summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Stiles <henry.stiles@artifex.com>1998-07-26 07:36:41 +0000
committerHenry Stiles <henry.stiles@artifex.com>1998-07-26 07:36:41 +0000
commiteec0ef527f18c5978c4476c9490f4de4c4249628 (patch)
tree5588d5e1300a245186594893c930949a19bcbbce
parentd4bdba93ef34f68d27148e1b31088d1d3e786e8c (diff)
downloadghostpdl-eec0ef527f18c5978c4476c9490f4de4c4249628.tar.gz
Initial revision
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@246 06663e23-700e-0410-b217-a244a6096597
-rw-r--r--gs/bug-form.txt61
-rw-r--r--gs/c-style.txt329
-rw-r--r--gs/commprod.txt220
-rw-r--r--gs/copying10
-rw-r--r--gs/current.txt119
-rw-r--r--gs/devices.txt2352
-rw-r--r--gs/dll.txt554
-rw-r--r--gs/doc/Gs-vms.hlp290
-rw-r--r--gs/doc/Public215
-rw-r--r--gs/doc/ps2epsi.txt62
-rw-r--r--gs/drivers.txt1355
-rw-r--r--gs/examples/ridt91.eps135
-rw-r--r--gs/fonts.txt480
-rw-r--r--gs/gdevpfax.c213
-rw-r--r--gs/helpers.txt170
-rw-r--r--gs/hershey.txt261
-rw-r--r--gs/history1.txt341
-rw-r--r--gs/history2.txt5160
-rw-r--r--gs/history3.txt8284
-rw-r--r--gs/humor.txt50
-rw-r--r--gs/install.txt256
-rw-r--r--gs/jpeg/Makefile274
-rw-r--r--gs/jpeg/README383
-rwxr-xr-xgs/jpeg/ansi2knrbin0 -> 7605 bytes
-rw-r--r--gs/jpeg/ansi2knr.136
-rw-r--r--gs/jpeg/ansi2knr.c693
-rw-r--r--gs/jpeg/cderror.h132
-rw-r--r--gs/jpeg/cdjpeg.c179
-rw-r--r--gs/jpeg/cdjpeg.h179
-rw-r--r--gs/jpeg/change.log152
-rwxr-xr-xgs/jpeg/cjpegbin0 -> 72722 bytes
-rw-r--r--gs/jpeg/cjpeg.1282
-rw-r--r--gs/jpeg/cjpeg.c606
-rw-r--r--gs/jpeg/ckconfig.c402
-rw-r--r--gs/jpeg/coderules.doc118
-rw-r--r--gs/jpeg/config.log20
-rwxr-xr-xgs/jpeg/config.status199
-rwxr-xr-xgs/jpeg/configure1731
-rwxr-xr-xgs/jpeg/djpegbin0 -> 88700 bytes
-rw-r--r--gs/jpeg/djpeg.1248
-rw-r--r--gs/jpeg/djpeg.c604
-rw-r--r--gs/jpeg/example.c433
-rw-r--r--gs/jpeg/filelist.doc203
-rw-r--r--gs/jpeg/install.doc931
-rw-r--r--gs/jpeg/jcapimin.c236
-rw-r--r--gs/jpeg/jcapistd.c161
-rw-r--r--gs/jpeg/jccoefct.c448
-rw-r--r--gs/jpeg/jccolor.c459
-rw-r--r--gs/jpeg/jcdctmgr.c387
-rw-r--r--gs/jpeg/jchuff.c846
-rw-r--r--gs/jpeg/jchuff.h34
-rw-r--r--gs/jpeg/jcinit.c72
-rw-r--r--gs/jpeg/jcmainct.c293
-rw-r--r--gs/jpeg/jcmarker.c641
-rw-r--r--gs/jpeg/jcmaster.c578
-rw-r--r--gs/jpeg/jcomapi.c94
-rw-r--r--gs/jpeg/jconfig.bcc48
-rw-r--r--gs/jpeg/jconfig.cfg44
-rw-r--r--gs/jpeg/jconfig.dj38
-rw-r--r--gs/jpeg/jconfig.doc155
-rw-r--r--gs/jpeg/jconfig.h45
-rw-r--r--gs/jpeg/jconfig.manx43
-rw-r--r--gs/jpeg/jconfig.mc652
-rw-r--r--gs/jpeg/jconfig.sas43
-rw-r--r--gs/jpeg/jconfig.st42
-rw-r--r--gs/jpeg/jconfig.vms37
-rw-r--r--gs/jpeg/jconfig.wat38
-rw-r--r--gs/jpeg/jcparam.c574
-rw-r--r--gs/jpeg/jcphuff.c829
-rw-r--r--gs/jpeg/jcprepct.c354
-rw-r--r--gs/jpeg/jcsample.c519
-rw-r--r--gs/jpeg/jctrans.c371
-rw-r--r--gs/jpeg/jdapimin.c406
-rw-r--r--gs/jpeg/jdapistd.c275
-rw-r--r--gs/jpeg/jdatadst.c151
-rw-r--r--gs/jpeg/jdatasrc.c212
-rw-r--r--gs/jpeg/jdcoefct.c735
-rw-r--r--gs/jpeg/jdcolor.c367
-rw-r--r--gs/jpeg/jdct.h176
-rw-r--r--gs/jpeg/jddctmgr.c269
-rw-r--r--gs/jpeg/jdhuff.c574
-rw-r--r--gs/jpeg/jdhuff.h202
-rw-r--r--gs/jpeg/jdinput.c381
-rw-r--r--gs/jpeg/jdmainct.c512
-rw-r--r--gs/jpeg/jdmarker.c1055
-rw-r--r--gs/jpeg/jdmaster.c555
-rw-r--r--gs/jpeg/jdmerge.c400
-rw-r--r--gs/jpeg/jdphuff.c642
-rw-r--r--gs/jpeg/jdpostct.c290
-rw-r--r--gs/jpeg/jdsample.c478
-rw-r--r--gs/jpeg/jdtrans.c122
-rw-r--r--gs/jpeg/jerror.c228
-rw-r--r--gs/jpeg/jerror.h277
-rw-r--r--gs/jpeg/jfdctflt.c168
-rw-r--r--gs/jpeg/jfdctfst.c224
-rw-r--r--gs/jpeg/jfdctint.c283
-rw-r--r--gs/jpeg/jidctflt.c241
-rw-r--r--gs/jpeg/jidctfst.c367
-rw-r--r--gs/jpeg/jidctint.c388
-rw-r--r--gs/jpeg/jidctred.c397
-rw-r--r--gs/jpeg/jinclude.h91
-rw-r--r--gs/jpeg/jmemansi.c167
-rw-r--r--gs/jpeg/jmemdos.c634
-rw-r--r--gs/jpeg/jmemdosa.asm379
-rw-r--r--gs/jpeg/jmemmac.c199
-rw-r--r--gs/jpeg/jmemmgr.c1115
-rw-r--r--gs/jpeg/jmemname.c271
-rw-r--r--gs/jpeg/jmemnobs.c109
-rw-r--r--gs/jpeg/jmemsys.h183
-rw-r--r--gs/jpeg/jmorecfg.h362
-rw-r--r--gs/jpeg/jpegint.h388
-rw-r--r--gs/jpeg/jpeglib.h1055
-rwxr-xr-xgs/jpeg/jpegtranbin0 -> 70882 bytes
-rw-r--r--gs/jpeg/jpegtran.1150
-rw-r--r--gs/jpeg/jpegtran.c372
-rw-r--r--gs/jpeg/jquant1.c856
-rw-r--r--gs/jpeg/jquant2.c1310
-rw-r--r--gs/jpeg/jutils.c179
-rw-r--r--gs/jpeg/jversion.h14
-rw-r--r--gs/jpeg/libjpeg.abin0 -> 150240 bytes
-rw-r--r--gs/jpeg/libjpeg.doc2772
-rw-r--r--gs/jpeg/makcjpeg.st37
-rw-r--r--gs/jpeg/makdjpeg.st37
-rw-r--r--gs/jpeg/makefile.ansi210
-rw-r--r--gs/jpeg/makefile.bcc279
-rw-r--r--gs/jpeg/makefile.cfg274
-rw-r--r--gs/jpeg/makefile.dj234
-rw-r--r--gs/jpeg/makefile.manx210
-rw-r--r--gs/jpeg/makefile.mc6233
-rw-r--r--gs/jpeg/makefile.mms214
-rw-r--r--gs/jpeg/makefile.sas244
-rw-r--r--gs/jpeg/makefile.unix224
-rw-r--r--gs/jpeg/makefile.vms141
-rw-r--r--gs/jpeg/makefile.wat229
-rw-r--r--gs/jpeg/makljpeg.st69
-rw-r--r--gs/jpeg/maktjpeg.st30
-rw-r--r--gs/jpeg/makvms.opt4
-rw-r--r--gs/jpeg/rdbmp.c439
-rw-r--r--gs/jpeg/rdcolmap.c253
-rw-r--r--gs/jpeg/rdgif.c683
-rwxr-xr-xgs/jpeg/rdjpgcombin0 -> 7666 bytes
-rw-r--r--gs/jpeg/rdjpgcom.145
-rw-r--r--gs/jpeg/rdjpgcom.c476
-rw-r--r--gs/jpeg/rdppm.c450
-rw-r--r--gs/jpeg/rdrle.c387
-rw-r--r--gs/jpeg/rdswitch.c332
-rw-r--r--gs/jpeg/rdtarga.c500
-rw-r--r--gs/jpeg/structure.doc948
-rw-r--r--gs/jpeg/testimg.gifbin0 -> 21846 bytes
-rw-r--r--gs/jpeg/testimg.jpgbin0 -> 5756 bytes
-rw-r--r--gs/jpeg/testimg.ppm4
-rw-r--r--gs/jpeg/testimgp.jpgbin0 -> 5645 bytes
-rw-r--r--gs/jpeg/testorig.jpgbin0 -> 5770 bytes
-rw-r--r--gs/jpeg/testprog.jpgbin0 -> 5655 bytes
-rw-r--r--gs/jpeg/usage.doc475
-rw-r--r--gs/jpeg/wizard.doc211
-rw-r--r--gs/jpeg/wrbmp.c442
-rw-r--r--gs/jpeg/wrgif.c505
-rwxr-xr-xgs/jpeg/wrjpgcombin0 -> 8922 bytes
-rw-r--r--gs/jpeg/wrjpgcom.1103
-rw-r--r--gs/jpeg/wrjpgcom.c575
-rw-r--r--gs/jpeg/wrppm.c268
-rw-r--r--gs/jpeg/wrrle.c305
-rw-r--r--gs/jpeg/wrtarga.c253
-rw-r--r--gs/language.txt768
-rw-r--r--gs/lib.txt363
-rw-r--r--gs/lib/Fontmap399
-rw-r--r--gs/lib/Fontmap.ATB169
-rw-r--r--gs/lib/Fontmap.ATM186
-rw-r--r--gs/lib/Fontmap.GS399
-rw-r--r--gs/lib/Fontmap.OS2215
-rw-r--r--gs/lib/Fontmap.OSF163
-rw-r--r--gs/lib/Fontmap.Sol482
-rw-r--r--gs/lib/Fontmap.Ult143
-rw-r--r--gs/lib/Fontmap.VMS120
-rwxr-xr-xgs/lib/_vc_make.bat5
-rwxr-xr-xgs/lib/_wm_cdir.bat1
-rw-r--r--gs/lib/acctest.ps99
-rw-r--r--gs/lib/align.ps71
-rw-r--r--gs/lib/alphabet.ps56
-rwxr-xr-xgs/lib/bdftops2
-rwxr-xr-xgs/lib/bdftops.bat1
-rw-r--r--gs/lib/bdftops.ps793
-rw-r--r--gs/lib/bjc610a0.upp44
-rw-r--r--gs/lib/bjc610a1.upp44
-rw-r--r--gs/lib/bjc610a2.upp44
-rw-r--r--gs/lib/bjc610a3.upp44
-rw-r--r--gs/lib/bjc610a4.upp45
-rw-r--r--gs/lib/bjc610a5.upp44
-rw-r--r--gs/lib/bjc610a6.upp44
-rw-r--r--gs/lib/bjc610a7.upp44
-rw-r--r--gs/lib/bjc610a8.upp44
-rw-r--r--gs/lib/bjc610b1.upp44
-rw-r--r--gs/lib/bjc610b2.upp44
-rw-r--r--gs/lib/bjc610b3.upp44
-rw-r--r--gs/lib/bjc610b4.upp45
-rw-r--r--gs/lib/bjc610b6.upp44
-rw-r--r--gs/lib/bjc610b7.upp44
-rw-r--r--gs/lib/bjc610b8.upp44
-rwxr-xr-xgs/lib/bughunt.sh119
-rw-r--r--gs/lib/caption.ps57
-rw-r--r--gs/lib/cbjc600.ppd404
-rw-r--r--gs/lib/cbjc800.ppd389
-rw-r--r--gs/lib/cdj550.upp48
-rw-r--r--gs/lib/cheq.ps945
-rw-r--r--gs/lib/chess.ps101
-rw-r--r--gs/lib/colorcir.ps120
-rwxr-xr-xgs/lib/cp.bat10
-rw-r--r--gs/lib/decrypt.ps13
-rw-r--r--gs/lib/docie.ps219
-rw-r--r--gs/lib/escher.ps379
-rwxr-xr-xgs/lib/font2c2
-rwxr-xr-xgs/lib/font2c.bat1
-rw-r--r--gs/lib/font2c.ps686
-rw-r--r--gs/lib/golfer.ps1398
-rw-r--r--gs/lib/grayalph.ps61
-rw-r--r--gs/lib/gs_btokn.ps283
-rw-r--r--gs/lib/gs_ccfnt.ps93
-rw-r--r--gs/lib/gs_cff.ps605
-rw-r--r--gs/lib/gs_cidfn.ps428
-rw-r--r--gs/lib/gs_cmap.ps242
-rw-r--r--gs/lib/gs_cmdl.ps181
-rw-r--r--gs/lib/gs_dbt_e.ps60
-rw-r--r--gs/lib/gs_diskf.ps225
-rw-r--r--gs/lib/gs_dpnxt.ps30
-rw-r--r--gs/lib/gs_dps.ps54
-rw-r--r--gs/lib/gs_dps1.ps136
-rw-r--r--gs/lib/gs_dps2.ps203
-rw-r--r--gs/lib/gs_epsf.ps60
-rw-r--r--gs/lib/gs_fform.ps110
-rw-r--r--gs/lib/gs_fonts.ps912
-rw-r--r--gs/lib/gs_init.ps1458
-rw-r--r--gs/lib/gs_iso_e.ps67
-rw-r--r--gs/lib/gs_kanji.ps159
-rw-r--r--gs/lib/gs_ksb_e.ps65
-rw-r--r--gs/lib/gs_l2img.ps186
-rw-r--r--gs/lib/gs_lev2.ps459
-rw-r--r--gs/lib/gs_mex_e.ps65
-rw-r--r--gs/lib/gs_mro_e.ps58
-rw-r--r--gs/lib/gs_pdf.ps646
-rw-r--r--gs/lib/gs_pdf_e.ps45
-rw-r--r--gs/lib/gs_pdfwr.ps377
-rw-r--r--gs/lib/gs_pfile.ps128
-rw-r--r--gs/lib/gs_res.ps665
-rw-r--r--gs/lib/gs_setpd.ps667
-rw-r--r--gs/lib/gs_statd.ps270
-rw-r--r--gs/lib/gs_std_e.ps74
-rw-r--r--gs/lib/gs_sym_e.ps84
-rw-r--r--gs/lib/gs_ttf.ps461
-rw-r--r--gs/lib/gs_typ42.ps45
-rw-r--r--gs/lib/gs_type1.ps136
-rw-r--r--gs/lib/gs_wan_e.ps45
-rw-r--r--gs/lib/gs_wl1_e.ps67
-rw-r--r--gs/lib/gs_wl2_e.ps67
-rw-r--r--gs/lib/gs_wl5_e.ps67
-rwxr-xr-xgs/lib/gsbj2
-rwxr-xr-xgs/lib/gsbj.bat1
-rwxr-xr-xgs/lib/gsdj2
-rwxr-xr-xgs/lib/gsdj.bat1
-rwxr-xr-xgs/lib/gsdj5002
-rwxr-xr-xgs/lib/gsdj500.bat1
-rwxr-xr-xgs/lib/gslj2
-rwxr-xr-xgs/lib/gslj.bat1
-rwxr-xr-xgs/lib/gslp2
-rwxr-xr-xgs/lib/gslp.bat1
-rw-r--r--gs/lib/gslp.ps537
-rwxr-xr-xgs/lib/gsnd2
-rwxr-xr-xgs/lib/gsnd.bat1
-rwxr-xr-xgs/lib/gsndt.bat1
-rwxr-xr-xgs/lib/gst.bat1
-rwxr-xr-xgs/lib/gstt.bat1
-rw-r--r--gs/lib/impath.ps180
-rw-r--r--gs/lib/landscap.ps29
-rw-r--r--gs/lib/level1.ps2
-rw-r--r--gs/lib/lines.ps152
-rwxr-xr-xgs/lib/lprsetup.sh188
-rw-r--r--gs/lib/markhint.ps131
-rw-r--r--gs/lib/markpath.ps60
-rwxr-xr-xgs/lib/mv.bat1
-rw-r--r--gs/lib/necp2x.upp35
-rw-r--r--gs/lib/necp2x6.upp35
-rw-r--r--gs/lib/packfile.ps334
-rw-r--r--gs/lib/pcharstr.ps127
-rwxr-xr-xgs/lib/pdf2dsc24
-rw-r--r--gs/lib/pdf2dsc.ps120
-rwxr-xr-xgs/lib/pdf2ps19
-rwxr-xr-xgs/lib/pdf2ps.bat21
-rw-r--r--gs/lib/pdf_2ps.ps273
-rw-r--r--gs/lib/pdf_base.ps456
-rw-r--r--gs/lib/pdf_draw.ps449
-rw-r--r--gs/lib/pdf_font.ps454
-rw-r--r--gs/lib/pdf_main.ps507
-rw-r--r--gs/lib/pdf_sec.ps58
-rw-r--r--gs/lib/pfbtogs.ps113
-rwxr-xr-xgs/lib/pftogsf.bat18
-rwxr-xr-xgs/lib/pj-gs.sh288
-rw-r--r--gs/lib/ppath.ps55
-rw-r--r--gs/lib/prfont.ps153
-rwxr-xr-xgs/lib/printafm6
-rw-r--r--gs/lib/printafm.ps146
-rw-r--r--gs/lib/ps2ai.ps542
-rwxr-xr-xgs/lib/ps2ascii16
-rwxr-xr-xgs/lib/ps2ascii.bat12
-rw-r--r--gs/lib/ps2ascii.ps1310
-rwxr-xr-xgs/lib/ps2epsi82
-rwxr-xr-xgs/lib/ps2epsi.bat25
-rw-r--r--gs/lib/ps2epsi.ps253
-rwxr-xr-xgs/lib/ps2pdf33
-rw-r--r--gs/lib/ps2pdf.bat62
-rwxr-xr-xgs/lib/pv.sh36
-rw-r--r--gs/lib/quit.ps1
-rw-r--r--gs/lib/ras1.upp8
-rw-r--r--gs/lib/ras24.upp8
-rw-r--r--gs/lib/ras3.upp8
-rw-r--r--gs/lib/ras32.upp8
-rw-r--r--gs/lib/ras4.upp8
-rw-r--r--gs/lib/ras8m.upp8
-rwxr-xr-xgs/lib/rm.bat9
-rw-r--r--gs/lib/rollconv.ps372
-rw-r--r--gs/lib/showchar.ps94
-rw-r--r--gs/lib/showpage.ps1
-rw-r--r--gs/lib/snowflak.ps90
-rw-r--r--gs/lib/stc.upp53
-rw-r--r--gs/lib/stc1520h.upp58
-rw-r--r--gs/lib/stc2.upp53
-rw-r--r--gs/lib/stc2_h.upp53
-rw-r--r--gs/lib/stc2s_h.upp57
-rw-r--r--gs/lib/stc500p.upp48
-rw-r--r--gs/lib/stc500ph.upp48
-rw-r--r--gs/lib/stc600ih.upp58
-rw-r--r--gs/lib/stc600p.upp34
-rw-r--r--gs/lib/stc600pl.upp34
-rw-r--r--gs/lib/stc800ih.upp58
-rw-r--r--gs/lib/stc800p.upp34
-rw-r--r--gs/lib/stc800pl.upp34
-rw-r--r--gs/lib/stc_h.upp53
-rw-r--r--gs/lib/stc_l.upp26
-rw-r--r--gs/lib/stcany.upp24
-rw-r--r--gs/lib/stcinfo.ps799
-rw-r--r--gs/lib/stcolor.ps171
-rwxr-xr-xgs/lib/sysvlp.sh45
-rw-r--r--gs/lib/t1tot2.ps485
-rw-r--r--gs/lib/test.ps9
-rw-r--r--gs/lib/tiger.ps2733
-rw-r--r--gs/lib/traceimg.ps43
-rw-r--r--gs/lib/traceop.ps79
-rw-r--r--gs/lib/type1enc.ps66
-rw-r--r--gs/lib/type1ops.ps238
-rw-r--r--gs/lib/uninfo.ps221
-rwxr-xr-xgs/lib/unix-lpr.sh160
-rw-r--r--gs/lib/unprot.ps61
-rw-r--r--gs/lib/viewcmyk.ps68
-rw-r--r--gs/lib/viewgif.ps162
-rw-r--r--gs/lib/viewjpeg.ps144
-rw-r--r--gs/lib/viewpbm.ps135
-rw-r--r--gs/lib/viewpcx.ps133
-rw-r--r--gs/lib/viewps2a.ps33
-rw-r--r--gs/lib/waterfal.ps74
-rwxr-xr-xgs/lib/wftopfa2
-rw-r--r--gs/lib/wftopfa.ps304
-rw-r--r--gs/lib/winmaps.ps107
-rw-r--r--gs/lib/wmakebat.bat2
-rw-r--r--gs/lib/wrfont.ps663
-rw-r--r--gs/lib/writecff.ps366
-rw-r--r--gs/lib/zeroline.ps101
-rw-r--r--gs/libpng/CHANGES169
-rw-r--r--gs/libpng/README166
-rw-r--r--gs/libpng/TODO19
-rw-r--r--gs/libpng/ansi2knr.c488
-rw-r--r--gs/libpng/build.bat2
-rw-r--r--gs/libpng/descrip.mms52
-rw-r--r--gs/libpng/example.c667
-rw-r--r--gs/libpng/libpng.abin0 -> 105305 bytes
-rw-r--r--gs/libpng/libpng.txt1519
-rw-r--r--gs/libpng/makefile68
-rw-r--r--gs/libpng/makefile.aco221
-rw-r--r--gs/libpng/makefile.ama42
-rw-r--r--gs/libpng/makefile.atr31
-rw-r--r--gs/libpng/makefile.bor168
-rw-r--r--gs/libpng/makefile.dj252
-rw-r--r--gs/libpng/makefile.elf86
-rw-r--r--gs/libpng/makefile.knr73
-rw-r--r--gs/libpng/makefile.mip62
-rw-r--r--gs/libpng/makefile.msc86
-rw-r--r--gs/libpng/makefile.std68
-rw-r--r--gs/libpng/makefile.sun72
-rw-r--r--gs/libpng/makefile.tc78
-rw-r--r--gs/libpng/makevms.com125
-rw-r--r--gs/libpng/png.c358
-rw-r--r--gs/libpng/png.h1835
-rw-r--r--gs/libpng/pngconf.h445
-rw-r--r--gs/libpng/pngerror.c112
-rw-r--r--gs/libpng/pngget.c300
-rw-r--r--gs/libpng/pngmem.c311
-rw-r--r--gs/libpng/pngpread.c1102
-rw-r--r--gs/libpng/pngread.c750
-rw-r--r--gs/libpng/pngrio.c137
-rw-r--r--gs/libpng/pngrtran.c3153
-rw-r--r--gs/libpng/pngrutil.c2137
-rw-r--r--gs/libpng/pngset.c312
-rwxr-xr-xgs/libpng/pngtestbin0 -> 105015 bytes
-rw-r--r--gs/libpng/pngtest.c377
-rw-r--r--gs/libpng/pngtest.pngbin0 -> 8634 bytes
-rw-r--r--gs/libpng/pngtrans.c565
-rw-r--r--gs/libpng/pngwio.c193
-rw-r--r--gs/libpng/pngwrite.c847
-rw-r--r--gs/libpng/pngwtran.c392
-rw-r--r--gs/libpng/pngwutil.c1917
-rw-r--r--gs/make.txt1540
-rw-r--r--gs/man/ansi2knr.136
-rw-r--r--gs/man/gs.1406
-rw-r--r--gs/man/pdf2dsc.152
-rw-r--r--gs/man/pdf2ps.121
-rw-r--r--gs/man/ps2ascii.137
-rw-r--r--gs/man/ps2epsi.1100
-rw-r--r--gs/man/ps2pdf.135
-rw-r--r--gs/new-user.txt570
-rw-r--r--gs/news5241
-rw-r--r--gs/ps2image.ps4
-rw-r--r--gs/ps2pdf.txt110
-rw-r--r--gs/psfiles.txt241
-rw-r--r--gs/public.txt75
-rw-r--r--gs/readme187
-rwxr-xr-xgs/src/_vc_temp.mak10
-rw-r--r--gs/src/ansi2knr.c546
-rw-r--r--gs/src/ansihead.mak283
-rw-r--r--gs/src/append_l.com19
-rw-r--r--gs/src/bcc32.cfg5
-rw-r--r--gs/src/bcwin32.mak434
-rw-r--r--gs/src/bench.c360
-rw-r--r--gs/src/bfont.h63
-rw-r--r--gs/src/bseq.h61
-rw-r--r--gs/src/btoken.h60
-rw-r--r--gs/src/cc-head.mak287
-rw-r--r--gs/src/ccfont.h93
-rw-r--r--gs/src/ccgs40
-rw-r--r--gs/src/cfonts.mak442
-rw-r--r--gs/src/copy_one.com14
-rwxr-xr-xgs/src/cp.cmd2
-rw-r--r--gs/src/ctype_.h26
-rw-r--r--gs/src/devs.mak1626
-rw-r--r--gs/src/dgc-head.mak267
-rw-r--r--gs/src/dirent_.h46
-rw-r--r--gs/src/dodebug.h29
-rw-r--r--gs/src/dos_.h77
-rw-r--r--gs/src/dpmainc.c310
-rw-r--r--gs/src/dstack.h279
-rwxr-xr-xgs/src/dvx-gcc.mak5696
-rw-r--r--gs/src/dvx-head.mak70
-rw-r--r--gs/src/dvx-tail.mak91
-rw-r--r--gs/src/dw32c.def6
-rw-r--r--gs/src/dwdll.cpp343
-rw-r--r--gs/src/dwdll.h118
-rw-r--r--gs/src/dwimg.cpp415
-rw-r--r--gs/src/dwimg.h51
-rw-r--r--gs/src/dwmain.cpp412
-rw-r--r--gs/src/dwmain.h5
-rw-r--r--gs/src/dwmain.rc30
-rw-r--r--gs/src/dwmain16.def7
-rw-r--r--gs/src/dwmain32.def7
-rw-r--r--gs/src/dwmainc.cpp219
-rw-r--r--gs/src/dwnodll.cpp349
-rw-r--r--gs/src/dwtext.cpp964
-rw-r--r--gs/src/dwtext.h144
-rw-r--r--gs/src/echogs.c294
-rw-r--r--gs/src/errno_.h30
-rw-r--r--gs/src/errors.h177
-rw-r--r--gs/src/estack.h135
-rw-r--r--gs/src/files.h137
-rw-r--r--gs/src/fname.h33
-rw-r--r--gs/src/gcc-head.mak295
-rw-r--r--gs/src/gconf.c121
-rw-r--r--gs/src/gdebug.h113
-rw-r--r--gs/src/gdev3852.c187
-rw-r--r--gs/src/gdev3b1.c791
-rw-r--r--gs/src/gdev4081.c95
-rw-r--r--gs/src/gdev4693.c168
-rw-r--r--gs/src/gdev8510.c144
-rw-r--r--gs/src/gdev8bcm.c76
-rw-r--r--gs/src/gdev8bcm.h68
-rw-r--r--gs/src/gdevabuf.c364
-rw-r--r--gs/src/gdevadmp.c407
-rw-r--r--gs/src/gdevasyn.c661
-rw-r--r--gs/src/gdevbbox.c759
-rw-r--r--gs/src/gdevbbox.h74
-rw-r--r--gs/src/gdevbgi.c661
-rw-r--r--gs/src/gdevbit.c341
-rw-r--r--gs/src/gdevbj10.c385
-rw-r--r--gs/src/gdevbjc.h282
-rw-r--r--gs/src/gdevbmp.c264
-rw-r--r--gs/src/gdevccr.c294
-rw-r--r--gs/src/gdevcdj.c3916
-rw-r--r--gs/src/gdevcgm.c474
-rw-r--r--gs/src/gdevcgml.c990
-rw-r--r--gs/src/gdevcgml.h403
-rw-r--r--gs/src/gdevcgmx.h182
-rw-r--r--gs/src/gdevcif.c98
-rw-r--r--gs/src/gdevcp50.c223
-rw-r--r--gs/src/gdevddrw.c477
-rw-r--r--gs/src/gdevdfax.c111
-rw-r--r--gs/src/gdevdflt.c911
-rw-r--r--gs/src/gdevdjet.c608
-rw-r--r--gs/src/gdevdjtc.c276
-rw-r--r--gs/src/gdevdm24.c289
-rw-r--r--gs/src/gdevegaa.asm277
-rw-r--r--gs/src/gdevemap.c59
-rw-r--r--gs/src/gdevepsc.c458
-rw-r--r--gs/src/gdevepsn.c497
-rw-r--r--gs/src/gdevescp.c415
-rw-r--r--gs/src/gdevevga.c108
-rw-r--r--gs/src/gdevherc.c482
-rw-r--r--gs/src/gdevht.c212
-rw-r--r--gs/src/gdevht.h42
-rw-r--r--gs/src/gdevimgn.c572
-rw-r--r--gs/src/gdevjpeg.c288
-rw-r--r--gs/src/gdevl256.c311
-rw-r--r--gs/src/gdevlbp8.c213
-rw-r--r--gs/src/gdevlj56.c269
-rw-r--r--gs/src/gdevlp8k.c412
-rw-r--r--gs/src/gdevm1.c685
-rw-r--r--gs/src/gdevm16.c149
-rw-r--r--gs/src/gdevm2.c239
-rw-r--r--gs/src/gdevm24.c490
-rw-r--r--gs/src/gdevm32.c228
-rw-r--r--gs/src/gdevm4.c202
-rw-r--r--gs/src/gdevm8.c220
-rw-r--r--gs/src/gdevmem.c377
-rw-r--r--gs/src/gdevmem.h214
-rw-r--r--gs/src/gdevmgr.c433
-rw-r--r--gs/src/gdevmgr.h116
-rw-r--r--gs/src/gdevmiff.c84
-rw-r--r--gs/src/gdevmpla.c177
-rw-r--r--gs/src/gdevmrop.c1333
-rw-r--r--gs/src/gdevmrop.h63
-rw-r--r--gs/src/gdevmswn.c477
-rw-r--r--gs/src/gdevmswn.h109
-rw-r--r--gs/src/gdevmsxf.c451
-rw-r--r--gs/src/gdevn533.c209
-rw-r--r--gs/src/gdevnfwd.c560
-rw-r--r--gs/src/gdevnp6.c257
-rw-r--r--gs/src/gdevo182.c311
-rw-r--r--gs/src/gdevokii.c327
-rw-r--r--gs/src/gdevos2p.c701
-rw-r--r--gs/src/gdevp2up.c148
-rw-r--r--gs/src/gdevpbm.c717
-rw-r--r--gs/src/gdevpccm.c173
-rw-r--r--gs/src/gdevpccm.h34
-rw-r--r--gs/src/gdevpcfb.c900
-rw-r--r--gs/src/gdevpcfb.h191
-rw-r--r--gs/src/gdevpcl.c216
-rw-r--r--gs/src/gdevpcl.h42
-rw-r--r--gs/src/gdevpcx.c461
-rw-r--r--gs/src/gdevpdf.c1337
-rw-r--r--gs/src/gdevpdfd.c381
-rw-r--r--gs/src/gdevpdfi.c1023
-rw-r--r--gs/src/gdevpdfm.c788
-rw-r--r--gs/src/gdevpdfp.c189
-rw-r--r--gs/src/gdevpdft.c755
-rw-r--r--gs/src/gdevpdfx.h445
-rw-r--r--gs/src/gdevpe.c362
-rw-r--r--gs/src/gdevpipe.c69
-rw-r--r--gs/src/gdevpjet.c251
-rw-r--r--gs/src/gdevpm.c1262
-rw-r--r--gs/src/gdevpm.h35
-rw-r--r--gs/src/gdevpng.c258
-rw-r--r--gs/src/gdevprn.c919
-rw-r--r--gs/src/gdevprn.h524
-rw-r--r--gs/src/gdevprna.h174
-rw-r--r--gs/src/gdevps.c798
-rw-r--r--gs/src/gdevpsdf.c613
-rw-r--r--gs/src/gdevpsdf.h191
-rw-r--r--gs/src/gdevpsim.c246
-rw-r--r--gs/src/gdevpstr.c143
-rw-r--r--gs/src/gdevpstr.h73
-rw-r--r--gs/src/gdevpx.c1566
-rw-r--r--gs/src/gdevpxat.h133
-rw-r--r--gs/src/gdevpxen.h239
-rw-r--r--gs/src/gdevpxop.h108
-rw-r--r--gs/src/gdevrrgb.c230
-rw-r--r--gs/src/gdevrun.c434
-rw-r--r--gs/src/gdevs3ga.c239
-rw-r--r--gs/src/gdevsco.c275
-rw-r--r--gs/src/gdevsgi.c220
-rw-r--r--gs/src/gdevsgi.h66
-rw-r--r--gs/src/gdevsj48.c293
-rw-r--r--gs/src/gdevsnfb.c116
-rw-r--r--gs/src/gdevsppr.c188
-rw-r--r--gs/src/gdevstc.c3552
-rw-r--r--gs/src/gdevstc.h252
-rw-r--r--gs/src/gdevstc1.c127
-rw-r--r--gs/src/gdevstc2.c427
-rw-r--r--gs/src/gdevstc3.c107
-rw-r--r--gs/src/gdevstc4.c301
-rw-r--r--gs/src/gdevsun.c685
-rw-r--r--gs/src/gdevsvga.c952
-rw-r--r--gs/src/gdevsvga.h92
-rw-r--r--gs/src/gdevtfax.c424
-rw-r--r--gs/src/gdevtfnx.c186
-rw-r--r--gs/src/gdevtifs.c238
-rw-r--r--gs/src/gdevtifs.h206
-rw-r--r--gs/src/gdevtknk.c253
-rw-r--r--gs/src/gdevupd.c6269
-rw-r--r--gs/src/gdevvec.c852
-rw-r--r--gs/src/gdevvec.h328
-rw-r--r--gs/src/gdevvglb.c389
-rw-r--r--gs/src/gdevwddb.c604
-rw-r--r--gs/src/gdevwdib.c674
-rw-r--r--gs/src/gdevwpr2.c804
-rw-r--r--gs/src/gdevwprn.c665
-rw-r--r--gs/src/gdevx.c1250
-rw-r--r--gs/src/gdevx.h177
-rw-r--r--gs/src/gdevxalt.c723
-rw-r--r--gs/src/gdevxini.c1001
-rw-r--r--gs/src/gdevxxf.c465
-rw-r--r--gs/src/genarch.c122
-rw-r--r--gs/src/genconf.c640
-rw-r--r--gs/src/geninit.c231
-rw-r--r--gs/src/ghost.h22
-rw-r--r--gs/src/gp.h196
-rw-r--r--gs/src/gp_dosfb.c200
-rw-r--r--gs/src/gp_dosfe.c145
-rw-r--r--gs/src/gp_dosfs.c86
-rw-r--r--gs/src/gp_dvx.c110
-rw-r--r--gs/src/gp_itbc.c212
-rw-r--r--gs/src/gp_iwatc.c154
-rw-r--r--gs/src/gp_msdos.c123
-rw-r--r--gs/src/gp_msio.c200
-rw-r--r--gs/src/gp_mslib.c45
-rw-r--r--gs/src/gp_mswin.c852
-rw-r--r--gs/src/gp_mswin.h52
-rw-r--r--gs/src/gp_nofb.c49
-rw-r--r--gs/src/gp_ntfs.c192
-rw-r--r--gs/src/gp_os2.c907
-rw-r--r--gs/src/gp_os9.c138
-rw-r--r--gs/src/gp_sysv.c66
-rw-r--r--gs/src/gp_unifn.c53
-rw-r--r--gs/src/gp_unifs.c419
-rw-r--r--gs/src/gp_unix.c165
-rw-r--r--gs/src/gp_vms.c422
-rw-r--r--gs/src/gp_win32.c253
-rw-r--r--gs/src/gpcheck.h53
-rw-r--r--gs/src/gpsync.h50
-rw-r--r--gs/src/gs.c68
-rw-r--r--gs/src/gs.mak339
-rw-r--r--gs/src/gs16spl.c220
-rw-r--r--gs/src/gs16spl.def7
-rw-r--r--gs/src/gs16spl.rc38
-rw-r--r--gs/src/gsalloc.c1282
-rw-r--r--gs/src/gsalloc.h53
-rw-r--r--gs/src/gsargs.c159
-rw-r--r--gs/src/gsargs.h70
-rw-r--r--gs/src/gsbitmap.h187
-rw-r--r--gs/src/gsbitops.c601
-rw-r--r--gs/src/gsbitops.h173
-rw-r--r--gs/src/gsbittab.c126
-rw-r--r--gs/src/gsbittab.h73
-rw-r--r--gs/src/gsccode.h64
-rw-r--r--gs/src/gsccolor.h46
-rw-r--r--gs/src/gscdef.c71
-rw-r--r--gs/src/gscdefs.h50
-rw-r--r--gs/src/gschar.c1432
-rw-r--r--gs/src/gschar.h123
-rw-r--r--gs/src/gschar0.c373
-rw-r--r--gs/src/gscie.c1189
-rw-r--r--gs/src/gscie.h472
-rw-r--r--gs/src/gscolor.c366
-rw-r--r--gs/src/gscolor.h40
-rw-r--r--gs/src/gscolor1.c229
-rw-r--r--gs/src/gscolor1.h44
-rw-r--r--gs/src/gscolor2.c198
-rw-r--r--gs/src/gscolor2.h127
-rw-r--r--gs/src/gscoord.c471
-rw-r--r--gs/src/gscoord.h51
-rw-r--r--gs/src/gscpm.h33
-rw-r--r--gs/src/gscrypt1.h45
-rw-r--r--gs/src/gscsel.h37
-rw-r--r--gs/src/gscsepr.c176
-rw-r--r--gs/src/gscsepr.h22
-rw-r--r--gs/src/gscspace.h189
-rw-r--r--gs/src/gsdcolor.h310
-rw-r--r--gs/src/gsdevice.c448
-rw-r--r--gs/src/gsdevice.h88
-rw-r--r--gs/src/gsdevmem.c216
-rw-r--r--gs/src/gsdll.c192
-rw-r--r--gs/src/gsdll.h128
-rw-r--r--gs/src/gsdll16.def20
-rw-r--r--gs/src/gsdll16.rc26
-rw-r--r--gs/src/gsdll2.def12
-rw-r--r--gs/src/gsdll2.rc22
-rw-r--r--gs/src/gsdll32.def17
-rw-r--r--gs/src/gsdll32.rc26
-rw-r--r--gs/src/gsdparam.c615
-rw-r--r--gs/src/gsdps.c129
-rw-r--r--gs/src/gsdps.h26
-rw-r--r--gs/src/gsdps1.c231
-rw-r--r--gs/src/gsdsc.c315
-rw-r--r--gs/src/gsdsrc.c107
-rw-r--r--gs/src/gsdsrc.h101
-rw-r--r--gs/src/gserror.h35
-rw-r--r--gs/src/gserrors.h43
-rw-r--r--gs/src/gserver.c290
-rw-r--r--gs/src/gsexit.h34
-rw-r--r--gs/src/gsfcmap.c153
-rw-r--r--gs/src/gsfcmap.h58
-rw-r--r--gs/src/gsfemu.c722
-rw-r--r--gs/src/gsflip.c293
-rw-r--r--gs/src/gsflip.h35
-rw-r--r--gs/src/gsfont.c527
-rw-r--r--gs/src/gsfont.h66
-rw-r--r--gs/src/gsfont0.c121
-rw-r--r--gs/src/gsfunc.c68
-rw-r--r--gs/src/gsfunc.h114
-rw-r--r--gs/src/gsfunc0.c246
-rw-r--r--gs/src/gsfunc0.h59
-rw-r--r--gs/src/gsgc.h83
-rw-r--r--gs/src/gsgraph.icx48
-rw-r--r--gs/src/gshsb.c136
-rw-r--r--gs/src/gshsb.h23
-rw-r--r--gs/src/gsht.c552
-rw-r--r--gs/src/gsht.h70
-rw-r--r--gs/src/gsht1.c356
-rw-r--r--gs/src/gsht1.h53
-rw-r--r--gs/src/gshtscr.c529
-rw-r--r--gs/src/gsimage.c311
-rw-r--r--gs/src/gsimage.h45
-rw-r--r--gs/src/gsimpath.c183
-rw-r--r--gs/src/gsinit.c69
-rw-r--r--gs/src/gsio.h60
-rw-r--r--gs/src/gsiodev.c265
-rw-r--r--gs/src/gsiparam.h167
-rw-r--r--gs/src/gsjconf.h59
-rw-r--r--gs/src/gsjerror.c27
-rw-r--r--gs/src/gsjerror.h383
-rw-r--r--gs/src/gsjmorec.h50
-rw-r--r--gs/src/gsjpglib.h938
-rw-r--r--gs/src/gslib.c549
-rw-r--r--gs/src/gslib.h34
-rw-r--r--gs/src/gsline.c302
-rw-r--r--gs/src/gsline.h66
-rw-r--r--gs/src/gslparam.h44
-rw-r--r--gs/src/gsmatrix.c426
-rw-r--r--gs/src/gsmatrix.h75
-rw-r--r--gs/src/gsmdebug.h45
-rw-r--r--gs/src/gsmemfix.c414
-rw-r--r--gs/src/gsmemfix.h64
-rw-r--r--gs/src/gsmemlok.c320
-rw-r--r--gs/src/gsmemlok.h52
-rw-r--r--gs/src/gsmemory.c472
-rw-r--r--gs/src/gsmemory.h390
-rw-r--r--gs/src/gsmemraw.h73
-rw-r--r--gs/src/gsmisc.c815
-rw-r--r--gs/src/gsnogc.c329
-rw-r--r--gs/src/gsos2.def3
-rw-r--r--gs/src/gsos2.icx209
-rw-r--r--gs/src/gsos2.rc22
-rw-r--r--gs/src/gspaint.c308
-rw-r--r--gs/src/gspaint.h31
-rw-r--r--gs/src/gsparam.c558
-rw-r--r--gs/src/gsparam.h445
-rw-r--r--gs/src/gsparams.c400
-rw-r--r--gs/src/gsparams.h44
-rw-r--r--gs/src/gspath.c416
-rw-r--r--gs/src/gspath.h72
-rw-r--r--gs/src/gspath1.c376
-rw-r--r--gs/src/gspath2.h30
-rw-r--r--gs/src/gspcolor.c991
-rw-r--r--gs/src/gspenum.h34
-rw-r--r--gs/src/gspmdrv.c1252
-rw-r--r--gs/src/gspmdrv.def3
-rw-r--r--gs/src/gspmdrv.h28
-rw-r--r--gs/src/gspmdrv.icx209
-rw-r--r--gs/src/gspmdrv.rc40
-rw-r--r--gs/src/gsrefct.h136
-rw-r--r--gs/src/gsrop.c96
-rw-r--r--gs/src/gsrop.h43
-rw-r--r--gs/src/gsropt.h189
-rw-r--r--gs/src/gsroptab.c372
-rw-r--r--gs/src/gsstate.c1046
-rw-r--r--gs/src/gsstate.h76
-rw-r--r--gs/src/gsstruct.h672
-rw-r--r--gs/src/gstext.icx48
-rw-r--r--gs/src/gstype1.c588
-rw-r--r--gs/src/gstype1.h250
-rw-r--r--gs/src/gstype2.c658
-rw-r--r--gs/src/gstype42.c444
-rw-r--r--gs/src/gstypes.h79
-rw-r--r--gs/src/gsuid.h67
-rw-r--r--gs/src/gsutil.c216
-rw-r--r--gs/src/gsutil.h61
-rw-r--r--gs/src/gswin.rc29
-rw-r--r--gs/src/gswin32.rc36
-rw-r--r--gs/src/gswin386.rc4
-rw-r--r--gs/src/gsxfont.h38
-rw-r--r--gs/src/gx.h38
-rw-r--r--gs/src/gxacpath.c447
-rw-r--r--gs/src/gxalloc.h373
-rw-r--r--gs/src/gxarith.h78
-rw-r--r--gs/src/gxband.h63
-rw-r--r--gs/src/gxbcache.c142
-rw-r--r--gs/src/gxbcache.h116
-rw-r--r--gs/src/gxbitmap.h120
-rw-r--r--gs/src/gxccache.c440
-rw-r--r--gs/src/gxccman.c763
-rw-r--r--gs/src/gxchar.h155
-rw-r--r--gs/src/gxcht.c585
-rw-r--r--gs/src/gxcindex.h96
-rw-r--r--gs/src/gxclbits.c742
-rw-r--r--gs/src/gxcldev.h636
-rw-r--r--gs/src/gxclfile.c145
-rw-r--r--gs/src/gxclimag.c1234
-rw-r--r--gs/src/gxclio.h89
-rw-r--r--gs/src/gxclip2.c375
-rw-r--r--gs/src/gxclip2.h56
-rw-r--r--gs/src/gxclist.c1187
-rw-r--r--gs/src/gxclist.h301
-rw-r--r--gs/src/gxcllzw.c47
-rw-r--r--gs/src/gxclmem.c1129
-rw-r--r--gs/src/gxclmem.h141
-rw-r--r--gs/src/gxclpage.c113
-rw-r--r--gs/src/gxclpage.h53
-rw-r--r--gs/src/gxclpath.c1230
-rw-r--r--gs/src/gxclpath.h201
-rw-r--r--gs/src/gxclread.c2491
-rw-r--r--gs/src/gxclrect.c616
-rw-r--r--gs/src/gxclzlib.c50
-rw-r--r--gs/src/gxcmap.c776
-rw-r--r--gs/src/gxcmap.h95
-rw-r--r--gs/src/gxcolor2.h72
-rw-r--r--gs/src/gxcoord.h33
-rw-r--r--gs/src/gxcpath.c1020
-rw-r--r--gs/src/gxcpath.h119
-rw-r--r--gs/src/gxcspace.h172
-rw-r--r--gs/src/gxctable.c140
-rw-r--r--gs/src/gxctable.h58
-rw-r--r--gs/src/gxcvalue.h41
-rw-r--r--gs/src/gxdcconv.c146
-rw-r--r--gs/src/gxdcconv.h31
-rw-r--r--gs/src/gxdcolor.c210
-rw-r--r--gs/src/gxdcolor.h184
-rw-r--r--gs/src/gxdda.h145
-rw-r--r--gs/src/gxdevice.h1004
-rw-r--r--gs/src/gxdevmem.h150
-rw-r--r--gs/src/gxdevrop.h31
-rw-r--r--gs/src/gxdht.h251
-rw-r--r--gs/src/gxdither.c478
-rw-r--r--gs/src/gxdither.h78
-rw-r--r--gs/src/gxfarith.h129
-rw-r--r--gs/src/gxfcache.h250
-rw-r--r--gs/src/gxfcmap.h93
-rw-r--r--gs/src/gxfill.c1507
-rw-r--r--gs/src/gxfixed.h227
-rw-r--r--gs/src/gxfmap.h92
-rw-r--r--gs/src/gxfont.h207
-rw-r--r--gs/src/gxfont0.h66
-rw-r--r--gs/src/gxfont1.h105
-rw-r--r--gs/src/gxfont42.h58
-rw-r--r--gs/src/gxfrac.h91
-rw-r--r--gs/src/gxftype.h51
-rw-r--r--gs/src/gxfunc.h55
-rw-r--r--gs/src/gxhint1.c254
-rw-r--r--gs/src/gxhint2.c402
-rw-r--r--gs/src/gxhint3.c518
-rw-r--r--gs/src/gxht.c458
-rw-r--r--gs/src/gxht.h142
-rw-r--r--gs/src/gxhttile.h47
-rw-r--r--gs/src/gxhttype.h38
-rw-r--r--gs/src/gximage.h275
-rw-r--r--gs/src/gximage0.c200
-rw-r--r--gs/src/gximage2.c470
-rw-r--r--gs/src/gximage3.c332
-rw-r--r--gs/src/gximage4.c299
-rw-r--r--gs/src/gximage5.c243
-rw-r--r--gs/src/gxiodev.h172
-rw-r--r--gs/src/gxistate.h216
-rw-r--r--gs/src/gxline.h70
-rw-r--r--gs/src/gxlum.h26
-rw-r--r--gs/src/gxmatrix.h76
-rw-r--r--gs/src/gxobj.h209
-rw-r--r--gs/src/gxop1.h69
-rw-r--r--gs/src/gxpageq.c305
-rw-r--r--gs/src/gxpageq.h186
-rw-r--r--gs/src/gxpaint.c65
-rw-r--r--gs/src/gxpaint.h108
-rw-r--r--gs/src/gxpath.c552
-rw-r--r--gs/src/gxpath.h193
-rw-r--r--gs/src/gxpath2.c452
-rw-r--r--gs/src/gxpcache.h52
-rw-r--r--gs/src/gxpcmap.c583
-rw-r--r--gs/src/gxpcolor.h125
-rw-r--r--gs/src/gxpcopy.c806
-rw-r--r--gs/src/gxpdash.c187
-rw-r--r--gs/src/gxpflat.c452
-rw-r--r--gs/src/gxsample.c186
-rw-r--r--gs/src/gxsample.h71
-rw-r--r--gs/src/gxstate.h76
-rw-r--r--gs/src/gxstroke.c1282
-rw-r--r--gs/src/gxsync.c140
-rw-r--r--gs/src/gxsync.h73
-rw-r--r--gs/src/gxtmap.h37
-rw-r--r--gs/src/gxtype1.c419
-rw-r--r--gs/src/gxtype1.h320
-rw-r--r--gs/src/gxxfont.h167
-rw-r--r--gs/src/gzacpath.h50
-rw-r--r--gs/src/gzcpath.h47
-rw-r--r--gs/src/gzline.h29
-rw-r--r--gs/src/gzpath.h293
-rw-r--r--gs/src/gzstate.h121
-rw-r--r--gs/src/ialloc.c259
-rw-r--r--gs/src/ialloc.h117
-rw-r--r--gs/src/iastate.h24
-rw-r--r--gs/src/iastruct.h22
-rw-r--r--gs/src/ibnum.c208
-rw-r--r--gs/src/ibnum.h59
-rw-r--r--gs/src/iccfont.c313
-rw-r--r--gs/src/iccinit0.c25
-rw-r--r--gs/src/icfontab.c51
-rw-r--r--gs/src/ichar.h62
-rw-r--r--gs/src/icharout.h48
-rw-r--r--gs/src/icie.h72
-rw-r--r--gs/src/icolor.h43
-rw-r--r--gs/src/iconf.c73
-rw-r--r--gs/src/icontext.c117
-rw-r--r--gs/src/icontext.h73
-rw-r--r--gs/src/icsmap.h34
-rw-r--r--gs/src/idebug.c262
-rw-r--r--gs/src/idebug.h36
-rw-r--r--gs/src/idict.c1003
-rw-r--r--gs/src/idict.h240
-rw-r--r--gs/src/idparam.c342
-rw-r--r--gs/src/idparam.h75
-rw-r--r--gs/src/ifilter.h72
-rw-r--r--gs/src/ifont.h82
-rw-r--r--gs/src/ifunc.h48
-rw-r--r--gs/src/igc.c1249
-rw-r--r--gs/src/igc.h79
-rw-r--r--gs/src/igcref.c682
-rw-r--r--gs/src/igcstr.c362
-rw-r--r--gs/src/igcstr.h30
-rw-r--r--gs/src/igstate.h162
-rw-r--r--gs/src/iht.h26
-rw-r--r--gs/src/iimage.h36
-rw-r--r--gs/src/iinit.c462
-rw-r--r--gs/src/ilevel.h24
-rw-r--r--gs/src/ilocate.c405
-rw-r--r--gs/src/imain.c612
-rw-r--r--gs/src/imain.h266
-rw-r--r--gs/src/imainarg.c704
-rw-r--r--gs/src/imainarg.h47
-rw-r--r--gs/src/imemory.h100
-rw-r--r--gs/src/iminst.h72
-rw-r--r--gs/src/iname.c602
-rw-r--r--gs/src/iname.h100
-rw-r--r--gs/src/inamedef.h207
-rw-r--r--gs/src/int.mak1223
-rw-r--r--gs/src/interp.c1565
-rw-r--r--gs/src/interp.h71
-rw-r--r--gs/src/ipacked.h124
-rw-r--r--gs/src/iparam.c1053
-rw-r--r--gs/src/iparam.h99
-rw-r--r--gs/src/iparray.h31
-rw-r--r--gs/src/ireclaim.c200
-rw-r--r--gs/src/iref.h376
-rw-r--r--gs/src/isave.c987
-rw-r--r--gs/src/isave.h106
-rw-r--r--gs/src/iscan.c1035
-rw-r--r--gs/src/iscan.h143
-rw-r--r--gs/src/iscanbin.c576
-rw-r--r--gs/src/iscannum.c377
-rw-r--r--gs/src/iscannum.h25
-rw-r--r--gs/src/isstate.h35
-rw-r--r--gs/src/istack.c500
-rw-r--r--gs/src/istack.h248
-rw-r--r--gs/src/istream.h32
-rw-r--r--gs/src/istruct.h65
-rw-r--r--gs/src/iutil.c599
-rw-r--r--gs/src/iutil.h107
-rw-r--r--gs/src/iutil2.c95
-rw-r--r--gs/src/iutil2.h41
-rw-r--r--gs/src/iutilasm.asm696
-rw-r--r--gs/src/ivmspace.h104
-rw-r--r--gs/src/jpeg.mak361
-rw-r--r--gs/src/lib.mak1278
-rw-r--r--gs/src/libpng.mak108
-rw-r--r--gs/src/main.h88
-rw-r--r--gs/src/malloc_.h46
-rw-r--r--gs/src/math_.h81
-rw-r--r--gs/src/memory_.h81
-rw-r--r--gs/src/msvc32.mak367
-rw-r--r--gs/src/msvccmd.mak185
-rw-r--r--gs/src/msvccom.mak225
-rw-r--r--gs/src/msvclib.mak342
-rw-r--r--gs/src/msvctail.mak39
-rwxr-xr-xgs/src/mv.cmd1
-rw-r--r--gs/src/opcheck.h67
-rw-r--r--gs/src/opdef.h138
-rw-r--r--gs/src/openvms.mak402
-rw-r--r--gs/src/oper.h95
-rw-r--r--gs/src/opextern.h103
-rw-r--r--gs/src/os2.mak553
-rw-r--r--gs/src/ostack.h88
-rw-r--r--gs/src/overlay.h38
-rwxr-xr-xgs/src/rm.cmd9
-rw-r--r--gs/src/rm_all.com15
-rw-r--r--gs/src/rm_one.com9
-rw-r--r--gs/src/sa85x.h40
-rw-r--r--gs/src/sbcp.c232
-rw-r--r--gs/src/sbhc.c269
-rw-r--r--gs/src/sbhc.h85
-rw-r--r--gs/src/sbtx.h34
-rw-r--r--gs/src/sbwbs.c471
-rw-r--r--gs/src/sbwbs.h66
-rw-r--r--gs/src/scanchar.h64
-rw-r--r--gs/src/scantab.c106
-rw-r--r--gs/src/scf.h176
-rw-r--r--gs/src/scfd.c781
-rw-r--r--gs/src/scfdgen.c203
-rw-r--r--gs/src/scfdtab.c938
-rw-r--r--gs/src/scfe.c500
-rw-r--r--gs/src/scfetab.c156
-rw-r--r--gs/src/scfx.h122
-rw-r--r--gs/src/scommon.h152
-rw-r--r--gs/src/sdct.h92
-rw-r--r--gs/src/sdctc.c33
-rw-r--r--gs/src/sdctd.c274
-rw-r--r--gs/src/sdcte.c165
-rw-r--r--gs/src/seexec.c177
-rw-r--r--gs/src/sfilter.h125
-rw-r--r--gs/src/sfilter1.c287
-rw-r--r--gs/src/sfilter2.c279
-rw-r--r--gs/src/sfxboth.c25
-rw-r--r--gs/src/sfxfd.c313
-rw-r--r--gs/src/sfxstdio.c241
-rw-r--r--gs/src/shc.c69
-rw-r--r--gs/src/shc.h245
-rw-r--r--gs/src/shcgen.c462
-rw-r--r--gs/src/shcgen.h50
-rw-r--r--gs/src/siscale.c483
-rw-r--r--gs/src/siscale.h131
-rw-r--r--gs/src/sjpeg.h70
-rw-r--r--gs/src/sjpegc.c264
-rw-r--r--gs/src/sjpegd.c84
-rw-r--r--gs/src/sjpege.c110
-rw-r--r--gs/src/sjpegerr.c80
-rw-r--r--gs/src/slzwc.c42
-rw-r--r--gs/src/slzwce.c155
-rw-r--r--gs/src/slzwd.c368
-rw-r--r--gs/src/slzwx.h66
-rw-r--r--gs/src/smtf.c166
-rw-r--r--gs/src/smtf.h38
-rw-r--r--gs/src/spcxd.c72
-rw-r--r--gs/src/spcxx.h25
-rw-r--r--gs/src/spdiff.c297
-rw-r--r--gs/src/spdiffx.h44
-rw-r--r--gs/src/spngp.c334
-rw-r--r--gs/src/spngpx.h50
-rw-r--r--gs/src/srld.c123
-rw-r--r--gs/src/srle.c194
-rw-r--r--gs/src/srlx.h65
-rw-r--r--gs/src/sstring.c435
-rw-r--r--gs/src/sstring.h61
-rw-r--r--gs/src/stat_.h46
-rw-r--r--gs/src/std.h220
-rw-r--r--gs/src/stdio_.h48
-rw-r--r--gs/src/stdpre.h378
-rw-r--r--gs/src/store.h238
-rw-r--r--gs/src/stream.c803
-rw-r--r--gs/src/stream.h318
-rw-r--r--gs/src/strimpl.h147
-rw-r--r--gs/src/string_.h48
-rw-r--r--gs/src/szlibc.c57
-rw-r--r--gs/src/szlibd.c94
-rw-r--r--gs/src/szlibe.c93
-rw-r--r--gs/src/szlibx.h54
-rw-r--r--gs/src/time_.h77
-rwxr-xr-xgs/src/turboc.cfg5
-rw-r--r--gs/src/ugcclib.mak158
-rwxr-xr-xgs/src/unix-cc.mak5775
-rw-r--r--gs/src/unix-end.mak137
-rwxr-xr-xgs/src/unix-gcc.mak5783
-rwxr-xr-xgs/src/unixansi.mak5771
-rw-r--r--gs/src/unixhead.mak76
-rw-r--r--gs/src/unixtail.mak144
-rw-r--r--gs/src/version.mak34
-rw-r--r--gs/src/vms-cc.mak102
-rw-r--r--gs/src/vms-decc.mak112
-rw-r--r--gs/src/vms-gcc.mak99
-rw-r--r--gs/src/vms.mak2245
-rw-r--r--gs/src/vmsmath.h37
-rw-r--r--gs/src/watc.mak230
-rw-r--r--gs/src/watclib.mak109
-rw-r--r--gs/src/watcw32.mak414
-rw-r--r--gs/src/wccommon.mak191
-rw-r--r--gs/src/wctail.mak75
-rw-r--r--gs/src/windows_.h39
-rw-r--r--gs/src/winint.mak96
-rw-r--r--gs/src/winlib.mak135
-rw-r--r--gs/src/wmin.mak60
-rw-r--r--gs/src/x_.h166
-rw-r--r--gs/src/zarith.c291
-rw-r--r--gs/src/zarray.c120
-rw-r--r--gs/src/zbseq.c269
-rw-r--r--gs/src/zchar.c661
-rw-r--r--gs/src/zchar1.c646
-rw-r--r--gs/src/zchar2.c317
-rw-r--r--gs/src/zchar42.c174
-rw-r--r--gs/src/zcharout.c234
-rw-r--r--gs/src/zcid.c91
-rw-r--r--gs/src/zcie.c627
-rw-r--r--gs/src/zcolor.c242
-rw-r--r--gs/src/zcolor1.c235
-rw-r--r--gs/src/zcolor2.c175
-rw-r--r--gs/src/zcontext.c709
-rw-r--r--gs/src/zcontrol.c804
-rw-r--r--gs/src/zcrd.c311
-rw-r--r--gs/src/zcsindex.c218
-rw-r--r--gs/src/zcssepr.c171
-rw-r--r--gs/src/zdevcal.c70
-rw-r--r--gs/src/zdevice.c362
-rw-r--r--gs/src/zdevice2.c330
-rw-r--r--gs/src/zdict.c494
-rw-r--r--gs/src/zdosio.c91
-rw-r--r--gs/src/zdouble.c488
-rw-r--r--gs/src/zdpnext.c438
-rw-r--r--gs/src/zdps.c182
-rw-r--r--gs/src/zdps1.c417
-rw-r--r--gs/src/zfbcp.c86
-rw-r--r--gs/src/zfcmap.c336
-rw-r--r--gs/src/zfdctc.c364
-rw-r--r--gs/src/zfdctd.c95
-rw-r--r--gs/src/zfdcte.c262
-rw-r--r--gs/src/zfdecode.c345
-rw-r--r--gs/src/zfile.c882
-rw-r--r--gs/src/zfileio.c782
-rw-r--r--gs/src/zfilter.c417
-rw-r--r--gs/src/zfilter2.c149
-rw-r--r--gs/src/zfilterx.c314
-rw-r--r--gs/src/zfname.c106
-rw-r--r--gs/src/zfont.c423
-rw-r--r--gs/src/zfont0.c319
-rw-r--r--gs/src/zfont1.c241
-rw-r--r--gs/src/zfont2.c547
-rw-r--r--gs/src/zfont42.c115
-rw-r--r--gs/src/zfproc.c332
-rw-r--r--gs/src/zfunc.c216
-rw-r--r--gs/src/zfunc0.c103
-rw-r--r--gs/src/zfzlib.c103
-rw-r--r--gs/src/zgeneric.c496
-rw-r--r--gs/src/zgstate.c453
-rw-r--r--gs/src/zhsb.c59
-rw-r--r--gs/src/zht.c243
-rw-r--r--gs/src/zht1.c143
-rw-r--r--gs/src/zht2.c326
-rw-r--r--gs/src/zimage.c477
-rw-r--r--gs/src/zimage2.c158
-rw-r--r--gs/src/ziodev.c396
-rw-r--r--gs/src/ziodev2.c134
-rw-r--r--gs/src/zlib.mak162
-rw-r--r--gs/src/zmath.c260
-rw-r--r--gs/src/zmatrix.c326
-rw-r--r--gs/src/zmedia2.c444
-rw-r--r--gs/src/zmisc.c308
-rw-r--r--gs/src/zmisc1.c140
-rw-r--r--gs/src/zmisc2.c243
-rw-r--r--gs/src/zpacked.c232
-rw-r--r--gs/src/zpaint.c80
-rw-r--r--gs/src/zpath.c178
-rw-r--r--gs/src/zpath1.c251
-rw-r--r--gs/src/zpcolor.c245
-rw-r--r--gs/src/zrelbit.c310
-rw-r--r--gs/src/zrop.c118
-rw-r--r--gs/src/zstack.c262
-rw-r--r--gs/src/zstring.c156
-rw-r--r--gs/src/zsysvm.c141
-rw-r--r--gs/src/ztoken.c227
-rw-r--r--gs/src/ztype.c463
-rw-r--r--gs/src/zupath.c561
-rw-r--r--gs/src/zusparam.c572
-rw-r--r--gs/src/zvmem.c365
-rw-r--r--gs/src/zvmem2.c151
-rw-r--r--gs/src/zwppm.c170
-rw-r--r--gs/unix-lpr.txt141
-rw-r--r--gs/use.txt1247
-rw-r--r--gs/xfonts.txt164
-rw-r--r--gs/zlib/ChangeLog239
-rw-r--r--gs/zlib/INDEX51
-rw-r--r--gs/zlib/Make_vms.com115
-rw-r--r--gs/zlib/Makefile130
-rw-r--r--gs/zlib/Makefile.in130
-rw-r--r--gs/zlib/Makefile.riscos46
-rw-r--r--gs/zlib/README99
-rw-r--r--gs/zlib/adler32.c48
-rw-r--r--gs/zlib/algorithm.doc105
-rw-r--r--gs/zlib/compress.c57
-rwxr-xr-xgs/zlib/configure86
-rw-r--r--gs/zlib/crc32.c162
-rw-r--r--gs/zlib/deflate.c1207
-rw-r--r--gs/zlib/deflate.h275
-rw-r--r--gs/zlib/descrip.mms48
-rwxr-xr-xgs/zlib/examplebin0 -> 44638 bytes
-rw-r--r--gs/zlib/example.c503
-rw-r--r--gs/zlib/gzio.c523
-rw-r--r--gs/zlib/infblock.c402
-rw-r--r--gs/zlib/infblock.h37
-rw-r--r--gs/zlib/infcodes.c247
-rw-r--r--gs/zlib/infcodes.h27
-rw-r--r--gs/zlib/inffast.c168
-rw-r--r--gs/zlib/inffast.h17
-rw-r--r--gs/zlib/inflate.c345
-rw-r--r--gs/zlib/inftrees.c470
-rw-r--r--gs/zlib/inftrees.h59
-rw-r--r--gs/zlib/infutil.c87
-rw-r--r--gs/zlib/infutil.h99
-rw-r--r--gs/zlib/libz.abin0 -> 50486 bytes
-rw-r--r--gs/zlib/makefile.b32104
-rw-r--r--gs/zlib/makefile.bor105
-rw-r--r--gs/zlib/makefile.dj293
-rw-r--r--gs/zlib/makefile.msc101
-rw-r--r--gs/zlib/makefile.sas64
-rw-r--r--gs/zlib/makefile.tc105
-rw-r--r--gs/zlib/makefile.wat103
-rwxr-xr-xgs/zlib/minigzipbin0 -> 41362 bytes
-rw-r--r--gs/zlib/minigzip.c246
-rw-r--r--gs/zlib/trees.c1141
-rw-r--r--gs/zlib/uncompr.c58
-rw-r--r--gs/zlib/zconf.h184
-rw-r--r--gs/zlib/zlib.def46
-rw-r--r--gs/zlib/zlib.h780
-rw-r--r--gs/zlib/zlib.rc32
-rw-r--r--gs/zlib/zutil.c211
-rw-r--r--gs/zlib/zutil.h203
1230 files changed, 387163 insertions, 0 deletions
diff --git a/gs/bug-form.txt b/gs/bug-form.txt
new file mode 100644
index 000000000..a97f57aa1
--- /dev/null
+++ b/gs/bug-form.txt
@@ -0,0 +1,61 @@
+ Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, bug-form.txt, contains an e-mailable form for reporting problems.
+Please read the section titled "If you need help" in new-user.txt before
+using the form below. For an overview of Ghostscript and a list of the
+documentation files, see README.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Please e-mail the completed form to ghost@aladdin.com. We can't promise to
+investigate every reported problem, but we do give priority to those
+reported using this form. Thanks.
+
+------snip------snip------snip------snip------snip------snip------snip------
+
+Ghostscript version:
+
+Where you got Ghostscript:
+
+Hardware you are using:
+
+Operating system you are using:
+
+(If you compiled Ghostscript yourself)
+C compiler you are using (including compiler version):
+
+(If you compiled Ghostscript yourself)
+Changes you made to the makefile(s), if any:
+
+Environment variables (GS_DEVICE, GS_FONTPATH, GS_LIB, GS_OPTIONS):
+
+Command line:
+
+URL or FTP location of test file(s)
+(or include the data at the end of this form if short):
+
+(Use as much space as you need for the remaining items.)
+Symptoms:
+
+Suggested fix (if any):
+
+Other comments:
+
+------snip------snip------snip------snip------snip------snip------snip------
diff --git a/gs/c-style.txt b/gs/c-style.txt
new file mode 100644
index 000000000..1b59f99b1
--- /dev/null
+++ b/gs/c-style.txt
@@ -0,0 +1,329 @@
+ Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, c-style.txt, describes Aladdin's C coding guidelines.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Generalities
+============
+
+All the rules below are meant to produce code that is easy to read. If you
+find a rule getting in your way or producing ugly-looking results once in a
+while, it's OK to break it.
+
+Indentation
+-----------
+
+Tab stops are set every 8 columns. However, tabs are not equivalent to
+logical nesting levels for C code: see below for details.
+
+File layout
+-----------
+
+Every code file should start with comments containing a copyright notice,
+the name of the file, and a half-to-one-line summary of what the file
+contains. If you create a file by copying the boilerplate from another
+file, make sure to edit the copyright year and the file name.
+
+C code
+======
+
+makefiles
+---------
+
+For each #include "xxx.h", make sure there is a dependency on $(xxx_h) in
+the makefile. If xxx ends with a _, this rule still holds: e.g., #include
+"math_.h" should create a dependency on $(math__h) (two underscores).
+
+List the dependencies bottom-to-top, like the #includes themselves; within
+each level, list them alphabetically. Also do this with the #includes
+themselves whenever possible (but sometimes there are inter-header
+dependencies that require bending this).
+
+Headers
+-------
+
+In header files, always use the following to prevent double inclusion:
+
+ << copyright notice, file name, 1-line file description >>
+
+ #ifndef <filename>_INCLUDED
+ # define <filename>_INCLUDED
+
+ << contents of file >>
+
+ #endif /* <filename>_INCLUDED */
+
+The header file is the first place that a reader will go to find out
+information about procedures, structures, constants, etc. Make sure that
+every procedure and structure has a comment that says what it does. Divide
+procedures into meaningful groups set off by some distinguished form of
+comment.
+
+#include lists
+--------------
+
+List #includes from "bottom" to "top", i.e., in the following order:
+ System includes ("xxx_.h")
+ g*.h
+ s*.h
+ pl*.h
+ p[cg]*.h
+
+Indentation
+-----------
+
+Put the first indentation point at the first tab stop; thereafter, each
+level of logical nesting indents by an additional 4 columns. Proceed as
+follows:
+
+ { ... in-line compound statement ...
+ ... (indented +2 columns)
+ }
+ ... construct requiring subordinate code ...
+ ... subordinate simple statement ... (indented +2 columns)
+ ... construct requiring subordinate code ...
+ { ... subordinate code ...
+ ... (indented +4 columns)
+ }
+
+Or you can do this if you prefer:
+
+ {
+ ... in-line compound statement ...
+ }
+ ... construct requiring subordinate code ...
+ ... subordinate simple statement ...
+ ... construct requiring subordinate code ...
+ {
+ ... subordinate code ...
+ }
+
+But not this:
+
+ if ... {
+ ... subordinate code ...
+ } else {
+ ... subordinate code ...
+ }
+
+Spaces
+------
+
+Do put a space:
+ - after every comma and semicolon, unless it ends a line;
+ - around every binary operator, although you can omit the spaces
+ around the innermost operator in a nested expression if you like;
+ - on both sides of the the parentheses of an if, for, or while.
+
+Don't put a space:
+ - at the end of a line;
+ - before a comma or semicolon;
+ - after unary prefix operators;
+ - before the parenthesis of a macro or procedure call.
+
+Parentheses
+-----------
+
+There are just a few places where parentheses are important:
+
+ - In expressions that mix && and ||, around the inner
+ subexpressions, even if not required by precedence, e.g.,
+ (xx && yy) || zz
+
+ - In expressions that mix &, |, and/or shifts, especially if
+ mixing these with other operators, around the inner subexpressions
+ similarly, e.g.,
+ (x << 3) | (y >> 5)
+
+ - In macro definitions, around every use of an argument that
+ logically could be an expression, e.g.,
+ ((x) * (x) + (y) * (y))
+
+Anywhere else, given the choice, use fewer parentheses.
+
+For stylistic consistency with the existing Ghostscript code, put
+parentheses around conditional expressions, even if they aren't
+syntactically required, unless you really dislike doing this. Note that the
+parentheses should go around the entire expression, not the condition: e.g.,
+instead of
+
+ hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
+ (pgls->g.pen_down) ? gs_lineto : gs_moveto);
+
+use
+
+ hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
+ (pgls->g.pen_down ? gs_lineto : gs_moveto));
+
+Types
+-----
+
+Use 'private' instead of 'static' for constructs (procedures and variables)
+declared at the outermost scope. This allows making such constructs either
+visible or invisible to profilers with a single changed #define.
+
+Use const wherever possible and appropriate.
+
+If you find yourself wanting to use void *, try to find an alternative using
+unions or (in the case of super- and subclasses) casts, unless you're
+writing something like a memory manager that really treats memory as opaque.
+
+Use anonymous structures as little as possible. Declare structure types
+like this (the _t on the type name is preferable but not required):
+
+ typedef struct xxx_yyy_s {
+ ... members ...
+ } xxx_yyy_t;
+
+Don't declare parameters as being of type float, short, or char. If you do
+this and forget to include the prototype at a call site, ANSI compilers will
+generate incompatible calling sequences. Use floatp (a synonym for double)
+instead of float, and use [u]int instead of short or char.
+
+If you have a parameter that is itself a procedure, do list its parameter
+types rather than just using ().
+
+Names
+-----
+
+Use fully spelled-out English words in names rather than contractions. This
+is most important for procedure and macro names, global variables and
+constants, #defined and enum values, structure and other typedef names, and
+structure member names, and for argument and variable names which have
+uninformative types like int. It's not very important for arguments or
+local variables of distinctive types, or for local index or count variables.
+
+Avoid names that run English words together. hpgl_compute_arc_center is
+preferable to hpgl_compute_arccenter.
+
+Procedures, variables, and structures visible outside a single .c file
+should generally have a prefix that indicates what subsystem they belong to
+(in the case of Ghostscript, gs_ or gx_). This rule isn't followed very
+consistently.
+
+Commenting
+----------
+
+The most important descriptive comments are ones in header files that
+describe structures, including invariants. But every procedure or structure
+declaration, or group of other declarations, should have a comment.
+
+Other formatting
+----------------
+
+Format procedures as follows:
+
+scope return_type
+proc_name(type1 arg1, type2 arg2, type3 arg3, type4 verylongargument4,
+ type5 argument5)
+{ ... body ...
+}
+
+Leave a blank line after the declarations of local variables in a procedure
+or compound statement, unless there's only 1 variable and the scope is less
+than 10 lines or so.
+
+Other
+-----
+
+When calling a variable or parameter procedure, do use explicit indirection,
+e.g., (*func)(...) rather than func(...). It makes it clearer to the reader
+what is going on. Also, not all compilers accept the elision. (gcc accepts
+a dismaying number of constructs that other compilers dislike.)
+
+ANSI compilers in their default mode do all floating point computations in
+double precision, so never cast a float to a double explicitly.
+
+Unless there's a good reason for doing otherwise, return floatp (double)
+rather than float values. Many FPUs do everything in double internally and
+have to do extra work to convert between double and float.
+
+In general, don't create procedures that are private and only called from
+one place. However, if a compound statement (especially an arm of a
+conditional) is long enough that the eye can't easily match up its } with
+its { (i.e., it's longer than 10 or 15 lines), and it doesn't use or set a
+lot of state held in outer local variables, putting it in a procedure may
+help readability.
+
+Global variables
+----------------
+
+Avoid global variables (non-const data) like the plague. Avoid global const
+data, but don't knock yourself out over it.
+
+Local variables
+---------------
+
+Avoid assigning new values to procedure parameters. It makes debugging very
+confusing when the parameter values printed for a procedure are not the ones
+actually supplied by the caller. Instead, use a separate local variable
+that is initialized to the value of the parameter.
+
+If a local variable only gets assigned a value once, assign it that value at
+its declaration, if convenient. E.g.,
+
+ int x = <some expression>;
+
+rather than
+
+ int x;
+ ...
+ x = <some expression>;
+
+Error handling
+--------------
+
+By convention, nearly all procedures return an int that indicates the
+outcome of the call: 0 indicates a normal return, >0 indicates a non-error
+return other than the normal case, and <0 indicates an error. All callers
+should check for error returns and, in general, propagate them to *their*
+caller.
+
+Preprocessor conditionals
+-------------------------
+
+Conditionals can easily lead to unreadable code, since the eye really wants
+to read linearly rather than having to parse the conditionals just to figure
+out what code is relevant. It's OK to use conditionals that have small
+scope and that don't change the structure or logic of the program
+(typically, they select between different sets of values depending on some
+configuration parameter), but where possible, break up source modules rather
+than use conditionals that affect the structure or logic.
+
+Preprocessor macros
+-------------------
+
+If you define a macro that looks like a procedure, make sure it will work
+wherever a procedure will work. In particular, put parentheses around every
+use of a macro argument, so that the macro will parse correctly if some of
+the arguments are expressions.
+
+PostScript code
+===============
+
+Put indentation points every 3 spaces.
+
+Format procedure definitions like this:
+
+/procname % <arg1> <arg2> procname <result1> <result2>
+ { ...code...
+ } bind def
diff --git a/gs/commprod.txt b/gs/commprod.txt
new file mode 100644
index 000000000..e1ec055b5
--- /dev/null
+++ b/gs/commprod.txt
@@ -0,0 +1,220 @@
+ Copyright (C) 1993, 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+Permission to copy and distribute this document unmodified for any
+purpose is hereby granted without fee, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, commprod.txt, sets forth the conditions under which Ghostscript
+may be distributed in a commercial context: under a written license from
+Artifex Software Inc., Aladdin Enterprises' exclusive commercial licensing
+partner, or under certain other very limited conditions.
+
+For an overview of Ghostscript and a list of the documentation files, see
+the README file in the Ghostscript fileset.
+
+
+ The Use of the Public Access "Free" Version of Ghostscript
+ ----------------------------------------------------------
+
+Ghostscript is a copyrighted work whose copyright is owned by Aladdin
+Enterprises. Some versions of Ghostscript are distributed freely under the
+name Aladdin Ghostscript; these versions are always distributed with a
+license, called the Aladdin Ghostscript Free Public License (also known as
+the AGFPL), which permits Aladdin Ghostscript to be redistributed freely
+under certain conditions. These conditions will almost always be met easily
+by individuals in their personal use of Aladdin Ghostscript. Aladdin
+Ghostscript may be *used* freely, including by commercial entities for
+evaluation or unsupported internal use. However, *distribution* for
+commercial purposes of Ghostscript, or anything containing or derived from
+Ghostscript in whole or in part, generally requires a written commercial
+license from Artifex Software Inc., the sole entity authorized by Aladdin
+Enterprises to grant such licenses. More specifically, the AGFPL states:
+
+ Distribution of the Program or any work based on the Program by a
+ commercial organization to any third party is prohibited if any payment is
+ made in connection with such distribution, whether directly (as in payment
+ for a copy of the Program) or indirectly (as in payment for some service
+ related to the Program, or payment for some product or service that
+ includes a copy of the Program "without charge"; these are only examples,
+ and not an exhaustive enumeration of prohibited activities). However, the
+ following methods of distribution involving payment shall not in and of
+ themselves be a violation of this restriction:
+
+ (i) Posting the Program on a public access information storage and
+ retrieval service for which a fee is received for retrieving information
+ (such as an on-line service), provided that the fee is not
+ content-dependent (i.e., the fee would be the same for retrieving the same
+ volume of information consisting of random data).
+
+ (ii) Distributing the Program on a CD-ROM, provided that the files
+ containing the Program are reproduced entirely and verbatim on such
+ CD-ROM, and provided further that all information on such CD-ROM be
+ redistributable for non-commercial purposes without charge.
+
+The intent of the exception provided in clause (i) is to allow commercial
+organizations operating an FTP server or a bulletin board to distribute
+Aladdin Ghostscript freely from it, provided that:
+
+ (1) the organization complies with the other provisions of the
+AGFPL, which include among other things a requirement to distribute the
+full source code of Aladdin Ghostscript and of any derived work, and to
+distribute the AGFPL itself along with Aladdin Ghostscript;
+
+ (2) the only charge for downloading Aladdin Ghostscript is a charge
+based on the distribution service and not one based on the content of the
+information being retrieved (i.e., the charge would be the same for
+retrieving a random collection of bits of the same size);
+
+ (3) the server or BBS is accessible to the general public, i.e.,
+the phone number or IP address is not kept secret, and anyone may obtain
+access to the information (possibly by paying a subscription or access fee
+that is not dependent on or related to purchasing anything else).
+
+Similarly, the exception in clause (ii) is intended to allow inclusion of
+Aladdin Ghostscript on "freeware" CD-ROMs that contain only material that is
+in the public domain, or is freely redistributable provided only that a
+copyright notice is retained (such as the Independent JPEG Group libraries),
+or is distributed under some other kind of license allowing free
+redistribution such as the GNU General Public License.
+
+If you want to distribute software in a commercial context that incorporates
+Ghostscript and you do *not* want to meet these conditions, you should
+contact Artifex Software to find out about commercial licensing. Commercial
+licenses involve a (negotiated) payment, and include support and other
+benefits. These are the only ways you legally can distribute Ghostscript or
+anything containing Ghostscript: either by distributing Aladdin Ghostscript
+under the requirements of the AGFPL, or by getting a commercial license from
+Artifex Software.
+
+For commercial licensing, please contact:
+
+ Miles Jones
+ Director of Marketing
+ Artifex Software Inc.
+ 454 Las Gallinas Ave., suite 108
+ San Rafael, CA 94903 U.S.A.
+ voice +1-415-492-9861
+ fax +1-415-492-9862
+ e-mail: info@arsoft.com
+
+If you have any questions about any of the information in this document,
+please contact:
+
+ Aladdin Enterprises
+ 203 Santa Margarita Ave.
+ Menlo Park, CA 94025 U.S.A.
+ voice +1-650-322-0103 (8:30 AM - noon, Monday - Friday)
+ fax +1-650-322-1734
+ e-mail: ghost@aladdin.com
+
+Appendix: The GNU General Public License
+----------------------------------------
+
+Older versions of Ghostscript (versions of 2.6.1 and previous) were
+distributed with a license called the GNU General Public License (also known
+as the "GNU License", the "GPL", or the "copyleft"), which allowed
+distribution with commercial products under certain conditions. Aladdin
+Enterprises may choose to distribute other versions of Ghostscript with the
+GPL in the future; however, these versions will be identified as "GNU
+Ghostscript." The remainder of this Appendix applies only to versions
+identified explicitly as GNU Ghostscript versions; the generic name
+Ghostscript, when applied to versions above 2.6.1, refers to Aladdin
+Ghostscript, which is governed by the Aladdin Ghostscript Free Public
+License, not the GPL.
+
+For those unfamiliar with the GPL, we now summarize its provisions. The
+full GPL is included under the name COPYING in the fileset that comprises
+GNU Ghostscript, and can also be obtained from:
+ Free Software Foundation, Inc. (FSF)
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307
+ U.S.A.
+ tel. +1-617-542-5942
+ fax (including Japan): +1-617-542-2652
+ e-mail gnu@prep.ai.mit.edu
+ Free Dial Fax (in Japan): 0031-13-2473 (KDD)
+ 0066-3382-0158 (IDC)
+In case of doubt or conflict, the contents of the COPYING file or the
+document obtained from the FSF, not this summary, are authoritative.
+
+ 1. Anyone may copy and distribute GNU Ghostscript (both source and
+object code), but they must distribute the source code as well as the
+object code (or, if they distribute only the object code, they must
+include an offer in writing to provide the source code at no more than
+reproduction cost), keep all copyright and other notices, and include the
+GPL with the copies. (Note that this allows anyone receiving such a copy
+to distribute it freely as well.)
+
+ 2. Anyone may modify GNU Ghostscript, but the provisions of #1
+apply to modified or derived works as well.
+
+ 3. GNU Ghostscript may be "aggregated" with another program; in
+this case, #1 and #2 do not apply to the other program, but only to GNU
+Ghostscript.
+
+Provision #1 makes it much harder to have a commercial business based only
+on selling copies of GNU Ghostscript (as distributed with the GPL) or
+products that contain GNU Ghostscript, since any customer is free to make
+as many copies as they want for any purpose. Provision #2 effectively
+prevents the development of proprietary commercial products that
+incorporate GNU Ghostscript without a commercial license as a part, since
+these are "derived works" in the legal sense.
+
+Questions have arisen at times in particular cases regarding provision #3
+as to whether GNU Ghostscript is "aggregated" with other parts of a
+commercial product, or whether the product has become a "derived work."
+Normally, combining GNU Ghostscript with another piece of software creates
+a "derived work"; we consider GNU Ghostscript to be "aggregated" with
+another piece of software, which we will refer to as "the application",
+only if all of the following conditions are met:
+
+ - The code and documentation for GNU Ghostscript are physically
+ separated from the code and documentation for the application.
+ For electronic form, it is both necessary and sufficient to put
+ the GNU Ghostscript code and documentation in their own directory
+ tree(s).
+
+ - GNU Ghostscript, as delivered with the application, is usable
+ independently of the application. More precisely, if a user
+ deletes from the computer system all files delivered with the
+ application except those in the GNU Ghostscript directories, the
+ user will still be able to use GNU Ghostscript as described in
+ GNU Ghostscript's documentation. Among other things, this
+ requires that GNU Ghostscript not call any routines in the
+ application, and not require any data or other files supplied as
+ part of the application.
+
+ - The application calls GNU Ghostscript in a way that allows an
+ ordinary user to substitute another program for GNU Ghostscript.
+ (Typically this requires use of a shell script or batch file, or a
+ system call like `exec'.) More precisely, if the user deletes
+ from the computer system all the files in the GNU Ghostscript
+ directories, and replaces the GNU Ghostscript executable with
+ another program with the same name and conforming to the same
+ documentation, the application will continue to work with it. One
+ implication of this is that the GNU Ghostscript documentation must
+ specify all properties of GNU Ghostscript on which the application
+ relies; for example, if GNU Ghostscript has been modified by the
+ addition of command line switches or language elements such as new
+ operators, the documentation must describe any such additions that
+ the application uses.
+
+ - The conditions of the GPL are met with respect to GNU
+ Ghostscript, including the requirement for propagation of the GPL
+ and the requirement for delivering (or an offer to deliver) source
+ code.
+
+Regarding this last point, the GPL clearly intends that if the distributor
+only offers to provide the GNU Ghostscript source code (as opposed to
+actually distributing the source code with every copy of the application),
+then they must deliver the source code in a timely way to anyone
+requesting it.
+
+The GPL makes it clear that if someone receives GNU Ghostscript only in
+its GPL-licensed form, they only have a right to distribute it if they
+comply with the GPL. Aladdin Enterprises, as the copyright holder, takes
+this requirement very seriously, and will, if necessary, take legal action
+to ensure that anyone distributing GNU Ghostscript with the GPL complies
+with the conditions set forth above.
diff --git a/gs/copying b/gs/copying
new file mode 100644
index 000000000..1d6e21632
--- /dev/null
+++ b/gs/copying
@@ -0,0 +1,10 @@
+
+ THIS IS *NOT* THE GNU GENERAL PUBLIC LICENSE
+
+ Many versions of Ghostscript, including all versions created before
+June 1993, are customarily distributed with a license called the GNU
+General Public License; in these versions, a file named COPYING contains a
+copy of the license. This copy of Ghostscript is governed not by the GNU
+License, but by a substantially different license in a similar spirit, the
+Aladdin Ghostscript Free Public License; the file PUBLIC contains a copy of
+this license.
diff --git a/gs/current.txt b/gs/current.txt
new file mode 100644
index 000000000..e2c281abe
--- /dev/null
+++ b/gs/current.txt
@@ -0,0 +1,119 @@
+ Copyright (C) 1990, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, current.txt, describes problems and new features in the current
+release of Ghostscript. This file describes version 5.13 of Ghostscript.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+New features (since release 5.03)
+============
+
+(This is not a complete list of new features: see NEWS for details.)
+
+ps2pdf (and the pdfwrite device) now produces much more compact output. By
+default, the output is compatible only with Acrobat 3.x; for Acrobat
+2.x-compatible output, use
+ ps2pdf -dCompatibilityLevel=1.1 ...
+
+ps2pdf now has more flexibility about the handling of unencoded glyphs. See
+gdevpdft.c for details.
+
+ps2pdf now recognizes the CompressPages, CompatibilityLevel, and
+UseFlateCompression device (distiller) parameters.
+
+The PDF interpreter now handles Lab and Separation color spaces, images with
+color space resources, embedded font subsets, undefined operators with
+BX/EX, and Functions.
+
+Changes
+=======
+
+The RGB<->CMYK conversion rules have been changed back to Adobe's documented
+rules.
+
+Known problems
+==============
+
+(This is not a complete list of known problems: see NEWS for details.)
+
+Usage
+-----
+
+On a MS-DOS system, interrupting the interpreter by typing ^C doesn't
+restore the display mode.
+
+Limitations
+-----------
+
+serialnumber returns the same value in all copies.
+
+Some floating point exceptions terminate the interpreter, rather than
+producing a limitcheck error.
+
+The DCTEncode filter disregards the Blend parameter, and uses different
+QuantTables and HuffTables from Adobe's.
+
+The DCT filters do not support nonintegral sample ratios. Also, DCTEncode
+will not create files with Sum(HS*VS)>10 (regardless of the value of the
+Relax parameter) because they violate the JPEG standard; but DCTDecode will
+read such files.
+
+The size of the execution stack cannot be changed dynamically. (However,
+the sizes of the operand and dictionary stacks can be changed.)
+
+Separation color spaces are implemented, but devices that actually produce
+color separations are not supported. The special color separations All and
+None, and the primary separations (Red, Green, etc.), are not supported.
+
+execform and ucache are implemented, but they do not actually do any
+caching; setucacheparams and ucachestatus are dummies. (This only impacts
+performance, not functionality.)
+
+The image operator only honors the Interpolate flag in the image dictionary
+if the combined transformation (ImageMatrix + CTM) doesn't involve rotation,
+skewing, or X-reflection; imagemask doesn't honor Interpolate at all.
+
+Some path building operations that would generate a device coordinate larger
+than +/-2^19 will cause a limitcheck. However, the common ones ([r]moveto,
+[r]lineto, [r]curveto, closepath) will not.
+
+Graphics bugs
+-------------
+
+Opening more than one window device at the same time doesn't work.
+This is the case for both X Windows and Microsoft Windows.
+
+cshow doesn't work with composite fonts.
+
+Non-graphics bugs
+-----------------
+
+The %statementedit pseudo-file is equivalent to %lineedit. As a
+consequence, the interactive interpreter requires that every statement fit
+on a line, i.e., you can't have an unpaired (, {, or <.
+
+The following operators that expect arrays won't accept packed arrays:
+ definefont (Subrs (type 1 fonts))
+
+Syntax errors occurring within a binary token do not produce the error
+message specified by the Adobe documentation.
+
+save doesn't save, and restore doesn't restore, the user parameters.
diff --git a/gs/devices.txt b/gs/devices.txt
new file mode 100644
index 000000000..ff2d2bc97
--- /dev/null
+++ b/gs/devices.txt
@@ -0,0 +1,2352 @@
+ Copyright (C) 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, devices.txt, gives more detailed documentation about
+certain specific devices for which Ghostscript can produce output.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Devices for which this file currently contains documentation:
+ SPARCprinter
+ HP DeskJet 520, 540, and 560C
+ HP DeskJet 500C & 550C
+ HP PaintJet, XL, and XL300
+ DEC LJ250
+ Apple Dot Matrix Printer (and Imagewriter)
+ Epson Stylus Color Printer
+ ESC/P, ESC/P2 Color-Printers
+ Canon BJC-600/BJC-4000/BJC-70 and BJC-800 BubbleJet Color Printers
+ (and Apple StyleWriter 2x00)
+ uniprint - a configurable ESC/P, ESC/P2 & HP-RTL/PCL-Driver
+ JPEG files
+
+### ------------------------- The SPARCprinter ------------------------- ###
+
+This section was written by Martin Schulte.
+
+Introduction
+------------
+
+The SPARCprinter is is connected to SPARCStation via a special SBUS card's
+video interface, the picture is composed on the host and only a bitmap is
+send to the printer unit.
+
+Together with a SPARCprinter, you always buy (as far as I know) software
+that enables you to do postscript-printing on your SPARCPrinter.
+
+So, the need for a Ghostscript-Interface to the SPARCPrinter seems low,
+but on the other hand some Postscript drawings are not correctly printed
+with SUN's software: on some pages occurred a thin vertical line of rubbish
+(reproduceable), on some Mathematica drawings the text at the axes wasn't
+rotated.
+
+I tried all of these with Ghostscript and always got the expected results.
+
+However, replacing proprietary software should never be a bad idea.
+
+The problem is that there has yet been no effort to make the SPARCPrinter-
+driver behave like a BSD output-filter, I made my tests using the script
+mentioned under Installation.
+
+Installation
+------------
+
+Add sparc.dev to DEVICE_DEVS and compile ghostscript as described in
+make.txt.
+
+Afterwards, you can use the following script (the way of handling standard
+input versus filename-arguments doesn't look very clever, has anyone a
+better idea ?) to print if you substitute <GSPATH> by the place where you
+installed the ghostscript binary:
+
+outcmd1='/vol/local/lib/troff2/psxlate -r'
+outcmd2='<GSPATH> -I/home/schulte/gs252 -sDEVICE=sparc -sOUTPUTFILE=/dev/lpvi0 -'
+
+if [ $# -eq 0 ]
+then
+ $outcmd1 | $outcmd2
+else
+ cat $* | $outcmd1 | $outcmd2
+fi
+
+Problems
+--------
+
+Since /dev/lpvi can only be opened for exclusive use, another job having
+opened it (engine_ctl_sparc or another ghostscript as the most probable
+candidates) will cause to stop ghostscript with "Error: /invalidfileaccess
+in --.outputpage--"
+
+In case of common printer problems like out of paper, a warning describing
+the reason will be printed to stdout, the driver will try to access again
+and again each five seconds.
+
+Due to a problem with the device-driver (in the kernel) the reason of
+printer failure is not always correctly reported to program. This is the
+case at least if you open the top cover (Error in the display: E5). Look
+to the display at the printer if a "Printer problem with unknown reason"
+is reported.
+
+Fatal errors will cause the print-job to be terminated.
+
+### ------------------------------ End --------------------------------- ###
+
+### ------------------- H-P color inkjet printers ---------------------- ###
+### (DeskJet 500C, DeskJet 550C, PaintJet, PaintJet XL, PaintJet XL300 ###
+### and the DEC LJ250 which can operate in a Paintjet-compatible mode) ###
+
+This section was written by George Cameron.
+
+Information and tips on usage for the drivers contained in gdevcdj.c
+====================================================================
+
+OVERVIEW:
+
+There are 6 generic drivers contained in the source module:
+
+ 1 - cdj500: HP DeskJet 500C and 540C
+ 2 - cdj550: HP DeskJet 550C, 560C, 660C, 660Cse
+ 3 - pjxl300: HP PaintJet XL300 and DeskJet 1200C
+ 4 - pjtest: HP PaintJet
+ 5 - pjxltest: HP PaintJet XL
+ 6 - declj250: DEC LJ250
+
+ All of these drivers have 8-bit (monochrome), 16-bit and 24-bit
+ (colour) and for the DJ 550C 32-bit, (colour, cmyk mode)
+ options in addition to standard colour and mono drivers.
+ It is also possible to set various printer-specific parameters
+ from the gs command line, eg.
+
+ gs -sDEVICE=cdeskjet -dBitsPerPixel=16 -dDepletion=1 -dShingling=2 tiger.ps
+
+NB/ The old names cdeskjet, cdjcolor and cdjmono drivers have been retained;
+ however, their functionality duplicates that available using the above
+ drivers (and cdeskjet is identical to cdj500), ie. we can use:
+
+ gs -sDEVICE=cdj500 -dBitsPerPixel=24 ... for cdjcolor, and
+ gs -sDEVICE=cdj500 -dBitsPerPixel=1 ... for cdjmono
+
+
+DEFAULT PAPER SIZE:
+
+ If the preprocessor symbol A4 is defined, the default paper size is the
+ European A4 size; otherwise it is the U.S. letter size (8.5"x11"). Other
+ paper sizes (including A3 for the PaintJet XL and PaintJet XL300) may be
+ specified on the command line as explained in the Ghostscript documentation.
+
+
+DEFAULT BITS-PER-PIXEL:
+
+ If the preprocessor symbol BITSPERPIXEL is defined as an integer (see below
+ for the range of allowable values), this number will be used to define the
+ default bits-per-pixel (ie. bit depth) for the generic drivers. If the
+ symbol is not defined, the default is set to 24 bits per pixel. It is
+ of course still possible to specify the value from the command line, as
+ described below. Note also that the cdeskjet, cdjcolor and cdjmono
+ drivers are unaffected by setting this symbol, as their default settings
+ are predefined to be 1, 3 and 24 respectively.
+
+
+DESKJET PHYSICAL LIMITS:
+
+ Maximum printing width = 2400 dots = 8". The printer manuals say that the
+ maximum recommended printing height on the page is 10.3", but since this
+ is obviously not true for A4 paper, and I have been unable to detect any
+ problems in printing longer page lengths, this would seem to be a rather
+ artificial restriction.
+
+ All Deskjets have 1/2" unprintable bottom margin, due to the mechanical
+ arrangement used to grab the paper. Side margins are approximately 0.25"
+ for US Letter paper, and 0.15" for A4.
+
+
+COMMAND LINE PARAMETERS:
+
+ Several printer 'properties' have been implemented for these printers.
+ Those available so far are all integer quantities, and thus may be
+ specified as eg.
+
+ gs -dBitsPerPixel=32 -dShingling=1 ...
+
+ which sets the BitsPerPixel parameter to 32 and the Shingling parameter
+ to 1.
+
+
+BITS-PER-PIXEL:
+
+ All of the drivers in gdevcdj.c accept a command line option to set the
+ BitsPerPixel property. This gives considerable flexibility in choosing
+ various trade-offs between speed/quality/colour etc. The valid numbers
+ are:
+
+ 1: This is a standard Ghostscript monochrome driver, and uses
+ black ink (by installing the separate mono cartridge in
+ the case of the DeskJet 500C, or automatically for the
+ other printers)
+
+ 3: A standard Ghostscript colour driver, using internal
+ dithering. This is fast to compute and to print, but
+ the clustered dithering can lose some detail and
+ colour fidelity.
+
+ 8: An 'error-diffusion' monochrome driver which uses
+ Floyd-Steinberg dithering to print greyscale images.
+ The patterns are much more randomised than with the
+ normal clustered dithering, but the data files can
+ be much larger and somewhat slower to print.
+
+ 16: This is a 'cheaper' version of the following (24-bit)
+ driver, which generates a Floyd-Steinberg colour dithered
+ output using the minimum amount of memory (this may be
+ helpful when using IBM PC's when Ghostscript has not
+ been compiled using a 32-bit 386-style compiler). The
+ quality can be almost as good as the 24-bit version.
+
+ 24: A high-quality colour driver using Floyd-Steinberg dithering
+ for maximum detail and colour range. However it is very
+ memory intensive and thus can be slow to compute (and it
+ tends to produce rather larger raw data files, so they
+ can also be slower to print).
+
+ 32: This is for the DeskJet 550C only, which uses the black
+ cartridge and the colour cartridge simultaneously (ie.
+ CMYK printing). This printer can be both faster and give
+ higher quality than the DeskJet 500C, because of the
+ true black ink. (Note that the 24-bit mode also permits
+ CMYK printing on this printer, and uses less memory. Any
+ differences between 24-bit and 32-bit should be very small.)
+
+
+DESKJET PROPERTIES:
+
+ The additional properties available for the DeskJets are:
+
+ BlackCorrect (int) /* Colour correction to give
+ * better blacks when using the DJ500C
+ * in colour mode, eg. the default of 4
+ * reduces the cyan component to 4/5
+ * Range accepted: 0 - 9 (0 = none) */
+ Shingling (int) /* Interlaced, multi-pass printing
+ * 0 = none, 1 = 50%, 2 = 25%, 2 is
+ * best & slowest */
+ Depletion (int) /* 'Intelligent' dot-removal
+ * 0 = none, 1 = 25%, 2 = 50%, 1 best
+ * for graphics?
+ * Use 0 for transparencies */
+
+PAINTJET XL300/PAINTJET XL PROPERTIES:
+
+ PrintQuality (int) /* Mechanical print quality
+ * -1 = fast, 0 = normal, 1 = presentation
+ * Fast mode reduces ink usage and uses
+ * single-pass operation for some media
+ * types. Presentation uses more ink and
+ * max number of passes, ie. slowest
+ * printing for highest quality */
+ RenderType (int) /* 0 = driver does dithering
+ * 1 = snap to primaries
+ * 2 = snap black -> white, others to black
+ * 3 = ordered dither
+ * 4 = error diffusion
+ * 5 = monochrome ordered dither
+ * 6 = monochrome error diffusion
+ * 7 = cluster ordered dither
+ * 8 = monochrome cluster ordered dither
+ * 9 = user-defined dither (not supported)
+ * 10 = monochrome user-defined dither ns. */
+
+PAINTJET PROPERTIES:
+
+ No additional properties
+
+
+GAMMA CORRECTION:
+
+ One consequence of using Floyd-Steinberg dithering rather than Ghostscript's
+ default clustered ordered dither is that it is much more obvious that the
+ ink dots are rather larger on the page than their nominal 1/180" or 1/300"
+ size (clustering the dots tends to minimise this effect). Thus it is often
+ the case that the printed result is rather too dark. A simple empirical
+ correction for this may be achieved by preceding the actual postscript
+ file to be printed by a short file which effectively sets the gamma for
+ the device, eg.
+
+ gs ... gamma.ps colorpic.ps -c quit
+
+ where gamma.ps is
+
+%!
+{0.333 exp} dup dup currenttransfer setcolortransfer
+
+ This example sets the gamma for r, g, and b to 3, which seems to work
+ reasonably well in practice.
+
+
+GENERAL TIPS:
+
+ For all the above printers, the paper is critically important to the
+ final results. Smoother, less fibrous paper is generally better (and
+ suggested types are given in the printer manuals). In particular, the
+ special ink-jet paper can make a big difference; the colours are
+ brighter, but most importantly, there is almost no colour bleed, even
+ with adjacent areas of very heavy inking. Similarly, the special coated
+ transparencies also work well (and ordinary transparencies do not work
+ at all!)
+
+ The unix-lpr.sh provides one example of setting up a multi-option
+ colour postscript lpr queue on Unix systems, and includes the ability
+ to choose a range of different colour options and printer accounting
+ and error logging.
+
+
+CAVEAT EMPTOR!:
+
+ It is not always easy for me to test all of these drivers, as the only
+ colour printer I have here is the DeskJet 500C. I rely on others testing
+ drivers for the additional machines and reporting their findings back to
+ me.
+
+HP's 600x300 dpi resolution-enhanced mode for inkjet printers
+=============================================================
+
+This feature is available on HP's more recent inkjet printers,
+including the Deskjet 520 (mono) 540 (mono or colour) and 560C (mono
+and colour).
+
+The colour and monochrome drivers for the HP deskjet 550c are
+(probably) the best you will get for use with ghostscript, for the
+following reasons:
+
+These printers do not offer true 600x300 dpi resolution. Those that
+print in colour are strictly 300x300 dpi in colour mode, while in mono
+mode there is a pseudo 600x300 dot mode, with the restriction that you
+can't print two adjacent dots. Thus, in effect what you have is 600 dpi
+dot positioning, but on average you don't get more dots per line.
+
+What this does give is the possibility to have eg. sharper character
+outlines, as you can place dots on the edges nearer to their ideal
+positions - this is why it is worth doing.
+
+However, HP will not support user-level programming of this
+resolution-enhanced mode, one reason being that (I understand) all the
+dot spacing has to be done by the driver, and if you get it wrong, you
+can actually damage the print head.
+
+To summarise, you may lose a smidgin of (potential) text clarity using
+the 550c drivers (cdj550, cdjcolor, cdjmono etc.), but other than that,
+they are the ones for the job.
+
+### ------------------------------ End --------------------------------- ###
+
+### ------------------- Apple Dot Matrix Printer ---------------------- ###
+
+This section was written by Mark Wedel.
+
+ The Dot Matrix Driver (DMP) driver is a simple driver I wrote. It
+could more more efficient, but it seems to print the images fine.
+
+ The Dot Matrix Printer was a parallel predecessor to the Imagewriter
+printer. As far as I know, the Imagewriter commands are a superset
+to those of the Dot Matrix printer, so the driver should work fine at
+generating output that can be printed on Imagewriters.
+
+ A few notes (from the gdevadmp.c file):
+
+ * To print out images, it sets the printer for unidirectional printing
+ * and 15 cpi (120 dpi). It sets the line feed to 1/9 of an inch (72 dpi).
+ * When finished, it sets things back to bidirectional printing, 1/8" line
+ * feeds, and 12 cpi. There does not appear to be a way to reset
+ * things to initial values.
+ *
+ * This code does not set for 8 bit characters (which is required). It
+ * also assumes that carriage return/newline is needed, and not just
+ * carriage return. These are all switch settings on the DMP, and
+ * I have configured them for 8 bit data and cr only.
+ *
+ * You can search for the strings Init and Reset (in devdemp.c) to find the
+ * strings that set up the printer and clear things when finished, and change
+ * them to meet your needs.
+ *
+ * Also, you need to make sure that the printer daemon (assuming unix)
+ * doesn't change the data as it is being printed. I have set my
+ * printcap file (sunos 4.1.1) with the string:
+ * ms=pass8,-opost
+ * and it works fine.
+
+ Mark Wedel
+master@cats.ucsc.edu
+
+### ------------------------------ End --------------------------------- ###
+
+### ------------------ The Epson Stylus Color printer ------------------ ###
+/*
+ Epson Stylus-Color Driver, contributed by Gunther Hess (address: see below)
+
+I N T R O D U C T I O N
+=======================
+This documentation accompanies version 1.90 of the stcolor-driver.
+Compared to version 1.21 (gs3.53) there are just a few, but somehow
+important chages:
+
+ - Default: noWeave escpBand=1 (-> default works with all known models)
+ - added Parameter "Softweave" (useful only with Original STC and PRO-Series)
+ - added Compile-Option (-DSTC_SIGNAL) to catch interrupts during printing
+ (thanks to Frederic Loyer)
+ - compatibility with ansi2knr
+ - compatibility with 64Bit Processors
+ - clarification of usage with Pro-XL and Stylus Color II
+
+A Note on the Version-Numbering: Version 1.xx comes to it's end.
+Any 1.xx > 1.90 will have only Bug-Fixes. Maybe that Version 2.xx
+comes to life, if this is the case it will include full support of
+the newer models.
+
+U S A G E
+=========
+This driver is selected with "-sDEVICE=stcolor" and produces output for an
+Epson Stylus-Color at 360DpI resolution by default, but it can do much
+more with this printer and with significantly better quality, than with
+the default-mode and it can also produce code for the monochrome-versions
+of this printer.
+
+This can be achieved either via command-line options or via ghostscript-input.
+For convenience a Postscript-File is supplied, that can be used as initial
+inputfile. Thus, assumed that ghostscript is invoked via "gs" on your computer,
+try the following command:
+
+ gs -sDEVICE=stcolor -rXDPIxYDPI stcolor.ps ... (e.g.: your input-files)
+
+were XDPI is one of 180/360/720 and YDPI is one of (90/)180/360/720. The result
+should be significantly better, you may use "stcolor.ps" with other devices
+too, but I do not recommend this, since it does nothing then. "stcolor.ps"
+should be available with binary distributions and should reside in the
+ghostscript input-directory. Thus if ghostscript is part of your
+printer-spooler, you can insert
+
+ (stcolor.ps) findlibfile { pop run } if pop
+
+to the files you want to run through the improved algorithms and you may want
+to adapt this file to your specific needs. The methods and options for this
+are described here, but this description is restricted to the gs-options, while
+their manipulation at the Postscript-level is documented in "language.txt" and
+in the mentioned "stcolor.ps".
+
+Next thing is to explain the options (as written on my unix-system).
+The order is somehow related to their use during the printing-Process:
+
+ -dUnidirectional - Force unidirectional printing,
+ recommended for transparencies
+
+ -dMicroweave - enable the printers "microweave"-feature.
+ -dnoWeave - disable any Weaving, overrides -dMicroweave
+ -dSoftweave - enable internal weaving of the driver.
+
+* Weave-Note: Softweave works *ONLY* with the original Stylus-Color
+* and the PRO-Series.
+
+ -sDithering="name" - select another dithering-algorithm, available are:
+ "gscmyk" : fast color-output, with CMYK-ProcessColorModel [D]
+ "gsmono" : fast black & white output
+ "gsrgb" : fast color-output, with RGB-ProcessColorModel
+ "fsmono" : Floyd-Steinberg, Monochrome
+ "fsrgb" : Floyd-Steinberg, with RGB-ProcessColorModel
+ (Almost identical to cdj550/mjcxxx-Algorithm)
+ "fsx4" : Floyd-Steinberg, with CMYK-ProcessColorModel
+ (shares code with fsmono & fsrgb, but is
+ algorithmically really bad)
+ "fscmyk" : Floyd-Steinberg, with CMYK-ProcessColorModel
+ and proper modifications for CMYK
+ "hscmyk" : modified Floyd-Steinberg with CMYK-Model
+ ("hs" stands for "hess" nor for "high speed",
+ but the major difference to "fscmyk" is speed)
+ "fs2" : algorithm by Steven Singer (RGB)
+ should be identical to escp2cfs2.
+
+ -dBitsPerPixel=1...32 - number of bits used for pixel-storage, the larger
+ the value, the better the quality - at least in
+ theory. In fsrgb one can gain some speed, when
+ restricting to 24 Bits, rather than the default
+ of 30.
+
+ -dFlag0 - causes some algorithms to select a uniform
+ initialisation rather than a set of random-values.
+ May yield "sharper" image-impression at the
+ cost of "dithering-artifacts".
+ (applies to hscmyk and all fs-modi, except for fs2,
+ which always uses a constant initialization.)
+
+ -dFlag1 ... -dFlag4 - available to future algorithms.
+
+ -dColorAdjustMatrix={3/9/16 x float}'
+ - This is a Matrix to adjust the colors. Values should
+ be between -1.0 and 1.0, and the number of
+ values depend on the colormodel used by the
+ selected algorithm. In RGB- and CMYK-modi a matrix
+ with 1.0 on the diagonal produces no transformation.
+ (I could not identify a similar feature at the
+ language-level, so this option was implemented, it
+ is really required, but I don't know reasonable
+ values yet.)
+
+ -dCtransfer='{float float ...}', -dMtransfer=..., -dY..., -dK... or
+ -dRtransfer='{float float ...}', -dG..., -dB... or
+ -dKtransfer='{float float ...}'
+ - which is used, depends on the algorithm, which
+ maybe either either CMYK, RGB or monochrome.
+ The values are arrays of floats in the range from
+ 0 to 1.0, which represent the visible
+ color-intensity for the device. One may achieve
+ similar effects with "setcolortransfer" at the
+ language-level, but this takes more time and the
+ underlying-code for the driver-specific parameters
+ is still required. The size of the arrays is
+ arbitrary and the defaults are {0.0 1.0}, which
+ is a linear characteristic, most of the code in
+ "stcolor.ps" are better transfer-arrays.
+
+ -dKcoding='{float...}', -dC..., -dM... etc.
+ - this are again arrays between 0.0 and 1.0, and
+ they control the internal coding of the
+ color-values. Clever usage of this arrays may
+ yield further enhancements, but no experience yet.
+ [To be discontinued with version >= 2.x]
+
+ -sModel=st800 - causes output to be suitable for the monochrome
+ Stylus 800 (no Weaving, no Color).
+
+ -sOutputCode= - can be either "plain", "runlength" or "deltarow"
+ and changes the ESC/P2 (TM) coding-technique used
+ by the driver. The default is to use the
+ runlength-encoding. "plain" selects uncompressed
+ encoding and yields enormous amounts of data to
+ generated.
+
+ -descp_Band=1/8/15/24 - Number of Nozzles of scanlines used in printing.
+ Useful only with -dnoWeave. Larger Values yield
+ smaller code, but this doesn't increase the
+ Printing-Speed.
+
+ -descp_Width= - Number of Pixels Printed in each scan-Line.
+ (Useful when tuning Margins only, se below)
+
+ -descp_Height= - Length of the entire Page in Pixels
+ (Parameter of "ESC(C" in default initialization)
+
+ -descp_Top= - Top-Margin in scanlines.
+ (1st Parameter of "ESC(c" in default initialization)
+
+ -descp_Bottom= - Bottom-Margin in scanlines.
+ (2nd Parameter of "ESC(c" in default initialization)
+
+ -sescp_Init="..." - Override for the initialization-sequence.
+ (Must set Graphics-Mode-1 & Units)
+
+ -sescp_Release="..." - Overrides the release-sequence.
+ (ESC @ FF by default)
+
+ Valid Resolutions:
+ any, ESC/P2 allows in theory, but only the following are
+ known to work with most printers:
+
+ -r360x360 (Default)
+ -r720x720 (not on STC-IIs ? and st800)
+
+ Valid Option Combinations: (Stylus I & PRO-Series only)
+
+ escp_Band ?Weave escp_Band/#Passes
+ 180x 90 15 no-Weave
+ 180x180 1 , 8, 24 no/u-Weave 15/2 sWeave
+ 180x360 15/4 sWeave
+ 180x720 15/8 sWeave
+ 360x 90 15 no-Weave
+ 360x180 1, 8, 24 no/u-Weave 15/2 sWeave
+ 360x360 1, 8, 24 no/u-Weave 15/4 sWeave
+ 360x720 15/8 sWeave
+ 720x 90 15 no-Weave
+ 720x180 15/2 sWeave
+ 720x360 15/4 sWeave
+ 720x720 1 no/u-Weave 15/8 sWeave
+
+*************************************************************************
+*************************************************************************
+** **
+** BEWARE: There are only few validity-checks for parameters. A good **
+** example is "escp_Band": if you set this, the driver tries **
+** to use your value, even if this value is not supported by **
+** the printer: **
+** **
+** YOU ASKED FOR IT, AND YOU GOT IT! **
+** **
+*************************************************************************
+*************************************************************************
+
+
+A P P L I C A T I O N - N O T E
+================================
+
+Quite a bunch of Parameters. Hopefully you never need any of them, besides
+feeding "stcolor.ps" to ghostscript in front of your input.
+
+After answering some questions over 50 Times, I prepared a STC-FAQ-Collection.
+I am currently unable offer this FAQ on the net.
+But thanks to Bill Davidson it is available as:
+
+ http://www.isisnet.com/bdavidson/gs_stc.FAQ.html
+
+And here it comes (as plain text):
+
+VERSION:
+This FAQ refers to ghostscript > 3.50 with stcolor > 1.20. The former
+release (ghostscript-3.33/stcolor-1.12) used different parameters and
+had some severe bugs. This FAQ is itself version 1.3.
+
+TOPIC: Pro XL?
+Yes, this driver supports the A3-Size Printer. Simply set the required
+pagesize and margins. A simple way to do this, is to specify the
+parameter "-sPAPERSIZE=a3" on the command line or to include the
+procedure-call "a3" in the postscript-Prolog section. If you want
+to optimize the printable area and/or set the proper Margins, see
+topic Margins, PageSize.
+
+TOPIC: Margins, PageSize
+Different than other drivers, i refuse to add code to the stcolor-driver,
+that tries to guess the proper margins or pagesize. This is due to the
+fact, that i found that such guessing is usually wrong and needs correction
+either in the source or the parameters. The following code can be
+inserted to "stcolor.ps" after the line:
+
+ mark % prepare stack for "putdeviceprops"
+
+And this is the new code:
+
+/.HWMargins [9.0 39.96 12.6 9.0] % Left, Bottom, Right, Top (1/72")
+/PageSize [597.6 842.4] % Paper, including Marings (1/72")
+/Margins [ % neg. Offset to Left/Top in Pixels
+ 4 index 0 get STCold /HWResolution get 0 get mul 72 div neg
+ 5 index 3 get STCold /HWResolution get 1 get mul 72 div neg
+]
+
+Feel free to change the Values for ".HWMargins" and "PageSize" to match
+your needs. The given Values are the defaults from the driver, when
+compiled with "-DA4" set.
+
+This Option -or it's omission- may cause trouble: The Stylus Color can
+print exactly 8" or 2880Pixel@360DpI. The remaining paper is the
+margin, where the left margin varies only slightly with the papersize,
+while the right margin ist significantly increased for wider paper,
+such as letter.
+
+-> If you are using stcolor > 1.20, compiled without "-DA4", on european
+ paper, then the Default-Margin is too large. You need to add the
+ proper ".HWMargins" to the command line or stolor.ps
+
+
+TOPIC: Stylus Color II / IIs and 1500.
+First the good news: The driver can print on the Stylus Color II.
+And the bad ones:
+- According to Epson-Support the driver "abuses" the color-capabilities.
+ (See topic "Future Plans" for details.)
+- You need some parameters on the command-line (or in stcolor.ps).
+- I doubted that it would be usable with the Stylus Color IIs.
+ *BUT* it is usable and suffers from the mixing-Problems!!.
+
+To make thinks work, you *MUST* disable the drivers internal
+weaving ("Softweave"). This can be done in two ways:
+
+ gs .... -dMicroweave ....
+
+or
+ gs ... -dnoWeave -descp_Band=1 ....
+
+[1.90 fixes this "bug" due to a changed default-behaviour]
+
+I experienced significantly increased printing speed with the second
+variant on the old Stylus Color, when printing mostly monochrome data.
+
+TOPIC: Future Plans
+Actually i thought, that the driver is finished by now, but an answer
+from Epson triggered future development. This was the answer from
+Epson-Support:
+
+To: Klaus-Gunther Hess
+Subject: Help: Need Programming Info for Stylus-(Color)-Printers
+
+The differentiation is necessary, as the printers produce the graphics
+differently. To wit:
+
+ CMY Class - ( Stylus Color IIs ) The Stylus Color IIs prints color
+ graphics with the three different color inks (cyan, magenta, and yellow).
+ Also, black is printed using composit black (mixture of CMY). For high
+ quality laser like black, a separate black ink cartridge should be used.
+
+ CMY + K Class - ( Stylus Color II ) This printer has both a CMY and a
+ black ink (K) cartridge installed at the same time. However, due to the
+ nature of the black ink it can not be mixed or overlaid with the color
+ inks. Therefore, when black is needed, composite black is used.
+ If the image calls for pure black (e.g., text), the black cartridge is used.
+
+ CMYK Class - ( Stylus Color, Stylus Pro and Pro XL ) These printers
+ have a mixable black (K) ink. This ink is compatible with the CMY inks
+ and will not bleed when combined or printed next to the CMY inks.
+
+Bruce U.
+The Epson Connection
+
+Thus I am working on a version, that supports CMY and CMY + K dithering.
+Actually there are also some new (*undocumented*) instructions used by
+the windows-driver in conjunction withe the Stylus Color II/IIs, that
+raises the need for some more "escp_*" Parameters.
+
+
+A C K N O W L E D G E M E N T S
+===============================
+
+This driver was "copied" from gdevcdj.c (ghostscript-3.12), which was
+contributed by:
+ George Cameron - g.cameron@biomed.abdn.ac.uk
+ Koert Zeilstra - koert@zen.cais.com
+ Eckhard Rueggeberg - eckhard@ts.go.dlr.de
+
+Some of the ESC/P2-code was drawn from gdevescp.c, contributed by
+ Richard Brown - rab@eos.ncsu.edu
+
+The POSIX-Interrupt-Code is from (Compile-Time-Option -DSTC_SIGNAL)
+ Frederic Loyer - loyer@ensta.fr
+
+And several improvements are based on discussions with
+ Brian Converse - BCONVERSE@ids.net
+ Bill Davidson - bdavidson@ra.isisnet.com
+ Gero Guenther - gero@cs.tu-berlin.de
+ Jason Patterson - jason@reflections.com.au
+ ? Rueschstroer - rue@ibe.med.uni-muenchen.de
+ Steven Singer - S.Singer@ph.surrey.ac.uk
+
+While I wish to thank all this people mentioned above, they are by no means
+responsible for bugs in the stcolor-driver - just for the features.
+
+Duisburg 8-May-1996, Gunther Hess
+
+up to sometime E-Mail: gunther@elmos.de
+After that time, one should use snail-mail or phone:
+
+Gunther Hess phone: ++49 203 376273
+Richard Wagner Strasse 112
+D-47057 Duisburg
+Germany
+
+R E C O M M E N D A T I O N S
+=============================
+
+The next section is a contribution from Jason Patterson <jason@reflections.com.au>
+who evaluated a previous version (1.17). GhostScript was invoked as follows:
+
+ gs -sDEVICE=stcolor [-r720x720] -sDithering=... -sOutputFile=escp.out \
+ stcolor.ps whatsoever.ps
+
+where "..." is the name of the desired algorithm. "stcolor.ps" was omitted
+for the gs-algorithms (gsmono, gsrgb and gscmyk), for which it is useless
+*and* it would not allow the selection of "gscmyk".
+
+So here comes a very truncated version of Jasons text:
+
+ COLOR DITHERING EXPERIMENTS with gdevstc-1.21
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Here's a bit of feedback about the EPSON Stylus Color driver's different
+dithering methods, based on a little experiment using 4 good quality
+scanned images of quite varied nature.
+
+Here is a summary of the results of the four experiments...
+
+
+ gsmono: Pretty much what you'd expect from a mono ordered pattern. Looks
+ like what a lot of mono laser printers produce.
+
+ fsmono: Excellent for monochrome.
+
+ gscmyk: Not very good, but then you'd expect that from an ordered pattern.
+
+ gsrgb: A little better than gscmyk. More consistent looking.
+
+ fs2: Good, but not quite as good as fsrgb. Gets the brightness wrong,
+ too light at 720dpi, too dark at 360dpi.
+
+ fsrgb: Very good, but a little too dark and has a slight blue tint.
+
+ hscmyk: Excellent. Slightly better than fsrgb and fs2. Better than fscmyk on
+ some images, almost the same on most.
+
+ fscmyk: Best. Very, *very* slightly better than hscmyk. On some images,
+ nearly as good as the EPSON demos (which were done with the
+ MS-Windows driver).
+
+ Overall Visual Quality (out of ten):
+
+ gsmono |*********
+ fsmono |*****************
+ |
+ gscmyk |********
+ gsrgb |*********
+ fs2 |****************
+ fsrgb |*****************
+ hscmyk |******************
+ fscmyk |******************
+ +---------------------
+ 0 1 2 3 4 5 6 7 8 9 10
+
+ best-to-worst order: color: fscmyk hscmyk fsrgb fs2 gsrgb gscmyk
+ mono: fsmono gsmono
+
+
+SANITY NOTE: The above results are only from *four* images, a total of 24
+ printouts (8 on 720dpi paper, 16 on plain paper). Your results
+ will almost certainly vary, and your standards might not be
+ the same as mine, so use these results as a *guide* only, not
+ as a formal evaluation.
+
+C O L O R - T R A N S F O R M A T I O N
+=======================================
+
+*NOTE*: Things are changing with version gdevstc > 2.00!
+
+In the initial version of the driver, distributed with Ghostscript-3.33,
+the parameter "SpotSize" was the only way to manipulate the colors at the
+driver-level. According to the parameters enumerated above, this has changed
+significantly with version 1.16 and above. This is the result of
+an ongoing discussion about dithering-algorithms and "false color" on the
+Epson-Stylus-Color. This initiated the transformation of the stcolor-driver
+into a framework for different dithering-algorithms, that provides a generalized
+interface to the internal Ghostscript-Color-Models and the other data-structures
+related to Ghostscript-Drivers.
+
+The main thing such a framework should be able to do is to deliver the
+values the dithering-algorithm needs and since this influences directly
+the optical image impression, this transformation should be adjustable without
+the need for recompilation and relinking.
+
+In general the process can be described as follows:
+
+ ColorAdjustMatrix Coding Transfer
+ +---------------------+ +---------------------+ +------------------+
+ | Ghostscript Color | | Ghostscript Raster | | Dithering Data |
+ | | => | 1/2/4/8/16/24/32Bit | => | 1/3/4x Values |
+ | 1/3/4x16Bit Values | | for all components | | (arbitrary type) |
+ +---------------------+ +---------------------+ +------------------+
+
+Due to the limitations on raster-storage, information is lost in the first
+transformation step, except for the 16Bit Monochrome-Mode. So any color
+adjustment should take place before this step and this is where the optional
+ColorAdjustMatrix works.
+
+The first transformation-step is called "coding" and is controlled by the
+?coding-Arrays. The Decoding-process expands the range of values
+pontentially to a larger range than that provided by the initial ghostscript
+color-model. It is therefore a reasonable place to make device- and/or
+algorithm-specific adjustments. This is the place where the ?transfer-Arrays
+are used. Array-Access might be not the fastest method, but its generality
+is superior, so this step is always based upon internally algorithm-specific
+array-access. If 8Bits are stored per color-component and if the algorithm
+uses bytes too, the second transformation is included within the first, what
+saves significant computation-time when printing the data.
+
+
+ColorAdjustMatrix
+-----------------
+
+The driver supports different "ProcessColorModel"-Values, which raises the
+need for different color-adjustments. In the following "CAM" stands for
+ColorAdjustMatrix:
+
+ DeviceGray: (3 Floats):
+ if((r == g) && (g == b))
+ K' = 1.0 - R;
+ else
+ K' = 1.0 - CAM[0] * R + CAM[1] * G + CAM[2] * B;
+
+ According to the documentation in drivers.txt, the latter should
+ never happen.
+
+ DeviceRGB: (9 Floats)
+ if((r == g) && (g == b))
+ R' = B' = G' = R;
+ else
+ R' = CAM[0]*R + CAM[1]*G + CAM[2]*B;
+ G' = CAM[3]*R + CAM[4]*G + CAM[5]*B;
+ B' = CAM[6]*R + CAM[7]*G + CAM[8]*B;
+
+ The Printer uses always four inks, thus a special treatment of black
+ is provided. Algorithms may take special action, if r==g==b. Maybe
+ that in future versions Kcoding & Ktransfer become active in RGB-Mode.
+
+ DeviceCMYK: (16 Floats)
+
+ if((c == m) && (m == y))
+ K' = max(C,K);
+ C' = M' = Y' = 0;
+ else
+ K = min(C,M,Y);
+ if((K > 0) && ColorAdjustMatrix_present) { => UCR
+ C -= K;
+ M -= K;
+ Y -= K;
+ }
+
+ C' = CAM[ 0]*C + CAM[ 1]*M + CAM[ 2]*Y + CAM[ 3]*K;
+ M' = CAM[ 4]*C + CAM[ 5]*M + CAM[ 6]*Y + CAM[ 7]*K;
+ Y' = CAM[ 8]*C + CAM[ 9]*M + CAM[10]*Y + CAM[11]*K;
+ K' = CAM[12]*C + CAM[13]*M + CAM[14]*Y + CAM[15]*K;
+
+ Again we have a special black-treatment. "max(C,K)" was introduced
+ because of a slight misbehaviour of ghostscript, that delivers
+ black under certain circumstances as (1,1,1,0). Normally, when
+ no special "Black Separation" and "Undercolor Removal" procedures
+ are defined at the postscript-level, either (c,m,y,0) or (0,0,0,k)
+ values are mapped. This would make the extended ColorAdjustMatrix
+ quite tedious, thus during mapping black-separation is done for
+ (c,m,y,0)-Requests and if there is a ColorAdjustMatrix, undercolor-
+ removal is used too. In other words the Default-Matrix is:
+
+ 1 0 0 1
+ 0 1 0 1
+ 0 0 1 1
+ 0 0 0 1
+
+ and it is applied to CMYK-Values with separated and removed Black.
+ Raising the CMY-Coefficients while lowering the K-coefficients
+ reduces black and intensifies color. But be careful, even low
+ deviations from the default cause drastic changes.
+
+If no ColorAdjustMatrix is set, the matrix-computations are skipped. Thus
+the transformation reduces to:
+
+ - Range-Inversion in Monochrome-Mode
+ - Black-Separation in CMYK-Mode
+
+
+RGB/CMYK-coding & -transfer and BitsPerPixel
+--------------------------------------------
+
+This two (groups) of parameters are arrays of floating point numbers in the
+range 0.0 to 1.0. They control the truncation to the desired number of
+bits stored in the raster-memory (BitsPerPixel) and the ink-density.
+
+The "truncation" may become a nonlinear-function, if any of the ?coding-arrays
+are set. Assume the following Ghostscript invocation:
+
+ gs -sDEVICE=stcolor -sDithering=fscmyk -dBitsPerPixel=16 \
+ -dMcoding='{ 0.0 0.09 0.9 1.0 }' \
+ -dYtransfer='{ 0.0 0.09 0.9 1.0 }' \
+ -dKcoding='{ 0.0 0.09 0.9 1.0 }' -dKtransfer='{ 0.0 0.09 0.9 1.0 }' \
+
+We may have ?coding and/or ?transfer, thus four combinations are possible
+and this four combinations appear in the given example. The resulting mapping
+is given in the following tables, where except for the internal Indices
+(4 Components * 4 Bits = 16 BitsPerPixel), all values are normalized to the
+Range 0-1. The actual range is 0 to 65535 for the ghostscript-color and
+0 to 16777215 (2^24-1) for the ink-values delivered to the fscmyk-algorithm.
+Sorry for the bunch of numbers following, but you may try this example in
+conjunction with "stcinfo.ps", what should give you a graphical
+printout of the following numbers, when you issue a "showpage"-command:
+
+ CYAN MAGENTA
+ CI/15 gs_color_values CI ink gs_color_values CI ink
+ 0.000 0.000 - 0.062 0 0.000 -0.123 - 0.123 0 0.000
+ 0.067 0.063 - 0.125 1 0.067 0.123 - 0.299 1 0.247
+ 0.133 0.125 - 0.187 2 0.133 0.299 - 0.365 2 0.351
+ 0.200 0.188 - 0.250 3 0.200 0.365 - 0.392 3 0.379
+ 0.267 0.250 - 0.312 4 0.267 0.392 - 0.420 4 0.406
+ 0.333 0.313 - 0.375 5 0.333 0.420 - 0.447 5 0.433
+ 0.400 0.375 - 0.437 6 0.400 0.447 - 0.475 6 0.461
+ 0.467 0.438 - 0.500 7 0.467 0.475 - 0.502 7 0.488
+ 0.533 0.500 - 0.562 8 0.533 0.502 - 0.529 8 0.516
+ 0.600 0.563 - 0.625 9 0.600 0.529 - 0.557 9 0.543
+ 0.667 0.625 - 0.687 10 0.667 0.557 - 0.584 10 0.571
+ 0.733 0.688 - 0.750 11 0.733 0.584 - 0.612 11 0.598
+ 0.800 0.750 - 0.812 12 0.800 0.612 - 0.639 12 0.626
+ 0.867 0.813 - 0.875 13 0.867 0.639 - 0.715 13 0.653
+ 0.933 0.875 - 0.937 14 0.933 0.715 - 0.889 14 0.778
+ 1.000 0.938 - 1.000 15 1.000 0.889 - 1.111 15 1.000
+
+The difference between Cyan and Magenta is the presence of a Coding-Array.
+The coding-process must map a range of color-values to each of the 16
+component-indices. If no coding-array is given, this is accomplished
+by a division with 4096 -equivalent to a right-shift by 12 Bits-. The
+final ink-density resides in the given interval and moves form the left to
+the right side from 0 to 15. In the Magenta-case, there is a coding array
+and the ink-value matches the center of the intervals. But the distribution
+of the mapped intervals follows the given Coding-Array and is nonlinear in
+the linear color-space of ghostscript.
+
+Now let us take a look at the case with Transfer-Arrays:
+
+ YELLOW BLACK
+ CI/15 gs_color_values CI ink gs_color_values CI ink
+ 0.000 0.000 - 0.062 0 0.000 -0.123-0.123 0 0.000
+ 0.067 0.063 - 0.125 1 0.018 0.123-0.299 1 0.067
+ 0.133 0.125 - 0.187 2 0.036 0.299-0.365 2 0.133
+ 0.200 0.188 - 0.250 3 0.054 0.365-0.392 3 0.200
+ 0.267 0.250 - 0.312 4 0.072 0.392-0.420 4 0.267
+ 0.333 0.313 - 0.375 5 0.090 0.420-0.447 5 0.333
+ 0.400 0.375 - 0.437 6 0.252 0.447-0.475 6 0.400
+ 0.467 0.438 - 0.500 7 0.414 0.475-0.502 7 0.467
+ 0.533 0.500 - 0.562 8 0.576 0.502-0.529 8 0.533
+ 0.600 0.563 - 0.625 9 0.738 0.529-0.557 9 0.600
+ 0.667 0.625 - 0.687 10 0.900 0.557-0.584 10 0.667
+ 0.733 0.688 - 0.750 11 0.920 0.584-0.612 11 0.733
+ 0.800 0.750 - 0.812 12 0.940 0.612-0.639 12 0.800
+ 0.867 0.813 - 0.875 13 0.960 0.639-0.715 13 0.867
+ 0.933 0.875 - 0.937 14 0.980 0.715-0.889 14 0.933
+ 1.000 0.938 - 1.000 15 1.000 0.889-1.111 15 1.000
+
+Yellow uses a transfer-array. There is no linear correspondence between
+the color- and the ink-values. This correspondence is defined through the
+given array. In other words: the Transfer-arrays define a nonlinear
+ink-characteristic, what is exactly the same functionality, that
+Postscript's "(color)transfer"-function provides.
+
+While in the case of Yellow, the intervals match the intervals used with Cyan,
+the intervals used for Black match the Magenta-Intervals, but watch
+the correspondence between the CI/15-values and the Ink-Density for Black:
+This is a linear distribution in the Ink-domain.
+
+Not a bad idea, I think. Consider the fs2-algorithm: It uses values in
+the range 0-255 (Bytes). If any transfer-array would be supplied alone,
+some of the 256 possible values would never be used and others will be
+used for adjacent intervals several times. Establishing an identical
+coding-array solves this problem, so that the full potential of the
+algorithm is utilized.
+
+Another useful feature of the coding-arrays is, that they are internally
+normalized to the 0-1 Range. In the 720x720Dpi-Mode the transfer-arrays
+in stcolor.ps limit the Dot-Density to about 50%, thus this arrays end
+at 0.5 (respectively start at 0.5 in the RGB-case). Due to the automatic
+normalization this arrays can be used as coding-arrays too. But of course
+in the fs2-case mentioned above, values from 0-127 will never be delivered
+to the algorithm, while values 128-255 are delivered for adjacent intervals.
+
+To clearify the intended use of the three parameters/parameter-groups the
+following statements should be kept in mind:
+
+- ColorAdjustMatrix is never used, when transferring gray-values. This
+ restricts it to what the name says: Adjustment of Colors e.g. the
+ correction for miscolored ink. Do not use it for saturation or
+ brightness-control.
+
+- ?transfer-arrays control the values delivered to the driver, which in
+ turn controls the ink-quantity. This arrays should be used for control
+ of saturation and brightness. Maybe that a Postscript-Header for the
+ manipulation of brightness and so on will be provided with future
+ versions. In general this arrays are identical for all inks.
+ If they differ they provide a simpler scheme for color-correction,
+ which is not necessarily faster than the ColorAdjustMatrix.
+
+- ?coding-arrays control the color-value-intervals mapped to
+ the internal color-indices.
+
+P R I N T - M O D I
+===================
+
+The parameters "Unidirectional", "Microweave", "noWeave",
+"OutputCode", "Model" and the given resolution provide control over the
+data generated for the printer.
+
+Unidirectional
+--------------
+Simply toggles the unidirectional-mode of the printer. Setting "Unidirectional"
+definitely decreases printing-speed, but may increase the quality. I use
+this for printing tranparencies, where fast head-movement could smear the ink.
+
+Microweave, noWeave and OutputCode=deltarow
+-------------------------------------------
+The first are two Booleans, what immediately tells, that 4 combinations are
+possible. Actually only three exist (if you don't count for deltarow):
+
+ 1. Softweave
+ 2. Microweave
+ 3. noWeave
+
+First and second are functionally identical, their difference is that either
+the driver or the printer does the job. So the question
+
+ What is weaving ?
+
+arises. The Epson Stylus Color has a Head-Assembly that contains two physically
+identifiable Heads. One for Black and one for Cyan/Magenta/Yellow. This
+makes 4 logical Heads, one for each color-component. Each of this four heads
+has several jets at some Y-distance, so several horizontal lines can be printed
+during one pass of the heads. From the experience I think there are 15 Jets
+per color spaced at 1/90".
+
+So the question arises, how to print at a Y-Resolution of 360Dpi with this
+90DpI-Jets. Simply by division, one gets 360/90 = 4, what tells us, that
+4 Passes of the head-assembly are required to achieve a Y-resolution of
+360DpI. Weaving is just the scheme how the 15 jets are utilized to print
+adjacent horizontal rows:
+
+ Weaving noWeave
+ Pass: 1 2 3 4 1 2 3 4
+ 0/360" jet0 - - - jet0 - - -
+ 1/360" - jet1 - - - jet0 - -
+ 2/360" - - jet2 - - - jet0 -
+ 3/360" - - - jet3 - - - jet0
+ 4/360" jet1 - - - jet1 - - -
+ 5/360" - jet2 - - - jet1 - -
+ 6/360" - - jet3 - - - jet1 -
+ ....
+
+Now let us assume, that the dot-diameter is different for each individual
+jet, but the average among the jets matches the desired resolution. With
+weaving adjacent rows are printed by different jets, thus the some averaging
+takes place. Without weaving adjacent rows are printed by the same jet and
+this makes the dot-diameter-deviations visible as 1/90"-stripes in the printout.
+
+In Softweave-Mode (the default) the driver sends the data properly arranged to
+the printer, while in Microweave-Mode the printer does the same job. But in
+general the host-processor is much faster than the printers processor and
+thus it is advantageous to let the host do this job. In addition to that, for
+720DpI 8 Passes are required and the amount of buffer-space required to buffer
+the data for the passes is far beyond the printers memory. Softweave requires
+an odd value of "escp_Band", the Stylus Color provides 15 for that.
+
+"OutputCode" controls the encoding used. In the basic modi, the choice consists
+of "plain" and "runlength". The computation of runlength-encoded data does not
+take much time, at least less than the data tranfer to the printer, thus this
+is the recommended mode and of course the default. With the Stylus Color
+Epson introduced some new encoding principles, namely "tiff" and "deltarow".
+While the first was omitted from this driver, since there were not potential
+advantages found, "deltarow" is available as an option. "Softweave" cannot
+be used with this encoding, so if "OutputCode=deltarow" is set, Microweave
+becomes the default. Maybe that the size of the ESC/P2-code becomes smaller,
+but I have never observed increased printing-speed - things tend to become
+slower with deltarow compared to Softweave.
+
+Model
+-----
+Some ESC/P2-Printers, such as the Stylus 800, do not offer Microweave or
+the commands required to do Softweave. Setting Model just changes the defaults
+and omits some parts of the initialization-sequence, which are not compatible
+with the given printer model. Currently only "st800" is supported besides the
+default (stcolor).
+
+
+BEWARE: BUGS & PITFALLS
+=======================
+
+* The given ?coding and ?transfer arrays should be strictly monotonic.
+
+* It is impossible to change WHITE: that's your paper.
+ Thus R/G/B-transfer should end at 1.0 and C/M/Y/K-transfer should
+ start at 0.0.
+
+* Usually 8Bits per component yields fastest operation.
+
+* The ColorAdjustMatrix is not used in the reverse-transformation, which
+ is used, when Ghostscript does the dithering (gs*-Modi). Expect funny
+ results.
+
+* If BitsPerPixel is less than 6, the entire coding/transfer-process
+ does not work. This is always true for the gs*-modi and becomes true
+ for the other modi, if BitsPerPixel is forced to low values.
+
+* 720x720Dpi-Printing should never select the gs-modi and should always
+ use stcolor.ps. (I prefer 360x720)
+
+T E S T S (version 1.13 and above)
+==================================
+
+This section should give an overview over the performance in terms of
+processing- & printing-time. Printing is done offline (via cp-instruction)
+to measure real printing-speed, since at high-resolutions processing-time
+is in the same order of magnitude and thus may become the limiting factor.
+
+The various OutputCodes
+-----------------------
+
+I ran several files though ghostscript and recorded the size of the code,
+the processing time and the printing-time, at least for some of the files.
+Always the following options were used:
+
+ "-sDEVICE=stcolor -sPAPERSIZE=a4 stcolor.ps - < file.ps"
+
+(Actually "-sPAPERSIZE=a4" is in my gs_init.ps since I'm a germ.)
+
+"Softweave" means actually, that nothing else was used, it is the default and
+implies that odd v=40/h=10/m=15 mode (ESC . 1 40 10 15).
+
+"Microweave" is just "-dMicroweave", which is equivalent to "ESC . 1 10 10 1",
+with full skip-optimization and microweave-activated.
+
+"deltarow" is the new encoding principle ("ESC . 3 10 10 1") with Microweave on.
+It is activated with "-sOutputCode=deltarow".
+
+Finally I wanted to see the plain Kathy Ireland and used "-sOutputCode=plain",
+which is just replacing RLE by no encoding, thus "ESC . 0 40 10 15" is
+used then.
+[So sorry ;-) Kathy was still blue dressed in front of the blue sea on a blue
+air-cushion - nice to see but hard to dither]
+
+So here are the results:
+
+ golfer.ps colorcir.ps drawing.ps brief.ps
+
+deltarow 572751/48.180u 643374/41.690u 90142/46.180u/1:50 178563/49.350u/2:22
+Softweave 559593/46.810u 669966/44.960u 296168/48.160u/1:30 269808/43.320u/1:55
+Microweave 590999/56.060u 754276/42.890u 338885/47.060u/1:50 282314/44.690u/2:22
+
+ kathy.ps
+deltarow 3975334/111.940u/5:35
+Softweave 3897112/101.940u/3:10
+Microweave 4062829/100.990u/3:15
+plain/soft 5072255/104.390u/3:05
+
+Evaluation:
+
+A.) Might be, that I've not chosen the optimal deltarow-code, but even if
+ it saves at lot of bytes, printing-speed is not increased.
+
+B.) At least the printer prefers plain-kathy. In other words: Sending a
+ 1 Megabyte or 20% more data, has no impact on printing speed.
+ [drawing.ps is an exception to this rule: plain prints slower than rle]
+
+C.) But "unclever" coding -especially with deltarow- can significantly
+ slows down printing. But even if very significant advantages in the
+ size of the code ar achieved, "deltarow" is not competitive.
+ [colorcir.ps shows savings in deltarow, but printing is a mess.]
+
+
+Printing-Time related to other options
+--------------------------------------
+
+Full page halftone images printed, unless otherwise noted.
+
+ DpI print-mode Size Time comments
+180x180 mono -/uni 358KB 1:15
+ -/bi 358KB 0:45
+ micro/bi 205KB 0:45 (not weaving)
+ soft/bi 179KB 1:25
+ color -/bi 641KB 2:45
+ soft/bi 556KB 1:32
+
+360x360 mono -/uni 269KB 0:50 (b/w Text)
+ -/bi 269KB 0:35 (b/w Text)
+ micro/bi 269KB 2:25 (b/w Text)
+ soft/uni 250KB 3:15 (b/w Text)
+ soft/bi 250KB 1:55 (b/w Text)
+ color -/bi 346KB 1:00 (sparse color-page, visible displacements)
+ micro/bi 346KB 1:50 (sparse color-page, looks buggy - printer?)
+ soft/bi 294KB 1:30 (sparse color-page, O.K.)
+ -/bi 2218KB 2:45 (visible stripes)
+ micro/bi 5171KB 3:17
+ soft/bi 3675KB 3:05
+
+360x720 mono soft/bi 2761KB 5:40
+ color soft/bi 7789KB 6:15 (just a small difference!)
+
+720x360 color soft/bi 7182KB 5:40
+
+720x720 color micro/bi 14748KB 30:26 (actually beyond printers capabilities)
+ soft/bi 14407KB 11:08
+### ------------------------------ End --------------------------------- ###
+
+### ------------ uniprint - an unified (?) printer driver ------------- ###
+
+uniprint -- ESC/P, ESC/P2 and PCL/RTL-Driver by Gunther Hess gunther@elmos.de
+=============================================================================
+
+This driver is intended to _become_ a unified printer driver. If you
+consider it ugly, please send me your suggestions for improvements. The
+driver will be updated with them. Thus the full explanation of the drivers
+name is:
+
+ Ugly- -> Updated- -> Unified-Printer-Driver
+
+But probably you want to know, something about the functionality:
+At the time of this writing uniprint drives:
+
+ NEC Pinwriter P2X (24Pin B/W Impact printer, ESC/P-Style)
+ Several Epson Stylus Color Models (ESC/P2-Style)
+ HP-Deskjet 550c (Basic HP-RTL)
+ Canon BJC 610
+
+It can be configured for various other printers _without_ recompilation
+and offers uncompressed (== ugly) SUN-Rasterfiles as another format, but
+this format is intended for testing purposes rather than real use.
+
+The usage of this driver is quite simple, the typical command line looks
+like this:
+
+ gs @MODEL.upp -sOutputFile=PRINT_FILE POSTSCRIPT_FILE -c quit
+
+with MODEL, PRINT_FILE and POSTSCRIPT_FILE replaced by actual filenames
+as in the following example from my Linux-Box:
+
+ gs @stc.upp -sOutputFile=/dev/lp1 tiger.ps -c quit
+
+There are several Unified-Printer-Parameterfiles (.upp) distributed
+with Ghostscript:
+
+ bjc610a0 - Canon BJC 610, 360x360DpI, plain paper high speed, color, rendered
+ bjc610a1 - Canon BJC 610, 360x360DpI, plain paper, color, rendered
+ bjc610a2 - Canon BJC 610, 360x360DpI, coated paper, color, rendered
+ bjc610a3 - Canon BJC 610, 360x360DpI, transparency film, color, rendered
+ bjc610a4 - Canon BJC 610, 360x360DpI, back print film, color, rendered
+ bjc610a5 - Canon BJC 610, 360x360DpI, fabric sheet, color, rendered
+ bjc610a6 - Canon BJC 610, 360x360DpI, glossy paper, color, rendered
+ bjc610a7 - Canon BJC 610, 360x360DpI, high gloss film, color, rendered
+ bjc610a8 - Canon BJC 610, 360x360DpI, high resolution paper, color, rendered
+
+ bjc610b1 - Canon BJC 610, 720x720DpI, plain paper, color, rendered
+ bjc610b2 - Canon BJC 610, 720x720DpI, coated paper, color, rendered
+ bjc610b3 - Canon BJC 610, 720x720DpI, transparency film, color, rendered
+ bjc610b4 - Canon BJC 610, 720x720DpI, back print film, color, rendered
+ bjc610b6 - Canon BJC 610, 720x720DpI, glossy paper, color, rendered
+ bjc610b8 - Canon BJC 610, 720x720DpI, high resolution paper, color, rendered
+
+ cdj550 - HP Deskjet 550C, 300DpI, 32Bit-CMYK
+
+ necp2x - NEC P2X at 360x360DpI, 8Bit (Floyd-Steinberg)
+
+ stcany - Any Epson Stylus Color, 360x360DpI, 4Bit, POSTSCRIPT-Halftoning
+
+ The next group is suitable for Original Stylus & Stylus Pro.
+ stc - Epson Stylus Color, 360x360DpI, 32Bit-CMYK, 15 Pin
+ stc_l - ditto, but 360x360DpI, 4Bit, POSTSCRIPT-Halftoning, Weaved noWeave
+ stc_h - ditto, but 720x720DpI, 32Bit-CMYK, 15 Pin Weave
+
+ stc2 - Epson Stylus Color II(s), 360x360DpI, 32Bit-CMYK, 20Pin
+ stc2_h - Epson Stylus Color II, 720x720DpI, 32Bit-CMYK, 20Pin
+ stc2s_h - Epson Stylus Color IIs, 720x720DpI, 32Bit-CMYK, 20Pin
+
+ Thanks to Mark Goldberg, the following two are known to have
+ good transfer-curves for plain-paper.
+ stc500p - Espon Stylus Color 500, 360DpI, 32Bit-CMYK, noWeave, plain paper
+ stc500ph - ditto, 720x720DpI, 32Bit-CMYK, noWeave, plain paper
+
+ The Stylus Color 600 does 32/90"-Weaving
+ stc600pl - Epson Stylus Color 800, 360DpI, 32Bit-CMYK, 32 Pin, plain paper
+ stc600p - Epson Stylus Color 800, 720DpI, 32Bit-CMYK, 32 Pin, plain paper
+ stc600ih - Epson Stylus Color 800, 1440DpI 32Bit-CMYK, 30 Pin, inkjet paper
+
+ The Stylus Color 800 does 64/180"-Weaving
+ stc800pl - Epson Stylus Color 800, 360DpI, 32Bit-CMYK, 64 Pin, plain paper
+ stc800p - Epson Stylus Color 800, 720DpI, 32Bit-CMYK, 64 Pin, plain paper
+ stc800ih - Epson Stylus Color 800, 1440DpI 32Bit-CMYK, 62 Pin, inkjet paper
+
+ ras1 - SUN rasterfile, 1Bit, monochrome (Ghostscript)
+ ras8m - SUN rasterfile, 8Bit, grayscale (Floyd-Steinberg)
+
+ ras3 - SUN rasterfile, 3Bit, RGB (Ghostscript)
+ ras24 - SUN rasterfile, 24Bit, RGB (Floyd-Steinberg)
+
+ ras4 - SUN rasterfile, 4Bit, CMYK (Ghostscript)
+ ras32 - SUN rasterfile, 32Bit, CMYK (CMYK-Floyd-Steinberg)
+
+There may be more parameter files available. I am trying to keep them together
+with the latest version of the driver-sources and some additional stuff at:
+
+ http://www-md.e-technik.uni-rostock.de/ma/gunther/gs/index.html
+
+At the time of this writing (21-Sep-1997) the contents of the website is
+outdated, but i still live in the hope to update it. I am becoming 42 in
+November, Thus all answers might be available on the web then.
+
+Please note the following:
+
+ - Changing the resolution via the -r-Parameter of Ghostscript is
+ usually _not_ possible.
+
+ - For Epson Stylus Color Models not listed above, the two stc500-Variants
+ are likely to work besides stcany, but the Gamma-Correction might be wrong.
+
+A few notes on the state of this driver
+=======================================
+
+The coding of uniprint was triggered by the requirements of the various
+Stylus Color models and some personal needs for HP- and NEC-Drivers. Thus
+the Epson-Models are well represented among the distributed Parameter-Files.
+When this driver entered the beta testphase, three other drivers appreared on
+the scene, that could/should at least partially integrated into uniprint:
+
+ cdj850 by Uli Wortmann (available via ftp://bonk.ethz.ch)
+ hpdj by Martin Lottermoser
+ bjc610 by Helmut Riegler
+
+Uli addresses features of the more recent Deskjet-Models, that will not be
+available in uniprint soon. Martin taught me a lesson on HP-PCL3-Headers,
+that will be available in uniprint soon. Helmut in turn followed an almost
+similar idea, but targetted primarily for printing on Canon-Printers from
+the pbmplus-Library. Starting with Version 1.68 of uniprint, the bjc-support
+is available. The work on the hpdj-Integration will start after the update of
+my website.
+
+A few notes on the uniprint-background
+======================================
+
+Uniprint is actually an update of stcolor, but much more versatile than
+its predecessor. Stcolor in turn started as a clone of the Color-Deskjet
+family of drivers (cdj*). Finally cdj* can be considered as an addition
+of features to the simpler Monochrome-Drivers of Ghostscript. This
+addition of features is useful to get an idea of the functionality of
+uniprint:
+
+1. Monochrome -> advanced Color (cdj*):
+ This adds color-mapping and rendering-functions to the driver.
+ Especially the Error-Diffusion is important for the printout quality.
+
+2.1. HP-Color -> Epson-Color (stcolor)
+ The Epson Stylus Color offered two features simultaneously: It could
+ produce 720x720Dpi-Output and it could soak the paper. In other words
+ it required more color-management-features inside the driver. This is
+ still the major conceptual difference in the data-generation
+ for HP- and Epson-Printers.
+
+2.2. Weaving-Techniques (stcolor)
+ Besides the internal color-management the Stylus Color did not provide
+ enough buffer-space to operate the printer fast at the 720x720DpI.
+ The use of Weaving could yield the triple print-speed. Weaving, also
+ called interleaving, is present in some monochrome-drivers too. The new
+ thing in stcolor was the combination with Error-Diffusion. Unfortunately
+ the weaving was somehow hardcoded, as the problems with the newer
+ members of the Stylus Color family of printers demonstrated.
+
+3. Generalized Output-Format and Weaving (uniprint)
+ The features mentioned above yielded about 90% of stolors source-code,
+ only 10% were related to the formatting of the output. The idea to
+ make the Output-Format switchable came up soon after completing
+ stcolor. But the final design of uniprint became triggered by the
+ (personal) necessity to drive a NEC-P2X and a Designjet 750c. (If
+ you are missing the dnj750-parameter-file: a temporary version will
+ be available soon, but a reasonable one requires some additions to
+ uniprint, which will take some time.)
+
+Thus uniprint accumulates almost any features, that can be found among
+the printer drivers. Clearly this has some disadvantages in terms of
+processing speed. This is still true for the current version (1.75),
+since it is targetted for the functionality and several speed-gaining
+features were (willingly) omitted.
+
+To summarize and to introduce the terms used in the description of the
+Parameters, the features of uniprint, that can be parameterized are:
+
+ 1. The Color-Mapping
+ 2. The Color-Renderining (alias Error-Diffusion or Floyd-Steinberg)
+ 3. The Output-Format, including
+ 4. The Weaving
+
+And the Parameters used for that are:
+
+upAbortCommand upAdjustBottomMarginCommand
+upAdjustMediaSizeCommand upAdjustPageLengthCommand
+upAdjustPageWidthCommand upAdjustTopMarginCommand
+upAdjustResolutionCommand upBeginJobCommand
+upBeginPageCommand upBlackTransfer
+upBlueTransfer upColorInfo
+upColorModel upColorModelInitialized
+upComponentBits upComponentShift
+upCyanTransfer upEndJobCommand
+upEndPageCommand upErrorDetected
+upFSFixedDirection upFSProcessWhiteSpace
+upFSReverseDirection upFSZeroInit
+upFormatXabsolute upFormatYabsolute
+upGreenTransfer upMagentaTransfer
+upMargins upModel
+upOutputAborted upOutputBuffers
+upOutputComponentOrder upOutputComponents
+upOutputFormat upOutputFormatInitialized
+upOutputHeight upOutputPins
+upOutputWidth upOutputXOffset
+upOutputXStep upOutputYOffset
+upOutputYStep upRasterBufferInitialized
+upRedTransfer upRendering
+upRenderingInitialized upSelectComponentCommands
+upSetLineFeedCommand upVersion
+upWeaveFinalPins upWeaveFinalScan
+upWeaveFinalXStarts upWeaveFinalYFeeds
+upWeaveInitialPins upWeaveInitialScan
+upWeaveInitialXStarts upWeaveInitialYFeeds
+upWeavePasses upWeaveXPasses
+upWeaveXStarts upWeaveYFeeds
+upWeaveYOffset upWeaveYPasses
+upWhiteTransfer upWriteComponentCommands
+upWroteData upXMoveCommand
+upXStepCommand upYFlip
+upYMoveCommand upYStepCommand
+upYellowTransfer
+
+All this Parameters are specific to uniprint. But since the names are
+choosen to be self-explanatory, you can now go ahead and write your
+own parameterfile ;-).
+
+Godzillas Guide to the Creation of Unified-Printer-Parameterfiles
+=================================================================
+
+Learning by example might be a good idea, thus here is one of the
+distributed parameter files (stc_l.upp) with some added "--"-Comments:
+
+ -supModel="Epson Stylus Color I (and PRO Series), 360x360DpI, noWeave"
+ -sDEVICE=uniprint -- Select the Driver
+ -dNOPAUSE -- Useful with Printers
+ -dSAFER -- Provides some Security
+ -dupColorModel=/DeviceCMYK -- Selects the Color-Mapping
+ -dupRendering=/ErrorDiffusion -- Selects the Color-Rendering
+ -dupOutputFormat=/EscP2 -- Selects the Output-Format
+ -r360x360 -- Adjusts the Resolution
+ -dupMargins="{ 9.0 39.96 9.0 9.0}" -- Establishes (L/B/R/T-Margins 1/72")
+ -dupComponentBits="{1 1 1 1}" -- Map: Bit's Per Component (Default: 8)
+ -dupWeaveYPasses=4 -- Weave: Y-Passes (Default: 1)
+ -dupOutputPins=15 -- Format/Weave: Scans per Command
+ -dupBeginPageCommand="< -- Goes to the Printer (second-data)
+ 1b40 1b40 -- ESC '@' ESC '@' -> dual reset
+ 1b2847 0100 01 -- ESC '(' 'G' 1 0 1 -> Graphics
+ 1b2869 0100 00 -- ESC '(' 'i' 1 0 1 -> no HW-Weave
+ 1b2855 0100 0A -- ESC '(' 'U' 1 0 10 -> 360DpI
+ 1b5500 -- ESC 'U' 0 -> Bidir-Print
+ 1b2843 0200 0000 -- ESC '(' 'C' 2 0 xx -> Page-Length
+ 1b2863 0400 0000 0000 -- ESC '(' 'c' 4 0 xxxx -> Margins
+ >" -- as it is, unless:
+ -dupAdjustPageLengthCommand -- Adjust Pagelength in BOP requested
+ -dupAdjustTopMarginCommand -- Adjust Top-Margin in BOP
+ -dupAdjustBottomMarginCommand -- Adjust Bottom-Margin in BOP
+ -dupEndPageCommand="(\033@\014)" -- Last (but one) data to the Printer
+ -dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
+That's short, and if one removes the "upWeaveYPasses" and "upOutputPins"
+this becomes shorter and almost "stcany.upp". This miniature-size
+is the result of the fact, that I am most familiar with ESC/P2 and was able
+to add defaults for the omitted parameters.
+
+Just a few notes about the parameters used in this example:
+
+- upModel, is a string serving as a comment (and nothing else)
+
+- DEVICE, NOPAUSE, SAFER are well known Ghostscript-Parameters
+
+- upColorModel, is one of major uniprint-Parameters and selects the
+ color-mapping and in turn the Postscript-ColorModel. The following
+ values are currently supported:
+
+ /DeviceGray, /DeviceRGBW, /DeviceRGB, /DeviceCMYK, /DeviceCMYKgenerate
+
+- upRendering, is the next major uniprint-Parameter and selects the
+ (Color-) Rendering. The following values are currently supported:
+
+ /ErrorDiffusion, /FSCMYK32
+
+ The first is similar to fsmono, fsrgb and fsx4 of stcolor, while the
+ second is (almost) identical to fscmyk/hscmyk, but is restricted to
+ 32Bit-Data and should be used in conjunction with /DeviceCMYKgenerate.
+
+- upOutputFormat, is the final major uniprint-Parameter and selects the
+ Output-Method. The following values are currently supported:
+
+ /SunRaster, /Epson, /EscP2, /EscP2XY, /Pcl
+
+ /SunRaster creates the Raster-Files and requires no other Parameters.
+ /Epson is used for the elderly ESC/P-Format (used by many printers)
+ /EscP2 is used by more recent Epson-printers (no X-Weaving supported)
+ /EscP2XY supports X-Weaving, used with 1440DpI-Printers and in stc2s_h
+ /Pcl is the HP-PCL/RTL-Style output-formatter without weaving.
+
+- -r360x360 is the Standard Resolution-Parameter of Ghostscript
+
+- upMargins="{ 9.0 39.96 9.0 9.0}
+ Has a similar function as the normal Ghostscript-Parameter ".HWMargins",
+ it sets the Left/Bottom/Right/Top-Margins in 1/72" units. Uniprint
+ provides this parameter to enable automatic L<>R exchange, if upYFlip
+ is active.
+
+- upComponentBits, is an array of integers, that selects the Bits stored
+ in Raster-Memory. The Default is to store 8 Bits per component. In this
+ example 1 Bit is selected for each component, thus turning down the
+ Floyd-Steinberg-Algorithm (But the time consuming computation is
+ still carried out, but this will change in future Versions). There is
+ a related Parameter "upComponentShift", which offers control over the
+ positioning of the components within the raster-memory. Each of the
+ given numbers corresponds to a component, and which depends on the
+ selected "upColorModel":
+
+ /DeviceGray /DeviceRGBW /DeviceRGB /DeviceCMYK, /DeviceCMYKgenerate
+ 0 White White Red Black Black
+ 1 - Red Green Cyan Cyan
+ 2 - Green Blue Magenta Magenta
+ 3 - Blue - Yellow Yellow
+
+ This order may not be suitable for some printers, thus there is
+ another Parameter to select the Output-Order. This is an array
+ of integers too, is named "upOutputComponentOrder" and uses the
+ numbers on the left.
+
+One group of very important Parameters, not used in the example above
+deserves to be mentioned here: The Transfer-Arrays, named
+
+ "up<color>Transfer"
+
+where <color> is one of the names in the table above. These are arrays
+of floats in the range from 0.0 to 1.0 and represent the colortransfer
+functions. They are used during mapping _and_ rendering. In the simplest
+case, this arrays ensure an equidistant distribution of the stored
+values within the device-space (Which means a non-linear mapping
+from Ghostscript's point of view). If the given array does not cover
+the entire range from 0 to 1, which applies for the Stylus Color Family
+at high resolution for some media, only the relevant part gets mapped to
+the raster-memory (thus it is fully utilized) and the rendering takes
+care of the "overhang" (In this case the Post-Diffusion of 1 Bit components
+makes sense).
+
+Finally an important note on the Transfer-Arrays: In the case of monochrome
+devices, the stored Component is White, which is the way Postscript defines
+this devices, but most printers require "Black", thus one has to provide
+a falling "upWhiteTransfer" for such printers.
+
+- upWeaveYPasses, is an integer, that gives the number of printhead passes
+ required to achieve the requested Y-DpI. This makes sense only if
+
+- upOutputPins ist set to something greater than 1, thus multiple Pins/Nozzles
+ are transferred with a single command and of course such a command must
+ be supported by the device.
+
+If no other Weave-Parameters are given, uniprint computes several defaults,
+which altogether do no weaving. The /Epson and /EscP2XY-Formats take care
+of "upWeaveXPasses" too.
+
+- upBeginPageCommand, represents the data transferred to the printer,
+ whenever a new Page begins. Prior to that, the "upBeginJobCommand"
+ is written to the device only once per OutputFile. (Intended for the
+ HP-PJL-Sequences).
+
+- upAdjustBottomMarginCommand, upAdjustMediaSize, upAdjustPageLengthCommand,
+ upAdjustPageWidthCommand, upAdjustResolutionCommand,
+ upAdjustTopMarginCommand
+ Normally uniprint does not change the "upBeginPageCommand" nor does it
+ provide a default. But if the above boolean values are set, the corresponding
+ values are changed. (Provided that the code of the formatters supports
+ this change and the commands to be adjusted are included in the
+ BOP-String)
+
+- upEndPageCommand is the fixed termination sequence for each page and
+ of course there is a "upEndJobCommand" too.
+
+- "upAbortCommand" is written, if the interrupt-detection in uniprint
+ is enabled and a signal is caught. It _replaces_ the "upEndPageCommand"
+ _and_ the "upEndJobCommand", thus allowing the indication of an
+ aborted job. (Ghostscript gets an error-return from uniprint in this
+ case and abandons further processing.)
+
+For the ESC/P(2) formats all commands represent binary data, while for
+the PCL/RTL-Formatter some of them are formats for fprintf. This strings
+_must_ have explicitly a trailing '\0'.
+
+I should write more, but time is short and the only recommendation is to
+take a look at the various parameter-files. But at least three more hints
+should be given:
+
+ 1. If the Driver rejects a Configuration, nothing happens until a
+ showpage occurs. Then an error is raised and a message with
+ "CALL-REJECTED upd_print_page..." is printed on stderr.
+
+ 2. uniprint has lots of messages that can be activated by setting bits
+ in the preprocessor macro UPD_MESSAGES. I usually use the compile-
+ time option -DUPD_MESSAGES=0x17 for Configuration-Development.
+ (For the semantics, check the UPD_M_... macros in the source.)
+
+ 3. There is a file "uninfo.ps" distributed. This file prints (on
+ the terminal, not on the printer) the contents of the
+ current-pagedevice-dictionary in alphabetical order. This includes
+ the parameters generated/changed by uniprint.
+
+Quick comments on all Parameters in alphabetical order
+======================================================
+String upAbortCommand - End of Page & File upon Interrupt
+Bool upAdjustBottomMarginCommand - Manipulate B-Marg in upBeginPageCommand
+Bool upAdjustMediaSize - Manipulate Mediasize [intended]
+Bool upAdjustPageLengthCommand - Manipulate P-Lngth in upBeginPageCommand
+Bool upAdjustPageWidthCommand - Manipulate P-Wdth in upBeginPageCommand
+Bool upAdjustResolutionCommand - Manipulate Resolution
+Bool upAdjustTopMarginCommand - Manipulate T-Marg in upBeginPageCommand
+String upBeginJobCommand - Begin of each OutputFile
+String upBeginPageCommand - Begin of each Page
+Float[] upBlackTransfer - Black-Transfer (CMKY* only!)
+Float[] upBlueTransfer - Blue-Transfer
+Int[] upColorInfo - struct gx_device_color_info
+Name upColorModel - Selects Color-Mapping
+Bool/RO upColorModelInitialized - Color-Mapping O.K. (readonly)
+Int[] upComponentBits - Bits stored per Component
+Int[] upComponentShift - Positioning within gx_color_index
+Float[] upCyanTransfer - Cyan-Transfer
+String upEndJobCommand - End of each File unless upAbortCommand
+String upEndPageCommand - End of each Page unless upAbortCommand
+Bool/RO upErrorDetected - Severe (VM) Error, not fully operational
+Bool upFSFixedDirection - Inhbits Direction-Toggling in Rendering
+Bool upFSProcessWhiteSpace - Causes White-Space Rendering
+Bool upFSReverseDirection - Run Rendering in Reverse (if fixed)
+Bool upFSZeroInit - Non-Random Rendering-Initialization
+Bool upFormatXabsolute - Write absolute X-Coordinates
+Bool upFormatYabsolute - Write absolute Y-Coordinates
+Float[] upGreenTransfer - Green-Transfer
+Float[] upMagentaTransfer - Magenta-Transfer
+Float[] upMargins - L/B/R/T-Margins in 1/72"
+String upModel - Comment-String, holds some info
+Bool/RO upOutputAborted - Caught an Interrupt
+Int upOutputBuffers - # of Rendering buffers (2^n)
+Int[] upOutputComponentOrder - Order of Comps when Printing
+Int upOutputComponents - # written Comps, not fully operational
+Name upOutputFormat - Selects Output-Format
+Bool/RO upOutputFormatInitialized - Format-Data o.k. (readonly)
+Int upOutputHeight - Output-Height in Pixels
+Int upOutputPins - # Pins/Nozzles per command
+Int upOutputWidth - Output Width in Pixels
+Int upOutputXOffset - Offset in Pixels, if upFormatXabsolute
+Int upOutputXStep - Divisor / Multiplier for X-Coords
+Int upOutputYOffset - Offset in Pixels, if upFormatYabsolute
+Int upOutputYStep - Divisor / Multiplier for Y-Coords
+Bool/RO upRasterBufferInitialized - GS-Buffer o.k. (readonly)
+Float[] upRedTransfer - Red-Transfer
+Name upRendering - Selects Rendering Algorithm
+Bool/RO upRenderingInitialized - Rendering-Parameters o.k. (readonly)
+String[] upSelectComponentCommands - Establishes Color (Output-Order!)
+String upSetLineFeedCommand - Adjust Linefeed (/Epson only)
+String/RO upVersion - Source code Version (readonly)
+Int[] upWeaveFinalPins - # of Bottom pins on EOP-Passes
+Int upWeaveFinalScan - Begin of EOP-Passes (Y-coord)
+Int[] upWeaveFinalXStarts - X-Pass indices for EOP-Passes
+Int[] upWeaveFinalYFeeds - Y-Increments for EOP-Passes
+Int[] upWeaveInitialPins - # of Top pins on BOP-Passes
+Int upWeaveInitialScan - End of BOP-Passes (Y-Coord)
+Int[] upWeaveInitialXStarts - X-Pass indices for BOP-Passes
+int[] upWeaveInitialYFeeds - Y-Increments for BOP-Passes
+Int upWeavePasses - XPasses * YPasses
+Int upWeaveXPasses - Number of X-Passes
+Int[] upWeaveXStarts - X-Pass indices for normal Passes
+Int[] upWeaveYFeeds - Y-Increments for normal Passes
+Int upWeaveYOffset - # of blank/incomplete scans at BOP
+Int upWeaveYPasses - Number of X-Passes
+Float[] upWhiteTransfer - White Transfer (Monochrome Devices!)
+String[] upWriteComponentCommands - Commands to write each component
+Bool/RO upWroteData - Something (BeginJob) written to Output
+String upXMoveCommand - X-Positioning-command
+String upXStepCommand - Single Step to the right
+Bool upYFlip - Flips Output along the Y-Axis
+String upYMoveCommand - Y-Positioning-Command
+String upYStepCommand - Single Step down
+Float[] upYellowTransfer - Yellow Transfer
+
+Uniprint's Roll of Honor
+========================
+
+I should mention all of the people, who were involved in stcolors
+evolution, but I've decided to start from scratch here:
+
+John P. Beale - for testing the stc600-modi
+Bill Davidson - who triggered some weaving-research (and tested stc2s_h)
+L. Peter Deutsch - who triggered an ease of configuration
+Mark Goldberg - who prepared the stc500-Transfers
+Scott F. Johnston and
+Scott J. Kramer - for testing the stc800-modi
+Martin Lottermoser - for his great commented hpdj-driver
+Helmut Riegler - for the BJC-Extension
+Hans-Gerd Straeter - for some measured transfer-curves and more
+Uli Wortmann - for discussions and his cdj850-driver
+
+my family - for tolerating my printer-driver-hacking,
+
+Duisburg 21-Sep-1997, Gunther Hess
+
+Gunther Hess phone: ++49 203 376273 (MET-evening hours)
+Richard Wagner Strasse 112 E-Mail: gunther@elmos.de
+D-47057 Duisburg
+Germany
+
+### ------------------------------ End --------------------------------- ###
+
+### -- The BJC-600/BJC-4000/BJC-70/Stylewriter 2x00, BJC-800 printers -- ###
+
+This section was written by Yves Arrouye <Yves.Arrouye@marin.fdn.fr>.
+
+
+HISTORY
+-------
+
+The BJC-600 driver was written in the first place by Yoshio Kuniyoshi
+<yoshio@nak.math.keio.ac.jp> and later modified by me, Yves Arrouye
+<Yves.Arrouye@marin.fdn.fr>. We both tried to make it evolve synchronously,
+though Yoshio cannot be reached since a long time.
+
+The drivers are based on code for the HP printers by George Cameron
+<g.cameron@biomed.abdn.ac.uk> (in fact, they are in the same file!),
+so he's the first person to thank!
+
+The 2.00 version of the drivers was a complete rewrite of the driver
+(arguments, optimization, colour handling, in short: everything!) by
+Yves Arrouye. The 2.x release is also the first one to be able to
+use the full width of an A3 paper size...
+
+With the 2.15 release, PostScript Printer Description (PPD) files for
+the drivers are released. They are not complete at the moment but they
+can be used to drive the printers' main features.
+
+VERSION INFORMATION
+-------------------
+
+The BJC-600 driver is version 2.17.00 dated 5/23/96.
+The BJC-800 driver is version 2.17.00 dated 5/23/96.
+
+
+COMPILATION NOTES
+-----------------
+
+Configuration
+-------------
+
+* Default values for options and other stuff
+
+Configuration for the drivers can be made by modifying default values
+in the file gdevbjc.h or on the compilation line. If you don't do
+that, the drivers use reasonable defaults that make them work "as
+expected".
+ All default values given below are defined in this file if you need
+to change them to customize your installation (a bad idea, better use
+options...).
+
+* CMYK to RGB color conversion
+
+By default, the drivers use the same algorithm as Ghostscript to
+convert CMYK colors to RGB. If you prefer to use Adobe formulaes,
+define USE_ADOBE_CMYK_RGB when compiling. (See the top of the
+gdevcdj.c file to see the difference between the two.)
+
+* Vertical centering of the printable area
+
+The drivers center the imageable area horizontally, but not vertically
+so that what can be printed does use the most of the output media. If
+you define BJC_DEFAULT_CENTEREDAREA when compiling, then the top and
+bottom margins will be the same, resulting in a (smaller) vertically
+centered imageable area too.
+
+* Margins
+
+If you define USE_RECOMMENDED_MARGINS then the top and bottom margins
+will be the same (i.e. BJC_DEFAULT_CENTEREDAREA will be defined for
+you) and these margins will be those recommended by Canon, 12.4 mm.
+ Because margins are a complicated thing (due to the fact that one
+does rely on the mechanical precision of the printer), the drivers do
+something about the bottom margin: by default the bottom margin is
+9.54 mm for the bjc600 driver and 7 mm for the bjc800 one. If you
+define USE_TIGHT_MARGINS then the bottom margin is 7 mm for both
+drivers (but I never managed to get my own bjc600 print a line on this
+low bound, hence the greater default). Regardless of the presence of
+this define, USE_FIXED_MARGINS will not allow the bjc800 to use the
+lower 7 mm bottom margin, so if you have a problem with the bottom
+margin on a bjc800, just define that (without defining USE_TIGHT_MARGINS,
+of course).
+
+Compilation
+-----------
+
+Make sure the bjc600 and/or bjc800 devices are in your DEVICE_DEVS
+variable. That is look in the makefile for your platform and add them
+if necessary. This means for example adding them to the DEVICE_DEVS6
+variable. The line should read something like that:
+
+ DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+
+Now if you get an error from make saying that it does not know how to
+make bjc800.dev it's because you have an old makefile with only the
+bjc600 device in it. You then have to copy the lines explaining how to
+make bjc800.dev in your makefile. These lines are in devs.mak (under
+the lines for making bjc600.dev) and should go just after the lines
+for making bjc600.dev.
+
+Testing the margins
+-------------------
+
+A quick way to be sure that the margins you selected (see above) are
+okay is to print a file whose contents are:
+
+ %!
+ clippath stroke showpage
+
+If the margins are okay, you will obtain a rectangle surrounding the
+printable area.
+
+USE OF THE DRIVERS
+------------------
+
+There are two drivers here: the "bjc600" one supports the BJC-600 and
+BJC-4000 (maybe the BJC-70 as well) and the "bjc800" one supports the
+BJC-800 series. When remarks here apply to both drivers, the name
+"bjc" will be used.
+
+Supported Options and Defaults
+------------------------------
+
+(Note: the names "options", "properties" and "parameters" will be used
+to designate the same thing: device parameters that you can change.)
+
+Preamble: if an option is given an incorrect value, an error will
+occur. Unless stated otherwise, this error will be a rangecheckerror.
+ Options may be set from the gs command-line (using the -d and -s
+switches or other predetermined switches if they have an effect on the
+driver) or using the setpagedevice Level 2 operator if Ghostscript has
+been compiled with the level2 device (it should ;-)). There are *no*
+special-purpose operators as one was able to find in Level 1 printers.
+
+The default number of bits per pixel for the bjc is 24 (unless you
+change the value of BJC_BITSPERPIXEL) and corresponds to a CMYK
+printing. Supported modes are 1 bpp and 4 bpp (gray levels), 8 bpp, 16
+bpp, 24 bpp and 32 bpp (colours). Colours are preferrably stored in
+the CMYK model (which means that with 16 bpp there are only 16
+different shades of each color, for example) but it is possible to
+store them as RGB color for some depths.
+ Some modes do Floyd-Steinberg dithering while some others don't and
+use the default Ghostscript halftoning (in fact, when halftoning is used
+dithering takes also place but due to the low point density it is
+usually not efficient and thus invisible).
+
+Here is a short description of each printing mode (expressed in
+bpp/colors):
+
+ 32/4 CMYK Colour printing, Floyd-Steinberg dithering.
+ 24/4 Id. (But each primary colour is stored on 6 bits instead of 8.)
+
+ 24/3 RGB colour printing, Floyd-Steinberg dithering. This mode will
+ *not* use the black cartridge (that's why it exists, for when you
+ don't want to use it ;-)). Each primary colour is stored on 8
+ bits as in the 32/4 mode, but black generation and under-color
+ removal are done on the driver side and not by Ghostscript so you
+ do not have any control on it. (This mode is not supported anymore
+ on this driver.)
+
+ 16/4 CMYK colour printing, halftoned by Ghostscript. FS dithering
+ is still visible here (but the halftone patterns are visible
+ too!).
+
+ 8/4 Id. (But each primary colour is stored on 2 bits instead of 4.)
+
+ 8/3 RGB colour printing. This mode is not intended to be
+ used. What I mean is that it should be used only if you
+ want to use custom halftone screens *and* the halftoning is
+ broken using the 8/4 mode (some versions of gs have this
+ problem).
+
+ 8/1 Gray-levels printing, Floyd-Steinberg dithering.
+
+ 1/1 Gray-levels printing, halftoned by GhostScript.
+
+These modes are selected using the BitsPerPixel *and* Colors integers
+options (either from the command line or in a PostScript program using
+setpagedevice). See below.
+
+A note about darkness of what is printed: Canon printers do print dark,
+really. And the Floyd-Steinberg dithering may eventually darken your image
+too. So you may need to apply gamma correction by calling gs as in
+
+ % gs -sDEVICE=bjc600 gamma.ps myfile.ps
+
+where gamma.ps changes the gamma correction (here to 3 for all colors):
+
+ { 0.45 exp } dup dup currenttransfer setcolortransfer
+
+(0.45 being value giving good results for me, your mileage may vary;
+the bigger the value the lighter the output).
+
+The drivers support printing at 90 dpi, 180 dpi and 360 dpi. Horizontal and
+vertical resolutions must be the same or a limitcheck error will happen. A
+rangecheck will happen too if the resolution is not 90 * 2**n. (If the
+driver is compiled with -DBJC_STRICT a rangecheck will also happen if
+the resolution is not one of those supported. This is not the case as we
+expect that there may be a 720 dpi bjc someday).
+
+Here are the various options supported by the bjc drivers, along with
+their type, supported values, effect(s) and usage:
+
+ BitsPerPixel (int) Choose the depth of the page. Valid values are
+ 1, 8, 16, 24 and 32. Default is 24.
+ Note that when this is set for the first
+ time, the Colors property is automatically
+ adjusted unless it is also specified. Defaults
+ adjustments are show in the table below,
+ default choices are indicated by a star (*).
+ This table gives also the corresponding
+ color models and the rendering method that is
+ visible (GS means Ghostscript halftoning, FS
+ Floyd-Steinberg dithering, and if both are
+ present it means that the dithering of
+ halftones is visible).
+
+ +-----+--------+---+----------+-------+
+ | Bpp | Colors | * | C. Model | Dith. |
+ +-----+--------+---+----------+-------+
+ | 32 | 4 | | CMYK | FS |
+ +-----+--------+---+----------+-------+
+ | 24 | 4 | * | CMYK | FS |
+ | | 3 | | RGB | FS |
+ +-----+--------+---+----------+-------+
+ | 16 | 4 | | CMYK | GS FS |
+ +-----+--------+---+----------+-------+
+ | 8 | 4 | * | CMYK | GS |
+ | | 3 | | RGB | GS |
+ | | 1 | | K (CMYK) | FS |
+ +-----+--------+---+----------+-------+
+ | 1 | 1 | * | K (CMYK) | GS |
+ +-----+--------+---+----------+-------+
+
+ Valid Colors values for allowed
+ BitsPerPixel values.
+
+ Also note that automagical change of one
+ parameter depending on the other one does not
+ work in a setpagedevice call. This means that
+ if you want to change BitsPerPixel to a value
+ whose valid Colors values do not include the
+ actual Colors value, you must change Colors
+ too.
+
+ Colors (int) Choose the number of color components. Valid
+ values are 1, 3 and 4. Default is 4.
+ This setting cannot be used in a PostScript
+ program, only on Ghostscript's command-line.
+ See ProcessColorModel below for what to use to
+ change the number of colors with PostScript
+ code.
+ Note that setting this property does limit
+ the choices of BitsPerPixel. As for the
+ previous property, its first setting may
+ induce a setting of the "other value" (namely
+ BitsPerPixel, here). Valid combinations are
+ shown in the table below (XX indicates that
+ the combination is valid, ** that this is the
+ default).
+
+ +--------+------+------------------------+
+ | | | BitsPerPixel ok values |
+ | Colors | Type +----+----+----+----+----+
+ | | | 32 | 24 | 16 | 8 | 1 |
+ +--------+------+----+----+----+----+----+
+ | 4 | CMYK | XX | ** | XX | XX | |
+ | 3 | RGB | | ** | | XX | |
+ | 1 | K | | | | XX | ** |
+ +--------+------+----+----+----+----+----+
+
+ Valid BitsPerPixel values
+ for allowed Colors values.
+
+ Also note that automagical change of one
+ parameter depending on the other one does not
+ work in a setpagedevice call. This means that
+ if you want to change Colors to a value whose
+ valid BitsPerPixel values do not include the
+ actual BitsPerPixel value, you must change
+ BitsPerPixel too.
+
+ ProcessColorModel (symbol)
+ A symbol taken from /DeviceGray, /DeviceRGB
+ or /DeviceCMYK which can be used to select 1,
+ 3 or 4 colors respectively.
+ Note that this parameter takes precedence
+ over the Colors one, and that both affect the
+ same variable of the driver. (See Colors above
+ for values combined with BitsPerPixel.)
+
+ HWResolution (floats array)
+ An array of 2 floats giving the horizontal and
+ vertical resolution in dots per inch. Supported
+ values are 90, 180 and 360 and both values
+ must be the same. Default is 360.
+ (On the gs command line, the resolution is
+ changed by saying "-rXDPIxYDPI".)
+
+ ManualFeed (bool) Indicate that the sheets won't be fed automatically
+ by the printer. Default is false.
+ (Not meaningful on the BJC-600, I fear.)
+
+ MediaType (string) Choose the media to print on. Values are chosen
+ amongst "PlainPaper", "CoatedPaper",
+ "TransparencyFilm", "Envelope", "Card" and "Other".
+ Default is "PlainPaper".
+ If the chosen media is "Envelope", "Card" or
+ "Other", the driver will make the printer go
+ in thick mode automatically regardless of the
+ media weight.
+
+ MediaWeight (int or null)
+ Choose the weight of the media (in g/m2). Using
+ null indicates that the weight is of no
+ importance. Default is null.
+ If the specified media weight is greater
+ than 105 (i.e. the value of the compilation
+ default BJC???_MEDIAWEIGHT_THICKLIMIT) then
+ the printer will be setup to use thick paper.
+
+ PrintQuality (string) Choose the quality of printing. For the bjc600
+ driver it can be one of "Normal", "High" and
+ "Draft". For the bjc800 driver it can be one
+ of "Low", "Normal", "High" and "Draft".
+ Default is "Normal" for both drivers.
+ For both drivers, "High" means 200% black and
+ 100% cyan, magenta and yellow (on a bjc600 you
+ will get the "Bk+" light).
+ For the bjc600 driver, "Normal" lits the
+ "HQ" light while "Draft" unlits it.
+ For the bjc800 driver, "Low" has the effect
+ of making only two printing passes instead of
+ four (should be twice as fast ;-)). This is
+ what is known as "CN" (Color Normal) mode.
+
+ DitheringType (string)
+ Choose a dithering algorithm. Actually the
+ only valid values are "Floyd-Steinberg" and
+ "None". "None" is the default for 1/1 print
+ mode, "Floyd-Steinberg" for other modes.
+ At the moment this parameter is read-only,
+ though no error will be generated if one tries
+ to change it.
+ This parameter is not of much value at the
+ moment and is mainly here to reserve the name
+ for future addition of dithering algorithms.
+
+ PrintColors (int) Mask for printing color. If 0, use black for
+ any color.
+ Otherwise, the value must be the sum of any
+ of 1 (cyan), 2 (magenta), 4 (yellow) and 8
+ (black), indicating which colors will be used
+ for printing.
+ When printing colour, only those colour
+ specified will be printed (this means that
+ some planes will be missing).
+ When printing grays, black is used if it is
+ present in the PrintColors; otherwise, the
+ data is printed by superimposing each
+ requested color.
+
+ MonochromePrint (bool)
+ *For bjc600 only*. Substitute black for Cyan,
+ Magenta and Yellow when printing (useful for
+ getting some monochrome output of a dithered
+ printing for example). Default is false.
+ This is a hardware mechanism as opposed to
+ the previous software one. I think that using
+ this or setting PrintColors to 0 will give the
+ same results.
+
+Note that the MediaType and ThickMedia options will be replaced by the use
+of the device InputAttributes and OutputAttributes as soon as possible.
+
+Please note too that the print mode may be reset at the start of a print,
+not at the end. This is the expected behaviour. If you need to reset
+the printer to its default state, simply print a file that does just a
+showpage.
+
+Device Informations
+-------------------
+
+Here are other informations published by the driver that you will find
+in the deviceinfo dictionary:
+
+ OutputFaceUp (bool) This has the boolean value true, indicating that
+ the sheets are stacked face up.
+
+ Version (float) In the form M.mmpp where M is the major version,
+ mm the bjc drivers minor version and pp the specific
+ driver minor version (that is, M.mm will always be
+ the same for the bjc600 and bjc800 drivers).
+
+ VersionString (string)
+ A string that gives the version info plus
+ other indications. At the moment, things like
+ 'a' or 'b' may follow the version to indicate
+ alpha or beta versions and the date of the
+ last change to this version is given in the
+ form MM/DD/YY (no, it won't adapt to your
+ locale!).
+
+Hardware Margins
+----------------
+
+The BJC printers have top and bottom hardware margins of 3 mm and 7.1
+mm respectively (Canon says 7 mm but this is not usable because of
+the rounding of paper sizes to PostScript points).. The left margin is
+3.4 mm for A4 and smaller paper sizes, 6.4 mm for US paper sizes,
+envelopes and cards. It is 4.0 mm for A3 paper on the BJC-800.
+
+The maximum printing width of a BJC-600 printer is 203 mm, in any event.
+The maximum printing width of a BJC-800 printer is 289 mm on A3 paper,
+and 203 mm on letter and A4 paper.
+
+
+POSTSCRIPT PRINTER DESCRIPTION FILES
+------------------------------------
+
+The BJC600.PPD and BJC800.PPD files (whose long names are, respectively,
+Canon_BubbleJetColor_600.ppd and Canon_BubbleJetColor_800.ppd) are PPD
+files driving the features of the bjc600 and bjc800 drivers.
+
+They can be used for example on NEXTSTEP systems (presumably on
+OpenStep systems too) and on Unix systems with Adobe's TranScript and
+pslpr (not tested).
+
+The files are not complete at the moment. Please note too that
+NEXTSTEP's printing interface does not correctly enforce constraints
+specified in these files (in UIConstraints descriptions): you must
+force yourself to use valid combinations of options.
+
+Customization of the PPD files
+------------------------------
+
+By default the files say that the paper used is US Letter, and they
+use a normalized transfer function.
+ If you choose to use A4 printing by default, you must replace Letter by
+A4 in lines that match the '\*Default.*: Letter' pattern.
+ Some versions of Ghostscript have problems with normalized colors,
+which makes them add magenta in gray levels. If you have this problem,
+replace the '*DefaultTransfer: Normalized' line by the alternate (correct)
+'*DefaultTransfer: Null' line.
+
+Also note that the 'Thick Media' option is implemented by choosing a
+value of 120 or 80 (for thick and thin media respectively) for the
+MediaWeight feature of the drivers. If you ever change the threshold
+for thick media in the driver code, you may need to change the values
+in the PPD files too.
+
+All customization should be done using the '*Include: ' feature of PPD
+files so that your local changes will be kept if you get an update of
+these PPD files.
+
+
+OTHER INFORMATIONS
+------------------
+
+Reporting Problems
+------------------
+
+When you report a problem please be as descriptive as possible, and
+please send information that can be used to reproduce the problem.
+ Please don't forget to tell me which driver you use and its
+version. Version information can be found in this file or preferrably
+by issuing the following command in a shell:
+
+ % echo "currentpagedevice /VersionString get ==" | \
+ gs -q -sDEVICE=bjc600 -
+
+(the % doesn't count as part of the command and the device name should
+be the device you really use).
+
+Contact Address
+---------------
+
+If you have problems with this driver (or if you are extremely
+satisfied with it) you may email me at Yves.Arrouye@marin.fdn.fr.
+
+Acknowledgements
+----------------
+
+I am particularly grateful to Yoshio Kuniyoshi <yoshio@nak.math.keio.ac.jp>
+without whom I'd never make these drivers and also to L. Peter Deutsch
+<ghost@aladdin.com> who answered *all* my (often silly) questions about
+the drivers interface used by Ghostscript.
+ Thanks also to the people who volunteered to beta-test the v2.x BJC
+drivers; David Gaudine <david@donald.concordia.ca>, Robert M. Kenney
+<rmk@unh.edu>, James McPherson <someone@erols.com> and Ian Thurlbeck
+<ian@stams.strath.ac.uk> (in an alphabetic listing) were particularly
+helpful by discovering bugs and helping find out exact paper margins on
+printers I don't have access to.
+ And *many* thanks to Klaus-Gunther Hess <gunther@elmos.de> for
+looking at the dithering code and devising a good CMYK dithering
+algorithm for the Stylus Color, which I then adapted to the code of
+these drivers.
+
+### ------------------------------ End --------------------------------- ###
+
+### ---------------- MS-Windows DIB printer driver ----------------- ###
+
+This section was written by Russell Lang, 4 September 1996
+
+The mswinpr2 device uses MS-Windows printer drivers and should work
+with any printer with DIB raster capabilities.
+The printer resolution cannot be selected using PostScript commands
+from Ghostscript; use the printer setup in the Control Panel instead.
+
+If no Windows printer name is specified in -sOutputFile, Ghostscript
+will prompt for a Windows printer using the standard Print Setup
+dialog box. You must set the orientation to Portrait, and you must
+set the page size to that expected by Ghostscript. Failure to do so
+will result in the image being clipped. Ghostscript sets the physical
+device size to that of the Windows printer driver, but it does not
+update the PostScript clipping path.
+
+If a Windows printer name is specified in -sOutputFile, using
+the format "\\spool\printer_name", e.g.
+ -sOutputFile="\\spool\Apple LaserWriter II NT"
+then Ghostscript will attempt to open the Windows printer without
+any prompts (except of course if the printer is connected to FILE:).
+Ghostscript attempts to set the Windows printer page size and orientation
+to match that expected by Ghostscript, but doesn't always succeed.
+The following algorithm is used:
+- If the requested page size matches one of the Windows standard
+ page sizes +/- 2mm, ask for that standard size.
+- Otherwise if the requested page size matches one of the Windows
+ standard page sizes in landscape mode, ask for that standard size
+ in landscape.
+- Otherwise ask for the page size by specifying its dimensions only.
+- If using Windows NT, select a form that matches the page size.
+ (This isn't working at the moment)
+- Merge the above requests with the defaults.
+ If the printer driver ignores the requested paper size, no
+ error will be generated. It will print on the wrong paper size.
+- Open the Windows printer with the merged orientation and size.
+The Ghostscript physical device size will be updated to match
+the Windows printer physical device.
+
+### ------------------------- JPEG file format ------------------------- ###
+
+Ghostscript includes output drivers that can produce JPEG (JFIF) files from
+Postscript images. *Please note* that JPEG is designed for continuous-tone
+images (such as photographs) and is therefore quite unsuitable for the vast
+majority of page images produced with Postscript. If you get crummy-looking
+JPEG files, don't blame Ghostscript; instead consult a reference about uses
+and abuses of JPEG, such as the JPEG FAQ available at
+http://www.faqs.org/faqs/jpeg-faq/.
+
+There are two JPEG output drivers, "jpeg" to produce color JPEG files and
+"jpeggray" to produce grayscale JPEGs. Basic usage is the same as for other
+file-format drivers: specify the device name and an output file name, for
+example
+ gs -sDEVICE=jpeg -sOutputFile=foo.jpg foo.ps
+You can also use the -r switch to determine the imaging resolution and thus
+the output file's size in pixels. (The default resolution is normally
+72x72dpi.)
+
+The JPEG devices support two special parameters to control the JPEG "quality
+setting" (DCT quantization level). You can write
+ -dJPEGQ=number
+to set the quality level according to the widely used IJG quality scale; or
+if you prefer Adobe's QFactor quality scale, use
+ -dQFactor=number
+The QFactor scale is used by Postscript's DCTEncode filter but is nearly
+unheard-of elsewhere.
+
+-dJPEGQ accepts an integer from 0 to 100, while -dQFactor expects a decimal
+fraction near 1.0. The default quality level is equivalent to -dJPEGQ=75.
+(At this writing, that is the same as -dQFactor=0.5; but the IJG default
+quality level might change in future releases.)
+
+The JPEG drivers could be extended to support additional JPEG compression
+options, such as the other DCTEncode filter parameters, but so far they
+haven't been.
+
+### ------------------------------ End --------------------------------- ###
diff --git a/gs/dll.txt b/gs/dll.txt
new file mode 100644
index 000000000..66890133c
--- /dev/null
+++ b/gs/dll.txt
@@ -0,0 +1,554 @@
+/* Copyright (C) 1994-1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, dll.txt, describes how to use the Ghostscript Dynamic
+Link Library.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+==================================
+DLL.TXT 1996-09-05
+==================================
+
+For the OS/2, Win16 and Win32 platforms, Ghostscript is compiled
+as a dynamic link library.
+
+To provide the interface described in use.txt, a smaller EXE loads
+this Ghostscript DLL.
+This EXE provides image windows and if necessary, a text window.
+The source for the EXE is in dp*.* for OS/2 and dw*.* for Windows.
+Refer to these source files for examples of DLL usage.
+
+This document document describes the DLL interface.
+
+The Win16 DLL (GSDLL16.DLL) is a large memory model DLL with far
+static data. Due to the limitations of 16 bit MS-Windows, the DLL
+can be used by only one program at a time.
+
+The Win32 DLL (GSDLL32.DLL) has MULTIPLE NONSHARED data segments.
+Under Win32s it can be used by only one program at a time.
+Under Windows 95 or NT it can be called by multiple programs.
+
+The OS/2 DLL (GSDLL2.DLL) has MULTIPLE NONSHARED data segments and
+can be called by multiple programs.
+
+The interface to the DLL consists of 8 main functions, 1 provided
+by the caller and the other 7 by the DLL. Some other platform
+dependant functions are provided by the DLL for display devices.
+
+=============
+DLL functions
+=============
+The seven functions provided by the DLL are:
+ int GSDLLAPI gsdll_revision(char **product, char **copyright,
+ long *gs_revision, long *gs_revisiondate)
+ int GSDLLAPI gsdll_init(GSDLL_CALLBACK callback, HWND hwnd,
+ int argc, char *argv[]);
+ int GSDLLAPI gsdll_execute_begin(void);
+ int GSDLLAPI gsdll_execute_cont(const char *str, int len);
+ int GSDLLAPI gsdll_execute_end(void);
+ int GSDLLAPI gsdll_exit(void);
+ int GSDLLAPI gsdll_lock_device(unsigned char *device, int flag);
+
+For OS/2, GSDLLAPI is defined as
+ #define GSDLLAPI
+For Win32 and Win16, GSDLLAPI is defined as
+ #define GSDLLAPI CALLBACK _export
+
+----------------
+gsdll_revision()
+----------------
+This returns the revision numbers and strings of the Ghostscript DLL.
+This function may be called before gsdll_init().
+An example:
+ char *product;
+ char *copyright;
+ long revision;
+ long revisiondate;
+ gsdll_revision(&product, &copyright, &revision, &revisiondate);
+NULL pointers may be used if you do not want a particular value.
+
+It is recommended that this function be called before gsdll_init()
+to make sure that the correct version of the Ghostscript DLL
+has been loaded.
+
+------------
+gsdll_init()
+------------
+The function gsdll_init() must be called after loading
+the DLL and before executing any ghostscript commands.
+The arguments are the address of the callback function,
+a parent window handle, the count of arguments and an
+array of pointers to the arguments.
+For example
+ char *argv[5];
+ argv[0] = "gswin.exe";
+ argv[1] = "-Ic:\\gs;c:\gs\\fonts";
+ argv[2] = "-dNOPAUSE",
+ argv[3] = "-sDEVICE=djet500",
+ argv[4] = NULL;
+ };
+ argc = 4;
+ code = gsdll_init(gsdll_callback, hwnd, argc, argv);
+
+hwnd is used as the parent window handle for any windows
+created by Ghostscript.
+hwnd may be NULL if the caller does not have any windows, but
+if NULL you should avoid using devices which may open windows.
+
+If the return code is zero then there is no error.
+gsdll_execute_begin() or gsdll_exit() may now be called.
+
+If the return value is non-zero then gsdll_exit() must not be called.
+
+A return value of GSDLL_INIT_QUIT indicates that one of the
+command line files or arguments called 'quit', or that GS
+was reading stdin and reached EOF. This is not an error.
+gsdll_exit() must not be called.
+
+A return value of GSDLL_INIT_IN_USE indicates that the DLL is
+in use by another application (Windows 3.1 only).
+The DLL should be immediately unloaded (or the caller terminated).
+gsdll_exit() must not be called.
+
+
+---------------------
+gsdll_execute_begin()
+---------------------
+This must be called after gsdll_init() and before gsdll_execute_cont();
+
+
+--------------------
+gsdll_execute_cont()
+--------------------
+After successfully calling gsdll_init() and gsdll_execute_begin(),
+commands may be given to Ghostscript with gsdll_execute_cont().
+Examples are:
+ char *command = "1 2 add == flush\n";
+ code = gsdll_execute_cont(command, strlen(command));
+ command = "qu"
+ code = gsdll_execute_cont(command, strlen(command));
+ command = "it\n"
+ code = gsdll_execute_cont(command, strlen(command));
+return code is zero if there are no errors.
+return code is less than zero if an error has occured.
+return code is less than or equal to -100 if "quit" has been
+ executed or a fatal error has occured.
+ gsdll_exit() must then be called - do not call gsdll_execute_end().
+gsdll_execute_cont does not flush stdio - if you want to see output from
+Ghostscript you must do this explicitly as shown in the example above.
+
+When executing a string with gsdll_execute_cont, currentfile is the
+input from gsdll_execute_cont. Reading from %stdin will use the
+callback.
+
+
+-------------------
+gsdll_execute_end()
+-------------------
+If gsdll_execute_cont() did not return an error, then gsdll_execute_end()
+must be called after gsdll_execute_cont() and before gsdll_exit();
+
+
+----------
+gsdll_exit
+----------
+To terminate the Ghostscript DLL, gsdll_exit() is called.
+This must be called if a fatal error has occured (see return
+value of gsdll_execute_cont).
+After calling gsdll_exit(), there are two options:
+1. Unload the DLL, either by terminating the application or by
+calling DosFreeModule (OS/2) or FreeLibrary (MS-Windows).
+2. Call gsdll_init() again to restart Ghostscript.
+
+
+-----------------
+gsdll_lock_device
+-----------------
+Since the caller may be multithreaded, a lock is needed to control
+access to the display device. This is accessed via the following
+function.
+
+int gsdll_lock_device(unsigned char *device, int flag);
+ /* Lock the device if flag = TRUE */
+ /* Unlock the device if flag = FALSE */
+ /* device is a pointer to Ghostscript os2dll or mswindll device */
+ /* from GSDLL_DEVICE message. */
+ /* Return value is the lock count. */
+
+To lock the device use
+ gsdll_lock_device(device, 1);
+To unlock the device use
+ gsdll_lock_device(device, 0);
+
+Locking the device prevents the Ghostscript DLL from closing
+the device or changing the device size or depth.
+Ghostscript may draw into the device bitmap or update the palette
+entries while the device is locked by the caller.
+
+This function is typically used to lock the device while
+repainting a window, or copying the device bitmap to the clipboard.
+
+Under OS/2, Win95 and WinNT, this lock is implemented using
+a mutual exclusion semaphore (mutex). The return value is
+the lock count, which will be either 0 or 1, for unlocked and
+locked respectively.
+This function will block until the device is locked by the caller.
+
+Under Win16 or Win32s, gsdll_lock_device will always return
+immediately, giving a lock count as the return value. If
+a lock value of 2 or more is returned, beware!
+Access to the device should be controlled by checking the
+windows message queue only when the bitmap is not being accessed.
+
+=================
+Callback function
+=================
+A callback function must be provided by the caller and given
+as an argument to gsdll_init().
+The callback function is called by the DLL for stdio and to notify
+the caller about device events.
+
+The function provided by the caller has the following prototype:
+ int gsdll_callback(int message, char *str, unsigned long count);
+The pascal calling convention is not used.
+
+An example callback function is:
+ int
+ gsdll_callback(int message, char *str, unsigned long count)
+ {
+ char *p;
+ switch (message) {
+ case GSDLL_STDIN:
+ p = fgets(str, count, stdin);
+ if (p)
+ return strlen(str);
+ else
+ return 0;
+ case GSDLL_STDOUT:
+ if (str != (char *)NULL)
+ fwrite(str, 1, count, stdout);
+ return count;
+ case GSDLL_DEVICE:
+ fprintf(stdout,"Callback: DEVICE %p %s\n", str,
+ count ? "open" : "close");
+ break;
+ case GSDLL_SYNC:
+ fprintf(stdout,"Callback: SYNC %p\n", str);
+ break;
+ case GSDLL_PAGE:
+ fprintf(stdout,"Callback: PAGE %p\n", str);
+ break;
+ case GSDLL_SIZE:
+ fprintf(stdout,"Callback: SIZE %p width=%d height=%d\n", str,
+ (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
+ break;
+ case GSDLL_POLL:
+ return 0; /* no error */
+ default:
+ fprintf(stdout,"Callback: Unknown message=%d\n",message);
+ break;
+ }
+ return 0;
+ }
+
+
+The messages used by the callback are:
+ #define GSDLL_STDIN 1 /* get count characters to str from stdin */
+ /* return number of characters read */
+ #define GSDLL_STDOUT 2 /* put count characters from str to stdout*/
+ /* return number of characters written */
+ #define GSDLL_DEVICE 3 /* device = str has been opened if count=1 */
+ /* or closed if count=0 */
+ #define GSDLL_SYNC 4 /* sync_output for device str */
+ #define GSDLL_PAGE 5 /* output_page for device str */
+ #define GSDLL_SIZE 6 /* resize for device str */
+ /* LOWORD(count) is new xsize */
+ /* HIWORD(count) is new ysize */
+ #define GSDLL_POLL 7 /* Called from gp_check_interrupt */
+ /* Can be used by caller to poll the message queue */
+ /* Normally returns 0 */
+ /* To abort gsdll_execute_cont(), return a */
+ /* non zero error code until gsdll_execute_cont() */
+ /* returns */
+
+==========================
+Example DLL usage for OS/2
+==========================
+The following example shows a minimal usage of the Ghostscript DLL.
+The example callback function above is needed.
+
+#define INCL_DOS
+#include <os2.h>
+#include <stdio.h>
+#include "gsdll.h"
+
+PFN_gsdll_init pgsdll_init;
+PFN_gsdll_execute_begin pgsdll_execute_begin;
+PFN_gsdll_execute_cont pgsdll_execute_cont;
+PFN_gsdll_execute_end pgsdll_execute_end;
+PFN_gsdll_exit pgsdll_exit;
+
+HMODULE hmodule_gsdll;
+char buf[256];
+
+int
+main(int argc, char *argv[])
+{
+int code;
+APIRET rc;
+ if (!DosLoadModule(buf, sizeof(buf), "GSDLL2", &hmodule_gsdll)) {
+ fprintf(stderr, "Loaded GSDLL2\n");
+ DosQueryProcAddr(hmodule_gsdll, 0, "gsdll_init", (PFN *)(&pgsdll_init));
+ DosQueryProcAddr(hmodule_gsdll, 0, "gsdll_execute_begin", (PFN *)(&pgsdll_execute_begin));
+ DosQueryProcAddr(hmodule_gsdll, 0, "gsdll_execute_cont", (PFN *)(&pgsdll_execute_cont));
+ DosQueryProcAddr(hmodule_gsdll, 0, "gsdll_execute_end", (PFN *)(&pgsdll_execute_end));
+ DosQueryProcAddr(hmodule_gsdll, 0, "gsdll_exit", (PFN *)(&pgsdll_exit));
+ }
+ else {
+ fprintf(stderr, "Can't load GSDLL2\n");
+ }
+
+ code = (*pgsdll_init)(gsdll_callback, NULL, argc, argv);
+ fprintf(stdout,"gsdll_init returns %d\n", code);
+ code = (*pgsdll_execute_begin)();
+ if (code==0) {
+ while (fgets(buf, sizeof(buf), stdin)) {
+ code = (*pgsdll_execute_cont)(buf, strlen(buf));
+ fprintf(stdout,"gsdll_execute returns %d\n", code);
+ if (code < 0)
+ break;
+ }
+ if (!code)
+ code = (*pgsdll_execute_end)();
+ code = (*pgsdll_exit)();
+ fprintf(stdout,"gsdll_exit returns %d\n", code);
+ }
+ rc = DosFreeModule(hmodule_gsdll);
+ fprintf(stdout,"DosFreeModule returns %d\n", rc);
+ return 0;
+}
+
+===============================
+Ghostscript DLL device for OS/2
+===============================
+The os2dll device is provided in the Ghostscript DLL for use
+by the caller. No drawing facilities are provided by the DLL
+because the DLL may be loaded by a text only (non PM) application.
+
+The caller will be notified via the gsdll_callback when a new
+os2dll device is opened or closed (GSDLL_DEVICE), when the window
+should be redrawn (GSDLL_SYNC or GSDLL_PAGE) or when the bitmap
+size changes (GSDLL_SIZE).
+
+Note that more than one os2dll device may be opened.
+
+One DLL function is available for accessing the os2dll device:
+
+----------------
+gsdll_get_bitmap
+----------------
+The following function returns a pointer to a bitmap in BMP format.
+The os2dll device draws into this bitmap.
+
+unsigned long gsdll_get_bitmap(unsigned char *device, unsigned char **pbitmap);
+ /* return in pbitmap the address of the bitmap */
+ /* device is a pointer to Ghostscript os2dll device from GSDLL_DEVICE message */
+
+The caller can then display the bitmap however it likes, but should
+lock the bitmap with gsdll_lock_device() before painting from it,
+and unlock it afterwards. The bitmap address will not change until
+the os2dll device is closed, however the bitmap size and palette
+may change at any time the bitmap is not locked.
+
+=====================================
+Ghostscript DLL device for MS-Windows
+=====================================
+The mswindll device is provided in the Ghostscript DLL for use
+by the caller.
+
+The caller will be notified via the gsdll_callback when a new
+mswindll device is opened or closed (GSDLL_DEVICE), when the window
+should be redrawn (GSDLL_SYNC or GSDLL_PAGE) or when the bitmap
+size changes (GSDLL_SIZE).
+
+Note that more than one mswindll device may be opened.
+
+Four extra DLL functions are available for accessing the mswindll device:
+
+--------------
+gsdll_copy_dib
+--------------
+This function is commonly used when copying the mswindll bitmap
+to the clipboard.
+
+/* make a copy of the device bitmap and return shared memory handle to it */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+HGLOBAL GSDLLAPI gsdll_copy_dib(unsigned char *device);
+
+------------------
+gsdll_copy_palette
+------------------
+This function can be used when copying the mswindll palette
+to the clipboard.
+
+/* make a copy of the device palette and return a handle to it */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+HPALETTE GSDLLAPI gsdll_copy_palette(unsigned char *device);
+
+----------
+gsdll_draw
+----------
+This function is used for displaying output from the mswindll device.
+The caller should create a window and call gsdll_draw in response to
+the WM_PAINT message. The device context hdc must be for a device
+because SetDIBitsToDevice() is used.
+
+/* copy the rectangle src from the device bitmap */
+/* to the rectangle dest on the device given by hdc */
+/* hdc must be a device context for a device (NOT a bitmap) */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+void GSDLLAPI gsdll_draw(unsigned char *device, HDC hdc,
+ LPRECT dest, LPRECT src);
+
+--------------------
+gsdll_get_bitmap_row
+--------------------
+The following function returns a BMP header, a palette and a pointer
+to a row in the bitmap.
+
+int GSDLLAPI gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE *ppbyte, unsigned int row)
+/* Copy bitmap
+ * If pbmih nonzero, copy the BITMAPINFOHEADER.
+ * If prgbquad nonzero, copy the palette.
+ * number of entries copied is given by pbmih->biClrUsed
+ * If ppbyte nonzero, return pointer to row.
+ * pointer is only valid while device is locked
+ * GS can change the palette while the device is locked.
+ * Do not call this function while GS is busy.
+ *
+ * This function exists to allow the bitmap to be copied to a file
+ * or structured storage, without the overhead of having two copies
+ * of the bitmap in memory at the same time.
+ */
+
+================
+MS-Windows 16bit
+================
+This platform has the most problems of the three.
+Support for it may be dropped in future.
+
+The Win16 DLL (GSDLL16.DLL) is a large memory model DLL with far
+static data. Due to the limitations of 16 bit MS-Windows, the DLL
+can used by only one program at a time.
+However, GSDLL16 is marked as having SINGLE SHARED data segments which
+allows multiple applications to load GSDLL16. (The DLL wouldn't load
+at all if MULTIPLE NONSHARED was used). Applications loading GSDLL16
+should check the return value of gsdll_init(). If it is non-zero
+then GSDLL16 is already in use by another application and should NOT
+be used. GSDLL16 should be unloaded immediately using FreeLibrary(),
+or the caller program should terminate.
+
+The segmented architecture of the 80286 causes the usual amount of
+grief when using GSDLL16.
+Because the callback is called from the DLL which is using a different
+data segment, the callback must be declared as _far _export.
+ int _far _export gsdll_callback(int message, char *str, unsigned long count);
+Instead of giving gsdll_init the address of gsdll_callback, it should
+instead be given the address of a thunk created by MakeProcInstance.
+This thunk changes the data segment back to that used by the caller:
+ FARPROC lpfnCallback;
+ lpfnCallback = (FARPROC)MakeProcInstance((FARPROC)gsdll_callback, hInstance);
+ code = (*pgsdll_init)((GSDLL_CALLBACK)lpfnCallback, NULL, argc, argv);
+ if (!code) {
+ fprintf(stderr, "GSDLL16 is already in use\n");
+ return -1;
+ }
+
+==================
+Changes 1996-09-05
+==================
+Ghostscript locks the device just before closing it, to prevent
+closing the device while the caller is drawing from it.
+
+Added gsdll_get_bitmap_row() to MS-Windows.
+
+==================
+Changes 1996-07-02
+==================
+gsdll_init() error code changed.
+
+==================
+Changes 1996-05-30
+==================
+gsdll_init() error code changed.
+
+==================
+Changes 1996-05-16
+==================
+Added HWND as a parameter to gsdll_init().
+THIS IS A NON BACKWARD COMPATIBLE CHANGE.
+
+Documented that gsdll_execute_end() must not be called if
+gsdll_execute_cont() returns with error.
+
+
+==================
+Changes 1996-03-16
+==================
+New call back message GSDLL_POLL.
+
+Removed OS/2 gsdll_lock_bitmap(). Replaced by gsdll_lock_device().
+
+Add gsdll_lock_device to OS/2 and MS-Windows.
+ For non multi-threaded environments (Win16, Win32s) this will
+ return a lock count but return immediately.
+ For multi-threaded environments this will maintain a lock
+ using a mutex (which may block).
+
+Changed gsdll_init() to take argc and argv. Now supports the
+ full range of Ghostscript command line options.
+
+*** OS/2 has't been tested yet.
+
+==================
+Changes 1995-07-26
+==================
+gsdll_revision needs to be checked before using other APIs,
+ to protect against finding a later version of the GS DLL
+ with changed APIs.
+
+gsdll_execute removed.
+gsdll_execute_begin/cont/end added.
+ Keywords can now be split across calls to gsdll_execute_cont.
+ DLL input can now be done without using the stdin callback
+
+Now use GSDLLAPI instead of WINAPI
+ Under Windows, the calling convention is CALLBACK, not pascal.
+ For Win32 this is _stdcall, for Win16 this is _far _pascal.
+
+
+Original version 1994-07-03
+
+====================
+/* end of dll.txt */
+====================
diff --git a/gs/doc/Gs-vms.hlp b/gs/doc/Gs-vms.hlp
new file mode 100644
index 000000000..6a19e3ecd
--- /dev/null
+++ b/gs/doc/Gs-vms.hlp
@@ -0,0 +1,290 @@
+1 gs
+ gs - Aladdin Ghostscript interpreter/previewer
+! This file describes version 5.13 of Aladdin Ghostscript.
+! 27 April 1998
+ Usage:
+ $ gs [options] [file ...]
+
+ Ghostscript is an implementation of Adobe Systems' PostScript (tm)
+ and Portable Document Format (PDF) languages. Gs reads files in sequence
+ and executes them as Ghostscript programs. After doing this, it reads
+ further input from the standard input stream (normally the keyboard).
+ Each line is interpreted separately. To exit from the interpreter,
+ enter the `quit' command. The interpreter also exits gracefully if it
+ encounters end-of-file. Typing the interrupt character (e.g. Control-C)
+ is also safe.
+
+2 Description
+ The interpreter recognizes several switches described below, which
+ may appear anywhere in the command line and apply to all files
+ thereafter.
+
+ You can get a help message by invoking Ghostscript with the -h
+ or -? option. This message also lists the available devices.
+
+ Ghostscript may be built with multiple output devices. Ghostscript
+ normally opens the first one and directs output to it. To use
+ device xyz as the initial output device, include the switch
+ "-sDEVICE=xyz"
+ in the command line. Note that this switch must precede the first
+ .ps file, and only its first invocation has any effect. For example,
+ for printer output in a normal configuration that includes an Epson
+ printer driver, you might use the command
+ gs "-sDEVICE=epson" myfile.ps
+ instead of just
+ gs myfile.ps
+ Alternatively, you can type
+ (epson) selectdevice
+ (myfile.ps) run
+ All output then goes to the printer instead of the display until
+ further notice. You can switch devices at any time by using the
+ selectdevice procedure, e.g.,
+ (vga) selectdevice
+ or
+ (epson) selectdevice
+ As yet a third alternative, you can define a logical name GS_DEVICE
+ as the desired default device name. The order of precedence for these
+ alternatives, highest to lowest, is:
+ selectdevice
+ (command line)
+ GS_DEVICE
+ (first device in build list)
+
+ To select the density on a printer, use
+ gs "-sDEVICE=<device>" -r<xres>x<yres>
+ For example, on a 9-pin Epson-compatible printer, you can get the
+ lowest-density (fastest) mode with
+ gs "-sDEVICE=epson" -r60x72
+ and the highest-density mode with
+ gs "-sDEVICE=epson" -r240x72.
+
+ If you select a printer as the output device, Ghostscript also
+ allows you to control where the device sends its output. Normally,
+ output goes directly to a scratch file on Unix and VMS systems. To
+ send the output to a series of files foo1.xyz, foo2.xyz, ..., use
+ the switch
+ "-sOutputFile=foo%d.xyz"
+ The %d is a printf format specification; you can use other formats
+ like %02d. Each file will receive one page of output. Alternatively,
+ to send the output to a single file foo.xyz, with all the pages con-
+ catenated, use the switch
+ "-sOutputFile=foo.xyz"
+
+ To find out what devices are available, type
+ devicenames ==
+ after starting up Ghostscript. Alternatively, you can use the -h or -?
+ switch in the command line; the help message also lists the available
+ devices.
+
+ To select a different paper size, use the command line switch
+ "-sPAPERSIZE=a_known_paper_size"
+ e.g.,
+ "-sPAPERSIZE=a4"
+ or
+ "-sPAPERSIZE=legal"
+
+ As of this printing, the known paper sizes, defined in gs_statd.ps, are:
+
+ PAPERSIZE X" Y" X cm Y cm
+ ____________________________________________________
+ 11x17 11" 17" 27.94 43.18
+ a0 33.0556" 46.7778" 83.9611 118.816
+ a10 1.02778" 1.45833" 2.61056 3.70417
+ a1 23.3889" 33.0556" 59.4078 83.9611
+ a2 16.5278" 23.3889" 41.9806 59.4078
+ a3 11.6944" 16.5278" 29.7039 41.9806
+ a4 8.26389" 11.6944" 20.9903 29.7039
+ a5 5.84722" 8.26389" 14.8519 20.9903
+ a6 4.125" 5.84722" 10.4775 14.8519
+ a7 2.91667" 4.125" 7.40833 10.4775
+ a8 2.05556" 2.91667" 5.22111 7.40833
+ a9 1.45833" 2.05556" 3.70417 5.22111
+ archA 9" 12" 22.86 30.48
+ archB 12" 18" 30.48 45.72
+ archC 18" 24" 45.72 60.96
+ archD 24" 36" 60.96 91.44
+ archE 36" 48" 91.44 121.92
+ b0 39.3889" 55.6667" 100.048 141.393
+ b1 27.8333" 39.3889" 70.6967 100.048
+ b2 19.6944" 27.8333" 50.0239 70.6967
+ b3 13.9167" 19.6944" 35.3483 50.0239
+ b4 9.84722" 13.9167" 25.0119 35.3483
+ b5 6.95833" 9.84722" 17.6742 25.0119
+ flsa 8.5" 13" 21.59 33.02
+ flse 8.5" 13" 21.59 33.02
+ halfletter 5.5" 8.5" 13.97 21.59
+ ledger 17" 11" 43.18 27.94
+ legal 8.5" 14" 21.59 35.56
+ letter 8.5" 11" 21.59 27.94
+ note 7.5" 10" 19.05 25.4
+
+2 Initialization_files
+ When looking for the initialization files (gs_*.ps), the files related
+ to fonts, or the file for the `run' operator, Ghostscript first tries
+ opening the file with the name as given (i.e., using the current
+ working directory if none is specified). If this fails, and the file
+ name doesn't specify an explicit directory or drive, Ghostscript will
+ try directories in the following order:
+
+ 1. The directory/ies specified by the -I switch(es) in the command
+ line (see below), if any;
+ 2. The directory/ies specified by the GS_LIB logical, if any;
+ 3. The directory/ies specified by the GS_LIB_DEFAULT macro in the
+ Ghostscript makefile.
+
+ Each of these (GS_LIB_DEFAULT, GS_LIB, and -I parameter) may be either
+ a single directory, or a list of directories separated by a `:'.
+
+2 X_resources
+ Ghostscript looks for the following resources under the program name
+ `Ghostscript':
+
+ borderWidth
+ The border width in pixels (default = 1).
+
+ borderColor
+ The name of the border color (default = black).
+
+ geometry
+ The window size and placement, WxH+X+Y (default is NULL).
+
+ xResolution
+ The number of x pixels per inch (default is computed from
+ WidthOfScreen and WidthMMOfScreen).
+
+ yResolution
+ The number of y pixels per inch (default is computed from
+ HeightOfScreen and HeightMMOfScreen).
+
+ useBackingPixmap
+ Determines whether backing store is to be used for saving display
+ window (default = true).
+
+ See the file `use.txt' for a more complete list of resources.
+
+ To set these resources, put them in a file (such as
+ SYS$Login:ghostscript.dat) in the following form:
+
+ Ghostscript*geometry: 612x792-0+0
+ Ghostscript*xResolution: 72
+ Ghostscript*yResolution: 72
+
+2 Options
+ Note that VMS will convert all command line arguments to lower case
+ if they are not within quotes. Therefore, if a certain command does
+ not work, try again but with quotes around it.
+
+ -- filename arg1 ...
+ Takes the next argument as a file name as usual, but takes all
+ remaining arguments (even if they have the syntactic form of switches)
+ and defines the name ARGUMENTS in userdict (not systemdict) as an
+ array of those strings, before running the file. When Ghostscript
+ finishes executing the file, it exits.
+
+ -Dname=token
+ -dname=token
+ Define a name in systemdict with the given definition. The token must
+ be exactly one token (as defined by the `token' operator) and must not
+ contain any whitespace.
+
+ -Dname
+ -dname
+ Define a name in systemdict with value=null.
+
+ -Sname=string
+ -sname=string
+ Define a name in systemdict with a given string as value. This is
+ different from -d. For example, -dname=35 is equivalent to the
+ program fragment
+ /name 35 def
+ whereas -sname=35 is equivalent to
+ /name (35) def
+
+ -q
+ Quiet startup - suppress normal startup messages, and also do the
+ equivalent of -dQUIET.
+
+ -gnumber1Xnumber2
+ Equivalent to -dDEVICEWIDTH=number1 and -dDEVICEHEIGHT=number2. This is
+ for the benefit of devices (such as X11 windows) that require (or allow)
+ width and height to be specified.
+
+ -rnumber
+ -rnumber1Xnumber2
+ Equivalent to -dDEVICEXRESOLUTION=number1 and -dDEVICEYRESOLUTION=number2
+ This is for the benefit of devices (such as printers) that support
+ multiple X and Y resolutions. (If only one number is given, it is used
+ for both X and Y resolutions.)
+
+ -Idirectories
+ Adds the designated list of directories at the head of the search path
+ for library files.
+
+ Note that gs_init.ps makes systemdict read-only, so the values of names
+ defined with -D/d/S/s cannot be changed (although, of course, they can
+ be superseded by definitions in userdict or other dictionaries.)
+
+2 Special_names
+
+ -dDISKFONTS
+ Causes individual character outlines to be loaded from the disk the
+ first time they are encountered. (Normally Ghostscript loads all the
+ character outlines when it loads a font.) This may allow loading more
+ fonts into RAM, at the expense of slower rendering.
+
+ -dNOCACHE
+ Disables character caching. Only useful for debugging.
+
+ -dNOBIND
+ Disables the `bind' operator. Only useful for debugging.
+
+ -dNODISPLAY
+ Suppresses the normal initialization of the output device. This may be
+ useful when debugging.
+
+ -dNOPAUSE
+ Disables the prompt and pause at the end of each page. This may be
+ desirable for applications where another program is `driving'
+ Ghostscript.
+
+ -dNOPLATFONTS
+ Disables the use of fonts supplied by the underlying platform (e.g.
+ X Windows). This may be needed if the platform fonts look undesirably
+ different from the scalable fonts.
+
+ -dSAFER
+ Disables the deletefile and renamefile operators, and the ability to
+ open files in any mode other than read-only. This may be desirable
+ for spoolers or other sensitive environments.
+
+ -dWRITESYSTEMDICT
+ Leaves systemdict writable. This is necessary when running special
+ utility programs such as font2c and pcharstr, which must bypass normal
+ PostScript access protection.
+
+ -sDEVICE=device
+ Selects an alternate initial output device, as described above.
+
+ -sOutputFile=filename
+ Selects an alternate output file for the initial output device, as
+ described above.
+
+2 Files
+!!! Change
+ GS_Root:[Ghostscript.gs4_0]
+ Startup-files, utilities, and basic font definitions.
+
+ GS_Root:[Ghostscript.Fonts4_0]
+ Additional font definitions.
+
+ GS_Root:[Ghostscript.gs4_0.Examples]
+ Demo Ghostscript files.
+
+ GS_Root:[Ghostscript.gs4_0.Doc]
+ Assorted document files.
+!!! Change
+2 See_also
+ The various Ghostscript document files (above).
+
+2 Bugs
+ See the network news group comp.lang.postscript.
diff --git a/gs/doc/Public b/gs/doc/Public
new file mode 100644
index 000000000..1b2c6b930
--- /dev/null
+++ b/gs/doc/Public
@@ -0,0 +1,215 @@
+ ALADDIN FREE PUBLIC LICENSE
+ (Version 6, June 17, 1997)
+
+ Copyright (C) 1994, 1995, 1997 Aladdin Enterprises,
+ Menlo Park, California, U.S.A. All rights reserved.
+
+ NOTE: This License is not the same as any of the GNU Licenses
+ published by the Free Software Foundation. Its terms are
+ substantially different from those of the GNU Licenses.
+ If you are familiar with the GNU Licenses, please read this
+ license with extra care.
+
+Aladdin Enterprises hereby grants to anyone the permission to apply this
+License to their own work, as long as the entire License (including the
+above notices and this paragraph) is copied with no changes, additions, or
+deletions except for changing the first paragraph of Section 0 to include a
+suitable description of the work to which the license is being applied and
+of the person or entity that holds the copyright in the work, and, if the
+License is being applied to a work created in a country other than the
+United States, replacing the first paragraph of Section 6 with an
+appropriate reference to the laws of the appropriate country.
+
+0. Subject Matter
+
+This License applies to the computer program known as "Aladdin Ghostscript."
+The "Program", below, refers to such program. The Program is a copyrighted
+work whose copyright is held by Aladdin Enterprises (the "Licensor").
+Please note that Aladdin Ghostscript is neither the program known as "GNU
+Ghostscript" nor the version of Ghostscript available for commercial
+licensing from Artifex Software Inc.
+
+A "work based on the Program" means either the Program or any derivative
+work of the Program, as defined in the United States Copyright Act of 1976,
+such as a translation or a modification.
+
+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. NOTHING OTHER THAN THIS LICENSE GRANTS YOU
+PERMISSION TO MODIFY OR DISTRIBUTE THE PROGRAM OR ITS DERIVATIVE WORKS.
+THESE ACTIONS ARE PROHIBITED BY LAW. IF YOU DO NOT ACCEPT THESE TERMS AND
+CONDITIONS, DO NOT MODIFY OR DISTRIBUTE THE PROGRAM.
+
+1. Licenses.
+
+Licensor hereby grants you the following rights, provided that you comply
+with all of the restrictions set forth in this License and provided,
+further, that you distribute an unmodified copy of this License with the
+Program:
+
+(a) You may copy and distribute literal (i.e., verbatim) copies of the
+Program's source code as you receive it throughout the world, in any
+medium.
+
+(b) You may modify the Program, create works based on the Program and
+distribute copies of such throughout the world, in any medium.
+
+2. Restrictions.
+
+This license is subject to the following restrictions:
+
+(a) Distribution of the Program or any work based on the Program by a
+commercial organization to any third party is prohibited if any payment is
+made in connection with such distribution, whether directly (as in payment
+for a copy of the Program) or indirectly (as in payment for some service
+related to the Program, or payment for some product or service that includes
+a copy of the Program "without charge"; these are only examples, and not an
+exhaustive enumeration of prohibited activities). The following methods of
+distribution involving payment shall not in and of themselves be a violation
+of this restriction:
+
+ (i) Posting the Program on a public access information storage and
+retrieval service for which a fee is received for retrieving information
+(such as an on-line service), provided that the fee is not content-dependent
+(i.e., the fee would be the same for retrieving the same volume of
+information consisting of random data) and that access to the service and to
+the Program is available independent of any other product or service. An
+example of a service that does not fall under this section is an on-line
+service that is operated by a company and that is only available to
+customers of that company. (This is not an exhaustive enumeration.)
+
+ (ii) Distributing the Program on removable computer-readable media,
+provided that the files containing the Program are reproduced entirely and
+verbatim on such media, that all information on such media be
+redistributable for non-commercial purposes without charge, and that such
+media are distributed by themselves (except for accompanying documentation)
+independent of any other product or service. Examples of such media include
+CD-ROM, magnetic tape, and optical storage media. (This is not intended to
+be an exhaustive list.) An example of a distribution that does not fall
+under this section is a CD-ROM included in a book or magazine. (This is not
+an exhaustive enumeration.)
+
+(b) Activities other than copying, distribution and modification of the
+Program are not subject to this License and they are outside its scope.
+Functional use (running) of the Program is not restricted, and any output
+produced through the use of the Program is subject to this license only if
+its contents constitute a work based on the Program (independent of having
+been made by running the Program).
+
+(c) You must meet all of the following conditions with respect to any work
+that you distribute or publish that in whole or in part contains or is
+derived from the Program or any part thereof ("the Work"):
+
+ (i) If you have modified the Program, you must cause the Work to
+carry prominent notices stating that you have modified the Program's files
+and the date of any change;
+
+ (ii) You must cause the Work to be licensed as a whole and at no
+charge to all third parties under the terms of this License;
+
+ (iii) If the Work normally reads commands interactively when run,
+you must cause it, at each time the Work commences operation, 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). Such notice must also state that users may redistribute the Work
+only under the conditions of this License and tell the user how to view the
+copy of this License included with the Work. (Exceptions: if the Program is
+interactive but normally prints or displays such an announcement only at the
+request of a user, such as in an "About box", the Work is required to print
+or display the notice only under the same circumstances; if the Program
+itself is interactive but does not normally print such an announcement, the
+Work is not required to print an announcement.);
+
+ (iv) You must accompany the Work with the complete corresponding
+machine-readable source code, delivered on a medium customarily used for
+software interchange. 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 code. If you
+distribute with the Work any component 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, you must
+also distribute the source code of that component if you have it and are
+allowed to do so;
+
+ (v) If you distribute any written or printed material at all with
+the Work, such material must include either a written copy of this License,
+or a prominent written indication that the Work is covered by this License
+and written instructions for printing and/or displaying the copy of the
+License on the distribution medium;
+
+ (vi) You may not impose any further restrictions on the recipient's
+exercise of the rights granted herein.
+
+If distribution of executable or object code is made by offering the
+equivalent ability to copy from a designated place, then offering
+equivalent ability 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 code along with the object code.
+
+3. Reservation of Rights.
+
+No rights are granted to the Program except as expressly set forth herein.
+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.
+
+4. Other Restrictions.
+
+If the distribution and/or use of the Program is restricted in certain
+countries for any reason, Licensor 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.
+
+5. Limitations.
+
+THE PROGRAM IS PROVIDED TO YOU "AS IS," WITHOUT WARRANTY. THERE IS NO
+WARRANTY FOR THE PROGRAM, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE
+RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD
+THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+SERVICING, REPAIR OR CORRECTION.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+LICENSOR, 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.
+
+6. General.
+
+This License is governed by the laws of the State of California, U.S.A.,
+excluding choice of law rules.
+
+If any part of this License is found to be in conflict with the law, that
+part shall be interpreted in its broadest meaning consistent with the law,
+and no other parts of the License shall be affected.
+
+For United States Government users, the Program is provided with RESTRICTED
+RIGHTS. If you are a unit or agency of the United States Government or are
+acquiring the Software for any such unit or agency, the following apply:
+
+ If the unit or agency is the Department of Defense ("DOD"), the
+ Software and its documentation are classified as "commercial computer
+ software" and "commercial computer software documentation"
+ respectively and, pursuant to DFAR Section 227.7202, the Government is
+ acquiring the Software and its documentation in accordance with the
+ terms of this License. If the unit or agency is other than DOD, the
+ Software and its documentation are classified as "commercial computer
+ software" and "commercial computer software documentation"
+ respectively and, pursuant to FAR Section 12.212, the Government is
+ acquiring the Software and its documentation in accordance with the
+ terms of this License.
diff --git a/gs/doc/ps2epsi.txt b/gs/doc/ps2epsi.txt
new file mode 100644
index 000000000..772aa179d
--- /dev/null
+++ b/gs/doc/ps2epsi.txt
@@ -0,0 +1,62 @@
+ NOTE: this file was contributed by a user: please contact
+ George Cameron <george@bio-medical-physics.aberdeen.ac.uk>
+ if you have questions.
+
+OVERVIEW:
+
+ ps2epsi is a utility, based on Ghostscript, which takes an input postscript
+ file and generates a new output file which conforms to Adobe's 'Encapsulated
+ Postscript Interchange' or EPSI format. This is a special form of encapsulated
+ postscript (EPS) which adds a bitmap version of the final displayed page (in
+ the form of postscript comments) to the beginning of the file. This bitmap
+ can be used by programs which understand EPSI (usually word processors or
+ DTP programs) to give a preview version of the postscript on screen. The
+ displayed quality is often not very good (eg. low resolution, no colours),
+ but the final printed version uses the 'real' postscript, and thus has the
+ normal full postscript quality.
+
+FRAMEMAKER:
+
+ The Framemaker DTP system is one application which understands EPSI files,
+ and ps2epsi has been tested on a number of postscript diagrams from a
+ variety of sources, using Framemaker 3.0 on a Sun. I believe that Framemaker
+ on the other platforms should also be able to use these files, although I
+ have not been able to test this.
+
+FILES:
+
+ ps2epsi.txt - this file
+ ps2epsi.bat - MSDOS batch file
+ ps2epsi - Unix shell script
+ ps2epsi.ps - the Ghostscript program which does the work
+
+MSDOS USAGE:
+
+ Using the supplied batch file, the command is simply:
+
+ ps2epsi infile.ps outfile.epi
+
+ where infile.ps is the original postscript file, and outfile.epi is the
+ name of the output file.
+
+UNIX USAGE:
+
+ Using the supplied shell script, the command is:
+
+ ps2epsi infile.ps [outfile.epsi]
+
+ where infile.ps is the input file and outfile.epsi is the output EPSI
+ file. If the output filename is omitted, it will be generated from the
+ input filename - if a standard extension (.ps, .cps, .eps or .epsf) is
+ used, this will be replaced with the output extension .epsi .
+
+LIMITATIONS:
+
+ Successful encapsulation of arbitrary postscript files cannot be guaranteed,
+ as there are certain restrictions in what is permitted in a postscript file
+ for it to be properly encapsulated. ps2epsi does a little extra work to
+ try to help encapsulation, and it automatically calculates the bounding box
+ (required for all encapsulated postscript files), so, most of the time, it
+ does a pretty good job. There are bound to be cases, however, where the
+ encapsulation will not work, because of the content of the original postscript
+ file.
diff --git a/gs/drivers.txt b/gs/drivers.txt
new file mode 100644
index 000000000..4306058ef
--- /dev/null
+++ b/gs/drivers.txt
@@ -0,0 +1,1355 @@
+ Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, drivers.txt, describes the interface between Ghostscript and
+device drivers.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** Adding a driver ********
+********
+
+To add a driver to Ghostscript, all you need to do is edit devs.mak in
+two places. The first is the list of devices, in the section headed
+
+# -------------------------------- Catalog ------------------------------- #
+
+Pick a name for your device, say smurf, and add smurf to the list.
+(Device names must be 1 to 8 characters, consisting of only letters,
+digits, and underscores, of which the first character must be a letter.
+Case is significant: all current device names are lower case.)
+The second is the section headed
+
+# ---------------------------- Device drivers ---------------------------- #
+
+Suppose the files containing the smurf driver are called joe and fred.
+Then you should add the following lines:
+
+# ------ The SMURF device ------ #
+
+smurf_=joe.$(OBJ) fred.$(OBJ)
+smurf.dev: $(smurf_)
+ $(SETDEV) smurf $(smurf_)
+
+joe.$(OBJ): joe.c ...and whatever it depends on
+
+fred.$(OBJ): fred.c ...and whatever it depends on
+
+If the smurf driver also needs special libraries, e.g., a library named
+gorf, then the entry should look like this:
+
+smurf.dev: $(smurf_)
+ $(SETDEV) smurf $(smurf_)
+ $(ADDMOD) smurf -lib gorf
+
+If, as will usually be the case, your driver is a printer driver (as
+discussed below), the device entry should look like this:
+
+smurf.dev: $(smurf_) page.dev
+ $(SETPDEV) smurf $(smurf_)
+
+or
+
+smurf.dev: $(smurf_) page.dev
+ $(SETPDEV) smurf $(smurf_)
+ $(ADDMOD) smurf -lib gorf
+
+********
+******** Keeping things simple
+********
+
+If you want to add a simple device (specifically, a black-and-white
+printer), you probably don't need to read the rest of this document; just
+use the code in an existing driver as a guide. The Epson and BubbleJet
+drivers (gdevepsn.c and gdevbj10.c) are good models for dot-matrix
+printers, which require presenting the data for many scan lines at once;
+the DeskJet/LaserJet drivers (gdevdjet.c) are good models for laser
+printers, which take a single scan line at a time but support data
+compression. (For color printers, there are unfortunately no good models:
+the two major color inkjet printer drivers, gdevcdj.c and gdevstc.c, are
+far too complex to read.)
+
+On the other hand, if you're writing a driver for some more esoteric
+device, you probably do need at least some of the information in the rest
+of this document. It might be a good idea for you to read it in
+conjunction with one of the existing drivers.
+
+Duplication of code, and sheer code volume, is a serious maintenance and
+distribution problem for Ghostscript. If your device is similar to an
+existing one, try to implement your driver by adding some parameterization
+to an existing driver rather than copying code. gdevepsn.c and gdevdjet.c
+are good examples of this approach.
+
+********
+******** Driver structure ********
+********
+
+A device is represented by a structure divided into three parts:
+
+ - procedures that are shared by all instances of each device;
+
+ - parameters that are present in all devices but may be different
+ for each device or instance; and
+
+ - device-specific parameters that may be different for each instance.
+
+Normally, the procedure structure is defined and initialized at compile
+time. A prototype of the parameter structure (including both generic and
+device-specific parameters) is defined and initialized at compile time, but
+is copied and filled in when an instance of the device is created. Both of
+these structures should be declared as const, but for backward
+compatibility reasons are not.
+
+The gx_device_common macro defines the common structure elements, with the
+intent that devices define and export a structure along the following
+lines. Do not fill in the individual generic parameter values in the usual
+way for C structures: use the macros defined for this purpose in gxdevice.h
+or, if applicable, gdevprn.h.
+
+ typedef struct smurf_device_s {
+ gx_device_common;
+ ... device-specific parameters ...
+ } smurf_device;
+ smurf_device far_data gs_smurf_device = {
+ ... macro for generic parameter values ...,
+ { ... procedures ... }, /* std_procs */
+ ... device-specific parameter values if any ...
+ };
+
+The device structure instance *must* have the name gs_smurf_device, where
+smurf is the device name used in devs.mak.
+
+All the device procedures are called with the device as the first argument.
+Since each device type is actually a different structure type, the device
+procedures must be declared as taking a gx_device * as their first
+argument, and must cast it to smurf_device * internally. For example, in
+the code for the "memory" device, the first argument to all routines is
+called dev, but the routines actually use mdev to reference elements of the
+full structure, by virtue of the definition
+
+ #define mdev ((gx_device_memory *)dev)
+
+(This is a cheap version of "object-oriented" programming: in C++, for
+example, the cast would be unnecessary, and in fact the procedure table
+would be constructed by the compiler.)
+
+Structure definition
+--------------------
+
+You should consult the definition of struct gx_device_s in gxdevice.h for
+the complete details of the generic device structure. Some of the most
+important members of this structure for ordinary drivers are:
+
+ const char *dname; /* the device name */
+ bool is_open; /* true if device has been opened */
+ gx_device_color_info color_info; /* color information */
+ int width; /* width in pixels */
+ int height; /* height in pixels */
+
+The name in the structure (dname) should be the same as the name in
+devs.mak.
+
+gx_device_common is a macro consisting of just the element definitions.
+
+For sophisticated developers only
+---------------------------------
+
+If for any reason you need to change the definition of the basic device
+structure, or add procedures, you must change the following places:
+
+ - This document and NEWS (if you want to keep the
+ documentation up to date).
+ - The definition of gx_device_common and/or the procedures
+ in gxdevice.h.
+ - Possibly, the default forwarding procedures declared in gxdevice.h
+ and implemented in gdevnfwd.c.
+ - The device procedure record completion routines in gdevdflt.c.
+ - Possibly, the default device implementation in gdevdflt.c and
+ gdevddrw.c.
+ - If you are adding procedures that produce output, the bounding box
+ device in gdevbbox.c.
+ - The following devices that must have complete (non-defaulted)
+ procedure vectors:
+ - The null device in gdevnfwd.c.
+ - The command list "device" in gxclist.c. This is
+ not an actual device; it only defines procedures.
+ - The "memory" devices in gdevmem.h and gdevm*.c.
+ - The halftoning device in gdevht.c.
+ - The clip list accumulation "device" in gxacpath.c.
+ - The clipping "devices" in gxcpath.c and gxclip2.c.
+ - The Pattern accumulation "device" in gxpcmap.c.
+ - The hit detection "device" in zupath.c.
+ - The generic printer device macros in gdevprn.h.
+ - The generic printer device code in gdevprn.c.
+ - The RasterOp source device in gdevmrop.c.
+
+You may also have to change the code for gx_default_get_params and/or
+gx_default_put_params (in gsdparam.c).
+
+You should not have to change any of the real devices in the standard
+Ghostscript distribution (listed in devs.mak) or any of your own devices,
+because all of them are supposed to use the macros in gxdevice.h or
+gdevprn.h to define and initialize their state.
+
+********
+******** Types and coordinates ********
+********
+
+Coordinate system
+-----------------
+
+Since each driver specifies the initial transformation from user to device
+coordinates, the driver can use any coordinate system it wants, as long as a
+device coordinate will fit in an int. (This is only an issue on MS-DOS
+systems, where ints are only 16 bits. User coordinates are represented as
+floats.) Most current drivers use a coordinate system with (0,0) in the
+upper left corner, with X increasing to the right and Y increasing toward
+the bottom. However, there is supposed to be nothing in the rest of
+Ghostscript that assumes this, and indeed some drivers use a coordinate
+system with (0,0) in the lower left corner.
+
+Drivers must check (and, if necessary, clip) the coordinate parameters
+given to them: they should not assume the coordinates will be in bounds.
+The fit_fill and fit_copy macros in gxdevice.h are very helpful in doing
+this.
+
+Color definition
+----------------
+
+Ghostscript represents colors internally as RGB or CMYK values. In
+communicating with devices, however, it assumes that each device has a
+palette of colors identified by integers (to be precise, elements of type
+gx_color_index). Drivers may provide a uniformly spaced gray ramp or
+color cube for halftoning, or they may do their own color approximation,
+or both.
+
+The color_info member of the device structure defines the color and
+gray-scale capabilities of the device. Its type is defined as follows:
+
+typedef struct gx_device_color_info_s {
+ int num_components; /* 1 = gray only, 3 = RGB, */
+ /* 4 = CMYK */
+ int depth; /* # of bits per pixel */
+ gx_color_value max_gray; /* # of distinct gray levels -1 */
+ gx_color_value max_rgb; /* # of distinct color levels -1 */
+ /* (only relevant if num_comp. > 1) */
+ gx_color_value dither_gray; /* size of gray ramp for halftoning */
+ gx_color_value dither_rgb; /* size of color cube ditto */
+ /* (only relevant if num_comp. > 1) */
+} gx_device_color_info;
+
+The following macros (in gxdevice.h) provide convenient shorthands for
+initializing this structure for ordinary black-and-white or color devices:
+
+#define dci_black_and_white ...
+#define dci_color(depth,maxv,dither) ...
+
+The idea is that a device has a certain number of gray levels (max_gray +1)
+and a certain number of colors (max_rgb +1) that it can produce directly.
+When Ghostscript wants to render a given RGB or CMYK color as a device
+color, it first tests whether the color is a gray level. (If
+num_components is 1, it converts all colors to gray levels.) If so:
+
+ - If max_gray is large (>= 31), Ghostscript asks the device to
+approximate the gray level directly. If the device returns a valid
+gx_color_index, Ghostscript uses it. Otherwise, Ghostscript assumes that
+the device can represent dither_gray distinct gray levels, equally spaced
+along the diagonal of the color cube, and uses the two nearest ones to the
+desired color for halftoning.
+
+If the color is not a gray level:
+
+ - If max_rgb is large (>= 31), Ghostscript asks the device to
+approximate the color directly. If the device returns a valid
+gx_color_index, Ghostscript uses it. Otherwise, Ghostscript assumes that
+the device can represent dither_rgb * dither_rgb * dither_rgb distinct
+colors, equally spaced throughout the color cube, and uses two of the
+nearest ones to the desired color for halftoning.
+
+Types
+-----
+
+Here is a brief explanation of the various types that appear as parameters
+or results of the drivers.
+
+gx_color_value (defined in gxdevice.h)
+
+ This is the type used to represent RGB or CMYK color values. It is
+currently equivalent to unsigned short. However, Ghostscript may use less
+than the full range of the type to represent color values:
+gx_color_value_bits is the number of bits actually used, and
+gx_max_color_value is the maximum value (equal to 2^gx_max_color_value_bits
+- 1).
+
+gx_device (defined in gxdevice.h)
+
+ This is the device structure, as explained above.
+
+gs_matrix (defined in gsmatrix.h)
+
+ This is a 2-D homogeneous coordinate transformation matrix, used by
+many Ghostscript operators.
+
+gx_color_index (defined in gxdevice.h)
+
+ This is meant to be whatever the driver uses to represent a device
+color. For example, it might be an index in a color map, or it might be
+R, G, and B values packed into a single integer. Ghostscript doesn't ever
+do any computations with gx_color_index values: it gets them from
+map_rgb_color or map_cmyk_color and hands them back as arguments to
+several other procedures. The special value gx_no_color_index (defined as
+(gx_color_index)(-1)) means "transparent" for some of the procedures. The
+type definition is simply:
+
+ typedef unsigned long gx_color_index;
+
+gs_param_list (defined in gsparam.h)
+
+ This is a parameter list, which is used to read and set attributes
+in a device. See the comments in gsparam.h, and the description of the
+get_params and put_params procedures below, for more detail.
+
+gx_tile_bitmap (defined in gxbitmap.h)
+gx_strip_bitmap (defined in gxbitmap.h)
+
+ These structure types represent bitmaps to be used as a tile for
+filling a region (rectangle). gx_tile_bitmap is an older type lacking shift
+and rep_shift; gx_strip_bitmap has superseded it, and it should not be used
+in new code. Here is a copy of the relevant part of the file:
+
+/*
+ * Structure for describing stored bitmaps.
+ * Bitmaps are stored bit-big-endian (i.e., the 2^7 bit of the first
+ * byte corresponds to x=0), as a sequence of bytes (i.e., you can't
+ * do word-oriented operations on them if you're on a little-endian
+ * platform like the Intel 80x86 or VAX). Each scan line must start on
+ * a (32-bit) word boundary, and hence is padded to a word boundary,
+ * although this should rarely be of concern, since the raster and width
+ * are specified individually. The first scan line corresponds to y=0
+ * in whatever coordinate system is relevant.
+ *
+ * For bitmaps used as halftone tiles, we may replicate the tile in
+ * X and/or Y, but it is still valuable to know the true tile dimensions
+ * (i.e., the dimensions prior to replication). Requirements:
+ * width % rep_width = 0
+ * height % rep_height = 0
+ *
+ * For halftones at arbitrary angles, we provide for storing the halftone
+ * data as a strip that must be shifted in X for different values of Y.
+ * For an ordinary (non-shifted) halftone that has a repetition width of
+ * W and a repetition height of H, the pixel at coordinate (X,Y)
+ * corresponds to halftone pixel (X mod W, Y mod H), ignoring phase;
+ * for a shifted halftone with shift S, the pixel at (X,Y) corresponds
+ * to halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). Requirements:
+ * strip_shift < rep_width
+ * strip_height % rep_height = 0
+ * shift = (strip_shift * (size.y / strip_height)) % rep_width
+ */
+typedef struct gx_strip_bitmap_s {
+ byte *data;
+ int raster; /* bytes per scan line */
+ gs_int_point size; /* width, height */
+ gx_bitmap_id id;
+ ushort rep_width, rep_height; /* true size of tile */
+ ushort strip_height;
+ ushort strip_shift;
+ ushort shift;
+} gx_strip_bitmap;
+
+********
+******** Coding conventions ********
+********
+
+All the driver procedures defined below that return int results return 0 on
+success, or an appropriate negative error code in the case of error
+conditions. The error codes are defined in gserrors.h; they correspond
+directly to the errors defined in the PostScript language reference
+manuals. The most common ones for drivers are:
+
+ gs_error_invalidfileaccess
+ An attempt to open a file failed.
+
+ gs_error_ioerror
+ An error occurred in reading or writing a file.
+
+ gs_error_limitcheck
+ An otherwise valid parameter value was too large for
+ the implementation.
+
+ gs_error_rangecheck
+ A parameter was outside the valid range.
+
+ gs_error_VMerror
+ An attempt to allocate memory failed. (If this
+ happens, the procedure should release all memory it
+ allocated before it returns.)
+
+If a driver does return an error, it should use the return_error
+macro rather than a simple return statement, e.g.,
+
+ return_error(gs_error_VMerror);
+
+This macro is defined in gx.h, which is automatically included by
+gdevprn.h but not by gserrors.h.
+
+Allocating storage
+------------------
+
+While most drivers (especially printer drivers) follow a very similar
+template, there is one important coding convention that is not obvious from
+reading the code for existing drivers: Driver procedures must not use
+malloc to allocate any storage that stays around after the procedure
+returns. Instead, they must use gs_malloc and gs_free, which have slightly
+different calling conventions. (The prototypes for these are in
+gsmemory.h, which is included in gx.h, which is included in gdevprn.h.)
+This is necessary so that Ghostscript can clean up all allocated memory
+before exiting, which is essential in environments that provide only
+single-address-space multi-tasking (some versions of Microsoft Windows).
+
+char *gs_malloc(uint num_elements, uint element_size,
+ const char *client_name);
+
+ Like calloc, but unlike malloc, gs_malloc takes an element count
+and an element size. For structures, num_elements is 1 and element_size is
+sizeof the structure; for byte arrays, num_elements is the number of bytes
+and element_size is 1. Unlike calloc, gs_malloc does NOT clear the block
+of storage.
+
+ The client_name is used for tracing and debugging. It must be a
+real string, not NULL. Normally it is the name of the procedure in which
+the call occurs.
+
+void gs_free(char *data, uint num_elements, uint element_size,
+ const char *client_name);
+
+ Unlike free, gs_free demands that num_elements and element_size be
+supplied. It also requires a client name, like gs_malloc.
+
+Driver instance allocation
+--------------------------
+
+All driver instances allocated by Ghostscript's standard allocator must
+point to a "structure descriptor" that tells the garbage collector how to
+trace pointers in the structure. For drivers that are registered in the
+normal way (using the makefile approach described above), no special care
+is needed as long as instances are only created by calling the
+gs_copydevice procedure defined in gsdevice.h. If you have a need to
+define devices that are not registered in this way, you must fill in the
+stype member in any dynamically allocated instances with a pointer to the
+same structure descriptor used to allocate the instance. For more
+information about structure descriptors, see gsmemory.h and gsstruct.h.
+
+********
+******** Printer drivers ********
+********
+
+Printer drivers (which include drivers that write some kind of raster
+file) are especially simple to implement. Of the driver procedures
+defined in the next section, they only need implement two: map_rgb_color
+(or map_cmyk_color) and map_color_rgb. In addition, they must implement a
+print_page or print_page_copies procedure. There are a set of macros in
+gdevprn.h that generate the device structure for such devices, of which
+the simplest is prn_device; for an example, see gdevbj10.c. If you are
+writing a printer driver, we suggest you start by reading gdevprn.h and
+the subsection on "Color mapping" below; you may be able to ignore all the
+rest of the driver procedures.
+
+The print_page procedures are defined as follows:
+
+int (*print_page)(P2(gx_device_printer *, FILE *))
+int (*print_page_copies)(P3(gx_device_printer *, FILE *, int))
+
+ This procedure must read out the rendered image from the device and
+write whatever is appropriate to the file. To read back one or more scan
+lines of the image, the print_page procedure must call one of the following
+procedures:
+
+ int gdev_prn_copy_scan_lines(P4(gx_device_printer *pdev, int y, byte *str,
+ uint size)
+
+For this procedure, str is where the data should be copied to, and size is
+the size of the buffer starting at str. This procedure returns the number
+of scan lines copied, or <0 for an error. str need not be aligned.
+
+ int gdev_prn_get_bits(gx_device_printer *pdev, int y, byte *str,
+ byte **actual_data)
+
+This procedure reads out exactly one scan line. If the scan line is
+available in the correct format already, *actual_data is set to point to it;
+otherwise, the scan line is copied to the buffer starting at str, and
+*actual_data is set to str. This saves a copying step most of the time.
+str need not be aligned; however, if *actual_data is set to point to an
+existing scan line, it will be aligned. (See the description of the
+get_bits procedure below for more details.)
+
+In either case, each row of the image is stored in the form described
+in the comment under gx_tile_bitmap above; each pixel takes the
+number of bits specified as color_info.depth in the device structure,
+and holds values returned by the device's map_{rgb,cmyk}_color
+procedure.
+
+The print_page procedure can determine the number of bytes required to hold
+a scan line by calling:
+
+ uint gdev_prn_raster(P1(gx_device_printer *))
+
+For a very simple concrete example, we suggest reading the code in
+bit_print_page in gdevbit.c.
+
+If the device provides print_page, Ghostscript will call print_page the
+requisite number of times to print the desired number of copies; if the
+device provides print_page_copies, Ghostscript will call print_page_copies
+once per page, passing it the desired number of copies.
+
+********
+******** Driver procedures ********
+********
+
+Most of the procedures that a driver may implement are optional. If a
+device doesn't supply an optional procedure <proc>, the entry in the
+procedure structure may be either gx_default_<proc>, e.g.
+gx_default_tile_rectangle, or NULL or 0. (The device procedure must also
+call the gx_default_ procedure if it doesn't implement the function for
+particular values of the arguments.) Since C compilers supply 0 as the
+value for omitted structure elements, this convention means that
+statically initialized procedure structures will continue to work even if
+new (optional) members are added.
+
+Life cycle
+----------
+
+A device instance start out life in a closed state. In this state, no
+output operations will occur. Only the following procedures may be called:
+ open_device
+ get_initial_matrix
+ get_params
+ put_params
+ get_hardware_params
+
+When setdevice installs a device instance in the graphics state, it checks
+whether the instance is closed or open. If the instance is closed,
+setdevice calls the open routine, and then sets the state to open.
+
+There is currently no user-accessible operation to close a device instance.
+Device instances are only closed when they are about to be freed, which
+occurs in three situations:
+
+ - When a 'restore' occurs, if the instance was created since the
+corresponding 'save';
+
+ - By the garbage collector, if the instance is no longer accessible;
+
+ - When Ghostscript exits (terminates).
+
+Open/close/sync
+---------------
+
+int (*open_device)(P1(gx_device *)) [OPTIONAL]
+
+ Open the device: do any initialization associated with making the
+device instance valid. This must be done before any output to the device.
+The default implementation does nothing.
+
+void (*get_initial_matrix)(P2(gx_device *, gs_matrix *)) [OPTIONAL]
+
+ Construct the initial transformation matrix mapping user
+coordinates (nominally 1/72" per unit) to device coordinates. The default
+procedure computes this from width, height, and x/y_pixels_per_inch on the
+assumption that the origin is in the upper left corner, i.e.
+ xx = x_pixels_per_inch/72, xy = 0,
+ yx = 0, yy = -y_pixels_per_inch/72,
+ tx = 0, ty = height.
+
+int (*sync_output)(P1(gx_device *)) [OPTIONAL]
+
+ Synchronize the device. If any output to the device has been
+buffered, send / write it now. Note that this may be called several times
+in the process of constructing a page, so printer drivers should NOT
+implement this by printing the page. The default implementation does
+nothing.
+
+int (*output_page)(P3(gx_device *, int num_copies, int flush)) [OPTIONAL]
+
+ Output a fully composed page to the device. The num_copies
+argument is the number of copies that should be produced for a hardcopy
+device. (This may be ignored if the driver has some other way to specify
+the number of copies.) The flush argument is true for showpage, false for
+copypage. The default definition just calls sync_output. Printer drivers
+should implement this by printing and ejecting the page.
+
+int (*close_device)(P1(gx_device *)) [OPTIONAL]
+
+ Close the device: release any associated resources. After this,
+output to the device is no longer allowed. The default implementation
+does nothing.
+
+Color/alpha mapping
+-------------------
+
+A given driver normally will implement either map_rgb_color or
+map_cmyk_color, but not both. Black-and-white drivers do not need to
+implement either one. Note that the map_xxx_color procedures must not
+return gx_no_color_index (all 1's).
+
+gx_color_index (*map_rgb_color)(P4(gx_device *, gx_color_value red,
+ gx_color_value green, gx_color_value blue)) [OPTIONAL]
+
+ Map a RGB color to a device color. The range of legal values of
+the RGB arguments is 0 to gx_max_color_value. The default algorithm uses
+the map_cmyk_color procedure if the driver supplies one, otherwise returns
+1 if any of the values exceeds gx_max_color_value/2, 0 otherwise.
+
+ Ghostscript assumes that for devices that have color capability
+(i.e., color_info.num_components > 1), map_rgb_color returns a color index
+for a gray level (as opposed to a non-gray color) iff red = green = blue.
+
+gx_color_index (*map_cmyk_color)(P5(gx_device *, gx_color_value cyan,
+ gx_color_value magenta, gx_color_value yellow, gx_color_value black))
+ [OPTIONAL]
+
+ Map a CMYK color to a device color. The range of legal values of
+the CMYK arguments is 0 to gx_max_color_value. The default algorithm
+calls the map_rgb_color procedure, with suitably transformed arguments.
+
+ Ghostscript assumes that for devices that have color capability
+(i.e., color_info.num_components > 1), map_cmyk_color returns a color
+index for a gray level (as opposed to a non-gray color) iff cyan = magenta
+= yellow.
+
+int (*map_color_rgb)(P3(gx_device *, gx_color_index color,
+ gx_color_value rgb[3])) [OPTIONAL]
+
+ Map a device color code to RGB values. The default algorithm
+returns (0 if color==0 else gx_max_color_value) for all three components.
+
+gx_color_index (*map_rgb_alpha_color)(P5(gx_device *, gx_color_value red,
+ gx_color_value green, gx_color_value blue, gx_color_value alpha)) [OPTIONAL]
+
+ Map a RGB color and an opacity value to a device color. The range
+of legal values of the RGB and alpha arguments is 0 to gx_max_color_value;
+alpha = 0 means transparent, alpha = gx_max_color_value means fully
+opaque. The default is to use the map_rgb_color procedure and ignore
+alpha.
+
+ Note that if a driver implements map_rgb_alpha_color, it must also
+implement map_rgb_color, and must implement them in such a way that
+map_rgb_alpha_color(dev, r, g, b, gx_max_color_value) returns the same
+value as map_rgb_color(dev, r, g, b).
+
+ Note that there is no map_cmyk_alpha_color procedure. CMYK
+devices currently do not support variable opacity; alpha is ignored on
+such devices.
+
+typedef enum { go_text, go_graphics } graphic_object_type;
+int (*get_alpha_bits)(P4(gx_device *dev, graphic_object_type type)) [OPTIONAL]
+
+ Return the number of alpha (opacity) bits that should be used in
+rendering an object of the given type. The default value is 1; the only
+values allowed are 1, 2, and 4.
+
+Drawing
+-------
+
+All drawing operations use device coordinates and device color values.
+
+int (*fill_rectangle)(P6(gx_device *, int x, int y,
+ int width, int height, gx_color_index color))
+
+ Fill a rectangle with a color. The set of pixels filled is
+{(px,py) | x <= px < x + width and y <= py < y + height}. In other words,
+the point (x,y) is included in the rectangle, as are (x+w-1,y), (x,y+h-1),
+and (x+w-1,y+h-1), but *not* (x+w,y), (x,y+h), or (x+w,y+h). If width <=
+0 or height <= 0, fill_rectangle should return 0 without drawing anything.
+
+ Note that fill_rectangle is the only non-optional procedure in the
+driver interface.
+
+int (*draw_line)(P6(gx_device *, int x0, int y0, int x1, int y1,
+ gx_color_index color)) [OPTIONAL]
+
+ Draw a minimum-thickness line from (x0,y0) to (x1,y1). The
+precise set of points to be filled is defined as follows. First, if y1 <
+y0, swap (x0,y0) and (x1,y1). Then the line includes the point (x0,y0)
+but not the point (x1,y1). If x0=x1 and y0=y1, draw_line should return 0
+without drawing anything.
+
+Bitmap imaging
+--------------
+
+Bitmap (or pixmap) images are stored in memory in a nearly standard way.
+The first byte corresponds to (0,0) in the image coordinate system: bits
+(or polybit color values) are packed into it left-to-right. There may be
+padding at the end of each scan line: the distance from one scan line to
+the next is always passed as an explicit argument.
+
+int (*copy_mono)(P11(gx_device *, const unsigned char *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1)) [OPTIONAL]
+
+ Copy a monochrome image (similar to the PostScript image operator).
+Each scan line is raster bytes wide. Copying begins at (data_x,0) and
+transfers a rectangle of the given width and height to the device at device
+coordinate (x,y). (If the transfer should start at some non-zero y value in
+the data, the caller can adjust the data address by the appropriate multiple
+of the raster.) The copying operation writes device color color0 at each
+0-bit, and color1 at each 1-bit: if color0 or color1 is gx_no_color_index,
+the device pixel is unaffected if the image bit is 0 or 1 respectively. If
+id is different from gx_no_bitmap_id, it identifies the bitmap contents
+unambiguously; a call with the same id will always have the same data,
+raster, and data contents.
+
+ This operation, with color0 = gx_no_color_index, is the workhorse
+for text display in Ghostscript, so implementing it efficiently is very
+important.
+
+int (*tile_rectangle)(P10(gx_device *, const gx_tile_bitmap *tile,
+ int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1,
+ int phase_x, int phase_y)) [OPTIONAL] [OBSOLETE]
+
+ This procedure is still supported, but has been superseded by
+strip_tile_rectangle. New drivers should implement strip_tile_rectangle; if
+they cannot cope with non-zero shift values, they should test for this
+explicitly and call the default implementation
+(gx_default_strip_tile_rectangle) if shift != 0. Clients should call
+strip_tile_rectangle, not tile_rectangle.
+
+int (*strip_tile_rectangle)(P10(gx_device *, const gx_strip_bitmap *tile,
+ int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1,
+ int phase_x, int phase_y)) [OPTIONAL]
+
+ Tile a rectangle. Tiling consists of doing multiple copy_mono
+operations to fill the rectangle with copies of the tile. The tiles are
+aligned with the device coordinate system, to avoid "seams".
+Specifically, the (phase_x, phase_y) point of the tile is aligned with the
+origin of the device coordinate system. (Note that this is backwards from
+the PostScript definition of halftone phase.) phase_x and phase_y are
+guaranteed to be in the range [0..tile->width) and [0..tile->height)
+respectively.
+
+ If color0 and color1 are both gx_no_color_index, then the tile is
+a color pixmap, not a bitmap: see the next section.
+
+ This operation is the workhorse for halftone filling in Ghostscript,
+so implementing it efficiently for solid tiles (i.e., where either color0
+and color1 are both gx_no_color_index, for colored halftones, or neither one
+is gx_no_color_index, for monochrome halftones) is very important.
+
+Pixmap imaging
+--------------
+
+Pixmaps are just like bitmaps, except that each pixel occupies more than
+one bit. All the bits for each pixel are grouped together (this is
+sometimes called "chunky" or "Z" format). For copy_color, the number of
+bits per pixel is given by the color_info.depth parameter in the device
+structure: the legal values are 1, 2, 4, 8, 16, 24, or 32. The pixel
+values are device color codes (i.e., whatever it is that map_rgb_color
+returns).
+
+int (*copy_color)(P9(gx_device *, const unsigned char *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height))
+ [OPTIONAL]
+
+ Copy a color image with multiple bits per pixel. The raster is in
+bytes, but x and width are in pixels, not bits. If id is different from
+gx_no_bitmap_id, it identifies the bitmap contents unambiguously; a call
+with the same id will always have the same data, raster, and data contents.
+
+We do not provide a separate procedure for tiling with a pixmap; instead,
+tile_rectangle can also take colored tiles. This is indicated by the
+color0 and color1 arguments both being gx_no_color_index. In this case,
+as for copy_color, the raster and height in the "bitmap" are interpreted
+as for real bitmaps, but the x and width are in pixels, not bits.
+
+int (*copy_alpha)(P11(gx_device *dev, const unsigned char *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)) [OPTIONAL]
+
+ Fill a given region with a given color modified by an individual
+alpha value for each pixel. depth, the number of bits per pixel, is
+either 2 or 4, and in any case is always a value returned by a previous
+call on the get_alpha_bits procedure. Note that if get_alpha_bits always
+returns 1, this procedure will never be called.
+
+Bitmap/pixmap imaging
+---------------------
+
+int (*copy_rop)(P15(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, int command)) [OPTIONAL]
+
+ This procedure is still supported, but has been superseded by
+strip_copy_rop. New drivers should implement strip_copy_rop; if they cannot
+cope with non-zero shift values in the texture, they should test for this
+explicitly and call the default implementation (gx_default_strip_copy_rop)
+if shift != 0. Clients should call strip_copy_rop, not copy_rop.
+
+int (*strip_copy_rop)(P15(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, int command)) [OPTIONAL]
+
+ Combine an optional source image S (as for copy_mono or copy_color)
+and an optional texture T (a tile, as for tile_rectangle) with the existing
+bitmap or pixmap D held by the driver, pixel by pixel, using any 3-input
+Boolean operation as modified by "transparency" flags: schematically, set D
+= f(D,S,T), computing f in RGB space rather than using actual device pixel
+values. S and T may each (independently) be a solid color, a bitmap with
+"foreground" and "background" colors, or a pixmap. This is a complex (and
+currently rather slow) operation. The arguments are as follows:
+
+ dev - the device, as for all driver procedures
+
+ sdata, sourcex, sraster, id, scolors - specify S, see below
+
+ texture, tcolors - specify T, see below
+
+ x, y, width, height - as for the other copy/fill procedures
+
+ phase_x, phase_y - part of T specification, see below
+
+ command - see below
+
+S specification
+...............
+
+As noted above, the source (S) may be a solid color, a bitmap, or a pixmap.
+
+If S is a solid color:
+
+ - sdata, sourcex, sraster, and id are irrelevant.
+
+ - scolors points to two gx_color_index values; scolors[0] =
+ scolors[1] = the color.
+
+If S is a bitmap:
+
+ - sdata, sourcex, sraster, and id arguments are as for copy_mono or
+ copy_color (data, data_x, raster, id), and specify a source bitmap.
+
+ - scolors points to two gx_color_index values; scolors[0] is the
+ background color (the color corresponding to 0-bits in the bitmap),
+ scolors[1] is the foreground color (the color corresponding to
+ 1-bits in the bitmap).
+
+If S is a pixmap:
+
+ - sdata, sourcex, sraster, and id arguments are as for copy_mono or
+ copy_color (data, data_x, raster, id), and specify a source pixmap
+ whose depth is the same as the depth of the destination.
+
+ - scolors is NULL.
+
+Note that if the source is a bitmap with background=0 and foreground=1, and
+the destination is 1 bit deep, then the source can be treated as a pixmap
+(scolors=NULL).
+
+T specification
+...............
+
+Similar to the source, the texture (T) may be a solid color, a bitmap, or a
+pixmap.
+
+If T is a solid color:
+
+ - The texture pointer is irrelevant.
+
+ - tcolors points to two gx_color_index values; tcolors[0] =
+ tcolors[1] = the color.
+
+If T is a bitmap:
+
+ - The texture argument points to a gx_tile_bitmap, as for the
+ tile_rectangle procedure. Similarly, phase_x and phase_y specify
+ the offset of the texture relative to the device coordinate system
+ origin, again as for tile_rectangle. The tile is a bitmap (1 bit
+ per pixel).
+
+ - tcolors points to two gx_color_index values; tcolors[0] is the
+ background color (the color corresponding to 0-bits in the bitmap),
+ tcolors[1] is the foreground color (the color corresponding to
+ 1-bits in the bitmap).
+
+If T is a pixmap:
+
+ - The texture argument points to a gx_tile_bitmap whose depth is
+ the same as the depth of the destination.
+
+ - tcolors is NULL.
+
+Again, if the texture is a bitmap with background=0 and foreground=1, and
+the destination depth is 1, the texture bitmap can be treated as a pixmap
+(tcolors=NULL).
+
+Note that while a source bitmap or pixmap has the same width and height as
+the destination, a texture bitmap or pixmap has its own width and height
+specified in the gx_tile_bitmap structure, and is replicated and/or clipped
+as needed.
+
+f specification
+...............
+
+Command indicates the raster operation and transparency as follows:
+
+ bits 7-0: raster op
+ bit 8: 0 if source opaque, 1 if source transparent
+ bit 9: 0 if texture opaque, 1 if texture transparent
+ bits ?-10: unused, must be 0
+
+The raster operation follows the Microsoft and H-P specification. It is an
+8-element truth table that specifies the output value for each of the
+possible 2x2x2 input values as follows:
+
+ Bit Texture Source Destination
+ 7 1 1 1
+ 6 1 1 0
+ 5 1 0 1
+ 4 1 0 0
+ 3 0 1 1
+ 2 0 1 0
+ 1 0 0 1
+ 0 0 0 0
+
+Transparency affects the output in the following way. A source or texture
+pixel is considered transparent if its value is all 1's (e.g., 1 for
+bitmaps, 0xffffff for 24-bit RGB pixmaps) *and* the corresponding
+transparency bit is set in the command. For each pixel, the result of the
+Boolean operation is written into the destination iff neither the source nor
+the texture pixel is transparent. (Note that the H-P RasterOp
+specification, on which this is based, specifies that if the source and
+texture are both all 1's and the command specifies transparent source and
+opaque texture, the result *should* be written in the output. We think this
+is an error in the documentation.)
+
+Notes
+.....
+
+Note that copy_rop is defined to operate on pixels in RGB space, again
+following the H-P and Microsoft specification. For devices that don't use
+RGB (or gray-scale with black=0, white=all 1's) as their native color
+representation, the implementation of copy_rop must convert to RGB or gray
+space, do the operation, and convert back (or do the equivalent of this).
+
+Here are the copy_rop equivalents of the most important previous imaging
+calls. Note that rop3_S may be replaced by any other Boolean operation.
+For monobit devices, we assume that black = 1. We assume the following
+declaration:
+ static const gx_color_index white2[2] = { 1, 1 };
+
+/* For all devices: */
+(*fill_rectangle)(dev, x, y, w, h, color) ==>
+
+ { gx_color_index colors[2];
+ colors[0] = colors[1] = color;
+ (*dev_proc(dev, copy_rop))(dev, NULL, 0, 0, gx_no_bitmap_id, colors,
+ NULL, colors /*irrelevant*/,
+ x, y, w, h, 0, 0, rop3_S);
+ }
+
+/* For black-and-white devices only: */
+(*copy_mono)(dev, base, sourcex, sraster, id,
+ x, y, w, h, (gx_color_index)0, (gx_color_index)1) ==>
+
+ (*dev_proc(dev, copy_rop))(dev, base, sourcex, sraster, id, NULL,
+ NULL, white2 /*irrelevant*/,
+ x, y, w, h, 0, 0, rop3_S);
+
+/* For color devices, where neither color0 nor color1 is gx_no_color_index: */
+(*copy_mono)(dev, base, sourcex, sraster, id,
+ x, y, w, h, color0, color1) ==>
+
+ { gx_color_index colors[2];
+ colors[0] = color0, colors[1] = color1;
+ (*dev_proc(dev, copy_rop))(dev, base, sourcex, sraster, id, colors,
+ NULL, white2 /*irrelevant*/,
+ x, y, w, h, 0, 0, rop3_S);
+ }
+
+/* For black-and-white devices only: */
+(*copy_mono)(dev, base, sourcex, sraster, id,
+ x, y, w, h, gx_no_color_index, (gx_color_index)1) ==>
+
+ (*dev_proc(dev, copy_rop))(dev, base, sourcex, sraster, id, NULL,
+ NULL, white2 /*irrelevant*/,
+ x, y, w, h, 0, 0,
+ rop3_S | lop_S_transparent);
+
+/* For all devices: */
+(*copy_color)(dev, base, sourcex, sraster, id,
+ x, y, w, h) ==> [same as first copy_mono above]
+
+/* For black-and-white devices only: */
+(*tile_rectangle)(dev, tile, x, y, w, h,
+ (gx_color_index)0, (gx_color_index)1, px, py) ==>
+
+ (*dev_proc(dev, copy_rop))(dev, NULL, 0, 0, gx_no_bitmap_id,
+ white2 /*irrelevant*/,
+ tile, NULL,
+ x, y, w, h, px, py, rop3_T)
+
+Polygons
+--------
+
+In addition to the lowest-level drawing operations that take integer device
+coordinates and pure device colors, the driver interface includes
+higher-level operations that draw polygons using fixed-point coordinates,
+possibly halftoned colors, and possibly a non-default logical operation.
+
+The fill_* drawing operations all use the center-of-pixel rule: a pixel is
+colored iff its center falls within the polygonal region being filled. If a
+pixel center (X+0.5,Y+0.5) falls exactly on the boundary, the pixel is
+filled iff the boundary is horizontal and the filled region is above it, or
+the boundary is not horizontal and the filled region is to the right of it.
+
+int (*fill_trapezoid)(P10(gx_device *dev,
+ fixed fx0, fixed fw0, fixed fy0,
+ fixed fx1, fixed fw1, fixed fh, bool swap_axes,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)) [OPTIONAL]
+
+ Fill a trapezoid whose parallel sides are parallel to a coordinate
+axis. The corners are (fx0,fy0), (fx0+fw0,fy0), (fx1,fy0+fh), and
+(fx1+fw1,fy0+fy). We require fw0 >= 0, fw1 >= 0, and fh >= 0; if fw0 = 0 or
+fw1 = 0, the trapezoid is actually a triangle. If swap_axes is set, the
+meanings of X and Y are interchanged.
+
+int (*fill_parallelogram)(P9(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)) [OPTIONAL]
+
+ Fill a parallelogram whose corners are (px,py), (px+ax,py+ay),
+(px+bx,py+by), and (px+ax+bx,py+ay+by). There are no constraints on the
+values of any of the parameters, so the parallelogram may have any
+orientation relative to the coordinate axes.
+
+int (*fill_triangle)(P9(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)) [OPTIONAL]
+
+ Fill a triangle whose corners are (px,py), (px+ax,py+ay), and
+(px+bx,py+by).
+
+int (*draw_thin_line)(P7(gx_device *dev,
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)) [OPTIONAL]
+
+ Draw a one-pixel-wide line from (fx0,fy0) to (fx1,fy1). This
+replaces the older draw_line procedure, which required integer coordinates,
+a pure color, and no logical operation.
+
+High-level drawing
+------------------
+
+In addition to the low-level drawing operations described above, the driver
+interface provides a set of high-level operations. Normally these will have
+their default implementation, which converts the high-level operation to the
+low-level ones just described; however, drivers that generate high-level
+output formats such as CGM, or communicate with devices that have firmware
+for higher-level operations such as polygon fills, may implement these
+high-level operations directly.
+
+For more details, please consult the source code, specifically:
+ gxpaint.h - defines gx_fill_params, gx_stroke_params
+ gxfixed.h - defines fixed, gs_fixed_point (used by gx_*_params)
+ gxistate.h - defines gs_imager_state (used by gx_*_params)
+ gxline.h - defines gx_line_params (used by gs_imager_state)
+ gslparam.h - defines line cap/join values (used by gx_line_params)
+ gxmatrix.h - defines gs_matrix_fixed (used by gs_imager_state)
+ g[s,x,z]path.h - defines gx_path
+ g[x,z]cpath.h - defines gx_clip_path
+
+int (*fill_path)(P6(gx_device *dev,
+ const gx_imager_state *pis, gx_path *ppath, const gx_fill_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)) [OPTIONAL]
+
+ Fill the given path, clipped by the given clip path, according to
+the given parameters, with the given color. The clip path pointer may be
+NULL, meaning do not clip.
+
+int (*stroke_path)(P6(gx_device *dev,
+ const gx_imager_state *pis, gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)) [OPTIONAL]
+
+ Stroke the given path, clipped by the given clip path, according to
+the given parameters, with the given color. The clip path pointer may be
+NULL, meaning do not clip.
+
+int (*fill_mask)(P13(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ const gx_drawing_color *pdcolor, int depth,
+ int command, const gx_clip_path *pcpath)) [OPTIONAL]
+
+ Color the 1-bits in the given mask (or according to the alpha
+values, if depth > 1), clipped by the given clip path, with the given color
+and logical operation. The clip path pointer may be NULL, meaning do not
+clip. The parameters data, ..., height are as for copy_mono; depth is as
+for copy_alpha; command is as for copy_rop.
+
+High-level bitmap imaging
+-------------------------
+
+Similar to the high-level interface for fill/stroke graphics, a high-level
+interface exists for bitmap images. All of the procedures in this part of
+the interface are optional; however, if begin_image is defined, image_data
+and end_image also must be defined.
+
+A bitmap image is defined by a gs_image_t structure. We only summarize this
+structure here.
+
+typedef struct gs_image_s {
+ int Width; /* Width of source image in pixels */
+ int Height; /* Height ditto */
+ gs_matrix ImageMatrix; /* transformation from 1x1 image space to */
+ /* user space defined by imager CTM */
+ int BitsPerComponent;
+ const gs_color_space *ColorSpace;
+ float Decode[8]; /* linear remapping of input values */
+ bool Interpolate; /* smooth image if true */
+ bool ImageMask; /* true = mask, false = solid image */
+ bool adjust; /* expand bits if mask */
+ bool CombineWithColor; /* use drawing color as RasterOp texture */
+} gs_image_t;
+typedef enum {
+ gs_image_format_chunky = 0,
+ gs_image_format_component_planar = 1
+} gs_image_format_t;
+
+For more details, consult the source code in
+ gsiparam.h - defines parameters for an image
+
+int (*begin_image)(P9(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim, gs_image_format_t format,
+ gs_int_rect *prect, const gx_drawing_color *pdcolor,
+ const gx_clip_path *pcpath, gs_memory_t *memory, void **pinfo)) [OPTIONAL]
+
+ Begin the transmission of an image. Zero or more calls of
+image_data will follow, and then a call of end_image. The parameters of
+begin_image are as follows:
+
+ pis - pointer to an imager state. The only relevant elements of the
+imager state are the CTM (coordinate transformation matrix), the logical
+operation (RasterOp/transparency), and the color rendering information.
+
+ pim - pointer to the gs_image_t structure that defines the image
+parameters.
+
+ format - defines how pixels are represented for image_data. See the
+description of image_data below.
+
+ prect - if not NULL, defines a subrectangle of the image; only the
+data for this subrectangle will be passed to image_data, and only this
+subrectangle should be drawn.
+
+ pdcolor - defines a drawing color, only needed for masks or if
+CombineWithColor is true.
+
+ pcpath - if not NULL, defines an optional clipping path.
+
+ memory - defines the allocator to be used for allocating bookkeeping
+information.
+
+ pinfo - the implementation should return a pointer to its
+bookkeeping structure here.
+
+ begin_image is expected to allocate a structure for its bookkeeping
+needs, using the allocator defined by the memory parameter, and return it in
+*pinfo. begin_image should not assume that the structures in *pim, *prect,
+or *pdcolor will survive the call on begin_image (except for the color space
+in *pim->ColorSpace): it should copy any necessary parts of them into its
+own bookkeeping structure. It may, however, assume that *pis, *pcpath, and
+of course *memory will live at least until end_image is called.
+
+int (*image_data)(P6(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height))
+ [OPTIONAL]
+
+ This call provides more of the image source data: specifically,
+height rows, with Width pixels supplied for each row.
+
+ The data for each row are packed big-endian within each byte, as for
+copy_color. The raster (number of bytes per row) may include some padding
+at the end of each row. Note that for non-mask images, the input data may
+be in any color space and may have any number of bits per component (1, 2,
+4, 8, 12); currently mask images always have 1 bit per component, but in the
+future, they might allow multiple bits of alpha. Note also that each call
+of image_data passes complete pixels: e.g., for a chunky image with 24 bits
+per pixel, each call of image_data passes 3N bytes of data (specifically, 3
+* Width * height).
+
+ The interpretation of planes depends on the format argument of
+begin_image:
+
+ -- If format is gs_image_format_chunky, planes[0] points to data in
+"chunky" format, in which the components follow each other (e.g.,
+RGBRGBRGB....)
+
+ -- If format is gs_image_format_component_planar, planes[0 .. N-1]
+point to data for the N components (e.g., N=3 for RGB data); each plane
+contains samples for a single component, e.g., RR..., GG..., BB.... Note
+that the planes are divided by component, not by bit: for example, for
+24-bit RGB data, N=3, with 8-bit values in each plane of data. Someday we
+may add gs_image_format_bit_planar, specifying that each plane would contain
+only a single bit of the pixel value, but this is not currently implemented.
+
+ If, as a result of this call, image_data has been called with all
+the data for the (sub-)image, it returns 1; otherwise, it returns 0 or an
+error code as usual.
+
+ image_data, unlike most other driver procedures that take bitmaps as
+arguments, does not require the data to be aligned in any way.
+
+int end_image(P3(gx_device *dev,
+ void *info, bool draw_last)) [OPTIONAL]
+
+ Finish processing an image, either because all data have been
+supplied or because the caller has decided to abandon this image. end_image
+may be called at any time after begin_image. It should free the info
+structure and any subsidiary structures. If draw_last is true, it should
+finish drawing any buffered lines of the image.
+
+ While there will almost never be more than one image enumeration in
+progress -- i.e., after a begin_image, end_image will almost always be
+called before the next begin_image -- driver code should not rely on this
+property; in particular, it should store all information regarding the image
+in the info structure, not in the driver structure.
+
+ Note that if begin_image saves its parameters in the info structure,
+it can decide on each call whether to use its own algorithms or to use the
+default implementation. (It may need to call gx_default_begin/end_image
+partway through.) [A later revision of this document may include an example
+here.]
+
+Reading bits back
+-----------------
+
+int (*get_bits)(P4(gx_device *, int y, byte *str, byte **actual_data))
+ [OPTIONAL]
+
+ Read one scan line of bits back from the device into the area
+starting at str, namely, scan line y. If the bits cannot be read back
+(e.g., from a printer), return -1; otherwise return 0. The contents of the
+bits beyond the last valid bit in the scan line (as defined by the device
+width) are unpredictable. str need not be aligned in any particular way.
+
+ If actual_data is NULL, the bits are always returned at str. If
+actual_data is not NULL, get_bits may either copy the bits to str and set
+*actual_data = str, or it may leave the bits where they are and return a
+pointer to them in *actual_data. In the latter case, the bits are
+guaranteed to start on a 32-bit boundary and to be padded to a multiple of
+32 bits; also in this case, the bits are not guaranteed to still be there
+after the next call on get_bits.
+
+Parameters
+----------
+
+Devices may have an open-ended set of parameters, which are simply pairs
+consisting of a name and a value. The value may be of various types:
+integer (int or long), boolean, float, string, name, null, array of integer,
+or array of float. For example, the Name of a device is a string; the
+Margins of a device is an array of 2 floats. See gsparam.h for more
+details.
+
+If a device has parameters other than the ones applicable to all devices
+(or, in the case of printer devices, all printer devices), it must provide
+get_params and put_params procedures. If your device has parameters beyond
+those of a straightforward display or printer, we strongly advise using the
+_get_params and _put_params procedures in an existing device (for example,
+gdevcdj.c or gdevbit.c) as a model for your own code.
+
+int (*get_params)(P2(gx_device *dev, gs_param_list *plist)) [OPTIONAL]
+
+ Read the parameters of the device into the parameter list at plist,
+using the param_write_* macros/procedures defined in gsparam.h.
+
+int (*get_hardware_params)(P2(gx_device *, gs_param_list *plist))
+ [OPTIONAL]
+
+ Read the hardware-related parameters of the device into the parameter
+list at plist. If a parameter involves significant delay or hardware action,
+the driver should only determine the value of the parameter if it is
+"requested" by the gs_param_list [param_requested(plist, key_name)].
+This function may cause the asynchronous rendering pipeline (if enabled) to
+be drained, so it should be used sparingly.
+
+int (*put_params)(P2(gx_device *dev, gs_param_list *plist)) [OPTIONAL]
+
+ Set the parameters of the device from the parameter list at plist,
+using the param_read_* macros/procedures defined in gsparam.h. All
+put_params procedures must use a "two-phase commit" algorithm; see gsparam.h
+for details.
+
+External fonts
+--------------
+
+Drivers may include the ability to display text. More precisely, they may
+supply a set of procedures that in turn implement some font and text
+handling capabilities. These procedures are documented in another file,
+xfonts.txt. The link between the two is the driver procedure that
+supplies the font/text procedures:
+
+xfont_procs *(*get_xfont_procs)(P1(gx_device *dev)) [OPTIONAL]
+
+ Return a structure of procedures for handling external fonts and
+text display. A NULL value means that this driver doesn't provide this
+capability.
+
+For technical reasons, a second procedure is also needed:
+
+gx_device *(*get_xfont_device)(P1(gx_device *dev)) [OPTIONAL]
+
+ Return the device that implements get_xfont_procs in a non-default
+way for this device, if any. Except for certain special internal devices,
+this is always the device argument.
+
+Page devices
+------------
+
+gx_device *(*get_page_device)(P1(gx_device *dev)) [OPTIONAL]
+
+ According to the Adobe specifications, some devices are "page
+devices" and some are not. This procedure returns NULL if the device is
+not a page device, or the device itself if it is a page device. In the
+case of forwarding devices, get_page_device returns the underlying page
+device (or NULL if the underlying device is not a page device).
+
+Miscellaneous
+-------------
+
+int (*get_band)(P3(gx_device *dev, int y, int *band_start)) [OPTIONAL]
+
+ If the device is a band device, this procedure stores in *band_start
+the scan line (device Y coordinate) of the band that includes the given Y
+coordinate, and returns the number of scan lines in the band. If the device
+is not a band device, this procedure returns 0. The latter is the default
+implementation.
+
+void (*get_clipping_box)(P2(gx_device *dev, gs_fixed_rect *pbox))
+ [OPTIONAL]
+
+ Stores in *pbox a rectangle that defines the device's clipping
+region. For all but a few specialized devices, this is
+((0,0),(width,height)).
diff --git a/gs/examples/ridt91.eps b/gs/examples/ridt91.eps
new file mode 100644
index 000000000..adea4cd66
--- /dev/null
+++ b/gs/examples/ridt91.eps
@@ -0,0 +1,135 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 380 200
+%%Creator: karl@cs.umb.edu from code by Roger Hersch
+%%CreationDate: 8 March 1991
+%%Title: RIDT logo
+
+% Forget everything we do.
+save
+
+% Make definitions in our own dictionary.
+20 dict begin
+
+% However, this isn't quite a true EPS file, because we use the
+% setscreen operator, which has device- and document-dependent effects.
+% In particular, if the document is being printed in landscape mode, we
+% have to rotate the cell by 90 degrees. The dvips translator sets the
+% variable `isls' to be true in landscape mode, so we test for that.
+%
+/screen_angle
+ /isls where
+ { /isls get { 90 } { 0 } ifelse }
+ { 0 }
+ ifelse
+def
+
+
+% Increasing this number makes the screen finer (it isn't the actual
+% frequency).
+%
+/screen_frequency 10 def
+
+
+% If you change these numbers, change the bounding box comment above.
+% This default size is approximately 134mm by 71mm.
+/logo_width 380 def
+/logo_height 200 def
+
+% Besides changing the size from the outside, you can also change the
+% scale factor defined here. Of course then the bounding box won't be
+% accurate.
+/scalefactor 1 def
+
+% We need a string to hold the gray values.
+/fountainstring 256 string def
+
+% Put values varying from 0 to 255 into the string; these will be values
+% for the image operator.
+0 1 255
+ {
+ fountainstring exch dup
+ 255 div 180 mul cos neg 2 div
+ .5 add 255 mul cvi
+ put
+ }
+bind for
+
+
+% This procedure takes the bounding box of a rectangle, and images
+% /fountainstring into it.
+/fountain
+ {
+ /ury exch def
+ /urx exch def
+ /lly exch def
+ /llx exch def
+ gsave
+ llx lly translate
+
+ % Scale to the size of the rectangle.
+ urx llx sub ury lly sub scale
+
+ % The source image has one row of 256 8-bit values.
+ 1 256 8
+
+ % Map unit square to source.
+ [1 0 0 -256 0 256]
+
+ % Image the string.
+ { fountainstring } image
+ grestore
+ }
+bind def
+
+
+% Draw a line across the bottom for visual anchoring.
+%
+0 0 moveto
+logo_width 0 lineto stroke
+
+ screen_frequency scalefactor div
+ screen_angle
+ { exch pop abs 1 exch sub } bind
+setscreen
+
+scalefactor scalefactor scale
+
+/Palatino-Roman findfont 100 scalefont setfont
+
+% Determine the dimensions of our string.
+/logo_words (RIDT 91) def
+
+0 0 moveto
+logo_words true charpath flattenpath pathbbox
+/word_height exch def
+/word_width exch def
+pop pop % llx and lly are zero.
+newpath
+
+/x_offset logo_width word_width sub 2 div def
+/y_offset 15 def
+
+% Draw the background pattern, which is dark at the top and light at the
+% bottom.
+%
+0 0 logo_width logo_height fountain
+
+% Make the clipping path be `RIDT 91', twice.
+x_offset y_offset moveto
+logo_words true charpath
+x_offset logo_height y_offset word_height add sub moveto
+logo_words true charpath
+clip
+newpath
+
+% Paint the pattern again, this time with light at the top and dark at
+% the bottom.
+%
+logo_width logo_height translate
+180 rotate
+0 0 logo_width logo_height fountain
+
+end
+restore
+
+% showpage
diff --git a/gs/fonts.txt b/gs/fonts.txt
new file mode 100644
index 000000000..f7cdd9440
--- /dev/null
+++ b/gs/fonts.txt
@@ -0,0 +1,480 @@
+ Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, fonts.txt, describes the fonts and font facilities supplied
+with Ghostscript.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+About Ghostscript fonts
+=======================
+
+Most of the font files supplied with Ghostscript have a .pfb extension; a
+few have a .pfa or .gsf extension. Each file defines one (transformable)
+font specified in outline form. They are ordinary Type 1 PostScript outline
+fonts, and can be given to any PostScript language interpreter. Files with
+.pfa or .pfb extension are also compatible with Adobe Type Manager and with
+tools that don't include a full PostScript language interpreter; files with
+.gsf extension are not compatible with ATM or other tools. Starting with
+release 4.0, Ghostscript configurations compiled with the `ttfont' option
+can also use TrueType fonts (.ttf).
+
+The only other font-related file that Ghostscript needs for proper operation
+is a file called Fontmap. This file maps font names (such as /Times-Roman)
+to font file names (such as n021003l.pfb) or aliases (such as
+NimbusNo9L-Regu).
+
+The free fonts supplied with Ghostscript fall into three groups:
+
+ - 35 basic PostScript fonts (Times, Helvetica, Courier, Symbol,
+ etc.) These are commercial-quality Type 1 fonts. See the file
+ `Fontmap' for the complete list.
+
+ - Fonts derived from the public domain Hershey fonts, with
+ improvements (such as adding accented characters) by Thomas Wolff.
+ These are quite different from traditional printer or display fonts;
+ the file `hershey.txt' describes them in more detail.
+
+ - A few miscellaneous fonts including Cyrillic and kana fonts.
+
+The 35 basic fonts are normally distributed in a file called
+`ghostscript-fonts-std-N.NN.tar.gz', the rest in a file called
+`ghostscript-fonts-other-N.NN.fonts.tar.gz'.
+
+The file gs_fonts.ps, which is loaded as part of Ghostscript initialization,
+arranges to load fonts on demand using the information from Fontmap. If you
+want to preload all of the known fonts, invoke the procedure
+ loadallfonts
+This is not done by default, since the fonts occupy about 50K each and there
+are a lot of them.
+
+If you want to try out the fonts, prfont.ps contains code for printing a
+sampler. Load this program, by including it in the gs command line or by
+invoking
+ (prfont.ps) run
+and then to produce a sampler of a particular font, invoke
+ /fontName DoFont
+e.g.
+ /Times-Roman DoFont
+
+About the Kanji fonts
+---------------------
+
+Mr. Tetsurou Tanaka of the Department of Engineering, University of Tokyo,
+has created a set of free Kanji fonts that is freely available on the
+Internet for anonymous FTP from moe.ipl.t.u-tokyo.ac.jp:/Font and is
+distributed with Ghostscript. Anyone can use these fonts as they are or
+with some format translation, and redistribute them without reporting. If
+you redistribute them, you must inform the recipient that he can get the
+original from the abovementioned FTP site, so that he could get the newest
+version later.
+
+The fonts include a README file in Japanese. Here is some English
+documentation supplied by Mr. Kiyotaka Sakai, also of the University of
+Tokyo.
+
+ The following four fonts are different styles of the same characters
+ (JISX208). These fonts also needs wadalab-sym.tar.Z in common.
+
+ wadalab-mincho-0-8.tar.gz
+ wadalab-mincho-0-12.6.tar.gz
+ wadalab-gothic-0-13.5.tar.gz
+ wadalab-maru-0-8.4.tar.gz
+
+ And the following two fonts are the other different styles of the same
+ characters(JISX0212).
+
+ wadalab-mincho-1-8.tar.gz
+ wadalab-maru-1-8.tar.gz
+
+ These fonts are postscript(type1) fonts. You can convert them to
+ Metafont, Type1(PFA) font, TeX font(for japanese TeX), BDF font,
+ Shotaikurabu font by using wftomf.c, wftopfa.c, wftodm.c, bdfmerge.c
+ wftovf.c in tools directory.
+
+In order to conform to MS-DOS naming restrictions, we have renamed the
+original font files as follows:
+ Name Original name
+ ---- -------------
+ got013-5.taz wadalab-gothic-0-13.5.tar.gz
+ mar08-4.taz wadalab-maru-0-8.4.tar.gz
+ mar18.taz wadalab-maru-1-8.tar.gz
+ min012-6.taz wadalab-mincho-0-12.6.tar.gz
+ min08-4.taz wadalab-mincho-0-8.4.tar.gz
+ min18.taz wadalab-mincho-1-8.tar.gz
+ sym-4.taz wadalab-sym.4.tar.gz
+
+Platform fonts
+==============
+
+Starting with release 2.6.1, Ghostscript uses whatever font technology is
+provided by the system on which it runs, by using the system's API for
+displaying text. On MS Windows this may be TrueType, or it may be ATM;
+Ghostscript neither knows nor cares.
+
+The PostScript language specifies that fonts are data structures with
+particular contents (e.g., they include a bounding box for the font, an
+Encoding vector for specifying the character set, etc.), and it is fairly
+common for PostScript files to make use of this fact; also, characters can
+be used as clipping regions, and can be arbitrarily rotated, skewed,
+expanded/condensed, etc. algorithmically. Most of this information is
+available in one form or another from the underlying graphics system, but
+one crucial piece is not: the actual scalable outlines of the characters,
+which Ghostscript needs in order to implement clipping with character
+shapes and to implement arbitrarily transformed characters. Consequently,
+
+ Ghostscript needs the scalable outlines of any font mentioned
+ in a document, and will load them from the disk (.PFA, .PFB, or
+ .GSF file) in the usual way, even if it uses the platform's font
+ machinery for displaying the characters.
+
+To make matters worse, platforms use different names for their standard
+fonts. For example, the Times Roman font, for which PostScript files use
+the name "Times-Roman", may be known as "Times-Roman", "Times Roman", "Tms
+Rmn", "Times New Roman", or "TimesNewRoman". The name may even be
+completely different: the usual Helvetica-equivalent TrueType font is
+called "Arial". Now, it is possible to cope with this situation by
+introducing aliases in Fontmap, but there are two reasons why the
+current Ghostscript release does not do this:
+
+ 1) Naming in different systems is so unstandardized that there
+does not seem to be a small set of alternative names that is likely to
+cover most of the situations. All 5 of the above names for Times Roman
+have been seen in Windows and OS/2 environments, depending on system
+version, TrueType vs. ATM, and other unknown factors.
+
+ 2) Each alias takes up a substantial amount of space (several
+hundred bytes) at run time. If each of the standard 35 fonts has 3
+additional aliases, this might amount to 50K of wasted space. This is a
+lot on a PC, although running under Windows in enhanced mode, it might not
+be a problem.
+
+If you don't seem to be getting nice characters on the screen under MS
+Windows, you can try adding aliases to the Fontmap, according to the
+documentation found there.
+
+Adding your own fonts
+=====================
+
+Ghostscript can use any Type 0, Type 1, Type 3, Type 4, or Type 42 font that
+is acceptable to other PostScript language interpreters or to ATM, including
+MultiMaster fonts. Starting with release 4.0, Ghostscript can also use
+TrueType fonts (if Ghostscript was compiled with the `ttfont' option).
+Ghostscript also provides a way to construct a (low-quality) Type 1 font
+from a bitmap font in BDF format, which is a popular format in the Unix
+world.
+
+If you want to add fonts of your own, you must edit Fontmap to include an
+entry for your new font at the end. The format for entries is documented
+in the Fontmap file. Since later entries in Fontmap override earlier
+entries, any fonts you add will supersede the corresponding fonts supplied
+with Ghostscript.
+
+In the PC world, Type 1 fonts are customarily given names ending in .PFA or
+.PFB. Ghostscript can use these directly; you just need to make the entry
+in Fontmap. If you are going to use a commercial Type 1 font (such as fonts
+obtained in conjunction with Adobe Type Manager) with Ghostscript, please
+read carefully the license that accompanies the font; Aladdin Enterprises
+takes no responsibility for any possible violations of such licenses. The
+same applies to TrueType fonts, whose names customarily end in .TTF.
+
+Converting BDF fonts
+--------------------
+
+If you want to convert a BDF file to a scalable outline, use the program
+bdftops.ps (and invoking shell script bdftops.bat or bdftops). Run the
+shell command
+ bdftops <BDF_file_name> [<AFM_file1_name> ...] <your_gsf_file_name>
+ <font_name> <uniqueID> [<XUID>] [<encoding_name>]
+e.g.,
+ bdftops pzdr.bdf ZapfDingbats.afm pzdr.gsf
+ ZapfDingbats 4100000 1000000.1.41
+(Obviously, you would enter this all on one line; the example is split so
+it will fit on the page.) Then make an entry for the .gsf file in Fontmap
+as described above. See the end of this document for more detail.
+
+For developers only
+===================
+
+The rest of this document is very unlikely to be of value to ordinary
+users.
+
+Contents of fonts
+-----------------
+
+As noted above, Ghostscript accepts fonts in the same formats as PostScript
+interpreters. Type 0, 1, and 3 fonts are documented in the PostScript
+Language Reference Manual (Second Edition); detailed documentation for Type
+1 fonts appears in a separate Adobe book. Type 42 (encapsulated TrueType)
+fonts are documented in an Adobe supplement; the TrueType format is
+documented in publications available from Apple and Microsoft. Type 4 fonts
+are not documented anywhere; they are essentially Type 1 fonts with a
+BuildChar or BuildGlyph procedure.
+
+Precompiling fonts
+------------------
+
+You can compile any Type 1 font into C and link it into the Ghostscript
+executable. (Type 1 fonts include any font whose name ends with .pfa or
+.pfb, and it also includes all the Ghostscript .gsf fonts except for the
+Hershey fonts.) This doesn't have any effect on rendering speed, but it
+eliminates the time for loading the font dynamically, which may make a big
+difference in total rendering time, especially for multi-page documents.
+Fonts that have been precompiled and linked in this way do not need to
+appear in the Fontmap, although if they do appear there, no harm is done.
+
+The utility for precompiling fonts is called font2c. Note that font2c is
+a PostScript language program, so you must have Ghostscript already
+running to be able to run font2c; you must also have entries in the
+Fontmap for the fonts you want to compile. For example, to precompile
+the Times-Italic font,
+ font2c Times-Italic ptmri.c
+where the first argument is the font name and the second is the name of
+the .c file. You can use any file name you want, as long as it ends in
+.c. It doesn't have to be limited to 8 characters, unless your operating
+system requires this. We suggest that you use names xxxx.c, where
+xxxx.gsf or xxxx.pfa is the name of the font file in the Fontmap file,
+just so you don't have to keep track of another set of names. (If you are
+running on a VMS platform, or another platform where the C compiler has a
+limit on the length of identifiers, you must do something slightly more
+complicated; see the section 'Platforms with identifier length limits'
+below. Also, on VMS, you must put quotes "" around the font name so that
+the VMS command processor doesn't convert the name to lower case.)
+
+For VMS environments, see the directions in the file make.txt, and ignore
+the rest of this section.
+
+Note that ncrr.c, ptmr.c, etc. are not supplied with the Ghostscript
+fileset, since they are quite large and can easily be recreated using the
+font2c program as described above. There is a makefile called cfonts.mak
+that will run font2c on all the fonts supplied with Ghostscript. Invoke it
+with
+ make -f cfonts.mak
+On some systems, you may have to omit the space following the -f, i.e.,
+ make -fcfonts.mak
+
+Besides running font2c, you must arrange things so that the fonts will be
+compiled, and linked into the executable. To do this, add the compiled
+fonts "feature" to your platform-specific makefile. On MS-DOS systems, you
+edit tc.mak, bc.mak, bcwin.mak, msc.mak, or watc.mak; on Unix systems, you
+edit ansihead.mak, cc-head.mak, or gcc-head.mak, and then execute tar_cat.
+Find the definition of the FEATURE_DEVS macro in the makefile, e.g.,
+ FEATURE_DEVS=level2.dev pdf.dev
+and add ccfonts.dev, e.g.,
+ FEATURE_DEVS=level2.dev pdf.dev ccfonts.dev
+
+Next, you must add the specific fonts to the generic makefile. On MS-DOS
+systems, you edit gs.mak; on Unix systems, you edit makefile. The makefile
+already has rules for the standard 35 fonts supplied with Ghostscript.
+Find the line in the relevant makefile that says
+ #ccfonts1_=<something>
+Remove the # mark from this line, and from all the following lines down to
+and including the one that says
+ #ccfonts9=<something>
+This is all you need to do for the standard fonts. The next couple of
+paragraphs describe how to compile in other fonts, such as the Utopia or
+Kana fonts or your own fonts.
+
+Suppose you want to compile the Kana fonts into the executable. First,
+pick one of ccfonts10 through 15 as the place you will do this, say
+ccfonts10. Add your compiled font file names, e.g.,
+ ccfonts10_=fhirw.$(OBJ)
+If the line gets too long, use another line of the same form, e.g.,
+ ccfonts11_=fkarw.$(OBJ)
+Just below this, you will find a line that says
+ ccfonts10_=
+Add your own fonts to the end of this line, e.g.,
+ ccfonts10=Calligraphic_Hiragana
+Notice that you must replace `-' by `_' in the font name. Again, if
+the line gets too long, add another line of the same form, e.g.,
+ ccfonts10=Calligraphic_Hiragana
+ ccfonts11=Calligraphic_Katakana
+
+After all the lines of this form, add a pair of lines to compile each font,
+separating these entries from the ccfonts* lines and from each other by a
+blank line. In our example:
+
+ fhirw.$(OBJ): fhirw.c $(CCFONT)
+ $(CCCF) fhirw.c
+
+ fkarw.$(OBJ): fkarw.c $(CCFONT)
+ $(CCCF) fkarw.c
+
+Finally, run `make'. The executable will now include the fonts you added.
+They will be present in FontDirectory when Ghostscript starts up.
+
+Precompiling fonts on platforms with identifier length limits
+-------------------------------------------------------------
+
+On some platforms, the C compiler and/or linker have a limit on the number
+of significant characters in an identifier. On such platforms, you must
+do a little extra work.
+
+Let N be the maximum number of significant characters in an identifier
+(typically 31). For each font whose name is longer than N-5 characters,
+pick an arbitrary identifier that we will call the "short name". This can
+be any string you want, as long as it contains only letters, digits, and
+underscores; is no longer than N-5 characters; and is not the same as any
+other font name or short name. A good choice for this would be to use the
+name of the C file. (There is no harm in doing this for fonts with names
+shorter than N-5 characters, it's just not necessary.)
+
+You must do two different things for fonts that require a short name.
+First, you must supply the short name as a third argument to the font2c
+program. For example, to compile NewCenturySchlbk-BoldItalic using the
+short name "pncbi",
+ font2c NewCenturySchlbk-BoldItalic pncbi.c pncbi
+Then when you add the font to the gsaddmod line in the makefile, use the
+short name, not the actual font name, e.g.,
+ ccfonts2=pncbi
+instead of
+ ccfonts2=NewCenturySchlbk_BoldItalic
+Everything else is as described above.
+
+This procedure doesn't change the name of the font in the Fontmap, or as
+seen from within Ghostscript; it's just a workaround for a limitation of
+some older compilers.
+
+Font names and unique IDs
+-------------------------
+
+If you create your own fonts, and are only going to use them within your own
+organization, you should use UniqueID values between 4000000 and 4999999 as
+described just below; if you are going to distribute fonts, call Adobe and
+get them to assign you some UniqueIDs and also an XUID for your
+organization. The current (September 1993) UniqueID Coordinator is Terry
+O'Donnell; he is very helpful and will probably be able to assign you the
+numbers over the phone.
+
+The suggested temporary UniqueID for a font looks like:
+ 4TTWVE0
+where
+ TT is a two-digit number representing the typeface,
+ W represents the weight (normal, bold, ...),
+ V represents the variant (normal, italic, oblique, ...), and
+ E represents the expansion (normal, condensed, ...).
+This scheme will not work forever. As soon there are more 99 typefaces, or
+more than 9 weights or variants, we will have to do something else. But it
+suffices for the near future.
+
+XUIDs are a Level 2 PostScript feature that serves the same function as
+UniqueIDs, but is not limited to a single 24-bit integer. The bdftops
+program creates XUIDs of the form [-X- 0 -U-] where -X- is the organization
+XUID and -U- is the UniqueID. (Aladdin Enterprises' organization XUID is
+107; do not use this for your own fonts that you distribute.)
+
+Ghostscript fonts are stored on files, and the file names must comply
+with the 8-character limit imposed by MS-DOS and other operating systems.
+We therefore construct the filename for a font in a way somewhat similar to
+the construction for temporary UniqueIDs:
+ FTTWVVVE.gsf
+where F is the foundry, TT a two-letter abbreviation for the typeface, and
+W, V, and E the weight, variant, and expansion. Since a font can have
+multiple variants, we allocate three letters to that (for example, Lucida
+Regular Sans Typewriter Italic). If a font has four variants, you're on
+your own. If a font does have multiple variants, it's best to add the
+expansion letter `r', so that it is clear which letters are variants and
+which the expansion.
+
+This scheme is very close to the one proposed in `Filenames for fonts',
+published in the first 1990 issue of TUGboat (the journal of the TeX Users
+Group).
+
+In the following tables, we made no attempt to be exhaustive. Instead, we
+have simply allocated entries for those things that we needed for the fonts
+that we are actually distributing.
+
+foundries:
+----------
+b = Bitstream
+f = freely distributable/public domain fonts
+n = IBM
+p = Adobe (`p' for PostScript)
+u = URW[++]
+
+typefaces:
+id name filename prefix
+----------------------------------------------------------------
+08 = Avant Garde = pag (Adobe)
+11 = Bookman = pbk (Adobe)
+01 = CharterBT = bch (Bitstream)
+02 = Courier = ncr (IBM)
+03 = Helvetica = phv (Adobe)
+04 = New Century Schoolbook = pnc (Adobe)
+09 = Palatino = ppl (Adobe)
+05 = Symbol = psy (Adobe)
+06 = Times = ptm (Adobe)
+-- Utopia = put (Adobe)
+07 = Zapf Chancery = zc (public domain)
+10 = Zapf Dingbats = pzd (Adobe)
+12 = public domain Cyrillic = fcy (public domain)
+13 = Kevin Hartig Hiragana = fhi (shareware)
+14 = Kevin Hartig Katakana = fka (shareware)
+
+90 = Hershey Gothic English = hrge
+91 = Hershey Gothic Italian = hrit
+92 = Hershey Gothic German = hrgr
+93 = Hershey Greek = hrgk
+94 = Hershey Plain = hrpl
+95 = Hershey Script = hrsc
+96 = Hershey Symbol = hrsy
+
+weights:
+--------
+0 = normal = r
+1 = bold = b
+2 = book = k
+3 = demi = d
+4 = light = l
+
+variants:
+---------
+0 = normal = r (omitted when the weight is normal)
+1 = italic = i
+2 = oblique = o
+3 = script/handwritten/swash = w
+
+expansions:
+-----------
+0 = normal = r (omitted when the weight and variant
+ are normal)
+1 = narrow = n
+
+Converting BDF fonts to .gsf (Type 1) fonts
+-------------------------------------------
+
+The bdftops conversion program takes the following arguments:
+
+ bdftops xx.bdf [yy1.afm ...] zz.gsf fontname UniqueID [XUID]
+ [encodingname]
+
+These arguments have the following meanings:
+
+ xx.bdf - the input bitmap file, a BDF file
+ yy*.afm - the AFM files giving the metrics (optional)
+ zz.gsf - the output file
+ fontname - the font name
+ UniqueID - the UniqueID, as described above
+ XUID - the XUID, in the form n1.n2.n3... (optional)
+ encodingname - the encoding for the font (optional)
+
+Currently, the defined encodings are StandardEncoding, ISOLatin1Encoding,
+SymbolEncoding, and DingbatsEncoding. If the encoding is omitted,
+StandardEncoding is assumed.
diff --git a/gs/gdevpfax.c b/gs/gdevpfax.c
new file mode 100644
index 000000000..b3b084489
--- /dev/null
+++ b/gs/gdevpfax.c
@@ -0,0 +1,213 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpfax.c */
+/* Generic PostScript system compatible fax support */
+#include "gdevprn.h"
+#include "gsparam.h"
+#include "gxiodev.h"
+
+/* This code defines a %Fax% IODevice, and also provides decoding for */
+/* the FaxOptions dictionary in a page device. */
+/* It is still fragmentary and incomplete. */
+
+#define limited_string(len)\
+ struct { byte data[len]; uint size; }
+
+/* ------ %Fax% implementation ------ */
+
+/* Define the structure for the Fax IODevice state. */
+typedef struct gx_io_device_fax_s {
+ gx_io_device_common;
+ bool ActivityReport;
+ bool DefaultCaptionOn;
+ bool DefaultConfirmOn;
+ bool DefaultCoversOn;
+ int DefaultResolution;
+ int DefaultRetryCount;
+ int DefaultRetryInterval;
+ int DialToneWaitPeriod;
+ limited_string(20) ID;
+ long MaxFaxBuffer;
+ limited_string(32) PostScriptPassword;
+ bool ReceivePostScript;
+ int Rings;
+ int ServiceEnable;
+ int Speaker;
+ const char *StorageDevice;
+ bool WaitForDialTone;
+} gx_io_device_fax;
+
+private iodev_proc_get_params(fax_get_params);
+private iodev_proc_put_params(fax_put_params);
+const gx_io_device_fax gs_iodev_Fax =
+ { "%Fax%", "Parameters",
+ { iodev_no_init, iodev_no_open_device, iodev_no_open_file,
+ iodev_os_fopen, iodev_os_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ fax_get_params, fax_put_params
+ },
+ false, /* A */
+ true, true, true, 1, 0, 3, 1, /* D */
+ { { 0 }, 0 }, /* I */
+ 350000, /* M */
+ { { 0 }, 0 }, /* P */
+ true, 4 /* ? */, /* R */
+ 3, 1, "%ram%", /* S */
+ true /* W */
+ };
+
+/* The following code is shared between get and put parameters. */
+typedef struct fax_strings_s {
+ gs_param_string id, pwd, sd;
+} fax_strings;
+private int
+fax_xfer_params(register gx_io_device_fax *faxdev, gs_param_list *plist,
+ fax_strings *pfs)
+{ int code;
+ pfs->id.data = faxdev->ID.data, pfs->id.size = faxdev->ID.size,
+ pfs->id.persistent = false;
+ pfs->pwd.data = faxdev->PostScriptPassword.data,
+ pfs->pwd.size = faxdev->PostScriptPassword.size,
+ pfs->pwd.persistent = false;
+ pfs->sd.data = (const byte *)faxdev->StorageDevice,
+ pfs->sd.size = strlen(pfs->sd.data),
+ pfs->sd.persistent = true;
+ if ( (code = param_bool_param(plist, "ActivityReport", &faxdev->ActivityReport)) < 0 ||
+ (code = param_bool_param(plist, "DefaultCaptionOn", &faxdev->DefaultCaptionOn)) < 0 ||
+ (code = param_bool_param(plist, "DefaultConfirmOn", &faxdev->DefaultConfirmOn)) < 0 ||
+ (code = param_bool_param(plist, "DefaultCoversOn", &faxdev->DefaultCoversOn)) < 0 ||
+ (code = param_int_param(plist, "DefaultResolution", &faxdev->DefaultResolution)) < 0 ||
+ (code = param_int_param(plist, "DefaultRetryCount", &faxdev->DefaultRetryCount)) < 0 ||
+ (code = param_int_param(plist, "DefaultRetryInterval", &faxdev->DefaultRetryInterval)) < 0 ||
+ (code = param_int_param(plist, "DialToneWaitPeriod", &faxdev->DialToneWaitPeriod)) < 0 ||
+ (code = param_string_param(plist, "ID", &pfs->id)) < 0 ||
+ (code = param_long_param(plist, "MaxFaxBuffer", &faxdev->MaxFaxBuffer)) < 0 ||
+ (code = param_string_param(plist, "PostScriptPassword", &pfs->pwd)) < 0 ||
+ (code = param_bool_param(plist, "ReceivePostScript", &faxdev->ReceivePostScript)) < 0 ||
+ (code = param_int_param(plist, "Rings", &faxdev->Rings)) < 0 ||
+ (code = param_int_param(plist, "ServiceEnable", &faxdev->ServiceEnable)) < 0 ||
+ (code = param_int_param(plist, "Speaker", &faxdev->Speaker)) < 0 ||
+ (code = param_string_param(plist, "StorageDevice", &pfs->sd)) < 0 ||
+ (code = param_bool_param(plist, "WaitForDialTone", &faxdev->WaitForDialTone))
+ )
+ return code;
+ return 0;
+}
+
+#define faxdev ((gx_io_device_fax *)iodev)
+
+/* Get parameters from device. */
+private int
+fax_get_params(gx_io_device *iodev, gs_param_list *plist)
+{ fax_strings fs;
+ return fax_xfer_params(faxdev, plist, &fs);
+}
+
+/* Put parameters to device. */
+private int
+fax_put_params(gx_io_device *iodev, gs_param_list *plist)
+{ gx_io_device_fax tdev;
+ fax_strings fs;
+ int code;
+ gx_io_device *sdev;
+ tdev = *faxdev;
+ code = fax_xfer_params(&tdev, plist, &fs);
+ if ( code < 0 )
+ return code;
+#define between(v, lo, hi) (tdev.v >= (lo) && tdev.v <= (hi))
+ if ( !( between(DefaultResolution, 0, 1) &&
+ between(DefaultRetryCount, 0, 100) &&
+ between(DefaultRetryInterval, 1, 60) &&
+ between(DialToneWaitPeriod, 1, 10) &&
+ fs.id.size > 20 ||
+ tdev.MaxFaxBuffer >= 350000 &&
+ fs.pwd.size > 32 ||
+ between(Rings, 1, 30) &&
+ between(ServiceEnable, 0, 3) &&
+ between(Speaker, 0, 2) &&
+ (sdev = gs_findiodevice(fs.sd.data, fs.sd.size)) != 0
+ )
+ )
+ return_error(gs_error_rangecheck);
+#undef between
+ memcpy(tdev.ID.data, fs.id.data, fs.id.size);
+ tdev.ID.size = fs.id.size;
+ memcpy(tdev.PostScriptPassword.data, fs.pwd.data, fs.pwd.size);
+ tdev.PostScriptPassword.size = fs.pwd.size;
+ tdev.StorageDevice = sdev->dname;
+ *faxdev = tdev;
+ return 0;
+}
+
+/* ------ FaxOptions decoding ------ */
+
+typedef struct fax_options_s fax_options;
+typedef struct fax_custom_params_s fax_custom_params;
+typedef int (*fax_custom_proc)(P2(const fax_options *, const fax_custom_params *));
+struct fax_options_s {
+ gs_param_string CalleePhone;
+ limited_string(20) CallerID;
+ gs_param_string CallerPhone;
+ fax_custom_proc Confirmation;
+ struct { fax_options *options; uint size; } Copies;
+ /* CoverNote */
+ fax_custom_proc CoverSheet;
+ bool CoverSheetOnly;
+ limited_string(100) DialCallee;
+ bool ErrorCorrect;
+ int FaxType;
+ int MailingTime[6];
+ int MaxRetries;
+ int nPages;
+ fax_custom_proc PageCaption;
+ limited_string(32) PostScriptPassword;
+ void *ProcInfo;
+ gs_param_string RecipientID;
+ gs_param_string RecipientMailStop;
+ gs_param_string RecipientName;
+ gs_param_string RecipientOrg;
+ gs_param_string RecipientPhone;
+ gs_param_string Regarding;
+ int RetryInterval;
+ bool RevertToRaster;
+ gs_param_string SenderID;
+ gs_param_string SenderMailStop;
+ gs_param_string SenderName;
+ gs_param_string SenderOrg;
+ gs_param_string SenderPhone;
+ bool TrimWhite;
+};
+
+/* ------ Custom fax procedure parameters ------ */
+
+struct fax_custom_params_s {
+ limited_string(20) CalleeID;
+ int CallLength;
+ int CoverType;
+ int CurrentPageNo;
+ /* ErrorArray */
+ int ErrorIndex;
+ bool IncludesFinalPage;
+ int InitialPage, LimitPage;
+ int NumberOfCalls;
+ int PagesSent;
+ bool SendPostScript;
+ int TimeSent[6];
+};
diff --git a/gs/helpers.txt b/gs/helpers.txt
new file mode 100644
index 000000000..4faf8c885
--- /dev/null
+++ b/gs/helpers.txt
@@ -0,0 +1,170 @@
+ Copyright (C) 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, helpers.txt, is a note of thanks to all the people who
+have helped in the development of Ghostscript.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Major contributors
+------------------
+
+Special thanks are due to Russell Lang, for the GSview for Windows program,
+for contributing most of the code for the Microsoft Windows and OS/2
+environments, and for the original version of the PNG driver; to Tim
+Theisen, for the Ghostview program for X Windows and for major contributions
+to the development and support of code for the X Windows environment; and to
+the Independent JPEG Group, for creating the JPEG DCT library that
+Ghostscript uses.
+
+Other contributors
+------------------
+
+Aladdin Enterprises would like to acknowledge and thank the following
+other people (in alphabetical order) who have contributed
+substantially to improving Ghostscript since its inception in 1986:
+
+ Hitoshi Aida (for help with the SunView driver),
+ Pierre Arnaud (for bug reports and fixes),
+ William Bader (for several drivers and bug reports),
+ Alan Barclay (for the RGB TIFF drivers),
+ Karl Berry and Kathy Hargreaves (for helping create the fonts
+ originally distributed with Ghostscript),
+ James W. Birdsall (for the IBM ProPrinter driver),
+ Andrew Birrell (for a challenging application),
+ Jan Bottorff (for help with the Microsoft Windows driver),
+ Tom Brosnan (for the Desqview/X port),
+ Philip Brown (for the LaserJet IIID duplex additions),
+ George Cameron (for DeskJet 500C and 550C drivers),
+ Maurice Castro (a collaborator of Russell Lang's),
+ Phil Conrad (for originating the PPM utilities and the PCX and
+ GIF drivers, and lots of bug reports),
+ Michel Dagenais (for major help with the DeskJet driver),
+ John Desrosiers (for the final work on the Microsoft Visual C++
+ makefiles),
+ Jim Dunham (for the OpenVMS makefile),
+ Gershon Elber (for improvements to the BGI driver),
+ Fritz Elfert (for the Unix file enumeration routine),
+ Mike Ferrara (for help with the LaserJet driver and HP-UX),
+ Andy Fyfe (for the BJ200 driver modifications to the BJ10e driver,
+ and for the 3B1 driver),
+ Tim Gallivan (for a port to the Atari ST),
+ J Greely (for help with the PostScript-to-ASCII filter),
+ Paul Haeberli (for the ideas behind better color selection
+ and trapezoid fill algorithms),
+ Karl Hakimian (for the Tek 4693d drivers),
+ Richard Hesketh (for GSPreview),
+ Gunther Hess (for the unified inkjet printer driver),
+ Thomas Hiller (for the Trident TVGA driver),
+ Frans van Hoesel (for improvements to the DeskJet driver),
+ Berthold K. P. Horn (for a better spot halftone screen),
+ Earl Johnson (for the motivation for the ps2ascii utility),
+ Ray Johnston (for a first draft of FAKEFONTS and EPSF recognition,
+ and for many small bug fixes),
+ Pete Kaiser (for beta testing, several versions of the OSF/1
+ font map, and an HTML version of the documentation),
+ Norio Katayama (for the first implementation of composite fonts,
+ and for testing and helping debug the later implementation),
+ Alfred Kayser (for a DeskJet 500C driver and beta testing),
+ Richard Keeney (for help with the SunView driver),
+ Markku Koppinen (for a better circle-to-curve algorithm),
+ Eleftherios Koutsofios (for help with the SunView driver),
+ Tom Lane (for major help with adapting and integrating the IJG code),
+ Sam Leffler (for the original TIFF G3 driver, and for finding
+ some subtle bugs in the CCITTFaxEncode filter),
+ Jonathan Luckey (for the hi-res Imagewriter drivers),
+ Ian MacPhedran (for a sixel driver),
+ Jim Mayer (for help with the DeskJet and LaserJet drivers),
+ Paul McJones (for help in identifying a variety of bugs),
+ William L. Menninger (for a version of the PC display state
+ save/restore code),
+ Richard Mlynarik (for a nearly overwhelming volume of
+ improvements and suggestions),
+ Ulrich Mueller (for the LN03 driver),
+ Daniel Newman (for major help with VMS and the CCITT Fax filters),
+ Bjorn S. Nilsson (for major help with VMS, including many updates
+ of the DCL build scripts and creating the VMS help file),
+ Roque Donizete de Oliveira (for testing and debugging,
+ and a 'man' page),
+ Gerbert Orasche (for some minor bug fixes),
+ Marc Paquette (for the original PaintJet driver),
+ Hal Peterson (for major help with BDF fonts),
+ Andy Piper (for the first draft of the WindowID feature),
+ Martin Pirker (for fixing two major problems with TrueType fonts),
+ Tom Quinn (for the Canon LBP-8II driver),
+ Matthias Rabe (for work on an OS/2 port),
+ Jerry Roylance (for help with statusdict),
+ Dave St. Clair (for the color Epson/Fujitsu driver),
+ Jan Sanislo (for two subtle but vital fixes),
+ Clemens Schrimpe (for help with accented characters),
+ Scott Schwartz (for improvements to gslp.ps),
+ Mike Smolenski (for the Sony drivers),
+ Snoopy (for major help with Hershey fonts, and many other
+ contributions),
+ Karsten Spang (for the Tektronix 4695/4696 driver),
+ Andreas Stolcke (for help with the SunView driver),
+ Hans-Gerd Straeter (for finding some obscure bugs),
+ Christoph Strozyk (for getting the URW fonts made available),
+ Michael Sweet (for help with the high-density Epson driver),
+ Guenther Thomsen (for the mid-density Epson driver),
+ Gregg Townsend (for the low-resolution dithering algorithm),
+ Christian Tschudin (for fixes to the virtual memory package,
+ and for the original BubbleJet driver),
+ Stephen Turnbull (for help with the DesqView/X port),
+ Jos Vos (for the original PBM/PGM/PPM driver, and for much
+ beta testing),
+ Renze de Waal (for an improvement to the "SAFER" feature),
+ Allan Wax (for the AT&T 6300 modification to the BGI driver),
+ Mark Wedel (for the Apple DMP driver),
+ David Wexelblat (for the high-resolution 9-pin Epson driver),
+ George N. White III (for testing the PDF writer and contributing
+ documentation),
+ Elizabeth Zwicky (for some very challenging examples).
+
+The following people have also helped out by beta testing, by reporting
+bugs and/or fixes, or in other ways:
+
+ Juan Manual Acosta, Vikas Aggarwal, Michael Almond,
+ Abramo Bagnara, Malcolm Bennett, David Brooks,
+ Jim Collins,
+ Peter da Silva, Art Dederick, Paul DuBois,
+ Toerless Eckert,
+ Bernhard Fabricius, Mark Friedman, Richard Foulk,
+ Glenn Geers, Dave Goldblatt, Ben Goren, Dirk Grunwald,
+ Lars Haakedal, Howard B. Halstead, Adam Hammer, George Hartzell,
+ Mike Hoffmann, Charles Hulse,
+ Brad Jones, Terry Jones,
+ David Keppel,
+ Anthony Lee, Marty Leisner, John Lundin Jr., Lee McLoughlin,
+ Stergios Marinopoulos, Herb Martin, David Maynard,
+ Doug McDonald, Rich Murphey,
+ Russ Nelson,
+ Peter Phillips,
+ Mark Rawling, Philippe Robert, Tomas Rokicki, Wolfgang Rupprecht,
+ Bill Schelter, Larry Schwimmer, Bakul Shah,
+ Erik Talvola, Mark A. Thomas, Kjetil Bernhard Thomassen,
+ Amanda Walker, Peter Wan, John L. Wehle, Carsten Wiethoff,
+ Carl Witty,
+ Frank Yellin,
+ Jamie Zawinski.
+
+If your name appears on the above list and I've forgotten a particular
+contribution you made, or if it doesn't appear at all, please forgive me:
+just remind me, and you will be properly acknowledged in the next release.
diff --git a/gs/hershey.txt b/gs/hershey.txt
new file mode 100644
index 000000000..9a6230112
--- /dev/null
+++ b/gs/hershey.txt
@@ -0,0 +1,261 @@
+This file is part of Ghostscript. Unlike the rest of Ghostscript, it
+consists entirely of information copied directly from public sources. It
+therefore is not covered by the Ghostscript copyright or license.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Mod.sources: Volume 4, Issue 42
+Submitted by: pyramid!octopus!pete (Pete Holzmann)
+
+
+This is part 1 of five parts of the first Usenet distribution of
+the Hershey Fonts. See the README file for more details.
+
+
+Peter Holzmann, Octopus Enterprises
+USPS: 19611 La Mar Court, Cupertino, CA 95014
+UUCP: {hplabs!hpdsd,pyramid}!octopus!pete
+Phone: 408/996-7746
+
+
+This distribution is made possible through the collective encouragement
+of the Usenet Font Consortium, a mailing list that sprang to life to get
+this accomplished and that will now most likely disappear into the mists
+of time... Thanks are especially due to Jim Hurt, who provided the packed
+font data for the distribution, along with a lot of other help.
+
+This file describes the Hershey Fonts in general, along with a description of
+the other files in this distribution and a simple re-distribution restriction.
+
+USE RESTRICTION:
+ This distribution of the Hershey Fonts may be used by anyone for
+ any purpose, commercial or otherwise, providing that:
+ 1. The following acknowledgements must be distributed with
+ the font data:
+ - The Hershey Fonts were originally created by Dr.
+ A. V. Hershey while working at the U. S.
+ National Bureau of Standards.
+ - The format of the Font data in this distribution
+ was originally created by
+ James Hurt
+ Cognition, Inc.
+ 900 Technology Park Drive
+ Billerica, MA 01821
+ (mit-eddie!ci-dandelion!hurt)
+ 2. The font data in this distribution may be converted into
+ any other format *EXCEPT* the format distributed by
+ the U.S. NTIS (which organization holds the rights
+ to the distribution and use of the font data in that
+ particular format). Not that anybody would really
+ *want* to use their format... each point is described
+ in eight bytes as "xxx yyy:", where xxx and yyy are
+ the coordinate values as ASCII numbers.
+
+*PLEASE* be reassured: The legal implications of NTIS' attempt to control
+a particular form of the Hershey Fonts *are* troubling. HOWEVER: We have
+been endlessly and repeatedly assured by NTIS that they do not care what
+we do with our version of the font data, they do not want to know about it,
+they understand that we are distributing this information all over the world,
+etc etc etc... but because it isn't in their *exact* distribution format, they
+just don't care!!! So go ahead and use the data with a clear conscience! (If
+you feel bad about it, take a smaller deduction for something on your taxes
+next week...)
+
+The Hershey Fonts:
+ - are a set of more than 2000 glyph (symbol) descriptions in vector
+ ( <x,y> point-to-point ) format
+ - can be grouped as almost 20 'occidental' (english, greek,
+ cyrillic) fonts, 3 or more 'oriental' (Kanji, Hiragana,
+ and Katakana) fonts, and a few hundred miscellaneous
+ symbols (mathematical, musical, cartographic, etc etc)
+ - are suitable for typographic quality output on a vector device
+ (such as a plotter) when used at an appropriate scale.
+ - were digitized by Dr. A. V. Hershey while working for the U.S.
+ Government National Bureau of Standards (NBS).
+ - are in the public domain, with a few caveats:
+ - They are available from NTIS (National Technical Info.
+ Service) in a computer-readable from which is *not*
+ in the public domain. This format is described in
+ a hardcopy publication "Tables of Coordinates for
+ Hershey's Repertory of Occidental Type Fonts and
+ Graphic Symbols" available from NTIS for less than
+ $20 US (phone number +1 703 487 4763).
+ - NTIS does not care about and doesn't want to know about
+ what happens to Hershey Font data that is not
+ distributed in their exact format.
+ - This distribution is not in the NTIS format, and thus is
+ only subject to the simple restriction described
+ at the top of this file.
+
+Hard Copy samples of the Hershey Fonts are best obtained by purchasing the
+book described above from NTIS. It contains a sample of all of the Occidental
+symbols (but none of the Oriental symbols).
+
+This distribution:
+ - contains
+ * a complete copy of the Font data using the original
+ glyph-numbering sequence
+ * a set of translation tables that could be used to generate
+ ASCII-sequence fonts in various typestyles
+ * a couple of sample programs in C and Fortran that are
+ capable of parsing the font data and displaying it
+ on a graphic device (we recommend that if you
+ wish to write programs using the fonts, you should
+ hack up one of these until it works on your system)
+
+ - consists of the following files...
+ hershey.doc - details of the font data format, typestyles and
+ symbols included, etc.
+ hersh.oc[1-4] - The Occidental font data (these files can
+ be catenated into one large database)
+ hersh.or[1-4] - The Oriental font data (likewise here)
+ *.hmp - Occidental font map files. Each file is a translation
+ table from Hershey glyph numbers to ASCII
+ sequence for a particular typestyle.
+ hershey.f77 - A fortran program that reads and displays all
+ of the glyphs in a Hershey font file.
+ hershey.c - The same, in C, using GKS, for MS-DOS and the
+ PC-Color Graphics Adaptor.
+
+Additional Work To Be Done (volunteers welcome!):
+
+ - Integrate this complete set of data with the hershey font typesetting
+ program recently distributed to mod.sources
+ - Come up with an integrated data structure and supporting routines
+ that make use of the ASCII translation tables
+ - Digitize additional characters for the few places where non-ideal
+ symbol substitutions were made in the ASCII translation tables.
+ - Make a version of the demo program (hershey.c or hershey.f77) that
+ uses the standard Un*x plot routines.
+ - Write a banner-style program using Hershey Fonts for input and
+ non-graphic terminals or printers for output.
+ - Anything else you'd like!
+
+SHAR_EOF
+
+This file provides a brief description of the contents of the Occidental
+Hershey Font Files. For a complete listing of the fonts in hard copy, order
+NBS Special Publication 424, "A contribution to computer typesetting
+techniques: Tables of Coordinates for Hershey's Repertory of Occidental
+Type Fonts and Graphic Symbols". You can get it from NTIS (phone number is
++1 703 487 4763) for less than twenty dollars US.
+
+Basic Glyph (symbol) data:
+
+ hersh.oc1 - numbers 1 to 1199
+ hersh.oc2 - numbers 1200 to 2499
+ hersh.oc3 - numbers 2500 to 3199
+ hersh.oc4 - numbers 3200 to 3999
+
+ These four files contain approximately 19 different fonts in
+the A-Z alphabet plus greek and cyrillic, along with hundreds of special
+symbols, described generically below.
+
+ There are also four files of Oriental fonts (hersh.or[1-4]). These
+files contain symbols from three Japanese alphabets (Kanji, Hiragana, and
+Katakana). It is unknown what other symbols may be contained therein, nor
+is it known what order the symbols are in (I don't know Japanese!).
+
+ Back to the Occidental files:
+
+Fonts:
+ Roman: Plain, Simplex, Duplex, Complex Small, Complex, Triplex
+ Italic: Complex Small, Complex, Triplex
+ Script: Simplex, Complex
+ Gothic: German, English, Italian
+ Greek: Plain, Simplex, Complex Small, Complex
+ Cyrillic: Complex
+
+Symbols:
+ Mathematical (227-229,232,727-779,732,737-740,1227-1270,2227-2270,
+ 1294-1412,2294-2295,2401-2412)
+ Daggers (for footnotes, etc) (1276-1279, 2276-2279)
+ Astronomical (1281-1293,2281-2293)
+ Astrological (2301-2312)
+ Musical (2317-2382)
+ Typesetting (ffl,fl,fi sorts of things) (miscellaneous places)
+ Miscellaneous (mostly in 741-909, but also elsewhere):
+ - Playing card suits
+ - Meteorology
+ - Graphics (lines, curves)
+ - Electrical
+ - Geometric (shapes)
+ - Cartographic
+ - Naval
+ - Agricultural
+ - Highways
+ - Etc...
+
+
+ASCII sequence translation files:
+
+ The Hershey glyphs, while in a particular order, are not in an
+ ASCII sequence. I have provided translation files that give the
+ sequence of glyph numbers that will most closely approximate the
+ ASCII printing sequence (from space through ~, with the degree
+ circle tacked on at the end) for each of the above fonts:
+
+ File names are made up of fffffftt.hmp,
+
+ where ffffff is the font style, one of:
+ roman Roman
+ greek Greek
+ italic Italic
+ script Script
+ cyril Cyrillic (some characters not placed in
+ the ASCII sequence)
+ gothgr Gothic German
+ gothgb Gothic English
+ gothit Gothic Italian
+
+ and tt is the font type, one of:
+ p Plain (very small, no lower case)
+ s Simplex (plain, normal size, no serifs)
+ d Duplex (normal size, no serifs, doubled lines)
+ c Complex (normal size, serifs, doubled lines)
+ t Triplex (normal size, serifs, tripled lines)
+ cs Complex Small (Complex, smaller than normal size)
+
+The three sizes are coded with particular base line (bottom of a capital
+ letter) and cap line (top of a capital letter) values for 'y':
+
+ Size Base Line Cap Line
+
+ Very Small -5 +4
+ Small -6 +7
+ Normal -9 +12
+
+ (Note: some glyphs in the 'Very Small' fonts are actually 'Small')
+
+The top line and bottom line, which are normally used to define vertical
+ spacing, are not given. Maybe somebody can determine appropriate
+ values for these!
+
+The left line and right line, which are used to define horizontal spacing,
+ are provided with each character in the database.
+
+SHAR_EOF
+
+Format of Hershey glyphs:
+
+5 bytes - glyphnumber
+3 bytes - length of data length in 16-bit words including left&right numbers
+1 byte - x value of left margin
+1 byte - x value of right margin
+(length*2)-2 bytes - stroke data
+
+left&right margins and stroke data are biased by the value of the letter 'R'
+Subtract the letter 'R' to get the data.
+
+e.g. if the data byte is 'R', the data is 0
+ if the data byte is 'T', the data is +2
+ if the data byte is 'J', the data is -8
+
+and so on...
+
+The coordinate system is x-y, with the origin (0,0) in the center of the
+glyph. X increases to the right and y increases *down*.
+
+The stroke data is pairs of bytes, one byte for x followed by one byte for y.
+
+A ' R' in the stroke data indicates a 'lift pen and move' instruction.
diff --git a/gs/history1.txt b/gs/history1.txt
new file mode 100644
index 000000000..b3237397f
--- /dev/null
+++ b/gs/history1.txt
@@ -0,0 +1,341 @@
+ Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, history1.txt, describes the changes in older releases of
+Ghostscript numbered 1.n. For more recent changes, see the historyN.txt (N
+> 1) and NEWS files.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Version 1.3 (6/20/89)
+===========
+
+This release should have had a lot more things in it, but time pressure
+and the already long delay in getting it out made it necessary to push it
+out the door in an incomplete state (e.g., no testing on X systems
+whatsoever).
+
+Interpreter
+-----------
+
+Makes -d and -D equivalent on the command line. Adds a new switch -s / -S
+that defines a name as a string rather than a token.
+
+Arranges things so that if -sLIB=_a_prefix_ is defined on the command
+line, (filename) run will look for _a_prefix_filename before giving up if
+filename isn't the name of an accessible file.
+
+Changes showpage from an operator to a procedure. The definition of
+showpage in ghost.ps does a copypage, beeps the console, waits for the
+user to type a character (normally a <return>, since line buffering is
+always enabled), and then does an erasepage and an initgraphics.
+
+Adds a new initialization file, gdevs.ps, containing device-dependent
+parameters. The default window size for X Windows is properly set to 612
+x 792, i.e., 8.5" x 11".
+
+Adds a new optional initialization file, statusd.ps, that provides dummy
+definitions for the names found in statusdict on LaserWriters.
+
+Adds a new operator, getenv, to get information from the shell
+environment.
+
+Adds a new predefined operator, defaultdevicename, that returns either (X)
+or (EGA) according to how the interpreter was built.
+
+Adds a new type, devicetype, and new operators deviceparams, getscanlines,
+makedevice, makeimagedevice, and setdevice. Changes currentdevice to
+return a device object rather than a set of parameters.
+
+Makes the scanner recognize reals with 'e' exponent notation, and handle
+reals with more than 9 digits.
+
+Fixes a bug that made names starting with digits read incorrectly.
+
+Fixes a bug in the exp operator that made it not pop its first argument
+from the stack.
+
+Fixes a bug in the rand operator that made it return negative values about
+half the time.
+
+Fixes a bug in equality comparison (eq, ne, and several other operators)
+that made unequal operator objects occasionally appear to be equal on DOS
+systems.
+
+Fixes a bug in the bind operator that made it not work on packed arrays.
+
+Changes the internal representation of dictionaries so they can be
+expanded or contracted dynamically. Adds a new operator, setmaxlength, to
+change the allocated size of a dictionary.
+
+Changes sstorei.h so that non-DOS compilers don't encounter the #pragma
+directive used by Turbo C.
+
+Restores the display mode (on MS-DOS systems) when exiting.
+
+Fonts
+-----
+
+Makes undefined characters in the standard font display as tilde rather
+than blank (or causing an error). Unmapped character codes (those mapped
+to .notdef in the encoding) still display as nothing, per the PostScript
+manual.
+
+Library
+-------
+
+Adds a new header file, gxbitmap.h, with some new documentation describing
+the internal storage format for bitmaps.
+
+Makes numerous internal changes in the character / font cache, affecting
+many of the routines in gxcache.c.
+
+Fixes a bug in gz_draw_line / gz_fill_trapezoid that made nearly
+horizontal lines display wrong.
+
+Fixes a bug in gs_scale that made scaling not work if the coordinate
+system was rotated or skewed.
+
+Extends the font cache so it will handle characters rotated by multiples
+of 90 degrees.
+
+Changes the second argument of gx_path_bbox and gx_path_is_rectangle to be
+a gs_fixed_rect * rather than a fixed [4].
+
+Changes gs_matrix_rotate so it handles multiples of 90 degrees as a
+special case.
+
+Changes the definition of the gx_device structure to accommodate the new
+device operators, and adds corresponding library calls.
+
+Changes the type for a device color index from int to gx_color_index
+(equivalent to unsigned long). ***NOTE***: this affects existing clients
+and drivers in a non-trivial way on MS-DOS systems.
+
+Changes gs_malloc and gs_free to take a client name string as an argument.
+
+Usage procedures
+----------------
+
+Changes the compilation rules for Unix systems to not use the -o and -c
+compiler flags together, to be compatible with more versions of cc.
+
+Changes the gcc makefile to use $(GCC) rather than gcc as the compiler
+name.
+
+Moves the -1 flag for the MS-DOS compiler from the cc*.bat files to the
+makefile.
+
+Changes CCDEBUG to CCFLAGS, and adds ASMFLAGS, in DOS makefile.
+
+Adds -DFOR80386 and /DFOR80386 to enable use of 80386 instructions in
+assembly code on DOS systems.
+
+Merges the DEBUG and gs_DEBUG switches. There is now only a single DEBUG
+switch that affects both the interpreter and the library.
+
+Adds a new compilation switch, -DNOPRIVATE, that makes private (static)
+variables and procedures public for debugging and profiling (only needed
+on DOS systems).
+
+Adds the DOS executable (gs.exe and gs.map) to the distribution fileset.
+
+Adds new platform-specific code files, gp-*.c, for a few things like
+reading the clock.
+
+Adds a new documentation file, drivers.doc, that describes the interface
+between Ghostscript and device drivers.
+
+Version 1.2 (2/22/89)
+===========
+
+Interpreter
+-----------
+
+Adds the new facilities in version 25 of PostScript: //name for immediate
+lookup, packed arrays (setpacking, currentpacking, packedarray operators),
+and new font cache parameters (setcacheparams, currentcacheparams
+operators).
+
+Adds new operators (setfileposition, currentfileposition) for random
+access to files.
+
+Extends readhexstring to take either a string or a file, just like token.
+
+Fixes a bug that caused the 'for' operator (and a couple of others) to
+randomly smash memory locations on PC platforms.
+
+Library
+-------
+
+Renames the init_device driver procedure as open_device, and adds a
+corresponding close_device.
+
+Adds new procedures to read and set the cache limit values (implementing
+the currentcacheparams and setcacheparams operators).
+
+Usage procedures
+----------------
+
+Changes the name of the Unix makefile to ux-cc-x.mak, and adds a new Unix
+makefile, ux-gcc-x.mak, for using gcc instead of cc. (The latter doesn't
+actually work yet.)
+
+Changes the name of the single built-in font from uglyfont.cp to
+ugly10.cp.
+
+Version 1.1 (2/12/89)
+===========
+
+Interpreter
+-----------
+
+Makes the scanner treat ^Z (ASCII code 26) as whitespace: it erroneously
+treated ^R (ASCII code 22, or octal 26) as whitespace.
+
+Makes the token and readline operators, and the syntax for comments,
+recognize \r (code 13), \n (code 10), and \r\n as equivalent end-of-line
+indicators. The token and readline operators will skip over any of these
+sequences at the end of a token or line respectively, and a comment will
+read through any of these sequences. The other file operators (read,
+write, readstring, writestring) do nothing special with these characters.
+
+Changes the debug switch name from -D to -Z. Adds a -D switch for
+defining names in systemdict from the command line. Defines -DDEBUG for
+printing out debugging information during initialization, and -DNODISPLAY
+for suppressing display output.
+
+Corrects a bug that prevented the error machinery from working -- in
+version 1.0, errors always dumped the stacks and aborted interpretation.
+
+Corrects a bug that made eq and ne not work for strings.
+
+Makes the atan (arctangent) operator normalize its results according to
+the PostScript convention.
+
+Makes the div operator check for zero divisor.
+
+Makes unimplemented operators (resetfile, echo, save, restore, strokepath,
+reversepath) truly undefined.
+
+Makes the interactive loop exit gracefully on end-of-file: in version 1.0
+this caused an infinite loop.
+
+Implements the status operator.
+
+Corrects a bug that made the 'for' operator deliver garbage values if one
+or more of the operands (start, increment, end) was a real.
+
+Corrects a bug that made the arc and arcn operators not pop their operands
+from the stack.
+
+Corrects a bug that made the kshow operator crash the interpreter.
+
+Corrects a bug that made the print operator fail on machines that don't
+pass structure arguments by simply pushing the contents of the structure.
+
+Adds a new operator, imagecharpath, to convert images to
+addcharpath-compatible outlines.
+
+Changes alloc and alloc_free to use char * rather than byte *, and
+alloc_free to return void rather than int, making them compatible with the
+library's expectations and with malloc/free.
+
+Explicitly casts all expressions of the form (ptr1 - ptr2) used as
+procedure arguments to unsigned, to handle an incompatibility between
+Turbo C versions 1.5 and 2.0.
+
+Changes some of the internal conventions for operators: operators that
+push on the operand stack must check for overflow explicitly, and
+operators that modify the execution stack must return a special code.
+(See oper.h for details.)
+
+Initialization (ghost.ps, gfonts.ps)
+--------------
+
+Modifies ghost.ps and gfonts.ps so they print debugging information only
+if the name DEBUG is defined. (Presumably the user will set this from the
+command line with -DDEBUG.)
+
+Changes ghost.ps so it initializes the nominal screen size to 640 x 350 on
+MS-DOS systems as before, but to 612 x 792 on Unix systems, which is an
+8.5" x 11" page at 72 pixels per inch.
+
+Library
+-------
+
+Corrects a bug that made the fill and eofill operators (gs_fill and
+gs_eofill) not perform a newpath afterward.
+
+Corrects the bug that made thin, nearly horizontal lines display wrong (as
+a series of disconnected dots) in the MS-DOS implementation.
+
+Fixes a bug in the EGA driver that often made it fill rectangular regions
+with black around information being displayed in white.
+
+Completely changes the internal representation of outline fonts, and
+changes btoi.ps (a Ghostscript language program for converting bitmaps to
+outlines) to use a new library call, gs_imagecharpath.
+
+Changes the extension for outline font files from .gf to .cp.
+
+Adds a new debugging switch, q, that traces all rectangle fill operations.
+
+Adds a new debugging switch, v, that traces all device-level output calls.
+
+Explicitly casts pointer differences passed as procedure arguments, as in
+the interpreter.
+
+Makes stringwidth work if there is no current point. In version 1.0, this
+gave a nocurrentpoint error.
+
+Usage procedures
+----------------
+
+Changes the name of the 'read me' file from READ.ME to README.
+
+Removes a bogus line (invoking the 'mcopy' utility) from the makefile.
+
+Splits up the makefile into a generic part (ghost.mak) and
+platform-specific parts (dos-ega.mak, unix-x11.mak). The latter are what
+is actually executed.
+
+Puts the definitions of the DEBUG and gs_DEBUG compilation flags into the
+makefile instead of in ghost.h and gx.h respectively.
+
+Changes the names of the documentation files to be a little less cryptic.
+Changes all the file names to lower-case in the documentation. Adds
+installation information to make.doc.
+
+Changes all function definitions (but not prototype declarations) to ANSI
+syntax, and adds a preprocessing step (ansi2knr) to convert them to K&R
+syntax on Unix systems.
+
+Changes the normal MS-DOS link configuration to not assume the presence of
+an 80x87 coprocessor, and describes how to increase performance if a
+coprocessor is present.
+
+Changes the names of all the interpreter .c files, except stream.c, to
+begin with 'i'.
+
+Version 1.0 (8/11/88)
+===========
+
+First version released to the public.
diff --git a/gs/history2.txt b/gs/history2.txt
new file mode 100644
index 000000000..ee4fd2def
--- /dev/null
+++ b/gs/history2.txt
@@ -0,0 +1,5160 @@
+ Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, history2.txt, describes the changes in older releases of
+Ghostscript numbered 2.n. For more recent changes, see the historyN.txt (N
+> 2) and NEWS files.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Version 2.9.10-beta (7/28/94)
+===================
+
+This is the last 2.9 beta, since 3.0 will be released on July 31.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A | in gs.1 had a \ in front of it instead of \\.
+
+Adds a paragraph in gs.1 that tells how to select paper size.
+
+Notes in devs.mak that the cdj550 driver is the best one for the H-P
+DeskJet 520, and the pjxl300 driver is the right one for the H-P DeskJet
+1200C.
+
+Notes in make.doc that Watcom C++ 10.0 may require a change in a makefile.
+
+Procedures
+----------
+
+Removes ICCINIT from MODULES.LIS for VMS systems.
+
+Updates VMS.MAK to support Motif V1.2.
+
+Updates jpeg.mak to work with version 5alpha4 of the IJG JPEG code.
+
+Utilities
+---------
+
+Fixes bugs:
+ - font2c didn't leave extra room in Type 0 font dictionaries for
+entries added by definefont.
+ - font2c left extra information on the stack.
+ - ansi2knr would remove newline characters within formal argument
+lists.
+ - font2c got an Error: /undefined in makefontprocname.
+
+Updates ansi2knr to work better with the GNU configure program.
+
+Updates ansi2knr to handle procedure formal arguments automatically.
+
+Drivers
+-------
+
+Fixes bugs:
+ - If a file contained color or gray-scale information followed by a
+masked image, the X driver would sometimes invert the polarity of the
+image.
+
+Platforms
+---------
+
+Fixes bugs:
+ - Unix systems with a 2-argument gettimeofday returned garbage
+values for the current time.
+ - The VMS build script for compiled fonts omitted the requirement
+to load gs_ccfnt.ps.
+ - memory_.h didn't note that System V Unix platforms need memmove.
+
+On Unix systems, changes the subdirectory of $datadir/ghostscript to just
+be the version number (e.g., 2.9.10 rather than gs-2.9.9).
+
+Fonts
+-----
+
+Adds support code for the Wadalab (University of Tokyo) free Kanji font.
+
+Notes in the documentation in Fontmap that .pfa and .pfb fonts are
+compatible with ATM, but .gsf fonts are not.
+
+Changes the names of Thomas Wolff's expanded Hershey fonts, replacing .gsf
+with .pfa.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The scanner became confused if the literal names /<< or />>
+straddled an input buffer boundary.
+ - .setlanguagelevel gave an invalidaccess error when
+switching from level 2 to level 1.
+ - currentgstate, setgstate, and copy for gstates didn't do
+the necessary access checks.
+ - The Category resource category didn't define .ResourceFile, so
+/Category resourcestatus gave an error.
+ - The garbage collector didn't trace the structures used by
+filenameforall properly on most platforms.
+ - Automatically expanding systemdict didn't work, but didn't give
+an error.
+ - Automatically expanding a dictionary usually expanded it by too
+much.
+ - systemdict was created too small.
+ - The garbage collector didn't trace the structures referenced only
+from allocator objects, leading to attempts to access freed storage.
+ - If a chunk was empty, the GC tried to free it even if it had
+inner chunks.
+* - The outer loop in dict_find_name_by_index() could cause an
+addressing fault on segmented machines when looking up Level 2 operators,
+because the offset could get decremented past 0.
+ - The heap_available procedure in gsmemory.c didn't convert
+properly to non-ANSI syntax. (New bug in 2.9.9.)
+ - The ledgertray procedure wasn't implemented.
+ - The xxxtray procedures didn't set the page size.
+ - The settumble operator wasn't implemented, even as a dummy.
+ - glyphshow didn't work with Type 3 fonts.
+ - Supplying a RenderTable for a CIE color space caused an error.
+ - The DCT filter code had the jpeg/ subdirectory name "wired in" to
+the source files.
+
+Adds experimental filters for Burrows/Wheeler block sorting compression
+(BWBlockSortEncode/Decode), described in DEC SRC Research Report #124,
+move-to-front coding (MoveToFrontEncode/Decode), and a simple form of
+Huffman coding (BoundedHuffmanEncode/Decode). These are experimental -- do
+not rely on them remaining the same (or existing at all) in future
+releases!
+
+Adds all function prototypes needed to pacify strict compilers.
+
+Removes all explicit references to userdict from the C code.
+
+Changes the SAFER switch so that it disallows not only explicit writing,
+deleting, or renaming of files, but also disallows specifying an explicit
+OutputFile for any device (except for the initial device, by means of
+-sOutputFile= on the command line).
+
+Streams
+-------
+
+Fixes bugs:
+ - Hex decoding (ASCIIHexDecode stream and <> literals) didn't treat
+the data source as read-only (although it restored it to its original
+contents).
+
+Implements move-to-front coding, a simple form of Huffman coding, and
+Burrows/Wheeler block sorting compression.
+
+Library
+-------
+
+Fixes bugs:
+* - (The following bug fix was actually implemented somewhere around
+version 2.7.) restore didn't purge character cache entries whose keys were
+names created more recently than the save.
+ - gstype1.h declared gs_type1_state_sizeof as an extern, but this
+wasn't defined anywhere.
+ - gs_makeimagedevice didn't set the size of the palette correctly,
+which confused the GC.
+ - gs_makeimagedevice didn't set num_components to 1 for
+mapped-color devices with only gray values.
+* - The two-color halftoning algorithms truncated when computing the
+halftone level, rather than rounding it.
+* - If a path being filled had line segments that fell entirely to
+the right of the clipping region, part of the path might not be filled.
+ - The optimized code for 24-bit color didn't ensure properly that
+32-bit accesses would be aligned appropriately.
+ - The miter join check had gotten reversed somewhere along the way.
+* - Because x and y were interchanged in the miter check computation,
+in some situations the check was inverted. (This is a very old bug!)
+ - It was believed that strokepath didn't work with dashed lines;
+the problem appears to have been an incorrect testing program.
+
+Adds all function prototypes needed to pacify strict compilers.
+
+Changes fixed2float so it doesn't cast the result to float, and removes
+fixed2double. This produces slightly more accurate results in many places,
+and may even be faster (for FPUs that normally generate double rather than
+single precision results).
+
+Version 2.9.9-beta (6/23/94)
+==================
+
+Documentation
+-------------
+
+Puts a pointer to devs.mak in the section of use.doc that talks about
+MS-DOS displays.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The %pipe% IODevice was omitted on System V platforms.
+ - The AXP VMS build script needed /NESTED_INCLUDE=PRIMARY in
+CC_QUAL to work around a bug in the DEC C compiler.
+
+Fonts
+-----
+
+Fixes bugs:
+ - gs_lev2.ps redefined .loadFontmap incorrectly.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - stream_compact used memcpy even though the source and destination
+might overlap.
+ - filter applied to a closed file could cause a crash.
+
+Library
+-------
+
+Fixes bugs:
+ - putdeviceparams to a printer didn't close and reopen the device
+if only the page size or resolution was changed.
+
+Version 2.9.8 (6/20/94)
+=============
+
+This is the first version that claims to be a full Level 2 implementation.
+It was distributed to satisfy a contractual requirement.
+
+Documentation
+-------------
+
+In make.doc:
+ - Adds a reference to the generic System V section at the end of
+the SCO section.
+ - Notes that DEC OSF/1 systems may require changing the name of the
+install program to installbsd.
+
+Updates drivers.doc to reflect the change from "properties" to
+"parameters".
+
+Updates the Aladdin Enterprises Free Public License to version 1.
+
+In language.doc, notes that certain device parameters will be phased out.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The file aa.ps was included in the distribution by mistake.
+
+Notes in the Unix makefiles that X11R6 probably needs SM and ICE added to
+XLIBS.
+
+Utilities
+---------
+
+Fixes bugs:
+ - viewjpeg.ps used a non-existent file as its example.
+ - A temporary string in wrfont.ps was allocated too small.
+
+Upgrades font2c.ps so it will handle (simple) Type 0 fonts as well as Type
+1.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF drivers didn't byte-align each scan line.
+ - gdevtfax.c applied & to an array member of a structure.
+
+Changes the param_list interface slightly: Implementations of the
+put_params driver procedure should now use param_signal_error to report
+errors, and should not give up at the first error. (Even though this is a
+non-backward-compatible change, old implementations will continue to work;
+they just won't deliver complete results to the setpagedevice Policies
+machinery.)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Removes the time zone adjustment from gp_get_clock in gp_unix.c,
+since the value returned by all Unix systems is bogus.
+ - The DV/X makefile still included the dfaxhigh and dfaxlow drivers.
+ - gssetmod.com (VMS command file) didn't work properly if the
+argument list was empty.
+ - vms.mak, vms-axp.mak, and modules.lis hadn't been updated to
+reflect changes in 2.9.7.
+ - The MS Windows version wouldn't link (overflowed the 64K primary
+data segment).
+
+Fonts
+-----
+
+Makes the font substitution algorithm somewhat more intelligent.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Enumerating the pointers of a zero-length array of structures
+caused a divide by zero.
+ - iref.h didn't protect itself against multiple inclusion.
+ - The CCITTFaxEncode filter didn't byte-align the final
+end-of-block code if EndOfBlock and EncodedByteAlign were both true.
+ - make_initial_dict in iinit.c used `name' as a formal parameter
+name, which some compilers believe conflicts with a typedef.
+ - Not all internal operators had registered names.
+ - The GC used memcpy, rather than bytes_copy, when compacting
+objects, even though the source and destination might overlap.
+ - When debugging was enabled, gc_string_mark could give a spurious
+error indication.
+ - vmstatus returned too small a value for the maximum VM.
+ - The scanner could get into a loop when reading a radix-85 string.
+ - The GC could get into a state where it was called after every
+allocation (because of the patch setting global = true in ireclaim).
+ - The general path filling algorithm didn't skip regions that were
+completely outside the clipping box.
+ - The gs_screen_enum structure contained a pointer (porder) that
+pointed into the middle of a structure, confusing the GC.
+
+Implements the BitmapWidths flag in fonts. The default of false means that
+we use scalable widths even with xfonts.
+
+Changes the Generic resource category so that ResourceFileName is optional.
+
+Changes the .getdeviceparams operator so that it takes an optional
+dictionary giving the set of keys whose values are wanted. Changes the
+.putdeviceparams operator so that it takes an optional policy dictionary
+specifying the action to be taken on errors, and returns a list of keys and
+errors if it fails, rather than causing an error. These are
+non-backward-compatible changes, but ordinary programs do not use these
+operators.
+
+Changes the names of some internal operators and procedures by adding
+a . to the beginning:
+ currenttime
+ devicename
+
+Implements currentpagedevice, and a small subset of setpagedevice. Only
+the following keys in the page device dictionary are known to the current
+implementation, and the ones marked with * are not actually processed:
+ PageSize
+ InputAttributes
+ MediaColor, MediaWeight, MediaType, InsertSheet
+ (for InputAttributes matching only)
+ *ImagingBBox
+ OutputAttributes
+ OutputType
+ (for OutputAttributes matching only)
+ NumCopies
+ HWResolution
+ *Margins
+ *Orientation (for all devices, not just roll devices)
+ Policies
+ Install
+ BeginPage
+ EndPage
+Does not implement:
+ - Updating InputAttributes or OutputAttributes by sensing the state
+ of the device;
+ - Retrying media matching after an initial failure;
+ - Automatic handling of portrait vs. landscape page size;
+ - Recording the CTM after Install as the one to be used for
+ defaultmatrix, initmatrix, and initgraphics.
+Also, media matching is normally disabled (with InputAttributes = null)
+for all devices. ****** We had to disable setpagedevice just before
+shipping this release, because of interactions with the older device
+handling machinery that we could not fix in the time available.
+
+Library
+-------
+
+Fixes bugs:
+ - 24-bit color (mem_true24_fill_rectangle and _copy_mono) had
+algorithm bugs.
+ - A complex conditional expression in gx_render_gray wouldn't
+compile properly with the DECStation 3100 Ultrix 4.3 compiler.
+ - The GC routines for gx_device_clip didn't handle the case where
+the 'current' pointer pointed to list.single.
+ - gx_add_char_bits used memcpy, rather than bytes_copy, for
+compressing character bitmaps, even though the source and destination might
+overlap.
+ - Some compilers require the definition of st_gstate_contents to
+precede the definitions of the GC procedures.
+ - Filling a large rectangle (more than 1K of bitmap) with a colored
+halftone overwrote random areas of the stack.
+
+Changes gs_setcachedevice[2] to take a pointer to an array of floats,
+rather than 6 or 10 individual floats. THIS IS A NON-BACKWARD-COMPATIBLE
+CHANGE.
+
+Implements the BitmapWidths flag in fonts.
+
+Version 2.9.7-beta (6/5/94)
+==================
+
+Yet another pre-3.0 beta. The main features are a fairly reliable garbage
+collector, and function prototypes almost everywhere they are needed.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The comment at the beginning of the zfindlibfile procedure was
+incorrect.
+
+Replaces the GNU License (the COPYING file) with version 0 of the new
+Aladdin Enterprises Free Public License (the PUBLIC file).
+
+Procedures
+----------
+
+Fixes bugs:
+ - The definition of cmykread.dev in gs.mak was incorrect (it
+modified color.dev).
+
+Adds the ability to specify a value for FONTPATH on the command line
+(-sFONTPATH=), overriding GS_FONTPATH.
+
+Replaces the -oper2 configuration resource type with the ability to specify
+in the op_def list the dictionary in which operators will be defined. (See
+opdef.h for more details.) This is an internal change only.
+
+Utilities
+---------
+
+Fixes bugs:
+ - viewgif.ps got an error on interlaced GIF files whose height
+wasn't a multiple of 8.
+
+Changes traceop.ps so it stores the traced operator in the same dictionary
+where the operator is currently defined, if possible.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The new G3 fax drivers crashed on page widths greater than 2623
+(40 * 64 + 63) pixels. (We fixed this by disallowing page widths greater
+than approximately twice this.)
+ - The 24-bit PCX driver had some debugging code accidentally left
+in it that produced large volumes of useless console output.
+
+Removes the previous (Leffler) TIFF/F driver and the TruFax driver.
+
+Platforms
+---------
+
+Fixes bugs:
+ - time_.h, gp_unix.c, and gp_sysv.c didn't do the right thing on
+SVR4 platforms, where gettimeofday only takes 1 argument.
+ - The final linking command on Turbo C platforms didn't specify the
+COMPDIR directory for the linker.
+
+Fonts
+-----
+
+Changes the standard Fontmap to use the URW contributed fonts as
+work-alikes for Helvetica and Times Roman.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The garbage collector wasn't in a consistent state.
+ - In Level 2 mode, statusdict was allocated in global VM rather
+than local VM.
+ - resourceforall gave an error on the built-in categories such as
+Filter.
+ - The file searching algorithm didn't check the current directory
+first.
+ - When opening a file failed, it didn't return a different error
+depending on the problem.
+ - The CCITTFaxEncode filter crashed on widths larger than 2623 (64
+* 40 + 63) pixels. (We fixed this by disallowing page widths greater than
+approximately twice this.)
+ - The .type1getsbw operator gave an invalidfont error if a
+CharString started with anything other than a [h]sbw. (Adobe's published
+specs say this is invalid, but some Adobe MultiMaster fonts start with a
+callsubr and/or a callothersubr.)
+ - When printing out the stack with == after an error, the error
+handler got a repeated (and ultimately fatal) typecheck error if it
+encountered an object of non-standard type.
+ - The token operator could incorrectly attempt to free a structure
+on the stack if it encountered an input buffer boundary.
+ - string_to_ref didn't correctly set the a_local flag in the string
+object it created.
+ - If the -c switch was the last switch on the command line,
+Ghostscript always exited without going into interactive mode.
+ - copy didn't check for errors when copying a dictionary.
+
+Makes many minor changes (mostly adding prototypes) to reduce error and
+warning messages from gcc and other strict compilers.
+
+Adds files containing the 4 predefined PDF encodings (MacRoman, MacExpert,
+WinAnsi, and PDFDoc).
+
+Library
+-------
+
+Fixes bugs:
+ - image_bbox in gxccman.c could produce a division by 0 if a
+0-width character was being entered into the cache.
+ - gx_image_cached_char incorrectly specified a scale of 2x2 rather
+than 1x1 if it had to read bits from an xfont.
+ - Stale pointers in the halftone cache weren't cleared properly by
+a restore. (We fixed this by making grestoreall clear the halftone cache.)
+ - setdash used gs_malloc, rather than the current allocator, for
+allocating the dash pattern.
+ - If one attempted to fill a very wide region with a colored
+halftone, gx_dc_ht_colored_fill_rectangle would loop indefinitely.
+ - The container_offset in clipping devices was set incorrectly,
+causing the garbage collector to mangle pointers.
+
+Changes the fopen routine in IODevices so that it can return an arbitrary
+error code, rather than simply succeeding or failing. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE. It only affects IODevice implementations,
+of which there are very few. (It doesn't affect ordinary device drivers.)
+
+Changes the char_metrics xfont procedure so it returns the width as
+floating point numbers rather than integers. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE. It only affects xfont implementations, of
+which there are very few.
+
+Makes many minor changes (mostly adding prototypes) to reduce error and
+warning messages from gcc and other strict compilers.
+
+Version 2.9.6-beta (5/23/94, not distributed to the public)
+==================
+
+This, too, was supposed to be the last beta release for public release 3.0.
+It was created primarily for a user who desperately needed a Level 1 system
+that would run properly on a 64-bit hardware architecture. The garbage
+collector is badly broken (it's in the middle of an architectural change);
+setpagedevice is still not implemented.
+
+Documentation
+-------------
+
+Documents the standard location of Type 1 fonts on AIX.
+
+Changes the last few mentions of Ghostview for Microsoft Windows to GSview
+for Windows.
+
+Notes that Solaris 2.n provides the X11 header files in a different place.
+
+Changes README to reflect the differentiation between Aladdin Ghostscript
+and GNU Ghostscript.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The compilation rules for the modules that call the IJG library
+used -Ijpeg rather than -I$(JPEGSRC).
+ - The rule for gslib.dev omitted echogs$(XE) as a prerequisite.
+
+Makes it possible to define the values of buildtime, copyright, revision,
+revisiondate, and serialnumber in the makefile.
+
+Utilities
+---------
+
+Fixes bugs:
+ - The viewgif.ps utility didn't handle local color tables.
+
+Updates ps2ai.ps to version 1.81.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF and fax devices used some identical names, causing
+linker complaints.
+ - The bj10e/bj200 driver inadvertently disabled the sheet feeder.
+(The change may not actually fix this bug, since we don't have either of
+these printers with a sheet feeder to test it on.)
+ - The 'bit' device didn't map colors to pixel values correctly.
+ - The monochrome PCL driver didn't work around the fact that the
+Canon LBP4i printer didn't clear its seed row correctly.
+
+Adds new drivers:
+ - A user-contributed driver for the H-P DesignJet 650C.
+ - A user-contributed driver for the Canon LIPS III printer.
+ - A completely new tiffg3 driver with one based on the new, fast
+faxg3 code. This driver does not include any external code, and carries an
+Aladdin copyright.
+ - A tiffg4 driver, also based on the fast CCITT filter code.
+
+Removes the tiffg3x driver that appeared briefly in 2.9.5, and renames the
+previous (Leffler) tiffg3 driver as tiffg3x.
+
+Adds support for A0, A1, and A2 paper sizes to PCL drivers.
+
+Changes all the names involving "props" to "params", for consistency with
+the header files, some other internal interfaces, and Adobe's terminology.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. However, it only affects devices
+that implement their own get_props and put_props procedures, of which there
+aren't very many.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The DV/X makefile used X11 rather than X for the X11 library name.
+ - The DV/X makefile incorrectly included the PC display drivers.
+ - The DV/X makefile omitted gp_dosfs.$(OBJ) from the list of
+platform-specific files.
+ - The DV/X makefile used : rather than ; for separating directory
+names in GS_LIB_DEFAULT.
+ - x_.h omitted a needed alias for XtAppSetFallbackResources.
+ - The makefile entry for System V Unix systems didn't include
+gp_unifn.$(OBJ).
+ - The comment before LDFLAGS in the gcc makefiles incorrectly
+suggested using the -x switch on Ultrix platforms.
+ - The forward declaration of quant_params in zfdct.c upset the Sun
+compiler because it declared a parameter as float rather than floatp.
+* - The Microsoft C compiler, like the Borland C compilers, only
+compares the offset part of segmented pointers.
+
+Fonts
+-----
+
+Adds a fontmap suitable for use with Adobe Type Basics.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The STACK_LOOP_BEGIN macro in istack.h didn't work correctly on
+segmented systems.
+ - The end_phase procedure in igc.c didn't work correctly on
+segmented systems.
+ - Indexed color spaces didn't mark their base space properly when
+garbage collecting.
+ - The garbage collector didn't work on segmented systems, because
+it smashed the lsize field of large objects with mark/reloc information.
+ - Some structures didn't have correct associated GC procedures:
+gs_indexed_map, gs_client_pattern, gs_pattern_instance.
+ - restore could free names or stack segments that were still
+referenced.
+* - If a packed object caused an error, the error object could be set
+to garbage rather than the correct object.
+* - Badly designed error handlers which use $error for temporary
+storage could cause a dictfull error.
+ - Some compilers objected to the use of "dict" as a variable name
+in a scope where it was defined as a type.
+ - IODevices were declared const and non-const inconsistently.
+ - setpagedevice popped one object too many off the stack if the
+request included any subdictionaries that needed to be merged.
+ - More garbage collector bugs were fixed.
+ - If the current stack block was empty, Level 2 restore would give
+a spurious typecheck error.
+ - The CCITTFaxEncode filter could get confused if it emptied the
+input and filled the output at the same time.
+ - The CCITTFaxEncode filter could insert an extra EOL if it had to
+suspend at certain times.
+ - The new parser for literal strings (as of 2.9.5) could mis-count
+internal parentheses if a parenthesis caused the internal buffer collecting
+the string to overflow.
+ - If the current stack block had fewer than 3 elements,
+.type1addpath could report a spurious typecheck error.
+ - Text rendering operations (show, stringwidth, etc.) caused a
+crash if the current color was a Pattern that hadn't already been
+rasterized.
+ - If a program did a grestore when the graphics state stack was
+empty, the graphics state was initialized to unexpected (and, in some
+cases, invalid) values.
+ - pathforall could cause a bogus stackoverflow if it overflowed the
+current stack block.
+ - Closing an encoding filter with a procedure as target left the
+filter on the stack.
+* - The outer loop in dict_lookup() could cause an addressing fault
+on segmented machines when looking up Level 2 operators, because the offset
+could get decremented past 0.
+ - There was an = instead of an == in a test in scanner_reloc_ptrs.
+ - The call on gs_reloc_refs in sproc_reloc_ptrs in zfproc.c omitted
+the last (gcst) argument.
+
+(Re-)implements the 2-D case of CCITTFaxEncode, and fixes a couple of bugs
+in it.
+
+Adds DiffEncode and DiffDecode filters that implement color prediction for
+the PDF variant of the LZWDecode filter.
+
+Changes the specification of .oserrorstring to be similar to getenv,
+where, etc. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE; however, no
+user-written code should be using .oserrorstring.
+
+Adds oversampling for better character rasterizing.
+
+Library
+-------
+
+Fixes bugs:
+ - gx_dc_ht_colored_fill_rectangle gave a compiler warning because
+of a problem with const pointers.
+ - dfmul2fixed_vars (in gxfixed.h) omitted the & before vda on
+big-endian platforms, causing compilation errors.
+ - IODevices were declared const and non-const inconsistently.
+ - The Type 1 rasterizer never enabled overshoot suppression.
+ - stroke didn't fatten the line properly if stroke adjustment was
+enabled, or if the line was horizontal or vertical.
+* - The clipping test for characters was too strict by almost 1
+pixel, leading to unnecessary clipping of text at the edge of the clipping
+box.
+* - The initial clipping box was computed incorrectly for devices
+whose initial transformation matrix included a rotation.
+
+Changed the implementation of clipping lists and show enumerators to use
+separate objects rather than embedded objects, to pacify the GC. (This is
+an internal change, not visible at the PostScript or API level.)
+
+Makes the character cache trim off left and right blank areas, as well as
+top and bottom. (Internal change.)
+
+Adds oversampling for better character rasterizing.
+
+Version 2.9.5-beta (4/11/94)
+==================
+
+This was supposed to be the last beta release before 3.0, but it won't be.
+The only known major defects are the unreliable garbage collector, and the
+dummy implementation of setpagedevice/currentpagedevice.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The file commnew.doc didn't belong in the fileset.
+
+Notes in the makefiles that SVR4 systems may need to set EXTRALIBS=-lnsl.
+
+Adds a user-contributed `man' page for the ps2epsi utility.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The IJG files didn't compile properly by themselves, because they
+didn't have $(AK) in their dependency list.
+
+Changes back the handling of files named on the command line, so that they
+are first sought in the current directory, and if that fails, use the
+search path. (2.9.4-beta changed things so that files on the command line
+did not use the search path, because as of that version, the search path
+doesn't necessarily include the current directory. I consider the "check
+the current directory and then use the search path" rule, which is the
+MS-DOS standard and was used in Ghostscript prior to 2.9.4, a serious
+mistake, since it is one of the best-known security holes in Unix and can
+also produce confusing and unexpected results depending on the current
+directory; I would much rather have a clear distinction between
+user-specified files, which should not use any path searching, and system
+files, that only use the defined search path. However, as of this moment,
+users seem to want the convenience at the expense of insecurity and
+confusion.)
+
+Adds '.' to the beginning of the search path for MS-DOS platforms, to
+conform to the usual MS-DOS file searching convention.
+
+Adds a -c ("code") switch, which interprets following arguments (until the
+next switch) as PostScript tokens.
+
+Changes the handling of FEATURE_DEVS so that either level1.dev or
+level2.dev must normally be selected. THIS IS A NON-BACKWARD-COMPATIBLE
+CHANGE for Level 1 systems, which formerly set FEATURE_DEVS to an empty
+definition.
+
+Utilities
+---------
+
+Fixes bugs:
+ - bench.ps didn't switch back to local VM properly before running
+the program being benchmarked.
+
+Adds a ppmsetpagesize command to the pstoppm utility.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PCX and GIF drivers used an incorrect algorithm for computing
+the blue component of the color palette, which could cause colors to come
+out with not quite enough blue.
+ - The SPARCprinter driver wouldn't compile with non-ANSI compilers.
+
+Adds new drivers:
+ - A user-contributed driver for DEC sixel displays like the VT240
+(sxlcrt, in gdevln03.c, which has a FSF copyright.)
+ - A much larger and supposedly faster version of the TIFF/F driver
+(tiffg3x, in gdevtifx.c), contributed by a user. This has the same
+copyright as the TIFF/F driver (gdevtiff.c).
+ - A driver (faxg3, in gdevfax.c) that produces plain Group 3 fax
+output with no header, using the CCITTFaxEncode filter to do the work.
+(This is around 2.5-3 times as fast as the other fax drivers distributed
+with Ghostscript.)
+ - A user-contributed driver for the Mitsubishi CP50 color printer.
+
+Changes the `bit' driver so one can set the Colors and *Values properties.
+
+Makes the color mapping for PC displays, PCX files, and GIF files identical
+(they differed slightly before).
+
+Platforms
+---------
+
+Fixes bugs:
+ - VMS used DISPLAY rather than DECW$DISPLAY to get the display name
+if opening the display failed.
+ - Many minor bugs relating to OS/2 and Win32 were fixed.
+ - On Unix and DV/X platforms, the install script didn't mkdir
+$(gsdir), and didn't mkdir the intermediate directory for the man page.
+ - On BSD and UTek platforms, the declaration of memset in
+memory_.h, and the definition in gsmisc.c, conflicted with the ANSI
+declaration.
+ - One of the SPARC compilers compiled the intersection computation
+in arc_either (gspath.c) incorrectly.
+ - The temporary file names created under OS/2 could exceed the 8.3
+length limit.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The test files for the IJG library had been damaged by EOL
+conversion.
+ - The garbage collector didn't mark some of the most recently
+created names.
+ - The interpreter would sometimes report a typecheck instead of a
+stackunderflow.
+ - If aload didn't have enough room on the stack, it would report a
+rangecheck rather than a stackoverflow.
+ - zcontext wouldn't compile, because it hadn't been updated to the
+new GC interfaces.
+ - The definition of private_st_stream_proc_state in ifilter.h ended
+with a semicolon, which upset some compilers.
+ - load didn't check to make sure that the dictionaries it examined
+had read access.
+ - cvrs didn't handle negative numbers in radix 2 or 3 properly.
+ - The allocator could become confused if it was asked to allocate a
+large array.
+ - readline gave an ioerror rather than a rangecheck if it
+overflowed the string.
+ - The allocator didn't free packed arrays properly.
+ - The allocator's check for LIFO freeing of arrays was off by 1, so
+it never succeeded.
+ - The undercolor removal and black generation procedures weren't
+initialized properly.
+ - If the interpreter couldn't find gs_init.ps, it returned a random
+exit code.
+ - If an operator expected a procedure and didn't get one, it
+sometimes gave an invalidaccess rather than a typecheck.
+ - Unix file enumeration often did the wrong thing if there were
+directories in the pattern.
+ - The ASCIIHexDecode filter read an extra character after the
+terminating >.
+ - scalefont didn't fill in ScaleMatrix properly.
+ - The CCITTFaxEncode filter crashed if the width of the page wasn't
+a multiple of 8 bits.
+ - The error printing code used .languagelevel, which wasn't defined
+in Level 1 configurations.
+ - setpagedevice didn't pop its argument.
+ - Definitions in statusdict didn't change according to the current
+language level.
+ - Separation color spaces didn't allow strings as color space names.
+ - Due to a bug in chunk_locate_ptr, the garbage collector sometimes
+decided incorrectly that a pointer was pointing outside collectable space.
+ - (Many other garbage collector bugs were fixed.)
+
+Implements additional Level 2 features:
+ - Garbage collection for strings.
+ - Expandable operand and dictionary stacks, and the ability to set
+ the maximum size of these stacks.
+ - Additional user and system parameters. The following are dummies:
+ AccurateScreens, JobName, JobTimeout, WaitTimeout.
+ - Procedure-based filters usable with cvx/exec and token.
+ - Separation color spaces (always using the alternate space).
+ (These were theoretically implemented in version 2.6, but they were
+ never tested and were actually missing most of the implementation.)
+ - VMThreshold and VMReclaim for invoking GC automatically.
+
+Adds a hook in iscan.c for parsing DSC comments.
+
+Adds encoding and decoding filters for the BCP and TBCP protocols. These
+are not fully implemented yet:
+ - The interrupt and status request characters are ignored on input,
+ and never generated on output;
+ - The TBCP encoder doesn't emit the start-of-protocol string;
+ - The TBCP decoder doesn't recognize the end-of-protocol string.
+
+Factors out Type 1 font capability as a separate feature.
+
+Changes the names of some files:
+ packed.h to ipacked.h;
+ bnum.h to ibnum.h.
+
+Changes the name of the value.index member of a ref to value.boolval.
+(Internal change only.)
+
+Library
+-------
+
+Fixes bugs:
+ - The definition of RELOC_PTRS_BEGIN in gsstruct.h wouldn't compile
+properly with non-ANSI compilers.
+ - The JPEG library wouldn't compile properly with non-ANSI compilers.
+* - The platform font machinery gave up too easily in some cases.
+ - CMYK devices needing halftoning converted the CMYK color to RGB.
+ - The debugging code in arc_add (gspath.c) didn't print the output
+values correctly.
+
+Factors out Type 1 font capability as a separate feature.
+
+Version 2.9.4-beta (2/19/94)
+==================
+
+Procedures
+----------
+
+Changes Ghostscript's path searching algorithm so that it does not
+automatically look in the current directory first. (The former algorithm
+was more MS-DOS-like; the new one is more Unix-like.) If you want to
+include the current directory, you must include '.' in the search path.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE.
+
+Adds two new resource types for genconf.c:
+ - -header filexxx.h adds #include "filexxx.h" to gconfig.h.
+ - -libpath dir adds dir to the list of library search paths.
+
+Utilities
+---------
+
+Fixes bugs:
+ - impath.ps (used by bdftops) computed the starting X coordinate
+incorrectly, typically causing characters to be displaced slightly to the
+right.
+ - pstoppm.ps didn't handle local and global VM properly.
+
+Adds a ps2ai.ps utility, contributed by a user, for converting arbitrary
+PostScript files into a form compatible with Adobe Illustrator.
+
+Drivers
+-------
+
+Adds new drivers:
+ - A user-contributed driver for Imagen Impress laser printers.
+ - A user-contributed driver for the DEC LA75plus printer.
+
+Platforms
+---------
+
+Under OS/2, adds the ability to keep Ghostscript in memory for a
+specified number of minutes.
+
+Adds support for Win32 and Win32s.
+
+Changes the MS Windows platform font interface so that it does not attempt
+to render fonts at sizes smaller than 6 pixels. Changes the X Windows
+interface, which already did this for 4-point and smaller fonts, to also
+use a lower limit of 6 pixels. Also changes the X Windows platform font
+machinery so it does not render fonts at sizes larger than 36 pixels: at
+large sizes, Ghostscript does a perfectly good job, and some X font servers
+rasterize the entire font and lock up the entire window system while doing
+so.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - currentdash always returned a new array of reals, rather than the
+actual argument of setdash.
+ - Strings in binary object sequences read in as integers.
+ - Because of a bug in chunk_locate_ptr, some large objects didn't
+get freed properly.
+ - If an error occurred while processing an image, Ghostscript would
+attempt to free random blocks of storage.
+ - Input filters discarded trailing data, rather than filling it out
+with zeros. (This is now fixed for ASCIIHexDecode and ASCII85Decode; it's
+not clear what other filters it should affect.)
+ - The ASCII85Encode filter produced garbage output for the final
+1-4 bytes before EOD.
+* - The TIFF output driver produced incorrect output for the second
+and subsequent pages if the output was being produced on multiple files.
+* - The default handleerror did a 'stop', which was not correct.
+ - gpcheck.h converted all positive return codes to 0 if interrupt
+checking was enabled.
+ - Images with multiple data sources didn't work.
+ - Images with 12-bit sample values didn't work.
+ - Images with a file as the data source read additional data beyond
+what was required.
+ - 2 vmreclaim worked (pretty much), but 1 vmreclaim didn't.
+ - If %lineedit was opened multiple times, characters from later
+openings overwrote characters from earlier ones.
+ - token returned garbage for the "remaining string" result when
+reading from a string, if it actually read all of the string. (New bug in
+2.9.2, probably.)
+
+Implements additional Level 2 features:
+ - DCTEncode and DCTDecode filters.
+ - Filters with procedures as the data source or target.
+ (Except for token and cvx/exec.)
+ - Garbage collection for names.
+
+Changes the error printout so that strings are always truncated at 200
+characters.
+
+For Level 2 systems, changes the initial setting of the object format
+parameter from 0 to an appropriate non-zero value.
+
+* Changes the .quit operator so that it takes two operands, an error object
+and an error code; if the latter is negative, the interpreter returns this
+as the error code, rather than e_Quit.
+
+Makes StandardEncoding and ISOLatin1Encoding arrays, rather than packed
+arrays, on large-memory systems, for compatibility with certain test
+suites. Changes .registerencoding to accept arrays as well as packed
+arrays.
+
+Library
+-------
+
+Fixes bugs:
+ - Due to an error in cie_mult3, CIE-based colors were badly
+mis-mapped.
+* - Very narrow (but not empty) rectangles would disappear.
+* - Small halftone cells could smash the next higher entry in the
+halftone cache.
+ - The orientation algorithm in gxstroke.c still interchanged
+clockwise and counter-clockwise coordinate systems (after having been
+"fixed" at least 3 times).
+ - Stroking 1-pixel-wide lines shortened them, instead of
+lengthening them, if non-butt caps were requested.
+
+Refactors mem_mapped8_copy_mono because of limitations in the bcc32
+compiler.
+
+Version 2.9.3-beta (1/19/94)
+==================
+
+This version was created for evaluation purposes for a few users who
+needed Level 2 capability; it was never released to anyone else, even
+beta testers.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The description of psview and xpsview was incorrect.
+
+Procedures
+----------
+
+Changes the installation directories for Unix and similar systems to put
+Ghostscript data in $(datadir)/ghostscript/gs-NN.NN.NN rather than directly
+in $(datadir)/ghostscript. (Fonts still go in $(datadir)/ghostscript/fonts.)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Some spaces were incorrectly replaced with tabs in the help
+message in the 3B1 display driver.
+ - The BMP driver wrote a spurious scan line at the beginning
+of its output.
+ - The monochrome PCX driver had the two palette elements
+interchanged.
+
+Adds new drivers:
+ - A user-contributed driver for the Xerox XES printer format. This
+has a FSF copyright.
+ - A user-contributed driver for the Epson AP3250 printer. (This is
+the same as the Stylus 800, with slightly different margins.)
+ - A user-contributed driver for the DEC LA70 printer with some
+algorithms for improving text at low resolutions. This has a FSF
+copyright.
+ - A user-contributed driver for an intermediate-resolution mode
+for 9-pin "Epson-compatible" printers.
+
+Changes the name of the Stylus 800 driver from escp2 to st800.
+
+Adds a compile-time flag to the Epson driver to cope with Panasonic 9-pin
+printers, which sometimes have trouble mixing graphics and tabs.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The MS Windows driver (gp_mswin.c) referred to iodev.h rather
+than gxiodev.h.
+ - On Unix System V platforms, gp_unifs.c and gdevpipe.c were
+incorrectly omitted from the link list.
+ - (Some?) System V platforms don't have the S_ISDIR macro,
+requiring a change in stat_.h.
+ - The Unix `install' target didn't install gs_std_e.ps and
+gs_iso_e.ps.
+ - No MODULES.LIS file was provided for VMS.
+
+Adds Desqview/X makefiles that actually work.
+
+Documents the set of H-P-supplied patches needed to make H-P's
+compilers process Ghostscript.
+
+Changes the MS Windows driver so that if the user presses the Enter key
+while the image window has the focus, the text window will be brought to
+the top and made the active window. This is useful when viewing a
+multi-page document with Ghostscript.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The definition of public_st_client_color() in gxccolor.h
+included an extraneous semicolon.
+ - The definition of private_st_AXD_state() in sfilter.h included an
+extraneous semicolon.
+ - saxx.c didn't include sfilter.h, which it needed for the
+definition of private_st_AXD_state().
+ - ialloc_struct failed to create a separate chunk if the structure
+was very large.
+ - setcolorspace didn't allocate the colorspace object in the same
+VM space as the graphics state, causing problems when the colorspace was
+freed.
+ - In rare circumstances, currentfile could return an empty array
+rather than a file.
+ - Dictionary keys were always allocated in global VM.
+ - If NOPLATFONTS was true, definefont didn't check whether the
+dictionary was read-only before trying to insert an ExactSize key.
+ - startjob could get an invalidaccess error, because serverdict was
+allocated in global VM.
+ - Using definefont with an already registered font created a
+circular list structure.
+ - If a PostScript procedure appeared as a CharString in a Type 1
+font, it was always called with the character name, never the character
+code.
+ - The SubFileDecode filter didn't work with a non-empty EOD string
+(went into an endless loop). (Probably a new bug in 2.8.)
+ - save/restore didn't properly restore the maxlength of a
+dictionary, causing data to get smashed at random. (New bug in 2.9.)
+ - save didn't mark objects as old, so a nested restore had no
+effect. (New bug in 2.9.2.)
+ - After returning from an OtherSubrs callback, op_type1_free
+freed the saved interpreter state incorrectly. (New bug in 2.7.)
+ - Level 1 configurations didn't work because .makeoperator gave an
+invalidaccess error. (New bug in 2.9.2.)
+ - ASCII85 string literals didn't work. (Probably a new bug in 2.8.)
+ - If the current global/local allocation mode was different at the
+end of a file than at the beginning, an addressing fault could occur
+(gs_unregister_root in gs_run_string). (New bug in 2.9.2.)
+ - After a setfileposition on a file open for reading,
+fileposition would return an incorrect value, even though the stream
+was actually repositioned properly.
+
+Brings the dictionary unpacking code for the DCT filters into line with
+Adobe Technical Note 5116, which describes the Picky parameter for
+DCTDecode and the NoMarker, Resync, Blend, Picky, and Relax parameters for
+DCTEncode.
+
+Changes the .quit operator so that if given a negative argument, the
+interpreter returns this as the error code, rather than e_Quit.
+
+Changes the Ghostscript integer version number from 100P+10S+T to
+10000P+100S+T.
+
+Changes the default halftone screen for high-resolution devices, both
+black-and-white and color.
+
+Library
+-------
+
+Fixes bugs:
+ - The software floating multiply code used with USE_FPU=-1 only
+worked on little-endian platforms.
+ - Specifying a left side bearing to .type1addpath produced an
+inappropriate offset.
+
+Version 2.9.2-beta (1/2/94)
+==================
+
+This version was distributed only to beta testers. It adds a garbage
+collector and full local and global VM support. It is the first version
+that sets languagelevel = 2, i.e., claims to be a Level 2 implementation.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - make.doc still referred to use_* variables in gdevx.c, and
+use.doc didn't explain the use* X resources.
+
+Notes that -Olimit=1000 is needed to compile Ghostscript on AXP systems
+under OSF/1 1.3.
+
+Utilities
+---------
+
+Fixes bugs:
+ - viewgif.ps did not work with interlaced images.
+ - font2c.ps omitted gsmemory.h from the #include list in compiled
+fonts.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The MS Windows driver hadn't been updated to work with the
+new additions to the gx_device structure.
+ - The BMP file driver wrote one scan line too many.
+ - The cdj driver omitted an important cast to int in the error
+diffusion code (FSdither macro).
+
+Changes the SuperVGA drivers to recognize erasepage and reset the
+color table, like the X driver.
+
+Adds some fragmentary code to begin implementing the PostScript fax
+extensions.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The procedure initializers for the MS Windows console I/O
+were missing the new reset element.
+ - The makefile entry in bcwin.mak used -fdev rather than -iodev.
+ - The Borland C++ makefiles exceeded MS-DOS's line length limit if
+the compiler files were in the standard Borland directory (BORLANDC).
+ - Some procedures weren't declared with prototypes in gp_vms.c.
+ - Some declarations had to be reordered to pacify the VAX compiler.
+ - Under MS Windows, Ghostscript didn't automatically de-iconify the
+text window to display messages on an error exit.
+ - The Unix makefile rule for gconfig_.h used echogs rather than
+./echogs.
+ - The Microsoft C makefile referred to an obsolete file gs.tr.
+ - gp_unifs.c used strpbrk and strrchr, which some systems lack.
+
+Updates the OS/2 code and documentation for compatibility with the current
+Ghostscript version.
+
+Fonts
+-----
+
+Fixes bugs:
+ - The X11 .pfa fonts replaced their .gsf requirements in the
+fontmap, but not distributed with the previous (beta) release.
+
+Adds fontmaps appropriate for use with DEC Ultrix and OSF/1 systems.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - 4-value entries in the Metrics dictionary were interpreted with
+the width and side bearing interchanged.
+ - Objects large enough to require their own chunk were not freed
+properly.
+ - The GS_FONTPATH scanner didn't deal with the possibility that
+opening a file might fail.
+ - The interrupt and timeout errors incorrectly pushed an error
+object on the operand stack.
+ - imagemask gave an error if it was invoked with a dictionary
+argument with a current color space with more than 1 parameter.
+ - definefont insisted that a new font not have a FID entry.
+ - Some places didn't cast char to byte when needed.
+ - An extra element was left on the stack when substituting the
+default font for a font whose file couldn't be found.
+ - The CCITTFaxDecode filter didn't allow the dictionary to be
+omitted. (The Adobe documentation doesn't allow this, but Adobe
+implementations do.)
+ - When the input came from a pipe (`-') switch, opening a filter on
+currentfile that required more than 1 input byte to make progress would
+cause Ghostscript to hang (in sreadbuf).
+ - The interpreter didn't call gs_set_lib_paths before executing a
+compiled-in initialization file.
+ - A stream could be closed more than once. (New bug in 2.8.)
+ - The LZW decoder produced incorrect output if a code string was
+too long to fit into a single output buffer. (New bug as of 2.8.)
+
+Implements a special check in def to allow construction of systemdict,
+which is stored in global VM but references dictionaries in local VM.
+
+Implements additional Level 2 features:
+ - %null% and %ram% IODevices.
+ - startjob, exitserver.
+ - Local and global VM (finish).
+ - Garbage collection (for everything except names and strings).
+
+Moves the procedures for selecting paper size from systemdict to userdict.
+
+Sets languagelevel to 2 in Level 2 mode, since essentially all of
+Level 2 is now implemented.
+
+Factors out the Level 1 extended color facilities (CMYK color and
+colorimage) as a separate configuration feature.
+
+Adds some preliminary code to begin implementing the Adobe BCP and TBCP
+communication protocols.
+
+Changes the implementation of save and restore so that the bookkeeping
+structures are allocated in the new area, not the old. (This is an
+internal change not visible at the PostScript level.)
+
+Library
+-------
+
+Fixes bugs:
+ - gdevprn used some preprocessor macros in formal argument
+lists that ansi2knr couldn't handle.
+ - pick_cell_size called gs_distance_transform with a 0 argument
+that non-ANSI compilers didn't automatically promote to floating point.
+ - gs_screen_init called hypot with integer arguments that
+non-ANSI compilers didn't automatically promote to floating point.
+ - Some places didn't cast char to byte when needed.
+ - The vx/vy origin adjustment for WMode=1 wasn't implemented.
+ - The pattern cache wasn't initialized properly.
+ - Composite fonts didn't properly decode strings that started with
+an escape sequence, which have a special (undocumented) decoding rule, and
+also didn't properly decode strings with multiple consecutive escape
+sequences.
+
+Factors out the Level 1 extended color facilities (CMYK color and
+colorimage) as a separate configuration feature.
+
+Version 2.9.1-beta (12/7/93)
+==================
+
+This version was distributed only to beta testers.
+
+Utilities
+---------
+
+Adds a viewgif.ps utility to view GIF files. The current version does not
+work with interlaced data, local color tables, or files containing more
+than one image.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - putinterval and copy didn't do the right thing if the source and
+destination were aliases for overlapping sections of the same array or
+string.
+ - The DCT filter stub didn't allow the dictionary to be omitted.
+(The Adobe documentation doesn't allow this, but Adobe implementations
+do.)
+
+Adds an optional dictionary argument to the LZWDecode filter, containing
+InitialCodeLength, FirstBitLowOrder, BlockData, and EarlyChange entries.
+Setting these parameters appropriately allows reading (non-interlaced) GIF
+data directly.
+
+Library
+-------
+
+Fixes bugs:
+ - setdash produced inverted output if the pattern had an odd
+number of elements and the offset O had the property that L <= O mod
+2*L, where L was the sum of the pattern elements.
+
+Version 2.9-beta (12/6/93)
+================
+
+Like 2.7, this version was created to satisfy a contractual requirement,
+and will never be distributed to anyone other than the other party to the
+contract.
+
+Documentation
+-------------
+
+Notes that Ghostscript runs on IBM PCs and compatibles under DR DOS
+6.0.
+
+Notes that Ghostscript will run on IBM PCs and compatibles with
+Hercules display cards if you redirect text output to a file.
+
+Notes that the alternate DeskJet 500C driver (djet500c) does not work
+on the 550C.
+
+Gives a list of system-specific directories where Type 1 fonts are
+likely to be installed, as a suggested setting for GS_FONTPATH.
+
+Procedures
+----------
+
+Changes the distribution script so that it stores all text files in the
+main source archive with Unix end-of-line conventions, but with DOS
+end-of-line conventions in the MS-DOS-specific archive.
+
+Changes the MS-DOS, MS Windows, and OS/2 makefiles so that 486SX and 486DX
+processors are different CPU_TYPEs. (The former, designated by
+CPU_TYPE=485, does not include an on-chip FPU.)
+
+Adds a line to gs_init.ps which can be uncommented to select A4 as
+the default paper size.
+
+Adds a definable CFLAGS macro to the makefiles, allowing -DA4 to
+select A4 as the default paper size.
+
+Adds the H-P printer drivers to the standard Unix configurations.
+
+Utilities
+---------
+
+Fixes bugs:
+ - If there were no unencoded characters, prfont.ps would get
+an error.
+
+Changes ansi2knr to accept a wider range of function declaration syntax,
+and to not depend on any Ghostscript header files.
+
+Drivers
+-------
+
+Fixes bugs:
+ - Several drivers (DigiFax, Epson LQ-2550, NEC P6) didn't handle
+A4 paper width.
+ - The IBM ProPrinter wasn't being initialized properly.
+ - The Epson driver didn't work properly with compilers that
+insisted on 'char' being a signed type.
+ - The Epson driver ignored its end_string argument, producing
+incorrect end-of-page behavior on some printers.
+
+Adds new drivers:
+ - User-contributed drivers for Bellcore MGR (a window manager most
+commonly used with OS-9) devices.
+ - A user-contributed driver for the CIF file format.
+ - A user-contributed driver for the HP 2563B line printer.
+
+Changes the LaserJet 2p, 3, and 4 drivers so they set the initial position
+to (0,0) rather than (0,0.25"). (I don't remember why it was the other
+way.)
+
+Implements the PageCount property in all drivers, not just printer
+drivers.
+
+Introduces a new gx_tile_bitmap type, and changes the tile_rectangle
+device procedure to take it in place of gx_bitmap. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE. However, it only affects devices that
+implement their own tile_rectangle procedures, of which there aren't very
+many.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS module lists referred to SDCTD and SDCTE instead of
+SDCT.
+ - The Unix install script tried to install the non-existent file
+readme.doc.
+ - Microsoft C does something bizarre with empty macro parameters,
+which caused a problem with the gs_struct_type_... macros.
+ - The Unix platforms didn't automatically handle the presence
+or absence of <dirent.h>.
+ - The DEC Alpha OSF/1 1.3 library lacks `const' in the prototype
+for popen, which requires a workaround.
+ - The DEC Alpha OSF/1 1.3 X Windows library uses `private' as a
+member name.
+
+Splits off gp_unifs.c, containing code common to "Unix-like" file systems.
+
+Adds a user-contributed OS-9 platform.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The currentfile cache wasn't updated properly if an executable
+file appeared in the middle of a procedure. In particular, eexec-encoded
+.PFB fonts often didn't work.
+ - There was an extraneous `goto top' in scfd.c.
+ - An integer constant overflowed in iname.c.
+ - -2147483648 (i.e., -1 << 31) was converted to a float.
+ - eexec didn't skip the first 4 characters correctly if they were
+split across a buffer boundary.
+ - The font/matrix pair cache didn't properly free entries with only
+an XUID that was being deallocated.
+
+Implements additional Level 2 features:
+ - Patterns, makepattern, setpattern.
+ - IODevice resource, setdevparams, currentdevparams.
+ - OutputDevice resource, setpagedevice, currentpagedevice.
+ (Partially implemented.)
+
+Adds a new type t_struct to handle miscellaneous types that are allocated
+as objects and that the interpreter doesn't handle specially, and changes
+condition, fontID, gstate, lock, and save types to use t_struct. (This is
+an internal change, not visible at the language level.)
+
+Moves the maxlength of a dictionary to its own ref, eliminating the "size
+of integer" hack. (This is an internal change, not visible at the
+language level.)
+
+Adds the last OS error number to the error printout.
+
+Removes the obsolete framedevice operator.
+
+Implements resetfile (the only Level 1 operator not yet implemented!).
+
+Changes the name of the getdevice operator to .getdevice.
+
+Library
+-------
+
+Fixes bugs:
+ - A couple of necessary casts from char * to byte * were omitted.
+ - A Sun compiler required an extra cast to (void *) in the e1
+macro in clip_rect_enum_ptrs in gxcpath.c.
+ - The gx_dc_ procedures defined in gxdraw.c weren't marked as
+'private'.
+ - The number of "on" pixels in a halftone cell sometimes varied by
+1 from cell to cell.
+ - Mapping a gray level to CMYK didn't subtract it from 1 (to
+produce the K component).
+* - charpath took hints into account.
+
+Shuffles the order of some declarations to pacify the VMS C compiler.
+
+Version 2.8-beta (11/10/93)
+================
+
+This version was distributed only to beta testers. It adds Type 0 font
+support. It also includes extensive redesign of streams (to eventually
+support procedure streams) and device properties (to eventually support
+get/setpagedevice and get/setdevparams).
+
+Documentation
+-------------
+
+Notes the change in X11 foreground/background handling.
+
+Changes README so it no longer claims that Ghostscript works with X11R3.
+
+Notes (in devs.mak) that the cdjmono driver is the best one to use for the
+DeskJet 510.
+
+Procedures
+----------
+
+Fixes bugs:
+ - echogs wasn't always invoked with ./ on Unix systems.
+
+Changes the file name unix-ansi.mak to unixansi.mak, so it can be created
+on a MS-DOS system.
+
+Adds a new "feature", ccinit.dev, which compiles and links the
+initialization files (gs_*.ps) into the executable, just as ccfonts.dev
+compiles and links fonts. If ccinit and ccfonts are both selected, the
+only external file needed at run time is Fontmap. Note that you must have
+a working version of Ghostscript already in order to create a version that
+uses the ccinit feature, just as for ccfonts.
+
+Utilities
+---------
+
+Fixes bugs:
+ - the ps2image utility didn't put a %! on the first line of the
+output.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The Hercules display driver didn't include definitions for
+outport2 and PAGE_HEIGHT_INCHES, which it uses.
+ - The BGI driver didn't call setactivepage or setvisualpage,
+which it needs to do in general.
+ - The Apple DMP driver declared dmp_print_page rather than
+appledmp_print_page, causing a compilation error.
+
+Changes the X11 driver so that it doesn't use the default foreground and
+background colors: you must set foreground and background explicitly for
+Ghostscript if you want them to be other than black and white
+respectively.
+
+Adds new user-contributed drivers for:
+ - The StarJet 48 inkjet printer;
+ - The Linux VGALIB display interface.
+ - OS/2 Presentation Manager.
+
+Changes the margins of the Epson driver to 0.2, 0.0, 0.0, 0.0, which
+more accurately reflect the printer's capabilities.
+
+Changes the get_props and put_props device procedures to take property
+list "objects" with a procedural interface, rather than a data structure
+interface. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. It affects all
+get_props and put_props procedures. Fortunately, there were only a few
+devices that implemented their own get_props and put_props procedures (the
+H-P color printers, and the three window systems -- X Windows, MS Windows,
+and OS/2 PM).
+
+Platforms
+---------
+
+Fixes bugs:
+ - The meaning of the -p switch for the Watcom compile-and-link
+program was changed between Watcom C/386 versions 8.5 and 9.5, causing the
+make process to malfunction.
+ - The SCFTAB and SCFDTAB modules were omitted from the VMS link
+list.
+
+Adds user-contributed code for OS/2.
+
+Removes the assumption that an 80486 CPU implies the presence of hardware
+floating point, since the 486SX and Cyrix 486SLC don't have it.
+
+Fonts
+-----
+
+Fixes bugs:
+* - The GS_FONTPATH scanner didn't recognize .PFB fonts beginning
+with %!PS-AdobeFont.
+* - The GS_FONTPATH scanner often didn't recognize .PFB fonts at all.
+ - Type 1 fonts always set the line join, line cap, and miter limit
+to known values, rather than using the current values. (Using the current
+values doesn't make much sense, but it's apparently what the Adobe
+implementations do.)
+ - DISKFONTS didn't work, because of the change in the Ghostscript
+fonts to do a systemdict begin/end (in version 2.7.1).
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - == didn't produce exactly the same output as the Adobe
+interpreters. (Some automated debugging and testing programs care.)
+ - The CCITTFaxEncode filter could get caught in an infinite loop,
+because it failed to mask a byte datum when scanning for runs of black
+pixels.
+ - The write operator gave an error for values outside the range 0
+to 255, rather than just using the low-order 8 bits.
+ - Some applications call a statusdict procedure named
+setresolution without checking first whether it is present; Ghostscript
+didn't provide one.
+ - Reading from a closed stream caused an error instead of
+returning EOF.
+ - Input streams didn't close automatically at EOF.
+ - findfont was defined as an operator, not a procedure.
+ - closefile on a closed file gave an error. (It isn't obvious
+that the Adobe documentation specifies that it shouldn't, but that's what
+Adobe says they do.)
+ - The LZWDecode filter didn't handle codes representing strings
+longer than the buffer size correctly.
+ - The LZWDecode filter only allowed 4095 codes to be used, rather
+than 4096.
+ - The rand operator produced an infinite string of zeros if
+given 0 or 0x7fffffff as the seed.
+ - When a CDevProc procedure was called, there was an extra
+copy of the character name on the operand stack below the operands of
+CDevProc.
+
+Replaces all stream implementations with new ones designed to allow
+interruption at arbitrary times. ****** The 2-D case of CCITTFaxEncode
+hasn't been converted (but it probably didn't work before, either).
+
+Implements additional Level 2 features:
+ - Type 0 (composite) fonts.
+
+Adds an eexecEncode filter.
+
+Implements setcolorscreen, which was accidentally omitted from 2.7.
+
+Library
+-------
+
+Fixes bugs:
+* - In colorimage, if the color space of the image was different
+from the current color space, and the first data values on a scan line
+were zeros, the wrong color could result.
+ - The new flatness testing algorithm could overflow, producing
+straight lines or obvious polygons instead of curves.
+ - Images could fail to display pixels after the first non-blank
+pixel on a line if halftoned color was required. (This bug was probably
+introduced in 2.7.)
+ - Interpolation between transfer map entries didn't work, because
+of a rounding/truncation bug in frac2bits (bug introduced in 2.7.1.)
+ - cshow did an extra grestore at the end.
+
+* Implements a hack to slightly displace 1-bit-wide or -high images. This
+is necessary to work around a bug in TeX (or dvips?), which uses such
+images to draw horizontal and vertical lines without positioning them to
+ensure that they cover device pixel centers.
+
+Adds support for composite fonts (no new client procedures).
+
+Version 2.7.2-beta (10/11/93)
+==================
+
+This version was distributed only to alpha testers.
+
+Utilities
+---------
+
+Fixes bugs:
+ - prfont.ps didn't print unencoded characters.
+
+Improves mergeini.ps to remove embedded comments.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - An error occurring within the scope of an internal .stopped
+didn't pop the command and error name off the stack.
+* - The = and == procedures weren't re-entrant.
+
+* Adds a .writecvs operator that does a cvs to an internal string followed
+by a writestring.
+
+Library
+-------
+
+Fixes bugs:
+ - grestore freed the path and the clip path in an order that
+was likely to lead to memory sandbars.
+ - moveto + closepath didn't actually close the path.
+ - moveto + reversepath produced an empty path (no moveto).
+ - moveto + closepath + reversepath produced an extra lineto.
+ - reversepath didn't set the current point to the end (i.e., the
+former beginning) of the last subpath.
+
+Adds a "planar" memory device.
+
+Version 2.7.1-beta (10/4/93, not distributed to the public)
+==================
+
+Like 2.7, this version was created to satisfy a contractual requirement,
+and will never be distributed to anyone other than the other party to the
+contract.
+
+Documentation
+-------------
+
+Documents the GS_OPTIONS environment variable.
+
+Adds a summary of all environment variables to the documentation
+(use.doc).
+
+Documents the existence of a third free viewer built on Ghostscript.
+
+Utilities
+---------
+
+Fixes bugs:
+ - wrfont didn't wrap a systemdict begin / end around the body of
+the font.
+ - wrfont wrote out the Symbol and ZapfDingbats encodings in a way
+that only worked if the encoding was known by name.
+
+Changes bdftops to include an XUID if desired.
+
+Changes bdftops so that it uses 'show' for unknown ligatures, rather than
+executing the characters as subroutines; this makes such ligatures work
+properly with xfonts.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PCL drivers sent a printer reset (<ESC>E) at the beginning
+of every page, instead of only before the first page.
+ - The PCX driver didn't round up the scan line width in the
+header, even though it produced scan lines with the correct (rounded)
+number of bytes.
+
+Adds a new map_rgb_alpha_color procedure. This is a backward-compatible
+change; this procedure defaults to calling map_rgb_color.
+
+Platforms
+---------
+
+Fixes bugs:
+ - On Unix platforms, the value of the TEMP environment variable
+had to end with a '/'.
+ - On MS-DOS systems, printer output to devices other than PRN
+(specifically, LPTn) didn't put the device into binary mode.
+
+Adds FPU_TYPE to the Unix makefiles, with a default value of 1.
+
+Removes the mention of Xmu linking problems on the SunOS platform,
+since the problem no longer exists.
+
+Changes the order of X Windows libraries from Xt X11 Xext to Xt Xext X11.
+This makes the OSF/1 linker happier.
+
+Fonts
+-----
+
+Fixes bugs:
+ - All the fonts originated by Aladdin, and the shareware fonts,
+had UniqueIDs in the 4xxxxxx range, which is only supposed to be used for
+limited-distribution fonts.
+* - When Ghostscript loaded a font, it pushed a scratch dictionary
+on the dictionary stack, rather than userdict. (Note that this fix also
+requires fixing the fonts to include a protective systemdict begin /
+end; see below.)
+* - When loading a font failed, Ghostscript didn't check the font
+name against the default font name properly.
+ - Ghostscript's own fonts didn't include a systemdict begin /
+end to guard against redefinition of names used in the reading
+procedures (e.g., index).
+* - When Ghostscript scanned a .PFB font to get the FontName, it
+didn't skip over the 6-byte header, which could cause confusion or a
+syntaxerror.
+ - Loading a .PFB font that left extra information on the
+operand stack didn't work.
+
+Changes the ZapfDingbats font to use DingbatsEncoding rather than include
+a copy of the encoding in itself, if DingbatsEncoding is known. Changes
+the Symbol font similarly.
+
+Removes eexec encryption from the 4 URW fonts, so they will work with
+DISKFONTS.
+
+Adds shareware Hiragana and Katakana fonts (Calligraphic-Hiragana and
+Calligraphic-Katakana, by Kevin Hartig).
+
+Adds GS on the end of the family names of all of Aladdin's own converted
+fonts.
+
+Replaces many of the Hershey fonts with new ones (mostly Type 1) created
+by Thomas Wolff, who added accents, accented characters, and other
+non-alphabetics. These too now have proper UniqueIDs.
+
+Interpreter
+-----------
+
+Fixes bugs:
+* - imagemask interpreted the Decode array incorrectly (inverted).
+ - Running out of memory when constructing a path incorrectly
+signalled a limitcheck rather than a VMerror.
+ - restore didn't purge uncached scaled fonts properly.
+
+Adds alpha (opacity) to the graphics state, and setalpha and
+currentalpha operators.
+
+Redefines erasepage in terms of a new .fillpage operator that fills
+the current page with the current color and then does a sync_output.
+
+Redefines setdevice and putdeviceprops in terms of new .setdevice and
+.putdeviceprops operators that return a boolean indicating whether the
+page needs to be erased. With this change, operators that erase the page
+always call erasepage at the interpreter level rather than calling
+gs_erasepage directly.
+
+Library
+-------
+
+Fixes bugs:
+ - The null device allowed its size to be reset.
+ - clippath didn't establish a current point if the clipping
+path was empty.
+* - The Type 1 font interpreter (gs_type1_interpret) flattened
+curves even if it was being invoked for charpath.
+ - Colored halftones usually didn't come out with the correct
+phase, and had several other problems.
+ - A show or charpath within a BuildChar procedure didn't work.
+ - Accented characters composed with seac used the base
+character width instead of the composed character width. (The Adobe
+documentation says these must be the same, but some commercial fonts
+don't obey this.)
+ - setcurrentpoint in the accent of a character composed with
+seac didn't take the accent's displacement into account.
+
+Adds an alpha (coverage) value to the graphics state, and
+gs_setalpha/currentalpha procedures. Currently Ghostscript just passes
+the alpha value to the driver; it doesn't attempt to emulate alpha
+handling if the driver doesn't support it.
+
+Redefines gs_erasepage to call gs_fillpage.
+
+Bypasses the fill code if the clipping box is empty. This makes a big
+difference for stringwidth, and doesn't hurt anything else.
+
+Changes frac_1 from 0x7fff to 0x7ff8. This allows exact representation of
+practically all useful fractions, since this number (32760) is
+2*2*2*3*3*5*7*13.
+
+Changes float to double in several matrix routines for better accuracy.
+
+Adds new device properties to implement the deviceinfo operator:
+Colors, GrayValues, RedValues, GreenValues, BlueValues, ColorValues.
+Also adds HWBitsPerPixel and HWColorMap.
+
+Changes the sorting algorithm for halftones to use qsort instead of
+special code.
+
+Changes the Type 1 interpreter so that it uses the current point, rather
+than (0,0), as the character origin.
+
+Version 2.7-beta (9/20/93, not distributed to the public)
+================
+
+This is the first of a series of beta-only versions planned for release
+between 2.6.n and 3.0. This version, in particular, was created to
+satisfy a contractual requirement, and will never be distributed to anyone
+other than the other party to the contract.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The "HP XLFD extensions" to X11R5 are not specific to H-P
+platforms.
+ - The configuration generation script used rm rather than rm -f.
+ - gs.1 was installed in $(docdir) rather than $(mandir);
+$(mandir) wasn't defined.
+ - ansi2knr.1 was installed in $(docdir), which was
+inappropriate because ansi2knr itself wasn't installed anywhere.
+
+Moves documentation for versions 2.4.x and 2.5.x to history.doc.
+
+Moves the documentation on how to add devices to the configuration
+from devs.mak to make.doc.
+
+Changes the name of readme.doc to current.doc, since the presence of
+two "readme" files was confusing to users.
+
+Documents how to use the Microsoft Windows PostScript printer driver
+to convert TrueType fonts to Type 1 fonts embedded in the document.
+
+Corrects several errors in the documentation of the get_bits driver
+procedure.
+
+Documents the fact that X11R3 is no longer supported.
+
+Removes the last references to "Ghostscript" from the comments in the
+gs_*.ps files. The only remaining reference, other than the boilerplate
+comments at the beginning of each file, is in the message at the end of
+gs_init.ps.
+
+Documents the use of WMAKEL rather than WMAKE with the Watcom compiler.
+
+Procedures
+----------
+
+Fixes bugs:
+* - The Unix install script used gs rather than $(GS) as the name of
+the executable.
+* - The Unix install script didn't copy gs_dbt_e.ps to $(gsdatadir).
+ - genconf.c used ps2 as a variable name; ps2 is a predefined
+preprocessor symbol in the VSC compiler used by IBM.
+ - @-expansion didn't interact properly with -- and -+.
+ - The Unix install script didn't copy COPYING to $(docdir),
+and copied README to $(gsdatadir) rather than $(docdir).
+ - ps2ascii used /bin/sh -f, which is an incorrect flag.
+
+Removes all uses and mentions of USG (a now-obsolete GNU convention)
+as a synonym for SYSV.
+
+Removes filter.dev and dps.dev from FEATURE_DEVS if level2.dev is
+included, since they don't add anything beyond level2.dev.
+
+Changes the ccgs script to explictly remove the old .o file before
+doing the mv, for the benefit of people who have changed mv to prompt
+before overwriting. Changes the configuration script to use rm -f
+for the same reason.
+
+Changes the -Z switch so an empty list of options does nothing, rather
+than turning on all options.
+
+Adds a -@ switch which is like -- and -+ except that it does
+@-expansion of arguments.
+
+Changes genconf so it takes patterns from the command line that describe
+how to write the linker control files, rather than having the patterns
+built in.
+
+Changes -d and -D so that if no value is supplied, the default is
+true rather than null.
+
+Utilities
+---------
+
+Fixes bugs:
+* - The ps2ascii script still referenced ps2ascii.ps under its
+old name gs_2asc.ps.
+* - ps2image.ps had a 'pop' missing in the written-out
+definition of 'max' in the boilerplate code it put at the beginning
+of compressed files.
+* - ps2image.ps got a typecheck if a scan line had no repeated
+data in it anywhere.
+ - wrfont.ps didn't handle CharStrings or Subrs that weren't
+strings.
+ - mergeini.ps produced an init file that incorrectly
+attempted to load the Symbol and Dingbats encodings dynamically.
+
+Removes the gsview.bat file, since it was confusingly named and not
+generally useful.
+
+Changes bdftops back to using encrypted CharStrings, for compatibility
+with Adobe interpreters, but also changes lenIV to 0, to save a little
+more space.
+
+Changes the traceop utility so it makes traced operators appear to be
+operators, and so it will replace a definition in systemdict if explicitly
+requested to do so and systemdict is writable.
+
+Adds a printafm utility for printing the metrics of fonts in AFM format.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The cdj driver was missing a few type casts that were needed to
+satisfy pedantic compilers.
+ - For banded devices, many of the non-displaying target routines
+were getting called with the original device as the first argument, not
+the target device. (This didn't make any difference in practice, because
+gdev_prn_open explicitly copied the non-rendering procedures back into the
+procedure vector.)
+* - The X driver didn't catch and discard bogus errors on
+XFreeColors, which faulty servers generate.
+* - The X driver gave up on color allocation too easily.
+* - The X driver dynamic color table size could become negative.
+* - x_lookup_font could return platform fonts of very small sizes,
+which have very inaccurate metrics.
+* - The ESCP/2 driver was incorrectly named gdevescp2 in devs.mak.
+ - The Apple DMP driver used #if 0 / #endif instead of comment
+brackets, and was incorrectly named "dmp" instead of "appledmp" in
+the source code.
+* - The X driver didn't free dynamic colors at the start of each page.
+* - The X driver didn't bind foreground/background defaults tightly.
+* - The X driver didn't check for GHOSTVIEW_COLORS properly.
+* - The X driver freed too many colors if an allocation request failed.
+* - The X driver didn't check return value of gs_malloc for being NULL.
+* - The DeskJet/LaserJet driver used an incorrect command for
+end-of-page.
+* - The DeskJet/LaserJet driver incorrectly reset the printer at the
+beginning of every page.
+* - The PCX driver put an old version number in the header, and
+didn't pad scan lines to an even number of bytes.
+ - The BMP driver used a variable named `quad', which is a
+reserved word on some platforms.
+* - The TIFF driver didn't handle A4 or B4 size paper correctly.
+* - The X11 driver incorrectly demanded the Xmu library, which was
+not needed and which caused link errors on some versions of SunOS.
+* - X11 font matching scheme was too loose, causing overlaps and
+other problems.
+* - X11 Font Extensions (rotated and mirrored fonts) did not work
+properly on NCD terminals.
+* - When freeing the rgb cube/gray ramp, the parameters to gs_free()
+did not exactly match the parameters to gs_malloc().
+* - Ghostscript failed to warn the user when it could not allocate
+the original color cube/gray ramp and dropped back to a smaller
+cube/ramp, or from color to mono.
+* - x_release could cause Ghostscript to fail if a font was freed
+after the device was closed.
+ - The X driver continued to ask the server for colors even after a
+request failed, causing colored images to display very slowly.
+
+* Adds a pcxgray driver to provide 8-bit gray scale output in PCX format.
+
+Adds a pcx24b driver to provide 24-bit RGB color PCX output.
+
+* Adds a LaserJet 4 driver.
+
+Adds a user-contributed driver for the DEC LA70 (very similar to the LA75).
+
+Substantially improves the performance of the PxM drivers by eliminating
+an unnecessary copying step and by writing each scan line with a single
+fwrite when possible.
+
+Moves the gray-scale and 24-bit RGB device color mapping routines to
+gxcmap.c from gdevpcx.c and (nowhere).
+
+Allows window granularities smaller than 64K in the VESA driver.
+
+Changes the LaserJet margins again.
+
+Platforms
+---------
+
+Fixes bugs:
+ - Platforms where stat doesn't return a st_blocks value
+computed the block count wrong.
+ - In gp_vms.c, the call on SYS$FILESCAN needed two uint *s
+rather than a long * and a struct *.
+* - The VMS script files referenced IBSCAN instead of ISCAN2,
+and omitted GDEVXXF.
+* - The UUENCODEd icons for the MS Windows platform were omitted
+from the fileset.
+* - On MS-DOS systems, filenameforall didn't interpret * alone
+as a pattern matching all files.
+
+Adds wildcard matching capability to filenameforall under Unix.
+
+Removes gp_file_status from the platform interface, since all
+platforms provide identical stat calls in the C library.
+
+Adds DesqView/X (using djgcc and go32) as a platform.
+
+Removes the S3 driver from the standard PC configurations.
+
+Adds documentation for compiling Ghostscript on the Intergraph Clipper.
+
+Updates the documentation to add a better list of X Windows font
+names for the Sun platform.
+
+Fonts
+-----
+
+Creates an external file (gs_dbt_e.ps) with the ZapfDingbats encoding
+(actually in 2.6.1, but not documented there).
+
+Changes the names of the Cyrillic fonts to Shareware-Cyrillic-Regular
+and Shareware-Cyrillic-Italic, keeping Cyrillic, Cyrillic-Regular,
+and Cyrillic-Italic as aliases.
+
+* Removes the requirement that the FontName in the font file be the same
+as the name in Fontmap. (This requirement led to the need for aliases,
+and was extremely confusing to users.)
+
+* Adds a GS_FONTPATH environment variable containing a list of directories
+that should be scanned automatically for fonts.
+
+* Gets rid of the Ugly font, and changes the default to the IBM Courier
+font, which is freely distributable.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - cvs didn't check for stack underflow.
+* - zht2.c didn't include alloc.h.
+* - execstackoverflow cleared the e-stack instead of just
+cutting it back.
+ - if and ifelse incorrectly reported typecheck instead of
+stackunderflow.
+ - Copying a dictionary could alter some items even if a later
+item causes an invalidaccess error because of an attempted store of a
+local object into global VM.
+ - bitshift and cvrs assumed that longs occupied 32 bits.
+* - exitserver didn't check the password, and always succeeded.
+ - Font loading didn't suppress all output messages if QUIET
+was set.
+* - The interpreter incorrectly pushed its exit procedure on
+the e-stack if it was called again after an interrupt.
+* - The interpreter didn't treat timeout like interrupt in
+terms of re-executing the current operation.
+* - `show' operators popped their operands before they were
+sure they wouldn't be interrupted.
+* - rotate with a matrix operand didn't check for multiples of
+90 degrees.
+ - In the system name table, ge was misspelled eg, and
+pathforall was misspelled pathfoall.
+* - file_close_file attempted to free the buffer even if it was an
+externally supplied string (specifically, the argument of gs_run_string).
+ - setprintername (in gs_statd.ps) set printername rather than
+.printername.
+
+Implements additional Level 2 features:
+ - Indexed color space with lookup procedure.
+ - sethalftone, except for the transfer function override,
+ and currenthalftone.
+
+Implements OtherSubrs for indices greater than 3 (required for
+MultiMaster fonts).
+
+Implements black generation and undercolor removal.
+
+Changes `store' from a C procedure to a PostScript procedure.
+
+Changes idiv back so it requires integer operands, per the Adobe
+documentation but not per some old Adobe interpreters.
+
+* Adds many new paper sizes to gs_statd.ps. It now includes ISO a0-a10
+and b0-b10, and CAD sizes archA-archE.
+
+Implements `status' for non-%os% files. (This is currently a no-op,
+but the framework is there.)
+
+Changes the error handler so it normally uses = rather than == to print
+the operand stack, to avoid recursive errors.
+
+* Adds time slicing capability to the interpreter.
+
+Implements setcolorscreen/currentcolorscreen.
+
+Library
+-------
+
+Fixes bugs:
+* - Rectangles with vertices specified in clockwise order were
+drawn as 0-width lines.
+* - The string matching function reported that 'abcdefg'
+matched the pattern 'abcde'.
+* - The bounding box of non-rectangular clipping paths was not
+being marked as valid, so cached characters would simply get
+discarded as being outside the bounding box.
+ - erasepage filled the page with the device's white color,
+not with gray level 1 passed through the transfer function.
+* - Colors with equal R/G/B or C/M/Y components were rendered
+incorrectly if the 3 or 4 transfer functions were not all the same.
+* - Because of a bug in rc_unshare, using CIE color would give
+random errors (such as /invalidaccess in --for--).
+* - setbbox didn't round the coordinates properly, which could
+cause erroneous rangecheck errors with coordinates on the edge of the
+box.
+* - Color halftones "flipped over" at the 50% point, inverting
+foreground and background.
+ - Quite a few places assumed that longs occupied 32 bits.
+* - kshow passed an incorrect c1 value to the procedure.
+ - The debugging code in update_x_list in gxfill.c didn't take
+into account the possibility that the active line at x_first might be
+deleted.
+ - gx_image_cached_char called the xfont render_char procedure an
+extra time if it failed with required=0 and succeeded with required=1.
+(This was just a small inefficiency, not a logic bug.)
+ - Non-rectangular clipping regions weren't computed correctly,
+because accum_add_rect didn't handle overlapping rectangles.
+ - Drivers didn't report file system errors (such as file system
+full) as an ioerror.
+* - setdevice didn't reset the charpath and setcachedevice flags.
+ - The Zortech compiler produced wrong code for the uid_equal
+macro; uid_equal is now a procedure.
+
+Passes OtherSubrs arguments back to the caller correctly for indices
+greater than 3.
+
+Implements black generation and undercolor removal.
+
+Removes gdev_mem_ensure_byte_order, which was no longer used or useful.
+
+Removes gstdev.c (device tracing), since it hasn't been used in a
+long time and is of little value given a reasonable debugger.
+
+Changes the interface to the xfont char_metrics and render_char
+procedures to allow them to return 1.
+
+Changes 32-bit memory devices so they use CMYK color mapping rather
+than RGB mapping with an unused byte.
+
+Implements gs_setcolorscreen/currentcolorscreen.
+
+Implements Level 2 halftones, except for the transfer function override.
+
+Implements a hack to make zero-width rectangles display as one pixel wide,
+to work around a bug in the Microsoft Windows PostScript driver.
+Currently the hack only works for vertical lines, not horizontal ones.
+
+Version 2.6.1 (5/28/93)
+=============
+
+This is primarily a bug-fix release for 2.6, with a couple of minor
+additions.
+
+Documentation
+-------------
+
+Adds proper `man' pages ansi2knr.1 and gs.1.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The Unix makefile produced an incorrect linker command if
+EXTRALIBS was not empty.
+ - The Unix install commands didn't copy devices.doc,
+ps2epsi.doc, and xfonts.doc to the documentation directory.
+ - echogs.c didn't include <sys/types.h>, which is needed for
+time_t on some systems.
+ - malloc_.h used <malloc.h> rather than <stdlib.h> on
+NeXTStep systems.
+
+Changes the configuration procedure to use a C program rather than
+complex shell scripts.
+
+Utilities
+---------
+
+Fixes bugs:
+ - The boilerplate produced by ps2image used the 'max'
+operator, which is not a standard PostScript operator.
+ - The winmaps.ps utility had 'floring' instead of 'florin' in
+the OEMEncoding table.
+ - quit.ps was omitted from the PC distribution.
+
+Changes the name of the dicttomark procedure to .dicttomark.
+
+Renames gs_2asc.ps as ps2ascii.ps, so it matches the names of the
+script files.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The pbmraw driver was writing out RGG instead of RGB values.
+ - The X11 driver used NULL in a place where it should have
+used None.
+ - For multi-file output, the GIF driver didn't write a header
+at the beginning of each file.
+ - The Epson driver didn't honor the -A4 compilation switch,
+didn't put (0,0) at the physical corner of the page, and was too
+liberal about using tabs instead of spaces.
+
+Replaces the color handling algorithms in the X Windows driver with
+new, much better ones.
+
+Makes the PC display drivers recognize the -A4 compilation switch,
+like the printer drivers.
+
+Adds new user-contributed drivers:
+ - A driver for Epson printers that use the ESC/P 2 control
+language, such as the Stylus 800.
+ - A driver for the Apple Dot Matrix Printer and Imagewriter.
+
+Adds a new get_xfont_device driver procedure. This is a
+backward-compatible change, since there is a sensible default.
+
+Platforms
+---------
+
+Fixes bugs:
+ - On VMS, gconfig.h didn't have #include "gsconfig.h" as its
+first line.
+ - gconfig.c compiled incorrectly on the RS/6000 because the
+compiler evaluated a constant of the form (x<<y)+z incorrectly.
+ - Quite a few files that used the mem... functions didn't
+include memory_.h, which caused trouble on some bsd4.2 systems.
+ - The definition of zfont_char_xglyph confused one of the AIX
+compilers.
+ - On VMS, DEC C allows extra arguments for fopen, but gcc doesn't.
+ - On the MS Windows platform, 2.6 used gdevwddb rather than
+gdevwdib; the latter is almost always faster.
+ - The PC .zip files didn't include the Windows .ICO and .RES
+files in either GSEXE.ZIP or GSFILES.ZIP.
+
+On PC platforms, adds an option (FPU_TYPE=-1) to optimize for
+machines lacking a floating point processor.
+
+Fonts
+-----
+
+Adds 4 new fonts contributed by URW. These have a URW copyright and
+are governed by the GNU License.
+
+Documents the fact that font names in Fontmap can be strings, not
+only names.
+
+Adds DingbatsEncoding as a predefined encoding (in addition to
+Standard, ISOLatin1, and Symbol).
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - memchr (used in zfile.c) isn't available on all platforms.
+ - languagelevel was defined as an operator rather than an
+integer.
+ - iccfont.c referred to name_StandardEncoding instead of
+#include'ing font.h and referring just to StandardEncoding.
+ - The CCITTFaxDecode filter didn't work on 32- (or 64-) bit
+machines, because of a bug in more_bits().
+ - The structures recording an allocation within the scope of
+a save could get allocated unnecessarily, because they weren't
+properly marked as free when an array was freed.
+
+Renames the following Ghostscript-specific operators by adding a '.'
+at the front: makeoperator, setdebug, setmaxlength, stringmatch,
+type1decrypt, type1encrypt.
+
+Adds a real implementation of glyphshow.
+
+Library
+-------
+
+Fixes bugs:
+ - Discarding fractional character coordinates in the Type 1
+rasterizer led to some rendering anomalies (e.g., characters 1 pixel
+too high).
+ - If a font had a non-standard encoding (i.e., not
+StandardEncoding, ISOLatin1Encoding, or SymbolEncoding), Ghostscript
+would never invoke the platform font code.
+ - The RGB to HSB color conversion algorithms produced
+nonsensical values.
+ - struct cached_char_s was defined redundantly in gxcdir.h,
+causing compilation problems on some systems.
+ - 32-bit color devices didn't work properly on little-endian
+machines (arrange_bytes in gdevmem2 was wrong).
+ - The scaled font cache could confuse two fonts with the same
+UniqueID and different Encodings.
+ - Under many common circumstances (first use of a character
+was with stringwidth, the font was renamed, the font encoding was
+changed), xfonts would not be used.
+
+Adds gs_glyphshow.
+
+Version 2.6 (5/9/93)
+===========
+
+The main new feature in this release is the ability to use platform
+fonts. It also adds many more Level 2 PostScript facilities.
+
+Documentation
+-------------
+
+Corrects some errors in the documentation of the makeimagedevice operator.
+
+Adds operand and result types to the comments at the beginning of all the
+operators.
+
+Adds new sections on installation in use.doc.
+
+Reinstates history.doc as a repository for old and no longer interesting
+history information.
+
+Adds a new file, devices.doc, with documentation for specific devices.
+
+Points out that font2c must be run with a Fontmap that includes the fonts
+being converted, and that its arguments must be quoted with "" on VMS
+systems.
+
+Notes that the font name in the Fontmap must be the same as the FontName
+in the font.
+
+Adds a list of the Level 2 facilities not provided by Ghostscript.
+
+Identifies bug-ghostscript@prep.ai.mit.edu as an alias for the
+gnu.ghostscript.bug newsgroup.
+
+Points out explicitly that -sOutputFile=- sends output to stdout, and
+requires using the -q switch.
+
+Documents the use of tar_cat to construct the Unix makefiles.
+
+Adds a new file, xfonts.doc, that describes the external font interface.
+
+Documents the fact that drivers must use gs_malloc and gs_free rather than
+malloc and free.
+
+Documents the *.sh (shell script) files.
+
+Adds brief documentation on some additional development tool .ps files.
+
+Documents the TEMP and GS_OPTIONS environment variable.
+
+Points out the need to run Windows in 386 Enhanced mode on machines
+that have less than 6 Mb of RAM.
+
+Consolidates documentation on compiler switches in make.doc (some of
+it had been in the unix*.mak files).
+
+Procedures
+----------
+
+Fixes bugs:
+ - \'s in arguments following -- were doubled.
+
+Includes the full set of filters automatically if the level2 feature
+is selected.
+
+Extends DEVICE_DEVS... up to DEVS9. Adds DEVICE_DEVS1 as well.
+
+Renames turboc.mak and tbcplus.mak as tc.mak and bc.mak.
+
+Makes @-files use the library path (GS_LIB, -I).
+
+Changed the Unix install script to use install <file> <destfile>
+rather than install <file> <directory>.
+
+Adds a GS_OPTIONS environment variable that acts like an implicit @-file
+at the beginning of the command line (i.e., may contain switches and
+initialization files).
+
+Renames sym__enc.ps as gs_sym_e.ps.
+
+Adds a user-contributed shell script for using Ghostscript with an
+H-P printer spooler.
+
+Adds level1.ps to the set of installed utility files.
+
+Extends the TEMP environment variable (the directory for scratch
+files) to work on Unix as well as MS-DOS.
+
+Changes the MS Windows makefile to generate gswin.exe rather than
+gs.exe, and the Watcom makefile to generate gs386.exe.
+
+Moves the "product" string from gs_init.ps to iinit.c.
+
+Adds a GS macro to the makefiles, to allow choosing the name of the
+executable.
+
+Utilities
+---------
+
+Fixes bugs:
+* - font2c did the wrong thing (still) for fonts that didn't
+use StandardEncoding, ISOLatin1Encoding, or SymbolEncoding.
+* - impath.ps had a fatal bug (wrong operand order for
+charstack_write) that caused bdftops to fail.
+ - gslp didn't wrap or truncate lines.
+ - gslp didn't handle tabs in a second or subsequent column
+properly.
+ - The definition of ashow in gs_2asc.ps incorrectly undid the
+increment following the last character.
+ - The definition of awidthshow in gs_2asc.ps failed to pop
+two entries from the stack, and also tested the character against the
+wrong value.
+
+Adds a shell script (sysvlp.sh) that interfaces Ghostscript with the
+System V 3.2 lp interface.
+
+Adds ps2ascii and ps2epsi script/batch files.
+
+Adds a new utility, mergeini.ps, for concatenating all the
+Ghostscript initialization files into a single file, optionally
+removing comments and blank lines.
+
+Adds new switches to gslp:
+ -q: suppress all printed output.
+ --detect: check whether the file begins with %!, and if so,
+ interpret it directly as a PostScript file.
+ --first-page <page#>: replaces the former -P switch.
+ --last-page <page#>: replaces the former -Q switch.
+ --(heading|footing)-(left|center|right) <string>: define
+ headers/footers. # inserts the page number.
+ --margin-(top|bottom|left|right) <inches>: define margins.
+ --spacing <n>: for double, triple, etc. spacing.
+Also makes gslp ignore all the enscript flags it doesn't implement.
+
+Adds an option to wrfont.ps to do encryption at read-in time. (This
+allows much better compression of the standard Ghostscript fonts.)
+Changes bdftops to use this option.
+
+Changes gslp to accept wild cards in file names.
+
+Replaces landscap.ps with a new one contributed by a user.
+
+Changes the compression scheme used in ps2image to a much more
+effective one. Writing images is much slower than with the previous
+scheme, but reading is not.
+
+Platforms
+---------
+
+Fixes bugs:
+ - SCFDTAB and SCFTAB were omitted from the VMS module lists.
+ - Function prototypes were not being used with the Watcom
+compiler.
+ - On MS-DOS platforms, if the value of the TEMP variable had
+a trailing : or \, Ghostscript appended a \ anyway.
+ - Under Windows, changing the size or resolution of the image
+closed and reopened the window.
+ - Ghostscript would not build correctly with the Watcom compiler
+if DOS4G=quiet was not set, because the DOS4GW copyright message was sent
+to stdout.
+* - Finally gets Ghostscript to run properly on the RS/6000, by
+adding a compiler bug workaround to arc_add and arc_either.
+* - Finally gets Ghostscript to compile properly on Sun SPARC
+systems, by adding a compiler bug workaround in scan_number.
+
+Changes the default MS-DOS configuration from 8086/8088 to 80286.
+
+Adds all the SuperVGA drivers to the BC++ and Watcom executables
+(except for the VESA driver in the Watcom executable).
+
+Adds a makefile (msc.mak) for the Microsoft C/C++ 7.0 platform. This
+is currently a MS-DOS, not a MS Windows, platform.
+
+Changes gp_enumerate_files_init so it takes a gs_memory_procs *, not
+separate proc_alloc_t and proc_free_t arguments; also, it must
+enumerate precisely the requested set of files, not a superset. THIS
+IS A NON-BACKWARD-COMPATIBLE CHANGE. It affects all gp_*.c files.
+
+Adds the P*M drivers and bit.dev to the standard configuration on
+Unix platforms.
+
+Changes the Watcom makefile so it uses the WATCOM environment variable (by
+default) as the base directory for the Watcom executables.
+
+Adds the MS Windows COMMDLG.DLL and SHELL.DLL files to the set of
+files incorporated in GSEXE.ZIP, since the new MS Windows code uses
+them, and they aren't provided with Windows 3.0.
+
+Makes major revisions to the MS Windows platform and driver code, to
+support the gsview front end, and also to remove the dependence on the
+Borland EasyWin library. NOTE: Compiling the MS Windows code now requires
+Borland C++ 3.1 (not 3.0).
+
+Changes time_.h so that Ghostscript will compile and run on A/UX.
+
+Changes the MS-DOS implementation of file enumeration so it always
+treats \s in the file name as literal characters, not escapes, unless
+there are two \\s in a row. This does the most sensible thing given
+the DOS file naming conventions.
+
+Adds a %pipe% file device under Unix.
+
+Adds a makefile for Watcom C under MS Windows. This is very preliminary;
+in particular, NO display output is supported.
+
+Fonts
+-----
+
+Fixes bugs:
+ - fonts.mak referred to ncri and puti rather than ncrri and
+putri.
+ - cyr and cyri had the wrong protection.
+ - The Hershey fonts left the font on the stack when they were
+loaded.
+* - The FontName of an aliased font was the original FontName
+from the file, not the alias.
+* - Fontmap.BTS had incorrect entries for AvantGarde-Demi and
+AvantGarde-DemiOblique.
+ - Ghostscript pushed userdict, rather than an empty writable
+dictionary, onto the stack when loading a font, leading to name clashes.
+
+Adds a new cfonts.mak with a full set of rules for compiling all the
+standard Ghostscript fonts (except the Hershey fonts) into C.
+
+Adds UniqueIDs to the Hershey fonts, and removes the UniqueIDs from
+the Hershey entries in the Fontmap.
+
+Adds a new Fontmap for VAX/VMS with DECWindows/Motif.
+
+Changes MakeHersheyFont so it takes the encoding as an additional
+parameter, and changes the Hershey-Symbol font to use SymbolEncoding.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The !@*&^%#@$ PCL drivers *still* didn't do the right thing
+about vertical spacing: the <ESC>*p+<n>Y command works on all PCL 3,
+4, and 5 printers *except* the LaserJet IIp.
+ - The cdj driver used recursive macros (height, t_margin,
+b_margin) that not all compilers handled correctly.
+ - The djtc driver used some assignments including =*, which
+some compilers dislike.
+ - The S3 driver wouldn't compile correctly with the Watcom
+compiler.
+ - The makefile entry for the S3 driver was wrong.
+ - The SuperVGA drivers returned an error, rather than using
+the highest available resolution, if a too-high resolution was
+requested.
+ - The GIF driver produced an incorrect header for images
+wider or taller than 32K pixels.
+ - The GIF driver wasn't able to handle multi-page documents
+correctly.
+ - The margins on the DeskJet were still not correct.
+ - Some ANSI C compilers rejected a complex expression in
+gdevpccm.c.
+ - Printer drivers didn't recover cleanly from problems in
+opening the scratch files.
+ - The BJ-10e driver used the same name `out' for a label and
+a variable.
+ - The SCO ODT compiler couldn't handle sizeof(ppdev->fname).
+ - The Epson driver used the wrong value for ESC in the
+initialization string.
+
+Adds new drivers:
+ - Drivers to produce MS Windows .BMP format output.
+ - A new ATI Wonder display driver (800x600, 16 colors) and a
+1024x768 mode for the existing driver.
+
+Adds new user-contributed drivers:
+ - A driver for the Tektronix 4693d color printer. This carries a
+university copyright.
+ - A driver for the SPARCprinter.
+ - A driver for the Canon BJ200 printer.
+ - A driver for the IBM ProPrinter.
+ - A driver for the DEC LJ250 printer, which has a
+PaintJet-compatible mode.
+ - A replacement driver for the Sony NWP533.
+ - A driver that writes TIFF/F (Group 3 fax) files. This carries
+an external copyright.
+ - A driver for the C.Itoh M8510 printer.
+ - A driver for the Okidata MicroLine 182 9-pin dot-matrix printer.
+ - A Hercules Graphics driver.
+ - A driver for printers under MS Windows.
+ - A driver for direct frame buffer addressing under SCO Unix
+and Xenix and AT&T SVR4.
+
+Changes the get_bits driver procedure so it always reads a single
+scan line, and optionally does not copy the data. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE. However, this change does not affect
+any existing printer driver, since these all go through intermediate
+routines in gdevprn.c.
+
+Changes gdevprn.h, and the relevant printer drivers, so that -DA4
+will change the default paper size for any printer driver.
+
+Allows the use of NULL or 0 for default procedures in the driver
+procedure vector.
+
+Adds an optional map_cmyk_color procedure to the driver procedure
+vector.
+
+Changes the Epson driver so that the minimum amount of white space
+required to use a tab is an easily changed parameter.
+
+Changes the BGI driver to use separate segments for the Borland
+device drivers, to reduce the risk of overflowing a segment.
+
+Adds an optimization option (normally enabled) to the PGM and PPM drivers
+such that they revert to PBM or (for PPM) PGM if the page can be
+represented that way.
+
+Adds a new (optional) driver procedure to get the procedure vector
+for external fonts.
+
+Adds an argument to gp_open_printer to indicate whether the file should be
+opened in binary or text mode. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE.
+However, this change does not affect any existing printer driver, since
+these all go through intermediate routines in gdevprn.c.
+
+Changes the LN03/LA50/LA75 driver so it uses a text record mode to open
+the output file under VMS (by adding an argument to gp_open_printer to
+indicate this.)
+
+Allows (indeed, encourages) drivers to use far_data to declare the device
+structure, primarily to avoid overflowing the 64K data segment under MS
+Windows. Changes the file output drivers and many of the printer drivers
+to declare their device structures as far_data.
+
+Replaces the AT&T 3B1 driver with an updated version (from the same
+contributor).
+
+Changes the Epson BJ driver and the SPARCprinter driver so they align
+the (0,0) point of the page with the physical corner of the paper
+rather than with the origin of the printable area.
+
+Removes the EIZO MDB-10 driver, since it caused complications for the
+EGA and VGA drivers and is not a widely used device.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The entry for the copydevice operator in the operator table
+was initialized incorrectly.
+ - printobject and writeobject didn't handle nested arrays.
+ - restore didn't properly close the current file (if
+appropriate), causing an invalidaccess error.
+ - buildfont required the presence of a valid, 4-element
+FontBBox. (The Red Books say it's required, but Adobe interpreters
+don't require it; some DEC software generates a 3-element FontBBox.)
+ - resourceforall had several bugs; it didn't do even
+approximately the right thing. There were quite a few other problems
+with the implementation of resources.
+ - setfont, makefont, and scalefont would accept a font with
+no FID entry.
+* - Loading a .PFB font left the file open (until the next
+restore or quit).
+ - The default (null) font didn't include a PaintType entry,
+which some PostScript files expected.
+* - The ASCIIHexDecode filter sometimes thought the underlying
+stream was at EOF even when there was (at most one buffer's worth of)
+data left.
+ - iscan.c included <ctype.h> before std.h, causing type name
+clashes on some systems.
+* - save and restore didn't handle the pointers in the graphics
+state correctly; for example, the current font wasn't restored
+properly.
+ - Binary object sequences at the top interpreter level didn't
+get executed immediately.
+ - On high-resolution devices, the default transfer function
+converted almost-white grays to very light grays rather than white.
+ - The `string' operator was checking the string length
+against max_uint rather than max_ushort, which could cause invalid
+lengths to be accepted.
+* - deviceinfo caused a stackunderflow error.
+* - idiv could give incorrect results for quotients or
+remainders that didn't fit in 24 bits.
+* - The ASCII85Encode filter padded trailing bytes with 1's
+rather than 0's.
+* - The ASCII85Decode filter had a typo that produced incorrect
+results if there were exactly 2 trailing bytes.
+ - findlibfile didn't push a copy of the file name if it was
+the name of a special (%) file.
+ - setduplexmode was not defined in statusdict, causing
+/undefined errors from some poorly designed input files.
+* - The CCITTFaxDecode filter had several bugs in 2-D decoding.
+* - The ASCII85Decode filter didn't read ahead to detect EOD if
+it fell precisely on a buffer boundary.
+ - If a file mentioned on the command line redefined `start',
+Ghostscript would run the new definition rather than the built-in one
+after processing all the files on the command line.
+ - The SCO ODT compiler couldn't handle the conditionals in the
+ngetc (iscan.c) and sgetc* (stream.h) macros.
+ - makefont and scalefont didn't cache the PostScript dictionaries
+for scaled fonts.
+ - Changing the elements of the Encoding of a font dynamically
+didn't take effect if the character was already cached.
+ - makefont and scalefont didn't add the (undocumented) OrigFont
+and ScaleMatrix entries to the new font.
+* - findfont insisted that the font name be a string or a name.
+ - filenameforall could cause an incorrect transfer of control
+if no files matched the pattern.
+* - ISOLatin1Encoding had hyphen instead of minus at code 45.
+ - restore didn't reset saved_cbot and saved_ctop correctly;
+as a result, some freed blocks could get abandoned rather than put on
+the free list.
+ - Some numerical constants in zarith.c assumed that longs
+occupied 32 bits.
+
+Implements additional Level 2 features:
+ - %device%file names (only the "os" device is provided).
+ - <~ ~> for ASCII-85 strings.
+ - Binary error messages.
+ - BuildGlyph.
+ - CCITTFaxDecode filter entries EndOfBlock, Rows, and
+ (undocumented) FirstBitLowOrder.
+ - {set/current}{color/colorspace/overprint/colorrendering/
+ blackgeneration/undercolorremoval}. (See below under library
+ for limitations.)
+ - Decode for the dictionary form of image.
+ - File access modes a, r/w/a+.
+ - Font entries CDevProc, Metrics2, and WMode.
+ - Font operators cshow, findencoding, rootfont, and
+ setcachedevice2.
+ - glyphshow (emulated with PostScript code).
+ - languagelevel.
+ - realtime.
+ - setbbox.
+ - (Subset of) system and user parameters.
+ - xshow, yshow, and xyshow.
+ - XUIDs for fonts.
+
+Moves the installation of systemdict and the initial allocation of
+globaldict (if relevant) and userdict from gs_init.ps to iinit.c.
+
+Makes Level 2 features dynamically selectable through the
+.setlanguagelevel operator; disables all Level 2 features
+(specifically including automatic dictionary expansion) unless the
+level2 feature is included and active.
+
+Adds the .knownget operator for speeding up system procedures.
+
+Renames the type1addpath operator as .type1addpath; adds an optional
+left side bearing argument; changes it so it does not do the
+setcachedevice, fill, or stroke, but does do a moveto for the
+character width. Changes Type1BuildChar appropriately. (All this is
+needed to make WMode work.)
+
+Removes the .setmetrics operator, which is no longer needed.
+
+* Changes the meaning of the user_errors argument to gs_run_file and
+gs_run_string so that -1 means always return on an error, 0 means
+only return on an error not within a `stopped'.
+
+Adds all the necessary checks and operators for local/global VM, but
+doesn't actually implement local/global mode.
+
+Changes setcachedevice back so that it requires 4 numbers on the
+stack rather than a 4-element array. (It was changed to be the other
+way in release 2.0, but that was because I didn't realize that fonts
+had to have an executable FontBBox, and some of the Ghostscript fonts
+didn't.)
+
+Changes all the filter operators from .filterxxx to .filter_xxx, and
+removes the need to enumerate them in gs_init.ps.
+
+Adds .oserrno and .oserrorstring operators for getting the last OS
+error (in the current context).
+
+Changes gs_finit similarly to gp_exit. Adds gs_exit_with_code that
+takes both an exit status and a Ghostscript error code.
+
+Changes the name of name.h to iname.h.
+
+Adds support for the `interrupt' error (but doesn't provide any standard
+way of generating one, other than through the gp_check_interrupts polling
+function).
+
+Adds copyright to systemdict.
+
+Changes the spot halftone screen to an elliptical screen supplied by
+Berthold K. P. Horn.
+
+Adds a check that the first token in gs_init.ps is an integer. In
+conjunction with other code in gs_init.ps, this should catch all attempts
+to run Ghostscript with a gs_init.ps that doesn't match the executable.
+
+Changes all relevant occurrences of sizeof to size_of in order to
+work with the buggy SVR4.2 C compiler.
+
+Changes gp_exit so it is passed both the Ghostscript error code and
+the exit status code as arguments. This is backward-compatible for
+all but the pickiest compilers.
+
+Adds a call on gp_check_interrupts() after fwrite calls in the stream
+machinery. This prevents lengthy console output from locking out
+other programs.
+
+Changes a couple of occurrences of op_def_ptr in iinit.c to work around a
+`const' bug in Sun's SC1.0 compiler.
+
+Adds a special hack in the 'where' operator to work around a bug in Aldus
+Freehand 2.x.
+
+Changes all empty argument lists from () to (void), which is the ANSI
+C syntax.
+
+Adds a hack to ignore ^[ and ^D^[ tokens, to work around the prologue
+and epilogue emitted by the MS Windows LaserJet IV driver.
+
+Defines the processcolors operator, which should not be needed, but
+is required because of bugs in Lotus 1-2-3 and Adobe PhotoShop.
+
+Changes the allocator (ialloc) to fill all allocated and/or freed
+blocks with a marker if gs_alloc_debug is set, as gs_malloc and
+gs_free already do.
+
+Library
+-------
+
+Fixes bugs:
+ - 16-bit memory devices stored the bytes of each pixel in the
+wrong order.
+ - copy_mono did the wrong thing when copying 1 source chunk
+to 2 destination chunks with polarity inverted. (This probably
+didn't affect any actual uses of Ghostscript.)
+* - The compile-time check for ints being 2 or 4 bytes used the
+#error directive, which most compilers don't recognize.
+ - arc and arcn didn't do the right thing for degenerate
+(single-point) arcs, or for arcs drawn in the "wrong" direction that
+were multiples of 360 degrees.
+ - charpath did the wrong thing with Type 3 fonts.
+ - copyscanlines gave an error if the buffer was too large.
+ - The copy_mono procedure (used for text and halftones) for
+2- and 4-bit-per-pixel memory and printer devices incorrectly
+incremented the destination pointer after every pixel, instead of
+only after every byte.
+ - The fill_rectangle procedure (used for graphics) for 2- and
+4-bit-per-pixel memory and printer devices, if given any color other
+than all 0's or all 1's, multiplied the X coordinate and width by 2
+or 4, thereby filling the wrong area.
+ - The use of 'data' in both gs_type1_data and gs_font upset
+the VMS compiler.
+ - The `Flex' feature wasn't implemented for Type 1 fonts,
+which caused serious errors in rendering some fonts that use it.
+(Unfortunately, some Adobe fonts violate the specification, so we had
+to implement Flex to always use a curve.)
+* - Stem width adjustment was too eager, producing very strange
+effects on small characters with tight curves (a curve point could
+get snapped to the other side of the open area).
+ - The allocator didn't align structures adequately on
+machines where sizeof(long) or sizeof(char *) was 8 bytes.
+ - The test for IEEE floating point gave an incorrect
+(negative) result on machines where sizeof(long) was 8 bytes.
+ - genarch.c assumed that the result of subtracting two
+pointers was an int, leading to a garbage arch.h file on systems
+where this was false.
+* - The Type 1 font interpreter incorrectly reset the adjusted
+path position to be the same as the unadjusted path position whenever
+it returned control to the client (in particular, for callothersubr),
+leading to discontinuities and distortions in the character shapes.
+* - Accented characters in Type 1 fonts often misplaced the
+accent to the left.
+ - gsmisc.c wouldn't compile on machines with 64-bit pointers,
+because _pad was 0, and ANSI compilers don't accept 0-length arrays.
+ - pathforall got confused if the client procedures modified
+the path.
+ - The command list file representation limited X and Y
+coordinates to 15 bits.
+* - stroke could produce spikes or other garbage for mitered
+joins as a result of stroke adjustment.
+ - The params_size field of the null device was wrong, so
+scaling the null device produced unpredictable results.
+
+Changes monobit memory devices to always store data big-endian. This
+eliminates byte-swapping, at the cost of slightly slower rendering.
+
+Removes the memswab* routines, since they are no longer needed.
+
+Implements gs_cshow_[n_]init, which provides support for cshow, and
+gs_xyshow_[n_]init, which provides support for {x,y,xy}show.
+
+Adds an optional left side bearing argument to gs_type1_interpret.
+
+Changes gs_type1_interpret so it does not do a setcachedevice, fill,
+or stroke, but only appends the character outline to the path
+(including a moveto for the character width.)
+
+Removes gs_setmetrics, which is no longer needed.
+
+Implements gs_setcachedevice2, which provides support for
+setcachedevice2.
+
+Speeds up gsave/grestore by allocating, deallocating, and copying as
+much as possible of the graphics state in a single operation.
+
+Implements gs_{set/current}{color/colorspace/overprint/colorrendering/
+blackgeneration/undercolorremoval}. Device, indexed (with table, not
+with procedure), CIE, and (substituted) separation colors are
+supported; some of the setup code for patterns is also present.
+
+Increases the size of temporary file names in gdevprn.h from 30
+characters to 60.
+
+Changes the character cache to be allocated dynamically in chunks.
+
+Splits gxcache.c into gxccache.c (fast "hit" code) and gxccman.c (all
+other code).
+
+Changes all occurrences of sizeof to size_of in order to work with the
+buggy SVR4.2 C compiler.
+
+Adds a new concept of "external fonts", which allow a driver to
+substitute its own fonts for the ones obtained through the normal
+font machinery.
+
+Changes all empty argument lists from () to (void), which is the ANSI
+C syntax.
+
+Version 2.5.2 (9/20/92)
+=============
+
+This is yet another bug fix release to (finally!) get the PCL drivers
+working again.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The comment in devs.mak for cdjcolor said it used 8 bits
+per pixel, rather than the correct 24.
+
+Adds gsbj/dj/lj/lp and gslp.ps to the installed files on Unix
+systems.
+
+Removes dps.dev and level2.dev from the standard configurations on
+all platforms, since the presence of the setcolor operator was
+causing the output of some common applications to fail.
+
+Utilities
+---------
+
+Fixes bugs:
+ - font2c produced invalid output for any font that didn't use
+StandardEncoding or ISOLatin1Encoding.
+
+Platforms
+---------
+
+Fixes bugs:
+ - gp_sysv.c required an extern long timezone.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PCL drivers were *still* doing the wrong thing about
+zeroing the seed row for Mode 3 compression.
+ - Setting the resolution with -r didn't work under Windows.
+ - The Windows driver got a stack overflow if it was ever
+asked to display a bit image wider than 32 pixels.
+ - The Tseng driver didn't sense the model (ET3000 vs. ET4000)
+correctly.
+
+Adds the eps9high device to the standard MS-DOS makefiles.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - gs_run_string used gs_user_errors (a global) rather than
+user_errors (its argument) to control error handling. (This does not
+affect normal operation of Ghostscript, only use as a server.)
+ - eexec popped the top element of the dictionary stack
+afterwards even if the encrypted code had pushed something onto it.
+This caused problems for some badly written PostScript code.
+ - The printed form of real numbers didn't always include a
+decimal point, causing compatibility problems.
+
+Makes -s and -d work for device properties.
+
+Increases the cache limit on large-memory systems.
+
+Adds a check to ensure that the revision of gs_init.ps matches that
+of the interpreter.
+
+Adds the .knownget operator.
+
+Library
+-------
+
+Fixes bugs:
+ - The raster computation in clist_render_init, and the
+computation of state_size in clist_open, didn't widen an operand to
+long, leading to possibly incorrect operation for 24-bit-per-pixel
+printers on MS-DOS systems.
+ - The flatness was set too large for Type 1 characters,
+leading to visible straight edges instead of curves at large sizes.
+ - Type 1 fonts that contained out-of-range coordinates would
+produce garbled output. (This was not a problem with the standard
+Ghostscript fonts, or with Adobe Type Manager fonts.)
+ - gschar0.c wouldn't compile, because it referred to a
+non-existing structure member penum->chr. (This had no effect on
+Ghostscript's operation.)
+ - The curve flattener required line segments to be no more
+than 8 x the flatness in length, leading to an enormous number of
+segments.
+ - pathforall would cause an addressing fault if the path
+consisted of only a moveto.
+
+Refactors some header files so that std.h is always included before
+any system header file that might include sys/types.h.
+
+Adds logic for removing top and bottom blank rows in cached
+characters. (This is the beginning of compression for the cache.)
+
+Changes the arguments of memswab2/4 from char * to byte *, for more
+accurate type conformance.
+
+Version 2.5.1 (9/11/92)
+=============
+
+This is the usual bug fix re-release.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The makefile rules for compiled fonts had a circular
+dependency.
+ - `make begin' didn't work properly on all platforms.
+
+Ensures that all batch files end with a newline. (The absence of the
+newline was confusing the GNU diff program.)
+
+Documents the fact that the -dASCIIOUT switch no longer exists.
+
+Utilities
+---------
+
+Fixes bugs:
+ - pstoppm didn't `bind' its internal procedures.
+ - grestoreall would undo the output device selected by
+pstoppm.
+
+Changes the utilities for reading and writing Type 1 character
+outlines so they can work with stack representations as well as
+arrays.
+
+Removes the pfbtogs.ps, phonbook.ps, and showpbm.ps utilities from
+the distribution.
+
+Adds a gslj utility to parallel gslp and gsdj.
+
+Platforms
+---------
+
+Adds the DeskJet 500C drivers (cdeskjet/cdj*) to the MS-DOS / Borland
+C++, MS-DOS / Watcom C/386, and MS-Windows configurations.
+
+Removes the PCX file driver from the MS Windows executable, because
+the static data segment exceeded 64K.
+
+Makes some changes in the Unix System V platform file (gp_sysv.c) and
+in time_.h and unixtail.mak to accommodate the 3B1.
+
+Fonts
+-----
+
+Fixes bugs:
+ - The Charter-Italic font was named bchi.pfa rather than
+bchri.pfa.
+ - The Cyrillic fonts (cyr.gsf, cyri.gsf) were omitted from
+the fileset.
+ - Ghostscript incorrectly assumed that all Type 1 fonts had a
+FontInfo dictionary.
+ - .loadfont used false PFBDecode, so a few .PFB fonts would
+get errors because the first eexec byte would be whitespace.
+
+Changes font2c and its supporting code so that compiled fonts are
+location-independent.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The margins for the H-P printers were still wrong.
+ - The H-P drivers accidentally cleared the compression seed
+row when switching compression modes.
+ - Some of the H-P drivers used the wrong control codes for
+skipping blank lines.
+
+Adds user-supported drivers for the AT&T 3B1 console device, and for
+the NEC P6+ printer.
+
+Updates the SunView driver with a new version supplied by a(nother)
+user.
+
+Changes the X Windows driver so the Ghostscript window doesn't get
+input focus.
+
+Changes the common code for the printer drivers so that if it can
+allocate a full bitmap but there isn't at least a minimum amount of
+memory left afterwards, it switches to banding.
+
+Changes the Windows driver so it handles devices with more than 8
+bits per pixel. (We haven't been able to test this.)
+
+Adds a read-only PageCount device property (for printer devices
+only).
+
+Changes all Aladdin-supported drivers to clip drawing requests to the
+((0,0), (width,height)) rectangle of device space.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Closing a NullEncode filter always gave an ioerror.
+ - If a single-character name occurred 1 character before the
+end of an input buffer, the character would be doubled.
+ - The procedures in gs_statd.ps didn't use "bind".
+ - Setting the page size didn't work properly with devices
+with rotated coordinate systems.
+ - If an error occurred, and the error object wasn't the last
+element of its procedure, the interpreter would re-execute the error
+object after running the error handler.
+ - Memory devices didn't get resized if HWSize was changed,
+leading to out-of-bounds memory accesses.
+
+Moves revision and revisiondate from gs_init.ps to iinit.c. Adds a
+-v switch that just prints these out.
+
+Arranges things so that if Ghostscript is reading from a pipe (`-'
+switch on the command line) and encounters an error, it exits with
+status 1 rather than 0.
+
+Changes the interpreter interface so the caller explicitly passes a
+pointer for storing an error object.
+
+Library
+-------
+
+Fixes bugs:
+ - The automatic adjustment of the scaling for variant paper
+sizes caused the image to get expanded when it should have been
+contracted, and vice versa.
+ - The curve flattener insisted that each line segment be no
+more than 2 x the flatness in length, leading to an enormous number
+of segments even when not necessary for accuracy.
+ - flattenpath and strokepath discarded a trailing moveto.
+ - strokepath treated "0-width" lines as really having a width
+of zero, rather than one pixel.
+ - Buffered devices weren't closed and reopened if the amount
+of buffer space was changed.
+ - stroke used the line cap at the beginning of each subpath
+even if the subpath was closed.
+
+Removes the requirement that the clipping rectangle fall in the
+non-negative quadrant of device space. (This was causing problems
+for Ghostview, but removing it required adding the extra clipping
+step to the drawing routines in the drivers.)
+
+Version 2.5 (8/18/92)
+===========
+
+This version adds Type 1 hinting, CCITTFax encoding and decoding, and
+Microsoft Windows support, as well as the usual minor improvements
+and bug fixes.
+
+Procedures
+----------
+
+Fixes bugs:
+ - GSIMPATH, SLZWD, and SLZWE were omitted from the VMS
+makefiles, and GSIM2OUT was not removed.
+ - landscap.ps messed up the current path.
+
+Adds new switches:
+ -dSAFER disables file writing and directory modification.
+ -dESTACKPRINT causes errors to print the execution stack with
+== instead of =.
+ -sOutputFile=<string> replaces -sOUTPUTFILE (which is still
+recognized) for setting the output file or pipe for the default
+(printer) device.
+ -sPAPERSIZE=<sizename> initializes the paper size.
+ -dBufferSpace=<number> sets the buffer size for the default
+(printer) device.
+
+For Unix systems, changes the directories in GS_LIB_DEFAULT from
+`pwd` to $(gsdatadir), i.e., normally $(datadir)/ghostscript, where
+datadir is normally /usr/local/lib.
+
+Adds a note in the header file to the effect that the X Windows
+driver expects to find header files in $(XINCLUDE)/X11, not in
+$(XINCLUDE).
+
+Changes -q so it defines QUIET as true instead of null (so it can be
+used in the middle of the command line as well as at the beginning).
+
+Renames the history.doc file as NEWS.
+
+Utilities
+---------
+
+Platforms
+---------
+
+Fixes bugs:
+ - The stack size was not getting increased on the Watcom
+platform.
+
+Removes "b" from the scratch file opening modes in gp_unix.c and
+(conditionally) in gdevprn.c, to pacify the DECstation Ultrix system.
+
+Adds a makefile (bcwin.mak) and a platform file (gp_mswin.c) for
+Microsoft Windows.
+
+On MS-DOS platforms (including Windows), uses the TEMP environment
+variable to designate the directory for scratch files.
+
+Changes std.h so that the VMS C compiler uses function prototypes and
+'const'.
+
+Changes the VMS cc makefile so it doesn't use ansi2knr.
+
+Fonts
+-----
+
+Fixes bugs:
+ - findfont left an extra entry on the stack if it couldn't
+find the default font.
+
+Renames bchi, ncri, and puti as bchri, ncrri, and putri, to conform
+with the naming scheme for other fonts.
+
+Adds $(CCFLAGS) to the command line used for compiling fonts.
+
+Converts the .pfa fonts (CharterBT, IBM Courier, and Utopia) to .gsf,
+by removing eexec encryption and also removing some mysterious
+unmapped characters from Courier. This makes these fonts work with
+DISKFONTS.
+
+Changes the implementation of compiled fonts so they are read-only
+and sharable (no external references). (They are, however, not
+position-independent.)
+
+Provides a way to use compiled fonts on platforms that limit the
+number of characters in an identifier.
+
+Adds public-domain Cyrillic and Cyrillic-Italic fonts.
+
+Adds a 'userdict begin' to .loadfont, because Type 3 fonts produced
+by Fontographer expect a writable dictionary on the top of the stack.
+
+Changes definefont for Type 1 fonts to insert UnderlinePosition and
+UnderlineThickness entries in FontInfo if they are absent, because
+many word processors incorrectly assume these entries are present.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The documentation in use.doc said that the densities for
+9-pin Epson printers were 60x60 to 240x60, rather than 60x72 to
+240x72.
+ - gdevprn.c smashed one byte beyond the end of the string
+given as the OutputFile device property.
+ - The X11 driver used XVisualIDFromVisual, which is not
+defined in X11R3.
+ - The SunView driver modified the input data, which was
+declared as const.
+ - The LaserJet IIP and III drivers shifted the page 185
+pixels to the left and 0.25" down, because the initialization string
+was incorrect.
+ - The PCX driver wrote 16-bit values using the byte ordering
+of the platform, rather than always LSB first.
+ - For vertical spacing, the LaserJet and DeskJet drivers used
+a command that spaces N/300", rather than N scan lines, but gave it a
+parameter in scan lines.
+ - The VESA driver didn't allocate a full 256-byte buffer for
+reading the mode information from the BIOS, causing the stack to get
+smashed by newer VESA implementations.
+ - The VESA driver didn't use the scan line length returned by
+the BIOS, causing garbage output for some cards and some resolutions.
+ - The generic printer driver didn't free the bitmap when
+closing the device, if it fit entirely in memory.
+ - The PaintJet driver allocated its data areas on the stack
+instead of with gs_malloc.
+ - The generic printer driver didn't attempt to increase the
+buffer size if it was too small.
+ - The band list driver didn't split large bitmaps properly,
+leading to garbled characters at high resolutions.
+ - The GIF and PCX drivers used a color map that often turned
+gray colors into non-grays.
+
+Changes the default put_props procedure so that if the device is
+open, setting HWSize and/or HWResolution closes the device and
+reopens it.
+
+Adds a driver for Microsoft Windows 3.n.
+
+Updates the 'cdj' and 'dj500c' DeskJet 500C drivers with new versions.
+(This are user-contributed drivers.)
+
+Changes gdev_prn_put_props so OutputFile can be changed dynamically.
+
+Updates the DEC LN03 driver to also handle the LA50 and LA75. (This
+is a user-contributed driver with a FSF copyright.)
+
+Changes the LaserJet/DeskJet driver so that -DA4 in the makefile
+makes A4 paper the default. The driver now also sends an appropriate
+page size selection command to the printer if the printer supports it.
+
+Changes all the Aladdin-supported drivers to return appropriate error
+codes rather than -1.
+
+Adds a driver for the S3 86C911, a PC graphics accelerator used in
+the popular Diamond Stealth board. This is the first driver that
+uploads character bitmaps to a device; others will probably follow.
+
+Adds user-supplied code to the Epson driver so it will do triple
+passes on 9-pin printers for higher resolution.
+
+Adds user-supplied code for the PaintJet XL to the PaintJet driver.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - zdps1.c didn't include alloc.h.
+ - On 32-bit systems, if maxlength of a dictionary was less
+than the actual allocated space, length could become larger than
+maxlength.
+ - flushfile didn't actually flush data when reading.
+ - The ASCII85Decode filter signalled EOF prematurely.
+ - The scanner interpreted .3D.glorp as the number 0.3, rather
+than as a name.
+ - Closing a file freed the stream structure, creating
+dangling references if there were other file objects pointing to the
+same stream.
+ - eexec called handleerror if an error occurred, instead of
+letting the error propagate to an enclosing stopped.
+ - gs.h made perror illegal, instead of defining it in terms
+of strerror.
+ - One-character names weren't being allocated at
+initialization, so they could be left dangling after a restore.
+ - Internal gsaves (i.e., the ones in show and setcachedevice)
+didn't also save istate, so setfont inside a BuildChar procedure
+might cause the font outside to get changed.
+ - The allocator incorrectly freed objects in the current
+chunk that were older than the current save.
+ - mark was just an object, rather than an operator, so 'bind'
+didn't bind it. (This is theoretically a problem for null, true, and
+false also, but even more unlikely to be a problem in practice.)
+ - packed_get didn't cast packed integers to int, so negative
+integer elements of packed arrays came out wrong.
+ - quit just did a gs_exit, instead of returning to the driver
+in an orderly way.
+ - Because check_type_access checked for errors in the wrong
+order, sometimes type errors were reported as access errors.
+ - eq didn't check for stack underflow.
+ - Some of the stream_procs structures weren't properly
+declared const, leading to link errors on VMS.
+
+Implements currentcolor, currentcolorspace, setcolor, and
+setcolorspace (for DeviceGray, DeviceRGB, and DeviceCMYK only).
+
+Implements the dictionary form of image and imagemask. All the pairs
+in the Decode array must be the same; Interpolate is ignored. The
+only supported color spaces are DeviceGray, DeviceRGB, and
+DeviceCMYK.
+
+Implements files as allowable sources for the image operators.
+
+Removes the index field from the name structure, moving it to the
+'size' field of name refs.
+
+Changes the unread/sungetc operation to require that the character be
+the same as the last one read from the file.
+
+Adds fflush calls to some debugging printout routines, because Unix
+sometimes buffers terminal output.
+
+Implements the CCITTFaxEncode and CCITTFaxDecode filters. Implements
+the general case of the SubFileDecode filter.
+
+Changes definefont to treat a UniqueID of 0 as equivalent to no
+UniqueID, because Fontographer output apparently often violates the
+specification in this way.
+
+Changes the default printer screen from 32.5 to 46 cells/inch. (The
+old value was appropriate for a hand-rotated cell with two spots in
+it.)
+
+Changes the utility routines to allow an integral real wherever an
+integer parameter is expected in a dictionary, because Fontographer
+produces fonts that violate the Adobe specification in this way.
+
+Adds a `dosio' feature that provides direct access to memory and to
+I/O ports under MS-DOS. (This feature is not included in the
+standard executables, of course.)
+
+Changes the default character cache limit to a 1/4" x 1/4" character
+at the default resolution, rather than basing it on the preallocated
+cache size.
+
+Removes support for t_color objects, which haven't actually been used
+for several releases.
+
+Implements setcmykcolor and currentcmykcolor as operators, so they
+will interact properly with setcolorspace and currentcolorspace.
+
+Changes the name of the file.h header file to files.h, to work around
+a bug in the VMS header library.
+
+Adds command line switches @file (to treat file as more command line,
+to get around the DOS 128-character command line limit) and -ffile
+(so one can specify file names that begin with - or @).
+
+Changes the PFBDecode filter so it takes an additional boolean that
+says whether or not to convert binary packets to hex. (Conversion to
+hex and back to binary accounted for a substantial amount of the time
+required to load .PFB fonts.)
+
+Splits off `copydevice' as a separate operator again.
+
+Library
+-------
+
+Fixes bugs:
+ - In the VMS environment, string_.h used its own prototypes
+for the str... and mem... functions instead of <string.h>
+ - gx_alloc_char_bits declared cdsize as long, but didn't
+shorten it when passing it to shorten_cached_char.
+ - Stroking didn't suppress fattening of the lines.
+ - kshow didn't update the cached CTM information in the show
+enumerator when returning from the callout, so further characters
+could get drawn in the wrong place.
+ - When a memory device returned its initial matrix, it
+smashed the padding fields, which contained the interpreter's type
+information.
+ - setcachedevice didn't set the initial matrix in the cache
+memory device.
+ - image_set_rgb (in the image operators) didn't do a
+gx_color_from_rgb, so in principle one could sometimes get incorrect
+colors in an image.
+ - The decision about whether or not to cache a character
+bitmap incorrectly compared the character size against cmax rather
+than cdata_size.
+ - show didn't reset the in_cachedevice flag in the graphics
+state, so characters rendered by a recursive show were never cached.
+ - clip and eoclip didn't release the intermediate flattened
+clip path, causing memory to be lost.
+ - The tile_diff routine didn't handle the case of two
+identical tiles properly; this produced garbage in the band list
+file.
+ - stringwidth didn't round the character origin to an
+integral pixel; this interacted badly with hinting, causing
+improperly hinted characters to wind up in the cache.
+ - Bitmaps (including characters) were displaced, as well as
+being clipped, if they intersected the top of a clipping region.
+ - In gxclist and gdevmem1, the raster computation (although
+not the result) could overflow an int on 16-bit machines.
+
+Implements decoding (sample mapping) for image and imagemask.
+
+Implements hinting for Type 1 fonts, based on (but not copying) the
+algorithms from the X11R5 tape.
+
+Changes curve rasterizing to use sampling, rather than recursive
+subdivision, for characters. This produces noticeably better output.
+Speed penalty for non-cached characters is less than 10% at display
+resolutions, up to 50% for 300 dpi printers.
+
+Implements gs_setcmykcolor and gs_currentcmykcolor. These are
+semi-fake, since they simply convert the color to and from RGB, but
+the former does set the current color space properly.
+
+Changes clipping regions so they use the any-part-of-pixel rule
+rather than the center-of-pixel rule. This helps avoid dropouts when
+using very small regions.
+
+Implements stroke adjustment.
+
+Version 2.4.2 (5/8/92)
+=============
+
+This is another quick release. It finally fixes rotated halftone
+screens, and cleans up a few minor problems from 2.4.1.
+
+This release is being distributed only to beta testers and commercial
+licensees, since I don't want to be distracted from working on 2.5.
+
+Procedures
+----------
+
+Fixes bugs:
+ - UTRACE still appeared in the VMS makefiles.
+ - The support files (*.bat, *.doc, *.gsf, *.ps, Fontmap,
+COPYING, README) weren't included in the MS-DOS tar file.
+ - The Unix install script didn't install landscap.ps.
+
+Replaces the type1imagepath operator with PostScript code (impath.ps,
+type1ops.ps) based on the new .imagepath operator.
+
+Renames LICENSE as COPYING.
+
+Utilities
+---------
+
+Fixes bugs:
+ - pcharstr.ps had an occurrence of Subrs rather than /Subrs,
+causing it to not print the Subrs, or to get an error if there were
+none.
+ - font2c.ps didn't get the const declarations for string
+dictionaries quite right.
+ - The missing newline at the end of gsbj.bat confused GNU
+diff.
+ - ansi2knr would go into an infinite loop if a statement
+exceeded its internal buffer size.
+ - Compiled fonts would get processed by ansi2knr, which
+messed them up.
+
+Platforms
+---------
+
+Fixes bugs:
+ - Ghostscript didn't supply equivalents for rename and
+gettimeofday, which some System V platforms lack.
+ - The missing newline at the end of gp_dosfb.c confused GNU
+diff.
+
+Changes the Borland makefiles so that stack checking is only enabled
+if DEBUG or TDEBUG is set.
+
+Fonts
+-----
+
+Changes the names of the Utopia fonts from utrg/utb/utbi/uti to
+putr/putb/putbi/puti, for consistency with the rest of the font names.
+Changes cour/courb/courbi/couri to ncrr/ncrb/ncrbi/ncri likewise.
+
+Replaces the Charter fonts with the CharterBT fonts donated by
+Bitstream to the X11R5 distribution.
+
+Adds font aliasing capability to Fontmap. Replaces
+Courier-[Bold]Oblique and ZapfChancery-MediumItalic by aliases.
+
+Changes the FontBBox of the Hershey fonts to be an executable, rather
+than a literal, array.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The GIF driver omitted a `private' on the definition of
+gif_print_page.
+ - The GIF driver wrote 16-bit values using the byte ordering
+of the platform, rather than always LSB first.
+ - George Cameron's DeskJet 500C driver had an incorrect
+control sequence for skipping blank lines.
+
+Adds 'const' in many places, including the tile and bitmap arguments
+of the tile_rectangle, copy_mono, and copy_color driver routines.
+THIS IS A DRIVER INTERFACE CHANGE. (Printer drivers are not
+affected, since they don't implement these routines.)
+
+Adds a driver for the Trident TVGA.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - alloc_free sometimes incorrectly chose to put an unaligned
+block in an old segment on a freelist.
+ - The default undercolor removal function returned its
+argument rather than returning 0.
+
+Adds NullEncode and SubFileDecode to the standard filters, since
+bdftops uses the latter.
+
+Adds RunLengthEncode and RunLengthDecode to the optional filters.
+
+Removes the type1imagepath operator. (It is still available as
+PostScript code, impath.ps.) Replaces it with a simpler outline
+tracing operator .imagepath.
+
+Adds 'const' in many places.
+
+Makes fileposition (but not setfileposition) legal for NullEncode
+filters.
+
+Changes the default transfer function for high-resolution devices
+from the identity function to the square root function.
+
+Moves array_get from zgeneric.c to iutil.c.
+
+Changes uses of fopen to add a "b" to the access mode, rather than
+relying on the _fmode global variable on MS-DOS platforms.
+
+Allows use of the -Z switch even when gsmain.c wasn't compiled with
+-DDEBUG, since other modules might have been.
+
+Reorganizes gs.c and gsmain.c so that the latter can be used in
+server environments.
+
+Replaces all uses of stdin/out/err with gs_stdin/out/err.
+
+Makes the number of permanent entries on the dictionary stack a
+parameter, to allow inserting globaldict in the future.
+
+Changes BlueShift in the Type 1 font Private dictionary to allow real
+numbers. (This differs from the Adobe specification, but at least
+one commercial font has a real number for BlueShift.)
+
+Library
+-------
+
+Fixes bugs:
+ - The doubling check in init_ht (gxht.c) still sometimes
+thought there was enough room to double the tile when there actually
+wasn't.
+ - Rotated halftone screens didn't work.
+ - gxarith.h used #ifdef vax, rather than #if
+!arch_floats_are_IEEE, to test whether IEEE floats were being used.
+ - pathforall didn't report a trailing moveto.
+
+Replaces gs_type1imagepath with gs_imagepath.
+
+Allows sOUTPUTFILE=-, meaning output to stdout.
+
+Adds 'const' in many places.
+
+Replaces all uses of stdin/out/err with gs_stdin/out/err.
+
+Version 2.4.1 (4/21/92)
+=============
+
+This is a quick release to fix minor problems discovered in 2.4, and
+to add a few improvements that didn't quite make it into 2.4. It
+also adds GIF and PCX file support.
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some makefile dependencies, and the ccgs script, caused trouble
+for parallel versions of `make'.
+ - Compiling genarch with -O with gcc on the RS/6000 produced a
+buggy executable.
+
+Fixes some minor problems in make.doc.
+
+Adds DEVICE_DEVS2..5 to handle long device lists.
+
+Removes the need to set GS_RUN_EXE when using the Watcom compiler on
+MS-DOS systems.
+
+Gets rid of gs_ccfnt.ps, merging its function into gs_fonts.ps.
+
+Gets rid of gconfig.ps; this information is now compiled in gconfig.c.
+
+Utilities
+---------
+
+Fixes bugs:
+ - The palette for pstoppm in 8-bit mode didn't contain all 8
+primary colors.
+ - font2c used just values_ to mean &values_[0]; some compilers
+couldn't handle this.
+
+Makes font2c insert `const' in many appropriate places.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The SunView driver had not been updated properly for 2.4 and was
+pretty thoroughly broken.
+ - None of the printer drivers worked properly with the Watcom
+compiler, because stdprn was doing \n -> \r\n substitution.
+ - If the generic printer driver couldn't allocate the requested
+size command list buffer, it gave up rather than trying to allocate a
+smaller buffer.
+ - The SuperVGA drivers (except for the VESA driver) didn't
+work with the Watcom compiler, because a couple of places in the
+drivers weren't truncating the offset of "segmented" pointers
+properly.
+ - Some of the H-P used <esc>*b#Y rather than <esc>*p+#Y for
+vertical positioning; this apparently is wrong, at least for the
+LJIIp.
+
+Removes the dependence of the X Windows driver on Xt, Xext, and Xmu. As a
+result, Ghostscript will not install a standard colormap itself, but it
+will use one if one is already installed.
+
+Adds a set of drivers for Portable Bitmap, Graymap, and Pixmap file
+formats.
+
+Adds drivers for monochrome, EGA/VGA-style, and SuperVGA-style PCX
+file formats.
+
+Adds drivers for monochrome and 256-color GIF file formats.
+
+Fonts
+-----
+
+Adds ZapfChancery-MediumItalic as a copy of ZapfChancery-Oblique.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A value with l_new set could 'escape' to save level 0 on a
+stack; if stored, it prevented the slot from being saved and restored
+properly.
+ - 16#7fffffff + 1 gave the floating point equivalent of -2^31, not
+2^31.
+ - The PFBDecode filter computed the packet length incorrectly if
+the 0x8000-bit of the length was set.
+ - 5-byte numbers in Type 1 CharStrings complained of a rangecheck
+if they exceeded 16 bits, rather than if they exceeded the integer part of
+a fixed.
+ - (, ), and \ appearing in file name arguments in the command
+line did not work properly.
+
+Adds 'const' in many places.
+
+Changes the random number generator to be the same as the one used in
+Level 2 PostScript (as reported by Ed Taft on comp.lang.postscript).
+
+Exits with code 1 rather than code 0 on an unrecoverable error detected at
+the PostScript level.
+
+Makes dictionaries expand automatically when they fill up.
+
+Adds gp_exit to complement gp_init.
+
+Changes dictionaries to always allocate a power of 2 entries on
+32-bit machines. Changes the name table to allocate indices
+scattered, so dictionary lookup doesn't have to do a multiply to
+scramble the index.
+
+Changes the handling of currentfile to do "shallow binding" so stack
+searching is almost never required.
+
+Library
+-------
+
+Fixes bugs:
+ - arc and arcn got a numeric exception if the radius was zero.
+ - The undocumented 15 opcode in Type 1 fonts wasn't ignored.
+ - PaintType 3 wasn't allowed. (It isn't clear what it should
+mean; we treat it as equivalent to 0.)
+ - The VAX/VMS C compiler was generating incorrect code for the
+chi_bits and cmask macros in gdevmem, producing incorrect output.
+ - If the result of the slow algorithm for intersecting clipping
+paths was a rectangle, the wrong thing happened (cbox didn't get set).
+ - gx_path_is_rectangle didn't recognize open rectangles.
+ - clist_change_tile didn't check properly whether the tile
+size had changed, so changing the screen could produce invalid band
+files.
+ - The image operators did the wrong thing in the 1-for-1
+case, interleaving N bytes of data with 7*N bytes of garbage.
+ - stroke sometimes handled bevel and miter joins wrong in
+reflected coordinate systems.
+ - init_ht checked incorrectly whether there was enough room
+to Y-replicate tiles, so sometimes it did it when it shouldn't have.
+ - stroke sometimes thought lines were thin when they weren't.
+
+Adds 'const' in many places.
+
+Adds support for 2- and 4-bit-per-pixel memory devices.
+
+Version 2.4 (3/25/92)
+===========
+
+This is a major release that adds SuperVGA support, support for Metrics,
+settable device properties, and incremental font loading. It also
+includes important performance improvements, based on rewrites of some key
+algorithms, and quite a few new Level 2 / Display PostScript facilities.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The rule for compiling gconfig.c didn't include the -I switches.
+ - .bat files were being distributed with a \n line terminator
+rather than \r\n.
+ - A CLOSE MODULE_LIST was needed after END_COMPILE: in the VMS
+command files.
+ - Unix systems couldn't handle multiple drivers with overlapping
+sets of files.
+ - -s<name> defined <name> as a null, rather than as an empty string.
+
+Adds gconfig.ps to the list of needed configuration files.
+
+Changes the way that the makefile handles nested .h files, so that it
+doesn't have to `touch' them.
+
+Adds the loadallfonts procedure to gs_fonts.ps.
+
+Changes the standard DOS configuration to include VGA, EGA, VESA, Epson,
+BubbleJet, and H-P printer drivers.
+
+Renames ghost.mak as gs.mak, and gdevs.mak as devs.mak.
+
+Adds a USE_ASM flag so that one can build a DOS version of Ghostscript
+without having an assembler.
+
+Splits off common code from the two MS-DOS makefiles into tccommon.mak.
+
+Replaces the COPYING and LICENSE files with a new LICENSE file containing
+version 2 of the GNU General Public License.
+
+Removes DEVICES and DEVICE_OBJS from the makefiles, since they are no
+longer needed.
+
+Adds a GS_DEVICE environment variable to supply a default device name if
+desired.
+
+Adds ansihead.mak and unix-ansi.mak, to parallel [g]cc-head.mak and
+unix-[g]cc.mak, for other ANSI C compilers.
+
+Changes the way that optional features are defined in the makefiles, so
+that they actually work.
+
+Adds support for the Watcom C/386 compiler.
+
+Allows # in the command line as equivalent to =, to compensate for
+brain-damaged MS-DOS shell.
+
+Adds -sOUTPUTFILE= to set the output file or pipe.
+
+Adds -dWRITESYSTEMDICT to leave systemdict writable.
+
+Utilities
+---------
+
+Fixes bugs:
+ - pcharstr.ps insisted on having Subrs be present in the font.
+ - pcharstr.ps decoded negative numbers between -108 and -1131
+incorrectly.
+ - pfbtogs.ps didn't handle packets longer than 64K correctly.
+
+Changes the bdftops utility so that it makes entries for UnderlinePosition
+and UnderlineThickness in FontInfo, and so that it always records a
+FullName (the FontName if no other is provided).
+
+Changes the name of the pfbtops utility to pfbtogs, because groff already
+includes a program called pfbtops.
+
+Adds the gslp utility for doing "line printing" of text files, similar to
+enscript + lpr.
+
+Adds a new variable DITHERPPI that enables a different dither pattern,
+claimed to be better for printers.
+
+Adds the font2c utility for compiling Type 1 fonts into C, so they can be
+linked into an executable rather than loaded dynamically.
+
+Drivers
+-------
+
+Fixes bugs:
+ - gdev_prn_copy_scan_lines was erroneously masking the last byte
+of data even on color printers, as was paintjet_print_page.
+ - The TruFax driver had a couple of compilation errors, since it
+hadn't been compiled in a while.
+ - The BGI driver sometimes didn't consult BGIPATH when looking for
+.BGI files.
+ - initclip did the wrong thing with memory devices.
+ - The BGI driver didn't look in BGIDIR for .BGI files.
+ - The Epson driver didn't set the right margin properly with
+ESC+Q.
+ - The BJ-10e driver was badly broken.
+ - gdev_prn_open/close_printer didn't reset the command list file,
+so it was taking quadratic time to print multi-page documents.
+
+Adds color to the SunView driver.
+
+Adds selectable resolution (75, 100, 150, or 300 DPI) to the
+DeskJet/LaserJet driver.
+
+Changes gssetdev so that drivers can specify special libraries to be
+loaded, as well as object files.
+
+Adds a driver for VESA-compliant SuperVGA displays. This driver handles
+all resolutions from 640 x 400 up to 1280 x 1024, in 256-color mode. The
+default is VGA resolution (640 x 480).
+
+Adds a driver for the ATI Wonder SuperVGA card, and for SuperVGA cards
+using the Tseng Labs ET3000 or ET4000 chip such as the STB VGA EM-16 and
+the Orchid ProDesigner II (256-color modes only).
+
+Adds a driver for Trident and Tseng Labs SuperVGA cards in 800 x 600,
+16-color modes (for cards with only 256K of memory).
+
+Adds user-contributed drivers for the Ricoh 4081, DEC LN03, Canon LBP-8II,
+and H-P DeskJet 500C printers.
+
+Adds Tim Theisen's Ghostview changes to the X11 driver.
+
+MAKES NON-BACKWARD-COMPATIBLE CHANGES TO THE DRIVER PROCEDURE INTERFACE as
+follows:
+
+ - Changes map_rgb_color and map_color_rgb to always work in a
+ 16-bit color value space, rather than a space defined by the
+ maximum number of distinct colors provided by the device.
+
+ - Adds an argument to the output_page procedure to indicate
+ whether the procedure is being called for copypage or
+ showpage, and a num_copies argument.
+
+ - Adds a gx_bitmap_id to the copy_ and tile_ procedures, so that
+ drivers can cache bitmaps in the server or device if they want
+ to.
+
+ - Removes fill_trapezoid and tile_trapezoid.
+
+ - Adds a new get_bits procedure for reading the bits back from the
+ driver buffer (when possible), replacing copy_scan_lines.
+ This procedure takes a new argument describing padding and
+ byte swapping, and returns a different value from
+ copy_scan_lines.
+
+ - Adds get_props and put_props procedures for accessing arbitrary
+ additional properties of devices. The interface is quite
+ complex, but provides a great deal of flexibility.
+
+See drivers.doc for details.
+
+Changes gdev_mem_bytes_per_scan_line to gdev_prn_bytes_per_scan_line.
+
+Adds a user-contributed driver for DigiBoard, Inc.'s fax software.
+
+Fonts
+-----
+
+Changes Type1BuildChar so it uses the information from the Metrics
+dictionary in the font, if Metrics is present.
+
+Changes findfont (.loadfont) so it recognizes .PFB fonts and can load them
+directly. Also changes .loadfont to disable packing temporarily, because
+some fonts rely on procedures being writable (!).
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The hypot function is not available on some Unix systems.
+ - Ghostscript didn't flush and close files when exiting.
+ - In statusdict, the /margins procedure used .leftmargin, but
+/setmargins used .lmargin.
+ - An out-of-range putinterval would simply do nothing, rather than
+reporting an error.
+ - If an attempt to allocate a block larger than the allocator's
+chunk size (20K) failed, the allocator would erroneously think it had
+succeeded.
+ - The bind operator made the top-level procedure read-only, as
+well as interior procedures.
+ - gs.c copied 1 extra character for the value of strings defined
+on the command line with -s...=, which could smash the first byte of the
+next object in memory.
+ - copying a dictionary erroneously required the maxlength of the
+destination to be greater than or equal to the maxlength of the source,
+rather than the length of the source.
+ - undef didn't correctly decide when to mark a deleted entry as
+deleted vs. free; as a result, some keys couldn't be looked up properly
+after an undef.
+ - type1encrypt and type1decrypt didn't set the size of the result
+properly.
+ - cvi and cvr didn't allow leading or trailing whitespace in
+strings.
+ - cvs didn't cause an error if the destination string was too
+short.
+ - Many operators didn't check correctly for stack underflow (off
+by 1).
+ - `for' used reals, rather than integers, if the limit was a real,
+even if the initial value and increment were integers.
+ - `restore' didn't properly invalidate copies of the save object
+being restored from; `save dup restore restore' would crash.
+ - `restore' sometimes didn't undo stores into matrices that were
+stored into by operators. (The identity matrix always had l_new set.)
+ - readline gave a rangecheck if the input line exactly filled the
+string.
+ - `--' as the last switch on the command line caused a crash
+rather than an error message.
+ - On MS-DOS systems, filenameforall didn't handle patterns with a
+drive or directory specifier properly.
+ - stroke sometimes called gz_draw_line_fixed even if the line went
+outside the clipping box by 1 pixel.
+
+Changes the loop that binds procedure "operators" to entirely disable the
+handling of the typecheck error, rather than to use stopped. This cuts
+initialization time significantly, and also eliminates about 35K of wasted
+space (for saving the stacks).
+
+Changes the version "operator" so it returns 47.0. Adds "revision" to
+define the Ghostscript version # x 100.
+
+Adds gscurrentresolution and gssetresolution procedures for getting and
+setting the device resolution.
+
+Adds -r<res> and -r<xres>x<yres> as command line options for setting
+device resolution.
+
+Adds a facility for incrementally loading the individual CharStrings of a
+Ghostscript font from the disk. This can save a lot of memory, at the
+expense of slower rendering. (It is intended primarily for MS-DOS
+systems.)
+
+Changes findlibfile to return the name of the file that was actually
+opened, as well as the file itself, when the operation succeeds.
+
+Changes the name of the main entry to the interpreter from interpret to
+gs_interpret, because of a conflict with a Data General library procedure.
+
+Adds the .setmetrics operator to set the metrics for the current
+character for Type 1 fonts.
+
+Adds more LaserWriter-specific entries to statusdict.
+
+Gives names to all the internal `operators', so they will print out
+reasonably when an error occurs.
+
+Extends the status operator to accept a string and return file
+information, as defined for Level 2 PostScript.
+
+Adds the filter operator and some specific filters: ASCII85Encode,
+ASCII85Decode, ASCIIHexEncode, ASCIIHexDecode, eexecDecode, NullEncode,
+PFBDecode, and the null case of SubFileDecode.
+
+Extends the scanner to recognize the Level 2 << and >> tokens.
+
+Adds a facility for extracting the text strings from a PostScript file and
+writing them out in a simple format (selected by -dASCIIOUT, implemented
+by gs_2asc.ps).
+
+Implements all of the remaining Display PostScript facilities that are
+also in Level 2 (i.e., everything in section A.1.3 of the PostScript
+Language Reference Manual, Second Edition, that is not also in section
+A.1.2). The virtual memory operations are all stubs; the new halftone
+options are not fully implemented.
+
+Changes makeimagedevice to use a string of gray or RGB values, rather than
+an array of color objects, to specify the palette. Removes
+currentgscolor and setgscolor from the interpreter, but leaves t_color
+objects in, since they may be useful later.
+
+Adds getdeviceprops and putdeviceprops for manipulating device properties.
+Currently defined properties for all devices: InitialMatrix, HWResolution,
+HWSize, Name. Currently defined properties for printers: BufferSpace,
+MaxBitmap, OutputFile. OutputFile allows |command for piping on Unix
+systems.
+
+Removes deviceparams and makedevice. Adds devicedefaultmatrix.
+
+Implements reversepath.
+
+Makes copy work on devices.
+
+MS-DOS specific
+- - - - - - - -
+
+Fixes bugs:
+ - iutilasm.asm wouldn't assemble with newer versions of MASM if
+CPU_TYPE was set to 286 or above.
+ - CPU_TYPE=386 didn't properly substitute the faster
+multiply/divide routines under Turbo C++ or Borland C++, only under the
+original Turbo C.
+
+Library
+-------
+
+Fixes bugs:
+ - A curve whose first and last points were the same wouldn't get
+drawn at all.
+ - A bug in the Turbo C++ compiler generated bad code when shifting
+a long right by 1 bit.
+ - If stroking a dashed line ever encountered a segment that was
+completely blank, Ghostscript would indirect through a null pointer.
+ - arc and arcn gave an error if the radius was negative.
+ - stroke always used the general algorithm, even if the line was
+guaranteed to be thin.
+ - arc and arcn erroneously reduced the angles mod 360.
+ - Very large or negative 32-bit numbers in Type 1 fonts didn't
+work properly on MS-DOS systems (the ff0000 bits got set to zero).
+ - Color printer devices rendering entirely in memory only
+allocated a monochrome-sized bitmap.
+ - clip and eoclip didn't intersect the paths properly in the
+general case.
+ - charpath erroneously rounded the current point to an integral
+value, causing characters to be spaced improperly.
+ - The definition of max_color_param got some compilers confused.
+ - charpath always used quadratic time and space, and dropped all
+but the last character when used with a Type 3 font.
+ - Stroking a path with a 180 degree angle would incorrectly miter
+instead of beveling.
+ - Type 1 fonts used the current flatness for curves, which could
+produce bad (and inconsistent) results.
+ - Stroking a degenerate line segment produced incorrect results.
+
+Changes the character cache to use the UniqueID as the key, when
+available, instead of the font pointer. This dramatically improves
+performance when fonts are getting removed and reloaded because of page
+isolation with save/restore.
+
+Removes some unnecessary casts to (float) from gsmatrix.c and gscoord.c.
+
+Changes the Type 1 interpreter so that it rounds line and curve endpoints
+to the center of the nearest half-pixel, and omits null line segments.
+This both speeds up rendering at small sizes and improves output quality.
+
+Changes gs_deviceparams to return resolution as well as extent; changes
+gs_makedevice to accept resolution as well as extent.
+
+Replaces the algorithm for approximating circular arcs with curves with a
+more accurate one.
+
+Changes gs_point and gs_rect to use doubles rather than floats.
+
+Adds gs_setmetrics, for overriding Type 1 font metrics for the current
+character.
+
+Changes clipping to use lists of rectangles rather than path intersection.
+ This makes a big difference when clipping bitmaps (including characters).
+
+Changes the character cache to discard entries incrementally, rather than
+clearing the entire cache when it fills up.
+
+Changes the implementation of transfer functions to use a cached map,
+built when the transfer function is set. This makes transfer functions
+work properly in all situations, including images.
+
+Defines a .quit operator that takes an exit code, and redefines quit in
+terms of it.
+
+Adds support for 16-bit-per-pixel devices in gdevmem.
+
+Adds gs_copydevice and gs_deviceinitialmatrix; removes gs_deviceparams and
+gs_makedevice.
+
+Changes setscreen to ensure that the cell is always at least 4x4 pixels in
+size.
+
+Version 2.3 (8/28/91)
+===========
+
+This is a minor release to fix two bugs and add the PaintJet driver, which
+didn't make it into 2.2.
+
+Utilities
+---------
+
+Changes the pstoppm utility so it counts pages correctly even in the
+presence of arbitrary saves and restores.
+
+Drivers
+-------
+
+Adds a new, "supported" PaintJet driver.
+
+Changes the Epson driver to use ESC+D rather than ESC+\ for horizontal
+positioning, since many printers don't support the latter.
+
+Adds horizontal double-density (two-pass) printing to the Epson driver, so
+it can do 240 x 60 and 360 x 180 densities. (Vertical double density is
+not supported yet.)
+
+Version 2.2 (6/1/91)
+===========
+
+The purpose of this release is to add save/restore, and a few
+miscellaneous Level 2 P*stScr*pt features such as undef. It also includes
+major improvements in graphics quality and in handling of high-resolution
+printers.
+
+Procedures
+----------
+
+Changes the version numbering to M.mpp rather than M.m.p, so that
+`version' can be a real number for those programs that insist on it.
+
+Renames ghost.ps as gs_init.ps, gfonts.ps as gs_fonts.ps, and statusd.ps
+as gs_statd.ps. The initialization files now all are named gs_*.ps.
+
+Renames gdevs.{c,h,tl} as gconfig.{c,h,tl}.
+
+Changes the relevant makefiles and command files so that a single build
+can contain several drivers that share code, e.g., the Epson driver and
+the DeskJet driver.
+
+Changes gs_init.ps so it relies on an external gconfig.ps file rather than
+making a specific test for the presence of Level 2 features.
+
+Adds an entry for uglyr.gsf to the makefile.
+
+Removes the distinction between CCA and CCNA, since most of the files now
+contain constructs that require non-ANSI compilation on MS-DOS platforms.
+
+Adds a `man' page for the ansi2knr utility.
+
+Changes the documentation (use.doc) to show how to use -sDEVICE=<device>,
+or the selectdevice procedure, to select devices by name.
+
+Adds DEVICE_DEVS to the makefiles (analogous to DEVICES and DEVICE_OBJS).
+This finally makes the make procedure fully automatic.
+
+Adds the name of the initialization file (gs_init.ps) as a
+platform-specific makefile parameter, GS_INIT.
+
+Removes the test program gt.{c,tr} from the fileset, since it is not
+useful to users.
+
+Moves the Symbol encoding vector to a separate file (symbol_e.ps), from
+which it is loaded when first used.
+
+Changes the error handler so it can handle errors that occur while reading
+the initialization files.
+
+Extends ansi2knr so it can handle `void' and `...' in parameter lists.
+
+Adds quit.ps to the set of installed files.
+
+MS-DOS-specific changes
+- - - - - - - - - - - -
+
+Adds the VGA and BGI drivers to the standard MS-DOS configuration, and
+makes VGA the default.
+
+Adds a `+' and a newline at the end of gs.tr, to avoid problems with file
+transfer programs or editors that add a newline at the end of files.
+
+Changes the name of msdos.mak to turboc.mak, and creates a new tbcplus.mak
+makefile for use with Turbo C++ and Borland C++.
+
+Changes the extension of the loader response files from .tl to .tr.
+
+Changes the default search path from c:/ghost and c:/ghost/fonts to c:/gs
+and c:/gs/fonts.
+
+Changes the directory separator from `|' back to ';', since it appears
+that DOS can handle a ; in a command line if it is prefixed with \.
+
+Unix-specific changes
+- - - - - - - - - - -
+
+Changes the uses of install in unixtail.mak so they only install a single
+file at a time, which is all that the standard Unix install allows.
+
+Removes the duplicate files (README/readme, LICENSE/license,
+COPYING/copying, Fontmap/fontmap).
+
+Changes the ld flags from LDPLAT to LDFLAGS.
+
+Adds XCFLAGS and XLDFLAGS. These are concatenated with CFLAGS and LDFLAGS
+respectively. The intention is that they be set from the `make' command
+line if desired.
+
+VMS-specific changes
+- - - - - - - - - -
+
+Repairs the omission of ZPACKED from the VMS build lists.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The SunView driver produced semi-garbage on little-endian
+platforms (Sun-386i) because it didn't swap the bit order.
+ - The X driver would dump core if it couldn't open the display and
+the DISPLAY environment variable wasn't set.
+ - The X driver relied on white = 0, black = ones in a couple of
+places;
+ - The X driver would return an error, instead of clipping, if
+asked to display outside the window.
+ - The X driver would create inappropriately sized windows, because
+it believed the server's report of the screen resolution.
+
+Adds Fran Taylor's Private Eye driver to gdevs.mak and the fileset (not
+supported by Aladdin Enterprises).
+
+Adds Neil Ostroff's TruFax driver to gdevs.mak and the fileset (not
+supported by Aladdin Enterprises).
+
+Makes the scratch file template for the printer drivers a per-platform
+quantity (gp_scratch_file_name_template). Puts the default scratch files
+for Unix in /usr/tmp rather than /tmp.
+
+Changes the SunView driver to prevent the Ghostscript window from being
+destroyed (which badly confuses the interpreter).
+
+Extends the Epson driver to handle a variety of print densities in both X
+and Y, to handle 24-pin as well as 8-pin graphics, and to allow optional
+specification of default density in the makefile (gdevs.mak).
+
+Refactors the printer drivers so that a single driver handles both DeskJet
+and LaserJet. Adds LaserJet drivers that use the new compression modes on
+the LJ IId/IIp and LJ III.
+
+Changes all the printer drivers to use band lists rather than bitmap
+paging as the buffering method. (The individual drivers need only a
+one-line change to replace mem_copy_scan_lines with
+gdev_prn_copy_scan_lines with a different argument.)
+
+Adds the halftone phase as additional arguments to tile_rectangle and
+tile_trapezoid.
+
+Adds an entirely new and much simpler PaintJet driver, using the new band
+list interface.
+
+Adds margin information to the device structure. This is currently only
+relevant for printer devices.
+
+Adds BGIPATH and BGIUSER environment variables, allowing additional
+control of the BGI driver.
+
+Changes the x/y_pixels_per_inch member of the device structure from int to
+float.
+
+Fonts
+-----
+
+Patches gs_fonts.ps so definefont will add an isFixedPitch entry to
+FontInfo if there isn't one there.
+
+Removes the old "type 7 path" encoding code from gs_fonts.ps.
+
+Changes bdftops so it puts isFixedWidth and ItalicAngle entries in the
+FontInfo dictionary of the fonts it creates, since some P*stScr*pt
+programs rely on this.
+
+Changes bdftops so it synthesizes as many missing characters as possible
+out of the ones that are there (in particular: synthesizes accents out of
+punctuation marks, and accented characters using seac.) The results
+aren't all that good, but they're a lot better than having characters
+missing out of the font.
+
+Utilities
+---------
+
+Adds a pfbtops utility for converting .PFB fonts to standard Ghostscript
+fonts.
+
+Fixes bugs:
+ - ps2image didn't reset things properly between pages for
+multi-page documents.
+
+Interpreter
+-----------
+
+Makes Ghostscript recognize `-' alone as meaning that it should read from
+standard input as though it were a file. This allows Ghostscript to
+accept a pipe as input.
+
+Fixes bugs:
+ - seac in type1addpath used the current font's encoding, not
+StandardEncoding.
+ - type1decryptfile (eexec) didn't recognize binary (as opposed to
+hex) representation.
+ - Mentioning a name whose value was a no-access object caused an
+invalidaccess error.
+ - There was a bogus definition of `run' in zfile.c.
+ - The interpreter didn't handle end-of-file on stdin properly.
+ - Real numbers with an 'e' or 'E' but no decimal point were not
+recognized.
+ - On MS-DOS systems, inside strings, \ followed by a newline was
+not discarded properly.
+ - On MS-DOS systems, the long unsigned divide routine sometimes
+gave incorrect answers. Among other things, this caused alternate-radix
+numbers sometimes to crash the interpreter.
+ - cvrs didn't do the right thing about reals or negative integers.
+ - .echo.mode was being reset with def instead of store, and was
+defined in systemdict rather than userdict.
+ - setgray and settransfer didn't interact properly.
+ - 16#80000000 was being interpreted as a signed integer (and
+converted to a real) rather than an unsigned one.
+ - atan returned 0 sometimes when it should have returned 180.
+ - currentcmykcolor was defined wrong.
+
+Removes the filename operator, since no standard Ghostscript code used it,
+and it caused problems with some P*stScr*pt files.
+
+Implements new operators: filenameforall, selectfont (as a procedure),
+stringmatch, undef.
+
+Adds new standard procedures: selectdevice.
+
+For MS-DOS, requires that the operand and execution stacks be located in
+the data segment, and uses short pointers to address them. This produces
+significantly smaller and faster code. (These changes are not visible to
+users or library clients.)
+
+Changes the assignment of attribute bits, and adds new bits for
+save/restore and the garbage collector. Changes many of the macros in
+store.h to support save/restore. (These changes are not visible to users
+or library clients.) Implements save and restore.
+
+Moves type names from gs_init.ps to ghost.h and ztype.c.
+
+Moves error names from gs_init.ps to errors.h and iinit.c.
+
+Introduces gp.h as a documented interface to the platform-specific files.
+
+Adds the -- switch, which allows Ghostscript programs to take arguments
+from the command line.
+
+Changes many uses of the name `name' to something else, to avoid upsetting
+the Microsoft C compiler.
+
+Really implements packed arrays -- they took the same amount of space as
+ordinary arrays in previous versions.
+
+Changes exitserver in serverdict so that it just clears the stacks. (This
+isn't the correct fix, but it will do as a workaround.)
+
+Makes many miscellaneous small changes to pacify various compilers.
+
+Changes gs_fonts.ps so that when "quiet" mode is selected (-q switch),
+Ghostscript doesn't print anything when loading fonts or when substituting
+for undefined characters.
+
+Defines the name consisting of just a control-D as a no-op, because some
+P*stScr*pt-generating applications put control-Ds in their output.
+
+Implements halftone phase (sethalftonephase and currenthalftonephase
+operators).
+
+Removes the -E switch, since it is no longer useful.
+
+Changes the -w and -h switches to a single -g (geometry) switch, with
+usage -g<width>x<height>. Makes the -h switch, and a new -? switch, print
+usage help.
+
+Implements correct handling of stack overflow errors (makes an array out
+of the contents of the overflowing stack, and resets the stack, before
+invoking the error handler).
+
+Adds t_oparray (`operators' defined as procedures) and the makeoperator
+operator. This is so that programs like the Distillery that rely on all
+operators being bound by `bind' will work properly.
+
+Adds a new NOPAUSE flag to suppress the prompt and pause at copypage and
+showpage.
+
+Library
+-------
+
+Fixes bugs:
+ - gs_type1_interpret didn't store the encryption state or the skip
+count before returning to let the client handle a seac or an endchar in
+the middle of a seac.
+ - The definition of the Type 1 operator ce_testadd was based on
+wrong information; the operator takes only 2 operands and does something
+unknown.
+ - mem_true24_copy_mono wasn't incrementing the destination pointer
+if the color was transparent, leading to garbled characters.
+ - gx_lookup_fm_pair would sometimes look at one entry beyond the
+end of the cached font/matrix pair area. (This probably had no practical
+effect.)
+ - gs_type1_interpret didn't save the current point when returning
+to the client for a callothersubr, causing some characters to be rendered
+displaced (such as some of the chess pieces in chess.ps).
+ - gs_setgray, gs_sethsbcolor, gs_setrgbcolor, gs_setflat, and
+gs_setlinewidth gave errors for out-of-range operands rather than forcing
+them into range.
+ - Transfer functions were not actually supported.
+ - The area fill algorithm failed on certain complex paths.
+ - The current point was sometimes defined when a BuildChar
+procedure was called.
+ - Stroking a degenerate line didn't display anything for round
+caps or joins.
+ - If the ends of a curve had exactly the same X coordinate, the
+curve sometimes wouldn't be displayed.
+ - Very thin lines that went outside the clipping region would
+sometimes be displayed as dashed, or not at all.
+ - The translation in a FontMatrix was ignored.
+ - Very wide, shallow lines would color extraneous pixels when
+using bevel or miter joins.
+ - Dashed lines didn't join properly at the beginning of a closed
+path.
+ - 0-degree arcs didn't add the appropriate line (possibly
+degenerate) to the path.
+ - gs_type1_interpret didn't reset the callsubr stack when starting
+the base character of a seac, which caused confusion if the accent's
+endchar fell inside a Subr.
+ - Non-monochrome memory memory devices weren't checking the
+arguments of the drawing procedures properly.
+ - The initial clipping rectangle for memory devices was being
+computed wrong.
+ - Null devices had a semi-infinite clipping rectangle instead of
+an empty one.
+ - gs_setlinewidth was treating negative arguments as zero, instead
+of taking the absolute value.
+ - imagemask with a dithered color used a solid color rather than
+the dithered one.
+
+Tweaks the area fill and image rendering algorithms to be a little more
+liberal with paint when being used to render characters.
+
+Changes the name of the 8-bit mapped color memory device from
+mem_mapped_color_device to mem_mapped8_color_device.
+
+Changes the memory devices so that on little-endian platforms, they can
+store the bytes within a word in either order. (Little-endian order
+allows efficient 32-bit updating, big-endian is required when displaying
+or writing to a printer or a file.)
+
+Implements halftone phase.
+
+Replaces the trapezoid fill algorithm with a much more accurate one
+inspired by a contribution from Paul Haeberli. This also changes the
+graphics convention back to filling only pixels whose center falls within
+the region to be filled.
+
+Changes the character cache to allocate headers and bits contiguously out
+of a single ring buffer.
+
+Changes gs_imagemask and gs_imagemask_init to take a thickness adjustment
+parameter.
+
+Changes gs_setcachedevice and gs_setcharwidth to take the graphics state
+as a parameter.
+
+Renames gx_device_memory_bitmap_size as gdev_mem_bitmap_size,
+mem_copy_scan_lines as gdev_mem_copy_scan_lines, and
+mem_bytes_per_scan_line as gdev_mem_bytes_per_scan_line.
+
+Version 2.1.1 (1/15/91)
+=============
+
+This is a sub-release distributed to fix a few early bugs in 2.1, just in
+time for the new GNU master tape.
+
+Build procedures
+----------------
+
+Removes all of the (undebugged) Level 2 code from the fileset, as well as
+the (unused) file gdevvga.c.
+
+Changes the tar file so that the files are stored in the directory
+gs<version> rather than simply gs, e.g., gs211.
+
+Interpreter
+-----------
+
+Changes the scanner so that \ is recognized within strings regardless of
+whether the scanner is reading from a string or from a file. This is
+compatible with newer P*stScr*pt interpreters, and with the newer
+P*stSc*pt language specification, but not with the older specification in
+the original PostScript Language Reference Manual.
+
+Drivers
+-------
+
+Fixes the max_value macro in gdevmem.c so that compilers won't complain
+about a left shift by 32.
+
+Adds 'byte' to the list of types that gdevx.c must sidestep because header
+files use them.
+
+Library
+-------
+
+Changes the computation of penum->unpack in gsimage.c so as not to upset
+compilers that don't treat procedures and pointers to procedures as
+compatible types for conditional expressions.
+
+Version 2.1 (12/31/90)
+===========
+
+This is primarily a bug fix release to clean up problems in 2.0. It also
+implements a first cut at the new color operators.
+
+Build procedures
+----------------
+
+Changes the separator for multiple directories in MS-DOS from ';' to '|',
+since there is no way to include a ';' in a command line.
+
+Adds <dir>/fonts to the default search path, where <dir> is c:/ghost for
+MS-DOS systems and `pwd` for Unix systems.
+
+Adds new documentation describing how to direct output to the printer.
+
+Changes the PROCTYPE and USE8087 options in MSDOS.MAK to CPU_TYPE and
+FPU_TYPE. The latter now indicates the type of FPU to generate code for,
+if any.
+
+Drivers
+-------
+
+Adds a driver for the Canon BubbleJet BJ10e.
+
+Modifies the EGA driver to handle (non-standard) frame buffers larger than
+64K. Adds drivers for the VGA and for the EIZO MDB-10 (a 1024 x 768 frame
+buffer).
+
+Changes the X driver so that it clips to the window dimensions, rather
+than reporting an error.
+
+Notes that the H-P LaserJet driver, like the DeskJet driver, works under
+Unix as well as MS-DOS.
+
+Adds support for 120 X DPI mode, and for the LQ-1500, to the Epson driver.
+
+Fonts
+-----
+
+Fixes bugs in bdftops:
+ - It was using /UniqueId instead of /UniqueID as the key for the
+font unique ID. This effectively disabled the font cache.
+ - The definition for .notdef was bogus -- an invalid CharString.
+
+Changes ghost.ps and gfonts.ps so that NullFont is the initial font,
+rather than Ugly.
+
+Arranges things so that when attempting a font substitution, if the
+default font is not found, NullFont is used instead.
+
+Extends bdftops so that if certain easily synthesized characters are
+missing from a font, it will attempt to synthesize them using available
+characters.
+
+Interpreter
+-----------
+
+Extends the -T switch to allow specifying a printf template for the
+arguments of the procedure being traced.
+
+Fixes bugs:
+ - /0 was interpreted as equivalent to 0 (a number) rather than a
+literal name.
+ - packedarray was defined as being like array, instead of like
+array followed by astore.
+ - Many minor and harmless type mismatches (and a couple of very
+minor genuine bugs) were upsetting the Apollo C compiler.
+ - exp was incorrectly failing in certain cases with a negative
+first argument.
+ - copyscanlines incorrectly required at least 4 elements on the
+operand stack, although it correctly only used the top 3.
+ - readhexstring incorrectly read 1 byte even if the string length
+was zero.
+ - Not every place that expected an array would accept a packed
+array.
+ - Very complex paths (and infrequently other things) could produce
+a 'memory leak'.
+ - / alone would skip following whitespace and gather following
+characters, rather than creating an empty name.
+ - ghost.ps left newerror defined as true in $error, which resulted
+in an erroneous error report if a program executed a 'stop'.
+ - The definition of exitserver in serverdict didn't clear the
+stack.
+ - currentfile returned an executable file, rather than a literal
+one.
+ - setfont for Type 1 fonts didn't check the UniqueID in the font
+dictionary against the one in the font's Private dictionary.
+ - A value stored in a dictionary under the key /xxx couldn't be
+retrieved using the key (xxx), and vice versa.
+ - charpath with a Type 1 font on a string containing a 'space'
+would produce garbage (it released the parent path inappropriately).
+ - bytesavailable did not work properly for terminal input.
+
+Changes the interface to the memory allocator so that it always takes an
+element size and an element count, like calloc instead of malloc (but note
+that alloc does *not* clear just-allocated blocks). Gets rid of the
+special 'dynamic' allocation procedures.
+
+Changes the random number operators to use a better implementation.
+
+Changes the idiv operator so it will accept any numbers, not just
+integers, as arguments. (The PostScript manual doesn't allow this, but
+implementations apparently do.)
+
+Provides semi-fake but usable definitions for all of the color PostScript
+extensions, including a real implementation of colorimage.
+
+No longer uses the name 'null', which is apparently reserved by Microsoft
+C. Makes a number of other minor changes required to pacify the Microsoft
+C compiler.
+
+Implements %statementedit and %lineedit. (%statementedit is equivalent to
+%lineedit, which is wrong.) Changes the interactive interpreter to use
+%statementedit.
+
+Changes the scanner to accept null, ctrl-K (vertical tab), and ctrl-L
+(form feed) as whitespace. Ctrl-L terminates a comment, null and ctrl-K
+do not.
+
+Allows a literal string as the 'proc' argument(s) for image, imagemask,
+and colorimage.
+
+Adds the following operators/procedures: arct, cleardictstack, deletefile,
+renamefile.
+
+Defines =print as a synonym for =, for the benefit of LaserPrep.
+
+Implements non-zero PaintType for the show operators (but not for
+charpath) for Type 1 fonts.
+
+Adds the ISOLatin1Encoding encoding vector.
+
+Renames currentcolor and setcolor as currentgscolor and setgscolor, to
+avoid conflict with the Level 2 PostScript names. Removes colorhsb,
+colorrgb, hsbcolor, and rgbcolor.
+
+Library
+-------
+
+Fixes bugs:
+ - In a couple of places, a 0 was being passed as a pointer
+argument without casting, which confused the Microsoft C compiler.
+ - Image devices were not recognized properly in debugging
+configurations.
+ - Inverted-color monochrome image devices were not recognized
+properly.
+ - Images that exactly fill the drawing area rendered very slowly,
+because they erroneously used the general clipping algorithm.
+ - Images that are 1-for-1 with the device were incorrectly scaled
+by a factor of 8 in X.
+ - Rounding artifacts sometimes caused characters to be unevenly
+offset vertically by 1 pixel.
+ - Type 1 fonts that used the Flex feature resulted in garbled
+images.
+ - The show operator routines would incorrectly fill or stroke a
+path that existed at the time the show was started.
+ - setscreen truncated the cell size instead of rounding, which
+could produce off-by-1 anomalies.
+ - stroke would sometimes produce garbage (or nothing at all) for
+very narrow lines.
+ - path filling would only color the pixels whose centers fell
+inside the path: the Adobe specification requires coloring a pixel if any
+part of it falls inside the path.
+
+Changes the Epson printer driver so that it drives the printer directly
+rather than writing to a file.
+
+Changes pathbbox so that if the path is empty but there is a current
+point, it returns a null rectangle at the current point.
+
+Changes gs_image_init to take an additional parameter (after bps) giving
+the number of samples per pixel (1, 3, or 4), and an indication of whether
+the samples for each pixel are together or separated (-3 or -4).
+
+Renames the gs_image_data and gs_imagemask_data procedures as gs_image and
+gs_imagemask, and removes the old versions of the latter.
+
+Adds gs_colorimage.
+
+Replaces Snoopy's color dithering algorithm with one contributed by Paul
+Haeberli.
+
+Changes gs_setgray, gs_[set]hsbcolor, and gs_[set]rgbcolor so that they
+coerce arguments outside the range [0..1] back into the range, instead of
+signalling an error.
+
+Makes a number of minor changes required to pacify the Microsoft C
+compiler.
+
+Changes gs_arcto so that if the last argument is a null pointer, the
+tangent points are not returned.
+
+Removes gs_type1addpath, which is not useful. (Clients must call
+gs_type1_init and gs_type1_interpret directly.)
+
+Implements the 'seac' opcode for Type 1 fonts, allowing fonts with accented
+characters to display properly.
+
+Implements the undocumented 'testadd' opcode for Type 1 fonts, which is
+used by some Adobe fonts.
+
+Renames gs_currentcolor and gs_setcolor as gs_currentgscolor and
+gs_setgscolor. Removes gs_colorhsb, gs_colorrgb, gs_hsbcolor, and
+gs_rgbcolor.
+
+Version 2.0 (9/12/90)
+===========
+
+The main purpose of this release is to add fonts, support for multiple
+devices, and imaging into memory. It also fixes a number of miscellaneous
+bugs. (Unfortunately, accurate records of the bugs fixed are not
+available.) The changes were so extensive that we chose to increment the
+major version number.
+
+Miscellaneous
+-------------
+
+Doesn't attempt to open the .MAP file on Unix systems.
+
+Adds mention of statusd.ps to interp.doc.
+
+Notes that Turbo C 2.0, not 1.5, is required for building the MS-DOS
+version.
+
+Adds a DEVICES= line to the makefile, and allows multiple devices.
+
+Documents, in interp.doc, the X Windows resources that Ghostscript
+recognizes.
+
+Adds three PostScript masters to the fileset: chess.ps (+ cheq.ps),
+golfer.ps, and escher.ps.
+
+Drivers
+-------
+
+Changes the names of all the device drivers. See gdevs.mak for the
+updated list.
+
+Adds a (working) driver for SunView.
+
+Adds drivers for the Sony NeWS frame buffer, and the Sony Microsystems
+NWP533 printers. These drivers were contributed by users, so we aren't
+prepared to answer questions about them.
+
+Adds a driver for the Borland Graphics Interface (BGI) for MS-DOS systems.
+Note that to use this driver with a non-EGA/VGA display, you need a .BGI
+file appropriate for your hardware. (The Ghostscript executable includes
+the EGA/VGA driver.)
+
+Adds a driver for Epson printers. The driver has only been tested on an
+LX-800, and on an H-P DeskJet in FX-80 emulation mode, but may work on
+other models. The driver could be adapted to work on Unix systems, but as
+distributed, it only works on MS-DOS systems.
+
+Adds a driver for the Hewlett-Packard DeskJet printer. The driver could
+be adapted to work on Unix systems, but as distributed, it only works on
+MS-DOS systems.
+
+The X Windows driver no longer waits for the user to type a character
+before bringing up the initial display.
+
+Adds information to drivers.doc describing how to change the definition of
+the device structure and procedure table.
+
+Extends the tile_rectangle and tile_trapezoid driver procedures to
+interpret color0 = color1 = gx_no_color_index as meaning that the tile is
+actually colored, not a mask.
+
+Build procedures
+----------------
+
+Changes the tar file so it puts everything in a directory called gs.
+
+Removes the -ansi switch for gcc (this was causing problems with <math.h>
+on some systems).
+
+Changes LDPLAT to the string -X, which is appropriate for most Unix
+systems (but not for SunOS 4.n).
+
+Adds EXTRALIBS to the makefile, for specifying additional libraries to be
+linked in.
+
+Adds a 'clean' target for 'make', to get rid of all temporary files, the
+binaries, and the executable.
+
+Changes names of system-specific files from gp-xxx.c to gp_xxx.c.
+
+Adds support for VMS (gp_vms.c and ghost.dcl).
+
+Creates a new file gdevs.mak, and reorganizes the other makefiles, so that
+the choice of which device driver(s) to include is isolated in a single
+line in the platform-specific makefile.
+
+Changes the standard MS-DOS makefile so it builds for 8088/86 (not 80386),
+with neither -DNOPRIVATE nor -DDEBUG.
+
+Changes the name of the MS-DOS makefile from dos-ega.mak to msdos.mak, and
+the Unix makefiles from ux-[g]cc-x.mak to unix-[g]cc.mak.
+
+Updates drivers.doc to describe how to add new drivers in gdevs.mak.
+
+Removes gdevs.ps: the drivers are now responsible for specifying the size
+of the imaging region.
+
+Interpreter
+-----------
+
+Adds a makefile macro GS_LIB_DEFAULT and an environment variable GS_LIB to
+define a search path for the library (initialization and font) files, and
+implements the -I switch for the same purpose (replacing -sLIB=, which was
+never actually implemented). See interp.doc for details.
+
+No longer clears the operand stack between interactive inputs. No longer
+prints the contents of the operand stack after every input in debug mode.
+
+Doesn't "eat" the character that the user types to proceed after a
+showpage, unless it's an isolated <return>.
+
+Changes the prompt so that it says
+ GS>
+if the operand stack is empty, or
+ GS<n>
+if there are n > 0 elements on the operand stack.
+
+Adds -w and -h switches to the command line, equivalent to -dWIDTH= and
+-dHEIGHT= except that they require numeric arguments.
+
+Adds -q (quiet startup) switch to the command line, which suppresses some
+initial messages and also has an effect equivalent to -dQUIET.
+
+Fixes bugs:
+ - = and == caused an error on some kinds of objects if the object
+didn't have read access.
+ - cvs didn't print operator names.
+ - The definition of dynamic_begin in iscan.c caused the DEC VMS C
+compiler to produce incorrect code.
+ - mul didn't return a correct (real) result when multiplying a
+very large integer by an integer that wasn't very large.
+ - eq and ne didn't work on files, fonts, save objects, and some
+operators.
+ - The scanner would sometimes blow up on floating point numbers
+beginning with a '.'.
+ - flushfile didn't pop its argument from the stack.
+ - put and putinterval would store into a packed array.
+ - a few operators didn't check properly for stack underflow.
+ - cvrs produced wrong output for radix values greater than 10.
+ - The scanner would convert upper-case letters in alternate-radix
+numbers wrong on Unix systems.
+ - String comparisons other than equality often produced the wrong
+result if the strings were of different lengths.
+ - An ifelse as the last thing inside a forall would confuse the
+execution stack.
+ - There were some omitted casts and 'private' declarations that
+made the GNU compiler unhappy.
+ - There was a memory leak in the image[mask] operators that caused
+516 bytes to be permanently lost each time one of them was used.
+ - Quoted strings of length greater than 50 and less than 100 would
+get mangled when being read in.
+ - The scanner didn't consume the whitespace character following a
+token, so programs that read data out of the program file could get
+confused.
+ - Under rare circumstances, an object of size between 249 and 255
+bytes could get allocated on top of another object.
+
+Allows bind to bind packed arrays, even though they aren't normally
+writable.
+
+Changes the length operator to allow a name as the argument. (The
+PostScript manual doesn't allow this, but implementations apparently do.)
+
+Changes the setcachedevice operator to allow the bounding box to be
+specified as a 4-element array instead of 4 scalars. (The PostScript
+manual doesn't allow this, but implementations apparently do.)
+
+Removes a line from ghost.ps that accidentally disabled the font cache.
+
+Implements memory devices (makeimagedevice, copyscanlines, and makedevice
+for image devices). makeimagedevice is implemented only for 1, 8, 24, and
+32 bits per pixel.
+
+Changes the deviceparams operator so it pushes a mark on the stack below
+the parameters. This is to allow for devices that have more than the
+standard set of parameters.
+
+Replaces defaultdevicename with two new operators, getdevice and
+devicename.
+
+Adds a flushpage operator that flushes any outstanding buffered output to
+the screen. This is not the same as copypage: on printers, copypage
+actually prints a page, whereas flushpage may do nothing; on displays,
+flushpage and copypage may both flush output to a server.
+
+Adds an unread operator for pushing back a character into a file.
+
+Adds a description of proposed grayimage and colorimage operators to
+ghost.doc, even though they aren't implemented yet.
+
+Changes the name of the currentfileposition operator to fileposition.
+
+Removes the framedevice operator, since the new device operators supersede
+it.
+
+Adds a writeppmfile operator, for writing the contents of a memory device
+to a ppm file.
+
+Makes Ghostscript work even when the >> operator doesn't sign-extend
+negative numbers. (This has not been tested.)
+
+Adds the Symbol encoding to ghost.ps.
+
+Adds two new file-related operators, filename and findlibfile. See
+ghost.doc and interp.doc for details.
+
+Adds type1encrypt and type1decrypt operators for manipulating Adobe Type 1
+encoded fonts.
+
+Changes the imagecharpath and addcharpath operators to type1imagepath and
+type1addpath. These operators now work with the Adobe Type 1 font
+encoding.
+
+Adds the type1decryptfile operator for reading Adobe Type 1 encrypted
+fonts.
+
+Library
+-------
+
+Fixes bugs:
+ - curveto and lineto didn't check for the current point being
+defined.
+ - stringwidth would fail if there was no current point.
+ - There were omitted casts that made the GNU compiler unhappy.
+ - Line caps and joins didn't always work.
+ - Dashed lines didn't work at all.
+ - If you read out the current matrix while inside a BuildChar
+procedure, the result was garbage.
+ - image[mask] would crash if you gave it a single string with more
+than 64K-1 pixels (MS-DOS only).
+ - Filling with a gray pattern sometimes wrote into pixels beyond
+the right edge of the region (MS-DOS only).
+ - The font cache would mistake fonts for each other if both fonts
+had a default (unsupplied) "unique ID".
+ - When a character was entered into the font cache for the first
+time, sometimes it would display as garbage and/or displaced vertically
+from its proper position.
+
+Implements gs_makeimagedevice, gs_copyscanlines, gs_getdevice,
+gs_devicename, gs_flushpage, gs_writeppmfile, gs_type1encrypt,
+gs_type1decrypt, gs_type1imagepath, and gs_type1addpath procedures
+corresponding to the new operators in the interpreter (see preceding
+section).
+
+Changes [gs_]setdevice so that it does an erasepage when it first opens
+the device.
+
+Changes definition of gx_device structure as follows. NOTE: THIS AFFECTS
+ALL DRIVERS.
+
+ - Removes bits_from_MSB (which wasn't actually used, in any case).
+ Ghostscript now assumes officially, as it always did in
+ practice, that device bitmaps are stored MSB first, i.e., X=0
+ corresponds to the 0x80 bit in the first byte.
+
+ - Removes the initial_matrix member, which wasn't actually being
+ set up.
+
+ - Adds a new member 'name', a string giving the device name.
+
+ - Adds new members 'x_pixels_per_inch' and 'y_pixels_per_inch'.
+ These are only used by the default initial_matrix procedure
+ (see below).
+
+ - Adds a new procedure 'output_page'. The default implementation
+ (gx_default_output_page) just calls the sync_output procedure.
+
+ - Adds a new procedure 'get_initial_matrix'. The default
+ procedure uses the width, height, and x/y_pixels_per_inch
+ members to compute the matrix, assuming that X values run from
+ right to left, and Y values run from top to bottom.
+
+Changes the names of the allocation procedure types gs_proc_alloc and
+gs_proc_free to proc_alloc_t and proc_free_t, and moves them from gs.h to
+std.h.
+
+Makes Ghostscript work even when the >> operator doesn't sign-extend
+negative numbers. (This has not been tested.)
+
+Versions before 2.0
+===================
+
+See the file history1.txt.
diff --git a/gs/history3.txt b/gs/history3.txt
new file mode 100644
index 000000000..55259f730
--- /dev/null
+++ b/gs/history3.txt
@@ -0,0 +1,8284 @@
+ Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, history3.txt, describes the changes in older releases of
+Ghostscript numbered 3.n. For more recent changes, see the NEWS file.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Version 3.70 patch 1 (6/24/96)
+====================
+
+This contains a few last-minute patches before the release.
+
+Procedures
+----------
+
+Comments out the color inkjet drivers in the cc-based makefile, because a
+bug in Sun's cc prevents them from compiling. (cc-head.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The os2prn driver smashed memory. (gdevos2p.c)
+ - Some initialized structures weren't declared 'static'.
+(gdevpdf.c, gdevpdfm.c)
+ - The PNG driver wouldn't compile with some older versions of the
+PNG library. (gdevpng.c)
+
+Version 3.70(limited) (6/23/96)
+=====================
+
+This is the candidate fileset for 4.0. Aside from one optimization for the
+PDF writer, the only changes are bug fixes.
+
+Documentation
+-------------
+
+Renames all the documentation files from *.doc to *.txt, since the .doc
+extension didn't give any information about the format of the file.
+(readme, *.doc, *.txt)
+
+Notes that IJG JPEG library v6[a] is now required. (jpeg.mak)
+
+Brings ps2pdf.1 up to date. (ps2pdf.1)
+
+Adds a new file describing Aladdin's C coding practices. (c-style.txt)
+
+Updates the man pages to refer to version 4.0. (gs.1, pdf2ps.1, ps2ascii.1,
+ps2pdf.1)
+
+Procedures
+----------
+
+Changes some file names to fit within the MS-DOS 8.3 limit. (gs.mak)
+
+Adds the PDF writer to the remaining 32-bit configurations (Watcom, OS/2,
+MSC). (watc.mak, watcwin.mak, os2.mak, msc.mak, msvcwint.mak)
+
+Changes the -sFONTMAP= switch so it can take a list of font names, like a
+search path. (use.txt)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Signed and unsigned values were mixed inconsistently. (gdevcdj.c)
+ - PDF files could contain e-format floating point numbers, which the
+PDF specification doesn't allow. (gdevpdfx.h, gdevpdf*.c)
+ - The PDF writer didn't handle glyphshow properly. (gs_pdfwr.ps)
+ - The PDF writer did the wrong thing with fonts whose FontMatrix had
+a non-zero translation component. (gs_pdfwr.ps, gdevpdft.c)
+ - The stand-alone bounding box device could crash when setting
+parameters. (gdevbbox.c)
+ - The mswinpr2 driver smashed memory. (gdevwpr2.c)
+
+Changes the PDF writer so that if it encounters a re-encoded character, it
+tries to map it to an encoded character in the standard (ISO Latin-1)
+encoding rather than converting the entire string containing it to a bitmap.
+This dramatically improves output file size for files with a few divergently
+encoded characters, but it may cause the text in the PDF file to differ from
+the text in the PostScript input. (gdevpdft.c)
+
+Disallows BitsPerPixel=16 in the MS Windows and OS/2 drivers, since this bit
+depth is not supported by Windows and would require special extra buffering.
+(install.txt, dwtext.h, dwtext.cpp, gdevmswn.c, gdevpm.c, gdevwpr2.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - On the PC platforms, file names weren't changed to reflect the
+value of CONFIG. (gs.mak, bc*.mak, ms*.mak, os2.mak, tc*.mak, watc*.mak,
+wccommon.mak)
+
+Modifies some makefiles for greater reusability. (bclib.mak, watclib.mak)
+
+Fonts
+-----
+
+Changes the font searching rules in the following NON-BACKWARD-COMPATIBLE
+way: (gs_fonts.ps, gs_res.ps)
+ - -sFONTMAP=files specifies a list of files containing fontmaps;
+previously, it specified only a single fontmap file.
+ - If -sFONTMAP= is not used, the interpreter reads the Fontmaps from
+*all* directories on the search path, and does so even if FONTPATH or
+GS_FONTPATH is set; previously, it read only the first Fontmap, and only if
+[GS_]FONTPATH was not set.
+ - Fontmap(s) take precedence over [GS_]FONTPATH; previously,
+[GS_]FONTPATH caused Fontmap to be ignored. (You can still force Fontmap to
+be ignored with -dNOFONTMAP.)
+ - Earlier [GS_]FONTPATH entries take precedence over later;
+previously, later entries took precedence over earlier. Note that this is
+different from Fontmap: earlier Fontmaps in the search path take precedence
+over later, but within a single Fontmap, later entries take precedence over
+earlier (for backward compatibility).
+ - [GS_]FONTPATH is consulted only if there is no Fontmap entry for a
+font, or no Fontmap entry leads to successful loading; previously,
+[GS_]FONTPATH was always consulted at startup.
+ - If loading a font fails, the interpreter tries the next Fontmap
+entry; previously, it fell back to font substitution.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Filters didn't peek ahead for an EOD (see Streams below).
+(zfileio.c, zpaint.c)
+
+Splits up a file to allow internal access to user and system parameters even
+in Level 1. (zmisc2.c, zusparam.c)
+
+Adds LIBPATH as a predefined name in systemdict. Its value is an array of
+strings comprising the library search path. (imain.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - A Dests dictionary entry with an array (rather than a dictionary)
+value caused an error. (pdf_main.ps)
+ - Rotated pages could have incorrect translation and/or clipping.
+(pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - If a buffer boundary fell just before an EOD, and the client read
+exactly as much data as was present before the EOD, filters didn't consume
+the EOD. (This is required as a tricky consequence of the Adobe
+specification.) (stream.h, strimpl.h, stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - An extra column of bits could get turned on at the right edge of
+masked or monochrome images. (gximage2.c)
+ - Rasterizing very long curves could cause arithmetic errors or
+floating point overflows. (gxpcopy.c)
+ - Banding with large line widths could truncate curves or introduce
+spurious lines. (gxclpath.c)
+
+Version 3.69(limited) (6/14/96)
+=====================
+
+More bug fixes, plus one irresistible new feature: the ability to use
+TrueType fonts as freely as Type 1 fonts. Also, one new feature (outside
+clipping) that was needed for Aladdin's PCL XL project. We incremented the
+version number because of the change in trapezoid and path filling (see
+under Library below).
+
+Documentation
+-------------
+
+Brings documentation about fonts up to date. (fonts.doc)
+
+Updates current.doc to reflect changes since 3.53. (current.doc)
+
+Updates the DLL documentation to reflect recent changes. (dll.doc)
+
+Documents a workaround for the code generation bug in gcc 2.7.x. (make.doc)
+
+Changes the contact information for potential commercial customers in
+Europe. (new-user.doc)
+
+Updates the OS/2 documentation to make it current. (install.doc, make.doc)
+
+Documents -dCOLORSCREEN=0. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - 'make clean' didn't work in the Watcom environment.
+(wmakebat.bat, gs.mak, msc.mak, msvcwint.mak, os2.mak, tccommon.mak,
+unixhead.mak, wccommon.mak)
+ - The X11 libraries were listed in an incorrect order.
+(ansihead.mak, cc-head.mak, gcc-head.mak, ugcclib.mak, unix-end.mak)
+ - The OS/2 makefile didn't ignore errors from `erase' commands.
+(os2.mak)
+
+Adds the PDF writer to the 32-bit MS Windows configuration. (bcwin32.mak)
+
+Adds the PNG drivers to the 32-bit MS Windows platform, since they now
+compile properly. (bcwin32.mak)
+
+Changes the ttfont feature so that it refers to support for direct usage of
+TrueType fonts; puts support for Type 42 fonts into a separate feature
+(type42). (gs.mak, int.mak)
+
+Adds direct TrueType font support to the Windows platforms. (bcwin.mak,
+bcwin32.mak)
+
+Rewrites vms.mak to be structured more like the other makefiles. (vms.mak,
+modules.lis)
+
+Makes the device lists in vms-*.mak the same as those for the Unix
+configurations. (vms-cc.mak, vms-decc.mak, vms-gcc.mak)
+
+Changes the default X library directory for gcc to /usr/X11/lib.
+(gcc-head.mak)
+
+Adds the list of devices to --help, since HylaFax depends on this.
+(imainarg.c)
+
+Adds -dCOLORSCREEN=0 to indicate use of 4 separate color screens with the
+same frequency and angle. (gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - When ps2epsi encountered a blank page, it called the
+(undocumented) .quit operator with only one argument, causing a stack
+underflow. (ps2epsi.ps)
+ - An extraneous file was included in the fileset. (checkacc.ps)
+ - A file was omitted from the fileset. (bench.c)
+ - Images in PostScript files produced by pdf2ps were processed about
+50 times slower than they should have been. (gs_pdf.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - An #include was omitted. (gdevpdfi.c)
+ - The BJC driver could get into an inconsistent state. (gdevcdj.c)
+ - Braces were omitted around the values for two initialized byte
+arrays. (gdevpcx.c)
+ - A function used 'float' in its argument list, causing problems in
+mixed ANSI/non-ANSI compilation. (gdevcdj.c)
+ - signed and unsigned char pointers were used inconsistently.
+(gdevcdj.c, gdevcgml.c)
+ - Some header files weren't protected against double inclusion.
+(gdevprn.h, gdevtifs.h)
+ - The 24-bit PNG driver included unnecessary copies of the color
+mapping procedures. (gdevpng.c)
+
+Fixes bugs in the PDF writer:
+ - The PDF writer sometimes produced a double // in front of a filter
+name. (gdevpdfi.c)
+ - The PDF writer produced zero-width, zero-height images for
+non-standard fonts. (bug introduced since 3.68) (gdevpdfi.c)
+ - The PDF writer got confused if the input file invoked
+setpagedevice. (gdevpdfp.c)
+ - The PDF writer put annotations on the page after the one they were
+supposed to be on. (gdevpdf.c)
+ - The PDF writer sometimes failed to set the font when needed.
+(gdevpdf.c)
+ - The PDF writer could produce in-line images that were too large.
+(gdevpdfi.c)
+ - The PDF writer didn't scale explicit character and word spacing
+(ashow/widthshow/awidthshow) properly. (gdevpdft.c)
+ - The PDF writer didn't copy named destination or article title
+strings, possibly leading to dangling pointers. (gdevpdf.c, gdevpdfm.c)
+ - The PDF writer produced incorrect output for re-encoded fonts.
+(It now converts any string containing characters in non-standard positions
+to bitmaps; this will be fixed in a later release.) (gs_pdfwr.ps,
+gdevpdfx.h, gdevpdfp.c, gdevpdft.c)
+
+Updates a few drivers for the change in the handling of band device
+procedures. (gdevcp50.c, gdevdjet.c)
+
+Updates the X Windows driver for strip halftones. (gdevx.c)
+
+Adds anti-aliasing capability to the os2pm device. (gdevpm.c)
+
+Increases the sizes of some tables in the PDF writer. (gdevpdfx.h)
+
+Platforms
+---------
+
+Fixes bugs:
+ - A patch for the MS Windows platform was accidentally omitted.
+(gp_mswin.c)
+ - A block of code was accidentally duplicated. (dwmain.cpp)
+ - An identifier exceeded VAX VMS C's limit of 31 characters.
+(gscspace.h)
+ - File name enumeration didn't work properly on Unix systems
+(still/again). (gp_unifs.c)
+ - On MS Windows, If you closed Ghostscript with the system menu, you
+only closed the text window; Ghostscript kept running and you had to use the
+task manager to kill it. (dwmain.cpp, dwmainc.cpp, dwtext.cpp)
+ - Some DLL-related typedefs were not consistent. (dwdll.h, gsdll.h,
+dpmainc.c, dwdll.cpp)
+ - Attempts to call the DLL before it was initialized were not
+detected. (gsdll.c)
+ - Bitmap line lengths were rounded up even on 32-bit Windows, which
+doesn't want this. (gdevwdib.c)
+
+Further improves the handling of attempts to use the DLL when it is already
+in use. (dwdll.cpp, gsdll.c)
+
+Adds a DLL-compatible main program for OS/2. (dpmainc.c, gp_os2.c, gsdll.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The WingDings TrueType font wasn't loaded properly. (gs_ttf.ps)
+
+Makes changes so that TrueType fonts can appear in the Fontmap and can be
+loaded directly. (gs_fonts.ps, gs_ttf.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Executing a .quit with only 1 element on the operand stack caused
+an invalid access. (zcontrol.c)
+ - The usage help message contained incorrect double %%s.
+(imainarg.c)
+ - If an initialization file tried to use any Encodings other than
+the 4 registered ones, it couldn't find them. (gs_init.ps, gs_res.ps)
+ - Places that expected arrays of coordinates (rectangles,
+x/y/xyshow) didn't accept packed arrays. (ibnum.c, zdps1.c)
+ - filterdict was still visible after initialization. (gs_init.ps)
+ - The usage error message wasn't terminated by a newline.
+(imainarg.c)
+ - setcacheparams (or setting the MaxFontCache user parameter) didn't
+actually affect the size of the character cache. (zfont.c, zmisc2.c)
+ - The main interpreter loop declared iref as a ref *, even though it
+may only be a ref_packed *. (iref.h, interp.c)
+
+Changes the character cache so it ignores absurd FontBBox values. Nothing
+in the Adobe spec suggests doing this, but it is necessary for handling
+questionable output produced by PageMaker 5.0 (an Adobe product!).
+(zchar1.c)
+
+Changes some type declarations slightly to reduce the number of 'discarding
+const' compiler warnings. (igc.h, igc.c, igcref.c)
+
+Adds .setclipoutside and .currentclipoutside operators for accessing the new
+outside clipping capability. (zpath.c)
+
+Adds the dictionary stack to the information printed in case of a fatal
+problem. (imain.c)
+
+Adds .set/currentrenderalgorithm operators for testing. (zrop.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The TrueType rasterizer didn't map quadratic to cubic splines
+well, and didn't handle off-curve points at the end of a contour properly.
+(gstype42.c)
+ - An #include was omitted. (gsimage.c, gxclimag.c)
+ - Some compilers complained about statements with no effect, or
+comma operators with no effect on the left. (gschar.c, gxcpath.c, gxfill.c)
+ - TrueType or Type 42 glyphs with a repeat count that crossed a
+contour boundary produced incorrect output. (gstype42.c)
+ - TrueType / Type 42 composite glyphs involving rotation were placed
+incorrectly. (gstype42.c)
+ - Type 42 fonts with an absent or incorrect FontBBox could fail to
+produce output. (gstype42.c)
+ - Some header files weren't protected against double inclusion.
+(gsio.h, gdebug.h)
+ - Decoding filters didn't "look ahead" to detect EOD, so if the last
+read operation before closing the filter ended just before the EOD mark, the
+EOD mark might not be absorbed. (stream.h, stream.c)
+ - Filling paths consisting of multiple subpaths that overlap in Y
+produced slightly inaccurate output. We were unable to find a way to fix
+this without making a NON-BACKWARD-COMPATIBLE change in the interface for
+the recently introduced fill_trapezoid device procedure. (gxdevice.h,
+gdevbbox.c, gdevddrw.c, gdevnfwd.c, gxfill.c)
+ - When banding, get_bits didn't detect calls with out-of-range Y
+values. (gxclread.c)
+ - setcacheparams didn't actually affect the size of the character
+cache. (gsfont.h, gxbcache.h, gxfcache.h, gschar.c, gsfont.c, gxbcache.c,
+gxccman.c, gxclbits.c)
+ - When banding, colored halftones could be mangled. (gxclread.c)
+
+Fixes bugs in the bounding box device:
+ - The bounding box device could give bizarre results if any objects
+crossed the lower edge of the page. (gdevbbox.c)
+ - The bounding box device could get a memory access error when
+processing image data. (gdebbox.c)
+ - The bounding box device ran the default drawing algorithms even if
+it had no target (performance bug only). (gdevbbox.c)
+ - The bounding box device computed an incorrect (too small) box for
+partially clipped bitmap images. (gdevbbox.c)
+ - The bounding box device got confused by files that filled the
+entire page with a background color. (gdevbbox.c)
+ - The bounding box device produced infinite-height boxes for certain
+kinds of data. (gdevbbox.c)
+
+Changes some type declarations slightly to reduce the number of 'discarding
+const' compiler warnings. (gsmemory.h, gsstruct.h)
+
+Adds the capability of clipping to the outside rather than the inside of the
+clipping path. This is required for emulating an obscure feature of the
+Microsoft Windows GDI. (gspath.h, gxclpath.h, gxpath.h, gxcpath.h,
+gzcpath.h, gspath.c, gxacpath.c, gxclpath.c, gxclread.c, gxcpath.c.)
+
+Makes it possible for band devices to select the underlying memory device
+used to accumulate the actual bits. This is required for (at least) PCL5
+emulation. This requires adding a procedure to the gx_device_printer
+structure, which, for devices that initialize the structure without using
+the macros in gdevprn.h or access the printer-specific procedures directly,
+is a NON-BACKWARD-COMPATIBLE change. (gdevprn.h, gxclist.h, gxdevice.h,
+gdevdflt.c, gdevprn.c, gxclread.c)
+
+Speeds up handling of rotated or halftoned masked images. (gximage2.c)
+
+Adds an output_page procedure to the bounding box device, for testing.
+(gdevbbox.c)
+
+Adds a sample device that keeps track of the "render algorithm", for PCL5c
+emulation. (gdevrrgb.c)
+
+Version 3.68 patch 4 (5/23/96)
+====================
+
+More minor bug fixes, mostly related to the MS Windows implementation.
+
+Documentation
+-------------
+
+Further updates various doc files to make them more useful to new users.
+(NEWS, README, current.doc, helpers.doc, new-user.doc)
+
+Adds user-contributed documentation for ps2pdf. (ps2pdf.doc, unix-end.mak)
+
+Documents a bug in the Borland C++ 4.52 compiler, and where to find the
+patch for it. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - A command line exceeded the MS-DOS 120 character limit.
+(devs.mak)
+
+A file was accidentally omitted from the fileset. (wmakebat.bat)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Many of the 'show' operators didn't work properly if the PDF
+writer was included in the configuration. (gs_pdfwr.ps)
+ - x_wrap_get_bits was ridiculously slow. (It still is, but not
+quite as ridiculously.) (gxcindex.h, gdevxalt.c)
+ - The PDF writer generated CR instead of CalRGB, which is legal per
+the Adobe spec but not compatible with some Adobe Acrobat products.
+(gdevpdfi.c)
+ - Some signed/unsigned discrepancies caused compilation warnings.
+(gdevpdfm.c, gdevpdfp.c, gdevpdft.c)
+
+Fixes bugs in the Windows driver:
+ - An accidentally opened tiny window didn't get closed.
+(gdevwdib.c)
+ - The name DllInit was misleading, and this procedure wasn't being
+called whtn the DLL was loaded, so the DLL couldn't know the instance
+handle. (gp_mswin.c)
+ - The code didn't recognize Win32s (vs. Windows 95) correctly.
+(dwmain.cpp, gdevwdib.c, gp_mswin.h, gp_mswin.c, gsdll16.rc)
+ - Some compiler warnings needed fixing. (gdevwdib.c)
+ - gsdll16.def and gsdll32.def were different. (gsdll32.def)
+ - A GPF leaving the 16-bit DLL loaded could make the DLL permanently
+unusable. (dwmain.cpp)
+ - Two obsolete files were still included in the fileset.
+(gswin.def, gswin32.def)
+
+Adds a compile-time option to the 'bit' drivers to expand 4-bit pixels to
+32-bit. This was required for tracking down customer problems, because the
+only tools we have available for displaying CMYK images require 32 bits per
+pixel. (gdevbit.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - In DEC C, <time.h> does define the timeval struct. (time_.h)
+
+Changes gsdll_init() to take an additional argument, a window handle. This
+is a NON-BACKWARD-COMPATIBLE change. (dll.doc, dwdll.h, gsdll.h, dwdll.cpp,
+dwmain.cpp, dwmainc.cpp, gsdll.c)
+
+Fonts
+-----
+
+Updates more Fontmaps to include the new URW++ fonts. (Fontmap.OS2,
+Fontmap.ATM)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The default operator array table wasn't big enough. (iinit.c)
+ - Some signed/unsigned discrepancies caused compilation warnings.
+(imain.c, imainarg.c, zfile.c)
+
+Adds encoding vectors for Windows 3.1 Latin 1, Latin 2, and Latin 5
+encodings. None of these are loaded in the standard configuration.
+(gs_wl{1,2,5}_e.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Some tracing output was incorrect or missing. (gxdither.c)
+ - Resized objects in the C heap had incorrect bookkeeping
+information (bug introduced in 3.68). (gsmemory.c)
+ - Image pixels that fell exactly on device half-pixel boundaries
+could get discarded. (gximage0.c)
+ - The bounding box device didn't set a variable properly and didn't
+implement end_image, leading to invalid memory accesses. (gdevbbox.c)
+ - Fonts with BuildChar routines written in C didn't work properly
+with kshow or xyshow. (gschar.c)
+
+Adds some additional tracing output for Patterns. (gxpcmap.c)
+
+Adds tracing output for freeing malloc'ed blocks at the end of execution.
+(gsmemory.c)
+
+Adds a gs_dashpath procedure that expands dashes in the same way that
+gs_flattenpath expands curves. (gspath.h, gspath1.c)
+
+Version 3.68 patch 3 (5/17/96)
+====================
+
+More bug fixes during the beta test period. AccurateScreens now works
+properly.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The help message was too long to fit on a PC screen or standard
+terminal. (imainarg.c)
+ - Failure to run tar_cat wasn't detected. (unix-end.mak,
+unixtail.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - In the PostScript files produced by pdf2ps, images using ASCII85
+encoding would cause a typecheck error. (gs_pdf.ps)
+ - pdf2ps wrote out strings longer than 200 characters incorrectly.
+(pdf_2ps.ps)
+
+Drivers
+-------
+
+Fixes bugs in gdevcdj.c (according to the author, we have no way to test
+this):
+ - The driver used to use Colors as well as ProcessColorModel to
+define the process color model. (devices.doc, gdevbjc.h, gdevcdj.c)
+ - Incorrect or inconsistent settings of BitsPerPixel and
+ProcessColorModel, or setting one but not the other, could leave the driver
+in an inconsistent state. (gdevcdj.c)
+
+Fixes bugs in the MS Windows driver:
+ - Insufficient memory for the backing bitmap could cause a GPF.
+(gdevmswn.c, gdevwdib.c)
+ - Invalid parameters could cause a crash within the DLL code.
+(gdevwdib.c)
+
+Adds a user-contributed driver for the CalComp Raster Format. (devs.mak,
+gdevccr.c)
+
+Adds an anti-aliasing option for MS Windows. (gdevmswn.c, gdevwdib.c)
+
+Platforms
+---------
+
+Fixes bugs in the Windows platform:
+ - One had to type "quit" twice to exit. (dwdll.h, dwdll.cpp)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Platform fonts didn't work properly if the document's primary
+encoding was the standard MS Windows encoding. (ifont.h, gs_wan_e.ps)
+ - stringwidth with a Type 1 font could give a spurious typecheck
+error (bug introduced in 3.65). (zcharout.c)
+ - If a DOS editor added a ^Z to the end of the Fontmap file, an
+error occurred during initialization. (gs_fonts.ps)
+ - Halftones that didn't specify a value for AccurateScreens
+sometimes ignored the setting of the AccurateScreens user parameter.
+(zht2.c)
+
+Library
+-------
+
+Fixes bugs:
+ - gs_join_none was defined, but not implemented. (gxstroke.c)
+ - A bookkeeping list for fonts could get confused, causing invalid
+memory accesses. (gsfont.c)
+ - An I/O error or internal error would cause the band list
+rasterizer to go into an infinite loop. (gxclread.c)
+ - The algorithm for choosing screen angles and frequencies produced
+poor results. (gshtscr.c)
+ - Color screens were broken (bug introduced in 3.68). (gxdht.h,
+gzht.h, gsht.c, gshtscr.c)
+
+Version 3.68 patch 2 (5/13/96)
+====================
+
+This is another set of patches for the next general release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Windows NT and Windows 95 implementations were identified as
+"under development" rather than available. (README)
+ - There were several other minor errors in the README file.
+(README)
+ - The claimed current IJG JPEG version was incorrect. (jpeg.mak)
+
+Splits off information for new users into a separate file. (README,
+new-user.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - gettimeofday takes 2 arguments on SVR4 systems more recent than
+SVR4.0. (make.doc, ansihead.mak, cc-head.mak, gcc-head.mak, time_.h)
+
+Changes the default Unix data installation directory from /usr/local/lib to
+/usr/local/share, which seems to be favored by more recent Unix systems
+(except for some Linux versions, which still use /usr/local/lib, and BSD/OS,
+which puts Ghostscript in /usr/contrib/lib.) (ansihead.mak, cc-head.mak,
+gcc-head.mak, ugcclib.mak)
+
+Changes the unset commands in the Unix script to assignments, because a few
+older Unix shells don't provide unset. (unixtail.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - An #include incorrectly referred directly to a system header.
+(gdevpdft.c)
+ - CMYK devices took an excessive amount of time clearing the page to
+white. (gdevm32.c)
+
+Adds a compile-time option to the 'bit' drivers to remove top and bottom
+whitespace. This change was required in order to track down a customer bug.
+(gdevbit.c)
+
+Interpreter
+-----------
+
+Updates the interpreter for the split in the gstate API. (igstate.h)
+
+Streams
+-------
+
+Fixes bugs:
+ - Some compilers don't define NULL widely enough. (spngp.c)
+
+Library
+-------
+
+Fixes bugs:
+ - There was a minor typo (& for &&) that didn't affect execution.
+(gxccman.c)
+ - There was a trailing comma in an enumeration. (gsiparam.h)
+ - Internal and public interfaces weren't separated properly. THIS
+IS A NON-BACKWARD-COMPATIBLE CHANGE for clients using certain undocumented
+interfaces to the graphics state. (gsstate.h, gxstate.h, gzstate.h,
+gsstate.c)
+ - A 'private' declaration was missing (yet again). (gxclimag.c)
+
+Version 3.68 patch 1 (5/10/96)
+====================
+
+This is the first bug fix (patch) incremental release for the next general
+release.
+
+Procedures
+----------
+
+Fixes bugs:
+ - Many Windows-specific files were omitted from the previous
+fileset: dw*.rc, dw*.cpp.
+
+Version 3.68(limited) (5/9/96)
+=====================
+
+This release cleans up the new Windows files, mostly implements the
+high-level driver API for bitmap images, and adds practical strip
+(AccurateScreens) halftoning. This is the first "serious beta" fileset for
+the next general release. It still has more problems than I would have
+liked.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The names of the executable files for MS Windows were out of date.
+(make.doc)
+ - gxcindex.h still referred to "drawing color". (gxcindex.h)
+ - The name of the default font directory for Unix systems was
+incorrect. (make.doc)
+
+Moves the list of files required for installation, and some other
+installation instructions, from make.doc to install.doc. (install.doc,
+make.doc)
+
+Adds a description of the PNGPredictor filters. (language.doc)
+
+Updates the documentation of the higher-level driver procedures to match the
+specification changes. (drivers.doc)
+
+Documents the change in the Watcom build procedure. (make.doc)
+
+Improves the documentation of bitmap IDs. (gxbitmap.h)
+
+Adds documentation for the new strip_tile_rectangle and strip_copy_rop
+driver procedures. (drivers.doc)
+
+Changes the few remaining direct FTP addresses in README to URLs. (README)
+
+Notes that zlib does not compile correctly on IRIX 6.n with optimization.
+(make.doc)
+
+Adds references to PDF and TrueType fonts to language.doc. (language.doc)
+
+Updates fonts.doc to remove references to fonts.mak. (fonts.doc)
+
+Describes how to substitute an LZW compressor for the LZW-compatible
+compressor provided in the standard release. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some lines had exceeded the 120-character limit of the
+MS-DOS shell. (int.mak)
+ - The configuration files weren't generated correctly when CONFIG
+wasn't an empty string. (unixhead.mak)
+
+Factors out shared DLL makefile rules into a new file. (bcwin.mak,
+bcwin32.mak, dwcommon.mak)
+
+Makes the cp and rm commands into makefile parameters, allowing automatic
+generation of build scripts even in the MS-DOS and MS Windows environments
+where the shell requires the CALL command for sub-scripts. (*.mak,
+genconf.c)
+
+Adds the PDF writer to the default Unix configurations. (ansihead.mak,
+cc-head.mak, gcc-head.mak)
+
+Adds TrueType support to all Level 2 configurations. (int.mak)
+
+Removes fonts.mak, which is no longer relevant. (fonts.mak)
+
+Brings the font compilation procedures up to date. (cfonts.mak, int.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - There was an extra 'show' in one file. (align.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The bit devices were missing the map_color_rgb procedure.
+(gdevbit.c)
+ - The MS Windows driver sent a redundant message. (gdevmswn.c)
+
+Adds a device that keeps track of the page bounding box. This device is not
+included in any standard configuration. (drivers.doc, gdevbbox.h,
+gsmatrix.h, gsstruct.h, gxdevice.h, gdevbbox.c, gdevnfwd.c, gsmatrix.c)
+
+Updates the PDF writer to track the changes in the high-level driver API,
+and to write out images in a reasonable way. NOTE: the current
+implementation doesn't write out CIE color space parameters, so CIE-color
+images won't be colored accurately. (gdevpdf.c, gdevpdfi.c)
+
+Adds a forwarding procedure for tile_rectangle. (gxdevice.h, gdevnfwd.c)
+
+Changes the copyright notices on the PDF writer to be the same as on the
+rest of Ghostscript. (gdevpdf*.[ch])
+
+Updates Gunther Hess's Epson Stylus Color driver from 1.21 to 1.90. (Aladdin
+Enterprises takes no responsibility for this driver: if you have questions,
+contact the author.) (devices.doc, devs.mak, gdevstc*.c, gdevstc.h)
+
+Platforms
+---------
+
+Removes some obsolete MS Windows files and #defines. (gp_mswtx.h,
+gp_mswtx.c, gp_mswin.h)
+
+Works around a memory limitation in the Watcom make utility. (wmakebat.bat)
+
+Fonts
+-----
+
+Changes the standard Fontmap from using the low-quality fonts converted from
+bitmaps to using high-quality fonts recently contributed by URW++.
+(Fontmap, Fontmap.GS)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A macro containing an if-else, and a macro generating a compound
+statement, could cause incorrect grouping of 'if' statements. (files.h,
+ostack.h)
+ - .setrasterop didn't pop its operand. (zrop.c)
+ - A rounding inaccuracy could cause bounding box rangecheck errors.
+(gsdps1.c)
+ - CIE-based images in PDF files didn't work. (gs_pdf.ps)
+ - The page parameter .MediaSize didn't get updated when PageSize was
+set. (This is just the most recent manifestation of the setpagedevice
+morass.) (gs_setpd.ps)
+ - %lineedit and %statementedit were limited to 160 characters.
+(zfileio.c, ziodev.c)
+ - Compiled initialization files didn't work properly. (geninit.c,
+gs_l2img.ps)
+ - Attempting to parse a command line with argc = 0 caused a crash.
+(imainarg.c)
+
+Renames some files to allow separating the non-DLL 'main' procedure into a
+separate file, and to make the file naming more consistent:
+ gs.c (except for 'main') => imainarg.c
+ gsmain.c => imain.c
+gs.c now consists only of 'main'. The name gs.c is still inconsistent (it
+should be i- something), but at least it's consistent with the name of the
+executable. (*.mak, imain.h, iminst.h, imainarg.h, gs.c, gsmain.c, imain.c,
+imainarg.c)
+
+Adds PNGPredictorEncode/Decode filters, and increases the size of filterdict
+slightly to make room for them. (iinit.c, zfpngp.c)
+
+Makes zwrite external, per a customer request. (opextern.h, zfileio.c)
+
+Updates clients to work with the new API-based bitmap imaging calls.
+(iimage.h, zcolor1.c, zimage2.c, zpaint.c)
+
+Updates clients for the split in gscspace.h. (zcie.c, zcolor1.c, zcolor2.c,
+zcsindex.c, zcssepr.c, zimage2.c, zpaint.c, zpcolor.c)
+
+Updates clients for strip-based halftones. (zpcolor.c)
+
+Updates the initialization code to pass the correct (system) allocator to
+the library initialization. (imain.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - If a filter reached EOD exactly at the end of reading data for
+certain operations, it didn't get closed automatically. (stream.c)
+ - The LZW-compatible encoding filter reset procedure had an
+incorrect return type. (slzwce.c)
+
+Changes the ASCIIHexEncode filter to insert \ns in fewer places, to be
+somewhat more compatible with the Adobe implementation. (sstring.c)
+
+Adds PNGPredictorEncode/Decode filters that implement the pixel prediction
+algorithms in the PNG specification. (We'd like to use the code in the PNG
+library, but it's too deeply embedded in the rest of the PNG machinery, and
+it also doesn't provide for suspendable I/O.) (spngpx.h, spngp.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A test for pure color was backwards, causing garbage output or
+possible address or floating point exceptions. (gxclpath.c)
+ - A macro containing an if-else could cause incorrect grouping of
+'if' statements. (gsrefct.h)
+ - The default implementation of RasterOp didn't handle the device
+depth correctly. (gdevmrop.c)
+ - The memory device implementation of RasterOp truncated 24-bit
+constant source or texture values to 8 bits. (gdevmrop.c)
+ - A typo caused the garbage collector to miss an internal buffer
+used when rendering images. (gximage.h)
+ - gs_debug_out was only defined if DEBUG was set. (gdebug.h)
+ - The raster of horizontally replicated tiles was incorrect.
+(gxht.c)
+ - A data type might not be declared, causing a compilation error.
+(gscoord.h)
+ - Empty TrueType glyphs weren't handled properly. (gstype42.c)
+ - Fonts with a build procedure written in C could cause an invalid
+memory access. (gschar.c)
+ - The initial point of a band list path sometimes didn't get
+written, causing excess or missing filled regions. (gxclpath.c)
+ - Characters between 49 and 56 bits wide were rendered incorrectly
+when banding. (gxclbits.c)
+
+Renames gsimage*.c as gximage*.c, to reflect more accurately the position of
+these files in the architecture. (gsimage*.c, gximage*.c)
+
+Fully implements the high-level bitmap image calls in the driver API. This
+includes some driver API changes; however, this part of the API was clearly
+documented as not stable enough to rely on. (gxdevice.h, gximage.h,
+gdevbbox.c, gdevddrw.c, gdevnfwd.c, gsimage.c, gximage*.c)
+
+Splits the color space header into client and implementation, as with many
+others. (gscspace.h, gxcspace.h, gximage.h, gscie.c, gscolor.c, gscolor1.c,
+gscolor2.c, gscsepr.c, gsimage.c, gspcolor.c, gsstate.c, gxcmap.c,
+gxpcmap.c)
+
+Extends band lists to handle high-level images. NOTE: This facility is
+patched out because there is not yet a way to pass the necessary color
+rendering information through the band list. (gxcldev.h, gxclist.h,
+gxclpath.h, gxclimag.c, gxclist.c, gxclpath.c, gxclread.c)
+
+Implements fixed2float and float2fixed more efficiently on machines with
+slow floating point. (gxfixed.h, gscoord.c, gsmisc.c)
+
+Makes one further NON-BACKWARD-COMPATIBLE change in the existing
+higher-level driver procedures (fill_path, stroke_path, fill_mask): we make
+the imager state pointer an explicit argument, rather than a member of the
+gx_fill/stroke_params structure. We now consider the specification of these
+procedures stable, and have removed the "subject to change" notice from the
+documentation. (gxdevice.h, gxpaint.h, gdevbbox.c, gdevnfwd.c, gxacpath.c,
+gxclpath.c, gxclread.c, gxfill.c, gxpaint.c, gxstroke.c)
+
+Extends halftone bitmaps to include "strip" and "shift" information,
+allowing halftone cells with arbitrary angles to be stored in space
+proportional to the number of bits in the cell rather than the square of the
+number of bits. This requires adding new (optional) strip_tile_rectangle
+and strip_copy_rop driver procedures that are like tile_rectangle and
+copy_rop respectively but accept a strip bitmap rather than an ordinary
+tile; these procedures supersede tile_rectangle and copy_rop (although these
+also remain, defined in terms of the new ones). This also requires making
+small but NON-BACKWARD-COMPATIBLE changes in several internal interfaces.
+(gdevmem.h, gdevprn.h, gsdcolor.h, gxbcache.h, gxbitmap.h, gxcldev.h,
+gxclip2.h, gxclist.h, gxdevice.h, gxdevrop.h, gxdht.h, gxfcache.h,
+gxhttile.h, gxpcolor.h, gzht.h; gdevabuf.c, gdevbbox.c, gdevdflt.c,
+gdevm*.c, gdevmpla.c, gdevmrop.c, gdevnfwd.c, gsht.c, gsht1.c, gshtscr.c,
+gspcolor.c, gsstate.c, gxcht.c, gxclbits.c, gxclip2.c, gxclist.c,
+gxclpath.c, gxclread.c, gxcpath.c, gxdcolor.c, gxdither.c, gxht.c,
+gximage2.c, gxpcmap.c, ...)
+
+Adds "no join" as a line join type. NOTE: this is not actually implemented
+yet. (gslparam.h)
+
+Changes the initialization code so that it passes the system allocator as an
+argument to module initialization procedures. While this is theoretically a
+NON-BACKWARD-COMPATIBLE change, module initialization procedures are not
+documented and presumably are not used by any code outside the
+implementation. (gscdefs.h, gconf.c, gdevmrop.c, gsinit.c, gxclimag.c,
+gxclpath.c)
+
+Splits up gs_lib_init into two procedures, allowing specification of a
+different default allocator for the library. (gslib.h, gsinit.c)
+
+Adds a resize_object operation to the allocator API. (gsmemory.h,
+gsalloc.c, gsmemory.c)
+
+Version 3.67(limited) (4/12/96)
+=====================
+
+This release restructures the MS Windows and OS/2 code to be primarily DLL-
+rather than EXE-based. See under Platforms below for more news. This
+release was put out in a hurry in order to get the new DLL code into
+testers' hands; it has more rough edges than usual.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A definition & use comment was incorrect. (scanchar.h)
+ - William Bader's e-mail address was wrong. (README)
+
+Adds documentation for the new begin_image, image_data, and end_image
+procedures. THIS INTERFACE IS STILL SUBJECT TO CHANGE. (drivers.doc)
+
+Procedures
+----------
+
+Renames all the *core.dev modules as *lib.dev. (int.mak, *lib.mak, vms.mak,
+gdevmrop.c)
+
+Updates all the remaining makefiles to IJG JPEG version 6a. (*.mak)
+
+Moves the configuration parameter definitions from gconf.c to a new file
+gscdefs.c. (bcwin*.mak, *lib.mak, gs.mak, int.mak, lib.mak, unixtail.mak,
+vms.mak, gconf.c, gscdefs.c)
+
+Platforms
+---------
+
+Restructures the MS Windows and OS/2 code to be primarily DLL- rather than
+EXE-based. This involves two minor NON-BACKWARD-COMPATIBLE changes to the DLL
+interface, documented near the end of dll.doc:
+
+ - Adding argv and argc as arguments to gsdll_init.
+
+ - Adding a new message type, GSDLL_POLL, to the callback procedure.
+
+(bcwin*.mak, devs.mak, os2.mak, dll.doc, install.doc, dw*.*, gsdll*.*,
+gdevms*.*, gdevpm.c, gdevw*.c, gp_mswin.c, gp_os2.c, gsos2.def, gswin.rc)
+
+Adds the BMP drivers to the Watcom platform. (watc.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - gs.c assumed the presence of stdio. (gs.c)
+
+Defines a new API entry point that is the equivalent of command line
+invocation. (imain.h, imainarg.h, gs.c)
+
+Changes clients to conform to the changes in gsimage.h. (zimage2.c,
+zpaint.c)
+
+Speeds up the search operator slightly. (zstring.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - If the PDF interpreter was present, running a PostScript file
+didn't close the file properly if it caused an error. (pdf_main.ps)
+
+Speeds up embedded font loading by making an internal buffer bigger.
+(pdf_font.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - There could be some non-zero garbage between the width and the
+next multiple of bitmap_align_mod for copy_alpha. (The driver API
+specification explicitly allows this, but it upset one customer.)
+(gxccman.c)
+ - Nibble-swapped alpha values could be displaced in memory by one
+pixel, damaging the output. (gdevabuf.c)
+
+Makes further changes towards adding high-level bitmap image calls to the
+driver API. This includes the following minor NON-BACKWARD-COMPATIBLE
+changes to the interface defined in gsimage.h:
+
+ - changing MultipleDataSources from a member of the gs_image_t
+ structure to an argument of gs_image_init;
+
+ - changing the default image parameter values from constant
+ structures to procedures that initialize the structure.
+
+As far as we know, this doesn't affect any existing client code.
+(gsimage.h, gsiparam.h, gxdevice.h, gdevddrw.c, gdevnfwd.c, gsimage.c,
+gspcolor.c, gxccache.c)
+
+Removes an unnecessary level of call for path filling. (gxpaint.h,
+gxfill.c, gxpaint.c)
+
+Version 3.66(limited) (4/8/96)
+=====================
+
+This release adds support for TrueType fonts and Type 42 (encapsulated
+TrueType) PostScript fonts. The MS Windows driver now interacts properly
+with the garbage collector. This release also includes a new, high-quality
+set of free fonts.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The list of generic makefiles had gotten out of date. (make.doc)
+
+Adds a mention of the bmv program, created by a user and available under the
+GPL. (README)
+
+Notes that a bug in gcc 2.7.x prevents these versions from compiling
+Ghostscript. (make.doc)
+
+Clarifies the meaning of "inverted" masks. (gsimage.h)
+
+Improves the documentation of the stack sizing parameters. (interp.c)
+
+Improves the documentation of the copy_rop driver procedure.
+(drivers.doc)
+
+Notes that all subclasses of gx_device must explicitly include the
+device_finalize finalization procedure. (gxdevice.h)
+
+Updates the documentation of the high-level driver API to reflect the change
+in gx_drawing_color, and the addition of the new polygon and image drawing
+procedures. (drivers.doc)
+
+Updates the documentation for building zlib and libpng. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The environment space overflowed on some inferior Unix systems.
+(unixtail.mak)
+
+Adds a ttfont.dev "feature" for including the TrueType interpreter and the
+ability to handle Type 42 fonts. A new procedure, .loadttfont, allows
+loading a TrueType font directly (by converting it to a Type 42 on the fly).
+(gs.mak, int.mak, lib.mak)
+
+Updates the makefiles and procedures to libpng 0.88 and zlib 1.0.
+(libpng.mak, zlib.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - pdf2ps could produce lines longer than 255 characters.
+(pdf_2ps.ps)
+
+Removes some unnecessary and error-inviting code from pdf2dsc. (pdf2dsc.ps)
+
+Updates lines.ps to test the new stroke code more fully. (lines.ps)
+
+Allows omitting the second argument of ps2pdf, as for ps2epsi. (ps2pdf)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A routine was incorrectly declared "private". (I wish gcc caught
+this!) (gdevpdf.c)
+ - A 'const' was omitted in a parameter list. (gdevpdfp.c)
+ - Some imported procedures didn't have prototypes declared.
+(gdevpdft.c)
+ - The ProcSet list for PDF files didn't include Text when it was
+needed. (gdevpdfx.h, gdevpdf.c, gdevpdft.c)
+ - Text in PDF output ignored the color setting. (gs_pdfwr.ps,
+gdevpdft.c)
+ - Text in PDF output could be positioned incorrectly. (gdevpdft.c)
+ - pdfmarks could produce an error when producing PDF output.
+(gs_pdfwr.ps)
+
+Slightly improves the text output of the PDF writer. (gs_pdfwr.ps,
+gdevpdft.c)
+
+Defines driver procedures for filling trapezoids (with the parallel edges
+parallel to a coordinate axis), parallelograms (with arbitrary orientation),
+triangles (ditto), and minimum-width lines (ditto). (Note that the last of
+these obsoletes the former draw_line procedure.) (gdevmem.h, gdevprn.h,
+gxdevice.h, gxdraw.h (deleted), gdevddrw.c, gdevdflt.c, gdevht.c,
+gdevnfwd.c, gsimage[12345].c, gxacpath.c, gxclist.c, gxclip2.c, gxcpath.c,
+gxdraw.c (deleted), gxfill.c, gxpcmap.c, gxstroke.c)
+
+Adds "sketched" driver procedures for high-level bitmap / pixmap image
+drawing. In this release, the argument lists are incomplete, and the
+procedures are stubs: don't try to use them! [see previous entry]
+
+Changes the screen update strategy for the X Windows driver from a
+compile-time option to a settable run-time variable. (gdevx.c)
+
+Patches around a problem with libpng 0.88 that can't be fixed without
+editing a configuration file. (gdevpng.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - %g formats with sscanf don't work on NeXT systems. (gdevpdft.c,
+iutil.c, zdouble.c)
+ - getenv could be declared inconsistently. (gp_unix.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The Type 1 font interpreter sometimes set the flatness too large.
+(gstype1.c)
+ - Fonts defined by definefont could never be garbage collected.
+(gsstruct.h, gxfcache.h, gxfont.h, gxfont0.h, gxfont1.h, gsfont.c,
+gsfont0.c)
+ - Type 0 fonts weren't garbage collected properly. (gsfont0.c)
+ - Compiled fonts caused a compilation error (bug introduced in
+3.65). (ifont.h)
+ - If a Type 1 font used hint replacement, hints could be applied
+more than once, distorting the character shape. (gxtype1.h, gxhint3.c)
+ - Oversampling wasn't applied to large enough characters.
+(gschar.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The scanner accepted /[, /], /<<, and />> as literal names (and
+similarly for //). It isn't obvious from the Red Book, but the Adobe
+implementations don't accept these. What a nuisance! (gs_btokn.ps,
+gs_init.ps, pdf_2ps.ps, pdf_base.ps, pdf_main.ps, iscan.c)
+ - A spurious stackoverflow could occur under unusual conditions.
+(istack.c)
+ - The values of OrigFont and ScaleMatrix in scaled fonts reflected
+only the most recent scaling operation, not the original font and the
+combined scaling operation. (zfont.c)
+ - The default size of systemdict had become slightly too small.
+(iinit.c)
+ - Type 1 characters defined by PostScript procedures were called
+incorrectly. (zcharout.c)
+
+Removes the papersize operator from statusdict, since it is not documented
+anywhere in the Adobe literature and didn't interact properly with the
+various ways of setting the page size. (gs_statd.ps)
+
+Changes the one client of sskip to match the changed API. (zpaint.c)
+
+Changes clients to reflect the creation of sstring.h. (iscan.h, zfilter.c)
+
+Adds PSStringEncode as an accessible filter. (zfilter.c)
+
+Adds support for TrueType and Type 42 fonts. (gs_fonts.ps, gs_ttf.ps,
+gs_typ42.ps, bfont.h, icharout.h, ifont.h, zchar1.c, zchar42.c, zcharout.c,
+zfont1.c, zfont2.c, zfont42.c)
+
+Adds a few ANSI sheet sizes (commented out, for documentation only).
+(gs_statd.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Clients who called pdfopen/close rather than runpdf could get an
+error (PSLevel1 undefined). (pdf_main.ps)
+ - Some masked images were displayed with black and white inverted.
+(gs_pdf.ps)
+ - In Level 1 output produced by pdf2ps, images caused a syntaxerror.
+(gs_pdf.ps)
+ - If a PDF file had multiple xref sections and later sections added
+new objects, an error occurred. (pdf_main.ps)
+ - Some very old Level 1 interpreters couldn't deal with a file
+object embedded in a procedure. (gs_pdf.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The PSStringEncode filter didn't always produce printable 7-bit
+output. (sstring.c)
+ - The CCITTFaxDecode filter didn't implement DamagedRowsBeforeError.
+(scfx.h, scfd.c)
+ - Interpolated images displayed nothing if the data stream ended
+before the image height was reached. (siscale.h, gsimage5.c, siscale.c)
+
+Changes the sskip stream procedure so that it takes an additional argument
+where it returns the actual number of bytes skipped. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE in the API. However, as far as we know,
+there are no external clients of this procedure. (stream.h, stream.c)
+
+Splits up sfilter.h so that the headers correspond more directly with the
+implementations. (sfilter.h, sstring.h, sstring.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The default device in the library configuration was device 1, not
+device 0. (bclib.mak, ugcclib.mak, watclib.mak, gslib.c)
+ - Patterns could be rendered with small gaps between them.
+(gspcolor.c)
+ - Large characters could render inaccurately because of a numerical
+boundary condition. (gxpcopy.c)
+ - The show_gstate pointer in the graphics state was not managed
+properly, possibly leading to dangling pointers or GC errors. (gsstate.c)
+ - Bitmaps could get shifted to the left if ALPHA_LSB_FIRST was
+selected (bug introduced in 3.53). (gsbitops.c)
+ - The garbage collector could move devices in memory, causing
+problems with command list devices. (gxdevice.h, gsdevice.c)
+
+Continues restructuring the image handling code in preparation for adding a
+high-level driver operation. (gsimage[12345].c)
+
+Starts to implement passing color mapping information (transfer function,
+black generation, undercolor removal, CRD, halftoning) in the band list.
+(gxfmap.h, gscolor.c, gscolor1.c, gsht1.c, gsstate.c)
+
+Speeds up the path filling code a little more. (gxdraw.c)
+
+Removes the workaround for the gcc 2.7.0/1/2 optimizer bug, since this
+turned out to cause more trouble than it was worth. (stdpre.h)
+
+Speeds up stroking dramatically for the case of butt or square caps, bevel
+or beveled miter joins, and no fill adjustment, by filling parallelograms
+and triangles directly rather than constructing and filling paths. This is
+an important common case for CAD drawings. (gxdraw.h, gxdraw.c, gxstroke.c)
+
+Adds support for TrueType and Type 42 fonts. (gxfont.h, gxfont42.h,
+gstype42.c)
+
+Extends the memory manager to allow allocating objects that the garbage
+collector won't move. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE for
+implementors of memory managers, but clients aren't supposed to have any of
+these. (gsmemory.h, gsmemory.c, gsalloc.c)
+
+Makes dynamically created instances of registered devices immovable.
+(gsdevice.c)
+
+Unifies gx_drawing_color with (makes it equivalent to) gx_device_color.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE for implementors of the
+higher-level driver procedures (fill_path, stroke_path, fill_mask). We
+regret that this was necessary, but the documentation in drivers.doc does
+warn the reader: "DO NOT ASSUME THESE OPERATIONS WILL REMAIN UNCHANGED IN
+FUTURE RELEASES." These three procedures, at least, should now be stable.
+(gsdcolor.h, gxcindex.h, gxdcolor.h, gxdevice.h, gximage.h, gxpaint.h,
+gxpcolor.h, gdevdflt.c, gdevpdf.c, gdevpdfi.c, gdevxalt.c, gsimage.c,
+gsimage2.c, gspcolor.c, gxacpath.c, gxccache.c, gxcht.c, gxclpath.c,
+gxclread.c, gxdcconv.c, gxdither.c, gxfill.c, gxdraw.c, gxht.c, gxpaint.c,
+gxpcmap.c, gxstroke.c)
+
+Version 3.65(limited) (3/9/96)
+=====================
+
+This release adds garbage collection for device instances. ****** NOTE:
+Because of changes in memory management, if you are using the MS Windows
+driver (mswin), you must run with -dNOGC. This is a temporary problem which
+will be fixed before the next beta release.
+
+Documentation
+-------------
+
+Documents the C API equivalent of a -d switch for setting a flag like
+NOPAUSE. (imain.h)
+
+Splits off the NEWS entries for versions 3.0 through 3.33 into a new
+file. (history3.doc)
+
+Adds a man page for ps2pdf. (ps2pdf.1)
+
+Documents the new memory management aspects of device drivers, and corrects
+many other aspects of driver documentation that had become inaccurate.
+(drivers.doc)
+
+Updates the documentation for the gs_*.ps files. (psfiles.doc)
+
+Replaces .type1addpath with .type1execchar. (language.doc)
+
+Adds some more documentation on how band lists do read/write switching.
+(gxclist.h)
+
+Adds a reference to the new Genscript program, a free Ghostscript-based
+replacement for enscript. (README)
+
+Notes that no further changes will be accepted for the gdevcdj.c file, which
+has gotten completely out of hand. (gdevcdj.c).
+
+Documents the TextAlphaBits and GraphicsAlphaBits device parameters.
+(language.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - gs_pdfwr.ps and pdf2ps.1 weren't installed on Unix systems.
+(unix-end.mak)
+ - The pdf2ps shell script didn't accept any options. (pdf2ps)
+ - The rule for srle.$(OBJ) incorrectly specified a dependency on
+srld.c. (lib.mak)
+ - The rule for command lists didn't include stream.$(OBJ).
+(lib.mak)
+ - The stack size for one configuration was set too small.
+(watclib.mak)
+
+Speeds up genconf by eliminating redundant file reading and processing.
+(genconf.c)
+
+Moves the pixel-difference filters from int.mak to lib.mak. (int.mak,
+lib.mak)
+
+Moves the library parts of the HSB color and Level 1 path (arcs, pathbbox,
+path enumeration) options from int.mak to lib.mak, and adds them to the
+library makefiles. (int.mak, lib.mak; bclib.mak. ugcclib.mak, watclib.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - pdf2ps would fail if it encountered a font with a standard
+encoding. (pdf_2ps.ps)
+
+Adds new switches to pdf2ps:
+ -dPSBinaryOK allows writing binary image data in the output.
+(pdf_2ps.ps)
+ -dPSLevel1 forces Level 1 compatible output. (int.mak,
+unix-end.mak, gs_l2img.ps, gs_pdf.ps, pdf_2ps.ps, pdf_main.ps)
+ -dPSNoProcSet causes the ProcSet to be loaded at run time, not at
+conversion time -- primarily useful for debugging. (pdf_2ps.ps)
+
+Adds a utility for viewing PCX files, so we can preview high-resolution
+output in a reasonable compressed format. (unix-end.mak, viewpcx.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Some compilers require an extra #include to define structures even
+if they are only referenced by pointers. (int.mak, gdevpdf.c, gdevpdfp.c)
+ - A procedure name was duplicated. (gdevpdfi.c)
+ - A pdfmark between a gsave and a grestore could cause a
+rangecheck error. (gdevpdfp.c)
+ - A pdfmark between a gsave and a grestore could cause the
+grestore to do an inappropriate initgraphics. (gs_pdfwr.ps)
+ - The pdfwrite driver could reinitialize the output file
+unpredictably. (gdevpdfp.c)
+ - The PCX drivers didn't clear padding bytes at the ends of scan
+lines. (gdevpcx.c)
+ - The PCX drivers didn't set the "version" field correctly (this was
+OK in 2.6.1, bug introduced sometime since then). (gdevpcx.c)
+ - Whoever last touched the color inkjet drivers completely broke the
+handling of the BitsPerPixel parameter, again. We were able to half-fix it,
+but the code is impossible to understand, let alone modify safely.
+(gdevcdj.c)
+ - Anti-aliased characters didn't work with banding. (gxclpath.c)
+ - The PGM/PPM drivers didn't recognize black-and-white pages for
+optimization to PBM, only gray or colored. (gdevpbm.c)
+ - The color inkjet drivers initialized the params_size field of the
+static instance incorrectly, resulting in garbage in the last few structure
+members when instances were copied. (gdevcdj.c)
+ - The 24-bit PCX driver didn't pad each scan line to an even number
+of bytes. (gdevpcx.c)
+ - The svga16 driver initialized its procedures incorrectly.
+(gdevpcfb.c)
+
+Adds text writing capability to the PDF writer. In its present form, this
+is a very bad hack: it only works for the 14 built-in fonts with their
+standard encodings. (gdevpdfx.h, gdevpdf.c, gdevpdfp.c, gdevpdft.c)
+
+Adds garbage collection and finalization for device instances (gscdefs.h,
+gsdevice.h, gxdevice.h, gconf.c, gdevmrop.c, gsdevice.c, gslib.c, gsmain.c).
+(See the "Driver instance allocation" section of drivers.doc for more
+details about what is required to make this work.)
+
+ - When an open device is freed (explicitly, by garbage collection,
+or by 'restore'), if the device was allocated dynamically by Ghostscript's
+standard allocator, the device's close procedure will be called. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE for dynamically created devices, which
+formerly were not closed automatically, even when Ghostscript exited.
+
+ - Device instances allocated in GC-able space will be traced
+like other objects, assuming they have proper structure descriptors.
+
+Provides a (very slow but correct) default implementation of copy_alpha.
+(gxcindex.h, gdevdflt.c, gsimage4.c)
+
+Removes the implementation of copy_alpha in gdevpbm.c, since this is now
+implemented (more efficiently) in gdevm24.c. (gdevpbm.c)
+
+Adds TextAlphaBits and GraphicsAlphaBits as readable parameters for all
+devices. (gsdparam.c, gdevpbm.c, gdevsvga.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - There were some attempts to coerce long to short pointers
+on segmented platforms. (gsdparam.c, gstype1.c)
+ - The stack could overflow on the 16-bit MS Windows platform.
+(gxfill.c, gxclread.c)
+ - The DLL callback parameter for window resize events was computed
+incorrectly on 16-bit systems. (gdevwdib.c)
+ - A file included gxdevice.h unnecessarily. (bcwin.mak,
+bcwin32.mak, msvcwint.mak, gp_mswin.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Storing into a read-only dictionary with def or store was
+allowed. (dstack.h)
+ - If the interpreter allocated extra space for a dictionary
+to round its storage size up to a power of 2, it was possible for
+length to exceed maxlength. (idict.c, iinit.c)
+ - The if and ifelse operators didn't check that their
+'procedure' arguments were actually procedures. (interp.c, zcontrol.c)
+ - The undef operator was defined even in Level 1
+configurations. (We need this capability for all configurations, so
+we always define .undef.) (zdict.c, gs_*.ps, pdf_*.ps)
+ - In Level 1 configurations, copying a dictionary should copy the
+access attributes, but it didn't. We have to work around this
+compatibility quirk in a lot of places. (gs_cidfn.ps, gs_cmap.ps,
+gs_dps1.ps, gs_fonts.ps, gs_init.ps, gs_l2img.ps, gs_lev2.ps, gs_pdf.ps,
+gs_pfile.ps, gs_res.ps, gs_setpd.ps, gs_type1.ps, zdict.c)
+ - DSC comments that crossed a buffer boundary didn't call the
+scan_dsc_proc. (iscan.c)
+ - "statusdict /setpage get exec" caused an error. (gs_statd.ps)
+ - The default size of systemdict had become slightly too small.
+(iinit.c)
+ - Doing a showpage or copypage would cause the equivalent of a
+setpagedevice at the next restore or grestore. We aren't entirely sure that
+the fix we made doesn't have bad side-effects. (gs_setpd.ps)
+ - Not all filters accepted (and ignored) an optional dictionary
+parameter on the stack. (ifilter.h, zfbcp.c, zfdecode.c, zfilter.c,
+zfilterx.c, zfzlib.c, zmisc1.c)
+ - The PixelDifference filters required a Columns parameter, rather
+than defaulting it to 1. (spdiffx.h, zfdecode.c)
+ - Contrary to the NEWS entry for release 3.60, the LZW filters did
+not implement pixel differencing. (zfdecode.c, zfilter2.c)
+ - readstring with a 0-length string didn't signal a rangecheck.
+This doesn't make a lot of sense to me, but it's what the Adobe
+documentation specifies. Unfortunately, we have to work around this in a
+number of places that assumed the sensible definition (return () true
+without reading anything). (gs_l2img.ps, pdf_font.ps, zfileio.c)
+ - Encoded number strings didn't work (bug introduced in 3.64).
+(ibnum.c)
+ - The allocator could produce spurious "free large 0x...... chunk
+not found" messages. (These didn't cause any harm, but they were
+disturbing.) (gsalloc.c)
+
+Changes the default transfer function for high-resolution devices so
+that it is the identity function if the device is continuous-tone.
+(gs_init.ps)
+
+Undoes the "subversion" of zgetdevice noted in release 3.61, since it
+is now possible to copy devices safely. (zdevice.c)
+
+Changes the implementation of the garbage collector and restore so that
+object finalization code may safely free objects. (igc.c, isave.c)
+
+Reimplements essentially all of Type 1 BuildChar in C. (gs_init.ps,
+gs_type0.ps (deleted), gs_type1.ps, ifont.h, zchar.c, zchar1.c, zfont.c)
+
+Reimplements DISKFONTS as a separate feature (diskfont.dev), and changes it
+to use Type 4 fonts rather than special machinery. Currently this feature
+is included only in the makefiles for 16-bit architectures. (bc.mak,
+bcwin.mak, int.mak, tc.mak, gs_diskf.ps, gs_fonts.ps, gs_type1.ps)
+
+Converts the library search path from a list of strings to a (PostScript)
+array of strings, one string per directory. (iminst.h, main.h, gs.c,
+gsmain.c, zfile.c)
+
+Adds a hook procedure scan_comment_proc for processing all comments,
+similar to scan_dsc_proc. If both are set, scan_comment_proc is used only
+for non-DSC comments. (iscan.h, iscan.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Encrypted PDF files produced a random error (usually ioerror in
+--token--) rather than a meaningful message. (pdf_main.ps)
+ - Color space setting didn't work. (gs_pdf.ps)
+ - The algorithm for skipping a possible blank line following the
+'stream' keyword wasn't robust enough. (We aren't sure the new algorithm is
+exactly right, either.) (pdf_base.ps)
+
+Gets rid of the special handling of the LZW decoding filter, since the
+filter itself now handles the Predictor facility. (pdf_base.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - Configurations with LZW encoding but not decoding had an
+undefined reference. (lib.mak, slzwc.c, slzwd.c)
+ - The LZW-compatible encoder didn't provide a 'reset' procedure.
+(slzwce.c)
+ - The PixelDifference filters didn't work for most parameter
+combinations in which each pixel took up more than 1 byte. (spdiff.c)
+ - Temporary write streams could cause an infinite loop. (We only
+need such streams for the Predictor = 2 case of LZWEncode: this is why the
+bug never showed up before.) (stream.c)
+
+Adds an optional reinitialization procedure to the stream template. Note
+that this is not the same as the PostScript 'reset' operation or the stream
+resetting operation invoked by sreset: the reinit procedure in the template
+reinitializes any internal state of the encoder or decoder without affecting
+buffered data. (scommon.h, strimpl.h, sbcp.c, sbhc.c, slzwce.c, slzwd.c,
+slzwe.c, smtf.c, spdiff.c, srle.c) ****** NOT DONE YET: sbwbs.c, szlibd.c,
+szlibe.c
+
+Adds a decoding stream for the run-length compression used in PCX.
+(spcxx.h, spcxd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A recent edit introduced an extraneous right parenthesis.
+(gpcheck.h)
+ - A minor nit in a macro could cause incorrect grouping of 'if'
+statements under implausible conditions. (gsmdebug.h)
+ - The first data plane buffer of an image enumerator didn't get
+marked during garbage collection. (gsimage.c)
+ - The Watcom C compiler required splitting up a declaration.
+(gxcmap.h)
+ - The extern declarations for the tables in gconf.c weren't gathered
+together in one place. (gscdefs.h, gxiodev.h, gconf.c, gsdevice.c, gslib.c,
+gsinit.c, gsiodev.c)
+ - charpath and show produced different output. We fixed this by
+undoing a "bug fix", introduced in version 2.9, which suppressed hinting and
+coordinate rounding for charpath; we aren't sure this won't cause some
+obscure problems to reappear. (gstype1.c)
+ - Clipping with a rectangle usually created a 3-rectangle clipping
+list, slowing down all drawing operations (performance bug only).
+(gxacpath.c)
+ - stroking in a rotated coordinate system sometimes thought lines
+were always thin when they actually weren't. (gxstroke.c)
+ - An unsigned quantity wasn't properly converted to signed, possibly
+causing band path coordinates to get mangled. (gxclread.c)
+ - A bug in the Borland compiler caused an unsigned quantity to be
+interpreted as signed, causing band path coordinates to get mangled.
+(gxclread.c)
+
+Changes structure type pointers on 16-bit segmented systems to full
+32-bit pointers. This will increase time and space requirements very
+slightly on these systems. (gsmemory.h, gxobj.h)
+
+Changes the memory manager so that object finalization code may safely free
+objects. (gsmemory.h, gsstruct.h, gsalloc.c, gsmemory.c)
+
+Refactors the Type 1 CharString interpreter so it can be included in
+the imager library. (gstype1.h, gxtype1.h, gstype1.c)
+
+Starts to refactor the implementation of band lists in memory so that it can
+use any encoding/decoding filter. Currently this choice is made at compile
+time, but it could easily be made dynamic. (gxclmem.h, gxclmem.c)
+
+Starts to refactor image rendering so that, like path filling and stroking,
+it only uses imager state and can be done after banding. (gxcmap.h,
+gxdraw.h, gximage.h, gsimage*.c, gxcmap.c)
+
+Speeds up copy_mono for 2-bit-per-pixel devices a little. (gdevm2.c)
+
+Implements an optimized copy_alpha for 24-bit memory devices. (gdevmem.h,
+gdevm24.c)
+
+Speeds up filling rectangles significantly. (gsbitops.c)
+
+Changes the band list rasterizer to use the memory space of the device
+rather than the C heap: our allocator is considerably faster than malloc.
+(gxclread.c)
+
+Speeds up stroking a little, especially in 90 degree rotated coordinate
+systems. (gxstroke.c)
+
+Version 3.64(limited, incremental) (1/27/96)
+==================================
+
+This release fixes a few more bugs, including some serious bugs in band
+lists, and adds pdfmark processing to the PDF writer. The PDF writer is
+still not fit for real use, since it converts all text characters into 720
+dpi bitmaps and turns images into zillions of tiny rectangles (!), but it
+should be producing legal output.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Frans van Hoesel's e-mail address was incorrect. (gdevdjet.c)
+ - The man page for ansi2knr was out of date. (ansi2knr.1)
+ - The description of a procedure was out of date. (gxdcolor.h)
+
+Notes that several "optional" features are required in order to obtain the
+full PostScript Level 1 functionality at the library level. (lib.doc)
+
+Documents the top-level interpreter API. (imain.h)
+
+Adds details on differences between the imager API and the PostScript
+graphics operators. (lib.doc)
+
+Notes (here, in NEWS) that the change for device prototypes in 3.61 made the
+protection attributes of a device significant for the first time. Only the
+writable attribute is significant so far. (news)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The .dev rules in the library makefiles didn't list echogs as a
+dependency. (jpeg.mak, libpng.mak, zlib.mak)
+ - The install rule tried to install gs.1.1 etc. rather than gs.1
+etc. (unix-end.mak)
+ - The install rule tried to install some nonexistent *.1 files.
+(unix-end.mak)
+
+Adds 'help' and '?' procedures to assist users who don't read the
+documentation. (gs_init.ps)
+
+Adds -A-, -E-, and -Z-... to turn off debugging flags. (gs.c)
+
+Adds a -dDELAYBIND switch to delay binding operators, to allow special
+packages like pstotext to redefine them. (gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Fonts produced by rollconv.ps left a couple of items on the
+operand stack, and left array packing set to true. (rollconv.ps)
+
+Makes ansi2knr require that the first token after a function header be a
+left brace on the next line, so it can cope with some macros in IJG release
+6a. Also updates it to work better without the GNU configure machinery, and
+on some old compilers. (ansi2knr.c)
+
+Changes align.ps so it can be used directly to determine the margin
+parameters. (align.ps, psfiles.doc)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF/F (G3 and G4) drivers were broken (bug introduced in
+3.60). (gdevtfax.c)
+ - The PDF writer produced invalid output for 0-width, 0-height
+images. (gdevpdfi.c)
+ - The PDF writer wasn't a page device. (gdevpdf.c)
+ - The PDF writer assigned the Contents node rather than the Pages
+node as the Parent of each page. (gdevpdfx.h, gdevpdf.c)
+
+Corrects the margin information for the DeskJet printers to be the actual
+values observed on a printer; all of the values in the file were wrong.
+(gdevdjet.c)
+
+Adds pdfmark recognition and conversion to the PDF writer. All documented
+pdfmarks (ANN, ARTICLE, DEST, DOCINFO, DOCVIEW, LNK, OUT, PAGE, PAGES, PS)
+are recognized and converted, but some of them are not converted correctly.
+(gs_pdfwr.ps, gdevpdfx.h, gdevpdf.c, gdevpdfm.c)
+
+Adds recognition of all Distiller parameters, except *ImageDict, to the PDF
+writer. Currently only ASCII85EncodePages actually has any effect.
+(gs_pdfwr.ps, gdevpdfx.h, gdevpdfp.c)
+
+Ensures that PDF output files include at least a default Info dictionary.
+(gdevpdf.c)
+
+Changes the handling of coordinates in PDF output files so that the scale is
+always 72 dpi, and so that each graphics operator is on a line by itself,
+for compatibility with Adobe Illustrator. (gdevpdfx.h, gdevpdf*.c)
+
+Adds a driver for ImageMagick's MIFF format. The driver currently only
+produces 24-bit, direct color, RLE compressed output. (gdevmiff.c)
+
+Platforms
+---------
+
+Changes the gp_check_interrupts platform procedure so that instead of just
+returning a Boolean, it can now also return a negative error code. THIS IS
+(THEORETICALLY) A NON-BACKWARD-COMPATIBLE CHANGE. However, since all
+implementations of this procedure should only have been returning 0 or 1 up
+to now, no existing code should need to be changed. (gpcheck.h, gsmisc.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - devicenames was accidentally deleted. (gs_init.ps)
+ - -dFAKEFONTS could cause the memory manager to waste a lot of time.
+(gs_dps1.ps)
+ - Using -r or -dFIXEDMEDIA with a non-page device caused an error.
+(gs_init.ps)
+ - A VMS compiler reserves the word "readonly", which was used as a
+parameter name. (imain.h, gsmain.c)
+ - A garbage collection during the execution of x/y/xyshow with an
+array providing the values could get confused. (ibnum.h, ichar.h, stream.h,
+ibnum.c, iscanbin.c, zchar.c, zchar2.c, zdps1.c, zupath.c)
+ - Errors in encoded number strings produced a typecheck rather than
+a rangecheck error. (ibnum.c, zupath.c)
+
+Updates the DCT filters for IJG release 6a. (zfdctc.c)
+
+Provides an API call for getting the real stdio files. (imain.h,
+gs.c, gsmain.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - If the CCITTFaxEncode stream encountered an output buffer boundary
+while processing the last scan line of input, it could fail to process some
+the scan line. (scfe.c)
+ - A couple of pointers weren't always initialized, possibly
+confusing the garbage collector. (stream.c)
+ - The weighting coefficient structures used for image scaling
+weren't declared properly for the garbage collector. (siscale.h, siscale.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Unrotated patterns always used the bounding box size as the step,
+rather than XStep/YStep. (gspcolor.c)
+ - Alpha computations for graphics could be seriously incorrect (bug
+introduced in 3.6x). (gdevabuf.c)
+ - The length of the next_data_x command for the fill_mask operation
+was incorrect, causing the band list to become confused (bug introduced in
+3.63). (gxclpath.c)
+ - An extern was omitted, causing linker warnings. (gxdevice.h)
+ - RasterOps could cause an invalid access because the palette
+for a memory device wasn't set. (gdevmrop.c)
+ - gximage.h was included unnecessarily. (gspaint.c)
+ - Color screens caused a segmentation fault (bug introduced in
+3.6x). (gxcht.c)
+ - cshow returned the width in an incorrect coordinate system.
+(gscoord.h, gschar.c)
+ - Filling or stroking a path that lay entirely off the page in the
++X or +Y direction could corrupt memory (bug introduced in 3.6x).
+(gxclpath.c)
+ - When banding, painting characters with halftones produced random
+results (bug introduced in 3.6x). (gxclpath.c)
+ - When banding, characters could get clipped when they shouldn't be
+(bug introduced in 3.6x). (gxclpath.c)
+ - The default implementation of fill_mask could discard clipped
+bitmaps (bug introduced in 3.6x). (gdevdflt.c)
+ - Non-halftoned 24-bit colors could get garbled when banding (bug
+introduced in 3.6x). (gxclist.c)
+ - When banding, if a stroked path had subpaths that fell entirely
+outside the current band, the rest of the path was drawn in the wrong place
+(bug introduced in 3.6x). (gxclpath.c)
+
+Speeds up image interpolation on machines with slow floating point.
+(siscale.h, siscale.c)
+
+Speeds up interpolated images when using device color spaces. (gxcvalue.h,
+gxfrac.h, gdevht.c, gxcmap.c, gsimage.c, gsimage3.c)
+
+Speeds up color mapping a little by removing tests and calls in favor of
+code copying. (gxcmap.c)
+
+Implements RasterOp for 24-bit RGB devices. (gdevm8.c, gdevm24.c,
+gdevmrop.c)
+
+Version 3.63(limited, incremental) (1/14/96)
+==================================
+
+This release has the usual collection of bug fixes, and two significant
+additions: AccurateScreens, and the first draft of a PostScript->PDF
+converter ("distiller").
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Some documentation for pstoppm.ps was out of date. (psfiles.doc)
+ - Documentation for acctest.ps, view*.ps, and zeroline.ps was
+missing. (psfiles.doc)
+ - The documentation for rollconv.ps omitted the .CSR file.
+(rollconv.ps)
+
+Removes an inappropriate RCS Id line. (gs.1)
+
+Adds a list of paper sizes to the man page. (gs.1)
+
+Suggests that driver authors use parameterization rather than copying when
+possible. (drivers.doc)
+
+Adds an announcement of Ghostscript support on CompuServe. (README)
+
+Documents the new -dCOLORSCREEN switch and the existing -dDITHERPPI=lpi
+switch. (use.doc)
+
+Notes that the OS/2 implementation now requires EMX/GCC 0.9b rather than
+0.9a. (install.doc)
+
+Adds some new man pages. (pdf2ps.1, ps2ascii.1)
+
+Greatly expands lib.doc. (lib.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The pg target for Unix platforms didn't include some necessary
+additional X11 libraries. (unix-end.mak)
+ - The Unix library makefile didn't define CCAUX or CCLEAF.
+(ugcclib.mak)
+ - Unix systems didn't `install' some .ps files. (unix-end.mak)
+
+Extends genconf so that features at the library level can have
+initialization procedures. (gconf.c, genconf.c, gsinit.c)
+
+Adds a -dCOLORSCREEN[=false] switch to force enabling or disabling of
+4-color screens. (gs_init.ps, gs_setpd.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The prfont utility didn't leave enough of a margin on the left.
+(prfont.ps)
+ - The ps2ascii utility still created files _temp_.out and _temp_.err
+even though they are no longer used. (ps2ascii.ps)
+ - The acctest.ps file was empty, rather than including a test
+program. (acctest.ps)
+
+Adds ps2pdf[.bat] scripts for invoking the new pdfwrite driver. (ps2pdf,
+ps2pdf.bat, unix-end.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The x11alpha driver had a patch that suppressed output in many
+cases. (gdevxalt.c)
+ - The X driver set up a parameter incorrectly in copy_color.
+(gdevx.c)
+ - An explicit cast was needed to handle a 'const' problem.
+(gdevpng.c)
+
+Adds a pdfwrite driver that creates syntactically correct PDF output. The
+output is only reasonable for fill/stroke graphics, not for text or images.
+(iscan.h, sa85x.h, sfilter.h, gdevpdf.c, sfilter2.c, zfdecode.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The test for WinExec failure on Win32 was incorrect. (gp_mswin.c)
+ - getenv was declared redundantly on OS/2. (gp_os2.c)
+ - gs16spl.c was missing <string.h>. (gs16spl.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Images read data in smaller and smaller increments (performance
+bug only). (zpaint.c)
+ - Images with MultipleDataSources=true and two or more DataSources
+referencing the same stream could get confused. (zpaint.c)
+ - Invoking setpagedevice with an undefined key, even with Policy =
+1, caused an error. (gs_setpd.ps)
+ - IEEE floats in binary tokens or encoded number strings were read
+incorrectly on CPUs that use non-IEEE floating point. (ibnum.c)
+
+Adds a 'const' to the second parameter of zimage_setup. (zimage2.c,
+zpaint.c)
+
+Encapsulates the filling of free memory blocks in a macro. (igc.c,
+igcstr.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - If the first line of a file began with % but the line was longer
+than 255 characters, an error occurred. (pdf_main.ps)
+ - Masked images didn't set the color before drawing. (gs_pdf.ps)
+ - Extraneous blank lines in the trailer or cross-reference region
+caused an error. (pdf_base.ps, pdf_main.ps)
+
+Streams
+-------
+
+Speeds up image interpolation a little. Much more could be still be done.
+(siscale.c)
+
+Library
+-------
+
+Fixes bugs:
+ - An error in handling a boundary condition could cause a horizontal
+streak of pixels to be turned on or off when it shouldn't be. (gxfill.c)
+ - The new scan-line-based filling loop could write pixels twice.
+(The old trapezoid-based loop still does write pixels twice.) (gxfill.c)
+ - For multi-plane images, gs_image_next only sets *pused for the
+last plane; this wasn't documented. (gsimage.h)
+ - Images with MultipleDataSources=true and two or more DataSources
+referencing the same stream could get confused. (gsimage.h, gsimage0.c)
+ - 12-bit gray images caused an invalid memory access. (gsimage.c)
+ - Nearly-zero-thickness lines didn't get filled, because the hack
+that compensates for this peculiarity of the MS Windows PostScript driver
+accidentally got disabled. (gxfill.c)
+ - Some casts to remove 'const' were omitted. (gxclread.c)
+ - 1-line-high bitmaps could get written in the band list with an
+inconsistent number of bytes, causing errors when reading. (gxcldev.h,
+gxclbits.c, gxclist.c, gxclpath.c, gxclread.c)
+ - Isolated dots produced by round caps usually disappeared. (They
+still disappear sometimes.) (gxstroke.c)
+ - On 16-bit platforms, the computation of t2 and t3 in
+gx_curve_x_at_y could overflow, leading to incorrect output. (gxpcopy.c)
+ - Stroking horizontal or vertical lines could produce variations of
+1 pixel in the line width. (gxstroke.c)
+ - The default clipping region for band rendering was too large,
+leading to wasted work. (gxclread.c)
+ - Guarantees no double pixel writing when necessary, i.e., when a
+non-idempotent RasterOp is selected. (gsropt.h, gxfill.c)
+ - For unrotated black-and-white images, one column of pixels at the
+right edge of the image might be incorrect. (gsimage1.c)
+ - A const pointer was passed inappropriately. (gxistate.h,
+gscoord.c)
+ - CIE color conversion could address 1 element beyond the end of an
+array, with unpredictable results. (gscie.c)
+
+Separates out the higher-level band list facilities, so they can be an
+optional feature. (lib.mak, gxcldev.h, gxclpath.h, gxclbits.c, gxclist.c,
+gxclpath.c, gxclread.c)
+
+Implements bitmap (fill_mask) clipping in the band list. (gxcldev.h,
+gxclpath.h, gxclist.c, gxclpath.c, gxclread.c)
+
+Starts to separate out the RasterOp facility as an optional feature.
+(lib.mak, gxdevice.h, gxdevrop.h, gdevdflt.c, gdevmrop.c)
+
+Encapsulates the filling of free memory blocks in a macro, at the request of
+a licensee. (gdebug.h, gsmdebug.h, gsmemory.h, gs.c, gsalloc.c, gsmemory.c,
+gxbcache.c)
+
+Speeds up fill_rectangle for 32-bit devices. (gdevm32.c)
+
+Speeds up path writing in band lists a little. (gxclpath.c)
+
+Implements AccurateScreens along the lines described in the Adobe
+documentation. The current implementation can produce very large
+super-cells, so it will not always be able to actually increase the screen
+accuracy. (gxdht.h, gsht.c, gshtscr.c)
+
+Version 3.62(limited, incremental) (12/26/95)
+==================================
+
+This release makes some licensee-requested improvements in the garbage
+collector and fixes a couple of minor bugs. It also constitutes a
+checkpoint for the forthcoming forked 3.53 release.
+
+Documentation
+-------------
+
+Notes that for Win32s, gs16spl.exe must be in the same directory as
+gswin32.exe. (install.doc)
+
+Changes `3.N' to a real version number in the man page. (gs.1)
+
+Adds a reference to dos-psv, another "dumb terminal" user interface for
+Ghostscript intended for MS-DOS users. (README)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The stack size for some of the PC platforms was set too small.
+(watc.mak, watcwin.mak)
+
+Changes the default value of ORIENT1 from false to true, i.e., assumes that
+a value of 1 for the orientation parameter of setpageparams indicates
+portrait orientation. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. It only
+affects files created for roll-media imagesetters. (gs_init.ps, use.doc)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The definition of the op_index_op_array_table macro had an
+incorrect trailing semicolon. (opdef.h)
+ - Setting the PageSize policy to 1 and then trying to set the page
+size caused an error if FIXEDMEDIA was selected. (gs_setpd.ps)
+
+Changes the garbage collector marking phase so that instead of just using a
+single block (allocated, free, or default) for the mark stack, it can chain
+all three types of block together. (igc.h, igc.c, igcstr.c, ilocate.c)
+
+Refactors the garbage collector slightly to reduce inter-module
+dependencies. (int.mak, igc.h, igcstr.h, igcstr.c)
+
+Changes the garbage collector to keep track of ranges within each chunk that
+must be scanned if the mark stack overflows. (gxalloc.h, igc.c)
+
+Adds [write]===[only] procedures, which act like == but also print the
+contents of dictionaries, and ppstack, which acts like pstack but uses ===.
+Changes ESTACKPRINT and OSTACKPRINT to use === rather than ==. (gs_init.ps,
+gs_setpd.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - If a PDF file substituted a calibrated color space for the
+DeviceGray or DeviceRGB color space using a ColorSpace resource, the
+PostScript file that pdf2ps produced from that PDF file caused an error.
+(gs_pdf.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The debugging code for checking the sorting of line lists didn't
+check for an empty list. (gxfill.c)
+
+Version 3.61(limited) (12/10/95)
+=====================
+
+This limited release fixes a few bugs (including a couple that significantly
+affected character quality) and also includes some substantial performance
+improvements.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The directory name for the PNG library was incorrect.
+(libpng.mak)
+ - The analysis of curve monotonocity in gxpcopy.c had an error.
+(gxpcopy.c)
+
+Changes the subdirectory names for zlib and libpng to be consistent.
+(make.doc)
+
+Documents a possible problem with object file format incompatibilities in
+certain versions of Linux. (make.doc)
+
+Documents the new distinction between devices and device prototypes.
+(language.doc)
+
+Adds a pointer to DEC's free pstotext utility. (README)
+
+Procedures
+----------
+
+Fixes bugs:
+ - zlib.mak omitted some files in the encoding module dependencies.
+(zlib.mak)
+ - os2.mak referred to png.mak rather than libpng.mak. (os2.mak)
+ - The png devices didn't include gdevpccm.$(OBJ) as a required file.
+(devs.mak)
+ - Some modules in lib.mak referred to stream.h, which was defined in
+int.mak. (int.mak, lib.mak)
+ - Quite a few dependencies on header files were missing from the
+makefiles. (int.mak, lib.mak, *.mak)
+
+Adds a 'pg' target to the Unix makefiles, for building profiling
+configurations. (unix-end.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Type 1 fonts in which some characters are defined by PostScript
+procedures couldn't be compiled. (ccfont.h, iccfont.c, font2c.ps)
+ - pdf2ps didn't write Widths or Encoding in the converted file,
+producing incorrect spacing and incorrect characters. (pdf_2ps.ps)
+ - markhint.ps didn't handle the Type 1 'div' operator, causing
+typecheck errors. (markhint.ps)
+ - markhint.ps ignored the hstem3 and vstem3 hints. (markhint.ps)
+
+Changes the rollconv.ps utility to produce files whose names conform to the
+8.3 length restriction, and to reduce the fixed RAM overhead for Kanji
+fonts. (rollconv.ps)
+
+Adds a utility for detecting compiler problems that affect Ghostscript.
+(bughunt.sh)
+
+Drivers
+-------
+
+Adds anti-aliasing capability (-dTextAlphaBits and -dGraphicsAlphaBits) to
+the PGM and PPM drivers. (gdevpbm.c)
+
+Declares the static_procs member of the device structure as const *. This
+should have been done a long time ago! (drivers.doc, gxdevice.h)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Printing didn't work in 32-bit MS Windows environments.
+(bcwin32.mak, gdevmswn.c, gp_mswin.c)
+ - There were some compatibility problems with IBM C. (os2.mak,
+gsdll.h, gdevpm.c, gp_os2.c)
+
+Adds the PNG drivers to the 32-bit MS Windows and OS/2 makefiles.
+(bcwin32.mak, os2.mak)
+
+Adds a conditional to work around a bug in gcc 2.7.x (it didn't recognize
+that the target of a const T * might still be mutable through aliasing).
+(stdpre.h)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Rasterizing a character in a Type 1 font with an invalid FontBBox
+left some garbage on the operand stack (bug introduced in 3.52 or 3.60).
+(gs_type1.ps)
+ - The font substitution algorithm could fail or loop. (gs_fonts.ps)
+
+Adds a little more support for CID fonts and CMaps. (gs_cidfn.ps,
+gs_cmap.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - An #include <memory_.h> was missing. (ziodev.h)
+ - Scanner-detected errors (primarily syntaxerror) didn't report the
+file position. (gs_init.ps)
+ - Rotated characters were rendered incorrectly (bug introduced in
+3.52). (gstype1.c)
+ - Some compilers got upset about the use of 'dict' as a variable
+name. (zdict.c)
+ - Operand stack overflows sometimes didn't set the "requested" field
+correctly. (interp.c)
+ - Using -dBufferSpace= with a non-printer device caused an error.
+(gs_init.ps)
+
+Adds zlibEncode/Decode filters. (int.mak, zfzlib.c)
+
+Separates devices from device prototypes. Prototypes, which lack the
+writable attribute, cannot be installed as the current device or have their
+parameters changed. This change allows Ghostscript to be exited and
+restarted without being reloaded, which solves some problems with DLL
+usage. ****** WE HAD TO SUBVERT THIS CHANGE BECAUSE OF MEMORY MANAGER
+PROBLEMS, by making zgetdevice return a writable reference to the
+prototype. (We finally fixed this in release 3.65.) (gs_init.ps, iref.h,
+opcheck.h, zdevice.c, ztype.c, zwppm.c)
+
+Extends the client API to allow for pushing values onto the operand stack.
+(imain.h, gs.c, gsmain.c)
+
+Defines a .setdefaultscreen procedure that sets the default halftone screen,
+transfer function, and stroke adjustment for the current device. Changes
+selectdevice and setpagedevice so that they call .setdefaultscreen;
+setpagedevice calls .setdefaultscreen before calling the Install procedure,
+so that Install can set different parameters if it wishes. Note that
+setdevice does not do this. (gs_init.ps, gs_setpd.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Tf set the current text font twice, and interacted with pdf2ps in
+an awkward way. (gs_pdf.ps, pdf_2ps.ps, pdf_font.ps)
+ - If a font had variant Widths, it could get confused in the cache
+with the underlying font. (pdf_font.ps)
+ - If a character appeared twice in an encoding and the font
+specified different Widths values for the two occurrences, the last Width
+would be used. We patched this to ignore zero Widths, which is not the
+correct solution but which almost always produces correct output.
+(pdf_font.ps)
+ - Arrays containing nulls didn't print out correctly (bug introduced
+in 3.60). (gs_init.ps)
+ - Some PDF files contain very large dictionaries, which caused a
+stackoverflow. (pdf_base.ps)
+
+Speeds up the initial processing of PDF files by caching the map from page
+numbers to page objects, and by not scanning the outlines if we aren't
+producing PostScript output. (pdf_2ps.ps, pdf_base.ps, pdf_main.ps)
+
+Streams
+-------
+
+Adds zlibEncode/Decode filters. (lib.mak, szlibx.h, szlibc.c, szlibd.c,
+szlibe.c)
+
+Library
+-------
+
+Fixes bugs:
+ - glyphshow displayed a character with code 0 rather than the
+requested character (bug introduced in 3.60.) (gschar.c)
+ - If trimming white space around a character reduced its raster, the
+character was garbled in the cache (bug introduced in 3.60.) (gxccman.c)
+ - colorimage would incorrectly convert white pixels to black if the
+image color space was CMYK, the current color space was not CMYK, and the
+number of bits per pixel was 4 or 8. (gsimage2.c)
+ - One of the clipping tests for images was backwards (bug introduced
+in 3.60). (gsimage.c)
+ - Type 1 fonts that used the Flex feature applied hints to the path
+multiple times, causing dropouts, uneven stems, and other problems (bug
+probably introduced in 3.21). (gstype1.c)
+ - If a Type 1 font used the Flex feature within the accent of an
+accented character defined with seac, the shape of the accent could be
+distorted. (gxtype1.h, gstype1.c)
+ - If a Type 1 font changed hints using the hint replacement facility
+when the last operation was a closepath, the old hints would be applied a
+second time, distorting the shape. (gxhint3.c)
+ - Band lists could read garbage beyond the end of data for a band,
+causing unpredictable errors (bug introduced in 3.60). (gxclread.c)
+ - If the bounding box of the path for fill_path or stroke_path went
+outside the device page boundary when banding, out-of-bounds memory
+references occurred (bug introduced in 3.60). (gxdevice.h, gxclpath.c)
+
+Adds an alternative implementation of the core path filling algorithm that
+is much faster on objects with curves but doesn't handle Y fattening. This
+is the implementation that will normally be used for rasterizing characters.
+This implementation rasterizes curves directly, without flattening them.
+(gxfixed.h, gxpath.h, gzpath.h, gsdps1.c, gxfill.c, gxpcopy.c, gxpdash.c)
+
+Speeds up the flattening of curves substantially by omitting more redundant
+points. (gxpcopy.c)
+
+Speeds up character bitmap compression a little more. (gsbitops.h,
+gdevabuf.c, gsbitops.c, gxccman.c)
+
+Speeds up anti-aliased graphics a bit by computing a bounding box before
+converting from oversampling to alpha values, and by speeding up the
+bounding box computation itself. (gsbitops.h, gdevabuf.c, gsbitops.c,
+gxccman.c)
+
+Version 3.60(limited) (11/20/95)
+=====================
+
+(Note: release numbers 3.54 through 3.59 were deliberately skipped.) This
+internal release includes a major redesign of band lists in order to reduce
+their size for embedded implementations, to move towards supporting "vector"
+output formats, and to further separate the imager library from the language
+interpreters.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A comment was incorrect. (viewpbm.ps)
+ - The PixelDifference filters were not documented. (language.doc)
+ - The change from currenttime to .currenttime wasn't documented.
+(language.doc)
+ - gs.1 incorrectly stated that the default font directory name
+included the version number. (gs.1)
+ - The -g and -r switches didn't specify that the units for their
+arguments are pixels and pixels per inch respectively. (use.doc)
+ - The PageOffset page device parameter wasn't listed.
+(language.doc)
+
+Changes copy_mono and copy_color to optional procedures. (drivers.doc)
+
+Adds a reference to ps_view.ps, a "dumb terminal" user interface for
+Ghostscript intended for MS-DOS users. (README)
+
+Splits off the documentation on installing Ghostscript into a separate file.
+(readme, install.doc, use.doc)
+
+Adds documentation on the data format produced by the standard LZWEncode
+filter. (readme, lzwce.doc)
+
+Clarifies XLIBDIR vs. XLIBDIRS. (make.doc)
+
+Adds user-contributed documentation on building Ghostscript under QNX.
+(make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The rule for building dfaxhigh.dev had a typo. (devs.mak)
+ - The dependencies for gdevpipe.h were missing errno__h and
+string__h. (unixtail.mak)
+ - The geninit program (the implementation of COMPILE_INITS=1) didn't
+parse the command line properly, and didn't check for PostScript files
+properly. (geninit.c)
+ - ccfontab.c was omitted from the fileset. The easiest way to fix
+this was to rename it to icfontab.c. (gs.mak, int.mak, ccfontab.c)
+ - The Unix makefiles installed caption.ls (a typo) rather than
+caption.ps. (unix-end.mak)
+ - XLIBDIR, for dynamic library access, wasn't defined. (*head.mak,
+*tail.mak, ugcclib.mak)
+
+Adds the PNG and ZLIB makefiles to the fileset. (*.mak, png.mak, zlib.mak,
+tar_cat)
+
+Puts the PixelDifference filters in the standard Level 2 set, since the LZW
+filters may invoke them (a post-Red Book addition to the PostScript language
+definition). (int.mak)
+
+Adds -Wcast-qual to the gcc compiler flags. (gcc-head.mak)
+
+Adds the PNG drivers to the standard Unix configurations.
+(ansi/cc-/gcc-head.mak)
+
+Adds a -dNOFONTPATH switch to suppress any consultation of the FONTPATH
+variable or the GS_FONTPATH environment variable. (gs_fonts.ps, gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The default scaling for viewing PBM files was computed
+incorrectly. (viewpbm.ps)
+ - ps2ascii left a value on the stack for each unrecognized character
+it processed, eventually causing a stackoverflow. (ps2ascii.ps)
+
+Changes viewpbm.ps so that it simply defines P1 through P6, allowing PBM
+files to be executed with 'run'. (viewpbm.ps)
+
+Adds a small benchmark to crudely measure hardware/system performance. The
+same file can either be compiled as a C program or executed as a PostScript
+program. (bench.c)
+
+Adds a few PPD files to the distribution. There will probably be more as
+time goes on. (tar_gs, unix-end.mak)
+
+Updates the Unix lpr scripts to handle a wider variety of device options.
+(unix-lpr.doc, lprsetup.sh, unix-lpr.sh)
+
+Adds a utility for converting files produced by Macromedia's Rollup program
+to a Type 0 form directly usable by Ghostscript. (rollconv.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Forwarding devices passed an incorrect first argument when
+forwarding a copy_rop operation. (gsdevice.c)
+ - Because of a typo, the LaserJet drivers had incorrect margins.
+This was probably a new bug in 3.5x. (gdevdjet.c)
+ - A private name was duplicated. (gdevtfax.c)
+ - The x11alpha driver passed invalid colors to the X library.
+(gdevxalt.c)
+ - The x11alpha driver set the blue component of colors incorrectly.
+(gdevxalt.c)
+ - Some `const' declarations were missing. (gdevtifs.c, gdevtfnx.c,
+gdevxxf.c)
+ - The size of A4 paper was slightly inconsistent across drivers.
+(gdevdjet.c, gdevl256.c)
+
+Provides default implementations of copy_mono and copy_color in terms of
+fill_rectangle. (gxdevice.h, gsdevice.c)
+
+Adds forwarders for sync_output and output_page. (gxdevice.h, gsdevice.c)
+
+Adds new optional procedures to the driver interface:
+ - fill_path for filling a path with a color;
+ - stroke_path for stroking a path;
+ - fill_mask for painting a color through a mask.
+The default implementations use the existing rasterizer algorithms. This
+involves a NON-BACKWARD-COMPATIBLE change to the parameters of a few
+internal routines:
+ gs_currentlineparams
+ gx_fill_path, gx_fill_path_only, gx_path_expand_dashes, gx_path_flatten
+and two externally visible routines not part of standard PostScript:
+ gs_setfilladjust, gs_currentfilladjust
+(gdevmem.h, gdevprn.h, gspath.h, gspenum.h, gxcpath.h, gxdevice.h, gxdraw.h,
+gxpaint.h, gxpath.h, gscoord.c, gsdevice.c, gspaint.c, gsstate.c,
+gxacpath.c, gxclist.c, gxclread.c, gxcpath.c, gxdraw.c, gxfill.c, gxpaint.c,
+gxpcmap.c, gxpcopy.c, gxstroke.c)
+
+Makes major changes to the dithering algorithm for the color DeskJet and
+BubbleJet drivers, contributed by a user. (gdevcdj.c)
+
+Adds a contributed 12-bit RGB TIFF driver. (gdevtfnx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The printjob created by Ghostscript was called "Ghostscirpt"
+instead of "Ghostscript". (gp_os2.c)
+ - An "export" declaration was omitted from DllInit. (gp_mswin.c)
+
+Removes gp_get_clock (its interface was changed from calendar
+days/milliseconds to epoch seconds/nanoseconds in an undocumented,
+NON-BACKWARD-COMPATIBLE change in 3.51), and adds a new gp_get_realtime
+procedure that returns epoch seconds/nanoseconds. This too is a
+NON-BACKWARD-COMPATIBLE change; it is required because we overlooked the
+prior change in a batch of user-contributed code. (gp.h, gp_*.c)
+
+Fonts
+-----
+
+Adds Heavy as a synonym for Bold when doing intelligent font substitution.
+(gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The setup for the CCITTFax filters set the 'raster' element
+redundantly. (zfdecode.c)
+ - currentscreen and currentcolorscreen could give an error if the
+current screen was set with sethalftone (or, for currentscreen,
+setcolorscreen). (gs_dps1.ps)
+ - The font operators didn't work properly if a PostScript file
+redefined certain operator names. (gs_res.ps)
+ - The CCITTFax filters imposed a limit of 9999 Rows or Columns. The
+new limit is 32000. (zfdecode.c)
+ - Streams could get removed from a bookkeeping list prematurely, and
+wind up dangling. (zfile.c)
+ - The garbage collector didn't ask for large enough a mark stack,
+and only used half of what it got. (This was only a performance problem.)
+(igc.c)
+ - Two private names duplicated names in a vendor library. (zbseq.c)
+ - Type 1 fonts didn't enforce the maximum value of BlueScale, which
+caused some faulty fonts produced by Fontographer to produce incorrect
+output. (zfont1.c)
+ - cvs / cvrs / = didn't produce Adobe-compatible output.
+(gs_init.ps, iutil.h, iutil.c, zfileio.c)
+ - Multiple -I switches set the search path incorrectly. (gsmain.c)
+ - Many `const' declarations were missing. (icie.h, idparam.h,
+iref.h, iutil.h, idparam.c, iinit.c, ilocate.c, iname.c, interp.c, iparam.c,
+iutil.c, zcie.c, zfile.c, zgstate.c, ziodev.c, ztype.c)
+ - Fonts could wind up with a pointer to the wrong VM space, causing
+potential GC or save/restore confusion. (zfont2.c)
+ - upath could leave garbage on the stack if it failed. (gs_dps1.ps)
+
+Speeds up rasterizing characters into the cache a little. (gs_type0.ps)
+
+Changes the default limit on the size of cached characters from the maximum
+of (18 points or 5 times the "average" character size) to (18 points or 1%
+of the total cache size). (gs_init.ps)
+
+Adds the DecodedByteAlign parameter to the CCITTFax filters. (zfdecode.c)
+
+Updates some code for compatibility with the new fill_path driver procedure.
+(zupath.c)
+
+Replaces .set/currentfilladjust with .set/currentfilladjust2, and defines
+the former in terms of the latter. (gs_init.ps, zgstate.c)
+
+Extends the make[word]imagedevice operators to accept palette values of 16,
+24, and 32, for creating true-color image devices. (zdevice.c)
+
+Changes realtime to match the definition of gp_get_realtime. (zmisc.c)
+
+Removes the [.]currenttime operator. realtime provides interval timing in
+milliseconds; the %Calendar% IODevice provides calendar times. (zmisc.c)
+
+Extends the LZW filters to handle the PDF Predictor (pixel-differencing)
+option. (zfdecode.c, zfilter2.c, zfpdiff.c (deleted))
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - The length of an image's data was sometimes calculated
+incorrectly, causing an error when converting PDF to PostScript.
+(pdf_draw.ps)
+ - If word spacing and/or text spacing was non-zero, an error could
+occur. (gs_pdf.ps)
+ - Text that was both filled and stroked caused an error.
+(gs_pdf.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - When closing an encoding filter stream whose target was also a
+filter, the latter could get called incorrectly with last = 1, possibly more
+than once, leading to premature EOD markers. (stream.c)
+ - The LZW-compatible encoder put out an incorrect end-of-data code.
+(slzwce.c)
+ - The LZW-compatible encoder didn't put out a reset code soon
+enough. (slzwce.c)
+ - Some `const' declarations were missing. (siscale.c)
+ - Doing a sgets on a closed stream could call sreadbuf, possibly
+causing an error. (stream.c)
+
+Adds a new (optional) set_defaults procedure to the stream template, which
+sets the stream parameters to default values. We only implement it for a
+few stream types. (scfx.h, scommon.h, slzwx.h, spdiffx.h, srlx.h,
+strimpl.h, scfd.c, scfe.c, slzwce.c, slzwd.c, slzwe.c, spdiff.c, srld.c,
+srle.c)
+
+Adds a new parameter to the CCITTFax filters, DecodedByteAlign. This is an
+integer N, which must be a power of 2 between 1 (2^0) and 16 (2^4), that
+specifies that decoded data scan lines are always a multiple of N bytes.
+The encoding filter skips data in each scan line from Columns to the next
+multiple of N bytes; the decoding filter pads each scan line to a multiple
+of N bytes. Default value: 1. (scfx.h, scfd.c, scfe.c)
+
+Increases the maximum width of a scan line for the CCITTFaxEncode filter to
+32000 pixels. (scf.h)
+
+Library
+-------
+
+Fixes bugs:
+ - Cached characters sometimes had extra blank space on the left,
+leading to some unnecessary bit-shuffling when imaging them. (gxccman.c)
+ - In rare cases, gray halftones called gx_color_load unnecessarily.
+(gxdither.c)
+ - The list of all-bands commands wasn't initialized/reset properly.
+(gxclist.c, gxclread.c)
+ - Rendering an anti-aliased character to a non-anti-aliased device
+didn't free the temporary bitmap, causing memory to be lost. (gxccache.c)
+ - Dash patterns where the offset exactly reached a run of length 0
+skipped over the 0-length run. (gsline.c)
+ - Rectangles closed with both lineto and closepath weren't
+recognized as rectangles. This is only a performance bug. (gxpath2.c)
+ - Because of a typo in a macro formal parameter list, a private name
+was duplicated. (gsstruct.h)
+ - Text display operations didn't update the current character in the
+enumerator structure during the fastest path through the code. This only
+matters to one very unusual commercial client. (gschar.c)
+ - Some `const' declarations were missing. (gsparam.h, gxistate.h,
+stdpre.h; gdevm1.c, gsalloc.c, gsfont.c, gsimage3.c, gsmemory.c, gsmisc.c,
+gspcolor.c, gstype1.c, gxfill.c, gxpcopy.c)
+
+Changes the header files to assume that gcc on Solaris defines
+__svr4__ and that, in this case, <string.h> has the right stuff in it.
+(memory_.h)
+
+Refactors the character cache to share structures with a similar cache
+used by band lists. Eventually the band list may be able to reference
+the character cache directly, saving a lot of copying. (gxbcache.h,
+gxfcache.h, gsfont.c, gxbcache.c, gxccache.c, gxccman.c)
+
+Speeds up getting the side bearing and width of a Type 1 charstring a
+little. (gxtype1.h, gstype1.c)
+
+Redesigns band lists so that they can cache character bitmaps as well as
+halftone bitmaps. Characters may be written for all bands, not just the
+band(s) they appear in, depending on the setting of the CHAR_ALL_BANDS_COUNT
+parameter in gxclbits.c. (gxcldev.h, gxclist.h, gxclbits.c, gxclist.c,
+gxclread.c)
+
+Adds G4 fax compression for band list bitmaps. (gxcldev.h, gxclist.c,
+gxclread.c)
+
+Incorporates the new set_defaults procedure into the memory-based band list
+implementation. (gxclmem.c)
+
+Implements a halftoning device that can be used in a device pipeline.
+(gdevht.h, gzht.h, gdevht.c, gxcht.c)
+
+Factors out imager state from the full graphics state. This division is
+preliminary and subject to change. (gxistate.h, gxop1.h, gzstate.h,
+gsline.c, gsstate.c, gstype1.c, gxhint*.c)
+
+Implements passing fill operations in the band list, except for pattern
+color or colored halftones. (gxcldev.h, gxclist.h, gxclist.c, gxclread.c)
+
+Implements passing stroke operations in the band list, except for pattern
+color or colored halftones. (gsline.h, gslparam.h, gxline.h, gzline.h,
+gsline.c; gxcldev.h, gxclist.h, gxclist.c, gxclread.c)
+
+Implements the ability to represent halftoned characters in the band list.
+(gxccache.c)
+
+Starts to implement the ability to do halftoning during the rendering phase
+rather than before writing the band list (currently for black-and-white
+devices only). Doing this required NON-BACKWARD-COMPATIBLE changes to the
+interfaces of a few internal procedures:
+ gx_check_tile_size, gx_render_device_{color,gray}
+(gxdcolor.h, gxdht.h, gzht.h, gsht.c, gsimage1.c, gsmisc.c, gspcolor.c,
+gsstate.c, gxcht.c, gxclbits.c, gxdither.c, gxht.c)
+
+Implements passing clipping information in the band list. (gzcpath.h,
+gxacpath.c, gxclpath.c, gxclread.c, gxcpath.c)
+
+Removes the gs_state * parameter from the device color fill_rectangle
+procedures and many of their callers, since it is no longer needed. This is
+a non-backward-compatible change to an internal API. (gdevmrop.h,
+gxdcolor.h, gxdraw.h, gxpaint.h, gdevmrop.c, gsimage.c, gspcolor.c, gxcht.c,
+gxclread.c, gxdraw.c, gxfill.c, gxht.c, gxpaint.c, gxstroke.c)
+
+Removes gxdevice.h from gzstate.h, since not all modules requiring access to
+the graphics state need to know the implementation of devices. This entails
+adding gxdevice.h to the include lists for some modules. (gxchar.h,
+gxcpath.h, gxcvalue.h, gxdevice.h, gxtype1.h, gzstate.h; gschar.c,
+gscoord.c, gsdevice.c, gsimage1.c, gsimage2.c, gsimage3.c, gspaint.c,
+gspath.c, gsstate.c, gstype1.c, gxccache.c, gxccman.c, gxhint1.c, gxhint2.c,
+gxhint3.c, gxpaint.c)
+
+Adds a compile-time option, ALPHA_LSB_FIRST, which causes alpha-sampled
+characters to be nibble-reversed in the cache. This was created for a
+specialized application and does not interact well with the rest of the
+code. (gsbitops.c)
+
+Substantially reduces the space required to represent 24- or 32-bit colors
+in the band list, by using more aggressive color differencing. (gxcldev.h,
+gxclist.c, gxclread.c)
+
+Changes the allocation of unique IDs for halftone tiles to use the gray
+level rather than the number of 1-bits as the increment to a base ID; this
+allows more efficient (delta) representation of halftone indices in the band
+list. (gxcldev.h, gxclist.c, gxclread.c, gxht.c)
+
+Substantially speeds up entering anti-aliased characters in the cache, by
+removing white space before compressing rather than vice versa.
+(gsbitops.c, gxccman.c)
+
+Version 3.53 (1/10/96)
+============
+
+This is an anomalous, out-of-sequence release requested by a commercial
+licensee. It consists of 3.52 plus the following retrofits from 3.60
+through 3.63:
+ - PDF interpreter and pdf2ps;
+ - Type 1 rasterizer fixes;
+ - Type 1 rasterizer and polygon fill performance improvements;
+ - MS Windows and OS/2 fixes;
+ - A few other important fixes.
+It does NOT fix all problems reported since 3.52.
+
+The list of changes below indicates which subsequent release was the source
+of each change. In several cases, minor editing of the change was required
+to make it compatible with 3.52.
+
+Documentation
+-------------
+
+Fixes bugs:
+ [3.61] The analysis of curve monotonocity in gxpcopy.c had an error.
+(gxpcopy.c)
+
+[3.63] Notes that the OS/2 implementation now requires EMX/GCC 0.9b rather
+than 0.9a. (use.doc)
+
+[3.62] Notes that for Win32s, gs16spl.exe must be in the same directory as
+gswin32.exe. (use.doc)
+
+[3.62] Adds a reference to dos-psv, another "dumb terminal" user interface
+for Ghostscript intended for MS-DOS users. (README)
+
+[3.61] Adds a pointer to DEC's free pstotext utility. (README)
+
+[3.60] Adds a reference to ps_view.ps, a "dumb terminal" user interface for
+Ghostscript intended for MS-DOS users. (README)
+
+Procedures
+----------
+
+Fixes bugs:
+ [3.60] The geninit program (the implementation of COMPILE_INITS=1)
+didn't parse the command line properly, and didn't check for PostScript
+files properly. (geninit.c)
+ [3.60] ccfontab.c was omitted from the fileset. The easiest way to
+fix this was to rename it to icfontab.c. (gs.mak, int.mak, ccfontab.c)
+ [3.60] The definition of pdfread.dev did an ADDMOD, not a SETMOD.
+(int.mak)
+
+[3.60] Adds a -dNOFONTPATH switch to suppress any consultation of the
+FONTPATH variable or the GS_FONTPATH environment variable. (gs_fonts.ps,
+gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ [3.61] pdf2ps didn't write Widths or Encoding in the converted file,
+producing incorrect spacing and incorrect characters. (pdf_2ps.ps)
+ [3.60] ps2ascii left a value on the stack for each unrecognized
+character it processed, eventually causing a stackoverflow. (ps2ascii.ps)
+
+[3.61] Changes the rollconv.ps utility to produce files whose names conform
+to the 8.3 length restriction, and to reduce the fixed RAM overhead for
+Kanji fonts. (rollconv.ps)
+
+[3.60] Adds a utility for converting files produced by Macromedia's Rollup
+program to a Type 0 form directly usable by Ghostscript. (rollconv.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ [3.60] Because of a typo, the LaserJet drivers had incorrect
+margins. This was probably a new bug in 3.5x. (gdevdjet.c)
+ [3.60] A private name was duplicated. (gdevtfax.c)
+ [3.60] The x11alpha driver passed invalid colors to the X library.
+(gdevxalt.c)
+ [3.60] The x11alpha driver set the blue component of colors
+incorrectly. (gdevxalt.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ [3.63] The test for WinExec failure on Win32 was incorrect.
+(gp_mswin.c)
+ [3.63] getenv was declared redundantly on OS/2. (gp_os2.c)
+ [3.63] gs16spl.c was missing <string.h>. (gs16spl.c)
+ [3.61] Printing didn't work in 32-bit MS Windows environments.
+(bcwin32.mak, gdevmswn.c, gp_mswin.c)
+ [3.61] There were some compatibility problems with IBM C. (os2.mak,
+gsdll.h, gdevpm.c, gp_os2.c)
+ [3.60] The printjob created by Ghostscript was called "Ghostscirpt"
+instead of "Ghostscript". (gp_os2.c)
+ [3.60] An "export" declaration was omitted from DllInit.
+(gp_mswin.c)
+
+[3.61] Adds a conditional to work around a bug in gcc 2.7.x (it didn't
+recognize that the target of a const T * might still be mutable through
+aliasing). (stdpre.h)
+
+Fonts
+-----
+
+Fixes bugs:
+ [3.61] Rasterizing a character in a Type 1 font with an invalid
+FontBBox left some garbage on the operand stack (bug introduced in 3.52 or
+3.60). (gs_type1.ps)
+ [3.61] The font substitution algorithm could fail or loop.
+(gs_fonts.ps)
+
+[3.60] Adds Heavy as a synonym for Bold when doing intelligent font
+substitution. (gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ [3.63] Invoking setpagedevice with an undefined key, even with
+Policy = 1, caused an error. (gs_setpd.ps)
+ [3.62] Setting the PageSize policy to 1 and then trying to set the
+page size caused an error if FIXEDMEDIA was selected. (gs_setpd.ps)
+ [3.61] Rotated characters were rendered incorrectly (bug introduced
+in 3.52). (gstype1.c)
+ [3.60] currentscreen and currentcolorscreen could give an error if
+the current screen was set with sethalftone (or, for currentscreen,
+setcolorscreen). (gs_dps1.ps)
+ [3.60] Streams could get removed from a bookkeeping list
+prematurely, and wind up dangling. (zfile.c)
+ [3.60] Multiple -I switches set the search path incorrectly.
+(gsmain.c)
+ [3.60] Fonts could wind up with a pointer to the wrong VM space,
+causing potential GC or save/restore confusion. (zfont2.c)
+ [3.60] upath could leave garbage on the stack if it failed.
+(gs_dps1.ps)
+
+[3.61] Extends the client API to allow for pushing values onto the operand
+stack. (imain.h, gs.c, gsmain.c)
+
+[3.61] Defines a .setdefaultscreen procedure that sets the default halftone
+screen, transfer function, and stroke adjustment for the current device.
+Changes selectdevice and setpagedevice so that they call .setdefaultscreen;
+setpagedevice calls .setdefaultscreen before calling the Install procedure,
+so that Install can set different parameters if it wishes. Note that
+setdevice does not do this. (gs_init.ps, gs_setpd.ps)
+
+[3.60] Speeds up rasterizing characters into the cache a little.
+(gs_type0.ps)
+
+[3.60] Changes the default limit on the size of cached characters from the
+maximum of (18 points or 5 times the "average" character size) to (18 points
+or 1% of the total cache size). (gs_init.ps)
+
+[3.60] Implements parts of the Type 1 BuildChar callout in C. (gs_type1.ps,
+zchar.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ [3.62] If a PDF file substituted a calibrated color space for the
+DeviceGray or DeviceRGB color space using a ColorSpace resource, the
+PostScript file that pdf2ps produced from that PDF file caused an error.
+(gs_pdf.ps)
+ [3.61] Tf set the current text font twice, and interacted with
+pdf2ps in an awkward way. (gs_pdf.ps, pdf_2ps.ps, pdf_font.ps)
+ [3.61] If a font had variant Widths, it could get confused in the
+cache with the underlying font. (pdf_font.ps)
+ [3.61] If a character appeared twice in an encoding and the font
+specified different Widths values for the two occurrences, the last Width
+would be used. We patched this to ignore zero Widths, which is not the
+correct solution but which almost always produces correct output.
+(pdf_font.ps)
+ [3.61] Arrays containing nulls didn't print out correctly (bug
+introduced in 3.60). (gs_init.ps)
+ [3.61] Some PDF files contain very large dictionaries, which caused
+a stackoverflow. (pdf_base.ps)
+ [3.60] The length of an image's data was sometimes calculated
+incorrectly, causing an error when converting PDF to PostScript.
+(pdf_draw.ps)
+ [3.60] If word spacing and/or text spacing was non-zero, an error
+could occur. (gs_pdf.ps)
+ [3.60] Text that was both filled and stroked caused an error.
+(gs_pdf.ps)
+
+[3.61] Speeds up the initial processing of PDF files by caching the map from
+page numbers to page objects, and by not scanning the outlines if we aren't
+producing PostScript output. (pdf_2ps.ps, pdf_base.ps, pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ [3.60] When closing an encoding filter stream whose target was also
+a filter, the latter could get called incorrectly with last = 1, possibly
+more than once, leading to premature EOD markers. (stream.c)
+ [3.60] The LZW-compatible encoder put out an incorrect end-of-data
+code. (slzwce.c)
+ [3.60] The LZW-compatible encoder didn't put out a reset code soon
+enough. (slzwce.c)
+ [3.60] Doing a sgets on a closed stream could call sreadbuf,
+possibly causing an error. (stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ [3.63] On 16-bit platforms, the computation of t2 and t3 in
+gx_curve_x_at_y could overflow, leading to incorrect output. (gxpcopy.c)
+ [3.61] glyphshow displayed a character with code 0 rather than the
+requested character (bug introduced in 3.60.) (gschar.c)
+ [3.61] If trimming white space around a character reduced its
+raster, the character was garbled in the cache (bug introduced in 3.60.)
+(gxccman.c)
+ [3.61] colorimage would incorrectly convert white pixels to black if
+the image color space was CMYK, the current color space was not CMYK, and
+the number of bits per pixel was 4 or 8. (gsimage2.c)
+ [3.61] Type 1 fonts that used the Flex feature applied hints to the
+path multiple times, causing dropouts, uneven stems, and other problems (bug
+probably introduced in 3.21). (gstype1.c)
+ [3.61] If a Type 1 font used the Flex feature within the accent of
+an accented character defined with seac, the shape of the accent could be
+distorted. (gxtype1.h, gstype1.c)
+ [3.61] If a Type 1 font changed hints using the hint replacement
+facility when the last operation was a closepath, the old hints would be
+applied a second time, distorting the shape. (gxhint2.c, gxhint3.c)
+ [3.60] Cached characters sometimes had extra blank space on the
+left, leading to some unnecessary bit-shuffling when imaging them.
+(gxccman.c)
+ [3.60] The list of all-bands commands wasn't initialized/reset
+properly. (gxclist.c)
+ [3.60] Because of a typo in a macro formal parameter list, a private
+name was duplicated. (gsstruct.h)
+ [3.60] Text display operations didn't update the current character
+in the enumerator structure during the fastest path through the code. This
+only matters to one very unusual commercial client. (gschar.c)
+
+[3.61] Adds an alternative implementation of the core path filling algorithm
+that is much faster on objects with curves but doesn't handle Y fattening.
+This is the implementation that will normally be used for rasterizing
+characters. This implementation rasterizes curves directly, without
+flattening them. (gxfixed.h, gxpath.h, gzpath.h, gxdraw.c, gxfill.c,
+gxpcopy.c)
+
+[3.61] Speeds up the flattening of curves substantially by omitting more
+redundant points. (gxpcopy.c)
+
+[3.61] Speeds up character bitmap compression a little more. (gsbitops.h,
+gdevabuf.c, gsbitops.c, gxccman.c)
+
+[3.61] Speeds up anti-aliased graphics a bit by computing a bounding box
+before converting from oversampling to alpha values, and by speeding up the
+bounding box computation itself. (gsbitops.h, gdevabuf.c, gsbitops.c,
+gxccman.c)
+
+[3.60] Speeds up getting the side bearing and width of a Type 1 charstring a
+little. (gxtype1.h, gstype1.c)
+
+[3.60] Adds a compile-time option, ALPHA_LSB_FIRST, which causes
+alpha-sampled characters to be nibble-reversed in the cache. This was
+created for a specialized application and does not interact well with the
+rest of the code. (gsbitops.c)
+
+[3.60] Substantially speeds up entering anti-aliased characters in the
+cache, by removing white space before compressing rather than vice versa.
+(gsbitops.c, gxccman.c)
+
+Version 3.52(limited) (10/6/95)
+=====================
+
+This is an incremental release to fix a few problems in 3.51. Since it is
+being made in an environment with no network connectivity, it will probably
+not be released to the general public. ****** THE CHANGES MARKED WITH ***
+BELOW WERE LOST IN THE PROCESS OF SHUFFLING FILESETS BETWEEN ENVIRONMENTS.
+THEY ARE INCORPORATED IN 3.60 BUT NOT IN 3.52. ******
+
+Procedures
+----------
+
+Fixes bugs:
+ - The fileset included a meaningless empty file. (acctest.ps)
+ *** The definition of pdfread.dev did an ADDMOD, not a SETMOD.
+(int.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The RunLengthEncode filter used with a dictionary argument could
+give a spurious error. (zfilter.c)
+ - The fast form of the 'dup' operator failed to check for stack
+overflow, which could lead to memory smashing. (interp.c)
+ *** Level 1 configurations gave errors during initialization.
+(ialloc.c, iinit.c, ireclaim.c)
+ *** Attempting to look up or insert a noaccess string as a
+dictionary key converted the string to a name rather than giving an error.
+(idict.h, idict.c)
+
+Adds a C implementation of the .dicttomark (>>) procedure. (gs_init.ps,
+zdict.c)
+
+*** Implements parts of the Type 1 BuildChar callout in C. (gs_type1.ps,
+ifont.h, zchar.c, zfont1.c, zfont2.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Braces were missing in an initializer. (gxdcolor.h)
+ - Composite fonts with a non-zero translation in the FontMatrix
+positioned characters incorrectly. (gschar.c)
+ *** gsparam.c wouldn't compile with some versions of the Borland
+compiler. (gsparam.c)
+
+Speeds up the handling of curve segments in Type 1 fonts a little.
+(gstype1.c)
+
+Speeds up displaying very short strings a little. (gschar.c)
+
+*** Implements parts of the Type 1 BuildChar callout in C. (gxfont.h)
+
+Version 3.51 (9/27/95)
+============
+
+This is the first public release since 3.33. Its main features are a
+working setpagedevice, a working PDF interpreter, and a working PDF to PS
+converter.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The -dSHORTERRORS switch wasn't documented in enough places.
+(current.doc, use.doc)
+ - The DLL documentation was internally inconsistent. (dll.doc)
+ - The %pipe% file name syntax wasn't documented. (language.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - caption.ps wasn't installed properly. (unix-end.mak)
+ - geninit depended on $(gconfig_h) in an improper way. (geninit.c,
+int.mak, *.mak)
+ - One script lacked the #!/bin/sh header. (gsdj500)
+
+Adds the 24-bit color TIFF driver to all configurations that support
+black-and-white TIFF. (*.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - align.ps was omitted from the fileset. (psfiles.doc, align.ps,
+unix-end.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A driver had some \s in formal parameter lists. (gdevcdj.c)
+ - A driver had some improper &s. (gdevtifs.c)
+ - The default MS Windows printer driver was very slow. (gdevwpr2.c)
+ - The (newly restructured) TIFF drivers could produce a memory
+access error. (gdevtifs.c)
+ - The CGM drivers referred to an obsolete structure member.
+(gdevcgm.c)
+ - The black-and-white H-P drivers didn't set the margins properly
+(again). (gdevdjet.c)
+ - Several of the most common printer drivers omitted some scan lines
+at the bottom of the page. (gdevprn.h, gdevprn.c)
+
+At the request of the main OS/2 developer, adds a printer device for OS/2.
+(gdevos2p.c, os2.mak)
+
+Makes many changes to the stcolor driver, submitted by the developer just
+before the release. (devices.doc, unix-end.mak, gdevstc.h, gdevstc*.c,
+stcinfo.ps, stcolor.ps, stcinfo.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - usertime (and realtime) were broken on VMS. (gp_vms.c)
+ - The 32-bit MS Windows DLL control file had a typo. (gsdll32.def)
+
+Removes the color inkjet drivers from the 16-bit Windows executable, because
+they overflow the 64K default data segment; adds PCX, TIFF, and BMP output
+formats. (bcwin.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A routine was declared 'private' inconsistently. (zcie.c)
+ - -dSHORTERRORS didn't remove enough non-Adobe error output.
+(gs_init.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - The ProcSet relied on the presence of NullFont. (gs_pdf.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - There was an extraneous \ outside a macro. (gsline.c)
+ - Scaling up a black-and-white image could caused many scan lines to
+be inverted. (gsimage1.c)
+ - The initial clipping path did not take Margins into account
+properly. (gxdevice.h, gdevxalt.c, gscoord.c, gsdevice.c, gsdevmem.c,
+gsdparam.c, gspath.c)
+ - If banding was required, characters could come out as solid black
+rectangles. (gxclist.c, gxclread.c)
+
+Version 3.50(limited) (9/24/95)
+=====================
+
+This is the last limited bug-fix release during beta test. The color
+DeskJet drivers are broken (they sometimes produce black rectangles instead
+of characters); we will fix this in the next release.
+
+The following issues have been postponed to an unspecified future release:
+ - Filling areas often writes pixels twice, causing incorrect output
+with certain unusual RasterOp values. [1.814]
+ - The tar.gz archives should include a subdirectory like gs-3.46/ in
+the file names.
+ - The CCITTFaxDecode filter should skip initial junk if EndOfLine =
+true. [1844 8/24/95, NRE]
+
+Procedures
+----------
+
+Fixes bugs:
+ - The name of the new 24-bit TIFF driver was incorrect in one place.
+(vms.mak)
+
+Utilities
+---------
+
+Adds a new utility to put a caption in a box at the bottom of each page.
+(caption.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PC display devices weren't page devices. Probably all the
+other display and window system devices should be made page devices too, but
+we aren't going to bother tracking them down. (gdevpcfb.c)
+ - There was a lot of duplicated code in the TIFF drivers.
+(gdevtifs.h, gdevtfax.c, gdevtfnx.c, gdevtifs.c)
+
+Updates the bjc600 / bjc800 drivers with changes from the author.
+(devices.doc, gdevbjc.h, gdevcdj.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Building with COMPILE_INITS=1 produced a stackunderflow error.
+(gs_pdf_e.ps)
+ - An internal operator didn't have a name. (ztoken.c)
+ - Some error and information messages weren't in the Adobe format.
+(gs_fonts.ps, gs_init.ps)
+ - Some common Adobe compatibility operators weren't implemented:
+pagemargin, pageparams, setpagemargin. (gs_statd.ps, gs_lev2.ps)
+ - setpageparams set Margins rather than PageOffset. (gs_lev2.ps)
+ - setpage and setpageparams didn't set Orientation. (gs_lev2.ps)
+ - If the end of an input buffer fell just after the / of a literal
+name, a memory access error could occur. (iscan.c)
+ - When the interpreter returned from gs_[main_]run_string_continue,
+there could be an extra value on the operand stack. (iscan.h, istream.h,
+interp.c, iscan.c, zfileio.c, zfproc.c, zpaint.c, ztoken.c)
+ - If the character cache was disabled, or if a character was too
+large to be cached, returning from a font BuildChar procedure could do an
+erasepage. (zchar.c)
+
+A minor change was required for compatibility with the library change for
+image devices. (zdevice.c)
+
+Adds a -dSHORTERRORS switch that changes some of the common error and
+warning messages for greater Adobe compatibility. (gs_init.ps, gs_fonts.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - If a CharProc for a Type 3 font did a BT/ET, the graphics state
+could get confused. (gs_pdf.ps)
+ - If a Tf occurred inside a BT/ET, it didn't take effect on
+subsequent BT/ETs. (gs_pdf.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - There was no way to control whether an image device was a page
+device. Fixing this required a NON-BACKWARD-COMPATIBLE CHANGE to
+gs_makewordimagedevice and gs_initialize_wordimagedevice to take a Boolean
+page_device argument. Fortunately, this change affects only a few obscure
+library clients. (gsdevice.h, gsdevmem.c)
+
+Adds translation capability to clipping devices. This isn't used anywhere
+yet. (gxcpath.h, gxcpath.c)
+
+Adds procedures for doing unaligned copy_xxx operations. These were added
+for a customer. (gxdevice.h, gsdevice.c)
+
+Changes the (undocumented) return value of gs_setcachedevice[2]: they used
+to return 1 if the current show operation was a non-displaying one
+(stringwidth or cshow), and now return 1 if the cache device was just
+installed. This change was required to fix the BuildChar page clearing bug
+in the interpreter. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE, but as far as
+I know, there aren't any external clients of these routines. (gschar.h,
+gschar.c)
+
+Version 3.49(limited) (9/20/95)
+=====================
+
+This is another bug-fix release during beta test. There are other bugs
+outstanding, but the ones I know about right now are all platform-specific.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - make.doc didn't mention that the .def files are needed to build a
+MS Windows executable. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - There were some forward references to macro definitions in the
+makefiles. (int.mak, lib.mak)
+ - The default device for library configurations was the null page
+device, not the first device in DEVICE_DEVS. (ugcclib.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The BJC600 / BJC800 drivers were missing a header file.
+(gdevbjc.h, gdevcdj.c)
+ - A procedure name was used in two different files. (gdevcdj.c)
+ - The PCX driver didn't return an error code in case of failure.
+(gdevpcx.c)
+ - The X Windows driver produced some confusing warning messages.
+(gdevxini.c)
+ - Some names were duplicated between drivers. (gdevepsc.c)
+ - The X driver maintained its own, peculiar initial matrix even if
+Ghostview wasn't involved. (gdevx.c)
+
+With the permission of the author, changes the 24-bit TIFF license from GNU
+to Aladdin. (gdevtfnx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS build scripts were out of sync with the makefiles (again).
+(modules.lis, vms.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - When the requested media size matched an available size exactly
+with a 90 degree rotation, Orientation was ignored. (zmedia2.c)
+
+Makes zcurrentdevice extern. (opextern.h, zdevice.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A couple of places used memcpy instead of memmove. (gxclread.c)
+ - If a bitmap image was compressed with RLE compression in a band
+list, it would cause an error on decompression. (gxclread.c)
+ - The representation of colors in the band list was needlessly
+inefficient. (gxcldev.h, gxclist.c, gxclread.c)
+ - When using colored halftones, snowflak.ps crashed with an invalid
+memory access. More generally, any use of halftones could cause the garbage
+collector to make an invalid access. (gsstate.c)
+
+Adds some more code for paths in band lists, but again doesn't activate it.
+(gxcldev.h, gxpath.h, gzline.h, gsline.c, gspath1.c, gxclist.c, gxclread.c,
+gxpath.c)
+
+Version 3.48(limited) (9/17/95)
+=====================
+
+This is the second bug-fix release during beta test. Among other things, it
+fixes a bug introduced in 3.47 that caused all PDF files to give an error.
+******NOTE: the BJC600 and BCJ800 drivers do not work in this release,
+because we didn't get a file from the author in time. They will compile,
+but not run. This will be fixed in the next round.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Alan Barclay's contact information was wrong. (README)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The linker path for Watcom C++ 10.5 was wrong. (wccommon.mak)
+ - There was a syntax error in a batch file. (pdf2ps.bat)
+ - The VMS build script didn't have entries for some printers.
+(vms.mak)
+
+Adds the bjc600 and bjc800 devices on all platforms that already include the
+color DeskJet devices. (*.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The H-P drivers didn't reposition the cursor properly at the
+beginning of pages after the first page, causing the image to be shifted
+down slightly and cut off at the bottom. (gdevdjet.c)
+ - The x11alpha driver was extremely slow. (gdevxalt.c)
+ - The -g switch by itself didn't work for the X Windows driver.
+(gdevxini.c)
+ - .installpagedevice can get a rangecheck on MS Windows because the
+HWColorMap can change spontaneously. (gs_setpd.ps)
+
+Updates the bjc600 and bjc800 drivers with new versions from Yves Arrouye.
+(gdevcdj.c)
+
+Adds a user-contributed driver that writes uncompressed 24-bit RGB TIFF
+images in a format that is standard on NeXT platforms. This driver is
+governed by the GNU license and is therefore separated from the rest of the
+Aladdin distribution. (gdevtfnx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - There was an undefined reference to clock_gettime on some Unix
+systems. (gp_unix.c)
+ - The new gp_fopen routine had several errors. (gp_vms.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Some routines that should be main-instance-specific weren't.
+(imain.h, main.h, gsmain.c)
+ - sethalftone with a Type 2 or Type 4 halftone didn't work on CMYK
+devices. (zht2.c)
+ - Setting A4 paper as the default in gs_init.ps, or specifying
+-dPAPERSIZE, conflicted with -g. (gs_init.ps)
+ - The maximum value of a single-precision float wasn't correct on
+VAX systems. (math_.h, iscannum.c)
+ - Some integer expressions were passed as floating point arguments.
+(gs.c, zmedia2.c)
+ - Media selection in setpagedevice was broken (again), as of 3.46.
+(gs_setpd.ps, zmedia2.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Substituted color spaces caused an error. (gs_pdf.ps,
+pdf_draw.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - If a halftone had no non-default components that matched the
+device's primary colors, the result would be a solid color rather than a
+halftone using the default screen. (gsht.c)
+ - sethalftone with a Type 2 or Type 4 halftone didn't work on CMYK
+devices. (gxht.h, gsht.c, gsht1.c)
+ - The new gp_fopen routine wasn't being used. (gsiodev.c)
+ - A mixing of float and fixed values caused a clipping region to be
+possibly incorrect by up to 1 pixel. (gspaint.c)
+ - A function definition was inconsistent with the prototype.
+(gspath1.c)
+
+Adds preliminary code for including paths in band lists, but doesn't
+activate any of it. (lib.mak, gxcldev.h, gxclist.c, gxclread.c)
+
+Version 3.47(limited) (9/14/95)
+=====================
+
+This is a bug-fix release during beta test. It is meant to have no new
+functionality, although in the case of setpagedevice that's stretching
+things a little.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The Mac documentation still referred to IJG JPEG v5a rather than
+v6. (make.doc)
+ - The RasterOp texture device was identified incorrectly.
+(gdevmrop.c)
+ - use.doc and psfiles.doc didn't mention the PDF-related files.
+(psfiles.doc, use.doc)
+ - psview is no longer available. (README)
+ - current.doc didn't document the recognized setpagedevice keys.
+(current.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Many utility programs weren't included in the Unix 'install' list.
+(unix-end.mak)
+ - It wasn't at all convenient to make configurations without the BCP
+or other non-standard filters. (*.mak, int.mak, modules.lis, zfilter2.c,
+zfilterx.c)
+ - The gconfig.c and iconfig.c files weren't deleted after
+compilation. (int.mak, lib.mak)
+ - unix-end.mak referred to the nonexistent macros INT{1,2}_MAK.
+(unix-end.mak)
+ - The rules for building the dfax drivers were incorrect. (devs.mak)
+ - Omitting filter.dev produced an undefined reference. (int.mak)
+
+Adds a customer-contributed makefile for Microsoft Visual C++ 2.n under
+Windows NT. (msvcwint.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The JPEG utility didn't support the new progressive JPEG modes,
+and didn't invert Adobe Photoshop output as needed. (viewjpeg.ps)
+ - The printafm utility had a single font name wired in. (printafm,
+printafm.ps)
+ - The CIE lookup simulation had several bugs. (docie.ps)
+ - pdf2ps[.bat] were missing from the fileset.
+ - Files produced by pdf_2ps didn't include the GS_PDF ProcSet.
+(gs_pdf.ps, pdf_2ps.ps, pdf_base.ps, pdf_main.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Bits read back from an EGA or VGA device were incorrect.
+(gdevpcfb.c)
+ - The 24-bit PCX run length compressor used a slow algorithm.
+(gdevpcx.c)
+ - gdevstc.c wouldn't compile with the Borland compiler. (gdevstc.c)
+ - There was a typo in the OS/2 PM driver. (gdevpm.c)
+ - .installpagedevice gets a rangecheck on X Windows because the
+HWColorMap can change spontaneously. (gs_setpd.ps)
+ - The left margin for the DeskJet 500 was wrong. (gdevdjet.c)
+ - The two notions of "margin" (offset of 0,0 from physical page
+corner vs. unprintable area around edges of physical page) were still
+confused. We've now fixed this for the H-P monochrome printers, but it's
+probably still confused for all other printers. (gdevprn.h, gdevdjet.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The Windows print spooler header file wasn't included when it
+needed to be, and some other Win32-specific changes were missing.
+(gsdll32.def, gp_mswin.c)
+ - Windows DLLs didn't parse "s in the command "arguments" correctly.
+(gsdll.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - FAKEFONTS could get the font directories into inconsistent states.
+(gs_dps1.ps, gs_fonts.ps)
+ - The substitutions for Adobe's Myriad and Minion fonts weren't
+appropriate. (gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - If pathforall got an error computing the user-space points on a
+path, it could cause an invalid access. (zpath1.c)
+ - A 'private' declaration were omitted. (Why doesn't gcc catch
+this??) (zcie.c)
+ - Setting GS_FONTPATH produced a stackunderflow error.
+(gs_fonts.ps)
+ - currentscreen caused a typecheck if the screen had been set by
+setcolorscreen. (gs_dps1.ps)
+ - setcolorrendering tried to cache values computed from the color
+space even if the current color space wasn't a CIE space. (zcrd.c)
+ - Out-of-range numbers like 10E38 caused a floating point exception.
+(iscannum.c)
+ - Giving a closed readable file as input for a filter caused an
+invalidaccess. (files.h, interp.c, zfilter.c)
+ - setpagedevice opened the default device even with -dNODISPLAY.
+(gs_init.ps, gs_setpd.ps)
+ - realtime returned the same value as usertime. (gs_lev2.ps,
+zmisc.c)
+ - Storing a local value into systemdict caused some redundant code
+to be executed. (zdict.c)
+ - Files with a very long first line could cause a rangecheck error.
+(gs_init.ps)
+ - The PageOffset page device parameter was ignored. (gs_setpd.ps)
+ - The Orientation page device parameter wasn't handled properly.
+(gs_setpd.ps, idparam.h, idparam.c, zmedia2.c)
+ - setpagedevice could set device parameters twice, with an
+incomplete update the first time. (gs_setpd.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Readers confused the internal pdfrun procedure with the public
+runpdf procedure. (pdf_*.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - Closed streams had a NULL state pointer, causing problems for some
+clients. (stream.c)
+ - Group 4 decoding could get an ioerror if an end-of-buffer occurred
+in a horizontal code sequence between a makeup code and the termination
+code. (scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Some 'private' declarations were omitted. (Why doesn't gcc catch
+these??) (gdevmrop.c, gxht.c)
+ - Patterns could produce bad output in the band list. (gxclist.c)
+ - RasterOp wasn't implemented at all for 2- or 4-bit devices. (In
+this release, we implement only a subset, and without handling transparency
+properly.) (gdevm2.c, gdevm4.c, gdevmrop.c)
+ - Drawing operations and text sometimes didn't apply the RasterOp
+when they should, and vice versa. (gxdcolor.h, gxdraw.c)
+ - setcolorrendering tried to cache values computed from the color
+space even if the current color space wasn't a CIE space. (gscie.h,
+gscie.c)
+ - Some CIE color spaces produced very distorted colors. (gscie.c)
+ - setpagedevice opened a window even with -dNODISPLAY. (gsdevice.c,
+gsdparam.c)
+ - realtime returned the same value as usertime. (gp.h, time_.h,
+gp_*.c)
+ - The library level attempted to handle the Orientation page device
+parameter. (gxdevice.h, gdevbit.c, gsdevice.c, gsdparam.c, gspath.c)
+ - Severely non-linear CIE encoding/decoding functions produced
+seriously skewed colors near the ends of the color value range. This
+problem can now be alleviated, at a significant cost in performance, by
+changing configuration parameters at the beginning of gscie.h. (gscie.h,
+gscie.c)
+ - Files FTP'ed in binary mode weren't being opened properly on VMS.
+(gp.h, gp_*.c, gsiodev.c)
+ - A header file had an inconsistent declaration. (math_.h)
+
+Adds a new gp_get_usertime procedure to gp.h. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE, affecting only platform implementors. It
+was necessary to fix the realtime/usertime bug. (gp.h, time_.h, gp_*.c)
+
+Adds a new gp_fopen procedure to gp.h. THIS IS A NON-BACKWARD-COMPATIBLE
+CHANGE, affecting only platform implementors. It was necessary to fix the
+binary file problem on VMS. (gp.h, gp_*.c)
+
+Version 3.46(limited) (9/4/95)
+=====================
+
+This is the "serious beta test" release for the next public release. It
+finishes implementing RasterOp in the graphics state, and the remaining
+commonly used parts of setpagedevice.
+
+Documentation
+-------------
+
+Documents some possible problems when building with DJGPP v2.0-beta.
+(make.doc)
+
+Adds documentation on using Ghostscript as a PDF interpreter. (use.doc)
+
+Notes linking problems with the Watcom 10.0 environment. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The rule for $(ccfonts).dev was wrong. (gs.mak)
+
+Makes some additional filters into 'features'. (devs.mak, gs.mak)
+
+Splits off 2 new makefiles from gs.mak, which had gotten very large: lib.mak
+(graphics library) and int.mak (interpreters). (tar_cat, tar_cat.bat,
+*.mak)
+
+Adds a new 'config-clean' target that may be helpful in changing
+configuration definitions. (gs.mak)
+
+Notes in the relevant makefiles that on Unix and DVX systems, one should not
+edit 'makefile' or the concatenated makefile, but should edit the individual
+subfile and run tar_cat. (ansihead.mak, cc-head.mak, dgc-head.mak,
+gcc-head.mak, devs.mak)
+
+Updates the Watcom makefiles to handle Watcom release 10.5, in which many
+executables moved to different directories. (watc.mak, watcwin.mak,
+wccommon.mak)
+
+Adds a pdf2ps shell script. (pdf2ps, pdf2ps.bat)
+
+Adds a -sFONTMAP= switch to specify the name of the Fontmap file.
+(gs_fonts.ps)
+
+Adds a -u<name> switch to undefine a name from systemdict. (interp.h, gs.c,
+iinit.c)
+
+Adds a -dFIXEDRESOLUTION switch to parallel -dFIXEDMEDIA. Makes -g set
+FIXEDMEDIA and -r set FIXEDRESOLUTION. (gs_init.ps, gs_setpd.ps, gs.c)
+
+Changes some build procedures to avoid problems with read-only source files.
+(gs.mak, int.mak, lib.mak)
+
+Utilities
+---------
+
+Adds a utility for emulating the CIE color mapping algorithms. (docie.ps)
+
+Drivers
+-------
+
+Changes the x11alpha device so that it uses 32-bit pixels with 8 bits of
+alpha. (gdevxalt.c)
+
+Updates the Epson Stylus Color driver to Gunther Hess's release 1.17.
+(devs.mak, unix-end.mak, devices.doc, stcolor.ps, gdevstc.h, gdevstc*.c)
+
+Updates the alternate X drivers for the change from PageSize to MediaSize.
+(gdevxalt.c)
+
+Makes Duplex an optional parameter of printer devices rather than of all
+devices. (gdevprn.h, gxdevice.h, gsdparam.c, gdevdjet.c, gdevprn.c)
+
+Platforms
+---------
+
+Makes pipes (%pipe% file syntax) a selectable option on Unix platforms,
+rather than always being included. (ansihead.mak, cc-head.mak,
+gcc-head.mak, ugcclib.mak, unixtail.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - colorimage, and the dictionary form of image with
+MultipleDataSources = true, didn't check that all the data sources were of
+the same type. (zpaint.c)
+ - colorimage, and dictionary-type images with MultipleDataSources =
+true, usually didn't work properly with files. (zpaint.c)
+ - grestoreall left a dangling pointer to the transfer function
+cache. (gsstate.c)
+ - Changes made by setpagedevice could get 'lost' and not installed
+in the current page device dictionary. (gs_setpd.ps)
+ - The Install procedure was called before the new page device
+dictionary had gotten installed. (gs_setpd.ps)
+ - If a grestore/grestoreall/restore/setgstate operation switched
+page devices, the new page device didn't get installed properly.
+(gs_setpd.ps, opextern.h, zdevice2.c, zdps1.c)
+ - If the current screen was a Type 1 halftone, currentscreen and
+currentcolorscreen returned frequency = 60, angle = 0 rather than the
+Frequency and Angle from the halftone (see Adobe TN 5085). (gs_dps1.ps,
+gs_init.ps)
+ - setscreen with a Type 1 halftone dictionary didn't insert the
+frequency and angle into the dictionary (see Adobe TN 5085). (gs_dps1.ps)
+ - upath didn't include a trailing moveto in the bounding box.
+(gs_dps1.ps, zpath1.c)
+ - setpagedevice didn't automatically rotate or scale the image when
+necessary. (gs_setpd.ps, zmedia2.c)
+
+Moves the RasterOp operators to a separate file. (iutil.h, iutil.c,
+zgstate.c, zrop.c)
+
+Eliminates the unnecessary "wrapper" around .setdevice. (zdevice2.c)
+
+Establishes the convention that all interpreter callbacks into PostScript
+code use procedure names that begin with %; documents this in gs_init.ps.
+Changes Type1BuildChar and Type1BuildGlyph to %Type1BuildChar and
+%Type1BuildGlyph. (gs_init.ps, gs_type1.ps, zfont0.c, zfont1.c)
+
+Changes image / imagemask / colorimage for the new library API. (zimage2.c,
+zpaint.c)
+
+Reorganizes font loading to make compiled fonts and Fontmap interact better
+with each other. (gs_ccfnt.ps, gs_fonts.ps, gs_init.ps, gs_res.ps)
+
+Implements parameter collection for the new CIEBasedDEF[G] color spaces, but
+doesn't actually implement the color spaces themselves. (icie.h, zcie.c,
+zcrd.c)
+
+Renames iconfig.c as iconf.c to avoid problems with read-only source files.
+(iconf.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - PDF to PostScript conversion didn't work. (pdf_main.ps)
+
+Shifts most of the work in the PDF interpreter from the reader to the
+ProcSet. This simplifies the code considerably and also makes it easier to
+modify. (gs_pdf.ps, pdf_draw.ps, pdf_font.ps, pdf_main.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - 'static' was omitted in a place that some compilers require it.
+(gxccman.c)
+ - Some compilers don't allow a variable with the same name as a
+preprocessor macro with arguments. (gscie.c)
+ - Some places did a "return -1" rather than a proper error return.
+(gsdevice.c, gxclist.c)
+ - An external declaration had a typo. (gsrop.h)
+ - An extra semicolon upset some compilers. (gzpath.h)
+ - Printer devices that didn't use the standard macros for generating
+their procedure vector wound up being considered as non-page devices.
+(gdevprn.c)
+ - Some compilers truncated identifiers longer than 31 characters.
+(gscspace.h, zcie.c, gscie.c)
+ - upath didn't include a trailing moveto in the bounding box.
+(gspath.h, gspath1.c)
+ - RasterOp value 126 returned an incorrect result. (gsroptab.c)
+
+Finishes implementing RasterOp in the graphics state. (gdevmrop.h, gsrop.h,
+gsropt.h, gsstate.h, gxbitmap.h, gxcindex.h, gxdcolor.h, gxdevice.h,
+gzstate.h, gdevmrop.c, gscolor.c, gsdevice.c, gsimage.c, gsimage1.c,
+gsimage2.c, gsimage3.c, gspcolor.c, gsrop.c, gsstate.c, gxacpath.c,
+gxccache.c, gxcht.c, gxcmap.c, gxdither.c, gxdraw.c, gxht.c)
+
+Changes forwarding devices so they forward get_bits by default. This
+probably doesn't affect any existing code. (gxdevice.h, gsdevice.c)
+
+Changes the API for gs_image[mask]_init to pass a structure rather than a
+very large number of scalars. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE,
+motivated by the addition of further image parameters to support RasterOp.
+Since there are no external clients of the library yet, it shouldn't matter.
+(gsimage.h, gsimage.c, gslib.c, gxccache.c)
+
+Redefines the device "page size" as being the size of the actual media,
+changing the name of the gx_device PageSize member to MediaSize, the name of
+the PageSize device parameter to .MediaSize (but keeping PageSize as
+equivalent, for backward compatibility), and the name of the
+gx_device_set_page_size procedure to gx_device_set_media_size (keeping the
+old name as a macro). THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. It is
+necessary to make setpagedevice work, and to avoid confusion about what
+"page size" means. It potentially affects any device driver, but almost
+none of the device drivers distributed with Ghostscript are affected, and
+those have been updated. (gsparam.h, gxdevice.h, gsdevice.c, gsdparam.c,
+gspath.c)
+
+Renames gconfig.c as gconf.c to avoid problems with read-only source files.
+(gconf.c)
+
+Adds an API procedure for setting a bitmap pattern. (gscolor2.h,
+gspcolor.c)
+
+Version 3.45(limited) (8/27/95)
+=====================
+
+The purpose of this release is to fix some minor bugs reported by commercial
+licensees, and to add two enhancements: optional RenderTable interpolation
+for CIE color, and reducing the temporary space used during character
+caching (also for a licensee).
+
+Documentation
+-------------
+
+Notes that the only valid return values from get_alpha_bits are 1, 2, and 4.
+(drivers.doc)
+
+Notes that the get_bits driver procedure will return a pointer to aligned
+data, but does not require the caller's data area to be aligned.
+(drivers.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Many of the printer and file output drivers in devs.mak still
+included gdevprn.$(OBJ) in their dependencies. (devs.mak)
+ - PDEVH was used before it was defined. (devs.mak)
+ - GENCONF_XE was used before it was defined. (unixhead.mak,
+unix-end.mak)
+
+Makes it possible to switch sfile implementations without editing gs.mak.
+(gs.mak)
+
+Makes it possible to specify alternate compiled font tables without editing
+gs.mak. (gs.mak)
+
+Allows quoted arguments in @-files, e.g.,
+ -sOutputFile="a file name with spaces"
+(gs.c)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The ps2ascii script could fail to delete temporary files in case
+of an abnormal exit. (ps2ascii)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The MS Windows printer capability test was wrong. (gdevwpr2.c)
+ - The MS Windows and OS/2/PM displays weren't page devices.
+(gdevwdib.c, gdevpm.c)
+
+Gets rid of all direct references to dev->PageSize in drivers. (gdevl256.c,
+gdevvglb.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The 32-bit MS Windows configuration file for the Borland C++
+compiler was missing from the fileset. (bcc32.cfg, tar_gs)
+
+Makes the printer devices in the OS/2 implementation capable of outputting
+directly to the print spooler. (use.doc, gp_os2.c)
+
+Makes printing on Windows NT and Windows 95 use the printer queue.
+(gp_mswin.c, gswin32.rc)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Copying a null device produced an uninitialized pointer.
+(gsdevice.c)
+ - The dictionary returned by deviceinfo wasn't read-only.
+(gs_lev2.ps)
+ - If a filter's init code failed, an entry on the operand stack
+(usually the top) could be smashed. (files.h, zfile.c, zfilter.c)
+
+Adds const in a few places that needed it. (zwppm.c)
+
+Adds interpolation to the CIE RenderTable lookup. (icie.h, zcie.c, zcrd.c)
+
+Interpreter (PDF)
+-----------------
+
+Allows PDF files with control-character garbage at the end, and up to 250
+characters of garbage at the beginning. The latter is only supported by
+runpdf, not by run. (pdf_base.ps, pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - A 1-D CCITTFaxDecode stream could give an error if an input buffer
+boundary fell just before a 0-length termination code. (scfx.h, scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A variable was used before being set, which could cause band
+devices to become confused when processing colored halftones. (gxclist.c)
+ - Some of the color and tile bookkeeping for band lists was wrong
+(as of 3.44), causing tiled areas to be filled with garbage. (gxclist.c,
+gxclread.c)
+ - Colored Patterns showed up blank on devices whose native
+representation of `black' was a non-zero value. The fix removes the
+'cached' member of the gx_device structure, and requires monobit memory
+devices to have a palette; this is a NON-BACKWARD-COMPATIBLE CHANGE for
+anyone who was foolish enough to statically initialize a gx_device structure
+without using the macros in gxdevice.h or gdevprn.h. (gdevmem.h,
+gxdevice.h, gxdevmem.h, gdevm1.c, gdevmrop.c, gsdevice.c, gxcpath.c,
+gxdither.c)
+
+Provides the framework for band devices to implement alpha (anti-aliasing).
+(gxcldev.h, gdevprn.c, gsdevice.c, gxclist.c, gxclread.c)
+
+Implements an efficient API for enumerating paths using device coordinates.
+(gspath.h, gxpath.h, gzpath.h, gspath1.c, gxpath2.c)
+
+Changes the character cache logic so that when rasterizing large
+anti-aliased characters, it converts the oversampled bits to alpha values on
+the fly rather than waiting until it has rasterized the entire character.
+This saves a lot of temporary space, at the expense of some extra time and
+lower quality results for Type 3 characters that don't use a single fill or
+imagemask operation to draw the character. This enhancement requires adding
+a member to the gx_device structure (max_fill_band), which is a
+NON-BACKWARD-COMPATIBLE CHANGE for badly written drivers (see above).
+(gxchar.h, gxdevice.h, gxpaint.h, gdevabuf.c, gschar.c, gspaint.c,
+gxccache.c, gxccman.c, gxfill.c)
+
+Changes the palette member of memory devices from gs_string to
+gs_const_string. (gdevmem.h, gxdevmem.h, gdevmem.c, gdevm1.c)
+
+Starts to decouple halftoning from the graphics state machinery, so
+it can be applied after banding rather than before. (gxdcolor.h,
+gxdht.h, gxdither.h, gzht.h, gxcmap.c, gxdither.c, gxdraw.c)
+
+Starts to decouple path filling from the graphics state machinery, so
+that we can pass paths through band lists. (gxpaint.h, gxfill.c)
+
+Adds interpolation to the CIE RenderTable lookup. This is optional, enabled
+by #define CIE_RENDER_TABLE_INTERPOLATE in gscie.h. (gscie.h, gxctable.h,
+gscie.c, gxctable.c)
+
+Version 3.44(limited) (8/21/95)
+=====================
+
+This includes a few bug fixes, but its main purpose is to add two new
+features: monobit and 8-bit gray-scale RasterOp (at the driver level, not at
+the gstate level yet), and (compressed) band lists in RAM. Of course, these
+new features may have introduced new bugs!
+
+Documentation
+-------------
+
+Adds contact information for a user working on NeXT machines. (README)
+
+Notes that Ghostscript runs on FreeBSD. (README)
+
+Adds copy_rop (the RasterOp operation) to the driver interface.
+(drivers.doc)
+
+Adds FONTPATH information for more operating systems. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The tar_cat script needed a #!/bin/sh to execute correctly on all
+platforms. (tar_cat)
+ - There were a number of minor errors in the makefiles. (gs.mak,
+unixhead.mak)
+ - Level 2 configurations without command lists had two undefined
+references. (gs.mak)
+ - Some shells required an extra ';' to terminate an 'if' command.
+(ugcclib.mak, unix-end.mak, unixtail.mak)
+
+Updates the JPEG code to the officially released version 6 of the IJG
+library. See jpeg.mak for information on where to find this library.
+(jpeg/*, jpeg.mak, *.mak, modules.lis)
+
+Adds a definition of XEAUX to the makefiles to parallel CCAUX, primarily for
+cross-compilation environments. All references to <some-program>$(XE) must
+be replaced by $(<SOME-PROGRAM>_XE), where some-program={$(GS), ansi2knr,
+echogs, genarch, genconf, geninit}. This is a NON-BACKWARD-COMPATIBLE
+CHANGE, required in order for the makefiles to work in cross-compiled
+environments. (For non-cross-compiled environments, it currently doesn't
+matter.) (gs.mak, *.mak)
+
+Utilities
+---------
+
+Updates ps2ai.ps to version 2.13. (ps2ai.ps)
+
+Changes all the utility shell scripts to include #!/bin/sh, to use exec, and
+to pass the original arguments using "$@". (bdftops, font2c, gsbj, gsdj,
+gslj, gslp, gsnd, wftopfa)
+
+Drivers
+-------
+
+Adds the requirement that all page-oriented devices (i.e., those that use
+gdevprn.h and implement the print_page procedure) include page.dev in their
+dependencies and use $(SETPDEV) rather than $(SETDEV) in their makefile rule
+bodies. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. Without this change, the
+command list logic (over 25K of unnecessary object code) would have to be
+included in every configuration. (gs.mak, devs.mak, echogs.c)
+
+Adds a user-contributed driver for the Okidata Microline (IBM compatible)
+dot matrix printers. (gdevokii.c)
+
+Adds copy_rop (the RasterOp operation) to the driver interface. Currently,
+only monobit and 8-bit gray-scale devices implement it. (gxdevice.h,
+gsdevice.c)
+
+Adds the ability to read back bits from the display to the x11 devices.
+(x_.h, gdevx.c, gdevxalt.c)
+
+Platforms
+---------
+
+Makes some minor changes to support QNX. (stat_.h)
+
+Removes the mswinprn driver from the 16-bit Windows configuration, because
+the 64K default data segment overflowed. (bcwin.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Type 1 fonts didn't accept packed arrays for Subrs or OtherSubrs.
+(zchar1.c, zfont1.c)
+ - TBCP-encoded files (yes, I know there isn't supposed to be any
+such thing) didn't automatically activate TBCP decoding. (gs_init.ps)
+ - Fonts with invalid FID entries weren't detected. (zfont.c)
+
+Speeds up dictionary operations slightly by removing redundant checks for
+nulls. (zdict.c)
+
+Starts adding support for the new CIEBasedDEF and CIEBasedDEFG color spaces.
+(gs_l2img.ps, gs_lev2.ps, igstate.h, zcrd.c)
+
+Adds access operators for RasterOp and transparency in the graphics state.
+(They don't actually do anything yet.) (zgstate.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - PDFDocEncoding was missing characters 24-31. (gs_pdf_e.ps)
+
+Moves the definition of pdfmark from systemdict to userdict so that Adobe
+PostScript files won't think the interpreter is a distiller. (gs_pdf.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Some JPEG images had bands of garbage alternating with bands of
+valid data. IJG v6 fixed this -- see above.
+ - With FPU_TYPE = -1, the cosine routine returned incorrect values
+for angles above 270 degrees. (gsmisc.c)
+ - CIE color conversion didn't work on 16-bit systems. (gscie.h,
+gscie.c)
+
+Partially implements reducing the intermediate space for rasterizing
+anti-aliased characters by compressing the oversampled representation to an
+alpha array incrementally. (gdevmem.h, gxchar.h, gxdevmem.h, gdevabuf.c,
+gschar.c, gspaint.c, gxccman.c)
+
+Starts adding support for the new CIEBasedDEF and CIEBasedDEFG color spaces.
+(gscie.h, gscspace.h, gscie.c)
+
+Completes the implementation of band lists in RAM. To select this feature,
+change the definition of cl_impl in gs.mak from clfile to clmem. (Someday
+we'll make this easier.) (gxclmem.h, gxclmem.c)
+
+Finishes implementing RasterOp and transparency at the driver level for
+monobit and 8-bit gray-scale devices, and implements some of the framework
+for general multiple-bit-per-pixel devices. See drivers.doc for
+documentation. (gsropt.h, gxcldev.h, gxclist.h, gdevm1.c, gdevm8.c,
+gdevmem.c, gdevmrop.c, gschar.c, gxclist.c, gxclread.c)
+
+Implements the ability to include commands applicable to all bands, rather
+than an individual band, in the band list. Eventually this will be used for
+passing halftones through the band list. (gxcldev.h, gxclist.h, gxclist.c)
+
+Adds support for 2-bit-deep 'word' memory devices. (gdevmem.h, gxdevmem.c,
+gdevm2.c)
+
+Changes the initialization for memory devices so that they determine their
+polarity from the device for which they are buffering the image (if any).
+This is a subtle change. (gdevmem.h, gdevmem.c, gdevm1.c, gsdevmem.c)
+
+Version 3.43(limited) (8/10/95)
+=====================
+
+Fixes a few more minor bugs, and changes FEATURE selection back to
+essentially the way it was before 3.41.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A ~ was missing in a URL. (README)
+
+Adds information about an Amiga port of Ghostscript. (README)
+
+Removes a file called gs.1.c, which appears to be an obsolete version of
+gs.1.
+
+Adds DCX documentation to the PCX driver. (We don't support DCX yet, but we
+might in the future.) (gdevpcx.c)
+
+Adds information about getting Type 1 fonts from H-P if you have an H-P
+PostScript printer. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The auxiliary programs wouldn't compile with ANSI compilers that
+don't accept K&R syntax. (ccgs, gs.mak, ugcclib.mak, *head.mak,
+unixtail.mak, echogs.c, genarch.c, genconf.c, geninit.c)
+
+Reinstates FEATURE_DEVS in the makefiles, getting rid of FEATURE1..10. THIS
+IS A NON-BACKWARD-COMPATIBLE CHANGE, but it puts things back the way they
+were before 3.41, with one exception: compiling the PostScript
+initialization code into the executable is now a separate macro
+COMPILE_INITS with a definition of 0 or 1, instead of the ccinit 'feature'.
+(gs.mak, *.mak, fonts.doc, make.doc)
+
+Adds a CCLEAF macro to the makefiles, for optimizing the compilation of
+modules containing only leaf procedures. (gs.mak, *.mak)
+
+Adds a CONFIG makefile variable that helps in maintaining multiple variants
+in a single directory. (gs.mak, *.mak)
+
+Platforms
+---------
+
+Fixes bugs:
+ - An extern for exit() (in <stdlib.h>) was omitted. (gp_vms.c)
+
+Fonts
+-----
+
+Reorganizes the compiled font facility so that fonts can be compiled and
+turned into a library by third parties. (gs.mak, font2c.ps, gs_ccfnt.ps,
+ccfont.h, iccfont.c, ccfontab.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - internaldict was implemented as a dictionary in systemdict and an
+operator in userdict, rather than as an operator in systemdict. This caused
+a noaccess error when loading certain Type 1 fonts. (gs_init.ps,
+gs_type1.ps)
+ - xfonts couldn't handle modified encodings. (zfont2.c)
+
+Changes the build date printout in the help message to YYYY-MM-DD. (gs.c)
+
+Adds native support for Multiple Master fonts (WeightVector). (zfont1.c)
+
+Implements sin and cos more efficiently (by table lookup with linear
+interpolation) on machines with slow (or no) floating point. (zmath.c)
+
+Separates out the code for 'reading' the .ps initialization files, for the
+new COMPILE_INITS arrangement. (imain.h, gconfig.c, gsmain.c, iconfig.c,
+iccinit0.c, iinit.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxDecode filter could read up to 3 bytes beyond EOD.
+This fix doesn't quite cover all cases, but at least it makes things better.
+(ghc.h, sbhc.c, scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - After a nocurrentpoint error from a show operation with a
+composite font, the bookkeeping was confused and could cause an access
+error. (gschar.c)
+ - xfonts couldn't handle modified encodings. (gsccode.h, gxchar.h,
+gxfont.h, gxxfont.h, gschar.c, gxccache.c)
+
+Makes .charboxpath able to use cached character information. (gxchar.h,
+gschar.c)
+
+Adds native support for Multiple Master fonts (OtherSubrs 14-18).
+(gxfont1.h, gstype1.c)
+
+Improves the hashing functions for the character cache. (gxfcache.h,
+gxccman.c)
+
+Adjusts the character oversampling algorithm to reduce thickening for
+devices with alpha capability. (gsbitops.c)
+
+Improves the encoding of the band list for certain kinds of small
+rectangles. (gxcldev.h, gxclist.c, gxclread.c)
+
+Implements sin and cos efficiently on machines with slow (or no) floating
+point. (gxfarith.h, gsmatrix.c, gsmisc.c, gspath1.c)
+
+Version 3.42(limited) (8/2/95)
+=====================
+
+Fixes a few significant problems in 3.41, and brings the DLL code up to
+date.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - language.doc still referred to rectappend rather than .rectappend.
+(language.doc)
+
+Adds documentation on the Macintosh port. (readme, make.doc)
+
+Updates the DLL documentation. (dll.doc)
+
+Documents the BCP and TBCP filters as non-experimental. (language.doc)
+
+Procedures
+----------
+
+Changes the build date printout to YYYY-MM-DD. (gs_init.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS build script had gotten out of sync with the makefiles
+(again). (vms.mak, modules.lis)
+
+Brings the MS Windows and OS/2 platforms up to date with the rest of the
+code, including DLL support for OS/2. (os2.mak, gsdll*.def, gdevswn.c,
+gdevpm.c, gdevwdib.c, gp_mswin.c, gp_os2.c, gsdll.c, gsmain.c)
+
+Adds a new platform-specific routine gp_do_exit, as an alias for the C
+library `exit' call. (gp.h, gsdll.c, gsmain.c, gp_*.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - .forgetsave at the outermost level didn't clear the l_new bit,
+causing changes to be undone improperly. (isave.c)
+ - A 'void' formal parameter list upset some compilers (as it should
+have). (gsmain.c)
+
+Adds a .charboxpath operator that appends to the current path the bounding
+boxes of the characters of a string. (zchar.c, zchar1.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - A procedure was declared private inconsistently. (siscale.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The library test program didn't do a necessary initial gsave.
+(gslib.c)
+ - The fix for landscape monobit images in 3.41 could smash memory.
+(gsimage1.c)
+ - 1-pixel-wide lines drawn with image or imagemask still disappeared
+sometimes. (gsimage.c)
+
+Does some more preparatory work for the implementation of command lists in
+RAM. (gdevprn.h, gxclio.h, gxclist.h, gxclfile.c, gxclist.c, gxclread.c)
+
+Adds a gs_charboxpath procedure that appends to the current path the
+bounding boxes of the characters of a string. (gschar.h, gscpm.h,
+gstype1.h, gxchar.h, gxpath.h, gxtype1.h, gzstate.h, gschar.c, gspaint.c,
+gstype1.c, gxpath.c)
+
+Version 3.41(limited) (7/27/95)
+=====================
+
+Another incremental release with bug fixes and customer-requested
+enhancements. This release was intended to include the full setpagedevice
+media matching and adjustment algorithm, but we discovered some
+architectural problems during development, and have postponed it.
+
+Documentation
+-------------
+
+Replaces the build instructions for NeXTSTEP with more up-to-date and
+accurate ones. (make.doc)
+
+Notes that some extra manual steps are required when cross-compiling.
+(make.doc)
+
+Documents how to define new 'features' in the makefile. (gs.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The build rule for ccinit.dev was circular. Fixing this required
+a small but NON-BACKWARD-COMPATIBLE change in the way that features are
+selected in the makefiles (FEATURE_DEVS replaced by FEATURE1..10). (*.mak,
+fonts.doc, make.doc)
+
+Changes the build rule for gconfig.h to be less likely to overrun MS-DOS's
+command line length limit. (gs.mak)
+
+Adds a -dFIXEDMEDIA switch to indicate that the media size should be
+considered fixed after initialization. (gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - traceimg.ps incorrectly referred to .stdout. (traceimg.ps)
+ - prfont.ps didn't display unencoded characters correctly.
+(prfont.ps)
+ - ps2epsi didn't give correct bounding box information. (ps2epsi,
+ps2epsi.ps)
+ - ps2epsi produced DSC comments that didn't fully conform to the
+Adobe standard. (ps2epsi, ps2epsi.ps)
+
+Allows viewpbm.ps to take multiple files on the command line. (viewpbm.ps)
+
+Drivers
+-------
+
+Adds a preliminary, contributed PNG driver. THIS IS NOT USABLE YET -- DON'T
+TRY TO USE IT. (png.mak, gdevpng.c)
+
+Increases the maximum allowable scan line width for the TIFF drivers from
+5183 pixels to 12863 pixels. (scf.h)
+
+Platforms
+---------
+
+Updates the MS Windows DLL code to export the new, suspendable run_string
+interface. (gsdll.h, gsdll.c, dll.doc)
+
+Fonts
+-----
+
+Fixes bugs:
+ - There were several errors in cfonts.mak. (cfonts.mak)
+ - The compiled fonts option didn't offer both free and standard
+configurations. (gs.mak)
+ - A bug in the handling of Encoding resources prevented compiled
+fonts from working. (gs_res.ps)
+
+Adds a little more support for CID-keyed fonts. They still aren't anywhere
+near usable. (gs_cidfn.ps, gs_type1.ps)
+
+Adds a new Fontmap for Solaris 2.3. (Fontmap.Solaris)
+
+Adds support for Type 4 fonts (Type 1 fonts with their own BuildChar
+procedures), including the CCRun procedure in internaldict. (gs_fonts.ps,
+gs_res.ps, gs_type1.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - showpage and copypage didn't honor NumCopies in a page device.
+(gs_setpd.ps, zdevice2.c)
+ - currentpagedevice returned incorrect information if the current
+device wasn't a page device. (gs_setpd.ps)
+ - currentpagedevice didn't guarantee the presence of InputAttributes
+and OutputAttributes. (gs_setpd.ps)
+ - The l_new bit wasn't set properly when a dictionary changed from
+packed to unpacked keys, leading to unnecessary saves. (idict.c)
+ - Streams requiring intermediate buffering could read ahead too far,
+causing input data to be skipped. (zfilter.c)
+ - cshow didn't reset the font to the base font when calling the
+procedure. (zchar2.c)
+ - The Install procedure in a page device didn't set the default CTM.
+(gs_setpd.ps, zmatrix.c)
+ - findlibfile didn't handle special files like %stdin correctly.
+(zfile.c)
+ - setpagedevice didn't implement media matching. (gs_setpd.ps,
+zdevice2.c, zmedia2.c, zmatrix.c)
+ - Some floating point numbers didn't print out with enough digits to
+read back in with the identical value. (iutil.c)
+ - Integers that overflowed 31 bits (but not 32 bits) were converted
+to negative integers rather than correct positive reals. (iscannum.c)
+
+Removes an experimental operator that called the image scaling/interpolation
+code. (zimage2.c)
+
+Adds a -sSUBSTFONT=<fontname> switch that substitutes the given font for all
+unknown fonts, bypassing the normal intelligent substitution algorithm.
+(gs_fonts.ps)
+
+Adds the Revision system parameter. (zmisc2.c)
+
+Adds a .knownundef operator that does an undef and returns true iff the key
+was formerly present. (zdict.c)
+
+Makes the maximum length of names be 256 if EXTEND_NAMES is being used, 16K
+otherwise. (inamedef.h, iname.c)
+
+Adds internaldict. (gs_init.ps, iinit.c)
+
+Adds support for Type 4 fonts. (bfont.h, zchar.c, zchar1.c, zfont1.c,
+zfont2.c)
+
+Changes .encodingdict to EncodingDirectory, for compatibility with Adobe
+interpreters. (gs_init.ps, gs_kanji.ps, gs_res.ps)
+
+Adds superexec, an undocumented operator that is equivalent to exec but
+suppresses all invalidaccess checks. NOT COMPLETED YET; currently superexec
+is equivalent to exec. (zcontrol.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - .stderr was used but is no longer defined. (pdf_base.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - Not all streams initialized their state pointer. (stream.c,
+sfile.c, sfileno.c)
+
+Adds a filter for the smoothed image scaling algorithm. Eventually this
+filter will require very little intermediate storage; right now it still
+needs to buffer the entire intermediate image. (siscale.h, siscale.c)
+
+Increases the maximum allowable scan line width for the CCITTFaxEncode
+filter from 5183 pixels to 12863 pixels. (scf.h)
+
+Library
+-------
+
+Fixes bugs:
+ - setpagedevice didn't update NumCopies correctly. (gdevprn.c,
+gsdparam.c)
+ - The newly optimized code for monobit bitmaps could cause an
+out-of-bounds memory access and/or make unaligned references. (gsimage1.c)
+ - setpagedevice with unknown keys could cause an /undefined error.
+(gsdparam.c)
+ - cshow didn't reset the font to the base font when calling the
+procedure. (gschar.h, gschar.c)
+ - The Install procedure in a page device didn't set the default CTM.
+(gzstate.h, gschar.c, gscoord.c, gsdevice.c)
+ - Very non-linear EncodeABC procedures in a color rendering
+dictionary could produce very inaccurate results. (gscie.h, gscie.c)
+ - The line_ptrs pointer in memory devices didn't get relocated if
+the bitmap was moved during garbage collection, leading to memory smashing.
+(gdevmem.c)
+ - setpagedevice didn't implement media matching. (gsdparam.c,
+gscoord.c)
+ - 'word' memory devices weren't recognized as memory devices.
+(gdevmem.c)
+ - makeimagedevice allocated, and then didn't free, an unnecessary
+palette for monobit devices. (gsdevmem.c)
+ - The hack for 1-bit-wide images didn't work consistently,
+particularly in landscape orientation. (gsimage.c, gsimage0.c)
+
+Adds an .IgnoreNumCopies page device parameter that causes #copies and
+NumCopies to be ignored. (gxdevice.h, gsdevice.c, gsdparam.c)
+
+Removes the .IsPageDevice device parameter. (gsdparam.c)
+
+Converts the image scaling/interpolation code to a filter. (gximage.h,
+gsimage.c, gsimage0.c, gsimage3.c)
+
+Adds support for Type 4 fonts. (gxfont.h)
+
+Adds a default implementation of parameter lists, designed to be usable
+easily from C code. (gsparam.h, gsparam.c)
+
+Version 3.40(limited) (6/28/95)
+=====================
+
+This is another incremental limited release for delivery of a couple of
+important bug fixes (pixel 'holes' in rotated images, setpagedevice errors
+on some platforms) and an enhancement (architectural support for band lists
+in RAM).
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The FTP location of the EMX DLLs was incorrect. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - A couple of build rules for IJG v6 were omitted. (jpeg.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - prfont.ps wouldn't print more than 128 unencoded characters.
+(prfont.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - setpagedevice often caused /undefined errors on MS Windows and
+OS/2 platforms. (gdevmswn.c, gdevpm.c)
+ - The VMS module list had gotten out of sync with the makefiles
+(again). (modules.lis)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A couple of casts betwen char * and byte * were omitted.
+(gsmain.c)
+ - gs_[main_]run_file_open wasn't exported properly. (imain.h,
+main.h, gsmain.c)
+
+Streams
+-------
+
+Changes the DCTEncode filter to return an error if it wasn't supplied enough
+data before being closed. (sdcte.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The coordinate computations for all filling operations were
+slightly inaccurate, leading to pixel 'holes' in rotated images. (gxdda.h,
+gximage.h, gsimage*.c, gxdraw.c, gxfill.c)
+
+Undoes an "optimization" (inlining the normal, fast case of a procedure)
+that actually hurt performance. (gxclist.c)
+
+Refactors the command list code so that it in the future it will be able to
+store command lists either in RAM or in the file system. (gdevprn.h,
+gxcldev.h, gxclio.h, gxclist.h, gdevprn.c, gxclfile.c, gxclist.c,
+gxclread.c)
+
+Changes the interface to the path filling code to take separate X and Y
+adjustment values. (gxpaint.h, gspaint.c, gxfill.c)
+
+Makes the command list allocate a small tile cache if the device doesn't
+need halftones. (gxclist.c)
+
+Version 3.39(limited) (6/24/95)
+=====================
+
+This is again an incremental release primarily for delivery of enhancements
+(suspendable string input in particular) to commercial customers, and with a
+few bug fixes.
+
+Documentation
+-------------
+
+Notes that PDF files and repositioning PostScript files do not work if
+Ghostscript was compiled with VAX C. (use.doc)
+
+Notes the requirement for EOD lookahead in decoding filters. (strimpl.h)
+
+Procedures
+----------
+
+Fixes bugs:
+ - There were a number of undefined or used-before-defined variables
+in the makefiles. (devs.mak, dvx-head.mak, unixhead.mak, gs.mak)
+ - Some commands in the makefile exceeded the MS-DOS limit of 120
+characters. (gs.mak)
+
+Adds a -P and -P- switch to control whether the search path automatically
+includes `.' as its first element. Moves the default value of this choice
+(SEARCH_HERE_FIRST) from gsmain.c to iminst.h. (iminst.h, gs.c, gsmain.c,
+use.doc)
+
+Makes some makefile changes in anticipation of the IJG v6 release. (*.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - font2c generated invalid C procedure names from font names that
+contained non-alphanumerics other then '-'. (font2c.ps)
+ - font2c generated a single element of incorrect type for numeric
+arrays of zero length. (font2c.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS build scripts had gotten out of sync (again). (vms*.mak,
+modules.lis)
+
+Fonts
+-----
+
+Makes the FONTPATH directory scanner accept fonts that begin with
+%!PS-AdobeFont or %!FontType1 with no following `-'. (gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - eq and ne on arrays or dictionaries required read access.
+(zrelbit.c)
+ - An include was missing. (zcsindex.c)
+ - .forgetsave at the outermost level didn't reset the l_new flag in
+changed slots, leading to an anomalous (although perhaps not harmful) state.
+(isave.c)
+ - Dictionary growing or unpacking would both save and free the old
+keys array, leading to a dangling reference. (idict.c)
+
+Changes gs_interpret so that for .quit with a negative operand <= -100,
+gs_interpret returns e_Fatal rather than the operand. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE, but as far as we know, it doesn't affect
+anyone. (interp.c)
+
+Adds an API to allow feeding string input to the interpreter in pieces.
+(errors.h, imain.h, main.h, gs.c, gsmain.c, interp.c, zcontrol.c, zfilter.c)
+
+Adds new predicates .identeq and .identne that test "pointer equality", even
+for numbers and strings. (iutil.h, iutil.c, zrelbit.c)
+
+Changes a few uses of return_error to return in places that don't lead
+directly to a PostScript error. (idict.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The logic for skipping up to a 0xff byte when decoding JPEG data
+could skip too much. (sdctd.c, sjpegd.c)
+ - If a buffer boundary fell in the middle of, or just before, an
+EOD, some decoding filters could stop reading too soon. (sbcp.c, smtf.c,
+sstring.c)
+
+Makes some minor changes in anticipation of the IJG v6 release.
+(gsjmorec.h)
+
+Library
+-------
+
+Fixes bugs:
+ - A declaration should have been removed. (gsdll.c)
+ - The library initialization/termination API wasn't declared.
+(gslib.h, gsinit.c, gsmain.c)
+ - A variable and a preprocessor macro with the same name confused
+VAX C. (gxclist.c)
+ - Image devices with depth 2-8 and only gray shades in the palette
+didn't set color_info correctly. (gsdevice.c)
+
+Speeds up unrotated black-and-white images further by making them render
+directly into a memory device when possible. (gxdevmem.h, gsimage1.c)
+
+Version 3.38(limited) (6/18/95)
+=====================
+
+This release incorporates several customer-requested enhancements (cleaner
+separation of the graphics library from the interpreter, option for >64K
+names, true garbage collection of names, better handling of halftones on
+band devices). It is intended primarily for those customers, but is
+intended as a dry run for the next public release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - gx_bitmap had not been updated to gx_tile_bitmap.
+(drivers.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The man page extension in the Unix makefiles was still $(manext),
+not $(man1ext). (unix-end.mak)
+ - 'make clean' didn't remove gs_init.c. (gs.mak)
+
+Restructures the makefiles to better separate the language interpreters from
+the graphics core. (gs.mak)
+
+Adds a -dNOPROMPT switch to suppress the end-of-page prompts (but still wait
+for the user to type a newline). This is different from -dNOPAUSE, which
+suppresses both the prompts and the wait. (gs_init.ps)
+
+Utilities
+---------
+
+Replaces the mergeini.ps program with an equivalent (actually slightly
+better) version written in C. (gs.mak, *.mak, psfiles.doc, use.doc,
+geninit.c)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The color DeskJet drivers wouldn't compile with a K&R compiler,
+because some of the procedure definitions weren't in the restricted syntax
+that ansi2knr requires. (gdevcdj.c)
+ - The color DeskJet drivers wouldn't compile because of a bug in
+Sun's cc. (gdevcdj.c)
+
+Changes the BJ-10e(x) margins to be identical to those of the BJ-200.
+(gdevbj10.c)
+
+Changes the LaserJet margins in response to a user's request. (gdevdjet.c)
+
+Changes the psmono driver to produce slightly larger files that execute
+faster on typical Level 1 printers. (gdevpsim.c)
+
+Changes the psmono driver so that it does not scale the image to fit the
+page size, but instead scales it to be the same physical size on the page.
+THIS IS A NON BACKWARD COMPATIBLE CHANGE. However, for full-page images, it
+will not have any visible effect. (gdevpsim.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - There were some problems associated with printing in 32-bit
+Windows environments. (gp_mswin.c)
+ - The IBM RS/6000 needs both <time.h> and <sys/time.h>. (time_.h)
+
+Adds the PDF interpreter to the standard MS Windows configuration.
+(bcwin.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The entry for Courier-BoldItalic in cfonts.mak incorrectly named
+it as Courier-Italic. (cfonts.mak)
+ - The files for Courier-Italic in cfonts.mak were inconsistently
+named ncrri instead of ncri. (cfonts.mak)
+ - The rules in cfonts.mak covered only the fonts distributed with
+the free versions of Ghostscript, omitting some of the standard set of 35.
+(cfonts.mak)
+ - The maximum number of stem hints per character in Type 1 fonts
+wasn't large enough for complex Asian characters. (gxtype1.h)
+
+Adds a -dNOFONTMAP switch to suppress loading the Fontmap file.
+(gs_init.ps, gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - One of the GC marking routines for halftones had a typo,
+possibly leading to an invalid access. (zht2.c)
+ - The GC could store beyond the end of the mark stack,
+possibly smashing some characters of a string or name. (igc.c)
+ - If the allocator allocated a new ref object from a
+freelist, the bookkeeping for the current ref object could get
+confused. (ialloc.c)
+ - The GC didn't remove names properly from the hash table.
+(iname.c)
+ - If a DOS editor added a ^Z to the end of an initialization file,
+an error occurred during initialization. (gs_init.ps)
+ - If an initialization file had any lines longer than 128
+characters, .skipeof would get an error. (gs_init.ps)
+ - makepattern could create structures in global VM pointing to
+structures in local VM. (zpcolor.c)
+ - The default color rendering dictionary didn't specify large enough
+ranges for some intermediate values. (gs_lev2.ps)
+ - Files being freed by a restore weren't unlinked properly, leading
+to dangling pointers. (zfile.c)
+ - The interpreter used strlen without a prototype. (interp.c)
+ - Indexed or Separation colors with a CIE base or alternate space
+didn't work. (zcie.c)
+ - The Watcom C 10.0 compiler produced incorrect code for an
+overlapping structure assignment. (zcsindex.c)
+
+Removes limit of 64K names, if EXTEND_NAMES is defined at compile
+time. (*.mak, idebug.h, iminst.h, iname.h, gs.c, gsmain.c, idebug.c,
+iname.c)
+
+Makes the garbage collector really collect names. (iname.h, inamedef.h,
+isstate.h, igc.c, iname.c, isave.c)
+
+Restructures some files to better separate the language interpreters
+from their support code. (gconfig.c, iconfig.c, iinit.c)
+
+Restructures some files to better separate the language interpreters
+from the graphics core. (iastate.h, iastruct.h, ialloc.c)
+
+Allows the operands of cshow to be in either order on the stack. Adobe
+interpreters apparently allow this, even though it's not documented.
+(zchar2.c)
+
+Adds a hack in cvs to truncate non-standard operator names, rather than
+giving a rangecheck, to work around the "max err string" problem in some
+common error handlers. (ztype.c)
+
+Changes the print string for unregistered operators from operator_0x... to
+@0x.... (iutil.c)
+
+Changes the garbage collector so it tries to allocate a large mark stack, to
+avoid going into its 'slow' mode if the mark stack overflows. (igc.c)
+
+Interpreter (PDF)
+-----------
+
+Fixes bugs:
+ - Stroked text used the text matrix, rather than just the
+CTM, for scaling the line width, which could lead to inappropriately
+wide lines. (gs_pdf.ps)
+ - Fonts based on other than a 1000-unit scale (i.e., with a
+FontMatrix other than [0.001 0 0 0.001 0 0]) didn't scale Widths to
+match the font scaling. (pdf_font.ps)
+
+Implements the PDF 1.1 color space extensions, except for Lab space.
+(gs_pdf.ps, pdf_draw.ps)
+
+Implements the Rotate key for pages. (pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - When the garbage collector closed a file stream, the stream
+incorrectly attempted to free the buffer. (stream.c)
+
+Separates out some stream implementations to better distinguish the
+graphics core from the language interpreters. (smtf.h, sfilter1.c,
+smtf.c, srld.c, srle.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Compressing characters being entered in the cache could cause an
+invalid memory access. (gsbitops.c)
+ - The setbbox bounding box check was slightly inaccurate.
+(gsdps1.c)
+ - makepattern could create structures in global VM pointing to
+structures in local VM. (gscolor2.h, gspcolor.c)
+ - Out-of-range values during CIE color conversion led to random
+results. (gscie.c)
+ - On output devices with non-inverted Y axes (such as MS Windows),
+Interpolated images would smash memory. (gsimage.c)
+ - 90 degree rotated zero-width images caused an invalid memory
+access. (gsimage1.c)
+ - If #copies was zero, showpage could create bogus empty output
+files. (gdevprn.c)
+ - PageCount didn't take #copies into account. (gsdevice.c)
+ - Indexed or Separation colors with a CIE base or alternate space
+didn't work. (gscie.h, gscie.c)
+
+Implements triangular line caps and joins, in anticipation of adding
+a PCL5 interpreter. (gsline.h, gxstroke.c)
+
+Moves some procedures around for better separation of library from
+interpreter. (gsinit.c, gslib.c, gsmain.c, gsmisc.c)
+
+Moves the standard allocator from the interpreter to the library.
+(gsalloc.h, gxalloc.h, gxobj.h, gsalloc.c)
+
+Starts to change the representation of paths slightly to make it possible to
+identify arcs. This change is backward-compatible for all code except
+callers of gx_path_add_arc. (gxpath.h, gspath1.c, gxpath.c, gxstroke.c)
+
+Adds some framework for keeping track of RasterOp and "transparency" in the
+graphics state, although these don't actually have any effect yet.
+(gsrop.h, gsropt.h, gsstate.h, gxcldev.h, gzstate.h, gsrop.c, gsstate.c,
+gxclist.c, gxclread.c)
+
+Adds a compile-time option for using the Adobe RGB<->CMYK conversion rules.
+(gxdcconv.c)
+
+Adds a driver procedure for identifying band devices. This change is
+backward-compatible for all existing devices. (gdevmem.h, gxdevice.h,
+gsdevice.c, gxclip2.c, gxclist.c, gxcpath.c)
+
+Speeds up gray-scale images on devices requiring banding, and enables
+further optimizations, by reintroducing the distinction between banded and
+non-banded devices. (gxdevice.h, gdevprn.c, gsimage1.c)
+
+Reduces the size of the band list for halftoned images by encoding tile
+indices more compactly. (gxcldev.h, gxclist.h, gxclist.c, gxclread.c)
+
+Extends the band list so it can cache more than 256 halftone tiles, and to
+make better decisions about tile caching. (gxcldev.h, gxclist.h, gxclist.c,
+gxclread.c)
+
+Version 3.37(limited) (5/11/95)
+=====================
+
+Another bug fix release distributed only to customers.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Some documentation about parameter lists was incorrect.
+(gsparam.h)
+ - The documentation did not note that one cannot "pipe" PDF files
+into the interpreter. (use.doc)
+
+Adds documentation for the BJC-600 to devices.doc. (devices.doc)
+
+Procedures
+----------
+
+Changes the debugging switch for OS calls from -Z0 to -Ze, and adds -Z0 for
+high-level GC tracing. (use.doc, gp_unifs.c, ialloc.c, igc.c)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The ps2ascii shell script included an erroneous @d. (ps2ascii)
+
+Enhances ps2ascii to output color and rectangle fill/stroke information if
+COMPLEX is defined. (ps2ascii.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - the BJC-600 driver didn't handle BitsPerPixel correctly.
+(gdevcdj.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Some buggy Type 1 fonts confused the Type 1 font reader.
+(gs_fonts.ps, gs_type1.ps, pdf_font.ps)
+
+Interpreter (PostScript)
+-----------
+
+Fixes bugs:
+ - .registerencoding didn't accept mixedarrays, which could cause an
+error if an encoding was loaded long after initialization. (zfont2.c)
+ - If a program did a lot of saves and restores, the garbage
+collector could get invoked much too often. (iastate.h, ialloc.c, igc.c,
+isave.c)
+
+Changes the name of the rectappend operator to .rectappend, since it isn't a
+standard PostScript operator. (zdps1.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - PDF files didn't interact properly with ps2ascii. (gs_pdf.ps)
+ - setdash wouldn't accept a packed array. (zgstate.c)
+ - PDF files with incorrect generation numbers in object references
+produced an error rather than a warning. (pdf_base.ps)
+
+Version 3.36(limited) (5/4/95)
+=====================
+
+This is a limited-distribution release for distributing bug fixes to a few
+customers.
+
+Documentation
+-------------
+
+Adds some environment variables to the man page. (gs.1)
+
+Procedures
+----------
+
+Adds the psmono device to all 32-bit configurations. (*.mak)
+
+Moves the psmono and 'bit' devices to DEVICE_DEVS12 to avoid exceeding the
+120-character maximum length of the DOS command line. (*.mak)
+
+Drivers
+-------
+
+Changes the pgm[raw] and ppm[raw] drivers so they do *not* automatically
+switch to pbm or pgm/ppm respectively if this is possible for the particular
+page being rendered; adds pgnm[raw] and pnm[raw] drivers that *do* do this.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE. However, existing programs will
+still work; they just won't produce the smallest and simplest possible
+output. (devs.mak, gdevpbm.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A multi-level restore didn't free gstates allocated by
+intermediate saves, causing some global VM to be lost until a garbage
+collection. (isave.h, isave.c, zvmem.c)
+
+Speeds up restore by skipping the scan of the character cache if no new
+names have been allocated since the save. (zfont.c)
+
+Extends the client API to allow for popping return values off the operand
+stack. (imain.h, gs.c, gsmain.c)
+
+Library
+-------
+
+Modifies the character oversampling algorithms to help prevent dropouts.
+(gsbitops.c, gschar.c)
+
+Version 3.35(internal) (5/2/95)
+======================
+
+This is another internal "snapshot" version.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Some of the file names in the `man' page had gotten out of date.
+(gs.1)
+ - Two references to .PageCount hadn't been changed to PageCount.
+(language.doc, devarch.doc)
+
+Procedures
+----------
+
+Puts writeppmfile back in the standard Unix and DV/X configurations, since
+gsftopk uses it. Also puts the PDF reader in all 32-bit configurations.
+(*.mak)
+
+Moves the BMP devices to DEVICE_DEVS11 to avoid exceeding the 120-character
+maximum length of the DOS command line. (bcwin.mak, bcwin32.mak, os2.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - unix-lpr.sh didn't handle 32-bit devices. (unix-lpr.sh)
+ - unix-lpr.sh still used the name .PageCount rather than PageCount.
+(unix-lpr.sh)
+ - font2c gave an error when trying to write general procedures in
+font dictionaries. (font2c.ps)
+
+Adds a pdf2dsc.ps utility for writing out fake DSC-compliant PostScript code
+to invoke the PDF reader, for the benefit of viewer programs that aren't
+PDF-aware. (unix-end.mak, pdf2dsc.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF drivers put out incorrect PageNumber values.
+(gdevtfax.c)
+ - Printer (and file output) devices got closed and reopened
+unnecessarily when changing parameters. (gdevprn.c)
+ - Printer (and file output) devices didn't check for invalid formats
+following a % in OutputFile. (devs.mak, gdevprn.c)
+ - 1-bit memory devices were not considered page devices, unlike all
+other memory devices. (gsdevice.c)
+ - The black-and-white H-P printers didn't close the printer
+properly, causing printing not to happen under MS Windows. (gdevprn.c)
+ - Some compilers didn't like initializing a const char * to NULL.
+(gdevlbp8.c)
+
+Changes the X Windows driver so that if Ghostview specifies a bounding box,
+this also sets ImagingBBox. (gdevxini.c)
+
+At the request of a customer, adds 1-, 4-, 8-, 24-, and 32-bit-deep memory
+devices that store bits in 32-bit units rather than byte units. (gdevmem.h,
+gxdevmem.h, gdevmem.c, gdevm1.c, gdevm2.c, gdevm4.c, gdevm8.c, gdevm16.c,
+gdevm24.c, gdevm32.c)
+
+Adds a new MS Windows printer driver, mswinpr2, that uses a DIB rather than
+a DDB. (gdevwpr2.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - A routine wouldn't compile because of a bug in the SGI C compiler.
+(zcsindex.c)
+ - Some declarations were inconsistent when compiling for segmented
+environments. (gscie.c)
+ - A routine wouldn't compile because of a bug in the VAX C compiler.
+(gscie.c)
+
+Turns on compiler optimization for OS/2; adds PDF support and more devices
+for Win32 and OS/2. (bcwin.mak, bcwin32.mak, os2.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Font loading used 'setglobal' without binding it, which caused
+some EPS files to signal errors. (gs_fonts.ps)
+ - A zero-length string with offset = 0 in a binary object sequence
+caused an error. (iscanbin.c)
+
+Adds a LOCALFONTS switch that causes Ghostscript to load Type 1 fonts into
+the current VM, rather than global VM. According to Adobe, this is what
+Adobe printers (but not other interpreters, such as DPS and CPSI) do.
+(gs_init.ps, gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The 'note' page size command caused pages to be clipped
+improperly. (gs_statd.ps)
+
+Adds "word" image devices. (gs_init.ps, zdevice.c)
+
+Starts converting the interpreter to use an explicit instance pointer. This
+is very fragmentary so far and not really supported. (main.h, gs.c,
+gsmain.c, iccinit.c)
+
+Library
+-------
+
+Adds "word" image devices. (gsdevice.h, gsdevice.c)
+
+Removes the requirement that ImagingBBox[0] and [1] be non-negative. (The
+Adobe specification requires this, but Ghostscript supports more general
+initial CTMs than the Adobe spec.) (gsdparam.c)
+
+Version 3.34(internal) (4/18/95)
+======================
+
+This is a "snapshot" version made for internal purposes. It was never
+released to anyone.
+
+Documentation
+-------------
+
+Updates commprod.doc to be fully consistent with the AGFPL. (commprod.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - tar_x was out of date. (tar_x)
+ - tar_gs assumed that if any PC executables were present, gs.exe
+would exist. (tar_gs)
+ - jpeg.mak said the current IJG version was 5b, but the makefiles
+actually referred to version 5a. (jpeg.mak)
+ - The build rule for the LIPS III driver was incorrect. (devs.mak)
+ - Some definitions in the makefiles occurred out of order.
+(ansihead.mak, cc-head.mak, gcc-head.mak, unixhead.mak, unixtail.mak)
+ - The build rule for dvx-gcc.mak was incorrect. (unix-end.mak)
+
+Interpreter
+-----------
+
+Restructures the CIE caches to move much more of the computation from color
+mapping time to cache loading time. (zcie.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Color conversion of 12-bit images was very slightly inaccurate.
+(gxfrac.h)
+
+Changes the transfer function, black generation, and undercolor removal
+caches so that they sample at 1024 points and don't interpolate, rather than
+sampling at 256 points and interpolating. This significantly improves the
+speed of colored image rendering. ****** LIMITED TO 256 POINTS BECAUSE OF
+O-STACK SIZE LIMIT. ****** (gxfmap.h, gxcmap.c)
+
+Restructures the CIE caches to move much more of the computation from color
+mapping time to cache loading time. (gscie.h, gscie.c)
+
+Version 3.33 (4/13/95)
+============
+
+A few more last-minute bug fixes. This is, finally, the first public
+release since 3.12.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - There was a reference to "VAX with OSF/1", which doesn't exist,
+and an incorrect reference to VAX with Ultrix. (make.doc)
+ - The Unix makefiles incorrectly stated that gsdatadir was only
+relevant to `make install'. (ansihead.mak, cc-head.mak, dgc-head.mak,
+gcc-head.mak)
+ - Notes that DV/X users should use the zip version of the JPEG
+library. (jpeg.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - A command line had gotten too long for the MS-DOS shell.
+(gs.mak)
+ - The VMS DEC C script didn't explicitly select DEC C.
+(vms-decc.mak)
+ - The VMS MODULES.LIS omitted SPDIFF and ZFPDIFF. (modules.lis)
+ - The VMS script had an incorrect entry. (vms.mak)
+ - The `if' fix in 3.31 broke some Unix systems with different
+implementations of sh. (unix-end.mak)
+ - The makefile definition of gscspace_h was out of order. (gs.mak)
+ - An extra ; got written in gconfig_.h on DV/X platforms.
+(dvx-tail.mak)
+ - '.' was incorrectly prepended to the library search list on DV/X
+platforms. (dgc-head.mak)
+ - The build rules for unix*.mak didn't work on DV/X. (unix-end.mak)
+
+Adds a description of the -c quit switch to the help message. (gs.c)
+
+For the DV/X platform, changes /usr/include to /djgpp/include as the place
+to look for header files. I'm not sure this is always correct.
+(dvx-tail.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2ascii would cause an error if given a font that didn't have an
+'X' character. (ps2ascii.ps)
+ - ps2ascii didn't intercept the Level 2 string display operators.
+(ps2ascii.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The Stylus Color driver had an incorrect type name. (gdevstc.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - -dBitsPerPixel= didn't work properly for MS Windows or OS/2 PM.
+(gdevmswn.c, gdevpm.c)
+ - The Win32 platform didn't compile properly. (memory_.h)
+
+Fonts
+-----
+
+Improves the font substitution algorithm to take the face name into account
+in more cases. (gs_fonts.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Unrotated black-and-white bitmaps with an inverted device X axis
+were displaced in X. (gsimage1.c)
+
+Version 3.32 (4/7/95)
+============
+
+More bug fixes. This is still not a public release.
+
+Documentation
+-------------
+
+Further clarifies the "two-phase commit" algorithm for device put_params
+procedures. (drivers.doc, gsparam.h)
+
+Adds a note about a compiler bug under Ultrix 4.4. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some installation scripts could fail because some implementations
+of sh take the status of an `if' condition as the status of the `if'
+command. (unix-end.mak)
+
+Adds "maintainer-clean" as a synonym for "real-clean". (gs.mak)
+
+Adds a -dORIENT1 switch that defines orientation = 1 as portrait for
+setpage[params]. (use.doc, gs_init.ps, gs_lev2.ps, gs_statd.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2ascii didn't redirect %stdout completely. (ps2ascii.ps)
+ - ps2ascii didn't preserve the local/global VM mode. (ps2ascii.ps)
+ - ps2ascii didn't handle fonts with an all-zero or missing bounding
+box correctly. (ps2ascii.ps)
+ - viewpbm didn't scale the image properly. (viewpbm.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The CGM driver wrote out an incorrect color precision value.
+(gdevcgm.c)
+ - The SGI bitmap driver was named "sgi" rather than "sgirgb".
+(gdevsgi.c)
+ - The PCX driver didn't round up an odd line length for gray-scale
+output. (gdevpcx.c)
+ - The PCX driver produced incorrect output for gray-scale or 4- or
+8-bit color. (gdevpcx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS MODULES.LIS file had gotten out of sync with the Unix
+makefiles (again). (modules.lis)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Some compilers won't accept '\l', even in the false arm of a
+preprocessor conditional. (scanchar.h)
+ - A procedure was declared with an incorrect argument type.
+(zcsindex.c)
+ - The scaled font cache didn't copy XUIDs properly. (bfont.h,
+zfont.c, zfont2.c)
+ - status could return true even if the file was closed. (zfile.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The LZW filters were factored improperly. (modules.lis, gs.mak,
+vms.mak, slzwx.h, slzwc.c, slzwd.c)
+
+Changes the DCTDecode filter for compatibility with Adobe implementations:
+ - Ignore bytes preceding the 0xff that marks the beginning of the
+JPEG data. (sdctd.c)
+ - Set MAX_BLOCKS_IN_MCU to 64. (jpeg.mak, gsjpglib.h)
+
+Library
+-------
+
+Fixes bugs:
+ - The "two-phase commit" for device parameters wasn't fully
+implemented. (gsiodev.c)
+ - Asking for a device color map before the device was opened could
+cause a crash. (gsdparam.c)
+ - The scaled font cache didn't copy XUIDs properly. (gxfont.h,
+gsfont.c)
+ - 90 or 270 degree rotated black-and-white bitmaps (including
+bitmapped fonts such as downloaded TrueType fonts) with an inverted device Y
+axis were displaced in Y. (gsimage1.c)
+ - On high-resolution devices, parts of regions filled with halftones
+could fail to be painted. (gxclist.c)
+
+Version 3.31 (4/2/95)
+============
+
+A few final bug fixes for the release. Includes significant speed
+improvements for CIE color, and a first draft of a low-level CGM driver.
+
+Documentation
+-------------
+
+Notes that the BJC600 driver also works for the BJC4000. (devs.mak)
+
+Procedures
+----------
+
+At the suggestion of a user, changes the default protections for installed
+files on Unix and DV/X systems from 775/664 to 755/644. (*head.mak)
+
+At the suggestion of a user, adds a -dNOCIE switch to substitute DeviceGray
+and DeviceRGB color spaces for CIEBasedA and CIEBasedABC spaces
+respectively. (gs_init.ps, gs_lev2.ps)
+
+Utilities
+---------
+
+Changes gslp and its relatives to use ISOLatin1Encoding for output, and to
+send almost all printout to stderr rather than stdout (for use as a filter
+under Unix). (gslp.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The fax/TIFF driver no longer exported gdev_fax_print_page, which
+the DigiFax driver needs. (gdevtfax.c)
+ - The color DeskJet drivers gave an error for BitsPerPixel=3.
+(gdevcdj.c)
+ - The "Windows printer" driver was setting its margins in points
+rather than inches. (gdevwprn.c)
+ - The BJ10 and BJ200 drivers calculated vertical skip distances
+wrong. (gdevbj10.c)
+ - The BJ10 and BJ200 drivers output two garbage bytes following the
+initialization string. (gdevbj10.c)
+
+Adds a preliminary driver that produces low-level CGM output. (gdevcgml.h,
+gdevcgmx.h, gdevcgm.c, gdevcgml.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS files had gotten out of sync with the other makefiles
+(again). (modules.lis, vms.mak)
+ - The MS Windows and OS/2-PM drivers hadn't been updated to handle
+BitsPerPixel as a standard parameter. (gdevmswn.c, gdevpm.c)
+
+Removes the TIFF drivers from the Windows platform, and restores the BMP
+drivers. (bcwin.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The CIE color mapping cache could produce anomalous results
+for the default (all zero values) color if some of the mapping
+functions were non-linear. (zcie.c)
+ - MultiMaster font substitution got confused if substituted
+fonts had their FontName changed. (gs_fonts.ps)
+ - A procedure was declared as private inconsistently. (zdevcal.c)
+ - Some pointer relocation procedures didn't work correctly on
+systems with sizeof(T *) > sizeof(int). (istack.c)
+ - The freelist vector wasn't large enough to handle graphics state
+objects on 64-bit systems, leading to severe memory sandbars. (iastate.h)
+ - The debugging messages from the allocator had gotten inconsistent
+and hard to use. (ialloc.c)
+ - Mixing save/restore with allocation could cause the GC never to
+get run. (isave.c)
+
+Speeds up the mapping of CIE colors. (zcie.c)
+
+Adds a .namestring operator for getting the string of a name without having
+to copy it. (zstring.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The IJG code needed a couple more flags set for IJG v6.
+(gsjmorec.h)
+ - Some pointer relocation procedures didn't work correctly on
+systems with sizeof(T *) > sizeof(int). (stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The end-test for the fast case of monobit images was wrong,
+leading to out-of-range memory accesses. (gsimage1.c)
+ - Monobit images rotated by 270 degrees displayed incorrectly.
+(gsimage1.c)
+ - If a Type 1 font used hint replacement, some parts of the outline
+before the hint replacement ignored the old hints. (gstype1.c)
+ - Some compilers didn't accept a variable name that was the same as
+a macro with parameters. (gxht.c)
+ - A procedure was declared as private inconsistently. (gdevm1.c)
+ - Some pointer relocation procedures didn't work correctly on
+systems with sizeof(T *) > sizeof(int). (gdevmem.c, gsstate.c)
+ - The test on FORCE_HINTS_TO_BIG_PIXELS was backwards. This bug was
+supposed to have been fixed in 3.30, but somehow the fix got lost.
+(gstype1.c)
+ - 90 degree rotated monobit images could drop some scan lines.
+(gsimage*.c)
+
+Speeds up the mapping of CIE colors. (gscie.h, gxcmap.h, gscie.c, gxcmap.c)
+
+Speeds up color images (non-interpolated, 1-8 bits per component) by adding
+a cache for mapped color values. (gximage.h, gsimage.c, gsimage1.c,
+gsimage2.c)
+
+Shrinks the band list file slightly by using only as many bytes as necessary
+for writing out colors, rather than always using 4 bytes. (gxclist.c,
+gxclread.c)
+
+Version 3.30(beta) (3/21/95)
+==================
+
+More bug fixes. The garbage collector and PDF interpreter finally appear to
+work reliably.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - language.doc had gotten out of date. (language.doc)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Changes in the handling of %stdout had broken ps2ascii.
+(gs_dps1.ps, ps2ascii.ps)
+
+Improves ps2ascii to skip empty strings and not output redundant font
+changes. (ps2ascii.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The fax and TIFF drivers didn't free all their working storage.
+(This bug was fixed in 3.27, and the fix somehow got lost.) (gdevtfax.c)
+
+Adds new drivers:
+ - sgirgb, to produce SGI RGB raster files. (gdevsgi.c)
+ - tiffcrle, to produce output in TIFF "CCITT 1-dimensional Huffman
+RLE" format (Group 3 fax with no EOLs). (gdevtfax.c)
+ - tifflzw, to produce output in TIFF LZW format (using the existing
+CCITTFaxEncode filter code). (gdevtfax.c)
+ - tiffpack, to produce output in TIFF PackBits format. (gdevtfax.c)
+
+Interpreter (PostScript)
+------------------------
+
+Fixes bugs:
+ - If the current screen was set with a halftone, setcolorscreen
+wouldn't accept what currentcolorscreen returned. (gs_dps1.ps)
+ - debug_print_full_ref didn't print t_oparray objects correctly.
+(idebug.c)
+ - The internal data for a font could be allocated in a different VM
+space from the font dictionary, causing dangling pointers. (zfont2.c)
+ - definefont became confused if a program failed to delete the FID
+from a re-encoded font. (This is questionable PostScript, but dvips does
+it.) (zfont2.c)
+ - If a BuildChar procedure did a save before the setcachedevice and
+a restore afterwards, the memory manager would attempt to free the cache
+device after it had already been freed by the restore, leading to damaged
+freelists. (gschar.c)
+ - setresolution (in statusdict) was ignored. (gs_lev2.ps,
+gs_statd.ps)
+ - If a string containing a string containing a \ was passed to the
+token operator, the \ was not recognized properly in a Level 2 environment.
+(iscan.c)
+ - A couple of default dictionary sizes had become too small.
+(iinit.c)
+
+Makes DOS EOF (control-Z, 0x1a) a self-delimiting token, like left bracket.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE, but it should not have any adverse
+effects. (gs_init.ps, iscan.c, iscantab.c)
+
+Distinguishes arch_small_memory from arch_ints_are_short, and adds a new
+-Z. switch to force small-memory table sizes regardless of actual memory
+size. (dstack.h, idict.c, zpcolor.c, zvmem2.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - A page with no Contents caused an error. (pdf_main.ps)
+ - Executing a Form resource caused an error. (pdf_draw.ps)
+ - Outlines with open entries caused an error. (pdf_main.ps)
+ - Embedded Type 3 fonts caused an error. (pdf_draw.ps, pdf_font.ps)
+ - The Widths array of fonts was ignored. (pdf_font.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Freeing an entry in the pattern cache didn't clear the pointers to
+the raster data, producing a dangling reference that confused the garbage
+collector. (gxpcmap.c)
+ - The test on FORCE_HINTS_TO_BIG_PIXELS was backwards. (gstype1.c)
+ - The pattern cache bookkeeping was incorrect. (gxpcmap.c)
+ - Depending on the order in which pointers were relocated, the
+garbage collector could incorrectly relocate pointers from the character
+cache. (gxfcache.h, gsfont.c, gxccache.c, gxccman.c)
+
+Changes the fast case of black-and-white images so it aligns scaled images
+with the device coordinate system, to improve performance. (gsimage1.c)
+
+Extends the coordinate transformation routines to handle absurdly large
+translation values in the CTM as long as the final device device coordinates
+are within fixed-point range. (gxmatrix.h, gxpath.h, gschar.c, gscoord.c,
+gsmatrix.c, gxhint2.c, gxpath2.c)
+
+Distinguishes arch_small_memory from arch_ints_are_short, and adds a new
+-Z. switch to force small-memory table sizes regardless of actual memory
+size. (gdevprn.h, gxpcolor.h, gzht.h, std.h, gsfont.c, gsht1.c, gspaint.c,
+gsstate.c, gxcht.c, gxht.c, gxpcmap.c)
+
+Version 3.29(internal) (3/8/95)
+======================
+
+Another bug-fix release. This release processes all but 7 of the 500+ files
+on the Adobe Acrobat Sampler CD-ROM without giving an error. The garbage
+collector finally appears to be stable. This version was created for a
+customer; it was not released to the general public or even to the beta test
+list.
+
+Documentation
+-------------
+
+Documents the possible need to set LD_RUN_PATH on SVR4 platforms.
+(make.doc)
+
+Expands the description of the device life cycle, and of the constraints on
+put_params procedures. (drivers.doc)
+
+Adds an explicit copyright notice to the Aladdin Ghostscript Free Public
+License. (PUBLIC)
+
+Clarifies that the Win32s documentation also applies to Windows NT.
+(make.doc)
+
+Procedures
+----------
+
+Removes the obsolete writeppmfile operator from the standard configurations.
+(gs.mak)
+
+Changes the Watcom makefiles to work properly with Watcom C/C++ 10.0.
+(make.doc, msc.mak, watc.mak, watcwin.mak, wccommon.mak)
+
+Utilities
+---------
+
+Adds a wftopfa utility for converting the Wadalab fonts to usable Type 0 and
+Type 1 form. (wftopfa)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Entries added automatically by definefont (FontInfo, ExactSize)
+could cause a font dictionary to become full. (gs_fonts.ps, gs_type1.ps)
+ - wrfont.ps couldn't deal with very long CharStrings. (wrfont.ps)
+
+Makes the name of the Fontmap file an easily editable parameter.
+(gs_fonts.ps)
+
+Adds a utility for converting the Wadalab font to usable Type 0 and Type 1
+form. (wrfont.ps, wftopfa.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The top margin for printer (and fax) devices was computed
+incorrectly, using the X resolution rather than the Y resolution.
+(gdevprn.h)
+ - Changing the page size or resolution of a printer device closed
+and reopened the device unnecessarily. (gdevprn.c)
+ - Changing the page size of the X11 device didn't change the initial
+matrix, so (0,0) didn't wind up in the lower left corner. (gdevx.c)
+ - The bit devices didn't allow changing the number of bits per
+pixel. (gdevbit.c)
+
+Adds a settable .IsPageDevice boolean device parameter to the X Windows
+driver. The default value is true. (gdevx.h, gdevx.c)
+
+Changes the PPM driver so that it chooses between PBM/PGM/PPM on a
+page-by-page basis, rather retaining the most general format ever required
+by any page. (gdevpbm.c)
+
+Interpreter (PostScript)
+------------------------
+
+Fixes bugs:
+ - The current page device could be null, rather than an empty
+dictionary. (igstate.h, zchar.c, zdevice.c, zdevice2.c, zgstate.c)
+ - The scanner didn't signal an error for names or strings that were
+too long. (iscan.c)
+ - A missing header file upset the VAX compilers. (ztype.c)
+ - Some places expecting dictionary operands didn't check the type,
+because they incorrectly assumed that the dict_check_read/write macro did
+this. (idict.h, zdevice2.c, zht2.c, zmisc2.c)
+ - The definition of quit in systemdict wasn't disabled within
+encapsulated jobs. (gs_lev2.ps)
+ - resetfile gave an error if the file was closed, rather than doing
+nothing. (zfileio.c)
+ - The scanner attempted to free an uninitialized pointer if it
+reached EOF after a / or //. (iscan.c)
+ - A restore in a different file than the corresponding save caused
+an invalidrestore error. (gs_init.ps)
+ - The default value of EndOfData in RunLengthDecode streams was set
+to false. (zfilter.c)
+ - .registerencoding didn't invoke the save machinery correctly,
+leading to GC problems. (zfont2.c)
+ - The facility for overriding .printerror didn't work correctly.
+(gs_init.ps)
+ - gs_run_file_open wasn't public. (gsmain.c)
+ - The interpreter returned e_undefined for undefined error names,
+rather than the error code. (interp.c)
+ - Allocation in system memory (specifically, adding a block to a
+stack) couldn't trigger automatic garbage collection. (interp.c, igc.c,
+zvmem2.c)
+ - A restore in a different invocation of gs_run_string than the
+corresponding save would stop reading the string. (files.h, gsmain.c,
+iccinit.c, zfile.c)
+ - The Type 1 rasterizer state included a pointer into the middle of
+an object, confusing the garbage collector. (zchar1.c, zfont1.c)
+ - When the garbage collector deleted a name, it didn't zero out the
+string pointer. (iname.c)
+ - On platforms where obj_align_mod > 4, the memory manager could
+access 1 beyond the end of its freelists. (iastate.h)
+ - makefont and scalefont didn't check the type of their font operand
+soon enough. (zfont.c)
+ - restore didn't finalize the objects it freed. (isave.c)
+ - restore didn't free system VM. (isave.c)
+ - Freeing a ref array that occupied an entire chunk didn't free the
+chunk. (ialloc.c)
+
+Adds a .runexec operator which implements the 'close if error' function of
+run. (zfile.c, zfileio.c)
+
+Moves the obsolete writeppmfile operator into a separate file. (zfileio.c,
+zwppm.c)
+
+Makes the statistics returned by the memory manager more accurate.
+(ialloc.c, zvmem.c)
+
+Adds a (read-only) %Calendar% IODevice. (zdevcal.c)
+
+Adds a "hook" in the character operators to allow external code to
+intervene; this is needed for a customer. (ichar.h, zchar.c, zchar2.c)
+
+Makes control-D (0x04) a self-delimiting token, like left bracket. THIS IS
+A NON-BACKWARD-COMPATIBLE CHANGE, but it should not have any adverse
+effects. (scanchar.h, iscan.c, iscantab.c)
+
+Changes the error stack printout so that it puts line breaks between items
+iff the items are being printed with ==. (gs_init.ps)
+
+Uses finalization to close streams being freed. (igc.c, zfile.c, ziodev.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Embedded Type 1 fonts that invoked save and restore while being
+read caused an error. (pdf_font.ps)
+ - Large files that referenced a non-alphabetic font for the first
+time late in the file could cause an error. (pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - SubFileDecode streams didn't copy partial matches of the EOD
+string into their output. (sfilter1.c)
+
+Makes switching between read and write modes a stream procedure. (stream.h,
+sfile.c, sfileno.c, stream.c, zfileio.c)
+
+Makes file streams close themselves when finalized. (We can't do this for
+other streams, because finalization procedures aren't allowed to free
+storage explicitly.) (stream.h, sfile.c, sfileno.c, stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The obsolete files gcdefs.h and gsfile.c were still included in
+the fileset.
+ - A number of places didn't deal with null patterns properly (p_tile
+== 0). (gxdcolor.h, gspcolor.c, gxpcmap.c)
+ - The pattern tiling algorithm was numerically unstable, especially
+if the X/YStep vectors were close to the axes. (gxcolor2.h, gspcolor.c,
+gxpcmap.c)
+ - setdeviceparams checked the values of read-only byte array
+parameters incorrectly. (gsdparam.c)
+ - The statistics macros in gxfill.c didn't use DO_NOTHING when
+disabled. (gxfill.c)
+ - Changing the orientation of a device closed and reopened the
+device unnecessarily. (gsdparam.c)
+ - ioerrors occurring when writing command lists weren't reported
+properly. (gxclist.h, gxclist.c)
+ - Errors from device procedures weren't always propagated up to
+clients. (gsimage1.c, gsimage3.c, gxclip2.c, gxclist.c)
+ - Overflowing the fixed-point translation values in the CTM caused a
+floating point exception rather than a limitcheck. (gxmatrix.h, gscoord.c)
+ - charpath set the current point correctly, but didn't append a
+moveto element to the path. (This mostly affected Mathematica output.)
+(gzpath.h)
+ - Image devices mapped colors incorrectly. (gdevmem.c, gdevm16.c)
+ - On devices with color capability but fewer than 4 bits per pixel,
+color halftones didn't work (and could cause an arithmetic exception).
+(gxdither.c)
+ - Black-on-white memory devices didn't map colors properly.
+(gdevprn.h, gxdevice.h, gxdevmem.h, gdevmem.c, gdevm1.c, gsdevice.c)
+ - Memory devices with a non-zero origin in their initial matrix
+clipped the image improperly. (gsdevice.c)
+ - The Type 1 rasterizer state included a pointer into the middle of
+an object, confusing the garbage collector. (gstype1.h, gxfont1.h,
+gxtype1.h, gstype1.c, gxhint2.c)
+ - The band rasterizer could produce garbled output for images
+(including characters) on 64-bit architectures. (gxclread.c)
+ - Bounding boxes (for pathbbox and setbbox) could be slightly
+inaccurate. (gsmatrix.c)
+ - On 64-bit architectures, halftone tiles less than 16 bits wide
+were handled incorrectly. (gxclist.c)
+
+Adds an .IsPageDevice boolean device parameter (normally read-only).
+(gsdparam.c)
+
+Removes the library code for implementing the obsolete writeppmfile
+operator. (gswppm.c)
+
+Makes the default matrix (for initmatrix and defaultmatrix) a settable
+parameter in the graphics state. (gscoord.h, gzstate.h, gscoord.c,
+gsdevice.c, gsdparam.c)
+
+Makes the statistics returned by the memory manager more accurate.
+(gsmemory.h)
+
+Adds a compile-time flag to choose whether or not to force Type 1 hints to
+"big pixel" boundaries when oversampling. (gstype1.c)
+
+Changes the .PageCount device parameter back to PageCount, because the
+change broke some scripts. (gsdparam.c)
+
+Adds optimization for 90 degree rotated images with pure colors.
+(gximage.h, gsimage.c, gsimage1.c)
+
+Changes the band rasterizer so that replicated halftone tiles are written on
+the band list in unreplicated form. (gsbitops.h, gxcldev.h, gsbitops.c,
+gxclist.c, gxclread.c, gxht.c)
+
+Changes the .HWBitsPerPixel device parameter to BitsPerPixel. (drivers.doc,
+language.doc, gdevcdj.c, gdevstc.c, gsdparam.c)
+
+Version 3.28(beta) (2/13/95)
+==================
+
+Another bug-fix beta release. The number of bugs being fixed in each of
+these sub-releases does exceed the number of new bugs introduced, but the
+latter number is discouragingly high.
+
+Documentation
+-------------
+
+Adds some information about handling VMS file attributes for files
+transferred by FTP. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - unix-gcc.mak said the static linkage switch for SunOS was -Bstatic
+rather than -static. (unix-gcc.mak)
+ - Some dependency lists in gs.mak were out of date. (gs.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - markhint.ps didn't check for protected fonts. (markhint.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The cdj driver had a byte/char agreement problem. (gdevcdj.c)
+ - The cdj driver attempted to initialize a dynamic array.
+(gdevcdj.c)
+
+Removes the setting of InputAttributes and OutputAttributes from the H-P
+drivers, since this causes more problems than it solves. (gdevdjet.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - makeoperator assigned incorrect attributes to operators. (bug
+introduced in 3.27) (opdef.h, iinit.c, iutil.c, zmisc.c)
+
+Library
+-------
+
+Fixes bugs:
+ - gs_makeimagedevice didn't set the caller's pointer to the newly
+created device. (bug introduced in 3.27) (gsdevice.c)
+ - There were still some mismatches between char * and byte * values.
+(gsdparam.c)
+ - The halftone replication algorithm could produce inappropriately
+large replicated masks. (gxht.c)
+ - stroke usually did the wrong thing for degenerate (single-point)
+subpaths. (gxstroke.c)
+
+Version 3.27(beta)(withdrawn) (2/8/95)
+=============================
+
+Yet another bug-fix beta release. This release had so many serious problems
+(the most serious being at least one changed file that the release tool
+failed to include in the fileset) that it was withdrawn less than a day
+after it was issued.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The NEWS for 3.26 didn't mention the fact that the stdxxx stream
+interface used by MS Windows, OS/2, and Macintosh implementations had
+changed. (NEWS)
+ - The file public.doc wasn't distributed with the previous fileset.
+
+Brings the NeXTSTEP documentation up to date for NeXTSTEP releases 3.2 and
+subsequent. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some dependency lists in gs.mak were out of date. (gs.mak)
+ - A 'fi;' was missing in the Unix install script. (unix-end.mak)
+ - There was no VMS build script for the PDF options. (vms.mak)
+ - The VMS script used CC_QUALI instead of CC_QUAL in several places.
+(vms.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2epsi's usage prompt referred to "pstoepsi". (ps2epsi)
+ - ps2epsi set PATH and LOCALPATH unilaterally. (ps2epsi)
+
+Comments out the sample usage line at the end of viewjpeg.ps. (viewjpeg.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The fax and tiff drivers didn't free all of their working storage.
+(gdevtfax.c)
+
+Adds user-contributed drivers for the BJC 600 and ESC/P printers.
+(devs.mak, gdevcdj.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Some necessary casts of string parameters to (const byte *) were
+omitted. (gp_mswin.c, gp_os2.c)
+
+Adds the psmono and bit* drivers, and removes the p*m drivers, in the OS/2,
+32-bit MS-DOS, and 32-bit Windows configurations. (bcwin32.mak, os2.mak,
+watc.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The Fontmap for Ultrix had somehow become slightly incorrect.
+(Fontmap.Ult)
+
+Removes the font file names from the dependency lists in cfonts.mak. This
+makes cfonts.mak readily usable with any set of fonts, but it also means
+that it will always run font2c, rather than being able to avoid this if the
+.c file is up to date. (cfonts.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Some operators could fail if the stdxxx streams weren't currently
+open. (files.h, zfileio.c, ziodev.c)
+ - setpagedevice didn't handle unrecognized keys properly.
+(gs_setpd.ps)
+ - The value returned for the HWColorMap device parameter was
+allocated incorrectly, confusing the garbage collector. (iparam.c)
+ - Typing ahead at the >>showpage<< prompt no longer caused all
+further pages to be processed without stopping. (gs_init.ps)
+ - Setting DEVICEWIDTHPOINTS or DEVICEHEIGHTPOINTS on the command
+line caused a typecheck. (gs_init.ps)
+ - The garbage collector didn't handle halftone threshold arrays
+properly. (zht2.c)
+ - setdefaulttimeouts caused an error on Level 2 systems.
+(gs_lev2.ps)
+ - cvi and cvr weren't equivalent to token followed by a type check.
+(iscan.h, iscannum.h, iscan.c, iscannum.c, ztoken.c, ztype.c)
+ - In Level 2 systems, image and colorimage didn't allow 12 bits per
+sample. (zpaint.c)
+ - If debugging was enabled, the garbage collector printed spurious
+error messages about the allocator objects not being in a chunk. (ialloc.c)
+ - restore didn't reset the count of operator procedures, so the
+operator procedure table could fill up. Fixing this required splitting the
+op_array_table into a global table and a local table. (opdef.h, iinit.c,
+iutil.c, zmisc.c)
+ - .forgetsave could leave a dangling pointer in the memory manager,
+causing an access error. (ialloc.c, isave.c)
+ - Freed objects weren't always marked as freed, which could confuse
+the memory validator. (ialloc.c)
+ - .forgetsave didn't mark inner chunk headers as free, leading to
+access errors. (isave.c)
+
+Changes the representation of operator procedures so that they point
+directly to their definition in the op_array_table. (iref.h, opdef.h,
+idebug.c, igc.c, igcref.c, interp.c, zmisc.c)
+
+Removes .makeglobaloperator. (zmisc.c)
+
+Adds patches to discard some common garbage produced by H-P-oriented
+applications and drivers. (gs_init.ps)
+
+Changes the >>showpage<< prompt so that if the input reaches EOF, the
+interpreter still stops after the next >>showpage<<, rather than processing
+all subsequent pages. This is a consequence of the bug fix that
+automatically reopens the stdxxx files.
+
+Adds an optional dictionary parameter for the RunLengthEncode/Decode
+filters, to allow specifying EndOfData. The default is true. (zfilter.c)
+
+Adds ByteTranslateEncode/Decode filters. (zfilter2.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The K > 0 option of the CCITTFaxDecode filter switched back to 2-D
+encoding if an output buffer boundary fell in the middle of a 1-D line, and
+signalled an error if an input buffer boundary fell in the middle of an EOL.
+(scfd.c)
+
+Adds an EndOfData flag to the RunLengthEncode/Decode filters. If true, RLE
+generates 128 as EOD, and RLD recognizes it; if false, RLE does not mark
+EOD, and RLD ignores 128. (srlx.h, gxclist.c, gxclread.c, sfilter1.c)
+
+Adds ByteTranslateEncode/Decode streams. (sbtx.h, sfilter2.c)
+
+Library
+-------
+
+Fixes bugs:
+ - There were some mismatches between char * and byte * values.
+(gsdparam.c)
+ - Failure to round a scaling coordinate caused one-for-one
+black-and-white images to render slower than they should. (gsimage.c)
+ - Setting PageSize without setting HWResolution could cause an
+invalid memory access. (gsdparam.c)
+ - The garbage collector didn't handle halftone threshold arrays
+properly. (gxht.h, gsht.c, gsht1.c)
+
+Version 3.26(beta) (2/1/95)
+==================
+
+Yet another bug-fix beta release, still not ready for public release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The description of device properties had gotten out of sync with
+the code. (language.doc)
+
+Splits off documentation specific to the Aladdin (non-GNU) release into a
+separate file. (readme, public.doc, unix-end.mak)
+
+Adds a pointer to a collection of other free fonts (including some Cyrillic
+ones) available on the net. (public.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - On VMS systems with both VAX C and DEC C installed, the build script
+used VAX C rather than DEC C. (vms.mak)
+ - zfdecode.c didn't have a build rule. (gs.mak)
+ - Several macros in the makefile were used before they were defined.
+(gs.mak)
+ - Several macros in the makefile were used without being defined.
+(gs.mak)
+
+Replaces the gssetdev, gssetmod, and gsaddmod scripts with more variants of
+echogs. (echogs.c, gs.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The ps2ascii shell script passed a -f flag to the shell, which not
+all shells recognize. (ps2ascii)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Due to a typo in an initialization string, the H-P printers didn't
+reset the top margin to zero. (gdevdjet.c)
+
+Adds InputAttributes and OutputAttributes entries to the H-P drivers. (This
+should probably be generic to all printers.) (gdevdjet.c)
+
+Replaces the contributed Epson Stylus Color driver with a newer version.
+(devices.doc, gdevstc.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - DEC C complained about 'abs' and 'exit' not being declared. (x_.h)
+ - gp_mswin.c and gp_os2.c wouldn't compile. (gp_mswin.c, gp_os2.c,
+ziodev.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The default CIE rendering dictionary gave everything a magenta tint.
+(gs_lev2.ps)
+ - Changing HWResolution and PageSize in the same call of
+setpagedevice produced an incorrect HWSize. (gsdparam.c)
+ - .putdeviceparams didn't accept all the keys that .getdeviceparams
+returned. (gsdparam.c)
+ - The default handler for interrupt and timeout errors didn't push a
+current object (command) on the stack. (gs_init.ps)
+ - The garbage collector didn't handle strings larger than 64K
+properly. (iastate.h, ialloc.c, igcstr.c)
+
+Adds media matching and Policy consultation to the implementation of
+setpagedevice. (gs_setpd.ps)
+
+Adds a MaxGlobalVM system parameter. (zmisc2.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxEncode filter could access a byte beyond the end of
+the allocated area. (scfe.c)
+ - The CCITTFaxDecode filter could get an ioerror if a buffer
+boundary fell in exactly the wrong place. (scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The garbage collector didn't trace colored halftones properly.
+(gzht.h)
+ - The garbage collector didn't relocate the bitmap pointers in
+halftone caches properly. (gzht.h, gxht.c)
+
+Adds the ability to transmit dictionaries through the param_list mechanism
+(specifically, as device parameters). This change is
+non-backward-compatible only for implementors of parameter lists, which only
+exist within the Ghostscript core. (gsparam.h, iparam.h, iparam.c)
+
+Removes the InitialMatrix device property. (gsdparam.c)
+
+Version 3.25(beta) (1/24/95)
+==================
+
+Yet another bug-fix beta release. There are still at least half a dozen
+significant known bugs to be fixed before a public release.
+
+Documentation
+-------------
+
+Notes that on Unix systems, one should not edit 'makefile', but should edit
+the individual subfile and run tar_cat. THIS IS A NON-BACKWARD-COMPATIBLE
+CHANGE. (make.doc)
+
+Adds information on the Macintosh implementation. (readme)
+
+Procedures
+----------
+
+Fixes bugs:
+ - make clean failed on Unix systems where rm -f requires at least one
+file name. (gs.mak)
+ - math_.h was omitted from many dependency lists. (gs.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The X Windows and MS Windows draw-line routines couldn't possibly
+produce sufficiently correct output (since the interface only provides integer
+coordinates). (gdevx.c, gdevwddb.c)
+
+In response to patent-related actions by Unisys and CompuServe, removes the
+GIF driver. (*.mak)
+
+Changes dci_std_color (and std_device_std_color_* and prn_device_std_*) so
+that if the number of bits per pixel is 32, the device is defined as CMYK
+rather than RGB. (gxdevice.h)
+
+Removes the tseng8 device, which is no longer useful. (devs.mak, gdevsvga.c)
+
+Adds pseudo-alpha support to the SVGA drivers, via the TextAlphaBits and
+GraphicsAlphaBits device parameters. (gdevsvga.h, gdevsvga.c)
+
+Adds a user-contributed driver for the Epson Stylus Color printer. (devs.mak,
+gdevstc.c, devices.doc)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS build scripts had gotten out of sync (again). (vms*.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The emulator name array was incorrectly declared const in one place.
+(gs.c)
+ - A closed file could incorrectly appear to be 'eq' to another file
+(open or closed). (iutil.c)
+ - If %stdin/%stdout/%stderr was ever closed, it couldn't be
+reopened. (gs_btokn.ps, gs_init.ps, files.h, zfile.c, zfileio.c, zfilter.c,
+zfproc.c, ziodev.c)
+
+Changes (almost) all the operator routines to 'static'. (z*.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The raster value for replicated tiles in the halftone cache was
+incorrect, causing unaligned memory accesses. (gxht.c)
+ - stroke and strokepath could produce slightly inaccurate output
+(leading to slight visible anomalies) as a result of stroke adjustment.
+(gxstroke.c)
+ - Attempting to draw an arc with zero radius could cause a numeric
+exception. (gspath1.c)
+ - Setting the Orientation of a device to null resulted in actually
+setting it to a random value. (gsdparam.c)
+ - charpath, stringwidth, and cshow attempted to remap the current
+color unnecessarily. (gschar.c)
+
+Adds the ability to trace calls on the sqrt function (and possibly other math
+functions in the future.) (math_.h, gsmisc.c)
+
+Adds additional interrupt checks in the banding code. (gxclist.c, gxclread.c)
+
+Version 3.24(beta) (1/17/95)
+==================
+
+This was supposed to be a public release, but too many bugs showed up in 3.23,
+so this is another bug-fix beta release. This is the first release with a
+working PDF reader.
+
+Documentation
+-------------
+
+Notes that Solaris requires using installbsd instead of install. (make.doc)
+
+Procedures
+----------
+
+Changes 'make mostlyclean' so that it doesn't delete the Ghostscript
+executable (but deletes everything else that 'make clean' does). (gs.mak)
+
+Changes the link list generator so it eliminates duplicate library requests.
+(genconf.c)
+
+Factors the interpreter further so as to include less unnecessary PostScript
+support in the PDF interpreter. (gs.mak, zpath.c, zpath1.c)
+
+Adds a printout of the available language interpreters to the -h message.
+(genconf.c, gs.c, iinit.c, gs.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The alternate X drivers used a cast in an initializer, causing a
+compilation error on some platforms. (gdevxalt.c)
+
+Adds a driver for the LaserJet IIID, including duplex printing if specified by
+the Duplex page device parameter. (gdevdjet.c)
+
+Adds Orientation to the bit device. (gdevbit.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - There was an extraneous pfen-> in the NT file system module, causing
+a compilation error. (gp_ntfs.c)
+ - The DLL code referred to an obsolete symbol a_foreign. (gsdll.c)
+ - The VMS build scripts omitted the LaserJet 4 driver. (vms-*.mak)
+ - The VMS build scripts had several other minor errors. (vms.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Defining a font alias in global VM with a name that was a string in
+local VM caused an error. (gs_fonts.ps)
+ - The font compiler referred to an obsolete symbol a_foreign.
+(font2c.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - There was an extraneous '#' before an extern declaration.
+(gsmain.c)
+ - The interpreter could (incorrectly) attempt to expand the e-stack.
+(istack.h, interp.c, istack.c)
+ - zfproc.c called memcpy but didn't include memory_.h. (zfproc.c)
+ - A garbage collection occurring within a 'save' would often smash
+memory. (igc.c)
+ - If the last character returned by the procedure of a procedure-based
+filter was \r, readline could get an endless loop. (zfileio.c)
+ - Saving a change to a ref member of a structure confused the garbage
+collector. (isave.h, isave.c, zdict.c)
+ - The -Zu debugging printout could cause an access error under rare
+circumstances. (isave.c)
+ - Save objects could get allocated in global VM, causing dangling
+references. (zvmem.c)
+ - The vmsave object created by the interpreter for a save didn't get
+freed properly if the memory manager created an invisible save level, which
+could cause the next garbage collection to crash. (zvmem.c)
+ - 'run' always printed an error message, rather than letting the
+top-level control loop do it. (gs.c, gs_init.ps)
+
+Adds support for duplex devices. (gxdevice.h, gsdparam.c, gs_statd.ps,
+gs_setpd.ps)
+
+Adds the beginnings of support for CID-keyed fonts. (gs_cidfn.ps)
+
+Changes the format of the stack dump printed for errors, to make it easier to
+read. (gs_init.ps)
+
+Interpreter (PostScript)
+------------------------
+
+Fixes bugs:
+ - The .local/global allocation operators always allocated in system
+VM. (zsysvm.c)
+ - setpage[params] caused an error. (gs_lev2.ps)
+ - If an error occurred during a cshow or (x|y|xy)show, the interpreter
+freed the enumerator twice. (zchar.c, zchar2.c)
+
+Changes setpageparams so that orientation = 0 means portrait. This is not
+compatible with AGFA's convention for roll-feed devices, but it is compatible
+with the more common cut-sheet printers. (gs_statd.ps)
+
+Adds meaningful values for the Emulator resource. (gsmain.c, gs_res.ps)
+
+Makes -Z? validate the state of memory before and after save and restore.
+(ialloc.h, igc.h, ialloc.c, igc.c, ilocate.c, zvmem.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - The Unix install script didn't install the PDF files if they were
+present. (unix-end.mak)
+ - PDF to PostScript conversion didn't work at all. (It still doesn't
+work very well.) (pdf_2ps.ps, pdf_main.ps)
+ - Images with an Indexed color space and no Decode entry caused an
+error. (pdf_draw.ps)
+ - The 'Page <n>' messages were printed even if QUIET was set.
+(pdf_main.ps)
+
+Changes the interpreter so that when it encounters an unknown operator, it
+prints an error message and continues, rather than signalling an error.
+(pdf_base.ps)
+
+Makes F a synonym for f if there is nothing on the operand stack, to
+compensate for a bug in some Adobe software. (pdf_base.ps)
+
+Changes pdfgetpage so it uses 1-origin rather than 0-origin indexing. THIS IS
+A NON-BACKWARD-COMPATIBLE CHANGE. (pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The Group 3 2-D and Group 4 encoders produced incorrect output if a
+scan line beginning with a black pixel was followed by a scan line beginning
+with a white pixel. (scfe.c)
+ - A SubFileDecode filter with a count of 1 and a non-empty EOD string
+would smash memory. (sfilter1.c)
+
+Updates the DCT filters so they will work with the latest version (5a) of the
+IJG library. (*.mak, jpeg.mak, sjpegerr.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A call with integer parameters to a procedure with floating point
+arguments didn't work on non-ANSI compilers. (gsimage.c)
+ - Arcs could get turned into polygons if the scaling values in the CTM
+were very large and the radius was (in user space coordinates) very small.
+(gspath.c)
+ - The current point was defined when a BuildChar procedure was called.
+(This bug was documented as fixed in version 2.2!) (gschar.c)
+
+Adds support for Orientation and Duplex page device parameters, for those
+devices that support these. (gdevprn.h, gxdevice.h, gsdevice.c, gsdparam.c)
+
+Version 3.23(beta) (1/5/95)
+==================
+
+This is almost entirely a bug fix release. It also includes a largely working
+PDF reader. This is intended as the beta test release for the next public
+release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - COPYLEFT, COPYING, NEWS, PUBLIC, README, and the standard Fontmap
+were omitted from the 3.22 fileset.
+
+Documents the use of the -oldc switch to work around a compiler crash on
+the DECstation.
+
+Expands and clarifies the documentation for building the DesqView/X version
+with djgcc. (make.doc)
+
+Adds documentation on the "600x300" H-P inkjet printers, explaining why
+this alleged higher resolution is not available. (devices.doc)
+
+Adds to the PUBLIC license a warning that it is not a GNU License, and a
+requirement to include a copy of or a pointer to the License in any written
+material. (PUBLIC)
+
+Documents the fact that Ghostscript *does* attempt to look up files in the
+current directory first. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - In VMS.MAK, .JPEG should have been changed to .JPEG-5 in a few
+places. (vms.mak)
+
+Adds the pjxl300 driver to all configurations that include the other color
+DeskJet drivers. Replaces pjet and pjetxl with pj and pjxl. (*.mak)
+
+Makes 'run' recognize PDF files if the PDF reader is included.
+(pdf_main.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - viewjpeg.ps needed the test for languagelevel = 2 at the
+beginning of the file. (viewjpeg.ps)
+ - prfont.ps used 'min', which isn't a standard PostScript operator.
+(prfont.ps)
+ - prfont.ps created Encoding vectors that weren't 256 elements
+long. (prfont.ps)
+
+Adds the gsdj500 script to the installation list. (unix-end.mak)
+
+Changes the Unix "line printer" shell scripts to add the date to the page
+header. (gsbj, gsdj, gsdj500, gslj)
+
+Changes ansi2knr so that it will work properly on systems where the ctype
+macros don't handle 8-bit characters correctly. (ansi2knr.c)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Some compilers don't allow casts in initialization expressions.
+(gdevx.c, gdevxalt.c)
+ - The cdj drivers didn't initialize the color_info structure
+properly. (gdevcdj.c)
+
+Adds another alternate X Windows driver, x11mono, that is a black-and-white
+device. (devs.mak, gdevxalt.c)
+
+Adds a user-contributed driver for the Apple Imagewriter LQ. (devs.mak,
+gdevadmp.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS MODULES.LIS file had gotten out of sync with the makefile
+(again); GDEVABUF and GSBITOPS were missing. (modules.lis)
+ - The VMS script file had gotten out of sync with the makefile
+(again). (vms.mak)
+ - The MS Windows platform code didn't recognize Windows 95 (Windows
+4.0) as equivalent to Windows NT. (gp_mswin.c)
+ - File name enumeration didn't work on OS/2 or win32. (gp_ntfs.c,
+gp_os2.c)
+ - -sOutputFile= didn't work under MS Windows. (gp_mswin.c)
+
+Changes the SCO Unix direct frame buffer driver so it generates in-line
+instructions to access the frame buffer, for a dramatic speed improvement.
+(gdevpcfb.h, gdevsco.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - If a font couldn't be found in the Fontmap, a recursion loop
+sometimes occurred. (gs_fonts.ps)
+ - Aliases for global fonts weren't automatically created as global,
+possibly leading to a recursion loop. (gs_dps1.ps, gs_fonts.ps)
+ - If a font was loaded into global VM within an inner save, the restore
+deleted it from FontDirectory but not from SharedFontDirectory, causing a
+possible recursion loop. (gs_dps1.ps, gs_fonts.ps, idict.h, idict.c, zdict.c)
+
+Further improves the algorithm for substituting for unknown fonts.
+(gs_fonts.ps)
+
+Interpreter (PostScript)
+------------------------
+
+Fixes bugs:
+ - zcontrol.c had an assignment of const char * to const byte *,
+which some compilers don't like. (zcontrol.c)
+ - Setting an Indexed color space based on a CIE space caused an
+attempt to free a random block of memory. (zcsindex.c)
+ - Some compilers don't like mixing conditionals and casts in
+initialization expressions. (iref.h)
+ - Some calculations of table sizes for string garbage collection
+didn't work if sizeof(long) != 4, leading to smashed strings. (iastate.h,
+ialloc.c, igcstr.c)
+ - Strings longer than about 7000 bytes smashed their chunk header
+and confused the garbage collector. (ialloc.c)
+ - Some compilers needed iccfont.c to include strimpl.h.
+(iccfont.c)
+ - The obsolete file zcspace2.c was still included in the fileset.
+ - If the command line included any @-files that required searching
+the library path, a limitcheck would occur. (zfile.c)
+ - The insideness testing operators caused a memory access error,
+because the procedure vector hadn't been updated to provide a default
+get_alpha_bits procedure. (zupath.c)
+ - gcheck didn't check for stack underflow. (zvmem2.c)
+ - cleardictstack could fail to clear the dictionary stack if the
+stack had overflowed into additional blocks. (zdict.c)
+ - If the '-' switch was selected, resources weren't released
+properly on exit. (gs.c)
+ - Setting a Pattern color space based on a CIE space caused an
+invalid memory access. (zcsindex.c)
+ - The garbage collector didn't treat refs properly on machines with
+short ints. (igcref.c)
+ - Operators with more than 16 arguments could break the
+interpreter. (interp.h, iinit.c, interp.c)
+ - save/restore didn't restore the setting of the current allocator
+VM (local/global). (isstate.h, isave.c)
+ - stdpre.h declared exit as an extern, instead of letting gsmain.c
+declare it. (stdpre.h, gsmain.c)
+ - gs.c used fputs to print help messages rather than fprintf.
+(gs.c)
+ - Interrupts failed to re-execute the operation that was
+interrupted. (interp.c)
+ - Low-resolution CMYK devices didn't use separate screens for each
+color plane as the default. (gs_init.ps)
+ - filterdict wasn't getting undef'ed at the end of initialization.
+(gs_init.ps)
+ - gstate operations were broken (bug introduced in 3.02).
+(zdevice2.c)
+ - resourceforall didn't remove the resource dictionary from the
+dictionary stack when calling the client-supplied procedure. (gs_res.ps)
+ - currentcolor with an Indexed color space returned a real rather
+than an integer. (zcolor2.c)
+ - setshared / setglobal left the stack in an unobvious state if
+they were given a non-Boolean argument. (gs_dps1.ps)
+ - sethalftone followed by currenthalftone returned an invalid value.
+(zht2.c)
+ - Empty strings produced spurious garbage collector error messages.
+(gsstruct.h, scommon.h, igc.c, igcstr.c, iname.c)
+ - The garbage collector didn't trace Separation color spaces properly.
+(gscsepr.c)
+
+Changes defineresource so that it does not, by default, make instances
+read-only. (gs_res.ps)
+
+Adds .{local,global}{array,dict,packedarray,string} operators for creating
+objects in a specific VM space. (zsysvm.c, gs_dps1.ps)
+
+Adds definitions of setpage and setpageparams to statusdict. (gs_setpd.ps,
+gs_statd.ps)
+
+Alleviates some performance problems in the garbage collector. (igc.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - PDF files that used filters with parameters caused a typecheck
+error because the arguments to 'filter' were reversed. (pdf_base.ps)
+ - The (undocumented) PDF 1.1 ability to specify link and annotation
+destinations indirectly was not supported. (pdf_main.ps)
+ - The (undocumented) PDF ability to specify a null page in a link
+destination was not supported. (pdf_main.ps)
+ - The PDF encodings weren't loaded properly in a system with both
+PS Level 2 and PDF features. (gs_res.ps, gs_init.ps)
+ - If the next line after a stream keyword was blank, the line
+wasn't skipped, which matters for binary data. (pdf_base.ps)
+ - A Q operator with no matching q operator caused an error.
+(pdf_draw.ps)
+ - The text position wasn't preserved across a fill or stroke
+operator. (gs_pdf.ps, pdf_draw.ps)
+ - Embedded Type 3 fonts didn't work. (pdf_base.ps, pdf_draw.ps,
+pdf_main.ps)
+ - Masked images with no Decode value had their polarity inverted.
+(pdf_draw.ps)
+ - Embedded Type 1 fonts referenced from within a stream didn't
+work. (pdf_font.ps)
+
+Changes the PDF code so that it automatically recognizes PDF files as such.
+(pdf_main.ps)
+
+Splits out the PixelDifference filters as a separate "feature". (gs.mak)
+
+Streams
+-------
+
+Fixes bugs:
+ - Closing the primary input stream caused an invalid memory access.
+(stream.c)
+ - Increasing the size of a buffer within a save resulted in a
+dangling reference after the restore. (files.h, sfilter.h, zfile.c,
+zfilter.c)
+ - The garbage collector didn't properly trace streams that referenced
+strings directly. (stream.h, stream.c, ziodev.c)
+
+Library
+-------
+
+Fixes bugs:
+ - An extraneous \ upset some compilers. (gdevabuf.c)
+ - Uncolored Patterns that completely filled their bounding box
+caused an invalid memory access. (gspcolor.c)
+ - If a color image required clipping, black or white pixels might
+be rendered with incorrect (random) colors. (gxcpath.c)
+ - Reference counts for color spaces were sometimes set too high, so
+they would only be freed by restore or garbage collection. (gscolor.c)
+ - The character cache could get confused if the Encoding for the
+character wasn't a name. (gschar.c)
+ - Character outlines were always rendered with flatness = 0,
+causing very bad performance for large characters. (gzstate.h, gschar.c,
+gsimage.c, gxfill.c, gxstroke.c)
+ - If a device (presumably uninitialized) had a
+color_info.num_components of zero, an invalid memory access could occur.
+(gsdparam.c)
+ - Intersecting clipping paths that are not both rectangular didn't
+properly set the outer box of new clipping path, leading to unnecessary
+computation. (gxcpath.h, gxacpath.c, gxcpath.c)
+ - A call passed false instead of NULL. (gschar.c)
+ - On machines where sizeof returns a long, genarch.c failed.
+(genarch.c)
+ - xfonts were consulted, incorrectly, even for stroked characters.
+(gxccman.c)
+ - gstate/currentgstate/setgstate didn't work properly. (gsline.c,
+gsstate.c)
+ - On CMYK devices needing halftoning, colors with C = M = Y were
+always converted to gray shades. (gxcmap.c)
+ - Isolated horizontal lines, or the horizontal edges of rectangles,
+could get drawn with one or both end pixels missing. (gxfill.c)
+
+Changes the character cache back so it oversamples characters at small
+sizes. (gschar.c)
+
+Changes all occurrences of (void)x to discard(x), and defines discard in
+stdpre.h as a cast to void, to make it possible to pacify compilers that
+don't accept this construct for some kinds of x. (gpcheck.h, stdpre.h,
+store.h, gdevmswn.c, gp_mswin.c, gscoord.c, gxclread.c, igc.c, sfile.c,
+sfileno.c, zcie.c, zht2.c, ziodev.c, zmisc1.c)
+
+Increases the size of the halftone cache on large-memory machines from 35K
+to 100K. This substantially improves halftoning performance at higher
+resolutions. (gxht.c)
+
+Version 3.22(beta) (11/30/94)
+==================
+
+This is primarily a bug fix release. It also includes limited anti-aliased
+graphics capability. This release was not distributed to the public.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The definition of ghost_h was misplaced, so changes in it or its
+antecedents didn't force recompilation of its dependents. (gs.mak)
+
+Actually implements the -Z+ switch, for forcing small stack blocks.
+(interp.c)
+
+Makes the -dSAFER switch disable the %pipe syntax for file names, even for
+reading. (gs_init.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The dfax drivers incorrectly set EncodedByteAlign to false.
+(gdevdfax.c)
+ - softwareValue and dateTimeValue were declared as byte rather than
+char. (gdevtfax.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS DEC C compilers declare delete in unixio.h, and doesn't
+declare unlink anywhere. (stdio_.h)
+ - The VMS compilers declare malloc and free in stdlib.h, which
+wasn't being included in malloc_.h. (malloc_.h)
+ - The SCO Unix C compiler needs both <sys/time.h> and <time.h>.
+(time_.h)
+ - The VMS compilers declare abs in stdlib.h, which wasn't being
+included anywhere. (gshtscr.c)
+ - The definition for A4 paper in VMS-AXP.MAK was incorrect.
+(vms-axp.mak)
+
+Renames VMS-AXP.MAK as VMS-DECC.MAK, with some changes that make it
+appropriate for DEC C on both VAX and AXP platforms. (vms-axp.mak =>
+vms.decc.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - gs_kanji.ps got an invalidaccess error. (gs_kanji.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - An off-by-1 test in the roll operator caused it to smash the
+stack if the operand stack had overflowed into additional blocks.
+(zstack.c)
+ - The default CIE color rendering dictionary didn't assume a
+reasonable intermediate (XYZ) space. (gs_lev2.ps)
+ - CIE color mapping tables weren't traced properly by the garbage
+collector. (gscie.h, gscie.c, zcie.c)
+ - If the very last character of a file was a ^M, the scanner
+(incorrectly) signaled a syntaxerror. (iscan.c)
+ - If an operator could return both a typecheck and a
+stackunderflow, it always returned a stackunderflow, which doesn't match
+the behavior of Adobe interpreters. (opcheck.h, idparam.c, interp.c,
+iutil.c, z*.c)
+ - astore, dictstack, and execstack could return a spurious
+invalidaccess error (or fail to detect an invalid access) if the operand
+stack had overflowed into additional blocks. (istack.c)
+ - The garbage collector didn't relocate pointers to names! (Bug
+introduced in 3.20.) (iname.h)
+ - If the dictionary stack overflowed into additional blocks, the
+cached value pointer for a name could get set incorrectly, and also not get
+relocated by the garbage collector. (idict.c)
+ - If the dictionary stack overflowed into additional blocks, the
+post-GC fixup of cached value pointers in names could cause an addressing
+error. (igc.c)
+ - With the -Z? switch set, the garbage collector could incorrectly
+report that objects or strings weren't in any chunk. (igc.c)
+ - << /a 1 /a 2 >> /a get gave the value 2 rather than 1.
+(gs_init.ps)
+ - Numbers in binary object sequences and encoded number arrays
+didn't work properly on machines where sizeof(short) != 2 or sizeof(long)
+!= 4. (ibnum.c)
+ - The put operator for dictionaries allowed null as a key.
+(idict.h, idict.c)
+ - >> didn't give an error if there were an odd number of values on
+the stack above the next mark. (gs_init.ps)
+ - Operations that explicitly freed ref objects (setting a CIE
+colorspace, resizing a dictionary, popping a block off a stack) could
+corrupt storage. (ialloc.c)
+ - The -Z@ switch, which fills freed blocks with a recognizable bit
+pattern, could incorrectly overwrite freed blocks in previous save levels,
+causing invalid memory accesses. (ialloc.c)
+ - Since streams freed by a restore weren't marked as free, they
+could confuse the garbage collector and lead to invalid memory accesses.
+(zfile.c)
+ - If one of the built-in dictionaries overflowed during
+initialization, no error was reported -- entries were simply discarded.
+(iinit.c)
+ - If the level2.dev feature was combined with certain other
+features, the current languagelevel was 2 when some gs_*.ps files were
+loaded, causing them to load incorrectly. (gs_btokn.ps, gs_setpd.ps)
+ - If readline read a line that ended with only a CR (no LF)
+followed by an end-of-file, it incorrectly closed the stream. (zfileio.c)
+
+Adds a .cond operator, similar to the Lisp multi-arm conditional.
+(zcontrol.c)
+
+Adds a .makeglobaloperator operator, allowing the definition of operator
+procedures in local VM that turn into global operators, provided the save
+level is zero. (iref.h, opdef.h, iinit.c, interp.c, zmisc.c)
+
+Note: the fix for returning typecheck vs. stackunderflow requires that all
+operators (or other code) that uses return_error(e_typecheck) to indicate
+an incorrect object type on the operand stack must change this to
+return_op_typecheck(op), where op points to the operand. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE.
+
+Implements string array and name array parameters for parameter lists.
+(gsparam.h, iparam.c)
+
+Brings filterdict inside the INITIAL_DICTIONARIES conditional. (iinit.c)
+
+Adds a .currentscreenlevels operator that returns the number of
+distinguishable halftone levels. (zht.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The 2-D case of CCITTFaxDecode could get confused by an input
+data buffer boundary that fell immediately after a horizontal code.
+(scfd.c)
+ - The LZW decoder didn't detect invalid data unless DEBUG was
+selected at build time. (slzwd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The clipping region accumulator could refer to a clipping
+rectangle even after it had been freed. (No effect on execution unless the
+-Z@ switch was selected.) (gxacpath.c)
+ - setbbox expanded the bounding box, but didn't place a limit on
+further path elements, if the current path wasn't empty. (gsdps1.c)
+ - setbbox didn't make sufficient allowance for rounding.
+(gsdps1.c)
+
+Implements the ProcessColorModel parameter (read-only) for all devices.
+(gsdparam.c)
+
+Adds a gs_currentscreenlevels procedure that returns the number of
+distinguishable halftone levels. (gsht.c)
+
+Version 3.21(beta) (11/17/94)
+==================
+
+This is primarily a bug fix release. It also includes a substantial
+improvement in the Type 1 font hinting algorithms. This release was not
+distributed to the public.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The `man' page referred to gnu.ghostscript.bug rather than
+comp.lang.postscript. (gs.1)
+
+Documents the special entries in operator definition tables that allow
+switching dictionaries. (opdef.h)
+
+Procedures
+----------
+
+Moves the definition of JSRCDIR to the individual platform makefiles, to
+make it easier to change on platforms that don't have file links. (*.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ansi2knr didn't recognize that a line ending with } couldn't be a
+function definition. (ansi2knr.c)
+ - ps2epsi always returned an empty bounding box. (ps2epsi,
+ps2epsi.bat)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The bitrgb device had an invalid depth of 3. (gdevbit.c)
+
+Replaces the color mapping code in the X driver with a much faster
+algorithm, courtesy of Tim Theisen. (gdevx.h, gdevx.c, gdevxini.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Two variable names were misspelled. (gdevpm.c, gp_mswin.c)
+ - It wasn't possible to compile a non-DLL configuration under OS/2.
+(os2.mak)
+ - Compilation under Microsoft C/C++ 8.0 gave errors. (gp_mswin.h,
+gp_mswin.c, gshtscr.c)
+
+Adds some more devices to the OS/2 makefile. (os2.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - wrfont.ps, and hence bdftops, didn't write out the FontType or
+PaintType. (Bug introduced since 2.6.1) (wrfont.ps)
+ - wrfont.ps omitted a 'begin' and 'end', causing -! or -| to be
+undefined when the font was loaded. (Bug introduced since 2.6.1)
+(wrfont.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - make_tasv_old called make_tasv_new with extra arguments.
+(store.h)
+ - currentcacheparams only returned 2 values instead of 3.
+(zfont.c)
+ - ustroke popped one element too many off the stack if a matrix was
+supplied. (zupath.c)
+ - inu[eo]fill popped one element too many off the stack.
+(zupath.c)
+ - The color rendering dictionary was initialized to null rather
+than a valid dictionary. (gs_lev2.ps)
+ - An invalid IODevice resource named "9" got created. (gs_res.ps)
+ - bytesavailable often caused an error rather than returning -1.
+(zfileio.c, stream.c)
+ - The insideness testing operators always returned true if the
+aperture was defined by a user path rather than a point. (zupath.c)
+ - If INITIAL_DICTIONARIES was defined in the makefile, the
+definition of the initial_dictionaries array was missing a comma.
+(iinit.c)
+ - Even if userdict appeared in INITIAL_DICTIONARIES, gs_init.ps set
+its maxlength to 200. (gs_init.ps)
+ - Setting a CIE color space left a garbage value on the stack.
+(zcie.c)
+ - If a file or filter was opened and then closed, opening a file
+subsequently within a 'save' could lead to a memory access error in the
+garbage collector. (zfile.c)
+ - Setting an Indexed or Separation color space could cause a crash
+either in the garbage collector or when printing out the e-stack.
+(icsmap.h, zcsindex.c, zcssepr.c)
+ - Invoking a filter with an invalid data source or sink could cause
+a memory access error (bug introduced in 3.20). (zfilter.c)
+ - Invoking stringwidth on a font whose BuildChar procedure did a
+save could cause a memory manager error or infinite loop, because
+stringwidth attempted to use an inapplicable shortcut. (gschar.c)
+ - The bounding box for rendering stroked Type 1 characters didn't
+take square caps and miter joins into account. (gs_type1.ps)
+ - Invoking filter with DCTDecode or DCTEncode could cause an
+addressing error if no dictionary argument was supplied. (zfdctd.c,
+zfdcte.c)
+ - The Generic resource, the Font resource, and half a dozen
+resources with no predefined instances all shared the same Instances
+dictionary. (gs_res.ps)
+ - The temporary null device allocated for stringwidth was never
+freed. (gschar.h, gschar.c, zchar.c)
+ - Internal operators, and structures that might be freed on stack
+unwinding, could "escape" from the e-stack. (zcontrol.c, ztype.c)
+ - makefont and scalefont didn't properly handle a font whose
+Encoding had been changed. (bfont.h, zfont.c, zfont2.c)
+ - Type 1 fonts with PaintType = 2 incorrectly checked for an xfont.
+(gxfont.h, gschar.c, gsfont.c, zchar1.c, zfont1.c, zfont2.c)
+ - Specifying a string argument with -d...=(...) or -d...=<...>
+would cause an invalidaccess error. (gs.c)
+ - The environment for encapsulated jobs didn't rebind quit to stop
+in userdict. (gs_lev2.ps)
+ - restore didn't deal properly with open files on the e-stack.
+(zvmem.c)
+ - Even with the '-' switch, Ghostscript would try to read ahead in
+the input stream rather than processing input character-by-character.
+(ziodev.c)
+ - If an error occurred with a unreadable dictionary on any stack,
+the standard error printer would get into an error loop and exit the
+interpreter. (gs_init.ps)
+ - The for_roots macro in igc.c used ap rather than mem as its
+second formal parameter. (This typo had no effect on the executable
+program.) (igc.c)
+ - If saving the stacks for an error caused a GC request, a value
+could get stored into an improper variable on the C stack, causing havoc.
+(interp.c)
+ - setdash checked to make sure that the distance array had read
+access; Adobe interpreters don't check this. (zgstate.c)
+ - The roots for gs_run_string and gs_interpret weren't registered
+properly, which could cause a dangling reference in the case of a restore
+whose save had been done earlier. (gsmain.c, interp.c)
+
+Adds an OpenOutputFile Boolean device parameter for printer devices; if
+true, the device opens the OutputFile at the time the device is opened,
+instead of waiting for the first showpage. This helps with synchronization
+when the OutputFile is a pipe. (gdevprn.h, gdevprn.c)
+
+Changes the BEGIN/END_OP_DEFS macros to require an explicit { and } at each
+use. (gsmain.c, interp.c, z*.c)
+
+Arranges things so that the operators that the interpreter handles
+specially are assigned the first N operator indices [internal change only].
+(interp.h, iinit.c, interp.c)
+
+Changes the operators max and min to .max and .min, to avoid conflicts with
+PostScript programs that use these names for variables and also use 'bind'.
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE from programs that depend on
+'bind' binding in these operators; however, we have also defined procedures
+max and min that just call the operators, which should take care of any
+ordinary code. (*.ps, zrelbit.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The pfb_state pointer in the eexecDecode filter state wasn't
+marked as traceable for the garbage collector. (sfilter.h)
+ - The eexec decoding filter could access invalid memory or return
+garbage under some conditions. (Bug introduced in 3.12.) (zmisc1.c)
+ - The eexec decoding filter would incorrectly ask for more input if
+the output buffer was full. (seexec.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Some compilers reserve the word 'try'. (gshtscr.c)
+ - Some compilers don't like line continuations (\) within a
+preprocessor macro formal parameter list. (gdevprn.h, gxdevice.h)
+ - Memory devices created with an inverted palette (0=white,
+1=black) interchanged white and black in fill operations. (gdevmem1.c)
+ - The 'bits' variable in mem_mono_copy_mono was unused on
+little-endian machines. (gdevmem1.c)
+ - Some garbage collector procedures were declared 'private'
+inconsistently. (gscie.c)
+ - The new anti-aliased text capability accidentally caused all
+characters to be oversampled. (gschar.c)
+ - Type 1 fonts with PaintType = 2 and StrokeWidth = 0 came out with
+many pixels missing because of oversampling. (gschar.c)
+ - Type 1 font stem hints were not being processed correctly.
+(gstype1.h, gxtype1.h, gstype1.c, gxhint2.c, gxhint3.c, gxpath.c)
+ - The tracing message for 9/7 composite fonts incorrectly
+identified them as 1/7 fonts. (gschar0.c)
+ - If a 1/7 or 9/7 composite font was a child of a non-modal font,
+the font number of the child font was computed incorrectly. (gschar0.c)
+
+Splits up the various memory devices into one file per depth [internal
+change only]. (gdevm*.c)
+
+Version 3.20(beta) (10/31/94)
+==================
+
+This version contains some support for a PDF interpreter; however, the PDF
+code itself is not ready for release yet. It also includes anti-aliased text
+capability. This release was not distributed to the public.
+
+Documentation
+-------------
+
+Notes that the FAQ has moved to smallo.ruhr.de:pub/ghost/gs.faq. (readme)
+
+Documents various implementation limits. (language.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - bcp.dev wasn't included in the list of dependencies for
+level1.dev. (gs.mak)
+
+Changes the printout of version numbers so that it is always A.BC,
+rather than A.B if C is zero. (gs.c, gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - font2c didn't correctly handle Metrics or Metrics2 dictionaries
+whose entries were arrays rather than scalars. (font2c.ps, ccfont.h,
+iccfont.c)
+ - font2c didn't handle CDevProc. (font2c.ps, ccfont.h, iccfont.c)
+ - genconf could get a stack overflow on small machines.
+(genconf.c)
+
+Changes mergeini.ps so it can take arguments on the command line specifying
+the input and output files. (mergeini.ps)
+
+Adds a gsdj500 shell script to parallel gsdj500.bat. (gsdj500)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The X driver didn't mask dynamically assigned colors properly, so
+it could request the same color over and over again. (gdevx.c)
+
+Adds two alternate X Windows drivers, for helping debug drivers with other
+color models:
+ - x11alpha, an RGB device with 4-bit alpha capability (for
+ copy_alpha only);
+ - x11cmyk, a 1-bit-per-component CMYK device.
+(devs.mak, gdevxalt.c)
+
+Changes the left margin of the lj4dith driver to 0.26". (gdevcdj.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - If <sys/time.h> didn't exist, time_.h didn't always include
+<time.h>. (time_.h)
+ - The OS/2 platform wouldn't compile. (gdevpm.c)
+ - The auxiliary VMS command files sometimes got blank lines
+inserted when going through EOL conversion. (vms.mak; delete gs_.com)
+ - The VMS makefiles didn't include the Level 1 operators in
+level1.dev. (vms.mak)
+ - The VMS gcc makefile didn't handle undefined DEVICE_DEVSn
+variables properly. (vms*.mak)
+ - The VMS makefiles didn't recognize DEVICE_DEVS{1,2,5,7}.
+(vms.mak)
+
+At the request of a Unix expert, changes all the Unix shell scripts to use
+exec gs ... "$@" rather than gs ... $*. (gsnd, gsbj, gsdj, gslj, gslp)
+
+Modifies the JPEG library so that it uses 4K less of the automatic data
+segment in 16-bit environments. (bcwin.mak, jpeg.mak, sjpeg.c, sjpegerr.c)
+
+Adds the bmp drivers back into the 16-bit MS Windows executable, since they
+will fit now. (bcwin.mak)
+
+Fonts
+-----
+
+Makes the font substitution algorithm recognize the word Roman as calling
+for a serif font. (gs_fonts.ps)
+
+Interpreters
+------------
+
+Fixes bugs:
+ - The fix in 3.13 for the inexact function values at 0 didn't work.
+(zcontrol.c)
+ - Level 1 configurations referenced an undefined procedure
+gs_currenthalftone. (gsht.c, gsht1.c)
+ - Specifying any device properties (including -r and -g) on the
+command line caused an error. (gs_init.ps)
+ - The forward declaration of cfont_name_array_create was
+incorrect. (iccfont.c)
+ - save and restore could get called before the graphics state stack
+had been initialized properly. (gs_mex_e.ps)
+ - Some encodings weren't loaded properly. (gs.mak, gs_mex_e.ps,
+gs_mro_e.ps, gs_pdf_e.ps, gs_wan_e.ps)
+ - Zero-height images were allowed, but zero-width images
+weren't. (zpaint.c)
+ - Neither zero-width nor zero-height images popped their
+arguments from the operand stack. (zpaint.c)
+ - lib_file_fopen overwrote its file name argument, causing havoc
+with @-files. (gxiodev.h, gdevpipe.c, gsiodev.c, zfile.c)
+ - The garbage collector got confused if there were any arrays or
+dictionaries with 8K or more elements. (igcref.c)
+ - >> could leave the stacks in a questionable state if it failed.
+(gs_init.ps)
+ - The Category resource category didn't implement undefineresource.
+(gs_res.ps)
+ - When the token operator read the last token from a string, it
+left an unchanged string on the stack instead of an empty string.
+(stream.c)
+ - noaccess didn't give an invalidaccess error when applied to the
+permanent dictionaries. (dstack.h, idict.c, ztype.c)
+ - Overflowing the exec stack wasn't handled properly. (istack.h,
+istack.c)
+ - The garbage collector cleared the cached value pointers in names,
+causing interpretation to slow down substantially. (idict.c, igc.c,
+iname.c)
+ - 0 dict created a dictionary with a maxlength of 1. (idict.c)
+
+Changes the default size of the execution stack from 150 to 250, to match
+the Adobe "typical" value. (interp.c)
+
+Moves the operator definitions out of the automatic data segment.
+(opdef.h, iinit.c, z*.c)
+
+Adds operators that allow creation of objects in system space:
+.systemvmstring, .systemvmarray, .systemvmpackedarray, .systemvmdict,
+.systemvmcheck. (zsysvm.c)
+
+Renames gcdefs.h as gscdefs.h.
+
+Allocates names in system space rather than global space. (gsmain.c)
+
+Changes the memory manager so that it allows programs to create objects in
+system space. (iref.h, iutil.h, ivmspace.h, ...)
+
+Changes the implementation of filters so they appear in their own
+dictionary named filterdict. (gs_init.ps, z*.c)
+
+Changes the implementation of color spaces so each one has its own
+setcolorspace procedure, defined in a new dictionary named
+colorspacedict. (gs_lev2.ps, z*.c)
+
+Adds a new debugging switch, $, that always initializes all fields in a
+ref, in order to keep Purify happy. (store.h)
+
+Library
+-------
+
+Fixes bugs:
+ - The page size for image devices was always set to (0, 0).
+(gsdevice.c)
+ - The PageSize computation in gx_default_put_params could overflow
+on 16-bit machines. (gsdparam.c)
+ - An omitted 'static' on an initialized array caused a compiler
+error. (gxccman.c)
+ - If interpolated image rendering was requested but not
+actually carried out, gs_image_cleanup could attempt to free a random
+pointer. (gsimage.c)
+ - Some compilers only retain 23 characters of procedure names, but
+some procedure names weren't unique in the first 23 characters. (gscie.c,
+gscolor.c, gscolor1.c, gxcmap.c)
+ - The garbage collector didn't trace device colors properly.
+(gxdcolor.h, gzht.h, gsimage1.c, gspcolor.c, gxcht.c, gxcmap.c, gxdraw.c,
+gxht.c)
+ - For CMYK devices, the transfer functions were being applied to
+the CMYK values rather than the complemented RGBW values. (gxcmap.c)
+ - Memory devices used their own color mapping procedures rather
+than those of the target; this could cause incorrect colors for patterns on
+devices with more than 1 bit per pixel. (gxdevmem.h, gdevmem1.c, gdevpm.c,
+gdevprn.c, gdevwdib.c, gschar.c, gsdevice.c, gxccache.c, gxccman.c,
+gxclip2.c, gxclread.c, gxpcmap.c)
+ - The garbage collector didn't trace image enumerators properly in
+the image_render_simple case. (gsimage.c)
+ - stroke produced different-looking output for thin (zero-width)
+lines depending on whether or not clipping was invoked. (gxstroke.c)
+ - If a clipping list changed from multiple rectangles to a single
+rectangle, it could fail to clip properly thereafter. (gxacpath.c)
+
+Adds two new device procedures: alpha_bits and copy_alpha. This change is
+backward-compatible for all existing devices. (gdevmem.h, gxdevice.h,
+gsdevice.c, gxclip2.c, gxclist.c, gxcpath.c)
+
+Changes the implementation of color halftones so that, when appropriate, it
+generates a single cell and uses the device tile_rectangle procedure.
+(gzht.h, gsht.c, gxcht.c, gxclist.c, gxclread.c)
+
+Adds partial support for the Orientation page device parameter.
+(gsdevice.c)
+
+Adds support for anti-aliased characters using 2 or 4 bits of alpha.
+(gxfcache.h, gschar.c, gxccache.c)
+
+Version 3.13(private) (10/3/94)
+=====================
+
+This release was created for a customer; it was not distributed to the
+public.
+
+Documentation
+-------------
+
+Notes in make.doc that the file names in the IJG archive distributed with
+Ghostscript do not include the gsA.BC/ prefix. (make.doc)
+
+Adds a cross-reference to make.doc to the Watcom makefiles. (watc.mak,
+watcwin.mak, wccommon.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The makefile rule for gconfig.h et al had a couple of blank lines
+in the middle of it. (gs.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - wrfont.ps didn't add a lenIV entry to the Private dictionary if
+it was needed. (wrfont.ps)
+
+Adds a packfile.ps utility that allows compressing multiple files into a
+single file for environments with very little permanent storage.
+(gs_pfile.ps, packfile.ps, wrfont.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The {tiff,fax}{g32d,g4} devices could produce incorrect output.
+See under Streams below.
+ - The dfax drivers referred to the obsolete structure member
+EncodedEOLAlign. (gdevdfax.c)
+
+Changes the default bit order for TIFF/F output to little-endian, which is
+apparently what the majority of TIFF decoders like best. The bit order for
+the fax drivers is still big-endian. (gdevdfax.c, gdevtfax.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS build script used -a rather than -w for creating
+gconfig_.h. (vms.mak)
+ - The VMS build script didn't create gconfigv.h. (vms.mak)
+ - The VMS Fontmap had incorrect entries for the Bitstream Charter
+fonts. (fontmap.vms)
+ - The VMS MODULES.LIS file assumed the JPEG library files were in
+directory JPEG rather than JPEG-5. (modules.lis)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Using DISKFONTS resulted in an invalidaccess error.
+(gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The standard transfer function considered gray values above
+roughly 0.994 equivalent to white; 0.999 is a better value. (gs_init.ps)
+ - The transfer, black generation, and undercolor removal functions
+gave slightly inexact results for an input value of 0. (zcolor.c,
+zcontrol.c)
+ - setpagedevice gave an /undefined error if it did not recognize a
+key, rather than ignoring the key. (zdevice.c, gs_init.ps, gs_lev2.ps,
+gs_setpd.ps)
+
+Changes .putdeviceparams to take an additional argument, a Boolean that
+says whether or not unrecognized keys should be reported as /undefined
+errors. THIS IS A NON-BACKWARD-COMPATIBLE CHANGE; however, no user-written
+code should be calling .putdeviceparams. (zdevice.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The Group 3 2-D and Group 4 fax encoders could emit incorrect
+output. (scfe.c)
+ - The algorithm for constructing optimal Huffman codes could
+produce invalid codes in some rare cases. (shcgen.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Rectangles closed with lineto rather than closepath weren't
+recognized as rectangles. (This only affected performance, not
+functionality.) (gxpath2.c)
+ - The xfont lookup_font procedure could get called with a matrix
+whose translation components had never been initialized. (gxccman.c)
+ - Some compilers don't allow \ in the formal argument list of a
+preprocessor macro. (gdevprn.h, gxdevice.h)
+
+Version 3.12 (9/29/94)
+============
+
+This is another bug fix release, the first Level 2 release that we believe
+is reasonably reliable.
+
+Documentation
+-------------
+
+Adds some text warning about making copies of the makefile. (make.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - There were a number of unnecessary dependencies on $(MAKEFILE) in
+gs.mak, left over from before the existence of gconfigv.h. (gs.mak)
+ - JPEGSRC was defined in gs.mak rather than in jpeg.mak. (gs.mak,
+jpeg.mak)
+
+Changes the version numbering scheme back to A.BC, since people seem to be
+adapting to the change, and this allows using the version number directly
+as a MS-DOS directory name. (gconfig.c, gdevtfax.c, gs.c, gs_init.ps)
+
+Updates the JPEG library to version 5 (official release) of the IJG code.
+(jpeg/*, jpeg.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF/F driver put out invalid PageNumber and Software
+entries. (gdevtifs.h, gdevtfax.c)
+ - The TIFF/F and fax Group 3 2-D drivers used K=3 and K=5 instead
+of K=2 and K=4. (gdevtfax.c)
+ - The TIFF/F and fax Group 3 2-D drivers emitted improperly aligned
+output. (See under Streams below.)
+ - The MS Windows driver didn't resize the window properly in
+response to changing the device parameters. (gdevmswn.c)
+
+Because of complementary bugs in various C compilers, changes all the
+non-printer devices to use a different set of macros. (gdevmem.h,
+gdevpcfb.h, gdevprn.h, gdevsvga.h, gxdevice.h, gdev{3b1, bgi, herc, l256,
+pe, pm, sun, vglb, wddb, wdib, wprn, x}.c, gsdevice.c, gxacpath.c,
+gxclip2.c, gxcpath.c, gxpcmap.c, zupath.c)
+
+Changes the X11 driver to ignore the "margins" specified by Ghostview.
+This is apparently necessary for Ghostview to handle landscape display
+properly. (gdevxini.c)
+
+Adds a WindowID parameter to the X11 device, to allow setting the window
+for the output. (gdevx.h, gdevx.c, gdevxini.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The definition of BEGINFILES in os2.mak occurred too late in the
+file to have the desired effect. (os2.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Updating the list of allocated file objects at a restore didn't
+clear the prev pointer of the new head, which could cause the garbage
+collector to encounter an invalid pointer. (Bug introduced by .forgetsave
+in 3.0.3.) (zfile.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxEncode filter with K > 0 and EncodedByteAlign = true
+incorrectly aligned the 1-D/2-D bit as the last bit of a byte, rather than
+the first bit. (scfx.h, scfe.c)
+ - eexec could loop indefinitely under certain conditions.
+(seexec.c)
+ - eexec's algorithm for recognizing text vs. binary encoding didn't
+work properly in some cases that don't conform to the Adobe Type 1 Font
+Format documentation. (seexec.c)
+ - Closing a stream didn't clear out the strm and state pointers,
+which could cause invalid accesses by the garbage collector. (stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - fill_loop could loop indefinitely under certain conditions.
+(Introduced by a bug fix in 3.1.) (gxfill.c)
+ - fill/eofill sometimes failed to paint parts of a region.
+(Introduced by a bug fix in 3.1.1.) (gxfill.c)
+ - Non-convex clipping paths sometimes omitted thin horizontal
+slivers of the region. (Probably introduced by the "thin graphics" fix in
+3.1.) (gxacpath.c)
+
+Version 3.1.1 (9/25/94)
+=============
+
+This is primarily a bug fix release. It was originally intended for some
+commercial licensees, but beta testers found too many problems with it.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - NEWS didn't indicate that there was a non-backward-compatible
+change in the gx_device structure -- specifically, that l_margin,
+b_margin, r_margin, and t_margin were replaced by macros named
+dev_l_margin(dev), etc. (news)
+
+Describes the two-phase commit requirement for device put_params
+procedures. (drivers.doc, gsparam.h)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The new S macro in genarch.c didn't work on compilers that do
+macro substitution within string constants (which is forbidden by the ANSI
+standard). (genarch.c)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Driver put_params implementations didn't observe a "two-phase
+commit" discipline; this could lead to the current device in the graphics
+state being closed, and other inconsistencies. (gsparam.h, gxdevice.h,
+iparam.h, gdevbit.c, gdevcdj.c, gdevmswn.c, gdevpcfb.c, gdevpm.c,
+gdevprn.c, gdevx.c, gsdevice.c, gsdparam.c, zdevice.c, ziodev2.c, zmisc2.c)
+THIS IS A NON-BACKWARD-COMPATIBLE CHANGE; however, it only affects
+put_params implementations, of which there are few.
+
+NOTE THE NON-BACKWARD-COMPATIBLE CHANGE IN THE gx_device STRUCTURE UNDER
+'Documentation' ABOVE. (gdevescp.c, gdevsj48.c, gdevsppr.c, gdevxini.c)
+
+Platforms
+---------
+
+Ensures that the Unix makefiles all include all the variants of TIFF/F and
+fax drivers. (ansihead.mak, cc-head.mak, gcc-head.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Most of the contents of statusdict were missing when
+running a Level 2 system in Level 1 mode. (zmisc2.c)
+
+Version 3.1 (9/20/94)
+===========
+
+This release finally includes a usable subset implementation of
+setpagedevice, including all the machinery needed to address the
+long-standing "margins" problems.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - t_oparray objects weren't identified as behaving differently
+depending on whether they were marked executable. (iref.h)
+ - drivers.doc had gx_color_value instead of gx_color_index in
+the description of color mapping. (drivers.doc)
+
+Updates drivers.doc to reflect the change from static_procs to
+std_procs in the gx_device structure. (drivers.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The commands for building the JPEG library used rm instead
+of rm -f. (jpeg.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The X Windows driver hadn't been updated to reflect some
+name changes in members of the gx_color_info structure. (gdevx.h,
+gdevx.c, gdevxini.c)
+
+Changes all non-printer drivers so that they use the new std_device_body
+macros. (gdev*.c)
+
+Adds a print_page_copies procedure for printer drivers, allowing the
+driver to receive num_copies. (gdevprn.h, gdevprn.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - ref_memory_enum/reloc_ptrs were declared inconsistently.
+(ialloc.c)
+ - If the operand of restore was invalid, the restore did
+nothing, instead of giving a typecheck. (zvmem.c)
+ - In Level 2, the margins and setmargins compatibility
+operators were defined incorrectly in terms of current/setpagedevice.
+(gs_lev2.ps)
+
+Enables .makeoperator to make local operators as well as global ones.
+(opdef.h, iinit.c, zmisc.c, zpacked.c)
+
+Finishes implementing the TransferFunction entry in halftone
+dictionaries. (zht1.c, zht2.c)
+
+Adds .set/currentfilladjust operators for access to the fill
+adjustment parameter in the graphics state. (zgstate.h)
+
+Removes the deviceinitialmatrix operator. (zdevice.c)
+
+Changes defaultmatrix from a procedure to an operator. (zmatrix.c)
+
+Sets the fill adjustment to 0.5 for high-resolution devices, effectively
+implementing Adobe's any-part-of-pixel filling rule. (gs_init.ps)
+
+Implements a small but useful subset of setpagedevice. (gs_lev2.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The eexec decoder incorrectly concluded that its data was
+in hex form if the first data character was whitespace. (seexec.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Thin graphics (e.g., lines or rectangles) with small angles
+relative to the X axis rendered with many points missing. (gxdraw.c,
+gxfill.c)
+ - The character cache rejected oversampled characters if the
+scaled-up size was too large, even if the scaled-down size wasn't.
+(gxchar.h, gschar.c, gxccache.c, gxccman.c)
+ - A call on sqrt with an integer argument didn't promote it
+explicitly to double, which is required for non-ANSI compilers.
+(gshtscr.c)
+
+Finishes implementing the TransferFunction entry in halftone
+dictionaries. (gsht1.c)
+
+Modifies the character oversampler so it can produce gray scale
+output instead of a 1-bit mask. We don't actually make use of this
+ability yet. (gxccman.c)
+
+Adds gs_set/currentfilladjust for access to the fill adjustment
+parameter in the graphics state. (gsstate.h, gsstate.c)
+
+Changes the names of the last few routines beginning with gz_ to
+begin with gx_ instead. (gzdraw.h => gxdraw.h, gsimage*.c, gxdraw.c,
+gxfill.c, gxstroke.c)
+
+Properly implements the PageSize, Margins, .HWMargins, and ImagingBBox
+device parameters for all devices. (gscoord.c, gsdparam.c, gspath2.c)
+Implements the NumCopies device parameter for printer devices.
+(gdevprn.c)
+
+Implements std_device_body macros to help insulate statically initialized
+non-printer devices from future changes in the gx_device structure.
+(gxdevice.h, ... many .c files ...)
+
+Version 3.0.3 (9/16/94)
+=============
+
+This is primarily a bug fix release; it also implements most of the
+remaining Level 2 loose ends (except for setpagedevice).
+
+Documentation
+-------------
+
+Changes code that refers to "Ghostscript" to use the correct product
+name from gs_product. (gs.mak, gdevpbm.c, gdevsun.c, gswppm.c)
+
+Documents the new .forgetsave operator. (language.doc)
+
+Clarifies the distinction between commercial licensing and single-copy
+end-user sales. (readme)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The compilation rule for gdevadmp.c was missing from the
+makefile. (devs.mak)
+
+Changes the version numbering scheme back to A.B.C, since too many
+people got confused by the change to A.BC. (gconfig.c, gs.c,
+gs_init.ps)
+
+Adds a -dNOGC switch to prevent the garbage collector from being
+enabled. (gs_init.ps)
+
+Utilities
+---------
+
+Removes the ps2image utility, since the new psmono driver replaces it.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The TIFF drivers incorrectly assumed that short and ulong
+were the same size as TIFF_short and TIFF_ulong, causing problems on
+64-bit systems. (gdevtfax.c)
+ - The EGA/VGA driver didn't do gray halftones properly if it
+was configured as a monochrome or 8-color device. (gdevpcfb.h)
+ - The comment in gdevevga.c incorrectly identified the file
+as gdevpcfb.c. (gdevevga.c)
+
+Changes the PC display drivers to save and restore more of the BIOS
+state. (gdevpcfb.h, gdevevga.c, gdevpcfb.c, gdevsco.c)
+
+Adds a new psmono driver that does the same thing as ps2image, faster
+and more conveniently. (gdevpsim.c)
+
+Replaces the X11 driver with the one from 3.01, since the color
+handling rewrite in 3.02 introduced serious bugs. (gdevx.h, gdevx.c,
+gdevxini.c)
+
+Platforms
+---------
+
+Changes the definition of gx_no_color_index to work around one of the
+bugs in the SGI Irix compiler. (gxdcolor.h)
+
+Rewrites the installation commands in unix-end.mak so they don't have
+very long lines. (unix-end.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Fonts that used 2- or 4-element arrays in the Metrics dictionary
+interpreted the width and side bearing interchanged with each other.
+(gs_type1.ps)
+ - Setting FONTPATH on the command line didn't work. (gs_fonts.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The stream position wasn't updated properly if sgets
+crossed a buffer boundary. (stream.c)
+
+Extends the BoundedHuffman filters so they can encode and decode runs of
+zeros specially, and so they mark and detect EOD. (sbhc.h, shc.h, sbhc.c,
+zfilter2.c)
+
+Provides an alternate implementation of file streams which doesn't use
+stdio buffering and which works around the System V "interrupted system
+call" problem. (stream.c, sfile.c, sfileno.c)
+
+Increases the maximum LZW output code from 3000 to 4095. (slzwe.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Opening a filter on a file of the wrong access type (read
+vs. write) didn't cause an error. (stream.h, sbasic.c, zfile.c, zfileio.c)
+ - save performed an extra, unnecessary gsave. (zvmem.c)
+ - sethalftone always gave a /undefined error. (zht2.c)
+ - eexec decryption read too much data from the input -- in
+Level 2, it isn't allowed to read 512 characters ahead. (sfilter.h,
+strimpl.h, seexec.c, sstring.c, zfileio.c, zmisc1.c)
+ - The scanner was too aggressive about allocating additional
+space for strings on small machines. (iscan.c)
+ - The AccurateScreens flag in Type 1 and Type 2 halftone
+dictionaries was being ignored. (zht2.c)
+ - The Level 2 definition of margins in statusdict didn't
+allow for Margins being undefined in the current page device.
+(gs_lev2.ps)
+ - The Interpolate flag was being ignored in image
+dictionaries. [implemented in library]
+ - The TransferFunction option was being ignored in halftone
+dictionaries. (zht2.c)
+ - Type 5 halftones usually didn't work, because they called
+the wrong (or an invalid) spot function. (zht2.c)
+
+Implements a .forgetsave operator that effectively causes a given save (and
+all more recent saves) to disappear. (isave.h, stream.h, isave.c, zfile.c,
+zvmem.c)
+
+Library
+-------
+
+Fixes bugs:
+ - In the 1-operand form of the image operator, a Decode value of [1
+0] with 8-bit sample values and a single data source was treated the same
+as [0 1]. (gsimage1.c)
+ - Some Monotype fonts put a callsubr between an OtherSubr call and
+the following 'pop' opcodes (which the Adobe documentation forbids); The
+Type 1 font interpreter gave an invalidfont error rather than allowing
+this. (gxtype1.h, gstype1.c)
+ - Patterns didn't implement XStep and YStep properly.
+(gxpcolor.h, gspcolor.c, gxclip2.c)
+ - Clipping regions were sometimes 1 pixel too small at the edges;
+this could cause vertical and horizontal lines produced by certain Windows
+drivers to disappear. (gzpath.h, gxacpath.c, gxcpath.c, gxfill.c)
+ - Oversampling cached rotated characters produced very bad
+results (many dropouts). (gschar.c)
+ - Rendering a DeviceGray color on a DeviceCMYK device applied
+the transfer function to all 4 components, not just to the K
+component. (gxcmap.c)
+ - A screen specified with setcolorscreen didn't take effect
+properly on CMYK devices. (gsht.c)
+
+Implements the Interpolate option for images. Currently this is only
+implemented for portrait-orientation images (no rotation, skewing, or
+X-reflection). (gscspace.h, gximage.h, gscie.c, gscolor.c, gscolor1.c,
+gscolor2.c, gspcolor.c, gxcmap.c, gsimage.c, gsimage2.c, gsimage3.c)
+
+Implements AccurateScreens, but only in the form of a larger limit on
+the size of a halftone super-cell. (gxht.h, gsht.c, gsht1.c)
+
+Starts to implement the TransferFunction option for halftones.
+(gzht.h, gzstate.h, gsht.c, ...too many others to list...)
+
+Version 3.02 (8/30/94)
+============
+
+This is another bug fix release. It was distributed only to a few people,
+since the new X Windows color mapping code is not reliable yet.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - make.doc, but not unixtail.mak, called for setting PLATFORM=unix_
+on SVR4 platforms. (unixtail.mak)
+ - drivers.doc contained some wording that suggested that
+Ghostscript always used RGB colors internally. (drivers.doc)
+ - The definition of gx_device in drivers.doc had gotten out of sync
+with gxdevice.h. (drivers.doc)
+ - README claimed that Ghostscript is not compatible with the
+VAX/VMS DEC C compiler, which is no longer true. (readme)
+
+Adds a new section on printer drivers to drivers.doc. (drivers.doc)
+
+Adds a large number of new display boards to the 800x600 SVGA section of
+use.doc. (use.doc)
+
+Adds a bug report form to the README file. (readme)
+
+Notes that OSF/1 AXP systems require changing the definition of INSTALL
+from install to installbsd. (make.doc)
+
+Procedures
+----------
+
+Removes -Wno-uninitialized from the gcc flags, and fixes all the places (in
+Aladdin's code only) that need to be fixed to pacify gcc after doing this.
+(gcc-head.mak, gdevgif.c, gdevmem2.c, gdevpcl.c, gs.c, gsht1.c, gsimpath.c,
+gsutil.c, gxclread.c, gxpcopy.c, gxstroke.c, idict.c, iscannum.c, stream.c,
+zdevice2.c) (NOT FINISHED YET)
+
+Adds a FAKEFONTS switch that makes fake entries in FontDirectory for
+unloaded fonts, for the benefit of programs that think they can find all
+the available fonts by scanning FontDirectory. (gs_fonts.ps, gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2epsi didn't work, because setdevice now erases the page.
+(ps2epsi.ps)
+ - ps2epsi didn't work, because -dNODISPLAY installs a null device
+with 0 width and height. The fix -- to remove the -dNODISPLAY -- is not
+satisfactory, because it opens an unnecessary window. (ps2epsi)
+
+Drivers
+-------
+
+Fixes bugs:
+ - gdev_fax_open was incorrectly declared static in gdevtfax.c,
+causing the extern reference in the dfax drivers not to be resolved.
+(gdevtfax.c)
+ - devs.mak included a duplicate definition of gdevmswn_h.
+(devs.mak)
+ - The fax drivers didn't link properly in Level 1 systems, because
+shc.c was omitted from their dependency list. (gs.mak, devs.mak)
+ - The TIFF/F drivers didn't set RowsPerStrip properly.
+(gdevtfax.c)
+ - The TIFF/F drivers didn't byte-align the EOL properly. (scfx.h,
+gdevdfax.c, gdevtfax.c, scfe.c, zfilter2.c)
+ - The rule for compiling gdevpccm.c incorrectly specified
+dependency on gs.h rather than gx.h. (devs.mak)
+ - The rule for compiling gdevtfax.c didn't include time_.h as a
+dependency. (devs.mak)
+ - The mode 2 compression routine for the DeskJet/LaserJet printers
+was broken. (gdevpcl.c)
+
+Removes the -O0 from the compilation rule for gdevsco.c, since it was
+misplaced to begin with. (devs.mak)
+
+Adds a maxDynamicColors X resource to control dynamic allocation in the
+color map. Replaces the X color lookup algorithms with completely new
+ones, for a substantial performance gain. (gdevx.h, gdevx.c, gdevxini.c)
+
+Adds PageNumber, Software, and DateTime entries to the TIFF/F drivers.
+(gdevtifs.h, gdevtfax.c)
+
+Changes the margins for the LaserJet 4 to 0. (gdevdjet.c)
+
+Adds a user-contributed LaserJet 4 driver that does Floyd-Steinberg
+dithering. (gdevcdj.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The exit codes for Ghostscript should be different on VMS.
+(iastate.h, gs.c, gsmain.c, igc.c, igcref.c)
+ - The VMS DEC C compiler declares malloc and free in stdlib.h, and
+delete and unlink in stdlib.h. (malloc_.h, stdio_.h)
+ - st_prn_device wasn't defined, which upset the VMS linker even
+though there were no references. (gdevprn.h)
+ - stdpre.h didn't bring in the right headers when running gcc on
+SCO Unix, causing compilation warnings/errors. (stdpre.h)
+ - The definition of rename in gp_sysv didn't include const for the
+arguments. (gp_sysv.c)
+ - The definition of gettimeofday in gp_sysv didn't return any
+value. (gp_sysv.c)
+ - time_.h didn't work on MS-DOS systems. (time_.h)
+ - math_.h didn't include <math.h> when compiling with gcc on VMS
+systems. (math_.h)
+ - DesqView/X doesn't have a 'cat' command, which caused problems in
+the linking step. (dvx-tail.mak)
+
+Changes the definitions of popen in gdevpipe.c and gp_unix.c so they don't
+specify the argument list. This is an attempt to get around the fact that
+there is no easy way to detect whether the available header files declare
+popen correctly (with const arguments), incorrectly (with non-const
+arguments), or not at all. (gdevpipe.c, gp_unix.c)
+
+Replaces VMS.MAK, VMS-CC.MAK, and VMS-AXP.MAK with new versions provided by
+a user. (vms.mak, vms-cc.mak, vms-axp.mak)
+
+Changes the 16-bit Borland makefiles so their standard configuration is
+Level 1 plus color.dev (CMYK color and colorimage). (bc.mak, bcwin.mak)
+
+Fonts
+-----
+
+Fixes bugs:
+ - cfonts.mak still referred to some .gsf files that have been
+replaced by .pfa files. (cfonts.mak)
+ - Compiled fonts got entered into FontDirectory, but didn't get
+registered as resources. (gs_ccfnt.ps)
+ - The Cyrillic, Kana, Hershey .gsf, and URW fonts didn't include a
+necessary systemdict begin/end, which caused them to fail in badly designed
+environments. (fonts/f*.gsf, fonts/h*.gsf, fonts/?0*.gsf)
+
+Changes the default target directory in cfonts.mak from fonts/c to .;
+changes the names of the Zapf Chancery compiled font procedures from c* to
+zc*. (cfonts.mak)
+
+Adds more fonts from the Adobe Type Manager package for MS Windows to
+Fontmap.ATM. (fontmap.atm)
+
+Adds the entire set of 35 standard fonts to the ccfonts feature in gs.mak;
+removes all the compilation rules for compiled fonts, since these rules are
+in cfonts.mak already. (gs.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - kshow executed a null, rather than the correct procedure, between
+the characters of the string, and got a typecheck error at the end.
+(zchar.c)
+ - MultiMaster fonts computed their side bearing and width
+incorrectly, producing incorrect output. (zchar1.c)
+ - There was no structure definition for gs_type1_state, so a GC
+during the execution of an OtherSubrs procedure could scramble pointers in
+the saved state. (zchar1.c, zfont1.c; also affects library, see below)
+ - kshow didn't work properly if the kerning procedure changed the
+depth of the operand or dictionary stack. (zchar.c)
+ - If the element count for roll was too large by only 1 or 2, the
+result was a crash rather than a rangecheck. (zstack.c)
+ - restore didn't undo currentgstate. (igstate.h, store.h,
+gsstate.c, zdevice2.c, zdps1.c, ztype.c)
+ - The scanner didn't set the local bit properly in a suspended
+state. (iscan.c)
+ - copypage disregarded #copies. (gs_init.ps)
+ - An incorrectly declared pointer led to addressing faults on
+16-bit systems. (zchar1.c)
+ - The cache for Separation colors was allocated with one element
+too few. (zcsindex.c)
+
+Changes `executive' so that if an error other than EOF occurs in the
+reading of the statement, the interpreter prints the error message, but
+control remains in the executive loop. (This isn't a very good fix; a
+better one will require refactoring executive / execute / run.)
+(gs_init.ps)
+
+Changes dictionary undo saving to use the new ref_must_save macro [internal
+change only]. (idict.c)
+
+Moves configuration definitions from iinit.c to gconfig.c. (gcdefs.h,
+interp.h, gconfig.c, gs.c, iinit.c, zmisc2.c, gs.mak)
+
+Moves =string from systemdict to userdict for Adobe compatibility.
+(gs_init.ps)
+
+Starts to implement the Interpolate flag in image dictionaries. See under
+Library below for restrictions. (zpaint.c, zimage2.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - stream_compact attempted to compact a read-only string being used
+as the data source of a filter. (sbasic.c, stream.c)
+
+Adds an EncodedEOLAlign flag to the CCITTFaxEncode stream, to allow direct
+generation of TIFF/F output. (scfx.h, scfe.c, zfilter2.c)
+
+Library
+-------
+
+Fixes bugs:
+ - There was no structure definition for gs_type1_state, so a GC
+during the execution of an OtherSubrs procedure could scramble pointers in
+the saved state. (gxfont1.h, gxtype1.h, gstype1.c, gxhint2.c)
+ - A couple of calls had to discard const, but didn't include the
+necessary cast. (gxpcmap.c)
+ - makeimagedevice refused to accept an empty image. (gsdevice.c)
+ - The extra parentheses around arguments in memory_.h caused some
+compilers to fail. (memory_.h)
+ - Floating point overflows during coordinate conversion terminated
+Ghostscript. (gxfarith.h, gxfixed.h, gsmatrix.c, gsmisc.c)
+ - Accents still weren't getting placed properly on characters
+created with seac. (gstype1.c, gxhint2.c)
+ - The SGI C compiler couldn't handle the (perfectly legal)
+definitions of dev_init_[open_]misc. (gxdevice.h)
+ - string_.h caused some problems with gcc on some versions of
+Solaris. (string_.h)
+ - The halftone levels for color screens were computed incorrectly.
+(gzht.h, gxdither.c)
+ - Color screens sometimes had vertical stripes of solid color
+interspersed. (gxcht.c)
+ - Colors could get mapped incorrectly if a compiler aggressively
+(and incorrectly) reordered the computation of procedure arguments
+involving the unit_frac macro. (gxcmap.c)
+ - setcachedevice[2] insisted that the corners of the bounding box
+be given in the correct order, i.e., llx < urx and lly < ury. (gschar.c)
+ - The image operator gave a limitcheck on unrotated 1-bit-per-pixel
+images whose width in device coordinates exceeded 65529. (gsimage.c)
+ - The garbage collector didn't trace the input data of an
+in-progress image operator correctly. (gsimage.c)
+
+Changes the max_rgb and dither_rgb members of gx_device_color_info to
+max_color and dither_colors, since Ghostscript now uses these for CMYK
+devices as well. Also changes dither_gray to dither_grays. (gdevmem.h,
+gdevprn.h, gxdevice.h, gdevbit.c, gdevcdj.c, gdevprn.c, gdevxini.c,
+gsdparam.c, gxcht.c, gxcmap.c)
+
+Starts to implement the Interpolate option for images. Currently this is
+only implemented for image, not imagemask, and only for rotations that are
+multiples of 90 degrees (possibly with reflection). (gsimage.h,
+gsiscale.h, gximage.h, gsimage.c, gsimage1.c, gsiscale.c)
+
+Starts to implement XStep and YStep in pattern dictionaries. (gxdcolor.h,
+gxpcolor.h, gspcolor.c, gxpcmap.c)
+
+Version 3.01 (8/14/94)
+============
+
+This is a patch release to fix early problems in release 3.0, and to clean
+up a few known loose ends.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - language.doc still documented the devicename procedure, which has
+been withdrawn. (language.doc)
+ - drivers.doc didn't specify under what circumstances each
+procedure could be called. (drivers.doc)
+ - current.doc said that setcachedevice and makeimagedevice wouldn't
+accept packed arrays, but neither of these operators takes any array
+arguments. (current.doc)
+ - current.doc said that definefont didn't interact properly with
+the resource machinery, which apparently is no longer true. (current.doc)
+ - make.doc incorrectly gave the name of the DVX makefile as
+dvx-djg.mak rather than dvx-gcc.mak. (make.doc)
+ - In one place, devices.doc incorrectly used -sBitsPerPixel= rather
+than -dBitsPerPixel=. (devices.doc)
+
+Notes that a kernel bug in SCO Unix makes Ghostscript not work correctly in
+some circumstances. (use.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - devs.mak incorrectly referred to gdevjetp.c instead of
+gdev3852.c. (devs.mak)
+ - The obsolete file gsprops.c was accidentally included in the
+fileset.
+
+Changes the version numbering scheme from A.BCC to A.B[C]. E.g., this
+release will be 3.01, not 3.001. (gs_init.ps, gs.c, iinit.c)
+
+Adds the LaserJet 4 driver to all makefiles that already include the
+LaserJet 3 driver. (*.mak)
+
+Adds the BJ-200 driver to all makefiles that already included the BJ-10e
+driver. (*.mak)
+
+Splits the Unix 'install' target into install-exec and install-data. Moves
+the executable scripts from gsdatadir to a new directory scriptdir, which
+defaults to bindir. (ansihead.mak, cc-head.mak, gcc-head.mak,
+unix-end.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - genconf had fixed buffer sizes built into it, which it could
+overrun its working storage without checking. (genconf.c)
+
+Removes RCS or SCCS headers from two utility files. (pj-gs.sh,
+printafm.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The new dfaxhigh and dfaxlow drivers didn't set
+state.EncodedByteAlign to false. (gdevdfax.c)
+ - The sunview driver assumed that the device would be open before
+map_rgb_color was called. (gdevsun.c)
+ - The CP50 driver incremented page_count itself, rather than
+letting the core library do it. (gdevcp50.c)
+ - The GIF driver(s) could loop indefinitely under certain
+circumstances. (gdevgif.c)
+ - The Group 4 fax drivers incorrectly included end-of-line codes in
+the output. (gdevtfax.c, gdevdfax.c)
+ - The Group 4 fax drivers could put out an EOB in the middle of the
+data. (scfe.c)
+ - The DesignJet 650C driver didn't use the correct compression
+mode. (gdevcdj.c)
+ - The Hercules and EGA/VGA/SVGA drivers computed the page height
+incorrectly according to the A4 switch. (gdevherc.c, gdevpcfb.h)
+
+Changes the page_count and showpage_count members of the device structure
+from int to long. (gxdevice.h, gdevprn.c, gsdparam.c)
+
+Changes the faxg3, faxg32d, and faxg4 drivers so that, like the TIFF and
+dfax drivers, they adjust the page size to one of the three CCITT standard
+sizes if this is reasonable. (gdevtfax.c)
+
+Splits the bit driver into bit, bitrgb, and bitcmyk. Adds bitrgb and
+bitcmyk to all makefiles that included bit. (*.mak, devs.mak, gdevbit.c)
+
+Replaces the atiw16, tseng16, and tvga16 SuperVGA drivers with a single
+svga16 driver that allows specifying the display mode number. (devs.mak,
+gdevpcfb.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The MS Windows and OS/2 drivers allocated their terminal input
+buffers in a way that could cause the GC to crash. (gp_mswin.c, gp_os2.c)
+ - The handling of gettimeofday on SVR4 platforms was incorrect.
+(time_.h, gp_sysv.c, gp_unix.c)
+ - On some platforms, function prototypes were not enabled even if
+__STDC__ was defined. (stdpre.h)
+ - The VMS build script referred to an obsolete feature lev2only.
+(vms.mak)
+
+Changes the DVX platform so that stdprn is buffered. This should improve
+printing performance dramatically. (gp_dvx.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Setting DISKFONTS resulted in a reference to FontFileDirectory
+before it was defined. (gs_type1.ps, gs_fonts.ps)
+ - /Font findresource gave an error rather than doing font
+substitution. (gs_res.ps)
+ - FontDirectory wasn't rebound to GlobalFontDirectory when global
+VM was current. (gs_res.ps, zdict.c)
+ - Type 1 fonts weren't loaded into global VM. (gs_fonts.ps)
+ - In the standard Fontmap, the Utopia fonts had extension .gsf
+rather than .pfa. (fontmap.gs)
+ - Fonts whose FontBBox was [0 0 0 0] were not displayed, or were
+displayed as tiny dots. (gs_type1.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - dict_put could read from the variable pvslot before it was used.
+(This was harmless, since the value was never actually used; it just upset
+Purify.) (idict.c)
+ - Binary object sequences could cause addressing faults.
+(iscanbin.c)
+ - The attributes on names were set incorrectly in binary object
+sequences. (iscanbin.c)
+ - gs.c duplicated (in some cases incorrectly) some definitions in
+interp.h. (gs.c)
+ - gs_lib_paths was declared const in one place and non-const in
+another. (zfile.c)
+ - file_restore and font_restore had inconsistent const declarations
+for their argument. (isave.c)
+ - iodev_os_open_file was missing its last formal parameter.
+(ziodev.c)
+ - gs.c declared gs_devicename with an incorrect extern. (gs.c)
+ - undefinefont didn't interact properly with the resource
+machinery. (gs_lev2.ps)
+ - The declaration for swap_entry used a typedef name as a formal
+parameter, which upset some compilers. (zmisc2.c)
+ - Including the ccinit feature could cause the garbage collector to
+make an invalid access. (stream.c)
+ - The check for t_[a]struct types in ztype.c was incorrect.
+(ztype.c)
+ - After the collection of halftone samples, temporary data
+structures were freed incorrectly. (gzht.h, gsht1.c, zht.c)
+ - Images with source width between 489 and 492 crashed the
+memory manager. (iastate.h)
+
+Makes it possible to define SEARCH_HERE_FIRST (gsmain.c) in the makefile.
+(gsmain.c)
+
+Splits the Level 2 resource machinery into a separate file. (gs_lev2.ps,
+gs_res.ps, gs.mak, unix-end.mak, vms.mak).
+
+Changes the names of the DiffEncode/Decode filters to
+PixelDifferenceEncode/Decode, and splits them off into a separate
+"feature". (gs.mak, zfilter2.c, zfpdiff.c, spdiff.c, spdiffx.h)
+
+Adds experimental code for filtered image scaling. DON'T USE THIS CODE.
+(zimage2.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxEncode filter could put out an EOB in the middle of
+the data. (scfe.c)
+
+Splits off the PixelDifferenceEncode/Decode filters into a separate
+"feature". (gs.mak)
+
+Library
+-------
+
+Fixes bugs:
+ - gs_setcachedevice could return a garbage error code. (gschar.c)
+ - joins on stroked lines were incorrect if the device coordinate
+system mapped +Y to +Y. (gxstroke.c)
+ - If gsmisc.c supplied versions of missing library routines, they
+could clash with the names of the real ones if those were present
+unexpectedly. (memory_.h, gsmisc.c)
+ - The initialization expression for is_open in the
+dev_init_misc_open macro included a cast, which some compilers don't allow.
+(gxdevice.h, gsdevice.c, gxclip2.c, gxpcmap.c)
+ - In Type 1 fonts, character that specified their side bearing and
+width with sbw rather than hsbw gave an invalidfont error. (gstype1.c)
+ - Some procedures were declared inconsistently with regard to const
+arguments. (gscie.c, gxpcmap.c, gxacpath.c, gxcmap.c)
+ - A few places still assumed that pointers occupied 4 bytes.
+(gxclist.c)
+ - Rendering a gray halftone on a CMYK device called the device's
+map_rgb_color procedure instead of map_cmyk_color. (gxdither.c)
+
+Renames gsfile.c as gswppm.c. (gsfile.c, gswppm.c)
+
+Implements the ability to cache arbitrarily transformed characters. This
+is currently enabled by a compile-time flag in gschar.c. (gschar.c)
+
+Version 3.0 (8/1/94)
+===========
+
+This is the first full Level 2 version released to the public.
+Unfortunately, we were not able to include setpagedevice in this release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - README didn't mention Aladdin's European distributor.
+ - psfiles.doc didn't describe some of the newer gs_*.ps files.
+
+Notes that gcc -O2 (version 2.5.8 of gcc) generates incorrect code for some
+modules on the H-P RISC architecture.
+
+Notes that on AXP platforms running VMS, DEC C V4.0 is required.
+
+Procedures
+----------
+
+Fixes bugs:
+ - 'make clean' didn't delete devs.tr or t.tr.
+ - devs.mak was missing the entry for faxg32d.
+ - unixansi.mak omitted some drivers that were included in
+unix-cc.mak and unix-gcc.mak.
+
+Updates jpeg.mak to reference version 5beta1 of the IJG JPEG code.
+
+Changes the version numbering scheme from A.B.C to A.B[CC]. I.e., the
+first sub-release after 3.0 will be 3.01 or 3.001, not 3.0.1.
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2ascii didn't do a setglobal.
+
+Adds an option to ansi2knr to convert ... to va_alist/va_dcl.
+
+Drivers
+-------
+
+Fixes bugs:
+ - The newly added faxg32d driver didn't have an entry in devs.mak.
+ - The BMP, GIF, and PCX drivers wrote out an incorrect color
+palette (the blue values were too small).
+ - The vgalib driver had some compilation problems.
+ - The TIFF drivers didn't produce correct multi-page output.
+
+Adds faxg32d and tiffg32d drivers.
+
+Reinstates the DigiFax drivers, which were withdrawn when the new fax
+drivers were added.
+
+Platforms
+---------
+
+Fixes bugs:
+ - gs_btokn.ps and gs_ccfnt.ps weren't installed on Unix platforms.
+ - The VMS module list omitted SBHC, included a non-existent GXDASH,
+and had incorrect names for some of the IJG JPEG files.
+ - The VMS build scripts (vms*.mak) had incorrect "boilerplate".
+ - The VMS script file gssetmod.com had \r characters in it, as well
+as \n characters.
+ - The echogs and genarch utilities didn't return the correct exit
+codes under VMS.
+ - The VMS Fontmap had incorrect entries for the Courier and Charter
+fonts.
+ - When running under Ghostview, Ghostscript didn't drain the input
+pipe. (We fixed this with a temporary patch in gs.c; this isn't a good
+solution for the longer term.)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The free AvantGarde, Bookman, and Palatino font families had
+incorrect FontBBox values.
+ - The 'f' and 'j' in the free AvantGarde-DemiOblique,
+Bookman-DemiItalic, Bookman-LightItalic, and Palatino-Italic fonts were
+chopped off on the right. (The bitmaps were chopped off in the original
+BDF fonts from which these fonts were made.) ****** THIS PROBLEM WAS NOT
+ACTUALLY FIXED. ******
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - gs -h and gs -v didn't print the tertiary version number correctly.
+ - Binary object sequences with no strings or names didn't read in
+correctly.
+ - Binary object sequences that crossed an input buffer boundary
+didn't read in correctly.
+ - Binary object sequences read in as {[e1 .. en] e1 ... en} instead
+of {[e1 ... en]}. (New bug in 2.9.x.)
+ - setpattern didn't set the current color space correctly if the
+current color space wasn't a Pattern space.
+ - If the current color space was an uncolored Pattern space but the
+current color was a colored Pattern, currentcolor returned extra values on
+the operands stack.
+ - .buildfont1 in gs_type1.ps didn't force binding of the old
+definition, causing ps2ascii to loop endlessly.
+
+Adds a facility for writing and reading dictionaries in binary object
+sequences. This is experimental and subject to change in the future.
+
+Streams
+-------
+
+Fixes bugs:
+ - gs_run_string and ccinit didn't have any way to mark the string
+as "foreign", which confused the GC.
+
+Library
+-------
+
+Fixes bugs:
+ - gxchar.h had an extra comma after the last element of the
+show_width_status enum, which upset some compilers.
+ - stroke and strokepath didn't correctly skip zero-length segments
+if the line width was less than one pixel, or if there was a closed subpath
+consisting entirely of zero-length segments.
+ - strokepath sometimes incorrectly added a moveto at the end of the
+path.
+
+Versions before 3.0
+===================
+
+See the files history2.txt and history1.txt.
diff --git a/gs/humor.txt b/gs/humor.txt
new file mode 100644
index 000000000..67daff416
--- /dev/null
+++ b/gs/humor.txt
@@ -0,0 +1,50 @@
+ Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, humor.txt, contains a humorous message, verbatim except for
+minor spelling corrections, received from a friend out in network-land.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Regarding Ghostscript: I hate to say this to you but I've already
+implemented a Ghostscript interpreter. I'm happy to see that someone else
+has recognized the need dead people have for computers. I have included an
+example of the output of my Ghostscript at the end of this letter.
+
+The interpreter is written in a language called cant-C, developed by Mr.
+Turing last year. The compiler is easily ported to any environment you
+care to name. I would be more than happy to send you a copy, but you must
+first contact my lawyer for this venture, Thomas Jefferson of Phila. Pa..
+(As a side note, Mr. Jefferson is very excited by Ghostscript. Look for
+The Declaration of Independance V1.1 RSN).
+
+The possibilities for Ghostscript go far beyond Deathtop publishing, I'm
+sure you'll agree. I have contacted numerous authors who may be interested
+in using Ghostscript (Shakespeare, Hemingway, etc) and all have been very
+excited by what they've seen. (Shakespeare wants to write a modern Romeo
+and Juliette, called Romeo and Julio, the story of 2 gay hispanic men kept
+apart by their parents.)
+
+Anyway, here is the Ghostscript example I promised. Feel free to show this
+to your friends and colleagues, I'm sure they'll all be suitably impressed.
+
+
+------Cut Here--------------------------------------
+
+------Cut Here--------------------------------------
diff --git a/gs/install.txt b/gs/install.txt
new file mode 100644
index 000000000..98716923b
--- /dev/null
+++ b/gs/install.txt
@@ -0,0 +1,256 @@
+ Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, install.txt, describes how to install the Ghostscript language
+interpreter.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** How to install Ghostscript ********
+********
+
+There are 3 separate items that you must have available in order to be able
+to run Ghostscript:
+
+ (1) The Ghostscript executable file(s) -- on some operating
+ systems, more than one file is required. These are entirely
+ platform-specific. See below for details.
+
+ (2) Initialization files that Ghostscript reads in when it
+ starts up. These are the same on all platforms.
+
+ (3) Fonts, for rendering text. These are platform-independent,
+ but if you already have fonts of the right kind on your platform,
+ you may be able to use them. See below for details. See the
+ companion document fonts.txt for more information about fonts.
+
+The initialization files (2) are the same on all platforms:
+
+ - gs_*.ps (see psfiles.txt for the full list), unless Ghostscript was
+ compiled using the "compiled initialization files" option.
+
+ - pdf_*.ps, if Ghostscript was compiled with the ability to
+ interpret PDF files (pdf.dev included in FEATURE_DEVS).
+
+ - Fontmap, unless you plan to always invoke Ghostscript with the
+ -dNOFONTMAP switch.
+
+See the search algorithm section of use.txt for a description of the search
+algorithm used to find these files.
+
+The per-platform descriptions that follow tell you where to install these
+files.
+
+MS-DOS
+------
+
+You need the following files to run Ghostscript:
+ GS386.EXE
+ DOS4GW.EXE
+
+You should install all the files except the fonts in C:\GS, and the
+fonts in C:\GS\FONTS.
+
+If you have Adobe Type Manager fonts installed on your system, and you wish
+to use them with Ghostscript, you may wish to replace the FONTMAP file with
+FONTMAP.ATM, and to add to the environment variable GS_LIB the name of the
+directory where the fonts are located (see below for more information about
+GS_LIB). Before you do this, please read carefully the license that
+accompanies the ATM fonts; Aladdin Enterprises takes no responsibility for
+any possible violations of such licenses. Similarly, if you have Adobe Type
+Basics, you may wish to replace FONTMAP with FONTMAP.ATB. Finally, if you
+have neither ATM nor ATB but you have Adobe Acrobat installed, you can use
+the 14 Acrobat fonts in place of the ones provided with Ghostscript by
+removing the following entries from FONTMAP:
+ Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique
+ Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique
+ Symbol
+ Times-Bold, Times-BoldItalic, Times-Italic, Times-Roman
+ ZapfDingbats
+and adding the Acrobat fonts directory to GS_FONTPATH.
+
+MS Windows
+----------
+
+Win32s or Windows 95 or Windows NT is required. You need the following
+files to run Ghostscript:
+ GSWIN32.EXE
+ GSWIN32C.EXE
+ GSDLL32.DLL
+ GS16SPL.EXE (Win32s only)
+
+You should install all the files except the fonts in C:\GS, and the fonts in
+C:\GS\FONTS.
+
+The GSview previewer contains an installation program to install and
+configure GSview and Ghostscript for Win32. Information on GSview is
+available from:
+ http://www.cs.wisc.edu/~ghost/gsview/
+
+See under "MS-DOS" above for information about using Adobe Type Manager,
+Adobe Type Basics, or Adobe Acrobat fonts.
+
+If your system uses TrueType fonts, you can get them converted to a
+Ghostscript-compatible format at the time you select your "printer" by
+doing the following:
+
+1) Open control panel and double click on the printers icon.
+2) Select your Postscript Printer.
+3) Choose Setup.
+4) Choose Options.
+5) Choose Advanced.
+6) At the top of the Dialog Box you will see TrueType Fonts
+ Send to Printer As: <drop down menu>
+ Choose Adobe Type 1.
+7) Uncheck Use Printer Fonts for All TrueType Fonts
+ and Use Substitution Table.
+8) OK.
+9) OK etc.
+
+That's it! Your TrueType fonts will automatically be downloaded in your
+PostScript file for Ghostscript to use.
+
+For printer devices, the default output is:
+ the default printer (Win95 or WinNT)
+OR
+ prompt for a printer port (Win32s).
+This can be modified as follows.
+ -sOutputFile="LPT1:"
+ Output to named port.
+ -sOutputFile="\\spool\printer name" (Win95 or WinNT only)
+ Output to named printer.
+ -sOutputFile="\\spool" (Win95 or WinNT only)
+ Prompt for printer name. Local printers only are supported.
+For Win32s, make sure that gs16spl.exe is in the same directory
+as gswin32.exe.
+
+
+OS/2 2.x
+--------
+
+The Ghostscript OS/2 implementation is designed for OS/2 2.1 or later.
+A few people have used it successfully under OS/2 2.0, but it has had
+very little testing.
+
+You need the following files to run Ghostscript:
+ GSOS2.EXE - this is a text application that will run windowed or
+ full screen.
+ GSDLL2.DLL - this is a Dynamic Link Library that must be in the same
+ directory as GSOS2.EXE or on the LIBPATH.
+ GSPMDRV.EXE - this is an "external driver" used by the "os2pm"
+ device, which is normally the default device and which
+ displays output in a Presentation Manager window.
+ GSPMDRV.EXE must be located in the same directory as
+ GSOS2.EXE or on the PATH.
+
+GSOS2.EXE, GSDLL2.DLL and GSPMDRV.EXE are compiled using EMX/GCC 0.9b.
+You must have the EMX DLL's on your LIBPATH. These are available from
+ ftp://hobbes.nmsu.edu/os2/unix/emx09b/emxrt.zip
+
+The system menu of the Ghostscript Image window includes a "Copy" command
+to copy the currently displayed bitmap to the Clipboard.
+
+OS/2 comes with some Adobe Type Manager fonts. If you wish to use these
+with Ghostscript, you should replace the FONTMAP file with FONTMAP.OS2,
+and add to the environment variable GS_LIB the name of the directory where
+the fonts are located, usually c:\psfonts. (see below for more
+information about GS_LIB). Before you do this, please read carefully the
+license that accompanies the ATM fonts; Aladdin Enterprises takes no
+responsibility for any possible violations of such licenses.
+
+Since GSOS2.EXE is not a PM application, it cannot determine the depth of
+the PM display. You must provide this information using the
+-dBitsPerPixel option. The default is 8 bits/pixel. Valid values are 1,
+4, 8 & 24.
+ For monochrome VGA use -dBitsPerPixel=1
+ For standard VGA screen use -dBitsPerPixel=4
+ For 256 colour SVGA use -dBitsPerPixel=8
+A command file gspm.cmd containing the following line may be useful:
+ @c:\gs\gsos2.exe -Ic:/gs;c:/gs/fonts;c:/psfonts -sDEVICE=os2pm
+ -dBitsPerPixel=8 -sPAPERSIZE=a4 %1 %2 %3 %4 %5 %6 %7 %8
+
+While drawing, the os2pm driver updates the display every 5 seconds. On
+slow computers this is undesirable and a different interval can be
+specified in milliseconds with the -dUpdateInterval option. The default
+is -dUpdateInterval=5000; to disable update use -dUpdateInterval=0.
+
+Standard VGA is very slow due to double buffering to avoid bugs and due to
+1 plane to 4 plane conversion. Use a 256 color display driver by
+preference. Many display drivers have bugs which cause 1 bit/pixel
+bitmaps to be displayed incorrectly.
+
+GSOS2.EXE and GSPMDRV.EXE will stay in memory for the number of minutes
+specified in the environment variable GS_LOAD.
+
+If you run GS386 in the OS/2 2.0 or 2.1 DOS Box, you must select the
+"ENABLED" setting for the DPMI_DOS_API option of the DOS Box. GS386
+will not run with the "AUTO" setting.
+
+For printer devices, output goes to the default queue.
+To print to a specified queue, use -sOutputFile=\\spool\NullLPT1
+where NullLPT1 is the queue physical name.
+
+Unix
+----
+
+You need the following file to run Ghostscript:
+ gs
+
+Installing Ghostscript on a Unix system requires compiling it first: please
+read the Unix section(s) in make.txt for more information, especially
+regarding how to decide which makefile to use and how you may need to edit
+it. After building, execute
+ make install
+
+The makefile installs all the files, except the fonts, in /usr/local or
+various subdirectories thereof. The fonts should be installed in
+/usr/local/share/ghostscript/fonts. Consult the makefile for more details.
+If you have Adobe Acrobat installed, you can use the 14 Acrobat fonts in
+place of the ones provided with Ghostscript by removing the following
+entries from Fontmap:
+ Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique
+ Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique
+ Symbol
+ Times-Bold, Times-BoldItalic, Times-Italic, Times-Roman
+ ZapfDingbats
+and adding the Acrobat fonts directory to GS_FONTPATH.
+
+NOTE: The syntax of the 'install' command varies unpredictably between Unix
+systems. If your system has an 'installbsd' program, edit the definition of
+INSTALL in the makefile to change 'install' to 'installbsd' before you run
+'make install'.
+
+VMS
+---
+
+You need the following executable file to run Ghostscript:
+ GS.EXE
+
+Installing Ghostscript on a VMS system requires compiling it first.
+
+You should install all the files, including the fonts, in the same directory
+as the executable and initialization files. By default, this is the
+directory in which you did the compilation. Consult the makefile
+(OPENVMS.MAK) for more details.
+
+If you have DECWindows/Motif installed, you may wish to replace the FONTMAP
+file with the file FONTMAP.VMS. Read the comment at the beginning of the
+latter file for more information.
diff --git a/gs/jpeg/Makefile b/gs/jpeg/Makefile
new file mode 100644
index 000000000..ce0c45f1c
--- /dev/null
+++ b/gs/jpeg/Makefile
@@ -0,0 +1,274 @@
+# Generated automatically from makefile.cfg by configure.
+# Makefile for Independent JPEG Group's software
+
+# makefile.cfg is edited by configure to produce a custom Makefile.
+
+# Read installation instructions before saying "make" !!
+
+# For compiling with source and object files in different directories.
+srcdir = .
+
+# Where to install the programs and man pages.
+prefix = /usr/local
+exec_prefix = ${prefix}
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+binprefix =
+manprefix =
+manext = 1
+mandir = $(prefix)/man/man$(manext)
+
+# The name of your C compiler:
+CC= gcc
+
+# You may need to adjust these cc options:
+CFLAGS= -O -I$(srcdir)
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+# However, any special defines for ansi2knr.c may be included here:
+ANSI2KNRFLAGS=
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+SHELL= /bin/sh
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# file rename command
+MV= mv
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+# installation program
+INSTALL= /usr/bin/install -c
+INSTALL_PROGRAM= ${INSTALL}
+INSTALL_DATA= ${INSTALL} -m 644
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# This rule causes ansi2knr to be invoked.
+# .c.o:
+# ./ansi2knr $(srcdir)/$*.c T$*.c
+# $(CC) $(CFLAGS) -c T$*.c
+# $(RM) T$*.c $*.o
+# $(MV) T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libjpeg.a: $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+install: cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+ $(INSTALL_PROGRAM) cjpeg $(bindir)/$(binprefix)cjpeg
+ $(INSTALL_PROGRAM) djpeg $(bindir)/$(binprefix)djpeg
+ $(INSTALL_PROGRAM) jpegtran $(bindir)/$(binprefix)jpegtran
+ $(INSTALL_PROGRAM) rdjpgcom $(bindir)/$(binprefix)rdjpgcom
+ $(INSTALL_PROGRAM) wrjpgcom $(bindir)/$(binprefix)wrjpgcom
+ $(INSTALL_DATA) $(srcdir)/cjpeg.1 $(mandir)/$(manprefix)cjpeg.$(manext)
+ $(INSTALL_DATA) $(srcdir)/djpeg.1 $(mandir)/$(manprefix)djpeg.$(manext)
+ $(INSTALL_DATA) $(srcdir)/jpegtran.1 $(mandir)/$(manprefix)jpegtran.$(manext)
+ $(INSTALL_DATA) $(srcdir)/rdjpgcom.1 $(mandir)/$(manprefix)rdjpgcom.$(manext)
+ $(INSTALL_DATA) $(srcdir)/wrjpgcom.1 $(mandir)/$(manprefix)wrjpgcom.$(manext)
+
+install-lib: libjpeg.a install-headers
+ $(INSTALL_DATA) libjpeg.a $(libdir)/$(binprefix)libjpeg.a
+
+install-headers: jconfig.h
+ $(INSTALL_DATA) jconfig.h $(includedir)/jconfig.h
+ $(INSTALL_DATA) $(srcdir)/jpeglib.h $(includedir)/jpeglib.h
+ $(INSTALL_DATA) $(srcdir)/jmorecfg.h $(includedir)/jmorecfg.h
+ $(INSTALL_DATA) $(srcdir)/jerror.h $(includedir)/jerror.h
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) ansi2knr core testout* config.log config.status
+
+distribute:
+ $(RM) jpegsrc.tar*
+ tar cvf jpegsrc.tar $(DISTFILES)
+ compress -v jpegsrc.tar
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm $(srcdir)/testorig.jpg
+ ./djpeg -dct int -gif -outfile testout.gif $(srcdir)/testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg $(srcdir)/testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+ ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+ cmp $(srcdir)/testimg.ppm testout.ppm
+ cmp $(srcdir)/testimg.gif testout.gif
+ cmp $(srcdir)/testimg.jpg testout.jpg
+ cmp $(srcdir)/testimg.ppm testoutp.ppm
+ cmp $(srcdir)/testimgp.jpg testoutp.jpg
+ cmp $(srcdir)/testorig.jpg testoutt.jpg
+
+check: test
+
+# GNU Make likes to know which target names are not really files to be made:
+.PHONY: all install install-lib install-headers clean distribute test check
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/README b/gs/jpeg/README
new file mode 100644
index 000000000..fa69a18c6
--- /dev/null
+++ b/gs/jpeg/README
@@ -0,0 +1,383 @@
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 6a of 7-Feb-96
+=================================
+
+This distribution contains the sixth public release of the Independent JPEG
+Group's free JPEG software. You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+Serious users of this software (particularly those incorporating it into
+larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to
+our electronic mailing list. Mailing list members are notified of updates
+and have a chance to participate in technical discussions, etc.
+
+This software is the work of Tom Lane, Philip Gladstone, Luis Ortiz, Jim
+Boucher, Lee Crocker, Julian Minguillon, George Phillips, Davide Rossi,
+Ge' Weijers, and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the official ISO JPEG standards committee.
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW General description of JPEG and the IJG software.
+LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
+REFERENCES Where to learn more about JPEG.
+ARCHIVE LOCATIONS Where to find newer versions of this software.
+RELATED SOFTWARE Other stuff you should get.
+FILE FORMAT WARS Software *not* to get.
+TO DO Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+ install.doc How to configure and install the IJG software.
+ usage.doc Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ *.1 Unix-style man pages for programs (same info as usage.doc).
+ wizard.doc Advanced usage instructions for JPEG wizards only.
+ change.log Version-to-version change highlights.
+Programmer and internal documentation:
+ libjpeg.doc How to use the JPEG library in your own programs.
+ example.c Sample code for calling the JPEG library.
+ structure.doc Overview of the JPEG library's internal structure.
+ filelist.doc Road map of IJG files.
+ coderules.doc Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.doc and usage.doc. Useful information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image compression and
+decompression. JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images. JPEG is intended for compressing
+"real-world" scenes; line drawings, cartoons and other non-realistic images
+are not its strong suit. JPEG is lossy, meaning that the output image is not
+exactly identical to the input image. Hence you must not use JPEG if you
+have to have identical output bits. However, on typical photographic images,
+very good compression levels can be obtained with no visible change, and
+remarkably high compression levels are possible if you can tolerate a
+low-quality image. For more details, see the references, or just experiment
+with various compression settings.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes. Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+For legal reasons, we are not distributing code for the arithmetic-coding
+variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting
+the hierarchical or lossless processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays. These extra functions can be compiled out of the
+library if not required for a particular application. We have also included
+"jpegtran", a utility for lossless transcoding between different JPEG
+processes, and "rdjpgcom" and "wrjpgcom", two simple applications for
+inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful. In particular,
+the software is not intended to be read as a tutorial on JPEG. (See the
+REFERENCES section for introductory material.) Rather, it is intended to
+be reliable, portable, industrial-strength code. We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-1996, Thomas G. Lane.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it. (See the file
+ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
+of any program generated from the IJG code, this does not limit you more than
+the foregoing paragraphs do.
+
+The configuration script "configure" was produced with GNU Autoconf. It
+is copyright by the Free Software Foundation but is freely distributable.
+
+It appears that the arithmetic coding option of the JPEG spec is covered by
+patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot
+legally be used without obtaining one or more licenses. For this reason,
+support for arithmetic coding has been removed from the free JPEG software.
+(Since arithmetic coding provides only a marginal gain over the unpatented
+Huffman mode, it is unlikely that very many implementations will support it.)
+So far as we are aware, there are no patent restrictions on the remaining
+code.
+
+WARNING: Unisys has begun to enforce their patent on LZW compression against
+GIF encoders and decoders. You will need a license from Unisys to use the
+included rdgif.c or wrgif.c files in a commercial or shareware application.
+At this time, Unisys is not enforcing their patent against freeware, so
+distribution of this package remains legal. However, we intend to remove
+GIF support from the IJG package as soon as a suitable replacement format
+becomes reasonably popular.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We highly recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+ Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+ Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.) If you don't have the CACM issue
+handy, a PostScript file containing a revised version of Wallace's article
+is available at ftp.uu.net, graphics/jpeg/wallace.ps.gz. The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material. Note: the Wallace article is copyright ACM and
+IEEE, and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson, published by M&T Books (Redwood
+City, CA), 1991, ISBN 1-55851-216-0. This book provides good explanations and
+example C code for a multitude of compression methods including JPEG. It is
+an excellent source if you are comfortable reading C code but don't know much
+about data compression in general. The book's JPEG sample code is far from
+industrial-strength, but when you are ready to look at a full implementation,
+you've got one here...
+
+The best full description of JPEG is the textbook "JPEG Still Image Data
+Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published
+by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp.
+The book includes the complete text of the ISO JPEG standards (DIS 10918-1
+and draft DIS 10918-2). This is by far the most complete exposition of JPEG
+in existence, and we highly recommend it.
+
+The JPEG standard itself is not available electronically; you must order a
+paper copy through ISO or ITU. (Unless you feel a need to own a certified
+official copy, we recommend buying the Pennebaker and Mitchell book instead;
+it's much cheaper and includes a great deal of useful explanatory material.)
+In the USA, copies of the standard may be ordered from ANSI Sales at (212)
+642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI
+doesn't take credit card orders, but Global does.) It's not cheap: as of
+1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7%
+shipping/handling. The standard is divided into two parts, Part 1 being the
+actual specification, while Part 2 covers compliance testing methods. Part 1
+is titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+
+Extensions to the original JPEG standard are defined in JPEG Part 3, a new ISO
+document. Part 3 is undergoing ISO balloting and is expected to be approved
+by the end of 1995; it will have document numbers ISO/IEC IS 10918-3, ITU-T
+T.84. IJG currently does not support any Part 3 extensions.
+
+The JPEG standard does not specify all details of an interchangeable file
+format. For the omitted details we follow the "JFIF" conventions, revision
+1.02. A copy of the JFIF spec is available from:
+ Literature Department
+ C-Cube Microsystems, Inc.
+ 1778 McCarthy Blvd.
+ Milpitas, CA 95035
+ phone (408) 944-6300, fax (408) 944-6314
+A PostScript version of this document is available at ftp.uu.net, file
+graphics/jpeg/jfif.ps.gz. It can also be obtained by e-mail from the C-Cube
+mail server, netlib@c3.pla.ca.us. Send the message "send jfif_ps from jpeg"
+to the server to obtain the JFIF document; send the message "help" if you have
+trouble.
+
+The TIFF 6.0 file format specification can be obtained by FTP from sgi.com
+(192.48.153.1), file graphics/tiff/TIFF6.ps.Z; or you can order a printed
+copy from Aldus Corp. at (206) 628-6593. The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7). Copies of this Note can be obtained from sgi.com or
+from ftp.uu.net:/graphics/jpeg/. It is expected that the next revision of
+the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note. libtiff is available
+from sgi.com:/graphics/tiff/.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is ftp.uu.net (Internet
+address 192.48.96.9). The most recent released version can always be found
+there in directory graphics/jpeg. This particular version will be archived
+as graphics/jpeg/jpegsrc.v6a.tar.gz. If you are on the Internet, you
+can retrieve files from ftp.uu.net by standard anonymous FTP. If you don't
+have FTP access, UUNET's archives are also available via UUCP; contact
+help@uunet.uu.net for information on retrieving files that way.
+
+Numerous Internet sites maintain copies of the UUNET files. However, only
+ftp.uu.net is guaranteed to have the latest official version.
+
+You can also obtain this software in DOS-compatible "zip" archive format from
+the SimTel archives (ftp.coast.net:/SimTel/msdos/graphics/), or on CompuServe
+in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 "JPEG Tools".
+Again, these versions may sometimes lag behind the ftp.uu.net release.
+
+The JPEG FAQ (Frequently Asked Questions) article is a useful source of
+general information about JPEG. It is updated constantly and therefore is
+not included in this distribution. The FAQ is posted every two weeks to
+Usenet newsgroups comp.graphics.misc, news.answers, and other groups.
+You can always obtain the latest version from the news.answers archive at
+rtfm.mit.edu. By FTP, fetch /pub/usenet/news.answers/jpeg-faq/part1 and
+.../part2. If you don't have FTP, send e-mail to mail-server@rtfm.mit.edu
+with body
+ send usenet/news.answers/jpeg-faq/part1
+ send usenet/news.answers/jpeg-faq/part2
+
+
+RELATED SOFTWARE
+================
+
+Numerous viewing and image manipulation programs now support JPEG. (Quite a
+few of them use this library to do so.) The JPEG FAQ described above lists
+some of the more popular free and shareware viewers, and tells where to
+obtain them on Internet.
+
+If you are on a Unix machine, we highly recommend Jef Poskanzer's free
+PBMPLUS image software, which provides many useful operations on PPM-format
+image files. In particular, it can convert PPM images to and from a wide
+range of other formats. You can obtain this package by FTP from ftp.x.org
+(contrib/pbmplus*.tar.Z) or ftp.ee.lbl.gov (pbmplus*.tar.Z). There is also
+a newer update of this package called NETPBM, available from
+wuarchive.wustl.edu under directory /graphics/graphics/packages/NetPBM/.
+Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software
+is; you are likely to have difficulty making it work on any non-Unix machine.
+
+A different free JPEG implementation, written by the PVRG group at Stanford,
+is available from havefun.stanford.edu in directory pub/jpeg. This program
+is designed for research and experimentation rather than production use;
+it is slower, harder to use, and less portable than the IJG code, but it
+is easier to read and modify. Also, the PVRG code supports lossless JPEG,
+which we do not.
+
+
+FILE FORMAT WARS
+================
+
+Some JPEG programs produce files that are not compatible with our library.
+The root of the problem is that the ISO JPEG committee failed to specify a
+concrete file format. Some vendors "filled in the blanks" on their own,
+creating proprietary formats that no one else could read. (For example, none
+of the early commercial JPEG implementations for the Macintosh were able to
+exchange compressed files.)
+
+The file format we have adopted is called JFIF (see REFERENCES). This format
+has been agreed to by a number of major commercial JPEG vendors, and it has
+become the de facto standard. JFIF is a minimal or "low end" representation.
+We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF
+Technical Note #2) for "high end" applications that need to record a lot of
+additional data about an image. TIFF/JPEG is fairly new and not yet widely
+supported, unfortunately.
+
+The upcoming JPEG Part 3 standard defines a file format called SPIFF.
+SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should
+be able to read the most common variant of SPIFF. SPIFF has some technical
+advantages over JFIF, but its major claim to fame is simply that it is an
+official standard rather than an informal one. At this point it is unclear
+whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto
+standard. IJG intends to support SPIFF once the standard is frozen, but we
+have not decided whether it should become our default output format or not.
+(In any case, our decoder will remain capable of reading JFIF indefinitely.)
+
+Various proprietary file formats incorporating JPEG compression also exist.
+We have little or no sympathy for the existence of these formats. Indeed,
+one of the original reasons for developing this free software was to help
+force convergence on common, open format standards for JPEG files. Don't
+use a proprietary file format!
+
+
+TO DO
+=====
+
+In future versions, we are considering supporting some of the upcoming JPEG
+Part 3 extensions --- principally, variable quantization and the SPIFF file
+format.
+
+Tuning the software for better behavior at low quality/high compression
+settings is also of interest. The current method for scaling the
+quantization tables is known not to be very good at low Q values.
+
+As always, speeding things up is high on our priority list.
+
+Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net.
diff --git a/gs/jpeg/ansi2knr b/gs/jpeg/ansi2knr
new file mode 100755
index 000000000..95b717a10
--- /dev/null
+++ b/gs/jpeg/ansi2knr
Binary files differ
diff --git a/gs/jpeg/ansi2knr.1 b/gs/jpeg/ansi2knr.1
new file mode 100644
index 000000000..f9ee5a631
--- /dev/null
+++ b/gs/jpeg/ansi2knr.1
@@ -0,0 +1,36 @@
+.TH ANSI2KNR 1 "19 Jan 1996"
+.SH NAME
+ansi2knr \- convert ANSI C to Kernighan & Ritchie C
+.SH SYNOPSIS
+.I ansi2knr
+[--varargs] input_file [output_file]
+.SH DESCRIPTION
+If no output_file is supplied, output goes to stdout.
+.br
+There are no error messages.
+.sp
+.I ansi2knr
+recognizes function definitions by seeing a non-keyword identifier at the left
+margin, followed by a left parenthesis, with a right parenthesis as the last
+character on the line, and with a left brace as the first token on the
+following line (ignoring possible intervening comments). It will recognize a
+multi-line header provided that no intervening line ends with a left or right
+brace or a semicolon. These algorithms ignore whitespace and comments, except
+that the function name must be the first thing on the line.
+.sp
+The following constructs will confuse it:
+.br
+ - Any other construct that starts at the left margin and follows the
+above syntax (such as a macro or function call).
+.br
+ - Some macros that tinker with the syntax of the function header.
+.sp
+The --varargs switch is obsolete, and is recognized only for
+backwards compatibility. The present version of
+.I ansi2knr
+will always attempt to convert a ... argument to va_alist and va_dcl.
+.SH AUTHOR
+L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and
+continues to maintain the current version; most of the code in the current
+version is his work. ansi2knr also includes contributions by Francois
+Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>.
diff --git a/gs/jpeg/ansi2knr.c b/gs/jpeg/ansi2knr.c
new file mode 100644
index 000000000..4e05fc2d3
--- /dev/null
+++ b/gs/jpeg/ansi2knr.c
@@ -0,0 +1,693 @@
+/* ansi2knr.c */
+/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone for the
+consequences of using it or for whether it serves any particular purpose or
+works at all, unless he says so in writing. Refer to the GNU General Public
+License (the "GPL") for full details.
+
+Everyone is granted permission to copy, modify and redistribute ansi2knr,
+but only under the conditions described in the GPL. A copy of this license
+is supposed to have been given to you along with ansi2knr so you can know
+your rights and responsibilities. It should be in a file named COPYLEFT.
+[In the IJG distribution, the GPL appears below, not in a separate file.]
+Among other things, the copyright notice and this notice must be preserved
+on all copies.
+
+We explicitly state here what we believe is already implied by the GPL: if
+the ansi2knr program is distributed as a separate set of sources and a
+separate executable file which are aggregated on a storage medium together
+with another program, this in itself does not bring the other program under
+the GPL, nor does the mere fact that such a program or the procedures for
+constructing it invoke the ansi2knr executable bring any other part of the
+program under the GPL.
+*/
+
+/*
+---------- Here is the GNU GPL file COPYLEFT, referred to above ----------
+----- These terms do NOT apply to the JPEG software itself; see README ------
+
+ GHOSTSCRIPT GENERAL PUBLIC LICENSE
+ (Clarified 11 Feb 1988)
+
+ Copyright (C) 1988 Richard M. Stallman
+ Everyone is permitted to copy and distribute verbatim copies of this
+ license, but changing it is not allowed. You can also use this wording
+ to make the terms for other programs.
+
+ The license agreements of most software companies keep you at the
+mercy of those companies. By contrast, our general public license is
+intended to give everyone the right to share Ghostscript. To make sure
+that you get the rights we want you to have, we need to make
+restrictions that forbid anyone to deny you these rights or to ask you
+to surrender the rights. Hence this license agreement.
+
+ Specifically, we want to make sure that you have the right to give
+away copies of Ghostscript, that you receive source code or else can get
+it if you want it, that you can change Ghostscript or use pieces of it
+in new free programs, and that you know you can do these things.
+
+ To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute
+copies of Ghostscript, 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 tell them their rights.
+
+ Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for Ghostscript. If Ghostscript is
+modified by someone else and passed on, we want its recipients to know
+that what they have is not what we distributed, so that any problems
+introduced by others will not reflect on our reputation.
+
+ Therefore we (Richard M. Stallman and the Free Software Foundation,
+Inc.) make the following terms which say what you must do to be allowed
+to distribute or change Ghostscript.
+
+
+ COPYING POLICIES
+
+ 1. You may copy and distribute verbatim copies of Ghostscript source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy a valid copyright and license
+notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
+Distributed by Free Software Foundation, Inc." (or with whatever year is
+appropriate); keep intact the notices on all files that refer to this
+License Agreement and to the absence of any warranty; and give any other
+recipients of the Ghostscript program a copy of this License Agreement
+along with the program. You may charge a distribution fee for the
+physical act of transferring a copy.
+
+ 2. You may modify your copy or copies of Ghostscript or any portion of
+it, and copy and distribute such modifications under the terms of
+Paragraph 1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish,
+ that in whole or in part contains or is a derivative of Ghostscript
+ or any part thereof, to be licensed at no charge to all third
+ parties on terms identical to those contained in this License
+ Agreement (except that you may choose to grant more extensive
+ warranty protection to some or all third parties, at your option).
+
+ c) You may charge a distribution fee for the physical act of
+ transferring a copy, and you may at your option offer warranty
+ protection in exchange for a fee.
+
+Mere aggregation of another unrelated program with this program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other program under the scope of these terms.
+
+ 3. You may copy and distribute Ghostscript (or a portion or derivative
+of it, under Paragraph 2) in object code or executable form under the
+terms of Paragraphs 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
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal
+ shipping charge) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+For an executable file, complete source code means all the source code for
+all modules it contains; but, as a special exception, it need not include
+source code for modules which are standard libraries that accompany the
+operating system on which the executable file runs.
+
+ 4. You may not copy, sublicense, distribute or transfer Ghostscript
+except as expressly provided under this License Agreement. Any attempt
+otherwise to copy, sublicense, distribute or transfer Ghostscript is
+void and your rights to use the program under this License agreement
+shall be automatically terminated. However, parties who have received
+computer software programs from you with this License Agreement will not
+have their licenses terminated so long as such parties remain in full
+compliance.
+
+ 5. If you wish to incorporate parts of Ghostscript into other free
+programs whose distribution conditions are different, write to the Free
+Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not
+yet worked out a simple rule that can be stated here, but we will often
+permit this. We 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.
+
+Your comments and suggestions about our licensing policies and our
+software are welcome! Please contact the Free Software Foundation,
+Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296.
+
+ NO WARRANTY
+
+ BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
+WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD
+M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES
+PROVIDE GHOSTSCRIPT "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 GHOSTSCRIPT IS WITH
+YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN
+ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE
+GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
+ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU
+HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM
+BY ANY OTHER PARTY.
+
+-------------------- End of file COPYLEFT ------------------------------
+*/
+
+/*
+ * Usage:
+ ansi2knr input_file [output_file]
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes function definitions by seeing a non-keyword
+ * identifier at the left margin, followed by a left parenthesis,
+ * with a right parenthesis as the last character on the line,
+ * and with a left brace as the first token on the following line
+ * (ignoring possible intervening comments).
+ * It will recognize a multi-line header provided that no intervening
+ * line ends with a left or right brace or a semicolon.
+ * These algorithms ignore whitespace and comments, except that
+ * the function name must be the first thing on the line.
+ * The following constructs will confuse it:
+ * - Any other construct that starts at the left margin and
+ * follows the above syntax (such as a macro or function call).
+ * - Some macros that tinker with the syntax of the function header.
+ */
+
+/*
+ * The original and principal author of ansi2knr is L. Peter Deutsch
+ * <ghost@aladdin.com>. Other authors are noted in the change history
+ * that follows (in reverse chronological order):
+ lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with
+ compilers that don't understand void, as suggested by
+ Tom Lane
+ lpd 96-01-15 changed to require that the first non-comment token
+ on the line following a function header be a left brace,
+ to reduce sensitivity to macros, as suggested by Tom Lane
+ <tgl@sss.pgh.pa.us>
+ lpd 95-06-22 removed #ifndefs whose sole purpose was to define
+ undefined preprocessor symbols as 0; changed all #ifdefs
+ for configuration symbols to #ifs
+ lpd 95-04-05 changed copyright notice to make it clear that
+ including ansi2knr in a program does not bring the entire
+ program under the GPL
+ lpd 94-12-18 added conditionals for systems where ctype macros
+ don't handle 8-bit characters properly, suggested by
+ Francois Pinard <pinard@iro.umontreal.ca>;
+ removed --varargs switch (this is now the default)
+ lpd 94-10-10 removed CONFIG_BROKETS conditional
+ lpd 94-07-16 added some conditionals to help GNU `configure',
+ suggested by Francois Pinard <pinard@iro.umontreal.ca>;
+ properly erase prototype args in function parameters,
+ contributed by Jim Avera <jima@netcom.com>;
+ correct error in writeblanks (it shouldn't erase EOLs)
+ lpd 89-xx-xx original version
+ */
+
+/* Most of the conditionals here are to make ansi2knr work with */
+/* or without the GNU configure machinery. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_CONFIG_H
+
+/*
+ For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
+ This will define HAVE_CONFIG_H and so, activate the following lines.
+ */
+
+# if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+#else /* not HAVE_CONFIG_H */
+
+/* Otherwise do it the hard way */
+
+# ifdef BSD
+# include <strings.h>
+# else
+# ifdef VMS
+ extern int strlen(), strncmp();
+# else
+# include <string.h>
+# endif
+# endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+/*
+ malloc and free should be declared in stdlib.h,
+ but if you've got a K&R compiler, they probably aren't.
+ */
+# ifdef MSDOS
+# include <malloc.h>
+# else
+# ifdef VMS
+ extern char *malloc();
+ extern void free();
+# else
+ extern char *malloc();
+ extern int free();
+# endif
+# endif
+
+#endif
+
+/*
+ * The ctype macros don't always handle 8-bit characters correctly.
+ * Compensate for this here.
+ */
+#ifdef isascii
+# undef HAVE_ISASCII /* just in case */
+# define HAVE_ISASCII 1
+#else
+#endif
+#if STDC_HEADERS || !HAVE_ISASCII
+# define is_ascii(c) 1
+#else
+# define is_ascii(c) isascii(c)
+#endif
+
+#define is_space(c) (is_ascii(c) && isspace(c))
+#define is_alpha(c) (is_ascii(c) && isalpha(c))
+#define is_alnum(c) (is_ascii(c) && isalnum(c))
+
+/* Scanning macros */
+#define isidchar(ch) (is_alnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *skipspace();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{ FILE *in, *out;
+#define bufsize 5000 /* arbitrary size */
+ char *buf;
+ char *line;
+ char *more;
+ /*
+ * In previous versions, ansi2knr recognized a --varargs switch.
+ * If this switch was supplied, ansi2knr would attempt to convert
+ * a ... argument to va_alist and va_dcl; if this switch was not
+ * supplied, ansi2knr would simply drop any such arguments.
+ * Now, ansi2knr always does this conversion, and we only
+ * check for this switch for backward compatibility.
+ */
+ int convert_varargs = 1;
+
+ if ( argc > 1 && argv[1][0] == '-' )
+ { if ( !strcmp(argv[1], "--varargs") )
+ { convert_varargs = 1;
+ argc--;
+ argv++;
+ }
+ else
+ { fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
+ exit(1);
+ }
+ }
+ switch ( argc )
+ {
+ default:
+ printf("Usage: ansi2knr input_file [output_file]\n");
+ exit(0);
+ case 2:
+ out = stdout;
+ break;
+ case 3:
+ out = fopen(argv[2], "w");
+ if ( out == NULL )
+ { fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+ exit(1);
+ }
+ }
+ in = fopen(argv[1], "r");
+ if ( in == NULL )
+ { fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+ exit(1);
+ }
+ fprintf(out, "#line 1 \"%s\"\n", argv[1]);
+ buf = malloc(bufsize);
+ line = buf;
+ while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+ {
+test: line += strlen(line);
+ switch ( test1(buf) )
+ {
+ case 2: /* a function header */
+ convert1(buf, out, 1, convert_varargs);
+ break;
+ case 1: /* a function */
+ /* Check for a { at the start of the next line. */
+ more = ++line;
+f: if ( line >= buf + (bufsize - 1) ) /* overflow check */
+ goto wl;
+ if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
+ goto wl;
+ switch ( *skipspace(more, 1) )
+ {
+ case '{':
+ /* Definitely a function header. */
+ convert1(buf, out, 0, convert_varargs);
+ fputs(more, out);
+ break;
+ case 0:
+ /* The next line was blank or a comment: */
+ /* keep scanning for a non-comment. */
+ line += strlen(line);
+ goto f;
+ default:
+ /* buf isn't a function header, but */
+ /* more might be. */
+ fputs(buf, out);
+ strcpy(buf, more);
+ line = buf;
+ goto test;
+ }
+ break;
+ case -1: /* maybe the start of a function */
+ if ( line != buf + (bufsize - 1) ) /* overflow check */
+ continue;
+ /* falls through */
+ default: /* not a function */
+wl: fputs(buf, out);
+ break;
+ }
+ line = buf;
+ }
+ if ( line != buf )
+ fputs(buf, out);
+ free(buf);
+ fclose(out);
+ fclose(in);
+ return 0;
+}
+
+/* Skip over space and comments, in either direction. */
+char *
+skipspace(p, dir)
+ register char *p;
+ register int dir; /* 1 for forward, -1 for backward */
+{ for ( ; ; )
+ { while ( is_space(*p) )
+ p += dir;
+ if ( !(*p == '/' && p[dir] == '*') )
+ break;
+ p += dir; p += dir;
+ while ( !(*p == '*' && p[dir] == '/') )
+ { if ( *p == 0 )
+ return p; /* multi-line comment?? */
+ p += dir;
+ }
+ p += dir; p += dir;
+ }
+ return p;
+}
+
+/*
+ * Write blanks over part of a string.
+ * Don't overwrite end-of-line characters.
+ */
+int
+writeblanks(start, end)
+ char *start;
+ char *end;
+{ char *p;
+ for ( p = start; p < end; p++ )
+ if ( *p != '\r' && *p != '\n' )
+ *p = ' ';
+ return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ * 0 - definitely not a function definition;
+ * 1 - definitely a function definition;
+ * 2 - definitely a function prototype (NOT USED);
+ * -1 - may be the beginning of a function definition,
+ * append another line and look again.
+ * The reason we don't attempt to convert function prototypes is that
+ * Ghostscript's declaration-generating macros look too much like
+ * prototypes, and confuse the algorithms.
+ */
+int
+test1(buf)
+ char *buf;
+{ register char *p = buf;
+ char *bend;
+ char *endfn;
+ int contin;
+
+ if ( !isidfirstchar(*p) )
+ return 0; /* no name at left margin */
+ bend = skipspace(buf + strlen(buf) - 1, -1);
+ switch ( *bend )
+ {
+ case ';': contin = 0 /*2*/; break;
+ case ')': contin = 1; break;
+ case '{': return 0; /* not a function */
+ case '}': return 0; /* not a function */
+ default: contin = -1;
+ }
+ while ( isidchar(*p) )
+ p++;
+ endfn = p;
+ p = skipspace(p, 1);
+ if ( *p++ != '(' )
+ return 0; /* not a function */
+ p = skipspace(p, 1);
+ if ( *p == ')' )
+ return 0; /* no parameters */
+ /* Check that the apparent function name isn't a keyword. */
+ /* We only need to check for keywords that could be followed */
+ /* by a left parenthesis (which, unfortunately, is most of them). */
+ { static char *words[] =
+ { "asm", "auto", "case", "char", "const", "double",
+ "extern", "float", "for", "if", "int", "long",
+ "register", "return", "short", "signed", "sizeof",
+ "static", "switch", "typedef", "unsigned",
+ "void", "volatile", "while", 0
+ };
+ char **key = words;
+ char *kp;
+ int len = endfn - buf;
+
+ while ( (kp = *key) != 0 )
+ { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+ return 0; /* name is a keyword */
+ key++;
+ }
+ }
+ return contin;
+}
+
+/* Convert a recognized function definition or header to K&R syntax. */
+int
+convert1(buf, out, header, convert_varargs)
+ char *buf;
+ FILE *out;
+ int header; /* Boolean */
+ int convert_varargs; /* Boolean */
+{ char *endfn;
+ register char *p;
+ char **breaks;
+ unsigned num_breaks = 2; /* for testing */
+ char **btop;
+ char **bp;
+ char **ap;
+ char *vararg = 0;
+
+ /* Pre-ANSI implementations don't agree on whether strchr */
+ /* is called strchr or index, so we open-code it here. */
+ for ( endfn = buf; *(endfn++) != '('; )
+ ;
+top: p = endfn;
+ breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+ if ( breaks == 0 )
+ { /* Couldn't allocate break table, give up */
+ fprintf(stderr, "Unable to allocate break table!\n");
+ fputs(buf, out);
+ return -1;
+ }
+ btop = breaks + num_breaks * 2 - 2;
+ bp = breaks;
+ /* Parse the argument list */
+ do
+ { int level = 0;
+ char *lp = NULL;
+ char *rp;
+ char *end = NULL;
+
+ if ( bp >= btop )
+ { /* Filled up break table. */
+ /* Allocate a bigger one and start over. */
+ free((char *)breaks);
+ num_breaks <<= 1;
+ goto top;
+ }
+ *bp++ = p;
+ /* Find the end of the argument */
+ for ( ; end == NULL; p++ )
+ { switch(*p)
+ {
+ case ',':
+ if ( !level ) end = p;
+ break;
+ case '(':
+ if ( !level ) lp = p;
+ level++;
+ break;
+ case ')':
+ if ( --level < 0 ) end = p;
+ else rp = p;
+ break;
+ case '/':
+ p = skipspace(p, 1) - 1;
+ break;
+ default:
+ ;
+ }
+ }
+ /* Erase any embedded prototype parameters. */
+ if ( lp )
+ writeblanks(lp + 1, rp);
+ p--; /* back up over terminator */
+ /* Find the name being declared. */
+ /* This is complicated because of procedure and */
+ /* array modifiers. */
+ for ( ; ; )
+ { p = skipspace(p - 1, -1);
+ switch ( *p )
+ {
+ case ']': /* skip array dimension(s) */
+ case ')': /* skip procedure args OR name */
+ { int level = 1;
+ while ( level )
+ switch ( *--p )
+ {
+ case ']': case ')': level++; break;
+ case '[': case '(': level--; break;
+ case '/': p = skipspace(p, -1) + 1; break;
+ default: ;
+ }
+ }
+ if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+ { /* We found the name being declared */
+ while ( !isidfirstchar(*p) )
+ p = skipspace(p, 1) + 1;
+ goto found;
+ }
+ break;
+ default:
+ goto found;
+ }
+ }
+found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+ { if ( convert_varargs )
+ { *bp++ = "va_alist";
+ vararg = p-2;
+ }
+ else
+ { p++;
+ if ( bp == breaks + 1 ) /* sole argument */
+ writeblanks(breaks[0], p);
+ else
+ writeblanks(bp[-1] - 1, p);
+ bp--;
+ }
+ }
+ else
+ { while ( isidchar(*p) ) p--;
+ *bp++ = p+1;
+ }
+ p = end;
+ }
+ while ( *p++ == ',' );
+ *bp = p;
+ /* Make a special check for 'void' arglist */
+ if ( bp == breaks+2 )
+ { p = skipspace(breaks[0], 1);
+ if ( !strncmp(p, "void", 4) )
+ { p = skipspace(p+4, 1);
+ if ( p == breaks[2] - 1 )
+ { bp = breaks; /* yup, pretend arglist is empty */
+ writeblanks(breaks[0], p + 1);
+ }
+ }
+ }
+ /* Put out the function name and left parenthesis. */
+ p = buf;
+ while ( p != endfn ) putc(*p, out), p++;
+ /* Put out the declaration. */
+ if ( header )
+ { fputs(");", out);
+ for ( p = breaks[0]; *p; p++ )
+ if ( *p == '\r' || *p == '\n' )
+ putc(*p, out);
+ }
+ else
+ { for ( ap = breaks+1; ap < bp; ap += 2 )
+ { p = *ap;
+ while ( isidchar(*p) )
+ putc(*p, out), p++;
+ if ( ap < bp - 1 )
+ fputs(", ", out);
+ }
+ fputs(") ", out);
+ /* Put out the argument declarations */
+ for ( ap = breaks+2; ap <= bp; ap += 2 )
+ (*ap)[-1] = ';';
+ if ( vararg != 0 )
+ { *vararg = 0;
+ fputs(breaks[0], out); /* any prior args */
+ fputs("va_dcl", out); /* the final arg */
+ fputs(bp[0], out);
+ }
+ else
+ fputs(breaks[0], out);
+ }
+ free((char *)breaks);
+ return 0;
+}
diff --git a/gs/jpeg/cderror.h b/gs/jpeg/cderror.h
new file mode 100644
index 000000000..41a29cd12
--- /dev/null
+++ b/gs/jpeg/cderror.h
@@ -0,0 +1,132 @@
+/*
+ * cderror.h
+ *
+ * Copyright (C) 1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the cjpeg/djpeg
+ * applications. These strings are not needed as part of the JPEG library
+ * proper.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef CDERROR_H
+#define CDERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* CDERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */
+
+#ifdef BMP_SUPPORTED
+JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
+JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported")
+JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
+JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
+JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
+JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
+JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
+JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
+JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
+JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image")
+JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
+#endif /* BMP_SUPPORTED */
+
+#ifdef GIF_SUPPORTED
+JMESSAGE(JERR_GIF_BUG, "GIF output got confused")
+JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d")
+JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB")
+JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file")
+JMESSAGE(JERR_GIF_NOT, "Not a GIF file")
+JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image")
+JMESSAGE(JTRC_GIF_BADVERSION,
+ "Warning: unexpected GIF version number '%c%c%c'")
+JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x")
+JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input")
+JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file")
+JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring")
+JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image")
+JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits")
+#endif /* GIF_SUPPORTED */
+
+#ifdef PPM_SUPPORTED
+JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB")
+JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file")
+JMESSAGE(JERR_PPM_NOT, "Not a PPM file")
+JMESSAGE(JTRC_PGM, "%ux%u PGM image")
+JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image")
+JMESSAGE(JTRC_PPM, "%ux%u PPM image")
+JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image")
+#endif /* PPM_SUPPORTED */
+
+#ifdef RLE_SUPPORTED
+JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library")
+JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB")
+JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE")
+JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file")
+JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header")
+JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header")
+JMESSAGE(JERR_RLE_NOT, "Not an RLE file")
+JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE")
+JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup")
+JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file")
+JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file")
+JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d")
+#endif /* RLE_SUPPORTED */
+
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format")
+JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file")
+JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB")
+JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image")
+JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image")
+JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image")
+#else
+JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled")
+#endif /* TARGA_SUPPORTED */
+
+JMESSAGE(JERR_BAD_CMAP_FILE,
+ "Color map file is invalid or of unsupported format")
+JMESSAGE(JERR_TOO_MANY_COLORS,
+ "Output file format cannot handle %d colormap entries")
+JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed")
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_UNKNOWN_FORMAT,
+ "Unrecognized input file format --- perhaps you need -targa")
+#else
+JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format")
+#endif
+JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTADDONCODE
+} ADDON_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
diff --git a/gs/jpeg/cdjpeg.c b/gs/jpeg/cdjpeg.c
new file mode 100644
index 000000000..a3d6e0675
--- /dev/null
+++ b/gs/jpeg/cdjpeg.c
@@ -0,0 +1,179 @@
+/*
+ * cdjpeg.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common support routines used by the IJG application
+ * programs (cjpeg, djpeg, jpegtran).
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef NEED_SIGNAL_CATCHER
+#include <signal.h> /* to declare signal() */
+#endif
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+
+/*
+ * Signal catcher to ensure that temporary files are removed before aborting.
+ * NB: for Amiga Manx C this is actually a global routine named _abort();
+ * we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus...
+ */
+
+#ifdef NEED_SIGNAL_CATCHER
+
+static j_common_ptr sig_cinfo;
+
+void /* must be global for Manx C */
+signal_catcher (int signum)
+{
+ if (sig_cinfo != NULL) {
+ if (sig_cinfo->err != NULL) /* turn off trace output */
+ sig_cinfo->err->trace_level = 0;
+ jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */
+ }
+ exit(EXIT_FAILURE);
+}
+
+
+GLOBAL(void)
+enable_signal_catcher (j_common_ptr cinfo)
+{
+ sig_cinfo = cinfo;
+ signal(SIGINT, signal_catcher);
+#ifdef SIGTERM /* not all systems have SIGTERM */
+ signal(SIGTERM, signal_catcher);
+#endif
+}
+
+#endif
+
+
+/*
+ * Optional progress monitor: display a percent-done figure on stderr.
+ */
+
+#ifdef PROGRESS_REPORT
+
+METHODDEF(void)
+progress_monitor (j_common_ptr cinfo)
+{
+ cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
+ int total_passes = prog->pub.total_passes + prog->total_extra_passes;
+ int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
+
+ if (percent_done != prog->percent_done) {
+ prog->percent_done = percent_done;
+ if (total_passes > 1) {
+ fprintf(stderr, "\rPass %d/%d: %3d%% ",
+ prog->pub.completed_passes + prog->completed_extra_passes + 1,
+ total_passes, percent_done);
+ } else {
+ fprintf(stderr, "\r %3d%% ", percent_done);
+ }
+ fflush(stderr);
+ }
+}
+
+
+GLOBAL(void)
+start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress)
+{
+ /* Enable progress display, unless trace output is on */
+ if (cinfo->err->trace_level == 0) {
+ progress->pub.progress_monitor = progress_monitor;
+ progress->completed_extra_passes = 0;
+ progress->total_extra_passes = 0;
+ progress->percent_done = -1;
+ cinfo->progress = &progress->pub;
+ }
+}
+
+
+GLOBAL(void)
+end_progress_monitor (j_common_ptr cinfo)
+{
+ /* Clear away progress display */
+ if (cinfo->err->trace_level == 0) {
+ fprintf(stderr, "\r \r");
+ fflush(stderr);
+ }
+}
+
+#endif
+
+
+/*
+ * Case-insensitive matching of possibly-abbreviated keyword switches.
+ * keyword is the constant keyword (must be lower case already),
+ * minchars is length of minimum legal abbreviation.
+ */
+
+GLOBAL(boolean)
+keymatch (char * arg, const char * keyword, int minchars)
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return FALSE; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return FALSE; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return FALSE;
+ return TRUE; /* A-OK */
+}
+
+
+/*
+ * Routines to establish binary I/O mode for stdin and stdout.
+ * Non-Unix systems often require some hacking to get out of text mode.
+ */
+
+GLOBAL(FILE *)
+read_stdin (void)
+{
+ FILE * input_file = stdin;
+
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "Cannot reopen stdin\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+ return input_file;
+}
+
+
+GLOBAL(FILE *)
+write_stdout (void)
+{
+ FILE * output_file = stdout;
+
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "Cannot reopen stdout\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+ return output_file;
+}
diff --git a/gs/jpeg/cdjpeg.h b/gs/jpeg/cdjpeg.h
new file mode 100644
index 000000000..cc0d60016
--- /dev/null
+++ b/gs/jpeg/cdjpeg.h
@@ -0,0 +1,179 @@
+/*
+ * cdjpeg.h
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common declarations for the sample applications
+ * cjpeg and djpeg. It is NOT used by the core JPEG library.
+ */
+
+#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */
+#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h" /* get library error codes too */
+#include "cderror.h" /* get application-specific error codes */
+
+
+/*
+ * Object interface for cjpeg's source file decoding modules
+ */
+
+typedef struct cjpeg_source_struct * cjpeg_source_ptr;
+
+struct cjpeg_source_struct {
+ JMETHOD(void, start_input, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+ JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+ JMETHOD(void, finish_input, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+
+ FILE *input_file;
+
+ JSAMPARRAY buffer;
+ JDIMENSION buffer_height;
+};
+
+
+/*
+ * Object interface for djpeg's output file encoding modules
+ */
+
+typedef struct djpeg_dest_struct * djpeg_dest_ptr;
+
+struct djpeg_dest_struct {
+ /* start_output is called after jpeg_start_decompress finishes.
+ * The color map will be ready at this time, if one is needed.
+ */
+ JMETHOD(void, start_output, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo));
+ /* Emit the specified number of pixel rows from the buffer. */
+ JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied));
+ /* Finish up at the end of the image. */
+ JMETHOD(void, finish_output, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo));
+
+ /* Target file spec; filled in by djpeg.c after object is created. */
+ FILE * output_file;
+
+ /* Output pixel-row buffer. Created by module init or start_output.
+ * Width is cinfo->output_width * cinfo->output_components;
+ * height is buffer_height.
+ */
+ JSAMPARRAY buffer;
+ JDIMENSION buffer_height;
+};
+
+
+/*
+ * cjpeg/djpeg may need to perform extra passes to convert to or from
+ * the source/destination file format. The JPEG library does not know
+ * about these passes, but we'd like them to be counted by the progress
+ * monitor. We use an expanded progress monitor object to hold the
+ * additional pass count.
+ */
+
+struct cdjpeg_progress_mgr {
+ struct jpeg_progress_mgr pub; /* fields known to JPEG library */
+ int completed_extra_passes; /* extra passes completed */
+ int total_extra_passes; /* total extra */
+ /* last printed percentage stored here to avoid multiple printouts */
+ int percent_done;
+};
+
+typedef struct cdjpeg_progress_mgr * cd_progress_ptr;
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_read_bmp jIRdBMP
+#define jinit_write_bmp jIWrBMP
+#define jinit_read_gif jIRdGIF
+#define jinit_write_gif jIWrGIF
+#define jinit_read_ppm jIRdPPM
+#define jinit_write_ppm jIWrPPM
+#define jinit_read_rle jIRdRLE
+#define jinit_write_rle jIWrRLE
+#define jinit_read_targa jIRdTarga
+#define jinit_write_targa jIWrTarga
+#define read_quant_tables RdQTables
+#define read_scan_script RdScnScript
+#define set_quant_slots SetQSlots
+#define set_sample_factors SetSFacts
+#define read_color_map RdCMap
+#define enable_signal_catcher EnSigCatcher
+#define start_progress_monitor StProgMon
+#define end_progress_monitor EnProgMon
+#define read_stdin RdStdin
+#define write_stdout WrStdout
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Module selection routines for I/O modules. */
+
+EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo,
+ boolean is_os2));
+EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo));
+
+/* cjpeg support routines (in rdswitch.c) */
+
+EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,
+ int scale_factor, boolean force_baseline));
+EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));
+EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));
+EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));
+
+/* djpeg support routines (in rdcolmap.c) */
+
+EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* common support routines (in cdjpeg.c) */
+
+EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo));
+EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo,
+ cd_progress_ptr progress));
+EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo));
+EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars));
+EXTERN(FILE *) read_stdin JPP((void));
+EXTERN(FILE *) write_stdout JPP((void));
+
+/* miscellaneous useful macros */
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+#ifndef EXIT_WARNING
+#ifdef VMS
+#define EXIT_WARNING 1 /* VMS is very nonstandard */
+#else
+#define EXIT_WARNING 2
+#endif
+#endif
diff --git a/gs/jpeg/change.log b/gs/jpeg/change.log
new file mode 100644
index 000000000..231650e89
--- /dev/null
+++ b/gs/jpeg/change.log
@@ -0,0 +1,152 @@
+CHANGE LOG for Independent JPEG Group's JPEG software
+
+
+Version 6a 7-Feb-96
+--------------------
+
+Library initialization sequence modified to detect version mismatches
+and struct field packing mismatches between library and calling application.
+This change requires applications to be recompiled, but does not require
+any application source code change.
+
+All routine declarations changed to the style "GLOBAL(type) name ...",
+that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the
+routine's return type as an argument. This makes it possible to add
+Microsoft-style linkage keywords to all the routines by changing just
+these macros. Note that any application code that was using these macros
+will have to be changed.
+
+DCT coefficient quantization tables are now stored in normal array order
+rather than zigzag order. Application code that calls jpeg_add_quant_table,
+or otherwise manipulates quantization tables directly, will need to be
+changed. If you need to make such code work with either older or newer
+versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is
+recommended.
+
+djpeg's trace capability now dumps DQT tables in natural order, not zigzag
+order. This allows the trace output to be made into a "-qtables" file
+more easily.
+
+New system-dependent memory manager module for use on Apple Macintosh.
+
+Fix bug in cjpeg's -smooth option: last one or two scanlines would be
+duplicates of the prior line unless the image height mod 16 was 1 or 2.
+
+Repair minor problems in VMS, BCC, MC6 makefiles.
+
+New configure script based on latest GNU Autoconf.
+
+Correct the list of include files needed by MetroWerks C for ccommand().
+
+Numerous small documentation updates.
+
+
+Version 6 2-Aug-95
+-------------------
+
+Progressive JPEG support: library can read and write full progressive JPEG
+files. A "buffered image" mode supports incremental decoding for on-the-fly
+display of progressive images. Simply recompiling an existing IJG-v5-based
+decoder with v6 should allow it to read progressive files, though of course
+without any special progressive display.
+
+New "jpegtran" application performs lossless transcoding between different
+JPEG formats; primarily, it can be used to convert baseline to progressive
+JPEG and vice versa. In support of jpegtran, the library now allows lossless
+reading and writing of JPEG files as DCT coefficient arrays. This ability
+may be of use in other applications.
+
+Notes for programmers:
+* We changed jpeg_start_decompress() to be able to suspend; this makes all
+decoding modes available to suspending-input applications. However,
+existing applications that use suspending input will need to be changed
+to check the return value from jpeg_start_decompress(). You don't need to
+do anything if you don't use a suspending data source.
+* We changed the interface to the virtual array routines: access_virt_array
+routines now take a count of the number of rows to access this time. The
+last parameter to request_virt_array routines is now interpreted as the
+maximum number of rows that may be accessed at once, but not necessarily
+the height of every access.
+
+
+Version 5b 15-Mar-95
+---------------------
+
+Correct bugs with grayscale images having v_samp_factor > 1.
+
+jpeg_write_raw_data() now supports output suspension.
+
+Correct bugs in "configure" script for case of compiling in
+a directory other than the one containing the source files.
+
+Repair bug in jquant1.c: sometimes didn't use as many colors as it could.
+
+Borland C makefile and jconfig file work under either MS-DOS or OS/2.
+
+Miscellaneous improvements to documentation.
+
+
+Version 5a 7-Dec-94
+--------------------
+
+Changed color conversion roundoff behavior so that grayscale values are
+represented exactly. (This causes test image files to change.)
+
+Make ordered dither use 16x16 instead of 4x4 pattern for a small quality
+improvement.
+
+New configure script based on latest GNU Autoconf.
+Fix configure script to handle CFLAGS correctly.
+Rename *.auto files to *.cfg, so that configure script still works if
+file names have been truncated for DOS.
+
+Fix bug in rdbmp.c: didn't allow for extra data between header and image.
+
+Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data.
+
+Fix several bugs in rdrle.c.
+
+NEED_SHORT_EXTERNAL_NAMES option was broken.
+
+Revise jerror.h/jerror.c for more flexibility in message table.
+
+Repair oversight in jmemname.c NO_MKTEMP case: file could be there
+but unreadable.
+
+
+Version 5 24-Sep-94
+--------------------
+
+Version 5 represents a nearly complete redesign and rewrite of the IJG
+software. Major user-visible changes include:
+ * Automatic configuration simplifies installation for most Unix systems.
+ * A range of speed vs. image quality tradeoffs are supported.
+ This includes resizing of an image during decompression: scaling down
+ by a factor of 1/2, 1/4, or 1/8 is handled very efficiently.
+ * New programs rdjpgcom and wrjpgcom allow insertion and extraction
+ of text comments in a JPEG file.
+
+The application programmer's interface to the library has changed completely.
+Notable improvements include:
+ * We have eliminated the use of callback routines for handling the
+ uncompressed image data. The application now sees the library as a
+ set of routines that it calls to read or write image data on a
+ scanline-by-scanline basis.
+ * The application image data is represented in a conventional interleaved-
+ pixel format, rather than as a separate array for each color channel.
+ This can save a copying step in many programs.
+ * The handling of compressed data has been cleaned up: the application can
+ supply routines to source or sink the compressed data. It is possible to
+ suspend processing on source/sink buffer overrun, although this is not
+ supported in all operating modes.
+ * All static state has been eliminated from the library, so that multiple
+ instances of compression or decompression can be active concurrently.
+ * JPEG abbreviated datastream formats are supported, ie, quantization and
+ Huffman tables can be stored separately from the image data.
+ * And not only that, but the documentation of the library has improved
+ considerably!
+
+
+The last widely used release before the version 5 rewrite was version 4A of
+18-Feb-93. Change logs before that point have been discarded, since they
+are not of much interest after the rewrite.
diff --git a/gs/jpeg/cjpeg b/gs/jpeg/cjpeg
new file mode 100755
index 000000000..ec33ca313
--- /dev/null
+++ b/gs/jpeg/cjpeg
Binary files differ
diff --git a/gs/jpeg/cjpeg.1 b/gs/jpeg/cjpeg.1
new file mode 100644
index 000000000..4dfce000c
--- /dev/null
+++ b/gs/jpeg/cjpeg.1
@@ -0,0 +1,282 @@
+.TH CJPEG 1 "15 June 1995"
+.SH NAME
+cjpeg \- compress an image file to a JPEG file
+.SH SYNOPSIS
+.B cjpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B cjpeg
+compresses the named image file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+The currently supported input file formats are: PPM (PBMPLUS color
+format), PGM (PBMPLUS gray-scale format), BMP, GIF, Targa, and RLE (Utah Raster
+Toolkit format). (RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-GIF
+is the same as
+.BR \-gif ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-quality " N"
+Scale quantization tables to adjust image quality. Quality is 0 (worst) to
+100 (best); default is 75. (See below for more info.)
+.TP
+.B \-grayscale
+Create monochrome JPEG file from color input. Be sure to use this switch when
+compressing a grayscale GIF file, because
+.B cjpeg
+isn't bright enough to notice whether a GIF file uses only shades of gray.
+By saying
+.BR \-grayscale ,
+you'll get a smaller JPEG file that takes less time to process.
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters. Without this, default
+encoding parameters are used.
+.B \-optimize
+usually makes the JPEG file a little smaller, but
+.B cjpeg
+runs somewhat slower and needs much more memory. Image quality and speed of
+decompression are unaffected by
+.BR \-optimize .
+.TP
+.B \-progressive
+Create progressive JPEG file (see below).
+.TP
+.B \-targa
+Input file is Targa format. Targa files that contain an "identification"
+field will not be automatically recognized by
+.BR cjpeg ;
+for such files you must specify
+.B \-targa
+to make
+.B cjpeg
+treat the input as Targa format.
+For most Targa files, you won't need this switch.
+.PP
+The
+.B \-quality
+switch lets you trade off compressed file size against quality of the
+reconstructed image: the higher the quality setting, the larger the JPEG file,
+and the closer the output image will be to the original input. Normally you
+want to use the lowest quality setting (smallest file) that decompresses into
+something visually indistinguishable from the original image. For this
+purpose the quality setting should be between 50 and 95; the default of 75 is
+often about right. If you see defects at
+.B \-quality
+75, then go up 5 or 10 counts at a time until you are happy with the output
+image. (The optimal setting will vary from one image to another.)
+.PP
+.B \-quality
+100 will generate a quantization table of all 1's, minimizing loss in the
+quantization step (but there is still information loss in subsampling, as well
+as roundoff error). This setting is mainly of interest for experimental
+purposes. Quality values above about 95 are
+.B not
+recommended for normal use; the compressed file size goes up dramatically for
+hardly any gain in output image quality.
+.PP
+In the other direction, quality values below 50 will produce very small files
+of low image quality. Settings around 5 to 10 might be useful in preparing an
+index of a large image library, for example. Try
+.B \-quality
+2 (or so) for some amusing Cubist effects. (Note: quality
+values below about 25 generate 2-byte quantization tables, which are
+considered optional in the JPEG standard.
+.B cjpeg
+emits a warning message when you give such a quality value, because some
+other JPEG programs may be unable to decode the resulting file. Use
+.B \-baseline
+if you need to ensure compatibility at low quality values.)
+.PP
+The
+.B \-progressive
+switch creates a "progressive JPEG" file. In this type of JPEG file, the data
+is stored in multiple scans of increasing quality. If the file is being
+transmitted over a slow communications link, the decoder can use the first
+scan to display a low-quality image very quickly, and can then improve the
+display with each subsequent scan. The final image is exactly equivalent to a
+standard JPEG file of the same quality setting, and the total file size is
+about the same --- often a little smaller.
+.B Caution:
+progressive JPEG is not yet widely implemented, so many decoders will be
+unable to view a progressive JPEG file at all.
+.PP
+Switches for advanced users:
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware. Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.B \-restart 0
+(the default) means no restart markers.
+.TP
+.BI \-smooth " N"
+Smooth the input image to eliminate dithering noise. N, ranging from 1 to
+100, indicates the strength of smoothing. 0 (the default) means no smoothing.
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.PP
+The
+.B \-restart
+option inserts extra markers that allow a JPEG decoder to resynchronize after
+a transmission error. Without restart markers, any damage to a compressed
+file will usually ruin the image from the point of the error to the end of the
+image; with restart markers, the damage is usually confined to the portion of
+the image up to the next restart marker. Of course, the restart markers
+occupy extra space. We recommend
+.B \-restart 1
+for images that will be transmitted across unreliable networks such as Usenet.
+.PP
+The
+.B \-smooth
+option filters the input to eliminate fine-scale noise. This is often useful
+when converting GIF files to JPEG: a moderate smoothing factor of 10 to 50
+gets rid of dithering patterns in the input file, resulting in a smaller JPEG
+file and a better-looking image. Too large a smoothing factor will visibly
+blur the image, however.
+.PP
+Switches for wizards:
+.TP
+.B \-baseline
+Force a baseline JPEG file to be generated. This clamps quantization values
+to 8 bits even at low quality settings.
+.TP
+.BI \-qtables " file"
+Use the quantization tables given in the specified text file.
+.TP
+.BI \-qslots " N[,...]"
+Select which quantization table to use for each color component.
+.TP
+.BI \-sample " HxV[,...]"
+Set JPEG sampling factors for each color component.
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+The "wizard" switches are intended for experimentation with JPEG. If you
+don't know what you are doing, \fBdon't use them\fR. These switches are
+documented further in the file wizard.doc.
+.SH EXAMPLES
+.LP
+This example compresses the PPM file foo.ppm with a quality factor of
+60 and saves the output as foo.jpg:
+.IP
+.B cjpeg \-quality
+.I 60 foo.ppm
+.B >
+.I foo.jpg
+.SH HINTS
+Color GIF files are not the ideal input for JPEG; JPEG is really intended for
+compressing full-color (24-bit) images. In particular, don't try to convert
+cartoons, line drawings, and other images that have only a few distinct
+colors. GIF works great on these, JPEG does not. If you want to convert a
+GIF to JPEG, you should experiment with
+.BR cjpeg 's
+.B \-quality
+and
+.B \-smooth
+options to get a satisfactory conversion.
+.B \-smooth 10
+or so is often helpful.
+.PP
+Avoid running an image through a series of JPEG compression/decompression
+cycles. Image quality loss will accumulate; after ten or so cycles the image
+may be noticeably worse than it was after one cycle. It's best to use a
+lossless format while manipulating an image, then convert to JPEG format when
+you are ready to file the image away.
+.PP
+The
+.B \-optimize
+option to
+.B cjpeg
+is worth using when you are making a "final" version for posting or archiving.
+It's also a win when you are using low quality settings to make very small
+JPEG files; the percentage improvement is often a lot more than it is on
+larger files. (At present,
+.B \-optimize
+mode is always selected when generating progressive JPEG files.)
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+Arithmetic coding is not supported for legal reasons.
+.PP
+Not all variants of BMP and Targa file formats are supported.
+.PP
+The
+.B \-targa
+switch is not a bug, it's a feature. (It would be a bug if the Targa format
+designers had not been clueless.)
+.PP
+Still not as fast as we'd like.
diff --git a/gs/jpeg/cjpeg.c b/gs/jpeg/cjpeg.c
new file mode 100644
index 000000000..194d93bdd
--- /dev/null
+++ b/gs/jpeg/cjpeg.c
@@ -0,0 +1,606 @@
+/*
+ * cjpeg.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG compressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ * cjpeg [options] inputfile outputfile
+ * cjpeg [options] [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program. Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes. Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided. The syntax
+ * cjpeg [options] -outfile outputfile inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h" /* for version message */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string) string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+ NULL
+};
+
+
+/*
+ * This routine determines what format the input file is,
+ * and selects the appropriate input-reading module.
+ *
+ * To determine which family of input formats the file belongs to,
+ * we may look only at the first byte of the file, since C does not
+ * guarantee that more than one character can be pushed back with ungetc.
+ * Looking at additional bytes would require one of these approaches:
+ * 1) assume we can fseek() the input file (fails for piped input);
+ * 2) assume we can push back more than one character (works in
+ * some C implementations, but unportable);
+ * 3) provide our own buffering (breaks input readers that want to use
+ * stdio directly, such as the RLE library);
+ * or 4) don't put back the data, and modify the input_init methods to assume
+ * they start reading after the start of file (also breaks RLE library).
+ * #1 is attractive for MS-DOS but is untenable on Unix.
+ *
+ * The most portable solution for file types that can't be identified by their
+ * first byte is to make the user tell us what they are. This is also the
+ * only approach for "raw" file types that contain only arbitrary values.
+ * We presently apply this method for Targa files. Most of the time Targa
+ * files start with 0x00, so we recognize that case. Potentially, however,
+ * a Targa file could start with any byte value (byte 0 is the length of the
+ * seldom-used ID field), so we provide a switch to force Targa input mode.
+ */
+
+static boolean is_targa; /* records user -targa switch */
+
+
+LOCAL(cjpeg_source_ptr)
+select_file_type (j_compress_ptr cinfo, FILE * infile)
+{
+ int c;
+
+ if (is_targa) {
+#ifdef TARGA_SUPPORTED
+ return jinit_read_targa(cinfo);
+#else
+ ERREXIT(cinfo, JERR_TGA_NOTCOMP);
+#endif
+ }
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ if (ungetc(c, infile) == EOF)
+ ERREXIT(cinfo, JERR_UNGETC_FAILED);
+
+ switch (c) {
+#ifdef BMP_SUPPORTED
+ case 'B':
+ return jinit_read_bmp(cinfo);
+#endif
+#ifdef GIF_SUPPORTED
+ case 'G':
+ return jinit_read_gif(cinfo);
+#endif
+#ifdef PPM_SUPPORTED
+ case 'P':
+ return jinit_read_ppm(cinfo);
+#endif
+#ifdef RLE_SUPPORTED
+ case 'R':
+ return jinit_read_rle(cinfo);
+#endif
+#ifdef TARGA_SUPPORTED
+ case 0x00:
+ return jinit_read_targa(cinfo);
+#endif
+ default:
+ ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
+ break;
+ }
+
+ return NULL; /* suppress compiler warnings */
+}
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -quality N Compression quality (0..100; 5-95 is useful range)\n");
+ fprintf(stderr, " -grayscale Create monochrome JPEG file\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+ fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+ fprintf(stderr, " -progressive Create progressive JPEG file\n");
+#endif
+#ifdef TARGA_SUPPORTED
+ fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+#ifdef DCT_ISLOW_SUPPORTED
+ fprintf(stderr, " -dct int Use integer DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
+ (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+ fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n");
+#endif
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ fprintf(stderr, "Switches for wizards:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+ fprintf(stderr, " -arithmetic Use arithmetic coding\n");
+#endif
+ fprintf(stderr, " -baseline Force baseline output\n");
+ fprintf(stderr, " -qtables file Use quantization tables given in file\n");
+ fprintf(stderr, " -qslots N[,...] Set component quantization tables\n");
+ fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n");
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
+#endif
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+ int quality; /* -quality parameter */
+ int q_scale_factor; /* scaling percentage for -qtables */
+ boolean force_baseline;
+ boolean simple_progressive;
+ char * qtablefile = NULL; /* saves -qtables filename if any */
+ char * qslotsarg = NULL; /* saves -qslots parm if any */
+ char * samplearg = NULL; /* saves -sample parm if any */
+ char * scansarg = NULL; /* saves -scans parm if any */
+
+ /* Set up default JPEG parameters. */
+ /* Note that default -quality level need not, and does not,
+ * match the default scaling for an explicit -qtables argument.
+ */
+ quality = 75; /* default -quality value */
+ q_scale_factor = 100; /* default to no scaling for -qtables */
+ force_baseline = FALSE; /* by default, allow 16-bit quantizers */
+ simple_progressive = FALSE;
+ is_targa = FALSE;
+ outfilename = NULL;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "arithmetic", 1)) {
+ /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+ cinfo->arith_code = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "baseline", 1)) {
+ /* Force baseline output (8-bit quantizer values). */
+ force_baseline = TRUE;
+
+ } else if (keymatch(arg, "dct", 2)) {
+ /* Select DCT algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "int", 1)) {
+ cinfo->dct_method = JDCT_ISLOW;
+ } else if (keymatch(argv[argn], "fast", 2)) {
+ cinfo->dct_method = JDCT_IFAST;
+ } else if (keymatch(argv[argn], "float", 2)) {
+ cinfo->dct_method = JDCT_FLOAT;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+ /* Force a monochrome JPEG file to be generated. */
+ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+ /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+ cinfo->optimize_coding = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "progressive", 1)) {
+ /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+ simple_progressive = TRUE;
+ /* We must postpone execution until num_components is known. */
+#else
+ fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "quality", 1)) {
+ /* Quality factor (quantization table scaling factor). */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &quality) != 1)
+ usage();
+ /* Change scale factor in case -qtables is present. */
+ q_scale_factor = jpeg_quality_scaling(quality);
+
+ } else if (keymatch(arg, "qslots", 2)) {
+ /* Quantization table slot numbers. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ qslotsarg = argv[argn];
+ /* Must delay setting qslots until after we have processed any
+ * colorspace-determining switches, since jpeg_set_colorspace sets
+ * default quant table numbers.
+ */
+
+ } else if (keymatch(arg, "qtables", 2)) {
+ /* Quantization tables fetched from file. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ qtablefile = argv[argn];
+ /* We postpone actually reading the file in case -quality comes later. */
+
+ } else if (keymatch(arg, "restart", 1)) {
+ /* Restart interval in MCU rows (or in MCUs with 'b'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (lval < 0 || lval > 65535L)
+ usage();
+ if (ch == 'b' || ch == 'B') {
+ cinfo->restart_interval = (unsigned int) lval;
+ cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+ } else {
+ cinfo->restart_in_rows = (int) lval;
+ /* restart_interval will be computed during startup */
+ }
+
+ } else if (keymatch(arg, "sample", 2)) {
+ /* Set sampling factors. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ samplearg = argv[argn];
+ /* Must delay setting sample factors until after we have processed any
+ * colorspace-determining switches, since jpeg_set_colorspace sets
+ * default sampling factors.
+ */
+
+ } else if (keymatch(arg, "scans", 2)) {
+ /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scansarg = argv[argn];
+ /* We must postpone reading the file in case -progressive appears. */
+#else
+ fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "smooth", 2)) {
+ /* Set input smoothing factor. */
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+ if (val < 0 || val > 100)
+ usage();
+ cinfo->smoothing_factor = val;
+
+ } else if (keymatch(arg, "targa", 1)) {
+ /* Input file is Targa format. */
+ is_targa = TRUE;
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ /* Post-switch-scanning cleanup */
+
+ if (for_real) {
+
+ /* Set quantization tables for selected quality. */
+ /* Some or all may be overridden if -qtables is present. */
+ jpeg_set_quality(cinfo, quality, force_baseline);
+
+ if (qtablefile != NULL) /* process -qtables if it was present */
+ if (! read_quant_tables(cinfo, qtablefile,
+ q_scale_factor, force_baseline))
+ usage();
+
+ if (qslotsarg != NULL) /* process -qslots if it was present */
+ if (! set_quant_slots(cinfo, qslotsarg))
+ usage();
+
+ if (samplearg != NULL) /* process -sample if it was present */
+ if (! set_sample_factors(cinfo, samplearg))
+ usage();
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (simple_progressive) /* process -progressive; -scans can override */
+ jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (scansarg != NULL) /* process -scans if it was present */
+ if (! read_scan_script(cinfo, scansarg))
+ usage();
+#endif
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ int file_index;
+ cjpeg_source_ptr src_mgr;
+ FILE * input_file;
+ FILE * output_file;
+ JDIMENSION num_scanlines;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "cjpeg"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG compression object with default error handling. */
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ /* Add some application-specific error messages (from cderror.h) */
+ jerr.addon_message_table = cdjpeg_message_table;
+ jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+ jerr.last_addon_message = JMSG_LASTADDONCODE;
+
+ /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+ /* Initialize JPEG parameters.
+ * Much of this may be overridden later.
+ * In particular, we don't yet know the input file's color space,
+ * but we need to provide some value for jpeg_set_defaults() to work.
+ */
+
+ cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
+ jpeg_set_defaults(&cinfo);
+
+ /* Scan command line to find file names.
+ * It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are ignored; we will rescan the switches after opening
+ * the input file.
+ */
+
+ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ input_file = read_stdin();
+ }
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ output_file = write_stdout();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+ /* Figure out the input file format, and set up to read it. */
+ src_mgr = select_file_type(&cinfo, input_file);
+ src_mgr->input_file = input_file;
+
+ /* Read the input file header to obtain file size & colorspace. */
+ (*src_mgr->start_input) (&cinfo, src_mgr);
+
+ /* Now that we know input colorspace, fix colorspace-dependent defaults */
+ jpeg_default_colorspace(&cinfo);
+
+ /* Adjust default compression parameters by re-parsing the options */
+ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+ /* Specify data destination for compression */
+ jpeg_stdio_dest(&cinfo, output_file);
+
+ /* Start compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Process data */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+ (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
+ }
+
+ /* Finish compression and release memory */
+ (*src_mgr->finish_input) (&cinfo, src_mgr);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ /* Close files, if we opened them */
+ if (input_file != stdin)
+ fclose(input_file);
+ if (output_file != stdout)
+ fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+ /* All done. */
+ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/gs/jpeg/ckconfig.c b/gs/jpeg/ckconfig.c
new file mode 100644
index 000000000..34baf795b
--- /dev/null
+++ b/gs/jpeg/ckconfig.c
@@ -0,0 +1,402 @@
+/*
+ * ckconfig.c
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+/*
+ * This program is intended to help you determine how to configure the JPEG
+ * software for installation on a particular system. The idea is to try to
+ * compile and execute this program. If your compiler fails to compile the
+ * program, make changes as indicated in the comments below. Once you can
+ * compile the program, run it, and it will produce a "jconfig.h" file for
+ * your system.
+ *
+ * As a general rule, each time you try to compile this program,
+ * pay attention only to the *first* error message you get from the compiler.
+ * Many C compilers will issue lots of spurious error messages once they
+ * have gotten confused. Go to the line indicated in the first error message,
+ * and read the comments preceding that line to see what to change.
+ *
+ * Almost all of the edits you may need to make to this program consist of
+ * changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL",
+ * or vice versa. This is called defining or undefining that symbol.
+ */
+
+
+/* First we must see if your system has the include files we need.
+ * We start out with the assumption that your system has all the ANSI-standard
+ * include files. If you get any error trying to include one of these files,
+ * undefine the corresponding HAVE_xxx symbol.
+ */
+
+#define HAVE_STDDEF_H /* replace 'define' by 'undef' if error here */
+#ifdef HAVE_STDDEF_H /* next line will be skipped if you undef... */
+#include <stddef.h>
+#endif
+
+#define HAVE_STDLIB_H /* same thing for stdlib.h */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h> /* If you ain't got this, you ain't got C. */
+
+/* We have to see if your string functions are defined by
+ * strings.h (old BSD convention) or string.h (everybody else).
+ * We try the non-BSD convention first; define NEED_BSD_STRINGS
+ * if the compiler says it can't find string.h.
+ */
+
+#undef NEED_BSD_STRINGS
+
+#ifdef NEED_BSD_STRINGS
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+/* On some systems (especially older Unix machines), type size_t is
+ * defined only in the include file <sys/types.h>. If you get a failure
+ * on the size_t test below, try defining NEED_SYS_TYPES_H.
+ */
+
+#undef NEED_SYS_TYPES_H /* start by assuming we don't need it */
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+
+/* Usually type size_t is defined in one of the include files we've included
+ * above. If not, you'll get an error on the "typedef size_t my_size_t;" line.
+ * In that case, first try defining NEED_SYS_TYPES_H just above.
+ * If that doesn't work, you'll have to search through your system library
+ * to figure out which include file defines "size_t". Look for a line that
+ * says "typedef something-or-other size_t;". Then, change the line below
+ * that says "#include <someincludefile.h>" to instead include the file
+ * you found size_t in, and define NEED_SPECIAL_INCLUDE. If you can't find
+ * type size_t anywhere, try replacing "#include <someincludefile.h>" with
+ * "typedef unsigned int size_t;".
+ */
+
+#undef NEED_SPECIAL_INCLUDE /* assume we DON'T need it, for starters */
+
+#ifdef NEED_SPECIAL_INCLUDE
+#include <someincludefile.h>
+#endif
+
+typedef size_t my_size_t; /* The payoff: do we have size_t now? */
+
+
+/* The next question is whether your compiler supports ANSI-style function
+ * prototypes. You need to know this in order to choose between using
+ * makefile.ansi and using makefile.unix.
+ * The #define line below is set to assume you have ANSI function prototypes.
+ * If you get an error in this group of lines, undefine HAVE_PROTOTYPES.
+ */
+
+#define HAVE_PROTOTYPES
+
+#ifdef HAVE_PROTOTYPES
+int testfunction (int arg1, int * arg2); /* check prototypes */
+
+struct methods_struct { /* check method-pointer declarations */
+ int (*error_exit) (char *msgtext);
+ int (*trace_message) (char *msgtext);
+ int (*another_method) (void);
+};
+
+int testfunction (int arg1, int * arg2) /* check definitions */
+{
+ return arg2[arg1];
+}
+
+int test2function (void) /* check void arg list */
+{
+ return 0;
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned char" means.
+ * If you get an error on the "unsigned char un_char;" line,
+ * then undefine HAVE_UNSIGNED_CHAR.
+ */
+
+#define HAVE_UNSIGNED_CHAR
+
+#ifdef HAVE_UNSIGNED_CHAR
+unsigned char un_char;
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned short" means.
+ * If you get an error on the "unsigned short un_short;" line,
+ * then undefine HAVE_UNSIGNED_SHORT.
+ */
+
+#define HAVE_UNSIGNED_SHORT
+
+#ifdef HAVE_UNSIGNED_SHORT
+unsigned short un_short;
+#endif
+
+
+/* Now we want to find out if your compiler understands type "void".
+ * If you get an error anywhere in here, undefine HAVE_VOID.
+ */
+
+#define HAVE_VOID
+
+#ifdef HAVE_VOID
+/* Caution: a C++ compiler will insist on complete prototypes */
+typedef void * void_ptr; /* check void * */
+#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES /* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+ void_ptr arg1;
+ void_func arg2;
+#endif
+{
+ char * locptr = (char *) arg1; /* check casting to and from void * */
+ arg1 = (void *) locptr;
+ (*arg2) (1, 2); /* check call of fcn returning void */
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "const" means.
+ * If you get an error here, undefine HAVE_CONST.
+ */
+
+#define HAVE_CONST
+
+#ifdef HAVE_CONST
+static const int carray[3] = {1, 2, 3};
+
+#ifdef HAVE_PROTOTYPES
+int test4function (const int arg1)
+#else
+int test4function (arg1)
+ const int arg1;
+#endif
+{
+ return carray[arg1];
+}
+#endif
+
+
+/* If you get an error or warning about this structure definition,
+ * define INCOMPLETE_TYPES_BROKEN.
+ */
+
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifndef INCOMPLETE_TYPES_BROKEN
+typedef struct undefined_structure * undef_struct_ptr;
+#endif
+
+
+/* If you get an error about duplicate names,
+ * define NEED_SHORT_EXTERNAL_NAMES.
+ */
+
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+#ifndef NEED_SHORT_EXTERNAL_NAMES
+
+int possibly_duplicate_function ()
+{
+ return 0;
+}
+
+int possibly_dupli_function ()
+{
+ return 1;
+}
+
+#endif
+
+
+
+/************************************************************************
+ * OK, that's it. You should not have to change anything beyond this
+ * point in order to compile and execute this program. (You might get
+ * some warnings, but you can ignore them.)
+ * When you run the program, it will make a couple more tests that it
+ * can do automatically, and then it will create jconfig.h and print out
+ * any additional suggestions it has.
+ ************************************************************************
+ */
+
+
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+ int arg;
+#endif
+{
+ if (arg == 189) { /* expected result for unsigned char */
+ return 0; /* type char is unsigned */
+ }
+ else if (arg != -67) { /* expected result for signed char */
+ printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ }
+ return 1; /* assume char is signed otherwise */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+ long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+ long res = arg >> 4;
+
+ if (res == -0x7F7E80CL) { /* expected result for signed shift */
+ return 1; /* right shift is signed */
+ }
+ /* see if unsigned-shift hack will fix it. */
+ /* we can't just test exact value since it depends on width of long... */
+ res |= (~0L) << (32-4);
+ if (res == -0x7F7E80CL) { /* expected result now? */
+ return 0; /* right shift is unsigned */
+ }
+ printf("Right shift isn't acting as I expect it to.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ return 0; /* try it with unsigned anyway */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int main (int argc, char ** argv)
+#else
+int main (argc, argv)
+ int argc;
+ char ** argv;
+#endif
+{
+ char signed_char_check = (char) (-67);
+ FILE *outfile;
+
+ /* Attempt to write jconfig.h */
+ if ((outfile = fopen("jconfig.h", "w")) == NULL) {
+ printf("Failed to write jconfig.h\n");
+ return 1;
+ }
+
+ /* Write out all the info */
+ fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n");
+ fprintf(outfile, "/* see jconfig.doc for explanations */\n\n");
+#ifdef HAVE_PROTOTYPES
+ fprintf(outfile, "#define HAVE_PROTOTYPES\n");
+#else
+ fprintf(outfile, "#undef HAVE_PROTOTYPES\n");
+#endif
+#ifdef HAVE_UNSIGNED_CHAR
+ fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n");
+#else
+ fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n");
+#endif
+#ifdef HAVE_UNSIGNED_SHORT
+ fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n");
+#else
+ fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n");
+#endif
+#ifdef HAVE_VOID
+ fprintf(outfile, "/* #define void char */\n");
+#else
+ fprintf(outfile, "#define void char\n");
+#endif
+#ifdef HAVE_CONST
+ fprintf(outfile, "/* #define const */\n");
+#else
+ fprintf(outfile, "#define const\n");
+#endif
+ if (is_char_signed((int) signed_char_check))
+ fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n");
+ else
+ fprintf(outfile, "#define CHAR_IS_UNSIGNED\n");
+#ifdef HAVE_STDDEF_H
+ fprintf(outfile, "#define HAVE_STDDEF_H\n");
+#else
+ fprintf(outfile, "#undef HAVE_STDDEF_H\n");
+#endif
+#ifdef HAVE_STDLIB_H
+ fprintf(outfile, "#define HAVE_STDLIB_H\n");
+#else
+ fprintf(outfile, "#undef HAVE_STDLIB_H\n");
+#endif
+#ifdef NEED_BSD_STRINGS
+ fprintf(outfile, "#define NEED_BSD_STRINGS\n");
+#else
+ fprintf(outfile, "#undef NEED_BSD_STRINGS\n");
+#endif
+#ifdef NEED_SYS_TYPES_H
+ fprintf(outfile, "#define NEED_SYS_TYPES_H\n");
+#else
+ fprintf(outfile, "#undef NEED_SYS_TYPES_H\n");
+#endif
+ fprintf(outfile, "#undef NEED_FAR_POINTERS\n");
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+ fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n");
+#else
+ fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n");
+#endif
+#ifdef INCOMPLETE_TYPES_BROKEN
+ fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n");
+#else
+ fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n");
+#endif
+ fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n");
+ if (is_shifting_signed(-0x7F7E80B1L))
+ fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n");
+ else
+ fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n");
+ fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n");
+ fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n");
+ fprintf(outfile, "#define BMP_SUPPORTED /* BMP image file format */\n");
+ fprintf(outfile, "#define GIF_SUPPORTED /* GIF image file format */\n");
+ fprintf(outfile, "#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */\n");
+ fprintf(outfile, "#undef RLE_SUPPORTED /* Utah RLE image file format */\n");
+ fprintf(outfile, "#define TARGA_SUPPORTED /* Targa image file format */\n\n");
+ fprintf(outfile, "#undef TWO_FILE_COMMANDLINE /* You may need this on non-Unix systems */\n");
+ fprintf(outfile, "#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */\n");
+ fprintf(outfile, "#undef DONT_USE_B_MODE\n");
+ fprintf(outfile, "/* #define PROGRESS_REPORT */ /* optional */\n");
+ fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n");
+
+ /* Close the jconfig.h file */
+ fclose(outfile);
+
+ /* User report */
+ printf("Configuration check for Independent JPEG Group's software done.\n");
+ printf("\nI have written the jconfig.h file for you.\n\n");
+#ifdef HAVE_PROTOTYPES
+ printf("You should use makefile.ansi as the starting point for your Makefile.\n");
+#else
+ printf("You should use makefile.unix as the starting point for your Makefile.\n");
+#endif
+
+#ifdef NEED_SPECIAL_INCLUDE
+ printf("\nYou'll need to change jconfig.h to include the system include file\n");
+ printf("that you found type size_t in, or add a direct definition of type\n");
+ printf("size_t if that's what you used. Just add it to the end.\n");
+#endif
+
+ return 0;
+}
diff --git a/gs/jpeg/coderules.doc b/gs/jpeg/coderules.doc
new file mode 100644
index 000000000..0ab5d9bd3
--- /dev/null
+++ b/gs/jpeg/coderules.doc
@@ -0,0 +1,118 @@
+IJG JPEG LIBRARY: CODING RULES
+
+Copyright (C) 1991-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Since numerous people will be contributing code and bug fixes, it's important
+to establish a common coding style. The goal of using similar coding styles
+is much more important than the details of just what that style is.
+
+In general we follow the recommendations of "Recommended C Style and Coding
+Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and
+Brader). This document is available in the IJG FTP archive (see
+jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl).
+
+Block comments should be laid out thusly:
+
+/*
+ * Block comments in this style.
+ */
+
+We indent statements in K&R style, e.g.,
+ if (test) {
+ then-part;
+ } else {
+ else-part;
+ }
+with two spaces per indentation level. (This indentation convention is
+handled automatically by GNU Emacs and many other text editors.)
+
+Multi-word names should be written in lower case with underscores, e.g.,
+multi_word_name (not multiWordName). Preprocessor symbols and enum constants
+are similar but upper case (MULTI_WORD_NAME). Names should be unique within
+the first fifteen characters. (On some older systems, global names must be
+unique within six characters. We accommodate this without cluttering the
+source code by using macros to substitute shorter names.)
+
+We use function prototypes everywhere; we rely on automatic source code
+transformation to feed prototype-less C compilers. Transformation is done
+by the simple and portable tool 'ansi2knr.c' (courtesy of Ghostscript).
+ansi2knr is not very bright, so it imposes a format requirement on function
+declarations: the function name MUST BEGIN IN COLUMN 1. Thus all functions
+should be written in the following style:
+
+LOCAL(int *)
+function_name (int a, char *b)
+{
+ code...
+}
+
+Note that each function definition must begin with GLOBAL(type), LOCAL(type),
+or METHODDEF(type). These macros expand to "static type" or just "type" as
+appropriate. They provide a readable indication of the routine's usage and
+can readily be changed for special needs. (For instance, special linkage
+keywords can be inserted for use in Windows DLLs.)
+
+ansi2knr does not transform method declarations (function pointers in
+structs). We handle these with a macro JMETHOD, defined as
+ #ifdef HAVE_PROTOTYPES
+ #define JMETHOD(type,methodname,arglist) type (*methodname) arglist
+ #else
+ #define JMETHOD(type,methodname,arglist) type (*methodname) ()
+ #endif
+which is used like this:
+ struct function_pointers {
+ JMETHOD(void, init_entropy_encoder, (int somearg, jparms *jp));
+ JMETHOD(void, term_entropy_encoder, (void));
+ };
+Note the set of parentheses surrounding the parameter list.
+
+A similar solution is used for forward and external function declarations
+(see the EXTERN and JPP macros).
+
+If the code is to work on non-ANSI compilers, we cannot rely on a prototype
+declaration to coerce actual parameters into the right types. Therefore, use
+explicit casts on actual parameters whenever the actual parameter type is not
+identical to the formal parameter. Beware of implicit conversions to "int".
+
+It seems there are some non-ANSI compilers in which the sizeof() operator
+is defined to return int, yet size_t is defined as long. Needless to say,
+this is brain-damaged. Always use the SIZEOF() macro in place of sizeof(),
+so that the result is guaranteed to be of type size_t.
+
+
+The JPEG library is intended to be used within larger programs. Furthermore,
+we want it to be reentrant so that it can be used by applications that process
+multiple images concurrently. The following rules support these requirements:
+
+1. Avoid direct use of file I/O, "malloc", error report printouts, etc;
+pass these through the common routines provided.
+
+2. Minimize global namespace pollution. Functions should be declared static
+wherever possible. (Note that our method-based calling conventions help this
+a lot: in many modules only the initialization function will ever need to be
+called directly, so only that function need be externally visible.) All
+global function names should begin with "jpeg_", and should have an
+abbreviated name (unique in the first six characters) substituted by macro
+when NEED_SHORT_EXTERNAL_NAMES is set.
+
+3. Don't use global variables; anything that must be used in another module
+should be in the common data structures.
+
+4. Don't use static variables except for read-only constant tables. Variables
+that should be private to a module can be placed into private structures (see
+the system architecture document, structure.doc).
+
+5. Source file names should begin with "j" for files that are part of the
+library proper; source files that are not part of the library, such as cjpeg.c
+and djpeg.c, do not begin with "j". Keep source file names to eight
+characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers. Keep
+compression and decompression code in separate source files --- some
+applications may want only one half of the library.
+
+Note: these rules (particularly #4) are not followed religiously in the
+modules that are used in cjpeg/djpeg but are not part of the JPEG library
+proper. Those modules are not really intended to be used in other
+applications.
diff --git a/gs/jpeg/config.log b/gs/jpeg/config.log
new file mode 100644
index 000000000..5c53e215a
--- /dev/null
+++ b/gs/jpeg/config.log
@@ -0,0 +1,20 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+gcc -E
+gcc -o conftest -O conftest.c
+gcc -c -O conftest.c
+gcc -E
+gcc -E
+gcc -E
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -c -O conftest.c
+gcc -o conftest -O conftest.c
+gcc -o conftest -O conftest.c
+gcc -o conftest -O conftest.c
+gcc -o conftest -O conftest.c
diff --git a/gs/jpeg/config.status b/gs/jpeg/config.status
new file mode 100755
index 000000000..e3cbafc81
--- /dev/null
+++ b/gs/jpeg/config.status
@@ -0,0 +1,199 @@
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host meerkat.dimensional.com:
+#
+# ./configure
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion"
+ exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "./config.status generated by autoconf version 2.7"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "$ac_cs_usage"; exit 0 ;;
+ *) echo "$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=.
+
+trap 'rm -fr Makefile jconfig.h conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+/^[ ]*VPATH[ ]*=[^:]*$/d
+
+s%@CFLAGS@%-O%g
+s%@CPPFLAGS@%%g
+s%@CXXFLAGS@%%g
+s%@DEFS@%-DHAVE_CONFIG_H%g
+s%@LDFLAGS@%%g
+s%@LIBS@%%g
+s%@exec_prefix@%${prefix}%g
+s%@prefix@%/usr/local%g
+s%@program_transform_name@%s,x,x,%g
+s%@bindir@%${exec_prefix}/bin%g
+s%@sbindir@%${exec_prefix}/sbin%g
+s%@libexecdir@%${exec_prefix}/libexec%g
+s%@datadir@%${prefix}/share%g
+s%@sysconfdir@%${prefix}/etc%g
+s%@sharedstatedir@%${prefix}/com%g
+s%@localstatedir@%${prefix}/var%g
+s%@libdir@%${exec_prefix}/lib%g
+s%@includedir@%${prefix}/include%g
+s%@oldincludedir@%/usr/include%g
+s%@infodir@%${prefix}/info%g
+s%@mandir@%${prefix}/man%g
+s%@CC@%gcc%g
+s%@CPP@%gcc -E%g
+s%@INSTALL@%/usr/bin/install -c%g
+s%@INSTALL_PROGRAM@%${INSTALL}%g
+s%@INSTALL_DATA@%${INSTALL} -m 644%g
+s%@RANLIB@%ranlib%g
+s%@MEMORYMGR@%jmemnobs.o%g
+s%@ANSI2KNR@%%g
+s%@ISANSICOM@%# %g
+s%@ANSI2KNRFLAGS@%%g
+s%@INCLUDEFLAGS@%-I$(srcdir)%g
+
+CEOF
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile:makefile.cfg"}
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"jconfig.h:jconfig.cfg"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ cp $ac_given_srcdir/$ac_file_in conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_PROTOTYPES${ac_dB}HAVE_PROTOTYPES${ac_dC}${ac_dD}
+${ac_uA}HAVE_PROTOTYPES${ac_uB}HAVE_PROTOTYPES${ac_uC}${ac_uD}
+${ac_eA}HAVE_PROTOTYPES${ac_eB}HAVE_PROTOTYPES${ac_eC}${ac_eD}
+${ac_dA}HAVE_STDDEF_H${ac_dB}HAVE_STDDEF_H${ac_dC}${ac_dD}
+${ac_uA}HAVE_STDDEF_H${ac_uB}HAVE_STDDEF_H${ac_uC}${ac_uD}
+${ac_eA}HAVE_STDDEF_H${ac_eB}HAVE_STDDEF_H${ac_eC}${ac_eD}
+${ac_dA}HAVE_STDLIB_H${ac_dB}HAVE_STDLIB_H${ac_dC}${ac_dD}
+${ac_uA}HAVE_STDLIB_H${ac_uB}HAVE_STDLIB_H${ac_uC}${ac_uD}
+${ac_eA}HAVE_STDLIB_H${ac_eB}HAVE_STDLIB_H${ac_eC}${ac_eD}
+${ac_dA}HAVE_UNSIGNED_CHAR${ac_dB}HAVE_UNSIGNED_CHAR${ac_dC}${ac_dD}
+${ac_uA}HAVE_UNSIGNED_CHAR${ac_uB}HAVE_UNSIGNED_CHAR${ac_uC}${ac_uD}
+${ac_eA}HAVE_UNSIGNED_CHAR${ac_eB}HAVE_UNSIGNED_CHAR${ac_eC}${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_UNSIGNED_SHORT${ac_dB}HAVE_UNSIGNED_SHORT${ac_dC}${ac_dD}
+${ac_uA}HAVE_UNSIGNED_SHORT${ac_uB}HAVE_UNSIGNED_SHORT${ac_uC}${ac_uD}
+${ac_eA}HAVE_UNSIGNED_SHORT${ac_eB}HAVE_UNSIGNED_SHORT${ac_eC}${ac_eD}
+${ac_dA}INLINE${ac_dB}INLINE${ac_dC}inline${ac_dD}
+${ac_uA}INLINE${ac_uB}INLINE${ac_uC}inline${ac_uD}
+${ac_eA}INLINE${ac_eB}INLINE${ac_eC}inline${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+
+
+exit 0
diff --git a/gs/jpeg/configure b/gs/jpeg/configure
new file mode 100755
index 000000000..146c43a49
--- /dev/null
+++ b/gs/jpeg/configure
@@ -0,0 +1,1731 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.7
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-maxmem[=N] enable use of temp files, set max mem usage to N MB"
+ac_help="$ac_help
+"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.7"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *=*)
+ varname=`echo "$ac_option"|sed -e 's/=.*//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $varname| sed 's/[a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $varname: invalid shell variable name" 1>&2; exit 1; }
+ fi
+ val="`echo "$ac_option"|sed 's/[^=]*=//'`"
+ test -n "$verbose" && echo " setting shell variable $varname to $val"
+ eval "$varname='$val'"
+ eval "export $varname" ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=jcmaster.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='echo $CPP $CPPFLAGS 1>&5;
+$CPP $CPPFLAGS'
+ac_compile='echo ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5;
+${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5'
+ac_link='echo ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5;
+${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -O""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_cc_o'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'int f(){ return 0; }' > conftest.c
+if test -z "`${CC-cc} -O -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_o=yes
+else
+ ac_cv_prog_cc_o=no
+fi
+rm -f conftest*
+
+fi
+ echo "$ac_t""$ac_cv_prog_cc_o" 1>&6
+ if test $ac_cv_prog_cc_o = yes; then
+ CFLAGS="-O"
+ else
+ CFLAGS=""
+ fi
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 615 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 629 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 663 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_cross=no
+else
+ ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_cross" 1>&6
+cross_compiling=$ac_cv_c_cross
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ijg_cv_have_prototypes'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 685 "configure"
+#include "confdefs.h"
+
+int testfunction (int arg1, int * arg2); /* check prototypes */
+struct methods_struct { /* check method-pointer declarations */
+ int (*error_exit) (char *msgtext);
+ int (*trace_message) (char *msgtext);
+ int (*another_method) (void);
+};
+int testfunction (int arg1, int * arg2) /* check definitions */
+{ return arg2[arg1]; }
+int test2function (void) /* check void arg list */
+{ return 0; }
+
+int main() { return 0; }
+int t() {
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ijg_cv_have_prototypes=yes
+else
+ rm -rf conftest*
+ ijg_cv_have_prototypes=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ijg_cv_have_prototypes" 1>&6
+if test $ijg_cv_have_prototypes = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PROTOTYPES
+EOF
+
+else
+ echo Your compiler does not seem to know about function prototypes.
+ echo Perhaps it needs a special switch to enable ANSI C mode.
+ echo If so, we recommend running configure like this:
+ echo " ./configure CC='cc -switch'"
+ echo where -switch is the proper switch.
+fi
+ac_safe=`echo "stddef.h" | tr './\055' '___'`
+echo $ac_n "checking for stddef.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 733 "configure"
+#include "confdefs.h"
+#include <stddef.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_STDDEF_H
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_safe=`echo "stdlib.h" | tr './\055' '___'`
+echo $ac_n "checking for stdlib.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 765 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_STDLIB_H
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_safe=`echo "string.h" | tr './\055' '___'`
+echo $ac_n "checking for string.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 797 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define NEED_BSD_STRINGS
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 826 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#ifdef NEED_BSD_STRINGS
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+typedef size_t my_size_t;
+
+int main() { return 0; }
+int t() {
+ my_size_t foovar;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ijg_size_t_ok=yes
+else
+ rm -rf conftest*
+ ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h"
+fi
+rm -f conftest*
+
+echo "$ac_t""$ijg_size_t_ok" 1>&6
+if test "$ijg_size_t_ok" != yes; then
+ac_safe=`echo "sys/types.h" | tr './\055' '___'`
+echo $ac_n "checking for sys/types.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 865 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define NEED_SYS_TYPES_H
+EOF
+
+cat > conftest.$ac_ext <<EOF
+#line 888 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "size_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ijg_size_t_ok="size_t is in sys/types.h"
+else
+ rm -rf conftest*
+ ijg_size_t_ok=no
+fi
+rm -f conftest*
+
+else
+ echo "$ac_t""no" 1>&6
+ijg_size_t_ok=no
+fi
+
+echo "$ac_t""$ijg_size_t_ok" 1>&6
+if test "$ijg_size_t_ok" = no; then
+ echo Type size_t is not defined in any of the usual places.
+ echo Try putting '"typedef unsigned int size_t;"' in jconfig.h.
+fi
+fi
+echo $ac_n "checking for type unsigned char""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 915 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+ unsigned char un_char;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6
+cat >> confdefs.h <<\EOF
+#define HAVE_UNSIGNED_CHAR
+EOF
+
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+echo $ac_n "checking for type unsigned short""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 937 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+ unsigned short un_short;
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6
+cat >> confdefs.h <<\EOF
+#define HAVE_UNSIGNED_SHORT
+EOF
+
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+echo $ac_n "checking for type void""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 959 "configure"
+#include "confdefs.h"
+
+/* Caution: a C++ compiler will insist on valid prototypes */
+typedef void * void_ptr; /* check void * */
+#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES /* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+ void_ptr arg1;
+ void_func arg2;
+#endif
+{
+ char * locptr = (char *) arg1; /* check casting to and from void * */
+ arg1 = (void *) locptr;
+ (*arg2) (1, 2); /* check call of fcn returning void */
+}
+
+int main() { return 0; }
+int t() {
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define void char
+EOF
+
+fi
+rm -f conftest*
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1005 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+ijg_cv_inline=""
+cat > conftest.$ac_ext <<EOF
+#line 1077 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+} inline int foo() { return 0; }
+int bar() { return foo();
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ijg_cv_inline="inline"
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 1092 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+} __inline__ int foo() { return 0; }
+int bar() { return foo();
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ijg_cv_inline="__inline__"
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 1107 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+} __inline int foo() { return 0; }
+int bar() { return foo();
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ijg_cv_inline="__inline"
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+echo "$ac_t""$ijg_cv_inline" 1>&6
+cat >> confdefs.h <<EOF
+#define INLINE $ijg_cv_inline
+EOF
+echo $ac_n "checking for broken incomplete types""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 1133 "configure"
+#include "confdefs.h"
+ typedef struct undefined_structure * undef_struct_ptr;
+int main() { return 0; }
+int t() {
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ echo "$ac_t""ok" 1>&6
+else
+ rm -rf conftest*
+ echo "$ac_t""broken" 1>&6
+cat >> confdefs.h <<\EOF
+#define INCOMPLETE_TYPES_BROKEN
+EOF
+
+fi
+rm -f conftest*
+echo $ac_n "checking for short external names""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 1155 "configure"
+#include "confdefs.h"
+
+int possibly_duplicate_function () { return 0; }
+int possibly_dupli_function () { return 1; }
+
+int main() { return 0; }
+int t() {
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ echo "$ac_t""ok" 1>&6
+else
+ rm -rf conftest*
+ echo "$ac_t""short" 1>&6
+cat >> confdefs.h <<\EOF
+#define NEED_SHORT_EXTERNAL_NAMES
+EOF
+
+fi
+rm -f conftest*
+
+echo $ac_n "checking to see if char is signed""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+ echo Assuming that char is signed on target machine.
+echo If it is unsigned, this will be a little bit inefficient.
+
+else
+cat > conftest.$ac_ext <<EOF
+#line 1186 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+ int arg;
+#endif
+{
+ if (arg == 189) { /* expected result for unsigned char */
+ return 0; /* type char is unsigned */
+ }
+ else if (arg != -67) { /* expected result for signed char */
+ printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ }
+ return 1; /* assume char is signed otherwise */
+}
+char signed_char_check = (char) (-67);
+main() {
+ exit(is_char_signed((int) signed_char_check));
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define CHAR_IS_UNSIGNED
+EOF
+
+else
+ echo "$ac_t""yes" 1>&6
+fi
+fi
+rm -fr conftest*
+echo $ac_n "checking to see if right shift is signed""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+ echo "$ac_t""Assuming that right shift is signed on target machine." 1>&6
+else
+cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+ long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+ long res = arg >> 4;
+
+ if (res == -0x7F7E80CL) { /* expected result for signed shift */
+ return 1; /* right shift is signed */
+ }
+ /* see if unsigned-shift hack will fix it. */
+ /* we can't just test exact value since it depends on width of long... */
+ res |= (~0L) << (32-4);
+ if (res == -0x7F7E80CL) { /* expected result now? */
+ return 0; /* right shift is unsigned */
+ }
+ printf("Right shift isn't acting as I expect it to.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ return 0; /* try it with unsigned anyway */
+}
+main() {
+ exit(is_shifting_signed(-0x7F7E80B1L));
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define RIGHT_SHIFT_IS_UNSIGNED
+EOF
+
+else
+ echo "$ac_t""yes" 1>&6
+fi
+fi
+rm -fr conftest*
+echo $ac_n "checking to see if fopen accepts b spec""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+ echo "$ac_t""Assuming that it does." 1>&6
+else
+cat > conftest.$ac_ext <<EOF
+#line 1274 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+main() {
+ if (fopen("conftestdata", "wb") != NULL)
+ exit(0);
+ exit(1);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define DONT_USE_B_MODE
+EOF
+
+fi
+fi
+rm -fr conftest*
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ijg_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ijg_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ # As a last resort, use cp
+ test -z "$ijg_cv_path_install" && ijg_cv_path_install="cp"
+fi
+ INSTALL="$ijg_cv_path_install"
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+if test -z "$INSTALL_DATA"; then
+ if test "$INSTALL" = cp; then
+ INSTALL_DATA='${INSTALL}'
+ else
+ INSTALL_DATA='${INSTALL} -m 644'
+ fi
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+MEMORYMGR="jmemnobs.o"
+MAXMEM="no"
+# Check whether --enable-maxmem or --disable-maxmem was given.
+if test "${enable_maxmem+set}" = set; then
+ enableval="$enable_maxmem"
+ MAXMEM="$enableval"
+fi
+
+# support --with-maxmem for backwards compatibility with IJG V5.
+# Check whether --with-maxmem or --without-maxmem was given.
+if test "${with_maxmem+set}" = set; then
+ withval="$with_maxmem"
+ MAXMEM="$withval"
+fi
+
+if test "x$MAXMEM" = xyes; then
+ MAXMEM=1
+fi
+if test "x$MAXMEM" != xno; then
+ if test -n "`echo $MAXMEM | sed 's/[0-9]//g'`"; then
+ { echo "configure: error: non-numeric argument to --enable-maxmem" 1>&2; exit 1; }
+ fi
+ DEFAULTMAXMEM=`expr $MAXMEM \* 1048576`
+cat >> confdefs.h <<EOF
+#define DEFAULT_MAX_MEM ${DEFAULTMAXMEM}
+EOF
+
+echo $ac_n "checking for 'tmpfile()'""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 1412 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() { return 0; }
+int t() {
+ FILE * tfile = tmpfile();
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6
+MEMORYMGR="jmemansi.o"
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+MEMORYMGR="jmemname.o"
+cat >> confdefs.h <<\EOF
+#define NEED_SIGNAL_CATCHER
+EOF
+echo $ac_n "checking for 'mktemp()'""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 1433 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+ char fname[80]; mktemp(fname);
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define NO_MKTEMP
+EOF
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+
+# Prepare to massage makefile.cfg correctly.
+if test $ijg_cv_have_prototypes = yes; then
+ ANSI2KNR=""
+ ISANSICOM="# "
+else
+ ANSI2KNR="ansi2knr"
+ ISANSICOM=""
+fi
+# ansi2knr needs -DBSD if string.h is missing
+if test $ac_cv_header_string_h = no; then
+ ANSI2KNRFLAGS="-DBSD"
+else
+ ANSI2KNRFLAGS=""
+fi
+# Set up -I directives
+if test "x$srcdir" = x.; then
+ INCLUDEFLAGS='-I$(srcdir)'
+else
+ INCLUDEFLAGS='-I. -I$(srcdir)'
+fi
+trap '' 1 2 15
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.7"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile:makefile.cfg jconfig.h:jconfig.cfg" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@MEMORYMGR@%$MEMORYMGR%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ISANSICOM@%$ISANSICOM%g
+s%@ANSI2KNRFLAGS@%$ANSI2KNRFLAGS%g
+s%@INCLUDEFLAGS@%$INCLUDEFLAGS%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile:makefile.cfg"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"jconfig.h:jconfig.cfg"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ cp $ac_given_srcdir/$ac_file_in conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+# Maximum number of lines to put in a single here document.
+ac_max_here_lines=12
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/gs/jpeg/djpeg b/gs/jpeg/djpeg
new file mode 100755
index 000000000..9eb99bbb3
--- /dev/null
+++ b/gs/jpeg/djpeg
Binary files differ
diff --git a/gs/jpeg/djpeg.1 b/gs/jpeg/djpeg.1
new file mode 100644
index 000000000..8efa5cd86
--- /dev/null
+++ b/gs/jpeg/djpeg.1
@@ -0,0 +1,248 @@
+.TH DJPEG 1 "15 June 1995"
+.SH NAME
+djpeg \- decompress a JPEG file to an image file
+.SH SYNOPSIS
+.B djpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B djpeg
+decompresses the named JPEG file, or the standard input if no file is named,
+and produces an image file on the standard output. PBMPLUS (PPM/PGM), BMP,
+GIF, Targa, or RLE (Utah Raster Toolkit) output format can be selected.
+(RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-GIF
+is the same as
+.BR \-gif ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-colors " N"
+Reduce image to at most N colors. This reduces the number of colors used in
+the output image, so that it can be displayed on a colormapped display or
+stored in a colormapped file format. For example, if you have an 8-bit
+display, you'd need to reduce to 256 or fewer colors.
+.TP
+.BI \-quantize " N"
+Same as
+.BR \-colors .
+.B \-colors
+is the recommended name,
+.B \-quantize
+is provided only for backwards compatibility.
+.TP
+.B \-fast
+Select recommended processing options for fast, low quality output. (The
+default options are chosen for highest quality output.) Currently, this is
+equivalent to \fB\-dct fast \-nosmooth \-onepass \-dither ordered\fR.
+.TP
+.B \-grayscale
+Force gray-scale output even if JPEG file is color. Useful for viewing on
+monochrome displays; also,
+.B djpeg
+runs noticeably faster in this mode.
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N. Currently the scale factor must be
+1/1, 1/2, 1/4, or 1/8. Scaling is handy if the image is larger than your
+screen; also,
+.B djpeg
+runs much faster when scaling down the output.
+.TP
+.B \-bmp
+Select BMP output format (Windows flavor). 8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-gif
+Select GIF output format. Since GIF does not support more than 256 colors,
+.B \-colors 256
+is assumed (unless you specify a smaller number of colors).
+.TP
+.B \-os2
+Select BMP output format (OS/2 1.x flavor). 8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-pnm
+Select PBMPLUS (PPM/PGM) output format (this is the default format).
+PGM is emitted if the JPEG file is gray-scale or if
+.B \-grayscale
+is specified; otherwise PPM is emitted.
+.TP
+.B \-rle
+Select RLE output format. (Requires URT library.)
+.TP
+.B \-targa
+Select Targa output format. Gray-scale format is emitted if the JPEG file is
+gray-scale or if
+.B \-grayscale
+is specified; otherwise, colormapped format is emitted if
+.B \-colors
+is specified; otherwise, 24-bit full-color format is emitted.
+.PP
+Switches for advanced users:
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware. Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.B \-dither fs
+Use Floyd-Steinberg dithering in color quantization.
+.TP
+.B \-dither ordered
+Use ordered dithering in color quantization.
+.TP
+.B \-dither none
+Do not use dithering in color quantization.
+By default, Floyd-Steinberg dithering is applied when quantizing colors; this
+is slow but usually produces the best results. Ordered dither is a compromise
+between speed and quality; no dithering is fast but usually looks awful. Note
+that these switches have no effect unless color quantization is being done.
+Ordered dither is only available in
+.B \-onepass
+mode.
+.TP
+.BI \-map " file"
+Quantize to the colors used in the specified image file. This is useful for
+producing multiple files with identical color maps, or for forcing a
+predefined set of colors to be used. The
+.I file
+must be a GIF or PPM file. This option overrides
+.B \-colors
+and
+.BR \-onepass .
+.TP
+.B \-nosmooth
+Use a faster, lower-quality upsampling routine.
+.TP
+.B \-onepass
+Use one-pass instead of two-pass color quantization. The one-pass method is
+faster and needs less memory, but it produces a lower-quality image.
+.B \-onepass
+is ignored unless you also say
+.B \-colors
+.IR N .
+Also, the one-pass method is always used for gray-scale output (the two-pass
+method is no improvement then).
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.SH EXAMPLES
+.LP
+This example decompresses the JPEG file foo.jpg, automatically quantizes to
+256 colors, and saves the output in GIF format in foo.gif:
+.IP
+.B djpeg \-gif
+.I foo.jpg
+.B >
+.I foo.gif
+.SH HINTS
+To get a quick preview of an image, use the
+.B \-grayscale
+and/or
+.B \-scale
+switches.
+.B \-grayscale \-scale 1/8
+is the fastest case.
+.PP
+Several options are available that trade off image quality to gain speed.
+.B \-fast
+turns on the recommended settings.
+.PP
+.B \-dct fast
+and/or
+.B \-nosmooth
+gain speed at a small sacrifice in quality.
+When producing a color-quantized image,
+.B \-onepass \-dither ordered
+is fast but much lower quality than the default behavior.
+.B \-dither none
+may give acceptable results in two-pass mode, but is seldom tolerable in
+one-pass mode.
+.PP
+If you are fortunate enough to have very fast floating point hardware,
+\fB\-dct float\fR may be even faster than \fB\-dct fast\fR. But on most
+machines \fB\-dct float\fR is slower than \fB\-dct int\fR; in this case it is
+not worth using, because its theoretical accuracy advantage is too small to be
+significant in practice.
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+Arithmetic coding is not supported for legal reasons.
+.PP
+Still not as fast as we'd like.
diff --git a/gs/jpeg/djpeg.c b/gs/jpeg/djpeg.c
new file mode 100644
index 000000000..546599404
--- /dev/null
+++ b/gs/jpeg/djpeg.c
@@ -0,0 +1,604 @@
+/*
+ * djpeg.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG decompressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ * djpeg [options] inputfile outputfile
+ * djpeg [options] [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program. Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes. Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided. The syntax
+ * djpeg [options] -outfile outputfile inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h" /* for version message */
+
+#include <ctype.h> /* to declare isprint() */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string) string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+ NULL
+};
+
+
+/*
+ * This list defines the known output image formats
+ * (not all of which need be supported by a given version).
+ * You can change the default output format by defining DEFAULT_FMT;
+ * indeed, you had better do so if you undefine PPM_SUPPORTED.
+ */
+
+typedef enum {
+ FMT_BMP, /* BMP format (Windows flavor) */
+ FMT_GIF, /* GIF format */
+ FMT_OS2, /* BMP format (OS/2 flavor) */
+ FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
+ FMT_RLE, /* RLE format */
+ FMT_TARGA, /* Targa format */
+ FMT_TIFF /* TIFF format */
+} IMAGE_FORMATS;
+
+#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */
+#define DEFAULT_FMT FMT_PPM
+#endif
+
+static IMAGE_FORMATS requested_fmt;
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
+ fprintf(stderr, " -fast Fast, low-quality processing\n");
+ fprintf(stderr, " -grayscale Force grayscale output\n");
+#ifdef IDCT_SCALING_SUPPORTED
+ fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
+#endif
+#ifdef BMP_SUPPORTED
+ fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n",
+ (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
+#endif
+#ifdef GIF_SUPPORTED
+ fprintf(stderr, " -gif Select GIF output format%s\n",
+ (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
+#endif
+#ifdef BMP_SUPPORTED
+ fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
+ (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
+#endif
+#ifdef PPM_SUPPORTED
+ fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n",
+ (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
+#endif
+#ifdef RLE_SUPPORTED
+ fprintf(stderr, " -rle Select Utah RLE output format%s\n",
+ (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
+#endif
+#ifdef TARGA_SUPPORTED
+ fprintf(stderr, " -targa Select Targa output format%s\n",
+ (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+#ifdef DCT_ISLOW_SUPPORTED
+ fprintf(stderr, " -dct int Use integer DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
+ (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+ fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
+ fprintf(stderr, " -dither none Don't use dithering in quantization\n");
+ fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
+#ifdef QUANT_2PASS_SUPPORTED
+ fprintf(stderr, " -map FILE Map to colors used in named image file\n");
+#endif
+ fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
+#ifdef QUANT_1PASS_SUPPORTED
+ fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
+#endif
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+
+ /* Set up default JPEG parameters. */
+ requested_fmt = DEFAULT_FMT; /* set default output file format */
+ outfilename = NULL;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "bmp", 1)) {
+ /* BMP output format. */
+ requested_fmt = FMT_BMP;
+
+ } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
+ keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
+ /* Do color quantization. */
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+ cinfo->desired_number_of_colors = val;
+ cinfo->quantize_colors = TRUE;
+
+ } else if (keymatch(arg, "dct", 2)) {
+ /* Select IDCT algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "int", 1)) {
+ cinfo->dct_method = JDCT_ISLOW;
+ } else if (keymatch(argv[argn], "fast", 2)) {
+ cinfo->dct_method = JDCT_IFAST;
+ } else if (keymatch(argv[argn], "float", 2)) {
+ cinfo->dct_method = JDCT_FLOAT;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "dither", 2)) {
+ /* Select dithering algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "fs", 2)) {
+ cinfo->dither_mode = JDITHER_FS;
+ } else if (keymatch(argv[argn], "none", 2)) {
+ cinfo->dither_mode = JDITHER_NONE;
+ } else if (keymatch(argv[argn], "ordered", 2)) {
+ cinfo->dither_mode = JDITHER_ORDERED;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "fast", 1)) {
+ /* Select recommended processing options for quick-and-dirty output. */
+ cinfo->two_pass_quantize = FALSE;
+ cinfo->dither_mode = JDITHER_ORDERED;
+ if (! cinfo->quantize_colors) /* don't override an earlier -colors */
+ cinfo->desired_number_of_colors = 216;
+ cinfo->dct_method = JDCT_FASTEST;
+ cinfo->do_fancy_upsampling = FALSE;
+
+ } else if (keymatch(arg, "gif", 1)) {
+ /* GIF output format. */
+ requested_fmt = FMT_GIF;
+
+ } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+ /* Force monochrome output. */
+ cinfo->out_color_space = JCS_GRAYSCALE;
+
+ } else if (keymatch(arg, "map", 3)) {
+ /* Quantize to a color map taken from an input file. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (for_real) { /* too expensive to do twice! */
+#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
+ FILE * mapfile;
+
+ if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ read_color_map(cinfo, mapfile);
+ fclose(mapfile);
+ cinfo->quantize_colors = TRUE;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "nosmooth", 3)) {
+ /* Suppress fancy upsampling */
+ cinfo->do_fancy_upsampling = FALSE;
+
+ } else if (keymatch(arg, "onepass", 3)) {
+ /* Use fast one-pass quantization. */
+ cinfo->two_pass_quantize = FALSE;
+
+ } else if (keymatch(arg, "os2", 3)) {
+ /* BMP output format (OS/2 flavor). */
+ requested_fmt = FMT_OS2;
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
+ /* PPM/PGM output format. */
+ requested_fmt = FMT_PPM;
+
+ } else if (keymatch(arg, "rle", 1)) {
+ /* RLE output format. */
+ requested_fmt = FMT_RLE;
+
+ } else if (keymatch(arg, "scale", 1)) {
+ /* Scale the output image by a fraction M/N. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d/%d",
+ &cinfo->scale_num, &cinfo->scale_denom) != 2)
+ usage();
+
+ } else if (keymatch(arg, "targa", 1)) {
+ /* Targa output format. */
+ requested_fmt = FMT_TARGA;
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * Marker processor for COM markers.
+ * This replaces the library's built-in processor, which just skips the marker.
+ * We want to print out the marker as text, if possible.
+ * Note this code relies on a non-suspending data source.
+ */
+
+LOCAL(unsigned int)
+jpeg_getc (j_decompress_ptr cinfo)
+/* Read next byte */
+{
+ struct jpeg_source_mgr * datasrc = cinfo->src;
+
+ if (datasrc->bytes_in_buffer == 0) {
+ if (! (*datasrc->fill_input_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+ datasrc->bytes_in_buffer--;
+ return GETJOCTET(*datasrc->next_input_byte++);
+}
+
+
+METHODDEF(boolean)
+COM_handler (j_decompress_ptr cinfo)
+{
+ boolean traceit = (cinfo->err->trace_level >= 1);
+ INT32 length;
+ unsigned int ch;
+ unsigned int lastch = 0;
+
+ length = jpeg_getc(cinfo) << 8;
+ length += jpeg_getc(cinfo);
+ length -= 2; /* discount the length word itself */
+
+ if (traceit)
+ fprintf(stderr, "Comment, length %ld:\n", (long) length);
+
+ while (--length >= 0) {
+ ch = jpeg_getc(cinfo);
+ if (traceit) {
+ /* Emit the character in a readable form.
+ * Nonprintables are converted to \nnn form,
+ * while \ is converted to \\.
+ * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+ */
+ if (ch == '\r') {
+ fprintf(stderr, "\n");
+ } else if (ch == '\n') {
+ if (lastch != '\r')
+ fprintf(stderr, "\n");
+ } else if (ch == '\\') {
+ fprintf(stderr, "\\\\");
+ } else if (isprint(ch)) {
+ putc(ch, stderr);
+ } else {
+ fprintf(stderr, "\\%03o", ch);
+ }
+ lastch = ch;
+ }
+ }
+
+ if (traceit)
+ fprintf(stderr, "\n");
+
+ return TRUE;
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ int file_index;
+ djpeg_dest_ptr dest_mgr = NULL;
+ FILE * input_file;
+ FILE * output_file;
+ JDIMENSION num_scanlines;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "djpeg"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG decompression object with default error handling. */
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ /* Add some application-specific error messages (from cderror.h) */
+ jerr.addon_message_table = cdjpeg_message_table;
+ jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+ jerr.last_addon_message = JMSG_LASTADDONCODE;
+ /* Insert custom COM marker processor. */
+ jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler);
+
+ /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+ /* Scan command line to find file names. */
+ /* It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are ignored; we will rescan the switches after opening
+ * the input file.
+ * (Exception: tracing level set here controls verbosity for COM markers
+ * found during jpeg_read_header...)
+ */
+
+ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ input_file = read_stdin();
+ }
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ output_file = write_stdout();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+ /* Specify data source for decompression */
+ jpeg_stdio_src(&cinfo, input_file);
+
+ /* Read file header, set default decompression parameters */
+ (void) jpeg_read_header(&cinfo, TRUE);
+
+ /* Adjust default decompression parameters by re-parsing the options */
+ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+ /* Initialize the output module now to let it override any crucial
+ * option settings (for instance, GIF wants to force color quantization).
+ */
+ switch (requested_fmt) {
+#ifdef BMP_SUPPORTED
+ case FMT_BMP:
+ dest_mgr = jinit_write_bmp(&cinfo, FALSE);
+ break;
+ case FMT_OS2:
+ dest_mgr = jinit_write_bmp(&cinfo, TRUE);
+ break;
+#endif
+#ifdef GIF_SUPPORTED
+ case FMT_GIF:
+ dest_mgr = jinit_write_gif(&cinfo);
+ break;
+#endif
+#ifdef PPM_SUPPORTED
+ case FMT_PPM:
+ dest_mgr = jinit_write_ppm(&cinfo);
+ break;
+#endif
+#ifdef RLE_SUPPORTED
+ case FMT_RLE:
+ dest_mgr = jinit_write_rle(&cinfo);
+ break;
+#endif
+#ifdef TARGA_SUPPORTED
+ case FMT_TARGA:
+ dest_mgr = jinit_write_targa(&cinfo);
+ break;
+#endif
+ default:
+ ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
+ break;
+ }
+ dest_mgr->output_file = output_file;
+
+ /* Start decompressor */
+ (void) jpeg_start_decompress(&cinfo);
+
+ /* Write output file header */
+ (*dest_mgr->start_output) (&cinfo, dest_mgr);
+
+ /* Process data */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+
+#ifdef PROGRESS_REPORT
+ /* Hack: count final pass as done in case finish_output does an extra pass.
+ * The library won't have updated completed_passes.
+ */
+ progress.pub.completed_passes = progress.pub.total_passes;
+#endif
+
+ /* Finish decompression and release memory.
+ * I must do it in this order because output module has allocated memory
+ * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
+ */
+ (*dest_mgr->finish_output) (&cinfo, dest_mgr);
+ (void) jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ /* Close files, if we opened them */
+ if (input_file != stdin)
+ fclose(input_file);
+ if (output_file != stdout)
+ fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+ /* All done. */
+ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/gs/jpeg/example.c b/gs/jpeg/example.c
new file mode 100644
index 000000000..7fc354f04
--- /dev/null
+++ b/gs/jpeg/example.c
@@ -0,0 +1,433 @@
+/*
+ * example.c
+ *
+ * This file illustrates how to use the IJG code as a subroutine library
+ * to read or write JPEG image files. You should look at this code in
+ * conjunction with the documentation file libjpeg.doc.
+ *
+ * This code will not do anything useful as-is, but it may be helpful as a
+ * skeleton for constructing routines that call the JPEG library.
+ *
+ * We present these routines in the same coding style used in the JPEG code
+ * (ANSI function definitions, etc); but you are of course free to code your
+ * routines in a different style if you prefer.
+ */
+
+#include <stdio.h>
+
+/*
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#include "jpeglib.h"
+
+/*
+ * <setjmp.h> is used for the optional error recovery mechanism shown in
+ * the second part of the example.
+ */
+
+#include <setjmp.h>
+
+
+
+/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to feed data into the JPEG compressor.
+ * We present a minimal version that does not worry about refinements such
+ * as error recovery (the JPEG code will just exit() if it gets an error).
+ */
+
+
+/*
+ * IMAGE DATA FORMATS:
+ *
+ * The standard input image format is a rectangular array of pixels, with
+ * each pixel having the same number of "component" values (color channels).
+ * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).
+ * If you are working with color data, then the color values for each pixel
+ * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit
+ * RGB color.
+ *
+ * For this example, we'll assume that this data structure matches the way
+ * our application has stored the image in memory, so we can just pass a
+ * pointer to our image buffer. In particular, let's say that the image is
+ * RGB color and is described by:
+ */
+
+extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */
+extern int image_height; /* Number of rows in image */
+extern int image_width; /* Number of columns in image */
+
+
+/*
+ * Sample routine for JPEG compression. We assume that the target file name
+ * and a compression quality factor are passed in.
+ */
+
+GLOBAL(void)
+write_JPEG_file (char * filename, int quality)
+{
+ /* This struct contains the JPEG compression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ * It is possible to have several such structures, representing multiple
+ * compression/decompression processes, in existence at once. We refer
+ * to any one struct (and its associated working data) as a "JPEG object".
+ */
+ struct jpeg_compress_struct cinfo;
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct jpeg_error_mgr jerr;
+ /* More stuff */
+ FILE * outfile; /* target file */
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+
+ /* Step 1: allocate and initialize JPEG compression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+
+ /* Here we use the library-supplied code to send compressed data to a
+ * stdio stream. You can also write your own code to do something else.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to write binary files.
+ */
+ if ((outfile = fopen(filename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ /* Step 3: set parameters for compression */
+
+ /* First we supply a description of the input image.
+ * Four fields of the cinfo struct must be filled in:
+ */
+ cinfo.image_width = image_width; /* image width and height, in pixels */
+ cinfo.image_height = image_height;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+ /* Now use the library's routine to set default compression parameters.
+ * (You must set at least cinfo.in_color_space before calling this,
+ * since the defaults depend on the source color space.)
+ */
+ jpeg_set_defaults(&cinfo);
+ /* Now you can set any non-default parameters you wish to.
+ * Here we just illustrate the use of quality (quantization table) scaling:
+ */
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+
+ /* TRUE ensures that we will write a complete interchange-JPEG file.
+ * Pass TRUE unless you are very sure of what you're doing.
+ */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.next_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ * To keep things simple, we pass one scanline per call; you can pass
+ * more if you wish, though.
+ */
+ row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+
+ jpeg_finish_compress(&cinfo);
+ /* After finish_compress, we can close the output file. */
+ fclose(outfile);
+
+ /* Step 7: release JPEG compression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above loop, we ignored the return value of jpeg_write_scanlines,
+ * which is the number of scanlines actually written. We could get away
+ * with this because we were only relying on the value of cinfo.next_scanline,
+ * which will be incremented correctly. If you maintain additional loop
+ * variables then you should be careful to increment them properly.
+ * Actually, for output to a stdio stream you needn't worry, because
+ * then jpeg_write_scanlines will write all the lines passed (or else exit
+ * with a fatal error). Partial writes can only occur if you use a data
+ * destination module that can demand suspension of the compressor.
+ * (If you don't know what that's for, you don't need it.)
+ *
+ * If the compressor requires full-image buffers (for entropy-coding
+ * optimization or a multi-scan JPEG file), it will create temporary
+ * files for anything that doesn't fit within the maximum-memory setting.
+ * (Note that temp files are NOT needed if you use the default parameters.)
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted. See libjpeg.doc.
+ *
+ * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
+ * files to be compatible with everyone else's. If you cannot readily read
+ * your data in that order, you'll need an intermediate array to hold the
+ * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
+ * source data using the JPEG code's internal virtual-array mechanisms.
+ */
+
+
+
+/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to read data from the JPEG decompressor.
+ * It's a bit more refined than the above, in that we show:
+ * (a) how to modify the JPEG library's standard error-reporting behavior;
+ * (b) how to allocate workspace using the library's memory manager.
+ *
+ * Just to make this example a little different from the first one, we'll
+ * assume that we do not intend to put the whole image into an in-memory
+ * buffer, but to send it line-by-line someplace else. We need a one-
+ * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG
+ * memory manager allocate it for us. This approach is actually quite useful
+ * because we don't need to remember to deallocate the buffer separately: it
+ * will go away automatically when the JPEG object is cleaned up.
+ */
+
+
+/*
+ * ERROR HANDLING:
+ *
+ * The JPEG library's standard error handler (jerror.c) is divided into
+ * several "methods" which you can override individually. This lets you
+ * adjust the behavior without duplicating a lot of code, which you might
+ * have to update with each future release.
+ *
+ * Our example here shows how to override the "error_exit" method so that
+ * control is returned to the library's caller when a fatal error occurs,
+ * rather than calling exit() as the standard error_exit method does.
+ *
+ * We use C's setjmp/longjmp facility to return control. This means that the
+ * routine which calls the JPEG library must first execute a setjmp() call to
+ * establish the return point. We want the replacement error_exit to do a
+ * longjmp(). But we need to make the setjmp buffer accessible to the
+ * error_exit routine. To do this, we make a private extension of the
+ * standard JPEG error handler object. (If we were using C++, we'd say we
+ * were making a subclass of the regular error handler.)
+ *
+ * Here's the extended error handler struct:
+ */
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+/*
+ * Here's the routine that will replace the standard error_exit method:
+ */
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+ my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+/*
+ * Sample routine for JPEG decompression. We assume that the source file name
+ * is passed in. We want to return 1 on success, 0 on error.
+ */
+
+
+GLOBAL(int)
+read_JPEG_file (char * filename)
+{
+ /* This struct contains the JPEG decompression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ */
+ struct jpeg_decompress_struct cinfo;
+ /* We use our private extension JPEG error handler.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct my_error_mgr jerr;
+ /* More stuff */
+ FILE * infile; /* source file */
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride; /* physical row width in output buffer */
+
+ /* In this example we want to open the input file before doing anything else,
+ * so that the setjmp() error recovery below can assume the file is open.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to read binary files.
+ */
+
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ return 0;
+ }
+
+ /* Step 1: allocate and initialize JPEG decompression object */
+
+ /* We set up the normal JPEG error routines, then override error_exit. */
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return 0;
+ }
+ /* Now we can initialize the JPEG decompression object. */
+ jpeg_create_decompress(&cinfo);
+
+ /* Step 2: specify data source (eg, a file) */
+
+ jpeg_stdio_src(&cinfo, infile);
+
+ /* Step 3: read file parameters with jpeg_read_header() */
+
+ (void) jpeg_read_header(&cinfo, TRUE);
+ /* We can ignore the return value from jpeg_read_header since
+ * (a) suspension is not possible with the stdio data source, and
+ * (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ * See libjpeg.doc for more info.
+ */
+
+ /* Step 4: set parameters for decompression */
+
+ /* In this example, we don't need to change any of the defaults set by
+ * jpeg_read_header(), so we do nothing here.
+ */
+
+ /* Step 5: Start decompressor */
+
+ (void) jpeg_start_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* We may need to do some setup of our own at this point before reading
+ * the data. After jpeg_start_decompress() we have the correct scaled
+ * output image dimensions available, as well as the output colormap
+ * if we asked for color quantization.
+ * In this example, we need to make an output work buffer of the right size.
+ */
+ /* JSAMPLEs per row in output buffer */
+ row_stride = cinfo.output_width * cinfo.output_components;
+ /* Make a one-row-high sample array that will go away when done with image */
+ buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ /* Step 6: while (scan lines remain to be read) */
+ /* jpeg_read_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.output_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ /* jpeg_read_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could ask for
+ * more than one scanline at a time if that's more convenient.
+ */
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ /* Assume put_scanline_someplace wants a pointer and sample count. */
+ put_scanline_someplace(buffer[0], row_stride);
+ }
+
+ /* Step 7: Finish decompression */
+
+ (void) jpeg_finish_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* Step 8: Release JPEG decompression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_decompress(&cinfo);
+
+ /* After finish_decompress, we can close the input file.
+ * Here we postpone it until after no more JPEG errors are possible,
+ * so as to simplify the setjmp error logic above. (Actually, I don't
+ * think that jpeg_destroy can do an error exit, but why assume anything...)
+ */
+ fclose(infile);
+
+ /* At this point you may want to check to see whether any corrupt-data
+ * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+ */
+
+ /* And we're done! */
+ return 1;
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above code, we ignored the return value of jpeg_read_scanlines,
+ * which is the number of scanlines actually read. We could get away with
+ * this because we asked for only one line at a time and we weren't using
+ * a suspending data source. See libjpeg.doc for more info.
+ *
+ * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
+ * we should have done it beforehand to ensure that the space would be
+ * counted against the JPEG max_memory setting. In some systems the above
+ * code would risk an out-of-memory error. However, in general we don't
+ * know the output image dimensions before jpeg_start_decompress(), unless we
+ * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this.
+ *
+ * Scanlines are returned in the same order as they appear in the JPEG file,
+ * which is standardly top-to-bottom. If you must emit data bottom-to-top,
+ * you can use one of the virtual arrays provided by the JPEG memory manager
+ * to invert the data. See wrbmp.c for an example.
+ *
+ * As with compression, some operating modes may require temporary files.
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted. See libjpeg.doc.
+ */
diff --git a/gs/jpeg/filelist.doc b/gs/jpeg/filelist.doc
new file mode 100644
index 000000000..707dc1c6b
--- /dev/null
+++ b/gs/jpeg/filelist.doc
@@ -0,0 +1,203 @@
+IJG JPEG LIBRARY: FILE LIST
+
+Copyright (C) 1994-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Here is a road map to the files in the IJG JPEG distribution. The
+distribution includes the JPEG library proper, plus two application
+programs ("cjpeg" and "djpeg") which use the library to convert JPEG
+files to and from some other popular image formats. A third application
+"jpegtran" uses the library to do lossless conversion between different
+variants of JPEG. There are also two stand-alone applications,
+"rdjpgcom" and "wrjpgcom".
+
+
+THE JPEG LIBRARY
+================
+
+Include files:
+
+jpeglib.h JPEG library's exported data and function declarations.
+jconfig.h Configuration declarations. Note: this file is not present
+ in the distribution; it is generated during installation.
+jmorecfg.h Additional configuration declarations; need not be changed
+ for a standard installation.
+jerror.h Declares JPEG library's error and trace message codes.
+jinclude.h Central include file used by all IJG .c files to reference
+ system include files.
+jpegint.h JPEG library's internal data structures.
+jchuff.h Private declarations for Huffman encoder modules.
+jdhuff.h Private declarations for Huffman decoder modules.
+jdct.h Private declarations for forward & reverse DCT subsystems.
+jmemsys.h Private declarations for memory management subsystem.
+jversion.h Version information.
+
+Applications using the library should include jpeglib.h (which in turn
+includes jconfig.h and jmorecfg.h). Optionally, jerror.h may be included
+if the application needs to reference individual JPEG error codes. The
+other include files are intended for internal use and would not normally
+be included by an application program. (cjpeg/djpeg/etc do use jinclude.h,
+since its function is to improve portability of the whole IJG distribution.
+Most other applications will directly include the system include files they
+want, and hence won't need jinclude.h.)
+
+
+C source code files:
+
+These files contain most of the functions intended to be called directly by
+an application program:
+
+jcapimin.c Application program interface: core routines for compression.
+jcapistd.c Application program interface: standard compression.
+jdapimin.c Application program interface: core routines for decompression.
+jdapistd.c Application program interface: standard decompression.
+jcomapi.c Application program interface routines common to compression
+ and decompression.
+jcparam.c Compression parameter setting helper routines.
+jctrans.c API and library routines for transcoding compression.
+jdtrans.c API and library routines for transcoding decompression.
+
+Compression side of the library:
+
+jcinit.c Initialization: determines which other modules to use.
+jcmaster.c Master control: setup and inter-pass sequencing logic.
+jcmainct.c Main buffer controller (preprocessor => JPEG compressor).
+jcprepct.c Preprocessor buffer controller.
+jccoefct.c Buffer controller for DCT coefficient buffer.
+jccolor.c Color space conversion.
+jcsample.c Downsampling.
+jcdctmgr.c DCT manager (DCT implementation selection & control).
+jfdctint.c Forward DCT using slow-but-accurate integer method.
+jfdctfst.c Forward DCT using faster, less accurate integer method.
+jfdctflt.c Forward DCT using floating-point arithmetic.
+jchuff.c Huffman entropy coding for sequential JPEG.
+jcphuff.c Huffman entropy coding for progressive JPEG.
+jcmarker.c JPEG marker writing.
+jdatadst.c Data destination manager for stdio output.
+
+Decompression side of the library:
+
+jdmaster.c Master control: determines which other modules to use.
+jdinput.c Input controller: controls input processing modules.
+jdmainct.c Main buffer controller (JPEG decompressor => postprocessor).
+jdcoefct.c Buffer controller for DCT coefficient buffer.
+jdpostct.c Postprocessor buffer controller.
+jdmarker.c JPEG marker reading.
+jdhuff.c Huffman entropy decoding for sequential JPEG.
+jdphuff.c Huffman entropy decoding for progressive JPEG.
+jddctmgr.c IDCT manager (IDCT implementation selection & control).
+jidctint.c Inverse DCT using slow-but-accurate integer method.
+jidctfst.c Inverse DCT using faster, less accurate integer method.
+jidctflt.c Inverse DCT using floating-point arithmetic.
+jidctred.c Inverse DCTs with reduced-size outputs.
+jdsample.c Upsampling.
+jdcolor.c Color space conversion.
+jdmerge.c Merged upsampling/color conversion (faster, lower quality).
+jquant1.c One-pass color quantization using a fixed-spacing colormap.
+jquant2.c Two-pass color quantization using a custom-generated colormap.
+ Also handles one-pass quantization to an externally given map.
+jdatasrc.c Data source manager for stdio input.
+
+Support files for both compression and decompression:
+
+jerror.c Standard error handling routines (application replaceable).
+jmemmgr.c System-independent (more or less) memory management code.
+jutils.c Miscellaneous utility routines.
+
+jmemmgr.c relies on a system-dependent memory management module. The IJG
+distribution includes the following implementations of the system-dependent
+module:
+
+jmemnobs.c "No backing store": assumes adequate virtual memory exists.
+jmemansi.c Makes temporary files with ANSI-standard routine tmpfile().
+jmemname.c Makes temporary files with program-generated file names.
+jmemdos.c Custom implementation for MS-DOS: knows about extended and
+ expanded memory as well as temporary files.
+jmemmac.c Custom implementation for Apple Macintosh.
+
+Exactly one of the system-dependent modules should be configured into an
+installed JPEG library (see install.doc for hints about which one to use).
+On unusual systems you may find it worthwhile to make a special
+system-dependent memory manager.
+
+
+Non-C source code files:
+
+jmemdosa.asm 80x86 assembly code support for jmemdos.c; used only in
+ MS-DOS-specific configurations of the JPEG library.
+
+
+CJPEG/DJPEG/JPEGTRAN
+====================
+
+Include files:
+
+cdjpeg.h Declarations shared by cjpeg/djpeg modules.
+cderror.h Additional error and trace message codes for cjpeg/djpeg.
+
+C source code files:
+
+cjpeg.c Main program for cjpeg.
+djpeg.c Main program for djpeg.
+jpegtran.c Main program for jpegtran.
+cdjpeg.c Utility routines used by all three programs.
+rdcolmap.c Code to read a colormap file for djpeg's "-map" switch.
+rdswitch.c Code to process some of cjpeg's more complex switches.
+ Also used by jpegtran.
+
+Image file reader modules for cjpeg:
+
+rdbmp.c BMP file input.
+rdgif.c GIF file input.
+rdppm.c PPM/PGM file input.
+rdrle.c Utah RLE file input.
+rdtarga.c Targa file input.
+
+Image file writer modules for djpeg:
+
+wrbmp.c BMP file output.
+wrgif.c GIF file output.
+wrppm.c PPM/PGM file output.
+wrrle.c Utah RLE file output.
+wrtarga.c Targa file output.
+
+
+RDJPGCOM/WRJPGCOM
+=================
+
+C source code files:
+
+rdjpgcom.c Stand-alone rdjpgcom application.
+wrjpgcom.c Stand-alone wrjpgcom application.
+
+These programs do not depend on the IJG library. They do use
+jconfig.h and jinclude.h, only to improve portability.
+
+
+ADDITIONAL FILES
+================
+
+Documentation (see README for a guide to the documentation files):
+
+README Master documentation file.
+*.doc Other documentation files.
+*.1 Documentation in Unix man page format.
+change.log Version-to-version change highlights.
+example.c Sample code for calling JPEG library.
+
+Configuration/installation files and programs (see install.doc for more info):
+
+configure Unix shell script to perform automatic configuration.
+ckconfig.c Program to generate jconfig.h on non-Unix systems.
+jconfig.doc Template for making jconfig.h by hand.
+makefile.* Sample makefiles for particular systems.
+jconfig.* Sample jconfig.h for particular systems.
+ansi2knr.c De-ANSIfier for pre-ANSI C compilers (courtesy of
+ L. Peter Deutsch and Aladdin Enterprises).
+
+Test files (see install.doc for test procedure):
+
+test*.* Source and comparison files for confidence test.
+ These are binary image files, NOT text files.
diff --git a/gs/jpeg/install.doc b/gs/jpeg/install.doc
new file mode 100644
index 000000000..585b29b2e
--- /dev/null
+++ b/gs/jpeg/install.doc
@@ -0,0 +1,931 @@
+INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software
+
+Copyright (C) 1991-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file explains how to configure and install the IJG software. We have
+tried to make this software extremely portable and flexible, so that it can be
+adapted to almost any environment. The downside of this decision is that the
+installation process is complicated. We have provided shortcuts to simplify
+the task on common systems. But in any case, you will need at least a little
+familiarity with C programming and program build procedures for your system.
+
+If you are only using this software as part of a larger program, the larger
+program's installation procedure may take care of configuring the IJG code.
+For example, Ghostscript's installation script will configure the IJG code.
+You don't need to read this file if you just want to compile Ghostscript.
+
+If you are on a Unix machine, you may not need to read this file at all.
+Try doing
+ ./configure
+ make
+ make test
+If that doesn't complain, do
+ make install
+(better do "make -n install" first to see if the makefile will put the files
+where you want them). Read further if you run into snags or want to customize
+the code for your system.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Before you start
+Configuring the software:
+ using the automatic "configure" script
+ using one of the supplied jconfig and makefile files
+ by hand
+Building the software
+Testing the software
+Installing the software
+Optional stuff
+Optimization
+Hints for specific systems
+
+
+BEFORE YOU START
+================
+
+Before installing the software you must unpack the distributed source code.
+Since you are reading this file, you have probably already succeeded in this
+task. However, there is a potential for error if you needed to convert the
+files to the local standard text file format (for example, if you are on
+MS-DOS you may have converted LF end-of-line to CR/LF). You must apply
+such conversion to all the files EXCEPT those whose names begin with "test".
+The test files contain binary data; if you change them in any way then the
+self-test will give bad results.
+
+Please check the last section of this file to see if there are hints for the
+specific machine or compiler you are using.
+
+
+CONFIGURING THE SOFTWARE
+========================
+
+To configure the IJG code for your system, you need to create two files:
+ * jconfig.h: contains values for system-dependent #define symbols.
+ * Makefile: controls the compilation process.
+(On a non-Unix machine, you may create "project files" or some other
+substitute for a Makefile. jconfig.h is needed in any environment.)
+
+We provide three different ways to generate these files:
+ * On a Unix system, you can just run the "configure" script.
+ * We provide sample jconfig files and makefiles for popular machines;
+ if your machine matches one of the samples, just copy the right sample
+ files to jconfig.h and Makefile.
+ * If all else fails, read the instructions below and make your own files.
+
+
+Configuring the software using the automatic "configure" script
+---------------------------------------------------------------
+
+If you are on a Unix machine, you can just type
+ ./configure
+and let the configure script construct appropriate configuration files.
+If you're using "csh" on an old version of System V, you might need to type
+ sh configure
+instead to prevent csh from trying to execute configure itself.
+Expect configure to run for a few minutes, particularly on slower machines;
+it works by compiling a series of test programs.
+
+Configure was created with GNU Autoconf and it follows the usual conventions
+for GNU configure scripts. It makes a few assumptions that you may want to
+override. You can do this by providing optional switches to configure:
+
+* Configure will use gcc (GNU C compiler) if it's available, otherwise cc.
+To force a particular compiler to be selected, use the CC option, for example
+ ./configure CC='cc'
+The same method can be used to include any unusual compiler switches.
+For example, on HP-UX you probably want to say
+ ./configure CC='cc -Aa'
+to get HP's compiler to run in ANSI mode.
+
+* The default CFLAGS setting is "-O". You can override this by saying,
+for example, ./configure CFLAGS='-O2'.
+
+* Configure will set up the makefile so that "make install" will install files
+into /usr/local/bin, /usr/local/man, etc. You can specify an installation
+prefix other than "/usr/local" by giving configure the option "--prefix=PATH".
+
+* If you don't have a lot of swap space, you may need to enable the IJG
+software's internal virtual memory mechanism. To do this, give the option
+"--enable-maxmem=N" where N is the default maxmemory limit in megabytes.
+This is discussed in more detail under "Selecting a memory manager", below.
+You probably don't need to worry about this on reasonably-sized Unix machines,
+unless you plan to process very large images.
+
+Configure has some other features that are useful if you are cross-compiling
+or working in a network of multiple machine types; but if you need those
+features, you probably already know how to use them.
+
+
+Configuring the software using one of the supplied jconfig and makefile files
+-----------------------------------------------------------------------------
+
+If you have one of these systems, you can just use the provided configuration
+files:
+
+Makefile jconfig file System and/or compiler
+
+makefile.manx jconfig.manx Amiga, Manx Aztec C
+makefile.sas jconfig.sas Amiga, SAS C
+mak*jpeg.st jconfig.st Atari ST/STE/TT, Pure C or Turbo C
+makefile.bcc jconfig.bcc MS-DOS or OS/2, Borland C
+makefile.dj jconfig.dj MS-DOS, DJGPP (Delorie's port of GNU C)
+makefile.mc6 jconfig.mc6 MS-DOS, Microsoft C version 6.x and up
+makefile.wat jconfig.wat MS-DOS, OS/2, or Windows NT, Watcom C
+makefile.mms jconfig.vms Digital VMS, with MMS software
+makefile.vms jconfig.vms Digital VMS, without MMS software
+
+Copy the proper jconfig file to jconfig.h and the makefile to Makefile
+(or whatever your system uses as the standard makefile name). For the
+Atari, we provide four project files; see the Atari hints below.
+
+
+Configuring the software by hand
+--------------------------------
+
+First, generate a jconfig.h file. If you are moderately familiar with C,
+the comments in jconfig.doc should be enough information to do this; just
+copy jconfig.doc to jconfig.h and edit it appropriately. Otherwise, you may
+prefer to use the ckconfig.c program. You will need to compile and execute
+ckconfig.c by hand --- we hope you know at least enough to do that.
+ckconfig.c may not compile the first try (in fact, the whole idea is for it
+to fail if anything is going to). If you get compile errors, fix them by
+editing ckconfig.c according to the directions given in ckconfig.c. Once
+you get it to run, it will write a suitable jconfig.h file, and will also
+print out some advice about which makefile to use.
+
+You may also want to look at the canned jconfig files, if there is one for a
+system similar to yours.
+
+Second, select a makefile and copy it to Makefile (or whatever your system
+uses as the standard makefile name). The most generic makefiles we provide
+are
+ makefile.ansi: if your C compiler supports function prototypes
+ makefile.unix: if not.
+(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES"
+in jconfig.h.) You may want to start from one of the other makefiles if
+there is one for a system similar to yours.
+
+Look over the selected Makefile and adjust options as needed. In particular
+you may want to change the CC and CFLAGS definitions. For instance, if you
+are using GCC, set CC=gcc. If you had to use any compiler switches to get
+ckconfig.c to work, make sure the same switches are in CFLAGS.
+
+If you are on a system that doesn't use makefiles, you'll need to set up
+project files (or whatever you do use) to compile all the source files and
+link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom.
+See the file lists in any of the makefiles to find out which files go into
+each program. Note that the provided makefiles all make a "library" file
+libjpeg first, but you don't have to do that if you don't want to; the file
+lists identify which source files are actually needed for compression,
+decompression, or both. As a last resort, you can make a batch script that
+just compiles everything and links it all together; makefile.vms is an example
+of this (it's for VMS systems that have no make-like utility).
+
+Here are comments about some specific configuration decisions you'll
+need to make:
+
+Command line style
+------------------
+
+These programs can use a Unix-like command line style which supports
+redirection and piping, like this:
+ cjpeg inputfile >outputfile
+ cjpeg <inputfile >outputfile
+ source program | cjpeg >outputfile
+The simpler "two file" command line style is just
+ cjpeg inputfile outputfile
+You may prefer the two-file style, particularly if you don't have pipes.
+
+You MUST use two-file style on any system that doesn't cope well with binary
+data fed through stdin/stdout; this is true for some MS-DOS compilers, for
+example. If you're not on a Unix system, it's safest to assume you need
+two-file style. (But if your compiler provides either the Posix-standard
+fdopen() library routine or a Microsoft-compatible setmode() routine, you
+can safely use the Unix command line style, by defining USE_FDOPEN or
+USE_SETMODE respectively.)
+
+To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE".
+
+Selecting a memory manager
+--------------------------
+
+The IJG code is capable of working on images that are too big to fit in main
+memory; data is swapped out to temporary files as necessary. However, the
+code to do this is rather system-dependent. We provide five different
+memory managers:
+
+* jmemansi.c This version uses the ANSI-standard library routine tmpfile(),
+ which not all non-ANSI systems have. On some systems
+ tmpfile() may put the temporary file in a non-optimal
+ location; if you don't like what it does, use jmemname.c.
+
+* jmemname.c This version creates named temporary files. For anything
+ except a Unix machine, you'll need to configure the
+ select_file_name() routine appropriately; see the comments
+ near the head of jmemname.c. If you use this version, define
+ NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files
+ are removed if the program is aborted.
+
+* jmemnobs.c (That stands for No Backing Store :-).) This will compile on
+ almost any system, but it assumes you have enough main memory
+ or virtual memory to hold the biggest images you work with.
+
+* jmemdos.c This should be used with most 16-bit MS-DOS compilers.
+ See the system-specific notes about MS-DOS for more info.
+ IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in
+ jconfig.h, and include the assembly file jmemdosa.asm in the
+ programs. The supplied makefiles and jconfig files for
+ 16-bit MS-DOS compilers already do both.
+
+* jmemmac.c Custom version for Apple Macintosh; see the system-specific
+ notes for Macintosh for more info.
+
+To use a particular memory manager, change the SYSDEPMEM variable in your
+makefile to equal the corresponding object file name (for example, jmemansi.o
+or jmemansi.obj for jmemansi.c).
+
+If you have plenty of (real or virtual) main memory, just use jmemnobs.c.
+"Plenty" means about ten bytes for every pixel in the largest images
+you plan to process, so a lot of systems don't meet this criterion.
+If yours doesn't, try jmemansi.c first. If that doesn't compile, you'll have
+to use jmemname.c; be sure to adjust select_file_name() for local conditions.
+You may also need to change unlink() to remove() in close_backing_store().
+
+Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM
+setting to a reasonable value for your system (either by adding a #define for
+DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile).
+This value limits the amount of data space the program will attempt to
+allocate. Code and static data space isn't counted, so the actual memory
+needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory
+setting. Larger max-memory settings reduce the amount of I/O needed to
+process a large image, but too large a value can result in "insufficient
+memory" failures. On most Unix machines (and other systems with virtual
+memory), just set DEFAULT_MAX_MEM to several million and forget it. At the
+other end of the spectrum, for MS-DOS machines you probably can't go much
+above 300K to 400K. (On MS-DOS the value refers to conventional memory only.
+Extended/expanded memory is handled separately by jmemdos.c.)
+
+
+BUILDING THE SOFTWARE
+=====================
+
+Now you should be able to compile the software. Just say "make" (or
+whatever's necessary to start the compilation). Have a cup of coffee.
+
+Here are some things that could go wrong:
+
+If your compiler complains about undefined structures, you should be able to
+shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h.
+
+If you have trouble with missing system include files or inclusion of the
+wrong ones, read jinclude.h. This shouldn't happen if you used configure
+or ckconfig.c to set up jconfig.h.
+
+There are a fair number of routines that do not use all of their parameters;
+some compilers will issue warnings about this, which you can ignore. There
+are also a few configuration checks that may give "unreachable code" warnings.
+Any other warning deserves investigation.
+
+If you don't have a getenv() library routine, define NO_GETENV.
+
+Also see the system-specific hints, below.
+
+
+TESTING THE SOFTWARE
+====================
+
+As a quick test of functionality we've included a small sample image in
+several forms:
+ testorig.jpg Starting point for the djpeg tests.
+ testimg.ppm The output of djpeg testorig.jpg
+ testimg.gif The output of djpeg -gif testorig.jpg
+ testimg.jpg The output of cjpeg testimg.ppm
+ testprog.jpg Progressive-mode equivalent of testorig.jpg.
+ testimgp.jpg The output of cjpeg -progressive -optimize testimg.ppm
+(The first- and second-generation .jpg files aren't identical since JPEG is
+lossy.) If you can generate duplicates of the testimg* files then you
+probably have working programs.
+
+With most of the makefiles, "make test" will perform the necessary
+comparisons.
+
+If you're using a makefile that doesn't provide the test option, run djpeg
+and cjpeg by hand and compare the output files to testimg* with whatever
+binary file comparison tool you have. The files should be bit-for-bit
+identical.
+
+If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you
+need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t.
+Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h. A less likely
+configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE
+as long should take care of that one.
+
+If the cjpeg test run fails with "Missing Huffman code table entry", it's a
+good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED. Go back to the
+configuration step and run ckconfig.c. (This is a good plan for any other
+test failure, too.)
+
+If you are using Unix (one-file) command line style on a non-Unix system,
+it's a good idea to check that binary I/O through stdin/stdout actually
+works. You should get the same results from "djpeg <testorig.jpg >out.ppm"
+as from "djpeg -outfile out.ppm testorig.jpg". Note that the makefiles all
+use the latter style and therefore do not exercise stdin/stdout! If this
+check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined.
+If it still doesn't work, better use two-file style.
+
+If you chose a memory manager other than jmemnobs.c, you should test that
+temporary-file usage works. Try "djpeg -gif -max 0 testorig.jpg" and make
+sure its output matches testimg.gif. If you have any really large images
+handy, try compressing them with -optimize and/or decompressing with -gif to
+make sure your DEFAULT_MAX_MEM setting is not too large.
+
+NOTE: this is far from an exhaustive test of the JPEG software; some modules,
+such as 1-pass color quantization, are not exercised at all. It's just a
+quick test to give you some confidence that you haven't missed something
+major.
+
+
+INSTALLING THE SOFTWARE
+=======================
+
+Once you're done with the above steps, you can install the software by
+copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom)
+to wherever you normally install programs. On Unix systems, you'll also want
+to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1)
+in the man-page directory. The canned makefiles don't support this step
+since there's such a wide variety of installation procedures on different
+systems.
+
+If you generated a Makefile with the "configure" script, you can just say
+ make install
+to install the programs and their man pages into the standard places.
+(You'll probably need to be root to do this.) We recommend first saying
+ make -n install
+to see where configure thought the files should go. You may need to edit
+the Makefile, particularly if your system's conventions for man page
+filenames don't match what configure expects.
+
+If you want to install the library file libjpeg.a and the include files j*.h
+(for use in compiling other programs besides the IJG ones), then say
+ make install-lib
+
+
+OPTIONAL STUFF
+==============
+
+Progress monitor:
+
+If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display
+of percent-done progress reports. The routine provided in cdjpeg.c merely
+prints percentages to stderr, but you can customize it to do something
+fancier.
+
+Utah RLE file format support:
+
+We distribute the software with support for RLE image files (Utah Raster
+Toolkit format) disabled, because the RLE support won't compile without the
+Utah library. If you have URT version 3.1 or later, you can enable RLE
+support as follows:
+ 1. #define RLE_SUPPORTED in jconfig.h.
+ 2. Add a -I option to CFLAGS in the Makefile for the directory
+ containing the URT .h files (typically the "include"
+ subdirectory of the URT distribution).
+ 3. Add -L... -lrle to LDLIBS in the Makefile, where ... specifies
+ the directory containing the URT "librle.a" file (typically the
+ "lib" subdirectory of the URT distribution).
+
+Support for 12-bit-deep pixel data:
+
+The JPEG standard allows either 8-bit or 12-bit data precision. (For color,
+this means 8 or 12 bits per channel, of course.) If you need to work with
+deeper than 8-bit data, you can compile the IJG code for 12-bit operation.
+To do so:
+ 1. In jmorecfg.h, define BITS_IN_JSAMPLE as 12 rather than 8.
+ 2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED,
+ because the code for those formats doesn't handle 12-bit data and won't
+ even compile. (The PPM code does work, as explained below. The GIF
+ code works too; it scales 8-bit GIF data to and from 12-bit depth
+ automatically.)
+ 3. Compile. Don't expect "make test" to pass, since the supplied test
+ files are for 8-bit data.
+
+Currently, 12-bit support does not work on 16-bit-int machines.
+
+Note that a 12-bit version will not read 8-bit JPEG files, nor vice versa;
+so you'll want to keep around a regular 8-bit compilation as well.
+(Run-time selection of data depth, to allow a single copy that does both,
+is possible but would probably slow things down considerably; it's very low
+on our to-do list.)
+
+The PPM reader (rdppm.c) can read 12-bit data from either text-format or
+binary-format PPM and PGM files. Binary-format PPM/PGM files which have a
+maxval greater than 255 are assumed to use 2 bytes per sample, LSB first
+(little-endian order). As of early 1995, 2-byte binary format is not
+officially supported by the PBMPLUS library, but it is expected that the
+next release of PBMPLUS will support it. Note that the PPM reader will
+read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming
+data is automatically rescaled to either maxval=255 or maxval=4095 as
+appropriate for the cjpeg bit depth.
+
+The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM
+format, maxval 4095, when compiled with BITS_IN_JSAMPLE=12. Since this
+format is not yet widely supported, you can disable it by compiling wrppm.c
+with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a
+standard 1-byte/sample PPM or PGM file. (Yes, this means still another copy
+of djpeg to keep around. But hopefully you won't need it for very long.
+Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.)
+
+Of course, if you are working with 12-bit data, you probably have it stored
+in some other, nonstandard format. In that case you'll probably want to
+write your own I/O modules to read and write your format.
+
+Note that a 12-bit version of cjpeg always runs in "-optimize" mode, in
+order to generate valid Huffman tables. This is necessary because our
+default Huffman tables only cover 8-bit data.
+
+Removing code:
+
+If you need to make a smaller version of the JPEG software, some optional
+functions can be removed at compile time. See the xxx_SUPPORTED #defines in
+jconfig.h and jmorecfg.h. If at all possible, we recommend that you leave in
+decoder support for all valid JPEG files, to ensure that you can read anyone's
+output. Taking out support for image file formats that you don't use is the
+most painless way to make the programs smaller. Another possibility is to
+remove some of the DCT methods: in particular, the "IFAST" method may not be
+enough faster than the others to be worth keeping on your machine. (If you
+do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST
+to a supported method, by adding a #define in jconfig.h.)
+
+
+OPTIMIZATION
+============
+
+Unless you own a Cray, you'll probably be interested in making the JPEG
+software go as fast as possible. This section covers some machine-dependent
+optimizations you may want to try. We suggest that before trying any of
+this, you first get the basic installation to pass the self-test step.
+Repeat the self-test after any optimization to make sure that you haven't
+broken anything.
+
+The integer DCT routines perform a lot of multiplications. These
+multiplications must yield 32-bit results, but none of their input values
+are more than 16 bits wide. On many machines, notably the 680x0 and 80x86
+CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32
+bit multiply. Unfortunately there is no portable way to specify such a
+multiplication in C, but some compilers can generate one when you use the
+right combination of casts. See the MULTIPLYxxx macro definitions in
+jdct.h. If your compiler makes "int" be 32 bits and "short" be 16 bits,
+defining SHORTxSHORT_32 is fairly likely to work. When experimenting with
+alternate definitions, be sure to test not only whether the code still works
+(use the self-test), but also whether it is actually faster --- on some
+compilers, alternate definitions may compute the right answer, yet be slower
+than the default. Timing cjpeg on a large PGM (grayscale) input file is the
+best way to check this, as the DCT will be the largest fraction of the runtime
+in that mode. (Note: some of the distributed compiler-specific jconfig files
+already contain #define switches to select appropriate MULTIPLYxxx
+definitions.)
+
+If your machine has sufficiently fast floating point hardware, you may find
+that the float DCT method is faster than the integer DCT methods, even
+after tweaking the integer multiply macros. In that case you may want to
+make the float DCT be the default method. (The only objection to this is
+that float DCT results may vary slightly across machines.) To do that, add
+"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h. Even if you don't change
+the default, you should redefine JDCT_FASTEST, which is the method selected
+by djpeg's -fast switch. Don't forget to update the documentation files
+(usage.doc and/or cjpeg.1, djpeg.1) to agree with what you've done.
+
+If access to "short" arrays is slow on your machine, it may be a win to
+define type JCOEF as int rather than short. This will cost a good deal of
+memory though, particularly in some multi-pass modes, so don't do it unless
+you have memory to burn and short is REALLY slow.
+
+If your compiler can compile function calls in-line, make sure the INLINE
+macro in jmorecfg.h is defined as the keyword that marks a function
+inline-able. Some compilers have a switch that tells the compiler to inline
+any function it thinks is profitable (e.g., -finline-functions for gcc).
+Enabling such a switch is likely to make the compiled code bigger but faster.
+
+In general, it's worth trying the maximum optimization level of your compiler,
+and experimenting with any optional optimizations such as loop unrolling.
+(Unfortunately, far too many compilers have optimizer bugs ... be prepared to
+back off if the code fails self-test.) If you do any experimentation along
+these lines, please report the optimal settings to jpeg-info@uunet.uu.net so
+we can mention them in future releases. Be sure to specify your machine and
+compiler version.
+
+
+HINTS FOR SPECIFIC SYSTEMS
+==========================
+
+We welcome reports on changes needed for systems not mentioned here. Submit
+'em to jpeg-info@uunet.uu.net. Also, if configure or ckconfig.c is wrong
+about how to configure the JPEG software for your system, please let us know.
+
+
+Acorn RISC OS:
+
+(Thanks to Simon Middleton for these hints on compiling with Desktop C.)
+After renaming the files according to Acorn conventions, take a copy of
+makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and
+change these definitions as indicated:
+
+CFLAGS= -throwback -IC: -Wn
+LDLIBS=C:o.Stubs
+SYSDEPMEM=jmemansi.o
+LN=Link
+AR=LibFile -c -o
+
+Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'. Remove the
+lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h'
+dependency section.
+
+Copy jconfig.doc to jconfig.h. Edit jconfig.h to define TWO_FILE_COMMANDLINE
+and CHAR_IS_UNSIGNED.
+
+Run the makefile using !AMU not !Make. If you want to use the 'clean' and
+'test' makefile entries then you will have to fiddle with the syntax a bit
+and rename the test files.
+
+
+Amiga:
+
+SAS C 6.50 reportedly is too buggy to compile the IJG code properly.
+A patch to update to 6.51 is available from SAS or AmiNet FTP sites.
+
+The supplied config files are set up to use jmemname.c as the memory
+manager, with temporary files being created on the device named by
+"JPEGTMP:".
+
+
+Atari ST/STE/TT:
+
+Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st
+to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively. The
+project files should work as-is with Pure C. For Turbo C, change library
+filenames "PC..." to "TC..." in each project file. Note that libjpeg.prj
+selects jmemansi.c as the recommended memory manager. You'll probably want to
+adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K
+less than your normal free memory. Put "#define DEFAULT_MAX_MEM nnnn" into
+jconfig.h to do this.
+
+To use the 68881/68882 coprocessor for the floating point DCT, add the
+compiler option "-8" to the project files and replace PCFLTLIB.LIB with
+PC881LIB.LIB in cjpeg.prj and djpeg.prj. Or if you don't have a
+coprocessor, you may prefer to remove the float DCT code by undefining
+DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float
+code will be too slow to be useful). In that case, you can delete
+PCFLTLIB.LIB from the project files.
+
+Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp,
+or jpegtran.ttp. You'll have to perform the self-test by hand.
+
+We haven't bothered to include project files for rdjpgcom and wrjpgcom.
+Those source files should just be compiled by themselves; they don't
+depend on the JPEG library.
+
+There is a bug in some older versions of the Turbo C library which causes the
+space used by temporary files created with "tmpfile()" not to be freed after
+an abnormal program exit. If you check your disk afterwards, you will find
+cluster chains that are allocated but not used by a file. This should not
+happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly
+close temp files before exiting. But if you use the JPEG library with your
+own code, be sure to supply a signal catcher, or else use a different
+system-dependent memory manager.
+
+
+Cray:
+
+Should you be so fortunate as to be running JPEG on a Cray YMP, there is a
+compiler bug in old versions of Cray's Standard C (prior to 3.1). If you
+still have an old compiler, you'll need to insert a line reading
+"#pragma novector" just before the loop
+ for (i = 1; i <= (int) htbl->bits[l]; i++)
+ huffsize[p++] = (char) l;
+in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c).
+[This bug may or may not still occur with the current IJG code, but it's
+probably a dead issue anyway...]
+
+
+HP-UX:
+
+If you have HP-UX 7.05 or later with the "software development" C compiler,
+you should run the compiler in ANSI mode. If using the configure script,
+say
+ ./configure CC='cc -Aa'
+(or -Ae if you prefer). If configuring by hand, use makefile.ansi and add
+"-Aa" to the CFLAGS line in the makefile.
+
+If you have a pre-7.05 system, or if you are using the non-ANSI C compiler
+delivered with a minimum HP-UX system, then you must use makefile.unix
+(and do NOT add -Aa); or just run configure without the CC option.
+
+On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior
+to A.08.07. If you get complaints about "not a typedef name", you'll have to
+use makefile.unix, or run configure without the CC option.
+
+
+Macintosh, generic comments:
+
+The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to
+provide a Unix-style command line interface. You can use this interface on
+the Mac by means of the ccommand() library routine provided by Metrowerks
+CodeWarrior or Think C. This is only appropriate for testing the library,
+however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want
+to develop a Mac-style user interface. Such an interface exists for pre-v5
+IJG libraries (see the Think C entry, below) but at this writing it has not
+been updated to work with the current release.
+
+We recommend replacing "malloc" and "free" by "NewPtr" and "DisposePtr" in
+whichever memory manager back end you use, because Mac C libraries often
+have inferior implementations of malloc/free. jmemmac.c is recommended;
+it is a customized version of jmemansi.c with this change and a Mac-specific
+implementation of jpeg_mem_available(). You can also use jmemnobs.c if you
+don't care about handling images larger than available memory.
+
+
+Macintosh, MPW:
+
+We don't directly support MPW in the current release, but Larry Rosenstein
+ported an earlier version of the IJG code without very much trouble. There's
+useful notes and conversion scripts in his kit for porting PBMPLUS to MPW.
+You can obtain the kit by FTP to ftp.apple.com, files /pub/lsr/pbmplus-port*.
+
+
+Macintosh, Metrowerks CodeWarrior:
+
+Metrowerks release DR2 has problems with the IJG code; don't use it. Release
+DR3.5 or later should be OK.
+
+The Unix-command-line-style interface can be used by defining USE_CCOMMAND.
+You'll also need to define either TWO_FILE_COMMANDLINE (to avoid stdin/stdout)
+or USE_FDOPEN (to make stdin/stdout work in binary mode). See the Think C
+entry for more details.
+
+On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended
+float. jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power
+of 2. Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+
+Macintosh, Think C:
+
+Jim Brunner has prepared a Mac-style user interface for the IJG library.
+Unfortunately, the released version of it only works with pre-v5 libraries;
+still, it may be a useful starting point. You can obtain Jim's additional
+source code from the Info-Mac archives, at sumex-aim.stanford.edu or mirrors
+thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx. Jim's documentation
+also includes more detailed build instructions for Think C.
+
+If you want to build the minimal command line version, proceed as follows.
+You'll have to prepare project files for the programs; we don't include any
+in the distribution since they are not text files. Use the file lists in
+any of the supplied makefiles as a guide. Also add the ANSI and Unix C
+libraries in a separate segment. You may need to divide the JPEG files into
+more than one segment; we recommend dividing compression and decompression
+modules. Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is
+called. You must also define TWO_FILE_COMMANDLINE because stdin/stdout
+don't handle binary data correctly.
+
+On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float.
+jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2.
+Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+
+MIPS R3000:
+
+MIPS's cc version 1.31 has a rather nasty optimization bug. Don't use -O
+if you have that compiler version. (Use "cc -V" to check the version.)
+Note that the R3000 chip is found in workstations from DEC and others.
+
+
+MS-DOS, generic comments for 16-bit compilers:
+
+The IJG code is designed to be compiled in 80x86 "small" or "medium" memory
+models (i.e., data pointers are 16 bits unless explicitly declared "far";
+code pointers can be either size). You may be able to use small model to
+compile cjpeg or djpeg by itself, but you will probably have to use medium
+model for any larger application. This won't make much difference in
+performance. You *will* take a noticeable performance hit if you use a
+large-data memory model, and you should avoid "huge" model if at all
+possible. Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use
+a small-data memory model; be sure it is NOT defined if you use a large-data
+model. (The supplied makefiles and jconfig files for Borland and Microsoft C
+compile in medium model and define NEED_FAR_POINTERS.)
+
+The DOS-specific memory manager, jmemdos.c, should be used if possible.
+It needs some assembly-code routines which are in jmemdosa.asm; make sure
+your makefile assembles that file and includes it in the library. If you
+don't have a suitable assembler, you can get pre-assembled object files for
+jmemdosa by FTP from ftp.uu.net: graphics/jpeg/jdosaobj.zip. (DOS-oriented
+distributions of the IJG source code often include these object files.)
+
+When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set
+MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value). If your
+C library's far-heap malloc() can't allocate blocks that large, reduce
+MAX_ALLOC_CHUNK to whatever it can handle.
+
+If you can't use jmemdos.c for some reason --- for example, because you
+don't have an assembler to assemble jmemdosa.asm --- you'll have to fall
+back to jmemansi.c or jmemname.c. You'll probably still need to set
+MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc()
+more than 64K at a time. IMPORTANT: if you use jmemansi.c or jmemname.c,
+you will have to compile in a large-data memory model in order to get the
+right stdio library. Too bad.
+
+wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB
+work area to hold the comment text. If your C library's malloc can't
+handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c.
+
+Most MS-DOS compilers treat stdin/stdout as text files, so you must use
+two-file command line style. But if your compiler has either fdopen() or
+setmode(), you can use one-file style if you like. To do this, define
+USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode.
+(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.) You
+should test that I/O through stdin/stdout produces the same results as I/O
+to explicitly named files... the "make test" procedures in the supplied
+makefiles do NOT use stdin/stdout.
+
+
+MS-DOS, generic comments for 32-bit compilers:
+
+None of the above comments about memory models apply if you are using a
+32-bit flat-memory-space environment, such as DJGPP or Watcom C. (And you
+should use one if you have it, as performance will be much better than
+8086-compatible code!) For flat-memory-space compilers, do NOT define
+NEED_FAR_POINTERS, and do NOT use jmemdos.c. Use jmemnobs.c if the
+environment supplies adequate virtual memory, otherwise use jmemansi.c or
+jmemname.c.
+
+You'll still need to be careful about binary I/O through stdin/stdout.
+See the last paragraph of the previous section.
+
+
+MS-DOS, Borland C:
+
+Be sure to convert all the source files to DOS text format (CR/LF newlines).
+Although Borland C will often work OK with unmodified Unix (LF newlines)
+source files, sometimes it will give bogus compile errors.
+"Illegal character '#'" is the most common such error. (This is true with
+Borland C 3.1, but perhaps is fixed in newer releases.)
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.bcc already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+
+MS-DOS, DJGPP:
+
+Use a recent version of DJGPP (1.11 or better). If you prefer two-file
+command line style, change the supplied jconfig.dj to define
+TWO_FILE_COMMANDLINE. makefile.dj is set up to generate only COFF files
+(cjpeg, djpeg, etc) when you say make. After testing, say "make exe" to
+make executables with stub.exe, or "make standalone" if you want executables
+that include go32. You will probably need to tweak the makefile's pointer to
+go32.exe to do "make standalone".
+
+
+MS-DOS, Microsoft C:
+
+makefile.mc6 works with Microsoft C, Visual C++, etc. Note that this
+makefile assumes that the working copy of itself is called "makefile".
+If you want to call it something else, say "makefile.mak", be sure to adjust
+the dependency line that reads "$(RFILE) : makefile". Otherwise the make
+will fail because it doesn't know how to create "makefile". Worse, some
+releases of Microsoft's make utilities give an incorrect error message in
+this situation.
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.mc6 already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+Old versions of MS C fail with an "out of macro expansion space" error
+because they can't cope with the macro TRACEMS8 (defined in jerror.h).
+If this happens to you, the easiest solution is to change TRACEMS8 to
+expand to nothing. You'll lose the ability to dump out JPEG coefficient
+tables with djpeg -debug -debug, but at least you can compile.
+
+Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn
+off optimization entirely (remove -O from CFLAGS). 6.00A is better, but it
+still generates bad code if you enable loop optimizations (-Ol or -Ox).
+
+MS C 8.0 reportedly fails to compile jquant1.c if optimization is turned off
+(yes, off).
+
+
+Microsoft Windows (all versions):
+
+Some Windows system include files define typedef boolean as "unsigned char".
+The IJG code also defines typedef boolean, but we make it "int" by default.
+This doesn't affect the IJG programs because we don't import those Windows
+include files. But if you use the JPEG library in your own program, and some
+of your program's files import one definition of boolean while some import the
+other, you can get all sorts of mysterious problems. A good preventive step
+is to change jmorecfg.h to define boolean as unsigned char. We recommend
+making that part of jmorecfg.h read like this:
+ #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+ typedef unsigned char boolean;
+ #endif
+In v6a and later, using incompatible definitions of boolean will usually lead
+to the failure message "JPEG parameter struct mismatch", rather than the
+difficult-to-diagnose bugs it caused with earlier versions.
+
+When using the library in a Windows application, you will almost certainly
+want to modify or replace the error handler module jerror.c, since our
+default error handler does a couple of inappropriate things:
+ 1. it tries to write error and warning messages on stderr;
+ 2. in event of a fatal error, it exits by calling exit().
+A simple stopgap solution for problem 1 is to replace the line
+ fprintf(stderr, "%s\n", buffer);
+(in output_message in jerror.c) with something like
+ MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK);
+It's highly recommended that you at least do that much, since otherwise
+error messages will disappear into nowhere.
+The proper solution for problem 2 is to return control to your calling
+application after a library error. This can be done with the setjmp/longjmp
+technique discussed in libjpeg.doc and illustrated in example.c.
+
+You may also want to modify jdatasrc.c and jdatadst.c to use Windows file
+operations rather than fread/fwrite. This is only necessary if your C
+compiler doesn't provide a competent implementation of C stdio functions.
+
+Many people want to convert the IJG library into a DLL. This is reasonably
+straightforward, but watch out for the following:
+ 1. Don't try to compile as a DLL in small or medium memory model; use
+large model, or even better, 32-bit flat model. Many places in the IJG code
+assume the address of a local variable is an ordinary (not FAR) pointer;
+that isn't true in a medium-model DLL.
+ 2. Microsoft C cannot pass file pointers between applications and DLLs.
+(See Microsoft Knowledge Base, PSS ID Number Q50336.) So jdatasrc.c and
+jdatadst.c don't work if you open a file in your application and then pass
+the pointer to the DLL. One workaround is to make jdatasrc.c/jdatadst.c
+part of your main application rather than part of the DLL.
+ 3. You'll probably need to modify the macros GLOBAL() and EXTERN() to
+attach suitable linkage keywords to the exported routine names. Similarly,
+you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers
+are declared in a way that lets application routines be called back through
+the function pointers. These macros are in jmorecfg.h. Typical definitions
+for a 16-bit DLL are:
+ #define GLOBAL(type) type _far _pascal _loadds _export
+ #define EXTERN(type) extern type _far _pascal
+ #define METHODDEF(type) static type _far _pascal
+ #define JMETHOD(type,methodname,arglist) \
+ type (_far _pascal *methodname) arglist
+Although not all the GLOBAL routines are actually intended to be called by
+the application, the performance cost of making them all DLL entry points is
+negligible.
+
+The unmodified IJG library presents a very C-specific application interface,
+so the resulting DLL is only usable from C or C++ applications. There has
+been some talk of writing wrapper code that would present a simpler interface
+usable from other languages, such as Visual Basic. This is on our to-do list
+but hasn't been very high priority --- any volunteers out there?
+
+
+Microsoft Windows, Borland C:
+
+Borland C++ 4.5 fails with an internal compiler error when trying to compile
+jdmerge.c in 32-bit mode. If enough people complain, perhaps Borland will fix
+it. In the meantime, the simplest known workaround is to add a redundant
+definition of the variable range_limit in h2v1_merged_upsample(), at the head
+of the block that handles odd image width (about line 268 in v6 jdmerge.c):
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */
+ cb = GETJSAMPLE(*inptr1);
+Pretty bizarre, especially since the very similar routine h2v2_merged_upsample
+doesn't trigger the bug.
+Recent reports suggest that this bug does not occur with "bcc32a" (the
+Pentium-optimized version of the compiler).
+
+
+SGI:
+
+On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile.
+If you are using configure, you can do this by saying
+ ./configure RANLIB='ar -ts'
+This change is not needed on all SGIs. Use it only if the make fails at the
+stage of linking the completed programs.
+
+On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2"
+reportedly speeds up the float DCT method substantially, enough to make it
+faster than the default int method (but still slower than the fast int
+method). If you use -mips2, you may want to alter the default DCT method to
+be float. To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h.
+
+
+VMS:
+
+On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1"
+qualifier with MMS when building the JPEG package.
+
+VAX/VMS v5.5-1 may have problems with the test step of the build procedure
+reporting differences when it compares the original and test images. If the
+error points to the last block of the files, it is most likely bogus and may
+be safely ignored. It seems to be because the files are Stream_LF and
+Backup/Compare has difficulty with the (presumably) null padded files.
+This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1.
diff --git a/gs/jpeg/jcapimin.c b/gs/jpeg/jcapimin.c
new file mode 100644
index 000000000..6d864574c
--- /dev/null
+++ b/gs/jpeg/jcapimin.c
@@ -0,0 +1,236 @@
+/*
+ * jcapimin.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-compression case or the transcoding-only
+ * case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jcapistd.c. But also see jcparam.c for
+ * parameter-setup helper routines, jcomapi.c for routines shared by
+ * compression and decompression, and jctrans.c for the transcoding case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG compression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_compress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
+
+ /* For debugging purposes, zero the whole master structure.
+ * But error manager pointer is already there, so save and restore it.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));
+ cinfo->err = err;
+ }
+ cinfo->is_decompressor = FALSE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->dest = NULL;
+
+ cinfo->comp_info = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++)
+ cinfo->quant_tbl_ptrs[i] = NULL;
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ cinfo->input_gamma = 1.0; /* in case application forgets */
+
+ /* OK, I'm ready */
+ cinfo->global_state = CSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG compression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_compress (j_compress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG compression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_compress (j_compress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Forcibly suppress or un-suppress all quantization and Huffman tables.
+ * Marks all currently defined tables as already written (if suppress)
+ * or not written (if !suppress). This will control whether they get emitted
+ * by a subsequent jpeg_start_compress call.
+ *
+ * This routine is exported for use by applications that want to produce
+ * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but
+ * since it is called by jpeg_start_compress, we put it here --- otherwise
+ * jcparam.o would be linked whether the application used it or not.
+ */
+
+GLOBAL(void)
+jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
+{
+ int i;
+ JQUANT_TBL * qtbl;
+ JHUFF_TBL * htbl;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
+ qtbl->sent_table = suppress;
+ }
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ }
+}
+
+
+/*
+ * Finish JPEG compression.
+ *
+ * If a multipass operating mode was selected, this may do a great deal of
+ * work including most of the actual output.
+ */
+
+GLOBAL(void)
+jpeg_finish_compress (j_compress_ptr cinfo)
+{
+ JDIMENSION iMCU_row;
+
+ if (cinfo->global_state == CSTATE_SCANNING ||
+ cinfo->global_state == CSTATE_RAW_OK) {
+ /* Terminate first pass */
+ if (cinfo->next_scanline < cinfo->image_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_pass) (cinfo);
+ } else if (cinfo->global_state != CSTATE_WRCOEFS)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any remaining passes */
+ while (! cinfo->master->is_last_pass) {
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) iMCU_row;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* We bypass the main controller and invoke coef controller directly;
+ * all work is being done from the coefficient buffer.
+ */
+ if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+ (*cinfo->master->finish_pass) (cinfo);
+ }
+ /* Write EOI, do final cleanup */
+ (*cinfo->marker->write_file_trailer) (cinfo);
+ (*cinfo->dest->term_destination) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+}
+
+
+/*
+ * Write a special marker.
+ * This is only recommended for writing COM or APPn markers.
+ * Must be called after jpeg_start_compress() and before
+ * first call to jpeg_write_scanlines() or jpeg_write_raw_data().
+ */
+
+GLOBAL(void)
+jpeg_write_marker (j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen)
+{
+ if (cinfo->next_scanline != 0 ||
+ (cinfo->global_state != CSTATE_SCANNING &&
+ cinfo->global_state != CSTATE_RAW_OK &&
+ cinfo->global_state != CSTATE_WRCOEFS))
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ (*cinfo->marker->write_any_marker) (cinfo, marker, dataptr, datalen);
+}
+
+
+/*
+ * Alternate compression function: just write an abbreviated table file.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * To produce a pair of files containing abbreviated tables and abbreviated
+ * image data, one would proceed as follows:
+ *
+ * initialize JPEG object
+ * set JPEG parameters
+ * set destination to table file
+ * jpeg_write_tables(cinfo);
+ * set destination to image file
+ * jpeg_start_compress(cinfo, FALSE);
+ * write data...
+ * jpeg_finish_compress(cinfo);
+ *
+ * jpeg_write_tables has the side effect of marking all tables written
+ * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress
+ * will not re-emit the tables unless it is passed write_all_tables=TRUE.
+ */
+
+GLOBAL(void)
+jpeg_write_tables (j_compress_ptr cinfo)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Initialize the marker writer ... bit of a crock to do it here. */
+ jinit_marker_writer(cinfo);
+ /* Write them tables! */
+ (*cinfo->marker->write_tables_only) (cinfo);
+ /* And clean up. */
+ (*cinfo->dest->term_destination) (cinfo);
+ /* We can use jpeg_abort to release memory. */
+ jpeg_abort((j_common_ptr) cinfo);
+}
diff --git a/gs/jpeg/jcapistd.c b/gs/jpeg/jcapistd.c
new file mode 100644
index 000000000..c0320b1b1
--- /dev/null
+++ b/gs/jpeg/jcapistd.c
@@ -0,0 +1,161 @@
+/*
+ * jcapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-compression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_compress, it will end up linking in the entire compressor.
+ * We thus must separate this file from jcapimin.c to avoid linking the
+ * whole compression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Compression initialization.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * We require a write_all_tables parameter as a failsafe check when writing
+ * multiple datastreams from the same compression object. Since prior runs
+ * will have left all the tables marked sent_table=TRUE, a subsequent run
+ * would emit an abbreviated stream (no tables) by default. This may be what
+ * is wanted, but for safety's sake it should not be the default behavior:
+ * programmers should have to make a deliberate choice to emit abbreviated
+ * images. Therefore the documentation and examples should encourage people
+ * to pass write_all_tables=TRUE; then it will take active thought to do the
+ * wrong thing.
+ */
+
+GLOBAL(void)
+jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (write_all_tables)
+ jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ jinit_compress_master(cinfo);
+ /* Set up for the first pass */
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ /* Ready for application to drive first pass through jpeg_write_scanlines
+ * or jpeg_write_raw_data.
+ */
+ cinfo->next_scanline = 0;
+ cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
+}
+
+
+/*
+ * Write some scanlines of data to the JPEG compressor.
+ *
+ * The return value will be the number of lines actually written.
+ * This should be less than the supplied num_lines only in case that
+ * the data destination module has requested suspension of the compressor,
+ * or if more than image_height scanlines are passed in.
+ *
+ * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * this likely signals an application programmer error. However,
+ * excess scanlines passed in the last valid call are *silently* ignored,
+ * so that the application need not adjust num_lines for end-of-image
+ * when using a multiple-scanline buffer.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION num_lines)
+{
+ JDIMENSION row_ctr, rows_left;
+
+ if (cinfo->global_state != CSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height)
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_scanlines. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_scanlines.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Ignore any extra scanlines at bottom of image. */
+ rows_left = cinfo->image_height - cinfo->next_scanline;
+ if (num_lines > rows_left)
+ num_lines = rows_left;
+
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+ cinfo->next_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to write raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION num_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != CSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_raw_data. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_raw_data.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Verify that at least one iMCU row has been passed. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
+ if (num_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Directly compress the row. */
+ if (! (*cinfo->coef->compress_data) (cinfo, data)) {
+ /* If compressor did not consume the whole row, suspend processing. */
+ return 0;
+ }
+
+ /* OK, we processed one iMCU row. */
+ cinfo->next_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
diff --git a/gs/jpeg/jccoefct.c b/gs/jpeg/jccoefct.c
new file mode 100644
index 000000000..d971ce5ba
--- /dev/null
+++ b/gs/jpeg/jccoefct.c
@@ -0,0 +1,448 @@
+/*
+ * jccoefct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for compression.
+ * This controller is the top level of the JPEG compressor proper.
+ * The coefficient buffer lies between forward-DCT and entropy encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* We use a full-image coefficient buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files. In all cases, the DCT
+ * step is run during the first pass, and subsequent passes need only read
+ * the buffered coefficients.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* For single-pass compression, it's sufficient to buffer just one MCU
+ * (although this may prove a bit slow in practice). We allocate a
+ * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
+ * MCU constructed and sent. (On 80x86, the workspace is FAR even though
+ * it's not really very big; this is to keep the module interfaces unchanged
+ * when a large coefficient buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays.
+ */
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+METHODDEF(boolean) compress_output
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (coef->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_data;
+ break;
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_first_pass;
+ break;
+ case JBUF_CRANK_DEST:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_output;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image.
+ * For single pass, this is the same as the components in the scan.
+ */
+
+METHODDEF(boolean)
+compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, bi, ci, yindex, yoffset, blockcnt;
+ JDIMENSION ypos, xpos;
+ jpeg_component_info *compptr;
+
+ /* Loop to write as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Determine where data comes from in input_buf and do the DCT thing.
+ * Each call on forward_DCT processes a horizontal row of DCT blocks
+ * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
+ * sequentially. Dummy blocks at the right or bottom edge are filled in
+ * specially. The data in them does not matter for image reconstruction,
+ * so we fill them with values that will encode to the smallest amount of
+ * data, viz: all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. (Thanks to Thomas Kinsman for this idea.)
+ */
+ blkn = 0;
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ xpos = MCU_col_num * compptr->MCU_sample_width;
+ ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ (*cinfo->fdct->forward_DCT) (cinfo, compptr,
+ input_buf[ci], coef->MCU_buffer[blkn],
+ ypos, xpos, (JDIMENSION) blockcnt);
+ if (blockcnt < compptr->MCU_width) {
+ /* Create some dummy blocks at the right edge of the image. */
+ jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
+ (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
+ for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
+ }
+ }
+ } else {
+ /* Create a row of dummy blocks at the bottom of the image. */
+ jzero_far((void FAR *) coef->MCU_buffer[blkn],
+ compptr->MCU_width * SIZEOF(JBLOCK));
+ for (bi = 0; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
+ }
+ }
+ blkn += compptr->MCU_width;
+ ypos += DCTSIZE;
+ }
+ }
+ /* Try to write the MCU. In event of a suspension failure, we will
+ * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
+ */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * This amount of data is read from the source buffer, DCT'd and quantized,
+ * and saved into the virtual arrays. We also generate suitable dummy blocks
+ * as needed at the right and lower edges. (The dummy blocks are constructed
+ * in the virtual arrays, which have been padded appropriately.) This makes
+ * it possible for subsequent passes not to worry about real vs. dummy blocks.
+ *
+ * We must also emit the data to the entropy encoder. This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image. All
+ * components are DCT'd and loaded into the virtual arrays in this pass.
+ * However, it may be that only a subset of the components are emitted to
+ * the entropy encoder during this first pass; be careful about looking
+ * at the scan-dependent variables (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION blocks_across, MCUs_across, MCUindex;
+ int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
+ JCOEF lastDC;
+ jpeg_component_info *compptr;
+ JBLOCKARRAY buffer;
+ JBLOCKROW thisblockrow, lastblockrow;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (coef->iMCU_row_num < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ blocks_across = compptr->width_in_blocks;
+ h_samp_factor = compptr->h_samp_factor;
+ /* Count number of dummy blocks to be added at the right margin. */
+ ndummy = (int) (blocks_across % h_samp_factor);
+ if (ndummy > 0)
+ ndummy = h_samp_factor - ndummy;
+ /* Perform DCT for all non-dummy blocks in this iMCU row. Each call
+ * on forward_DCT processes a complete horizontal row of DCT blocks.
+ */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ thisblockrow = buffer[block_row];
+ (*cinfo->fdct->forward_DCT) (cinfo, compptr,
+ input_buf[ci], thisblockrow,
+ (JDIMENSION) (block_row * DCTSIZE),
+ (JDIMENSION) 0, blocks_across);
+ if (ndummy > 0) {
+ /* Create dummy blocks at the right edge of the image. */
+ thisblockrow += blocks_across; /* => first dummy block */
+ jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
+ lastDC = thisblockrow[-1][0];
+ for (bi = 0; bi < ndummy; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ }
+ }
+ /* If at end of image, create dummy block rows as needed.
+ * The tricky part here is that within each MCU, we want the DC values
+ * of the dummy blocks to match the last real block's DC value.
+ * This squeezes a few more bytes out of the resulting file...
+ */
+ if (coef->iMCU_row_num == last_iMCU_row) {
+ blocks_across += ndummy; /* include lower right corner */
+ MCUs_across = blocks_across / h_samp_factor;
+ for (block_row = block_rows; block_row < compptr->v_samp_factor;
+ block_row++) {
+ thisblockrow = buffer[block_row];
+ lastblockrow = buffer[block_row-1];
+ jzero_far((void FAR *) thisblockrow,
+ (size_t) (blocks_across * SIZEOF(JBLOCK)));
+ for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
+ lastDC = lastblockrow[h_samp_factor-1][0];
+ for (bi = 0; bi < h_samp_factor; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ thisblockrow += h_samp_factor; /* advance to next MCU in row */
+ lastblockrow += h_samp_factor;
+ }
+ }
+ }
+ }
+ /* NB: compress_output will increment iMCU_row_num if successful.
+ * A suspension return will result in redoing all the work above next time.
+ */
+
+ /* Emit data to the entropy encoder, sharing code with subsequent passes */
+ return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan.
+ * NB: during first pass, this is safe only because the buffers will
+ * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+#endif /* FULL_COEF_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ int ci;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) compptr->v_samp_factor);
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->whole_image[0] = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/gs/jpeg/jccolor.c b/gs/jpeg/jccolor.c
new file mode 100644
index 000000000..0a8a4b5d1
--- /dev/null
+++ b/gs/jpeg/jccolor.c
@@ -0,0 +1,459 @@
+/*
+ * jccolor.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_converter pub; /* public fields */
+
+ /* Private state for RGB->YCC conversion */
+ INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
+} my_color_converter;
+
+typedef my_color_converter * my_cconvert_ptr;
+
+
+/**************** RGB -> YCbCr conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
+ * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
+ * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
+ * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
+ * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
+ * were not represented exactly. Now we sacrifice exact representation of
+ * maximum red and maximum blue in order to get exact grayscales.
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times R,G,B for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * in the tables to save adding them separately in the inner loop.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+/* We allocate one big table and divide it up into eight parts, instead of
+ * doing eight alloc_small requests. This lets us use a single table base
+ * address, which can be held in a register in the inner loops on many
+ * machines (more than can hold all eight addresses, anyway).
+ */
+
+#define R_Y_OFF 0 /* offset to R => Y section */
+#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
+#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
+#define R_CB_OFF (3*(MAXJSAMPLE+1))
+#define G_CB_OFF (4*(MAXJSAMPLE+1))
+#define B_CB_OFF (5*(MAXJSAMPLE+1))
+#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
+#define G_CR_OFF (6*(MAXJSAMPLE+1))
+#define B_CR_OFF (7*(MAXJSAMPLE+1))
+#define TABLE_SIZE (8*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize for RGB->YCC colorspace conversion.
+ */
+
+METHODDEF(void)
+rgb_ycc_start (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ INT32 * rgb_ycc_tab;
+ INT32 i;
+
+ /* Allocate and fill in the conversion tables. */
+ cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (TABLE_SIZE * SIZEOF(INT32)));
+
+ for (i = 0; i <= MAXJSAMPLE; i++) {
+ rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
+ rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i;
+ rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
+ rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i;
+ rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i;
+ /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
+ * This ensures that the maximum output will round to MAXJSAMPLE
+ * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+ */
+ rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+/* B=>Cb and R=>Cr tables are the same
+ rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+*/
+ rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i;
+ rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ *
+ * Note that we change from the application's interleaved-pixel format
+ * to our internal noninterleaved, one-plane-per-component format.
+ * The input buffer is therefore three times as wide as the output buffer.
+ *
+ * A starting row offset is provided only for the output buffer. The caller
+ * can easily adjust the passed input_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+rgb_ycc_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/**************** Cases other than RGB -> YCbCr **************/
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles RGB->grayscale conversion, which is the same
+ * as the RGB->Y portion of RGB->YCbCr.
+ * We assume rgb_ycc_start has been called (we only use the Y tables).
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* Y */
+ outptr[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles Adobe-style CMYK->YCCK conversion,
+ * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume rgb_ycc_start has been called.
+ */
+
+METHODDEF(void)
+cmyk_ycck_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ outptr3 = output_buf[3][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
+ g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
+ b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
+ /* K passes through as-is */
+ outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
+ inptr += 4;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles grayscale output with no conversion.
+ * The source can be either plain grayscale or YCbCr (since Y == gray).
+ */
+
+METHODDEF(void)
+grayscale_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+ int instride = cinfo->input_components;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
+ inptr += instride;
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles multi-component colorspaces without conversion.
+ * We assume input_components == num_components.
+ */
+
+METHODDEF(void)
+null_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ register int ci;
+ int nc = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ /* It seems fastest to make a separate pass for each component. */
+ for (ci = 0; ci < nc; ci++) {
+ inptr = *input_buf;
+ outptr = output_buf[ci][output_row];
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
+ inptr += nc;
+ }
+ }
+ input_buf++;
+ output_row++;
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+null_method (j_compress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for input colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_converter (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_converter));
+ cinfo->cconvert = (struct jpeg_color_converter *) cconvert;
+ /* set start_pass to null method until we find out differently */
+ cconvert->pub.start_pass = null_method;
+
+ /* Make sure input_components agrees with in_color_space */
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->input_components != 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+#if RGB_PIXELSIZE != 3
+ if (cinfo->input_components != RGB_PIXELSIZE)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+#endif /* else share code with YCbCr */
+
+ case JCS_YCbCr:
+ if (cinfo->input_components != 3)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->input_components != 4)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->input_components < 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+ }
+
+ /* Check num_components, set conversion method based on requested space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_GRAYSCALE)
+ cconvert->pub.color_convert = grayscale_convert;
+ else if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_gray_convert;
+ } else if (cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = grayscale_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_ycc_convert;
+ } else if (cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = cmyk_ycck_convert;
+ } else if (cinfo->in_color_space == JCS_YCCK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default: /* allow null conversion of JCS_UNKNOWN */
+ if (cinfo->jpeg_color_space != cinfo->in_color_space ||
+ cinfo->num_components != cinfo->input_components)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ cconvert->pub.color_convert = null_convert;
+ break;
+ }
+}
diff --git a/gs/jpeg/jcdctmgr.c b/gs/jpeg/jcdctmgr.c
new file mode 100644
index 000000000..61fa79b9e
--- /dev/null
+++ b/gs/jpeg/jcdctmgr.c
@@ -0,0 +1,387 @@
+/*
+ * jcdctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the forward-DCT management logic.
+ * This code selects a particular DCT implementation to be used,
+ * and it performs related housekeeping chores including coefficient
+ * quantization.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_forward_dct pub; /* public fields */
+
+ /* Pointer to the DCT routine actually in use */
+ forward_DCT_method_ptr do_dct;
+
+ /* The actual post-DCT divisors --- not identical to the quant table
+ * entries, because of scaling (especially for an unnormalized DCT).
+ * Each table is given in normal array order.
+ */
+ DCTELEM * divisors[NUM_QUANT_TBLS];
+
+#ifdef DCT_FLOAT_SUPPORTED
+ /* Same as above for the floating-point case. */
+ float_DCT_method_ptr do_float_dct;
+ FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
+#endif
+} my_fdct_controller;
+
+typedef my_fdct_controller * my_fdct_ptr;
+
+
+/*
+ * Initialize for a processing pass.
+ * Verify that all referenced Q-tables are present, and set up
+ * the divisor table for each one.
+ * In the current implementation, DCT of all components is done during
+ * the first pass, even if only some components will be output in the
+ * first scan. Hence all components should be examined here.
+ */
+
+METHODDEF(void)
+start_pass_fdctmgr (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ int ci, qtblno, i;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtbl;
+ DCTELEM * dtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ qtblno = compptr->quant_tbl_no;
+ /* Make sure specified quantization table is present */
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ qtbl = cinfo->quant_tbl_ptrs[qtblno];
+ /* Compute divisors for this quant table */
+ /* We may do this more than once for same table, but it's not a big deal */
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ /* For LL&M IDCT method, divisors are equal to raw quantization
+ * coefficients multiplied by 8 (to counteract scaling).
+ */
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
+ }
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ */
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = (DCTELEM)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-3);
+ }
+ }
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ * What's actually stored is 1/divisor so that the inner loop can
+ * use a multiplication rather than a division.
+ */
+ FAST_FLOAT * fdtbl;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ if (fdct->float_divisors[qtblno] == NULL) {
+ fdct->float_divisors[qtblno] = (FAST_FLOAT *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(FAST_FLOAT));
+ }
+ fdtbl = fdct->float_divisors[qtblno];
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fdtbl[i] = (FAST_FLOAT)
+ (1.0 / (((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col] * 8.0)));
+ i++;
+ }
+ }
+ }
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Perform forward DCT on one or more blocks of a component.
+ *
+ * The input samples are taken from the sample_data[] array starting at
+ * position start_row/start_col, and moving to the right for any additional
+ * blocks. The quantized coefficients are returned in coef_blocks[].
+ */
+
+METHODDEF(void)
+forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for integer DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ forward_DCT_method_ptr do_dct = fdct->do_dct;
+ DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
+ DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
+ /* Load data into workspace, applying unsigned->signed conversion */
+ { register DCTELEM *workspaceptr;
+ register JSAMPROW elemptr;
+ register int elemr;
+
+ workspaceptr = workspace;
+ for (elemr = 0; elemr < DCTSIZE; elemr++) {
+ elemptr = sample_data[elemr] + start_col;
+#if DCTSIZE == 8 /* unroll the inner loop */
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+#else
+ { register int elemc;
+ for (elemc = DCTSIZE; elemc > 0; elemc--) {
+ *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
+ }
+ }
+#endif
+ }
+ }
+
+ /* Perform the DCT */
+ (*do_dct) (workspace);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register DCTELEM temp, qval;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ qval = divisors[i];
+ temp = workspace[i];
+ /* Divide the coefficient value by qval, ensuring proper rounding.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ *
+ * In most files, at least half of the output values will be zero
+ * (at default quantization settings, more like three-quarters...)
+ * so we should ensure that this case is fast. On many machines,
+ * a comparison is enough cheaper than a divide to make a special test
+ * a win. Since both inputs will be nonnegative, we need only test
+ * for a < b to discover whether a/b is 0.
+ * If your machine's division is fast enough, define FAST_DIVIDE.
+ */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a,b) a /= b
+#else
+#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
+#endif
+ if (temp < 0) {
+ temp = -temp;
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ temp = -temp;
+ } else {
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ }
+ output_ptr[i] = (JCOEF) temp;
+ }
+ }
+ }
+}
+
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+METHODDEF(void)
+forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for floating-point DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ float_DCT_method_ptr do_dct = fdct->do_float_dct;
+ FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
+ FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
+ /* Load data into workspace, applying unsigned->signed conversion */
+ { register FAST_FLOAT *workspaceptr;
+ register JSAMPROW elemptr;
+ register int elemr;
+
+ workspaceptr = workspace;
+ for (elemr = 0; elemr < DCTSIZE; elemr++) {
+ elemptr = sample_data[elemr] + start_col;
+#if DCTSIZE == 8 /* unroll the inner loop */
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+#else
+ { register int elemc;
+ for (elemc = DCTSIZE; elemc > 0; elemc--) {
+ *workspaceptr++ = (FAST_FLOAT)
+ (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+ }
+ }
+#endif
+ }
+ }
+
+ /* Perform the DCT */
+ (*do_dct) (workspace);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register FAST_FLOAT temp;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ /* Apply the quantization and scaling factor */
+ temp = workspace[i] * divisors[i];
+ /* Round to nearest integer.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ * The maximum coefficient size is +-16K (for 12-bit data), so this
+ * code should work for either 16-bit or 32-bit ints.
+ */
+ output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
+ }
+ }
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
+
+
+/*
+ * Initialize FDCT manager.
+ */
+
+GLOBAL(void)
+jinit_forward_dct (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct;
+ int i;
+
+ fdct = (my_fdct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_fdct_controller));
+ cinfo->fdct = (struct jpeg_forward_dct *) fdct;
+ fdct->pub.start_pass = start_pass_fdctmgr;
+
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ fdct->pub.forward_DCT = forward_DCT;
+ fdct->do_dct = jpeg_fdct_islow;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ fdct->pub.forward_DCT = forward_DCT;
+ fdct->do_dct = jpeg_fdct_ifast;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ fdct->pub.forward_DCT = forward_DCT_float;
+ fdct->do_float_dct = jpeg_fdct_float;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+
+ /* Mark divisor tables unallocated */
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ fdct->divisors[i] = NULL;
+#ifdef DCT_FLOAT_SUPPORTED
+ fdct->float_divisors[i] = NULL;
+#endif
+ }
+}
diff --git a/gs/jpeg/jchuff.c b/gs/jpeg/jchuff.c
new file mode 100644
index 000000000..b3eec8ada
--- /dev/null
+++ b/gs/jpeg/jchuff.c
@@ -0,0 +1,846 @@
+/*
+ * jchuff.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy encoding routines.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU. To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jchuff.h" /* Declarations shared with jcphuff.c */
+
+
+/* Expanded entropy encoder object for Huffman encoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ INT32 put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).put_buffer = (src).put_buffer, \
+ (dest).put_bits = (src).put_bits, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ savable_state saved; /* Bit buffer & DC state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
+ long * dc_count_ptrs[NUM_HUFF_TBLS];
+ long * ac_count_ptrs[NUM_HUFF_TBLS];
+#endif
+} huff_entropy_encoder;
+
+typedef huff_entropy_encoder * huff_entropy_ptr;
+
+/* Working state while writing an MCU.
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ savable_state cur; /* Current bit buffer & DC state */
+ j_compress_ptr cinfo; /* dump_buffer needs access to this */
+} working_state;
+
+
+/* Forward declarations */
+METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo));
+#ifdef ENTROPY_OPT_SUPPORTED
+METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo));
+#endif
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, dctbl, actbl;
+ jpeg_component_info * compptr;
+
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->pub.encode_mcu = encode_mcu_gather;
+ entropy->pub.finish_pass = finish_pass_gather;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ entropy->pub.encode_mcu = encode_mcu_huff;
+ entropy->pub.finish_pass = finish_pass_huff;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ actbl = compptr->ac_tbl_no;
+ /* Make sure requested tables are present */
+ /* (In gather mode, tables need not be allocated yet) */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
+ (cinfo->dc_huff_tbl_ptrs[dctbl] == NULL && !gather_statistics))
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ if (actbl < 0 || actbl >= NUM_HUFF_TBLS ||
+ (cinfo->ac_huff_tbl_ptrs[actbl] == NULL && !gather_statistics))
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->dc_count_ptrs[dctbl] == NULL)
+ entropy->dc_count_ptrs[dctbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long));
+ if (entropy->ac_count_ptrs[actbl] == NULL)
+ entropy->ac_count_ptrs[actbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long));
+#endif
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_c_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl],
+ & entropy->dc_derived_tbls[dctbl]);
+ jpeg_make_c_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl],
+ & entropy->ac_derived_tbls[actbl]);
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize bit buffer to empty */
+ entropy->saved.put_buffer = 0;
+ entropy->saved.put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * Note this is also used by jcphuff.c.
+ */
+
+GLOBAL(void)
+jpeg_make_c_derived_tbl (j_compress_ptr cinfo, JHUFF_TBL * htbl,
+ c_derived_tbl ** pdtbl)
+{
+ c_derived_tbl *dtbl;
+ int p, i, l, lastp, si;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (c_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(c_derived_tbl));
+ dtbl = *pdtbl;
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+ /* Note that this is in code-length order. */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ for (i = 1; i <= (int) htbl->bits[l]; i++)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* Note that this is in code-length order. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure C.3: generate encoding tables */
+ /* These are code and size indexed by symbol value */
+
+ /* Set any codeless symbols to have code length 0;
+ * this allows emit_bits to detect any attempt to emit such symbols.
+ */
+ MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
+
+ for (p = 0; p < lastp; p++) {
+ dtbl->ehufco[htbl->huffval[p]] = huffcode[p];
+ dtbl->ehufsi[htbl->huffval[p]] = huffsize[p];
+ }
+}
+
+
+/* Outputting bytes to the file */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte(state,val,action) \
+ { *(state)->next_output_byte++ = (JOCTET) (val); \
+ if (--(state)->free_in_buffer == 0) \
+ if (! dump_buffer(state)) \
+ { action; } }
+
+
+LOCAL(boolean)
+dump_buffer (working_state * state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+ struct jpeg_destination_mgr * dest = state->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (state->cinfo))
+ return FALSE;
+ /* After a successful buffer dump, must reset buffer pointers */
+ state->next_output_byte = dest->next_output_byte;
+ state->free_in_buffer = dest->free_in_buffer;
+ return TRUE;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits (working_state * state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = state->cur.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte(state, c, return FALSE);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte(state, 0, return FALSE);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ state->cur.put_buffer = put_buffer; /* update state variables */
+ state->cur.put_bits = put_bits;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+flush_bits (working_state * state)
+{
+ if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
+ return FALSE;
+ state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
+ state->cur.put_bits = 0;
+ return TRUE;
+}
+
+
+/* Encode a single block's worth of coefficients */
+
+LOCAL(boolean)
+encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
+ c_derived_tbl *dctbl, c_derived_tbl *actbl)
+{
+ register int temp, temp2;
+ register int nbits;
+ register int k, r, i;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = temp2 = block[0] - last_dc_val;
+
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+
+ /* Emit the Huffman-coded symbol for the number of bits */
+ if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ if (! emit_bits(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k < DCTSIZE2; k++) {
+ if ((temp = block[jpeg_natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
+ return FALSE;
+ r -= 16;
+ }
+
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+
+ /* Emit Huffman symbol for run length / number of bits */
+ i = (r << 4) + nbits;
+ if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (! emit_bits(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0]))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart (working_state * state, int restart_num)
+{
+ int ci;
+
+ if (! flush_bits(state))
+ return FALSE;
+
+ emit_byte(state, 0xFF, return FALSE);
+ emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
+ state->cur.last_dc_val[ci] = 0;
+
+ /* The restart counter is not updated until we successfully write the MCU. */
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of Huffman-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Load up working state */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! emit_restart(&state, entropy->next_restart_num))
+ return FALSE;
+ }
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ if (! encode_one_block(&state,
+ MCU_data[blkn][0], state.cur.last_dc_val[ci],
+ entropy->dc_derived_tbls[compptr->dc_tbl_no],
+ entropy->ac_derived_tbls[compptr->ac_tbl_no]))
+ return FALSE;
+ /* Update last_dc_val */
+ state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ /* Completed MCU, so update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+
+ /* Load up working state ... flush_bits needs it */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Flush out the last data */
+ if (! flush_bits(&state))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * This actually is optimization, in the sense that we find the best possible
+ * Huffman table(s) for the given data. We first scan the supplied data and
+ * count the number of uses of each symbol that is to be Huffman-coded.
+ * (This process must agree with the code above.) Then we build an
+ * optimal Huffman coding tree for the observed counts.
+ *
+ * The JPEG standard requires Huffman codes to be no more than 16 bits long.
+ * If some symbols have a very small but nonzero probability, the Huffman tree
+ * must be adjusted to meet the code length restriction. We currently use
+ * the adjustment method suggested in the JPEG spec. This method is *not*
+ * optimal; it may not choose the best possible limited-length code. But
+ * since the symbols involved are infrequently used, it's not clear that
+ * going to extra trouble is worthwhile.
+ */
+
+#ifdef ENTROPY_OPT_SUPPORTED
+
+
+/* Process a single block's worth of coefficients */
+
+LOCAL(void)
+htest_one_block (JCOEFPTR block, int last_dc_val,
+ long dc_counts[], long ac_counts[])
+{
+ register int temp;
+ register int nbits;
+ register int k, r;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = block[0] - last_dc_val;
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+
+ /* Count the Huffman symbol for the number of bits */
+ dc_counts[nbits]++;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k < DCTSIZE2; k++) {
+ if ((temp = block[jpeg_natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ ac_counts[0xF0]++;
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+
+ /* Count Huffman symbol for run length / number of bits */
+ ac_counts[(r << 4) + nbits]++;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ ac_counts[0]++;
+}
+
+
+/*
+ * Trial-encode one MCU's worth of Huffman-compressed coefficients.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(boolean)
+encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Take care of restart intervals if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Update restart state */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ htest_one_block(MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
+ entropy->dc_count_ptrs[compptr->dc_tbl_no],
+ entropy->ac_count_ptrs[compptr->ac_tbl_no]);
+ entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Generate the optimal coding for the given counts, fill htbl.
+ * Note this is also used by jcphuff.c.
+ */
+
+GLOBAL(void)
+jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
+{
+#define MAX_CLEN 32 /* assumed maximum initial code length */
+ UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
+ int codesize[257]; /* codesize[k] = code length of symbol k */
+ int others[257]; /* next symbol in current branch of tree */
+ int c1, c2;
+ int p, i, j;
+ long v;
+
+ /* This algorithm is explained in section K.2 of the JPEG standard */
+
+ MEMZERO(bits, SIZEOF(bits));
+ MEMZERO(codesize, SIZEOF(codesize));
+ for (i = 0; i < 257; i++)
+ others[i] = -1; /* init links to empty */
+
+ freq[256] = 1; /* make sure there is a nonzero count */
+ /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
+ * that no real symbol is given code-value of all ones, because 256
+ * will be placed in the largest codeword category.
+ */
+
+ /* Huffman's basic algorithm to assign optimal code lengths to symbols */
+
+ for (;;) {
+ /* Find the smallest nonzero frequency, set c1 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c1 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v) {
+ v = freq[i];
+ c1 = i;
+ }
+ }
+
+ /* Find the next smallest nonzero frequency, set c2 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c2 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v && i != c1) {
+ v = freq[i];
+ c2 = i;
+ }
+ }
+
+ /* Done if we've merged everything into one frequency */
+ if (c2 < 0)
+ break;
+
+ /* Else merge the two counts/trees */
+ freq[c1] += freq[c2];
+ freq[c2] = 0;
+
+ /* Increment the codesize of everything in c1's tree branch */
+ codesize[c1]++;
+ while (others[c1] >= 0) {
+ c1 = others[c1];
+ codesize[c1]++;
+ }
+
+ others[c1] = c2; /* chain c2 onto c1's tree branch */
+
+ /* Increment the codesize of everything in c2's tree branch */
+ codesize[c2]++;
+ while (others[c2] >= 0) {
+ c2 = others[c2];
+ codesize[c2]++;
+ }
+ }
+
+ /* Now count the number of symbols of each code length */
+ for (i = 0; i <= 256; i++) {
+ if (codesize[i]) {
+ /* The JPEG standard seems to think that this can't happen, */
+ /* but I'm paranoid... */
+ if (codesize[i] > MAX_CLEN)
+ ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+
+ bits[codesize[i]]++;
+ }
+ }
+
+ /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+ * Huffman procedure assigned any such lengths, we must adjust the coding.
+ * Here is what the JPEG spec says about how this next bit works:
+ * Since symbols are paired for the longest Huffman code, the symbols are
+ * removed from this length category two at a time. The prefix for the pair
+ * (which is one bit shorter) is allocated to one of the pair; then,
+ * skipping the BITS entry for that prefix length, a code word from the next
+ * shortest nonzero BITS entry is converted into a prefix for two code words
+ * one bit longer.
+ */
+
+ for (i = MAX_CLEN; i > 16; i--) {
+ while (bits[i] > 0) {
+ j = i - 2; /* find length of new prefix to be used */
+ while (bits[j] == 0)
+ j--;
+
+ bits[i] -= 2; /* remove two symbols */
+ bits[i-1]++; /* one goes in this length */
+ bits[j+1] += 2; /* two new symbols in this length */
+ bits[j]--; /* symbol of this length is now a prefix */
+ }
+ }
+
+ /* Remove the count for the pseudo-symbol 256 from the largest codelength */
+ while (bits[i] == 0) /* find largest codelength still in use */
+ i--;
+ bits[i]--;
+
+ /* Return final symbol counts (only for lengths 0..16) */
+ MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
+
+ /* Return a list of the symbols sorted by code length */
+ /* It's not real clear to me why we don't need to consider the codelength
+ * changes made above, but the JPEG spec seems to think this works.
+ */
+ p = 0;
+ for (i = 1; i <= MAX_CLEN; i++) {
+ for (j = 0; j <= 255; j++) {
+ if (codesize[j] == i) {
+ htbl->huffval[p] = (UINT8) j;
+ p++;
+ }
+ }
+ }
+
+ /* Set sent_table FALSE so updated table will be written to JPEG file. */
+ htbl->sent_table = FALSE;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, dctbl, actbl;
+ jpeg_component_info * compptr;
+ JHUFF_TBL **htblptr;
+ boolean did_dc[NUM_HUFF_TBLS];
+ boolean did_ac[NUM_HUFF_TBLS];
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ MEMZERO(did_dc, SIZEOF(did_dc));
+ MEMZERO(did_ac, SIZEOF(did_ac));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ actbl = compptr->ac_tbl_no;
+ if (! did_dc[dctbl]) {
+ htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]);
+ did_dc[dctbl] = TRUE;
+ }
+ if (! did_ac[actbl]) {
+ htblptr = & cinfo->ac_huff_tbl_ptrs[actbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]);
+ did_ac[actbl] = TRUE;
+ }
+ }
+}
+
+
+#endif /* ENTROPY_OPT_SUPPORTED */
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_huff_encoder (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
+#endif
+ }
+}
diff --git a/gs/jpeg/jchuff.h b/gs/jpeg/jchuff.h
new file mode 100644
index 000000000..fa4643a4e
--- /dev/null
+++ b/gs/jpeg/jchuff.h
@@ -0,0 +1,34 @@
+/*
+ * jchuff.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains declarations for Huffman entropy encoding routines
+ * that are shared between the sequential encoder (jchuff.c) and the
+ * progressive encoder (jcphuff.c). No other modules need to see these.
+ */
+
+/* Derived data constructed for each Huffman table */
+
+typedef struct {
+ unsigned int ehufco[256]; /* code for each symbol */
+ char ehufsi[256]; /* length of code for each symbol */
+ /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
+} c_derived_tbl;
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_make_c_derived_tbl jMkCDerived
+#define jpeg_gen_optimal_table jGenOptTbl
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Expand a Huffman table definition into the derived format */
+EXTERN(void) jpeg_make_c_derived_tbl
+ JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, c_derived_tbl ** pdtbl));
+
+/* Generate an optimal table definition given the specified counts */
+EXTERN(void) jpeg_gen_optimal_table
+ JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]));
diff --git a/gs/jpeg/jcinit.c b/gs/jpeg/jcinit.c
new file mode 100644
index 000000000..d96bb3777
--- /dev/null
+++ b/gs/jpeg/jcinit.c
@@ -0,0 +1,72 @@
+/*
+ * jcinit.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains initialization logic for the JPEG compressor.
+ * This routine is in charge of selecting the modules to be executed and
+ * making an initialization call to each one.
+ *
+ * Logically, this code belongs in jcmaster.c. It's split out because
+ * linking this routine implies linking the entire compression library.
+ * For a transcoding-only application, we want to be able to use jcmaster.c
+ * without linking in the whole library.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Master selection of compression modules.
+ * This is done once at the start of processing an image. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ */
+
+GLOBAL(void)
+jinit_compress_master (j_compress_ptr cinfo)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, FALSE /* full compression */);
+
+ /* Preprocessing */
+ if (! cinfo->raw_data_in) {
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ }
+ /* Forward DCT */
+ jinit_forward_dct(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ jinit_phuff_encoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* Need a full-image coefficient buffer in any multi-pass mode. */
+ jinit_c_coef_controller(cinfo,
+ (cinfo->num_scans > 1 || cinfo->optimize_coding));
+ jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
diff --git a/gs/jpeg/jcmainct.c b/gs/jpeg/jcmainct.c
new file mode 100644
index 000000000..e0279a7e0
--- /dev/null
+++ b/gs/jpeg/jcmainct.c
@@ -0,0 +1,293 @@
+/*
+ * jcmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for compression.
+ * The main buffer lies between the pre-processor and the JPEG
+ * compressor proper; it holds downsampled data in the JPEG colorspace.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Note: currently, there is no operating mode in which a full-image buffer
+ * is needed at this step. If there were, that mode could not be used with
+ * "raw data" input, since this module is bypassed in that case. However,
+ * we've left the code here for possible use in special applications.
+ */
+#undef FULL_MAIN_BUFFER_SUPPORTED
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_main_controller pub; /* public fields */
+
+ JDIMENSION cur_iMCU_row; /* number of current iMCU row */
+ JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */
+ boolean suspended; /* remember if we suspended output */
+ J_BUF_MODE pass_mode; /* current operating mode */
+
+ /* If using just a strip buffer, this points to the entire set of buffers
+ * (we allocate one for each component). In the full-image case, this
+ * points to the currently accessible strips of the virtual arrays.
+ */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* If using full-image storage, this array holds pointers to virtual-array
+ * control blocks for each component. Unused if not full-image storage.
+ */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+METHODDEF(void) process_data_buffer_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ /* Do nothing in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ main->cur_iMCU_row = 0; /* initialize counters */
+ main->rowgroup_ctr = 0;
+ main->suspended = FALSE;
+ main->pass_mode = pass_mode; /* save mode for use by process_data */
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ if (main->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ main->pub.process_data = process_data_simple_main;
+ break;
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ case JBUF_SAVE_SOURCE:
+ case JBUF_CRANK_DEST:
+ case JBUF_SAVE_AND_PASS:
+ if (main->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ main->pub.process_data = process_data_buffer_main;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This routine handles the simple pass-through mode,
+ * where we have only a strip buffer.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Read input data if we haven't filled the main buffer yet */
+ if (main->rowgroup_ctr < DCTSIZE)
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main->buffer, &main->rowgroup_ctr,
+ (JDIMENSION) DCTSIZE);
+
+ /* If we don't have a full iMCU row buffered, return to application for
+ * more data. Note that preprocessor will always pad to fill the iMCU row
+ * at the bottom of the image.
+ */
+ if (main->rowgroup_ctr != DCTSIZE)
+ return;
+
+ /* Send the completed row to the compressor */
+ if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main->suspended) {
+ (*in_row_ctr)--;
+ main->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main->suspended) {
+ (*in_row_ctr)++;
+ main->suspended = FALSE;
+ }
+ main->rowgroup_ctr = 0;
+ main->cur_iMCU_row++;
+ }
+}
+
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+
+/*
+ * Process some data.
+ * This routine handles all of the modes that use a full-size buffer.
+ */
+
+METHODDEF(void)
+process_data_buffer_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci;
+ jpeg_component_info *compptr;
+ boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
+
+ while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Realign the virtual buffers if at the start of an iMCU row. */
+ if (main->rowgroup_ctr == 0) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, main->whole_image[ci],
+ main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
+ }
+ /* In a read pass, pretend we just read some source data. */
+ if (! writing) {
+ *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
+ main->rowgroup_ctr = DCTSIZE;
+ }
+ }
+
+ /* If a write pass, read input data until the current iMCU row is full. */
+ /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
+ if (writing) {
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main->buffer, &main->rowgroup_ctr,
+ (JDIMENSION) DCTSIZE);
+ /* Return to application if we need more data to fill the iMCU row. */
+ if (main->rowgroup_ctr < DCTSIZE)
+ return;
+ }
+
+ /* Emit data, unless this is a sink-only pass. */
+ if (main->pass_mode != JBUF_SAVE_SOURCE) {
+ if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main->suspended) {
+ (*in_row_ctr)--;
+ main->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main->suspended) {
+ (*in_row_ctr)++;
+ main->suspended = FALSE;
+ }
+ }
+
+ /* If get here, we are done with this iMCU row. Mark buffer empty. */
+ main->rowgroup_ctr = 0;
+ main->cur_iMCU_row++;
+ }
+}
+
+#endif /* FULL_MAIN_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main;
+ int ci;
+ jpeg_component_info *compptr;
+
+ main = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_c_main_controller *) main;
+ main->pub.start_pass = start_pass_main;
+
+ /* We don't need to create a buffer in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ /* Create the buffer. It holds downsampled data, so each component
+ * may be of a different size.
+ */
+ if (need_full_buffer) {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component */
+ /* Note we pad the bottom to a multiple of the iMCU height */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ compptr->width_in_blocks * DCTSIZE,
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor) * DCTSIZE,
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ main->whole_image[0] = NULL; /* flag for no virtual arrays */
+#endif
+ /* Allocate a strip buffer for each component */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * DCTSIZE,
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
+ }
+ }
+}
diff --git a/gs/jpeg/jcmarker.c b/gs/jpeg/jcmarker.c
new file mode 100644
index 000000000..0198954c6
--- /dev/null
+++ b/gs/jpeg/jcmarker.c
@@ -0,0 +1,641 @@
+/*
+ * jcmarker.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write JPEG datastream markers.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/*
+ * Basic output routines.
+ *
+ * Note that we do not support suspension while writing a marker.
+ * Therefore, an application using suspension must ensure that there is
+ * enough buffer space for the initial markers (typ. 600-700 bytes) before
+ * calling jpeg_start_compress, and enough space to write the trailing EOI
+ * (a few bytes) before calling jpeg_finish_compress. Multipass compression
+ * modes are not supported at all with suspension, so those two are the only
+ * points where markers will be written.
+ */
+
+LOCAL(void)
+emit_byte (j_compress_ptr cinfo, int val)
+/* Emit a byte */
+{
+ struct jpeg_destination_mgr * dest = cinfo->dest;
+
+ *(dest->next_output_byte)++ = (JOCTET) val;
+ if (--dest->free_in_buffer == 0) {
+ if (! (*dest->empty_output_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+}
+
+
+LOCAL(void)
+emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
+/* Emit a marker code */
+{
+ emit_byte(cinfo, 0xFF);
+ emit_byte(cinfo, (int) mark);
+}
+
+
+LOCAL(void)
+emit_2bytes (j_compress_ptr cinfo, int value)
+/* Emit a 2-byte integer; these are always MSB first in JPEG files */
+{
+ emit_byte(cinfo, (value >> 8) & 0xFF);
+ emit_byte(cinfo, value & 0xFF);
+}
+
+
+/*
+ * Routines to write specific marker types.
+ */
+
+LOCAL(int)
+emit_dqt (j_compress_ptr cinfo, int index)
+/* Emit a DQT marker */
+/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
+{
+ JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
+ int prec;
+ int i;
+
+ if (qtbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
+
+ prec = 0;
+ for (i = 0; i < DCTSIZE2; i++) {
+ if (qtbl->quantval[i] > 255)
+ prec = 1;
+ }
+
+ if (! qtbl->sent_table) {
+ emit_marker(cinfo, M_DQT);
+
+ emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
+
+ emit_byte(cinfo, index + (prec<<4));
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ /* The table entries must be emitted in zigzag order. */
+ unsigned int qval = qtbl->quantval[jpeg_natural_order[i]];
+ if (prec)
+ emit_byte(cinfo, qval >> 8);
+ emit_byte(cinfo, qval & 0xFF);
+ }
+
+ qtbl->sent_table = TRUE;
+ }
+
+ return prec;
+}
+
+
+LOCAL(void)
+emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
+/* Emit a DHT marker */
+{
+ JHUFF_TBL * htbl;
+ int length, i;
+
+ if (is_ac) {
+ htbl = cinfo->ac_huff_tbl_ptrs[index];
+ index += 0x10; /* output index has AC bit set */
+ } else {
+ htbl = cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
+
+ if (! htbl->sent_table) {
+ emit_marker(cinfo, M_DHT);
+
+ length = 0;
+ for (i = 1; i <= 16; i++)
+ length += htbl->bits[i];
+
+ emit_2bytes(cinfo, length + 2 + 1 + 16);
+ emit_byte(cinfo, index);
+
+ for (i = 1; i <= 16; i++)
+ emit_byte(cinfo, htbl->bits[i]);
+
+ for (i = 0; i < length; i++)
+ emit_byte(cinfo, htbl->huffval[i]);
+
+ htbl->sent_table = TRUE;
+ }
+}
+
+
+LOCAL(void)
+emit_dac (j_compress_ptr cinfo)
+/* Emit a DAC marker */
+/* Since the useful info is so small, we want to emit all the tables in */
+/* one DAC marker. Therefore this routine does its own scan of the table. */
+{
+#ifdef C_ARITH_CODING_SUPPORTED
+ char dc_in_use[NUM_ARITH_TBLS];
+ char ac_in_use[NUM_ARITH_TBLS];
+ int length, i;
+ jpeg_component_info *compptr;
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ dc_in_use[i] = ac_in_use[i] = 0;
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ dc_in_use[compptr->dc_tbl_no] = 1;
+ ac_in_use[compptr->ac_tbl_no] = 1;
+ }
+
+ length = 0;
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ length += dc_in_use[i] + ac_in_use[i];
+
+ emit_marker(cinfo, M_DAC);
+
+ emit_2bytes(cinfo, length*2 + 2);
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ if (dc_in_use[i]) {
+ emit_byte(cinfo, i);
+ emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
+ }
+ if (ac_in_use[i]) {
+ emit_byte(cinfo, i + 0x10);
+ emit_byte(cinfo, cinfo->arith_ac_K[i]);
+ }
+ }
+#endif /* C_ARITH_CODING_SUPPORTED */
+}
+
+
+LOCAL(void)
+emit_dri (j_compress_ptr cinfo)
+/* Emit a DRI marker */
+{
+ emit_marker(cinfo, M_DRI);
+
+ emit_2bytes(cinfo, 4); /* fixed length */
+
+ emit_2bytes(cinfo, (int) cinfo->restart_interval);
+}
+
+
+LOCAL(void)
+emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
+/* Emit a SOF marker */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, code);
+
+ emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
+
+ /* Make sure image isn't bigger than SOF field can handle */
+ if ((long) cinfo->image_height > 65535L ||
+ (long) cinfo->image_width > 65535L)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
+
+ emit_byte(cinfo, cinfo->data_precision);
+ emit_2bytes(cinfo, (int) cinfo->image_height);
+ emit_2bytes(cinfo, (int) cinfo->image_width);
+
+ emit_byte(cinfo, cinfo->num_components);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ emit_byte(cinfo, compptr->component_id);
+ emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
+ emit_byte(cinfo, compptr->quant_tbl_no);
+ }
+}
+
+
+LOCAL(void)
+emit_sos (j_compress_ptr cinfo)
+/* Emit a SOS marker */
+{
+ int i, td, ta;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, M_SOS);
+
+ emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
+
+ emit_byte(cinfo, cinfo->comps_in_scan);
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ emit_byte(cinfo, compptr->component_id);
+ td = compptr->dc_tbl_no;
+ ta = compptr->ac_tbl_no;
+ if (cinfo->progressive_mode) {
+ /* Progressive mode: only DC or only AC tables are used in one scan;
+ * furthermore, Huffman coding of DC refinement uses no table at all.
+ * We emit 0 for unused field(s); this is recommended by the P&M text
+ * but does not seem to be specified in the standard.
+ */
+ if (cinfo->Ss == 0) {
+ ta = 0; /* DC scan */
+ if (cinfo->Ah != 0 && !cinfo->arith_code)
+ td = 0; /* no DC table either */
+ } else {
+ td = 0; /* AC scan */
+ }
+ }
+ emit_byte(cinfo, (td << 4) + ta);
+ }
+
+ emit_byte(cinfo, cinfo->Ss);
+ emit_byte(cinfo, cinfo->Se);
+ emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
+}
+
+
+LOCAL(void)
+emit_jfif_app0 (j_compress_ptr cinfo)
+/* Emit a JFIF-compliant APP0 marker */
+{
+ /*
+ * Length of APP0 block (2 bytes)
+ * Block ID (4 bytes - ASCII "JFIF")
+ * Zero byte (1 byte to terminate the ID string)
+ * Version Major, Minor (2 bytes - 0x01, 0x01)
+ * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
+ * Xdpu (2 bytes - dots per unit horizontal)
+ * Ydpu (2 bytes - dots per unit vertical)
+ * Thumbnail X size (1 byte)
+ * Thumbnail Y size (1 byte)
+ */
+
+ emit_marker(cinfo, M_APP0);
+
+ emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
+
+ emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0x49);
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0);
+ /* We currently emit version code 1.01 since we use no 1.02 features.
+ * This may avoid complaints from some older decoders.
+ */
+ emit_byte(cinfo, 1); /* Major version */
+ emit_byte(cinfo, 1); /* Minor version */
+ emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
+ emit_2bytes(cinfo, (int) cinfo->X_density);
+ emit_2bytes(cinfo, (int) cinfo->Y_density);
+ emit_byte(cinfo, 0); /* No thumbnail image */
+ emit_byte(cinfo, 0);
+}
+
+
+LOCAL(void)
+emit_adobe_app14 (j_compress_ptr cinfo)
+/* Emit an Adobe APP14 marker */
+{
+ /*
+ * Length of APP14 block (2 bytes)
+ * Block ID (5 bytes - ASCII "Adobe")
+ * Version Number (2 bytes - currently 100)
+ * Flags0 (2 bytes - currently 0)
+ * Flags1 (2 bytes - currently 0)
+ * Color transform (1 byte)
+ *
+ * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
+ * now in circulation seem to use Version = 100, so that's what we write.
+ *
+ * We write the color transform byte as 1 if the JPEG color space is
+ * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
+ * whether the encoder performed a transformation, which is pretty useless.
+ */
+
+ emit_marker(cinfo, M_APP14);
+
+ emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
+
+ emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */
+ emit_byte(cinfo, 0x64);
+ emit_byte(cinfo, 0x6F);
+ emit_byte(cinfo, 0x62);
+ emit_byte(cinfo, 0x65);
+ emit_2bytes(cinfo, 100); /* Version */
+ emit_2bytes(cinfo, 0); /* Flags0 */
+ emit_2bytes(cinfo, 0); /* Flags1 */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_YCbCr:
+ emit_byte(cinfo, 1); /* Color transform = 1 */
+ break;
+ case JCS_YCCK:
+ emit_byte(cinfo, 2); /* Color transform = 2 */
+ break;
+ default:
+ emit_byte(cinfo, 0); /* Color transform = 0 */
+ break;
+ }
+}
+
+
+/*
+ * This routine is exported for possible use by applications.
+ * The intended use is to emit COM or APPn markers after calling
+ * jpeg_start_compress() and before the first jpeg_write_scanlines() call
+ * (hence, after write_file_header but before write_frame_header).
+ * Other uses are not guaranteed to produce desirable results.
+ */
+
+METHODDEF(void)
+write_any_marker (j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen)
+/* Emit an arbitrary marker with parameters */
+{
+ if (datalen <= (unsigned int) 65533) { /* safety check */
+ emit_marker(cinfo, (JPEG_MARKER) marker);
+
+ emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
+
+ while (datalen--) {
+ emit_byte(cinfo, *dataptr);
+ dataptr++;
+ }
+ }
+}
+
+
+/*
+ * Write datastream header.
+ * This consists of an SOI and optional APPn markers.
+ * We recommend use of the JFIF marker, but not the Adobe marker,
+ * when using YCbCr or grayscale data. The JFIF marker should NOT
+ * be used for any other JPEG colorspace. The Adobe marker is helpful
+ * to distinguish RGB, CMYK, and YCCK colorspaces.
+ * Note that an application can write additional header markers after
+ * jpeg_start_compress returns.
+ */
+
+METHODDEF(void)
+write_file_header (j_compress_ptr cinfo)
+{
+ emit_marker(cinfo, M_SOI); /* first the SOI */
+
+ if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
+ emit_jfif_app0(cinfo);
+ if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
+ emit_adobe_app14(cinfo);
+}
+
+
+/*
+ * Write frame header.
+ * This consists of DQT and SOFn markers.
+ * Note that we do not emit the SOF until we have emitted the DQT(s).
+ * This avoids compatibility problems with incorrect implementations that
+ * try to error-check the quant table numbers as soon as they see the SOF.
+ */
+
+METHODDEF(void)
+write_frame_header (j_compress_ptr cinfo)
+{
+ int ci, prec;
+ boolean is_baseline;
+ jpeg_component_info *compptr;
+
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ prec = 0;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
+
+ /* Check for a non-baseline specification.
+ * Note we assume that Huffman table numbers won't be changed later.
+ */
+ if (cinfo->arith_code || cinfo->progressive_mode ||
+ cinfo->data_precision != 8) {
+ is_baseline = FALSE;
+ } else {
+ is_baseline = TRUE;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
+ is_baseline = FALSE;
+ }
+ if (prec && is_baseline) {
+ is_baseline = FALSE;
+ /* If it's baseline except for quantizer size, warn the user */
+ TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
+ }
+ }
+
+ /* Emit the proper SOF marker */
+ if (cinfo->arith_code) {
+ emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
+ } else {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (is_baseline)
+ emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
+ else
+ emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
+ }
+}
+
+
+/*
+ * Write scan header.
+ * This consists of DHT or DAC markers, optional DRI, and SOS.
+ * Compressed data will be written following the SOS.
+ */
+
+METHODDEF(void)
+write_scan_header (j_compress_ptr cinfo)
+{
+ int i;
+ jpeg_component_info *compptr;
+
+ if (cinfo->arith_code) {
+ /* Emit arith conditioning info. We may have some duplication
+ * if the file has multiple scans, but it's so small it's hardly
+ * worth worrying about.
+ */
+ emit_dac(cinfo);
+ } else {
+ /* Emit Huffman tables.
+ * Note that emit_dht() suppresses any duplicate tables.
+ */
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ if (cinfo->progressive_mode) {
+ /* Progressive mode: only DC or only AC tables are used in one scan */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ } else {
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+ } else {
+ /* Sequential mode: need both DC and AC tables */
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+ }
+ }
+
+ /* Emit DRI if required --- note that DRI value could change for each scan.
+ * If it doesn't, a tiny amount of space is wasted in multiple-scan files.
+ * We assume DRI will never be nonzero for one scan and zero for a later one.
+ */
+ if (cinfo->restart_interval)
+ emit_dri(cinfo);
+
+ emit_sos(cinfo);
+}
+
+
+/*
+ * Write datastream trailer.
+ */
+
+METHODDEF(void)
+write_file_trailer (j_compress_ptr cinfo)
+{
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Write an abbreviated table-specification datastream.
+ * This consists of SOI, DQT and DHT tables, and EOI.
+ * Any table that is defined and not marked sent_table = TRUE will be
+ * emitted. Note that all tables will be marked sent_table = TRUE at exit.
+ */
+
+METHODDEF(void)
+write_tables_only (j_compress_ptr cinfo)
+{
+ int i;
+
+ emit_marker(cinfo, M_SOI);
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if (cinfo->quant_tbl_ptrs[i] != NULL)
+ (void) emit_dqt(cinfo, i);
+ }
+
+ if (! cinfo->arith_code) {
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, FALSE);
+ if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, TRUE);
+ }
+ }
+
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Initialize the marker writer module.
+ */
+
+GLOBAL(void)
+jinit_marker_writer (j_compress_ptr cinfo)
+{
+ /* Create the subobject */
+ cinfo->marker = (struct jpeg_marker_writer *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(struct jpeg_marker_writer));
+ /* Initialize method pointers */
+ cinfo->marker->write_any_marker = write_any_marker;
+ cinfo->marker->write_file_header = write_file_header;
+ cinfo->marker->write_frame_header = write_frame_header;
+ cinfo->marker->write_scan_header = write_scan_header;
+ cinfo->marker->write_file_trailer = write_file_trailer;
+ cinfo->marker->write_tables_only = write_tables_only;
+}
diff --git a/gs/jpeg/jcmaster.c b/gs/jpeg/jcmaster.c
new file mode 100644
index 000000000..c3e1ef5f6
--- /dev/null
+++ b/gs/jpeg/jcmaster.c
@@ -0,0 +1,578 @@
+/*
+ * jcmaster.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG compressor.
+ * These routines are concerned with parameter validation, initial setup,
+ * and inter-pass control (determining the number of passes and the work
+ * to be done in each pass).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef enum {
+ main_pass, /* input data, also do first output step */
+ huff_opt_pass, /* Huffman code optimization pass */
+ output_pass /* data output pass */
+} c_pass_type;
+
+typedef struct {
+ struct jpeg_comp_master pub; /* public fields */
+
+ c_pass_type pass_type; /* the type of the current pass */
+
+ int pass_number; /* # of passes completed */
+ int total_passes; /* total # of passes needed */
+
+ int scan_number; /* current index in scan_info[] */
+} my_comp_master;
+
+typedef my_comp_master * my_master_ptr;
+
+
+/*
+ * Support routines that do various essential calculations.
+ */
+
+LOCAL(void)
+initial_setup (j_compress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+ int ci;
+ jpeg_component_info *compptr;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Sanity check on image dimensions */
+ if (cinfo->image_height <= 0 || cinfo->image_width <= 0
+ || cinfo->num_components <= 0 || cinfo->input_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* Width of an input scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Fill in the correct component_index value; don't rely on application */
+ compptr->component_index = ci;
+ /* For compression, we never do DCT scaling. */
+ compptr->DCT_scaled_size = DCTSIZE;
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * DCTSIZE));
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) cinfo->max_h_samp_factor);
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) cinfo->max_v_samp_factor);
+ /* Mark component needed (this flag isn't actually used for compression) */
+ compptr->component_needed = TRUE;
+ }
+
+ /* Compute number of fully interleaved MCU rows (number of times that
+ * main controller will call coefficient controller).
+ */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor*DCTSIZE));
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(void)
+validate_script (j_compress_ptr cinfo)
+/* Verify that the scan script in cinfo->scan_info[] is valid; also
+ * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
+ */
+{
+ const jpeg_scan_info * scanptr;
+ int scanno, ncomps, ci, coefi, thisi;
+ int Ss, Se, Ah, Al;
+ boolean component_sent[MAX_COMPONENTS];
+#ifdef C_PROGRESSIVE_SUPPORTED
+ int * last_bitpos_ptr;
+ int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
+ /* -1 until that coefficient has been seen; then last Al for it */
+#endif
+
+ if (cinfo->num_scans <= 0)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+
+ /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
+ * for progressive JPEG, no scan can have this.
+ */
+ scanptr = cinfo->scan_info;
+ if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ cinfo->progressive_mode = TRUE;
+ last_bitpos_ptr = & last_bitpos[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (coefi = 0; coefi < DCTSIZE2; coefi++)
+ *last_bitpos_ptr++ = -1;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ component_sent[ci] = FALSE;
+ }
+
+ for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {
+ /* Validate component indexes */
+ ncomps = scanptr->comps_in_scan;
+ if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (thisi < 0 || thisi >= cinfo->num_components)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ /* Components must appear in SOF order within each scan */
+ if (ci > 0 && thisi <= scanptr->component_index[ci-1])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ }
+ /* Validate progression parameters */
+ Ss = scanptr->Ss;
+ Se = scanptr->Se;
+ Ah = scanptr->Ah;
+ Al = scanptr->Al;
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
+ Ah < 0 || Ah > 13 || Al < 0 || Al > 13)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ if (Ss == 0) {
+ if (Se != 0) /* DC and AC together not OK */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ if (ncomps != 1) /* AC scans must be for only one component */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ for (ci = 0; ci < ncomps; ci++) {
+ last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
+ if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ for (coefi = Ss; coefi <= Se; coefi++) {
+ if (last_bitpos_ptr[coefi] < 0) {
+ /* first scan of this coefficient */
+ if (Ah != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ /* not first scan */
+ if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ last_bitpos_ptr[coefi] = Al;
+ }
+ }
+#endif
+ } else {
+ /* For sequential JPEG, all progression parameters must be these: */
+ if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ /* Make sure components are not sent twice */
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (component_sent[thisi])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ component_sent[thisi] = TRUE;
+ }
+ }
+ }
+
+ /* Now verify that everything got sent. */
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ /* For progressive mode, we only check that at least some DC data
+ * got sent for each component; the spec does not require that all bits
+ * of all coefficients be transmitted. Would it be wiser to enforce
+ * transmission of all coefficient bits??
+ */
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (last_bitpos[ci][0] < 0)
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+#endif
+ } else {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (! component_sent[ci])
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+ }
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+LOCAL(void)
+select_scan_parameters (j_compress_ptr cinfo)
+/* Set up the scan parameters for the current scan */
+{
+ int ci;
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (cinfo->scan_info != NULL) {
+ /* Prepare for current scan --- the script is already validated */
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
+
+ cinfo->comps_in_scan = scanptr->comps_in_scan;
+ for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
+ cinfo->cur_comp_info[ci] =
+ &cinfo->comp_info[scanptr->component_index[ci]];
+ }
+ cinfo->Ss = scanptr->Ss;
+ cinfo->Se = scanptr->Se;
+ cinfo->Ah = scanptr->Ah;
+ cinfo->Al = scanptr->Al;
+ }
+ else
+#endif
+ {
+ /* Prepare for single sequential-JPEG scan containing all components */
+ if (cinfo->num_components > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPS_IN_SCAN);
+ cinfo->comps_in_scan = cinfo->num_components;
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
+ }
+ cinfo->Ss = 0;
+ cinfo->Se = DCTSIZE2-1;
+ cinfo->Ah = 0;
+ cinfo->Al = 0;
+ }
+}
+
+
+LOCAL(void)
+per_scan_setup (j_compress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = DCTSIZE;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width,
+ (long) (cinfo->max_h_samp_factor*DCTSIZE));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor*DCTSIZE));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+
+ /* Convert restart specified in rows to actual MCU count. */
+ /* Note that count must fit in 16 bits, so we provide limiting. */
+ if (cinfo->restart_in_rows > 0) {
+ long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;
+ cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);
+ }
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each pass. We determine which modules
+ * will be active during this pass and give them appropriate start_pass calls.
+ * We also set is_last_pass to indicate whether any more passes will be
+ * required.
+ */
+
+METHODDEF(void)
+prepare_for_pass (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ switch (master->pass_type) {
+ case main_pass:
+ /* Initial pass: will collect input data, and do either Huffman
+ * optimization or data output for the first scan.
+ */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (! cinfo->raw_data_in) {
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->downsample->start_pass) (cinfo);
+ (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ (*cinfo->fdct->start_pass) (cinfo);
+ (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
+ (*cinfo->coef->start_pass) (cinfo,
+ (master->total_passes > 1 ?
+ JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ if (cinfo->optimize_coding) {
+ /* No immediate data output; postpone writing frame/scan headers */
+ master->pub.call_pass_startup = FALSE;
+ } else {
+ /* Will write frame/scan headers at first jpeg_write_scanlines call */
+ master->pub.call_pass_startup = TRUE;
+ }
+ break;
+#ifdef ENTROPY_OPT_SUPPORTED
+ case huff_opt_pass:
+ /* Do Huffman optimization for a scan after the first one. */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) {
+ (*cinfo->entropy->start_pass) (cinfo, TRUE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ }
+ /* Special case: Huffman DC refinement scans need no Huffman table
+ * and therefore we can skip the optimization pass for them.
+ */
+ master->pass_type = output_pass;
+ master->pass_number++;
+ /*FALLTHROUGH*/
+#endif
+ case output_pass:
+ /* Do a data-output pass. */
+ /* We need not repeat per-scan setup if prior optimization pass did it. */
+ if (! cinfo->optimize_coding) {
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ }
+ (*cinfo->entropy->start_pass) (cinfo, FALSE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ /* We emit frame/scan headers now */
+ if (master->scan_number == 0)
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ }
+
+ master->pub.is_last_pass = (master->pass_number == master->total_passes-1);
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->total_passes;
+ }
+}
+
+
+/*
+ * Special start-of-pass hook.
+ * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
+ * In single-pass processing, we need this hook because we don't want to
+ * write frame/scan headers during jpeg_start_compress; we want to let the
+ * application write COM markers etc. between jpeg_start_compress and the
+ * jpeg_write_scanlines loop.
+ * In multi-pass processing, this routine is not used.
+ */
+
+METHODDEF(void)
+pass_startup (j_compress_ptr cinfo)
+{
+ cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */
+
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+}
+
+
+/*
+ * Finish up at end of pass.
+ */
+
+METHODDEF(void)
+finish_pass_master (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* The entropy coder always needs an end-of-pass call,
+ * either to analyze statistics or to flush its output buffer.
+ */
+ (*cinfo->entropy->finish_pass) (cinfo);
+
+ /* Update state for next pass */
+ switch (master->pass_type) {
+ case main_pass:
+ /* next pass is either output of scan 0 (after optimization)
+ * or output of scan 1 (if no optimization).
+ */
+ master->pass_type = output_pass;
+ if (! cinfo->optimize_coding)
+ master->scan_number++;
+ break;
+ case huff_opt_pass:
+ /* next pass is always output of current scan */
+ master->pass_type = output_pass;
+ break;
+ case output_pass:
+ /* next pass is either optimization or output of next scan */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ master->scan_number++;
+ break;
+ }
+
+ master->pass_number++;
+}
+
+
+/*
+ * Initialize master compression control.
+ */
+
+GLOBAL(void)
+jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_comp_master));
+ cinfo->master = (struct jpeg_comp_master *) master;
+ master->pub.prepare_for_pass = prepare_for_pass;
+ master->pub.pass_startup = pass_startup;
+ master->pub.finish_pass = finish_pass_master;
+ master->pub.is_last_pass = FALSE;
+
+ /* Validate parameters, determine derived values */
+ initial_setup(cinfo);
+
+ if (cinfo->scan_info != NULL) {
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ validate_script(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ cinfo->num_scans = 1;
+ }
+
+ if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */
+ cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
+
+ /* Initialize my private state */
+ if (transcode_only) {
+ /* no main pass in transcoding */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ else
+ master->pass_type = output_pass;
+ } else {
+ /* for normal compression, first pass is always this type: */
+ master->pass_type = main_pass;
+ }
+ master->scan_number = 0;
+ master->pass_number = 0;
+ if (cinfo->optimize_coding)
+ master->total_passes = cinfo->num_scans * 2;
+ else
+ master->total_passes = cinfo->num_scans;
+}
diff --git a/gs/jpeg/jcomapi.c b/gs/jpeg/jcomapi.c
new file mode 100644
index 000000000..b518ec62c
--- /dev/null
+++ b/gs/jpeg/jcomapi.c
@@ -0,0 +1,94 @@
+/*
+ * jcomapi.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface routines that are used for both
+ * compression and decompression.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Abort processing of a JPEG compression or decompression operation,
+ * but don't destroy the object itself.
+ *
+ * For this, we merely clean up all the nonpermanent memory pools.
+ * Note that temp files (virtual arrays) are not allowed to belong to
+ * the permanent pool, so we will be able to close all temp files here.
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_abort (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
+ (*cinfo->mem->free_pool) (cinfo, pool);
+ }
+
+ /* Reset overall state for possible reuse of object */
+ cinfo->global_state = (cinfo->is_decompressor ? DSTATE_START : CSTATE_START);
+}
+
+
+/*
+ * Destruction of a JPEG object.
+ *
+ * Everything gets deallocated except the master jpeg_compress_struct itself
+ * and the error manager struct. Both of these are supplied by the application
+ * and must be freed, if necessary, by the application. (Often they are on
+ * the stack and so don't need to be freed anyway.)
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_destroy (j_common_ptr cinfo)
+{
+ /* We need only tell the memory manager to release everything. */
+ /* NB: mem pointer is NULL if memory mgr failed to initialize. */
+ if (cinfo->mem != NULL)
+ (*cinfo->mem->self_destruct) (cinfo);
+ cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */
+ cinfo->global_state = 0; /* mark it destroyed */
+}
+
+
+/*
+ * Convenience routines for allocating quantization and Huffman tables.
+ * (Would jutils.c be a more reasonable place to put these?)
+ */
+
+GLOBAL(JQUANT_TBL *)
+jpeg_alloc_quant_table (j_common_ptr cinfo)
+{
+ JQUANT_TBL *tbl;
+
+ tbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
+
+
+GLOBAL(JHUFF_TBL *)
+jpeg_alloc_huff_table (j_common_ptr cinfo)
+{
+ JHUFF_TBL *tbl;
+
+ tbl = (JHUFF_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
diff --git a/gs/jpeg/jconfig.bcc b/gs/jpeg/jconfig.bcc
new file mode 100644
index 000000000..c6c53ff63
--- /dev/null
+++ b/gs/jpeg/jconfig.bcc
@@ -0,0 +1,48 @@
+/* jconfig.bcc --- jconfig.h for Borland C (Turbo C) on MS-DOS or OS/2. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#ifdef __MSDOS__
+#define NEED_FAR_POINTERS /* for small or medium memory model */
+#endif
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN /* this assumes you have -w-stu in CFLAGS */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#ifdef __MSDOS__
+#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */
+#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */
+#define USE_FMEM /* Borland has _fmemcpy() and _fmemset() */
+#endif
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE /* Borland has setmode() */
+#ifdef __MSDOS__
+#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */
+#endif
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.cfg b/gs/jpeg/jconfig.cfg
new file mode 100644
index 000000000..36a04fa84
--- /dev/null
+++ b/gs/jpeg/jconfig.cfg
@@ -0,0 +1,44 @@
+/* jconfig.cfg --- source file edited by configure script */
+/* see jconfig.doc for explanations */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UNSIGNED_SHORT
+#undef void
+#undef const
+#undef CHAR_IS_UNSIGNED
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+/* Define this if you get warnings about undefined structures. */
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+#undef INLINE
+/* These are for configuring the JPEG memory manager. */
+#undef DEFAULT_MAX_MEM
+#undef NO_MKTEMP
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
+#undef PROGRESS_REPORT
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.dj b/gs/jpeg/jconfig.dj
new file mode 100644
index 000000000..f759a9dbd
--- /dev/null
+++ b/gs/jpeg/jconfig.dj
@@ -0,0 +1,38 @@
+/* jconfig.dj --- jconfig.h for DJGPP (Delorie's GNU C port) on MS-DOS. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS /* DJGPP uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE /* optional */
+#define USE_SETMODE /* Needed to make one-file style work in DJGPP */
+#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.doc b/gs/jpeg/jconfig.doc
new file mode 100644
index 000000000..c18d1c064
--- /dev/null
+++ b/gs/jpeg/jconfig.doc
@@ -0,0 +1,155 @@
+/*
+ * jconfig.doc
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file documents the configuration options that are required to
+ * customize the JPEG software for a particular system.
+ *
+ * The actual configuration options for a particular installation are stored
+ * in jconfig.h. On many machines, jconfig.h can be generated automatically
+ * or copied from one of the "canned" jconfig files that we supply. But if
+ * you need to generate a jconfig.h file by hand, this file tells you how.
+ *
+ * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING.
+ * EDIT A COPY NAMED JCONFIG.H.
+ */
+
+
+/*
+ * These symbols indicate the properties of your machine or compiler.
+ * #define the symbol if yes, #undef it if no.
+ */
+
+/* Does your compiler support function prototypes?
+ * (If not, you also need to use ansi2knr, see install.doc)
+ */
+#define HAVE_PROTOTYPES
+
+/* Does your compiler support the declaration "unsigned char" ?
+ * How about "unsigned short" ?
+ */
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+
+/* Define "void" as "char" if your compiler doesn't know about type void.
+ * NOTE: be sure to define void such that "void *" represents the most general
+ * pointer type, e.g., that returned by malloc().
+ */
+/* #define void char */
+
+/* Define "const" as empty if your compiler doesn't know the "const" keyword.
+ */
+/* #define const */
+
+/* Define this if an ordinary "char" type is unsigned.
+ * If you're not sure, leaving it undefined will work at some cost in speed.
+ * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
+ */
+#undef CHAR_IS_UNSIGNED
+
+/* Define this if your system has an ANSI-conforming <stddef.h> file.
+ */
+#define HAVE_STDDEF_H
+
+/* Define this if your system has an ANSI-conforming <stdlib.h> file.
+ */
+#define HAVE_STDLIB_H
+
+/* Define this if your system does not have an ANSI/SysV <string.h>,
+ * but does have a BSD-style <strings.h>.
+ */
+#undef NEED_BSD_STRINGS
+
+/* Define this if your system does not provide typedef size_t in any of the
+ * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
+ * <sys/types.h> instead.
+ */
+#undef NEED_SYS_TYPES_H
+
+/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
+ * unless you are using a large-data memory model or 80386 flat-memory mode.
+ * On less brain-damaged CPUs this symbol must not be defined.
+ * (Defining this symbol causes large data structures to be referenced through
+ * "far" pointers and to be allocated with a special version of malloc.)
+ */
+#undef NEED_FAR_POINTERS
+
+/* Define this if your linker needs global names to be unique in less
+ * than the first 15 characters.
+ */
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+/* Although a real ANSI C compiler can deal perfectly well with pointers to
+ * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
+ * and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
+ * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
+ * actually get "missing structure definition" warnings or errors while
+ * compiling the JPEG code.
+ */
+#undef INCOMPLETE_TYPES_BROKEN
+
+
+/*
+ * The following options affect code selection within the JPEG library,
+ * but they don't need to be visible to applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+
+/* Define this if your compiler implements ">>" on signed values as a logical
+ * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
+ * which is the normal and rational definition.
+ */
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+
+#endif /* JPEG_INTERNALS */
+
+
+/*
+ * The remaining options do not affect the JPEG library proper,
+ * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
+ * Other applications can ignore these.
+ */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+/* These defines indicate which image (non-JPEG) file formats are allowed. */
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+/* Define this if you want to name both input and output files on the command
+ * line, rather than using stdout and optionally stdin. You MUST do this if
+ * your system can't cope with binary I/O to stdin/stdout. See comments at
+ * head of cjpeg.c or djpeg.c.
+ */
+#undef TWO_FILE_COMMANDLINE
+
+/* Define this if your system needs explicit cleanup of temporary files.
+ * This is crucial under MS-DOS, where the temporary "files" may be areas
+ * of extended memory; on most other systems it's not as important.
+ */
+#undef NEED_SIGNAL_CATCHER
+
+/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
+ * This is necessary on systems that distinguish text files from binary files,
+ * and is harmless on most systems that don't. If you have one of the rare
+ * systems that complains about the "b" spec, define this symbol.
+ */
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg.
+ */
+#undef PROGRESS_REPORT
+
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.h b/gs/jpeg/jconfig.h
new file mode 100644
index 000000000..25c413d1b
--- /dev/null
+++ b/gs/jpeg/jconfig.h
@@ -0,0 +1,45 @@
+/* jconfig.h. Generated automatically by configure. */
+/* jconfig.cfg --- source file edited by configure script */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+#undef void
+#undef const
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+/* Define this if you get warnings about undefined structures. */
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+#define INLINE inline
+/* These are for configuring the JPEG memory manager. */
+#undef DEFAULT_MAX_MEM
+#undef NO_MKTEMP
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
+#undef PROGRESS_REPORT
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.manx b/gs/jpeg/jconfig.manx
new file mode 100644
index 000000000..6dd0d008e
--- /dev/null
+++ b/gs/jpeg/jconfig.manx
@@ -0,0 +1,43 @@
+/* jconfig.manx --- jconfig.h for Amiga systems using Manx Aztec C ver 5.x. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */
+
+#define SHORTxSHORT_32 /* produces better DCT code with Aztec C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#define signal_catcher _abort /* hack for Aztec C naming requirements */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.mc6 b/gs/jpeg/jconfig.mc6
new file mode 100644
index 000000000..c55082df4
--- /dev/null
+++ b/gs/jpeg/jconfig.mc6
@@ -0,0 +1,52 @@
+/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#define NEED_FAR_POINTERS /* for small or medium memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */
+
+#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */
+
+#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */
+
+#define NEED_FHEAPMIN /* far heap management routines are broken */
+
+#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */
+/* Note: the above define is known to improve the code with Microsoft C 6.00A.
+ * I do not know whether it is good for later compiler versions.
+ * Please report any info on this point to jpeg-info@uunet.uu.net.
+ */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE /* Microsoft has setmode() */
+#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.sas b/gs/jpeg/jconfig.sas
new file mode 100644
index 000000000..efdac2229
--- /dev/null
+++ b/gs/jpeg/jconfig.sas
@@ -0,0 +1,43 @@
+/* jconfig.sas --- jconfig.h for Amiga systems using SAS C 6.0 and up. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */
+
+#define NO_MKTEMP /* SAS C doesn't have mktemp() */
+
+#define SHORTxSHORT_32 /* produces better DCT code with SAS C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.st b/gs/jpeg/jconfig.st
new file mode 100644
index 000000000..4421b7a1a
--- /dev/null
+++ b/gs/jpeg/jconfig.st
@@ -0,0 +1,42 @@
+/* jconfig.st --- jconfig.h for Atari ST/STE/TT using Pure C or Turbo C. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#define INCOMPLETE_TYPES_BROKEN /* suppress undefined-structure warnings */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define ALIGN_TYPE long /* apparently double is a weird size? */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE /* optional -- undef if you like Unix style */
+/* Note: if you undef TWO_FILE_COMMANDLINE, you may need to define
+ * USE_SETMODE. Some Atari compilers require it, some do not.
+ */
+#define NEED_SIGNAL_CATCHER /* needed if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.vms b/gs/jpeg/jconfig.vms
new file mode 100644
index 000000000..55a6ffba5
--- /dev/null
+++ b/gs/jpeg/jconfig.vms
@@ -0,0 +1,37 @@
+/* jconfig.vms --- jconfig.h for use on Digital VMS. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE /* Needed on VMS */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jconfig.wat b/gs/jpeg/jconfig.wat
new file mode 100644
index 000000000..6cc545bae
--- /dev/null
+++ b/gs/jpeg/jconfig.wat
@@ -0,0 +1,38 @@
+/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */
+/* see jconfig.doc for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#define CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE /* optional */
+#define USE_SETMODE /* Needed to make one-file style work in Watcom */
+#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/gs/jpeg/jcparam.c b/gs/jpeg/jcparam.c
new file mode 100644
index 000000000..54871d5b3
--- /dev/null
+++ b/gs/jpeg/jcparam.c
@@ -0,0 +1,574 @@
+/*
+ * jcparam.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains optional default-setting code for the JPEG compressor.
+ * Applications do not have to use this file, but those that don't use it
+ * must know a lot more about the innards of the JPEG code.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Quantization table setup routines
+ */
+
+GLOBAL(void)
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor, boolean force_baseline)
+/* Define a quantization table equal to the basic_table times
+ * a scale factor (given as a percentage).
+ * If force_baseline is TRUE, the computed quantization table entries
+ * are limited to 1..255 for JPEG baseline compatibility.
+ */
+{
+ JQUANT_TBL ** qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];
+ int i;
+ long temp;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;
+ /* limit the values to the valid range */
+ if (temp <= 0L) temp = 1L;
+ if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
+ if (force_baseline && temp > 255L)
+ temp = 255L; /* limit to baseline range if requested */
+ (*qtblptr)->quantval[i] = (UINT16) temp;
+ }
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*qtblptr)->sent_table = FALSE;
+}
+
+
+GLOBAL(void)
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+ boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and a straight percentage-scaling quality scale. In most cases it's better
+ * to use jpeg_set_quality (below); this entry point is provided for
+ * applications that insist on a linear percentage scaling.
+ */
+{
+ /* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+ static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ };
+ static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ /* Set up two quantization tables using the specified scaling */
+ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+ scale_factor, force_baseline);
+ jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+ scale_factor, force_baseline);
+}
+
+
+GLOBAL(int)
+jpeg_quality_scaling (int quality)
+/* Convert a user-specified quality rating to a percentage scaling factor
+ * for an underlying quantization table, using our recommended scaling curve.
+ * The input 'quality' factor should be 0 (terrible) to 100 (very good).
+ */
+{
+ /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */
+ if (quality <= 0) quality = 1;
+ if (quality > 100) quality = 100;
+
+ /* The basic table is used as-is (scaling 100) for a quality of 50.
+ * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+ * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+ * to make all the table entries 1 (hence, minimum quantization loss).
+ * Qualities 1..50 are converted to scaling percentage 5000/Q.
+ */
+ if (quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality*2;
+
+ return quality;
+}
+
+
+GLOBAL(void)
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables.
+ * This is the standard quality-adjusting entry point for typical user
+ * interfaces; only those who want detailed control over quantization tables
+ * would use the preceding three routines directly.
+ */
+{
+ /* Convert user 0-100 rating to percentage scaling */
+ quality = jpeg_quality_scaling(quality);
+
+ /* Set up standard quality tables */
+ jpeg_set_linear_quality(cinfo, quality, force_baseline);
+}
+
+
+/*
+ * Huffman table setup routines
+ */
+
+LOCAL(void)
+add_huff_table (j_compress_ptr cinfo,
+ JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
+/* Define a Huffman table */
+{
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+ MEMCOPY((*htblptr)->huffval, val, SIZEOF((*htblptr)->huffval));
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*htblptr)->sent_table = FALSE;
+}
+
+
+LOCAL(void)
+std_huff_tables (j_compress_ptr cinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+ static const UINT8 bits_dc_luminance[17] =
+ { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_luminance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_dc_chrominance[17] =
+ { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_chrominance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_ac_luminance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+ static const UINT8 val_ac_luminance[] =
+ { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ static const UINT8 bits_ac_chrominance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+ static const UINT8 val_ac_chrominance[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance, val_dc_luminance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance, val_ac_luminance);
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance, val_dc_chrominance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+/*
+ * Default parameter setup for compression.
+ *
+ * Applications that don't choose to use this routine must do their
+ * own setup of all these parameters. Alternately, you can call this
+ * to establish defaults and then alter parameters selectively. This
+ * is the recommended approach since, if we add any new parameters,
+ * your code will still work (they'll be set to reasonable defaults).
+ */
+
+GLOBAL(void)
+jpeg_set_defaults (j_compress_ptr cinfo)
+{
+ int i;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Allocate comp_info array large enough for maximum component count.
+ * Array is made permanent in case application wants to compress
+ * multiple images at same param settings.
+ */
+ if (cinfo->comp_info == NULL)
+ cinfo->comp_info = (jpeg_component_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ MAX_COMPONENTS * SIZEOF(jpeg_component_info));
+
+ /* Initialize everything not dependent on the color space */
+
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+ /* Set up two quantization tables using default quality of 75 */
+ jpeg_set_quality(cinfo, 75, TRUE);
+ /* Set up two Huffman tables */
+ std_huff_tables(cinfo);
+
+ /* Initialize default arithmetic coding conditioning */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+
+ /* Default is no multiple-scan output */
+ cinfo->scan_info = NULL;
+ cinfo->num_scans = 0;
+
+ /* Expect normal source image, not raw downsampled data */
+ cinfo->raw_data_in = FALSE;
+
+ /* Use Huffman coding, not arithmetic coding, by default */
+ cinfo->arith_code = FALSE;
+
+ /* By default, don't do extra passes to optimize entropy coding */
+ cinfo->optimize_coding = FALSE;
+ /* The standard Huffman tables are only valid for 8-bit data precision.
+ * If the precision is higher, force optimization on so that usable
+ * tables will be computed. This test can be removed if default tables
+ * are supplied that are valid for the desired precision.
+ */
+ if (cinfo->data_precision > 8)
+ cinfo->optimize_coding = TRUE;
+
+ /* By default, use the simpler non-cosited sampling alignment */
+ cinfo->CCIR601_sampling = FALSE;
+
+ /* No input smoothing */
+ cinfo->smoothing_factor = 0;
+
+ /* DCT algorithm preference */
+ cinfo->dct_method = JDCT_DEFAULT;
+
+ /* No restart markers */
+ cinfo->restart_interval = 0;
+ cinfo->restart_in_rows = 0;
+
+ /* Fill in default JFIF marker parameters. Note that whether the marker
+ * will actually be written is determined by jpeg_set_colorspace.
+ */
+ cinfo->density_unit = 0; /* Pixel size is unknown by default */
+ cinfo->X_density = 1; /* Pixel aspect ratio is square by default */
+ cinfo->Y_density = 1;
+
+ /* Choose JPEG colorspace based on input space, set defaults accordingly */
+
+ jpeg_default_colorspace(cinfo);
+}
+
+
+/*
+ * Select an appropriate JPEG colorspace for in_color_space.
+ */
+
+GLOBAL(void)
+jpeg_default_colorspace (j_compress_ptr cinfo)
+{
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+ break;
+ case JCS_RGB:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_YCbCr:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_CMYK:
+ jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */
+ break;
+ case JCS_YCCK:
+ jpeg_set_colorspace(cinfo, JCS_YCCK);
+ break;
+ case JCS_UNKNOWN:
+ jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ }
+}
+
+
+/*
+ * Set the JPEG colorspace, and choose colorspace-dependent default values.
+ */
+
+GLOBAL(void)
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+{
+ jpeg_component_info * compptr;
+ int ci;
+
+#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
+ (compptr = &cinfo->comp_info[index], \
+ compptr->component_id = (id), \
+ compptr->h_samp_factor = (hsamp), \
+ compptr->v_samp_factor = (vsamp), \
+ compptr->quant_tbl_no = (quant), \
+ compptr->dc_tbl_no = (dctbl), \
+ compptr->ac_tbl_no = (actbl) )
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* For all colorspaces, we use Q and Huff tables 0 for luminance components,
+ * tables 1 for chrominance components.
+ */
+
+ cinfo->jpeg_color_space = colorspace;
+
+ cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */
+ cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */
+
+ switch (colorspace) {
+ case JCS_GRAYSCALE:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 1;
+ /* JFIF specifies component ID 1 */
+ SET_COMP(0, 1, 1,1, 0, 0,0);
+ break;
+ case JCS_RGB:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
+ cinfo->num_components = 3;
+ SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCbCr:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 3;
+ /* JFIF specifies component IDs 1,2,3 */
+ /* We default to 2x2 subsamples of chrominance */
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ break;
+ case JCS_CMYK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);
+ SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCCK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ SET_COMP(3, 4, 2,2, 0, 0,0);
+ break;
+ case JCS_UNKNOWN:
+ cinfo->num_components = cinfo->input_components;
+ if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ SET_COMP(ci, ci, 1,1, 0, 0,0);
+ }
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ }
+}
+
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+
+LOCAL(jpeg_scan_info *)
+fill_a_scan (jpeg_scan_info * scanptr, int ci,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for specified component */
+{
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_scans (jpeg_scan_info * scanptr, int ncomps,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for each component */
+{
+ int ci;
+
+ for (ci = 0; ci < ncomps; ci++) {
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ }
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
+/* Support routine: generate interleaved DC scan if possible, else N scans */
+{
+ int ci;
+
+ if (ncomps <= MAX_COMPS_IN_SCAN) {
+ /* Single interleaved DC scan */
+ scanptr->comps_in_scan = ncomps;
+ for (ci = 0; ci < ncomps; ci++)
+ scanptr->component_index[ci] = ci;
+ scanptr->Ss = scanptr->Se = 0;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ } else {
+ /* Noninterleaved DC scan for each component */
+ scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
+ }
+ return scanptr;
+}
+
+
+/*
+ * Create a recommended progressive-JPEG script.
+ * cinfo->num_components and cinfo->jpeg_color_space must be correct.
+ */
+
+GLOBAL(void)
+jpeg_simple_progression (j_compress_ptr cinfo)
+{
+ int ncomps = cinfo->num_components;
+ int nscans;
+ jpeg_scan_info * scanptr;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Figure space needed for script. Calculation must match code below! */
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ nscans = 10;
+ } else {
+ /* All-purpose script for other color spaces. */
+ if (ncomps > MAX_COMPS_IN_SCAN)
+ nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */
+ else
+ nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
+ }
+
+ /* Allocate space for script. */
+ /* We use permanent pool just in case application re-uses script. */
+ scanptr = (jpeg_scan_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ nscans * SIZEOF(jpeg_scan_info));
+ cinfo->scan_info = scanptr;
+ cinfo->num_scans = nscans;
+
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ /* Initial DC scan */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ /* Initial AC scan: get some luma data out in a hurry */
+ scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+ /* Chroma data is too small to be worth expending many scans on */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+ /* Complete spectral selection for luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+ /* Refine next bit of luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+ /* Finish DC successive approximation */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ /* Finish AC successive approximation */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+ /* Luma bottom bit comes last since it's usually largest scan */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+ } else {
+ /* All-purpose script for other color spaces. */
+ /* Successive approximation first pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+ scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+ /* Successive approximation second pass */
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+ /* Successive approximation final pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+ }
+}
+
+#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/gs/jpeg/jcphuff.c b/gs/jpeg/jcphuff.c
new file mode 100644
index 000000000..9ace161cb
--- /dev/null
+++ b/gs/jpeg/jcphuff.c
@@ -0,0 +1,829 @@
+/*
+ * jcphuff.c
+ *
+ * Copyright (C) 1995-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy encoding routines for progressive JPEG.
+ *
+ * We do not support output suspension in this module, since the library
+ * currently does not allow multiple-scan files to be written with output
+ * suspension.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jchuff.h" /* Declarations shared with jchuff.c */
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+
+/* Expanded entropy encoder object for progressive Huffman encoding. */
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ /* Mode flag: TRUE for optimization, FALSE for actual data output */
+ boolean gather_statistics;
+
+ /* Bit-level coding status.
+ * next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
+ */
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ INT32 put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+ j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
+
+ /* Coding status for DC components */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+
+ /* Coding status for AC components */
+ int ac_tbl_no; /* the table number of the single component */
+ unsigned int EOBRUN; /* run length of EOBs */
+ unsigned int BE; /* # of buffered correction bits before MCU */
+ char * bit_buffer; /* buffer for correction bits (1 per char) */
+ /* packing correction bits tightly would save some space but cost time... */
+
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan).
+ * Since any one scan codes only DC or only AC, we only need one set
+ * of tables, not one for DC and one for AC.
+ */
+ c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+ /* Statistics tables for optimization; again, one set is enough */
+ long * count_ptrs[NUM_HUFF_TBLS];
+} phuff_entropy_encoder;
+
+typedef phuff_entropy_encoder * phuff_entropy_ptr;
+
+/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
+ * buffer can hold. Larger sizes may slightly improve compression, but
+ * 1000 is already well into the realm of overkill.
+ * The minimum safe size is 64 bits.
+ */
+
+#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS int ishift_temp;
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+/* Forward declarations */
+METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo));
+METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo));
+
+
+/*
+ * Initialize for a Huffman-compressed scan using progressive JPEG.
+ */
+
+METHODDEF(void)
+start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ boolean is_DC_band;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ entropy->cinfo = cinfo;
+ entropy->gather_statistics = gather_statistics;
+
+ is_DC_band = (cinfo->Ss == 0);
+
+ /* We assume jcmaster.c already validated the scan parameters. */
+
+ /* Select execution routines */
+ if (cinfo->Ah == 0) {
+ if (is_DC_band)
+ entropy->pub.encode_mcu = encode_mcu_DC_first;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_first;
+ } else {
+ if (is_DC_band)
+ entropy->pub.encode_mcu = encode_mcu_DC_refine;
+ else {
+ entropy->pub.encode_mcu = encode_mcu_AC_refine;
+ /* AC refinement needs a correction bit buffer */
+ if (entropy->bit_buffer == NULL)
+ entropy->bit_buffer = (char *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ MAX_CORR_BITS * SIZEOF(char));
+ }
+ }
+ if (gather_statistics)
+ entropy->pub.finish_pass = finish_pass_gather_phuff;
+ else
+ entropy->pub.finish_pass = finish_pass_phuff;
+
+ /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1
+ * for AC coefficients.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Initialize DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ /* Make sure requested tables are present */
+ /* (In gather mode, tables need not be allocated yet) */
+ if (is_DC_band) {
+ if (cinfo->Ah != 0) /* DC refinement needs no table */
+ continue;
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS ||
+ (cinfo->dc_huff_tbl_ptrs[tbl] == NULL && !gather_statistics))
+ ERREXIT1(cinfo,JERR_NO_HUFF_TABLE, tbl);
+ } else {
+ entropy->ac_tbl_no = tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS ||
+ (cinfo->ac_huff_tbl_ptrs[tbl] == NULL && !gather_statistics))
+ ERREXIT1(cinfo,JERR_NO_HUFF_TABLE, tbl);
+ }
+ if (gather_statistics) {
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->count_ptrs[tbl] == NULL)
+ entropy->count_ptrs[tbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long));
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ if (is_DC_band)
+ jpeg_make_c_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[tbl],
+ & entropy->derived_tbls[tbl]);
+ else
+ jpeg_make_c_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[tbl],
+ & entropy->derived_tbls[tbl]);
+ }
+ }
+
+ /* Initialize AC stuff */
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+
+ /* Initialize bit buffer to empty */
+ entropy->put_buffer = 0;
+ entropy->put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/* Outputting bytes to the file.
+ * NB: these must be called only when actually outputting,
+ * that is, entropy->gather_statistics == FALSE.
+ */
+
+/* Emit a byte */
+#define emit_byte(entropy,val) \
+ { *(entropy)->next_output_byte++ = (JOCTET) (val); \
+ if (--(entropy)->free_in_buffer == 0) \
+ dump_buffer(entropy); }
+
+
+LOCAL(void)
+dump_buffer (phuff_entropy_ptr entropy)
+/* Empty the output buffer; we do not support suspension in this module. */
+{
+ struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (entropy->cinfo))
+ ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
+ /* After a successful buffer dump, must reset buffer pointers */
+ entropy->next_output_byte = dest->next_output_byte;
+ entropy->free_in_buffer = dest->free_in_buffer;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(void)
+emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
+/* Emit some bits, unless we are in gather mode */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = entropy->put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+ if (entropy->gather_statistics)
+ return; /* do nothing if we're only getting stats */
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= entropy->put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte(entropy, c);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte(entropy, 0);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ entropy->put_buffer = put_buffer; /* update variables */
+ entropy->put_bits = put_bits;
+}
+
+
+LOCAL(void)
+flush_bits (phuff_entropy_ptr entropy)
+{
+ emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */
+ entropy->put_buffer = 0; /* and reset bit-buffer to empty */
+ entropy->put_bits = 0;
+}
+
+
+/*
+ * Emit (or just count) a Huffman symbol.
+ */
+
+INLINE
+LOCAL(void)
+emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+ if (entropy->gather_statistics)
+ entropy->count_ptrs[tbl_no][symbol]++;
+ else {
+ c_derived_tbl * tbl = entropy->derived_tbls[tbl_no];
+ emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+ }
+}
+
+
+/*
+ * Emit bits from a correction bit buffer.
+ */
+
+LOCAL(void)
+emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart,
+ unsigned int nbits)
+{
+ if (entropy->gather_statistics)
+ return; /* no real work */
+
+ while (nbits > 0) {
+ emit_bits(entropy, (unsigned int) (*bufstart), 1);
+ bufstart++;
+ nbits--;
+ }
+}
+
+
+/*
+ * Emit any pending EOBRUN symbol.
+ */
+
+LOCAL(void)
+emit_eobrun (phuff_entropy_ptr entropy)
+{
+ register int temp, nbits;
+
+ if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */
+ temp = entropy->EOBRUN;
+ nbits = 0;
+ while ((temp >>= 1))
+ nbits++;
+
+ emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
+ if (nbits)
+ emit_bits(entropy, entropy->EOBRUN, nbits);
+
+ entropy->EOBRUN = 0;
+
+ /* Emit any buffered correction bits */
+ emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(void)
+emit_restart (phuff_entropy_ptr entropy, int restart_num)
+{
+ int ci;
+
+ emit_eobrun(entropy);
+
+ if (! entropy->gather_statistics) {
+ flush_bits(entropy);
+ emit_byte(entropy, 0xFF);
+ emit_byte(entropy, JPEG_RST0 + restart_num);
+ }
+
+ if (entropy->cinfo->Ss == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
+ entropy->last_dc_val[ci] = 0;
+ } else {
+ /* Re-initialize all AC-related fields to 0 */
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ int blkn, ci;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+ jpeg_component_info * compptr;
+ ISHIFT_TEMPS
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Compute the DC value after the required point transform by Al.
+ * This is simply an arithmetic right shift.
+ */
+ temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al);
+
+ /* DC differences are figured on the point-transformed values. */
+ temp = temp2 - entropy->last_dc_val[ci];
+ entropy->last_dc_val[ci] = temp2;
+
+ /* Encode the DC coefficient difference per section G.1.2.1 */
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+
+ /* Count/emit the Huffman-coded symbol for the number of bits */
+ emit_symbol(entropy, compptr->dc_tbl_no, nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ emit_bits(entropy, (unsigned int) temp2, nbits);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ register int r, k;
+ int Se = cinfo->Se;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = (*block)[jpeg_natural_order[k]]) == 0) {
+ r++;
+ continue;
+ }
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value; so the code is
+ * interwoven with finding the abs value (temp) and output bits (temp2).
+ */
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ /* For a negative coef, want temp2 = bitwise complement of abs(coef) */
+ temp2 = ~temp;
+ } else {
+ temp >>= Al; /* apply the point transform */
+ temp2 = temp;
+ }
+ /* Watch out for case that nonzero coef is zero after point transform */
+ if (temp == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any pending EOBRUN */
+ if (entropy->EOBRUN > 0)
+ emit_eobrun(entropy);
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ emit_bits(entropy, (unsigned int) temp2, nbits);
+
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ if (entropy->EOBRUN == 0x7FFF)
+ emit_eobrun(entropy); /* force it out to avoid overflow */
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ int blkn;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* We simply emit the Al'th bit of the DC coefficient value. */
+ temp = (*block)[0];
+ emit_bits(entropy, (unsigned int) (temp >> Al), 1);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ register int r, k;
+ int EOB;
+ char *BR_buffer;
+ unsigned int BR;
+ int Se = cinfo->Se;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+ int absvalues[DCTSIZE2];
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* It is convenient to make a pre-pass to determine the transformed
+ * coefficients' absolute values and the EOB position.
+ */
+ EOB = 0;
+ for (k = cinfo->Ss; k <= Se; k++) {
+ temp = (*block)[jpeg_natural_order[k]];
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if (temp < 0)
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ absvalues[k] = temp; /* save abs value for main pass */
+ if (temp == 1)
+ EOB = k; /* EOB = index of last newly-nonzero coef */
+ }
+
+ /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
+
+ r = 0; /* r = run length of zeros */
+ BR = 0; /* BR = count of buffered bits added now */
+ BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = absvalues[k]) == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any required ZRLs, but not if they can be folded into EOB */
+ while (r > 15 && k <= EOB) {
+ /* emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+ /* Emit ZRL */
+ emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ /* Emit buffered correction bits that must be associated with ZRL */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ }
+
+ /* If the coef was previously nonzero, it only needs a correction bit.
+ * NOTE: a straight translation of the spec's figure G.7 would suggest
+ * that we also need to test r > 15. But if r > 15, we can only get here
+ * if k > EOB, which implies that this coefficient is not 1.
+ */
+ if (temp > 1) {
+ /* The correction bit is the next bit of the absolute value. */
+ BR_buffer[BR++] = (char) (temp & 1);
+ continue;
+ }
+
+ /* Emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
+
+ /* Emit output bit for newly-nonzero coef */
+ temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1;
+ emit_bits(entropy, (unsigned int) temp, 1);
+
+ /* Emit buffered correction bits that must be associated with this code */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0 || BR > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ entropy->BE += BR; /* concat my correction bits to older ones */
+ /* We force out the EOB if we risk either:
+ * 1. overflow of the EOB counter;
+ * 2. overflow of the correction bit buffer during the next MCU.
+ */
+ if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
+ emit_eobrun(entropy);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed progressive scan.
+ */
+
+METHODDEF(void)
+finish_pass_phuff (j_compress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Flush out any buffered data */
+ emit_eobrun(entropy);
+ flush_bits(entropy);
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather_phuff (j_compress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ boolean is_DC_band;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+ JHUFF_TBL **htblptr;
+ boolean did[NUM_HUFF_TBLS];
+
+ /* Flush out buffered data (all we care about is counting the EOB symbol) */
+ emit_eobrun(entropy);
+
+ is_DC_band = (cinfo->Ss == 0);
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ MEMZERO(did, SIZEOF(did));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ if (is_DC_band) {
+ if (cinfo->Ah != 0) /* DC refinement needs no table */
+ continue;
+ tbl = compptr->dc_tbl_no;
+ } else {
+ tbl = compptr->ac_tbl_no;
+ }
+ if (! did[tbl]) {
+ if (is_DC_band)
+ htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
+ else
+ htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]);
+ did[tbl] = TRUE;
+ }
+ }
+}
+
+
+/*
+ * Module initialization routine for progressive Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_phuff_encoder (j_compress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy;
+ int i;
+
+ entropy = (phuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(phuff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass_phuff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ entropy->count_ptrs[i] = NULL;
+ }
+ entropy->bit_buffer = NULL; /* needed only in AC refinement scan */
+}
+
+#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/gs/jpeg/jcprepct.c b/gs/jpeg/jcprepct.c
new file mode 100644
index 000000000..fa93333db
--- /dev/null
+++ b/gs/jpeg/jcprepct.c
@@ -0,0 +1,354 @@
+/*
+ * jcprepct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the compression preprocessing controller.
+ * This controller manages the color conversion, downsampling,
+ * and edge expansion steps.
+ *
+ * Most of the complexity here is associated with buffering input rows
+ * as required by the downsampler. See the comments at the head of
+ * jcsample.c for the downsampler's needs.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* At present, jcsample.c can request context rows only for smoothing.
+ * In the future, we might also need context rows for CCIR601 sampling
+ * or other more-complex downsampling procedures. The code to support
+ * context rows should be compiled only if needed.
+ */
+#ifdef INPUT_SMOOTHING_SUPPORTED
+#define CONTEXT_ROWS_SUPPORTED
+#endif
+
+
+/*
+ * For the simple (no-context-row) case, we just need to buffer one
+ * row group's worth of pixels for the downsampling step. At the bottom of
+ * the image, we pad to a full row group by replicating the last pixel row.
+ * The downsampler's last output row is then replicated if needed to pad
+ * out to a full iMCU row.
+ *
+ * When providing context rows, we must buffer three row groups' worth of
+ * pixels. Three row groups are physically allocated, but the row pointer
+ * arrays are made five row groups high, with the extra pointers above and
+ * below "wrapping around" to point to the last and first real row groups.
+ * This allows the downsampler to access the proper context rows.
+ * At the top and bottom of the image, we create dummy context rows by
+ * copying the first or last real pixel row. This copying could be avoided
+ * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
+ * trouble on the compression side.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_prep_controller pub; /* public fields */
+
+ /* Downsampling input buffer. This buffer holds color-converted data
+ * until we have enough to do a downsample step.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ JDIMENSION rows_to_go; /* counts rows remaining in source image */
+ int next_buf_row; /* index of next row to store in color_buf */
+
+#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */
+ int this_row_group; /* starting row index of group to process */
+ int next_buf_stop; /* downsample when we reach this index */
+#endif
+} my_prep_controller;
+
+typedef my_prep_controller * my_prep_ptr;
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+
+ if (pass_mode != JBUF_PASS_THRU)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Initialize total-height counter for detecting bottom of image */
+ prep->rows_to_go = cinfo->image_height;
+ /* Mark the conversion buffer empty */
+ prep->next_buf_row = 0;
+#ifdef CONTEXT_ROWS_SUPPORTED
+ /* Preset additional state variables for context mode.
+ * These aren't used in non-context mode, so we needn't test which mode.
+ */
+ prep->this_row_group = 0;
+ /* Set next_buf_stop to stop after two row groups have been read in. */
+ prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
+#endif
+}
+
+
+/*
+ * Expand an image vertically from height input_rows to height output_rows,
+ * by duplicating the bottom row.
+ */
+
+LOCAL(void)
+expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
+ int input_rows, int output_rows)
+{
+ register int row;
+
+ for (row = input_rows; row < output_rows; row++) {
+ jcopy_sample_rows(image_data, input_rows-1, image_data, row,
+ 1, num_cols);
+ }
+}
+
+
+/*
+ * Process some data in the simple no-context case.
+ *
+ * Preprocessor output data is counted in "row groups". A row group
+ * is defined to be v_samp_factor sample rows of each component.
+ * Downsampling will produce this much data from each max_v_samp_factor
+ * input rows.
+ */
+
+METHODDEF(void)
+pre_process_data (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ JDIMENSION inrows;
+ jpeg_component_info * compptr;
+
+ while (*in_row_ctr < in_rows_avail &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ /* If at bottom of image, pad to fill the conversion buffer. */
+ if (prep->rows_to_go == 0 &&
+ prep->next_buf_row < cinfo->max_v_samp_factor) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, cinfo->max_v_samp_factor);
+ }
+ prep->next_buf_row = cinfo->max_v_samp_factor;
+ }
+ /* If we've filled the conversion buffer, empty it. */
+ if (prep->next_buf_row == cinfo->max_v_samp_factor) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf, (JDIMENSION) 0,
+ output_buf, *out_row_group_ctr);
+ prep->next_buf_row = 0;
+ (*out_row_group_ctr)++;
+ }
+ /* If at bottom of image, pad the output to a full iMCU height.
+ * Note we assume the caller is providing a one-iMCU-height output buffer!
+ */
+ if (prep->rows_to_go == 0 &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ expand_bottom_edge(output_buf[ci],
+ compptr->width_in_blocks * DCTSIZE,
+ (int) (*out_row_group_ctr * compptr->v_samp_factor),
+ (int) (out_row_groups_avail * compptr->v_samp_factor));
+ }
+ *out_row_group_ctr = out_row_groups_avail;
+ break; /* can exit outer loop without test */
+ }
+ }
+}
+
+
+#ifdef CONTEXT_ROWS_SUPPORTED
+
+/*
+ * Process some data in the context case.
+ */
+
+METHODDEF(void)
+pre_process_context (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ int buf_height = cinfo->max_v_samp_factor * 3;
+ JDIMENSION inrows;
+
+ while (*out_row_group_ctr < out_row_groups_avail) {
+ if (*in_row_ctr < in_rows_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = prep->next_buf_stop - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ /* Pad at top of image, if first time through */
+ if (prep->rows_to_go == cinfo->image_height) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ int row;
+ for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
+ jcopy_sample_rows(prep->color_buf[ci], 0,
+ prep->color_buf[ci], -row,
+ 1, cinfo->image_width);
+ }
+ }
+ }
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ } else {
+ /* Return for more data, unless we are at the bottom of the image. */
+ if (prep->rows_to_go != 0)
+ break;
+ /* When at bottom of image, pad to fill the conversion buffer. */
+ if (prep->next_buf_row < prep->next_buf_stop) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, prep->next_buf_stop);
+ }
+ prep->next_buf_row = prep->next_buf_stop;
+ }
+ }
+ /* If we've gotten enough data, downsample a row group. */
+ if (prep->next_buf_row == prep->next_buf_stop) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf,
+ (JDIMENSION) prep->this_row_group,
+ output_buf, *out_row_group_ctr);
+ (*out_row_group_ctr)++;
+ /* Advance pointers with wraparound as necessary. */
+ prep->this_row_group += cinfo->max_v_samp_factor;
+ if (prep->this_row_group >= buf_height)
+ prep->this_row_group = 0;
+ if (prep->next_buf_row >= buf_height)
+ prep->next_buf_row = 0;
+ prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
+ }
+ }
+}
+
+
+/*
+ * Create the wrapped-around downsampling input buffer needed for context mode.
+ */
+
+LOCAL(void)
+create_context_buffer (j_compress_ptr cinfo)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int rgroup_height = cinfo->max_v_samp_factor;
+ int ci, i;
+ jpeg_component_info * compptr;
+ JSAMPARRAY true_buffer, fake_buffer;
+
+ /* Grab enough space for fake row pointers for all the components;
+ * we need five row groups' worth of pointers for each component.
+ */
+ fake_buffer = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (cinfo->num_components * 5 * rgroup_height) *
+ SIZEOF(JSAMPROW));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate the actual buffer space (3 row groups) for this component.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ true_buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) (3 * rgroup_height));
+ /* Copy true buffer row pointers into the middle of the fake row array */
+ MEMCOPY(fake_buffer + rgroup_height, true_buffer,
+ 3 * rgroup_height * SIZEOF(JSAMPROW));
+ /* Fill in the above and below wraparound pointers */
+ for (i = 0; i < rgroup_height; i++) {
+ fake_buffer[i] = true_buffer[2 * rgroup_height + i];
+ fake_buffer[4 * rgroup_height + i] = true_buffer[i];
+ }
+ prep->color_buf[ci] = fake_buffer + rgroup_height;
+ fake_buffer += 5 * rgroup_height; /* point to space for next component */
+ }
+}
+
+#endif /* CONTEXT_ROWS_SUPPORTED */
+
+
+/*
+ * Initialize preprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_prep_ptr prep;
+ int ci;
+ jpeg_component_info * compptr;
+
+ if (need_full_buffer) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ prep = (my_prep_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_prep_controller));
+ cinfo->prep = (struct jpeg_c_prep_controller *) prep;
+ prep->pub.start_pass = start_pass_prep;
+
+ /* Allocate the color conversion buffer.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ if (cinfo->downsample->need_context_rows) {
+ /* Set up to provide context rows */
+#ifdef CONTEXT_ROWS_SUPPORTED
+ prep->pub.pre_process_data = pre_process_context;
+ create_context_buffer(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* No context, just make it tall enough for one row group */
+ prep->pub.pre_process_data = pre_process_data;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/gs/jpeg/jcsample.c b/gs/jpeg/jcsample.c
new file mode 100644
index 000000000..212ec8757
--- /dev/null
+++ b/gs/jpeg/jcsample.c
@@ -0,0 +1,519 @@
+/*
+ * jcsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains downsampling routines.
+ *
+ * Downsampling input data is counted in "row groups". A row group
+ * is defined to be max_v_samp_factor pixel rows of each component,
+ * from which the downsampler produces v_samp_factor sample rows.
+ * A single row group is processed in each call to the downsampler module.
+ *
+ * The downsampler is responsible for edge-expansion of its output data
+ * to fill an integral number of DCT blocks horizontally. The source buffer
+ * may be modified if it is helpful for this purpose (the source buffer is
+ * allocated wide enough to correspond to the desired output width).
+ * The caller (the prep controller) is responsible for vertical padding.
+ *
+ * The downsampler may request "context rows" by setting need_context_rows
+ * during startup. In this case, the input arrays will contain at least
+ * one row group's worth of pixels above and below the passed-in data;
+ * the caller will create dummy rows at image top and bottom by replicating
+ * the first or last real pixel row.
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ *
+ * The downsampling algorithm used here is a simple average of the source
+ * pixels covered by the output pixel. The hi-falutin sampling literature
+ * refers to this as a "box filter". In general the characteristics of a box
+ * filter are not very good, but for the specific cases we normally use (1:1
+ * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
+ * nearly so bad. If you intend to use other sampling ratios, you'd be well
+ * advised to improve this code.
+ *
+ * A simple input-smoothing capability is provided. This is mainly intended
+ * for cleaning up color-dithered GIF input files (if you find it inadequate,
+ * we suggest using an external filtering program such as pnmconvol). When
+ * enabled, each input pixel P is replaced by a weighted sum of itself and its
+ * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF,
+ * where SF = (smoothing_factor / 1024).
+ * Currently, smoothing is only supported for 2h2v sampling factors.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to downsample a single component */
+typedef JMETHOD(void, downsample1_ptr,
+ (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_downsampler pub; /* public fields */
+
+ /* Downsampling method pointers, one per component */
+ downsample1_ptr methods[MAX_COMPONENTS];
+} my_downsampler;
+
+typedef my_downsampler * my_downsample_ptr;
+
+
+/*
+ * Initialize for a downsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_downsample (j_compress_ptr cinfo)
+{
+ /* no work for now */
+}
+
+
+/*
+ * Expand a component horizontally from width input_cols to width output_cols,
+ * by duplicating the rightmost samples.
+ */
+
+LOCAL(void)
+expand_right_edge (JSAMPARRAY image_data, int num_rows,
+ JDIMENSION input_cols, JDIMENSION output_cols)
+{
+ register JSAMPROW ptr;
+ register JSAMPLE pixval;
+ register int count;
+ int row;
+ int numcols = (int) (output_cols - input_cols);
+
+ if (numcols > 0) {
+ for (row = 0; row < num_rows; row++) {
+ ptr = image_data[row] + input_cols;
+ pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
+ for (count = numcols; count > 0; count--)
+ *ptr++ = pixval;
+ }
+ }
+}
+
+
+/*
+ * Do downsampling for a whole row group (all components).
+ *
+ * In this version we simply downsample each component independently.
+ */
+
+METHODDEF(void)
+sep_downsample (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
+{
+ my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JSAMPARRAY in_ptr, out_ptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ in_ptr = input_buf[ci] + in_row_index;
+ out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor);
+ (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * One row group is processed per call.
+ * This version handles arbitrary integral sampling ratios, without smoothing.
+ * Note that this version is not actually used for customary sampling ratios.
+ */
+
+METHODDEF(void)
+int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
+ JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
+ JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
+ JSAMPROW inptr, outptr;
+ INT32 outvalue;
+
+ h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
+ v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
+ numpix = h_expand * v_expand;
+ numpix2 = numpix/2;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * h_expand);
+
+ inrow = 0;
+ for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
+ outptr = output_data[outrow];
+ for (outcol = 0, outcol_h = 0; outcol < output_cols;
+ outcol++, outcol_h += h_expand) {
+ outvalue = 0;
+ for (v = 0; v < v_expand; v++) {
+ inptr = input_data[inrow+v] + outcol_h;
+ for (h = 0; h < h_expand; h++) {
+ outvalue += (INT32) GETJSAMPLE(*inptr++);
+ }
+ }
+ *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
+ }
+ inrow += v_expand;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ /* Copy the data */
+ jcopy_sample_rows(input_data, 0, output_data, 0,
+ cinfo->max_v_samp_factor, cinfo->image_width);
+ /* Edge-expand */
+ expand_right_edge(output_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, compptr->width_in_blocks * DCTSIZE);
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the common case of 2:1 horizontal and 1:1 vertical,
+ * without smoothing.
+ *
+ * A note about the "bias" calculations: when rounding fractional values to
+ * integer, we do not want to always round 0.5 up to the next integer.
+ * If we did that, we'd introduce a noticeable bias towards larger values.
+ * Instead, this code is arranged so that 0.5 will be rounded up or down at
+ * alternate pixel locations (a simple ordered dither pattern).
+ */
+
+METHODDEF(void)
+h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int outrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
+ register JSAMPROW inptr, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
+ outptr = output_data[outrow];
+ inptr = input_data[outrow];
+ bias = 0; /* bias = 0,1,0,1,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
+ + bias) >> 1);
+ bias ^= 1; /* 0=>1, 1=>0 */
+ inptr += 2;
+ }
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
+ register JSAMPROW inptr0, inptr1, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ inrow = 0;
+ for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ bias = 1; /* bias = 1,2,1,2,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+ + bias) >> 2);
+ bias ^= 3; /* 1=>2, 2=>1 */
+ inptr0 += 2; inptr1 += 2;
+ }
+ inrow += 2;
+ }
+}
+
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
+ register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols * 2);
+
+ /* We don't bother to form the individual "smoothed" input pixel values;
+ * we can directly compute the output which is the average of the four
+ * smoothed values. Each of the four member pixels contributes a fraction
+ * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
+ * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
+ * output. The four corner-adjacent neighbor pixels contribute a fraction
+ * SF to just one smoothed pixel, or SF/4 to the final output; while the
+ * eight edge-adjacent neighbors contribute SF to each of two smoothed
+ * pixels, or SF/2 overall. In order to use integer arithmetic, these
+ * factors are scaled by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
+ neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
+
+ inrow = 0;
+ for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ above_ptr = input_data[inrow-1];
+ below_ptr = input_data[inrow+2];
+
+ /* Special case for first column: pretend column -1 is same as column 0 */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ /* sum of pixels directly mapped to this output element */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ /* sum of edge-neighbor pixels */
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
+ /* The edge-neighbors count twice as much as corner-neighbors */
+ neighsum += neighsum;
+ /* Add in the corner-neighbors */
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
+ /* form final output scaled up by 2^16 */
+ membersum = membersum * memberscale + neighsum * neighscale;
+ /* round, descale and output it */
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ inrow += 2;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int outrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
+ register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+ int colsum, lastcolsum, nextcolsum;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols);
+
+ /* Each of the eight neighbor pixels contributes a fraction SF to the
+ * smoothed pixel, while the main pixel contributes (1-8*SF). In order
+ * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
+ neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
+
+ for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
+ outptr = output_data[outrow];
+ inptr = input_data[outrow];
+ above_ptr = input_data[outrow-1];
+ below_ptr = input_data[outrow+1];
+
+ /* Special case for first column */
+ colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
+ GETJSAMPLE(*inptr);
+ membersum = GETJSAMPLE(*inptr++);
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = colsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ membersum = GETJSAMPLE(*inptr++);
+ above_ptr++; below_ptr++;
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + colsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ }
+}
+
+#endif /* INPUT_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Module initialization routine for downsampling.
+ * Note that we must select a routine for each component.
+ */
+
+GLOBAL(void)
+jinit_downsampler (j_compress_ptr cinfo)
+{
+ my_downsample_ptr downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean smoothok = TRUE;
+
+ downsample = (my_downsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_downsampler));
+ cinfo->downsample = (struct jpeg_downsampler *) downsample;
+ downsample->pub.start_pass = start_pass_downsample;
+ downsample->pub.downsample = sep_downsample;
+ downsample->pub.need_context_rows = FALSE;
+
+ if (cinfo->CCIR601_sampling)
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* Verify we can handle the sampling factors, and set up method pointers */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor == cinfo->max_h_samp_factor &&
+ compptr->v_samp_factor == cinfo->max_v_samp_factor) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = fullsize_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = fullsize_downsample;
+ } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
+ compptr->v_samp_factor == cinfo->max_v_samp_factor) {
+ smoothok = FALSE;
+ downsample->methods[ci] = h2v1_downsample;
+ } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
+ compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = h2v2_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = h2v2_downsample;
+ } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
+ (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) {
+ smoothok = FALSE;
+ downsample->methods[ci] = int_downsample;
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ }
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor && !smoothok)
+ TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
+#endif
+}
diff --git a/gs/jpeg/jctrans.c b/gs/jpeg/jctrans.c
new file mode 100644
index 000000000..429604868
--- /dev/null
+++ b/gs/jpeg/jctrans.c
@@ -0,0 +1,371 @@
+/*
+ * jctrans.c
+ *
+ * Copyright (C) 1995-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding compression,
+ * that is, writing raw DCT coefficient arrays to an output JPEG file.
+ * The routines in jcapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transencode_master_selection
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+LOCAL(void) transencode_coef_controller
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+
+
+/*
+ * Compression initialization for writing raw-coefficient data.
+ * Before calling this, all parameters and a data destination must be set up.
+ * Call jpeg_finish_compress() to actually write the data.
+ *
+ * The number of passed virtual arrays must match cinfo->num_components.
+ * Note that the virtual arrays need not be filled or even realized at
+ * the time write_coefficients is called; indeed, if the virtual arrays
+ * were requested from this compression object's memory manager, they
+ * typically will be realized during this routine and filled afterwards.
+ */
+
+GLOBAL(void)
+jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Mark all tables to be written */
+ jpeg_suppress_tables(cinfo, FALSE);
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ transencode_master_selection(cinfo, coef_arrays);
+ /* Wait for jpeg_finish_compress() call */
+ cinfo->next_scanline = 0; /* so jpeg_write_marker works */
+ cinfo->global_state = CSTATE_WRCOEFS;
+}
+
+
+/*
+ * Initialize the compression object with default parameters,
+ * then copy from the source object all parameters needed for lossless
+ * transcoding. Parameters that can be varied without loss (such as
+ * scan script and Huffman optimization) are left in their default states.
+ */
+
+GLOBAL(void)
+jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo)
+{
+ JQUANT_TBL ** qtblptr;
+ jpeg_component_info *incomp, *outcomp;
+ JQUANT_TBL *c_quant, *slot_quant;
+ int tblno, ci, coefi;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (dstinfo->global_state != CSTATE_START)
+ ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
+ /* Copy fundamental image dimensions */
+ dstinfo->image_width = srcinfo->image_width;
+ dstinfo->image_height = srcinfo->image_height;
+ dstinfo->input_components = srcinfo->num_components;
+ dstinfo->in_color_space = srcinfo->jpeg_color_space;
+ /* Initialize all parameters to default values */
+ jpeg_set_defaults(dstinfo);
+ /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
+ * Fix it to get the right header markers for the image colorspace.
+ */
+ jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
+ dstinfo->data_precision = srcinfo->data_precision;
+ dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
+ /* Copy the source's quantization tables. */
+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+ if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
+ qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
+ MEMCOPY((*qtblptr)->quantval,
+ srcinfo->quant_tbl_ptrs[tblno]->quantval,
+ SIZEOF((*qtblptr)->quantval));
+ (*qtblptr)->sent_table = FALSE;
+ }
+ }
+ /* Copy the source's per-component info.
+ * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
+ */
+ dstinfo->num_components = srcinfo->num_components;
+ if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
+ ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
+ outcomp->component_id = incomp->component_id;
+ outcomp->h_samp_factor = incomp->h_samp_factor;
+ outcomp->v_samp_factor = incomp->v_samp_factor;
+ outcomp->quant_tbl_no = incomp->quant_tbl_no;
+ /* Make sure saved quantization table for component matches the qtable
+ * slot. If not, the input file re-used this qtable slot.
+ * IJG encoder currently cannot duplicate this.
+ */
+ tblno = outcomp->quant_tbl_no;
+ if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
+ srcinfo->quant_tbl_ptrs[tblno] == NULL)
+ ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
+ slot_quant = srcinfo->quant_tbl_ptrs[tblno];
+ c_quant = incomp->quant_table;
+ if (c_quant != NULL) {
+ for (coefi = 0; coefi < DCTSIZE2; coefi++) {
+ if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
+ ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
+ }
+ }
+ /* Note: we do not copy the source's Huffman table assignments;
+ * instead we rely on jpeg_set_colorspace to have made a suitable choice.
+ */
+ }
+}
+
+
+/*
+ * Master selection of compression modules for transcoding.
+ * This substitutes for jcinit.c's initialization of the full compressor.
+ */
+
+LOCAL(void)
+transencode_master_selection (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ /* Although we don't actually use input_components for transcoding,
+ * jcmaster.c's initial_setup will complain if input_components is 0.
+ */
+ cinfo->input_components = 1;
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, TRUE /* transcode only */);
+
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ jinit_phuff_encoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* We need a special coefficient buffer controller. */
+ transencode_coef_controller(cinfo, coef_arrays);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
+
+
+/*
+ * The rest of this file is a special implementation of the coefficient
+ * buffer controller. This is similar to jccoefct.c, but it handles only
+ * output from presupplied virtual arrays. Furthermore, we generate any
+ * dummy padding blocks on-the-fly rather than expecting them to be present
+ * in the arrays.
+ */
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* Virtual block array for each component. */
+ jvirt_barray_ptr * whole_image;
+
+ /* Workspace for constructing dummy blocks at right/bottom edges. */
+ JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ if (pass_mode != JBUF_CRANK_DEST)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Process some data.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, blockcnt;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yindex+yoffset < compptr->last_row_height) {
+ /* Fill in pointers to real blocks in this row */
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < blockcnt; xindex++)
+ MCU_buffer[blkn++] = buffer_ptr++;
+ } else {
+ /* At bottom of image, need a whole row of dummy blocks */
+ xindex = 0;
+ }
+ /* Fill in any dummy blocks needed in this row.
+ * Dummy blocks are filled in the same way as in jccoefct.c:
+ * all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. The init routine has already zeroed the
+ * AC entries, so we need only set the DC entries correctly.
+ */
+ for (; xindex < compptr->MCU_width; xindex++) {
+ MCU_buffer[blkn] = coef->dummy_buffer[blkn];
+ MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
+ blkn++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Initialize coefficient buffer controller.
+ *
+ * Each passed coefficient array must be the right size for that
+ * coefficient: width_in_blocks wide and height_in_blocks high,
+ * with unitheight at least v_samp_factor.
+ */
+
+LOCAL(void)
+transencode_coef_controller (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ my_coef_ptr coef;
+ JBLOCKROW buffer;
+ int i;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+ coef->pub.compress_data = compress_output;
+
+ /* Save pointer to virtual arrays */
+ coef->whole_image = coef_arrays;
+
+ /* Allocate and pre-zero space for dummy DCT blocks. */
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->dummy_buffer[i] = buffer + i;
+ }
+}
diff --git a/gs/jpeg/jdapimin.c b/gs/jpeg/jdapimin.c
new file mode 100644
index 000000000..c70215425
--- /dev/null
+++ b/gs/jpeg/jdapimin.c
@@ -0,0 +1,406 @@
+/*
+ * jdapimin.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-decompression case or the
+ * transcoding-only case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jdapistd.c. But also see jcomapi.c for routines
+ * shared by compression and decompression, and jdtrans.c for the transcoding
+ * case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG decompression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_decompress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
+
+ /* For debugging purposes, zero the whole master structure.
+ * But error manager pointer is already there, so save and restore it.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
+ cinfo->err = err;
+ }
+ cinfo->is_decompressor = TRUE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->src = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++)
+ cinfo->quant_tbl_ptrs[i] = NULL;
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ /* Initialize marker processor so application can override methods
+ * for COM, APPn markers before calling jpeg_read_header.
+ */
+ jinit_marker_reader(cinfo);
+
+ /* And initialize the overall input controller. */
+ jinit_input_controller(cinfo);
+
+ /* OK, I'm ready */
+ cinfo->global_state = DSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG decompression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG decompression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Install a special processing method for COM or APPn markers.
+ */
+
+GLOBAL(void)
+jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
+ jpeg_marker_parser_method routine)
+{
+ if (marker_code == JPEG_COM)
+ cinfo->marker->process_COM = routine;
+ else if (marker_code >= JPEG_APP0 && marker_code <= JPEG_APP0+15)
+ cinfo->marker->process_APPn[marker_code-JPEG_APP0] = routine;
+ else
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
+
+
+/*
+ * Set default decompression parameters.
+ */
+
+LOCAL(void)
+default_decompress_parms (j_decompress_ptr cinfo)
+{
+ /* Guess the input colorspace, and set output colorspace accordingly. */
+ /* (Wish JPEG committee had provided a real way to specify this...) */
+ /* Note application may override our guesses. */
+ switch (cinfo->num_components) {
+ case 1:
+ cinfo->jpeg_color_space = JCS_GRAYSCALE;
+ cinfo->out_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ if (cinfo->saw_JFIF_marker) {
+ cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
+ } else if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_RGB;
+ break;
+ case 1:
+ cinfo->jpeg_color_space = JCS_YCbCr;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ break;
+ }
+ } else {
+ /* Saw no special markers, try to guess from the component IDs */
+ int cid0 = cinfo->comp_info[0].component_id;
+ int cid1 = cinfo->comp_info[1].component_id;
+ int cid2 = cinfo->comp_info[2].component_id;
+
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3)
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
+ else {
+ TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ }
+ }
+ /* Always guess RGB is proper output colorspace. */
+ cinfo->out_color_space = JCS_RGB;
+ break;
+
+ case 4:
+ if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_CMYK;
+ break;
+ case 2:
+ cinfo->jpeg_color_space = JCS_YCCK;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
+ break;
+ }
+ } else {
+ /* No special markers, assume straight CMYK. */
+ cinfo->jpeg_color_space = JCS_CMYK;
+ }
+ cinfo->out_color_space = JCS_CMYK;
+ break;
+
+ default:
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->out_color_space = JCS_UNKNOWN;
+ break;
+ }
+
+ /* Set defaults for other decompression parameters. */
+ cinfo->scale_num = 1; /* 1:1 scaling */
+ cinfo->scale_denom = 1;
+ cinfo->output_gamma = 1.0;
+ cinfo->buffered_image = FALSE;
+ cinfo->raw_data_out = FALSE;
+ cinfo->dct_method = JDCT_DEFAULT;
+ cinfo->do_fancy_upsampling = TRUE;
+ cinfo->do_block_smoothing = TRUE;
+ cinfo->quantize_colors = FALSE;
+ /* We set these in case application only sets quantize_colors. */
+ cinfo->dither_mode = JDITHER_FS;
+#ifdef QUANT_2PASS_SUPPORTED
+ cinfo->two_pass_quantize = TRUE;
+#else
+ cinfo->two_pass_quantize = FALSE;
+#endif
+ cinfo->desired_number_of_colors = 256;
+ cinfo->colormap = NULL;
+ /* Initialize for no mode change in buffered-image mode. */
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+}
+
+
+/*
+ * Decompression startup: read start of JPEG datastream to see what's there.
+ * Need only initialize JPEG object and supply a data source before calling.
+ *
+ * This routine will read as far as the first SOS marker (ie, actual start of
+ * compressed data), and will save all tables and parameters in the JPEG
+ * object. It will also initialize the decompression parameters to default
+ * values, and finally return JPEG_HEADER_OK. On return, the application may
+ * adjust the decompression parameters and then call jpeg_start_decompress.
+ * (Or, if the application only wanted to determine the image parameters,
+ * the data need not be decompressed. In that case, call jpeg_abort or
+ * jpeg_destroy to release any temporary space.)
+ * If an abbreviated (tables only) datastream is presented, the routine will
+ * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then
+ * re-use the JPEG object to read the abbreviated image datastream(s).
+ * It is unnecessary (but OK) to call jpeg_abort in this case.
+ * The JPEG_SUSPENDED return code only occurs if the data source module
+ * requests suspension of the decompressor. In this case the application
+ * should load more source data and then re-call jpeg_read_header to resume
+ * processing.
+ * If a non-suspending data source is used and require_image is TRUE, then the
+ * return code need not be inspected since only JPEG_HEADER_OK is possible.
+ *
+ * This routine is now just a front end to jpeg_consume_input, with some
+ * extra error checking.
+ */
+
+GLOBAL(int)
+jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
+{
+ int retcode;
+
+ if (cinfo->global_state != DSTATE_START &&
+ cinfo->global_state != DSTATE_INHEADER)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ retcode = jpeg_consume_input(cinfo);
+
+ switch (retcode) {
+ case JPEG_REACHED_SOS:
+ retcode = JPEG_HEADER_OK;
+ break;
+ case JPEG_REACHED_EOI:
+ if (require_image) /* Complain if application wanted an image */
+ ERREXIT(cinfo, JERR_NO_IMAGE);
+ /* Reset to start state; it would be safer to require the application to
+ * call jpeg_abort, but we can't change it now for compatibility reasons.
+ * A side effect is to free any temporary memory (there shouldn't be any).
+ */
+ jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
+ retcode = JPEG_HEADER_TABLES_ONLY;
+ break;
+ case JPEG_SUSPENDED:
+ /* no work */
+ break;
+ }
+
+ return retcode;
+}
+
+
+/*
+ * Consume data in advance of what the decompressor requires.
+ * This can be called at any time once the decompressor object has
+ * been created and a data source has been set up.
+ *
+ * This routine is essentially a state machine that handles a couple
+ * of critical state-transition actions, namely initial setup and
+ * transition from header scanning to ready-for-start_decompress.
+ * All the actual input is done via the input controller's consume_input
+ * method.
+ */
+
+GLOBAL(int)
+jpeg_consume_input (j_decompress_ptr cinfo)
+{
+ int retcode = JPEG_SUSPENDED;
+
+ /* NB: every possible DSTATE value should be listed in this switch */
+ switch (cinfo->global_state) {
+ case DSTATE_START:
+ /* Start-of-datastream actions: reset appropriate modules */
+ (*cinfo->inputctl->reset_input_controller) (cinfo);
+ /* Initialize application's data source module */
+ (*cinfo->src->init_source) (cinfo);
+ cinfo->global_state = DSTATE_INHEADER;
+ /*FALLTHROUGH*/
+ case DSTATE_INHEADER:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+ /* Set up default parameters based on header data */
+ default_decompress_parms(cinfo);
+ /* Set global state: ready for start_decompress */
+ cinfo->global_state = DSTATE_READY;
+ }
+ break;
+ case DSTATE_READY:
+ /* Can't advance past first SOS until start_decompress is called */
+ retcode = JPEG_REACHED_SOS;
+ break;
+ case DSTATE_PRELOAD:
+ case DSTATE_PRESCAN:
+ case DSTATE_SCANNING:
+ case DSTATE_RAW_OK:
+ case DSTATE_BUFIMAGE:
+ case DSTATE_BUFPOST:
+ case DSTATE_STOPPING:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ break;
+ default:
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ return retcode;
+}
+
+
+/*
+ * Have we finished reading the input file?
+ */
+
+GLOBAL(boolean)
+jpeg_input_complete (j_decompress_ptr cinfo)
+{
+ /* Check for valid jpeg object */
+ if (cinfo->global_state < DSTATE_START ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->eoi_reached;
+}
+
+
+/*
+ * Is there more than one scan?
+ */
+
+GLOBAL(boolean)
+jpeg_has_multiple_scans (j_decompress_ptr cinfo)
+{
+ /* Only valid after jpeg_read_header completes */
+ if (cinfo->global_state < DSTATE_READY ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->has_multiple_scans;
+}
+
+
+/*
+ * Finish JPEG decompression.
+ *
+ * This will normally just verify the file trailer and release temp storage.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_decompress (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
+ /* Terminate final pass of non-buffered mode */
+ if (cinfo->output_scanline < cinfo->output_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state == DSTATE_BUFIMAGE) {
+ /* Finishing after a buffered-image operation */
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state != DSTATE_STOPPING) {
+ /* STOPPING = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read until EOI */
+ while (! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ /* Do final cleanup */
+ (*cinfo->src->term_source) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+ return TRUE;
+}
diff --git a/gs/jpeg/jdapistd.c b/gs/jpeg/jdapistd.c
new file mode 100644
index 000000000..c8e3fa0c3
--- /dev/null
+++ b/gs/jpeg/jdapistd.c
@@ -0,0 +1,275 @@
+/*
+ * jdapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-decompression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_decompress, it will end up linking in the entire decompressor.
+ * We thus must separate this file from jdapimin.c to avoid linking the
+ * whole decompression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * If a multipass operating mode was selected, this will do all but the
+ * last pass, and thus may take a great deal of time.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_start_decompress (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ jinit_master_decompress(cinfo);
+ if (cinfo->buffered_image) {
+ /* No more work here; expecting jpeg_start_output next */
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+ }
+ cinfo->global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo->global_state == DSTATE_PRELOAD) {
+ /* If file has multiple scans, absorb them all into the coef buffer */
+ if (cinfo->inputctl->has_multiple_scans) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* jdmaster underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+ }
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ } else if (cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Set up for an output pass, and perform any dummy pass(es) needed.
+ * Common subroutine for jpeg_start_decompress and jpeg_start_output.
+ * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
+ * Exit: If done, returns TRUE and sets global_state for proper output mode.
+ * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
+ */
+
+LOCAL(boolean)
+output_pass_setup (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state != DSTATE_PRESCAN) {
+ /* First call: do pass setup */
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+ cinfo->global_state = DSTATE_PRESCAN;
+ }
+ /* Loop over any required dummy passes */
+ while (cinfo->master->is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Crank through the dummy pass */
+ while (cinfo->output_scanline < cinfo->output_height) {
+ JDIMENSION last_scanline;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* Process some data */
+ last_scanline = cinfo->output_scanline;
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
+ &cinfo->output_scanline, (JDIMENSION) 0);
+ if (cinfo->output_scanline == last_scanline)
+ return FALSE; /* No progress made, must suspend */
+ }
+ /* Finish up dummy pass, and set up for another one */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ }
+ /* Ready for application to drive output pass through
+ * jpeg_read_scanlines or jpeg_read_raw_data.
+ */
+ cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+ return TRUE;
+}
+
+
+/*
+ * Read some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually read.
+ * This may be less than the number requested in several cases,
+ * including bottom of image, data source suspension, and operating
+ * modes that emit multiple scanlines at a time.
+ *
+ * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * this likely signals an application programmer error. However,
+ * an oversize buffer (max_lines > scanlines remaining) is not an error.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
+{
+ JDIMENSION row_ctr;
+
+ if (cinfo->global_state != DSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Process some data */
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ cinfo->output_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to read raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION max_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != DSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Verify that at least one iMCU row can be returned. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
+ if (max_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Decompress directly into user's buffer. */
+ if (! (*cinfo->coef->decompress_data) (cinfo, data))
+ return 0; /* suspension forced, can do nothing more */
+
+ /* OK, we processed one iMCU row. */
+ cinfo->output_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
+
+
+/* Additional entry points for buffered-image mode. */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Initialize for an output pass in buffered-image mode.
+ */
+
+GLOBAL(boolean)
+jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
+{
+ if (cinfo->global_state != DSTATE_BUFIMAGE &&
+ cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Limit scan number to valid range */
+ if (scan_number <= 0)
+ scan_number = 1;
+ if (cinfo->inputctl->eoi_reached &&
+ scan_number > cinfo->input_scan_number)
+ scan_number = cinfo->input_scan_number;
+ cinfo->output_scan_number = scan_number;
+ /* Perform any dummy output passes, and set up for the real pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Finish up after an output pass in buffered-image mode.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_output (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
+ /* Terminate this pass. */
+ /* We do not require the whole pass to have been completed. */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_BUFPOST;
+ } else if (cinfo->global_state != DSTATE_BUFPOST) {
+ /* BUFPOST = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read markers looking for SOS or EOI */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/gs/jpeg/jdatadst.c b/gs/jpeg/jdatadst.c
new file mode 100644
index 000000000..a8f6fb0e0
--- /dev/null
+++ b/gs/jpeg/jdatadst.c
@@ -0,0 +1,151 @@
+/*
+ * jdatadst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains compression data destination routines for the case of
+ * emitting JPEG data to a file (or any stdio stream). While these routines
+ * are sufficient for most applications, some will want to use a different
+ * destination manager.
+ * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
+ * JOCTETs into 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ FILE * outfile; /* target stream */
+ JOCTET * buffer; /* start of buffer */
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ /* Allocate the output buffer --- it will be released when done with image */
+ dest->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
+ (size_t) OUTPUT_BUF_SIZE)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written. Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+ size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+ /* Write any data remaining in the buffer */
+ if (datacount > 0) {
+ if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ }
+ fflush(dest->outfile);
+ /* Make sure we wrote the output file OK */
+ if (ferror(dest->outfile))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
+{
+ my_dest_ptr dest;
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same file without re-executing jpeg_stdio_dest.
+ * This makes it dangerous to use this manager and a different destination
+ * manager serially with the same JPEG object, because their private object
+ * sizes may be different. Caveat programmer.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_destination_mgr));
+ }
+
+ dest = (my_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->outfile = outfile;
+}
diff --git a/gs/jpeg/jdatasrc.c b/gs/jpeg/jdatasrc.c
new file mode 100644
index 000000000..edc752bf5
--- /dev/null
+++ b/gs/jpeg/jdatasrc.c
@@ -0,0 +1,212 @@
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from a file (or any stdio stream). While these routines
+ * are sufficient for most applications, some will want to use a different
+ * source manager.
+ * IMPORTANT: we assume that fread() will correctly transcribe an array of
+ * JOCTETs from 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/* Expanded data source object for stdio input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ FILE * infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = TRUE;
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded. It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return. If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer. In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there. However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later. In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any). The application should resume
+ * decompression after it has loaded more data into the input buffer. Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return. If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) fill_input_buffer(cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
+{
+ my_src_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_source_mgr));
+ src = (my_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * SIZEOF(JOCTET));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
diff --git a/gs/jpeg/jdcoefct.c b/gs/jpeg/jdcoefct.c
new file mode 100644
index 000000000..c0cd0bd50
--- /dev/null
+++ b/gs/jpeg/jdcoefct.c
@@ -0,0 +1,735 @@
+/*
+ * jdcoefct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for decompression.
+ * This controller is the top level of the JPEG decompressor proper.
+ * The coefficient buffer lies between entropy decoding and inverse-DCT steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ * Also, the input side (only) is used when reading a file for transcoding.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* Block smoothing is only applicable for progressive JPEG, so: */
+#ifndef D_PROGRESSIVE_SUPPORTED
+#undef BLOCK_SMOOTHING_SUPPORTED
+#endif
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_coef_controller pub; /* public fields */
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ /* In single-pass modes, it's sufficient to buffer just one MCU.
+ * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+ * and let the entropy decoder write into that workspace each time.
+ * (On 80x86, the workspace is FAR even though it's not really very big;
+ * this is to keep the module interfaces unchanged when a large coefficient
+ * buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays; it is used only by the input side.
+ */
+ JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+#endif
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* When doing block smoothing, we latch coefficient Al values here */
+ int * coef_bits_latch;
+#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
+#endif
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_onepass
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) decompress_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));
+METHODDEF(int) decompress_smooth_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->MCU_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass (j_decompress_ptr cinfo)
+{
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* If multipass, check to see whether to use block smoothing on this pass */
+ if (coef->pub.coef_arrays != NULL) {
+ if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
+ coef->pub.decompress_data = decompress_smooth_data;
+ else
+ coef->pub.decompress_data = decompress_data;
+ }
+#endif
+ cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the single-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ * For single pass, this is the same as the components in the scan.
+ */
+
+METHODDEF(int)
+decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, useful_width;
+ JSAMPARRAY output_ptr;
+ JDIMENSION start_col, output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
+ jzero_far((void FAR *) coef->MCU_buffer[0],
+ (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ /* Determine where data should go in output_buf and do the IDCT thing.
+ * We skip dummy blocks at the right and bottom edges (but blkn gets
+ * incremented past them!). Note the inner loop relies on having
+ * allocated the MCU_buffer[] blocks sequentially.
+ */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed) {
+ blkn += compptr->MCU_blocks;
+ continue;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+ useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ output_ptr = output_buf[ci] + yoffset * compptr->DCT_scaled_size;
+ start_col = MCU_col_num * compptr->MCU_sample_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (cinfo->input_iMCU_row < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ output_col = start_col;
+ for (xindex = 0; xindex < useful_width; xindex++) {
+ (*inverse_DCT) (cinfo, compptr,
+ (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
+ output_ptr, output_col);
+ output_col += compptr->DCT_scaled_size;
+ }
+ }
+ blkn += compptr->MCU_width;
+ output_ptr += compptr->DCT_scaled_size;
+ }
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ cinfo->output_iMCU_row++;
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data (j_decompress_ptr cinfo)
+{
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image coefficient buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor block rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ cinfo->input_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Note: entropy decoder expects buffer to be zeroed,
+ * but this is handled automatically by the memory manager
+ * because we requested a pre-zeroed array.
+ */
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to fetch the MCU. */
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Decompress and return some data in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num;
+ int ci, block_row, block_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number < cinfo->output_scan_number ||
+ (cinfo->input_scan_number == cinfo->output_scan_number &&
+ cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ cinfo->output_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ output_col = 0;
+ for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
+ output_ptr, output_col);
+ buffer_ptr++;
+ output_col += compptr->DCT_scaled_size;
+ }
+ output_ptr += compptr->DCT_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+
+/*
+ * This code applies interblock smoothing as described by section K.8
+ * of the JPEG standard: the first 5 AC coefficients are estimated from
+ * the DC values of a DCT block and its 8 neighboring blocks.
+ * We apply smoothing only for progressive JPEG decoding, and only if
+ * the coefficients it can estimate are not yet known to full precision.
+ */
+
+/* Natural-order array positions of the first 5 zigzag-order coefficients */
+#define Q01_POS 1
+#define Q10_POS 8
+#define Q20_POS 16
+#define Q11_POS 9
+#define Q02_POS 2
+
+/*
+ * Determine whether block smoothing is applicable and safe.
+ * We also latch the current states of the coef_bits[] entries for the
+ * AC coefficients; otherwise, if the input side of the decompressor
+ * advances into a new scan, we might think the coefficients are known
+ * more accurately than they really are.
+ */
+
+LOCAL(boolean)
+smoothing_ok (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ boolean smoothing_useful = FALSE;
+ int ci, coefi;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtable;
+ int * coef_bits;
+ int * coef_bits_latch;
+
+ if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
+ return FALSE;
+
+ /* Allocate latch area if not already done */
+ if (coef->coef_bits_latch == NULL)
+ coef->coef_bits_latch = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components *
+ (SAVED_COEFS * SIZEOF(int)));
+ coef_bits_latch = coef->coef_bits_latch;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* All components' quantization values must already be latched. */
+ if ((qtable = compptr->quant_table) == NULL)
+ return FALSE;
+ /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
+ if (qtable->quantval[0] == 0 ||
+ qtable->quantval[Q01_POS] == 0 ||
+ qtable->quantval[Q10_POS] == 0 ||
+ qtable->quantval[Q20_POS] == 0 ||
+ qtable->quantval[Q11_POS] == 0 ||
+ qtable->quantval[Q02_POS] == 0)
+ return FALSE;
+ /* DC values must be at least partly known for all components. */
+ coef_bits = cinfo->coef_bits[ci];
+ if (coef_bits[0] < 0)
+ return FALSE;
+ /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
+ for (coefi = 1; coefi <= 5; coefi++) {
+ coef_bits_latch[coefi] = coef_bits[coefi];
+ if (coef_bits[coefi] != 0)
+ smoothing_useful = TRUE;
+ }
+ coef_bits_latch += SAVED_COEFS;
+ }
+
+ return smoothing_useful;
+}
+
+
+/*
+ * Variant of decompress_data for use when doing block smoothing.
+ */
+
+METHODDEF(int)
+decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num, last_block_column;
+ int ci, block_row, block_rows, access_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+ boolean first_row, last_row;
+ JBLOCK workspace;
+ int *coef_bits;
+ JQUANT_TBL *quanttbl;
+ INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
+ int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
+ int Al, pred;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if (cinfo->input_scan_number == cinfo->output_scan_number) {
+ /* If input is working on current scan, we ordinarily want it to
+ * have completed the current row. But if input scan is DC,
+ * we want it to keep one row ahead so that next block row's DC
+ * values are up to date.
+ */
+ JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
+ if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
+ break;
+ }
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row) {
+ block_rows = compptr->v_samp_factor;
+ access_rows = block_rows * 2; /* this and next iMCU row */
+ last_row = FALSE;
+ } else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ access_rows = block_rows; /* this iMCU row only */
+ last_row = TRUE;
+ }
+ /* Align the virtual buffer for this component. */
+ if (cinfo->output_iMCU_row > 0) {
+ access_rows += compptr->v_samp_factor; /* prior iMCU row too */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
+ (JDIMENSION) access_rows, FALSE);
+ buffer += compptr->v_samp_factor; /* point to current iMCU row */
+ first_row = FALSE;
+ } else {
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
+ first_row = TRUE;
+ }
+ /* Fetch component-dependent info */
+ coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
+ quanttbl = compptr->quant_table;
+ Q00 = quanttbl->quantval[0];
+ Q01 = quanttbl->quantval[Q01_POS];
+ Q10 = quanttbl->quantval[Q10_POS];
+ Q20 = quanttbl->quantval[Q20_POS];
+ Q11 = quanttbl->quantval[Q11_POS];
+ Q02 = quanttbl->quantval[Q02_POS];
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ if (first_row && block_row == 0)
+ prev_block_row = buffer_ptr;
+ else
+ prev_block_row = buffer[block_row-1];
+ if (last_row && block_row == block_rows-1)
+ next_block_row = buffer_ptr;
+ else
+ next_block_row = buffer[block_row+1];
+ /* We fetch the surrounding DC values using a sliding-register approach.
+ * Initialize all nine here so as to do the right thing on narrow pics.
+ */
+ DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
+ DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
+ DC7 = DC8 = DC9 = (int) next_block_row[0][0];
+ output_col = 0;
+ last_block_column = compptr->width_in_blocks - 1;
+ for (block_num = 0; block_num <= last_block_column; block_num++) {
+ /* Fetch current DCT block into workspace so we can modify it. */
+ jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
+ /* Update DC values */
+ if (block_num < last_block_column) {
+ DC3 = (int) prev_block_row[1][0];
+ DC6 = (int) buffer_ptr[1][0];
+ DC9 = (int) next_block_row[1][0];
+ }
+ /* Compute coefficient estimates per K.8.
+ * An estimate is applied only if coefficient is still zero,
+ * and is not known to be fully accurate.
+ */
+ /* AC01 */
+ if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
+ num = 36 * Q00 * (DC4 - DC6);
+ if (num >= 0) {
+ pred = (int) (((Q01<<7) + num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q01<<7) - num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[1] = (JCOEF) pred;
+ }
+ /* AC10 */
+ if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {
+ num = 36 * Q00 * (DC2 - DC8);
+ if (num >= 0) {
+ pred = (int) (((Q10<<7) + num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q10<<7) - num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[8] = (JCOEF) pred;
+ }
+ /* AC20 */
+ if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {
+ num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q20<<7) + num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q20<<7) - num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[16] = (JCOEF) pred;
+ }
+ /* AC11 */
+ if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {
+ num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
+ if (num >= 0) {
+ pred = (int) (((Q11<<7) + num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q11<<7) - num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[9] = (JCOEF) pred;
+ }
+ /* AC02 */
+ if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {
+ num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q02<<7) + num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q02<<7) - num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[2] = (JCOEF) pred;
+ }
+ /* OK, do the IDCT */
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,
+ output_ptr, output_col);
+ /* Advance for next column */
+ DC1 = DC2; DC2 = DC3;
+ DC4 = DC5; DC5 = DC6;
+ DC7 = DC8; DC8 = DC9;
+ buffer_ptr++, prev_block_row++, next_block_row++;
+ output_col += compptr->DCT_scaled_size;
+ }
+ output_ptr += compptr->DCT_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* BLOCK_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_d_coef_controller *) coef;
+ coef->pub.start_input_pass = start_input_pass;
+ coef->pub.start_output_pass = start_output_pass;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ coef->coef_bits_latch = NULL;
+#endif
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ /* Note we ask for a pre-zeroed array. */
+ int ci, access_rows;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* If block smoothing could be used, need a bigger window */
+ if (cinfo->progressive_mode)
+ access_rows *= 3;
+#endif
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) access_rows);
+ }
+ coef->pub.consume_data = consume_data;
+ coef->pub.decompress_data = decompress_data;
+ coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->pub.consume_data = dummy_consume_data;
+ coef->pub.decompress_data = decompress_onepass;
+ coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/gs/jpeg/jdcolor.c b/gs/jpeg/jdcolor.c
new file mode 100644
index 000000000..026949840
--- /dev/null
+++ b/gs/jpeg/jdcolor.c
@@ -0,0 +1,367 @@
+/*
+ * jdcolor.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains output colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_deconverter pub; /* public fields */
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+} my_color_deconverter;
+
+typedef my_color_deconverter * my_cconvert_ptr;
+
+
+/**************** YCbCr -> RGB conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ * Notice that Y, being an integral input, does not contribute any fraction
+ * so it need not participate in the rounding.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times Cb and Cr for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+ * values for the G calculation are left scaled up, since we must add them
+ * together before rounding.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ cconvert->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ cconvert->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ cconvert->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ cconvert->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the output colorspace.
+ *
+ * Note that we change from noninterleaved, one-plane-per-component format
+ * to interleaved-pixel format. The output buffer is therefore three times
+ * as wide as the input buffer.
+ * A starting row offset is provided only for the input buffer. The caller
+ * can easily adjust the passed output_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+ycc_rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
+ outptr[RGB_GREEN] = range_limit[y +
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS))];
+ outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/**************** Cases other than YCbCr -> RGB **************/
+
+
+/*
+ * Color conversion for no colorspace change: just copy the data,
+ * converting from separate-planes to interleaved representation.
+ */
+
+METHODDEF(void)
+null_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION count;
+ register int num_components = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->output_width;
+ int ci;
+
+ while (--num_rows >= 0) {
+ for (ci = 0; ci < num_components; ci++) {
+ inptr = input_buf[ci][input_row];
+ outptr = output_buf[0] + ci;
+ for (count = num_cols; count > 0; count--) {
+ *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */
+ outptr += num_components;
+ }
+ }
+ input_row++;
+ output_buf++;
+ }
+}
+
+
+/*
+ * Color conversion for grayscale: just copy the data.
+ * This also works for YCbCr -> grayscale conversion, in which
+ * we just copy the Y (luminance) component and ignore chrominance.
+ */
+
+METHODDEF(void)
+grayscale_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
+ num_rows, cinfo->output_width);
+}
+
+
+/*
+ * Adobe-style YCCK->CMYK conversion.
+ * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume build_ycc_rgb_table has been called.
+ */
+
+METHODDEF(void)
+ycck_cmyk_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ inptr3 = input_buf[3][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
+ outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS)))];
+ outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
+ /* K passes through unchanged */
+ outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
+ outptr += 4;
+ }
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+start_pass_dcolor (j_decompress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for output colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_deconverter (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+ int ci;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_deconverter));
+ cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert;
+ cconvert->pub.start_pass = start_pass_dcolor;
+
+ /* Make sure num_components agrees with jpeg_color_space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->num_components < 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+ }
+
+ /* Set out_color_components and conversion method based on requested space.
+ * Also clear the component_needed flags for any unused components,
+ * so that earlier pipeline stages can avoid useless computation.
+ */
+
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
+ cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = grayscale_convert;
+ /* For color->grayscale conversion, only the Y (0) component is needed */
+ for (ci = 1; ci < cinfo->num_components; ci++)
+ cinfo->comp_info[ci].component_needed = FALSE;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgb_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) {
+ cconvert->pub.color_convert = null_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ cinfo->out_color_components = 4;
+ if (cinfo->jpeg_color_space == JCS_YCCK) {
+ cconvert->pub.color_convert = ycck_cmyk_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_CMYK) {
+ cconvert->pub.color_convert = null_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default:
+ /* Permit null conversion to same output space */
+ if (cinfo->out_color_space == cinfo->jpeg_color_space) {
+ cinfo->out_color_components = cinfo->num_components;
+ cconvert->pub.color_convert = null_convert;
+ } else /* unsupported non-null conversion */
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+ }
+
+ if (cinfo->quantize_colors)
+ cinfo->output_components = 1; /* single colormapped output component */
+ else
+ cinfo->output_components = cinfo->out_color_components;
+}
diff --git a/gs/jpeg/jdct.h b/gs/jpeg/jdct.h
new file mode 100644
index 000000000..04192a266
--- /dev/null
+++ b/gs/jpeg/jdct.h
@@ -0,0 +1,176 @@
+/*
+ * jdct.h
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file contains common declarations for the forward and
+ * inverse DCT modules. These declarations are private to the DCT managers
+ * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+ * The individual DCT algorithms are kept in separate files to ease
+ * machine-dependent tuning (e.g., assembly coding).
+ */
+
+
+/*
+ * A forward DCT routine is given a pointer to a work area of type DCTELEM[];
+ * the DCT is to be performed in-place in that buffer. Type DCTELEM is int
+ * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT
+ * implementations use an array of type FAST_FLOAT, instead.)
+ * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
+ * The DCT outputs are returned scaled up by a factor of 8; they therefore
+ * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
+ * convention improves accuracy in integer implementations and saves some
+ * work in floating-point ones.
+ * Quantization of the output coefficients is done by jcdctmgr.c.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef int DCTELEM; /* 16 or 32 bits is fine */
+#else
+typedef INT32 DCTELEM; /* must have 32 bits */
+#endif
+
+typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data));
+typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data));
+
+
+/*
+ * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+ * to an output sample array. The routine must dequantize the input data as
+ * well as perform the IDCT; for dequantization, it uses the multiplier table
+ * pointed to by compptr->dct_table. The output data is to be placed into the
+ * sample array starting at a specified column. (Any row offset needed will
+ * be applied to the array pointer before it is passed to the IDCT code.)
+ * Note that the number of samples emitted by the IDCT routine is
+ * DCT_scaled_size * DCT_scaled_size.
+ */
+
+/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
+
+/*
+ * Each IDCT routine has its own ideas about the best dct_table element type.
+ */
+
+typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
+#if BITS_IN_JSAMPLE == 8
+typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
+#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
+#else
+typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
+#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
+#endif
+typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
+
+
+/*
+ * Each IDCT routine is responsible for range-limiting its results and
+ * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
+ * be quite far out of range if the input data is corrupt, so a bulletproof
+ * range-limiting step is required. We use a mask-and-table-lookup method
+ * to do the combined operations quickly. See the comments with
+ * prepare_range_limit_table (in jdmaster.c) for more info.
+ */
+
+#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
+
+#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_fdct_islow jFDislow
+#define jpeg_fdct_ifast jFDifast
+#define jpeg_fdct_float jFDfloat
+#define jpeg_idct_islow jRDislow
+#define jpeg_idct_ifast jRDifast
+#define jpeg_idct_float jRDfloat
+#define jpeg_idct_4x4 jRD4x4
+#define jpeg_idct_2x2 jRD2x2
+#define jpeg_idct_1x1 jRD1x1
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Extern declarations for the forward and inverse DCT routines. */
+
+EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data));
+EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data));
+EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data));
+
+EXTERN(void) jpeg_idct_islow
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_ifast
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_float
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x1
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+
+
+/*
+ * Macros for handling fixed-point arithmetic; these are used by many
+ * but not all of the DCT/IDCT modules.
+ *
+ * All values are expected to be of type INT32.
+ * Fractional constants are scaled left by CONST_BITS bits.
+ * CONST_BITS is defined within each module using these macros,
+ * and may differ from one module to the next.
+ */
+
+#define ONE ((INT32) 1)
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
+ * thus causing a lot of useless floating-point operations at run time.
+ */
+
+#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
+
+/* Descale and correctly round an INT32 value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * This macro is used only when the two inputs will actually be no more than
+ * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
+ * full 32x32 multiply. This provides a useful speedup on many machines.
+ * Unfortunately there is no way to specify a 16x16->32 multiply portably
+ * in C, but some C compilers will do the right thing if you provide the
+ * correct combination of casts.
+ */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
+#endif
+#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
+#endif
+
+#ifndef MULTIPLY16C16 /* default definition */
+#define MULTIPLY16C16(var,const) ((var) * (const))
+#endif
+
+/* Same except both inputs are variables. */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2)))
+#endif
+
+#ifndef MULTIPLY16V16 /* default definition */
+#define MULTIPLY16V16(var1,var2) ((var1) * (var2))
+#endif
diff --git a/gs/jpeg/jddctmgr.c b/gs/jpeg/jddctmgr.c
new file mode 100644
index 000000000..bbf8d0e92
--- /dev/null
+++ b/gs/jpeg/jddctmgr.c
@@ -0,0 +1,269 @@
+/*
+ * jddctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the inverse-DCT management logic.
+ * This code selects a particular IDCT implementation to be used,
+ * and it performs related housekeeping chores. No code in this file
+ * is executed per IDCT step, only during output pass setup.
+ *
+ * Note that the IDCT routines are responsible for performing coefficient
+ * dequantization as well as the IDCT proper. This module sets up the
+ * dequantization multiplier table needed by the IDCT routine.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/*
+ * The decompressor input side (jdinput.c) saves away the appropriate
+ * quantization table for each component at the start of the first scan
+ * involving that component. (This is necessary in order to correctly
+ * decode files that reuse Q-table slots.)
+ * When we are ready to make an output pass, the saved Q-table is converted
+ * to a multiplier table that will actually be used by the IDCT routine.
+ * The multiplier table contents are IDCT-method-dependent. To support
+ * application changes in IDCT method between scans, we can remake the
+ * multiplier tables if necessary.
+ * In buffered-image mode, the first output pass may occur before any data
+ * has been seen for some components, and thus before their Q-tables have
+ * been saved away. To handle this case, multiplier tables are preset
+ * to zeroes; the result of the IDCT will be a neutral gray level.
+ */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_inverse_dct pub; /* public fields */
+
+ /* This array contains the IDCT method code that each multiplier table
+ * is currently set up for, or -1 if it's not yet set up.
+ * The actual multiplier tables are pointed to by dct_table in the
+ * per-component comp_info structures.
+ */
+ int cur_method[MAX_COMPONENTS];
+} my_idct_controller;
+
+typedef my_idct_controller * my_idct_ptr;
+
+
+/* Allocated multiplier tables: big enough for any supported variant */
+
+typedef union {
+ ISLOW_MULT_TYPE islow_array[DCTSIZE2];
+#ifdef DCT_IFAST_SUPPORTED
+ IFAST_MULT_TYPE ifast_array[DCTSIZE2];
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ FLOAT_MULT_TYPE float_array[DCTSIZE2];
+#endif
+} multiplier_table;
+
+
+/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef IDCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Prepare for an output pass.
+ * Here we select the proper IDCT routine for each component and build
+ * a matching multiplier table.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
+ int ci, i;
+ jpeg_component_info *compptr;
+ int method = 0;
+ inverse_DCT_method_ptr method_ptr = NULL;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Select the proper IDCT routine for this component's scaling */
+ switch (compptr->DCT_scaled_size) {
+#ifdef IDCT_SCALING_SUPPORTED
+ case 1:
+ method_ptr = jpeg_idct_1x1;
+ method = JDCT_ISLOW; /* jidctred uses islow-style table */
+ break;
+ case 2:
+ method_ptr = jpeg_idct_2x2;
+ method = JDCT_ISLOW; /* jidctred uses islow-style table */
+ break;
+ case 4:
+ method_ptr = jpeg_idct_4x4;
+ method = JDCT_ISLOW; /* jidctred uses islow-style table */
+ break;
+#endif
+ case DCTSIZE:
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ method_ptr = jpeg_idct_islow;
+ method = JDCT_ISLOW;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ method_ptr = jpeg_idct_ifast;
+ method = JDCT_IFAST;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ method_ptr = jpeg_idct_float;
+ method = JDCT_FLOAT;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size);
+ break;
+ }
+ idct->pub.inverse_DCT[ci] = method_ptr;
+ /* Create multiplier table from quant table.
+ * However, we can skip this if the component is uninteresting
+ * or if we already built the table. Also, if no quant table
+ * has yet been saved for the component, we leave the
+ * multiplier table all-zero; we'll be reading zeroes from the
+ * coefficient controller's buffer anyway.
+ */
+ if (! compptr->component_needed || idct->cur_method[ci] == method)
+ continue;
+ qtbl = compptr->quant_table;
+ if (qtbl == NULL) /* happens if no data yet for component */
+ continue;
+ idct->cur_method[ci] = method;
+ switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ {
+ /* For LL&M IDCT method, multipliers are equal to raw quantization
+ * coefficients, but are stored as ints to ensure access efficiency.
+ */
+ ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ for (i = 0; i < DCTSIZE2; i++) {
+ ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
+ }
+ }
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * For integer operation, the multiplier table is to be scaled by
+ * IFAST_SCALE_BITS.
+ */
+ IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ ifmtbl[i] = (IFAST_MULT_TYPE)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-IFAST_SCALE_BITS);
+ }
+ }
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ */
+ FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fmtbl[i] = (FLOAT_MULT_TYPE)
+ ((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col]);
+ i++;
+ }
+ }
+ }
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Initialize IDCT manager.
+ */
+
+GLOBAL(void)
+jinit_inverse_dct (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct;
+ int ci;
+ jpeg_component_info *compptr;
+
+ idct = (my_idct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_idct_controller));
+ cinfo->idct = (struct jpeg_inverse_dct *) idct;
+ idct->pub.start_pass = start_pass;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate and pre-zero a multiplier table for each component */
+ compptr->dct_table =
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(multiplier_table));
+ MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
+ /* Mark multiplier table not yet set up for any method */
+ idct->cur_method[ci] = -1;
+ }
+}
diff --git a/gs/jpeg/jdhuff.c b/gs/jpeg/jdhuff.c
new file mode 100644
index 000000000..5b5544b67
--- /dev/null
+++ b/gs/jpeg/jdhuff.c
@@ -0,0 +1,574 @@
+/*
+ * jdhuff.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdhuff.h" /* Declarations shared with jdphuff.c */
+
+
+/*
+ * Expanded entropy decoder object for Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+ savable_state saved; /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+} huff_entropy_decoder;
+
+typedef huff_entropy_decoder * huff_entropy_ptr;
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, dctbl, actbl;
+ jpeg_component_info * compptr;
+
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning because
+ * there are some baseline files out there with all zeroes in these bytes.
+ */
+ if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 ||
+ cinfo->Ah != 0 || cinfo->Al != 0)
+ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ actbl = compptr->ac_tbl_no;
+ /* Make sure requested tables are present */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
+ cinfo->dc_huff_tbl_ptrs[dctbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ if (actbl < 0 || actbl >= NUM_HUFF_TBLS ||
+ cinfo->ac_huff_tbl_ptrs[actbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl],
+ & entropy->dc_derived_tbls[dctbl]);
+ jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl],
+ & entropy->ac_derived_tbls[actbl]);
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->bitstate.printed_eod = FALSE;
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * Note this is also used by jdphuff.c.
+ */
+
+GLOBAL(void)
+jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, JHUFF_TBL * htbl,
+ d_derived_tbl ** pdtbl)
+{
+ d_derived_tbl *dtbl;
+ int p, i, l, si;
+ int lookbits, ctr;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (d_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(d_derived_tbl));
+ dtbl = *pdtbl;
+ dtbl->pub = htbl; /* fill in back link */
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+ /* Note that this is in code-length order. */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ for (i = 1; i <= (int) htbl->bits[l]; i++)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+
+ /* Figure C.2: generate the codes themselves */
+ /* Note that this is in code-length order. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure F.15: generate decoding tables for bit-sequential decoding */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ if (htbl->bits[l]) {
+ dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */
+ dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */
+ p += htbl->bits[l];
+ dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
+ } else {
+ dtbl->maxcode[l] = -1; /* -1 if no codes of this length */
+ }
+ }
+ dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
+
+ /* Compute lookahead tables to speed up decoding.
+ * First we set all the table entries to 0, indicating "too long";
+ * then we iterate through the Huffman codes that are short enough and
+ * fill in all the entries that correspond to bit sequences starting
+ * with that code.
+ */
+
+ MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
+
+ p = 0;
+ for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+ for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
+ /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+ /* Generate left-justified code followed by all possible bit sequences */
+ lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+ for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+ dtbl->look_nbits[lookbits] = l;
+ dtbl->look_sym[lookbits] = htbl->huffval[p];
+ lookbits++;
+ }
+ }
+ }
+}
+
+
+/*
+ * Out-of-line code for bit fetching (shared with jdphuff.c).
+ * See jdhuff.h for info about usage.
+ * Note: current values of get_buffer and bits_left are passed as parameters,
+ * but are returned in the corresponding fields of the state struct.
+ *
+ * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
+ * of get_buffer to be used. (On machines with wider words, an even larger
+ * buffer could be used.) However, on some machines 32-bit shifts are
+ * quite slow and take time proportional to the number of places shifted.
+ * (This is true with most PC compilers, for instance.) In this case it may
+ * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the
+ * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
+ */
+
+#ifdef SLOW_SHIFT_32
+#define MIN_GET_BITS 15 /* minimum allowable value */
+#else
+#define MIN_GET_BITS (BIT_BUF_SIZE-7)
+#endif
+
+
+GLOBAL(boolean)
+jpeg_fill_bit_buffer (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ int nbits)
+/* Load up the bit buffer to a depth of at least nbits */
+{
+ /* Copy heavily used state fields into locals (hopefully registers) */
+ register const JOCTET * next_input_byte = state->next_input_byte;
+ register size_t bytes_in_buffer = state->bytes_in_buffer;
+ register int c;
+
+ /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+ /* (It is assumed that no request will be for more than that many bits.) */
+
+ while (bits_left < MIN_GET_BITS) {
+ /* Attempt to read a byte */
+ if (state->unread_marker != 0)
+ goto no_more_data; /* can't advance past a marker */
+
+ if (bytes_in_buffer == 0) {
+ if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo))
+ return FALSE;
+ next_input_byte = state->cinfo->src->next_input_byte;
+ bytes_in_buffer = state->cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+
+ /* If it's 0xFF, check and discard stuffed zero byte */
+ if (c == 0xFF) {
+ do {
+ if (bytes_in_buffer == 0) {
+ if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo))
+ return FALSE;
+ next_input_byte = state->cinfo->src->next_input_byte;
+ bytes_in_buffer = state->cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+ } while (c == 0xFF);
+
+ if (c == 0) {
+ /* Found FF/00, which represents an FF data byte */
+ c = 0xFF;
+ } else {
+ /* Oops, it's actually a marker indicating end of compressed data. */
+ /* Better put it back for use later */
+ state->unread_marker = c;
+
+ no_more_data:
+ /* There should be enough bits still left in the data segment; */
+ /* if so, just break out of the outer while loop. */
+ if (bits_left >= nbits)
+ break;
+ /* Uh-oh. Report corrupted data to user and stuff zeroes into
+ * the data stream, so that we can produce some kind of image.
+ * Note that this code will be repeated for each byte demanded
+ * for the rest of the segment. We use a nonvolatile flag to ensure
+ * that only one warning message appears.
+ */
+ if (! *(state->printed_eod_ptr)) {
+ WARNMS(state->cinfo, JWRN_HIT_MARKER);
+ *(state->printed_eod_ptr) = TRUE;
+ }
+ c = 0; /* insert a zero byte into bit buffer */
+ }
+ }
+
+ /* OK, load c into get_buffer */
+ get_buffer = (get_buffer << 8) | c;
+ bits_left += 8;
+ }
+
+ /* Unload the local registers */
+ state->next_input_byte = next_input_byte;
+ state->bytes_in_buffer = bytes_in_buffer;
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ return TRUE;
+}
+
+
+/*
+ * Out-of-line code for Huffman code decoding.
+ * See jdhuff.h for info about usage.
+ */
+
+GLOBAL(int)
+jpeg_huff_decode (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ d_derived_tbl * htbl, int min_bits)
+{
+ register int l = min_bits;
+ register INT32 code;
+
+ /* HUFF_DECODE has determined that the code is at least min_bits */
+ /* bits long, so fetch that many bits in one swoop. */
+
+ CHECK_BIT_BUFFER(*state, l, return -1);
+ code = GET_BITS(l);
+
+ /* Collect the rest of the Huffman code one bit at a time. */
+ /* This is per Figure F.16 in the JPEG spec. */
+
+ while (code > htbl->maxcode[l]) {
+ code <<= 1;
+ CHECK_BIT_BUFFER(*state, 1, return -1);
+ code |= GET_BITS(1);
+ l++;
+ }
+
+ /* Unload the local registers */
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ /* With garbage input we may reach the sentinel value l = 17. */
+
+ if (l > 16) {
+ WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
+ return 0; /* fake a zero as the safest result */
+ }
+
+ return htbl->pub->huffval[ htbl->valptr[l] +
+ ((int) (code - htbl->mincode[l])) ];
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
+
+#else
+
+#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
+
+static const int extend_test[16] = /* entry n is 2**(n-1) */
+ { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
+
+static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
+ { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
+ ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
+ ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
+ ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+
+ /* Next segment can get another out-of-data warning */
+ entropy->bitstate.printed_eod = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Decode and return one MCU's worth of Huffman-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
+ * (Wholesale zeroing is usually a little faster than retail...)
+ *
+ * Returns FALSE if data source requested suspension. In that case no
+ * changes have been made to permanent state. (Exception: some output
+ * coefficients may already have been assigned. This is harmless for
+ * this module, since we'll just re-assign them on the next call.)
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int s, k, r;
+ int blkn, ci;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ savable_state state;
+ d_derived_tbl * dctbl;
+ d_derived_tbl * actbl;
+ jpeg_component_info * compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = entropy->dc_derived_tbls[compptr->dc_tbl_no];
+ actbl = entropy->ac_derived_tbls[compptr->ac_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* Shortcut if component's values are not interesting */
+ if (! compptr->component_needed)
+ goto skip_ACs;
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
+ (*block)[0] = (JCOEF) s;
+
+ /* Do we need to decode the AC coefficients for this component? */
+ if (compptr->DCT_scaled_size > 1) {
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (k = 1; k < DCTSIZE2; k++) {
+ HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Output coefficient in natural (dezigzagged) order.
+ * Note: the extra entries in jpeg_natural_order[] will save us
+ * if k >= DCTSIZE2, which could happen if the data is corrupted.
+ */
+ (*block)[jpeg_natural_order[k]] = (JCOEF) s;
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ } else {
+skip_ACs:
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (k = 1; k < DCTSIZE2; k++) {
+ HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ }
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff_decoder;
+ entropy->pub.decode_mcu = decode_mcu;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+ }
+}
diff --git a/gs/jpeg/jdhuff.h b/gs/jpeg/jdhuff.h
new file mode 100644
index 000000000..bcc3ab127
--- /dev/null
+++ b/gs/jpeg/jdhuff.h
@@ -0,0 +1,202 @@
+/*
+ * jdhuff.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains declarations for Huffman entropy decoding routines
+ * that are shared between the sequential decoder (jdhuff.c) and the
+ * progressive decoder (jdphuff.c). No other modules need to see these.
+ */
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_make_d_derived_tbl jMkDDerived
+#define jpeg_fill_bit_buffer jFilBitBuf
+#define jpeg_huff_decode jHufDecode
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Derived data constructed for each Huffman table */
+
+#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
+
+typedef struct {
+ /* Basic tables: (element [0] of each array is unused) */
+ INT32 mincode[17]; /* smallest code of length k */
+ INT32 maxcode[18]; /* largest code of length k (-1 if none) */
+ /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
+ int valptr[17]; /* huffval[] index of 1st symbol of length k */
+
+ /* Link to public Huffman table (needed only in jpeg_huff_decode) */
+ JHUFF_TBL *pub;
+
+ /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+ * the input data stream. If the next Huffman code is no more
+ * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+ * the corresponding symbol directly from these tables.
+ */
+ int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
+ UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
+} d_derived_tbl;
+
+/* Expand a Huffman table definition into the derived format */
+EXTERN(void) jpeg_make_d_derived_tbl JPP((j_decompress_ptr cinfo,
+ JHUFF_TBL * htbl, d_derived_tbl ** pdtbl));
+
+
+/*
+ * Fetching the next N bits from the input stream is a time-critical operation
+ * for the Huffman decoders. We implement it with a combination of inline
+ * macros and out-of-line subroutines. Note that N (the number of bits
+ * demanded at one time) never exceeds 15 for JPEG use.
+ *
+ * We read source bytes into get_buffer and dole out bits as needed.
+ * If get_buffer already contains enough bits, they are fetched in-line
+ * by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough
+ * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
+ * as full as possible (not just to the number of bits needed; this
+ * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
+ * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
+ * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
+ * at least the requested number of bits --- dummy zeroes are inserted if
+ * necessary.
+ */
+
+typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
+#define BIT_BUF_SIZE 32 /* size of buffer in bits */
+
+/* If long is > 32 bits on your machine, and shifting/masking longs is
+ * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
+ * appropriately should be a win. Unfortunately we can't do this with
+ * something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
+ * because not all machines measure sizeof in 8-bit bytes.
+ */
+
+typedef struct { /* Bitreading state saved across MCUs */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ boolean printed_eod; /* flag to suppress multiple warning msgs */
+} bitread_perm_state;
+
+typedef struct { /* Bitreading working state within an MCU */
+ /* current data source state */
+ const JOCTET * next_input_byte; /* => next byte to read from source */
+ size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
+ int unread_marker; /* nonzero if we have hit a marker */
+ /* bit input buffer --- note these values are kept in register variables,
+ * not in this struct, inside the inner loops.
+ */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ /* pointers needed by jpeg_fill_bit_buffer */
+ j_decompress_ptr cinfo; /* back link to decompress master record */
+ boolean * printed_eod_ptr; /* => flag in permanent state */
+} bitread_working_state;
+
+/* Macros to declare and load/save bitread local variables. */
+#define BITREAD_STATE_VARS \
+ register bit_buf_type get_buffer; \
+ register int bits_left; \
+ bitread_working_state br_state
+
+#define BITREAD_LOAD_STATE(cinfop,permstate) \
+ br_state.cinfo = cinfop; \
+ br_state.next_input_byte = cinfop->src->next_input_byte; \
+ br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
+ br_state.unread_marker = cinfop->unread_marker; \
+ get_buffer = permstate.get_buffer; \
+ bits_left = permstate.bits_left; \
+ br_state.printed_eod_ptr = & permstate.printed_eod
+
+#define BITREAD_SAVE_STATE(cinfop,permstate) \
+ cinfop->src->next_input_byte = br_state.next_input_byte; \
+ cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
+ cinfop->unread_marker = br_state.unread_marker; \
+ permstate.get_buffer = get_buffer; \
+ permstate.bits_left = bits_left
+
+/*
+ * These macros provide the in-line portion of bit fetching.
+ * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
+ * before using GET_BITS, PEEK_BITS, or DROP_BITS.
+ * The variables get_buffer and bits_left are assumed to be locals,
+ * but the state struct might not be (jpeg_huff_decode needs this).
+ * CHECK_BIT_BUFFER(state,n,action);
+ * Ensure there are N bits in get_buffer; if suspend, take action.
+ * val = GET_BITS(n);
+ * Fetch next N bits.
+ * val = PEEK_BITS(n);
+ * Fetch next N bits without removing them from the buffer.
+ * DROP_BITS(n);
+ * Discard next N bits.
+ * The value N should be a simple variable, not an expression, because it
+ * is evaluated multiple times.
+ */
+
+#define CHECK_BIT_BUFFER(state,nbits,action) \
+ { if (bits_left < (nbits)) { \
+ if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \
+ { action; } \
+ get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
+
+#define GET_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1))
+
+#define PEEK_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1))
+
+#define DROP_BITS(nbits) \
+ (bits_left -= (nbits))
+
+/* Load up the bit buffer to a depth of at least nbits */
+EXTERN(boolean) jpeg_fill_bit_buffer
+ JPP((bitread_working_state * state, register bit_buf_type get_buffer,
+ register int bits_left, int nbits));
+
+
+/*
+ * Code for extracting next Huffman-coded symbol from input bit stream.
+ * Again, this is time-critical and we make the main paths be macros.
+ *
+ * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+ * without looping. Usually, more than 95% of the Huffman codes will be 8
+ * or fewer bits long. The few overlength codes are handled with a loop,
+ * which need not be inline code.
+ *
+ * Notes about the HUFF_DECODE macro:
+ * 1. Near the end of the data segment, we may fail to get enough bits
+ * for a lookahead. In that case, we do it the hard way.
+ * 2. If the lookahead table contains no entry, the next code must be
+ * more than HUFF_LOOKAHEAD bits long.
+ * 3. jpeg_huff_decode returns -1 if forced to suspend.
+ */
+
+#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
+{ register int nb, look; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ nb = 1; goto slowlabel; \
+ } \
+ } \
+ look = PEEK_BITS(HUFF_LOOKAHEAD); \
+ if ((nb = htbl->look_nbits[look]) != 0) { \
+ DROP_BITS(nb); \
+ result = htbl->look_sym[look]; \
+ } else { \
+ nb = HUFF_LOOKAHEAD+1; \
+slowlabel: \
+ if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
+ { failaction; } \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ } \
+}
+
+/* Out-of-line case for Huffman code fetching */
+EXTERN(int) jpeg_huff_decode
+ JPP((bitread_working_state * state, register bit_buf_type get_buffer,
+ register int bits_left, d_derived_tbl * htbl, int min_bits));
diff --git a/gs/jpeg/jdinput.c b/gs/jpeg/jdinput.c
new file mode 100644
index 000000000..a8565c501
--- /dev/null
+++ b/gs/jpeg/jdinput.c
@@ -0,0 +1,381 @@
+/*
+ * jdinput.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input control logic for the JPEG decompressor.
+ * These routines are concerned with controlling the decompressor's input
+ * processing (marker reading and coefficient decoding). The actual input
+ * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_input_controller pub; /* public fields */
+
+ boolean inheaders; /* TRUE until first SOS is reached */
+} my_input_controller;
+
+typedef my_input_controller * my_inputctl_ptr;
+
+
+/* Forward declarations */
+METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Routines to calculate various quantities related to the size of the image.
+ */
+
+LOCAL(void)
+initial_setup (j_decompress_ptr cinfo)
+/* Called once, when first SOS marker is reached */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
+ * In the full decompressor, this will be overridden by jdmaster.c;
+ * but in the transcoder, jdmaster.c is not used, so we must do it here.
+ */
+ cinfo->min_DCT_scaled_size = DCTSIZE;
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->DCT_scaled_size = DCTSIZE;
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * DCTSIZE));
+ /* downsampled_width and downsampled_height will also be overridden by
+ * jdmaster.c if we are doing full decompression. The transcoder library
+ * doesn't use these values, but the calling application might.
+ */
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) cinfo->max_h_samp_factor);
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) cinfo->max_v_samp_factor);
+ /* Mark component needed, until color conversion says otherwise */
+ compptr->component_needed = TRUE;
+ /* Mark no quantization table yet saved for component */
+ compptr->quant_table = NULL;
+ }
+
+ /* Compute number of fully interleaved MCU rows. */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor*DCTSIZE));
+
+ /* Decide whether file contains multiple scans */
+ if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
+ cinfo->inputctl->has_multiple_scans = TRUE;
+ else
+ cinfo->inputctl->has_multiple_scans = FALSE;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_decompress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = compptr->DCT_scaled_size;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width,
+ (long) (cinfo->max_h_samp_factor*DCTSIZE));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor*DCTSIZE));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+}
+
+
+/*
+ * Save away a copy of the Q-table referenced by each component present
+ * in the current scan, unless already saved during a prior scan.
+ *
+ * In a multiple-scan JPEG file, the encoder could assign different components
+ * the same Q-table slot number, but change table definitions between scans
+ * so that each component uses a different Q-table. (The IJG encoder is not
+ * currently capable of doing this, but other encoders might.) Since we want
+ * to be able to dequantize all the components at the end of the file, this
+ * means that we have to save away the table actually used for each component.
+ * We do this by copying the table at the start of the first scan containing
+ * the component.
+ * The JPEG spec prohibits the encoder from changing the contents of a Q-table
+ * slot between scans of a component using that slot. If the encoder does so
+ * anyway, this decoder will simply use the Q-table values that were current
+ * at the start of the first scan for the component.
+ *
+ * The decompressor output side looks only at the saved quant tables,
+ * not at the current Q-table slots.
+ */
+
+LOCAL(void)
+latch_quant_tables (j_decompress_ptr cinfo)
+{
+ int ci, qtblno;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* No work if we already saved Q-table for this component */
+ if (compptr->quant_table != NULL)
+ continue;
+ /* Make sure specified quantization table is present */
+ qtblno = compptr->quant_tbl_no;
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ /* OK, save away the quantization table */
+ qtbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(JQUANT_TBL));
+ MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
+ compptr->quant_table = qtbl;
+ }
+}
+
+
+/*
+ * Initialize the input modules to read a scan of compressed data.
+ * The first call to this is done by jdmaster.c after initializing
+ * the entire decompressor (during jpeg_start_decompress).
+ * Subsequent calls come from consume_markers, below.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ per_scan_setup(cinfo);
+ latch_quant_tables(cinfo);
+ (*cinfo->entropy->start_pass) (cinfo);
+ (*cinfo->coef->start_input_pass) (cinfo);
+ cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+}
+
+
+/*
+ * Finish up after inputting a compressed-data scan.
+ * This is called by the coefficient controller after it's read all
+ * the expected data of the scan.
+ */
+
+METHODDEF(void)
+finish_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->inputctl->consume_input = consume_markers;
+}
+
+
+/*
+ * Read JPEG markers before, between, or after compressed-data scans.
+ * Change state as necessary when a new scan is reached.
+ * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * The consume_input method pointer points either here or to the
+ * coefficient controller's consume_data routine, depending on whether
+ * we are reading a compressed data segment or inter-segment markers.
+ */
+
+METHODDEF(int)
+consume_markers (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+ int val;
+
+ if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
+ return JPEG_REACHED_EOI;
+
+ val = (*cinfo->marker->read_markers) (cinfo);
+
+ switch (val) {
+ case JPEG_REACHED_SOS: /* Found SOS */
+ if (inputctl->inheaders) { /* 1st SOS */
+ initial_setup(cinfo);
+ inputctl->inheaders = FALSE;
+ /* Note: start_input_pass must be called by jdmaster.c
+ * before any more input can be consumed. jdapi.c is
+ * responsible for enforcing this sequencing.
+ */
+ } else { /* 2nd or later SOS marker */
+ if (! inputctl->pub.has_multiple_scans)
+ ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
+ start_input_pass(cinfo);
+ }
+ break;
+ case JPEG_REACHED_EOI: /* Found EOI */
+ inputctl->pub.eoi_reached = TRUE;
+ if (inputctl->inheaders) { /* Tables-only datastream, apparently */
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_NO_SOS);
+ } else {
+ /* Prevent infinite loop in coef ctlr's decompress_data routine
+ * if user set output_scan_number larger than number of scans.
+ */
+ if (cinfo->output_scan_number > cinfo->input_scan_number)
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ }
+ break;
+ case JPEG_SUSPENDED:
+ break;
+ }
+
+ return val;
+}
+
+
+/*
+ * Reset state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = TRUE;
+ /* Reset other modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->marker->reset_marker_reader) (cinfo);
+ /* Reset progression state -- would be cleaner if entropy decoder did this */
+ cinfo->coef_bits = NULL;
+}
+
+
+/*
+ * Initialize the input controller module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl;
+
+ /* Create subobject in permanent pool */
+ inputctl = (my_inputctl_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_input_controller));
+ cinfo->inputctl = (struct jpeg_input_controller *) inputctl;
+ /* Initialize method pointers */
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.reset_input_controller = reset_input_controller;
+ inputctl->pub.start_input_pass = start_input_pass;
+ inputctl->pub.finish_input_pass = finish_input_pass;
+ /* Initialize state: can't use reset_input_controller since we don't
+ * want to try to reset other modules yet.
+ */
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = TRUE;
+}
diff --git a/gs/jpeg/jdmainct.c b/gs/jpeg/jdmainct.c
new file mode 100644
index 000000000..13c956f5d
--- /dev/null
+++ b/gs/jpeg/jdmainct.c
@@ -0,0 +1,512 @@
+/*
+ * jdmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for decompression.
+ * The main buffer lies between the JPEG decompressor proper and the
+ * post-processor; it holds downsampled data in the JPEG colorspace.
+ *
+ * Note that this code is bypassed in raw-data mode, since the application
+ * supplies the equivalent of the main buffer in that case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * In the current system design, the main buffer need never be a full-image
+ * buffer; any full-height buffers will be found inside the coefficient or
+ * postprocessing controllers. Nonetheless, the main controller is not
+ * trivial. Its responsibility is to provide context rows for upsampling/
+ * rescaling, and doing this in an efficient fashion is a bit tricky.
+ *
+ * Postprocessor input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+ * sample rows of each component. (We require DCT_scaled_size values to be
+ * chosen such that these numbers are integers. In practice DCT_scaled_size
+ * values will likely be powers of two, so we actually have the stronger
+ * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
+ * Upsampling will typically produce max_v_samp_factor pixel rows from each
+ * row group (times any additional scale factor that the upsampler is
+ * applying).
+ *
+ * The coefficient controller will deliver data to us one iMCU row at a time;
+ * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
+ * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
+ * to one row of MCUs when the image is fully interleaved.) Note that the
+ * number of sample rows varies across components, but the number of row
+ * groups does not. Some garbage sample rows may be included in the last iMCU
+ * row at the bottom of the image.
+ *
+ * Depending on the vertical scaling algorithm used, the upsampler may need
+ * access to the sample row(s) above and below its current input row group.
+ * The upsampler is required to set need_context_rows TRUE at global selection
+ * time if so. When need_context_rows is FALSE, this controller can simply
+ * obtain one iMCU row at a time from the coefficient controller and dole it
+ * out as row groups to the postprocessor.
+ *
+ * When need_context_rows is TRUE, this controller guarantees that the buffer
+ * passed to postprocessing contains at least one row group's worth of samples
+ * above and below the row group(s) being processed. Note that the context
+ * rows "above" the first passed row group appear at negative row offsets in
+ * the passed buffer. At the top and bottom of the image, the required
+ * context rows are manufactured by duplicating the first or last real sample
+ * row; this avoids having special cases in the upsampling inner loops.
+ *
+ * The amount of context is fixed at one row group just because that's a
+ * convenient number for this controller to work with. The existing
+ * upsamplers really only need one sample row of context. An upsampler
+ * supporting arbitrary output rescaling might wish for more than one row
+ * group of context when shrinking the image; tough, we don't handle that.
+ * (This is justified by the assumption that downsizing will be handled mostly
+ * by adjusting the DCT_scaled_size values, so that the actual scale factor at
+ * the upsample step needn't be much less than one.)
+ *
+ * To provide the desired context, we have to retain the last two row groups
+ * of one iMCU row while reading in the next iMCU row. (The last row group
+ * can't be processed until we have another row group for its below-context,
+ * and so we have to save the next-to-last group too for its above-context.)
+ * We could do this most simply by copying data around in our buffer, but
+ * that'd be very slow. We can avoid copying any data by creating a rather
+ * strange pointer structure. Here's how it works. We allocate a workspace
+ * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
+ * of row groups per iMCU row). We create two sets of redundant pointers to
+ * the workspace. Labeling the physical row groups 0 to M+1, the synthesized
+ * pointer lists look like this:
+ * M+1 M-1
+ * master pointer --> 0 master pointer --> 0
+ * 1 1
+ * ... ...
+ * M-3 M-3
+ * M-2 M
+ * M-1 M+1
+ * M M-2
+ * M+1 M-1
+ * 0 0
+ * We read alternate iMCU rows using each master pointer; thus the last two
+ * row groups of the previous iMCU row remain un-overwritten in the workspace.
+ * The pointer lists are set up so that the required context rows appear to
+ * be adjacent to the proper places when we pass the pointer lists to the
+ * upsampler.
+ *
+ * The above pictures describe the normal state of the pointer lists.
+ * At top and bottom of the image, we diddle the pointer lists to duplicate
+ * the first or last sample row as necessary (this is cheaper than copying
+ * sample rows around).
+ *
+ * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
+ * situation each iMCU row provides only one row group so the buffering logic
+ * must be different (eg, we must read two iMCU rows before we can emit the
+ * first row group). For now, we simply do not support providing context
+ * rows when min_DCT_scaled_size is 1. That combination seems unlikely to
+ * be worth providing --- if someone wants a 1/8th-size preview, they probably
+ * want it quick and dirty, so a context-free upsampler is sufficient.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_main_controller pub; /* public fields */
+
+ /* Pointer to allocated workspace (M or M+2 row groups). */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+ boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
+ JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
+
+ /* Remaining fields are only used in the context case. */
+
+ /* These are the master pointers to the funny-order pointer lists. */
+ JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
+
+ int whichptr; /* indicates which pointer set is now in use */
+ int context_state; /* process_data state machine status */
+ JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
+ JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+/* context_state values: */
+#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
+#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
+#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+METHODDEF(void) process_data_context_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) process_data_crank_post
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#endif
+
+
+LOCAL(void)
+alloc_funny_pointers (j_decompress_ptr cinfo)
+/* Allocate space for the funny pointer lists.
+ * This is done only once, not once per pass.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, rgroup;
+ int M = cinfo->min_DCT_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ /* Get top-level space for component array pointers.
+ * We alloc both arrays with one call to save a few cycles.
+ */
+ main->xbuffer[0] = (JSAMPIMAGE)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
+ main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size; /* height of a row group of component */
+ /* Get space for pointer lists --- M+4 row groups in each list.
+ * We alloc both pointer lists with one call to save a few cycles.
+ */
+ xbuf = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
+ xbuf += rgroup; /* want one row group at negative offsets */
+ main->xbuffer[0][ci] = xbuf;
+ xbuf += rgroup * (M + 4);
+ main->xbuffer[1][ci] = xbuf;
+ }
+}
+
+
+LOCAL(void)
+make_funny_pointers (j_decompress_ptr cinfo)
+/* Create the funny pointer lists discussed in the comments above.
+ * The actual workspace is already allocated (in main->buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY buf, xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size; /* height of a row group of component */
+ xbuf0 = main->xbuffer[0][ci];
+ xbuf1 = main->xbuffer[1][ci];
+ /* First copy the workspace pointers as-is */
+ buf = main->buffer[ci];
+ for (i = 0; i < rgroup * (M + 2); i++) {
+ xbuf0[i] = xbuf1[i] = buf[i];
+ }
+ /* In the second list, put the last four row groups in swapped order */
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
+ xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
+ }
+ /* The wraparound pointers at top and bottom will be filled later
+ * (see set_wraparound_pointers, below). Initially we want the "above"
+ * pointers to duplicate the first actual data line. This only needs
+ * to happen in xbuffer[0].
+ */
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[0];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_wraparound_pointers (j_decompress_ptr cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size; /* height of a row group of component */
+ xbuf0 = main->xbuffer[0][ci];
+ xbuf1 = main->xbuffer[1][ci];
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+ xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+ xbuf0[rgroup*(M+2) + i] = xbuf0[i];
+ xbuf1[rgroup*(M+2) + i] = xbuf1[i];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_bottom_pointers (j_decompress_ptr cinfo)
+/* Change the pointer lists to duplicate the last sample row at the bottom
+ * of the image. whichptr indicates which xbuffer holds the final iMCU row.
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup, iMCUheight, rows_left;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Count sample rows in one iMCU row and in one row group */
+ iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size;
+ rgroup = iMCUheight / cinfo->min_DCT_scaled_size;
+ /* Count nondummy sample rows remaining for this component */
+ rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
+ if (rows_left == 0) rows_left = iMCUheight;
+ /* Count nondummy row groups. Should get same answer for each component,
+ * so we need only do it once.
+ */
+ if (ci == 0) {
+ main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+ }
+ /* Duplicate the last real sample row rgroup*2 times; this pads out the
+ * last partial rowgroup and ensures at least one full rowgroup of context.
+ */
+ xbuf = main->xbuffer[main->whichptr][ci];
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf[rows_left + i] = xbuf[rows_left-1];
+ }
+ }
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->upsample->need_context_rows) {
+ main->pub.process_data = process_data_context_main;
+ make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+ main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
+ main->context_state = CTX_PREPARE_FOR_IMCU;
+ main->iMCU_row_ctr = 0;
+ } else {
+ /* Simple case with no context needed */
+ main->pub.process_data = process_data_simple_main;
+ }
+ main->buffer_full = FALSE; /* Mark buffer empty */
+ main->rowgroup_ctr = 0;
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_CRANK_DEST:
+ /* For last pass of 2-pass quantization, just crank the postprocessor */
+ main->pub.process_data = process_data_crank_post;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the simple case where no context is required.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ JDIMENSION rowgroups_avail;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
+ return; /* suspension forced, can do nothing more */
+ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ }
+
+ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+ rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size;
+ /* Note: at the bottom of the image, we may pass extra garbage row groups
+ * to the postprocessor. The postprocessor has to check for bottom
+ * of image anyway (at row resolution), so no point in us doing it too.
+ */
+
+ /* Feed the postprocessor */
+ (*cinfo->post->post_process_data) (cinfo, main->buffer,
+ &main->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+
+ /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+ if (main->rowgroup_ctr >= rowgroups_avail) {
+ main->buffer_full = FALSE;
+ main->rowgroup_ctr = 0;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the case where context rows must be provided.
+ */
+
+METHODDEF(void)
+process_data_context_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo,
+ main->xbuffer[main->whichptr]))
+ return; /* suspension forced, can do nothing more */
+ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ main->iMCU_row_ctr++; /* count rows received */
+ }
+
+ /* Postprocessor typically will not swallow all the input data it is handed
+ * in one call (due to filling the output buffer first). Must be prepared
+ * to exit and restart. This switch lets us keep track of how far we got.
+ * Note that each case falls through to the next on successful completion.
+ */
+ switch (main->context_state) {
+ case CTX_POSTPONED_ROW:
+ /* Call postprocessor using previously set pointers for postponed row */
+ (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+ &main->rowgroup_ctr, main->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main->rowgroup_ctr < main->rowgroups_avail)
+ return; /* Need to suspend */
+ main->context_state = CTX_PREPARE_FOR_IMCU;
+ if (*out_row_ctr >= out_rows_avail)
+ return; /* Postprocessor exactly filled output buf */
+ /*FALLTHROUGH*/
+ case CTX_PREPARE_FOR_IMCU:
+ /* Prepare to process first M-1 row groups of this iMCU row */
+ main->rowgroup_ctr = 0;
+ main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
+ /* Check for bottom of image: if so, tweak pointers to "duplicate"
+ * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+ */
+ if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
+ set_bottom_pointers(cinfo);
+ main->context_state = CTX_PROCESS_IMCU;
+ /*FALLTHROUGH*/
+ case CTX_PROCESS_IMCU:
+ /* Call postprocessor using previously set pointers */
+ (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+ &main->rowgroup_ctr, main->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main->rowgroup_ctr < main->rowgroups_avail)
+ return; /* Need to suspend */
+ /* After the first iMCU, change wraparound pointers to normal state */
+ if (main->iMCU_row_ctr == 1)
+ set_wraparound_pointers(cinfo);
+ /* Prepare to load new iMCU row using other xbuffer list */
+ main->whichptr ^= 1; /* 0=>1 or 1=>0 */
+ main->buffer_full = FALSE;
+ /* Still need to process last row group of this iMCU row, */
+ /* which is saved at index M+1 of the other xbuffer */
+ main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
+ main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
+ main->context_state = CTX_POSTPONED_ROW;
+ }
+}
+
+
+/*
+ * Process some data.
+ * Final pass of two-pass quantization: just call the postprocessor.
+ * Source data will be the postprocessor controller's internal buffer.
+ */
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+METHODDEF(void)
+process_data_crank_post (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
+ (JDIMENSION *) NULL, (JDIMENSION) 0,
+ output_buf, out_row_ctr, out_rows_avail);
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main;
+ int ci, rgroup, ngroups;
+ jpeg_component_info *compptr;
+
+ main = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_d_main_controller *) main;
+ main->pub.start_pass = start_pass_main;
+
+ if (need_full_buffer) /* shouldn't happen */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Allocate the workspace.
+ * ngroups is the number of row groups we need.
+ */
+ if (cinfo->upsample->need_context_rows) {
+ if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
+ ngroups = cinfo->min_DCT_scaled_size + 2;
+ } else {
+ ngroups = cinfo->min_DCT_scaled_size;
+ }
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size; /* height of a row group of component */
+ main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_scaled_size,
+ (JDIMENSION) (rgroup * ngroups));
+ }
+}
diff --git a/gs/jpeg/jdmarker.c b/gs/jpeg/jdmarker.c
new file mode 100644
index 000000000..b79ec37fb
--- /dev/null
+++ b/gs/jpeg/jdmarker.c
@@ -0,0 +1,1055 @@
+/*
+ * jdmarker.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to decode JPEG datastream markers.
+ * Most of the complexity arises from our desire to support input
+ * suspension: if not all of the data for a marker is available,
+ * we must exit back to the application. On resumption, we reprocess
+ * the marker.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/*
+ * Macros for fetching data from the data source module.
+ *
+ * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
+ * the current restart point; we update them only when we have reached a
+ * suitable place to restart if a suspension occurs.
+ */
+
+/* Declare and initialize local copies of input pointer/count */
+#define INPUT_VARS(cinfo) \
+ struct jpeg_source_mgr * datasrc = (cinfo)->src; \
+ const JOCTET * next_input_byte = datasrc->next_input_byte; \
+ size_t bytes_in_buffer = datasrc->bytes_in_buffer
+
+/* Unload the local copies --- do this only at a restart boundary */
+#define INPUT_SYNC(cinfo) \
+ ( datasrc->next_input_byte = next_input_byte, \
+ datasrc->bytes_in_buffer = bytes_in_buffer )
+
+/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */
+#define INPUT_RELOAD(cinfo) \
+ ( next_input_byte = datasrc->next_input_byte, \
+ bytes_in_buffer = datasrc->bytes_in_buffer )
+
+/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
+ * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+ * but we must reload the local copies after a successful fill.
+ */
+#define MAKE_BYTE_AVAIL(cinfo,action) \
+ if (bytes_in_buffer == 0) { \
+ if (! (*datasrc->fill_input_buffer) (cinfo)) \
+ { action; } \
+ INPUT_RELOAD(cinfo); \
+ } \
+ bytes_in_buffer--
+
+/* Read a byte into variable V.
+ * If must suspend, take the specified action (typically "return FALSE").
+ */
+#define INPUT_BYTE(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ V = GETJOCTET(*next_input_byte++); )
+
+/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
+ * V should be declared unsigned int or perhaps INT32.
+ */
+#define INPUT_2BYTES(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
+ MAKE_BYTE_AVAIL(cinfo,action); \
+ V += GETJOCTET(*next_input_byte++); )
+
+
+/*
+ * Routines to process JPEG markers.
+ *
+ * Entry condition: JPEG marker itself has been read and its code saved
+ * in cinfo->unread_marker; input restart point is just after the marker.
+ *
+ * Exit: if return TRUE, have read and processed any parameters, and have
+ * updated the restart point to point after the parameters.
+ * If return FALSE, was forced to suspend before reaching end of
+ * marker parameters; restart point has not been moved. Same routine
+ * will be called again after application supplies more input data.
+ *
+ * This approach to suspension assumes that all of a marker's parameters can
+ * fit into a single input bufferload. This should hold for "normal"
+ * markers. Some COM/APPn markers might have large parameter segments,
+ * but we use skip_input_data to get past those, and thereby put the problem
+ * on the source manager's shoulders.
+ *
+ * Note that we don't bother to avoid duplicate trace messages if a
+ * suspension occurs within marker parameters. Other side effects
+ * require more care.
+ */
+
+
+LOCAL(boolean)
+get_soi (j_decompress_ptr cinfo)
+/* Process an SOI marker */
+{
+ int i;
+
+ TRACEMS(cinfo, 1, JTRC_SOI);
+
+ if (cinfo->marker->saw_SOI)
+ ERREXIT(cinfo, JERR_SOI_DUPLICATE);
+
+ /* Reset all parameters that are defined to be reset by SOI */
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+ cinfo->restart_interval = 0;
+
+ /* Set initial assumptions for colorspace etc */
+
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */
+
+ cinfo->saw_JFIF_marker = FALSE;
+ cinfo->density_unit = 0; /* set default JFIF APP0 values */
+ cinfo->X_density = 1;
+ cinfo->Y_density = 1;
+ cinfo->saw_Adobe_marker = FALSE;
+ cinfo->Adobe_transform = 0;
+
+ cinfo->marker->saw_SOI = TRUE;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
+/* Process a SOFn marker */
+{
+ INT32 length;
+ int c, ci;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ cinfo->progressive_mode = is_prog;
+ cinfo->arith_code = is_arith;
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);
+ INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);
+
+ length -= 8;
+
+ TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,
+ (int) cinfo->image_width, (int) cinfo->image_height,
+ cinfo->num_components);
+
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
+ /* We don't support files in which the image height is initially specified */
+ /* as 0 and is later redefined by DNL. As long as we have to check that, */
+ /* might as well have a general sanity check. */
+ if (cinfo->image_height <= 0 || cinfo->image_width <= 0
+ || cinfo->num_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ if (length != (cinfo->num_components * 3))
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ if (cinfo->comp_info == NULL) /* do only once, even if suspend */
+ cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * SIZEOF(jpeg_component_info));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->component_index = ci;
+ INPUT_BYTE(cinfo, compptr->component_id, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ compptr->h_samp_factor = (c >> 4) & 15;
+ compptr->v_samp_factor = (c ) & 15;
+ INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);
+
+ TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
+ compptr->component_id, compptr->h_samp_factor,
+ compptr->v_samp_factor, compptr->quant_tbl_no);
+ }
+
+ cinfo->marker->saw_SOF = TRUE;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sos (j_decompress_ptr cinfo)
+/* Process a SOS marker */
+{
+ INT32 length;
+ int i, ci, n, c, cc;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ if (! cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOS_NO_SOF);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */
+
+ if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ TRACEMS1(cinfo, 1, JTRC_SOS, n);
+
+ cinfo->comps_in_scan = n;
+
+ /* Collect the component-spec parameters */
+
+ for (i = 0; i < n; i++) {
+ INPUT_BYTE(cinfo, cc, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (cc == compptr->component_id)
+ goto id_found;
+ }
+
+ ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
+
+ id_found:
+
+ cinfo->cur_comp_info[i] = compptr;
+ compptr->dc_tbl_no = (c >> 4) & 15;
+ compptr->ac_tbl_no = (c ) & 15;
+
+ TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc,
+ compptr->dc_tbl_no, compptr->ac_tbl_no);
+ }
+
+ /* Collect the additional scan parameters Ss, Se, Ah/Al. */
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ss = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Se = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ah = (c >> 4) & 15;
+ cinfo->Al = (c ) & 15;
+
+ TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,
+ cinfo->Ah, cinfo->Al);
+
+ /* Prepare to scan data & restart markers */
+ cinfo->marker->next_restart_num = 0;
+
+ /* Count another SOS marker */
+ cinfo->input_scan_number++;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+METHODDEF(boolean)
+get_app0 (j_decompress_ptr cinfo)
+/* Process an APP0 marker */
+{
+#define JFIF_LEN 14
+ INT32 length;
+ UINT8 b[JFIF_LEN];
+ int buffp;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ /* See if a JFIF APP0 marker is present */
+
+ if (length >= JFIF_LEN) {
+ for (buffp = 0; buffp < JFIF_LEN; buffp++)
+ INPUT_BYTE(cinfo, b[buffp], return FALSE);
+ length -= JFIF_LEN;
+
+ if (b[0]==0x4A && b[1]==0x46 && b[2]==0x49 && b[3]==0x46 && b[4]==0) {
+ /* Found JFIF APP0 marker: check version */
+ /* Major version must be 1, anything else signals an incompatible change.
+ * We used to treat this as an error, but now it's a nonfatal warning,
+ * because some bozo at Hijaak couldn't read the spec.
+ * Minor version should be 0..2, but process anyway if newer.
+ */
+ if (b[5] != 1)
+ WARNMS2(cinfo, JWRN_JFIF_MAJOR, b[5], b[6]);
+ else if (b[6] > 2)
+ TRACEMS2(cinfo, 1, JTRC_JFIF_MINOR, b[5], b[6]);
+ /* Save info */
+ cinfo->saw_JFIF_marker = TRUE;
+ cinfo->density_unit = b[7];
+ cinfo->X_density = (b[8] << 8) + b[9];
+ cinfo->Y_density = (b[10] << 8) + b[11];
+ TRACEMS3(cinfo, 1, JTRC_JFIF,
+ cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
+ if (b[12] | b[13])
+ TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, b[12], b[13]);
+ if (length != ((INT32) b[12] * (INT32) b[13] * (INT32) 3))
+ TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) length);
+ } else {
+ /* Start of APP0 does not match "JFIF" */
+ TRACEMS1(cinfo, 1, JTRC_APP0, (int) length + JFIF_LEN);
+ }
+ } else {
+ /* Too short to be JFIF marker */
+ TRACEMS1(cinfo, 1, JTRC_APP0, (int) length);
+ }
+
+ INPUT_SYNC(cinfo);
+ if (length > 0) /* skip any remaining data -- could be lots */
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+METHODDEF(boolean)
+get_app14 (j_decompress_ptr cinfo)
+/* Process an APP14 marker */
+{
+#define ADOBE_LEN 12
+ INT32 length;
+ UINT8 b[ADOBE_LEN];
+ int buffp;
+ unsigned int version, flags0, flags1, transform;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ /* See if an Adobe APP14 marker is present */
+
+ if (length >= ADOBE_LEN) {
+ for (buffp = 0; buffp < ADOBE_LEN; buffp++)
+ INPUT_BYTE(cinfo, b[buffp], return FALSE);
+ length -= ADOBE_LEN;
+
+ if (b[0]==0x41 && b[1]==0x64 && b[2]==0x6F && b[3]==0x62 && b[4]==0x65) {
+ /* Found Adobe APP14 marker */
+ version = (b[5] << 8) + b[6];
+ flags0 = (b[7] << 8) + b[8];
+ flags1 = (b[9] << 8) + b[10];
+ transform = b[11];
+ TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
+ cinfo->saw_Adobe_marker = TRUE;
+ cinfo->Adobe_transform = (UINT8) transform;
+ } else {
+ /* Start of APP14 does not match "Adobe" */
+ TRACEMS1(cinfo, 1, JTRC_APP14, (int) length + ADOBE_LEN);
+ }
+ } else {
+ /* Too short to be Adobe marker */
+ TRACEMS1(cinfo, 1, JTRC_APP14, (int) length);
+ }
+
+ INPUT_SYNC(cinfo);
+ if (length > 0) /* skip any remaining data -- could be lots */
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dac (j_decompress_ptr cinfo)
+/* Process a DAC marker */
+{
+ INT32 length;
+ int index, val;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+ INPUT_BYTE(cinfo, val, return FALSE);
+
+ length -= 2;
+
+ TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
+
+ if (index < 0 || index >= (2*NUM_ARITH_TBLS))
+ ERREXIT1(cinfo, JERR_DAC_INDEX, index);
+
+ if (index >= NUM_ARITH_TBLS) { /* define AC table */
+ cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;
+ } else { /* define DC table */
+ cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);
+ cinfo->arith_dc_U[index] = (UINT8) (val >> 4);
+ if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
+ ERREXIT1(cinfo, JERR_DAC_VALUE, val);
+ }
+ }
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dht (j_decompress_ptr cinfo)
+/* Process a DHT marker */
+{
+ INT32 length;
+ UINT8 bits[17];
+ UINT8 huffval[256];
+ int i, index, count;
+ JHUFF_TBL **htblptr;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DHT, index);
+
+ bits[0] = 0;
+ count = 0;
+ for (i = 1; i <= 16; i++) {
+ INPUT_BYTE(cinfo, bits[i], return FALSE);
+ count += bits[i];
+ }
+
+ length -= 1 + 16;
+
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[1], bits[2], bits[3], bits[4],
+ bits[5], bits[6], bits[7], bits[8]);
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[9], bits[10], bits[11], bits[12],
+ bits[13], bits[14], bits[15], bits[16]);
+
+ if (count > 256 || ((INT32) count) > length)
+ ERREXIT(cinfo, JERR_DHT_COUNTS);
+
+ for (i = 0; i < count; i++)
+ INPUT_BYTE(cinfo, huffval[i], return FALSE);
+
+ length -= count;
+
+ if (index & 0x10) { /* AC table definition */
+ index -= 0x10;
+ htblptr = &cinfo->ac_huff_tbl_ptrs[index];
+ } else { /* DC table definition */
+ htblptr = &cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (index < 0 || index >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_DHT_INDEX, index);
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+ MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval));
+ }
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dqt (j_decompress_ptr cinfo)
+/* Process a DQT marker */
+{
+ INT32 length;
+ int n, i, prec;
+ unsigned int tmp;
+ JQUANT_TBL *quant_ptr;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ INPUT_BYTE(cinfo, n, return FALSE);
+ prec = n >> 4;
+ n &= 0x0F;
+
+ TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
+
+ if (n >= NUM_QUANT_TBLS)
+ ERREXIT1(cinfo, JERR_DQT_INDEX, n);
+
+ if (cinfo->quant_tbl_ptrs[n] == NULL)
+ cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+ quant_ptr = cinfo->quant_tbl_ptrs[n];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ if (prec)
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+ else
+ INPUT_BYTE(cinfo, tmp, return FALSE);
+ /* We convert the zigzag-order table to natural array order. */
+ quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp;
+ }
+
+ if (cinfo->err->trace_level >= 2) {
+ for (i = 0; i < DCTSIZE2; i += 8) {
+ TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
+ quant_ptr->quantval[i], quant_ptr->quantval[i+1],
+ quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],
+ quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],
+ quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);
+ }
+ }
+
+ length -= DCTSIZE2+1;
+ if (prec) length -= DCTSIZE2;
+ }
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dri (j_decompress_ptr cinfo)
+/* Process a DRI marker */
+{
+ INT32 length;
+ unsigned int tmp;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ if (length != 4)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
+
+ cinfo->restart_interval = tmp;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+METHODDEF(boolean)
+skip_variable (j_decompress_ptr cinfo)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ INT32 length;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);
+
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ (*cinfo->src->skip_input_data) (cinfo, (long) length - 2L);
+
+ return TRUE;
+}
+
+
+/*
+ * Find the next JPEG marker, save it in cinfo->unread_marker.
+ * Returns FALSE if had to suspend before reaching a marker;
+ * in that case cinfo->unread_marker is unchanged.
+ *
+ * Note that the result might not be a valid marker code,
+ * but it will never be 0 or FF.
+ */
+
+LOCAL(boolean)
+next_marker (j_decompress_ptr cinfo)
+{
+ int c;
+ INPUT_VARS(cinfo);
+
+ for (;;) {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ /* Skip any non-FF bytes.
+ * This may look a bit inefficient, but it will not occur in a valid file.
+ * We sync after each discarded byte so that a suspending data source
+ * can discard the byte from its buffer.
+ */
+ while (c != 0xFF) {
+ cinfo->marker->discarded_bytes++;
+ INPUT_SYNC(cinfo);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ }
+ /* This loop swallows any duplicate FF bytes. Extra FFs are legal as
+ * pad bytes, so don't count them in discarded_bytes. We assume there
+ * will not be so many consecutive FF bytes as to overflow a suspending
+ * data source's input buffer.
+ */
+ do {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ } while (c == 0xFF);
+ if (c != 0)
+ break; /* found a valid marker, exit loop */
+ /* Reach here if we found a stuffed-zero data sequence (FF/00).
+ * Discard it and loop back to try again.
+ */
+ cinfo->marker->discarded_bytes += 2;
+ INPUT_SYNC(cinfo);
+ }
+
+ if (cinfo->marker->discarded_bytes != 0) {
+ WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);
+ cinfo->marker->discarded_bytes = 0;
+ }
+
+ cinfo->unread_marker = c;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+first_marker (j_decompress_ptr cinfo)
+/* Like next_marker, but used to obtain the initial SOI marker. */
+/* For this marker, we do not allow preceding garbage or fill; otherwise,
+ * we might well scan an entire input file before realizing it ain't JPEG.
+ * If an application wants to process non-JFIF files, it must seek to the
+ * SOI before calling the JPEG library.
+ */
+{
+ int c, c2;
+ INPUT_VARS(cinfo);
+
+ INPUT_BYTE(cinfo, c, return FALSE);
+ INPUT_BYTE(cinfo, c2, return FALSE);
+ if (c != 0xFF || c2 != (int) M_SOI)
+ ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
+
+ cinfo->unread_marker = c2;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Read markers until SOS or EOI.
+ *
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ */
+
+METHODDEF(int)
+read_markers (j_decompress_ptr cinfo)
+{
+ /* Outer loop repeats once for each marker. */
+ for (;;) {
+ /* Collect the marker proper, unless we already did. */
+ /* NB: first_marker() enforces the requirement that SOI appear first. */
+ if (cinfo->unread_marker == 0) {
+ if (! cinfo->marker->saw_SOI) {
+ if (! first_marker(cinfo))
+ return JPEG_SUSPENDED;
+ } else {
+ if (! next_marker(cinfo))
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* At this point cinfo->unread_marker contains the marker code and the
+ * input point is just past the marker proper, but before any parameters.
+ * A suspension will cause us to return with this state still true.
+ */
+ switch (cinfo->unread_marker) {
+ case M_SOI:
+ if (! get_soi(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ if (! get_sof(cinfo, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF2: /* Progressive, Huffman */
+ if (! get_sof(cinfo, TRUE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF9: /* Extended sequential, arithmetic */
+ if (! get_sof(cinfo, FALSE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF10: /* Progressive, arithmetic */
+ if (! get_sof(cinfo, TRUE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ /* Currently unsupported SOFn types */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_JPG: /* Reserved for JPEG extensions */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
+ break;
+
+ case M_SOS:
+ if (! get_sos(cinfo))
+ return JPEG_SUSPENDED;
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_SOS;
+
+ case M_EOI:
+ TRACEMS(cinfo, 1, JTRC_EOI);
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_EOI;
+
+ case M_DAC:
+ if (! get_dac(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DHT:
+ if (! get_dht(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DQT:
+ if (! get_dqt(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DRI:
+ if (! get_dri(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_APP0:
+ case M_APP1:
+ case M_APP2:
+ case M_APP3:
+ case M_APP4:
+ case M_APP5:
+ case M_APP6:
+ case M_APP7:
+ case M_APP8:
+ case M_APP9:
+ case M_APP10:
+ case M_APP11:
+ case M_APP12:
+ case M_APP13:
+ case M_APP14:
+ case M_APP15:
+ if (! (*cinfo->marker->process_APPn[cinfo->unread_marker - (int) M_APP0]) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_COM:
+ if (! (*cinfo->marker->process_COM) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_RST0: /* these are all parameterless */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);
+ break;
+
+ case M_DNL: /* Ignore DNL ... perhaps the wrong thing */
+ if (! skip_variable(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ default: /* must be DHP, EXP, JPGn, or RESn */
+ /* For now, we treat the reserved markers as fatal errors since they are
+ * likely to be used to signal incompatible JPEG Part 3 extensions.
+ * Once the JPEG 3 version-number marker is well defined, this code
+ * ought to change!
+ */
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+ break;
+ }
+ /* Successfully processed marker, so reset state variable */
+ cinfo->unread_marker = 0;
+ } /* end loop */
+}
+
+
+/*
+ * Read a restart marker, which is expected to appear next in the datastream;
+ * if the marker is not there, take appropriate recovery action.
+ * Returns FALSE if suspension is required.
+ *
+ * This is called by the entropy decoder after it has read an appropriate
+ * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder
+ * has already read a marker from the data source. Under normal conditions
+ * cinfo->unread_marker will be reset to 0 before returning; if not reset,
+ * it holds a marker which the decoder will be unable to read past.
+ */
+
+METHODDEF(boolean)
+read_restart_marker (j_decompress_ptr cinfo)
+{
+ /* Obtain a marker unless we already did. */
+ /* Note that next_marker will complain if it skips any data. */
+ if (cinfo->unread_marker == 0) {
+ if (! next_marker(cinfo))
+ return FALSE;
+ }
+
+ if (cinfo->unread_marker ==
+ ((int) M_RST0 + cinfo->marker->next_restart_num)) {
+ /* Normal case --- swallow the marker and let entropy decoder continue */
+ TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
+ cinfo->unread_marker = 0;
+ } else {
+ /* Uh-oh, the restart markers have been messed up. */
+ /* Let the data source manager determine how to resync. */
+ if (! (*cinfo->src->resync_to_restart) (cinfo,
+ cinfo->marker->next_restart_num))
+ return FALSE;
+ }
+
+ /* Update next-restart state */
+ cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;
+
+ return TRUE;
+}
+
+
+/*
+ * This is the default resync_to_restart method for data source managers
+ * to use if they don't have any better approach. Some data source managers
+ * may be able to back up, or may have additional knowledge about the data
+ * which permits a more intelligent recovery strategy; such managers would
+ * presumably supply their own resync method.
+ *
+ * read_restart_marker calls resync_to_restart if it finds a marker other than
+ * the restart marker it was expecting. (This code is *not* used unless
+ * a nonzero restart interval has been declared.) cinfo->unread_marker is
+ * the marker code actually found (might be anything, except 0 or FF).
+ * The desired restart marker number (0..7) is passed as a parameter.
+ * This routine is supposed to apply whatever error recovery strategy seems
+ * appropriate in order to position the input stream to the next data segment.
+ * Note that cinfo->unread_marker is treated as a marker appearing before
+ * the current data-source input point; usually it should be reset to zero
+ * before returning.
+ * Returns FALSE if suspension is required.
+ *
+ * This implementation is substantially constrained by wanting to treat the
+ * input as a data stream; this means we can't back up. Therefore, we have
+ * only the following actions to work with:
+ * 1. Simply discard the marker and let the entropy decoder resume at next
+ * byte of file.
+ * 2. Read forward until we find another marker, discarding intervening
+ * data. (In theory we could look ahead within the current bufferload,
+ * without having to discard data if we don't find the desired marker.
+ * This idea is not implemented here, in part because it makes behavior
+ * dependent on buffer size and chance buffer-boundary positions.)
+ * 3. Leave the marker unread (by failing to zero cinfo->unread_marker).
+ * This will cause the entropy decoder to process an empty data segment,
+ * inserting dummy zeroes, and then we will reprocess the marker.
+ *
+ * #2 is appropriate if we think the desired marker lies ahead, while #3 is
+ * appropriate if the found marker is a future restart marker (indicating
+ * that we have missed the desired restart marker, probably because it got
+ * corrupted).
+ * We apply #2 or #3 if the found marker is a restart marker no more than
+ * two counts behind or ahead of the expected one. We also apply #2 if the
+ * found marker is not a legal JPEG marker code (it's certainly bogus data).
+ * If the found marker is a restart marker more than 2 counts away, we do #1
+ * (too much risk that the marker is erroneous; with luck we will be able to
+ * resync at some future point).
+ * For any valid non-restart JPEG marker, we apply #3. This keeps us from
+ * overrunning the end of a scan. An implementation limited to single-scan
+ * files might find it better to apply #2 for markers other than EOI, since
+ * any other marker would have to be bogus data in that case.
+ */
+
+GLOBAL(boolean)
+jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+ int marker = cinfo->unread_marker;
+ int action = 1;
+
+ /* Always put up a warning. */
+ WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
+
+ /* Outer loop handles repeated decision after scanning forward. */
+ for (;;) {
+ if (marker < (int) M_SOF0)
+ action = 2; /* invalid marker */
+ else if (marker < (int) M_RST0 || marker > (int) M_RST7)
+ action = 3; /* valid non-restart marker */
+ else {
+ if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired+2) & 7)))
+ action = 3; /* one of the next two expected restarts */
+ else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired-2) & 7)))
+ action = 2; /* a prior restart, so advance */
+ else
+ action = 1; /* desired restart or too far away */
+ }
+ TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
+ switch (action) {
+ case 1:
+ /* Discard marker and let entropy decoder resume processing. */
+ cinfo->unread_marker = 0;
+ return TRUE;
+ case 2:
+ /* Scan to the next marker, and repeat the decision loop. */
+ if (! next_marker(cinfo))
+ return FALSE;
+ marker = cinfo->unread_marker;
+ break;
+ case 3:
+ /* Return without advancing past this marker. */
+ /* Entropy decoder will be forced to process an empty segment. */
+ return TRUE;
+ }
+ } /* end loop */
+}
+
+
+/*
+ * Reset marker processing state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_marker_reader (j_decompress_ptr cinfo)
+{
+ cinfo->comp_info = NULL; /* until allocated by get_sof */
+ cinfo->input_scan_number = 0; /* no SOS seen yet */
+ cinfo->unread_marker = 0; /* no pending marker */
+ cinfo->marker->saw_SOI = FALSE; /* set internal state too */
+ cinfo->marker->saw_SOF = FALSE;
+ cinfo->marker->discarded_bytes = 0;
+}
+
+
+/*
+ * Initialize the marker reader module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_marker_reader (j_decompress_ptr cinfo)
+{
+ int i;
+
+ /* Create subobject in permanent pool */
+ cinfo->marker = (struct jpeg_marker_reader *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(struct jpeg_marker_reader));
+ /* Initialize method pointers */
+ cinfo->marker->reset_marker_reader = reset_marker_reader;
+ cinfo->marker->read_markers = read_markers;
+ cinfo->marker->read_restart_marker = read_restart_marker;
+ cinfo->marker->process_COM = skip_variable;
+ for (i = 0; i < 16; i++)
+ cinfo->marker->process_APPn[i] = skip_variable;
+ cinfo->marker->process_APPn[0] = get_app0;
+ cinfo->marker->process_APPn[14] = get_app14;
+ /* Reset marker processing state */
+ reset_marker_reader(cinfo);
+}
diff --git a/gs/jpeg/jdmaster.c b/gs/jpeg/jdmaster.c
new file mode 100644
index 000000000..6f3351e61
--- /dev/null
+++ b/gs/jpeg/jdmaster.c
@@ -0,0 +1,555 @@
+/*
+ * jdmaster.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_decomp_master pub; /* public fields */
+
+ int pass_number; /* # of passes completed */
+
+ boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
+
+ /* Saved references to initialized quantizer modules,
+ * in case we need to switch modes.
+ */
+ struct jpeg_color_quantizer * quantizer_1pass;
+ struct jpeg_color_quantizer * quantizer_2pass;
+} my_decomp_master;
+
+typedef my_decomp_master * my_master_ptr;
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample (j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+ return FALSE;
+ /* jdmerge.c only supports YCC=>RGB color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+ cinfo->out_color_space != JCS_RGB ||
+ cinfo->out_color_components != RGB_PIXELSIZE)
+ return FALSE;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo->comp_info[0].h_samp_factor != 2 ||
+ cinfo->comp_info[1].h_samp_factor != 1 ||
+ cinfo->comp_info[2].h_samp_factor != 1 ||
+ cinfo->comp_info[0].v_samp_factor > 2 ||
+ cinfo->comp_info[1].v_samp_factor != 1 ||
+ cinfo->comp_info[2].v_samp_factor != 1)
+ return FALSE;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
+ cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
+ cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
+ return FALSE;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return TRUE; /* by golly, it'll work... */
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
+ /* Provide 1/8 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 8L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 8L);
+ cinfo->min_DCT_scaled_size = 1;
+ } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
+ /* Provide 1/4 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 4L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 4L);
+ cinfo->min_DCT_scaled_size = 2;
+ } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
+ /* Provide 1/2 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 2L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 2L);
+ cinfo->min_DCT_scaled_size = 4;
+ } else {
+ /* Provide 1/1 scaling */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ cinfo->min_DCT_scaled_size = DCTSIZE;
+ }
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code assumes that the supported DCT scalings are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = cinfo->min_DCT_scaled_size;
+ while (ssize < DCTSIZE &&
+ (compptr->h_samp_factor * ssize * 2 <=
+ cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
+ (compptr->v_samp_factor * ssize * 2 <=
+ cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_scaled_size = ssize;
+ }
+
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
+ (long) (cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
+ (long) (cinfo->max_v_samp_factor * DCTSIZE));
+ }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ break;
+ case JCS_RGB:
+#if RGB_PIXELSIZE != 3
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ break;
+#endif /* else share code with YCbCr */
+ case JCS_YCbCr:
+ cinfo->out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo->out_color_components = cinfo->num_components;
+ break;
+ }
+ cinfo->output_components = (cinfo->quantize_colors ? 1 :
+ cinfo->out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+ else
+ cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc. These
+ * processes are inner loops and need to be as fast as possible. On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ * x = sample_range_limit[x];
+ * is faster than explicit tests
+ * if (x < 0) x = 0;
+ * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is
+ * possible if the input data is corrupt. To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ * x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples. Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table. The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ *
+ * Note that the table is allocated in near data space on PCs; it's small
+ * enough and used often enough to justify this.
+ */
+
+LOCAL(void)
+prepare_range_limit_table (j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ JSAMPLE * table;
+ int i;
+
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE) i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ MEMZERO(table + (2 * (MAXJSAMPLE+1)),
+ (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers. We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master->pass_number = 0;
+ master->using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master->quantizer_1pass = NULL;
+ master->quantizer_2pass = NULL;
+ /* No mode changes if not using buffered-image mode. */
+ if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ }
+ if (cinfo->quantize_colors) {
+ if (cinfo->raw_data_out)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ /* 2-pass quantizer only works in 3-component color space. */
+ if (cinfo->out_color_components != 3) {
+ cinfo->enable_1pass_quant = TRUE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ cinfo->colormap = NULL;
+ } else if (cinfo->colormap != NULL) {
+ cinfo->enable_external_quant = TRUE;
+ } else if (cinfo->two_pass_quantize) {
+ cinfo->enable_2pass_quant = TRUE;
+ } else {
+ cinfo->enable_1pass_quant = TRUE;
+ }
+
+ if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+ jinit_1pass_quantizer(cinfo);
+ master->quantizer_1pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ /* We use the 2-pass code to map to external colormaps. */
+ if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+ jinit_2pass_quantizer(cinfo);
+ master->quantizer_2pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+ /* If both quantizers are initialized, the 2-pass one is left active;
+ * this is necessary for starting with quantization to an external map.
+ */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (! cinfo->raw_data_out) {
+ if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ }
+ /* Inverse DCT */
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef D_PROGRESSIVE_SUPPORTED
+ jinit_phuff_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+
+ if (! cinfo->raw_data_out)
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+ if (cinfo->progress != NULL && ! cinfo->buffered_image &&
+ cinfo->inputctl->has_multiple_scans) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+ /* Count the input pass as done */
+ master->pass_number++;
+ }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass. We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls. We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapi.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Final pass of 2-pass quantization */
+ master->pub.is_dummy_pass = FALSE;
+ (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+ (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+ (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+ /* Select new quantization method */
+ if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+ cinfo->cquantize = master->quantizer_2pass;
+ master->pub.is_dummy_pass = TRUE;
+ } else if (cinfo->enable_1pass_quant) {
+ cinfo->cquantize = master->quantizer_1pass;
+ } else {
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ (*cinfo->idct->start_pass) (cinfo);
+ (*cinfo->coef->start_output_pass) (cinfo);
+ if (! cinfo->raw_data_out) {
+ if (! master->using_merged_upsample)
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->upsample->start_pass) (cinfo);
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+ (*cinfo->post->start_pass) (cinfo,
+ (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->pass_number +
+ (master->pub.is_dummy_pass ? 2 : 1);
+ /* In buffered-image mode, we assume one more output pass if EOI not
+ * yet reached, but no more passes if EOI has been reached.
+ */
+ if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
+ cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+ }
+ }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->finish_pass) (cinfo);
+ master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_BUFIMAGE)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+ cinfo->colormap != NULL) {
+ /* Select 2-pass quantizer for external colormap use */
+ cinfo->cquantize = master->quantizer_2pass;
+ /* Notify quantizer of colormap change */
+ (*cinfo->cquantize->new_color_map) (cinfo);
+ master->pub.is_dummy_pass = FALSE; /* just in case */
+ } else
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress (j_decompress_ptr cinfo)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_decomp_master));
+ cinfo->master = (struct jpeg_decomp_master *) master;
+ master->pub.prepare_for_output_pass = prepare_for_output_pass;
+ master->pub.finish_output_pass = finish_output_pass;
+
+ master->pub.is_dummy_pass = FALSE;
+
+ master_selection(cinfo);
+}
diff --git a/gs/jpeg/jdmerge.c b/gs/jpeg/jdmerge.c
new file mode 100644
index 000000000..37444468c
--- /dev/null
+++ b/gs/jpeg/jdmerge.c
@@ -0,0 +1,400 @@
+/*
+ * jdmerge.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains code for merged upsampling/color conversion.
+ *
+ * This file combines functions from jdsample.c and jdcolor.c;
+ * read those files first to understand what's going on.
+ *
+ * When the chroma components are to be upsampled by simple replication
+ * (ie, box filtering), we can save some work in color conversion by
+ * calculating all the output pixels corresponding to a pair of chroma
+ * samples at one time. In the conversion equations
+ * R = Y + K1 * Cr
+ * G = Y + K2 * Cb + K3 * Cr
+ * B = Y + K4 * Cb
+ * only the Y term varies among the group of pixels corresponding to a pair
+ * of chroma samples, so the rest of the terms can be calculated just once.
+ * At typical sampling ratios, this eliminates half or three-quarters of the
+ * multiplications needed for color conversion.
+ *
+ * This file currently provides implementations for the following cases:
+ * YCbCr => RGB color conversion only.
+ * Sampling ratios of 2h1v or 2h2v.
+ * No scaling needed at upsample time.
+ * Corner-aligned (non-CCIR601) sampling alignment.
+ * Other special cases could be added, but in most applications these are
+ * the only common cases. (For uncommon cases we fall back on the more
+ * general code in jdsample.c and jdcolor.c.)
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Pointer to routine to do actual upsampling/conversion of one row group */
+ JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf));
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+
+ /* For 2:1 vertical sampling, we produce two output rows at a time.
+ * We need a "spare" row buffer to hold the second output row if the
+ * application provides just a one-row buffer; we also use the spare
+ * to discard the dummy last row if the image height is odd.
+ */
+ JSAMPROW spare_row;
+ boolean spare_full; /* T if spare buffer is occupied */
+
+ JDIMENSION out_row_width; /* samples per output row */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ * This is taken directly from jdcolor.c; see that file for more info.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ upsample->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ upsample->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ upsample->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ upsample->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_merged_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the spare buffer empty */
+ upsample->spare_full = FALSE;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * The control routine just handles the row buffering considerations.
+ */
+
+METHODDEF(void)
+merged_2v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 2:1 vertical sampling case: may need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPROW work_ptrs[2];
+ JDIMENSION num_rows; /* number of rows returned to caller */
+
+ if (upsample->spare_full) {
+ /* If we have a spare row saved from a previous cycle, just return it. */
+ jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+ 1, upsample->out_row_width);
+ num_rows = 1;
+ upsample->spare_full = FALSE;
+ } else {
+ /* Figure number of rows to return to caller. */
+ num_rows = 2;
+ /* Not more than the distance to the end of the image. */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+ /* Create output pointer array for upsampler. */
+ work_ptrs[0] = output_buf[*out_row_ctr];
+ if (num_rows > 1) {
+ work_ptrs[1] = output_buf[*out_row_ctr + 1];
+ } else {
+ work_ptrs[1] = upsample->spare_row;
+ upsample->spare_full = TRUE;
+ }
+ /* Now do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
+ }
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (! upsample->spare_full)
+ (*in_row_group_ctr)++;
+}
+
+
+METHODDEF(void)
+merged_1v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 1:1 vertical sampling case: much easier, never need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Just do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
+ output_buf + *out_row_ctr);
+ /* Adjust counts */
+ (*out_row_ctr)++;
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by the control routines to do
+ * the actual upsampling/conversion. One row group is processed per call.
+ *
+ * Note: since we may be writing directly into application-supplied buffers,
+ * we have to be honest about the output width; we can't assume the buffer
+ * has been rounded up to an even width.
+ */
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
+ */
+
+METHODDEF(void)
+h2v1_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
+ */
+
+METHODDEF(void)
+h2v2_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ y = GETJSAMPLE(*inptr01);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Module initialization routine for merged upsampling/color conversion.
+ *
+ * NB: this is called under the conditions determined by use_merged_upsample()
+ * in jdmaster.c. That routine MUST correspond to the actual capabilities
+ * of this module; no safety checks are made here.
+ */
+
+GLOBAL(void)
+jinit_merged_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_merged_upsample;
+ upsample->pub.need_context_rows = FALSE;
+
+ upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
+
+ if (cinfo->max_v_samp_factor == 2) {
+ upsample->pub.upsample = merged_2v_upsample;
+ upsample->upmethod = h2v2_merged_upsample;
+ /* Allocate a spare row buffer */
+ upsample->spare_row = (JSAMPROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
+ } else {
+ upsample->pub.upsample = merged_1v_upsample;
+ upsample->upmethod = h2v1_merged_upsample;
+ /* No spare row needed */
+ upsample->spare_row = NULL;
+ }
+
+ build_ycc_rgb_table(cinfo);
+}
+
+#endif /* UPSAMPLE_MERGING_SUPPORTED */
diff --git a/gs/jpeg/jdphuff.c b/gs/jpeg/jdphuff.c
new file mode 100644
index 000000000..f6a89f346
--- /dev/null
+++ b/gs/jpeg/jdphuff.c
@@ -0,0 +1,642 @@
+/*
+ * jdphuff.c
+ *
+ * Copyright (C) 1995-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines for progressive JPEG.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdhuff.h" /* Declarations shared with jdhuff.c */
+
+
+#ifdef D_PROGRESSIVE_SUPPORTED
+
+/*
+ * Expanded entropy decoder object for progressive Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ unsigned int EOBRUN; /* remaining EOBs in EOBRUN */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).EOBRUN = (src).EOBRUN, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+ savable_state saved; /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+ d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
+} phuff_entropy_decoder;
+
+typedef phuff_entropy_decoder * phuff_entropy_ptr;
+
+/* Forward declarations */
+METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_phuff_decoder (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ boolean is_DC_band, bad;
+ int ci, coefi, tbl;
+ int *coef_bit_ptr;
+ jpeg_component_info * compptr;
+
+ is_DC_band = (cinfo->Ss == 0);
+
+ /* Validate scan parameters */
+ bad = FALSE;
+ if (is_DC_band) {
+ if (cinfo->Se != 0)
+ bad = TRUE;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2)
+ bad = TRUE;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ bad = TRUE;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Al != cinfo->Ah-1)
+ bad = TRUE;
+ }
+ if (cinfo->Al > 13) /* need not check for < 0 */
+ bad = TRUE;
+ if (bad)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int cindex = cinfo->cur_comp_info[ci]->component_index;
+ coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (is_DC_band)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (is_DC_band)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Make sure requested tables are present, and compute derived tables.
+ * We may build same derived table more than once, but it's not expensive.
+ */
+ if (is_DC_band) {
+ if (cinfo->Ah == 0) { /* DC refinement needs no table */
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS ||
+ cinfo->dc_huff_tbl_ptrs[tbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[tbl],
+ & entropy->derived_tbls[tbl]);
+ }
+ } else {
+ tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS ||
+ cinfo->ac_huff_tbl_ptrs[tbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[tbl],
+ & entropy->derived_tbls[tbl]);
+ /* remember the single active table */
+ entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->bitstate.printed_eod = FALSE;
+
+ /* Initialize private state variables */
+ entropy->saved.EOBRUN = 0;
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
+
+#else
+
+#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
+
+static const int extend_test[16] = /* entry n is 2**(n-1) */
+ { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
+
+static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
+ { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
+ ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
+ ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
+ ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Re-init EOB run count, too */
+ entropy->saved.EOBRUN = 0;
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+
+ /* Next segment can get another out-of-data warning */
+ entropy->bitstate.printed_eod = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Huffman MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * Huffman-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ *
+ * We return FALSE if data source requested suspension. In that case no
+ * changes have been made to permanent state. (Exception: some output
+ * coefficients may already have been assigned. This is harmless for
+ * spectral selection, since we'll just re-assign them on the next call.
+ * Successive approximation AC refinement has to be more careful, however.)
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Al = cinfo->Al;
+ register int s, r;
+ int blkn, ci;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ savable_state state;
+ d_derived_tbl * tbl;
+ jpeg_component_info * compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ tbl = entropy->derived_tbls[compptr->dc_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (s << Al);
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Se = cinfo->Se;
+ int Al = cinfo->Al;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Load up working state.
+ * We can avoid loading/saving bitread state if in an EOB run.
+ */
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we care about */
+
+ /* There is always only one block per MCU */
+
+ if (EOBRUN > 0) /* if it's a band of zeroes... */
+ EOBRUN--; /* ...process it now (we do nothing) */
+ else {
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al);
+ } else {
+ if (r == 15) { /* ZRL */
+ k += 15; /* skip 15 zeroes in band */
+ } else { /* EOBr, run length is 2^r + appended bits */
+ EOBRUN = 1 << r;
+ if (r) { /* EOBr, r > 0 */
+ CHECK_BIT_BUFFER(br_state, r, return FALSE);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ EOBRUN--; /* this band is processed at this moment */
+ break; /* force end-of-band */
+ }
+ }
+ }
+
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ }
+
+ /* Completed MCU, so update state */
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we care about */
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int blkn;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+ if (GET_BITS(1))
+ (*block)[0] |= p1;
+ /* Note: since we use |=, repeating the assignment later is safe */
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Se = cinfo->Se;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+ register int s, k, r;
+ unsigned int EOBRUN;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+ int num_newnz;
+ int newnz_pos[DCTSIZE2];
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we care about */
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ /* If we are forced to suspend, we must undo the assignments to any newly
+ * nonzero coefficients in the block, because otherwise we'd get confused
+ * next time about which coefficients were already nonzero.
+ * But we need not undo addition of bits to already-nonzero coefficients;
+ * instead, we can test the current bit position to see if we already did it.
+ */
+ num_newnz = 0;
+
+ /* initialize coefficient loop counter to start of band */
+ k = cinfo->Ss;
+
+ if (EOBRUN == 0) {
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ if (s != 1) /* size of new coef should always be 1 */
+ WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1))
+ s = p1; /* newly nonzero coef is positive */
+ else
+ s = m1; /* newly nonzero coef is negative */
+ } else {
+ if (r != 15) {
+ EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
+ if (r) {
+ CHECK_BIT_BUFFER(br_state, r, goto undoit);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ break; /* rest of block is handled by EOB logic */
+ }
+ /* note s = 0 for processing ZRL */
+ }
+ /* Advance over already-nonzero coefs and r still-zero coefs,
+ * appending correction bits to the nonzeroes. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ do {
+ thiscoef = *block + jpeg_natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ } else {
+ if (--r < 0)
+ break; /* reached target zero coefficient */
+ }
+ k++;
+ } while (k <= Se);
+ if (s) {
+ int pos = jpeg_natural_order[k];
+ /* Output newly nonzero coefficient */
+ (*block)[pos] = (JCOEF) s;
+ /* Remember its position in case we have to suspend */
+ newnz_pos[num_newnz++] = pos;
+ }
+ }
+ }
+
+ if (EOBRUN > 0) {
+ /* Scan any remaining coefficient positions after the end-of-band
+ * (the last newly nonzero coefficient, if any). Append a correction
+ * bit to each already-nonzero coefficient. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ for (; k <= Se; k++) {
+ thiscoef = *block + jpeg_natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ }
+ }
+ /* Count one block completed in EOB run */
+ EOBRUN--;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we care about */
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+
+undoit:
+ /* Re-zero any output coefficients that we made newly nonzero */
+ while (num_newnz > 0)
+ (*block)[newnz_pos[--num_newnz]] = 0;
+
+ return FALSE;
+}
+
+
+/*
+ * Module initialization routine for progressive Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_phuff_decoder (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy;
+ int *coef_bit_ptr;
+ int ci, i;
+
+ entropy = (phuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(phuff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass_phuff_decoder;
+
+ /* Mark derived tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+
+ /* Create progression status table */
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+}
+
+#endif /* D_PROGRESSIVE_SUPPORTED */
diff --git a/gs/jpeg/jdpostct.c b/gs/jpeg/jdpostct.c
new file mode 100644
index 000000000..571563d72
--- /dev/null
+++ b/gs/jpeg/jdpostct.c
@@ -0,0 +1,290 @@
+/*
+ * jdpostct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the decompression postprocessing controller.
+ * This controller manages the upsampling, color conversion, and color
+ * quantization/reduction steps; specifically, it controls the buffering
+ * between upsample/color conversion and color quantization/reduction.
+ *
+ * If no color quantization/reduction is required, then this module has no
+ * work to do, and it just hands off to the upsample/color conversion code.
+ * An integrated upsample/convert/quantize process would replace this module
+ * entirely.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_post_controller pub; /* public fields */
+
+ /* Color quantization source buffer: this holds output data from
+ * the upsample/color conversion step to be passed to the quantizer.
+ * For two-pass color quantization, we need a full-image buffer;
+ * for one-pass operation, a strip buffer is sufficient.
+ */
+ jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
+ JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
+ JDIMENSION strip_height; /* buffer size in rows */
+ /* for two-pass mode only: */
+ JDIMENSION starting_row; /* row # of first row in current strip */
+ JDIMENSION next_row; /* index of next row to fill/empty in strip */
+} my_post_controller;
+
+typedef my_post_controller * my_post_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) post_process_1pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) post_process_prepass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+METHODDEF(void) post_process_2pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->quantize_colors) {
+ /* Single-pass processing with color quantization. */
+ post->pub.post_process_data = post_process_1pass;
+ /* We could be doing buffered-image output before starting a 2-pass
+ * color quantization; in that case, jinit_d_post_controller did not
+ * allocate a strip buffer. Use the virtual-array buffer as workspace.
+ */
+ if (post->buffer == NULL) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ (JDIMENSION) 0, post->strip_height, TRUE);
+ }
+ } else {
+ /* For single-pass processing without color quantization,
+ * I have no work to do; just call the upsampler directly.
+ */
+ post->pub.post_process_data = cinfo->upsample->upsample;
+ }
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ /* First pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_prepass;
+ break;
+ case JBUF_CRANK_DEST:
+ /* Second pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_2pass;
+ break;
+#endif /* QUANT_2PASS_SUPPORTED */
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+ post->starting_row = post->next_row = 0;
+}
+
+
+/*
+ * Process some data in the one-pass (strip buffer) case.
+ * This is used for color precision reduction as well as one-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_1pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Fill the buffer, but not more than what we can dump out in one go. */
+ /* Note we rely on the upsampler to detect bottom of image. */
+ max_rows = out_rows_avail - *out_row_ctr;
+ if (max_rows > post->strip_height)
+ max_rows = post->strip_height;
+ num_rows = 0;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &num_rows, max_rows);
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer, output_buf + *out_row_ctr, (int) num_rows);
+ *out_row_ctr += num_rows;
+}
+
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+/*
+ * Process some data in the first pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_prepass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION old_next_row, num_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, TRUE);
+ }
+
+ /* Upsample some data (up to a strip height's worth). */
+ old_next_row = post->next_row;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &post->next_row, post->strip_height);
+
+ /* Allow quantizer to scan new data. No data is emitted, */
+ /* but we advance out_row_ctr so outer loop can tell when we're done. */
+ if (post->next_row > old_next_row) {
+ num_rows = post->next_row - old_next_row;
+ (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
+ (JSAMPARRAY) NULL, (int) num_rows);
+ *out_row_ctr += num_rows;
+ }
+
+ /* Advance if we filled the strip. */
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+
+/*
+ * Process some data in the second pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_2pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, FALSE);
+ }
+
+ /* Determine number of rows to emit. */
+ num_rows = post->strip_height - post->next_row; /* available in strip */
+ max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+ /* We have to check bottom of image here, can't depend on upsampler. */
+ max_rows = cinfo->output_height - post->starting_row;
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer + post->next_row, output_buf + *out_row_ctr,
+ (int) num_rows);
+ *out_row_ctr += num_rows;
+
+ /* Advance if we filled the strip. */
+ post->next_row += num_rows;
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize postprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_post_ptr post;
+
+ post = (my_post_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_post_controller));
+ cinfo->post = (struct jpeg_d_post_controller *) post;
+ post->pub.start_pass = start_pass_dpost;
+ post->whole_image = NULL; /* flag for no virtual arrays */
+ post->buffer = NULL; /* flag for no strip buffer */
+
+ /* Create the quantization buffer, if needed */
+ if (cinfo->quantize_colors) {
+ /* The buffer strip height is max_v_samp_factor, which is typically
+ * an efficient number of rows for upsampling to return.
+ * (In the presence of output rescaling, we might want to be smarter?)
+ */
+ post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
+ if (need_full_buffer) {
+ /* Two-pass color quantization: need full-image storage. */
+ /* We round up the number of rows to a multiple of the strip height. */
+#ifdef QUANT_2PASS_SUPPORTED
+ post->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ cinfo->output_width * cinfo->out_color_components,
+ (JDIMENSION) jround_up((long) cinfo->output_height,
+ (long) post->strip_height),
+ post->strip_height);
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ /* One-pass color quantization: just make a strip buffer. */
+ post->buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width * cinfo->out_color_components,
+ post->strip_height);
+ }
+ }
+}
diff --git a/gs/jpeg/jdsample.c b/gs/jpeg/jdsample.c
new file mode 100644
index 000000000..80ffefb2a
--- /dev/null
+++ b/gs/jpeg/jdsample.c
@@ -0,0 +1,478 @@
+/*
+ * jdsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains upsampling routines.
+ *
+ * Upsampling input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+ * sample rows of each component. Upsampling will normally produce
+ * max_v_samp_factor pixel rows from each row group (but this could vary
+ * if the upsampler is applying a scale factor of its own).
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to upsample a single component */
+typedef JMETHOD(void, upsample1_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Color conversion buffer. When using separate upsampling and color
+ * conversion steps, this buffer holds one upsampled row group until it
+ * has been color converted and output.
+ * Note: we do not allocate any storage for component(s) which are full-size,
+ * ie do not need rescaling. The corresponding entry of color_buf[] is
+ * simply set to point to the input data array, thereby avoiding copying.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ /* Per-component upsampling method pointers */
+ upsample1_ptr methods[MAX_COMPONENTS];
+
+ int next_row_out; /* counts rows emitted from color_buf */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+
+ /* Height of an input row group for each component. */
+ int rowgroup_height[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_expand need not
+ * recompute them each time. They are unused for other upsampling methods.
+ */
+ UINT8 h_expand[MAX_COMPONENTS];
+ UINT8 v_expand[MAX_COMPONENTS];
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the conversion buffer empty */
+ upsample->next_row_out = cinfo->max_v_samp_factor;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * In this version we upsample each component independently.
+ * We upsample one row group into the conversion buffer, then apply
+ * color conversion a row at a time.
+ */
+
+METHODDEF(void)
+sep_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JDIMENSION num_rows;
+
+ /* Fill the conversion buffer, if it's empty */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Invoke per-component upsample method. Notice we pass a POINTER
+ * to color_buf[ci], so that fullsize_upsample can change it.
+ */
+ (*upsample->methods[ci]) (cinfo, compptr,
+ input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
+ upsample->color_buf + ci);
+ }
+ upsample->next_row_out = 0;
+ }
+
+ /* Color-convert and emit rows */
+
+ /* How many we have in the buffer: */
+ num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
+ /* Not more than the distance to the end of the image. Need this test
+ * in case the image height is not a multiple of max_v_samp_factor:
+ */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+
+ (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
+ (JDIMENSION) upsample->next_row_out,
+ output_buf + *out_row_ctr,
+ (int) num_rows);
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ upsample->next_row_out += num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor)
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by sep_upsample to upsample pixel values
+ * of a single component. One row group is processed per call.
+ */
+
+
+/*
+ * For full-size components, we just make color_buf[ci] point at the
+ * input buffer, and thus avoid copying any data. Note that this is
+ * safe only because sep_upsample doesn't declare the input row group
+ * "consumed" until we are done color converting and emitting it.
+ */
+
+METHODDEF(void)
+fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = input_data;
+}
+
+
+/*
+ * This is a no-op version used for "uninteresting" components.
+ * These components will not be referenced by color conversion.
+ */
+
+METHODDEF(void)
+noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = NULL; /* safety check */
+}
+
+
+/*
+ * This version handles any integral sampling ratios.
+ * This is not used for typical JPEG files, so it need not be fast.
+ * Nor, for that matter, is it particularly accurate: the algorithm is
+ * simple replication of the input pixel onto the corresponding output
+ * pixels. The hi-falutin sampling literature refers to this as a
+ * "box filter". A box filter tends to introduce visible artifacts,
+ * so if you are actually going to use 3:1 or 4:1 sampling ratios
+ * you would be well advised to improve this code.
+ */
+
+METHODDEF(void)
+int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ register int h;
+ JSAMPROW outend;
+ int h_expand, v_expand;
+ int inrow, outrow;
+
+ h_expand = upsample->h_expand[compptr->component_index];
+ v_expand = upsample->v_expand[compptr->component_index];
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ /* Generate one output row with proper horizontal expansion */
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ for (h = h_expand; h > 0; h--) {
+ *outptr++ = invalue;
+ }
+ }
+ /* Generate any additional output rows by duplicating the first one */
+ if (v_expand > 1) {
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ v_expand-1, cinfo->output_width);
+ }
+ inrow++;
+ outrow += v_expand;
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int inrow;
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ inptr = input_data[inrow];
+ outptr = output_data[inrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int inrow, outrow;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ 1, cinfo->output_width);
+ inrow++;
+ outrow += 2;
+ }
+}
+
+
+/*
+ * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
+ *
+ * The upsampling algorithm is linear interpolation between pixel centers,
+ * also known as a "triangle filter". This is a good compromise between
+ * speed and visual quality. The centers of the output pixels are 1/4 and 3/4
+ * of the way between input pixel centers.
+ *
+ * A note about the "bias" calculations: when rounding fractional values to
+ * integer, we do not want to always round 0.5 up to the next integer.
+ * If we did that, we'd introduce a noticeable bias towards larger values.
+ * Instead, this code is arranged so that 0.5 will be rounded up or down at
+ * alternate pixel locations (a simple ordered dither pattern).
+ */
+
+METHODDEF(void)
+h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register int invalue;
+ register JDIMENSION colctr;
+ int inrow;
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ inptr = input_data[inrow];
+ outptr = output_data[inrow];
+ /* Special case for first column */
+ invalue = GETJSAMPLE(*inptr++);
+ *outptr++ = (JSAMPLE) invalue;
+ *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2);
+
+ for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
+ /* General case: 3/4 * nearer pixel + 1/4 * further pixel */
+ invalue = GETJSAMPLE(*inptr++) * 3;
+ *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2);
+ *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2);
+ }
+
+ /* Special case for last column */
+ invalue = GETJSAMPLE(*inptr);
+ *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2);
+ *outptr++ = (JSAMPLE) invalue;
+ }
+}
+
+
+/*
+ * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical.
+ * Again a triangle filter; see comments for h2v1 case, above.
+ *
+ * It is OK for us to reference the adjacent input rows because we demanded
+ * context from the main buffer controller (see initialization code).
+ */
+
+METHODDEF(void)
+h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr0, inptr1, outptr;
+#if BITS_IN_JSAMPLE == 8
+ register int thiscolsum, lastcolsum, nextcolsum;
+#else
+ register INT32 thiscolsum, lastcolsum, nextcolsum;
+#endif
+ register JDIMENSION colctr;
+ int inrow, outrow, v;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ for (v = 0; v < 2; v++) {
+ /* inptr0 points to nearest input row, inptr1 points to next nearest */
+ inptr0 = input_data[inrow];
+ if (v == 0) /* next nearest is row above */
+ inptr1 = input_data[inrow-1];
+ else /* next nearest is row below */
+ inptr1 = input_data[inrow+1];
+ outptr = output_data[outrow++];
+
+ /* Special case for first column */
+ thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
+ nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
+ *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4);
+ *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ lastcolsum = thiscolsum; thiscolsum = nextcolsum;
+
+ for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
+ /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
+ /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
+ nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
+ *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ lastcolsum = thiscolsum; thiscolsum = nextcolsum;
+ }
+
+ /* Special case for last column */
+ *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4);
+ }
+ inrow++;
+ }
+}
+
+
+/*
+ * Module initialization routine for upsampling.
+ */
+
+GLOBAL(void)
+jinit_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean need_buffer, do_fancy;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_upsample;
+ upsample->pub.upsample = sep_upsample;
+ upsample->pub.need_context_rows = FALSE; /* until we find out differently */
+
+ if (cinfo->CCIR601_sampling) /* this isn't supported */
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
+ * so don't ask for it.
+ */
+ do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1;
+
+ /* Verify we can handle the sampling factors, select per-component methods,
+ * and create storage as needed.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Compute size of an "input group" after IDCT scaling. This many samples
+ * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size;
+ v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
+ cinfo->min_DCT_scaled_size;
+ h_out_group = cinfo->max_h_samp_factor;
+ v_out_group = cinfo->max_v_samp_factor;
+ upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
+ need_buffer = TRUE;
+ if (! compptr->component_needed) {
+ /* Don't bother to upsample an uninteresting component. */
+ upsample->methods[ci] = noop_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
+ /* Fullsize components can be processed without any work. */
+ upsample->methods[ci] = fullsize_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group == v_out_group) {
+ /* Special cases for 2h1v upsampling */
+ if (do_fancy && compptr->downsampled_width > 2)
+ upsample->methods[ci] = h2v1_fancy_upsample;
+ else
+ upsample->methods[ci] = h2v1_upsample;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group * 2 == v_out_group) {
+ /* Special cases for 2h2v upsampling */
+ if (do_fancy && compptr->downsampled_width > 2) {
+ upsample->methods[ci] = h2v2_fancy_upsample;
+ upsample->pub.need_context_rows = TRUE;
+ } else
+ upsample->methods[ci] = h2v2_upsample;
+ } else if ((h_out_group % h_in_group) == 0 &&
+ (v_out_group % v_in_group) == 0) {
+ /* Generic integral-factors upsampling method */
+ upsample->methods[ci] = int_upsample;
+ upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
+ upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ if (need_buffer) {
+ upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) jround_up((long) cinfo->output_width,
+ (long) cinfo->max_h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/gs/jpeg/jdtrans.c b/gs/jpeg/jdtrans.c
new file mode 100644
index 000000000..db620bcdf
--- /dev/null
+++ b/gs/jpeg/jdtrans.c
@@ -0,0 +1,122 @@
+/*
+ * jdtrans.c
+ *
+ * Copyright (C) 1995-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding decompression,
+ * that is, reading raw DCT coefficient arrays from an input JPEG file.
+ * The routines in jdapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Read the coefficient arrays from a JPEG file.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * The entire image is read into a set of virtual coefficient-block arrays,
+ * one per component. The return value is a pointer to the array of
+ * virtual-array descriptors. These can be manipulated directly via the
+ * JPEG memory manager, or handed off to jpeg_write_coefficients().
+ * To release the memory occupied by the virtual arrays, call
+ * jpeg_finish_decompress() when done with the data.
+ *
+ * Returns NULL if suspended. This case need be checked only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(jvirt_barray_ptr *)
+jpeg_read_coefficients (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize active modules */
+ transdecode_master_selection(cinfo);
+ cinfo->global_state = DSTATE_RDCOEFS;
+ } else if (cinfo->global_state != DSTATE_RDCOEFS)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Absorb whole file into the coef buffer */
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return NULL;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* startup underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+ /* Set state so that jpeg_finish_decompress does the right thing */
+ cinfo->global_state = DSTATE_STOPPING;
+ return cinfo->coef->coef_arrays;
+}
+
+
+/*
+ * Master selection of decompression modules for transcoding.
+ * This substitutes for jdmaster.c's initialization of the full decompressor.
+ */
+
+LOCAL(void)
+transdecode_master_selection (j_decompress_ptr cinfo)
+{
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef D_PROGRESSIVE_SUPPORTED
+ jinit_phuff_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Always get a full-image coefficient buffer. */
+ jinit_d_coef_controller(cinfo, TRUE);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+ /* Initialize progress monitoring. */
+ if (cinfo->progress != NULL) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else if (cinfo->inputctl->has_multiple_scans) {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ } else {
+ nscans = 1;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = 1;
+ }
+}
diff --git a/gs/jpeg/jerror.c b/gs/jpeg/jerror.c
new file mode 100644
index 000000000..8b89e39c1
--- /dev/null
+++ b/gs/jpeg/jerror.c
@@ -0,0 +1,228 @@
+/*
+ * jerror.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains simple error-reporting and trace-message routines.
+ * These are suitable for Unix-like systems and others where writing to
+ * stderr is the right thing to do. Many applications will want to replace
+ * some or all of these routines.
+ *
+ * These routines are used by both the compression and decompression code.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jversion.h"
+#include "jerror.h"
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+
+
+/*
+ * Create the message string table.
+ * We do this from the master message list in jerror.h by re-reading
+ * jerror.h with a suitable definition for macro JMESSAGE.
+ * The message table is made an external symbol just in case any applications
+ * want to refer to it directly.
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_message_table jMsgTable
+#endif
+
+#define JMESSAGE(code,string) string ,
+
+const char * const jpeg_std_message_table[] = {
+#include "jerror.h"
+ NULL
+};
+
+
+/*
+ * Error exit handler: must not return to caller.
+ *
+ * Applications may override this if they want to get control back after
+ * an error. Typically one would longjmp somewhere instead of exiting.
+ * The setjmp buffer can be made a private field within an expanded error
+ * handler object. Note that the info needed to generate an error message
+ * is stored in the error object, so you can generate the message now or
+ * later, at your convenience.
+ * You should make sure that the JPEG object is cleaned up (with jpeg_abort
+ * or jpeg_destroy) at some point.
+ */
+
+METHODDEF(void)
+error_exit (j_common_ptr cinfo)
+{
+ /* Always display the message */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Let the memory manager delete any temp files before we die */
+ jpeg_destroy(cinfo);
+
+ exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Actual output of an error or trace message.
+ * Applications may override this method to send JPEG messages somewhere
+ * other than stderr.
+ */
+
+METHODDEF(void)
+output_message (j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+ /* Send it to stderr, adding a newline */
+ fprintf(stderr, "%s\n", buffer);
+}
+
+
+/*
+ * Decide whether to emit a trace or warning message.
+ * msg_level is one of:
+ * -1: recoverable corrupt-data warning, may want to abort.
+ * 0: important advisory messages (always display to user).
+ * 1: first level of tracing detail.
+ * 2,3,...: successively more detailed tracing messages.
+ * An application might override this method if it wanted to abort on warnings
+ * or change the policy about which messages to display.
+ */
+
+METHODDEF(void)
+emit_message (j_common_ptr cinfo, int msg_level)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+
+ if (msg_level < 0) {
+ /* It's a warning message. Since corrupt files may generate many warnings,
+ * the policy implemented here is to show only the first warning,
+ * unless trace_level >= 3.
+ */
+ if (err->num_warnings == 0 || err->trace_level >= 3)
+ (*err->output_message) (cinfo);
+ /* Always count warnings in num_warnings. */
+ err->num_warnings++;
+ } else {
+ /* It's a trace message. Show it if trace_level >= msg_level. */
+ if (err->trace_level >= msg_level)
+ (*err->output_message) (cinfo);
+ }
+}
+
+
+/*
+ * Format a message string for the most recent JPEG error or message.
+ * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
+ * characters. Note that no '\n' character is added to the string.
+ * Few applications should need to override this method.
+ */
+
+METHODDEF(void)
+format_message (j_common_ptr cinfo, char * buffer)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+ int msg_code = err->msg_code;
+ const char * msgtext = NULL;
+ const char * msgptr;
+ char ch;
+ boolean isstring;
+
+ /* Look up message string in proper table */
+ if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+ msgtext = err->jpeg_message_table[msg_code];
+ } else if (err->addon_message_table != NULL &&
+ msg_code >= err->first_addon_message &&
+ msg_code <= err->last_addon_message) {
+ msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+ }
+
+ /* Defend against bogus message number */
+ if (msgtext == NULL) {
+ err->msg_parm.i[0] = msg_code;
+ msgtext = err->jpeg_message_table[0];
+ }
+
+ /* Check for string parameter, as indicated by %s in the message text */
+ isstring = FALSE;
+ msgptr = msgtext;
+ while ((ch = *msgptr++) != '\0') {
+ if (ch == '%') {
+ if (*msgptr == 's') isstring = TRUE;
+ break;
+ }
+ }
+
+ /* Format the message into the passed buffer */
+ if (isstring)
+ sprintf(buffer, msgtext, err->msg_parm.s);
+ else
+ sprintf(buffer, msgtext,
+ err->msg_parm.i[0], err->msg_parm.i[1],
+ err->msg_parm.i[2], err->msg_parm.i[3],
+ err->msg_parm.i[4], err->msg_parm.i[5],
+ err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+
+/*
+ * Reset error state variables at start of a new image.
+ * This is called during compression startup to reset trace/error
+ * processing to default state, without losing any application-specific
+ * method pointers. An application might possibly want to override
+ * this method if it has additional error processing state.
+ */
+
+METHODDEF(void)
+reset_error_mgr (j_common_ptr cinfo)
+{
+ cinfo->err->num_warnings = 0;
+ /* trace_level is not reset since it is an application-supplied parameter */
+ cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
+}
+
+
+/*
+ * Fill in the standard error-handling methods in a jpeg_error_mgr object.
+ * Typical call is:
+ * struct jpeg_compress_struct cinfo;
+ * struct jpeg_error_mgr err;
+ *
+ * cinfo.err = jpeg_std_error(&err);
+ * after which the application may override some of the methods.
+ */
+
+GLOBAL(struct jpeg_error_mgr *)
+jpeg_std_error (struct jpeg_error_mgr * err)
+{
+ err->error_exit = error_exit;
+ err->emit_message = emit_message;
+ err->output_message = output_message;
+ err->format_message = format_message;
+ err->reset_error_mgr = reset_error_mgr;
+
+ err->trace_level = 0; /* default = no tracing */
+ err->num_warnings = 0; /* no warnings emitted yet */
+ err->msg_code = 0; /* may be useful as a flag for "no error" */
+
+ /* Initialize message table pointers */
+ err->jpeg_message_table = jpeg_std_message_table;
+ err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
+
+ err->addon_message_table = NULL;
+ err->first_addon_message = 0; /* for safety */
+ err->last_addon_message = 0;
+
+ return err;
+}
diff --git a/gs/jpeg/jerror.h b/gs/jpeg/jerror.h
new file mode 100644
index 000000000..de82c8a19
--- /dev/null
+++ b/gs/jpeg/jerror.h
@@ -0,0 +1,277 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994-1995, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too. Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef JERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* JERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_ARITH_NOTIMPL,
+ "Sorry, there are legal restrictions on arithmetic coding")
+JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
+JMESSAGE(JERR_BAD_LIB_VERSION,
+ "Wrong JPEG library version: library is %d, caller expects %d")
+JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_PROGRESSION,
+ "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+JMESSAGE(JERR_BAD_PROG_SCRIPT,
+ "Invalid progressive parameters at scan script entry %d")
+JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
+JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
+JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_STRUCT_SIZE,
+ "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_COUNTS, "Bogus DHT counts")
+JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
+JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
+ "Cannot transcode due to multiple use of quantization table %d")
+JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
+JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
+JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS,
+ "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
+JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE,
+ "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES,
+ "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE,
+ "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
+JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, "JFIF APP0 marker, density %dx%d %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
+ "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_MINOR, "Unknown JFIF minor revision number %d.%02d")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, "Skipping marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL,
+ "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, "Start of Image")
+JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
+JMESSAGE(JTRC_UNKNOWN_IDS,
+ "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_BOGUS_PROGRESSION,
+ "Inconsistent progression sequence for component %d coefficient %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA,
+ "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC,
+ "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
+
+
+#ifndef JERROR_H
+#define JERROR_H
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JERROR_H */
diff --git a/gs/jpeg/jfdctflt.c b/gs/jpeg/jfdctflt.c
new file mode 100644
index 000000000..79d7a0078
--- /dev/null
+++ b/gs/jpeg/jfdctflt.c
@@ -0,0 +1,168 @@
+/*
+ * jfdctflt.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * This implementation should be more accurate than either of the integer
+ * DCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_float (FAST_FLOAT * data)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;
+ FAST_FLOAT *dataptr;
+ int ctr;
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[0] + dataptr[7];
+ tmp7 = dataptr[0] - dataptr[7];
+ tmp1 = dataptr[1] + dataptr[6];
+ tmp6 = dataptr[1] - dataptr[6];
+ tmp2 = dataptr[2] + dataptr[5];
+ tmp5 = dataptr[2] - dataptr[5];
+ tmp3 = dataptr[3] + dataptr[4];
+ tmp4 = dataptr[3] - dataptr[4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/gs/jpeg/jfdctfst.c b/gs/jpeg/jfdctfst.c
new file mode 100644
index 000000000..ccb378a3b
--- /dev/null
+++ b/gs/jpeg/jfdctfst.c
@@ -0,0 +1,224 @@
+/*
+ * jfdctfst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jfdctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * Again to save a few shifts, the intermediate results between pass 1 and
+ * pass 2 are not upscaled, but are represented only to integral precision.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#define CONST_BITS 8
+
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */
+#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */
+#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */
+#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */
+#else
+#define FIX_0_382683433 FIX(0.382683433)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_707106781 FIX(0.707106781)
+#define FIX_1_306562965 FIX(1.306562965)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_ifast (DCTELEM * data)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z1, z2, z3, z4, z5, z11, z13;
+ DCTELEM *dataptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[0] + dataptr[7];
+ tmp7 = dataptr[0] - dataptr[7];
+ tmp1 = dataptr[1] + dataptr[6];
+ tmp6 = dataptr[1] - dataptr[6];
+ tmp2 = dataptr[2] + dataptr[5];
+ tmp5 = dataptr[2] - dataptr[5];
+ tmp3 = dataptr[3] + dataptr[4];
+ tmp4 = dataptr[3] - dataptr[4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/gs/jpeg/jfdctint.c b/gs/jpeg/jfdctint.c
new file mode 100644
index 000000000..0a78b64ae
--- /dev/null
+++ b/gs/jpeg/jfdctint.c
@@ -0,0 +1,283 @@
+/*
+ * jfdctint.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D DCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true DCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D DCT,
+ * because the y0 and y4 outputs need not be divided by sqrt(N).
+ * In the IJG code, this factor of 8 is removed by the quantization step
+ * (in jcdctmgr.c), NOT in this module.
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (For 12-bit sample data, the intermediate
+ * array is INT32 anyway.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_islow (DCTELEM * data)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3, z4, z5;
+ DCTELEM *dataptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[0] + dataptr[7];
+ tmp7 = dataptr[0] - dataptr[7];
+ tmp1 = dataptr[1] + dataptr[6];
+ tmp6 = dataptr[1] - dataptr[6];
+ tmp2 = dataptr[2] + dataptr[5];
+ tmp5 = dataptr[2] - dataptr[5];
+ tmp3 = dataptr[3] + dataptr[4];
+ tmp4 = dataptr[3] - dataptr[4];
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS);
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents cos(K*pi/16).
+ * i0..i3 in the paper are tmp4..tmp7 here.
+ */
+
+ z1 = tmp4 + tmp7;
+ z2 = tmp5 + tmp6;
+ z3 = tmp4 + tmp6;
+ z4 = tmp5 + tmp7;
+ z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
+
+ tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS);
+ dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents cos(K*pi/16).
+ * i0..i3 in the paper are tmp4..tmp7 here.
+ */
+
+ z1 = tmp4 + tmp7;
+ z2 = tmp5 + tmp6;
+ z3 = tmp4 + tmp6;
+ z4 = tmp5 + tmp7;
+ z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
+
+ tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3,
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4,
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3,
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4,
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/gs/jpeg/jidctflt.c b/gs/jpeg/jidctflt.c
new file mode 100644
index 000000000..1724a0b82
--- /dev/null
+++ b/gs/jpeg/jidctflt.c
@@ -0,0 +1,241 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a float result.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ FLOAT_MULT_TYPE * quantptr;
+ FAST_FLOAT * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] |
+ inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] |
+ inptr[DCTSIZE*7]) == 0) {
+ /* AC terms all zero */
+ FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+ tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE*0] = tmp0 + tmp7;
+ wsptr[DCTSIZE*7] = tmp0 - tmp7;
+ wsptr[DCTSIZE*1] = tmp1 + tmp6;
+ wsptr[DCTSIZE*6] = tmp1 - tmp6;
+ wsptr[DCTSIZE*2] = tmp2 + tmp5;
+ wsptr[DCTSIZE*5] = tmp2 - tmp5;
+ wsptr[DCTSIZE*4] = tmp3 + tmp4;
+ wsptr[DCTSIZE*3] = tmp3 - tmp4;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * And testing floats for zero is relatively expensive, so we don't bother.
+ */
+
+ /* Even part */
+
+ tmp10 = wsptr[0] + wsptr[4];
+ tmp11 = wsptr[0] - wsptr[4];
+
+ tmp13 = wsptr[2] + wsptr[6];
+ tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+ tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+ outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/gs/jpeg/jidctfst.c b/gs/jpeg/jidctfst.c
new file mode 100644
index 000000000..c8661ba21
--- /dev/null
+++ b/gs/jpeg/jidctfst.c
@@ -0,0 +1,367 @@
+/*
+ * jidctfst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jidctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * The dequantized coefficients are not integers because the AA&N scaling
+ * factors have been incorporated. We represent them scaled up by PASS1_BITS,
+ * so that the first and second IDCT rounds have the same input scaling.
+ * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * avoid a descaling shift; this compromises accuracy rather drastically
+ * for small quantization table entries, but it saves a lot of shifts.
+ * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * so we use a much larger scaling factor to preserve accuracy.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 8
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 8
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */
+#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */
+#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */
+#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */
+#else
+#define FIX_1_082392200 FIX(1.082392200)
+#define FIX_1_414213562 FIX(1.414213562)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_2_613125930 FIX(2.613125930)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a DCTELEM result. For 8-bit data a 16x16->16
+ * multiplication will do. For 12-bit data, the multiplier table is
+ * declared INT32, so a 32-bit multiply will be used.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval))
+#else
+#define DEQUANTIZE(coef,quantval) \
+ DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)
+#endif
+
+
+/* Like DESCALE, but applies to a DCTELEM and produces an int.
+ * We assume that int right shift is unsigned if INT32 right shift is.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS DCTELEM ishift_temp;
+#if BITS_IN_JSAMPLE == 8
+#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */
+#else
+#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */
+#endif
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+#ifdef USE_ACCURATE_ROUNDING
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n))
+#else
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n))
+#endif
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ IFAST_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS /* for DESCALE */
+ ISHIFT_TEMPS /* for IDESCALE */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] |
+ inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] |
+ inptr[DCTSIZE*7]) == 0) {
+ /* AC terms all zero */
+ int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+ wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+ wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+ wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+ wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);
+ wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+ wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+ wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[4] | wsptr[5] | wsptr[6] |
+ wsptr[7]) == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part */
+
+ tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+ tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+
+ tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+ tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562)
+ - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+ z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+ z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+ z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+ outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/gs/jpeg/jidctint.c b/gs/jpeg/jidctint.c
new file mode 100644
index 000000000..002dac2b8
--- /dev/null
+++ b/gs/jpeg/jidctint.c
@@ -0,0 +1,388 @@
+/*
+ * jidctint.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true IDCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D IDCT,
+ * because the y0 and y4 inputs need not be divided by sqrt(N).
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (To scale up 12-bit sample data further, an
+ * intermediate INT32 array would be needed.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce an int result. In this module, both inputs and result
+ * are 16 bits or less, so either int or short multiply will work.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3, z4, z5;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] |
+ inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] |
+ inptr[DCTSIZE*7]) == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
+ tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z1 = tmp0 + tmp3;
+ z2 = tmp1 + tmp2;
+ z3 = tmp0 + tmp2;
+ z4 = tmp1 + tmp3;
+ z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[4] | wsptr[5] | wsptr[6] |
+ wsptr[7]) == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
+ tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS;
+ tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z1 = tmp0 + tmp3;
+ z2 = tmp1 + tmp2;
+ z3 = tmp0 + tmp2;
+ z4 = tmp1 + tmp3;
+ z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/gs/jpeg/jidctred.c b/gs/jpeg/jidctred.c
new file mode 100644
index 000000000..3ec649c2b
--- /dev/null
+++ b/gs/jpeg/jidctred.c
@@ -0,0 +1,397 @@
+/*
+ * jidctred.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains inverse-DCT routines that produce reduced-size output:
+ * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block.
+ *
+ * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M)
+ * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step
+ * with an 8-to-4 step that produces the four averages of two adjacent outputs
+ * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output).
+ * These steps were derived by computing the corresponding values at the end
+ * of the normal LL&M code, then simplifying as much as possible.
+ *
+ * 1x1 is trivial: just take the DC coefficient divided by 8.
+ *
+ * See jidctint.c for additional comments.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling is the same as in jidctint.c. */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */
+#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */
+#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */
+#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */
+#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */
+#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */
+#else
+#define FIX_0_211164243 FIX(0.211164243)
+#define FIX_0_509795579 FIX(0.509795579)
+#define FIX_0_601344887 FIX(0.601344887)
+#define FIX_0_720959822 FIX(0.720959822)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_850430095 FIX(0.850430095)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_061594337 FIX(1.061594337)
+#define FIX_1_272758580 FIX(1.272758580)
+#define FIX_1_451774981 FIX(1.451774981)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_2_172734803 FIX(2.172734803)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_624509785 FIX(3.624509785)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce an int result. In this module, both inputs and result
+ * are 16 bits or less, so either int or short multiply will work.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 4x4 output block.
+ */
+
+GLOBAL(void)
+jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
+ /* Don't bother to process column 4, because second pass won't use it */
+ if (ctr == DCTSIZE-4)
+ continue;
+ if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] |
+ inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | inptr[DCTSIZE*7]) == 0) {
+ /* AC terms all zero; we need not examine term 4 for 4x4 output */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= (CONST_BITS+1);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
+ + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
+ + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
+ + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */
+
+ tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
+ + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
+ + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
+ + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */
+
+ /* Final output stage */
+
+ wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1);
+ wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1);
+ wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1);
+ wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1);
+ }
+
+ /* Pass 2: process 4 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* It's not clear whether a zero row test is worthwhile here ... */
+
+#ifndef NO_ZERO_ROW_TEST
+ if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[5] | wsptr[6] |
+ wsptr[7]) == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part */
+
+ tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1);
+
+ tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065)
+ + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[7];
+ z2 = (INT32) wsptr[5];
+ z3 = (INT32) wsptr[3];
+ z4 = (INT32) wsptr[1];
+
+ tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
+ + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
+ + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
+ + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */
+
+ tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
+ + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
+ + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
+ + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2,
+ CONST_BITS+PASS1_BITS+3+1)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2,
+ CONST_BITS+PASS1_BITS+3+1)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0,
+ CONST_BITS+PASS1_BITS+3+1)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0,
+ CONST_BITS+PASS1_BITS+3+1)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 2x2 output block.
+ */
+
+GLOBAL(void)
+jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp10, z1;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE*2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
+ /* Don't bother to process columns 2,4,6 */
+ if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6)
+ continue;
+ if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*3] |
+ inptr[DCTSIZE*5] | inptr[DCTSIZE*7]) == 0) {
+ /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+
+ continue;
+ }
+
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp10 = z1 << (CONST_BITS+2);
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */
+ z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */
+ z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */
+
+ /* Final output stage */
+
+ wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2);
+ wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2);
+ }
+
+ /* Pass 2: process 2 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 2; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* It's not clear whether a zero row test is worthwhile here ... */
+
+#ifndef NO_ZERO_ROW_TEST
+ if ((wsptr[1] | wsptr[3] | wsptr[5] | wsptr[7]) == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part */
+
+ tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */
+ + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */
+ + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */
+ + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3+2)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3+2)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 1x1 output block.
+ */
+
+GLOBAL(void)
+jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ int dcval;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* We hardly need an inverse DCT routine for this: just take the
+ * average pixel value, which is one-eighth of the DC coefficient.
+ */
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
+ dcval = (int) DESCALE((INT32) dcval, 3);
+
+ output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
+}
+
+#endif /* IDCT_SCALING_SUPPORTED */
diff --git a/gs/jpeg/jinclude.h b/gs/jpeg/jinclude.h
new file mode 100644
index 000000000..0a4f15146
--- /dev/null
+++ b/gs/jpeg/jinclude.h
@@ -0,0 +1,91 @@
+/*
+ * jinclude.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file exists to provide a single place to fix any problems with
+ * including the wrong system include files. (Common problems are taken
+ * care of by the standard jconfig symbols, but on really weird systems
+ * you may have to edit this file.)
+ *
+ * NOTE: this file is NOT intended to be included by applications using the
+ * JPEG library. Most applications need only include jpeglib.h.
+ */
+
+
+/* Include auto-config file to find out which system include files we need. */
+
+#include "jconfig.h" /* auto configuration options */
+#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
+
+/*
+ * We need the NULL macro and size_t typedef.
+ * On an ANSI-conforming system it is sufficient to include <stddef.h>.
+ * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
+ * pull in <sys/types.h> as well.
+ * Note that the core JPEG library does not require <stdio.h>;
+ * only the default error handler and data source/destination modules do.
+ * But we must pull it in because of the references to FILE in jpeglib.h.
+ * You can remove those references if you want to compile without <stdio.h>.
+ */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+
+/*
+ * We need memory copying and zeroing functions, plus strncpy().
+ * ANSI and System V implementations declare these in <string.h>.
+ * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+ * Some systems may declare memset and memcpy in <memory.h>.
+ *
+ * NOTE: we assume the size parameters to these functions are of type size_t.
+ * Change the casts in these macros if not!
+ */
+
+#ifdef NEED_BSD_STRINGS
+
+#include <strings.h>
+#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size))
+#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size))
+
+#else /* not BSD, assume ANSI/SysV string lib */
+
+#include <string.h>
+#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size))
+#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size))
+
+#endif
+
+/*
+ * In ANSI C, and indeed any rational implementation, size_t is also the
+ * type returned by sizeof(). However, it seems there are some irrational
+ * implementations out there, in which sizeof() returns an int even though
+ * size_t is defined as long or unsigned long. To ensure consistent results
+ * we always use this SIZEOF() macro in place of using sizeof() directly.
+ */
+
+#define SIZEOF(object) ((size_t) sizeof(object))
+
+/*
+ * The modules that use fread() and fwrite() always invoke them through
+ * these macros. On some systems you may need to twiddle the argument casts.
+ * CAUTION: argument order is different from underlying functions!
+ */
+
+#define JFREAD(file,buf,sizeofbuf) \
+ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+#define JFWRITE(file,buf,sizeofbuf) \
+ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/gs/jpeg/jmemansi.c b/gs/jpeg/jmemansi.c
new file mode 100644
index 000000000..2d93e4962
--- /dev/null
+++ b/gs/jpeg/jmemansi.c
@@ -0,0 +1,167 @@
+/*
+ * jmemansi.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a simple generic implementation of the system-
+ * dependent portion of the JPEG memory manager. This implementation
+ * assumes that you have the ANSI-standard library routine tmpfile().
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
+#define SEEK_SET 0 /* if not, assume 0 is correct */
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFREAD(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFWRITE(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ fclose(info->temp_file);
+ /* Since this implementation uses tmpfile() to create the file,
+ * no explicit file deletion is needed.
+ */
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses tmpfile(), which constructs a suitable file name
+ * behind the scenes. We don't have to use info->temp_name[] at all;
+ * indeed, we can't even find out the actual name of the temp file.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ if ((info->temp_file = tmpfile()) == NULL)
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/gs/jpeg/jmemdos.c b/gs/jpeg/jmemdos.c
new file mode 100644
index 000000000..77fb5ad5b
--- /dev/null
+++ b/gs/jpeg/jmemdos.c
@@ -0,0 +1,634 @@
+/*
+ * jmemdos.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides an MS-DOS-compatible implementation of the system-
+ * dependent portion of the JPEG memory manager. Temporary data can be
+ * stored in extended or expanded memory as well as in regular DOS files.
+ *
+ * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
+ * if you compile in a small-data memory model; it should NOT be defined if
+ * you use a large-data memory model. This file is not recommended if you
+ * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
+ * Also, this code will NOT work if struct fields are aligned on greater than
+ * 2-byte boundaries.
+ *
+ * Based on code contributed by Ge' Weijers.
+ */
+
+/*
+ * If you have both extended and expanded memory, you may want to change the
+ * order in which they are tried in jopen_backing_store. On a 286 machine
+ * expanded memory is usually faster, since extended memory access involves
+ * an expensive protected-mode-and-back switch. On 386 and better, extended
+ * memory is usually faster. As distributed, the code tries extended memory
+ * first (what? not everyone has a 386? :-).
+ *
+ * You can disable use of extended/expanded memory entirely by altering these
+ * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
+ */
+
+#ifndef XMS_SUPPORTED
+#define XMS_SUPPORTED 1
+#endif
+#ifndef EMS_SUPPORTED
+#define EMS_SUPPORTED 1
+#endif
+
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare these */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+extern char * getenv JPP((const char * name));
+#endif
+
+#ifdef NEED_FAR_POINTERS
+
+#ifdef __TURBOC__
+/* These definitions work for Borland C (Turbo C) */
+#include <alloc.h> /* need farmalloc(), farfree() */
+#define far_malloc(x) farmalloc(x)
+#define far_free(x) farfree(x)
+#else
+/* These definitions work for Microsoft C and compatible compilers */
+#include <malloc.h> /* need _fmalloc(), _ffree() */
+#define far_malloc(x) _fmalloc(x)
+#define far_free(x) _ffree(x)
+#endif
+
+#else /* not NEED_FAR_POINTERS */
+
+#define far_malloc(x) malloc(x)
+#define far_free(x) free(x)
+
+#endif /* NEED_FAR_POINTERS */
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#else
+#define READ_BINARY "rb"
+#endif
+
+#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */
+ MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
+#endif
+
+
+/*
+ * Declarations for assembly-language support routines (see jmemdosa.asm).
+ *
+ * The functions are declared "far" as are all their pointer arguments;
+ * this ensures the assembly source code will work regardless of the
+ * compiler memory model. We assume "short" is 16 bits, "long" is 32.
+ */
+
+typedef void far * XMSDRIVER; /* actually a pointer to code */
+typedef struct { /* registers for calling XMS driver */
+ unsigned short ax, dx, bx;
+ void far * ds_si;
+ } XMScontext;
+typedef struct { /* registers for calling EMS driver */
+ unsigned short ax, dx, bx;
+ void far * ds_si;
+ } EMScontext;
+
+extern short far jdos_open JPP((short far * handle, char far * filename));
+extern short far jdos_close JPP((short handle));
+extern short far jdos_seek JPP((short handle, long offset));
+extern short far jdos_read JPP((short handle, void far * buffer,
+ unsigned short count));
+extern short far jdos_write JPP((short handle, void far * buffer,
+ unsigned short count));
+extern void far jxms_getdriver JPP((XMSDRIVER far *));
+extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
+extern short far jems_available JPP((void));
+extern void far jems_calldriver JPP((EMScontext far *));
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is highly system-dependent, and you may want to customize it.
+ */
+
+static int next_file_num; /* to distinguish among several temp files */
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ const char * env;
+ char * ptr;
+ FILE * tfile;
+
+ /* Keep generating file names till we find one that's not in use */
+ for (;;) {
+ /* Get temp directory name from environment TMP or TEMP variable;
+ * if none, use "."
+ */
+ if ((env = (const char *) getenv("TMP")) == NULL)
+ if ((env = (const char *) getenv("TEMP")) == NULL)
+ env = ".";
+ if (*env == '\0') /* null string means "." */
+ env = ".";
+ ptr = fname; /* copy name to fname */
+ while (*env != '\0')
+ *ptr++ = *env++;
+ if (ptr[-1] != '\\' && ptr[-1] != '/')
+ *ptr++ = '\\'; /* append backslash if not in env variable */
+ /* Append a suitable file name */
+ next_file_num++; /* advance counter */
+ sprintf(ptr, "JPG%03d.TMP", next_file_num);
+ /* Probe to see if file name is already in use */
+ if ((tfile = fopen(fname, READ_BINARY)) == NULL)
+ break;
+ fclose(tfile); /* oops, it's there; close tfile & try again */
+ }
+}
+
+
+/*
+ * Near-memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are allocated in far memory, if possible
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) far_malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ far_free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+/*
+ * For MS-DOS we support three types of backing storage:
+ * 1. Conventional DOS files. We access these by direct DOS calls rather
+ * than via the stdio package. This provides a bit better performance,
+ * but the real reason is that the buffers to be read or written are FAR.
+ * The stdio library for small-data memory models can't cope with that.
+ * 2. Extended memory, accessed per the XMS V2.0 specification.
+ * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
+ * You'll need copies of those specs to make sense of the related code.
+ * The specs are available by Internet FTP from the SIMTEL archives
+ * (oak.oakland.edu and its various mirror sites). See files
+ * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
+ */
+
+
+/*
+ * Access methods for a DOS file.
+ */
+
+
+METHODDEF(void)
+read_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (jdos_seek(info->handle.file_handle, file_offset))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+ if (byte_count > 65535L) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+ if (jdos_read(info->handle.file_handle, buffer_address,
+ (unsigned short) byte_count))
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (jdos_seek(info->handle.file_handle, file_offset))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+ if (byte_count > 65535L) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+ if (jdos_write(info->handle.file_handle, buffer_address,
+ (unsigned short) byte_count))
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_file_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ jdos_close(info->handle.file_handle); /* close the file */
+ remove(info->temp_name); /* delete the file */
+/* If your system doesn't have remove(), try unlink() instead.
+ * remove() is the ANSI-standard name for this function, but
+ * unlink() was more common in pre-ANSI systems.
+ */
+ TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+LOCAL(boolean)
+open_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ short handle;
+
+ select_file_name(info->temp_name);
+ if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
+ /* might as well exit since jpeg_open_backing_store will fail anyway */
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+ return FALSE;
+ }
+ info->handle.file_handle = handle;
+ info->read_backing_store = read_file_store;
+ info->write_backing_store = write_file_store;
+ info->close_backing_store = close_file_store;
+ TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+ return TRUE; /* succeeded */
+}
+
+
+/*
+ * Access methods for extended memory.
+ */
+
+#if XMS_SUPPORTED
+
+static XMSDRIVER xms_driver; /* saved address of XMS driver */
+
+typedef union { /* either long offset or real-mode pointer */
+ long offset;
+ void far * ptr;
+ } XMSPTR;
+
+typedef struct { /* XMS move specification structure */
+ long length;
+ XMSH src_handle;
+ XMSPTR src;
+ XMSH dst_handle;
+ XMSPTR dst;
+ } XMSspec;
+
+#define ODD(X) (((X) & 1L) != 0)
+
+
+METHODDEF(void)
+read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ XMScontext ctx;
+ XMSspec spec;
+ char endbuffer[2];
+
+ /* The XMS driver can't cope with an odd length, so handle the last byte
+ * specially if byte_count is odd. We don't expect this to be common.
+ */
+
+ spec.length = byte_count & (~ 1L);
+ spec.src_handle = info->handle.xms_handle;
+ spec.src.offset = file_offset;
+ spec.dst_handle = 0;
+ spec.dst.ptr = buffer_address;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x0b00; /* EMB move */
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ ERREXIT(cinfo, JERR_XMS_READ);
+
+ if (ODD(byte_count)) {
+ read_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
+ }
+}
+
+
+METHODDEF(void)
+write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ XMScontext ctx;
+ XMSspec spec;
+ char endbuffer[2];
+
+ /* The XMS driver can't cope with an odd length, so handle the last byte
+ * specially if byte_count is odd. We don't expect this to be common.
+ */
+
+ spec.length = byte_count & (~ 1L);
+ spec.src_handle = 0;
+ spec.src.ptr = buffer_address;
+ spec.dst_handle = info->handle.xms_handle;
+ spec.dst.offset = file_offset;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x0b00; /* EMB move */
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ ERREXIT(cinfo, JERR_XMS_WRITE);
+
+ if (ODD(byte_count)) {
+ read_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
+ write_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ }
+}
+
+
+METHODDEF(void)
+close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ XMScontext ctx;
+
+ ctx.dx = info->handle.xms_handle;
+ ctx.ax = 0x0a00;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
+ /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ XMScontext ctx;
+
+ /* Get address of XMS driver */
+ jxms_getdriver((XMSDRIVER far *) & xms_driver);
+ if (xms_driver == NULL)
+ return FALSE; /* no driver to be had */
+
+ /* Get version number, must be >= 2.00 */
+ ctx.ax = 0x0000;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax < (unsigned short) 0x0200)
+ return FALSE;
+
+ /* Try to get space (expressed in kilobytes) */
+ ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
+ ctx.ax = 0x0900;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ return FALSE;
+
+ /* Succeeded, save the handle and away we go */
+ info->handle.xms_handle = ctx.dx;
+ info->read_backing_store = read_xms_store;
+ info->write_backing_store = write_xms_store;
+ info->close_backing_store = close_xms_store;
+ TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
+ return TRUE; /* succeeded */
+}
+
+#endif /* XMS_SUPPORTED */
+
+
+/*
+ * Access methods for expanded memory.
+ */
+
+#if EMS_SUPPORTED
+
+/* The EMS move specification structure requires word and long fields aligned
+ * at odd byte boundaries. Some compilers will align struct fields at even
+ * byte boundaries. While it's usually possible to force byte alignment,
+ * that causes an overall performance penalty and may pose problems in merging
+ * JPEG into a larger application. Instead we accept some rather dirty code
+ * here. Note this code would fail if the hardware did not allow odd-byte
+ * word & long accesses, but all 80x86 CPUs do.
+ */
+
+typedef void far * EMSPTR;
+
+typedef union { /* EMS move specification structure */
+ long length; /* It's easy to access first 4 bytes */
+ char bytes[18]; /* Misaligned fields in here! */
+ } EMSspec;
+
+/* Macros for accessing misaligned fields */
+#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset])))
+#define SRC_TYPE(spec) FIELD_AT(spec,4,char)
+#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH)
+#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short)
+#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short)
+#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR)
+#define DST_TYPE(spec) FIELD_AT(spec,11,char)
+#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH)
+#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short)
+#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short)
+#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR)
+
+#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */
+
+#define HIBYTE(W) (((W) >> 8) & 0xFF)
+#define LOBYTE(W) ((W) & 0xFF)
+
+
+METHODDEF(void)
+read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ EMScontext ctx;
+ EMSspec spec;
+
+ spec.length = byte_count;
+ SRC_TYPE(spec) = 1;
+ SRC_HANDLE(spec) = info->handle.ems_handle;
+ SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
+ SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+ DST_TYPE(spec) = 0;
+ DST_HANDLE(spec) = 0;
+ DST_PTR(spec) = buffer_address;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x5700; /* move memory region */
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ ERREXIT(cinfo, JERR_EMS_READ);
+}
+
+
+METHODDEF(void)
+write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ EMScontext ctx;
+ EMSspec spec;
+
+ spec.length = byte_count;
+ SRC_TYPE(spec) = 0;
+ SRC_HANDLE(spec) = 0;
+ SRC_PTR(spec) = buffer_address;
+ DST_TYPE(spec) = 1;
+ DST_HANDLE(spec) = info->handle.ems_handle;
+ DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
+ DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x5700; /* move memory region */
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ ERREXIT(cinfo, JERR_EMS_WRITE);
+}
+
+
+METHODDEF(void)
+close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ EMScontext ctx;
+
+ ctx.ax = 0x4500;
+ ctx.dx = info->handle.ems_handle;
+ jems_calldriver((EMScontext far *) & ctx);
+ TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
+ /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ EMScontext ctx;
+
+ /* Is EMS driver there? */
+ if (! jems_available())
+ return FALSE;
+
+ /* Get status, make sure EMS is OK */
+ ctx.ax = 0x4000;
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ return FALSE;
+
+ /* Get version, must be >= 4.0 */
+ ctx.ax = 0x4600;
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
+ return FALSE;
+
+ /* Try to allocate requested space */
+ ctx.ax = 0x4300;
+ ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ return FALSE;
+
+ /* Succeeded, save the handle and away we go */
+ info->handle.ems_handle = ctx.dx;
+ info->read_backing_store = read_ems_store;
+ info->write_backing_store = write_ems_store;
+ info->close_backing_store = close_ems_store;
+ TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
+ return TRUE; /* succeeded */
+}
+
+#endif /* EMS_SUPPORTED */
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ /* Try extended memory, then expanded memory, then regular file. */
+#if XMS_SUPPORTED
+ if (open_xms_store(cinfo, info, total_bytes_needed))
+ return;
+#endif
+#if EMS_SUPPORTED
+ if (open_ems_store(cinfo, info, total_bytes_needed))
+ return;
+#endif
+ if (open_file_store(cinfo, info, total_bytes_needed))
+ return;
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ next_file_num = 0; /* initialize temp file name generator */
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
+ * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
+ */
+#ifdef NEED_FHEAPMIN
+ _fheapmin();
+#endif
+}
diff --git a/gs/jpeg/jmemdosa.asm b/gs/jpeg/jmemdosa.asm
new file mode 100644
index 000000000..ecd43729f
--- /dev/null
+++ b/gs/jpeg/jmemdosa.asm
@@ -0,0 +1,379 @@
+;
+; jmemdosa.asm
+;
+; Copyright (C) 1992, Thomas G. Lane.
+; This file is part of the Independent JPEG Group's software.
+; For conditions of distribution and use, see the accompanying README file.
+;
+; This file contains low-level interface routines to support the MS-DOS
+; backing store manager (jmemdos.c). Routines are provided to access disk
+; files through direct DOS calls, and to access XMS and EMS drivers.
+;
+; This file should assemble with Microsoft's MASM or any compatible
+; assembler (including Borland's Turbo Assembler). If you haven't got
+; a compatible assembler, better fall back to jmemansi.c or jmemname.c.
+;
+; To minimize dependence on the C compiler's register usage conventions,
+; we save and restore all 8086 registers, even though most compilers only
+; require SI,DI,DS to be preserved. Also, we use only 16-bit-wide return
+; values, which everybody returns in AX.
+;
+; Based on code contributed by Ge' Weijers.
+;
+
+JMEMDOSA_TXT segment byte public 'CODE'
+
+ assume cs:JMEMDOSA_TXT
+
+ public _jdos_open
+ public _jdos_close
+ public _jdos_seek
+ public _jdos_read
+ public _jdos_write
+ public _jxms_getdriver
+ public _jxms_calldriver
+ public _jems_available
+ public _jems_calldriver
+
+;
+; short far jdos_open (short far * handle, char far * filename)
+;
+; Create and open a temporary file
+;
+_jdos_open proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov cx,0 ; normal file attributes
+ lds dx,dword ptr [bp+10] ; get filename pointer
+ mov ah,3ch ; create file
+ int 21h
+ jc open_err ; if failed, return error code
+ lds bx,dword ptr [bp+6] ; get handle pointer
+ mov word ptr [bx],ax ; save the handle
+ xor ax,ax ; return zero for OK
+open_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_open endp
+
+
+;
+; short far jdos_close (short handle)
+;
+; Close the file handle
+;
+_jdos_close proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ mov ah,3eh ; close file
+ int 21h
+ jc close_err ; if failed, return error code
+ xor ax,ax ; return zero for OK
+close_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_close endp
+
+
+;
+; short far jdos_seek (short handle, long offset)
+;
+; Set file position
+;
+_jdos_seek proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ mov dx,word ptr [bp+8] ; LS offset
+ mov cx,word ptr [bp+10] ; MS offset
+ mov ax,4200h ; absolute seek
+ int 21h
+ jc seek_err ; if failed, return error code
+ xor ax,ax ; return zero for OK
+seek_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_seek endp
+
+
+;
+; short far jdos_read (short handle, void far * buffer, unsigned short count)
+;
+; Read from file
+;
+_jdos_read proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ lds dx,dword ptr [bp+8] ; buffer address
+ mov cx,word ptr [bp+12] ; number of bytes
+ mov ah,3fh ; read file
+ int 21h
+ jc read_err ; if failed, return error code
+ cmp ax,word ptr [bp+12] ; make sure all bytes were read
+ je read_ok
+ mov ax,1 ; else return 1 for not OK
+ jmp short read_err
+read_ok: xor ax,ax ; return zero for OK
+read_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_read endp
+
+
+;
+; short far jdos_write (short handle, void far * buffer, unsigned short count)
+;
+; Write to file
+;
+_jdos_write proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ lds dx,dword ptr [bp+8] ; buffer address
+ mov cx,word ptr [bp+12] ; number of bytes
+ mov ah,40h ; write file
+ int 21h
+ jc write_err ; if failed, return error code
+ cmp ax,word ptr [bp+12] ; make sure all bytes written
+ je write_ok
+ mov ax,1 ; else return 1 for not OK
+ jmp short write_err
+write_ok: xor ax,ax ; return zero for OK
+write_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_write endp
+
+
+;
+; void far jxms_getdriver (XMSDRIVER far *)
+;
+; Get the address of the XMS driver, or NULL if not available
+;
+_jxms_getdriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov ax,4300h ; call multiplex interrupt with
+ int 2fh ; a magic cookie, hex 4300
+ cmp al,80h ; AL should contain hex 80
+ je xmsavail
+ xor dx,dx ; no XMS driver available
+ xor ax,ax ; return a nil pointer
+ jmp short xmsavail_done
+xmsavail: mov ax,4310h ; fetch driver address with
+ int 2fh ; another magic cookie
+ mov dx,es ; copy address to dx:ax
+ mov ax,bx
+xmsavail_done: les bx,dword ptr [bp+6] ; get pointer to return value
+ mov word ptr es:[bx],ax
+ mov word ptr es:[bx+2],dx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jxms_getdriver endp
+
+
+;
+; void far jxms_calldriver (XMSDRIVER, XMScontext far *)
+;
+; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the XMS call is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jxms_calldriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ les bx,dword ptr [bp+10] ; get XMScontext pointer
+ mov ax,word ptr es:[bx] ; load registers
+ mov dx,word ptr es:[bx+2]
+ mov si,word ptr es:[bx+6]
+ mov ds,word ptr es:[bx+8]
+ mov bx,word ptr es:[bx+4]
+ call dword ptr [bp+6] ; call the driver
+ mov cx,bx ; save returned BX for a sec
+ les bx,dword ptr [bp+10] ; get XMScontext pointer
+ mov word ptr es:[bx],ax ; put back ax,dx,bx
+ mov word ptr es:[bx+2],dx
+ mov word ptr es:[bx+4],cx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jxms_calldriver endp
+
+
+;
+; short far jems_available (void)
+;
+; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs)
+;
+_jems_available proc far
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov ax,3567h ; get interrupt vector 67h
+ int 21h
+ push cs
+ pop ds
+ mov di,000ah ; check offs 10 in returned seg
+ lea si,ASCII_device_name ; against literal string
+ mov cx,8
+ cld
+ repe cmpsb
+ jne no_ems
+ mov ax,1 ; match, it's there
+ jmp short avail_done
+no_ems: xor ax,ax ; it's not there
+avail_done: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ ret
+
+ASCII_device_name db "EMMXXXX0"
+
+_jems_available endp
+
+
+;
+; void far jems_calldriver (EMScontext far *)
+;
+; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the EMS trap is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jems_calldriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ les bx,dword ptr [bp+6] ; get EMScontext pointer
+ mov ax,word ptr es:[bx] ; load registers
+ mov dx,word ptr es:[bx+2]
+ mov si,word ptr es:[bx+6]
+ mov ds,word ptr es:[bx+8]
+ mov bx,word ptr es:[bx+4]
+ int 67h ; call the EMS driver
+ mov cx,bx ; save returned BX for a sec
+ les bx,dword ptr [bp+6] ; get EMScontext pointer
+ mov word ptr es:[bx],ax ; put back ax,dx,bx
+ mov word ptr es:[bx+2],dx
+ mov word ptr es:[bx+4],cx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jems_calldriver endp
+
+JMEMDOSA_TXT ends
+
+ end
diff --git a/gs/jpeg/jmemmac.c b/gs/jpeg/jmemmac.c
new file mode 100644
index 000000000..41756cb03
--- /dev/null
+++ b/gs/jpeg/jmemmac.c
@@ -0,0 +1,199 @@
+/*
+ * jmemmac.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * jmemmac.c provides an Apple Macintosh implementation of the system-
+ * dependent portion of the JPEG memory manager.
+ *
+ * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
+ * instead of malloc and free. It accurately determines the amount of
+ * memory available by using CompactMem. Notice that if left to its
+ * own devices, this code can chew up all available space in the
+ * application's zone, with the exception of the rather small "slop"
+ * factor computed in jpeg_mem_available(). The application can ensure
+ * that more space is left over by reducing max_memory_to_use.
+ *
+ * Large images are swapped to disk using temporary files created with
+ * tmpfile(); that part of the module is the same as in jmemansi.c.
+ * Metrowerks CodeWarrior's implementation of tmpfile() isn't quite what
+ * we want: it puts the files in the local directory and makes them
+ * user-visible -- and only deletes them when the application quits,
+ * which means they stick around in the event of a crash.
+ * It would be better to create the temp files in the system's temporary
+ * items folder. Perhaps someday we'll get around to doing that.
+ *
+ * Contributed by Sam Bushell (jsam@iagu.on.net).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#include <Memory.h> /* we use the MacOS memory manager */
+
+#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
+#define SEEK_SET 0 /* if not, assume 0 is correct */
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the MacOS library
+ * routines NewPtr() and DisposePtr(), which allocate fixed-address
+ * storage. Unfortunately, the IJG library isn't smart enough to cope
+ * with relocatable storage.
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ DisposePtr((Ptr) object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: we include FAR keywords in the routine declarations simply for
+ * consistency with the rest of the IJG code; FAR should expand to empty
+ * on rational architectures like the Mac.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ DisposePtr((Ptr) object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ long limit = cinfo->mem->max_memory_to_use - already_allocated;
+ long slop, mem;
+
+ /* Don't ask for more than what application has told us we may use */
+ if (max_bytes_needed > limit && limit > 0)
+ max_bytes_needed = limit;
+ /* Find whether there's a big enough free block in the heap.
+ * CompactMem tries to create a contiguous block of the requested size,
+ * and then returns the size of the largest free block (which could be
+ * much more or much less than we asked for).
+ * We add some slop to ensure we don't use up all available memory.
+ */
+ slop = max_bytes_needed / 16 + 32768L;
+ mem = CompactMem(max_bytes_needed + slop) - slop;
+ if (mem < 0)
+ mem = 0; /* sigh, couldn't even get the slop */
+ /* Don't take more than the application says we can have */
+ if (mem > limit && limit > 0)
+ mem = limit;
+ return mem;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFREAD(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFWRITE(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ fclose(info->temp_file);
+ /* Since this implementation uses tmpfile() to create the file,
+ * no explicit file deletion is needed.
+ */
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses tmpfile(), which constructs a suitable file name
+ * behind the scenes. We don't have to use info->temp_name[] at all;
+ * indeed, we can't even find out the actual name of the temp file.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ if ((info->temp_file = tmpfile()) == NULL)
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ /* max_memory_to_use will be initialized to FreeMem()'s result;
+ * the calling application might later reduce it, for example
+ * to leave room to invoke multiple JPEG objects.
+ * Note that FreeMem returns the total number of free bytes;
+ * it may not be possible to allocate a single block of this size.
+ */
+ return FreeMem();
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/gs/jpeg/jmemmgr.c b/gs/jpeg/jmemmgr.c
new file mode 100644
index 000000000..5ea19ce14
--- /dev/null
+++ b/gs/jpeg/jmemmgr.c
@@ -0,0 +1,1115 @@
+/*
+ * jmemmgr.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the JPEG system-independent memory management
+ * routines. This code is usable across a wide variety of machines; most
+ * of the system dependencies have been isolated in a separate file.
+ * The major functions provided here are:
+ * * pool-based allocation and freeing of memory;
+ * * policy decisions about how to divide available memory among the
+ * virtual arrays;
+ * * control logic for swapping virtual arrays between main memory and
+ * backing storage.
+ * The separate system-dependent file provides the actual backing-storage
+ * access code, and it contains the policy decision about how much total
+ * main memory to use.
+ * This file is system-dependent in the sense that some of its functions
+ * are unnecessary in some systems. For example, if there is enough virtual
+ * memory so that backing storage will never be used, much of the virtual
+ * array control logic could be removed. (Of course, if you have that much
+ * memory then you shouldn't care about a little bit of unused code...)
+ */
+
+#define JPEG_INTERNALS
+#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef NO_GETENV
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */
+extern char * getenv JPP((const char * name));
+#endif
+#endif
+
+
+/*
+ * Some important notes:
+ * The allocation routines provided here must never return NULL.
+ * They should exit to error_exit if unsuccessful.
+ *
+ * It's not a good idea to try to merge the sarray and barray routines,
+ * even though they are textually almost the same, because samples are
+ * usually stored as bytes while coefficients are shorts or ints. Thus,
+ * in machines where byte pointers have a different representation from
+ * word pointers, the resulting machine code could not be the same.
+ */
+
+
+/*
+ * Many machines require storage alignment: longs must start on 4-byte
+ * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
+ * always returns pointers that are multiples of the worst-case alignment
+ * requirement, and we had better do so too.
+ * There isn't any really portable way to determine the worst-case alignment
+ * requirement. This module assumes that the alignment requirement is
+ * multiples of sizeof(ALIGN_TYPE).
+ * By default, we define ALIGN_TYPE as double. This is necessary on some
+ * workstations (where doubles really do need 8-byte alignment) and will work
+ * fine on nearly everything. If your machine has lesser alignment needs,
+ * you can save a few bytes by making ALIGN_TYPE smaller.
+ * The only place I know of where this will NOT work is certain Macintosh
+ * 680x0 compilers that define double as a 10-byte IEEE extended float.
+ * Doing 10-byte alignment is counterproductive because longwords won't be
+ * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
+ * such a compiler.
+ */
+
+#ifndef ALIGN_TYPE /* so can override from jconfig.h */
+#define ALIGN_TYPE double
+#endif
+
+
+/*
+ * We allocate objects from "pools", where each pool is gotten with a single
+ * request to jpeg_get_small() or jpeg_get_large(). There is no per-object
+ * overhead within a pool, except for alignment padding. Each pool has a
+ * header with a link to the next pool of the same class.
+ * Small and large pool headers are identical except that the latter's
+ * link pointer must be FAR on 80x86 machines.
+ * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
+ * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
+ * of the alignment requirement of ALIGN_TYPE.
+ */
+
+typedef union small_pool_struct * small_pool_ptr;
+
+typedef union small_pool_struct {
+ struct {
+ small_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} small_pool_hdr;
+
+typedef union large_pool_struct FAR * large_pool_ptr;
+
+typedef union large_pool_struct {
+ struct {
+ large_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} large_pool_hdr;
+
+
+/*
+ * Here is the full definition of a memory manager object.
+ */
+
+typedef struct {
+ struct jpeg_memory_mgr pub; /* public fields */
+
+ /* Each pool identifier (lifetime class) names a linked list of pools. */
+ small_pool_ptr small_list[JPOOL_NUMPOOLS];
+ large_pool_ptr large_list[JPOOL_NUMPOOLS];
+
+ /* Since we only have one lifetime class of virtual arrays, only one
+ * linked list is necessary (for each datatype). Note that the virtual
+ * array control blocks being linked together are actually stored somewhere
+ * in the small-pool list.
+ */
+ jvirt_sarray_ptr virt_sarray_list;
+ jvirt_barray_ptr virt_barray_list;
+
+ /* This counts total space obtained from jpeg_get_small/large */
+ long total_space_allocated;
+
+ /* alloc_sarray and alloc_barray set this value for use by virtual
+ * array routines.
+ */
+ JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
+} my_memory_mgr;
+
+typedef my_memory_mgr * my_mem_ptr;
+
+
+/*
+ * The control blocks for virtual arrays.
+ * Note that these blocks are allocated in the "small" pool area.
+ * System-dependent info for the associated backing store (if any) is hidden
+ * inside the backing_store_info struct.
+ */
+
+struct jvirt_sarray_control {
+ JSAMPARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_sarray_ptr next; /* link to next virtual sarray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+struct jvirt_barray_control {
+ JBLOCKARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION blocksperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_barray_ptr next; /* link to next virtual barray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+
+#ifdef MEM_STATS /* optional extra stuff for statistics */
+
+LOCAL(void)
+print_mem_stats (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+
+ /* Since this is only a debugging stub, we can cheat a little by using
+ * fprintf directly rather than going through the trace message code.
+ * This is helpful because message parm array can't handle longs.
+ */
+ fprintf(stderr, "Freeing pool %d, total space = %ld\n",
+ pool_id, mem->total_space_allocated);
+
+ for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
+ lhdr_ptr = lhdr_ptr->hdr.next) {
+ fprintf(stderr, " Large chunk used %ld\n",
+ (long) lhdr_ptr->hdr.bytes_used);
+ }
+
+ for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
+ shdr_ptr = shdr_ptr->hdr.next) {
+ fprintf(stderr, " Small chunk used %ld free %ld\n",
+ (long) shdr_ptr->hdr.bytes_used,
+ (long) shdr_ptr->hdr.bytes_left);
+ }
+}
+
+#endif /* MEM_STATS */
+
+
+LOCAL(void)
+out_of_memory (j_common_ptr cinfo, int which)
+/* Report an out-of-memory error and stop execution */
+/* If we compiled MEM_STATS support, report alloc requests before dying */
+{
+#ifdef MEM_STATS
+ cinfo->err->trace_level = 2; /* force self_destruct to report stats */
+#endif
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
+}
+
+
+/*
+ * Allocation of "small" objects.
+ *
+ * For these, we use pooled storage. When a new pool must be created,
+ * we try to get enough space for the current request plus a "slop" factor,
+ * where the slop will be the amount of leftover space in the new pool.
+ * The speed vs. space tradeoff is largely determined by the slop values.
+ * A different slop value is provided for each pool class (lifetime),
+ * and we also distinguish the first pool of a class from later ones.
+ * NOTE: the values given work fairly well on both 16- and 32-bit-int
+ * machines, but may be too small if longs are 64 bits or more.
+ */
+
+static const size_t first_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 1600, /* first PERMANENT pool */
+ 16000 /* first IMAGE pool */
+};
+
+static const size_t extra_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 0, /* additional PERMANENT pools */
+ 5000 /* additional IMAGE pools */
+};
+
+#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */
+
+
+METHODDEF(void *)
+alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "small" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr hdr_ptr, prev_hdr_ptr;
+ char * data_ptr;
+ size_t odd_bytes, min_request, slop;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
+ out_of_memory(cinfo, 1); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* See if space is available in any existing pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+ prev_hdr_ptr = NULL;
+ hdr_ptr = mem->small_list[pool_id];
+ while (hdr_ptr != NULL) {
+ if (hdr_ptr->hdr.bytes_left >= sizeofobject)
+ break; /* found pool with enough space */
+ prev_hdr_ptr = hdr_ptr;
+ hdr_ptr = hdr_ptr->hdr.next;
+ }
+
+ /* Time to make a new pool? */
+ if (hdr_ptr == NULL) {
+ /* min_request is what we need now, slop is what will be leftover */
+ min_request = sizeofobject + SIZEOF(small_pool_hdr);
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ slop = first_pool_slop[pool_id];
+ else
+ slop = extra_pool_slop[pool_id];
+ /* Don't ask for more than MAX_ALLOC_CHUNK */
+ if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
+ slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
+ /* Try to get space, if fail reduce slop and try again */
+ for (;;) {
+ hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
+ if (hdr_ptr != NULL)
+ break;
+ slop /= 2;
+ if (slop < MIN_SLOP) /* give up when it gets real small */
+ out_of_memory(cinfo, 2); /* jpeg_get_small failed */
+ }
+ mem->total_space_allocated += min_request + slop;
+ /* Success, initialize the new pool header and add to end of list */
+ hdr_ptr->hdr.next = NULL;
+ hdr_ptr->hdr.bytes_used = 0;
+ hdr_ptr->hdr.bytes_left = sizeofobject + slop;
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ mem->small_list[pool_id] = hdr_ptr;
+ else
+ prev_hdr_ptr->hdr.next = hdr_ptr;
+ }
+
+ /* OK, allocate the object from the current pool */
+ data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
+ data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
+ hdr_ptr->hdr.bytes_used += sizeofobject;
+ hdr_ptr->hdr.bytes_left -= sizeofobject;
+
+ return (void *) data_ptr;
+}
+
+
+/*
+ * Allocation of "large" objects.
+ *
+ * The external semantics of these are the same as "small" objects,
+ * except that FAR pointers are used on 80x86. However the pool
+ * management heuristics are quite different. We assume that each
+ * request is large enough that it may as well be passed directly to
+ * jpeg_get_large; the pool management just links everything together
+ * so that we can free it all on demand.
+ * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
+ * structures. The routines that create these structures (see below)
+ * deliberately bunch rows together to ensure a large request size.
+ */
+
+METHODDEF(void FAR *)
+alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "large" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ large_pool_ptr hdr_ptr;
+ size_t odd_bytes;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
+ out_of_memory(cinfo, 3); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* Always make a new pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
+ SIZEOF(large_pool_hdr));
+ if (hdr_ptr == NULL)
+ out_of_memory(cinfo, 4); /* jpeg_get_large failed */
+ mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
+
+ /* Success, initialize the new pool header and add to list */
+ hdr_ptr->hdr.next = mem->large_list[pool_id];
+ /* We maintain space counts in each pool header for statistical purposes,
+ * even though they are not needed for allocation.
+ */
+ hdr_ptr->hdr.bytes_used = sizeofobject;
+ hdr_ptr->hdr.bytes_left = 0;
+ mem->large_list[pool_id] = hdr_ptr;
+
+ return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
+}
+
+
+/*
+ * Creation of 2-D sample arrays.
+ * The pointers are in near heap, the samples themselves in FAR heap.
+ *
+ * To minimize allocation overhead and to allow I/O of large contiguous
+ * blocks, we allocate the sample rows in groups of as many rows as possible
+ * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
+ * NB: the virtual array control routines, later in this file, know about
+ * this chunking of rows. The rowsperchunk value is left in the mem manager
+ * object so that it can be saved away if this sarray is the workspace for
+ * a virtual array.
+ */
+
+METHODDEF(JSAMPARRAY)
+alloc_sarray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow, JDIMENSION numrows)
+/* Allocate a 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JSAMPARRAY result;
+ JSAMPROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) samplesperrow * SIZEOF(JSAMPLE));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JSAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
+ * SIZEOF(JSAMPLE)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += samplesperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Creation of 2-D coefficient-block arrays.
+ * This is essentially the same as the code for sample arrays, above.
+ */
+
+METHODDEF(JBLOCKARRAY)
+alloc_barray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow, JDIMENSION numrows)
+/* Allocate a 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JBLOCKARRAY result;
+ JBLOCKROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) blocksperrow * SIZEOF(JBLOCK));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JBLOCKROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
+ * SIZEOF(JBLOCK)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += blocksperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * About virtual array management:
+ *
+ * The above "normal" array routines are only used to allocate strip buffers
+ * (as wide as the image, but just a few rows high). Full-image-sized buffers
+ * are handled as "virtual" arrays. The array is still accessed a strip at a
+ * time, but the memory manager must save the whole array for repeated
+ * accesses. The intended implementation is that there is a strip buffer in
+ * memory (as high as is possible given the desired memory limit), plus a
+ * backing file that holds the rest of the array.
+ *
+ * The request_virt_array routines are told the total size of the image and
+ * the maximum number of rows that will be accessed at once. The in-memory
+ * buffer must be at least as large as the maxaccess value.
+ *
+ * The request routines create control blocks but not the in-memory buffers.
+ * That is postponed until realize_virt_arrays is called. At that time the
+ * total amount of space needed is known (approximately, anyway), so free
+ * memory can be divided up fairly.
+ *
+ * The access_virt_array routines are responsible for making a specific strip
+ * area accessible (after reading or writing the backing file, if necessary).
+ * Note that the access routines are told whether the caller intends to modify
+ * the accessed strip; during a read-only pass this saves having to rewrite
+ * data to disk. The access routines are also responsible for pre-zeroing
+ * any newly accessed rows, if pre-zeroing was requested.
+ *
+ * In current usage, the access requests are usually for nonoverlapping
+ * strips; that is, successive access start_row numbers differ by exactly
+ * num_rows = maxaccess. This means we can get good performance with simple
+ * buffer dump/reload logic, by making the in-memory buffer be a multiple
+ * of the access height; then there will never be accesses across bufferload
+ * boundaries. The code will still work with overlapping access requests,
+ * but it doesn't handle bufferload overlaps very efficiently.
+ */
+
+
+METHODDEF(jvirt_sarray_ptr)
+request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION samplesperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_sarray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_sarray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->samplesperrow = samplesperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
+ mem->virt_sarray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(jvirt_barray_ptr)
+request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION blocksperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_barray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_barray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->blocksperrow = blocksperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_barray_list; /* add to list of virtual arrays */
+ mem->virt_barray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(void)
+realize_virt_arrays (j_common_ptr cinfo)
+/* Allocate the in-memory buffers for any unrealized virtual arrays */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ long space_per_minheight, maximum_space, avail_mem;
+ long minheights, max_minheights;
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ /* Compute the minimum space needed (maxaccess rows in each buffer)
+ * and the maximum space needed (full image height in each buffer).
+ * These may be of use to the system-dependent jpeg_mem_available routine.
+ */
+ space_per_minheight = 0;
+ maximum_space = 0;
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) sptr->maxaccess *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ maximum_space += (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ }
+ }
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) bptr->maxaccess *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ maximum_space += (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ }
+ }
+
+ if (space_per_minheight <= 0)
+ return; /* no unrealized arrays, no work */
+
+ /* Determine amount of memory to actually use; this is system-dependent. */
+ avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
+ mem->total_space_allocated);
+
+ /* If the maximum space needed is available, make all the buffers full
+ * height; otherwise parcel it out with the same number of minheights
+ * in each buffer.
+ */
+ if (avail_mem >= maximum_space)
+ max_minheights = 1000000000L;
+ else {
+ max_minheights = avail_mem / space_per_minheight;
+ /* If there doesn't seem to be enough space, try to get the minimum
+ * anyway. This allows a "stub" implementation of jpeg_mem_available().
+ */
+ if (max_minheights <= 0)
+ max_minheights = 1;
+ }
+
+ /* Allocate the in-memory buffers and initialize backing store as needed. */
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ sptr->rows_in_mem = sptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & sptr->b_s_info,
+ (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow *
+ (long) SIZEOF(JSAMPLE));
+ sptr->b_s_open = TRUE;
+ }
+ sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
+ sptr->samplesperrow, sptr->rows_in_mem);
+ sptr->rowsperchunk = mem->last_rowsperchunk;
+ sptr->cur_start_row = 0;
+ sptr->first_undef_row = 0;
+ sptr->dirty = FALSE;
+ }
+ }
+
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ bptr->rows_in_mem = bptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & bptr->b_s_info,
+ (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow *
+ (long) SIZEOF(JBLOCK));
+ bptr->b_s_open = TRUE;
+ }
+ bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
+ bptr->blocksperrow, bptr->rows_in_mem);
+ bptr->rowsperchunk = mem->last_rowsperchunk;
+ bptr->cur_start_row = 0;
+ bptr->first_undef_row = 0;
+ bptr->dirty = FALSE;
+ }
+ }
+}
+
+
+LOCAL(void)
+do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual sample array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+LOCAL(void)
+do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual coefficient-block array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+METHODDEF(JSAMPARRAY)
+access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual sample array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_sarray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_sarray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+METHODDEF(JBLOCKARRAY)
+access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual block array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_barray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_barray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+/*
+ * Release all objects belonging to a specified pool.
+ */
+
+METHODDEF(void)
+free_pool (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+ size_t space_freed;
+
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+#ifdef MEM_STATS
+ if (cinfo->err->trace_level > 1)
+ print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
+#endif
+
+ /* If freeing IMAGE pool, close any virtual arrays first */
+ if (pool_id == JPOOL_IMAGE) {
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->b_s_open) { /* there may be no backing store */
+ sptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
+ }
+ }
+ mem->virt_sarray_list = NULL;
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->b_s_open) { /* there may be no backing store */
+ bptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
+ }
+ }
+ mem->virt_barray_list = NULL;
+ }
+
+ /* Release large objects */
+ lhdr_ptr = mem->large_list[pool_id];
+ mem->large_list[pool_id] = NULL;
+
+ while (lhdr_ptr != NULL) {
+ large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
+ space_freed = lhdr_ptr->hdr.bytes_used +
+ lhdr_ptr->hdr.bytes_left +
+ SIZEOF(large_pool_hdr);
+ jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ lhdr_ptr = next_lhdr_ptr;
+ }
+
+ /* Release small objects */
+ shdr_ptr = mem->small_list[pool_id];
+ mem->small_list[pool_id] = NULL;
+
+ while (shdr_ptr != NULL) {
+ small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
+ space_freed = shdr_ptr->hdr.bytes_used +
+ shdr_ptr->hdr.bytes_left +
+ SIZEOF(small_pool_hdr);
+ jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ shdr_ptr = next_shdr_ptr;
+ }
+}
+
+
+/*
+ * Close up shop entirely.
+ * Note that this cannot be called unless cinfo->mem is non-NULL.
+ */
+
+METHODDEF(void)
+self_destruct (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Close all backing store, release all memory.
+ * Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ free_pool(cinfo, pool);
+ }
+
+ /* Release the memory manager control block too. */
+ jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
+ cinfo->mem = NULL; /* ensures I will be called only once */
+
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+}
+
+
+/*
+ * Memory manager initialization.
+ * When this is called, only the error manager pointer is valid in cinfo!
+ */
+
+GLOBAL(void)
+jinit_memory_mgr (j_common_ptr cinfo)
+{
+ my_mem_ptr mem;
+ long max_to_use;
+ int pool;
+ size_t test_mac;
+
+ cinfo->mem = NULL; /* for safety if init fails */
+
+ /* Check for configuration errors.
+ * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
+ * doesn't reflect any real hardware alignment requirement.
+ * The test is a little tricky: for X>0, X and X-1 have no one-bits
+ * in common if and only if X is a power of 2, ie has only one one-bit.
+ * Some compilers may give an "unreachable code" warning here; ignore it.
+ */
+ if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
+ /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
+ * a multiple of SIZEOF(ALIGN_TYPE).
+ * Again, an "unreachable code" warning may be ignored here.
+ * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
+ */
+ test_mac = (size_t) MAX_ALLOC_CHUNK;
+ if ((long) test_mac != MAX_ALLOC_CHUNK ||
+ (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+
+ max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
+
+ /* Attempt to allocate memory manager's control block */
+ mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
+
+ if (mem == NULL) {
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+ }
+
+ /* OK, fill in the method pointers */
+ mem->pub.alloc_small = alloc_small;
+ mem->pub.alloc_large = alloc_large;
+ mem->pub.alloc_sarray = alloc_sarray;
+ mem->pub.alloc_barray = alloc_barray;
+ mem->pub.request_virt_sarray = request_virt_sarray;
+ mem->pub.request_virt_barray = request_virt_barray;
+ mem->pub.realize_virt_arrays = realize_virt_arrays;
+ mem->pub.access_virt_sarray = access_virt_sarray;
+ mem->pub.access_virt_barray = access_virt_barray;
+ mem->pub.free_pool = free_pool;
+ mem->pub.self_destruct = self_destruct;
+
+ /* Initialize working state */
+ mem->pub.max_memory_to_use = max_to_use;
+
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ mem->small_list[pool] = NULL;
+ mem->large_list[pool] = NULL;
+ }
+ mem->virt_sarray_list = NULL;
+ mem->virt_barray_list = NULL;
+
+ mem->total_space_allocated = SIZEOF(my_memory_mgr);
+
+ /* Declare ourselves open for business */
+ cinfo->mem = & mem->pub;
+
+ /* Check for an environment variable JPEGMEM; if found, override the
+ * default max_memory setting from jpeg_mem_init. Note that the
+ * surrounding application may again override this value.
+ * If your system doesn't support getenv(), define NO_GETENV to disable
+ * this feature.
+ */
+#ifndef NO_GETENV
+ { char * memenv;
+
+ if ((memenv = getenv("JPEGMEM")) != NULL) {
+ char ch = 'x';
+
+ if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
+ if (ch == 'm' || ch == 'M')
+ max_to_use *= 1000L;
+ mem->pub.max_memory_to_use = max_to_use * 1000L;
+ }
+ }
+ }
+#endif
+
+}
diff --git a/gs/jpeg/jmemname.c b/gs/jpeg/jmemname.c
new file mode 100644
index 000000000..d1b57e9ef
--- /dev/null
+++ b/gs/jpeg/jmemname.c
@@ -0,0 +1,271 @@
+/*
+ * jmemname.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a generic implementation of the system-dependent
+ * portion of the JPEG memory manager. This implementation assumes that
+ * you must explicitly construct a name for each temp file.
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
+#define SEEK_SET 0 /* if not, assume 0 is correct */
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define RW_BINARY "w+"
+#else
+#define READ_BINARY "rb"
+#define RW_BINARY "w+b"
+#endif
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is system-dependent!
+ *
+ * The code as given is suitable for most Unix systems, and it is easily
+ * modified for most non-Unix systems. Some notes:
+ * 1. The temp file is created in the directory named by TEMP_DIRECTORY.
+ * The default value is /usr/tmp, which is the conventional place for
+ * creating large temp files on Unix. On other systems you'll probably
+ * want to change the file location. You can do this by editing the
+ * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.
+ *
+ * 2. If you need to change the file name as well as its location,
+ * you can override the TEMP_FILE_NAME macro. (Note that this is
+ * actually a printf format string; it must contain %s and %d.)
+ * Few people should need to do this.
+ *
+ * 3. mktemp() is used to ensure that multiple processes running
+ * simultaneously won't select the same file names. If your system
+ * doesn't have mktemp(), define NO_MKTEMP to do it the hard way.
+ * (If you don't have <errno.h>, also define NO_ERRNO_H.)
+ *
+ * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c
+ * will cause the temp files to be removed if you stop the program early.
+ */
+
+#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */
+#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */
+#endif
+
+static int next_file_num; /* to distinguish among several temp files */
+
+#ifdef NO_MKTEMP
+
+#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME "%sJPG%03d.TMP"
+#endif
+
+#ifndef NO_ERRNO_H
+#include <errno.h> /* to define ENOENT */
+#endif
+
+/* ANSI C specifies that errno is a macro, but on older systems it's more
+ * likely to be a plain int variable. And not all versions of errno.h
+ * bother to declare it, so we have to in order to be most portable. Thus:
+ */
+#ifndef errno
+extern int errno;
+#endif
+
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ FILE * tfile;
+
+ /* Keep generating file names till we find one that's not in use */
+ for (;;) {
+ next_file_num++; /* advance counter */
+ sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+ if ((tfile = fopen(fname, READ_BINARY)) == NULL) {
+ /* fopen could have failed for a reason other than the file not
+ * being there; for example, file there but unreadable.
+ * If <errno.h> isn't available, then we cannot test the cause.
+ */
+#ifdef ENOENT
+ if (errno != ENOENT)
+ continue;
+#endif
+ break;
+ }
+ fclose(tfile); /* oops, it's there; close tfile & try again */
+ }
+}
+
+#else /* ! NO_MKTEMP */
+
+/* Note that mktemp() requires the initial filename to end in six X's */
+#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME "%sJPG%dXXXXXX"
+#endif
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ next_file_num++; /* advance counter */
+ sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+ mktemp(fname); /* make sure file name is unique */
+ /* mktemp replaces the trailing XXXXXX with a unique string of characters */
+}
+
+#endif /* NO_MKTEMP */
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFREAD(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFWRITE(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ fclose(info->temp_file); /* close the file */
+ unlink(info->temp_name); /* delete the file */
+/* If your system doesn't have unlink(), use remove() instead.
+ * remove() is the ANSI-standard name for this function, but if
+ * your system was ANSI you'd be using jmemansi.c, right?
+ */
+ TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ select_file_name(info->temp_name);
+ if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+ TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ next_file_num = 0; /* initialize temp file name generator */
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/gs/jpeg/jmemnobs.c b/gs/jpeg/jmemnobs.c
new file mode 100644
index 000000000..eb8c33772
--- /dev/null
+++ b/gs/jpeg/jmemnobs.c
@@ -0,0 +1,109 @@
+/*
+ * jmemnobs.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a really simple implementation of the system-
+ * dependent portion of the JPEG memory manager. This implementation
+ * assumes that no backing-store files are needed: all required space
+ * can be obtained from malloc().
+ * This is very portable in the sense that it'll compile on almost anything,
+ * but you'd better have lots of main memory (or virtual memory) if you want
+ * to process big images.
+ * Note that the max_memory_to_use option is ignored by this implementation.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * Here we always say, "we got all you want bud!"
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return max_bytes_needed;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Since jpeg_mem_available always promised the moon,
+ * this should never be called and we can just error out.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. Here, there isn't any.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return 0; /* just set max_memory_to_use to 0 */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/gs/jpeg/jmemsys.h b/gs/jpeg/jmemsys.h
new file mode 100644
index 000000000..6d4c7f2ae
--- /dev/null
+++ b/gs/jpeg/jmemsys.h
@@ -0,0 +1,183 @@
+/*
+ * jmemsys.h
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file defines the interface between the system-independent
+ * and system-dependent portions of the JPEG memory manager. No other
+ * modules need include it. (The system-independent portion is jmemmgr.c;
+ * there are several different versions of the system-dependent portion.)
+ *
+ * This file works as-is for the system-dependent memory managers supplied
+ * in the IJG distribution. You may need to modify it if you write a
+ * custom memory manager. If system-dependent changes are needed in
+ * this file, the best method is to #ifdef them based on a configuration
+ * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR.
+ */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_get_small jGetSmall
+#define jpeg_free_small jFreeSmall
+#define jpeg_get_large jGetLarge
+#define jpeg_free_large jFreeLarge
+#define jpeg_mem_available jMemAvail
+#define jpeg_open_backing_store jOpenBackStore
+#define jpeg_mem_init jMemInit
+#define jpeg_mem_term jMemTerm
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * These two functions are used to allocate and release small chunks of
+ * memory. (Typically the total amount requested through jpeg_get_small is
+ * no more than 20K or so; this will be requested in chunks of a few K each.)
+ * Behavior should be the same as for the standard library functions malloc
+ * and free; in particular, jpeg_get_small must return NULL on failure.
+ * On most systems, these ARE malloc and free. jpeg_free_small is passed the
+ * size of the object being freed, just in case it's needed.
+ * On an 80x86 machine using small-data memory model, these manage near heap.
+ */
+
+EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
+EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,
+ size_t sizeofobject));
+
+/*
+ * These two functions are used to allocate and release large chunks of
+ * memory (up to the total free space designated by jpeg_mem_available).
+ * The interface is the same as above, except that on an 80x86 machine,
+ * far pointers are used. On most other machines these are identical to
+ * the jpeg_get/free_small routines; but we keep them separate anyway,
+ * in case a different allocation strategy is desirable for large chunks.
+ */
+
+EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,
+ size_t sizeofobject));
+EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
+ size_t sizeofobject));
+
+/*
+ * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
+ * be requested in a single call to jpeg_get_large (and jpeg_get_small for that
+ * matter, but that case should never come into play). This macro is needed
+ * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
+ * On those machines, we expect that jconfig.h will provide a proper value.
+ * On machines with 32-bit flat address spaces, any large constant may be used.
+ *
+ * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
+ * size_t and will be a multiple of sizeof(align_type).
+ */
+
+#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */
+#define MAX_ALLOC_CHUNK 1000000000L
+#endif
+
+/*
+ * This routine computes the total space still available for allocation by
+ * jpeg_get_large. If more space than this is needed, backing store will be
+ * used. NOTE: any memory already allocated must not be counted.
+ *
+ * There is a minimum space requirement, corresponding to the minimum
+ * feasible buffer sizes; jmemmgr.c will request that much space even if
+ * jpeg_mem_available returns zero. The maximum space needed, enough to hold
+ * all working storage in memory, is also passed in case it is useful.
+ * Finally, the total space already allocated is passed. If no better
+ * method is available, cinfo->mem->max_memory_to_use - already_allocated
+ * is often a suitable calculation.
+ *
+ * It is OK for jpeg_mem_available to underestimate the space available
+ * (that'll just lead to more backing-store access than is really necessary).
+ * However, an overestimate will lead to failure. Hence it's wise to subtract
+ * a slop factor from the true available space. 5% should be enough.
+ *
+ * On machines with lots of virtual memory, any large constant may be returned.
+ * Conversely, zero may be returned to always use the minimum amount of memory.
+ */
+
+EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,
+ long min_bytes_needed,
+ long max_bytes_needed,
+ long already_allocated));
+
+
+/*
+ * This structure holds whatever state is needed to access a single
+ * backing-store object. The read/write/close method pointers are called
+ * by jmemmgr.c to manipulate the backing-store object; all other fields
+ * are private to the system-dependent backing store routines.
+ */
+
+#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
+
+#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
+
+typedef unsigned short XMSH; /* type of extended-memory handles */
+typedef unsigned short EMSH; /* type of expanded-memory handles */
+
+typedef union {
+ short file_handle; /* DOS file handle if it's a temp file */
+ XMSH xms_handle; /* handle if it's a chunk of XMS */
+ EMSH ems_handle; /* handle if it's a chunk of EMS */
+} handle_union;
+
+#endif /* USE_MSDOS_MEMMGR */
+
+typedef struct backing_store_struct * backing_store_ptr;
+
+typedef struct backing_store_struct {
+ /* Methods for reading/writing/closing this backing-store object */
+ JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info));
+
+ /* Private fields for system-dependent backing-store management */
+#ifdef USE_MSDOS_MEMMGR
+ /* For the MS-DOS manager (jmemdos.c), we need: */
+ handle_union handle; /* reference to backing-store storage object */
+ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+ /* For a typical implementation with temp files, we need: */
+ FILE * temp_file; /* stdio reference to temp file */
+ char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
+#endif
+} backing_store_info;
+
+/*
+ * Initial opening of a backing-store object. This must fill in the
+ * read/write/close pointers in the object. The read/write routines
+ * may take an error exit if the specified maximum file size is exceeded.
+ * (If jpeg_mem_available always returns a large value, this routine can
+ * just take an error exit.)
+ */
+
+EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,
+ backing_store_ptr info,
+ long total_bytes_needed));
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. jpeg_mem_init will be called before anything is
+ * allocated (and, therefore, nothing in cinfo is of use except the error
+ * manager pointer). It should return a suitable default value for
+ * max_memory_to_use; this may subsequently be overridden by the surrounding
+ * application. (Note that max_memory_to_use is only important if
+ * jpeg_mem_available chooses to consult it ... no one else will.)
+ * jpeg_mem_term may assume that all requested memory has been freed and that
+ * all opened backing-store objects have been closed.
+ */
+
+EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));
diff --git a/gs/jpeg/jmorecfg.h b/gs/jpeg/jmorecfg.h
new file mode 100644
index 000000000..e43651b14
--- /dev/null
+++ b/gs/jpeg/jmorecfg.h
@@ -0,0 +1,362 @@
+/*
+ * jmorecfg.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains additional configuration options that customize the
+ * JPEG software for special applications or support machine-dependent
+ * optimizations. Most users will not need to touch this file.
+ */
+
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ * We do not support run-time selection of data precision, sorry.
+ */
+
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+
+
+/*
+ * Maximum number of components (color channels) allowed in JPEG image.
+ * To meet the letter of the JPEG spec, set this to 255. However, darn
+ * few applications need more than 4 channels (maybe 5 for CMYK + alpha
+ * mask). We recommend 10 as a reasonable compromise; use 4 if you are
+ * really short on memory. (Each allowed component costs a hundred or so
+ * bytes of storage, whether actually used in an image or not.)
+ */
+
+#define MAX_COMPONENTS 10 /* maximum number of image components */
+
+
+/*
+ * Basic data types.
+ * You may need to change these if you have a machine with unusual data
+ * type sizes; for example, "char" not 8 bits, "short" not 16 bits,
+ * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits,
+ * but it had better be at least 16.
+ */
+
+/* Representation of a single sample (pixel element value).
+ * We frequently allocate large arrays of these, so it's important to keep
+ * them small. But if you have memory to burn and access to char or short
+ * arrays is very slow on your hardware, you might want to change these.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+/* JSAMPLE should be the smallest type that will hold the values 0..255.
+ * You can use a signed char by having GETJSAMPLE mask it with 0xFF.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JSAMPLE;
+#define GETJSAMPLE(value) ((int) (value))
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JSAMPLE;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJSAMPLE(value) ((int) (value))
+#else
+#define GETJSAMPLE(value) ((int) (value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+#define MAXJSAMPLE 255
+#define CENTERJSAMPLE 128
+
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE == 12
+/* JSAMPLE should be the smallest type that will hold the values 0..4095.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value) ((int) (value))
+
+#define MAXJSAMPLE 4095
+#define CENTERJSAMPLE 2048
+
+#endif /* BITS_IN_JSAMPLE == 12 */
+
+
+/* Representation of a DCT frequency coefficient.
+ * This should be a signed value of at least 16 bits; "short" is usually OK.
+ * Again, we allocate large arrays of these, but you can change to int
+ * if you have memory to burn and "short" is really slow.
+ */
+
+typedef short JCOEF;
+
+
+/* Compressed datastreams are represented as arrays of JOCTET.
+ * These must be EXACTLY 8 bits wide, at least once they are written to
+ * external storage. Note that when using the stdio data source/destination
+ * managers, this is also the data type passed to fread/fwrite.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JOCTET;
+#define GETJOCTET(value) (value)
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JOCTET;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJOCTET(value) (value)
+#else
+#define GETJOCTET(value) ((value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+/* These typedefs are used for various table entries and so forth.
+ * They must be at least as wide as specified; but making them too big
+ * won't cost a huge amount of memory, so we don't provide special
+ * extraction code like we did for JSAMPLE. (In other words, these
+ * typedefs live at a different point on the speed/space tradeoff curve.)
+ */
+
+/* UINT8 must hold at least the values 0..255. */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char UINT8;
+#else /* not HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char UINT8;
+#else /* not CHAR_IS_UNSIGNED */
+typedef short UINT8;
+#endif /* CHAR_IS_UNSIGNED */
+#endif /* HAVE_UNSIGNED_CHAR */
+
+/* UINT16 must hold at least the values 0..65535. */
+
+#ifdef HAVE_UNSIGNED_SHORT
+typedef unsigned short UINT16;
+#else /* not HAVE_UNSIGNED_SHORT */
+typedef unsigned int UINT16;
+#endif /* HAVE_UNSIGNED_SHORT */
+
+/* INT16 must hold at least the values -32768..32767. */
+
+#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */
+typedef short INT16;
+#endif
+
+/* INT32 must hold at least signed 32-bit values. */
+
+#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
+typedef long INT32;
+#endif
+
+/* Datatype used for image dimensions. The JPEG standard only supports
+ * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore
+ * "unsigned int" is sufficient on all machines. However, if you need to
+ * handle larger images and you don't mind deviating from the spec, you
+ * can change this datatype.
+ */
+
+typedef unsigned int JDIMENSION;
+
+#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */
+
+
+/* These macros are used in all function definitions and extern declarations.
+ * You could modify them if you need to change function linkage conventions;
+ * in particular, you'll need to do that to make the library a Windows DLL.
+ * Another application is to make all functions global for use with debuggers
+ * or code profilers that require it.
+ */
+
+/* a function called through method pointers: */
+#define METHODDEF(type) static type
+/* a function used only in its module: */
+#define LOCAL(type) static type
+/* a function referenced thru EXTERNs: */
+#define GLOBAL(type) type
+/* a reference to a GLOBAL function: */
+#define EXTERN(type) extern type
+
+
+/* This macro is used to declare a "method", that is, a function pointer.
+ * We want to supply prototype parameters if the compiler can cope.
+ * Note that the arglist parameter must be parenthesized!
+ * Again, you can customize this if you need special linkage keywords.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JMETHOD(type,methodname,arglist) type (*methodname) arglist
+#else
+#define JMETHOD(type,methodname,arglist) type (*methodname) ()
+#endif
+
+
+/* Here is the pseudo-keyword for declaring pointers that must be "far"
+ * on 80x86 machines. Most of the specialized coding for 80x86 is handled
+ * by just saying "FAR *" where such a pointer is needed. In a few places
+ * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.
+ */
+
+#ifdef NEED_FAR_POINTERS
+#define FAR far
+#else
+#define FAR
+#endif
+
+
+/*
+ * On a few systems, type boolean and/or its values FALSE, TRUE may appear
+ * in standard header files. Or you may have conflicts with application-
+ * specific header files that you want to include together with these files.
+ * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
+ */
+
+#ifndef HAVE_BOOLEAN
+typedef int boolean;
+#endif
+#ifndef FALSE /* in case these macros already exist */
+#define FALSE 0 /* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+/*
+ * The remaining options affect code selection within the JPEG library,
+ * but they don't need to be visible to most applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+#define JPEG_INTERNAL_OPTIONS
+#endif
+
+#ifdef JPEG_INTERNAL_OPTIONS
+
+
+/*
+ * These defines indicate whether to include various optional functions.
+ * Undefining some of these symbols will produce a smaller but less capable
+ * library. Note that you can leave certain source files out of the
+ * compilation/linking process if you've #undef'd the corresponding symbols.
+ * (You may HAVE to do that if your compiler doesn't like null source files.)
+ */
+
+/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */
+
+/* Capability options common to encoder and decoder: */
+
+#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
+#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
+#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
+
+/* Encoder capability options: */
+
+#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
+#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
+/* Note: if you selected 12-bit data precision, it is dangerous to turn off
+ * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
+ * precision, so jchuff.c normally uses entropy optimization to compute
+ * usable tables for higher precision. If you don't want to do optimization,
+ * you'll have to supply different default Huffman tables.
+ * The exact same statements apply for progressive JPEG: the default tables
+ * don't work for progressive mode. (This may get fixed, however.)
+ */
+#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
+
+/* Decoder capability options: */
+
+#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
+#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
+#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
+#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
+#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
+#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
+#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
+
+/* more capability options later, no doubt */
+
+
+/*
+ * Ordering of RGB data in scanlines passed to or from the application.
+ * If your application wants to deal with data in the order B,G,R, just
+ * change these macros. You can also deal with formats such as R,G,B,X
+ * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing
+ * the offsets will also change the order in which colormap data is organized.
+ * RESTRICTIONS:
+ * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
+ * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not
+ * useful if you are using JPEG color spaces other than YCbCr or grayscale.
+ * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
+ * is not 3 (they don't understand about dummy color components!). So you
+ * can't use color quantization if you change that value.
+ */
+
+#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
+#define RGB_GREEN 1 /* Offset of Green */
+#define RGB_BLUE 2 /* Offset of Blue */
+#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */
+
+
+/* Definitions for speed-related optimizations. */
+
+
+/* If your compiler supports inline functions, define INLINE
+ * as the inline keyword; otherwise define it as empty.
+ */
+
+#ifndef INLINE
+#ifdef __GNUC__ /* for instance, GNU C knows about inline */
+#define INLINE __inline__
+#endif
+#ifndef INLINE
+#define INLINE /* default is to define it as empty */
+#endif
+#endif
+
+
+/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
+ * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER
+ * as short on such a machine. MULTIPLIER must be at least 16 bits wide.
+ */
+
+#ifndef MULTIPLIER
+#define MULTIPLIER int /* type for fastest integer multiply */
+#endif
+
+
+/* FAST_FLOAT should be either float or double, whichever is done faster
+ * by your compiler. (Note that this type is only used in the floating point
+ * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
+ * Typically, float is faster in ANSI C compilers, while double is faster in
+ * pre-ANSI compilers (because they insist on converting to double anyway).
+ * The code below therefore chooses float if we have ANSI-style prototypes.
+ */
+
+#ifndef FAST_FLOAT
+#ifdef HAVE_PROTOTYPES
+#define FAST_FLOAT float
+#else
+#define FAST_FLOAT double
+#endif
+#endif
+
+#endif /* JPEG_INTERNAL_OPTIONS */
diff --git a/gs/jpeg/jpegint.h b/gs/jpeg/jpegint.h
new file mode 100644
index 000000000..7ba30c3fa
--- /dev/null
+++ b/gs/jpeg/jpegint.h
@@ -0,0 +1,388 @@
+/*
+ * jpegint.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides common declarations for the various JPEG modules.
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+
+/* Declarations for both compression & decompression */
+
+typedef enum { /* Operating modes for buffer controllers */
+ JBUF_PASS_THRU, /* Plain stripwise operation */
+ /* Remaining modes require a full-image buffer to have been created */
+ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
+ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
+ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
+} J_BUF_MODE;
+
+/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+#define CSTATE_START 100 /* after create_compress */
+#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
+#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
+#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
+#define DSTATE_START 200 /* after create_decompress */
+#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
+#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
+#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
+#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
+#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
+#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
+#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
+#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
+#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
+#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
+
+
+/* Declarations for compression modules */
+
+/* Master control module */
+struct jpeg_comp_master {
+ JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean call_pass_startup; /* True if pass_startup must be called */
+ boolean is_last_pass; /* True during last pass */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_c_main_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail));
+};
+
+/* Compression preprocessing (downsampling input buffer control) */
+struct jpeg_c_prep_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_c_coef_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf));
+};
+
+/* Colorspace conversion */
+struct jpeg_color_converter {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows));
+};
+
+/* Downsampling */
+struct jpeg_downsampler {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, downsample, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Forward DCT (also controls coefficient quantization) */
+struct jpeg_forward_dct {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ /* perhaps this should be an array??? */
+ JMETHOD(void, forward_DCT, (j_compress_ptr cinfo,
+ jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks));
+};
+
+/* Entropy encoding */
+struct jpeg_entropy_encoder {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
+ JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+};
+
+/* Marker writing */
+struct jpeg_marker_writer {
+ /* write_any_marker is exported for use by applications */
+ /* Probably only COM and APPn markers should be written */
+ JMETHOD(void, write_any_marker, (j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen));
+ JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
+ JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
+};
+
+
+/* Declarations for decompression modules */
+
+/* Master control module */
+struct jpeg_decomp_master {
+ JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
+};
+
+/* Input control module */
+struct jpeg_input_controller {
+ JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
+ JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean has_multiple_scans; /* True if file has multiple scans */
+ boolean eoi_reached; /* True when EOI has been consumed */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_d_main_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_d_coef_controller {
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE output_buf));
+ /* Pointer to array of coefficient virtual arrays, or NULL if none */
+ jvirt_barray_ptr *coef_arrays;
+};
+
+/* Decompression postprocessing (color quantization buffer control) */
+struct jpeg_d_post_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Marker reading & parsing */
+struct jpeg_marker_reader {
+ JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
+ /* Read markers until SOS or EOI.
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ */
+ JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
+ /* Read a restart marker --- exported for use by entropy decoder only */
+ jpeg_marker_parser_method read_restart_marker;
+ /* Application-overridable marker processing methods */
+ jpeg_marker_parser_method process_COM;
+ jpeg_marker_parser_method process_APPn[16];
+
+ /* State of marker reader --- nominally internal, but applications
+ * supplying COM or APPn handlers might like to know the state.
+ */
+ boolean saw_SOI; /* found SOI? */
+ boolean saw_SOF; /* found SOF? */
+ int next_restart_num; /* next restart number expected (0-7) */
+ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
+};
+
+/* Entropy decoding */
+struct jpeg_entropy_decoder {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+};
+
+/* Inverse DCT (also performs dequantization) */
+typedef JMETHOD(void, inverse_DCT_method_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col));
+
+struct jpeg_inverse_dct {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ /* It is useful to allow each component to have a separate IDCT method. */
+ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+};
+
+/* Upsampling (note that upsampler must also call color converter) */
+struct jpeg_upsampler {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, upsample, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Colorspace conversion */
+struct jpeg_color_deconverter {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows));
+};
+
+/* Color quantization or color precision reduction */
+struct jpeg_color_quantizer {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
+ JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf,
+ int num_rows));
+ JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
+};
+
+
+/* Miscellaneous useful macros */
+
+#undef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#undef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity. This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit. But some
+ * C compilers implement >> with an unsigned shift. For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts. SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft) \
+ ((shift_temp = (x)) < 0 ? \
+ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+ (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_compress_master jICompress
+#define jinit_c_master_control jICMaster
+#define jinit_c_main_controller jICMainC
+#define jinit_c_prep_controller jICPrepC
+#define jinit_c_coef_controller jICCoefC
+#define jinit_color_converter jICColor
+#define jinit_downsampler jIDownsampler
+#define jinit_forward_dct jIFDCT
+#define jinit_huff_encoder jIHEncoder
+#define jinit_phuff_encoder jIPHEncoder
+#define jinit_marker_writer jIMWriter
+#define jinit_master_decompress jIDMaster
+#define jinit_d_main_controller jIDMainC
+#define jinit_d_coef_controller jIDCoefC
+#define jinit_d_post_controller jIDPostC
+#define jinit_input_controller jIInCtlr
+#define jinit_marker_reader jIMReader
+#define jinit_huff_decoder jIHDecoder
+#define jinit_phuff_decoder jIPHDecoder
+#define jinit_inverse_dct jIIDCT
+#define jinit_upsampler jIUpsampler
+#define jinit_color_deconverter jIDColor
+#define jinit_1pass_quantizer jI1Quant
+#define jinit_2pass_quantizer jI2Quant
+#define jinit_merged_upsampler jIMUpsampler
+#define jinit_memory_mgr jIMemMgr
+#define jdiv_round_up jDivRound
+#define jround_up jRound
+#define jcopy_sample_rows jCopySamples
+#define jcopy_block_row jCopyBlocks
+#define jzero_far jZeroFar
+#define jpeg_zigzag_order jZIGTable
+#define jpeg_natural_order jZAGTable
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Compression module initialization routines */
+EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
+ boolean transcode_only));
+EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
+/* Decompression module initialization routines */
+EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
+/* Memory manager initialization */
+EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
+
+/* Utility routines in jutils.c */
+EXTERN(long) jdiv_round_up JPP((long a, long b));
+EXTERN(long) jround_up JPP((long a, long b));
+EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols));
+EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks));
+EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
+/* Constant tables in jutils.c */
+extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
+extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
+
+/* Suppress undefined-structure complaints if necessary. */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+#endif
+#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/gs/jpeg/jpeglib.h b/gs/jpeg/jpeglib.h
new file mode 100644
index 000000000..b778e2df7
--- /dev/null
+++ b/gs/jpeg/jpeglib.h
@@ -0,0 +1,1055 @@
+/*
+ * jpeglib.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the application interface for the JPEG library.
+ * Most applications using the library need only include this file,
+ * and perhaps jerror.h if they want to know the exact error codes.
+ */
+
+#ifndef JPEGLIB_H
+#define JPEGLIB_H
+
+/*
+ * First we include the configuration files that record how this
+ * installation of the JPEG library is set up. jconfig.h can be
+ * generated automatically for many systems. jmorecfg.h contains
+ * manual configuration options that most people need not worry about.
+ */
+
+#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
+#include "jconfig.h" /* widely used configuration options */
+#endif
+#include "jmorecfg.h" /* seldom changed options */
+
+
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+
+#define JPEG_LIB_VERSION 61 /* Version 6a */
+
+
+/* Various constants determining the sizes of things.
+ * All of these are specified by the JPEG standard, so don't change them
+ * if you want to be compatible.
+ */
+
+#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
+#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
+#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
+#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */
+#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */
+#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */
+#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */
+/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
+ * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
+ * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
+ * to handle it. We even let you do this from the jconfig.h file. However,
+ * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
+ * sometimes emits noncompliant files doesn't mean you should too.
+ */
+#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */
+#ifndef D_MAX_BLOCKS_IN_MCU
+#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */
+#endif
+
+
+/* Data structures for images (arrays of samples and of DCT coefficients).
+ * On 80x86 machines, the image arrays are too big for near pointers,
+ * but the pointer arrays can fit in near memory.
+ */
+
+typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */
+typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
+typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+
+typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
+typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */
+typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
+typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
+
+typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
+
+
+/* Types for JPEG compression parameters and working tables. */
+
+
+/* DCT coefficient quantization tables. */
+
+typedef struct {
+ /* This array gives the coefficient quantizers in natural array order
+ * (not the zigzag order in which they are stored in a JPEG DQT marker).
+ * CAUTION: IJG versions prior to v6a kept this array in zigzag order.
+ */
+ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JQUANT_TBL;
+
+
+/* Huffman coding tables. */
+
+typedef struct {
+ /* These two fields directly represent the contents of a JPEG DHT marker */
+ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */
+ /* length k bits; bits[0] is unused */
+ UINT8 huffval[256]; /* The symbols, in order of incr code length */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JHUFF_TBL;
+
+
+/* Basic info about one component (color channel). */
+
+typedef struct {
+ /* These values are fixed over the whole image. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOF marker. */
+ int component_id; /* identifier for this component (0..255) */
+ int component_index; /* its index in SOF or cinfo->comp_info[] */
+ int h_samp_factor; /* horizontal sampling factor (1..4) */
+ int v_samp_factor; /* vertical sampling factor (1..4) */
+ int quant_tbl_no; /* quantization table selector (0..3) */
+ /* These values may vary between scans. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOS marker. */
+ /* The decompressor output side may not use these variables. */
+ int dc_tbl_no; /* DC entropy table selector (0..3) */
+ int ac_tbl_no; /* AC entropy table selector (0..3) */
+
+ /* Remaining fields should be treated as private by applications. */
+
+ /* These values are computed during compression or decompression startup: */
+ /* Component's size in DCT blocks.
+ * Any dummy blocks added to complete an MCU are not counted; therefore
+ * these values do not depend on whether a scan is interleaved or not.
+ */
+ JDIMENSION width_in_blocks;
+ JDIMENSION height_in_blocks;
+ /* Size of a DCT block in samples. Always DCTSIZE for compression.
+ * For decompression this is the size of the output from one DCT block,
+ * reflecting any scaling we choose to apply during the IDCT step.
+ * Values of 1,2,4,8 are likely to be supported. Note that different
+ * components may receive different IDCT scalings.
+ */
+ int DCT_scaled_size;
+ /* The downsampled dimensions are the component's actual, unpadded number
+ * of samples at the main buffer (preprocessing/compression interface), thus
+ * downsampled_width = ceil(image_width * Hi/Hmax)
+ * and similarly for height. For decompression, IDCT scaling is included, so
+ * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
+ */
+ JDIMENSION downsampled_width; /* actual width in samples */
+ JDIMENSION downsampled_height; /* actual height in samples */
+ /* This flag is used only for decompression. In cases where some of the
+ * components will be ignored (eg grayscale output from YCbCr image),
+ * we can skip most computations for the unused components.
+ */
+ boolean component_needed; /* do we need the value of this component? */
+
+ /* These values are computed before starting a scan of the component. */
+ /* The decompressor output side may not use these variables. */
+ int MCU_width; /* number of blocks per MCU, horizontally */
+ int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_blocks; /* MCU_width * MCU_height */
+ int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */
+ int last_col_width; /* # of non-dummy blocks across in last MCU */
+ int last_row_height; /* # of non-dummy blocks down in last MCU */
+
+ /* Saved quantization table for component; NULL if none yet saved.
+ * See jdinput.c comments about the need for this information.
+ * This field is currently used only for decompression.
+ */
+ JQUANT_TBL * quant_table;
+
+ /* Private per-component storage for DCT or IDCT subsystem. */
+ void * dct_table;
+} jpeg_component_info;
+
+
+/* The script for encoding a multiple-scan file is an array of these: */
+
+typedef struct {
+ int comps_in_scan; /* number of components encoded in this scan */
+ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
+ int Ss, Se; /* progressive JPEG spectral selection parms */
+ int Ah, Al; /* progressive JPEG successive approx. parms */
+} jpeg_scan_info;
+
+
+/* Known color spaces. */
+
+typedef enum {
+ JCS_UNKNOWN, /* error/unspecified */
+ JCS_GRAYSCALE, /* monochrome */
+ JCS_RGB, /* red/green/blue */
+ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
+ JCS_CMYK, /* C/M/Y/K */
+ JCS_YCCK /* Y/Cb/Cr/K */
+} J_COLOR_SPACE;
+
+/* DCT/IDCT algorithm options. */
+
+typedef enum {
+ JDCT_ISLOW, /* slow but accurate integer algorithm */
+ JDCT_IFAST, /* faster, less accurate integer method */
+ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */
+} J_DCT_METHOD;
+
+#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */
+#define JDCT_DEFAULT JDCT_ISLOW
+#endif
+#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */
+#define JDCT_FASTEST JDCT_IFAST
+#endif
+
+/* Dithering options for decompression. */
+
+typedef enum {
+ JDITHER_NONE, /* no dithering */
+ JDITHER_ORDERED, /* simple ordered dither */
+ JDITHER_FS /* Floyd-Steinberg error diffusion dither */
+} J_DITHER_MODE;
+
+
+/* Common fields between JPEG compression and decompression master structs. */
+
+#define jpeg_common_fields \
+ struct jpeg_error_mgr * err; /* Error handler module */\
+ struct jpeg_memory_mgr * mem; /* Memory manager module */\
+ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\
+ boolean is_decompressor; /* so common code can tell which is which */\
+ int global_state /* for checking call sequence validity */
+
+/* Routines that are to be used by both halves of the library are declared
+ * to receive a pointer to this structure. There are no actual instances of
+ * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.
+ */
+struct jpeg_common_struct {
+ jpeg_common_fields; /* Fields common to both master struct types */
+ /* Additional fields follow in an actual jpeg_compress_struct or
+ * jpeg_decompress_struct. All three structs must agree on these
+ * initial fields! (This would be a lot cleaner in C++.)
+ */
+};
+
+typedef struct jpeg_common_struct * j_common_ptr;
+typedef struct jpeg_compress_struct * j_compress_ptr;
+typedef struct jpeg_decompress_struct * j_decompress_ptr;
+
+
+/* Master record for a compression instance */
+
+struct jpeg_compress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */
+
+ /* Destination for compressed data */
+ struct jpeg_destination_mgr * dest;
+
+ /* Description of source image --- these fields must be filled in by
+ * outer application before starting compression. in_color_space must
+ * be correct before you can even call jpeg_set_defaults().
+ */
+
+ JDIMENSION image_width; /* input image width */
+ JDIMENSION image_height; /* input image height */
+ int input_components; /* # of color components in input image */
+ J_COLOR_SPACE in_color_space; /* colorspace of input image */
+
+ double input_gamma; /* image gamma of input image */
+
+ /* Compression parameters --- these fields must be set before calling
+ * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to
+ * initialize everything to reasonable defaults, then changing anything
+ * the application specifically wants to change. That way you won't get
+ * burnt when new parameters are added. Also note that there are several
+ * helper routines to simplify changing parameters.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ int num_scans; /* # of entries in scan_info array */
+ const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */
+ /* The default value of scan_info is NULL, which causes a single-scan
+ * sequential JPEG file to be emitted. To create a multi-scan file,
+ * set num_scans and scan_info to point to an array of scan definitions.
+ */
+
+ boolean raw_data_in; /* TRUE=caller supplies downsampled data */
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+ int smoothing_factor; /* 1..100, or 0 for no input smoothing */
+ J_DCT_METHOD dct_method; /* DCT algorithm selector */
+
+ /* The restart interval can be specified in absolute MCUs by setting
+ * restart_interval, or in MCU rows by setting restart_in_rows
+ * (in which case the correct restart_interval will be figured
+ * for each scan).
+ */
+ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */
+ int restart_in_rows; /* if > 0, MCU rows per restart interval */
+
+ /* Parameters controlling emission of special markers. */
+
+ boolean write_JFIF_header; /* should a JFIF marker be written? */
+ /* These three values are not used by the JPEG code, merely copied */
+ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */
+ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */
+ /* ratio is defined by X_density/Y_density even when density_unit=0. */
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean write_Adobe_marker; /* should an Adobe marker be written? */
+
+ /* State variable: index of next scanline to be written to
+ * jpeg_write_scanlines(). Application may use this to control its
+ * processing loop, e.g., "while (next_scanline < image_height)".
+ */
+
+ JDIMENSION next_scanline; /* 0 .. image_height-1 */
+
+ /* Remaining fields are known throughout compressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during compression startup
+ */
+ boolean progressive_mode; /* TRUE if scan script uses progressive mode */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
+ /* The coefficient controller receives data in units of MCU rows as defined
+ * for fully interleaved scans (whether the JPEG file is interleaved or not).
+ * There are v_samp_factor * DCTSIZE sample rows of each component in an
+ * "iMCU" (interleaved MCU) row.
+ */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[C_MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+
+ /*
+ * Links to compression subobjects (methods and private variables of modules)
+ */
+ struct jpeg_comp_master * master;
+ struct jpeg_c_main_controller * main;
+ struct jpeg_c_prep_controller * prep;
+ struct jpeg_c_coef_controller * coef;
+ struct jpeg_marker_writer * marker;
+ struct jpeg_color_converter * cconvert;
+ struct jpeg_downsampler * downsample;
+ struct jpeg_forward_dct * fdct;
+ struct jpeg_entropy_encoder * entropy;
+};
+
+
+/* Master record for a decompression instance */
+
+struct jpeg_decompress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_compress_struct */
+
+ /* Source of compressed data */
+ struct jpeg_source_mgr * src;
+
+ /* Basic description of image --- filled in by jpeg_read_header(). */
+ /* Application may inspect these values to decide how to process image. */
+
+ JDIMENSION image_width; /* nominal image width (from SOF marker) */
+ JDIMENSION image_height; /* nominal image height */
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ /* Decompression processing parameters --- these fields must be set before
+ * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes
+ * them to default values.
+ */
+
+ J_COLOR_SPACE out_color_space; /* colorspace for output */
+
+ unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+ double output_gamma; /* image gamma wanted in output */
+
+ boolean buffered_image; /* TRUE=multiple output passes */
+ boolean raw_data_out; /* TRUE=downsampled data wanted */
+
+ J_DCT_METHOD dct_method; /* IDCT algorithm selector */
+ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */
+ boolean do_block_smoothing; /* TRUE=apply interblock smoothing */
+
+ boolean quantize_colors; /* TRUE=colormapped output wanted */
+ /* the following are ignored if not quantize_colors: */
+ J_DITHER_MODE dither_mode; /* type of color dithering to use */
+ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */
+ int desired_number_of_colors; /* max # colors to use in created colormap */
+ /* these are significant only in buffered-image mode: */
+ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */
+ boolean enable_external_quant;/* enable future use of external colormap */
+ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */
+
+ /* Description of actual output image that will be returned to application.
+ * These fields are computed by jpeg_start_decompress().
+ * You can also use jpeg_calc_output_dimensions() to determine these values
+ * in advance of calling jpeg_start_decompress().
+ */
+
+ JDIMENSION output_width; /* scaled image width */
+ JDIMENSION output_height; /* scaled image height */
+ int out_color_components; /* # of color components in out_color_space */
+ int output_components; /* # of color components returned */
+ /* output_components is 1 (a colormap index) when quantizing colors;
+ * otherwise it equals out_color_components.
+ */
+ int rec_outbuf_height; /* min recommended height of scanline buffer */
+ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
+ * high, space and time will be wasted due to unnecessary data copying.
+ * Usually rec_outbuf_height will be 1 or 2, at most 4.
+ */
+
+ /* When quantizing colors, the output colormap is described by these fields.
+ * The application can supply a colormap by setting colormap non-NULL before
+ * calling jpeg_start_decompress; otherwise a colormap is created during
+ * jpeg_start_decompress or jpeg_start_output.
+ * The map has out_color_components rows and actual_number_of_colors columns.
+ */
+ int actual_number_of_colors; /* number of entries in use */
+ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
+
+ /* State variables: these variables indicate the progress of decompression.
+ * The application may examine these but must not modify them.
+ */
+
+ /* Row index of next scanline to be read from jpeg_read_scanlines().
+ * Application may use this to control its processing loop, e.g.,
+ * "while (output_scanline < output_height)".
+ */
+ JDIMENSION output_scanline; /* 0 .. output_height-1 */
+
+ /* Current input scan number and number of iMCU rows completed in scan.
+ * These indicate the progress of the decompressor input side.
+ */
+ int input_scan_number; /* Number of SOS markers seen so far */
+ JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */
+
+ /* The "output scan number" is the notional scan being displayed by the
+ * output side. The decompressor will not allow output scan/row number
+ * to get ahead of input scan/row, but it can fall arbitrarily far behind.
+ */
+ int output_scan_number; /* Nominal scan number being displayed */
+ JDIMENSION output_iMCU_row; /* Number of iMCU rows read */
+
+ /* Current progression status. coef_bits[c][i] indicates the precision
+ * with which component c's DCT coefficient i (in zigzag order) is known.
+ * It is -1 when no data has yet been received, otherwise it is the point
+ * transform (shift) value for the most recent scan of the coefficient
+ * (thus, 0 at completion of the progression).
+ * This pointer is NULL when reading a non-progressive file.
+ */
+ int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */
+
+ /* Internal JPEG parameters --- the application usually need not look at
+ * these fields. Note that the decompressor output side may not use
+ * any parameters that can change between scans.
+ */
+
+ /* Quantization and Huffman tables are carried forward across input
+ * datastreams when processing abbreviated JPEG datastreams.
+ */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ /* These parameters are never carried across datastreams, since they
+ * are given in SOF/SOS markers or defined to be reset by SOI.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */
+
+ /* These fields record data obtained from optional markers recognized by
+ * the JPEG library.
+ */
+ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */
+ /* Data copied from JFIF marker: */
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */
+ UINT8 Adobe_transform; /* Color transform code from Adobe marker */
+
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+
+ /* Remaining fields are known throughout decompressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during decompression startup
+ */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
+ /* The coefficient controller's input and output progress is measured in
+ * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
+ * in fully interleaved JPEG scans, but are used whether the scan is
+ * interleaved or not. We define an iMCU row as v_samp_factor DCT block
+ * rows of each component. Therefore, the IDCT output contains
+ * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.
+ */
+
+ JSAMPLE * sample_range_limit; /* table for fast range-limiting */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ * Note that the decompressor output side must not use these fields.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[D_MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+
+ /* This field is shared between entropy decoder and marker parser.
+ * It is either zero or the code of a JPEG marker that has been
+ * read from the data source, but has not yet been processed.
+ */
+ int unread_marker;
+
+ /*
+ * Links to decompression subobjects (methods, private variables of modules)
+ */
+ struct jpeg_decomp_master * master;
+ struct jpeg_d_main_controller * main;
+ struct jpeg_d_coef_controller * coef;
+ struct jpeg_d_post_controller * post;
+ struct jpeg_input_controller * inputctl;
+ struct jpeg_marker_reader * marker;
+ struct jpeg_entropy_decoder * entropy;
+ struct jpeg_inverse_dct * idct;
+ struct jpeg_upsampler * upsample;
+ struct jpeg_color_deconverter * cconvert;
+ struct jpeg_color_quantizer * cquantize;
+};
+
+
+/* "Object" declarations for JPEG modules that may be supplied or called
+ * directly by the surrounding application.
+ * As with all objects in the JPEG library, these structs only define the
+ * publicly visible methods and state variables of a module. Additional
+ * private fields may exist after the public ones.
+ */
+
+
+/* Error handler object */
+
+struct jpeg_error_mgr {
+ /* Error exit handler: does not return to caller */
+ JMETHOD(void, error_exit, (j_common_ptr cinfo));
+ /* Conditionally emit a trace or warning message */
+ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
+ /* Routine that actually outputs a trace or error message */
+ JMETHOD(void, output_message, (j_common_ptr cinfo));
+ /* Format a message string for the most recent JPEG error or message */
+ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));
+#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */
+ /* Reset error state variables at start of a new image */
+ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
+
+ /* The message ID code and any parameters are saved here.
+ * A message can have one string parameter or up to 8 int parameters.
+ */
+ int msg_code;
+#define JMSG_STR_PARM_MAX 80
+ union {
+ int i[8];
+ char s[JMSG_STR_PARM_MAX];
+ } msg_parm;
+
+ /* Standard state variables for error facility */
+
+ int trace_level; /* max msg_level that will be displayed */
+
+ /* For recoverable corrupt-data errors, we emit a warning message,
+ * but keep going unless emit_message chooses to abort. emit_message
+ * should count warnings in num_warnings. The surrounding application
+ * can check for bad data by seeing if num_warnings is nonzero at the
+ * end of processing.
+ */
+ long num_warnings; /* number of corrupt-data warnings */
+
+ /* These fields point to the table(s) of error message strings.
+ * An application can change the table pointer to switch to a different
+ * message list (typically, to change the language in which errors are
+ * reported). Some applications may wish to add additional error codes
+ * that will be handled by the JPEG library error mechanism; the second
+ * table pointer is used for this purpose.
+ *
+ * First table includes all errors generated by JPEG library itself.
+ * Error code 0 is reserved for a "no such error string" message.
+ */
+ const char * const * jpeg_message_table; /* Library errors */
+ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */
+ /* Second table can be added by application (see cjpeg/djpeg for example).
+ * It contains strings numbered first_addon_message..last_addon_message.
+ */
+ const char * const * addon_message_table; /* Non-library errors */
+ int first_addon_message; /* code for first string in addon table */
+ int last_addon_message; /* code for last string in addon table */
+};
+
+
+/* Progress monitor object */
+
+struct jpeg_progress_mgr {
+ JMETHOD(void, progress_monitor, (j_common_ptr cinfo));
+
+ long pass_counter; /* work units completed in this pass */
+ long pass_limit; /* total number of work units in this pass */
+ int completed_passes; /* passes completed so far */
+ int total_passes; /* total number of passes expected */
+};
+
+
+/* Data destination object for compression */
+
+struct jpeg_destination_mgr {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+
+ JMETHOD(void, init_destination, (j_compress_ptr cinfo));
+ JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
+ JMETHOD(void, term_destination, (j_compress_ptr cinfo));
+};
+
+
+/* Data source object for decompression */
+
+struct jpeg_source_mgr {
+ const JOCTET * next_input_byte; /* => next byte to read from buffer */
+ size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+
+ JMETHOD(void, init_source, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
+ JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
+ JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
+ JMETHOD(void, term_source, (j_decompress_ptr cinfo));
+};
+
+
+/* Memory manager object.
+ * Allocates "small" objects (a few K total), "large" objects (tens of K),
+ * and "really big" objects (virtual arrays with backing store if needed).
+ * The memory manager does not allow individual objects to be freed; rather,
+ * each created object is assigned to a pool, and whole pools can be freed
+ * at once. This is faster and more convenient than remembering exactly what
+ * to free, especially where malloc()/free() are not too speedy.
+ * NB: alloc routines never return NULL. They exit to error_exit if not
+ * successful.
+ */
+
+#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */
+#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */
+#define JPOOL_NUMPOOLS 2
+
+typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
+typedef struct jvirt_barray_control * jvirt_barray_ptr;
+
+
+struct jpeg_memory_mgr {
+ /* Method pointers */
+ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows));
+ JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows));
+ JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
+ int pool_id,
+ boolean pre_zero,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows,
+ JDIMENSION maxaccess));
+ JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,
+ int pool_id,
+ boolean pre_zero,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows,
+ JDIMENSION maxaccess));
+ JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));
+ JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,
+ jvirt_sarray_ptr ptr,
+ JDIMENSION start_row,
+ JDIMENSION num_rows,
+ boolean writable));
+ JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,
+ jvirt_barray_ptr ptr,
+ JDIMENSION start_row,
+ JDIMENSION num_rows,
+ boolean writable));
+ JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));
+ JMETHOD(void, self_destruct, (j_common_ptr cinfo));
+
+ /* Limit on memory allocation for this JPEG object. (Note that this is
+ * merely advisory, not a guaranteed maximum; it only affects the space
+ * used for virtual-array buffers.) May be changed by outer application
+ * after creating the JPEG object.
+ */
+ long max_memory_to_use;
+};
+
+
+/* Routine signature for application-supplied marker processing methods.
+ * Need not pass marker code since it is stored in cinfo->unread_marker.
+ */
+typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
+
+
+/* Declarations for routines called by application.
+ * The JPP macro hides prototype parameters from compilers that can't cope.
+ * Note JPP requires double parentheses.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JPP(arglist) arglist
+#else
+#define JPP(arglist) ()
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers.
+ * We shorten external names to be unique in the first six letters, which
+ * is good enough for all known systems.
+ * (If your compiler itself needs names to be unique in less than 15
+ * characters, you are out of luck. Get a better compiler.)
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_error jStdError
+#define jpeg_CreateCompress jCreaCompress
+#define jpeg_CreateDecompress jCreaDecompress
+#define jpeg_destroy_compress jDestCompress
+#define jpeg_destroy_decompress jDestDecompress
+#define jpeg_stdio_dest jStdDest
+#define jpeg_stdio_src jStdSrc
+#define jpeg_set_defaults jSetDefaults
+#define jpeg_set_colorspace jSetColorspace
+#define jpeg_default_colorspace jDefColorspace
+#define jpeg_set_quality jSetQuality
+#define jpeg_set_linear_quality jSetLQuality
+#define jpeg_add_quant_table jAddQuantTable
+#define jpeg_quality_scaling jQualityScaling
+#define jpeg_simple_progression jSimProgress
+#define jpeg_suppress_tables jSuppressTables
+#define jpeg_alloc_quant_table jAlcQTable
+#define jpeg_alloc_huff_table jAlcHTable
+#define jpeg_start_compress jStrtCompress
+#define jpeg_write_scanlines jWrtScanlines
+#define jpeg_finish_compress jFinCompress
+#define jpeg_write_raw_data jWrtRawData
+#define jpeg_write_marker jWrtMarker
+#define jpeg_write_tables jWrtTables
+#define jpeg_read_header jReadHeader
+#define jpeg_start_decompress jStrtDecompress
+#define jpeg_read_scanlines jReadScanlines
+#define jpeg_finish_decompress jFinDecompress
+#define jpeg_read_raw_data jReadRawData
+#define jpeg_has_multiple_scans jHasMultScn
+#define jpeg_start_output jStrtOutput
+#define jpeg_finish_output jFinOutput
+#define jpeg_input_complete jInComplete
+#define jpeg_new_colormap jNewCMap
+#define jpeg_consume_input jConsumeInput
+#define jpeg_calc_output_dimensions jCalcDimensions
+#define jpeg_set_marker_processor jSetMarker
+#define jpeg_read_coefficients jReadCoefs
+#define jpeg_write_coefficients jWrtCoefs
+#define jpeg_copy_critical_parameters jCopyCrit
+#define jpeg_abort_compress jAbrtCompress
+#define jpeg_abort_decompress jAbrtDecompress
+#define jpeg_abort jAbort
+#define jpeg_destroy jDestroy
+#define jpeg_resync_to_restart jResyncRestart
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Default error-management setup */
+EXTERN(struct jpeg_error_mgr *) jpeg_std_error
+ JPP((struct jpeg_error_mgr * err));
+
+/* Initialization of JPEG compression objects.
+ * jpeg_create_compress() and jpeg_create_decompress() are the exported
+ * names that applications should call. These expand to calls on
+ * jpeg_CreateCompress and jpeg_CreateDecompress with additional information
+ * passed for version mismatch checking.
+ * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx.
+ */
+#define jpeg_create_compress(cinfo) \
+ jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
+ (size_t) sizeof(struct jpeg_compress_struct))
+#define jpeg_create_decompress(cinfo) \
+ jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \
+ (size_t) sizeof(struct jpeg_decompress_struct))
+EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo,
+ int version, size_t structsize));
+EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo,
+ int version, size_t structsize));
+/* Destruction of JPEG compression objects */
+EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));
+
+/* Standard data source and destination managers: stdio streams. */
+/* Caller is responsible for opening the file before and closing after. */
+EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
+EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* Default parameter setup for compression */
+EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
+/* Compression parameter setup aids */
+EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo,
+ J_COLOR_SPACE colorspace));
+EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,
+ boolean force_baseline));
+EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN(int) jpeg_quality_scaling JPP((int quality));
+EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,
+ boolean suppress));
+EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo));
+EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo));
+
+/* Main entry points for compression */
+EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo,
+ boolean write_all_tables));
+EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION num_lines));
+EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));
+
+/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION num_lines));
+
+/* Write a special marker. See libjpeg.doc concerning safe usage. */
+EXTERN(void) jpeg_write_marker
+ JPP((j_compress_ptr cinfo, int marker,
+ const JOCTET * dataptr, unsigned int datalen));
+
+/* Alternate compression function: just write an abbreviated table file */
+EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo));
+
+/* Decompression startup: read start of JPEG datastream to see what's there */
+EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
+ boolean require_image));
+/* Return value is one of: */
+#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */
+#define JPEG_HEADER_OK 1 /* Found valid image datastream */
+#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */
+/* If you pass require_image = TRUE (normal case), you need not check for
+ * a TABLES_ONLY return code; an abbreviated file will cause an error exit.
+ * JPEG_SUSPENDED is only possible if you use a data source module that can
+ * give a suspension return (the stdio source module doesn't).
+ */
+
+/* Main entry points for decompression */
+EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION max_lines));
+EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo));
+
+/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION max_lines));
+
+/* Additional entry points for buffered-image mode. */
+EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,
+ int scan_number));
+EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo));
+EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo));
+/* Return value is one of: */
+/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */
+#define JPEG_REACHED_SOS 1 /* Reached start of new scan */
+#define JPEG_REACHED_EOI 2 /* Reached end of image */
+#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */
+#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */
+
+/* Precalculate output dimensions for current decompression parameters. */
+EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
+
+/* Install a special processing method for COM or APPn markers. */
+EXTERN(void) jpeg_set_marker_processor
+ JPP((j_decompress_ptr cinfo, int marker_code,
+ jpeg_marker_parser_method routine));
+
+/* Read or write raw DCT coefficients --- useful for lossless transcoding. */
+EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays));
+EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo));
+
+/* If you choose to abort compression or decompression before completing
+ * jpeg_finish_(de)compress, then you need to clean up to release memory,
+ * temporary files, etc. You can just call jpeg_destroy_(de)compress
+ * if you're done with the JPEG object, but if you want to clean it up and
+ * reuse it, call this:
+ */
+EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo));
+
+/* Generic versions of jpeg_abort and jpeg_destroy that work on either
+ * flavor of JPEG object. These may be more convenient in some places.
+ */
+EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));
+
+/* Default restart-marker-resync procedure for use by data source modules */
+EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,
+ int desired));
+
+
+/* These marker codes are exported since applications and data source modules
+ * are likely to want to use them.
+ */
+
+#define JPEG_RST0 0xD0 /* RST0 marker code */
+#define JPEG_EOI 0xD9 /* EOI marker code */
+#define JPEG_APP0 0xE0 /* APP0 marker code */
+#define JPEG_COM 0xFE /* COM marker code */
+
+
+/* If we have a brain-damaged compiler that emits warnings (or worse, errors)
+ * for structure definitions that are never filled in, keep it quiet by
+ * supplying dummy definitions for the various substructures.
+ */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+struct jpeg_comp_master { long dummy; };
+struct jpeg_c_main_controller { long dummy; };
+struct jpeg_c_prep_controller { long dummy; };
+struct jpeg_c_coef_controller { long dummy; };
+struct jpeg_marker_writer { long dummy; };
+struct jpeg_color_converter { long dummy; };
+struct jpeg_downsampler { long dummy; };
+struct jpeg_forward_dct { long dummy; };
+struct jpeg_entropy_encoder { long dummy; };
+struct jpeg_decomp_master { long dummy; };
+struct jpeg_d_main_controller { long dummy; };
+struct jpeg_d_coef_controller { long dummy; };
+struct jpeg_d_post_controller { long dummy; };
+struct jpeg_input_controller { long dummy; };
+struct jpeg_marker_reader { long dummy; };
+struct jpeg_entropy_decoder { long dummy; };
+struct jpeg_inverse_dct { long dummy; };
+struct jpeg_upsampler { long dummy; };
+struct jpeg_color_deconverter { long dummy; };
+struct jpeg_color_quantizer { long dummy; };
+#endif /* JPEG_INTERNALS */
+#endif /* INCOMPLETE_TYPES_BROKEN */
+
+
+/*
+ * The JPEG library modules define JPEG_INTERNALS before including this file.
+ * The internal structure declarations are read only when that is true.
+ * Applications using the library should not include jpegint.h, but may wish
+ * to include jerror.h.
+ */
+
+#ifdef JPEG_INTERNALS
+#include "jpegint.h" /* fetch private declarations */
+#include "jerror.h" /* fetch error codes too */
+#endif
+
+#endif /* JPEGLIB_H */
diff --git a/gs/jpeg/jpegtran b/gs/jpeg/jpegtran
new file mode 100755
index 000000000..5a4342ad2
--- /dev/null
+++ b/gs/jpeg/jpegtran
Binary files differ
diff --git a/gs/jpeg/jpegtran.1 b/gs/jpeg/jpegtran.1
new file mode 100644
index 000000000..73198845c
--- /dev/null
+++ b/gs/jpeg/jpegtran.1
@@ -0,0 +1,150 @@
+.TH JPEGTRAN 1 "15 June 1995"
+.SH NAME
+jpegtran \- lossless transcoding of JPEG files
+.SH SYNOPSIS
+.B jpegtran
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B jpegtran
+translates JPEG files from one variant of JPEG to another, for example
+from baseline JPEG to progressive JPEG. The transformation is lossless:
+no image degradation occurs, which would not be true if you used
+.B djpeg
+followed by
+.BR cjpeg .
+However, you cannot alter the image quality, because that would not be
+a lossless operation.
+.B jpegtran
+reads the named JPEG/JFIF file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+.SH OPTIONS
+.B jpegtran
+accepts a subset of the switches recognized by
+.BR cjpeg .
+If you specify no switches, you get a plain baseline JPEG output file.
+.PP
+All switch names may be abbreviated; for example,
+.B \-optimize
+may be written
+.B \-opt
+or
+.BR \-o .
+Upper and lower case are equivalent.
+British spellings are also accepted (e.g.,
+.BR \-optimise ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters. Without this, default
+encoding parameters are used.
+.B \-optimize
+usually makes the JPEG file a little smaller, but at the price of slower
+compression. Note that
+.B \-progressive
+implies
+.BR \-optimize .
+.TP
+.B \-progressive
+Create progressive JPEG file (see below).
+.PP
+The
+.B \-progressive
+switch creates a "progressive JPEG" file. In this type of JPEG file, the data
+is stored in multiple scans of increasing quality. If the file is being
+transmitted over a slow communications link, the decoder can use the first
+scan to display a low-quality image very quickly, and can then improve the
+display with each subsequent scan. The final image is exactly equivalent to a
+standard JPEG file of the same quality setting, and the total file size is
+about the same --- often a little smaller.
+.B Caution:
+progressive JPEG is not yet widely implemented, so many decoders will be
+unable to view a progressive JPEG file at all.
+.PP
+Switches for advanced users:
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.B \-restart 0
+(the default) means no restart markers.
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.PP
+The
+.B \-restart
+option inserts extra markers that allow a JPEG decoder to resynchronize after
+a transmission error. Without restart markers, any damage to a compressed
+file will usually ruin the image from the point of the error to the end of the
+image; with restart markers, the damage is usually confined to the portion of
+the image up to the next restart marker. Of course, the restart markers
+occupy extra space. We recommend
+.B \-restart 1
+for images that will be transmitted across unreliable networks such as Usenet.
+.PP
+Switches for wizards:
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+The "wizard" switches are intended for experimentation with JPEG. If you
+don't know what you are doing, \fBdon't use them\fR. These switches are
+documented further in the file wizard.doc.
+.SH EXAMPLES
+.LP
+This example converts a baseline JPEG file to progressive form:
+.IP
+.B jpegtran \-progressive
+.I foo.jpg
+.B >
+.I fooprog.jpg
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+Arithmetic coding is not supported for legal reasons.
+.PP
+Still not as fast as we'd like.
diff --git a/gs/jpeg/jpegtran.c b/gs/jpeg/jpegtran.c
new file mode 100644
index 000000000..51901027c
--- /dev/null
+++ b/gs/jpeg/jpegtran.c
@@ -0,0 +1,372 @@
+/*
+ * jpegtran.c
+ *
+ * Copyright (C) 1995-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for JPEG transcoding.
+ * It is very similar to cjpeg.c, but provides lossless transcoding between
+ * different JPEG file formats.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h" /* for version message */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+ fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+ fprintf(stderr, " -progressive Create progressive JPEG file\n");
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+ fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ fprintf(stderr, "Switches for wizards:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+ fprintf(stderr, " -arithmetic Use arithmetic coding\n");
+#endif
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
+#endif
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+ boolean simple_progressive;
+ char * scansarg = NULL; /* saves -scans parm if any */
+
+ /* Set up default JPEG parameters. */
+ simple_progressive = FALSE;
+ outfilename = NULL;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "arithmetic", 1)) {
+ /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+ cinfo->arith_code = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+ /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+ cinfo->optimize_coding = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "progressive", 1)) {
+ /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+ simple_progressive = TRUE;
+ /* We must postpone execution until num_components is known. */
+#else
+ fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "restart", 1)) {
+ /* Restart interval in MCU rows (or in MCUs with 'b'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (lval < 0 || lval > 65535L)
+ usage();
+ if (ch == 'b' || ch == 'B') {
+ cinfo->restart_interval = (unsigned int) lval;
+ cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+ } else {
+ cinfo->restart_in_rows = (int) lval;
+ /* restart_interval will be computed during startup */
+ }
+
+ } else if (keymatch(arg, "scans", 2)) {
+ /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scansarg = argv[argn];
+ /* We must postpone reading the file in case -progressive appears. */
+#else
+ fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ /* Post-switch-scanning cleanup */
+
+ if (for_real) {
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (simple_progressive) /* process -progressive; -scans can override */
+ jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (scansarg != NULL) /* process -scans if it was present */
+ if (! read_scan_script(cinfo, scansarg))
+ usage();
+#endif
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_decompress_struct srcinfo;
+ struct jpeg_compress_struct dstinfo;
+ struct jpeg_error_mgr jsrcerr, jdsterr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ jvirt_barray_ptr * coef_arrays;
+ int file_index;
+ FILE * input_file;
+ FILE * output_file;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "jpegtran"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG decompression object with default error handling. */
+ srcinfo.err = jpeg_std_error(&jsrcerr);
+ jpeg_create_decompress(&srcinfo);
+ /* Initialize the JPEG compression object with default error handling. */
+ dstinfo.err = jpeg_std_error(&jdsterr);
+ jpeg_create_compress(&dstinfo);
+
+ /* Now safe to enable signal catcher.
+ * Note: we assume only the decompression object will have virtual arrays.
+ */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &srcinfo);
+#endif
+
+ /* Scan command line to find file names.
+ * It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are ignored; we will rescan the switches after opening
+ * the input file.
+ */
+
+ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
+ jsrcerr.trace_level = jdsterr.trace_level;
+ srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ input_file = read_stdin();
+ }
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ output_file = write_stdout();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &dstinfo, &progress);
+#endif
+
+ /* Specify data source for decompression */
+ jpeg_stdio_src(&srcinfo, input_file);
+
+ /* Read file header */
+ (void) jpeg_read_header(&srcinfo, TRUE);
+
+ /* Read source file as DCT coefficients */
+ coef_arrays = jpeg_read_coefficients(&srcinfo);
+
+ /* Initialize destination compression parameters from source values */
+ jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
+
+ /* Adjust default compression parameters by re-parsing the options */
+ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
+
+ /* Specify data destination for compression */
+ jpeg_stdio_dest(&dstinfo, output_file);
+
+ /* Start compressor */
+ jpeg_write_coefficients(&dstinfo, coef_arrays);
+
+ /* ought to copy source comments here... */
+
+ /* Finish compression and release memory */
+ jpeg_finish_compress(&dstinfo);
+ jpeg_destroy_compress(&dstinfo);
+ (void) jpeg_finish_decompress(&srcinfo);
+ jpeg_destroy_decompress(&srcinfo);
+
+ /* Close files, if we opened them */
+ if (input_file != stdin)
+ fclose(input_file);
+ if (output_file != stdout)
+ fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &dstinfo);
+#endif
+
+ /* All done. */
+ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/gs/jpeg/jquant1.c b/gs/jpeg/jquant1.c
new file mode 100644
index 000000000..b2f96aa15
--- /dev/null
+++ b/gs/jpeg/jquant1.c
@@ -0,0 +1,856 @@
+/*
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values. Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_1PASS_SUPPORTED
+
+
+/*
+ * The main purpose of 1-pass quantization is to provide a fast, if not very
+ * high quality, colormapped output capability. A 2-pass quantizer usually
+ * gives better visual quality; however, for quantized grayscale output this
+ * quantizer is perfectly adequate. Dithering is highly recommended with this
+ * quantizer, though you can turn it off if you really want to.
+ *
+ * In 1-pass quantization the colormap must be chosen in advance of seeing the
+ * image. We use a map consisting of all combinations of Ncolors[i] color
+ * values for the i'th component. The Ncolors[] values are chosen so that
+ * their product, the total number of colors, is no more than that requested.
+ * (In most cases, the product will be somewhat less.)
+ *
+ * Since the colormap is orthogonal, the representative value for each color
+ * component can be determined without considering the other components;
+ * then these indexes can be combined into a colormap index by a standard
+ * N-dimensional-array-subscript calculation. Most of the arithmetic involved
+ * can be precalculated and stored in the lookup table colorindex[].
+ * colorindex[i][j] maps pixel value j in component i to the nearest
+ * representative value (grid plane) for that component; this index is
+ * multiplied by the array stride for component i, so that the
+ * index of the colormap entry closest to a given pixel value is just
+ * sum( colorindex[component-number][pixel-component-value] )
+ * Aside from being fast, this scheme allows for variable spacing between
+ * representative values with no additional lookup cost.
+ *
+ * If gamma correction has been applied in color conversion, it might be wise
+ * to adjust the color grid spacing so that the representative colors are
+ * equidistant in linear space. At this writing, gamma correction is not
+ * implemented by jdcolor, so nothing is done here.
+ */
+
+
+/* Declarations for ordered dithering.
+ *
+ * We use a standard 16x16 ordered dither array. The basic concept of ordered
+ * dithering is described in many references, for instance Dale Schumacher's
+ * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
+ * In place of Schumacher's comparisons against a "threshold" value, we add a
+ * "dither" value to the input pixel and then round the result to the nearest
+ * output value. The dither value is equivalent to (0.5 - threshold) times
+ * the distance between output values. For ordered dithering, we assume that
+ * the output colors are equally spaced; if not, results will probably be
+ * worse, since the dither may be too much or too little at a given point.
+ *
+ * The normal calculation would be to form pixel value + dither, range-limit
+ * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * We can skip the separate range-limiting step by extending the colorindex
+ * table in both directions.
+ */
+
+#define ODITHER_SIZE 16 /* dimension of dither matrix */
+/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */
+#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */
+#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */
+
+typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];
+typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];
+
+static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {
+ /* Bayer's order-4 dither array. Generated by the code given in
+ * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
+ * The values in this array must range from 0 to ODITHER_CELLS-1.
+ */
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+};
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array is indexed [component#][position].
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+#define MAX_Q_COMPS 4 /* max components I can handle */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Initially allocated colormap is saved here */
+ JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
+ int sv_actual; /* number of entries in use */
+
+ JSAMPARRAY colorindex; /* Precomputed mapping for speed */
+ /* colorindex[i][j] = index of color closest to pixel value j in component i,
+ * premultiplied as described above. Since colormap indexes must fit into
+ * JSAMPLEs, the entries of this array will too.
+ */
+ boolean is_padded; /* is the colorindex padded for odither? */
+
+ int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */
+
+ /* Variables for ordered dithering */
+ int row_index; /* cur row's vertical index in dither matrix */
+ ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Policy-making subroutines for create_colormap and create_colorindex.
+ * These routines determine the colormap to be used. The rest of the module
+ * only assumes that the colormap is orthogonal.
+ *
+ * * select_ncolors decides how to divvy up the available colors
+ * among the components.
+ * * output_value defines the set of representative values for a component.
+ * * largest_input_value defines the mapping from input values to
+ * representative values for a component.
+ * Note that the latter two routines may impose different policies for
+ * different components, though this is not currently done.
+ */
+
+
+LOCAL(int)
+select_ncolors (j_decompress_ptr cinfo, int Ncolors[])
+/* Determine allocation of desired colors to components, */
+/* and fill in Ncolors[] array to indicate choice. */
+/* Return value is total number of colors (product of Ncolors[] values). */
+{
+ int nc = cinfo->out_color_components; /* number of color components */
+ int max_colors = cinfo->desired_number_of_colors;
+ int total_colors, iroot, i, j;
+ boolean changed;
+ long temp;
+ static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };
+
+ /* We can allocate at least the nc'th root of max_colors per component. */
+ /* Compute floor(nc'th root of max_colors). */
+ iroot = 1;
+ do {
+ iroot++;
+ temp = iroot; /* set temp = iroot ** nc */
+ for (i = 1; i < nc; i++)
+ temp *= iroot;
+ } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
+ iroot--; /* now iroot = floor(root) */
+
+ /* Must have at least 2 color values per component */
+ if (iroot < 2)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);
+
+ /* Initialize to iroot color values for each component */
+ total_colors = 1;
+ for (i = 0; i < nc; i++) {
+ Ncolors[i] = iroot;
+ total_colors *= iroot;
+ }
+ /* We may be able to increment the count for one or more components without
+ * exceeding max_colors, though we know not all can be incremented.
+ * Sometimes, the first component can be incremented more than once!
+ * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
+ * In RGB colorspace, try to increment G first, then R, then B.
+ */
+ do {
+ changed = FALSE;
+ for (i = 0; i < nc; i++) {
+ j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);
+ /* calculate new total_colors if Ncolors[j] is incremented */
+ temp = total_colors / Ncolors[j];
+ temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */
+ if (temp > (long) max_colors)
+ break; /* won't fit, done with this pass */
+ Ncolors[j]++; /* OK, apply the increment */
+ total_colors = (int) temp;
+ changed = TRUE;
+ }
+ } while (changed);
+
+ return total_colors;
+}
+
+
+LOCAL(int)
+output_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return j'th output value, where j will range from 0 to maxj */
+/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+{
+ /* We always provide values 0 and MAXJSAMPLE for each component;
+ * any additional values are equally spaced between these limits.
+ * (Forcing the upper and lower values to the limits ensures that
+ * dithering can't produce a color outside the selected gamut.)
+ */
+ return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);
+}
+
+
+LOCAL(int)
+largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return largest input value that should map to j'th output value */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+{
+ /* Breakpoints are halfway between values returned by output_value */
+ return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));
+}
+
+
+/*
+ * Create the colormap.
+ */
+
+LOCAL(void)
+create_colormap (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colormap; /* Created colormap */
+ int total_colors; /* Number of distinct output colors */
+ int i,j,k, nci, blksize, blkdist, ptr, val;
+
+ /* Select number of colors for each component */
+ total_colors = select_ncolors(cinfo, cquantize->Ncolors);
+
+ /* Report selected color counts */
+ if (cinfo->out_color_components == 3)
+ TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,
+ total_colors, cquantize->Ncolors[0],
+ cquantize->Ncolors[1], cquantize->Ncolors[2]);
+ else
+ TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);
+
+ /* Allocate and fill in the colormap. */
+ /* The colors are ordered in the map in standard row-major order, */
+ /* i.e. rightmost (highest-indexed) color changes most rapidly. */
+
+ colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ /* blkdist is distance between groups of identical entries for a component */
+ blkdist = total_colors;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colormap entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blkdist / nci;
+ for (j = 0; j < nci; j++) {
+ /* Compute j'th output value (out of nci) for component */
+ val = output_value(cinfo, i, j, nci-1);
+ /* Fill in all colormap entries that have this value of this component */
+ for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
+ /* fill in blksize entries beginning at ptr */
+ for (k = 0; k < blksize; k++)
+ colormap[i][ptr+k] = (JSAMPLE) val;
+ }
+ }
+ blkdist = blksize; /* blksize of this color is blkdist of next */
+ }
+
+ /* Save the colormap in private storage,
+ * where it will survive color quantization mode changes.
+ */
+ cquantize->sv_colormap = colormap;
+ cquantize->sv_actual = total_colors;
+}
+
+
+/*
+ * Create the color index table.
+ */
+
+LOCAL(void)
+create_colorindex (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPROW indexptr;
+ int i,j,k, nci, blksize, val, pad;
+
+ /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
+ * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+ * This is not necessary in the other dithering modes. However, we
+ * flag whether it was done in case user changes dithering mode.
+ */
+ if (cinfo->dither_mode == JDITHER_ORDERED) {
+ pad = MAXJSAMPLE*2;
+ cquantize->is_padded = TRUE;
+ } else {
+ pad = 0;
+ cquantize->is_padded = FALSE;
+ }
+
+ cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (MAXJSAMPLE+1 + pad),
+ (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ blksize = cquantize->sv_actual;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colorindex entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blksize / nci;
+
+ /* adjust colorindex pointers to provide padding at negative indexes. */
+ if (pad)
+ cquantize->colorindex[i] += MAXJSAMPLE;
+
+ /* in loop, val = index of current output value, */
+ /* and k = largest j that maps to current val */
+ indexptr = cquantize->colorindex[i];
+ val = 0;
+ k = largest_input_value(cinfo, i, 0, nci-1);
+ for (j = 0; j <= MAXJSAMPLE; j++) {
+ while (j > k) /* advance val if past boundary */
+ k = largest_input_value(cinfo, i, ++val, nci-1);
+ /* premultiply so that no multiplication needed in main processing */
+ indexptr[j] = (JSAMPLE) (val * blksize);
+ }
+ /* Pad at both ends if necessary */
+ if (pad)
+ for (j = 1; j <= MAXJSAMPLE; j++) {
+ indexptr[-j] = indexptr[0];
+ indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];
+ }
+ }
+}
+
+
+/*
+ * Create an ordered-dither array for a component having ncolors
+ * distinct output values.
+ */
+
+LOCAL(ODITHER_MATRIX_PTR)
+make_odither_array (j_decompress_ptr cinfo, int ncolors)
+{
+ ODITHER_MATRIX_PTR odither;
+ int j,k;
+ INT32 num,den;
+
+ odither = (ODITHER_MATRIX_PTR)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ODITHER_MATRIX));
+ /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+ * Hence the dither value for the matrix cell with fill order f
+ * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+ * On 16-bit-int machine, be careful to avoid overflow.
+ */
+ den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));
+ for (j = 0; j < ODITHER_SIZE; j++) {
+ for (k = 0; k < ODITHER_SIZE; k++) {
+ num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))
+ * MAXJSAMPLE;
+ /* Ensure round towards zero despite C's lack of consistency
+ * about rounding negative values in integer division...
+ */
+ odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);
+ }
+ }
+ return odither;
+}
+
+
+/*
+ * Create the ordered-dither tables.
+ * Components having the same number of representative colors may
+ * share a dither table.
+ */
+
+LOCAL(void)
+create_odither_tables (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ ODITHER_MATRIX_PTR odither;
+ int i, j, nci;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ odither = NULL; /* search for matching prior component */
+ for (j = 0; j < i; j++) {
+ if (nci == cquantize->Ncolors[j]) {
+ odither = cquantize->odither[j];
+ break;
+ }
+ }
+ if (odither == NULL) /* need a new table? */
+ odither = make_odither_array(cinfo, nci);
+ cquantize->odither[i] = odither;
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colorindex = cquantize->colorindex;
+ register int pixcode, ci;
+ register JSAMPROW ptrin, ptrout;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ register int nc = cinfo->out_color_components;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = 0;
+ for (ci = 0; ci < nc; ci++) {
+ pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
+ }
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW ptrin, ptrout;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ int * dither; /* points to active row of dither matrix */
+ int row_index, col_index; /* current indexes into dither matrix */
+ int nc = cinfo->out_color_components;
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ jzero_far((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ row_index = cquantize->row_index;
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ colorindex_ci = cquantize->colorindex[ci];
+ dither = cquantize->odither[ci][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+ * select output value, accumulate into output code for this pixel.
+ * Range-limiting need not be done explicitly, as we have extended
+ * the colorindex table to produce the right answers for out-of-range
+ * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
+ * required amount of padding.
+ */
+ *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];
+ input_ptr += nc;
+ output_ptr++;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ }
+ /* Advance row index for next row */
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int * dither0; /* points to active row of dither matrix */
+ int * dither1;
+ int * dither2;
+ int row_index, col_index; /* current indexes into dither matrix */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ row_index = cquantize->row_index;
+ input_ptr = input_buf[row];
+ output_ptr = output_buf[row];
+ dither0 = cquantize->odither[0][row_index];
+ dither1 = cquantize->odither[1][row_index];
+ dither2 = cquantize->odither[2][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +
+ dither0[col_index]]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +
+ dither1[col_index]]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +
+ dither2[col_index]]);
+ *output_ptr++ = (JSAMPLE) pixcode;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register LOCFSERROR cur; /* current error or pixel value */
+ LOCFSERROR belowerr; /* error for pixel below cur */
+ LOCFSERROR bpreverr; /* error for below/prev col */
+ LOCFSERROR bnexterr; /* error for below/next col */
+ LOCFSERROR delta;
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ JSAMPROW colormap_ci;
+ int pixcode;
+ int nc = cinfo->out_color_components;
+ int dir; /* 1 for left-to-right, -1 for right-to-left */
+ int dirnc; /* dir * nc */
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ jzero_far((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ input_ptr += (width-1) * nc; /* so point to rightmost pixel */
+ output_ptr += width-1;
+ dir = -1;
+ dirnc = -nc;
+ errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dirnc = nc;
+ errorptr = cquantize->fserrors[ci]; /* => entry before first column */
+ }
+ colorindex_ci = cquantize->colorindex[ci];
+ colormap_ci = cquantize->sv_colormap[ci];
+ /* Preset error values: no error propagated to first pixel from left */
+ cur = 0;
+ /* and no error propagated to row below yet */
+ belowerr = bpreverr = 0;
+
+ for (col = width; col > 0; col--) {
+ /* cur holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE; this sets the required size
+ * of the range_limit array.
+ */
+ cur += GETJSAMPLE(*input_ptr);
+ cur = GETJSAMPLE(range_limit[cur]);
+ /* Select output value, accumulate into output code for this pixel */
+ pixcode = GETJSAMPLE(colorindex_ci[cur]);
+ *output_ptr += (JSAMPLE) pixcode;
+ /* Compute actual representation error at this pixel */
+ /* Note: we can do this even though we don't have the final */
+ /* pixel code, because the colormap is orthogonal. */
+ cur -= GETJSAMPLE(colormap_ci[pixcode]);
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ bnexterr = cur;
+ delta = cur * 2;
+ cur += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr + cur);
+ cur += delta; /* form error * 5 */
+ bpreverr = belowerr + cur;
+ belowerr = bnexterr;
+ cur += delta; /* form error * 7 */
+ /* At this point cur contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ input_ptr += dirnc; /* advance input ptr to next column */
+ output_ptr += dir; /* advance output ptr to next column */
+ errorptr += dir; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error value into the
+ * final fserrors[] entry. Note we need not unload belowerr because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
+ }
+ cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
+ }
+}
+
+
+/*
+ * Allocate workspace for Floyd-Steinberg errors.
+ */
+
+LOCAL(void)
+alloc_fs_workspace (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ cquantize->fserrors[i] = (FSERRPTR)
+ (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ }
+}
+
+
+/*
+ * Initialize for one-pass color quantization.
+ */
+
+METHODDEF(void)
+start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ /* Install my colormap. */
+ cinfo->colormap = cquantize->sv_colormap;
+ cinfo->actual_number_of_colors = cquantize->sv_actual;
+
+ /* Initialize for desired dithering mode. */
+ switch (cinfo->dither_mode) {
+ case JDITHER_NONE:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = color_quantize3;
+ else
+ cquantize->pub.color_quantize = color_quantize;
+ break;
+ case JDITHER_ORDERED:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = quantize3_ord_dither;
+ else
+ cquantize->pub.color_quantize = quantize_ord_dither;
+ cquantize->row_index = 0; /* initialize state for ordered dither */
+ /* If user changed to ordered dither from another mode,
+ * we must recreate the color index table with padding.
+ * This will cost extra space, but probably isn't very likely.
+ */
+ if (! cquantize->is_padded)
+ create_colorindex(cinfo);
+ /* Create ordered-dither tables if we didn't already. */
+ if (cquantize->odither[0] == NULL)
+ create_odither_tables(cinfo);
+ break;
+ case JDITHER_FS:
+ cquantize->pub.color_quantize = quantize_fs_dither;
+ cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
+ /* Allocate Floyd-Steinberg workspace if didn't already. */
+ if (cquantize->fserrors[0] == NULL)
+ alloc_fs_workspace(cinfo);
+ /* Initialize the propagated errors to zero. */
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++)
+ jzero_far((void FAR *) cquantize->fserrors[i], arraysize);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+}
+
+
+/*
+ * Finish up at the end of the pass.
+ */
+
+METHODDEF(void)
+finish_pass_1_quant (j_decompress_ptr cinfo)
+{
+ /* no work in 1-pass case */
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ * Shouldn't get to this module!
+ */
+
+METHODDEF(void)
+new_color_map_1_quant (j_decompress_ptr cinfo)
+{
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+
+/*
+ * Module initialization routine for 1-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_1pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_1_quant;
+ cquantize->pub.finish_pass = finish_pass_1_quant;
+ cquantize->pub.new_color_map = new_color_map_1_quant;
+ cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */
+ cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */
+
+ /* Make sure my internal arrays won't overflow */
+ if (cinfo->out_color_components > MAX_Q_COMPS)
+ ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
+
+ /* Create the colormap and color index table. */
+ create_colormap(cinfo);
+ create_colorindex(cinfo);
+
+ /* Allocate Floyd-Steinberg workspace now if requested.
+ * We do this now since it is FAR storage and may affect the memory
+ * manager's space calculations. If the user changes to FS dither
+ * mode in a later pass, we will allocate the space then, and will
+ * possibly overrun the max_memory_to_use setting.
+ */
+ if (cinfo->dither_mode == JDITHER_FS)
+ alloc_fs_workspace(cinfo);
+}
+
+#endif /* QUANT_1PASS_SUPPORTED */
diff --git a/gs/jpeg/jquant2.c b/gs/jpeg/jquant2.c
new file mode 100644
index 000000000..af601e334
--- /dev/null
+++ b/gs/jpeg/jquant2.c
@@ -0,0 +1,1310 @@
+/*
+ * jquant2.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 2-pass color quantization (color mapping) routines.
+ * These routines provide selection of a custom color map for an image,
+ * followed by mapping of the image to that color map, with optional
+ * Floyd-Steinberg dithering.
+ * It is also possible to use just the second pass to map to an arbitrary
+ * externally-given color map.
+ *
+ * Note: ordered dithering is not supported, since there isn't any fast
+ * way to compute intercolor distances; it's unclear that ordered dither's
+ * fundamental assumptions even hold with an irregularly spaced color map.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+
+/*
+ * This module implements the well-known Heckbert paradigm for color
+ * quantization. Most of the ideas used here can be traced back to
+ * Heckbert's seminal paper
+ * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display",
+ * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
+ *
+ * In the first pass over the image, we accumulate a histogram showing the
+ * usage count of each possible color. To keep the histogram to a reasonable
+ * size, we reduce the precision of the input; typical practice is to retain
+ * 5 or 6 bits per color, so that 8 or 4 different input values are counted
+ * in the same histogram cell.
+ *
+ * Next, the color-selection step begins with a box representing the whole
+ * color space, and repeatedly splits the "largest" remaining box until we
+ * have as many boxes as desired colors. Then the mean color in each
+ * remaining box becomes one of the possible output colors.
+ *
+ * The second pass over the image maps each input pixel to the closest output
+ * color (optionally after applying a Floyd-Steinberg dithering correction).
+ * This mapping is logically trivial, but making it go fast enough requires
+ * considerable care.
+ *
+ * Heckbert-style quantizers vary a good deal in their policies for choosing
+ * the "largest" box and deciding where to cut it. The particular policies
+ * used here have proved out well in experimental comparisons, but better ones
+ * may yet be found.
+ *
+ * In earlier versions of the IJG code, this module quantized in YCbCr color
+ * space, processing the raw upsampled data without a color conversion step.
+ * This allowed the color conversion math to be done only once per colormap
+ * entry, not once per pixel. However, that optimization precluded other
+ * useful optimizations (such as merging color conversion with upsampling)
+ * and it also interfered with desired capabilities such as quantizing to an
+ * externally-supplied colormap. We have therefore abandoned that approach.
+ * The present code works in the post-conversion color space, typically RGB.
+ *
+ * To improve the visual quality of the results, we actually work in scaled
+ * RGB space, giving G distances more weight than R, and R in turn more than
+ * B. To do everything in integer math, we must use integer scale factors.
+ * The 2/3/1 scale factors used here correspond loosely to the relative
+ * weights of the colors in the NTSC grayscale equation.
+ * If you want to use this code to quantize a non-RGB color space, you'll
+ * probably need to change these scale factors.
+ */
+
+#define R_SCALE 2 /* scale R distances by this much */
+#define G_SCALE 3 /* scale G distances by this much */
+#define B_SCALE 1 /* and B by this much */
+
+/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+ * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B
+ * and B,G,R orders. If you define some other weird order in jmorecfg.h,
+ * you'll get compile errors until you extend this logic. In that case
+ * you'll probably want to tweak the histogram sizes too.
+ */
+
+#if RGB_RED == 0
+#define C0_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 0
+#define C0_SCALE B_SCALE
+#endif
+#if RGB_GREEN == 1
+#define C1_SCALE G_SCALE
+#endif
+#if RGB_RED == 2
+#define C2_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 2
+#define C2_SCALE B_SCALE
+#endif
+
+
+/*
+ * First we have the histogram data structure and routines for creating it.
+ *
+ * The number of bits of precision can be adjusted by changing these symbols.
+ * We recommend keeping 6 bits for G and 5 each for R and B.
+ * If you have plenty of memory and cycles, 6 bits all around gives marginally
+ * better results; if you are short of memory, 5 bits all around will save
+ * some space but degrade the results.
+ * To maintain a fully accurate histogram, we'd need to allocate a "long"
+ * (preferably unsigned long) for each cell. In practice this is overkill;
+ * we can get by with 16 bits per cell. Few of the cell counts will overflow,
+ * and clamping those that do overflow to the maximum value will give close-
+ * enough results. This reduces the recommended histogram size from 256Kb
+ * to 128Kb, which is a useful savings on PC-class machines.
+ * (In the second pass the histogram space is re-used for pixel mapping data;
+ * in that capacity, each cell must be able to store zero to the number of
+ * desired colors. 16 bits/cell is plenty for that too.)
+ * Since the JPEG code is intended to run in small memory model on 80x86
+ * machines, we can't just allocate the histogram in one chunk. Instead
+ * of a true 3-D array, we use a row of pointers to 2-D arrays. Each
+ * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
+ * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that
+ * on 80x86 machines, the pointer row is in near memory but the actual
+ * arrays are in far memory (same arrangement as we use for image arrays).
+ */
+
+#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */
+
+/* These will do the right thing for either R,G,B or B,G,R color order,
+ * but you may not like the results for other color orders.
+ */
+#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */
+#define HIST_C1_BITS 6 /* bits of precision in G histogram */
+#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */
+
+/* Number of elements along histogram axes. */
+#define HIST_C0_ELEMS (1<<HIST_C0_BITS)
+#define HIST_C1_ELEMS (1<<HIST_C1_BITS)
+#define HIST_C2_ELEMS (1<<HIST_C2_BITS)
+
+/* These are the amounts to shift an input value to get a histogram index. */
+#define C0_SHIFT (BITS_IN_JSAMPLE-HIST_C0_BITS)
+#define C1_SHIFT (BITS_IN_JSAMPLE-HIST_C1_BITS)
+#define C2_SHIFT (BITS_IN_JSAMPLE-HIST_C2_BITS)
+
+
+typedef UINT16 histcell; /* histogram cell; prefer an unsigned type */
+
+typedef histcell FAR * histptr; /* for pointers to histogram cells */
+
+typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */
+typedef hist1d FAR * hist2d; /* type for the 2nd-level pointers */
+typedef hist2d * hist3d; /* type for top-level pointer */
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array has (#columns + 2) entries; the extra entry at
+ * each end saves us from special-casing the first and last pixels.
+ * Each entry is three values long, one value for each color component.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Space for the eventually created colormap is stashed here */
+ JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+ int desired; /* desired # of colors = size of colormap */
+
+ /* Variables for accumulating image statistics */
+ hist3d histogram; /* pointer to the histogram */
+
+ boolean needs_zeroed; /* TRUE if next pass must zero histogram */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+ int * error_limiter; /* table for clamping the applied error */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Prescan some rows of pixels.
+ * In this module the prescan simply updates the histogram, which has been
+ * initialized to zeroes by start_pass.
+ * An output_buf parameter is required by the method signature, but no data
+ * is actually output (in fact the buffer controller is probably passing a
+ * NULL pointer).
+ */
+
+METHODDEF(void)
+prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW ptr;
+ register histptr histp;
+ register hist3d histogram = cquantize->histogram;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptr = input_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the histogram */
+ histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
+ [GETJSAMPLE(ptr[1]) >> C1_SHIFT]
+ [GETJSAMPLE(ptr[2]) >> C2_SHIFT];
+ /* increment, check for overflow and undo increment if so. */
+ if (++(*histp) <= 0)
+ (*histp)--;
+ ptr += 3;
+ }
+ }
+}
+
+
+/*
+ * Next we have the really interesting routines: selection of a colormap
+ * given the completed histogram.
+ * These routines work with a list of "boxes", each representing a rectangular
+ * subset of the input color space (to histogram precision).
+ */
+
+typedef struct {
+ /* The bounds of the box (inclusive); expressed as histogram indexes */
+ int c0min, c0max;
+ int c1min, c1max;
+ int c2min, c2max;
+ /* The volume (actually 2-norm) of the box */
+ INT32 volume;
+ /* The number of nonzero histogram cells within this box */
+ long colorcount;
+} box;
+
+typedef box * boxptr;
+
+
+LOCAL(boxptr)
+find_biggest_color_pop (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest color population */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register long maxc = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->colorcount > maxc && boxp->volume > 0) {
+ which = boxp;
+ maxc = boxp->colorcount;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(boxptr)
+find_biggest_volume (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest (scaled) volume */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register INT32 maxv = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->volume > maxv) {
+ which = boxp;
+ maxv = boxp->volume;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(void)
+update_box (j_decompress_ptr cinfo, boxptr boxp)
+/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
+/* and recompute its volume and population */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ INT32 dist0,dist1,dist2;
+ long ccount;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ if (c0max > c0min)
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0min = c0min = c0;
+ goto have_c0min;
+ }
+ }
+ have_c0min:
+ if (c0max > c0min)
+ for (c0 = c0max; c0 >= c0min; c0--)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0max = c0max = c0;
+ goto have_c0max;
+ }
+ }
+ have_c0max:
+ if (c1max > c1min)
+ for (c1 = c1min; c1 <= c1max; c1++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1min = c1min = c1;
+ goto have_c1min;
+ }
+ }
+ have_c1min:
+ if (c1max > c1min)
+ for (c1 = c1max; c1 >= c1min; c1--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1max = c1max = c1;
+ goto have_c1max;
+ }
+ }
+ have_c1max:
+ if (c2max > c2min)
+ for (c2 = c2min; c2 <= c2max; c2++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2min = c2min = c2;
+ goto have_c2min;
+ }
+ }
+ have_c2min:
+ if (c2max > c2min)
+ for (c2 = c2max; c2 >= c2min; c2--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2max = c2max = c2;
+ goto have_c2max;
+ }
+ }
+ have_c2max:
+
+ /* Update box volume.
+ * We use 2-norm rather than real volume here; this biases the method
+ * against making long narrow boxes, and it has the side benefit that
+ * a box is splittable iff norm > 0.
+ * Since the differences are expressed in histogram-cell units,
+ * we have to shift back to JSAMPLE units to get consistent distances;
+ * after which, we scale according to the selected distance scale factors.
+ */
+ dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
+ dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
+ dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
+ boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;
+
+ /* Now scan remaining volume of box and compute population */
+ ccount = 0;
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++, histp++)
+ if (*histp != 0) {
+ ccount++;
+ }
+ }
+ boxp->colorcount = ccount;
+}
+
+
+LOCAL(int)
+median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,
+ int desired_colors)
+/* Repeatedly select and split the largest box until we have enough boxes */
+{
+ int n,lb;
+ int c0,c1,c2,cmax;
+ register boxptr b1,b2;
+
+ while (numboxes < desired_colors) {
+ /* Select box to split.
+ * Current algorithm: by population for first half, then by volume.
+ */
+ if (numboxes*2 <= desired_colors) {
+ b1 = find_biggest_color_pop(boxlist, numboxes);
+ } else {
+ b1 = find_biggest_volume(boxlist, numboxes);
+ }
+ if (b1 == NULL) /* no splittable boxes left! */
+ break;
+ b2 = &boxlist[numboxes]; /* where new box will go */
+ /* Copy the color bounds to the new box. */
+ b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
+ b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
+ /* Choose which axis to split the box on.
+ * Current algorithm: longest scaled axis.
+ * See notes in update_box about scaling distances.
+ */
+ c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
+ c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
+ c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
+ /* We want to break any ties in favor of green, then red, blue last.
+ * This code does the right thing for R,G,B or B,G,R color orders only.
+ */
+#if RGB_RED == 0
+ cmax = c1; n = 1;
+ if (c0 > cmax) { cmax = c0; n = 0; }
+ if (c2 > cmax) { n = 2; }
+#else
+ cmax = c1; n = 1;
+ if (c2 > cmax) { cmax = c2; n = 2; }
+ if (c0 > cmax) { n = 0; }
+#endif
+ /* Choose split point along selected axis, and update box bounds.
+ * Current algorithm: split at halfway point.
+ * (Since the box has been shrunk to minimum volume,
+ * any split will produce two nonempty subboxes.)
+ * Note that lb value is max for lower box, so must be < old max.
+ */
+ switch (n) {
+ case 0:
+ lb = (b1->c0max + b1->c0min) / 2;
+ b1->c0max = lb;
+ b2->c0min = lb+1;
+ break;
+ case 1:
+ lb = (b1->c1max + b1->c1min) / 2;
+ b1->c1max = lb;
+ b2->c1min = lb+1;
+ break;
+ case 2:
+ lb = (b1->c2max + b1->c2min) / 2;
+ b1->c2max = lb;
+ b2->c2min = lb+1;
+ break;
+ }
+ /* Update stats for boxes */
+ update_box(cinfo, b1);
+ update_box(cinfo, b2);
+ numboxes++;
+ }
+ return numboxes;
+}
+
+
+LOCAL(void)
+compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
+/* Compute representative color for a box, put it in colormap[icolor] */
+{
+ /* Current algorithm: mean weighted by pixels (not colors) */
+ /* Note it is important to get the rounding correct! */
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ long count;
+ long total = 0;
+ long c0total = 0;
+ long c1total = 0;
+ long c2total = 0;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++) {
+ if ((count = *histp++) != 0) {
+ total += count;
+ c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count;
+ c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count;
+ c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count;
+ }
+ }
+ }
+
+ cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);
+ cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);
+ cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);
+}
+
+
+LOCAL(void)
+select_colors (j_decompress_ptr cinfo, int desired_colors)
+/* Master routine for color selection */
+{
+ boxptr boxlist;
+ int numboxes;
+ int i;
+
+ /* Allocate workspace for box list */
+ boxlist = (boxptr) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));
+ /* Initialize one box containing whole space */
+ numboxes = 1;
+ boxlist[0].c0min = 0;
+ boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+ boxlist[0].c1min = 0;
+ boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+ boxlist[0].c2min = 0;
+ boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+ /* Shrink it to actually-used volume and set its statistics */
+ update_box(cinfo, & boxlist[0]);
+ /* Perform median-cut to produce final box list */
+ numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
+ /* Compute the representative color for each box, fill colormap */
+ for (i = 0; i < numboxes; i++)
+ compute_color(cinfo, & boxlist[i], i);
+ cinfo->actual_number_of_colors = numboxes;
+ TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
+}
+
+
+/*
+ * These routines are concerned with the time-critical task of mapping input
+ * colors to the nearest color in the selected colormap.
+ *
+ * We re-use the histogram space as an "inverse color map", essentially a
+ * cache for the results of nearest-color searches. All colors within a
+ * histogram cell will be mapped to the same colormap entry, namely the one
+ * closest to the cell's center. This may not be quite the closest entry to
+ * the actual input color, but it's almost as good. A zero in the cache
+ * indicates we haven't found the nearest color for that cell yet; the array
+ * is cleared to zeroes before starting the mapping pass. When we find the
+ * nearest color for a cell, its colormap index plus one is recorded in the
+ * cache for future use. The pass2 scanning routines call fill_inverse_cmap
+ * when they need to use an unfilled entry in the cache.
+ *
+ * Our method of efficiently finding nearest colors is based on the "locally
+ * sorted search" idea described by Heckbert and on the incremental distance
+ * calculation described by Spencer W. Thomas in chapter III.1 of Graphics
+ * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that
+ * the distances from a given colormap entry to each cell of the histogram can
+ * be computed quickly using an incremental method: the differences between
+ * distances to adjacent cells themselves differ by a constant. This allows a
+ * fairly fast implementation of the "brute force" approach of computing the
+ * distance from every colormap entry to every histogram cell. Unfortunately,
+ * it needs a work array to hold the best-distance-so-far for each histogram
+ * cell (because the inner loop has to be over cells, not colormap entries).
+ * The work array elements have to be INT32s, so the work array would need
+ * 256Kb at our recommended precision. This is not feasible in DOS machines.
+ *
+ * To get around these problems, we apply Thomas' method to compute the
+ * nearest colors for only the cells within a small subbox of the histogram.
+ * The work array need be only as big as the subbox, so the memory usage
+ * problem is solved. Furthermore, we need not fill subboxes that are never
+ * referenced in pass2; many images use only part of the color gamut, so a
+ * fair amount of work is saved. An additional advantage of this
+ * approach is that we can apply Heckbert's locality criterion to quickly
+ * eliminate colormap entries that are far away from the subbox; typically
+ * three-fourths of the colormap entries are rejected by Heckbert's criterion,
+ * and we need not compute their distances to individual cells in the subbox.
+ * The speed of this approach is heavily influenced by the subbox size: too
+ * small means too much overhead, too big loses because Heckbert's criterion
+ * can't eliminate as many colormap entries. Empirically the best subbox
+ * size seems to be about 1/512th of the histogram (1/8th in each direction).
+ *
+ * Thomas' article also describes a refined method which is asymptotically
+ * faster than the brute-force method, but it is also far more complex and
+ * cannot efficiently be applied to small subboxes. It is therefore not
+ * useful for programs intended to be portable to DOS machines. On machines
+ * with plenty of memory, filling the whole histogram in one shot with Thomas'
+ * refined method might be faster than the present code --- but then again,
+ * it might not be any faster, and it's certainly more complicated.
+ */
+
+
+/* log2(histogram cells in update box) for each axis; this can be adjusted */
+#define BOX_C0_LOG (HIST_C0_BITS-3)
+#define BOX_C1_LOG (HIST_C1_BITS-3)
+#define BOX_C2_LOG (HIST_C2_BITS-3)
+
+#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */
+#define BOX_C1_ELEMS (1<<BOX_C1_LOG)
+#define BOX_C2_ELEMS (1<<BOX_C2_LOG)
+
+#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG)
+#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG)
+#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG)
+
+
+/*
+ * The next three routines implement inverse colormap filling. They could
+ * all be folded into one big routine, but splitting them up this way saves
+ * some stack space (the mindist[] and bestdist[] arrays need not coexist)
+ * and may allow some compilers to produce better code by registerizing more
+ * inner-loop variables.
+ */
+
+LOCAL(int)
+find_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ JSAMPLE colorlist[])
+/* Locate the colormap entries close enough to an update box to be candidates
+ * for the nearest entry to some cell(s) in the update box. The update box
+ * is specified by the center coordinates of its first cell. The number of
+ * candidate colormap entries is returned, and their colormap indexes are
+ * placed in colorlist[].
+ * This routine uses Heckbert's "locally sorted search" criterion to select
+ * the colors that need further consideration.
+ */
+{
+ int numcolors = cinfo->actual_number_of_colors;
+ int maxc0, maxc1, maxc2;
+ int centerc0, centerc1, centerc2;
+ int i, x, ncolors;
+ INT32 minmaxdist, min_dist, max_dist, tdist;
+ INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
+
+ /* Compute true coordinates of update box's upper corner and center.
+ * Actually we compute the coordinates of the center of the upper-corner
+ * histogram cell, which are the upper bounds of the volume we care about.
+ * Note that since ">>" rounds down, the "center" values may be closer to
+ * min than to max; hence comparisons to them must be "<=", not "<".
+ */
+ maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
+ centerc0 = (minc0 + maxc0) >> 1;
+ maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
+ centerc1 = (minc1 + maxc1) >> 1;
+ maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
+ centerc2 = (minc2 + maxc2) >> 1;
+
+ /* For each color in colormap, find:
+ * 1. its minimum squared-distance to any point in the update box
+ * (zero if color is within update box);
+ * 2. its maximum squared-distance to any point in the update box.
+ * Both of these can be found by considering only the corners of the box.
+ * We save the minimum distance for each color in mindist[];
+ * only the smallest maximum distance is of interest.
+ */
+ minmaxdist = 0x7FFFFFFFL;
+
+ for (i = 0; i < numcolors; i++) {
+ /* We compute the squared-c0-distance term, then add in the other two. */
+ x = GETJSAMPLE(cinfo->colormap[0][i]);
+ if (x < minc0) {
+ tdist = (x - minc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else if (x > maxc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ min_dist = 0;
+ if (x <= centerc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[1][i]);
+ if (x < minc1) {
+ tdist = (x - minc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[2][i]);
+ if (x < minc2) {
+ tdist = (x - minc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ mindist[i] = min_dist; /* save away the results */
+ if (max_dist < minmaxdist)
+ minmaxdist = max_dist;
+ }
+
+ /* Now we know that no cell in the update box is more than minmaxdist
+ * away from some colormap entry. Therefore, only colors that are
+ * within minmaxdist of some part of the box need be considered.
+ */
+ ncolors = 0;
+ for (i = 0; i < numcolors; i++) {
+ if (mindist[i] <= minmaxdist)
+ colorlist[ncolors++] = (JSAMPLE) i;
+ }
+ return ncolors;
+}
+
+
+LOCAL(void)
+find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+/* Find the closest colormap entry for each cell in the update box,
+ * given the list of candidate colors prepared by find_nearby_colors.
+ * Return the indexes of the closest entries in the bestcolor[] array.
+ * This routine uses Thomas' incremental distance calculation method to
+ * find the distance from a colormap entry to successive cells in the box.
+ */
+{
+ int ic0, ic1, ic2;
+ int i, icolor;
+ register INT32 * bptr; /* pointer into bestdist[] array */
+ JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ INT32 dist0, dist1; /* initial distance values */
+ register INT32 dist2; /* current distance in inner loop */
+ INT32 xx0, xx1; /* distance increments */
+ register INT32 xx2;
+ INT32 inc0, inc1, inc2; /* initial values for increments */
+ /* This array holds the distance to the nearest-so-far color for each cell */
+ INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Initialize best-distance for each cell of the update box */
+ bptr = bestdist;
+ for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)
+ *bptr++ = 0x7FFFFFFFL;
+
+ /* For each color selected by find_nearby_colors,
+ * compute its distance to the center of each cell in the box.
+ * If that's less than best-so-far, update best distance and color number.
+ */
+
+ /* Nominal steps between cell centers ("x" in Thomas article) */
+#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE)
+#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE)
+#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE)
+
+ for (i = 0; i < numcolors; i++) {
+ icolor = GETJSAMPLE(colorlist[i]);
+ /* Compute (square of) distance from minc0/c1/c2 to this color */
+ inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
+ dist0 = inc0*inc0;
+ inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
+ dist0 += inc1*inc1;
+ inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
+ dist0 += inc2*inc2;
+ /* Form the initial difference increments */
+ inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
+ inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
+ inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
+ /* Now loop over all cells in box, updating distance per Thomas method */
+ bptr = bestdist;
+ cptr = bestcolor;
+ xx0 = inc0;
+ for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {
+ dist1 = dist0;
+ xx1 = inc1;
+ for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {
+ dist2 = dist1;
+ xx2 = inc2;
+ for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {
+ if (dist2 < *bptr) {
+ *bptr = dist2;
+ *cptr = (JSAMPLE) icolor;
+ }
+ dist2 += xx2;
+ xx2 += 2 * STEP_C2 * STEP_C2;
+ bptr++;
+ cptr++;
+ }
+ dist1 += xx1;
+ xx1 += 2 * STEP_C1 * STEP_C1;
+ }
+ dist0 += xx0;
+ xx0 += 2 * STEP_C0 * STEP_C0;
+ }
+ }
+}
+
+
+LOCAL(void)
+fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)
+/* Fill the inverse-colormap entries in the update box that contains */
+/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */
+/* we can fill as many others as we wish.) */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int minc0, minc1, minc2; /* lower left corner of update box */
+ int ic0, ic1, ic2;
+ register JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ register histptr cachep; /* pointer into main cache array */
+ /* This array lists the candidate colormap indexes. */
+ JSAMPLE colorlist[MAXNUMCOLORS];
+ int numcolors; /* number of candidate colors */
+ /* This array holds the actually closest colormap index for each cell. */
+ JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Convert cell coordinates to update box ID */
+ c0 >>= BOX_C0_LOG;
+ c1 >>= BOX_C1_LOG;
+ c2 >>= BOX_C2_LOG;
+
+ /* Compute true coordinates of update box's origin corner.
+ * Actually we compute the coordinates of the center of the corner
+ * histogram cell, which are the lower bounds of the volume we care about.
+ */
+ minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
+ minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
+ minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
+
+ /* Determine which colormap entries are close enough to be candidates
+ * for the nearest entry to some cell in the update box.
+ */
+ numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+ /* Determine the actually nearest colors. */
+ find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
+ bestcolor);
+
+ /* Save the best color numbers (plus 1) in the main cache array */
+ c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */
+ c1 <<= BOX_C1_LOG;
+ c2 <<= BOX_C2_LOG;
+ cptr = bestcolor;
+ for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
+ for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
+ cachep = & histogram[c0+ic0][c1+ic1][c2];
+ for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
+ *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
+ }
+ }
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+pass2_no_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register JSAMPROW inptr, outptr;
+ register histptr cachep;
+ register int c0, c1, c2;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the cache */
+ c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
+ c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
+ c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
+ cachep = & histogram[c0][c1][c2];
+ /* If we have not seen this color before, find nearest colormap entry */
+ /* and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, c0,c1,c2);
+ /* Now emit the colormap index for this cell */
+ *outptr++ = (JSAMPLE) (*cachep - 1);
+ }
+ }
+}
+
+
+METHODDEF(void)
+pass2_fs_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */
+ LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
+ LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ JSAMPROW inptr; /* => current input pixel */
+ JSAMPROW outptr; /* => current output pixel */
+ histptr cachep;
+ int dir; /* +1 or -1 depending on direction */
+ int dir3; /* 3*dir, for advancing inptr & errorptr */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ int *error_limit = cquantize->error_limiter;
+ JSAMPROW colormap0 = cinfo->colormap[0];
+ JSAMPROW colormap1 = cinfo->colormap[1];
+ JSAMPROW colormap2 = cinfo->colormap[2];
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ inptr += (width-1) * 3; /* so point to rightmost pixel */
+ outptr += width-1;
+ dir = -1;
+ dir3 = -3;
+ errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */
+ cquantize->on_odd_row = FALSE; /* flip for next time */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dir3 = 3;
+ errorptr = cquantize->fserrors; /* => entry before first real column */
+ cquantize->on_odd_row = TRUE; /* flip for next time */
+ }
+ /* Preset error values: no error propagated to first pixel from left */
+ cur0 = cur1 = cur2 = 0;
+ /* and no error propagated to row below yet */
+ belowerr0 = belowerr1 = belowerr2 = 0;
+ bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
+ for (col = width; col > 0; col--) {
+ /* curN holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
+ cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
+ cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
+ /* Limit the error using transfer function set by init_error_limit.
+ * See comments with init_error_limit for rationale.
+ */
+ cur0 = error_limit[cur0];
+ cur1 = error_limit[cur1];
+ cur2 = error_limit[cur2];
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+ * this sets the required size of the range_limit array.
+ */
+ cur0 += GETJSAMPLE(inptr[0]);
+ cur1 += GETJSAMPLE(inptr[1]);
+ cur2 += GETJSAMPLE(inptr[2]);
+ cur0 = GETJSAMPLE(range_limit[cur0]);
+ cur1 = GETJSAMPLE(range_limit[cur1]);
+ cur2 = GETJSAMPLE(range_limit[cur2]);
+ /* Index into the cache with adjusted pixel value */
+ cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];
+ /* If we have not seen this color before, find nearest colormap */
+ /* entry and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);
+ /* Now emit the colormap index for this cell */
+ { register int pixcode = *cachep - 1;
+ *outptr = (JSAMPLE) pixcode;
+ /* Compute representation error for this pixel */
+ cur0 -= GETJSAMPLE(colormap0[pixcode]);
+ cur1 -= GETJSAMPLE(colormap1[pixcode]);
+ cur2 -= GETJSAMPLE(colormap2[pixcode]);
+ }
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ { register LOCFSERROR bnexterr, delta;
+
+ bnexterr = cur0; /* Process component 0 */
+ delta = cur0 * 2;
+ cur0 += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+ cur0 += delta; /* form error * 5 */
+ bpreverr0 = belowerr0 + cur0;
+ belowerr0 = bnexterr;
+ cur0 += delta; /* form error * 7 */
+ bnexterr = cur1; /* Process component 1 */
+ delta = cur1 * 2;
+ cur1 += delta; /* form error * 3 */
+ errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+ cur1 += delta; /* form error * 5 */
+ bpreverr1 = belowerr1 + cur1;
+ belowerr1 = bnexterr;
+ cur1 += delta; /* form error * 7 */
+ bnexterr = cur2; /* Process component 2 */
+ delta = cur2 * 2;
+ cur2 += delta; /* form error * 3 */
+ errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+ cur2 += delta; /* form error * 5 */
+ bpreverr2 = belowerr2 + cur2;
+ belowerr2 = bnexterr;
+ cur2 += delta; /* form error * 7 */
+ }
+ /* At this point curN contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ inptr += dir3; /* Advance pixel pointers to next column */
+ outptr += dir;
+ errorptr += dir3; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error values into the
+ * final fserrors[] entry. Note we need not unload belowerrN because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
+ errorptr[1] = (FSERROR) bpreverr1;
+ errorptr[2] = (FSERROR) bpreverr2;
+ }
+}
+
+
+/*
+ * Initialize the error-limiting transfer function (lookup table).
+ * The raw F-S error computation can potentially compute error values of up to
+ * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
+ * much less, otherwise obviously wrong pixels will be created. (Typical
+ * effects include weird fringes at color-area boundaries, isolated bright
+ * pixels in a dark area, etc.) The standard advice for avoiding this problem
+ * is to ensure that the "corners" of the color cube are allocated as output
+ * colors; then repeated errors in the same direction cannot cause cascading
+ * error buildup. However, that only prevents the error from getting
+ * completely out of hand; Aaron Giles reports that error limiting improves
+ * the results even with corner colors allocated.
+ * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * well, but the smoother transfer function used below is even better. Thanks
+ * to Aaron Giles for this idea.
+ */
+
+LOCAL(void)
+init_error_limit (j_decompress_ptr cinfo)
+/* Allocate and fill in the error_limiter table */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ int * table;
+ int in, out;
+
+ table = (int *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));
+ table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+ cquantize->error_limiter = table;
+
+#define STEPSIZE ((MAXJSAMPLE+1)/16)
+ /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+ out = 0;
+ for (in = 0; in < STEPSIZE; in++, out++) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+ for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
+ for (; in <= MAXJSAMPLE; in++) {
+ table[in] = out; table[-in] = -out;
+ }
+#undef STEPSIZE
+}
+
+
+/*
+ * Finish up at the end of each pass.
+ */
+
+METHODDEF(void)
+finish_pass1 (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Select the representative colors and fill in cinfo->colormap */
+ cinfo->colormap = cquantize->sv_colormap;
+ select_colors(cinfo, cquantize->desired);
+ /* Force next pass to zero the color index table */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+METHODDEF(void)
+finish_pass2 (j_decompress_ptr cinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * Initialize for each processing pass.
+ */
+
+METHODDEF(void)
+start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int i;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ if (is_pre_scan) {
+ /* Set up method pointers */
+ cquantize->pub.color_quantize = prescan_quantize;
+ cquantize->pub.finish_pass = finish_pass1;
+ cquantize->needs_zeroed = TRUE; /* Always zero histogram */
+ } else {
+ /* Set up method pointers */
+ if (cinfo->dither_mode == JDITHER_FS)
+ cquantize->pub.color_quantize = pass2_fs_dither;
+ else
+ cquantize->pub.color_quantize = pass2_no_dither;
+ cquantize->pub.finish_pass = finish_pass2;
+
+ /* Make sure color count is acceptable */
+ i = cinfo->actual_number_of_colors;
+ if (i < 1)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
+ if (i > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+
+ if (cinfo->dither_mode == JDITHER_FS) {
+ size_t arraysize = (size_t) ((cinfo->output_width + 2) *
+ (3 * SIZEOF(FSERROR)));
+ /* Allocate Floyd-Steinberg workspace if we didn't already. */
+ if (cquantize->fserrors == NULL)
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ /* Initialize the propagated errors to zero. */
+ jzero_far((void FAR *) cquantize->fserrors, arraysize);
+ /* Make the error-limit table if we didn't already. */
+ if (cquantize->error_limiter == NULL)
+ init_error_limit(cinfo);
+ cquantize->on_odd_row = FALSE;
+ }
+
+ }
+ /* Zero the histogram or inverse color map, if necessary */
+ if (cquantize->needs_zeroed) {
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ jzero_far((void FAR *) histogram[i],
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = FALSE;
+ }
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+METHODDEF(void)
+new_color_map_2_quant (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Reset the inverse color map */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+/*
+ * Module initialization routine for 2-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_2pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+ int i;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_2_quant;
+ cquantize->pub.new_color_map = new_color_map_2_quant;
+ cquantize->fserrors = NULL; /* flag optional arrays not allocated */
+ cquantize->error_limiter = NULL;
+
+ /* Make sure jdmaster didn't give me a case I can't handle */
+ if (cinfo->out_color_components != 3)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
+ /* Allocate the histogram/inverse colormap storage */
+ cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
+
+ /* Allocate storage for the completed colormap, if required.
+ * We do this now since it is FAR storage and may affect
+ * the memory manager's space calculations.
+ */
+ if (cinfo->enable_2pass_quant) {
+ /* Make sure color count is acceptable */
+ int desired = cinfo->desired_number_of_colors;
+ /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
+ if (desired < 8)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (desired > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+ cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
+ cquantize->desired = desired;
+ } else
+ cquantize->sv_colormap = NULL;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ /* Allocate Floyd-Steinberg workspace if necessary.
+ * This isn't really needed until pass 2, but again it is FAR storage.
+ * Although we will cope with a later change in dither_mode,
+ * we do not promise to honor max_memory_to_use if dither_mode changes.
+ */
+ if (cinfo->dither_mode == JDITHER_FS) {
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR))));
+ /* Might as well create the error-limiting table too. */
+ init_error_limit(cinfo);
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/gs/jpeg/jutils.c b/gs/jpeg/jutils.c
new file mode 100644
index 000000000..d18a95556
--- /dev/null
+++ b/gs/jpeg/jutils.c
@@ -0,0 +1,179 @@
+/*
+ * jutils.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains tables and miscellaneous utility routines needed
+ * for both compression and decompression.
+ * Note we prefix all global names with "j" to minimize conflicts with
+ * a surrounding application.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
+ * of a DCT block read in natural order (left to right, top to bottom).
+ */
+
+#if 0 /* This table is not actually needed in v6a */
+
+const int jpeg_zigzag_order[DCTSIZE2] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#endif
+
+/*
+ * jpeg_natural_order[i] is the natural-order position of the i'th element
+ * of zigzag order.
+ *
+ * When reading corrupted data, the Huffman decoders could attempt
+ * to reference an entry beyond the end of this array (if the decoded
+ * zero run length reaches past the end of the block). To prevent
+ * wild stores without adding an inner-loop test, we put some extra
+ * "63"s after the real entries. This will cause the extra coefficient
+ * to be stored in location 63 of the block, not somewhere random.
+ * The worst case would be a run-length of 15, which means we need 16
+ * fake entries.
+ */
+
+const int jpeg_natural_order[DCTSIZE2+16] = {
+ 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,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+/*
+ * Arithmetic utilities
+ */
+
+GLOBAL(long)
+jdiv_round_up (long a, long b)
+/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
+/* Assumes a >= 0, b > 0 */
+{
+ return (a + b - 1L) / b;
+}
+
+
+GLOBAL(long)
+jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+ a += b - 1L;
+ return a - (a % b);
+}
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays. This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model. However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries. These will be used if USE_FMEM is defined.
+ * Otherwise, the routines below do it the hard way. (The performance cost
+ * is not all that great, because these routines aren't very heavily used.)
+ */
+
+#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */
+#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size)
+#define FMEMZERO(target,size) MEMZERO(target,size)
+#else /* 80x86 case, define if we can */
+#ifdef USE_FMEM
+#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
+#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size))
+#endif
+#endif
+
+
+GLOBAL(void)
+jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols)
+/* Copy some rows of samples from one place to another.
+ * num_rows rows are copied from input_array[source_row++]
+ * to output_array[dest_row++]; these areas may overlap for duplication.
+ * The source and destination arrays must be at least as wide as num_cols.
+ */
+{
+ register JSAMPROW inptr, outptr;
+#ifdef FMEMCOPY
+ register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
+#else
+ register JDIMENSION count;
+#endif
+ register int row;
+
+ input_array += source_row;
+ output_array += dest_row;
+
+ for (row = num_rows; row > 0; row--) {
+ inptr = *input_array++;
+ outptr = *output_array++;
+#ifdef FMEMCOPY
+ FMEMCOPY(outptr, inptr, count);
+#else
+ for (count = num_cols; count > 0; count--)
+ *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */
+#endif
+ }
+}
+
+
+GLOBAL(void)
+jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks)
+/* Copy a row of coefficient blocks from one place to another. */
+{
+#ifdef FMEMCOPY
+ FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
+#else
+ register JCOEFPTR inptr, outptr;
+ register long count;
+
+ inptr = (JCOEFPTR) input_row;
+ outptr = (JCOEFPTR) output_row;
+ for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
+ *outptr++ = *inptr++;
+ }
+#endif
+}
+
+
+GLOBAL(void)
+jzero_far (void FAR * target, size_t bytestozero)
+/* Zero out a chunk of FAR memory. */
+/* This might be sample-array data, block-array data, or alloc_large data. */
+{
+#ifdef FMEMZERO
+ FMEMZERO(target, bytestozero);
+#else
+ register char FAR * ptr = (char FAR *) target;
+ register size_t count;
+
+ for (count = bytestozero; count > 0; count--) {
+ *ptr++ = 0;
+ }
+#endif
+}
diff --git a/gs/jpeg/jversion.h b/gs/jpeg/jversion.h
new file mode 100644
index 000000000..b903be7d4
--- /dev/null
+++ b/gs/jpeg/jversion.h
@@ -0,0 +1,14 @@
+/*
+ * jversion.h
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains software version identification.
+ */
+
+
+#define JVERSION "6a 7-Feb-96"
+
+#define JCOPYRIGHT "Copyright (C) 1996, Thomas G. Lane"
diff --git a/gs/jpeg/libjpeg.a b/gs/jpeg/libjpeg.a
new file mode 100644
index 000000000..97ba0b1bd
--- /dev/null
+++ b/gs/jpeg/libjpeg.a
Binary files differ
diff --git a/gs/jpeg/libjpeg.doc b/gs/jpeg/libjpeg.doc
new file mode 100644
index 000000000..b3333a8ef
--- /dev/null
+++ b/gs/jpeg/libjpeg.doc
@@ -0,0 +1,2772 @@
+USING THE IJG JPEG LIBRARY
+
+Copyright (C) 1994-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file describes how to use the IJG JPEG library within an application
+program. Read it if you want to write a program that uses the library.
+
+The file example.c provides heavily commented skeleton code for calling the
+JPEG library. Also see jpeglib.h (the include file to be used by application
+programs) for full details about data structures and function parameter lists.
+The library source code, of course, is the ultimate reference.
+
+Note that there have been *major* changes from the application interface
+presented by IJG version 4 and earlier versions. The old design had several
+inherent limitations, and it had accumulated a lot of cruft as we added
+features while trying to minimize application-interface changes. We have
+sacrificed backward compatibility in the version 5 rewrite, but we think the
+improvements justify this.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Overview:
+ Functions provided by the library
+ Outline of typical usage
+Basic library usage:
+ Data formats
+ Compression details
+ Decompression details
+ Mechanics of usage: include files, linking, etc
+Advanced features:
+ Compression parameter selection
+ Decompression parameter selection
+ Special color spaces
+ Error handling
+ Compressed data handling (source and destination managers)
+ I/O suspension
+ Progressive JPEG support
+ Buffered-image mode
+ Abbreviated datastreams and multiple images
+ Special markers
+ Raw (downsampled) image data
+ Really raw data: DCT coefficients
+ Progress monitoring
+ Memory management
+ Library compile-time options
+ Portability considerations
+ Notes for MS-DOS implementors
+
+You should read at least the overview and basic usage sections before trying
+to program with the library. The sections on advanced features can be read
+if and when you need them.
+
+
+OVERVIEW
+========
+
+Functions provided by the library
+---------------------------------
+
+The IJG JPEG library provides C code to read and write JPEG-compressed image
+files. The surrounding application program receives or supplies image data a
+scanline at a time, using a straightforward uncompressed image format. All
+details of color conversion and other preprocessing/postprocessing can be
+handled by the library.
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG. These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression. They include colorspace conversion, downsampling/upsampling,
+and color quantization. The application indirectly selects use of this code
+by specifying the format in which it wishes to supply or receive image data.
+For example, if colormapped output is requested, then the decompression
+library automatically invokes color quantization.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing. The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation. On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical. It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+A word about functions *not* provided by the library. We handle a subset of
+the ISO JPEG standard; most baseline, extended-sequential, and progressive
+JPEG processes are supported. (Our subset includes all features now in common
+use.) Unsupported ISO options include:
+ * Hierarchical storage
+ * Lossless JPEG
+ * Arithmetic entropy coding (unsupported for legal reasons)
+ * DNL marker
+ * Nonintegral subsampling ratios
+We support both 8- and 12-bit data precision, but this is a compile-time
+choice rather than a run-time choice; hence it is difficult to use both
+precisions in a single application.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format. The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats. (For example, this library is
+used by the free LIBTIFF library to support JPEG compression in TIFF.)
+
+
+Outline of typical usage
+------------------------
+
+The rough outline of a JPEG compression operation is:
+
+ Allocate and initialize a JPEG compression object
+ Specify the destination for the compressed data (eg, a file)
+ Set parameters for compression, including image size & colorspace
+ jpeg_start_compress(...);
+ while (scan lines remain to be written)
+ jpeg_write_scanlines(...);
+ jpeg_finish_compress(...);
+ Release the JPEG compression object
+
+A JPEG compression object holds parameters and working state for the JPEG
+library. We make creation/destruction of the object separate from starting
+or finishing compression of an image; the same object can be re-used for a
+series of image compression operations. This makes it easy to re-use the
+same parameter settings for a sequence of images. Re-use of a JPEG object
+also has important implications for processing abbreviated JPEG datastreams,
+as discussed later.
+
+The image data to be compressed is supplied to jpeg_write_scanlines() from
+in-memory buffers. If the application is doing file-to-file compression,
+reading image data from the source file is the application's responsibility.
+The library emits compressed data by calling a "data destination manager",
+which typically will write the data into a file; but the application can
+provide its own destination manager to do something else.
+
+Similarly, the rough outline of a JPEG decompression operation is:
+
+ Allocate and initialize a JPEG decompression object
+ Specify the source of the compressed data (eg, a file)
+ Call jpeg_read_header() to obtain image info
+ Set parameters for decompression
+ jpeg_start_decompress(...);
+ while (scan lines remain to be read)
+ jpeg_read_scanlines(...);
+ jpeg_finish_decompress(...);
+ Release the JPEG decompression object
+
+This is comparable to the compression outline except that reading the
+datastream header is a separate step. This is helpful because information
+about the image's size, colorspace, etc is available when the application
+selects decompression parameters. For example, the application can choose an
+output scaling ratio that will fit the image into the available screen size.
+
+The decompression library obtains compressed data by calling a data source
+manager, which typically will read the data from a file; but other behaviors
+can be obtained with a custom source manager. Decompressed data is delivered
+into in-memory buffers passed to jpeg_read_scanlines().
+
+It is possible to abort an incomplete compression or decompression operation
+by calling jpeg_abort(); or, if you do not need to retain the JPEG object,
+simply release it by calling jpeg_destroy().
+
+JPEG compression and decompression objects are two separate struct types.
+However, they share some common fields, and certain routines such as
+jpeg_destroy() can work on either type of object.
+
+The JPEG library has no static variables: all state is in the compression
+or decompression object. Therefore it is possible to process multiple
+compression and decompression operations concurrently, using multiple JPEG
+objects.
+
+Both compression and decompression can be done in an incremental memory-to-
+memory fashion, if suitable source/destination managers are used. See the
+section on "I/O suspension" for more details.
+
+
+BASIC LIBRARY USAGE
+===================
+
+Data formats
+------------
+
+Before diving into procedural details, it is helpful to understand the
+image data format that the JPEG library expects or returns.
+
+The standard input image format is a rectangular array of pixels, with each
+pixel having the same number of "component" or "sample" values (color
+channels). You must specify how many components there are and the colorspace
+interpretation of the components. Most applications will use RGB data
+(three components per pixel) or grayscale data (one component per pixel).
+PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE.
+A remarkable number of people manage to miss this, only to find that their
+programs don't work with grayscale JPEG files.
+
+There is no provision for colormapped input. JPEG files are always full-color
+or full grayscale (or sometimes another colorspace such as CMYK). You can
+feed in a colormapped image by expanding it to full-color format. However
+JPEG often doesn't work very well with source data that has been colormapped,
+because of dithering noise. This is discussed in more detail in the JPEG FAQ
+and the other references mentioned in the README file.
+
+Pixels are stored by scanlines, with each scanline running from left to
+right. The component values for each pixel are adjacent in the row; for
+example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an
+array of data type JSAMPLE --- which is typically "unsigned char", unless
+you've changed jmorecfg.h. (You can also change the RGB pixel layout, say
+to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in
+that file before doing so.)
+
+A 2-D array of pixels is formed by making a list of pointers to the starts of
+scanlines; so the scanlines need not be physically adjacent in memory. Even
+if you process just one scanline at a time, you must make a one-element
+pointer array to conform to this structure. Pointers to JSAMPLE rows are of
+type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY.
+
+The library accepts or supplies one or more complete scanlines per call.
+It is not possible to process part of a row at a time. Scanlines are always
+processed top-to-bottom. You can process an entire image in one call if you
+have it all in memory, but usually it's simplest to process one scanline at
+a time.
+
+For best results, source data values should have the precision specified by
+BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress
+data that's only 6 bits/channel, you should left-justify each value in a
+byte before passing it to the compressor. If you need to compress data
+that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12.
+(See "Library compile-time options", later.)
+
+
+The data format returned by the decompressor is the same in all details,
+except that colormapped output is supported. (Again, a JPEG file is never
+colormapped. But you can ask the decompressor to perform on-the-fly color
+quantization to deliver colormapped output.) If you request colormapped
+output then the returned data array contains a single JSAMPLE per pixel;
+its value is an index into a color map. The color map is represented as
+a 2-D JSAMPARRAY in which each row holds the values of one color component,
+that is, colormap[i][j] is the value of the i'th color component for pixel
+value (map index) j. Note that since the colormap indexes are stored in
+JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE
+(ie, at most 256 colors for an 8-bit JPEG library).
+
+
+Compression details
+-------------------
+
+Here we revisit the JPEG compression outline given in the overview.
+
+1. Allocate and initialize a JPEG compression object.
+
+A JPEG compression object is a "struct jpeg_compress_struct". (It also has
+a bunch of subsidiary structures which are allocated via malloc(), but the
+application doesn't control those directly.) This struct can be just a local
+variable in the calling routine, if a single routine is going to execute the
+whole JPEG compression sequence. Otherwise it can be static or allocated
+from malloc().
+
+You will also need a structure representing a JPEG error handler. The part
+of this that the library cares about is a "struct jpeg_error_mgr". If you
+are providing your own error handler, you'll typically want to embed the
+jpeg_error_mgr struct in a larger structure; this is discussed later under
+"Error handling". For now we'll assume you are just using the default error
+handler. The default error handler will print JPEG error/warning messages
+on stderr, and it will call exit() if a fatal error occurs.
+
+You must initialize the error handler structure, store a pointer to it into
+the JPEG object's "err" field, and then call jpeg_create_compress() to
+initialize the rest of the JPEG object.
+
+Typical code for this step, if you are using the default error handler, is
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ...
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+
+jpeg_create_compress allocates a small amount of memory, so it could fail
+if you are out of memory. In that case it will exit via the error handler;
+that's why the error handler must be initialized first.
+
+
+2. Specify the destination for the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library delivers compressed data to a
+"data destination" module. The library includes one data destination
+module which knows how to write to a stdio stream. You can use your own
+destination module if you want to do something else, as discussed later.
+
+If you use the standard destination module, you must open the target stdio
+stream beforehand. Typical code for this step looks like:
+
+ FILE * outfile;
+ ...
+ if ((outfile = fopen(filename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_dest(&cinfo, outfile);
+
+where the last line invokes the standard destination module.
+
+WARNING: it is critical that the binary compressed data be delivered to the
+output file unchanged. On non-Unix systems the stdio library may perform
+newline translation or otherwise corrupt binary data. To suppress this
+behavior, you may need to use a "b" option to fopen (as shown above), or use
+setmode() or another routine to put the stdio stream in binary mode. See
+cjpeg.c and djpeg.c for code that has been found to work on many systems.
+
+You can select the data destination after setting other parameters (step 3),
+if that's more convenient. You may not change the destination between
+calling jpeg_start_compress() and jpeg_finish_compress().
+
+
+3. Set parameters for compression, including image size & colorspace.
+
+You must supply information about the source image by setting the following
+fields in the JPEG object (cinfo structure):
+
+ image_width Width of image, in pixels
+ image_height Height of image, in pixels
+ input_components Number of color channels (samples per pixel)
+ in_color_space Color space of source image
+
+The image dimensions are, hopefully, obvious. JPEG supports image dimensions
+of 1 to 64K pixels in either direction. The input color space is typically
+RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special
+color spaces", later, for more info.) The in_color_space field must be
+assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or
+JCS_GRAYSCALE.
+
+JPEG has a large number of compression parameters that determine how the
+image is encoded. Most applications don't need or want to know about all
+these parameters. You can set all the parameters to reasonable defaults by
+calling jpeg_set_defaults(); then, if there are particular values you want
+to change, you can do so after that. The "Compression parameter selection"
+section tells about all the parameters.
+
+You must set in_color_space correctly before calling jpeg_set_defaults(),
+because the defaults depend on the source image colorspace. However the
+other three source image parameters need not be valid until you call
+jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more
+than once, if that happens to be convenient.
+
+Typical code for a 24-bit RGB source image is
+
+ cinfo.image_width = Width; /* image width and height, in pixels */
+ cinfo.image_height = Height;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+
+ jpeg_set_defaults(&cinfo);
+ /* Make optional parameter settings here */
+
+
+4. jpeg_start_compress(...);
+
+After you have established the data destination and set all the necessary
+source image info and other parameters, call jpeg_start_compress() to begin
+a compression cycle. This will initialize internal state, allocate working
+storage, and emit the first few bytes of the JPEG datastream header.
+
+Typical code:
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+The "TRUE" parameter ensures that a complete JPEG interchange datastream
+will be written. This is appropriate in most cases. If you think you might
+want to use an abbreviated datastream, read the section on abbreviated
+datastreams, below.
+
+Once you have called jpeg_start_compress(), you may not alter any JPEG
+parameters or other fields of the JPEG object until you have completed
+the compression cycle.
+
+
+5. while (scan lines remain to be written)
+ jpeg_write_scanlines(...);
+
+Now write all the required image data by calling jpeg_write_scanlines()
+one or more times. You can pass one or more scanlines in each call, up
+to the total image height. In most applications it is convenient to pass
+just one or a few scanlines at a time. The expected format for the passed
+data is discussed under "Data formats", above.
+
+Image data should be written in top-to-bottom scanline order. The JPEG spec
+contains some weasel wording about how top and bottom are application-defined
+terms (a curious interpretation of the English language...) but if you want
+your files to be compatible with everyone else's, you WILL use top-to-bottom
+order. If the source data must be read in bottom-to-top order, you can use
+the JPEG library's virtual array mechanism to invert the data efficiently.
+Examples of this can be found in the sample application cjpeg.
+
+The library maintains a count of the number of scanlines written so far
+in the next_scanline field of the JPEG object. Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.next_scanline < cinfo.image_height)".
+
+Code for this step depends heavily on the way that you store the source data.
+example.c shows the following code for the case of a full-size 2-D source
+array containing 3-byte RGB pixels:
+
+ JSAMPROW row_pointer[1]; /* pointer to a single row */
+ int row_stride; /* physical row width in buffer */
+
+ row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+jpeg_write_scanlines() returns the number of scanlines actually written.
+This will normally be equal to the number passed in, so you can usually
+ignore the return value. It is different in just two cases:
+ * If you try to write more scanlines than the declared image height,
+ the additional scanlines are ignored.
+ * If you use a suspending data destination manager, output buffer overrun
+ will cause the compressor to return before accepting all the passed lines.
+ This feature is discussed under "I/O suspension", below. The normal
+ stdio destination manager will NOT cause this to happen.
+In any case, the return value is the same as the change in the value of
+next_scanline.
+
+
+6. jpeg_finish_compress(...);
+
+After all the image data has been written, call jpeg_finish_compress() to
+complete the compression cycle. This step is ESSENTIAL to ensure that the
+last bufferload of data is written to the data destination.
+jpeg_finish_compress() also releases working memory associated with the JPEG
+object.
+
+Typical code:
+
+ jpeg_finish_compress(&cinfo);
+
+If using the stdio destination manager, don't forget to close the output
+stdio stream if necessary.
+
+If you have requested a multi-pass operating mode, such as Huffman code
+optimization, jpeg_finish_compress() will perform the additional passes using
+data buffered by the first pass. In this case jpeg_finish_compress() may take
+quite a while to complete. With the default compression parameters, this will
+not happen.
+
+It is an error to call jpeg_finish_compress() before writing the necessary
+total number of scanlines. If you wish to abort compression, call
+jpeg_abort() as discussed below.
+
+After completing a compression cycle, you may dispose of the JPEG object
+as discussed next, or you may use it to compress another image. In that case
+return to step 2, 3, or 4 as appropriate. If you do not change the
+destination manager, the new datastream will be written to the same target.
+If you do not change any JPEG parameters, the new datastream will be written
+with the same parameters as before. Note that you can change the input image
+dimensions freely between cycles, but if you change the input colorspace, you
+should call jpeg_set_defaults() to adjust for the new colorspace; and then
+you'll need to repeat all of step 3.
+
+
+7. Release the JPEG compression object.
+
+When you are done with a JPEG compression object, destroy it by calling
+jpeg_destroy_compress(). This will free all subsidiary memory. Or you can
+call jpeg_destroy() which works for either compression or decompression
+objects --- this may be more convenient if you are sharing code between
+compression and decompression cases. (Actually, these routines are equivalent
+except for the declared type of the passed pointer. To avoid gripes from
+ANSI C compilers, jpeg_destroy() should be passed a j_common_ptr.)
+
+If you allocated the jpeg_compress_struct structure from malloc(), freeing
+it is your responsibility --- jpeg_destroy() won't. Ditto for the error
+handler structure.
+
+Typical code:
+
+ jpeg_destroy_compress(&cinfo);
+
+
+8. Aborting.
+
+If you decide to abort a compression cycle before finishing, you can clean up
+in either of two ways:
+
+* If you don't need the JPEG object any more, just call
+ jpeg_destroy_compress() or jpeg_destroy() to release memory. This is
+ legitimate at any point after calling jpeg_create_compress() --- in fact,
+ it's safe even if jpeg_create_compress() fails.
+
+* If you want to re-use the JPEG object, call jpeg_abort_compress(), or
+ jpeg_abort() which works on both compression and decompression objects.
+ This will return the object to an idle state, releasing any working memory.
+ jpeg_abort() is allowed at any time after successful object creation.
+
+Note that cleaning up the data destination, if required, is your
+responsibility.
+
+
+Decompression details
+---------------------
+
+Here we revisit the JPEG decompression outline given in the overview.
+
+1. Allocate and initialize a JPEG decompression object.
+
+This is just like initialization for compression, as discussed above,
+except that the object is a "struct jpeg_decompress_struct" and you
+call jpeg_create_decompress(). Error handling is exactly the same.
+
+Typical code:
+
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ...
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+(Both here and in the IJG code, we usually use variable name "cinfo" for
+both compression and decompression objects.)
+
+
+2. Specify the source of the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library reads compressed data from a "data
+source" module. The library includes one data source module which knows how
+to read from a stdio stream. You can use your own source module if you want
+to do something else, as discussed later.
+
+If you use the standard source module, you must open the source stdio stream
+beforehand. Typical code for this step looks like:
+
+ FILE * infile;
+ ...
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_src(&cinfo, infile);
+
+where the last line invokes the standard source module.
+
+WARNING: it is critical that the binary compressed data be read unchanged.
+On non-Unix systems the stdio library may perform newline translation or
+otherwise corrupt binary data. To suppress this behavior, you may need to use
+a "b" option to fopen (as shown above), or use setmode() or another routine to
+put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that
+has been found to work on many systems.
+
+You may not change the data source between calling jpeg_read_header() and
+jpeg_finish_decompress(). If you wish to read a series of JPEG images from
+a single source file, you should repeat the jpeg_read_header() to
+jpeg_finish_decompress() sequence without reinitializing either the JPEG
+object or the data source module; this prevents buffered input data from
+being discarded.
+
+
+3. Call jpeg_read_header() to obtain image info.
+
+Typical code for this step is just
+
+ jpeg_read_header(&cinfo, TRUE);
+
+This will read the source datastream header markers, up to the beginning
+of the compressed data proper. On return, the image dimensions and other
+info have been stored in the JPEG object. The application may wish to
+consult this information before selecting decompression parameters.
+
+More complex code is necessary if
+ * A suspending data source is used --- in that case jpeg_read_header()
+ may return before it has read all the header data. See "I/O suspension",
+ below. The normal stdio source manager will NOT cause this to happen.
+ * Abbreviated JPEG files are to be processed --- see the section on
+ abbreviated datastreams. Standard applications that deal only in
+ interchange JPEG files need not be concerned with this case either.
+
+It is permissible to stop at this point if you just wanted to find out the
+image dimensions and other header info for a JPEG file. In that case,
+call jpeg_destroy() when you are done with the JPEG object, or call
+jpeg_abort() to return it to an idle state before selecting a new data
+source and reading another header.
+
+
+4. Set parameters for decompression.
+
+jpeg_read_header() sets appropriate default decompression parameters based on
+the properties of the image (in particular, its colorspace). However, you
+may well want to alter these defaults before beginning the decompression.
+For example, the default is to produce full color output from a color file.
+If you want colormapped output you must ask for it. Other options allow the
+returned image to be scaled and allow various speed/quality tradeoffs to be
+selected. "Decompression parameter selection", below, gives details.
+
+If the defaults are appropriate, nothing need be done at this step.
+
+Note that all default values are set by each call to jpeg_read_header().
+If you reuse a decompression object, you cannot expect your parameter
+settings to be preserved across cycles, as you can for compression.
+You must set desired parameter values each time.
+
+
+5. jpeg_start_decompress(...);
+
+Once the parameter values are satisfactory, call jpeg_start_decompress() to
+begin decompression. This will initialize internal state, allocate working
+memory, and prepare for returning data.
+
+Typical code is just
+
+ jpeg_start_decompress(&cinfo);
+
+If you have requested a multi-pass operating mode, such as 2-pass color
+quantization, jpeg_start_decompress() will do everything needed before data
+output can begin. In this case jpeg_start_decompress() may take quite a while
+to complete. With a single-scan (non progressive) JPEG file and default
+decompression parameters, this will not happen; jpeg_start_decompress() will
+return quickly.
+
+After this call, the final output image dimensions, including any requested
+scaling, are available in the JPEG object; so is the selected colormap, if
+colormapped output has been requested. Useful fields include
+
+ output_width image width and height, as scaled
+ output_height
+ out_color_components # of color components in out_color_space
+ output_components # of color components returned per pixel
+ colormap the selected colormap, if any
+ actual_number_of_colors number of entries in colormap
+
+output_components is 1 (a colormap index) when quantizing colors; otherwise it
+equals out_color_components. It is the number of JSAMPLE values that will be
+emitted per pixel in the output arrays.
+
+Typically you will need to allocate data buffers to hold the incoming image.
+You will need output_width * output_components JSAMPLEs per scanline in your
+output buffer, and a total of output_height scanlines will be returned.
+
+Note: if you are using the JPEG library's internal memory manager to allocate
+data buffers (as djpeg does), then the manager's protocol requires that you
+request large buffers *before* calling jpeg_start_decompress(). This is a
+little tricky since the output_XXX fields are not normally valid then. You
+can make them valid by calling jpeg_calc_output_dimensions() after setting the
+relevant parameters (scaling, output color space, and quantization flag).
+
+
+6. while (scan lines remain to be read)
+ jpeg_read_scanlines(...);
+
+Now you can read the decompressed image data by calling jpeg_read_scanlines()
+one or more times. At each call, you pass in the maximum number of scanlines
+to be read (ie, the height of your working buffer); jpeg_read_scanlines()
+will return up to that many lines. The return value is the number of lines
+actually read. The format of the returned data is discussed under "Data
+formats", above. Don't forget that grayscale and color JPEGs will return
+different data formats!
+
+Image data is returned in top-to-bottom scanline order. If you must write
+out the image in bottom-to-top order, you can use the JPEG library's virtual
+array mechanism to invert the data efficiently. Examples of this can be
+found in the sample application djpeg.
+
+The library maintains a count of the number of scanlines returned so far
+in the output_scanline field of the JPEG object. Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test
+should NOT be against image_height, unless you never use scaling. The
+image_height field is the height of the original unscaled image.)
+The return value always equals the change in the value of output_scanline.
+
+If you don't use a suspending data source, it is safe to assume that
+jpeg_read_scanlines() reads at least one scanline per call, until the
+bottom of the image has been reached.
+
+If you use a buffer larger than one scanline, it is NOT safe to assume that
+jpeg_read_scanlines() fills it. (The current implementation won't return
+more than cinfo.rec_outbuf_height scanlines per call, no matter how large
+a buffer you pass.) So you must always provide a loop that calls
+jpeg_read_scanlines() repeatedly until the whole image has been read.
+
+
+7. jpeg_finish_decompress(...);
+
+After all the image data has been read, call jpeg_finish_decompress() to
+complete the decompression cycle. This causes working memory associated
+with the JPEG object to be released.
+
+Typical code:
+
+ jpeg_finish_decompress(&cinfo);
+
+If using the stdio source manager, don't forget to close the source stdio
+stream if necessary.
+
+It is an error to call jpeg_finish_decompress() before reading the correct
+total number of scanlines. If you wish to abort compression, call
+jpeg_abort() as discussed below.
+
+After completing a decompression cycle, you may dispose of the JPEG object as
+discussed next, or you may use it to decompress another image. In that case
+return to step 2 or 3 as appropriate. If you do not change the source
+manager, the next image will be read from the same source.
+
+
+8. Release the JPEG decompression object.
+
+When you are done with a JPEG decompression object, destroy it by calling
+jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of
+destroying compression objects applies here too.
+
+Typical code:
+
+ jpeg_destroy_decompress(&cinfo);
+
+
+9. Aborting.
+
+You can abort a decompression cycle by calling jpeg_destroy_decompress() or
+jpeg_destroy() if you don't need the JPEG object any more, or
+jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object.
+The previous discussion of aborting compression cycles applies here too.
+
+
+Mechanics of usage: include files, linking, etc
+-----------------------------------------------
+
+Applications using the JPEG library should include the header file jpeglib.h
+to obtain declarations of data types and routines. Before including
+jpeglib.h, include system headers that define at least the typedefs FILE and
+size_t. On ANSI-conforming systems, including <stdio.h> is sufficient; on
+older Unix systems, you may need <sys/types.h> to define size_t.
+
+If the application needs to refer to individual JPEG library error codes, also
+include jerror.h to define those symbols.
+
+jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are
+installing the JPEG header files in a system directory, you will want to
+install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h.
+
+The most convenient way to include the JPEG code into your executable program
+is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix
+machines) and reference it at your link step. If you use only half of the
+library (only compression or only decompression), only that much code will be
+included from the library, unless your linker is hopelessly brain-damaged.
+The supplied makefiles build libjpeg.a automatically (see install.doc).
+
+On some systems your application may need to set up a signal handler to ensure
+that temporary files are deleted if the program is interrupted. This is most
+critical if you are on MS-DOS and use the jmemdos.c memory manager back end;
+it will try to grab extended memory for temp files, and that space will NOT be
+freed automatically. See cjpeg.c or djpeg.c for an example signal handler.
+
+It may be worth pointing out that the core JPEG library does not actually
+require the stdio library: only the default source/destination managers and
+error handler need it. You can use the library in a stdio-less environment
+if you replace those modules and use jmemnobs.c (or another memory manager of
+your own devising). More info about the minimum system library requirements
+may be found in jinclude.h.
+
+
+ADVANCED FEATURES
+=================
+
+Compression parameter selection
+-------------------------------
+
+This section describes all the optional parameters you can set for JPEG
+compression, as well as the "helper" routines provided to assist in this
+task. Proper setting of some parameters requires detailed understanding
+of the JPEG standard; if you don't know what a parameter is for, it's best
+not to mess with it! See REFERENCES in the README file for pointers to
+more info about JPEG.
+
+It's a good idea to call jpeg_set_defaults() first, even if you plan to set
+all the parameters; that way your code is more likely to work with future JPEG
+libraries that have additional parameters. For the same reason, we recommend
+you use a helper routine where one is provided, in preference to twiddling
+cinfo fields directly.
+
+The helper routines are:
+
+jpeg_set_defaults (j_compress_ptr cinfo)
+ This routine sets all JPEG parameters to reasonable defaults, using
+ only the input image's color space (field in_color_space, which must
+ already be set in cinfo). Many applications will only need to use
+ this routine and perhaps jpeg_set_quality().
+
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+ Sets the JPEG file's colorspace (field jpeg_color_space) as specified,
+ and sets other color-space-dependent parameters appropriately. See
+ "Special color spaces", below, before using this. A large number of
+ parameters, including all per-component parameters, are set by this
+ routine; if you want to twiddle individual parameters you should call
+ jpeg_set_colorspace() before rather than after.
+
+jpeg_default_colorspace (j_compress_ptr cinfo)
+ Selects an appropriate JPEG colorspace based on cinfo->in_color_space,
+ and calls jpeg_set_colorspace(). This is actually a subroutine of
+ jpeg_set_defaults(). It's broken out in case you want to change
+ just the colorspace-dependent JPEG parameters.
+
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+ Constructs JPEG quantization tables appropriate for the indicated
+ quality setting. The quality value is expressed on the 0..100 scale
+ recommended by IJG (cjpeg's "-quality" switch uses this routine).
+ Note that the exact mapping from quality values to tables may change
+ in future IJG releases as more is learned about DCT quantization.
+ If the force_baseline parameter is TRUE, then the quantization table
+ entries are constrained to the range 1..255 for full JPEG baseline
+ compatibility. In the current implementation, this only makes a
+ difference for quality settings below 25, and it effectively prevents
+ very small/low quality files from being generated. The IJG decoder
+ is capable of reading the non-baseline files generated at low quality
+ settings when force_baseline is FALSE, but other decoders may not be.
+
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+ boolean force_baseline)
+ Same as jpeg_set_quality() except that the generated tables are the
+ sample tables given in the JPEC spec section K.1, multiplied by the
+ specified scale factor (which is expressed as a percentage; thus
+ scale_factor = 100 reproduces the spec's tables). Note that larger
+ scale factors give lower quality. This entry point is useful for
+ conforming to the Adobe PostScript DCT conventions, but we do not
+ recommend linear scaling as a user-visible quality scale otherwise.
+ force_baseline again constrains the computed table entries to 1..255.
+
+int jpeg_quality_scaling (int quality)
+ Converts a value on the IJG-recommended quality scale to a linear
+ scaling percentage. Note that this routine may change or go away
+ in future releases --- IJG may choose to adopt a scaling method that
+ can't be expressed as a simple scalar multiplier, in which case the
+ premise of this routine collapses. Caveat user.
+
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor, boolean force_baseline)
+ Allows an arbitrary quantization table to be created. which_tbl
+ indicates which table slot to fill. basic_table points to an array
+ of 64 unsigned ints given in normal array order. These values are
+ multiplied by scale_factor/100 and then clamped to the range 1..65535
+ (or to 1..255 if force_baseline is TRUE).
+ CAUTION: prior to library version 6a, jpeg_add_quant_table expected
+ the basic table to be given in JPEG zigzag order. If you need to
+ write code that works with either older or newer versions of this
+ routine, you must check the library version number. Something like
+ "#if JPEG_LIB_VERSION >= 61" is the right test.
+
+jpeg_simple_progression (j_compress_ptr cinfo)
+ Generates a default scan script for writing a progressive-JPEG file.
+ This is the recommended method of creating a progressive file,
+ unless you want to make a custom scan sequence. You must ensure that
+ the JPEG color space is set correctly before calling this routine.
+
+
+Compression parameters (cinfo fields) include:
+
+J_DCT_METHOD dct_method
+ Selects the algorithm used for the DCT step. Choices are:
+ JDCT_ISLOW: slow but accurate integer algorithm
+ JDCT_IFAST: faster, less accurate integer method
+ JDCT_FLOAT: floating-point method
+ JDCT_DEFAULT: default method (normally JDCT_ISLOW)
+ JDCT_FASTEST: fastest method (normally JDCT_IFAST)
+ The FLOAT method is very slightly more accurate than the ISLOW method,
+ but may give different results on different machines due to varying
+ roundoff behavior. The integer methods should give the same results
+ on all machines. On machines with sufficiently fast FP hardware, the
+ floating-point method may also be the fastest. The IFAST method is
+ considerably less accurate than the other two; its use is not
+ recommended if high quality is a concern. JDCT_DEFAULT and
+ JDCT_FASTEST are macros configurable by each installation.
+
+J_COLOR_SPACE jpeg_color_space
+int num_components
+ The JPEG color space and corresponding number of components; see
+ "Special color spaces", below, for more info. We recommend using
+ jpeg_set_color_space() if you want to change these.
+
+boolean optimize_coding
+ TRUE causes the compressor to compute optimal Huffman coding tables
+ for the image. This requires an extra pass over the data and
+ therefore costs a good deal of space and time. The default is
+ FALSE, which tells the compressor to use the supplied or default
+ Huffman tables. In most cases optimal tables save only a few percent
+ of file size compared to the default tables. Note that when this is
+ TRUE, you need not supply Huffman tables at all, and any you do
+ supply will be overwritten.
+
+unsigned int restart_interval
+int restart_in_rows
+ To emit restart markers in the JPEG file, set one of these nonzero.
+ Set restart_interval to specify the exact interval in MCU blocks.
+ Set restart_in_rows to specify the interval in MCU rows. (If
+ restart_in_rows is not 0, then restart_interval is set after the
+ image width in MCUs is computed.) Defaults are zero (no restarts).
+
+const jpeg_scan_info * scan_info
+int num_scans
+ By default, scan_info is NULL; this causes the compressor to write a
+ single-scan sequential JPEG file. If not NULL, scan_info points to
+ an array of scan definition records of length num_scans. The
+ compressor will then write a JPEG file having one scan for each scan
+ definition record. This is used to generate noninterleaved or
+ progressive JPEG files. The library checks that the scan array
+ defines a valid JPEG scan sequence. (jpeg_simple_progression creates
+ a suitable scan definition array for progressive JPEG.) This is
+ discussed further under "Progressive JPEG support".
+
+int smoothing_factor
+ If non-zero, the input image is smoothed; the value should be 1 for
+ minimal smoothing to 100 for maximum smoothing. Consult jcsample.c
+ for details of the smoothing algorithm. The default is zero.
+
+boolean write_JFIF_header
+ If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and
+ jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space
+ (ie, YCbCr or grayscale) is selected, otherwise FALSE.
+
+UINT8 density_unit
+UINT16 X_density
+UINT16 Y_density
+ The resolution information to be written into the JFIF marker;
+ not used otherwise. density_unit may be 0 for unknown,
+ 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1
+ indicating square pixels of unknown size.
+
+boolean write_Adobe_marker
+ If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and
+ jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK,
+ or YCCK is selected, otherwise FALSE. It is generally a bad idea
+ to set both write_JFIF_header and write_Adobe_marker. In fact,
+ you probably shouldn't change the default settings at all --- the
+ default behavior ensures that the JPEG file's color space can be
+ recognized by the decoder.
+
+JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]
+ Pointers to coefficient quantization tables, one per table slot,
+ or NULL if no table is defined for a slot. Usually these should
+ be set via one of the above helper routines; jpeg_add_quant_table()
+ is general enough to define any quantization table. The other
+ routines will set up table slot 0 for luminance quality and table
+ slot 1 for chrominance.
+
+JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]
+JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]
+ Pointers to Huffman coding tables, one per table slot, or NULL if
+ no table is defined for a slot. Slots 0 and 1 are filled with the
+ JPEG sample tables by jpeg_set_defaults(). If you need to allocate
+ more table structures, jpeg_alloc_huff_table() may be used.
+ Note that optimal Huffman tables can be computed for an image
+ by setting optimize_coding, as discussed above; there's seldom
+ any need to mess with providing your own Huffman tables.
+
+There are some additional cinfo fields which are not documented here
+because you currently can't change them; for example, you can't set
+arith_code TRUE because arithmetic coding is unsupported.
+
+
+Per-component parameters are stored in the struct cinfo.comp_info[i] for
+component number i. Note that components here refer to components of the
+JPEG color space, *not* the source image color space. A suitably large
+comp_info[] array is allocated by jpeg_set_defaults(); if you choose not
+to use that routine, it's up to you to allocate the array.
+
+int component_id
+ The one-byte identifier code to be recorded in the JPEG file for
+ this component. For the standard color spaces, we recommend you
+ leave the default values alone.
+
+int h_samp_factor
+int v_samp_factor
+ Horizontal and vertical sampling factors for the component; must
+ be 1..4 according to the JPEG standard. Note that larger sampling
+ factors indicate a higher-resolution component; many people find
+ this behavior quite unintuitive. The default values are 2,2 for
+ luminance components and 1,1 for chrominance components, except
+ for grayscale where 1,1 is used.
+
+int quant_tbl_no
+ Quantization table number for component. The default value is
+ 0 for luminance components and 1 for chrominance components.
+
+int dc_tbl_no
+int ac_tbl_no
+ DC and AC entropy coding table numbers. The default values are
+ 0 for luminance components and 1 for chrominance components.
+
+int component_index
+ Must equal the component's index in comp_info[]. (Beginning in
+ release v6, the compressor library will fill this in automatically;
+ you don't have to.)
+
+
+Decompression parameter selection
+---------------------------------
+
+Decompression parameter selection is somewhat simpler than compression
+parameter selection, since all of the JPEG internal parameters are
+recorded in the source file and need not be supplied by the application.
+(Unless you are working with abbreviated files, in which case see
+"Abbreviated datastreams", below.) Decompression parameters control
+the postprocessing done on the image to deliver it in a format suitable
+for the application's use. Many of the parameters control speed/quality
+tradeoffs, in which faster decompression may be obtained at the price of
+a poorer-quality image. The defaults select the highest quality (slowest)
+processing.
+
+The following fields in the JPEG object are set by jpeg_read_header() and
+may be useful to the application in choosing decompression parameters:
+
+JDIMENSION image_width Width and height of image
+JDIMENSION image_height
+int num_components Number of color components
+J_COLOR_SPACE jpeg_color_space Colorspace of image
+boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen
+ UINT8 density_unit Resolution data from JFIF marker
+ UINT16 X_density
+ UINT16 Y_density
+boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen
+ UINT8 Adobe_transform Color transform code from Adobe marker
+
+The JPEG color space, unfortunately, is something of a guess since the JPEG
+standard proper does not provide a way to record it. In practice most files
+adhere to the JFIF or Adobe conventions, and the decoder will recognize these
+correctly. See "Special color spaces", below, for more info.
+
+
+The decompression parameters that determine the basic properties of the
+returned image are:
+
+J_COLOR_SPACE out_color_space
+ Output color space. jpeg_read_header() sets an appropriate default
+ based on jpeg_color_space; typically it will be RGB or grayscale.
+ The application can change this field to request output in a different
+ colorspace. For example, set it to JCS_GRAYSCALE to get grayscale
+ output from a color file. (This is useful for previewing: grayscale
+ output is faster than full color since the color components need not
+ be processed.) Note that not all possible color space transforms are
+ currently implemented; you may need to extend jdcolor.c if you want an
+ unusual conversion.
+
+unsigned int scale_num, scale_denom
+ Scale the image by the fraction scale_num/scale_denom. Default is
+ 1/1, or no scaling. Currently, the only supported scaling ratios
+ are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary
+ scaling ratios but this is not likely to be implemented any time soon.)
+ Smaller scaling ratios permit significantly faster decoding since
+ fewer pixels need be processed and a simpler IDCT method can be used.
+
+boolean quantize_colors
+ If set TRUE, colormapped output will be delivered. Default is FALSE,
+ meaning that full-color output will be delivered.
+
+The next three parameters are relevant only if quantize_colors is TRUE.
+
+int desired_number_of_colors
+ Maximum number of colors to use in generating a library-supplied color
+ map (the actual number of colors is returned in a different field).
+ Default 256. Ignored when the application supplies its own color map.
+
+boolean two_pass_quantize
+ If TRUE, an extra pass over the image is made to select a custom color
+ map for the image. This usually looks a lot better than the one-size-
+ fits-all colormap that is used otherwise. Default is TRUE. Ignored
+ when the application supplies its own color map.
+
+J_DITHER_MODE dither_mode
+ Selects color dithering method. Supported values are:
+ JDITHER_NONE no dithering: fast, very low quality
+ JDITHER_ORDERED ordered dither: moderate speed and quality
+ JDITHER_FS Floyd-Steinberg dither: slow, high quality
+ Default is JDITHER_FS. (At present, ordered dither is implemented
+ only in the single-pass, standard-colormap case. If you ask for
+ ordered dither when two_pass_quantize is TRUE or when you supply
+ an external color map, you'll get F-S dithering.)
+
+When quantize_colors is TRUE, the target color map is described by the next
+two fields. colormap is set to NULL by jpeg_read_header(). The application
+can supply a color map by setting colormap non-NULL and setting
+actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress()
+selects a suitable color map and sets these two fields itself.
+[Implementation restriction: at present, an externally supplied colormap is
+only accepted for 3-component output color spaces.]
+
+JSAMPARRAY colormap
+ The color map, represented as a 2-D pixel array of out_color_components
+ rows and actual_number_of_colors columns. Ignored if not quantizing.
+ CAUTION: if the JPEG library creates its own colormap, the storage
+ pointed to by this field is released by jpeg_finish_decompress().
+ Copy the colormap somewhere else first, if you want to save it.
+
+int actual_number_of_colors
+ The number of colors in the color map.
+
+Additional decompression parameters that the application may set include:
+
+J_DCT_METHOD dct_method
+ Selects the algorithm used for the DCT step. Choices are the same
+ as described above for compression.
+
+boolean do_fancy_upsampling
+ If TRUE, do careful upsampling of chroma components. If FALSE,
+ a faster but sloppier method is used. Default is TRUE. The visual
+ impact of the sloppier method is often very small.
+
+boolean do_block_smoothing
+ If TRUE, interblock smoothing is applied in early stages of decoding
+ progressive JPEG files; if FALSE, not. Default is TRUE. Early
+ progression stages look "fuzzy" with smoothing, "blocky" without.
+ In any case, block smoothing ceases to be applied after the first few
+ AC coefficients are known to full accuracy, so it is relevant only
+ when using buffered-image mode for progressive images.
+
+boolean enable_1pass_quant
+boolean enable_external_quant
+boolean enable_2pass_quant
+ These are significant only in buffered-image mode, which is
+ described in its own section below.
+
+
+The output image dimensions are given by the following fields. These are
+computed from the source image dimensions and the decompression parameters
+by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions()
+to obtain the values that will result from the current parameter settings.
+This can be useful if you are trying to pick a scaling ratio that will get
+close to a desired target size. It's also important if you are using the
+JPEG library's memory manager to allocate output buffer space, because you
+are supposed to request such buffers *before* jpeg_start_decompress().
+
+JDIMENSION output_width Actual dimensions of output image.
+JDIMENSION output_height
+int out_color_components Number of color components in out_color_space.
+int output_components Number of color components returned.
+int rec_outbuf_height Recommended height of scanline buffer.
+
+When quantizing colors, output_components is 1, indicating a single color map
+index per pixel. Otherwise it equals out_color_components. The output arrays
+are required to be output_width * output_components JSAMPLEs wide.
+
+rec_outbuf_height is the recommended minimum height (in scanlines) of the
+buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the
+library will still work, but time will be wasted due to unnecessary data
+copying. In high-quality modes, rec_outbuf_height is always 1, but some
+faster, lower-quality modes set it to larger values (typically 2 to 4).
+If you are going to ask for a high-speed processing mode, you may as well
+go to the trouble of honoring rec_outbuf_height so as to avoid data copying.
+
+
+Special color spaces
+--------------------
+
+The JPEG standard itself is "color blind" and doesn't specify any particular
+color space. It is customary to convert color data to a luminance/chrominance
+color space before compressing, since this permits greater compression. The
+existing de-facto JPEG file format standards specify YCbCr or grayscale data
+(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special
+applications such as multispectral images, other color spaces can be used,
+but it must be understood that such files will be unportable.
+
+The JPEG library can handle the most common colorspace conversions (namely
+RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown
+color space, passing it through without conversion. If you deal extensively
+with an unusual color space, you can easily extend the library to understand
+additional color spaces and perform appropriate conversions.
+
+For compression, the source data's color space is specified by field
+in_color_space. This is transformed to the JPEG file's color space given
+by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color
+space depending on in_color_space, but you can override this by calling
+jpeg_set_colorspace(). Of course you must select a supported transformation.
+jccolor.c currently supports the following transformations:
+ RGB => YCbCr
+ RGB => GRAYSCALE
+ YCbCr => GRAYSCALE
+ CMYK => YCCK
+plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB,
+YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN.
+
+The de-facto file format standards (JFIF and Adobe) specify APPn markers that
+indicate the color space of the JPEG file. It is important to ensure that
+these are written correctly, or omitted if the JPEG file's color space is not
+one of the ones supported by the de-facto standards. jpeg_set_colorspace()
+will set the compression parameters to include or omit the APPn markers
+properly, so long as it is told the truth about the JPEG color space.
+For example, if you are writing some random 3-component color space without
+conversion, don't try to fake out the library by setting in_color_space and
+jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an
+APPn marker of your own devising to identify the colorspace --- see "Special
+markers", below.
+
+When told that the color space is UNKNOWN, the library will default to using
+luminance-quality compression parameters for all color components. You may
+well want to change these parameters. See the source code for
+jpeg_set_colorspace(), in jcparam.c, for details.
+
+For decompression, the JPEG file's color space is given in jpeg_color_space,
+and this is transformed to the output color space out_color_space.
+jpeg_read_header's setting of jpeg_color_space can be relied on if the file
+conforms to JFIF or Adobe conventions, but otherwise it is no better than a
+guess. If you know the JPEG file's color space for certain, you can override
+jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also
+selects a default output color space based on (its guess of) jpeg_color_space;
+set out_color_space to override this. Again, you must select a supported
+transformation. jdcolor.c currently supports
+ YCbCr => GRAYSCALE
+ YCbCr => RGB
+ YCCK => CMYK
+as well as the null transforms.
+
+The two-pass color quantizer, jquant2.c, is specialized to handle RGB data
+(it weights distances appropriately for RGB colors). You'll need to modify
+the code if you want to use it for non-RGB output color spaces. Note that
+jquant2.c is used to map to an application-supplied colormap as well as for
+the normal two-pass colormap selection process.
+
+CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG
+files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect.
+This is arguably a bug in Photoshop, but if you need to work with Photoshop
+CMYK files, you will have to deal with it in your application. We cannot
+"fix" this in the library by inverting the data during the CMYK<=>YCCK
+transform, because that would break other applications, notably Ghostscript.
+Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK
+data in the same inverted-YCCK representation used in bare JPEG files, but
+the surrounding PostScript code performs an inversion using the PS image
+operator. I am told that Photoshop 3.0 will write uninverted YCCK in
+EPS/JPEG files, and will omit the PS-level inversion. (But the data
+polarity used in bare JPEG files will not change in 3.0.) In either case,
+the JPEG library must not invert the data itself, or else Ghostscript would
+read these EPS files incorrectly.
+
+
+Error handling
+--------------
+
+When the default error handler is used, any error detected inside the JPEG
+routines will cause a message to be printed on stderr, followed by exit().
+You can supply your own error handling routines to override this behavior
+and to control the treatment of nonfatal warnings and trace/debug messages.
+The file example.c illustrates the most common case, which is to have the
+application regain control after an error rather than exiting.
+
+The JPEG library never writes any message directly; it always goes through
+the error handling routines. Three classes of messages are recognized:
+ * Fatal errors: the library cannot continue.
+ * Warnings: the library can continue, but the data is corrupt, and a
+ damaged output image is likely to result.
+ * Trace/informational messages. These come with a trace level indicating
+ the importance of the message; you can control the verbosity of the
+ program by adjusting the maximum trace level that will be displayed.
+
+You may, if you wish, simply replace the entire JPEG error handling module
+(jerror.c) with your own code. However, you can avoid code duplication by
+only replacing some of the routines depending on the behavior you need.
+This is accomplished by calling jpeg_std_error() as usual, but then overriding
+some of the method pointers in the jpeg_error_mgr struct, as illustrated by
+example.c.
+
+All of the error handling routines will receive a pointer to the JPEG object
+(a j_common_ptr which points to either a jpeg_compress_struct or a
+jpeg_decompress_struct; if you need to tell which, test the is_decompressor
+field). This struct includes a pointer to the error manager struct in its
+"err" field. Frequently, custom error handler routines will need to access
+additional data which is not known to the JPEG library or the standard error
+handler. The most convenient way to do this is to embed either the JPEG
+object or the jpeg_error_mgr struct in a larger structure that contains
+additional fields; then casting the passed pointer provides access to the
+additional fields. Again, see example.c for one way to do it.
+
+The individual methods that you might wish to override are:
+
+error_exit (j_common_ptr cinfo)
+ Receives control for a fatal error. Information sufficient to
+ generate the error message has been stored in cinfo->err; call
+ output_message to display it. Control must NOT return to the caller;
+ generally this routine will exit() or longjmp() somewhere.
+ Typically you would override this routine to get rid of the exit()
+ default behavior. Note that if you continue processing, you should
+ clean up the JPEG object with jpeg_abort() or jpeg_destroy().
+
+output_message (j_common_ptr cinfo)
+ Actual output of any JPEG message. Override this to send messages
+ somewhere other than stderr. Note that this method does not know
+ how to generate a message, only where to send it.
+
+format_message (j_common_ptr cinfo, char * buffer)
+ Constructs a readable error message string based on the error info
+ stored in cinfo->err. This method is called by output_message. Few
+ applications should need to override this method. One possible
+ reason for doing so is to implement dynamic switching of error message
+ language.
+
+emit_message (j_common_ptr cinfo, int msg_level)
+ Decide whether or not to emit a warning or trace message; if so,
+ calls output_message. The main reason for overriding this method
+ would be to abort on warnings. msg_level is -1 for warnings,
+ 0 and up for trace messages.
+
+Only error_exit() and emit_message() are called from the rest of the JPEG
+library; the other two are internal to the error handler.
+
+The actual message texts are stored in an array of strings which is pointed to
+by the field err->jpeg_message_table. The messages are numbered from 0 to
+err->last_jpeg_message, and it is these code numbers that are used in the
+JPEG library code. You could replace the message texts (for instance, with
+messages in French or German) by changing the message table pointer. See
+jerror.h for the default texts. CAUTION: this table will almost certainly
+change or grow from one library version to the next.
+
+It may be useful for an application to add its own message texts that are
+handled by the same mechanism. The error handler supports a second "add-on"
+message table for this purpose. To define an addon table, set the pointer
+err->addon_message_table and the message numbers err->first_addon_message and
+err->last_addon_message. If you number the addon messages beginning at 1000
+or so, you won't have to worry about conflicts with the library's built-in
+messages. See the sample applications cjpeg/djpeg for an example of using
+addon messages (the addon messages are defined in cderror.h).
+
+Actual invocation of the error handler is done via macros defined in jerror.h:
+ ERREXITn(...) for fatal errors
+ WARNMSn(...) for corrupt-data warnings
+ TRACEMSn(...) for trace and informational messages.
+These macros store the message code and any additional parameters into the
+error handler struct, then invoke the error_exit() or emit_message() method.
+The variants of each macro are for varying numbers of additional parameters.
+The additional parameters are inserted into the generated message using
+standard printf() format codes.
+
+See jerror.h and jerror.c for further details.
+
+
+Compressed data handling (source and destination managers)
+----------------------------------------------------------
+
+The JPEG compression library sends its compressed data to a "destination
+manager" module. The default destination manager just writes the data to a
+stdio stream, but you can provide your own manager to do something else.
+Similarly, the decompression library calls a "source manager" to obtain the
+compressed data; you can provide your own source manager if you want the data
+to come from somewhere other than a stdio stream.
+
+In both cases, compressed data is processed a bufferload at a time: the
+destination or source manager provides a work buffer, and the library invokes
+the manager only when the buffer is filled or emptied. (You could define a
+one-character buffer to force the manager to be invoked for each byte, but
+that would be rather inefficient.) The buffer's size and location are
+controlled by the manager, not by the library. For example, if you desired to
+decompress a JPEG datastream that was all in memory, you could just make the
+buffer pointer and length point to the original data in memory. Then the
+buffer-reload procedure would be invoked only if the decompressor ran off the
+end of the datastream, which would indicate an erroneous datastream.
+
+The work buffer is defined as an array of datatype JOCTET, which is generally
+"char" or "unsigned char". On a machine where char is not exactly 8 bits
+wide, you must define JOCTET as a wider data type and then modify the data
+source and destination modules to transcribe the work arrays into 8-bit units
+on external storage.
+
+A data destination manager struct contains a pointer and count defining the
+next byte to write in the work buffer and the remaining free space:
+
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is filled. The manager's empty_output_buffer method must reset the pointer
+and count. The manager is expected to remember the buffer's starting address
+and total size in private fields not visible to the library.
+
+A data destination manager provides three methods:
+
+init_destination (j_compress_ptr cinfo)
+ Initialize destination. This is called by jpeg_start_compress()
+ before any data is actually written. It must initialize
+ next_output_byte and free_in_buffer. free_in_buffer must be
+ initialized to a positive value.
+
+empty_output_buffer (j_compress_ptr cinfo)
+ This is called whenever the buffer has filled (free_in_buffer
+ reaches zero). In typical applications, it should write out the
+ *entire* buffer (use the saved start address and buffer length;
+ ignore the current state of next_output_byte and free_in_buffer).
+ Then reset the pointer & count to the start of the buffer, and
+ return TRUE indicating that the buffer has been dumped.
+ free_in_buffer must be set to a positive value when TRUE is
+ returned. A FALSE return should only be used when I/O suspension is
+ desired (this operating mode is discussed in the next section).
+
+term_destination (j_compress_ptr cinfo)
+ Terminate destination --- called by jpeg_finish_compress() after all
+ data has been written. In most applications, this must flush any
+ data remaining in the buffer. Use either next_output_byte or
+ free_in_buffer to determine how much data is in the buffer.
+
+term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you
+want the destination manager to be cleaned up during an abort, you must do it
+yourself.
+
+You will also need code to create a jpeg_destination_mgr struct, fill in its
+method pointers, and insert a pointer to the struct into the "dest" field of
+the JPEG compression object. This can be done in-line in your setup code if
+you like, but it's probably cleaner to provide a separate routine similar to
+the jpeg_stdio_dest() routine of the supplied destination manager.
+
+Decompression source managers follow a parallel design, but with some
+additional frammishes. The source manager struct contains a pointer and count
+defining the next byte to read from the work buffer and the number of bytes
+remaining:
+
+ const JOCTET * next_input_byte; /* => next byte to read from buffer */
+ size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is emptied. The manager's fill_input_buffer method must reset the pointer and
+count. In most applications, the manager must remember the buffer's starting
+address and total size in private fields not visible to the library.
+
+A data source manager provides five methods:
+
+init_source (j_decompress_ptr cinfo)
+ Initialize source. This is called by jpeg_read_header() before any
+ data is actually read. Unlike init_destination(), it may leave
+ bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
+ will occur immediately).
+
+fill_input_buffer (j_decompress_ptr cinfo)
+ This is called whenever bytes_in_buffer has reached zero and more
+ data is wanted. In typical applications, it should read fresh data
+ into the buffer (ignoring the current state of next_input_byte and
+ bytes_in_buffer), reset the pointer & count to the start of the
+ buffer, and return TRUE indicating that the buffer has been reloaded.
+ It is not necessary to fill the buffer entirely, only to obtain at
+ least one more byte. bytes_in_buffer MUST be set to a positive value
+ if TRUE is returned. A FALSE return should only be used when I/O
+ suspension is desired (this mode is discussed in the next section).
+
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+ Skip num_bytes worth of data. The buffer pointer and count should
+ be advanced over num_bytes input bytes, refilling the buffer as
+ needed. This is used to skip over a potentially large amount of
+ uninteresting data (such as an APPn marker). In some applications
+ it may be possible to optimize away the reading of the skipped data,
+ but it's not clear that being smart is worth much trouble; large
+ skips are uncommon. bytes_in_buffer may be zero on return.
+ A zero or negative skip count should be treated as a no-op.
+
+resync_to_restart (j_decompress_ptr cinfo, int desired)
+ This routine is called only when the decompressor has failed to find
+ a restart (RSTn) marker where one is expected. Its mission is to
+ find a suitable point for resuming decompression. For most
+ applications, we recommend that you just use the default resync
+ procedure, jpeg_resync_to_restart(). However, if you are able to back
+ up in the input data stream, or if you have a-priori knowledge about
+ the likely location of restart markers, you may be able to do better.
+ Read the read_restart_marker() and jpeg_resync_to_restart() routines
+ in jdmarker.c if you think you'd like to implement your own resync
+ procedure.
+
+term_source (j_decompress_ptr cinfo)
+ Terminate source --- called by jpeg_finish_decompress() after all
+ data has been read. Often a no-op.
+
+For both fill_input_buffer() and skip_input_data(), there is no such thing
+as an EOF return. If the end of the file has been reached, the routine has
+a choice of exiting via ERREXIT() or inserting fake data into the buffer.
+In most cases, generating a warning message and inserting a fake EOI marker
+is the best course of action --- this will allow the decompressor to output
+however much of the image is there. In pathological cases, the decompressor
+may swallow the EOI and again demand data ... just keep feeding it fake EOIs.
+jdatasrc.c illustrates the recommended error recovery behavior.
+
+term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want
+the source manager to be cleaned up during an abort, you must do it yourself.
+
+You will also need code to create a jpeg_source_mgr struct, fill in its method
+pointers, and insert a pointer to the struct into the "src" field of the JPEG
+decompression object. This can be done in-line in your setup code if you
+like, but it's probably cleaner to provide a separate routine similar to the
+jpeg_stdio_src() routine of the supplied source manager.
+
+For more information, consult the stdio source and destination managers
+in jdatasrc.c and jdatadst.c.
+
+
+I/O suspension
+--------------
+
+Some applications need to use the JPEG library as an incremental memory-to-
+memory filter: when the compressed data buffer is filled or emptied, they want
+control to return to the outer loop, rather than expecting that the buffer can
+be emptied or reloaded within the data source/destination manager subroutine.
+The library supports this need by providing an "I/O suspension" mode, which we
+describe in this section.
+
+The I/O suspension mode is not a panacea: nothing is guaranteed about the
+maximum amount of time spent in any one call to the library, so it will not
+eliminate response-time problems in single-threaded applications. If you
+need guaranteed response time, we suggest you "bite the bullet" and implement
+a real multi-tasking capability.
+
+To use I/O suspension, cooperation is needed between the calling application
+and the data source or destination manager; you will always need a custom
+source/destination manager. (Please read the previous section if you haven't
+already.) The basic idea is that the empty_output_buffer() or
+fill_input_buffer() routine is a no-op, merely returning FALSE to indicate
+that it has done nothing. Upon seeing this, the JPEG library suspends
+operation and returns to its caller. The surrounding application is
+responsible for emptying or refilling the work buffer before calling the
+JPEG library again.
+
+Compression suspension:
+
+For compression suspension, use an empty_output_buffer() routine that returns
+FALSE; typically it will not do anything else. This will cause the
+compressor to return to the caller of jpeg_write_scanlines(), with the return
+value indicating that not all the supplied scanlines have been accepted.
+The application must make more room in the output buffer, adjust the output
+buffer pointer/count appropriately, and then call jpeg_write_scanlines()
+again, pointing to the first unconsumed scanline.
+
+When forced to suspend, the compressor will backtrack to a convenient stopping
+point (usually the start of the current MCU); it will regenerate some output
+data when restarted. Therefore, although empty_output_buffer() is only
+called when the buffer is filled, you should NOT write out the entire buffer
+after a suspension. Write only the data up to the current position of
+next_output_byte/free_in_buffer. The data beyond that point will be
+regenerated after resumption.
+
+Because of the backtracking behavior, a good-size output buffer is essential
+for efficiency; you don't want the compressor to suspend often. (In fact, an
+overly small buffer could lead to infinite looping, if a single MCU required
+more data than would fit in the buffer.) We recommend a buffer of at least
+several Kbytes. You may want to insert explicit code to ensure that you don't
+call jpeg_write_scanlines() unless there is a reasonable amount of space in
+the output buffer; in other words, flush the buffer before trying to compress
+more data.
+
+The compressor does not allow suspension while it is trying to write JPEG
+markers at the beginning and end of the file. This means that:
+ * At the beginning of a compression operation, there must be enough free
+ space in the output buffer to hold the header markers (typically 600 or
+ so bytes). The recommended buffer size is bigger than this anyway, so
+ this is not a problem as long as you start with an empty buffer. However,
+ this restriction might catch you if you insert large special markers, such
+ as a JFIF thumbnail image, without flushing the buffer afterwards.
+ * When you call jpeg_finish_compress(), there must be enough space in the
+ output buffer to emit any buffered data and the final EOI marker. In the
+ current implementation, half a dozen bytes should suffice for this, but
+ for safety's sake we recommend ensuring that at least 100 bytes are free
+ before calling jpeg_finish_compress().
+
+A more significant restriction is that jpeg_finish_compress() cannot suspend.
+This means you cannot use suspension with multi-pass operating modes, namely
+Huffman code optimization and multiple-scan output. Those modes write the
+whole file during jpeg_finish_compress(), which will certainly result in
+buffer overrun. (Note that this restriction applies only to compression,
+not decompression. The decompressor supports input suspension in all of its
+operating modes.)
+
+Decompression suspension:
+
+For decompression suspension, use a fill_input_buffer() routine that simply
+returns FALSE (except perhaps during error recovery, as discussed below).
+This will cause the decompressor to return to its caller with an indication
+that suspension has occurred. This can happen at four places:
+ * jpeg_read_header(): will return JPEG_SUSPENDED.
+ * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE.
+ * jpeg_read_scanlines(): will return the number of scanlines already
+ completed (possibly 0).
+ * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE.
+The surrounding application must recognize these cases, load more data into
+the input buffer, and repeat the call. In the case of jpeg_read_scanlines(),
+increment the passed pointers past any scanlines successfully read.
+
+Just as with compression, the decompressor will typically backtrack to a
+convenient restart point before suspending. When fill_input_buffer() is
+called, next_input_byte/bytes_in_buffer point to the current restart point,
+which is where the decompressor will backtrack to if FALSE is returned.
+The data beyond that position must NOT be discarded if you suspend; it needs
+to be re-read upon resumption. In most implementations, you'll need to shift
+this data down to the start of your work buffer and then load more data after
+it. Again, this behavior means that a several-Kbyte work buffer is essential
+for decent performance; furthermore, you should load a reasonable amount of
+new data before resuming decompression. (If you loaded, say, only one new
+byte each time around, you could waste a LOT of cycles.)
+
+The skip_input_data() source manager routine requires special care in a
+suspension scenario. This routine is NOT granted the ability to suspend the
+decompressor; it can decrement bytes_in_buffer to zero, but no more. If the
+requested skip distance exceeds the amount of data currently in the input
+buffer, then skip_input_data() must set bytes_in_buffer to zero and record the
+additional skip distance somewhere else. The decompressor will immediately
+call fill_input_buffer(), which should return FALSE, which will cause a
+suspension return. The surrounding application must then arrange to discard
+the recorded number of bytes before it resumes loading the input buffer.
+(Yes, this design is rather baroque, but it avoids complexity in the far more
+common case where a non-suspending source manager is used.)
+
+If the input data has been exhausted, we recommend that you emit a warning
+and insert dummy EOI markers just as a non-suspending data source manager
+would do. This can be handled either in the surrounding application logic or
+within fill_input_buffer(); the latter is probably more efficient. If
+fill_input_buffer() knows that no more data is available, it can set the
+pointer/count to point to a dummy EOI marker and then return TRUE just as
+though it had read more data in a non-suspending situation.
+
+The decompressor does not attempt to suspend within any JPEG marker; it will
+backtrack to the start of the marker. Hence the input buffer must be large
+enough to hold the longest marker in the file. We recommend at least a 2K
+buffer. The buffer would need to be 64K to allow for arbitrary COM or APPn
+markers, but the decompressor does not actually try to read these; it just
+skips them by calling skip_input_data(). If you provide a special marker
+handling routine that does look at such markers, coping with buffer overflow
+is your problem. Ordinary JPEG markers should normally not exceed a few
+hundred bytes each (DHT tables are typically the longest). For robustness
+against damaged marker length counts, you may wish to insert a test in your
+application for the case that the input buffer is completely full and yet the
+decoder has suspended without consuming any data --- otherwise, if this
+situation did occur, it would lead to an endless loop.
+
+Multiple-buffer management:
+
+In some applications it is desirable to store the compressed data in a linked
+list of buffer areas, so as to avoid data copying. This can be handled by
+having empty_output_buffer() or fill_input_buffer() set the pointer and count
+to reference the next available buffer; FALSE is returned only if no more
+buffers are available. Although seemingly straightforward, there is a
+pitfall in this approach: the backtrack that occurs when FALSE is returned
+could back up into an earlier buffer. For example, when fill_input_buffer()
+is called, the current pointer & count indicate the backtrack restart point.
+Since fill_input_buffer() will set the pointer and count to refer to a new
+buffer, the restart position must be saved somewhere else. Suppose a second
+call to fill_input_buffer() occurs in the same library call, and no
+additional input data is available, so fill_input_buffer must return FALSE.
+If the JPEG library has not moved the pointer/count forward in the current
+buffer, then *the correct restart point is the saved position in the prior
+buffer*. Prior buffers may be discarded only after the library establishes
+a restart point within a later buffer. Similar remarks apply for output into
+a chain of buffers.
+
+The library will never attempt to backtrack over a skip_input_data() call,
+so any skipped data can be permanently discarded. You still have to deal
+with the case of skipping not-yet-received data, however.
+
+It's much simpler to use only a single buffer; when fill_input_buffer() is
+called, move any unconsumed data (beyond the current pointer/count) down to
+the beginning of this buffer and then load new data into the remaining buffer
+space. This approach requires a little more data copying but is far easier
+to get right.
+
+
+Progressive JPEG support
+------------------------
+
+Progressive JPEG rearranges the stored data into a series of scans of
+increasing quality. In situations where a JPEG file is transmitted across a
+slow communications link, a decoder can generate a low-quality image very
+quickly from the first scan, then gradually improve the displayed quality as
+more scans are received. The final image after all scans are complete is
+identical to that of a regular (sequential) JPEG file of the same quality
+setting. Progressive JPEG files are often slightly smaller than equivalent
+sequential JPEG files, but the possibility of incremental display is the main
+reason for using progressive JPEG.
+
+The IJG encoder library generates progressive JPEG files when given a
+suitable "scan script" defining how to divide the data into scans.
+Creation of progressive JPEG files is otherwise transparent to the encoder.
+Progressive JPEG files can also be read transparently by the decoder library.
+If the decoding application simply uses the library as defined above, it
+will receive a final decoded image without any indication that the file was
+progressive. Of course, this approach does not allow incremental display.
+To perform incremental display, an application needs to use the decoder
+library's "buffered-image" mode, in which it receives a decoded image
+multiple times.
+
+Each displayed scan requires about as much work to decode as a full JPEG
+image of the same size, so the decoder must be fairly fast in relation to the
+data transmission rate in order to make incremental display useful. However,
+it is possible to skip displaying the image and simply add the incoming bits
+to the decoder's coefficient buffer. This is fast because only Huffman
+decoding need be done, not IDCT, upsampling, colorspace conversion, etc.
+The IJG decoder library allows the application to switch dynamically between
+displaying the image and simply absorbing the incoming bits. A properly
+coded application can automatically adapt the number of display passes to
+suit the time available as the image is received. Also, a final
+higher-quality display cycle can be performed from the buffered data after
+the end of the file is reached.
+
+Progressive compression:
+
+To create a progressive JPEG file (or a multiple-scan sequential JPEG file),
+set the scan_info cinfo field to point to an array of scan descriptors, and
+perform compression as usual. Instead of constructing your own scan list,
+you can call the jpeg_simple_progression() helper routine to create a
+recommended progression sequence; this method should be used by all
+applications that don't want to get involved in the nitty-gritty of
+progressive scan sequence design. (If you want to provide user control of
+scan sequences, you may wish to borrow the scan script reading code found
+in rdswitch.c, so that you can read scan script files just like cjpeg's.)
+When scan_info is not NULL, the compression library will store DCT'd data
+into a buffer array as jpeg_write_scanlines() is called, and will emit all
+the requested scans during jpeg_finish_compress(). This implies that
+multiple-scan output cannot be created with a suspending data destination
+manager, since jpeg_finish_compress() does not support suspension. We
+should also note that the compressor currently forces Huffman optimization
+mode when creating a progressive JPEG file, because the default Huffman
+tables are unsuitable for progressive files.
+
+Progressive decompression:
+
+When buffered-image mode is not used, the decoder library will read all of
+a multi-scan file during jpeg_start_decompress(), so that it can provide a
+final decoded image. (Here "multi-scan" means either progressive or
+multi-scan sequential.) This makes multi-scan files transparent to the
+decoding application. However, existing applications that used suspending
+input with version 5 of the IJG library will need to be modified to check
+for a suspension return from jpeg_start_decompress().
+
+To perform incremental display, an application must use the library's
+buffered-image mode. This is described in the next section.
+
+
+Buffered-image mode
+-------------------
+
+In buffered-image mode, the library stores the partially decoded image in a
+coefficient buffer, from which it can be read out as many times as desired.
+This mode is typically used for incremental display of progressive JPEG files,
+but it can be used with any JPEG file. Each scan of a progressive JPEG file
+adds more data (more detail) to the buffered image. The application can
+display in lockstep with the source file (one display pass per input scan),
+or it can allow input processing to outrun display processing. By making
+input and display processing run independently, it is possible for the
+application to adapt progressive display to a wide range of data transmission
+rates.
+
+The basic control flow for buffered-image decoding is
+
+ jpeg_create_decompress()
+ set data source
+ jpeg_read_header()
+ set overall decompression parameters
+ cinfo.buffered_image = TRUE; /* select buffered-image mode */
+ jpeg_start_decompress()
+ for (each output pass) {
+ adjust output decompression parameters if required
+ jpeg_start_output() /* start a new output pass */
+ for (all scanlines in image) {
+ jpeg_read_scanlines()
+ display scanlines
+ }
+ jpeg_finish_output() /* terminate output pass */
+ }
+ jpeg_finish_decompress()
+ jpeg_destroy_decompress()
+
+This differs from ordinary unbuffered decoding in that there is an additional
+level of looping. The application can choose how many output passes to make
+and how to display each pass.
+
+The simplest approach to displaying progressive images is to do one display
+pass for each scan appearing in the input file. In this case the outer loop
+condition is typically
+ while (! jpeg_input_complete(&cinfo))
+and the start-output call should read
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+The second parameter to jpeg_start_output() indicates which scan of the input
+file is to be displayed; the scans are numbered starting at 1 for this
+purpose. (You can use a loop counter starting at 1 if you like, but using
+the library's input scan counter is easier.) The library automatically reads
+data as necessary to complete each requested scan, and jpeg_finish_output()
+advances to the next scan or end-of-image marker (hence input_scan_number
+will be incremented by the time control arrives back at jpeg_start_output()).
+With this technique, data is read from the input file only as needed, and
+input and output processing run in lockstep.
+
+After reading the final scan and reaching the end of the input file, the
+buffered image remains available; it can be read additional times by
+repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output()
+sequence. For example, a useful technique is to use fast one-pass color
+quantization for display passes made while the image is arriving, followed by
+a final display pass using two-pass quantization for highest quality. This
+is done by changing the library parameters before the final output pass.
+Changing parameters between passes is discussed in detail below.
+
+In general the last scan of a progressive file cannot be recognized as such
+until after it is read, so a post-input display pass is the best approach if
+you want special processing in the final pass.
+
+When done with the image, be sure to call jpeg_finish_decompress() to release
+the buffered image (or just use jpeg_destroy_decompress()).
+
+If input data arrives faster than it can be displayed, the application can
+cause the library to decode input data in advance of what's needed to produce
+output. This is done by calling the routine jpeg_consume_input().
+The return value is one of the following:
+ JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan)
+ JPEG_REACHED_EOI: reached the EOI marker (end of image)
+ JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data
+ JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan
+ JPEG_SUSPENDED: suspended before completing any of the above
+(JPEG_SUSPENDED can occur only if a suspending data source is used.) This
+routine can be called at any time after initializing the JPEG object. It
+reads some additional data and returns when one of the indicated significant
+events occurs. (If called after the EOI marker is reached, it will
+immediately return JPEG_REACHED_EOI without attempting to read more data.)
+
+The library's output processing will automatically call jpeg_consume_input()
+whenever the output processing overtakes the input; thus, simple lockstep
+display requires no direct calls to jpeg_consume_input(). But by adding
+calls to jpeg_consume_input(), you can absorb data in advance of what is
+being displayed. This has two benefits:
+ * You can limit buildup of unprocessed data in your input buffer.
+ * You can eliminate extra display passes by paying attention to the
+ state of the library's input processing.
+
+The first of these benefits only requires interspersing calls to
+jpeg_consume_input() with your display operations and any other processing
+you may be doing. To avoid wasting cycles due to backtracking, it's best to
+call jpeg_consume_input() only after a hundred or so new bytes have arrived.
+This is discussed further under "I/O suspension", above. (Note: the JPEG
+library currently is not thread-safe. You must not call jpeg_consume_input()
+from one thread of control if a different library routine is working on the
+same JPEG object in another thread.)
+
+When input arrives fast enough that more than one new scan is available
+before you start a new output pass, you may as well skip the output pass
+corresponding to the completed scan. This occurs for free if you pass
+cinfo.input_scan_number as the target scan number to jpeg_start_output().
+The input_scan_number field is simply the index of the scan currently being
+consumed by the input processor. You can ensure that this is up-to-date by
+emptying the input buffer just before calling jpeg_start_output(): call
+jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or
+JPEG_REACHED_EOI.
+
+The target scan number passed to jpeg_start_output() is saved in the
+cinfo.output_scan_number field. The library's output processing calls
+jpeg_consume_input() whenever the current input scan number and row within
+that scan is less than or equal to the current output scan number and row.
+Thus, input processing can "get ahead" of the output processing but is not
+allowed to "fall behind". You can achieve several different effects by
+manipulating this interlock rule. For example, if you pass a target scan
+number greater than the current input scan number, the output processor will
+wait until that scan starts to arrive before producing any output. (To avoid
+an infinite loop, the target scan number is automatically reset to the last
+scan number when the end of image is reached. Thus, if you specify a large
+target scan number, the library will just absorb the entire input file and
+then perform an output pass. This is effectively the same as what
+jpeg_start_decompress() does when you don't select buffered-image mode.)
+When you pass a target scan number equal to the current input scan number,
+the image is displayed no faster than the current input scan arrives. The
+final possibility is to pass a target scan number less than the current input
+scan number; this disables the input/output interlock and causes the output
+processor to simply display whatever it finds in the image buffer, without
+waiting for input. (However, the library will not accept a target scan
+number less than one, so you can't avoid waiting for the first scan.)
+
+When data is arriving faster than the output display processing can advance
+through the image, jpeg_consume_input() will store data into the buffered
+image beyond the point at which the output processing is reading data out
+again. If the input arrives fast enough, it may "wrap around" the buffer to
+the point where the input is more than one whole scan ahead of the output.
+If the output processing simply proceeds through its display pass without
+paying attention to the input, the effect seen on-screen is that the lower
+part of the image is one or more scans better in quality than the upper part.
+Then, when the next output scan is started, you have a choice of what target
+scan number to use. The recommended choice is to use the current input scan
+number at that time, which implies that you've skipped the output scans
+corresponding to the input scans that were completed while you processed the
+previous output scan. In this way, the decoder automatically adapts its
+speed to the arriving data, by skipping output scans as necessary to keep up
+with the arriving data.
+
+When using this strategy, you'll want to be sure that you perform a final
+output pass after receiving all the data; otherwise your last display may not
+be full quality across the whole screen. So the right outer loop logic is
+something like this:
+ do {
+ absorb any waiting input by calling jpeg_consume_input()
+ final_pass = jpeg_input_complete(&cinfo);
+ adjust output decompression parameters if required
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+ ...
+ jpeg_finish_output()
+ } while (! final_pass);
+rather than quitting as soon as jpeg_input_complete() returns TRUE. This
+arrangement makes it simple to use higher-quality decoding parameters
+for the final pass. But if you don't want to use special parameters for
+the final pass, the right loop logic is like this:
+ for (;;) {
+ absorb any waiting input by calling jpeg_consume_input()
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+ ...
+ jpeg_finish_output()
+ if (jpeg_input_complete(&cinfo) &&
+ cinfo.input_scan_number == cinfo.output_scan_number)
+ break;
+ }
+In this case you don't need to know in advance whether an output pass is to
+be the last one, so it's not necessary to have reached EOF before starting
+the final output pass; rather, what you want to test is whether the output
+pass was performed in sync with the final input scan. This form of the loop
+will avoid an extra output pass whenever the decoder is able (or nearly able)
+to keep up with the incoming data.
+
+When the data transmission speed is high, you might begin a display pass,
+then find that much or all of the file has arrived before you can complete
+the pass. (You can detect this by noting the JPEG_REACHED_EOI return code
+from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().)
+In this situation you may wish to abort the current display pass and start a
+new one using the newly arrived information. To do so, just call
+jpeg_finish_output() and then start a new pass with jpeg_start_output().
+
+A variant strategy is to abort and restart display if more than one complete
+scan arrives during an output pass; this can be detected by noting
+JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This
+idea should be employed with caution, however, since the display process
+might never get to the bottom of the image before being aborted, resulting
+in the lower part of the screen being several passes worse than the upper.
+In most cases it's probably best to abort an output pass only if the whole
+file has arrived and you want to begin the final output pass immediately.
+
+When receiving data across a communication link, we recommend always using
+the current input scan number for the output target scan number; if a
+higher-quality final pass is to be done, it should be started (aborting any
+incomplete output pass) as soon as the end of file is received. However,
+many other strategies are possible. For example, the application can examine
+the parameters of the current input scan and decide whether to display it or
+not. If the scan contains only chroma data, one might choose not to use it
+as the target scan, expecting that the scan will be small and will arrive
+quickly. To skip to the next scan, call jpeg_consume_input() until it
+returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher
+number as the target scan for jpeg_start_output(); but that method doesn't
+let you inspect the next scan's parameters before deciding to display it.
+
+
+In buffered-image mode, jpeg_start_decompress() never performs input and
+thus never suspends. An application that uses input suspension with
+buffered-image mode must be prepared for suspension returns from these
+routines:
+* jpeg_start_output() performs input only if you request 2-pass quantization
+ and the target scan isn't fully read yet. (This is discussed below.)
+* jpeg_read_scanlines(), as always, returns the number of scanlines that it
+ was able to produce before suspending.
+* jpeg_finish_output() will read any markers following the target scan,
+ up to the end of the file or the SOS marker that begins another scan.
+ (But it reads no input if jpeg_consume_input() has already reached the
+ end of the file or a SOS marker beyond the target output scan.)
+* jpeg_finish_decompress() will read until the end of file, and thus can
+ suspend if the end hasn't already been reached (as can be tested by
+ calling jpeg_input_complete()).
+jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress()
+all return TRUE if they completed their tasks, FALSE if they had to suspend.
+In the event of a FALSE return, the application must load more input data
+and repeat the call. Applications that use non-suspending data sources need
+not check the return values of these three routines.
+
+
+It is possible to change decoding parameters between output passes in the
+buffered-image mode. The decoder library currently supports only very
+limited changes of parameters. ONLY THE FOLLOWING parameter changes are
+allowed after jpeg_start_decompress() is called:
+* dct_method can be changed before each call to jpeg_start_output().
+ For example, one could use a fast DCT method for early scans, changing
+ to a higher quality method for the final scan.
+* dither_mode can be changed before each call to jpeg_start_output();
+ of course this has no impact if not using color quantization. Typically
+ one would use ordered dither for initial passes, then switch to
+ Floyd-Steinberg dither for the final pass. Caution: changing dither mode
+ can cause more memory to be allocated by the library. Although the amount
+ of memory involved is not large (a scanline or so), it may cause the
+ initial max_memory_to_use specification to be exceeded, which in the worst
+ case would result in an out-of-memory failure.
+* do_block_smoothing can be changed before each call to jpeg_start_output().
+ This setting is relevant only when decoding a progressive JPEG image.
+ During the first DC-only scan, block smoothing provides a very "fuzzy" look
+ instead of the very "blocky" look seen without it; which is better seems a
+ matter of personal taste. But block smoothing is nearly always a win
+ during later stages, especially when decoding a successive-approximation
+ image: smoothing helps to hide the slight blockiness that otherwise shows
+ up on smooth gradients until the lowest coefficient bits are sent.
+* Color quantization mode can be changed under the rules described below.
+ You *cannot* change between full-color and quantized output (because that
+ would alter the required I/O buffer sizes), but you can change which
+ quantization method is used.
+
+When generating color-quantized output, changing quantization method is a
+very useful way of switching between high-speed and high-quality display.
+The library allows you to change among its three quantization methods:
+1. Single-pass quantization to a fixed color cube.
+ Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL.
+2. Single-pass quantization to an application-supplied colormap.
+ Selected by setting cinfo.colormap to point to the colormap (the value of
+ two_pass_quantize is ignored); also set cinfo.actual_number_of_colors.
+3. Two-pass quantization to a colormap chosen specifically for the image.
+ Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL.
+ (This is the default setting selected by jpeg_read_header, but it is
+ probably NOT what you want for the first pass of progressive display!)
+These methods offer successively better quality and lesser speed. However,
+only the first method is available for quantizing in non-RGB color spaces.
+
+IMPORTANT: because the different quantizer methods have very different
+working-storage requirements, the library requires you to indicate which
+one(s) you intend to use before you call jpeg_start_decompress(). (If we did
+not require this, the max_memory_to_use setting would be a complete fiction.)
+You do this by setting one or more of these three cinfo fields to TRUE:
+ enable_1pass_quant Fixed color cube colormap
+ enable_external_quant Externally-supplied colormap
+ enable_2pass_quant Two-pass custom colormap
+All three are initialized FALSE by jpeg_read_header(). But
+jpeg_start_decompress() automatically sets TRUE the one selected by the
+current two_pass_quantize and colormap settings, so you only need to set the
+enable flags for any other quantization methods you plan to change to later.
+
+After setting the enable flags correctly at jpeg_start_decompress() time, you
+can change to any enabled quantization method by setting two_pass_quantize
+and colormap properly just before calling jpeg_start_output(). The following
+special rules apply:
+1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass
+ or 2-pass mode from a different mode, or when you want the 2-pass
+ quantizer to be re-run to generate a new colormap.
+2. To switch to an external colormap, or to change to a different external
+ colormap than was used on the prior pass, you must call
+ jpeg_new_colormap() after setting cinfo.colormap.
+NOTE: if you want to use the same colormap as was used in the prior pass,
+you should not do either of these things. This will save some nontrivial
+switchover costs.
+(These requirements exist because cinfo.colormap will always be non-NULL
+after completing a prior output pass, since both the 1-pass and 2-pass
+quantizers set it to point to their output colormaps. Thus you have to
+do one of these two things to notify the library that something has changed.
+Yup, it's a bit klugy, but it's necessary to do it this way for backwards
+compatibility.)
+
+Note that in buffered-image mode, the library generates any requested colormap
+during jpeg_start_output(), not during jpeg_start_decompress().
+
+When using two-pass quantization, jpeg_start_output() makes a pass over the
+buffered image to determine the optimum color map; it therefore may take a
+significant amount of time, whereas ordinarily it does little work. The
+progress monitor hook is called during this pass, if defined. It is also
+important to realize that if the specified target scan number is greater than
+or equal to the current input scan number, jpeg_start_output() will attempt
+to consume input as it makes this pass. If you use a suspending data source,
+you need to check for a FALSE return from jpeg_start_output() under these
+conditions. The combination of 2-pass quantization and a not-yet-fully-read
+target scan is the only case in which jpeg_start_output() will consume input.
+
+
+Application authors who support buffered-image mode may be tempted to use it
+for all JPEG images, even single-scan ones. This will work, but it is
+inefficient: there is no need to create an image-sized coefficient buffer for
+single-scan images. Requesting buffered-image mode for such an image wastes
+memory. Worse, it can cost time on large images, since the buffered data has
+to be swapped out or written to a temporary file. If you are concerned about
+maximum performance on baseline JPEG files, you should use buffered-image
+mode only when the incoming file actually has multiple scans. This can be
+tested by calling jpeg_has_multiple_scans(), which will return a correct
+result at any time after jpeg_read_header() completes.
+
+It is also worth noting that when you use jpeg_consume_input() to let input
+processing get ahead of output processing, the resulting pattern of access to
+the coefficient buffer is quite nonsequential. It's best to use the memory
+manager jmemnobs.c if you can (ie, if you have enough real or virtual main
+memory). If not, at least make sure that max_memory_to_use is set as high as
+possible. If the JPEG memory manager has to use a temporary file, you will
+probably see a lot of disk traffic and poor performance. (This could be
+improved with additional work on the memory manager, but we haven't gotten
+around to it yet.)
+
+In some applications it may be convenient to use jpeg_consume_input() for all
+input processing, including reading the initial markers; that is, you may
+wish to call jpeg_consume_input() instead of jpeg_read_header() during
+startup. This works, but note that you must check for JPEG_REACHED_SOS and
+JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes.
+Once the first SOS marker has been reached, you must call
+jpeg_start_decompress() before jpeg_consume_input() will consume more input;
+it'll just keep returning JPEG_REACHED_SOS until you do. If you read a
+tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI
+without ever returning JPEG_REACHED_SOS; be sure to check for this case.
+If this happens, the decompressor will not read any more input until you call
+jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not
+using buffered-image mode, but in that case it's basically a no-op after the
+initial markers have been read: it will just return JPEG_SUSPENDED.
+
+
+Abbreviated datastreams and multiple images
+-------------------------------------------
+
+A JPEG compression or decompression object can be reused to process multiple
+images. This saves a small amount of time per image by eliminating the
+"create" and "destroy" operations, but that isn't the real purpose of the
+feature. Rather, reuse of an object provides support for abbreviated JPEG
+datastreams. Object reuse can also simplify processing a series of images in
+a single input or output file. This section explains these features.
+
+A JPEG file normally contains several hundred bytes worth of quantization
+and Huffman tables. In a situation where many images will be stored or
+transmitted with identical tables, this may represent an annoying overhead.
+The JPEG standard therefore permits tables to be omitted. The standard
+defines three classes of JPEG datastreams:
+ * "Interchange" datastreams contain an image and all tables needed to decode
+ the image. These are the usual kind of JPEG file.
+ * "Abbreviated image" datastreams contain an image, but are missing some or
+ all of the tables needed to decode that image.
+ * "Abbreviated table specification" (henceforth "tables-only") datastreams
+ contain only table specifications.
+To decode an abbreviated image, it is necessary to load the missing table(s)
+into the decoder beforehand. This can be accomplished by reading a separate
+tables-only file. A variant scheme uses a series of images in which the first
+image is an interchange (complete) datastream, while subsequent ones are
+abbreviated and rely on the tables loaded by the first image. It is assumed
+that once the decoder has read a table, it will remember that table until a
+new definition for the same table number is encountered.
+
+It is the application designer's responsibility to figure out how to associate
+the correct tables with an abbreviated image. While abbreviated datastreams
+can be useful in a closed environment, their use is strongly discouraged in
+any situation where data exchange with other applications might be needed.
+Caveat designer.
+
+The JPEG library provides support for reading and writing any combination of
+tables-only datastreams and abbreviated images. In both compression and
+decompression objects, a quantization or Huffman table will be retained for
+the lifetime of the object, unless it is overwritten by a new table definition.
+
+
+To create abbreviated image datastreams, it is only necessary to tell the
+compressor not to emit some or all of the tables it is using. Each
+quantization and Huffman table struct contains a boolean field "sent_table",
+which normally is initialized to FALSE. For each table used by the image, the
+header-writing process emits the table and sets sent_table = TRUE unless it is
+already TRUE. (In normal usage, this prevents outputting the same table
+definition multiple times, as would otherwise occur because the chroma
+components typically share tables.) Thus, setting this field to TRUE before
+calling jpeg_start_compress() will prevent the table from being written at
+all.
+
+If you want to create a "pure" abbreviated image file containing no tables,
+just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the
+tables. If you want to emit some but not all tables, you'll need to set the
+individual sent_table fields directly.
+
+To create an abbreviated image, you must also call jpeg_start_compress()
+with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress()
+will force all the sent_table fields to FALSE. (This is a safety feature to
+prevent abbreviated images from being created accidentally.)
+
+To create a tables-only file, perform the same parameter setup that you
+normally would, but instead of calling jpeg_start_compress() and so on, call
+jpeg_write_tables(&cinfo). This will write an abbreviated datastream
+containing only SOI, DQT and/or DHT markers, and EOI. All the quantization
+and Huffman tables that are currently defined in the compression object will
+be emitted unless their sent_tables flag is already TRUE, and then all the
+sent_tables flags will be set TRUE.
+
+A sure-fire way to create matching tables-only and abbreviated image files
+is to proceed as follows:
+
+ create JPEG compression object
+ set JPEG parameters
+ set destination to tables-only file
+ jpeg_write_tables(&cinfo);
+ set destination to image file
+ jpeg_start_compress(&cinfo, FALSE);
+ write data...
+ jpeg_finish_compress(&cinfo);
+
+Since the JPEG parameters are not altered between writing the table file and
+the abbreviated image file, the same tables are sure to be used. Of course,
+you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence
+many times to produce many abbreviated image files matching the table file.
+
+You cannot suppress output of the computed Huffman tables when Huffman
+optimization is selected. (If you could, there'd be no way to decode the
+image...) Generally, you don't want to set optimize_coding = TRUE when
+you are trying to produce abbreviated files.
+
+In some cases you might want to compress an image using tables which are
+not stored in the application, but are defined in an interchange or
+tables-only file readable by the application. This can be done by setting up
+a JPEG decompression object to read the specification file, then copying the
+tables into your compression object. See jpeg_copy_critical_parameters()
+for an example of copying quantization tables.
+
+
+To read abbreviated image files, you simply need to load the proper tables
+into the decompression object before trying to read the abbreviated image.
+If the proper tables are stored in the application program, you can just
+allocate the table structs and fill in their contents directly. More commonly
+you'd want to read the tables from a tables-only file. The jpeg_read_header()
+call is sufficient to read a tables-only file. You must pass a second
+parameter of FALSE to indicate that you do not require an image to be present.
+Thus, the typical scenario is
+
+ create JPEG decompression object
+ set source to tables-only file
+ jpeg_read_header(&cinfo, FALSE);
+ set source to abbreviated image file
+ jpeg_read_header(&cinfo, TRUE);
+ set decompression parameters
+ jpeg_start_decompress(&cinfo);
+ read data...
+ jpeg_finish_decompress(&cinfo);
+
+In some cases, you may want to read a file without knowing whether it contains
+an image or just tables. In that case, pass FALSE and check the return value
+from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found,
+JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value,
+JPEG_SUSPENDED, is possible when using a suspending data source manager.)
+Note that jpeg_read_header() will not complain if you read an abbreviated
+image for which you haven't loaded the missing tables; the missing-table check
+occurs later, in jpeg_start_decompress().
+
+
+It is possible to read a series of images from a single source file by
+repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence,
+without releasing/recreating the JPEG object or the data source module.
+(If you did reinitialize, any partial bufferload left in the data source
+buffer at the end of one image would be discarded, causing you to lose the
+start of the next image.) When you use this method, stored tables are
+automatically carried forward, so some of the images can be abbreviated images
+that depend on tables from earlier images.
+
+If you intend to write a series of images into a single destination file,
+you might want to make a specialized data destination module that doesn't
+flush the output buffer at term_destination() time. This would speed things
+up by some trifling amount. Of course, you'd need to remember to flush the
+buffer after the last image. You can make the later images be abbreviated
+ones by passing FALSE to jpeg_start_compress().
+
+
+Special markers
+---------------
+
+Some applications may need to insert or extract special data in the JPEG
+datastream. The JPEG standard provides marker types "COM" (comment) and
+"APP0" through "APP15" (application) to hold application-specific data.
+Unfortunately, the use of these markers is not specified by the standard.
+COM markers are fairly widely used to hold user-supplied text. The JFIF file
+format spec uses APP0 markers with specified initial strings to hold certain
+data. Adobe applications use APP14 markers beginning with the string "Adobe"
+for miscellaneous data. Other APPn markers are rarely seen, but might
+contain almost anything.
+
+If you wish to store user-supplied text, we recommend you use COM markers
+and place readable 7-bit ASCII text in them. Newline conventions are not
+standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR
+(Mac style). A robust COM reader should be able to cope with random binary
+garbage, including nulls, since some applications generate COM markers
+containing non-ASCII junk. (But yours should not be one of them.)
+
+For program-supplied data, use an APPn marker, and be sure to begin it with an
+identifying string so that you can tell whether the marker is actually yours.
+It's probably best to avoid using APP0 or APP14 for any private markers.
+(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you
+not use APP8 markers for any private purposes, either.)
+
+Keep in mind that at most 65533 bytes can be put into one marker, but you
+can have as many markers as you like.
+
+By default, the IJG compression library will write a JFIF APP0 marker if the
+selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if
+the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but
+we don't recommend it. The decompression library will recognize JFIF and
+Adobe markers and will set the JPEG colorspace properly when one is found.
+
+You can write special markers immediately following the datastream header by
+calling jpeg_write_marker() after jpeg_start_compress() and before the first
+call to jpeg_write_scanlines(). When you do this, the markers appear after
+the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before
+all else. Specify the marker type parameter as "JPEG_COM" for COM or
+"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write
+any marker type, but we don't recommend writing any other kinds of marker.)
+For example, to write a user comment string pointed to by comment_text:
+ jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text));
+Or if you prefer to synthesize the marker byte sequence yourself, you can
+just cram it straight into the data destination module.
+
+For decompression, you can supply your own routine to process COM or APPn
+markers by calling jpeg_set_marker_processor(). Usually you'd call this
+after creating a decompression object and before calling jpeg_read_header(),
+because the markers of interest will normally be scanned by jpeg_read_header.
+Once you've supplied a routine, it will be used for the life of that
+decompression object. A separate routine may be registered for COM and for
+each APPn marker code.
+
+A marker processor routine must have the signature
+ boolean jpeg_marker_parser_method (j_decompress_ptr cinfo)
+Although the marker code is not explicitly passed, the routine can find it
+in cinfo->unread_marker. At the time of call, the marker proper has been
+read from the data source module. The processor routine is responsible for
+reading the marker length word and the remaining parameter bytes, if any.
+Return TRUE to indicate success. (FALSE should be returned only if you are
+using a suspending data source and it tells you to suspend. See the standard
+marker processors in jdmarker.c for appropriate coding methods if you need to
+use a suspending data source.)
+
+If you override the default APP0 or APP14 processors, it is up to you to
+recognize JFIF and Adobe markers if you want colorspace recognition to occur
+properly. We recommend copying and extending the default processors if you
+want to do that.
+
+A simple example of an external COM processor can be found in djpeg.c.
+
+
+Raw (downsampled) image data
+----------------------------
+
+Some applications need to supply already-downsampled image data to the JPEG
+compressor, or to receive raw downsampled data from the decompressor. The
+library supports this requirement by allowing the application to write or
+read raw data, bypassing the normal preprocessing or postprocessing steps.
+The interface is different from the standard one and is somewhat harder to
+use. If your interest is merely in bypassing color conversion, we recommend
+that you use the standard interface and simply set jpeg_color_space =
+in_color_space (or jpeg_color_space = out_color_space for decompression).
+The mechanism described in this section is necessary only to supply or
+receive downsampled image data, in which not all components have the same
+dimensions.
+
+
+To compress raw data, you must supply the data in the colorspace to be used
+in the JPEG file (please read the earlier section on Special color spaces)
+and downsampled to the sampling factors specified in the JPEG parameters.
+You must supply the data in the format used internally by the JPEG library,
+namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional
+arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one
+color component. This structure is necessary since the components are of
+different sizes. If the image dimensions are not a multiple of the MCU size,
+you must also pad the data correctly (usually, this is done by replicating
+the last column and/or row). The data must be padded to a multiple of a DCT
+block in each component: that is, each downsampled row must contain a
+multiple of 8 valid samples, and there must be a multiple of 8 sample rows
+for each component. (For applications such as conversion of digital TV
+images, the standard image size is usually a multiple of the DCT block size,
+so that no padding need actually be done.)
+
+The procedure for compression of raw data is basically the same as normal
+compression, except that you call jpeg_write_raw_data() in place of
+jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do
+the following:
+ * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().)
+ This notifies the library that you will be supplying raw data.
+ * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace()
+ call is a good idea. Note that since color conversion is bypassed,
+ in_color_space is ignored, except that jpeg_set_defaults() uses it to
+ choose the default jpeg_color_space setting.
+ * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and
+ cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the
+ dimensions of the data you are supplying, it's wise to set them
+ explicitly, rather than assuming the library's defaults are what you want.
+
+To pass raw data to the library, call jpeg_write_raw_data() in place of
+jpeg_write_scanlines(). The two routines work similarly except that
+jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY.
+The scanlines count passed to and returned from jpeg_write_raw_data is
+measured in terms of the component with the largest v_samp_factor.
+
+jpeg_write_raw_data() processes one MCU row per call, which is to say
+v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines
+value must be at least max_v_samp_factor*DCTSIZE, and the return value will
+be exactly that amount (or possibly some multiple of that amount, in future
+library versions). This is true even on the last call at the bottom of the
+image; don't forget to pad your data as necessary.
+
+The required dimensions of the supplied data can be computed for each
+component as
+ cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row
+ cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image
+after jpeg_start_compress() has initialized those fields. If the valid data
+is smaller than this, it must be padded appropriately. For some sampling
+factors and image sizes, additional dummy DCT blocks are inserted to make
+the image a multiple of the MCU dimensions. The library creates such dummy
+blocks itself; it does not read them from your supplied data. Therefore you
+need never pad by more than DCTSIZE samples. An example may help here.
+Assume 2h2v downsampling of YCbCr data, that is
+ cinfo->comp_info[0].h_samp_factor = 2 for Y
+ cinfo->comp_info[0].v_samp_factor = 2
+ cinfo->comp_info[1].h_samp_factor = 1 for Cb
+ cinfo->comp_info[1].v_samp_factor = 1
+ cinfo->comp_info[2].h_samp_factor = 1 for Cr
+ cinfo->comp_info[2].v_samp_factor = 1
+and suppose that the nominal image dimensions (cinfo->image_width and
+cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will
+compute downsampled_width = 101 and width_in_blocks = 13 for Y,
+downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same
+for the height fields). You must pad the Y data to at least 13*8 = 104
+columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The
+MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16
+scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual
+sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed,
+so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row
+of Y data is dummy, so it doesn't matter what you pass for it in the data
+arrays, but the scanlines count must total up to 112 so that all of the Cb
+and Cr data gets passed.
+
+Output suspension is supported with raw-data compression: if the data
+destination module suspends, jpeg_write_raw_data() will return 0.
+In this case the same data rows must be passed again on the next call.
+
+
+Decompression with raw data output implies bypassing all postprocessing:
+you cannot ask for rescaling or color quantization, for instance. More
+seriously, you must deal with the color space and sampling factors present in
+the incoming file. If your application only handles, say, 2h1v YCbCr data,
+you must check for and fail on other color spaces or other sampling factors.
+The library will not convert to a different color space for you.
+
+To obtain raw data output, set cinfo->raw_data_out = TRUE before
+jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to
+verify that the color space and sampling factors are ones you can handle.
+Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The
+decompression process is otherwise the same as usual.
+
+jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a
+buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is
+the same as for raw-data compression). The buffer you pass must be large
+enough to hold the actual data plus padding to DCT-block boundaries. As with
+compression, any entirely dummy DCT blocks are not processed so you need not
+allocate space for them, but the total scanline count includes them. The
+above example of computing buffer dimensions for raw-data compression is
+equally valid for decompression.
+
+Input suspension is supported with raw-data decompression: if the data source
+module suspends, jpeg_read_raw_data() will return 0. You can also use
+buffered-image mode to read raw data in multiple passes.
+
+
+Really raw data: DCT coefficients
+---------------------------------
+
+It is possible to read or write the contents of a JPEG file as raw DCT
+coefficients. This facility is mainly intended for use in lossless
+transcoding between different JPEG file formats. Other possible applications
+include lossless cropping of a JPEG image, lossless reassembly of a
+multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc.
+
+To read the contents of a JPEG file as DCT coefficients, open the file and do
+jpeg_read_header() as usual. But instead of calling jpeg_start_decompress()
+and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the
+entire image into a set of virtual coefficient-block arrays, one array per
+component. The return value is a pointer to an array of virtual-array
+descriptors. Each virtual array can be accessed directly using the JPEG
+memory manager's access_virt_barray method (see Memory management, below,
+and also read structure.doc's discussion of virtual array handling). Or,
+for simple transcoding to a different JPEG file format, the array list can
+just be handed directly to jpeg_write_coefficients().
+
+When you are done using the virtual arrays, call jpeg_finish_decompress()
+to release the array storage and return the decompression object to an idle
+state; or just call jpeg_destroy() if you don't need to reuse the object.
+
+If you use a suspending data source, jpeg_read_coefficients() will return
+NULL if it is forced to suspend; a non-NULL return value indicates successful
+completion. You need not test for a NULL return value when using a
+non-suspending data source.
+
+Each block in the block arrays contains quantized coefficient values in
+normal array order (not JPEG zigzag order). The block arrays contain only
+DCT blocks containing real data; any entirely-dummy blocks added to fill out
+interleaved MCUs at the right or bottom edges of the image are discarded
+during reading and are not stored in the block arrays. (The size of each
+block array can be determined from the width_in_blocks and height_in_blocks
+fields of the component's comp_info entry.) This is also the data format
+expected by jpeg_write_coefficients().
+
+To write the contents of a JPEG file as DCT coefficients, you must provide
+the DCT coefficients stored in virtual block arrays. You can either pass
+block arrays read from an input JPEG file by jpeg_read_coefficients(), or
+allocate virtual arrays from the JPEG compression object and fill them
+yourself. In either case, jpeg_write_coefficients() is substituted for
+jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is
+ * Create compression object
+ * Set all compression parameters as necessary
+ * Request virtual arrays if needed
+ * jpeg_write_coefficients()
+ * jpeg_finish_compress()
+ * Destroy or re-use compression object
+jpeg_write_coefficients() is passed a pointer to an array of virtual block
+array descriptors; the number of arrays is equal to cinfo.num_components.
+
+The virtual arrays need only have been requested, not realized, before
+jpeg_write_coefficients() is called. A side-effect of
+jpeg_write_coefficients() is to realize any virtual arrays that have been
+requested from the compression object's memory manager. Thus, when obtaining
+the virtual arrays from the compression object, you should fill the arrays
+after calling jpeg_write_coefficients(). The data is actually written out
+when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes
+the file header.
+
+When writing raw DCT coefficients, it is crucial that the JPEG quantization
+tables and sampling factors match the way the data was encoded, or the
+resulting file will be invalid. For transcoding from an existing JPEG file,
+we recommend using jpeg_copy_critical_parameters(). This routine initializes
+all the compression parameters to default values (like jpeg_set_defaults()),
+then copies the critical information from a source decompression object.
+The decompression object should have just been used to read the entire
+JPEG input file --- that is, it should be awaiting jpeg_finish_decompress().
+
+jpeg_write_coefficients() marks all tables stored in the compression object
+as needing to be written to the output file (thus, it acts like
+jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid
+emitting abbreviated JPEG files by accident. If you really want to emit an
+abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables'
+individual sent_table flags, between calling jpeg_write_coefficients() and
+jpeg_finish_compress().
+
+
+Progress monitoring
+-------------------
+
+Some applications may need to regain control from the JPEG library every so
+often. The typical use of this feature is to produce a percent-done bar or
+other progress display. (For a simple example, see cjpeg.c or djpeg.c.)
+Although you do get control back frequently during the data-transferring pass
+(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes
+will occur inside jpeg_finish_compress or jpeg_start_decompress; those
+routines may take a long time to execute, and you don't get control back
+until they are done.
+
+You can define a progress-monitor routine which will be called periodically
+by the library. No guarantees are made about how often this call will occur,
+so we don't recommend you use it for mouse tracking or anything like that.
+At present, a call will occur once per MCU row, scanline, or sample row
+group, whichever unit is convenient for the current processing mode; so the
+wider the image, the longer the time between calls. During the data
+transferring pass, only one call occurs per call of jpeg_read_scanlines or
+jpeg_write_scanlines, so don't pass a large number of scanlines at once if
+you want fine resolution in the progress count. (If you really need to use
+the callback mechanism for time-critical tasks like mouse tracking, you could
+insert additional calls inside some of the library's inner loops.)
+
+To establish a progress-monitor callback, create a struct jpeg_progress_mgr,
+fill in its progress_monitor field with a pointer to your callback routine,
+and set cinfo->progress to point to the struct. The callback will be called
+whenever cinfo->progress is non-NULL. (This pointer is set to NULL by
+jpeg_create_compress or jpeg_create_decompress; the library will not change
+it thereafter. So if you allocate dynamic storage for the progress struct,
+make sure it will live as long as the JPEG object does. Allocating from the
+JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You
+can use the same callback routine for both compression and decompression.
+
+The jpeg_progress_mgr struct contains four fields which are set by the library:
+ long pass_counter; /* work units completed in this pass */
+ long pass_limit; /* total number of work units in this pass */
+ int completed_passes; /* passes completed so far */
+ int total_passes; /* total number of passes expected */
+During any one pass, pass_counter increases from 0 up to (not including)
+pass_limit; the step size is usually but not necessarily 1. The pass_limit
+value may change from one pass to another. The expected total number of
+passes is in total_passes, and the number of passes already completed is in
+completed_passes. Thus the fraction of work completed may be estimated as
+ completed_passes + (pass_counter/pass_limit)
+ --------------------------------------------
+ total_passes
+ignoring the fact that the passes may not be equal amounts of work.
+
+When decompressing, pass_limit can even change within a pass, because it
+depends on the number of scans in the JPEG file, which isn't always known in
+advance. The computed fraction-of-work-done may jump suddenly (if the library
+discovers it has overestimated the number of scans) or even decrease (in the
+opposite case). It is not wise to put great faith in the work estimate.
+
+When using the decompressor's buffered-image mode, the progress monitor work
+estimate is likely to be completely unhelpful, because the library has no way
+to know how many output passes will be demanded of it. Currently, the library
+sets total_passes based on the assumption that there will be one more output
+pass if the input file end hasn't yet been read (jpeg_input_complete() isn't
+TRUE), but no more output passes if the file end has been reached when the
+output pass is started. This means that total_passes will rise as additional
+output passes are requested. If you have a way of determining the input file
+size, estimating progress based on the fraction of the file that's been read
+will probably be more useful than using the library's value.
+
+
+Memory management
+-----------------
+
+This section covers some key facts about the JPEG library's built-in memory
+manager. For more info, please read structure.doc's section about the memory
+manager, and consult the source code if necessary.
+
+All memory and temporary file allocation within the library is done via the
+memory manager. If necessary, you can replace the "back end" of the memory
+manager to control allocation yourself (for example, if you don't want the
+library to use malloc() and free() for some reason).
+
+Some data is allocated "permanently" and will not be freed until the JPEG
+object is destroyed. Most data is allocated "per image" and is freed by
+jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the
+memory manager yourself to allocate structures that will automatically be
+freed at these times. Typical code for this is
+ ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size);
+Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object.
+Use alloc_large instead of alloc_small for anything bigger than a few Kbytes.
+There are also alloc_sarray and alloc_barray routines that automatically
+build 2-D sample or block arrays.
+
+The library's minimum space requirements to process an image depend on the
+image's width, but not on its height, because the library ordinarily works
+with "strip" buffers that are as wide as the image but just a few rows high.
+Some operating modes (eg, two-pass color quantization) require full-image
+buffers. Such buffers are treated as "virtual arrays": only the current strip
+need be in memory, and the rest can be swapped out to a temporary file.
+
+If you use the simplest memory manager back end (jmemnobs.c), then no
+temporary files are used; virtual arrays are simply malloc()'d. Images bigger
+than memory can be processed only if your system supports virtual memory.
+The other memory manager back ends support temporary files of various flavors
+and thus work in machines without virtual memory. They may also be useful on
+Unix machines if you need to process images that exceed available swap space.
+
+When using temporary files, the library will make the in-memory buffers for
+its virtual arrays just big enough to stay within a "maximum memory" setting.
+Your application can set this limit by setting cinfo->mem->max_memory_to_use
+after creating the JPEG object. (Of course, there is still a minimum size for
+the buffers, so the max-memory setting is effective only if it is bigger than
+the minimum space needed.) If you allocate any large structures yourself, you
+must allocate them before jpeg_start_compress() or jpeg_start_decompress() in
+order to have them counted against the max memory limit. Also keep in mind
+that space allocated with alloc_small() is ignored, on the assumption that
+it's too small to be worth worrying about; so a reasonable safety margin
+should be left when setting max_memory_to_use.
+
+If you use the jmemname.c or jmemdos.c memory manager back end, it is
+important to clean up the JPEG object properly to ensure that the temporary
+files get deleted. (This is especially crucial with jmemdos.c, where the
+"temporary files" may be extended-memory segments; if they are not freed,
+DOS will require a reboot to recover the memory.) Thus, with these memory
+managers, it's a good idea to provide a signal handler that will trap any
+early exit from your program. The handler should call either jpeg_abort()
+or jpeg_destroy() for any active JPEG objects. A handler is not needed with
+jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either,
+since the C library is supposed to take care of deleting files made with
+tmpfile().
+
+
+Library compile-time options
+----------------------------
+
+A number of compile-time options are available by modifying jmorecfg.h.
+
+The JPEG standard provides for both the baseline 8-bit DCT process and
+a 12-bit DCT process. 12-bit lossy JPEG is supported if you define
+BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be
+larger than a char, so it affects the surrounding application's image data.
+The sample applications cjpeg and djpeg can support 12-bit mode only for PPM
+and GIF file formats; you must disable the other file formats to compile a
+12-bit cjpeg or djpeg. (install.doc has more information about that.)
+At present, a 12-bit library can handle *only* 12-bit images, not both
+precisions. (If you need to include both 8- and 12-bit libraries in a single
+application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES
+for just one of the copies. You'd have to access the 8-bit and 12-bit copies
+from separate application source files. This is untested ... if you try it,
+we'd like to hear whether it works!)
+
+Note that a 12-bit library always compresses in Huffman optimization mode,
+in order to generate valid Huffman tables. This is necessary because our
+default Huffman tables only cover 8-bit data. If you need to output 12-bit
+files in one pass, you'll have to supply suitable default Huffman tables.
+
+The maximum number of components (color channels) in the image is determined
+by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we
+expect that few applications will need more than four or so.
+
+On machines with unusual data type sizes, you may be able to improve
+performance or reduce memory space by tweaking the various typedefs in
+jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s
+is quite slow; consider trading memory for speed by making JCOEF, INT16, and
+UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int.
+You probably don't want to make JSAMPLE be int unless you have lots of memory
+to burn.
+
+You can reduce the size of the library by compiling out various optional
+functions. To do this, undefine xxx_SUPPORTED symbols as necessary.
+
+
+Portability considerations
+--------------------------
+
+The JPEG library has been written to be extremely portable; the sample
+applications cjpeg and djpeg are slightly less so. This section summarizes
+the design goals in this area. (If you encounter any bugs that cause the
+library to be less portable than is claimed here, we'd appreciate hearing
+about them.)
+
+The code works fine on both ANSI and pre-ANSI C compilers, using any of the
+popular system include file setups, and some not-so-popular ones too. See
+install.doc for configuration procedures.
+
+The code is not dependent on the exact sizes of the C data types. As
+distributed, we make the assumptions that
+ char is at least 8 bits wide
+ short is at least 16 bits wide
+ int is at least 16 bits wide
+ long is at least 32 bits wide
+(These are the minimum requirements of the ANSI C standard.) Wider types will
+work fine, although memory may be used inefficiently if char is much larger
+than 8 bits or short is much bigger than 16 bits. The code should work
+equally well with 16- or 32-bit ints.
+
+In a system where these assumptions are not met, you may be able to make the
+code work by modifying the typedefs in jmorecfg.h. However, you will probably
+have difficulty if int is less than 16 bits wide, since references to plain
+int abound in the code.
+
+char can be either signed or unsigned, although the code runs faster if an
+unsigned char type is available. If char is wider than 8 bits, you will need
+to redefine JOCTET and/or provide custom data source/destination managers so
+that JOCTET represents exactly 8 bits of data on external storage.
+
+The JPEG library proper does not assume ASCII representation of characters.
+But some of the image file I/O modules in cjpeg/djpeg do have ASCII
+dependencies in file-header manipulation; so does cjpeg's select_file_type()
+routine.
+
+The JPEG library does not rely heavily on the C library. In particular, C
+stdio is used only by the data source/destination modules and the error
+handler, all of which are application-replaceable. (cjpeg/djpeg are more
+heavily dependent on stdio.) malloc and free are called only from the memory
+manager "back end" module, so you can use a different memory allocator by
+replacing that one file.
+
+The code generally assumes that C names must be unique in the first 15
+characters. However, global function names can be made unique in the
+first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES.
+
+More info about porting the code may be gleaned by reading jconfig.doc,
+jmorecfg.h, and jinclude.h.
+
+
+Notes for MS-DOS implementors
+-----------------------------
+
+The IJG code is designed to work efficiently in 80x86 "small" or "medium"
+memory models (i.e., data pointers are 16 bits unless explicitly declared
+"far"; code pointers can be either size). You may be able to use small
+model to compile cjpeg or djpeg by itself, but you will probably have to use
+medium model for any larger application. This won't make much difference in
+performance. You *will* take a noticeable performance hit if you use a
+large-data memory model (perhaps 10%-25%), and you should avoid "huge" model
+if at all possible.
+
+The JPEG library typically needs 2Kb-3Kb of stack space. It will also
+malloc about 20K-30K of near heap space while executing (and lots of far
+heap, but that doesn't count in this calculation). This figure will vary
+depending on selected operating mode, and to a lesser extent on image size.
+There is also about 5Kb-6Kb of constant data which will be allocated in the
+near data segment (about 4Kb of this is the error message table).
+Thus you have perhaps 20K available for other modules' static data and near
+heap space before you need to go to a larger memory model. The C library's
+static data will account for several K of this, but that still leaves a good
+deal for your needs. (If you are tight on space, you could reduce the sizes
+of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to
+1K. Another possibility is to move the error message table to far memory;
+this should be doable with only localized hacking on jerror.c.)
+
+About 2K of the near heap space is "permanent" memory that will not be
+released until you destroy the JPEG object. This is only an issue if you
+save a JPEG object between compression or decompression operations.
+
+Far data space may also be a tight resource when you are dealing with large
+images. The most memory-intensive case is decompression with two-pass color
+quantization, or single-pass quantization to an externally supplied color
+map. This requires a 128Kb color lookup table plus strip buffers amounting
+to about 50 bytes per column for typical sampling ratios (eg, about 32000
+bytes for a 640-pixel-wide image). You may not be able to process wide
+images if you have large data structures of your own.
+
+Of course, all of these concerns vanish if you use a 32-bit flat-memory-model
+compiler, such as DJGPP or Watcom C. We highly recommend flat model if you
+can use it; the JPEG library is significantly faster in flat model.
diff --git a/gs/jpeg/makcjpeg.st b/gs/jpeg/makcjpeg.st
new file mode 100644
index 000000000..3b523dbd2
--- /dev/null
+++ b/gs/jpeg/makcjpeg.st
@@ -0,0 +1,37 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de)
+; and to Dr. B. Setzepfandt (bernd@gina.uni-muenster.de).
+;
+; To use this file, rename it to CJPEG.PRJ.
+; If you are using Turbo C, change filenames beginning with "PC..." to "TC..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+cjpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+PCSTART.O
+cjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+LIBJPEG.LIB ; built by LIBJPEG.PRJ
+PCFLTLIB.LIB ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+PCSTDLIB.LIB ; standard library
+PCEXTLIB.LIB ; extended library
diff --git a/gs/jpeg/makdjpeg.st b/gs/jpeg/makdjpeg.st
new file mode 100644
index 000000000..49d23eacc
--- /dev/null
+++ b/gs/jpeg/makdjpeg.st
@@ -0,0 +1,37 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de)
+; and to Dr. B. Setzepfandt (bernd@gina.uni-muenster.de).
+;
+; To use this file, rename it to DJPEG.PRJ.
+; If you are using Turbo C, change filenames beginning with "PC..." to "TC..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+djpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+PCSTART.O
+djpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdcolmap.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+LIBJPEG.LIB ; built by LIBJPEG.PRJ
+PCFLTLIB.LIB ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+PCSTDLIB.LIB ; standard library
+PCEXTLIB.LIB ; extended library
diff --git a/gs/jpeg/makefile.ansi b/gs/jpeg/makefile.ansi
new file mode 100644
index 000000000..8175ca0e7
--- /dev/null
+++ b/gs/jpeg/makefile.ansi
@@ -0,0 +1,210 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Unix-like systems with ANSI-capable compilers.
+# If you have a non-ANSI compiler, makefile.unix is a better starting point.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+CFLAGS= -O
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.a: $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) core testout*
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ ./djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ ./jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.gif testout.gif
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.bcc b/gs/jpeg/makefile.bcc
new file mode 100644
index 000000000..4f20bea60
--- /dev/null
+++ b/gs/jpeg/makefile.bcc
@@ -0,0 +1,279 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Borland C on MS-DOS or OS/2.
+# It works with Borland C++ for DOS, revision 3.0 or later,
+# and has been tested with Borland C++ for OS/2, revision 2.0.
+# Thanks to Tom Wright and Ge' Weijers (original DOS) and
+# Ken Porter (OS/2) for this file.
+
+# Read installation instructions before saying "make" !!
+
+# Are we under DOS or OS/2?
+!if !$d(DOS) && !$d(OS2)
+!if $d(__OS2__)
+OS2=1
+!else
+DOS=1
+!endif
+!endif
+
+# The name of your C compiler:
+CC= bcc
+
+# You may need to adjust these cc options:
+!if $d(DOS)
+CFLAGS= -O2 -mm -w-par -w-stu -w-ccc -w-rch
+!else
+CFLAGS= -O1 -w-par -w-stu -w-ccc -w-rch
+!endif
+# -O2 enables full code optimization (for pre-3.0 Borland C++, use -O -G -Z).
+# -O2 is buggy in Borland OS/2 C++ revision 2.0, so use -O1 for now.
+# -mm selects medium memory model (near data, far code pointers; DOS only!)
+# -w-par suppresses warnings about unused function parameters
+# -w-stu suppresses warnings about incomplete structures
+# -w-ccc suppresses warnings about compile-time-constant conditions
+# -w-rch suppresses warnings about unreachable code
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!if $d(DOS)
+LDFLAGS= -mm
+# memory model option here must match CFLAGS!
+!else
+LDFLAGS=
+# -lai full-screen app
+# -lc case-significant link
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.
+# For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# For OS/2, we recommend jmemnobs.c (flat memory!)
+# SYSDEPMEMLIB must list the same files with "+" signs for the librarian.
+!if $d(DOS)
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj
+!else
+SYSDEPMEM= jmemnobs.obj
+SYSDEPMEMLIB= +jmemnobs.obj
+!endif
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \
+ jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \
+ jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \
+ jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \
+ jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \
+ jquant1.obj jquant2.obj jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+ - del libjpeg.lib
+ tlib libjpeg.lib /E /C @&&|
++jcapimin.obj +jcapistd.obj +jctrans.obj +jcparam.obj +jdatadst.obj &
++jcinit.obj +jcmaster.obj +jcmarker.obj +jcmainct.obj +jcprepct.obj &
++jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj +jcphuff.obj &
++jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj +jfdctint.obj +jdapimin.obj &
++jdapistd.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj +jdinput.obj &
++jdmarker.obj +jdhuff.obj +jdphuff.obj +jdmainct.obj +jdcoefct.obj &
++jdpostct.obj +jddctmgr.obj +jidctfst.obj +jidctflt.obj +jidctint.obj &
++jidctred.obj +jdsample.obj +jdcolor.obj +jquant1.obj +jquant2.obj &
++jdmerge.obj +jcomapi.obj +jutils.obj +jerror.obj +jmemmgr.obj &
+$(SYSDEPMEMLIB)
+|
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -ecjpeg.exe $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -edjpeg.exe $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -ejpegtran.exe $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+!if $d(DOS)
+ $(CC) -ms -O rdjpgcom.c
+!else
+ $(CC) $(CFLAGS) rdjpgcom.c
+!endif
+
+# On DOS, wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+!if $d(DOS)
+ $(CC) -ml -O wrjpgcom.c
+!else
+ $(CC) $(CFLAGS) wrjpgcom.c
+!endif
+
+# This "{}" syntax allows Borland Make to "batch" source files.
+# In this way, each run of the compiler can build many modules.
+.c.obj:
+ $(CC) $(CFLAGS) -c{ $<}
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ - del *.obj
+ - del libjpeg.lib
+ - del cjpeg.exe
+ - del djpeg.exe
+ - del jpegtran.exe
+ - del rdjpgcom.exe
+ - del wrjpgcom.exe
+ - del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+ - del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+!if $d(DOS)
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.gif testout.gif
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+!else
+ echo n > n.tmp
+ comp testimg.ppm testout.ppm < n.tmp
+ comp testimg.gif testout.gif < n.tmp
+ comp testimg.jpg testout.jpg < n.tmp
+ comp testimg.ppm testoutp.ppm < n.tmp
+ comp testimgp.jpg testoutp.jpg < n.tmp
+ comp testorig.jpg testoutt.jpg < n.tmp
+ del n.tmp
+!endif
+
+
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj: jmemdosa.asm
+ tasm /mx jmemdosa.asm
diff --git a/gs/jpeg/makefile.cfg b/gs/jpeg/makefile.cfg
new file mode 100644
index 000000000..d3241c6e5
--- /dev/null
+++ b/gs/jpeg/makefile.cfg
@@ -0,0 +1,274 @@
+# Makefile for Independent JPEG Group's software
+
+# makefile.cfg is edited by configure to produce a custom Makefile.
+
+# Read installation instructions before saying "make" !!
+
+# For compiling with source and object files in different directories.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# Where to install the programs and man pages.
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+binprefix =
+manprefix =
+manext = 1
+mandir = $(prefix)/man/man$(manext)
+
+# The name of your C compiler:
+CC= @CC@
+
+# You may need to adjust these cc options:
+CFLAGS= @CFLAGS@ @CPPFLAGS@ @INCLUDEFLAGS@
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+# However, any special defines for ansi2knr.c may be included here:
+ANSI2KNRFLAGS= @ANSI2KNRFLAGS@
+
+# Link-time cc options:
+LDFLAGS= @LDFLAGS@
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= @LIBS@
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= @MEMORYMGR@
+
+# miscellaneous OS-dependent stuff
+SHELL= /bin/sh
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# file rename command
+MV= mv
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= @RANLIB@
+# installation program
+INSTALL= @INSTALL@
+INSTALL_PROGRAM= @INSTALL_PROGRAM@
+INSTALL_DATA= @INSTALL_DATA@
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: @ANSI2KNR@ libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# This rule causes ansi2knr to be invoked.
+@ISANSICOM@.c.o:
+@ISANSICOM@ ./ansi2knr $(srcdir)/$*.c T$*.c
+@ISANSICOM@ $(CC) $(CFLAGS) -c T$*.c
+@ISANSICOM@ $(RM) T$*.c $*.o
+@ISANSICOM@ $(MV) T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libjpeg.a: @ANSI2KNR@ $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+install: cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+ $(INSTALL_PROGRAM) cjpeg $(bindir)/$(binprefix)cjpeg
+ $(INSTALL_PROGRAM) djpeg $(bindir)/$(binprefix)djpeg
+ $(INSTALL_PROGRAM) jpegtran $(bindir)/$(binprefix)jpegtran
+ $(INSTALL_PROGRAM) rdjpgcom $(bindir)/$(binprefix)rdjpgcom
+ $(INSTALL_PROGRAM) wrjpgcom $(bindir)/$(binprefix)wrjpgcom
+ $(INSTALL_DATA) $(srcdir)/cjpeg.1 $(mandir)/$(manprefix)cjpeg.$(manext)
+ $(INSTALL_DATA) $(srcdir)/djpeg.1 $(mandir)/$(manprefix)djpeg.$(manext)
+ $(INSTALL_DATA) $(srcdir)/jpegtran.1 $(mandir)/$(manprefix)jpegtran.$(manext)
+ $(INSTALL_DATA) $(srcdir)/rdjpgcom.1 $(mandir)/$(manprefix)rdjpgcom.$(manext)
+ $(INSTALL_DATA) $(srcdir)/wrjpgcom.1 $(mandir)/$(manprefix)wrjpgcom.$(manext)
+
+install-lib: libjpeg.a install-headers
+ $(INSTALL_DATA) libjpeg.a $(libdir)/$(binprefix)libjpeg.a
+
+install-headers: jconfig.h
+ $(INSTALL_DATA) jconfig.h $(includedir)/jconfig.h
+ $(INSTALL_DATA) $(srcdir)/jpeglib.h $(includedir)/jpeglib.h
+ $(INSTALL_DATA) $(srcdir)/jmorecfg.h $(includedir)/jmorecfg.h
+ $(INSTALL_DATA) $(srcdir)/jerror.h $(includedir)/jerror.h
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) ansi2knr core testout* config.log config.status
+
+distribute:
+ $(RM) jpegsrc.tar*
+ tar cvf jpegsrc.tar $(DISTFILES)
+ compress -v jpegsrc.tar
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm $(srcdir)/testorig.jpg
+ ./djpeg -dct int -gif -outfile testout.gif $(srcdir)/testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg $(srcdir)/testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+ ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+ cmp $(srcdir)/testimg.ppm testout.ppm
+ cmp $(srcdir)/testimg.gif testout.gif
+ cmp $(srcdir)/testimg.jpg testout.jpg
+ cmp $(srcdir)/testimg.ppm testoutp.ppm
+ cmp $(srcdir)/testimgp.jpg testoutp.jpg
+ cmp $(srcdir)/testorig.jpg testoutt.jpg
+
+check: test
+
+# GNU Make likes to know which target names are not really files to be made:
+.PHONY: all install install-lib install-headers clean distribute test check
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.dj b/gs/jpeg/makefile.dj
new file mode 100644
index 000000000..811fd7d51
--- /dev/null
+++ b/gs/jpeg/makefile.dj
@@ -0,0 +1,234 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for DJGPP (Delorie's GNU C port) on MS-DOS.
+# Say "make exe" to get stub-style .exe's, or
+# "make standalone" to get standalone .exe's.
+
+# Read installation instructions before saying "make" !!
+
+# To do "make standalone", you'll need to be sure this points to go32.exe:
+GO32= c:/djgpp/bin/go32.exe
+
+# The name of your C compiler:
+CC= gcc
+
+# You may need to adjust these cc options:
+CFLAGS= -O2 -Wall
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For DJGPP this is usually jmemnobs.o, but you could
+# use jmemname.o if you want to use named temp files instead of swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= del
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.a: $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+exe: cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+ coff2exe cjpeg
+ coff2exe djpeg
+ coff2exe jpegtran
+ coff2exe rdjpgcom
+ coff2exe wrjpgcom
+
+standalone: cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+ coff2exe -s $(GO32) cjpeg
+ coff2exe -s $(GO32) djpeg
+ coff2exe -s $(GO32) jpegtran
+ coff2exe -s $(GO32) rdjpgcom
+ coff2exe -s $(GO32) wrjpgcom
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ $(RM) *.o
+ $(RM) cjpeg
+ $(RM) djpeg
+ $(RM) jpegtran
+ $(RM) rdjpgcom
+ $(RM) wrjpgcom
+ $(RM) libjpeg.a
+ $(RM) testout*.*
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*.*
+ go32 djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ go32 djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ go32 cjpeg -dct int -outfile testout.jpg testimg.ppm
+ go32 djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ go32 cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ go32 jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.gif testout.gif
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.manx b/gs/jpeg/makefile.manx
new file mode 100644
index 000000000..fa035fce9
--- /dev/null
+++ b/gs/jpeg/makefile.manx
@@ -0,0 +1,210 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using Manx Aztec C ver 5.x.
+# Thanks to D.J. James (djjames@cup.portal.com) for this version.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+# Uncomment for generic 68000 code (will work on any Amiga)
+ARCHFLAGS= -sn
+
+# Uncomment for 68020/68030 code (faster, but won't run on 68000 CPU)
+#ARCHFLAGS= -c2
+
+CFLAGS= -MC -MD $(ARCHFLAGS) -spfam -r4
+
+# Link-time cc options:
+LDFLAGS= -g
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= -lml -lcl
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= ln
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= lb
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: libjpeg.lib cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.lib: $(LIBOBJECTS)
+ -$(RM) libjpeg.lib
+ $(AR) libjpeg.lib $(LIBOBJECTS)
+
+cjpeg: $(COBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.lib $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.lib $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.lib $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ -$(RM) *.o cjpeg djpeg jpegtran libjpeg.lib rdjpgcom wrjpgcom
+ -$(RM) core testout*.*
+
+test: cjpeg djpeg jpegtran
+ -$(RM) testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.gif testout.gif
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.mc6 b/gs/jpeg/makefile.mc6
new file mode 100644
index 000000000..a8ab313a7
--- /dev/null
+++ b/gs/jpeg/makefile.mc6
@@ -0,0 +1,233 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Microsoft C for MS-DOS, version 6.00A and up.
+# Use NMAKE, not Microsoft's brain-damaged MAKE.
+# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd.
+
+# Read installation instructions before saying "nmake" !!
+
+# You may need to adjust these compiler options:
+CFLAGS = -AM -Oecigt -Gs -W3
+# -AM medium memory model (or use -AS for small model, if you remove features)
+# -Oecigt -Gs maximum safe optimisation (-Ol has bugs in MSC 6.00A)
+# -W3 warning level 3
+# You might also want to add -G2 if you have an 80286, etc.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# If you change this, you'll need to modify the linker response file
+# name list, below, by hand!
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \
+ jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \
+ jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \
+ jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \
+ jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \
+ jquant1.obj jquant2.obj jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj
+
+# need linker response file because file list > 128 chars
+RFILE = libjpeg.ans
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS) $(RFILE)
+ del libjpeg.lib
+ lib @$(RFILE)
+
+# linker response file for building libjpeg.lib
+$(RFILE) : makefile
+ del $(RFILE)
+ echo libjpeg.lib >$(RFILE)
+# silly want-to-create-it prompt:
+ echo y >>$(RFILE)
+ echo +jcapimin.obj +jcapistd.obj +jctrans.obj +jcparam.obj & >>$(RFILE)
+ echo +jdatadst.obj +jcinit.obj +jcmaster.obj +jcmarker.obj & >>$(RFILE)
+ echo +jcmainct.obj +jcprepct.obj +jccoefct.obj & >>$(RFILE)
+ echo +jccolor.obj +jcsample.obj +jchuff.obj +jcphuff.obj & >>$(RFILE)
+ echo +jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj & >>$(RFILE)
+ echo +jfdctint.obj +jdapimin.obj +jdapistd.obj & >>$(RFILE)
+ echo +jdtrans.obj +jdatasrc.obj +jdmaster.obj +jdinput.obj & >>$(RFILE)
+ echo +jdmarker.obj +jdhuff.obj +jdphuff.obj +jdmainct.obj & >>$(RFILE)
+ echo +jdcoefct.obj +jdpostct.obj +jddctmgr.obj & >>$(RFILE)
+ echo +jidctfst.obj +jidctflt.obj +jidctint.obj & >>$(RFILE)
+ echo +jidctred.obj +jdsample.obj +jdcolor.obj +jquant1.obj & >>$(RFILE)
+ echo +jquant2.obj +jdmerge.obj +jcomapi.obj +jutils.obj & >>$(RFILE)
+ echo +jerror.obj +jmemmgr.obj +jmemdos.obj +jmemdosa.obj ; >>$(RFILE)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ echo $(COBJECTS) >cjpeg.lst
+ link /STACK:4096 /EXEPACK @cjpeg.lst, cjpeg.exe, , libjpeg.lib, ;
+ del cjpeg.lst
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ echo $(DOBJECTS) >djpeg.lst
+ link /STACK:4096 /EXEPACK @djpeg.lst, djpeg.exe, , libjpeg.lib, ;
+ del djpeg.lst
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ link /STACK:4096 /EXEPACK $(TROBJECTS), jpegtran.exe, , libjpeg.lib, ;
+
+rdjpgcom.exe: rdjpgcom.c
+ $(CC) -AS -O -W3 rdjpgcom.c
+
+# wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+ $(CC) -AL -O -W3 wrjpgcom.c
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ del *.obj
+ del libjpeg.lib
+ del cjpeg.exe
+ del djpeg.exe
+ del jpegtran.exe
+ del rdjpgcom.exe
+ del wrjpgcom.exe
+ del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+ del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.gif testout.gif
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj : jmemdosa.asm
+ masm /mx $*;
diff --git a/gs/jpeg/makefile.mms b/gs/jpeg/makefile.mms
new file mode 100644
index 000000000..401fe200f
--- /dev/null
+++ b/gs/jpeg/makefile.mms
@@ -0,0 +1,214 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for use with MMS on Digital VMS systems.
+# Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+# and Tim Bell (tbell@netcom.com) for their help.
+
+# Read installation instructions before saying "MMS" !!
+
+# You may need to adjust these cc options:
+CFLAGS= $(CFLAGS) /NoDebug /Optimize
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via /Define switches here.
+.ifdef ALPHA
+OPT=
+.else
+OPT= ,Sys$Disk:[]MAKVMS.OPT/Option
+.endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \
+ jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \
+ jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \
+ jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \
+ jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \
+ jquant1.obj jquant2.obj jdmerge.obj
+# These objectfiles are included in libjpeg.olb
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj
+# objectfile lists with commas --- what a crock
+COBJLIST= cjpeg.obj,rdppm.obj,rdgif.obj,rdtarga.obj,rdrle.obj,rdbmp.obj,\
+ rdswitch.obj,cdjpeg.obj
+DOBJLIST= djpeg.obj,wrppm.obj,wrgif.obj,wrtarga.obj,wrrle.obj,wrbmp.obj,\
+ rdcolmap.obj,cdjpeg.obj
+TROBJLIST= jpegtran.obj,rdswitch.obj,cdjpeg.obj
+LIBOBJLIST= jcapimin.obj,jcapistd.obj,jctrans.obj,jcparam.obj,jdatadst.obj,\
+ jcinit.obj,jcmaster.obj,jcmarker.obj,jcmainct.obj,jcprepct.obj,\
+ jccoefct.obj,jccolor.obj,jcsample.obj,jchuff.obj,jcphuff.obj,\
+ jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj,jfdctint.obj,jdapimin.obj,\
+ jdapistd.obj,jdtrans.obj,jdatasrc.obj,jdmaster.obj,jdinput.obj,\
+ jdmarker.obj,jdhuff.obj,jdphuff.obj,jdmainct.obj,jdcoefct.obj,\
+ jdpostct.obj,jddctmgr.obj,jidctfst.obj,jidctflt.obj,jidctint.obj,\
+ jidctred.obj,jdsample.obj,jdcolor.obj,jquant1.obj,jquant2.obj,\
+ jdmerge.obj,jcomapi.obj,jutils.obj,jerror.obj,jmemmgr.obj,$(SYSDEPMEM)
+
+
+.first
+ @- Define /NoLog Sys Sys$Library
+
+ALL : libjpeg.olb cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+ @ Continue
+
+libjpeg.olb : $(LIBOBJECTS)
+ Library /Create libjpeg.olb $(LIBOBJLIST)
+
+cjpeg.exe : $(COBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = cjpeg.exe $(COBJLIST),libjpeg.olb/Library$(OPT)
+
+djpeg.exe : $(DOBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = djpeg.exe $(DOBJLIST),libjpeg.olb/Library$(OPT)
+
+jpegtran.exe : $(TROBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = jpegtran.exe $(TROBJLIST),libjpeg.olb/Library$(OPT)
+
+rdjpgcom.exe : rdjpgcom.obj
+ $(LINK) $(LFLAGS) /Executable = rdjpgcom.exe rdjpgcom.obj$(OPT)
+
+wrjpgcom.exe : wrjpgcom.obj
+ $(LINK) $(LFLAGS) /Executable = wrjpgcom.exe wrjpgcom.obj$(OPT)
+
+jconfig.h : jconfig.vms
+ @- Copy jconfig.vms jconfig.h
+
+clean :
+ @- Set Protection = Owner:RWED *.*;-1
+ @- Set Protection = Owner:RWED *.OBJ
+ - Purge /NoLog /NoConfirm *.*
+ - Delete /NoLog /NoConfirm *.OBJ;
+
+test : cjpeg.exe djpeg.exe jpegtran.exe
+ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ mcr sys$disk:[]djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm
+ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+ - Backup /Compare/Log testimg.ppm testout.ppm
+ - Backup /Compare/Log testimg.gif testout.gif
+ - Backup /Compare/Log testimg.jpg testout.jpg
+ - Backup /Compare/Log testimg.ppm testoutp.ppm
+ - Backup /Compare/Log testimgp.jpg testoutp.jpg
+ - Backup /Compare/Log testorig.jpg testoutt.jpg
+
+
+jcapimin.obj : jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj : jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj : jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj : jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj : jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj : jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.obj : jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj : jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj : jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj : jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj : jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj : jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.obj : jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.obj : jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj : jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj : jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj : jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj : jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj : jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj : jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj : jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj : jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj : jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj : jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.obj : jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj : jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj : jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj : jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj : jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.obj : jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.obj : jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj : jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj : jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj : jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj : jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj : jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj : jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj : jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj : jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj : jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.obj : jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj : jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj : jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj : jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj : jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj : jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj : jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj : jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj : jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj : jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj : cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj : djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj : jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.obj : cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj : rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj : rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.obj : rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj : wrjpgcom.c jinclude.h jconfig.h
+rdppm.obj : rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj : wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj : rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj : wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj : rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj : wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj : rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj : wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj : rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj : wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.sas b/gs/jpeg/makefile.sas
new file mode 100644
index 000000000..14be5a46a
--- /dev/null
+++ b/gs/jpeg/makefile.sas
@@ -0,0 +1,244 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using SAS C 6.0 and up.
+# Thanks to Ed Hanway, Mark Rinfret, and Jim Zepeda.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= sc
+
+# You may need to adjust these cc options:
+# Uncomment the following lines for generic 680x0 version
+ARCHFLAGS= cpu=any
+SUFFIX=
+
+# Uncomment the following lines for 68030-only version
+#ARCHFLAGS= cpu=68030
+#SUFFIX=.030
+
+CFLAGS= nostackcheck data=near parms=register optimize $(ARCHFLAGS) \
+ ignore=104 ignore=304 ignore=306
+# ignore=104 disables warnings for mismatched const qualifiers
+# ignore=304 disables warnings for variables being optimized out
+# ignore=306 disables warnings for the inlining of functions
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via define switches here.
+
+# Link-time cc options:
+LDFLAGS= SC SD ND BATCH
+
+# To link any special libraries, add the necessary commands here.
+LDLIBS= LIB:scm.lib LIB:sc.lib
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= slink
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= oml
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: libjpeg.lib cjpeg$(SUFFIX) djpeg$(SUFFIX) jpegtran$(SUFFIX) rdjpgcom$(SUFFIX) wrjpgcom$(SUFFIX)
+
+libjpeg.lib: $(LIBOBJECTS)
+ -$(RM) libjpeg.lib
+ $(AR) libjpeg.lib r $(LIBOBJECTS)
+
+cjpeg$(SUFFIX): $(COBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO cjpeg$(SUFFIX)
+FROM LIB:c.o $(COBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+djpeg$(SUFFIX): $(DOBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO djpeg$(SUFFIX)
+FROM LIB:c.o $(DOBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+jpegtran$(SUFFIX): $(TROBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO jpegtran$(SUFFIX)
+FROM LIB:c.o $(TROBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+rdjpgcom$(SUFFIX): rdjpgcom.o
+ $(LN) <WITH <
+$(LDFLAGS)
+TO rdjpgcom$(SUFFIX)
+FROM LIB:c.o rdjpgcom.o
+LIB $(LDLIBS)
+<
+
+wrjpgcom$(SUFFIX): wrjpgcom.o
+ $(LN) <WITH <
+$(LDFLAGS)
+TO wrjpgcom$(SUFFIX)
+FROM LIB:c.o wrjpgcom.o
+LIB $(LDLIBS)
+<
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ -$(RM) *.o cjpeg djpeg jpegtran cjpeg.030 djpeg.030 jpegtran.030
+ -$(RM) rdjpgcom wrjpgcom rdjpgcom.030 wrjpgcom.030
+ -$(RM) libjpeg.lib core testout*.*
+
+test: cjpeg djpeg jpegtran
+ -$(RM) testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.gif testout.gif
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.unix b/gs/jpeg/makefile.unix
new file mode 100644
index 000000000..2ce9820df
--- /dev/null
+++ b/gs/jpeg/makefile.unix
@@ -0,0 +1,224 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Unix-like systems with non-ANSI compilers.
+# If you have an ANSI compiler, makefile.ansi is a better starting point.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+CFLAGS= -O
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+# However, any special defines for ansi2knr.c may be included here:
+ANSI2KNRFLAGS=
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# file rename command
+MV= mv
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c \
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c \
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st \
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms \
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc \
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \
+ jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \
+ jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \
+ jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \
+ jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \
+ jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \
+ jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o
+
+
+all: ansi2knr libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# This rule causes ansi2knr to be invoked.
+.c.o:
+ ./ansi2knr $*.c T$*.c
+ $(CC) $(CFLAGS) -c T$*.c
+ $(RM) T$*.c $*.o
+ $(MV) T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libjpeg.a: ansi2knr $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: ansi2knr $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: ansi2knr $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: ansi2knr $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) ansi2knr core testout*
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ ./djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ ./jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.gif testout.gif
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makefile.vms b/gs/jpeg/makefile.vms
new file mode 100644
index 000000000..4501847fa
--- /dev/null
+++ b/gs/jpeg/makefile.vms
@@ -0,0 +1,141 @@
+$! Makefile for Independent JPEG Group's software
+$!
+$! This is a command procedure for Digital VMS systems that do not have MMS.
+$! It builds the JPEG software by brute force, recompiling everything whether
+$! or not it is necessary. It then runs the basic self-test.
+$! Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+$! and Tim Bell (tbell@netcom.com) for their help.
+$!
+$! Read installation instructions before running this!!
+$!
+$ If F$Mode () .eqs. "INTERACTIVE"
+$ Then
+$ VERIFY = F$Verify (0)
+$ Else
+$ VERIFY = F$Verify (1)
+$ EndIf
+$ On Control_Y Then GoTo End
+$ On Error Then GoTo End
+$
+$ If F$GetSyi ("HW_MODEL") .gt. 1023
+$ Then
+$ OPT = ""
+$ Else
+$ OPT = ",Sys$Disk:[]makvms.opt/Option"
+$ EndIf
+$
+$ DoCompile := CC /NoDebug /Optimize /NoList
+$!
+$ DoCompile jcapimin.c
+$ DoCompile jcapistd.c
+$ DoCompile jctrans.c
+$ DoCompile jcparam.c
+$ DoCompile jdatadst.c
+$ DoCompile jcinit.c
+$ DoCompile jcmaster.c
+$ DoCompile jcmarker.c
+$ DoCompile jcmainct.c
+$ DoCompile jcprepct.c
+$ DoCompile jccoefct.c
+$ DoCompile jccolor.c
+$ DoCompile jcsample.c
+$ DoCompile jchuff.c
+$ DoCompile jcphuff.c
+$ DoCompile jcdctmgr.c
+$ DoCompile jfdctfst.c
+$ DoCompile jfdctflt.c
+$ DoCompile jfdctint.c
+$ DoCompile jdapimin.c
+$ DoCompile jdapistd.c
+$ DoCompile jdtrans.c
+$ DoCompile jdatasrc.c
+$ DoCompile jdmaster.c
+$ DoCompile jdinput.c
+$ DoCompile jdmarker.c
+$ DoCompile jdhuff.c
+$ DoCompile jdphuff.c
+$ DoCompile jdmainct.c
+$ DoCompile jdcoefct.c
+$ DoCompile jdpostct.c
+$ DoCompile jddctmgr.c
+$ DoCompile jidctfst.c
+$ DoCompile jidctflt.c
+$ DoCompile jidctint.c
+$ DoCompile jidctred.c
+$ DoCompile jdsample.c
+$ DoCompile jdcolor.c
+$ DoCompile jquant1.c
+$ DoCompile jquant2.c
+$ DoCompile jdmerge.c
+$ DoCompile jcomapi.c
+$ DoCompile jutils.c
+$ DoCompile jerror.c
+$ DoCompile jmemmgr.c
+$ DoCompile jmemnobs.c
+$!
+$ Library /Create libjpeg.olb jcapimin.obj,jcapistd.obj,jctrans.obj, -
+ jcparam.obj,jdatadst.obj,jcinit.obj,jcmaster.obj,jcmarker.obj, -
+ jcmainct.obj,jcprepct.obj,jccoefct.obj,jccolor.obj,jcsample.obj, -
+ jchuff.obj,jcphuff.obj,jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj, -
+ jfdctint.obj,jdapimin.obj,jdapistd.obj,jdtrans.obj,jdatasrc.obj, -
+ jdmaster.obj,jdinput.obj,jdmarker.obj,jdhuff.obj,jdphuff.obj, -
+ jdmainct.obj,jdcoefct.obj,jdpostct.obj,jddctmgr.obj,jidctfst.obj, -
+ jidctflt.obj,jidctint.obj,jidctred.obj,jdsample.obj,jdcolor.obj, -
+ jquant1.obj,jquant2.obj,jdmerge.obj,jcomapi.obj,jutils.obj, -
+ jerror.obj,jmemmgr.obj,jmemnobs.obj
+$!
+$ DoCompile cjpeg.c
+$ DoCompile rdppm.c
+$ DoCompile rdgif.c
+$ DoCompile rdtarga.c
+$ DoCompile rdrle.c
+$ DoCompile rdbmp.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = cjpeg.exe cjpeg.obj,rdppm.obj,rdgif.obj, -
+ rdtarga.obj,rdrle.obj,rdbmp.obj,rdswitch.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile djpeg.c
+$ DoCompile wrppm.c
+$ DoCompile wrgif.c
+$ DoCompile wrtarga.c
+$ DoCompile wrrle.c
+$ DoCompile wrbmp.c
+$ DoCompile rdcolmap.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = djpeg.exe djpeg.obj,wrppm.obj,wrgif.obj, -
+ wrtarga.obj,wrrle.obj,wrbmp.obj,rdcolmap.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile jpegtran.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = jpegtran.exe jpegtran.obj,rdswitch.obj, -
+ cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile rdjpgcom.c
+$ Link /NoMap /Executable = rdjpgcom.exe rdjpgcom.obj'OPT'
+$!
+$ DoCompile wrjpgcom.c
+$ Link /NoMap /Executable = wrjpgcom.exe wrjpgcom.obj'OPT'
+$!
+$! Run the self-test
+$!
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+$ mcr sys$disk:[]djpeg -dct int -gif -outfile testout.gif testorig.jpg
+$ mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+$ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+$ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+$ Backup /Compare/Log testimg.ppm testout.ppm
+$ Backup /Compare/Log testimg.gif testout.gif
+$ Backup /Compare/Log testimg.jpg testout.jpg
+$ Backup /Compare/Log testimg.ppm testoutp.ppm
+$ Backup /Compare/Log testimgp.jpg testoutp.jpg
+$ Backup /Compare/Log testorig.jpg testoutt.jpg
+$!
+$End:
+$ If Verify Then Set Verify
+$ Exit
diff --git a/gs/jpeg/makefile.wat b/gs/jpeg/makefile.wat
new file mode 100644
index 000000000..ff022a082
--- /dev/null
+++ b/gs/jpeg/makefile.wat
@@ -0,0 +1,229 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Watcom C/C++ 10.0 on MS-DOS (using
+# dos4g extender), OS/2, and Windows NT console mode.
+# Thanks to Janos Haide, jhaide@btrvtech.com.
+
+# Read installation instructions before saying "wmake" !!
+
+# Uncomment line for desired system
+SYSTEM=DOS
+#SYSTEM=OS2
+#SYSTEM=NT
+
+# The name of your C compiler:
+CC= wcl386
+
+# You may need to adjust these cc options:
+CFLAGS= -4r -ort -wx -zq -bt=$(SYSTEM)
+# Caution: avoid -ol or -ox; these generate bad code with 10.0 or 10.0a.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!ifeq SYSTEM DOS
+LDFLAGS= -zq -l=dos4g
+!else ifeq SYSTEM OS2
+LDFLAGS= -zq -l=os2v2
+!else ifeq SYSTEM NT
+LDFLAGS= -zq -l=nt
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. jmemnobs should work fine for dos4g or OS/2 environment.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c &
+ jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c &
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c &
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c &
+ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c &
+ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c &
+ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c &
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c cdjpeg.c rdcolmap.c rdswitch.c &
+ rdjpgcom.c wrjpgcom.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c &
+ wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h &
+ jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h
+# documentation, test, and support files
+DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 &
+ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc &
+ coderules.doc filelist.doc change.log
+MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc &
+ makefile.mc6 makefile.dj makefile.wat makcjpeg.st makdjpeg.st &
+ makljpeg.st maktjpeg.st makefile.manx makefile.sas makefile.mms &
+ makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.manx jconfig.sas jconfig.st jconfig.bcc &
+ jconfig.mc6 jconfig.dj jconfig.wat jconfig.vms
+OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg testprog.jpg &
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) &
+ $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj &
+ jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj &
+ jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj &
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj &
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj &
+ jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj &
+ jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj &
+ jquant1.obj jquant2.obj jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj &
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj &
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+ - del libjpeg.lib
+ * wlib -n libjpeg.lib $(LIBOBJECTS)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+ $(CC) $(CFLAGS) $(LDFLAGS) rdjpgcom.c
+
+wrjpgcom.exe: wrjpgcom.c
+ $(CC) $(CFLAGS) $(LDFLAGS) wrjpgcom.c
+
+.c.obj:
+ $(CC) $(CFLAGS) -c $<
+
+jconfig.h: jconfig.doc
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.doc.
+ exit 1
+
+clean: .SYMBOLIC
+ - del *.obj
+ - del libjpeg.lib
+ - del cjpeg.exe
+ - del djpeg.exe
+ - del jpegtran.exe
+ - del rdjpgcom.exe
+ - del wrjpgcom.exe
+ - del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe .SYMBOLIC
+ - del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -gif -outfile testout.gif testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+!ifeq SYSTEM DOS
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.gif testout.gif
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+!else
+ echo n > n.tmp
+ comp testimg.ppm testout.ppm < n.tmp
+ comp testimg.gif testout.gif < n.tmp
+ comp testimg.jpg testout.jpg < n.tmp
+ comp testimg.ppm testoutp.ppm < n.tmp
+ comp testimgp.jpg testoutp.jpg < n.tmp
+ comp testorig.jpg testoutt.jpg < n.tmp
+ del n.tmp
+!endif
+
+
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/gs/jpeg/makljpeg.st b/gs/jpeg/makljpeg.st
new file mode 100644
index 000000000..435e23411
--- /dev/null
+++ b/gs/jpeg/makljpeg.st
@@ -0,0 +1,69 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de)
+; and to Dr. B. Setzepfandt (bernd@gina.uni-muenster.de).
+;
+; To use this file, rename it to LIBJPEG.PRJ.
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+libjpeg.lib
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+.L[-J] ; link new Obj-format (so we get a library)
+=
+; * * * * List of modules * * * *
+jcapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcdctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jchuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jchuff.h)
+jcinit.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcomapi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcparam.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcphuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jchuff.h)
+jcprepct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jctrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdatadst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdatasrc.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdcoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdcolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jddctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jdhuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdhuff.h)
+jdinput.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmerge.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdphuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdhuff.h)
+jdpostct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdtrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jerror.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jversion.h,jerror.h)
+jfdctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctred.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jquant1.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jquant2.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jutils.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jmemmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
+jmemansi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
diff --git a/gs/jpeg/maktjpeg.st b/gs/jpeg/maktjpeg.st
new file mode 100644
index 000000000..48e57e2c3
--- /dev/null
+++ b/gs/jpeg/maktjpeg.st
@@ -0,0 +1,30 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de)
+; and to Dr. B. Setzepfandt (bernd@gina.uni-muenster.de).
+;
+; To use this file, rename it to JPEGTRAN.PRJ.
+; If you are using Turbo C, change filenames beginning with "PC..." to "TC..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+jpegtran.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+PCSTART.O
+jpegtran.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+LIBJPEG.LIB ; built by LIBJPEG.PRJ
+PCSTDLIB.LIB ; standard library
+PCEXTLIB.LIB ; extended library
diff --git a/gs/jpeg/makvms.opt b/gs/jpeg/makvms.opt
new file mode 100644
index 000000000..675e8fe98
--- /dev/null
+++ b/gs/jpeg/makvms.opt
@@ -0,0 +1,4 @@
+! A pointer to the VAX/VMS C Run-Time Shareable Library.
+! This file is needed by makefile.mms and makefile.vms,
+! but only for the older VAX C compiler. DEC C does not need it.
+Sys$Library:VAXCRTL.EXE /Share
diff --git a/gs/jpeg/rdbmp.c b/gs/jpeg/rdbmp.c
new file mode 100644
index 000000000..b05fe2ac4
--- /dev/null
+++ b/gs/jpeg/rdbmp.c
@@ -0,0 +1,439 @@
+/*
+ * rdbmp.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Microsoft "BMP"
+ * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
+ * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
+ * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
+ * Also, we don't support RLE-compressed files.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed BMP format).
+ *
+ * This code contributed by James Arthur Boucher.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef BMP_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _bmp_source_struct * bmp_source_ptr;
+
+typedef struct _bmp_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ j_compress_ptr cinfo; /* back link saves passing separate parm */
+
+ JSAMPARRAY colormap; /* BMP colormap (converted to my format) */
+
+ jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
+ JDIMENSION source_row; /* Current source row number */
+ JDIMENSION row_width; /* Physical width of scanlines in file */
+
+ int bits_per_pixel; /* remembers 8- or 24-bit format */
+} bmp_source_struct;
+
+
+LOCAL(int)
+read_byte (bmp_source_ptr sinfo)
+/* Read next byte from BMP file */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int c;
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ return c;
+}
+
+
+LOCAL(void)
+read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a BMP file */
+{
+ int i;
+
+ switch (mapentrysize) {
+ case 3:
+ /* BGR format (occurs in OS/2 files) */
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ }
+ break;
+ case 4:
+ /* BGR0 format (occurs in MS Windows files) */
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ (void) read_byte(sinfo);
+ }
+ break;
+ default:
+ ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
+ break;
+ }
+}
+
+
+/*
+ * Read one row of pixels.
+ * The image has been read into the whole_image array, but is otherwise
+ * unprocessed. We must read it out in top-to-bottom row order, and if
+ * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
+ */
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ register JSAMPARRAY colormap = source->colormap;
+ JSAMPARRAY image_ptr;
+ register int t;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+
+ /* Expand the colormap indexes to real data */
+ inptr = image_ptr[0];
+ outptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
+ *outptr++ = colormap[1][t];
+ *outptr++ = colormap[2][t];
+ }
+
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+
+ /* Transfer data. Note source values are in BGR order
+ * (even though Microsoft's own documents say the opposite).
+ */
+ inptr = image_ptr[0];
+ outptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[1] = *inptr++;
+ outptr[0] = *inptr++;
+ outptr += 3;
+ }
+
+ return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
+ * get_8bit_row or get_24bit_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ register FILE *infile = source->pub.input_file;
+ register int c;
+ register JSAMPROW out_ptr;
+ JSAMPARRAY image_ptr;
+ JDIMENSION row, col;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Read the data into a virtual array in input-file row order. */
+ for (row = 0; row < cinfo->image_height; row++) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) row;
+ progress->pub.pass_limit = (long) cinfo->image_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ row, (JDIMENSION) 1, TRUE);
+ out_ptr = image_ptr[0];
+ for (col = source->row_width; col > 0; col--) {
+ /* inline copy of read_byte() for speed */
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ *out_ptr++ = (JSAMPLE) c;
+ }
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Set up to read from the virtual array in top-to-bottom order */
+ switch (source->bits_per_pixel) {
+ case 8:
+ source->pub.get_pixel_rows = get_8bit_row;
+ break;
+ case 24:
+ source->pub.get_pixel_rows = get_24bit_row;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ }
+ source->source_row = cinfo->image_height;
+
+ /* And read the first row */
+ return (*source->pub.get_pixel_rows) (cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ U_CHAR bmpfileheader[14];
+ U_CHAR bmpinfoheader[64];
+#define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \
+ (((unsigned int) UCH(array[offset+1])) << 8))
+#define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \
+ (((INT32) UCH(array[offset+1])) << 8) + \
+ (((INT32) UCH(array[offset+2])) << 16) + \
+ (((INT32) UCH(array[offset+3])) << 24))
+ INT32 bfOffBits;
+ INT32 headerSize;
+ INT32 biWidth = 0; /* initialize to avoid compiler warning */
+ INT32 biHeight = 0;
+ unsigned int biPlanes;
+ INT32 biCompression;
+ INT32 biXPelsPerMeter,biYPelsPerMeter;
+ INT32 biClrUsed = 0;
+ int mapentrysize = 0; /* 0 indicates no colormap */
+ INT32 bPad;
+ JDIMENSION row_width;
+
+ /* Read and verify the bitmap file header */
+ if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */
+ ERREXIT(cinfo, JERR_BMP_NOT);
+ bfOffBits = (INT32) GET_4B(bmpfileheader,10);
+ /* We ignore the remaining fileheader fields */
+
+ /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
+ * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
+ */
+ if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ headerSize = (INT32) GET_4B(bmpinfoheader,0);
+ if (headerSize < 12 || headerSize > 64)
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+
+ switch ((int) headerSize) {
+ case 12:
+ /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
+ biWidth = (INT32) GET_2B(bmpinfoheader,4);
+ biHeight = (INT32) GET_2B(bmpinfoheader,6);
+ biPlanes = GET_2B(bmpinfoheader,8);
+ source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10);
+
+ switch (source->bits_per_pixel) {
+ case 8: /* colormapped image */
+ mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
+ TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
+ break;
+ case 24: /* RGB image */
+ TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ break;
+ }
+ if (biPlanes != 1)
+ ERREXIT(cinfo, JERR_BMP_BADPLANES);
+ break;
+ case 40:
+ case 64:
+ /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
+ /* or OS/2 2.x header, which has additional fields that we ignore */
+ biWidth = GET_4B(bmpinfoheader,4);
+ biHeight = GET_4B(bmpinfoheader,8);
+ biPlanes = GET_2B(bmpinfoheader,12);
+ source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14);
+ biCompression = GET_4B(bmpinfoheader,16);
+ biXPelsPerMeter = GET_4B(bmpinfoheader,24);
+ biYPelsPerMeter = GET_4B(bmpinfoheader,28);
+ biClrUsed = GET_4B(bmpinfoheader,32);
+ /* biSizeImage, biClrImportant fields are ignored */
+
+ switch (source->bits_per_pixel) {
+ case 8: /* colormapped image */
+ mapentrysize = 4; /* Windows uses RGBQUAD colormap */
+ TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
+ break;
+ case 24: /* RGB image */
+ TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ break;
+ }
+ if (biPlanes != 1)
+ ERREXIT(cinfo, JERR_BMP_BADPLANES);
+ if (biCompression != 0)
+ ERREXIT(cinfo, JERR_BMP_COMPRESSED);
+
+ if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
+ /* Set JFIF density parameters from the BMP data */
+ cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
+ cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
+ cinfo->density_unit = 2; /* dots/cm */
+ }
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ break;
+ }
+
+ /* Compute distance to bitmap data --- will adjust for colormap below */
+ bPad = bfOffBits - (headerSize + 14);
+
+ /* Read the colormap, if any */
+ if (mapentrysize > 0) {
+ if (biClrUsed <= 0)
+ biClrUsed = 256; /* assume it's 256 */
+ else if (biClrUsed > 256)
+ ERREXIT(cinfo, JERR_BMP_BADCMAP);
+ /* Allocate space to store the colormap */
+ source->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) biClrUsed, (JDIMENSION) 3);
+ /* and read it from the file */
+ read_colormap(source, (int) biClrUsed, mapentrysize);
+ /* account for size of colormap */
+ bPad -= biClrUsed * mapentrysize;
+ }
+
+ /* Skip any remaining pad bytes */
+ if (bPad < 0) /* incorrect bfOffBits value? */
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ while (--bPad >= 0) {
+ (void) read_byte(source);
+ }
+
+ /* Compute row width in file, including padding to 4-byte boundary */
+ if (source->bits_per_pixel == 24)
+ row_width = (JDIMENSION) (biWidth * 3);
+ else
+ row_width = (JDIMENSION) biWidth;
+ while ((row_width & 3) != 0) row_width++;
+ source->row_width = row_width;
+
+ /* Allocate space for inversion array, prepare for preload pass */
+ source->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
+ source->pub.get_pixel_rows = preload_image;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+
+ /* Allocate one-row buffer for returned data */
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+
+ cinfo->in_color_space = JCS_RGB;
+ cinfo->input_components = 3;
+ cinfo->data_precision = 8;
+ cinfo->image_width = (JDIMENSION) biWidth;
+ cinfo->image_height = (JDIMENSION) biHeight;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for BMP format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_bmp (j_compress_ptr cinfo)
+{
+ bmp_source_ptr source;
+
+ /* Create module interface object */
+ source = (bmp_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(bmp_source_struct));
+ source->cinfo = cinfo; /* make back link for subroutines */
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_bmp;
+ source->pub.finish_input = finish_input_bmp;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* BMP_SUPPORTED */
diff --git a/gs/jpeg/rdcolmap.c b/gs/jpeg/rdcolmap.c
new file mode 100644
index 000000000..f79458edc
--- /dev/null
+++ b/gs/jpeg/rdcolmap.c
@@ -0,0 +1,253 @@
+/*
+ * rdcolmap.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file implements djpeg's "-map file" switch. It reads a source image
+ * and constructs a colormap to be supplied to the JPEG decompressor.
+ *
+ * Currently, these file formats are supported for the map file:
+ * GIF: the contents of the GIF's global colormap are used.
+ * PPM (either text or raw flavor): the entire file is read and
+ * each unique pixel value is entered in the map.
+ * Note that reading a large PPM file will be horrendously slow.
+ * Typically, a PPM-format map file should contain just one pixel
+ * of each desired color. Such a file can be extracted from an
+ * ordinary image PPM file with ppmtomap(1).
+ *
+ * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
+ * currently implemented.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/*
+ * Add a (potentially) new color to the color map.
+ */
+
+LOCAL(void)
+add_map_entry (j_decompress_ptr cinfo, int R, int G, int B)
+{
+ JSAMPROW colormap0 = cinfo->colormap[0];
+ JSAMPROW colormap1 = cinfo->colormap[1];
+ JSAMPROW colormap2 = cinfo->colormap[2];
+ int ncolors = cinfo->actual_number_of_colors;
+ int index;
+
+ /* Check for duplicate color. */
+ for (index = 0; index < ncolors; index++) {
+ if (GETJSAMPLE(colormap0[index]) == R &&
+ GETJSAMPLE(colormap1[index]) == G &&
+ GETJSAMPLE(colormap2[index]) == B)
+ return; /* color is already in map */
+ }
+
+ /* Check for map overflow. */
+ if (ncolors >= (MAXJSAMPLE+1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));
+
+ /* OK, add color to map. */
+ colormap0[ncolors] = (JSAMPLE) R;
+ colormap1[ncolors] = (JSAMPLE) G;
+ colormap2[ncolors] = (JSAMPLE) B;
+ cinfo->actual_number_of_colors++;
+}
+
+
+/*
+ * Extract color map from a GIF file.
+ */
+
+LOCAL(void)
+read_gif_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ int header[13];
+ int i, colormaplen;
+ int R, G, B;
+
+ /* Initial 'G' has already been read by read_color_map */
+ /* Read the rest of the GIF header and logical screen descriptor */
+ for (i = 1; i < 13; i++) {
+ if ((header[i] = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ }
+
+ /* Verify GIF Header */
+ if (header[1] != 'I' || header[2] != 'F')
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* There must be a global color map. */
+ if ((header[10] & 0x80) == 0)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* OK, fetch it. */
+ colormaplen = 2 << (header[10] & 0x07);
+
+ for (i = 0; i < colormaplen; i++) {
+ R = getc(infile);
+ G = getc(infile);
+ B = getc(infile);
+ if (R == EOF || G == EOF || B == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ add_map_entry(cinfo,
+ R << (BITS_IN_JSAMPLE-8),
+ G << (BITS_IN_JSAMPLE-8),
+ B << (BITS_IN_JSAMPLE-8));
+ }
+}
+
+
+/* Support routines for reading PPM */
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(infile);
+ if (ch == '#') {
+ do {
+ ch = getc(infile);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_decompress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+ register int ch;
+ register unsigned int val;
+
+ /* Skip any leading whitespace */
+ do {
+ ch = pbm_getc(infile);
+ if (ch == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+ if (ch < '0' || ch > '9')
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ val = ch - '0';
+ while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+ val *= 10;
+ val += ch - '0';
+ }
+ return val;
+}
+
+
+/*
+ * Extract color map from a PPM file.
+ */
+
+LOCAL(void)
+read_ppm_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ int c;
+ unsigned int w, h, maxval, row, col;
+ int R, G, B;
+
+ /* Initial 'P' has already been read by read_color_map */
+ c = getc(infile); /* save format discriminator for a sec */
+
+ /* while we fetch the remaining header info */
+ w = read_pbm_integer(cinfo, infile);
+ h = read_pbm_integer(cinfo, infile);
+ maxval = read_pbm_integer(cinfo, infile);
+
+ if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* For now, we don't support rescaling from an unusual maxval. */
+ if (maxval != (unsigned int) MAXJSAMPLE)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ switch (c) {
+ case '3': /* it's a text-format PPM file */
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ R = read_pbm_integer(cinfo, infile);
+ G = read_pbm_integer(cinfo, infile);
+ B = read_pbm_integer(cinfo, infile);
+ add_map_entry(cinfo, R, G, B);
+ }
+ }
+ break;
+
+ case '6': /* it's a raw-format PPM file */
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ R = pbm_getc(infile);
+ G = pbm_getc(infile);
+ B = pbm_getc(infile);
+ if (R == EOF || G == EOF || B == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ add_map_entry(cinfo, R, G, B);
+ }
+ }
+ break;
+
+ default:
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ break;
+ }
+}
+
+
+/*
+ * Main entry point from djpeg.c.
+ * Input: opened input file (from file name argument on command line).
+ * Output: colormap and actual_number_of_colors fields are set in cinfo.
+ */
+
+GLOBAL(void)
+read_color_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ /* Allocate space for a color map of maximum supported size. */
+ cinfo->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
+ cinfo->actual_number_of_colors = 0; /* initialize map to empty */
+
+ /* Read first byte to determine file format */
+ switch (getc(infile)) {
+ case 'G':
+ read_gif_map(cinfo, infile);
+ break;
+ case 'P':
+ read_ppm_map(cinfo, infile);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ break;
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/gs/jpeg/rdgif.c b/gs/jpeg/rdgif.c
new file mode 100644
index 000000000..0da2515cb
--- /dev/null
+++ b/gs/jpeg/rdgif.c
@@ -0,0 +1,683 @@
+/*
+ * rdgif.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ **************************************************************************
+ * WARNING: You will need an LZW patent license from Unisys in order to *
+ * use this file legally in any commercial or shareware application. *
+ **************************************************************************
+ *
+ * This file contains routines to read input images in GIF format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; input_init may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed GIF format).
+ */
+
+/*
+ * This code is loosely based on giftoppm from the PBMPLUS distribution
+ * of Feb. 1991. That file contains the following copyright notice:
+ * +-------------------------------------------------------------------+
+ * | Copyright 1990, David Koblas. |
+ * | Permission to use, copy, modify, and distribute this software |
+ * | and its documentation for any purpose and without fee is hereby |
+ * | granted, provided that the above copyright notice appear in all |
+ * | copies and that both that copyright notice and this permission |
+ * | notice appear in supporting documentation. This software is |
+ * | provided "as is" without express or implied warranty. |
+ * +-------------------------------------------------------------------+
+ *
+ * We are also required to state that
+ * "The Graphics Interchange Format(c) is the Copyright property of
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ * CompuServe Incorporated."
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef GIF_SUPPORTED
+
+
+#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */
+#define NUMCOLORS 3 /* # of colors */
+#define CM_RED 0 /* color component numbers */
+#define CM_GREEN 1
+#define CM_BLUE 2
+
+#define MAX_LZW_BITS 12 /* maximum LZW code size */
+#define LZW_TABLE_SIZE (1<<MAX_LZW_BITS) /* # of possible LZW symbols */
+
+/* Macros for extracting header data --- note we assume chars may be signed */
+
+#define LM_to_uint(a,b) ((((b)&0xFF) << 8) | ((a)&0xFF))
+
+#define BitSet(byte, bit) ((byte) & (bit))
+#define INTERLACE 0x40 /* mask for bit signifying interlaced image */
+#define COLORMAPFLAG 0x80 /* mask for bit signifying colormap presence */
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+/* LZW decompression tables look like this:
+ * symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)
+ * symbol_tail[K] = suffix byte of any LZW symbol K (0..LZW_TABLE_SIZE-1)
+ * Note that entries 0..end_code of the above tables are not used,
+ * since those symbols represent raw bytes or special codes.
+ *
+ * The stack represents the not-yet-used expansion of the last LZW symbol.
+ * In the worst case, a symbol could expand to as many bytes as there are
+ * LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.
+ * (This is conservative since that number includes the raw-byte symbols.)
+ *
+ * The tables are allocated from FAR heap space since they would use up
+ * rather a lot of the near data space in a PC.
+ */
+
+
+/* Private version of data source object */
+
+typedef struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ j_compress_ptr cinfo; /* back link saves passing separate parm */
+
+ JSAMPARRAY colormap; /* GIF colormap (converted to my format) */
+
+ /* State for GetCode and LZWReadByte */
+ char code_buf[256+4]; /* current input data block */
+ int last_byte; /* # of bytes in code_buf */
+ int last_bit; /* # of bits in code_buf */
+ int cur_bit; /* next bit index to read */
+ boolean out_of_blocks; /* TRUE if hit terminator data block */
+
+ int input_code_size; /* codesize given in GIF file */
+ int clear_code,end_code; /* values for Clear and End codes */
+
+ int code_size; /* current actual code size */
+ int limit_code; /* 2^code_size */
+ int max_code; /* first unused code value */
+ boolean first_time; /* flags first call to LZWReadByte */
+
+ /* Private state for LZWReadByte */
+ int oldcode; /* previous LZW symbol */
+ int firstcode; /* first byte of oldcode's expansion */
+
+ /* LZW symbol table and expansion stack */
+ UINT16 FAR *symbol_head; /* => table of prefix symbols */
+ UINT8 FAR *symbol_tail; /* => table of suffix bytes */
+ UINT8 FAR *symbol_stack; /* => stack for symbol expansions */
+ UINT8 FAR *sp; /* stack pointer */
+
+ /* State for interlaced image processing */
+ boolean is_interlaced; /* TRUE if have interlaced image */
+ jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
+ JDIMENSION cur_row_number; /* need to know actual row number */
+ JDIMENSION pass2_offset; /* # of pixel rows in pass 1 */
+ JDIMENSION pass3_offset; /* # of pixel rows in passes 1&2 */
+ JDIMENSION pass4_offset; /* # of pixel rows in passes 1,2,3 */
+} gif_source_struct;
+
+typedef gif_source_struct * gif_source_ptr;
+
+
+/* Forward declarations */
+METHODDEF(JDIMENSION) get_pixel_rows
+ JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
+METHODDEF(JDIMENSION) load_interlaced_image
+ JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
+METHODDEF(JDIMENSION) get_interlaced_row
+ JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
+
+
+LOCAL(int)
+ReadByte (gif_source_ptr sinfo)
+/* Read next byte from GIF file */
+{
+ register FILE * infile = sinfo->pub.input_file;
+ int c;
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ return c;
+}
+
+
+LOCAL(int)
+GetDataBlock (gif_source_ptr sinfo, char *buf)
+/* Read a GIF data block, which has a leading count byte */
+/* A zero-length block marks the end of a data block sequence */
+{
+ int count;
+
+ count = ReadByte(sinfo);
+ if (count > 0) {
+ if (! ReadOK(sinfo->pub.input_file, buf, count))
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ }
+ return count;
+}
+
+
+LOCAL(void)
+SkipDataBlocks (gif_source_ptr sinfo)
+/* Skip a series of data blocks, until a block terminator is found */
+{
+ char buf[256];
+
+ while (GetDataBlock(sinfo, buf) > 0)
+ /* skip */;
+}
+
+
+LOCAL(void)
+ReInitLZW (gif_source_ptr sinfo)
+/* (Re)initialize LZW state; shared code for startup and Clear processing */
+{
+ sinfo->code_size = sinfo->input_code_size + 1;
+ sinfo->limit_code = sinfo->clear_code << 1; /* 2^code_size */
+ sinfo->max_code = sinfo->clear_code + 2; /* first unused code value */
+ sinfo->sp = sinfo->symbol_stack; /* init stack to empty */
+}
+
+
+LOCAL(void)
+InitLZWCode (gif_source_ptr sinfo)
+/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
+{
+ /* GetCode initialization */
+ sinfo->last_byte = 2; /* make safe to "recopy last two bytes" */
+ sinfo->last_bit = 0; /* nothing in the buffer */
+ sinfo->cur_bit = 0; /* force buffer load on first call */
+ sinfo->out_of_blocks = FALSE;
+
+ /* LZWReadByte initialization: */
+ /* compute special code values (note that these do not change later) */
+ sinfo->clear_code = 1 << sinfo->input_code_size;
+ sinfo->end_code = sinfo->clear_code + 1;
+ sinfo->first_time = TRUE;
+ ReInitLZW(sinfo);
+}
+
+
+LOCAL(int)
+GetCode (gif_source_ptr sinfo)
+/* Fetch the next code_size bits from the GIF data */
+/* We assume code_size is less than 16 */
+{
+ register INT32 accum;
+ int offs, ret, count;
+
+ while ( (sinfo->cur_bit + sinfo->code_size) > sinfo->last_bit) {
+ /* Time to reload the buffer */
+ if (sinfo->out_of_blocks) {
+ WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
+ return sinfo->end_code; /* fake something useful */
+ }
+ /* preserve last two bytes of what we have -- assume code_size <= 16 */
+ sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
+ sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
+ /* Load more bytes; set flag if we reach the terminator block */
+ if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) {
+ sinfo->out_of_blocks = TRUE;
+ WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
+ return sinfo->end_code; /* fake something useful */
+ }
+ /* Reset counters */
+ sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
+ sinfo->last_byte = 2 + count;
+ sinfo->last_bit = sinfo->last_byte * 8;
+ }
+
+ /* Form up next 24 bits in accum */
+ offs = sinfo->cur_bit >> 3; /* byte containing cur_bit */
+#ifdef CHAR_IS_UNSIGNED
+ accum = sinfo->code_buf[offs+2];
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs+1];
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs];
+#else
+ accum = sinfo->code_buf[offs+2] & 0xFF;
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs+1] & 0xFF;
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs] & 0xFF;
+#endif
+
+ /* Right-align cur_bit in accum, then mask off desired number of bits */
+ accum >>= (sinfo->cur_bit & 7);
+ ret = ((int) accum) & ((1 << sinfo->code_size) - 1);
+
+ sinfo->cur_bit += sinfo->code_size;
+ return ret;
+}
+
+
+LOCAL(int)
+LZWReadByte (gif_source_ptr sinfo)
+/* Read an LZW-compressed byte */
+{
+ register int code; /* current working code */
+ int incode; /* saves actual input code */
+
+ /* First time, just eat the expected Clear code(s) and return next code, */
+ /* which is expected to be a raw byte. */
+ if (sinfo->first_time) {
+ sinfo->first_time = FALSE;
+ code = sinfo->clear_code; /* enables sharing code with Clear case */
+ } else {
+
+ /* If any codes are stacked from a previously read symbol, return them */
+ if (sinfo->sp > sinfo->symbol_stack)
+ return (int) *(-- sinfo->sp);
+
+ /* Time to read a new symbol */
+ code = GetCode(sinfo);
+
+ }
+
+ if (code == sinfo->clear_code) {
+ /* Reinit state, swallow any extra Clear codes, and */
+ /* return next code, which is expected to be a raw byte. */
+ ReInitLZW(sinfo);
+ do {
+ code = GetCode(sinfo);
+ } while (code == sinfo->clear_code);
+ if (code > sinfo->clear_code) { /* make sure it is a raw byte */
+ WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
+ code = 0; /* use something valid */
+ }
+ /* make firstcode, oldcode valid! */
+ sinfo->firstcode = sinfo->oldcode = code;
+ return code;
+ }
+
+ if (code == sinfo->end_code) {
+ /* Skip the rest of the image, unless GetCode already read terminator */
+ if (! sinfo->out_of_blocks) {
+ SkipDataBlocks(sinfo);
+ sinfo->out_of_blocks = TRUE;
+ }
+ /* Complain that there's not enough data */
+ WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE);
+ /* Pad data with 0's */
+ return 0; /* fake something usable */
+ }
+
+ /* Got normal raw byte or LZW symbol */
+ incode = code; /* save for a moment */
+
+ if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */
+ /* code == max_code is OK; anything bigger is bad data */
+ if (code > sinfo->max_code) {
+ WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
+ incode = 0; /* prevent creation of loops in symbol table */
+ }
+ /* this symbol will be defined as oldcode/firstcode */
+ *(sinfo->sp++) = (UINT8) sinfo->firstcode;
+ code = sinfo->oldcode;
+ }
+
+ /* If it's a symbol, expand it into the stack */
+ while (code >= sinfo->clear_code) {
+ *(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */
+ code = sinfo->symbol_head[code]; /* head is another LZW symbol */
+ }
+ /* At this point code just represents a raw byte */
+ sinfo->firstcode = code; /* save for possible future use */
+
+ /* If there's room in table, */
+ if ((code = sinfo->max_code) < LZW_TABLE_SIZE) {
+ /* Define a new symbol = prev sym + head of this sym's expansion */
+ sinfo->symbol_head[code] = sinfo->oldcode;
+ sinfo->symbol_tail[code] = (UINT8) sinfo->firstcode;
+ sinfo->max_code++;
+ /* Is it time to increase code_size? */
+ if ((sinfo->max_code >= sinfo->limit_code) &&
+ (sinfo->code_size < MAX_LZW_BITS)) {
+ sinfo->code_size++;
+ sinfo->limit_code <<= 1; /* keep equal to 2^code_size */
+ }
+ }
+
+ sinfo->oldcode = incode; /* save last input symbol for future use */
+ return sinfo->firstcode; /* return first byte of symbol's expansion */
+}
+
+
+LOCAL(void)
+ReadColorMap (gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
+/* Read a GIF colormap */
+{
+ int i;
+
+ for (i = 0; i < cmaplen; i++) {
+#if BITS_IN_JSAMPLE == 8
+#define UPSCALE(x) (x)
+#else
+#define UPSCALE(x) ((x) << (BITS_IN_JSAMPLE-8))
+#endif
+ cmap[CM_RED][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
+ cmap[CM_GREEN][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
+ cmap[CM_BLUE][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
+ }
+}
+
+
+LOCAL(void)
+DoExtension (gif_source_ptr sinfo)
+/* Process an extension block */
+/* Currently we ignore 'em all */
+{
+ int extlabel;
+
+ /* Read extension label byte */
+ extlabel = ReadByte(sinfo);
+ TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel);
+ /* Skip the data block(s) associated with the extension */
+ SkipDataBlocks(sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ gif_source_ptr source = (gif_source_ptr) sinfo;
+ char hdrbuf[10]; /* workspace for reading control blocks */
+ unsigned int width, height; /* image dimensions */
+ int colormaplen, aspectRatio;
+ int c;
+
+ /* Allocate space to store the colormap */
+ source->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) MAXCOLORMAPSIZE, (JDIMENSION) NUMCOLORS);
+
+ /* Read and verify GIF Header */
+ if (! ReadOK(source->pub.input_file, hdrbuf, 6))
+ ERREXIT(cinfo, JERR_GIF_NOT);
+ if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')
+ ERREXIT(cinfo, JERR_GIF_NOT);
+ /* Check for expected version numbers.
+ * If unknown version, give warning and try to process anyway;
+ * this is per recommendation in GIF89a standard.
+ */
+ if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
+ (hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))
+ TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]);
+
+ /* Read and decipher Logical Screen Descriptor */
+ if (! ReadOK(source->pub.input_file, hdrbuf, 7))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ width = LM_to_uint(hdrbuf[0],hdrbuf[1]);
+ height = LM_to_uint(hdrbuf[2],hdrbuf[3]);
+ colormaplen = 2 << (hdrbuf[4] & 0x07);
+ /* we ignore the color resolution, sort flag, and background color index */
+ aspectRatio = hdrbuf[6] & 0xFF;
+ if (aspectRatio != 0 && aspectRatio != 49)
+ TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);
+
+ /* Read global colormap if header indicates it is present */
+ if (BitSet(hdrbuf[4], COLORMAPFLAG))
+ ReadColorMap(source, colormaplen, source->colormap);
+
+ /* Scan until we reach start of desired image.
+ * We don't currently support skipping images, but could add it easily.
+ */
+ for (;;) {
+ c = ReadByte(source);
+
+ if (c == ';') /* GIF terminator?? */
+ ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);
+
+ if (c == '!') { /* Extension */
+ DoExtension(source);
+ continue;
+ }
+
+ if (c != ',') { /* Not an image separator? */
+ WARNMS1(cinfo, JWRN_GIF_CHAR, c);
+ continue;
+ }
+
+ /* Read and decipher Local Image Descriptor */
+ if (! ReadOK(source->pub.input_file, hdrbuf, 9))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ /* we ignore top/left position info, also sort flag */
+ width = LM_to_uint(hdrbuf[4],hdrbuf[5]);
+ height = LM_to_uint(hdrbuf[6],hdrbuf[7]);
+ source->is_interlaced = BitSet(hdrbuf[8], INTERLACE);
+
+ /* Read local colormap if header indicates it is present */
+ /* Note: if we wanted to support skipping images, */
+ /* we'd need to skip rather than read colormap for ignored images */
+ if (BitSet(hdrbuf[8], COLORMAPFLAG)) {
+ colormaplen = 2 << (hdrbuf[8] & 0x07);
+ ReadColorMap(source, colormaplen, source->colormap);
+ }
+
+ source->input_code_size = ReadByte(source); /* get min-code-size byte */
+ if (source->input_code_size < 2 || source->input_code_size >= MAX_LZW_BITS)
+ ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);
+
+ /* Reached desired image, so break out of loop */
+ /* If we wanted to skip this image, */
+ /* we'd call SkipDataBlocks and then continue the loop */
+ break;
+ }
+
+ /* Prepare to read selected image: first initialize LZW decompressor */
+ source->symbol_head = (UINT16 FAR *)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ LZW_TABLE_SIZE * SIZEOF(UINT16));
+ source->symbol_tail = (UINT8 FAR *)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ LZW_TABLE_SIZE * SIZEOF(UINT8));
+ source->symbol_stack = (UINT8 FAR *)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ LZW_TABLE_SIZE * SIZEOF(UINT8));
+ InitLZWCode(source);
+
+ /*
+ * If image is interlaced, we read it into a full-size sample array,
+ * decompressing as we go; then get_interlaced_row selects rows from the
+ * sample array in the proper order.
+ */
+ if (source->is_interlaced) {
+ /* We request the virtual array now, but can't access it until virtual
+ * arrays have been allocated. Hence, the actual work of reading the
+ * image is postponed until the first call to get_pixel_rows.
+ */
+ source->interlaced_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) width, (JDIMENSION) height, (JDIMENSION) 1);
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+ source->pub.get_pixel_rows = load_interlaced_image;
+ } else {
+ source->pub.get_pixel_rows = get_pixel_rows;
+ }
+
+ /* Create compressor input buffer. */
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) width * NUMCOLORS, (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+
+ /* Return info about the image. */
+ cinfo->in_color_space = JCS_RGB;
+ cinfo->input_components = NUMCOLORS;
+ cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+
+ TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen);
+}
+
+
+/*
+ * Read one row of pixels.
+ * This version is used for noninterlaced GIF images:
+ * we read directly from the GIF file.
+ */
+
+METHODDEF(JDIMENSION)
+get_pixel_rows (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ gif_source_ptr source = (gif_source_ptr) sinfo;
+ register int c;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+ register JSAMPARRAY colormap = source->colormap;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ c = LZWReadByte(source);
+ *ptr++ = colormap[CM_RED][c];
+ *ptr++ = colormap[CM_GREEN][c];
+ *ptr++ = colormap[CM_BLUE][c];
+ }
+ return 1;
+}
+
+
+/*
+ * Read one row of pixels.
+ * This version is used for the first call on get_pixel_rows when
+ * reading an interlaced GIF file: we read the whole image into memory.
+ */
+
+METHODDEF(JDIMENSION)
+load_interlaced_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ gif_source_ptr source = (gif_source_ptr) sinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW sptr;
+ register JDIMENSION col;
+ JDIMENSION row;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Read the interlaced image into the virtual array we've created. */
+ for (row = 0; row < cinfo->image_height; row++) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) row;
+ progress->pub.pass_limit = (long) cinfo->image_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->interlaced_image,
+ row, (JDIMENSION) 1, TRUE);
+ sptr = image_ptr[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ *sptr++ = (JSAMPLE) LZWReadByte(source);
+ }
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Replace method pointer so subsequent calls don't come here. */
+ source->pub.get_pixel_rows = get_interlaced_row;
+ /* Initialize for get_interlaced_row, and perform first call on it. */
+ source->cur_row_number = 0;
+ source->pass2_offset = (cinfo->image_height + 7) / 8;
+ source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8;
+ source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4;
+
+ return get_interlaced_row(cinfo, sinfo);
+}
+
+
+/*
+ * Read one row of pixels.
+ * This version is used for interlaced GIF images:
+ * we read from the virtual array.
+ */
+
+METHODDEF(JDIMENSION)
+get_interlaced_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ gif_source_ptr source = (gif_source_ptr) sinfo;
+ JSAMPARRAY image_ptr;
+ register int c;
+ register JSAMPROW sptr, ptr;
+ register JDIMENSION col;
+ register JSAMPARRAY colormap = source->colormap;
+ JDIMENSION irow;
+
+ /* Figure out which row of interlaced image is needed, and access it. */
+ switch ((int) (source->cur_row_number & 7)) {
+ case 0: /* first-pass row */
+ irow = source->cur_row_number >> 3;
+ break;
+ case 4: /* second-pass row */
+ irow = (source->cur_row_number >> 3) + source->pass2_offset;
+ break;
+ case 2: /* third-pass row */
+ case 6:
+ irow = (source->cur_row_number >> 2) + source->pass3_offset;
+ break;
+ default: /* fourth-pass row */
+ irow = (source->cur_row_number >> 1) + source->pass4_offset;
+ break;
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->interlaced_image,
+ irow, (JDIMENSION) 1, FALSE);
+ /* Scan the row, expand colormap, and output */
+ sptr = image_ptr[0];
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ c = GETJSAMPLE(*sptr++);
+ *ptr++ = colormap[CM_RED][c];
+ *ptr++ = colormap[CM_GREEN][c];
+ *ptr++ = colormap[CM_BLUE][c];
+ }
+ source->cur_row_number++; /* for next time */
+ return 1;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for GIF format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_gif (j_compress_ptr cinfo)
+{
+ gif_source_ptr source;
+
+ /* Create module interface object */
+ source = (gif_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(gif_source_struct));
+ source->cinfo = cinfo; /* make back link for subroutines */
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_gif;
+ source->pub.finish_input = finish_input_gif;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* GIF_SUPPORTED */
diff --git a/gs/jpeg/rdjpgcom b/gs/jpeg/rdjpgcom
new file mode 100755
index 000000000..7b5c2ed8e
--- /dev/null
+++ b/gs/jpeg/rdjpgcom
Binary files differ
diff --git a/gs/jpeg/rdjpgcom.1 b/gs/jpeg/rdjpgcom.1
new file mode 100644
index 000000000..0de92bff8
--- /dev/null
+++ b/gs/jpeg/rdjpgcom.1
@@ -0,0 +1,45 @@
+.TH RDJPGCOM 1 "15 June 1995"
+.SH NAME
+rdjpgcom \- display text comments from a JPEG file
+.SH SYNOPSIS
+.B rdjpgcom
+[
+.B \-verbose
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B rdjpgcom
+reads the named JPEG/JFIF file, or the standard input if no file is named,
+and prints any text comments found in the file on the standard output.
+.PP
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+.SH OPTIONS
+.TP
+.B \-verbose
+Causes
+.B rdjpgcom
+to also display the JPEG image dimensions.
+.PP
+Switch names may be abbreviated, and are not case sensitive.
+.SH HINTS
+.B rdjpgcom
+does not depend on the IJG JPEG library. Its source code is intended as an
+illustration of the minimum amount of code required to parse a JPEG file
+header correctly.
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR wrjpgcom (1)
+.SH AUTHOR
+Independent JPEG Group
diff --git a/gs/jpeg/rdjpgcom.c b/gs/jpeg/rdjpgcom.c
new file mode 100644
index 000000000..95770ec74
--- /dev/null
+++ b/gs/jpeg/rdjpgcom.c
@@ -0,0 +1,476 @@
+/*
+ * rdjpgcom.c
+ *
+ * Copyright (C) 1994-1995, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a very simple stand-alone application that displays
+ * the text in COM (comment) markers in a JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ */
+
+#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
+#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
+
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#else
+#define READ_BINARY "rb"
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+
+
+/*
+ * These macros are used to read the input file.
+ * To reuse this code in another application, you might need to change these.
+ */
+
+static FILE * infile; /* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE() getc(infile)
+
+
+/* Error exit handler */
+#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
+
+
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+ int c;
+
+ c = NEXTBYTE();
+ if (c == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ if (c1 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ c2 = NEXTBYTE();
+ if (c2 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF). Here are the marker codes of interest
+ * in this program. (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0 0xC0 /* Start Of Frame N */
+#define M_SOF1 0xC1 /* N indicates which compression process */
+#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
+#define M_EOI 0xD9 /* End Of Image (end of datastream) */
+#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+#define M_COM 0xFE /* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file.
+ * There could also be non-FF garbage between markers. The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+
+static int
+next_marker (void)
+{
+ int c;
+ int discarded_bytes = 0;
+
+ /* Find 0xFF byte; count and skip any non-FFs. */
+ c = read_1_byte();
+ while (c != 0xFF) {
+ discarded_bytes++;
+ c = read_1_byte();
+ }
+ /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
+ * are legal as pad bytes, so don't count them in discarded_bytes.
+ */
+ do {
+ c = read_1_byte();
+ } while (c == 0xFF);
+
+ if (discarded_bytes != 0) {
+ fprintf(stderr, "Warning: garbage data found in JPEG file\n");
+ }
+
+ return c;
+}
+
+
+/*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI. To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+
+static int
+first_marker (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI)
+ ERREXIT("Not a JPEG file");
+ return c2;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ (void) read_1_byte();
+ length--;
+ }
+}
+
+
+/*
+ * Process a COM marker.
+ * We want to print out the marker contents as legible text;
+ * we must guard against random junk and varying newline representations.
+ */
+
+static void
+process_COM (void)
+{
+ unsigned int length;
+ int ch;
+ int lastch = 0;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+
+ while (length > 0) {
+ ch = read_1_byte();
+ /* Emit the character in a readable form.
+ * Nonprintables are converted to \nnn form,
+ * while \ is converted to \\.
+ * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+ */
+ if (ch == '\r') {
+ printf("\n");
+ } else if (ch == '\n') {
+ if (lastch != '\r')
+ printf("\n");
+ } else if (ch == '\\') {
+ printf("\\\\");
+ } else if (isprint(ch)) {
+ putc(ch, stdout);
+ } else {
+ printf("\\%03o", ch);
+ }
+ lastch = ch;
+ length--;
+ }
+ printf("\n");
+}
+
+
+/*
+ * Process a SOFn marker.
+ * This code is only needed if you want to know the image dimensions...
+ */
+
+static void
+process_SOFn (int marker)
+{
+ unsigned int length;
+ unsigned int image_height, image_width;
+ int data_precision, num_components;
+ const char * process;
+ int ci;
+
+ length = read_2_bytes(); /* usual parameter length count */
+
+ data_precision = read_1_byte();
+ image_height = read_2_bytes();
+ image_width = read_2_bytes();
+ num_components = read_1_byte();
+
+ switch (marker) {
+ case M_SOF0: process = "Baseline"; break;
+ case M_SOF1: process = "Extended sequential"; break;
+ case M_SOF2: process = "Progressive"; break;
+ case M_SOF3: process = "Lossless"; break;
+ case M_SOF5: process = "Differential sequential"; break;
+ case M_SOF6: process = "Differential progressive"; break;
+ case M_SOF7: process = "Differential lossless"; break;
+ case M_SOF9: process = "Extended sequential, arithmetic coding"; break;
+ case M_SOF10: process = "Progressive, arithmetic coding"; break;
+ case M_SOF11: process = "Lossless, arithmetic coding"; break;
+ case M_SOF13: process = "Differential sequential, arithmetic coding"; break;
+ case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
+ case M_SOF15: process = "Differential lossless, arithmetic coding"; break;
+ default: process = "Unknown"; break;
+ }
+
+ printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
+ image_width, image_height, num_components, data_precision);
+ printf("JPEG process: %s\n", process);
+
+ if (length != (unsigned int) (8 + num_components * 3))
+ ERREXIT("Bogus SOF marker length");
+
+ for (ci = 0; ci < num_components; ci++) {
+ (void) read_1_byte(); /* Component ID code */
+ (void) read_1_byte(); /* H, V sampling factors */
+ (void) read_1_byte(); /* Quantization table number */
+ }
+}
+
+
+/*
+ * Parse the marker stream until SOS or EOI is seen;
+ * display any COM markers.
+ * While the companion program wrjpgcom will always insert COM markers before
+ * SOFn, other implementations might not, so we scan to SOS before stopping.
+ * If we were only interested in the image dimensions, we would stop at SOFn.
+ * (Conversely, if we only cared about COM markers, there would be no need
+ * for special code to handle SOFn; we could treat it like other markers.)
+ */
+
+static int
+scan_JPEG_header (int verbose)
+{
+ int marker;
+
+ /* Expect SOI at start of file */
+ if (first_marker() != M_SOI)
+ ERREXIT("Expected SOI marker first");
+
+ /* Scan miscellaneous markers until we reach SOS. */
+ for (;;) {
+ marker = next_marker();
+ switch (marker) {
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ case M_SOF2: /* Progressive, Huffman */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_SOF9: /* Extended sequential, arithmetic */
+ case M_SOF10: /* Progressive, arithmetic */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ if (verbose)
+ process_SOFn(marker);
+ else
+ skip_variable();
+ break;
+
+ case M_SOS: /* stop before hitting compressed data */
+ return marker;
+
+ case M_EOI: /* in case it's a tables-only JPEG stream */
+ return marker;
+
+ case M_COM:
+ process_COM();
+ break;
+
+ default: /* Anything else just gets skipped */
+ skip_variable(); /* we assume it has a parameter count... */
+ break;
+ }
+ } /* end loop */
+}
+
+
+/* Command line parsing code */
+
+static const char * progname; /* program name for error messages */
+
+
+static void
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
+
+ fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -verbose Also display dimensions of JPEG image\n");
+
+ exit(EXIT_FAILURE);
+}
+
+
+static int
+keymatch (char * arg, const char * keyword, int minchars)
+/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
+/* keyword is the constant keyword (must be lower case already), */
+/* minchars is length of minimum legal abbreviation. */
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return 0; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return 0; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return 0;
+ return 1; /* A-OK */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ int argn;
+ char * arg;
+ int verbose = 0;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "rdjpgcom"; /* in case C library doesn't provide it */
+
+ /* Parse switches, if any */
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (arg[0] != '-')
+ break; /* not switch, must be file name */
+ arg++; /* advance over '-' */
+ if (keymatch(arg, "verbose", 1)) {
+ verbose++;
+ } else
+ usage();
+ }
+
+ /* Open the input file. */
+ /* Unix style: expect zero or one file name */
+ if (argn < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+ if (argn < argc) {
+ if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdin\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ infile = stdin;
+#endif
+ }
+
+ /* Scan the JPEG headers. */
+ (void) scan_JPEG_header(verbose);
+
+ /* All done. */
+ exit(EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/gs/jpeg/rdppm.c b/gs/jpeg/rdppm.c
new file mode 100644
index 000000000..e1c2a9285
--- /dev/null
+++ b/gs/jpeg/rdppm.c
@@ -0,0 +1,450 @@
+/*
+ * rdppm.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in PPM/PGM format.
+ * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
+ * The PBMPLUS library is NOT required to compile this software
+ * (but it is highly useful as a set of PPM image manipulation programs).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed PPM format).
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef PPM_SUPPORTED
+
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/*
+ * On most systems, reading individual bytes with getc() is drastically less
+ * efficient than buffering a row at a time with fread(). On PCs, we must
+ * allocate the buffer in near data space, because we are assuming small-data
+ * memory model, wherein fread() can't reach far memory. If you need to
+ * process very wide images on a PC, you might have to compile in large-memory
+ * model, or else replace fread() with a getc() loop --- which will be much
+ * slower.
+ */
+
+
+/* Private version of data source object */
+
+typedef struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ U_CHAR *iobuffer; /* non-FAR pointer to I/O buffer */
+ JSAMPROW pixrow; /* FAR pointer to same */
+ size_t buffer_width; /* width of I/O buffer */
+ JSAMPLE *rescale; /* => maxval-remapping array, or NULL */
+} ppm_source_struct;
+
+typedef ppm_source_struct * ppm_source_ptr;
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(infile);
+ if (ch == '#') {
+ do {
+ ch = getc(infile);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+ register int ch;
+ register unsigned int val;
+
+ /* Skip any leading whitespace */
+ do {
+ ch = pbm_getc(infile);
+ if (ch == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+ if (ch < '0' || ch > '9')
+ ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
+
+ val = ch - '0';
+ while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+ val *= 10;
+ val += ch - '0';
+ }
+ return val;
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ * In all cases, input is scaled to the size of JSAMPLE.
+ *
+ * A really fast path is provided for reading byte/sample raw files with
+ * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE * infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE * infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
+ * In this case we just read right into the JSAMPLE buffer!
+ * Note that same code works for PPM and PGM files.
+ */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register int temp;
+ temp = UCH(*bufferptr++);
+ temp |= UCH(*bufferptr++) << 8;
+ *ptr++ = rescale[temp];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register int temp;
+ temp = UCH(*bufferptr++);
+ temp |= UCH(*bufferptr++) << 8;
+ *ptr++ = rescale[temp];
+ temp = UCH(*bufferptr++);
+ temp |= UCH(*bufferptr++) << 8;
+ *ptr++ = rescale[temp];
+ temp = UCH(*bufferptr++);
+ temp |= UCH(*bufferptr++) << 8;
+ *ptr++ = rescale[temp];
+ }
+ return 1;
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ int c;
+ unsigned int w, h, maxval;
+ boolean need_iobuffer, use_raw_buffer, need_rescale;
+
+ if (getc(source->pub.input_file) != 'P')
+ ERREXIT(cinfo, JERR_PPM_NOT);
+
+ c = getc(source->pub.input_file); /* save format discriminator for a sec */
+
+ /* fetch the remaining header info */
+ w = read_pbm_integer(cinfo, source->pub.input_file);
+ h = read_pbm_integer(cinfo, source->pub.input_file);
+ maxval = read_pbm_integer(cinfo, source->pub.input_file);
+
+ if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+ ERREXIT(cinfo, JERR_PPM_NOT);
+
+ cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
+ cinfo->image_width = (JDIMENSION) w;
+ cinfo->image_height = (JDIMENSION) h;
+
+ /* initialize flags to most common settings */
+ need_iobuffer = TRUE; /* do we need an I/O buffer? */
+ use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */
+ need_rescale = TRUE; /* do we need a rescale array? */
+
+ switch (c) {
+ case '2': /* it's a text-format PGM file */
+ cinfo->input_components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
+ source->pub.get_pixel_rows = get_text_gray_row;
+ need_iobuffer = FALSE;
+ break;
+
+ case '3': /* it's a text-format PPM file */
+ cinfo->input_components = 3;
+ cinfo->in_color_space = JCS_RGB;
+ TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
+ source->pub.get_pixel_rows = get_text_rgb_row;
+ need_iobuffer = FALSE;
+ break;
+
+ case '5': /* it's a raw-format PGM file */
+ cinfo->input_components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
+ if (maxval > 255) {
+ source->pub.get_pixel_rows = get_word_gray_row;
+ } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+ source->pub.get_pixel_rows = get_raw_row;
+ use_raw_buffer = TRUE;
+ need_rescale = FALSE;
+ } else {
+ source->pub.get_pixel_rows = get_scaled_gray_row;
+ }
+ break;
+
+ case '6': /* it's a raw-format PPM file */
+ cinfo->input_components = 3;
+ cinfo->in_color_space = JCS_RGB;
+ TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
+ if (maxval > 255) {
+ source->pub.get_pixel_rows = get_word_rgb_row;
+ } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+ source->pub.get_pixel_rows = get_raw_row;
+ use_raw_buffer = TRUE;
+ need_rescale = FALSE;
+ } else {
+ source->pub.get_pixel_rows = get_scaled_rgb_row;
+ }
+ break;
+
+ default:
+ ERREXIT(cinfo, JERR_PPM_NOT);
+ break;
+ }
+
+ /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
+ if (need_iobuffer) {
+ source->buffer_width = (size_t) w * cinfo->input_components *
+ ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
+ source->iobuffer = (U_CHAR *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ source->buffer_width);
+ }
+
+ /* Create compressor input buffer. */
+ if (use_raw_buffer) {
+ /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
+ /* Synthesize a JSAMPARRAY pointer structure */
+ /* Cast here implies near->far pointer conversion on PCs */
+ source->pixrow = (JSAMPROW) source->iobuffer;
+ source->pub.buffer = & source->pixrow;
+ source->pub.buffer_height = 1;
+ } else {
+ /* Need to translate anyway, so make a separate sample buffer. */
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+ }
+
+ /* Compute the rescaling array if required. */
+ if (need_rescale) {
+ INT32 val, half_maxval;
+
+ /* On 16-bit-int machines we have to be careful of maxval = 65535 */
+ source->rescale = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
+ half_maxval = maxval / 2;
+ for (val = 0; val <= (INT32) maxval; val++) {
+ /* The multiplication here must be done in 32 bits to avoid overflow */
+ source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
+ }
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for PPM format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_ppm (j_compress_ptr cinfo)
+{
+ ppm_source_ptr source;
+
+ /* Create module interface object */
+ source = (ppm_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ppm_source_struct));
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_ppm;
+ source->pub.finish_input = finish_input_ppm;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* PPM_SUPPORTED */
diff --git a/gs/jpeg/rdrle.c b/gs/jpeg/rdrle.c
new file mode 100644
index 000000000..542bc3749
--- /dev/null
+++ b/gs/jpeg/rdrle.c
@@ -0,0 +1,387 @@
+/*
+ * rdrle.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Utah RLE format.
+ * The Utah Raster Toolkit library is required (version 3.1 or later).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed RLE format).
+ *
+ * Based on code contributed by Mike Lijewski,
+ * with updates from Robert Hutchinson.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef RLE_SUPPORTED
+
+/* rle.h is provided by the Utah Raster Toolkit. */
+
+#include <rle.h>
+
+/*
+ * We assume that JSAMPLE has the same representation as rle_pixel,
+ * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * We support the following types of RLE files:
+ *
+ * GRAYSCALE - 8 bits, no colormap
+ * MAPPEDGRAY - 8 bits, 1 channel colomap
+ * PSEUDOCOLOR - 8 bits, 3 channel colormap
+ * TRUECOLOR - 24 bits, 3 channel colormap
+ * DIRECTCOLOR - 24 bits, no colormap
+ *
+ * For now, we ignore any alpha channel in the image.
+ */
+
+typedef enum
+ { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
+
+
+/*
+ * Since RLE stores scanlines bottom-to-top, we have to invert the image
+ * to conform to JPEG's top-to-bottom order. To do this, we read the
+ * incoming image into a virtual array on the first get_pixel_rows call,
+ * then fetch the required row from the virtual array on subsequent calls.
+ */
+
+typedef struct _rle_source_struct * rle_source_ptr;
+
+typedef struct _rle_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ rle_kind visual; /* actual type of input file */
+ jvirt_sarray_ptr image; /* virtual array to hold the image */
+ JDIMENSION row; /* current row # in the virtual array */
+ rle_hdr header; /* Input file information */
+ rle_pixel** rle_row; /* holds a row returned by rle_getrow() */
+
+} rle_source_struct;
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JDIMENSION width, height;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /* Use RLE library routine to get the header info */
+ source->header = *rle_hdr_init(NULL);
+ source->header.rle_file = source->pub.input_file;
+ switch (rle_get_setup(&(source->header))) {
+ case RLE_SUCCESS:
+ /* A-OK */
+ break;
+ case RLE_NOT_RLE:
+ ERREXIT(cinfo, JERR_RLE_NOT);
+ break;
+ case RLE_NO_SPACE:
+ ERREXIT(cinfo, JERR_RLE_MEM);
+ break;
+ case RLE_EMPTY:
+ ERREXIT(cinfo, JERR_RLE_EMPTY);
+ break;
+ case RLE_EOF:
+ ERREXIT(cinfo, JERR_RLE_EOF);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_RLE_BADERROR);
+ break;
+ }
+
+ /* Figure out what we have, set private vars and return values accordingly */
+
+ width = source->header.xmax - source->header.xmin + 1;
+ height = source->header.ymax - source->header.ymin + 1;
+ source->header.xmin = 0; /* realign horizontally */
+ source->header.xmax = width-1;
+
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+ cinfo->data_precision = 8; /* we can only handle 8 bit data */
+
+ if (source->header.ncolors == 1 && source->header.ncmap == 0) {
+ source->visual = GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
+ } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
+ source->visual = MAPPEDGRAY;
+ TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
+ source->visual = PSEUDOCOLOR;
+ TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
+ source->visual = TRUECOLOR;
+ TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
+ source->visual = DIRECTCOLOR;
+ TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
+ } else
+ ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
+
+ if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ cinfo->input_components = 1;
+ } else {
+ cinfo->in_color_space = JCS_RGB;
+ cinfo->input_components = 3;
+ }
+
+ /*
+ * A place to hold each scanline while it's converted.
+ * (GRAYSCALE scanlines don't need converting)
+ */
+ if (source->visual != GRAYSCALE) {
+ source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
+ }
+
+ /* request a virtual array to hold the image */
+ source->image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) (width * source->header.ncolors),
+ (JDIMENSION) height, (JDIMENSION) 1);
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ /* count file input as separate pass */
+ progress->total_extra_passes++;
+ }
+#endif
+
+ source->pub.buffer_height = 1;
+}
+
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+
+ source->row--;
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+ return 1;
+}
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for PSEUDOCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JSAMPROW src_row, dest_row;
+ JDIMENSION col;
+ rle_map *colormap;
+ int val;
+
+ colormap = source->header.cmap;
+ dest_row = source->pub.buffer[0];
+ source->row--;
+ src_row = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+ for (col = cinfo->image_width; col > 0; col--) {
+ val = GETJSAMPLE(*src_row++);
+ *dest_row++ = (JSAMPLE) (colormap[val ] >> 8);
+ *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
+ *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
+ }
+
+ return 1;
+}
+
+
+/*
+ * Load the image into a virtual array. We have to do this because RLE
+ * files start at the lower left while the JPEG standard has them starting
+ * in the upper left. This is called the first time we want to get a row
+ * of input. What we do is load the RLE data into the array and then call
+ * the appropriate routine to read one row from the array. Before returning,
+ * we set source->pub.get_pixel_rows so that subsequent calls go straight to
+ * the appropriate row-reading routine.
+ */
+
+METHODDEF(JDIMENSION)
+load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JDIMENSION row, col;
+ JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;
+ rle_pixel **rle_row;
+ rle_map *colormap;
+ char channel;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ colormap = source->header.cmap;
+ rle_row = source->rle_row;
+
+ /* Read the RLE data into our virtual array.
+ * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
+ * and (b) we are not on a machine where FAR pointers differ from regular.
+ */
+ RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_limit = cinfo->image_height;
+ progress->pub.pass_counter = 0;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+
+ switch (source->visual) {
+
+ case GRAYSCALE:
+ case PSEUDOCOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_getrow(&source->header, rle_row);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ break;
+
+ case MAPPEDGRAY:
+ case TRUECOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ scanline = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_row = source->rle_row;
+ rle_getrow(&source->header, rle_row);
+
+ for (col = 0; col < cinfo->image_width; col++) {
+ for (channel = 0; channel < source->header.ncolors; channel++) {
+ *scanline++ = (JSAMPLE)
+ (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ break;
+
+ case DIRECTCOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ scanline = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_getrow(&source->header, rle_row);
+
+ red_ptr = rle_row[0];
+ green_ptr = rle_row[1];
+ blue_ptr = rle_row[2];
+
+ for (col = cinfo->image_width; col > 0; col--) {
+ *scanline++ = *red_ptr++;
+ *scanline++ = *green_ptr++;
+ *scanline++ = *blue_ptr++;
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+#endif
+
+ /* Set up to call proper row-extraction routine in future */
+ if (source->visual == PSEUDOCOLOR) {
+ source->pub.buffer = source->rle_row;
+ source->pub.get_pixel_rows = get_pseudocolor_row;
+ } else {
+ source->pub.get_pixel_rows = get_rle_row;
+ }
+ source->row = cinfo->image_height;
+
+ /* And fetch the topmost (bottommost) row */
+ return (*source->pub.get_pixel_rows) (cinfo, sinfo);
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for RLE format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_rle (j_compress_ptr cinfo)
+{
+ rle_source_ptr source;
+
+ /* Create module interface object */
+ source = (rle_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(rle_source_struct));
+ /* Fill in method ptrs */
+ source->pub.start_input = start_input_rle;
+ source->pub.finish_input = finish_input_rle;
+ source->pub.get_pixel_rows = load_image;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* RLE_SUPPORTED */
diff --git a/gs/jpeg/rdswitch.c b/gs/jpeg/rdswitch.c
new file mode 100644
index 000000000..4f4bb4f58
--- /dev/null
+++ b/gs/jpeg/rdswitch.c
@@ -0,0 +1,332 @@
+/*
+ * rdswitch.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to process some of cjpeg's more complicated
+ * command-line switches. Switches processed here are:
+ * -qtables file Read quantization tables from text file
+ * -scans file Read scan script from text file
+ * -qslots N[,N,...] Set component quantization table selectors
+ * -sample HxV[,HxV,...] Set component sampling factors
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include <ctype.h> /* to declare isdigit(), isspace() */
+
+
+LOCAL(int)
+text_getc (FILE * file)
+/* Read next char, skipping over any comments (# to end of line) */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(file);
+ if (ch == '#') {
+ do {
+ ch = getc(file);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(boolean)
+read_text_integer (FILE * file, long * result, int * termchar)
+/* Read an unsigned decimal integer from a file, store it in result */
+/* Reads one trailing character after the integer; returns it in termchar */
+{
+ register int ch;
+ register long val;
+
+ /* Skip any leading whitespace, detect EOF */
+ do {
+ ch = text_getc(file);
+ if (ch == EOF) {
+ *termchar = ch;
+ return FALSE;
+ }
+ } while (isspace(ch));
+
+ if (! isdigit(ch)) {
+ *termchar = ch;
+ return FALSE;
+ }
+
+ val = ch - '0';
+ while ((ch = text_getc(file)) != EOF) {
+ if (! isdigit(ch))
+ break;
+ val *= 10;
+ val += ch - '0';
+ }
+ *result = val;
+ *termchar = ch;
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_quant_tables (j_compress_ptr cinfo, char * filename,
+ int scale_factor, boolean force_baseline)
+/* Read a set of quantization tables from the specified file.
+ * The file is plain ASCII text: decimal numbers with whitespace between.
+ * Comments preceded by '#' may be included in the file.
+ * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
+ * The tables are implicitly numbered 0,1,etc.
+ * NOTE: does not affect the qslots mapping, which will default to selecting
+ * table 0 for luminance (or primary) components, 1 for chrominance components.
+ * You must use -qslots if you want a different component->table mapping.
+ */
+{
+ FILE * fp;
+ int tblno, i, termchar;
+ long val;
+ unsigned int table[DCTSIZE2];
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "Can't open table file %s\n", filename);
+ return FALSE;
+ }
+ tblno = 0;
+
+ while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
+ if (tblno >= NUM_QUANT_TBLS) {
+ fprintf(stderr, "Too many tables in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ table[0] = (unsigned int) val;
+ for (i = 1; i < DCTSIZE2; i++) {
+ if (! read_text_integer(fp, &val, &termchar)) {
+ fprintf(stderr, "Invalid table data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ table[i] = (unsigned int) val;
+ }
+ jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline);
+ tblno++;
+ }
+
+ if (termchar != EOF) {
+ fprintf(stderr, "Non-numeric data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+
+ fclose(fp);
+ return TRUE;
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(boolean)
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of read_text_integer that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+ register int ch;
+
+ if (! read_text_integer(file, result, termchar))
+ return FALSE;
+ ch = *termchar;
+ while (ch != EOF && isspace(ch))
+ ch = text_getc(file);
+ if (isdigit(ch)) { /* oops, put it back */
+ if (ungetc(ch, file) == EOF)
+ return FALSE;
+ ch = ' ';
+ } else {
+ /* Any separators other than ';' and ':' are ignored;
+ * this allows user to insert commas, etc, if desired.
+ */
+ if (ch != EOF && ch != ';' && ch != ':')
+ ch = ' ';
+ }
+ *termchar = ch;
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_scan_script (j_compress_ptr cinfo, char * filename)
+/* Read a scan script from the specified text file.
+ * Each entry in the file defines one scan to be emitted.
+ * Entries are separated by semicolons ';'.
+ * An entry contains one to four component indexes,
+ * optionally followed by a colon ':' and four progressive-JPEG parameters.
+ * The component indexes denote which component(s) are to be transmitted
+ * in the current scan. The first component has index 0.
+ * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
+ * The file is free format text: any whitespace may appear between numbers
+ * and the ':' and ';' punctuation marks. Also, other punctuation (such
+ * as commas or dashes) can be placed between numbers if desired.
+ * Comments preceded by '#' may be included in the file.
+ * Note: we do very little validity checking here;
+ * jcmaster.c will validate the script parameters.
+ */
+{
+ FILE * fp;
+ int scanno, ncomps, termchar;
+ long val;
+ jpeg_scan_info * scanptr;
+#define MAX_SCANS 100 /* quite arbitrary limit */
+ jpeg_scan_info scans[MAX_SCANS];
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "Can't open scan definition file %s\n", filename);
+ return FALSE;
+ }
+ scanptr = scans;
+ scanno = 0;
+
+ while (read_scan_integer(fp, &val, &termchar)) {
+ if (scanno >= MAX_SCANS) {
+ fprintf(stderr, "Too many scans defined in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ scanptr->component_index[0] = (int) val;
+ ncomps = 1;
+ while (termchar == ' ') {
+ if (ncomps >= MAX_COMPS_IN_SCAN) {
+ fprintf(stderr, "Too many components in one scan in file %s\n",
+ filename);
+ fclose(fp);
+ return FALSE;
+ }
+ if (! read_scan_integer(fp, &val, &termchar))
+ goto bogus;
+ scanptr->component_index[ncomps] = (int) val;
+ ncomps++;
+ }
+ scanptr->comps_in_scan = ncomps;
+ if (termchar == ':') {
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Ss = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Se = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Ah = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar))
+ goto bogus;
+ scanptr->Al = (int) val;
+ } else {
+ /* set non-progressive parameters */
+ scanptr->Ss = 0;
+ scanptr->Se = DCTSIZE2-1;
+ scanptr->Ah = 0;
+ scanptr->Al = 0;
+ }
+ if (termchar != ';' && termchar != EOF) {
+bogus:
+ fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ scanptr++, scanno++;
+ }
+
+ if (termchar != EOF) {
+ fprintf(stderr, "Non-numeric data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+
+ if (scanno > 0) {
+ /* Stash completed scan list in cinfo structure.
+ * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
+ * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
+ */
+ scanptr = (jpeg_scan_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ scanno * SIZEOF(jpeg_scan_info));
+ MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));
+ cinfo->scan_info = scanptr;
+ cinfo->num_scans = scanno;
+ }
+
+ fclose(fp);
+ return TRUE;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+GLOBAL(boolean)
+set_quant_slots (j_compress_ptr cinfo, char *arg)
+/* Process a quantization-table-selectors parameter string, of the form
+ * N[,N,...]
+ * If there are more components than parameters, the last value is replicated.
+ */
+{
+ int val = 0; /* default table # */
+ int ci;
+ char ch;
+
+ for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+ if (*arg) {
+ ch = ','; /* if not set by sscanf, will be ',' */
+ if (sscanf(arg, "%d%c", &val, &ch) < 1)
+ return FALSE;
+ if (ch != ',') /* syntax check */
+ return FALSE;
+ if (val < 0 || val >= NUM_QUANT_TBLS) {
+ fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
+ NUM_QUANT_TBLS-1);
+ return FALSE;
+ }
+ cinfo->comp_info[ci].quant_tbl_no = val;
+ while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+ ;
+ } else {
+ /* reached end of parameter, set remaining components to last table */
+ cinfo->comp_info[ci].quant_tbl_no = val;
+ }
+ }
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+set_sample_factors (j_compress_ptr cinfo, char *arg)
+/* Process a sample-factors parameter string, of the form
+ * HxV[,HxV,...]
+ * If there are more components than parameters, "1x1" is assumed for the rest.
+ */
+{
+ int ci, val1, val2;
+ char ch1, ch2;
+
+ for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+ if (*arg) {
+ ch2 = ','; /* if not set by sscanf, will be ',' */
+ if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
+ return FALSE;
+ if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
+ return FALSE;
+ if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
+ fprintf(stderr, "JPEG sampling factors must be 1..4\n");
+ return FALSE;
+ }
+ cinfo->comp_info[ci].h_samp_factor = val1;
+ cinfo->comp_info[ci].v_samp_factor = val2;
+ while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+ ;
+ } else {
+ /* reached end of parameter, set remaining components to 1x1 sampling */
+ cinfo->comp_info[ci].h_samp_factor = 1;
+ cinfo->comp_info[ci].v_samp_factor = 1;
+ }
+ }
+ return TRUE;
+}
diff --git a/gs/jpeg/rdtarga.c b/gs/jpeg/rdtarga.c
new file mode 100644
index 000000000..4c2cd2673
--- /dev/null
+++ b/gs/jpeg/rdtarga.c
@@ -0,0 +1,500 @@
+/*
+ * rdtarga.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Targa format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed Targa format).
+ *
+ * Based on code contributed by Lee Daniel Crocker.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef TARGA_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _tga_source_struct * tga_source_ptr;
+
+typedef struct _tga_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ j_compress_ptr cinfo; /* back link saves passing separate parm */
+
+ JSAMPARRAY colormap; /* Targa colormap (converted to my format) */
+
+ jvirt_sarray_ptr whole_image; /* Needed if funny input row order */
+ JDIMENSION current_row; /* Current logical row number to read */
+
+ /* Pointer to routine to extract next Targa pixel from input file */
+ JMETHOD(void, read_pixel, (tga_source_ptr sinfo));
+
+ /* Result of read_pixel is delivered here: */
+ U_CHAR tga_pixel[4];
+
+ int pixel_size; /* Bytes per Targa pixel (1 to 4) */
+
+ /* State info for reading RLE-coded pixels; both counts must be init to 0 */
+ int block_count; /* # of pixels remaining in RLE block */
+ int dup_pixel_count; /* # of times to duplicate previous pixel */
+
+ /* This saves the correct pixel-row-expansion method for preload_image */
+ JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+} tga_source_struct;
+
+
+/* For expanding 5-bit pixel values to 8-bit with best rounding */
+
+static const UINT8 c5to8bits[32] = {
+ 0, 8, 16, 25, 33, 41, 49, 58,
+ 66, 74, 82, 90, 99, 107, 115, 123,
+ 132, 140, 148, 156, 165, 173, 181, 189,
+ 197, 206, 214, 222, 230, 239, 247, 255
+};
+
+
+
+LOCAL(int)
+read_byte (tga_source_ptr sinfo)
+/* Read next byte from Targa file */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int c;
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ return c;
+}
+
+
+LOCAL(void)
+read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a Targa file */
+{
+ int i;
+
+ /* Presently only handles 24-bit BGR format */
+ if (mapentrysize != 24)
+ ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
+
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ }
+}
+
+
+/*
+ * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
+ */
+
+METHODDEF(void)
+read_non_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file; no RLE expansion */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int i;
+
+ for (i = 0; i < sinfo->pixel_size; i++) {
+ sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+ }
+}
+
+
+METHODDEF(void)
+read_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file, expanding RLE data as needed */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int i;
+
+ /* Duplicate previously read pixel? */
+ if (sinfo->dup_pixel_count > 0) {
+ sinfo->dup_pixel_count--;
+ return;
+ }
+
+ /* Time to read RLE block header? */
+ if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
+ i = read_byte(sinfo);
+ if (i & 0x80) { /* Start of duplicate-pixel block? */
+ sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
+ sinfo->block_count = 0; /* then read new block header */
+ } else {
+ sinfo->block_count = i & 0x7F; /* number of pixels after this one */
+ }
+ }
+
+ /* Read next pixel */
+ for (i = 0; i < sinfo->pixel_size; i++) {
+ sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+ }
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit grayscale pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register int t;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+ register JSAMPARRAY colormap = source->colormap;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ t = UCH(source->tga_pixel[0]);
+ *ptr++ = colormap[0][t];
+ *ptr++ = colormap[1][t];
+ *ptr++ = colormap[2][t];
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 16-bit pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register int t;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ t = UCH(source->tga_pixel[0]);
+ t += UCH(source->tga_pixel[1]) << 8;
+ /* We expand 5 bit data to 8 bit sample width.
+ * The format of the 16-bit (LSB first) input word is
+ * xRRRRRGGGGGBBBBB
+ */
+ ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
+ t >>= 5;
+ ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
+ t >>= 5;
+ ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
+ ptr += 3;
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+ }
+ return 1;
+}
+
+/*
+ * Targa also defines a 32-bit pixel format with order B,G,R,A.
+ * We presently ignore the attribute byte, so the code for reading
+ * these pixels is identical to the 24-bit routine above.
+ * This works because the actual pixel length is only known to read_pixel.
+ */
+
+#define get_32bit_row get_24bit_row
+
+
+/*
+ * This method is for re-reading the input data in standard top-down
+ * row order. The entire image has already been read into whole_image
+ * with proper conversion of pixel format, but it's in a funny row order.
+ */
+
+METHODDEF(JDIMENSION)
+get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ JDIMENSION source_row;
+
+ /* Compute row of source that maps to current_row of normal order */
+ /* For now, assume image is bottom-up and not interlaced. */
+ /* NEEDS WORK to support interlaced images! */
+ source_row = cinfo->image_height - source->current_row - 1;
+
+ /* Fetch that row from virtual array */
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source_row, (JDIMENSION) 1, FALSE);
+
+ source->current_row++;
+ return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
+ * get_memory_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ JDIMENSION row;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Read the data into a virtual array in input-file row order. */
+ for (row = 0; row < cinfo->image_height; row++) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) row;
+ progress->pub.pass_limit = (long) cinfo->image_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
+ (*source->get_pixel_rows) (cinfo, sinfo);
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Set up to read from the virtual array in unscrambled order */
+ source->pub.get_pixel_rows = get_memory_row;
+ source->current_row = 0;
+ /* And read the first row */
+ return get_memory_row(cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ U_CHAR targaheader[18];
+ int idlen, cmaptype, subtype, flags, interlace_type, components;
+ unsigned int width, height, maplen;
+ boolean is_bottom_up;
+
+#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \
+ (((unsigned int) UCH(targaheader[offset+1])) << 8))
+
+ if (! ReadOK(source->pub.input_file, targaheader, 18))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+
+ /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
+ if (targaheader[16] == 15)
+ targaheader[16] = 16;
+
+ idlen = UCH(targaheader[0]);
+ cmaptype = UCH(targaheader[1]);
+ subtype = UCH(targaheader[2]);
+ maplen = GET_2B(5);
+ width = GET_2B(12);
+ height = GET_2B(14);
+ source->pixel_size = UCH(targaheader[16]) >> 3;
+ flags = UCH(targaheader[17]); /* Image Descriptor byte */
+
+ is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */
+ interlace_type = flags >> 6; /* bits 6/7 are interlace code */
+
+ if (cmaptype > 1 || /* cmaptype must be 0 or 1 */
+ source->pixel_size < 1 || source->pixel_size > 4 ||
+ (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
+ interlace_type != 0) /* currently don't allow interlaced image */
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+
+ if (subtype > 8) {
+ /* It's an RLE-coded file */
+ source->read_pixel = read_rle_pixel;
+ source->block_count = source->dup_pixel_count = 0;
+ subtype -= 8;
+ } else {
+ /* Non-RLE file */
+ source->read_pixel = read_non_rle_pixel;
+ }
+
+ /* Now should have subtype 1, 2, or 3 */
+ components = 3; /* until proven different */
+ cinfo->in_color_space = JCS_RGB;
+
+ switch (subtype) {
+ case 1: /* Colormapped image */
+ if (source->pixel_size == 1 && cmaptype == 1)
+ source->get_pixel_rows = get_8bit_row;
+ else
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
+ break;
+ case 2: /* RGB image */
+ switch (source->pixel_size) {
+ case 2:
+ source->get_pixel_rows = get_16bit_row;
+ break;
+ case 3:
+ source->get_pixel_rows = get_24bit_row;
+ break;
+ case 4:
+ source->get_pixel_rows = get_32bit_row;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ break;
+ }
+ TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
+ break;
+ case 3: /* Grayscale image */
+ components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ if (source->pixel_size == 1)
+ source->get_pixel_rows = get_8bit_gray_row;
+ else
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ break;
+ }
+
+ if (is_bottom_up) {
+ /* Create a virtual array to buffer the upside-down image. */
+ source->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+ /* source->pub.buffer will point to the virtual array. */
+ source->pub.buffer_height = 1; /* in case anyone looks at it */
+ source->pub.get_pixel_rows = preload_image;
+ } else {
+ /* Don't need a virtual array, but do need a one-row input buffer. */
+ source->whole_image = NULL;
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) width * components, (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+ source->pub.get_pixel_rows = source->get_pixel_rows;
+ }
+
+ while (idlen--) /* Throw away ID field */
+ (void) read_byte(source);
+
+ if (maplen > 0) {
+ if (maplen > 256 || GET_2B(3) != 0)
+ ERREXIT(cinfo, JERR_TGA_BADCMAP);
+ /* Allocate space to store the colormap */
+ source->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
+ /* and read it from the file */
+ read_colormap(source, (int) maplen, UCH(targaheader[7]));
+ } else {
+ if (cmaptype) /* but you promised a cmap! */
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ source->colormap = NULL;
+ }
+
+ cinfo->input_components = components;
+ cinfo->data_precision = 8;
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for Targa format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_targa (j_compress_ptr cinfo)
+{
+ tga_source_ptr source;
+
+ /* Create module interface object */
+ source = (tga_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(tga_source_struct));
+ source->cinfo = cinfo; /* make back link for subroutines */
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_tga;
+ source->pub.finish_input = finish_input_tga;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* TARGA_SUPPORTED */
diff --git a/gs/jpeg/structure.doc b/gs/jpeg/structure.doc
new file mode 100644
index 000000000..51c9def7e
--- /dev/null
+++ b/gs/jpeg/structure.doc
@@ -0,0 +1,948 @@
+IJG JPEG LIBRARY: SYSTEM ARCHITECTURE
+
+Copyright (C) 1991-1995, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file provides an overview of the architecture of the IJG JPEG software;
+that is, the functions of the various modules in the system and the interfaces
+between modules. For more precise details about any data structure or calling
+convention, see the include files and comments in the source code.
+
+We assume that the reader is already somewhat familiar with the JPEG standard.
+The README file includes references for learning about JPEG. The file
+libjpeg.doc describes the library from the viewpoint of an application
+programmer using the library; it's best to read that file before this one.
+Also, the file coderules.doc describes the coding style conventions we use.
+
+In this document, JPEG-specific terminology follows the JPEG standard:
+ A "component" means a color channel, e.g., Red or Luminance.
+ A "sample" is a single component value (i.e., one number in the image data).
+ A "coefficient" is a frequency coefficient (a DCT transform output number).
+ A "block" is an 8x8 group of samples or coefficients.
+ An "MCU" (minimum coded unit) is an interleaved set of blocks of size
+ determined by the sampling factors, or a single block in a
+ noninterleaved scan.
+We do not use the terms "pixel" and "sample" interchangeably. When we say
+pixel, we mean an element of the full-size image, while a sample is an element
+of the downsampled image. Thus the number of samples may vary across
+components while the number of pixels does not. (This terminology is not used
+rigorously throughout the code, but it is used in places where confusion would
+otherwise result.)
+
+
+*** System features ***
+
+The IJG distribution contains two parts:
+ * A subroutine library for JPEG compression and decompression.
+ * cjpeg/djpeg, two sample applications that use the library to transform
+ JFIF JPEG files to and from several other image formats.
+cjpeg/djpeg are of no great intellectual complexity: they merely add a simple
+command-line user interface and I/O routines for several uncompressed image
+formats. This document concentrates on the library itself.
+
+We desire the library to be capable of supporting all JPEG baseline, extended
+sequential, and progressive DCT processes. Hierarchical processes are not
+supported.
+
+The library does not support the lossless (spatial) JPEG process. Lossless
+JPEG shares little or no code with lossy JPEG, and would normally be used
+without the extensive pre- and post-processing provided by this library.
+We feel that lossless JPEG is better handled by a separate library.
+
+Within these limits, any set of compression parameters allowed by the JPEG
+spec should be readable for decompression. (We can be more restrictive about
+what formats we can generate.) Although the system design allows for all
+parameter values, some uncommon settings are not yet implemented and may
+never be; nonintegral sampling ratios are the prime example. Furthermore,
+we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a
+run-time option, because most machines can store 8-bit pixels much more
+compactly than 12-bit.
+
+For legal reasons, JPEG arithmetic coding is not currently supported, but
+extending the library to include it would be straightforward.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format. The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats. (For example, libtiff uses this
+library to implement JPEG compression within the TIFF file format.)
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG. These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression. They include colorspace conversion, downsampling/upsampling,
+and color quantization. This code can be omitted if not needed.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing. The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation. On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical. It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+
+*** Portability issues ***
+
+Portability is an essential requirement for the library. The key portability
+issues that show up at the level of system architecture are:
+
+1. Memory usage. We want the code to be able to run on PC-class machines
+with limited memory. Images should therefore be processed sequentially (in
+strips), to avoid holding the whole image in memory at once. Where a
+full-image buffer is necessary, we should be able to use either virtual memory
+or temporary files.
+
+2. Near/far pointer distinction. To run efficiently on 80x86 machines, the
+code should distinguish "small" objects (kept in near data space) from
+"large" ones (kept in far data space). This is an annoying restriction, but
+fortunately it does not impact code quality for less brain-damaged machines,
+and the source code clutter turns out to be minimal with sufficient use of
+pointer typedefs.
+
+3. Data precision. We assume that "char" is at least 8 bits, "short" and
+"int" at least 16, "long" at least 32. The code will work fine with larger
+data sizes, although memory may be used inefficiently in some cases. However,
+the JPEG compressed datastream must ultimately appear on external storage as a
+sequence of 8-bit bytes if it is to conform to the standard. This may pose a
+problem on machines where char is wider than 8 bits. The library represents
+compressed data as an array of values of typedef JOCTET. If no data type
+exactly 8 bits wide is available, custom data source and data destination
+modules must be written to unpack and pack the chosen JOCTET datatype into
+8-bit external representation.
+
+
+*** System overview ***
+
+The compressor and decompressor are each divided into two main sections:
+the JPEG compressor or decompressor proper, and the preprocessing or
+postprocessing functions. The interface between these two sections is the
+image data that the official JPEG spec regards as its input or output: this
+data is in the colorspace to be used for compression, and it is downsampled
+to the sampling factors to be used. The preprocessing and postprocessing
+steps are responsible for converting a normal image representation to or from
+this form. (Those few applications that want to deal with YCbCr downsampled
+data can skip the preprocessing or postprocessing step.)
+
+Looking more closely, the compressor library contains the following main
+elements:
+
+ Preprocessing:
+ * Color space conversion (e.g., RGB to YCbCr).
+ * Edge expansion and downsampling. Optionally, this step can do simple
+ smoothing --- this is often helpful for low-quality source data.
+ JPEG proper:
+ * MCU assembly, DCT, quantization.
+ * Entropy coding (sequential or progressive, Huffman or arithmetic).
+
+In addition to these modules we need overall control, marker generation,
+and support code (memory management & error handling). There is also a
+module responsible for physically writing the output data --- typically
+this is just an interface to fwrite(), but some applications may need to
+do something else with the data.
+
+The decompressor library contains the following main elements:
+
+ JPEG proper:
+ * Entropy decoding (sequential or progressive, Huffman or arithmetic).
+ * Dequantization, inverse DCT, MCU disassembly.
+ Postprocessing:
+ * Upsampling. Optionally, this step may be able to do more general
+ rescaling of the image.
+ * Color space conversion (e.g., YCbCr to RGB). This step may also
+ provide gamma adjustment [ currently it does not ].
+ * Optional color quantization (e.g., reduction to 256 colors).
+ * Optional color precision reduction (e.g., 24-bit to 15-bit color).
+ [This feature is not currently implemented.]
+
+We also need overall control, marker parsing, and a data source module.
+The support code (memory management & error handling) can be shared with
+the compression half of the library.
+
+There may be several implementations of each of these elements, particularly
+in the decompressor, where a wide range of speed/quality tradeoffs is very
+useful. It must be understood that some of the best speedups involve
+merging adjacent steps in the pipeline. For example, upsampling, color space
+conversion, and color quantization might all be done at once when using a
+low-quality ordered-dither technique. The system architecture is designed to
+allow such merging where appropriate.
+
+
+Note: it is convenient to regard edge expansion (padding to block boundaries)
+as a preprocessing/postprocessing function, even though the JPEG spec includes
+it in compression/decompression. We do this because downsampling/upsampling
+can be simplified a little if they work on padded data: it's not necessary to
+have special cases at the right and bottom edges. Therefore the interface
+buffer is always an integral number of blocks wide and high, and we expect
+compression preprocessing to pad the source data properly. Padding will occur
+only to the next block (8-sample) boundary. In an interleaved-scan situation,
+additional dummy blocks may be used to fill out MCUs, but the MCU assembly and
+disassembly logic will create or discard these blocks internally. (This is
+advantageous for speed reasons, since we avoid DCTing the dummy blocks.
+It also permits a small reduction in file size, because the compressor can
+choose dummy block contents so as to minimize their size in compressed form.
+Finally, it makes the interface buffer specification independent of whether
+the file is actually interleaved or not.) Applications that wish to deal
+directly with the downsampled data must provide similar buffering and padding
+for odd-sized images.
+
+
+*** Poor man's object-oriented programming ***
+
+It should be clear by now that we have a lot of quasi-independent processing
+steps, many of which have several possible behaviors. To avoid cluttering the
+code with lots of switch statements, we use a simple form of object-style
+programming to separate out the different possibilities.
+
+For example, two different color quantization algorithms could be implemented
+as two separate modules that present the same external interface; at runtime,
+the calling code will access the proper module indirectly through an "object".
+
+We can get the limited features we need while staying within portable C.
+The basic tool is a function pointer. An "object" is just a struct
+containing one or more function pointer fields, each of which corresponds to
+a method name in real object-oriented languages. During initialization we
+fill in the function pointers with references to whichever module we have
+determined we need to use in this run. Then invocation of the module is done
+by indirecting through a function pointer; on most machines this is no more
+expensive than a switch statement, which would be the only other way of
+making the required run-time choice. The really significant benefit, of
+course, is keeping the source code clean and well structured.
+
+We can also arrange to have private storage that varies between different
+implementations of the same kind of object. We do this by making all the
+module-specific object structs be separately allocated entities, which will
+be accessed via pointers in the master compression or decompression struct.
+The "public" fields or methods for a given kind of object are specified by
+a commonly known struct. But a module's initialization code can allocate
+a larger struct that contains the common struct as its first member, plus
+additional private fields. With appropriate pointer casting, the module's
+internal functions can access these private fields. (For a simple example,
+see jdatadst.c, which implements the external interface specified by struct
+jpeg_destination_mgr, but adds extra fields.)
+
+(Of course this would all be a lot easier if we were using C++, but we are
+not yet prepared to assume that everyone has a C++ compiler.)
+
+An important benefit of this scheme is that it is easy to provide multiple
+versions of any method, each tuned to a particular case. While a lot of
+precalculation might be done to select an optimal implementation of a method,
+the cost per invocation is constant. For example, the upsampling step might
+have a "generic" method, plus one or more "hardwired" methods for the most
+popular sampling factors; the hardwired methods would be faster because they'd
+use straight-line code instead of for-loops. The cost to determine which
+method to use is paid only once, at startup, and the selection criteria are
+hidden from the callers of the method.
+
+This plan differs a little bit from usual object-oriented structures, in that
+only one instance of each object class will exist during execution. The
+reason for having the class structure is that on different runs we may create
+different instances (choose to execute different modules). You can think of
+the term "method" as denoting the common interface presented by a particular
+set of interchangeable functions, and "object" as denoting a group of related
+methods, or the total shared interface behavior of a group of modules.
+
+
+*** Overall control structure ***
+
+We previously mentioned the need for overall control logic in the compression
+and decompression libraries. In IJG implementations prior to v5, overall
+control was mostly provided by "pipeline control" modules, which proved to be
+large, unwieldy, and hard to understand. To improve the situation, the
+control logic has been subdivided into multiple modules. The control modules
+consist of:
+
+1. Master control for module selection and initialization. This has two
+responsibilities:
+
+ 1A. Startup initialization at the beginning of image processing.
+ The individual processing modules to be used in this run are selected
+ and given initialization calls.
+
+ 1B. Per-pass control. This determines how many passes will be performed
+ and calls each active processing module to configure itself
+ appropriately at the beginning of each pass. End-of-pass processing,
+ where necessary, is also invoked from the master control module.
+
+ Method selection is partially distributed, in that a particular processing
+ module may contain several possible implementations of a particular method,
+ which it will select among when given its initialization call. The master
+ control code need only be concerned with decisions that affect more than
+ one module.
+
+2. Data buffering control. A separate control module exists for each
+ inter-processing-step data buffer. This module is responsible for
+ invoking the processing steps that write or read that data buffer.
+
+Each buffer controller sees the world as follows:
+
+input data => processing step A => buffer => processing step B => output data
+ | | |
+ ------------------ controller ------------------
+
+The controller knows the dataflow requirements of steps A and B: how much data
+they want to accept in one chunk and how much they output in one chunk. Its
+function is to manage its buffer and call A and B at the proper times.
+
+A data buffer control module may itself be viewed as a processing step by a
+higher-level control module; thus the control modules form a binary tree with
+elementary processing steps at the leaves of the tree.
+
+The control modules are objects. A considerable amount of flexibility can
+be had by replacing implementations of a control module. For example:
+* Merging of adjacent steps in the pipeline is done by replacing a control
+ module and its pair of processing-step modules with a single processing-
+ step module. (Hence the possible merges are determined by the tree of
+ control modules.)
+* In some processing modes, a given interstep buffer need only be a "strip"
+ buffer large enough to accommodate the desired data chunk sizes. In other
+ modes, a full-image buffer is needed and several passes are required.
+ The control module determines which kind of buffer is used and manipulates
+ virtual array buffers as needed. One or both processing steps may be
+ unaware of the multi-pass behavior.
+
+In theory, we might be able to make all of the data buffer controllers
+interchangeable and provide just one set of implementations for all. In
+practice, each one contains considerable special-case processing for its
+particular job. The buffer controller concept should be regarded as an
+overall system structuring principle, not as a complete description of the
+task performed by any one controller.
+
+
+*** Compression object structure ***
+
+Here is a sketch of the logical structure of the JPEG compression library:
+
+ |-- Colorspace conversion
+ |-- Preprocessing controller --|
+ | |-- Downsampling
+Main controller --|
+ | |-- Forward DCT, quantize
+ |-- Coefficient controller --|
+ |-- Entropy encoding
+
+This sketch also describes the flow of control (subroutine calls) during
+typical image data processing. Each of the components shown in the diagram is
+an "object" which may have several different implementations available. One
+or more source code files contain the actual implementation(s) of each object.
+
+The objects shown above are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+ holds the preprocessed input data. This controller invokes preprocessing to
+ fill the subsampled-data buffer, and JPEG compression to empty it. There is
+ usually no need for a full-image buffer here; a strip buffer is adequate.
+
+* Preprocessing controller: buffer controller for the downsampling input data
+ buffer, which lies between colorspace conversion and downsampling. Note
+ that a unified conversion/downsampling module would probably replace this
+ controller entirely.
+
+* Colorspace conversion: converts application image data into the desired
+ JPEG color space; also changes the data from pixel-interleaved layout to
+ separate component planes. Processes one pixel row at a time.
+
+* Downsampling: performs reduction of chroma components as required.
+ Optionally may perform pixel-level smoothing as well. Processes a "row
+ group" at a time, where a row group is defined as Vmax pixel rows of each
+ component before downsampling, and Vk sample rows afterwards (remember Vk
+ differs across components). Some downsampling or smoothing algorithms may
+ require context rows above and below the current row group; the
+ preprocessing controller is responsible for supplying these rows via proper
+ buffering. The downsampler is responsible for edge expansion at the right
+ edge (i.e., extending each sample row to a multiple of 8 samples); but the
+ preprocessing controller is responsible for vertical edge expansion (i.e.,
+ duplicating the bottom sample row as needed to make a multiple of 8 rows).
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+ This controller handles MCU assembly, including insertion of dummy DCT
+ blocks when needed at the right or bottom edge. When performing
+ Huffman-code optimization or emitting a multiscan JPEG file, this
+ controller is responsible for buffering the full image. The equivalent of
+ one fully interleaved MCU row of subsampled data is processed per call,
+ even when the JPEG file is noninterleaved.
+
+* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients.
+ Works on one or more DCT blocks at a time. (Note: the coefficients are now
+ emitted in normal array order, which the entropy encoder is expected to
+ convert to zigzag order as necessary. Prior versions of the IJG code did
+ the conversion to zigzag order within the quantization step.)
+
+* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the
+ coded data to the data destination module. Works on one MCU per call.
+ For progressive JPEG, the same DCT blocks are fed to the entropy coder
+ during each pass, and the coder must emit the appropriate subset of
+ coefficients.
+
+In addition to the above objects, the compression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+ and per-pass initialization of the other modules.
+
+* Marker writing: generates JPEG markers (except for RSTn, which is emitted
+ by the entropy encoder when needed).
+
+* Data destination manager: writes the output JPEG datastream to its final
+ destination (e.g., a file). The destination manager supplied with the
+ library knows how to write to a stdio stream; for other behaviors, the
+ surrounding application may provide its own destination manager.
+
+* Memory manager: allocates and releases memory, controls virtual arrays
+ (with backing store management, where required).
+
+* Error handler: performs formatting and output of error and trace messages;
+ determines handling of nonfatal errors. The surrounding application may
+ override some or all of this object's methods to change error handling.
+
+* Progress monitor: supports output of "percent-done" progress reports.
+ This object represents an optional callback to the surrounding application:
+ if wanted, it must be supplied by the application.
+
+The error handler, destination manager, and progress monitor objects are
+defined as separate objects in order to simplify application-specific
+customization of the JPEG library. A surrounding application may override
+individual methods or supply its own all-new implementation of one of these
+objects. The object interfaces for these objects are therefore treated as
+part of the application interface of the library, whereas the other objects
+are internal to the library.
+
+The error handler and memory manager are shared by JPEG compression and
+decompression; the progress monitor, if used, may be shared as well.
+
+
+*** Decompression object structure ***
+
+Here is a sketch of the logical structure of the JPEG decompression library:
+
+ |-- Entropy decoding
+ |-- Coefficient controller --|
+ | |-- Dequantize, Inverse DCT
+Main controller --|
+ | |-- Upsampling
+ |-- Postprocessing controller --| |-- Colorspace conversion
+ |-- Color quantization
+ |-- Color precision reduction
+
+As before, this diagram also represents typical control flow. The objects
+shown are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+ holds the output of JPEG decompression proper. This controller's primary
+ task is to feed the postprocessing procedure. Some upsampling algorithms
+ may require context rows above and below the current row group; when this
+ is true, the main controller is responsible for managing its buffer so as
+ to make context rows available. In the current design, the main buffer is
+ always a strip buffer; a full-image buffer is never required.
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+ This controller handles MCU disassembly, including deletion of any dummy
+ DCT blocks at the right or bottom edge. When reading a multiscan JPEG
+ file, this controller is responsible for buffering the full image.
+ (Buffering DCT coefficients, rather than samples, is necessary to support
+ progressive JPEG.) The equivalent of one fully interleaved MCU row of
+ subsampled data is processed per call, even when the source JPEG file is
+ noninterleaved.
+
+* Entropy decoding: Read coded data from the data source module and perform
+ Huffman or arithmetic entropy decoding. Works on one MCU per call.
+ For progressive JPEG decoding, the coefficient controller supplies the prior
+ coefficients of each MCU (initially all zeroes), which the entropy decoder
+ modifies in each scan.
+
+* Dequantization and inverse DCT: like it says. Note that the coefficients
+ buffered by the coefficient controller have NOT been dequantized; we
+ merge dequantization and inverse DCT into a single step for speed reasons.
+ When scaled-down output is asked for, simplified DCT algorithms may be used
+ that emit only 1x1, 2x2, or 4x4 samples per DCT block, not the full 8x8.
+ Works on one DCT block at a time.
+
+* Postprocessing controller: buffer controller for the color quantization
+ input buffer, when quantization is in use. (Without quantization, this
+ controller just calls the upsampler.) For two-pass quantization, this
+ controller is responsible for buffering the full-image data.
+
+* Upsampling: restores chroma components to full size. (May support more
+ general output rescaling, too. Note that if undersized DCT outputs have
+ been emitted by the DCT module, this module must adjust so that properly
+ sized outputs are created.) Works on one row group at a time. This module
+ also calls the color conversion module, so its top level is effectively a
+ buffer controller for the upsampling->color conversion buffer. However, in
+ all but the highest-quality operating modes, upsampling and color
+ conversion are likely to be merged into a single step.
+
+* Colorspace conversion: convert from JPEG color space to output color space,
+ and change data layout from separate component planes to pixel-interleaved.
+ Works on one pixel row at a time.
+
+* Color quantization: reduce the data to colormapped form, using either an
+ externally specified colormap or an internally generated one. This module
+ is not used for full-color output. Works on one pixel row at a time; may
+ require two passes to generate a color map. Note that the output will
+ always be a single component representing colormap indexes. In the current
+ design, the output values are JSAMPLEs, so an 8-bit compilation cannot
+ quantize to more than 256 colors. This is unlikely to be a problem in
+ practice.
+
+* Color reduction: this module handles color precision reduction, e.g.,
+ generating 15-bit color (5 bits/primary) from JPEG's 24-bit output.
+ Not quite clear yet how this should be handled... should we merge it with
+ colorspace conversion???
+
+Note that some high-speed operating modes might condense the entire
+postprocessing sequence to a single module (upsample, color convert, and
+quantize in one step).
+
+In addition to the above objects, the decompression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+ and per-pass initialization of the other modules. This is subdivided into
+ input and output control: jdinput.c controls only input-side processing,
+ while jdmaster.c handles overall initialization and output-side control.
+
+* Marker reading: decodes JPEG markers (except for RSTn).
+
+* Data source manager: supplies the input JPEG datastream. The source
+ manager supplied with the library knows how to read from a stdio stream;
+ for other behaviors, the surrounding application may provide its own source
+ manager.
+
+* Memory manager: same as for compression library.
+
+* Error handler: same as for compression library.
+
+* Progress monitor: same as for compression library.
+
+As with compression, the data source manager, error handler, and progress
+monitor are candidates for replacement by a surrounding application.
+
+
+*** Decompression input and output separation ***
+
+To support efficient incremental display of progressive JPEG files, the
+decompressor is divided into two sections that can run independently:
+
+1. Data input includes marker parsing, entropy decoding, and input into the
+ coefficient controller's DCT coefficient buffer. Note that this
+ processing is relatively cheap and fast.
+
+2. Data output reads from the DCT coefficient buffer and performs the IDCT
+ and all postprocessing steps.
+
+For a progressive JPEG file, the data input processing is allowed to get
+arbitrarily far ahead of the data output processing. (This occurs only
+if the application calls jpeg_consume_input(); otherwise input and output
+run in lockstep, since the input section is called only when the output
+section needs more data.) In this way the application can avoid making
+extra display passes when data is arriving faster than the display pass
+can run. Furthermore, it is possible to abort an output pass without
+losing anything, since the coefficient buffer is read-only as far as the
+output section is concerned. See libjpeg.doc for more detail.
+
+A full-image coefficient array is only created if the JPEG file has multiple
+scans (or if the application specifies buffered-image mode anyway). When
+reading a single-scan file, the coefficient controller normally creates only
+a one-MCU buffer, so input and output processing must run in lockstep in this
+case. jpeg_consume_input() is effectively a no-op in this situation.
+
+The main impact of dividing the decompressor in this fashion is that we must
+be very careful with shared variables in the cinfo data structure. Each
+variable that can change during the course of decompression must be
+classified as belonging to data input or data output, and each section must
+look only at its own variables. For example, the data output section may not
+depend on any of the variables that describe the current scan in the JPEG
+file, because these may change as the data input section advances into a new
+scan.
+
+The progress monitor is (somewhat arbitrarily) defined to treat input of the
+file as one pass when buffered-image mode is not used, and to ignore data
+input work completely when buffered-image mode is used. Note that the
+library has no reliable way to predict the number of passes when dealing
+with a progressive JPEG file, nor can it predict the number of output passes
+in buffered-image mode. So the work estimate is inherently bogus anyway.
+
+No comparable division is currently made in the compression library, because
+there isn't any real need for it.
+
+
+*** Data formats ***
+
+Arrays of pixel sample values use the following data structure:
+
+ typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE
+ typedef JSAMPLE *JSAMPROW; ptr to a row of samples
+ typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows
+ typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays
+
+The basic element type JSAMPLE will typically be one of unsigned char,
+(signed) char, or short. Short will be used if samples wider than 8 bits are
+to be supported (this is a compile-time option). Otherwise, unsigned char is
+used if possible. If the compiler only supports signed chars, then it is
+necessary to mask off the value when reading. Thus, all reads of JSAMPLE
+values must be coded as "GETJSAMPLE(value)", where the macro will be defined
+as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere.
+
+With these conventions, JSAMPLE values can be assumed to be >= 0. This helps
+simplify correct rounding during downsampling, etc. The JPEG standard's
+specification that sample values run from -128..127 is accommodated by
+subtracting 128 just as the sample value is copied into the source array for
+the DCT step (this will be an array of signed ints). Similarly, during
+decompression the output of the IDCT step will be immediately shifted back to
+0..255. (NB: different values are required when 12-bit samples are in use.
+The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be
+defined as 255 and 128 respectively in an 8-bit implementation, and as 4095
+and 2048 in a 12-bit implementation.)
+
+We use a pointer per row, rather than a two-dimensional JSAMPLE array. This
+choice costs only a small amount of memory and has several benefits:
+* Code using the data structure doesn't need to know the allocated width of
+ the rows. This simplifies edge expansion/compression, since we can work
+ in an array that's wider than the logical picture width.
+* Indexing doesn't require multiplication; this is a performance win on many
+ machines.
+* Arrays with more than 64K total elements can be supported even on machines
+ where malloc() cannot allocate chunks larger than 64K.
+* The rows forming a component array may be allocated at different times
+ without extra copying. This trick allows some speedups in smoothing steps
+ that need access to the previous and next rows.
+
+Note that each color component is stored in a separate array; we don't use the
+traditional layout in which the components of a pixel are stored together.
+This simplifies coding of modules that work on each component independently,
+because they don't need to know how many components there are. Furthermore,
+we can read or write each component to a temporary file independently, which
+is helpful when dealing with noninterleaved JPEG files.
+
+In general, a specific sample value is accessed by code such as
+ GETJSAMPLE(image[colorcomponent][row][col])
+where col is measured from the image left edge, but row is measured from the
+first sample row currently in memory. Either of the first two indexings can
+be precomputed by copying the relevant pointer.
+
+
+Since most image-processing applications prefer to work on images in which
+the components of a pixel are stored together, the data passed to or from the
+surrounding application uses the traditional convention: a single pixel is
+represented by N consecutive JSAMPLE values, and an image row is an array of
+(# of color components)*(image width) JSAMPLEs. One or more rows of data can
+be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is
+converted to component-wise storage inside the JPEG library. (Applications
+that want to skip JPEG preprocessing or postprocessing will have to contend
+with component-wise storage.)
+
+
+Arrays of DCT-coefficient values use the following data structure:
+
+ typedef short JCOEF; a 16-bit signed integer
+ typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients
+ typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks
+ typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows
+ typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays
+
+The underlying type is at least a 16-bit signed integer; while "short" is big
+enough on all machines of interest, on some machines it is preferable to use
+"int" for speed reasons, despite the storage cost. Coefficients are grouped
+into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than
+"8" and "64").
+
+The contents of a coefficient block may be in either "natural" or zigzagged
+order, and may be true values or divided by the quantization coefficients,
+depending on where the block is in the processing pipeline. In the current
+library, coefficient blocks are kept in natural order everywhere; the entropy
+codecs zigzag or dezigzag the data as it is written or read. The blocks
+contain quantized coefficients everywhere outside the DCT/IDCT subsystems.
+(This latter decision may need to be revisited to support variable
+quantization a la JPEG Part 3.)
+
+Notice that the allocation unit is now a row of 8x8 blocks, corresponding to
+eight rows of samples. Otherwise the structure is much the same as for
+samples, and for the same reasons.
+
+On machines where malloc() can't handle a request bigger than 64Kb, this data
+structure limits us to rows of less than 512 JBLOCKs, or a picture width of
+4000+ pixels. This seems an acceptable restriction.
+
+
+On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW)
+must be declared as "far" pointers, but the upper levels can be "near"
+(implying that the pointer lists are allocated in the DS segment).
+We use a #define symbol FAR, which expands to the "far" keyword when
+compiling on 80x86 machines and to nothing elsewhere.
+
+
+*** Suspendable processing ***
+
+In some applications it is desirable to use the JPEG library as an
+incremental, memory-to-memory filter. In this situation the data source or
+destination may be a limited-size buffer, and we can't rely on being able to
+empty or refill the buffer at arbitrary times. Instead the application would
+like to have control return from the library at buffer overflow/underrun, and
+then resume compression or decompression at a later time.
+
+This scenario is supported for simple cases. (For anything more complex, we
+recommend that the application "bite the bullet" and develop real multitasking
+capability.) The libjpeg.doc file goes into more detail about the usage and
+limitations of this capability; here we address the implications for library
+structure.
+
+The essence of the problem is that the entropy codec (coder or decoder) must
+be prepared to stop at arbitrary times. In turn, the controllers that call
+the entropy codec must be able to stop before having produced or consumed all
+the data that they normally would handle in one call. That part is reasonably
+straightforward: we make the controller call interfaces include "progress
+counters" which indicate the number of data chunks successfully processed, and
+we require callers to test the counter rather than just assume all of the data
+was processed.
+
+Rather than trying to restart at an arbitrary point, the current Huffman
+codecs are designed to restart at the beginning of the current MCU after a
+suspension due to buffer overflow/underrun. At the start of each call, the
+codec's internal state is loaded from permanent storage (in the JPEG object
+structures) into local variables. On successful completion of the MCU, the
+permanent state is updated. (This copying is not very expensive, and may even
+lead to *improved* performance if the local variables can be registerized.)
+If a suspension occurs, the codec simply returns without updating the state,
+thus effectively reverting to the start of the MCU. Note that this implies
+leaving some data unprocessed in the source/destination buffer (ie, the
+compressed partial MCU). The data source/destination module interfaces are
+specified so as to make this possible. This also implies that the data buffer
+must be large enough to hold a worst-case compressed MCU; a couple thousand
+bytes should be enough.
+
+In a successive-approximation AC refinement scan, the progressive Huffman
+decoder has to be able to undo assignments of newly nonzero coefficients if it
+suspends before the MCU is complete, since decoding requires distinguishing
+previously-zero and previously-nonzero coefficients. This is a bit tedious
+but probably won't have much effect on performance. Other variants of Huffman
+decoding need not worry about this, since they will just store the same values
+again if forced to repeat the MCU.
+
+This approach would probably not work for an arithmetic codec, since its
+modifiable state is quite large and couldn't be copied cheaply. Instead it
+would have to suspend and resume exactly at the point of the buffer end.
+
+The JPEG marker reader is designed to cope with suspension at an arbitrary
+point. It does so by backing up to the start of the marker parameter segment,
+so the data buffer must be big enough to hold the largest marker of interest.
+Again, a couple KB should be adequate. (A special "skip" convention is used
+to bypass COM and APPn markers, so these can be larger than the buffer size
+without causing problems; otherwise a 64K buffer would be needed in the worst
+case.)
+
+The JPEG marker writer currently does *not* cope with suspension. I feel that
+this is not necessary; it is much easier simply to require the application to
+ensure there is enough buffer space before starting. (An empty 2K buffer is
+more than sufficient for the header markers; and ensuring there are a dozen or
+two bytes available before calling jpeg_finish_compress() will suffice for the
+trailer.) This would not work for writing multi-scan JPEG files, but
+we simply do not intend to support that capability with suspension.
+
+
+*** Memory manager services ***
+
+The JPEG library's memory manager controls allocation and deallocation of
+memory, and it manages large "virtual" data arrays on machines where the
+operating system does not provide virtual memory. Note that the same
+memory manager serves both compression and decompression operations.
+
+In all cases, allocated objects are tied to a particular compression or
+decompression master record, and they will be released when that master
+record is destroyed.
+
+The memory manager does not provide explicit deallocation of objects.
+Instead, objects are created in "pools" of free storage, and a whole pool
+can be freed at once. This approach helps prevent storage-leak bugs, and
+it speeds up operations whenever malloc/free are slow (as they often are).
+The pools can be regarded as lifetime identifiers for objects. Two
+pools/lifetimes are defined:
+ * JPOOL_PERMANENT lasts until master record is destroyed
+ * JPOOL_IMAGE lasts until done with image (JPEG datastream)
+Permanent lifetime is used for parameters and tables that should be carried
+across from one datastream to another; this includes all application-visible
+parameters. Image lifetime is used for everything else. (A third lifetime,
+JPOOL_PASS = one processing pass, was originally planned. However it was
+dropped as not being worthwhile. The actual usage patterns are such that the
+peak memory usage would be about the same anyway; and having per-pass storage
+substantially complicates the virtual memory allocation rules --- see below.)
+
+The memory manager deals with three kinds of object:
+1. "Small" objects. Typically these require no more than 10K-20K total.
+2. "Large" objects. These may require tens to hundreds of K depending on
+ image size. Semantically they behave the same as small objects, but we
+ distinguish them for two reasons:
+ * On MS-DOS machines, large objects are referenced by FAR pointers,
+ small objects by NEAR pointers.
+ * Pool allocation heuristics may differ for large and small objects.
+ Note that individual "large" objects cannot exceed the size allowed by
+ type size_t, which may be 64K or less on some machines.
+3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs
+ (typically large enough for the entire image being processed). The
+ memory manager provides stripwise access to these arrays. On machines
+ without virtual memory, the rest of the array may be swapped out to a
+ temporary file.
+
+(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large
+objects for the data proper and small objects for the row pointers. For
+convenience and speed, the memory manager provides single routines to create
+these structures. Similarly, virtual arrays include a small control block
+and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.)
+
+In the present implementation, virtual arrays are only permitted to have image
+lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is
+not very useful since a virtual array's raison d'etre is to store data for
+multiple passes through the image.) We also expect that only "small" objects
+will be given permanent lifespan, though this restriction is not required by
+the memory manager.
+
+In a non-virtual-memory machine, some performance benefit can be gained by
+making the in-memory buffers for virtual arrays be as large as possible.
+(For small images, the buffers might fit entirely in memory, so blind
+swapping would be very wasteful.) The memory manager will adjust the height
+of the buffers to fit within a prespecified maximum memory usage. In order
+to do this in a reasonably optimal fashion, the manager needs to allocate all
+of the virtual arrays at once. Therefore, there isn't a one-step allocation
+routine for virtual arrays; instead, there is a "request" routine that simply
+allocates the control block, and a "realize" routine (called just once) that
+determines space allocation and creates all of the actual buffers. The
+realize routine must allow for space occupied by non-virtual large objects.
+(We don't bother to factor in the space needed for small objects, on the
+grounds that it isn't worth the trouble.)
+
+To support all this, we establish the following protocol for doing business
+with the memory manager:
+ 1. Modules must request virtual arrays (which may have only image lifespan)
+ during the initial setup phase, i.e., in their jinit_xxx routines.
+ 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be
+ allocated during initial setup.
+ 3. realize_virt_arrays will be called at the completion of initial setup.
+ The above conventions ensure that sufficient information is available
+ for it to choose a good size for virtual array buffers.
+Small objects of any lifespan may be allocated at any time. We expect that
+the total space used for small objects will be small enough to be negligible
+in the realize_virt_arrays computation.
+
+In a virtual-memory machine, we simply pretend that the available space is
+infinite, thus causing realize_virt_arrays to decide that it can allocate all
+the virtual arrays as full-size in-memory buffers. The overhead of the
+virtual-array access protocol is very small when no swapping occurs.
+
+A virtual array can be specified to be "pre-zeroed"; when this flag is set,
+never-yet-written sections of the array are set to zero before being made
+available to the caller. If this flag is not set, never-written sections
+of the array contain garbage. (This feature exists primarily because the
+equivalent logic would otherwise be needed in jdcoefct.c for progressive
+JPEG mode; we may as well make it available for possible other uses.)
+
+The first write pass on a virtual array is required to occur in top-to-bottom
+order; read passes, as well as any write passes after the first one, may
+access the array in any order. This restriction exists partly to simplify
+the virtual array control logic, and partly because some file systems may not
+support seeking beyond the current end-of-file in a temporary file. The main
+implication of this restriction is that rearrangement of rows (such as
+converting top-to-bottom data order to bottom-to-top) must be handled while
+reading data out of the virtual array, not while putting it in.
+
+
+*** Memory manager internal structure ***
+
+To isolate system dependencies as much as possible, we have broken the
+memory manager into two parts. There is a reasonably system-independent
+"front end" (jmemmgr.c) and a "back end" that contains only the code
+likely to change across systems. All of the memory management methods
+outlined above are implemented by the front end. The back end provides
+the following routines for use by the front end (none of these routines
+are known to the rest of the JPEG code):
+
+jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown
+
+jpeg_get_small, jpeg_free_small interface to malloc and free library routines
+ (or their equivalents)
+
+jpeg_get_large, jpeg_free_large interface to FAR malloc/free in MSDOS machines;
+ else usually the same as
+ jpeg_get_small/jpeg_free_small
+
+jpeg_mem_available estimate available memory
+
+jpeg_open_backing_store create a backing-store object
+
+read_backing_store, manipulate a backing-store object
+write_backing_store,
+close_backing_store
+
+On some systems there will be more than one type of backing-store object
+(specifically, in MS-DOS a backing store file might be an area of extended
+memory as well as a disk file). jpeg_open_backing_store is responsible for
+choosing how to implement a given object. The read/write/close routines
+are method pointers in the structure that describes a given object; this
+lets them be different for different object types.
+
+It may be necessary to ensure that backing store objects are explicitly
+released upon abnormal program termination. For example, MS-DOS won't free
+extended memory by itself. To support this, we will expect the main program
+or surrounding application to arrange to call self_destruct (typically via
+jpeg_destroy) upon abnormal termination. This may require a SIGINT signal
+handler or equivalent. We don't want to have the back end module install its
+own signal handler, because that would pre-empt the surrounding application's
+ability to control signal handling.
+
+The IJG distribution includes several memory manager back end implementations.
+Usually the same back end should be suitable for all applications on a given
+system, but it is possible for an application to supply its own back end at
+need.
+
+
+*** Implications of DNL marker ***
+
+Some JPEG files may use a DNL marker to postpone definition of the image
+height (this would be useful for a fax-like scanner's output, for instance).
+In these files the SOF marker claims the image height is 0, and you only
+find out the true image height at the end of the first scan.
+
+We could read these files as follows:
+1. Upon seeing zero image height, replace it by 65535 (the maximum allowed).
+2. When the DNL is found, update the image height in the global image
+ descriptor.
+This implies that control modules must avoid making copies of the image
+height, and must re-test for termination after each MCU row. This would
+be easy enough to do.
+
+In cases where image-size data structures are allocated, this approach will
+result in very inefficient use of virtual memory or much-larger-than-necessary
+temporary files. This seems acceptable for something that probably won't be a
+mainstream usage. People might have to forgo use of memory-hogging options
+(such as two-pass color quantization or noninterleaved JPEG files) if they
+want efficient conversion of such files. (One could improve efficiency by
+demanding a user-supplied upper bound for the height, less than 65536; in most
+cases it could be much less.)
+
+The standard also permits the SOF marker to overestimate the image height,
+with a DNL to give the true, smaller height at the end of the first scan.
+This would solve the space problems if the overestimate wasn't too great.
+However, it implies that you don't even know whether DNL will be used.
+
+This leads to a couple of very serious objections:
+1. Testing for a DNL marker must occur in the inner loop of the decompressor's
+ Huffman decoder; this implies a speed penalty whether the feature is used
+ or not.
+2. There is no way to hide the last-minute change in image height from an
+ application using the decoder. Thus *every* application using the IJG
+ library would suffer a complexity penalty whether it cared about DNL or
+ not.
+We currently do not support DNL because of these problems.
+
+A different approach is to insist that DNL-using files be preprocessed by a
+separate program that reads ahead to the DNL, then goes back and fixes the SOF
+marker. This is a much simpler solution and is probably far more efficient.
+Even if one wants piped input, buffering the first scan of the JPEG file needs
+a lot smaller temp file than is implied by the maximum-height method. For
+this approach we'd simply treat DNL as a no-op in the decompressor (at most,
+check that it matches the SOF image height).
+
+We will not worry about making the compressor capable of outputting DNL.
+Something similar to the first scheme above could be applied if anyone ever
+wants to make that work.
diff --git a/gs/jpeg/testimg.gif b/gs/jpeg/testimg.gif
new file mode 100644
index 000000000..ca4036187
--- /dev/null
+++ b/gs/jpeg/testimg.gif
Binary files differ
diff --git a/gs/jpeg/testimg.jpg b/gs/jpeg/testimg.jpg
new file mode 100644
index 000000000..b34ca5d31
--- /dev/null
+++ b/gs/jpeg/testimg.jpg
Binary files differ
diff --git a/gs/jpeg/testimg.ppm b/gs/jpeg/testimg.ppm
new file mode 100644
index 000000000..9d81ce24a
--- /dev/null
+++ b/gs/jpeg/testimg.ppm
@@ -0,0 +1,4 @@
+P6
+227 149
+255
+0/-0/-10.21/51.51.62/62/83/83/:3-:3-:3-:3-:3-:3-:2/91.91.80-80-91.91.:2/80-80-80-80-80-80-80-80-6.+6.+6.+5-*5-*4,)4,)4,)4,)4,)4,)4,)4,)4,)4,)2-)/*$/,%/,%0-&1.'2/(30)30)63,63,74-85.85.96/:70:7.A:0B<0D>2F@4IA4JB5KC6KC6MD5MD5OC3NB2OC3OC3PD4RE5R?1Y?2b@4nB5}E6‹H8™G9£F7¯G:¸G9¾E:ÅG;ÇG>ÊG?ËH@ÐE@çFLíCLëDKëEIîCIïBDñ>Bô=Aø;A÷:@ô:?ð<?é?@â@>×?<ËA7»=/µ@.µ@.´?-´?-³@-²?-¯@-­@,ªA,¦A-¢B,Ÿ@*›A)˜@*–A,”>-’?/’?/‘>.‘>,=+’<+’<+”?+”?+”=*”=*”=*•>+–?,–@/–?6•>5—=2Ÿ?1©B3³D3¼D4¿D4¹?0µA2¬F8žH;‡H9oA2T8*C3&=5295495473271160050-50-72/72/72/61.61-50,50,41,//-.0-//-//-0/-0/-2.-2.-5,-4+,4*+3)*7(+=.1E69P:<jBC|IHMM•OOŸW[ªdnªoƒŸt”{£‡®€†º~ˆ½sy­`a‘TKvPDhSJgOG^MH^TQbfdo|}‚‘™ž˜£©Ÿ¢¨šž “’{|lfgUXWEQNEUR[UQbUQb0/-0/-10.10.40-51.62/62/83/83/:3-:3-:3-:3-:3-:3-91.91.80-80-80-80-91.91.80-80-80-80-80-80-80-80-6.+6.+5-*5-*5-*4,)4,)4,)5-*5-*5-*5-*5-*5-*5-*3.*0+%0-&0-&1.'2/(30)41*41*63,63,74-74-85.96/:70:7.@9/A;/C=1E?3H@3IA4JB5JB5LC4LC4MA1MA1MA1NB2OC3QD4P>0U?1^A3jC4xD6„E4’E5œC3§C4¯A4µA4¼B7ÀD:ÄE<ÅF=ÍC@áEIçBIèCIêDHíDGïBDó@Cö?Cø;A÷:@ô:?ð<?é?@àA>Õ@<Ê@6¹>/µ@.´?-´?-´?-²?,°?-¯@-­@,©@+¦A-¡A+Ÿ@*›A)˜@*–A,”>-’?/‘>.‘>.‘>,=+’<+’<+”?+“>*”=*”=*”=*•>+–?,–@/”@5•>5˜>3 >1«A3µD4½C4¿D5»A2·C6¬F8œI;…G:l@3S9*B4)>63:6595484382271161.61.72/72/72/61.61-50,50,41,//-.0-//-//-0/-0/-2.-2.-3--5,-4*+3)*5)+<-0C47N8:d>=vEA†JINLšTV¤aj¥l}rŽ‘{¢†€®…¹{„»ou©[[QHuOCiOFeOG_PH_RN_[Yfnotƒ‡ˆ”™•™ž—š ”™‘ƒ~ojkY][LVSJXSZVRaXQa/.,/.,0/-10.40-40-51.51.72.72.72.72.92,92,92,92,91.80.7/-7/-7/-7/-80.91/80.80.80.80.80.80.80.80.6.,5-+5-+5-+4,*4,*4,*4,*5-+5-+5-+5-+5-+5-+5-+3.*2-'1.'2/(30)30)41*41*52+63,63,63,74-85.96/96/:7.?8.@:.B<0D>2G?4H@5H@3H@3I@1I@1K?1K?1K?/L@0MA1NB2MA1QA1YB2dC2qC3|C2‡B2’A0˜<- :+§;.¯=2µ@6ºD:¿F=ÅD>ÙCEá@FãBGçBFêDFðCEôADø?Dú;@ù:?õ;@ð=@è@@ÜA=Ñ@;Æ@5·=.³@-³@-²?,²?-°?-¯>,­@,ª?-§@-¥@,¡A+A,š?*˜@*•@+”>-‘>.‘>.‘>.=+=+=+=+‘>,‘>,’<+’<+“=,“=,”?+•?.•A6–?5š>3£>2¯A4¹C5¿D5ÁC5ÀD8¸F;®I=™J=G;h@4Q:,B5,?74=77<66:4494183072/72/62/62/62/51.52-41,41,21,.0-,1-.0-.0-//-//-0/-2.-5//4..5,-4*+4*+9-/>24I56[97l?9|E@†IDOM˜[`›fv”mˆŒwžƒ}­}‚¹u~·fm¤TV‰MEvLAkMAeOFcQHcMH^NK\[[eqty…‰ˆ‡Œ†Šˆ…†Š|xzlfiXZ[MVSLZU[ZT`[S`.-+/.,/.,0/-3/,40-40-40-61-61-61-61-81+81+81+81+7/-7/-6.,6.,6.,6.,7/-7/-80.80.80.80.80.80.80.80.5-+5-+5-+4,*4,*4,*3+)3+)6.,6.,6.,6.,6.,6.,6.,4/,30+30)30)41*41*52+52+52+52+52+63,74-85.85.96/96->7-?9-@:.B<0E=2E=2F>1F>1G=1G>/H<.I=/I=/J>.L@0JA0KD2NE4UD4^D3iD2sB1~A/†?-Œ9)”9'9*£<-¬@3³E8¸H<ÁF>ÒDCÚACÞBCâDCçCDìBCó@C÷?Aú;@ù:?õ;@î>@åA@ÚB=Í@9Â@3µ=-°@,°@,°@,¯>,®?,®?,¬?+©@-¦?,£@+ @*œ@+˜@*–@)”?*‘>,‘>.‘>.=-=+=+<*<*=+=+<*<*’<+‘>,”>-’?-•A6–?5œ>2¦@4²B6¼C8ÁC7ÂB7ÂF<ºJ?¬L@—K>|F:b@4L:.A7-@85>96=77<74:5294183083062/62/62/32.52-21,21,12--2.-2./1./1.00.00.10.10.5106005//5,-4+,6,-:01D22T71c;3qA7{E;‚HD‰RU_l‹i‚ƒs˜}y«x}µowµ`f¢QR‹LEyL@pL@hPEgQFfLC^GBVMLZ^^fjnquyxx}wz€vwzokoa`bTWYLTTL]WY]V]]V^------.-+/.,0/-10.3/,40-3/,3/,4/+4/+4/+4/+6/)6/)4/,4/,3.+3.+3.+3.+4/,4/,50-50-50-50-50-50-50-50-3.+3.+2-*2-*2-*1,)1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,41,41,41,41,41,52-52-52-52-52-63.63.74/85096196/<5-=6,?8.@9/B:/C;0C;0C;.D:.D:.F:.G;-H<.I=/J>0I@1JG6MH5RG5YF5bE3jD1uB/}>,‚;)‹:)“:*š=,£B2¬F8²J=»I?ÌGBÔDCØDBÝEBâBBéAAð=@ô<>ù:?ø:<ô<>í?>áB>ÓC:ÅA5¹?0²?-®?,®?,®?,­>-¬>-¬>-ª?-¨>.¤?- ?,ž?+š?,—?+•>*“>*‘>,?.>->->-Ž=,Ž=,Ž=,Ž=,Ž=,Ž=,Ž=,<,>-‘>.?.”B4—A4@1¨@3¶A7¿C9ÅB8ÄA7¾C;·H?¦LCJ@tE;Z>2E9-<5+@93@85?75>63=52<4194083/62/43/43/23.32.12-12-02--2.,2.-2.-2./1./1.00.10.3205105104..2,,4+,7./=/.N5.Y9.e=1n@3sB;yKK€Zeƒg€p—zxªu{·ks´_d¦TT”OGƒLBwNAmNBhMAeJA`GBYGFXKKWMPU]cc`fbbia`f\Z`TW[MUXMXXP^YV`WX`WZ,,,,,,.-+.-+/.,0/-3/,3/,2.+2.+3.*3.*3.*3.*5.(5-*3.+3.+2-*1,)1,)2-*3.+3.+3.+3.+3.+3.+3.+3.+3.+3.+2-*2-*2-*2-*1,)1,)1,)0+(3.+3.+3.+3.+3.+3.+3.+3.+41,41,41,41,41,41,41,41,41,52-52-63.74/85085085.;4,<5+=6,>7-@7.A9.A9.A9.C9/C9-E9-F:.G;/H<.J>0HA1JG6IH6NG5VF6\E3dC2n@0v>-{<+‚;)Œ;*”=,œ@1£F5ªJ:´J=ÄH@ÌEAÑFAÖE@ÞCAä@>ì>?ñ:<÷;<ô:;ð<=é@=ÜC=ÍC8¾@2±>,®?,«@,ª?+ª?+ª?-©>,©>,¨?,¥>-¢?, ?,›>,—?+•>*“>)‘?*>+>->->-Ž=,Ž=,Ž=,<+Ž=,‹<+<+‹<+‹<-Œ=,>/Ž?.”B4—A2 @2¬B5¹C9ÂC:ÅB:ÂA;ºA9±I@£NGNEoG=S?4A;/96-@93A75?74>63<4194083/74/43/43/34/23.23.02-02-.3--3/-3/.3/.3/02/02/11/11/21/32032040/2.-1-,4..8.,G4-O4)X8+`<0e?6mGFyYd‚k…€uŸ||²w|¼nu»dh¯[[¡RMLB~OArL@hI=cH>`HB^ECX@BO;@FBGJDMJJQJJQIIQFKQEOUIVWO^YS`YS`XU++++++,,,---/.,/.,0/-0/-1-*1-*1-*1-*2-)2-)2-)2-)2-*2,,1++1++1++1++2,,2,,1++1++1++1++1++1++1++1++2,,2,,2,,1++1++1++0**0**3--3--3--3--3--3--3--3.+41,41,41,30+30+30+30+30+41,41,52-63.74/74/85085.:3+;4,<5-=6.?6/?6-?6-?7,B8.B8.E8/E9-G;/H<0J>2H@3HE6GF4KE5QD4XC2_B2f?.n=,v=,|:*…9)Œ;*“=.›B2¢F7¬F8»F<ÂF>ÉF>ÐE>ÙD@âC?ê@@ð>>ò::ñ;:ì<<äA<ÖC;ÆD6µ@/ª=)ª?-©@-©@-¨?,¨>.¨>.§=-¥>-£=. ?.ž?-š?-–?,“>*‘?*>)>+>->-Œ=,Œ=.Œ=.‹<-‹<-‹<-Š=-Š;,‰<,Š</‹>.‹=0Œ?/’C2˜B1¡A1®B6¼C:ÂC<ÄC=ÀC=¹FA²QJ¥XRXQsRIWI>CC7<?6>93@72>71=60:5/94.83/63.43.43.34/13.13..3-.3-.3--3/-3/-3/-3/.3/.3/02/02/00.11/22021/0/-/.,2.-4/,?0+D0)K3)T8-Z<4dFFu]jƒs‰€«…„¾~ƒÇtzÆmp½ce¯VSšLC‚K?qI<gG;cE>_FB]DBW?AN;?H:BE>HGDMHGQIGQHJRGNVKUXM^ZOaYNaXO++++++,,,,,,.,-/.,0/-0/-1-*1-*1-*1-*2-)2-)2-)2-*2,,1++1++0**0**1++1++2,,0**0**0**0**0**0**0**0**2,,2,,2,,1++1++0**0**0**2,,2,,2,,2,,2,,2,,2,,2,,3/,30+30+30+30+30+30+30+41,41,52-63.63.74/85085092,:3+;4,<5->5.>5.>5.>5,B8/B8.E8/E8/G:1I=1J>2I?3FC4FC4JB5OA4TA2\@2b>0j<-q<.w9*}8)…8(Œ:,•=/›B4¤B5²F:ºE;ÁF>ÊG?ÔG@ÞFAçCAîB@í;;ë;;ç>;ßB;ÑD:¿D4¯@-¤>(¦A-¦A-¥@,¥@.¥@.¤?-¤?-¤>/¢>.Ÿ@.œ?.˜?-•>+‘?*>)>+>->->-Œ=,Œ=.‹<-‹<-Š=-Š=-ˆ<.ˆ<.ˆ<.ˆ</‡>/ˆ>1‹?1‘D2–C1¢B4­C6ºC;ÁD>ÁD>»EA¹PL²[T¥e\‘f]u_T[UIGMACI?<92?82>71;6094.74-63.43.43.34.24/13./4..3-.3-.3--3/-3/-3/-3/.3/.3/02/02///-00.22022010.0/-0/-3/,8,,;,)C0*K70S<6^IHtbn‡z”Š¶ŒÆ„ˆÏz€ÌrxÆik¶WWŸID„E=nG<dD<aC>^CAY@CV@DP>EKGQRKWUQ^WU`XS_UR^TT^SY_S^[LaZJaZJ,-/,-/,-/,.-------.-+.-+/.,/.,1-*0,)0,)0,)/+(/+(/+*/+*/+*/+*/+*/+*/+*0,+/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+1-,1-,2.-1-,1-,1-,1-,1-,1-,1-,1-,0,)1-*2.+3/,3/,3/,3/,3/,3/,3/,3/,3/,40-51.62/74/80-92,:3-;4.=4/>5.>5.>5.?4.?5,B5-C6.D7/F90G:1F<2G?4H@5J@6P?5T>3X<1^90b6+m9.t8-|8+ƒ9,;/“=0˜?1ž>0§A3­A4µC8¾E:ÊG=ÔG>ÞE?åC@è@?êBAæDAÚE>ÈD8·B1ªA.¢B,¢A.¡@-¢?,¢>.¡=-¡=-¢>. ?/œ<,š=,˜<-•>-“=,=+Ž=*Œ>*‹<+‹<+Š=-‰<,‰<,‰<,ˆ:-‡;-‰=/†</†</‡=0ˆ>3ˆ@2‰A5‹A4‘E5—D4£E9±I>ºG@»D>»EA¸MG´ZR¯f_£qf‘sh~rdjj^V^SIQFLLBJF=B>5<8/95,74+63,33+43.34.14-14-02-/1,,1+,1+-2.-2.-2.-2./1./1./1./1.02/02/11/11/11/11/11/40/4+0;/3A32C4/J;6]OOymy‹…Ÿ“»”–Ï•Ùƒ‰ÓtzÆjn·_b§Z[”LItHBdA>]>>X?BUAIVLU\U`bbqnn}xv†|rulyoguh_k_W_P]\Hb\Fc]G,-/,-/,-/,-/------.,-.-+/.,.-+0,)0,)/+(/+(/+(/+(.*).*).*).*)/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+0,+1-,1-,1-,1-,1-,1-,1-,1-,1-,1-,0,+0,)1-*2.+3/,3/,2.+2.+2.+2.+2.+2.+3/,40-51.62/80.91.:2/;4.=4/>50>50=4-?4.?4.A4.B5-C6.E80G:2H;3H>5H>5L=6O>6Q=4V;2Z90_7/h70p7.w7-9-‰9.<1–<1›=1¢@3§A3¬B5´D8¾E:ÉF<ÔE=ÛD=ßD@àE@ÞFAÔG>ÄF8²C2¥B-žB-ŸC.žB-Ÿ@.ž?-ž?-ž?-ž>.ž>.š=,™>,–=-”=,=+>+Œ>*Œ=,‹<+Š=+‰<,‰<,‰<,‡;+‡;-…<-†</…=/…=1ƒ=1„>2†@6‡A7ˆB6“G9—E7£G<¯J@¸IB¸GA·LF³TN±d\ªqfŸ~oo|mmseZfZNXMLNAKI=EC7@=4=:188.44,11)23-23-03,/2+/1,.0+.0+.0+/1.-2./1./1./1./1./1./1.02/02/11/11/11/11/11/2015+49-7<23?53H?:^VTxr|Šˆž““¹”—Ê–Ô„‹ÏyÂqy¸kt­hnž\_€XZqSUjRWjT^hZgmfvvr‚tˆ~’‡ƒ•‰~Žv†yr€qfteZeT[ZE`Z@b\D,-/,-/,-/,-/,-/,.-------.-+.-+.-+-,*/+(.*'.*'.*',+),*+,*+,*++)*+)*+)*+)*-+,-+,-+,-+,-+,-+,-+,-+,,*+,*+-+,-+,-+,.,-.,-.,-.,-.,-.,-/-./-./-./-./.,0,+0,+1-,2.-2.-2.-2.-1-,1-,1-,1-,1-,2.-3/.40/51.80.91.:2/;30=31=4/=4/=4/?40?4.A4.A4.C60D71F93G:4H;5J;6K<7N=6P;6S:5V72[6.c60k6.t5,}7/‡9/;0”<0–<1?3 @4¢@3¨@3±C6ºD8ÅE:ÍD:ÕF@×H@ÔIBÌI?¾E:®C3¡B.œA.B/œA.œ?.›>-›>-›>-›>/›?0˜<-–=-”<.“=.>-Œ=,‹<+Š=+‰<*‰<*‰<,‡;+‡;-…<-„:-ƒ;-„<0‚<0‚<2‚>3ƒ?4…A8‡C:ˆD9”J=—H; H>¬KD²KF³LG²SM®`V­sg¦qŒz‘Ž{‚‰ws€ocqbXcUNRDMN@HI;DD8@@49;.46+/1&01)01)/0*/0*./*./*//-//-//-.0-//-//-//-//-//-//-00.00.00.00.00.00.00.1/26+97+98/4;63HE>_^Yzz|‹š”±’—¿•Ç„ŽÃ}‰»{‰¶|‹²}Œ«}ˆšwƒq~‡n}‚n~~o‚~yŽ…ƒ™‹¡”‘¨˜¥”ˆŠƒ–ƒ|{j{i\hTXX@]Y<_[@-.0-.0-.0-.0-.0-.0.......-+.-+-,*-,*.*'.*'.*'.*),*++)*+)*+)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+-+,-+,-+,-+,.,-.,-.,-.,-/-./-./-./+*0,+1-,1-,1-,1-,0,+0,+0,+0,+0,+0,+1-,2.-3/.40/91/:20;31<41=31=31=31=4/>3/>3/@2/@3-A4.C60D71E82F93H94I:5J;6L:6N94Q83T50^72e60o6/x8/‚90Š:/<1”>1™?4›?4›?2Ÿ?1¥A2®B5¸D7¿E:ÇG>ËH@ÊJAÃI>¶F:ªB5žA0™@.™A-™A-˜?-—>,—>,™>,™=.—>.•<,”=,“=.=-Ž=,Š=+Š=-‰<,ˆ;)ˆ;)‡;+‡;+„;,„;,ƒ;-€;,;/€<1€<1>5ƒ@7ƒC:‡D<ˆE<”L@–H<žG>§JC®LI®QL­]Vªj^§€o¡yšš‚›ƒ†•€z‹xm{jbm]SZJQUFKO@EI:@D6;=057,13(01)/0(./).-(.-).-)/.,0/-/.,/.,/.,/.,/.,..,/.,..,0/-//-0/-//-//-//-//-2-17,:6*83-1961HJ?bfX{€z‹““£–°Œ•¶ƒ²¯…™²¤¶’¨³“¨«¤£Œ ž‡ž˜‚™}˜‰œ‹ˆ£”°š˜±›”­—‹£…›„’|k|iXfOSV;ZV9^Z=+/2+/2+/2+/2-.0-.0......------.-+-,*-,*,+),+),+),*+,*+,*++)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*++)*+)*+)*,*+-+,-+,.,-.,-/-./-./-./+*0,+0,+0,+0,+0,+/+*.*)/+*/+*/+*/+*0,+1-,3/.40/901:20;31<42=32=31<20<20=20=2.?1.?1.@2/A30B5/C60D63C84D95E:6G96H94K84N50X72_60i70r7/}:1†<1Œ>2>2—@6—?5—?5—?3œ@3£C5«C6³E8ºE;½G=¾H>¹G=°D8¦A5›?0—@/—@-—@-–?.•>-”=,•<,–=/–=/•<.“;-’</Ž<.‹<-‰<,‰<,ˆ<,‡;+†:*†:*†:*ƒ:+ƒ:+‚:,€:.€:0€<1€=4?6‚B9ƒD=‡F@ˆH?‘KA’H=šG?£LE¨PL¨XQ©f]¦vh¢Œw›™€•¤‡Œ£‡†ƒ~‘}t‚qjue\eRV_LNUCEL:?F6<@27:/68-01)00(.-(/,'/+(/+*1-,2.-1-,1-,1-,1-,1-,/.,1-,/.,2.-0/-2.-0/-0/-0/-0/-2-18,:5)51++66,GL8`hQzƒpˆ’‡—–š ™¥†–£‡›¢ª©›¹± À³˜·¨š¶§›·¨˜·¥‘±œ‰«’‰«±”’³–•´•­ˆ¢…„›{’xgzdTbIQT9VU9XW;,03,03,03,03./1./1//////....../.,.-+.-+.-+-,*-,*-+,-+,-+,,*++)**()*()*()+)*+)*+)*+)*+)*+)*+)*+)*,*+,*++)*+)*+)**()*()*(),*+,*+,*+-+,.,-.,-/-./-./+*/+*0,+0,+/+*/+*.*)-)(0,+0,+/+*0,+1-,2.-3/.40/:12:12;31<42=32<21<20;1/=20<1/>0->0-?1.@2/A4.?4.@51@72@93A:4B94C84F74H5/Q51X5/a6/l8-u9.€</†>0‹=1“?5•>5“?5“?4•B4šB4 C4¥D4¬B5°D8´E:±E;ªB7¡?4š>1–>0•?.”?+“=,“=,“<+“<+”<.”<.“;-’<-<.;-Š;,‰<,‡;+‡;+†:*†:*…9)ƒ:)ƒ:+9*9-9-€<1<3?6€A8‚C<…F?ˆIBŠICŽJAG>—HCŸNJ§VR§`Z©pe¤ƒrœ”}–¡ƒ¨Šˆ§ˆƒ „~–~yˆup{jdp\]iSR^JJS@BK:>E5:@29<134,22*1.)/,'/))0**1++2,,1++1++1++1++1++0,+0,+0,+1-,1-,1-,1-,/.,/.,/.,2,.8*75(13+(56&EK1\gGu‚d†“yŽ›Š‘ž”Ÿš‹ž˜¥——´ž¢Å¥©Î­¥É­¦Ê°§Ë±¤È¬—¾Ÿ‹³‘ˆ°²Ž²Ž²¬Š„¡‚€™{wŽrdx]Q_ENR7QQ5SR6,03,03,03,03./1./1./1./1/////////////.,/.,.-+.-+/-..,-.,--+,,*++)*+)**()+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)**()*()*())'()'(+)*+)*,*+-+,.,-.,-/-./-./+*/+*/+*/+*/+*.*)-)(,('0,+0,+0,+0,+1-,2.-40/40/:12;23;23<34=32<21<21;10<1/<1/>0/=/.>0->0-?1.>3/=60;60;83<94=:5>93@72C60G4.O4+Y4+d5+n8,x:-;.…;.<4‘<5>3@3A2“B1—A2™@0 >1¦@4ªB7ªB9¥@6Ÿ>5—=2•?2’?-’?-‘>,=+‘;*‘;*’<-’<-‘;.‘;.Ž;-;-Š;.ˆ:-†:,„;,…9)…9)ƒ:)‚9(‚9*9*~8,~8,€<1€=4€@7B9„E>…IAˆKFŒMFŒIAŽH@˜JF¡SO¨]X©hb©{n¤Žy™œ’§†‰¬‹‚ªˆ€¡„™€~‹wxnjxadr[ZhQQ]IITCCL;>D6<?467/44,30+0+'1()1()2)*4+,2)*2)*2)*2)*2)*0**0**0**1++1++0,+0,+0,+0,+0,+1+-6)25)-4-%46!AH&Wc;q€W‚’mœ} †¢Œ‹¡Š¨‰•¸Ž È”¤Ð©Ó«¨Ò®§Ñ­¡Ë¥“½—…¯‡‚¬„‡°†ˆ®…Œ±ˆ‹«†Ÿ{{”tqˆk_sWM]BIO3JM0KK/./1,01./1./1.0/.0/.0////00.00.00.0/-0/-0/+/.,1-,2.-1-,1-,0,+/+,,*++)*+)*+)*+)*+)*+)*+)*+)*+),+)*+),+)*-(,*(),())'()'((&'*()+)*,*+,+)-+,.-+/.,/.,-,*-,*/+*/+*.*)-)(,(',('1-,2-*2-*2-*3.+4/,50-61.;31;31<42<42=31<20;1/;1/<1/<1/=/.=/.=/,>0-?1.=2.=4-=6.;819919:29:2;81?6/C2+J1,T2)^3*g7+o9-u=.z</‡=2‹=3‹?2Œ@2Ž@3@1’?1•=/˜</œ>2¢B6¡C7žB7™?4–>2”>1”>/“=.=-<,Ž=,Œ=,Œ=.>/Ž<.Ž<.‹</Š;.ˆ:-ˆ:-†:,„;,‚:+‚:+:*~;*~;+|:*}9,|:.€>2>5€@6‚C:ƒG=…JB‡NE‹OGŒICŽID“PJ˜\Tžg`uiž‡už˜€”¡…ª‰‰¬‹ƒ¨‡€¡„~›zytˆoi}bby]\pUUgOO\HGRAAH8=A388.85.7/,3+)2()2()3)*4*+0*,/+*0*,0**0*,0*,2),2),3*-1+-1+-1+-0,-0,-0,-1+/4)/4*+4-%46!?F%T`8m|Qg‰™tžz¡~ˆ¡zŠ§{‘¶‚›ÄˆŸËŸÉ™žÇÆš˜Á•Œ·Š‚­€…®‚Œµ‰„«‰®…‰©‚~œxvolƒfZnSJZ?GM3FJ1DF./0+.0+/0+01,01,01,12-21-32.43/43/62/51.41,3/,4/,50-50-4/,3.+2,,1-,0,+0,+.,-.,---/--/,,.++-*).))+.)/.)-/(/.)-/)-.)-.*+.*+/+*/+*-,*.-)--+-.)./*./*------.,-/-./.,0/-2.+2.+2-*4,)5-*6.+8/*:1,:1*;2+=4-=4->50>50>50=4/<3.;2-=2.<1-<1/;0.=/.>0/>0/@1.A0)@2);4*77-39-28.56.:3-?-)F*'L)'S*&Z/(`5,d<0k@0yA0@/†A1‹B3@3“=0“;/’8-“;/“=.”A1•B2”C2’A0‘>.‘;,—;0—:2’;1Œ=0ˆ?0„?/‚?.ƒ>.ˆ@1ˆ?0Š>1Š<0‰;/ˆ:.†:-ƒ;-{9+~@3w<.q7)w>-w>-v;-}?2{;/‚@4‡E9‰I?ˆLA†MB„PC‡NE‘KI—SP”bY‘paŒ}j‰‰q‰–|Šž‚¤‡¦‰Ž§Š§Œ‡¤ˆ~Ÿ‚uš{o—uiib„_[zXZsUZnSWeNPWEJK=C?6@93;0.6**3')3'+3'+1&*,*-)+***,*(),'+.(,1(-2'-3(.3(.3(02(00)10)1/*1/*0/)-1++0-(//#<?*V\@pzX‹gœu‹sŒ¡vŒ¦wŠ¨v‰ªuŽ´{™¿†ŸÁ¾–ºŠ³ƒˆ®}…«|ƒª{…ª~ƒ¨}ƒ¦~€ž|y”ur‰mh|cYkUMZFIQ<CH4?B//0*01+01+01+12,12,21,32-43.43.74/74/63.52-50,50,7/,7/,6.,6.,3.+2-*0,+0,+0,-/-./-0--/-,1+*/)*.)(-.)//(//(//(//)-/)-.*+.*+/+*/+*.-).-)./*./*./)./*.....0....../.,/.,1-*3.+5-*5.(7.)8/(:/);0*<2)=3*>5,>5,>5.>5.>5.=4-<3.<3.=2.<1-;0.;0.=/.=/.>0/@1.C0*C0)A2+>4+:6-95,:3-<1-?-+D*)I*(N+'T/)Z5-_:1e>/pA/xA-€A0ˆ@2?4‘=3“:2“;19.‹</‹>.Œ@0A1A1ŽA/‘?1•;2•;2<2‹=0†>0ƒ@/?/‚?.…@1†>/‰=0ˆ<.‡;.„;,‚:,€;,x8,x<1s9-n9+s>.s>.r8*u:,}=1ƒA5‰E:‹I=‰K@†NA„PC‡NE‘JH—SR’f]Œwf„†p€“wž„¥†ˆ§ˆ§Š§§Š¤‰Ÿƒwœ}o˜ve’i`‹`Y‚ZY{X\wXZnSSaJNUCFH;C@7<737/-3*+2)*1(+.(*,*+**,+),+),-(,/)-2(02(02(02(02(10)1/*1-*3-*3-*12-12.-0,)--%8:,SXBox]€‹i‡–o†™l†žnˆ£p†¤p„¥pŠ­w“¶€™¹‡–¶„“³Œ®{†«x‚¨w‚¨yƒ¨|ƒ¦|‚¤{x’uqˆnh{eYjWMZHEL<@D5;=/12,12,12,12,23-23-43.43.54/54/85085085074/72.61-80-80-7/,6.+4/,3.+2,,1-,1-./-.0.1/-0--/,,.+*/+)./(/1'//)-/)-/)-/)-.*+.*+0,+0,+/.*/.*/.)0/*0/*0/+//-///0./0./0/-/.,1-*2-*6.+70*90+:1*<1+=3*>4+?5,?6-?6-@7.@7.?6/>5.=4-=4-=2.<1-;0.;0.;0.;0.<1/?1.C2+E0+H/+K--L,/K+.I*/E+.A-,@.*A.(E.(M.)X1*b3-g5,j:,o;-w;0=4‡<6Œ<5:4:4Š<2‡=2†>2…?3†A2‰A3ŒB5C5Ž?2=/Œ>1Š>.‡>/…>,†=.ˆ<,‰;.‰<,ˆ:-†:*ƒ;,<)~=+{<+}=1z<1v:/u;/x@1x@1v<.v;-?5‚B8‰F=‹H?‰JA‡KA‡NCŠNF‘JH˜TQ–f\ve‡…n‚‘t{¤ƒ…¨‡ˆª‰ªŒ©ŒŽ¥‰ˆŸƒš}y˜xi–ma’e\‹a\†`]‚`[|]UrVPhPFYEBP?:D93:2.3,*/)*,)**(0'(1&*1&*1&*0'*1(+0*.0+//*.-+.,+0+,0)-0(-1(-1)-01/23/..*'**"57*PUAmv[|Ši€k~“j™jƒŸn€ n~ m€¥q‡¬x¯|‹­zˆªx„©v§v§u¦w¦y¤y€¢}}›yw‘tp‡mh|cYkUMZHDH9=?299-23-23-34.34.34.45/54/54/650761961:72:72961940940:2/91.91.80-50-4/,4..4..3/03/01/01/20.1..0--/-+.0)02).0*.0*.0*.0*,/+,/+*1-,1-,0/+0/+10+10+10+10,11/1111/010.10.2.+3.+3.*92,92,;2+<3,>4+@6-@6-A7.B8/A8/B90A8/A81@70>5.>5.=2.=2.<1/;0.;0.<1/=20=2.B3.E2.L..R+0V'/U&.P'/I).C/.<1+;2)?2)G0(R/)_.*d/)i9/k;/u<3}<6…;8‰;9Š;7ˆ:6‰>8†@8†B9…B9…C7†B7‡A7‰A5ˆ@1ˆA/‡@.‡@.‡>-ˆ<,ˆ;+‰:+Š8*ˆ9*‡:*ƒ:)<){=(x>(x>*‚>1{7.z7.z<1v;-w=/|A3{@2€B7ƒE:†H=ˆJ?†J@‡MBˆODŠQHŒSJŽ\QŽh[‹tb…g€‹m~–vž|ƒ§ƒ„©‡‡ª‰‹ªŠ‹¦‡‡ ‚ƒš~}˜yq•oi”ifgfŒeg‹gd†e_~_Zw[PhPK^JBP?8D62:/.4*,/(+*%2&&5%(4%(2&(1'(/)+/+,.,-+++*+-*+-(,-(,/',/',/*+-.*+1++0+'.+"88,PUAiqYv„c{Œhyh|–iœl}Ÿmyžkz m¥r‚§t€¥q}£p}£p}¥s~¥v~¥x}¤x|¡x}Ÿzz™wuqn‡je|bWkRN[GDF9?=1:8,45/45/45/560560560761761872872;83<94<94<94<73<73<41<41;30;3083072/61.61.5106216213122011/00./1-.2,04+.4+.4+.2,.2,,2,,2,,3/.3/,3/,3/,21,21,32-32.32032032032051051.61.61-;4.<5/=4-?6-A7.B8/E8/C9/D:1D:1E;2D:1C90B8/@5/@5/>3/>3/=2.=2.=20=20>31>31@51E31M02T,4X)3W(2R)1K,1B30:6-77+:6*B4)M2)X/)^/)f:1j;3s<7z=:‚<:†<;‡;;†::‚;7>8A8B9ƒC:ƒC:…@9„@7‚C2‚C1ƒB0„?/†=.ˆ<.‰:-‹9-‰7+‡8+…9+‚:+~=+x>*v?*x>*9-|/'‚8/„>4w4+s5*}A6}C7E:€G<‚I>ƒJ?„KB†MD‡QG…WJ|aNzjQ€pYu]‚|bƒ†i†“uˆ|ƒ£~§‚‚ª…‚¬†©„¥€{ž}z™wz’pzlxlwŒkumr‰lm„gkd`rX[iRR[HHL=@@4;7,70&5*$6('5''3''1'&.)&+*(++)+-*',('+*)+*)+***,+),+),-)*,#$2*'50*86*BC5UZFfpWn}^tˆeqŠbuex˜iw›ks™htšiwŸkz¢nx lwŸmx ny£s{¥u{¥w|£wyžuzœww–tsŽom†hd{_WkPN[GCC7>:195,560560671671782782872872983:94=:5>;6>;6>;6>95>95?74?74>63=52;63:5294194184184395484373243151240/6-06-.6-06-.4..4..4..4/,40-40-40-51.32-32-43.43.43/431542540841850940:5/=60>7/@7.A8/C90D:0G:1H;2F<3F<3F<3F<3E;2C90B71A60@51@51?40>3/>31?42@53?53@72C52I35P16T/6S.5P05J22C52=90<:-=:+C7)I6(Q3)W2)]2+d3,l50v64}77‚87ƒ77‚66~75}:4}<6}>5€?9ƒ@8†?9…A8€B3€C1B1ƒ@0…=/‡;.ˆ:.‡9-…9,ƒ9,‚:,<,|=,y>,x?,|=,‡5*‹2,¡LE§XQ‹A8|90‚F;€K=yH:zJ<{M>|N?}OBQE‡UJ‚_LrkOosR|uX‡w]yb˜iŸ‹s ”z––z|‹£ˆ¨…§‚€¤~{Ÿy~™vƒ‘p…ŽoƒŽp€pp{ŽpwŒms‡kj~bfv\_hSV[GOM>GA3@6*=0';,'9+(6+'3+(/,',-'+.').().(+-(-,*/+*3)*4(*7'*7'(3($<3,E>4IG8QR@]bKgqVjyZn‚]k„\l‰]p‘bq•eo•do—eršfuŸmrœjq›itžnx¢rz¤vy¢vyŸvvštw™vu”rokj…fc|^UlON\ECC7@91;4,671782782782893893983:94:94;:5>;6?<7?<7?<7@;7@;7B:7B:7A96@85=84=84<73<73<73<74<74<74;639529338308/09/.8/080.80.80.61.61-61-61-52-52-63.63.74/74/540540841952:63<94=84@93@70A8/C90D:0G:1H<0I=1I=1J=4J=4J=4I<3F<3D:1B8/A7.A81@70@72?61?61@72@72A83?74@85B86D97G96H96H96H94E80E8/E9-E9+G9,I9*K9+Q7*Z/&d/'n3-z63ƒ98‰;9‹;:‹=;‹A>‡@:‚=6<3:3‚<4ˆ=7‰@7ƒA5B3‚@2ƒ?2ƒ=1„<0;/€</~<.|=.{=.|>/|>/}>/=/†9/1+¢<8ÍlfÙ~y­ZTŒC<ˆLAN@tJ<qM=pQ?qR@tS@zWD‚[J~eOmsOo{U„y[˜u_©oc¶mf¾qk½wo»‚w±Œz§—~žŸ€–¡¡~…y…™vˆ‘r‹rˆ‘r„“r€–r|–sx“pt’pm‹ii„edx\]kQV^GMP;ED0B;+@3+?2,;0*70*30)00(./'./)/0*2/*6,+:*+>(+C&+E$+C&(F5-LC4VQ>[YD`bJgmQiwVj{Wl‚[g‚Wf†WlŽ\o”an”an–bršfsko›jo™irœnw ty¢xxžwu›vs—su—vs’rn‹li„cb{[TmMM]CGH:E<5@707827828938938939:4:94:94;:5<;6?<7@=8@=8@=8A<8A<8C;8C;8C;8B:7?:6>95>95=84>95>95>95>95=85<73:51;30:0.:0.91.91.91/91.91.72.61-61-63.63.63.74/74/74/540651952;83<94?:4B;5B;3A8/B:/C9/E;/H<0I=1J>2J>2K>5K>5J=4J=4F<3E;2C90B8/B92B92A83@72@72A83B94A:4?82@93B;5D=7F=6G<6K<5N;4M6.N6,Q6+Q6+Q7*P9+P9)V6'f6*r6,~;3‰@9•D@›HDŸJGŸLF QJ™LDŽD;…;0„7-…7-Œ91=4ˆ>5‡>7†=6…<5…<5=4}=3z>3x@3vA3x@3z>3<3ƒ:3ˆ73‘31˜(&³=;ì|zý•’Åhc–G@‰K@xH:nM<jQ=fT>hV>lX@t[E`L€hPysQ„wUžt\´l^É__ÓV\ÙQ[×T\äouÙzx̆|À~µ•€«•}£’xŸvœŠrœŠt™u•u‘‘u‹’s†‘s‚‘r|‹ny†ju{amoWgbN_TBUE5R</O4-M1-I0,D/*>/(9/&7.'6/'81):/)=.+A,+F)+H(+K'+H)'TB4YQ<d^FgeLilOnuVm{Xl~Xk„Zg„Vg‡Vm]p•bq–br™duit›lo™ko–jr™mwvyŸxwšyt–us”uu”usqoŠki„ea|[TmMM]BMN@KB9F=69:49:49:49:49:4:;5=<7=<7=<7=<7@=8@=8A>9B?:D?;D?;E@<E@<E@:D?9D?9C>8E>8D=7B;5B;5B;5B;5B:7B;5A:4A:4A83A83A83@72@64>71>71>71<71<71;60:5/85.85.74/74/961961961:70<71=82A:2B;1C:1D<1F<2J>2K?3L@2N@3N@5N@7N@7L?6K>5I<3H;2E;2E;2B90A8/@91?80?80?80@93@93<5/MD=M@:K:3T@9R62O0+a<6\3-`5.`4+^/'^/%f6,m=1q=0‰I=G;—I?ŸKAŸF>›>7š=6žD;¦ND¤PE¨VJ«YK¥OB™A5—;0›>6“98‘98Œ65†52†84„?8|@6r>1rB4oA2q=0v:0‚72Œ43’-1š',ÈHIèbaÅEDÍWUáyv«VO†F<„VFmR=i[AibFjeHj`En^D|dLjT’bL²m]ÑnhÛX]à;Lç-Eò+Hõ0Lö@YìI\ä[eånrâ{|Û€}Ûƒ؉‚Ãv½wº„x¶†x²ˆx­Šw¨‹y¥Œxš€o™~m˜xi“oabY„UM{IBxA>u:<i.2d02a11P&'G%#L0-M51G4.E2,D1-F1.F.,G+*K--Q6/YH4`W:f_BgdEkoNu|Zu„]oYlƒWl‡Zp]r’as•bu—dw™fv›hr–js˜os—qq•os•tw™xz˜|y–zx•ysrm‡jk„fi‚dazZTmMO_DNO?SK@PG>9:49:49:49:4:;5;<6>=8?>9>=8>=8A>9A>9B?:C@;D?;D?;FA=E@<E@:E@:D?9D?9E>8E>8E>8E>8E>8D=5C<6C<4D;4C:1B92B92B92B92A83A83@93@93>71<71;60;6096/85.74/74/96196/96/:70<71>:1A:0B<0C;0E;/I=1J>0L@2L@2N@3N@3N@5N@7M?6J=4I<3H;2E;2E;2C:1B90@91@91@91@91A:4B92D93I81L/+V.,j76u99{;;…ECƒD?„H@…IA†G>ŽIB™NH¡PL¢OG“D7”B4šB6ŸC8 >3œ7-œ7-Ÿ=0£C5›?0™@0 E3¤G6§F6®H:¶NE´LM¯HL¥@D™9;‘98>:ƒ@8x>3o>0zI;…LA„?8„,+’).³9DÒLWÜKNßMMÊ>=À@?Ð`\³YQ„@5‚TDyaIe[@^]?ihIslOvgJ~dK–cN¼dXÖ_[æUZëANò,Eþ%Dÿ&Hÿ'Iÿ.Nù3Nò<RðIZëP^åQ]ãS]àXbÛbiÕflÔjnÒmqÏqrÍutÉxwÇywÊ||ÉyzÈvxÇqtÆkrÅfnÅakÃ_kÅ`n³S_¥KUšGQDK†EIm69HT1-M0*H1+J6/K81K:2O>6UE8[O5cZ9gaAifEnrOz‚]z‰bt†^r‰_p‰_p‹`qŽ`u’dw”dw”dw”fs’ix–rz—xy–x~˜}ƒ„…‡ƒ›…™ƒz’zr‰om„hhd`y[TmMNaERSAVPBUOC8938938939:4;<6<=7?>9@?:@?:@?:C@;C@;C@;C@;D?;D?;FA;FA;FA;E@:E@:E@:G@8F?7JA:I@9H?8G>5F=6E<3F<3E;1D:1D:1D:1D:1D;4D;4D;4C<4?80?80<71;60:5/:5/94.94.96/96/:5/;7.>7/@9/B90C;0E;1F<0I=1K?1M?2M@0NA1M@0P?5M?4L>3K=2I<3H;2E;1D:0C:1C:1A:0A:0?;2@<3@<3D;4UD<R3.j23ŽAG­LWÃU`Ë]fÆ_b›B>—I?–LAœNB¬RJ¾URÌOSÄLK¥@4B0 @0¥?1¥;.£7+¤8+§=/«E6¡>+˜7$:'¥>-¬A/²C2¶D:§02¯:B¹DL½LRºMR­KL–A>‚71{8/v6,x2*„1-œ37¹=GÕGWèM[âFIÏ53Ð:9½31ÈNKÆc]”J?Œ[J}cLj_CgdEtoOpQhJhN°hYäbbõQZôDQö7Iý1Jÿ2Nÿ/Mÿ*Hÿ2Oü0K÷1Jõ5Lò4Mð2Kó3Ló7Pò@XïC[îF]íIaëNcêQeèUhèVkåSjäRiãOiäNiçNlëPoòSsóVuþh…ña|å[tÕUlÍYlÉdr¨R]r-2^&'Y0,W:4Q?5B:-:8)>B1LN9VO3aV6e_?heDquT†e~ŒiwˆdxŒiu‹er‹dr‹cvŒeyhzizj€•v„›~Šž… Š’£—¨–˜©™–¦™‘¢’‡˜†zypƒmg~b^wYTmMPcGSXDXUDYVG7827828939:4;<6=>8@?:A@;BA<BA<DA<DA<DA<DA<E@<E@<GB<GB<GB<FA;FA;FB9HA9HA9LC<KB9JA8I@7H>5G=3F<2E;1D:0D:0E;1E;2D;2E<3E<5E<5@91?80=82<71;60:5/:5/:5/96/96-;7.;7,?8.@:.C;0D</F<0F=.J>0K?/M@0M@0M@/M@0O?2O>4L>3K=2J<3G:1E;1D:0D;2D;2B;1@<1@<3A=4B>5F<3S81[*&‰:?¾T`ÙTeæUfãUcËJOŸ30–:/‘>0™A3®F=ÅIGÕBHÍ>@±B7§F5©B3¬@3¯?3°>3³B4´D6²G5©B/£<)¤;(©<(«:(®6&­3(¶97º9=½7>¼7<¿<BÆJLÄTS¾XS™?7Œ4*‰,%61ÃHKÜOWâAQÛ3@Þ:9Í.*Ó84È74ÆE@È]U©WKWFwW@veI~pSpQ„fJdK©o[ÕuiîSWüDP÷;Jø9Iþ=Nÿ@Qÿ:Lù4Hÿ?Sþ9Mú4Ký3Ký1Jÿ/Iÿ0Nÿ6Sÿ3Tý4Vý6Wú7Wø9Zø=\÷>^õ@aøCfö@fõ?eõ?gø?hüCmÿErÿIsÿOuÿQuþUvòSqçTnåaxÖfv·Wb}15j0/X1*P8,G>/>A.;D/?G/PK._T8g`CokN||`ˆŽr‡‘v}‹qzq|s|szozŠm}Œoƒ’uˆ—z•£Šœ©•£®¦±¡¬´§±¹®°·°«µ­¡«¢” ”ƒ‘‚s„qh|c]tXSlNPdHRZCWYDYZH671671782893:;5<=7?>9@?:BA<BA<DA<DA<DA<EB=FA=FA=FC<FC<GB<HC=HD;HD;JC;JC9LC:KB9KA8J@6J=4I=1H<0G;/E;/E;/E;/E;1E;1E;1D;2D;2@9/@9/@91?80<71;60;60:5/;7.;7.;7.<8-?8.A;/C;0D</G=1G>/K?1M@0M@0NA0O?/O?0O?2N=3N=3J<1I;0G;/D:0D:0D<1D<1B;1@<1A=2A?3B?6K=4\5.w32­LSÛ]iæM_å@Q×6E·&+¨1)7(’:&—<)¬@3ÃD=Ô>?Í;;±?5¨B4ª@2­?2²@5¸C9¼H;»J<¬>/ª?/¨=+¦;)ª9)°:,·;/¼<1ÊFAÎDAÐ>?Ð79Ö7<ÞBEâLNÝROÄC>ÆKCÍTLÔSMÙKJÛ?Bà5>á27Û4.Ú7.Ð1+Ï:4¿84³@9µ[P–UC{N9‚bI†kP„`F’[F­fTËrdçmhêEKò:Dê9Cç<DçBHçFKèGLêFMôJSòBMò9Iö5Hù2Gý/Fÿ2Lÿ8Rÿ9Vÿ9Xÿ:Xý:Zþ;]ÿ=_ÿ@bÿAeÿCiþDkþDmýBmüCoüCoüBqýBoÿGpÿ@hÿGmÿMpòIhéOkå[rÙcs½YcŽ?D`&$Q+"V@3VO=IL7@D-RJ3eYCujV€{gŽy™œ‹•œŒˆ“ƒ‚Ž€‰—ˆ›Œ™ˆ‡’‚Š“‚—žŽ¤¨™²¶§¸¼®¿Á¶ÀÁ¹ÂýÅÆÁÃÃþ¾¾°µ±¢©¢—Œy‡vi{e\sYTmORfJQ[BUZCW\F560560671782893:;5=<7>=8@?:@?:C@;DA<EB=EB=GB>GB>GD=GD=HC=ID>IE<IE<KD:LE;LC:KC8LB8KA5L@4K?3J>2I=1G=1G=1F<0F<0E;1E;1D;2C:1A:0A:0@91@91=82<71;60;60;7.;7.;7,<8-?9-A;/D</E=0H?0J>0L?/M@0NA0NA0O?/O?/O?2N=3M<2L;1I;0G;/F90C9/C;0B<0B;1@<1@>2A?3B?6N;4m84—FEÄY_ÛWbßCQÞ8FÔ3;½++­1'¡8%˜:!—9 ¤;&¶>.Ã:2¾71§7,¢:-¥9-§7,¯:1¸B8ºE;·E:®>2­?0§<,¤6'ª6)¶>0ÃD;ÊG=¾8-Î@6áD?ìBBô=Aó9>ë27Þ.0Û75âGBèSLåNGÜ=9Ù10ã/2ê67Ù1(Þ</Í,"Ð71¾3,°7/Ég\¸l\ŽWC‡ZCƒV?‰R=©\LÎlaágbäTTðEKñ=Fä;@Ù=>ÒA>ÒGBÝOMëWWíNRïDMð:Gö5F÷2Fø.Dû1Gþ7Nþ8Sý8Tý8Vþ9Wÿ;\ÿ>aÿAeÿCkþ;eý<hý>jý?mú>nø>oô=mö:jÿHrÿ;aÿ?dÿKnÿKn÷NmïUoãZnèr‚Âaj˜ILt:8\6-P9+PC2UM:^QAreUˆ|n•‚Ÿ‘¦§Ÿ¡¦Ÿ–œ˜•ž›ž§¤¦¯¬¦¬¨¢§£¦¨£µ´°ÂÁ¼ÌÉÀÑÎÅÕÐÌÕÐÍÔÎÎÕÏÑÑËÏËÆÊ¿½À°²¯˜Ÿ˜€Œ~m~k`t[WnRVjNS`FV`EX`H560560560560671893:94;:5=<7>=8A>9C@;DA<FC>HC?HC?GD=HE>ID>ID>JF=JF=MF<MF<ME:LD9MC9MC7NB6MA3N@3MA3JA2JA2I@1H?0G=1F<0D<1D<1C:1C:1A:2@91?82?82<71<71<8/<8-<8-<8-@:.A;/D</E=0H?0K?1M@0NA0P@0P@0O@-O?/O=1O=1M=0L</I;0F:.E8/C9/B:/A;/A:0?;0?=1@>2@@4P91r1/¨JKÁSV»>D½06Â03Á//º1)©1!£9#œ=!™;›< ¡=#¥;%¤6%ž6) 8-¢6,¥4,­81·@:¸C<²@6±B7­A4¨</¦8+¯:0¼C8ÃD=Å@7Ã>-Ï>-Ù5+á*&í"%ú%+ÿ*1ÿ.4í)*ç.+á3,ß4,à3,ã2,é0-ç2+Ú2%Ö6&Ð2&Ï7,Å6.½>7È`UÒq¦eSVBŠM:£WIÈf[ßd_çRTèCIõFMí@Dß??Ô@<É@8Æ@7ÑFAãMLïJNô@Kù9Hý7Hü5Hø3E÷6Gú;Mú8Pü7Rû6Rý6Uÿ6Xÿ9]ÿ;aÿ<gÿ>kÿ?mÿ@qÿBtÿBuþBuüBtùBpÿFmúAaþEeÿKjþKkÿVtÿ_zõ]tòj~æp~Óow®^aƒCAg6/hB7sUJye\Œ}v£–­£¡²®«¶¶¶²¶¹ª¯³°·½¶½Å½ÁÊÀÃÊÃÂÊÉÆÍÕÎÖÝ×ÛâÚØçÝÛéÝÝæÚÜåØßä×ààÔÞÙÏØÊÅ˺ºº¢§£ˆ’‡t‚qexb\sW[oS[jM\iK]gL561561561560561671872983<;6=<7@=8B?:DA<FC<GD=HE>HE>HE>HE<JF=JF;KG;KG;NH:MG;MG;ME:MD;MD;MD=NC?NC=MC7MD5KB3JA2H>2G=1E=2D;2C:1C:3A:2A:4@93?74<73<71>7/>7/<8/=90>:1A:2C<2D=3H@5I?3L@2MA1NA0P@0O@-O@-L?/L>1M=0L;1J91I81E80C90@9/>:/;;/<<0=>0>?1A?0S8-‡<7Ä\[ÊZY®86«.*²1+®.%­2#¬9&¬B*ªF,¦D'£A&£A&¢<#Ÿ9# 9*£;0¦:0¦7.­<4¶C<·E;°@5«=0¨</©;.¬<0»E9ÆLAÅE<¼8,¿6$Í:(Ý;.æ3,ñ+*ù(+ý&+û%'ø**õ.+ï2,ë4,è3*å3)ä2(à3%à:*Ñ2Ü?0Î6)È8-Â?5³A6Ñl`¿gY¥RB¨OAËcZçhbæRRêAFóBJë>Dá;=Ö<<Í@9Á>4¶8,¹6.Ä94âHHé@Eð;Dö:Hú:Iø8G÷;Iû?NþAUÿ?Vþ<Tþ9Tÿ8Uÿ9Zÿ:^ÿ;cÿ>iÿ>lÿ>oÿ>pý>qú@rø@t÷Aq÷CjÿMmÿSs÷Jhë@`ýTsÿg…ÿe‚÷]wï_xçh{Üp}Æqx§gg^X{ZQ—~wª™’¾°­Ä¼ºÆÂÃÈÇÌÇÇÏÃÃÏËÊØÌÊØÑÊÚ×ÎßßÔäæÛéêàëíãëïåæòèæôèèðäæîáèíàéêÝçäØâÑÊÑÁ¿Â««©‘–z†xl{hbu_`rXbpVboScmT21/320431651875984984984;:5<;6==5??7AA9CC9EE;EE;HH@HH>HH<JH;KJ8LK7ML8NK8MJ9JF:GD;JFCNIMNIPGDOD?ENE>LC4J@4KA5MC9LB8F=4B90E<5C:5@93?74@85?75<74<42C:5B94A96>95?:7>:7?;8@<9B?:D@7G@6J@4L@0O@-O@+L?,G@.F?/I;0K81M53K65J88F;9B?:6904</9D4:A/69$?=(bC1¼j^¹JA¦7,¥5)§7+¥5'¥7&¨=+£8$¥<&ª@*­@)¬=)¬9&®6%«6%¤6'¡7)¢8*¦<.ª@2¬B4¬B2¬A1©>,«=,­<,³=/½C4ÄF8À>1º2&Ç9+Ì8*Ð8+Ö8-Û7-â5.é3/î1-ñ.,ô.-ó0,ñ1,ê5*ã7)Ý:)Û:(Ü9&Ô3Ð3 Ï8'Æ7'¾6(ÂB5ÏSIÈNCÏSKá\Wî]ZðPRí>Cò9?÷?GêAFßCDÕAAÈ?9»<3±;/°</²<0ÊL@ÔKCÜGCá>?ë<A÷?Gý?Iù;GþDQüCQþDRÿDUý@Vü<Uÿ<ZÿBdÿFkÿAjú;gõ:gö<mùCsýIyÿKzÿMyÿMtøPsðOpçMiêMjüYxÿgˆÿ_ƒõGlöWwè_yÃ^n½{‡a^xp§‘„»§œÑÄ»ÝÖÐÝÜÚÜÛàÞÜçâÛëæ×ìëØîñÙñöÝó÷âó÷çôõëôôîòùôñùôðùñïöíîóèìîãééÞäæÝâÖÐÔÍÉÊ»º¸£¥ ‹‰yƒxr}op{k}†sxlv}k0./1/0320542653762873872:94;:5==5??7AA7CC9DD8EE;HH>HH>HH<JH9KJ6LK6MM5NM8KJ8KI=KJEPPRWU`YXjVTjRO`OIKMD?H?:F=8G>9H?:F=8B;5D:8A96?74?74@85@85=85;62=4/=4/=52<74=96>:9=<:>=9B?:D?9G@6J@4M@0O@-P?+L@*B?,B?.F<0H:1J65I56F35@65@<9:=6;>5@@4E<-J9)^B4€L>®QB«;- 2#¡6&£:'ž7$ž9%£>*¡;%§<(®?+³@-¶=,·9*¸6(µ7)ª9)¥:*¤9)¥;+¨>.«A1«B/«@.®?,«:(±<+¿E6ÆH9Á?1¼8+À6)Ë7+Ï7,Ð9.Ñ;-Ô</Ø:.à8/ç4-î1-ô.+ô.+ñ0+ê4)á7(×:'Õ:$Þ<'Ù6#Õ8%Ô=*Ì;*Á5&Ä:/ÏF<ÑF?ÚIDéOMóPQôGIð;@õ:AøCHåBEÚDCÒBAÅ>8·;1®:-ª<-«=.¶E5ÆL?ÔNEÜGCã?>ï?Bú?Fþ@JøCJ÷CLúDPÿFTýBSù>Sü>XÿBaÿFhÿCiü?iù@jùBpüFvþJzÿK{ÿJzÿHtõKpñQsõ\zù_{ûXwüNqýEkúDlïEiÚKgÈ_p±nukLI~t°–‰Ì²¥äÓÉìãÜëçæêéîêçòíâóöãùûáúÿâýÿçÿÿìÿÿòþÿöþÿùûþú÷ýúõü÷ôúõòøïðôëîñèíïæëæÝàÜÖØÊÆų²®ž¡šŽ“Œ‰…ˆƒ•‡‰€†Œ~/.,0/-10.21/43/540762761:94::2<<4>>6@@6BB8CC9DD:IF=IG;JH;LI8MJ7NL7NL7OL9KI:NKBTRS_^fihxmm…lkŠkhƒ`YiYQ\OGRH@KH>GG=EE<A@:<C:;?:7<74<73=82>93>:1=9083-94.;60<92=:3>;4?<5@<3E>4G?4I?3L@0O?0P?/P?-L?,<;&:=(?<+A;-B71A62>42;30=84B;5H94N2.Y,)l/.‡;= FE£;0¢2$Ÿ1 ¤9'¥<)ž7$ž8"¢<&¤;&ª=)±A-¶A/¹>.»<-¾:-¾</²<.¬<.©9+©9+«<+­>-­>-­<,²?-°8(¹>.ËL=ËG:¼6*º2&É9.Ð6,Ô6+Ô8,Ö:.Ø:/Ü8.ã6/è3,ð0-ô.+ô.+ð1)ç2'Ý6&Ô8"Ò7!Ý8$Ü5#Ú9'Ú>/Ó=.È6)Å9,ËA7É<5Í>8ÙEAåKIêJJéCCì?AëCCÞCAÕD?ÍB=Â=4¶:.®8*«:*¬;+¬8)ÀD8ÔNEÝIEà@@è>A÷BIÿHPôAGô@IùCOýGTþEUú@Uû?XþA_ÿDfÿCiÿCkÿFpÿIwÿK{ÿL|ÿJzÿFxÿHwÿKtúNtÿZ|ÿa€ýUvñCdûIkÿTvÜ?\ÍI`Ø{…¸||aC;|n®ŽÕ³§óÛÑûìåúòðù÷ú÷ôýôìûúëÿÿêÿÿìÿÿîÿÿóÿÿ÷ÿÿûÿÿýüÿþûÿýùÿúøÿøöÿõöýóôûðôùðóðçêåßáÓÏξ½¹­®¨¢¥ž£™£—£«žž¦—›£–/.,/.,0/-10,21-32.54/650880991;;3==5??5AA7BB8CC9HE<JF;KH9MJ9PK8OM8QL8OL;LJ>QPL^]bmlzzz’‚¡€‚¨€€¦{u—rkŠe_{YSmTLdMEZG@PB<HD?F@;?<87;63;60<8/=9.;8/:70991;;3>;2?=1@<1?;/A;-F?/H?.K?/M@/O?0O?/P>0L?/@=*?>,@=.?;/?;2>93=:5:94<94D95M51V-+j)-„28ž8C«>C¦7.¥7(¥:(ª?-¨?, 9&¡8#¤;&¥:&«<)³>,¹@/½>/Á=0Å=1Ä>2½?3¶=2²9.®8*¯9+°:,²:,³9*¶;,¹;-ÄB4ËE9È>3¾1'À2(Í9/Ö5+Ø4*Ú6-Û7-Þ7.á6,æ3,ì1*ó0,ô.+ô/)ï0(ä2&Û4$Ò6 Ð5×2Ú0Ú4$Ü<.Ö=/Ð9.Í=2ÒD:Ä5-Å60Ê;5ØD@âMIåKIÞC?Ö=8Ó@9ÎA8Ç>4¾</µ:+°8*¯9+±;-¬4&½?3ÑH@ÙHCÝB@å@DóFLýNUð?Eð?EöBMþHUþHWüBWú@XüA^ÿAcÿCfÿFmÿIrÿMyÿO|ÿL{ÿIyÿDvÿN~ÿR}þKrøMoÿVuÿUu÷MjðFcïKfÒ>VádtþŸ§ÓŽd92lJ>¥ynÐ¥œõÔËÿéãÿôòÿýÿÿüÿùóÿüïÿÿïÿÿðÿÿòÿÿôÿÿ÷ÿÿûýÿüûÿýúÿüøÿúøÿù÷ÿö÷ÿõöÿôøþó÷öëïìãäÚÕÒÉÆÁº¹´³´¬±´©°¶ª¶¾³°¸­¬´©10,10,0/+0/+10,21,43.54/77/880991;;3==3??5AA7DA8IE:LF:NH:PJ:RK9RM:SL:QK=OJDVTUfdqwx††¨¹“ÃÆŽ‹À‡ƒ¶{w©pmšid_[~UPnNJaKGXEBM?=B;7895296/85,85,671783891;;1></?<+B=*C<)G?,J?+K@,LA/M@0M?2L@4K>5L?6K>5F<3B92=82:946;47<59<5>:1H4-Y2-w78”?D¦>E§9<ª;0ª<+«@.¬A/©@-¥<)¦;'«>*§8$­:'µ<+¼=.Á<-Å;.Ê<0Ê=3Å?6¾>3º:/·7,·7,¸8+º8+º8+»7+ÇA5ÍC8Å8.Á1&Æ3)Ë7-Ï5+Û4+ß3)á4-â6,ã5,ç5+ì1*ð/*õ/,ö/*ò/)ì0'â2#Ù4!Ð5Ï4Ö1Ù/Ø2"Ø6)×9-Ô:0Ö?6ØE=ÖF>Í@7É<5Ë@9ÖKDÙNGÒE>Å;1Å=1Â<0À</º;,·9*´:+¶<-¹?0µ9-¿<2É@:ÒC?ÛCBãDHíJOöOVì?Eí>CòBLûIUÿJYýFXúCYûC]û@_ûBdÿElÿJsÿNzÿO|ÿLyþIvÿJwÿTÿT}ýJqùImÿStÿVtøNiëD^äF]êXkÿ–¢ÿµ¼óžŽHFk.)¦kcÍ–óÈÁÿãÞÿñðÿüýÿýÿü÷þþöÿÿöÿÿ÷ÿÿøÿÿúÿÿüÿÿýýÿýúÿüøÿûøÿùøÿø÷ÿöøÿõ÷ÿôøÿôøýñóóéêäÜÚÖÑÍÍÊÃÉÉ¿ÊÊÀÊÍÂÉÐȾȿ·Á¸65143.32.10+10+21,32-43.66.77/880::2<<2>>4@@6B@4JD8ME8OH8RK;TK:TM;SL<RKAQLIZW^li|~Œ¸–™Ì™žØšžÞ™˜Ú”‘ÔŒŠÉ†…¿~µxv§nk–fe‡]ZwVTiMKYDAJ><?;:8;74762555457664872<:.?<+C>*F@*G?*H@+IA,IB0IA4HB6HA9G@:K=<I;;C9:=77875384/83/917<574+C1']80~C=–GCž>?ž51§;/ª<+ª?-ª?-©>,©>*¬?+°?-«8%²9(¹:+¿9-Ã9,È:.Í:0Ï<4Ë>5Æ;4Â91Á8.Á8.Â9/Â8.Ã6,Å7-ÑC9Ð@7Ã0&Ã,#Ð7/Ö<4Ó2*à3,ä2(ç2+è3*ê3+í2+ð/*ó-*ö/*õ.)ñ0)ì1(á4$Ú5"Ñ6 Ð5Ø7#Ù3#Ö3$Õ3&Õ5)Ô8,Ô<1Ö?6ìYQáRJÓHAÌC;ÊE<ÌI?ÈE;À>1¼:*¼;(¼:*¹:)·:(¸:+¼>0¿A3ÁA6Á<3Å<6ÏA=×EEÝGHäIMëLPèBFê@CðCIùKTþNYüJZüF\üF_øA_ùBaýEiÿJpÿNwÿOzÿNxÿLvÿQ{ÿRyþOvýOtÿVyÿ]{ÿSoîD^úTlîQd÷dtÿ’žÿ‹•ôƒ‰Ç`d§MMµjgΊXÿÞÙÿïîÿúùÿüþýûÿýúÿþûÿÿûÿÿûÿÿüÿÿûýÿûûÿûøÿûøÿüùÿûúÿûúÿøúÿöøÿó÷ýñóùíïòææçÝÛßØÒÛ×ÎÝÛÏàÞÒßáÖÜãÛÏØÓÅÎÉ<94;8185052+41*41*52+63,74-85.96/;81=:1?<3A>5C?4JB7MC7PG8SJ;WK;UL=UK?SJCSJK]Wcnl‚‚‚¦‘•Åš ÚŸ¦ê¢©ñ¡¥ïž ë™›å•˜Ý”•Ö‘ʉ‰½‚ƒ±zy¡rq‘fc~XVkPN\IGRFCLCBJ??K==G;:@;9:<94?;/C=-E@,F@*FA+EB/EC4CC7BC;AC>@ACB<FD>LCANEEOCHNAIL>HI>GDCHAA=2L:.gF7ƒOAI<Ž?2”8)¥>/©>,«>*¬?+­@,¯@-°?-±<*±8'¶8)½9*Ã9,È8-Ì8.Ò91Ô;5Ï:4Í:3Ë81Ë81Ì92Í:2Ì70Ë6/Ó<5Õ>5Ò91Ì2(Î4*Ø;2Ú<3×3*ä1*é1'ì1*î2)ð1)ò/)ô-(ö,(÷-)ô/)ð1)é3(â5'Ù6%Ò7!Ï7 Ô9%Õ8%Ó6%Ñ4%Ò4(Ó7+Ò8.Ð7/ãNGèXPçZSÚQIÌG>ÄD9¿@7¹>/¹<*¹<&¹<(¹:'¸9(º;*À>0ÃA4ÉD;Æ@7É@:ÑFCÕIHÖHGØGJßIKæFHèBDíDIõLSüQZûO]ûL]ûK`öD^÷DaùFfýIlÿNuÿOxÿOxÿPw÷VxóUvôTvüYxÿ]{ÿZwûQkòI`ýWköUgêM^ö^mâKZæTaåTa×XaÁefȃ~嫧ÿÔÑÿëèÿóòÿøùÿþÿûüÿûüÿûüÿüüþüúýýùúý÷÷ü÷ôÿú÷ÿûøÿüûÿûúÿøøÿóóýîñúëîðáäéÝÝäÙÕâÙÒæßÕëçÛñíáññåìóìÛæâÎÙÕ@=6=:3:7074-52+52+52+63,74-74-96/;81=:1?<3@=4B>3JB7MC7RF8VJ:WK;XL<WK?TICSJM^Xfpmˆ‚„«‘—Ëœ¤ã£­õ§°ýª±ÿ¦¬ú¡§ó ¤îŸ£ê¡á™›Ö•–Ì’’ĉˆ´yyŸji‹`]|XUpRPhOMeNJcKG^FBS@=H?:>?:6@<1A>/C@/CB0BC3BD7?D=>D@<ED;BJ>CVCIaLRhU\o\br`dobbjd`afXWaJDlG>ƒSE•XF“J7‘@+™>+¨A.®@/®A-¯@-°A.´A/²=+°7&µ7(¼8+Â8+È8-Í6-Ñ7/Õ81Ø;4Ò72Ð72Ð72Ñ82Ô94Ô94Ó83Ó6/ÞA:Õ8/Ñ3*Ö8/Þ=5Þ=5Ú91Ü5,ç2)ë0'ï0(ñ0)ô/)÷-)÷,(÷,(÷-)ô/)î2)é4)á5'Ú7&Ô7$Ï8#Î7"Ï8%Î7$Ï6&Ð7)Ò9+Ñ7+Î4*Ë4+ãNGód\ë`YÕOFÄA7º;2µ9-¸>)¸>'¹<&¹;%º9&½9*À</Ä>2ÊD9ÊA9ÎE?ÕKHÓLIÎGDÍEEÖHGãIIæCDèEHòMSøSZùR\÷O^úOaôH^õG`øGdûIiÿNrÿQxÿRyÿTzðUuïZwù^}ý^|ùUpõMgùOiÿYnÿ[mÿctðM^÷TeôO`üUgõL_äR_À^_»vqל˜úÉÅÿåãÿíëÿôôÿÿýüÿÿûÿÿûÿÿûÿþýýýýüúþùöýøõÿøõÿùöÿúùÿúùÿööüððøéìôææëÝÝèÚÙäÙÓèÞÕðèÝùóåÿúìþþòôúöáëêÓÝÜB>5A=4@<3>:1<8/:6-84+73*62)62)73*84+;60>93A<6E>6I@7MC7RF8UI9WJ:XK;ZLA[NHTIMXR`gd|~§’Ê— ãžªö¥°ÿª³ÿ«²ÿ¬´ÿ¬²üª±ùª¯ó¨¬ì©«èŸ¡Ú™šÒÁ±tr¡he’]Z‡XR~XQzYQvVOnMH_C?M?:@?;:B?8>>4@B5BE:?D=<B>:CB>FH?LUDVnQfƒarŽisŽtvx„o€€^lŠ[c’WYžWU¦VM¦M?Ÿ@.œ9$ :$§<(¬=*®?,±@.³@-´?-¶=,¹;,º6'¾6(Ä6*Ë7-Ñ7-Ö8/Ú91Ú83×84Ø95Ù:6Ø93Ø61Ø61Ú83Ý:3æC<à=6Ú70ã@7þ[Rÿlcÿ]Tç?6å3)í2)ñ2*ô/)ô*&õ(%ø(&ø+(÷-+ó0,í2+ã1'Ú0#Ô1"Ô4$Ó:(Ì;&Ê<(Í<)Ï<*Ò:,Ò9+Ò8,Ñ7-Ú@8Ï81ÜGAôc^åXQËB<Å@;·4*·:&¶<$¹<&º<&½:(¿:+Ä<0Æ>2Ç>4ÌC;ÙPJßXRÔOJÃ?:À?:ÏHDÞHGâGEæJKïPTñRWïNVíKXñL\ùRføOf÷Ke÷JfüMlÿQsÿRvýRvôWvîXuõXuû[wÿ\xÿZsÿWnÿVkÿbuýVgÿ\mÿ[lñFXôDXÿQeîVeÆfgªieʋ網øÒÏÿëçýïîüø÷ùýüùÿÿùÿÿúÿþüþýÿþüÿûøþöôþùõÿû÷ÿùöÿöôÿööÿõõöèèæØØãÕÔÞÐÍáÖÐñçÞüôçþøèÿüéÿÿóúÿùèñðØáàC?6B>3A=4?;2=90;7.:6-95,73*73*73*84+:5/=82@;5D=5H?6LB6QE7TH8VI8WJ9YK>ZMEUJNWQ_eby{¤ŠÉ”⛦õ£®þ«´ÿ¬µÿ®¶ÿ¯·ÿ°·ÿ¯¶ü¯´ø¯²õ©ªë¢£ã˜˜ØŒŠÉ€»uq®ie c^˜`WŽ`Vˆ]TVPtMIbFCTBAIAAC<<:AB=FEACD?A?@DBEOMRWVdch†quš}¢‡}Ÿ’}œ {š¥pŠ¤`u¬Yi¶VaºQU¸HF°@4¬;)¬<&­='¨8$¨7%«8&®9(°8'²9(µ7(¸6(»3%Â4(Ê7-Ó:2Ù<3Þ=5ß<5ß<5á>9ß<7ß<7á>9åB=èC=çB<æA;å@:æB9ä@7Ü8/Õ1(Ø6+ëI>ÿ[Oñ@6î6,ê+#î)#ø-)ÿ/-þ,+ö((ú0.õ4/ï61ç6.Þ3)Ö2&Ô2%Ï6&Ë:'È;'Ê<(Í:(Ï9*Ð7)Ñ5)Ð4(Ó9/Ï5-Ô=6åPJåTQÛLHÍB?·1(¼;(»=&½<'¾;'¾9(À8(Â:,Ä:/È>4ËB8ÕOFÜWPÒRIÃD=¿C;ÌHCÛLHßJFåMLëSRíTWëPVéNVìOZ÷VføUhùSiúRküRmÿSqÿStÿRuòMmøUtÿ\zÿ_{ÿ\vÿUoûRiûReüUf÷RbÿZhÿZhóN^øScþYißS^¶`_—^W¶}Ù©¥îÈÅýáÞùééýøõúüùùÿÿøÿÿ÷ÿýúþýÿÿýÿûûÿ÷õýøôþùõþùõþöóÿ÷öÿõõöêêêÜÛäÖÓÝÐÊßÕÌïåÛüõåÿùçÿýéÿÿïúÿøèñîÛáßEA6EA5C?4A=2?;0=9.<8-;7,84+84+73*84+:5/=82?:4C<4G>5JB7ND8RF6TG6WG7YI<YJCWKKXP]b^ysuœ…ŠÂ™Ü˜¤ð «úª³þ­µþ¯·ÿ±¹ÿ³ºÿ´»ÿµ¹ÿµ¹ÿ¯²ù¬¬ô££ë™—àŽÓƒ€Çxu¼sm³k`¢i]›cZ‘]W…VRwNKhEDV@@L85<A<@KABL@BQ>BZEJpW]‚cs˜r—¥z§®«²{£¸vœÀp“ÂcƒÀTnÂG\ÐK\ÑHPÄ<<º5.¸9*µ<'°<%°;'°;)²:)´;*·<,»<-À<-Ä<.Ä6*Ë8.Ó<1Ù?5ßA8á>7à<3ß:4Ü71Ù4.Ø3-Þ93æA;ìE?éB<ä=5ã<4Û4,Ø4+Û7-Ô2'Ì, Ö6*éG:õK>ò@6ï4-ð-)ö,*ú,,ü,,ø*,ð*)ì/+è2.ã5.Ü4+Ø1(Õ1'Ñ3'Í7(Ë:)Í:(Ð:)Ò;*Ó:*Ô8+Ô8,Ñ4+Ö<4Õ:5Õ<7åONíYWÙEEÂ3/À;,¿<(À;*¿:)Á9)À8(À8*À8,Æ=3ÇA6ÏJAØUKÒRGÆG>ÀD:ÇG>ÖKDØICÝLIäSPåSTâPSâMSåNWòXdöZhý[pþZrüVnúRlûQlÿQpýGmÿPvÿZ}ÿ[{ÿVrýTkþWkÿ\mûYhøZhûamö`kí]gïfnìfmÉ\_ ]W{OF˜mfÁ˜”ݺ¶ðÔÑôàßÿõôùù÷ùÿýùÿÿ÷ÿýúþýÿÿÿÿýÿÿøùüùôüùòüùôýøôÿùöÿøöùîìïäâåÚÖÛÐÊÜÒÈîäØýöäÿûèÿýçÿÿíúýôêðìÞãßIE9HD8FB6D@4B>3@<1?;0>:/:6-95,95,95,:5/<71>93@;5E>6I@7LD7OF5RE4UE5WG8WI>XMKXNW^Zqpp–€†ºŒ–Ô•¡é©õ¨°ù©±ù­³ý°·ÿ±·ÿ²¹ÿ´¸ÿ´¸ÿ¯±ü«­ø¥§òŸžê—–⌋ׂÍ}yÅum¶pgªf`ž_ZYX„QQuGGcA>Q=5DH8BT=C`@EnCJ€OU–]d«fx¿kÉnšËo˜ÉiÈ`ƒÉWxÆIgÄ;UÆ2HÙAPàEMÑ;<Æ71Ä?0½@,±:$­6"­5$®5$³5&¶7(¼8+Ã;-È</Ó@6×@7Ú@6Ü?6Þ=5Þ93Ý6.Û4,Ó.(Ò-'Ó.(Ø3-á:4ã<4á81Ü5-Ü5-Ð,"Í)Ù7,âB6Ü?0Ð4%Ë.éF7óI<ýH?ü<7ô-*ñ#%õ')û/2ñ-.ë/.ä2.Þ3,Ú1*×0*Ö/)Ó0'Ó7*Ò9+Ö:+Ø<-Ú>/Û?0Ü@3Ü@3Ò6*æLBåJEÎ50ßGFóZ\ßIKÕA?È</Ä;+Ã:*Ã:*Â:*Â:*Á9+¾9*Â<0Â>2ÈF9ÏOBÎPDÆH<¿C7ÁC7ÎH?ÑF?ÕJEÛPKÝROÙMLÚKMÜKPëX`ó[güaqÿauúXmõOgõMgÿNkÿOuÿRyÿUwÿTqüTmý[pÿcuÿjxÿguúboõamídlãflÙhjÎghµfa^TeG<^U©ˆÍ«©åÇÅïÚÙÿóóùøöùýüøÿÿ÷ÿÿûÿÿÿþÿÿüÿÿùúþûöûûóûúõþûöÿýùÿûøþôòøíéêßÙÞÔËÝÓÉíæÖÿøåÿþèÿÿæÿÿëøúïêïèãæßNH:MG9LF8JD6HB6F@4D=3C<2?80>7/=6.=6.=60>71@93?:4C>8EA8KC8NE6QD3RE2VF6VH;ZMGVMR[Whlk‹~‚±Š“Î’Ÿãš¦î¦®÷©¯ù­°ý¯³ý°³ÿ°´þ°³ÿ¯³ý«®û¨«ø¤§ô ¢ïšœé“•âŠŒÙ†…уÉ{u»mk¬dež_a’Y[„RQsNHbWFY_CQmBLEM˜MT¬U]¼[bÊZhÙRpâRußTuÙPlÒJbÍBWÇ8JÅ.?Ô8EãCKæGKØ>>Í>6ÌF:ÃH6¶?+·>-¸=-º<-½>/Ã?0ÊB4ÐD7ÕE:ÙE9ÚB7Û>5Ù;2Ù6-Ù5,Ú3+×3*Ô1*×4-Ú7.Ý90ß80Þ7/Ý6.Ü5,Ö/&Ù5+×7+Ï2#Í1"Ò9)Õ>-Ô;)Ø<-æD7øJAýD?ù64õ*-ö*-÷/2÷67í55â30Ú1,×0*×/,Ù0-Ù0+ã81ä91â:1â;2à<0ß=0Ü?0Ú>1Ñ7+ïWLøaZÓ;6Ñ;:æPQÜFHæPQÏ<4Ê:/Æ8,Å9,Ä:-Ä<.Ã;-À;,¾:-¾<.ÃA3ÇH9ÇI;ÂD6¾@2¼>0ÉF<ÊE<ÎIBÕPI×RMÕNKÓKK×LOéZ`ð^hüfrÿhxü]qòPeóMeýNkÿVzÿTxÿRrøTmö]qûhxûjw÷erüetó_mì`kêkrßruÃjfªd\žla}fVXH9kXJ”|r½ œÞÂÁîÖÖþîïûõõûûûûÿÿùÿÿýþÿÿþÿÿûÿÿúýÿþùûþõûüöÿþùÿÿúÿþúÿûõÿ÷òñèáäÜÑáÙÌðé×ÿúäÿÿæÿþåÿÿê÷ùëíðçèéáQK=PJ<OI;MG9KE9IC7G@6G@6B;3A:2@91?80?82?82A:4@;5B?8EB9KE9MF6PE3RE2UF3UH7YLCUKLZScii…|«‰“È“žÞš¤ë¦¬ø©¬û¬­ý­°ÿ®±ÿ®±þ­°ý­°ý©¬ù§ª÷¤¨ò¢¦ðŸ£íšžè•™ã’”Þ’’Ú‰ŠÍ|€Àsx²ou©mpigŽj_}y_x‚WjŽP_£O\»S\ÍT]ÖPWÛHRå@Qè?RäCRÜDPÖCKÏ@DÊ9<É46äJLçIJáAAÕ74Î95ÎA8ÈD8¾>1ÃE6ÃE6ÅF7ÉE8ÎF8ÑG:×G<ÚG=Ö>3Õ;1Ö8/Õ4,Ö3*Ø4+Û4,Ú6-Û81Ý<4à=4ß<3Ý90Ü5-Ü5,Û7-Ò.$Ý;0Ú=.Í1"Æ-Î7&Ò=)Í:&Ì9'Ô8)â:/ó=9ÿ@@ÿ<>þ37ó,/ê,.á+*Ø*)Ô+(×/,Þ44ä88é99ï75ð74î73è71ã7-Ü6*×5(Ñ5&Í5(çPEÿmcÛHAÈ42×CCÓ>BêVVÙA<Ò>4Ë8.Æ6+Æ:-Æ</Ã>/Á=.»9+»<-¾?0ÀA2¿A2½@.¼=.»<-ÃC6ÄD9ÈH?ÐPGÓRLÐOIÒNLÕONé^cîagûitÿnzÿduõVjõQiÿUoÿWvÿVtúXpñ^pônyöw€íksÞXañ`mñ`mìboïs}숊Ì|ªth™yjskXON:_VGƒqg¯–’ÜÀ¿ïÕØüéëþôõýûüýþÿúþÿþýÿÿýÿÿûÿÿùþÿÿûùÿõúýöÿÿúÿÿúÿÿøÿý÷ÿþöùðçíåÚéáÔôïÜÿûåÿþåÿÿãÿÿèùúêòôçîðåSM=RL<QK=OI;MG9KE7JD8IC7E>4D=3B;3A:2@93A:4A96@;7A@;CC;IE9MG7OG2RF0UF1UH5WK?RHFXR^jg‚}§‰“Ä’žÚ˜¢ç¤§ö¦§ú«©ü«¬þ¬­ÿ­®þ¬®û¬®û¨¬ö¦ªô¤¨ñ£§ð¡¨î §í¤è›¢æ™žâ’šÛ‹“҆ʃ„ˆ·ƒ¨ˆyšmˆšcz©Xi»Q_ÏMYàIRèAIê=Aé=;ã>8ÝC9ÖH:ÎI8ÅF3ÂC0Å@1äTIàG?Ú;7Ø64Ø88Ø:;Ñ98È74À:/¾<.¿;.À:.Â8+Ã7*Æ4'Æ2&Î4*Ð3*Ñ3(Ô3)Ö3*Ù5,Ý6.Ü8/Þ=3Û=2Ü;1Û8/Û7-Ú6,Ø4*×3)Õ3&Ó3%Ð4%Ï6&Ò=)Ñ>*Ê9$À2È:&Ê4%Õ1'ç51ú<<ÿ=@ÿ7=÷37ê-1á-.Ù--×/.Ü43ã9:é;=ð9=ö26ø03ô01í1/ä1*Þ2(Õ1%Ï3$É1$Ñ=1új_äTLÈ95Ð@?Ë:=äRSäJHÜC=Ñ:3É6.Æ8.Å;0Â<0¿=/º;*¼?-½@.¼?-º;*º;(½;+¾<,¼>0¼>2ÀD8ÈLBÌPHÊNFÌLIÐNLèaeìaføhrÿo{ÿhx÷Zk÷UjþZrÿYsû]tîaræjtë}€ñ‡‰èwyÚ_dñgtþm|óeuëlwö‘•ì¢ŸÄ”Š¢|hjUHQ<WUFth\¤ŒˆÛ¿¾òÕÙùãæÿóöÿúüþþÿüýÿþûÿÿüÿÿúÿÿøýÿÿûùÿõ÷ýóýÿ÷ÿÿøÿýöÿý÷ÿÿöÿùïõïáòìÜúõáÿýçÿýäÿþâÿÿçýþìùúì÷÷ëVO?TN>SK>PJ<OG:LF8LD7JD8H@5F@4E<3B;1B92A:2C:3A<6C@9DD:JF:MG7OG2QF0TH2UH5UI=QGEWQ]jh€~‚¨Œ”Å“Ø™¢çŸ ò£ ÷¦£ú§§ý¨ªÿ©«þ©¬ý§­û¥«õ£ªò£§î¢§ë¤©í¦©î¥¨í£§î˜ è”¡å”Ÿß”Ÿ×•›Íš•¾ Œ¯ªƒ ¥e´]pÂQcÐIWÜBNå>Fë<Aì<<ê?8ãA4ÜE4ÔI4ÊI3ÂF.¿B,Â?-âSEÞD<Ý97æ>>êDFå@DÙ8=Î65ÍB;ÈD8ÉC8ÇA5Æ>2Ã9,Â6)Â2'Æ2(Ë3(Î4*Ó5,Ø5.Ù4.Û4.Û4,äB7Ý=1Ù7,Ú6,ß9-ß9-Û5)Õ1%Ø8(Í2 Ê1!Ï9(Î8'Ç4"Ê7%ÔC0È7&Î8*×6,Þ5.æ3/î53ö:9û?>ÿLKúHFòBBì>=ê<=ç7:å26æ,1ô+1ø)/ô,.ï/.è1+à4*Ù5)Ó7(Æ0!À.ôdYë]SÏ@:ÔDCË;;ßMMêRQàHEÓ;6É6/Æ8.Æ9/Ã;-¾:+¾<,Á@-ÀA.»<)·8%¸9&½<)¾?.µ7)³7+¸>1ÁG:ÅK@ÅIAÈIBËJEåa_æ^`ñdjþnwþkuó]iðXeø]mú^sõbtèdoãlrì~ù‹ö†…éqsøryÿy†õaqàXföˆ‘ÿ´´Ð®¢ ›‡]jPDR9QT?jbU›ˆÚÀ¿òØÙöàãÿô÷ÿúýÿþÿýüÿþüÿÿýÿÿûÿþùýûÿúôÿòòþòùÿôüÿöûýòÿýôÿÿôÿÿóûõç÷ñáþùåÿýçþüãþýáÿÿêÿÿñýýóüüòXO@WP@WN?UN>TK<RK;RI:PH;MC7KC6KA5H@3H>2G?2H>2F@4GC:GE9JG8NI6RJ5UJ4UJ4VK9XNDULMZTbkhƒ{~§‰Ã‘™×˜Ÿç£¤ö¥¢ù¢¢ü¡¢ü ¤ÿ¢¨ÿ£«ÿ¤­ü¡ªõ¡©ñ¡¨ì¥¨íª©ï­©ó±©ö¬©ø ©ø—§ò’¡â–ŸÖ¦£Î¶ž¾¹…œ¸gz¿L]ÑERß>Mç;Gç<Dæ=Bà@@à@@â>?ß<=ÝEBÉ:4ÊD9ÊF:º1)ÛJEèJIéCEë>Bè;?æ<?á=>Ú<=Ô<;ÏB;È?7ÊD;ÑMAÍK>¿=0¸6)½9,¿7+Ã6,È5-Ë2*Ñ/*Ô/+Û2/Þ5.çA5ß9+Ù1$Ý3&å9+ç;-ß8&Õ2Ï2Ì4Ê5!Ç4"Ç4"Ê4%Í5'Ï5)Ê0&Ï2)Ñ5)Ò6*Ò4(Õ3&×3'Ü4)à2)æ3.ë52ë33é/2ç-2è-4í.5ö-3ö+/ï+,ì/-ê5.ã9,Ù7(Ð4%Ã-Ä3"çXHéYNË;3ßNIÅ41ÚHHáOPÜJJÔC@Ì;6È80Æ8,Ç9+È<+Å<*Â;(¾9&¼;(»<)º=)º=+·<,´8,µ;0¹=1»?3»?3¾@4À@5ÄA7ïjaõpiêc_ômjûqqìadôgmÿpyÿlzûhxðdoébiëdjîlnîqoîqoûy{ÿ}…ùZlücwßbpû¬¯¶ªš}‘u]rQJY:LR8snZ¥•ˆË·°íÕÓÿîðÿö÷ÿ÷ûýøüüüþþÿÿþÿÿÿþÿûÿþðÿôåþéæûêïÿîøÿöüÿôþÿóÿþñÿýñÿûîÿúêÿùæÿùãÿùáÿùáüúåÿÿõÿÿûÿÿûYPAXO@XO@VM>UL=TK<SJ;RI:NE6MD5LC4KB3JA2JA2JA2IA4GC8HD9LF8OH6RJ5SK4VK7TK:XNEULMYUckhƒ{}¦†ŒÀ•Ó–šáŸžìŸñžžôžŸù¢ýŸ¦ÿ ªÿ¡¬û ¬ô «íŸ§è¢¥è¥¤ê©£í« î¤Ÿï §÷š¦ðœ¡á£œÐ±˜À¿ªÂq„ÄTbÑCOâ<Fì8Aï7?ê:=å<?Ü@AÛACà<CÚ9?ÚADË;;ÌB?Ê@=Á31åOPæCFè?Dê;Bç8?â8;Û89Õ:8Ï;7ÔE?Æ=5Å<4ÌG>ÌLAÁC5¸:,·9+¹7*¿7+Æ6-Ë4-Ñ2.Ø3/á53ä84ä>2á;-Þ6)ß5&á5'á5'Ú5"Ó4Ñ9$Ë9"Ç9%Ç:&É<+Ë<,Ì8,Î4*Õ3.Ö5-Ó7+Ï7)É6&Ç4"Ë4!Ï4"Ø2$Þ2&ã0+æ.,æ,-æ,/æ-2è.3ì+.í,-ì0.è2.à4*Û5'Õ8'Ò9'Õ?.»*ÖD5Ð>1ÙF>ëVPÚB?ØBAçUVâRRÜKHÔC>Í=5É9.È9+Ç8(È;*Ä;(¿:'½<)½>+º?-¹@/¶>.²:,´;0·=0¸>1º?0½?1ÁB3ÅC5ëi\òmdçb[ðkfõolèbañklütxÿq~ÿo|öirí]fêY`ñbf÷qpþzxûvwÿx~ùRdþ[pä]nö¦©©¦“jŒkZtON_;SZ;us\©ÖĸöáÜÿõñÿúúÿúûÿûüüüüúþýûÿþúþÿõÿúíÿóáÿéáýæéÿëóÿñøÿòýÿòÿÿñÿýïÿýíÿúéÿöåûóàúòÝüôßü÷äýúóüüúÿÿý\PB[OA[OAYM?XL>WK=VJ<VJ<SG9RF8QE7OC5OC5OC5OC5MC7JC9JF;MG9PI7SK6VK5VK7TK:WMCVMNZWbkiy{¡…‰¹‹‘Ë‘–Ö˜˜Þ™™ã˜™éšî› ô£÷Ÿ§ø ©ô ªï¨èœ¤ãœ¢àžŸàžá™ã›™â–›ßššÚ¤•Ð±ŒÀ¿‚¬Çr“ÉYqÇBS×ALß>Dã=?å==å<?ã=?á>Aá>Cà<C×8=Õ?AÏA@ÊC?Ã<8Ä96éWWàBCä>Bè;?ã9<Ü68Ö66Ñ96Ì;6ÕHAÄ;1¾5+ÅA5ÍK>ÆH:»=/·8)º6)¿7)Ç7,Ï6.×50Þ71æ95é=9×3*×5*Ú6*Ü6*Ý5*Ý7)Ú:*×>,Å4!¿4¹4!¹6"¼8)½8)½3(À-%ã@;å>8Þ=3Õ<.Ì9)È7$È7"Ì7#Ò7%Õ3$×/&Ù.'Û.*Ü.-Û//Ü./Û,)ß0+à5-Ü5,Õ3&Ð4%Ð9&Ñ>*ÔA/Â1 çSEÒ;0ÚA;ÞC?èJIðTUíUTçSQãOMÝJCÖC;Ï<2Ê8+Å6&Ä7&À7%¼7&¹:'¹<*·>-µ=,²=,°:,±;/´<.µ=/·=.¹?0¾C4ÃE7Ü\Qêg]äaYðlgöpmça`ìfgójqàR^ï^kõhqòemñ`gôeiùqqþxwútuÿnuóJ]øRhä[mñœ¡£œŠa€`UoHOd=W`Aww]­¥’áÑÂÿîæÿøñÿüøÿþúþÿúûÿüûÿýûÿýùÿûóÿöèÿîÜþãÚøÞáùáèûåïüèöýëýþìýúéÿúêÿ÷æúñàôèØòçÕöëÙøñáþúñýüøÿþû\PB\PB[OAZN@YM?YM?XL>XL>UI;TH:SG9RF8RF8RF8RF8PF:LE;KG<OI;RK9TL7WL6WL8WK;VLBUMK\V`jh~yy›‚…²ŠÂ”Γ•Ò•”Ö••Û–˜ã˜›è˜žìš¢í›£ëœ¥è˜¢ß–ŸÚ•›Õ”˜Õ“—Ö’“Ö‘Ò…„½‘ƒ¶¥}±·s¢ÈfÒVzÕGaÔ<KÞAJàBCÞCAàB?áAAä?Cç>Eç=Fã?FÖ:>Ñ?@ÑEDÆA<º61Å>:êZYÝABã@Cæ=@ã:=Û89Ó97Ð<8ÎA8ÏE;Â:.»2(À</ÇE7ÄE6½>/¸9(½8)Â9)Ë8.Ò:/Ù80à91è;7ë>8Ø1+Ù2*Ü3,Ý5,à5-ß7.Û9.Ö=/É7(Æ:)Á<+¾<,¿;.Á;0Å<6Î95ëC@í@<ä@7Ù=1Ï9*Ç9%È:&É;%Ï<(Ð7'Ï1%Ñ1%Ô1(Ö3,Ô1,Ñ/*Ó2*Ó5,Ó7+Ð7)Í5'Ê7%Ì;(Ì>*Ì;(Ï<,ô^PàF<Ò3/Ò.,æ@@ûWXÿusÿroÿjgö^YçPGÕA7Ç5(½. Ä8'À8(»8&¸;)·<,µ=-²=,°<-¯;.­<.°</°<-±;-¶>.¼B3ÀF7ËMAß`Wâa[ôpløtræ`aä]aæ]dÖHTçYeógrôgoöelükpþsvþvvûpsûenñDXôKbåXkë’– •ƒ_zYQlCSh?\gEy|_°ª”çÜÊÿõèÿùðÿûñþþôýÿ÷ûÿúùÿúöÿøòüóêûëÚøÞÎóÒÊëÌÏìÎ×îÒàðÖéóÛò÷áöõáûöãüõãõìÛíáÑéÝÍíáÑñèÙüõíü÷ñþùó\PB\PB[OA[OAZN@YM?YM?YM?WK=VJ<UI;UI;TH:UI;UI;SI=OG<OI=QI<SL:UM8XM7YL9XL<UKAUKI\U]hexut“|~¥…‡·ŒÂŽÃȒϔԒ•Ü“—à”˜ß•šÞ•Ü’›ÖŽ”ΉDž‹Å‡Ã}ƒÁ~¸}tŸŽp”¨gÁ\„ÖNvâAcè:Uê9KæAGàECÜGAÛGCßEEæAGî<Jí=JæBI×>@Ð@?ÐIE¿>8³2,ÈC<àUPÜDCáACã?@á>?Ú?=Ô@<ÑD;ÏF<Ç=2À8*½5)½9*¿=-¿=-½;+½<)Â:*Ç;*Ï;/Õ;/Û8/à8/ç83é:5æ95ä52ä20æ21ç32æ40Ý2+Ô0'Ë1'Ë7-È:0Ä7.Á4-Ã40Ì:;Ý?@ë8;í76ä71Ø5,Ì4&Æ5"Ä7#Å:%Ë=)Ë8&Ì4&Î5'Ô8,Ô:0Ó9/Ð8-Ð>1Ê;-Å8'Ä7%Æ9'Ç<)Ç<)Ç:(Í>-Í:*Ø>2áC:Ô/-ä::à24ß56×53Ö;6ÞC>åKCêQIêSHèTHäUGË?0Ä?.¾<,¸=-·>-´?.°?/®>0¬<.¬<.¬<.¬=,­<,±=.·A3ºD6ÆLAÞbXâc]ðnlôrrå`cå`eç`g÷kvûoz÷kví`hð_fýlqÿx{ÿy|úmsø^jóAWôC]èUh懣“ƒg]YtI^uIhwPˆf³²–èâÌÿúéÿýíÿþïýÿòûÿôøÿôôÿñíûêäòáØî×Åèǻ伺޺¿Þ¼ÇàÀÍâÃØæÌãëÓìîØôñÞ÷òßóêÙìàÒèÚÍêÜÏïáÖòèßñèáòéâ[OA[OA[OAZN@ZN@YM?YM?YM?XL>XL>WK=VJ<VJ<WK=WK=XL>QI>QI>SK>UL;XM9XM7YL9XM;WK?ULGYSWe^nnjƒut–~}¥„…±†‰´‡‰¹Š‹Á‹ÈŽÏŽŽÔÕӔӋʃˆÀ|¸u|²ov­io«ljœ€lˆ“cy®YvËPoãBdð7Vö4L÷8Hï@EåFBÝJCÛJEáGGèCJò=Nð>LäCI×CCÌA>ÎIDº;4°4,ÉI@ÕLFØBAÚ?=Û;;Ú<;Ø@=ÔE?ÍG<ËG:À8*Á8(À8*¾9(¼9'»8&½:(À;(Ä;)Ê=,Ò<.×;.Ü8.á6.ä6/è50é32è./é,0î02õ47õ77î45æ21Ú.*×4/Õ62Ñ32Ï/1Ò/4Û6=ê:Dí06î02æ3/Ü3,Ñ5)Ê7'È9(É<(Æ8$É6$Î6(Ó:,Ú>2ÝA5ÝA5ØA6ÓG8ÉA1Â;(À9&Ã<)Æ=*Å<*Å8&Ì:+Í7)Í0'æC<Û2/ï?Aã/2Ú*,Õ1/Ò5.Õ81Ö90Ò8.Ì5*Æ2&À1#ÎE5ÆA2¼=.µ:*±9)¯9+«:,ª:,«;/«=0¬>/¬<.«<+­<,²>/µA2ÉSGàg^àc_êjiînoæchðjqõoxúq{ýt~ömuîbködnÿrzÿx~ÿquúipøWfùAYô@[êQfá~ƒ¬—†ykmˆ]o‰ZyŠ`—r¶·˜ßÞÂùôÞüúåÿÿïûÿïõÿïïÿëçúäÜïÙÐãÍÅÞÁ°Ö­¨Ó¦ªÐ§°Ó«¶Ô®¼Ö±ÇÚºÒßÁàæÌèêÔòíÚòéØîâÔìÛÑêÙÏìÛÓéÚÓæÙÑåØÐ[N>[N>[N>[N>ZM=ZM=ZM=ZM=YL<YL<XK;XK;XK;YL<YL<YM?SI?TJ>UL=XL<YN:ZM:ZM:YN<YM?ULEXOR_Wbd_sjfsoyy|~¤~€©‚²ƒ„¼††Æˆ‡Ë‰ˆÌ‰ˆÊˆˆÈƒƒ¿|}µvw­pq§kl¤fg l`Ž‚`q•V^³N^ÒJ^ì@X÷6Kþ3Fþ9Có?BéD@áHBÞICâFIéBJò=Nï>NÝAEÔFDÈA=ÉHB´:/±7,ÎOFÉB<Î=8Ð64Ï10Ð51Ó>8ÏE;ÈF9ÃD5¾9(Ã:(Â:*¿:'½8%¾9&¿:'Á:&Ä9&Ë:)Ó:,Ù9+Ý7+á5+ä3+ê3-ë*+ñ*-ø-3ü/4ÿ17ÿ37ÿ38ý58ù8;õ8<ò9>ò9Aô9D÷7Fû6Hþ5Eô+5ô-2í12ã4/Ù6-Ð8*Î;+Î=,Ë5&Ñ8*Ù;/ß=2â>4ä=4å>5ßA6ÙJ<ÏG7ÉA1Ä<,Â9)Â9'Æ8*È9)É2'Ó9/á@8ëD>Þ0/à..ë46è66Ø3-Õ7.×90×:1Õ;1Ò;0Í:0É;/ÖL?ÌF:¿@1´9*°6)¬6(«7*©8*¬;-­=/®>0­=/«<+«<+­<.±=0ÀKAÚdZÞc^èkiðosêinõrzüvîfp÷oyùryöjsþlvÿwÿv}ùhoùcn÷RbþB[÷<YêKaÝt{µš‰žz}˜k{—f‚•h‘u¬²ŽËÌ­ààÄéìÑîöÞåóÙÙíÑÏæÉÅÞÀ¼Õ·´Ë®ªÈ¤šÁ”–™Ó¡È™§Ë¬Ë¡µÎ§ÁÒ°ÎÙ»ÙÝÄåãÎìåÕïáÖëÚÒçÒÍãÐÊàÏÈÚÌÃÕǾ[N>ZM=ZM=ZM=ZM=ZM=YL<YL<ZM=YL<YL<XK;XK;YL<ZM=ZL?VJ>VJ>XL>YN<ZM<ZM:ZM:ZM<[OAWMDWML\RZ^Xfb]qjfspwv–xxœ|{§~µ„¿…‚ň‚ȉ„Ç‚}¿y·zu­xq§vo¥tk¢pg za‹„QZ™HE³EHÓHOîBNø:Fþ6Aþ9@õ==îA=æD?ãEBäCHèAKî=Më?MØ?BÑGDÅA<ÃG?²9.³:/ÑUKÃ>5É83Ç/,Å*&È/*Í:3ÌC9ÃC6¼>/À;*Ä;)Ã<)Á:'Â;(Ã<)Â;'Ã8%Ä5$Ê7%Ô8)Ù7*Ý5*á3*å3)ê2*õ33ÿ58ÿ8<ÿ4:ÿ-2ÿ(-ÿ(-þ+1ü-3ö)0ò&1÷)6ÿ,?ÿ*Aü 9ó/ö"0ó(.í,1æ0/Ú1,Ô3+Ñ5)Ð6*Ô6+Ý90æ=6ë>7ë:4è71è50â92ßH=×K<ÓE7Ë=/Ä6(Â3%È6)Ï8-Î4*Ô6-æC<ß82à21Ò ì89å63Õ1(Ò4)Ò4)Ï5)Î6+Ê6*È5+Å7+ãYNØRFÊH;¾@2·;/µ;.µ<1µ<1¯9-±;/±=0±=.¯;,­9*­9,®:-±<2ÐYQÜb]ìppôvyîmrõq|ör}ÿzƒÿ‰ÿy€ôhq÷epÿq|ÿuÿktø^jöOaÿA^÷8WéG^Ûntº‹™©„‚žn~šg—hœq¡©‚´º–ÈÍ­ÕܽÌÙ»ÁÔ´²Ì©§ÂŸž¼˜š¶–²Œ±†‰³†µ~¹„•À‹œÂŸÄ‘¨Å™²È¡¾ÎªÉÒµÚÙÄæßÍêÞÒéÖÏáÌÉÛÆÃÔÁ»Î½µÈ·°ZM=ZM=ZM=ZM=ZM=ZM=ZM=ZM=XK;XK;XK;YL<YL<ZM=ZM=ZM=ZL?ZL?ZM=[N=]M=^O<\O<\O>YM=WMCWLHXNOZPX]Ub`Yia\rjfokŽsp›vq§{u³ƒ~ÁŠƒÉŠƒÇˆÀŠ~¼ˆy²ƒr¨†r§t«‡l£†\„HL¤B9¶A:ÍC@Þ@?è:;ô<>ÿDE÷><ó=<ì>=ê@AëBIêCMëANãALÐ>>Å@9¾?6·>3°</²<0ÀD8ÒMDÇ61Ô;6Í2.Ì3.ÖC;Ç?3µ6'»>,º7%Á:'Ã<)Â;(À9%Â9&Å:'Ç:(Ë:'Ð9(Ö6(Ø2$Ú."à/%ì7.õ=5õ82÷40÷0-ø**û&(û%'û%'û%'û&*÷!)ø".ÿ'7ÿ(>ÿ!;ÿ6ý1ÿ'8ï#,æ#+ã+-Ý--Ô+(Ò-)Ü41â62è64î66ò65ò12ï./î,,å/,Ü92Ñ:1Ò91ìSK»"Ä+#ßF>È.&Í.(Þ<7èE@â:7Ø/*Ú.*â51å<7ß>4Õ<.Ï5)Ë3&Ì5*Í;.Ë;0Å8.ìbXàZOÈC:¹6,º:/¸8-±3'´6*°0%°2&®2&¯4%°6'²:*´<.³=1°:0ºC;Ö\Wìppñsvöx|ûyƒõq|ÿ|„ýw€út}üs{ÿr~ÿr}ÿmxÿgsü`nôI\ÿ>\ÿ>[äAVÔek´•€’¡zƒm}™f~”c‡—j”Ÿwž¦ ¨ƒœ¨„’£Š£|€Ÿvzšqyšo|r vƒ¤u‚­wƒ³y‹¸‘¼„“¾†—¾‡œ¾Œ¢½§¼“¯½š¾Â§Ï̹ßÓÇãÒÊÜÇÄÔ¿¼Ìº¶Á²«¹ª¥ZM=ZM=ZM=ZM=ZM=ZM=ZM=ZM=XK;XK;XK;YL<YL<ZM=ZM=ZM=ZL?ZM=\L=]M=]N;^O<\O<\O>]P@[OC[NFYNJZPQ\SX_U^_Wfd\tibƒng‘qjxp¬€y¼‡€ÄŠÄ€Á~ºt«Œn¢—q¤¡u¨šjž™W{=Aª5+±5+Â<3Ó@8Ý>8è?:óA=õ=;õ;<ô;@ñ>Bî@IèAIâ@KÚAFÇ<9½=4¶<1±;/«:,®:+½A5ÐJAÚG@ÜA=Ô63Ð51Õ@9ÍC8»9+²5#½8'Â;(Ä=*Ä=*Ä;(Æ;(Ç:(Ê9(Ï9(Ï6&Ô2%Ú2%ã5*ê8.ï80ð91ç1&ç/%ê.%ï,&ö+'û+)þ,+ÿ-.ü*-ú%+ú$.ÿ'7ÿ$;ÿ7ÿ3ü0õ0ö.9õ3<å*1Û(,Ü.0Þ02Û+.ñ:>ô7=÷4:ö26ö/4ø03ù25ô87Û2-Ú;5×82äE?äE?Î/+Ñ2.Á"Ô51á?:èE@à=8Ø3-Ù2,Ý60Ý:1Ô:.Ï9*É5'Ç5(È9+Ê<0Ê<2Æ9/ícYáXNÉ@8º4+Â91Ã:0¿6,Â9/¿5+¾4*½4*»5)¸6)µ5(´6(°6)´;0»B9ÓYTèljïqtöx|þ|„øv€þ|„üyùv~þuÿsÿp}ÿkwüdqý_nöI]ÿ>\ÿ>\éCYÓeh®Žw‰˜oz•bu’\xŽ]cŠ•k˜p‹•p…”mp‡]l‰]h‰\g^k_q•ey›izŸk¬t„±vŠ·|»}¼“¼‚–½†›»‰›µ†¡³‹­¶—¾½¨ÏÆ·ØÇ¿ÖÁ¼Ï¼¸Æ·´º¬©²¤£\L<\L<\L<\L<\L<\L<\L<\L<ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<\L=\L=]K=]M=]N;^O<^O<\O<_RA]QA\PD[NFZOK[PN]QS]RZ_SgcXvh]…kb‘sk¤vµ†}¾‰}½—…Á™€·›v©žpž®u¢ºv¥µi˜±Rt¸<D¾5-º4+À<0ËC7ÓE9ÛC8ä?9ñ=<÷:>ù:Aö=Eï@GæAHÙ@EÏ@BÀ;6¸90±9+­9*©8(­9*»?3ÏF<ÙD>×96Ù74Ú;7ÜC=ÝOEÎH<µ3#¾9(Á:'Ä;)Æ=+É=,È<+É:)Ì9)Ï7)Ï2#Ó/#ß4*î=3ô?6ñ91é4+à4&ß5&â2%å/$ë,$î+%ñ+(ò+(ó+-ð(+ò&/ø(6þ%:ý7ü3ø3ô%7ò0;ó5Aò8Cð;Dð<Eé5>ä,6ð2<ó/;ö.9ö-7õ.3õ.1ó/1í42Ü0,â=9Ú64ß;9ÿmjåCAÑ/-Î/,Ù:7ß@<àA;Û<6Õ7.Ö5-Ö5+Ò6*È6'Ã6%Â6'Ä8)Å;.Æ<1Æ<1Å;1ë`YáTMÉ<3¿0(Ë;3Ñ>6Î;3Ò=6Ø=8×<7Ô=6Ï<2É;1Ã9.¼6*¶6)¹;/¼@6ÏTMãgeíorøz~ÿˆû|ƒû|ƒûyûx€ÿwÿsÿn}ÿgvû`pü[mõG^ÿ<Zÿ>\ìFZÎ`až~ev…Zi„Qh…OmƒRt…X{ˆ]}ˆ^x„\q‚X`zM_Pa…UeYn•`uœg} j~£mƒ¬r„²tˆ¶x‹¹y‹¹y¹z‘º~”º“±•¬€›©†©­’ºµ¢Ç¹®Ë¸²È¶´¸¬¬ª¡¢ —š[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]K=]K=]L<^M=^M;^O<^O<^O<^Q@^Q@]OB[OC\NE[NF\OI]OO^P_bTmdY{i^‰pgœ|t­…{·ˆ{³™…º¥…´¯€ª¸z¡ÆxŸÑuœÌcŒÈMlÜFRßA@ÕA=ÏE;ÌH;ÍG;ÓE9ÞA:î@Aõ<Aú=Dø?GðAHâAFÒ@AÆ?<¿?6¶<1¯9+«:*ª9)®8*¼>0ÎD:Õ<7Õ31à;9åA?áD?èSLßUJ¿:+Á9)¾7$À7%Ä;)É=,Ê=,Ë9*Î8)Í4&Ò2&Ù2)å9/ñ>7õ>6ð5.ä/&à6)Þ6)à4*ã1'ç.)ê-)ì*(ì**ê),è',ë'1ò)9ö&<÷!;û=û%Aû6Hä(6ç.<ÿP\ÿ`lÿP\ò<Ió9Gè)8í*8ñ-9ô0:ñ27ê01á+*×(%Ø0-Ú72Ô2/åC@ÿspõVSÝ>;åGDÛ=:Ú<9Õ:5Ò80Ñ7-Ð6*Í4&Æ3#¾5#¹6$»8&¿;,À</¿9-À:/Å<2åXQÜMGÊ70Ç0)×<7ÞA:Ú;5ß<5ç>9é=9æ?9á@8Ù?5Ð<2È:.Á9-»9,»=1ËNHàc_ìnoú|ÿ„ˆý~…øy€øy€üyÿx‚ÿt‚ÿn}ýetù^n÷VhóE\ý8Vÿ<ZîH\ÇYZŠlRcrG\tB\yCdzIl}PtVvƒXrXoWm‡ZlŽ\o•buh{¤l¨o„ªq…«p…­q…±tˆ´u‰·v‰·v‰·v‹¸w¹z‘´|«{’¤|›¤…­«–¾²¤È·¯Ç¸µ´«®¡ž¥—’™[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]L<^K<^K<^M=^M;_N<^O<^O<^O<^N>^N>\O?^NA]OB^PE^OJbNYbQdcTqdZ}le‘xr¢w¨ƒv¤”}§¬†«Â‰©Î‚žÚw”ál‰ÛXwÚD_óBTúDPïJPáIHÐE>ËE<ÐF<ÙD>èBBð@Cõ@GõBHíDGßCDÏA=Â?7¿@7µ=/®:+«:*ª9)®8*»;.Ì?6áFAâ=;îBBëAAÞ;6ãJBæXLÕK>È@2À8(¼3#Á8(È<-É:*Ë7)Ð8+Î0%×3)à8/é;4í:5í60ë0+å,'ã0,ã1-ç10ì31ó25ö37÷48÷6;ì-5ê,6í.=ñ0Có-Fö)Gý+Nÿ3Rô9Lå3?ð@Mÿ_lÿlzÿWfõCSõ>Pî3Dí3Aí3>é6<ã99Û83Î4*Ç/$Ë2*Ç.(Ð72òYTö\ZòXVÛA?âHFÜB@Ô<7Î70Í6-Ï8-Ï9+Ê7'Â5#¹8#³9$µ:(¸=-¹;,¶6)¼7.Æ=5ÛNGÙEAÎ50Ð1-á>9ç@:ã81ç51ë20î21ë52ç83á:2Ø:/Ð9.È:.¾6*º8+ÈIBÜ_Yënlû}€ÿ…‰ýƒõv}öw~üyÿx‚ÿsƒÿk}ýdvù^pôSeôF]ý8Vþ=ZïL]ÀTRz_BWh<Yq?[vCfyKn~QtVx…Zyˆ_wŒay•exšhz m|§qªr„«r…«p†©o‡­rˆ°t‰³tˆµt‡µt…·r‰¸t‹¸w¶{Ž¬xŽ£x™¤‚­­•À¹§ÎÀµÒÄÁ¼¹À¨ª¶œœ¨ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:[K;[K;\L<\L<]L<^K<^K<^K<_L=^M;_N<^O<^O<]N;]N;^O<_O?_O?`P@aQAbPFbNPcN]_Pe`Usga…to—{t}q—v–®ƒŸÌ‹¡Û‚–ær…ëduéPdé;Rù3Lÿ<QûERéDKÕ?@Î@>ÑC?ÖEBãEFèBDîAEíCFçDEÚEAËB:¿?4»?3±;-©8(¨9(ª9)°8*¼:-Ê;3èIEé??ë=>å78Ú2/ÞA:îZPôh[ÚPCÉA3¾5%Â6'Ç9+È9+Ë7+Ò8,Ñ0&Ú6-æ;4é;4ê40è/,ê-+ë--ó49õ3;ø3=ü3=ÿ1>þ0=ý1=ù1>õ0Aò1Bô4Kõ5Nõ0Nö-Oÿ1Xÿ>_æ3HùO\ÿanÿ_nÿWfûP`ôDXé8JóAQê:GÝ2:Ò/2Ê2-Â8-½;+¼:*Ä:/À2(ÙJBúkcÝLGáPKÏ;9Ï;9àLJÔ@<Ê70Ê7-Î</Í<+Ë:)Ä;(´;&­:%¯<)³>-±9)¯3'º:/ÊD;ÖGAØC=Ô72×2.ç;7ì:6è2.í2-ò,-ô,,ò./ï31è71â:1Ú<1Ò>2Â6)º4)ÅB:×XRçjhú|}ÿ†‰þ€„õv}÷xýz‚ÿx‚ÿqÿi{ûbtø]oòQc÷I`ÿ:Xý?[ðO_ºQNqX:Sf8]uEa|InSv†Y{ˆ]~‹`g‚—l€œl}Ÿm|¤o}¨p€©o‚ªnƒ©l…©lˆ«qˆ®qˆ°r†³r„³oƒµp…·r‰¸t‹µv‰¬tŽ¥wš¨„°´™ÈïØ̾ÚÑÌÂÂÌ«±Á›¡±ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:]L:^K<`J<^K<_L=^M;_N<^O<^O<^O:_P;`O;aP>aP>aP>aP<bOAeMMdMW`O_aUmgb€uq’|v˜€s‘uŽ­€”͆”ß~‡îqyùclúP[ú;Mÿ*Fÿ2Qÿ<Sñ<Mà<E×@EÕCDÔBCÜCEàBCäADâBDÞDBÔC>É@8¾>3¸>1¯9+¨7'©:)­<*´<,Á=1Ï?7ß=:å99ã03â/2à42Û94æMEülaòh[ÙQCÆ</Æ:-È:.É7*Í6+Õ8/Õ4,Þ7/æ93è62é1/è/,î1/õ15ÿ2Cÿ0Eÿ-Fÿ*Bÿ%@ÿ#=ü 9ö 8÷'Aõ+Eõ.Mõ/Pó+Pô)Tÿ2`ÿAhóCXÿ`mÿhuøVeíKZñL\ëBUÚ2Cë@RÝ7CÉ-1º((±.$«8&¥?&¨@'¸?.¼:,ÝYMá]QÍG>ÍD>Á63É;7äUQÕF@É91È8-É:,È9(È9(Ä=)±?'¦<&¨;&¬=*«7(¬3(¼=4ÓLFÖGAÝE@Û96Ü30é73ì51ë0+ô1-ý,/ÿ+-ú./ô1/í4/æ81ß;1Ø>2É9.½3(À;2ÏNHáa^÷yzÿˆŠÿƒ‡ùzû|ƒÿ{†ÿx„ÿn~þew÷^põZlëL`õIaü9Wû=YîM]²JGhQ1Qd6\tDf~Nuˆ[Žc„h†’jˆ—n‰žsˆ¤t„¦t§r}¨p¨n©mƒ©l…©l…¨n‡«n…­o…¯o°l€²k‚¶n…·r‡³t‡­t§wœ¬…²¹šÈƯ×νÙÒÌ»¿Ê¤¬¿’š­[J8ZK8[J8ZK8[J8ZK8[J8ZK8[J8ZK8[J8[L9\K9\M:]L:]L:^K<^K<^K<^M=^M=^O<^O<\O<`Q>aR=aR?bQ?bQ?aP>aO;bL>hOKgNRbP\cWkjfuv”}|œx—‘z–«•Æ„’Ú}…ðuzþlmÿY[ýDLþ/Iÿ5Rÿ<Uó<Né?LãCKÝBHÖ=@ÛACÜ@AÞ@AÛA?ØC?ÐA9Ç>4½=0µ?1¬;+©8(­<,´?.»@1ÊA7ØC=Ù74á85Þ..â30æ:6Ó0'Ï5)ëUGÿwjë[PÑC7Ê<0Ë;0É7*Í6+Ô:0Ú70ß82å63ç32ê01í12ô36ý4<þ%6ÿ#9ÿ"9ÿ"9ÿ!8ÿ6ý5ø6ï2î9ð%Bï(Gî&Jñ'Mÿ3\ÿEhÿbuÿ`l÷WcñQ]òP]ïMZâ@MÔ2=Ú=FÌ7;»/.®/(¦5'¢;(›?&œ>%ª9'²8+ÒVJ»;2Ä?8¾41½2/ÎC@åWSÕHAÈ91Ä6*Å6(Ä5%Æ5$Ã:(±<(§:&¨7%­9*¬4&¯1%Â?5ÛRJÙIAáHBÞ;6Þ2.ê41í1/ï-+ü22þ,/ý+.ù+-ó++í-*æ1*ß4,Ö8,Ñ=1¿2(¼7.ÈIBÙ\Xówwÿ‰‹ÿ‡Šû€…þ†ÿ}ˆÿv„ÿj|þ_s÷XlöTiêD\õD^õ6Uñ:VàLZ¥HC^K-Mc5Uo?b}JtŒ\€–g‡˜lˆ›nŠ r‹¥vŒ¬z†«wªr~§m|¥i}¥g¥g‚¦i‚¥k‚¨mƒ«m‚¬l®h~°i³j„¶o‰¶s‰¯rŽ¬x™°„­»˜¿Å©ËʵËͶ½Åžªº‹—§]K7\K7]K7\K7]K7\K7]K7\K7^L8]L8^L8]L8^L8]L8^L8]L:]J<]K=^L>\L<\L<[N=]P?^SA`SB_R?`P@bQAcRBdQBdNAdLBjMIhKMdPYf[lnk†w{ž€…­‰ˆ²ƒ©¥‡©¾ˆ Ð‚’ây~ðsqújbÿa^ùJWñ>Që:Lî?NïCQê@Kæ<Gå>Fá<Bß<?Ú<=Ö<:Ï>9Ê=4Á;0¸:,§6&¯A0­<,¬6(¿A5ÌF=Ì=5Ð72Ú85Ü71Þ5.Þ6-Þ8*Ý<*×:'Ó6%Ù;0ðSLòZOÙE9Ç8*Í>.ÔB3Ò:-Ô3+ðGBá//î5:ó6=î,7ÿBMñ'3ú&2ÿ)2ÿ(2ù'ý"*ÿ'/þ'/ð&ð)ù+7ê .ì&7ñ-Aç#;ÿXrç-Dÿ]lÿ_iþZcùU\õPWëHMÝ?@Í84Ë>7ÄA7·?1¦7&™2!™6#š;'Ÿ<)§8-®7/ÂE?¿;7½31Ä64Å54ÔDCÛLHÚKEÑD;È:0Ä4)Ç5(Ë4)Å5*¼</³9,­/#«(³-$Ã9/ÒC;ØH?äPFßE=Ú70Ý0*ç0,ò21ù13ý14÷/1ö01ö01ó0.ò0.í2-æ5-Ý9/Õ=0¾2%À>1¹=3Ö_Yésqÿû„†û‡Šÿ„Œÿxˆÿh}ÿ_wÿ[uÿUoøLføEcñ:Yô;[æ?YÛ]i‹@;VF-L^6YuBg†Mw–]}œcg€¡jƒ¦n‚¨o€§n¦m~¥l}¥i|¤h}£f£e£f¥l¦m«l¬k~­g®f±gƒ³i‡µm‹´r°vŽ®|™´‰§½™±Á¤²Á®¦²°˜žz…‹]K7]K7]K7]K7]K7]K7]K7]K7^L8^L8^L8^L8^L8^L8^L8^K:\K;^L>_M?^N>[N=[N=\Q?^RB_SC]QA]OB_OB`NDbPFcOHeNHiMJgNQeS_g_tnny~¨€‡»‡ŠÁž•Ê£‹»«£¹xÓyƒê|{ôvjöi`ø]aóOZìFRòHSøIVõEPï?Jë;Eä9?à:<Ú::Õ=8Î?7Ç>4À</·<,«<+ª?-©8(²:,ÁA6Å<4Ç61Ô<7Ò50Ö5-×5*Ø4(Ù8&Û:&Û;%Ú9'Ý6.æA;ëMDáI<Ð>/Ç8(Ê8)Ó;.Þ;4öJFä01ð6;ö6Añ.<ÿ@Nï'4ó$,÷%(û),ý+,ü*+ø((ö((÷+,ï$'í%(ê%,ý;DÙ'ð4CüARØ&6ÿjuÿbjþZaüW]ôOSåBC×<8Ñ>6¾8,¿D5¹H6©>,™/)(’(ž-%°:6ÑTPÎHGÃ54Æ45Ñ==ëWUØGBÖG?ÐA9Ç9/Æ3)Ê6,Ð7/Î70Ç=3Â91Â5.Ã2-É4.Ñ83Ø?9ÞE=äJ@ÞA8Ú6-Ý0*ç0,ò21û03û03ô02ó12ô01ó/0ó0.î1-ç4-ß9-×=1¿3$¾</·=2Ó^Wévsÿù…ˆø…Šÿ‚Šÿt…ÿf|ÿ\vÿXtÿQoþIhü@aó:Zñ?_áI`ÁS\{?7RF.M_9ZvCe‡Ks•Yxœ_wb{¡f}¥i}¦j|¥i|¥i|¤h{£e{¡d{¡d}¡c~¢e|£j}¦l}©l}ªi|«e}­c¯c‚±c…°h‡²kˆ¯pˆ«s‹«|¬„ª‡Œ¢‹x‡€dppR^^]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8^K:_N>aP@`P@]P?\O>[O?[RC[QE[QG\OG\OI_PMcQOfTTgUUgUUgV\h]nli†sv£|ƒº‚ŠËŠÔ˜‘× ŠÊª‚´¹}ŸÏ€“䄆îvósjûeg÷S\íGQðFOöHR÷EQòAKî=Eä7=à7:Ù99Ô<7Í@7ÅA4¾?0¶>-­>-ª<+«:,¸B6ÇH?À;2»0)Ê:2Í6/Ð6.Õ7,Ø8,Ù7(Ù8&Ü9&à:*Ý4-Û4.âA9éOCÞH:È5%È2#Ù@2â>5õHDè13ò5;ù7@ø4@ÿESø2?ð)0ë#&ì$'ù13õ-/ï''ì&%õ12ë)*ö8:è+1â)1ë3=ÿR^ï=Kÿ[gþ^fñV\îOTðMRêEIÝ:;Õ74Ô?9À6,Á?2¼B5³=1¬7-¥3)¡,#œ' š%©/*ÇECÂ::¼,,È35×ABô^]Ð?:ÒC;ÐA9Ë=3Ì9/Ô=4Ú@8Û@;Û@<Ø=;Ý>;ãA?ä>>à::ã?=ëIDàB9Ý<4Ù5,Ý2+ç1-ð31õ12ø02ô02ô02ô01ó/0ó0.î1-ç4-ß9-Ø>2À4%º8+µ;0Ð[Tízwÿ“’û‡Šúƒ‰ý~‰ÿr‚ÿdyÿ[tÿTqÿNmÿFgû=_ô=\îEbßTg¢AHp;3SH2Qa<]xEf‡Nr“Zu˜^tš_xžc{£g{£gy¢fy¢fy¡cx byŸby a| bz cz¢f{¤h{§h{¨e{©a{©`}«`®`‡²jŠµn‹²s‰¬t†¦w‚žuy“no†lSeYAPM2A>^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^L8`N:aP<`Q>]P?ZN>YOCXPEXOH[QO_UTbXYeX_iYcl\fk^glaildqok‚rtšy~µ†Ê…ŒÚŒŽáŽ‡×Ÿ‹Ó­ŠÄ³€©½yŽÌ{Þzò‚wÿsrÿcgùU\ôMTõGPôCMò>Gï<Bå6;à88Û97Ô<7Í@6ÅA4¼A1·?.«:*­>-±=0¼F:ÌRGÇH?º5.º1)È91Í81Ó;0Ù=1Û;-Ù6'Ü6&à8+à5-Û2+à=4ìNBãK=Ò:,Ñ8*àB6ß7.ð>:é/0ð16÷4<ü8BÿNZÿLUý>Eò38â$&í/1ê,,ð22è**ë/.ò::Ñæ37Ý,2è9@ðEMÿXcóMWØ=CÚADáBFá>AÞ9=Ü89Ø88Ó97É83Â91½:2ÀA:ÍNHÖVSÐNNÃC@²72¶95ÏKIÙMLãQRïYZêRQñYVÉ51Î>6ÒB9Ð@7Ó?5ÙB9àC<â@;é?@ç8=ì9=ò?Cï:?è58ì>=öMJÞ93Û60Ú3+Þ3,å4.ì30ò21ô01ô02ö/2ö01õ/0õ/.ð0-é4-à8-Ù?3Â6'·5(³9.ËVOï|yÿ“’üˆ‹ý‰þz‡ýoücwÿXqÿOlÿFhÿ@cû9\ô?^éKdØZh…35g;0WO8WgCa{Kj‰Ps’Yt•\u˜^wby¡ez¢fw dv awŸavž`xŸ`xŸ`{Ÿaz cz¢fz£gz§fz§bz¨`z¨]|«]~­_†²g‹´nŒ³tŠ­s†¦u€qtŽii€dQcUDSL8G@^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M9]K5_M5`P9_P;\O>ZN@XOFXQKYPQ`W\g`hnfsshysg{sg}qh}ol}pq†rw—v}«z‚Á‡Ò„ŠàŠ‹å“ãŒÚ „¿žuŸ l‚¬nq¼vlÒviòsmÿllÿgiþ^`ûRWõFMï<Bê7=æ5;á78Ý98Ö=7ÎA7ÆB5½B0¸@/­7)´@3¯:0°;1ÈRHÕ\QÉMC»;0¾90Á7-Ì9/Ö>3Û=1Ú6*Ü4'â6*à3,â70ä=5åE9âF9ÞB3ÞA2â>2Û0&ê72ì0/ï.1ñ.4ú7?ÿPXÿ]dÿZ_ÿOSá.1ã03à,-÷EEè66Ü,,Û-.ë>@Ü25Ù37ÿbhà=BË*2Ê-4Á&*Õ;=á@EÛ6:Ù37ß9=Ü7;Í/0Ì43Í;;ÕGFÞRSì`cõilôekê^aÄ@>ÆE@å^[øhgÿopÿjjåKK×=;É40Ñ>7×D<ÖC;Õ>5Õ<4Ø:1Ü41î5;ñ-7ð,6ò.8ï,4ë,3ó9<þJKß3/Ü3.Ú3+Ü3,ã5.ê40ï4/ò21ô02ö/2÷/1ö.0õ/.ð0-ê3-â7-Ù?3Æ8*´2%²8-ÃNGï|yÿ’‘ÿˆŒÿ‰ÿw…úl|øatûTnýHgÿ>bÿ:_ú6\óAaàNeÂWap/+_?0[W>^lIe}Mk‰St’\u–_v™_xžcy¡cx buŸ`uŸ`u_vž_wž_xŸ`{Ÿaz¡bz¢d{¥e|¦d|§`y§^y¨Z{ª\}¬^€¬a…¯g‡®m‡ªp…¥sƒ r{•nrŠjexe[k^RbU_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N:^L4_N4`N8^O:[N>YOEZSMZTT_ZahbprmzuŒ{u‘{q“zp“vp’qt“rxšt}¨w¶zƒÄ~†Ï„‰Ú‹ŒÞ–Ü™ŠÍ›…¶¢ƒ£ª„‘«~yŸl[šQ>¼MBÔQIâWRëWUñSRñKMí>Cå4:é9<æ9;à;9Ø=8Ó@8ÊB6ÀA0º?/³9,ºA6«5+£.$¾I?Ùg\ÙdZËUI¸<2¸6)À3)Î:0Ù;0Ú6,Þ3)ä6-ß1*ä71ã;2Ý9/Þ>0ãF5äB3ß9+ß1(é4-ð31ï-.í*.ô17ÿEJÿV[ÿ]bÿ\aâ9<ã9<Õ+,ôJKâ89×//Û57Ì()Ì'+øXZÝ>BÕ9=Ñ6:º#Ä(+Ü<>æAEÝ49Ù,2Þ17Ù05Í(.Ò37äKNöaeûhnùcl÷`iú`løbkÖLLÕNJê\ZêVTçMMãHFÏ42Î3/ÙA<àKDäOHßJCÙ@8×:3×6.Ü.-õ2:û-:ø*7õ'4õ)4ø0:ÿ>CÿJJà1.Þ3,Ü3,Ý5,á4-ç4/í4/ð3/ô02÷/2ù.1ø-0ö..ñ/-ë2-â7-Ù=1É;-³1$±7,ºC=ìyvÿÿˆÿ|ˆÿqöhxö_rùRlûDcÿ9^ÿ6]ú6\ðFcÑN`¢IMe5+VD0[Y@^lIe|NkˆRt‘[w•_x™`{ždz cvž`s›]rœ\s›\tœ]v^wž_{Ÿaz¡by¡bz¤b|§b{¦_x¦[x§Yz©Y{ªZ~ª_ƒ­e…¬k‡©m‰§s‰¥u„s|”ru‰pnlfwe_P=_P=_P=_P=_P=_P=_P=_P=^O<^O<^O<^O<^O<^O<^O<_N:aP6aP6aO9^O<[OA[RK\VV_Zakgvso†}z—‚~¡|¥}w£{u¥xv§sy©s}°x¸{„¿~†Ä„‰ÉŽÎ”“Íš“Ç •½«›µ¼¦²É­©Å¦”ªˆmœfJœE2¯A4¶@4ÂB9ÖHDèNNîJKì?Cë=?é;=ä<;ß=:Ù@8Ð@5È>1Á=0½:0¾?6¯4,§1'»I?ÑcVÖh[ÕeWÃOBº>2º4)Ç7,Ö90Ù5,ß2+ç60â0,ã4/â7/Þ7.à>1åC4ä>0Þ4%æ4*é0+ð3/ð..ï-.ò14ó78öBEöMRüY^éFKöQWØ37ëFJÝ8<æAEÚ7:Î.0Ñ05äHKÒ7;Ð7:¹#%Õ;=Û8;å;>ë<Aç6<â-6Ý)2á1;ç<DðLSý]eÿksÿjsú`jöZgùXh÷[fôddèZVèWTØ@=Ï10Ô44Ó33áC@ãJEéRKêSLáJAÙ?7Ø93Û81ã33ó.7ÿ0>ÿ0=ú*7ü.:ÿ;EÿCHûABã1/ß4-Ý4-Ý5,â4-æ3,í4/ñ40ô02÷/2ù.1ø-0ö..ñ/-ë2-ã7-Ø:/Í>0µ1%±7,²;5ésqÿŠŠÿ‡ÿv†þi}óató[p÷PjúCbÿ7`ÿ7aù;_ìLf¿O[~86]=0NF1VX@ZeEcxMj…RrŽ[v”^yša{ždxžas›]p˜Yp™WqšXqšXt›\uœ]y_xŸ`x¡_y¢^z¥^y¤\x¤Yx¤Wy¥V{§X©_‚¬d„«h†¨l‡¥o†¢q€šmx‘jq…ij~cbv]_P=_P=_P=_P=_P=_P=_P=_P=^O<^O<^O<^O<^O<^O<^O<_N:cQ9cQ9aP<]P@ZPG\TR_Zaa_mtrŠyx˜€¨ƒ°~~°yy¯yu°wwµw|¾x€Á}…Ä‚ˆÄ…ŠÁ¿—–¾ ¼¬§»¶¬µ¾³±È¸«Ð¾¦ÖÁ¢Ñ»–Ьˆ¯oT®\G¤G5¨>0ÂG?àWQïWVñNOé@Cê=?æ<=â=;ß=:×=5Ñ:1É90Á80Á<5¹:3¸=5ÁOEÇXMÇ]OÑeXÓcUÂL>¼:-Å8.Ò91×4-ß2,ç60æ40á2-à5.ã<3çC7æC4â:-ß3%ê5,æ.&ð0-ï/,ð31ñ54ç-.â24çBF÷X]öW\ÿouåDJëHMà<Cþ[`ÿouÞ=Bÿ}‚ÿmqêQTÔ>@Æ02Ö:=òHKî9>ð7?ø=Fò7Bè-8ô>Jÿ]gÿmwÿjrÿcn÷]gú^kÿaoÿ]nùYeò\]ãPIâJGÕ74Ò/0Ù54Ò0.Ø95ßD?ãJDâIAÙ@8Ó6/Ö4/Ü71è66ê'/ü0<þ2=÷+6ù0:ÿ>Eý?Aì44â3.à5.Þ6-ß4,á3*è3,ï4/ô41ö01÷/2ù.1ø-0ø..ò/-ë2-ã7-×9.Ñ?2¶0%²6,°61èpoÿ‡ˆÿ†Žÿp‚ücxñ\pôXn÷OiûBbÿ9aÿ<döAbäRg°QWd/'WD3GG/RT<U^?btLiQq‹[v’_z˜b|dxœ_r™Zn—Un—Un—Uo˜Vr™Zt›\w›]wž]wž[x¡[y£[w£Xv¢Wv¢Uw£Ty¥Xz¤Z~¦_¦c¡d~œf{—frŒ]i‚X`vRZoPRgH\L<^N>`P@`P@_O?_O?_O?aQAbRB_O?]M=]M=aQAcSCbRB`Q>dS?aP>]P@^QI[QPZSZeapsq‰yxšz|¥~€±€¹}ºxz·rs´lo¶twÈv{Ì€ƒÊ‹Æ–—䤾²°»¼¹´ËƳÓÌ°ÙϬÛϧÜÏ£ÝУÙ˜٘Ѩˆ¸€g ^FËzgÖue½H?×QN÷ccéKLå?Aâ89ä::â:9Ü75Ù61Ö;6Ë81À5.ÇB;»<3¿I?ÆXK¹OAÎdVÑcTÌXIÅG9Ä:/Í6-Ø7/á6/ã4/ß0-ß2,à70ä=4à<0Ý7)ß5(å7,ä/$ê/&ì/)î1-î20ë40è51â64×79æJNõY]íNS×8=×6<ùX`ÿ~„ÿ~†ÿouÿgoÿipÿflõ\añX[ûZ_ÿUZÿDKü8Bû7Aö2>î+9ì0>ñ=HÿS_ÿ`iÿgrÿepþbmÿcnÿ`oý]gíSSßF@Ö85Ö41×11×/.Ø31Û94áD=ÜB:Ù?7Ö<4×90Û81à93æ66ð7<ó4;ó4;ö4<õ6;ò59ë33ã1/Þ3,Þ5.ß7.à5+ä3+é2,ï2,õ20÷12ø03ú/2ù.1ù//ó0.ì3.å7.à?5Ì8,¿6,¯/&¸;7ÒXWÿ˜šþ{ƒÿm€ÿe|ø\rðPhôGeüCeÿ;dù9`õNlÓRd‰=?P, C;&CG.KM5Y_CZjEcxMqˆZx’bx–`t•\r–Yq˜Yl•Sm–Rn—So˜Tr™Xt›Zuœ]uœ[t›XtWv Xw¡Wv¢Wv¢Uu¡Tt S{¥[{£]zž^u—[m‹Ub~MXrCSj>AW0?U/<R,[K;^N>`P@`P@`P@_O?`P@aQAbRB`P@_O?`P@bRBcSCbRB`P@fVG_QF\OG^TSaZad`omkƒvw–wy¢{}®}¸x|¹quµkp´lo¶nq¾uvÐ|~Õ‰‰Ó˜˜Î¨§Ç¸¶ÁÉźÓαÛתâÛ¥çÞ¥æÝ¢äÛ¤âØ£ÛÑ ÔǛӼš»œ€©}dÅ‹wÊ}m´VJÒa[örpìZ[çKLã?@ç=>ë>@ç;;â66Û64Ö=8É83Ê?8¹6.¸>3½K@¶H;È]MÝo`Ô`QÆH:½5)Ä0&Ô6-Ü5-Û0)â51å95ä=7à<3Ü8.Û5)ß4*ã5*ì7.í5+í2+ë0+ç0,ã2,á4.Ý52Ö87Ø>@äJLóW[ú^bü\dþ]eÿaiôS[ïNVñQYÿ_gÿjqÿflõZ`óNTí4:ñ,5ô*6÷-9ñ'5å!-æ'6í7CþPZÿZdÿblÿdmÿenÿcmý[hõQZåEEÞ<7Û64Þ63ß55Ü30Ú2/Û62à>9Û>7Ø;4×:3Û81ß82å95ç:6é9;ê7:ë7:î79î79ì65å31ß2,Ü3,Ý6-ß7,â6,å2+ê1,ò1,õ20÷12÷03ú/2ù.1÷//ó0.ì3.å7.ß<3Ô=2Â8.¶1*·74ØZ[ÿ“ûs}ÿfzÿ^vùWo÷OiùFfû?bü<cô@cåOh¹KVx;8L2#<:#<B(EG/OS8VdA`rJnƒXu_v“]t“Xq“Vp”Tk’Ok”Pl•Qm–Rp—Vr™Xsš[sšYt›XuWuŸWuŸWtžTržQqRpœQn˜Pl”NhŒLbFXu?Ni6F]/@W+@W-@W-AX.YL<[N>^QA^QA^QA^QA_RB`SCaTD`SC_RB`SCaTDaTD`SC^PCbUM\QM[QRcYbkdtqm„vu•y{¤y{¬y~¶x|»nsµei°`g¯jn¸ruÆ}}ׇ„Ý—”Û©§Ø»¹ÏËÊÈÜØ¿åá´éäªíè¦ðé¥íå¤çá§âÛ§×Ï¡ËÃœ¸¯©››ƒk¨ƒp§o`œRGº]UÝmi÷uuï__äJLå@DëADì>@è8:â66ß=:Ô;6ÔA:Â70·7,·>3®=/¶F8Ûj\ßi[Ù[MÊB6Å2(Ñ4+Ù6-Ù2,Þ52éA>ìGCà=6Õ2)Õ1'Ú2'Þ0%æ4*è1)ç.)æ/)ã2,â7/á=4àB9Æ-(Ê43ÜDCðVXú^b÷ZaóS[ñQ[èFQêHSïOYü\fÿmvÿntôY_ã>Dé.5ô-4û2<ü2>õ+9í'4ö6EÿKW÷ISõPWøW_þ^fÿckÿ`i÷RYéBIÞ97Þ71ã75é<8ë;;æ95á51Ý60Ý:3Ù;2×90×90Ü71á83ç:6é<8ã99ã99å97ç98è88æ74á40Û2+Ú6-Û7-Þ8,â6,ç2)ë0)ó0,÷10õ12õ13ø02÷/1÷//ò0.î3.ç6.Ý90ÜD9Ç80»4.µ/.ä_bÿƒˆølwþbxþWsúPmþLlÿCfö:]ó;_ìIfÔSgDJl;4O>,=<':?(ED/FH0Q\<YkEg|Qr‰[tZqUmRkOiMi‘Ki’Lk”Pm–Tn—Up—Xq˜WuœYuWtœUrœTpšRm—Mk•Mj”LeGaˆE[AUt;Li3E`-AX*>U'B\/E_2Ic6WJ:ZM=\O?^QA]P@^QA_RBaTD`SC`SC`SCaTDaTD`SC_RB\PDZOMZQVbXcjcsqm†vu•xz£z|­w|´sy·mr´bi¯]d¬ag±lr¾x{ʉ‰ß•‘夡䶵áÇÄÙÕÑÎáÝÄçä¹ëæ¯îê­îè¬éâ«ãÛªÚÓ©Ë¡»¶™¥¥›™„“ˆv˜q™rc›bW³i`Ïrmû‹‰õutê[]æLNèCGí@Dì<?é;<ß:8Û<8ÞE?ÓC;Ã:0º:/°6)§1#¿I;ÛaRêk\ÛSEÉ:,Ì4'Ô6+×4-Ù42ñMKþZXíKFÙ80Ö3*Û4+Þ2(ß.&á,%á,%Þ-%Ü1)Ú6,Ù;0×?4Â/'Ä4,Î:6ÙCBßFHàEIäGNêMVñQ]öVbøXbù\eÿgpÿmuôYaÞ;@ê17ñ.4ò-6ð+4ë%2ì(4û=IÿS_í?IèAIêGLôQVÿY`ÿX]ôGMä68á53ä73ê;8ò@>ô@?ï=;æ95à72Ý82Ú91Ù80Ù80Ü71ã73è96é:7â:7à;9ã:7æ:8ç:6å84à5.Ú3+Ú6,Û7-Þ8,â6,ç2)ë0)ò/+ö0/ô22ô23÷12ö01ö0/ò0.î3.ç6.Ü8/àF<É91¾3.¶,,îfjÿy€øgtÿbyýTqþKkÿGjÿ>cò6Yë=^ãQhÄXeˆBBgC7[N;GF1AC-JH3EE-LU6Sc>btLlƒUp‹XnRkPiŽKgIhJh‘Kj“Mk”Pm–To–Wp—Vt›Xs›Uq™So—Pj“MgJeŽHdG`‡D]AWy=Rq8Mi6Lf6Ne7Of8Lf7Oi9Sm>UH8WJ:[N>\O?]P@]P@_RBaTD_RB`SCaTDaTD`SC_RB_RB^QIVMR_Xhnf{tp‰xt—xw¡xz«y{´sy·jr³`g­[c«_g°jr»v|Æ€„Γ•àžžä­®ç»½æËÉßÔÓØÝÛÎáßÆåá¾æâ¼äß¹à׶ÚеÎƱ¾µ¦­§›˜šŒŒŽ€‰…yŠ|q‘vk›si¨meºoi扄î~ósrñedñWYðMNîDEì@@ã:7à;7äB=ÞE?Ì<3Æ=3ÄB5¯1#®0"ÇI;ÜXKÖN@Ì=/Î8*Ð6*Ñ3*Ö42õUUÿkhú]XãD>Ü;3ß;2ã80â4-ã2,â1+Ý0)Ô0'Í/$Æ/$Â0#Å9,À4'Á3)Ë:5×CAÛEGÛBGÚ@HàDOëOZòVaòVaú^iÿgoóYaáBGê:<í57í38ï28ñ3=÷9CÿHSÿV_ä6?Ý4;ß6;ëADùJOüIMô;Aé13è51ë95ï<8ò<9ó;9ð:7é73â70ß;2Ü;1Û:0Ü90ß82ä73è64é75æ:8ä;8æ:8è:9è;7æ95á6/Ü3,Û7-Ü8.ß9-á7*å3)é1)ñ0)ô1-ó32ñ33ô22ô01ô1/ò0.î3.ç6.Þ7/àC:Ê70À1-À13÷jpÿqzúftû]túPmÿCfÿ=dÿ9cõ8^æEdÙZm«V[wE>dJ=aYFTO;KI4PI6GE.GP3L\8ZlFf|Nm…SmŠRlŒMhJfŽHgHg‘Ii’Lj“Ol•Sn•Vo–Ut™Vs˜Un•Rj’LfKcŒHaŠF_ˆFZBX|?St;Pn8Ok:Rl=Wn@ZqCUo?Vq>WqARE5UH8XK;ZM=[N>\O?^QA`SC`SCaTDaTDaTD`SC`SCbUEaVP^Vcje|yu}yšzy¡xy©vy°sw´jr³cj°[c«]e®hp¹v~LJшŒÓ™Ý£¥à¯³ã»¿åÆÇãÏÎÞÔÓØ×ÖÑÙ×ËÙÖÇ×ÑÅÒÉÀÌþŹ¹´¨¬£šŠ‹†x{tyvquleleogŽa[`[ÀsmØyuð{ü|yÿrpýccöSTðHGïC?ê>:á<6àA;Ñ:1ÓC:ÝTJÂ>2¸6)½9,Â=.È?/ÏB1×C5Ö@1Ñ7-Ð2/êLMú_]òWSßD?Ù:4Û81à70æ93ç92ç92â:1Ú9/Ñ9,Ê8+Ä8)°(¸3"È@2ÓI>ÒD@Ë;:Ì7;Ï:@Ñ7AâHRíV_ðYbõ^g÷`iêU[ÜAEå@>ì?;ñACúGJÿLTÿQYÿT]ÿV^á4:Ú/5Ü/3ç7:ô=Aø;?÷48ó12í42ï95ð86í42ë20ê20ç40á4.ã<4à=4ß<3Þ;2á83ä73è43è43è88ç98è88ë99ë97é75â5/Þ3,Û7-Ü8,Ý:+ß7*ã2(ç0(ï0(ò1,ñ42ð43ó32ó11ó1/ñ1.ì3.ç6.à91Ù<3Ì71Á0-Ñ@CÿnuýkuùbqðRiõHfÿ;aÿ4^ÿ6bû>däNiÊ\i‹GFjF:]L<]VCXQ>RJ7OG4ID.DJ.GU2Sc>^sHgMj‡OjŠKgŒGgŒFfŽGfHgJi’Nk”Rm”Um”Uq•Uo”Qj‘NgŽKcŒH`‰E_ˆF^†G\‚E[~DWxAVr?Uo@YpB]rG^uG[sCYtAXs@NB2QE5UI9WK;XL<ZN>\P@^RBaUEbVFbVFaUE_SCaUEfZJh]YngwupŽ|x™{y wx¦vw­pu¯jo¯ah¬^f®_g°em¶pxÀ}…ؙ͉ؗ Ö¡¨Öª±Û´¹ßº¿ßÀÁÝÃÃÛÇÆØÆÃÔÅÁÐÁ»É¼³Ä»°Áµ¨¼¦˜¯–‹œˆ…Œqqqtpopfewhe†nj„_Y•d_›ZT¹f`Ùsnðzvÿ{wÿwsÿhfüZWþRNõHBæ=6çD=Ø;4ÛG=ê\RÅ;0Ä<0½7+¾6(Ç>.ÑD3ÔB3ÔA1×A3Ò86Ø>>ÝCCÜB@Ö=7Õ81Ø7/Þ7/å:3æ93å:3â;3Û>5ÕA5ÑE8ÌG6®-¼;%ÍJ8ÑL=Æ=5»0+À00Ê9>×AJáKTëU`ðZeð]eìYaßLRÔ>@Ï4/Ø7/à;9ê@@òCHõDJñBIî?Fâ5;ß26ã36ï8<õ79ø14û/2ü14ï20ð95ð74ì0.è,*ç0,æ3.à3,ä=5à=4à=4à<3ã:5æ95ê65ì65ì57ì57í57î68î66ë54ä2.Þ1+Þ7.Ý9-Ý:+ß7*á4&æ1&í1(ñ1,ð42î53ñ42ò21ó1/ñ1.ì3.ç6.â;3Ò4+Ò:5Æ20çUXÿpxùcnòZiçI`óEfÿ8bÿ/]ÿ5bÿBhÜLe±PYj5/^G7XK:UN;[P>VI8M@0JC0@F,AO.K[6Xj@bxGfJhˆIf‹FeŠDc‹BcEeŽHgLh‘Oi‘Rk’Sn’RlPhNd‹JaŠH_ˆF_‡H_‡H_…H_‚H]~G]yF]wH`wKcxOczN]uC[vAZu@JC3MF6QH9TK<WK=YM?\O?^QAdWFeXGdXHbVF_UIaWMg^Ulcfwr‰yušxvžtsŸrr¤tu­lp¯bg©Za©_e¯fl¸ms¿v|ȇӓݗœÞ›¡Õ §Ó©­Ú®³Ý±´Ý²´Û´´Ú¶´Ûµ±Ö³­Ñ®§É«¡ÄªžÂ¤˜¼™‹¯ˆ~™|x†dbgiefcYZj[X{c_yVP’c]ŠNF¢UM½`XÖkcñwrÿzÿzwÿnjþa\÷TOéGBîOIÝB=ÞG@êWOº,"¾1'¾4'Ç>.ÑE6Ë>-Á2"Ê7'ÛE7ÞE?Ó97Ì3.Í50Ô;5×=5Ý<4á=4ä;4ä92Þ5.×4+Ï5)Ê8+Å<,Â?-ÔS>ÈG2½<)¾:-Ã=2Ä;5Â74Â43ÜKNÞMRáPUåTYèY]åVXÜMOÓD@É5+Ñ7+Ø7/Ý52â24å26æ18æ.6ì4>ì3;ó5?û9Bý4>ú+5ÿ(3ÿ/9ø-3ù57ù59ð./ë*+é0.è51â5/ã<4à=4à=4á=4ä;6ç:6ë76î66ì46ë35ì25í34í55ê41ã1-Û0(Þ8,Ý:+Ý:+Þ8(à4&ã3$é3&ì4*î50î52ð42ð3/ò2/ï2,ì4,ç6.ä=4Í/&×>9Ì35ùbgÿoy÷[iðNcêC]ùEhÿ:eÿ0]ÿ6aöGhÉJ]“CFR,#VI8SL:OH6[O?UI9F?-HF1>B'@J(IU1Sd:_rEe}Ig„JeˆHcˆCa‰BbŠCcEeŽHfMhPiQlPkMfJcŠIaˆG`‡F`‡H`†I^G^F_}G`|Ia{Kd{Mf|Nf~N]xC]z@^{CDB6FD8JF;PG>RH>WI>]M>_O?`Q>aR?`SB_VGbYRgb_ojnso~wq“zt |y¨yw©pp¦gg£`a¢\_¤`b­fhµopÀyzÌ„‚Ö‹ß–’眙栞ݡ¡×££Ù¤¤Ú¦£Ø¥¢×¥¡Ô¤ Ó¥žÑ£Í¢šÉ¢™ÈŸ–Ù»Ž‚°ƒ|žrn}igld^`fZZkYUrWP}WNŒWO•RI¨ZPµXPÁZSØkdìyrù‚|ÿ‹†ùuqÿusí_]ßPLÙEAïZTÌ71Å2*Ä6*Ã7(À7'Ã7&Æ9(Ê;+Ð<.Õ?1Ò8.Ö<2×?4Ó;0Í5(Í3'Ø:/â@5à90á90Þ7.×7+Ï7)É:*Æ?,ÄA/Â=.Æ@4ËE:ÍG<ÌC;Å<4»2,¶+&Ç<7ÐEBÙOLàVSãYVáXRØOIÐC:Ì;*Ó:(Ü8,â5.è./ì*2ð(3ô'6ú->ú+?û*?ý)?ÿ(?ÿ&?ÿ$<ÿ$<ÿ$8ÿ'9ÿ+<þ,9ó+5í.5è45ç;9Ý84Ý:3Þ;4à;5ã:5æ95é73ë54ë35ì46ë54é54ç53â5/Ý5,Û5)Ü8,Û9*Ü9(Þ9&ß8&â7%ã6%æ4&ì5-í4/ð50ñ4.ñ5,í5+ê5*å7,à90Ø7/Õ:6Û?BÿmwÿbsûSjõIcÿKjö6[ÿ6_ÿ<gø>cçNj¯IV^$"D, ?:'HE4PM<PI9EB1>C/?G/BH&EK%KS.S]8[kDavKd~NdƒJb†F`ˆBa‰@c‹BeFhJlPm‘Ql‘LiŽHgŒGf‹HfŠJe‰Ic…HaƒGdƒJdIbGc~GdJdHe~Ga}C[{<\=_‚B=?4?A6FC<JE?PE?TG>[K>]M=`O;`Q<^SA^VIc[Xhcinlyso†tp•vpžtp¢pm¢gfŸaaŸ]^¡\\¤ed°kjºtrÅ}{φ‚Ù‰à”Žæ˜“å›–Ùœ˜Õ™Öžš×ž˜Ö—Õœ–Ô›•Ñž–Ñœ”Íœ“Ê›’ǚē‰»ˆ®‚xtk|mdif]^f[YiZSoWM{UJŠVKšVK°\RºYRÁXRÓfaàqjãvoí~wý‡…ÿ‡…÷usîgdãUSëZUÇ2,Â/%Å7)Ã7&À7%Á8&Ä8'È;*Ï;-Ó=/Õ9,Õ9,Ó:,Ò:,Ñ9+Ñ9+Ô8+Ø8,ß;1à90Ü8.Ö8,Ï9*È9(Á:&¾9&¾6*Á80Æ=5É@8ÊA9È?7Å<4Â91¿4-Ç>6ÑH@ØOGÚQI×NFÌC;Ã7*Ê7%Ó8$Ý7)å4,í//ô+3ù)7ý(:ÿ+@ÿ*Aÿ)Aÿ&Aÿ#@ÿ!<ÿ=ÿ:ÿ:ÿ 9ÿ%;ÿ);÷-9ð19ê7:å;;Ü94Ü:5Þ;4à;5ã:5æ95é73ë52ë35ì46ë54è64ä71ß6/Ü5,Ù5)Û9*Û9*Ü9(Ü9&Þ9&ß8%á8%ã6%ç5+ê3+ë4,ë5*ë5*ê6(ä7)á7*ß;1Õ4,Ó54óTYÿesÿ[põGbÿIhÿAdÿ;`ý3[ù;aòMmÍLb‰8?S*$A5'69(;<,B@1DA0@?-=B.>G,=CKP'\b<eoJhvRezQd~Od‚LaƒFa†Aa‰@cŒ@gDiŽHkMl‘Nl‘KjGhHf‹FgŠJf‰If…JdƒHfƒKdIdHd€FeGeGfEb~A]€>_„?b‡B69.:<1??7DA:KB;OE<VH=YL<^O<\O<\SB^WMc]]helom{sq‰so”qk™jf˜c`•\[”ZZ˜\] \_¦hjµno¿wxÊ€Ò†„ØŠˆÜ‹à‘ŽÝ“Ó“‘ÑÑҔѓŽÑ“ŒÐ’‹Î•ŒÍ“‹Ç”‹Ä”‹À“‹¾Œ„³ƒz¥€r•|ewu^fi[[d[Vd[RfXKrVH„TH£ZQ½`YÉ\YÏYWÛcbákißokãvqûŠ„ÿŠ†ÿ…ÿ}y÷nhîaXÄ4+À2&Ä8)Á:'À9&À9%Â9&Æ;(Ì:+Ð:,Ö:-Ó5)Î5'Ð8*Ô>/Ô>/Î6(Ë/"Ú:.Ú8-Ù7,Ö8,Ð:+É:)Â9&¾7$½5)À6,Â8.Ä:0Ç=3Ê@6ËA7ÌB8Ç:1Ê@6ÏE;ÐF<ÒH>ÑG=Ê@6Å7+Ì6%Ö6&ß7,ç4/ñ03ö-5û+9ÿ*<ü';ü'=û%=ù#;û!:ú7ü7þ6ÿ8ÿ6ÿ$8ý*;÷2<ñ6=ë8;ä::Ü94Ü:5Þ;4à;5å95ç85é73ë52í36î47í55ê65å61á6/Ü5,Ø4(Ú8)Ù9)Ú9'Û8%Ý8%Þ7$à7$á6%á5'â4)ã5*ã6(ã6(á7(Þ6)Û7+Ý<2Ð1+Ø88ÿkrÿ]nþPiñ<[ÿHlÿ7]ÿ>eù5[î>bæVqª?Qa#(L/);7+07'37&9<)@=*A<(@>)BB&?FXa4s~T€Œdw‡`hSa}La€G`ƒC`…?a‰@cŒ@hŽEjJkMl‘Nn“Mk‘HhHgŒGh‹Kh‹KfˆLd†Je„KdƒJc€FdGf‚Hf‚GeFb€Bc†DeŠEhH25*58-;<4A>7G@:KB;RE<VJ<XL<YM=YQD^WOc^bigron€roŒrm•jg”`^WW‹TUŽWX˜\_¢ac­ln»rsÃ{|΂ƒÕˆ†ÙŠˆÛŒˆÜŠ×ŽÒΌώ‹Ð‰ÑŽˆÐŽ†Ï…Î…ÊŽ…Æ…Á‡¼‡¶‰‚¬€xoŒ€_p|Y`lXYd[T^_Q_\IjWF}SEžUL¾\YÐY[ÙX\äcgçkkáplåxsì}vízsþƒ~ÿ†ÿ{õkaÉ<2Ä8)Â;(¿:'¿;&¾:%Á:&Å:'È9)Î8*Ø:.Ô6*Î5'Î8)Ñ>.Ñ>.Ë8(Ç/!Ò6)Ó5)Ò4(Ò6)Ñ9+Í<+È=*Ä;)Ä:-Ä:/Æ90Æ9/Ç:1È;1É<3Ë=3ÓD<ÓE;ÐA9Ë=3Ë<4ÏA7Ï@8Î;1Î5'Ù5)â5.ë31ò/5÷+6ù)7ü):ù&9÷&;÷&;ø'<û&<ý%:ÿ$:ÿ#:ÿ"7þ#7ú%7ù,;÷5>ò9?è8:à87Ü94Ü:5Þ;4à;5å95ç85é73ë54î47î47î66ê65æ72á6/Ü5,×5*Ø8*Ø8(Ø8(Ù8&Ú7&Ü7$Ý6$Ý6$Û5%Ü6(Ý7'Ü9(Ü9(Û:(Ù9)×:+×:1Ð3.ëHKÿoyÿVjøD_ø<_ÿAgÿ3\ÿ8bø>cèMlÅOe€0=J C1-11'.6'4=,=B.B@+B<$E>$HE$U\0p~MŸr—¨|ƒ˜mj„W_{J]~E_ƒCa†@bŠAfCkJl‘Lm’Om’Oo”Nl’IiŽIhHiŒLiŒLhŠNg‰Mf…LdƒJdGe‚HgƒHh„If‚Gd‚DgŠHiŽIl‘L-3'36+891<;6B=9G@:MD=QG=SI=SK>UNDZUQa^eigumklkŠjhb`XVˆPP†QQXYš`cªfj´orÁuxÉ|Ђ…Ö†‡Ù‡ˆØŠ‰Ù‹ŠÖ‹ŒÏ‹ŠÌŠ‰Í‰‡Ð‰…ш„ÑŠƒÑ‰‚ÐŒ„Ï‹„È…Á†º†°‡¥~w–m…„Yj€SZnVTc\RZaOZ_HeZDxUB’LD¸TRÐSWÛRYå^dèejãklæuqäunâoh÷~vÿ‚{ÿ‡~ôl`É?2Á8(À;(¿='¿='À<'Â;'Å:'Ç8(Í7)Ø:/Ù8.Ò8,Ï9+Ì:+É:*È9)É7(Ï9+Ñ7+Ò8,Ñ7+Ï7*Ì8*Ë<,Ë>-Ê<0É=0Ê<2É;/È:0Æ8,Å7-Å5*Ð@7Ð@5Í=4É9.Ë80Î;1Í:2Ì5,Ð/%Ù0)ä20ì25ô/8ù-9û+;ü,<ü-?û.?ü/@ü/@þ/Aÿ/?ÿ-?ÿ.@ÿ)9ü)8÷+7õ0:ñ6=í8=ã77Ü43Ü94Ü:5Þ;6â:7å95ç85ê65ì44ñ48ñ48ï56í76æ72á6/Ú6,×5*Ø8*Ö9(Ö9(Ø9&Ø9&Ù8&Ú7&Ù8&Õ8%Õ:&Ö;'Õ=(Ô=(Ô=*Ô=,Ô<.Ñ7/Ú;8ÿ^eÿaqÿPi÷<[ÿAiÿ4_ÿ4`û1YôKlÛYq•>NZ%-C),:2/-0)08+7@/:B+<<"A<UH(`[5{…S£lª¾‹¨¾Ž¥wo‹[aK^F`„DcˆBeDj“Go”Np•Po“So“So”Nl’IiŽIgŒGiŒLiŒLi‹OhŠNf…Je„IdƒHe„Ig…Ih†Hg…Ge…DiŽIi‘Kl”N+1%.4*470893>:7B=:HA;KD<NH<NG=OJDWSR_^ffeugggf†ba‰[YŠQQ…NO‡RS“[^£ei³lo¾uwÊz|ÑÖƒ…؆‡Ù†‡×ˆ‡Õ‰‰Ó‡ˆË†‡È†…Ë…ƒÎ…€Ð…€Ò‡Ò‡€Ð…ÒŒ…Ë…ÁŒ…¸‹…«„{v|jz„VcPVnUQd^P[eMXbIb^EsXCOE´WRÐUZÚSZç\cèagågjèpoìyræqh÷|tósjþxmæ\QÄ;+¾5#Â;'Á=(Á=(Ã<(Ä;(È;)Ë9*Ï7*Ö5+Ø7-Ô:.Î:,Ç:)Ä8'Æ:)Ê=,Ï=.Ö@2ÙA4Ö>1Î8*È4&Ê8)Ë<,É:,È:,É;/É;-Ê:/È9+È5+Ç5(Ê6,Ï;/Ò>4Ó?3Ö?6Õ>3Î7.É,#Ò+%Ü-*ç02ð39ö1;ú0<ý0?ý0?ù0@÷1@÷1@ö0=÷/<÷-9ú,9ú*7ý/<ù/;õ0:ð3:í6;æ69ß55Ù42Ü94Ý:5ß:6â:7å95ç85ê65ì44ò59ò59ð67í76æ74ß6/Ú6-Ö6*Õ7+Ô8)Ô8)Ô9'Õ8'Õ8%×7'Ô9%Ð9$Î<%Ï=&Ï?'Î@(Î@*Ð?.Ò;0Ñ61ëHIÿfrÿOdÿHfû7[ÿAmý/]ÿ7aò4XãPj¼Ufm19E(*E697325406906=-3;#38CCja:…TŸ®w©Á‡µÎ—¯Ç“’®}v”be†Q`‚F`…BcˆBgFm–Jr˜Or—Rq•Up”To”Nl‘KhHf‹Fh‹KiŒLi‹Ni‹Og†Kf…Je„If…IhˆIi‰Hi‡Gf†CjJk“Mn–P(0#+1'/4-350764<85@=8C>8IE<HE<KHCRPQ[[eabtbb|``‚_^ˆZXŠTTŠTT\] gi³psÄvxÍ{Ø~‚Ûƒ„Þ„†Ý„…؃„Ö…„Ô†…у†Ë‚…ȃƒË‚̓€Ñ…€Ôˆ€Õˆ€Ó…Ò‹„È‹ƒ¾‹ƒ²‰‚¤|“wp€veo~U[|PQnUNf_O]eMZdIaaGq]E‰TF­]TÈZ[ÔVZâ[aæ]déaeîllõzsírj÷xoÞYPå[PÒD8Ã5'Ç:)Å:'Ä<&Å='È=(Ê;*Í:*Ð8*Ô6*Ó0'Ô3)Ò8,Í;,Ç;*Â;(À;(Ã<)È;*ÕC4áK=ÞH:Ó=/Ê4&É5'Í;,È9)È9)È9+È9)Ê8+Ê8)Ë7+Ë7)Í6+Ò<.×?4Ø@3Ú@6ÛA5×:1Ò1)Ü0.å14î49õ6>ù4>ù1>ú0@ø/?ò.<ï/<í/9í07ï-5ï,2ò+2ñ*1õ2:õ3;ò5;ì59å57á55Þ65Ü75Ü86Ý97ß:6ã:7æ87é77ê67ì46ô5:ô5:ñ7:î87æ74à70Ú6-Ô6*Ó7*Ñ8*Ð8*Ð9(Ð9(Ð9&Ñ8(Ð9&Ë9"È:"È>$Ç?%È@(È@*Ì=-Ï;1×96üU\ÿ^qÿGcÿ?aÿ:aÿ7gþ3bû8`íFdÅNa‰@IS12A64@:<:46?56<7179+4="9CSZ.‚‚P¢§q±ÅŠ¯ËŽ°Ì’¦Ã’®}{™egˆQ_E^ƒ@c‰@iDo•Js™Ps˜Sq•Uo“Sn“NkJgŒGeŠEgŠJh‹Ki‹Ni‹NfˆKd†Id†IeˆHgŠJh‹Ii‰Hf‰Ej’Ll–No™Q&.!(0%-2+13.331764:95<;6GD=DD<GFBOOQZZd_ap^`y\\~`_‰\ZŒYX‘\\šgg­qsÀz|р܄ႅ䅆ㄅჃۂՃ‚Òƒ‚΄‡Ìƒ†É„„̃‚Î…‚Ó‡‚ÖŠ‚׌ƒÔ…ÐŒƒÄ‹‚·Š‚«…›xˆsnuqbevWUtSLjVKf_MbfM_eIcbFp^FzQ?[M·ZSÅSR×VZâW\êY`òce÷rmñnf÷qhÑD;ÔA7Å1%È4&ÔC2Ç9%Ç:&É;'Í<)Ð:+Ó:,Ø8,Ù7,Ï,#Î0%Î6)Ë<,Ç@-Á>*¾;'¼7$À4#ÑB2ãOAäN@ØB4Ë7)Ë7)Ð>/Ê;+É:*Ç8(Æ7'È6'Ê6(Î8*Ð8+Ó;.Õ;/Õ9-Ò6*Õ7,Ú<1Ý<2Ü71è88ñ8=÷:Aû9Bú4Aõ/<ò,;ï,:í/;ê19ê38ë48í57ñ56ô36ó57ð37ï6;í9<é69â45Ý33ß76à;9Ý86Þ97á96ã:7æ87é77ê67ì46ô5:ô5:ñ7:ì89æ95ß82Ø7/Ó7+Ð8+Í:*Í9+Ì;*Í:*Í:(Í:*Ì;(Å9"Â:"Ã=$Â>%Ã?(Æ?+Ê<.Ï81ß<?ÿ\fÿQhÿIfÿ9]ÿ=hù.]ý<hé;\å\p¦LV^..G83BC><89?48E26C41=:)>E&FU*bs?›a­½±ËŒ«É‹¦Ã‹º„Ž¬z{™ef‡PZ|@^?a‡>hŽCo•Jr˜Or—Rp”Tn’Rn“NjIf‹Fd‰Df‰Ih‹Ki‹Ni‹NfˆKe‡Jd‡GeˆFgŠHh‹Gh‹GeŠDk“Lm—OpšR(0!'/"(-&).(.0-3317839:4==5?@8DE@JLKORYVXeZ\s]^}YX‚[Y‹^]–ee£nn¶wxÈØ„…⌌ðŠŠì†‡ä‚‚Ü€€Ö‚€Óƒ‚΀ƒÈ„ǃƒË„„ΆƒÐˆƒÓ‹„ÒŒ„ÏŠ€ÅŠ€¼‰€¯‡}Ÿ€xwozkegf]Xm[Qm[Mi\Lf^Kd_IeaHhaGo_FoP;…UA¥]O¿aYÑYXÝQTîS[ø\`ùheæYPÔD<Î70Ñ7/×:1Ö=/Ô;+Ï9(Í:&Ï9(Ñ:)Ô8)Ø8*Ü5,Ü5,Ð/%Í3)Ì8,Ê>/Å@/Á@-¾=*¼9'Â9)¾0"éWJßK?Ã/#Ñ=1Î</Ç8(Ê;+É:)È9(Ç8'È7&É6&Ë5&Ì4&Ð7)×;.Ü>2Ü<0Ù7,Ú8-â>4ìC<õBEò9?ð2<ö4?ö2@ñ-;í-:í2=ì7>æ5;ä68å78ë99ð:9ñ78ï77ò;=î<<ê::æ87á85ß74Ü75Ü75Þ97á98ã99æ::é9;ì9<í9<ï8<ô7;ó6:ð8:í9:ç;9à;5×90Ï7,Ê8+È9)Ç9+Æ:)Ç:)Ç:(È;*Ç<)Á9#Ä='¾:#¶4¼9%ÉD3Ï?6Ê1,ÿ^eÿVgÿIbÿ<\ø1X÷0Yû6cõBiçYo¬FQo33N3,B?6>C<@78@-1L/3K2.A9&DJ(Zn=~š_ž¸w¨Å‚¬ÊŒŸ¾‚˜¶€”²~‚ nf„RXvBY{?]€>c‡AiDn”Im•Ll”Nk’Ol‘NiŽIfŠDc†Bc†Bf‰Ih‹KfŠLdˆJg‹MhŒNg‹Kf‹HeŠEf‹EjIk“Jq›QržSt U*0")/#).').(-/,130561782;<4>?7AD=HJGOPTSUaXYkZ\u\Z^]‰db”kj¤utº~·‡ß‹Œéð‰‰ë…„ ؀~Ҁς‚Ì…†É†‡È‡ˆË‰ˆÎ‹ˆÏŒ†Î†ÌŽ…ÈŠ€¼‰±†|¡‚x‘{s€tknlb`e]Re`Me^Kf^Kh]Ki\Ij^Hk_Gn^Ew_G[C’YF­ZLÇVPÞRSõQXÿX_ðUSãLEÙ>9Õ60Ù6/Ü90Û9,Ö9(Ó8&Ñ8&Ñ8(Ô8)×7)Ü6*ß4,Ý5,Î0'É5)È9+Æ=-ÄA/Á@-¿<*¾9(Ä8)Ë<.äREÜH<È4(Ì:-È:,Â4&Ê=,Ë<+Ê;*Ê;*Ë:)Ì9)Î8)Ï6(Ó7*Ö8,Ù7,×3)Õ1'Ø1(Þ7.ç<5øDGñ8>í/9ï/:ð0=î.;ë1<ë6?ä5:Ü36Ø22ß:8îEBøIFøDCó?>é:7ç98å97â96á85à85á98á98à87â88å99ç9:é9;ì9<í9<î7;ó6:ò59î68ê88ä;8Ü:5Ó9/Ë7+Æ8*Ã:*Â:*À;*À;*Á<)Á<+Á<)½9$Á?)»:%³5¹:'Á;/Ê:2Ø<=ÿ^gÿPdÿA[ù8Wö6[õ;`ô>dãIe«?Lƒ?>_:2G;/:>08>2F<:R>=N0.S8/VK5ciEx[°pÂ}¡Æš¹}š¹€š¶ƒ©xrŽ^YuETp=\{B_@b†@iCm“Hl”Kk“LiMiMgŒGe‰Cc†Bc†DgŠJiŒLhŒNg‹MiOiMiŽKgŒGgŒFfŽEl’Im•LpœQoRt U-1"-1#,/&,.)//-11/34/45-9;0<>1@B7EHAKMLQRWUUaVWi\Yt^]fdŒpn zx·…ƒÎ‹ßêŽïŽŒíŠ‰ç‡„ßÓ|Ë}ȀƅLjˆÆŠŠÊŒŠÉŒŠÉŒˆÅŒ„¿‹‚·‰€­†|¡€v{p€ujpndbi_Vc]M_aL_aKc^Jg\Jl[In\Ho]Gq]EwaIxX?‡S=£VDÇXOãUSøOTþMSâ><Þ<7Ý84Þ71á6/á6.Ý7+Ú7(Ô7&Ó8$Ó8&Õ8'Ø6)Ý5*à3,Ý5,Ë3(Ä6(Â9)Á<+Â?-Â?-Á<+À8(Ã5'ÜJ=ÚF:ÕA5Î</Ä6(Ä;+¾6&Æ:)Ç:)Ç:)É:*Ê8)Ë7)Ì6(Í3'Õ9-Õ7,Ö3*×3*Ú3+ß6/å:3é<8ð<=í49ë07ì18î3<í4<ë7@ê=CÝ7;áAAìNKøYUýZUúQLïB>å84â62à72à72à72á85â96ä;8ä;8á77ä88æ8:è8;ë8<ë8<ë8<ì8;ï58î47ì57ç77â:7Ù:4Ï8/Ç7,Â8+¿:+½;+»<+»<+»<)»<+»<)¸9&½@*³9$±6$¶;+µ0'Ã40ìPTÿ[iÿJ`õ:Uð7Vñ@]ïHfçHdÍNa‚89e?6R@2DA09=,57)>6+K9/E-#R=,g]Bˆ_’«t—»{–Áz–¿{”³xœ¸…š´…€šm\uKHb5Nh8[xB_}?cƒ@hŒDl’Gj’Ih’JgLfKd‰Dd‡Cc†DeˆFh‹KkŽNkOjŽNiOiOiMhJgHh’Hl”Ko™Ms¡Vs£Wv¤Y24&04&01)01+12-23.34.46+9;-;>-?A3DF9IJDMONRQWSS]XVd\Zoda~nl”zw¬„‚ÃŒ‰Ö‘㔑ê“뎋≅قÌ|Ã|¿€~½„‚Á†…Á‰ˆÂŠÃ‹ˆ¿‰…¸‡®…}¤…{€vŽyn~rgmmaak^Vi[Pc\J]`K]aJc^Jh[JmZKqZJtZIv[FsWAxR;ŠQ=ªYFÍ[PãTPðFIñ>AÛ2/Ü5/á51ã60ã5.á5+à6)Û8)Ö7$Ó8$Ñ8&Ô9'Ø6)Ü6*à3,Ú6-È6)½8'¼7&½:(¿>+Â?-Ã;+Ä8)Æ4'éUIÓ<1Ì8,ÑB4¾5%À=+À=+À8(Ä8'Å9(Ç:)È9)Ë7)Ì6(Í3'Ò6*Ô3)Õ2)Û4,ã:3é>7ì?9ì=:è45ì59ï6;î5;ê2:æ39ä7=â<@óUVübbÿmjÿidóVQäA<ß63Ý4/ß61Þ71Þ71ß82á85â96å97æ:8å78æ89è8;é9<ë8<ë8<ë8<ì7<î5:î68ê67å97ß<7Ö<4Ì9/Å9,¾9*º;*¶;)µ<)µ<+´=)³;*³<(³:'·@,­8&­8'³;-«+"Ã54ý`gÿTdúG\ð<Uë=XçG_áOdÒO_´SZvGAXH9KD2FE1BE0=?*:8#;3?3PG*nkHŠ“f•¬t‘´tŽ·s‘ºxž»…¡¸Š§}l‚[K_:AW0Lc7Wr?_{@dƒ@iŠCk‘Fi‘Hg‘GdHeŽJb‡Bc†Bd‡EgŠHjMlOm‘Qn’Rj‘Pj‘Nj’Lh’Jg‘Gi“Gm—KpœOv¥Wv¦Zx¨\78(68*66,56.56056067/68+;>-=@-@C.DG4IK>MNFQPNRRRVUSYX]a_lkius›€}²ˆ†ÇŒŠÓ•’ᔑâÜ‹‡Ó„Ä}º|µ|³~·„º‡„¹‰…·Š„²†¨z›€xs‡znzrfjm_^j[Ti[PjZKfZJb_Lb_Le^Li\Kn[Lr[Kw\K{ZG~UA†R=›RA¶VFÎRHÚG@â88å33Ý1-ß3/â5/ã5.á3,ß3)Ý5(Ü9(Ó8$Ð9$Ï:&Ñ:'Ô8)Ù7*Ý5,Ø7-Ä;+¹:)µ6%·8'½;+Â=.Ç;.Ç7,Ð90õ\TÖ=5É5+ÏA5¸3$·:(¼?+¿:)Ã:*Æ:+È:,Ê;-Ì:-Ï8-Ñ7-Ð3*Ò1)Ö1+Þ71å<7ê>:è;7æ74é75ï;<ð<?ê69ä15ä5:èBFíMOÿxwÿqnñ`[ÝJCÑ83Ñ2.Ü73ç@:à93à91à72à72â62ã73å76å76æ68ç79ê7;ë8<ë8>ë8>è7=ê7;î7;î79ê7:ä::ß=:Ö=7Ë;2Ã;/º8*µ:*³;*¯<)¯<*¬<(¬;)¬;)ª;(¬=*¦8'§9*ª8-¬/)Ë@CÿhrôM^óH[íDYåH[ÙO^ÉT]·TWœXUdM?OL9LG4JE1FD-?B'=D#>H#KV.\g<xT‹™f‘¤m©n²r—¹}Ÿ¶ˆ’§€u†dRcC?P0BS1Oa9Vl=b{Be‚BiŠCjEi’Fe‘FbHcŽGb‡Bf†CgŠHiŒJkŽNmPn’Ro“Sj‘Nk’Oj“Mi“Ki“Ij–InšKržOv¥Wv§Xw¨Y?=.=>.==1==3==5;<4;=2;=/?B/@D-CG.FJ3KL:NOAQQIRRHYWJZZN_^\gerqn‰{y¡ƒ€·‡…Čьӊϊ…ǃº~y¯zw¦yv¥{v¬|y®€|®ƒ}©ƒ}£x—|t‹zrvksrffm_\j\Sk[NlZLl[Kk[Ki]Mg^Mi]Mj]Mn]Ms^Mz]MZI“`O›VG§N@¸J=Å@7Ï6.Ø1+Þ1+á51á6/â5.â4-à2)Þ4'Ü6&Ú;(Ñ9$Í;$Ì;&Î;'Ñ:)Õ9*Ù7,Ó9-Á>,´;(°5#²5#»9)Ä<.É;/Ë7-Ù?7ø[TãIAÎ:0Ì@3¸6&¬3 µ<)¼9'¿7'À7'Ã7(Å7)É7*Î7,Ñ7-Ù<3Û:2Þ93å<7ê>:ê=9ç85ã41è96ë<9ì::è8:ì>@øPPÿbcÿppùheâTPÊ=6À1+É40Ö;7ß=:à;7â;5á:2â94á83ã73ä73å55æ66é69é69ê7;ë8<ë8>ê7=è7=é6:ï8<ì89è8:ã;:Ý>:Ó>7É<2À</¶8)²:)®;)ª;(©<(¨;'¥:&¥:(¥<) 9( ;) 9*¢6*µ>8ÛTXûepîK\ïI]éJ\ÛM[ÉQZ´VV ZRŠ`RPI7HM9NI5H@+;567>O%Lf6lŠTw”\„›e‰šd›f£k”­t˜°|ƒ•mn}\Q`C<J09F,AP1O_;Wj=czDe‚Bj‹Dk‘Fi’Fe‘FaFcŽGcˆCi‰FjKlMlOlOm‘Qn’Rm”Qm•Om–Pl–Lk—Jm™JrŸNs¢Q{¬]{¬]z«\DA0DB3DB6CC9CC;CC;BB6BC3DF0EH-GJ-JM2ON9RQ?TREUSD\ZC\\D\]Oaaaihxrq{z¦~µ†‚¿ˆƒÃˆ„Á„º{®ys¡to—om•plžrn¡vpžwršwr’to…skzrinmb`l_Wj\Qk[Lm\Lo\Mo\Kq[Mq[No\Nm]Nl_Om`Os`Oz_N†ZMŸ_S¤PE®B8º;2Æ6-Î1(Ö2)Ý5,â70á6/á4-à3,à4*Ý5(Ø7%Ô9%Ï:"Ê="É=$Ê>'Í<)Ò;*Õ9,Ï;-¿@-±<(¬5!®3!º8(Ä<.Ê:/Î5-Ø93ðNIñTMÙB9ÌB5¾?.¦1³<(¾<,Á9+Á7*Â6)Å7+É9.Ï;1Ô;3áD=ãA<ä?;ç>;é=;é;:è88ç85ç85æ95æ74é;:ôJJÿ\[ÿdcøc_Ì=9Á82½4.Ã81ÕA=ÞE@ß=;Ù42â;5â;3â94â94ä84å84ç77é77ê69ë7:ë6;ë8<ë8>è7=è7=é6:ë7:é69æ89à;9Û>9Ñ>6Æ<1¾<.³8)®;)ª;(¦;'¤;(£:'£:' 9&¡>+–7%œ=+š9)š2'ÃPKíkmî\fìP^éJ\ßHWÍKS¹RS¤[R’cQ€jUJM8DL7JB/H9$B7FH#Up=g“V~³o‚³qƒ¥h}’YƒYŽ–c‰—d|Œ_XfCGT89E-6B*:D,=J0JX7Wh>e|Fh‚Cl‹ElFi“Gc‘Fa‘GaGf‹FlŒImNn‘OlOkŽNkOm‘Qp—Tq™Sp™SpšPo›NqNt£Rw¦U|­^z­^y¬]IC3JD6IE9IE:IG;IG;HF9HG5IH3JJ2LL2NN4RP;TQ>XRDYTA]Y>[Z>\YH^[Tdahnk~xs“}x {§ƒ}«…­ƒ|¦}wunoi…kg‚ieˆjf‹mhˆmi‚mh|lfrkbgj`^g]Th\Nh[Kk\In]Kq_Kq_Kp]Lp]Np]Op]Ns]Ow]N~]N‡\L’XL¡UH¤F<«9/º7-Ê7/Ó6-Ú6-Þ6-ß6/ß4-ß4,ß4,ß7,Ý7)Ø6'Ñ6$Ï:$Ì<$Ê<&Ë='Î;)Ñ;*Ó:,Î<-¾A/¯<'¨3!¬3 ¶9'Á=.É;/Ì8.Ì2*àA;ø[TàI@ÐD7ÊF7«2¹>,ÊF7ÌB5Ê@3Ë?2Í?3ÔA7ÜE<ãF?â@;â=9ã:7â64ã54ä65å97å<9ä?9à=6Ü:5ß@:êMHêQLÓ@9¸)#¸-&¾5-É>7Ñ@;Ö>9Ú;8ã;;ç==â96â96â96ä86å95ç:6é99ê::ê88ê88ë8;ë8;é9<è8;ç7:ç7:é6:æ68â88Þ:8Ö=8Ì=5Â<1¹;-®9(ª;*¦;)¢;( ;'ž;&Ÿ:(›:'˜?-Œ5"™=.˜8*—/&Í\X÷y|ßX_æXdÚQ[ÊKR¹LO©VPž`UgU€nVPW8?J*<;C=UQ+lvDƒ¢f”Á~‡¼v†¸s|žan‚Mu~Q‚‡^u}V[b@;D)4<%5=(=D2<E29C+CP2Ue>g{HiƒFl‹Gm‘Gj“Gf’GbGcŽGhJlMo’Pn“PlMiŽKjJj’Ls›TsUsSržQržOs¢Rw¦Uz«Zv¦Zu¥[s£YRK;RK;RJ=RJ=RJ=RJ=RJ=RK;UN<VO=WP>XQ?YR@[TD\UE\UEb[HaZHaYLbYRe][kaiqftuj{zn„|pˆs‹s‰|p„uj{mbre]jc`k`_g_\c_Z^^ZY^YUaZRbZOe[Og[Ki\Kk\Ik\Gm]Fm]Fj^HicMqfTqZJuOB‹WJœ\P£YL¬ZL¥N=¦E4§<,±7(Â8-Ñ80Ü41Ý1-ß6/Þ7.Þ7.Þ7.Þ7.Û7+Ø6)×7)Õ8)Ô8)Ò9)Ò9)Ò9+Ò9+Ô8+Í;,½;+¶>-®9(©1 «2!·9*À</Ã9.È5+Î5-Ô:0ÛC8ÝK>ÔH9Â=,·2#ÝPFØJ@ÔF<ÔD;ÚG?ÞG@àC>à<:à74æ87ì::ì::ç77â64à93Ü=7ÙF>ÏB9Ä:/¼4(·1&¹5)¿;/Ã?3Ã:0É<3Ò?7Ú?:â=;ç;9ì89í9:ç7:å8:å8:å99å97å97å95å95à40á51ä65å76æ89ç9:ç9:ç9;ë;>æ9;ß99Ü=:ÖA=ÍB;ÁA6·?1©:)£<+ =*›<(™:&–:%—8&‘8&A0‹<-‡/#‘/&¼LJämoçloÍVZ½LNµNOªQM¢UO›XO—]R•aTŠjSWZ/:M7FTa)~ŽP›°oŸ¼yœ½x’µs~ah€L\mCYdBT]BHP9?D0:=,@C2<@1:>0<C3:C0AN2Rd>]sBgƒHpKo“Kl’Gj’Ii“KgJlPm‘So“Sl“Pm’Mk“Jm–Jm˜IqœLqžMrŸNr¡Pt£Rv§UyªYzª^y¦cm™ZbŽOWN?WN?WN?WN?WN?WN?WN?WN?XO@YPAYPA[RC\SD]TE^UF_VGd[JcZIcYMcYOf[Uj_]nbdpdhreltgpvirvirsfmm`gg[_bXY^[VZZRYVOWTKXTIXTH\VH^WGcZKcZIf[Ig\Hi]Gj^Fk_Gh`IcbMngTv\MSFšVM«VO°RJ·QE¯H9¬C0¬=,±9)¾8,Ë80Õ62Ù40Ý6.Ü8.Ü8.Ü8.Û7-Ú8-Ù7,×7+×7+Õ7+Õ7+Õ7+Ô8+Ô8+Ô8+Î:,¾<.¶>.®9(¦1 §2 ²:)¹>.¾<.Æ:-Ç4*Ë4)Ò;0ÜE:áOBßQCÝOCÛF?Ø@;Ó<5Ò;4Ö=7Ú=8Ü86Ý33ç77ë78î79ë78ç77å97â=9ÛB:ÊA7¿?4¸:,±6'¯5&²8)¸=-¿@1ÅA4Í@6×@7ß=8ã:7é77ï56ñ7:é6:ç6<ç7:æ89æ87å95å95ã:5â92ã:3ã:5ä;6ä;8ä;8å99å99ä:;ã;;ß<=Ù?=ÐA;Ä?6·=2¬;-¥;+ =*œ=+—<)–;(’:&“8%Œ:%€9'€8)‰5*<5¿QP×eeÑ^a·MM¬NL¤TMYP˜\Q—^S—^S˜_VŒfQ`_/Sg*^r3zO™¯n¥¾|™²pˆ bj‚HauBTe;JX7FP7?H59?158-:</AB4=?4:=2=A3:C0@M3Rd>^tEgƒHqMp”Ln’Hk”Hk“Lh‘Km‘Qn’Tm”Sm”Qk“Lk”Hl—Hm˜HpJpJp Ls¢Qu¦Tx©Xx©Xx¨^m—Xb‹QY‚H]TE]TE]TE]TE]TE]TE]TE]TE[RC\SD]TE^UF_VG`WHaXIaXGe]Je]Hd[Jd[Le[Qf[Uh]Yh][i]]j^^k__k__i^\f[YbWS_VQZVMWTKUQHRNCQMBSOCWQCXRB^WG^WEaYFc[Fg\Hi^Hk`JhbLbaMngUy_PˆXN¢[U±VQ²IE¸E@¹@7¸>1·;/¸8+¼8+Ã9,É;/Ñ:/Ù8.Û7-Û7-Û9.Ú8-Ù7,Ù7,×7+×7+Õ7+Õ7+Ô8+Ô8+Ô8+Ò9+Í;,À>0¶>.­:(£2 £3ª:&³>,¹>.Ä?0Ä8+Å2(È4*Ð<0ØF9ÜM?âNDÙ:6Ø43Ô20Ö42Û97á=<æ<<é;<í9<î5:ë27é26è58å99á<:Ù@:¾8-µ:+±6'®4%­5%°8(µ<+»=.ÈD5ÏC6ÖB8Ü=7â94è64í55ï79ê69é69é69ç77ç77æ95å95å:3ã:3ä;4ä;6ã<6ã;8â:9á99Þ88Ý9:Ü<<Ú@>ÓB=È?9¹:1­7+¥7(¡;,<+™<+”;)“:(9&7%Š9&z6#y6%ˆ9, F=¹SOÀWT¸PO«IF¢MHœSL™YP—^S—aW—aW˜_V‹ePsrFzV“¦n¤¹€«À‡ž³{|[[o<?R$AS+AP/?L2:C06<.69058/9;.@A3=?49<1=A39B/@M3Qc=`vGi…Js’Or–Np”Jm–Jm•Nk”Np”Tq•Uo–Sn–Pl”Kl•Il—Hn™IpLpLpŸNu¤Sx©Xyª[u¦Wq X_‰JVEOx>aXIaXIaXIaXIaXIaXIaXIaXI_VG`WH`WHaXIbYJcZKd[Ld[Je]Hf^Gf^Ig_Lg^Of\Pf\Rf\Sh]Wh]Wh]Wh^Ug]Te[QdZPc[N]YMZVJVRFRNBPL@PM>TN@UO?WQAYTA[VC]XDaZGd]Jf_LfaMdcQleUv\OŠ[Q©b\¸ZX¶FD¹<:Ã<8Æ;6Ä:0Â8-½8)¼:*¾?.Ç?/Ó9-Ù7,Ú8-Ù9-Ú8-Ø8,Ø8,Õ7+Õ7+Ô8+Ô8+Ô8+Ô8+Ô8+Ò9+Í;,Á?1¶>.¬9'¢3 3¢8"¬=)µ@.¼?-¿:+Ã7*Å5*Ë7+Î:.Î</Ó:2Þ65à24Û12Ý34à88å;<ê=?ì<>î7<ì38é06æ25å58á77Ú65Î61·5(¯7'®6&¬7&¬7&®9(²:)µ:*ÃA1ÊB4ÔA7Ü?8â;5æ95ë76î87í68ë78ë78ê86ê86è94ç:4æ;4â92á:2ß:4à;7Þ:8Ü:8Û97Ù99Ö<:Õ@<ÒC=ÊA;»;2¯6+¤6'ž7(œ;*˜;)”;)’;(:&8$Œ7#‡9%€=*v5#5'™E:ªPH¬MG©LG¦QLPJ˜UL”ZO”^R•aV•aV—aWgT‰…_™©x­½Ž¦¸ˆ¡ts†YN`8/A->3B%:F.=F3;A3:=2:=4<=599-?@2<>39<1<@29B/?L2Pb<awHj†Kt“Ps—Or–Lo˜Lo—Pm—Op—Ts˜Up˜Ro—Pm–Jm–Hn™Jp›KqžMrŸNt£Sy¨X{¬]w§[mSe’M[…FS|BNw=cZKcZKcZKcZKcZKcZKcZKcZKcZKcZKd[Ld[Le\Mf]Nf]Nf]Lf^Gg_Hh`IiaLiaNi`Oh_Pg^Oj`Ti`Qi`Qh_Nh_Nh`Mh`MhaNd^N`ZL[UGVPBPM>NK:NK:NK:PM<RO>TQ@VS@XWC[ZF]\H^]Kb`Qf^QmWJ†[R¬ic¾c`ÁMMÈBCÐ;=Ô89Ó84Ì70Á9+º=)µC+¼B+Î;+×7)Ø8*×:+Ù9+Ö9*Ö9*Ô8)Ô8)Ô8)Ô8)Ò9)Ò9)Ò9)Ò9)Í;,Á?1¶>0«:(¡6"š4›7 £=&¯B-³;*º;,Â:,Ç9-Ë8.Î:0Ð<0Ù:4é9<ì4<æ39ã28â38á48â38â25é6<é49ç4:ç7:ã9<Û76Ð21À0(´6(­:(­:(«:(«:(«:(¬9&¯7&¸:+Á;/Î>3Ø?7à=8ä;8è96ì87î66î66î66í74ê84è:3ç:3ä<3á:2ß;2ß<5Ü=7Û=:Ù><×=;Ô>=Ï@<ËB<ÅB:¹=5­7-£5(ž7(š:*–;)“<)‘;*:(Š9&‰8%ˆ7$ƒ8%ƒ@-u4"{3%“G:¤QI¡NFžNG¡WN˜UL’XLZN\N]R”`U—aWhW‰f˜¥z©€Žj]kHDS42@&$2-:&0;*5=.9?3<?4=?4:;3::099->?1;=28;0;?18A.>K1Pb<bxIk‡Lu”Qt˜Ps—MqšNq™Ro™QršSršSršQp™Mm—Km˜Ip›LsžOt Qv¢Sx§Y{©^z¨_qŸVd’JY†C]†JW~GRyBe\Me\Me\Me\Me\Me\Me\Me\Me\Mf]Nf]Nf]Ng^Og^Oh_Ph_Ng_Jh`IiaLjbMjbOjbOjaPjaPjaPiaNh`Mh`Kh`Kh`IiaJjbKf_Mb]J^XHXRBSM=MJ9KH7IH6KJ8LK9LM;NO=PQ?QTASVESVE[YL^VIcQEzXN¡ha¶eaÄVUÖQRÙ@Cß:>Ü87Ô70Ç;.¼?+±C*µA(Ê;*Ô7(Õ8)Õ9*Ö9*Õ9*Õ9*Ô8)Ô8)Ò9)Ò9)Ò9)Ò9)Ò9)Ò9)Í;,Á?1µ=/«<)¢9$™6•5›;"§A*²B.¹@/¿;,Ã7*Å2(Ë4+Ò;0ß=8ê5:î3<ë6=é8>ç:>ä;>ã:=â9<ß58á7:â9>á=>Û=>Ñ96Ã2/¶0'¯9+«>*«>*©>*ª=)©<(©:'«8%¯6%¹7)Å;0Ð=3Ù<5ß<7ä;8è;7î87ï75ï75î85ë:4é;4ç<4ä=4â>5à?7ÞA:ÚA;ÙA>ÕA?Ñ@=ÍB?Ã?:»@8³=3ª8-¡5(›5'˜8(•<*‘<(<)Š<(ˆ:&†9'„7%ƒ6$6%}:)t3!~9*—OA£YNœRG•OE˜VJ•YN[MŽZMŒ[MŽ\Q“_T™`W‘gW~xXyƒ^r|ZU`B;E,/;%0;*0<.3=24<16<2<?6@A9?A6<<077+89+>?1:<17:/:>07@-=J0Oa;bxIk‡Lu”Qu™Qt˜NqšNršSpšRršQsœPr›Op™Kn™Jp›LsžOv¡Ry¥X{§Zz¨]x¦]qŸWg”O]ŠEX‚B`‡NY€ISzCg^Og^Og^Og^Og^Og^Og^Og^Og^Og^Og^Oh_Ph_Ph_Ph_Pi`OjaPjbOjbOjbOi`Oi`OiaNiaNiaNh`Kh`Kh`Ih`IhaGhaGhaGf_Le^Kb[I\WDWR?PM:LI8IH6IH6GH6GJ9GK:HL;IM<HO?JN?PQCXRF[OCiRDƒYM–VL°SLÔZYÛIJâ?Bá99Ú72Ï;1Â?-´B*³<$É:)Ó7(Ô8)Ó:*Õ9*Ó:*Ó:*Ó:*Ò9)Ñ:)Ñ:)Ñ:)Ñ:)Ñ:)Ñ:)Í;,Á=0µ=/¬=,£<)˜8 4•9 ¡A)­C-¶A/¿=/À6+Â/%Ç0'Ð6.Þ:8è59î6>ì;Aê@CæAEàBCÜ@AÙ??Í12Ð66Ó:<Ñ=;É;9¾71µ4.­4)ª<-¥>+¥>+¥@,¥>+¤>(¦;'©:'ª7%²7'¼8+Å8.Ì70Ô94Ü=9æ>;é:7ì95ì95ë:4é;4è;4å=4â>4àB7ÝC9ÚC<ÕB;ÏA=Ê?<Ç=;¿>9±<3©:/¢8+œ6(˜7'”8)‘:):(‹=)‰<*‡<)ƒ:'‚9(€7&6%}6$x3#x5%…B2˜UEWK”PCPD•ZL“YMZN\Q\Q’[T•\U˜[VŽbUkbEV`=JS4=G,6?*2=,4>35?66=68?8=B;CF=EG<CD6@>/;9*78*=>0:<17:/:>06?,=J0N`:awHk‡Lu”Qu™Qt˜Nr›OršSpšPq›OrNqœMp›LošKrNu¡Ty¥X«`~©az¥]qœUf‘L_‰G]‡E^ˆIb‰PY€ISzCh_Ph_Ph_Ph_Ph_Ph_Ph_Ph_Pg^Oh_Ph_Ph_Ph_Ph_Pi`Qi`QmdUlcTjaRi`Qh_Pg^Og^Mh`MiaNiaLiaLiaLh`Ih`IhaGh`IgaKf_Le^Kb[H\WDUR?PM<ML:EF4DG4DH7DH7BI9BK:BK:CJ:IK>SQDSPAXL<eK:tE5•H>ÂYSÙROàDEà::Ü75Õ;3Ê>/º=)µ8"É:)Ï8'Ð9(Ò;*Ò;*Ò;*Ò;*Ò;*Ñ:)Ñ:)Ñ:)Ñ:)Ñ:)Ñ:)Ñ:)Í;,Á;0¶:.­<,§>+™9#3“7Ÿ?'£9#°;)À>0Æ<1Ì8.Ð7/Ù<5ã?=ì=Bî?DéCEâDCØ@?Ê;7À50»1.¹/,¼51¾:6»<6³:2ª8.¤8,¡:+¡=-Ÿ>+ ?,¡@-¡@-¡A+£>*¦=*©;*­:(²7(¹5)¿5+É90Ô?9àC>ä=7è;5è;5ç<4å<5ä=4á>5Þ@5ÜD9ØD:ÒC;ÊA9Ä?:¼;6¸85°93¢7-™8(•5'“6'‘:)<*‹:)…8&ˆ=*…<+ƒ<*€<)~:'|8%{6&{6&y1#€8*ŒG8–SC’PB‹L=RE™_S‘WL’YN”[R–]T–]V—\V–YTŒ^QaX;EM(6@8A&>G2<E43=2-7.1817>6BE<GJ?HI;BC1?>*;:&78(=>09;069.:>06?,<I/N`:awHj†Ku”Qt˜Pt˜Nr›OršSpšPqœMqœLqœLp›Kp›LsžOw£V{§\‚­e€«dx£\j•P]‡EYƒA^ˆHePcŠQZJSzCi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi_Sj`Wj`Wj`Wj`Wj`Vj`Vj`TjaRjaRjaPjaPjbOjbOjbOjbMjbMg_Jg_Jf^Ie_Ib]IZXCSP=ML:HI7EH7AE6@D5?E7?G8?G8>F7GK=IK=AE4KJ6\Q;aE/ƒJ9Àj]Üg`ãUSäFEåA@àA=Õ>5É=0Æ=-Æ4%Ë5&Ì6'Í7(Í7(Î8)Ñ;,Ó=.Ò<-Ò<-Ò<-Ò<-Ñ;,Ñ;,Ñ;,Î<-»2(¶7.±;/¨:)š7"”5•7œ9"®A-³;+º6)Á4*Í6/×<7âC?êHEèDEèEHÝCCÉ:6»61´80®8.©4+«9/©9.¤8. 8-›9,–:+“<+’<+–=+˜=*™>+š?,›@-A, A-£@-¢;*¥:(«7(°6)¶6+¾8-Ä;3Ì<4Ú=6à=6â?8âA7âA9ÞB6Ú@6×@5ØH=ÒE;ÇA8»;2²5/ª3-¦1*Ÿ2+™9-’;*‘9+:*‹:)ˆ;)‡;+…<+€9'}8(|9(|9(|9({8'y6&x3$w- ‹A4—OC“MAŽL@‘QE“UJŽRG˜\R˜\R‘UMTL—ZU•XS”WT“gZ]T5IQ*AK(BK,>H/7@+2=-4?14<1HPCZ^PW[JMO:DF.AA'==%:;)>?1;=2:=2;?14=*;H.Pb<cyJlˆMu”Qs—Or–Lp™MršSq›QpLqžKrŸNrŸNsŸPv¢U{§\ªb‚­fx£^j“O`‰G^‡Ea‰JfŽPhTd‰S[€LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi_Sj_Yj_[j_[j_Yj_Yj`Wj`Vj`Tj`TjaRjaRjaRjaRjaRjaPjaPh`Mh`Kg_Jg_Jd]J^YEUR?ON:IJ:EH7BD6@D5?E7>F7>F7=E6@F8>E5>F1HL5MI0U?'Q:¼sbËcXà_ZëUTçGGâ@>àA=Ø?9Î:0Í9+Î=,Ï=.Ï>-Ï;-Î;+Í9+Í:*Î:,Ð:+Ð:,Ð:+Ð:,Ð:+Ð:,Í;.É?5ÅB:¼B7®=/Ÿ6#–1–1›2¨5#´6(Ã;/ÑA8ÞE?æIDéJFêKHÞCAÛEDÐB>¼<3¯9/©=0¥?1Ÿ=0Ÿ?1œ>2—>0”>/=/Š>.‡@.ˆ?,Ž=*‘;*’<+“=,”?+•>+—>,™>,Ÿ@.¡=-¤:,¨8,¬8+±8-¶:0¼9/Ê<2Ð<2Ó?5ÕA7×C9ÖC9ÔD9ÑE8ÊB6ÃA4¹=3°:0©6/¤5.Ÿ4,™7,’:.Œ=,Š;,ˆ;+†:*„;*ƒ<*<,~;*|;){9)y:)x9(w8'u6'w4$€4'D7˜NC‘K?ŒJ>QD’TIRG“SJ˜XO˜UO—VPœ]X”WRŽSOŠcT]W5Xc9_jBZfBIT66C)4@*<H4OXGYbQ_fTW\FJN7BE*??#<<"9:(=>0:<19<1<@25>+;H.Pb<dzKlˆMu”Qt˜Pr–LqšNršSq›Qs OrŸLpLqžMt Qx¤W|§_ªc{¦aošUcŒJ]†Da‰JeNeNc‹Od‰S[€LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi_Uj_[j^^j^^j_]j_Yj`Wj`Vj`Tj`Tj`Tj`Tj`Tj`Tj`Tj`Vj`TlaOk`LiaNiaNf_La\HYVCSR>MK<HI9DF8AE6AE6?F6>D6<D5=F57@-@H1IK3F?%W?'‡ZC·s`¶VJÙbZðebìTSæFHëGHæCDØ;6Ë7+É:*É:,É:*Ë9,Ê8)È6)È6'Ê8+Ë7)Ë7+Ë7)Ë7+Ì8*Ì8,Ë8.Â3-¾5/¶6-­3(¡0"ž/ 1 §3$¼A2ÇC7ÖG?áLFçLGéJFåFBßD@×CAÏDAÁ@:±;1¤</¡A1œE4˜E3“D3‘D4B2ŠA0…@0‚A/~A.@.†:*‹9+‹:)Š;*‹<+<+Ž=*<*–?.–=-›;+9* 8+¥9-©;.®9/¸:.¾90Á;0Ä>3Å?3ÅA4ÃA3ÁA4¶;,²:,ª8-£7+ž6+›6,˜7.”:/;/ˆ<,‡;-„;,‚:+€;+€;+<,};+z;*z;,w9*v8)u7(t6)v4&ˆ;1”F<–NBŽJ=ˆH<OB‘SH’RI’OI™TO™SQšVSš]Z“YU[Tl[}X~‰^€‹alxRLX46D#=J.LZ@eqYeoW]eMPU>EI0?C(=@#:<$89';<.8:/9<1=A36?,<I/Pb<dzKm‰Nv•Rt˜Ps—MqšNršSpšPu¢Qp LnLpŸOu¤Vy§\}¨`|§`p™UfM\„E\„EeŒMiQfN_…HcˆRZLSxEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QjaRjaRjaRjaRjaRjaRjaRj`Vk`\k__k`^k`\k`ZkaXkaWkaUkaUkaUkaUkaUkaWkaWkaXkaWnbRmbPjbOjbOhaNe^K_ZGYVERO>MK<GH:DF8CE7BD6@D5<C3<H49B-FJ3LF0O:%qL9šcOª^N¡A5ÆSLçc_ð^^íSUëJOéDHáAAÌ91Ç9-Å7+Å7+È8-Ê:/Ë;0Í:0Ñ>4Ñ>4Ò>4Ò>4Ó?5Ó?5Ó?5Ó>7Ó?;ÑB>ËD>ÆF=ÂF<ÃI>ÇM@ÎPDÙSHÝPGâMGäIEäGBâC?àA=ÛB=ÕFBÉD?º?7«=0Ÿ>.šC0•G3”I6F4ŒE3ˆC3…B1€A0}@.zA.|?-‚:,†8,…9+†:,†:,‡;-‡;+ˆ;+‰:+‹:)Ž8)8*•9,™;/=/¢<0ª:/­8.¯9/°:.°:.°:,¯9+®8*¨7)¥7(ž6)›6*•7+’8-‘9/Ž<0ˆ<.…<-ƒ;,9*:*~9*}:*};+|:,z;,y;,w9*s8*q6(r7)u5)ŒD8’H=‘K?ŠH:‡I<‹OD“TK—TL–QL›TP˜QO”SO–\X_Xh^—~j””p…’fu‚WYh?CR+?O*P`<crQetU\iKNX=CL1?E+>B)=A(;='78(:;-79.9<1=A37@-<I/Oa;bxIlˆMv•Ru™Qt˜Nr›OršSo›Pq OožMožMs¢Rz¨]|ªaz¥^u [cŒJ^‡E[ƒD_‡HgŽOj‘PfL`‡Hb‡QY~KRwDi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QjaRjaRjaRjaRjaRjaRjaRj`Tk`Zk`\k`ZkaXkaWkaUkbSkbSkbSkbSkbSkaUkaWkaWkaXkaWocUnbRkbQkbQkbQhaOd]M`ZJXRBRO>NK<IG8GE6DE5BC3>B1=I1?G/LG1S>+g=-•ZL­_Sœ>4ž3+¶?9ØXUóigödeëRUæJNèNPÙIAÓF<Í@6Ë>4Î@6ÒD:ÕG=×G>ÚJAÚJAÝJBÝJBÞKCÞKCàKDàKEëSRèTTãSRÜROØSLØSLÛULàUNàLHáIFãEBâC@äB@âC@äEBàFDÙJFÊE@¹>7¬=2¡?2˜B1’E3G4ŒE3ˆC3‡B3ƒ@0?1~?0z?/|>/€:.ƒ9.ƒ9.ƒ9.ƒ;-ƒ;-ƒ;-ƒ;-9*‚9*…9+‡:*‰:+;-<.“;/›;/ž9-Ÿ9- :,¡9,¢8+¢8*¢8*Ÿ8)œ8)˜8(”8)9*Œ:,‰:-‡;-„:-‚:,9+€8*}8)}7+|8+{9+z8,y9-x:-v8+q5*o5)q7+t9+ŒH;I<‰I=„I;…K?ŒRF“WM˜XO˜QMœUQ˜RP“VQ’`YˆbWƒg[†zdnrQZi@JY0AR(IZ0Wi?dvNj|VXiEL[:?L.:D)<D,>C-<A-:=,89+:;-68-8;0>B47@-;H.L^8_uFi…Jt“Pt˜Pt˜Nr›Os›TpœQnMmžLp¡Pw¨Y|ªaz¨`rXi“QZƒA\„EaˆIeŒMgŽMgŽKhJfŠLc†PY{IRtBi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkaUlbYlbYlbYlbVlbVlcRlcRldQldQldQlcRlcTlbVlbXlbXlbXocUnbRkbQlcRlcRkbQg`Pd]M^WGYSCSM?MJ;KH9GE6EB3?B/;H.?H-OC-a=-ƒE:«XR´NJž,+²:9¹=;ÓSRòpnþvvñehëX^ð^_ãUQÚPFÔG@ÐC:ÑD=ÔG>ÖGAÖG?ÙHCÚJBÜHDÝJCÞJFÞKDàKGàKGâHHáGIÜHHÙGGÖHD×HDØGBÛFBàBAäABæBAèBBçCBäB@ßA>ÛA?ÛJGÊC?¹<6®>3¢@3˜A0A0C3ŠA2ˆ@1‡?1…=1‚<0€<1=1=1;1;1ƒ:3;1;1€</€<1=/€</€=-<-€;,‚:,9*‚8+ƒ7)Œ:.8.‘9-”:/—;.š=.ž</Ÿ>.™9)–9(“:*:+Š;,‡;+„;,‚:+‚:,9+7)~6({5){5){5)z6)x6*x8,w9,s8*p4)o5)r:-v<0‹M@‰K<„J<‚M=…QC‹VH’XM—WN“NI™TO—VR•\Ue\{^PfVF`^GEO->N)?O(J\2_rEk~QexKXj@M_7@Q-6E&7D*=F1=D4:>07;-8:,:;-68-8;0>B47@-9F,I[5[qBeFr‘Ns—Os—Mr›Os›TpœQmœLo Os¤Ux¨\z¨`s [i“Q`ŠHYB^†GeŒMgŽMfJeGgŒGhŒLa„NXzHQsAi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSlbXlbVlbVlcRlcRldOldOldMldMldMldOldQlcRlcTlbVlbVocUmaSkbSlcTmdUlcTi`Qf_Ob[K^WGXQARL<OI9JG6IC3AC.:G+@F*U@+xG9£PL´HH¶8<º39ÈAEÄ?@ÊJIßb`ñqpðnpçbeâZ\ÛQNÕLDÏD?ÍB;ÏD?ÐE>ÐB>Í@9ÒC?ÒC=ÔC@ÕD?×CAØD@ÙECÚDCÝADÝADÞDFÝGHßIHàJIãIIåGHçACêADìBEìBEçAAâ@>Û=:Õ=:ÚFFÉ=<¹83°;2¦@4˜?1‘>0@1Š</Š<0‰;1ˆ:0‡81†93…:4„;4;3€<3:4€<3<3}=1}=3|<0|<0|=.|=.{<-|:,{9)z8*{7*‚:.ƒ9.‡9-‰9.9.‘;.•<.–=-’9)‘:):*Š;*‡;+ƒ<*€;+~;*€8*€8,~6*}5)|4(z4(z4*y5*u2)v6,v8-r6+o3)o5*s:/x@3ŠPB†N?N=‚Q@…VF‰XIŽUJ‘RI’OI—TN“TO‘\VŠfZn[JPK7EK1AN0KZ9WgC`rJgyOdzLVl>G]/AV-7H$1@!6B*=F5<D98=67:39;.;<.68-9<1?C57@-7D*FX2Vl=a}BoŽKq•Ms—Mr›OtœUqRožPq¢Qu¦Wv¦Zs¡Yj—RbŒJ[…E^†H`ˆIcŠKeŒKfJfŽHf‹Fe‰I`ƒMWyGPr@i`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSlbVlcTlcTlcRldQldOldOldMldMldOldOldQlcRlcTlcTlcTnbTmaSmaSmaSmdUlcTjaRg`Pd]M`YIZSCUN>PK8MH5ID1DC.@F*DD([B,ˆTG¯\X«>A¬/3ÎINÆ?EÀ;>»;<ÄFGØZ[ãefÛY[ÌGHÑJGÐEBÍB?ÐB>ÔFBÔFBÐB>É>7ÏD=ÏD=ÒD@ÔEAÖEBÙECÚDEÝDFÞ?Cß@DÞBEßEEáGGàFFàBCá>?èBDé@Cè>Aç=>ä>>ãA?áC@ßECÖBBÅ98¶50°;4¦?6š>3=/?2ˆ</‡:0‡:0‡81‡83‡83ˆ94ˆ;5‚92€:2€:2;2~<0~<0|<0|<0x8,y9-z:.z:.{<-{<-z;,z;,};/9/€7.7,„6*…5*†7*†7(Š8*ˆ9*ˆ;+…<-„<-€=,~<,};+}9,}7-|6,y5*z4*x4)x4)x5,r2(u5+v8-r6+n4)n5*t;0xB6ŠUG„PB€O@„SDˆWIŒVJŒRGNG•TN”UN‹RK„XMdSeZDGK2=J,IX9ZkIgxTcxQYnESh=Nc8J_4:L&0?,95>)=C5<B8:<79<5;=2;=079.9<1?C58?-8B)EU1Uh;azCnŠMr“Nr–NršQsSqRr Uu£Xv¤[t¢ZošUfN^ˆH[ƒDdŒNa‰K`‡HcŠIfJgŽKeŠEa…E`ƒMWyGPr@i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbQkbQkbQkbQlcRlcRlcRlcRlcTlcTlcTnbTk]Pp`QtdWrdWnbVj`Th`ShbTgaSgaQc]M[VCVQ=SN8NH2GA)KG,I?$bI3‘gW¶xm»le¸YW¹OO¶BE½BEÂDGÈFHÍHKÐJKÒLMÓKMÏEEÐDEÓEDÖFEÕFBÒC=ÎC<ÏF<ÈD8ÉE9ÊE<ÌE?ÒD@×CCÚADÛ?CáBFâBDáCDàDEàDEáFDãEDäDDãCCäB@ä@?ã?>ã?>â@=â@=ÞC?ÓB?Å>:¶93ª70Ÿ:0—=2Ž>3†>2ƒ?2?3=2;3„93†93ˆ81ˆ92…;0„<.„<.ƒ;-;/€:.€:.€:.~:-~:-~:-~:-};/};/};/};/}90}90~80~8.€7.€7.€7.~8,€8,~8,}9,|8-{9-z8,x8,x8,x8.x8.w7-v8-v6,t6+s5*q5+m1'r6,n4)m3(o6+m4)q8-I=…SH…SJ†RGˆRH‹PHQJ”QK•RL“TMTK‰[N‚cQo_HYU:MV7O_;j~YbxQYoHUjCRg@Mb;IY5CR17D&4>#2:#6;'<>0@B5@@6<>358-39-4:.7:/9=/;?.=B,<E(S_;arFn†Rs‘Ur•QršSsSrUužZ~§e~§ep˜YbŠK^†G^†H^„G`†IbˆKdŠMfNeŒMcŠK`‡H^„G_‚LTvDKm;i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTnbTrbSqaRrbUqcVrfZogZmeXjdVgcWkhYoiYlgThcOc^H[U=RL4PJ0H>%Q?)kP=XG„NBˆE=“D?±WV¸TT»QQÀPOÀNMÁMMÂLJÃKJÐTTÈHGÂ=>Ä=:ÐB@ÓEAÏB;Ç>4ÊD9ÉE9ËF=ÍG>ÔFBØDDÜAEÝAEáBFáCDáCDâDEâDCáFDáFDáFDàEAßD@àB?ßA>àA=àA=àA=ÞC?ÔE?ÈC<º>6¬:0 90”:/Š<0‚<0€A2~@3~>4<3ƒ:3†91ˆ81‰90‡;.…<-„;,„;,ƒ;-‚:,‚:,‚:,9-9-9-9-~:/~:/~:/~:/}90}90}90}90}90}90|90|90|90z:0z:0y9/y9/y9/w9.w9.w8/w8/t8.s7-r6,r6,p6+p6+k1&q7,m4)l3(o6+l3(p7,~H>„RI…SLˆQJ‹PJQL”PM•QN”SOŠOG…SH€[K{ePsiPhkLfqQgxT^tMXnGPf?La:K_:K\:GV7CP4<F-8@)6;'7:)<=/?@2>>2;=04:03;05;16<0:</<?.>A,>D*Q[9^mDkRpŒRp“Sq™RsSsžVxŸ^|¢exžak‘T`†I]ƒF]ƒF\‚E`†Ia‡Jc‰Le‹NdŠMbˆK`†I^„I]LRtBIk9i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTnbTqdTo_Pm]Pm_RqeYog\ldYhbVfbWpl`{xi~{jyizubpiVe`JTT<FF.C>(MB.S@/U8(]7*l=3n70u91~;5‡@:’IB›PJ¥XP­ZR»^YºSN·GE¼B?ÈDBÑFCÓD@Ï@:ÐA;ÐC<ÒE>ÔG@ÖGCÚFFÛEFÞDFßCDßCDßCDßCDàDEßEEßECßECÞDBÞDBÜD?ÛC>ÜC=ÜC=ÜC=ÛC>ÖE@ÎE?ÃB<³>5¢:1”8-ˆ9,ƒ;-‚@2@1~>2=1ƒ:1†91‡81ˆ:0‡;.„;,„;,„;,‚:,‚:,€:.€:.9-9-~:/~:/~:/~:/~:/~:/}90}90}90}90|90{8/{8/{8/{;1{;1z:0y;0x:/x:/x:/x:/t8.t8.s7-s7-r6,q5+o5*o5*j1&o6+m4)k2'l6*i3'm7+}G=‡PI‡PI‹PJŽQL‘RM’SN”UP‘VPŒWO‡[P~^OtbNoiQorUlwYfwUQeBK_:EY6DU3EV6GV9GT8ER8?I0<D-9>*7;*:<.<>0;=/9;.6<25=26<26<0:</<>0=@-=C)MW5Zi@f|MlˆNn‘Qq™RuŸUtŸWz¡`w`n”Wc‰L\‚E\‚E\‚EZ€C_…Ha‡JbˆKdŠMc‰La‡J_…H]ƒH[}JPr@Gi7i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTnbTrdWoaTm_Rk_SkaWlcZle[jf]jf]xtiˆ„x‘•’Œ~‰‚r}zg`cNOT>DG2FE1HC0F=,L<,VC4P9+R6*V4*Y5)\6+a9/e=1m=1ŠKBSJ®UO¶NK¼FDÆABÒDCØFFÔ@>ÕA?ÖB>ÖE@ÙECÚFDÛEDÝEDÞDDßCDßCDÞDDÞDDÝEDÝEBÞFCÛFBÚEAÙD>ØE>×D<×D<ÙD=ØE>ÔD<ÓF?ÉF>ºA8§;1˜8,Œ9+…<-ƒ@0@1~?0=/ƒ:1„:/‡9/ˆ:.„:-„;,„;,ƒ:+‚:,‚:,9-9-9-9-~:/~:/~:/~:/~:/~:/}90|90}90{8/{8/{8/{8/x8.{;1y;0y;0y;0x:/x:/x:/v:/s7-s7-s7-r6,q5+o5*o5*m4)j1&o6+l3(h2&k5)h2&l6*|F<ŠOGŒOJPKRMSN‘VPWPŒZQ‰]R…aUy_PiZGd_IdhO\fKN]@EU8AQ4=M0<K.?M3CQ7FR:GS;BL4>G2:A/9=,9=.9=.8<-7;-7=36=56;46<2:<1;=/<?,<A*JS4Ve>bxIj†Ln‘Qs›Tw¡Wx¢Z{¢ar˜[e‹N\‚EZ€C\‚E\‚EZ€C_…H`†Ia‡JbˆKa‡J`†I^„G]ƒHY{HNp>Eg5haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTrfXth\sg[mcYjaXle]snhzwp~w† ”¨¥œ«§œ¨¤™£‘™–‡z{kcfSOR?GJ7EH5BE2BE2EH5KL<JH9GD5D>0A9,A7+@6*F4(S5*qB8ŒPHŸPK¯IG¿GIÌEIÓBEÖ@BÙ@BÚBAÛCBÚEAÚEAÜDAÜDAÞDDÞDFÞDFÞDFÞDDÝEDÝEDÚDCÚFB×FAÖF>ÔE=ÔE=ÓF=ÔE=ÕF>ÔA:ÓC;ÎE=ÁB9®>3ž9-‘;.Š</„?0?/€>.€=-;/„:-†:-‡;.„:-ƒ;-‚:,‚:,‚:,9+9-9-~:/~:/~:/~:/}:1}:1}:1}:1|91z:1|91y90y90x8/x8/v7.y:1y:1x90v:0v:0u9/u9/t:/r7/q6.q6.p5-o4,n3+n3+m4+j1(m7-j4*h2(j4*f2'j6+}D;NGNHQJTLUOŽWPŠYRƒ[Q{YMv\OkZJ]UBYXDY^HOYA?K3:H/7E.4B+5A+8D.=I3CL7EN9BK6?H5<E2:A/8?/7>.5<,4:,5<45<56;56;49;0:</;>-;@)GP1Ra:`vGi…Ko’RuVy£Yy£[xŸ`n‘W`ƒIZ}C[~D^G^G]€F`ƒIa„Jb…Kb…Ka„J`ƒI_‚H^IW|ILp@Bf6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTkaUndZpf\lcZkd\rmg„|‘Œ§£ µ±®ÄÁ¼ÉÆÁÉľÅÀºÀ¹±¹²¨¤œˆ‚rfcTPQ?FI8>E3;D1:F28E38E38C2:B3<B4@C8CE:GE9>4(P:/e?6€EA¡PO¿X[ÊQVÊCIÕFJ×EFÚFFÛEDÝEBÞDBÝD?ÞCAÞDDÞDFÞDFÞDFÜDCÜDCÜDCÚDCÙEA×FAÕF@ÓF=ÒE<ÐF<ÑG=ÔE=Ô?8Õ@9ÐC:ÆC9¶A7¥=0–=/Œ=.†>/‚?/>.€=-<-ƒ;-„:-…;.‚:,‚:,‚:,‚:,9+:+9-~8,~:/~:/~:/~:/}:1}:1}:1}:1z:1z:1y90y90x8/v7.v7.t8.w8/u9/u9/s9.t8.s9.r8-r8-q6.q6.p5-o4,n3+m4+l3*j4*h2(l6,i3)f2'h4)e1&i5*{B9ŽMG’MH‘PJTLVO‡XNYO|\Qs\Nk[L`WFVSBPSBJQ?@I64@,3<+2;*09(09(2;*5>-9B1<E4?H7?H5>G4:F2:C25@/3>-1<,3:33954954928919;.;>-;@*CL/O^7]sDi„Mp“SwŸYy£Yw¡Yq˜Yf‰OZ}CX{A\E]€F]€F^G`ƒI`ƒI`ƒI`ƒI`ƒI_‚H^G]€JV{HJn@Ae7haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlbVj`VjaXkdZkg^upjˆ…€Ÿžš°°®ÃÂÀÓÒÐâáßçæäçãàãÞÚÞÖÓÙÎÈμ²¸¥——‡zym]_YIKL:@E1;D/>J6=H7=F5;C4;>5:;3983880==3C<2N71a84ˆHH¯]_Å`dÊWZÍQSÓNO×MKÛKJÞHGáFDãDAâBBßCDÞDFÞDFÝCEÝCEÜBDÜBBÛCBÚDCØD@ÕD?ÓF?ÒE<ÐF<ÐG=ÔE=Ù@:Ù@:ÑB:ÈC:¼C:¬@4™;/Œ9+‰=/ƒ>.>-€=,<,ƒ;,ƒ;,„<-‚:,‚:,‚:,9+9-9-~8.}9.~:/~:/}:1}:1}:1}:1}:1}:1z:1y:1x90x90w8/t8.s7-r8-t8.s9.r8-q8-r8-p7,p7,p7,o6-o6-n5,n5,m4+l3*k2)i3)g1'k7,h4)e1&h4)b0%f4)zA8MG’MH‘PJŽULˆXNYOxZOr\Nk^N^WGRPAKN=CJ:9B12:+08)17+17-06,/5+/5)08+2:+4<-9D4;F5=H7<I7;F56C13@,1>-.800621622717829;0:<.:?)?H+KY5[qChƒLq“Vwž[w¡YsœVgP^IUx@WzB[~F[~F[~F]€H_‚J_‚J_‚J_‚J^I^I]€H]€JUvIJk@@a6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlbVpg^ng_lgatqj‡„¡ œ¼¼ºÎÐÏÏÏÏàààòòòúøùû÷ö÷óðñìéðâßèÐÆÝÁµÁ«¢‘}ub^\GKM7CH2AI2AI4@G5BD7AA7B=9C97?:69<5>?7B71J.+d66QR³giÆnmÀ\\ÇZWÐVS×QNÜLKâHHæCDåBCßCFÝDFÝDFÝCEÝCEÜBDÜBBÜBBÜDCÙCB×C?ÓD>ÒE>ÐF<ÐF<ÔE=ÜC=ÛA9ÒB:ÊD;¿E:°A6œ:-‹5&Š</…=.‚=-€=,<,<,ƒ<*„<-‚:,‚:,‚:,:+9-~8,}9.}9.~:/~:/}:1}:1}:1}:1}:1{;1y:1w;1x90u9/t8.s9.r8-q7,r8-q8-p7,n8,p7,m7+o6+o6+o6-o6-n5,m4+l3*j4*i3)h4)f2'k7,h4)c1&e3(b0%e3(xB8ŽMG’OIŽRJŠUMƒXOzZOq[Mh\LZTDIJ:?C4>D69A208+/7*6<247058157247025.06,08-19,6A3:E5=J9>K9<I77F32A,1>-,6..400511606718:/:<.:?+<E*IW4YoAg‚Mp’Vv\užXp™U`†IX{CSv>WzB[~FY|DY|D\G_‚J_‚J^I^I^I]€H]€H]LStIHhA?]7icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSjcSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUldWibZgd]vsn“’Ž¯¯­ÄÆÅÚÜÛêîïóôöö÷ùüüþÿÿÿÿÿýÿûúü÷ôýòì÷áÔòØÇàʵƶŸª ‡ˆ„ibbFEH-DH/CG0FE1GD5F<3C60F42H:9>=9>?:B:7I75cGF’jjÅ“’è­©Ò‹‡ÇtnÀ]XÆSPÕONßJLçFKéFKßEGßIKÚDFÔ;>Ø>@áGIàDGÖ:=Ú@@Ú@@ÙA@ÖB>ÔC>ÑB<ÐA;ÑA9ÞC>ÛA9Ó@9ÊA9¾B8°@5Ÿ:.8*Œ=0‡>/ƒ>.>-€=,<+=*<,:+9-9-~8,~8.|8-|8-|8-|90|90|90|90z:1z:1z:1z:1y=5w<4w;3u:2t91q8/p7.p7.o6-m7-m7-l8-m7-l8-m7-m7-i2+m6/p92o81k4-g2*g2*h3+e0(i7.d2)]-#`0&_/%b2(s>6ŒOJPKˆQJRJ}YMv_QfYITN>DE5>E5:C25@04</3;04:04:068378366446135016//6..6+.9+2=-6C2:G6:I68G44C.1?.*4+,2.-2..3-45/79.:</:?+6>&DR1WlCh‚Rs”]wž_r›Wk”R[~DXyDTu@Tu@WxCZ{F[|GZ{F^JbƒNbƒN^J\}H_€K`L^~MTsJFd@<W4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUldYgd]onj†…ƒ¤¤¢ÁÃÂÖÚÛêîï÷ûü÷ûþøüÿüýÿþþþÿÿýÿþúÿüùÿúóÿðàûëÔíßÅ×ͲÀ»¤£„‚ƒcgjKLQ3GJ/EC.GB/H>2I:3L95K<9?:7BA?MHE]RPyjg£Ž‹Î²®èÅ¿ÿ×Ñ쳪͂|Àc^ÊVVØRSßHMÚADÖDEÕEEØHHÜJKÛEFÕ<>Ö<>ÛACÙ??Ù??ÙA@×A@ÖB>ÓB=ÒA<Ó@9ÜA<Û@;Ó@9ËB:¿C;±A6 ;1’8-Œ=0‡>/ƒ>.>-€=,<+<,<,:+9-9-~8,}9.|8-|8-|8-|90|90|90|90z:1{;2{;2z;2w<4u<3u:2s:1r90n8.o6-m7-m7-l8-l8-l8-l8-j8-l8-l8-k6.n70o81n91l7/i4,g2*e3*c1(d4*_/%^.$b2(^.$`0&p>5JE‡RL‡XR~XOrVKdRDQJ:>?/:A16A05@03>04<14<15;17:379477577557246116//6./7,.9+1<.4A08E49H58G44E24B1.8/.5..3--2+23+46+8:-9=,7?(DQ3WlEh‚Ut•`wbp˜YgPY|DWxCTu@Tu@VwBYzEYzEYzE[|G_€K_€K\}H[|G^J^J^{MSnKF_A9R4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUneVneVlfZed_y{x—™˜²¶·ÍÑÒäéìôùüúÿÿûÿÿüÿÿýþÿþþþÿþüÿÿûÿÿúÿÿôþüçúùÝïðÑáåÄÒØ´¼ÄŸ ¨ƒ‡‘l`gEQX7DG,DC.JD4LD7KA8I>:C;9SJKia_wvœ’¾³¯ÙÎÈêÜÓþèÝÿóéÿäÛð©£ÃecµBEÇDIÚRVÛUTÑMKÊDAÍCAÔFE×EFØDDÙCDÖ=?×>@Ø@?Ö@?ÖB@ÓB?ÓB=ÔA:Ù@:Ù@:ÒB:ËE<ÀD<²B7¡<2“9.Ž<0‰=0ƒ>/>.=-~<,€=-€=-9-9-~:/}9.}9.|8-{8/{8/}:1}:1{;2{;2{;2{;2z;4x<4t;2q;1r90o9/n8.l8-l6,k7,l8-j8-j8-j8-j8-i9-j8-j8-n91m80m80m80m80i7.f4+c1(d2)a1']-#_0&c4*\-#_0&sD<}PJVP~YQpTI^J?OC7?<-46(2;*0;+1<.2=/4<14<15;17:379479668357257227007/08-.9+0;-2?.6C27E48G48G49F54>33:2/4-,2(/0(13(57*6:)6>'DQ5YmJk„Zw—fwœfl“Z_‡KWxCWuCTr@Tr@VtBXvDYwEYwEZxF]{I_}K]{I]{I_}K^|JZwKPgJAW@3I2icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVneVneVmg[jkfƒ‡ˆ£§¨¹¾ÁÐÕØåíïóûýõýÿûÿÿûÿÿüÿÿüþûýþùþýøÿþ÷ÿÿóøýæôýÞî÷ØæòÎÝéÃÎÚ´¶Á™¡«†€‡efmLMQ6FH0HJ5KI:HD9D@7OGDj`_‹€¤š™·¯¬ËÆÂÞÛÔêæÝúñèÿûñÿ÷íÿÝÕû¶±åŽÊcd°@?ÃPKÉTMÉPHÃF@ÈGBÔMJÖKHÐ@?Ò>>Ó??Õ?>ÕA?ÕA?ÓB?ÓB=ÓB=Ö>9Õ@:ÒC=ÌE?ÀE>²A9¢=5•;2Ž<1‰=0ƒ>/>.=/~<,€=-€=-9-9-~:/}9.}9.|8-{8/{8/~;2~;2|<3{;2{;2{;2z;4x<4r90o9/o9/m9.l8-k7,j6+h6+i7,i7,i7,h8,h8,h8,h8,h8,m;2l7/j5-i7.j8/j8/f4+a1'e5+a2(].$a2(b3)Y* a2(yNE\VvWRiNGWC:I<3@:.:;-8<.08)/:*3;.4</5=25;169069079468368349238139/19.19..9+/:,0=,2?.5B17E4;H6<I89C87?428.-3'.0%/1$24&48'4<'ER8]pPr‹d{šnwœifXU|ESsATr@Sq?Sq?Tr@UsAVtBVtBWuC[yG]{I\zH^|J_}K\zHWrIJ^E<M;.?-gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVofWofWng]qqo‡Œ¤©¬·¿ÂÍÕØãíïòüþôþÿøÿÿúÿÿûÿüýÿúüýõúüñùùíöøêöÿèóÿäðýáîùÙéôÒÞèÅÊÒ­¶¾™£}‚bY]BGL5FK7FJ9CG9AC8c^X…}z«¡ŸÁ·µÌÂÁ×ÏÍæáÝñîéú÷ðüõëÿñæÿòéÿôìÿåß騤·hc¦LAµPDÁYNÇ[QÆQH¿D=ÂA<ËDAË@=Î@>Ð@?ÑA@ÒC?ÑC?ÑC?ÒC=Ó?;ÒA<ÐE@ÉE@½C>¯@9 >5•=3Ž<1‰<2ƒ=1=0=1~<.=/=/~:/~:/~:/}9.|90{8/{8/{8/|<3|<3|<3{;2z;4y:3y:3w;3n70m80l7/l7/k6.h6-h6-h6-i7.h8.h8.g8.g8.g8.g8.h8.k92h6/f4-g5.i70h70e4-b1*c2+b3+_0(]1(]1(V*!b6-{ULtYRaNHN?8A7.=6,;9-9;.9<139-3;.5;/6<06<07:/58-47.69049238139/39/2:/19.19,.9+.9+/:,0;-3>.6C2:E5<G7=E8:B55;/06(02%/1$13%15$2:%GS;buWwk|›rq•g\‚QJp=Oo>Qn>Qn>Qn>Qn>Qn>Sp@Sp@WtD[xH]zJ]zJ_|L_|LZwGRlECU?6D7(6)gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXpgXng]lnmz‚…“š «µ·ÄÎÐÜæèí÷ùôþÿõþýöÿüúÿúûÿùûþóøúíõöèñôãôýêôýèôüåóùßòöÛéìÍØ×¹ÅÄ¥±°’ŽregOMP;GK:FM=GOBKQG{{sŸš”ž¸ØÎÌßÓÓçÛÛóëéü÷ôðïêüüôÿÿöÿýóÿùïÿóêÿçÞÿ×ËØ“ƒ¸eS£J:´TF½WIµF;·@8ÈKEÇC>ÊC?ÌB?ÎC@ÎC>ÎC>ÍD>ÍB=ÑB<ÒC?ÎDAÅD?¸A=ª=8ž;5•<4Ž;3‰<2ƒ=3=2=1~<0=1=/~:/~:/~:/}9.|90{8/{8/{8/|<3{;2{;2z:1y:3x92w81u91n70l7/l7/j8/i7.i7.h6-g7-g7-g7-f7-f7-f7-f7-f7-f7-h70h6/g5.g5.g6/h70g6/f5.a2*e6.^2)\0'`4+a5,i=4uSJXG@E>6<5/95,;8/8:/57,36+69.5;/7:/69.69.58-57,36+28,19,28.19,19.19,19,19,.9+.9+.9+/:,0;+3>.6A17B2<D5:C28?/5;-46)24'13%04%07%HT>ex\umt’lf‰_RwKBh9Kk<Nk;Pm=Pm=Nk;Nk;Ol<Qn>VsCZwG]zJ^{K_|L_|LVsCNg@<J9/:2$.&gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXqhYoh^hikmtz…Œ”£¬±¿ÈÍÓÞâåðòðüüòüûõþùøÿ÷úÿöüÿòúýìøùçö÷çööê÷÷ëú÷èüöæýõâ÷ìÖçØÃÕƯÀ±šž“}un[ZWFPQCSVK[bZeld•˜²²¨ÕÎÆèÝÙóããúêëÿñôÿ÷ùÿþûþýùùúôøúïüüðÿÿóÿÿñÿûêÿæÑñª”¼o[©VD®RCµPD»LA¿JAÂG?ÆE?ÉE@ÊE@ÊE>ÉD=ÈC<ÉB<ÑC?ÐE@ÌEAÂC=³=9¦;5œ;5•<6Œ<3‡=4…<5=4<3~<0=1=1~:/~:/~:/}9.|90{8/{8/{8/{;2{;2y:3x92w81v70v70s7/n70j8/j8/j8/j8/h8.h8.h8.g7-f7-f7-f7-d8-d8-d8-f7-g6/h70i81i81h70i81j;3l=5g80k<4b6-a5,oC:xLCtI@nMDC9056.45/8918;247.14+25,58-58-57,46+46+46+46)37)/7(.9)08+.9).9+.9)08)08)19*08)08+/7*08+19,3;.4<-9B1:C0;B0:A1:<.68*24&/3$29'IU?cu[m„gf„bWyTInE?d8Hg;Li;Nk=Nk=Li;Li;Mj<Ol>UrDYvH[xJ]zL^{M\yKQn@G_;6B4+4/#)%gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSjcSjbUlbVlbVmcWmdUmdUmdUleUmfVngWogZnh\oh^mjekormtzƒŠ¥®³ÃÌÑÕßáæîñôüþôýú÷ýùùþ÷úÿôüÿòüÿñüÿîýþðûøïþúñÿùïÿúíÿùéÿòßïàËÝηÁ²›¢—|ubb_NXZL]cWmwn|†}¦¬¢¾ÀµÚÕÏîäâüîîÿôôÿô÷þôõÿùùûúøûýøüÿúøÿõôüñ÷ýñÿÿñÿùèÿôãÿÌ»½p›QD©SFµSH²C:ÀJ@ÄH@ÇG>ÉF>ÈE=ÇD<ÆC;ÆC;ÍG>ÌG>ÇG>¼C;­>5Ÿ:2—:3‘>6Š=5†=4ƒ=5=4€<3;0;1;1~:/~:/~:1}90|90{8/{8/{8/z:1z:1x92w81v70u6/u6/q6.m80k90j8/j8/i9/i9/i9/h8.g7-f7-g7-f7-f7-f7-f7-f7-f5.j81m;4k:3j92j:0m>4oC8l@5oD;d<2c=2zVJ†dZyWMbLA>:13814927<54:0/5+25,9<336+25*24)03(13(25*46+47,.6),7)/7*-8*/7*/7*/7*/7*19,08+08-/7,/7,/7,08-08+7?09B1<E4=D4;A38<.26'-4$2;*JVBcr[h|a]vXOmKFfAAa:Hd;Kh<Nk?Nk?Kh<Jg9Li=Nk=TqEWtHZwK[xL]zNZvMNjAC[;2>4*00!''heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdVjdVjdXldYlcZmeZmeXmfVg`NjeRnkXol]he\feasqr‚†Š“–ž¡«³¶ÃÈËØÝàêîïö÷ùùûúüþýþþüÿÿúýþöúýòùüñúýòûþóùúòúúòùùíüúëþüçù÷ÞéåÊÕÔ¶º¹›˜˜|qtY_dMbkXr}l„‚‘›´¹²ËÌÇãâÞòîë÷óòû÷öýùøüø÷ÿþüþþüþþüýÿúýÿúýÿúýÿúýÿúúü÷ÿÿúÿûöÿêåا £`X›D=µNE¿MCÂF<ÄD9ÊE<ÎI@ÎKAËH@ÇG<ÆG8ÃH8½J8³H8¦E5šB4‘B5‹C5†B5„B6‚@4‚>3‚<2„:1†91†9191~:1|91{80z7/z7/w7.v6-w7.w7.w8/w8/v7.u6-q5+n3+l7/i81i81h70h70g6/g6/g6/f5.g6/i70i81h70g6/e4-e3,h3-j5/m80k90j:0i;.i=0kA3gB2jI:dH:v_O~k\ŠxjŒoRJ=79.4:04:039/39/39/28.28.17-17-36-06,25,/5+14+/5+/4-.5-/4-.5-/4-/4-/4-/4-05./4-/4-.3,.3,/4-/4-/6.1;23=26@58B79D67B45@03>-4?.DQ=WeN[kQPbHEX<@T8BW6Ic>Ke>Kf=Kf=Je<Je:Lg>Oj?UpGYtK\vO]wP]wRWqNHb?;O6&1+&+.$),heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVidQjhSmjWjk[gg_lll~„“š¨¯µ¸ÂÄÑÖÙâçêòóõûüþÿþÿÿþÿþýûÿþúÿÿúþÿùûüôøûòöüò÷ýó÷úñøúïøúí÷úéùûåòõÚßâÃÌЯ´¸—‘–vkqUYaI_kUtoŒ˜Š§œ¿Á¼ÓÓÑççåóóñ÷÷õûûùüüúûûùþþüþþüþþüþþüþþüþþüþþüûÿþõÿÿõÿÿþÿÿÿûúÿíêð¿ºÂ~uŸKA¯M@¹K>ÂL@ÅK>ÃE9¼=4¾?6ÃE9ÄF7ÃJ7½L:³J7¦F6™C2‘C6E7…C7‚B8A7>5‚<4ƒ:3†91„93~92}:2z:1z:1y90x8/v7.v7.u6-v7.t8.t8.t8.r6,o5*m4+l7/i81j81h70i70h70g6/g6/e3,e3,g5.h6/j81j81j81k92k60l71k90k;1k;/j>1j@0iD2gH6kP=gRAufSueŒ…s†ƒrKL<69.39/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4..3-.3-.3-.3-/4./6/.80/:21=34@66B66B66B45B16C1CP>P]IR`IIW@AO6BP7EU:Jb@Jd?Ke@Ke>Ic<Hc:Id;Je<SnEXrK\vQ]wT[tTTmOC\>6I5&1-',0$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVmhUkiTmjWjk[kkcwww‘’—§¬²¿ÆÌÒÜÞìñô÷üÿþÿÿþÿÿÿþÿÿþÿþýûÿþúÿÿúýþøúûóõøïñ÷ëñ÷ëô÷ìõùëöøêõøåõ÷áîîÔÛÛ¿ÉÊ«°±’“–yuy`kpZt{iˆŸ§œ®µ­ÍÏÊÞÞÜïïíøøöûûùþþüþþüýýûþþüþþüþþüþþüþþüþþüþþüýÿþûÿÿûÿÿÿÿÿÿûùÿúôÿ÷íýÑÆØž”L=¥RB©L;§@1·G;ÏYMÏUJ¼@4ÄD7ÆH:ÃK=¹I;ªB7?3—@7“E;‰@9„A9A8?6~>5}=4<4}=4z;4x<4w;3w;3u:2t91t91t91r90r90r90r90o9/n8.l6,k5+l7/j81l71j81k60i70i70h6/g5.g5.f5.g6/h70i81k:3k:3l;4j;3i:0h<1k?2jC4iD2fE2fI7lVAjYGujV†m‘Ž{€mEF658-28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4./4./4..3--2,-2,.3-/4..5.+5-+6.-9//;12>24@46B47D38E3?L:ER>CQ:;I28F->L3DT9J_@Jb@LdBKc?Ia=G`9F_8G`9RkDXpL]uS^vVZqTPgK=T8.A.&1-',0%*.heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVniVljUlkWlm]pqi€‚ž¡¦¹¾ÄÄËÑÛåçõúýûÿÿüýÿüýÿþüýüûùÿþüÿÿûÿþùûüôõöîîñæéïãçíßíñâðôåñôãñôßòñÜêêÐØؼÇÇ«²±•¡¡‰‘“}“€œž‘ª­¢¶»´ÀÅ¿ÜÜÚééçööôûûùýýûÿÿýÿÿýýýûþþüþþüþþüþþüþþüþþüþþüþþþûûýÿþÿÿþÿ÷òïüóìÿüóÿûíÿôäìñ¹p•P@¢O?¸XJ·M?µE9ÀG<ÁA6ÈE;ÅI?½G=¯@9¡<4š=6–A<?;‡@<@:}@;z?9y@9x?8x?8v=4v=4v=4u<3s=3r<2r<2q;1o;0o;0o;0n:/k9.j8-j8-i7.m82n72m61l71l71k60i70i70l:3j92h70f7/f7/f7/h91f:1j?6f>4e=1f>2hC3iE5fG3cG2cJ6hV@i\IskV…‚oŽzpq_9=,47,28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3-.3-.3--2,-2,-2,-2,.3--4-*4,)4,*6,+7-.:.1=14@25A36C2:G5<I78E12?+2@)8F/>N4DX<E]=K`AJb@K`?G_;H^:F^:SiEXpN`uV^uXZnSLcI9M4):(%.+%*.$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVlgTkiTnmYop`tum…‡†¤§¬¿ÄÊÎÕÛæðòûÿÿûÿÿûüþýþÿÿþÿþýûÿÿýÿÿûþýø÷øðïðèçêßàæÚÞåÕçëÚêïÛíðÛìðÙîîÖèèÐÚØ¿Ìʱ½§·µ ±®¶´§Á¾µÉÈÃÒÓÎÙÙ×èèæòòðúúøüüúýýûÿÿýÿÿýüüúþþüþþüþþüþþüþþüþþüþþüÿþüÿüÿÿüÿÿûúüû÷ýÿùþÿøþÿôÿÿíÿþìøßËÅœŠbP–J:¥L<´P@¼L>¿@7ÆC;ÅF?¿D=±>;¦:7ž:8™>;‘=;Š?<„@=}@=xA<tB;rC;rC;q?6s>6s>6r=5r=5r=5p>5o=4n>4m=3l<2k;1j;1i:0i:0j:0n72p62p62m61m61l71i70i70l;4k:3h91e90e90e90e:1d<2fB6cA5cC4dD5dG5dI6bI3_I2^L6eV?jbMrmW„ƒo„‡r[`L3:(28,28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3--2,-2,,1+,1+,1+,1+-2,,3,,6.+5-*4+*4++5,.8-0;-2=/2=-5@/6A05A-1=)1=)5A-8F/=O5@T8FY=H\@J]?I^=K^>K`?TgG[pQcvZauZYkSJ]G6G4&4%$-*$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZlfVjgTkjUlnYorasvm…„Ÿ¤¨¸¿ÇÖßäí÷ùûÿÿûÿÿûüÿþÿÿÿþÿþýûÿÿûÿÿúüüôóõêëíâãçÙÝãÕÜãÑäéÓçìÕéíÖêìÔëëÓèæÏßÚÄÓθÓκÌƶËøÐÉÁ×ÒÎàÛØêæåðïíóòðùù÷ýýûýýûýýûÿÿýþþüüüúþþüþþüþþüþþüþþüþþüþþüÿýüÿûüÿøùÿþýþÿýùÿýôÿøïÿõ÷ÿöð÷çÿÿíÿîÛͧ”¤kX¢[GªWE­L;¹D:ÀD<ÀE>¼E?´A>ª=:¢:9š;9•=<?=…?=}@;wB<rC;oD;oD;p?8q?6q?6q?6q?6p>5o?5o?5o@6n?5m>4k<2h<1h<1h<1l<2o83q62p62p62m61l71j81i81h70g80e90e:1d<2e?4f@5dB6^B4aG8cL:dM;cM8`K6]K3]M4]Q9bX?mhRss[€ƒnv{eFO:4=*39-28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0*+0*+0*,1+,3,.5.,6.*4+*4+*4++5,-7,.9+-8*0;+4?/5@/4?.3?+3>-3@,7F/9K3@O8BT:GW<H[?M]BM`DUeJ\oSdtZ`rZXgRGXE4B1$2%$-*$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdVjdVjcYkdZlc\md[lfZlfVliVlkVkmXkn]lrhy}• ®·¾ÒÛàêóøûÿÿùþÿùúþþÿÿÿþÿúù÷ÿÿûþýøùùññóèéëÞãçØßæÖàèÓäéÒçíÓèìÓçéÑèèÐçåÎàÛÇ×оÚÓÃÙÑÆÞÔËæÝØîäãóéêúñôÿùûúù÷þþüÿÿýýýûýýûÿÿýÿÿýüüúþþüþþüþþüþþüþþüþþüþþüÿýüÿùøÿúùÿþýüÿý÷ÿþîÿùñÿÿòÿýõÿúóùëÿýíÿúèôλ«wbQ:ª\H²N>¸J=¹I>¸I@´G@¯D>¥=:œ:7–=9>:ˆ?9€A:xA:tD:pF:pE<p?8q?8q?8q?8q?8q?8p?8p?8qB:pA9n?7l=5i=4j>5j>5n=6o83r73p62p62n72l71j81i81d8/d90c;1d>3d@4cA5cA5_C5ZE4_N<gVBhWCcS<^O8[O5\R7]V<]Y>nlUtv^|kcmU2>(6B.3;.39/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1+,1++0**/)*/)+0*,1++2+-4-+5-*4,*4,+5,+5,,6+-7,,6+/:,2=/6A17B27B15@04?.2?-4C.:G3=L5AO8DT:JX?L\BTbI\kTcqZ^mXUbPDRA2>0#/%&/,&,,$**heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdVjdVjcYkdZlc\md[lfZlfVolYmlWjlWgkZflbr{xŽ˜š¨±¸ÊÓØãìñøýÿ÷üÿúûÿþÿÿÿþÿúùõÿÿúýýõøøîðòåéëÝåéØãêØåíÖæìÒéíÒêíÒèèÎèæÏèãÏáÚÈØÐÃØÎÄÝÒÌêßÛøíëÿôöÿõùÿõûÿùüþüýÿÿýÿÿýþþüþþüÿÿýÿÿýýýûþþüþþüþþüþþüþþüþþüþþüÿþúÿýûÿýûýüúùýüøÿÿõÿÿóÿÿíýúóÿûûÿúÿÿôÿöæÿóßÿãÍ×­•©oY¨WD®Q@¬O>¯OA±OB­K@¤C<™<5•>7?6ˆ?8A7{B7uD6qE8qE8p?8q?8s>8q?8q?8q?8q?8p?8sB;qB:o@8m>6l=5j>5m>6o>7o83q73o83m82m82i81h91f:1f;2d>3d@4bB5`C5]A3\@2WB1TG4[S>f^Gi^HbX?ZS9ZS7\W:ZV;XW;kmUsw^u}fUaI&28D03;.4:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0**/)*/)+0*+0*,1++2+)3+*4,+5-+5,,6--7.-7,,6+.8-2<16A39D69D47B46A10;+2?-5B09F2<I5@N7FT=JX?R`I[hTanZ\iWQ^MBN@/;/",#+1-(.,&,,heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeWkeWkdZle[md]ne\mg[mgWqn[kmWknYkr`jrgpyv‡‘“Ÿª°»ÄÉÐÙÞêïóöûþüýÿþÿÿÿþÿþýùÿÿúþþöúúðöøëôöèðôãêñßçïØðöÚíòÔëîÑììÒèæÑáÜÉÝÕÈÞÔÊáÔÎèÚÙòääúëîþòôÿ÷ûÿùÿÿüÿÿýþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúÿþúÿþúþþüýÿþûÿÿúÿÿúÿÿûÿÿþÿÿÿÿýÿûõÿûñÿüìÿûåÿóÛÿêѺ‚i¦bK—O9ŸT?¨ZF£RAJ: M?Ž<0‹=0†>2=/x=/t?/sB3tD6r=5r=7t=8s>8u@:u@:t?9q?8sA:q@9q@9q@9p?8n?7o>7o>7k92m82l:3l;4l;4h<3g<3c=2c?3^>1dG9cG9T=-N9(M8'@1WQ;PN7KI0OK2]Y>ieJeaDVU7XX<]`CosZz€fdlU=I1-9#2>*4</5;14:04:04:039/39/39/39/39/39/28.17-17-17-06,16016005/05//4./4./4./4.,1+,1+,1+,1+,1+,1++0*+0*.5.-4--4-,3,-4--4,.5-.5-+2*-4,07/5=29A6=E8?G<?J<7B25@/3>-1=)2>*9E/BN8IU?O[GVbN]hWYdTLWI<F;/9.)3*)/+(.*'-+heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeWkeWkdZle[md]ne\mg[khWonZjlVknYkr`jtiq|x‰”–£®´¾ÇÌÒÛàëðô÷üÿýþÿþÿÿÿþüþýùÿÿúþþôûûï÷ùëô÷æðõáêòÝèíÖêïÑæëËäçÊææÌãáÌßÙÉÞÔÊßÔÎçÙØíßßöçêûïóÿôøÿ÷ûÿúþÿüÿÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüûÿúûÿúýÿüýþÿþýÿÿüÿÿüÿÿûÿÿüÿÿüÿÿûùÿüõÿþñÿÿíÿûåÿòÙÿëÑà±—§u\‘[C–ZBšYCšVC™R@ŽG5‹F6ˆE4ƒD3|C2wB0s@/o>/u@8s>8u>9u@:t?9o=6p>7sA:q?8p?8p?8n?7o>7m>6n=6m>6k<4l=5m>6k?6j?6gA6eA5bB5dG9[A2^G7^I8N=+F7$G8%>6!LL4GK2DG,DD*MM1\[?baC`aBYY=dgJsw^sy_X`I:D,/;%7C/6>16<26<26<25;15;15;15;15;15;15;14:04:039/39/39/27127127116016016005/05/.3-.3--2,-2,,1+,1++0*+0**1**1*)0))0))0)*1*+2*,3+.5--4,.5-07/4;39A6?F>BJ?;F8:E57B14?.3?+6B.<H2@L6LXDS_KYdTWbRLVK=G<1;2+5,+2+*0,)/+heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeWkeWlcZmd[md]ne\mg[khWmlXimVjoYktaiuiq}yŠ˜™¥²¸¿ÊÐÔÝâíòö÷üÿüýÿýÿþÿþüþýøÿÿ÷ýýóúûí÷úéô÷äïôÞçïØåëÑâçÉÞáÂÝÝÁÞÞÆÞÛÈÝ×ËàÕÏäÙ×îââóçëúîòÿôøÿ÷ûÿùüÿúýÿýýÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüøÿüøÿüûÿþþþþÿüÿÿúÿÿùÿÿøÿÿùÿÿúÿÿúúÿýøÿÿöÿÿóýÿïÿúæÿôÜÿøàÿìÓ㿧¬‚j‡YB…Q;’[F—]IS?F2u>)r>)s@+tD0vE4q?4n<3q<4tB9sA8o?5qA7xH>n>4m>4m>4k?4l=3j>3l=3j>3g?5gA6gA6gC7eC7cC6`C5^D5bK;UB1ZI7`S@RG3C;&E=(FA+AE,BH.AE*<@%?B%NN2_`AijKaaEnqTvzagmSJO94<%4=(=F38>28>48>48>47=37=37=36<28>48>47=37=37=36<26<26<25:449349349338238238227105/05//4..3--2,,1++0*+0*).().().().().(*/)+0*,1+160/4.,1+,1+/4.6;4=B<AH@@K=>K:<I78E34A-2?+3A*5C,DQ=KXDQ^MQ^MHTH<H<2>4.8/-4--4-,3,gdUgdUheVheVheVheVifWifWifWifWifWifWifWifWifWifWkeWkeWlcZmd[md]mf\mg[jiWkmXimVjoYjs`hthm|wˆ˜˜¦³¹¿ÊÐÓÜãëðööûÿüýÿýÿþÿÿýÿþùþþöýýñúûí÷úçô÷âîóÜåíÕâèÎÛàÀ×Ú»ÖÖ¼Ù×ÂÝ×ÇÞ×ÍåÛÙìààøìðûðöÿõûÿùþÿúýÿûûÿûûÿýüÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüøÿþøÿþûÿþþþþÿüþÿúÿÿùÿÿøþÿúýÿùüÿùùÿýúÿÿøÿÿøûÿõüþðÿÿíÿüéÿñßÿðÝÿïÚñÒ½´z{R>tJ4uH3vI4zM8}P;yL7nA.e7'{M@sD:qB8sD:oC8g;0d8-g=1i?3i?3i?3g?3f>2f>2f>2e?2b@4bB5`C5_C5_C5[D4ZE4WD3XI6OB/\T?oiSc^HMK4IG0IK3>D*?H-@F*<B&<A#FI,XY:deFmmQxx\tv^[_F@C.6;%8@+<C19?39?59?58>48>47=37=37=39?58>48>48>48>48>48>48>47<67<67<66;56;56;55:45:438238216005//4.-2,,1+,1++0*+0**/)*/)+0*,1+-2,-2,05/.3-+0*+0*-2.2718=9;B:@K=@M;@M;=J68E13@,1?(0>'<I5BO;HUCIVEDPB;G;2>4.:0,6..5.-4-gdUgdUgdUheVheVifWifWifWifWifWifWifWifWifWifWifWkeWldWlcZmd[md]mf\mg[jiWkmXinWiqZgs_drejyt…••£²·½ÈÎÒÛâêïõôùýûüÿýÿþÿÿýÿÿúÿÿøÿÿóþÿñûþë÷úåðõÞæîÖâèÌÙÜ¿ÕÕ¹ÒйÔѾÚÔÈàÙÑêàßôéíþóùÿ÷üÿûÿÿýÿÿþÿÿþüÿþúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþúÿÿúÿÿûÿÿþþþÿýþÿüüÿûüÿûúÿúøÿù÷ÿú÷ÿýøÿÿûÿÿûýÿúýþùùôîÿþöÿýôÿüóÿûîÿ÷çûæÕéÒÀÏ´¡¶š…”uawVCjI6lI6rM;uP>mF7iB3gB2jE5nI9nJ:oK;oK;eA1cB1cB1cB1cB1cB1bC1`C3]F6\G6\G6ZG6ZG6WH5TG4RG3PH3NH2fdM~~frrZVX@JL4GM3<E*<F+?H+AG+AF(DG*MN/TU6xw[{z^nnVUU=CB.?A,>A.:>-;>39?59?58>48>47=37=37=38>48>48>48>48>48>48>48>49>89>89>88=78=78=77<67<66;55:449338227105//4./4.-2.-2.,1-+0,+0,,1--2.-2.,1-,1-,1-,1-.210513764;4;G9=L9@O<@O:<K67F/4C,2A*6E.:I4@O<BP??M>8F71?2-9-,6--4,,3+fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWldWldWlcZmd[md]mf\mg[jiWkmXinWiqZgs_bpcgxr‚””£²·ÀËÑÔÝäëðöõúþûüÿýÿþÿÿýÿÿúÿÿøÿÿôÿÿóÿÿïúýèò÷àçðÕâèÌ×Ú½ÑѵÍË´Î˺ÖÏÅÞ×Ñìâã÷îóÿöþÿúÿÿýÿÿþÿÿÿýþÿúþÿùþÿúþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþýþÿýþÿýþÿýÿþýÿüþÿúþÿùÿÿ÷ýýóýýõþýøþýùÿþüþþþÿýÿÿþÿþùÿÿüÿÿûüûöóÿøòÿýôÿþñÿýíÿúéÿòà÷äÓçÒ¿Ò»©¹ŸŽŸ„srb|]K}^LtUCaD2W:(Y<*[>,X=*`E2`E2`E2_F2`G3`G3`G3]H3\K7\M:\M:YL9XM9UM8RL6QL6NL5QQ9ikS|€gmqXSY?FL2>G,<F+<F+?H+DJ.EJ,DG*HI*LM.yx\tsWfdMTR;LI6KJ6FE3<=-<?49?59?59?58>48>48>48>47=37=38>48>48>48>49?59?5:?9:?9:?9:?99>89>89>88=78=78=77<66;55:4493382382/40.3/-2.,1-+0,+0,+0,+0,+0,,1--10.21/32/32/32-4-3?17F3=L7@O:?N7<K49H18G05D-8G0<K6>M:<J97E61?2-9-+5,-4,,3+fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWldWldWlcZmd[md]mf\mg[jiWjlWhmVhrZfs_cqdhys…——¥·»ÇÒØÚãêðõûøýÿüýÿýÿþÿÿýÿþùÿÿõÿÿòÿÿðüÿìøûæïôÝâëÐÝãÇÕÕ¹Î̳ÉÄ°ÊÄ´ÐÉ¿ÚÒÏéàãöíòÿ÷ÿÿúÿÿýÿÿþÿÿÿýýÿúüÿøüÿøýÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿüÿÿüÿþýÿýÿþúÿúøÿùøÿõøÿóøÿóøÿõüÿøýÿúÿýþÿüÿÿüÿÿûÿý÷ÿÿúÿÿüÿÿýÿÿþÿþýûûûóúøìÿÿñÿÿïÿÿíÿþíÿýíÿöçÿîàýêÛúãÑÿæÐãÊ´¥xt^GeO8bL5\H0^J2\J2\J2]K3]K3^L4^L4\M6YN8WO:WO:VP:UO9SN8PN7NN6MO7PT;`fLfoTU^CEO4AK0<F+?I.?I.CL/HN2HM/FI,OP1YX:qmRjfKa\F[V@YTATQ>MJ9BC3=@5;A7;A7;A7:@6:@6:@69?58>48>48>49?59?5:@6:@6:@6;@:;@:;@::?9:?99>89>89>8:?9:?99>89>88=78=77<67<6495273162/40-2.,1-+/.+/.,0/,0/-10.21.23.23-12+1-+9*/@-6H2;M7=O7<N4:L2:L25G/7I1:L6<M::K96G70@3-;.,6--4,,3+cdRcdRdeSefTgeVhfWigXigXhfWifWifWifWifWifWifWkeWkeWkeWldYle[md]mf\kg[jiWikVhmWhrZgt`dqgj{u‰›ª¼ÀÍØÞàçíôùÿúÿÿûÿÿýÿüþÿúþþöúúîúûíúûéøúåóöáêî×ßãÊÙÜÁÓѸÌDZž¬Æ¾±ÌüÖÎËæÝàôêòþ÷ÿÿúÿÿþÿÿÿÿþþþýÿúüÿúüÿúýÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüÿþüÿþüÿýþÿüÿÿüÿÿýÿýÿþûÿüøÿù÷ÿ÷÷ÿõøÿöùÿöüÿøÿÿûÿþýÿüÿÿûÿÿúÿÿúÿÿûÿÿüÿÿþÿþýÿûýüüþûþÿúùúòúüñýûïþúîÿùìÿûìÿýïÿýìÿðÛÿûâìÜÞŽu`P7RB)XH/XH.[M3[M3ZN4ZN4[O5[O5\P6[Q8UO7TO9TO9QO8PN7NN6KM5IM4JN5LR8S\APY<@I,;F(AL.?J,DM0EN1JQ2MR4JM0LL0YY=kjNhdIb^E^ZA_ZD`[GZUAQO:KJ8AB4@B5@B5>A6>A6>A6=@7=@79?59?59?5:@6:@6:B7:B7:B7;@9;@9;@::?8:?99>79>89>7;@:;@9;@:;@9:?9:?8:?9:?98?87=94;4382160/4..3/.3/.21.21,2.,2.+2++2*,4))6%$6)=!2F+8L1;O6;M5;M5;M58J29K3;M5<N6<N87H51B0.<--7,.5--4,]eN^fO_gP`hQdiUfiVgjWijXfgUhgUheVheVjdVkeWkeYlfXlfXkhYmg[kg\mf^jf[ieYgeVghVfkUenYbo]dqhsƒ€–¨¬¹ÈÏÒÛââéïò÷û÷üÿùýüüþùüÿöüþñ÷øêùúêø÷åòñÝîíÙëêÖàßÊ×Ò¾×ϼËÀ®½´¥½³©Â·±ÌÂÁÛÒ×êàèúóûüöÿþûÿÿþÿþýÿüýÿüþýüþýþþþþþþþþþþþþþþþþþþÿþüÿþüÿþüÿþüþýùþýùÿüùÿýúÿþûÿþûÿþÿÿýþÿüýÿýþÿÿÿþÿýýÿüûýøÿÿûüý÷ÿýøÿþúÿýøÿúöÿ÷ôÿùùÿúÿÿüÿÿýÿÿÿÿÿÿÿýÿüýÿþüþýþÿÿÿÿÿÿþüÿþùÿþóÿþîÿýêÿýæúôÜÿúàçàƈlUN2WN1TK.SJ+WN1WN1UN1UN1TO2TO2TN4SO4QM2RN5QO6PP6MO7KO6HM6GL5JP6FO4AJ-=F'>H&DK*FM+EL*PV4PT3KN/HK,TT8bbFccIZZ@[Y@\ZA][B][B[Y@XV=US:SQ8HF1GD1DA0A?0@>1>>2??5>@5;>59?59?59A69A48C58C58C5:B79A69@88@58?79A69@8:B7:A9:B79@8:B7;B:<D9=D<>E=8B:8B:7A88@56>14</39/271.40/51-7/-9-.;)0@&6G'7M';V+:W+;U0;T4;R8=P:>O<>P::L6@R8EW=FY=DX=@T;5H2+<),6+,3++2*ZgM[hN\hP]iQbjSckTglXhkXghVghVifWifWkeWlfXmeZmgYmgYkhYkg[kg\jf]jf[hfZefVhiWglVfo\erajwnzŠ‰œ«²ºÈÑÐÙàáéìò÷ûøþþùþúúÿøûþóùýïøùë÷øæõôâíìØéæÓåâÏÜ×ÄÒ˹ʿ­Á´¤¹­¡¼¯¦Á¶²ËÁÀÛÐÖæßæûóþý÷ÿþûÿÿþÿþýÿüýÿüýÿüýÿþþþþþþþþþþþþþþþþþþÿþüÿþüÿþüÿþüÿýúÿüùÿüùÿýúÿýùÿþúÿþýÿýüÿüýÿýþÿþÿÿþÿÿýþýûüÿþýÿþûÿüúÿøóøíçòåÝöèßûðêÿúýÿüÿÿýþÿÿýÿÿûýÿüýÿþüýÿýþÿýþÿÿýÿÿþüÿþõÿÿîÿþèÿÿäúöÝýûâäàÇ‹‡lRM0SN0QK+QK+UO/UO/TO1TO1SO2SO2QP4QP4QM2PO3PN5NQ6MO7JP6HM6EM5HQ6EN1BK.?I'BI(FM+JP,KQ-NR/PT1VZ7^bA_bCY\?TW<UU=VV>WU>XV=YW>XV=XW;WV:XT9QK3OI3LG4ID1DA2B@3A?3>@5<=59?59?59A67B48C57D37D3:B79A69A68@58@59A69A6:B7:B7:B7:B7:B7;C8<D9=E:<F;=G?<H><F;;F6<D5:B39?38=67>74>63=40>-3C)9M*BY/Ga1Op;Ln;Li=Fa>BY?<R=;L::K8=O9DV<K^BM`BL`DH\@:Q71D.+5*+2*)0(ZgM[hN\hP^jRbjSdlUglXilYijXijXkhYkhYlfXmgYnf[nhZmgYkhYkg[jf[jf]ieZhfZfgWhiWejTdmZgtco|sŽ¬³¶ÄÍÍÖÝÞæéñöúøþþúþýùþøøûòôøêóôæðñßêé×áàÌÜÙÆ×ÔÁÐ˸ÇÀ®¿³£½° ¼°¤Ã¶®ËÀ¼ÕËÊãØÞëäëüôÿý÷ÿþûÿÿþÿþýÿüýÿüýÿýÿþþþþþþþþþþþþþþþþþþþÿþüÿþüÿþüÿþüÿýúÿýúÿüùÿüùÿüøÿüøÿýüÿüûÿûüÿüýÿþÿÿþÿÿýþþüýÿþýÿþûÿýûüóîêßÙâÕÍëÝÔ÷ìæÿúýÿüÿÿýþÿÿýÿÿûýÿüýÿþüýÿýþÿýþÿÿþÿÿÿýÿþõÿþíÿýçÿþãû÷ÞþüããßƉ…jPK.QL.QK+QK+TN.UO/TO1UP2TP3SO2QP4PO3QM2ON2PN5MP5MO7JP6IN7FN6HQ6FO2CL/CM+FM,JQ/OU1SY5QY2W_8jpJy[qvVY^@KO4MP5QQ9QQ9RP9SQ8TR9UT8YU:ZV;XR:VP:RM:NI6HE6DB5CA5?A6<=59?5:@69A67B47B47D37D3:B7:B79A69A69A69A6:B7:B7:B7:B7:B7:B7;C8<D9>F;<F;?IA>J@?I>>I9?G8>F7>D8=B;>E>9C;6@74B19I/BV3Pg=XrB^J[}JXuIMhECZ@9O:6G54E2<N8EW=NaESfHSgKNbF@W=6I3/9./6.-4,ZgM[hN\hP^jRblTemVhmYinZklZklZlj[liZnhZnhZog\oi[liZkhYjfZjf[ie\ieZhfZfgWfgUbgQajWerao|s~Ž–¥¬«¹ÂÇÐ×Úáçîó÷öüüøüûõúôóöíîòäéêÜãäÒÜÛÉÓÒ¾Î˸ÉƳþ«½¶¤Ã·§Ç¹¬ÍÁµÖÉÁßÔÐéßÞóèîøñøýõÿþøÿÿüÿþýÿýüÿüýÿüþýýÿþþþþþþþþþþþþþþþþþþþÿþüÿþüþýûÿþüÿýúÿýúÿýúÿüùÿû÷ÿû÷ÿýüÿüûþúûÿûüÿýþÿþÿÿýþþüýÿüûÿþûÿýûýôïíâÜæÙÑðâÙüñëÿúýÿüÿÿýþÿÿýÿÿûýÿúýÿþüýÿýþÿýþÿÿþÿÿÿýÿþõÿþíÿüæÿüáþùãÿþçäßÉŠ†mPJ0RM0SL/SM-TN.UO/UP2UP2TP3SO2PO3ON2PL1NM1OM4LO4LN6JP6JO8HP8JS8GP3GP3IS1MT3OV4V\8\d=grHtUˆ“i›s…lnuTZaBRV;LN6NN6MM5NL5OM6RP7WS:YU<ZT>XR<TO<QL9KH9GE8EC7@B7=>6:@6:@69A67B47B46C26C2;C8:B79A69A69A69A6:B7;C8;C8:B7:B7;C8;C8=E:>F;=G<=G?<H>>H=>I9?G8>F7>D8=B;=D=9C;6@74B19I/DX5Ri?[uEZ{FWyFTqEIdA=T:2H3/@.->+6H2@R8L_CReGSgKOcG@W=6I30:/07/-4,YgMZhN\hP^jRblTemVinZjo[mn\lm[mk\mj[nhZnhZoi]oi[liZkhYjfZieZie\ieZig[ghXghVchRajWerao|s{‹ŠŸ¦¢°¹ÁËÔÔÝäéñôòúüôúøñöðíðçèìÞâãÕÚÛÉÒÑ¿ÌɶÉıþ«¿¸¦¼³¢Ê¾®ÓŸÜÐÄæÙÑíâàöìíÿôúÿùÿÿ÷ÿÿúÿÿüÿþýÿýüÿûüþüþýþÿÿþþþþþþþþþþþþþþþþþþÿþüÿþüþýûþýûÿýúÿýúÿýúÿûøÿúöþùõÿýüÿûúýùúþúûþüýÿýþÿþÿÿýþÿüûÿýúÿüúÿøó÷ìæòåÝøêáÿôîÿúýÿüÿÿýþÿÿýÿÿûýÿúýÿþüýÿüýÿýþÿÿþÿÿÿýÿþõÿýìÿûãþúßÿüæÿÿéçâÌŒˆoRL2TO2TM0UN1TN.UO/VQ3VQ3UQ4SO2ON2NM1PL1NM1NL3KN3LN6KQ7KP9JR:LU:IR5JS6OY7SZ9T[9]c?fnG‚’c’¦sŸ±›ª’¡zˆ”pr{\\bFLP7KM5LK6KI4LJ5PK5TN8VP:WQ;VP:SN;QL9LI:IG:GE9CE:=>6:@6:@69A67B47B46C26C2;C8;C8:B79A69A6:B7;C8;C8;C8;C8;C8;C8<D9=E:>F;=G<=G?<H>=G<=H8>F7=E6=C7=B;:A:7A95?64B19I/BV3Ne;Uo?Tu@RtAPmAE`=9P6-C.+<*+<)1C-<N4H[?PcERfJNbF@W=5H2,6++2*'.& \ No newline at end of file
diff --git a/gs/jpeg/testimgp.jpg b/gs/jpeg/testimgp.jpg
new file mode 100644
index 000000000..8cbb658bb
--- /dev/null
+++ b/gs/jpeg/testimgp.jpg
Binary files differ
diff --git a/gs/jpeg/testorig.jpg b/gs/jpeg/testorig.jpg
new file mode 100644
index 000000000..9816a0c62
--- /dev/null
+++ b/gs/jpeg/testorig.jpg
Binary files differ
diff --git a/gs/jpeg/testprog.jpg b/gs/jpeg/testprog.jpg
new file mode 100644
index 000000000..920fee2e3
--- /dev/null
+++ b/gs/jpeg/testprog.jpg
Binary files differ
diff --git a/gs/jpeg/usage.doc b/gs/jpeg/usage.doc
new file mode 100644
index 000000000..49f3d7fff
--- /dev/null
+++ b/gs/jpeg/usage.doc
@@ -0,0 +1,475 @@
+USAGE instructions for the Independent JPEG Group's JPEG software
+=================================================================
+
+This file describes usage of the JPEG conversion programs cjpeg and djpeg,
+as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See
+the other documentation files if you wish to use the JPEG library within
+your own programs.)
+
+If you are on a Unix machine you may prefer to read the Unix-style manual
+pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1.
+
+
+INTRODUCTION
+
+These programs implement JPEG image compression and decompression. JPEG
+(pronounced "jay-peg") is a standardized compression method for full-color
+and gray-scale images. JPEG is designed to handle "real-world" scenes,
+for example scanned photographs. Cartoons, line drawings, and other
+non-realistic images are not JPEG's strong suit; on that sort of material
+you may get poor image quality and/or little compression.
+
+JPEG is lossy, meaning that the output image is not necessarily identical to
+the input image. Hence you should not use JPEG if you have to have identical
+output bits. However, on typical real-world images, very good compression
+levels can be obtained with no visible change, and amazingly high compression
+is possible if you can tolerate a low-quality image. You can trade off image
+quality against file size by adjusting the compressor's "quality" setting.
+
+
+GENERAL USAGE
+
+We provide two programs, cjpeg to compress an image file into JPEG format,
+and djpeg to decompress a JPEG file back into a conventional image format.
+
+On Unix-like systems, you say:
+ cjpeg [switches] [imagefile] >jpegfile
+or
+ djpeg [switches] [jpegfile] >imagefile
+The programs read the specified input file, or standard input if none is
+named. They always write to standard output (with trace/error messages to
+standard error). These conventions are handy for piping images between
+programs.
+
+On most non-Unix systems, you say:
+ cjpeg [switches] imagefile jpegfile
+or
+ djpeg [switches] jpegfile imagefile
+i.e., both the input and output files are named on the command line. This
+style is a little more foolproof, and it loses no functionality if you don't
+have pipes. (You can get this style on Unix too, if you prefer, by defining
+TWO_FILE_COMMANDLINE when you compile the programs; see install.doc.)
+
+You can also say:
+ cjpeg [switches] -outfile jpegfile imagefile
+or
+ djpeg [switches] -outfile imagefile jpegfile
+This syntax works on all systems, so it is useful for scripts.
+
+The currently supported image file formats are: PPM (PBMPLUS color format),
+PGM (PBMPLUS gray-scale format), BMP, GIF, Targa, and RLE (Utah Raster Toolkit
+format). (RLE is supported only if the URT library is available.)
+cjpeg recognizes the input image format automatically, with the exception
+of some Targa-format files. You have to tell djpeg which format to generate.
+
+JPEG files are in the defacto standard JFIF file format. There are other,
+less widely used JPEG-based file formats, but we don't support them.
+
+All switch names may be abbreviated; for example, -grayscale may be written
+-gray or -gr. Most of the "basic" switches can be abbreviated to as little as
+one letter. Upper and lower case are equivalent (-GIF is the same as -gif).
+British spellings are also accepted (e.g., -greyscale), though for brevity
+these are not mentioned below.
+
+
+CJPEG DETAILS
+
+The basic command line switches for cjpeg are:
+
+ -quality N Scale quantization tables to adjust image quality.
+ Quality is 0 (worst) to 100 (best); default is 75.
+ (See below for more info.)
+
+ -grayscale Create monochrome JPEG file from color input.
+ Be sure to use this switch when compressing a grayscale
+ GIF file, because cjpeg isn't bright enough to notice
+ whether a GIF file uses only shades of gray. By
+ saying -grayscale, you'll get a smaller JPEG file that
+ takes less time to process.
+
+ -optimize Perform optimization of entropy encoding parameters.
+ Without this, default encoding parameters are used.
+ -optimize usually makes the JPEG file a little smaller,
+ but cjpeg runs somewhat slower and needs much more
+ memory. Image quality and speed of decompression are
+ unaffected by -optimize.
+
+ -progressive Create progressive JPEG file (see below).
+
+ -targa Input file is Targa format. Targa files that contain
+ an "identification" field will not be automatically
+ recognized by cjpeg; for such files you must specify
+ -targa to make cjpeg treat the input as Targa format.
+ For most Targa files, you won't need this switch.
+
+The -quality switch lets you trade off compressed file size against quality of
+the reconstructed image: the higher the quality setting, the larger the JPEG
+file, and the closer the output image will be to the original input. Normally
+you want to use the lowest quality setting (smallest file) that decompresses
+into something visually indistinguishable from the original image. For this
+purpose the quality setting should be between 50 and 95; the default of 75 is
+often about right. If you see defects at -quality 75, then go up 5 or 10
+counts at a time until you are happy with the output image. (The optimal
+setting will vary from one image to another.)
+
+-quality 100 will generate a quantization table of all 1's, minimizing loss
+in the quantization step (but there is still information loss in subsampling,
+as well as roundoff error). This setting is mainly of interest for
+experimental purposes. Quality values above about 95 are NOT recommended for
+normal use; the compressed file size goes up dramatically for hardly any gain
+in output image quality.
+
+In the other direction, quality values below 50 will produce very small files
+of low image quality. Settings around 5 to 10 might be useful in preparing an
+index of a large image library, for example. Try -quality 2 (or so) for some
+amusing Cubist effects. (Note: quality values below about 25 generate 2-byte
+quantization tables, which are considered optional in the JPEG standard.
+cjpeg emits a warning message when you give such a quality value, because some
+other JPEG programs may be unable to decode the resulting file. Use -baseline
+if you need to ensure compatibility at low quality values.)
+
+The -progressive switch creates a "progressive JPEG" file. In this type of
+JPEG file, the data is stored in multiple scans of increasing quality. If the
+file is being transmitted over a slow communications link, the decoder can use
+the first scan to display a low-quality image very quickly, and can then
+improve the display with each subsequent scan. The final image is exactly
+equivalent to a standard JPEG file of the same quality setting, and the total
+file size is about the same --- often a little smaller. CAUTION: progressive
+JPEG is not yet widely implemented, so many decoders will be unable to view a
+progressive JPEG file at all.
+
+Switches for advanced users:
+
+ -dct int Use integer DCT method (default).
+ -dct fast Use fast integer DCT (less accurate).
+ -dct float Use floating-point DCT method.
+ The float method is very slightly more accurate than
+ the int method, but is much slower unless your machine
+ has very fast floating-point hardware. Also note that
+ results of the floating-point method may vary slightly
+ across machines, while the integer methods should give
+ the same results everywhere. The fast integer method
+ is much less accurate than the other two.
+
+ -restart N Emit a JPEG restart marker every N MCU rows, or every
+ N MCU blocks if "B" is attached to the number.
+ -restart 0 (the default) means no restart markers.
+
+ -smooth N Smooth the input image to eliminate dithering noise.
+ N, ranging from 1 to 100, indicates the strength of
+ smoothing. 0 (the default) means no smoothing.
+
+ -maxmemory N Set limit for amount of memory to use in processing
+ large images. Value is in thousands of bytes, or
+ millions of bytes if "M" is attached to the number.
+ For example, -max 4m selects 4000000 bytes. If more
+ space is needed, temporary files will be used.
+
+ -verbose Enable debug printout. More -v's give more printout.
+ or -debug Also, version information is printed at startup.
+
+The -restart option inserts extra markers that allow a JPEG decoder to
+resynchronize after a transmission error. Without restart markers, any damage
+to a compressed file will usually ruin the image from the point of the error
+to the end of the image; with restart markers, the damage is usually confined
+to the portion of the image up to the next restart marker. Of course, the
+restart markers occupy extra space. We recommend -restart 1 for images that
+will be transmitted across unreliable networks such as Usenet.
+
+The -smooth option filters the input to eliminate fine-scale noise. This is
+often useful when converting GIF files to JPEG: a moderate smoothing factor of
+10 to 50 gets rid of dithering patterns in the input file, resulting in a
+smaller JPEG file and a better-looking image. Too large a smoothing factor
+will visibly blur the image, however.
+
+Switches for wizards:
+
+ -baseline Force a baseline JPEG file to be generated. This
+ clamps quantization values to 8 bits even at low
+ quality settings.
+
+ -qtables file Use the quantization tables given in the specified
+ text file.
+
+ -qslots N[,...] Select which quantization table to use for each color
+ component.
+
+ -sample HxV[,...] Set JPEG sampling factors for each color component.
+
+ -scans file Use the scan script given in the specified text file.
+
+The "wizard" switches are intended for experimentation with JPEG. If you
+don't know what you are doing, DON'T USE THEM. These switches are documented
+further in the file wizard.doc.
+
+
+DJPEG DETAILS
+
+The basic command line switches for djpeg are:
+
+ -colors N Reduce image to at most N colors. This reduces the
+ or -quantize N number of colors used in the output image, so that it
+ can be displayed on a colormapped display or stored in
+ a colormapped file format. For example, if you have
+ an 8-bit display, you'd need to reduce to 256 or fewer
+ colors. (-colors is the recommended name, -quantize
+ is provided only for backwards compatibility.)
+
+ -fast Select recommended processing options for fast, low
+ quality output. (The default options are chosen for
+ highest quality output.) Currently, this is equivalent
+ to "-dct fast -nosmooth -onepass -dither ordered".
+
+ -grayscale Force gray-scale output even if JPEG file is color.
+ Useful for viewing on monochrome displays; also,
+ djpeg runs noticeably faster in this mode.
+
+ -scale M/N Scale the output image by a factor M/N. Currently
+ the scale factor must be 1/1, 1/2, 1/4, or 1/8.
+ Scaling is handy if the image is larger than your
+ screen; also, djpeg runs much faster when scaling
+ down the output.
+
+ -bmp Select BMP output format (Windows flavor). 8-bit
+ colormapped format is emitted if -colors or -grayscale
+ is specified, or if the JPEG file is gray-scale;
+ otherwise, 24-bit full-color format is emitted.
+
+ -gif Select GIF output format. Since GIF does not support
+ more than 256 colors, -colors 256 is assumed (unless
+ you specify a smaller number of colors). If you
+ specify -fast, the default number of colors is 216.
+
+ -os2 Select BMP output format (OS/2 1.x flavor). 8-bit
+ colormapped format is emitted if -colors or -grayscale
+ is specified, or if the JPEG file is gray-scale;
+ otherwise, 24-bit full-color format is emitted.
+
+ -pnm Select PBMPLUS (PPM/PGM) output format (this is the
+ default format). PGM is emitted if the JPEG file is
+ gray-scale or if -grayscale is specified; otherwise
+ PPM is emitted.
+
+ -rle Select RLE output format. (Requires URT library.)
+
+ -targa Select Targa output format. Gray-scale format is
+ emitted if the JPEG file is gray-scale or if
+ -grayscale is specified; otherwise, colormapped format
+ is emitted if -colors is specified; otherwise, 24-bit
+ full-color format is emitted.
+
+Switches for advanced users:
+
+ -dct int Use integer DCT method (default).
+ -dct fast Use fast integer DCT (less accurate).
+ -dct float Use floating-point DCT method.
+ The float method is very slightly more accurate than
+ the int method, but is much slower unless your machine
+ has very fast floating-point hardware. Also note that
+ results of the floating-point method may vary slightly
+ across machines, while the integer methods should give
+ the same results everywhere. The fast integer method
+ is much less accurate than the other two.
+
+ -dither fs Use Floyd-Steinberg dithering in color quantization.
+ -dither ordered Use ordered dithering in color quantization.
+ -dither none Do not use dithering in color quantization.
+ By default, Floyd-Steinberg dithering is applied when
+ quantizing colors; this is slow but usually produces
+ the best results. Ordered dither is a compromise
+ between speed and quality; no dithering is fast but
+ usually looks awful. Note that these switches have
+ no effect unless color quantization is being done.
+ Ordered dither is only available in -onepass mode.
+
+ -map FILE Quantize to the colors used in the specified image
+ file. This is useful for producing multiple files
+ with identical color maps, or for forcing a predefined
+ set of colors to be used. The FILE must be a GIF
+ or PPM file. This option overrides -colors and
+ -onepass.
+
+ -nosmooth Use a faster, lower-quality upsampling routine.
+
+ -onepass Use one-pass instead of two-pass color quantization.
+ The one-pass method is faster and needs less memory,
+ but it produces a lower-quality image. -onepass is
+ ignored unless you also say -colors N. Also,
+ the one-pass method is always used for gray-scale
+ output (the two-pass method is no improvement then).
+
+ -maxmemory N Set limit for amount of memory to use in processing
+ large images. Value is in thousands of bytes, or
+ millions of bytes if "M" is attached to the number.
+ For example, -max 4m selects 4000000 bytes. If more
+ space is needed, temporary files will be used.
+
+ -verbose Enable debug printout. More -v's give more printout.
+ or -debug Also, version information is printed at startup.
+
+
+HINTS FOR CJPEG
+
+Color GIF files are not the ideal input for JPEG; JPEG is really intended for
+compressing full-color (24-bit) images. In particular, don't try to convert
+cartoons, line drawings, and other images that have only a few distinct
+colors. GIF works great on these, JPEG does not. If you want to convert a
+GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options
+to get a satisfactory conversion. -smooth 10 or so is often helpful.
+
+Avoid running an image through a series of JPEG compression/decompression
+cycles. Image quality loss will accumulate; after ten or so cycles the image
+may be noticeably worse than it was after one cycle. It's best to use a
+lossless format while manipulating an image, then convert to JPEG format when
+you are ready to file the image away.
+
+The -optimize option to cjpeg is worth using when you are making a "final"
+version for posting or archiving. It's also a win when you are using low
+quality settings to make very small JPEG files; the percentage improvement
+is often a lot more than it is on larger files. (At present, -optimize
+mode is always selected when generating progressive JPEG files.)
+
+
+HINTS FOR DJPEG
+
+To get a quick preview of an image, use the -grayscale and/or -scale switches.
+"-grayscale -scale 1/8" is the fastest case.
+
+Several options are available that trade off image quality to gain speed.
+"-fast" turns on the recommended settings.
+
+"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality.
+When producing a color-quantized image, "-onepass -dither ordered" is fast but
+much lower quality than the default behavior. "-dither none" may give
+acceptable results in two-pass mode, but is seldom tolerable in one-pass mode.
+
+If you are fortunate enough to have very fast floating point hardware,
+"-dct float" may be even faster than "-dct fast". But on most machines
+"-dct float" is slower than "-dct int"; in this case it is not worth using,
+because its theoretical accuracy advantage is too small to be significant
+in practice.
+
+Two-pass color quantization requires a good deal of memory; on MS-DOS machines
+it may run out of memory even with -maxmemory 0. In that case you can still
+decompress, with some loss of image quality, by specifying -onepass for
+one-pass quantization.
+
+
+HINTS FOR BOTH PROGRAMS
+
+If more space is needed than will fit in the available main memory (as
+determined by -maxmemory), temporary files will be used. (MS-DOS versions
+will try to get extended or expanded memory first.) The temporary files are
+often rather large: in typical cases they occupy three bytes per pixel, for
+example 3*800*600 = 1.44Mb for an 800x600 image. If you don't have enough
+free disk space, leave out -progressive and -optimize (for cjpeg) or specify
+-onepass (for djpeg).
+
+On MS-DOS, the temporary files are created in the directory named by the TMP
+or TEMP environment variable, or in the current directory if neither of those
+exist. Amiga implementations put the temp files in the directory named by
+JPEGTMP:, so be sure to assign JPEGTMP: to a disk partition with adequate free
+space.
+
+The default memory usage limit (-maxmemory) is set when the software is
+compiled. If you get an "insufficient memory" error, try specifying a smaller
+-maxmemory value, even -maxmemory 0 to use the absolute minimum space. You
+may want to recompile with a smaller default value if this happens often.
+
+On machines that have "environment" variables, you can define the environment
+variable JPEGMEM to set the default memory limit. The value is specified as
+described for the -maxmemory switch. JPEGMEM overrides the default value
+specified when the program was compiled, and itself is overridden by an
+explicit -maxmemory switch.
+
+On MS-DOS machines, -maxmemory is the amount of main (conventional) memory to
+use. (Extended or expanded memory is also used if available.) Most
+DOS-specific versions of this software do their own memory space estimation
+and do not need you to specify -maxmemory.
+
+
+JPEGTRAN
+
+jpegtran translates JPEG files from one variant of JPEG to another, for
+example from baseline JPEG to progressive JPEG or vice versa. The
+transformation is lossless: no image degradation occurs, which would not
+be true if you used djpeg followed by cjpeg. However, you cannot alter
+the image quality, because that would not be a lossless operation.
+
+jpegtran operates similarly to cjpeg, except that it reads a JPEG file
+and writes another JPEG file.
+
+jpegtran accepts a subset of the switches recognized by cjpeg:
+ -outfile filename
+ -optimize
+ -progressive
+ -restart N
+ -scans file
+ -maxmemory N
+ -verbose
+ -debug
+See the previous discussion of cjpeg for details about these switches.
+
+If you specify no switches, you get a plain baseline-JPEG output file.
+
+
+THE COMMENT UTILITIES
+
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+
+We provide two utility programs to display COM block contents and add COM
+blocks to a JPEG file.
+
+rdjpgcom searches a JPEG file and prints the contents of any COM blocks on
+standard output. The command line syntax is
+ rdjpgcom [-verbose] [inputfilename]
+The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG
+image dimensions. If you omit the input file name from the command line,
+the JPEG file is read from standard input. (This may not work on some
+operating systems, if binary data can't be read from stdin.)
+
+wrjpgcom adds a COM block, containing text you provide, to a JPEG file.
+Ordinarily, the COM block is added after any existing COM blocks, but you
+can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG
+file; it does not modify the input file. DO NOT try to overwrite the input
+file by directing wrjpgcom's output back into it; on most systems this will
+just destroy your file.
+
+The command line syntax for wrjpgcom is similar to cjpeg's. On Unix-like
+systems, it is
+ wrjpgcom [switches] [inputfilename]
+The output file is written to standard output. The input file comes from
+the named file, or from standard input if no input file is named.
+
+On most non-Unix systems, the syntax is
+ wrjpgcom [switches] inputfilename outputfilename
+where both input and output file names must be given explicitly.
+
+wrjpgcom understands three switches:
+ -replace Delete any existing COM blocks from the file.
+ -comment "Comment text" Supply new COM text on command line.
+ -cfile name Read text for new COM block from named file.
+(Switch names can be abbreviated.) If you have only one line of comment text
+to add, you can provide it on the command line with -comment. The comment
+text must be surrounded with quotes so that it is treated as a single
+argument. Longer comments can be read from a text file.
+
+If you give neither -comment nor -cfile, then wrjpgcom will read the comment
+text from standard input. (In this case an input image file name MUST be
+supplied, so that the source JPEG file comes from somewhere else.) You can
+enter multiple lines, up to 64KB worth. Type an end-of-file indicator
+(usually control-D or control-Z) to terminate the comment text entry.
+
+wrjpgcom will not add a COM block if the provided comment string is empty.
+Therefore -replace -comment "" can be used to delete all COM blocks from a
+file.
+
+These utility programs do not depend on the IJG JPEG library. In
+particular, the source code for rdjpgcom is intended as an illustration of
+the minimum amount of code required to parse a JPEG file header correctly.
diff --git a/gs/jpeg/wizard.doc b/gs/jpeg/wizard.doc
new file mode 100644
index 000000000..54170b227
--- /dev/null
+++ b/gs/jpeg/wizard.doc
@@ -0,0 +1,211 @@
+Advanced usage instructions for the Independent JPEG Group's JPEG software
+==========================================================================
+
+This file describes cjpeg's "switches for wizards".
+
+The "wizard" switches are intended for experimentation with JPEG by persons
+who are reasonably knowledgeable about the JPEG standard. If you don't know
+what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files
+with worse image quality and/or poorer compression than you'd get from the
+default settings. Furthermore, these switches must be used with caution
+when making files intended for general use, because not all JPEG decoders
+will support unusual JPEG parameter settings.
+
+
+Quantization Table Adjustment
+-----------------------------
+
+Ordinarily, cjpeg starts with a default set of tables (the same ones given
+as examples in the JPEG standard) and scales them up or down according to
+the -quality setting. The details of the scaling algorithm can be found in
+jcparam.c. At very low quality settings, some quantization table entries
+can get scaled up to values exceeding 255. Although 2-byte quantization
+values are supported by the IJG software, this feature is not in baseline
+JPEG and is not supported by all implementations. If you need to ensure
+wide compatibility of low-quality files, you can constrain the scaled
+quantization values to no more than 255 by giving the -baseline switch.
+Note that use of -baseline will result in poorer quality for the same file
+size, since more bits than necessary are expended on higher AC coefficients.
+
+You can substitute a different set of quantization values by using the
+-qtables switch:
+
+ -qtables file Use the quantization tables given in the named file.
+
+The specified file should be a text file containing decimal quantization
+values. The file should contain one to four tables, each of 64 elements.
+The tables are implicitly numbered 0,1,etc. in order of appearance. Table
+entries appear in normal array order (NOT in the zigzag order in which they
+will be stored in the JPEG file).
+
+Quantization table files are free format, in that arbitrary whitespace can
+appear between numbers. Also, comments can be included: a comment starts
+with '#' and extends to the end of the line. Here is an example file that
+duplicates the default quantization tables:
+
+ # Quantization tables given in JPEG spec, section K.1
+
+ # This is table 0 (the luminance table):
+ 16 11 10 16 24 40 51 61
+ 12 12 14 19 26 58 60 55
+ 14 13 16 24 40 57 69 56
+ 14 17 22 29 51 87 80 62
+ 18 22 37 56 68 109 103 77
+ 24 35 55 64 81 104 113 92
+ 49 64 78 87 103 121 120 101
+ 72 92 95 98 112 100 103 99
+
+ # This is table 1 (the chrominance table):
+ 17 18 24 47 99 99 99 99
+ 18 21 26 66 99 99 99 99
+ 24 26 56 99 99 99 99 99
+ 47 66 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+
+If the -qtables switch is used without -quality, then the specified tables
+are used exactly as-is. If both -qtables and -quality are used, then the
+tables taken from the file are scaled in the same fashion that the default
+tables would be scaled for that quality setting. If -baseline appears, then
+the quantization values are constrained to the range 1-255.
+
+By default, cjpeg will use quantization table 0 for luminance components and
+table 1 for chrominance components. To override this choice, use the -qslots
+switch:
+
+ -qslots N[,...] Select which quantization table to use for
+ each color component.
+
+The -qslots switch specifies a quantization table number for each color
+component, in the order in which the components appear in the JPEG SOF marker.
+For example, to create a separate table for each of Y,Cb,Cr, you could
+provide a -qtables file that defines three quantization tables and say
+"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color
+components, then the last table number is repeated as necessary.
+
+
+Sampling Factor Adjustment
+--------------------------
+
+By default, cjpeg uses 2:1 horizontal and vertical downsampling when
+compressing YCbCr data, and no downsampling for all other color spaces.
+You can override this default with the -sample switch:
+
+ -sample HxV[,...] Set JPEG sampling factors for each color
+ component.
+
+The -sample switch specifies the JPEG sampling factors for each color
+component, in the order in which they appear in the JPEG SOF marker.
+If you specify fewer HxV pairs than there are components, the remaining
+components are set to 1x1 sampling. For example, the default YCbCr setting
+is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to
+"-sample 2x2".
+
+There are still some JPEG decoders in existence that support only 2x1
+sampling (also called 4:2:2 sampling). Compatibility with such decoders can
+be achieved by specifying "-sample 2x1". This is not recommended unless
+really necessary, since it increases file size and encoding/decoding time
+with very little quality gain.
+
+
+Multiple Scan / Progression Control
+-----------------------------------
+
+By default, cjpeg emits a single-scan sequential JPEG file. The
+-progressive switch generates a progressive JPEG file using a default series
+of progression parameters. You can create multiple-scan sequential JPEG
+files or progressive JPEG files with custom progression parameters by using
+the -scans switch:
+
+ -scans file Use the scan sequence given in the named file.
+
+The specified file should be a text file containing a "scan script".
+The script specifies the contents and ordering of the scans to be emitted.
+Each entry in the script defines one scan. A scan definition specifies
+the components to be included in the scan, and for progressive JPEG it also
+specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan
+definitions are separated by semicolons (';'). A semicolon after the last
+scan definition is optional.
+
+Each scan definition contains one to four component indexes, optionally
+followed by a colon (':') and the four progressive-JPEG parameters. The
+component indexes denote which color component(s) are to be transmitted in
+the scan. Components are numbered in the order in which they appear in the
+JPEG SOF marker, with the first component being numbered 0. (Note that these
+indexes are not the "component ID" codes assigned to the components, just
+positional indexes.)
+
+The progression parameters for each scan are:
+ Ss Zigzag index of first coefficient included in scan
+ Se Zigzag index of last coefficient included in scan
+ Ah Zero for first scan of a coefficient, else Al of prior scan
+ Al Successive approximation low bit position for scan
+If the progression parameters are omitted, the values 0,63,0,0 are used,
+producing a sequential JPEG file. cjpeg automatically determines whether
+the script represents a progressive or sequential file, by observing whether
+Ss and Se values other than 0 and 63 appear. (The -progressive switch is
+not needed to specify this; in fact, it is ignored when -scans appears.)
+The scan script must meet the JPEG restrictions on progression sequences.
+(cjpeg checks that the spec's requirements are obeyed.)
+
+Scan script files are free format, in that arbitrary whitespace can appear
+between numbers and around punctuation. Also, comments can be included: a
+comment starts with '#' and extends to the end of the line. For additional
+legibility, commas or dashes can be placed between values. (Actually, any
+single punctuation character other than ':' or ';' can be inserted.) For
+example, the following two scan definitions are equivalent:
+ 0 1 2: 0 63 0 0;
+ 0,1,2 : 0-63, 0,0 ;
+
+Here is an example of a scan script that generates a partially interleaved
+sequential JPEG file:
+
+ 0; # Y only in first scan
+ 1 2; # Cb and Cr in second scan
+
+Here is an example of a progressive scan script using only spectral selection
+(no successive approximation):
+
+ # Interleaved DC scan for Y,Cb,Cr:
+ 0,1,2: 0-0, 0, 0 ;
+ # AC scans:
+ 0: 1-2, 0, 0 ; # First two Y AC coefficients
+ 0: 3-5, 0, 0 ; # Three more
+ 1: 1-63, 0, 0 ; # All AC coefficients for Cb
+ 2: 1-63, 0, 0 ; # All AC coefficients for Cr
+ 0: 6-9, 0, 0 ; # More Y coefficients
+ 0: 10-63, 0, 0 ; # Remaining Y coefficients
+
+Here is an example of a successive-approximation script. This is equivalent
+to the default script used by "cjpeg -progressive" for YCbCr images:
+
+ # Initial DC scan for Y,Cb,Cr (lowest bit not sent)
+ 0,1,2: 0-0, 0, 1 ;
+ # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits:
+ 0: 1-5, 0, 2 ;
+ # Send all Cr,Cb AC coefficients, minus lowest bit:
+ # (chroma data is usually too small to be worth subdividing further;
+ # but note we send Cr first since eye is least sensitive to Cb)
+ 2: 1-63, 0, 1 ;
+ 1: 1-63, 0, 1 ;
+ # Send remaining Y AC coefficients, minus 2 lowest bits:
+ 0: 6-63, 0, 2 ;
+ # Send next-to-lowest bit of all Y AC coefficients:
+ 0: 1-63, 2, 1 ;
+ # At this point we've sent all but the lowest bit of all coefficients.
+ # Send lowest bit of DC coefficients
+ 0,1,2: 0-0, 1, 0 ;
+ # Send lowest bit of AC coefficients
+ 2: 1-63, 1, 0 ;
+ 1: 1-63, 1, 0 ;
+ # Y AC lowest bit scan is last; it's usually the largest scan
+ 0: 1-63, 1, 0 ;
+
+It may be worth pointing out that this script is tuned for quality settings
+of around 50 to 75. For lower quality settings, you'd probably want to use
+a script with fewer stages of successive approximation (otherwise the
+initial scans will be really bad). For higher quality settings, you might
+want to use more stages of successive approximation (so that the initial
+scans are not too large).
diff --git a/gs/jpeg/wrbmp.c b/gs/jpeg/wrbmp.c
new file mode 100644
index 000000000..3283b0f15
--- /dev/null
+++ b/gs/jpeg/wrbmp.c
@@ -0,0 +1,442 @@
+/*
+ * wrbmp.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in Microsoft "BMP"
+ * format (MS Windows 3.x and OS/2 1.x flavors).
+ * Either 8-bit colormapped or 24-bit full-color format can be written.
+ * No compression is supported.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * This code contributed by James Arthur Boucher.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef BMP_SUPPORTED
+
+
+/*
+ * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
+ * This is not yet implemented.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * Since BMP stores scanlines bottom-to-top, we have to invert the image
+ * from JPEG's top-to-bottom order. To do this, we save the outgoing data
+ * in a virtual array during put_pixel_row calls, then actually emit the
+ * BMP file during finish_output. The virtual array contains one JSAMPLE per
+ * pixel if the output is grayscale or colormapped, three if it is full color.
+ */
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ boolean is_os2; /* saves the OS2 format request flag */
+
+ jvirt_sarray_ptr whole_image; /* needed to reverse row order */
+ JDIMENSION data_width; /* JSAMPLEs per row */
+ JDIMENSION row_width; /* physical width of one row in the BMP file */
+ int pad_bytes; /* number of padding bytes needed per row */
+ JDIMENSION cur_output_row; /* next row# to write to virtual array */
+} bmp_dest_struct;
+
+typedef bmp_dest_struct * bmp_dest_ptr;
+
+
+/* Forward declarations */
+LOCAL(void) write_colormap
+ JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
+ int map_colors, int map_entry_size));
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* This version is for writing 24-bit pixels */
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ int pad;
+
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+
+ /* Transfer data. Note destination values must be in BGR order
+ * (even though Microsoft's own documents say the opposite).
+ */
+ inptr = dest->pub.buffer[0];
+ outptr = image_ptr[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[1] = *inptr++;
+ outptr[0] = *inptr++;
+ outptr += 3;
+ }
+
+ /* Zero out the pad bytes. */
+ pad = dest->pad_bytes;
+ while (--pad >= 0)
+ *outptr++ = 0;
+}
+
+METHODDEF(void)
+put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* This version is for grayscale OR quantized color output */
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ int pad;
+
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+
+ /* Transfer data. */
+ inptr = dest->pub.buffer[0];
+ outptr = image_ptr[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
+ }
+
+ /* Zero out the pad bytes. */
+ pad = dest->pad_bytes;
+ while (--pad >= 0)
+ *outptr++ = 0;
+}
+
+
+/*
+ * Startup: normally writes the file header.
+ * In this module we may as well postpone everything until finish_output.
+ */
+
+METHODDEF(void)
+start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* no work here */
+}
+
+
+/*
+ * Finish up at the end of the file.
+ *
+ * Here is where we really output the BMP file.
+ *
+ * First, routines to write the Windows and OS/2 variants of the file header.
+ */
+
+LOCAL(void)
+write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
+/* Write a Windows-style BMP file header, including colormap if needed */
+{
+ char bmpfileheader[14];
+ char bmpinfoheader[40];
+#define PUT_2B(array,offset,value) \
+ (array[offset] = (char) ((value) & 0xFF), \
+ array[offset+1] = (char) (((value) >> 8) & 0xFF))
+#define PUT_4B(array,offset,value) \
+ (array[offset] = (char) ((value) & 0xFF), \
+ array[offset+1] = (char) (((value) >> 8) & 0xFF), \
+ array[offset+2] = (char) (((value) >> 16) & 0xFF), \
+ array[offset+3] = (char) (((value) >> 24) & 0xFF))
+ INT32 headersize, bfSize;
+ int bits_per_pixel, cmap_entries;
+
+ /* Compute colormap size and total file size */
+ if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* Colormapped RGB */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ } else {
+ /* Unquantized, full color RGB */
+ bits_per_pixel = 24;
+ cmap_entries = 0;
+ }
+ } else {
+ /* Grayscale output. We need to fake a 256-entry colormap. */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ }
+ /* File size */
+ headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
+ bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
+ MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
+
+ /* Fill the file header */
+ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
+ bmpfileheader[1] = 0x4D;
+ PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
+ /* we leave bfReserved1 & bfReserved2 = 0 */
+ PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
+
+ /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
+ PUT_2B(bmpinfoheader, 0, 40); /* biSize */
+ PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
+ PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
+ PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
+ PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
+ /* we leave biCompression = 0, for none */
+ /* we leave biSizeImage = 0; this is correct for uncompressed data */
+ if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
+ PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
+ PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
+ }
+ PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
+ /* we leave biClrImportant = 0 */
+
+ if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ if (cmap_entries > 0)
+ write_colormap(cinfo, dest, cmap_entries, 4);
+}
+
+
+LOCAL(void)
+write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
+/* Write an OS2-style BMP file header, including colormap if needed */
+{
+ char bmpfileheader[14];
+ char bmpcoreheader[12];
+ INT32 headersize, bfSize;
+ int bits_per_pixel, cmap_entries;
+
+ /* Compute colormap size and total file size */
+ if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* Colormapped RGB */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ } else {
+ /* Unquantized, full color RGB */
+ bits_per_pixel = 24;
+ cmap_entries = 0;
+ }
+ } else {
+ /* Grayscale output. We need to fake a 256-entry colormap. */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ }
+ /* File size */
+ headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
+ bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
+ MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
+
+ /* Fill the file header */
+ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
+ bmpfileheader[1] = 0x4D;
+ PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
+ /* we leave bfReserved1 & bfReserved2 = 0 */
+ PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
+
+ /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
+ PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
+ PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
+ PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
+ PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
+ PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
+
+ if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ if (cmap_entries > 0)
+ write_colormap(cinfo, dest, cmap_entries, 3);
+}
+
+
+/*
+ * Write the colormap.
+ * Windows uses BGR0 map entries; OS/2 uses BGR entries.
+ */
+
+LOCAL(void)
+write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
+ int map_colors, int map_entry_size)
+{
+ JSAMPARRAY colormap = cinfo->colormap;
+ int num_colors = cinfo->actual_number_of_colors;
+ FILE * outfile = dest->pub.output_file;
+ int i;
+
+ if (colormap != NULL) {
+ if (cinfo->out_color_components == 3) {
+ /* Normal case with RGB colormap */
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(colormap[2][i]), outfile);
+ putc(GETJSAMPLE(colormap[1][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ } else {
+ /* Grayscale colormap (only happens with grayscale quantization) */
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ }
+ } else {
+ /* If no colormap, must be grayscale data. Generate a linear "map". */
+ for (i = 0; i < 256; i++) {
+ putc(i, outfile);
+ putc(i, outfile);
+ putc(i, outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ }
+ /* Pad colormap with zeros to ensure specified number of colormap entries */
+ if (i > map_colors)
+ ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
+ for (; i < map_colors; i++) {
+ putc(0, outfile);
+ putc(0, outfile);
+ putc(0, outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+}
+
+
+METHODDEF(void)
+finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ register FILE * outfile = dest->pub.output_file;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW data_ptr;
+ JDIMENSION row;
+ register JDIMENSION col;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Write the header and colormap */
+ if (dest->is_os2)
+ write_os2_header(cinfo, dest);
+ else
+ write_bmp_header(cinfo, dest);
+
+ /* Write the file body from our virtual array */
+ for (row = cinfo->output_height; row > 0; row--) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) (cinfo->output_height - row);
+ progress->pub.pass_limit = (long) cinfo->output_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
+ data_ptr = image_ptr[0];
+ for (col = dest->row_width; col > 0; col--) {
+ putc(GETJSAMPLE(*data_ptr), outfile);
+ data_ptr++;
+ }
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Make sure we wrote the output file OK */
+ fflush(outfile);
+ if (ferror(outfile))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for BMP format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
+{
+ bmp_dest_ptr dest;
+ JDIMENSION row_width;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (bmp_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(bmp_dest_struct));
+ dest->pub.start_output = start_output_bmp;
+ dest->pub.finish_output = finish_output_bmp;
+ dest->is_os2 = is_os2;
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = put_gray_rows;
+ else
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ } else {
+ ERREXIT(cinfo, JERR_BMP_COLORSPACE);
+ }
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
+ row_width = cinfo->output_width * cinfo->output_components;
+ dest->data_width = row_width;
+ while ((row_width & 3) != 0) row_width++;
+ dest->row_width = row_width;
+ dest->pad_bytes = (int) (row_width - dest->data_width);
+
+ /* Allocate space for inversion array, prepare for write pass */
+ dest->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ row_width, cinfo->output_height, (JDIMENSION) 1);
+ dest->cur_output_row = 0;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* BMP_SUPPORTED */
diff --git a/gs/jpeg/wrgif.c b/gs/jpeg/wrgif.c
new file mode 100644
index 000000000..85cfaa8bd
--- /dev/null
+++ b/gs/jpeg/wrgif.c
@@ -0,0 +1,505 @@
+/*
+ * wrgif.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ **************************************************************************
+ * WARNING: You will need an LZW patent license from Unisys in order to *
+ * use this file legally in any commercial or shareware application. *
+ **************************************************************************
+ *
+ * This file contains routines to write output images in GIF format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ */
+
+/*
+ * This code is loosely based on ppmtogif from the PBMPLUS distribution
+ * of Feb. 1991. That file contains the following copyright notice:
+ * Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
+ * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
+ * Copyright (C) 1989 by Jef Poskanzer.
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * We are also required to state that
+ * "The Graphics Interchange Format(c) is the Copyright property of
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ * CompuServe Incorporated."
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef GIF_SUPPORTED
+
+
+#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */
+
+typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */
+
+#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS)
+
+#define HSIZE 5003 /* hash table size for 80% occupancy */
+
+typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */
+
+#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
+
+
+/*
+ * The LZW hash table consists of two parallel arrays:
+ * hash_code[i] code of symbol in slot i, or 0 if empty slot
+ * hash_value[i] symbol's value; undefined if empty slot
+ * where slot values (i) range from 0 to HSIZE-1. The symbol value is
+ * its prefix symbol's code concatenated with its suffix character.
+ *
+ * Algorithm: use open addressing double hashing (no chaining) on the
+ * prefix code / suffix character combination. We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe.
+ *
+ * The hash_value[] table is allocated from FAR heap space since it would
+ * use up rather a lot of the near data space in a PC.
+ */
+
+typedef INT32 hash_entry; /* must hold (code_int<<8) | byte */
+
+#define HASH_ENTRY(prefix,suffix) ((((hash_entry) (prefix)) << 8) | (suffix))
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ j_decompress_ptr cinfo; /* back link saves passing separate parm */
+
+ /* State for packing variable-width codes into a bitstream */
+ int n_bits; /* current number of bits/code */
+ code_int maxcode; /* maximum code, given n_bits */
+ int init_bits; /* initial n_bits ... restored after clear */
+ INT32 cur_accum; /* holds bits not yet output */
+ int cur_bits; /* # of bits in cur_accum */
+
+ /* LZW string construction */
+ code_int waiting_code; /* symbol not yet output; may be extendable */
+ boolean first_byte; /* if TRUE, waiting_code is not valid */
+
+ /* State for LZW code assignment */
+ code_int ClearCode; /* clear code (doesn't change) */
+ code_int EOFCode; /* EOF code (ditto) */
+ code_int free_code; /* first not-yet-used symbol code */
+
+ /* LZW hash table */
+ code_int *hash_code; /* => hash table of symbol codes */
+ hash_entry FAR *hash_value; /* => hash table of symbol values */
+
+ /* GIF data packet construction buffer */
+ int bytesinpkt; /* # of bytes in current packet */
+ char packetbuf[256]; /* workspace for accumulating packet */
+
+} gif_dest_struct;
+
+typedef gif_dest_struct * gif_dest_ptr;
+
+
+/*
+ * Routines to package compressed data bytes into GIF data blocks.
+ * A data block consists of a count byte (1..255) and that many data bytes.
+ */
+
+LOCAL(void)
+flush_packet (gif_dest_ptr dinfo)
+/* flush any accumulated data */
+{
+ if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */
+ dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
+ if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
+ != (size_t) dinfo->bytesinpkt)
+ ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
+ dinfo->bytesinpkt = 0;
+ }
+}
+
+
+/* Add a character to current packet; flush to disk if necessary */
+#define CHAR_OUT(dinfo,c) \
+ { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \
+ if ((dinfo)->bytesinpkt >= 255) \
+ flush_packet(dinfo); \
+ }
+
+
+/* Routine to convert variable-width codes into a byte stream */
+
+LOCAL(void)
+output (gif_dest_ptr dinfo, code_int code)
+/* Emit a code of n_bits bits */
+/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
+{
+ dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
+ dinfo->cur_bits += dinfo->n_bits;
+
+ while (dinfo->cur_bits >= 8) {
+ CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
+ dinfo->cur_accum >>= 8;
+ dinfo->cur_bits -= 8;
+ }
+
+ /*
+ * If the next entry is going to be too big for the code size,
+ * then increase it, if possible. We do this here to ensure
+ * that it's done in sync with the decoder's codesize increases.
+ */
+ if (dinfo->free_code > dinfo->maxcode) {
+ dinfo->n_bits++;
+ if (dinfo->n_bits == MAX_LZW_BITS)
+ dinfo->maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */
+ else
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ }
+}
+
+
+/* The LZW algorithm proper */
+
+
+LOCAL(void)
+clear_hash (gif_dest_ptr dinfo)
+/* Fill the hash table with empty entries */
+{
+ /* It's sufficient to zero hash_code[] */
+ MEMZERO(dinfo->hash_code, HSIZE * SIZEOF(code_int));
+}
+
+
+LOCAL(void)
+clear_block (gif_dest_ptr dinfo)
+/* Reset compressor and issue a Clear code */
+{
+ clear_hash(dinfo); /* delete all the symbols */
+ dinfo->free_code = dinfo->ClearCode + 2;
+ output(dinfo, dinfo->ClearCode); /* inform decoder */
+ dinfo->n_bits = dinfo->init_bits; /* reset code size */
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+}
+
+
+LOCAL(void)
+compress_init (gif_dest_ptr dinfo, int i_bits)
+/* Initialize LZW compressor */
+{
+ /* init all the state variables */
+ dinfo->n_bits = dinfo->init_bits = i_bits;
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ dinfo->ClearCode = ((code_int) 1 << (i_bits - 1));
+ dinfo->EOFCode = dinfo->ClearCode + 1;
+ dinfo->free_code = dinfo->ClearCode + 2;
+ dinfo->first_byte = TRUE; /* no waiting symbol yet */
+ /* init output buffering vars */
+ dinfo->bytesinpkt = 0;
+ dinfo->cur_accum = 0;
+ dinfo->cur_bits = 0;
+ /* clear hash table */
+ clear_hash(dinfo);
+ /* GIF specifies an initial Clear code */
+ output(dinfo, dinfo->ClearCode);
+}
+
+
+LOCAL(void)
+compress_byte (gif_dest_ptr dinfo, int c)
+/* Accept and compress one 8-bit byte */
+{
+ register hash_int i;
+ register hash_int disp;
+ register hash_entry probe_value;
+
+ if (dinfo->first_byte) { /* need to initialize waiting_code */
+ dinfo->waiting_code = c;
+ dinfo->first_byte = FALSE;
+ return;
+ }
+
+ /* Probe hash table to see if a symbol exists for
+ * waiting_code followed by c.
+ * If so, replace waiting_code by that symbol and return.
+ */
+ i = ((hash_int) c << (MAX_LZW_BITS-8)) + dinfo->waiting_code;
+ /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */
+ if (i >= HSIZE)
+ i -= HSIZE;
+
+ probe_value = HASH_ENTRY(dinfo->waiting_code, c);
+
+ if (dinfo->hash_code[i] != 0) { /* is first probed slot empty? */
+ if (dinfo->hash_value[i] == probe_value) {
+ dinfo->waiting_code = dinfo->hash_code[i];
+ return;
+ }
+ if (i == 0) /* secondary hash (after G. Knott) */
+ disp = 1;
+ else
+ disp = HSIZE - i;
+ for (;;) {
+ i -= disp;
+ if (i < 0)
+ i += HSIZE;
+ if (dinfo->hash_code[i] == 0)
+ break; /* hit empty slot */
+ if (dinfo->hash_value[i] == probe_value) {
+ dinfo->waiting_code = dinfo->hash_code[i];
+ return;
+ }
+ }
+ }
+
+ /* here when hashtable[i] is an empty slot; desired symbol not in table */
+ output(dinfo, dinfo->waiting_code);
+ if (dinfo->free_code < LZW_TABLE_SIZE) {
+ dinfo->hash_code[i] = dinfo->free_code++; /* add symbol to hashtable */
+ dinfo->hash_value[i] = probe_value;
+ } else
+ clear_block(dinfo);
+ dinfo->waiting_code = c;
+}
+
+
+LOCAL(void)
+compress_term (gif_dest_ptr dinfo)
+/* Clean up at end */
+{
+ /* Flush out the buffered code */
+ if (! dinfo->first_byte)
+ output(dinfo, dinfo->waiting_code);
+ /* Send an EOF code */
+ output(dinfo, dinfo->EOFCode);
+ /* Flush the bit-packing buffer */
+ if (dinfo->cur_bits > 0) {
+ CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
+ }
+ /* Flush the packet buffer */
+ flush_packet(dinfo);
+}
+
+
+/* GIF header construction */
+
+
+LOCAL(void)
+put_word (gif_dest_ptr dinfo, unsigned int w)
+/* Emit a 16-bit word, LSB first */
+{
+ putc(w & 0xFF, dinfo->pub.output_file);
+ putc((w >> 8) & 0xFF, dinfo->pub.output_file);
+}
+
+
+LOCAL(void)
+put_3bytes (gif_dest_ptr dinfo, int val)
+/* Emit 3 copies of same byte value --- handy subr for colormap construction */
+{
+ putc(val, dinfo->pub.output_file);
+ putc(val, dinfo->pub.output_file);
+ putc(val, dinfo->pub.output_file);
+}
+
+
+LOCAL(void)
+emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
+/* Output the GIF file header, including color map */
+/* If colormap==NULL, synthesize a gray-scale colormap */
+{
+ int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
+ int cshift = dinfo->cinfo->data_precision - 8;
+ int i;
+
+ if (num_colors > 256)
+ ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
+ /* Compute bits/pixel and related values */
+ BitsPerPixel = 1;
+ while (num_colors > (1 << BitsPerPixel))
+ BitsPerPixel++;
+ ColorMapSize = 1 << BitsPerPixel;
+ if (BitsPerPixel <= 1)
+ InitCodeSize = 2;
+ else
+ InitCodeSize = BitsPerPixel;
+ /*
+ * Write the GIF header.
+ * Note that we generate a plain GIF87 header for maximum compatibility.
+ */
+ putc('G', dinfo->pub.output_file);
+ putc('I', dinfo->pub.output_file);
+ putc('F', dinfo->pub.output_file);
+ putc('8', dinfo->pub.output_file);
+ putc('7', dinfo->pub.output_file);
+ putc('a', dinfo->pub.output_file);
+ /* Write the Logical Screen Descriptor */
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
+ FlagByte = 0x80; /* Yes, there is a global color table */
+ FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */
+ FlagByte |= (BitsPerPixel-1); /* size of global color table */
+ putc(FlagByte, dinfo->pub.output_file);
+ putc(0, dinfo->pub.output_file); /* Background color index */
+ putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
+ /* Write the Global Color Map */
+ /* If the color map is more than 8 bits precision, */
+ /* we reduce it to 8 bits by shifting */
+ for (i=0; i < ColorMapSize; i++) {
+ if (i < num_colors) {
+ if (colormap != NULL) {
+ if (dinfo->cinfo->out_color_space == JCS_RGB) {
+ /* Normal case: RGB color map */
+ putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
+ putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
+ putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
+ } else {
+ /* Grayscale "color map": possible if quantizing grayscale image */
+ put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
+ }
+ } else {
+ /* Create a gray-scale map of num_colors values, range 0..255 */
+ put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1));
+ }
+ } else {
+ /* fill out the map to a power of 2 */
+ put_3bytes(dinfo, 0);
+ }
+ }
+ /* Write image separator and Image Descriptor */
+ putc(',', dinfo->pub.output_file); /* separator */
+ put_word(dinfo, 0); /* left/top offset */
+ put_word(dinfo, 0);
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
+ /* flag byte: not interlaced, no local color map */
+ putc(0x00, dinfo->pub.output_file);
+ /* Write Initial Code Size byte */
+ putc(InitCodeSize, dinfo->pub.output_file);
+
+ /* Initialize for LZW compression of image data */
+ compress_init(dinfo, InitCodeSize+1);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+
+ if (cinfo->quantize_colors)
+ emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
+ else
+ emit_header(dest, 256, (JSAMPARRAY) NULL);
+}
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ compress_byte(dest, GETJSAMPLE(*ptr++));
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+
+ /* Flush LZW mechanism */
+ compress_term(dest);
+ /* Write a zero-length data block to end the series */
+ putc(0, dest->pub.output_file);
+ /* Write the GIF terminator mark */
+ putc(';', dest->pub.output_file);
+ /* Make sure we wrote the output file OK */
+ fflush(dest->pub.output_file);
+ if (ferror(dest->pub.output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for GIF format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_gif (j_decompress_ptr cinfo)
+{
+ gif_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (gif_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(gif_dest_struct));
+ dest->cinfo = cinfo; /* make back link for subroutines */
+ dest->pub.start_output = start_output_gif;
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ dest->pub.finish_output = finish_output_gif;
+
+ if (cinfo->out_color_space != JCS_GRAYSCALE &&
+ cinfo->out_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_GIF_COLORSPACE);
+
+ /* Force quantization if color or if > 8 bits input */
+ if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
+ /* Force quantization to at most 256 colors */
+ cinfo->quantize_colors = TRUE;
+ if (cinfo->desired_number_of_colors > 256)
+ cinfo->desired_number_of_colors = 256;
+ }
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ if (cinfo->output_components != 1) /* safety check: just one component? */
+ ERREXIT(cinfo, JERR_GIF_BUG);
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ /* Allocate space for hash table */
+ dest->hash_code = (code_int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ HSIZE * SIZEOF(code_int));
+ dest->hash_value = (hash_entry FAR *)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ HSIZE * SIZEOF(hash_entry));
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* GIF_SUPPORTED */
diff --git a/gs/jpeg/wrjpgcom b/gs/jpeg/wrjpgcom
new file mode 100755
index 000000000..e0aeb79b0
--- /dev/null
+++ b/gs/jpeg/wrjpgcom
Binary files differ
diff --git a/gs/jpeg/wrjpgcom.1 b/gs/jpeg/wrjpgcom.1
new file mode 100644
index 000000000..d419a9999
--- /dev/null
+++ b/gs/jpeg/wrjpgcom.1
@@ -0,0 +1,103 @@
+.TH WRJPGCOM 1 "15 June 1995"
+.SH NAME
+wrjpgcom \- insert text comments into a JPEG file
+.SH SYNOPSIS
+.B wrjpgcom
+[
+.B \-replace
+]
+[
+.BI \-comment " text"
+]
+[
+.BI \-cfile " name"
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B wrjpgcom
+reads the named JPEG/JFIF file, or the standard input if no file is named,
+and generates a new JPEG/JFIF file on standard output. A comment block is
+added to the file.
+.PP
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+.PP
+.B wrjpgcom
+adds a COM block, containing text you provide, to a JPEG file.
+Ordinarily, the COM block is added after any existing COM blocks; but you
+can delete the old COM blocks if you wish.
+.SH OPTIONS
+Switch names may be abbreviated, and are not case sensitive.
+.TP
+.B \-replace
+Delete any existing COM blocks from the file.
+.TP
+.BI \-comment " text"
+Supply text for new COM block on command line.
+.TP
+.BI \-cfile " name"
+Read text for new COM block from named file.
+.PP
+If you have only one line of comment text to add, you can provide it on the
+command line with
+.BR \-comment .
+The comment text must be surrounded with quotes so that it is treated as a
+single argument. Longer comments can be read from a text file.
+.PP
+If you give neither
+.B \-comment
+nor
+.BR \-cfile ,
+then
+.B wrjpgcom
+will read the comment text from standard input. (In this case an input image
+file name MUST be supplied, so that the source JPEG file comes from somewhere
+else.) You can enter multiple lines, up to 64KB worth. Type an end-of-file
+indicator (usually control-D) to terminate the comment text entry.
+.PP
+.B wrjpgcom
+will not add a COM block if the provided comment string is empty. Therefore
+\fB\-replace \-comment ""\fR can be used to delete all COM blocks from a file.
+.SH EXAMPLES
+.LP
+Add a short comment to in.jpg, producing out.jpg:
+.IP
+.B wrjpgcom \-c
+\fI"View of my back yard" in.jpg
+.B >
+.I out.jpg
+.PP
+Attach a long comment previously stored in comment.txt:
+.IP
+.B wrjpgcom
+.I in.jpg
+.B <
+.I comment.txt
+.B >
+.I out.jpg
+.PP
+or equivalently
+.IP
+.B wrjpgcom
+.B -cfile
+.I comment.txt
+.B <
+.I in.jpg
+.B >
+.I out.jpg
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1)
+.SH AUTHOR
+Independent JPEG Group
diff --git a/gs/jpeg/wrjpgcom.c b/gs/jpeg/wrjpgcom.c
new file mode 100644
index 000000000..3b6411ce5
--- /dev/null
+++ b/gs/jpeg/wrjpgcom.c
@@ -0,0 +1,575 @@
+/*
+ * wrjpgcom.c
+ *
+ * Copyright (C) 1994-1995, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a very simple stand-alone application that inserts
+ * user-supplied text as a COM (comment) marker in a JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ */
+
+#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
+#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */
+extern void * malloc ();
+#endif
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+
+/* Reduce this value if your malloc() can't allocate blocks up to 64K.
+ * On DOS, compiling in large model is usually a better solution.
+ */
+
+#ifndef MAX_COM_LENGTH
+#define MAX_COM_LENGTH 65000 /* must be < 65534 in any case */
+#endif
+
+
+/*
+ * These macros are used to read the input file and write the output file.
+ * To reuse this code in another application, you might need to change these.
+ */
+
+static FILE * infile; /* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE() getc(infile)
+
+static FILE * outfile; /* output JPEG file */
+
+/* Emit an output byte */
+#define PUTBYTE(x) putc((x), outfile)
+
+
+/* Error exit handler */
+#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
+
+
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+ int c;
+
+ c = NEXTBYTE();
+ if (c == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ if (c1 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ c2 = NEXTBYTE();
+ if (c2 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/* Routines to write data to output file */
+
+static void
+write_1_byte (int c)
+{
+ PUTBYTE(c);
+}
+
+static void
+write_2_bytes (unsigned int val)
+{
+ PUTBYTE((val >> 8) & 0xFF);
+ PUTBYTE(val & 0xFF);
+}
+
+static void
+write_marker (int marker)
+{
+ PUTBYTE(0xFF);
+ PUTBYTE(marker);
+}
+
+static void
+copy_rest_of_file (void)
+{
+ int c;
+
+ while ((c = NEXTBYTE()) != EOF)
+ PUTBYTE(c);
+}
+
+
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF). Here are the marker codes of interest
+ * in this program. (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0 0xC0 /* Start Of Frame N */
+#define M_SOF1 0xC1 /* N indicates which compression process */
+#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
+#define M_EOI 0xD9 /* End Of Image (end of datastream) */
+#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+#define M_COM 0xFE /* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file. (Padding FFs will NOT be replicated in the output file.)
+ * There could also be non-FF garbage between markers. The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+
+static int
+next_marker (void)
+{
+ int c;
+ int discarded_bytes = 0;
+
+ /* Find 0xFF byte; count and skip any non-FFs. */
+ c = read_1_byte();
+ while (c != 0xFF) {
+ discarded_bytes++;
+ c = read_1_byte();
+ }
+ /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
+ * are legal as pad bytes, so don't count them in discarded_bytes.
+ */
+ do {
+ c = read_1_byte();
+ } while (c == 0xFF);
+
+ if (discarded_bytes != 0) {
+ fprintf(stderr, "Warning: garbage data found in JPEG file\n");
+ }
+
+ return c;
+}
+
+
+/*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI. To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+
+static int
+first_marker (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI)
+ ERREXIT("Not a JPEG file");
+ return c2;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+
+static void
+copy_variable (void)
+/* Copy an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ write_2_bytes(length);
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ write_1_byte(read_1_byte());
+ length--;
+ }
+}
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ (void) read_1_byte();
+ length--;
+ }
+}
+
+
+/*
+ * Parse the marker stream until SOFn or EOI is seen;
+ * copy data to output, but discard COM markers unless keep_COM is true.
+ */
+
+static int
+scan_JPEG_header (int keep_COM)
+{
+ int marker;
+
+ /* Expect SOI at start of file */
+ if (first_marker() != M_SOI)
+ ERREXIT("Expected SOI marker first");
+ write_marker(M_SOI);
+
+ /* Scan miscellaneous markers until we reach SOFn. */
+ for (;;) {
+ marker = next_marker();
+ switch (marker) {
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ case M_SOF2: /* Progressive, Huffman */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_SOF9: /* Extended sequential, arithmetic */
+ case M_SOF10: /* Progressive, arithmetic */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ return marker;
+
+ case M_SOS: /* should not see compressed data before SOF */
+ ERREXIT("SOS without prior SOFn");
+ break;
+
+ case M_EOI: /* in case it's a tables-only JPEG stream */
+ return marker;
+
+ case M_COM: /* Existing COM: conditionally discard */
+ if (keep_COM) {
+ write_marker(marker);
+ copy_variable();
+ } else {
+ skip_variable();
+ }
+ break;
+
+ default: /* Anything else just gets copied */
+ write_marker(marker);
+ copy_variable(); /* we assume it has a parameter count... */
+ break;
+ }
+ } /* end loop */
+}
+
+
+/* Command line parsing code */
+
+static const char * progname; /* program name for error messages */
+
+
+static void
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n");
+ fprintf(stderr, "You can add to or replace any existing comment(s).\n");
+
+ fprintf(stderr, "Usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -replace Delete any existing comments\n");
+ fprintf(stderr, " -comment \"text\" Insert comment with given text\n");
+ fprintf(stderr, " -cfile name Read comment from named file\n");
+ fprintf(stderr, "Notice that you must put quotes around the comment text\n");
+ fprintf(stderr, "when you use -comment.\n");
+ fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n");
+ fprintf(stderr, "then the comment text is read from standard input.\n");
+ fprintf(stderr, "It can be multiple lines, up to %u characters total.\n",
+ (unsigned int) MAX_COM_LENGTH);
+#ifndef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "You must specify an input JPEG file name when supplying\n");
+ fprintf(stderr, "comment text from standard input.\n");
+#endif
+
+ exit(EXIT_FAILURE);
+}
+
+
+static int
+keymatch (char * arg, const char * keyword, int minchars)
+/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
+/* keyword is the constant keyword (must be lower case already), */
+/* minchars is length of minimum legal abbreviation. */
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return 0; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return 0; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return 0;
+ return 1; /* A-OK */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ int argn;
+ char * arg;
+ int keep_COM = 1;
+ char * comment_arg = NULL;
+ FILE * comment_file = NULL;
+ unsigned int comment_length = 0;
+ int marker;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "wrjpgcom"; /* in case C library doesn't provide it */
+
+ /* Parse switches, if any */
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (arg[0] != '-')
+ break; /* not switch, must be file name */
+ arg++; /* advance over '-' */
+ if (keymatch(arg, "replace", 1)) {
+ keep_COM = 0;
+ } else if (keymatch(arg, "cfile", 2)) {
+ if (++argn >= argc) usage();
+ if ((comment_file = fopen(argv[argn], "r")) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else if (keymatch(arg, "comment", 1)) {
+ if (++argn >= argc) usage();
+ comment_arg = argv[argn];
+ /* If the comment text starts with '"', then we are probably running
+ * under MS-DOG and must parse out the quoted string ourselves. Sigh.
+ */
+ if (comment_arg[0] == '"') {
+ comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
+ if (comment_arg == NULL)
+ ERREXIT("Insufficient memory");
+ strcpy(comment_arg, argv[argn]+1);
+ for (;;) {
+ comment_length = strlen(comment_arg);
+ if (comment_length > 0 && comment_arg[comment_length-1] == '"') {
+ comment_arg[comment_length-1] = '\0'; /* zap terminating quote */
+ break;
+ }
+ if (++argn >= argc)
+ ERREXIT("Missing ending quote mark");
+ strcat(comment_arg, " ");
+ strcat(comment_arg, argv[argn]);
+ }
+ }
+ comment_length = strlen(comment_arg);
+ } else
+ usage();
+ }
+
+ /* Cannot use both -comment and -cfile. */
+ if (comment_arg != NULL && comment_file != NULL)
+ usage();
+ /* If there is neither -comment nor -cfile, we will read the comment text
+ * from stdin; in this case there MUST be an input JPEG file name.
+ */
+ if (comment_arg == NULL && comment_file == NULL && argn >= argc)
+ usage();
+
+ /* Open the input file. */
+ if (argn < argc) {
+ if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdin\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ infile = stdin;
+#endif
+ }
+
+ /* Open the output file. */
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have explicit output file name */
+ if (argn != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]);
+ exit(EXIT_FAILURE);
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (argn < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+ /* default output file is stdout */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdout\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ outfile = stdout;
+#endif
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Collect comment text from comment_file or stdin, if necessary */
+ if (comment_arg == NULL) {
+ FILE * src_file;
+ int c;
+
+ comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
+ if (comment_arg == NULL)
+ ERREXIT("Insufficient memory");
+ comment_length = 0;
+ src_file = (comment_file != NULL ? comment_file : stdin);
+ while ((c = getc(src_file)) != EOF) {
+ if (comment_length >= (unsigned int) MAX_COM_LENGTH) {
+ fprintf(stderr, "Comment text may not exceed %u bytes\n",
+ (unsigned int) MAX_COM_LENGTH);
+ exit(EXIT_FAILURE);
+ }
+ comment_arg[comment_length++] = (char) c;
+ }
+ if (comment_file != NULL)
+ fclose(comment_file);
+ }
+
+ /* Copy JPEG headers until SOFn marker;
+ * we will insert the new comment marker just before SOFn.
+ * This (a) causes the new comment to appear after, rather than before,
+ * existing comments; and (b) ensures that comments come after any JFIF
+ * or JFXX markers, as required by the JFIF specification.
+ */
+ marker = scan_JPEG_header(keep_COM);
+ /* Insert the new COM marker, but only if nonempty text has been supplied */
+ if (comment_length > 0) {
+ write_marker(M_COM);
+ write_2_bytes(comment_length + 2);
+ while (comment_length > 0) {
+ write_1_byte(*comment_arg++);
+ comment_length--;
+ }
+ }
+ /* Duplicate the remainder of the source file.
+ * Note that any COM markers occuring after SOF will not be touched.
+ */
+ write_marker(marker);
+ copy_rest_of_file();
+
+ /* All done. */
+ exit(EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/gs/jpeg/wrppm.c b/gs/jpeg/wrppm.c
new file mode 100644
index 000000000..6c6d90881
--- /dev/null
+++ b/gs/jpeg/wrppm.c
@@ -0,0 +1,268 @@
+/*
+ * wrppm.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in PPM/PGM format.
+ * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
+ * The PBMPLUS library is NOT required to compile this software
+ * (but it is highly useful as a set of PPM image manipulation programs).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef PPM_SUPPORTED
+
+
+/*
+ * For 12-bit JPEG data, we either downscale the values to 8 bits
+ * (to write standard byte-per-sample PPM/PGM files), or output
+ * nonstandard word-per-sample PPM/PGM files. Downscaling is done
+ * if PPM_NORAWWORD is defined (this can be done in the Makefile
+ * or in jconfig.h).
+ * (When the core library supports data precision reduction, a cleaner
+ * implementation will be to ask for that instead.)
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v)
+#define BYTESPERSAMPLE 1
+#define PPM_MAXVAL 255
+#else
+#ifdef PPM_NORAWWORD
+#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8))
+#define BYTESPERSAMPLE 1
+#define PPM_MAXVAL 255
+#else
+/* The word-per-sample format always puts the LSB first. */
+#define PUTPPMSAMPLE(ptr,v) \
+ { register int val_ = v; \
+ *ptr++ = (char) (val_ & 0xFF); \
+ *ptr++ = (char) ((val_ >> 8) & 0xFF); \
+ }
+#define BYTESPERSAMPLE 2
+#define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1)
+#endif
+#endif
+
+
+/*
+ * When JSAMPLE is the same size as char, we can just fwrite() the
+ * decompressed data to the PPM or PGM file. On PCs, in order to make this
+ * work the output buffer must be allocated in near data space, because we are
+ * assuming small-data memory model wherein fwrite() can't reach far memory.
+ * If you need to process very wide images on a PC, you might have to compile
+ * in large-memory model, or else replace fwrite() with a putc() loop ---
+ * which will be much slower.
+ */
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ /* Usually these two pointers point to the same place: */
+ char *iobuffer; /* fwrite's I/O buffer */
+ JSAMPROW pixrow; /* decompressor output buffer */
+ size_t buffer_width; /* width of I/O buffer */
+ JDIMENSION samples_per_row; /* JSAMPLEs per output row */
+} ppm_dest_struct;
+
+typedef ppm_dest_struct * ppm_dest_ptr;
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ *
+ * put_pixel_rows handles the "normal" 8-bit case where the decompressor
+ * output buffer is physically the same as the fwrite buffer.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * This code is used when we have to copy the data and apply a pixel
+ * format translation. Typically this only happens in 12-bit mode.
+ */
+
+METHODDEF(void)
+copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = dest->samples_per_row; col > 0; col--) {
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Write some pixel data when color quantization is in effect.
+ * We have to demap the color index values to straight data.
+ */
+
+METHODDEF(void)
+put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register int pixval;
+ register JSAMPROW ptr;
+ register JSAMPROW color_map0 = cinfo->colormap[0];
+ register JSAMPROW color_map1 = cinfo->colormap[1];
+ register JSAMPROW color_map2 = cinfo->colormap[2];
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ pixval = GETJSAMPLE(*ptr++);
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval]));
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval]));
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval]));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+METHODDEF(void)
+put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register JSAMPROW ptr;
+ register JSAMPROW color_map = cinfo->colormap[0];
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)]));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+
+ /* Emit file header */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ /* emit header for raw PGM format */
+ fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n",
+ (long) cinfo->output_width, (long) cinfo->output_height,
+ PPM_MAXVAL);
+ break;
+ case JCS_RGB:
+ /* emit header for raw PPM format */
+ fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n",
+ (long) cinfo->output_width, (long) cinfo->output_height,
+ PPM_MAXVAL);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_PPM_COLORSPACE);
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* Make sure we wrote the output file OK */
+ fflush(dinfo->output_file);
+ if (ferror(dinfo->output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for PPM format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_ppm (j_decompress_ptr cinfo)
+{
+ ppm_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (ppm_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ppm_dest_struct));
+ dest->pub.start_output = start_output_ppm;
+ dest->pub.finish_output = finish_output_ppm;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Create physical I/O buffer. Note we make this near on a PC. */
+ dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
+ dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char));
+ dest->iobuffer = (char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);
+
+ if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||
+ SIZEOF(JSAMPLE) != SIZEOF(char)) {
+ /* When quantizing, we need an output buffer for colormap indexes
+ * that's separate from the physical I/O buffer. We also need a
+ * separate buffer if pixel format translation must take place.
+ */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width * cinfo->output_components, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+ if (! cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = copy_pixel_rows;
+ else if (cinfo->out_color_space == JCS_GRAYSCALE)
+ dest->pub.put_pixel_rows = put_demapped_gray;
+ else
+ dest->pub.put_pixel_rows = put_demapped_rgb;
+ } else {
+ /* We will fwrite() directly from decompressor output buffer. */
+ /* Synthesize a JSAMPARRAY pointer structure */
+ /* Cast here implies near->far pointer conversion on PCs */
+ dest->pixrow = (JSAMPROW) dest->iobuffer;
+ dest->pub.buffer = & dest->pixrow;
+ dest->pub.buffer_height = 1;
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ }
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* PPM_SUPPORTED */
diff --git a/gs/jpeg/wrrle.c b/gs/jpeg/wrrle.c
new file mode 100644
index 000000000..a4e73372d
--- /dev/null
+++ b/gs/jpeg/wrrle.c
@@ -0,0 +1,305 @@
+/*
+ * wrrle.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in RLE format.
+ * The Utah Raster Toolkit library is required (version 3.1 or later).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * Based on code contributed by Mike Lijewski,
+ * with updates from Robert Hutchinson.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef RLE_SUPPORTED
+
+/* rle.h is provided by the Utah Raster Toolkit. */
+
+#include <rle.h>
+
+/*
+ * We assume that JSAMPLE has the same representation as rle_pixel,
+ * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Since RLE stores scanlines bottom-to-top, we have to invert the image
+ * from JPEG's top-to-bottom order. To do this, we save the outgoing data
+ * in a virtual array during put_pixel_row calls, then actually emit the
+ * RLE file during finish_output.
+ */
+
+
+/*
+ * For now, if we emit an RLE color map then it is always 256 entries long,
+ * though not all of the entries need be used.
+ */
+
+#define CMAPBITS 8
+#define CMAPLENGTH (1<<(CMAPBITS))
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ jvirt_sarray_ptr image; /* virtual array to store the output image */
+ rle_map *colormap; /* RLE-style color map, or NULL if none */
+ rle_pixel **rle_row; /* To pass rows to rle_putrow() */
+
+} rle_dest_struct;
+
+typedef rle_dest_struct * rle_dest_ptr;
+
+/* Forward declarations */
+METHODDEF(void) rle_put_pixel_rows
+ JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied));
+
+
+/*
+ * Write the file header.
+ *
+ * In this module it's easier to wait till finish_output to write anything.
+ */
+
+METHODDEF(void)
+start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+ size_t cmapsize;
+ int i, ci;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /*
+ * Make sure the image can be stored in RLE format.
+ *
+ * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
+ * uses unsigned, so we have to check the width.
+ *
+ * - Colorspace is expected to be grayscale or RGB.
+ *
+ * - The number of channels (components) is expected to be 1 (grayscale/
+ * pseudocolor) or 3 (truecolor/directcolor).
+ * (could be 2 or 4 if using an alpha channel, but we aren't)
+ */
+
+ if (cinfo->output_width > 32767 || cinfo->output_height > 32767)
+ ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width,
+ cinfo->output_height);
+
+ if (cinfo->out_color_space != JCS_GRAYSCALE &&
+ cinfo->out_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_RLE_COLORSPACE);
+
+ if (cinfo->output_components != 1 && cinfo->output_components != 3)
+ ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);
+
+ /* Convert colormap, if any, to RLE format. */
+
+ dest->colormap = NULL;
+
+ if (cinfo->quantize_colors) {
+ /* Allocate storage for RLE-style cmap, zero any extra entries */
+ cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);
+ dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);
+ MEMZERO(dest->colormap, cmapsize);
+
+ /* Save away data in RLE format --- note 8-bit left shift! */
+ /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
+ for (ci = 0; ci < cinfo->out_color_components; ci++) {
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
+ dest->colormap[ci * CMAPLENGTH + i] =
+ GETJSAMPLE(cinfo->colormap[ci][i]) << 8;
+ }
+ }
+ }
+
+ /* Set the output buffer to the first row */
+ dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);
+ dest->pub.buffer_height = 1;
+
+ dest->pub.put_pixel_rows = rle_put_pixel_rows;
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->total_extra_passes++; /* count file writing as separate pass */
+ }
+#endif
+}
+
+
+/*
+ * Write some pixel data.
+ *
+ * This routine just saves the data away in a virtual array.
+ */
+
+METHODDEF(void)
+rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+
+ if (cinfo->output_scanline < cinfo->output_height) {
+ dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ cinfo->output_scanline, (JDIMENSION) 1, TRUE);
+ }
+}
+
+/*
+ * Finish up at the end of the file.
+ *
+ * Here is where we really output the RLE file.
+ */
+
+METHODDEF(void)
+finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+ rle_hdr header; /* Output file information */
+ rle_pixel **rle_row, *red, *green, *blue;
+ JSAMPROW output_row;
+ char cmapcomment[80];
+ int row, col;
+ int ci;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /* Initialize the header info */
+ header = *rle_hdr_init(NULL);
+ header.rle_file = dest->pub.output_file;
+ header.xmin = 0;
+ header.xmax = cinfo->output_width - 1;
+ header.ymin = 0;
+ header.ymax = cinfo->output_height - 1;
+ header.alpha = 0;
+ header.ncolors = cinfo->output_components;
+ for (ci = 0; ci < cinfo->output_components; ci++) {
+ RLE_SET_BIT(header, ci);
+ }
+ if (cinfo->quantize_colors) {
+ header.ncmap = cinfo->out_color_components;
+ header.cmaplen = CMAPBITS;
+ header.cmap = dest->colormap;
+ /* Add a comment to the output image with the true colormap length. */
+ sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors);
+ rle_putcom(cmapcomment, &header);
+ }
+
+ /* Emit the RLE header and color map (if any) */
+ rle_put_setup(&header);
+
+ /* Now output the RLE data from our virtual array.
+ * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
+ * and (b) we are not on a machine where FAR pointers differ from regular.
+ */
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_limit = cinfo->output_height;
+ progress->pub.pass_counter = 0;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+
+ if (cinfo->output_components == 1) {
+ for (row = cinfo->output_height-1; row >= 0; row--) {
+ rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ (JDIMENSION) row, (JDIMENSION) 1, FALSE);
+ rle_putrow(rle_row, (int) cinfo->output_width, &header);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ } else {
+ for (row = cinfo->output_height-1; row >= 0; row--) {
+ rle_row = (rle_pixel **) dest->rle_row;
+ output_row = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ (JDIMENSION) row, (JDIMENSION) 1, FALSE);
+ red = rle_row[0];
+ green = rle_row[1];
+ blue = rle_row[2];
+ for (col = cinfo->output_width; col > 0; col--) {
+ *red++ = GETJSAMPLE(*output_row++);
+ *green++ = GETJSAMPLE(*output_row++);
+ *blue++ = GETJSAMPLE(*output_row++);
+ }
+ rle_putrow(rle_row, (int) cinfo->output_width, &header);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+#endif
+
+ /* Emit file trailer */
+ rle_puteof(&header);
+ fflush(dest->pub.output_file);
+ if (ferror(dest->pub.output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for RLE format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_rle (j_decompress_ptr cinfo)
+{
+ rle_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (rle_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(rle_dest_struct));
+ dest->pub.start_output = start_output_rle;
+ dest->pub.finish_output = finish_output_rle;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Allocate a work array for output to the RLE library. */
+ dest->rle_row = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width, (JDIMENSION) cinfo->output_components);
+
+ /* Allocate a virtual array to hold the image. */
+ dest->image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) (cinfo->output_width * cinfo->output_components),
+ cinfo->output_height, (JDIMENSION) 1);
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* RLE_SUPPORTED */
diff --git a/gs/jpeg/wrtarga.c b/gs/jpeg/wrtarga.c
new file mode 100644
index 000000000..cf104d2de
--- /dev/null
+++ b/gs/jpeg/wrtarga.c
@@ -0,0 +1,253 @@
+/*
+ * wrtarga.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in Targa format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * Based on code contributed by Lee Daniel Crocker.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef TARGA_SUPPORTED
+
+
+/*
+ * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
+ * This is not yet implemented.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * The output buffer needs to be writable by fwrite(). On PCs, we must
+ * allocate the buffer in near data space, because we are assuming small-data
+ * memory model, wherein fwrite() can't reach far memory. If you need to
+ * process very wide images on a PC, you might have to compile in large-memory
+ * model, or else replace fwrite() with a putc() loop --- which will be much
+ * slower.
+ */
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ char *iobuffer; /* physical I/O buffer */
+ JDIMENSION buffer_width; /* width of one row */
+} tga_dest_struct;
+
+typedef tga_dest_struct * tga_dest_ptr;
+
+
+LOCAL(void)
+write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors)
+/* Create and write a Targa header */
+{
+ char targaheader[18];
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(targaheader, SIZEOF(targaheader));
+
+ if (num_colors > 0) {
+ targaheader[1] = 1; /* color map type 1 */
+ targaheader[5] = (char) (num_colors & 0xFF);
+ targaheader[6] = (char) (num_colors >> 8);
+ targaheader[7] = 24; /* 24 bits per cmap entry */
+ }
+
+ targaheader[12] = (char) (cinfo->output_width & 0xFF);
+ targaheader[13] = (char) (cinfo->output_width >> 8);
+ targaheader[14] = (char) (cinfo->output_height & 0xFF);
+ targaheader[15] = (char) (cinfo->output_height >> 8);
+ targaheader[17] = 0x20; /* Top-down, non-interlaced */
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ targaheader[2] = 3; /* image type = uncompressed gray-scale */
+ targaheader[16] = 8; /* bits per pixel */
+ } else { /* must be RGB */
+ if (num_colors > 0) {
+ targaheader[2] = 1; /* image type = colormapped RGB */
+ targaheader[16] = 8;
+ } else {
+ targaheader[2] = 2; /* image type = uncompressed RGB */
+ targaheader[16] = 24;
+ }
+ }
+
+ if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* used for unquantized full-color output */
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */
+ outptr[1] = (char) GETJSAMPLE(inptr[1]);
+ outptr[2] = (char) GETJSAMPLE(inptr[0]);
+ inptr += 3, outptr += 3;
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+METHODDEF(void)
+put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* used for grayscale OR quantized color output */
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = (char) GETJSAMPLE(*inptr++);
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Write some demapped pixel data when color quantization is in effect.
+ * For Targa, this is only applied to grayscale data.
+ */
+
+METHODDEF(void)
+put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JSAMPROW color_map0 = cinfo->colormap[0];
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]);
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ int num_colors, i;
+ FILE *outfile;
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ /* Targa doesn't have a mapped grayscale format, so we will */
+ /* demap quantized gray output. Never emit a colormap. */
+ write_header(cinfo, dinfo, 0);
+ if (cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = put_demapped_gray;
+ else
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* We only support 8-bit colormap indexes, so only 256 colors */
+ num_colors = cinfo->actual_number_of_colors;
+ if (num_colors > 256)
+ ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors);
+ write_header(cinfo, dinfo, num_colors);
+ /* Write the colormap. Note Targa uses BGR byte order */
+ outfile = dest->pub.output_file;
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile);
+ putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile);
+ putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile);
+ }
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else {
+ write_header(cinfo, dinfo, 0);
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ }
+ } else {
+ ERREXIT(cinfo, JERR_TGA_COLORSPACE);
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* Make sure we wrote the output file OK */
+ fflush(dinfo->output_file);
+ if (ferror(dinfo->output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for Targa format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_targa (j_decompress_ptr cinfo)
+{
+ tga_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (tga_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(tga_dest_struct));
+ dest->pub.start_output = start_output_tga;
+ dest->pub.finish_output = finish_output_tga;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Create I/O buffer. Note we make this near on a PC. */
+ dest->buffer_width = cinfo->output_width * cinfo->output_components;
+ dest->iobuffer = (char *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (dest->buffer_width * SIZEOF(char)));
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* TARGA_SUPPORTED */
diff --git a/gs/language.txt b/gs/language.txt
new file mode 100644
index 000000000..00dd65fda
--- /dev/null
+++ b/gs/language.txt
@@ -0,0 +1,768 @@
+ Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, language.txt, describes the relationship between the Ghostscript
+interpreter and the PostScript language.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+The Ghostscript interpreter, except as noted below, is intended to execute
+properly any source program written in the (Level 2) PostScript language as
+defined in the December 1990 printing of the PostScript Language Reference
+Manual (Second Edition) published by Addison-Wesley (ISBN 0-201-18127-4).
+However, the interpreter is configurable in ways that can restrict it to
+various subsets of this language. Specifically, the base interpreter
+accepts the Level 1 subset of the PostScript language, as defined in the
+first edition of the PostScript Language Reference Manual, ISBN
+0-201-10174-2, Addison-Wesley, 1985, plus the file system, version 25.0
+language, and miscellaneous additions listed in sections A.1.6, A.1.7, and
+A.1.8 of the Second Edition respectively, including allowing a string
+operand for the 'status' operator. The base interpreter may be configured
+by adding any combination of the following:
+
+ - The ability to process PostScript Type 1 fonts. This facility is
+normally included in the interpreter.
+
+ - The CMYK color extensions listed in section A.1.4 of the Second
+Edition (including colorimage). These facilities are only available if the
+color, dps, or level2 feature was selected at the time that Ghostscript was
+compiled and linked.
+
+ - The Display PostScript extensions listed in section A.1.3
+of the Second Edition, but excluding the operators listed in section
+A.1.2. These facilities are only available if the dps feature or the
+level2 feature was selected at the time that Ghostscript was compiled
+and linked.
+
+ - The composite font extensions listed in section A.1.5 of the
+Second Edition, and the ability to handle Type 0 fonts. These facilities
+are only available if the compfont feature or the level2 feature was
+selected at the time that Ghostscript was compiled and linked.
+
+ - The ability to load TrueType fonts and to handle PostScript Type
+42 (encapsulated TrueType) fonts. These facilities are only available if
+the ttfont feature was selected at the time that Ghostscript was compiled
+and linked.
+
+ - The PostScript Level 2 "filter" facilities aside from DCTEncode
+and DCTDecode filters. These facilities are only available if the filter,
+dps, or level2 feature was selected at the time that Ghostscript was
+compiled and linked.
+
+ - The PostScript Level 2 DCTEncode and DCTDecode filters. These
+facilities are only available if the dct or level2 feature was selected at
+the time that Ghostscript was compiled and linked.
+
+ - All the other PostScript Level 2 operators and facilities listed
+in section A.1.1 of the Second Edition and not listed in any of the other
+A.1.n sections. These facilities are only available if the level2 feature
+was selected at the time that Ghostscript was compiled and linked.
+
+ - The ability to recognize MS-DOS EPSF files and process only the
+PostScript part, ignoring bitmap previews or other information. This
+facility is only available if the epsf feature was selected at the time that
+Ghostscript was compiled and linked.
+
+Adding all of these produces a full Level 2 PostScript language
+interpreter.
+
+Ghostscript also includes the optional ability to interpret files in the PDF
+1.2 format defined in the Portable Document Format Reference Manual, Version
+1.2 (November 12, 1996) distributed by Adobe Systems Incorporated. This
+facility is only available if the 'pdf' feature was selected at the time
+that Ghostscript was compiled and linked.
+
+Ghostscript also includes a number of operators defined below that are not
+in the PostScript language.
+
+Implementation limits
+=====================
+
+The following implementation limits correspond to those in Table B.1 and
+B.2 of the Second Edition. Those marked with * are different from the ones
+in the Second Edition.
+
+Architectural limits
+--------------------
+
+integer 32-bit two's complement integer
+real single-precision IEEE float
+*array
+ On 16-bit systems: 8191 elements
+ On 32-bit systems: 65535 elements
+*dictionary
+ On 16-bit systems: 8190 elements
+ On 32-bit systems: 65534 elements
+*string 65535 characters
+*name 16383 characters
+filename 100 characters
+*save level none (capacity of memory)
+*gsave level none (capacity of memory)
+
+Typical memory limits in Level 1
+--------------------------------
+
+userdict 200
+FontDirectory 100
+*operand stack 800
+dictionary stack 20
+execution stack 250
+*interpreter level none (capacity of memory)
+*path none (capacity of memory)
+dash 11
+*VM capacity of memory
+*file determined by operating system
+*image 65535 values (samples x components) for 1, 2, 4,
+ or 8-bit samples; 32767 values for 12-bit samples
+
+Other differences in VM consumption
+-----------------------------------
+
+Packed array elements occupy either 2 bytes or 8 bytes. The average
+element size is probably about 5 bytes.
+
+Names occupy 12 bytes plus the space for the string.
+
+Graphics/text operator additions
+================================
+
+Graphics state operators
+------------------------
+
+ <bool> .setaccuratecurves -
+ Sets a graphics state flag that determines whether curves
+ and arcs, when flattened, always start and end with a
+ line that a segment of the tangent; this also causes
+ butt and square caps to be properly perpendicular to
+ the tangent. initgraphics sets this flag to false,
+ to match other PostScript implementations.
+
+ - .currentaccuratecurves <bool>
+ Returns the current value of the accurate curves flag.
+
+ <bool> .setclipoutside -
+ Sets a graphics state flag that determines whether the
+ effective clipping region is the inside (false) or the
+ outside (true) of the region defined by the clipping
+ operators (clip, rectclip, etc.) initclip sets this
+ flag to false.
+
+ - .currentclipoutside <bool>
+ Returns the current value of the outside clipping flag.
+
+ <bool> .setdashadapt -
+ Sets a graphics state flag that determines whether dash
+ patterns do (true) or do not (false) automatically scale
+ themselves so that each line segment consists of an
+ integral number of pattern repetitions. initgraphics sets
+ this flag to false.
+
+ - .currentdashadapt <bool>
+ Returns the current value of the dash adaptation flag.
+
+ <matrix> .setdefaultmatrix -
+ Sets the default matrix that is returned by defaultmatrix
+ and installed by initmatrix. Ordinary programs should
+ not use this operator.
+
+ <num> <bool> .setdotlength -
+ Sets a graphics state parameter that determines the handling
+ of zero-length lines (dots). If the dot length is zero,
+ dots are painted as circles if round line caps are in
+ effect, otherwise they are not painted at all. If the dot
+ length is non-zero, dots are treated exactly like lines of
+ the given length: the length is specified in user
+ coordinates (like line width) if bool is false, or in
+ default user coordinates (1/72" units) if bool is true.
+ Dots occurring as part of dash patterns will be oriented
+ correctly; isolated dots will be oriented as though they
+ were part of a vertical line. initgraphics sets the dot
+ length to zero.
+
+ - .currentdotlength <num> <bool>
+ Returns the current dot length and dot length mode.
+
+ <dx> <dy> .setfilladjust2 -
+ Sets graphics state parameters that cause all filled and
+ stroked regions to be "fattened" by the given amount
+ relative to an algorithm that only paints pixels whose
+ centers fall within the region to be painted.
+ dx and dy are numbers between 0 and 0.5, measured in
+ device space. The only two values that are likely to
+ be useful are 0, which gives a pure center-of-pixel
+ rule, and 0.5, which gives Adobe's any-part-of-pixel
+ rule. (0.5 is treated slightly specially in order to
+ create half-open pixels per Adobe's specification.)
+
+ - .currentfilladjust2 <dx> <dy>
+ Returns the current fill adjustment values.
+
+Path operators
+--------------
+
+ - .dashpath -
+ If there is no current dash pattern, does nothing.
+ Otherwise, does the equivalent of flattenpath and then
+ chops up the path as determined by the dash pattern.
+
+ <x> <y> <width> <height> .rectappend -
+ <numarray> .rectappend -
+ <numstring> .rectappend -
+ Appends a rectangle or rectangles to the current path, in
+ the same manner as rectfill, rectclip, etc. Only
+ defined if the dps and/or level2 option is selected.
+
+Painting operators
+------------------
+
+Ghostscript supports an experimental extension of the PostScript imaging
+model to include RasterOp and some related facilities. This extension is
+only available if the rasterop option was selected when building
+Ghostscript.
+
+With the RasterOp extension, imaging operations compute a function D =
+f(D,S,T) in RGB space, where f is an arbitrary 3-input Boolean function, D
+is the destination (frame buffer or print buffer), S is the source
+(described below), and T is the texture (the current PostScript color, which
+may be a pattern). The source and texture depend on the PostScript imaging
+operation:
+
+ - For fill and stroke, the source is solid black, covering the
+ region to be painted; the texture is the current PostScript color.
+
+ - For show and imagemask, the source is solid black, covering the
+ pixels to be painted; the texture is the current PostScript color.
+
+ - For image and colorimage, the source is the image data; the
+ texture depends on an optional Boolean parameter, CombineWithColor,
+ in the image dictionary. If CombineWithColor is false (the
+ default), the texture is solid black. If CombineWithColor is true,
+ the texture is the current color. For the non-dictionary form of
+ the image operator, CombineWithColor is considered to be false.
+
+The rasterop option adds the following operators:
+
+ <int8> .setrasterop -
+ Sets the RasterOp function in the graphics state.
+ The default function is 252, Source | Texture.
+
+ - .currentrasterop <int8>
+ Returns the current RasterOp function.
+
+ <bool> .setsourcetransparent -
+ Sets source transparency in the graphics state. When source
+ transparency is true, white source pixels prevent storing
+ into the destination, regardless of what the RasterOp
+ function returns. The default source transparency is
+ false.
+
+ - .currentsourcetransparent <bool> -
+ Returns the current source transparency.
+
+ <bool> .settexturetransparent -
+ Sets texture transparency in the graphics state. When texture
+ transparency is true, white texture pixels prevent storing
+ into the destination, regardless of what the RasterOp
+ function returns. The default texture transparency is
+ false.
+
+ - .currenttexturetransparent <bool> -
+ Returns the current texture transparency.
+
+For more information on RasterOp and transparency, please consult chapter 5
+of the "PCL 5 Color Technical Reference Manual", Hewlett-Packard Manual Part
+No. 5961-0635.
+
+Character operators
+-------------------
+
+ <string> <bool> .charboxpath -
+ For each character C in the rendering of <string>, let the
+ bounding box of C *in device space* be the four
+ *user-space* points p1x/y, p2x/y, p3x/y, and p4x/y. For
+ each character in order, .charboxpath appends the
+ following to the current path:
+ - If <bool> is true, the equivalent of:
+ p1x p1y moveto
+ p2x p2y lineto
+ p3x p3y lineto
+ p4x p4y lineto
+ closepath
+ This creates a path whose pathbbox is the bbox of the
+ string.
+ - If <bool> is false, the equivalent of:
+ p1x p1y moveto
+ p3x p3y lineto
+ If the CTM is well-behaved (consists only of reflection,
+ scaling, and rotation by multiples of 90 degrees), this
+ too creates a (simpler) path whose pathbbox is the bbox of
+ the string.
+
+ <font> <charname|charcode> <charname> <charstring> .type1execchar -
+ Does all the work for rendering a Type 1 outline. This
+ operator, like setcharwidth and setcachedevice, is
+ only valid in the context of a show operator -- i.e.,
+ it must only be called from within a BuildChar or
+ BuildGlyph procedure.
+
+ <font> <charcode> %Type1BuildChar -
+ This is not a new operator: rather, it is a name known
+ specially to the interpreter. Whenever the interpreter
+ needs to render a character (during a ...show,
+ stringwidth, or charpath), it looks up the name
+ BuildChar in the font dictionary to find a procedure to
+ run. If it does not find this name, and if the FontType
+ is 1, the interpreter instead uses the value (looked up
+ on the dictionary stack in the usual way) of the name
+ %Type1BuildChar.
+ The standard definition of %Type1BuildChar is in gs_type1.ps.
+ Users should not need to redefine %Type1BuildChar, except
+ perhaps for tracing or debugging.
+
+ <font> <charname> %Type1BuildGlyph -
+ Provides the Type 1 implementation of BuildGlyph.
+
+Other operator additions
+========================
+
+Mathematical operators
+----------------------
+
+ <number> arccos <number>
+ Computes the arc cosine of a number between -1 and 1.
+
+ <number> arcsin <number>
+ Computes the arc sine of a number between -1 and 1.
+
+String operators
+----------------
+
+ <state> <fromString> <toString> .type1encrypt <newState> <toSubstring>
+ Encrypts fromString according to the algorithm for Adobe
+ Type 1 fonts, writing the result into toString.
+ toString must be at least as long as fromString or a
+ rangecheck error occurs. state is the initial state of
+ the encryption algorithm (a 16-bit non-negative
+ integer); newState is the new state of the algorithm.
+
+ <state> <fromString> <toString> .type1decrypt <newState> <toSubstring>
+ Decrypts fromString according to the algorithm for Adobe
+ Type 1 fonts, writing the result into toString. Other
+ specifications are as for type1encrypt.
+
+Relational operators
+--------------------
+
+ <number|string> <number|string> max <number|string>
+ Returns the larger of two numbers or strings.
+
+ <number|string> <number|string> min <number|string>
+ Returns the smaller of two numbers or strings.
+
+File operators
+--------------
+
+ <string> findlibfile <foundstring> <file> true
+ <string> findlibfile <string> false
+ Opens the file of the given name for reading, searching
+ through directories as described in use.txt. If the
+ search fails, findlibfile simply pushes false on the
+ stack and returns, rather than causing an error.
+
+ <file> <integer> unread -
+ Pushes back the last-read character onto the front of the
+ file. If the file is only open for writing, or if the
+ integer argument is not the same as the last character
+ read from the file, causes an ioerror error. May also
+ cause an ioerror if the last operation on the file was not
+ a reading operation.
+
+ <file> <device> writeppmfile -
+ Writes the contents of the device, which must be an image
+ device, onto the file, in Portable PixMap (ppm) format.
+ Does not close the file.
+
+Ghostscript also supports the following IODevice in addition to a subset of
+those defined in the Adobe documentation: %pipe%command, which opens a pipe
+on the given command. This is only supported on operating systems that
+provide popen (primarily Unix systems, and not all of those).
+
+Filters
+-------
+
+Ghostscript supports all the standard PostScript Level 2 filters, except
+that it does not currently support the EarlyChange key in the LZWEncode
+filter. Ghostscript also supports the as yet undocumented FlateEncode and
+FlateDecode filters from PDF 1.2 and (presumably) PostScript Level 3, except
+for the Effort key in FlateEncode. In addition, Ghostscript supports the
+following non-standard filters:
+
+ <target> /BCPEncode filter <file>
+ <source> /BCPDecode filter <file>
+ Create filters that implement the Adobe Binary
+ Communications Protocol. See Adobe documentation for
+ details.
+
+ <target> <seed_integer> /eexecEncode filter <file>
+ Creates a filter for encrypting data into the
+ eexec encrypted format described in the
+ Adobe Type 1 Font Format documentation. The
+ seed_integer must be 55665 for proper operation.
+ This filter produces binary output and does not
+ include the initial 4 (or lenIV) garbage bytes.
+
+ <source> <seed_integer> /eexecDecode filter <file>
+ <source> <dict> /eexecDecode filter <file>
+ Creates a filter for decrypting data that has been
+ encrypted using eexec encryption as described in the
+ Adobe Type 1 Font Format documentation. The
+ seed_integer must be 55665 for proper operation.
+ Recognized dictionary keys are:
+ seed <16-bit integer> (required)
+ lenIV <non-negative integer> (default=4)
+
+ <source> /PCXDecode filter <file>
+ Creates a filter that decodes data in the run-length
+ encoding used in the PCX graphics file format.
+
+ <source> <hex_boolean> /PFBDecode filter <file>
+ Creates a filter that decodes data in .PFB format, the
+ usual semi-binary representation for Type 1 font files
+ on IBM PC and compatible systems. If hex_boolean is true,
+ binary packets are converted to hex; if false, binary
+ packets are not converted.
+
+ <target> <dict> /PixelDifferenceEncode filter <file>
+ <source> <dict> /PixelDifferenceDecode filter <file>
+ Implements the Predictor=2 pixel-differencing option of the
+ LZW filters. Recognized keys are:
+ Colors <integer> 1..4 (default=1)
+ BitsPerComponent <integer> 1,2,4,8 (default=8)
+ Columns <integer> >= 0 (required)
+ See the Adobe "Portable Document Format Reference Manual"
+ for details.
+
+ <target> <dict> /PNGPredictorEncode filter <file>
+ <source> <dict> /PNGPredictorDecode filter <file>
+ Implements the "filter" algorithms of the PNG graphics
+ format. Recognized keys are:
+ Colors <integer> 1..16 (default=1)
+ BitsPerComponent <integer> 1,2,4,8,16 (default=8)
+ Columns <integer> >= 0 (default=1)
+ Predictor <integer> 10..15 (default=15)
+ The Predictor is the PNG algorithm number + 10 for the
+ Encoding filter; the Decoding filter ignores Predictor.
+ 15 means the encoder attempts to optimize the choice of
+ algorithm. For more details, see libpng.mak, which has
+ a pointer to the PNG specification.
+
+ <target> /TBCPEncode filter <file>
+ <source> /TBCPDecode filter <file>
+ Create filters that implement the Adobe Tagged Binary
+ Communications Protocol. See Adobe documentation for
+ details.
+
+ <target> /zlibEncode filter <file>
+ <source> /zlibDecode filter <file>
+ Creates filters that use the zlib data compression method
+ (the same method used by the gzip application).
+ This filter is only available if the fzlib feature was
+ selected when Ghostscript was compiled and linked.
+
+Various versions of Ghostscript may also support other non-standard filters
+for experimental purposes. The current version includes the following
+non-standard filters, which are not documented further. No guarantee is
+made that these filters will exist in compatible form, or at all, in future
+versions.
+
+ <target/source> <string> ByteTranslateEncode/Decode
+ <target> <int> BigStringEncode
+ <target/source> <dict> BoundedHuffmanEncode/Decode
+ FirstBitLowOrder <bool> false
+ MaxCodeLength <int> 16
+ EndOfData <bool> true
+ EncodeZeroRuns <int> 256
+ Tables <int_array>
+ <target/source> <dict> BWBlockSortEncode/Decode
+ BlockSize <int> 16384
+ <target/source> MoveToFrontEncode/Decode
+
+Ghostscript also supports additional keys in the optional dictionary
+operands for some filters. For the LZWDecode filter:
+
+ InitialCodeLength <integer>
+ An integer between 2 and 11 specifying the initial number
+of data bits per code. Note that the actual initial code length is 1
+greater than this, to allow for the reset and end-of-data code values.
+Default value: 8.
+
+ FirstBitLowOrder <boolean>
+ If true, codes appear with their low-order bit first.
+Default value: false.
+
+ BlockData <boolean>
+ If true, the data is broken into blocks in the manner
+specified for the GIF file format. Default value: false.
+
+For the CCITTFaxEncode and CCITTFaxDecode filters:
+
+ DecodedByteAlign <integer>
+ An integer N with the value 1, 2, 4, 8, or 16, specifying
+that decoded data scan lines are always a multiple of N bytes. The encoding
+filter skips data in each scan line from Columns to the next multiple of N
+bytes; the decoding filter pads each scan line to a multiple of N bytes.
+Default value: 1.
+
+Virtual memory operators
+------------------------
+
+ <save> .forgetsave -
+ Cancels the effect of a save -- makes it as though the
+ save never happened.
+
+Miscellaneous operators
+-----------------------
+
+ <string> getenv <string> true
+ <string> getenv false
+ Looks up a name in the shell environment. If the name is
+ found, returns the corresponding value and true; if the
+ name is not found, returns false.
+
+ <name> <array> .makeoperator <operator>
+ Constructs and returns a new operator that is actually the
+ given procedure in disguise. The name is only used for
+ printing. The operator has the executable attribute.
+ Operators defined in this way do one other thing besides
+ running the procedure: if an error occurs during the
+ execution of the procedure, and there has been no net
+ reduction in operand or dictionary stack depth, the
+ operand or dictionary stack pointer respectively is reset
+ to its position at the beginning of the procedure.
+
+ <string> <boolean> .setdebug -
+ If the Ghostscript interpreter was built with the DEBUG
+ flag set, sets or resets any subset of the debugging
+ flags normally controlled by -Z in the command line.
+ Has no effect otherwise.
+
+ - .oserrno <errno>
+ Returns the error code for the most recent OS error.
+
+ - .oserror <string>
+ Returns the error string for the most recent OS error.
+
+Device operators
+----------------
+
+ <device> copydevice <device>
+ Copies a device. The copy is writable and installable.
+
+ <index> .getdevice <device>
+ Returns a device from the set of devices known to the
+ system. The first device, which is default, is numbered
+ 0. If the index is out of range, causes a rangecheck
+ error. This device is actually a prototype, not a
+ directly usable device, and is marked read-only;
+ it cannot have its parameters changed or be installed as
+ the current device.
+
+ <matrix> <width> <height> <palette> makeimagedevice <device>
+ Makes a new device that accumulates an image in memory.
+ matrix is the initial transformation matrix: it must be
+ orthogonal (i.e., [a 0 0 b x y] or [0 a b 0 x y]).
+ palette is a string of 2^N or 3*2^N elements, specifying
+ how the 2^N possible pixel values will be interpreted.
+ Each element is interpreted as a gray value, or as RGB
+ values, multiplied by 255. For example, if you want
+ a monochrome image for which 0=white and 1=black, the
+ palette should be <ff 00>; if you want a 3-bit deep
+ image with just the primary colors and their complements
+ (ignoring the fact that 3-bit images are not supported),
+ the palette might be <000000 0000ff 00ff00 00ffff
+ ff0000 ff00ff ffff00 ffffff>. At present, the palette
+ must contain exactly 2, 4, 16, or 256 entries,
+ and must contain an entry for black and an entry
+ for white; if it contains any entries that aren't black,
+ white, or gray, it must contain at least the six primary
+ colors (red, green, blue, and their complements cyan,
+ magenta, and yellow); aside from this, its contents are
+ arbitrary.
+ Alternatively, palette can be 16, 24, 32, or null
+ (equivalent to 24). These are interpreted as:
+ 16 = 5R, 6G, 5B bits;
+ 24 = 8R, 8G, 8B bits;
+ 32 = 8C, 8M, 8Y, 8K bits.
+ Note that one can also make an image device (with the same
+ palette as an existing image device) by copying a device
+ using the copydevice operator.
+
+ <matrix> <width> <height> <palette> <word?> makewordimagedevice
+ <device>
+ Makes an image device as described above. word? is a
+ Boolean value indicating whether the data should be stored
+ in a word-oriented format internally. No ordinary
+ PostScript programs should use this operator.
+
+ <device> <index> <string> copyscanlines <substring>
+ Copies one or more scan lines from an image device into a
+ string, starting at a given scan line in the image.
+ The data is in the same format as for the image
+ operator. Error if the device is not an image device or
+ if the string is too small to hold at least one complete
+ scan line. Always copies an integral number of scan
+ lines.
+
+ <device> setdevice -
+ Sets the current device to the specified device. Also
+ resets the transformation and clipping path to the
+ initial values for the device. Signals an invalidaccess
+ error if the device is a prototype.
+
+ - currentdevice <device>
+ Gets the current device from the graphics state.
+
+ <device> getdeviceprops <mark> <name1> <value1> ... <namen> <valuen>
+ Gets the properties of a device. See the "device
+ parameters" section below for details.
+
+ <mark> <name1> <value1> ... <namen> <valuen> <device>
+ putdeviceprops <device>
+ Sets properties of a device. May cause undefined,
+ typecheck, rangecheck, or limitcheck errors.
+
+ - flushpage -
+ On displays, flushes any buffered output, so that it
+ is guaranteed to show up on the screen; on printers,
+ has no effect.
+
+Device parameters
+=================
+
+Ghostscript supports the concept of device parameters for all devices, not
+just page devices. (For non-page devices, these are accessible through
+get/putdeviceprops, as indicated above.)
+
+Here are the currently defined parameters for all devices:
+
+ BitsPerPixel <integer> (usually read-only)
+ Number of bits per pixel.
+
+ .HWMargins [<4 floats>]
+ Size of non-imageable regions around the edges
+ of the page, in 1/72" units.
+
+ HWSize [<integer> <integer>]
+ X and Y size in pixels.
+
+ Name <string> (read-only)
+ The device name. Currently, same as OutputDevice.
+
+ Colors, GrayValues, RedValues, GreenValues,
+ BlueValues, ColorValues (usually read-only)
+ As for the 'deviceinfo' operator of Display PostScript.
+ Red/Green/Blue/ColorValues are only defined if Colors > 1.
+
+ TextAlphaBits, GraphicsAlphaBits (usually read-only)
+ The number of bits of anti-aliasing
+ information for text or graphics
+ respectively. Legal values are 1 (no
+ anti-aliasing), 2, or 4; the default value
+ for most devices is 1.
+
+In addition, the following are defined per Adobe's documentation for the
+setpagedevice operator:
+ Duplex (if supported)
+ HWResolution
+ ImagingBBox
+ Margins
+ NumCopies (for printers only)
+ Orientation (if supported)
+ OutputDevice
+ PageOffset (write-only)
+ PageSize
+ ProcessColorModel
+Some devices may only allow certain values for HWResolution and PageSize.
+The null device ignores attempts to set PageSize; its size is always [0 0].
+
+For printers, the following are also defined:
+
+ BufferSpace <integer>
+ Buffer space for band lists, if the bitmap
+ is too big to fit in RAM.
+
+ MaxBitmap <integer>
+ Maximum space for a full bitmap in RAM.
+
+ OutputFile <string>
+ () means send to printer directly,
+ otherwise specifies the file name for
+ output; a %d is replaced by the page #;
+ on Unix systems, (|command) writes to a pipe
+
+ OpenOutputFile <boolean>
+ If true, open the device's output file
+ when the device is opened, rather than
+ waiting until the first page is ready to
+ print.
+
+ PageCount <integer> (read-only)
+ Counts the number of pages printed on the device.
+
+The following parameters are for use only by very specialized applications
+that separate band construction from band rasterization. Improper use may
+cause unpredictable errors. In particular, if you only want to allocate
+more memory for banding, to increase band size and improve performance, use
+the BufferSpace parameter, not BandBufferSpace.
+
+ BandHeight <integer>
+ The height of bands when banding. 0 means use the largest
+ band height that will fit within the BandBufferSpace
+ (or BufferSpace, if BandBufferSpace is not specified).
+
+ BandWidth <integer>
+ The width of bands in the rasterizing pass, in pixels. 0
+ means use the actual page width.
+
+ BandBufferSpace <integer>
+ The size of the band buffer in the rasterizing pass, in
+ bytes. 0 means use the same buffer size as for the
+ interpretation pass.
+
+In addition, Ghostscript supports the following parameter for
+setpagedevice/currentpagedevice that is *not* a device parameter per se:
+
+ ViewerPreProcess procedure
+ Specifies a procedure to be applied to the page device
+ dictionary before any other processing is done. The
+ procedure may not alter the dictionary, but it may return
+ a modified copy. This "hook" is provided for use by
+ viewing programs such as GSview.
+
+Miscellaneous additions
+=======================
+
+run can take either a string or a file as its argument. In the latter
+case, it just runs the file, closing it at the end, and trapping errors
+just as for the string case.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+PostScript is a trademark of Adobe Systems, Incorporated.
diff --git a/gs/lib.txt b/gs/lib.txt
new file mode 100644
index 000000000..e279b053e
--- /dev/null
+++ b/gs/lib.txt
@@ -0,0 +1,363 @@
+ Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, lib.txt, describes the Ghostscript library, a collection of C
+procedures that implement the primitive graphic operations of the
+Ghostscript language.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** The Ghostscript library ********
+********
+
+Ghostscript is actually two programs: a language interpreter, and a graphics
+library. The library provides, in the form of C procedures, all the
+graphics functions of the language, i.e., approximately those facilities
+listed in section 8.1 of the PostScript Language Reference Manual, Second
+Edition, starting with the graphics state operators. In addition, the
+library provides some lower-level graphics facilities that offer higher
+performance in exchange for less generality.
+
+PostScript operator API
+-----------------------
+
+The highest level of the library, which is the one that most clients will
+use, directly implements the PostScript graphics operators with procedures
+named gs_XXX, e.g., gs_moveto, gs_fill. Nearly all of these procedures take
+a graphics state object as their first argument, e.g.,
+ int gs_moveto(gs_state *, double, double);
+
+Nearly all procedures return an integer code which is >= 0 for a successful
+return or <0 for a failure. The failure codes correspond directly to
+PostScript errors, and are defined in gserrors.h.
+
+The library implements all the operators in the following sections of the
+PostScript Language Reference Manual, Second Edition, with the indicated
+omissions and with the APIs defined in the indicated .h files. A header of
+the form A.h(B.h) indicates that A.h is included in B.h, so A.h need not be
+included explicitly if B.h is included. Operators marked with * in the
+Omissions column are not implemented directly; the library provides
+lower-level procedures that can be used to implement the operator.
+
+There are slight differences in the operators that return multiple values,
+since C's provisions for this are awkward. Also, the control structure for
+the operators involving (a) callback procedure(s) (pathforall, image,
+colorimage, imagemask) is partly inverted: the client calls a procedure to
+set up an enumerator object, and then calls another procedure for each
+iteration. The ...show operators, charpath, and stringwidth also use an
+inverted control structure.
+
+Section Headers Omissions
+------- ------- ---------
+
+Graphics State Operators --
+Device Independent
+ gscolor.h(gsstate.h)
+ gscolor1.h
+ gscolor2.h
+ gscspace.h
+ gshsb.h
+ gsline.h(gsstate.h)
+ gsstate.h
+
+Graphics State Operators --
+Device Dependent
+ gscolor.h(gsstate.h)
+ gscolor1.h
+ gscolor2.h
+ gsht.h(gsht1.h,gsstate.h)
+ gsht1.h
+ gsline.h(gsstate.h)
+
+Coordinate System and
+Matrix Operators
+ gscoord.h *matrix, *identmatrix,
+ gsmatrix.h *concatmatrix, *invertmatrix
+
+Path Construction Operators
+ gspath.h *arct, *pathforall,
+ gspath2.h ustrokepath, uappend, upath, ucache
+
+Painting Operators
+ gsimage.h *image, *colorimage, *imagemask,
+ gspaint.h ufill, ueofill, ustroke
+ gspath2.h
+
+Form and Pattern Operators
+ gscolor2.h execform
+
+Device Setup and Output
+Operators
+ gsdevice.h *showpage, *set/currentpagedevice
+
+Character and Font Operators
+ gschar.h *(all the show operators),
+ gsfont.h definefont, undefinefont,
+ findfont, *scalefont, *makefont,
+ selectfont, [Global]FontDirectory,
+ Standard/ISOLatin1Encoding,
+ findencoding
+
+<< -------------------------------- end -------------------------------- >>
+
+The following procedures in the above list operate differently from their
+PostScript operator counterparts:
+
+Procedure(header) Difference(s)
+----------------- -------------
+
+gs_makepattern(gscolor2.h)
+ Takes an explicit current color, rather than using
+ the current color in the graphics state.
+ Takes an explicit allocator for allocating the
+ pattern implementation. See below for more details
+ on gs_makepattern.
+
+gs_setpattern(gscolor2.h)
+gs_setcolor(gscolor2.h)
+gs_currentcolor(gscolor2.h)
+ Use gs_client_color rather than a set of color
+ parameter values. See below for more details on
+ gs_setpattern.
+
+gs_currentdash_length/pattern/offset(gsline.h)
+ Splits up currentdash into 3 separate procedures.
+
+gs_screen_init/currentpoint/next/install(gsht.h)
+ Provide an "enumeration style" interface to
+ setscreen. (gs_setscreen is also implemented.)
+
+gs_rotate/scale/translate(gscoord.h)
+gs_[i][d]transform(gscoord.h)
+ These always operate on the graphics state CTM.
+ The corresponding operations on free-standing
+ matrices are in gsmatrix.h and have different names.
+
+gs_path_enum_alloc/init/next/cleanup(gspath.h)
+ Provide an "enumeration style" implementation of
+ pathforall.
+
+gs_image_enum_alloc(gsimage.h)
+gs_image_init/next/cleanup(gsimage.h)
+ Provide an "enumeration style" interface to the
+ equivalent of image, imagemask, and colorimage.
+ In the gs_image_t, ColorSpace provides an explicit
+ color space, rather than using the current color
+ space in the graphics state; ImageMask distinguishes
+ imagemask from [color]image.
+
+gs_get/putdeviceparams(gsdevice.h)
+ Take a gs_param_list for specifying or receiving
+ the parameter values. See gsparam.h for more
+ details.
+
+gs_show_enum_alloc/release(gschar.h)
+gs_xxxshow_[n_]init(gschar.h)
+gs_show_next(gschar.h)
+ Provide an "enumeration style" interface to writing
+ text. Note that control returns to the caller if
+ the character must be rasterized.
+
+<< -------------------------------- end -------------------------------- >>
+
+This level of the library also implements the following operators from other
+sections of the Manual:
+
+Section Headers Operators
+------- ------- ---------
+
+Interpreter Parameter
+Operators
+ gsfont.h cachestatus, setcachelimit,
+ *set/currentcacheparams
+
+Display PostScript Operators
+ gsstate.h set/currenthalftonephase
+
+<< -------------------------------- end -------------------------------- >>
+
+In order to obtain the full PostScript Level 2 functionality listed above,
+FEATURE_DEVS must be set in the makefile to include at least the following:
+
+ FEATURE_DEVS=patcore.dev cmykcore.dev psl2core.dev dps2core.dev ciecore.dev\
+ path1core.dev hsbcore.dev
+
+The *lib.mak makefiles mentioned below do not always include all of these
+features.
+
+Files named gs*.c implement the higher level of the graphics library. As
+might be expected, all procedures, variables, and structures available at
+this level begin with gs_. Structures that appear in these interfaces, but
+whose definitions may be hidden from clients, also have names beginning with
+gs_, i.e., the prefix reflects at what level the abstraction is made
+available, not the implementation.
+
+Patterns
+--------
+
+Patterns are the most complicated PostScript language objects that the
+library API deals with. As in PostScript, defining a pattern color and
+using the color are two separate operations.
+
+gs_makepattern defines a pattern color. Its arguments are as follows:
+
+ gs_client_color * -- the resulting Pattern color is stored here.
+ This is different from PostScript, which has no color objects per
+ se and hence returns a modified copy of the dictionary.
+
+ const gs_client_pattern * -- the analogue of the original Pattern
+ dictionary, described in detail just below.
+
+ const gs_matrix * -- corresponds to the matrix argument of the
+ makepattern operator.
+
+ gs_state * -- the current graphics state.
+
+ gs_memory_t * -- the allocator to use for allocating the saved data
+ for the Pattern color. If this is NULL, gs_makepattern uses the
+ same allocator that allocated the graphics state. Library clients
+ should probably always use NULL.
+
+The gs_client_pattern structure defined in gscolor2.h corresponds to the
+Pattern dictionary that is the argument to the PostScript language
+makepattern operator. This structure has one extra member, void
+*client_data, which is a place for clients to store a pointer to additional
+data for the PaintProc; this provides the same functionality as putting
+additional keys in the Pattern dictionary at the PostScript language level.
+The PaintProc is an ordinary C procedure that takes as parameters a
+gs_client_color *, which is the Pattern color that is being used for
+painting, and a gs_state *, which is the same graphics state that would be
+presented to the PaintProc in PostScript. Currently the gs_client_color *
+is always the current color in the graphics state, but the PaintProc should
+not rely on this. The PaintProc can retrieve the gs_client_pattern * from
+the gs_client_color * with the gs_getpattern procedure, also defined in
+gscolor2.h, and from there, it can retrieve the client_data pointer.
+
+The normal way to set a Pattern color is to call gs_setpattern with the
+graphics state and with the gs_client_color returned by gs_makepattern.
+After that, one can use gs_setcolor to set further Pattern colors (colored,
+or uncolored with the same underlying color space); the rules are the same
+as those in PostScript. Note that for gs_setpattern, the paint.values in
+the gs_client_color must be filled in for uncolored patterns; this
+corresponds to the additional arguments for the PostScript setpattern
+operator in the uncolored case.
+
+There is a special procedure gs_makebitmappattern for creating bitmap-based
+patterns. Its API is documented in gscolor2.h; its implementation, in
+gspcolor.c, may be useful as an example of a pattern using a particularly
+simple PaintProc.
+
+Lower-level API
+---------------
+
+Files named gx*.c implement the lower level of the graphics library. The
+interfaces at the gx level are less stable, and expose more of the
+implementation detail, than those at the gs level: in particular, the gx
+interfaces generally use device coordinates in an internal fixed-point
+representation, as opposed to the gs interfaces that use floating point user
+coordinates. Named entities at this level begin with gx_.
+
+Files named gz*.c and gz*.h are internal to the Ghostscript implementation,
+and are not designed to be called by clients.
+
+A full example
+--------------
+
+The file gslib.c in the Ghostscript fileset is a complete example program
+that initializes the library and produces output using it; files named
+*lib.mak (e.g., ugcclib.mak, bclib.mak) are makefiles using gslib.c as the
+main program. The following annotated excerpts from this file are intended
+to provide a roadmap for applications that call the library.
+
+ /* Capture stdin/out/err before gs.h redefines them. */
+ #include <stdio.h>
+ static FILE *real_stdin, *real_stdout, *real_stderr;
+ static void
+ get_real(void)
+ { real_stdin = stdin, real_stdout = stdout, real_stderr = stderr;
+ }
+
+Any application using Ghostscript should include the above fragment at the
+very beginning of the main program.
+
+ #include "gx.h"
+
+The gx.h header includes a wealth of declarations related to the Ghostscript
+memory manager, portability machinery, debugging framework, and other
+substrate facilities. Any application file that calls any Ghostscript API
+functions should probably include gx.h.
+
+ /* Configuration information imported from gconfig.c. */
+ extern gx_device *gx_device_list[];
+
+ /* Other imported procedures */
+ /* from gsinit.c */
+ extern void gs_lib_init(P1(FILE *));
+ extern void gs_lib_finit(P2(int, int));
+ /* from gsalloc.c */
+ extern gs_ref_memory_t *ialloc_alloc_state(P2(gs_memory_t *, uint));
+
+The above externs are needed for initializing the library.
+
+ gs_ref_memory_t *imem;
+ #define mem ((gs_memory_t *)imem)
+ gs_state *pgs;
+ gx_device *dev = gx_device_list[0];
+
+ gp_init();
+ get_real();
+ gs_stdin = real_stdin;
+ gs_stdout = real_stdout;
+ gs_stderr = real_stderr;
+ gs_lib_init(stdout);
+ ....
+ imem = ialloc_alloc_state(&gs_memory_default, 20000);
+ imem->space = 0;
+ ....
+ pgs = gs_state_alloc(mem);
+
+The above code initializes the library and its memory manager. pgs now
+points to the graphics state that will be passed to the drawing routines in
+the library.
+
+ gs_setdevice_no_erase(pgs, dev); /* can't erase yet */
+ { gs_point dpi;
+ gs_screen_halftone ht;
+ gs_dtransform(pgs, 72.0, 72.0, &dpi);
+ ht.frequency = min(fabs(dpi.x), fabs(dpi.y)) / 16.001;
+ ht.angle = 0;
+ ht.spot_function = odsf;
+ gs_setscreen(pgs, &ht);
+ }
+
+The above initializes the default device and sets a default halftone screen.
+(For brevity, we have omitted the definition of odsf, the spot function.)
+
+ /* gsave and grestore (among other places) assume that */
+ /* there are at least 2 gstates on the graphics stack. */
+ /* Ensure that now. */
+ gs_gsave(pgs);
+
+The above call completes initializing the graphics state.
+
+When the program is finished, it should execute:
+
+ gs_lib_finit(0, 0);
diff --git a/gs/lib/Fontmap b/gs/lib/Fontmap
new file mode 100644
index 000000000..70e42feea
--- /dev/null
+++ b/gs/lib/Fontmap
@@ -0,0 +1,399 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Fontmap - standard font catalog for Ghostscript.
+
+% ----------------------------------------------------------------
+
+% This file is a catalog of fonts known to Ghostscript. Any font
+% that is to be loaded automatically when named must be in this catalog,
+% except for fonts that Ghostscript finds automatically in directories
+% named in the GS_FONTPATH environment variable.
+
+% Each font has an entry consisting of three items:
+%
+% - The name by which the font is known inside Ghostscript
+% (a Ghostscript name preceded by a `/', or a string enclosed
+% in parentheses). This is used to find the file from which
+% a font of a given name should be loaded.
+%
+% - Information depending on whether this is a real font or a
+% font alias:
+%
+% - For real fonts, the name of the Ghostscript font
+% file (a Ghostscript string, enclosed in parentheses).
+% The filename should include the extension, which (by
+% convention) is `.gsf'. `.pfa' and `.pfb' files are
+% also usable as fonts for Ghostscript.
+%
+% - For font aliases, the name of the font which should
+% be used when this one is requested, preceded by a
+% `/'. See the entry for Charter below for an example.
+% Note that an alias name cannot be enclosed in parentheses.
+%
+% - At least one space or tab, and a terminating semicolon.
+
+% Because of limitations in the MS-DOS environment, Ghostscript font
+% file names must be no more than 8 characters long, must consist only
+% of LOWER CASE letters, digits, and underscores, and must start with a
+% letter. Font names, on the other hand, need only obey the syntax of
+% names in the Ghostscript language, which is much more liberal.
+
+% The following table is actually a Ghostscript data structure.
+% If you add new entries, be sure to copy the punctuation accurately;
+% in particular, you must leave at least one space or tab between each
+% field in the entry. Also, please read fonts.doc for important information
+% about font names.
+
+% Note that .pfa and .pfb fonts are compatible with Adobe Type Manager
+% and other programs that don't include full PostScript interpreters,
+% as well as with PostScript interpreters; .gsf fonts are compatible with
+% PostScript interpreters, but not with ATM or similar programs.
+
+%
+%
+% Fonts contributed by:
+% URW++ Design and Development Incorporated
+% Poppenbuetteler Bogen 29A
+% D-22399 Hamburg
+% Germany
+% tel. +49 (40) 60 60 50
+% fax +49 (40) 60 60 51 11
+% http://www.urwpp.de
+% for distribution under the GNU License and Aladdin Free Public License.
+% See the notice at the head of this Fontmap file for licensing terms.
+% Each of these fonts is individually covered by the license:
+% for licensing purposes, they are not "part of" any larger entity.
+% The following notice applies to these fonts:
+%
+% Copyright URW Software, Copyright 1994 by URW.
+%
+
+% Actual fonts
+
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+
+/NimbusMonL-Regu (n022003l.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+
+/URWGothicL-Book (a010013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+
+/NimbusSanL-Regu (n019003l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+
+/URWPalladioL-Roma (p052003l.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+
+/CenturySchL-Roma (c059013l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+
+/StandardSymL (s050000l.pfb) ;
+
+/URWChanceryL-MediItal (z003034l.pfb) ;
+
+/Dingbats (d050000l.pfb) ;
+
+% Aliases
+
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+
+/Courier /NimbusMonL-Regu ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+
+/Helvetica /NimbusSanL-Regu ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+
+/Palatino-Roman /URWPalladioL-Roma ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+
+/Times-Roman /NimbusRomNo9L-Regu ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+
+/Symbol /StandardSymL ;
+
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+
+/ZapfDingbats /Dingbats ;
+
+%
+%
+% Type 1 fonts contributed to the X11R5 distribution.
+%
+
+% The following notice accompanied the Charter fonts.
+%
+% (c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA.
+%
+% You are hereby granted permission under all Bitstream propriety rights
+% to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream
+% Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts
+% for any purpose and without restriction; provided, that this notice is
+% left intact on all copies of such fonts and that Bitstream's trademark
+% is acknowledged as shown below on all unmodified copies of the 4 Charter
+% Type 1 fonts.
+%
+% BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
+
+% The Bitstream Charter fonts have different names (CharterBT-
+% instead of Charter-), but Ghostscript doesn't care.
+/Charter-Roman (bchr.pfa) ;
+/Charter-Italic (bchri.pfa) ;
+/Charter-Bold (bchb.pfa) ;
+/Charter-BoldItalic (bchbi.pfa) ;
+
+% The following notice accompanied the Utopia font:
+%
+% Permission to use, reproduce, display and distribute the listed
+% typefaces is hereby granted, provided that the Adobe Copyright notice
+% appears in all whole and partial copies of the software and that the
+% following trademark symbol and attribution appear in all unmodified
+% copies of the software:
+%
+% Copyright (c) 1989 Adobe Systems Incorporated
+% Utopia (R)
+% Utopia is a registered trademark of Adobe Systems Incorporated
+%
+% The Adobe typefaces (Type 1 font program, bitmaps and Adobe Font
+% Metric files) donated are:
+%
+% Utopia Regular
+% Utopia Italic
+% Utopia Bold
+% Utopia Bold Italic
+
+/Utopia-Regular (putr.pfa) ;
+/Utopia-Italic (putri.pfa) ;
+/Utopia-Bold (putb.pfa) ;
+/Utopia-BoldItalic (putbi.pfa) ;
+
+%
+%
+% Fonts contributed by URW GmbH for distribution under the GNU License.
+% The following notice accompanied these fonts:
+%
+% U004006T URW Grotesk 2031 Bold PostScript Type 1 Font Program
+% U003043T URW Antiqua 2051 Regular Condensed PostScript Type 1 Font Program
+%
+% Copyright (c) 1992 URW GmbH, Hamburg, Germany
+%
+% 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) later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; wihtout 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.
+%
+% Address:
+% URW GmbH
+% PC Support
+% Harksheider Strasse 102
+% 2000 Hamburg 65
+% Germany
+% Phone: +49 40 60 60 50 (Reception)
+% Phone: +49 40 60 60 52 30 (PC Support)
+% Fax : +49 40 60 60 52 52
+%
+
+/URWAntiquaT-RegularCondensed (u003043t.gsf) ;
+/URWGroteskT-Bold (u004006t.gsf) ;
+
+%
+%
+% Shareware Kana fonts. These are subject to the following notice:
+%
+% These copyrighted fonts were developed by Kevin Hartig. Permission is
+% granted to freely distribute them in entirety along with this statement.
+% This is shareware. If you decide to use these fonts please contribute
+% $10 US to help support further freeware and shareware software development.
+% Questions and comments may be sent to:
+%
+% hartig@fsl.noaa.gov
+% khartig@nyx.cs.du.edu
+%
+% Kevin Hartig
+% 1126 Collyer Street
+% Longmont, CO 80501 USA
+%
+% copyright 1993.
+
+% Hiragana and Katakana fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+
+%
+%
+% Public-domain fonts. These have no copyright, and are of unknown quality.
+
+% Cyrillic fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+
+% Aliases
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+%
+%
+% Fonts converted from Hershey outlines. These are constructed and
+% maintained manually. These are also in the public domain.
+%
+% The suggested UniqueID's and filenames are constructed differently for
+% these than for the ones above, because of the strange way that the Hershey
+% fonts were constructed. The scheme for these looks like:
+%
+% 42TTXY0
+%
+% TT = typeface, X = ``class'', Y = variation
+%
+% The typeface names and numbers are listed in fonts.mak.
+%
+% class:
+% 0 = normal = r
+% 1 = simplex = s
+% 2 = complex = c
+% 3 = triplex = t
+% 4 = duplex = d
+%
+% variation:
+% 0 = normal (omitted)
+% 1 = oblique = o
+% 2 = italic = i
+% 3 = bold = b
+% 4 = bold oblique = bo
+% 5 = bold italic = bi
+%
+
+% Fonts created by Thomas Wolff <wolff@inf.fu-berlin.de>, by adding
+% accents, accented characters, and various other non-alphabetics
+% to the original Hershey fonts. These are "freeware", not to be sold.
+
+/Hershey-Gothic-English (hrger.pfa) ; % 5066533
+/Hershey-Gothic-German (hrgrr.pfa) ;
+/Hershey-Gothic-Italian (hritr.pfa) ;
+
+/Hershey-Plain-Duplex (hrpld.pfa) ;
+/Hershey-Plain-Duplex-Italic (hrpldi.pfa) ;
+/Hershey-Plain-Triplex (hrplt.pfa) ;
+/Hershey-Plain-Triplex-Italic (hrplti.pfa) ;
+
+/Hershey-Script-Complex (hrscc.pfa) ;
+/Hershey-Script-Simplex (hrscs.pfa) ; % 5066541
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Gothic-English-Bold (hrgerb.gsf) ; % 5066542
+/Hershey-Gothic-English-Oblique (hrgero.gsf) ;
+/Hershey-Gothic-English-SemiBold (hrgerd.gsf) ;
+/Hershey-Gothic-German-Bold (hrgrrb.gsf) ;
+/Hershey-Gothic-German-Oblique (hrgrro.gsf) ;
+/Hershey-Gothic-Italian-Bold (hritrb.gsf) ;
+/Hershey-Gothic-Italian-Oblique (hritro.gsf) ;
+
+/Hershey-Plain-Duplex-Bold (hrpldb.gsf) ;
+/Hershey-Plain-Duplex-Bold-Italic (hrpldbi.gsf) ;
+/Hershey-Plain-Triplex-Bold (hrpltb.gsf) ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpltbi.gsf) ;
+
+/Hershey-Script-Complex-Bold (hrsccb.gsf) ;
+/Hershey-Script-Complex-Oblique (hrscco.gsf) ;
+/Hershey-Script-Simplex-Bold (hrscsb.gsf) ;
+/Hershey-Script-Simplex-Oblique (hrscso.gsf) ; % 5066556
+
+% Fonts consisting only of characters from the original Hershey
+% distribution. These are Type 3 fonts.
+
+/Hershey-Greek-Complex (hrgkc.gsf) ; % 5066557
+/Hershey-Greek-Simplex (hrgks.gsf) ;
+
+/Hershey-Plain (hrplr.gsf) ;
+/Hershey-Plain-Simplex (hrpls.gsf) ; % 5066560
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Plain-Bold (hrplrb.gsf) ; % 5066561
+/Hershey-Plain-Bold-Oblique (hrplrbo.gsf) ;
+/Hershey-Plain-Oblique (hrplro.gsf) ;
+/Hershey-Plain-Simplex-Bold (hrplsb.gsf) ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrplsbo.gsf) ;
+/Hershey-Plain-Simplex-Oblique (hrplso.gsf) ; % 5066566
+
+% This font, and only this font among the Hershey fonts, uses
+% the SymbolEncoding.
+
+/Hershey-Symbol (hrsyr.gsf) ; % 5066567
diff --git a/gs/lib/Fontmap.ATB b/gs/lib/Fontmap.ATB
new file mode 100644
index 000000000..a622c9e6b
--- /dev/null
+++ b/gs/lib/Fontmap.ATB
@@ -0,0 +1,169 @@
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Fontmap.ATB - an alternative Fontmap for Ghostscript,
+% suitable for use with the 65 Adobe Type Manager fonts
+% supplied with Adobe Type Basics.
+
+% Before you use ATM fonts with Ghostscript, please read carefully
+% the license that accompanies the ATM fonts; neither Aladdin Enterprises
+% nor any other distributor of Ghostscript takes any responsibility for
+% any possible violations of such licenses.
+
+% The 65 Adobe Type Basics ATM fonts
+
+%disk 1
+/Bookman-Light (bkl_____.pfb) ;
+/Bookman-Demi (bkd_____.pfb) ;
+/Bookman-DemiItalic (bkdi____.pfb) ;
+/Bookman-LightItalic (bkli____.pfb) ;
+/Courier (com_____.pfb) ;
+/Courier-Bold (cob_____.pfb) ;
+/Courier-BoldOblique (cobo____.pfb) ;
+/Courier-Oblique (coo_____.pfb) ;
+/Helvetica (hv______.pfb) ;
+/Helvetica-Bold (hvb_____.pfb) ;
+/Helvetica-BoldOblique (hvbo____.pfb) ;
+/Helvetica-Oblique (hvo_____.pfb) ;
+/Helvetica-Narrow (hvn_____.pfb) ;
+/Helvetica-Narrow-Bold (hvnb____.pfb) ;
+/Helvetica-Narrow-BoldOblique (hvnbo___.pfb) ;
+/Helvetica-Narrow-Oblique (hvno____.pfb) ;
+/Palatino-Roman (por_____.pfb) ;
+/Palatino-Bold (pob_____.pfb) ;
+/Palatino-BoldItalic (pobi____.pfb) ;
+/Palatino-Italic (poi_____.pfb) ;
+/Symbol (sy______.pfb) ;
+/Times-Roman (tir_____.pfb) ;
+/Times-Bold (tib_____.pfb) ;
+/Times-BoldItalic (tibi____.pfb) ;
+/Times-Italic (tii_____.pfb) ;
+
+% disk2
+/AGaramond-Regular (gdrg____.pfb) ;
+/AGaramond-Italic (gdi_____.pfb) ;
+/AGaramond-Bold (gdb_____.pfb) ;
+/AGaramond-BoldItalic (gdbi____.pfb) ;
+/Americana (am______.pfb) ;
+/Americana-ExtraBold (ameb____.pfb) ;
+/AvantGarde-Book (agw_____.pfb) ;
+/AvantGarde-Demi (agd_____.pfb) ;
+/AvantGarde-DemiOblique (agdo____.pfb) ;
+/AvantGarde-BookOblique (agwo____.pfb) ;
+/Carta (cr______.pfb) ;
+/Kaufmann (kf______.pfb) ;
+/Lithos-Regular (lorg____.pfb) ;
+/Lithos-Black (lobl____.pfb) ;
+/NewCenturySchlbk-Roman (ncr_____.pfb) ;
+/NewCenturySchlbk-Bold (ncb_____.pfb) ;
+/NewCenturySchlbk-BoldItalic (ncbi____.pfb) ;
+/NewCenturySchlbk-Italic (nci_____.pfb) ;
+/Parisian (pn______.pfb) ;
+/ParkAvenue (pa______.pfb) ;
+/Tekton (tkrg____.pfb) ;
+/Tekton-Bold (tkb_____.pfb) ;
+/Trajan-Bold (tjb_____.pfb) ;
+/ZapfChancery-MediumItalic (zcmi____.pfb) ;
+/ZapfDingbats (zd______.pfb) ;
+
+%disk 3
+/ACaslon-Regular (awrg____.pfb) ;
+/ACaslon-Semibold (awsb____.pfb) ;
+/ACaslon-SemiboldItalic (awsbi___.pfb) ;
+/ACaslon-Italic (awi_____.pfb) ;
+/Barmeno-Regular (bfrg____.pfb) ;
+/Barmeno-Medium (bfm_____.pfb) ;
+/Barmeno-Bold (bfb_____.pfb) ;
+/Barmeno-ExtraBold (bfeb____.pfb) ;
+/Blackoak (bo______.pfb) ;
+/Formata-Regular (fmrg____.pfb) ;
+/Formata-Medium (fmm_____.pfb) ;
+/Formata-MediumItalic (fmmi____.pfb) ;
+/Formata-Italic (fmi_____.pfb) ;
+/Poetica-SuppOrnaments (pvor____.pfb) ;
+/WoodtypeOrnaments-Two (woor2___.pfb) ;
+
+
+% Fonts converted from bitmaps.
+
+/Charter-Roman (bchr.gsf) ;
+/Charter-Italic (bchri.gsf) ;
+/Charter-Bold (bchb.gsf) ;
+/Charter-BoldItalic (bchbi.gsf) ;
+
+/ZapfChancery (zcr.gsf) ;
+/ZapfChancery-Oblique (zcro.gsf) ;
+/ZapfChancery-Bold (zcb.gsf) ;
+
+% Fonts from the X11R5 distribution.
+
+/Utopia-Regular (putr.gsf) ;
+/Utopia-Italic (putri.gsf) ;
+/Utopia-Bold (putb.gsf) ;
+/Utopia-BoldItalic (putbi.gsf) ;
+
+% Shareware fonts. See FONTMAP.GS for the copyright statements.
+
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+% Aliases
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+
+% Fonts converted from Hershey outlines.
+
+/Hershey-Gothic-English (hrge_r.gsf) 4290000 ;
+/Hershey-Gothic-English-Bold (hrge_rb.gsf) 4290030 ;
+/Hershey-Gothic-English-Oblique (hrge_ro.gsf) 4290010 ;
+
+/Hershey-Gothic-German (hrgr_r.gsf) 4291000 ;
+/Hershey-Gothic-German-Bold (hrgr_rb.gsf) 4291030 ;
+/Hershey-Gothic-German-Oblique (hrgr_ro.gsf) 4291010 ;
+
+/Hershey-Gothic-Italian (hrit_r.gsf) 4292000 ;
+/Hershey-Gothic-Italian-Bold (hrit_rb.gsf) 4292030 ;
+/Hershey-Gothic-Italian-Oblique (hrit_ro.gsf) 4292010 ;
+
+/Hershey-Greek-Complex (hrgk_c.gsf) 4293200 ;
+/Hershey-Greek-Simplex (hrgk_s.gsf) 4293100 ;
+
+/Hershey-Plain (hrpl_r.gsf) 4294000 ;
+/Hershey-Plain-Bold (hrpl_rb.gsf) 4294030 ;
+/Hershey-Plain-Oblique (hrpl_ro.gsf) 4294010 ;
+/Hershey-Plain-Simplex (hrpl_s.gsf) 4294100 ;
+/Hershey-Plain-Simplex-Bold (hrpl_sb.gsf) 4294130 ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrpl_sbo.gsf) 4294140 ;
+/Hershey-Plain-Simplex-Oblique (hrpl_so.gsf) 4294110 ;
+/Hershey-Plain-Triplex (hrpl_t.gsf) 4294300 ;
+/Hershey-Plain-Triplex-Italic (hrpl_ti.gsf) 4294320 ;
+/Hershey-Plain-Triplex-Bold (hrpl_tb.gsf) 4294330 ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpl_tbi.gsf) 4294350 ;
+
+/Hershey-Script-Complex (hrsc_c.gsf) 4295200 ;
+/Hershey-Script-Complex-Bold (hrsc_cb.gsf) 4295230 ;
+/Hershey-Script-Complex-Oblique (hrsc_co.gsf) 4295210 ;
+/Hershey-Script-Simplex (hrsc_s.gsf) 4295100 ;
+/Hershey-Script-Simplex-Bold (hrsc_sb.gsf) 4295130 ;
+/Hershey-Script-Simplex-Oblique (hrsc_so.gsf) 4295110 ;
+
+% This font, and only this font among the Hershey fonts, uses
+% the SymbolEncoding.
+/Hershey-Symbol (hrsy_r.gsf) 4296000 ;
diff --git a/gs/lib/Fontmap.ATM b/gs/lib/Fontmap.ATM
new file mode 100644
index 000000000..6500a7a5d
--- /dev/null
+++ b/gs/lib/Fontmap.ATM
@@ -0,0 +1,186 @@
+% Copyright (C) 1990, 1992, 1994, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Fontmap.ATM - an alternative Fontmap for Ghostscript,
+% suitable for use with Adobe Type Manager fonts.
+
+% Before you use ATM fonts with Ghostscript, please read carefully
+% the license that accompanies the ATM fonts; neither Aladdin Enterprises
+% nor any other distributor of Ghostscript takes any responsibility for
+% any possible violations of such licenses.
+
+%
+%
+% Fonts contributed by:
+% URW++ Design and Development Incorporated
+% Poppenbuetteler Bogen 29A
+% D-22399 Hamburg
+% Germany
+% tel. +49 (40) 60 60 50
+% fax +49 (40) 60 60 51 11
+% http://www.urwpp.de
+% for distribution under the GNU License and Aladdin Free Public License.
+% See the notice at the head of this Fontmap file for licensing terms.
+% Each of these fonts is individually covered by the license:
+% for licensing purposes, they are not "part of" any larger entity.
+% The following notice applies to these fonts:
+%
+% Copyright URW Software, Copyright 1994 by URW.
+%
+
+% Actual fonts
+
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+
+/NimbusMonL-Regu (n022003l.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+
+/URWGothicL-Book (a010013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+
+/NimbusSanL-Regu (n019003l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+
+/URWPalladioL-Roma (p052003l.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+
+/CenturySchL-Roma (c059013l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+
+/StandardSymL (s050000l.pfb) ;
+
+/URWChanceryL-MediItal (z003034l.pfb) ;
+
+/Dingbats (d050000l.pfb) ;
+
+% Aliases
+
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+
+/Courier /NimbusMonL-Regu ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+
+/Helvetica /NimbusSanL-Regu ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+
+/Palatino-Roman /URWPalladioL-Roma ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+
+/Times-Roman /NimbusRomNo9L-Regu ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+
+/Symbol /StandardSymL ;
+
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+
+/ZapfDingbats /Dingbats ;
+
+
+% ATM fonts.
+
+/Courier (com_____.pfb) ;
+/Courier-Oblique (coo_____.pfb) ;
+/Courier-Bold (cob_____.pfb) ;
+/Courier-BoldOblique (cobo____.pfb) ;
+
+/Helvetica (hv______.pfb) ;
+/Helvetica-Oblique (hvo_____.pfb) ;
+/Helvetica-Bold (hvb_____.pfb) ;
+/Helvetica-BoldOblique (hvbo____.pfb) ;
+
+/Symbol (sy______.pfb) ;
+
+/Times-Roman (tir_____.pfb) ;
+/Times-Italic (tii_____.pfb) ;
+/Times-Bold (tib_____.pfb) ;
+/Times-BoldItalic (tibi____.pfb) ;
+
+
+% More fonts from Adobe Type Manager for MS Windows.
+
+/TektonMM (zjrg____.pfb) ;
+
+/Boulevard (qtrg____.pfb) ;
+/Anna (iarg____.pfb) ;
+
+/PopplLaudatio-Regular (pyrg____.pfb) ;
+/PopplLaudatio-Medium (pym_____.pfb) ;
+/PopplLaudatio-Italic (pyi_____.pfb) ;
+/PopplLaudatio-MediumItalic (pymi____.pfb) ;
+
+/Boton-Regular (tnr_____.pfb) ;
+/Boton-Medium (tnm_____.pfb) ;
+/Boton-Italic (tni_____.pfb) ;
+/Boton-MediumItalic (tnmi____.pfb) ;
+
+/BaskervilleBE-Regular (virg____.pfb) ;
+/BaskervilleBE-Medium (vim_____.pfb) ;
+/BaskervilleBE-Italic (vii_____.pfb) ;
+/BaskervilleBE-MediumItalic (vimi____.pfb) ;
+
+/Giddyup (wg______.pfb) ;
+/Giddyup-Thangs (wgtha___.pfb) ;
+
diff --git a/gs/lib/Fontmap.GS b/gs/lib/Fontmap.GS
new file mode 100644
index 000000000..70e42feea
--- /dev/null
+++ b/gs/lib/Fontmap.GS
@@ -0,0 +1,399 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Fontmap - standard font catalog for Ghostscript.
+
+% ----------------------------------------------------------------
+
+% This file is a catalog of fonts known to Ghostscript. Any font
+% that is to be loaded automatically when named must be in this catalog,
+% except for fonts that Ghostscript finds automatically in directories
+% named in the GS_FONTPATH environment variable.
+
+% Each font has an entry consisting of three items:
+%
+% - The name by which the font is known inside Ghostscript
+% (a Ghostscript name preceded by a `/', or a string enclosed
+% in parentheses). This is used to find the file from which
+% a font of a given name should be loaded.
+%
+% - Information depending on whether this is a real font or a
+% font alias:
+%
+% - For real fonts, the name of the Ghostscript font
+% file (a Ghostscript string, enclosed in parentheses).
+% The filename should include the extension, which (by
+% convention) is `.gsf'. `.pfa' and `.pfb' files are
+% also usable as fonts for Ghostscript.
+%
+% - For font aliases, the name of the font which should
+% be used when this one is requested, preceded by a
+% `/'. See the entry for Charter below for an example.
+% Note that an alias name cannot be enclosed in parentheses.
+%
+% - At least one space or tab, and a terminating semicolon.
+
+% Because of limitations in the MS-DOS environment, Ghostscript font
+% file names must be no more than 8 characters long, must consist only
+% of LOWER CASE letters, digits, and underscores, and must start with a
+% letter. Font names, on the other hand, need only obey the syntax of
+% names in the Ghostscript language, which is much more liberal.
+
+% The following table is actually a Ghostscript data structure.
+% If you add new entries, be sure to copy the punctuation accurately;
+% in particular, you must leave at least one space or tab between each
+% field in the entry. Also, please read fonts.doc for important information
+% about font names.
+
+% Note that .pfa and .pfb fonts are compatible with Adobe Type Manager
+% and other programs that don't include full PostScript interpreters,
+% as well as with PostScript interpreters; .gsf fonts are compatible with
+% PostScript interpreters, but not with ATM or similar programs.
+
+%
+%
+% Fonts contributed by:
+% URW++ Design and Development Incorporated
+% Poppenbuetteler Bogen 29A
+% D-22399 Hamburg
+% Germany
+% tel. +49 (40) 60 60 50
+% fax +49 (40) 60 60 51 11
+% http://www.urwpp.de
+% for distribution under the GNU License and Aladdin Free Public License.
+% See the notice at the head of this Fontmap file for licensing terms.
+% Each of these fonts is individually covered by the license:
+% for licensing purposes, they are not "part of" any larger entity.
+% The following notice applies to these fonts:
+%
+% Copyright URW Software, Copyright 1994 by URW.
+%
+
+% Actual fonts
+
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+
+/NimbusMonL-Regu (n022003l.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+
+/URWGothicL-Book (a010013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+
+/NimbusSanL-Regu (n019003l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+
+/URWPalladioL-Roma (p052003l.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+
+/CenturySchL-Roma (c059013l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+
+/StandardSymL (s050000l.pfb) ;
+
+/URWChanceryL-MediItal (z003034l.pfb) ;
+
+/Dingbats (d050000l.pfb) ;
+
+% Aliases
+
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+
+/Courier /NimbusMonL-Regu ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+
+/Helvetica /NimbusSanL-Regu ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+
+/Palatino-Roman /URWPalladioL-Roma ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+
+/Times-Roman /NimbusRomNo9L-Regu ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+
+/Symbol /StandardSymL ;
+
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+
+/ZapfDingbats /Dingbats ;
+
+%
+%
+% Type 1 fonts contributed to the X11R5 distribution.
+%
+
+% The following notice accompanied the Charter fonts.
+%
+% (c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA.
+%
+% You are hereby granted permission under all Bitstream propriety rights
+% to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream
+% Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts
+% for any purpose and without restriction; provided, that this notice is
+% left intact on all copies of such fonts and that Bitstream's trademark
+% is acknowledged as shown below on all unmodified copies of the 4 Charter
+% Type 1 fonts.
+%
+% BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
+
+% The Bitstream Charter fonts have different names (CharterBT-
+% instead of Charter-), but Ghostscript doesn't care.
+/Charter-Roman (bchr.pfa) ;
+/Charter-Italic (bchri.pfa) ;
+/Charter-Bold (bchb.pfa) ;
+/Charter-BoldItalic (bchbi.pfa) ;
+
+% The following notice accompanied the Utopia font:
+%
+% Permission to use, reproduce, display and distribute the listed
+% typefaces is hereby granted, provided that the Adobe Copyright notice
+% appears in all whole and partial copies of the software and that the
+% following trademark symbol and attribution appear in all unmodified
+% copies of the software:
+%
+% Copyright (c) 1989 Adobe Systems Incorporated
+% Utopia (R)
+% Utopia is a registered trademark of Adobe Systems Incorporated
+%
+% The Adobe typefaces (Type 1 font program, bitmaps and Adobe Font
+% Metric files) donated are:
+%
+% Utopia Regular
+% Utopia Italic
+% Utopia Bold
+% Utopia Bold Italic
+
+/Utopia-Regular (putr.pfa) ;
+/Utopia-Italic (putri.pfa) ;
+/Utopia-Bold (putb.pfa) ;
+/Utopia-BoldItalic (putbi.pfa) ;
+
+%
+%
+% Fonts contributed by URW GmbH for distribution under the GNU License.
+% The following notice accompanied these fonts:
+%
+% U004006T URW Grotesk 2031 Bold PostScript Type 1 Font Program
+% U003043T URW Antiqua 2051 Regular Condensed PostScript Type 1 Font Program
+%
+% Copyright (c) 1992 URW GmbH, Hamburg, Germany
+%
+% 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) later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; wihtout 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.
+%
+% Address:
+% URW GmbH
+% PC Support
+% Harksheider Strasse 102
+% 2000 Hamburg 65
+% Germany
+% Phone: +49 40 60 60 50 (Reception)
+% Phone: +49 40 60 60 52 30 (PC Support)
+% Fax : +49 40 60 60 52 52
+%
+
+/URWAntiquaT-RegularCondensed (u003043t.gsf) ;
+/URWGroteskT-Bold (u004006t.gsf) ;
+
+%
+%
+% Shareware Kana fonts. These are subject to the following notice:
+%
+% These copyrighted fonts were developed by Kevin Hartig. Permission is
+% granted to freely distribute them in entirety along with this statement.
+% This is shareware. If you decide to use these fonts please contribute
+% $10 US to help support further freeware and shareware software development.
+% Questions and comments may be sent to:
+%
+% hartig@fsl.noaa.gov
+% khartig@nyx.cs.du.edu
+%
+% Kevin Hartig
+% 1126 Collyer Street
+% Longmont, CO 80501 USA
+%
+% copyright 1993.
+
+% Hiragana and Katakana fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+
+%
+%
+% Public-domain fonts. These have no copyright, and are of unknown quality.
+
+% Cyrillic fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+
+% Aliases
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+%
+%
+% Fonts converted from Hershey outlines. These are constructed and
+% maintained manually. These are also in the public domain.
+%
+% The suggested UniqueID's and filenames are constructed differently for
+% these than for the ones above, because of the strange way that the Hershey
+% fonts were constructed. The scheme for these looks like:
+%
+% 42TTXY0
+%
+% TT = typeface, X = ``class'', Y = variation
+%
+% The typeface names and numbers are listed in fonts.mak.
+%
+% class:
+% 0 = normal = r
+% 1 = simplex = s
+% 2 = complex = c
+% 3 = triplex = t
+% 4 = duplex = d
+%
+% variation:
+% 0 = normal (omitted)
+% 1 = oblique = o
+% 2 = italic = i
+% 3 = bold = b
+% 4 = bold oblique = bo
+% 5 = bold italic = bi
+%
+
+% Fonts created by Thomas Wolff <wolff@inf.fu-berlin.de>, by adding
+% accents, accented characters, and various other non-alphabetics
+% to the original Hershey fonts. These are "freeware", not to be sold.
+
+/Hershey-Gothic-English (hrger.pfa) ; % 5066533
+/Hershey-Gothic-German (hrgrr.pfa) ;
+/Hershey-Gothic-Italian (hritr.pfa) ;
+
+/Hershey-Plain-Duplex (hrpld.pfa) ;
+/Hershey-Plain-Duplex-Italic (hrpldi.pfa) ;
+/Hershey-Plain-Triplex (hrplt.pfa) ;
+/Hershey-Plain-Triplex-Italic (hrplti.pfa) ;
+
+/Hershey-Script-Complex (hrscc.pfa) ;
+/Hershey-Script-Simplex (hrscs.pfa) ; % 5066541
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Gothic-English-Bold (hrgerb.gsf) ; % 5066542
+/Hershey-Gothic-English-Oblique (hrgero.gsf) ;
+/Hershey-Gothic-English-SemiBold (hrgerd.gsf) ;
+/Hershey-Gothic-German-Bold (hrgrrb.gsf) ;
+/Hershey-Gothic-German-Oblique (hrgrro.gsf) ;
+/Hershey-Gothic-Italian-Bold (hritrb.gsf) ;
+/Hershey-Gothic-Italian-Oblique (hritro.gsf) ;
+
+/Hershey-Plain-Duplex-Bold (hrpldb.gsf) ;
+/Hershey-Plain-Duplex-Bold-Italic (hrpldbi.gsf) ;
+/Hershey-Plain-Triplex-Bold (hrpltb.gsf) ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpltbi.gsf) ;
+
+/Hershey-Script-Complex-Bold (hrsccb.gsf) ;
+/Hershey-Script-Complex-Oblique (hrscco.gsf) ;
+/Hershey-Script-Simplex-Bold (hrscsb.gsf) ;
+/Hershey-Script-Simplex-Oblique (hrscso.gsf) ; % 5066556
+
+% Fonts consisting only of characters from the original Hershey
+% distribution. These are Type 3 fonts.
+
+/Hershey-Greek-Complex (hrgkc.gsf) ; % 5066557
+/Hershey-Greek-Simplex (hrgks.gsf) ;
+
+/Hershey-Plain (hrplr.gsf) ;
+/Hershey-Plain-Simplex (hrpls.gsf) ; % 5066560
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Plain-Bold (hrplrb.gsf) ; % 5066561
+/Hershey-Plain-Bold-Oblique (hrplrbo.gsf) ;
+/Hershey-Plain-Oblique (hrplro.gsf) ;
+/Hershey-Plain-Simplex-Bold (hrplsb.gsf) ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrplsbo.gsf) ;
+/Hershey-Plain-Simplex-Oblique (hrplso.gsf) ; % 5066566
+
+% This font, and only this font among the Hershey fonts, uses
+% the SymbolEncoding.
+
+/Hershey-Symbol (hrsyr.gsf) ; % 5066567
diff --git a/gs/lib/Fontmap.OS2 b/gs/lib/Fontmap.OS2
new file mode 100644
index 000000000..4ec6074bf
--- /dev/null
+++ b/gs/lib/Fontmap.OS2
@@ -0,0 +1,215 @@
+% Copyright (C) 1990, 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% fontmap.os2 aka Fontmap.OS2 - OS/2 font catalog for Ghostscript.
+
+% ----------------------------------------------------------------
+
+% This file is a catalog of fonts known to Ghostscript. Any font
+% that is to be loaded automatically when named must be in this catalog,
+% except for fonts that Ghostscript finds automatically in directories
+% named in the GS_FONTPATH environment variable.
+
+% Each font has an entry consisting of three items:
+%
+% - The name by which the font is known inside Ghostscript
+% (a Ghostscript name preceded by a `/', or a string enclosed
+% in parentheses). This is used to find the file from which
+% a font of a given name should be loaded.
+%
+% - Information depending on whether this is a real font or a
+% font alias:
+%
+% - For real fonts, the name of the Ghostscript font
+% file (a Ghostscript string, enclosed in parentheses).
+% The filename should include the extension, which (by
+% convention) is `.gsf'. `.pfa' and `.pfb' files are
+% also usable as fonts for Ghostscript.
+%
+% - For font aliases, the name of the font which should
+% be used when this one is requested, preceded by a
+% `/'. See the entry for Charter below for an example.
+%
+% - A terminating semicolon.
+
+% Because of limitations in the MS-DOS environment, Ghostscript font
+% file names must be no more than 8 characters long, must consist only
+% of LOWER CASE letters, digits, and underscores, and must start with a
+% letter. Font names, on the other hand, need only obey the syntax of
+% names in the Ghostscript language, which is much more liberal.
+
+% Most of the Ghostscript fonts were created automatically from freely
+% available bitmaps. There is a makefile (fonts.mak) that specifies
+% how this conversion was done. fonts.mak also specifies, for each such
+% converted font, its uniqueID (an integer used to identify distinct fonts
+% within the Ghostscript font machinery), and its encoding (the mapping
+% from character codes in a string to character names). For more detailed
+% information, read fonts.mak.
+
+% The following table is actually a Ghostscript data structure.
+% If you add new entries, be sure to copy the punctuation accurately;
+% in particular, you must leave at least one space or tab between each
+% field in the entry. Also, please read fonts.doc for important information
+% about font names.
+
+
+%
+%
+% Fonts contributed by:
+% URW++ Design and Development Incorporated
+% Poppenbuetteler Bogen 29A
+% D-22399 Hamburg
+% Germany
+% tel. +49 (40) 60 60 50
+% fax +49 (40) 60 60 51 11
+% http://www.urwpp.de
+% for distribution under the GNU License and Aladdin Free Public License.
+% See the notice at the head of this Fontmap file for licensing terms.
+% Each of these fonts is individually covered by the license:
+% for licensing purposes, they are not "part of" any larger entity.
+% The following notice applies to these fonts:
+%
+% Copyright URW Software, Copyright 1994 by URW.
+%
+
+% Actual fonts
+
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+
+/NimbusMonL-Regu (n022003l.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+
+/URWGothicL-Book (a010013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+
+/NimbusSanL-Regu (n019003l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+
+/URWPalladioL-Roma (p052003l.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+
+/CenturySchL-Roma (c059013l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+
+/StandardSymL (s050000l.pfb) ;
+
+/URWChanceryL-MediItal (z003034l.pfb) ;
+
+/Dingbats (d050000l.pfb) ;
+
+% Aliases
+
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+
+/Courier /NimbusMonL-Regu ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+
+/Helvetica /NimbusSanL-Regu ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+
+/Palatino-Roman /URWPalladioL-Roma ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+
+/Times-Roman /NimbusRomNo9L-Regu ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+
+/Symbol /StandardSymL ;
+
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+
+/ZapfDingbats /Dingbats ;
+
+
+%
+% ATM fonts that come with OS/2.
+
+/Courier (cour.pfb) ;
+/Courier-Oblique /Courier-Italic ;
+/Courier-Italic (couri.pfb) ;
+/Courier-Bold (courb.pfb) ;
+/Courier-BoldOblique /Courier-BoldItalic ;
+/Courier-BoldItalic (courbi.pfb) ;
+
+/Helvetica (helv.pfb) ;
+/Helvetica-Oblique /Helvetica-Italic ;
+/Helvetica-Italic (helvi.pfb) ;
+/Helvetica-Bold (helvb.pfb) ;
+/Helvetica-BoldOblique /Helvetica-BoldItalic ;
+/Helvetica-BoldItalic (helvbi.pfb) ;
+
+/Symbol /SymbolSet ;
+/SymbolSet (symb.pfb) ;
+
+/Times-Roman /TimesNewRoman ;
+/TimesNewRoman (tnr.pfb) ;
+/Times-Italic /TimesNewRoman-Italic ;
+/TimesNewRoman-Italic (tnri.pfb) ;
+/Times-Bold /TimesNewRoman-Bold ;
+/TimesNewRoman-Bold (tnrb.pfb) ;
+/Times-BoldItalic /TimesNewRoman-BoldItalic ;
+/TimesNewRoman-BoldItalic (tnrbi.pfb) ;
+
+
diff --git a/gs/lib/Fontmap.OSF b/gs/lib/Fontmap.OSF
new file mode 100644
index 000000000..563f14a99
--- /dev/null
+++ b/gs/lib/Fontmap.OSF
@@ -0,0 +1,163 @@
+% fontmap.osf aka Fontmap.OSF1 - Ghostscript fontmap for DEC OSF/1 systems.
+%
+% UNIX systems from Digital Equipment Corporation are bundled with a license
+% for Display PostScript, including certain fonts. Using their font outlines
+% (which on OSF/1 systems are found in /usr/lib/X11/fonts/Type1Adobe)
+% improves the visual quality of documents displayed on screen. To do that,
+% use this file as your Fontmap file and add /usr/lib/X11/fonts/Type1Adobe
+% as the second argument to GS_LIB_DEFAULT in your makefile
+% in your makefile.
+%
+% This file is Pete Kaiser's original Ultrix file as modified by
+% Bjorn S. Nilsson (nilsson@nbi.dk) first for Ultrix 4.3 and then
+% for OSF/1 version 1.3.
+%
+
+%/AvantGarde-Book (AvantGarde-Book) ;
+%/AvantGarde-BookOblique (AvantGarde-BookOblique);
+%/AvantGarde-Demi (AvantGarde-Demi) ;
+%/AvantGarde-DemiOblique (AvantGarde-DemiOblique);
+
+%/Courier-BoldItalic /Courier-BoldOblique ;
+%/Courier-Italic /Courier-Oblique ;
+
+%/Courier (Courier) ;
+%/Courier-Bold (Courier-Bold) ;
+%/Courier-BoldOblique (Courier-BoldOblique) ;
+%/Courier-Oblique (Courier-Oblique) ;
+
+%/Helvetica (Helvetica) ;
+%/Helvetica-Bold (Helvetica-Bold) ;
+%/Helvetica-BoldOblique (Helvetica-BoldOblique) ;
+%/Helvetica-Oblique (Helvetica-Oblique) ;
+
+%/LubalinGraph-Book (LubalinGraph-Book) ;
+%/LubalinGraph-BookOblique (LubalinGraph-BookOblique);
+%/LubalinGraph-Demi (LubalinGraph-Demi) ;
+%/LubalinGraph-DemiOblique (LubalinGraph-DemiOblique);
+
+%/NewCenturySchlbk-Bold (NewCenturySchlbk-Bold) ;
+%/NewCenturySchlbk-BoldItalic (NewCenturySchlbk-BoldItalic);
+%/NewCenturySchlbk-Italic (NewCenturySchlbk-Italic);
+%/NewCenturySchlbk-Roman (NewCenturySchlbk-Roman);
+
+%/Souvenir-Demi (Souvenir-Demi) ;
+%/Souvenir-DemiItalic (Souvenir-DemiItalic) ;
+%/Souvenir-Light (Souvenir-Light) ;
+%/Souvenir-LightItalic (Souvenir-LightItalic) ;
+
+%/Symbol (Symbol) ;
+
+%/Times-Bold (Times-Bold) ;
+%/Times-BoldItalic (Times-BoldItalic) ;
+%/Times-Italic (Times-Italic) ;
+%/Times-Roman (Times-Roman) ;
+
+%/ZapfDingbats (ZapfDingbats) ;
+
+/AvantGarde-Book (AvantGarde-Book.pfa) ;
+/AvantGarde-BookOblique (AvantGarde-BookOblique.pfa) ;
+/AvantGarde-Demi (AvantGarde-Demi.pfa) ;
+/AvantGarde-DemiOblique (AvantGarde-DemiOblique.pfa) ;
+/Bookman-Demi (pbkd.gsf) ;
+/Bookman-DemiItalic (pbkdi.gsf) ;
+/Bookman-Light (pbkl.gsf) ;
+/Bookman-LightItalic (pbkli.gsf) ;
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+/CharterBT-Bold (bchb.gsf) ;
+/CharterBT-BoldItalic (bchbi.gsf) ;
+/CharterBT-Italic (bchri.gsf) ;
+/CharterBT-Roman (bchr.gsf) ;
+/Courier (Courier.pfa) ;
+/Courier-Bold (Courier-Bold.pfa) ;
+/Courier-BoldOblique (Courier-BoldOblique.pfa) ;
+/Courier-Oblique (Courier-Oblique.pfa) ;
+/Helvetica (Helvetica.pfa) ;
+/Helvetica-Bold (Helvetica-Bold.pfa) ;
+/Helvetica-BoldOblique (Helvetica-BoldOblique.pfa) ;
+/Helvetica-Oblique (Helvetica-Oblique.pfa) ;
+/Hershey-Gothic-English (hrger.gsf) ;
+/Hershey-Gothic-German (hrgrr.gsf) ;
+/Hershey-Gothic-Italian (hritr.gsf) ;
+/Hershey-Plain-Duplex (hrpld.gsf) ;
+/Hershey-Plain-Duplex-Italic (hrpldi.gsf) ;
+/Hershey-Plain-Triplex (hrplt.gsf) ;
+/Hershey-Plain-Triplex-Italic (hrplti.gsf) ;
+/Hershey-Script-Complex (hrscc.gsf) ;
+/Hershey-Script-Simplex (hrscs.gsf) ;
+/Hershey-Gothic-English-Bold (hrgerb.gsf) ;
+/Hershey-Gothic-English-Oblique (hrgero.gsf) ;
+/Hershey-Gothic-English-Semibold (hrgerd.gsf) ;
+/Hershey-Gothic-German-Bold (hrgrrb.gsf) ;
+/Hershey-Gothic-German-Oblique (hrgrro.gsf) ;
+/Hershey-Gothic-Italian-Bold (hritrb.gsf) ;
+/Hershey-Gothic-Italian-Oblique (hritro.gsf) ;
+/Hershey-Plain-Duplex-Bold (hrpldb.gsf) ;
+/Hershey-Plain-Duplex-Bold-Italic (hrpldbi.gsf) ;
+/Hershey-Plain-Triplex-Bold (hrpltb.gsf) ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpltbi.gsf) ;
+/Hershey-Script-Complex-Bold (hrsccb.gsf) ;
+/Hershey-Script-Complex-Oblique (hrscco.gsf) ;
+/Hershey-Script-Simplex-Bold (hrscsb.gsf) ;
+/Hershey-Script-Simplex-Oblique (hrscso.gsf) ;
+/Hershey-Greek-Complex (hrgkc.gsf) ;
+/Hershey-Greek-Simplex (hrgks.gsf) ;
+/Hershey-Plain (hrplr.gsf) ;
+/Hershey-Plain-Simplex (hrpls.gsf) ;
+/Hershey-Plain-Bold (hrplrb.gsf) ;
+/Hershey-Plain-Bold-Oblique (hrplrbo.gsf) ;
+/Hershey-Plain-Oblique (hrplro.gsf) ;
+/Hershey-Plain-Simplex-Bold (hrplsb.gsf) ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrplsbo.gsf) ;
+/Hershey-Plain-Simplex-Oblique (hrplso.gsf) ;
+/Hershey-Symbol (hrsy_r.gsf) ;
+/LubalinGraph-Book (LubalinGraph-Book.pfa) ;
+/LubalinGraph-BookOblique (LubalinGraph-BookOblique.pfa) ;
+/LubalinGraph-Demi (LubalinGraph-Demi.pfa) ;
+/LubalinGraph-DemiOblique (LubalinGraph-DemiOblique.pfa) ;
+/NewCenturySchlbk-Bold (NewCenturySchlbk-Bold.pfa) ;
+/NewCenturySchlbk-BoldItalic (NewCenturySchlbk-BoldItalic.pfa) ;
+/NewCenturySchlbk-Italic (NewCenturySchlbk-Italic.pfa) ;
+/NewCenturySchlbk-Roman (NewCenturySchlbk-Roman.pfa) ;
+/NimbusRomanNo9L-Regular (n021003l.gsf) ;
+/NimbusSansL-Regular (n019003l.gsf) ;
+/Palatino-Bold (pplb.gsf) ;
+/Palatino-BoldItalic (pplbi.gsf) ;
+/Palatino-Italic (pplri.gsf) ;
+/Palatino-Roman (pplr.gsf) ;
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+/Souvenir-Demi (Souvenir-Demi.pfa) ;
+/Souvenir-DemiItalic (Souvenir-DemiItalic.pfa) ;
+/Souvenir-Light (Souvenir-Light.pfa) ;
+/Souvenir-LightItalic (Souvenir-LightItalic.pfa) ;
+/Symbol (Symbol.pfa) ;
+/Times-Bold (Times-Bold.pfa) ;
+/Times-BoldItalic (Times-BoldItalic.pfa) ;
+/Times-Italic (Times-Italic.pfa) ;
+/Times-Roman (Times-Roman.pfa) ;
+/URWAntiquaT-RegularCondensed (u003043t.gsf) ;
+/URWGroteskT-Bold (u004006t.gsf) ;
+/Utopia-Bold (putb.gsf) ;
+/Utopia-BoldItalic (putbi.gsf) ;
+/Utopia-Italic (putri.gsf) ;
+/Utopia-Regular (putr.gsf) ;
+/ZapfChancery (zcr.gsf) ;
+/ZapfChancery-Bold (zcb.gsf) ;
+/ZapfChancery-Oblique (zcro.gsf) ;
+/ZapfDingbats (ZapfDingbats.pfa) ;
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+% BSN additions from original Fontmap file and some more aliases
+
+/Helvetica-Narrow-Bold /Helvetica-Narrow ;
+/ZapfChancery-MediumItalic /ZapfChancery-Oblique ;
+/Charter-Roman /CharterBT-Roman ;
+/Charter-Italic /CharterBT-Italic ;
+/Charter-Bold /CharterBT-Bold ;
+/Charter-BoldItalic /CharterBT-BoldItalic ;
+/Courier-Italic /Courier-Oblique ;
+/Courier-BoldItalic /Courier-BoldOblique ;
diff --git a/gs/lib/Fontmap.Sol b/gs/lib/Fontmap.Sol
new file mode 100644
index 000000000..9f34460a0
--- /dev/null
+++ b/gs/lib/Fontmap.Sol
@@ -0,0 +1,482 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Fontmap.Solaris - Ghostscript Fontmap for Solaris 2.3 and above
+% ===============================================================
+%
+% The Solaris 2.3 (and above) operating system from Sun Microsystems comes with
+% Display Postscript (DPS), including certain Type1 and Type3 PostScript fonts.
+% Using these fonts instead of the default Ghostscript fonts greatly improves
+% the visual quality of Ghostscript rendered documents, especially at larger
+% font sizes. You should definately use these fonts if you have Solaris 2.3 or
+% above.
+%
+% To use the Solaris 2 DPS fonts, simply copy this file (Fontmap.Solaris) to
+%
+% /usr/local/lib/Ghostscript/VERSION/Fontmap
+% (where VERSION is the version number of Ghostscript, eg: 3.33)
+%
+% and set the environment variable GS_LIB as follows:
+%
+% GS_LIB=/usr/openwin/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/Type3
+% export GS_LIB
+%
+% You can use /usr/openwin/lib/fonts/Type1/outline instead if you like, it
+% makes no difference (the files in /usr/openwin/lib/fonts/Type1 are symlinks
+% into /usr/openwin/lib/fonts/Type1/outline).
+%
+% Instead of setting GS_LIB, you could add the above directories to
+% GS_LIB_DEFAULT in your makefile before building Ghostscript.
+%
+%
+% IMPORTANT NOTE
+% ==============
+%
+% Note that simply setting GS_FONTPATH may not work, because for some reason
+% some versions of gs can't seem to find any fonts in
+% /usr/openwin/lib/X11/fonts/Type1/outline.
+% It says: "15 files, 15 scanned, 0 new fonts".
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% ----------------------------------------------------------------
+
+% This file is a catalog of fonts known to Ghostscript. Any font
+% that is to be loaded automatically when named must be in this catalog,
+% except for fonts that Ghostscript finds automatically in directories
+% named in the GS_FONTPATH environment variable.
+
+% Each font has an entry consisting of three items:
+%
+% - The name by which the font is known inside Ghostscript
+% (a Ghostscript name preceded by a `/', or a string enclosed
+% in parentheses). This is used to find the file from which
+% a font of a given name should be loaded.
+%
+% - Information depending on whether this is a real font or a
+% font alias:
+%
+% - For real fonts, the name of the Ghostscript font
+% file (a Ghostscript string, enclosed in parentheses).
+% The filename should include the extension, which (by
+% convention) is `.gsf'. `.pfa' and `.pfb' files are
+% also usable as fonts for Ghostscript.
+%
+% - For font aliases, the name of the font which should
+% be used when this one is requested, preceded by a
+% `/'. See the entry for Charter below for an example.
+% Note that an alias name cannot be enclosed in parentheses.
+%
+% - At least one space or tab, and a terminating semicolon.
+
+% Because of limitations in the MS-DOS environment, Ghostscript font
+% file names must be no more than 8 characters long, must consist only
+% of LOWER CASE letters, digits, and underscores, and must start with a
+% letter. Font names, on the other hand, need only obey the syntax of
+% names in the Ghostscript language, which is much more liberal.
+
+% The following table is actually a Ghostscript data structure.
+% If you add new entries, be sure to copy the punctuation accurately;
+% in particular, you must leave at least one space or tab between each
+% field in the entry. Also, please read fonts.doc for important information
+% about font names.
+
+% Note that .pfa and .pfb fonts are compatible with Adobe Type Manager
+% and other programs that don't include full PostScript interpreters,
+% as well as with PostScript interpreters; .gsf fonts are compatible with
+% PostScript interpreters, but not with ATM or similar programs.
+
+%
+%
+% Fonts contributed by:
+% URW++ Design and Development Incorporated
+% Poppenbuetteler Bogen 29A
+% D-22399 Hamburg
+% Germany
+% tel. +49 (40) 60 60 50
+% fax +49 (40) 60 60 51 11
+% http://www.urwpp.de
+% for distribution under the GNU License and Aladdin Free Public License.
+% See the notice at the head of this Fontmap file for licensing terms.
+% Each of these fonts is individually covered by the license:
+% for licensing purposes, they are not "part of" any larger entity.
+% The following notice applies to these fonts:
+%
+% Copyright URW Software, Copyright 1994 by URW.
+%
+
+% Actual fonts
+
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+
+/NimbusMonL-Regu (n022003l.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+
+/URWGothicL-Book (a010013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+
+/NimbusSanL-Regu (n019003l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+
+/URWPalladioL-Roma (p052003l.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+
+/CenturySchL-Roma (c059013l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+
+/StandardSymL (s050000l.pfb) ;
+
+/URWChanceryL-MediItal (z003034l.pfb) ;
+
+/Dingbats (d050000l.pfb) ;
+
+% Aliases
+
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+
+/Courier /NimbusMonL-Regu ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+
+% Solaris 2 DPS has Helvetica as a Type1 font.
+%/Helvetica /NimbusSanL-Regu ;
+%/Helvetica-Oblique /NimbusSanL-ReguItal ;
+%/Helvetica-Bold /NimbusSanL-Bold ;
+%/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+
+/Palatino-Roman /URWPalladioL-Roma ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+
+% Solaris 2 DPS has Times as a Type1 font.
+%/Times-Roman /NimbusRomNo9L-Regu ;
+%/Times-Italic /NimbusRomNo9L-ReguItal ;
+%/Times-Bold /NimbusRomNo9L-Medi ;
+%/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+
+% Solaris 2 DPS has Symbol as a Type1 font.
+%/Symbol /StandardSymL ;
+
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+
+/ZapfDingbats /Dingbats ;
+
+%
+%
+% Type 1 fonts contributed to the X11R5 distribution.
+%
+
+% The following notice accompanied the Charter fonts.
+%
+% (c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA.
+%
+% You are hereby granted permission under all Bitstream propriety rights
+% to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream
+% Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts
+% for any purpose and without restriction; provided, that this notice is
+% left intact on all copies of such fonts and that Bitstream's trademark
+% is acknowledged as shown below on all unmodified copies of the 4 Charter
+% Type 1 fonts.
+%
+% BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
+
+% The Bitstream Charter fonts have different names (CharterBT-
+% instead of Charter-), but Ghostscript doesn't care.
+/Charter-Roman (bchr.pfa) ;
+/Charter-Italic (bchri.pfa) ;
+/Charter-Bold (bchb.pfa) ;
+/Charter-BoldItalic (bchbi.pfa) ;
+
+% The following notice accompanied the Utopia font:
+%
+% Permission to use, reproduce, display and distribute the listed
+% typefaces is hereby granted, provided that the Adobe Copyright notice
+% appears in all whole and partial copies of the software and that the
+% following trademark symbol and attribution appear in all unmodified
+% copies of the software:
+%
+% Copyright (c) 1989 Adobe Systems Incorporated
+% Utopia (R)
+% Utopia is a registered trademark of Adobe Systems Incorporated
+%
+% The Adobe typefaces (Type 1 font program, bitmaps and Adobe Font
+% Metric files) donated are:
+%
+% Utopia Regular
+% Utopia Italic
+% Utopia Bold
+% Utopia Bold Italic
+
+/Utopia-Regular (putr.pfa) ;
+/Utopia-Italic (putri.pfa) ;
+/Utopia-Bold (putb.pfa) ;
+/Utopia-BoldItalic (putbi.pfa) ;
+
+%
+%
+% Fonts contributed by URW GmbH for distribution under the GNU License.
+% The following notice accompanied these fonts:
+%
+% U004006T URW Grotesk 2031 Bold PostScript Type 1 Font Program
+% U003043T URW Antiqua 2051 Regular Condensed PostScript Type 1 Font Program
+%
+% Copyright (c) 1992 URW GmbH, Hamburg, Germany
+%
+% 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) later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; wihtout 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.
+%
+% Address:
+% URW GmbH
+% PC Support
+% Harksheider Strasse 102
+% 2000 Hamburg 65
+% Germany
+% Phone: +49 40 60 60 50 (Reception)
+% Phone: +49 40 60 60 52 30 (PC Support)
+% Fax : +49 40 60 60 52 52
+%
+
+/URWAntiquaT-RegularCondensed (u003043t.gsf) ;
+/URWGroteskT-Bold (u004006t.gsf) ;
+
+%
+%
+% Shareware Kana fonts. These are subject to the following notice:
+%
+% These copyrighted fonts were developed by Kevin Hartig. Permission is
+% granted to freely distribute them in entirety along with this statement.
+% This is shareware. If you decide to use these fonts please contribute
+% $10 US to help support further freeware and shareware software development.
+% Questions and comments may be sent to:
+%
+% hartig@fsl.noaa.gov
+% khartig@nyx.cs.du.edu
+%
+% Kevin Hartig
+% 1126 Collyer Street
+% Longmont, CO 80501 USA
+%
+% copyright 1993.
+
+% Hiragana and Katakana fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+
+%
+%
+% Public-domain fonts. These have no copyright, and are of unknown quality.
+
+% Cyrillic fonts. The character names are inappropriate,
+% and the encoding is probably not related to any known standard.
+
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+
+% Aliases
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+%
+%
+% Fonts converted from Hershey outlines. These are constructed and
+% maintained manually. These are also in the public domain.
+%
+% The suggested UniqueID's and filenames are constructed differently for
+% these than for the ones above, because of the strange way that the Hershey
+% fonts were constructed. The scheme for these looks like:
+%
+% 42TTXY0
+%
+% TT = typeface, X = ``class'', Y = variation
+%
+% The typeface names and numbers are listed in fonts.mak.
+%
+% class:
+% 0 = normal = r
+% 1 = simplex = s
+% 2 = complex = c
+% 3 = triplex = t
+% 4 = duplex = d
+%
+% variation:
+% 0 = normal (omitted)
+% 1 = oblique = o
+% 2 = italic = i
+% 3 = bold = b
+% 4 = bold oblique = bo
+% 5 = bold italic = bi
+%
+
+% Fonts created by Thomas Wolff <wolff@inf.fu-berlin.de>, by adding
+% accents, accented characters, and various other non-alphabetics
+% to the original Hershey fonts. These are "freeware", not to be sold.
+
+/Hershey-Gothic-English (hrger.pfa) ; % 5066533
+/Hershey-Gothic-German (hrgrr.pfa) ;
+/Hershey-Gothic-Italian (hritr.pfa) ;
+
+/Hershey-Plain-Duplex (hrpld.pfa) ;
+/Hershey-Plain-Duplex-Italic (hrpldi.pfa) ;
+/Hershey-Plain-Triplex (hrplt.pfa) ;
+/Hershey-Plain-Triplex-Italic (hrplti.pfa) ;
+
+/Hershey-Script-Complex (hrscc.pfa) ;
+/Hershey-Script-Simplex (hrscs.pfa) ; % 5066541
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Gothic-English-Bold (hrgerb.gsf) ; % 5066542
+/Hershey-Gothic-English-Oblique (hrgero.gsf) ;
+/Hershey-Gothic-English-SemiBold (hrgerd.gsf) ;
+/Hershey-Gothic-German-Bold (hrgrrb.gsf) ;
+/Hershey-Gothic-German-Oblique (hrgrro.gsf) ;
+/Hershey-Gothic-Italian-Bold (hritrb.gsf) ;
+/Hershey-Gothic-Italian-Oblique (hritro.gsf) ;
+
+/Hershey-Plain-Duplex-Bold (hrpldb.gsf) ;
+/Hershey-Plain-Duplex-Bold-Italic (hrpldbi.gsf) ;
+/Hershey-Plain-Triplex-Bold (hrpltb.gsf) ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpltbi.gsf) ;
+
+/Hershey-Script-Complex-Bold (hrsccb.gsf) ;
+/Hershey-Script-Complex-Oblique (hrscco.gsf) ;
+/Hershey-Script-Simplex-Bold (hrscsb.gsf) ;
+/Hershey-Script-Simplex-Oblique (hrscso.gsf) ; % 5066556
+
+% Fonts consisting only of characters from the original Hershey
+% distribution. These are Type 3 fonts.
+
+/Hershey-Greek-Complex (hrgkc.gsf) ; % 5066557
+/Hershey-Greek-Simplex (hrgks.gsf) ;
+
+/Hershey-Plain (hrplr.gsf) ;
+/Hershey-Plain-Simplex (hrpls.gsf) ; % 5066560
+
+% Fonts created algorithmically from the above.
+
+/Hershey-Plain-Bold (hrplrb.gsf) ; % 5066561
+/Hershey-Plain-Bold-Oblique (hrplrbo.gsf) ;
+/Hershey-Plain-Oblique (hrplro.gsf) ;
+/Hershey-Plain-Simplex-Bold (hrplsb.gsf) ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrplsbo.gsf) ;
+/Hershey-Plain-Simplex-Oblique (hrplso.gsf) ; % 5066566
+
+% This font, and only this font among the Hershey fonts, uses
+% the SymbolEncoding.
+
+/Hershey-Symbol (hrsyr.gsf) ; % 5066567
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Solaris 2 Display PostScript Type1 and Type3 fonts...
+%
+
+/Helvetica (Helvetica.pfa) ;
+/Helvetica-Bold (Helvetica-Bold.pfa) ;
+/Helvetica-BoldOblique (Helvetica-BoldOblique.pfa) ;
+/Helvetica-Oblique (Helvetica-Oblique.pfa) ;
+
+/Symbol (Symbol.pfa) ;
+/SymbolSet /Symbol ;
+
+/Times-Bold (Times-Bold.pfa) ;
+/Times-BoldItalic (Times-BoldItalic.pfa) ;
+/Times-Italic (Times-Italic.pfa) ;
+/Times-Roman (Times-Roman.pfa) ;
+/TimesNewRoman /Times-Roman ;
+/TimesNewRoman-Bold /Times-Bold ;
+/TimesNewRoman-BoldItalic /Times-BoldItalic ;
+/TimesNewRoman-Italic /Times-Italic ;
+
+/Dijkstra (Dijkstra.ps) ;
+
+/Hershey-Cyrillic (HrshCyr.ps) ;
+
+/Hershey-Gothic (HrshGoth.ps) ;
+
+/Hershey-Greek (HrshGrk.ps) ;
+/Hershey-Greek-Narrow (HrshGrkN.ps) ;
+/Hershey-Greekp (HrshGrkp.ps) ;
+
+/Hershey-Italic (HrshI.ps) ;
+/Hershey-Italic-Narrow (HrshIN.ps) ;
+/Hershey-Italic-Wide (HrshIW.ps) ;
+/Hershey-Roman (HrshRom.ps) ;
+/Hershey-Roman-Narrow (HrshRomN.ps) ;
+/Hershey-Roman-Wide (HrshRomW.ps) ;
+/Hershey-Romand (HrshRomd.ps) ;
+/Hershey-Romanp (HrshRomp.ps) ;
+
+/Hershey-Script (HrshScr.ps) ;
+/Hershey-Script-Narrow (HrshScrN.ps) ;
diff --git a/gs/lib/Fontmap.Ult b/gs/lib/Fontmap.Ult
new file mode 100644
index 000000000..00aa778e9
--- /dev/null
+++ b/gs/lib/Fontmap.Ult
@@ -0,0 +1,143 @@
+% Copyright (C) 1990, 1995 Aladdin Enterprises. All rights reserved.
+%
+% Fontmap.Ult
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+%
+% Fontmap.Ult is derived from the standard Fontmap file distributed with
+% ghostscript; for credits and sources see that file. The modifications here
+% are valid for ULTRIX 4.3, and consist of defining some fonts and font
+% aliases as the licensed fontfiles included in ULTRIX for use on ULTRIX
+% workstations, which give better quality than the free fontfiles available
+% for ghostscript. Under ULTRIX 4.3 the licensed fontfiles are found in
+%
+% /usr/lib/DPS/outline/decwin
+%
+% so that directory must either be built into ghostscript by redefining
+% GS_LIB_DEFAULT when ghostscript is compiled, or else by defining an
+% environmental variable GS_LIB_DEFAULT, which contains it as an element of
+% the path, when running ghostscript. For instance, under the KornShell
+%
+% GS_LIB_DEFAULT=/usr/gs:/usr/lib/DPS/outline/decwin:/usr/gs/fonts
+% export GS_LIB_DEFAULT
+%
+% Peter Kaiser (kaiser@acm.org) 27 January 1995
+
+/AvantGarde-Book (AvantGarde-Book) ;
+/AvantGarde-BookOblique (AvantGarde-BookOblique) ;
+/AvantGarde-Demi (AvantGarde-Demi) ;
+/AvantGarde-DemiOblique (AvantGarde-DemiOblique) ;
+/Courier (Courier) ;
+/Courier-Bold (Courier-Bold) ;
+/Courier-BoldOblique (Courier-BoldOblique) ;
+/Courier-Oblique (Courier-Oblique) ;
+/Helvetica (Helvetica) ;
+/Helvetica-Bold (Helvetica-Bold) ;
+/Helvetica-BoldOblique (Helvetica-BoldOblique) ;
+/Helvetica-Oblique (Helvetica-Oblique) ;
+/LubalinGraph-Book (LubalinGraph-Book) ;
+/LubalinGraph-BookOblique (LubalinGraph-BookOblique) ;
+/LubalinGraph-Demi (LubalinGraph-Demi) ;
+/LubalinGraph-DemiOblique (LubalinGraph-DemiOblique) ;
+/NewCenturySchlbk-Bold (NewCenturySchlbk-Bold) ;
+/NewCenturySchlbk-BoldItalic (NewCenturySchlbk-BoldItalic) ;
+/NewCenturySchlbk-Italic (NewCenturySchlbk-Italic) ;
+/NewCenturySchlbk-Roman (NewCenturySchlbk-Roman) ;
+/Souvenir-Demi (Souvenir-Demi) ;
+/Souvenir-DemiItalic (Souvenir-DemiItalic) ;
+/Souvenir-Light (Souvenir-Light) ;
+/Souvenir-LightItalic (Souvenir-LightItalic) ;
+/Symbol (Symbol) ;
+/Times-Bold (Times-Bold) ;
+/Times-BoldItalic (Times-BoldItalic) ;
+/Times-Italic (Times-Italic) ;
+/Times-Roman (Times-Roman) ;
+
+% Fonts distributed as part of ghostscript
+
+/Bookman-Demi (pbkd.gsf) ;
+/Bookman-DemiItalic (pbkdi.gsf) ;
+/Bookman-Light (pbkl.gsf) ;
+/Bookman-LightItalic (pbkli.gsf) ;
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
+/Charter-Bold (bchb.pfa) ;
+/Charter-BoldItalic (bchbi.pfa) ;
+/Charter-Italic (bchri.pfa) ;
+/Charter-Roman (bchr.pfa) ;
+/Hershey-Gothic-English (hrger.pfa) ;
+/Hershey-Gothic-English-Bold (hrgerb.gsf) ;
+/Hershey-Gothic-English-Oblique (hrgero.gsf) ;
+/Hershey-Gothic-English-SemiBold (hrgerd.gsf) ;
+/Hershey-Gothic-German (hrgrr.pfa) ;
+/Hershey-Gothic-German-Bold (hrgrrb.gsf) ;
+/Hershey-Gothic-German-Oblique (hrgrro.gsf) ;
+/Hershey-Gothic-Italian (hritr.pfa) ;
+/Hershey-Gothic-Italian-Bold (hritrb.gsf) ;
+/Hershey-Gothic-Italian-Oblique (hritro.gsf) ;
+/Hershey-Greek-Complex (hrgkc.gsf) ;
+/Hershey-Greek-Simplex (hrgks.gsf) ;
+/Hershey-Plain (hrplr.gsf) ;
+/Hershey-Plain-Bold (hrplrb.gsf) ;
+/Hershey-Plain-Bold-Oblique (hrplrbo.gsf) ;
+/Hershey-Plain-Duplex (hrpld.pfa) ;
+/Hershey-Plain-Duplex-Bold (hrpldb.gsf) ;
+/Hershey-Plain-Duplex-Bold-Italic (hrpldbi.gsf) ;
+/Hershey-Plain-Duplex-Italic (hrpldi.pfa) ;
+/Hershey-Plain-Oblique (hrplro.gsf) ;
+/Hershey-Plain-Simplex (hrpls.gsf) ;
+/Hershey-Plain-Simplex-Bold (hrplsb.gsf) ;
+/Hershey-Plain-Simplex-Bold-Oblique (hrplsbo.gsf) ;
+/Hershey-Plain-Simplex-Oblique (hrplso.gsf) ;
+/Hershey-Plain-Triplex (hrplt.pfa) ;
+/Hershey-Plain-Triplex-Bold (hrpltb.gsf) ;
+/Hershey-Plain-Triplex-Bold-Italic (hrpltbi.gsf) ;
+/Hershey-Plain-Triplex-Italic (hrplti.pfa) ;
+/Hershey-Script-Complex (hrscc.pfa) ;
+/Hershey-Script-Complex-Bold (hrsccb.gsf) ;
+/Hershey-Script-Complex-Oblique (hrscco.gsf) ;
+/Hershey-Script-Simplex (hrscs.pfa) ;
+/Hershey-Script-Simplex-Bold (hrscsb.gsf) ;
+/Hershey-Script-Simplex-Oblique (hrscso.gsf) ;
+/Hershey-Symbol (hrsyr.gsf) ;
+/NimbusRomanNo9L-Regular (n021003l.gsf) ;
+/NimbusSansL-Regular (n019003l.gsf) ;
+/Palatino-Bold (pplb.gsf) ;
+/Palatino-BoldItalic (pplbi.gsf) ;
+/Palatino-Italic (pplri.gsf) ;
+/Palatino-Roman (pplr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/URWAntiquaT-RegularCondensed (u003043t.gsf) ;
+/URWGroteskT-Bold (u004006t.gsf) ;
+/Utopia-Bold (putb.pfa) ;
+/Utopia-BoldItalic (putbi.pfa) ;
+/Utopia-Italic (putri.pfa) ;
+/Utopia-Regular (putr.pfa) ;
+/ZapfChancery (zcr.gsf) ;
+/ZapfChancery-Bold (zcb.gsf) ;
+/ZapfChancery-Oblique (zcro.gsf) ;
+/ZapfDingbats (pzdr.gsf) ;
+
+% Font aliases
+
+/Courier-BoldItalic /Courier-BoldOblique ;
+/Courier-Italic /Courier-Oblique ;
+/Cyrillic /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Helvetica-Narrow-Bold /Helvetica-Narrow ;
+/ZapfChancery-MediumItalic /ZapfChancery-Oblique ;
diff --git a/gs/lib/Fontmap.VMS b/gs/lib/Fontmap.VMS
new file mode 100644
index 000000000..4348b104b
--- /dev/null
+++ b/gs/lib/Fontmap.VMS
@@ -0,0 +1,120 @@
+% fontmap.vms - Ghostscript fontmap for VAX/VMS systems with DECwindows/Motif.
+%
+%Uses all the XDPS Outline fonts (Type 1 fonts) provided with Motif (with the
+%exception of Courier which already comes with GhostScript in Type 1 form).
+%
+%XDPS on VAX/VMS does not have Bookman, Palatino and ZapfChancery fonts, so
+%we still have to use the dreaded bitmaps for those. Helvetica-Narrow is also
+%missing. But then you get the LubalinGraph and Souvenir fonts which are just
+%beautiful!
+%
+%Note: this file omits the Hershey fonts (Hershey ?? YOU MUST BE JOKING)
+% but retains the Cyrillic and Kana fonts.
+
+/AvantGarde-Book
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]AVANTGARDE-BOOK.XDPS$OUTLINE) ;
+/AvantGarde-BookOblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]AVANTGARDE-BOOKOBLIQUE.XDPS$OUTLINE) ;
+/AvantGarde-Demi
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]AVANTGARDE-DEMI.XDPS$OUTLINE) ;
+/AvantGarde-DemiOblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]AVANTGARDE-DEMIOBLIQUE.XDPS$OUTLINE) ;
+/Helvetica-Bold
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]HELVETICA-BOLD.XDPS$OUTLINE) ;
+/Helvetica-BoldOblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]HELVETICA-BOLDOBLIQUE.XDPS$OUTLINE) ;
+/Helvetica-Oblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]HELVETICA-OBLIQUE.XDPS$OUTLINE) ;
+/Helvetica
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]HELVETICA.XDPS$OUTLINE) ;
+/LubalinGraph-Book
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]LUBALINGRAPH-BOOK.XDPS$OUTLINE) ;
+/LubalinGraph-BookOblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]LUBALINGRAPH-BOOKOBLIQUE.XDPS$OUTLINE) ;
+/LubalinGraph-Demi
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]LUBALINGRAPH-DEMI.XDPS$OUTLINE) ;
+/LubalinGraph-DemiOblique
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]LUBALINGRAPH-DEMIOBLIQUE.XDPS$OUTLINE) ;
+/NewCenturySchlbk-Roman
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]NEWCENTURYSCHLBK-ROMAN.XDPS$OUTLINE) ;
+/NewCenturySchlbk-Italic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]NEWCENTURYSCHLBK-ITALIC.XDPS$OUTLINE) ;
+/NewCenturySchlbk-Bold
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]NEWCENTURYSCHLBK-BOLD.XDPS$OUTLINE) ;
+/NewCenturySchlbk-BoldItalic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]NEWCENTURYSCHLBK-BOLDITALIC.XDPS$OUTLINE) ;
+/Souvenir-Light
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]SOUVENIR-LIGHT.XDPS$OUTLINE) ;
+/Souvenir-LightItalic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]SOUVENIR-LIGHTITALIC.XDPS$OUTLINE) ;
+/Souvenir-Demi
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]SOUVENIR-DEMI.XDPS$OUTLINE) ;
+/Souvenir-DemiItalic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]SOUVENIR-DEMIITALIC.XDPS$OUTLINE) ;
+%If you want the Apple symbol (SIC!) then remove the comment (%)
+%in front of character 240 in the following file (he he he)
+/Symbol
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]SYMBOL.XDPS$OUTLINE) ;
+/Times-Roman
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]TIMES-ROMAN.XDPS$OUTLINE) ;
+/Times-Italic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]TIMES-ITALIC.XDPS$OUTLINE) ;
+/Times-Bold
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]TIMES-BOLD.XDPS$OUTLINE) ;
+/Times-BoldItalic
+ (SYS$COMMON:[SYSFONT.XDPS.OUTLINE]TIMES-BOLDITALIC.XDPS$OUTLINE) ;
+
+% Fonts converted from bitmaps (Not in the XDPS set)
+/Bookman-Light (pbkl.gsf) ;
+/Bookman-LightItalic (pbkli.gsf) ;
+/Bookman-Demi (pbkd.gsf) ;
+/Bookman-DemiItalic (pbkdi.gsf) ;
+/Palatino-Roman (pplr.gsf) ;
+/Palatino-Italic (pplri.gsf) ;
+/Palatino-Bold (pplb.gsf) ;
+/Palatino-BoldItalic (pplbi.gsf) ;
+/ZapfChancery (zcr.gsf) ;
+/ZapfChancery-Oblique (zcro.gsf) ;
+/ZapfChancery-Bold (zcb.gsf) ;
+%MediumItalic font to Oblique aliasing
+/ZapfChancery-MediumItalic /ZapfChancery-Oblique ;
+/ZapfDingbats (pzdr.gsf) ;
+
+% BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
+/CharterBT-Roman (bchr.pfa) ;
+/CharterBT-Italic (bchri.pfa) ;
+/CharterBT-Bold (bchb.pfa) ;
+/CharterBT-BoldItalic (bchbi.pfa) ;
+%Charter to CharterBT aliasing
+/Charter-Roman /CharterBT-Roman ;
+/Charter-Italic /CharterBT-Italic ;
+/Charter-Bold /CharterBT-Bold ;
+/Charter-BoldItalic /CharterBT-BoldItalic ;
+
+% IBM Courier - Copyright (c) IBM Corporation 1990, 1991
+/Courier (ncrr.pfa) ;
+/Courier-Italic (ncrri.pfa) ;
+/Courier-Bold (ncrb.pfa) ;
+/Courier-BoldItalic (ncrbi.pfa) ;
+%Oblique to Italic aliasing
+/Courier-Oblique /Courier-Italic ;
+/Courier-BoldOblique /Courier-BoldItalic ;
+
+% Utopia is a registered trademark of Adobe Systems Incorporated
+/Utopia-Regular (putr.gsf) ;
+/Utopia-Italic (putri.gsf) ;
+/Utopia-Bold (putb.gsf) ;
+/Utopia-BoldItalic (putbi.gsf) ;
+
+% Shareware fonts. These have no copyright, and are of unknown quality.
+/Shareware-Cyrillic-Regular (fcyr.gsf) ;
+/Shareware-Cyrillic-Italic (fcyri.gsf) ;
+% Aliases
+/Cyrillic /Cyrillic-Regular ;
+/Cyrillic-Regular /Shareware-Cyrillic-Regular ;
+/Cyrillic-Italic /Shareware-Cyrillic-Italic ;
+
+% Copyrighted shareware fonts.
+% See FONTMAP.GS for the full copyright statement.
+/Calligraphic-Hiragana (fhirw.gsf) ;
+/Calligraphic-Katakana (fkarw.gsf) ;
diff --git a/gs/lib/_vc_make.bat b/gs/lib/_vc_make.bat
new file mode 100755
index 000000000..e80bd028f
--- /dev/null
+++ b/gs/lib/_vc_make.bat
@@ -0,0 +1,5 @@
+cd ..\gs
+c:\progra~1\devstudio\VC\bin\nmake /F _vc_temp.mak CONFIG=5 gsargs.obj gsnogc.obj echogs.exe
+c:\progra~1\devstudio\VC\bin\nmake /F _vc_temp.mak CONFIG=5 ld5.tr gconfig5.obj gscdefs5.obj
+..\gs\echogs.exe -w _wm_cdir.bat cd -s -r _vc_dir.bat
+_wm_cdir.bat
diff --git a/gs/lib/_wm_cdir.bat b/gs/lib/_wm_cdir.bat
new file mode 100755
index 000000000..6cc2625dd
--- /dev/null
+++ b/gs/lib/_wm_cdir.bat
@@ -0,0 +1 @@
+cd \ No newline at end of file
diff --git a/gs/lib/acctest.ps b/gs/lib/acctest.ps
new file mode 100644
index 000000000..b1c5e9dca
--- /dev/null
+++ b/gs/lib/acctest.ps
@@ -0,0 +1,99 @@
+%!
+% Check that operators do their access tests correctly.
+
+% proc dotest => .
+/dotest
+ {
+ dup
+ mark
+ exch
+ stopped not % False if error, true if no error.
+ { (Allowed access: ) print cleartomark == }
+ if
+ clear
+ }
+def
+
+0 0 moveto % So the show commands don't bomb because of nocurrentpoint.
+
+{ [1 2] executeonly aload } dotest
+{ (string) executeonly (seek) anchorsearch } dotest
+{ (string) (seek) executeonly anchorsearch } dotest
+{ 100 101 (string) noaccess ashow} dotest
+{ 100 1 array readonly astore } dotest
+{ 100 101 102 103 104 (string) noaccess awidthshow } dotest
+{ 1 dict noacess begin } dotest
+{ 1 array executeonly 1 array copy } dotest
+{ 1 array 1 array readonly copy } dotest
+{ 1 dict noaccess 1 dict copy } dotest
+{ 1 dict 1 dict readonly copy } dotest
+{ 1 string executeonly 1 string copy } dotest
+{ 1 string 1 string readonly copy } dotest
+{ (100) executeonly cvi } dotest
+{ (string) executeonly cvn } dotest
+{ (100.001) executeonly cvr } dotest
+{ 1 10 1 string readonly cvrs } dotest
+{ true 5 string readonly cvs } dotest
+{ 1 dict readonly begin /foo true def } dotest
+{ 10 array readonly dictstack } dotest
+{ 1 string executeonly 1 string eq } dotest
+{ 1 string 1 string executeonly eq } dotest
+{ 10 array readonly execstack } dotest
+{ 1 string noaccess executeonly } dotest
+{ 1 array noaccess executeonly } dotest
+{ 1 array executeonly { pop } forall } dotest
+{ 1 dict noaccess { pop pop } forall } dotest
+{ 1 string executeonly { pop } forall } dotest
+{ (string1) executeonly (string2) ge } dotest
+{ (string1) (string2) executeonly ge } dotest
+{ 1 array executeonly 0 get } dotest
+{ 1 dict noaccess /key get } dotest
+{ 1 string executeonly 0 get } dotest
+{ 1 array executeonly 0 1 getinterval } dotest
+{ 1 string executeonly 0 1 getinterval } dotest
+{ (string1) executeonly (string2) gt } dotest
+{ (string1) (string2) executeonly gt } dotest
+{ 1 dict noaccess /key known } dotest
+{ {} (string) executeonly kshow } dotest
+{ (string1) executeonly (string2) le } dotest
+{ (string1) (string2) executeonly le } dotest
+{ 1 array executeonly length } dotest
+{ 1 dict noaccess length } dotest
+{ 1 string executeonly length } dotest
+%%{ /foo 1 dict def foo begin /bar foo def bar noaccess pop /key load } dotest
+{ (string1) executeonly (string2) lt } dotest
+{ (string1) (string2) executeonly lt } dotest
+{ 1 dict noaccess maxlength } dotest
+{ 1 string executeonly 1 string ne } dotest
+{ 1 string 1 string executeonly ne } dotest
+%{ newpath 0 0 moveto (a) false charpath
+% {} {} {} {} pathforall closepath } dotest
+{ 1 array executeonly 0 put } dotest
+{ 1 dict noaccess /key put } dotest
+{ 1 string executeonly 0 put } dotest
+{ 1 array executeonly 0 1 putinterval } dotest
+{ 1 string executeonly 0 1 putinterval } dotest
+{ (access.ps) (r) file executeonly read } dotest
+{ (access.ps) (r) file executeonly 10 string readhexstring } dotest
+{ (access.ps) (r) file 10 string readonly readhexstring } dotest
+{ (access.ps) (r) file executeonly 100 string readline } dotest
+{ (access.ps) (r) file 100 string readonly readline } dotest
+{ (access.ps) (r) file executeonly 10 string readstring } dotest
+{ (access.ps) (r) file 10 string readonly readstring } dotest
+% run does not check for no read access?
+{ (string) executeonly (seek) search } dotest
+{ (string) (seek) executeonly search } dotest
+{ (string) executeonly show }
+%% some test for store.
+{ (string) executeonly stringwidth } dotest
+{ (access.ps) (r) file executeonly token } dotest
+{ (10) executeonly token } dotest
+{ /foo 1 dict def foo begin /bar foo def bar noaccess pop /key where } dotest
+{ 100 101 102 (string) noaccess widthshow } dotest
+{ (/tmp/_.ps) noaccess (w) file closefile } dotest
+{ (/tmp/_.ps) (w) noaccess file closefile } dotest
+{ (/tmp/_.ps) (w) file executeonly 100 write } dotest
+{ (/tmp/_.ps) (w) file executeonly 10 string writehexstring } dotest
+{ (/tmp/_.ps) (w) file 10 string executeonly writehexstring } dotest
+{ (/tmp/_.ps) (w) file executeonly 10 string writestring } dotest
+{ (/tmp/_.ps) (w) file 10 string executeonly writestring } dotest
diff --git a/gs/lib/align.ps b/gs/lib/align.ps
new file mode 100644
index 000000000..75d2b66c7
--- /dev/null
+++ b/gs/lib/align.ps
@@ -0,0 +1,71 @@
+% Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Print a page that indicates the proper settings of Margins and HWMargins
+% for a given device. Requires a Level 2 system.
+
+% Reset the offset and margins.
+
+<<
+ /PageOffset [0 0]
+ /Margins [0 0]
+ /.HWMargins [0 0 0 0]
+>>
+setpagedevice
+<<
+ /ImagingBBox null
+>>
+setpagedevice
+
+% Determine the actual page size.
+
+clippath pathbbox newpath
+/y1 exch def /x1 exch def pop pop
+
+% Draw lines that should be exactly 1" in from each edge,
+% and should extend precisely to the edge of the paper.
+
+1 setlinewidth
+0 setgray
+72 0 moveto 0 y1 rlineto stroke
+0 72 moveto x1 0 rlineto stroke
+
+% Print the text in the middle of the page.
+
+/S 80 string def
+108 360 moveto
+/Helvetica 12 selectfont
+ { currentfile S readline pop dup (%END) eq { pop exit } if
+ gsave show grestore 0 -15 rmoveto
+ } loop
+Let the distance in inches from the left edge of the page to
+the vertical line be H, and from the bottom edge to the
+horizontal line be V; let the lengths of the gaps at the top
+and bottom of the vertical line be T and B respectively, and
+the gaps at the left and right of the horizontal line be L
+and R. For measurements in inches, the proper page device
+parameters for this printer are set by
+ << /.HWMargins [ml mb mr mt] /Margins [x y]
+ >> setpagedevice
+where
+ ml = L * 72, mb = B * 72, mr = R * 72, mt = T * 72
+%END
+/res currentpagedevice /.MarginsHWResolution get def
+( x = (1 - H) * ) show res 0 get =string cvs show
+(, y = (V - 1) * ) show res 1 get =string cvs show
+
+showpage
diff --git a/gs/lib/alphabet.ps b/gs/lib/alphabet.ps
new file mode 100644
index 000000000..80dc25e8a
--- /dev/null
+++ b/gs/lib/alphabet.ps
@@ -0,0 +1,56 @@
+% Check for command line parameters:
+% Name, FirstSize, Ratio, NumSizes, UseOutline.
+
+/FontName where { pop } { /FontName (Palatino-Italic) def } ifelse
+/FirstSize where { pop } { /FirstSize 15 def } ifelse
+/Ratio where { pop } { /Ratio 1.6 def } ifelse
+/NumSizes where { pop } { /NumSizes 3 def } ifelse
+/UseOutline where { pop } { /UseOutline false def } ifelse
+
+/Strings FirstSize 20 gt
+ { [
+ (ABCDEFGHIJ) (KLMNOPQR) (STUVWXYZ)
+ (abcdefghijklm) (nopqrstuvwxyz)
+ (0123456789<=>) (:;?@ !"#$%&')
+ (\(\)*+,-./[\\]^_) (`{|}~)
+ ] }
+ { [
+ (ABCDEFGHIJKLMNOPQRSTUVWXYZ)
+ (abcdefghijklmnopqrstuvwxyz)
+ (0123456789<=>:;?@ !"#$%&')
+ (\(\)*+,-./ [\\]^_ `{|}~)
+ ] }
+ifelse def
+
+/sshow
+ { gsave UseOutline
+ { { gsave ( ) dup 0 4 -1 roll put
+ false charpath pathbbox 0 setlinewidth stroke grestore
+ pop 8 add currentpoint exch pop moveto pop
+ } forall
+ }
+ { 2 0 3 -1 roll ashow }
+ ifelse grestore
+ } def
+
+FontName findfont FirstSize scalefont setfont
+
+clippath pathbbox /top exch def pop pop pop newpath
+10 10 moveto
+NumSizes
+ { gsave nulldevice (Q) false charpath pathbbox grestore
+ exch pop exch sub exch pop 1.25 mul /height exch def
+ Strings
+ { currentpoint exch pop top height 3 mul sub gt
+ { showpage 10 10 height sub moveto
+ }
+ if
+ dup sshow
+ UseOutline not
+ { 0 height rmoveto gsave 0.01 rotate sshow grestore }
+ if
+ 0 height rmoveto
+ } forall
+ Ratio dup scale
+ } repeat
+showpage
diff --git a/gs/lib/bdftops b/gs/lib/bdftops
new file mode 100755
index 000000000..c2d86bd77
--- /dev/null
+++ b/gs/lib/bdftops
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -dNODISPLAY -- bdftops.ps "$@"
diff --git a/gs/lib/bdftops.bat b/gs/lib/bdftops.bat
new file mode 100755
index 000000000..bd3d6fa8d
--- /dev/null
+++ b/gs/lib/bdftops.bat
@@ -0,0 +1 @@
+@gs -q -dNODISPLAY -- bdftops.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/bdftops.ps b/gs/lib/bdftops.ps
new file mode 100644
index 000000000..4bfc12aaa
--- /dev/null
+++ b/gs/lib/bdftops.ps
@@ -0,0 +1,793 @@
+% Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% bdftops.ps
+% Convert a BDF file (possibly with (an) associated AFM file(s))
+% to a PostScript Type 1 font (without eexec encryption).
+% The resulting font will work with any PostScript language interpreter,
+% but not with ATM or other font rasterizers lacking a complete interpreter.
+
+/envBDF 120 dict def
+envBDF begin
+
+% "Import" the image-to-path package.
+% This also brings in the Type 1 opcodes (type1ops.ps).
+ (impath.ps) runlibfile
+
+% "Import" the font-writing package.
+ (wrfont.ps) runlibfile
+ wrfont_dict begin
+ /binary_CharStrings false def
+ /binary_tokens false def
+ /encrypt_CharStrings true def
+ /standard_only true def
+ end
+ /lenIV 0 def
+
+% Invert the StandardEncoding vector.
+ 256 dict dup begin
+ 0 1 255 { dup StandardEncoding exch get exch def } for
+ end /StandardDecoding exch def
+
+% Define the properties copied to FontInfo.
+ mark
+ (COPYRIGHT) /Notice
+ (FAMILY_NAME) /FamilyName
+ (FULL_NAME) /FullName
+ (WEIGHT_NAME) /Weight
+ .dicttomark /properties exch def
+
+% Define the character sequences for synthesizing missing composite
+% characters in the standard encoding.
+ mark
+ /AE [/A /E]
+ /OE [/O /E]
+ /ae [/a /e]
+ /ellipsis [/period /period /period]
+ /emdash [/hyphen /hyphen /hyphen]
+ /endash [/hyphen /hyphen]
+ /fi [/f /i]
+ /fl [/f /l]
+ /germandbls [/s /s]
+ /guillemotleft [/less /less]
+ /guillemotright [/greater /greater]
+ /oe [/o /e]
+ /quotedblbase [/comma /comma]
+ .dicttomark /composites exch def
+
+% Define the procedure for synthesizing composites.
+% This must not be bound.
+ /compose
+ { exch pop
+ FontMatrix Private /composematrix get invertmatrix concat
+ 0 0 moveto
+ dup gsave false charpath pathbbox currentpoint grestore
+ 6 2 roll setcachedevice show
+ } def
+% Define the CharString procedure that calls compose, with the string
+% on the stack. This too must remain unbound.
+ /compose_proc
+ { Private /compose get exec
+ } def
+
+% Define aliases for missing characters similarly.
+ mark
+ /acute /quoteright
+ /bullet /asterisk
+ /cedilla /comma
+ /circumflex /asciicircum
+ /dieresis /quotedbl
+ /dotlessi /i
+ /exclamdown /exclam
+ /florin /f
+ /fraction /slash
+ /grave /quoteleft
+ /guilsinglleft /less
+ /guilsinglright /greater
+ /hungarumlaut /quotedbl
+ /periodcentered /asterisk
+ /questiondown /question
+ /quotedblleft /quotedbl
+ /quotedblright /quotedbl
+ /quotesinglbase /comma
+ /quotesingle /quoteright
+ /tilde /asciitilde
+ .dicttomark /aliases exch def
+
+% Define overstruck characters that can be synthesized with seac.
+ mark
+ [ /Aacute /Acircumflex /Adieresis /Agrave /Aring /Atilde
+ /Ccedilla
+ /Eacute /Ecircumflex /Edieresis /Egrave
+ /Iacute /Icircumflex /Idieresis /Igrave
+ /Lslash
+ /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
+ /lslash
+ /ntilde
+ /oacute /ocircumflex /odieresis /ograve /otilde
+ /scaron
+ /uacute /ucircumflex /udieresis /ugrave
+ /yacute /ydieresis
+ /zcaron
+ ]
+ { dup =string cvs
+ [ exch dup 0 1 getinterval cvn
+ exch dup length 1 sub 1 exch getinterval cvn
+ ]
+ } forall
+ /cent [/c /slash]
+ /daggerdbl [/bar /equal]
+ /divide [/colon /hyphen]
+ /sterling [/L /hyphen]
+ /yen [/Y /equal]
+ .dicttomark /accentedchars exch def
+
+% ------ Output utilities ------ %
+
+ /ws {psfile exch writestring} bind def
+ /wl {ws (\n) ws} bind def
+ /wt {=string cvs ws ( ) ws} bind def
+
+% ------ BDF file parsing utilities ------ %
+
+% Define a buffer for reading the BDF file.
+ /buffer 400 string def
+
+% Read a line from the BDF file into the buffer.
+% Ignore empty (zero-length) lines.
+% Define /keyword as the first word on the line.
+% Define /args as the remainder of the line.
+% If the keyword is equal to commentword, skip the line.
+% (If commentword is equal to a space, never skip.)
+ /nextline
+ { { bdfile buffer readline not
+ { (Premature EOF\n) print stop } if
+ dup length 0 ne { exit } if pop
+ }
+ loop
+ ( ) search
+ { /keyword exch def pop }
+ { /keyword exch def () }
+ ifelse
+ /args exch def
+ keyword commentword eq { nextline } if
+ } bind def
+
+% Get a word argument from args. We do *not* copy the string.
+ /warg % warg -> string
+ { args ( ) search
+ { exch pop exch }
+ { () }
+ ifelse /args exch def
+ } bind def
+
+% Get an integer argument from args.
+ /iarg % iarg -> int
+ { warg cvi
+ } bind def
+
+% Get a numeric argument from args.
+ /narg % narg -> int|real
+ { warg cvr
+ dup dup cvi eq { cvi } if
+ } bind def
+
+% Convert the remainder of args into a string.
+ /remarg % remarg -> string
+ { args copystring
+ } bind def
+
+% Get a string argument that occupies the remainder of args.
+ /sarg % sarg -> string
+ { args (") anchorsearch
+ { pop /args exch def } { pop } ifelse
+ args args length 1 sub get (") 0 get eq
+ { args 0 args length 1 sub getinterval /args exch def } if
+ args copystring
+ } bind def
+
+% Check that the keyword is the expected one.
+ /checkline % (EXPECTED-KEYWORD) checkline ->
+ { dup keyword ne
+ { (Expected ) print =
+ (Line=) print keyword print ( ) print args print (\n) print stop
+ } if
+ pop
+ } bind def
+
+% Read a line and check its keyword.
+ /getline % (EXPECTED-KEYWORD) getline ->
+ { nextline checkline
+ } bind def
+
+% Find the first/last non-zero bit of a non-zero byte.
+ /fnzb
+ { 0 { exch dup 128 ge { pop exit } { dup add exch 1 add } ifelse }
+ loop
+ } bind def
+ /lnzb
+ { 7 { exch dup 1 and 0 ne { pop exit } { -1 bitshift exch 1 sub } ifelse }
+ loop
+ } bind def
+
+% ------ Type 1 encoding utilities ------ %
+
+% Parse the side bearing and width information that begins a CharString.
+% Arguments: charstring. Result: sbx sby wx wy substring.
+ /parsesbw
+ { mark exch lenIV
+ { % stack: mark ... string dropcount
+ dup 2 index length exch sub getinterval
+ dup 0 get dup 32 lt { pop exit } if
+ dup 246 le
+ { 139 sub exch 1 }
+ { dup 250 le
+ { 247 sub 8 bitshift 108 add 1 index 1 get add exch 2 }
+ { dup 254 le
+ { 251 sub 8 bitshift 108 add 1 index 1 get add neg exch 2 }
+ { pop dup 1 get 128 xor 128 sub
+ 8 bitshift 1 index 2 get add
+ 8 bitshift 1 index 3 get add
+ 8 bitshift 1 index 4 get add exch 5
+ } ifelse
+ } ifelse
+ } ifelse
+ } loop
+ counttomark 3 eq { 0 3 1 roll 0 exch } if
+ 6 -1 roll pop
+ } bind def
+
+% Find the side bearing and width information that begins a CharString.
+% Arguments: charstring. Result: charstring sizethroughsbw.
+ /findsbw
+ { dup parsesbw 4 { exch pop } repeat skipsbw
+ } bind def
+ /skipsbw % charstring sbwprefix -> sizethroughsbw
+ { length 1 index length exch sub
+ 2 copy get 12 eq { 2 } { 1 } ifelse add
+ } bind def
+
+% Encode a number, and append it to a string.
+% Arguments: str num. Result: newstr.
+ /concatnum
+ { dup dup -107 ge exch 107 le and
+ { 139 add 1 string dup 0 3 index put }
+ { dup dup -1131 ge exch 1131 le and
+ { dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
+ 2 string dup 0 3 index -8 bitshift put
+ dup 1 3 index 255 and put
+ }
+ { 5 string dup 0 255 put exch
+ 2 copy 1 exch -24 bitshift 255 and put
+ 2 copy 2 exch -16 bitshift 255 and put
+ 2 copy 3 exch -8 bitshift 255 and put
+ 2 copy 4 exch 255 and put
+ exch
+ }
+ ifelse
+ }
+ ifelse exch pop concatstrings
+ } bind def
+
+% ------ Point arithmetic utilities ------ %
+
+ /ptadd { exch 4 -1 roll add 3 1 roll add } bind def
+ /ptexch { 4 2 roll } bind def
+ /ptneg { neg exch neg exch } bind def
+ /ptpop { pop pop } bind def
+ /ptsub { ptneg ptadd } bind def
+
+% ------ The main program ------ %
+
+ /readBDF % <infilename> <outfilename> <fontname>
+ % <encodingname> <uniqueID> <xuid> readBDF -> <font>
+ { /xuid exch def % may be null
+ /uniqueID exch def % may be -1
+ /encodingname exch def
+ /encoding encodingname cvx exec def
+ /fontname exch def
+ /psname exch def
+ /bdfname exch def
+ gsave % so we can set the CTM to the font matrix
+
+% Open the input files. We don't open the output file until
+% we've done a minimal validity check on the input.
+ bdfname (r) file /bdfile exch def
+ /commentword ( ) def
+
+% Check for the STARTFONT.
+ (STARTFONT) getline
+ args (2.1) ne { (Not version 2.1\n) print stop } if
+
+% Initialize the font.
+ /Font 20 dict def
+ Font begin
+ /FontName fontname def
+ /PaintType 0 def
+ /FontType 1 def
+ uniqueID 0 gt { /UniqueID uniqueID def } if
+ xuid null ne { /XUID xuid def } if
+ /Encoding encoding def
+ /FontInfo 20 dict def
+ /Private 20 dict def
+ currentdict end currentdict end
+ exch begin begin % insert font above environment
+
+% Initialize the Private dictionary in the font.
+ Private begin
+ /-! {string currentfile exch readhexstring pop} readonly def
+ /-| {string currentfile exch readstring pop} readonly def
+ /|- {readonly def} readonly def
+ /| {readonly put} readonly def
+ /BlueValues [] def
+ /lenIV lenIV def
+ /MinFeature {16 16} def
+ /password 5839 def
+ /UniqueID uniqueID def
+ end % Private
+
+% Invert the Encoding, for synthesizing composite characters.
+ /decoding encoding length dict def
+ 0 1 encoding length 1 sub
+ { dup encoding exch get exch decoding 3 1 roll put }
+ for
+
+% Now open the output file.
+ psname (w) file /psfile exch def
+
+% Put out a header compatible with the Adobe "standard".
+ (%!FontType1-1.0: ) ws fontname wt (000.000) wl
+ (% This is a font description converted from ) ws
+ bdfname wl
+ (% by bdftops running on ) ws
+ statusdict /product get ws ( revision ) ws
+ revision =string cvs ws (.) wl
+
+% Copy the initial comments, up to FONT.
+ true
+ { nextline
+ keyword (COMMENT) ne {exit} if
+ { (% Here are the initial comments from the BDF file:\n%) wl
+ } if false
+ (%) ws remarg wl
+ } loop pop
+ () wl
+ /commentword (COMMENT) def % do skip comments from now on
+
+% Read and process the FONT, SIZE, and FONTBOUNDINGBOX.
+ % If we cared about FONT, we'd use it here. If the BDF files
+ % from MIT had PostScript names rather than X names, we would
+ % care; but what's there is unusable, so we discard FONT.
+ % The FONTBOUNDINGBOX may not be reliable, so we discard it too.
+ (FONT) checkline
+ (SIZE) getline
+ /pointsize iarg def /xres iarg def /yres iarg def
+ (FONTBOUNDINGBOX) getline
+ nextline
+
+% Initialize the font bounding box bookeeping.
+ /fbbxo 1000 def
+ /fbbyo 1000 def
+ /fbbxe -1000 def
+ /fbbye -1000 def
+
+% Read and process the properties. We only care about a few of them.
+ keyword (STARTPROPERTIES) eq
+ { iarg
+ { nextline
+ properties keyword known
+ { FontInfo properties keyword get sarg readonly put
+ } if
+ } repeat
+ (ENDPROPERTIES) getline
+ nextline
+ } if
+
+% Compute and set the FontMatrix.
+ Font /FontMatrix
+ [ 0.001 0 0 0.001 xres mul yres div 0 0 ] readonly
+ dup setmatrix put
+
+% Read and process the header for the bitmaps.
+ (CHARS) checkline
+ /ccount iarg def
+
+% Initialize the CharStrings dictionary.
+ /charstrings ccount
+ composites length add
+ aliases length add
+ accentedchars length add
+ 1 add dict def % 1 add for .notdef
+ /isfixedwidth true def
+ /fixedwidth null def
+ /subrcount 0 def
+ /subrs [] def
+
+% Read the bitmap data. This reads the remainder of the file.
+% We do this before processing the bitmaps so that we can compute
+% the correct FontBBox first.
+ /chardata ccount dict def
+ ccount -1 1
+ { (STARTCHAR) getline
+ /charname remarg def
+ (ENCODING) getline
+ /eindex iarg def
+ eindex 0 ge
+ { charname /charname StandardEncoding eindex get def
+ charname /.notdef eq eindex 0 gt and
+ { /charname (A) eindex =string cvs concatstrings cvn def
+ }
+ if
+ (/) print charname =string cvs print (,) print print
+ }
+ { (/) print charname print
+ }
+ ifelse
+ 10 mod 1 eq { (\n) print flush } if
+ (SWIDTH) getline
+ /swx iarg pointsize mul 1000 div xres mul 72 div def
+ /swy iarg pointsize mul 1000 div xres mul 72 div def
+ (DWIDTH) getline % Ignore, use SWIDTH instead
+ (BBX) getline
+ /bbw iarg def /bbh iarg def /bbox iarg def /bboy iarg def
+ nextline
+ keyword (ATTRIBUTES) eq
+ { nextline
+ } if
+ (BITMAP) checkline
+
+% Update the font bounding box.
+ /fbbxo fbbxo bbox min def
+ /fbbyo fbbyo bboy min def
+ /fbbxe fbbxe bbox bbw add max def
+ /fbbye fbbye bboy bbh add max def
+
+% Read the bits for this character.
+ /raster bbw 7 add 8 idiv def
+ /cbits raster bbh mul string def
+ 0 raster cbits length raster sub
+ { cbits exch raster getinterval
+ bdfile buffer readline not
+ { (EOF in bitmap\n) print stop } if
+ % stack has <cbits.interval> <buffer.interval>
+ 0 () /SubFileDecode filter
+ exch 2 copy readhexstring pop pop pop closefile
+ } for
+ (ENDCHAR) getline
+
+% Save the character data.
+ chardata charname [swx swy bbw bbh bbox bboy cbits] put
+ } for
+
+ (ENDFONT) getline
+
+% Allocate the buffers for the bitmap and the outline,
+% according to the font bounding box.
+ /fbbw fbbxe fbbxo sub def
+ /fbbh fbbye fbbyo sub def
+ /fraster fbbw 7 add 8 idiv def
+ /bits fraster fbbh mul 200 max 65535 min string def
+ /outline bits length 6 mul 65535 min string def
+
+% Process the characters.
+ chardata
+ { exch /charname exch def aload pop
+ /cbits exch def
+ /bboy exch def /bbox exch def
+ /bbh exch def /bbw exch def
+ /swy exch def /swx exch def
+
+% The bitmap handed to type1imagepath must have the correct height,
+% because type1imagepath uses this to compute the scale factor,
+% so we have to clear the unused parts of it.
+ /raster bbw 7 add 8 idiv def
+ bits dup 0 1 raster fbbh mul 1 sub
+ { 0 put dup } for
+ pop pop
+ bits raster fbbh bbh sub mul cbits putinterval
+
+% Compute the font entry, converting the bitmap to an outline.
+ bits 0 raster fbbh mul getinterval % the bitmap image
+ bbw fbbh % bitmap width & height
+ swx swy % width x & y
+ bbox neg bboy neg % origin x & y
+ % Account for lenIV when converting the outline.
+ outline lenIV outline length lenIV sub getinterval
+ type1imagepath
+ length lenIV add
+ outline exch 0 exch getinterval
+
+% Check for a fixed width font.
+ isfixedwidth
+ { fixedwidth null eq
+ { /fixedwidth swx def }
+ { fixedwidth swx ne { /isfixedwidth false def } if }
+ ifelse
+ } if
+
+% Finish up the character.
+ copystring
+ charname exch charstrings 3 1 roll put
+ } forall
+
+% Add CharStrings entries for aliases.
+ aliases
+ { charstrings 2 index known not charstrings 2 index known and
+ { charstrings exch get charstrings 3 1 roll put
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall
+
+% If this is not a fixed-width font, synthesize missing characters
+% out of available ones.
+ isfixedwidth not
+ { false composites
+ { 1 index charstrings exch known not
+ 1 index { decoding exch known and } forall
+ { ( /) print 1 index bits cvs print
+ /combine exch def
+ 0 1 combine length 1 sub
+ { dup combine exch get decoding exch get
+ bits 3 1 roll put
+ } for
+ bits 0 combine length getinterval copystring
+ [ exch /compose_proc load aload pop ] cvx
+ charstrings 3 1 roll put
+ pop true
+ }
+ { pop pop }
+ ifelse
+ }
+ forall flush
+ { Private /composematrix matrix put
+ Private /compose /compose load put
+ }
+ if
+ }
+ if
+
+% Synthesize accented characters with seac if needed and possible.
+ accentedchars
+ { aload pop /accent exch def /base exch def
+ buffer cvs /accented exch def
+ charstrings accented known not
+ charstrings base known and
+ charstrings accent known and
+ StandardDecoding base known and
+ StandardDecoding accent known and
+ encoding StandardDecoding base get get base eq and
+ encoding StandardDecoding accent get get accent eq and
+ { ( /) print accented print
+ charstrings base get findsbw 0 exch getinterval
+ /acstring exch def % start with sbw of base
+ charstrings accent get parsesbw
+ 4 { pop } repeat % just leave sbx
+ acstring exch concatnum
+ 0 concatnum 0 concatnum % adx ady
+ decoding base get concatnum % bchar
+ decoding accent get concatnum % achar
+ s_seac concatstrings
+ charstrings exch accented copystring exch put
+ } if
+ } forall
+
+% Make a CharStrings entry for .notdef.
+ outline lenIV <8b8b0d0e> putinterval % 0 0 hsbw endchar
+ charstrings /.notdef outline 0 lenIV 4 add getinterval copystring put
+
+% Encrypt the CharStrings and Subrs (in place).
+ charstrings
+ { % Be careful not to encrypt aliased characters twice,
+ % since they share their CharString.
+ aliases 2 index known
+ { charstrings aliases 3 index get .knownget
+ { 1 index ne }
+ { true }
+ ifelse
+ }
+ { true
+ }
+ ifelse
+ 1 index type /stringtype eq and
+ { 4330 exch dup .type1encrypt exch pop
+ readonly charstrings 3 1 roll put
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall
+ 0 1 subrcount 1 sub
+ { dup subrs exch get
+ 4330 exch dup .type1encrypt exch pop
+ subrs 3 1 roll put
+ }
+ for
+
+% Make most of the remaining entries in the font dictionaries.
+
+% The Type 1 font machinery really only works with a 1000 unit
+% character coordinate system. Set this up here, by computing the factor
+% to make the X entry in the FontMatrix come out at exactly 0.001.
+ /fontscale 1000 fbbh div yres mul xres div def
+ Font /FontBBox
+ [ fbbxo fontscale mul
+ fbbyo fontscale mul
+ fbbxe fontscale mul
+ fbbye fontscale mul
+ ] cvx readonly put
+ Font /CharStrings charstrings readonly put
+ FontInfo /FullName known not
+ { % Some programs insist on FullName being present.
+ FontInfo /FullName FontName dup length string cvs put
+ }
+ if
+ FontInfo /isFixedPitch isfixedwidth put
+ subrcount 0 gt
+ { Private /Subrs subrs 0 subrcount getinterval readonly put
+ } if
+
+% Determine the italic angle and underline position
+% by actually installing the font.
+ save
+ /_temp_ Font definefont setfont
+ [1000 0 0 1000 0 0] setmatrix % mitigate rounding problems
+% The italic angle is the multiple of -5 degrees
+% that minimizes the width of the 'I'.
+ 0 9999 0 5 85
+ { dup rotate
+ newpath 0 0 moveto (I) false charpath
+ dup neg rotate
+ pathbbox pop exch pop exch sub
+ dup 3 index lt { 4 -2 roll } if
+ pop pop
+ }
+ for pop
+% The underline position is halfway between the bottom of the 'A'
+% and the bottom of the FontBBox.
+ newpath 0 0 moveto (A) false charpath
+ FontMatrix concat
+ pathbbox pop pop exch pop
+% Put the values in FontInfo.
+ 3 -1 roll
+ restore
+ Font /FontBBox get 1 get add 2 div cvi
+ dup FontInfo /UnderlinePosition 3 -1 roll put
+ 2 div abs FontInfo /UnderlineThickness 3 -1 roll put
+ FontInfo /ItalicAngle 3 -1 roll put
+
+% Clean up and finish.
+ grestore
+ bdfile closefile
+ Font currentdict end end begin % remove font from dict stack
+ (\n) print flush
+
+ } bind def
+
+% ------ Reader for AFM files ------ %
+
+% Dictionary for looking up character keywords
+ /cmdict 6 dict dup begin
+ /C { /c iarg def } def
+ /N { /n warg copystring def } def
+ /WX { /w narg def } def
+ /W0X /WX load def
+ /W /WX load def
+ /W0 /WX load def
+ end def
+
+ /readAFM % fontdict afmfilename readAFM -> fontdict
+ { (r) file /bdfile exch def
+ /Font exch def
+ /commentword (Comment) def
+
+% Check for the StartFontMetrics.
+ (StartFontMetrics) getline
+ args cvr 2.0 lt { (Not version 2.0 or greater\n) print stop } if
+
+% Look for StartCharMetrics, then parse the character metrics.
+% The only information we care about is the X width.
+ /metrics 0 dict def
+ { nextline
+ keyword (EndFontMetrics) eq { exit } if
+ keyword (StartCharMetrics) eq
+ { iarg dup dict /metrics exch def
+ { /c -1 def /n null def /w null def
+ nextline buffer
+ { token not { exit } if
+ dup cmdict exch known
+ { exch /args exch def cmdict exch get exec args }
+ { pop }
+ ifelse
+ } loop
+ c 0 ge n null ne or w null ne and
+ { n null eq { /n Font /Encoding get c get def } if
+ metrics n w put
+ }
+ if
+ }
+ repeat
+ (EndCharMetrics) getline
+ } if
+ } loop
+
+% Insert the metrics in the font.
+ metrics length 0 ne
+ { Font /Metrics metrics readonly put
+ } if
+ Font
+ } bind def
+
+end % envBDF
+
+% Enter the main program in the current dictionary.
+/bdfafmtops % infilename afmfilename* outfilename fontname
+ % encodingname uniqueID xuid
+ { envBDF begin
+ 7 -2 roll exch 7 2 roll % afm* in out fontname encodingname uniqueID xuid
+ readBDF % afm* font
+ exch { readAFM } forall
+ save exch
+ dup /FontName get exch definefont
+ setfont
+ psfile writefont
+ restore
+ psfile closefile
+ end
+ } bind def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark 4 ge
+ { dup 0 get
+ dup 48 ge exch 57 le and % last arg starts with a digit?
+ { /StandardEncoding } % no encodingname
+ { cvn } % have encodingname
+ ifelse
+ exch (.) search % next-to-last arg has . in it?
+ { mark 4 1 roll % have xuid
+ { cvi exch pop exch (.) search not { exit } if }
+ loop cvi ]
+ 3 -1 roll cvi exch
+ }
+ { cvi null % no xuid
+ }
+ ifelse
+ counttomark 5 roll
+ counttomark 6 sub array astore
+ 7 -2 roll cvn 7 -3 roll % make sure fontname is a name
+ bdfafmtops
+ }
+ { cleartomark
+ (Usage:\n bdftops xx.bdf [yy1.afm ...] zz.gsf fontname uniqueID [xuid] [encodingname]\n) print flush
+ mark
+ }
+ ifelse
+ }
+if pop
diff --git a/gs/lib/bjc610a0.upp b/gs/lib/bjc610a0.upp
new file mode 100644
index 000000000..99d676f96
--- /dev/null
+++ b/gs/lib/bjc610a0.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, plain paper high speed, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 100200
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1400
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a1.upp b/gs/lib/bjc610a1.upp
new file mode 100644
index 000000000..febbdd954
--- /dev/null
+++ b/gs/lib/bjc610a1.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, plain paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 100110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1400
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a2.upp b/gs/lib/bjc610a2.upp
new file mode 100644
index 000000000..bf039508c
--- /dev/null
+++ b/gs/lib/bjc610a2.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, coated paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 101110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1410
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a3.upp b/gs/lib/bjc610a3.upp
new file mode 100644
index 000000000..031f47c83
--- /dev/null
+++ b/gs/lib/bjc610a3.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, transparency film, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 102110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1420
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a4.upp b/gs/lib/bjc610a4.upp
new file mode 100644
index 000000000..eb47e685c
--- /dev/null
+++ b/gs/lib/bjc610a4.upp
@@ -0,0 +1,45 @@
+-supModel="Canon BJC 610, 360x360DpI, back print film, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupYFlip
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 103110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1430
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a5.upp b/gs/lib/bjc610a5.upp
new file mode 100644
index 000000000..42dbd20ef
--- /dev/null
+++ b/gs/lib/bjc610a5.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, fabric sheet, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 104110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1850
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a6.upp b/gs/lib/bjc610a6.upp
new file mode 100644
index 000000000..19ad1f656
--- /dev/null
+++ b/gs/lib/bjc610a6.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, glossy paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 105110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1460
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a7.upp b/gs/lib/bjc610a7.upp
new file mode 100644
index 000000000..727d366f8
--- /dev/null
+++ b/gs/lib/bjc610a7.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, high gloss film, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 106110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 1470
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610a8.upp b/gs/lib/bjc610a8.upp
new file mode 100644
index 000000000..b5407b576
--- /dev/null
+++ b/gs/lib/bjc610a8.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 360x360DpI, high resolution paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r360x360
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0058 0.0164 0.0301 0.0463 0.0648 0.0851 0.1073
+0.1311 0.1564 0.1832 0.2114 0.2408 0.2716 0.3035 0.3366
+0.3708 0.4061 0.4425 0.4798 0.5182 0.5576 0.5978 0.6391
+0.6812 0.7242 0.7681 0.8128 0.8584 0.9048 0.9520 1.0000
+}"
+-dupCyanTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupYellowTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 107110
+ 1b28 64 0200 0168
+ 1b28 6c 0200 14a0
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b1.upp b/gs/lib/bjc610b1.upp
new file mode 100644
index 000000000..0d6e48137
--- /dev/null
+++ b/gs/lib/bjc610b1.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, plain paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0029 0.0082 0.0151 0.0232 0.0324 0.0426 0.0537
+0.0655 0.0782 0.0916 0.1057 0.1204 0.1358 0.1517 0.1683
+0.1854 0.2030 0.2212 0.2399 0.2591 0.2788 0.2989 0.3195
+0.3406 0.3621 0.3840 0.4064 0.4292 0.4524 0.4760 0.5000
+}"
+-dupCyanTransfer="{
+0.0000 0.0004 0.0017 0.0037 0.0067 0.0104 0.0150 0.0204
+0.0266 0.0337 0.0416 0.0504 0.0599 0.0703 0.0816 0.0937
+0.1066 0.1203 0.1349 0.1503 0.1665 0.1836 0.2015 0.2202
+0.2398 0.2601 0.2814 0.3034 0.3263 0.3501 0.3746 0.4000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0004 0.0017 0.0037 0.0067 0.0104 0.0150 0.0204
+0.0266 0.0337 0.0416 0.0504 0.0599 0.0703 0.0816 0.0937
+0.1066 0.1203 0.1349 0.1503 0.1665 0.1836 0.2015 0.2202
+0.2398 0.2601 0.2814 0.3034 0.3263 0.3501 0.3746 0.4000
+}"
+-dupYellowTransfer="{
+0.0000 0.0004 0.0017 0.0037 0.0067 0.0104 0.0150 0.0204
+0.0266 0.0337 0.0416 0.0504 0.0599 0.0703 0.0816 0.0937
+0.1066 0.1203 0.1349 0.1503 0.1665 0.1836 0.2015 0.2202
+0.2398 0.2601 0.2814 0.3034 0.3263 0.3501 0.3746 0.4000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 101110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1410
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b2.upp b/gs/lib/bjc610b2.upp
new file mode 100644
index 000000000..f17947af8
--- /dev/null
+++ b/gs/lib/bjc610b2.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, coated paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0029 0.0082 0.0151 0.0232 0.0324 0.0426 0.0537
+0.0655 0.0782 0.0916 0.1057 0.1204 0.1358 0.1517 0.1683
+0.1854 0.2030 0.2212 0.2399 0.2591 0.2788 0.2989 0.3195
+0.3406 0.3621 0.3840 0.4064 0.4292 0.4524 0.4760 0.5000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 101110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1410
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b3.upp b/gs/lib/bjc610b3.upp
new file mode 100644
index 000000000..0ed5ca27b
--- /dev/null
+++ b/gs/lib/bjc610b3.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, transparency film, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 102110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1420
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b4.upp b/gs/lib/bjc610b4.upp
new file mode 100644
index 000000000..a4d665688
--- /dev/null
+++ b/gs/lib/bjc610b4.upp
@@ -0,0 +1,45 @@
+-supModel="Canon BJC 610, 720x720DpI, back print film, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupYFlip
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0019 0.0042 0.0075 0.0117 0.0169 0.0229
+0.0300 0.0379 0.0468 0.0567 0.0674 0.0791 0.0918 0.1054
+0.1199 0.1353 0.1517 0.1690 0.1873 0.2065 0.2266 0.2477
+0.2697 0.2927 0.3165 0.3414 0.3671 0.3938 0.4214 0.4500
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0019 0.0042 0.0075 0.0117 0.0169 0.0229
+0.0300 0.0379 0.0468 0.0567 0.0674 0.0791 0.0918 0.1054
+0.1199 0.1353 0.1517 0.1690 0.1873 0.2065 0.2266 0.2477
+0.2697 0.2927 0.3165 0.3414 0.3671 0.3938 0.4214 0.4500
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0019 0.0042 0.0075 0.0117 0.0169 0.0229
+0.0300 0.0379 0.0468 0.0567 0.0674 0.0791 0.0918 0.1054
+0.1199 0.1353 0.1517 0.1690 0.1873 0.2065 0.2266 0.2477
+0.2697 0.2927 0.3165 0.3414 0.3671 0.3938 0.4214 0.4500
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 103110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1430
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b6.upp b/gs/lib/bjc610b6.upp
new file mode 100644
index 000000000..ae27bdb32
--- /dev/null
+++ b/gs/lib/bjc610b6.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, glossy paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0029 0.0082 0.0151 0.0232 0.0324 0.0426 0.0537
+0.0655 0.0782 0.0916 0.1057 0.1204 0.1358 0.1517 0.1683
+0.1854 0.2030 0.2212 0.2399 0.2591 0.2788 0.2989 0.3195
+0.3406 0.3621 0.3840 0.4064 0.4292 0.4524 0.4760 0.5000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 105110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1460
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b7.upp b/gs/lib/bjc610b7.upp
new file mode 100644
index 000000000..f7c68c4b2
--- /dev/null
+++ b/gs/lib/bjc610b7.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, high gloss paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 106110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 1470
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bjc610b8.upp b/gs/lib/bjc610b8.upp
new file mode 100644
index 000000000..56c2feec2
--- /dev/null
+++ b/gs/lib/bjc610b8.upp
@@ -0,0 +1,44 @@
+-supModel="Canon BJC 610, 720x720DpI, high resolution paper, color, rendered"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Canon
+-r720x720
+-dupMargins="{ 8.23 20.44 11.05 7.9 }"
+-dupOutputComponentOrder="{ 3 2 1 0 }"
+-dupBlackTransfer="{
+0.0000 0.0008 0.0033 0.0075 0.0133 0.0208 0.0300 0.0408
+0.0533 0.0674 0.0832 0.1007 0.1199 0.1407 0.1632 0.1873
+0.2131 0.2406 0.2697 0.3005 0.3330 0.3671 0.4029 0.4404
+0.4795 0.5203 0.5627 0.6069 0.6527 0.7001 0.7492 0.8000
+}"
+-dupCyanTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupMagentaTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupYellowTransfer="{
+0.0000 0.0005 0.0021 0.0047 0.0083 0.0130 0.0187 0.0255
+0.0333 0.0421 0.0520 0.0630 0.0749 0.0879 0.1020 0.1171
+0.1332 0.1504 0.1686 0.1878 0.2081 0.2294 0.2518 0.2752
+0.2997 0.3252 0.3517 0.3793 0.4079 0.4376 0.4683 0.5000
+}"
+-dupBeginPageCommand="<
+ 1b5b4b 0200 000f
+ 1b28 62 0100 01
+ 1b28 63 0300 107110
+ 1b28 64 0200 02d0
+ 1b28 6c 0200 14a0
+ 1b28 67 0100 E5
+>"
+-dupEndJobCommand="(\033\050b\001\000\000\033@)"
+-dupEndPageCommand="(\014)"
diff --git a/gs/lib/bughunt.sh b/gs/lib/bughunt.sh
new file mode 100755
index 000000000..f3292aac0
--- /dev/null
+++ b/gs/lib/bughunt.sh
@@ -0,0 +1,119 @@
+#! /bin/sh
+# NB: If your sh does not support functions, then try
+# /usr/local/bin/bash or /bin/ksh, if you have them.
+#
+# Hunt down compiler bugs that break gs.
+#
+# Usage:
+# ./BUGHUNT "optimization level"
+# e.g.
+# ./BUGHUNT "-O2"
+#
+# Start with the code compiled at the lowest optimization level where
+# it works, then run this script with suitable compiler options. The
+# script will delete one object file at a time and rebuild gs at
+# a higher optimization level. This should uncover the routine(s)
+# that the compiler is generating bad code for.
+#
+# In order to make this test possible in unattended batch mode,
+# ghostscript is run with command-line options that force creation of
+# a bitmap file, rather than a window.
+#
+# The okay subdirectory should contain correct output for each
+# of the tests.
+#
+# [06-Dec-1995]
+
+OBJECTS=" adler32.o deflate.o gconfig.o gdevabuf.o gdevbit.o \
+ gdevbj10.o gdevcdj.o gdevdflt.o gdevdjet.o \
+ gdevemap.o gdevm1.o gdevm16.o gdevm2.o gdevm24.o \
+ gdevm32.o gdevm4.o gdevm8.o gdevmem.o gdevmpla.o \
+ gdevmrop.o gdevpbm.o gdevpccm.o gdevpcl.o gdevpcx.o \
+ gdevpipe.o gdevpng.o gdevprn.o gdevpsim.o gdevtfax.o \
+ gdevtfnx.o gdevtifs.o gdevx.o gdevxalt.o gdevxini.o \
+ gdevxxf.o gp_nofb.o gp_unifn.o gp_unifs.o gp_unix.o \
+ gs.o gsalloc.o gsbitops.o gsbittab.o gschar.o \
+ gschar0.o gscie.o gscolor.o gscolor1.o gscolor2.o \
+ gscoord.o gscsepr.o gsdevice.o gsdevmem.o gsdparam.o \
+ gsdps1.o gsfont.o gsfont0.o gshsb.o gsht.o gsht1.o \
+ gshtscr.o gsimage.o gsimage0.o gsimage1.o gsimage2.o \
+ gsimage3.o gsimpath.o gsinit.o gsiodev.o gsline.o \
+ gsmain.o gsmatrix.o gsmemory.o gsmisc.o gspaint.o \
+ gsparam.o gspath.o gspath1.o gspcolor.o gsrop.o \
+ gsroptab.o gsstate.o gstype1.o gsutil.o gxacpath.o \
+ gxbcache.o gxccache.o gxccman.o gxcht.o gxclbits.o \
+ gxclfile.o gxclip2.o gxclist.o gxclpath.o gxclread.o \
+ gxcmap.o gxcpath.o gxctable.o gxdcconv.o gxdither.o \
+ gxdraw.o gxfill.o gxhint1.o gxhint2.o gxhint3.o \
+ gxht.o gxpaint.o gxpath.o gxpath2.o gxpcmap.o \
+ gxpcopy.o gxstroke.o ialloc.o ibnum.o iccinit0.o \
+ iconfig.o idebug.o idict.o idparam.o igc.o igcref.o \
+ igcstr.o iinit.o ilocate.o iname.o interp.o iparam.o \
+ ireclaim.o isave.o iscan.o iscanbin.o iscannum.o \
+ iscantab.o istack.o iutil.o iutil2.o jcapimin.o \
+ jcapistd.o jccoefct.o jccolor.o jcdctmgr.o jchuff.o \
+ jcinit.o jcmainct.o jcmarker.o jcmaster.o jcomapi.o \
+ jcparam.o jcprepct.o jcsample.o jdapimin.o \
+ jdapistd.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o \
+ jdinput.o jdmainct.o jdmarker.o jdmaster.o jdphuff.o \
+ jdpostct.o jdsample.o jfdctint.o jidctint.o \
+ jmemmgr.o jutils.o png.o pngerror.o pngio.o pngmem.o \
+ pngtrans.o pngwrite.o pngwtran.o pngwutil.o sbcp.o \
+ sbhc.o sbwbs.o scfd.o scfdtab.o scfe.o scfetab.o \
+ sdctc.o sdctd.o sdcte.o seexec.o sfile.o sfilter1.o \
+ sfilter2.o shc.o shcgen.o siscale.o sjpegc.o \
+ sjpegd.o sjpege.o sjpegerr.o slzwc.o slzwd.o slzwe.o \
+ smtf.o spdiff.o srld.o srle.o sstring.o stream.o \
+ trees.o zarith.o zarray.o zbseq.o zchar.o zchar1.o \
+ zchar2.o zcie.o zcolor.o zcolor1.o zcolor2.o \
+ zcontrol.o zcrd.o zcsindex.o zcssepr.o zdevcal.o \
+ zdevice.o zdevice2.o zdict.o zdps1.o zfbcp.o \
+ zfdctc.o zfdctd.o zfdcte.o zfdecode.o zfile.o \
+ zfileio.o zfilter.o zfilter2.o zfilterx.o zfname.o \
+ zfont.o zfont0.o zfont1.o zfont2.o zfproc.o \
+ zgeneric.o zgstate.o zhsb.o zht.o zht1.o zht2.o \
+ zimage2.o ziodev.o ziodev2.o zmath.o zmatrix.o \
+ zmedia2.o zmisc.o zmisc1.o zmisc2.o zpacked.o \
+ zpaint.o zpath.o zpath1.o zpcolor.o zrelbit.o \
+ zstack.o zstring.o zsysvm.o ztoken.o ztype.o \
+ zupath.o zutil.o zvmem.o zvmem2.o zwppm.o"
+
+TESTS="exepsf tiger"
+
+dotest()
+{
+ # Create empty output file, so even if gs core dumps,
+ # we will have something to compare against.
+ touch $1.ljp
+ ./gs -sDEVICE=ljetplus -r75x75 -sOutputFile=$1.ljp \
+ $1.ps quit.ps < /dev/null
+ if cmp $1.ljp okay/$1.ljp
+ then
+ /bin/true
+ else
+ echo COMPARISON FAILURE: $1.ljp okay/$1.ljp
+ echo "Remaking $f and gs with lower optimization"
+ /bin/rm -f $f ./gs
+ make $f gs
+ fi
+}
+
+for f in $OBJECTS
+do
+ echo ==================== $f ====================
+
+ date
+
+ # Remove the old (good) object file and ghostscript
+ /bin/rm -f $f gs
+
+ # Rebuild gs with optimization; only one object file should be
+ # recreated.
+ make gs CC="cc $1"
+
+ # Now check this new version of gs with each test file.
+ for t in $TESTS
+ do
+ dotest $t
+ done
+done
diff --git a/gs/lib/caption.ps b/gs/lib/caption.ps
new file mode 100644
index 000000000..c119f022c
--- /dev/null
+++ b/gs/lib/caption.ps
@@ -0,0 +1,57 @@
+%!
+% Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Add a "caption" to the bottom of each page.
+/captionsize 20 def
+/caption
+ { /Helvetica //captionsize selectfont
+ (Printed by Aladdin's XXYYZZ) show
+ /Symbol //captionsize selectfont
+ (\324) show % trademarkserif
+ /Helvetica //captionsize selectfont
+ ( product) show
+ } bind def
+
+10 dict begin
+gsave
+ initgraphics
+ clippath pathbbox
+ pop exch 36 add /by exch def
+ % We can't use stringwidth, so we have to show and measure.
+ gsave
+ 0 0 0 0 rectclip
+ 0 0 moveto caption currentpoint pop /bw exch def
+ grestore
+ add bw sub 2 div /bx exch def
+ % We don't have the font bbox available, so we guess.
+ /bh captionsize 1.05 mul def
+grestore
+/showcaption
+ { gsave
+ initgraphics
+ //bx 9 sub //by 9 sub //bw 18 add //bh 18 add
+ 1 setgray 4 copy rectfill 0 setgray 1.5 setlinewidth rectstroke
+ //bx //by moveto //caption exec
+ grestore
+ } bind def
+<< /EndPage [
+ /showcaption load /exec load
+ currentpagedevice /EndPage get /exec load
+ ] cvx
+>> setpagedevice
+end
diff --git a/gs/lib/cbjc600.ppd b/gs/lib/cbjc600.ppd
new file mode 100644
index 000000000..4b992d48a
--- /dev/null
+++ b/gs/lib/cbjc600.ppd
@@ -0,0 +1,404 @@
+*PPD-Adobe: "4.1"
+*% Adobe Systems PostScript(R) Printer Description File
+*% Copyright 1995 Yves Arrouye for Aladdin Ghostscript with Level 2 PS.
+*% All Rights Reserved.
+*% This file may be distributed as part of GNU Ghostscript and/or Aladdin
+*% Ghostscript, under the same terms and conditions as Ghostscript.
+*% End of Copyright statement
+*FormatVersion: "4.1"
+*FileVersion: "1.0"
+*LanguageVersion: English
+*PCFileName: "CBJC600.PPD"
+*Product: "(Canon Bubble Jet Color 600)"
+*PSVersion: "(2010.351) 0"
+*ModelName: "Canon Bubble Jet Color 600"
+*NickName: "BJC-600"
+
+*% This file is not complete, and may lack some useful information...
+
+*% Note: the default transfer function should be set to Null if Ghostscript
+*% exhibit a bug making magenta appear while printing in gray levels...
+*% Note: if you print on A4 paper by default, change *Default values (the
+*% default is Letter here).
+
+*% ==============Constraints =================
+
+*UIConstraints: *BitsPerPixel None *ColorModel DeviceCMYK
+*UIConstraints: *BitsPerPixel None *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 16 *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 16 *ColorModel DeviceGray
+*UIConstraints: *BitsPerPixel 24 *ColorModel DeviceGray
+*UIConstraints: *BitsPerPixel 32 *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 32 *ColorModel DeviceGray
+
+*UIConstraints: *ColorModel DeviceCMYK *BitsPerPixel None
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel None
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel 16
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel 32
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 16
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 24
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 32
+
+*% =========== Device Capabilities ===============
+
+*LanguageLevel: "2"
+*Protocols: TBCP
+*FreeVM: "2124600"
+*ColorDevice: True
+*DefaultColorSpace: CMYK
+*FileSystem: True
+*Throughput: "1"
+
+*Password: "()"
+
+*% ============Paper Size Information ==============
+
+*OpenUI *PageSize: PickOne
+*OrderDependency: 30 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize A4: "1 dict dup /PageSize [595 842] put setpagedevice"
+*PageSize A5: "1 dict dup /PageSize [421 595] put setpagedevice"
+*PageSize A6: "1 dict dup /PageSize [297 421] put setpagedevice"
+*PageSize A7: "1 dict dup /PageSize [210 297] put setpagedevice"
+*PageSize A8: "1 dict dup /PageSize [148 210] put setpagedevice"
+*PageSize A9: "1 dict dup /PageSize [105 148] put setpagedevice"
+*PageSize A10: "1 dict dup /PageSize [74 105] put setpagedevice"
+*PageSize B5: "1 dict dup /PageSize [501 709] put setpagedevice"
+*PageSize Letter/US Letter: "1 dict dup /PageSize [612 792] put setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 40 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion A4: "1 dict dup /PageSize [595 842] put setpagedevice"
+*PageRegion A5: "1 dict dup /PageSize [421 595] put setpagedevice"
+*PageRegion A6: "1 dict dup /PageSize [297 421] put setpagedevice"
+*PageRegion A7: "1 dict dup /PageSize [210 297] put setpagedevice"
+*PageRegion A8: "1 dict dup /PageSize [148 210] put setpagedevice"
+*PageRegion A9: "1 dict dup /PageSize [105 148] put setpagedevice"
+*PageRegion A10: "1 dict dup /PageSize [74 105] put setpagedevice"
+*PageRegion B5: "1 dict dup /PageSize [501 709] put setpagedevice"
+*PageRegion Letter/US Letter: "1 dict dup /PageSize [612 792] put setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea A4: "18.425196 27.096094 576.625183 833.496094"
+*ImageableArea A5: "18.425196 27.096045 402.625183 586.496033"
+*ImageableArea A6: "18.425196 27.096045 278.625183 412.496033"
+*ImageableArea A7: "18.425196 27.096045 191.625198 288.496033"
+*ImageableArea A8: "18.425196 27.096045 129.625198 201.496048"
+*ImageableArea A9: "18.425196 27.096045 86.625198 139.496048"
+*ImageableArea A10: "18.425196 27.096045 55.625195 96.496048"
+*ImageableArea B5: "18.425196 27.096045 482.625183 700.496033"
+*ImageableArea Letter/US Letter: "18.425196 27.096045 593.625183 783.496033"
+
+*?ImageableArea: "
+save
+ /cvp {( ) cvs print ( ) print } bind def
+ /upperright {10000 mul floor 10000 div} bind def
+ /lowerleft {10000 mul ceiling 10000 div} bind def
+ newpath clippath pathbbox
+ 4 -2 roll exch 2 {lowerleft cvp} repeat
+ exch 2 {upperright cvp} repeat flush
+ restore
+"
+*End
+
+*PaperDimension A4: "595 842"
+*PaperDimension A5: "421 595"
+*PaperDimension A6: "297 421"
+*PaperDimension A7: "210 297"
+*PaperDimension A8: "148 210"
+*PaperDimension A9: "105 148"
+*PaperDimension A10: "74 105"
+*PaperDimension B5: "501 709"
+*PaperDimension Letter/US Letter: "612 792"
+
+*HWMargins: "9.637794495 27.042521 9.637794495 8.503937"
+
+*% =============Halftone Information ===============
+
+*ScreenFreq: "60.0"
+*ScreenAngle: "45.0"
+
+*DefaultScreenProc: Dot
+*ScreenProc Dot: "
+{dup mul exch dup mul add 1.0 exch sub }
+"
+*End
+*ScreenProc Line: "{ pop }"
+*ScreenProc Ellipse: "{ dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub }"
+
+*DefaultTransfer: Normalized
+*Transfer Normalized: "{mark
+1.0 1.000 0.955 0.915 0.847 0.765 0.683 0.602 0.500 0.311 0.030 0.0
+counttomark dup 3 add -1 roll exch
+2 sub mul dup floor cvi dup 3 1 roll sub exch dup
+3 add index exch 2 add index dup 4 1 roll sub mul add
+counttomark 1 add 1 roll cleartomark
+} bind"
+*End
+*Transfer Null: "{ }"
+*Transfer Null.Inverse: "{ 1 exch sub }"
+*End
+
+*%==================Input Slot====================
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 20 AnySetup *InputSlot
+*DefaultInputSlot: Feeder
+*InputSlot Feeder/Paper Tray: ""
+*CloseUI: *InputSlot
+
+*%=================Manual Feed====================
+
+*OpenUI *ManualFeed/Manual Feed: Boolean
+*OrderDependency: 20 AnySetup *ManualFeed
+*DefaultManualFeed: False
+*ManualFeed True/True: "1 dict dup /ManualFeed true put setpagedevice"
+*ManualFeed False/False: "1 dict dup /ManualFeed false put setpagedevice"
+*?ManualFeed: "
+ save
+ currentpagedevice /ManualFeed get
+ {(True)}{(False)}ifelse = flush
+ restore"
+*End
+
+*CloseUI: *ManualFeed
+
+*%===================Resolution====================
+
+*OpenUI *Resolution/Resolution: PickOne
+*OrderDependency: 10 AnySetup *Resolution
+*DefaultResolution: 360x360dpi
+*Resolution 90x90dpi/90dpi: "
+ 1 dict dup /HWResolution [ 90 90 ]
+ put setpagedevice"
+*End
+
+*Resolution 180x180dpi/180dpi: "
+ 1 dict dup /HWResolution [ 180 180 ]
+ put setpagedevice"
+*End
+
+*Resolution 360x360dpi/360dpi: "
+ 1 dict dup /HWResolution [ 360 360 ]
+ put setpagedevice"
+*End
+
+*?Resolution: "
+ save
+ currentpagedevice /HWResolution get dup
+ 0 get cvi 10 string cvs print
+ (x) print
+ 0 get cvi 10 string print
+ (dpi) = flush
+ restore"
+*End
+
+*CloseUI: *Resolution
+
+*%===================Output Depth====================
+
+*OpenUI *BitsPerPixel/Print Depth: PickOne
+*OrderDependency: 30 AnySetup *BitsPerPixel
+*DefaultBitsPerPixel: 24
+*BitsPerPixel None/1bpp: "
+ 1 dict dup /BitsPerPixel 1 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 8/8bpp: "
+ 1 dict dup /BitsPerPixel 8 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 16/16bpp: "
+ 1 dict dup /BitsPerPixel 16 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 24/24bpp: "
+ 1 dict dup /BitsPerPixel 24 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 32/32bpp: "
+ 1 dict dup /BitsPerPixel 32 put
+ setpagedevice"
+*End
+
+*?BitsPerPixel: "
+ save
+ currentpagedevice /BitsPerPixel get dup 1 eq { pop (None) } if = flush
+ restore"
+*End
+
+*CloseUI: *BitsPerPixel
+
+*%=================Media Type============================
+
+*OpenUI *MediaType/Media Type: PickOne
+*OrderDependency: 50 AnySetup *MediaType
+*DefaultMediaType: PlainPaper
+*MediaType PlainPaper/Plain Paper: "
+ 1 dict dup /MediaType (PlainPaper) put setpagedevice"
+*End
+
+*MediaType CoatedPaper/Coated Paper: "
+ 1 dict dup /MediaType (CoatedPaper) put setpagedevice"
+*End
+
+*MediaType TransparencyFilm/Transparency Film: "
+ 1 dict dup /MediaType (TransparencyFilm) put setpagedevice"
+*End
+
+*MediaType Envelope/Envelope: "
+ 1 dict dup /MediaType (Envelope) put setpagedevice"
+*End
+
+*MediaType Card/Card: "
+ 1 dict dup /MediaType (Card) put setpagedevice"
+*End
+
+*MediaType Other/Other: "
+ 1 dict dup /MediaType (Other) put setpagedevice"
+*End
+
+*?MediaType: "
+ save
+ currentpagedevice /MediaType get
+ dup null eq {pop (Unknown)} if = flush
+ restore "
+*End
+
+*CloseUI: *MediaType
+
+*%===================Printing Quality====================
+
+*OpenUI *OutputMode/Print Quality: PickOne
+*OrderDependency: 50 AnySetup *OuputMode
+*DefaultOutputMode: Normal
+*OutputMode Draft/Draft: "
+ 1 dict dup /PrintQuality (Draft) put setpagedevice"
+*End
+
+*OutputMode Normal/Normal: "
+ 1 dict dup /PrintQuality (Normal) put setpagedevice"
+*End
+
+*OutputMode High/High: "
+ 1 dict dup /PrintQuality (High) put setpagedevice"
+*End
+
+*?OutputMode: "
+ save
+ currentpagedevice /PrintQuality get
+ dup null eq {pop (Unknown)} if = flush
+ restore "
+*End
+
+*CloseUI: *OutputMode
+
+*%===================Color/Gray Printing====================
+
+*OpenUI *ColorModel/Color Processing: PickOne
+*OrderDependency: 20 AnySetup *ColorModel
+*DefaultColorModel: DeviceCMYK
+*ColorModel DeviceGray/Gray: "
+ 1 dict dup /ProcessColorModel /DeviceGray
+ put setpagedevice"
+*End
+
+*ColorModel DeviceRGB/RGB: "
+ 1 dict dup /ProcessColorModel /DeviceRGB
+ put setpagedevice"
+*End
+
+*ColorModel DeviceCMYK/CMYK: "
+ 1 dict dup /ProcessColorModel /DeviceCMYK
+ put setpagedevice"
+*End
+
+*?ColorModel: "
+ save
+ currentpagedevice /ProcessColorModel get = flush
+ restore "
+*End
+
+*CloseUI: *ColorModel
+
+*%===================Media Weight/Thick Media====================
+
+*OpenUI *ThickMedia/Thick Media: PickOne
+*OrderDependency: 30 AnySetup *ThickMedia
+*Default ThickMedia: Thin
+*ThickMedia Thin/No: "
+ 1 dict dup /MediaWeight 80
+ put setpagedevice"
+*End
+
+*ThickMedia Thick/Yes: "
+ 1 dict dup /ThickMedia 120
+ put setpagedevice"
+*End
+
+*?ThickMedia: "
+ save
+ currentpagedevice /MediaWeight get 105 gt { (Thick) } { (Thin) } ifelse
+ = flush
+ restore "
+*End
+
+*CloseUI: *ThickMedia
+
+*%===================PrintColors====================
+
+*OpenUI *PrintColors/Print Colors: PickOne
+*OrderDependency: 20 AnySetup *PrintColors
+*DefaultPrintColors: "15"
+*PrintColors 0/None: "1 dict dup /PrintColors 0 put setpagedevice"
+*End
+
+*PrintColors 1/Cyan: "1 dict dup /PrintColors 1 put setpagedevice"
+*End
+
+*PrintColors 2/Magenta: "1 dict dup /PrintColors 2 put setpagedevice"
+*End
+
+*PrintColors 4/Yellow: "1 dict dup /PrintColors 4 put setpagedevice"
+*End
+
+*PrintColors 8/Black: "1 dict dup /PrintColors 8 put setpagedevice"
+*End
+
+*PrintColors 15/All: "1 dict dup /PrintColors 15 put setpagedevice"
+*End
+
+
+*CloseUI *PrintColors
+
+*%===================Monochrome Printing====================
+
+*OpenUI *MonochromePrint/Monochrome Print: Boolean
+*OrderDependency: 50 AnySetup *MonochromePrint
+*DefaultMonochromePrint: False
+*MonochromePrint True/Yes: "
+ 1 dict dup /MonochromePrint true
+ put setpagedevice"
+*End
+
+*MonochromePrint False/No: "
+ 1 dict dup /MonochromePrint false
+ put setpagedevice"
+*End
+
+*?MonochromePrint: "
+ save
+ currentpagedevice /MonochromePrint get
+ {(True)}{(False)}ifelse = flush
+ restore"
+*End
+
+*CloseUI: *MonochromePrint
+
diff --git a/gs/lib/cbjc800.ppd b/gs/lib/cbjc800.ppd
new file mode 100644
index 000000000..a36d5e62d
--- /dev/null
+++ b/gs/lib/cbjc800.ppd
@@ -0,0 +1,389 @@
+*PPD-Adobe: "4.1"
+*% Adobe Systems PostScript(R) Printer Description File
+*% Copyright 1995 Yves Arrouye for Aladdin Ghostscript with Level 2 PS.
+*% All Rights Reserved.
+*% This file may be distributed as part of GNU Ghostscript and/or Aladdin
+*% Ghostscript, under the same terms and conditions as Ghostscript.
+*% End of Copyright statement
+*FormatVersion: "4.1"
+*FileVersion: "1.0"
+*LanguageVersion: English
+*PCFileName: "CBJC800.PPD"
+*Product: "(Canon Bubble Jet Color 800)"
+*PSVersion: "(2010.351) 0"
+*ModelName: "Canon Bubble Jet Color 800"
+*NickName: "BJC-800"
+
+*% This file is not complete, and may lack some useful information...
+
+*% Note: the default transfer function should be set to Null if Ghostscript
+*% exhibit a bug making magenta appear while printing in gray levels...
+*% Note: if you print on A4 paper by default, change *Default values (the
+*% default is Letter here).
+
+*% ==============Constraints =================
+
+*UIConstraints: *BitsPerPixel None *ColorModel DeviceCMYK
+*UIConstraints: *BitsPerPixel None *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 16 *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 16 *ColorModel DeviceGray
+*UIConstraints: *BitsPerPixel 24 *ColorModel DeviceGray
+*UIConstraints: *BitsPerPixel 32 *ColorModel DeviceRGB
+*UIConstraints: *BitsPerPixel 32 *ColorModel DeviceGray
+
+*UIConstraints: *ColorModel DeviceCMYK *BitsPerPixel None
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel None
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel 16
+*UIConstraints: *ColorModel DeviceRGB *BitsPerPixel 32
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 16
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 24
+*UIConstraints: *ColorModel DeviceGray *BitsPerPixel 32
+
+*% =========== Device Capabilities ===============
+
+*LanguageLevel: "2"
+*Protocols: TBCP
+*FreeVM: "2124600"
+*ColorDevice: True
+*DefaultColorSpace: CMYK
+*FileSystem: True
+*Throughput: "1"
+
+*Password: "()"
+
+*% ============Paper Size Information ==============
+
+*OpenUI *PageSize: PickOne
+*OrderDependency: 30 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize A4: "1 dict dup /PageSize [595 842] put setpagedevice"
+*PageSize A5: "1 dict dup /PageSize [421 595] put setpagedevice"
+*PageSize A6: "1 dict dup /PageSize [297 421] put setpagedevice"
+*PageSize A7: "1 dict dup /PageSize [210 297] put setpagedevice"
+*PageSize A8: "1 dict dup /PageSize [148 210] put setpagedevice"
+*PageSize A9: "1 dict dup /PageSize [105 148] put setpagedevice"
+*PageSize A10: "1 dict dup /PageSize [74 105] put setpagedevice"
+*PageSize B5: "1 dict dup /PageSize [501 709] put setpagedevice"
+*PageSize Letter/US Letter: "1 dict dup /PageSize [612 792] put setpagedevice"
+*PageSize 11x17/US 11x17: "1 dict dup /PageSize [792 1224] put setpagedevice"
+*PageSize Ledger/US Ledger: "1 dict dup /PageSize [1224 792] put setpagedevice"
+*PageSize Legal/US Legal: "1 dict dup /PageSize [612 1008] put setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 40 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion A4: "1 dict dup /PageSize [595 842] put setpagedevice"
+*PageRegion A5: "1 dict dup /PageSize [421 595] put setpagedevice"
+*PageRegion A6: "1 dict dup /PageSize [297 421] put setpagedevice"
+*PageRegion A7: "1 dict dup /PageSize [210 297] put setpagedevice"
+*PageRegion A8: "1 dict dup /PageSize [148 210] put setpagedevice"
+*PageRegion A9: "1 dict dup /PageSize [105 148] put setpagedevice"
+*PageRegion A10: "1 dict dup /PageSize [74 105] put setpagedevice"
+*PageRegion B5: "1 dict dup /PageSize [501 709] put setpagedevice"
+*PageRegion Letter/US Letter: "1 dict dup /PageSize [612 792] put setpagedevice"
+*PageRegion 11x17/US 11x17: "1 dict dup /PageSize [792 1224] put setpagedevice"
+*PageRegion Ledger/US Ledger: "1 dict dup /PageSize [1224 792] put setpagedevice"
+*PageRegion Legal/US Legal: "1 dict dup /PageSize [612 1008] put setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea A3: "9.637793 27.096094 832.437805 1181.496094"
+*ImageableArea A4: "18.425196 27.096094 576.625183 833.496094"
+*ImageableArea A5: "18.425196 27.096045 402.625183 586.496033"
+*ImageableArea A6: "18.425196 27.096045 278.625183 412.496033"
+*ImageableArea A7: "18.425196 27.096045 191.625198 288.496033"
+*ImageableArea A8: "18.425196 27.096045 129.625198 201.496048"
+*ImageableArea A9: "18.425196 27.096045 86.625198 139.496048"
+*ImageableArea A10: "18.425196 27.096045 55.625195 96.496048"
+*ImageableArea B5: "18.425196 27.096045 482.625183 700.496033"
+*ImageableArea Letter/US Letter: "18.425196 27.096045 593.625183 783.496033"
+*ImageableArea 11x17/US 11x17: "9.637793 27.096094 782.437805 1215.496094"
+*ImageableArea Ledger/US Ledger: "9.637793 27.096045 1214.437744 783.496033"
+*ImageableArea Legal/US Legal: "9.637793 27.096094 602.437805 999.496094"
+
+*?ImageableArea: "
+save
+ /cvp {( ) cvs print ( ) print } bind def
+ /upperright {10000 mul floor 10000 div} bind def
+ /lowerleft {10000 mul ceiling 10000 div} bind def
+ newpath clippath pathbbox
+ 4 -2 roll exch 2 {lowerleft cvp} repeat
+ exch 2 {upperright cvp} repeat flush
+ restore
+"
+*End
+
+*PaperDimension A4: "595 842"
+*PaperDimension A5: "421 595"
+*PaperDimension A6: "297 421"
+*PaperDimension A7: "210 297"
+*PaperDimension A8: "148 210"
+*PaperDimension A9: "105 148"
+*PaperDimension A10: "74 105"
+*PaperDimension B5: "501 709"
+*PaperDimension Letter/US Letter: "612 792"
+*PaperDimension 11x17/US 11x17: "792 1224"
+*PaperDimension Ledger/US Ledger: "1224 792"
+*PaperDimension Legal/US Legal: "612 1008"
+
+*HWMargins: "9.637794495 19.842518 9.637794495 8.503937"
+
+*% =============Halftone Information ===============
+
+*ScreenFreq: "60.0"
+*ScreenAngle: "45.0"
+
+*DefaultScreenProc: Dot
+*ScreenProc Dot: "
+{dup mul exch dup mul add 1.0 exch sub }
+"
+*End
+*ScreenProc Line: "{ pop }"
+*ScreenProc Ellipse: "{ dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub }"
+
+*DefaultTransfer: Normalized
+*Transfer Normalized: "{mark
+1.0 1.000 0.955 0.915 0.847 0.765 0.683 0.602 0.500 0.311 0.030 0.0
+counttomark dup 3 add -1 roll exch
+2 sub mul dup floor cvi dup 3 1 roll sub exch dup
+3 add index exch 2 add index dup 4 1 roll sub mul add
+counttomark 1 add 1 roll cleartomark
+} bind"
+*End
+*Transfer Null: "{ }"
+*Transfer Null.Inverse: "{ 1 exch sub }"
+*End
+
+*%==================Input Slot====================
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 20 AnySetup *InputSlot
+*DefaultInputSlot: Feeder
+*InputSlot Feeder/Paper Tray: ""
+*CloseUI: *InputSlot
+
+*%=================Manual Feed====================
+
+*OpenUI *ManualFeed/Manual Feed: Boolean
+*OrderDependency: 20 AnySetup *ManualFeed
+*DefaultManualFeed: False
+*ManualFeed True/True: "1 dict dup /ManualFeed true put setpagedevice"
+*ManualFeed False/False: "1 dict dup /ManualFeed false put setpagedevice"
+*?ManualFeed: "
+ save
+ currentpagedevice /ManualFeed get
+ {(True)}{(False)}ifelse = flush
+ restore"
+*End
+
+*CloseUI: *ManualFeed
+
+*%===================Resolution====================
+
+*OpenUI *Resolution/Resolution: PickOne
+*OrderDependency: 10 AnySetup *Resolution
+*DefaultResolution: 360x360dpi
+*Resolution 90x90dpi/90dpi: "
+ 1 dict dup /HWResolution [ 90 90 ]
+ put setpagedevice"
+*End
+
+*Resolution 180x180dpi/180dpi: "
+ 1 dict dup /HWResolution [ 180 180 ]
+ put setpagedevice"
+*End
+
+*Resolution 360x360dpi/360dpi: "
+ 1 dict dup /HWResolution [ 360 360 ]
+ put setpagedevice"
+*End
+
+*?Resolution: "
+ save
+ currentpagedevice /HWResolution get dup
+ 0 get cvi 10 string cvs print
+ (x) print
+ 0 get cvi 10 string print
+ (dpi) = flush
+ restore"
+*End
+
+*CloseUI: *Resolution
+
+*%===================Output Depth====================
+
+*OpenUI *BitsPerPixel/Print Depth: PickOne
+*OrderDependency: 30 AnySetup *BitsPerPixel
+*DefaultBitsPerPixel: 24
+*BitsPerPixel None/1bpp: "
+ 1 dict dup /BitsPerPixel 1 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 8/8bpp: "
+ 1 dict dup /BitsPerPixel 8 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 16/16bpp: "
+ 1 dict dup /BitsPerPixel 16 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 24/24bpp: "
+ 1 dict dup /BitsPerPixel 24 put
+ setpagedevice"
+*End
+
+*BitsPerPixel 32/32bpp: "
+ 1 dict dup /BitsPerPixel 32 put
+ setpagedevice"
+*End
+
+*?BitsPerPixel: "
+ save
+ currentpagedevice /BitsPerPixel get dup 1 eq { pop (None) } if = flush
+ restore"
+*End
+
+*CloseUI: *BitsPerPixel
+
+*%=================Media Type============================
+
+*OpenUI *MediaType/Media Type: PickOne
+*OrderDependency: 50 AnySetup *MediaType
+*DefaultMediaType: PlainPaper
+*MediaType PlainPaper/Plain Paper: "
+ 1 dict dup /MediaType (PlainPaper) put setpagedevice"
+*End
+
+*MediaType CoatedPaper/Coated Paper: "
+ 1 dict dup /MediaType (CoatedPaper) put setpagedevice"
+*End
+
+*MediaType TransparencyFilm/Transparency Film: "
+ 1 dict dup /MediaType (TransparencyFilm) put setpagedevice"
+*End
+
+*MediaType Envelope/Envelope: "
+ 1 dict dup /MediaType (Envelope) put setpagedevice"
+*End
+
+*MediaType Card/Card: "
+ 1 dict dup /MediaType (Card) put setpagedevice"
+*End
+
+*MediaType Other/Other: "
+ 1 dict dup /MediaType (Other) put setpagedevice"
+*End
+
+*?MediaType: "
+ save
+ currentpagedevice /MediaType get
+ dup null eq {pop (Unknown)} if = flush
+ restore "
+*End
+
+*CloseUI: *MediaType
+
+*%===================Printing Quality====================
+
+*OpenUI *OutputMode/Print Quality: PickOne
+*OrderDependency: 10 AnySetup *OuputMode
+*DefaultOutputMode: Normal
+*OutputMode Draft/Draft: "
+ 1 dict dup /PrintQuality (Draft) put setpagedevice"
+*End
+
+*OutputMode Low/Low: "
+ 1 dict dup /PrintQuality (Low) put setpagedevice"
+*End
+
+*OutputMode Normal/Normal: "
+ 1 dict dup /PrintQuality (Normal) put setpagedevice"
+*End
+
+*OutputMode High/High: "
+ 1 dict dup /PrintQuality (High) put setpagedevice"
+*End
+
+*CloseUI: *OutputMode
+
+*%===================Color/Gray Printing====================
+
+*OpenUI *ColorModel/Color Processing: PickOne
+*OrderDependency: 20 AnySetup *ColorModel
+*DefaultColorModel: DeviceCMYK
+*ColorModel DeviceGray/Gray: "
+ 1 dict dup /ProcessColorModel /DeviceGray
+ put setpagedevice"
+*End
+
+*ColorModel DeviceRGB/RGB: "
+ 1 dict dup /ProcessColorModel /DeviceRGB
+ put setpagedevice"
+*End
+
+*ColorModel DeviceCMYK/CMYK: "
+ 1 dict dup /ProcessColorModel /DeviceCMYK
+ put setpagedevice"
+*End
+
+*?ColorModel: "
+ save
+ currentpagedevice /ProcessColorModel get = flush
+ restore "
+*End
+
+*CloseUI: *ColorModel
+
+*%===================Media Weight/Thick Media====================
+
+*OpenUI *ThickMedia/Thick Media: PickOne
+*OrderDependency: 30 AnySetup *ThickMedia
+*Default ThickMedia: Thin
+*ThickMedia Thin/No: "
+ 1 dict dup /MediaWeight 80
+ put setpagedevice"
+*End
+
+*ThickMedia Thick/Yes: "
+ 1 dict dup /ThickMedia 120
+ put setpagedevice"
+*End
+
+*?ThickMedia: "
+ save
+ currentpagedevice /MediaWeight get 105 gt { (Thick) } { (Thin) } ifelse
+ = flush
+ restore "
+*End
+
+*CloseUI: *ThickMedia
+
+*%===================PrintColors====================
+
+*OpenUI *PrintColors/Print Colors: PickOne
+*OrderDependency: 20 AnySetup *PrintColors
+*DefaultPrintColors: "15"
+*PrintColors 0/None: "1 dict dup /PrintColors 0 put setpagedevice"
+*End
+
+*PrintColors 1/Cyan: "1 dict dup /PrintColors 1 put setpagedevice"
+*End
+
+*PrintColors 2/Magenta: "1 dict dup /PrintColors 2 put setpagedevice"
+*End
+
+*PrintColors 4/Yellow: "1 dict dup /PrintColors 4 put setpagedevice"
+*End
+
+*PrintColors 8/Black: "1 dict dup /PrintColors 8 put setpagedevice"
+*End
+
+*PrintColors 15/All: "1 dict dup /PrintColors 15 put setpagedevice"
+*End
+
+
+*CloseUI *PrintColors
diff --git a/gs/lib/cdj550.upp b/gs/lib/cdj550.upp
new file mode 100644
index 000000000..9e2a5422d
--- /dev/null
+++ b/gs/lib/cdj550.upp
@@ -0,0 +1,48 @@
+-supModel="HP Deskjet 550c, 300x300DpI, Gamma=2"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/Pcl
+-r300x300
+-dupMargins="{ 12.0 36.0 12.0 12.0}"
+-dupBlackTransfer="{
+ 0.0000 0.0010 0.0042 0.0094 0.0166 0.0260 0.0375 0.0510
+ 0.0666 0.0843 0.1041 0.1259 0.1498 0.1758 0.2039 0.2341
+ 0.2663 0.3007 0.3371 0.3756 0.4162 0.4589 0.5036 0.5505
+ 0.5994 0.6504 0.7034 0.7586 0.8158 0.8751 0.9365 1.0000
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0010 0.0042 0.0094 0.0166 0.0260 0.0375 0.0510
+ 0.0666 0.0843 0.1041 0.1259 0.1498 0.1758 0.2039 0.2341
+ 0.2663 0.3007 0.3371 0.3756 0.4162 0.4589 0.5036 0.5505
+ 0.5994 0.6504 0.7034 0.7586 0.8158 0.8751 0.9365 1.0000
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0010 0.0042 0.0094 0.0166 0.0260 0.0375 0.0510
+ 0.0666 0.0843 0.1041 0.1259 0.1498 0.1758 0.2039 0.2341
+ 0.2663 0.3007 0.3371 0.3756 0.4162 0.4589 0.5036 0.5505
+ 0.5994 0.6504 0.7034 0.7586 0.8158 0.8751 0.9365 1.0000
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0010 0.0042 0.0094 0.0166 0.0260 0.0375 0.0510
+ 0.0666 0.0843 0.1041 0.1259 0.1498 0.1758 0.2039 0.2341
+ 0.2663 0.3007 0.3371 0.3756 0.4162 0.4589 0.5036 0.5505
+ 0.5994 0.6504 0.7034 0.7586 0.8158 0.8751 0.9365 1.0000
+}"
+-dupBeginPageCommand="<
+ 1b2a726243
+ 1b2a7433303052
+ 1b266c33616f6c45
+ 1b2a6f31643251
+ 1b2a703059
+ 1b2a72732d34753041
+ 1b2a62326d
+>"
+-dupAdjustPageWidthCommand
+-dupEndPageCommand="(0M\033*rbC\033E\033&l0H)"
+-dupAbortCommand="(0M\033*rbC\033E\15\12\12\12\12 Printout-Aborted\15\033&l0H)"
+-dupYMoveCommand="(%dy\0)"
+-dupWriteComponentCommands="{ (%dv\0) (%dv\0) (%dv\0) (%dw\0) }"
+
diff --git a/gs/lib/cheq.ps b/gs/lib/cheq.ps
new file mode 100644
index 000000000..2e98d0edd
--- /dev/null
+++ b/gs/lib/cheq.ps
@@ -0,0 +1,945 @@
+%!PS-AdobeFont-1.0: Cheq 001.000
+%%CreationDate: Wed May 24 10:41:05 1989
+%%VMusage: 23317 29750
+%% Adobe is licensing this font software "Cheq" to you royalty-free for your
+%% use and not for sale to others. This font software is provided as is and
+%% Adobe disclaims all warranties, including merchantability and fitness for
+%% a particular purpose. Any and all copies of this software must contain
+%% this notice intact. Design (D) 1989 John S. Renner, Adobe Systems,
+%% Inc.
+11 dict begin
+/FontInfo 10 dict dup begin
+/version (001.000) readonly def
+/Notice (Copyright (c) 1989 Adobe Systems Incorporated. All rights reserved.) readonly def
+/Copyright ( Adobe is licensing this font software "Cheq" to you
+ royalty-free for your use and not for sale to others. This
+ font software is provided as is and Adobe disclaims all
+ warranties, including merchantability and fitness for a
+ particular purpose.
+ Any and all copies of this software must contain this notice
+ intact.
+
+ Design (D) 1989 John S. Renner, Adobe Systems, Inc.
+ ) readonly def
+/FullName (Cheq) readonly def
+/FamilyName (Cheq) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch true def
+/UnderlinePosition -100 def
+/UnderlineThickness 50 def
+end readonly def
+/FontName /Cheq def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+ %% Encoding below refers to Macintosh keyboard.
+ %% You may want to re-encode for your needs.
+ %% some entries are an attempt to accommodate
+ %% the German/Russian spelling mnemonics,
+ %% except for "B" which remains for Bishop,
+ %% and not for Bauer (the pawn).
+dup 120 /BSquare put % x
+dup 32 /space put % space
+dup 66 /BBishop put % shift-b
+dup 68 /BQueen put % shift-d
+dup 75 /BKing put % shift-k
+dup 76 /BBishop put % shift-l
+dup 78 /BKnight put % shift-n
+dup 80 /BPawn put % shift-p
+dup 81 /BQueen put % shift-q
+dup 82 /BRook put % shift-r
+dup 83 /BKnight put % shift-s
+dup 84 /BRook put % shift-t
+dup 98 /WBishop put % b
+dup 100 /WQueen put % d
+dup 107 /WKing put % k
+dup 108 /WBishop put % l
+dup 110 /WKnight put % n
+dup 112 /WPawn put % p
+dup 113 /WQueen put % q
+dup 114 /WRook put % r
+dup 115 /WKnight put % s
+dup 116 /WRook put % t
+dup 245 /BBishopOnBlack put % shift-option-b
+dup 235 /BQueenOnBlack put % shift-option-d
+dup 240 /BKingOnBlack put % shift-option-k
+dup 241 /BBishopOnBlack put % shift-option-l
+dup 246 /BKnightOnBlack put % shift-option-n
+dup 184 /BPawnOnBlack put % shift-option-p
+dup 206 /BQueenOnBlack put % shift-option-q
+dup 229 /BRookOnBlack put % shift-option-r
+dup 234 /BKnightOnBlack put % shift-option-s
+dup 230 /BRookOnBlack put % shift-option-t
+dup 186 /WBishopOnBlack put % option-b
+dup 182 /WQueenOnBlack put % option-d
+dup 251 /WKingOnBlack put % option-k
+dup 194 /WBishopOnBlack put % option-l
+dup 181 /WKnightOnBlack put % option-m
+dup 185 /WPawnOnBlack put % option-p
+dup 207 /WQueenOnBlack put % option-q
+dup 168 /WRookOnBlack put % option-r
+dup 167 /WKnightOnBlack put % option-s
+dup 160 /WRookOnBlack put % option-t
+dup 47 /left put % slash
+dup 92 /right put % backslash
+dup 95 /top put % underscore
+dup 45 /bottom put % hyphen/minus
+def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/UniqueID 23368 def
+/FontBBox{-50 -150 1050 950}readonly def
+currentdict end
+currentfile eexec
+06ba7b33fcf5ae0f0b258ced9b9688e8a87f93db8efdacd17ec2401f2e7dac03
+bf5515b9e42d78a8037b743d280529fc7630d62bd4c75492c78fd28b2c2aba67
+9cc93d471b097ea30e29f7c89735dd88b4c3e9cb32e14ef50432a6ab37870a14
+af81e471af496fa0e292e1e8168461acf6191017048deb62dd5fd7c784ba88aa
+a921563b3143218981a38441910687a3202a5135e58ce2ecdf9c2d521c6df45b
+aab245f99427574c148904e2a60104e97e6b05bfd9be9a086246a797a03dab25
+948bf8e7996f70ffd6471eef9faeada641e245d63c4964a38500b4754836131f
+86fc61b1de2e0b53ad441b1446fedcd2c533d44c69631a545c98d4c552e5f0b2
+27b40aa0443f7f88e1d6e5bd206ed737fffbe94e8bf001e3481cca5a45735979
+e41ea918a7c0ca5e26ab946df29d27b5ec2671d8e0d7d31b114c29e48ccd3e8d
+7bc69903aeb804fc25aa2dda700de6ede9fc025f0db1aa478b53fa21ed455ec1
+98c7a20020a077a67b743f563cc4c4e59c2d8253bc8c3ea62d4a870f53b2515c
+8b63b857664ab5f0ad71eb89d34decf825e81c10c3a7e676ddddd182cd6ff6da
+631d2051ccb078bea7b2ffab7dc23ca08b337ecc454a8f743a71512149244b00
+72670c8978396cefa735113500de6cec50ab91084340db0ba24a01672dc3a3a5
+e860df42ef02350778cb8e77b5533227aa2f79cbed414f760d92cd071fb5db1b
+669ef0196c6e95a530c8112a8a3ac716fb913a8a1332a590b46d2e267b97b1be
+0e0ba7e4e8c90f1d37b8c1836fbdc93121c5758a31d3ef4650adc41f253ba07a
+ab0dc45d90e8936672b1a47307903dbcbf8e15b70c862d25c57c6e2727f6674b
+c47ff5eae01e0fe7d182742ac456f986d0eb460f4f7fc2693e37899a04b3684e
+fd57e9b235b339017c36b1ef22f9659a0c7743e663e831be7faa602cff221701
+85b13653ad5269a88da74ed803beb08bc40f0bfcfd7cbc49531756b41171c22d
+aae8ff9a454f9d68df7f4b23409634346d8e26ac2109391398ed37705e2e063a
+065a871b78b2b0d4c74b6e4e42877a4450b1974474dc19437e9e1d8a6ff2a374
+0e399857e4f67056577a19f7e26542fae9a75f1e07ed1869c504625d701fdbea
+392b4b2e83ea3c179991f5dded833a74df4d277fdd119f69e8209be9394473f3
+6d6383a762a518d04812f29ec4bb71f451882e9f89a52114215b31b225db3da5
+eb453e7f4f40861963d6412855582128dcd1677d94df95442aba41d3cdf32f0c
+f1a6eace61e491f64152a57410902642145aca0104350bd8b19441072da5e142
+758ef9a1f6c6e0fe47335113843443a07c68606510af206677e764dc0e319ff0
+93d0fef01274205b370422182765a40ac3d23f4c326a732282c455a0eb737ac4
+11673164b7b35e42cb4be5dd4be49958b2c61a5bcc5a332b917d5525c0680a14
+b7c700339112eb47015e80cadfd5a6484af9201f57f6e15b70c0964ea5365173
+ba78aec0d5a7414a4636090b9eef9d71fa424c47fb191bfaeea8d1d29beebbe2
+fc78ea4a1edb5c325bba25851e72146eab86a69e57b6a4a31bc7a4cad9f8910d
+3394c3a92e5189b3447df2fc1a5add98fb8e4ad616685beb6778fe7d444b5ef3
+f4847419c0013e6689e40860aaf46d77f172b86be22630674ac7d37354098a7b
+08add07f1c48dc3dfd56716c3e126f674690d504fc771beaf5e12e9a32f2a17b
+1f753b50c16bb45e2db812bb8e179f1641147da41ac30d08238141315c211f57
+fe8f9c86a087208ebd350f3d1381187a19850d4c2dc0428889c7776047f69574
+4ac1f676453ea360e0d5b18fdf2b2ac8f9e72369e221f447f0eb55bc80460149
+9e5e501c359e1656ab1bc4699569566ba8bee1463746ca84c51ce83cc98adcde
+48f109d71339d0293ed3104a84287b15c3fc4ae425754f5fd66bec0c9f6e27b6
+ea6dbfdbdbdb3c3aaf935969d635a71a61fb4bd8a8384571c4671c98da20d1fd
+accbcdcdd1cca1f44bdd6ea4827ebcf41ea97147921d6894eff290d1bda74208
+38e9c0453e9f9e6d522dcc5667c1b44f57d60be5239c5e58f4b1e16672608a3f
+68f1b7c3d11f609ed4fe10ab359a5b5a7a9da15b44273fd38c303dad6832ace0
+81e7e85a836e4bd7e9f9149276be282442ae3ce0fa74d29a9b4e56a99aa06f2a
+be39c7f4755745f07d29f9a4522a1a43f11f60c31538ea1a37ca793376ecdb2f
+9dee32abb3fb035ad68e1b24d97ac3004508b514f33b86b6e19ab578c1a891ec
+6a2e2f9cb6f784f2c1372978706102bd273bb721cddb3fa2659ff4485119cc94
+2e140051600bb66d0ae6db27205fc9c9e1c6f07a4eb6cda7adec4d86bfbf0748
+45dd09d9178745f790ef5f5679840deff1cc38810e49066d41743db0b6a087bc
+93307d009dd566c4cc13ed3b634b7f60fd6a7e9fb2774eda2b106d2960dfe979
+c76d0fe4689ce8f4490c76c1064861624d909d678379f9602c2b9df3b0f9abcf
+dab614aec38e22bf064950094d9201c6afa52cc5fc7779b279ef41231546f13d
+f1ef498eae5c445f7691f96ebabef21e7f2d1ee2eedd9846c20b067a73aa2159
+a116bd056e733b00a847a9dcc82ce288f3037b76be87412ab5c0f86dc3959ab5
+85223a2465a11d0bc9b5d93805c5e4466081109f175fae62f82c5012ef4a2c7c
+23ff8004c8704103f0dc1589270f8282f9d5a0f51408379ace784d0af862b548
+1c11650e865e17af7e04df20a4049295e93d32f22c1cc3c39a8626fa343d1f18
+a3495bc7dcab911cff66d60d29e1b45a7f16a477b83cf18c523c288c91adc74f
+e6b3a91445a68313118abd7bd8a0a1ce9290f868f583a3ff80db71381eeb2de8
+e80b4d8d2cf70bcdafc08788ba8cd6cb2b6fd739ef809c3cb2ad1ded30e14240
+a7db077e83d18c867e22ba60a57ee2d825c2f7c8b9054d09d6049255a30c67d7
+3d01bca101e4e93d2e82e14a86f331b501736cdcac5f562d16f190aeecb5fe39
+7b434555d2b8a2bd4d363cdd4a19e69c6bf2e7856e3c9214b0931d392ae644b9
+bec489e739e7e091e0dea23212e398e9ae3194d52f42afb75079a63f9c39f205
+73acb5dc43426f3657575930d5c2a053f7fd5b43f2d011ad74070c1ebdd52aa9
+70961253b0715079e17a8339f7d48c9821bad9b4ea2ea0e03e19fefca01f36c8
+bb91586e2ded2b2fd7512bc9e6787340d78d6d308e8fcafc751707f243fb30f2
+5479cf7e89801c62ba25ff7548892e1e224878aeb4cb1f05287cb7febe450986
+5d8f2f6469bba902a8f7f0892a954d7ab83e600ceb2dc127239d570428fe9008
+ba45c4f6b1734a4019122ccea228571be3dee9302bbb7aff9f4ff06290422f91
+97f61416b4b19c2cf8225cb54dd3e8090c74abbe1080301cf19d61faebaee2db
+9e5c3931c102eab99c20676b1920913273aaf753ba60d87773ca7215562fb612
+5f246db99d0b1381f716a7690efe7ab2b54c072853bb28705d12dc35b3722ff6
+11675754ee99e7323b2389024b7112be202194e142285227bf08270b560fcf34
+2d16392b6dd428e30a10e0d87977a5e6b035063b3f43f4fcaa21b30c90a194cc
+5569a0c060b081a054de4bee53914c2bba4e3376b4a44ca48b58e18be2f84a62
+5039ec6f2ef3a6cd1d31d5eb6692420d89306f2e6a712d3f3220e2937f9c4e41
+33cdae5b6d2a09e0a141fb41d58d5ae2111e74501fe591bd3697d6592db2b425
+0ca00f66be5069fc5800e04fd4c4dc1c86f723c02684b7c353f90c4cffa5fd92
+8ee3d10b9b259048c67c3bbfe026185e8a5e8b097390dac73faeedd924ea3d24
+cf82c27494b4f0d7abb77821408175187ce0e81ee5d672000d1dfdb089864ead
+599f8392cb7a14624c0624d8b1116645ecede619b1d864332d521b0124de044f
+e576158176364601a6192366bfe9c3ca0491c91e53d21845b63b54ed4d1f37c1
+8214248152c57a2bfdf8499abb15e1b9dc565456e5765edab49357464a2597c0
+e4c987620bb512fa33b6c3f643f94e89d83b5778cf56e0cdf6c1721f58c4d3b2
+dc13d5372a854d1b4f0415d37e96f6ba8cc5685413ba4481f2fc489484461d6f
+5e081b04a478b0a09139a26ab2944deb0ea32a61f1e787d90cb55ca1c88bbfcd
+37233d2cc2f7deea0112a9ea83ede40232d5d97e4447e02dc450d0c944bd746c
+8d33b0bf6a190614c016bc96dc7b58835bb0daeeeed1b306326a4c516ef39a43
+4e59f1d5e469678ddfb649bfb3ae3726c2a50e680701812e57f5f11056d3b6a4
+df4be50aa1edab57e5df5f5fa7af30f9fe9627b01871e88637ab68e7d7d9aef6
+7920bdfa66b77bcccbaa2f09cb59496e96a4f7cdd7986e6a1fac884a9c729771
+a3c7ce311151e93138e3e02bab11bdd4b1fc2e7073b5a35bb8601ad01da624d8
+2f578fefdd7f81db5ccf4e4eeabba67aac9b5e38a63ce7c1e591dccc86ccd17c
+f978e4fa9ba685854464de478f113a9be8d6575cbed7d32723a879628b9f977c
+42d4771fe17fa0a4cb918b6565dda1c28f7219851e917806cf7105efe42a9a94
+a76536077b3a9732c01dea56b938803a43f521faa3ab493383ddafd8b159f00e
+87dcd4dd42de5bd113ea2ff055a2153bbb1fcf3b51a85fa18191ff143948de0b
+cf606706cba9afc5db85c4911fd1fe2377f68514a3485b40b91c1aa46f526485
+ca9720dd285b3abad88fe5d9ff2afc628caddd01b044161f6c18ec243028b727
+b2aa343385c848560c52d6fb81791f3a2ff66fcadd3ea41691a2073ef984229f
+07355f8a6a37a9489494fe02c233c4506f440043b4062755f0cf7ff4b32bc154
+dd96fc84a35f0f989a1c668a945a8032980f073469b84002a85bebf6ef17fa30
+d332c88ef5235cddf6a66addac6d66d1f8944d9fdf9e33740c319979ca36a0d2
+02e72221f5fa890d1b88734bf6504ff40a4777b27fab35ae19a46338f9542851
+ab50034d1a515fd8aa550bd7074b283b2206acf1c13da6d3a9430b1dc5463b95
+b631f28aa62edf5d9b273ba803e72145bf0dfae33223132539b0346c9de97ed2
+7e553e095c97f9b3a14da699c383840456823419906b5f4be20337e537e0e8ad
+557795a68d1fd3e6f770b2cceadcf493d19d688e2e80f83d8dbaa95ece47f6a3
+5c028455cff81071c06eeb830496722a588204cbf52d18544b9ad755e21afb16
+7e27bd39aba20041bad3a99c66d6c16e67fee8ed79712f2a0a788c51e8f26d73
+54585dee498403b734f56cc3015e2a88a23dc6890f942690ee717ac457a1592a
+ba7b038bf3f0e6f1e056879cf8d23660d8eb5db01951f0ef32ad2e6e8af7e06f
+b81e7e945f45dfe64a264ffa6e8d9f0b03d2ff2ebe450e8b6d4969e49d0f5e1b
+080eec0d7f9ec42dd64d2f2629db0769590fe62871df28a350379426cea16b52
+db14a5e5c23d13da4084723b9346011ac33caa39886424c31899460a5f35f405
+363e69085db6e55b069ded255dd172fe3df0b0d31a0053e234b3e2ec44f433a6
+7a638f9a55a445412fcf8c6ff4d01fdcf6e012ed305beb3fa0b1752441c56e51
+c30b82300e0b98ff032e3bc4e27d6485741e27a07ea8a131bd7e697e28854ef8
+c58801a100ba86d94ebc1213cb54a81083367f385d028644f213bc18eb70734e
+8de376d680e8b71b530a5f235fb14d7f3d3059862cbb7ea9b6bc2d827bf71744
+87226be663ce0a9feb4f248e28b71649355bde7febf2b8cce5f674f6afea22cf
+f42e98405fd872dc2afadb1d8b1630265913cd5452c7b6bfe516624c16e6133c
+3b0152abf170701b5600882b3a4c2fabe4c9794a4bb48c3e2d9a4c03744662b8
+0ffa2ac877f5a0db47d26d97bece9f04220d7a19f7abae2346016a359f183271
+1a022c704e4bb9bf7215089e7979cefb7fd438fce318f3a900385d6162aaf8d6
+23f50ebd7b7de89e426631b59b1fdc688f36fc81ff8621e7adbc3b1aad6c2d19
+b9995b873acdce08661a25f30f551144e88bf163db7739c67fe4f26ed01fb8fa
+9e0a8628ac2338778249c101bcb667f8e7d37f97fa68a680ebe80421ff943a33
+ddb2dd16c13f82c7100d6d4ca8fea5283518cc9004a9cf1e6b590bd8b9795599
+eb091c682528dcc8890bc45517ee013e146f6e2d37e4b20f007c47fbba8d600a
+63288701ae7e57cb2905f5b71557f2d1599f1d5eda80f59896199e2aa744dd56
+74af44b9b87886ff41240188c6753248d30b7f1aec5520c18589120615e458f0
+65e158f2015098676e62329cbfb76bd5bacbe510ab5cd1df00c4b750eab9bc05
+b2a6d05a17ff8f198ddc48abe338e5aa4280080f5256bca57289511d5206dc65
+d77507048626e2483fd6239bd14d81b4e6ee321c957332629f004710adda7007
+04307317a3daa98a28ae9a788c025aba2e667f28e567678f7dd8e1ab1732e74c
+886e342da3330094619b2a0fb6adb7189c0be350c4052e24ac09c307b4de27de
+88b13f8c3690f42ffc6f9b3a16ea9fd3aad6d2529d507de80a66fb2974f96f5a
+6ec51c306f3253a03720e45cdeff9d70d1383ef21e36f9d9a8236fb90504eecc
+5cf90d24debe60c8c45e12ed3f6a61c29788d1c5cd7cada5a2f09dd01bfd1a4e
+f57202691b773a337533dcaf80ed4dadcbbbaccd19765eff4d7316860502a30c
+b422ebaf5d9b9bb9634abd56a40c0e5d05b1e8b76710abf46d8ae3be97ac19b0
+31f01237a0bf80b474cbfec8b863141298ddcc4bbe702d5cc574d64d21921615
+755553007b7a3e031ece5e2797d72e381c49f4c3976594f863660c1529b461fb
+bbd4da0d101d5f1b7e3f00a0e0611758619f0624fffef8c234c224de122ba669
+2621eee9b5edc20b8071453f3773c076ff8025824aaf89ad9d17024b7bbd3db3
+477635edfff2293a9d9e5d7553bf5fdf6eed19a04bca31837facd884f5fa0735
+b2f244ecc17773995d753c3ec1f81fcf46b9c7fc35b6d8c073fe3700a2924c4a
+673fafc2fc4bb02ec5d7e864176d5c87c5348c3b2a8d5c583196fdf8cf6108a0
+0b0381d126076f5ff5283d05b97b0a21091be3f73860f72b69b3a4dbd19372ae
+b661219c6fc715f06d226bf54805fe97a1b03a69f6818a561a3c789ee6db3af6
+8fe31b152e9c8813a880c08295cb6e6167a145b4ab25e97855f7e058d02fa8ef
+0f828432b6e9436ab01c7c6a320a33d542ca5e5446d08ebd597d8dd49ed5f83a
+b9803bb48daaf7bdf9a0457e4247eb2fc41a96c19e562a5513494350acec5ed4
+75d010b13951fd6c1ff7ffdacc977e1f22da9d11636bd77d80c7742bec079523
+fb7036b4c65f16330cbb06bb4441ba6d9695d57f376a7faef1c5c051b0485d08
+25cf232eb12683489e97e46c1addae9f5147ae117c5744fc975eb90821791157
+110fd856d1bd00c7f9bc1040ae0d83b1ddf572d7d958c1af16549c7c9a498007
+002bc771b5286ba7af2ae748c03e5885407d7a5b56aa55e1d86e583fbbd9b88f
+3fce64f8aeb894babf7521ad50dc5608d04765ca71b0a97ea4d4f67fda9efb5f
+1d67b0fba08ddb711f63e52304e098f871ec1c7e9d58b2b2e58c887122e1fab6
+d3d4b391f3253170ace505c35c4877d32c9c36506cde3ae243d1de6aa33f5e18
+fd129165278045b075c43bcf0ced8580a81d702ba464102bdd123a6c2b2310cb
+c2236427fb40b0f16dbcf46c31019d5beed1e6034949377fd5f7cd57bc04479a
+8b53083904c373a63a4a09c60eca4229aff9209449eb78d245ad1cbf3d831867
+7d60c285af422f15d6cab2efe202a00c5f21635ba36b4bfb92bc54557de1c092
+7a3645afb9dc24dc97030dfffb5606c8db3dc60e35bc6a0086aae19ace912bfb
+c12f209036c0d43f1aa6500f94ba24a0c4db2309a26f0960fe1426f4239d4551
+fc9a87d4add8c89cf7c5e40a181396b68043e0b9321caad83cc8a2a71b51c2ca
+3efe240e26ddcb4d64eb6fdcb0b59ec196361f7897a2a16b25bfc5513129bb27
+24023176e04983e273b0780533fea226cedeff949967b1b9aa9815ba9e1cccda
+bdf873229770b6d02b5bc81a2cdca77d93ebc04b79595d1eff2afd3d6ced3489
+b9d273766dfae70b459d5b94b1182cd11bd4beb370c4ef4d5c551063fec1ddb9
+8761995d160323356be08008e366649a771b54b5bf40f822ba6dfe66dcaa7caa
+4ea1ee4ff8fca8aed14a2966baa5d3db25d0d2cb4062a06061adbb7b2a35b2df
+5dc202bafbfeccae75c27aea6c7230320412c30a993e056d6288935160ef1ed2
+c9f6cfa3119948d4b63e5708cc6923dcd520d8a45a1fbbb34567f322d7a8676b
+8fc31fca3c42b5a5528b5151127a445f34f897175f317579593251a920f0b4f6
+a0d85e4aabf120ed28263706965ae8564bf9fdca5fbff9721299b212d7562335
+f12569804a23475ae1f5ca757b91ea476efb0da9baadfa85b1c33f6e4ff91e1d
+1863aca97bb5b63a07e76a2e0d9d88718871f4e9ff325aa7c5fcfcf40dbeeb1b
+82536677ec6ed3e57fc50270ef1067354719a1b2026927e52d0e3e69521d8e8a
+a0186da08d4cbf91f7cb7701ffe8f63ad558fe50e1a19550d6f769068b96f7a4
+7bf99f865c8b6d0de4c4b3a24c9deaf648c462cdd4892a544430ac0ff0932695
+8a9df434c065161b1adfb008cc3cd949c055fb8a99c7712789321628f72a498c
+646096ad2f24620366f20fa7516c2535df0d3745143b62424254dd79e2f14d07
+ac4e4f623b95dfc1e3dc8a980451f248d55cf6b0257c95f72915c53e710cc7e4
+c770c7176434d40d1e2f6ac378dee3d56599be2e75dbb80b68aa0cb1a9b05640
+2eb87374757ebcd800ee8166a7c14344d534ec43c679f19a3faf0831f6ac06c5
+418d0cc5bd0202c8fb9ea4a4bbeec84746782b34f0cdf595537108c04fb2c4f0
+f734dfc1ab7b6e448c5466e596f550709be51ea4ad3d2e1809406081f24bedc2
+afe6b2f0dc106177f0f23e50a68087b935681700a73687311c047b7a3b959e94
+f1d66a5b9d363b07946af750f7c23c88ac57abe52753eee2ca1738ced53e343c
+d7147f4e518e410268717ea1d47f935e68e37f1393f4643295cf9fe6bb6a8e4f
+24eb7d36e5a73e95668dd0484b43dc7fa7a2e1a4771439af53b8292d4dd9ba0f
+87090fa3fc1412e99fbbd9293d622389feab98221d1d17783f4e98f438807085
+f1c5248b0d6cc84306cdd2d6b4b49859030ecca03a3bc135fd0e2e0c4dbce468
+b2fb4d3149b24460809e7a40e7733fc69ff9e1f5034bdbbcf54b02de9ba72d97
+3e02f2391c4ffaad4155684839c9a1ad84259f7e0e0870b443f6065a9e6ba2f2
+5d2b7ed4ff02b658fd881882183a92a619e23b78e368deeac7731942c86e792f
+575e124aba8bc9eb8f1ff27baa023b354cb58a1b4b7bca7ace708aa264079a54
+8a7291a7aa9ce597599c436314f0ce6bd9a91f7d7d6f5fc74311e3a43bca381f
+84343da850a3b97a8b8647428fb3d7675a8c747a364af6733b624c37e119408e
+2b8dbcd0ebf1128d3d622fb12811f6fa86734714fdacd66f22fbbed86e0eef19
+8165412707a465ab93c043d6ace1453d51a027eea5aee64dc20e6b1677bf0c51
+6d988d4c2dea53fd3220ae68b7ba8ec9b4a9e12740610db32c86ff6f9dbbc4be
+c895877b4a50136972e64c5cec736350fcc746b9a35d227e861a84ea1b7a991d
+df9923afa67b38558210e59584be3bc822be7b00f0b676d52860aff3fca1c731
+29ba85e325b7c525bedf73fd53f8cca733dc99afb00c7d35203ec104ab6ef99a
+303c5320a7ae6961e7ad96e49801de1aadfb9a49a4e4938ec5c9866a2a073255
+3a0ca67cd73514e1925cc131a6201522d44caacaed554b6dce99a30ca2fcfbb8
+00b9b263fa2680d678a94aa745d1628c8722384af1a6ffa490b18e3d34d21ddd
+6fb6a7d01123c8071d7325e30c1d0d29c069f00c2b3e6c2c337e4c19c151c5c9
+780d3e2b9fb69473e31406af3d3894edf3d56b15719b27bfbd18bf14e245b809
+f29ecae8d0d23194e99d15e3b3cfe3c6dadfffbf9f33c139f814ba96aaafab3d
+7de097d6ec31f1bae09529750e5a124b1df043b0fcb630631fdcee4fc7238b1e
+08a3a34498bf112ef7a8c543720cbaa77200a40b1cf72b5a6a05d66a0ed37d68
+22533e12b1393da9c1edaad4f2299558c82506af548eaf465c76ed43926797c0
+8c127e349a26c21006cde478eaffe17c59d981f045ae488880e427626ef9c073
+d5c9145af6f127bc9f127f0a859836c56b9f40b6ecc446e137e9d9fff367226e
+73ca9add9ea28abad05f87cac5643bc07e91b82e0b35b36626444dfc50a6dafc
+c37d6306d441ade0b998c7c98dc259e40d974a22d8900263f9421d506386ac95
+c1c00fef532fe5641f4cacd814ceb9cffceb23a219841e9e1b6c465ac9fcf270
+5408cd925a37ee97c64894e02c73d0df87b382622c074734a1e2370aa4a2642c
+1fd382156fd054f3a5e2f66a623e396cf56f44273eccb27b5d11170338d4cf27
+3f61f8effe3e52b90bd1c49dc15e8416f3f1f839b2a5d900ec8a33b3bd8c3ead
+6f51f1d68dd4e4202021adb52ce62191f848273c485a5f88dc1c09952bd38ad9
+4d0d9c08cac17187e36c4bef849ea1b5eae2c15ba8a299e9fb3e8d7353fbafa3
+0d7af0f616bd16a11d8e98b7c5f39155b2c8bc3a360c89961ab212a8520db33f
+763c7caead9ed5815351fcc2026a35646336a498ff3bfc6a074e90f0395ff802
+48c1a6b403c1e57eca7068453f149eb8c5a6c1bd980a0215d90b9825372d8d3b
+3fe32871eb3b517ed6e20e30477c0433de4d2cec73f7d7773210a10c4932e909
+eff2f2f83896892eb69f7d27014b55aca65dcc5e8bc62046fcb80a2a24a52165
+77e8ae37ef099a4dab23cd5979017ad30872aa6e94b2bf4e4d7f495f2eceb4f0
+b6d258f94077d191f62dd3f96f94ab43f4ec19a0c1182c13a8ba469601ff148a
+57e007c07b6d305e3bacb2bc0a6708a1b17bef4ea41982a321240ef969390985
+d83828feea903855db4ed66f678dc7c5d6ab49070c4079106163e37cd1144057
+c781dfd270ee40e3c13b5d74f52324f85c84e55f750298ad9f145759c26b4528
+8e707897bbb2aed1037f30d37109a784174cfd5b0aa698c1e79f25d09c603628
+e23a3abc8d6ee13777f7f5f9e27cf34b97598d3d5bfa96d2499e91e2fa7c505e
+3227f8217212bec21eb2f31622a28d292429ab899aaa92ea40a4ca1033217f4a
+ef6666c16305389f149449a44a0adec2899fe892fba9d88b635668becd219657
+02d4b8792bdf922e4342dd5d6d27dd7392a427f153ff35552140a01d7dbb14b7
+57da81569ced971af93e59ec7a6927843ece2a555a58532c4a5c0c5aa2d27405
+72cab4d7f7b59b45fba1c9f61115ee87574e374554d2ea0c7bc7ef0a07843e37
+cfc76c2baf0bbc7d58a95b70f7ad9d2c2c1cbacc6f5190e4392fc5598792e623
+4f89f3b28442b8d37e3cc2c612b29f960005e68198ccdc8805d2887d9e9fab27
+70299a4eae741dca4c983967bb2275ab152a58299a35457759619c6dc3b25eab
+68fa0ed545b09833bc269e15456c018ed4494d2c8529f176a03b340fb3d39c45
+726f023eaf1cbb5a0c776e2a65b77db5a17e47f75c0debec46166e3ad2804efc
+2e41259900f9cbf3dde0d6b1ee4f16964e1f3df0c332021504140bb87e68694d
+f8046216bc50fb9d7c68a5870ca8ef17d8d543dcc872a32d6421c5b30d561efb
+e55607c7e21669fb949aee071954491d5ed28c97304eedb5941fc51aec6b7d4c
+fb4efd4d49610ca7779e0c384e3435e4e9ad4346616667794b925d638355d76e
+a0130cc84045ef68a6f45a9839d642faec80a9b817474fa8ecf3176570bcb441
+e9b7450ea2d3f2d5586db80b4218d41c3f256ab8d7bed7e59458b91872f91ceb
+fcfad2965a08a73861fa7388dd75cac1924c202b26387b6129e5ba5830b9e88a
+497c7e94c61c286ae8f4d596fee7c17ba5635b829029ff837c7d4c084df29bd1
+b318d69d487a679988ebc1751d7c944b83b6b44824cf91246fc75de3d8a2b092
+d1946b845f3f5ebb0b9b043215188cfe3a4f34fb4fd0d6dd89af38c49d8309f1
+b95e43c6e5a48a4684dd826e526d8bfd8318447b57aa8c210753b55039c057a4
+4a35faf9efa90f25e9c5336ac001e71374dd7e45588759e4c0a2689d82870948
+68f456a56dac56b2f0f60a1b7bd307ef18d7d86a3d0fb8e4599524341d8c57cc
+3f20e4840cf87c11929718d250faeb37a28a5c230e9aac9abd7f0339d4128c54
+eb3cc09e4ec9eda06a4687cdf21d1f117e63aba8fe5079e879eb3d1309d24761
+32dd8f3ed3ec6a3ecefbbd5eddeab99521bd87f39f20b19ed0cbee4fbadb108a
+8a25aef0f277ec0c2d49f30afed6975967c513a0772d8a1176d3a4e0a7768321
+2c85b1cd14ac7825d029b02cdecca22e891f3579ff5ef8304e74cf3dccdcb3a7
+254134118665dfbdff5427c0471b7d7c2b64118d995734a9cb4495bd347cac39
+8805fe76a5973959645a471df1bf99cd333f8a68815706fc4e365de7b496160a
+4aba0c061e8509a1b39fd0f2582f813d21daa11c35a5350036dd993e83ef6c41
+dd17d079fcdc56e9bc4b1c0afd6eb855c7d347612938431ae72bceb78aab6efa
+5ccb731cc337171d3e591140e9ec3436bb12ff9b39ee8631de4a6934bce1a4db
+b61aae9a226e38b0db3afd189165d90812e6a8e74490e080d2d79eb010b96bc1
+548062cf654b1b627b7a8faec8f496cb6898635e123651996d2cb52afd58c014
+ab44719499d2eccbb5378666d6a0b14f8c336226b55f8e4fe55c975c84eda8b3
+cb66b0e4372f23966d4a1ec8e7e2333acd6f7a18423ab867dd5572e30ee1028c
+8a172ab879715601ccc59e4431f3a1923fa3c5f79e1ef8ba28b54ff006bc380c
+db98623bbf0604a247e87888a62fb03473a98e06c9879f158484d243b72b4d3e
+04573192531beffc3202c5740209da69deeefa077d9497e9c5d2309b941d8397
+2d9f88eab63fe121bd4658a3bc09677772f7f63d27ee5374adf60c1cb4f37a43
+355567a8649aa36d60bb14b0ed70932de29a7ec4910b836fcf8662adf5d80f49
+362ed0e804b459be1c5315d4070b61bb6d1296a5a8b2516b11dcb8dfd0bbb426
+c5897ae6a20b531f8f251cc12bb52ae6406ddf28d77784229ce474b8b72b4329
+97073759a48cc211b122ac6e29e089d75b81a983c4c9aee019e5cf78a4c77bca
+b335eebd138ba85807b57bbd7321283d1cc1793721189de7062dcae2c3533402
+06426a9edf0844911997187917ba23fe1d0718acd5c4d4ad8c2819de24db6ef2
+b2cb9701789ded9938eb436641d998078216ebdb97c418428e99b6abdef04853
+bc270a8bd461065d26efea3434e7d3b52eccd21e07f526881b3ea123e3c2329a
+056ed88fb4089b69abb3746877771817f2fe9bb6728a7eb3fd2e64761463ac3d
+669ad3d8928451303c7d645910521533282982bca604677f2bb2988b10f7b848
+2114cf7557798ce13952dea8adc2c68397f100a0ce55f5b790c6b8ead46fe7e3
+6e958c634bf76423a7a87c9448e0824f142d0a64ba8215e8cbc0da34e79d8589
+cc9baa0f29410ca4162c027383eb8260a8705f7f1c2c7676aeec54c4e0c42b08
+5b66dda1c9f7984877dc5219fa062d884266438b49c4a9aa6a1c469440c75a4b
+ae1f5362b78a3c9f74181f0f28b0354af3c84affd618a156a3aad277065fc6cb
+ffcae5406758d4add98169fe89d3e21f9d39e00d018da20350599a441b786cfe
+74a43b7bc4659b5904b02ea88638622bb0096ac3b47af0476594fd3ca6753f65
+357d504941120a2aa326d006e5a69c6b806d3a0e928b926e253dc81ae13b1dfe
+f4ddc4709ff15ecd4bd41b88d8ac189096ed4c56465d3dc7b76ad19f222f7397
+52426640589f5c13136131d42b814a8c40d6597572e6766dced40ecc45059318
+5cce8f0121abe54423c3b28e103a8660df4fbb1b95aa2ef9a9cb0a1253c49a94
+f32be151957c11ab2c0d522f57b245edb047eafed062c59ed0a6b82687caa7c9
+9b203a1c30ec063b4905ae31f0118f800c6c3f7759cdb6b3f043af3243b8ba8c
+cc383e27aaba6334a74868e3f85d9a4fed0550257ef85cdbe8ecb69e7a5d7dc9
+3bfc2ccfc997e74ca7714fd25ddffb54650d15417471c95360ce43693abeeb42
+5804a13f77d03cc1b53084ffdab17f068e4f0c506cf6343b928251165853f6c7
+d337f6c3bd8aa64c57156ccc69050130f1206cbaff5f2202b8a17630d41b7b62
+0c4c276f8c6e76a9228b1756aaa31b87598b29d2bc5a268b45ee3720261cab35
+e5997e262ccbd3c464aa67d0074f1c4b04c786ee08c05d643e01acf498be936c
+d83bf1800d6f30a4b5d7a08c15fb036d4e053e436c9260891534cbc3c8eda536
+2cdeccbc03a423e0f2e508ab719f6bf7c274d8ee7740b79b13a505102acdd25c
+50637a1c6b75840b12e6dc77e1befb1b6e4f3877cf2e1c2ddc399e0098093d39
+c8951f6e32c75fd6ca02d74451fdf614a55007b0bd7b920aab1cbf2de7eb072a
+4d57fd5734e35cbbf8b5693fa3a09e5842d938b609110d33b63dfa6c31bfb1d0
+7696ee850223891791a68294433e6b9d733eef2683785694539e5c9d34d5963e
+22672ae0f47061e450c62df0596aa5742d7d720906e6d8b6002ba1b01a8f0732
+5aa66cb81ec1a2009f72790ffbbf58a0d6838a934c41aa1e9d34edb183e4715d
+e1025b0a03a2b4d3083d5dc24bf1656751ff0d50ed96d3d03ba155a1de7ba075
+cb09c98ac1f7d7565fa3b826d89c02b966b978fd33ca5a42cb96345f356ee8dd
+d392b5a04cc3333002d469e6e1efde17df13d5d2037545694b428a6a3706e769
+6d31cd8cf72cf7245865818fb45979507b876a83aa961312a92bfd0fea3f0037
+a3025364dba8603907e6f3641a4823a1bbc556638b27133a0071790fb8fcbd0e
+abcb83a258007bd8e2fa723b72fc36ede7e4745e67f5ecd38db6278901e4559a
+efb6761215e98f2dec27a53eb6a5090030c74c57d1d1b1a29f0a578ce26e4682
+bdd7854c35cf5690514eac890d2dddabf2b6aa6b66304abc6b9f012d4c70bfb3
+a3ba42cb4bdd4f3550172055a44dda0cec627935ad8d96aa1048ca98256417a8
+c56462c7ac76f1f7977d51a5a65c2ad9bc3115a0728235fcb438f18cf370e880
+684c90971014482b2ca100d46d3a3de6a16b75c1d8e9c4949985b753c4256ef2
+49aaa058a2d4795774325e21f92fd0350dd2ff1a3ea9f8f0e9142a4757b7e926
+8c8ada143c295cb86a21afdb5260b4afb8e3bb4a0902b9d4fe09e3b0a187f7d4
+bd129264d0f121a3e0ca622bee85bfef35a039f29ff88131ebd4ac4ee473773d
+b5c0a258efc4a51dc8582089314ded2ae3d39c42f5a733585c5b32343e23681a
+2c5207e7b8c1477e09a3f131ae893172b7d2ff21d7bd5e67e1fdce06450b5406
+0b163a8c31674c8d6749d270a15117df4a221fe98463eaddadb4c8c8c8638439
+bc34c47fae4ca32e13579ce1fd6d5448bf23fa791905adab3e42aeed0b5bb6c1
+1f541b58bc1355288c4557b690ab27616f462fea63bd490e1c481338e9d7d68f
+daf78b3fed65606463aea70d124b4757f47db307487a0360d2a422dd6aeee042
+27a9f57f734e233a4153fb652c06ee776a4c64991cf2d3e69c90ec4e797273a3
+d1339ddbed5e2810f5b54aa0b611ca5f1565c3cea89bfdd721151f01d625f07d
+0c551db5db902aa5fb2027c8e5513f2000bb5d5e33bd99132536d3e65fb52c4c
+424688691e4801e9d00f29a61dd7493228a9a3c137bb298257714ef0ee4f9f16
+87f0fafa42a93bf619817a73f292ff65941ac480bb3f9e4a5612a98e24a5373c
+30b5e0a5b5d4b55221199eb4f5a6f70b7330a182c3c195229155f9d3ed4d7fd2
+f08cef3911f7ab70cf3d7d4b7dc302623b383a236f3f7c985ab4828709ba1d4c
+c2a0e4daca3ece4c41e53a853c98e7e840c59614a88fe1227be49c38154f024d
+83c4f0339c7f1afdee7b6d58c003359d1bc4f460468448222c26258d81b1844d
+40283e5db7bb6baa955d9effbbe88f9981bd204a79da80206033a5d3c0c1b8f5
+00ec8a79f2472396493eae9ebeafd1662b941db3c23e3e820c7e8f85988a2a53
+7d955f18d7869632f498be0d6f5a81fe7e6727d8e6d0fc88cafa99839629c1cf
+b7ac3cf2b21c43da3f07a3cc1798909400e840f4f48bcd3e76be4f94d9f38ee7
+f480e76021b36b9306c16a51ec9bba0c6f9b98248f17d49dddfde34226e33622
+c94655b5afa1c372d4463bc68155803096a36b6cffb7cf261100a46c0ce8bae0
+9fd42e392888bc3431bc9212de09437d3b7ff15fff9320fe11b2a16adf4f8350
+564725a52e4183b11b06166e8ca561d4913fa14603baff5169b44ab1f9085d2f
+0111e4c3b9f6f72f92b61a915f4b6aff97b5163c5e131f1e0083a00f45e5eb57
+3b5de28f5e51e6484af6eece850985170fae9a91040fd860faf7b6be1fa851f8
+2740f3f32906c221796fef28187ada916dfebc65e327533b83a9a63d164d8b2e
+6a6d834bb6390399d564c91c1b998ec5f992d280ba2538098b91cbfb09379f9d
+c35deb26723693e7ce021f80792262a4d2f6e0f9a4df9f5286705c04f982ec57
+f10d2ac027d949cc4b62304d987640a6bda12acc60644983811ae225a0869ee5
+d5d92ec5ca8571b372033c63c402b0c671c63c3677d129837e6e75528351562e
+bc2f6fba03df82eb600e57094c370d1dc844143b30b7d5dd0f7e20b4dabf379c
+6a2e401a6023773c8b85ee50e1949476341338f3477113e8deea7096b8255aa4
+1fc4bb718842713425c6385227e6fb1ccf1f3fe89cd7f7f153a8132be0fcf7ff
+5e30259022e09ab8a3932cc33d1cb4f6d3e299adf4c15ed0be59df30c1d5ed5b
+471ac14fc7b10192ce7d55a412628142ba12ff9b39dff0cc18176e9693ecfcf4
+452838dd87cc9059f1aff608182b12d37ad5c13ad77ada2114f1cae0951a4d58
+725b18973e4c5c3ce7d4454aab91090409fee42d3ccf5d09cd768712e2a73b6a
+4c134b390e0209773af69e875de4f7903b65f8ac253eefa28de825e83ff35b5e
+7357ae7de5445bc6e2022b3d4c161f3697b2ee9650552271020b06f802f5a418
+d20dd1def4368956c713a197321b545625093fab4cb41413f88b6ed006c8fd54
+296ec46e4834ced1987ce6739f21631e0b79de38542248c7afb9e08a9e8f68fd
+243f7cfb11767e9e4647972dbead5ec136764ad4120e1431b38e2566c0c0bb81
+6117d1d5b188935ba2924653feb532cc4f900f7e81e2e6278a753fcd50fd04c7
+3b0edd77747e070c2bd18ceeea2eae31dbaa343678b28b05b037c7b6e604d048
+394b1e694d23096040a5e709eca5a8755a2f15df09c607843d8abdca62b82e42
+5d0dcfe5bec63ffabe011e9aae3322228a26b0358d7c6a740cf91c526d847b84
+87c084b7f813f6870a27535b9f727253a9c41f502ddefdc210d7367371a8a1ca
+6dd58d8a7234bd5457772728fccb21f82b1b5d1d8c538661c92fdab651e02e56
+766e16d58fb6ec299dd0fab458a79ec777eefe57ef9919b5f966c7de075c87b0
+f624e4900d476b49ff754e3029607cac879c150f12b548cd78aa6a6fcf0dabee
+40412bc17072ea2e951b2268eb3777a619a250fa18c1f25a0db6f5b8895565d1
+5ca1a6f296c7a95aea09063c817468ad8c76694f2025db959a3f476c0235f3cd
+2dc07f725c862e3cc9ecad251596061eeb04156fe89cf21589f6e11082bf3c5b
+8d61dfbdbe592a120402983939b99c7d38b4cd32429237421594e21a21841a6a
+e3756576fc0b063ea6a439f193e4f1dd48edb446da9ae6dbc55f0983f0a5445b
+1223abb431e6bb1683c0d07d33e42ff9c37b2d16a0fbc52ea27f53937ebb52f5
+bc7493f84915b1e4b8f5c05441cd09f43e0e5418cc9d82f31ad35a5a69f32289
+df6f52bca5f1fc74b2625a42185cbf40350779c94b75a4b9f551f30439acd9d8
+3f9b79c46694b87fa60ea3af78ab05a65df0fbd2491d8a33710137a2e7fa7559
+39941651fe072f868f92b80792a40673a91776b083156f36bec4a3120d0ddb82
+9296dcb0f5d70028c9838788b84b6d9a84a12dd167eb1afafede886c6e9e9d21
+4ef74aef4a070cc6ca07a88629d15241be5d62e4975b55c734cdbdf872471c4c
+9bc047036203d37cff7a98848b58e6ebc04412dabba494d4bf25ad9e4b4ef4b4
+ee155539af0c4b9aa1b8b8195375f6d5444a7ba34c0586405946b2492652ddd3
+d3e034add236bfa5a8612e8d453736ecef2fca9d8cada78698cbe62f7a7d9611
+f4bf3e04813a874d0e5bab4de5e3c72a98f38457dfbc0852557f6fb9e376e7c7
+1d3a0c9492e439cfecfdac766b7b5c3b59c29b3239726e2d6f672352a15d2aa4
+14d150814d18468a2558a8b86d2642c2b83db6b296b5a943ef70eaf987be7ee7
+de41f5cd1b1280aaf49289de4f4865f6c1a3a303e77b80a9263b142cf080ab87
+8fb6ebcb18a9701ea271a21b287bb8436d780dbcb0f20cb1bf949f080680a92b
+ea81f980230b41311c8f30e9e25f325c92c2fd4006211444a31f80c86919f8f0
+890e6c1ca1ff51741d0634ce4818c9c2f0c553e5e8a17ffa5b834fa7672fe319
+75c0731a3f73a51585f5815419d05a7b10a7e24abdfae5078f7f8f5b34581bac
+224f8d63b4283dbc34a2a1573b5f69eeb158c93e844403f3bd4e7a3b3a4e1e8a
+ac0878ec2eb7c1b7e1c9e6780233608d46b7c801c6c0c83eb67b5d080f4af67a
+7b0ce2d1a392ece3e3a0b71f7f37ee8c333ac76bf8ccadbbe158caa15c6a2429
+9b350ae180c2ce885d870be5d8378fbc05643de7c8da7171ec14c923c59fa500
+4d4fca2d8f85e7ba1aa642c8a214ff8bce3b9f62ef6a4a88c8129bebdcbfe426
+808e6d59b712b2aa3d7edee5e45bfa7aec02429796717995785614d69721ed40
+c9c5a56c5b10e5fb4d5e30d02371ee0b7c7b67d8c7a9fe60b2b9cc7ff4efac5f
+523fd88267950ec3d0640347966f43bd326def79b20ddf0421551168a43c8791
+627a6ee25d3d8a1200c504226211219c690f3e708465da2317bc25baa1e9efd7
+78c9daef857ecbec0449bc16dad92f9f054d68cb91de65caac086e95605ef628
+702bcb7e8dfe538d683263bef330c0d900bbf6f62fdaf663d6d1346274006ba0
+e321644c01e752faa7793efbeede43a7b83173f7f167f3d6fe970acb6646917f
+d36bb285e6d96ff1fcfc668ae4d185d868c898f3964fda9f0463eb6f83d2cec9
+ed861f5027330eefe13163560908a7129990799e21a1e83e814c7df4dfe15365
+ff29765bd346019d69809f425c453ce0a3948fdf3565b83332e47cd65c73467f
+efb2bf3791994d3172dcff4f82a8d7ae4f9fd53664d180d930dd20aa1001a935
+e61e9410667536058ec3fd7b97aabd163f8de60a45794196df0cee18e8c56276
+25217e4002862b3241a017e7b497ba015662ed624d48749b783f69b204792a35
+1212fcf465faa1d4d5905a68f5f17e25ea35b3bb33498162e88f3b0e44d0b2e5
+756156eaf47340a82db8a28fce1e0b26e104295e94ac9aa330a5292167d153dd
+cdc91e47e273eeff554fd652213148655557763b3aef2797df0ab81b202d53ec
+76f5f57865cd1835f7f94515efd2335b966b9e81c76335a29414e4372bc6f186
+7140b735589bac9c6a9203b83919f44ee6c51e805a5bed6d7ffb66c44ccfe988
+59c87bc52021a819b52b850573c5fff13bf7cb9c11f23387d486eee0afca0052
+334f4858f1643f6163936a27c472b8dafcd6e14d3bf3f91eecd70bb7856ef444
+9cc49c7b9788c6c095e968b2c59923dde8ed1628c62eebcd5f32681ced0dccd0
+8e1e61a074c1a78d340c3d873c1eddc97df7051e3d3feb313e054934d4f8696e
+8d617c28f03d817a40572e3630f050091c8738fd3e40c231abe958a9f5868b3a
+3c9120fcfd2dbc319a91289cba50898b43a409cbb612c040d2f33d43ad9d759a
+4cce86ef8dd46945e33caf837a0a7ecfb6b5900204662c56c9cc1b943427074e
+a3a81765d85dbe3ad77bf5c1162900b5f1ef594285ce655ca2a15ca431afcbc4
+6007c144597fbe8ca9638756b3ce61ffa44d524266d2d4c6d6b7a7273625c55d
+56c00242b0ff2a150297e504b9fef2b0b478531e1cc7e1c14ab647dac9feb0c5
+b7b3b20dbfc4285db7745ebb9a3039b230282cdf2a19c1afc822775f3a8026d7
+d793498b915d792bbda081d45f89d9af12967de9e4f4e3779650d7c2dc3cf1dc
+d91b8debee82d3d4fbcca89dd4e129a73968660b457da664d1cec437e17680bb
+7094ab35e4f77fdcf34b40b84b76f8b7750346b1e2f133686110e9f1de217d4f
+8eb81f8d1be2e871ce57632c635189116b9a0a7deaf78d9d6d85178a4f1edef5
+e30c05971c0d6746dd2e1104281b6148217916a8fcb3944217a35b1a98390849
+68cebde7f17a14ccb58bfc1b5440b5d8c75ada3f1a581db2cf6bba553cc32e52
+0b3c5f0a9f7cc12e549f3c65798f74123c5556c9e0173254c1eeb1e094e0d8ef
+35ea280b388b3d393dc9b84e6400abf8493017c5de85bc0c23ac61919a053262
+9a05cf198df82d4f2fb5d6b837fa75bab14bc34c1b46b9ddc4deb67ef4444152
+c280be46a9f0aeb0fdd5e90e8bfa5449bae9315ab5184a01d4753af4286ceb79
+09dbef7f742f7a488c93ed0024ee725686ba71296a18e04aa758742844d37648
+5541087952778948eff1a7521fe37a8ab311c7a7e818841c1d39751430a7b656
+0453c931b40d6d15915b79a73bd0d06893c0cfa0517e76cd9bd87673f7e7fdc0
+317e639f78ba7baaa5f1b43bb52788807b2461e95cd8193414724d954ea066e4
+63f578d9ac9a67822057b4e61241b8b5c8f3ce019c767ea2b84fec80ee642ab5
+9af04e1490b930da33cee816e91a7ec3756343129efc90f36468b8286566fdd7
+3f94d19bbe2076959797ddd83a7b901741578486b79d8102942f71f70c72b2f7
+359de20293952d3fd821f6a164487ac420dbf4374463889ca97198ade2827ad7
+d08bcc071bf2e455b4703891e0ddd950b5f2a11ab246cd2e4bd5401721b8e9b1
+702b439fdc8f1ba1a4ed9ef30a18eb514ec61d3fee9e20822a84c3ea225e5652
+65eeb21129e3e950d1143cfb759f8ac5e097a42fbd4807034c2b375598b6c439
+a2e90d007a1995738c61217224cbb54be3ad5aab1fc60d9f9414146b0cacc853
+4a57c5aa095ac953a6c4f5c16f001cf51c9586a3e67e2abbbd304e5abd9fe25f
+ad3d2ad2c8b193113bdca6d5cbe2ce54fbc7f7f8feccff8eb98fb09dd1e2b7ae
+b2db85d4a4aa399585edfcd485ca6bbde307e546e39856f24d3ce215a5ca1bc1
+b6aba3df0bce9bfb7ada72b6a9e1d73ffeb9dcdbbbb0861651ff71373d040f9a
+43bb1797bd93db1948fb3a28cb446a04f52c3c8ff33ab4a9d87708e0bb86efc2
+db4e9459f7213ad59a61d9d7790d346d7036d36a8aa2599241d59b8130b8a37b
+0242a2b59220eae2c2b7a1b169b1729da75fb682f0d612c007372135fab5afb2
+a6c05076f0f08c198a8178e84b9943ec3c8321e0d5ffdb4e07004e2d17a8fe28
+632cb2949c1fe77b543318c7b107212b363f9ac881c7b868255952cf50cb9504
+9dfdb8d429d7a0f3337db9da3e48be60d69999be3df1093303c88f2bfc2982e5
+5e8b7004b75d5658f681fe30bfb471863a318d7d0fb496ceec4429bf71d9f07f
+32c5af99df3e6fa0095b096a3ac03c9b8009471cae3cdbf81cb21baaca707ba3
+f0bd970b52a4844cfc81cd66da5930686163303bb503cf72f7bbbb6f47b14785
+f6c40dc6518227a76bdfc5f7788fbb79978b6de3cf37e0e4f8b284bf249fd602
+d5ef47d169eb36137bddb00ba693ab9974d37347e9f8f0eb9f06f87d515cbf4d
+003396ecfcf3305e83ea35edd75e05b2b363111f45fbc056cd13d1cee1e96797
+adab632023d85dbbc2fa22e057c031a84f69448fac91d804e40e3d8861b30469
+2fd221c7d77e7742ff66aa06be2e20150f6ba142e6c2ce640291d2374b849eac
+f6b4b970ec408a84c72aa94de175618cb50e0f0813b179066d3e41e644fcc92f
+97558fd8523d73986daa8e1a598b5a151fa10ba8b0795d9dd932948ceb56fa1a
+3b6a96166bdfb663301bdb0a3d559a7e398c117e425e9c9b809995e757c4423e
+ee52c0271a7ed1fdeba6ff0c18fc199b3d73b8441d7d64b4bcd2231375412415
+85e7c8ce647a5b45e0f1378d7948ec1b69d676ead40dd592947249b4fbf8b75c
+36631914cb78d3bc5cf506520d6f9c1cb2e9aaf47a213b804496242a77e7b160
+1be264e885bb92abbd28ca502653a98b811c244cd92de8d9b95a46457f7e0390
+0ac1f0f5f458f5052d069d7320cd09e76aebfae3b0a6676e4de1742acf1e2fa2
+d5369d5670e30c7bb46abc78f1bb601f1b652ddd740261811cda6d6215be2a58
+cf2c798f9a47abf9b59fc32046e927c413de487117ab003c4da86f1ef4a2a92c
+5d1ba48d463b11fc9a455a56010bac81b71212e818f15b498882338b83053bfc
+f2126947a623eec40ec7348718f95aca261e8de0f35b8cbd5f9412659725a2c4
+9f29bc32e865636e1ef039b0efc8443db058159aaf304477fe7c2dabfc81b3d4
+35499d35a59eb97061292996fa65c5a1c1b4762d31046dfe2dd4a33e3f8e390c
+922447ce8ff34f911e68000e98d0a94e9c84ea366eca151a3b9ba00d021367f2
+03bc330c1ce0f955231ba61a54c655d8dd7b271a0eedd56a844bc77181f724d2
+42e49d31778f9fdeaf240c096ee364c1e9945fec04d9b2b3cd256c70390f8f00
+aa80d6608d747053bfb92005c8b204abfd262dc7f7d015f4b966d7831e4a506e
+87cdc738974049daee1e1c945fa916b7d8a04885c7be53d7191ed6839fb61409
+9a9798c718a6e2d96c362b5ae30d79c432279ef0b7c8e1a53e7e7e7be0074459
+f4941bc1b6f3efb8a8a3df0f0c2fbbfadfc1f48fed0a1c9aad6a08a50bd7582b
+cee2ddb5be2a5ce078cc8e8beb8119bd78e320d6890bc7dcb10aeb7b5562b9ee
+7e3c2d1a6b38fbf551cc5a3b60054d4718fbb6c396753ec4c76f99b5ac70d9e8
+29d607bebc0fbfeb7d33e6c876f0f1ae24e25393d501aa2a5b18a393975da2f1
+0e048f2043c45126643b6827d80f45c649f44580845f0e8e8e1a04e743364248
+cbc3891cb409f801a153bb47c4672976c62caf5d87c2bf547d3ba11abdbda794
+6ac66599f6819bfcc0f6ee2bd9d94562322edb6b87a3767f30d82bad0e023b88
+602eed6dcd0b9e387e586aeefdc3a2ccdb482604f556ef16193355c437e382b5
+0b87aa275f70bafdd7d5fdab98635e4110030e18f7ddf58c3978c7967df99427
+592988661029f55423765dcea061f1ae72f3aeaae59400cf30f6104614e62825
+9ba0d0151dcb3f28aa6ff41f16ac640b01ba51627f923386c33013bdae4aea54
+eaeeeeef8da3109e8866aa8aab18217a1a1f890d10df396a74bd0e1057a2dedd
+7986109646d103f44f1581821446c1f8cf0b3bb5ef8bf04b27938a6ebfcd5001
+c67de72985041253e4df6d5ab6048002bf1d16753cee57e3fd8414e43c2ff7f2
+b46e54c389c058073f7affacc5140294666f06e2ad2eae8a41add24dff1a32d7
+3c94032b739009b75cf1b8771764f48d1c57033e9ee582144e4af8255ee0d7b3
+ea36a8208a72147db694e21b144c29f0d07e4af8c01fda6c109ca8612a1a6fad
+3d2308b8b6b064f2dab4203724b76c0ad3df3f6e03eb5ec4f42739173e2bd19f
+8cd09a5b79a6b1d6851af6e5c47545e4273d0be5f0147d68c3af68f59bbbd05a
+b913d069a61831cfaf101c2f2174aa0f1c3daa7a73074611624db7ebf1f5643e
+2c5bb1da08b0e1418733d28d0da8f543e438076eea37da310b2f4e049d7d3a64
+2db23c12150dddd516ad182b31e7549fb791e28cb54b37655d95b3c23c879ed0
+c6956040b8c5bc89cbb2a8473df767ca889a2e1240b735313254e9294dc91e31
+b3ed5faa6f7b4267f70524bf8e81c0aebdd63dc94ffa5742b20acc20ec097eec
+40f28ea5744a3ee3910dcaae093b74e694dce05ac03ed910eccb4133fba37d0e
+99953a6a3e290725d5ee4c10d03bd7f254ba2a4d1bf25e6b98de5c940f6f5303
+2cb0d0f029f0985b418b1f07af698bbc601329f9fe9978e5038e749f5872f2eb
+5572d9225f688d3e9c228f8c793e227bd5a9a28d0d5ce6cae9bb7a8372ff7519
+e40e2bab027992d8ba49458b42abc954fbfce21141a270468b9fdee484a7ebff
+64cf291404eca8486b14d0a5614604d5b80f8eef6eca462f6e672d72908cc3f8
+57550b516fab7e03c4d74245f2fe2c35df1535196170e9653be1b5cdb555cb60
+2d46549c63987b12a4cb569223c13d255ecb9300ba7a38686eab1c0b4484671c
+3523cab620c1d5670d4bc9e59d23bf85e9bb2f57764031e1840437832ed96e79
+4ecb47cb9b8c8f45a922179f111895947ebcd3fe38d2e54eed036ec309f28af4
+1d9964639cab6eeadd23691b8da7affa00b364817cbb5a2f1100bf653ae568e4
+6cee6fd265e715618c4270e482e5162d85cc1125c7f7218aaf555f518373057b
+75e49bd4a6f0903e0c3345337e00a2c6e1ec2d30162aa033016253af30b9ddd8
+c16dbb6e053ff3ce4c5b052f3f00daccf580a0ab2244670597e8dbfd66f3f088
+a51db45be935a2f8042e2dff5424e3804cd135f96cc59da82cfcb7216e7f719b
+a361f655f268616942e7b79bba5d73683ad747440c75e9d07569d8aa38824a46
+b20d8b3bb3e86297d45632d310abb735d92e2ecd158cefcb4a98c93bb3f13c0a
+36af62f165ea7f5eede9cc125600127618e35d12f3bf700e58cae49b05e22c79
+e591171df2f348d5455eb23b1513521bdbb0eb06d5bcb69b982190e63e28eb39
+7da07c06e388ea6229223ee4f14a9c384dfdc2ba0d8f9ff3c5fe852d0d662628
+d103f681fa2b56421d40944ad0d0e750c84b8e6ff963f5f37b2e3116082662bc
+59e3614531463a63ca3caa4af5fa82add2ba8ec478c04cec24104b3e608d0fb4
+611bc75b97c00d1729e8650a636a36861e8f7e6429c8ca0d2f566e73611a114a
+8b8e9f96300bcafde0cf2324243e77fff438811aa9882989a8bd09c385609a4d
+dcb6209312d4529ad9bc0969a05b91e42492cba53b5249a102662e6edac95704
+271d5502666bc5255d35aa2f20e77729e8ab3987b82521bebd459fee449f240c
+6b1d52790b5ea81f4a4cdadb65d89bff4399fce28a200917fffef754fe24b734
+13186717c09a7579cc44b7946d1838026896e2ccc45f41f5b1354f3de87292be
+7e6a7e66626b69c59cb697684023f79f832fee404e3a83bed6aa7376239c326d
+4c30ce5b557e8670fe2ca161d3d28515a89e9d378c6f2b479a93be0584a26d3e
+c35e7a54c2f25589da8f4c0577e177da9564d0a704e1559046299345d7c9f68c
+3ecd1a372bace2ac0321805c103ac438985078a4766b0daf8590e683db158636
+ce4b7c3ea542584d1df38d2d8f0cdb679bd0b5c82423d902ef6f1fcfd746324b
+50128d13ee0f5ac9957188c08b0eb413328ca4f8080d7beaab16cc3aacd51a8f
+03839492b671138f3960de304ffb63286fe91486319e92ad8493045516b4636a
+8e178794903a2252eef2e90806740071b9817742f87e074af21c498fa3f21dbb
+e1b8e3c8146d7973d10dbb2708d5024eba4f333669bccc0a29312420c0dc7138
+463b986f41d8c25950d7ef64a99ffe90f6a3520939de3d0e516a4dc7be23bea4
+74f3fd1c2f2ad8d7ce4c327ffa20710e2bf6c5f815693a5b4025605314f715a3
+9ef8f5a86b7f260c8a6c345840443bc02d700d46bff7ce8667032a952d4063e7
+0dda03de1244830f0ccaadc7062abc6ff41ddc4ed9ca12488904ebed85608c97
+5d0e302df6ebd6c22a5e213d21019ca37446a679eac1bbe0de6317005f955de8
+6b2a301f0c903915981e74f2ef18c4671bec9f12c2595d7f51788d54009c46ea
+e3e1af39badc71cef60d590ca95e47a8f1c53274a7e02c50e21c8bea2001dbf8
+5d787235e5f31bac2d4d489136d9491c83001256948fdcd34eb2da295a775fae
+9e9fccbd0830a99cdc497bdb8cf2adc6bdbb7ff8c150f306e5875378457e79c0
+1a01ff998cc41965862136b37e22ef4d3aa1234bb3419bdc71a43d45f10f879b
+925fe4aa3b48c736f989898c68d3fefcee68ce151a55590d4b1a5312a2558be5
+6066657d53fc820e84fcb162f67de282b513f80d182931c323959377f16c483b
+fb0b65b28215a0dc15dacc09b82551f9a04cba42cdad1dd1aa8871c534e0413b
+5e1dbdd772e4b0eafb21e01a245bfc273b2f8ad00d518dbc35d0ed6ff463c68d
+00165563ec93b156cc00e7f945a8705726c752907283e71ae5bc8e1dd61ca3d6
+dea7fec8928d460243534d16dba851dd77e3176eed0d7b8284718a891a0e8091
+e8525ca038e4a358ba3fbd2089ad33bc7821bf753dbaa23c1708cd6c80fd8e04
+919a230b790ba7e65e2e6c99c6254ce61b1f23466843a12a87d0bb46993d114f
+2cfa18545e813e0f0bcd42fb41ca0bb3843f5324d9f68825c520beb38e34c1aa
+da4aa7c3e03c55fa023b2f4b4d3ae618a14b2b3555de7f2a55a644f2035fa18b
+787abdf31401eef648529e4bd15d9b8e3e3ff5eed76afa2112a32716ca12e39b
+08f6053b68c42944648bbfc34d02af7e6bd35d21127f9fa0a79406f7c2b6d278
+62103da11c6e1cb34512af560b3af2300882fa769716e84a435a9c6cefdcb0be
+e0ce3c9fd5531cd4d66ea9f663889660385423c905663cbbe9bb46838799f9b2
+1d0485547700339b458c605f15f65030e4ab270ae1500e30a133ce0ddefa2190
+23d55a16daf62c8c788432c3b9813865a25edaaa731831ff905bd900434f2d69
+2f8880b60a14c12e99c74bb7550da6b5ce8d2228ac4b44cc7432b1dc58c96e4d
+1f4390a3b6dcba3569110f0d5f98f77289d27feb69b656257aa14edc8bb3c00d
+2da9a4cbbab69bf6ce190c1270be5fc5efc49df45c0b376f081dcfecd80b12e6
+cced2edb8423294bf8886bdba31002f5c673c0ec8772585640feea2a6e17f385
+1cfb1639e697548a5bd849e688ba187bc1b261c60e67cc84a4e5920fb753d5ca
+5db41f5bca801c9cf1daf7b88c866d8c18c117ec29aa7087fc08ac4518eb94f6
+c761bdfae10843c4e6f279d7ffdc2eb36fe38f777745dd255415a9b2bd9c5b7c
+efc7fbebefb52686382f76cfa9b6af9241d1573bcb8e1e7d2243f621380ea522
+a30c94f1b19e21e9f2e4ce61d1597e45aad5e4180b1d7069b7f9f2e9490722f0
+73f8c7dfb9c8f7514d97d18a2f4ad6a49985f7f4d6447bd439a6ed01e198440d
+4b30845005396d3c346450902f88e470141d2cd45b253f8a7fb94342be3f8dfa
+0fb042e016ce042d04f903e36519b2750136b94c1978a66b660e3c79a698abb2
+d7340e9097fc4bd724050ad42cec80696352c3c6e82558361b6421084a509a0c
+40eaddcee7050ca7c43726daacab25ed87ad4c04bfd64047f24d7c8230cba804
+948d06cd0c1aa4fdba32b51f268dc4730b8d65c8b50a4bf0b2a9b43ece574336
+bd1cd5af9a1994f3709aa64583a2cd451e3a787307a84a7a159d34c2dd276b9d
+a351f2751918509502ae9bc0590450916a99ed8b3778d1afed341f0584589c94
+f0dcca7db60869ff3f91493e636c35194d1dc1a396a48bd1f7e724c6ec46db60
+0a4a38ab1535ff3da2c64000dbbe240236143c66cf63742f621896406fcfcd43
+c4822c4d1c80e2f7722fea857c98180318338e1009afcbd10d5b65ecc2796a8c
+14457624bad811cfe85533418fd87f901ae8b760df86e190e0682da9156b7476
+d6b0f81ba0c303e4dcf6607893de4f15b6ff0de435efcf8398dd55f416502d46
+99baaf44e39a29dc7d7c01332922934bb5fc9e5dadf4688f7a997ef9d8deaad3
+035640e40af15329b528ef163ecd867d31d008aae735f7a9498eaf20c4804f27
+a1ced03d39d4ca49791493e0e570e6fa9796e1f9fc79f3f74db5c1ccfa3c53b0
+182c636df0377c95d1d560da832244fdd446df61ed5cb36a2c5336cd59f63d0e
+df7efd374fee9b2d35dc757ad2922bcf7441bb44167fa4c1e47ce46bb63a787a
+90b9377fd9e42548091bae3db4a20bba6c4471dcb335b9b043c318577c96af23
+d046572134d38c2b38fdff6e5eda47689ef58ac2bcc0159d31355d7d063c4bb9
+5cf7a615ba26328a3173163f081c01aef825343386df17f0226890e536fe35c4
+1792b5115f3c92561da144315039f3f03d7eb6f450bb94931ea74ac6455dfe65
+b7c4b4993417f69ee10db426fc86681a697e7dc9abd96b7eac6b9a243cb6bc41
+f38340628ccf7bb442c089beffaa2ef864a31a736bff274ef95ce0cc2a77f695
+edadda05bc61825f4657bc14e579dcf1d05791a1b079cdccf6def41f026d4aeb
+44604cd93e788fde233afd4d26aa71b111e2024e3b271d0e703022f52f635e5a
+371c892ac55cb627caa3f36c14745b5fdf230211e076965f29ce80b102bd0b57
+a0322849da6cf05aa33b10384e32aee2ee65674e554eeac8cc9074b5d71c7988
+929b350b98950f6704c9448f2fdc0e4cd8c2f650be4a1ab53fced3c25a7bee82
+f35fae1c3bfe26407db5e7aceab1cc4b6dc4da552f5cd79ee8d5f068b1fff665
+e6fa41e77db2a0629507bfc547493051d4942405b0f01eb5deaf18dd9ade3631
+184ef75891ce7a1fafda1380d47e55767dd7d3c88baab501cbe0a87352716873
+8137bfb1a91b6c98b52dbadbee01a113655dcb67359a2314099b2866b3261773
+392aebd266a8fb6a11c04f40b345b4382ed8d2a25eabcf4ece87af1900c891aa
+bd5a30cde2f1a0d3be3e5ce534299632521430f12084948a6ae70b75517ff665
+62e9268f2a454f3a10d7e5710f87ab29b96801b4fa815ce8a8acce2ea4404cba
+5ff8b3a56c64ef081a75d664a6206fa341c605683b17d01abbcda227ef3c55a2
+3c56c79194138ea19d3cf3be55ddb73f45d00c4c681b667b8eda54a174968018
+5a5d990820dc716000a49c13d583bc06cff6a8f0f95ba7bb84e8d8673aef8817
+793f4981e1a4f4378958d7388db7ea6c9d1863d153a536a70a229a240aff8194
+e8ac2dcd2ea751a22d00784c7045c2c9d23e5fb214bc817b60425fc3e8a48f31
+e6e8a9342cc134e95c4e59026d9abdfc49900411c4a5d972027ffb7e1662a19c
+56eeb69c9e67040399fd3913ade537cce040b8180c8c9e323a7d6b1e0c7d12f1
+52b135e2e4b589ce34338eff6bd405f1bb1d7ff5c2d7c221bcf320d672fcb97c
+0bcf0649e70bc0f85b0c7462816a69f038e97fd614d97f82cb01d144c0743126
+e8b4b7a34995fbd9d870a22e9ef270926e0fb1f345e3f70f258a45f3c3af6036
+af94b49a7695dfffaba8d00d7c92687ef96b5f268b5ca004d10e38ee997df62a
+cc19ee6387baeff268359df4880fe6a31bd113b4e10464365f31f7a1dd16bf3b
+5fa72f13f53b1a0d61f7ae2e001b475ac61066bed04fcfbaa0dc7aac8dd693f4
+15eed8a4c33b7ae5d845a61c63d382a0b952b0672cccae58110544e7a7329441
+0bb1b2f7283a052228b7da6f5094202c0ed8eb09dbdf2ce10fa5c55cd44a35e7
+085258438bd77317fd7f990c408f4ad2ac594bf9d3f335e505cb3c024381c1bb
+2fb22bac693761ca67bb1b8942103892402f006015466d5cb35492e507018581
+4ff9733b61051f2a0c71269d06af3c2a58bd5449a65a42d008a139c7beaa45ed
+220a233174b00e35c77ee5a5e2995511f17a2eacd575007e666c2e57761e8385
+dba2ef66791e676bdfdc06efac4fbb27ab2ac285295b5ae013026e1bb7938a13
+e1fb9d071ae6f9fe3eb0f3b382695382783fa00c461d622a50ffe6b4651cd059
+c5cf8a359a5a2222b2ae48acea4f258460c8f69283f7e4554d37b18b691815ad
+faab55eabbc37c18ea30eaaf5991d7e06574d94e9b87e631806c1d94ff0b7d78
+701743409efb366d7c405a11819f5472ffcb3f595ec7bf6146d8570caa949cab
+15327fb424c04827148f1793c7041740ce61b521bdb5144e26bfa74be5adb8ca
+b319e3ddd345b30662422673bbbbd23d30e71f6375c29bcd1ec632652f181c68
+efbc2026dae64875e32d6c7d8412c9724b72011f8a6615f972e5d4bd4f92d308
+ef8bb44cd603d22639fcdea9601ac016efd1284e4f899c1f977272926ff61d89
+89fea615693c7ad528befdc4277c2a50f335299cd065418407a0d3698ec60244
+dc7266dbda3270547e90eff22c65e2676a9fae32c088da780b75ea2ddd2bb617
+2eb6b68c19b0435652f8d5d2690a15747d6ee5180654fbee72f84a3051dcd4a4
+eb767370a85995016bac53ab3c0ee44a2e405903e8f6f33c36bf8feb48410d83
+cf3a04681cb878490415f09229bee9ca1d73da791c2c71313cb951713c5e450c
+8482216a71f86f8a541122bea18446797554323764998165bac81b3096796faf
+8538bf83af476e0bbabfa0813feed0dc578814b387a0473badf2da98a5f1a129
+b1385b2e4c9ab79424548e922b91cf56cb3f7a0dca6f4f04ac1ce5d4681d4062
+dc238c93ece3cb0f6c3523d07115a0c7c018a73490d5cdbb1985165ac41b14fe
+de1352571c132e47e16915b04c85e16e57a07fd5aea653ad9491019970546d19
+3caf494886d2c197c8a39bb5ca92348b18ed84814a6fca4b9e07271c13598990
+08c821cf8044a71b89ee6b7c7581e5be5f0167f7f6c39f1e4eae183ac9a5b9da
+9f71945962b981055d138d93acdafe0ff2162eb6e320a55fb6783e4755624762
+0326c12ae49da52f315f90646fa82072fc772a557b777ffbf2cc54c2c2f76b7f
+09531e2890dce9f26157181c69e8fb98d1de277ea3ef5a9653198ca06524ff00
+248413ef8662efd204a4163e39b86c3d7a27f1e81052713179c5a39fea89b5e5
+5f7ddf87911339a827bdef19ab239624e7c0617ec03e0a6fb4fa29fe6e0b05fa
+c50a614158995dfed1235c3b39fa966d848633c5a740632d285edce385929d15
+0d389b43f47da2171ca336cded4a0851470cc086c04a466e4cf03fddb92f9c20
+1f7c732e4a8077527ba27743f9dd4e207b97a1f7cd53778a99f64b092d66f4f9
+1b6a3455a72666386fbc9dd06631a041ae1c63452b5a0480fa75e9a5eeedb8d2
+7bd88740e3d38d5e954d622aacf4342f536ca534cab1e34d352f706b06e04630
+169bc810621d52699cedb96d4796ae1cc28fee4ba7e2223e77faafb9160e3571
+c013b910f1c61fe188625f318ffcc0a10f614d5716e806f14326aad495ea90a4
+4f7bcf589dba538895d4d3da8b5871eeea731f956594bf088a9c4a67794cf661
+ffb389ca93696eb5fb9589aa2c19f43cfeb41cac18b736775017ad51339e5ccf
+de061c17b697242189fe127db52d26407b204a664a4d4ef5428ca588f07d5b3e
+8d19ad7d2437cdafa87353498a304838433dd2b372b15ed83e7969a11f793b58
+40c2d5161aa2f7398f754e2ab2721cfa51915c1795bfdc775012050ac793768b
+960744ec1b1e34a02bd28a03660e0da853be50177e0a22fe9e8355cebf20ee28
+332ac812ab318ab5a391fe54f18fb88d9effdbabffc20ca9a16d9ef29ea37b8d
+5a10f7d36fb1e102528c65f9535683cbe3e31a5d5d1274ec5c7e57042b9b5126
+38015154d7080dc6068f4a5cad76cd02ccce389db91c27d9eeaaeb619569a4da
+f8c6375fd2e2876111e6d481192007eb92f84674583ff8d706e922d31e97178d
+1a0e968e64ceb0a703df1e3de767135b655e569c6fa83e1713b15532205a736f
+cc3899b0df69a87d53a2f065f69988b35cbd395427bc6e6b688cc3d4a11bf0f4
+311b75cfab9955f347a91c8f3245c8fb5555075e8a3d529f33aedba49aaec0c6
+04a19a7bc5ed45f2f09c7548f6f59b933e96350221fb10d2e654e52f508060ac
+b0082531fc830e5f4b059731a81ac8e36a2ad89735ecec3d1c30aea57af5d4da
+a8769c1801f817e4f29c2214ec66d58c3918a9f233133120541f4938c0c8ab6a
+e2dbf3b0deeb140cb17070d75a64e4b41a169534dd99ad8ee635779da4b131be
+e1165e25aa26a2127fdcab0738d769117d8c4b7ee4dcf2caff4e126fa83dd96d
+0373bfcda5e1a920756329ff21cd4445ebda128a491860b193a4d97d5605acb9
+9610029edc11f240a776c45f55997f7d94e5346e1a94d9d8c9ce272d16331f42
+e6158bd248136122b06bf617d6e51977f2ef2ca94fbfbec1ed369ed566da0a3f
+0011484eea81b59772c52834f41208c87b06bcd4dda705404082ccd6280fe7c5
+72e8e5f7279d16bdb543488fdcdbc01e3781c3f2f1343c805c2f5d3b3b5ef19f
+ebc207585693f4ad3b5333260b10a3fd73ae4c496d62bd0abf05f089a89ab658
+aadceec15421d25fbe0c5df76884133b05214e327cf0f6b872bd93160f69435c
+fb012578b281d2d38ba93de5d992574e0ee2f0dad835146f4cec5373b1213fa3
+c8198b7dfbf455d73a7cc6fd50c37b7adcfb6d5c6b5be7c66bbcfe1f58245626
+96a7369a9d01fd31b358cdd12738bc129f571396931b3d14e65866e5881e92c0
+c57ce463d9af9663b21a4c47fe605cd91d220a72d57c5f5217031634e59a7fdc
+784d90821ad69adf1bff61844e9f87bb12576a97d6a658daff1c8dfc6815df7e
+8dc35d4dde5b42c440259bda1f8112756a956aeb85e59da6b13030837403d79b
+726b4cea02e999a2bfdfe58428731cfaddba5504de48dbfc609d7989ebe36b0e
+b4eaa7e5c3f285d51f3898d1b2e8d3e653374014629b506b8b3fc0bcdab045e0
+8a43aa4513e2355dcc5ac7a703c31dcaa61f24213832aca3bbc7e342d7ad27f3
+4152ae1fe6f4e28eba9245faf38fc3266cd5ae400635942efd22f0ff9dca428f
+ce3a8d7d19b8eaa5b36f4e0057b37f83f1b10a83b5d1aab002d6d63bec695e6c
+2b46ffa670650aa4f2dc3578114987faa786de2d6db7e6e6872282d0a86e1b82
+1cfb6be029aebf854dac8c88f35dab7cdd4a9ed0077dc7ba7c39a34df81662c3
+3a5f558328bd31934517e79a53563d330b41105a5329d1fa7053820da39a811d
+74c4a92a9ee3f923a26d86c59a8908b9a042e1981da48642ff2298a9b05a5878
+5566e7be4c0aa5e34759faaefc41dfbbfc3af607411349681b5030e287d0b577
+a3eafa4753e746f1d71fd7a6915f7708cd60d15ecc6ce797ba3798a93265a03a
+874a07745af0df81363002f3aadd88cb95d5fbb6c45fb044e4ce9e09502003d8
+7c4bef2b82b63f91910a0d4ead2f1ea8c8ba01dffbfade76731a8690dd289a7b
+71ed0c03819641772101c6bf4c433ccc585d18f93f26fa41fdffe0ef8294296a
+b9172a28f500fe5b75eef97ee0165ba4a878084ae651784d5de65f5b65cc479b
+04116a57611681eba68c09f82efec26ae0c60ac40424bb0fdc8b987b75875464
+f59dd2e0b62dba0b3fd820cb03f00c2f7babbdf5e24267b9038b45966cb2ff3b
+115ca8b0af271afd2b574a0153eebd04a87ab4b418c6a554682b3d2b5420d0e2
+e23e16ceb4953105df0355be7f31c233af2c0153858030f9fb16e7e9b4795718
+7b436b9788c463c7e8d8ab67a6cad843d27dce5caefedc3a76ec535ec979093e
+723ca8bd8d0234e1f39973064946c79b93fc892e7b24cefce88d099b821a69c7
+7324c9ccf28db4b97f844fdcca54012b142a6f560426674c19839f5d776b29c4
+424979e3a16e398e7a792a5e92a7eee5727b6d033e3f305e204ce370dfe40997
+b7a84f7eb97795b9e243c8fd58ea4cc7371d9ad3949f1c8e9c174cb9af2b0c28
+633cfbce09b4a380aa29e9199e055d891e3d89d5589c5e83e8aa7770220551d1
+b10a88550cf10372add5884010c25359e45c821611a71adeeff841d5d8068918
+68f204fcb9f4c9493c8d91cc039baeb898efc4b5eec85623bfc6fdbf5bce605f
+5c7c618e19ac01c68961d702b17d16d31368a0b7c3bc46c5b6da34a546e31b5b
+c9ed437ae5209c91433d0e8df0021e606294a22edc3a02ece80bbd267bc3a1e4
+1ce2f5272f1db7002aac2a8d7dc2a649c8316662a941f6baf7fb8ee7e86922c2
+75588ff6af85f540bbcc5a380d86e81a37bf88a3c57a8deaed33d274e87720be
+2d99585c5029538b2fee86082598a139ec39ca4e061c137f1ff59cfc69120c28
+3e654ecb7cc48649900801bb329736c7bf21b07ffba69534036cb85dc5f29396
+9ab322e19804863da9c5f0860ebadc5228badb80cfd4e9f31bc0052430e0f3cc
+0b63b1cff9fa9f4467d43262d4f63eeae49ff8d1560ec55a06a3a92fdcf158bd
+5089f8b188d3095666d4aa9679ffebc6786940132d259d42e7153760de7b6adc
+d3e6056db55f124726cb20d0ac763b67c727e9789979882578ef2ae32c8d0a9e
+2e2947f7ba52cf89944a36cd2f2e5dc4a02656202cb49ba081569584a335be14
+9cb5bd5b785123b7cd202158ba98a831edc01d6a461ba2641c07150d3f55b292
+bcf9c69d619746c9fc9d444a6132c5fc9ed2228bef99ca5c7e6dc772f194a1e7
+7a54a8d99c5e665422be3f13bd4e104e69ad02a479ac3c9ff61bb2e74dfa9735
+e80a744cc4d4674c5b33e674eec87362da4012b98ed0e7f05d75073897a40bc8
+d66140db1a850483fdd4606b3110ab5d7a6bb6229a6df028e8c8c62538a85884
+0abd25dcc84bfe9d13fe4ef567165eb72e0e246826cc67d0f35bcec135c2d4f7
+433f278e9948eb91b30f0c11de38e1c9b7484c5e3970b09d37334df686c704b7
+77fe267a0ce2ad7a5887e5dff00640e3f619dfcab32fbc28192876018f4fa492
+b2ed5983a9a1325acc22366a8c5c94412d26b75eee6a2bd08d3d2d9247d0673b
+59e680ad1d3432849a695c8910b686533f3bd7d64c3fa3e9ccd76475b4e2d079
+0b9e58f792d619b0cc48defcf09cd6855293975b75e38847041662a1899686b7
+74d2bbeaeab5431d53aa8c380a57703a21c1306472c4420d33076c25a2bd2710
+cd7cbe3616afe747a410e03387ff9c5951a89c8818af2879d95d74c5c0734c5a
+c84218c219a639ad2e8329e55f6d339c03c64452aaab6608a0829f6979a745ac
+d351cdc8b67f351549aa6df608197e0eb65718f47b5513bbfbad13a5e32adcd4
+e7869dcfd53b918282c5916f756f6e8eac46cf58f5e9de2d073a4bdd54a54d0b
+f2f4a61432c62430c1f9eb783018d1c7be62df2514f562f3a285e9584819c8da
+91e15749bd71197cd549ef0f89638f560f42a3e02a9dc69a93da820d3748b983
+b1409f29e499401bd76037e195f9c50895b1034089d2bf6fa736591ef5cad597
+836512b623f94e85907d7706b8e3c0686b93432e3d3bf7f42c98de62ad150fdf
+ee1569f3d3b8aad8fe31f00fed1c767736e9dc189d1ef18979d1725538b060bb
+2dac78c707f717a0ecf9bb9f222ef8aff9fda74c4f07ea07b6f52d8b3bc3f02d
+763abd9b9bb4305f4707fcd03750e033d502e9e69bbc3db91f4fc1ab9356f1e8
+b66649370d6e1099250e0638d0b5688bfff1bb8dc7ea038a7163502eee800e53
+a1bda9971e2ac70b7489492bafa8ef42dfe4851f9f1cc7c2c95a40ab25db455c
+12b42cb94aebc3b1b3d7cabdbef637205ec1dec48bf04fe2c86c3f41ff127108
+9d8e5c37f7d406d743962f7fe013149b4c1291d9573a544f2bc8e2fea78fb276
+c5ea8cd6583182ee34fcd8ccdc4dbb7273f848b2c2005dae6e43f99086dd21b1
+0756bb1258696753248513daeaff92bfeaae1eabe8c063491a5fd6c00e1f445c
+cc1ec75c816d6d27e62bc657ed551328c3b85afcd1ca9b09d00373f0053ff68c
+97605c183bf8c30a2bfed48a3245ef6b584398f62024642832c88f24a24d3a01
+be6f512b9c3623843d388c792bc4add0805343713d7535f6a1d03d4a2fce724a
+b91c4977150914ad0a34fef0addb71980c0a764375d91b86e9f379c438562dcf
+11686d0794d26b07d4c59febaff8a93c43946d987e6c4b6ad650c932cd595fa5
+a2b46b2802463c70449af8e61fa30c6e83c748a33be7d81476376064716e3197
+f8703d525f95c6a2ddae5b66a9561d8b1440915286c30c345f599ac82fdd1a12
+a5be554ec240b610383f34d85a1ed94466ee7c0cd5cc1676570a73ac9c6d80df
+f71c2b487882da466f9a08a2cd963653dc67957514976be58d40a12e9ff9962e
+3407c304c750f81a7bfb458a44dcd8a04f8742c8d7ad67b9bc8e4fb9bd425abe
+af4a2714d56d23dd7fe79d99c5d935b2b97d82415e55f326135fcf51db7e4a81
+8e6177e53ce48a628514e93ad45782277eeb78f5dbb51908db22e74825d31478
+f4a9f5ecd373d6f4fda7b89dcc1d124c3d09265a8835ef1b36c31cb078b4de28
+3435ae9df3477504a90b52a788093f0ee924d382b380295faba3c35f56b8f46b
+0bfbe880af354d949dc30f0869b9ccb3f194782f4f784c37b79f575ed5dbb38a
+d3819a668e204d528f6d6e05ba0a45371f7656c6d1be0aff866f9fa6a8ce5654
+fa485ab31cf114a531b1b674371119eb36ccba3350c58ec35af3c410c393f0a5
+d6c2149856ddaf28ed279ef64a66a77297f131a9981ca618b5941f28af7ee370
+30a59da5e4175b5806a786d4981081b31d306b96f4c7a54e024ea32b8892b12b
+6161f3c880242602476dff9070e24a364d40e9a5fde87b26535e9f892c778c50
+98e10efa0b5b661971a3a018028789a71b363c7a62ed0944b0c2cbba0c79e4bb
+9f7a05b1dc1fcc278e2546201c9d23ba42d67d68d1f4614b3735cbd6f50dc46f
+8172cb5d3b6d099e43499c2c0b14c58aecacf63b00a58204f99026dc45994d28
+6de59019e2275322d4ce46ebe5ed630489886160a2bf9a7099abb49a864a6e0b
+a9446b97ed62b61926520d26201f31a803e4bbd8c9bf89d154f3005950dd5721
+e7d1ccd7982ca0beca6a8cd2dcae488fd9edea9f09ecacc6b430ad9e644bfd94
+f43177ef3eaca6f2b22ed5c1f61657102792f438a6a8bcc721cf54d445ae5973
+ed53eef181537f66fe15498f408fce30eb7348a97857391ab7532865f48f7240
+5040adf2af45da7b6f5b03d8a37a94a2647936865b470ecd43dc0d4d72269950
+f0a668b72e6001519f6934380b80a2758686d4f99a618fc4bb61abbb58eddd87
+7bc4f0aabd28d596fb613ccffb0f26a75e53a7c7fd432754422538424fdbd636
+be60414dbede5fa639eeca055c7d0d0f80a121c24f3b2402f98ac91dea0d06de
+0e1faab1c2e4ce5172a48a417c210c2ee4619edcadc89c4b69aec28c8b2efb81
+e37a006366876e99eaa815b69837baa67778e5e359fd316570fb52880a9ca629
+97dd0dbf406138783d84792cf7616dbf2c7a31825aa33670c6bdec650ca2698c
+5c8546a3966159d66473b07c4c99f2d48c95238ad5352a1cb2f06afdd953475a
+4e5dda657bb5f5f834b29b30fc9d9aee7f4d8797dcee9a35cfeb066d8317fb4a
+41924f4a2e65cea7cb1fa8114e9e31c4be6847b0547b9712df4cdcf490709df9
+e76cb3fd933b03b8b7c786790c6ed880458500a3c66ae48306a3dacce3fc1663
+b0d7e2850a7d9d22c4e2b183ec58bfbf818b4fb7717ae53cf58d9b52020c02af
+1686682b215aae195d6c82abf3d27a82a28b2a580a79c88ea264b478196848b3
+f8789685914564daec64c7798d8ceca706aecdbdf57ad457eb1b5058dd8d081b
+b125ecd5b6c8cd541f4fe62c9c48a708df183f53b8ee3d1226bb909492ba6878
+e837627727fa290c2e9296f29991a366a2977ef4ee9c1b9a4635b424b78b0a92
+eea383038fd13201bf9724313c7bef7f3f86a6b854375077625cfd5c90de6f49
+c8f7a0da7c5f31b611ecabb893e90a470ca1bfced8b4b34c757869d0778a4934
+2a73cf77653d660d6815e3fe282d9d172522f351c58ee095b7dcdf3196b59c39
+20309447c3dc2e1679ca39c9efc65b587f0e4c879c8542869bee1ef90f562fb8
+02323011b77fd8e079009aabd0011f382de66d9cd74a581b8810251482c985ec
+af0ca59367f51819c4532af37a5bd5926744b46a03f43da0560bd0eead27310e
+3a3e522593a807ad4b8f800960f78894cb757e82f3476a2724d0ae623f5460f1
+67bf93d0b305322dca45e038a56b299c7ed6dff66fd747bfa55947b9ecb485db
+681af9d82546e9096ae4d6172dcf0aff907642ef8d57ea3f84921041b8a29c94
+d5a8e867bb5d85576e08324ed1c18b9384fb2c0f5fa5aa87f48d4f2f6f2ed3ac
+0cdadc949455fce9165d5e5f5bc4bf4d6314ae8ab1708d2774f95a808ac809fe
+565d77765add2900affc
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
diff --git a/gs/lib/chess.ps b/gs/lib/chess.ps
new file mode 100644
index 000000000..3200f1eab
--- /dev/null
+++ b/gs/lib/chess.ps
@@ -0,0 +1,101 @@
+%!PS-Adobe-2.1
+%%% HOW TO USE: from Unix, "cat Cheq Example | lpr -Pprintername "
+%%Title: Cheq.cheqtxtx
+%%Creator: Glenn Reid and still.ps (V 1.0d release 10 edit 08)
+%%BoundingBox: (atend)
+%%Pages: (atend)
+%%DocumentProcSets: Adobe_distill 0.95
+%%EndComments
+%%BeginProcSet: Adobe_distill 0.95
+/PROLOGUE 30 40 add dict def
+ % 30 procedure entries + room for 40 cached font dictionaries
+ PROLOGUE begin
+ /clip { } def % causes problems. remove if "clip" is needed
+ /bdef { bind def } bind def /ldef { load def } bdef
+ /T { moveto show } bdef /A { moveto ashow } bdef
+ /W { moveto widthshow } bdef /AW { moveto awidthshow } bdef
+ /f /fill ldef /R { { rlineto } repeat } bdef
+ /r /rlineto ldef /L { { lineto } repeat } bdef
+ /m /moveto ldef /l { moveto lineto stroke } bdef
+ /x { 0 rlineto } bdef /y { 0 exch rlineto } bdef
+ /c /curveto ldef /cp /closepath ldef
+ /s /stroke ldef /w /setlinewidth ldef
+ /g /setgray ldef /j /setlinejoin ldef
+ /d /setdash ldef /F /setfont ldef
+ /C /setcmykcolor where { /setcmykcolor get }{ %ifelse
+ { %def
+ 1 sub 3 { 3 index add neg dup 0 lt { pop 0 } if 3 1 roll } repeat
+ setrgbcolor
+ } bind
+ } ifelse def
+ /MF { findfont exch makefont setfont } bdef
+ /DF { findfont exch scalefont setfont currentfont def } bdef
+ /BEGINPAGE { pop /pagesave save def } bdef
+ /ENDPAGE { pop pagesave restore showpage } def
+ /REMAP { %def
+ FontDirectory 2 index known { pop pop pop } { %ifelse
+ findfont dup length dict begin
+ { 1 index /FID ne {def}{pop pop} ifelse } forall
+ exch dup length 0 gt { /Encoding exch def }{ pop } ifelse
+ currentdict end definefont pop
+ } ifelse
+ } bdef
+ /RECODE { %def
+ 3 -1 roll 1 index findfont /Encoding get 256 array copy exch
+ 0 exch { %forall
+ dup type/nametype eq
+ { 3 {2 index} repeat put pop 1 add }{ exch pop }ifelse
+ } forall pop 3 1 roll REMAP
+ } bdef
+ end %PROLOGUE
+%%EndProcSet: Adobe_distill 0.95
+%%EndProlog
+%%BeginSetup
+PROLOGUE begin
+
+%%EndSetup
+%%Page: 1 1
+%%PageFonts: (atend)
+%%PageBoundingBox: (atend)
+
+
+%%%%%% Following line added by Aladdin Enterprises:
+%%%%%% load the font explicitly so it doesn't have to be in Fontmap.
+(cheq.ps) run
+
+
+1 BEGINPAGE
+1 1 1 0 C
+/F1 12 /Times-Roman DF
+(Cheq \(gift of Adobe Systems\) "Chequed Board")
+72 756 T
+(p. 1)
+558 756 T
+/F2 30 /Cheq DF
+
+
+%%%%%% Following line added by Aladdin Enterprises:
+%%%%%% scale up and relocate the image.
+-140 -800 translate 2 2 scale
+
+
+( ________) 72 714 T
+(/R\366B\316K\365N\345\\) 72 684 T
+(/\270P\270P\270P\270P\\) 72 654 T
+(/ x x x x\\) 72 624 T
+(/x xQ\360 x \\) 72 594 T
+(/ x x x x\\) 72 564 T
+(/x x \317kx \\) 72 534 T
+(/p\271p\271p\271p\271\\) 72 504 T
+(/\250n\272q\373b\265r\\) 72 474 T %%%%%% 277??
+( --------) 72 444 T
+2 ENDPAGE
+%%PageTrailer
+%%PageFonts: Times-Roman Cheq
+%%PageBoundingBox: 20 20 576 756
+%%Trailer
+end %PROLOGUE
+%%Pages: 1
+%%BoundingBox: 20 20 576 756
+%%DocumentFonts: Times-Roman Cheq
+%%EOF
diff --git a/gs/lib/colorcir.ps b/gs/lib/colorcir.ps
new file mode 100644
index 000000000..d8360d4ff
--- /dev/null
+++ b/gs/lib/colorcir.ps
@@ -0,0 +1,120 @@
+%!
+
+gsave
+/Times-Roman findfont 24 scalefont setfont
+72 72 translate 0 0 moveto 1 0 0 setrgbcolor (Red) show
+72 0 translate 0 0 moveto 0 1 0 setrgbcolor (Green) show
+72 0 translate 0 0 moveto 0 0 1 setrgbcolor (Blue) show
+72 0 translate 0 0 moveto 1 1 0 setrgbcolor (Yellow) show
+72 0 translate 0 0 moveto 1 0 1 setrgbcolor (Pink) show
+72 0 translate 0 0 moveto 0 1 1 setrgbcolor (Cyan) show
+72 0 translate 0 0 moveto 0.9 0.9 0.9 setrgbcolor ('White') show
+grestore
+
+0.0 setlinewidth
+
+/hsvcircle {
+gsave
+ /h 0.0 def
+ 0 4 360 {
+ pop
+ gsave
+ 0.5 0.0 translate
+
+ newpath
+ 0.0 0.0 moveto
+ 0.1 0.0 lineto
+ 0.1 0.02 lineto
+ 0.0 0.02 lineto
+ closepath
+ h 1.0 1.0 sethsbcolor
+ fill
+
+ %newpath
+ %0.0 0.0 moveto
+ %0.1 0.0 lineto
+ %0.1 0.02 lineto
+ %0.0 0.02 lineto
+ %closepath
+ %0.0 setgray
+ %stroke
+
+ grestore
+ /h h 4 360 div add def
+ 4 rotate
+ } for
+grestore
+} def
+
+/graycircle {
+gsave
+ /h -1.0 def
+ 0 4 360 {
+ pop
+ gsave
+ 0.5 0.0 translate
+
+ newpath
+ 0.0 0.0 moveto
+ 0.1 0.0 lineto
+ 0.1 0.02 lineto
+ 0.0 0.02 lineto
+ closepath
+
+ h abs setgray
+ fill
+
+ %newpath
+ %0.0 0.0 moveto
+ %0.1 0.0 lineto
+ %0.1 0.02 lineto
+ %0.0 0.02 lineto
+ %closepath
+ %0.0 setgray
+ %stroke
+ grestore
+
+ /h h 8 360 div add def
+ 4 rotate
+ } for
+grestore
+} def
+
+0.0 setlinewidth
+0.0 setgray
+300 400 translate
+500 500 scale
+
+30 rotate
+1.0 0.7 scale
+-30 rotate
+
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+0.8 0.8 scale
+hsvcircle
+0.8 0.8 scale
+graycircle
+
+showpage
diff --git a/gs/lib/cp.bat b/gs/lib/cp.bat
new file mode 100755
index 000000000..a40a63ff8
--- /dev/null
+++ b/gs/lib/cp.bat
@@ -0,0 +1,10 @@
+@echo off
+if "%2"=="." goto ne
+erase _.tmp
+rem >_.tmp
+copy /B %1+_.tmp %2
+erase _.tmp
+goto x
+:ne
+copy /B %1 %2
+:x
diff --git a/gs/lib/decrypt.ps b/gs/lib/decrypt.ps
new file mode 100644
index 000000000..9cc8b2f17
--- /dev/null
+++ b/gs/lib/decrypt.ps
@@ -0,0 +1,13 @@
+% Decrypt an eexec-encoded file.
+
+(t.in) (r) file /in exch def
+(t.out) (w) file /out exch def
+256 string /buf exch def
+55665 % eexec encryption seed
+ { in buf readhexstring /more exch def
+ dup .type1decrypt out exch writestring
+ more not { exit } if
+ } loop
+in closefile
+out closefile
+quit
diff --git a/gs/lib/docie.ps b/gs/lib/docie.ps
new file mode 100644
index 000000000..9e7419047
--- /dev/null
+++ b/gs/lib/docie.ps
@@ -0,0 +1,219 @@
+% Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% docie.ps
+% Emulate CIE algorithms in PostScript.
+
+% ---------------- Auxiliary procedures ---------------- %
+
+/r1default [0 1] def
+/r3default [0 1 0 1 0 1] def
+
+/apply3 % <u> <v> <w> [<pu> <pv> <pw>] apply3 <u'> <v'> <w'>
+ { { 4 -1 roll exch exec } forall
+ } bind def
+
+/restrict % <u> <min> <max> restrict <u'>
+ { 3 1 roll .max .min
+ } bind def
+
+/restrict3 % <u> <v> <w> [<minu> ... <maxw>] restrict3 <u'> <v'> <w'>
+ { aload pop
+ 7 -1 roll 3 1 roll restrict 7 1 roll
+ 5 -1 roll 3 1 roll restrict 5 1 roll
+ restrict 3 1 roll
+ } bind def
+
+/rescale % <u> <min> <max> rescale <u'>
+ { 1 index sub 3 1 roll sub exch div 0 .max 1 .min
+ } bind def
+
+/rescale3 % <u> <v> <w> [<minu> ... <maxw>] rescale3 <u'> <v'> <w'>
+ { aload pop
+ 7 -1 roll 3 1 roll rescale 7 1 roll
+ 5 -1 roll 3 1 roll rescale 5 1 roll
+ rescale 3 1 roll
+ } bind def
+
+/mmult3 % <u> <v> <w> [<uu> <uv> ... <wv> <ww>] mmult3
+ % <u'> <v'> <w'>
+ { 4 -1 roll dup dup 6 -1 roll dup dup 8 -1 roll dup dup
+ 10 -1 roll { 10 -1 roll mul } forall
+ % Stack: u1 v1 w1 u2 v2 w2 u3 v3 w3
+ 4 -1 roll add 6 -1 roll add
+ % Stack: u1 v1 u2 v2 u3 v3 w'
+ 7 1 roll 3 -1 roll add 4 -1 roll add
+ % Stack: w' u1 u2 u3 v'
+ 5 1 roll add add 3 1 roll
+ } bind def
+
+/minvert3 % [<uu> <uv> ... <wv> <ww>] minvert3
+ % [<uu'> <uv'> ... <wv'> <ww'>]
+ { 16 dict begin
+ aload pop { I H G F E D C B A } { exch def } forall
+ /coa E I mul F H mul sub def
+ /cob F G mul D I mul sub def
+ /coc D H mul E G mul sub def
+ /det A coa mul B cob mul add C coc mul add def
+ [ coa det div
+ C H mul B I mul sub det div
+ B F mul C E mul sub det div
+ cob det div
+ A I mul C G mul sub det div
+ C D mul A F mul sub det div
+ coc det div
+ B G mul A H mul sub det div
+ A E mul B D mul sub det div
+ ]
+ end
+ } bind def
+
+/print1
+ { print dup ==
+ } bind def
+
+/print3
+ { print 3 array astore dup == aload pop
+ } bind def
+
+% ---------------- Mapping to XYZ ---------------- %
+
+/csmap % <csdict> <l> <m> <n> csmap <csdict> <x> <y> <z>
+ { 3 index /RangeLMN .knownget not { r3default } if restrict3
+DEBUG { (After RangeLMN Decode: ) print3 } if
+ 3 index /DecodeLMN .knownget { apply3 } if
+DEBUG { (After DecodeLMN Decode: ) print3 } if
+ 3 index /MatrixLMN .knownget { mmult3 } if
+DEBUG { (After MatrixLMN Decode: ) print3 } if
+ } bind def
+
+/csciea % <csdict> <a> csciea <csdict> <x> <y> <z>
+ { 1 index /RangeA .knownget not { r1default } if restrict
+DEBUG { (After RangeA Decode: ) print1 } if
+ 1 index /DecodeA .knownget { exec } if
+DEBUG { (After DecodeA Decode: ) print1 } if
+ 1 index /MatrixA .knownget
+ { { 1 index mul exch } forall pop }
+ { dup dup }
+ ifelse
+DEBUG { (After MatrixA Decode: ) print3 } if
+ csmap
+ } bind def
+
+/cscieabc % <csdict> <a> <b> <c> cscieabc <csdict> <x> <y> <z>
+ { 3 index /RangeABC .knownget not { r3default } if restrict3
+DEBUG { (After RangeABC Decode: ) print3 } if
+ 3 index /DecodeABC .knownget { apply3 } if
+DEBUG { (After DecodeABC Decode: ) print3 } if
+ 3 index /MatrixABC .knownget { mmult3 } if
+DEBUG { (After MatrixABC Decode: ) print3 } if
+ csmap
+ } bind def
+
+% ---------------- Rendering from XYZ ---------------- %
+
+/lookup3 % <rtable> <a[0..1]> <b[0..1]> <c[0..1]> lookup3
+ % <rtable> <bytes>
+ { 3 -1 roll 3 index 0 get 1 sub mul
+ 3 -1 roll 3 index 1 get 1 sub mul
+ 3 -1 roll 3 index 2 get 1 sub mul
+ % Stack: rtable ia ib ic
+DEBUG { (RenderTable indices: ) print3 mark 5 1 roll } if
+ 3 -1 roll round cvi 3 index 3 get exch get
+ % Stack: rtable ib ic string
+ 3 -1 roll round cvi 3 index 2 get mul
+ % Stack: rtable ic string ib*nc
+ 3 -1 roll round cvi add 2 index 4 get mul
+ % Stack: rtable string index
+ 2 index 4 get getinterval
+ % Stack: rtable bytes
+DEBUG { (RenderTable values: ) print (<) print (%stdout) (w) file 1 index writehexstring (>) = } if
+ } bind def
+
+/bpdefault [0 0 0] def
+
+/crmap % <csdict> <crdict> <x> <y> <z> crmap <v1> ...
+ {
+DEBUG { (CIE XYZ = ) print3 } if
+ 3 index /MatrixPQR .knownget { mmult3 } if
+DEBUG { (After MatrixPQR: ) print3 } if
+ 4 index /WhitePoint get
+ 5 index /BlackPoint .knownget not { bpdefault } if
+ 5 index /WhitePoint get
+ 6 index /BlackPoint .knownget not { bpdefault } if
+ 4
+ { 4 -1 roll aload pop
+ % Stack: csdict crdict x y z pt pt pt px py pz
+ 3 copy 12 index /MatrixPQR .knownget { mmult3 } if 6 array astore
+ }
+ repeat
+ % Stack: csdict crdict x y z wps+ bps+ wpd+ bpd+
+ 9 -1 roll pop % get rid of csdict
+ 7 4 roll
+ 7 index /TransformPQR get
+ { % Stack: crdict wps+ bps+ wpd+ bpd+ u v w proc
+ 8 copy exch pop exch pop
+ exec exch pop 4 -1 roll pop
+ }
+ forall
+ 7 3 roll pop pop pop pop % get rid of White/BlackPoints
+DEBUG { (After TransformPQR: ) print3 } if
+ 3 index /MatrixPQR .knownget { minvert3 mmult3 } if
+DEBUG { (After MatrixPQR': ) print3 } if
+ 3 index /MatrixLMN .knownget { mmult3 } if
+DEBUG { (After MatrixLMN Encode: ) print3 } if
+ 3 index /EncodeLMN .knownget { apply3 } if
+DEBUG { (After EncodeLMN Encode: ) print3 } if
+ 3 index /RangeLMN .knownget not { r3default } if restrict3
+DEBUG { (After RangeLMN Encode: ) print3 } if
+ 3 index /MatrixABC .knownget { mmult3 } if
+DEBUG { (After MatrixABC Encode: ) print3 } if
+ 3 index /EncodeABC .knownget { apply3 } if
+DEBUG { (After EncodeABC Encode: ) print3 } if
+ 3 index /RangeABC .knownget not { r3default } if
+ 5 -1 roll /RenderTable .knownget
+ { % Stack: u v w ranges rtable
+ 5 1 roll rescale3
+DEBUG { (Rescaled ABC: ) print3 } if
+ % Stack: rtable a b c
+ lookup3
+ % Stack: rtable bytes
+ 0 1 3 index 4 get 1 sub
+ { % Stack: values rtable bytes c
+ 2 copy get 255 div
+ % Stack: values rtable bytes c v
+ 3 index 3 -1 roll 5 add get exec 3 1 roll
+ }
+ for pop pop
+DEBUG { (After RenderTableT: ) print ] dup == aload pop } if
+ }
+ { restrict3
+DEBUG { (After RangeABC Encode: ) print3 } if
+ }
+ ifelse
+ } bind def
+
+% ---------------- Top level control ---------------- %
+
+/mapdict mark
+ /CIEBasedA { 1 get exch csciea currentcolorrendering 4 1 roll crmap } bind
+ /CIEBasedABC { 1 get 4 1 roll cscieabc currentcolorrendering 4 1 roll crmap } bind
+.dicttomark def
+/mapcie % <a> mapcie <v1> ...
+ % <a> <b> <c> mapcie <v1> ...
+ { currentcolorspace dup 0 get //mapdict exch get exec
+ } bind def
diff --git a/gs/lib/escher.ps b/gs/lib/escher.ps
new file mode 100644
index 000000000..c17bf0f4b
--- /dev/null
+++ b/gs/lib/escher.ps
@@ -0,0 +1,379 @@
+%!
+% If you're concerned that the cpu in your PostScript printer will atrophy
+% from disuse, here is another Escher-like contribution to to keep it busy
+% for a while. It uses PostScript color commands, but will still work on
+% a monochrome printer (but isn't very pretty in black & white).
+%
+% The butterflies are arranged in a hexagonal grid (wallpaper group p6),
+% and the moveto, lineto, curveto commands used to render the tesselation
+% are redefined so as to impose a nonlinear transform that shrinks the
+% infinite plane to an ellipse. This is a sleazy way to mimic Escher's
+% "circle limit" sorts of things.
+%
+% The butterfly permimeter was made by imposing all the symmetry constraints
+% on a path, and then that path was filled in using Adobe Illustrator
+%
+% The routines Xform and next_color are easy to change if you want to hack
+% with them. The code was written to sacrifice efficiency for readability.
+%
+% Bob Wallis
+%
+% UUCP {sun,pyramid,cae780,apple}!weitek!wallis
+
+%statusdict begin waittimeout 6000 lt % if you have a slow printer, you
+% {0 60 6000 setdefaulttimeouts} % might need to uncomment this
+%if end
+
+/nlayers 1 def % 1 takes about 10 minutes on a LW+; 2 takes 4x longer
+/warp 1 def % 1 -> ellipsoidal distortion; 0 -> flat Euclidean
+/inch {72 mul} def
+
+/x4 152 def /y4 205.6 def % 6 fold rotation center of bfly
+/x12 387.20 def /y12 403.84 def % 3 fold center of bfly
+
+/dx x4 x12 sub def % [dx,dy] = distance between the
+/dy y4 y12 sub def % two fixed points above
+
+/Dm dx dup mul dy dup mul % magnitude of basis vectors of
+ add sqrt 3 sqrt mul % parallelogram lattice
+def % = |dx,dy| * sqrt(3)
+
+/Da dy dx atan 30 add def
+/D1x Dm Da cos mul def % [D1x, D1y] = basis vector vector #1
+/D1y Dm Da sin mul def % = [Dm,0] exp(j30)
+
+/Da dy dx atan 30 sub def
+/D2x Dm Da cos mul def % [D2x, D2y] = basis vector vector #2
+/D2y Dm Da sin mul def % = [Dm,0] exp(-j30)
+
+/m { moveto} def
+/L {lineto} def
+/S {stroke} def
+/c {curveto} def
+/f {closepath fill} def
+/F {closepath fill} def
+/g { setgray} def
+
+/FillStroke { % fill interior & stroke black border
+ closepath gsave fill grestore 0 setgray stroke
+} def
+
+%
+% Description of 1 butterfly
+%
+/body {
+ 314.96 280.19 m
+ 383.4 261.71 445.11 243.23 513.52 224.68 c
+ 463.68 256.59 490.26 328.83 446.99 360.76 c
+ 423.71 347.32 397.08 339.7 367.07 337.9 c
+ 388.93 358.28 414.14 372.84 442.73 381.58 c
+ 426.68 398.18 394.07 389.7 387.2 403.84 c
+ 371.52 404.96 362.56 372.48 340.16 366.88 c
+ 346.88 396.01 346.88 425.12 340.16 454.24 c
+ 326.72 427.35 320 400.48 320 373.6 c
+ 270.71 352.1 221.44 411.23 168.88 384.02 c
+ 189.04 388.03 202.48 380.4 212.57 366.95 c
+ 216.72 350.85 209.23 341.46 190.1 338.79 c
+ 177.34 343.57 167.94 354.17 161.9 370.59 c
+ 176.06 305.52 132.02 274.05 152 205.6 c
+ 201.29 257.12 250.56 234.72 299.84 279.52 c
+ 288.64 266.08 284.16 252.64 286.4 239.2 c
+ 298.27 223.97 310.15 222.18 322.02 233.82 c
+ 328.62 249.28 328.51 264.74 314.96 280.19 c
+ FillStroke
+} def
+
+/eyes {
+ 294.8125 238.3246 m
+ 296.9115 238.3246 298.6132 242.7964 298.6132 248.3125 c
+ 298.6132 253.8286 296.9115 258.3004 294.8125 258.3004 c
+ 292.7135 258.3004 291.0118 253.8286 291.0118 248.3125 c
+ 291.0118 242.7964 292.7135 238.3246 294.8125 238.3246 c
+ closepath gsave 1 g fill grestore 0 g S
+
+ 319.5 241.1782 m
+ 321.7455 241.1782 323.5659 245.4917 323.5659 250.8125 c
+ 323.5659 256.1333 321.7455 260.4468 319.5 260.4468 c
+ 317.2545 260.4468 315.4341 256.1333 315.4341 250.8125 c
+ 315.4341 245.4917 317.2545 241.1782 319.5 241.1782 c
+ closepath gsave 1 g fill grestore 0 g S
+ 0 g
+ 296.875 242.0939 m
+ 297.4608 242.0939 297.9356 243.479 297.9356 245.1875 c
+ 297.9356 246.896 297.4608 248.2811 296.875 248.2811 c
+ 296.2892 248.2811 295.8143 246.896 295.8143 245.1875 c
+ 295.8143 243.479 296.2892 242.0939 296.875 242.0939 c
+ f
+ 0 g
+ 318.5 243.7707 m
+ 319.281 243.7707 319.9142 245.0766 319.9142 246.6875 c
+ 319.9142 248.2984 319.281 249.6043 318.5 249.6043 c
+ 317.719 249.6043 317.0858 248.2984 317.0858 246.6875 c
+ 317.0858 245.0766 317.719 243.7707 318.5 243.7707 c
+ f
+} def
+
+/stripes {
+ 292 289 m
+ 252 294 241 295 213 279 c
+ 185 263 175 252 159 222 c
+ S
+ 285 313 m
+ 239 326 226 325 206 315 c
+ 186 305 164 278 161 267 c
+ S
+ 298 353 m
+ 262 342 251 339 237 355 c
+ 223 371 213 380 201 383 c
+ S
+ 330 288 m
+ 384 293 385 292 418 280 c
+ 451 268 452 264 473 247 c
+ S
+ 342 306 m
+ 381 311 386 317 410 311 c
+ 434 305 460 287 474 262 c
+ S
+ 345 321 m
+ 352 357 359 367 379 377 c
+ 399 387 409 385 426 382 c
+ S
+ 327.75 367.75 m
+ 336.5 392.25 333.682 403.348 335.25 415.5 c
+ S
+ 320 364.75 m
+ 322 361.75 323.5 360.5 326.25 360 c
+ 329 359.5 332 360.5 334 362.75 c
+ S
+ 316.25 356.5 m
+ 318.75 353.25 320 353 323.25 352.25 c
+ 326.5 351.5 329 352 331.5 353.25 c
+ S
+ 312.5 349 m
+ 316.75 345.5 318.25 344.5 321.25 343.75 c
+ 324.25 343 327 344 329.75 346 c
+ S
+ 310.75 340.75 m
+ 314.25 336.5 316.25 335.25 320 335.25 c
+ 323.75 335.25 327 336.5 329.25 338 c
+ S
+ 308.5 332 m
+ 311.75 328.5 312.5 327.25 317 327 c
+ 321.5 326.75 325.75 328.25 327.75 329.75 c
+ S
+ 305 322 m
+ 309.5 317.75 310.75 317 315 316.5 c
+ 319.25 316 322.25 318 324.75 320 c
+ S
+ 302.25 311 m
+ 307 307.5 307.75 306.25 312.75 306 c
+ 317.75 305.75 320 307.25 323.75 309.5 c
+ S
+ 301.25 298.25 m
+ 304.5 292.75 305.25 292 308.25 292 c
+ 311.25 292 313.75 293.75 315.75 295.75 c
+ S
+} def
+/nostrils {
+ 0 g
+ 304.062 227.775 m
+ 304.599 227.775 305.034 228.883 305.034 230.25 c
+ 305.034 231.616 304.599 232.724 304.062 232.724 c
+ 303.525 232.724 303.09 231.616 303.09 230.25 c
+ 303.09 228.883 303.525 227.775 304.062 227.775 c
+ f
+ 304.062 230.25 m
+ F
+ 309.562 228.275 m
+ 310.099 228.275 310.534 229.383 310.534 230.75 c
+ 310.534 232.116 310.099 233.224 309.562 233.224 c
+ 309.025 233.224 308.59 232.116 308.59 230.75 c
+ 308.59 229.383 309.025 228.275 309.562 228.275 c
+ f
+} def
+/thorax
+{
+ 327.5 300 m
+ 316.5 283 315.5 275.5 308 277.5 c
+ 294 311.5 299 313.5 304 334 c
+ 309 354.5 315.5 362 322.5 372 c
+ 329.5 382 327.5 376.5 331 376 c
+ 334.5 375.5 339.1367 379.1109 339 369 c
+ 338.5 332 333.4999 324.5 330.5 311.5 c
+ 0 g S
+} def
+/spots {
+ next_color
+ 192 242.201 m
+ 202.1535 242.201 210.3848 251.0655 210.3848 262 c
+ 210.3848 272.9345 202.1535 281.799 192 281.799 c
+ 181.8465 281.799 173.6152 272.9345 173.6152 262 c
+ 173.6152 251.0655 181.8465 242.201 192 242.201 c
+ FillStroke
+ next_color
+ 447.5 250.2365 m
+ 459.6061 250.2365 469.4203 257.5181 469.4203 266.5 c
+ 469.4203 275.4819 459.6061 282.7635 447.5 282.7635 c
+ 435.3939 282.7635 425.5797 275.4819 425.5797 266.5 c
+ 425.5797 257.5181 435.3939 250.2365 447.5 250.2365 c
+ FillStroke
+ next_color
+ 401 369.1005 m
+ 409.5914 369.1005 416.5563 373.5327 416.5563 379 c
+ 416.5563 384.4673 409.5914 388.8995 401 388.8995 c
+ 392.4086 388.8995 385.4436 384.4673 385.4436 379 c
+ 385.4436 373.5327 392.4086 369.1005 401 369.1005 c
+ FillStroke
+ next_color
+ 249 348.2721 m
+ 261.4966 348.2721 271.6274 353.9707 271.6274 361 c
+ 271.6274 368.0293 261.4966 373.7279 249 373.7279 c
+ 236.5034 373.7279 226.3726 368.0293 226.3726 361 c
+ 226.3726 353.9707 236.5034 348.2721 249 348.2721 c
+ FillStroke
+} def
+
+/ncolor 6 def
+/cidx 0 def
+
+/next_color {
+ cidx ncolor div % hue
+ .75 % saturation (change these if you like)
+ .8 % lightness
+ sethsbcolor
+ /cidx cidx 1 add ncolor mod def
+} def
+
+/cidx 0 def
+
+/max_r2 % radius^2 for center of outermost ring of butterflies
+ Dm nlayers mul 1.05 mul dup mul
+def
+
+/max_radius max_r2 sqrt def
+/max_radius_inv 1 max_radius div def
+/Dm_inv 1 Dm div def
+
+%
+% Ellipsoidal distortion, maps "nlayers" concentric rings of cells into
+% an ellipse centered on page
+
+% D length of 1 basis vector separating hexagonal cells
+% z0 center of 6-fold rotation = origin of shrink xform
+% z' = (z - z0)/D new coord system
+% |z'| = sqrt(x^2 + [(8.5/11)*y]^2) aspect ratio of paper
+% z" = z' * a/M(|z'|) shrink by "a/M(|z|)" as fcn of radius
+
+% At the max radius, we want the shrunk ellipse to be "W" units wide so it
+% just fits our output format - solve for scale factor "a"
+
+% zmax = n+0.5 for n layers of cells
+% zmax * [a/M(zmax)] = W 1/2 width of output on paper
+% a = M(zmax)*W/zmax solve for "a"
+
+%/M{dup mul 1 add sqrt}bind def % M(u) = sqrt(1+|u|^2) = one possible shrink
+/M { 1.5 add } bind def % M(u) = (1.5+|u|) = another possible one
+/W 3.8 inch def % 1/2 width of ellipse
+/zmax 0.5 nlayers add def % radius at last layer of hexagons
+/a zmax M W mul zmax div def % a = M(zmax)*W/zmax
+
+/Xform { % [x0,y0] = ctr ellipse
+ Matrix transform
+ /y exch def
+ /x exch def
+ /z x dup mul y .773 mul dup mul add sqrt def % ellipse radius
+ /Scale a z M div def % z=a/M(|z|)
+ x Scale mul x0 add % magnify back up
+ y Scale mul y0 add % [x0+x*s, y0+y*s]
+} def
+
+
+/Helvetica findfont 8 scalefont setfont
+4.25 inch 0.5 inch moveto
+(RHW) stringwidth pop -0.5 mul 0 rmoveto
+(RHW) show % autograph
+
+warp 1 eq { % redefine commands to use Xform
+ /moveto { Xform //moveto} def
+ /lineto { Xform //lineto} def
+ /curveto {
+ Xform 6 -2 roll
+ Xform 6 -2 roll
+ Xform 6 -2 roll
+ //curveto
+ } def
+}if
+
+
+/bfly { % paint 1 butterfly
+ next_color body
+ 1 setgray eyes
+ stripes
+ 0 setgray nostrils
+ 0.5 setgray thorax next_color
+ spots
+} def
+
+/x0 x4 def % center
+/y0 y4 def
+
+/T1matrix % xlate to center of image
+ x0 neg y0 neg matrix translate
+def
+
+/Smatrix % scale so that 1 basis vector = 1.0
+ Dm_inv dup matrix scale
+def
+
+/HexCell { % 6 butterflys rotated about center of
+ /cidx 0 def % 6 fold symmetry
+ /color 0 def
+ /T2matrix dx dy matrix translate def
+ 0 60 300 {
+ /angle exch def
+ /Rmatrix angle matrix rotate def
+ /Matrix % translate, rotate, scale - used by Xform
+ T1matrix Rmatrix matrix concatmatrix
+ T2matrix matrix concatmatrix
+ Smatrix matrix concatmatrix
+ def
+ gsave
+ warp 0 eq % then may use usual PostScript machinery
+ { % else using Xform
+ x0 y0 translate angle rotate
+ .5 dup scale
+ dx x0 sub dy y0 sub translate
+ } if
+ bfly
+ next_color
+ grestore
+ } for
+} def
+
+
+%320 x4 sub 240 y4 sub translate
+4.25 inch x4 sub 5.5 inch y4 sub translate
+
+
+0 setlinewidth
+/N 2 def
+N neg 1 N {
+ /i exch def % translate to
+ N neg 1 N { % i*D1 + j*D2
+ /j exch def % and draw HexCell
+ gsave
+ /dx i D1x mul j D2x mul add def % translate HexCell by
+ /dy i D1y mul j D2y mul add def % [dx,dy]
+ /r2 dx dup mul dy dup mul add def % r^2 = |dx,dy|^2
+ r2 max_r2 lt % inside radius?
+ { % yes
+ 1 r2 max_r2 div sub sqrt 2 div
+ setlinewidth % make skinnier lines
+ HexCell % 6 butterflies
+ }
+ if
+ grestore
+ } for
+} for
+
+showpage
diff --git a/gs/lib/font2c b/gs/lib/font2c
new file mode 100755
index 000000000..0d0fcbd2a
--- /dev/null
+++ b/gs/lib/font2c
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -dNODISPLAY -dWRITESYSTEMDICT -- font2c.ps "$@"
diff --git a/gs/lib/font2c.bat b/gs/lib/font2c.bat
new file mode 100755
index 000000000..b9daf4095
--- /dev/null
+++ b/gs/lib/font2c.bat
@@ -0,0 +1 @@
+@gs -q -dNODISPLAY -dWRITESYSTEMDICT -- font2c.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/font2c.ps b/gs/lib/font2c.ps
new file mode 100644
index 000000000..50a34a1c1
--- /dev/null
+++ b/gs/lib/font2c.ps
@@ -0,0 +1,686 @@
+% Copyright (C) 1992, 1993, 1994, 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% font2c.ps
+% Write out a PostScript Type 0 or Type 1 font as C code
+% that can be linked with the interpreter.
+% This even works on protected fonts, if you use the -dWRITESYSTEMDICT
+% switch in the command line. The code is reentrant and location-
+% independent and has no external references, so it can be put into
+% a sharable library even on VMS.
+
+% Define the maximum string length that all compilers will accept.
+% This must be approximately
+% min(max line length, max string literal length) / 4 - 5.
+
+/font2cdict 100 dict dup begin
+
+/max_wcs 50 def
+
+% Define a temporary file for writing out procedures.
+/wtempname (_.tmp) def
+
+% ------ Protection utilities ------ %
+
+% Protection values are represented by a mask:
+/a_noaccess 0 def
+/a_executeonly 1 def
+/a_readonly 3 def
+/a_all 7 def
+/prot_names
+ [ (0) (a_execute) null (a_readonly) null null null (a_all)
+ ] def
+/prot_opers
+ [ {noaccess} {executeonly} {} {readonly} {} {} {} {}
+ ] def
+
+% Get the protection of an object.
+ /getpa
+ { dup wcheck
+ { pop a_all }
+ { % Check for executeonly or noaccess objects in protected.
+ dup protected exch known
+ { protected exch get }
+ { pop a_readonly }
+ ifelse
+ }
+ ifelse
+ } bind def
+
+% Get the protection appropriate for (all the) values in a dictionary.
+ /getva
+ { a_noaccess exch
+ { exch pop
+ dup type dup /stringtype eq 1 index /arraytype eq or
+ exch /packedarraytype eq or
+ { getpa a_readonly and or }
+ { pop pop a_all exit }
+ ifelse
+ }
+ forall
+ } bind def
+
+% Keep track of executeonly and noaccess objects,
+% but don't let the protection actually take effect.
+.currentglobal
+false .setglobal % so protected can reference local objs
+/protected % do first so // will work
+ systemdict wcheck { 1500 dict } { 1 dict } ifelse
+def
+systemdict wcheck not
+ { (Warning: you will not be able to convert protected fonts.\n) print
+ (If you need to convert a protected font, please\n) print
+ (restart the program and specify the -dWRITESYSTEMDICT switch.\n) print
+ flush
+ (%end) .skipeof
+ }
+if
+userdict begin
+ /executeonly
+ { dup //protected exch //a_executeonly put readonly
+ } bind def
+ /noaccess
+ { dup //protected exch //a_noaccess put readonly
+ } bind def
+end
+true .setglobal
+systemdict begin
+ /executeonly
+ { userdict /executeonly get exec
+ } bind odef
+ /noaccess
+ { userdict /noaccess get exec
+ } bind odef
+end
+%end
+.setglobal
+
+% ------ Output utilities ------ %
+
+% By convention, the output file is named cfile.
+
+% Define some utilities for writing the output file.
+ /wtstring 100 string def
+ /wb {cfile exch write} bind def
+ /ws {cfile exch writestring} bind def
+ /wl {ws (\n) ws} bind def
+ /wt {wtstring cvs ws} bind def
+
+% Write a C string. Some compilers have unreasonably small limits on
+% the length of a string literal or the length of a line, so every place
+% that uses wcs must either know that the string is short,
+% or be prepared to use wcca instead.
+ /wbx
+ { 8#1000 add 8 (0000) cvrs dup 0 (\\) 0 get put ws
+ } bind def
+ /wcst
+ [
+ 32 { /wbx load } repeat
+ 95 { /wb load } repeat
+ 129 { /wbx load } repeat
+ ] def
+ ("\\) { wcst exch { (\\) ws wb } put } forall
+ /wcs
+ { (") ws { dup wcst exch get exec } forall (") ws
+ } bind def
+ /can_wcs % Test if can use wcs
+ { length max_wcs le
+ } bind def
+ /wncs % name -> C string
+ { wtstring cvs wcs
+ } bind def
+% Write a C string as an array of character values.
+% We only need this because of line and literal length limitations.
+ /wca % <string> <prefix> <suffix> wca -
+ { 0 4 -2 roll exch
+ { % Stack: suffix n prefix char
+ exch ws
+ exch dup 19 ge { () wl pop 0 } if 1 add
+ exch dup 32 ge 1 index 126 le and
+ { 39 wb dup 39 eq 1 index 92 eq or { 92 wb } if wb 39 wb }
+ { wt }
+ ifelse (,)
+ } forall
+ pop pop ws
+ } bind def
+ /wcca % <string> wcca -
+ { ({\n) (}) wca
+ } bind def
+
+% Write object protection attributes. Note that dictionaries and arrays are
+% the only objects that can be writable.
+ /wpa
+ { dup xcheck { (a_executable|) ws } if
+ dup type dup /dicttype eq exch /arraytype eq or
+ { getpa }
+ { getpa a_readonly and }
+ ifelse prot_names exch get ws
+ } bind def
+ /wva
+ { getva prot_names exch get ws
+ } bind def
+
+% ------ Object writing ------ %
+
+ /wnstring 128 string def
+
+% Convert an object to a string to be scanned at a later time.
+ /cvos % <obj> cvos <string>
+ { % We'd like to use == and write directly to a string,
+ % but we can't do the former because of operators,
+ % and we can't do the latter because we can't predict
+ % how long the string would have to be....
+ wtempname (w) file dup 3 -1 roll wproc closefile
+ wtempname status pop pop pop exch pop string
+ wtempname (r) file dup 3 -1 roll readstring pop exch closefile
+ } bind def
+
+% Write a string/name or null as an element of a string/name/null array.
+% Convert any other kind of value to a token to be read back in.
+ /wsn
+ { dup null eq
+ { pop (\t255,255,) wl
+ }
+ { dup type /nametype eq { wnstring cvs } if
+ dup type /stringtype ne { cvos (255,) ws } if
+ dup length 256 idiv wt (,) ws
+ dup length 256 mod wt
+ (,) (,\n) wca
+ }
+ ifelse
+ } bind def
+% Write a packed string/name/null array.
+ /wsna % <name> <(string|name|null)*> wsna -
+ { (\tstatic const char ) ws exch wt ([] = {) wl
+ { wsn } forall
+ (\t0\n};) wl
+ } bind def
+
+% Write a number or an array of numbers, as refs.
+/isnumber
+ { type dup /integertype eq exch /realtype eq or
+ } bind def
+/wnums
+ { dup isnumber
+ { (real_v\() ws wt (\),) ws }
+ { { wnums } forall }
+ ifelse
+ } bind def
+
+% Test whether a procedure or unusual array can be written (printed).
+/iswx 4 dict dup begin
+ /arraytype { { iswproc } isall } def
+ /nametype { pop true } def
+ /operatortype { pop true } def % assume it has been bound in
+ /packedarraytype /arraytype load def
+end def
+/iswnx 6 dict dup begin
+ /arraytype { { iswproc } isall } def
+ /integertype { pop true } def
+ /nametype { pop true } def
+ /realtype { pop true } def
+ /stringtype { pop true } def
+ /packedarraytype /arraytype load def
+end def
+/iswproc % <obj> iswproc <bool>
+ { dup xcheck { iswx } { iswnx } ifelse
+ 1 index type .knownget { exec } { pop false } ifelse
+ } bind def
+
+% Write a printable procedure (one for which iswproc returns true).
+/wproca 3 dict dup begin
+ /arraytype
+ { 1 index ({) writestring
+ { 1 index ( ) writestring 1 index exch wproc } forall
+ (}) writestring
+ } bind def
+ /packedarraytype /arraytype load def
+ /operatortype { .writecvs } bind def % assume binding would work
+end def
+/wproc % <file> <proc> wproc -
+ { dup type wproca exch .knownget { exec } { write==only } ifelse
+ } bind def
+
+% Write a named object. Return true if this was possible.
+% Legal types are: boolean, integer, name, real, string,
+% array of (integer, integer+real, name, null+string),
+% and certain procedures and other arrays (see iswproc above).
+% All other objects are either handled specially or ignored.
+ /isall % <array> <proc> isall <bool>
+ { true 3 -1 roll
+ { 2 index exec not { pop false exit } if }
+ forall exch pop
+ } bind def
+ /wott 8 dict dup begin
+ /arraytype
+ { woatt
+ { aload pop 2 index 2 index exec
+ { exch pop exec exit }
+ { pop pop }
+ ifelse
+ }
+ forall
+ } bind def
+ /booleantype
+ { { (\tmake_true\(&) } { (\tmake_false\(&) } ifelse ws
+ wt (\);) wl true
+ } bind def
+ /integertype
+ { (\tmake_int\(&) ws exch wt (, ) ws
+ wt (\);) wl true
+ } bind def
+ /nametype
+ { (\tcode = (*pprocs->name_create)\(&) ws exch wt
+ (, ) ws wnstring cvs wcs % OK, names are short
+ (\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ true
+ } bind def
+ /packedarraytype
+ /arraytype load def
+ /realtype
+ { (\tmake_real\(&) ws exch wt (, ) ws
+ wt (\);) wl true
+ } bind def
+ /stringtype
+ { ({\tstatic const char s_[] = ) ws
+ dup dup can_wcs { wcs } { wcca } ifelse
+ (;) wl
+ (\tmake_const_string\(&) ws exch wt
+ (, a_readonly, ) ws length wt (, (const byte *)s_\);) wl
+ (}) wl true
+ } bind def
+ end def
+% Write some other kind of object, if known.
+ /wother
+ { dup otherobjs exch known
+ { otherobjs exch get (\t) ws exch wt ( = ) ws wt (;) wl true }
+ { pop pop false }
+ ifelse
+ } bind def
+% Top-level procedure.
+ /wo % name obj -> OK
+ { dup type wott exch .knownget { exec } { wother } ifelse
+ } bind def
+
+% Write an array (called by wo).
+ /wap % <name> <array> wap -
+ { dup xcheck not 1 index wcheck not and 1 index rcheck and
+ { pop pop }
+ { (\tr_set_attrs\(&) ws exch wt (, ) ws wpa (\);) wl }
+ ifelse
+ } bind def
+ /wnuma % <name> <array> <element_C_type> <<type>_v> wnuma -
+ { 2 index wcheck
+ { % Allocate an array and copy the values into it.
+ % We can't define new callback procedures, so we must
+ % do this the hard way.
+ pop pop
+ ({\tstatic const byte z_[) ws dup length 1 .max 2 mul wt
+ (] = {0}; ref r_;) wl
+ (\tcode = (*pprocs->string_array_create)\(&r_, z_, ) ws
+ dup length wt (, 0\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ (\tr_set_attrs\(&r_, ) ws dup wpa (\);) wl
+ (\t) ws exch wt ( = r_;) wl
+ 0 1 2 index length 1 sub
+ { 2 copy get
+ % Stack: array index value
+ dup type /integertype eq { (\tmake_int) } { (\tmake_real) } ifelse
+ ws (_new\(&r_.value.refs[) ws exch wt
+ (], ) ws wt (\);) wl
+ }
+ for pop
+ }
+ { ({\tstatic const ref_\() ws exch ws
+ (\) a_[] = {) wl exch
+ dup length 0 eq
+ { (\t) ws 1 index ws (\(0\)) wl
+ }
+ { dup
+ { (\t) ws 2 index ws (\() ws wt (\),) wl
+ } forall
+ }
+ ifelse exch pop
+ (\t};) wl
+ (\tmake_const_array\(&) ws exch wt
+ (, avm_foreign|) ws dup wpa (, ) ws length wt
+ (, (const ref *)a_\);) wl
+ }
+ ifelse
+ (}) wl
+ } bind def
+ /woatt [
+ % Integers
+ { { { type /integertype eq } isall }
+ { (long) (integer_v) wnuma true }
+ }
+ % Integers + reals
+ { { { type dup /integertype eq exch /realtype eq or } isall }
+ { (float) (real_v) wnuma true }
+ }
+ % Strings + nulls
+ { { { type dup /nulltype eq exch /stringtype eq or } isall }
+ { ({) ws dup (sa_) exch wsna
+ (\tcode = (*pprocs->string_array_create)\(&) ws exch wt
+ (, sa_, ) ws dup length wt (, ) ws wpa (\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ (}) wl true
+ }
+ }
+ % Names
+ { { { type /nametype eq } isall }
+ { ({) ws dup (na_) exch wsna
+ (\tcode = (*pprocs->name_array_create)\(&) ws 1 index wt
+ (, na_, ) ws dup length wt (\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ wap (}) wl true
+ }
+ }
+ % Procedure
+ { { iswproc }
+ { dup cvos
+ % Stack: name proc string
+ ({\tstatic const char s_[] = ) ws
+ dup dup can_wcs { wcs } { wcca } ifelse
+ (;) wl
+ (\tcode = (*pprocs->ref_from_string)\(&) ws 2 index wt
+ (, s_, ) ws length wt (\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ wap (}) wl true
+ wtempname deletefile
+ }
+ }
+ % Default
+ { { pop true }
+ { wother }
+ }
+ ] def
+
+% Write a named dictionary. We assume the ref is already declared.
+ /wd % <name> <dict> <extra> wd -
+ { 3 1 roll
+ ({) ws
+ (\tref v_[) ws dup length wt (];) wl
+ dup [ exch
+ { counttomark 2 sub wtstring cvs
+ (v_[) exch concatstrings (]) concatstrings exch wo not
+ { (Skipping ) print ==only (....\n) print }
+ if
+ } forall
+ ]
+ % Stack: array of keys (names)
+ ({) ws dup (str_keys_) exch wsna
+ (\tstatic const cfont_dict_keys keys_ =) wl
+ (\t { 0, 0, ) ws length wt (, ) ws 3 -1 roll wt (, ) ws
+ dup wpa (, ) ws dup wva ( };) wl pop
+ (\tcode = \(*pprocs->ref_dict_create\)\(&) ws wt
+ (, &keys_, str_keys_, v_\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ (}) wl
+ (}) wl
+ } bind def
+
+% Write character dictionary keys.
+% We save a lot of space by abbreviating keys which appear in
+% StandardEncoding or ISOLatin1Encoding.
+% Writes code to declare and initialize enc_keys_, str_keys, and keys_.
+/wcdkeys % <dict> wcdkeys -
+ { % Write keys present in StandardEncoding or ISOLatin1Encoding,
+ % pushing other keys on the o-stack.
+ (static const charindex enc_keys_[] = {) wl
+ dup [ exch 0 exch
+ { pop decoding 1 index known
+ { decoding exch get ({) ws dup -8 bitshift wt
+ (,) ws 255 and wt (}, ) ws
+ 1 add dup 5 mod 0 eq { (\n) ws } if
+ }
+ { exch }
+ ifelse
+ }
+ forall pop
+ ]
+ ({0,0}\n};) wl
+ % Write other keys.
+ (str_keys_) exch wsna
+ % Write the declaration for keys_.
+ (static const cfont_dict_keys keys_ = {) wl
+ (\tenc_keys_, countof\(enc_keys_\) - 1,) wl
+ (\t) ws dup length wt ( - \(countof\(enc_keys_\) - 1\), 0, ) ws
+ dup wpa (, ) ws wva () wl
+ (};) wl
+ } bind def
+
+% Enumerate character dictionary values in the same order that
+% the keys appear in enc_keys_ and str_keys_.
+% <proc> is called with each value in turn.
+/cdforall % <dict> <proc> cdforall -
+ { 2 copy
+ { decoding 3 index known
+ { 3 -1 roll pop exec }
+ { pop pop pop }
+ ifelse
+ }
+ /exec cvx 3 packedarray cvx
+ /forall cvx
+ 5 -2 roll
+ { decoding 3 index known
+ { pop pop pop }
+ { 3 -1 roll pop exec }
+ ifelse
+ }
+ /exec cvx 3 packedarray cvx
+ /forall cvx
+ 6 packedarray cvx exec
+ } bind def
+
+% ------ Writers for special objects ------ %
+
+/writespecial 10 dict dup begin
+
+ /FontInfo { 0 wd } def
+
+ /Private { 0 wd } def
+
+ /CharStrings
+ { ({) wl
+ dup wcdkeys
+ (static const char values_[] = {) wl
+ { wsn } cdforall
+ (\t0\n};) wl
+ (\tcode = \(*pprocs->string_dict_create\)\(&) ws wt
+ (, &keys_, str_keys_, values_\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ (}) wl
+ } bind def
+
+ /Metrics
+ { ({) wl
+ dup wcdkeys
+ (static const ref_(float) values_[] = {) wl
+ dup { (\t) ws wnums () wl } cdforall
+ (\t0\n};) wl
+ (static const char lengths_[] = {) wl
+ { (\t) ws dup isnumber
+ { pop 0 }
+ { length 1 add }
+ ifelse wt (,) wl
+ } cdforall
+ (\t0\n};) wl
+ (\tcode = \(*pprocs->num_dict_create\)\(&) ws wt
+ (, &keys_, str_keys_, (const ref *)values_, lengths_\);) wl
+ (\tif ( code < 0 ) return code;) wl
+ (}) wl
+ } bind def
+
+ /Metrics2 /Metrics load def
+
+ /FDepVector pop % (converted to a list of font names)
+
+end def
+
+% ------ The main program ------ %
+
+% Construct an inverse dictionary of encodings.
+[ /StandardEncoding /ISOLatin1Encoding
+ /SymbolEncoding /DingbatsEncoding
+ /KanjiSubEncoding
+]
+dup length dict begin
+ { mark exch dup { .findencoding exch def } stopped cleartomark
+ } forall
+currentdict end /encodingnames exch def
+
+% Invert the StandardEncoding and ISOLatin1Encoding vectors.
+512 dict begin
+ 0 1 255 { dup ISOLatin1Encoding exch get exch 256 add def } for
+ 0 1 255 { dup StandardEncoding exch get exch def } for
+currentdict end /decoding exch def
+
+/writefont % cfilename procname -> [writes the current font]
+ { (gsf_) exch concatstrings
+ /fontprocname exch def
+ /cfname exch def
+ /cfile cfname (w) file def
+
+% Remove unwanted keys from the font.
+ currentfont dup length dict begin { def } forall
+ { /FID /MIDVector /CurMID } { currentdict exch undef } forall
+ /Font currentdict end def
+
+% Replace the FDepVector with a list of font names.
+ Font /FDepVector .knownget
+ { [ exch { /FontName get } forall ]
+ Font /FDepVector 3 -1 roll put
+ }
+ if
+
+% Find all the special objects we know about.
+% wo uses this to write out references to otherwise intractable objects.
+ /otherobjs writespecial length dict dup begin
+ writespecial
+ { pop Font 1 index .knownget { exch def } { pop } ifelse
+ }
+ forall
+ end def
+
+% Define a dummy FontInfo, in case the font doesn't have one.
+ /FontInfo 0 dict def
+
+% Write out the boilerplate.
+ Font begin
+ (/****************************************************************) wl
+ ( Portions of this file are subject to the following notice(s):) wl
+ systemdict /copyright get wl
+ FontInfo /Notice .knownget
+ { (----------------------------------------------------------------) wl wl
+ } if
+ (****************************************************************/) wl
+ () wl
+ (/* ) ws cfname ws ( */) wl
+ (/* This file was created by the ) ws product ws ( font2c utility. */) wl
+ () wl
+ (#undef DEBUG) wl
+ (#include "ccfont.h") wl
+ () wl
+
+% Write the procedure prologue.
+ (#ifdef __PROTOTYPES__) wl
+ (int huge) wl
+ fontprocname ws ((const cfont_procs *pprocs, ref *pfont)) wl
+ (#else) wl
+ (int huge) wl
+ fontprocname ws ((pprocs, pfont) const cfont_procs *pprocs; ref *pfont;) wl
+ (#endif) wl
+ ({\tint code;) wl
+ (\tref Font;) wl
+ otherobjs
+ { exch pop (\tref ) ws wt (;) wl }
+ forall
+
+% Write out the special objects.
+ otherobjs
+ { exch writespecial 2 index get exec
+ }
+ forall
+
+% Write out the main font dictionary.
+% If possible, substitute the encoding name for the encoding;
+% PostScript code will fix this up.
+ { /Encoding /PrefEnc }
+ { Font 1 index .knownget
+ { encodingnames exch .knownget { def } { pop } ifelse }
+ { pop }
+ ifelse
+ }
+ forall
+ (Font) Font FontType 0 eq { 5 } { 1 } ifelse wd
+
+% Finish the procedural initialization code.
+ (\t*pfont = Font;) wl
+ (\treturn 0;) wl
+ (}) wl
+ end % Font
+
+ cfile closefile
+
+ } bind def
+
+end def % font2cdict
+
+% Compute the procedure name from the font name.
+% Replace all non-alphanumeric characters with '_'.
+/makefontprocnamemap 256 string
+ 0 1 255 { 2 copy 95 put pop } for
+ (0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz)
+ { 2 copy dup put pop } forall
+readonly def
+/makefontprocname % <fontname> makefontprocname <procnamestring>
+ { dup length string cvs
+ dup length 1 sub -1 0
+ { % Stack: string index
+ 2 copy 2 copy get //makefontprocnamemap exch get put pop
+ }
+ for
+ } def
+
+/writefont { font2cdict begin writefont end } def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark dup 2 eq exch 3 eq or
+ { counttomark -1 roll cvn
+ (Converting ) print dup =only ( font.\n) print flush
+ dup FontDirectory exch known { dup FontDirectory exch undef } if
+ findfont setfont
+ (FontName is ) print currentfont /FontName get ==only (.\n) print flush
+ counttomark 1 eq
+ { % Construct the procedure name from the file name.
+ currentfont /FontName get makefontprocname
+ }
+ if
+ writefont
+ (Done.\n) print flush
+ }
+ { cleartomark
+ (Usage: font2c fontname cfilename.c [shortname]\n) print
+ ( e.g.: font2c Courier cour.c\n) print flush
+ mark
+ }
+ ifelse
+ }
+if pop
diff --git a/gs/lib/golfer.ps b/gs/lib/golfer.ps
new file mode 100644
index 000000000..930f777de
--- /dev/null
+++ b/gs/lib/golfer.ps
@@ -0,0 +1,1398 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%Creator:Adobe Illustrator(TM) 1.0b2-
+%%Title:golfer art+
+%%CreationDate:1/6/87 9:32 AM
+%%DocumentFonts:Helvetica-Bold
+%%BoundingBox:7 31 577 726
+%%TemplateBox:0 -48 576 672
+%%EndComments
+100 dict begin
+/q{bind def}bind def
+/Q{load def}q
+/x{exch def}q
+/X/def Q
+/g{/_g x/p{_g setgray}X}q
+/G{/_G x/P{_G setgray}X}q
+/k{/_b x/_g x/_r x/p{_r _g _b setrgbcolor}X}q
+/K{/_B x/_G x/_R x/P{_R _G _B setrgbcolor}X}q
+/d/setdash Q
+/i/setflat Q
+/j/setlinejoin Q
+/J/setlinecap Q
+/M/setmiterlimit Q
+/w/setlinewidth Q
+/_C{.25 sub round .25 add}q
+/_c{transform _C exch _C exch itransform}q
+/c{_c curveto}q
+/C/c Q
+/v{currentpoint 6 2 roll _c curveto}q
+/V/v Q
+/y{_c 2 copy curveto}q
+/Y/y Q
+/l{_c lineto}q
+/L/l Q
+/m{_c moveto}q
+/_e[]X
+/_E{_e length 0 ne{gsave 1 g 0 G 1 i 0 J 0 j .5 w 10 M[]0 d
+/Helvetica-Bold 24 0 0 1 z
+[0.966 0.259 -0.259 0.966
+_e 0 get _e 2 get add 2 div _e 1 get _e 3 get add 2 div]a
+(ERROR: can't fill a path)t T grestore}if}q
+/n/newpath Q
+/N/newpath Q
+/F{p{fill}stopped{/_e[pathbbox]X n _E}if}q
+/f{closepath F}q
+/S{P stroke}q
+/s{closepath S}q
+/B{gsave F grestore S}q
+/b{closepath B}q
+/u{}q
+/U{}q
+/_s/ashow Q
+/_S{(?)exch{2 copy 0 exch put pop dup true charpath currentpoint _m setmatrix
+stroke _M setmatrix moveto 3 copy pop rmoveto}forall pop pop pop n}q
+/_A{_a moveto _t exch 0 exch}q
+/_L{0 _l neg translate _M currentmatrix pop}q
+/_w{dup stringwidth exch 3 -1 roll length 1 sub _t mul add exch}q
+/_z[{0 0}bind{dup _w exch neg 2 div exch neg 2 div}bind
+{dup _w exch neg exch neg}bind]X
+/z{_z exch get/_a x/_t x/_l x exch findfont exch scalefont setfont}q
+/_d{matrix currentmatrix X}q
+/_D{/_m _d gsave concat/_M _d}q
+/e{_D p/t{_A _s _L}X}q
+/r{_D P/t{_A _S _L}X}q
+/a{_D/t{dup p _A _s P _A _S _L}X}q
+/o{_D/t{pop _L}X}q
+/T{grestore}q
+/Z{findfont begin currentdict dup length dict begin
+{1 index/FID ne{X}{pop pop}ifelse}forall/FontName exch X dup length 0 ne
+{/Encoding Encoding 256 array copy X 0 exch{dup type/nametype eq
+{Encoding 2 index 2 index put pop 1 add}{exch pop}ifelse}forall}if pop
+currentdict dup end end/FontName get exch definefont pop}q
+n
+%%EndProlog
+u
+0.9 g
+0 G
+1 i
+0 J
+0 j
+1 w
+10 M
+[]0 d
+%%Note:
+15.815 40.248 m
+567.815 40.002 L
+567.748 716.565 L
+15.998 716.81 L
+15.815 40.248 L
+b
+U
+1 g
+285.313 40 m
+567.688 40.125 L
+567.812 78.375 L
+285.312 78.25 L
+285.313 40 L
+b
+0 g
+175.5 163 m
+180.007 163 173.738 169.081 171.75 168.75 c
+174.75 169.25 176.25 169.5 174.5 171.25 C
+178 171.25 176.349 173.783 175 176.75 c
+173.75 179.5 170.75 182.25 168.25 182 C
+165.5 181.25 167.622 182.838 165.25 186 c
+164.5 187 164.75 187.5 161.75 186.75 c
+158.75 186 163.25 190 156.75 190 c
+150.25 190 148.5 189 145.5 186 c
+142.5 183 139.75 183.75 139.5 182.5 c
+139.25 181.25 139.5 176.75 138.75 175.5 c
+138 174.25 136.75 174.25 136.25 178 c
+135.75 181.75 140.25 182.25 134 187 C
+135.75 190.75 134.5 191.75 131 193.5 C
+131 200 129.202 203.364 119.5 208.5 c
+115.25 210.75 107 212.75 104.75 208.75 c
+102.5 204.75 103 206.5 96.5 205.75 c
+90 205 87.25 202.5 86.5 197.75 c
+85.75 193 82.75 195 79 194.75 c
+75.25 194.5 77 192.75 77.25 191.75 c
+77.5 190.75 75.25 192.5 71.5 192 c
+67.75 191.5 64.25 185.5 69.5 180.75 c
+74.75 176 66.5 180.75 64.25 182.25 c
+62 183.75 60.5 181.75 61 180.25 c
+61.5 178.75 58.75 180.75 57.5 180.75 c
+56.25 180.75 51.008 180.188 52 172.25 c
+52.25 170.25 51.5 170.5 49.75 169.25 c
+48 168 45.75 164.25 48.5 158.75 c
+51.25 153.25 49 150 48 145.5 c
+47 141 48 138.25 51.25 137.25 c
+54.5 136.25 54 133.791 54 130.75 C
+57 130.5 59 129.25 58.75 124.5 C
+62.25 124.5 61.75 126.75 62.5 130 c
+63.25 133.25 65.75 129 66.25 127 c
+66.75 125 67.5 125 72 125 C
+74.75 116.25 74.75 120.5 75.25 117.25 C
+80 117.5 79.5 116.75 83.25 113.75 c
+87 110.75 88.25 115.5 92 118.5 c
+95.75 121.5 94.25 122.75 96.25 118.75 c
+98.25 114.75 98.5 119 101.5 119.25 c
+104.5 119.5 101 115.75 105.25 114.5 c
+109.5 113.25 105 113.75 103.5 111.25 c
+102 108.75 95 103.5 101.75 101.5 c
+108.5 99.5 103.5 99.75 94.75 99.5 c
+86 99.25 73.75 87.5 97.25 73.25 C
+117.25 53.25 117.25 53.5 v
+117.25 53.75 175.25 163 175.5 163 c
+f
+1 J
+0.2 w
+389.709 210.076 m
+511.826 210.076 l
+S
+394.709 212.461 m
+516.826 212.461 l
+S
+415.459 215.112 m
+537.576 215.112 l
+S
+399.709 217.762 m
+521.826 217.762 l
+S
+402.459 222.799 m
+524.576 222.799 l
+S
+402.709 225.45 m
+524.826 225.45 l
+S
+392.959 227.851 m
+515.076 227.851 l
+S
+400.691 232.856 m
+522.809 232.856 l
+S
+388.191 235.241 m
+510.309 235.241 l
+S
+393.941 237.892 m
+516.059 237.892 l
+S
+393.441 240.292 m
+515.559 240.292 l
+S
+396.191 242.928 m
+518.309 242.928 l
+S
+386.441 245.579 m
+508.559 245.579 l
+S
+393.191 248.23 m
+515.309 248.23 l
+S
+414.191 250.631 m
+536.309 250.631 l
+S
+397.95 252.973 m
+520.067 252.973 l
+S
+398.7 255.358 m
+520.817 255.358 l
+S
+400.7 258.009 m
+522.817 258.009 l
+S
+384.45 260.659 m
+506.567 260.659 l
+S
+380.7 265.696 m
+502.817 265.696 l
+S
+379.95 268.347 m
+502.067 268.347 l
+S
+386.7 270.748 m
+508.817 270.748 l
+S
+394.433 275.752 m
+516.55 275.752 l
+S
+381.933 278.138 m
+504.05 278.138 l
+S
+379.433 280.789 m
+501.55 280.789 l
+S
+383.183 283.189 m
+505.3 283.189 l
+S
+370.433 285.825 m
+492.55 285.825 l
+S
+382.433 288.476 m
+504.55 288.476 l
+S
+356.183 291.127 m
+478.3 291.127 l
+S
+372.433 293.277 m
+494.55 293.277 l
+S
+361.866 296.006 m
+483.984 296.006 l
+S
+365.616 298.406 m
+487.734 298.406 l
+S
+366.866 301.042 m
+488.984 301.042 l
+S
+346.866 303.693 m
+468.984 303.693 l
+S
+338.616 306.344 m
+460.734 306.344 l
+S
+330.866 308.494 m
+452.984 308.494 l
+S
+301.575 344.342 m
+423.692 344.342 l
+S
+314.075 346.728 m
+436.192 346.728 l
+S
+318.325 349.378 m
+440.442 349.378 l
+S
+312.075 352.029 m
+434.192 352.029 l
+S
+327.325 357.065 m
+449.442 357.065 l
+S
+327.575 359.716 m
+449.692 359.716 l
+S
+317.825 362.117 m
+439.942 362.117 l
+S
+335.558 367.122 m
+457.675 367.122 l
+S
+313.058 369.507 m
+435.175 369.507 l
+S
+318.808 372.158 m
+440.925 372.158 l
+S
+317.579 404.674 m
+439.696 404.674 l
+S
+322.312 409.179 m
+444.429 409.179 l
+S
+323.812 412.065 m
+445.929 412.065 l
+S
+329.562 414.715 m
+451.679 414.715 l
+S
+329.062 417.116 m
+451.179 417.116 l
+S
+331.812 419.752 m
+453.929 419.752 l
+S
+322.062 422.402 m
+444.179 422.402 l
+S
+328.812 425.053 m
+450.929 425.053 l
+S
+349.812 427.454 m
+471.929 427.454 l
+S
+333.571 429.796 m
+455.688 429.796 l
+S
+334.321 432.182 m
+456.438 432.182 l
+S
+336.321 434.832 m
+458.438 434.832 l
+S
+320.071 437.483 m
+442.188 437.483 l
+S
+316.321 442.519 m
+438.438 442.519 l
+S
+315.571 445.17 m
+437.688 445.17 l
+S
+322.321 447.571 m
+444.438 447.571 l
+S
+330.054 452.576 m
+452.171 452.576 l
+S
+317.554 454.961 m
+439.671 454.961 l
+S
+315.054 457.612 m
+437.171 457.612 l
+S
+318.804 460.012 m
+440.921 460.012 l
+S
+306.054 462.648 m
+428.171 462.648 l
+S
+300.054 465.299 m
+422.171 465.299 l
+S
+291.804 467.95 m
+413.921 467.95 l
+S
+308.054 470.101 m
+430.171 470.101 l
+S
+260.834 543.511 m
+382.951 543.511 l
+S
+246.066 548.016 m
+368.184 548.016 l
+S
+256.066 550.901 m
+378.184 550.901 l
+S
+253.566 553.552 m
+375.684 553.552 l
+S
+230.316 555.952 m
+352.434 555.952 l
+S
+244.566 558.588 m
+366.684 558.588 l
+S
+238.566 561.239 m
+360.684 561.239 l
+S
+230.316 563.89 m
+352.434 563.89 l
+S
+216.566 565.541 m
+338.684 565.541 l
+S
+104.443 572.01 m
+226.575 572.209 l
+S
+98.682 567.48 m
+220.814 567.68 l
+S
+91.688 565.11 m
+213.82 565.31 l
+S
+97.192 561.955 m
+219.324 562.155 l
+S
+73.943 559.517 m
+196.075 559.717 l
+S
+88.199 556.904 m
+210.331 557.103 l
+S
+82.203 554.243 m
+204.335 554.443 l
+S
+73.956 551.578 m
+196.088 551.778 l
+S
+73.707 549.405 m
+195.839 549.605 l
+S
+85.302 539.953 m
+207.434 540.152 l
+S
+79.541 535.423 m
+201.673 535.623 l
+S
+72.547 533.053 m
+194.679 533.253 l
+S
+78.051 529.898 m
+200.183 530.098 l
+S
+54.802 527.46 m
+176.934 527.66 l
+S
+69.058 524.847 m
+191.19 525.046 l
+S
+63.061 522.186 m
+185.194 522.385 l
+S
+54.815 519.521 m
+176.947 519.721 l
+S
+54.566 517.348 m
+176.698 517.547 l
+S
+u
+189.475 196.879 m
+311.592 196.879 l
+S
+176.975 199.265 m
+299.092 199.265 l
+S
+174.475 201.916 m
+296.592 201.916 l
+S
+178.225 204.316 m
+300.342 204.316 l
+S
+165.475 206.952 m
+287.592 206.952 l
+S
+177.475 209.603 m
+299.592 209.603 l
+S
+155.725 212.254 m
+277.842 212.254 l
+S
+167.475 214.404 m
+289.592 214.404 l
+S
+156.908 217.133 m
+279.026 217.133 l
+S
+144.658 219.533 m
+266.776 219.533 l
+S
+161.908 222.169 m
+284.026 222.169 l
+S
+153.908 224.82 m
+276.026 224.82 l
+S
+163.658 226.971 m
+285.776 226.971 l
+S
+152.408 229.121 m
+274.526 229.121 l
+S
+145.925 233.316 m
+268.042 233.316 l
+S
+157.675 235.466 m
+279.792 235.466 l
+S
+147.108 238.195 m
+269.226 238.195 l
+S
+134.858 240.595 m
+256.976 240.595 l
+S
+137.608 243.231 m
+259.726 243.231 l
+S
+144.108 245.882 m
+266.226 245.882 l
+S
+153.858 248.033 m
+275.976 248.033 l
+S
+155.108 231.183 m
+277.226 231.183 l
+S
+103.425 247.816 m
+225.542 247.816 l
+S
+100.175 249.966 m
+222.292 249.966 l
+S
+89.608 252.695 m
+211.726 252.695 l
+S
+77.358 255.095 m
+199.476 255.095 l
+S
+U
+u
+1 g
+0 J
+1 w
+120.001 389.999 m
+170.811 344.713 248.714 349.191 294.001 400.001 c
+339.287 450.811 334.809 528.714 283.999 574.001 c
+233.189 619.287 155.286 614.809 109.999 563.999 c
+64.713 513.189 69.191 435.286 120.001 389.999 c
+f
+202 482 m
+F
+U
+u
+258 302 m
+306.6 267.759 373.759 279.4 408 328 c
+442.241 376.6 430.6 443.759 382 478 c
+333.4 512.241 266.241 500.6 232 452 c
+197.759 403.4 209.4 336.241 258 302 c
+f
+320 390 m
+F
+U
+u
+196 376 m
+252.332 345.072 323.072 365.668 354 422 c
+384.928 478.332 364.332 549.072 308 580 c
+251.668 610.928 180.928 590.332 150 534 c
+119.072 477.668 139.668 406.928 196 376 c
+f
+252 478 m
+F
+U
+u
+106 257 m
+170.064 231.595 242.595 262.936 268 327 c
+293.405 391.064 262.064 463.595 198 489 c
+133.936 514.405 61.405 483.064 36 419 c
+10.595 354.936 41.936 282.405 106 257 c
+f
+152 373 m
+F
+U
+u
+366.001 122 m
+415.706 97.7 475.7 118.296 500 168.001 c
+524.3 217.706 503.704 277.7 453.999 302 c
+404.294 326.3 344.3 305.704 320 255.999 c
+295.7 206.294 316.296 146.3 366.001 122 c
+f
+410 212 m
+F
+U
+u
+227.999 198 m
+267.763 185.85 309.849 208.236 322 247.999 c
+334.15 287.763 311.764 329.849 272.001 342 c
+232.237 354.15 190.151 331.764 178 292.001 c
+165.85 252.237 188.236 210.151 227.999 198 c
+f
+250 270 m
+F
+U
+0 g
+15.75 71.25 m
+24.25 82.75 24.75 84.75 27.75 82.25 c
+30.75 79.75 31.75 81.25 32.75 82.75 c
+33.75 84.25 30.75 86.75 35.75 88.75 c
+40.75 90.75 41.25 91.75 43.25 89.75 c
+45.25 87.75 39.25 89.25 50.25 88.75 c
+61.25 88.25 70.25 81.75 74.25 75.25 c
+78.25 68.75 77.75 67.25 75.25 63.25 c
+72.75 59.25 68.25 56.75 72.25 57.25 c
+76.25 57.75 75.75 60.75 77.75 56.75 c
+79.75 52.75 80.25 51.25 79.25 49.25 c
+78.25 47.25 74.25 46.75 81.25 46.25 c
+88.25 45.75 91.75 37.557 91.75 40.25 c
+15.752 40.248 l
+15.75 71.25 l
+f
+340.75 55.5 m
+F
+u
+u
+3 w
+280.774 44.223 m
+567.893 44.223 l
+S
+280.774 48.728 m
+567.893 48.728 l
+S
+280.774 53.734 m
+567.893 53.734 l
+S
+U
+u
+280.774 58.739 m
+567.893 58.739 l
+S
+280.774 63.245 m
+567.893 63.245 l
+S
+280.774 68.251 m
+567.893 68.251 l
+S
+U
+u
+280.774 73.257 m
+567.893 73.257 l
+S
+280.774 78.263 m
+567.893 78.263 l
+S
+U
+U
+0.8 g
+0.2 w
+243 252 m
+323 235 l
+346 273 l
+368 248 l
+376 247 376 248 V
+377 174 380.5 121 330.5 40 C
+90.5 40 91.5 40 V
+138.5 129 163 162 214 200 C
+236 229 234.527 240.11 238 254 c
+240 262 243 252 y
+b
+0.5 g
+359.5 485 m
+389.267 485 402.5 486.25 415.75 489 c
+429 491.75 435 493.25 439 493.5 c
+443 493.75 490.398 537.797 502.5 562 c
+507 571 514.5 577 517.5 579.5 c
+520.5 582 501.5 591 y
+428 512 428 512.5 v
+428 513 356.5 510 356 509.5 c
+355.5 509 351 488 y
+359 485 359.5 485 v
+b
+0.7 g
+370 496.5 m
+368 480.5 365.5 472.5 364.5 471.5 C
+329.5 476.5 l
+323.5 489.5 l
+370 496.5 l
+b
+0.5 g
+352.75 494 m
+380 493.25 399.626 496.75 407.5 499 c
+418 502 424.586 497.135 432.75 505.5 c
+453 526.25 473.5 544.5 496.5 586.5 C
+473.5 590 473.5 590.5 V
+456 571.5 443 563.5 434 558 c
+425 552.5 416 544 408.5 534.5 C
+399 533 379.5 537.5 364 537.5 c
+348.5 537.5 352.75 494 y
+b
+1 g
+500 583 m
+500.5 577.098 517 573.5 520.5 572 c
+524 570.5 526.353 568.989 526.5 579 c
+526.675 590.992 541 586 539 624 C
+538.5 624 506 628 y
+499.958 583.498 500 583 v
+b
+0 g
+1 J
+3 w
+562 629 m
+343 645 217 644 77 601 C
+52 576 L
+59.5 562 80.132 560.877 87 589 c
+89.513 599.292 87 597 101 601 c
+108.323 603.092 265 654 561 617 C
+562 629 l
+f
+1 G
+0 J
+0.7 w
+305 634 m
+391.5 636.5 415 635 473 632 c
+S
+0.5 w
+213 626.5 m
+153.5 619 125.925 611.699 90.75 602.5 c
+78.654 599.337 82.567 597.884 82.5 592 c
+82.395 582.717 73.75 571 59 572.5 c
+S
+1 g
+0 G
+1 w
+73 595.25 m
+79.25 592.5 76.25 574.75 57.25 580 C
+73 595.25 l
+f
+0.5 g
+0.2 w
+312 574.25 m
+311.25 570.5 310.687 571.687 306.187 569.187 C
+307.687 564.187 311.106 565.66 304.5 561.5 c
+302.594 560.299 305.598 556.561 305.75 555.5 c
+306.038 553.485 304.629 548.098 297 548.5 c
+292.25 548.75 255.5 536 y
+229.5 608.5 l
+224 650 224.5 650 v
+248.101 650 273.345 678.918 298 655.5 c
+324.857 629.99 316.981 613.501 316.75 612.875 c
+313.346 603.644 313.238 604.937 314.75 597.375 c
+316.88 586.725 317.016 588.834 318.625 584.75 C
+320.25 581.875 318.625 580.375 y
+316.689 578.236 313.081 579.809 310.375 579 c
+307.013 577.994 312 574.25 y
+B
+0 g
+0.5 w
+288.5 456 m
+S
+0.2 w
+211 511 m
+194.5 518.5 187 520.5 170.5 500 C
+154.5 498.5 149.5 501 131.5 479.5 C
+151 477.5 140 475 161 460 c
+182 445 190.5 436.5 212 461 C
+224.5 458 229 454.5 238.5 447 C
+238 446.5 237 500.5 y
+211 511 l
+f
+1 g
+207.5 526.5 m
+206 514.5 204 506 236 490.5 C
+242.5 509.5 l
+207.5 526.5 l
+b
+0 g
+1 w
+294.464 627.589 m
+288.571 618.522 284.821 617.313 280 615.5 c
+275.179 613.686 271.429 605.224 277.857 587.089 C
+274.107 586.485 275.179 585.88 275.714 582.858 C
+271.429 599.179 270.357 606.433 259.643 609.455 c
+248.929 612.477 245.714 589.507 247.321 566.537 C
+228.572 554.448 L
+224.639 578.851 235.956 576.38 212.5 600.992 c
+194.17 620.226 195.893 654.791 225.357 658.418 C
+223.214 667.485 233.929 678.97 259.107 677.761 c
+284.286 676.552 281.071 667.485 Y
+302.5 667.485 334.964 665.942 301.429 614.895 C
+306.25 639.679 303.571 643.306 296.607 646.933 C
+299.286 634.239 294.464 627.589 y
+f
+0.7 g
+0.2 w
+207.5 524.5 m
+214.75 519.25 241.5 509 y
+239 504.5 l
+232 503 214.5 508.75 206.75 519 C
+207 522.5 207.5 524.5 y
+b
+1 g
+298 546.5 m
+272.625 574.625 248.5 596 195.5 568.5 C
+196.26 524.417 214.492 504.333 239.5 510.5 C
+298 546.5 l
+b
+0.8 g
+351.5 542 m
+367 540 L
+358.5 509.5 357 489.5 357 482 C
+323.5 482.5 295.5 485.5 284.5 477.5 c
+298.5 468.5 l
+299 457 l
+270.5 451 l
+238.5 483.5 l
+241 513.5 l
+250.5 538 252.5 547.5 282.5 550 C
+306.251 550 334.454 541.702 343.687 542.187 C
+342.576 538.175 346.737 538.055 351.5 542 c
+b
+0 g
+1 w
+333.25 484.75 m
+343.25 458.25 371.5 466 349 418.5 C
+359 348.5 378 357 363 336 C
+358.5 333 359 333 v
+359.5 333 353 328 359 327.5 c
+365 327 371 316.5 373.5 253.5 C
+381 245.5 l
+371 221 371 220.5 V
+360.5 247 358 253 351 261.5 C
+340 238 331.5 220.5 328.5 211.5 C
+301 229.5 265 250 232.5 244.5 C
+247.5 287 246 299.5 275 320.5 C
+270 331.5 268.689 334.634 265.75 336.25 c
+255.75 341.75 261.891 340.771 251 375 c
+247.5 386 249.5 384 255.5 399 C
+252.5 397 253.5 401 253.5 402.5 c
+253.5 404 252.057 400.023 251 402.5 c
+235 440 219.5 489.5 249.5 534 C
+238.5 503.5 242.102 477.13 260 463 c
+269.5 455.5 278.75 453.25 291 457.25 C
+297.5 461 299.549 465.787 282 476.75 C
+292.5 487.5 333.25 484.75 y
+f
+457.25 576.25 m
+454.936 574.233 453.51 595.217 479.25 583 C
+495.651 573.321 495.931 560.263 482.5 560.5 C
+486.25 566 491.682 565.465 478.5 575 c
+463.444 585.891 460.318 578.924 457.25 576.25 c
+f
+1 g
+460.75 581.5 m
+463.387 583.699 467.528 583.937 470.5 583.375 c
+473.752 582.76 473.75 581.75 Y
+461.735 583.841 458.891 579.95 460.75 581.5 c
+f
+0 g
+310.393 647.785 m
+329.089 651.66 328.75 623.692 320.178 607.976 C
+319.107 621.274 316.428 636.386 310.536 635.782 c
+304.643 635.177 310.393 647.785 y
+f
+284.286 663.858 m
+286.964 677.157 280.536 689.246 281.071 689.246 C
+289.107 677.761 288.036 665.672 y
+284.286 663.858 l
+f
+0.2 w
+274.643 683.201 m
+278.929 678.97 280 668.694 279.464 665.672 c
+S
+276.25 686.224 m
+284.393 677.036 283.75 662.045 y
+S
+1 w
+297.679 661.44 m
+312.602 661.44 312.143 677.157 310.536 680.784 C
+308.929 672.321 305.179 666.276 292.857 664.463 C
+297.679 661.44 l
+f
+0.2 w
+295 661.44 m
+298.75 666.276 302.5 675.343 294.464 683.201 c
+S
+300.357 681.992 m
+304.265 669.255 303.814 670.807 292.321 656.604 c
+S
+311.821 649.078 m
+321.464 649.078 330.571 646.66 329.5 627.921 c
+S
+307.536 650.892 m
+316.268 651.33 319.057 653.025 326.821 646.056 c
+330.446 642.802 331.1 637.618 331.107 637.593 c
+S
+304.643 665.067 m
+305.629 663.874 321.031 667.072 321.304 651.569 c
+S
+0.5 w
+311.071 639.679 m
+317.893 638.968 312.696 617.332 v
+S
+1 w
+313.375 612.875 m
+315.455 614.262 313.5 617.375 297.125 615.375 C
+310.375 616.625 311.875 611.875 313.375 612.875 c
+f
+1 g
+308.5 604.875 m
+309.833 600.875 309.125 601.25 307.375 599 C
+302.25 600.625 303.25 599.875 299 602.5 C
+304.25 604.75 308.375 605.25 308.5 604.875 c
+f
+0 g
+307.5 604.437 m
+305.463 602.811 305.481 601.49 307.375 598.937 C
+309.261 601.307 309.489 602.172 308.562 605.062 C
+308.562 604.937 308.191 604.989 307.5 604.437 c
+f
+0.2 w
+305.625 583.75 m
+304.687 582.562 306.5 579.375 308.875 579.75 c
+S
+1 w
+311.125 574.5 m
+310.25 573.898 310 573.437 304.937 569.312 C
+306.229 564.611 308.063 564.014 308.312 564.562 C
+309.775 566.476 307.663 569.565 306.687 569.75 C
+311.812 571.75 311.625 572.5 312 574.25 C
+311.687 574.75 311.176 574.535 311.125 574.5 c
+f
+298.625 603 m
+302 600.437 304.294 599.524 307.812 598.937 c
+308.187 598.875 308.562 598.5 308.687 597.875 c
+S
+297.5 602.25 m
+299.939 602.851 307.687 603.062 311.75 607.812 C
+307.812 606 297.011 602.129 297.5 602.25 c
+f
+213.5 576.125 m
+218.674 549.92 230.862 532.355 245.5 526.5 C
+243.75 514.5 209.75 494.25 195.5 568.5 C
+203.75 572.25 213.347 576.901 213.5 576.125 c
+f
+0.2 w
+343.375 541.75 m
+333.375 534.75 318.25 525.5 312 521.25 c
+S
+351.562 541.937 m
+337.936 530.579 327.2 525.581 313.25 517.75 c
+S
+0.3 w
+312.75 495 m
+291.75 483.5 276.25 476 274.25 466 c
+S
+0.5 w
+229 580.75 m
+235.5 571 241.25 554.75 245.75 528 c
+S
+1 w
+235 581 m
+246 555.75 246.75 537.75 245.75 526 C
+252.125 560.5 243.75 567.75 239.75 581.5 C
+240 581.5 237 581.75 235 581 C
+f
+0.7 g
+0.2 w
+248.625 580.5 m
+253.169 564.605 256.75 553.75 250.25 535.75 C
+257.5 552.75 259.125 558.937 252.875 579.687 C
+251.029 580.149 248.517 580.879 248.625 580.5 c
+b
+0 g
+1 w
+258.25 577.75 m
+262.047 567.879 262.5 552.5 259.25 544.25 C
+267.75 548.25 275 549.75 278.25 549.75 C
+281.75 555.25 282.75 556.75 279.5 565.25 C
+270.06 573.13 257.909 578.635 258.25 577.75 c
+f
+207.5 524.5 m
+F
+207.25 514.75 m
+207.185 514.86 228.75 497.5 238 500.75 C
+236 494.5 l
+225 498 213.924 503.454 207.25 514.75 c
+f
+1 g
+0.2 w
+191 516 m
+175.472 497.418 168.5 492 171.5 453 C
+185 443.5 189 443.5 200 450.5 C
+186.5 469.5 182 491 198.5 515.5 C
+194.5 516 191.339 516.406 191 516 c
+b
+201 515 m
+194 499 187 484 203.5 453 C
+206.5 455 211.5 460.5 212 461 C
+203.5 480.5 193.5 501.5 206 510.5 C
+205 499.5 210.5 490.5 232.5 473.5 C
+232.5 483 231.5 482.5 233 492 C
+221 498 210 505 208 512.5 C
+201 515 l
+b
+0 g
+1 G
+0.5 w
+268 442.5 m
+253.5 402.5 l
+S
+269.5 435.5 m
+258.5 407 258.5 407.5 v
+S
+0.5 G
+0.4 w
+293.5 480.5 m
+297.5 463.5 298.5 460.5 289 445.5 c
+S
+1 G
+1 J
+0.3 w
+349.125 418.125 m
+338.393 403.978 348.387 416.158 341.625 408.875 c
+S
+u
+1 g
+0 G
+0 J
+0.2 w
+336.038 340.015 m
+338.267 329.694 L
+342.937 338.843 L
+340.707 349.164 L
+336.038 340.015 L
+b
+339.487 339.429 m
+B
+U
+u
+328.791 340.569 m
+331.562 330.38 L
+335.743 339.762 L
+332.972 349.952 L
+328.791 340.569 L
+b
+332.267 340.166 m
+B
+U
+u
+321.758 340.67 m
+325.133 330.664 L
+328.746 340.28 L
+325.37 350.286 L
+321.758 340.67 L
+b
+325.252 340.475 m
+B
+U
+u
+314.504 340.97 m
+317.88 330.964 L
+321.492 340.58 L
+318.117 350.586 L
+314.504 340.97 L
+b
+317.998 340.775 m
+B
+U
+u
+u
+307.24 340.468 m
+311.982 331.033 L
+314.214 341.059 L
+309.473 350.494 L
+307.24 340.468 L
+b
+310.727 340.764 m
+B
+U
+u
+300.016 339.751 m
+304.757 330.316 L
+306.99 340.342 L
+302.249 349.777 L
+300.016 339.751 L
+b
+303.503 340.047 m
+B
+U
+U
+u
+u
+292.985 339.2 m
+298.349 330.104 L
+299.903 340.258 L
+294.54 349.353 L
+292.985 339.2 L
+b
+296.444 339.729 m
+B
+U
+u
+285.826 338 m
+291.189 328.904 L
+292.744 339.057 L
+287.38 348.153 L
+285.826 338 L
+b
+289.285 338.529 m
+B
+U
+U
+u
+278.742 336.229 m
+285.413 328.042 L
+285.423 338.314 L
+278.753 346.501 L
+278.742 336.229 L
+b
+282.083 337.272 m
+B
+U
+u
+272.228 332.392 m
+279.743 324.974 L
+278.644 335.186 L
+271.13 342.604 L
+272.228 332.392 L
+b
+275.437 333.789 m
+B
+U
+0 g
+1 G
+1 w
+266.25 335.5 m
+276.25 351.5 284.659 350 343 350 c
+364 350 363 336 y
+S
+271 321 m
+294 332 309 335 362 324 c
+S
+u
+1 g
+0 G
+0.2 w
+350.823 325.912 m
+364.33 322.302 L
+361.658 347.078 L
+348.151 350.689 L
+350.823 325.912 L
+b
+356.24 336.495 m
+B
+U
+0 g
+1 w
+274 347.5 m
+281.5 351.5 280.229 357.581 311 338 c
+316.5 334.5 322.5 338 351 357.5 C
+282 360 l
+274 347.5 l
+f
+1 G
+0.5 w
+269.25 355.75 m
+277.75 353.25 284.25 352.5 288.75 349.75 c
+S
+353.25 358.25 m
+347.25 354 345.5 353.5 339.75 349.5 c
+S
+0.3 w
+355.25 272.75 m
+359.75 281.5 361.25 285 363.25 290.75 c
+S
+0.5 G
+0.5 w
+354 219 m
+339 195 327 176 317 166 c
+S
+323 197 m
+310 150 308 135 235 48 c
+S
+1 w
+241 241.5 m
+232 227.5 215.231 198.443 215 198 c
+192.581 155 178 110 164 71 c
+S
+0 G
+0.2 w
+265.394 600.822 m
+263.576 606.114 262.122 612.994 253.035 607.173 C
+250.126 603.468 249.763 601.704 249.763 596.589 c
+249.763 591.473 254.307 592.179 257.76 587.24 c
+261.213 582.301 266.484 579.302 267.029 588.475 c
+S
+0.3 g
+260.668 605.409 m
+262.486 601.352 261.94 599.941 257.578 597.824 c
+253.216 595.707 257.76 591.473 260.305 592.355 c
+262.849 593.237 263.394 592.532 264.303 591.65 c
+265.212 590.768 266.666 591.826 264.667 594.119 c
+262.667 596.413 259.759 593.943 261.032 597.471 c
+262.304 600.999 260.668 605.409 y
+b
+0 g
+257.578 606.644 m
+254.125 605.056 251.58 604.174 251.58 598.177 c
+251.58 592.179 258.487 590.415 259.214 588.651 c
+S
+u
+1 g
+257.397 584.594 m
+258.601 581.671 262.019 580.25 265.03 581.419 c
+268.041 582.588 269.506 585.905 268.302 588.827 c
+267.097 591.75 263.679 593.172 260.668 592.003 c
+257.657 590.833 256.192 587.516 257.397 584.594 c
+b
+262.849 586.711 m
+B
+U
+u
+0.2 g
+1 w
+258.487 586.358 m
+263.213 582.477 L
+267.211 587.063 L
+262.486 590.944 L
+258.487 586.358 L
+f
+262.849 586.711 m
+F
+U
+0 g
+309.25 579.875 m
+310.75 580.5 313.25 583.125 314.625 581 c
+F
+1 g
+307.964 565.926 m
+307.88 566.015 306.794 566.513 307.22 566.682 c
+307.647 566.851 307.68 566.599 307.935 566.639 C
+307.924 566.13 307.971 566.31 307.964 565.926 c
+f
+510 104 m
+509.564 104.895 511.5 89 495.5 74.5 C
+495.5 68 l
+506 79 518.582 86.358 510 104 c
+f
+0 g
+0.2 w
+403.75 534.25 m
+413.25 533.75 415.75 534.25 417.75 534.75 c
+S
+1 G
+0.3 w
+538.5 629 m
+542 625 547.5 620 y
+S
+548.75 629.25 m
+552.25 625.25 557.75 620.25 y
+S
+0 G
+0.2 w
+518.5 587.5 m
+522.5 586 526 587.5 527 587.5 c
+S
+514 617.5 m
+518 614 518.5 611.5 520 607.5 c
+S
+528.25 613.75 m
+533.25 615.25 532.5 615.5 538.25 614.25 c
+S
+1 g
+538 637.5 m
+537.25 618 533 617.5 531.25 617.5 c
+529.5 617.5 528.235 615.255 528.5 622.5 c
+529.25 643 528.775 643.326 534.25 642.75 c
+539 642.25 539 642.25 540.5 630.75 C
+538 631 l
+538 629 538 631.25 v
+538 633.5 538 637.5 Y
+b
+0.7 g
+507.5 650.75 m
+510 648.5 510.25 645.75 511.75 643.25 c
+513.25 640.75 508.5 638.25 508.5 638 c
+508.5 637.75 507.5 650.75 y
+b
+1 g
+529.25 639.25 m
+528.5 643 527 642.75 524 642.75 c
+521 642.75 519.75 644 519.5 632.25 C
+519.75 638 519.75 641 v
+519.75 644 518.75 644.25 515.25 644.25 c
+511.75 644.25 511.75 646 509.25 641.25 c
+506.75 636.5 505.75 633.25 506 633.25 c
+506.25 633.25 509.75 628.25 Y
+511.5 620.25 512.75 619.75 515.5 619.5 c
+518.25 619.25 520.25 618.25 519.5 623.5 C
+521 618.25 521 617.75 524.75 617 c
+528.5 616.25 528.5 618.25 528.5 622.5 c
+528.5 626.75 529.25 639.25 y
+b
+507.75 636.75 m
+512.687 638.231 515.604 641 515.25 641 C
+517.839 637.469 517.494 629.281 508.75 625.5 C
+508.75 625.25 502 635 502.25 634.75 c
+502.5 634.5 507.75 636.75 y
+b
+493.5 571.5 m
+495.171 563.425 503.634 565.498 503.5 576.25 c
+503.25 596.25 515.75 586.25 509 636.75 c
+508.301 641.977 510 650.75 506.5 651.5 c
+501.514 652.568 500.436 652.26 499.25 644.75 c
+498.5 640 496.5 646.25 496 648.5 c
+495.5 650.75 493.75 651 490.75 650.25 c
+487.75 649.5 488.253 648.665 487.5 645.5 c
+486.194 640.013 486.75 641.75 484.5 645.5 c
+482.39 649.016 481.306 648.011 477.5 647.25 c
+475 646.75 474.784 644.479 475.25 640.75 c
+475.5 638.75 474 642.25 472.5 644.5 c
+471 646.75 469.25 645.5 466.5 645.5 c
+463.75 645.5 463.25 641.003 463.5 635.5 c
+463.511 635.25 463 626.25 y
+449.75 627.25 l
+459.25 618.5 465.606 612.863 468.25 597 c
+468.75 594 468 592.25 470 592.75 C
+459.719 593.497 459.195 585.398 461 586 c
+466.25 587.75 471.75 589.25 476.75 587 c
+481.75 584.75 486.25 584.25 489.5 586.25 C
+490.25 582.75 492 578.75 493.5 571.5 c
+b
+0 g
+486.25 592.5 m
+489 595.25 492.117 593.078 492.25 592.75 c
+494.972 586.028 477 591.75 467.25 593 c
+S
+0.4 w
+470 592.75 m
+474.25 595.75 475 596 481.5 595.75 c
+S
+1 J
+2.5 w
+477.75 630 m
+478.5 620.75 l
+S
+479.25 617.5 m
+480 610.5 l
+S
+480.25 607.75 m
+481 600.25 481 600.5 v
+S
+487.5 631.75 m
+487.75 623.5 l
+S
+487.75 620.75 m
+487.75 612.5 l
+S
+488 609.25 m
+488.25 609.25 487.75 602.5 y
+S
+498 630.75 m
+497.25 623.75 l
+S
+496.75 620.75 m
+495.5 612.5 l
+S
+495.25 609.5 m
+493.75 602 l
+S
+0 J
+0.2 w
+465.5 637.25 m
+464.5 629.75 461.25 628.75 464.75 617 c
+S
+0.5 w
+502 589.25 m
+503.25 585 503.5 583.25 503.5 577 c
+S
+1 g
+1 w
+521.949 86.694 m
+521.637 87.353 523.021 75.657 511.583 64.988 C
+511.583 60.205 l
+519.089 68.299 528.083 73.713 521.949 86.694 c
+f
+553.457 99.673 m
+553.091 100.449 554.713 86.67 541.309 74.1 C
+541.309 68.465 l
+550.105 78.001 560.646 84.379 553.457 99.673 c
+f
+482.74 95.04 m
+482.429 95.699 483.812 84.003 472.375 73.334 C
+472.375 68.551 l
+479.881 76.645 488.875 82.059 482.74 95.04 c
+f
+450.924 87.63 m
+450.69 88.028 451.731 80.968 443.129 74.528 C
+443.129 71.641 l
+448.774 76.527 455.538 79.795 450.924 87.63 c
+f
+0 g
+308 61.5 m
+N
+3 w
+16.002 40.373 m
+568.002 40.127 L
+567.748 716.565 L
+S
+u
+15.815 40.248 m
+567.815 40.002 L
+567.748 716.565 L
+15.998 716.81 L
+15.815 40.248 L
+s
+U
+%%Trailer
+_E end
+showpage
diff --git a/gs/lib/grayalph.ps b/gs/lib/grayalph.ps
new file mode 100644
index 000000000..d7ed52d61
--- /dev/null
+++ b/gs/lib/grayalph.ps
@@ -0,0 +1,61 @@
+%!
+% grayscaled text test, including a trivial user bitmap font
+
+/inch {72 mul} def
+
+/BuildCharDict 10 dict def
+/$ExampleFont 7 dict def
+$ExampleFont begin
+ /FontType 3 def % user defined font.
+ /FontMatrix [1 0 0 1 0 0] def
+ /FontBBox [0 0 1 1] def
+ /Encoding 256 array def
+ 0 1 255 {Encoding exch /.notdef put} for
+ Encoding (a) 0 get /plus put
+ /CharStrings 2 dict def
+ CharStrings /.notdef {} put
+ CharStrings /plus
+ { gsave
+ 0 0 moveto
+ 32 32 true [32 0 0 -32 0 32]
+ {<0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000
+ 0007E000 0007E000 0007E000 0007E000 0007E000 FFFFFFFF FFFFFFFF FFFFFFFF
+ FFFFFFFF FFFFFFFF FFFFFFFF 0007E000 0007E000 0007E000 0007E000 0007E000
+ 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000>
+ } imagemask
+ grestore
+ } put
+ /BuildChar
+ { BuildCharDict begin
+ /char exch def
+ /fontdict exch def
+ /charproc
+ fontdict /Encoding get char get
+ fontdict /CharStrings get
+ exch get def
+ 1 0 0 0 1 1 setcachedevice
+ charproc
+ end
+ } def
+end
+
+/MyFont $ExampleFont definefont pop
+
+ newpath
+ .5 inch 7.5 inch moveto
+ 7.5 inch 0 rlineto
+ 0 1.5 inch rlineto
+ -7.5 inch 0 rlineto
+ closepath
+ 0 setgray
+ fill
+
+ /MyFont findfont 72 scalefont setfont
+ .75 inch 7.75 inch moveto
+ 0 1 6
+ { /n exch def
+ 1 n 6 div sub setgray
+ (a) show
+ } for
+
+showpage
diff --git a/gs/lib/gs_btokn.ps b/gs/lib/gs_btokn.ps
new file mode 100644
index 000000000..afba44651
--- /dev/null
+++ b/gs/lib/gs_btokn.ps
@@ -0,0 +1,283 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for binary tokens.
+% When this is run, systemdict is still writable,
+% but everything defined here goes into level2dict.
+
+% Define whether or not to allow writing dictionaries.
+/WRITEDICTS true def
+
+languagelevel 1 .setlanguagelevel
+level2dict begin
+
+% Initialization for the system name table.
+
+mark
+% 0
+ /abs /add /aload /anchorsearch /and
+ /arc /arcn /arct /arcto /array
+ /ashow /astore /awidthshow /begin /bind
+ /bitshift /ceiling /charpath /clear /cleartomark
+% 20
+ /clip /clippath /closepath /concat /concatmatrix
+ /copy /count /counttomark /currentcmykcolor /currentdash
+ /currentdict /currentfile /currentfont /currentgray /currentgstate
+ /currenthsbcolor /currentlinecap /currentlinejoin /currentlinewidth /currentmatrix
+% 40
+ /currentpoint /currentrgbcolor /currentshared /curveto /cvi
+ /cvlit /cvn /cvr /cvrs /cvs
+ /cvx /def /defineusername /dict /div
+ /dtransform /dup /end /eoclip /eofill
+% 60
+ /eoviewclip /eq /exch /exec /exit
+ /file /fill /findfont /flattenpath /floor
+ /flush /flushfile /for /forall /ge
+ /get /getinterval /grestore /gsave /gstate
+% 80
+ /gt /identmatrix /idiv /idtransform /if
+ /ifelse /image /imagemask /index /ineofill
+ /infill /initviewclip /inueofill /inufill /invertmatrix
+ /itransform /known /le /length /lineto
+% 100
+ /load /loop /lt /makefont /matrix
+ /maxlength /mod /moveto /mul /ne
+ /neg /newpath /not /null /or
+ /pathbbox /pathforall /pop /print /printobject
+% 120
+ /put /putinterval /rcurveto /read /readhexstring
+ /readline /readstring /rectclip /rectfill /rectstroke
+ /rectviewclip /repeat /restore /rlineto /rmoveto
+ /roll /rotate /round /save /scale
+% 140
+ /scalefont /search /selectfont /setbbox /setcachedevice
+ /setcachedevice2 /setcharwidth /setcmykcolor /setdash /setfont
+ /setgray /setgstate /sethsbcolor /setlinecap /setlinejoin
+ /setlinewidth /setmatrix /setrgbcolor /setshared /shareddict
+% 160
+ /show /showpage /stop /stopped /store
+ /string /stringwidth /stroke /strokepath /sub
+ /systemdict /token /transform /translate /truncate
+ /type /uappend /ucache /ueofill /ufill
+% 180
+ /undef /upath /userdict /ustroke /viewclip
+ /viewclippath /where /widthshow /write /writehexstring
+ /writeobject /writestring /wtranslation /xor /xshow
+ /xyshow /yshow /FontDirectory /SharedFontDirectory /Courier
+% 200
+ /Courier-Bold /Courier-BoldOblique /Courier-Oblique /Helvetica /Helvetica-Bold
+ /Helvetica-BoldOblique /Helvetica-Oblique /Symbol /Times-Bold /Times-BoldItalic
+ /Times-Italic /Times-Roman /execuserobject /currentcolor /currentcolorspace
+ /currentglobal /execform /filter /findresource /globaldict
+% 220
+ /makepattern /setcolor /setcolorspace /setglobal /setpagedevice
+ /setpattern
+% pad to 256
+ counttomark 256 exch sub { 0 } repeat
+% 256
+ /= /== /ISOLatin1Encoding /StandardEncoding
+% 260
+ ([) cvn (]) cvn /atan /banddevice /bytesavailable
+ /cachestatus /closefile /colorimage /condition /copypage
+ /cos /countdictstack /countexecstack /cshow /currentblackgeneration
+ /currentcacheparams /currentcolorscreen /currentcolortransfer /currentcontext /currentflat
+% 280
+ /currenthalftone /currenthalftonephase /currentmiterlimit /currentobjectformat /currentpacking
+ /currentscreen /currentstrokeadjust /currenttransfer /currentundercolorremoval /defaultmatrix
+ /definefont /deletefile /detach /deviceinfo /dictstack
+ /echo /erasepage /errordict /execstack /executeonly
+% 300
+ /exp /false /filenameforall /fileposition /fork
+ /framedevice /grestoreall /handleerror /initclip /initgraphics
+ /initmatrix /instroke /inustroke /join /kshow
+ /ln /lock /log /mark /monitor
+% 320
+ /noaccess /notify /nulldevice /packedarray /quit
+ /rand /rcheck /readonly /realtime /renamefile
+ /renderbands /resetfile /reversepath /rootfont /rrand
+ /run /scheck /setblackgeneration /setcachelimit /setcacheparams
+% 340
+ /setcolorscreen /setcolortransfer /setfileposition /setflat /sethalftone
+ /sethalftonephase /setmiterlimit /setobjectformat /setpacking /setscreen
+ /setstrokeadjust /settransfer /setucacheparams /setundercolorremoval /sin
+ /sqrt /srand /stack /status /statusdict
+% 360
+ /true /ucachestatus /undefinefont /usertime /ustrokepath
+ /version /vmreclaim /vmstatus /wait /wcheck
+ /xcheck /yield /defineuserobject /undefineuserobject /UserObjects
+ /cleardictstack
+% 376
+ /A /B /C /D /E /F /G /H /I /J /K /L /M
+ /N /O /P /Q /R /S /T /U /V /W /X /Y /Z
+ /a /b /c /d /e /f /g /h /i /j /k /l /m
+ /n /o /p /q /r /s /t /u /v /w /x /y /z
+% 428
+ /setvmthreshold (<<) cvn
+ (>>) cvn /currentcolorrendering /currentdevparams /currentoverprint /currentpagedevice
+ /currentsystemparams /currentuserparams /defineresource /findencoding /gcheck
+% 440
+ /glyphshow /languagelevel /product /pstack /resourceforall
+ /resourcestatus /revision /serialnumber /setcolorrendering /setdevparams
+ /setoverprint /setsystemparams /setuserparams /startjob /undefineresource
+ /GlobalFontDirectory /ASCII85Decode /ASCII85Encode /ASCIIHexDecode /ASCIIHexEncode
+% 460
+ /CCITTFaxDecode /CCITTFaxEncode /DCTDecode /DCTEncode /LZWDecode
+ /LZWEncode /NullEncode /RunLengthDecode /RunLengthEncode /SubFileDecode
+ /CIEBasedA /CIEBasedABC /DeviceCMYK /DeviceGray /DeviceRGB
+ /Indexed /Pattern /Separation
+% 478 -- end
+.packtomark
+dup /SystemNames exch def .installsystemnames
+
+% Define printobject and writeobject.
+% These are mostly implemented in PostScript, so that we don't have to
+% worry about interrupts or callbacks when writing to the output file.
+
+% Define procedures for accumulating the space required to represent
+% an object in binary form.
+/cntdict mark % <#refs> <#chars> <obj> -proc- <#refs> <#chars>
+ /integertype /pop load
+ /realtype 1 index
+ /marktype 1 index
+ /nulltype 1 index
+ /booleantype 1 index
+ /nametype { length add } bind
+ /stringtype 1 index
+ /arraytype null
+ WRITEDICTS { /dicttype null } if
+.dicttomark def
+cntdict /arraytype
+ { dup dup length 5 -1 roll add 4 2 roll
+ { dup type //cntdict exch get exec } forall
+ } bind put
+WRITEDICTS
+ { cntdict /dicttype
+ { dup dup length 2 mul 5 -1 roll add 4 2 roll
+ { 4 1 roll dup type //cntdict exch get exec
+ 3 -1 roll dup type //cntdict exch get exec
+ } forall
+ } bind put
+ } if
+
+/w2dict mark
+ /nametype { 2 copy .writecvs pop } bind
+ /stringtype 1 index
+.dicttomark def
+
+/.writeobjects % <file> <tag> <array> .writeobjects -
+ {
+ mark exch
+
+ % Count the space required for refs and strings.
+ dup length 0 3 -1 roll
+ % Stack: <file> <tag> -mark- <#refs> <#chars> <array>
+
+ dup 4 1 roll
+ { dup type //cntdict exch get exec
+ } forall
+
+ % Write the header.
+ % Stack: <file> <tag> -mark- <array1> ... <array|dictN> <#refs> <#chars>
+ counttomark 3 add -2 roll 4 1 roll
+ % Stack: -mark- <array1> ... <array|dictN> <tag> <#refs> <#chars> <file>
+ dup counttomark 1 sub index length
+ 4 index 3 bitshift 4 index add
+ (xxxxxxxx) .bosheader writestring
+
+ % Write the objects per se.
+ 3 1 roll pop
+ counttomark 1 sub index length 3 bitshift exch
+ 3 bitshift
+ % Stack: -mark- <array1> ... <array|dictN> <tag> <file> <ref#> <char#>
+
+ counttomark 4 sub
+ { counttomark -1 roll dup 6 1 roll
+ dup type /dicttype eq % can't be first object
+ { { 5 1 roll (xxxxxxxx) .bosobject
+ 3 index exch writestring
+ 4 -1 roll (xxxxxxxx) .bosobject
+ 3 index exch writestring
+ } forall
+ }
+ { { (xxxxxxxx) .bosobject
+ dup 1 6 index put
+ 3 index exch writestring
+ 4 -1 roll pop 0 4 1 roll % clear tag
+ } forall
+ }
+ ifelse
+ }
+ repeat
+
+ % Write the strings and names.
+ pop pop exch pop
+ % Stack: -mark- <array1> ... <array|dictN> <file>
+
+ counttomark 1 sub
+ { counttomark -1 roll
+ { % The counting pass ensured that the keys and values
+ % of any dictionary must be writable objects.
+ % Hence, we are processing a dictionary iff
+ % the next-to-top stack element is not a file.
+ 1 index type /filetype ne
+ { exch 2 index exch dup type //w2dict exch .knownget
+ { exec } { pop } ifelse pop
+ }
+ if
+ dup type //w2dict exch .knownget { exec } { pop } ifelse
+ } forall
+ }
+ repeat
+
+ % Clean up.
+ % Stack: -mark- <file>
+
+ pop pop
+
+ } odef
+currentdict /cntdict .undef
+currentdict /w2dict .undef
+
+/printobject { % <obj> <tag> printobject -
+ (%stdout) (w) file 2 index 2 index writeobject pop pop
+} odef
+/writeobject { % <file> <obj> <tag> writeobject -
+ 3 copy exch
+ % We must allocate the array in local VM
+ % to avoid a possible invalidaccess.
+ .currentglobal false .setglobal exch 1 array astore exch .setglobal
+ .writeobjects pop pop pop
+} odef
+
+% Implement binary error message output.
+ /.printerror
+ { $error /binary get .languagelevel 2 eq and
+ { currentobjectformat 0 ne
+ { [ /Error $error /errorname get $error /command get false
+ ] 250 printobject
+ }
+ //.printerror
+ ifelse
+ }
+ //.printerror
+ ifelse
+ } bind def
+
+% End of level2dict
+
+end
+.setlanguagelevel
diff --git a/gs/lib/gs_ccfnt.ps b/gs/lib/gs_ccfnt.ps
new file mode 100644
index 000000000..0c37d7e4f
--- /dev/null
+++ b/gs/lib/gs_ccfnt.ps
@@ -0,0 +1,93 @@
+% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Find and register all the precompiled font operators in systemdict.
+
+/registerfont % <fontname> <fontdict> registerfont <font>
+ { DEBUG { (Registering ) print 1 index = } if
+ dup begin
+ Encoding type /nametype eq
+ { Encoding .findencoding /Encoding exch def
+ }
+ if
+ dup /PrefEnc known
+ { PrefEnc type /nametype eq
+ { PrefEnc .findencoding /PrefEnc exch def
+ }
+ if
+ }
+ if
+ dup /FDepVector known
+ { /FDepVector [ FDepVector
+ { .FontDirectory 1 index .knownget
+ { exch pop }
+ { ccfonts 1 index .knownget
+ { registerfont
+ }
+ { Fontmap 1 index known
+ { findfont }
+ { pop NullFont }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+ }
+ forall ] readonly def
+ }
+ if
+ end
+ % Use the value of definefont appropriate at run-time, not bind-time
+ /definefont load exec
+ } bind odef
+% Bind recursive call (bind descends into oparrays: feature!)
+/registerfont dup load bind def
+
+/.loadinitialfonts {
+ //.loadinitialfonts exec
+ /ccfonts mark
+ 0 1 null .getccfont 1 sub { .getccfont dup /FontName get exch } for
+ .dicttomark def
+ ccfonts
+ { .FontDirectory 2 index known { pop pop } { registerfont pop } ifelse }
+ forall
+ currentdict /ccfonts .undef
+} bind def
+
+currentdict /registerfont .undef
+
+
+% If we're in a Level 2 system but running in Level 1 mode,
+% register the fonts explicitly as resources.
+% This is a bit of a hack, but doing better is too much work.
+
+/level2dict where
+ { pop /findresource where
+ { % Level 2 system, Level 2 mode
+ pop
+ }
+ { % Level 2 system, Level 1 mode
+ /Font /Category level2dict /findresource get exec begin
+ .FontDirectory
+ { dup .gcheck { Instances } { LocalInstances } ifelse
+ 3 1 roll [exch 0 -1] .growput
+ }
+ forall end
+ }
+ ifelse
+ }
+if
diff --git a/gs/lib/gs_cff.ps b/gs/lib/gs_cff.ps
new file mode 100644
index 000000000..7510443a5
--- /dev/null
+++ b/gs/lib/gs_cff.ps
@@ -0,0 +1,605 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Loader for CFF (compressed) fonts.
+% The following are not implemented yet:
+% Deleted entries in the Name Index
+% Embedded PostScript
+% Multiple Master fonts
+% CIDFonts
+% Chameleon fonts
+% Synthetic fonts
+% Also, Type 2 charstrings are converted into Type 1 fonts with
+% CharstringType = 2, which may or may not be supported.
+
+30 dict begin
+
+% ---------------- Standard strings (actually names) ---------------- %
+
+/StandardStrings mark
+% 0
+ /.notdef /space /exclam /quotedbl /numbersign
+ /dollar /percent /ampersand /quoteright /parenleft
+ /parenright /asterisk /plus /comma /hyphen
+ /period /slash /zero /one /two
+ /three /four /five /six /seven
+ /eight /nine /colon /semicolon /less
+ /equal /greater /question /at /A
+ /B /C /D /E /F
+ /G /H /I /J /K
+ /L /M /N /O /P
+% 50
+ /Q /R /S /T /U
+ /V /W /X /Y /Z
+ /bracketleft /backslash /bracketright /asciicircum /underscore
+ /quoteleft /a /b /c /d
+ /e /f /g /h /i
+ /j /k /l /m /n
+ /o /p /q /r /s
+ /t /u /v /w /x
+ /y /z /braceleft /bar /braceright
+ /asciitilde /exclamdown /cent /sterling /fraction
+% 100
+ /yen /florin /section /currency /quotesingle
+ /quotedblleft /guillemotleft /guilsinglleft /guilsinglright /fi
+ /fl /endash /dagger /daggerdbl /periodcentered
+ /paragraph /bullet /quotesinglbase /quotedblbase /quotedblright
+ /guillemotright /ellipsis /perthousand /questiondown /grave
+ /acute /circumflex /tilde /macron /breve
+ /dotaccent /dieresis /ring /cedilla /hungarumlaut
+ /ogonek /caron /emdash /AE /ordfeminine
+ /Lslash /Oslash /OE /ordmasculine /ae
+ /dotlessi /lslash /oslash /oe /germandbls
+% 150
+ /onesuperior /logicalnot /mu /trademark /Eth
+ /onehalf /plusminus /Thorn /onequarter /divide
+ /brokenbar /degree /thorn /threequarters /twosuperior
+ /registered /minus /eth /multiply /threesuperior
+ /copyright /Aacute /Acircumflex /Adieresis /Agrave
+ /Aring /Atilde /Ccedilla /Eacute /Ecircumflex
+ /Edieresis /Egrave /Iacute /Icircumflex /Idieresis
+ /Igrave /Ntilde /Oacute /Ocircumflex /Odieresis
+ /Ograve /Otilde /Scaron /Uacute /Ucircumflex
+ /Udieresis /Ugrave /Yacute /Ydieresis /Zcaron
+% 200
+ /aacute /acircumflex /adieresis /agrave /aring
+ /atilde /ccedilla /eacute /ecircumflex /edieresis
+ /egrave /iacute /icircumflex /idieresis /igrave
+ /ntilde /oacute /ocircumflex /odieresis /ograve
+ /otilde /scaron /uacute /ucircumflex /udieresis
+ /ugrave /yacute /ydieresis /zcaron /exclamsmall
+ /Hungarumlautsmall /dollaroldstyle /dollarsuperior /ampersandsmall /Acutesmall
+ /parenleftsuperior /parenrightsuperior /twodotenleader /onedotenleader /zerooldstyle
+ /oneoldstyle /twooldstyle /threeoldstyle /fouroldstyle /fiveoldstyle
+ /sixoldstyle /sevenoldstyle /eightoldstyle /nineoldstyle /commasuperior
+% 250
+ /threequartersemdash /periodsuperior /questionsmall /asuperior /bsuperior
+ /centsuperior /dsuperior /esuperior /isuperior /lsuperior
+ /msuperior /nsuperior /osuperior /rsuperior /ssuperior
+ /tsuperior /ff /ffi /ffl /parenleftinferior
+ /parenrightinferior /Circumflexsmall /hyphensuperior /Gravesmall /Asmall
+ /Bsmall /Csmall /Dsmall /Esmall /Fsmall
+ /Gsmall /Hsmall /Ismall /Jsmall /Ksmall
+ /Lsmall /Msmall /Nsmall /Osmall /Psmall
+ /Qsmall /Rsmall /Ssmall /Tsmall /Usmall
+ /Vsmall /Wsmall /Xsmall /Ysmall /Zsmall
+% 300
+ /colonmonetary /onefitted /rupiah /Tildesmall /exclamdownsmall
+ /centoldstyle /Lslashsmall /Scaronsmall /Zcaronsmall /Dieresissmall
+ /Brevesmall /Caronsmall /Dotaccentsmall /Macronsmall /figuredash
+ /hypheninferior /Ogoneksmall /Ringsmall /Cedillasmall /questiondownsmall
+ /oneeighth /threeeighths /fiveeighths /seveneighths /onethird
+ /twothirds /zerosuperior /foursuperior /fivesuperior /sixsuperior
+ /sevensuperior /eightsuperior /ninesuperior /zeroinferior /oneinferior
+ /twoinferior /threeinferior /fourinferior /fiveinferior /sixinferior
+ /seveninferior /eightinferior /nineinferior /centinferior /dollarinferior
+ /periodinferior /commainferior /Agravesmall /Aacutesmall /Acircumflexsmall
+% 350
+ /Atildesmall /Adieresissmall /Aringsmall /AEsmall /Ccedillasmall
+ /Egravesmall /Eacutesmall /Ecircumflexsmall /Edieresissmall /Igravesmall
+ /Iacutesmall /Icircumflexsmall /Idieresissmall /Ethsmall /Ntildesmall
+ /Ogravesmall /Oacutesmall /Ocircumflexsmall /Otildesmall /Odieresissmall
+ /OEsmall /Oslashsmall /Ugravesmall /Uacutesmall /Ucircumflexsmall
+ /Udieresissmall /Yacutesmall /Thornsmall /Ydieresissmall (001.000)
+ (001.001) (001.002) (001.003) /Black /Bold
+ /Book /Light /Medium /Regular /Roman
+ /Semibold
+.packtomark def
+
+% ---------------- Standard encodings ---------------- %
+
+/StandardEncodings [
+
+% StandardEncoding
+mark
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
+ 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
+ 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
+ 0 111 112 113 114 0 115 116 117 118 119 120 121 122 0 123
+ 0 124 125 126 127 128 129 130 131 0 132 133 0 134 135 136
+ 137 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 138 0 139 0 0 0 0 140 141 142 143 0 0 0 0
+ 0 144 0 0 0 145 0 0 146 147 148 149 0 0 0 0
+.packtomark
+
+% ExpertEncoding
+mark
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 229 230 0 231 232 233 234 235 236 237 238 13 14 15 99
+ 239 240 241 242 243 244 245 246 247 248 27 28 249 250 251 252
+ 0 253 254 255 256 257 0 0 0 258 0 0 259 260 261 262
+ 0 0 263 264 265 0 266 109 110 267 268 269 0 270 271 272
+ 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
+ 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 304 305 306 0 0 307 308 309 310 311 0 312 0 0 313
+ 0 0 314 315 0 0 316 317 318 0 0 0 158 155 163 319
+ 320 321 322 323 324 325 0 0 326 150 164 169 327 328 329 330
+ 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
+ 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
+ 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
+.packtomark
+
+] readonly def
+
+% ---------------- Standard Charsets ---------------- %
+
+% We include an explicit 0 at the beginning of each charset.
+
+/StandardCharsets [
+
+% ISOAdobe
+mark
+ 0
+ 1 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
+.packtomark
+
+% Expert
+mark
+ 0
+ 1 229 230 231 232 233 234 235 236 237 238 13 14 15 99 239
+ 240 241 242 243 244 245 246 247 248 27 28 249 250 251 252 253
+ 254 255 256 257 258 259 260 261 262 263 264 265 266 109 110 267
+ 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
+ 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
+ 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
+ 316 317 318 158 155 163 319 320 321 322 323 324 325 326 150 164
+ 169 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
+ 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
+ 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
+ 374 375 376 377 378
+.packtomark
+
+% ExpertSubset
+mark
+ 0
+ 1 231 232 235 236 237 238 13 14 15 99 239 240 241 242 243
+ 244 245 246 247 248 27 28 249 250 251 253 254 255 256 257 258
+ 259 260 261 262 263 264 265 266 109 110 267 268 269 270 272 300
+ 301 302 305 314 315 158 155 163 320 321 322 323 324 325 326 150
+ 164 169 327 328 329 330 331 332 333 334 335 336 337 338 339 340
+ 341 342 343 344 345 346
+.packtomark
+
+] readonly def
+
+% ---------------- Font loading ---------------- %
+
+% ------ Utilities ------ %
+
+/advance { % <n> advance -
+ f cff eq { /pos pos 3 -1 roll add store } { pop } ifelse
+} def
+/next { % - next <byte>
+ f read { 1 advance } if
+} def
+/nextstring { % <length> nextstring <string>
+ dup 0 eq {
+ pop ()
+ } {
+ string f exch readstring pop dup length advance
+ } ifelse
+} def
+/card8 % - card8 <card8>
+ /next load
+def
+/card16 { % - card16 <card16>
+ card8 8 bitshift card8 add
+} def
+/offset { % <offsize> offset <offset>
+ 0 exch { 8 bitshift next add } repeat
+} def
+/sid % - <sid> sid
+ /card16 load
+def
+/Index { % - Index <array>
+ mark card16 dup 0 ne {
+ 1 exch next dup offset pop exch {
+ dup offset dup 4 -1 roll sub 3 1 roll exch
+ } repeat pop
+ } if pop .packtomark
+ [ exch { nextstring } forall ] readonly
+} def
+/tokens { % - tokens <num1> ... <op#> (op# = 12 means EOF)
+ {
+ f read not { 12 exit } if
+ 1 advance
+ dup 12 eq { pop next 32 add exit } if
+ dup 28 lt { exit } if
+ dup 32 lt {
+ 28 sub {
+ { card16 32768 xor 32768 sub }
+ { 4 offset dup 16#7fffffff gt { -1 32 bitshift add } if }
+ { tokenreal }
+ { 31 exit }
+ } exch get exec
+ } {
+ dup 247 lt {
+ 139 sub
+ } {
+ 247 sub {
+ { next 108 add }
+ { next 364 add }
+ { next 620 add }
+ { next 876 add }
+ { next 108 add neg }
+ { next 364 add neg }
+ { next 620 add neg }
+ { next 876 add neg }
+ % 255 is deliberately omitted and will cause a rangecheck
+ } exch get exec
+ } ifelse
+ } ifelse
+ } loop
+} def
+/tokenbuf 100 string def
+/tokenput { % <index> <char> tokenput <index+1>
+ tokenbuf 2 index 3 -1 roll put 1 add
+} def
+/tokenrealarray [
+ (0123456789.E) { } forall
+ [(E) 0 get /tokenput cvx (-) 0 get] cvx
+ null % will give an error
+ (-) 0 get
+ { exit }
+] readonly def
+/tokenreal { % - tokenreal <float>
+ 0 {
+ next exch 1 index -4 bitshift tokenrealarray exch get exec tokenput
+ % We must leave the byte on the stack temporarily so that
+ % the exit will see a consistent stack state.
+ 1 index 15 and tokenrealarray exch get exec tokenput exch pop
+ } loop
+ tokenbuf 0 3 -1 roll getinterval cvr exch pop
+} def
+/Dict { % <opsdict> Dict -
+ /opdict exch store {
+ mark tokens opdict exch .knownget { exec } if cleartomark
+ } loop cleartomark
+} def
+/idstring { % <sid> idstring <string|name>
+ dup 391 lt { StandardStrings } { 391 sub strings } ifelse exch get
+} def
+/idname { % <sid> idname <name>
+ idstring dup type /nametype ne { cvn } if
+} def
+
+% ------ Top dictionary ------ %
+
+/offput { % <offset> <proc> offput -
+ currentdict exch aload length 1 add packedarray cvx
+ offsets 3 1 roll put
+} def
+/queueput { % <font> <proc> queueput -
+ 16#7fffffff offsets { pop .min } forall
+ pos sub nextstring
+ 3 1 roll aload length 2 add packedarray cvx
+ [ queued aload pop counttomark 2 add -1 roll ]
+ /queued exch store
+} def
+/xxput { % <value> <key> <dict> xxput -
+ 3 1 roll exch put
+} def
+/putfi { % <value> <key> putfi -
+ FontInfo xxput
+} def
+/xdef { % <value> <key> xdef -
+ exch def
+} def
+/topdictops mark
+ 12 { exit }
+ 0 { idstring /version putfi }
+ 1 { idstring /Notice putfi }
+ 32 { idstring /Copyright putfi }
+ 2 { idstring /FullName putfi }
+ 3 { idstring /FamilyName putfi }
+ 4 { idstring /Weight putfi }
+ 33 { 0 ne /isFixedPitch putfi }
+ 34 { /ItalicAngle putfi }
+ 35 { /UnderlinePosition putfi }
+ 36 { /UnderlineThickness putfi }
+ 37 { /PaintType xdef }
+ 38 { /CharstringType xdef }
+ 39 { counttomark array astore /FontMatrix xdef }
+ 13 { /UniqueID xdef }
+ 5 { counttomark array astore /FontBBox xdef }
+ 40 { /StrokeWidth xdef }
+ 14 { counttomark array astore /XUID xdef }
+ 15 {
+ dup StandardCharsets length lt {
+ StandardCharsets exch get /charset xdef
+ } {
+ { queuecharset } offput
+ } ifelse
+ }
+ 16 {
+ dup StandardEncodings length lt {
+ /Encoding xdef
+ } {
+ { queueEncoding } offput
+ } ifelse
+ }
+ 17 { { readCharStrings } offput }
+ 18 { exch /readPrivate cvx 2 packedarray offput }
+.dicttomark readonly def
+
+/readCharStrings { % <font> readCharStrings -
+ /CharStringArray Index put
+} def
+
+% ------ Charsets and encodings ------ %
+
+% Note: formats 1 and 2 can overflow the operand stack.
+% We'll fix this if it ever becomes necessary.
+/charsetformats [
+{ [ 0 CharStringArray length 1 sub { sid } repeat ]
+}
+{ [ 0 CharStringArray length 1 sub {
+ dup 0 eq { pop exit } if
+ sid card8 1 add 2 index .min { exch 1 sub 1 index 1 add } repeat pop
+ } loop ]
+}
+{ [ 0 CharStringArray length 1 sub {
+ dup 0 eq { pop exit } if
+ sid card16 1 add 2 index .min { exch 1 sub 1 index 1 add } repeat pop
+ } loop ]
+}
+] readonly def
+/queuecharset { % <font> queuecharset -
+ { readcharset } queueput
+} def
+/readcharset { % <data> <font> readcharset -
+ begin 0 () /SubFileDecode filter /f exch store
+ charsetformats next get exec /charset exch def end
+} def
+
+/encodingformats [
+{ 1 1 next { next exch Encoding 3 1 roll put } for
+}
+{ 1 next {
+ next next 1 add {
+ % Stack: gid code
+ Encoding 1 index 3 index put
+ exch 1 add exch 1 add
+ } repeat pop
+ } repeat pop
+}
+] readonly def
+/queueEncoding { % <font> queueEncoding -
+ { readEncoding } queueput
+} def
+/readEncoding { % <data> <font> readEncoding -
+ begin 0 () /SubFileDecode filter /f exch store
+ /Encoding [ 256 { /.notdef } repeat ] def
+ next encodingformats 1 index 127 and get exec
+ 128 ge {
+ % Read supplementary encodings.
+ next {
+ Encoding next sid idname put
+ } repeat
+ } if end
+} def
+
+% ------ Private dictionary ------ %
+
+/deltarray { % -mark- <num1> ... deltarray <num1'> ...
+ 0 counttomark 1 sub { counttomark -1 roll add dup } repeat pop
+ counttomark array astore
+} def
+
+/privatedictops mark
+ 12 { exit }
+ 6 { deltarray /BlueValues xdef }
+ 7 { deltarray /OtherBlues xdef }
+ 8 { deltarray /FamilyBlues xdef }
+ 9 { deltarray /FamilyOtherBlues xdef }
+ 41 { /BlueScale xdef }
+ 42 { /BlueShift xdef }
+ 43 { /BlueFuzz xdef }
+ 10 { 1 array astore /StdHW xdef }
+ 11 { 1 array astore /StdVW xdef }
+ 44 { deltarray /StemSnapH xdef }
+ 45 { deltarray /StemSnapV xdef }
+ 46 { 0 ne /ForceBold xdef }
+ 47 { /ForceBoldThreshold xdef }
+ 48 { /lenIV xdef }
+ 49 { /LanguageGroup xdef }
+ 50 { /ExpansionFactor xdef }
+ 51 { /initialRandomSeed xdef }
+ 19 { { readSubrs } offput }
+ 20 { /defaultWidthX xdef }
+ 21 { /nominalWidthX xdef }
+ % Multiple Master fonts only
+ 59 { /NDV xdef }
+ 60 { /CDV xdef }
+ 61 { /lenBuildCharArray xdef }
+.dicttomark readonly def
+
+/readPrivate { % <font> <size> readPrivate -
+ exch 1 index f exch () /SubFileDecode filter /f exch def
+ /Private get begin //privatedictops Dict end
+ /f cff def advance
+} def
+
+% ------ Main program ------ %
+
+% We need to pass the file as a parameter for the sake of the PDF
+% interpreter.
+/StartData { % <resname> <nbytes> StartData -
+ currentfile exch () /SubFileDecode filter ReadData
+} def
+/ReadData { % <resname> <file> ReadData -
+
+ % Initialize.
+
+ 30 dict begin
+ /cff exch def
+ /pos 0 def
+ /resname exch cvlit def
+
+ % Read the header.
+
+ /f cff def
+ /vmajor next def
+ /vminor next def
+ /hdrsize next def
+ /aoffsize next def
+
+ % Read the Indexes.
+
+ /names Index def
+ /topdicts Index def
+ /strings Index def
+ /gsubrs Index def
+
+ % Read the top Dicts.
+
+ /offsets 50 dict def
+ /queued [] def
+ /opdict null def % reserve a slot
+ /fonts [ topdicts {
+ 0 () /SubFileDecode filter /f exch def
+ 40 dict begin
+ % Preload defaults that differ from PostScript defaults.
+ /FontType 1 def
+ /CharstringType 2 def
+ /FontMatrix [0.001 0 0 0.001 0 0] def
+ /charset StandardCharsets 0 get def
+ /Encoding 0 def
+ /FontInfo 10 dict
+ dup /UnderlinePosition -100 put
+ dup /UnderlineThickness 50 put
+ def
+ /Private 20 dict
+ gsubrs length 0 ne { dup /GlobalSubrs gsubrs put } if
+ def
+ //topdictops Dict
+ currentdict end
+ } forall ] def
+
+ % Read other tables with queued offsets.
+
+ { /f cff def
+ offsets pos 2 copy .knownget not { pop pop exit } if
+ 3 1 roll undef exec
+ } loop
+ offsets length 0 ne {
+ (Error: missing tables at ) print [ offsets { pop } forall ] ==
+ (Current position is ) print pos ==
+ flush stop
+ } if
+
+ % Process out-of-order tables.
+
+ queued { exec } forall
+
+ % Update Encoding and CharStrings.
+
+ fonts {
+ begin
+ % Construct the real Encoding.
+ % The value of Encoding is either a number, for predefined
+ % encodings, or an array of mixed GIDs and names.
+ /Encoding mark Encoding dup type /integertype eq {
+ StandardEncodings exch get { idname } forall
+ } {
+ {
+ dup type /integertype eq { charset exch get idname } if
+ } forall
+ } ifelse .packtomark def
+ % Construct the CharStrings.
+ /CharStrings charset length dict def
+ 0 1 charset length 1 sub {
+ dup CharStringArray exch get
+ exch charset exch get idstring
+ CharStrings xxput
+ } for
+ % Remove unwanted entries.
+ currentdict /charset undef
+ currentdict /CharSetArray undef
+ end
+ } forall
+
+ % Wrap up.
+
+ resname mark 0 1 fonts length 1 sub {
+ dup names exch get exch fonts exch get
+ dup /FontName 3 index put
+ 1 index exch definefont
+ } for .dicttomark
+ end % temporary dict
+ end % FontSetInit ProcSet
+ /FontSet defineresource pop
+
+} bind def
+
+% ---------------- Resource category definition ---------------- %
+
+currentdict end readonly
+
+languagelevel exch 2 .setlanguagelevel
+
+/FontSet /Generic /Category findresource dup length dict .copydict
+/Category defineresource pop
+
+/FontSetInit exch /ProcSet defineresource pop
+
+.setlanguagelevel
diff --git a/gs/lib/gs_cidfn.ps b/gs/lib/gs_cidfn.ps
new file mode 100644
index 000000000..557065b7c
--- /dev/null
+++ b/gs/lib/gs_cidfn.ps
@@ -0,0 +1,428 @@
+% Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% ProcSet for implementing CIDFont and CIDMap resources.
+% When this is run, systemdict is still writable.
+
+% ---------------- Defining CIDFont resources ---------------- %
+
+% Define a CIDFont resource. This is the defineresource implementation for
+% the CIDFont resource category.
+
+/.definecidfont [
+
+% CIDFontType 0
+{ dup /FontMatrix known not
+ { dup /FontMatrix [0.001 0 0 0.001 0 0] put
+ dup /FDArray get
+ { /FontMatrix get [1000 0 0 1000 0 0] 1 index concatmatrix pop }
+ forall
+ }
+ if
+ dup /FDArray get mark exch
+ { % Add pro forma entries
+ dup /FontType 1 put
+ dup /CharStrings 10 dict put
+ dup /Encoding [] put
+ % Create a dummy Subrs array now.
+ dup /Private get dup /SubrCount .knownget
+ { array 1 index /Subrs 3 -1 roll put }
+ if pop
+ dup /FontName .knownget not { () } if exch .buildfont1 exch pop
+ }
+ forall ] 1 index /FDepVector 3 -1 roll put
+ 1 index exch .buildfont9 exch pop
+} bind
+
+% CIDFontType 1
+{ 1 index exch .buildfont10 exch pop
+} bind
+
+% CIDFontType 2
+{ 1 index exch .buildfont11 exch pop
+} bind
+
+] def
+
+% ---------------- Reading CIDFontType 0 files ---------------- %
+
+30 dict begin
+
+% We add the following entries to the CIDFont dictionary, in addition to
+% the ones documented by Adobe:
+% ReadString - procedure for reading a string from the binary data
+% SubrCache - dictionary for caching Subr arrays
+% For CIDFonts where we read the data from disk incrementally:
+% DataOffset - starting position of data in file
+% (if data are in hex) OffsetMap - map from logical data positions to
+% physical positions in file
+
+/StartData % <(Binary)|(Hex)> <datalength> StartData -
+ % (currentdict is CID font dict)
+{ % If we're loading a resource file, we can just save a
+ % pointer to the binary data and load it incrementally.
+ % Check for this by opening the resource file,
+ % positioning it to currentfile's position plus the
+ % data length, and checking for %%EndData.
+ mark
+ { currentfile fileposition
+ CIDFontName 100 string ResourceFileName (r) file
+ mark
+ { % Stack: (Binary)|(Hex) length -mark- pos resfile
+ % -mark-
+ 5 index (Hex) eq
+ { 1 index 3 index setfileposition
+ 1 index 5 index .skiphex
+ %**************** SKIP > AND WHITESPACE SOMEHOW
+ }
+ { 1 index 3 index 6 index add setfileposition
+ }
+ ifelse
+ 1 index 9 string readstring pop (%%EndData) ne { stop } if
+ }
+ .internalstopped { cleartomark closefile stop } if
+ pop % pop the mark
+ }
+ .internalstopped
+ { % File is not positionable, load the data now.
+ cleartomark exch (Hex) eq
+ { { currentfile exch readhexstring pop } }
+ { { currentfile exch readstring pop } }
+ ifelse /ReadString exch def
+ dup 65535 le
+ { string ReadString
+ }
+ { mark exch
+ { dup 0 eq { pop exit } if
+ dup 65535 min dup string ReadString
+ 3 1 roll sub
+ }
+ loop ]
+ }
+ ifelse
+ /GlyphData exch def
+ /.vmreadstring cvx
+ }
+ { % File is positionable, just save a pointer.
+ % Stack: (Binary)|(Hex) length -mark- pos file
+ 4 1 roll
+ /DataOffset exch def
+ pop /GlyphData exch def
+ exch (Hex) eq
+ { % Hex data, build the offset map.
+ .buildoffsetmap
+ /.hexreadstring
+ }
+ { % Binary data, just skip over it.
+ currentfile DataOffset GlyphData add setfileposition
+ /.binaryreadstring
+ }
+ ifelse cvx
+ 2 packedarray cvx
+ }
+ ifelse /ReadString exch def
+ /SubrCache 10 dict def
+ CIDFontName currentdict /CIDFont defineresource pop
+ end % CID font dict
+ end % resource category dict
+} bind def
+
+% Skip a given distance in an ASCIIHex encoded file. We use this at
+% rendering time as well.
+/.skiphex % <file> <count> .skiphex -
+{ exch /ASCIIHexDecode filter dup 3 -1 roll () /SubFileDecode filter
+ dup flushfile closefile closefile
+} bind def
+
+% Build the map from logical offsets to physical offsets in ASCIIHex
+% encoded data.
+/.buildoffsetmap
+{ /OffsetMap GlyphData 256 idiv 8000 min array def
+ 2 dict begin
+ /block GlyphData OffsetMap length idiv def
+ 0 1 OffsetMap length 1 sub
+ { OffsetMap exch currentfile fileposition put
+ currentfile block .skiphex
+ }
+ for
+ GlyphData block mod dup 0 eq
+ { pop }
+ { currentfile exch .skiphex }
+ ifelse
+ end % scratch dict
+} bind def
+
+currentdict end
+
+% ---------------- Rendering ---------------- %
+
+% ------ Generic ------ %
+
+% Read a string at a given offset in a "file" (binary file, ASCII hex file,
+% or GlyphData in RAM).
+/.binaryreadstring % <pos> <string> <file> .binaryreadstring <string>
+ { dup 4 -1 roll DataOffset add setfileposition exch readstring pop
+ } bind def
+/.hexreadstring % <pos> <string> <file> .hexreadstring <string>
+{ % Use the OffsetMap to get to the block of hex data,
+ % then skip to the correct position by reading.
+ GlyphData OffsetMap length idiv
+ % Stack: pos string file blocklen
+ 3 index 1 index idiv OffsetMap exch get
+ 2 index exch setfileposition
+ % Skip the next (pos % blocklen) hex bytes.
+ 4 -1 roll exch mod 1 index exch .skiphex
+ % Stack: string file
+ exch readhexstring pop
+} bind def
+/.vmreadstring % <pos> <string> .vmreadstring <vmstring>
+{ GlyphData .stringsreadstring
+} bind def
+/.stringsreadstring % <pos> <string> <strings> .stringsreadstring
+ % <vmstring>
+{ dup type /stringtype eq
+ { 3 1 roll length getinterval
+ }
+ { { % Stack: pos string glyphdata
+ dup 0 get length dup 4 index gt { exit } if
+ 4 -1 roll exch sub 3 1 roll
+ dup length 1 sub 1 exch getinterval
+ }
+ loop
+ % Stack: pos string glyphdata glyphdata[0]length
+ % We know no request can span more than 2 strings.
+ 3 index 3 index length add 1 index le
+ { % Request fits in a single string: just return a substring.
+ pop 0 get 3 1 roll length getinterval
+ }
+ { % Request spans 2 strings. Copy the first part.
+ 1 index 0 get 4 index 3 -1 roll 1 index sub getinterval
+ 2 index copy
+ % Copy the second part.
+ % Stack: pos str glyphdata str1
+ length exch 1 get 0 3 index length
+ 3 index sub getinterval 2 index 3 1 roll putinterval
+ exch pop
+ }
+ ifelse
+ }
+ ifelse
+} bind def
+
+% Interpret a byte string as a (big-endian) integer.
+/.cvbsi % <bytes> .cvbsi <int>
+{ 0 exch { exch 8 bitshift add } forall
+} bind def
+
+% Read an integer from binary data.
+/.readint % <pos> <nbytes> .readint <int>
+{ string ReadString .cvbsi
+} bind def
+
+% Read the glyph data for a given CID.
+% The CIDFont is currentdict.
+/.readglyphdata % <cid> .readglyphdata <subfont> <string|null>
+{ currentdict /GlyphDirectory .knownget
+ { dup type /arraytype eq
+ { 1 index exch get }
+ { 1 index exch .knownget not { null } if }
+ ifelse
+ dup null eq
+ { FDepVector 0 get exch }
+ { FDBytes 0 eq
+ { FDepVector 0 get exch }
+ { % Note: FDBytes > 1 is not supported.
+ dup 0 get FDepVector exch get
+ exch dup length 1 sub 1 exch getinterval
+ }
+ ifelse
+ }
+ ifelse
+ }
+ { FDBytes GDBytes add mul CIDMapOffset add
+ dup FDBytes .readint exch
+ FDBytes add dup GDBytes .readint
+ exch GDBytes add FDBytes add GDBytes .readint
+ % Stack: fd pos nextpos
+ 1 index sub dup 0 eq
+ { pop pop pop FDepVector 0 get null }
+ { string ReadString exch FDepVector exch get exch }
+ ifelse
+ }
+ ifelse
+} bind def
+
+% ------ CIDFontType 0 ------ %
+
+% Read some Subrs for the current Type 1 subfont.
+% The subfont's Private dict is currentdict; the CIDFont itself is the
+% next dictionary on the stack.
+/.readsubrs % <Subrs> <start> .readsubrs <Subrs>
+{ 1 SubrCount 1 sub
+ { dup SDBytes mul SubrMapOffset add
+ dup SDBytes .readint exch SDBytes add SDBytes .readint
+ 1 index sub string ReadString 2 index 3 1 roll put
+ }
+ for
+} bind def
+
+% Ensure that all the Subrs for the current Type 1 subfont are loaded.
+% The subfont's Private dict is currentdict; the CIDFont itself is the
+% next dictionary on the stack.
+/.loadsubrs
+{ currentdict /SubrMapOffset .knownget
+ { Subrs 0 get null ne
+ { pop % We've already loaded the Subrs.
+ }
+ { SubrCache 1 index .knownget
+ { % We've already loaded some Subrs at this offset.
+ % Make sure we've got as many as we need.
+ dup length SubrCount lt
+ { % We need to load more.
+ SubrCount array exch 1 index copy length .readsubrs
+ SubrCache 3 -1 roll 2 index put
+ }
+ if
+ }
+ { % We haven't loaded any Subrs at this offset yet.
+ SubrCount array 0 .readsubrs
+ SubrCache 3 -1 roll 2 index put
+ }
+ ifelse
+ Subrs copy pop
+ }
+ ifelse
+ }
+ if
+} bind def
+
+% BuildGlyph procedure for CIDFontType 0.
+% ****** WHY NOT USE .type1execchar FOR THIS? ******
+% The name %Type9BuildGlyph is known to the interpreter.
+/.cid0buildstring 10 string def
+(%Type9BuildGlyph) cvn % <cidfont> <cid> %Type9BuildGlyph -
+{ .currentglobal 3 1 roll 1 index gcheck .setglobal
+ 1 index begin
+ dup .readglyphdata dup null eq
+ { %**** HANDLE NOTDEF ****
+ }
+ if
+ % Stack: cidfont cid subfont charstring
+dup null eq { pop pop pop pop } { %**** WRONG ****
+ 4 -1 roll pop
+ exch dup /Private get begin .loadsubrs end
+ 3 -1 roll //.cid0buildstring cvs cvn 3 1 roll
+ dup /CharStrings get 3 index 4 -1 roll put
+ setfont
+ 1000 0 setcharwidth %**** WRONG ****
+ 0 0 moveto glyphshow
+} ifelse %**** WRONG ****
+ end
+ .setglobal
+} bind def
+
+% ------ CIDFontType 2 ------ %
+
+% BuildGlyph procedure for CIDFontType 2.
+% ****** ADD THE OUTLINE STRING AS AN ARGUMENT TO .type42execchar. ******
+% The name %Type11BuildGlyph is known to the interpreter.
+(%Type11BuildGlyph) cvn % <cidfont> <cid> %Type11BuildGlyph -
+{ .currentglobal 3 1 roll 1 index gcheck .setglobal
+ 1 index begin
+ dup GDBytes mul GDBytes string CIDMap .stringsreadstring .cvbsi
+ % Stack: cidfont cid glyphindex
+%**************** GlyphDirectory is not supported yet.
+(
+ currentdict /GlyphDirectory .knownget
+) pop false
+ { dup type /arraytype eq
+ { 1 index exch get }
+ { 1 index exch .knownget not { null } if }
+ ifelse
+ dup null eq
+ { %**** HANDLE NOTDEF
+ }
+ if
+ 1 index exch .type42execchar
+ }
+ { 1 index exch .type42execchar
+ }
+ ifelse
+ end
+ .setglobal
+} bind def
+
+% ---------------- Define resources ---------------- %
+
+languagelevel exch 2 .setlanguagelevel
+
+% Define the CIDInit ProcSet resource.
+% The ProcSet dictionary is still on the stack.
+
+/CMap /Generic /Category findresource dup length dict .copydict
+/Category defineresource pop
+ % We might have loaded CMap support already.
+/CIDInit /ProcSet 2 copy resourcestatus {
+ pop pop findresource dup length 4 index length add dict .copydict
+ 4 -1 roll exch .copydict
+} {
+ 3 -1 roll
+} ifelse exch defineresource pop
+
+% Define the CIDFont resource category.
+
+/CIDFont /Generic /Category findresource dup length dict .copydict
+dup /InstanceType /dicttype put
+dup /DefineResource {
+ dup /CIDFontType get dup 9 add /FontType exch 3 index 3 1 roll put
+ //.definecidfont exch get exec
+ /Generic /Category findresource /DefineResource get exec
+} put
+/Category defineresource pop
+
+currentdict /.definecidfont undef
+
+% Add the new FontType resources.
+
+9 1 11 { dup /FontType defineresource pop } for
+
+% Add the new FMapType resource.
+
+9 dup /FMapType defineresource pop
+
+% Define the CIDMap resource category.
+% These aren't documented, but it's clear what they are for:
+% to give names to CIDMaps for CIDFontType 2 fonts.
+
+/CIDMap /Generic /Category findresource dup length dict .copydict
+dup /.CheckResource {
+ % Allow either a string or an array of strings.
+ dup type dup /stringtype eq
+ { pop true
+ }
+ { dup /arraytype eq exch /packedarraytype eq or
+ { true exch { type /stringtype ne { pop false exit } if } forall
+ }
+ { false
+ }
+ ifelse
+ }
+ ifelse
+} bind put
+/Category defineresource pop
+
+.setlanguagelevel
diff --git a/gs/lib/gs_cmap.ps b/gs/lib/gs_cmap.ps
new file mode 100644
index 000000000..7905d3639
--- /dev/null
+++ b/gs/lib/gs_cmap.ps
@@ -0,0 +1,242 @@
+% Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% ProcSet for implementing CMap resources.
+% When this is run, systemdict is still writable.
+
+% NOTE: Rearranged fonts are not implemented yet.
+
+% ---------------- Public operators ---------------- %
+
+% composefont doesn't appear in CMap files -- it's documented in
+% the "PostScript Language Reference Manual Supplement".
+/composefont % <name> <cmap|cmapname> <fonts> composefont <font>
+ { 10 dict begin
+ 1 index dup type /dicttype ne { /CMap findresource } if
+ /CMap exch def
+ /Encoding [ 0 1 4 index length 1 sub { } for ] def
+ /FDepVector 1 index def
+ /FMapType 9 def
+ /FontMatrix matrix def
+ /FontName 3 index def
+ /CMap load /WMode .knownget { /WMode exch def } if
+ /FontType 0 def
+ pop pop currentdict end /Font defineresource
+ } bind odef
+
+% ---------------- CMap operators ---------------- %
+
+30 dict begin
+
+% Our internal .CodeMaps structure is an array of two arrays: array 0
+% is the map for defined characters, array 1 is the map for notdefs.
+% Both are multi-level arrays indexed by the successive bytes of the
+% character code. Each value is either a sub-array, null, a character name,
+% a CID (an integer), or a character code (expressed as a byte string).
+% All of the arrays are read-only after they have been built.
+%
+% Note that the code in zfcmap.c that constructs the C structures from
+% the PostScript structures has intimate knowledge of the above format.
+
+/.getmap { .CodeMaps exch get } bind def
+/.putmap { .CodeMaps exch 3 -1 roll put } bind def
+
+% ------ Font-level operators ------ %
+
+/begincmap % - begincmap -
+ { /.CodeMaps [256 array 256 array] def
+ } bind def
+/endcmap % - endcmap -
+ { /.CodeMaps .CodeMaps .endmap def
+ /CodeMap null def % for .buildcmap
+ currentdict end .buildcmap begin
+ } bind def
+
+/begincodespacerange % <count> begincodespacerange -
+ { pop mark
+ } bind def
+/endcodespacerange % <code_lo> <code_hi> ... endcodespacerange -
+ { counttomark 2 idiv
+ { .CodeMaps { 3 copy .addcodespacerange pop } forall pop pop
+ } repeat pop
+ } bind def
+
+/.addcodespacerange % <code_lo> <code_hi> <map> .addcodespacerange -
+ { 2 index length 1 eq
+ { 2 { 3 -1 roll 0 get } repeat 1 exch
+ { 2 copy 0 put pop } for pop
+ }
+ { 2 index 0 get 1 3 index 0 get
+ 6 -2 roll
+ 2 { 1 1 index length 1 sub getinterval 6 1 roll } repeat
+ % Stack: lo hi map lo0 1 hi0
+ { 2 copy get null eq { 2 copy 256 array put } if
+ 4 copy get .addcodespacerange pop
+ }
+ for pop pop pop
+ }
+ ifelse
+ } bind def
+/.endmap % <map> .endmap <map>
+ { dup type /arraytype eq { dup { .endmap exch } forall astore readonly } if
+ } bind def
+
+/usecmap % <CMap_name> usecmap -
+ { /CMap findresource
+ dup length dict .copydict
+ currentdict end exch .copydict begin
+ } bind def
+
+% ------ Rearranged font operators ------ %
+
+/beginrearrangedfont % <font_name> <font*> beginrearrangedfont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+/endrearrangedfont % - endrearrangedfont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+/usefont % <fontID> usefont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+/beginusematrix % <fontID> beginusematrix -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+/endusematrix % <matrix> endusematrix -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+% ------ Character name/code selector operators ------ %
+
+/beginbfchar % <count> beginbfchar -
+ { pop mark
+ } bind def
+/endbfchar % <code> <to_code|charname> ... endbfchar
+ { 0 .getmap .endmapchar 0 .putmap
+ } bind def
+
+/beginbfrange % <count> beginbfrange -
+ { pop mark
+ } bind def
+/endbfrange % <code_lo> <code_hi> <to_code|(charname*)> ...
+ % endbfrange -
+ { 0 .getmap counttomark 3 idiv { .addbfrange } repeat 0 .putmap pop
+ } bind def
+
+/.addbfrange % <code_lo> <code_hi> <to_code|(charname*)> <map>
+ % .addbfrange <map>
+ { 1 index type /stringtype eq
+ { { dup length string copy dup dup length 1 sub 2 copy get 1 add put }
+ exch .addmaprange
+ }
+ { 2 dict begin exch /codes 1 index def 0 get exch
+ { codes dup length 1 sub 1 exch getinterval /codes 1 index def
+ dup length 0 gt { 0 get } if
+ }
+ exch .addmaprange end
+ }
+ ifelse exch pop
+ } bind def
+
+% ------ CID selector operators ------ %
+
+/begincidchar % <count> begincidchar -
+ { pop mark
+ } bind def
+/endcidchar % <code> <cid> ... endcidchar -
+ { 0 .getmap .endmapchar 0 .putmap
+ } bind def
+
+/begincidrange % <count> begincidrange -
+ { pop mark
+ } bind def
+/endcidrange % <code_lo> <code_hi> <cid_base> ... endcidrange -
+ { 0 .getmap counttomark 3 idiv { { 1 add } exch .addmaprange exch pop } repeat
+ 0 .putmap pop
+ } bind def
+
+/.endmapchar % -mark- <code> <value> ... <map> .endmapchar -
+ { counttomark 2 idiv
+ { 2 index 3 1 roll { } exch .addmaprange exch pop
+ } repeat exch pop
+ } bind def
+
+/.addmaprange % <code_lo> <code_hi> <value_base> <next_proc> <map>
+ % .addcidrange <value_next> <map>
+ { % We may be updating a (partly) read-only map from another CMap.
+ % If so, implement copy-on-write.
+ dup wcheck not { dup length array copy } if
+ 4 index length 1 eq
+ { 2 { 5 -1 roll 0 get } repeat 1 exch
+ { % Stack: value proc map code
+ 2 copy 5 index put pop
+ 3 -1 roll 2 index exec 3 1 roll
+ } for
+ }
+ { 4 index 0 get 1 5 index 0 get
+ 8 -2 roll
+ 2 { 1 1 index length 1 sub getinterval 8 1 roll } repeat
+ % Stack: lo hi next proc map lo0 1 hi0
+ { 6 copy get .addmaprange
+ % Stack: lo hi oldnext proc map i next submap
+ exch 6 1 roll 5 -1 roll pop
+ % Stack: lo hi next proc map i submap
+ 3 copy put pop pop
+ }
+ for 5 -2 roll pop pop
+ }
+ ifelse exch pop
+ } bind def
+
+% ------ notdef operators ------ %
+
+/beginnotdefchar % <count> beginnotdefchar -
+ { pop mark
+ } bind def
+/endnotdefchar % <code> <cid> ... endnotdefchar -
+ { counttomark 2 idiv { 1 index exch .addnotdefrange } repeat pop
+ } bind def
+
+/beginnotdefrange % <count> beginnotdefrange -
+ { pop mark
+ } bind def
+/endnotdefrange % <code_lo> <code_hi> <cid> ... endnotdefrange -
+ { counttomark 3 idiv { .addnotdefrange } repeat pop
+ } bind def
+
+/.addnotdefrange % <code_lo> <code_hi> <cid_base> .addnotdefrange -
+ { { } 1 .getmap .addmaprange 1 .putmap pop
+ } bind def
+
+% ---------------- Resource category definition ---------------- %
+
+currentdict end
+
+languagelevel exch 2 .setlanguagelevel
+
+/CMap /Generic /Category findresource dup length dict .copydict
+/Category defineresource pop
+ % We might have loaded CID font support already.
+/CIDInit /ProcSet 2 copy { findresource } .internalstopped
+ % An interior `stopped' might have reset VM allocation to local.
+true .setglobal
+ { pop pop 3 -1 roll }
+ { dup length 4 index length add dict .copydict 4 -1 roll exch .copydict }
+ifelse exch defineresource pop
+
+.setlanguagelevel
diff --git a/gs/lib/gs_cmdl.ps b/gs/lib/gs_cmdl.ps
new file mode 100644
index 000000000..a245ebbdb
--- /dev/null
+++ b/gs/lib/gs_cmdl.ps
@@ -0,0 +1,181 @@
+% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Parse and execute the command line.
+% C code handles the following switches: -h/-? -I -M -v
+
+/cmddict 50 dict def
+cmddict begin
+
+% ---------------- Utility procedures ---------------- %
+
+% Get the next argument from the parsed argument list.
+/nextarg % - nextarg <arg> true
+ % - nextarg false
+ { argv length 0 eq
+ { false }
+ { argv dup 0 get exch dup length 1 sub 1 exch getinterval /argv exch def }
+ ifelse
+ } bind def
+
+% Run a file, under job control if implemented.
+/runjob % <file> runjob -
+ { end % cmddict
+ /startjob where { pop false () startjob pop }
+ run
+ //cmddict begin
+ } bind def
+/runfilejob % <filename> runfilejob -
+ { findlibfile { exch pop } { (r) file } runjob
+ } bind def
+
+% Expand arguments. Free variables: expand@.
+/expandarg % <string> expandarg <args...>
+ { dup () eq
+ { pop
+ }
+ { dup dup (--) eq exch (-+) eq or
+ { pop /expand@ false def
+ }
+ { expand@ { (@) anchorsearch } { false } ifelse
+ { pop findlibfile
+ { exch pop }
+ { (r) file } % let the error happen
+ expandargfile
+ }
+ if
+ }
+ ifelse
+ }
+ } bind def
+/expandargfile % <file> expandargfile <args...>
+ { [ exch cvlit
+ { token not { exit } if
+ dup type /stringtype ne { =string cvs dup length string copy } if
+ expandarg
+ }
+ /exec cvx
+ ] cvx loop
+ } bind def
+
+% ---------------- Recognized switches ---------------- %
+
+% Switches with arguments are defined as <x>;
+% switches without arguments are defined as -<x>.
+
+% Switches without arguments
+/--
+ { nextarg not
+ { (-- and -+ require a file name.\n) print flush }
+ { //systemdict /ARGUMENTS argv put /argv [] def runjob }
+ ifelse
+ } bind def
+/-+ /-- load def
+/-@ /-- load def
+/-A { (@) Z } bind def
+/-c
+ { { argv length 0 eq { exit } if
+ argv 0 get (-) anchorsearch { pop pop exit } if
+ pop nextarg token
+ { exch pop % Probably should check for empty.
+ end exec //cmddict begin
+ }
+ if
+ }
+ loop
+ } bind def
+/-e { (#) Z } bind def
+/-E /-e load def
+/-f { } def
+/-q { //systemdict /QUIET true put } bind def
+
+% Switches with arguments
+/d
+ { (=) search not { (#) search not { () exch dup } if } if
+ exch pop cvn dup where
+ { pop (Redefining ) print print ( is not allowed.\n) print flush pop }
+ { exch token
+ { exch pop } % Probably should check for empty.
+ { true }
+ ifelse
+ //systemdict 3 1 roll put
+ }
+ ifelse
+ } bind def
+/D /d load def
+/f { dup length 0 ne { runfilejob } if } bind def
+/g
+ { (x) search { cvi pop exch cvi } { cvi dup } ifelse
+ //systemdict begin /DEVICEHEIGHT exch def /DEVICEWIDTH exch def end
+ } bind def
+/r
+ { (x) search { cvr pop exch cvr } { cvr dup } ifelse
+ //systemdict begin /DEVICEYRESOLUTION exch def /DEVICEXRESOLUTION exch def end
+ } bind def
+/s
+ { (=) search not { (#) search not { () exch dup } if } if
+ exch pop cvn dup where { pop dup load } { () } ifelse
+ type /stringtype ne
+ { (Redefining ) print print ( is not allowed.\n) print flush pop }
+ { exch //systemdict 3 1 roll put }
+ ifelse
+ } bind def
+/S /s load def
+/Z { true .setdebug } bind def
+
+% ---------------- Main program ---------------- %
+
+% We process the command line in two passes. In the first pass,
+% we read and expand any @-files as necessary. The second pass
+% does the real work.
+
+/cmdstart
+ { //cmddict begin
+ /expand@ true def
+ [
+ % Process the GS_OPTIONS environment variable.
+ (GS_OPTIONS) getenv { 0 () /SubFileDecode filter expandargfile } if
+ % Process the actual command line.
+ .getargv { expandarg } forall
+ ] readonly /argv exch def
+ % Now interpret the commands.
+ { nextarg not { exit } if
+ dup 0 get (-) 0 get eq
+ { dup length 1 eq
+ { pop (%stdin) (r) file runjob
+ }
+ { dup length 2 gt
+ { dup dup length 2 sub 2 exch getinterval exch 1 1 getinterval }
+ if currentdict .knownget
+ { exec
+ }
+ { (Ignoring unknown switch ) print
+ dup length 1 eq { (-) print print } if print
+ (\n) print flush
+ }
+ ifelse
+ }
+ ifelse
+ }
+ { runfilejob
+ }
+ ifelse
+ }
+ loop end
+ } bind def
+
+end % cmddict
diff --git a/gs/lib/gs_dbt_e.ps b/gs/lib/gs_dbt_e.ps
new file mode 100644
index 000000000..53698ec47
--- /dev/null
+++ b/gs/lib/gs_dbt_e.ps
@@ -0,0 +1,60 @@
+% Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the Dingbats encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/DingbatsEncoding
+% \000
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \040
+ /space /a1 /a2 /a202 /a3 /a4 /a5 /a119
+ /a118 /a117 /a11 /a12 /a13 /a14 /a15 /a16
+ /a105 /a17 /a18 /a19 /a20 /a21 /a22 /a23
+ /a24 /a25 /a26 /a27 /a28 /a6 /a7 /a8
+% \100
+ /a9 /a10 /a29 /a30 /a31 /a32 /a33 /a34
+ /a35 /a36 /a37 /a38 /a39 /a40 /a41 /a42
+ /a43 /a44 /a45 /a46 /a47 /a48 /a49 /a50
+ /a51 /a52 /a53 /a54 /a55 /a56 /a57 /a58
+% \140
+ /a59 /a60 /a61 /a62 /a63 /a64 /a65 /a66
+ /a67 /a68 /a69 /a70 /a71 /a72 /a73 /a74
+ /a203 /a75 /a204 /a76 /a77 /a78 /a79 /a81
+ /a82 /a83 /a84 /a97 /a98 /a99 /a100 /.notdef
+% \200
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \240
+ /.notdef /a101 /a102 /a103 /a104 /a106 /a107 /a108
+ /a112 /a111 /a110 /a109 /a120 /a121 /a122 /a123
+ /a124 /a125 /a126 /a127 /a128 /a129 /a130 /a131
+ /a132 /a133 /a134 /a135 /a136 /a137 /a138 /a139
+% \300
+ /a140 /a141 /a142 /a143 /a144 /a145 /a146 /a147
+ /a148 /a149 /a150 /a151 /a152 /a153 /a154 /a155
+ /a156 /a157 /a158 /a159 /a160 /a161 /a163 /a164
+ /a196 /a165 /a192 /a166 /a167 /a168 /a169 /a170
+% \340
+ /a171 /a172 /a173 /a162 /a174 /a175 /a176 /a177
+ /a178 /a179 /a193 /a180 /a199 /a181 /a200 /a182
+ /.notdef /a201 /a183 /a184 /a197 /a185 /a194 /a198
+ /a186 /a195 /a187 /a188 /a189 /a190 /a191 /.notdef
+256 packedarray .defineencoding
+3 DingbatsEncoding .registerencoding
+exec
diff --git a/gs/lib/gs_diskf.ps b/gs/lib/gs_diskf.ps
new file mode 100644
index 000000000..3a9e65100
--- /dev/null
+++ b/gs/lib/gs_diskf.ps
@@ -0,0 +1,225 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Support for converting Type 1 fonts without eexec encryption to
+% Type 4 fonts that load individual character outlines on demand.
+
+% If DISKFONTS is true, we load individual CharStrings as they are needed.
+% (This is intended primarily for machines with very small memories.)
+% Initially, the character definition is the file position of the definition;
+% this gets replaced with the actual CharString.
+% Note that if we are loading characters lazily, CharStrings is writable.
+
+% _Cstring must be long enough to hold the longest CharString for
+% a character defined using seac. This is lenIV + 4 * 5 (for the operands
+% of sbw, assuming div is not used) + 2 (for sbw) + 3 * 5 (for the operands
+% of seac other than the character codes) + 2 * 2 (for the character codes)
+% + 2 (for seac), i.e., lenIV + 43.
+
+/_Cstring 60 string def
+
+% When we initially load the font, we call
+% <index|charname> <length> <readproc> cskip_C
+% to skip over each character definition and return the file position instead.
+% This substitutes for the procedure
+% <index|charname> <length> string currentfile exch read[hex]string pop
+% [encrypt]
+% What we actually store in the CharString is fileposition * 1000 + length,
+% negated if the string is stored in binary form.
+
+/cskip_C
+ { exch dup 1000 ge 3 index type /nametype ne or
+ { % This is a Subrs string, or the string is so long we can't represent
+ % its length. Load it now.
+ exch exec
+ }
+ { % Record the position and length, and skip the string.
+ dup currentfile fileposition 1000 mul add
+ 2 index 3 get /readstring cvx eq { neg } if
+ 3 1 roll
+ dup _Cstring length idiv
+ { currentfile _Cstring 3 index 3 get exec pop pop
+ } repeat
+ _Cstring length mod _Cstring exch 0 exch getinterval
+ currentfile exch 3 -1 roll 3 get exec pop pop
+ }
+ ifelse
+ } bind def
+
+% Load a CharString from the file. The font is the top entry
+% on the dictionary stack.
+/load_C % <charname> <fileposandlength> load_C -
+ { dup abs 1000 idiv FontFile exch setfileposition
+ CharStrings 3 1 roll
+ .currentglobal CharStrings .gcheck .setglobal exch
+ dup 0 lt
+ { neg 1000 mod string FontFile exch readstring }
+ { 1000 mod string FontFile exch readhexstring }
+ ifelse pop
+ exch .setglobal
+% If the CharStrings aren't encrypted on the file, encrypt now.
+ Private /-| get 0 get
+ dup type /nametype ne
+ { dup length 5 sub 5 exch getinterval exec }
+ { pop }
+ ifelse dup 4 1 roll put
+% If the character is defined with seac, load its components now.
+ mark exch seac_C
+ counttomark
+ { StandardEncoding exch get dup CharStrings exch get
+ dup type /integertype eq { load_C } { pop pop } ifelse
+ } repeat
+ pop % the mark
+ } bind def
+
+/seac_C % <charstring> seac_C <achar> <bchar> ..or nothing..
+ { dup length _Cstring length le
+ { 4330 exch _Cstring .type1decrypt exch pop
+ dup dup length 2 sub 2 getinterval <0c06> eq % seac
+ { dup length
+ Private /lenIV known { Private /lenIV get } { 4 } ifelse
+ exch 1 index sub getinterval
+% Parse the string just enough to extract the seac information.
+% We assume that the only possible operators are hsbw, sbw, and seac,
+% and that there are no 5-byte numbers.
+ mark 0 3 -1 roll
+ { exch
+ { { dup 32 lt
+ { pop 0 }
+ { dup 247 lt
+ { 139 sub 0 }
+ { dup 251 lt
+ { 247 sub 256 mul 108 add 1 1 }
+ { 251 sub -256 mul -108 add -1 1 }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+ } % 0
+ { mul add 0 } % 1
+ }
+ exch get exec
+ }
+ forall pop
+ counttomark 1 add 2 roll cleartomark % pop all but achar bchar
+ }
+ { pop % not seac
+ }
+ ifelse
+ }
+ { pop % punt
+ }
+ ifelse
+ } bind def
+
+% Define replacement procedures for loading fonts.
+% If DISKFONTS is true and the body of the font is not encrypted with eexec:
+% - Prevent the CharStrings from being made read-only.
+% - Substitute a different CharString-reading procedure.
+% (eexec disables this because the implicit 'systemdict begin' hides
+% the redefinitions that make the scheme work.)
+% We assume that:
+% - The magic procedures (-|, -!, |-, and |) are defined with
+% executeonly or readonly;
+% - The contents of the reading procedures are as defined in bdftops.ps;
+% - The font includes the code
+% <font> /CharStrings <CharStrings> readonly put
+/.loadfontdict 6 dict def mark
+ /begin % push this dict after systemdict
+ { dup begin
+ //systemdict eq { //.loadfontdict begin } if
+ } bind
+ /end % match begin
+ { currentdict end
+ //.loadfontdict eq currentdict //systemdict eq and { end } if
+ } bind
+ /dict % leave room for FontFile, BuildChar, BuildGlyph
+ { 3 add dict
+ } bind
+ /executeonly % for reading procedures
+ { readonly
+ }
+ /noaccess % for Subrs strings and Private dictionary
+ { readonly
+ }
+ /readonly % for procedures and CharStrings dictionary
+ { % We want to take the following non-standard actions here:
+ % - If the operand is the CharStrings dictionary, do nothing;
+ % - If the operand is a number (a file position replacing the
+ % actual CharString), do nothing;
+ % - If the operand is either of the reading procedures (-| or -!),
+ % substitute a different one.
+ dup type /dicttype eq % CharStrings or Private
+ count 2 gt and
+ { 1 index /CharStrings ne { readonly } if }
+ { dup type /arraytype eq % procedure or data array
+ { dup length 5 ge 1 index xcheck and
+ { dup 0 get /string eq
+ 1 index 1 get /currentfile eq and
+ 1 index 2 get /exch eq and
+ 1 index 3 get dup /readstring eq exch /readhexstring eq or and
+ 1 index 4 get /pop eq and
+ { /cskip_C cvx 2 packedarray cvx
+ }
+ { readonly
+ }
+ ifelse
+ }
+ { readonly
+ }
+ ifelse
+ }
+ { dup type /stringtype eq % must be a Subr string
+ { readonly }
+ if
+ }
+ ifelse
+ }
+ ifelse
+ } bind
+ /definefont % to insert BuildChar/Glyph and change FontType
+ { dup /FontType get 1 eq
+ { dup /FontType 4 put
+ dup /BuildChar /build_C load put
+ dup /BuildGlyph /build_C load put
+ }
+ if definefont
+ } bind
+counttomark 2 idiv { .loadfontdict 3 1 roll put } repeat pop
+.loadfontdict readonly pop
+
+% Define the BuildChar and BuildGlyph procedures for modified fonts.
+% A single procedure serves for both.
+/build_C % <font> <code|name> build_C -
+ { 1 index begin
+ dup dup type /integertype eq { Encoding exch get } if
+ % Stack: font code|name name
+ dup CharStrings exch .knownget not
+ { 2 copy eq { exch pop /.notdef exch } if
+ QUIET not
+ { (Substituting .notdef for ) print = flush }
+ { pop }
+ ifelse
+ /.notdef CharStrings /.notdef get
+ } if
+ % Stack: font code|name name charstring
+ dup type /integertype eq
+ { load_C end build_C }
+ { end .type1execchar }
+ ifelse
+ } bind def
diff --git a/gs/lib/gs_dpnxt.ps b/gs/lib/gs_dpnxt.ps
new file mode 100644
index 000000000..515e16d3f
--- /dev/null
+++ b/gs/lib/gs_dpnxt.ps
@@ -0,0 +1,30 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% gs_dpnxt.ps
+% NeXT Display PostScript extensions
+
+/sizeimage { % <x> <y> <width> <height> <matrix> sizeimage
+ % <pixelswide> <pixelshigh> <bits/sample> <matrix>
+ % <multiproc> <ncolors>
+ /sizeimage cvx /undefined signalerror % ****** NYI ******
+} odef
+
+/readimage { % <x> <y> <width> <height> <proc_0> [... <proc_N-1>]
+ % <string> <alpha_bool> readimage -
+ /readimage cvx /undefined signalerror % ****** NYI ******
+} odef
diff --git a/gs/lib/gs_dps.ps b/gs/lib/gs_dps.ps
new file mode 100644
index 000000000..6978d4189
--- /dev/null
+++ b/gs/lib/gs_dps.ps
@@ -0,0 +1,54 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for Display PostScript functions.
+
+% ------ Halftone phase ------ %
+
+/sethalftonephase { % <x> <y> sethalftonephase -
+ -1 2 index 2 index .setscreenphase pop pop
+} odef
+/currenthalftonephase { % - currenthalftonephase <x> <y>
+ 0 .currentscreenphase
+} odef
+
+% ------ Device information ------ %
+
+/.deviceinfodict mark
+ /Colors null /GrayValues null /RedValues null /GreenValues null
+ /BlueValues null /ColorValues null
+.dicttomark readonly def
+/deviceinfo { % - deviceinfo <dict>
+ currentdevice //.deviceinfodict .getdeviceparams .dicttomark readonly
+} odef
+
+% The current implementation allocates a 2-element array each time.
+% Perhaps we should change this to 2 separate parameters for X and Y?
+/.wtdict mark
+ /wtranslation null
+.dicttomark readonly def
+/wtranslation { % - wtranslation <x> <y>
+ currentdevice //.wtdict .getdeviceparams exch pop exch pop aload pop
+} odef
+currentdict /.wtdict .undef
+
+% ------ View clipping ------ %
+
+/rectviewclip { % <x> <y> <width> <height> rectviewclip -
+ % <numarray|numstring> rectviewclip -
+ newpath .rectappend viewclip
+} odef
diff --git a/gs/lib/gs_dps1.ps b/gs/lib/gs_dps1.ps
new file mode 100644
index 000000000..45b79cee3
--- /dev/null
+++ b/gs/lib/gs_dps1.ps
@@ -0,0 +1,136 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for most of the Display PostScript functions
+% that are also included in Level 2.
+
+level2dict begin
+
+% ------ Virtual memory ------ %
+
+/currentshared /.currentglobal load def
+/scheck /.gcheck load def
+%****** FOLLOWING IS WRONG ******
+/shareddict currentdict /globaldict .knownget not { 20 dict } if def
+
+% Global and LocalFontDirectory must remain in systemdict
+% even if we temporarily exit Level 2 mode.
+
+end % level2dict
+systemdict begin
+
+/SharedFontDirectory .FontDirectory .gcheck
+ { .currentglobal false .setglobal
+ /LocalFontDirectory .FontDirectory dup maxlength dict copy def
+ .setglobal .FontDirectory
+ }
+ { /LocalFontDirectory .FontDirectory def
+ 50 dict
+ }
+ifelse def
+
+end % systemdict
+level2dict begin
+
+% setshared must rebind FontDirectory to the appropriate one of
+% Local or SharedFontDirectory.
+
+/.setglobal % <bool> .setglobal -
+ { dup .setglobal
+ //systemdict /FontDirectory .currentglobal
+ { //SharedFontDirectory }
+ { //systemdict /LocalFontDirectory get } % can't embed ref to local VM
+ ifelse .forceput pop
+ } .bind odef % must bind .forceput and .setglobal
+ % even if NOBIND in effect
+/setshared /.setglobal load def
+.currentglobal setshared
+
+% ------ Fonts ------ %
+
+/selectfont % <fontname> <size> selectfont -
+ { 1 index findfont
+ 1 index dup type /arraytype eq { makefont } { scalefont } ifelse
+ setfont pop pop
+ } odef
+% undefinefont has to take local/global VM into account.
+/undefinefont % <fontname> undefinefont -
+ { .FontDirectory 1 index .undef
+ .currentglobal
+ { % Current mode is global; delete from local directory too.
+ //systemdict /LocalFontDirectory .knownget
+ { 1 index .undef }
+ if
+ }
+ { % Current mode is local; if there was a shadowed global
+ % definition, copy it into the local directory.
+ //systemdict /SharedFontDirectory .knownget
+ { 1 index .knownget
+ { .FontDirectory 2 index 3 -1 roll put }
+ if
+ }
+ if
+ }
+ ifelse pop
+ } odef
+
+% If we load a font into global VM within an inner save, the restore
+% will delete it from FontDirectory but not from SharedFontDirectory.
+% We have to handle this by making restore copy missing entries from
+% SharedFontDirectory to FontDirectory. Since this could slow down restore
+% considerably, we define a new operator .dictcopynew for this purpose.
+% Furthermore, if FAKEFONTS is in effect, we want global real fonts to
+% override fake local ones. We handle this by brute force.
+/restore % <save> restore -
+ { dup //restore % bind even if NOBIND
+ //systemdict /LocalFontDirectory get
+ FAKEFONTS
+ { mark
+ % We want to delete a fake font from the local directory
+ % iff the global directory now has no definition for it,
+ % or a non-fake definition.
+ 1 index dup
+ { % Stack: lfd mark lfd key ... lfd key value
+ length 1 gt
+ { % This is a real local definition; don't do anything.
+ pop
+ }
+ { % This is a fake local definition, check for global.
+ //SharedFontDirectory 1 index .knownget
+ { % A global definition exists, check for fake.
+ length 1 eq { pop } { 1 index } ifelse
+ }
+ { % No global definition, delete the local one.
+ 1 index
+ }
+ ifelse
+ }
+ ifelse
+ } forall
+ pop counttomark 2 idiv { .undef } repeat pop
+ }
+ if
+ //SharedFontDirectory exch .dictcopynew pop
+ .currentglobal .setglobal % Rebind FontDirectory according to current VM.
+ pop
+ } bind odef
+
+% ------ Miscellaneous ------ %
+
+/undef /.undef load def
+
+end % level2dict
diff --git a/gs/lib/gs_dps2.ps b/gs/lib/gs_dps2.ps
new file mode 100644
index 000000000..9a6d715fb
--- /dev/null
+++ b/gs/lib/gs_dps2.ps
@@ -0,0 +1,203 @@
+% Copyright (C) 1990, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for basic Display PostScript functions
+% that are also included in Level 2.
+
+level2dict begin
+
+% ------ Halftones ------ %
+
+/.makestackdict
+ { { counttomark -1 roll } forall .dicttomark
+ } bind def
+/currenthalftone % - currenthalftone <dict>
+ { mark .currenthalftone
+ { { exch pop } % halftone
+ { /HalftoneType 1 % screen
+ { /Frequency /Angle /SpotFunction }
+ .makestackdict
+ }
+ { /HalftoneType 2 % colorscreen
+ { /RedFrequency /RedAngle /RedSpotFunction
+ /GreenFrequency /GreenAngle /GreenSpotFunction
+ /BlueFrequency /BlueAngle /BlueSpotFunction
+ /GrayFrequency /GrayAngle /GraySpotFunction
+ }
+ .makestackdict
+ }
+ }
+ exch get exec
+ } odef
+% Define sethalftone so it converts all other types to type 5.
+/.sethalftoneRGBV % <dict> <type> <keys> <keysRGBV>
+ { 4 -1 roll exch { 1 index exch get exch } forall 15 1 roll
+ 14 -2 roll mark 15 1 roll { /Gray /Blue /Green /Red }
+ { % stack: v0 v1 v2 type keys comp
+ mark
+ 2 index 0 get 8 -1 roll
+ 4 index 1 get 9 -1 roll
+ 6 index 2 get 10 -1 roll
+ % stack: type keys comp mark k0 v0 k1 v1 k2 v2
+ /HalftoneType 10 index .dicttomark
+ counttomark 2 roll
+ }
+ forall pop pop
+ /Default 1 index .dicttomark .sethalftone5
+ } bind def
+/sethalftone { % <dict> sethalftone -
+ % We must create the new dictionary in the same VM as the
+ % operand; otherwise, invalidaccess errors may occur.
+ .currentglobal 1 index dup gcheck .setglobal
+ dup /HalftoneType get 1 sub {
+ { mark /Default 2 index .dicttomark .sethalftone5
+ }
+ { 1 { /Frequency /Angle /SpotFunction }
+ { /RedFrequency /RedAngle /RedSpotFunction
+ /GreenFrequency /GreenAngle /GreenSpotFunction
+ /BlueFrequency /BlueAngle /BlueSpotFunction
+ /GrayFrequency /GrayAngle /GraySpotFunction
+ } .sethalftoneRGBV
+ }
+ { mark /Default 2 index .dicttomark .sethalftone5
+ }
+ { 3 { /Width /Height /Thresholds }
+ { /RedWidth /RedHeight /RedThresholds
+ /GreenWidth /GreenHeight /GreenThresholds
+ /BlueWidth /BlueHeight /BlueThresholds
+ /GrayWidth /GrayHeight /GrayThresholds
+ } .sethalftoneRGBV
+ }
+ { dup .sethalftone5
+ }
+ } exch get exec .setglobal pop
+} odef
+% Redefine setscreen and setcolorscreen to recognize halftone dictionaries,
+% and to insert the Frequency and Angle into Type 1 halftones, per
+% Adobe TN 5085.
+/.fixsethalftonescreen % <freq> <angle> <dict> .fix...screen
+ % <freq> <angle> <dict> <dict'>
+ { dup dup /HalftoneType get 1 eq
+ { dup wcheck not { dup length .copydict } if
+ dup /Frequency 5 index put
+ dup /Angle 4 index put
+ }
+ if
+ } bind def
+/setscreen % <ignore*2> <dict> setscreen -
+ { dup type /dicttype eq
+ { .fixsethalftonescreen sethalftone pop pop pop }
+ { //setscreen }
+ ifelse
+ } odef
+/setcolorscreen % <ignore*11> <dict> setcolorscreen -
+ { dup type /dicttype eq
+ { .fixsethalftonescreen sethalftone 12 { pop } repeat }
+ { //setcolorscreen }
+ ifelse
+ } odef
+% Redefine currentscreen and currentcolorscreen to extract the Frequency
+% and Angle from Type 1 halftones, per Adobe TN 5085.
+/.fixcurrenthalftonescreen % <dict> .fix... <freq> <angle> <proc>
+ { dup /HalftoneType get 1 eq
+ { dup /Frequency get 1 index /Angle get }
+ { 60 0 }
+ ifelse 3 2 roll
+ } bind def
+/currentscreen % - currentscreen 60 0 <dict>
+ { .currenthalftone
+ { { .fixcurrenthalftonescreen } % halftone
+ { } % screen
+ { 12 3 roll 9 { pop } repeat % colorscreen
+ dup type /dicttype eq { .fixcurrenthalftonescreen } if
+ }
+ }
+ exch get exec
+ } odef
+/currentcolorscreen % - currentcolorscreen (60 0 <dict>)*4
+ { .currenthalftone
+ { { .fixcurrenthalftonescreen 3 copy 6 copy } % halftone
+ { 3 copy 6 copy } % screen
+ { } % colorscreen
+ }
+ exch get exec
+ } odef
+
+% ------ User objects ------ %
+
+/.localarray where {
+ pop
+} {
+ /.localarray {
+ currentglobal false setglobal
+ exch array exch setglobal
+ } bind def
+} ifelse
+% The name UserObjects may be rebound, but we need to make sure these
+% operators always refer to the binding in userdict (which may also be
+% rebound!).
+/.UserObjects {
+ //systemdict /userdict get /UserObjects
+} odef
+% In order to get proper error recovery behavior, we need to be careful
+% not to pop any operands from the stack until we're done.
+% The code below faithfully duplicates the apparent array-growing
+% behavior of Adobe interpreters.
+/defineuserobject { % <index> <value> defineuserobject -
+ .UserObjects .knownget {
+ length dup 3 index le {
+ % Stack: index value len
+ 2 index eq { 1 index 2 mul } { 1 index 1 add } ifelse
+ .localarray userdict /UserObjects get
+ 1 index copy pop
+ .UserObjects 3 -1 roll put
+ } {
+ pop
+ } ifelse
+ } {
+ .UserObjects 3 index 1 add 10 .max .localarray put
+ } ifelse
+ .UserObjects get 2 index 2 index put pop pop
+} odef
+/execuserobject { % <index> execuserobject -
+ .UserObjects get 1 index get exch pop exec
+} odef
+/undefineuserobject { % <index> undefineuserobject -
+ .UserObjects get 1 index null put pop
+} odef
+
+% ------ User paths ------ %
+
+/upath { % <bool> upath <array>
+ [ 1 index {/ucache cvx} if
+ true .pathbbox /setbbox cvx
+ {/moveto cvx} {/lineto cvx} {/curveto cvx} {/closepath cvx}
+ pathforall ] cvx exch pop
+} odef
+
+% Dummy definitions for cache control operators
+
+/ucachestatus { % - ucachestatus -mark- ? ? ? ? <size>
+ mark 0 0 0 0 userdict /.ucachesize .knownget not { 0 } if
+} odef
+/setucacheparams { % -mark- ... <size> setucacheparams -
+ % Provoke an appropriate error if needed.
+ counttomark 1 lt { () 0 get } if
+ 0 or userdict /.ucachesize 2 index 0 .max put cleartomark
+} odef
+
+end % level2dict
diff --git a/gs/lib/gs_epsf.ps b/gs/lib/gs_epsf.ps
new file mode 100644
index 000000000..e45b5e652
--- /dev/null
+++ b/gs/lib/gs_epsf.ps
@@ -0,0 +1,60 @@
+% Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Allow the interpreter to recognize MS-DOS EPSF file headers, and skip to
+% the PostScript section of the file.
+
+/.runnoepsf /run load def
+/.epsfheader <C5D0D3C6> def
+/run
+ { dup type /filetype ne { (r) file } if
+ % Check for MS-DOS EPSF file (see Red Book p. 729).
+ true exch 0 1 3
+ { % Stack: true file index
+ 1 index read dup { pop dup .epsfheader 3 index get eq } if
+ { pop pop } % if matched, don't need the character
+ { % unread characters (wasn't EPSF)
+ 2 index exch unread % unread mismatch character
+ dup { % loop unreading backwards in .epsfheader
+ 1 sub dup .epsfheader exch get 2 index exch unread
+ } repeat pop
+ exch not exch exit % change true to false
+ }
+ ifelse
+ }
+ for exch % Stack: file true/false
+ { % This block is executed if the file is MS-DOS EPSF.
+ % Build up the little-endian byte offset and length.
+ 2
+ { 1 0 4
+ { 2 index read not { pop exit } if % if EOF, let error happen
+ 2 index mul add exch 256 mul exch
+ }
+ repeat exch pop exch
+ }
+ repeat
+ % Stack: offset length file
+ % Use flushfile to skip quickly to the start of the
+ % PostScript section.
+ dup 4 -1 roll 12 sub () /SubFileDecode filter flushfile
+ % Now interpret the PostScript.
+ exch () /SubFileDecode filter cvx .runexec
+ }
+ { .runnoepsf
+ }
+ ifelse
+ } odef
diff --git a/gs/lib/gs_fform.ps b/gs/lib/gs_fform.ps
new file mode 100644
index 000000000..38ea6be2b
--- /dev/null
+++ b/gs/lib/gs_fform.ps
@@ -0,0 +1,110 @@
+% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% gs_fform.ps
+% Monochrome Form caching implemented in PostScript.
+
+% This implementation is pretty unreasonable:
+% - It doesn't remember transparent pixels.
+% - It reduces everything to black and white.
+% - It doesn't handle halftone or Pattern phasing.
+% However, it's good enough to produce some useful output.
+
+% In order to prevent restore from clearing the cache, we explicitly
+% push the cache entries on the stack before a restore and reinstall them.
+/formcachedict 20 dict def
+currentglobal true setglobal
+/restore
+ { mark formcachedict { } forall
+ counttomark 1 add index { restore } .internalstopped
+ { cleartomark restore }
+ { counttomark 2 idiv { formcachedict 3 1 roll put } repeat pop pop }
+ ifelse
+ } bind odef
+
+/.form.buffer 65000 string def
+/execform
+ { dup /Implementation known not
+ { dup /FormType get 1 ne { /rangecheck signalerror } if
+ formcachedict 1 index .knownget not
+ { currentglobal true setglobal
+ % Stack: form global
+ 10 dict
+ dup /ImageType 1 put
+ dup /ImageMatrix [0 0 0 0 0 0] put
+ dup /DataSource
+ { % Stack: y (impl is on dict stack)
+ Height 1 index sub
+ //.form.buffer length Width 7 add 8 idiv idiv .min
+ 1 index add exch
+ Device exch //.form.buffer copyscanlines
+ }
+ put
+ dup /BitsPerComponent 1 put
+ dup /Decode [0 1] put
+ dup /Device null put
+ % Stack: form global impl
+ formcachedict 3 index 2 index put
+ exch setglobal
+ }
+ if 1 index /Implementation 3 -1 roll put
+ }
+ if
+ gsave dup /Matrix get concat
+ dup /Implementation get
+ % Check whether we can use the cached value.
+ % Stack: form implementation
+ dup /ImageMatrix get matrix currentmatrix
+ true 0 1 3
+ { % Stack: form impl cachemat curmat true index
+ 3 index 1 index get exch 3 index exch get ne { pop false exit } if
+ }
+ for % Stack: form impl cachemat curmat valid
+ exch pop exch pop not
+ { % Cache is invalid. Execute the Form and save the bits.
+ gsave begin
+ currentglobal exch true setglobal
+ ImageMatrix currentmatrix pop
+ dup /BBox get aload pop
+ exch 3 index sub exch 2 index sub rectclip
+ % Make the cache device.
+ clippath gsave matrix setmatrix pathbbox grestore
+ % We now have the bounding box in device space.
+ 2 { 4 -1 roll floor cvi } repeat
+ 2 { 4 -1 roll ceiling cvi } repeat
+ 2 index sub /Height exch def
+ 2 index sub /Width exch def
+ ImageMatrix aload pop
+ exch 7 index sub exch 6 index sub
+ 6 array astore
+ 3 1 roll pop pop
+ dup ImageMatrix copy pop
+ Width Height <00 ff> makeimagedevice
+ /Device 1 index def
+ nulldevice setdevice initgraphics
+ exch setglobal
+ dup dup /PaintProc get exec
+ nulldevice grestore currentdict end
+ }
+ if
+ % Now paint the bits.
+ % Stack: form implementation
+ /DeviceGray setcolorspace dup begin 0 exch image end pop
+ pop grestore
+ } odef
+
+setglobal
diff --git a/gs/lib/gs_fonts.ps b/gs/lib/gs_fonts.ps
new file mode 100644
index 000000000..e36214b25
--- /dev/null
+++ b/gs/lib/gs_fonts.ps
@@ -0,0 +1,912 @@
+% Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Font initialization and management code.
+
+% Define the default font.
+/defaultfontname /Courier def
+
+% Define the name of the font map file.
+/defaultfontmap (Fontmap) def
+
+% ------ End of editable parameters ------ %
+
+% If SUBSTFONT is defined, make it the default font.
+/SUBSTFONT where { pop /defaultfontname /SUBSTFONT load def } if
+
+% Define a reliable way of accessing FontDirectory in systemdict.
+/.FontDirectory
+{ //systemdict /FontDirectory get
+} bind odef
+
+% If DISKFONTS is true, we load individual CharStrings as they are needed.
+% (This is intended primarily for machines with very small memories.)
+% In this case, we define another dictionary, parallel to FontDirectory,
+% that retains an open file for every font loaded.
+/FontFileDirectory 10 dict def
+
+% Define a temporary string for local use, since using =string
+% interferes with some PostScript programs.
+/.fonttempstring 128 string def
+
+% Split up a search path into individual directories or files.
+/.pathlist % <path> .pathlist <dir1|file1> ...
+ { { dup length 0 eq { pop exit } if
+ .filenamelistseparator search not { exit } if
+ exch pop exch
+ }
+ loop
+ } bind def
+
+% Load a font name -> font file name map.
+userdict /Fontmap .FontDirectory maxlength dict put
+/.loadFontmap % <file> .loadFontmap -
+ { % We would like to simply execute .definefontmap as we read,
+ % but we have to maintain backward compatibility with an older
+ % specification that makes later entries override earlier.
+ 50 dict exch
+ { dup token not { closefile exit } if
+ % stack: <file> fontname
+ % This is a hack to get around the absurd habit of MS-DOS editors
+ % of adding an EOF character at the end of the file.
+ dup (\032) eq { pop closefile exit } if
+ 1 index token not
+ { (Fontmap entry for ) print dup =only
+ ( has no associated file or alias name! Giving up.\n) print flush
+ {.loadFontmap} 0 get 1 .quit
+ } if
+ dup type dup /stringtype eq exch /nametype eq or not
+ { (Fontmap entry for ) print 1 index =only
+ ( has an invalid file or alias name! Giving up.\n) print flush
+ {.loadFontmap} 0 get 1 .quit
+ } if
+ % stack: dict file fontname filename|aliasname
+ % Read and pop tokens until a semicolon.
+ { 2 index token not
+ { (Fontmap entry for ) print 1 index =only
+ ( ends prematurely! Giving up.\n) print flush
+ {.loadFontmap} 0 get 1 .quit
+ } if
+ dup /; eq { pop 3 index 3 1 roll .growput exit } if
+ pop
+ } loop
+ } loop
+ { .definefontmap } forall
+ } bind def
+% Add an entry in Fontmap. We redefine this if the Level 2
+% resource machinery is loaded.
+/.definefontmap % <fontname> <file|alias> .definefontmap -
+ { % Since Fontmap is global, make sure the values are storable.
+ .currentglobal 3 1 roll true .setglobal
+ dup type /stringtype eq
+ { dup .gcheck not { dup length string copy } if
+ }
+ if
+ Fontmap 3 -1 roll 2 copy .knownget
+ { % Add an element to the end of the existing value,
+ % unless it's the same as the current last element.
+ mark exch aload pop counttomark 4 add -1 roll
+ 2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse
+ }
+ { % Make a new entry.
+ mark 4 -1 roll ] readonly .growput
+ }
+ ifelse .setglobal
+ } bind def
+
+% Parse a font file just enough to find the FontName or FontType.
+/.findfontvalue % <file> <key> .findfontvalue <value> true
+ % <file> <key> .findfontvalue false
+ % Closes the file in either case.
+ { exch dup read not { -1 } if
+ 2 copy unread 16#80 eq
+ { dup (xxxxxx) readstring pop pop } % skip .PFB header
+ if
+ % Stack: key file
+ { dup token not { false exit } if % end of file
+ dup /eexec eq { pop false exit } if % reached eexec section
+ dup /Subrs eq { pop false exit } if % Subrs without eexec
+ dup /CharStrings eq { pop false exit } if % CharStrings without eexec
+ dup 3 index eq
+ { xcheck not { dup token exit } if } % found key
+ { pop }
+ ifelse
+ } loop
+ % Stack: key file value true (or)
+ % Stack: key file false
+ dup { 4 } { 3 } ifelse -2 roll closefile pop
+ } bind def
+/.findfontname
+ { /FontName .findfontvalue
+ } bind def
+
+% If there is no FONTPATH, try to get one from the environment.
+NOFONTPATH { /FONTPATH () def } if
+/FONTPATH where
+ { pop }
+ { /FONTPATH (GS_FONTPATH) getenv not { () } if def }
+ifelse
+FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
+/FONTPATH [ FONTPATH .pathlist ] def
+
+% Scan directories looking for plausible fonts. "Plausible" means that
+% the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001
+% followed by four arbitrary bytes and then either of these strings.
+% To speed up the search, we skip any file whose name appears in
+% the Fontmap (with any extension and upper/lower case variation) already,
+% and any file whose extension definitely indicates it is not a font.
+%
+% NOTE: The current implementation of this procedure is somewhat Unix/DOS-
+% specific. It assumes that '/' and '\' are directory separators, and that
+% the part of a file name following the last '.' is the extension.
+%
+/.lowerstring % <string> .lowerstring <lowerstring>
+ { 0 1 2 index length 1 sub
+ { 2 copy get dup 65 ge exch 90 le and
+ { 2 copy 2 copy get 32 add put }
+ if pop
+ }
+ for
+ } bind def
+/.splitfilename % <dir.../base.extn> .basename <base> <extn>
+ { { (/) search { true } { (\\) search } ifelse
+ { pop pop }
+ { exit }
+ ifelse
+ }
+ loop
+ dup { (.) search { pop pop } { exit } ifelse } loop
+ 2 copy eq
+ { pop () }
+ { exch dup length 2 index length 1 add sub 0 exch getinterval exch }
+ ifelse
+% Following is debugging code.
+% (*** Split => ) print 2 copy exch ==only ( ) print ==only
+% ( ***\n) print flush
+ } bind def
+/.scanfontdict 1 dict def % establish a binding
+/.scanfontbegin
+ { % Construct the table of all file names already in Fontmap.
+ currentglobal true setglobal
+ .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength
+ Fontmap
+ { exch pop
+ { dup type /stringtype eq
+ { .splitfilename pop .fonttempstring copy .lowerstring cvn
+ .scanfontdict exch true put
+ }
+ { pop
+ }
+ ifelse
+ }
+ forall
+ }
+ forall
+ setglobal
+ } bind def
+/.scanfontskip mark
+ % Strings are converted to names anyway, so....
+ /afm true
+ /bat true
+ /c true
+ /cmd true
+ /com true
+ /dll true
+ /doc true
+ /drv true
+ /exe true
+ /fon true
+ /fot true
+ /h true
+ /o true
+ /obj true
+ /pfm true
+ /pss true % Adobe Multiple Master font instances
+ /txt true
+.dicttomark def
+/.scan1fontstring 128 string def
+/.scanfontheaders [(%!PS-Adobe*) (%!FontType*)] def
+0 .scanfontheaders { length max } forall 6 add % extra for PFB header
+/.scan1fontfirst exch string def
+/.scanfontdir % <dirname> .scanfontdir -
+ { currentglobal exch true setglobal
+ QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if
+ (*) 2 copy .filenamedirseparator
+ dup (\\) eq { pop (\\\\) } if % double \ for pattern match
+ exch concatstrings concatstrings
+ 0 0 0 4 -1 roll % found scanned files
+ { % stack: <fontcount> <scancount> <filecount> <filename>
+ exch 1 add exch % increment filecount
+ dup .splitfilename .lowerstring
+ % stack: <fontcount> <scancount> <filecount+1> <filename>
+ % <BASE> <ext>
+ .scanfontskip exch known exch .scanfontdict exch known or
+ { pop
+ % stack: <fontcount> <scancount> <filecount+1>
+ }
+ { 3 -1 roll 1 add 3 1 roll
+ % stack: <fontcount> <scancount+1> <filecount+1> <filename>
+ dup (r) { file } .internalstopped
+ { pop pop null ()
+ % stack: <fontcount> <scancount+1> <filecount+1> <filename>
+ % null ()
+ }
+ {
+ % On some platforms, the file operator will open directories,
+ % but an error will occur if we try to read from one.
+ % Handle this possibility here.
+ dup .scan1fontfirst { readstring } .internalstopped
+ { pop pop () }
+ { pop }
+ ifelse
+ % stack: <fontcount> <scancount+1> <filecount+1>
+ % <filename> <file> <header>
+ }
+ ifelse
+ % Check for PFB file header.
+ dup (\200\001????*) .stringmatch
+ { dup length 6 sub 6 exch getinterval }
+ if
+ % Check for font file headers.
+ false .scanfontheaders
+ { 2 index exch .stringmatch or
+ }
+ forall exch pop
+ { % stack: <fontcount> <scancount+1> <filecount+1> <filename>
+ % <file>
+ dup 0 setfileposition .findfontname
+ { dup Fontmap exch known
+ { pop pop
+ }
+ { exch copystring exch
+ DEBUG { ( ) print dup =only } if
+ 1 index .definefontmap
+ .splitfilename pop true .scanfontdict 3 1 roll .growput
+ % Increment fontcount.
+ 3 -1 roll 1 add 3 1 roll
+ }
+ ifelse
+ }
+ { pop
+ }
+ ifelse
+ }
+ % .findfontname will have done a closefile in the above case.
+ { dup null eq { pop } { closefile } ifelse pop
+ }
+ ifelse
+ }
+ ifelse
+ }
+ .scan1fontstring filenameforall
+ QUIET
+ { pop pop pop }
+ { ( ) print =only ( files, ) print =only ( scanned, ) print
+ =only ( new fonts.\n) print flush
+ }
+ ifelse
+ setglobal
+ } bind def
+
+%END FONTPATH
+
+% Create the dictionary that registers the .buildfont procedure (called by
+% definefont) for each FontType.
+/buildfontdict 20 dict def
+
+% Register Type 3 fonts, which are always supported, for definefont.
+buildfontdict 3 /.buildfont3 cvx put
+
+% Register Type 0 fonts if they are supported. Strictly speaking,
+% we should do this in its own file (gs_type0.ps), but since this is
+% the only thing that would be in that file, it's simpler to put it here.
+/.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if
+
+% Define definefont. This is a procedure built on a set of operators
+% that do all the error checking and key insertion.
+/.growfontdict
+ { % Grow the font dictionary, if necessary, to ensure room for an
+ % added entry, making sure there is at least one slot left for FID.
+ dup maxlength 1 index length sub 2 lt
+ { dup dup wcheck
+ { .growdict }
+ { .growdictlength dict .copydict }
+ ifelse
+ }
+ { dup wcheck not { dup maxlength dict .copydict } if
+ }
+ ifelse
+ } bind def
+/.completefont {
+ { % Check for disabled platform fonts.
+ NOPLATFONTS
+ { % Make sure we leave room for FID.
+ .growfontdict dup /ExactSize 0 put
+ }
+ { % Hack: if the Encoding looks like it might be the
+ % Symbol or Dingbats encoding, load those now (for the
+ % benefit of platform font matching) just in case
+ % the font didn't actually reference them.
+ dup /Encoding get length 65 ge
+ { dup /Encoding get 64 get
+ dup /congruent eq { SymbolEncoding pop } if
+ /a9 eq { DingbatsEncoding pop } if
+ }
+ if
+ }
+ ifelse
+ dup /FontType get //buildfontdict exch get exec
+ DISKFONTS
+ { FontFileDirectory 2 index known
+ { dup /FontFile FontFileDirectory 4 index get .growput
+ }
+ if
+ }
+ if
+ readonly % stack: name fontdict
+ } stopped { /invalidfont signalerror } if
+} bind odef
+/definefont
+ { .completefont
+ % If the current allocation mode is global, also enter
+ % the font in LocalFontDirectory.
+ .currentglobal
+ { //systemdict /LocalFontDirectory .knownget
+ { 2 index 2 index .growput }
+ if
+ }
+ if
+ dup .FontDirectory 4 -2 roll .growput
+ } odef
+
+% Define a procedure for defining aliased fonts.
+% We can't just copy the font (or even use the same font unchanged),
+% because a significant number of PostScript files assume that
+% the FontName of a font is the same as the font resource name or
+% the key in [Shared]FontDirectory; on the other hand, some Adobe files
+% rely on the FontName of a substituted font *not* being the same as
+% the requested resource name. We address this issue heuristically:
+% we substitute the new name iff the font name doesn't have MM in it.
+/.aliasfont % <name> <font> .aliasfont <newFont>
+ { .currentglobal 3 1 roll dup .gcheck .setglobal
+ dup length 2 add dict
+ dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall
+ % Stack: global fontname newfont newfont.
+ % We might be defining a global font whose FontName
+ % is a local string. This is weird, but legal,
+ % and doesn't cause problems anywhere else:
+ % to avoid any possible problems in this case, do a cvn.
+ % We might also be defining (as an alias) a global font
+ % whose FontName is a local non-string, if someone passed a
+ % garbage value to findfont. In this case, just don't
+ % call definefont at all.
+ 2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or
+ { 2 index .fonttempstring cvs (MM) search
+ { pop pop pop pop
+ }
+ { /FontName exch dup type /stringtype eq { cvn } if put
+ }
+ ifelse
+ % Don't bind in definefont, since Level 2 redefines it.
+ //systemdict /definefont get exec
+ }
+ { .completefont pop exch pop
+ }
+ ifelse exch .setglobal
+ } odef % so findfont will bind it
+
+% Define .loadfontfile for loading a font. If we recognize Type 1 and/or
+% TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this.
+/.loadfontfile { cvx exec } bind def
+/.loadfont
+ { % Some buggy fonts leave extra junk on the stack,
+ % so we have to make a closure that records the stack depth
+ % in a fail-safe way.
+ /.loadfontfile cvx count 1 sub 2 packedarray cvx exec
+ count exch sub { pop } repeat
+ } bind def
+
+% Find an alternate font to substitute for an unknown one.
+% We go to some trouble to parse the font name and extract
+% properties from it. Later entries take priority over earlier.
+/.substitutefaces [
+ % Guess at suitable substitutions for random unknown fonts.
+ [(Grot) /Times]
+ [(Roman) /Times]
+ [(Book) /NewCenturySchlbk]
+ % If the family name appears in the font name,
+ % use a font from that family.
+ [(Arial) /Helvetica]
+ [(Avant) /AvantGarde]
+ [(Bookman) /Bookman]
+ [(Century) /NewCenturySchlbk]
+ [(Cour) /Courier]
+ [(Geneva) /Helvetica]
+ [(Helv) /Helvetica]
+ [(NewYork) /Times]
+ [(Pala) /Palatino]
+ [(Sans) /Helvetica]
+ [(Schlbk) /NewCenturySchlbk]
+ [(Serif) /Times]
+ [(Swiss) /Helvetica]
+ [(Times) /Times]
+ [(Univers) /Helvetica]
+ % Substitute for Adobe Multiple Master fonts.
+ [(Minion) /Times]
+ [(Myriad) /Helvetica]
+ [(MyriadPkg) /Helvetica-Narrow]
+ % Condensed or narrow fonts map to the only narrow family we have.
+ [(Cond) /Helvetica-Narrow]
+ [(Narrow) /Helvetica-Narrow]
+ % If the font wants to be monospace, use Courier.
+ [(Monospace) /Courier]
+ [(Typewriter) /Courier]
+] readonly def
+/.substituteproperties [
+ [(It) 1] [(Oblique) 1]
+ [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2]
+] readonly def
+/.substitutefamilies mark
+ /AvantGarde
+ {/AvantGarde-Book /AvantGarde-BookOblique
+ /AvantGarde-Demi /AvantGarde-DemiOblique}
+ /Bookman
+ {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic}
+ /Courier
+ {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique}
+ /Helvetica
+ {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
+ /Helvetica-Narrow
+ {/Helvetica-Narrow /Helvetica-Narrow-Oblique
+ /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique}
+ /NewCenturySchlbk
+ {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
+ /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic}
+ /Palatino
+ {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic}
+ /Times
+ {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic}
+.dicttomark readonly def
+/.substitutefont % <fontname> .substitutefont <altname>
+ { % Look for properties and/or a face name in the font name.
+ % If we find any, use Helvetica as the base font;
+ % otherwise, use the default font.
+ % Note that the "substituted" font name may be the same as
+ % the requested one; the caller must check this.
+ dup type dup /stringtype eq exch /nametype eq or
+ { dup length string cvs } { () } ifelse
+ {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
+ exch 0 exch % stack: fontname facelist properties fontname
+ % Look for a face name.
+ .substitutefaces
+ { 2 copy 0 get search
+ { pop pop pop 1 get .substitutefamilies exch get
+ 4 -1 roll pop 3 1 roll
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall
+ .substituteproperties
+ { 2 copy 0 get search
+ { pop pop pop 1 get 3 -1 roll or exch }
+ { pop pop }
+ ifelse
+ }
+ forall pop get exec
+ % Only accept fonts known in the Fontmap.
+ Fontmap 1 index known not { pop defaultfontname } if
+ } bind def
+
+% If requested, make (and recognize) fake entries in FontDirectory for fonts
+% present in Fontmap but not actually loaded. Thanks to Ray Johnston for
+% the idea behind this code.
+FAKEFONTS not { (%END FAKEFONTS) .skipeof } if
+
+% We use the presence or absence of the FontMatrix key to indicate whether
+% a font is real or fake. We must pop the arguments at the very end,
+% so that stack protection will be effective.
+
+/definefont { % <name> <font> definefont <font>
+ dup /FontMatrix known {
+ //definefont
+ } {
+ 2 copy /FontName get findfont //definefont exch pop exch pop
+ } ifelse
+} bind odef
+
+/scalefont { % <font> <scale> scalefont <font>
+ 1 index /FontMatrix known {
+ //scalefont
+ } {
+ 1 index /FontName get findfont 1 index //scalefont
+ exch pop exch pop
+ } ifelse
+} bind odef
+
+/makefont { % <font> <matrix> makefont <font>
+ 1 index /FontMatrix known {
+ //makefont
+ } {
+ 1 index /FontName get findfont 1 index //makefont
+ exch pop exch pop
+ } ifelse
+} bind odef
+
+/setfont { % <font> setfont -
+ dup /FontMatrix known {
+ //setfont
+ } {
+ dup /FontName get findfont //setfont pop
+ } ifelse
+} bind odef
+
+%END FAKEFONTS
+
+% Define findfont so it tries to load a font if it's not found.
+% The Red Book requires that findfont be a procedure, not an operator,
+% but it still needs to restore the stacks reliably if it fails,
+% so we do all the work in an operator.
+/.findfont {
+ mark 1 index
+ //systemdict begin .dofindfont
+ % Define any needed aliases.
+ counttomark 1 sub { .aliasfont } repeat end
+ exch pop exch pop
+} odef
+/findfont {
+ .findfont
+} bind def
+% Check whether the font name we are about to look for is already on the list
+% of aliases we're accumulating; if so, cause an error.
+/.checkalias % -mark- <alias1> ... <name> .checkalias <<same>>
+ { counttomark 1 sub -1 1
+ { index 1 index eq
+ { pop QUIET not
+ { (Unable to substitute for font.\n) print flush
+ } if
+ /findfont cvx /invalidfont signalerror
+ }
+ if
+ }
+ for
+ } bind def
+% Get a (non-fake) font if present in a FontDirectory.
+/.fontknownget % <fontdir> <fontname> .fontknownget <font> true
+ % <fontdir> <fontname> .fontknownget false
+ { .knownget
+ { FAKEFONTS
+ { dup /FontMatrix known { true } { pop false } ifelse }
+ { true }
+ ifelse
+ }
+ { false
+ }
+ ifelse
+ } bind def
+% Do the work of findfont, including substitution, defaulting, and
+% scanning of FONTPATH.
+/.dofindfont % <fontname> .dofindfont <font>
+ { { .tryfindfont { exit } if
+ % We didn't find the font. If we haven't scanned
+ % all the directories in FONTPATH, scan the next one now,
+ % and look for the font again.
+ null 0 1 FONTPATH length 1 sub
+ { FONTPATH 1 index get null ne { exch pop exit } if pop
+ }
+ for dup null ne
+ { dup 0 eq { .scanfontbegin } if
+ FONTPATH 1 index get .scanfontdir
+ FONTPATH exch null put
+ % Start over with an empty alias list.
+ counttomark 1 sub { pop } repeat
+ .dofindfont exit
+ }
+ if pop
+ % No luck. Make sure we're not already
+ % looking for the default font.
+ dup defaultfontname eq
+ { QUIET not
+ { (Unable to load default font ) print
+ dup =only (! Giving up.\n) print flush
+ }
+ if /findfont cvx /invalidfont signalerror
+ }
+ if
+ % Substitute for the font.
+ % If SUBSTFONT is defined, don't alias.
+ /SUBSTFONT where {
+ pop QUIET not {
+ (Substituting for font ) print dup =only
+ (.\n) print flush
+ } if
+ cleartomark mark defaultfontname
+ } {
+ dup .substitutefont
+ 2 copy eq { pop defaultfontname } if
+ .checkalias
+ QUIET not {
+ (Substituting font ) print dup =only ( for ) print
+ 1 index =only (.\n) print flush
+ } if
+ } ifelse
+ }
+ loop
+ } bind def
+% Try to find a font using only the present contents of Fontmap.
+/.tryfindfont % <fontname> .tryfindfont <font> true
+ % <fontname> .tryfindfont false
+ { .FontDirectory 1 index .fontknownget
+ { % Already loaded
+ exch pop true
+ }
+ { dup Fontmap exch .knownget not
+ { % Unknown font name. Look for a file with the
+ % same name as the requested font.
+ dup dup type /nametype eq { .namestring } if .loadfontloop
+ }
+ { % Try each element of the Fontmap in turn.
+ false exch % (in case we exhaust the list)
+ % Stack: fontname false fontmaplist
+ { exch pop
+ dup type /nametype eq
+ { % Font alias
+ .checkalias .tryfindfont exit
+ }
+ { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and
+ { % Font with a procedural definition
+ exec % The procedure will load the font.
+ % Check to make sure this really happened.
+ .FontDirectory 1 index .knownget
+ { exch pop true exit }
+ if
+ }
+ { % Font file name
+ .loadfontloop { true exit } if
+ }
+ ifelse
+ }
+ ifelse false
+ }
+ forall
+ % Stack: font true -or- fontname false
+ { true
+ }
+ { % None of the Fontmap entries worked.
+ % Try loading a file with the same name
+ % as the requested font.
+ dup dup type /nametype eq { .namestring } if .loadfontloop
+ }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+ } bind def
+% Attempt to load a font from a file.
+/.loadfontloop % <filename> .loadfontloop <font> true
+ % <filename> .loadfontloop false
+ { % See above regarding the use of 'loop'.
+
+ {
+ % Is the font name a string?
+ dup type /stringtype ne
+ { QUIET not
+ { (Can't find font with non-string name: ) print dup =only (.\n) print flush
+ }
+ if pop false exit
+ }
+ if
+ % Can we open the file?
+ findlibfile not
+ { QUIET not
+ { (Can't find \(or can't open\) font file ) print dup print
+ (.\n) print flush
+ }
+ if pop false exit
+ }
+ if
+
+ % Stack: fontname fontfilename fontfile
+ DISKFONTS
+ { .currentglobal true .setglobal
+ 2 index (r) file
+ FontFileDirectory exch 5 index exch .growput
+ .setglobal
+ }
+ if
+ QUIET not
+ { (Loading ) print 2 index =only
+ ( font from ) print 1 index print (... ) print flush
+ }
+ if
+ % If LOCALFONTS isn't set, load the font into local or global
+ % VM according to FontType; if LOCALFONTS is set, load the font
+ % into the current VM, which is what Adobe printers (but not
+ % DPS or CPSI) do.
+ LOCALFONTS { false } { /setglobal where } ifelse
+ { pop /FontType .findfontvalue { 1 eq } { false } ifelse
+ % .setglobal, like setglobal, aliases FontDirectory to
+ % GlobalFontDirectory if appropriate. However, we mustn't
+ % allow the current version of .setglobal to be bound in,
+ % because it's different depending on language level.
+ .currentglobal exch /.setglobal load exec
+ % Remove the fake definition, if any.
+ .FontDirectory 3 index .undef
+ 1 index (r) file .loadfont .FontDirectory exch
+ /.setglobal load exec
+ }
+ { .loadfont .FontDirectory
+ }
+ ifelse
+ % Stack: fontname fontfilename fontdirectory
+ QUIET not
+ { //systemdict /level2dict known
+ { .currentglobal false .setglobal vmstatus
+ true .setglobal vmstatus 3 -1 roll pop
+ 6 -1 roll .setglobal 5
+ }
+ { vmstatus 3
+ }
+ ifelse { =only ( ) print } repeat
+ (done.\n) print flush
+ } if
+
+ % Check to make sure the font was actually loaded.
+ dup 3 index .fontknownget
+ { 4 1 roll pop pop pop true exit } if
+
+ % Maybe the file had a different FontName.
+ % See if we can get a FontName from the file, and if so,
+ % whether a font by that name exists now.
+ exch (r) file .findfontname
+ { 2 copy .fontknownget
+ { % Yes. Stack: origfontname fontdirectory filefontname fontdict
+ 3 -1 roll pop exch
+ QUIET
+ { pop
+ }
+ { (Using ) print =only
+ ( font for ) print 1 index =only
+ (.\n) print flush
+ }
+ ifelse true exit
+ }
+ if pop
+ }
+ if pop
+
+ % The font definitely did not load correctly.
+ QUIET not
+ { (Loading ) print dup =only
+ ( font failed.\n) print flush
+ } if
+ false exit
+
+ } loop % end of loop
+
+ } bind def
+
+% Define a procedure to load all known fonts.
+% This isn't likely to be very useful.
+/loadallfonts
+ { Fontmap { pop findfont pop } forall
+ } bind def
+
+% If requested, load all the fonts defined in the Fontmap into FontDirectory
+% as "fake" fonts i.e., font dicts with only FontName and FontType defined.
+% (We define FontType only to for the sake of some questionable code in the
+% Apple Printer Utility 2.0 font inquiry code.) We must ensure that this
+% happens in both global and local directories.
+/.definefakefonts
+ {
+ }
+ { (gs_fonts FAKEFONTS) VMDEBUG
+ 2
+ { .currentglobal not .setglobal
+ Fontmap
+ { pop dup type /stringtype eq { cvn } if
+ .FontDirectory 1 index known not
+ { 2 dict dup /FontName 3 index put
+ dup /FontType 1 put
+ .FontDirectory 3 1 roll put
+ }
+ { pop
+ }
+ ifelse
+ }
+ forall
+ }
+ repeat
+ }
+FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined
+
+% Install initial fonts from Fontmap.
+/.loadinitialfonts
+ { NOFONTMAP not
+ { /FONTMAP where
+ { pop [ FONTMAP .pathlist ]
+ { dup VMDEBUG findlibfile
+ { exch pop .loadFontmap }
+ { /undefinedfilename signalerror }
+ ifelse
+ }
+ }
+ { LIBPATH
+ { defaultfontmap 2 copy .filenamedirseparator
+ exch concatstrings concatstrings dup VMDEBUG
+ (r) { file } .internalstopped
+ { pop pop } { .loadFontmap } ifelse
+ }
+ }
+ ifelse forall
+ }
+ if
+ .definefakefonts
+ } def % don't bind, .current/setglobal get redefined
+
+% ---------------- Synthetic font support ---------------- %
+
+% Create a new font by modifying an existing one. paramdict contains
+% entries with the same keys as the ones found in a Type 1 font;
+% it should also contain enough empty entries to allow adding the
+% corresponding non-overridden entries from the original font dictionary,
+% including FID. If paramdict includes a FontInfo entry, this will
+% also override the original font's FontInfo, entry by entry;
+% again, it must contain enough empty entries.
+
+% Note that this procedure does not perform a definefont.
+
+/.makemodifiedfont % <fontdict> <paramdict> .makemodifiedfont <fontdict'>
+ { exch
+ { % Stack: destdict key value
+ 1 index /FID ne
+ { 2 index 2 index known
+ { % Skip fontdict entry supplied in paramdict, but
+ % handle FontInfo specially.
+ 1 index /FontInfo eq
+ { 2 index 2 index get % new FontInfo
+ 1 index % old FontInfo
+ { % Stack: destdict key value destinfo key value
+ 2 index 2 index known
+ { pop pop }
+ { 2 index 3 1 roll put }
+ ifelse
+ }
+ forall pop
+ }
+ if
+ }
+ { % No override, copy the fontdict entry.
+ 2 index 3 1 roll put
+ dup dup % to match pop pop below
+ }
+ ifelse
+ }
+ if
+ pop pop
+ } forall
+ } bind def
+
+% Make a modified font and define it. Note that unlike definefont,
+% this does not leave the font on the operand stack.
+
+/.definemodifiedfont % <fontdict> <paramdict> .definemodifiedfont -
+ { .makemodifiedfont
+ dup /FontName get exch definefont pop
+ } bind def
diff --git a/gs/lib/gs_init.ps b/gs/lib/gs_init.ps
new file mode 100644
index 000000000..791a36afa
--- /dev/null
+++ b/gs/lib/gs_init.ps
@@ -0,0 +1,1458 @@
+% Copyright (C) 1989, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for the interpreter.
+% When this is run, systemdict is still writable.
+
+% Comment lines of the form
+% %% Replace <n> <file(s)>
+% indicate places where the next <n> lines should be replaced by
+% the contents of <file(s)>, when creating a single merged init file.
+
+% The interpreter can call out to PostScript code. All procedures
+% called in this way, and no other procedures defined in these
+% initialization files, have names that begin with %, e.g.,
+% (%Type1BuildChar) cvn.
+
+% Check the interpreter revision. NOTE: the interpreter code requires
+% that the first non-comment token in this file be an integer.
+513
+dup revision ne
+ { (gs: Interpreter revision \() print revision 10 string cvs print
+ (\) does not match gs_init.ps revision \() print 10 string cvs print
+ (\).\n) print flush null 1 .quit
+ }
+if pop
+
+% Acquire userdict, and set its length if necessary.
+/userdict where
+ { pop userdict maxlength 0 eq }
+ { true }
+ifelse
+ { % userdict wasn't already set up by iinit.c.
+ /userdict
+ currentdict dup 200 .setmaxlength % userdict
+ systemdict begin def % can't use 'put', userdict is local
+ }
+ { systemdict begin
+ }
+ifelse
+
+% Define dummy local/global operators if needed.
+systemdict /.setglobal known
+ { true .setglobal
+ }
+ { /.setglobal { pop } bind def
+ /.currentglobal { false } bind def
+ /.gcheck { pop false } bind def
+ }
+ifelse
+
+% Define .languagelevel if needed.
+systemdict /.languagelevel known not { /.languagelevel 1 def } if
+
+% Optionally choose a default paper size other than U.S. letter.
+% (a4) /PAPERSIZE where { pop pop } { /PAPERSIZE exch def } ifelse
+
+% Turn on array packing for the rest of initialization.
+true setpacking
+
+% Define the old MS-DOS EOF character as a no-op.
+% This is a hack to get around the absurd habit of MS-DOS editors
+% of adding an EOF character at the end of the file.
+<1a> cvn { } def
+
+% Acquire the debugging flags.
+currentdict /DEBUG known /DEBUG exch def
+ /VMDEBUG
+ DEBUG {{print mark
+ systemdict /level2dict known
+ { .currentglobal dup false .setglobal vmstatus
+ true .setglobal vmstatus 3 -1 roll pop
+ 6 -2 roll pop .setglobal
+ }
+ { vmstatus 3 -1 roll pop
+ }
+ ifelse usertime 16#fffff and counttomark
+ { ( ) print ( ) cvs print }
+ repeat pop
+ ( ) print systemdict length ( ) cvs print
+ ( ) print countdictstack ( ) cvs print
+ ( <) print count ( ) cvs print (>\n) print flush
+ }}
+ {{pop
+ }}
+ ifelse
+ def
+
+currentdict /BATCH known /BATCH exch def
+currentdict /DELAYBIND known /DELAYBIND exch def
+currentdict /DISKFONTS known /DISKFONTS exch def
+currentdict /ESTACKPRINT known /ESTACKPRINT exch def
+currentdict /FAKEFONTS known /FAKEFONTS exch def
+currentdict /FIXEDMEDIA known /FIXEDMEDIA exch def
+currentdict /FIXEDRESOLUTION known /FIXEDRESOLUTION exch def
+currentdict /LOCALFONTS known /LOCALFONTS exch def
+currentdict /NOBIND known /NOBIND exch def
+/.bind /bind load def
+NOBIND { /bind { } def } if
+currentdict /NOCACHE known /NOCACHE exch def
+currentdict /NOCIE known /NOCIE exch def
+currentdict /NODISPLAY known not /DISPLAYING exch def
+currentdict /NOFONTMAP known /NOFONTMAP exch def
+currentdict /NOFONTPATH known /NOFONTPATH exch def
+currentdict /NOGC known /NOGC exch def
+currentdict /NOPAUSE known /NOPAUSE exch def
+currentdict /NOPLATFONTS known /NOPLATFONTS exch def
+currentdict /NOPROMPT known /NOPROMPT exch def
+% The default value of ORIENT1 is true, not false.
+currentdict /ORIENT1 known not { /ORIENT1 true def } if
+currentdict /OSTACKPRINT known /OSTACKPRINT exch def
+currentdict /OUTPUTFILE known % obsolete
+ { /OutputFile /OUTPUTFILE load def
+ currentdict /OUTPUTFILE .undef
+ } if
+currentdict /QUIET known /QUIET exch def
+currentdict /SAFER known /SAFER exch def
+currentdict /SHORTERRORS known /SHORTERRORS exch def
+currentdict /WRITESYSTEMDICT known /WRITESYSTEMDICT exch def
+
+% Acquire environment variables.
+currentdict /DEVICE known not
+ { (GS_DEVICE) getenv { /DEVICE exch def } if } if
+
+(START) VMDEBUG
+
+% Open the standard files, so they will be open at the outermost save level.
+(%stdin) (r) file pop
+(%stdout) (w) file pop
+(%stderr) (w) file pop
+
+% Define a procedure for skipping over an unneeded section of code.
+% This avoids allocating space for the skipped procedures.
+% We can't use readline, because that imposes a line length limit.
+/.skipeof % <string> .skipeof -
+ { currentfile exch 1 exch .subfiledecode flushfile
+ } bind def
+
+% If we're delaying binding, remember everything that needs to be bound later.
+DELAYBIND NOBIND not and
+ { .currentglobal false .setglobal
+ userdict /.delaybind 1500 array put
+ .setglobal
+ userdict /.delaycount 0 put
+ % When we've done the delayed bind, we want to stop saving.
+ % Detect this by the disappearance of .delaybind.
+ /bind
+ { userdict /.delaybind .knownget
+ { .delaycount 2 index put
+ userdict /.delaycount .delaycount 1 add put
+ }
+ { .bind
+ }
+ ifelse
+ } bind def
+ } if
+
+% Define procedures to assist users who don't read the documentation.
+userdict begin
+/help
+ { (Enter PostScript commands. '(filename) run' runs a file, 'quit' exits.\n)
+ print flush
+ } bind def
+/? /help load def
+end
+
+% Define =string, which is used by some PostScript programs even though
+% it isn't documented anywhere.
+% Put it in userdict so that each context can have its own copy.
+userdict /=string 256 string put
+
+% Print the greeting.
+
+/printgreeting
+ { mark
+ product (Ghostscript) search
+ { pop pop pop
+ (This software comes with NO WARRANTY: see the file PUBLIC for details.\n)
+ }
+ { pop
+ }
+ ifelse
+ (\n) copyright
+ (\)\n) revisiondate 100 mod (-)
+ revisiondate 100 idiv 100 mod (-)
+ revisiondate 10000 idiv ( \()
+ revision 10 mod
+ revision 100 mod dup 0 ne { 10 idiv } { pop } ifelse (.)
+ revision 100 idiv ( )
+ product
+ counttomark
+ { (%stdout) (w) file exch false .writecvp
+ } repeat pop
+ } bind def
+
+QUIET not { printgreeting flush } if
+
+% Define a special version of def for making operator procedures.
+/odef % <name> <proc> odef -
+ { 1 index exch .makeoperator def
+ } .bind def
+
+%**************** BACKWARD COMPATIBILITY
+/getdeviceprops
+ { null .getdeviceparams
+ } bind odef
+/.putdeviceprops
+ { null true counttomark 1 add 3 roll .putdeviceparams
+ dup type /booleantype ne
+ { dup mark eq { /unknown /rangecheck } if
+ counttomark 4 add 1 roll cleartomark pop pop pop
+ /.putdeviceprops load exch signalerror
+ }
+ if
+ } bind odef
+/max { .max } bind def
+/min { .min } bind def
+/.currentfilladjust { .currentfilladjust2 pop } bind odef
+/.setfilladjust { dup .setfilladjust2 } bind odef
+/.writecvs { false .writecvp } bind odef
+
+% Define predefined procedures substituting for operators,
+% in alphabetical order.
+
+userdict /#copies 1 put
+% Adobe implementations don't accept /[ or /], so we don't either.
+([) cvn
+ /mark load def
+(]) cvn
+ {counttomark array astore exch pop} odef
+/abs {dup 0 lt {neg} if} odef
+% .beginpage is redefined if setpagedevice is present.
+/.beginpage { } odef
+/copypage
+ { 1 .endpage
+ { .currentnumcopies false .outputpage
+ (>>copypage, press <return> to continue<<\n) .confirm
+ }
+ if .beginpage
+ } odef
+/countexecstack { false .countexecstack } odef
+% .currentnumcopies is redefined in Level 2.
+/.currentnumcopies { #copies } odef
+/setcolorscreen where { pop % not in all Level 1 configurations
+ /currentcolorscreen
+ { .currenthalftone
+ { { 60 exch 0 exch 3 copy 6 copy } % halftone - not possible
+ { 3 copy 6 copy } % screen
+ { } % colorscreen
+ }
+ exch get exec
+ } odef
+} if
+/currentscreen
+ { .currenthalftone
+ { { 60 exch 0 exch } % halftone - not possible
+ { } % screen
+ { 12 3 roll 9 { pop } repeat } % colorscreen
+ }
+ exch get exec
+ } odef
+/.echo /echo load def
+userdict /.echo.mode true put
+/echo {dup /.echo.mode exch store .echo} odef
+/eexec
+ { 55665 //filterdict /eexecDecode get exec
+ cvx //systemdict begin exec
+ % Only pop systemdict if it is still the top element,
+ % because this is apparently what Adobe interpreters do.
+ currentdict //systemdict eq { end } if
+ } odef
+% .endpage is redefined if setpagedevice is present.
+/.endpage { 2 ne } odef
+% erasepage mustn't use gsave/grestore, because we call it before
+% the graphics state stack has been fully initialized.
+/erasepage
+ { /currentcolor where
+ { pop currentcolor currentcolorspace { setcolorspace setcolor } }
+ { /currentcmykcolor where
+ { pop currentcmykcolor { setcmykcolor } }
+ { currentrgbcolor { setrgbcolor } }
+ ifelse
+ }
+ ifelse 1 setgray .fillpage exec
+ } odef
+/execstack { false .execstack } odef
+/executive
+ { { prompt
+ { (%statementedit) (r) file } stopped
+ { pop pop $error /errorname get /undefinedfilename eq
+ { .clearerror exit } if % EOF
+ handleerror null % ioerror??
+ }
+ if
+ cvx { .runexec } execute
+ } loop
+ } odef
+/filter
+ { //filterdict 1 index .knownget
+ { exch pop exec }
+ { /filter load /undefined signalerror }
+ ifelse
+ } odef
+/handleerror
+ { //systemdict /errordict get /handleerror get exec } bind def
+/identmatrix [1.0 0.0 0.0 1.0 0.0 0.0] readonly def
+/identmatrix
+ { dup 0 //identmatrix putinterval } odef
+/languagelevel 1 def % gs_lev2.ps may change this
+/makeimagedevice { false makewordimagedevice } odef
+/matrix { 6 array identmatrix } odef
+/pathbbox
+ { false .pathbbox
+ } odef
+/prompt { flush flushpage
+ (GS) print
+ count 0 ne { (<) print count =only } if
+ (>) print flush
+ } bind def
+/pstack { 0 1 count 3 sub { index == } for } bind def
+/putdeviceprops
+ { .putdeviceprops { erasepage } if } odef
+/quit { /quit load 0 .quit } odef
+/run { dup type /filetype ne { (r) file } if
+ % We must close the file when execution terminates,
+ % regardless of the state of the stack,
+ % and then propagate an error, if any.
+ cvx .runexec
+ } odef
+% Execute a file.
+% Level 2 uses 2 .stop to clear the e-stack for a successful startjob:
+% we detect that here, since we need to handle this even if we start out
+% without job control in effect.
+%
+% What we push on the e-stack is the following to be executed in this order:
+% <lit-file|fileproc> .runexec1 <lit-file|fileproc> .runexec2
+/.runexec1 { % <file|fileproc> .runexec1 -
+ dup type /filetype ne { cvx exec } if
+ cvx null 2 .stopped
+ % If we got back here from a startjob, just keep going.
+ % startjob replaces the null on the o-stack with a procedure
+ % to be executed when we get back here.
+ dup null ne { exec true } { pop false } ifelse
+} bind def
+/.runexec2 { % <continue> <file|fileproc> .runexec2 -
+ exch {
+ .runexec
+ } {
+ dup type /filetype ne { cvx exec } if
+ closefile
+ } ifelse
+} bind def
+/.runexec { % <file|fileproc> .runexec -
+ cvlit /.runexec1 cvx 1 index /.runexec2 cvx 4 .execn
+} bind def
+% The following is only for compatibility with Adobe interpreters.
+/setdash {
+ 1 index length 11 gt { /setdash load /limitcheck signalerror } if
+ //setdash
+} odef
+/setdevice
+ { .setdevice { erasepage } if } odef
+/setlinecap {
+ dup 2 gt { /setlinecap load /rangecheck signalerror } if
+ .setlinecap
+} odef
+/setlinejoin {
+ dup 2 gt { /setlinejoin load /rangecheck signalerror } if
+ .setlinejoin
+} odef
+/showpage
+ { 0 .endpage .doneshowpage
+ { .currentnumcopies true .outputpage
+ (>>showpage, press <return> to continue<<\n) .confirm
+ erasepage
+ }
+ if initgraphics .beginpage
+ } odef
+% Code output by Adobe Illustrator relies on the fact that
+% `stack' is a procedure, not an operator!!!
+/stack { 0 1 count 3 sub { index = } for } bind def
+/start { BATCH { null 0 .quit } { executive } ifelse } def
+% Internal uses of stopped that aren't going to do a stop if an error occurs
+% should use .internalstopped to avoid setting newerror et al.
+/.internalstopped { null 1 .stopped null ne } bind def
+/store { % Don't alter operands before completing.
+ 1 index where { 2 index 2 index put pop pop } { def } ifelse
+ } odef
+% When running in Level 1 mode, this interpreter is supposed to be
+% compatible with PostScript "version" 54.0 (I think).
+/version (54.0) def
+
+% internaldict is defined in systemdict, but is allocated in local VM.
+systemdict /internaldict .knownget not { 0 } if type /operatortype ne
+ { .currentglobal false .setglobal
+ //systemdict /internaldict known not { /internaldict 5 dict def } if
+ /internaldict
+ [ /dup load 1183615869 /eq load
+ [ /pop load internaldict ] cvx
+ [ /internaldict /cvx load /invalidaccess /signalerror cvx ] cvx
+ /ifelse load
+ ] cvx bind odef
+ .setglobal
+ } if
+
+% Define some additional built-in procedures (beyond the ones defined by
+% the PostScript Language Reference Manual).
+% Warning: these are not guaranteed to stay the same from one release
+% to the next!
+/concatstrings
+ { exch dup length 2 index length add string % str2 str1 new
+ dup dup 4 2 roll copy % str2 new new new1
+ length 4 -1 roll putinterval
+ } bind def
+/copyarray
+ { dup length array copy } bind def
+% Copy a dictionary per the Level 2 spec even in Level 1.
+/.copydict % <fromdict> <todict> .copydict <todict>
+ { dup 3 -1 roll { put dup } forall pop } bind def
+/copystring
+ { dup length string copy } bind def
+/finddevice
+ { //systemdict /devicedict get exch get
+ dup 1 get null eq
+ { % This is the first request for this type of device.
+ % Create a default instance now.
+ % Stack: [proto null]
+ .currentglobal true .setglobal exch
+ dup dup 0 get copydevice 1 exch put
+ exch .setglobal
+ }
+ if 1 get
+ } bind def
+/.growdictlength % get size for growing a dictionary
+ { length 3 mul 2 idiv 1 add
+ } bind def
+/.growdict % grow a dictionary
+ { dup .growdictlength .setmaxlength
+ } bind def
+/.growput % put, grow the dictionary if needed
+ { 2 index length 3 index maxlength eq
+ { 3 copy pop known not { 2 index .growdict } if
+ } if
+ put
+ } bind def
+/.packtomark
+ { counttomark packedarray exch pop } bind def
+/ppstack
+ { 0 1 count 3 sub { index === } for } bind def
+/runlibfile
+ { % We don't want to bind 'run' into this procedure,
+ % since run may get redefined.
+ findlibfile
+ { exch pop //systemdict /run get exec }
+ { /undefinedfilename signalerror }
+ ifelse
+ } bind def
+/selectdevice
+ { finddevice setdevice .setdefaultscreen } bind def
+/signalerror % <object> <errorname> signalerror -
+ { //systemdict /errordict get exch get exec } bind def
+
+% Define the =[only] procedures. Also define =print,
+% which is used by some PostScript programs even though
+% it isn't documented anywhere.
+/write=only {
+ .writecvs
+} bind def
+/write= {
+ 1 index exch write=only (\n) writestring
+} bind def
+/=only { (%stdout) (w) file exch write=only } bind def
+/= { =only (\n) print } bind def
+/=print /=only load def
+% Temporarily define == as = for the sake of runlibfile0.
+/== /= load def
+
+% Define procedures for getting and setting the current device resolution.
+
+/gsgetdeviceprop % <device> <propname> gsgetdeviceprop <value>
+ { 2 copy mark exch null .dicttomark .getdeviceparams
+ dup mark eq % if true, not found
+ { pop dup /undefined signalerror }
+ { 5 1 roll pop pop pop pop }
+ ifelse
+ } bind def
+/gscurrentresolution % - gscurrentresolution <[xres yres]>
+ { currentdevice /HWResolution gsgetdeviceprop
+ } bind def
+/gssetresolution % <[xres yres]> gssetresolution -
+ { 2 array astore mark exch /HWResolution exch
+ currentdevice copydevice putdeviceprops setdevice
+ } bind def
+
+% Define auxiliary procedures needed for the above.
+/shellarguments % -> shell_arguments true (or) false
+ { /ARGUMENTS where
+ { /ARGUMENTS get dup type /arraytype eq
+ { aload pop /ARGUMENTS null store true }
+ { pop false }
+ ifelse }
+ { false } ifelse
+ } bind def
+/.confirm
+ { DISPLAYING NOPAUSE not and
+ { % Print a message (unless NOPROMPT is true)
+ % and wait for the user to type something.
+ % If the user just types a newline, flush it.
+ NOPROMPT { pop } { print flush } ifelse
+ .echo.mode false echo
+ (%stdin) (r) file dup read
+ { dup (\n) 0 get eq { pop pop } { unread } ifelse }
+ { pop }
+ ifelse echo
+ }
+ { pop
+ }
+ ifelse
+ } bind def
+
+% Define the procedure used by .runfile, .runstdin and .runstring
+% for executing user input.
+% This is called with a procedure or executable file on the operand stack.
+/.execute { % <obj> .execute <stopped>
+ stopped $error /newerror get and
+ { handleerror flush true } { false } ifelse
+} bind def
+/execute { % <obj> execute -
+ .execute pop
+} odef
+% Define an execute analogue of runlibfile0.
+/execute0 { % <obj> execute0 -
+ .execute { /execute0 cvx 1 .quit } if
+} bind def
+% Define the procedure that the C code uses for running files
+% named on the command line.
+/.runfile {
+ { runlibfile } execute
+} def
+% Define the procedure that the C code uses for running piped input.
+% We don't use the obvious { (%stdin) run }, because we want the file to be
+% reopened if a startjob does a restore.
+/.runstdin {
+ { { (%stdin) (r) file cvx } .runexec } execute0
+} bind def
+% Define the procedure that the C code uses for running commands
+% given on the command line with -c. We turn the string into a file so that
+% .runexec can do the right thing with a startjob.
+/.runstring {
+ .currentglobal exch true .setglobal
+ 0 () .subfiledecode
+ exch .setglobal cvx { .runexec } execute
+} bind def
+% Define the procedure that the C code uses to set up for executing
+% a string that may be received in pieces.
+/.runstringbegin {
+ .currentglobal true .setglobal
+ { .needinput } bind 0 () .subfiledecode
+ exch .setglobal cvx .runexec
+} bind def
+
+% Define a special version of runlibfile that aborts on errors.
+/runlibfile0
+ { cvlit dup /.currentfilename exch def
+ { findlibfile not { stop } if }
+ stopped
+ { (Can't find \(or open\) initialization file ) print
+ .currentfilename == flush /runlibfile0 cvx 1 .quit
+ } if
+ exch pop cvx stopped
+ { (While reading ) print .currentfilename print (:\n) print flush
+ handleerror /runlibfile0 1 .quit
+ } if
+ } bind def
+% Temporarily substitute it for the real runlibfile.
+/.runlibfile /runlibfile load def
+/runlibfile /runlibfile0 load def
+
+% Create the error handling machinery.
+% Define the standard error handlers.
+% The interpreter has created the ErrorNames array.
+/.unstoppederrorhandler % <command> <errorname> .unstoppederrorhandler -
+ { % This is the handler that gets used for recursive errors,
+ % or errors outside the scope of a 'stopped'.
+ 2 copy SHORTERRORS
+ { (%%[ Error: ) print =only flush
+ (; OffendingCommand: ) print =only ( ]%%\n) print
+ }
+ { (Unrecoverable error: ) print =only flush
+ ( in ) print = flush
+ count 2 gt
+ { (Operand stack:\n ) print
+ 2 1 count 3 sub { ( ) print index =only flush } for
+ (\n) print flush
+ } if
+ }
+ ifelse
+ -1 0 1 //ErrorNames length 1 sub
+ { dup //ErrorNames exch get 3 index eq
+ { not exch pop exit } { pop } ifelse
+ }
+ for exch pop .quit
+ } bind def
+/.errorhandler % <command> <errorname> .errorhandler -
+ { % Detect an internal 'stopped'.
+ 1 .instopped { null eq { pop pop stop } if } if
+ $error /.inerror get 1 .instopped { pop } { pop true } ifelse
+ { .unstoppederrorhandler
+ } if % detect error recursion
+ $error /globalmode .currentglobal false .setglobal put
+ $error /.inerror true put
+ $error /newerror true put
+ $error exch /errorname exch put
+ $error exch /command exch put
+ $error /recordstacks get $error /errorname get /VMerror ne and
+ { % Attempt to store the stack contents atomically.
+ count array astore dup $error /ostack 4 -1 roll
+ countexecstack array execstack $error /estack 3 -1 roll
+ countdictstack array dictstack $error /dstack 3 -1 roll
+ put put put aload pop
+ }
+ { $error /dstack .undef
+ $error /estack .undef
+ $error /ostack .undef
+ }
+ ifelse
+ $error /position currentfile status
+ { currentfile { fileposition } .internalstopped { pop null } if
+ }
+ { % If this was a scanner error, the file is no longer current,
+ % but the command holds the file, which may still be open.
+ $error /command get dup type /filetype eq
+ { { fileposition } .internalstopped { pop null } if }
+ { pop null }
+ ifelse
+ }
+ ifelse put
+ % During initialization, we don't reset the allocation
+ % mode on errors.
+ $error /globalmode get $error /.nosetlocal get and .setglobal
+ $error /.inerror false put
+ stop
+ } bind def
+% Define the standard handleerror. We break out the printing procedure
+% (.printerror) so that it can be extended for binary output
+% if the Level 2 facilities are present.
+ /.printerror
+ { $error begin
+ /command load errorname SHORTERRORS
+ { (%%[ Error: ) print =only flush
+ (; OffendingCommand: ) print =only
+ currentdict /errorinfo .knownget
+ { (;\nErrorInfo:) print
+ dup type /arraytype eq
+ { { ( ) print =only } forall }
+ { ( ) print =only }
+ ifelse
+ } if
+ ( ]%%\n) print flush
+ }
+ { (Error: ) print ==only flush
+ ( in ) print ==only flush
+ currentdict /errorinfo .knownget
+ { (\nAdditional information: ) print ==only flush
+ } if
+ .printerror_long
+ }
+ ifelse
+ .clearerror
+ end
+ flush
+ } bind def
+ /.printerror_long % long error printout,
+ % $error is on the dict stack
+ { % Push the (anonymous) stack printing procedure.
+ % <heading> <==flag> <override-name> <stackname> proc
+ {
+ currentdict exch .knownget % stackname defined in $error?
+ {
+ 4 1 roll % stack: <stack> <head> <==flag> <over>
+ errordict exch .knownget % overridename defined?
+ {
+ exch pop exch pop exec % call override with <stack>
+ }
+ {
+ exch print exch % print heading. stack <==flag> <stack>
+ 1 index not { (\n) print } if
+ { 1 index { (\n ) } { ( ) } ifelse print
+ dup type /dicttype eq
+ {
+ (--dict:) print
+ dup rcheck
+ { dup length =only (/) print maxlength =only }
+ { pop }
+ ifelse
+ (--) print
+ }
+ {
+ dup type /stringtype eq 2 index or
+ { ===only } { =only } ifelse
+ } ifelse
+ } forall
+ pop
+ }
+ ifelse % overridden
+ }
+ { pop pop pop
+ }
+ ifelse % stack known
+ }
+
+ (\nOperand stack:) OSTACKPRINT /.printostack /ostack 4 index exec
+ (\nExecution stack:) ESTACKPRINT /.printestack /estack 4 index exec
+ (\nBacktrace:) true /.printbacktrace /backtrace 4 index exec
+ (\nDictionary stack:) false /.printdstack /dstack 4 index exec
+ (\n) print
+ pop % printing procedure
+
+ errorname /VMerror eq
+ { (VM status:) print mark vmstatus
+ counttomark { ( ) print counttomark -1 roll dup =only } repeat
+ cleartomark (\n) print
+ } if
+
+ .languagelevel 2 ge
+ { (Current allocation mode is ) print
+ globalmode { (global\n) } { (local\n) } ifelse print
+ } if
+
+ .oserrno dup 0 ne
+ { (Last OS error: ) print
+ errorname /VMerror ne
+ { dup .oserrorstring { = pop } { = } ifelse }
+ { = }
+ ifelse
+ }
+ { pop
+ }
+ ifelse
+
+ position null ne
+ { (Current file position is ) print position = }
+ if
+
+ } bind def
+% Define a procedure for clearing the error indication.
+/.clearerror
+ { $error /newerror false put
+ $error /errorname null put
+ $error /errorinfo .undef
+ 0 .setoserrno
+ } bind def
+
+% Define $error. This must be in local VM.
+.currentglobal false .setglobal
+/$error 40 dict def % newerror, errorname, command, errorinfo,
+ % ostack, estack, dstack, recordstacks,
+ % binary, globalmode,
+ % .inerror, .nosetlocal, position,
+ % plus extra space for badly designed error handers.
+$error begin
+ /newerror false def
+ /recordstacks true def
+ /binary false def
+ /globalmode .currentglobal def
+ /.inerror false def
+ /.nosetlocal true def
+ /position null def
+end
+% Define errordict similarly. It has one entry per error name,
+% plus handleerror.
+/errordict ErrorNames length 1 add dict def
+.setglobal % contents of errordict are global
+errordict begin
+ ErrorNames
+ { mark 1 index systemdict /.errorhandler get /exec load .packtomark cvx def
+ } forall
+% The handlers for interrupt and timeout are special; there is no
+% 'current object', so they push their own name.
+ { /interrupt /timeout }
+ { mark 1 index dup systemdict /.errorhandler get /exec load .packtomark cvx def
+ } forall
+/handleerror
+ { //systemdict /.printerror get exec
+ } bind def
+end
+
+% Define the [write]==[only] procedures.
+/.dict 26 dict dup
+begin def
+ /.cvp {1 index exch .writecvs} bind def
+ /.nop {exch pop .p} bind def
+ /.p {1 index exch writestring} bind def
+ /.p1 {2 index exch writestring} bind def
+ /.p2 {3 index exch writestring} bind def
+ /.print
+ { dup type .dict exch .knownget
+ { dup type /stringtype eq { .nop } { exec } ifelse }
+ { (-) .p1 type .cvp (-) .p }
+ ifelse
+ } bind def
+ /.pstring
+ { { dup dup 32 lt exch 127 ge or
+ { (\\) .p1 2 copy -6 bitshift 48 add write
+ 2 copy -3 bitshift 7 and 48 add write
+ 7 and 48 add
+ }
+ { dup dup -2 and 40 eq exch 92 eq or {(\\) .p1} if
+ }
+ ifelse 1 index exch write
+ }
+ forall
+ } bind def
+ /booleantype /.cvp load def
+ /conditiontype (-condition-) def
+ /devicetype (-device-) def
+ /dicttype (-dict-) def
+ /filetype (-file-) def
+ /fonttype (-fontID-) def
+ /gstatetype (-gstate-) def
+ /integertype /.cvp load def
+ /locktype (-lock-) def
+ /marktype (-mark-) def
+ /nulltype (null) def
+ /realtype {1 index exch true .writecvp} bind def
+ /savetype (-save-) def
+ /nametype
+ {dup xcheck not {(/) .p1} if
+ 1 index exch .writecvs} bind def
+ /arraytype
+ {dup rcheck
+ {() exch dup xcheck
+ {({) .p2
+ {exch .p1
+ 1 index exch .print pop ( )} forall
+ (})}
+ {([) .p2
+ {exch .p1
+ 1 index exch .print pop ( )} forall
+ (])}
+ ifelse exch pop .p}
+ {(-array-) .nop}
+ ifelse} bind def
+ /operatortype
+ {(--) .p1 .cvp (--) .p} bind def
+ /packedarraytype
+ { dup rcheck
+ { arraytype }
+ { (-packedarray-) .nop }
+ ifelse
+ } bind def
+ /stringtype
+ { dup rcheck
+ { (\() .p1 dup length 200 le
+ { .pstring }
+ { 0 200 getinterval .pstring (...) .p }
+ ifelse (\)) .p
+ }
+ { (-string-) .nop
+ }
+ ifelse
+ } bind def
+{//.dict begin .print pop end}
+ bind
+end
+
+/write==only exch def
+/write== {1 index exch write==only (\n) writestring} bind def
+/==only { (%stdout) (w) file exch write==only } bind def
+/== {==only (\n) print} bind def
+
+% Define [write]===[only], an extension that prints dictionaries
+% in readable form and doesn't truncate strings.
+/.dict /write==only load 0 get dup length dict .copydict dup
+begin def
+ /dicttype
+ { dup rcheck
+ { (<< ) .p1
+ { 2 index 3 -1 roll .print pop ( ) .p1
+ 1 index exch .print pop ( ) .p
+ }
+ forall (>>) .p
+ }
+ { (-dict-) .nop
+ }
+ ifelse
+ } bind def
+ /stringtype
+ { dup rcheck
+ { (\() .p1 .pstring (\)) .p }
+ { (-string-) .nop }
+ ifelse
+ } bind def
+
+{//.dict begin .print pop end}
+ bind
+end
+
+/write===only exch def
+/write=== {1 index exch write===only (\n) writestring} bind def
+/===only { (%stdout) (w) file exch write===only } bind def
+/=== { ===only (\n) print } bind def
+
+(END PROCS) VMDEBUG
+
+% Define the font directory.
+/FontDirectory false .setglobal 100 dict true .setglobal def
+
+% Define the encoding dictionary.
+/EncodingDirectory 10 dict def % enough for Level 2 + PDF standard encodings
+
+% Define .findencoding. (This is redefined in Level 2.)
+/.findencoding
+ { //EncodingDirectory exch get exec
+ } bind def
+/.defineencoding
+ { //EncodingDirectory 3 1 roll put
+ } bind def
+% If we've got the composite font extensions, define findencoding.
+/rootfont where { pop /findencoding { .findencoding } odef } if
+
+% Load StandardEncoding.
+%% Replace 1 (gs_std_e.ps)
+(gs_std_e.ps) dup runlibfile VMDEBUG
+
+% Load ISOLatin1Encoding.
+%% Replace 1 (gs_iso_e.ps)
+(gs_iso_e.ps) dup runlibfile VMDEBUG
+
+% Define stubs for the Symbol and Dingbats encodings.
+% Note that the first element of the procedure must be the file name,
+% since gs_lev2.ps extracts it to set up the Encoding resource category.
+
+ /SymbolEncoding { /SymbolEncoding .findencoding } bind def
+%% Replace 3 (gs_sym_e.ps)
+ EncodingDirectory /SymbolEncoding
+ { (gs_sym_e.ps) //systemdict begin runlibfile SymbolEncoding end }
+ bind put
+
+ /DingbatsEncoding { /DingbatsEncoding .findencoding } bind def
+%% Replace 3 (gs_dbt_e.ps)
+ EncodingDirectory /DingbatsEncoding
+ { (gs_dbt_e.ps) //systemdict begin runlibfile DingbatsEncoding end }
+ bind put
+
+(END FONTDIR/ENCS) VMDEBUG
+
+% Construct a dictionary of all available devices.
+% These are (read-only) device prototypes that can't be
+% installed or have their parameters changed. For this reason,
+% the value in the dictionary is actually a 2-element writable array,
+% to allow us to create a default instance of the prototype on demand.
+
+ % Loop until the .getdevice gets a rangecheck.
+errordict /rangecheck 2 copy get
+errordict /rangecheck { pop stop } put % pop the command
+ 0 { {dup .getdevice exch 1 add} loop} .internalstopped pop
+ 1 add dict /devicedict 1 index def
+ begin % 2nd copy of count is on stack
+ { dup .devicename exch
+ dup wcheck { dup } { null } ifelse 2 array astore def
+ } repeat
+ end
+put % errordict /rangecheck
+.clearerror
+/devicenames devicedict { pop } forall devicedict length packedarray def
+
+% Determine the default device.
+/defaultdevice DISPLAYING
+ { systemdict /DEVICE .knownget
+ { devicedict 1 index known not
+ { (Unknown device: ) print =
+ flush /defaultdevice cvx 1 .quit
+ }
+ if
+ }
+ { 0 .getdevice .devicename
+ }
+ ifelse
+ }
+ { /nullpage
+ }
+ifelse
+/.defaultdevicename 1 index def
+finddevice % make a copy
+def
+devicedict /Default devicedict .defaultdevicename get put
+
+(END DEVS) VMDEBUG
+
+% Define statusdict, for the benefit of programs
+% that think they are running on a LaserWriter or similar printer.
+%% Replace 1 (gs_statd.ps)
+(gs_statd.ps) runlibfile
+
+(END STATD) VMDEBUG
+
+% Load the standard font environment.
+%% Replace 1 (gs_fonts.ps)
+(gs_fonts.ps) runlibfile
+
+(END GS_FONTS) VMDEBUG
+
+% Load the initialization files for optional features.
+%% Replace 4 INITFILES
+systemdict /INITFILES known
+ { INITFILES { dup runlibfile VMDEBUG } forall
+ }
+if
+
+% If Level 2 functionality is implemented, enable it now.
+/.setlanguagelevel where
+ { pop 2 .setlanguagelevel
+ % If the resource machinery is loaded, fix up some things now.
+ /.fixresources where { pop .fixresources } if
+ } if
+
+(END INITFILES) VMDEBUG
+
+% Create a null font. This is the initial font.
+8 dict dup begin
+ /FontMatrix [ 1 0 0 1 0 0 ] readonly def
+ /FontType 3 def
+ /FontName () def
+ /Encoding StandardEncoding def
+ /FontBBox { 0 0 0 0 } readonly def % executable is bogus, but customary ...
+ /BuildChar { pop pop 0 0 setcharwidth } bind def
+ /PaintType 0 def % shouldn't be needed!
+end
+/NullFont exch definefont setfont
+
+% Define NullFont as the font.
+/NullFont currentfont def
+
+% Load initial fonts from FONTPATH directories, Fontmap file,
+% and/or .getccfont as appropriate.
+.loadinitialfonts
+
+% Remove NullFont from FontDirectory, so it can't be accessed by mistake.
+FontDirectory /NullFont .undef
+
+(END FONTS) VMDEBUG
+
+% Restore the real definition of runlibfile.
+/runlibfile /.runlibfile load def
+currentdict /.runlibfile .undef
+
+% Bind all the operators defined as procedures.
+/.bindoperators % binds operators in currentdict
+ { % Temporarily disable the typecheck error.
+ errordict /typecheck 2 copy get
+ errordict /typecheck { pop } put % pop the command
+ currentdict
+ { dup type /operatortype eq
+ { % This might be a real operator, so bind might cause a typecheck,
+ % but we've made the error a no-op temporarily.
+ .bind % do a real bind even if NOBIND is set
+ }
+ if pop pop
+ } forall
+ put
+ } def
+NOBIND DELAYBIND or not { .bindoperators } if
+
+% Establish a default environment.
+
+defaultdevice
+DISPLAYING not { setdevice (%END DISPLAYING) .skipeof } if
+systemdict /DEVICEWIDTH known
+systemdict /DEVICEHEIGHT known or
+systemdict /DEVICEWIDTHPOINTS known or
+systemdict /DEVICEHEIGHTPOINTS known or
+systemdict /DEVICEXRESOLUTION known or
+systemdict /DEVICEYRESOLUTION known or
+systemdict /PAPERSIZE known or
+not { (%END DEVICE) .skipeof } if
+% Let DEVICE{WIDTH,HEIGHT}[POINTS] override PAPERSIZE.
+systemdict /PAPERSIZE known
+systemdict /DEVICEWIDTH known not and
+systemdict /DEVICEHEIGHT known not and
+systemdict /DEVICEWIDTHPOINTS known not and
+systemdict /DEVICEHEIGHTPOINTS known not and
+ { % Convert the paper size to device dimensions.
+ true statusdict /.pagetypenames get
+ { PAPERSIZE eq
+ { PAPERSIZE load
+ dup 0 get /DEVICEWIDTHPOINTS exch def
+ 1 get /DEVICEHEIGHTPOINTS exch def
+ pop false exit
+ }
+ if
+ }
+ forall
+ { (Unknown paper size: ) print PAPERSIZE ==only (.\n) print
+ }
+ if
+ }
+if
+% Adjust the device parameters per the command line.
+% It is possible to specify resolution, pixel size, and page size;
+% since any two of these determine the third, conflicts are possible.
+% We simply pass them to .setdeviceparams and let it sort things out.
+ mark /HWResolution null /HWSize null /PageSize null .dicttomark
+ .getdeviceparams .dicttomark begin
+ mark
+ % Check for resolution.
+ /DEVICEXRESOLUTION where dup
+ { exch pop HWResolution 0 DEVICEXRESOLUTION put }
+ if
+ /DEVICEYRESOLUTION where dup
+ { exch pop HWResolution 1 DEVICEYRESOLUTION put }
+ if
+ or { /HWResolution HWResolution } if
+ % Check for device sizes specified in pixels.
+ /DEVICEWIDTH where dup
+ { exch pop HWSize 0 DEVICEWIDTH put }
+ if
+ /DEVICEHEIGHT where dup
+ { exch pop HWSize 1 DEVICEHEIGHT put }
+ if
+ or { /HWSize HWSize } if
+ % Check for device sizes specified in points.
+ /DEVICEWIDTHPOINTS where dup
+ { exch pop PageSize 0 DEVICEWIDTHPOINTS put }
+ if
+ /DEVICEHEIGHTPOINTS where dup
+ { exch pop PageSize 1 DEVICEHEIGHTPOINTS put }
+ if
+ or { /PageSize PageSize } if
+ % Check whether any parameters were set.
+ dup mark eq { pop } { defaultdevice putdeviceprops } ifelse
+ end
+%END DEVICE
+% Set any device properties defined on the command line.
+% If BufferSpace is defined but not MaxBitmap, set MaxBitmap to BufferSpace.
+systemdict /BufferSpace known
+systemdict /MaxBitmap known not and
+ { systemdict /MaxBitmap BufferSpace put
+ } if
+dup getdeviceprops
+counttomark 2 idiv
+ { systemdict 2 index known
+ { pop dup load counttomark 2 roll }
+ { pop pop }
+ ifelse
+ } repeat
+counttomark dup 0 ne
+ { 2 add -1 roll putdeviceprops }
+ { pop pop }
+ifelse
+setdevice % does an erasepage
+% If the media size is fixed, update the current page device dictionary.
+FIXEDMEDIA
+dup { pop systemdict /.currentpagedevice known } if
+dup { pop .currentpagedevice exch pop } if
+not { (%END MEDIA) .skipeof } if
+currentpagedevice dup length dict .copydict
+dup /Policies
+ % Stack: <pagedevice> <pagedevice> /Policies
+1 index /InputAttributes
+2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <pagedevice>
+ % /InputAttributes <inputattrs'>
+dup 0 2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <pagedevice>
+ % /InputAttributes <inputattrs'> <inputattrs'> 0 <attrs0'>
+dup /PageSize 7 index /PageSize get
+put % PageSize in 0
+put % 0 in InputAttributes
+put % InputAttributes in pagedevice
+% Also change the page size policy so we don't get an error.
+ % Stack: <pagedevice> <pagedevice> /Policies
+2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <policies'>
+dup /PageSize 7 put % PageSize in Policies
+put % Policies in pagedevice
+.setpagedevice
+%END MEDIA
+%END DISPLAYING
+
+(END DEVICE) VMDEBUG
+
+% Establish a default upper limit in the character cache,
+% namely, enough room for a 18-point character at the resolution
+% of the default device, or for a character consuming 1% of the
+% maximum cache size, whichever is larger.
+mark
+ % Compute limit based on character size.
+ 18 dup dtransform
+ exch abs cvi 31 add 32 idiv 4 mul % X raster
+ exch abs cvi mul % Y
+ % Compute limit based on allocated space.
+ cachestatus pop pop pop pop pop exch pop 0.01 mul cvi
+ .max dup 10 idiv exch
+setcacheparams
+% Conditionally disable the character cache.
+NOCACHE { 0 setcachelimit } if
+
+(END CONFIG) VMDEBUG
+
+% Establish an appropriate halftone screen and BG/UCR functions.
+% We make this a procedure so we can call it again when switching devices.
+
+% Use an ordered dither for low-resolution devices.
+/.setloresscreen % <dpi> .setloresscreen -
+ { % The following 'ordered dither' spot function was contributed by
+ % Gregg Townsend. Thanks, Gregg!
+ 16.001 div 0 % not 16: avoids rounding problems
+ { 1 add 7.9999 mul cvi exch 1 add 7.9999 mul cvi 16 mul add <
+ 0E 8E 2E AE 06 86 26 A6 0C 8C 2C AC 04 84 24 A4
+ CE 4E EE 6E C6 46 E6 66 CC 4C EC 6C C4 44 E4 64
+ 3E BE 1E 9E 36 B6 16 96 3C BC 1C 9C 34 B4 14 94
+ FE 7E DE 5E F6 76 D6 56 FC 7C DC 5C F4 74 D4 54
+ 01 81 21 A1 09 89 29 A9 03 83 23 A3 0B 8B 2B AB
+ C1 41 E1 61 C9 49 E9 69 C3 43 E3 63 CB 4B EB 6B
+ 31 B1 11 91 39 B9 19 99 33 B3 13 93 3B BB 1B 9B
+ F1 71 D1 51 F9 79 D9 59 F3 73 D3 53 FB 7B DB 5B
+ 0D 8D 2D AD 05 85 25 A5 0F 8F 2F AF 07 87 27 A7
+ CD 4D ED 6D C5 45 E5 65 CF 4F EF 6F C7 47 E7 67
+ 3D BD 1D 9D 35 B5 15 95 3F BF 1F 9F 37 B7 17 97
+ FD 7D DD 5D F5 75 D5 55 FF 7F DF 5F F7 77 D7 57
+ 02 82 22 A2 0A 8A 2A AA 00 80 20 A0 08 88 28 A8
+ C2 42 E2 62 CA 4A EA 6A C0 40 E0 60 C8 48 E8 68
+ 32 B2 12 92 3A BA 1A 9A 30 B0 10 90 38 B8 18 98
+ F2 72 D2 52 FA 7A DA 5A F0 70 D0 50 F8 78 D8 58
+ > exch get 256 div
+ }
+ bind
+ % Use correct, per-plane screens for CMYK devices only.
+ //systemdict /setcolorscreen known processcolors 4 eq and
+ { 3 copy 6 copy setcolorscreen }
+ { setscreen }
+ ifelse
+ 0 array cvx settransfer % Genoa CET won't accept a packed array!
+ /setstrokeadjust where { pop true setstrokeadjust } if
+ } bind def
+% Use a 45-degree spot screen for high-resolution devices.
+/.sethiresscreen % <dpi> .sethiresscreen -
+ { % According to information published by Hewlett-Packard,
+ % they use a 60 line screen on 300 DPI printers and
+ % an 85 line screen on 600 DPI printers.
+ % However, we use a 106 line screen, which produces smoother-
+ % looking shades but fewer of them (32 vs. 50).
+ % 46 was suggested as a good frequency value for printers
+ % between 200 and 400 DPI, so we use it for lower resolutions.
+ % Imagesetters need even higher frequency screens.
+ //systemdict /DITHERPPI known
+ { DITHERPPI
+ }
+ { dup cvi 100 idiv 15 .min
+ {null 46 46 60 60 60 106 106 106 106 133 133 133 133 133 150}
+ exch get
+ }
+ ifelse
+ 1 index 4.01 div .min % at least a 4x4 cell
+ 45
+ % The following screen algorithm is used by permission of the author.
+ { 1 add 180 mul cos 1 0.08 add mul exch 2 add 180 mul cos
+ 1 0.08 sub mul add 2 div % (C) 1989 Berthold K.P. Horn
+ }
+ bind
+ % Determine whether we have lots of process colors.
+ % If so, don't bother with color screening or gamma correction.
+ % Also don't do gamma correction on very high-resolution devices.
+ % (This should depend on dot gain, not resolution, but we don't
+ % currently have a way to determine this.)
+ currentdevice mark
+ /RedValues 0 /GreenValues 0 /BlueValues 0 /GrayValues 0
+ .dicttomark .getdeviceparams
+ counttomark 2 idiv 1 sub { exch pop min } repeat
+ exch pop exch pop 32 lt 4 index 800 lt and 5 1 roll
+ % Stack: doscreen dpi freq angle proc
+ % Ghostscript currently doesn't use correct, per-plane halftones
+ % unless setcolorscreen has been executed. Since these are
+ % computationally much more expensive than binary halftones,
+ % we check to make sure they are really warranted, i.e., we have
+ % a high-resolution CMYK device (i.e., not a display) with
+ % fewer than 5 bits per plane (i.e., not a true-color device).
+ 4 -1 roll 150 ge
+ { /setcolorscreen where
+ { pop //systemdict /COLORSCREEN known
+ { COLORSCREEN }
+ { 3 index }
+ ifelse
+ dup false ne
+ { 4 1 roll 3 copy 6 copy 13 -1 roll
+ % For really high-quality screening on printers, we need to
+ % give each plane its own screen angle. Unfortunately,
+ % this currently has very large space and time costs.
+ true eq % true => different angles,
+ % 0 => same angles
+ { { 45 90 15 75 } { 3 1 roll exch pop 12 3 roll } forall
+ }
+ if setcolorscreen
+ }
+ { pop setscreen % false => single binary screen
+ }
+ ifelse
+ }
+ { setscreen % setcolorscreen not known
+ }
+ ifelse
+ }
+ { setscreen % not high resolution
+ }
+ ifelse
+ % Stack: doscreen
+ { % Set the transfer function to lighten up the grays.
+ % We correct at the high end so that very light grays
+ % don't disappear completely if they darken <1 screen pixel.
+ % Parameter values closer to 1 are better for devices with
+ % less dot spreading; lower values are better with more spreading.
+ % The value 0.8 is a compromise that will probably please no one!
+ %
+ % Because of a bug in FrameMaker, we have to accept operands
+ % outside the valid range of [0..1].
+ { dup dup 0.0 gt exch 1.0 lt and
+ { 0.8 exp dup dup 0.9375 gt exch 0.999 lt and % > 15/16
+ { .currentscreenlevels 1 sub % tweak to avoid boundary
+ 1 exch div 1 exch sub .min
+ }
+ if
+ }
+ if
+ }
+ }
+ { % Set the transfer function to the identity.
+ 0 array cvx % Genoa CET won't accept a packed array!
+ }
+ ifelse settransfer
+ /setstrokeadjust where { pop false setstrokeadjust } if
+ % Increase fill adjustment so that we effectively use Adobe's
+ % any-part-of-pixel rule.
+ 0.5 .setfilladjust
+ } bind def
+% Set the default screen and BG/UCR based on the device resolution and
+% process color capability.
+/.setdefaultbgucr systemdict /setblackgeneration known { {
+ processcolors 1 eq { { } } { { pop 0.0 } } ifelse
+ dup setblackgeneration setundercolorremoval
+} } { {
+} } ifelse bind def
+/.setdefaultscreen
+ { % Compute min(|dpi x|,|dpi y|) as the definition of the resolution.
+ 72 72 matrix defaultmatrix dtransform abs exch abs .min
+ dup 150 lt //systemdict /DITHERPPI known not and
+ { .setloresscreen } { .sethiresscreen }
+ ifelse .setdefaultbgucr
+ } bind def
+.setdefaultscreen
+initgraphics
+
+% The interpreter relies on there being at least 2 entries
+% on the graphics stack. Establish the second one now.
+gsave
+
+% Define some control sequences as no-ops.
+% This is a hack to get around problems
+% in some common PostScript-generating applications.
+<04> cvn { } def % Apple job separator
+<0404> cvn { } def % two of the same
+<1b> cvn { } def % MS Windows LaserJet 4 prologue
+ % (UEL = ESC %-12345X)
+<1b45> cvn { } def % PJL reset prologue (ESC E)
+<1b451b> cvn { } def % PJL reset epilogue (ESC E + UEL)
+<041b> cvn { } def % MS Windows LaserJet 4 epilogue (^D + UEL)
+(\001M) cvn % TBCP initiator
+ { currentfile /TBCPDecode filter cvx exec
+ } bind def
+/@PJL % H-P job control
+ { currentfile //=string readline { pop } if
+ } bind def
+
+% If we want a "safer" system, disable some obvious ways to cause havoc.
+SAFER not { (%END SAFER) .skipeof } if
+/file
+ { dup (r) eq 2 index (%pipe*) .stringmatch not and
+ 2 index (%std*) .stringmatch or
+ { file }
+ { /invalidfileaccess signalerror }
+ ifelse
+ } .bind odef
+/renamefile { /invalidfileaccess signalerror } odef
+/deletefile { /invalidfileaccess signalerror } odef
+/putdeviceprops
+ { counttomark
+ dup 2 mod 0 eq { pop /rangecheck signalerror } if
+ 3 2 3 2 roll
+ { dup index /OutputFile eq
+ { -2 roll
+ dup () ne { /putdeviceprops load /invalidfileaccess signalerror } if
+ 3 -1 roll
+ }
+ { pop
+ }
+ ifelse
+ } for
+ putdeviceprops
+ } .bind odef
+
+%END SAFER
+
+% If we delayed binding, make it possible to do it later.
+/.bindnow
+ { //systemdict begin .bindoperators end
+ % Temporarily disable the typecheck error.
+ errordict /typecheck 2 copy get
+ errordict /typecheck { pop } put % pop the command
+ 0 1 .delaycount 1 sub { .delaybind exch get .bind pop } for
+ userdict /.delaybind .undef % reclaim the space
+ userdict /.delaycount .undef
+ put
+ } .bind def
+
+% Turn off array packing, since some PostScript code assumes that
+% procedures are writable.
+false setpacking
+
+% Close up systemdict.
+currentdict /.forceput .undef % remove temptation
+currentdict /filterdict .undef % bound in where needed
+end
+WRITESYSTEMDICT not { systemdict readonly pop } if
+
+(END INIT) VMDEBUG
+
+% Since some badly-behaved files include extremely long procedures,
+% or construct huge arrays on the operand stack, increase the operand
+% stack size here.
+/setuserparams where
+ { pop mark /MaxOpStack 20000 .dicttomark setuserparams
+ } if
+
+% Establish local VM as the default.
+false /setglobal where { pop setglobal } { .setglobal } ifelse
+$error /.nosetlocal false put
+
+% Clean up VM, and enable GC.
+/vmreclaim where
+ { pop NOGC not { 2 vmreclaim 0 vmreclaim } if
+ } if
+
+(END GC) VMDEBUG
+
+% The interpreter will run the initial procedure (start).
diff --git a/gs/lib/gs_iso_e.ps b/gs/lib/gs_iso_e.ps
new file mode 100644
index 000000000..2f4245b14
--- /dev/null
+++ b/gs/lib/gs_iso_e.ps
@@ -0,0 +1,67 @@
+% Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the ISO Latin-1 encoding vector.
+% The first half is the same as the standard encoding,
+% except for minus instead of hyphen at code 055.
+/ISOLatin1Encoding
+StandardEncoding 0 45 getinterval aload pop
+ /minus
+StandardEncoding 46 82 getinterval aload pop
+% NOTE: the following are missing in the Adobe documentation,
+% but appear in the displayed table:
+% macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
+% This is an error in the Red Book, corrected in Adobe TN 5085.
+% \20x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
+ /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
+% \24x
+ /space /exclamdown /cent /sterling
+ /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft
+ /logicalnot /hyphen /registered /macron
+ /degree /plusminus /twosuperior /threesuperior
+ /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright
+ /onequarter /onehalf /threequarters /questiondown
+% \30x
+ /Agrave /Aacute /Acircumflex /Atilde
+ /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis
+ /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute
+ /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex
+ /Udieresis /Yacute /Thorn /germandbls
+% \34x
+ /agrave /aacute /acircumflex /atilde
+ /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis
+ /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute
+ /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex
+ /udieresis /yacute /thorn /ydieresis
+% Make an array on large systems, a packed array on small ones.
+256
+vmstatus exch pop exch pop
+100000 ge { array astore readonly } { packedarray } ifelse
+def
+1 ISOLatin1Encoding .registerencoding
+/ISOLatin1Encoding ISOLatin1Encoding .defineencoding
diff --git a/gs/lib/gs_kanji.ps b/gs/lib/gs_kanji.ps
new file mode 100644
index 000000000..09bb529a4
--- /dev/null
+++ b/gs/lib/gs_kanji.ps
@@ -0,0 +1,159 @@
+% Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Scaffolding for Kanji fonts. This is based on the Wadalab free font
+% from the University of Tokyo; it may not be appropriate for other
+% Kanji fonts.
+
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+
+% Define the encoding for the root font.
+
+/KanjiEncoding
+% \x00
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+% \x20
+ 0 1 2 3 4 5 6 7
+ 8 0 0 0 0 0 0 0
+ 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24
+% \x40
+ 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40
+ 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56
+% \x60
+ 57 58 59 60 61 62 63 64
+ 65 66 67 68 69 70 71 72
+ 73 74 75 76 77 0 0 0
+ 0 0 0 0 0 0 0 0
+% \x80
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+% \xA0
+ 0 1 2 3 4 5 6 7
+ 8 0 0 0 0 0 0 0
+ 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24
+% \xC0
+ 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40
+ 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56
+% \xE0
+ 57 58 59 60 61 62 63 64
+ 65 66 67 68 69 70 71 72
+ 73 74 75 76 77 0 0 0
+ 0 0 0 0 0 0 0 0
+256 packedarray def
+
+% Define a stub for the base font encoding.
+
+ /KanjiSubEncoding { /KanjiSubEncoding .findencoding } bind def
+%% Replace 3 (gs_ksb_e.ps)
+ EncodingDirectory /KanjiSubEncoding
+ { (gs_ksb_e.ps) //systemdict begin runlibfile KanjiSubEncoding end }
+ bind put
+
+% Support procedures and data.
+
+/T1FontInfo 8 dict begin
+ /version (001.001) readonly def
+ /FullName (KanjiBase) readonly def
+ /FamilyName (KanjiBase) readonly def
+ /Weight (Medium) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition 0 def
+ /UnderlineThickness 0 def
+currentdict end readonly def
+
+/T1NF % <fontname> T1NF <font>
+{
+20 dict begin
+ /FontName exch def
+ /FontType 1 def
+ /FontInfo T1FontInfo def
+ /FontMatrix [.001 0 0 .001 0 0] def
+ /FontBBox [0 0 1000 1000] def
+ /Encoding KanjiSubEncoding def
+ /CharStrings 150 dict def
+ /PaintType 0 def
+ /Private 2 dict def
+ Private begin
+ /BlueValues [] def
+ /password 5839 def
+ end
+FontName currentdict end definefont
+} def
+
+/T0NF % <fontname> T0NF <font>
+{
+20 dict begin
+ /FontName exch def
+ /FDepVector exch def
+ /FontType 0 def
+ /FontMatrix [1 0 0 1 0 0] def
+ /FMapType 2 def
+ /Encoding KanjiEncoding def
+FontName currentdict end definefont
+} def
+
+% Define the composite font and all the base fonts.
+
+/CompNF % <fontname> CompNF <font>
+{
+/newname1 exch def
+newname1 dup length string cvs /str exch def
+str length /len exch def
+/fdepvector 78 array def
+/j 1 def
+16#21 1 16#74 {
+/i exch def
+KanjiEncoding i get 0 gt {
+len 4 add string /newstr exch def
+newstr 0 str putinterval
+newstr len (.r) putinterval
+newstr len 2 add i 16 2 string cvrs putinterval
+newstr cvn /newlit exch def
+newlit T1NF /newfont exch def
+fdepvector j newfont put
+/j j 1 add def
+} if
+} for
+fdepvector 0 fdepvector 1 get put
+/j 0 def
+fdepvector newname1 T0NF
+} def
+
+% Define an individual character in a composite font.
+/CompD % <charstring> <(HL)> CompD -
+ { currentfont /Encoding get 1 index 0 get get % FDepVector index
+ currentfont /FDepVector get exch get % base font
+ dup /Encoding get 3 -1 roll 1 get get % base font character name
+ exch /CharStrings get exch 3 -1 roll put
+ } bind def
+
+exec
diff --git a/gs/lib/gs_ksb_e.ps b/gs/lib/gs_ksb_e.ps
new file mode 100644
index 000000000..b6e478914
--- /dev/null
+++ b/gs/lib/gs_ksb_e.ps
@@ -0,0 +1,65 @@
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the KanjiSub encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/KanjiSubEncoding
+%\x00
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+%\x20
+ /.notdef /c21 /c22 /c23 /c24 /c25 /c26 /c27
+ /c28 /c29 /c2A /c2B /c2C /c2D /c2E /c2F
+ /c30 /c31 /c32 /c33 /c34 /c35 /c36 /c37
+ /c38 /c39 /c3A /c3B /c3C /c3D /c3E /c3F
+%\x40
+ /c40 /c41 /c42 /c43 /c44 /c45 /c46 /c47
+ /c48 /c49 /c4A /c4B /c4C /c4D /c4E /c4F
+ /c50 /c51 /c52 /c53 /c54 /c55 /c56 /c57
+ /c58 /c59 /c5A /c5B /c5C /c5D /c5E /c5F
+%\x60
+ /c60 /c61 /c62 /c63 /c64 /c65 /c66 /c67
+ /c68 /c69 /c6A /c6B /c6C /c6D /c6E /c6F
+ /c70 /c71 /c72 /c73 /c74 /c75 /c76 /c77
+ /c78 /c79 /c7A /c7B /c7C /c7D /c7E /.notdef
+%\x80
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+%\xA0
+ /.notdef /c21 /c22 /c23 /c24 /c25 /c26 /c27
+ /c28 /c29 /c2A /c2B /c2C /c2D /c2E /c2F
+ /c30 /c31 /c32 /c33 /c34 /c35 /c36 /c37
+ /c38 /c39 /c3A /c3B /c3C /c3D /c3E /c3F
+%\xC0
+ /c40 /c41 /c42 /c43 /c44 /c45 /c46 /c47
+ /c48 /c49 /c4A /c4B /c4C /c4D /c4E /c4F
+ /c50 /c51 /c52 /c53 /c54 /c55 /c56 /c57
+ /c58 /c59 /c5A /c5B /c5C /c5D /c5E /c5F
+%\xE0
+ /c60 /c61 /c62 /c63 /c64 /c65 /c66 /c67
+ /c68 /c69 /c6A /c6B /c6C /c6D /c6E /c6F
+ /c70 /c71 /c72 /c73 /c74 /c75 /c76 /c77
+ /c78 /c79 /c7A /c7B /c7C /c7D /c7E /.notdef
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_l2img.ps b/gs/lib/gs_l2img.ps
new file mode 100644
index 000000000..9ac5726ee
--- /dev/null
+++ b/gs/lib/gs_l2img.ps
@@ -0,0 +1,186 @@
+% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Emulate the Level 2 dictionary-based image operator in Level 1,
+% except for Interpolate (ignored) and MultipleDataSources = true;
+% also, we require that the data source be either a procedure of a
+% particular form or a stream, not a string or a general procedure.
+
+% pdf2ps copies the portion of this file from %BEGIN to %END if Level 1
+% compatible output is requested.
+
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+
+/packedarray where
+ { pop }
+ { /packedarray { array astore readonly } bind def }
+ifelse
+
+%BEGIN
+
+11 dict /.csncompdict 1 index def begin
+ /DeviceGray { 1 /setgray load } bind def
+ /DeviceRGB { 3 /setrgbcolor load } bind def
+ /DeviceCMYK { 4 /setcmykcolor load } bind def
+ /Indexed
+ { dup 1 index 1 get //.csncompdict exch get exec
+ % Stack: [/Indexed base hival map] ncomp basesetcolor
+ 3 -1 roll 3 get mark 3 1 roll
+ % Stack: ncomp -mark- basesetcolor map
+ dup type /stringtype eq
+ { { -
+ { exch round cvi get 255 div
+ }
+ -
+ { exch round cvi 3 mul 2 copy 2 copy get 255 div
+ 3 1 roll 1 add get 255 div
+ 4 2 roll 2 add get 255 div
+ }
+ { exch round cvi 4 mul 2 copy 2 copy 2 copy get 255 div
+ 3 1 roll 1 add get 255 div
+ 4 2 roll 2 add get 255 div
+ 5 3 roll 3 add get 255 div
+ }
+ }
+ 4 index get aload pop counttomark -1 roll
+ }
+ { /exec load 3 -1 roll
+ % Stack: -mark- mapproc --exec-- basesetcolor
+ }
+ ifelse .packtomark cvx
+ exch pop 1 exch
+ } bind def
+ /Separation
+ { dup 2 index //.csncompdict exch get exec
+ % Stack: [/Separation name alt xform] ncomp altsetcolor
+ 3 -1 roll 3 get /exec load 3 -1 roll 3 array astore readonly cvx
+ exch pop 1 exch
+ } bind def
+ % Substitute device spaces for CIE spaces.
+ /CIEBasedA /DeviceGray load def
+ /CIEBasedABC /DeviceRGB load def
+ /CIEBasedDEF /DeviceRGB load def
+ /CIEBasedDEFG /DeviceCMYK load def
+end
+
+/.packtomark { counttomark packedarray exch pop } bind def
+
+/.csinextbits % - .csinextbits <bits>
+ % Uses b, nnb, i, row, mask, BitsPerComponent;
+ % sets b, nnb, i.
+ { /nnb nnb BitsPerComponent add
+ { dup 0 le { exit } if
+ /b b 8 bitshift row i get add def
+ /i i 1 add def 8 sub
+ }
+ loop def
+ b nnb bitshift mask and
+ } bind def
+
+% Note that the ColorSpace key must be present in the image dictionary.
+/.colorspaceimage % <imagedict> .colorspaceimage -
+ { save exch
+ dup length 15 add dict begin { cvlit def } forall
+ ColorSpace dup dup type /nametype ne { 0 get } if
+ .csncompdict exch get exec
+ /setpixelcolor exch def /ncomp exch def pop
+ /row ncomp BitsPerComponent mul Width mul 7 add 8 idiv string def
+ /mask 1 BitsPerComponent bitshift 1 sub def
+ /nextbits BitsPerComponent 8 eq
+ { { row i get /i i 1 add def } }
+ { /.csinextbits load }
+ ifelse def
+ /nextpixel mark 0 2 ncomp 1 sub 2 mul
+ { /nextbits cvx exch
+ Decode exch 2 getinterval
+ dup aload pop exch sub
+ dup mask eq { pop } { mask div /mul load 3 -1 roll } ifelse
+ 0 get dup 0 eq { pop } { /sub load 3 -1 roll } ifelse
+ }
+ for
+ /setpixelcolor load dup type /operatortype ne { /exec load } if
+ .packtomark cvx def
+ /readrow
+ /DataSource load dup type
+ dup /arraytype eq exch /packedarraytype eq or
+ { % Must be { <file> <string> ... }
+ aload length 1 add array /pop load exch astore
+ dup 1 row put cvx
+ }
+ { pop
+ % Adobe requires readstring to signal an error if given
+ % an empty string. Work around this nonsense here.
+ row length 0 eq
+ { { } }
+ { { DataSource row readstring pop pop } }
+ ifelse
+ }
+ ifelse def
+ ImageMatrix matrix invertmatrix concat
+ /imat matrix def
+ 0 1 Height 1 sub
+ { imat 5 3 -1 roll neg put
+%(.) print flush
+ readrow
+ /b 0 def /nnb 0 def /i 0 def
+ 0 1 Width 1 sub
+ { imat 4 3 -1 roll neg put nextpixel
+ 1 1 true imat {<80>} imagemask
+ }
+ for
+ }
+ for
+ end restore
+ } bind def
+
+%END
+exec
+currentfile closefile
+
+% Patch for testing.
+/.cincompdict 3 dict begin
+ 1 { {0 1} {/DeviceGray} } def
+ 3 { {0 1 0 1 0 1} {/DeviceRGB} } def
+ 4 { {0 1 0 1 0 1 0 1} {/DeviceCMYK} } def
+currentdict end def
+/.imagekeys [
+ /Decode /DataSource /ImageMatrix /BitsPerComponent /Height /Width
+] def
+/colorimage % <width> <height> <bits/comp> <matrix>
+ % <datasrc> false <ncomp> colorimage -
+ { 1 index { /colorimage load /rangecheck signalerror } if exch pop
+ //.cincompdict exch get exec
+ 7 dict begin /ColorSpace exch cvlit def
+ .imagekeys { exch cvlit def } forall
+ currentdict end .colorspaceimage
+ } bind odef
+/image
+ { dup type /dicttype ne
+ { 7 dict begin /ColorSpace /DeviceGray def [0 1]
+ .imagekeys { exch cvlit def } forall
+ currentdict end
+ }
+ { dup length 1 add dict .copydict dup /ColorSpace currentcolorspace put
+ }
+ ifelse
+ .colorspaceimage
+ } bind odef
+
+exec
diff --git a/gs/lib/gs_lev2.ps b/gs/lib/gs_lev2.ps
new file mode 100644
index 000000000..f07bf81b9
--- /dev/null
+++ b/gs/lib/gs_lev2.ps
@@ -0,0 +1,459 @@
+% Copyright (C) 1990, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for Level 2 functions.
+% When this is run, systemdict is still writable,
+% but (almost) everything defined here goes into level2dict.
+
+level2dict begin
+
+% ------ System and user parameters ------ %
+
+% User parameters are managed entirely in C code.
+/currentuserparams { % - currentuserparams <dict>
+ mark .currentuserparams .dicttomark
+ } odef
+systemdict begin
+/getuserparam { % <name> getuserparam <value>
+ .getuserparam
+} odef
+end
+
+% Some system parameters are managed entirely at the PostScript level.
+% We take care of that here.
+systemdict begin
+currentdict /systemparams known not {
+ /systemparams 10 dict readonly def
+} if
+/getsystemparam { % <name> getsystemparam <value>
+ //systemparams 1 index .knownget { exch pop } { .getsystemparam } ifelse
+} odef
+end
+/currentsystemparams { % - currentsystemparams <dict>
+ mark .currentsystemparams //systemparams { } forall .dicttomark
+} odef
+/.setsystemparams /setsystemparams load def
+/setsystemparams { % <dict> setsystemparams -
+ % Check that we will be able to set the PostScript-level
+ % system parameters.
+ dup
+ { //systemparams 3 -1 roll .knownget
+ { type 1 index type ne
+ { pop /setsystemparams load /typecheck signalerror }
+ if
+ dup type /stringtype eq
+ { dup dup gcheck exch rcheck or not
+ { /setsystemparams load /invalidaccess signalerror }
+ if
+ }
+ if pop
+ }
+ { pop
+ }
+ ifelse
+ }
+ forall
+ % Set the C-level system params. If this succeeds, we know that
+ % the password check succeeded.
+ dup .setsystemparams
+ % Now set the PostScript-level params. We must copy local strings
+ % into global VM.
+ dup
+ { //systemparams 2 index known
+ { % Stack: key newvalue
+ dup gcheck not
+ { % The only composite objects that can have passed
+ % the type check are strings.
+ .currentglobal true .setglobal
+ 1 index length string exch .setglobal
+ copy readonly
+ }
+ if //systemparams 3 1 roll .forceput
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall pop
+} odef
+
+% ------ Miscellaneous ------ %
+
+(<<) cvn % - << -mark-
+ /mark load def
+(>>) cvn % -mark- <key1> <value1> ... >> <dict>
+ /.dicttomark load def
+/languagelevel 2 def
+% When running in Level 2 mode, this interpreter is supposed to be
+% compatible with PostScript version 2010 (I think).
+/version (2010) def
+
+% If binary tokens are supported by this interpreter,
+% set an appropriate default binary object format.
+/setobjectformat where
+ { pop
+ /RealFormat getsystemparam (IEEE) eq { 1 } { 3 } ifelse
+ /ByteOrder getsystemparam { 1 add } if
+ setobjectformat
+ } if
+
+% ------ Virtual memory ------ %
+
+/currentglobal % - currentglobal <bool>
+ /currentshared load def
+/gcheck % <obj> gcheck <bool>
+ /scheck load def
+/setglobal % <bool> setglobal -
+ /setshared load def
+% We can make the global dictionaries very small, because they auto-expand.
+/globaldict currentdict /shareddict .knownget not { 4 dict } if def
+/GlobalFontDirectory SharedFontDirectory def
+
+% ------ IODevices ------ %
+
+/.getdevparams where {
+ pop /currentdevparams { % <iodevice> currentdevparams <dict>
+ .getdevparams .dicttomark
+ } odef
+} if
+/.putdevparams where {
+ pop /setdevparams { % <iodevice> <dict> setdevparams -
+ mark 1 index { } forall counttomark 2 add index
+ .putdevparams pop pop
+ } odef
+} if
+
+% ------ Job control ------ %
+
+serverdict begin
+
+% We could protect the job information better, but we aren't attempting
+% (currently) to protect ourselves against maliciousness.
+
+/.jobsave null def % top-level save object
+/.jobsavelevel 0 def % save depth of job (0 if .jobsave is null,
+ % 1 otherwise)
+/.adminjob true def % status of current unencapsulated job
+
+/exitserver { % <password> exitserver -
+ true exch startjob not { /exitserver /invalidaccess signalerror } if
+} bind def
+
+end % serverdict
+
+% Because there may be objects on the e-stack created since the job save,
+% we have to clear the e-stack before doing the end-of-job restore.
+% We do this by executing a 2 .stop, which is caught by the 2 .stopped
+% in .runexec; we leave on the o-stack a procedure to execute aftewards.
+%
+%**************** The definition of startjob is not complete yet, since
+% it doesn't reset stdin/stdout or other aspects of the interpreter.
+/.finishstartjob { % <exit_bool> <password_level>
+ % .finishstartjob -true-
+ serverdict /.jobsave get dup null eq { pop } { restore } ifelse
+ exch {
+ % Unencapsulated job
+ serverdict /.jobsave null put
+ serverdict /.jobsavelevel 0 put
+ serverdict /.adminjob 3 -1 roll 1 gt put
+ } {
+ % Encapsulated job
+ pop
+ serverdict /.jobsave save put
+ serverdict /.jobsavelevel 1 put
+ userdict /quit /stop load put
+ } ifelse true
+} bind def
+/startjob { % <exit_bool> <password> startjob <ok_bool>
+ vmstatus pop pop serverdict /.jobsavelevel get eq
+ 1 index .checkpassword 0 gt and {
+ .checkpassword count 2 roll count 2 sub { pop } repeat
+ cleardictstack
+ % Reset the e-stack back to the 2 .stopped in .runexec.
+ { .finishstartjob } 2 .stop
+ } { % Password check failed
+ pop pop false
+ } ifelse
+} odef
+
+systemdict begin
+/quit { % - quit -
+ //systemdict begin serverdict /.jobsave get null eq
+ { end //quit }
+ { /quit load /invalidaccess /signalerror load end exec }
+ ifelse
+} bind odef
+end
+
+% ------ Compatibility ------ %
+
+% In Level 2 mode, the following replace the definitions that gs_statd.ps
+% installs in statusdict and serverdict.
+% Note that statusdict must be allocated in local VM.
+% We don't bother with many of these yet.
+
+/.dict1 { exch mark 3 1 roll .dicttomark } bind def
+
+currentglobal false setglobal 25 dict exch setglobal begin
+currentsystemparams
+
+/buildtime 1 index /BuildTime get def
+/byteorder 1 index /ByteOrder get def
+/checkpassword { .checkpassword 0 gt } bind def
+/defaulttimeouts
+ { currentsystemparams dup
+ /JobTimeout .knownget not { 0 } if
+ exch /WaitTimeout .knownget not { 0 } if
+ currentpagedevice /ManualFeedTimeout .knownget not { 0 } if
+ } bind def
+dup /DoStartPage known
+ { /dostartpage { /DoStartPage getsystemparam } bind def
+ /setdostartpage { /DoStartPage .dict1 setsystemparams } bind def
+ } if
+dup /StartupMode known
+ { /dosysstart { /StartupMode getsystemparam 0 ne } bind def
+ /setdosysstart { { 1 } { 0 } ifelse /StartupMode .dict1 setsystemparams } bind def
+ } if
+%****** Setting jobname is supposed to set userparams.JobName, too.
+/jobname { /JobName getuserparam } bind def
+/jobtimeout { /JobTimeout getuserparam } bind def
+%manualfeed
+%manualfeedtimeout
+/margins
+ { currentpagedevice /Margins .knownget { exch } { [0 0] } ifelse
+ } bind def
+%pagecount
+%pagestackorder
+/printername
+ { currentsystemparams /PrinterName .knownget not { () } if exch copy
+ } bind def
+%/ramsize { /RamSize getsystemparam } bind def
+/realformat 1 index /RealFormat get def
+
+/.setpagedevice where
+ { pop
+ /setdefaulttimeouts
+ { exch mark /ManualFeedTimeout 3 -1 roll
+ /Policies mark /ManualFeedTimeout 1 .dicttomark
+ .dicttomark setpagedevice
+ /WaitTimeout exch mark /JobTimeout 5 2 roll .dicttomark setsystemparams
+ } bind def
+ /setmargins
+ { exch 2 array astore /Margins .dict1 setpagedevice
+ } bind def
+ }
+if
+%setpagestackorder
+dup /PrinterName known
+ { /setprintername { /PrinterName .dict1 setsystemparams } bind def
+ } if
+currentuserparams /WaitTimeout known
+ { /waittimeout { /WaitTimeout getuserparam } bind def
+ } if
+
+/.setpagedevice where
+ { pop
+ /pagemargin
+ { currentpagedevice /PageOffset .knownget { 0 get } { 0 } ifelse
+ } bind def
+ /pageparams
+ { currentpagedevice
+ dup /Orientation .knownget { 1 and ORIENT1 { 1 xor } if } { 0 } ifelse exch
+ dup /PageSize get aload pop 3 index 0 ne { exch } if 3 2 roll
+ /PageOffset .knownget { 0 get } { 0 } ifelse 4 -1 roll
+ } bind def
+ /.setpagesize { 2 array astore /PageSize .dict1 setpagedevice } bind def
+ /setduplexmode { /Duplex .dict1 setpagedevice } bind def
+ /setpagemargin { 0 2 array astore /PageOffset .dict1 setpagedevice } bind def
+ /setpageparams
+ { mark /PageSize 6 -2 roll
+ 4 index 1 and ORIENT1 { 1 } { 0 } ifelse ne { exch } if 2 array astore
+ /Orientation 5 -1 roll ORIENT1 { 1 xor } if
+ /PageOffset counttomark 2 add -1 roll 0 2 array astore
+ .dicttomark setpagedevice
+ } bind def
+ /setresolution
+ { dup 2 array astore /HWResolution .dict1 setpagedevice
+ } bind def
+ }
+if
+
+pop % currentsystemparams
+
+% Flag the current dictionary so it will be swapped when we
+% change language levels. (See zmisc2.c for more information.)
+/statusdict currentdict def
+
+currentdict end
+/statusdict exch def
+
+% ------ Color spaces ------ %
+
+% Define the setcolorspace procedures:
+% <colorspace> proc <colorspace'|null>
+/colorspacedict mark
+ /DeviceGray { pop 0 setgray null } bind
+ /DeviceRGB { pop 0 0 0 setrgbcolor null } bind
+ /setcmykcolor where
+ { pop /DeviceCMYK { pop 0 0 0 1 setcmykcolor null } bind
+ } if
+ /.setcieaspace where
+ { pop /CIEBasedA { NOCIE { pop 0 setgray null } { dup 1 get .setcieaspace } ifelse } bind
+ } if
+ /.setcieabcspace where
+ { pop /CIEBasedABC { NOCIE { pop 0 0 0 setrgbcolor null } { dup 1 get .setcieabcspace } ifelse } bind
+ } if
+ /.setciedefspace where
+ { pop /CIEBasedDEF { NOCIE { pop 0 0 0 setrgbcolor null } { dup 1 get .setciedefspace } ifelse } bind
+ } if
+ /.setciedefgspace where
+ { pop /CIEBasedDEFG { NOCIE { pop 0 0 0 1 setcmykcolor null } { dup 1 get .setciedefgspace } ifelse } bind
+ } if
+ /.setseparationspace where
+ { pop /Separation { dup 2 get setcolorspace dup .setseparationspace } bind
+ } if
+ /.setindexedspace where
+ { pop /Indexed { dup 1 get setcolorspace dup .setindexedspace } bind
+ } if
+ /.nullpatternspace [/Pattern] readonly def
+ /.setpatternspace where
+ { pop /Pattern
+ { dup type /nametype eq { pop //.nullpatternspace } if
+ dup length 1 gt { dup 1 get setcolorspace } if
+ dup .setpatternspace
+ } bind
+ } if
+ currentdict /.nullpatternspace .undef
+.dicttomark def
+
+/.devcs [/DeviceGray /DeviceRGB /DeviceCMYK] readonly def
+/currentcolorspace { % - currentcolorspace <array>
+ .currentcolorspace dup type /integertype eq {
+ //.devcs exch 1 getinterval
+ } if
+} odef
+currentdict /.devcs .undef
+
+/setcolorspace { % <name|array> setcolorspace -
+ dup dup dup type /nametype ne { 0 get } if
+ //colorspacedict exch get exec
+ dup null eq { pop } { .setcolorspace } ifelse pop
+} odef
+
+% ------ CIE color rendering ------ %
+
+/setcolorrendering where { pop } { (%END CRD) .skipeof } ifelse
+
+% Initialize the CIE rendering dictionary if necessary.
+% The most common CIE files seem to assume the "calibrated RGB color space"
+% described on p. 189 of the PostScript Language Reference Manual,
+% 2nd Edition; we simply invert this transformation back to RGB.
+mark
+ /ColorRenderingType 1
+% We must make RangePQR and RangeLMN large enough so that values computed by
+% the assumed encoding MatrixLMN don't get clamped.
+ /RangePQR [0 0.9505 0 1 0 1.0890]
+ /TransformPQR [ { 4 { exch pop } repeat } dup dup ]
+ /RangeLMN [0 0.9505 0 1 0 1.0890]
+ /MatrixABC
+ [ 3.24063 -0.96893 0.05571
+ -1.53721 1.87576 -0.20402
+ -0.49863 0.04152 1.05700
+ ]
+ /EncodeABC [{0 max 0.45 exp} bind dup dup]
+ /WhitePoint [0.9505 1 1.0890]
+ % Some Genoa tests seem to require the presence of BlackPoint.
+ /BlackPoint [0 0 0]
+.dicttomark setcolorrendering
+
+% Define findcolorrendering and a default ColorRendering ProcSet.
+
+/findcolorrendering { % <intentname> findcolorrendering
+ % <crdname> <found>
+ /ColorRendering /ProcSet findresource
+ 1 index .namestring (.) concatstrings
+ 1 index /GetPageDeviceName get exec .namestring (.) concatstrings
+ 2 index /GetHalftoneName get exec .namestring
+ concatstrings concatstrings
+ dup /ColorRendering resourcestatus {
+ pop pop exch pop exch pop true
+ } {
+ pop /GetSubstituteCRD get exec false
+ } ifelse
+} odef
+
+5 dict dup begin
+
+/GetPageDeviceName { % - GetPageDeviceName <name>
+ currentpagedevice dup /PageDeviceName .knownget {
+ exch pop
+ } {
+ pop /none
+ } ifelse
+} bind def
+
+/GetHalftoneName { % - GetHalftoneName <name>
+ currenthalftone /HalftoneName .knownget not { /none } if
+} bind def
+
+/GetSubstituteCRD { % <intentname> GetSubstituteCRD <crdname>
+ pop /DefaultColorRendering
+} bind def
+
+end
+% The resource machinery hasn't been activated, so just save the ProcSet
+% and let .fixresources finish the installation process.
+/ColorRendering exch def
+
+%END CRD
+
+% ------ Painting ------ %
+
+% A straightforward definition of execform that doesn't actually
+% do any caching.
+/.execform1
+ { % This is a separate operator so that the stacks will be restored
+ % properly if an error occurs.
+ dup /Implementation known not
+ { dup /FormType get 1 ne { /rangecheck signalerror } if
+ dup /Implementation null put readonly
+ } if
+ dup /Matrix get concat
+ dup /BBox get aload pop
+ exch 3 index sub exch 2 index sub rectclip
+ dup /PaintProc get exec
+ } odef
+/execform % <form> execform -
+ { gsave { .execform1 } stopped grestore { stop } if
+ } odef
+
+/makepattern { % <proto_dict> <matrix> makepattern <pattern>
+ 1 index dup length 1 add currentglobal
+ { false setglobal dict .copydict 1 index .buildpattern true setglobal }
+ { dict .copydict 1 index .buildpattern }
+ ifelse
+ 1 index /Implementation 3 -1 roll put
+ readonly exch pop exch pop
+} odef
+
+/setpattern { % [<comp1> ...] <pattern> setpattern -
+ currentcolorspace 0 get /Pattern ne {
+ [ /Pattern currentcolorspace ] setcolorspace
+ } if setcolor
+} odef
+
+end % level2dict
diff --git a/gs/lib/gs_mex_e.ps b/gs/lib/gs_mex_e.ps
new file mode 100644
index 000000000..45baf92f7
--- /dev/null
+++ b/gs/lib/gs_mex_e.ps
@@ -0,0 +1,65 @@
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the MacExpert encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/MacExpertEncoding
+% \00x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \04x
+ /space /exclamsmall /Hungarumlautsmall /centoldstyle /dollaroldstyle /dollarsuperior /ampersandsmall /Acutesmall
+ /parenleftsuperior /parenrightsuperior /twodotenleader /onedotenleader /comma /hyphen /period /fraction
+ /zerooldstyle /oneoldstyle /twooldstyle /threeoldstyle /fouroldstyle /fiveoldstyle /sixoldstyle /sevenoldstyle
+ /eightoldstyle /nineoldstyle /colon /semicolon /.notdef /threequartersemdash /.notdef /questionsmall
+% \10x
+ /.notdef /.notdef /.notdef /.notdef /Ethsmall /.notdef /.notdef /onequarter
+ /onehalf /threequarters /oneeighth /threeeighths /fiveeighths /seveneighths /onethird /twothirds
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /ff /fi
+ /fl /ffi /ffl /parenleftinferior /.notdef /parenrightinferior /Circumflexsmall /hypheninferior
+% \14x
+ /Gravesmall /Asmall /Bsmall /Csmall /Dsmall /Esmall /Fsmall /Gsmall
+ /Hsmall /Ismall /Jsmall /Ksmall /Lsmall /Msmall /Nsmall /Osmall
+ /Psmall /Qsmall /Rsmall /Ssmall /Tsmall /Usmall /Vsmall /Wsmall
+ /Xsmall /Ysmall /Zsmall /colonmonetary /onefitted /rupiah /Tildesmall /.notdef
+% \20x
+ /.notdef /asuperior /centsuperior /.notdef /.notdef /.notdef /.notdef /Aacutesmall
+ /Agravesmall /Acircumflexsmall /Adieresissmall /Atildesmall /Aringsmall /Ccedillasmall /Eacutesmall /Egravesmall
+ /Ecircumflexsmall /Edieresissmall /Iacutesmall /Igravesmall /Icircumflexsmall /Idieresissmall /Ntildesmall /Oacutesmall
+ /Ogravesmall /Ocircumflexsmall /Odieresissmall /Otildesmall /Uacutesmall /Ugravesmall /Ucircumflexsmall /Udieresissmall
+% \24x
+ /.notdef /eightsuperior /fourinferior /threeinferior /sixinferior /eightinferior /seveninferior /Scaronsmall
+ /.notdef /centinferior /twoinferior /.notdef /Dieresissmall /.notdef /Caronsmall /osuperior
+ /fiveinferior /.notdef /commainferior /periodinferior /Yacutesmall /.notdef /dollarinferior /.notdef
+ /.notdef /Thornsmall /.notdef /nineinferior /zeroinferior /Zcaronsmall /AEsmall /Oslashsmall
+% \30x
+ /questiondownsmall /oneinferior /Lslashsmall /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /Cedillasmall /.notdef /.notdef /.notdef /.notdef /.notdef /OEsmall
+ /figuredash /hyphensuperior /.notdef /.notdef /.notdef /.notdef /exclamdownsmall /.notdef
+ /Ydieresissmall /.notdef /onesuperior /twosuperior /threesuperior /foursuperior /fivesuperior /sixsuperior
+% \34x
+ /sevensuperior /ninesuperior /zerosuperior /.notdef /esuperior /rsuperior /tsuperior /.notdef
+ /.notdef /isuperior /ssuperior /dsuperior /.notdef /.notdef /.notdef /.notdef
+ /.notdef /lsuperior /Ogoneksmall /Brevesmall /Macronsmall /bsuperior /nsuperior /msuperior
+ /commasuperior /periodsuperior /Dotaccentsmall /Ringsmall /.notdef /.notdef /.notdef /.notdef
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_mro_e.ps b/gs/lib/gs_mro_e.ps
new file mode 100644
index 000000000..6cd59cbc2
--- /dev/null
+++ b/gs/lib/gs_mro_e.ps
@@ -0,0 +1,58 @@
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the MacRoman encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/MacRomanEncoding
+StandardEncoding 0 39 getinterval aload pop
+ /quotesingle
+StandardEncoding 40 56 getinterval aload pop
+ /grave
+StandardEncoding 97 31 getinterval aload pop
+% \20x
+ /Adieresis /Aring /Ccedilla /Eacute /Ntilde /Odieresis /Udieresis /aacute
+ /agrave /acircumflex /adieresis /atilde /aring /ccedilla /eacute /egrave
+ /ecircumflex /edieresis /iacute /igrave
+ /icircumflex /idieresis /ntilde /oacute
+ /ograve /ocircumflex /odieresis /otilde
+ /uacute /ugrave /ucircumflex /udieresis
+% \24x
+ /dagger /degree /cent /sterling /section /bullet /paragraph /germandbls
+ /registered /copyright /trademark /acute /dieresis /.notdef /AE /Oslash
+ /.notdef /plusminus /.notdef /.notdef /yen /mu /.notdef /.notdef
+ /.notdef /.notdef /.notdef /ordfeminine /ordmasculine /.notdef /ae /oslash
+% \30x
+ /questiondown /exclamdown /logicalnot /.notdef
+ /florin /.notdef /.notdef /guillemotleft
+ /guillemotright /ellipsis /space /Agrave /Atilde /Otilde /OE /oe
+ /endash /emdash /quotedblleft /quotedblright
+ /quoteleft /quoteright /divide /.notdef
+ /ydieresis /Ydieresis /fraction /currency
+ /guilsingleft /guilsingright /fi /fl
+% \34x
+ /daggerdbl /periodcentered /quotesinglbase /quotedblbase
+ /perthousand /Acircumflex /Ecircumflex /Aacute
+ /Edieresis /Egrave /Iacute /Icircumflex
+ /Idieresis /Igrave /Oacute /Ocircumflex
+ /.notdef /Ograve /Uacute /Ucircumflex
+ /Ugrave /dotlessi /circumflex /tilde
+ /macron /breve /dotaccent /ring /cedilla /hungarumlaut /ogonek /caron
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_pdf.ps b/gs/lib/gs_pdf.ps
new file mode 100644
index 000000000..3798278ac
--- /dev/null
+++ b/gs/lib/gs_pdf.ps
@@ -0,0 +1,646 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% gs_pdf.ps
+% ProcSet for PostScript files created by the PDF to PostScript converter.
+% This ProcSet requires only a Level 1 interpreter, unless fonts other
+% than ordinary Type 1 or Type 3 fonts are involved.
+
+% pdf2ps copies this file from %BEGIN to the end.
+
+%BEGIN
+% Patches for Level 1 printers and non-Ghostscript interpreters.
+mark
+/currentglobal { false }
+/setglobal { pop }
+/packedarray { array astore readonly }
+/setcmykcolor {
+ 1 exch sub
+ 4 -1 roll 1 exch sub 1 index mul
+ 4 -1 roll 1 exch sub 2 index mul
+ 4 -2 roll exch 1 exch sub mul
+ setrgbcolor
+}
+/sethalftonephase { pop pop }
+/setpagedevice {
+ statusdict /pageparams get exec
+ 4 index /PageSize .knownget { aload pop 6 -2 roll pop pop 4 2 roll } if
+ 4 index /Orientation .knownget { 3 -1 roll pop exch } if
+ statusdict /setpageparams get exec
+ /PageOffset .knownget { aload pop translate } if
+}
+/setoverprint { pop }
+/setstrokeadjust { pop }
+/.copydict { dup 3 -1 roll { put dup } forall pop }
+/.dicttomark {
+ counttomark 2 idiv dup dict begin { def } repeat pop currentdict end
+}
+/.knownget { 2 copy known { get true } { pop pop false } ifelse }
+/.setdefaultscreen { }
+counttomark 2 idiv {
+ 1 index where { pop pop pop } { bind executeonly def } ifelse
+} repeat pop
+
+currentglobal true setglobal
+
+% Define pdfmark. Don't allow it to be bound in.
+% Also don't define it in systemdict, because this leads some Adobe code
+% to think this interpreter is a distiller.
+% (If this interpreter really is a distiller, don't do this.)
+systemdict /pdfmark known not
+ { userdict /pdfmark { cleartomark } bind put } if
+
+% This ProcSet is designed so that it can be used either to execute PDF
+% (the default) or to convert PDF to PostScript. See ! and ~ below.
+
+userdict /GS_PDF_ProcSet 127 dict dup begin
+
+% ---------------- Abbreviations ---------------- %
+
+/bdef { bind def } bind def
+
+% ---------------- Operator execution ---------------- %
+
+% We record "operator" names in a dictionary with their argument counts,
+% so that they can easily be redefined later to write PostScript in
+% addition to (or instead of) being executed.
+
+/numargsdict 100 dict def
+/! % <procname> <proc> <numargs> ! -
+ { //numargsdict 3 index 3 -1 roll put def
+ } bdef
+/~ % <procname> <opname> <numargs> ~ -
+ { exch cvx 1 packedarray cvx exch !
+ } bdef
+
+% ---------------- Graphics state stack ---------------- %
+
+% PDF adds a number of parameters to the graphics state.
+% We implement this by pushing and popping a dictionary
+% each time we do a PDF gsave or grestore.
+% The keys in this dictionary are as follows:
+% self % identifies the dictionary as one of ours
+% Show
+% TextOrigin % origin of current line, in text space
+% TextSaveMatrix % matrix at time of BT
+% (The following correspond directly to PDF state parameters.)
+% FillColor
+% FillColorSpace
+% StrokeColor
+% StrokeColorSpace
+% TextSpacing
+% TextHScaling
+% Leading
+% TextFont
+% TextMatrix
+% TextRise
+% TextRenderingMode
+% WordSpacing
+
+/nodict 1 dict def
+nodict /self { //nodict } executeonly put
+nodict readonly pop
+
+/beginpage
+ { //nodict 20 dict .copydict begin graphicsbeginpage textbeginpage
+ } bdef
+/endpage
+ { showpage end
+ } bdef
+
+/graphicsbeginpage { initgraphics 0 g 0 G } bdef
+
+/gput % <value> <key> gput -
+ { exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
+ % If we're in a Level 1 system, we need to grow the
+ % dictionary explicitly.
+ currentdict length currentdict maxlength ge %eq
+ { currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin
+ }
+ if def
+ } bdef
+
+/q_
+ { gsave //nodict begin
+ } bdef
+/q /q_ load 0 !
+% Some PDF files have excess Q operators!
+/Q_
+ { currentdict /self .knownget { exec //nodict eq { end grestore } if } if
+ } bdef
+/Q /Q_ load 0 !
+
+% ---------------- Graphics state parameters ---------------- %
+
+/d /setdash 2 ~
+/i /setflat 1 ~
+/j /setlinejoin 1 ~
+/J /setlinecap 1 ~
+/M /setmiterlimit 1 ~
+/w /setlinewidth 1 ~
+
+% ---------------- Color setting ---------------- %
+
+/fcput % <color> <colorspace> fcput -
+ { /FillColorSpace gput /FillColor gput
+ } bdef
+/scput % <color> <colorspace> scput -
+ { /StrokeColorSpace gput /StrokeColor gput
+ } bdef
+
+/csdevgray [/DeviceGray] readonly def
+/csdevrgb [/DeviceRGB] readonly def
+/csdevcmyk [/DeviceCMYK] readonly def
+% Perhaps some of the values in the following need to be modified
+% depending on the WhitePoint value....
+/cslabinit mark
+ /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]
+ /MatrixABC [1 1 1 1 0 0 0 0 -1]
+ /DecodeLMN [
+ {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse
+ 0.9505 mul} bind
+ {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse
+ } bind
+ {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse
+ 1.0890 mul} bind
+ ]
+.dicttomark readonly def
+/nullpattern1 mark
+ /PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 0 0]
+ /XStep 1 /YStep 1 /PaintProc { }
+.dicttomark readonly def
+/nullpattern2 nullpattern1 dup length dict copy readonly def
+
+% Each entry in the color space dictionary is a procedure of the form
+% <cspace> -proc- <initial-color> <cspace'>
+/CSdict 11 dict dup begin
+ /DeviceGray { 0 exch } bdef
+ /DeviceRGB { [0 0 0] cvx exch } bdef
+ /DeviceCMYK { [0 0 0 1] cvx exch } bdef
+ /Indexed
+ { dup 1 get csset exch pop
+ dup 2 index 1 get eq
+ { pop }
+ { exch 4 array copy dup 1 4 -1 roll put }
+ ifelse 0 exch
+ } bdef
+ /CalGray
+ { systemdict /setcolorrendering known
+ { 1 get dup /Gamma .knownget
+ { dup length 1 add dict .copydict
+ dup /DecodeA 4 -1 roll /exp load 2 packedarray cvx put
+ }
+ if /CIEBasedA exch 2 array astore 0 exch
+ }
+ { pop //csdevgray csset
+ }
+ ifelse
+ } bdef
+ /CalRGB
+ { systemdict /setcolorrendering known
+ { 1 get dup /Gamma known 1 index /Matrix known or
+ { dup length 2 add dict .copydict
+ dup /Matrix .knownget { 1 index /MatrixABC 3 -1 roll put } if
+ dup /Gamma .knownget
+ { [ exch { /exp load 2 packedarray cvx } forall
+ ] 1 index /DecodeABC 3 -1 roll put
+ }
+ if
+ }
+ if /CIEBasedABC exch 2 array astore [0 0 0] cvx exch
+ }
+ { pop //csdevrgb csset
+ }
+ ifelse
+ } bdef
+ /CalCMYK { pop //csdevcmyk csset } bdef % not supported yet
+ /Lab
+ { systemdict /setcolorrendering known
+ { 1 get dup length 3 add dict .copydict
+ dup /Range .knownget not { [-100 100 -100 100] } if
+ [-100 0 null null null null] dup 2 4 -1 roll putinterval
+ 1 index /RangeABC 3 -1 roll put
+ //cslabinit exch copy
+ /CIEBasedABC exch 2 array astore [0 0 0] cvx exch
+ }
+ { (****** Lab color space not supported. ******\n) print flush
+ /setcolorspace cvx /undefined signalerror
+ }
+ ifelse
+ } bdef
+ /Pattern
+ { //nullpattern1 1 index type /nametype ne
+ { 1 index length 0 ne { pop //nullpattern2 } if
+ } if
+ matrix makepattern exch
+ } bdef
+ /Separation { 1 exch } bdef
+end def
+/csset % <cspace> csset <color> <cspace'>
+ { dup dup type /nametype ne { 0 get } if //CSdict exch get exec
+ } bdef
+
+/g { //csdevgray fcput } 1 !
+/G { //csdevgray scput } 1 !
+/rg { 3 array astore cvx //csdevrgb fcput } 3 !
+/RG { 3 array astore cvx //csdevrgb scput } 3 !
+/k { 4 array astore cvx //csdevcmyk fcput } 4 !
+/K { 4 array astore cvx //csdevcmyk scput } 4 !
+/cs { csset fcput } 1 !
+/CS { csset scput } 1 !
+% We have to break up sc according to the number of operands.
+/sc1 { /FillColor gput } 1 !
+/SC1 { /StrokeColor gput } 1 !
+/sc2 { /FillColor gput } 2 !
+/SC2 { /StrokeColor gput } 2 !
+/sc3 { /FillColor load astore pop } 3 !
+/SC3 { /StrokeColor load astore pop } 3 !
+/sc4 { /FillColor load astore pop } 4 !
+/SC4 { /StrokeColor load astore pop } 4 !
+/sc5 { /FillColor gput } 5 !
+/SC5 { /StrokeColor gput } 5 !
+
+% ---------------- Color installation ---------------- %
+
+% Establish a given color (and color space) as current.
+/setfillcolor { FillColor FillColorSpace setgcolor } def
+/setstrokecolor { StrokeColor StrokeColorSpace setgcolor } def
+/CIdict mark % only used for Level 1
+ /DeviceGray 1 /DeviceRGB 3 /DeviceCMYK 4
+ /CIEBaseA 1 /CIEBaseABC 3 /CIEBasedDEF 3 /CIEBaseDEFG 4
+.dicttomark def
+/Cdict 11 dict dup begin % <color...> <colorspace> -proc- -
+ /DeviceGray { pop setgray } bdef
+ /DeviceRGB { pop setrgbcolor } bdef
+ /DeviceCMYK { pop setcmykcolor } bdef
+ /CIEBasedA
+ { dup currentcolorspace eq { pop } { setcolorspace } ifelse setcolor } bdef
+ /CIEBasedABC /CIEBasedA load def
+ /CIEBasedDEF /CIEBasedA load def
+ /CIEBasedDEFG /CIEBasedA load def
+ /Indexed /setcolorspace where
+ { pop /CIEBasedA load }
+ { /setindexedcolor cvx }
+ ifelse def
+ /Pattern
+ { dup currentcolorspace eq { pop } { setcolorspace } ifelse
+ dup /Matrix get makepattern setcolor
+ } bdef
+ /Separation /CIEBasedA load def
+end def
+/setindexedcolor % <index> [/Indexed base hival proc|str]
+ % setindexedcolor - (only used for Level 1)
+ { mark 3 -1 roll
+ 2 index 3 get % Stack: cspace -mark- index proc|str
+ dup type /stringtype eq
+ { //CIdict 4 index 1 get 0 get get % # of components
+ dup 4 -1 roll mul exch getinterval { 255 div } forall
+ }
+ { exec
+ }
+ ifelse
+ counttomark 2 add -2 roll pop
+ 1 get setgcolor
+ } bdef
+/setgcolor % (null | <color...>) <colorspace> setgcolor -
+ { 1 index null eq
+ { pop pop }
+ { dup 0 get //Cdict exch get exec }
+ ifelse
+ } bdef
+/fsexec % <fillop|strokeop> fsexec -
+ { % Preserve the current point, if any.
+ { currentpoint } stopped
+ { $error /newerror false put cvx exec }
+ { 3 -1 roll cvx exec moveto }
+ ifelse
+ } bdef
+
+% ---------------- Transformations ---------------- %
+
+/cmmatrix matrix def
+/cm { //cmmatrix astore concat } 6 !
+
+% ---------------- Path creation ---------------- %
+
+/m /moveto 2 ~
+/l /lineto 2 ~
+/c /curveto 6 ~
+/h /closepath 0 ~
+/v { currentpoint 6 2 roll curveto } 4 !
+/y { 2 copy curveto } 4 !
+/re
+ { 4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto
+ closepath
+ } 4 !
+
+% ---------------- Path painting and clipping ---------------- %
+
+/S_ { setstrokecolor /stroke fsexec } bdef
+/S { S_ } 0 !
+/f { setfillcolor /fill fsexec } 0 !
+/f* { setfillcolor /eofill fsexec } 0 !
+/n_ { newpath } bdef % don't allow n_ to get bound in
+/n { n_ } 0 !
+/s { closepath S_ } 0 !
+/B_ { gsave setfillcolor fill grestore S_ } bdef
+/B /B_ load 0 !
+/b { closepath B_ } 0 !
+/B*_ { gsave setfillcolor eofill grestore S_ } bdef
+/B* /B*_ load 0 !
+/b* { closepath B*_ } 0 !
+
+% Clipping:
+
+/Wdict 4 dict dup begin
+/S_ { gsave setstrokecolor stroke grestore n_ } bdef
+/f { gsave setfillcolor fill grestore n_ } 0 !
+/f* { gsave setfillcolor eofill grestore n_ } 0 !
+/n_ { end clip newpath } bdef
+end readonly def
+/W { //Wdict begin } 0 !
+/W*dict 4 dict dup begin
+/S_ { gsave setstrokecolor stroke grestore n_ } bdef
+/f { gsave setfillcolor fill grestore n_ } 0 !
+/f* { gsave setfillcolor eofill grestore n_ } 0 !
+/n_ { end eoclip newpath } bdef
+end readonly def
+/W* { //W*dict begin } 0 !
+
+% ---------------- Images ---------------- %
+
+% We mustn't bind these now, since they reference Level 2 operators.
+/Is % <imagedict> Is <imagedict> <datasource>
+ { dup /DataSource get string /readstring cvx /currentfile cvx
+ % Stack: imagedict string -readstring- -currentfile-
+ 3 index /FilterProc .knownget
+ { dup dup 0 get /ASCIIHexDecode eq exch length 2 eq and
+ { pop exch pop /readhexstring cvx exch }
+ { exch exec exch exec }
+ ifelse
+ }
+ if 3 1 roll /pop cvx 4 packedarray cvx
+ } bdef
+/EI { } def % placeholder, only needed when writing PostScript
+% Note that ID* take a dictionary, not separate values;
+% ColorSpace must be a name if it has no parameters;
+% DataSource is the size of the row buffer in bytes;
+% FilterProc is an optional procedure for constructing the decoding filter;
+% and ImageMask is required, not optional.
+/csimage
+ { /setcolorspace where
+ { pop dup /ColorSpace get csset setcolorspace pop image }
+ { .colorspaceimage }
+ ifelse
+ } def % don't bind, because of Level 2
+/ID % <imagedict> ID -
+ { Is dup 3 -1 roll dup /ImageMask get
+ { setfillcolor dup /Interpolate .knownget not { false } if
+ { dup /DataSource 4 -1 roll put /imagemask cvx exec
+ }
+ { { /Width /Height /Decode /ImageMatrix }
+ { 1 index exch get exch }
+ forall pop exch 0 get 0 ne exch
+ 5 -1 roll imagemask
+ }
+ ifelse
+ }
+ { dup /ColorSpace get /DeviceGray eq
+ 1 index /BitsPerComponent get 8 le and
+ 1 index /Decode get dup 1 get 1 eq exch 0 get 0 eq and and
+ 1 index /Interpolate .knownget not { false } if not and
+ { { /Width /Height /BitsPerComponent /ImageMatrix }
+ { 1 index exch get exch }
+ forall pop 5 -1 roll image
+ }
+ { dup /DataSource 4 -1 roll put csimage
+ }
+ ifelse
+ }
+ ifelse
+ % If we were reading with readhexstring,
+ % skip the terminating > now.
+ % Stack: datasource
+ dup type /filetype ne % array or packedarray
+ { dup 2 get /readhexstring eq
+ { { dup 0 get exec read pop (>) 0 get eq { exit } if } loop
+ }
+ if pop
+ }
+ { pop
+ }
+ ifelse EI
+ } 1 !
+% IDx handles general images.
+/IDx % <imagedict> IDx -
+ { Is 1 index /DataSource 3 -1 roll put
+ csimage EI
+ } 1 !
+
+% ---------------- Text control ---------------- %
+
+/textbeginpage
+ { /TextSpacing 0 def % 0 Tc
+ /TextLeading 0 def % 0 TL
+ /TextRenderingMode 0 def % 0 Tr
+ /TextRise 0 def % 0 Ts
+ /WordSpacing 0 def % 0 Tw
+ /TextHScaling 1.0 def % 100 Tz
+ /TextFont null def
+ /Show { showfirst } def
+ } bdef
+
+% Contrary to the statement in the PDF manual, BT and ET *can* be nested,
+% if the CharProc for a Type 3 font does a BT/ET itself.
+% Since we always call the CharProc inside a q_/Q_, we simply ensure that
+% the text state is saved and restored like the rest of the extended
+% graphics state.
+
+/settextmatrix
+ { TextMatrix concat
+ TextHScaling 1 ne { TextHScaling 1 scale } if
+ TextRise 0 ne { 0 TextRise translate } if
+ } bdef
+/settextstate { TextSaveMatrix setmatrix settextmatrix } bdef
+
+/BT
+ { currentdict /TextMatrix .knownget
+ { identmatrix pop }
+ { matrix /TextMatrix gput }
+ ifelse
+ currentdict /TextOrigin .knownget
+ { dup 0 0 put 1 0 put }
+ { [0 0] cvx /TextOrigin gput }
+ ifelse
+ { showfirst } /Show gput
+ currentdict /TextSaveMatrix .knownget not
+ { matrix dup /TextSaveMatrix gput }
+ if currentmatrix pop settextmatrix 0 0 moveto
+ TextFont dup null eq { pop } { setfont } ifelse
+ } bind 0 !
+/ET
+ { TextSaveMatrix setmatrix
+ } bind 0 !
+/Tc_ { /TextSpacing gput { showfirst } /Show gput } bdef
+/Tc { Tc_ } 1 !
+/TL { /TextLeading gput } bind 1 !
+/Tr { /TextRenderingMode gput { showfirst } /Show gput } bind 1 !
+/Ts { /TextRise gput settextstate } bind 1 !
+/Tw_ { /WordSpacing gput { showfirst } /Show gput } bdef
+/Tw { Tw_ } 1 !
+/Tz { 100 div /TextHScaling gput settextstate } bind 1 !
+
+% ---------------- Font control ---------------- %
+
+/Tf % <font> <scale> Tf -
+ { dup 1 eq { pop } { scalefont } ifelse
+ dup setfont /TextFont gput
+ } 2 !
+
+% Read a CFF font.
+/FRD % <resdict> <file> FRD -
+ { /FontSetInit /ProcSet findresource begin ReadData
+ } 2 !
+
+% Copy a font, removing its FID. If changed is true, also remove
+% the UniqueID and XUID, if any. If the original dictionary doesn't have
+% the keys being removed, don't copy it.
+/.copyfontdict % <font> <changed> .copyfontdict <dict>
+ { 1 index /FID known
+ 1 index { 2 index /UniqueID known or 2 index /XUID known or } if
+ { % We add 1 to the length just in case the original
+ % didn't have a FID.
+ exch dup length 1 add dict exch
+ { % Stack: changed newfont key value
+ 1 index /FID eq 4 index
+ { 2 index /UniqueID eq or 2 index /XUID eq or }
+ if not { 3 copy put } if pop pop
+ }
+ forall exch
+ }
+ if pop
+ } bdef
+
+% Insert a new Encoding or Metrics into a font if necessary.
+% Return a possibly updated font, and a flag to indicate whether
+% the font was actually copied.
+/.updatefont % <font> <Encoding|null> <Metrics|null> .updatefont
+ % <font'> <copied>
+ { 2 index 4 1 roll
+ dup null ne
+ { 3 -1 roll true .copyfontdict dup /Metrics 4 -1 roll put exch }
+ { pop }
+ ifelse
+ dup null ne 1 index 3 index /Encoding get ne and
+ { exch false .copyfontdict dup /Encoding 4 -1 roll put }
+ { pop }
+ ifelse exch 1 index ne
+ } bdef
+
+% ---------------- Text positioning ---------------- %
+
+/Td_
+ { TextOrigin exch 4 -1 roll add 3 1 roll add
+ 2 copy /TextOrigin load astore pop moveto
+ } bdef
+/Td { Td_ } 2 !
+/TD { dup neg /TextLeading gput Td_ } 2 !
+/T*_ { 0 TextLeading neg Td_ } bdef
+/T* { T*_ } 0 !
+/Tm
+ { TextMatrix astore pop settextstate
+ 0 0 /TextOrigin load astore pop
+ 0 0 moveto
+ } 6 !
+
+% ---------------- Text painting ---------------- %
+
+/textrenderingprocs [ % (0 is handled specially)
+ { tf } { tS } { tB } { tn }
+ % We don't know what the clipping modes mean....
+ 4 copy
+] readonly def
+/setshowstate
+ { WordSpacing 0 eq TextSpacing 0 eq and
+ { TextRenderingMode 0 eq
+ { { setfillcolor show } }
+ { { false charpath textrenderingprocs TextRenderingMode get exec } }
+ ifelse
+ }
+ { TextRenderingMode 0 eq
+ { WordSpacing 0 eq
+ { { setfillcolor TextSpacing exch 0 exch ashow } }
+ { TextSpacing 0 eq
+ { { setfillcolor WordSpacing exch 0 exch 32 exch widthshow } }
+ { { setfillcolor WordSpacing exch TextSpacing exch 0 32 4 2 roll 0 exch awidthshow } }
+ ifelse
+ }
+ ifelse
+ }
+ { { WordSpacing TextSpacing 2 index
+ % Implement the combination of t3 and false charpath.
+ % Stack: xword xchar string
+ 0 1 2 index length 1 sub
+ { 2 copy 1 getinterval false charpath
+ % Stack: xword xchar string i
+ 4 copy get 32 eq { add } { exch pop } ifelse 0 rmoveto
+ pop
+ }
+ for pop pop pop pop
+ textrenderingprocs TextRenderingMode get exec
+ }
+ }
+ ifelse
+ }
+ ifelse /Show gput
+ } bdef
+/showfirst { setshowstate Show } def
+
+/Tj { Show } 1 !
+/' { T*_ Show } 1 !
+/" { exch Tc_ exch Tw_ T*_ Show } 3 !
+% TJ expects a mark followed by arguments, not an array.
+/TJ
+ { counttomark -1 1
+ { -1 roll dup type /stringtype eq
+ { Show
+ }
+ { -1000 div
+ currentfont /ScaleMatrix .knownget { 0 get mul } if
+ 0 rmoveto
+ }
+ ifelse
+ }
+ for pop
+% Adobe implementations don't accept /[, so we don't either.
+ } ([) cvn !
+
+/tf { setfillcolor currentpoint fill moveto } bdef
+/tn { currentpoint newpath moveto } bdef
+% For stroking characters, temporarily restore the graphics CTM so that
+% the line width will be transformed properly.
+/Tmatrix matrix def
+/tS
+ { setstrokecolor
+ currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke
+ setmatrix moveto
+ } bdef
+/tB { gsave tf grestore tS } bdef
+
+end readonly put % GS_PDF_ProcSet
+
+setglobal
diff --git a/gs/lib/gs_pdf_e.ps b/gs/lib/gs_pdf_e.ps
new file mode 100644
index 000000000..c0c935653
--- /dev/null
+++ b/gs/lib/gs_pdf_e.ps
@@ -0,0 +1,45 @@
+% Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the PDFDoc encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/PDFDocEncoding
+ISOLatin1Encoding 0 24 getinterval aload pop
+ /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde
+ISOLatin1Encoding 32 7 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 31 getinterval aload pop
+% \20x
+ /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction
+ /guilsinglleft /guilsinglright /minus /perthousand
+ /quotedblbase /quotedblleft /quotedblright /quoteleft
+ /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron
+ /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron /.notdef
+% \24x
+ /.notdef
+ISOLatin1Encoding 161 12 getinterval aload pop
+ /.notdef
+ISOLatin1Encoding 174 82 getinterval aload pop
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_pdfwr.ps b/gs/lib/gs_pdfwr.ps
new file mode 100644
index 000000000..e4b079aac
--- /dev/null
+++ b/gs/lib/gs_pdfwr.ps
@@ -0,0 +1,377 @@
+% Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% gs_pdfwr.ps
+% PDF writer additions to systemdict.
+
+% This file should be included iff the pdfwrite "device" is included
+% in the executable.
+
+% Redefine pdfmark to pass the data to the driver.
+% We use a pseudo-parameter named /pdfmark whose value is an array:
+% key1 value1 ... CTM /type
+/.pdf===dict mark
+ /arraytype
+ { dup xcheck { ({) (}) } { ([) (]) } ifelse
+ % Stack: file obj left right
+ 4 1 roll 2 index exch writestring () exch
+ { exch 2 index exch writestring
+ 1 index exch pdfmark===only ( )
+ }
+ forall pop exch writestring
+ } bind
+ /packedarraytype 1 index
+ /dicttype
+ { 1 index (<<\n) writestring
+ { 2 index 3 -1 roll pdfmark===only 1 index ( ) writestring
+ 1 index exch pdfmark===only dup (\n) writestring
+ }
+ forall (>>) writestring
+ } bind
+.dicttomark readonly def
+/pdfmark===only % <file> <obj> pdfmark===only -
+ { .pdf===dict 1 index type .knownget { exec } { write==only } ifelse
+ } bind def
+/.pdfcvs % <obj> .pdfcvs <string>
+ { % We can't handle long values yet.
+ =string /NullEncode filter dup 2 index pdfmark===only
+ dup (\n\000) writestring closefile pop
+ =string (\n\000) search
+ { dup length string copy exch pop exch pop }
+ { % The converted representation didn't fit. Punt.
+ pop (???)
+ }
+ ifelse
+ } bind def
+/.pdfputparams % <paramarray> <paramname> .pdfputparams <result...>
+ { currentdevice null false mark 6 -2 roll exch
+ % Don't allow the page device to get cleared....
+ {.putdeviceparams} 0 get .currentpagedevice pop {.setpagedevice} 0 get
+ 3 array astore cvx exec
+ } bind def
+/pdfmark % -mark- <key> <value> ... <markname> pdfmark -
+ { counttomark 1 add copy
+ matrix currentmatrix .pdfcvs exch ]
+ 1 2 2 index length 3 sub { 2 copy 2 copy get .pdfcvs put pop } for
+ /pdfmark .pdfputparams
+ type /booleantype ne { cleartomark } if cleartomark
+ } odef
+userdict /pdfmark .undef
+
+% Define setdistillerparams / currentdistillerparams.
+% Distiller parameters are currently treated as device parameters.
+/.distillerparamkeys mark
+ % General parameters
+ /ASCII85EncodePages { }
+ /AutoRotatePages { }
+ /CompatibilityLevel { }
+ /CompressPages { }
+ /CoreDistVersion { }
+ /DoThumbnails { }
+ /ImageMemory { }
+ /LZWEncodePages { }
+ /PreserveHalftoneInfo { }
+ /PreserveOPIComments { }
+ /PreserveOverprintSettings { }
+ /TransferFunctionInfo { }
+ /UCRandBGInfo { }
+ /UseFlateCompression { }
+ % Color sampled image parameters
+ /ColorACSDict { }
+ /AntiAliasColorImages { }
+ /AutoFilterColorImages { }
+ /ColorImageDepth { }
+ /ColorImageDict { }
+ /DownsampleColorImages { }
+ /ColorImageDownsampleType { }
+ /EncodeColorImages { }
+ /ColorImageFilter { }
+ /ColorImageResolution { }
+ /ColorConversionStrategy { }
+ /ConvertCMYKImagesToRGB { }
+ /ConvertImagesToIndexed { }
+ % Grayscale sampled image parameters
+ /GrayACSDict { }
+ /AntiAliasGrayImages { }
+ /AutoFilterGrayImages { }
+ /GrayImageDepth { }
+ /GrayImageDict { }
+ /DownsampleGrayImages { }
+ /GrayImageDownsampleType { }
+ /EncodeGrayImages { }
+ /GrayImageFilter { }
+ /GrayImageResolution { }
+ % Monochrome sampled image parameters
+ /AntiAliasMonoImages { }
+ /MonoImageDepth { }
+ /MonoImageDict { }
+ /DownsampleMonoImages { }
+ /MonoImageDownsampleType { }
+ /EncodeMonoImages { }
+ /MonoImageFilter { }
+ /MonoImageResolution { }
+ % Font embedding parameters
+ /AlwaysEmbed
+ { dup length 0 gt
+ { dup 0 get false eq
+ { dup length 1 sub 1 exch getinterval exch pop /~AlwaysEmbed exch
+ } if
+ } if
+ }
+ /NeverEmbed
+ { dup length 0 gt
+ { dup 0 get false eq
+ { dup length 1 sub 1 exch getinterval exch pop /~NeverEmbed exch
+ } if
+ } if
+ }
+ /EmbedAllFonts { }
+ /SubsetFonts { }
+ /MaxSubsetPct { }
+.dicttomark readonly def
+/.distillerdevice
+ { currentdevice .devicename /pdfwrite eq
+ { currentdevice }
+ { /pdfwrite finddevice }
+ ifelse
+ } bind def
+/setdistillerparams % <dict> setdistillerparams -
+ { .distillerdevice null false mark 4 index
+ { //.distillerparamkeys 2 index .knownget { exec } { pop pop } ifelse }
+ forall .putdeviceparams
+ type /booleantype eq { pop } { cleartomark pop pop pop } ifelse pop
+ } odef
+/currentdistillerparams % - currentdistillerparams <dict>
+ { .distillerdevice //.distillerparamkeys .getdeviceparams .dicttomark
+ } odef
+
+% Patch the 'show' operators to pass the data to the device.
+% We use a pseudo-parameter named /show whose value is a dictionary:
+% /String (str)
+% /Values [cx cy char ax ay px py]
+% /FontName /fontname
+% /Matrix [xx xy yx yy tx ty]
+% /Encoding [e0 .. e255]
+% (optional, omitted if Encoding = BaseEncoding = StandardEncoding)
+% /BaseEncoding [e0 ... e255] (optional, ditto)
+% /CharStrings << charnames => anything >> (optional)
+% Note that the cx/y and ax/y values are in text space, not user space.
+% We also fill an empty path in order to get the clipping region and
+% current color set properly. THIS IS A BIG HACK.
+/.pdfknownfonts mark
+ /Courier {StandardEncoding}
+ /Courier-Bold 1 index
+ /Courier-Oblique 1 index
+ /Courier-BoldOblique 1 index
+ /Helvetica 1 index
+ /Helvetica-Bold 1 index
+ /Helvetica-Oblique 1 index
+ /Helvetica-BoldOblique 1 index
+ /Times-Roman 1 index
+ /Times-Bold 1 index
+ /Times-Italic 1 index
+ /Times-BoldItalic 1 index
+ /Symbol {SymbolEncoding}
+ /ZapfDingbats {DingbatsEncoding}
+.dicttomark readonly def
+.currentglobal false .setglobal
+/.pdfknownids 50 dict def
+.setglobal
+/.findorigfont { % <font> .findorigfont <origfont>
+ % Check for a known font with the same name,
+ % or one of the 14 known names,
+ % and the same UniqueID.
+ dup /UniqueID .knownget {
+ .pdfknownids 1 index .knownget {
+ exch pop dup null ne { true } { pop false } ifelse
+ } { % We haven't looked up the UniqueID yet.
+ % Register the UniqueIDs of all fonts.
+ .FontDirectory {
+ exch pop dup /UniqueID .knownget {
+ % Stack: font uniqueid somefont somefontid
+ exch .pdfknownids 3 1 roll put
+ } {
+ pop
+ } ifelse
+ } forall
+ % Register the UniqueIDs of the 14 built-in fonts,
+ % to make sure they override any other fonts
+ % with the same UniqueIDs.
+ .pdfknownfonts {
+ pop
+ //systemdict /GlobalFontDirectory .knownget not { .FontDirectory } if
+ 1 index .knownget {
+ % Stack: font uniqueid knownname knownfont
+ dup /UniqueID get exch .pdfknownids 3 1 roll put
+ } if pop
+ } forall
+ % Now see if the UniqueID is known.
+ .pdfknownids 1 index .knownget {
+ exch pop true
+ } { % Record the UniqueID as not registered.
+ .pdfknownids exch null put false
+ } ifelse
+ } ifelse
+ } { % This font has no UniqueID.
+ false
+ } ifelse
+ % Stack: font knownfont -true- | font -false-
+ {
+ exch pop
+ } {
+ { dup /OrigFont .knownget not { exit } if exch pop } loop
+ } ifelse
+} .bind def
+/setvmthreshold where { pop 1000000 setvmthreshold } if
+/.pdfdoshow % <string> <cxd> <cyd> <char> <axd> <ayd> .pdfdoshow
+ % <bool>
+ { mark /String 8 2 roll
+%vmstatus pop =only pop (, ) print
+ currentpoint transform 7 array astore /Values exch
+ currentfont .findorigfont
+ % Pass the original font name.
+ dup /FontName get
+ /FontName exch 3 -1 roll
+ % Concatenate the "quotient" of the current FontMatrix
+ % and the FontMatrix of the original font.
+ % Be sure to include any translation.
+ /Matrix
+ exch /FontMatrix get matrix invertmatrix
+ currentfont /FontMatrix get 1 index concatmatrix
+ % The matrix on the stack is now the font scaling matrix.
+ % Use it to inverse-transform cx/y and ax/y, so they will be in
+ % text space.
+ % Stack: mark /String <string> /Values <values> /FontName <fontname>
+ % /Matrix <matrix>
+ 4 index aload
+ % ... cx cy char ax ay px py values
+ 8 -2 roll 8 index idtransform 8 2 roll
+ 5 -2 roll 8 index idtransform 5 2 roll
+ astore pop
+ % Now construct the combined matrix.
+ matrix currentmatrix dup 4 0 put dup 5 0 put dup concatmatrix
+ % Omit either encoding that is StandardEncoding.
+ /Encoding currentfont /Encoding .knownget not { [] } if
+ dup StandardEncoding eq { pop pop } if
+ % Make a reasonable guess at the base encoding.
+ /BaseEncoding .pdfknownfonts 6 index % FontName
+ .knownget { exec } { StandardEncoding } ifelse
+ dup StandardEncoding eq {
+ pop pop
+ } {
+ currentfont /CharStrings .knownget { /CharStrings exch } if
+ } ifelse
+%vmstatus pop =only pop (, ) print
+ .dicttomark
+ % Set the clipping region and color in the output.
+ % This is another hack!
+ gsave newpath fill grestore
+%vmstatus pop =only pop (, ) print
+ /show .pdfputparams
+%vmstatus pop =only pop () = flush
+ dup type /booleantype eq
+ { pop pop true }
+ { dup /undefined eq
+ { cleartomark pop pop pop false }
+ { dup mark eq { /unknown /rangecheck } if
+ counttomark 4 add 1 roll cleartomark pop pop pop
+ /.pdfshow cvx exch signalerror
+ }
+ ifelse
+ }
+ ifelse
+ } .bind def
+/.pdfexecshow % <proc> .pdfexecshow -
+ { % Prevent output, but don't switch devices, since this
+ % confuses the Pattern caching mechanism.
+ gsave currentpoint newpath clip moveto exec currentpoint
+ grestore moveto
+ } .bind def
+/.pdfwrite? % - .pdfwrite? <bool>
+ { currentdevice .devicename /pdfwrite eq
+ currentfont /FontType get 1 eq and
+ } .bind def
+% .pdfshow isn't an operator per se, but it still needs to be careful with
+% the stack so that the operators will have stack protection.
+/.pdfshow % <string> <cx> <cy> <char> <ax> <ay> <showproc>
+ % .pdfshow -
+ { 7 1 roll .pdfwrite?
+ { .pdfdoshow }
+ { 6 { pop } repeat false }
+ ifelse
+ { .pdfexecshow }
+ { exec }
+ ifelse
+ } .bind def
+/show
+ { dup 0 0 32 0 0 { show } .pdfshow
+ } .bind odef
+/ashow
+ { dup 0 0 32 6 index 6 index { ashow } .pdfshow
+ } .bind odef
+/widthshow
+ { 4 copy 4 1 roll 0 0 { widthshow } .pdfshow
+ } .bind odef
+/awidthshow
+ { 6 copy 6 1 roll { awidthshow } .pdfshow
+ } .bind odef
+/glyphshow where { pop } { (%END) .skipeof } ifelse
+/glyphshow
+ { .pdfwrite?
+ { currentfont /Encoding .knownget not { {} } if
+ 0 1 2 index length 1 sub
+ { % Stack: glyph encoding index
+ 2 copy get 3 index eq { exch pop exch pop null exit } if pop
+ }
+ for null eq
+ { (X) dup 0 3 index put show pop }
+ { glyphshow }
+ ifelse
+ }
+ { glyphshow
+ }
+ ifelse
+ } .bind odef
+%END
+/.kshow1 { % <index> <proc> <string> .kshow1
+ (X) dup 0 3 index 6 index get put show
+ 2 index 1 index length 1 sub lt {
+ dup 3 index get exch 4 -1 roll 1 add get
+ 3 -1 roll exec
+ } {
+ pop pop pop
+ } ifelse
+} .bind def
+/kshow {
+ .pdfwrite? {
+ % Construct a closure, and work character by character.
+ 0 1 2 index length 1 sub 5 -2 roll
+ //.kshow1 /exec cvx 4 packedarray cvx for
+ } {
+ kshow
+ } ifelse
+} .bind odef
+% The remaining operators aren't implemented correctly.
+/xshow where {
+ pop /xshow { .pdfwrite? { 1 index show pop pop } { xshow } ifelse } .bind odef
+} if
+/yshow where {
+ pop /yshow { .pdfwrite? { 1 index show pop pop } { yshow } ifelse } .bind odef
+} if
+/xyshow where {
+ pop /xyshow { .pdfwrite? { 1 index show pop pop } { xyshow } ifelse } .bind odef
+} if
diff --git a/gs/lib/gs_pfile.ps b/gs/lib/gs_pfile.ps
new file mode 100644
index 000000000..00190bf4c
--- /dev/null
+++ b/gs/lib/gs_pfile.ps
@@ -0,0 +1,128 @@
+% Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Runtime support for minimum-space fonts and packed files.
+
+% ****** NOTE: This file must be kept consistent with
+% ****** packfile.ps and wrfont.ps.
+
+% ---------------- Packed file support ---------------- %
+
+% A packed file is the concatenation of several file groups, each of which
+% is the result of compressing several files concatenated together.
+% The packed file begins with a procedure that creates an appropriate
+% decoding filter for each file group, as follows:
+% <group-subfile-filter> -proc- <group-decode-filter>
+% Thus, accessing an individual file requires 4 parameters:
+% the starting address and length of the outer compressed file,
+% and the starting address and length of the inner file.
+/.packedfilefilter % <file> <ostart> <olength> <istart> <ilength>
+ % .packedfilefilter <filter>
+ { 4 index systemdict begin token pop end 6 1 roll
+ % Stack: fproc file ostart olength istart ilength
+ 4 index 5 -1 roll setfileposition
+ % Stack: fproc file olength istart ilength
+ 4 -2 roll () /SubFileDecode filter
+ % Stack: fproc istart ilength ofilter
+ 4 -1 roll exec
+ % Filters don't support setfileposition, so we must skip data
+ % by reading it into a buffer. We rely on the fact that
+ % save/restore don't affect file positions.
+ % Stack: istart ilength dfilter
+ save exch 1000 string
+ % Stack: istart ilength save dfilter scratch
+ 4 index 1 index length idiv { 2 copy readstring pop pop } repeat
+ 2 copy 0 8 -1 roll 2 index length mod getinterval readstring pop pop pop
+ % Stack: ilength save dfilter
+ exch restore exch () /SubFileDecode filter
+ } bind def
+
+% Run a packed library file.
+/.runpackedlibfile % <filename> <ostart> <olength> <istart> <ilength>
+ % .runpackedlibfile
+ { 5 -1 roll findlibfile
+ { exch pop dup 6 2 roll .packedfilefilter
+ currentobjectformat exch 1 setobjectformat run
+ setobjectformat closefile
+ }
+ { 5 1 roll /findlibfile load /undefinedfilename signalerror
+ }
+ ifelse
+ } bind def
+
+% ---------------- Compacted font support ---------------- %
+
+% Compacted fonts written by wrfont.ps depend on the existence and
+% specifications of the procedures and data in this section.
+
+/.compactfontdefault mark
+ /PaintType 0
+ /FontMatrix [0.001 0 0 0.001 0 0] readonly
+ /FontType 1
+ /Encoding StandardEncoding
+.dicttomark readonly def
+
+/.checkexistingfont % <fontname> <uid> <privatesize> <fontsize>
+ % .checkexistingfont
+ % {} (<font> on d-stack)
+ % <fontname> <uid> <privatesize> <fontsize>
+ % .checkexistingfont
+ % -save- --restore-- (<font> on d-stack)
+ { FontDirectory 4 index .knownget
+ { dup /UniqueID .knownget
+ { 4 index eq exch /FontType get 1 eq and }
+ { pop false }
+ ifelse
+ }
+ { false
+ }
+ ifelse
+ { save /restore load 6 2 roll }
+ { {} 5 1 roll }
+ ifelse
+ dict //.compactfontdefault exch .copydict begin
+ dict /Private exch def
+ Private begin
+ /MinFeature {16 16} def
+ /Password 5839 def
+ /UniqueID 1 index def
+ end
+ /UniqueID exch def
+ /FontName exch def
+ } bind def
+
+/.knownEncodings [
+ ISOLatin1Encoding
+ StandardEncoding
+ SymbolEncoding
+] readonly def
+
+/.readCharStrings % <count> <encrypt> .readCharStrings <dict>
+ { exch dup dict dup 3 -1 roll
+ { currentfile token pop dup type /integertype eq
+ { dup -8 bitshift //.knownEncodings exch get exch 255 and get } if
+ currentfile token pop dup type /nametype eq
+ { 2 index exch get
+ }
+ { % Stack: encrypt dict dict key value
+ 4 index { 4330 exch dup .type1encrypt exch pop } if
+ readonly
+ }
+ ifelse put dup
+ }
+ repeat pop exch pop
+ } bind def
diff --git a/gs/lib/gs_res.ps b/gs/lib/gs_res.ps
new file mode 100644
index 000000000..8ce478525
--- /dev/null
+++ b/gs/lib/gs_res.ps
@@ -0,0 +1,665 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Initialization file for Level 2 resource machinery.
+% When this is run, systemdict is still writable,
+% but (almost) everything defined here goes into level2dict.
+
+level2dict begin
+
+(BEGIN RESOURCES) VMDEBUG
+
+% We keep track of (global) instances with another entry in the resource
+% dictionary, an Instances dictionary. For categories with implicit
+% instances, the values in Instances are the same as the keys;
+% for other categories, the values are [instance status size].
+
+% Note that the dictionary that defines a resource category is stored
+% in global memory. The PostScript manual says that each category must
+% manage global and local instances separately. However, objects in
+% global memory other than systemdict can't reference objects in local memory.
+% This means that the resource category dictionary, which would otherwise be
+% the obvious place to keep track of the instances, can't be used to keep
+% track of local instances. Instead, we define a dictionary in local VM
+% called localinstancedict, in which the key is the category name and
+% the value is the analogue of Instances for local instances.
+
+% We don't currently implement automatic resource unloading.
+% When and if we do, it should be hooked to the garbage collector.
+% However, Ed Taft of Adobe says their interpreters don't implement this
+% either, so we aren't going to worry about it for a while.
+
+currentglobal false setglobal systemdict begin
+ /localinstancedict 5 dict def
+end true setglobal
+/.emptydict 0 dict readonly def
+setglobal
+
+% Resource category dictionaries have the following keys (those marked with
+% * are optional):
+% Standard, defined in the Red Book:
+% Category (name)
+% *InstanceType (name)
+% DefineResource
+% <key> <instance> DefineResource <instance>
+% UndefineResource
+% <key> UndefineResource -
+% FindResource
+% <key> FindResource <instance>
+% ResourceStatus
+% <key> ResourceStatus <status> <size> true
+% <key> ResourceStatus false
+% ResourceForAll
+% <template> <proc> <scratch> ResourceForAll -
+% *ResourceFileName
+% <key> <scratch> ResourceFileName <filename>
+% Additional, specific to our implementation:
+% Instances (dictionary)
+% .LocalInstances
+% - .LocalInstances <dict>
+% .GetInstance
+% <key> .GetInstance <instance> -true-
+% <key> .GetInstance -false-
+% .CheckResource
+% <key> <value> .CheckResource <key> <value> <ok>
+% (or may give an error if not OK)
+% .DoLoadResource
+% <key> .DoLoadResource - (may give an error)
+% .LoadResource
+% <key> .LoadResource - (may give an error)
+% .ResourceFile
+% <key> .ResourceFile <file> -true-
+% <key> .ResourceFile <key> -false-
+% All the above procedures expect that the top dictionary on the d-stack
+% is the resource dictionary.
+
+% Define enough of the Category category so we can define other categories.
+% The dictionary we're about to create will become the Category
+% category definition dictionary.
+
+/.findcategory % <name> .findcategory <category>
+ { { /Category findresource } stopped { pop stop } if
+ } bind def
+
+/.resourceexec % <key> /xxxResource .resourceexec -
+ { % (also pops the category from the dstack)
+ load stopped { Category end stop } if end
+ } bind def
+
+12 dict begin
+
+ % Standard entries
+
+/Category /Category def
+/InstanceType /dicttype def
+
+/DefineResource
+ { .CheckResource
+ { dup /Category 3 index cvlit .growput
+ % We would like to make Category dictionaries read-only,
+ % and we used to do that here, but we can't do it,
+ % because we have to be able to replace the dummy, empty
+ % Instances dictionary with the real one later.
+ dup [ exch 0 -1 ] exch
+ Instances 4 2 roll put
+ }
+ { /defineresource load /typecheck signalerror
+ }
+ ifelse
+ } bind def
+/FindResource % (redefined below)
+ { Instances exch get 0 get
+ } bind def
+
+ % Additional entries
+
+/Instances 25 dict def
+Instances /Category [currentdict 0 -1] put
+
+/.LocalInstances 0 dict def
+/.GetInstance
+ { Instances exch .knownget
+ } bind def
+/.CheckResource
+ { dup gcheck currentglobal and
+ { /DefineResource /FindResource /ResourceForAll /ResourceStatus
+ /UndefineResource }
+ { 2 index exch known and }
+ forall
+ not { /defineresource load /invalidaccess signalerror } if
+ true
+ } bind def
+
+Instances end begin % for the base case of findresource
+
+(END CATEGORY) VMDEBUG
+
+% Define the resource operators. We use the "stack protection" feature of
+% odef to make sure the stacks are restored properly on an error.
+% This requires that the operators not pop anything from the stack until
+% they have executed their logic successfully. We can't make this
+% work for resourceforall, but we can make it work for the others.
+
+mark
+/defineresource { % <key> <instance> <category> defineresource <instance>
+ 3 copy .findcategory dup begin
+ /InstanceType known {
+ dup type InstanceType ne {
+ dup type /packedarraytype eq InstanceType /arraytype eq and
+ not { /defineresource load /typecheck signalerror } if
+ } if
+ } if
+ /DefineResource .resourceexec
+ 4 1 roll pop pop pop
+}
+/findresource { % <key> <category> findresource <instance>
+ 2 copy dup /Category eq
+ { pop //Category 0 get } { .findcategory } ifelse
+ begin
+ /FindResource .resourceexec exch pop exch pop
+}
+/resourceforall { % <template> <proc> <scratch> <category> resourceforall -
+ .findcategory begin /ResourceForAll .resourceexec
+}
+/resourcestatus { % <key> <category> resourcestatus <status> <size> true
+ % <key> <category> resourcestatus false
+ 2 copy .findcategory begin /ResourceStatus .resourceexec
+ { 4 2 roll pop pop true } { pop pop false } ifelse
+}
+/undefineresource { % <key> <category> undefineresource -
+ 2 copy .findcategory begin /UndefineResource .resourceexec pop pop
+}
+end % Instances of Category
+counttomark 2 idiv { bind odef } repeat pop
+
+% Define the system parameters used for the Generic implementation of
+% ResourceFileName.
+systemdict begin
+currentdict /systemparams known not { /systemparams 10 dict readonly def } if
+systemparams
+ dup /FontResourceDir (/Resource/Font/) readonly .forceput
+ dup /GenericResourceDir (/Resource/) readonly .forceput
+ dup /GenericResourcePathSep (/) readonly .forceput
+pop
+end
+
+% Define the generic algorithm for computing resource file names.
+/.rfnstring 100 string def
+/.genericrfn % <key> <scratch> <prefix> .genericrfn <filename>
+ { 3 -1 roll //.rfnstring cvs concatstrings exch copy
+ } bind def
+
+% Define the Generic category.
+
+/Generic mark
+
+ % Standard entries
+
+% We're still running in Level 1 mode, so dictionaries won't expand.
+% Leave room for the /Category entry.
+/Category null
+
+/DefineResource
+ { .CheckResource
+ { dup [ exch 0 -1 ]
+ % Stack: key value instance
+ currentglobal
+ { false setglobal 2 index UndefineResource % remove local def if any
+ true setglobal
+ Instances dup //.emptydict eq
+ { pop 3 dict /Instances 1 index def
+ }
+ if
+ }
+ { .LocalInstances dup //.emptydict eq
+ { pop 3 dict localinstancedict Category 2 index put
+ }
+ if
+ }
+ ifelse
+ % Stack: key value instance instancedict
+ 3 index 2 index .growput
+ % Now make the resource value read-only.
+ 0 2 copy get { readonly } .internalstopped pop
+ dup 4 1 roll put exch pop exch pop
+ }
+ { /defineresource load /typecheck signalerror
+ }
+ ifelse
+ } bind
+/UndefineResource
+ { { dup 2 index .knownget
+ { dup 1 get 1 ge
+ { dup 0 null put 1 2 put pop pop }
+ { pop exch .undef }
+ ifelse
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ currentglobal
+ { 2 copy Instances exch exec
+ }
+ if .LocalInstances exch exec
+ } bind
+/FindResource
+ { dup ResourceStatus
+ { pop 1 gt % not in VM
+ { .DoLoadResource
+ }
+ if
+ .GetInstance pop % can't fail
+ 0 get
+ }
+ { /findresource load /undefinedresource signalerror
+ }
+ ifelse
+ } bind
+/ResourceStatus
+ { dup .GetInstance
+ { exch pop dup 1 get exch 2 get true }
+ { .ResourceFile
+ { closefile 2 -1 true }
+ { pop false }
+ ifelse
+ }
+ ifelse
+ } bind
+/ResourceForAll
+ { % **************** Doesn't present instance groups in
+ % **************** the correct order yet.
+ % We construct a new procedure so we don't have to use
+ % static resources to hold the iteration state.
+ % Make sure it is in local VM, to avoid an invalidaccess.
+ 3 copy .currentglobal 4 1 roll false .setglobal
+ 3 packedarray % template, proc, scratch
+ { exch pop % stack contains: key, {template, proc, scratch}
+ 2 copy 0 get .stringmatch
+ { 1 index type dup /stringtype eq exch /nametype eq or
+ { 2 copy 2 get cvs
+ exch 1 get 3 -1 roll pop
+ }
+ { 1 get
+ }
+ ifelse exec
+ }
+ { pop pop
+ }
+ ifelse
+ } /exec cvx 3 packedarray cvx
+ % Stack: template proc scratch global? iterproc
+ % We must pop the resource dictionary off the dict stack
+ % when doing the actual iteration, and restore it afterwards.
+ currentglobal .LocalInstances length 0 eq or not
+ { % We must do local instances, and do them first.
+ /forall cvx 1 index currentdict 3 packedarray cvx
+ .LocalInstances 3 1 roll end exec begin
+ }
+ if
+ exch .setglobal
+ Instances exch
+ /forall cvx currentdict
+ end 2 .execn begin pop pop pop
+ } bind
+/ResourceFileName
+ { /GenericResourceDir getsystemparam
+ Category .namestring concatstrings
+ /GenericResourcePathSep getsystemparam concatstrings
+ .genericrfn
+ } bind
+
+ % Additional entries
+
+% Unfortunately, we can't create the real Instances dictionary now,
+% because if someone copies the Generic category (which pp. 95-96 of the
+% 2nd Edition Red Book says is legitimate), they'll wind up sharing
+% the Instances. Instead, we have to create Instances on demand,
+% just like the entry in localinstancedict.
+% We also have to prevent anyone from creating instances of Generic itself.
+/Instances //.emptydict
+
+/.LocalInstances
+ { localinstancedict Category .knownget not { //.emptydict } if
+ } bind
+/.GetInstance
+ { currentglobal
+ { Instances exch .knownget }
+ { .LocalInstances 1 index .knownget
+ { exch pop true }
+ { Instances exch .knownget }
+ ifelse
+ }
+ ifelse
+ } bind
+/.CheckResource
+ { true
+ } bind
+/.DoLoadResource
+ { dup vmstatus pop exch pop exch
+ .LoadResource
+ vmstatus pop exch pop exch sub
+ 1 index .GetInstance not
+ { pop dup /undefinedresource signalerror } % didn't load
+ if
+ dup 1 1 put
+ 2 3 -1 roll put
+ } bind
+/.LoadResource
+ { dup .ResourceFile
+ { exch pop currentglobal
+ { run }
+ { true setglobal { run } stopped false setglobal { stop } if }
+ ifelse
+ }
+ { dup /undefinedresource signalerror
+ }
+ ifelse
+ } bind
+/.ResourceFile
+ { currentdict /ResourceFileName known
+ { mark 1 index 100 string { ResourceFileName }
+ .internalstopped
+ { cleartomark false }
+ { exch pop findlibfile
+ { exch pop exch pop true }
+ { pop false }
+ ifelse
+ }
+ ifelse
+ }
+ { false }
+ ifelse
+ } bind
+
+.dicttomark
+/Category defineresource pop
+
+% Fill in the rest of the Category category.
+/Category /Category findresource dup
+/Generic /Category findresource begin
+ { /FindResource /ResourceForAll /ResourceStatus /UndefineResource /.ResourceFile }
+ { dup load put dup } forall
+pop readonly pop end
+
+(END GENERIC) VMDEBUG
+
+% Define the fixed categories.
+
+mark
+ % Things other than types
+ /ColorSpaceFamily
+ mark colorspacedict { pop } forall .packtomark
+ /Emulator
+ mark EMULATORS { cvn } forall .packtomark
+ /Filter
+ mark filterdict { pop } forall .packtomark
+ /IODevice
+ % Loop until the .getiodevice gets a rangecheck.
+ errordict /rangecheck 2 copy get
+ errordict /rangecheck { pop stop } put % pop the command
+ mark 0 { {dup .getiodevice exch 1 add} loop} .internalstopped
+ pop pop pop .packtomark
+ 4 1 roll put
+ .clearerror
+ % Types
+ /setcolorrendering where
+ { pop /ColorRenderingType
+ {1}
+ } if
+ /FMapType
+ { } % These must be deferred, because optional features may add some.
+ /FontType
+ { } % These must be deferred, because optional features may add some.
+ /FormType
+ {1}
+ /HalftoneType
+ {1 2 3 4 5}
+ /ImageType
+ {1}
+ /PatternType
+ {1} % should check for Pattern color space
+counttomark 2 idiv
+ { mark
+
+ % Standard entries
+
+ % We'd like to prohibit defineresource,
+ % but because optional features may add entries, we can't.
+ % We can at least require that the key and value match.
+ /DefineResource
+ { currentglobal not
+ { /defineresource load /invalidaccess signalerror }
+ { 2 copy ne
+ { /defineresource load /rangecheck signalerror }
+ { dup Instances 4 -2 roll .growput }
+ ifelse
+ }
+ ifelse
+ } bind
+ /UndefineResource
+ { /undefineresource load /invalidaccess signalerror } bind
+ /FindResource
+ { Instances 1 index .knownget
+ { exch pop }
+ { /findresource load /undefinedresource signalerror }
+ ifelse
+ } bind
+ /ResourceStatus
+ { Instances exch known { 0 0 true } { false } ifelse } bind
+ /ResourceForAll
+ /Generic /Category findresource /ResourceForAll get
+
+ % Additional entries
+
+ counttomark 2 add -1 roll
+ dup length dict dup begin exch { dup def } forall end
+ % We'd like to make the Instances readonly here,
+ % but because optional features may add entries, we can't.
+ /Instances exch
+ /.LocalInstances % used by ResourceForAll
+ 0 dict def
+
+ .dicttomark /Category defineresource pop
+ } repeat pop
+
+(END FIXED) VMDEBUG
+
+% Define the other built-in categories.
+
+/.definecategory % <name> -mark- <key1> ... <valuen> .definecategory -
+ { counttomark 2 idiv 2 add % Instances, Category
+ /Generic /Category findresource dup maxlength 3 -1 roll add
+ dict .copydict begin
+ counttomark 2 idiv { def } repeat pop % pop the mark
+ currentdict end /Category defineresource pop
+ } bind def
+
+/ColorRendering mark /InstanceType /dicttype .definecategory
+/ColorSpace mark /InstanceType /arraytype .definecategory
+/Form mark /InstanceType /dicttype .definecategory
+/Halftone mark /InstanceType /dicttype .definecategory
+/Pattern mark /InstanceType /dicttype .definecategory
+/ProcSet mark /InstanceType /dicttype .definecategory
+
+(END MISC) VMDEBUG
+
+% Define the Encoding category.
+
+/Encoding mark
+
+/InstanceType /arraytype
+
+% Handle already-registered encodings, including lazily loaded encodings
+% that aren't loaded yet.
+
+/Instances mark
+ EncodingDirectory
+ { dup length 256 eq { [ exch readonly 0 -1 ] } { pop [null 2 -1] } ifelse
+ } forall
+.dicttomark
+
+/.ResourceFileDict mark
+ EncodingDirectory
+ { dup length 256 eq { pop pop } { 0 get } ifelse
+ } forall
+.dicttomark
+
+/ResourceFileName
+ { .ResourceFileDict 2 index .knownget
+ { exch copy exch pop }
+ { /Generic /Category findresource /ResourceFileName get exec }
+ ifelse
+ } bind
+
+.definecategory % Encoding
+
+% Make placeholders in level2dict for the redefined Encoding operators,
+% so that they will be swapped properly when we switch language levels.
+
+/.findencoding /.findencoding load def
+/findencoding /findencoding load def
+/.defineencoding /.defineencoding load def
+
+(END ENCODING) VMDEBUG
+
+% Define the Font category.
+
+/Font mark
+
+/InstanceType /dicttype
+
+/DefineResource
+ { 2 copy //definefont exch pop
+ /Generic /Category findresource /DefineResource get exec
+ } bind
+/UndefineResource
+ { dup //undefinefont
+ /Generic /Category findresource /UndefineResource get exec
+ } bind
+/FindResource
+ { dup ResourceStatus
+ { pop 1 gt { .loadfont } { .GetInstance pop 0 get } ifelse }
+ { .loadfont }
+ ifelse
+ } bind
+/ResourceFileName
+ { /FontResourceDir getsystemparam .genericrfn
+ } bind
+
+/.loadfont
+ { dup vmstatus pop exch pop exch
+ //findfont exec exch % findfont is a procedure....
+ vmstatus pop exch pop exch sub
+ % stack: name font vmused
+ % findfont has the prerogative of not calling definefont
+ % in certain obscure cases of font substitution.
+ 2 index .GetInstance
+ { dup 1 1 put
+ 2 3 -1 roll put
+ }
+ { pop
+ }
+ ifelse exch pop
+ } bind
+
+/Instances FontDirectory length 2 mul dict
+
+.definecategory % Font
+
+% Redefine font "operators".
+/.definefontmap
+ { /Font /Category findresource /Instances get
+ dup 3 index known
+ { pop
+ }
+ { 2 index
+ % Make sure we create the array in global VM.
+ .currentglobal true .setglobal
+ [null 2 -1] exch .setglobal
+ .growput
+ }
+ ifelse
+ //.definefontmap exec
+ } bind def
+
+% Make sure the old definitions are still in systemdict so that
+% they will get bound properly.
+systemdict begin
+ /.origdefinefont /definefont load def
+ /.origundefinefont /undefinefont load def
+ /.origfindfont /findfont load def
+end
+/definefont {
+ /Font defineresource
+} bind odef
+/undefinefont {
+ /Font undefineresource
+} bind odef
+% The Red Book requires that findfont be a procedure, not an operator,
+% but it still needs to restore the stacks reliably if it fails.
+/.findfontop {
+ /Font findresource
+} bind odef
+/findfont {
+ .findfontop
+} bind def % Must be a procedure, not an operator
+
+% Remove initialization utilities.
+currentdict /.definecategory .undef
+currentdict /.emptydict .undef
+
+end % level2dict
+
+% Convert deferred resources after we finally switch to Level 2.
+
+/.fixresources {
+ % Encoding resources
+ EncodingDirectory
+ { dup length 256 eq
+ { /Encoding defineresource pop }
+ { pop pop }
+ ifelse
+ } forall
+ /.findencoding { /Encoding findresource } bind def
+ /findencoding /.findencoding load odef
+ /.defineencoding { /Encoding defineresource pop } bind def
+ % ColorRendering resources and ProcSet
+ systemdict /ColorRendering .knownget {
+ /ColorRendering exch /ProcSet defineresource pop
+ systemdict /ColorRendering undef
+ /DefaultColorRendering currentcolorrendering /ColorRendering
+ defineresource pop
+ % FontType and FMapType resources
+ buildfontdict { pop dup /FontType defineresource pop } forall
+ mark
+ buildfontdict 0 known { 2 3 4 5 6 7 8 } if
+ buildfontdict 9 known { 9 } if
+ counttomark { dup /FMapType defineresource pop } repeat pop
+ } if
+ % Make the fixed resource categories immutable.
+ { /ColorSpaceFamily /Emulator /Filter /IODevice /ColorRenderingType
+ /FMapType /FontType /FormType /HalftoneType /ImageType /PatternType
+ } {
+ /Category findresource
+ dup /Instances get readonly pop
+ .LocalInstances readonly pop
+ readonly pop
+ } forall
+ % clean up
+ systemdict /.fixresources undef
+} bind def
diff --git a/gs/lib/gs_setpd.ps b/gs/lib/gs_setpd.ps
new file mode 100644
index 000000000..e006d0cf1
--- /dev/null
+++ b/gs/lib/gs_setpd.ps
@@ -0,0 +1,667 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% The current implementation of setpagedevice has the following limitations:
+% - It doesn't attempt to "interact with the user" for Policy = 2.
+
+languagelevel 1 .setlanguagelevel
+level2dict begin
+
+% ---------------- Redefinitions ---------------- %
+
+% Redefine .beginpage and .endpage so that they call BeginPage and
+% EndPage respectively if appropriate.
+
+% We have to guard against the BeginPage procedure not popping its operand.
+% This is really stupid, but the Genoa CET does it.
+/.beginpage % - .beginpage -
+ { .currentshowpagecount
+ { .currentpagedevice pop /BeginPage .knownget
+ { % Stack: ... pagecount proc
+ count 2 .execn
+ % Stack: ... ..???.. oldcount
+ count 1 add exch sub { pop } repeat
+ }
+ { pop
+ }
+ ifelse
+ }
+ if
+ } bind odef
+
+% Guard similarly against EndPage not popping its operand.
+/.endpage % <reason> .endpage <print_bool>
+ { .currentshowpagecount
+ { 1 index .currentpagedevice pop /EndPage .knownget
+ { % Stack: ... reason pagecount reason proc
+ count 2 .execn
+ % Stack: ... ..???.. print oldcount
+ count 2 add exch sub { exch pop } repeat
+ }
+ { pop pop 2 ne
+ }
+ ifelse
+ }
+ { 2 ne
+ }
+ ifelse
+ } bind odef
+
+% Define interpreter callouts for handling gstate-saving operators,
+% to make sure that they create a page device dictionary for use by
+% the corresponding gstate-restoring operator.
+% We'd really like to avoid the cost of doing this, but we don't see how.
+% The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
+% %copygstatepagedevice, and %currentgstatepagedevice are known to the
+% interpreter.
+
+(%gsavepagedevice) cvn
+ { currentpagedevice pop gsave
+ } bind def
+
+(%savepagedevice) cvn
+ { currentpagedevice pop save
+ } bind def
+
+(%gstatepagedevice) cvn
+ { currentpagedevice pop gstate
+ } bind def
+
+(%copygstatepagedevice) cvn
+ { currentpagedevice pop copy
+ } bind def
+
+(%currentgstatepagedevice) cvn
+ { currentpagedevice pop currentgstate
+ } bind def
+
+% Define interpreter callouts for handling gstate-restoring operators
+% when the current page device needs to be changed.
+% The names %grestorepagedevice, %grestoreallpagedevice,
+% %restorepagedevice, and %setgstatepagedevice are known to the interpreter.
+
+/.installpagedevice
+ { % Since setpagedevice doesn't create new device objects,
+ % we must (carefully) reinstall the old parameters in
+ % the same device.
+ .currentpagedevice pop null currentdevice null .trysetparams
+ dup type /booleantype eq
+ { pop pop }
+ { % This should never happen!
+ DEBUG { (Error in .trysetparams!\n) print pstack flush } if
+ cleartomark pop pop pop
+ /.installpagedevice cvx /rangecheck signalerror
+ }
+ ifelse pop pop
+ erasepage initgraphics .beginpage
+ } bind def
+
+/.uninstallpagedevice
+ { 2 .endpage { .currentnumcopies false .outputpage } if
+ nulldevice
+ } bind def
+
+(%grestorepagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice
+ } bind def
+
+(%grestoreallpagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice grestoreall
+ } bind def
+
+(%restorepagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice restore
+ } bind def
+
+(%setgstatepagedevice) cvn
+ { .uninstallpagedevice setgstate .installpagedevice
+ } bind def
+
+% Redefine .currentnumcopies so it consults the NumCopies device parameter.
+/.numcopiesdict mark
+ /NumCopies dup
+.dicttomark readonly def
+
+/.currentnumcopies
+ { currentdevice //.numcopiesdict .getdeviceparams
+ dup type /integertype eq
+ { exch pop exch pop }
+ { cleartomark #copies }
+ ifelse
+ } bind odef
+
+% ---------------- Auxiliary definitions ---------------- %
+
+% Define the required attributes of all page devices, and their default values.
+% We don't include attributes such as .MediaSize, which all devices
+% are guaranteed to supply on their own.
+/.defaultpolicies mark
+ /PolicyNotFound 1
+ /PageSize 0
+ /PolicyReport {pop} bind
+.dicttomark readonly def
+/.requiredattrs mark
+ /PageOffset [0 0] readonly
+% We define InputAttributes and OutputAttributes with a single
+% dummy media type that handles pages of any size.
+% Devices that care will override this.
+ /InputAttributes mark 0
+ mark /PageSize [0 dup 16#7ffff dup] .dicttomark readonly
+ .dicttomark readonly
+ (%MediaSource) 0
+ /OutputAttributes mark 0
+ mark .dicttomark readonly
+ .dicttomark readonly
+ (%MediaDestination) 0
+ /Install {.callinstall} bind
+ /BeginPage {.callbeginpage} bind
+ /EndPage {.callendpage} bind
+ /Policies .defaultpolicies
+.dicttomark readonly def
+
+% Define currentpagedevice so it creates the dictionary on demand if needed,
+% adding all the required entries defined just above.
+% We have to deal specially with entries that the driver may change
+% on its own.
+/.dynamicppkeys mark
+ /.MediaSize dup % because it changes when PageSize is set
+ /PageCount dup
+.dicttomark readonly def
+/.makecurrentpagedevice % - .makecurrentpagedevice <dict>
+ { currentdevice null .getdeviceparams
+ % In case of duplicate keys, .dicttomark takes the entry
+ % lower on the stack, so we can just append the defaults here.
+ .requiredattrs { } forall .dicttomark
+ dup .setpagedevice
+ } bind def
+/currentpagedevice
+ { .currentpagedevice
+ { dup length 0 eq
+ { pop .makecurrentpagedevice
+ }
+ { % If any of the dynamic keys have changed,
+ % we must update the page device dictionary.
+ currentdevice //.dynamicppkeys .getdeviceparams .dicttomark
+ { % Stack: current key value
+ 2 index 2 index .knownget { 1 index ne } { true } ifelse
+ { 2 index wcheck not
+ { % This is the first entry being updated.
+ % Copy the dictionary to make it writable.
+ 3 -1 roll dup length dict .copydict
+ 3 1 roll
+ }
+ if
+ 2 index 3 1 roll put
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall
+ % We would like to do a .setpagedevice so we don't keep
+ % re-creating the dictionary. Unfortunately, the effect
+ % of this is that if any dynamic key changes (PageCount
+ % in particular), we will do the equivalent of a
+ % setpagedevice at the next restore or grestore.
+ % Therefore, we make the dictionary read-only, but
+ % we don't store it away. I.e., NOT:
+ % dup wcheck { .setpagedevice .currentpagedevice pop } if
+ readonly
+ }
+ ifelse
+ }
+ if
+ } bind odef
+
+% The implementation of setpagedevice is quite complex. Currently,
+% everything but the media matching algorithm is implemented here.
+
+% By default, we only present the requested changes to the device,
+% but there are some parameters that require special merging action.
+% Define those parameters here, with the procedures that do the merging.
+% The procedures are called as follows:
+% <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
+/.mergespecial mark
+ /InputAttributes
+ { dup null eq
+ { pop null
+ }
+ { 3 copy pop .knownget
+ { dup null eq
+ { pop dup length dict }
+ { dup length 2 index length add dict .copydict }
+ ifelse
+ }
+ { dup length dict
+ }
+ ifelse .copydict readonly
+ }
+ ifelse
+ } bind
+ /OutputAttributes 1 index
+ /Policies
+ { 3 copy pop .knownget
+ { dup length 2 index length add dict .copydict }
+ { dup length dict }
+ ifelse copy readonly
+ } bind
+.dicttomark readonly def
+
+% Define the keys used in input attribute matching.
+/.inputattrkeys [
+ /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
+
+% Define all the parameters that should always be copied to the merged
+% dictionary.
+/.copiedkeys [
+ /OutputDevice
+ .mergespecial { pop } forall
+ .inputattrkeys aload pop
+ .inputselectionkeys aload pop
+ .outputattrkeys aload pop
+] readonly def
+
+% Define the parameters that should not be presented to the device.
+% The procedures are called as follows:
+% <merged> <key> <value> -proc-
+% The procedure leaves all its operands on the stack and returns
+% true iff the key/value pair should be presented to .putdeviceparams.
+/.presentspecial mark
+ .dynamicppkeys { pop false } forall
+ % We must ignore an explicit request for .MediaSize,
+ % because media matching always handles this.
+ /.MediaSize false
+ /Name false
+ /OutputDevice false
+ /PageOffset false
+ /PageSize false % obsolete alias for .MediaSize
+ /InputAttributes false
+ .inputattrkeys
+ { dup /PageSize eq
+ { pop }
+ { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
+ ifelse
+ }
+ forall
+ .inputselectionkeys { false } forall
+ /OutputAttributes false
+ .outputattrkeys
+ { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
+ forall
+ /Install false
+ /BeginPage false
+ /EndPage false
+ /Policies false
+ % Our extensions:
+ /HWColorMap
+ { % HACK: don't transmit the color map, because
+ % window systems can change the color map on their own
+ % incrementally. Someday we'll have a better
+ % solution for this....
+ false
+ }
+ /ViewerPreProcess false
+.dicttomark readonly def
+
+% Define access to device defaults.
+/.defaultdeviceparams
+ { finddevice null .getdeviceparams
+ } bind def
+
+% Select media (input or output). The hard work is done in an operator:
+% <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
+% <pagedict> <attrdict> <policydict> <keys> .matchmedia false
+% <pagedict> null <policydict> <keys> .matchmedia null true
+/.selectmedia % <orig> <request> <merged> <failed> <-- retained
+ % <attrdict> <policydict> <attrkeys> <mediakey>
+ % .selectmedia
+ { 5 index 5 -2 roll 4 index .matchmedia
+ % Stack: orig request merged failed attrkeys mediakey
+ % (key true | false)
+ { 4 index 3 1 roll put pop
+ }
+ { % Adobe's implementations have a "big hairy heuristic"
+ % to choose the set of keys to report as having failed the match.
+ % For the moment, we report any keys that are in the request
+ % and don't have the same value as in the original dictionary.
+ 5 index 1 index .knownget
+ { 4 index 3 1 roll put }
+ { 3 index exch .undef }
+ ifelse
+ { % Stack: <orig> <request> <merged> <failed> <attrkey>
+ 3 index 1 index .knownget
+ { 5 index 2 index .knownget { ne } { pop true } ifelse }
+ { true }
+ ifelse % Stack: ... <failed> <attrkey> <report>
+ { 2 copy /rangecheck put }
+ if pop
+ }
+ forall
+ }
+ ifelse
+ } bind def
+
+% Apply Policies to any unprocessed failed requests.
+% As we process each request entry, we replace the error name
+% in the <failed> dictionary with the policy value,
+% and we replace the key in the <merged> dictionary with its prior value
+% (or remove it if it had no prior value).
+/.policyprocs mark
+% These procedures are called with the following on the stack:
+% <orig> <merged> <failed> <Policies> <key> <policy>
+% They are expected to consume the top 2 operands.
+% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
+% the same as 0, i.e., we signal an error.
+ 0 { % Set errorinfo and signal a configurationerror.
+ pop dup 4 index exch get 2 array astore
+ $error /errorinfo 3 -1 roll put
+ cleartomark
+ /setpagedevice load /configurationerror signalerror
+ } bind
+ 1 { % Roll back the failed request to its previous status.
+DEBUG { (Rolling back.\n) print pstack flush } if
+ 3 index 2 index 3 -1 roll put
+ 4 index 1 index .knownget
+ { 4 index 3 1 roll put }
+ { 3 index exch .undef }
+ ifelse
+ } bind
+ 7 { % For PageSize only, just impose the request.
+ 1 index /PageSize eq
+ { pop pop 1 index /PageSize 7 put }
+ { .policyprocs 0 get exec }
+ ifelse
+ } bind
+.dicttomark readonly def
+/.applypolicies % <orig> <merged> <failed> .applypolicies
+ % <orig> <merged'> <failed'>
+ { 1 index /Policies get 1 index
+ { type /integertype eq
+ { pop % already processed
+ }
+ { 2 copy .knownget not { 1 index /PolicyNotFound get } if
+ % Stack: <orig> <merged> <failed> <Policies> <key>
+ % <policy>
+ .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
+ }
+ ifelse
+ }
+ forall pop
+ } bind def
+
+% Prepare to present parameters to the device, by spreading them onto the
+% operand stack and removing any that shouldn't be presented.
+/.prepareparams % <params> .prepareparams -mark- <key1> <value1> ...
+ { mark exch dup
+ { % Stack: -mark- key1 value1 ... merged key value
+ .presentspecial 2 index .knownget
+ { exec { 3 -1 roll } { pop pop } ifelse }
+ { 3 -1 roll }
+ ifelse
+ }
+ forall pop
+ } bind def
+
+% Put device parameters without resetting currentpagedevice.
+% (.putdeviceparams clears the current page device.)
+/.putdeviceparamsonly % <device> <Policies|null> <require_all> -mark-
+ % <key1> <value1> ... .putdeviceparamsonly
+ % On success: <device> <eraseflag>
+ % On failure: <device> <Policies|null> <req_all> -mark-
+ % <key1> <error1> ...
+ { .currentpagedevice
+ { counttomark 4 add 1 roll .putdeviceparams
+ dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
+ .setpagedevice
+ }
+ { pop .putdeviceparams
+ }
+ ifelse
+ } bind def
+
+% Try setting the device parameters from the merged request.
+/.trysetparams % <merged> <(ignored)> <device> <Policies>
+ % .trysetparams
+ { true 4 index .prepareparams
+ % Add the computed .MediaSize.
+ % Stack: merged (ignored) device Policies -true-
+ % -mark- key1 value1 ...
+ counttomark 5 add index .computemediasize
+ exch pop exch pop /.MediaSize exch
+DEBUG { (Putting.\n) print pstack flush } if
+ .putdeviceparamsonly
+DEBUG { (Result of putting.\n) print pstack flush } if
+ } bind def
+
+% Compute the media size and initial matrix from a merged request (after
+% media selection).
+/.computemediasize % <request> .computemediasize
+ % <request> <matrix> <[width height]>
+ { dup /PageSize get % requested page size
+ 1 index /InputAttributes get
+ 2 index (%MediaSource) get get /PageSize get % media size
+ % (may be a range)
+ 2 index /Policies get
+ dup /PageSize .knownget
+ { exch pop } { /PolicyNotFound get } ifelse % PageSize policy,
+ % affects scaling
+ 3 index /Orientation .knownget not { null } if
+ 4 index /RollFedMedia .knownget not { false } if
+ matrix .matchpagesize pop % (can't fail)
+ 2 array astore
+ } bind def
+
+% ---------------- setpagedevice itself ---------------- %
+
+/setpagedevice
+ { % We mustn't pop the argument until the very end,
+ % so that the pseudo-operator machinery can restore the stack
+ % if an error occurs.
+ mark 1 index currentpagedevice
+
+ % Check whether we are changing OutputDevice;
+ % also handle the case where the current device
+ % is not a page device.
+ % Stack: mark <request> <current>
+DEBUG { (Checking.\n) print pstack flush } if
+
+ dup /OutputDevice .knownget
+ { % Current device is a page device.
+ 2 index /OutputDevice .knownget
+ { % A specific OutputDevice was requested.
+ 2 copy eq
+ { pop pop null }
+ { exch pop }
+ ifelse
+ }
+ { pop null
+ }
+ ifelse
+ }
+ { % Current device is not a page device.
+ % Use the default device.
+ 1 index /OutputDevice .knownget not { .defaultdevicename } if
+ }
+ ifelse
+ dup null eq
+ { pop
+ }
+ { exch pop .defaultdeviceparams
+ % In case of duplicate keys, .dicttomark takes the entry
+ % lower on the stack, so we can just append the defaults here.
+ .requiredattrs { } forall .dicttomark
+ }
+ ifelse
+
+ % Check whether a viewer wants to intervene.
+ % We must check both the request (which takes precedence)
+ % and the current dictionary.
+ % Stack: mark <request> <orig>
+ exch dup /ViewerPreProcess .knownget
+ { exec }
+ { 1 index /ViewerPreProcess .knownget { exec } if }
+ ifelse exch
+
+ % Construct a merged request from the actual request plus
+ % any keys that should always be propagated.
+ % Stack: mark <request> <orig>
+DEBUG { (Merging.\n) print pstack flush } if
+
+ exch 1 index length 1 index length add dict
+ .copiedkeys
+ { % Stack: <orig> <request> <merged> <key>
+ 3 index 1 index .knownget { 3 copy put pop } if pop
+ }
+ forall
+ % Stack: <orig> <request> <merged>
+ dup 2 index
+ { % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
+ .mergespecial 2 index .knownget { exec } if
+ put dup
+ }
+ forall pop
+ % Hack: if FIXEDRESOLUTION is true, discard any attempt to
+ % change HWResolution.
+ FIXEDRESOLUTION { dup /HWResolution .undef } if
+ % Hack: if FIXEDMEDIA is true, discard any attempt to change
+ % PageSize or HWSize.
+ FIXEDMEDIA
+ { dup /PageSize 4 index /PageSize get put
+ dup /HWSize 4 index /HWSize get put
+ } if
+
+ % Select input and output media.
+ % Stack: mark <orig> <request> <merged>
+DEBUG { (Selecting.\n) print pstack flush } if
+
+ 0 dict % <failed>
+ 1 index /InputAttributes .knownget
+ { 2 index /Policies get
+ .inputattrkeys (%MediaSource) cvn .selectmedia
+ } if
+ 1 index /OutputAttributes .knownget
+ { 2 index /Policies get
+ .outputattrkeys (%MediaDestination) cvn .selectmedia
+ } if
+ 3 -1 roll 4 1 roll % temporarily swap orig & request
+ .applypolicies
+ 3 -1 roll 4 1 roll % swap back
+
+ % Construct the new device, and attempt to set its attributes.
+ % Stack: mark <orig> <request> <merged> <failed>
+DEBUG { (Constructing.\n) print pstack flush } if
+
+ currentdevice .devicename 2 index /OutputDevice get eq
+ { currentdevice }
+ { 1 index /OutputDevice get finddevice }
+ ifelse
+ %**************** We should copy the device here,
+ %**************** but since we can't close the old device,
+ %**************** we don't. This is WRONG.
+ %****************copydevice
+ 2 index /Policies get
+ .trysetparams
+ dup type /booleantype ne
+ { % The request failed.
+ % Stack: ... <orig> <request> <merged> <failed> <device>
+ % <Policies> true mark <name> <errorname> ...
+DEBUG { (Recovering.\n) print pstack flush } if
+ counttomark 4 add index
+ counttomark 2 idiv { dup 4 -2 roll put } repeat
+ pop pop pop
+ % Stack: mark ... <orig> <request> <merged> <failed> <device>
+ % <Policies>
+ 6 2 roll 3 -1 roll 4 1 roll
+ .applypolicies
+ 3 -1 roll 4 1 roll 6 -2 roll
+ .trysetparams % shouldn't fail!
+ dup type /booleantype ne
+ { 2 { counttomark 1 add 1 roll cleartomark } repeat
+ /setpagedevice load exch signalerror
+ }
+ if
+ }
+ if
+
+ % The attempt succeeded. Install the new device.
+ % Stack: mark ... <merged> <failed> <device> <eraseflag>
+DEBUG { (Installing.\n) print pstack flush } if
+
+ pop 2 .endpage
+ { 1 true .outputpage
+ (>>setpagedevice, press <return> to continue<<\n) .confirm
+ }
+ if
+ % .setdevice clears the current page device!
+ .currentpagedevice pop exch
+ .setdevice pop
+ .setpagedevice
+
+ % Merge the request into the current page device.
+ % Stack: mark ... <merged> <failed>
+ exch currentpagedevice dup length 2 index length add dict
+ .copydict .copydict
+ % Initialize the default matrix, taking media matching
+ % into account.
+ .computemediasize pop initmatrix concat
+ dup /PageOffset .knownget
+ { % Translate by the given number of 1/72" units in device X/Y.
+ dup 0 get exch 1 get
+ 2 index /HWResolution get dup 1 get exch 0 get
+ 4 -1 roll mul 72 div 3 1 roll mul 72 div
+ idtransform translate
+ }
+ if
+ % We must install the new page device dictionary
+ % before calling the Install procedure.
+ dup .setpagedevice
+ .setdefaultscreen % Set the default screen before calling Install.
+ dup /Install .knownget { exec } if
+ matrix currentmatrix .setdefaultmatrix
+ % Erase and initialize the page.
+ erasepage initgraphics
+ .beginpage
+
+ % Clean up, calling PolicyReport if needed.
+ % Stack: mark ... <failed> <merged>
+DEBUG { (Finishing.\n) print pstack flush } if
+
+ exch dup length 0 ne
+ { 1 index /Policies get /PolicyReport get
+ counttomark 1 add 2 roll cleartomark
+ exec
+ }
+ { cleartomark
+ }
+ ifelse pop
+
+ } odef
+
+end % level2dict
+.setlanguagelevel
diff --git a/gs/lib/gs_statd.ps b/gs/lib/gs_statd.ps
new file mode 100644
index 000000000..e2bbbfc34
--- /dev/null
+++ b/gs/lib/gs_statd.ps
@@ -0,0 +1,270 @@
+% Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% This file provides statusdict, serverdict, and assorted LaserWriter
+% operators, mostly for the benefit of poorly designed PostScript programs
+% that 'know' they are running on a LaserWriter.
+
+systemdict begin
+ % We make statusdict a little larger for Level 2 stuff.
+ % Note that it must be allocated in local VM.
+ .currentglobal false .setglobal
+ /statusdict 89 dict def
+ % To support the Level 2 job control features,
+ % serverdict must also be in local VM.
+ /serverdict 10 dict def % ditto
+ .setglobal
+end
+
+% Define various paper formats. The Adobe documentation defines only these:
+% 11x17, a3, a4, a4small, b5, ledger, legal, letter, lettersmall, note.
+% These procedures are also accessed as data structures during initialization,
+% so the page dimensions must be the first two elements of the procedure.
+
+/.setpagesize { //systemdict /statusdict get begin .setpagesize end } bind def
+userdict begin
+ /letter {612 792 //.setpagesize exec} bind def
+% 'note' is an anomaly. It is apparently supposed to use a 540x720 region
+% centered on a 612x792 page, with (0,0) at the lower left corner of the
+% 612x792 page, but we have no way to represent this. In order to avoid
+% clipping the image, we define note as equivalent to letter.
+%/note {540 720 //.setpagesize exec} bind def
+ /note /letter load def
+ /legal {612 1008 //.setpagesize exec} bind def
+ /a0 {2380 3368 //.setpagesize exec} bind def % ISO standard
+ /a1 {1684 2380 //.setpagesize exec} bind def % ISO standard
+ /a2 {1190 1684 //.setpagesize exec} bind def % ISO standard
+ /a3 {842 1190 //.setpagesize exec} bind def % ISO standard
+ /a4 {595 842 //.setpagesize exec} bind def % ISO standard
+ /a5 {421 595 //.setpagesize exec} bind def % ISO standard
+ /a6 {297 421 //.setpagesize exec} bind def % ISO standard
+ /a7 {210 297 //.setpagesize exec} bind def % ISO standard
+ /a8 {148 210 //.setpagesize exec} bind def % ISO standard
+ /a9 {105 148 //.setpagesize exec} bind def % ISO standard
+ /a10 {74 105 //.setpagesize exec} bind def % ISO standard
+ /b0 {2836 4008 //.setpagesize exec} bind def % ISO standard
+ /b1 {2004 2836 //.setpagesize exec} bind def % ISO standard
+ /b2 {1418 2004 //.setpagesize exec} bind def % ISO standard
+ /b3 {1002 1418 //.setpagesize exec} bind def % ISO standard
+ /b4 {709 1002 //.setpagesize exec} bind def % ISO standard
+ /b5 {501 709 //.setpagesize exec} bind def % ISO standard
+ /archE {2592 3456 //.setpagesize exec} bind def % U.S. CAD std
+ /archD {1728 2592 //.setpagesize exec} bind def % U.S. CAD std
+ /archC {1296 1728 //.setpagesize exec} bind def % U.S. CAD std
+ /archB {864 1296 //.setpagesize exec} bind def % U.S. CAD std
+ /archA {648 864 //.setpagesize exec} bind def % U.S. CAD std
+ /flsa {612 936 //.setpagesize exec} bind def % U.S. foolscap
+ /flse {612 936 //.setpagesize exec} bind def % European foolscap
+ /halfletter {396 612 //.setpagesize exec} bind def
+ /11x17 {792 1224 //.setpagesize exec} bind def % 11x17 portrait
+% /tabloid {792 1224 //.setpagesize exec} bind def % 11x17 portrait
+ /ledger {1224 792 //.setpagesize exec} bind def % 11x17 landscape
+% /csheet {1224 1584 //.setpagesize exec} bind def % ANSI C 17x22
+% /dsheet {1584 2448 //.setpagesize exec} bind def % ANSI D 22x34
+% /esheet {2448 3168 //.setpagesize exec} bind def % ANSI E 34x44
+end
+currentdict /.setpagesize .undef
+
+statusdict begin
+
+% Define the pagetype values for the known page formats.
+% The values for all but letter and note are arbitrary.
+/.pagetypenames
+ { /letter /note /legal
+ /a0 /a1 /a2 /a3 /a4 /a5 /a6 /a7 /a8 /a9 /a10
+ /b0 /b1 /b2 /b3 /b4 /b5 /archE /archD /archC /archB /archA
+ /flsa /flse /halfletter /11x17 /ledger
+ } cvlit readonly def
+
+%%%%%% The following items were suggested by a user as useful.
+
+% Permanent definitions
+
+/ramsize 4194304 def
+/hardwareiomode 0 def
+ /sethardwareiomode {pop} bind def
+/softwareiomode 0 def
+ /setsoftwareiomode {pop} bind def
+/dosysstart false def
+ /setdosysstart {pop} bind def
+/allowjobreset true def
+ /setallowjobreset {pop} bind def
+/defaultpaperfamily 0 def
+ /setdefaultpaperfamily {pop} bind def
+/defaultpapertray 0 def
+ /setdefaultpapertray {pop} bind def
+/defaulttrayswitch false def
+ /setdefaulttrayswitch {pop} bind def
+
+% Tray and format selection
+
+ /11x17tray userdict /11x17 get def
+ /a3tray userdict /a3 get def
+ /a4tray userdict /a4 get def
+ /a5tray userdict /a5 get def
+ /a6tray userdict /a6 get def
+ /b4tray userdict /b4 get def
+ /flsatray userdict /flsa get def
+ /flsetray userdict /flse get def
+ /halflettertray userdict /halfletter get def
+ /ledgertray userdict /ledger get def
+ /legaltray userdict /legal get def
+ /lettertray userdict /letter get def
+
+% Per-job parameters
+
+/paperfamily 0 def % 0 is US, 1 is European
+/papertray 1 def
+ /setpapertray {statusdict exch /papertray exch put} bind def
+/trayswitch false def % paperout feeds from another tray
+% We don't implement the (undocumented by Adobe) papersize 'operator',
+% because it's very awkward to make it interact properly with all the
+% different ways of setting the paper size.
+%/papersize {/letter true} bind def % <name of paper size>, <short-edge-first-p>
+/appletalktype (LaserWriter) def
+
+%%%%%% The following items are defined in the PostScript Language
+%%%%%% Reference Manual, First Edition, and subsequent 'compatibility'
+%%%%%% documentation from Adobe.
+
+ /checkpassword {statusdict begin .password eq end} bind def
+ /defaulttimeouts {statusdict begin .timeouts aload pop end} bind def
+%/dostartpage
+ /eescratch {pop 0} bind def
+ /idlefonts {statusdict begin mark .idlefonts aload pop end} bind def
+ /jobname () def
+%/jobtimeout
+ /manualfeed false def
+ /manualfeedtimeout 60 def
+ /margins {statusdict begin .topmargin .leftmargin end} bind def
+ /pagecount {4711} bind def
+ /pagestackorder {false} bind def
+ /pagetype 0 def
+ /prefeed false def
+ /printererror {pop pop} bind def
+ /printername {statusdict /.printername get exch copy} bind def
+ /processcolors /processcolors load def % defined in systemdict
+ /product product def % product is defined in systemdict
+ /revision revision def % revision is defined in systemdict
+ /sccbatch {pop 9600 0} bind def
+ /sccinteractive {pop 9600 0} bind def
+ /setdefaulttimeouts {statusdict begin .timeouts astore pop end} bind def
+ /setdostartpage {statusdict exch /dostartpage exch put} bind def
+ /setduplexmode {mark /Duplex 3 -1 roll currentdevice putdeviceprops} bind def
+ /seteescratch {pop pop} bind def
+ /setidlefonts {] statusdict exch /.idlefonts exch put} bind def
+ /setjobtimeout {statusdict exch /jobtimeout exch put} bind def
+ /setmargins
+ { statusdict begin
+ /.leftmargin exch def /.topmargin exch def
+ end
+ } bind def
+
+% The following compatibility operators are only documented by Adobe in a
+% supplement to the Red Book.
+%
+% - pagemargin <offset>
+% - pageparams <width> <height> <offset> <orientation>
+% <width> <height> <orientation> setpage -
+% <offset> setpagemargin -
+% <width> <height> <offset> <orientation> setpageparams -
+%
+% width and height are in default units (and if orientation is odd, are
+% exchanged!). offset is the x margin, also in default units.
+% Unfortunately, because orientation is relative to the device paper feed,
+% it does not have a consistent meaning in terms of image orientation.
+% We follow the convention that ORIENT1 determines the orientation value
+% that means portait: false means 0, true means 1.
+
+ /pagemargin { 0 } bind def
+ /pageparams
+ { currentdevice 1 dict dup /.MediaSize dup put .getdeviceparams
+ exch pop exch pop aload pop 0 ORIENT1 { 1 } { 0 } ifelse
+ } bind def
+ /setpage
+ { ORIENT1 { 1 } { 0 } ifelse ne {exch} if
+ statusdict /.setpagesize get exec
+ } bind def
+ /setpagemargin {pop} bind def % can't do better without setpagedevice
+ /setpageparams
+ { exch pop ORIENT1 { 1 } { 0 } ifelse ne {exch} if
+ statusdict /.setpagesize get exec
+ } bind def
+ /setpagetype
+ { statusdict begin
+ dup .pagetypenames exch get //systemdict exch get exec
+ /pagetype exch def
+ end
+ } bind def
+ /setpassword
+ {exch checkpassword
+ {statusdict exch /.password exch put true}
+ {pop false}
+ ifelse} bind def
+ /setprintername
+ {dup length string copy statusdict exch /.printername exch put} bind def
+
+% setresolution is not documented by Adobe, but some applications
+% use it anyway, without testing whether or not it is present.
+%
+% <pixels_per_inch> setresolution -
+%
+% sets the resolution of the device.
+
+ /setresolution
+ { mark /HWResolution [ 4 -1 roll dup ] currentdevice putdeviceprops pop
+ initmatrix erasepage
+ } bind def
+ /setsccbatch {pop pop pop} bind def
+ /setsccinteractive {pop pop pop} bind def
+ /settumble {pop} bind def
+ /waittimeout 300 def
+
+%%%%%% End of documented items.
+
+/.setpagesize
+ { mark /HWSize [
+ 4 index 4 index matrix defaultmatrix dtransform
+ abs ceiling cvi exch abs ceiling cvi exch
+ ] currentdevice putdeviceprops pop pop pop
+ initmatrix initclip erasepage
+ } bind def
+/.password 0 def
+/.timeouts [0 60 30] def
+true setdostartpage
+mark setidlefonts
+0 setjobtimeout
+0 0 setmargins
+product setprintername
+
+end % statusdict
+
+% The following contents of serverdict are a complete guess,
+% based on some observed LaserWriter boilerplate.
+
+serverdict begin
+
+ /execjob { } bind def
+% The Red Book implies that something like the following is
+% an appropriate definition of exitserver.
+ /exitserver { clear stop } bind def
+% However, this interacts badly with our standard error handler,
+% so we override it with the following less appropriate definition.
+ /exitserver { 0 ne { clear cleardictstack } if } bind def
+ /setrealdevice { } bind def
+
+end % serverdict
diff --git a/gs/lib/gs_std_e.ps b/gs/lib/gs_std_e.ps
new file mode 100644
index 000000000..71e16ef56
--- /dev/null
+++ b/gs/lib/gs_std_e.ps
@@ -0,0 +1,74 @@
+% Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the standard encoding vector.
+/StandardEncoding
+% \00x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \04x
+ /space /exclam /quotedbl /numbersign
+ /dollar /percent /ampersand /quoteright
+ /parenleft /parenright /asterisk /plus
+ /comma /hyphen /period /slash
+ /zero /one /two /three
+ /four /five /six /seven
+ /eight /nine /colon /semicolon
+ /less /equal /greater /question
+% \10x
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+% \14x
+ /quoteleft /a /b /c /d /e /f /g
+ /h /i /j /k /l /m /n /o
+ /p /q /r /s /t /u /v /w
+ /x /y /z /braceleft /bar /braceright /asciitilde /.notdef
+% \20x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \24x
+ /.notdef /exclamdown /cent /sterling
+ /fraction /yen /florin /section
+ /currency /quotesingle /quotedblleft /guillemotleft
+ /guilsinglleft /guilsinglright /fi /fl
+ /.notdef /endash /dagger /daggerdbl
+ /periodcentered /.notdef /paragraph /bullet
+ /quotesinglbase /quotedblbase /quotedblright /guillemotright
+ /ellipsis /perthousand /.notdef /questiondown
+% \30x
+ /.notdef /grave /acute /circumflex /tilde /macron /breve /dotaccent
+ /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
+ /emdash /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \34x
+ /.notdef /AE /.notdef /ordfeminine /.notdef /.notdef /.notdef /.notdef
+ /Lslash /Oslash /OE /ordmasculine /.notdef /.notdef /.notdef /.notdef
+ /.notdef /ae /.notdef /.notdef /.notdef /dotlessi /.notdef /.notdef
+ /lslash /oslash /oe /germandbls /.notdef /.notdef /.notdef /.notdef
+% Make an array on large systems, a packed array on small ones.
+256
+vmstatus exch pop exch pop
+100000 ge { array astore readonly } { packedarray } ifelse
+def
+0 StandardEncoding .registerencoding
+/StandardEncoding StandardEncoding .defineencoding
diff --git a/gs/lib/gs_sym_e.ps b/gs/lib/gs_sym_e.ps
new file mode 100644
index 000000000..aaed543f7
--- /dev/null
+++ b/gs/lib/gs_sym_e.ps
@@ -0,0 +1,84 @@
+% Copyright (C) 1991, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the Symbol encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/SymbolEncoding
+% \000
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \040
+ /space /exclam /universal /numbersign
+ /existential /percent /ampersand /suchthat
+ /parenleft /parenright /asteriskmath /plus
+ /comma /minus /period /slash
+ /zero /one /two /three
+ /four /five /six /seven
+ /eight /nine /colon /semicolon
+ /less /equal /greater /question
+% \100
+ /congruent /Alpha /Beta /Chi
+ /Delta /Epsilon /Phi /Gamma
+ /Eta /Iota /theta1 /Kappa
+ /Lambda /Mu /Nu /Omicron
+ /Pi /Theta /Rho /Sigma
+ /Tau /Upsilon /sigma1 /Omega
+ /Xi /Psi /Zeta /bracketleft
+ /therefore /bracketright /perpendicular /underscore
+% \140
+ /radicalex /alpha /beta /chi
+ /delta /epsilon /phi /gamma
+ /eta /iota /phi1 /kappa
+ /lambda /mu /nu /omicron
+ /pi /theta /rho /sigma
+ /tau /upsilon /omega1 /omega
+ /xi /psi /zeta /braceleft
+ /bar /braceright /similar /.notdef
+% \200
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \240
+ /.notdef /Upsilon1 /minute /lessequal
+ /fraction /infinity /florin /club
+ /diamond /heart /spade /arrowboth
+ /arrowleft /arrowup /arrowright /arrowdown
+ /degree /plusminus /second /greaterequal
+ /multiply /proportional /partialdiff /bullet
+ /divide /notequal /equivalence /approxequal
+ /ellipsis /arrowvertex /arrowhorizex /carriagereturn
+% \300
+ /aleph /Ifraktur /Rfraktur /weierstrass
+ /circlemultiply /circleplus /emptyset /intersection
+ /union /propersuperset /reflexsuperset /notsubset
+ /propersubset /reflexsubset /element /notelement
+ /angle /gradient /registerserif /copyrightserif
+ /trademarkserif /product /radical /dotmath
+ /logicalnot /logicaland /logicalor /arrowdblboth
+ /arrowdblleft /arrowdblup /arrowdblright /arrowdbldown
+% \340
+ /lozenge /angleleft /registersans /copyrightsans
+ /trademarksans /summation /parenlefttp /parenleftex
+ /parenleftbt /bracketlefttp /bracketleftex /bracketleftbt
+ /bracelefttp /braceleftmid /braceleftbt /braceex
+ /.notdef /angleright /integral /integraltp
+ /integralex /integralbt /parenrighttp /parenrightex
+ /parenrightbt /bracketrighttp /bracketrightex /bracketrightbt
+ /bracerighttp /bracerightmid /bracerightbt /.notdef
+256 packedarray .defineencoding
+2 SymbolEncoding .registerencoding
+exec
diff --git a/gs/lib/gs_ttf.ps b/gs/lib/gs_ttf.ps
new file mode 100644
index 000000000..f18f9182a
--- /dev/null
+++ b/gs/lib/gs_ttf.ps
@@ -0,0 +1,461 @@
+% Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Support code for direct use of TrueType fonts.
+% (Not needed for Type 42 fonts.)
+
+% ---------------- Font loading machinery ---------------- %
+
+% Augment the FONTPATH machinery so it recognizes TrueType fonts.
+
+/.scanfontheaders where % only defined if DISKFONTS is recognized
+ { pop
+ /.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) ] def
+ }
+if
+/.findnonttfontvalue /.findfontvalue load def
+/.findfontvalue % <file> <key> .findfontvalue <value> true
+ % <file> <key> .findfontvalue false
+ % Closes the file in either case.
+ { 1 index read pop 2 index 1 index unread 0 eq
+ { % If this is a font at all, it's a TrueType font.
+ dup /FontType eq
+ { pop closefile 42 true }
+ { dup /FontName eq
+ { pop .findttfontname }
+ { pop closefile false }
+ ifelse
+ }
+ ifelse
+ }
+ { % Not a TrueType font.
+ .findnonttfontvalue
+ }
+ ifelse
+ } bind def
+/.findttfontname % <file> .findttfontname <fname> true
+ % <file> .findttfontname false
+ % Closes the file in either case.
+ { .loadttfonttables
+ (name) findtableentry
+ { dup 8 getu32 f exch setfileposition
+ 12 getu32 string f exch readstring pop
+ 6 findname
+ }
+ { false
+ }
+ ifelse
+ f closefile end end
+ } bind def
+
+% Load a font file that might be a TrueType font.
+
+/.loadnonttfontfile /.loadfontfile load def
+/.loadfontfile % <file> .loadfontfile -
+ { dup read pop 2 copy unread 0 eq
+ { % If this is a font at all, it's a TrueType font.
+ .loadttfont pop
+ }
+ { % Not a TrueType font.
+ .loadnonttfontfile
+ }
+ ifelse
+ } bind def
+
+% ---------------- Automatic Type 42 generation ---------------- %
+
+% Load a TrueType font from a file as a Type 42 PostScript font.
+% The thing that makes this really messy is the handling of encodings.
+% There are 3 interacting tables that affect the encoding:
+% 'cmap' provides multiple maps from character codes to glyph indices
+% 'glyf' maps glyph indices to outlines
+% 'post' maps glyph indices to glyph names (if present)
+% What we need to get out of this is:
+% Encoding mapping character codes to glyph names
+% (the composition of cmap and post)
+% CharStrings mapping glyph names to glyph indices
+% (the inverse of post)
+% If the post table is missing, we have to take a guess based on the cmap
+% table.
+
+/.loadttfontdict mark
+/orgXUID 107 def % Aladdin Enterprises organization XUID
+/maxstring 65500 def % maximum length of a PostScript string
+
+% Define the Macintosh standard mapping from characters to glyph indices.
+/MacRomanEncoding dup .findencoding def
+/MacGlyphEncoding mark
+ /.notdef /.null /CR
+MacRomanEncoding 32 95 getinterval aload pop
+MacRomanEncoding 128 45 getinterval aload pop
+% 143
+ /notequal /AE
+ /Oslash /infinity /plusinus /lessequal /greaterequal
+ /yen /mu1 /partialdiff /summation /product
+ /pi /integral /ordfeminine /ordmasculine /Ohm
+ /ae /oslash /questiondown /exclamdown /logicalnot
+ /radical /florin /approxequal /increment /guillemotleft
+ /guillemotright /ellipsis /nbspace
+MacRomanEncoding 203 12 getinterval aload pop
+ /lozenge
+MacRomanEncoding 216 24 getinterval aload pop
+ /applelogo
+MacRomanEncoding 241 7 getinterval aload pop
+ /overscore
+MacRomanEncoding 249 7 getinterval aload pop
+% 226
+ /Lslash /lslash /Scaron /scaron
+ /Zcaron /zcaron /brokenbar /Eth /eth
+ /Yacute /yacute /Thorn /thorn /minus
+ /multiply /onesuperior /twosuperior /threesuperior /onehalf
+ /onequarter /threequarters /franc /Gbreve /gbreve
+ /Idot /Scedilla /scedilla /Cacute /cacute
+ /Ccaron /ccaron /dmacron
+/packedarray where
+ { pop counttomark packedarray exch pop }
+ { ] readonly }
+ifelse def
+
+% Procedures
+/getu16 % <string> <index> getu16 <integer>
+ { 2 copy get 8 bitshift 3 1 roll 1 add get add
+ } bind def
+/gets16 % <string> <index> gets16 <integer>
+ { getu16 16#8000 xor 16#8000 sub
+ } bind def
+/getu32 % <string> <index> getu32 <integer>
+ { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
+ } bind def
+/gets32 % <string> <index> gets32 <integer>
+ { getu32 dup 16#7fffffff gt { 4 { 16#40000000 sub } repeat } if
+ } bind def
+/getrange % <offset> <length> getrange <string>
+ % Free variables: sfnts
+ { () sfnts
+ { % Stack: offset length () sfnt
+ dup length 4 index gt { exch pop exit } if
+ 4 -1 roll exch length sub 3 1 roll
+ }
+ forall 3 1 roll getinterval
+ } bind def
+/findtableentry % <name4> findtableentry <tableentry> true
+ % <name4> findtableentry false
+ % Free variables: tables
+ { false 0 16 tables length 16 sub
+ { % Stack: name4 false toffset
+ tables 1 index 4 getinterval 3 index eq
+ { tables exch 16 getinterval
+ exch pop exch true exit
+ }
+ if pop
+ }
+ for exch pop
+ } bind def
+/findtable % <name4> findtable <table> true
+ % <name4> findtable false
+ % Free variables: tables
+ { findtableentry
+ { dup 8 getu32 exch 12 getu32 getrange true }
+ { false }
+ ifelse
+ } bind def
+/findname % <nametable> <nameid> findname <string> true
+ % <nametable> <nameid> findname false
+ { false 3 1 roll 0 1 3 index 2 getu16 1 sub
+ { % Stack: false table id index
+ 12 mul 6 add 2 index exch 12 getinterval
+ dup 6 getu16 2 index eq
+ { % We found the name we want.
+ exch pop
+ % Stack: false table record
+ dup 10 getu16 2 index 4 getu16 add
+ 1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
+ % Stack: false string record
+ % Check for 8- vs. 16-bit characters.
+ is2byte { string2to1 } if true null 4 -1 roll exit
+ }
+ if pop
+ }
+ for pop pop
+ } bind def
+/is2byte % <namerecord> is2byte <bool>
+ { dup 0 getu16
+ { { pop true } % Apple Unicode
+ { pop false } % Macintosh Script manager
+ { 1 getu16 1 eq } % ISO
+ { 1 getu16 1 eq } % Microsoft
+ }
+ exch get exec
+ } bind def
+/string2to1 % <string2> string2to1 <string>
+ { dup length 2 idiv string dup
+ 0 1 3 index length 1 sub
+ { 3 index 1 index 2 mul 1 add get put dup }
+ for pop exch pop
+ } bind def
+/cmapformats mark
+ % Each procedure in this dictionary is called as follows:
+ % -mark- encodingtable <<proc>> -mark- glyphindices...
+ 0 % Apple standard 1-to-1 mapping.
+ { 6 256 getinterval { } forall
+ } bind
+ 4 % Microsoft/Adobe segmented mapping.
+ { /etab exch def
+ /nseg2 etab 6 getu16 def
+ 14 /endc etab 2 index nseg2 getinterval def
+ % The Apple TrueType documentation omits the 2-byte
+ % 'reserved pad' that follows the endCount vector!
+ 2 add
+ nseg2 add /startc etab 2 index nseg2 getinterval def
+ nseg2 add /iddelta etab 2 index nseg2 getinterval def
+ nseg2 add /idroff etab 2 index nseg2 getinterval def
+ % The following hack allows us to properly handle
+ % idiosyncratic fonts that start at 0xf000:
+ /firstcode startc 0 getu16 16#ff00 and def
+ pop 0 2 nseg2 3 sub
+ { /i2 exch def
+ /scode startc i2 getu16 def
+ counttomark scode firstcode sub 256 min exch sub 0 max { 0 } repeat
+ /ecode endc i2 getu16 def
+ /delta iddelta i2 getu16 def
+ idroff i2 getu16 dup 0 eq
+ { pop scode 1 ecode { delta add 65535 and } for
+ }
+ { % The +2 is for the 'reserved pad'.
+ /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
+ 0 1 ecode scode sub
+ { 2 mul gloff add etab exch getu16
+ dup 0 ne { delta add 65535 and } if
+ }
+ for
+ }
+ ifelse
+ }
+ for
+ } bind
+ 6 % Single interval lookup.
+ { dup 6 getu16 { 0 exch } repeat
+ dup 8 getu16 0 exch 1 exch 1 sub
+ { 2 mul 10 add 2 copy getu16 exch pop exch }
+ repeat pop
+ } bind
+.dicttomark readonly def % cmapformats
+/cmaparray % <cmaptab> cmaparray -mark- <glyphs> ...
+ { mark exch dup 0 getu16 cmapformats exch .knownget
+ { exec }
+ { (Can't handle format ) print 0 getu16 = flush
+ 0 1 255 { } for
+ }
+ ifelse
+ } bind def
+/postformats mark
+ % Each procedure in this dictionary is called as follows:
+ % posttable <<proc>> glyphencoding
+ 16#00020000 % Detailed map, required by Microsoft fonts.
+ { /postglyphs exch def
+ postglyphs 32 getu16 /numglyphs exch def
+ /glyphnames numglyphs 2 mul 34 add def
+ [ 0 1 numglyphs 1 sub
+ { 2 mul 34 add postglyphs exch getu16
+ dup 258 lt
+ { MacGlyphEncoding exch get
+ }
+ { 258 sub glyphnames exch
+ { postglyphs 1 index get 1 add add }
+ repeat
+ 1 add postglyphs exch 2 copy 1 sub get getinterval cvn
+ }
+ ifelse
+ }
+ for ]
+ } bind
+.dicttomark readonly def % postformats
+.dicttomark readonly def % .loadttfontdict
+/.loadttfonttables % <file> .loadttfonttables -
+ % Pushes .loadttfontdict & scratch dict on d-stack,
+ % defines f, offsets, tables
+ { .loadttfontdict begin
+ 40 dict begin
+ /f exch def
+ /offsets f 12 string readstring pop def
+ /tables f offsets 4 getu16 16 mul string readstring pop def
+ } bind def
+/.readsfnts0 { % <len0> .readsfnts0 <string>
+ dup string
+ dup 0 offsets putinterval
+ dup offsets length tables putinterval
+ dup offsets length tables length add
+ % Stack: len0 str str off+tab
+ 3 index 1 index sub getinterval
+ f exch dup length 0 ne { readstring } if pop pop
+ exch pop
+} bind def
+/.dividesfnts { % <length> .dividesfnts -
+ (glyf) findtableentry pop
+ dup 8 getu32 /len0 exch def
+ 12 getu32 /len1 exch def
+ len0 len1 add sub /len2 exch def
+ /sfnts [
+ len0 .readsfnts0
+ len1 dup maxstring gt
+ { % Bad news: we'll have to split the glyfs.
+ % Right now we only provide for splitting into 2 parts,
+ % but we could generalize this without too much trouble.
+ f maxstring string readstring pop
+ exch maxstring sub
+ }
+ if string f exch readstring pop
+ len2 0 ne { f len2 string readstring pop } if
+ ] def
+ /head (head) findtable pop def
+ len1 maxstring gt
+ { % Determine where to split the glyfs by scanning loca.
+ % The very last entry in loca may be bogus.
+ % What a nuisance!
+ (loca) findtable pop dup length
+ head 50 getu16 0 ne
+ { % 32-bit loca
+ 8 sub -4 0
+ { 1 index exch getu32 dup maxstring le { exch pop exit } if pop }
+ }
+ { % 16-bit loca
+ 4 sub -2 0
+ { 1 index exch getu16 1 bitshift dup maxstring le { exch pop exit } if pop }
+ }
+ ifelse for
+ % Now the top element of the stack is the length of
+ % the first glyf string.
+ sfnts 1 get dup 0 3 index getinterval
+ sfnts exch 1 exch put
+ exch 1 index length 1 index sub getinterval
+ sfnts 2 get concatstrings sfnts exch 2 exch put
+ }
+ if
+} bind def
+/.makesfnts % - .makesfnts -
+ % Defines head, sfnts
+ { % Find the end of the last table, and also the end of
+ % the last table below the 64K mark.
+ 0 8 16 tables length
+ { % Stack: end toffset
+ DEBUG
+ { tables 1 index 8 sub 4 getinterval print ( ) print
+ tables 1 index getu32 =only ( ) print
+ tables 1 index 4 add getu32 =
+ }
+ if
+ tables 1 index getu32 exch tables exch 4 add getu32 add max
+ }
+ for
+ dup maxstring le {
+ .readsfnts0
+ % Pad to even length if necessary, per Adobe specification.
+ dup length 2 mod 0 ne {
+ <00> concatstrings
+ } if
+ 1 array astore /sfnts exch def
+ /head (head) findtable pop def
+ } {
+ % If the total length exceeds maxstring, divide the data
+ % into 2+n strings: before glyf, glyfs, after glyf
+ .dividesfnts
+ } ifelse
+ } bind def
+/.loadttfont % <file> .loadttfont <type42font>
+ { .loadttfonttables
+ .makesfnts
+ /upem head 18 getu16 def
+ (cmap) findtable pop
+ % The Apple cmap format is no help in determining the encoding.
+ % Look for a Microsoft table. If we can't find one,
+ % just use the first table, whatever it is.
+ dup 4 8 getinterval exch % the default
+ 0 1 2 index 2 getu16 1 sub
+ { 8 mul 4 add 1 index exch 8 getinterval
+ dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
+ }
+ for
+ % Stack: subentry table
+ /cmapsub 2 index def
+ exch 4 getu32 1 index length 1 index sub getinterval
+ /cmaptab exch def
+ % See if we have PostScript glyph name information.
+ /post (post) findtable not { null } if def
+ /glyphencoding post null eq
+ { MacGlyphEncoding }
+ { postformats post 0 getu32 .knownget
+ { post exch exec }
+ { MacGlyphEncoding }
+ ifelse
+ }
+ ifelse def
+ /checksum head 8 getu32 def
+ mark
+ /FontType 42
+ /FontMatrix matrix
+ /PaintType 0
+ /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
+ (name) findtable
+ { % Find the names from the 'name' table.
+ /names exch def
+ /FontName names 6 findname not { checksum 16 8 string cvrs } if
+ /FontInfo mark
+ names 0 findname { /Notice exch } if
+ names 1 findname { /FamilyName exch } if
+ names 4 findname { /FullName exch } if
+ names 5 findname { /Version exch } if
+ }
+ { % No name table, fabricate a FontName.
+ /FontName checksum 16 8 string cvrs
+ /FontInfo mark
+ }
+ ifelse
+ % Stack: /FontInfo mark key1 value1 ...
+ post null ne
+ { /ItalicAngle post 4 gets32 65536.0 div
+ /isFixedPitch post 12 getu32 0 ne
+ /UnderlinePosition post 8 gets16 upem div
+ /UnderlineThickness post 10 gets16 upem div
+ }
+ if
+ counttomark 0 ne
+ { .dicttomark }
+ { pop pop }
+ ifelse
+ /Encoding
+ cmaptab cmaparray
+ counttomark array astore { glyphencoding exch get } forall
+ counttomark 256 sub dup 0 ge
+ { { pop } repeat }
+ { neg { /.notdef } repeat }
+ ifelse ]
+ % Until we can compute the MD5 fingerprint,
+ % just use the precomputed checksum.
+ /XUID [orgXUID 42 checksum]
+ /CharStrings glyphencoding dup length dict
+ 0 1 3 index length 1 sub
+ { % Stack: glyphencoding dict index
+ 2 index 1 index get 2 index 1 index known
+ { pop pop }
+ { 2 index exch 3 -1 roll put }
+ ifelse
+ }
+ for exch pop readonly
+ /sfnts sfnts
+ .dicttomark
+ end end dup /FontName get exch definefont
+ } bind def
diff --git a/gs/lib/gs_typ42.ps b/gs/lib/gs_typ42.ps
new file mode 100644
index 000000000..fcce3d4a3
--- /dev/null
+++ b/gs/lib/gs_typ42.ps
@@ -0,0 +1,45 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Type 42 font support code.
+
+% Here are the BuildChar and BuildGlyph implementation for Type 42 fonts.
+% The names %Type42BuildChar and %Type42BuildGlyph are known to the
+% interpreter. The real work is done in an operator:
+% <font> <code|name> <name> <glyphindex> .type42execchar -
+
+(%Type42BuildChar) cvn % <font> <code> %Type42BuildChar -
+ { 1 index /Encoding get 1 index get .type42build
+ } bind def
+(%Type42BuildGlyph) cvn % <font> <name> %Type42BuildGlyph -
+ { dup .type42build
+ } bind def
+/.type42build % <font> <code|name> <name> .type42build -
+ { 2 index begin
+ dup CharStrings exch .knownget not
+ { 2 copy eq { exch pop /.notdef exch } if
+ QUIET not
+ { (Substituting .notdef for ) print = flush }
+ { pop }
+ ifelse
+ /.notdef CharStrings /.notdef get
+ } if
+ end .type42execchar
+ } bind def
+
+% Register the font type for definefont.
+buildfontdict 42 /.buildfont42 cvx put
diff --git a/gs/lib/gs_type1.ps b/gs/lib/gs_type1.ps
new file mode 100644
index 000000000..09e843270
--- /dev/null
+++ b/gs/lib/gs_type1.ps
@@ -0,0 +1,136 @@
+% Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Type 1 font support code.
+
+% The standard representation for PostScript compatible fonts is described
+% in the book "Adobe Type 1 Font Format", published by Adobe Systems Inc.
+
+% Define an augmented version of .buildfont1 that inserts UnderlinePosition
+% and UnderlineThickness entries in FontInfo if they aren't there already.
+% (This works around the incorrect assumption, made by many word processors,
+% that these entries are present in the built-in fonts.)
+/.buildfont1
+ { dup /FontInfo known not
+ { .growfontdict dup /FontInfo 2 dict put }
+ if
+ dup dup /FontInfo get dup dup
+ /UnderlinePosition known exch /UnderlineThickness known and
+ { pop pop % entries already present
+ }
+ { dup length 2 add dict .copydict
+ dup /UnderlinePosition known not
+ { dup /UnderlinePosition 3 index /FontBBox .knownget
+ { 1 get 2 div } % 1/2 the font descent
+ { -100 } ifelse put
+ }
+ if
+ dup /UnderlineThickness known not
+ { dup /UnderlineThickness 3 index /FontBBox .knownget
+ { dup 3 get exch 1 get sub 20 div } % 1/20 the font height
+ { 50 } ifelse put
+ }
+ if
+ 1 index /FontInfo get wcheck not { readonly } if
+ /FontInfo exch put
+ }
+ ifelse //.buildfont1
+ } bind def
+% If the diskfont feature isn't included, define a dummy .loadfontdict.
+/.loadfontdict where
+ { pop }
+ { /.loadfontdict 0 dict readonly def }
+ifelse
+/.loadfontfile % <file> .loadfontfile -
+ { mark exch //systemdict begin
+ DISKFONTS { .loadfontdict begin } if
+ % We really would just like systemdict on the stack,
+ % but fonts produced by Fontographer require a writable dictionary.
+ % However, we can't use any of the other well-known dictionaries
+ % (such as userdict), since the whole point of pushing systemdict
+ % is to make sure that nothing important has been redefined.
+ 5 dict begin
+ % We can't just use `run', because we want to check for .PFB files.
+ currentpacking
+ { false setpacking .loadfont1 true setpacking }
+ { .loadfont1 }
+ ifelse
+ { stop } if
+ end
+ DISKFONTS { end } if
+ end cleartomark
+ } bind def
+/.loadfont1 % <file> .loadfont1 <errorflag>
+ { % We would like to use `false /PFBDecode filter',
+ % but this occasionally produces a whitespace character as
+ % the first of an eexec section, so we can't do it.
+ % Also, since the real input file never reaches EOF if we are using
+ % a PFBDecode filter (the filter stops just after reading the last
+ % character), we must explicitly close the real file in this case.
+ % Since the file might leave garbage on the operand stack,
+ % we have to create a procedure to close the file reliably.
+ { dup read not { -1 } if
+ 2 copy unread 16#80 eq
+ { [ exch dup true /PFBDecode filter cvx exch cvlit
+ //systemdict /closefile get ]
+ }
+ if cvx exec
+ } stopped
+ $error /newerror get and dup { .clearerror } if
+ } bind def
+
+
+% The CharStrings are a dictionary in which the key is the character name,
+% and the value is a compressed and encrypted representation of a path.
+% For detailed information, see the book "Adobe Type 1 Font Format",
+% published by Adobe Systems Inc.
+
+% Here are the BuildChar and BuildGlyph implementation for Type 1 fonts.
+% The names %Type1BuildChar and %Type1BuildGlyph are known to the interpreter.
+% The real work is done in an operator:
+% <font> <code|name> <name> <charstring> .type1execchar -
+
+(%Type1BuildChar) cvn % <font> <code> %Type1BuildChar -
+ { 1 index /Encoding get 1 index get .type1build
+ } bind def
+(%Type1BuildGlyph) cvn % <font> <name> %Type1BuildGlyph -
+ { dup .type1build
+ } bind def
+/.type1build % <font> <code|name> <name> .type1build -
+ { 2 index begin
+ dup CharStrings exch .knownget not
+ { 2 copy eq { exch pop /.notdef exch } if
+ QUIET not
+ { (Substituting .notdef for ) print = flush }
+ { pop }
+ ifelse
+ /.notdef CharStrings /.notdef get
+ } if
+ end .type1execchar
+ } bind def
+% CCRun is an undocumented procedure provided for Type 4 fonts.
+1183615869 internaldict begin
+/CCRun % <font> <code|name> <charstring> CCRun -
+ { 1 index dup type /integertype eq
+ { 3 index /Encoding get exch get }
+ if exch .type1execchar
+ } bind def
+end
+
+% Register the font types for definefont.
+buildfontdict 1 /.buildfont1 cvx put
+buildfontdict 4 /.buildfont4 cvx put
diff --git a/gs/lib/gs_wan_e.ps b/gs/lib/gs_wan_e.ps
new file mode 100644
index 000000000..ba63c51ca
--- /dev/null
+++ b/gs/lib/gs_wan_e.ps
@@ -0,0 +1,45 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the WinAnsi encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/WinAnsiEncoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /bullet
+% \20x
+ /bullet /bullet /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /bullet /bullet /bullet
+ /bullet /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /bullet /bullet /Ydieresis
+ISOLatin1Encoding 160 96 getinterval aload pop
+256 packedarray
+4 1 index .registerencoding
+.defineencoding
+exec
diff --git a/gs/lib/gs_wl1_e.ps b/gs/lib/gs_wl1_e.ps
new file mode 100644
index 000000000..5dfe719e3
--- /dev/null
+++ b/gs/lib/gs_wl1_e.ps
@@ -0,0 +1,67 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the Windows 3.1 Latin 1 encoding vector (H-P Symbol set 19U).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win31Latin1Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /.notdef /.notdef /.notdef
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /.notdef /.notdef /Ydieresis
+ /.notdef /exclamdown /cent /sterling
+ /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft
+ /logicalnot /softhyphen /registered /overscore
+ /degree /plusminus /twosuperior /threesuperior
+ /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright
+ /onequarter /onehalf /threequarters /questiondown
+% \30x
+ /Agrave /Aacute /Acircumflex /Atilde
+ /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis
+ /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute
+ /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex
+ /Udieresis /Yacute /Thorn /germandbls
+ /agrave /aacute /acircumflex /atilde
+ /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis
+ /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute
+ /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex
+ /udieresis /yacute /thorn /ydieresis
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_wl2_e.ps b/gs/lib/gs_wl2_e.ps
new file mode 100644
index 000000000..ed7e3ccda
--- /dev/null
+++ b/gs/lib/gs_wl2_e.ps
@@ -0,0 +1,67 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the Windows 3.1 Latin 2 encoding vector (H-P Symbol set 9E).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win32Latin2Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /.notdef
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /.notdef /perthousand /Scaron /guilsinglleft
+ /Sacute /Tcaron /Zcaron /Zacute
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /.notdef /trademark /scaron /guilsinglright
+ /sacute /tcaron /zcaron /zacute
+ /.notdef /caron /breve /Lslash
+ /currency /Aogonek /brokenbar /section
+ /dieresis /copyright /Scedilla /guillemotleft
+ /logicalnot /softhyphen /registered /Zdotaccent
+ /degree /plusminus /ogonek /lslash
+ /acute /mu /paragraph /periodcentered
+ /cedilla /aogonek /scedilla /guillemotright
+ /Lcaron /hungarumlaut /lcaron /zdotaccent
+% \30x
+ /Racute /Aacute /Acircumflex /Abreve
+ /Adieresis /Lacute /Cacute /Ccedilla
+ /Ccaron /Eacute /Eogonek /Edieresis
+ /Ecaron /Iacute /Icircumflex /Dcaron
+ /Dcroat /Nacute /Ncaron /Oacute
+ /Ocircumflex /Ohungarumlaut /Odieresis /multiply
+ /Rcaron /Uring /Uacute /Uhungarumlaut
+ /Udieresis /Yacute /Tcommaaccent /germandbls
+ /racute /aacute /acircumflex /abreve
+ /adieresis /lacute /cacute /ccedilla
+ /ccaron /eacute /eogonek /edieresis
+ /ecaron /iacute /icircumflex /dcaron
+ /dcroat /nacute /ncaron /oacute
+ /ocircumflex /ohungarumlaut /odieresis /divide
+ /rcaron /uring /uacute /uhungarumlaut
+ /udieresis /yacute /tcommaaccent /dotaccent
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gs_wl5_e.ps b/gs/lib/gs_wl5_e.ps
new file mode 100644
index 000000000..619c29eba
--- /dev/null
+++ b/gs/lib/gs_wl5_e.ps
@@ -0,0 +1,67 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Define the Windows 3.1 Latin 5 encoding vector (H-P Symbol set 5T).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win32Latin5Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /.notdef /.notdef /.notdef
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /.notdef /.notdef /Ydieresis
+ /.notdef /exclamdown /cent /sterling
+ /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft
+ /logicalnot /softhyphen /registered /overscore
+ /degree /plusminus /twosuperior /threesuperior
+ /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright
+ /onequarter /onehalf /threequarters /questiondown
+% \30x
+ /Agrave /Aacute /Acircumflex /Atilde
+ /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis
+ /Igrave /Iacute /Icircumflex /Idieresis
+ /Gbreve /Ntilde /Ograve /Oacute
+ /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex
+ /Udieresis /Idotaccent /Scedilla /germandbls
+ /agrave /aacute /acircumflex /atilde
+ /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis
+ /igrave /iacute /icircumflex /idieresis
+ /gbreve /ntilde /ograve /oacute
+ /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex
+ /udieresis /dotlessi /scedilla /ydieresis
+256 packedarray .defineencoding
+exec
diff --git a/gs/lib/gsbj b/gs/lib/gsbj
new file mode 100755
index 000000000..6bcafab43
--- /dev/null
+++ b/gs/lib/gsbj
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -sDEVICE=bj10e -r180 -dNOPAUSE -sPROGNAME=$0 -- gslp.ps --heading-center "`date`" "$@"
diff --git a/gs/lib/gsbj.bat b/gs/lib/gsbj.bat
new file mode 100755
index 000000000..f51261b34
--- /dev/null
+++ b/gs/lib/gsbj.bat
@@ -0,0 +1 @@
+@gs -q -sDEVICE=bj10e -r180 -dNOPAUSE -sPROGNAME=gsbj -- gslp.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gsdj b/gs/lib/gsdj
new file mode 100755
index 000000000..a87b1a84b
--- /dev/null
+++ b/gs/lib/gsdj
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -sDEVICE=deskjet -r300 -dNOPAUSE -sPROGNAME=$0 -- gslp.ps --heading-center "`date`" "$@"
diff --git a/gs/lib/gsdj.bat b/gs/lib/gsdj.bat
new file mode 100755
index 000000000..f07cc7ff8
--- /dev/null
+++ b/gs/lib/gsdj.bat
@@ -0,0 +1 @@
+@gs -q -sDEVICE=deskjet -r300 -dNOPAUSE -sPROGNAME=gsdj -- gslp.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gsdj500 b/gs/lib/gsdj500
new file mode 100755
index 000000000..df77f8a57
--- /dev/null
+++ b/gs/lib/gsdj500
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -sDEVICE=djet500 -r300 -dNOPAUSE -sPROGNAME=$0 -- gslp.ps --heading-center "`date`" "$@"
diff --git a/gs/lib/gsdj500.bat b/gs/lib/gsdj500.bat
new file mode 100755
index 000000000..05cb796a1
--- /dev/null
+++ b/gs/lib/gsdj500.bat
@@ -0,0 +1 @@
+@gs -q -sDEVICE#djet500 -r300 -dNOPAUSE -sPROGNAME=gsdj500 -- gslp.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gslj b/gs/lib/gslj
new file mode 100755
index 000000000..976aab68e
--- /dev/null
+++ b/gs/lib/gslj
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -sDEVICE=laserjet -r300 -dNOPAUSE -sPROGNAME=$0 -- gslp.ps --heading-center "`date`" "$@"
diff --git a/gs/lib/gslj.bat b/gs/lib/gslj.bat
new file mode 100755
index 000000000..6fb54b54d
--- /dev/null
+++ b/gs/lib/gslj.bat
@@ -0,0 +1 @@
+@gs -q -sDEVICE=laserjet -r300 -dNOPAUSE -sPROGNAME=gslj -- gslp.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gslp b/gs/lib/gslp
new file mode 100755
index 000000000..9054010cb
--- /dev/null
+++ b/gs/lib/gslp
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -sDEVICE=epson -r180 -dNOPAUSE -sPROGNAME=$0 -- gslp.ps --heading-center "`date`" "$@"
diff --git a/gs/lib/gslp.bat b/gs/lib/gslp.bat
new file mode 100755
index 000000000..fb0b15904
--- /dev/null
+++ b/gs/lib/gslp.bat
@@ -0,0 +1 @@
+@gs -q -sDEVICE=epson -r180 -dNOPAUSE -sPROGNAME=gslp -- gslp.ps %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gslp.ps b/gs/lib/gslp.ps
new file mode 100644
index 000000000..650beaa7a
--- /dev/null
+++ b/gs/lib/gslp.ps
@@ -0,0 +1,537 @@
+% Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% gslp.ps - format and print text
+
+% This utility provides functionality approximately equivalent to the Unix
+% `enscript' program. It prints plain text files using a single font.
+% It currently handles tabs and formfeeds, but not backspaces.
+% It only works with fixed-pitch fonts.
+% Standard flags implemented:
+% -12BclqRr -b<header> -f<font> -F<hfont> -L<lines> -p<outfile>
+% Sun flags implemented:
+% -T<n> set tab width
+% Flags ignored:
+% -GghKkmow -# -C -d -J -n -P -S -s -t -v
+% Flags added:
+% --columns <n>
+% print in <n> columns
+% --detect
+% treat the file as PostScript if it starts with %!
+% --first-page <n>
+% start printing at page <n>
+% --last-page <n>
+% stop printing after page <n>
+% --(heading|footing)-(left|center|right) <string>
+% set the heading/footing fields; use -B first to clear
+% --margin-(top|bottom|left|right) <inches>
+% set a margin
+% --no-eject-(file|formfeed)
+% end-of-file/FF only starts a new column, not a new sheet
+% --spacing <n>
+% use double (n=2), triple (n=3), etc. spacing
+% Also, the string %# in a heading or footing is replaced with the page #.
+/PageNumberString (%#) def
+
+/lpdict 150 dict def
+lpdict begin
+
+% build iso-latin-1 version of a font
+/font-to-iso-latin-1 { % <font> font-to-iso-latin-1 <font>
+ %% reencode for iso latin1; from the 2nd edition red book, sec 5.6.1
+ dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall
+ /Encoding ISOLatin1Encoding def currentdict end
+ dup /FontName get 80 string cvs (-ISOLatin1) concatstrings cvn
+ exch definefont
+} def
+
+/find-latin-font { % <name> find-latin-font <font>
+ findfont font-to-iso-latin-1
+} def
+
+% Define the initial values of the printing parameters.
+
+/BodyFont null def % use default
+ /defaultBodyFont
+ { /Courier find-latin-font Landscape { 7 } { 10 } ifelse scalefont } def
+/Columns 1 def
+/DetectFileType false def
+/EjectEOF true def
+/EjectFF true def
+/Footers false def
+/FootingLeft () def
+/FootingCenter () def
+/FootingRight () def
+/Headers true def
+/HeadingLeft () def
+/HeadingCenter () def
+/HeadingRight (page ) PageNumberString concatstrings def
+/HeadingFont null def % use default
+ /defaultHeadingFont
+ { /Courier-Bold find-latin-font 10 scalefont } def
+/Landscape false def
+/MarginBottom 36 def % 1/2"
+/MarginLeft 36 def % 1/2"
+/MarginRight 36 def % 1/2"
+/MarginTop 36 def % 1/2"
+/MaxLines 9999 def % max lines per page
+/Noisy true def % i.e., not quiet
+/OutFile null def % null = write directly to device
+/PageFirst 1 def
+/PageLast 99999 def
+/Spacing 1 def
+/Tab 8 def
+/Truncate false def % wrap long lines, don't truncate
+
+% When writing to a file, we want to write out PostScript;
+% when writing to the printer, we want to execute it;
+% some commands should be executed regardless.
+% lpexec provides for all this.
+
+/lpexec % <arg1> ... <argn> </op> <n> <do_always> lpexec -
+ { OutFile null eq
+ { pop 1 add true
+ }
+ { /t exch def 1 add /n exch def cvx
+ n { n -1 roll dup wosp } repeat
+ OutFile (\n) writestring
+ n t
+ }
+ ifelse
+ { pop load exec }
+ { { pop } repeat }
+ ifelse
+ } def
+
+/lpmoveto
+ { /moveto 2 true lpexec
+ } def
+/lpshow
+ { dup length 0 ne { /show 1 true lpexec } { pop } ifelse
+ } def
+/lpsetmyfont
+ { dup load setfont
+ OutFile null ne { cvx /setfont 1 false lpexec } { pop } ifelse
+ } def
+
+% Define some utility procedures.
+
+/banner % ypos left center right
+ { /HFont lpsetmyfont
+ 3 -1 roll bannerstring pop 0 4 index pwidth showline2 pop
+ exch bannerstring pwidth exch sub 2 div 3 index pwidth showline2 pop
+ bannerstring
+ % Prevent the last character of the heading from grazing
+ % the right margin.
+ % ****** WHY DOES IT REQUIRE SO MUCH PADDING? ******
+ ( ) stringwidth pop 2 mul add
+ pwidth exch sub
+ 3 -1 roll pwidth showline2 pop
+ } def
+
+/bannerstring % string -> string width
+ { PageNumberString search
+ { exch pop pindex 4 string cvs concatstrings exch concatstrings
+ }
+ if dup stringwidth pop
+ } def
+
+/beginpage
+ { /lindex 0 def
+ /skipping pindex PageFirst ge pindex PageLast le and not def
+ /save 0 true lpexec /pagesave exch def
+ skipping { nulldevice /OutFile null def } if
+ Headers
+ { lheight hdescent add
+ HeadingLeft HeadingCenter HeadingRight banner
+ } if
+ /BFont lpsetmyfont
+ } def
+
+/endpage
+ { lindex 0 ne
+ { Footers
+ { topskip plength sub hdescent add
+ FootingLeft FootingCenter FootingRight banner
+ } if
+ /showpage 0 false lpexec
+ } if
+ pagesave /restore 0 true lpexec
+ /pindex pindex 1 add def
+ } def
+
+/endcolumn
+ { lindex colines 1 sub add colines idiv colines mul
+ dup llength ge { pop endpage beginpage } { /lindex exch def } ifelse
+ } def
+
+/fontheight % <font> fontheight <ascent> <height>
+ { gsave setfont
+ newpath 0 0 moveto
+ (|^_j) false charpath
+ pathbbox exch pop dup 2 index sub 4 -2 roll pop pop
+ grestore exch 1.25 mul exch 1.25 mul
+ } def
+
+/wosp
+ { OutFile ( ) writestring OutFile exch write==only
+ } def
+
+/outfont % name font ->
+ { OutFile null ne
+ { exch wosp
+ dup /FontName get
+ dup wosp OutFile ( findfont) writestring
+ %% reencode for iso latin1; from the 2nd edition red book, sec 5.6.1
+ OutFile (
+ dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall
+ /Encoding ISOLatin1Encoding def currentdict end
+ ) writestring
+ wosp OutFile (-ISOLatin1 exch definefont) writestring
+ /FontMatrix get 0 get 1000 mul round cvi wosp
+ OutFile ( scalefont def\n) writestring
+ }
+ { pop pop
+ }
+ ifelse
+ } def
+
+/StringFF (\f) def
+/CharFF StringFF 0 get def
+/StringTAB (\t) def
+/CharTAB StringTAB 0 get def
+
+/showline % line -> leftover_line (handles \f)
+ { { showline1 dup length 0 eq { exit } if
+ dup 0 get CharFF ne { exit } if
+ EjectFF { endpage beginpage } { endcolumn } ifelse
+ skip1
+ }
+ loop
+ } def
+
+/showline1 % line -> leftover_line (handles page break)
+ { lindex llength eq { endpage beginpage } if
+ lindex colines idiv cowidth mul % x
+ lindex colines mod 1 add lheight mul neg fascent sub % y
+ 1 index cowidth add
+ showline2
+ /lindex lindex 1 add def
+ } def
+
+/showline2 % string x y xlimit -> leftover_string (handles tabs)
+ { 2 index exch 5 2 roll lpmoveto % xinit xlimit string
+ { showline3 dup length 0 eq { exit } if
+ dup 0 get CharTAB ne { exit } if
+ currentpoint exch 4 index sub tabwx div
+ 0.05 add ceiling tabwx mul 4 index add exch lpmoveto
+ skip1
+ currentpoint pop 2 index ge { exit } if
+ }
+ loop exch pop exch pop
+ } def
+
+/showline3 % xlimit string -> xlimit leftover_string
+ % (finds line break / tab / formfeed)
+ { currentpoint pop 2 index exch sub
+ cwx div 0.1 add cvi 0 max 1 index length min
+ 1 index 0 3 -1 roll getinterval
+ % look for \f or \t
+ StringFF search { exch pop exch pop } if
+ StringTAB search { exch pop exch pop } if
+ dup lpshow
+ length dup 2 index length exch sub getinterval
+ } def
+
+/skip1
+ { dup length 1 sub 1 exch getinterval
+ } def
+
+/e== { % <object> e== - -- print an object to stderr
+ (%stderr) (w) file dup 3 -1 roll write==only flushfile
+} def
+
+/eprint { % <string> eprint - -- print a string to stderr
+ (%stderr) (w) file dup 3 -1 roll writestring flushfile
+} def
+
+% The main printing procedure
+
+/lp % file initial_chars ->
+ { /lpline exch def
+ /lpfile exch def
+ /save 0 true lpexec
+
+% Initialize the device and fonts.
+ /BFont
+ BodyFont null eq { defaultBodyFont } { BodyFont } ifelse def
+ /BFont BFont outfont
+ Headers Footers or
+ { /HFont
+ HeadingFont null eq { defaultHeadingFont } { HeadingFont } ifelse def
+ /HFont HFont outfont
+ }
+ if
+
+% Get the layout parameters.
+ clippath
+ Landscape { 90 /rotate 1 true lpexec } if
+ BFont setfont ( ) stringwidth pop /cwx exch def
+ cwx Tab mul /tabwx exch def
+ BFont fontheight /fheight exch def /fascent exch def
+ Headers Footers or { HFont fontheight } { 0 0 } ifelse
+ /hheight exch def /hascent exch def
+ /hdescent hheight hascent sub def
+ fheight Spacing mul /lheight exch def
+ Headers { hheight lheight add } { 0 } ifelse
+ /topskip exch def
+ Footers { hheight lheight add } { 0 } ifelse
+ /botskip exch def
+ /pskip topskip botskip add def
+ % Translate the page so that (0,0) corresponds to
+ % the top of the topmost body line.
+ pathbbox
+ 2 index sub MarginBottom MarginTop add sub /plength exch def
+ 2 index sub MarginLeft MarginRight add sub /pwidth exch def
+ pwidth Columns div /cowidth exch def
+ exch MarginLeft add
+ exch MarginBottom add plength add topskip sub
+ /translate 2 true lpexec
+ plength pskip sub lheight div cvi MaxLines min
+ dup /colines exch def
+ Columns mul /llength exch def
+ OutFile null ne { nulldevice } if
+
+% Print layout
+ Noisy
+ { (Page height = ) eprint llength e==
+ (.\n) eprint flush
+ } if
+
+% Disable stack recording so we can use stopped with readline.
+ $error /recordstacks false put
+
+% Initialize for the first page.
+ /lbuf 1000 string def
+ /pindex 1 def
+ beginpage
+
+% Iterate through the file.
+ lpline
+ { dup length /pos exch def
+ lbuf exch 0 exch putinterval
+ { lpfile lbuf pos lbuf length pos sub getinterval readline } stopped
+ { % Filled the line before a CR or EOF.
+ exch pop showline
+ }
+ { % Reached CR and/or EOF first.
+ exch length pos add lbuf exch 0 exch getinterval
+ 1 index { showline } if % omit final empty line
+ { dup length 0 eq Truncate or { pop () exit } if
+ showline
+ }
+ loop
+ exch not { exit } if
+ }
+ ifelse
+ } loop
+ pop
+
+% Wrap up.
+%**************** WHY IS THIS COMMENTED OUT? ****************
+% EjectEOF { endpage } { endcolumn } ifelse
+ endpage
+ /restore 0 true lpexec
+
+ } def
+
+end
+
+% Usage: <file> lp
+% prints <file> using the current parameter settings.
+% Usage: [ <arg1> ... <argn> ] lpcommand
+% interprets args like a command line.
+
+/lp { save lpdict begin () lp end restore } def
+
+lpdict begin
+
+/splitfn % (FontNNN) -> <font>
+ { dup /arg exch def length
+ { dup 0 le { exit } if
+ dup 1 sub arg exch get dup 48 ge exch 59 le and not { exit } if
+ 1 sub
+ } loop
+ arg exch 0 exch getinterval dup cvn find-latin-font
+ exch arg exch anchorsearch pop pop cvr scalefont
+ } def
+
+% Parse the command line switches.
+
+/doswitch % argn ... arg1 (-?) restofswitch ->
+ { exch dup cvn lpdict exch known
+ { cvn load exec }
+ { exch pop (Unknown switch: ) eprint eprint (\n) eprint }
+ ifelse
+ } def
+
+/more % argn ... arg1 restofswitch ->
+ { dup length 0 ne
+ { (- ) dup 1 3 index 0 get put
+ exch dup length 1 sub 1 exch getinterval
+ doswitch
+ }
+ { pop
+ }
+ ifelse
+ } def
+
+/-- { (--) exch concatstrings
+ dup cvn lpdict exch known
+ { cvn load exec }
+ { (Unknown switch: ) eprint eprint (\n) eprint }
+ ifelse
+ } def
+/--columns { cvi 1 max /Columns exch def } def
+/--detect { /DetectFileType true def } def
+/--first-page { cvi /PageFirst exch def } def
+/--footing-center { /FootingCenter exch def /Footers true def } def
+/--footing-left { /FootingLeft exch def /Footers true def } def
+/--footing-right { /FootingRight exch def /Footers true def} def
+/--heading-center { /HeadingCenter exch def /Headers true def } def
+/--heading-left { /HeadingLeft exch def /Headers true def } def
+/--heading-right { /HeadingRight exch def /Headers true def } def
+/--last-page { cvi /PageLast exch def } def
+/--margin-bottom { cvr 72.0 mul /MarginBottom exch def } def
+/--margin-left { cvr 72.0 mul /MarginLeft exch def } def
+/--margin-right { cvr 72.0 mul /MarginRight exch def } def
+/--margin-top { cvr 72.0 mul /MarginTop exch def } def
+/--no-eject-file { /EjectEOF false def } def
+/--no-eject-formfeed { /EjectFF false def } def
+/--spacing { cvr /Spacing exch def } def
+
+/-# { pop } def % ignore
+/-+ { -- } def
+(-1)cvn { /Columns 1 def more } def
+(-2)cvn { /Columns 2 def more } def
+/-b { /HeadingLeft exch def /HeadingCenter () def /HeadingRight PageNumberString def
+ /Headers true def
+ /break true def
+ } def
+/-B { /HeadingLeft () def /HeadingCenter () def /HeadingRight () def
+ /Headers false def
+ /FootingLeft () def /FootingCenter () def /FootingRight () def
+ /Footers false def
+ /break true def
+ more
+ } def
+/-C { pop } def % ignore
+/-c { /Truncate true def more } def
+/-d { pop } def % ignore
+/-f { splitfn /BodyFont exch def } def
+/-F { splitfn /HeadingFont exch def } def
+/-G { more } def % ignore
+/-g { more } def % ignore
+/-h { more } def % ignore
+/-J { pop } def % ignore
+/-K { more } def % ignore
+/-k { more } def % ignore
+/-l { 66 -L -B } def
+/-L { cvi /MaxLines exch def } def
+/-m { more } def % ignore
+/-n { pop } def % ignore
+/-o { more } def % ignore
+/-p { (w) file /OutFile exch def OutFile (%!\n) writestring } def
+/-P { pop } def % ignore
+/-q { /Noisy false def more } def
+/-r { /Landscape true def more } def
+/-R { /Landscape false def more } def
+/-S { pop } def % ignore
+/-s { pop } def % ignore
+/-T { cvi /Tab exch def } def
+/-v { pop } def % ignore
+/-w { more } def % ignore
+
+/lp1 % filename ->
+ { break not { dup /HeadingLeft exch def } if
+ Noisy
+ { (Printing ) eprint dup eprint (\n) eprint
+ } if
+ (r) file
+ % If requested, check for a PostScript file.
+ DetectFileType
+ { dup 2 string readstring pop dup (%!) eq
+ { % Yes, it's a PostScript file.
+ pop dup 80 string readline pop pop cvx exec
+ }
+ { lp
+ }
+ ifelse
+ }
+ { () lp
+ }
+ ifelse
+ } bind def
+
+/lpcstring 100 string def
+
+end
+
+/lpcommand % <[arg1 ... argn]> lpcommand <any_printed>
+ { % Push the commands on the stack in reverse order
+ mark exch
+ dup length 1 sub -1 0 { 1 index exch get exch } for pop
+ lpdict begin
+ /any false def
+ /break false def
+ { dup mark eq { pop exit } if
+ dup length 2 ge { dup 0 get (-) 0 get eq } { false } ifelse
+ { dup 0 2 getinterval
+ exch dup length 2 sub 2 exch getinterval
+ doswitch
+ }
+ { dup /matched false def
+ { /matched true def /any true def lp1 } lpcstring filenameforall
+ matched { pop } { lp1 } ifelse % let the error happen
+ }
+ ifelse
+ } loop
+ OutFile null ne
+ { OutFile (%stdout) (w) file ne { OutFile closefile } if
+ /OutFile null def
+ } if
+ any
+ end
+ } def
+
+[ shellarguments
+ { ] dup length 0 ne { lpcommand } { false } ifelse not
+ { (%stderr) (w) file
+ [ (Usage: )
+ /PROGNAME where { pop PROGNAME } { (gslp) } ifelse
+ ( [-12BclqRr] [-b<header>] [-f<font>] [-F<hfont>]\n)
+ ( [-L<lines>] [-p<outfile>] [-T<tabwidth>] [--columns <n>]\n)
+ ( [--detect] [--first-page <page#>] [--last-page <page#>]\n)
+ ( [--(heading|footing)-(left|right|center) <string>]\n)
+ ( [--margin-(top|bottom|left|right) <inches>]\n)
+ ( [--no-eject-(file|formfeed)] [--spacing <n>] file1 ... filen\n)
+ ] { 2 copy writestring pop } forall dup flushfile closefile
+ }
+ if
+ }
+ { pop }
+ifelse
diff --git a/gs/lib/gsnd b/gs/lib/gsnd
new file mode 100755
index 000000000..f85a3c5f6
--- /dev/null
+++ b/gs/lib/gsnd
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -DNODISPLAY "$@"
diff --git a/gs/lib/gsnd.bat b/gs/lib/gsnd.bat
new file mode 100755
index 000000000..c190d6670
--- /dev/null
+++ b/gs/lib/gsnd.bat
@@ -0,0 +1 @@
+@gs -DNODISPLAY %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/gs/lib/gsndt.bat b/gs/lib/gsndt.bat
new file mode 100755
index 000000000..793708f23
--- /dev/null
+++ b/gs/lib/gsndt.bat
@@ -0,0 +1 @@
+@gst -DNODISPLAY %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file
diff --git a/gs/lib/gst.bat b/gs/lib/gst.bat
new file mode 100755
index 000000000..0e4f03c8b
--- /dev/null
+++ b/gs/lib/gst.bat
@@ -0,0 +1 @@
+@gs %1 %2 %3 %4 %5 %6 %7 %8 %9 >t
diff --git a/gs/lib/gstt.bat b/gs/lib/gstt.bat
new file mode 100755
index 000000000..67c8f1c46
--- /dev/null
+++ b/gs/lib/gstt.bat
@@ -0,0 +1 @@
+@gs %1 %2 %3 %4 %5 %6 %7 %8 %9 >>t
diff --git a/gs/lib/impath.ps b/gs/lib/impath.ps
new file mode 100644
index 000000000..0fc2d9c7c
--- /dev/null
+++ b/gs/lib/impath.ps
@@ -0,0 +1,180 @@
+% Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% impath.ps
+% Reverse-rasterize a bitmap to produce a Type 1 outline.
+% (This was formerly a Ghostscript operator implemented in C.)
+
+% <image> <width> <height> <wx> <wy> <ox> <oy> <string>
+% type1imagepath <substring>
+% Converts an image (bitmap) description of a character into
+% a scalable description in Adobe Type 1 format. The
+% current transformation matrix should be the same as the
+% FontMatrix of the font in which this character will be
+% used: this establishes the scaling relationship between
+% image pixels (the image is assumed to be 1 unit high in
+% user space) and the character coordinate system used in
+% the scalable description. wx and wy are the character
+% width, and ox and oy are the character origin relative
+% to the lower left corner of the bitmap, in *pixels*.
+% The image is assumed to be stored in left-to-right,
+% top-to-bottom order. Note that this is not consistent
+% with the `image' operator's interpretation of the CTM.
+% All coordinates in the scalable description are rounded to
+% integers, so the coefficients in the FontMatrix should
+% be on the order of 1/N for some value of N that is
+% either a multiple of the height/width or is large
+% compared to the width and height. (There is a
+% convention, which some PostScript programs rely on, that
+% N=1000.)
+% Note that the encoded description has *not* been subjected
+% to CharString encryption, which is necessary before the
+% description can be given to type1addpath: to do this,
+% follow the type1imagepath with
+% 4330 exch dup .type1encrypt exch pop
+% If the description is too complex to fit into the supplied
+% string, a limitcheck error results. A good rule of
+% thumb is that the size of the string should be about 6
+% times the number of 1-bits in the image that are not
+% completely surrounded by other 1-bits.
+
+% Import the Type 1 opcodes.
+(type1ops.ps) runlibfile
+
+100 dict
+dup /type1imagepath_dict exch def
+begin
+
+/rc { round cvi } bind def
+/moving [/rmoveto /hmoveto /vmoveto] def
+/drawing [/rlineto /hlineto /vlineto] def
+
+% Convert the current path to a Type 1 token array.
+/putxy % x y ops -> cs_elements
+ { 3 -1 roll dup x sub rc exch /x exch def
+ 3 -1 roll dup y sub rc exch /y exch def
+ % stack: ops dx dy
+ dup 0 eq
+ { % dy = 0, use hmoveto/lineto
+ pop exch 1 get
+ }
+ { 1 index 0 eq
+ { % dx = 0, use vmoveto/lineto
+ exch pop exch 2 get
+ }
+ { % use rmoveto/rlineto
+ 3 -1 roll 0 get
+ }
+ ifelse
+ }
+ ifelse
+ } bind def
+/pathtotype1 % -> charstack
+ { 3 dict begin /x 0 def /y 0 def
+ mark
+ { moving putxy
+ }
+ { drawing putxy
+ }
+ { % Convert curve to relative form
+ x y 3
+ { exch neg 7 index add rc
+ exch neg 6 index add rc
+ 8 -2 roll
+ }
+ repeat /y exch def /x exch def
+ 1 index 0 eq 5 index 0 eq and % dy1=dx3=0, hv
+ { 5 -1 roll pop exch pop /hvcurveto
+ }
+ { dup 0 eq 6 index 0 eq and % dx1=dy3=0, vh
+ { 6 -1 roll pop pop /vhcurveto
+ }
+ { /rrcurveto % none of the above
+ }
+ ifelse
+ }
+ ifelse
+ }
+ { /closepath
+ }
+ pathforall end
+ } bind def
+
+end % type1imagepath_dict
+
+% The main program
+/type1imagepath % image width height wx wy ox oy string ->
+ % substring
+ { type1imagepath_dict begin
+ /tsave save def
+ /ostring exch def
+ /oy exch def /ox exch def
+ /wy exch def /wx exch def
+ /height exch def /width exch def
+ /data exch def
+
+ /ofilter ostring /NullEncode filter def
+ /raster width 7 add 8 idiv def
+
+% Construct the coordinate transformation.
+ height dup scale
+ matrix currentmatrix matrix invertmatrix setmatrix
+
+% Determine the left side bearing.
+ /lsbx width
+ 0 1 width 1 sub
+ { dup dup 8 idiv 0 exch
+ raster raster height mul 1 sub
+ { data exch get or }
+ for exch 8 mod bitshift 128 and 0 ne
+ { exch pop exit }
+ if pop
+ }
+ for def
+
+% Compute and encode the origin, width, and side bearing.
+ mark
+ ox oy dtransform
+ rc /opty exch def rc /optx exch def
+ wx wy dtransform
+ rc /iwy exch def rc /iwx exch def
+ lsbx ox sub 0 dtransform
+ rc /ilsby exch def rc /ilsbx exch def
+ ilsbx
+ iwy 0 ne ilsby 0 ne or
+ { ilsby iwx iwy /sbw }
+ { iwx /hsbw }
+ ifelse
+ ofilter charstack_write
+
+% Flip over the Y axis, because the image is stored top-to-bottom.
+ [1 0 0 -1 0 height] concat
+% Account for the character origin.
+ lsbx oy translate
+% Trace the outline.
+ newpath
+ width height data .imagepath
+ gsave matrix setmatrix pathtotype1 grestore
+ ofilter charstack_write
+% Terminate the output
+ mark /endchar ofilter charstack_write
+
+ ofilter fileposition ofilter closefile % flush buffers
+ ostring 0 3 -1 roll getinterval
+ tsave restore
+ end
+ } bind def
diff --git a/gs/lib/landscap.ps b/gs/lib/landscap.ps
new file mode 100644
index 000000000..5d69ca21a
--- /dev/null
+++ b/gs/lib/landscap.ps
@@ -0,0 +1,29 @@
+%!
+% landscap.ps
+% This file can be prepended to most PostScript pages to force
+% rotation to "landscape" mode.
+%
+% There are (at least) four possible ways to reasonably position a
+% page after rotation. Any of the four old corners (llx,lly e.g.)
+% can be moved to match the corresonding new corner.
+% By uncommmenting the appropriate line below (i.e., remove the
+% leading '%'), any such positioning can be chosen for positive or
+% negative rotation. The comments at the end of each "rotate" line
+% indicate the ORIGINAL corner to be aligned. For example, as given
+% below, the lower left hand corner is aligned. When viewed, this
+% corner will have moved to the urx,lly corner.
+%
+% James E. Burns, 3/8/93, burns@nova.bellcore.com
+%
+gsave clippath pathbbox grestore
+4 dict begin
+/ury exch def /urx exch def /lly exch def /llx exch def
+%90 rotate llx neg ury neg translate % llx,ury
+90 rotate llx neg llx urx sub lly sub translate % llx,lly
+%90 rotate ury lly sub urx sub ury neg translate % urx,ury
+%90 rotate ury lly sub urx sub llx urx sub lly sub translate % urx,lly
+%-90 rotate urx neg lly neg translate % urx,lly
+%-90 rotate urx neg urx llx sub ury sub translate % urx,ury
+%-90 rotate llx lly add ury sub urx llx sub ury sub translate % llx,ury
+%-90 rotate llx lly add ury sub lly neg translate % llx,lly
+end
diff --git a/gs/lib/level1.ps b/gs/lib/level1.ps
new file mode 100644
index 000000000..b4c53c1a4
--- /dev/null
+++ b/gs/lib/level1.ps
@@ -0,0 +1,2 @@
+%!
+/.setlanguagelevel where { pop 1 .setlanguagelevel } if
diff --git a/gs/lib/lines.ps b/gs/lib/lines.ps
new file mode 100644
index 000000000..eb1b89f3a
--- /dev/null
+++ b/gs/lib/lines.ps
@@ -0,0 +1,152 @@
+%!
+% ** Copyright (C) 1989, 1990, 1992, 1994, 1996 by Aladdin Enterprises. **
+% ** All rights reserved. **
+
+% Test line rendering (stroke).
+
+% Exercise the miter limit. The left column of lines should bevel at
+% 90 degrees, the right column at 60 degrees.
+
+gsave
+1.8 setlinewidth
+0 setgray
+15 15 scale
+-5 5 translate
+[1.415 2.0]
+ { setmiterlimit 12 0 translate 0 0 moveto
+ 10 30 360
+ { gsave 5 0 rlineto rotate 2.5 0 rlineto
+ gsave 0 setlinewidth 1 0 0 setrgbcolor stroke grestore
+ strokepath 0 setlinewidth stroke
+ grestore
+ 0 4 rmoveto
+ } for
+ } forall
+
+showpage
+grestore
+
+% Exercise all the combinations of cap and join styles
+% for one-line, two-line, and closed paths.
+
+gsave
+
+/drawlines {
+gsave
+2.0 setmiterlimit
+2.0 setlinewidth
+6 6 scale
+5 20 translate
+{0 1 2} % line cap
+ { setlinecap gsave
+ {0 1 2} % line join
+ { setlinejoin gsave
+ { {currentpoint lineto}
+ {3 7 lineto}
+ {3 7 lineto 5 1 lineto}
+ {3 7 lineto 6 3 lineto closepath}
+ }
+ { gsave 0 0 moveto exec
+ gsave stroke grestore
+ 0.5 setlinewidth 1 0 0 setrgbcolor stroke
+ grestore 8 0 translate
+ } forall
+ grestore 35 0 translate
+ } forall
+ grestore 0 20 translate
+ } forall
+grestore
+} def
+/xflip
+ { 8.5 72 mul 0 translate -1 1 scale
+ } def
+/rot90
+ { 90 rotate 0 -9.75 72 mul translate
+ } def
+/rot180
+ { rot90 rot90
+ } def
+/rot270
+ { rot180 rot90
+ } def
+
+drawlines showpage
+gsave xflip drawlines grestore showpage
+gsave rot90 drawlines grestore showpage
+gsave rot90 xflip drawlines grestore showpage
+gsave drawlines rot180 showpage
+gsave rot180 xflip drawlines grestore showpage
+gsave rot270 drawlines grestore showpage
+gsave rot270 xflip drawlines grestore showpage
+grestore
+
+% Here are some boundary conditions, contributed by Mark Rawling.
+
+gsave
+1 setlinecap
+2.6 setmiterlimit
+3.0 setlinewidth
+
+5 5 scale
+10 20 translate
+
+% [ 0.5 sqrt dup dup dup neg exch 0 0 ] concat % 45 rotate
+
+{0 1 2} % line join
+{
+ setlinejoin gsave
+ 0 0 moveto 0 10 lineto 10 0 lineto gsave stroke grestore
+ 15 0 translate
+ 0 0 moveto 0 10 lineto 10 20 lineto gsave stroke grestore
+ 15 0 translate
+ 10 0 moveto 10 10 lineto 0 20 lineto gsave stroke grestore
+ 15 0 translate
+ 10 0 moveto 10 10 lineto 0 0 lineto gsave stroke grestore
+ grestore
+ gsave
+ 0 20 translate
+ 0 20 moveto 0 10 lineto 10 20 lineto gsave stroke grestore
+ 15 0 translate
+ 0 20 moveto 0 10 lineto 10 0 lineto gsave stroke grestore
+ 15 0 translate
+ 10 20 moveto 10 10 lineto 0 0 lineto gsave stroke grestore
+ 15 0 translate
+ 10 20 moveto 10 10 lineto 0 20 lineto gsave stroke grestore
+ grestore 60 0 translate
+} forall
+
+showpage
+grestore
+
+% Test narrow lines at a variety of angles.
+
+gsave
+
+/rad 120 def
+/ray { gsave rotate 0 0 moveto rad 0 rlineto stroke grestore } def
+/star
+ { newpath gsave
+ gsave 0.5 setgray 0 0 rad 0 360 arc stroke grestore
+ 0 90 359
+ { rotate
+ 0 3 14 { ray } for
+ 15 15 89 { ray } for
+ } for
+ grestore
+ } def
+
+0 setgray
+150 150 translate
+[ [ 0 0.5 1 ] [ 1.5 2 2.5 ] [ 3 3.5 4 ] ]
+ { gsave
+ { setlinewidth star
+ 250 0 translate
+ } forall
+ grestore 0 250 translate
+ } forall
+
+grestore showpage
+
+% End
+
+quit
diff --git a/gs/lib/lprsetup.sh b/gs/lib/lprsetup.sh
new file mode 100755
index 000000000..5b8052856
--- /dev/null
+++ b/gs/lib/lprsetup.sh
@@ -0,0 +1,188 @@
+#!/bin/sh
+#
+# BSD PRINT FILTER SETUP utility for Ghostscript - used and tested on
+# SunOS 4.1.3, but I hope it will be useful on other BSD systems
+# See documentation for usage
+#
+
+DEVICES="bjt600.32 bjc600.32 bjc600.24 bjc600.24.3 bjc600.16 bjc600.8 bjc600.8.1 bjc600.1 bjc600.dq"
+#FILTERS="if nf tf gf vf df cf rf"
+FILTERS="if"
+
+# The port your printer is on
+PRINTERDEV=/dev/lp1
+# The kind of printer (accepted values: 'parallel' and 'serial')
+PRINTERTYPE=parallel
+
+GSDIR=/usr/local/lib/ghostscript
+GSFILTERDIR=$GSDIR/filt
+SPOOLDIR=/var/spool
+GSIF=unix-lpr.sh
+PCAP=printcap.insert
+
+PATH=/bin:/usr/bin:/usr/ucb
+export PATH
+
+if [ ! -w $GSDIR ]; then
+ echo "$GSDIR must be writable to create filter directory"
+ exit 1
+fi
+
+echo "
+Making links in the filter directory $GSFILTERDIR ...
+"
+
+#
+# Make the directory for holding the filter and links
+#
+if [ -d $GSFILTERDIR ]; then
+ echo "$GSFILTERDIR already exists - not created"
+else
+ mkdir $GSFILTERDIR
+fi
+rm -f $GSFILTERDIR/direct
+ln -s . $GSFILTERDIR/direct
+rm -f $GSFILTERDIR/indirect
+ln -s . $GSFILTERDIR/indirect
+
+#
+# Create a link from each filtertype to the real filter script
+#
+for filter in $FILTERS
+do
+ rm -f $GSFILTERDIR/gs$filter
+ ln -s ../$GSIF $GSFILTERDIR/gs$filter
+done
+
+#
+# Create a link from each device to the filter directory
+#
+for device in $DEVICES
+do
+ dualqueue=
+ case "$device" in
+ *.dq) device=`basename $device .dq` ; dualqueue=t ;;
+ esac
+ rm -f $GSFILTERDIR/$device
+ if [ $dualqueue ]; then
+ rm -f $GSFILTERDIR/indirect/$device
+ ln -s . $GSFILTERDIR/indirect/$device
+ else
+ rm -f $GSFILTERDIR/direct/$device
+ ln -s . $GSFILTERDIR/direct/$device
+ fi
+done
+
+#
+# Create a basic printcap insert - this is made in the CURRENT directory
+#
+rm -f $PCAP
+cat > $PCAP << EOF
+# This is an example printcap insert for Ghostscript printers
+# You will probably want either to change the names for each printer
+# below (first line for each device) to something more sensible, or
+# to add additional name entries (eg cdjcolor for cdj500.24)
+# The example is shown set up for $PRINTERTYPE printers - you will need
+# to alter the entries for different or networked remote printer,
+# eg. a remote network printer would have a line something like:
+# :lp=:rm=artemis:rp=LPT1:
+# for a PC called artemis, replacing the serial port settings
+#
+# NB/ This is only an example - it is unlikely to be complete or exactly
+# correct for your system, but is designed to illustrate filter names
+# corresponding to the accompanying bsd-if print filter
+#
+EOF
+
+(
+previous=undefined
+for device in $DEVICES
+do
+ dualqueue=
+ case "$device" in
+ *.dq) device=`basename $device .dq` ; dualqueue=t ;;
+ esac
+ base="`echo $device | sed 's/\.[0-9][0-9]*$//'`"
+ base="`echo $base | sed 's/\.[0-9][0-9]*$//'`"
+#
+# If device listed with '.dq' suffix, we set up a separate output queue
+#
+ if [ $dualqueue ]; then
+ if [ $base != $previous ]; then
+ previous=$base
+ echo "\
+# Entry for raw device $base.raw
+$base.raw|Raw output device $base:\\
+ :lp=$PRINTERDEV:\\"
+ if test "$PRINTERTYPE" = serial
+ then
+ echo "br#19200:xc#0177777:\\"
+ echo ":ms=-parity,ixon,-opost:\\"
+ fi
+ echo ":sd=$SPOOLDIR/$base/raw:\\
+ :mx#0:sf:sh:rs:"
+ fi
+ echo "\
+# Entry for device $device (output to $base.raw)
+$device|Ghostscript device $device:\\
+ :lp=/dev/null:\\"
+ else
+ echo "\
+# Entry for device $device
+$device|Ghostscript device $device:\\
+ :lp=$PRINTERDEV:\\"
+ if test "$PRINTERTYPE" = serial
+ then
+ echo "br#19200:xc#0177777:\\"
+ echo ":ms=-parity,ixon,-opost:\\"
+ fi
+ fi
+ echo "\
+ :sd=$SPOOLDIR/$base:\\
+ :lf=$SPOOLDIR/$base/logfile:\\
+ :af=$SPOOLDIR/$base/acct:\\"
+ for filter in $FILTERS
+ do
+ if [ $dualqueue ]; then
+ echo "\
+ :$filter=$GSFILTERDIR/indirect/$device/gs$filter:\\"
+ else
+ echo "\
+ :$filter=$GSFILTERDIR/direct/$device/gs$filter:\\"
+ fi
+ done
+ echo "\
+ :mx#0:sf:sh:rs:"
+done
+) >> $PCAP
+
+echo "
+Example printcap insert file \"$PCAP\" now created"
+
+#
+# Remind the user what's still to do
+#
+
+echo "
+NB/ You will need to create the following directories, with
+appropriate permissions, and do 'touch logfile' and 'touch acct'
+in the top level directories (ie. not the 'raw' ones):
+"
+(
+for device in $DEVICES
+do
+ dualqueue=
+ case "$device" in
+ *.dq) device=`basename $device .dq` ; dualqueue=t ;;
+ esac
+ base="`echo $device | sed 's/\.[0-9][0-9]*$//'`"
+ base="`echo $base | sed 's/\.[0-9][0-9]*$//'`"
+ echo " $SPOOLDIR/$base"
+ if [ $dualqueue ]; then
+ echo " $SPOOLDIR/$base/raw"
+ fi
+done
+) | sort -u
+
+echo "
+ + + + "
diff --git a/gs/lib/markhint.ps b/gs/lib/markhint.ps
new file mode 100644
index 000000000..5eed2e5e5
--- /dev/null
+++ b/gs/lib/markhint.ps
@@ -0,0 +1,131 @@
+% Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% markhint.ps
+% Draw the hints for a Type 1 font.
+
+(type1ops.ps) runlibfile
+
+/mhsetup % <matrix> <print> mhsetup -
+ { /mhprint exch def
+ /mhmx exch def
+ /mhdash 0 9 gsave initmatrix dtransform grestore idtransform add abs def
+ gsave
+ clippath pathbbox
+ 2 index sub /bbh exch def
+ 2 index sub /bbw exch def
+ /bby exch def
+ /bbx exch def
+ grestore
+ } def
+
+/markfonthints % <matrix> <print> markfonthints -
+ { mhsetup
+ } def
+
+/hmark % <y> hmark -
+ { bbx exch moveto bbw 0 rlineto stroke
+ } def
+/hsmark % <y0> <dy> hsmark -
+ { 1 index add exch gsave
+ [mhdash] 0 setdash 0 exch mhmx transform exch pop hmark
+ [mhdash 2 div dup 2 mul] 0 setdash 0 exch mhmx transform exch pop hmark
+ grestore
+ } def
+/vmark % <x> vmark -
+ { bby moveto 0 bbh rlineto stroke
+ } def
+/vsmark % <x0> <dx> vsmark -
+ { 1 index add exch gsave
+ [mhdash] mhdash setdash 0 mhmx transform pop vmark
+ [mhdash 2 div dup 2 mul] 0 setdash 0 mhmx transform pop vmark
+ grestore
+ } def
+/pmark % <x> <y> pmark -
+ { newpath 0 4.5 gsave initmatrix dtransform grestore idtransform add abs
+ 0 360 arc stroke
+ } def
+/mchdict mark
+ /hsbw { pop 0 mhmx transform translate 0 0 pmark }
+ /sbw { pop pop mhmx transform translate 0 0 pmark }
+ /hstem
+ { mhprint { (hstem ) print 2 copy 2 packedarray == } if
+ hsmark
+ }
+ /vstem
+ { mhprint { (vstem ) print 2 copy 2 packedarray == } if
+ vsmark
+ }
+ /hstem3
+ { mhprint { (hstem3 ) print 6 copy 6 packedarray == } if
+ 3 { hsmark } repeat
+ }
+ /vstem3
+ { mhprint { (vstem3 ) print 6 copy 6 packedarray == } if
+ 3 { vsmark } repeat
+ }
+ /div
+ { div
+ }
+ /callothersubr
+ { 3 eq
+ { pop
+ mhprint { (replace) = } if
+ % We're replacing hints; lighten the color.
+ currentrgbcolor 3 { 2 mul 3 div 3 1 roll } repeat setrgbcolor
+ }
+ { { pop } repeat
+ } ifelse
+ }
+ /callsubr
+ { Private /Subrs get exch get mchinterp
+ }
+ /pop
+ {
+ }
+ /return
+ {
+ }
+.dicttomark def
+
+/mchinterp % <charstring> mchinterp -
+ { 4330 exch dup length string .type1decrypt exch pop
+ dup length lenIV sub lenIV exch getinterval
+ 0 () /SubFileDecode filter
+ mark exch charstack_read ]
+ { dup type /nametype eq
+ { mchdict exch .knownget { exec } { cleartomark mark } ifelse
+ }
+ if
+ }
+ forall
+ } def
+
+/markcharhints % <charname> <matrix> <print> markcharhints -
+ { mhsetup
+ gsave mark
+ /Private currentfont /Private get def
+ Private rcheck % make sure we won't get an access error
+ { /lenIV Private /lenIV .knownget not { 4 } if def
+ currentfont /CharStrings get 3 -1 roll get mchinterp
+ }
+ { (Sorry, this font is protected; I can't show the hints.\n) print flush
+ exch
+ }
+ ifelse
+ cleartomark grestore
+ } def
diff --git a/gs/lib/markpath.ps b/gs/lib/markpath.ps
new file mode 100644
index 000000000..6c6e0b0dc
--- /dev/null
+++ b/gs/lib/markpath.ps
@@ -0,0 +1,60 @@
+% Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% markpath.ps
+% Mark the corners of a path, drawing it slowly if desired.
+
+/Delay where { pop } { /Delay 0 def } ifelse
+/setxy0
+ { currentpoint /y0 exch def /x0 exch def
+ } def
+/bip
+ { epsx epsy idtransform /ey exch def /ex exch def
+ currentpoint ex 2 div ey 2 div rlineto currentpoint 0 ey neg rlineto
+ ex neg 0 rlineto 0 ey rlineto lineto lineto
+ stroke
+ } def
+/dally
+ { Delay { } repeat
+ Delay 0 ne { flushpage } if
+ } def
+/movebip
+ { /xs 2 index def /ys 1 index def
+ gsave newpath mpmx transform moveto setxy0 bip grestore
+ } def
+/linebip
+ { gsave newpath x0 y0 moveto mpmx transform lineto setxy0 bip dally grestore
+ } def
+/curvebip
+ { gsave newpath x0 y0 moveto 5 index 5 index mpmx transform lineto bip
+ 2 copy mpmx transform moveto 3 index 3 index mpmx transform lineto bip
+ x0 y0 moveto
+ 3 { mpmx transform 6 2 roll } repeat
+ curveto setxy0 bip dally grestore
+ } def
+/closebip
+ { xs ys linebip
+ } def
+
+/markpath % <matrix> markpath -
+ { /mpmx exch def
+ gsave initgraphics 9 dup dtransform grestore
+ /epsy exch def /epsx exch def
+ gsave 0 setlinewidth
+ { movebip } { linebip } { curvebip } { closebip } pathforall
+ grestore
+ } def
diff --git a/gs/lib/mv.bat b/gs/lib/mv.bat
new file mode 100755
index 000000000..daff17f54
--- /dev/null
+++ b/gs/lib/mv.bat
@@ -0,0 +1 @@
+@rename %1 %2
diff --git a/gs/lib/necp2x.upp b/gs/lib/necp2x.upp
new file mode 100644
index 000000000..70a9d7e7c
--- /dev/null
+++ b/gs/lib/necp2x.upp
@@ -0,0 +1,35 @@
+-supModel="NEC Prinwriter 2X, 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceGray
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/Epson
+-r360x360
+-dupMargins="{ 9.0 40.0 9.0 67.0}"
+-dupWhiteTransfer="{
+ 0.40000 0.36253 0.32747 0.29475
+ 0.26428 0.23599 0.20979 0.18561
+ 0.16336 0.14297 0.12435 0.10741
+ 0.09209 0.07831 0.06597 0.05500
+ 0.04532 0.03684 0.02950 0.02320
+ 0.01787 0.01343 0.00979 0.00687
+ 0.00461 0.00290 0.00168 0.00086
+ 0.00036 0.00011 0.00001 0.00000
+}"
+-dupWeaveXPasses=2
+-dupWeaveYPasses=2
+-dupOutputPins=24
+-dupWeaveYFeeds="{11 12 13 12}"
+-dupWeaveInitialYFeeds="{ 0 1 0 11}"
+-dupWeaveInitialPins="{ 6 24 16 5}"
+-dupFormatXabsolute
+-dupBeginPageCommand="<
+1b40 1b40 1b7401 1b5200 1b50 1b54 1b7200 1b32 1b4306 1b5500 0d 1c242000
+>"
+-dupAdjustPageLengthCommand
+-dupEndPageCommand="(\014)"
+-dupAbortCommand="(\034F\034\063\044\15\12\12\12 Printout-Aborted\15\014)"
+-dupXMoveCommand="(\015\034$)"
+-dupSetLineFeedCommand="(\034F\034\063)"
+-dupWriteComponentCommands="{(\033*\047)}"
diff --git a/gs/lib/necp2x6.upp b/gs/lib/necp2x6.upp
new file mode 100644
index 000000000..f0af04e03
--- /dev/null
+++ b/gs/lib/necp2x6.upp
@@ -0,0 +1,35 @@
+-supModel="NEC Prinwriter 2X, 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceGray
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/Epson
+-r360x360
+-dupMargins="{ 9.0 9.0 9.0 67.0}"
+-dupWhiteTransfer="{
+ 0.40000 0.36253 0.32747 0.29475
+ 0.26428 0.23599 0.20979 0.18561
+ 0.16336 0.14297 0.12435 0.10741
+ 0.09209 0.07831 0.06597 0.05500
+ 0.04532 0.03684 0.02950 0.02320
+ 0.01787 0.01343 0.00979 0.00687
+ 0.00461 0.00290 0.00168 0.00086
+ 0.00036 0.00011 0.00001 0.00000
+}"
+-dupWeaveXPasses=3
+-dupWeaveYPasses=2
+-dupOutputPins=24
+-dupWeaveYFeeds="{ 7 9 7 9 7 9}"
+-dupWeaveInitialYFeeds="{ 0 0 1 0 0 9}"
+-dupWeaveInitialPins="{ 5 21 13 16 8 24}"
+-dupFormatXabsolute
+-dupBeginPageCommand="<
+1b40 1b40 1b7401 1b5200 1b50 1b54 1b7200 1b32 1b4306 1b5500 0d 1c242000
+>"
+-dupAdjustPageLengthCommand
+-dupEndPageCommand="(\014)"
+-dupAbortCommand="(\034F\034\063\044\15\12\12\12 Printout-Aborted\15\014)"
+-dupXMoveCommand="(\015\034$)"
+-dupSetLineFeedCommand="(\034F\034\063)"
+-dupWriteComponentCommands="{(\033*\041)}"
diff --git a/gs/lib/packfile.ps b/gs/lib/packfile.ps
new file mode 100644
index 000000000..5c00b01f1
--- /dev/null
+++ b/gs/lib/packfile.ps
@@ -0,0 +1,334 @@
+% Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% packfile.ps
+% Pack groups of files together, with compression, for use in
+% storage-scarce environments.
+
+% ****** NOTE: This file must be kept consistent with gs_pfile.ps.
+
+% ---------------- Huffman coding utilities ---------------- %
+
+% We count runs of zeros, and individual byte frequencies separately
+% depending on whether they follow or do not follow a run of zeros.
+/zruns 256 array def
+/zfreq 256 array def
+/nzfreq 256 array def
+/maxcode 13 def % max code length, must be between 10 and 16
+/maxzrun 100 def % max length of zero run, must be <= 100
+/statbuf 10000 string def
+
+% Initialize statistics.
+/initstats % - initstats -
+ { 0 1 255 { zruns exch 0 put } for
+ 0 1 255 { zfreq exch 0 put } for
+ 0 1 255 { nzfreq exch 0 put } for
+ } bind def
+
+% Accumulate statistics from an individual file.
+/addstats % <file> addstats -
+ { 0
+ { 1 index //statbuf readstring 3 1 roll
+ % Stack: file eof numzeros data
+ { dup 0 eq
+ { pop 1 add
+ }
+ { 1 index 0 ne
+ { exch 255 min
+ //zruns exch 2 copy get 1 add put
+ 0 exch //zfreq
+ }
+ { //nzfreq
+ }
+ ifelse
+ exch 2 copy get 1 add put
+ }
+ ifelse
+ } forall
+ exch not { exit } if (.) print flush
+ } loop
+ pop closefile
+ } bind def
+
+% Compute the Huffman codes from the statistics.
+/statcodes % - statcodes <array>
+ { maxcode 1 add 256 add maxzrun 2 sub add 1 add array % full array
+ dup maxcode 1 add dup 2 index length exch sub getinterval % data
+ % Put statistics into array
+ dup 0 1 255
+ { zfreq 1 index get nzfreq 2 index get add put dup
+ } for
+ 0 zruns 1 get put
+ 256 zruns 2 maxzrun 2 sub getinterval putinterval
+ dup dup length 1 sub 1 put % EOD
+ maxcode .computecodes
+ } bind def
+
+% ---------------- File handling ---------------- %
+
+% Copy one file to another.
+% Close the input file, but not the output file.
+/copyfile % <infile> <outfile> copyfile <outfile> <length>
+ { 0 mark statbuf
+ { 4 index 1 index readstring
+ exch 5 index 1 index writestring
+ length 5 -1 roll add 4 1 roll
+ not { exit } if (.) print flush
+ } loop
+ cleartomark 3 -1 roll closefile dup == flush
+ } bind def
+
+% Represent a Type 1 font in its most compressed format.
+% Requires -dWRITESYSTEMDICT to run.
+% Does not close the output file.
+(wrfont.ps) runlibfile
+/compressfont % <fontname> <outfile> compressfont <outfile>
+ { exch save
+ systemdict /executeonly /readonly load put
+ systemdict /noaccess /readonly load put
+ systemdict readonly pop
+ wrfont_dict begin
+ /binary_CharStrings true def
+ /binary_tokens true def
+ /encrypt_CharStrings false def
+ /standard_only false def
+ /use_lenIV 0 def
+ /smallest_output true def
+ end
+ exch findfont setfont
+ 1 index writefont
+ restore
+ } bind def
+
+% ---------------- Main program ---------------- %
+
+% Find the length of a file.
+/filelength % <filename> filelength <length>
+ { status { pop pop exch pop } { -1 } ifelse
+ } bind def
+
+% Define the header string for a compressed file.
+/beginfilestring
+({dup token pop exch[/MaxCodeLength 2 index token pop/Tables 4 index token pop
+/EndOfData true/EncodeZeroRuns 256 .dicttomark
+/BoundedHuffmanDecode filter/MoveToFrontDecode filter
+[/BlockSize 4 -1 roll .dicttomark/BWBlockSortDecode filter
+}) readonly def
+
+% Write a 16-bit big-endian non-negative integer on a file.
+/write16 % <file> <int> write16 -
+ { 2 copy -8 bitshift write 255 and write
+ } bind def
+
+% Compress a group of files together.
+% Return a dictionary in which the keys are the input file names
+% and the values are [startpos length] in the uncompressed concatenation.
+% Does not open or close the output file.
+/tempname (t.em) def
+/packfiles % <filenames> <outfile> packfiles <outfile> <posdict>
+ { % Concatenate files to a temporary file.
+ tempname (w) file
+ dup /MoveToFrontEncode filter
+ dup <<
+ /BlockSize 1000000
+ >> /BWBlockSortEncode filter
+ % Stack: filenames outfile tempfile mtfe bwe
+ 5 -1 roll dup length dict 0 6 2 roll
+ { % Stack: outfile posdict pos tempfile mtfe bwe infilename
+ dup ==only dup (r) file 2 index copyfile exch pop
+ dup 7 index 4 2 roll 7 index exch 2 array astore put
+ 5 -1 roll add 4 1 roll
+ } forall
+ closefile closefile closefile pop exch
+ % Stack: posdict outfile
+ % Compute an optimal Huffman code.
+ initstats
+ tempname (r) file addstats
+ % Actually compress the file.
+ % Write the decompression information on the output first.
+ dup tempname filelength write==
+ dup maxcode write==
+ % Write the code table as a homogenous number array.
+ statcodes exch
+ dup 149 write dup 32 write dup 2 index length write16
+ exch { 2 copy write16 pop } forall
+ dup <<
+ /MaxCodeLength maxcode
+ /EndOfData true
+ /EncodeZeroRuns 256
+ /Tables statcodes
+ >> /BoundedHuffmanEncode filter
+ tempname (r) file exch copyfile pop closefile
+ exch
+ } bind def
+
+% Squeeze a font to a .cpf file in anticipation of compression.
+/squeezefont % <fontname> squeezefont <filename.cpf>
+ { dup type /nametype ne { cvn } if
+ dup
+ { dup type /stringtype eq { exit } if
+ Fontmap exch get
+ }
+ loop
+ % Stack: fontname filename
+ dup dup
+ { (.) search not { exit } if
+ exch pop exch 3 -1 roll pop
+ }
+ loop
+ % Stack: fontname filename noextname extension
+ exch
+ { (/) search not { (\\) search not { exit } if } if
+ pop pop
+ }
+ loop
+ % If the font extension is anything other than
+ % .pfa or .pfb, we assume it can't be rewritten
+ % using compressfont.
+ % Stack: fontname filename extension basename
+ (.cpf) concatstrings dup 5 1 roll (w) file
+ % Stack: outfilename fontname filename extension outfile
+ exch dup (pfa) eq exch (pfb) eq or
+ % Stack: outfilename fontname filename outfile bool
+ { exch pop compressfont
+ }
+ { 3 -1 roll pop
+ exch findlibfile pop exch pop
+ exch copyfile pop
+ }
+ ifelse closefile
+ } bind def
+
+% ---------------- Production code ---------------- %
+
+% The following code constructs a packed version of the commercial-quality
+% fonts available from Aladdin Enterprises. To use this code:
+% - If desired, change the output file names below.
+% - Make sure you have the synthetic font data (fontmap.shs and the
+% *.ps files for the commercial fonts) in a directory that is on
+% Ghostscript's search path.
+% - Construct the packed fonts by running
+% gs -dNODISPLAY -dWRITESYSTEMDICT packfile.ps
+% - If desired, move the output files to the directory that will be
+% used at run time. You no longer need the *.pfb or *.ps files
+% for the original fonts; however, you do still need the Fontmap
+% for these fonts, because it defines the font name aliases.
+% - Add the following line to the end of gs_fonts.ps:
+% (ALL.cmp) run
+% (substituting the definition of allmapname if you changed it).
+
+% Define the output file names. The extensions are arbitrary;
+% any legal file name is allowed.
+/allname (ALL.cff) def % the compressed font file
+/allmapname (ALL.cmp) def % the Fontmap override file
+
+% Load an alternate Fontmap that references the synthetic oblique and
+% narrow fonts.
+true .setglobal
+(fontmap.shs) findlibfile pop exch pop .loadFontmap
+false .setglobal
+
+% Define the packaging of fonts into font groups.
+% Fewer larger groups compress better, but make decompression slower.
+/Lists [
+[ % The oblique and narrow fonts are synthetic,
+ % and take very little space.
+ /AvantGarde-BookOblique /AvantGarde-DemiOblique
+ /Courier-Oblique /Courier-BoldOblique
+ /Helvetica-Oblique /Helvetica-BoldOblique
+ /Helvetica-Narrow /Helvetica-Narrow-Oblique
+ /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique
+]
+[/AvantGarde-Book /AvantGarde-Demi
+ /Bookman-Light] [/Bookman-LightItalic
+ /Bookman-Demi /Bookman-DemiItalic
+ /Courier] [/Courier-Bold
+ /Helvetica /Helvetica-Bold]
+[/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
+ /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic]
+[/Palatino-Roman /Palatino-Italic
+ /Palatino-Bold /Palatino-BoldItalic]
+[/Times-Roman /Times-Italic
+ /Times-Bold /Times-BoldItalic]
+[/Symbol
+ /ZapfChancery-MediumItalic
+ /ZapfDingbats]
+] def
+
+% We need to register the fonts under their true names, not aliases.
+/Lists Lists mark exch
+ { mark exch
+ { { Fontmap 1 index get dup type /nametype ne { pop exit } if
+ exch pop
+ }
+ loop
+ }
+ forall ]
+ }
+forall ] def
+
+% Squeeze the fonts to their .cpf format.
+(Squeezing... ) print flush
+/fdict mark
+Lists
+ { { dup squeezefont } forall } forall
+.dicttomark def
+(done.\n) print flush
+
+% Invert fdict.
+/f2dict fdict length dict def
+fdict { exch f2dict 3 1 roll put } forall
+
+% Construct the compressed font file.
+(Creating ) print allname print (... ) print flush
+/posdict fdict length dict def
+/all allname (w) file def
+all beginfilestring writestring
+Lists
+ { dup == flush
+ /fbegin all fileposition def
+ mark exch { fdict exch get } forall ]
+ all packfiles exch pop
+ /flength all fileposition fbegin sub def
+ { fbegin flength 3 -1 roll aload pop 4 packedarray
+ exch f2dict exch get exch posdict 3 1 roll put
+ }
+ forall
+ }
+forall
+all closefile
+(done.\n) print flush
+
+% Write the Fontmap addendum for accessing compressed fonts.
+(Writing ) print allmapname print (... ) print flush
+allmapname (w) file
+dup (%!
+/.runpackedlibfile where{pop}{(gs_pfile.ps)runlibfile}ifelse
+.currentglobal true .setglobal
+) writestring
+posdict
+ { exch 2 index exch write==only exch dup ({) writestring
+ dup allname write==only
+ exch { 1 index dup ( ) writestring exch write==only } forall
+ dup ( .runpackedlibfile}bind .definefontmap
+) writestring
+ }
+forall
+dup (.setglobal
+) writestring
+closefile
+(done.\n) print flush
diff --git a/gs/lib/pcharstr.ps b/gs/lib/pcharstr.ps
new file mode 100644
index 000000000..faf80b511
--- /dev/null
+++ b/gs/lib/pcharstr.ps
@@ -0,0 +1,127 @@
+% Copyright (C) 1990, 1992, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pcharstr.ps
+% Print the CharStrings and Subrs (if present) from a Type 1 font,
+% in either a PostScript-like or a C-compatible form,
+% depending on whether CSFormat is defined as /PS or /C.
+
+% Load the Type 1 utilities.
+(type1ops.ps) run
+
+% Define the printing procedures for PostScript-like output.
+/pcs_ps_dict mark
+ /, {( ) print}
+ /charname {==only}
+ /csbegin {}
+ /beginchars {(%---------------- CharStrings\n) print}
+ /charbegin {==only}
+ /char1 {( ) print ==only}
+ /endchars {}
+ /beginsubrs {(%---------------- Subrs\n) print}
+ /subrbegin {=only}
+ /endsubrs {}
+ /beginboxes {(%---------------- Encoding & metrics\n) print}
+ /notdefbox {}
+ /boxbegin {=only ( ) print}
+ /boxend {(\n) print}
+ /endboxes {(%----------------\n) print}
+.dicttomark readonly def
+
+% Define the printing procedures for C-like output.
+/pcs_c_dict mark
+ /, {(, ) print}
+ /charname {(") print =only (") print}
+ /csbegin {counttomark =only ,}
+ /beginchars {(\nconstdata int CSCharData[] = {\n) print}
+ /charbegin {pop}
+ /char1 {=only ,}
+ /endchars {
+ (-1\n};\nconstdata char *CSCharNames[] = {\n) print
+ CharStrings {pop charname ,} forall (0\n};\n) print
+ }
+ /beginsubrs {(\nconstdata int CSSubrs[] = {\n) print}
+ /subrbegin {pop}
+ /endsubrs {(-1\n};\n) print}
+ /beginboxes {(\nconstdata type1_box CSboxes[] = {\n) print}
+ /notdefbox {( {""},\n) print}
+ /boxbegin {pop ( {) print}
+ /boxend {(},) =}
+ /endboxes {( {0}\n};\n) print}
+.dicttomark readonly def
+
+/printcs
+ { dup type /stringtype eq
+ { printcs1 (\n) print }
+ { ( ) print == }
+ ifelse
+ } bind def
+/printcs1
+ { save exch
+ lenIV 0 ge {
+ 4330 exch dup length string .type1decrypt exch pop
+ dup length lenIV sub lenIV exch getinterval
+ } if
+ 0 () /SubFileDecode filter
+ mark exch charstack_read csbegin
+ counttomark 1 sub -1 0 { index char1 } for
+ cleartomark restore
+ } bind def
+
+/printfont
+ { pcs_ps_dict
+ /CSFormat where { pop CSFormat /C eq { pop pcs_c_dict } if } if
+ begin
+ currentfont begin Private begin 10 dict begin
+
+ % Print the CharStrings and Subrs
+
+ beginchars
+ CharStrings { exch charbegin printcs } forall
+ endchars
+ /Subrs where
+ { pop % the dictionary
+ beginsubrs
+ 0 1 Subrs length 1 sub
+ { dup subrbegin
+ Subrs exch get printcs
+ } for
+ endsubrs
+ } if
+
+ % Print the bounding boxes
+
+ gsave nulldevice FontMatrix matrix invertmatrix concat
+ beginboxes
+ 0 1 Encoding length 1 sub
+ { dup Encoding exch get dup /.notdef eq
+ { pop pop notdefbox
+ }
+ { 1 index boxbegin charname ,
+ ( ) dup 0 4 -1 roll put
+ newpath 0 0 moveto false charpath
+ pathbbox ({) print 4 -1 roll =only ,
+ 3 -1 roll =only , exch =only , =only (}) print
+ boxend
+ }
+ ifelse
+ } for
+ endboxes
+ grestore
+
+ end end end end
+ } bind def
diff --git a/gs/lib/pdf2dsc b/gs/lib/pdf2dsc
new file mode 100755
index 000000000..0d7cddfff
--- /dev/null
+++ b/gs/lib/pdf2dsc
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+# psf2dsc: generates an index of a PDF file.
+#
+# Yves Arrouye <arrouye@debian.org>, 1996.
+
+me=`basename $0`
+
+usage() {
+ >&2 echo usage: $me "pdffile [ dscfile ]"
+ exit 1
+}
+
+if [ $# -gt 2 ]
+then
+ usage
+fi
+
+pdffile=$1
+dscfile=$2
+: ${dscfile:=`echo $pdffile | sed 's,\.[^/.]*,,'`.dsc}
+
+exec gs -q -dNODISPLAY \
+ -sPDFname="$pdffile" -sDSCname="$dscfile" pdf2dsc.ps -c quit
diff --git a/gs/lib/pdf2dsc.ps b/gs/lib/pdf2dsc.ps
new file mode 100644
index 000000000..f8e7fd530
--- /dev/null
+++ b/gs/lib/pdf2dsc.ps
@@ -0,0 +1,120 @@
+% Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf2dsc.ps
+% read pdf file and produce DSC "index" file.
+%
+% Input file is named PDFname
+% Output file is named DSCname
+%
+% Run using:
+% gs -dNODISPLAY -sPDFname=pdffilename -sDSCname=tempfilename pdf2dsc.ps
+% Then display the PDF file with
+% gs tempfilename
+%
+% Modified by Johannes Plass <plass@dipmza.physik.uni-mainz.de> 1996-11-05:
+% Adds BoundingBox and Orientation if available.
+% Modified by rjl/lpd 9/19/96
+% Updates for compatibility with modified pdf_*.ps code for handling
+% page ranges (i.e., partial files) better.
+% Modified by Geoff Keating <Geoff.Keating@anu.edu.au> 7/3/96:
+% include Title and CreationDate DSC comments (these are displayed by
+% Ghostview);
+% reduce the size of typical output files by a factor of about 3.
+% Modified by L. Peter Deutsch 3/18/96:
+% Removes unnecessary and error-prone code duplicated from pdf_main.ps
+% Modified by L. Peter Deutsch for GS 3.33
+% Originally by Russell Lang 1995-04-26
+
+/DSCfile DSCname (w) file def
+/DSCstring 255 string def
+ GS_PDF_ProcSet begin
+ pdfdict begin
+ PDFname (r) file
+ pdfopen begin
+% setup for loop (init increment limit)
+ /FirstPage where { pop FirstPage } { 1 } ifelse
+ 1
+ /LastPage where { pop LastPage } { pdfpagecount } ifelse
+% write header and prolog
+DSCfile (%!PS-Adobe-3.0\n) writestring
+Trailer /Info knownoget
+ {
+ dup /Title knownoget
+ {
+ DSCfile (%%Title: ) writestring
+ DSCfile exch write==
+ }
+ if
+ /CreationDate knownoget
+ {
+ DSCfile (%%CreationDate: ) writestring
+ DSCfile exch write==
+ }
+ if
+ }
+if
+DSCfile (%%Pages: ) writestring
+DSCfile 1 index 3 index sub 1 add DSCstring cvs writestring
+DSCfile (\n%%EndComments\n) writestring
+DSCfile (%%BeginProlog\n) writestring
+DSCfile (/Page null def\n/Page# 0 def\n/PDFSave null def\n/DSCPageCount 0 def\n) writestring
+DSCfile (/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def\n) writestring
+DSCfile (GS_PDF_ProcSet begin\npdfdict begin\n) writestring
+DSCfile (%%EndProlog\n) writestring
+DSCfile (%%BeginSetup\n) writestring
+DSCfile PDFname write==only
+DSCfile ( \(r\) file pdfopen begin\n) writestring
+DSCfile (%%EndSetup\n) writestring
+% process each page
+ {
+DSCfile (%%Page: ) writestring
+DSCfile 1 index DSCstring cvs writestring
+DSCfile ( ) writestring
+DSCfile 1 index DSCstring cvs writestring
+DSCfile (\n) writestring
+
+%BEGIN ##jp##
+dup pdfgetpage /CropBox knownoget { % file maxpage pageno cropbox
+ DSCfile (%%PageBoundingBox: ) writestring
+ {DSCfile exch write=only DSCfile ( ) writestring} forall
+ DSCfile (\n) writestring
+} if
+dup pdfgetpage /Rotate knownoget { % file maxpage pageno angle
+ DSCfile (%%PageOrientation: ) writestring
+ 90 div cvi 4 mod dup 0 lt {4 add} if
+ [(Portrait) (Landscape) (UpsideDown) (Seascape)] exch get
+ DSCfile exch writestring
+ DSCfile (\n) writestring
+} if
+%END ##jp##
+
+DSCfile exch DSCstring cvs writestring
+DSCfile ( DoPDFPage\n) writestring
+ } for
+ currentdict pdfclose
+ end
+ end
+ end
+% write trailer
+DSCfile (%%Trailer\n) writestring
+DSCfile (currentdict pdfclose\nend\nend\nend\n) writestring
+DSCfile (%%EOF\n) writestring
+% close output file and exit
+DSCfile closefile
+quit
+% end of pdf2dsc.ps
diff --git a/gs/lib/pdf2ps b/gs/lib/pdf2ps
new file mode 100755
index 000000000..f172ddc22
--- /dev/null
+++ b/gs/lib/pdf2ps
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Convert PDF to PostScript.
+
+OPTIONS=""
+while true
+do
+ case "$1" in
+ -*) OPTIONS="$OPTIONS $1" ;;
+ *) break ;;
+ esac
+ shift
+done
+
+if [ $# -ne 2 ]; then
+ echo "Usage: `basename $0` [-dPSBinaryOK] [-dPSLevel1] [-dPSNoProcSet] input.pdf output.ps" 1>&2
+ exit 1
+fi
+
+exec gs -q -dNODISPLAY -sPSFile=$2 -dNOPAUSE $OPTIONS $1 -c quit
diff --git a/gs/lib/pdf2ps.bat b/gs/lib/pdf2ps.bat
new file mode 100755
index 000000000..a51f47ba9
--- /dev/null
+++ b/gs/lib/pdf2ps.bat
@@ -0,0 +1,21 @@
+@echo off
+@rem Convert PDF to PostScript.
+
+if "%1"=="" goto usage
+if "%2"=="" goto usage
+echo -dNODISPLAY -dNOPAUSE >_.at
+:cp
+if "%3"=="" goto doit
+echo %1 >>_.at
+shift
+goto cp
+
+:doit
+rem Watcom C deletes = signs, so use # instead.
+gs -q -sPSFile#%2 @_.at %1 -c quit
+goto end
+
+:usage
+echo "Usage: pdf2ps [-dPSBinaryOK] [-dPSLevel1] [-dPSNoProcSet] input.pdf output.ps"
+
+:end
diff --git a/gs/lib/pdf_2ps.ps b/gs/lib/pdf_2ps.ps
new file mode 100644
index 000000000..4251eff1b
--- /dev/null
+++ b/gs/lib/pdf_2ps.ps
@@ -0,0 +1,273 @@
+% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_2ps.ps
+% PDF to PostScript additions to PDF reader.
+
+GS_PDF_ProcSet begin
+pdfdict begin
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+
+userdict /pdf2psdict 30 dict put
+pdf2psdict begin
+
+% Generate a sufficiently unique name (at least unique within the current
+% save/restore environment).
+/uniqueid#
+ { userdict length
+ { dup neg =string cvs dup 0 (_) putinterval cvn
+ userdict 1 index known not { exch pop exit } if pop 1 add
+ }
+ loop
+ } bdef
+
+% "Wrap" all the runtime operators so they call #exec.
+% Make sure we have enough room in the current dictionary for this.
+currentdict dup maxlength numargsdict length add .setmaxlength
+numargsdict
+ { 1 index load exch 2 index exch /#exec cvx 4 packedarray cvx def
+ }
+forall
+/pdfmark
+ /pdfmark load dup type /operatortype eq { 1 packedarray cvx } if
+ { /pdfmark counttomark 1 sub #exec } bind
+ aload length 1 add packedarray cvx
+def
+% Define #exec so it also prints out its arguments.
+/dictwrite# % <file> <dict> dictwrite# -
+ { dup length 240 le
+ { 1 index (mark ) writestring
+ { exch 2 index exch write#
+ 1 index ( ) writestring 1 index exch write#
+ 2 index (\n) writestring
+ }
+ forall dup (.dicttomark) writestring
+ }
+ { 2 copy length write=only 1 index ( dict\n) writestring
+ { exch 2 index dup (dup ) writestring exch write#
+ 1 index dup ( ) writestring exch write#
+ dup ( put\n) writestring
+ }
+ forall
+ }
+ ifelse pop
+ } bdef
+/fontwrite# % <file> <font> fontwrite# -
+ { % Find the named font and then modify it.
+ 2 copy /FontName get =string cvs
+ { dup dup length 1 sub 1 getinterval (%) ne { exit } if
+ 0 1 index length 1 sub getinterval
+ }
+ loop cvn write===only 1 index ( findfont ) writestring
+ % Load the appropriate Encoding, by name if possible.
+ dup /Encoding get
+ dup dup StandardEncoding eq exch ISOLatin1Encoding eq or
+ % Stack: file font encoding stdbool
+ { StandardEncoding eq { (StandardEncoding) } { (ISOLatin1Encoding) } ifelse
+ 2 index exch writestring
+ }
+ { 2 index exch write#
+ }
+ ifelse
+ % Check for modified Metrics.
+ dup /Metrics .knownget
+ { 2 index ( ) writestring
+ 2 index exch write#
+ }
+ { 1 index ( null) writestring
+ }
+ ifelse
+ 1 index ( .updatefont { /_ exch definefont } if\n) writestring
+ pop pop
+ } bdef
+/write#dict 10 dict dup begin
+ /arraytype
+ { dup xcheck { (}) ({) } { (]) ([) } ifelse
+ 2 index length 0 eq
+ { 3 index exch writestring exch
+ }
+ { 3 -1 roll
+ { 3 index 2 index writestring 3 index exch write# pop (\n) }
+ forall
+ }
+ ifelse pop writestring
+ } bdef
+ /dicttype
+ { null userdict { 3 index eq { exch pop exit } if pop } forall
+ dup null eq
+ { pop 2 copy dup /FID known { fontwrite# } { dictwrite# } ifelse
+ 1 index ( userdict ) writestring
+ uniqueid# 2 index 1 index write# 2 index ( 2 index put) writestring
+ userdict exch 3 -1 roll put pop
+ }
+ { exch pop cvx write===only
+ }
+ ifelse
+ } bdef
+ /filetype
+ { % Convert all files into currentfile, on the theory that
+ % any file-based data will be copied in-line.
+ pop (currentfile) writestring
+ } bdef
+ /marktype
+ { pop ([) writestring
+ } bdef
+ /packedarraytype
+ /arraytype load def
+ /realtype
+ { dup abs 16#ffffff le { dup dup cvi eq { cvi } if } if write=only
+ } bdef
+end def
+/write#
+ { dup type //write#dict exch .knownget { exec } { write===only } ifelse
+ } bind def
+
+% Rebind the procedures that conditionally write out PostScript.
+
+/# % <arg1> ... <argN> <opname> <N> # -
+ { 1 index load 3 1 roll #exec
+ } bdef
+/#? % - #? <writing>
+ { /PSout where { pop true } { false } ifelse
+ } bdef
+/defined# % <name> defined# <bool>
+ { dup where { exch get } { pop false } ifelse
+ } bdef
+/#exec % <arg1> ... <argN> <proc|operator> <opname> <N> #exec -
+ { /PSout where
+ { pop dup ([) eq { pop counttomark 1 sub } if
+ -1 1 { 1 add index PSout exch write# PSout ( ) writestring } for
+ PSout exch write=
+ }
+ { pop pop
+ }
+ ifelse exec
+ } bdef
+/#dsc % mark <obj1> ... #dsc -
+ { /PSout where
+ { pop counttomark
+ { counttomark -1 roll PSout exch write=only }
+ repeat pop PSout (\n) writestring
+ }
+ { cleartomark
+ }
+ ifelse
+ } bdef
+/copyfile# % <filename> copyfile# -
+ { findlibfile
+ { exch pop }
+ { (r) file } % let the error happen
+ ifelse
+ { dup =string readline pop (%BEGIN) eq { exit } if
+ }
+ loop
+ { dup =string readline not { pop exit } if
+ dup (%END) eq { pop exit } if
+ { ( ) anchorsearch
+ { pop }
+ { (\t) anchorsearch { pop } { exit } ifelse }
+ ifelse
+ }
+ loop
+ dup () eq { true } { dup 0 1 getinterval (%) eq } ifelse
+ { pop }
+ { (%) search { exch pop exch pop } if mark exch #dsc }
+ ifelse
+ }
+ loop closefile
+ } bdef
+/#dscfile % <filename> #dscfile -
+ { /PSout where
+ { pop /PSNoProcSet defined#
+ { PSout exch write===only PSout ( runlibfile\n) writestring }
+ { copyfile# }
+ ifelse
+ }
+ { pop
+ }
+ ifelse
+ } bdef
+
+% Rebind Is, which constructs a data source for an image.
+% pdf_draw defined it to simply retrieve the stream.
+/ID_draw /ID load def
+/Is_draw /Is load def
+/EI_draw /EI load def
+userdict /Is_string null put % establish a binding
+userdict /Is_data null put % ditto
+/ID_proc1 {/ASCIIHexDecode filter} def % no bind
+/ID_proc2 {/ASCII85Decode filter /RunLengthDecode filter} def % no bind
+/ID
+ { /PSout where
+ { pop dup length 1 add dict copy
+ dup /FilterProc PSLevel1 { /ID_proc1 } { /ID_proc2 } ifelse load
+ /PSBinaryOK defined# { dup length 2 sub 2 exch getinterval } if
+ dup length 0 eq { pop pop pop } { put } ifelse
+ }
+ if ID_draw
+ } bdef
+/Is % <imagedict> Is <imagedict> <datasource>
+ { /PSout where
+ { pop dup /DataSource get string /Is_string exch store
+ /Is_data [ PSout
+ PSLevel1
+ { /PSBinaryOK defined#
+ { /NullEncode } { /ASCIIHexEncode } ifelse
+ filter
+ }
+ { /PSBinaryOK defined#
+ { Is_string length /RunLengthEncode filter
+ }
+ { /ASCII85Encode filter
+ dup Is_string length /RunLengthEncode filter exch
+ }
+ ifelse
+ }
+ ifelse ] store
+ Is_draw
+ { Is_string readstring pop Is_data 0 get 1 index writestring }
+ aload length 1 add packedarray cvx
+ }
+ { Is_draw
+ }
+ ifelse
+ } bdef
+/EI
+ { /PSout where { pop Is_data { closefile } forall } { EI_draw } ifelse
+ } bdef
+
+% Rebind readfontfilter, which constructs the filter that
+% reads the text of an embedded Type 1 (and eventually Type 3) font.
+/readfontfilter_orig /readfontfilter load def
+/readfontfilter { % <proc|file> readfontfilter <filter>
+ dup type /filetype eq {
+ cvlit 100 string /readstring cvx /pop cvx 4 array astore cvx
+ } if
+ /copyfontdata cvx 2 array astore cvx
+ 0 () /SubFileDecode filter
+} bdef
+/copyfontdata { % <string> <origproc> copyfontdata <substring>
+ exec /PSout where { pop PSout 1 index writestring } if
+} bdef
+
+currentdict readonly pop end % pdf2psdict
+
+.setglobal
+end % pdfdict
+end % GS_PDF_ProcSet
diff --git a/gs/lib/pdf_base.ps b/gs/lib/pdf_base.ps
new file mode 100644
index 000000000..d99acc801
--- /dev/null
+++ b/gs/lib/pdf_base.ps
@@ -0,0 +1,456 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_base.ps
+% Basic parser for PDF reader.
+
+% This handles basic parsing of the file (including the trailer
+% and cross-reference table), as well as objects, object references,
+% and streams; it doesn't include any facilities for making marks on
+% the page.
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+pdfdict begin
+
+% We rebind #, #?, #dsc, and #dscfile later if we're writing out PostScript.
+/# % <arg1> ... <argN> <opname> <N> # -
+ { pop cvx exec
+ } bind def
+/#?
+ { false
+ } bind def
+/#dsc % mark <obj1> ... #dsc -
+ { cleartomark
+ } bind def
+/#dscfile % <filename> #dscfile -
+ { pop
+ } bind def
+
+% Define the name interpretation dictionary for reading values.
+/valueopdict mark
+ (<<) cvn { mark } bind % don't push an actual mark!
+ (>>) cvn /.dicttomark load
+ ([) cvn { mark } bind % ditto
+ (]) cvn dup load
+ /true true
+ /false false
+ /null null
+ /F dup cvx % see Objects section below
+ /R dup cvx % see Objects section below
+ /stream dup cvx % see Streams section below
+.dicttomark readonly def
+
+% ------ Utilities ------ %
+
+% Define a scratch string. The PDF language definition says that
+% no line in a PDF file can exceed 255 characters.
+/pdfstring 255 string def
+
+% Read the previous line of a file. If we aren't at a line boundary,
+% read the line containing the current position.
+% Skip any blank lines.
+/prevline % - prevline <startpos> <substring>
+ { PDFfile fileposition dup () pdfstring
+ 2 index 257 sub 0 .max PDFfile exch setfileposition
+ { % Stack: initpos linepos line string
+ PDFfile fileposition
+ PDFfile 2 index readline pop
+ dup length 0 gt
+ { 3 2 roll 5 -2 roll pop pop 2 index }
+ { pop }
+ ifelse
+ % Stack: initpos linepos line string startpos
+ PDFfile fileposition 5 index ge { exit } if
+ pop
+ }
+ loop pop pop 3 -1 roll pop
+ } bind def
+
+% Read a token from a file, recognizing the PDF 1.2 #nn escape convention.
+% This should be done in C!
+/.pdftoken % <file> .pdftoken <obj> -true-
+ % <file> .pdftoken -false-
+{ token
+ { dup type /nametype eq
+ { dup xcheck
+ { true
+ }
+ { dup .namestring (#) search
+ { name#escape cvn exch pop }
+ { pop }
+ ifelse true
+ }
+ ifelse
+ }
+ { true
+ }
+ ifelse
+ }
+ { false
+ }
+ ifelse
+} bind def
+/name#escape % <post> <(#)> <pre> name#escape <string>
+{ exch pop
+ 1 index 2 () /SubFileDecode filter dup (x) readhexstring
+ % Stack: post pre stream char t/f
+ not { /.pdftoken cvx /syntaxerror signalerror } if
+ exch closefile concatstrings
+ exch 2 1 index length 2 sub getinterval
+ (#) search { name#escape } if concatstrings
+} bind def
+
+% Execute a file, interpreting its executable names in a given
+% dictionary. The name procedures may do whatever they want
+% to the operand stack.
+/.pdfrun % <file> <opdict> .pdfrun -
+ { % Construct a procedure with the stack depth, file and opdict
+ % bound into it.
+ 1 index cvlit count 2 sub 3 1 roll mark mark 5 2 roll
+ { % Stack: ..operands.. count opdict file
+ .pdftoken not { (%%EOF) cvn cvx } if
+ dup xcheck
+ { DEBUG { dup == flush } if
+ 2 copy .knownget
+ { exch pop exch pop exch pop exec }
+ { BXlevel 0 le
+ { (%stderr) (w) file
+ dup (****************Unknown operator: ) writestring
+ dup 2 index .writecvs dup (\n) writestring flushfile
+ }
+ if pop pop
+ count exch sub { pop } repeat % pop all the operands
+ }
+ ifelse
+ }
+ { exch pop exch pop DEBUG { dup ==only ( ) print flush } if
+ }
+ ifelse
+ }
+ aload pop .packtomark cvx
+ /loop cvx 2 packedarray cvx
+ { stopped /PDFsource } aload pop
+ PDFsource
+ { store { stop } if } aload pop .packtomark cvx
+ /PDFsource 3 -1 roll store exec
+ } bind def
+
+% ------ File reading ------ %
+
+% Read the cross-reference entry for an (unresolved) object.
+% The caller must save and restore the PDFfile position if desired.
+% For invalid (free) objects, we return 0.
+/readxrefentry % <object#> readxrefentry <objpos>
+ { dup Objects exch lget
+ PDFfile exch setfileposition
+ PDFfile token pop % object position
+ PDFfile token pop % generation #
+ PDFfile token pop % n or f
+ dup /n eq
+ { pop 1 add dup 255 gt
+ { Generations ltype /stringtype eq
+ { % Convert Generations from a string to an array.
+ larray Generations llength lgrowto dup
+ 0 1 2 index llength 1 sub
+ { Generations 1 index lget lput dup
+ }
+ for pop /Generations exch store
+ }
+ if
+ }
+ if
+ }
+ { /f eq
+ { pop 0 }
+ { /readxrefentry cvx /syntaxerror signalerror }
+ ifelse
+ }
+ ifelse
+ % Stack: obj# objpos 1+gen#
+ Generations 4 -1 roll 3 -1 roll lput
+ } bind def
+
+% ================================ Objects ================================ %
+
+% Since we may have more than 64K objects, we have to use a 2-D array to
+% hold them (and the parallel Generations structure).
+/lshift 9 def
+/lnshift lshift neg def
+/lsubmask 1 lshift bitshift 1 sub def
+/lsublen lsubmask 1 add def
+/larray { % - larray <larray>
+ [ [] ]
+} bind def
+/lstring { % - lstring <lstring>
+ [ () ]
+} bind def
+/ltype { % <lseq> type <type
+ 0 get type
+} bind def
+/lget { % <lseq> <index> lget <value>
+ dup //lsubmask and 3 1 roll //lnshift bitshift get exch get
+} bind def
+/lput { % <lseq> <index> <value> lput -
+ 3 1 roll
+ dup //lsubmask and 4 1 roll //lnshift bitshift get
+ 3 1 roll put
+} bind def
+/llength { % <lseq> llength <length>
+ dup length 1 sub dup //lshift bitshift
+ 3 1 roll get length add
+} bind def
+% lgrowto assumes newlength > llength(lseq)
+/growto { % <string/array> <length> growto <string'/array'>
+ 1 index type /stringtype eq { string } { array } ifelse
+ 2 copy copy pop exch pop
+} bind def
+/lgrowto { % <lseq> <newlength> lgrowto <lseq'>
+ dup //lsubmask add //lnshift bitshift dup 3 index length gt {
+ % Add more sub-arrays. Start by completing the last existing one.
+ % Stack: lseq newlen newtoplen
+ 3 -1 roll dup llength 1 sub //lsubmask or 1 add lgrowto
+ % Stack: newlen newtoplen lseq
+ [ exch aload pop
+ counttomark 2 add -1 roll % newtoplen
+ counttomark sub { dup 0 0 getinterval lsublen growto } repeat
+ dup 0 0 getinterval ] exch
+ } {
+ pop
+ } ifelse
+ % Expand the last sub-array.
+ 1 sub //lsubmask and 1 add
+ exch dup dup length 1 sub 2 copy
+ % Stack: newsublen lseq lseq len-1 lseq len-1
+ get 5 -1 roll growto put
+} bind def
+
+% We represent an unresolved object reference by a procedure of the form
+% {obj# gen# resolveR}. This is not a possible PDF object, because PDF has
+% no way to represent procedures. Since PDF in fact has no way to represent
+% any PostScript object that doesn't evaluate to itself, we can 'force'
+% a possibly indirect object painlessly with 'exec'.
+% Note that since we represent streams by executable dictionaries
+% (see below), we need both an xcheck and a type check to determine
+% whether an object has been resolved.
+/unresolved? % <object#> unresolved? <bool>
+ { Objects exch lget dup xcheck exch type /integertype eq and
+ } bind def
+/oforce /exec load def
+/oget % <array> <index> oget <object>
+ % <dict> <key> oget <object>
+ { 2 copy get dup xcheck
+ { exec dup 4 1 roll put }
+ { exch pop exch pop }
+ ifelse
+ } bind def
+% A null value in a dictionary is equivalent to an omitted key;
+% we must check for this specially.
+/knownoget
+ { 2 copy known
+ { oget dup null eq { pop false } { true } ifelse }
+ { pop pop false }
+ ifelse
+ } bind def
+
+% PDF 1.1 defines a 'foreign file reference', but not its meaning.
+% Per the specification, we convert these to nulls.
+/F % <file#> <object#> <generation#> F <object>
+ { % Some PDF 1.1 files use F as a synonym for f!
+ count 3 lt { f } { pop pop pop null } ifelse
+ } bind def
+
+% We keep track of objects in a pair of arrays, Objects and Generations.
+% Generations[N] is 1+ the current generation number for object number N.
+% (As far as we can tell, this is needed only for error checking.)
+% If object N is loaded, Objects[N] is the actual object;
+% otherwise, Objects[N] is an executable integer giving the file offset
+% of the object's entry in the cross-reference table.
+% For free objects, Generations[N] is 0.
+/checkgeneration % <object#> <generation#> checkgeneration <object#> <OK>
+ { Generations 2 index lget 1 sub 1 index eq
+ { pop true
+ }
+ { (Warning: wrong generation: ) print 1 index =only ( ) print = false
+ }
+ ifelse
+ } bind def
+/R % <object#> <generation#> R <object>
+ { 1 index unresolved?
+ { /resolveR cvx 3 packedarray cvx }
+ { checkgeneration { Objects exch lget } { pop null } ifelse }
+ ifelse
+ } bind def
+
+% If we encounter an object definition while reading sequentially,
+% we just store it away and keep going.
+/objopdict mark
+ valueopdict { } forall
+ /endobj dup cvx
+.dicttomark readonly def
+/obj % <object#> <generation#> obj <object>
+ { PDFfile objopdict .pdfrun
+ } bind def
+/endobj % <object#> <generation#> <object> endobj <object>
+ { 3 1 roll
+ % Read the xref entry if we haven't yet done so.
+ % This is only needed for generation # checking.
+ 1 index unresolved?
+ { PDFfile fileposition
+ 2 index readxrefentry pop
+ PDFoffset add PDFfile exch setfileposition
+ } if
+ checkgeneration { Objects exch 2 index lput } { pop pop null } ifelse
+ } bind def
+
+% When resolving an object reference, we stop at the endobj.
+/resolveopdict mark
+ valueopdict { } forall
+ /endobj { endobj exit } bind
+.dicttomark readonly def
+/resolveR % <object#> <generation#> resolveR <object>
+ { DEBUG { (%Resolving: ) print 2 copy 2 array astore == } if
+ 1 index unresolved?
+ { PDFfile fileposition 3 1 roll
+ 1 index readxrefentry
+ 3 1 roll checkgeneration
+ { % Stack: savepos objpos obj#
+ exch PDFoffset add PDFfile exch setfileposition
+ PDFfile token pop 2 copy ne
+ { (xref error!\n) print /resolveR cvx /rangecheck signalerror
+ }
+ if pop PDFfile token pop
+ PDFfile token pop /obj ne
+ { (xref error!\n) print /resolveR cvx /rangecheck signalerror
+ }
+ if
+ pdf_run_resolve % PDFfile resolveopdict .pdfrun
+ }
+ { Objects exch null lput pop null
+ }
+ ifelse exch PDFfile exch setfileposition
+ }
+ { pop Objects exch lget
+ }
+ ifelse
+ } bind def
+
+%================================ Streams ================================ %
+
+% We represent a stream by an executable dictionary that contains,
+% in addition to the contents of the original stream dictionary:
+% /File - the file or string where the stream contents are stored;
+% /FilePosition - iff File is a file, the position in the file
+% where the contents start.
+% /StreamKey - the key used to decrypt this stream if any
+% We do the real work of constructing the data stream only when the
+% contents are needed.
+
+% Construct a stream. The length is not reliable in the face of
+% different end-of-line conventions, but it's all we've got.
+%
+% PDF files are inconsistent about what may fall between the 'stream' keyword
+% and the actual stream data, and it appears that no one algorithm can
+% detect this reliably. We used to try to guess whether the file included
+% extraneous \r and/or \n characters, but we no longer attempt to do so,
+% especially since the PDF 1.2 specification states flatly that the only
+% legal terminators following the 'stream' keyword are \n or \r\n, both of
+% which are properly skipped and discarded by the token operator.
+/stream
+ { PDFsource PDFfile eq
+ { dup /File PDFfile put
+ dup /FilePosition PDFfile fileposition put
+ DEBUG { (%FilePosition: ) print dup /FilePosition get == } if
+ PDFfile fileposition 1 index /Length oget add
+ PDFfile exch setfileposition
+ }
+ { % We're already reading from a stream, which we can't reposition.
+ % Capture the sub-stream contents in a string.
+ dup /Length oget string PDFsource exch readstring
+ not
+ { (Unexpected EOF in stream!\n) print
+ /stream cvx /rangecheck signalerror
+ }
+ if
+ 1 index exch /File exch put
+ }
+ ifelse
+ PDFsource token pop
+ /endstream ne { /stream cvx /syntaxerror signalerror } if
+ cvx
+ } bind def
+
+% Resolve a stream dictionary to a PostScript stream.
+% Streams with no filters require special handling:
+% - If we are going to interpret their contents, we let endstream
+% terminate the interpretation loop;
+% - If we are just going to read data from them, we impose
+% a SubFileDecode filter that reads just the requisite amount of data.
+% Note that, in general, resolving a stream repositions PDFfile.
+% Clients must save and restore the position of PDFfile themselves.
+/resolvestream % <streamdict> <readdata?> resolvestream <stream>
+ { exch dup /FilePosition .knownget
+ { 1 index /File get exch setfileposition }
+ if
+ % Stack: readdata? dict
+ dup /DecodeParms .knownget not { null } if
+ 1 index /Filter .knownget not { {} } if
+ dup type /nametype eq
+ { 1 array astore
+ 1 index null ne { exch 1 array astore exch } if
+ }
+ if
+ % Stack: readdata? dict parms filternames
+ 2 index /File get exch
+ % Stack: readdata? dict parms file/string filternames
+ pdf_decrypt_stream % add decryption if needed
+ dup length 0 eq
+ { % All the PDF filters have EOD markers, but in this case
+ % there is no specified filter.
+ pop exch pop
+ % Stack: readdata? dict file/string
+ 2 index
+ { % We're going to read data; use a SubFileDecode filter.
+ 1 index /Length oget () /SubFileDecode filter
+ }
+ { dup type /filetype ne
+ { % Use a SubFileDecode filter to read from a string.
+ 0 () SubFileDecode filter
+ }
+ if
+ }
+ ifelse
+ }
+ { 2 index null eq
+ { { filter }
+ }
+ { % Stack: readdata? dict parms file/string filtername
+ { 2 index 0 get dup null eq { pop } { exch } ifelse filter
+ exch dup length 1 sub 1 exch getinterval exch
+ }
+ }
+ ifelse forall exch pop
+ }
+ ifelse
+ % Stack: readdata? dict file
+ exch pop exch pop
+ } bind def
+/endstream { exit } def
+
+end % pdfdict
+.setglobal
diff --git a/gs/lib/pdf_draw.ps b/gs/lib/pdf_draw.ps
new file mode 100644
index 000000000..a1187d3dd
--- /dev/null
+++ b/gs/lib/pdf_draw.ps
@@ -0,0 +1,449 @@
+% Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_draw.ps
+% PDF drawing operations (graphics, text, and images).
+
+% We don't handle the following PDF elements yet (identified by
+% page number in the reference manual):
+% style strings (63-64), except in a few known fonts
+% font descriptor resources (71-75), except for MissingWidth
+% text clipping modes (104)
+% What do these mean??
+
+% We handle the following PDF 1.2 constructs:
+% gs operator (but not functions)
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+GS_PDF_ProcSet begin
+pdfdict begin
+
+% For simplicity, we use a single interpretation dictionary for all
+% PDF graphics operations, even though this is too liberal.
+/drawopdict 100 dict def
+
+% ================================ Graphics ================================ %
+
+% ---------------- Functions ---------------- %
+
+/resolvefunction { % <fndict> resolvefunction <function>
+ % Don't lose our place in PDFfile.
+ PDFfile fileposition exch
+ dup true resolvestream
+ % The stream isn't positionable, so read all the data now.
+ % Note that we only support FunctionType 0.
+ % Stack: filepos fndict stream
+ 1 index /Range get length 2 idiv 2 index /BitsPerSample get mul
+ 2 index /Size get { mul } forall
+ 7 add 8 idiv string
+ 1 index exch readstring pop exch closefile
+ % Stack: filepos fndict data
+ exch dup length 1 add dict .copydict
+ dup /DataSource 4 -1 roll put
+ .buildfunction
+ exch PDFfile exch setfileposition
+} bdef
+
+% ---------------- Graphics state management ---------------- %
+
+drawopdict begin
+ % Graphics state stack
+ /q { q } def
+ /Q { Q } def
+ % Graphics state setting
+ /cm { cm } def
+ /i { i } def
+ /J { J } def
+ /d { d } def
+ /j { j } def
+ /w { w } def
+ /M { M } def
+ /gs { gs } def
+end
+
+/gsparamdict mark
+ /Type { pop }
+ /SA { /setstrokeadjust 1 # }
+ /OP { /setoverprint 1 # }
+ /BG
+ { dup /Identity eq
+ { pop { } /setblackgeneration 1 #
+ }
+ { %****** DUMMY ******
+ pop
+ }
+ ifelse
+ }
+ /UCR
+ { dup /Identity eq
+ { pop { } /setundercolorremoval 1 #
+ }
+ { %****** DUMMY ******
+ pop
+ }
+ ifelse
+ }
+ /TR
+ { dup /Identity eq
+ { pop { } /settransfer 1 #
+ }
+ { %****** DUMMY ******
+ pop
+ }
+ ifelse
+ }
+ /HT
+ { dup /Default eq
+ { pop /.setdefaultscreen 0 #
+ }
+ { %****** DUMMY ******
+ pop
+ }
+ ifelse
+ }
+ /HTP { oget aload pop /sethalftonephase 2 # }
+.dicttomark readonly def
+/gs % <gsres> gs -
+ { Page /ExtGState rget
+ { { oforce exch gsparamdict exch .knownget { exec } { pop } ifelse }
+ forall
+ }
+ if
+ } bdef
+
+% ---------------- Color setting ---------------- %
+
+/csncompdict mark
+ /DeviceGray 1
+ /CalGray 1
+ /DeviceRGB 3
+ /CalRGB 3
+ /Lab 3
+ /DeviceCMYK 4
+ /CalCMYK 4
+ /Separation 1
+.dicttomark readonly def
+
+/csrdict mark
+ /DeviceGray {
+ /DefaultGray Page /ColorSpace rget { exch pop } if
+ }
+ /CalGray { }
+ /DeviceRGB {
+ /DefaultRGB Page /ColorSpace rget { exch pop } if
+ }
+ /CalRGB { }
+ /Lab { }
+ /DeviceCMYK { }
+ /CalCMYK { }
+ /Indexed %****** SHOULD RESOLVE BASE SPACE *****
+ { dup 3 oget dup type /stringtype eq
+ { pop
+ }
+ { % The color lookup table is a stream.
+ % Get its contents. Don't lose our place in PDFfile.
+ PDFfile fileposition 3 1 roll
+ true resolvestream
+ 1 index 2 get 1 add
+ csncompdict 3 index 1 get
+ dup type /arraytype eq { 0 get } if get mul
+ string readstring pop
+ % Stack: cspace filepos table
+ 1 index 3 3 -1 roll put
+ exch PDFfile exch setfileposition
+ }
+ ifelse
+ }
+ /Pattern
+ { dup type /nametype ne
+ { dup length 1 ge
+ { 1 get resolvecolorspace
+ /Pattern exch 2 array astore
+ }
+ if
+ }
+ if
+ }
+ /Separation %****** SHOULD RESOLVE ALTERNATIVE SPACE ******
+ { % Resolve the tintTransform function.
+ dup 3 oget resolvefunction
+ 1 index 3 3 -1 roll put
+ }
+.dicttomark readonly def
+
+/csgray % <op> <csop> csgray -
+ { /DeviceGray resolvecolorspace
+ dup /DeviceGray eq { pop } { exch 3 -1 roll } ifelse
+ pop cvx exec
+ } bdef
+/csrgb % <op> <csop> csrgb -
+ { /DeviceRGB resolvecolorspace
+ dup /DeviceRGB eq { pop } { exch 3 -1 roll } ifelse
+ pop cvx exec
+ } bdef
+/cscmyk % <op> <csop> cscmyk -
+ { pop cvx exec
+ } bdef
+/csresolve % <csresourcename> csresolve <cspace>
+ { dup Page /ColorSpace rget
+ { exch pop resolvecolorspace }
+ { /undefined cvx signalerror }
+ ifelse
+ } bdef
+/resolvecolorspace { % <cspace> resolvecolorspace <cspace'>
+ dup dup type /arraytype eq { 0 get } if
+ //csrdict exch .knownget {
+ exec dup type /nametype ne { dup length 1 eq { 0 get } if } if
+ } {
+ csresolve
+ } ifelse
+} bdef
+
+/cset % <c0> ... [- <sc1> <sc2> <sc3> <sc4> <sc5>] cset -
+ { % We can't really make sc[n] and SC[N] work, because
+ % the color space information isn't available at
+ % conversion time; so we hack it by assuming that
+ % all the operands on the stack are used, and that
+ % if the top operand is a name, it's a Pattern resource.
+ 1 index type /nametype eq
+ { exch Page /Pattern rget { resolvepattern } { null } ifelse exch }
+ if
+ count 1 sub get exec
+ } bdef
+/resolvepattern % <patternstreamdict> resolvepattern <patterndict>
+ { % Don't do the resolvestream now: just capture the data
+ % from the file if necessary.
+ dup length dict copy
+ dup /FilePosition .knownget
+ { 1 index /File get dup fileposition 3 1 roll
+ % Stack: dict savepos pos file
+ dup 3 -1 roll setfileposition
+ dup 3 index /Length get string readstring pop
+ % Stack: dict savepos file string
+ 3 1 roll exch setfileposition
+ 1 index /File 3 -1 roll put
+ dup /FilePosition undef
+ }
+ if
+ dup /PaintProc
+ { false resolvestream pdfopdict .pdfrun
+ }
+ put
+ } bdef
+
+drawopdict begin
+ /g { /g { cs sc1 } csgray } bdef
+ /rg { /rg { cs sc3 } csrgb } bdef
+ /k { /k { cs sc4 } cscmyk } bdef
+ /cs { csresolve cs } bdef
+ /sc { { null sc1 sc2 sc3 sc4 sc5 } cset } bdef
+ /scn /sc load def
+ /G { /G { CS SC1 } csgray } bdef
+ /RG { /RG { CS SC3 } csrgb } bdef
+ /K { /K { CS SC4 } cscmyk } bdef
+ /CS { csresolve CS } bdef
+ /SC { { null SC1 SC2 SC3 SC4 SC5 } cset } bdef
+ /SCN /SC load def
+end
+
+% ---------------- Paths ---------------- %
+
+drawopdict begin
+ % Path construction
+ /m { m } def
+ /l { l } def
+ /c { c } def
+ /v { v } def
+ /y { y } def
+ /re { re } def
+ /h { h } def
+ % Path painting and clipping
+ /n { n } def
+ /S { S } def
+ /s { s } def
+ /f { f } def
+ /f* { f* } def
+ /B { B } def
+ /b { b } def
+ /B* { B* } def
+ /b* { b* } def
+ /W { W } def
+ /W* { W* } def
+end
+
+% ---------------- XObjects ---------------- %
+
+/xobjectprocs mark % <dict> -proc- -
+ /Image { DoImage }
+ /Form { DoForm }
+.dicttomark readonly def
+
+/defaultdecodedict mark
+ /DeviceGray [0 1] readonly
+ /CalGray 1 index
+ /DeviceRGB [0 1 0 1 0 1] readonly
+ /CalRGB 1 index
+ /Lab
+ { 0 100 2 index 1 get /Range .knownget not { {-100 100 -100 100} } if
+ aload pop 6 array astore readonly
+ } bind
+ /DeviceCMYK [0 1 0 1 0 1 0 1] readonly
+ /CalCMYK 1 index
+ /Separation [0 1] readonly
+.dicttomark readonly def
+
+/DoImage
+ { dup length dict
+ 1 index /ColorSpace knownoget
+ { resolvecolorspace
+ dup type /arraytype eq { dup length 1 eq { 0 get } if } if
+ exch begin /ColorSpace exch def
+ }
+ { begin
+ }
+ ifelse
+ /ImageType 1 def
+ % Always define ImageMask appropriately.
+ dup /ImageMask knownoget dup { and } if
+ /ImageMask exch def
+ /Width 2 copy oget def
+ /Height 2 copy oget def
+ /BitsPerComponent 2 copy oget def
+ /Decode 2 copy knownoget not
+ { % Decode is required for the PostScript image operators.
+ ImageMask
+ { [0 1]
+ }
+ { ColorSpace dup type /arraytype eq { 0 get } if dup /Indexed eq
+ { pop [ 0 1 BitsPerComponent bitshift 1 sub ] }
+ { defaultdecodedict exch get exec }
+ ifelse
+ }
+ ifelse
+ }
+ if def
+ /Interpolate 2 copy knownoget { def } { pop } ifelse
+ /ImageMatrix Width 0 0 Height neg 0 Height 6 array astore def
+ % Define DataSource as the width of the row buffer,
+ % which is what is needed if we're writing PostScript.
+ /DataSource
+ Width BitsPerComponent mul
+ ImageMask not { Decode length 2 idiv mul } if
+ 7 add 8 idiv
+ def
+ % Even though we're going to read data,
+ % pass false to resolvestream so that
+ % it doesn't try to use Length (which may not be present).
+ false resolvestream /Is_stream exch store
+ currentdict end ID
+ } bdef
+% Redefine Is, which constructs the data source for the image,
+% to retrieve the stream. (pdf_2ps.ps redefines Is to copy the data too.)
+userdict /Is_stream null put
+/Is % <imagedict> Is <imagedict> <datasource>
+ { Is_stream
+ } bdef
+
+/DoForm
+ { dup [ /pop load 2 index
+ { false resolvestream pdfopdict .pdfrun }
+ aload pop ] cvx /PaintProc exch put
+ execform
+ } bdef
+
+drawopdict begin
+ /Do
+ { PDFfile fileposition exch
+ dup Page /XObject rget not { /undefined cvx signalerror } if
+ exch pop dup /Subtype get xobjectprocs exch get exec
+ PDFfile exch setfileposition
+ } bdef
+end
+
+% ---------------- In-line images ---------------- %
+
+% Undo the abbreviations in an in-line image dictionary.
+% Note that these can appear as keys, values, or members of array values.
+% /I is ambiguous; we check specially for it below.
+/unabbrevdict mark
+ % Top-level dictionary keys
+ /BPC /BitsPerComponent /CS /ColorSpace /D /Decode /DP /DecodeParms
+ /F /Filter /H /Height /IM /ImageMask /W /Width
+ % Values
+ /AHx /ASCIIHexDecode /A85 /ASCII85Decode /CC /CalCMYK
+ /CCF /CCITTFaxDecode /CG /CalGray /CR /CalRGB
+ /DCT /DCTDecode /CMYK /DeviceCMYK /G /DeviceGray /RGB /DeviceRGB
+ /I /Indexed /LZW /LZWDecode /RL /RunLengthDecode
+.dicttomark readonly def
+/unabbrev % <obj> unabbrev <obj'>
+ { dup type /nametype eq
+ { unabbrevdict 1 index .knownget { exch pop } if
+ }
+ { dup type /arraytype eq
+ { dup 0 1 2 index length 1 sub
+ { 2 copy get unabbrev put dup
+ }
+ for pop
+ }
+ if
+ }
+ ifelse
+ } bdef
+
+drawopdict begin
+ /BI { mark } bdef
+ /ID
+ { counttomark
+ { counttomark 1 roll
+ dup /I eq { pop /Interpolate } { unabbrev } ifelse
+ }
+ repeat
+ /File PDFsource
+ .dicttomark DoImage
+ PDFsource token pop /EI ne { /ID cvx /syntaxerror signalerror } if
+ } bdef
+end
+
+% ================================ Text ================================ %
+
+drawopdict begin
+ % Text control
+ /BT { BT } def
+ /ET { ET } def
+ /Tc { Tc } def
+ /TL { TL } def
+ /Tr { Tr } def
+ /Ts { Ts } def
+ /Tw { Tw } def
+ /Tz { Tz } def
+ % Text positioning
+ /Td { Td } def
+ /TD { TD } def
+ /Tm { Tm } def
+ /T* { T* } def
+ % Text painting
+ /Tj { Tj } def
+ /' { ' } def
+ /" { " } def
+ /TJ { mark exch aload pop TJ } def
+end
+
+end % pdfdict
+end % GS_PDF_ProcSet
+.setglobal
diff --git a/gs/lib/pdf_font.ps b/gs/lib/pdf_font.ps
new file mode 100644
index 000000000..01739080d
--- /dev/null
+++ b/gs/lib/pdf_font.ps
@@ -0,0 +1,454 @@
+% Copyright (C) 1994, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_font.ps
+% PDF font operations.
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+GS_PDF_ProcSet begin
+pdfdict begin
+
+% We cache the PostScript font in an additional element of the
+% font resource dictionary, called PSFont.
+
+% ---------------- Encodings ---------------- %
+
+% Apply a list of differences to an Encoding.
+/updateencoding % <encoding> <differences> updateencoding <enc'>
+ { exch dup length array copy
+ exch 0 exch {
+ % Stack: enc' code element
+ dup type /nametype ne
+ { exch pop }
+ { 3 copy put pop 1 add }
+ ifelse
+ } forall pop
+ } bdef
+
+% Get the Encoding for a font.
+/getencoding % <base-encoding> <font-resource> getencoding <enc>
+ { /Encoding knownoget
+ { dup type /nametype eq
+ { exch pop findencoding
+ }
+ { dup /BaseEncoding knownoget
+ { findencoding 3 -1 roll pop exch
+ }
+ if
+ /Differences knownoget { updateencoding } if
+ }
+ ifelse
+ }
+ if
+ } bdef
+
+% Adjust a font according to the Encoding and Widths in the font resource.
+/adjustfont % <font-resource> <font> adjustfont
+ % <font'> <changed>
+ { getfontencoding getfontmetrics 4 -1 roll pop .updatefont
+ { dup /FontName 2 copy get genfontname dup 5 1 roll put definefont }
+ if
+ } bind def
+
+% Get the (possibly modified) encoding of a font.
+/getfontencoding % <font-resource> <font> getfontencoding
+ % <font-resource> <font> <encoding>
+ { dup /Encoding get 2 index getencoding
+ } bdef
+
+% Get the metrics of a font, if specified.
+/getfontmetrics % <font-resource> <font> <encoding> getfontmetrics
+ % <font-resource> <font> <encoding> <Metrics|null>
+ { 2 index /Widths known
+ { 2 dict begin
+ /Encoding exch def
+ /Metrics Encoding length dict def
+ exch
+ % Stack: font font-res
+ % Note that widths are always based on a 1000-unit
+ % character space, but the FontMatrix may specify
+ % some other scale factor. Compensate for this here,
+ % by scaling the Widths if necessary.
+ 0.001 2 index /FontMatrix get 0 get div
+ % Stack: font font-res mscale
+ 1 index /FirstChar oget dup 1 4 index /LastChar oget
+ { % Stack: font font-res mscale first-char index
+ Encoding 1 index get
+ 4 index /Widths oget 2 index 4 index sub get
+ % Stack: font font-res mscale first-char index charname width
+ 4 index mul
+ % There is a hack here to deal with encodings where the
+ % same character appears more than once, because the Metrics
+ % dictionary works by character name, not by character code.
+ % Because of this, we can't deal with Width vectors that
+ % specify different widths for the same character name
+ % appearing multiple times in the Encoding.
+ Metrics 2 index .knownget not { 0 } if 0 ne
+ { pop pop }
+ { Metrics 3 1 roll put }
+ ifelse pop
+ }
+ for pop
+ % Now fill in the MissingWidth for any encoded characters
+ % that aren't in Metrics already.
+ % Stack: font font-res mscale
+ Metrics 2 index /FontDescriptor oget
+ /MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
+ Encoding
+ { % Stack: font font-res mscale missing-width metrics charname
+ 2 copy known not { 2 copy 4 index put } if pop
+ }
+ forall pop pop pop
+ exch Encoding Metrics end
+ }
+ { null
+ }
+ ifelse
+ } bdef
+
+% ---------------- Descriptors ---------------- %
+
+% Partial descriptors for the 14 built-in fonts.
+/standardfontdescriptors mark
+ /Courier mark /Flags 16#23 .dicttomark
+ /Courier-Oblique 1 index
+ /Courier-Bold 1 index
+ /Courier-BoldOblique 1 index
+ /Helvetica mark /Flags 16#20 .dicttomark
+ /Helvetica-Oblique 1 index
+ /Helvetica-Bold 1 index
+ /Helvetica-BoldOblique 1 index
+ /Times-Roman mark /Flags 16#22 .dicttomark
+ /Times-Bold 1 index
+ /Times-Italic mark /Flags 16#62 .dicttomark
+ /Times-BoldItalic 1 index
+ /Symbol mark /Flags 16#4 .dicttomark
+ /ZapfDingbats 1 index
+.dicttomark readonly def
+
+% ---------------- Utilities ---------------- %
+
+% Fabricate a font name by adding %'s on the end.
+/genfontname % <name> genfontname <name>
+ { dup length string cvs
+ { (%) concatstrings
+ dup cvn FontDirectory exch known not { cvn exit } if
+ }
+ loop
+ } bdef
+
+% Find a font, and adjust its encoding if necessary.
+/pdffindfont % <font-resource> <fontname> pdffindfont <font>
+ { findfont adjustfont
+ } bdef
+
+% ---------------- Type 1 fonts ---------------- %
+
+/buildType1 % <Type1-font-resource> buildType1 <font>
+ { dup /BaseFont get pdffindfont
+ } bdef
+
+% The state dictionary for the embedded Type 1 font reading procedure
+% has the following keys and values:
+% data - stream (filter)
+% buffer, buffer2 - string
+% leftstr - string containing (non-negative) integer
+% sectionstr - string containing a character 0 .. 2
+% stream - (stream) dictionary
+% proc - procedure of the form {-dict- type1read}
+% When the procedure is executing, this dictionary is current.
+% leftstr and sectionstr are strings so that we can change their values
+% reliably in case the font executes a restore!
+
+% Read an embedded Type 1 font.
+/readfontfilter % <proc> readfontfilter <filter>
+ { % We make this a separate procedure so that we can
+ % redefine it when we're writing PostScript.
+ 0 () /SubFileDecode filter
+ } bdef
+/readtype1dict 5 dict dup begin
+ /definefont {
+ dup wcheck not { dup length dict copy } if
+ exch pop savedFontName exch
+ //systemdict /definefont get exec
+ } bdef
+ /eexec {
+ 55665 /eexecDecode filter
+ //systemdict begin readtype1dictcopy begin cvx stopped
+ currentdict readtype1dictcopy eq { end } if
+ currentdict //systemdict eq { end } if
+ { stop } if
+ } bdef
+end readonly def
+/readtype1 % <font-resource> <stream-dict> readtype1 <font>
+ { % Read the definition, using a procedure-based filter
+ % that turns binary/hex conversion on and off
+ % at the right times.
+ PDFfile fileposition 3 1 roll
+ 7 dict begin
+ /leftstr ( ) 10 string copy def
+ dup /Length1 oget leftstr cvs pop
+ /sectionstr <00> 1 string copy def
+ /stream 1 index def
+ true resolvestream /data exch def
+ /buffer 1000 string def % arbitrary
+ /buffer2 buffer length 2.1 div cvi 1 sub string def
+ currentdict end
+ /type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
+ readfontfilter
+ % Some buggy embedded fonts leave extra junk on the stack,
+ % so we have to make a closure that records the stack depth
+ % in a fail-safe way.
+ //systemdict begin
+ % Rebind definefont so we can substitute the FontName
+ % from the descriptor.
+ //readtype1dict dup length 2 add dict copy begin
+ 1 index /FontDescriptor oget /FontName oget /savedFontName exch def
+ /readtype1dictcopy currentdict def
+ { run } aload pop count 1 sub 2 packedarray cvx exec
+ end end
+ count exch sub { pop } repeat
+ PDFfile 3 -1 roll setfileposition
+ /FontDescriptor oget /FontName oget findfont
+ } bdef
+
+% Execute the appropriate reading procedure.
+/type1read % <dict> type1read <string>
+ { begin leftstr cvi
+ { type1read1 type1read2 type1read3 } sectionstr 0 get get exec
+ ( ) leftstr copy cvs pop end
+ } bdef
+
+% Read the next block of data into the buffer.
+/type1readdata % <left> <buffer> type1readdata <substring> <left'>
+ { 0 2 index 2 index length min getinterval
+ % Adobe requires readstring to signal an error if given
+ % an empty string. Work around this nonsense here.
+ dup length 0 ne { data exch readstring pop } if
+ dup length 3 -1 roll exch sub
+ DEBUG
+ { dup =only ( read ) print
+ 1 index length =only (: ) print
+ 1 index == flush
+ } if
+ } bdef
+
+% Read the next block of the initial text portion.
+/type1read1 % <left> type1read1 <string> <left'>
+ { DEBUG { (read1 ) print } if
+ dup 0 eq
+ { pop sectionstr 0 1 put
+ stream /Length2 oget type1read2
+ }
+ { buffer type1readdata
+ }
+ ifelse
+ } bdef
+
+% Read the next block of the encrypted portion.
+/type1trailer
+(0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+0000000000000000000000000000000000000000000000000000000000000000\n\
+cleartomark\n)
+readonly def
+/type1read2 % <left> type1read2 <string> <left'>
+ { DEBUG { (read2 ) print } if
+ dup 0 eq
+ { pop sectionstr 0 2 put
+ stream /Length3 oget
+ dup 0 eq
+ { DEBUG { (trailer ) print } if
+ type1trailer exch
+ }
+ { type1read3
+ }
+ ifelse
+ }
+ { buffer2 type1readdata exch
+ buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
+ buffer (>) search pop exch pop exch pop exch
+ }
+ ifelse
+ } bdef
+
+% Read the next block of the final text portion.
+% When finished, this procedure returns an empty string.
+/type1read3 % <left> type1read3 <string> <left'>
+ { DEBUG { (read3 ) print } if
+ buffer type1readdata
+ } bdef
+
+% ---------------- Type 3 fonts ---------------- %
+
+/.notdefEncoding 256 { /.notdef } repeat 256 packedarray def
+
+/buildType3 % <Type3-font-resource> buildType3 <font>
+ { 8 dict begin
+ /FontType 3 def
+ /FontBBox 1 index /FontBBox get cvx def
+ /FontMatrix 1 index /FontMatrix oget def
+ /CharProcs 1 index /CharProcs oget def
+ /FontName 1 index /Name get genfontname def
+ /Encoding .notdefEncoding 2 index getencoding def
+ /BuildGlyph
+ { exch /CharProcs get exch oget
+ PDFfile fileposition exch
+ false resolvestream
+ % Don't let setgcolor set the color inside the BuildGlyph
+ % procedure, because this causes an /undefined error.
+ q_ null /FillColor gput null /StrokeColor gput
+ pdfopdict .pdfrun
+ Q_
+ PDFfile exch setfileposition
+ } bdef
+ FontName currentdict end definefont exch pop
+ } bdef
+
+% ---------------- TrueType fonts ---------------- %
+
+/TTfonts mark
+ /Arial /Helvetica
+ /Arial,Italic /Helvetica-Oblique
+ /Arial,Bold /Helvetica-Bold
+ /Arial,BoldItalic /Helvetica-BoldOblique
+ /TimesNewRoman /Times-Roman
+ /TimesNewRoman,Italic /Times-Italic
+ /TimesNewRoman,Bold /Times-Bold
+ /TimesNewRoman,BoldItalic /Times-BoldItalic
+.dicttomark readonly def
+
+/buildTrueType % <TrueType-font-resource> buildTrueType <font>
+ { dup /BaseFont get
+ dup TTfonts exch .knownget { exch pop } if pdffindfont
+ } bdef
+
+% Read an embedded TrueType font.
+/readtruetype % <font-resource> <stream-dict> readtruetype <font>
+ { % This is much simpler than readtype1, because we don't
+ % have to deal with the tripartite .PFB format.
+ PDFfile fileposition 3 1 roll
+ true resolvestream readfontfilter .loadttfont
+ dup /FontName get exch definefont exch pop
+ PDFfile 3 -1 roll setfileposition
+ } bdef
+
+% ---------------- Type 0 fonts ---------------- %
+%**************** NOT ACTUALLY SUPPORTED YET
+
+/buildType0 % <Type0-font-resource> buildType0 <font>
+{ 10 dict begin
+ /FontType 0 def
+ /FontMatrix 1 index /FontMatrix knownoget not { matrix } if def
+ /FontName 1 index /BaseFont get def
+ /FMapType 9 def
+ /Encoding [ 0 1 4 index /DescendantFonts oget length 1 sub { } for ] def
+ /FDepVector [ 2 index /DescendantFonts oget { exec } forall ] def
+ /CMap 1 index /Encoding oget
+ dup type /nametype eq
+ { dup Page /CMap rget
+ { exch pop resolvestream } { /undefined signalerror } ifelse
+ }
+ { resolvestream
+ }
+ ifelse
+ % FontName currentdict end definefont exch pop
+ end pop /Times-Roman findfont
+} bdef
+
+% ---------------- Other embedded fonts ---------------- %
+
+/fontloadprocs mark
+ /Type1C /readType1C cvx
+.dicttomark readonly def
+
+% Read an embedded compressed font.
+/readType1C % <font-resource> <stream-dict> readType1C <font>
+ { PDFfile fileposition 3 1 roll
+ dup true resolvestream dup readfontfilter
+ % Stack: pos resource streamdict stream filter
+ 3 index /FontDescriptor oget /FontName oget
+ 1 index FRD
+ closefile closefile pop
+ PDFfile 3 -1 roll setfileposition
+ /FontDescriptor oget /FontName oget findfont
+ } bdef
+
+% ---------------- Font lookup ---------------- %
+
+/fonttypeprocs mark % <font-resource> -proc- <font>
+ /Type0 /buildType0 cvx
+ /Type1 /buildType1 cvx
+ /MMType1 1 index
+ /Type3 /buildType3 cvx
+ /TrueType /buildTrueType cvx
+.dicttomark readonly def
+
+/resourcefont % <font-resource> resourcefont <font>
+ { dup /PSFont .knownget
+ { /FID .knownget { type /fonttype eq } { false } ifelse }
+ { false }
+ ifelse
+ { /PSFont get
+ }
+ { dup dup /FontDescriptor knownoget
+ { % Stack: font-res font-res font-desc
+ dup /FontFile knownoget
+ { exch pop 1 index 3 1 roll readtype1 adjustfont true }
+ { dup /FontFile2 knownoget
+ { exch pop 1 index 3 1 roll readtruetype adjustfont true }
+ { /FontFile3 knownoget
+ { 1 index exch dup /Subtype get fontloadprocs exch get exec adjustfont true }
+ { false }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+ }
+ { false }
+ ifelse
+ % Stack: font-res font-res false
+ % -or-: font-res font true
+ not
+ { dup /Subtype get fonttypeprocs exch get exec }
+ if
+ 2 copy /PSFont exch put
+ exch pop
+ }
+ ifelse
+ } bdef
+
+drawopdict begin
+ /d0 /setcharwidth load def
+ /d1 /setcachedevice load def
+ /Tf
+ { 1 index Page /Font rget not { 1 index /undefinedfont signalerror } if
+ resourcefont exch Tf pop
+ } bdef
+end
+
+end % pdfdict
+end % GS_PDF_ProcSet
+.setglobal
diff --git a/gs/lib/pdf_main.ps b/gs/lib/pdf_main.ps
new file mode 100644
index 000000000..948dda932
--- /dev/null
+++ b/gs/lib/pdf_main.ps
@@ -0,0 +1,507 @@
+% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_main.ps
+% PDF file- and page-level operations.
+
+% We handle the following PDF 1.2 constructs:
+% page number rather than page object in Dest array
+% We explicitly ignore the following PDF 1.2 constructs:
+% "Marked content" operators
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+pdfdict begin
+
+% For simplicity, we use a single interpretation dictionary for all
+% PDF graphics execution, even though this is too liberal.
+/pdfopdict mark
+ objopdict { } forall
+ drawopdict { } forall
+ /endstream { exit } bind
+ (%%EOF) cvn { exit } bind % for filters
+ % PDF 1.1 operators
+ /BX { /BXlevel BXlevel 1 add store } bind
+ /EX { /BXlevel BXlevel 1 sub store } bind
+ % PDF 1.2 operators
+ /BMC { pop } bind
+ /BDC { pop pop } bind
+ /EMC { }
+ /MP { pop } bind
+ /DP { pop pop } bind
+.dicttomark readonly def
+
+% ======================== Main program ======================== %
+
+end % pdfdict
+userdict begin
+
+/defaultfontname /Times-Roman def
+
+% Make sure the registered encodings are loaded, so we don't run the risk
+% that some of the indices for their names will overflow the packed
+% representation. (Yes, this is a hack.)
+SymbolEncoding pop
+DingbatsEncoding pop
+
+% Redefine 'run' so it recognizes PDF files.
+systemdict begin
+/.runps /run load def
+/runpdfstring 50 string def % length is arbitrary
+/run
+ { dup type /filetype ne { (r) file } if
+ dup read
+ { dup (%) 0 get eq
+ { pop dup //runpdfstring
+ % Some invalid files might have extra-long first lines....
+ { { readline } .internalstopped not { pop pop exit } if
+ pop =string
+ }
+ loop
+ //runpdfstring (PDF-) anchorsearch
+ { pop pop runpdf }
+ { pop cvx .runexec }
+ ifelse
+ }
+ { 2 copy unread pop .runps
+ }
+ ifelse
+ }
+ { closefile
+ }
+ ifelse
+ } bind odef
+/runpdf % <file> runpdf -
+ { userdict begin
+ /PSFile where { pop PSFile (w) file /PSout exch def } if
+ /Page# null def
+ /Page null def
+ /DSCPageCount 0 def
+ /PDFSave null def
+ GS_PDF_ProcSet begin
+ pdfdict begin
+ pdfopen begin
+ Trailer /Root oget /Pages oget /CropBox knownoget
+ { mark /CropBox 3 -1 roll /PAGES pdfmark
+ }
+ if
+ /FirstPage where { pop FirstPage } { 1 } ifelse
+ 1
+ /LastPage where { pop LastPage } { pdfpagecount } ifelse
+ QUIET not
+ { (Processing pages ) print 2 index =only ( through ) print dup =only
+ (.\n) print flush
+ }
+ if
+ { dup /Page# exch store
+ QUIET not { (Page ) print dup == flush } if
+ pdfgetpage pdfshowpage
+ } for
+ currentdict pdfclose
+ end % temporary dict
+ end % pdfdict
+ end % userdict
+ } bind def
+end % systemdict
+% Redefine the procedure that the C code uses for running piped input.
+% It is OK to use { (%stdin) run } here, because a startjob cannot occur.
+/.runstdin {
+ { (%stdin) run } execute0
+} bind def
+
+end % userdict
+pdfdict begin
+
+% ======================== File parsing ======================== %
+
+% Read the cross-reference and trailer sections.
+
+/traileropdict mark
+ (<<) cvn { mark } bind
+ (>>) cvn /.dicttomark load
+ ([) cvn { mark } bind % ditto
+ (]) cvn dup load
+ /true true
+ /false false
+ /null null
+ /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below
+ /startxref /exit load
+.dicttomark readonly def
+
+% Because of EOL conversion, lines with fixed contents might be followed
+% by one or more blanks.
+/lineeq % <filestr> <conststr> lineeq <bool>
+ { anchorsearch
+ { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
+ { pop false }
+ ifelse
+ } bind def
+/linene { lineeq not } bind def
+
+% Read (mostly scan) the cross-reference table.
+/readxref % <pos> readxref <trailerdict>
+ { PDFoffset add PDFfile exch setfileposition
+ % In some PDF files, this position actually points to
+ % white space before the xref line. Skip over this here.
+ { PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
+ } loop
+ PDFfile exch setfileposition
+ PDFfile pdfstring readline pop
+ (xref) linene { /readxref cvx /syntaxerror signalerror } if
+ % Store the xref table entry position for each object.
+ % We only need to read the run headers, not every entry.
+ { PDFfile token pop % first object # or trailer
+ dup /trailer eq { pop exit } if
+ PDFfile pdfstring readline pop
+ token pop % entry count
+ exch pop exch
+ % This section might be adding new objects:
+ % ensure that Objects and Generations are big enough.
+ % Stack: count obj#
+ 2 copy add
+ dup Objects llength gt
+ { dup Objects exch lgrowto /Objects exch def }
+ if
+ dup Generations llength gt
+ { dup Generations exch lgrowto /Generations exch def }
+ if
+ pop
+ PDFfile fileposition 3 -1 roll
+ { Objects 2 index lget null eq % later update might have set it
+ { Objects 2 index 2 index cvx lput }
+ if exch 1 add exch 20 add
+ }
+ repeat PDFfile exch setfileposition pop
+ } loop
+ PDFfile traileropdict .pdfrun
+ } bind def
+
+% Open a PDF file and read the trailer and cross-reference.
+/pdfopen % <file> pdfopen <dict>
+ { pdfdict readonly pop % can't do it any earlier than this
+ /PSout where { pop /pdf2psdict where { pop pdf2psdict begin } if } if
+ 10 dict begin
+ /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
+ cvlit /PDFfile exch def
+ /PDFsource PDFfile def
+ PDFfile dup 0 setfileposition pdfstring readstring
+ not {/pdfopen cvx /syntaxerror signalerror} if
+ (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
+ length /PDFoffset exch def pop pop
+ PDFfile dup dup 0 setfileposition bytesavailable
+ % Scan backwards over trailing control-character garbage
+ % (nulls, ^Zs, EOLs).
+ { 1 sub 2 copy setfileposition 1 index read pop
+ 32 ge {exit} if
+ } loop 1 sub setfileposition
+ prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
+ PDFfile exch setfileposition
+ prevline cvi % xref start position
+ exch PDFfile exch setfileposition
+ prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
+ pop
+ % Stack: xrefpos
+ /Objects larray def
+ /Generations lstring def
+ % Read the last cross-reference table.
+ readxref /Trailer exch def
+ Trailer /Encrypt known
+ { pdf_process_Encrypt % signal error
+ }
+ if
+ % Read any previous cross-reference tables.
+ Trailer { /Prev .knownget not { exit } if readxref } loop
+ % Create and initialize some caches.
+ /PageCount pdfpagecount def
+ /PageNumbers PageCount dict def
+ /PageIndex PageCount array def
+ % Write the DSC header if appropriate.
+ [ (%!PS-Adobe-1.0) #dsc
+ [ (%%Pages: (atend)) #dsc
+ [ (%%EndComments) #dsc
+ [ (%%BeginProlog) #dsc
+ [ (% This copyright applies to everything between here and the %%EndProlog:) #dsc
+ [ (% ) copyright #dsc
+ (gs_pdf.ps) #dscfile
+ PSLevel1 { (gs_l2img.ps) #dscfile } if
+ [ (%%EndProlog) #dsc
+ % Copy bookmarks (outline) to the output.
+ #?
+ { Trailer /Root oget /Outlines knownoget
+ { /First knownoget
+ { { dup writeoutline /Next knownoget not { exit } if } loop }
+ if
+ }
+ if
+ }
+ if
+ currentdict end
+ } bind def
+
+% Write the outline structure for a file. Uses linkdest (below).
+/writeoutline % <outlinedict> writeoutline -
+ { mark
+ 0 2 index /First knownoget
+ { { exch 1 add exch /Next knownoget not { exit } if } loop }
+ if
+ % stack: dict mark count
+ dup 0 eq
+ { pop 1 index
+ }
+ { 2 index /Count knownoget { 0 lt { neg } if } if
+ /Count exch 3 index
+ }
+ ifelse linkdest /Title oget /Title exch /OUT pdfmark
+ /First knownoget
+ { { dup writeoutline /Next knownoget not { exit } if } loop }
+ if
+ } bind def
+
+% Close a PDF file.
+/pdfclose % <dict> pdfclose -
+ { begin
+ /PSout where
+ { pop
+ [ (%%Trailer) #dsc
+ [ (%%Pages: ) DSCPageCount #dsc
+ PSout closefile
+ }
+ if
+ PDFfile closefile
+ end
+ pdf2psdict where { pop currentdict pdf2psdict eq { end } if } if
+ } bind def
+
+% ======================== Page accessing ======================== %
+
+% Get a (possibly inherited) attribute of a page.
+/pget % <pagedict> <key> pget <value> -true-
+ % <pagedict> <key> pget -false-
+ { 2 copy knownoget
+ { exch pop exch pop true
+ }
+ { exch /Parent knownoget
+ { exch pget }
+ { pop false }
+ ifelse
+ }
+ ifelse
+ } bind def
+
+% Get the value of a resource on a given page.
+/rget % <resname> <pagedict> <restype> rget <value> -true-
+ % <resname> <pagedict> <restype> rget -false-
+{ exch /Resources pget
+ { exch knownoget
+ { exch knownoget }
+ { pop false }
+ ifelse
+ }
+ { pop pop false
+ }
+ ifelse
+} bind def
+
+% Get the total number of pages in the document.
+/pdfpagecount % - pdfpagecount <int>
+ { Trailer /Root oget /Pages oget /Count oget
+ } bind def
+
+% Find the N'th page of the document by iterating through the Pages tree.
+% The first page is numbered 1.
+/pdffindpage % <int> pdffindpage <pagedict>
+ { dup Trailer /Root oget /Pages oget
+ { % We should be able to tell when we reach a leaf
+ % by finding a Type unequal to /Pages. Unfortunately,
+ % some files distributed by Adobe lack the Type key
+ % in some of the Pages nodes! Instead, we check for Kids.
+ dup /Kids knownoget not { exit } if
+ exch pop null
+ 0 1 3 index length 1 sub
+ { 2 index exch oget
+ dup /Kids known { dup /Count oget } { 1 } ifelse
+ % Stack: index kids null node count
+ dup 5 index ge { pop exch pop exit } if
+ 5 -1 roll exch sub 4 1 roll pop
+ }
+ for exch pop
+ dup null eq { pop pop 1 null exit } if
+ }
+ loop
+ % Stack: index countleft node
+ 1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
+ exch pop
+ PageIndex 2 index 1 sub 2 index put
+ PageNumbers 1 index 3 index put
+ exch pop
+ } bind def
+
+% Find the N'th page of the document.
+% The first page is numbered 1.
+/pdfgetpage % <int> pdfgetpage <pagedict>
+ { PageIndex 1 index 1 sub get dup null ne
+ { exch pop }
+ { pop pdffindpage }
+ ifelse
+ } bind def
+
+% Find the page number of a page object (inverse of pdfgetpage).
+/pdfpagenumber % <pagedict> pdfpagenumber <int>
+ { % We use the simplest and stupidest of all possible algorithms....
+ PageNumbers 1 index .knownget
+ { exch pop
+ }
+ { 1 1 PageCount 1 add % will give a rangecheck if not found
+ { dup pdfgetpage oforce 2 index eq { exit } if pop
+ }
+ for exch pop
+ }
+ ifelse
+ } bind def
+
+% Display a given page.
+/boxrect % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
+ { aload pop exch 3 index sub exch 2 index sub
+ } bind def
+/linkdest % <link|outline> linkdest
+ % ([/Page <n>] /View <view> | ) <link|outline>
+ { dup /Dest knownoget
+ { % Check for a name, to be looked up in Dests.
+ dup type /nametype eq
+ { Trailer /Root oget /Dests oget exch knownoget
+ { dup type /dicttype eq { /D get } if }
+ { null }
+ ifelse
+ }
+ if
+ dup null eq
+ { pop }
+ { dup 0 oget
+ dup null eq
+ { pop }
+ { dup type /integertype ne { pdfpagenumber } if
+ /Page exch 4 -2 roll
+ }
+ ifelse
+ dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
+ }
+ ifelse
+ }
+ if
+ } bind def
+/annottypes 5 dict dup begin
+ /Text
+ { mark exch
+ { /Rect /Open /Contents }
+ { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
+ forall pop /ANN pdfmark
+ } bind def
+ /Link
+ { mark exch
+ { /Rect /Border }
+ { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
+ forall linkdest pop /LNK pdfmark
+ } bind def
+end def
+
+/pdfshowpage % <pagedict> pdfshowpage -
+ { dup /Page exch store
+ pdfshowpage_init
+ pdfshowpage_setpage
+ save /PDFSave exch store
+ (before exec) VMDEBUG
+ pdfshowpage_finish
+ (after exec) VMDEBUG
+ PDFSave restore
+ } bind def
+
+/pdfpagecontents % <pagedict> pdfpagecontents <contents>
+ { } bind def
+
+/pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
+ { gsave
+ [ (%%Page: ) Page# ( )
+ DSCPageCount 1 add /DSCPageCount 1 index store #dsc
+ [ (GS_PDF_ProcSet begin) #dsc
+ } bind def
+
+/pdfshowpage_setpage % <pagedict> pdfshowpage_setpage <pagedict>
+ {
+ 3 dict % for setpagedevice
+ % Stack: pagedict setpagedict
+ % We want to look at Rotate for displays, but not for printers.
+ % The following is a hack, but we don't know a better way to do this.
+ currentpagedevice /OutputFile known
+ /PSout where dup { exch pop } if or not
+ { dup /Orientation 3 index /Rotate pget not { 0 } if 90 idiv
+ % Rotate specifies *clockwise* rotation!
+ neg 3 and put
+ }
+ if
+ % Stack: pagedict setpagedict
+ 1 index /MediaBox pget
+ { % Set the page size.
+ boxrect [ 2 index 5 index sub 2 index 5 index sub ]
+ % Stack: pagedict setpagedict llx lly urx ury pagesize
+ 5 index exch /PageSize exch put
+ % Stack: pagedict contents setpagedict llx lly urx ury
+ pop pop
+ neg exch neg exch
+ [ 3 1 roll ]
+ % Stack: pagedict setpagedict pageoffset
+ 1 index exch /PageOffset exch put
+ }
+ if
+ % Stack: pagedict setpagedict
+ /setpagedevice 1 #
+ } bind def
+
+/pdfshowpage_finish % <pagedict> pdfshowpage_finish -
+ {
+ % Copy crop box.
+ dup /CropBox pget
+ { boxrect rectclip
+ dup /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
+ }
+ if
+
+ % Copy annotations and links.
+ dup /Annots knownoget
+ { 0 1 2 index length 1 sub
+ { 1 index exch oget
+ dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
+ }
+ for pop
+ }
+ if
+
+ % Display the actual page contents.
+ 2 dict begin
+ /BXlevel 0 def
+ matrix currentmatrix /beginpage 0 # setmatrix
+ /Contents knownoget not { 0 array } if
+ dup type /arraytype ne { 1 array astore } if
+ { oforce false resolvestream pdfopdict .pdfrun } forall
+ /endpage 0 #
+ end % scratch dict
+ grestore
+ [ (end) #dsc
+ } bind def
+
+end % pdfdict
+.setglobal
diff --git a/gs/lib/pdf_sec.ps b/gs/lib/pdf_sec.ps
new file mode 100644
index 000000000..67ebbc129
--- /dev/null
+++ b/gs/lib/pdf_sec.ps
@@ -0,0 +1,58 @@
+% Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% pdf_sec.ps
+% Security hooks for PDF reader.
+
+% This file contains the procedures that have to take encryption into
+% account when reading a PDF file. There is no actual decryption code here,
+% because U.S. export control laws might prohibit making this file available
+% to anyone outside the U.S. if the code were included. Instead, you can
+% get the real version of this file from
+% http://www.ozemail.com.au/~geoffk/pdfencrypt/pdf_sec.ps
+% or, if the ~ character upsets your software,
+% http://www.ozemail.com.au/%7Egeoffk/pdfencrypt/pdf_sec.ps
+% NOTE: these URLs are referenced in the error message below.
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+pdfdict begin
+
+% Process the encryption information in the Trailer.
+/pdf_process_Encrypt
+ { (\n\n) print
+ ( **** The PDF input file uses encryption and cannot be processed.\n) print
+ ( **** Please get and install the patch available from\n) print
+ ( **** http://www.ozemail.com.au/~geoffk/pdfencrypt/pdf_sec.ps\n) print
+ (\n\n) print flush
+ /pdfopen cvx /invalidfileaccess signalerror
+ } bind def
+
+% Run the code to resolve an object reference.
+/pdf_run_resolve
+ { PDFfile resolveopdict .pdfrun
+ } bind def
+
+% Prefix a decryption filter to a stream if needed.
+% Stack: readdata? dict parms file/string filternames
+/pdf_decrypt_stream
+ {
+ } bind def
+
+end % pdfdict
+.setglobal
diff --git a/gs/lib/pfbtogs.ps b/gs/lib/pfbtogs.ps
new file mode 100644
index 000000000..e14d57f34
--- /dev/null
+++ b/gs/lib/pfbtogs.ps
@@ -0,0 +1,113 @@
+% Copyright (C) 1991, 1992, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Ghostscript.
+%
+% Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the Ghostscript General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute
+% Ghostscript, but only under the conditions described in the Ghostscript
+% General Public License. A copy of this license is supposed to have been
+% given to you along with Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+
+% pfbtogs.ps
+% Convert a PFB file to a Ghostscript font.
+
+% A .pfb file is a sequence of packets. Each packet starts with byte
+% 0x80. The second byte in the packet gives the type of packet: 1
+% means it's a packet of ascii data which should be sent out as is
+% (except for translating \r to the appropriate end-of-line
+% character(s)); 2 means it's a packet of binary data (which may be
+% translated into hex); 3 means EOF. For types 1 and 2, the type byte
+% is followed by four bytes giving the length of the packet, least
+% significant first.
+
+/envPFB 20 dict def
+envPFB begin
+
+% ------ Packet writing routines ------ %
+
+ /pfbtext % str ->
+ { { (\r) search
+ { ofile exch writestring pop
+ ofile (\n) writestring
+ }
+ { ofile exch writestring exit
+ }
+ ifelse
+ } loop
+ } def
+
+ /pfbbinary % str ->
+ { { dup length 30 gt
+ { dup 0 30 getinterval ofile exch writehexstring
+ ofile (\n) writestring
+ dup length 30 sub 30 exch getinterval
+ }
+ { ofile exch writehexstring exit
+ }
+ ifelse
+ } loop ofile (\n) writestring
+ } def
+
+ /pfbcopy % count proc ->
+ { exch % proc count
+ { dup bufsize min
+ buf 0 3 -1 roll getinterval
+ 2 index exec
+ bufsize sub dup 0 le { exit } if
+ } loop pop pop
+ } def
+
+% ------ The main program ------ %
+
+ /bufsize 30000 def
+ /buf bufsize string def
+
+ /pfbtogs % infilename outfilename pfbtogs ->
+ { /psname exch def
+ /pfbname exch def
+
+ pfbname (r) file /ifile exch def
+ /packet 6 string def
+ ifile packet readstring
+ { dup length 6 eq { 0 get 128 eq } { pop false } ifelse }
+ { pop false }
+ ifelse
+ not { (Not a valid .PFB file.\n) print flush stop } if
+
+ ifile 0 setfileposition
+ psname (w) file /ofile exch def
+
+ { ifile packet readstring
+ not { exit } if
+ (packet: ) print packet { ( ) print =only } forall (\n) print flush
+ packet 5 get 256 mul packet 4 get add
+ 256 mul packet 3 get add 256 mul packet 2 get add
+ packet 1 get 1 sub
+ { { { ifile exch readstring pop pfbtext } pfbcopy }
+ { { ifile exch readstring pop pfbbinary } pfbcopy }
+ { exit }
+ } exch get exec
+ } loop
+
+ ofile closefile
+ ifile closefile
+
+ } bind def
+
+end
+
+% Enter the main program in the current dictionary.
+/pfbtogs
+ { envPFB begin pfbtogs end
+ } bind def
+
+% If the program was invoked from the command line, run it now.
+shellarguments { pfbtogs } if
diff --git a/gs/lib/pftogsf.bat b/gs/lib/pftogsf.bat
new file mode 100755
index 000000000..1d29c1a30
--- /dev/null
+++ b/gs/lib/pftogsf.bat
@@ -0,0 +1,18 @@
+@echo off
+rem
+rem ******************************
+rem * Convert .pf? files to .gsf *
+rem ******************************
+rem
+echo (wrfont.ps) run (unprot.ps) run unprot >_temp_.ps
+echo systemdict /definefont. /definefont load put >>_temp_.ps
+echo systemdict /definefont { userdict /LFN 3 index put definefont. } bind put >>_temp_.ps
+echo ARGUMENTS 0 get (r) file .loadfont LFN findfont setfont prunefont reprot >>_temp_.ps
+echo ARGUMENTS 1 get (w) file dup writefont closefile quit >>_temp_.ps
+rem for %%f in (cyr cyri) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\pfa\%%f.pfa fonts\%%f.gsf
+rem for %%f in (ncrr ncrb ncrri ncrbi) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\pfa\%%f.pfa fonts\%%f.gsf
+rem for %%f in (bchr bchb bchri bchbi) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\pfa\%%f.pfa fonts\%%f.gsf
+rem for %%f in (putr putb putri putbi) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\pfa\%%f.pfa fonts\%%f.gsf
+rem for %%f in (n019003l n021003l u003043t u004006t) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\%%f.gsf %%f.gsf
+for %%f in (hig_____ kak_____) do gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps fonts\pfb\%%f.pfb %%f.gsf
+rem gs -q -dNODISPLAY -dWRITESYSTEMDICT -- _temp_.ps allfonts\baxter.pfb baxter.gsf
diff --git a/gs/lib/pj-gs.sh b/gs/lib/pj-gs.sh
new file mode 100755
index 000000000..fadb36a2a
--- /dev/null
+++ b/gs/lib/pj-gs.sh
@@ -0,0 +1,288 @@
+#!/bin/sh
+
+# PaintJet driver script for Ghostscript,
+# created by Philippe-Andre Prindeville <philipp@res.enst.fr>
+
+# PCL level 1 interface
+#
+#=======================================================================#
+# OPTIONS RECOGNIZED: ( all may be preceded with a "-" ) #
+# NOTE: Options marked with a "*" before their descriptions #
+# are provided for backward compatibility with the #
+# former hp2225a, hp2227a and hp3630a printer models - #
+# these models have become links to this model. Consult #
+# your printer reference manual to determine which #
+# options are valid for your particular printer. #
+# #
+# Horizontal Pitch Selection: #
+# c compressed print mode #
+# e * expanded print pitch #
+# 10 * 10 cpi (Pica print pitch) #
+# (expanded compressed on thinkjet and quietjet)#
+# 12 * 12 cpi (Elite print pitch) #
+# #
+# Print Quality Selection #
+# q | lq * near letter quality #
+# #
+# Font Selection #
+# b | bold * set font stroke weight to bold #
+# #
+# Output filtering: (Default Cooked) #
+# r | raw raw mode for plotting mode etc. #
+# #
+# Other: #
+# nb do not output banner page (to save paper) #
+# #
+# NOTE: * = NOT OFFICIAL PCL LEVEL 1 OPTIONS, USE OF #
+# THESE OPTIONS MAY OR MAY NOT PRODUCE #
+# DESIRED RESULTS. #
+#=======================================================================#
+
+PATH="/bin:/usr/bin:/usr/lib:/usr/local/bin"
+export PATH
+
+# set up redirection of stderr
+log=/usr/spool/lp/log
+exec 2>>$log
+
+# sec_class=`getconf SECURITY_CLASS`
+sec_class=
+if [ $? -ne 0 ]
+then
+ echo "getconf SECURITY_CLASS failed"
+fi
+
+# Save the arguments to the model
+printer=`basename $0`
+
+if [ "$sec_class" = "2" ] # B1 Trusted System
+then
+ reqid=$1
+ user=$2
+ dev=$3
+ title=$4
+ copies=$5
+ options=$6
+else
+ reqid=$1
+ user=$2
+ title=$3
+ copies=$4
+ options=$5
+fi
+
+
+# Definitions of functions used within this script
+do_banner()
+{
+ # Print the standard header
+ x="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ echo "$x\n$x\n$x\n$x\n"
+ banner `echo $user`
+ echo "\n"
+ user=`pwget -n $user | line | cut -d: -f5`
+ if [ -n "$user" ]
+ then
+ echo "User: $user\n"
+ else
+ echo "\n"
+ fi
+ echo "Request id: $reqid Printer: `basename $0`\n"
+ date
+ echo "\n"
+ if [ -n "$title" ]
+ then
+ banner "$title"
+ fi
+ echo "\014\r\c"
+}
+
+# Set up interface
+if [ -t 1 ]
+then
+ stty 9600 opost onlcr -parenb cs8 ixon -istrip clocal tab3 <&1 2>/dev/null
+else
+ slp -n -k 2>/dev/null
+fi
+
+# Handle disable and cancel traps.
+trap "echo 'Terminated: $reqid' >> $log; trap 15; kill -15 0; exit 0 " 15
+
+# Set up printer default modes
+echo "\033&k0S\c" # reset pitches
+echo "\033(s0B\033)s0B\c" # reset stroke weights
+echo "\033&d@\c" # disable auto-underline
+echo "\033&l6D\c" # reset to 6 lpi
+echo "\033(s0Q\c" # reset print quality
+echo "\033&v0S\c" # reset color
+echo "\033&k2G\c" # Set line termination mode
+
+
+# Determine which options have been invoked
+pitch="def"
+weight="def"
+quality="def"
+# outputmode="cooked"
+outputmode="raw"
+# banner="yes"
+banner=
+
+for i in $options
+do
+ case "$i" in
+ -c | c) # compressed print
+ pitch="c";;
+
+ -e | e) # expanded print
+ pitch="e";;
+
+ -10 | 10) # pitch set to 10 cpi
+ pitch="10";;
+
+ -12 | 12) # pitch set to 12 cpi
+ pitch="12";;
+
+ -q | q | -lq | lq) # near letter quality
+ quality=1;;
+
+ -b | b | -bold | bold) # set font weight to bold
+ weight=1;;
+
+ r | raw) # raw mode for binary output to printer
+ outputmode="raw";;
+
+ -nb | nb) # do not output banner page
+ banner="";;
+
+ esac
+done
+
+shift; shift; shift; shift; shift
+
+if [ "$sec_class" = "2" ] # B1 Trusted System
+then
+ shift
+ files="$*"
+ Nofilter= Nolabel=
+ set -- `getopt fl $options`
+ if [ $? != 0 ]
+ then
+ exit 2
+ fi
+
+ for opt in $*
+ do
+ shift
+ case $opt in
+ -f) Nofilter=$opt ;;
+ -l) Nolabel=$opt ;;
+ --) break ;;
+ esac
+ done
+
+ # Print the sensitivity label of the process
+ echo "$x\n$x\n"
+ /usr/lib/lpbanner -j $reqid -t "$title" -u $user -p PCL1 -n $printer -d $dev $files
+ echo "\n$x\n$x"
+
+else
+ # Assume that the rest of the arguments are files
+ files="$*"
+ # print the banner if nb option not specified
+ if [ -n "$banner" ]
+ then
+ do_banner
+ fi
+fi
+
+# Print the spooled files
+i=1
+while [ $i -le $copies ]
+do
+ for file in $files
+ do
+
+ # If raw mode, turn off output processing,
+ # set for no tab expansion
+ # If cooked mode, uncomment the cooked case if it is
+ # desired not to print on the page perforations
+ case "$outputmode" in
+ raw) if [ -t 1 ]
+ then
+ stty raw 9600 -opost -parenb cs8 ixon -istrip clocal tab0 <&1 2>/dev/null
+ else
+ slp -r 2>/dev/null
+ fi
+ echo "\033&k0G";; # Reset line termination mode
+ # cooked) echo "\033&l1L\r\c";;
+ esac
+
+ case "$pitch" in
+ def);;
+ c) echo "\033&k2S\r\c";;
+ e) echo "\033&k1S\r\c";;
+ 10) echo "\033&k3S\r\c";;
+ 12) echo "\033&k0S\r\c"
+ echo "\033&k4S\r\c";;
+ esac
+
+ case "$quality" in
+ def);;
+ *) echo "\033(s${quality}Q\r\c";;
+ esac
+
+ case "$weight" in
+ def) echo "\033(s0B\033)s0B\r\c";;
+ *) echo "\033(s${weight}B\r\c";;
+ esac
+
+ if [ "$sec_class" = "2" ] # B1 Trusted System
+ then
+ /usr/lib/lprcat $Nofilter $Nolabel $file PCL1 $user $dev
+ else
+ type=`file $file | sed 's/^[^:]*..//'`
+ case "$type" in
+ postscript*)
+#
+# We could do the following, but this would leave gs with a rather large
+# image in memory for (possibly) several minutes. Better to use and
+# intermediate file, since cat is "lightweight"...
+#
+# gs -q -sDEVICE=paintjet -r180 -sOutputFile=- -dDISKFONTS -dNOPAUSE - < $file 2>/tmp/sh$$
+
+ gs -q -sDEVICE=paintjet -r180 -sOutputFile=/tmp/pj$$ -dDISKFONTS -dNOPAUSE - < $file 1>2
+ cat /tmp/pj$$
+ rm /tmp/pj$$
+ needff=
+ ;;
+ *) cat "$file" 2>/tmp/sh$$
+ needff=1
+ ;;
+ esac
+
+ if [ -s /tmp/sh$$ ]
+ then
+# cat /tmp/sh$$ # output any errors
+ cat /tmp/sh$$ 1>2 # output any errors
+ fi
+ rm -f /tmp/sh$$
+ if [ $needff ]; then echo "\014\r\c"; fi
+ fi
+
+ echo "\033&k0S\r\c" # reset pitches
+ echo "\033(s0B\033)s0B\r\c" # reset stroke weights
+ echo "\033&d@\r\c" # disable auto-underline
+ echo "\033&l6D\r\c" # reset to 6 lpi
+ echo "\033(s0Q\c" # reset print quality
+ echo "\033&v0S\c" # reset color
+ done
+ i=`expr $i + 1`
+ done
+
+# Insure all buffers are flushed to printer
+if [ -t 1 ]
+then
+ stty 9600 opost onlcr -parenb cs8 ixon -istrip clocal tab3 <&1 2>/dev/null
+fi
+
+exit 0
diff --git a/gs/lib/ppath.ps b/gs/lib/ppath.ps
new file mode 100644
index 000000000..fc4ecea6b
--- /dev/null
+++ b/gs/lib/ppath.ps
@@ -0,0 +1,55 @@
+% Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Redefine pathforall for tracing.
+% Can't be used recursively.
+
+/# {( )print} def
+
+/-mat matrix def
+/-imat matrix def
+/-smat { //-mat currentmatrix pop //-imat setmatrix } bind def
+/-rmat { //-mat setmatrix } bind def
+/-pathforall /pathforall load def
+/-p2 { ( ) print exch =only ( ) print =only } bind def
+/-dp2 { 2 copy -p2 2 { exch 4096 mul dup cvi dup ( ) print =only sub dup 0 eq { pop } { (+) print =only } ifelse } repeat } bind def
+/-tp2 { //-mat itransform -p2 } bind def
+/-dict 5 dict def
+
+/pathforall
+ { -dict begin
+ /-close exch def /-curve exch def /-line exch def /-move exch def
+ end -smat -mat ==only ( setmatrix) =
+ {2 copy -tp2 ( moveto\t%)print
+ 2 copy -dp2 (\n)print
+ flush -dict /-move get -rmat exec -smat}
+ {2 copy -tp2 ( lineto\t%)print
+ 2 copy -dp2 (\n)print
+ flush -dict /-line get -rmat eyec -smat}
+ {5 index 5 index -tp2 3 index 3 index -tp2 2 copy -tp2 ( curveto\t%)print
+ 5 index 5 index -dp2 3 index 3 index -dp2 2 copy -dp2 (\n)print
+ flush -dict /-curve get -rmat exec -smat}
+ {(closepath\n)print flush -dict /-close get -rmat exec -smat}
+ -pathforall -rmat
+ }
+def
+
+% Just print the current path
+
+/printpath {
+ {pop pop} {pop pop} {pop pop pop pop pop pop} {} pathforall
+} def
diff --git a/gs/lib/prfont.ps b/gs/lib/prfont.ps
new file mode 100644
index 000000000..cbbc716e4
--- /dev/null
+++ b/gs/lib/prfont.ps
@@ -0,0 +1,153 @@
+%!
+%%Creator: Eric Gisin <egisin@waterloo.csnet>
+%%Title: Print font catalog
+% Copyright (c) 1986 Eric Gisin
+% Copyright (C) 1992 Aladdin Enterprises, Menlo Park, CA (ghost@aladdin.com)
+% Modified to print all 256 encoded characters.
+% Copyright (C) 1993 Aladdin Enterprises, Menlo Park, CA (ghost@aladdin.com)
+% Modified to print unencoded characters.
+% Copyright (C) 1994 Aladdin Enterprises, Menlo Park, CA (ghost@aladdin.com)
+% Modified to always create 256-element Encoding vectors.
+% Copyright (C) 1995 Aladdin Enterprises, Menlo Park, CA (ghost@aladdin.com)
+% Modified to print more than 128 unencoded characters.
+% Copyright (C) 1996 Aladdin Enterprises, Menlo Park, CA (ghost@aladdin.com)
+% Modified to leave a slightly wider left margin, because many H-P
+% printers can't print in the leftmost 1/4" of the page.
+% Modified to print unencoded characters in any font that has CharStrings.
+
+% Example usages at bottom of file
+
+/#copies 1 def
+/min { 2 copy gt { exch } if pop } bind def
+
+/T6 /Times-Roman findfont 6 scalefont def
+/Temp 64 string def
+/Inch {72 mul} def
+/Base 16 def % char code output base
+/TempEncoding [ 256 { /.notdef } repeat ] def
+
+% do single character of page
+% output to rectangle ll=(0,-24) ur=(36,24)
+/DoChar {
+ /C exch def
+ /S (_) dup 0 C put def
+ /N F /Encoding get C get def
+
+ % print code name, width and char name
+ /W F setfont S stringwidth pop def
+ T6 setfont
+ N /.notdef ne {0 -20 moveto N Temp cvs show} if
+ 0 -12 moveto C Base Temp cvrs show ( ) show
+ W 0.0005 add Temp cvs 0 5 getinterval show
+
+ % print char with reference lines
+ N /.notdef ne {
+ 3 0 translate
+ 0 0 moveto F24 setfont N glyphshow
+ /W S stringwidth pop def
+ 0 -6 moveto 0 24 lineto
+ W -6 moveto W 24 lineto
+ -3 0 moveto W 3 add 0 lineto
+ 0 setlinewidth stroke
+ } if
+} def
+
+% print page title
+/DoTitle {
+ /Times-Roman findfont 18 scalefont setfont
+ 36 10.5 Inch moveto FName Temp cvs show ( ) show ((24 point)) show
+} def
+
+% print one block of characters
+/DoBlock { % firstcode lastcode
+ /FirstCode 2 index def
+ 1 exch {
+ /I exch def
+ /Xn I FirstCode sub 16 mod def /Yn I FirstCode sub 16 idiv def
+ gsave
+ Xn 35 mul 24 add Yn -56 mul 9.5 Inch add translate
+ I DoChar
+ grestore
+ } for
+} def
+
+% print a line of character
+/DoLine { % firstcode lastcode
+ 1 exch { (_) dup 0 3 index put show pop } for
+} def
+
+% print font sample page
+/DoFont {
+ /FName exch def % font name
+ /F FName findfont def
+ /F24 F 24 scalefont def
+ /Line0 96 string def
+ /Line1 96 string def
+
+ % Display the first 128 encoded characters.
+
+ DoTitle (, characters 0-127) show
+ 0 127 DoBlock
+ F 10 scalefont setfont
+ 36 2.0 Inch moveto 0 63 DoLine
+ 36 1.5 Inch moveto 64 127 DoLine
+ showpage
+
+ % Display the second 128 encoded characters.
+
+ DoTitle (, characters 128-255) show
+ 128 255 DoBlock
+ F 10 scalefont setfont
+ 36 2.0 Inch moveto 128 191 DoLine
+ 36 1.5 Inch moveto 192 255 DoLine
+ showpage
+
+ F /CharStrings known
+ {
+ % Find and display the unencoded characters.
+
+ /Encoded F /Encoding get length dict def
+ F /Encoding get { true Encoded 3 1 roll put } forall
+ /Unencoded [ F /CharStrings get
+ { pop dup Encoded exch known { pop } if }
+ forall ] def
+ /Count Unencoded length def
+
+ % Print the unencoded characters in blocks of 128.
+
+ 0 128 Unencoded length 1 sub
+ { dup 128 add Unencoded length min 1 index sub
+ Unencoded 3 1 roll getinterval TempEncoding copy
+ /BlockEncoding exch def
+ /BlockCount BlockEncoding length def
+ save
+ F length dict F
+ { 1 index /FID eq { pop pop } { 2 index 3 1 roll put } ifelse }
+ forall dup /Encoding TempEncoding put
+ /* exch definefont
+ /F exch def
+ /F24 F 24 scalefont def
+
+ DoTitle (, unencoded characters) show
+ 0 BlockCount 1 sub DoBlock
+ F 10 scalefont setfont
+ 36 2.0 Inch moveto 0 BlockCount 64 min 1 sub DoLine
+ BlockCount 64 gt
+ { 36 1.5 Inch moveto 64 BlockCount 128 min 1 sub DoLine
+ }
+ if
+ showpage
+ restore
+ } for
+
+ }
+ if
+
+} def
+
+% Do font samples
+% /Times-Roman DoFont % Test (less than a minute)
+% /Hershey-Gothic-English DoFont % Test (8 minutes)
+
+% Do a complete catalog
+% FontDirectory {pop DoFont} forall % All fonts (quite a long time)
diff --git a/gs/lib/printafm b/gs/lib/printafm
new file mode 100755
index 000000000..b74e01906
--- /dev/null
+++ b/gs/lib/printafm
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Print the metrics from a font in AFM format. Usage:
+# printafm fontname
+# Output goes to stdout.
+
+exec gs -q -dNODISPLAY -- printafm.ps "$@"
diff --git a/gs/lib/printafm.ps b/gs/lib/printafm.ps
new file mode 100644
index 000000000..4743b41fc
--- /dev/null
+++ b/gs/lib/printafm.ps
@@ -0,0 +1,146 @@
+%!
+% written by James Clark <jjc@jclark.uucp>
+% print an afm file on the standard output
+% usage is `fontname printafm' eg `/Times-Roman printafm'
+
+% From the `dvitops' distribution, which included this notice:
+% dvitops is not copyrighted; you can do with it exactly as you please.
+% I would, however, ask that if you make improvements or modifications,
+% you ask me before distributing them to others.
+
+% Altered by d.love@dl.ac.uk to produce input for Rokicki's afm2tfm,
+% which groks the format of the Adobe AFMs.
+
+% Modified by L. Peter Deutsch 9/14/93:
+% uses Ghostscript's =only procedure to replace 'buf cvs print'.
+% Modified by L. Peter Deutsch 9/6/95:
+% uses Ghostscript's shellarguments facility to accept the font name
+% on the command line.
+
+/onechar 1 string def
+
+% c toupper - c
+/toupper {
+ dup dup 8#141 ge exch 8#172 le and {
+ 8#40 sub
+ } if
+} bind def
+
+% printcharmetrics -
+
+/printcharmetrics {
+ (StartCharMetrics ) print
+ currentfont /CharStrings get dup length exch /.notdef known { 1 sub } if =
+ currentfont 1000 scalefont setfont 0 0 moveto
+ /e currentfont /Encoding get def
+ 0 1 255 {
+ dup e exch get
+ dup /.notdef ne {
+ exch dup printmetric
+ } {
+ pop pop
+ } ifelse
+ } for
+ % s contains an entry for each name in the original encoding vector
+ /s 256 dict def
+ e {
+ s exch true put
+ } forall
+ % v is the new encoding vector
+ /v 256 array def
+ 0 1 255 {
+ v exch /.notdef put
+ } for
+ % fill up v with names in CharStrings
+ /i 0 def
+ currentfont /CharStrings get {
+ pop
+ i 255 le {
+ v i 3 -1 roll put
+ /i i 1 add def
+ } {
+ pop
+ } ifelse
+ } forall
+ % define a new font with v as its encoding vector
+ currentfont maxlength dict /f exch def
+ currentfont {
+ exch dup dup /FID ne exch /Encoding ne and {
+ exch f 3 1 roll put
+ } {
+ pop pop
+ } ifelse
+ } forall
+ f /Encoding v put
+ f /FontName /temp put
+ % make this new font the current font
+ /temp f definefont setfont
+ % print a entry for each character not in old vector
+ /e currentfont /Encoding get def
+ 0 1 255 {
+ dup e exch get
+ dup dup /.notdef ne exch s exch known not and {
+ exch -1 printmetric
+ } {
+ pop pop
+ } ifelse
+ } for
+ (EndCharMetrics) =
+} bind def
+
+% name actual_code normal_code printmetric -
+
+/printmetric {
+ /saved save def
+ (C ) print =only
+ ( ; WX ) print
+ onechar 0 3 -1 roll put
+ onechar stringwidth pop round cvi =only
+ ( ; N ) print =only
+ ( ; B ) print
+ onechar false charpath flattenpath mark pathbbox counttomark {
+ counttomark -1 roll
+ round cvi =only
+ ( ) print
+ } repeat pop
+ (;) =
+ saved restore
+} bind def
+
+% fontname printafm -
+
+/printafm {
+ findfont gsave setfont
+ (StartFontMetrics 2.0) =
+ (FontName ) print currentfont /FontName get =
+
+ % Print the FontInfo
+
+ currentfont /FontInfo get {
+ exch
+ =string cvs dup dup 0 get 0 exch toupper put print
+ ( ) print =
+ } forall
+
+ % Print the FontBBox
+
+ (FontBBox) print
+ currentfont /FontBBox get {
+ ( ) print round cvi =only
+ } forall
+ (\n) print
+
+ printcharmetrics
+ (EndFontMetrics) =
+ grestore
+} bind def
+
+% Check for command line arguments.
+[ shellarguments
+ { ] dup length 1 eq
+ { 0 get printafm }
+ { (Usage: printafm fontname\n) print flush }
+ ifelse
+ }
+ { pop }
+ifelse
diff --git a/gs/lib/ps2ai.ps b/gs/lib/ps2ai.ps
new file mode 100644
index 000000000..835f45afa
--- /dev/null
+++ b/gs/lib/ps2ai.ps
@@ -0,0 +1,542 @@
+%!
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Ghostscript.
+%
+% Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the Ghostscript General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute
+% Ghostscript, but only under the conditions described in the Ghostscript
+% General Public License. A copy of this license is supposed to have been
+% given to you along with Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+%
+% ps2ai.ps - a postscript to editable adobe illustrator file filter
+%
+/vers {2.13} def % April 25, 1994
+%
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+%
+% needs a postscript level 2 interpreter, like gnu ghostscript, to work
+%
+% Usage: gs -q -dNODISPLAY ps2ai.ps file.ps > file.aips
+% or (see below)
+% gs -q -dNODISPLAY ps2ai.ps file.ps
+% or
+% cat ps2ai.ps file.ps | lpr (then look in log file)
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+% Options
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+% Output Options: directly to a file or standard out
+%
+/jout false def % true=file false=stdout (default=false)
+/joutput (ps2ai.out.aips) def % Name of Output file
+%
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+%
+% Other Options
+%
+/jtxt3 true def % output text in AI3 form (false=ai88)
+ % for coreldraw/photoshop readable output
+/joutln false def % use font outline instead of font
+/jerr false def % use error handling (ie die gracefully)
+/jbiterr false def % attempt to handle bitmap fonts (kludge)
+/jMacGS false def % true if using MacGS (not fully implemented yet)
+/jMacfix true def % convert filled boxes to lines (only usefull with
+ % laserwriter 8 postscript input)
+%
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+% No options below here
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+%
+% - Notes -
+% ai uses cmykcolor, so level 1 interpreters don't work
+% ai doesn't use image/imagemask - so bitmaps don't work correctly
+% the output file has a header so it is viewable/printable/reconvertable
+%
+% Comments, suggestions, bug-fixes, etc send to:
+%
+% Jason Olszewski (olszewsk@splash.princeton.edu)
+%
+% anonymous ftp: toby.princeton.edu /pub/olszewsk/ps2ai.ps
+% URL ftp://toby.princeton.edu/pub/olszewsk
+%
+% - Fix History -
+% 2.13 check for bitmap fonts, work better with TeX,WinPS,etc
+% 2.12 fixed initclip to US letter size page
+% 2.11 added header support for *u/*U compound paths
+% 2.1 option of font outline instead of text(gwhite@trevnx.bio.dfo.ca)
+% 2.0 major change to complex path handling
+% 1.9 fixed text leaking ascii (,),\
+% 1.85 added default font to handle no setfont (Courier)
+% 1.84 added even-odd fill/clip (D)
+% 1.83 undefined PPD PageSize printer specific info
+% 1.82 added kludge to save clipping status through a restore
+% 1.81 added custom color/gray support to header (x/X, g/G)
+% 1.8 added newpath if clippath is not consumed correctly(amiga)
+% 1.79 eliminated scientific notation of numbers less than 0.0001
+% 1.78 fixed transposed h & H
+% 1.77 made laserwriter 8 fixes optional
+% 1.76 added margin fix for unix AI (brown@wi.extrel.com)
+% 1.75 added kludge to handle bitmap font errors (TeX, Windows.ps)
+% 1.74 made grestore a little smarter
+% 1.73 included header handle encoded fontname (/_fontname)
+% 1.72 fixed problem with restore/clip info - (not enough Qs problem)
+% 1.71 filter font names to remove previous encoding (|,_,etc)
+% 1.7 change text format to AI3, works better with PS & CD
+% 1.67 deal with weird makefonts
+% 1.66 handle to many bad stroke/fills (s s s w/o paths)
+% 1.65 more useable with non-gs interpreters (defaultmatrix fix)
+% 1.64 fixed "smart grestore" repeat bug
+% 1.63 fixed ashow/awidthshow bug
+% 1.62 check if cmykcolor is understood otherwise rgb
+% 1.61 made grestore smarter (only print if different)
+% 1.6 add better compatibility to CorelDraw and PhotoShop
+% 1.53 make it more gs-backward compatible (clarke@lsl.co.uk)
+% 1.52 handle clipping paths a little better (Posted)
+% 1.51 improve mac lw8 output (lines instead of filled boxes)
+% 1.5 handle some level 2 stuff (mac lw8)
+% 1.4 fixed scaling of linewidth and dash
+% 1.31 made trailer more AI88 friendly
+% 1.3 add ablity to output to file directly
+% 1.21 print matrix cleaner
+% 1.2 fix rotated fonts, thanks to G.Cameron (g.cameron@biomed.abdn.ac.uk)
+% 1.1 fix stroke/fill color difference (k vs K)
+% 1.0 posted to comp.lang.postscript
+%
+% - To Do List -
+% find real %%BoundingBox: llx lly urx ury
+% make MacGS friendly (line-endings)
+% handle eps w/o showpage:(append to end)
+% write out image data to external file
+%
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+% Nothing of Interest below here
+%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+matrix identmatrix setmatrix % make ctm [1 0 0 1 0 0]
+/oldgsave {} def /oldgrestore {} def
+/initgraphics {} def /initmatrix {} def
+% undefine PPD PageSizes to be more printer independant
+/letter {} def /legal {} def /a4 {} def /b5 {} def /lettersmall {} def
+/setpagedevice { pop } def % for level 2 PPD PageSizes
+/Courier findfont 12 scalefont setfont % handle no setfont
+/initclip {0 0 moveto 0 792 lineto 612 792 lineto 612 0 lineto closepath
+ clip newpath } def
+/xdef {exch def} def
+/trx {transform exch} def
+/cbdef {cvx bind def} def
+/jltz {dup abs 0.0001 lt {pop 0} if} def % get rid of scientific notation bug
+/clstate false def % closepath state
+/dpth false def % destroy path (ie newpath)
+/fclp false def % first paint after clip
+/kscl {1.0} def % default current scale X-factor
+/gcnt {1} def % graphics state counter
+/spth {1} def % multiple paths on stack
+/jeol (\n) def % default end-of-line
+/jnump {0} def % number of paths on stack
+/jx {0} def /jy {0} def /j_ax {0} def
+/j3ftxt true def
+/clarry 10 array def
+0 1 9 {clarry exch false put} for % initilize no clipping path
+%
+% handle cmyk color on level 1 interpreters
+/setcmykcolor where {pop}
+ {/setcmykcolor {
+ /blk exch def /yel exch def /mag exch def /cyan exch def
+ /ccomp {add dup 1 gt {pop 1} if} def
+ /red {1 cyan blk ccomp sub} def
+ /green {1 mag blk ccomp sub} def
+ /blue {1 yel blk ccomp sub} def
+ red green blue setrgbcolor
+ } def
+} ifelse
+/currentcmykcolor where {pop}
+ {/currentcmykcolor {
+ currentrgbcolor /bval xdef /gval xdef /rval xdef
+ /rawC 1 rval sub def /rawM 1 gval sub def /rawY 1 bval sub def
+ rawC rawM ge { rawY rawM ge { /blk rawM def} if } if
+ rawC rawY ge { rawM rawY ge { /blk rawY def} if } if
+ rawY rawC ge { rawM rawC ge { /blk rawC def} if } if
+ rawY rawC eq { rawM rawC eq { /blk rawC def} if } if
+ /cyan rawC blk sub def
+ /mag rawM blk sub def
+ /yel rawY blk sub def
+ /blk blk def
+ cyan mag yel blk
+ } def
+} ifelse
+% If using Mac Ghostscript
+jMacGS {
+% /jeol {(\r) jp} def
+ /jout true def
+ (%%Note: Loading ps2ai.ps\n) print
+ } if
+/jstr 40 string def
+jout {joutput (w) file /joutput xdef} if
+%
+% Output
+%
+jout {/jp { joutput exch writestring } bind def }{/jp {print}bind def} ifelse
+/jpnum {jltz ( ) jp =string cvs jp } bind def
+/jpmat { dup /jarry exch def length 1 sub /j_num exch def
+ (\[) jp 0 1 j_num {jarry exch get jpnum} for (\]) jp } def
+%
+% Stack to Paths converters
+%
+/ckpnt { % check which paint and clipping to use
+ dpth { % if there are multiple paths on the stack
+ clarry gcnt get fclp and {clstate {(h W\n) jp }{(H W\n) jp } ifelse} if
+ spth 0 eq {clstate {(n\n) jp }{(N\n) jp } ifelse} if
+ spth 1 eq {clstate {(s\n) jp }{(S\n) jp } ifelse} if
+ spth 2 eq {clstate {(f\n) jp }{(F\n) jp } ifelse} if
+ } if
+} def
+/jpm {
+ ckpnt
+ /dpth true def
+ transform 2 copy /yst xdef /xst xdef exch jpnum jpnum ( m\n) jp } bind def
+/jpl { trx jpnum jpnum ( l\n) jp } bind def
+/jpc { 6 4 roll trx jpnum jpnum 4 2 roll trx jpnum jpnum trx
+ jpnum jpnum ( c\n) jp } bind def
+/jpp {xst jpnum yst jpnum ( l\n) jp /clstate true def} def
+/cntpaths { % count paths on stack
+ oldgsave
+ {pop pop /jnump jnump 1 add def} {pop pop} {6 {pop} repeat}{} pathforall
+ oldgrestore
+} def
+/ppforall {
+ cntpaths % find out how many paths are on the stack
+ jnump 1 gt { (*u\n) jp } if
+ {jpm}{jpl}{jpc}{jpp} pathforall
+ ckpnt
+ jnump 1 gt { (*U\n) jp } if
+ /jnump 0 def /clstate false def /dpth false def /fclp false def
+ oldnewpath
+} bind def
+%
+% Painting Operators
+%
+/oldnewpath [/newpath load] cbdef
+/newpath { (\n) jp /spth 0 def ppforall} def
+/stroke { (\n) jp /spth 1 def ppforall } def
+/fill {(\n) jp /spth 2 def ppforall } def
+/eofill {(1 D\n) jp fill (0 D\n) jp} def
+/clip {clarry gcnt get {(Q\nq\n) jp}{(q\n) jp} ifelse
+ /fclp true def clarry gcnt true put} def
+/eoclip {(1 D\n) jp clip (0 D\n) jp} def
+%
+% Text Operators
+%
+/oldshow [/show load] cbdef
+/curpt {stringwidth pop jx add jy} def
+/jNN {dup 0 eq {pop oldgsave currentfont /FontMatrix get setmatrix kscl
+ oldgrestore} if
+} def
+/curftmatrix {
+ currentfont /FontMatrix get dup 0 get jNN abs /norm exch def
+ dup 0 get norm div exch dup
+ 1 get norm div exch dup 2 get norm div exch dup 3 get norm div exch dup
+ 4 get exch 5 get 6 array astore matrix currentmatrix matrix concatmatrix
+} def
+% AI does not support negitive font sizes
+/curftsize {currentfont /FontMatrix get 0 get jNN abs 1000 mul} def
+/hstr (X) def
+/vbar (|) 0 get def /undsc (_) 0 get def
+/ftnamefix { % handle font names with |,_ (previously encoded)
+jstr cvs
+{ %forall
+ dup vbar eq {pop}{ %ifelse
+ dup undsc eq {pop}{ %ifelse
+ hstr exch 0 exch put hstr jp
+ } ifelse
+ } ifelse
+ } forall flush
+} bind def
+%/curftname {currentfont /FontName get ftnamefix}def
+/curftname { currentfont /FontName known {currentfont /FontName get}
+ { (Times-Roman)} ifelse ftnamefix } def
+/lftpar (\() 0 get def
+/rhtpar (\)) 0 get def
+/bckslsh (\\) 0 get def
+/handft { % handle strings with (,),\
+ (\() jp
+ { %forall
+ dup lftpar eq { (\\\() jp }{ %ifelse
+ dup rhtpar eq { (\\\)) jp }{ %ifelse
+ dup bckslsh eq { (\\\\) jp }{ %ifelse
+ hstr exch 0 exch put hstr jp
+ } ifelse
+ } ifelse
+ } ifelse
+ } forall (\)) jp flush
+} bind def
+% AI 3 text format pieces
+jtxt3 {
+/j3txt { j3ftxt {(0 Ts 100 Tz 0 Tt 0 TA 0 0 5 TC 100 100 200 TW 0 0 0 Ti\n) jp
+ (0 Ta 0 Tq 0 0 TI 0 Tc 0 Tw\n) jp} if } def
+/show {oldgsave (0 To\n) jp
+ currentpoint 2 copy /jy exch def /jx exch def translate
+ curftmatrix /jitm exch def
+ 0 1 5 {jitm exch get jpnum} for ( 0 Tp\n) jp (TP\n) jp
+ (0 Tr\n) jp (\/_) jp curftname curftsize jpnum ( Tf\n) jp
+ (0) jp j_ax curftsize div 100 mul jpnum ( 100 TC\n) jp % percent(?)
+ dup curpt moveto mark exch handft ( Tx\n) jp (TO\n) jp /j3ftxt false def
+ cleartomark currentpoint oldgrestore moveto
+} def
+/ashow {exch pop exch /j_ax exch def show /j_ax {0} def } def
+}
+ {
+/show {oldgsave (u\n) jp currentpoint 2 copy /jy exch def /jx exch def translate
+ (\/) jp curftname jstr cvs jp
+ curftsize dup jpnum jpnum ( 0 0 z\n) jp
+ curftmatrix jpmat ( e\n) jp
+ dup curpt moveto mark exch handft ( t T U\n) jp
+ cleartomark currentpoint oldgrestore moveto} def
+/ashow {oldgsave (u\n) jp currentpoint translate (\/) jp curftname jstr cvs jp
+ curftsize dup jpnum jpnum exch kscl mul jpnum ( 0 z\n) jp
+ curftmatrix jpmat ( e\n) jp dup curpt moveto mark exch handft
+ ( t T U\n) jp cleartomark currentpoint oldgrestore moveto} def
+} ifelse
+/widthshow { show pop pop pop} def
+/awidthshow {ashow pop pop pop} def
+/kshow {show pop} def
+%/show {true charpath fill} bind def % get outline of charactor
+joutln {/show { true charpath currentpoint
+ /jy exch def /jx exch def fill jx jy moveto} bind def} if
+%/show {oldshow} def % do nothing different
+%
+% Color Operators
+%
+/oldsetcmykcolor [/setcmykcolor load] cbdef
+/setcmykcolor {oldsetcmykcolor
+currentcmykcolor 4 -1 roll jpnum 3 -1 roll jpnum 2 -1 roll jpnum jpnum ( k\n) jp
+currentcmykcolor 4 -1 roll jpnum 3 -1 roll jpnum 2 -1 roll jpnum jpnum ( K\n) jp
+ } def
+/oldsetgray [/setgray load] cbdef
+/setgray {0 0 0 4 -1 roll 1 exch sub setcmykcolor} def
+/oldsethsbcolor [/sethsbcolor load] cbdef
+/sethsbcolor {oldsethsbcolor currentcmykcolor setcmykcolor} def
+/oldsetrgbcolor [/setrgbcolor load] cbdef
+/setrgbcolor {oldsetrgbcolor currentrgbcolor /bval xdef /gval xdef /rval xdef
+ /rawC 1 rval sub def /rawM 1 gval sub def /rawY 1 bval sub def
+ rawC rawM ge { rawY rawM ge { /blk rawM def} if } if
+ rawC rawY ge { rawM rawY ge { /blk rawY def} if } if
+ rawY rawC ge { rawM rawC ge { /blk rawC def} if } if
+ rawY rawC eq { rawM rawC eq { /blk rawC def} if } if
+ /cyan rawC blk sub def
+ /mag rawM blk sub def
+ /yel rawY blk sub def
+ /blk blk def
+ cyan mag yel blk setcmykcolor } def
+%
+% State Operators
+%
+/oldsetlinewidth [/setlinewidth load] cbdef
+/setlinewidth {kscl abs mul jltz oldsetlinewidth
+ currentlinewidth jpnum ( w\n) jp } def
+/oldsetlinecap [/setlinecap load] cbdef
+/setlinecap {dup oldsetlinecap jpnum ( J\n) jp} def
+/oldsetlinejoin [/setlinejoin load] cbdef
+/setlinejoin {dup oldsetlinejoin jpnum ( j\n) jp} def
+/oldsetmiterlimit [/setmiterlimit load] cbdef
+/setmiterlimit {dup oldsetmiterlimit jpnum ( M\n) jp}def
+/oldsetdash [/setdash load] cbdef
+/setdash {exch [ exch {kscl abs mul} forall ] exch kscl abs mul oldsetdash
+ currentdash exch jpmat jpnum ( d\n) jp } def
+/oldsetflat [/setflat load] cbdef
+/setflat {dup oldsetflat jpnum ( i\n) jp } def
+%
+% More State Operators
+%
+/kscl { % use just the x scale factor
+ oldgsave
+ matrix currentmatrix /jctm exch def
+ jctm 4 0 put jctm 5 0 put jctm setmatrix
+ 1 0 moveto currentpoint transform
+ dup mul exch dup mul add sqrt 10000 mul round 10000 div
+ oldgrestore
+} def
+/currentstate {currentcmykcolor setcmykcolor
+ currentflat jpnum ( i) jp currentlinecap jpnum ( J) jp
+ currentlinejoin jpnum ( j) jp currentlinewidth jpnum ( w) jp
+ currentmiterlimit jpnum ( M ) jp currentdash exch jpmat jpnum ( d\n) jp
+} def
+/jdifG {
+ currentcmykcolor /jok xdef /joy xdef /jom xdef /joc xdef
+ currentflat /jof xdef currentlinecap /jolc xdef currentlinejoin /jolj xdef
+ currentlinewidth /jolw xdef currentmiterlimit /joml xdef
+ currentdash /jood xdef /joad xdef
+ oldgrestore
+ currentcmykcolor /jnk xdef /jny xdef /jnm xdef /jnc xdef
+ currentflat /jnf xdef currentlinecap /jnlc xdef currentlinejoin /jnlj xdef
+ currentlinewidth /jnlw xdef currentmiterlimit /jnml xdef
+ currentdash /jnod xdef /jnad xdef
+ % compare old gstate to new gstate
+ joc jnc ne jom jnm ne joy jny ne jok jnk ne
+ jof jnf ne jolc jnlc ne jolj jnlj ne jolw jnlw ne joml jnml ne
+ false joad {true exit} forall {pop pop true}{false} ifelse
+ false jnad {true exit} forall {pop pop true}{false} ifelse ne
+ jood jnod ne 10 {or} repeat {currentstate} if
+} def
+/oldgsave [/gsave load] cbdef
+/gsave {oldgsave /gcnt gcnt 1 add def } def % clarry gcnt false put} def
+% (%%Note:gsave ) jp gcnt jpnum (\n) jp} def
+/oldgrestore [/grestore load] cbdef
+/grestore {dpth {newpath} if clarry gcnt get {(Q\n) jp clarry gcnt false put} if
+ jdifG /gcnt gcnt 1 sub def } def
+% oldgrestore currentstate } def
+% (%%Note:grestore ) jp gcnt 1 add jpnum (\n) jp} def
+/oldrestore [/restore load] cbdef
+% a kludgy way of saving the clipping path status information
+/restore {clarry aload pop 11 -1 roll oldrestore clarry astore pop} def
+/showpage { 0 1 9 {clarry exch get {(Q\n) jp} if } for
+ (%%Note: If Error, make sure there are matched pairs of 'q's and 'Q's\n) jp
+ (%%Note: in the file. Add 'Q's before '%%Trailer' until equal\n) jp
+ (%%Trailer\n) jp
+ jtxt3 {(Adobe_IllustratorA_AI3 /terminate get exec\n) jp
+ (Adobe_typography_AI3 /terminate get exec\n) jp
+ (Adobe_customcolor /terminate get exec\n) jp
+ (Adobe_cshow /terminate get exec\n) jp
+ (Adobe_cmykcolor /terminate get exec\n) jp
+ (Adobe_packedarray /terminate get exec\n) jp
+}{
+ (Adobe_Illustrator881 /terminate get exec\n) jp
+ (Adobe_customcolor /terminate get exec\n) jp
+ (Adobe_cshow /terminate get exec\n) jp
+ (Adobe_cmykcolor /terminate get exec\n) jp
+ (Adobe_packedarray /terminate get exec\n) jp
+ } ifelse
+( showpage\n%EOF\n%%EndDocument\n) jp
+ jout {joutput closefile} if jMacGS not {quit} if /j3ftxt true def } def
+%
+% Error handling
+%
+errordict begin
+% Attempt to handle the error caused by bitmap fonts (TeX,Windows.ps,etc)
+% this is a big-time kludge
+jbiterr {
+ /undefined {pop pop (Times-Roman)} def
+ /typecheck {pop pop} def
+} if
+jerr {
+ /handleerror {
+ (%%Note: ps2ai error, aborting rest of conversion\n) jp showpage
+ } def
+} if
+end
+%
+% Mac LW 8 improvements
+%
+/jmacimp { % stroked line instead of thin filled boxes
+ /@a { 3 -1 roll 2 div dup 3 -1 roll add exch 3 -1 roll add exch moveto
+ 3 -1 roll 2 div dup 3 -1 roll add exch 3 -1 roll exch sub exch lineto
+ abs setlinewidth stroke pop pop} def
+ /@b { 3 -1 roll 2 div dup 3 -1 roll add exch 3 -1 roll add exch moveto
+ pop
+ 3 -1 roll 2 div dup 3 -1 roll add exch 3 -1 roll add exch lineto
+ abs setlinewidth stroke} def
+ /endp {showpage pm restore} def % because the restore stops clean up
+} def
+%
+% Handle (some) PS Level 2
+%
+/rectstroke { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto
+ closepath stroke} def
+/rectfill { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto
+ fill } def
+/rectclip { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto
+ closepath clip newpath jMacfix {jmacimp} if } def
+%
+% Add a header prolog to the output file so it is still view/print-able
+%
+(%!PS-Adobe-2.0 EPSF-1.2\n%%BoundingBox: 0 0 612 792\n) jp
+(%%Title: Adobe Illustator 3 Editable Document\n) jp
+(%%Creator: ps2ai.ps vers.) jp vers jpnum ( \(C\) 1993-94 Jason Olszewski\n) jp
+(%%TemplateBox: 0 0 612 792\n) jp
+jtxt3 {(%%AI3_Margin:0 0 0 0\n) jp } if
+(%%EndComments\n) jp
+(%%BeginProlog\n) jp
+(/m {moveto} def /l {lineto} def /c {curveto} def\n) jp
+(/S {stroke} def /F {fill} def\n) jp
+(/s {closepath S} def /f {closepath F} def\n) jp
+(/q {gsave} def /Q {grestore} def /W {clip} def /k {setcmykcolor} def\n) jp
+(/i {setflat} def /J {setlinecap} def /j {setlinejoin} def\n) jp
+(/w {setlinewidth} def /M {setmiterlimit} def /d {setdash} def\n) jp
+(/u {gsave} def /U {grestore} def /K {k} def\n) jp
+(/N {newpath} def /n {closepath N} def\n) jp
+(/g {setgray} def /G {g} def\n) jp
+(/x {pop pop k} def /X {x} def\n) jp
+(/H {} def /h {H closepath} def /D {pop} def\n) jp
+(/*u { /N {/spth 0 def}def /S{/spth 1 def}def /F {/spth 2 def} def} def\n) jp
+(/*U { spth 0 eq {newpath} if spth 1 eq {stroke} if spth 2 eq {fill} if\n) jp
+( /N {newpath} def /S {stroke} def /F {fill} def } def\n) jp
+%(\n) jp
+jtxt3 {
+ (/TC {pop pop pop} def /Tr {pop} def\n) jp
+ (/To {pop gsave} def /TO {grestore} def\n) jp
+ (/Tp {pop matrix astore concat} def /TP {0 0 moveto} def\n) jp
+ (/a_str 40 string def /cnt 0 def /h_str (X) def /undsc (_) 0 get def\n) jp
+ (/fntfix {a_str cvs dup length 1 sub /f_str exch string def\n) jp
+ ( {dup undsc eq {pop}{f_str cnt 3 -1 roll put /cnt cnt 1 add def\n) jp
+ ( } ifelse } forall flush /cnt 0 def f_str cvn } bind def\n) jp
+
+ (/Tf {exch fntfix findfont exch scalefont setfont} def /Tx {show} def\n) jp
+}{
+ (/z {pop pop pop exch findfont exch scalefont setfont} def\n) jp
+ (/e {concat 0 0 m} def /t {show} def /T {} def\n) jp
+} ifelse
+(\n) jp
+jtxt3 {
+ (userdict /Adobe_packedarray 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_cmykcolor 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_cshow 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_customcolor 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_typography_AI3 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_IllustratorA_AI3 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+}{
+ (userdict /Adobe_packedarray 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_cmykcolor 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_cshow 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_customcolor 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+ (userdict /Adobe_Illustrator881 2 dict dup begin put\n) jp
+ (/initialize {} def /terminate {} def\n) jp
+} ifelse
+(%%EndProlog\n) jp
+(%%BeginSetup\n) jp
+jtxt3 {
+ (Adobe_packedarray /initialize get exec\n) jp
+ (Adobe_cmykcolor /initialize get exec\n) jp
+ (Adobe_cshow /initialize get exec\n) jp
+ (Adobe_customcolor /initialize get exec\n) jp
+ (Adobe_typography_AI3 /initialize get exec\n) jp
+ (Adobe_IllustratorA_AI3 /initialize get exec\n) jp
+}{
+ (Adobe_packedarray /initialize get exec\n) jp
+ (Adobe_cmykcolor /initialize get exec\n) jp
+ (Adobe_cshow /initialize get exec\n) jp
+ (Adobe_customcolor /initialize get exec\n) jp
+ (Adobe_Illustrator881 /initialize get exec\n) jp
+} ifelse
+(%%EndSetup\n) jp
+0 0 0 1 oldsetcmykcolor
+currentstate
+jout {(%%Note: Load Postscript file to be converted now\n) print} if
+
diff --git a/gs/lib/ps2ascii b/gs/lib/ps2ascii
new file mode 100755
index 000000000..aa3f87978
--- /dev/null
+++ b/gs/lib/ps2ascii
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Extract ASCII text from a PostScript file. Usage:
+# ps2ascii [infile.ps [outfile.txt]]
+# If outfile is omitted, output goes to stdout.
+# If both infile and outfile are omitted, ps2ascii acts as a filter,
+# reading from stdin and writing on stdout.
+
+trap "rm -f _temp_.err _temp_.out" 0 1 2 15
+
+if ( test $# -eq 0 ) then
+ gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE -c save -f ps2ascii.ps - -c quit
+elif ( test $# -eq 1 ) then
+ gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE -c save -f ps2ascii.ps $1 -c quit
+else
+ gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE -c save -f ps2ascii.ps $1 -c quit >$2
+fi
diff --git a/gs/lib/ps2ascii.bat b/gs/lib/ps2ascii.bat
new file mode 100755
index 000000000..c00398959
--- /dev/null
+++ b/gs/lib/ps2ascii.bat
@@ -0,0 +1,12 @@
+@echo off
+if '%1'=='' goto a0
+if '%2'=='' goto a1
+gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE ps2ascii.ps %1 -c quit >%2
+goto x
+:a0
+gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE ps2ascii.ps - -c quit
+goto x
+:a1
+gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE ps2ascii.ps %1 -c quit
+goto x
+:x
diff --git a/gs/lib/ps2ascii.ps b/gs/lib/ps2ascii.ps
new file mode 100644
index 000000000..e014bb8e8
--- /dev/null
+++ b/gs/lib/ps2ascii.ps
@@ -0,0 +1,1310 @@
+% Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Extract the ASCII text from a PostScript file. Nothing is displayed.
+% Instead, ASCII information is written to stdout. The idea is similar to
+% Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
+
+% If SIMPLE is defined, just the text is written, with a guess at line
+% breaks and word spacing. If SIMPLE is not defined, lines are written
+% to stdout as follows:
+%
+% F <height> <width> (<fontname>)
+% Indicate the font height and the width of a space.
+%
+% P
+% Indicate the end of the page.
+%
+% S <x> <y> (<string>) <width>
+% Display a string.
+%
+% <width> and <height> are integer dimensions in units of 1/720".
+% <x> and <y> are integer coordinates, in units of 1/720", with the origin
+% at the lower left.
+% <string> and <fontname> are strings represented with the standard
+% PostScript escape conventions.
+
+% If COMPLEX is defined, the following additional types of lines are
+% written to stdout.
+%
+% C <r> <g> <b>
+% Indicate the current color.
+%
+% I <x> <y> <width> <height>
+% Note the presence of an image.
+%
+% R <x> <y> <width> <height>
+% Fill a rectangle.
+%
+% <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
+%
+% Note that future versions of this program (in COMPLEX mode) may add
+% other output elements, so programs parsing the output should be
+% prepared to ignore elements that they do not recognize.
+
+% Note that this code will only work in all cases if systemdict is writable
+% and if `binding' the definitions of operators defined as procedures
+% is deferred. For this reason, it is normally invoked with
+% gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT ps2ascii.ps
+
+% Thanks to:
+% J Greely <jgreely@cis.ohio-state.edu> for improvements to this code;
+% Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements;
+% David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below.
+
+%%* Modifications to ps2ascii.ps by David M. Jones
+%%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996
+
+%%* Modifications:
+%%*
+%%* (a) added code to give better support for dvips files by providing
+%%* FontBBox's, FontName's and Encoding vectors for downloaded
+%%* bitmap fonts. This is done by using dvips's start-hook to
+%%* overwrite the df-tail and D procedures that dvips uses to
+%%* define its Type 3 bitmap fonts. Thus, this change should
+%%* provide better support for dvips-generated PS files without
+%%* affecting the handling of other documents.
+%%*
+%%* (b) Fixed two bugs that could potentially affect any PS file, not
+%%* just those created by dvips: (1) added missing "get" operator
+%%* in .show.write and (2) fixed bug that caused a hyphen at the
+%%* end of a line to be replaced by a space rather than begin
+%%* deleted. Note that the first bug was a source of stack
+%%* leakage, causing ps2ascii to run out of operand stack space
+%%* occasionally.
+%%*
+%%* Search for "%%* BF" to find these modifications.
+%%*
+%%* (c) Improved the heuristic for determining whether a line break
+%%* has occured and whether a line break represents a paragraph
+%%* break. Previously, any change in the vertical position caused
+%%* a line break; now a line break is only registered if the
+%%* change is larger than the height of the current font. This
+%%* means that superscripts, subscripts, and such things as
+%%* shifted accents generated by TeX won't cause line breaks.
+%%* Paragraph-recognition is now done by comparing the indentation
+%%* of the new line to the indentation of the previous line and by
+%%* comparing the vertical distance between the new line and the
+%%* previous line to the vertical distance between the previous
+%%* line and its predecessor.
+%%*
+%%* (d) Added a hook for renaming the files where stdout and stderr
+%%* go.
+%%*
+%%* In general, my additions or changes to the code are described in
+%%* comments beginning with "%%*". However, there are numerous other
+%%* places where I have either re-formatted code or added comments to
+%%* the code while I was trying to understand it. These are usually
+%%* not specially marked.
+%%*
+
+/QUIET true def
+systemdict wcheck { systemdict } { userdict } ifelse begin
+/.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
+/COMPLEX dup where { pop true } { false } ifelse def
+/SIMPLE dup where { pop true } { false } ifelse def
+/setglobal where
+ { pop currentglobal /setglobal load true setglobal }
+ { { } }
+ifelse
+
+% Define a way to store and retrieve integers that survives save/restore.
+/.i.string0 (0 ) def
+/.i.string .i.string0 length string def
+/.iget { cvi } bind def
+/.iput { exch //.i.string exch copy cvs pop } bind def
+/.inew { //.i.string0 dup length string copy } bind def
+
+% We only want to redefine operators if they are defined already.
+
+/codef { 1 index where { pop def } { pop pop } ifelse } def
+
+% Redefine the end-of-page operators.
+
+/erasepage { } codef
+/copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
+/showpage { copypage erasepage initgraphics } codef
+
+% Redefine the fill operators to detect rectangles.
+
+/.orderrect % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
+ { % Ensure llx <= urx, lly <= ury.
+ 1 index 4 index lt { 4 2 roll } if
+ dup 3 index lt { 3 1 roll exch } if
+ exch 3 index sub exch 2 index sub
+ } odef
+/.fillcomplex
+ { % Do a first pass to see if the path is all rectangles in
+ % the output coordinate system. We don't worry about overlapping
+ % rectangles that might be partially not filled.
+ % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
+ mark true mark
+ % Add a final moveto so we pick up any trailing unclosed subpath.
+ 0 0 itransform moveto
+ { .coord counttomark 2 gt
+ { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop } ifelse }
+ if
+ }
+ { .coord }
+ { cleartomark not mark exit }
+ { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
+ pathforall cleartomark
+ { .showcolor counttomark 4 idiv
+ { counttomark -4 roll .orderrect
+ (R ) //print .show==4
+ }
+ repeat pop
+ }
+ { cleartomark
+ }
+ ifelse
+ } odef
+/.fillcheckrect
+ { % Check whether the current subpath is a rectangle.
+ % If it is, add it to the list of rectangles being accumulated;
+ % if not exit the .fillcomplex loop.
+ % The subpath has not been closed.
+ % Stack: as in .fillcomplex, + newx newy
+ counttomark 10 eq { 9 index 9 index 4 2 roll } if
+ counttomark 12 ne { cleartomark not mark exit } if
+ 12 2 roll
+ % Check for the two possible forms of rectangles:
+ % x0 y0 x0 y1 x1 y1 x1 y0 x0 y0
+ % x0 y0 x1 y0 x1 y1 x0 y1 x0 y0
+ 9 index 2 index eq 9 index 2 index eq and
+ 10 index 9 index eq
+ { % Check for first form.
+ 7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
+ }
+ { % Check for second form.
+ 9 index 8 index eq and
+ 8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
+ }
+ ifelse not { cleartomark not mark exit } if
+ % We have a rectangle.
+ pop pop pop pop 4 2 roll pop pop 8 4 roll
+ } odef
+/eofill { COMPLEX { .fillcomplex } if newpath } codef
+/fill { COMPLEX { .fillcomplex } if newpath } codef
+/rectfill { gsave newpath .rectappend fill grestore } codef
+/ueofill { gsave newpath uappend eofill grestore } codef
+/ufill { gsave newpath uappend fill grestore } codef
+
+% Redefine the stroke operators to detect rectangles.
+
+/rectstroke
+ { gsave newpath
+ dup type dup /arraytype eq exch /packedarraytype eq or
+ { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
+ { .rectappend }
+ ifelse stroke grestore
+ } codef
+/.strokeline % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
+ % Note: fromx and fromy are in output coordinates;
+ % tox and toy are in user coordinates.
+ { .coord 2 copy 6 2 roll .orderrect
+ % Add in the line width. Assume square or round caps.
+ currentlinewidth 2 div dup .dcoord add abs 1 max 5 1 roll
+ 4 index add 4 1 roll 4 index add 4 1 roll
+ 4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
+ (R ) //print .show==4
+ } odef
+/.strokecomplex
+ { % Do a first pass to see if the path is all horizontal and vertical
+ % lines in the output coordinate system.
+ % Stack: true mark origx origy curx cury
+ true mark null null null null
+ { .coord 6 2 roll pop pop pop pop 2 copy }
+ { .coord 1 index 4 index eq 1 index 4 index eq or
+ { 4 2 roll pop pop }
+ { cleartomark not mark exit }
+ ifelse
+ }
+ { cleartomark not mark exit }
+ { counttomark -2 roll 2 copy counttomark 2 roll
+ 1 index 4 index eq 1 index 4 index eq or
+ { pop pop 2 copy }
+ { cleartomark not mark exit }
+ ifelse
+ }
+ pathforall cleartomark
+ 0 currentlinewidth .dcoord 0 eq exch 0 eq or and
+ % Do the second pass to write out the rectangles.
+ % Stack: origx origy curx cury
+ { .showcolor null null null null
+ { 6 2 roll pop pop pop pop 2 copy .coord }
+ { .strokeline }
+ { }
+ { 3 index 3 index .strokeline }
+ pathforall pop pop pop pop
+ }
+ if
+ } odef
+/stroke { COMPLEX { .strokecomplex } if newpath } codef
+/ustroke
+ { gsave newpath
+ dup length 6 eq { exch uappend concat } { uappend } ifelse
+ stroke grestore
+ } codef
+
+% The image operators must read the input and note the dimensions.
+% Eventually we should redefine these to detect 1-bit-high all-black images,
+% since this is how dvips does underlining (!).
+
+/.noteimagerect % <width> <height> <matrix> .noteimagerect -
+ { COMPLEX
+ { gsave setmatrix itransform 0 0 itransform
+ grestore .coord 4 2 roll .coord .orderrect
+ (I ) //print .show==4
+ }
+ { pop pop pop
+ }
+ ifelse
+ } odef
+/colorimage where
+ { pop /colorimage
+ { 1 index
+ { dup 6 add index 1 index 6 add index 2 index 5 add index }
+ { 6 index 6 index 5 index }
+ ifelse .noteimagerect gsave nulldevice //colorimage grestore
+ } codef
+ } if
+/.noteimage % Arguments as for image[mask]
+ { dup type /dicttype eq
+ { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
+ { 4 index 4 index 3 index }
+ ifelse .noteimagerect
+ } odef
+/image { .noteimage gsave nulldevice //image grestore } codef
+/imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
+
+% Output the current color if necessary.
+/.color.r .inew def
+ .color.r -1 .iput % make sure we write the color at the beginning
+/.color.g .inew def
+/.color.b .inew def
+/.showcolor
+ { COMPLEX
+ { currentrgbcolor
+ 1000 mul round cvi
+ 3 1 roll 1000 mul round cvi
+ exch 1000 mul round cvi
+ % Stack: b g r
+ dup //.color.r .iget eq
+ 2 index //.color.g .iget eq and
+ 3 index //.color.b .iget eq and
+ { pop pop pop
+ }
+ { (C ) //print
+ dup //.color.r exch .iput .show==only
+ ( ) //print dup //.color.g exch .iput .show==only
+ ( ) //print dup //.color.b exch .iput .show==only
+ (\n) //print
+ }
+ ifelse
+ }
+ if
+ } bind def
+
+% Redefine `show'.
+
+% Set things up so our output will be in tenths of a point, with origin at
+% lower left. This isolates us from the peculiarities of individual devices.
+
+/.show.ident.matrix matrix def
+/.show.ident
+% { //.show.ident.matrix defaultmatrix
+% % Assume the original transformation is well-behaved.
+% 0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
+% 0.1 dup 3 -1 roll scale
+ { gsave initmatrix
+ % Assume the original transformation is well-behaved.
+ 0.1 0 dtransform abs exch abs .max /.show.scale exch def
+ 0.1 dup scale .show.ident.matrix currentmatrix
+ grestore
+ } bind def
+
+/.coord
+ { transform .show.ident itransform
+ exch round cvi exch round cvi
+ } odef
+
+/.dcoord
+ { % Transforming distances is trickier, because
+ % the coordinate system might be rotated.
+ .show.ident pop
+ exch 0 dtransform
+ dup mul exch dup mul add sqrt
+ .show.scale div round cvi
+ exch 0 exch dtransform
+ dup mul exch dup mul add sqrt
+ .show.scale div round cvi
+ } odef
+
+% Remember the current X, Y, and height.
+/.show.x .inew def
+/.show.y .inew def
+/.show.height .inew def
+
+% Remember the last character of the previous string; if it was a
+% hyphen preceded by a letter, we didn't output the hyphen.
+
+/.show.last (\000) def
+
+% Remember the current font.
+/.font.name 130 string def
+/.font.name.length .inew def
+/.font.height .inew def
+/.font.width .inew def
+
+%%* Also remember indentation of current line and previous vertical
+%%* skip
+
+/.show.indent .inew def
+/.show.dy .inew def
+
+% We have to redirect stdout somehow....
+
+/.show.stdout { (%stdout) (w) file } bind def
+
+% Make sure writing will work even if a program uses =string.
+/.show.string =string length string def
+/.show.=string =string length string def
+/.show==only
+ { //=string //.show.=string copy pop
+ dup type /stringtype eq
+ { dup length //.show.string length le
+ { dup rcheck { //.show.string copy } if
+ } if
+ } if
+ .show.stdout exch write==only
+ //.show.=string //=string copy pop
+ } odef
+/.show==4
+ { 4 -1 roll .show==only ( ) //print
+ 3 -1 roll .show==only ( ) //print
+ exch .show==only ( ) //print
+ .show==only (\n) //print
+ } odef
+
+/.showwidth % Same as stringwidth, but disable COMPLEX so that
+ % we don't try to detect rectangles during BuildChar.
+ { COMPLEX
+ { /COMPLEX false def stringwidth /COMPLEX true def }
+ { stringwidth }
+ ifelse
+ } odef
+
+/.showfont % <string> .showfont <string>
+ { gsave
+ % Try getting the height and width of the font from the FontBBox.
+ currentfont /FontBBox .knownget not { {0 0 0 0} } if
+ aload pop % llx lly urx ury
+ exch 4 -1 roll % lly ury urx llx
+ sub % lly ury dx
+ 3 1 roll exch % dx ury lly
+ sub % dx dy
+ 2 copy .max 0 ne
+ { currentfont /FontMatrix get dtransform
+ }
+ { pop pop
+ % Fonts produced by dvips, among other applications, have
+ % BuildChar procedures that bomb out when given unexpected
+ % characters, and there is no way to determine whether a given
+ % character will do this. So for Type 1 fonts, we measure a
+ % typical character ('X'); for others, we punt.
+ currentfont /FontType get 1 eq
+ { (X) .showwidth pop dup 1.3 mul
+ }
+ { % No safe way to get the character size. Punt.
+ 0 0
+ }
+ ifelse
+ }
+ ifelse .dcoord exch
+ currentfont /FontName .knownget not { () } if
+ dup type /stringtype ne { //.show.string cvs } if
+ grestore
+ % Stack: height width fontname
+ SIMPLE
+ { pop pop //.show.height exch .iput }
+ { 2 index //.font.height .iget eq
+ 2 index //.font.width .iget eq and
+ 1 index //.font.name 0 //.font.name.length .iget getinterval eq and
+ { pop pop pop
+ }
+ { (F ) //print
+ 3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
+ exch dup //.font.width exch .iput .show==only ( ) //print
+ dup length //.font.name.length exch .iput
+ //.font.name cvs .show==only (\n) //print
+ }
+ ifelse
+ }
+ ifelse
+ } odef
+
+% Define the letters -- characters which, if they occur followed by a hyphen
+% at the end of a line, cause the hyphen and line break to be ignored.
+/.letter.chars 100 dict def
+mark
+ 65 1 90 { dup 32 add } for
+ counttomark
+ { StandardEncoding exch get .letter.chars exch dup put }
+ repeat
+pop
+
+% Define a set of characters which, if they occur at the start of a line,
+% are taken as indicating a paragraph break.
+/.break.chars 50 dict def
+mark
+ /bullet /dagger /daggerdbl /periodcentered /section
+ counttomark
+ { .break.chars exch dup put }
+ repeat
+pop
+
+% Define character translation to ASCII.
+% We have to do this for the entire character set.
+
+/.char.map 500 dict def
+
+/.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
+
+% Encode the printable ASCII characters.
+
+mark 32 1 126
+ { 1 string dup 0 4 -1 roll put
+ dup 0 get StandardEncoding exch get exch
+ }
+for .chars.def
+
+ % Encode accents.
+mark
+ /acute (')
+ /caron (^)
+ /cedilla (,)
+ /circumflex (^)
+ /dieresis (")
+ /grave (`)
+ /ring (*)
+ /tilde (~)
+.chars.def
+
+ % Encode the ISO accented characters.
+mark 192 1 255
+ { ISOLatin1Encoding exch get =string cvs
+ dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
+ .char.map 2 index known .char.map 2 index known and
+ { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
+ .char.map 3 1 roll put
+ }
+ { pop pop pop
+ }
+ ifelse
+ }
+for .chars.def
+
+% Encode the remaining standard and ISO alphabetic characters.
+
+mark
+ /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
+ /ae (ae) /eth (dh)
+ /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
+ /germandbls (ss) /oe (oe) /thorn (th)
+.chars.def
+
+% Encode the other standard and ISO characters.
+
+mark
+ /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
+ /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
+ /dotlessi (i)
+ /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
+ /florin (f) /fraction (/)
+ /guillemotleft (<<) /guillemotright (>>)
+ /guilsingleft (<) /guilsingright (>) /hungarumlaut ("") /logicalnot (~)
+ /macron (_) /minus (-) /mu (u) /multiply (*)
+ /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
+ /ordfeminine (-a) /ordmasculine (-o)
+ /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
+ /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
+ /quotesinglbase (,) /quotesingle (') /registered ((R))
+ /section ($) /sterling (#)
+ /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
+ /yen (Y)
+.chars.def
+
+% Encode a few common Symbol characters.
+
+mark
+ /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
+ /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
+ /trademarksans ((TM)) /trademarkserif ((TM))
+.chars.def
+
+%%* Add a few characters from StandardEncoding and ISOLatin1Encoding
+%%* that were missing.
+
+mark
+ /cent (c)
+ /guilsinglleft (<)
+ /guilsinglright (>)
+ /breve (*)
+ /Lslash (L/)
+ /lslash (l/)
+.chars.def
+
+%%* Define the OT1Encoding and T1Encoding vectors for use with dvips
+%%* files. Unfortunately, there's no way of telling what font is
+%%* really being used within a dvips document, so we can't provide an
+%%* appropriate encoding for each individual font. Instead, we'll
+%%* just provide support for the two most popular text encodings, the
+%%* OT1 and T1 encodings, and just accept the fact that any font not
+%%* using one of those encodings will be rendered as gibberish.
+%%*
+%%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1
+%%* (aka the Cork encoding) is the 8-bit encoding used by the DC
+%%* fonts, a preliminary version of the proposed Extended Computer
+%%* Modern fonts. Unfortunately, T1 is not a strict extension of OT1;
+%%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134,
+%%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same
+%%* vector for both.
+%%*
+%%* Of course, we also can't reliably tell the difference between an
+%%* OT1-encoded font and a T1-encoded font based on the information in
+%%* a dvips-created PostScript file. As a best-guess solution, we'll
+%%* use the T1 encoding if the font contains any characters in
+%%* positions above 8#177 and the OT1 encoding if it doesn't.
+
+/T1Encoding 256 array def
+
+/OT1Encoding 256 array def
+
+%%* T1Encoding shares a lot with StandardEncoding, so let's start
+%%* there.
+
+StandardEncoding T1Encoding copy pop
+
+/OT1.encode {
+ counttomark
+ 2 idiv
+ { OT1Encoding 3 1 roll put }
+ repeat
+ cleartomark
+} def
+
+/T1.encode {
+ counttomark
+ 2 idiv
+ { T1Encoding 3 1 roll put }
+ repeat
+ cleartomark
+} def
+
+mark
+ 8#000 /grave
+ 8#001 /acute
+ 8#002 /circumflex
+ 8#003 /tilde
+ 8#004 /dieresis
+ 8#005 /hungarumlaut
+ 8#006 /ring
+ 8#007 /caron
+
+ 8#010 /breve
+ 8#011 /macron
+ 8#012 /dotaccent
+ 8#013 /cedilla
+ 8#014 /ogonek
+ 8#015 /quotesinglbase
+ 8#016 /guilsinglleft
+ 8#017 /guilsinglright
+
+ 8#020 /quotedblleft
+ 8#021 /quotedblright
+ 8#022 /quotedblbase
+ 8#023 /guillemotleft
+ 8#024 /guillemotright
+ 8#025 /endash
+ 8#026 /emdash
+ 8#027 /cwm
+
+ 8#030 /perthousandzero
+ 8#031 /dotlessi
+ 8#032 /dotlessj
+ 8#033 /ff
+ 8#034 /fi
+ 8#035 /fl
+ 8#036 /ffi
+ 8#037 /ffl
+
+%% 8#040 through 8#176 follow StandardEncoding
+
+ 8#177 /hyphen
+T1.encode
+
+mark
+ 8#200 /Abreve
+ 8#201 /Aogonek
+ 8#202 /Cacute
+ 8#203 /Ccaron
+ 8#204 /Dcaron
+ 8#205 /Ecaron
+ 8#206 /Eogonek
+ 8#207 /Gbreve
+ 8#210 /Lacute
+ 8#211 /Lcaron
+ 8#212 /Lslash
+ 8#213 /Nacute
+ 8#214 /Ncaron
+ 8#215 /Eng
+ 8#216 /Ohungarumlaut
+ 8#217 /Racute
+ 8#220 /Rcaron
+ 8#221 /Sacute
+ 8#222 /Scaron
+ 8#223 /Scedilla
+ 8#224 /Tcaron
+ 8#225 /Tcedilla
+ 8#226 /Uhungarumlaut
+ 8#227 /Uring
+ 8#230 /Ydieresis
+ 8#231 /Zacute
+ 8#232 /Zcaron
+ 8#233 /Zdot
+ 8#234 /IJ
+ 8#235 /Idot
+ 8#236 /dbar
+ 8#237 /section
+ 8#240 /abreve
+ 8#241 /aogonek
+ 8#242 /cacute
+ 8#243 /ccaron
+ 8#244 /dcaron
+ 8#245 /ecaron
+ 8#246 /eogonek
+ 8#247 /gbreve
+ 8#250 /lacute
+ 8#251 /lcaron
+ 8#252 /lslash
+ 8#253 /nacute
+ 8#254 /ncaron
+ 8#255 /eng
+ 8#256 /ohungarumlaut
+ 8#257 /racute
+ 8#260 /rcaron
+ 8#261 /sacute
+ 8#262 /scaron
+ 8#263 /scedilla
+ 8#264 /tcaron
+ 8#265 /tcedilla
+ 8#266 /uhungarumlaut
+ 8#267 /uring
+ 8#270 /ydieresis
+ 8#271 /zacute
+ 8#272 /zcaron
+ 8#273 /zdot
+ 8#274 /ij
+ 8#275 /exclamdown
+ 8#276 /questiondown
+ 8#277 /sterling
+
+ 8#300 /Agrave
+ 8#301 /Aacute
+ 8#302 /Acircumflex
+ 8#303 /Atilde
+ 8#304 /Adieresis
+ 8#305 /Aring
+ 8#306 /AE
+ 8#307 /Ccedilla
+ 8#310 /Egrave
+ 8#311 /Eacute
+ 8#312 /Ecircumflex
+ 8#313 /Edieresis
+ 8#314 /Igrave
+ 8#315 /Iacute
+ 8#316 /Icircumflex
+ 8#317 /Idieresis
+ 8#320 /Eth
+ 8#321 /Ntilde
+ 8#322 /Ograve
+ 8#323 /Oacute
+ 8#324 /Ocircumflex
+ 8#325 /Otilde
+ 8#326 /Odieresis
+ 8#327 /OE
+ 8#330 /Oslash
+ 8#331 /Ugrave
+ 8#332 /Uacute
+ 8#333 /Ucircumflex
+ 8#334 /Udieresis
+ 8#335 /Yacute
+ 8#336 /Thorn
+ 8#337 /Germandbls
+
+ 8#340 /agrave
+ 8#341 /aacute
+ 8#342 /acircumflex
+ 8#343 /atilde
+ 8#344 /adieresis
+ 8#345 /aring
+ 8#346 /ae
+ 8#347 /ccedilla
+ 8#350 /egrave
+ 8#351 /eacute
+ 8#352 /ecircumflex
+ 8#353 /edieresis
+ 8#354 /igrave
+ 8#355 /iacute
+ 8#356 /icircumflex
+ 8#357 /idieresis
+ 8#360 /eth
+ 8#361 /ntilde
+ 8#362 /ograve
+ 8#363 /oacute
+ 8#364 /ocircumflex
+ 8#365 /otilde
+ 8#366 /odieresis
+ 8#367 /oe
+ 8#370 /oslash
+ 8#371 /ugrave
+ 8#372 /uacute
+ 8#373 /ucircumflex
+ 8#374 /udieresis
+ 8#375 /yacute
+ 8#376 /thorn
+ 8#377 /germandbls
+
+T1.encode
+
+%%* Now copy OT1Encoding into T1Encoding and make a few changes.
+
+T1Encoding OT1Encoding copy pop
+
+mark
+ 8#000 /Gamma
+ 8#001 /Delta
+ 8#002 /Theta
+ 8#003 /Lambda
+ 8#004 /Xi
+ 8#005 /Pi
+ 8#006 /Sigma
+ 8#007 /Upsilon
+
+ 8#010 /Phi
+ 8#011 /Psi
+ 8#012 /Omega
+ 8#013 /ff
+ 8#014 /fi
+ 8#015 /fl
+ 8#016 /ffi
+ 8#017 /ffl
+
+ 8#020 /dotlessi
+ 8#021 /dotlessj
+ 8#022 /grave
+ 8#023 /acute
+ 8#024 /caron
+ 8#025 /breve
+ 8#026 /macron
+ 8#027 /ring
+
+ 8#030 /cedilla
+ 8#031 /germandbls
+ 8#032 /ae
+ 8#033 /oe
+ 8#034 /oslash
+ 8#035 /AE
+ 8#036 /OE
+ 8#037 /Oslash
+
+ 8#040 /polishslash
+
+ 8#042 /quotedblright
+
+ 8#074 /exclamdown
+ 8#076 /questiondown
+
+ 8#134 /quotedblleft
+ 8#137 /dotaccent
+
+ 8#173 /endash
+ 8#174 /emdash
+ 8#175 /hungarumlaut
+ 8#177 /dieresis
+OT1.encode
+
+%%* And add a few characters from the OT1Encoding
+
+mark
+ /Gamma (\\Gamma )
+ /Delta (\\Delta )
+ /Theta (\\Theta )
+ /Lambda (\\Lambda )
+ /Xi (\\Xi )
+ /Pi (\\Pi )
+ /Sigma (\\Sigma )
+ /Upsilon (\\Upsilon )
+
+ /Phi (\\Phi )
+ /Psi (\\Psi )
+ /Omega (\\Omega )
+
+ /dotlessj (j)
+ /ff (ff)
+
+ /cwm ()
+
+ /perthousandzero (0)
+
+ /polishslash ()
+
+ /Abreve (A*)
+ /Aogonek (A,)
+ /Cacute (C')
+ /Ccaron (C^)
+ /Dcaron (D^)
+ /Ecaron (E^)
+ /Eogonek (E,)
+ /Gbreve (G*)
+ /Lacute (L')
+ /Lcaron (L^)
+ /Nacute (N')
+ /Ncaron (N^)
+ /Eng (NG)
+ /Ohungarumlaut (O"")
+ /Racute (R')
+ /Rcaron (R^)
+ /Sacute (S')
+ /Scaron (S^)
+ /Scedilla (S,)
+ /Tcaron (T^)
+ /Tcedilla (T,)
+ /Uhungarumlaut (U"")
+ /Uring (U*)
+ /Ydieresis (Y")
+ /Zacute (Z')
+ /Zcaron (Z^)
+ /Zdot (Z.)
+ /IJ (IJ)
+ /Idot (I.)
+ /dbar (d-)
+ /abreve (a*)
+ /aogonek (a,)
+ /cacute (c')
+ /ccaron (c^)
+ /dcaron (d^)
+ /ecaron (e^)
+ /eogonek (e,)
+ /gbreve (g*)
+ /lacute (l')
+ /lcaron (l^)
+ /nacute (n')
+ /ncaron (n^)
+ /eng (ng)
+ /ohungarumlaut (o"")
+ /racute (r')
+ /rcaron (r^)
+ /sacute (s')
+ /scaron (s^)
+ /scedilla (s,)
+ /tcaron (t^)
+ /tcedilla (t,)
+ /uhungarumlaut (u"")
+ /uring (u*)
+ /zacute (z')
+ /zcaron (z^)
+ /zdot (z.)
+ /ij (ij)
+ /Germandbls (SS)
+.chars.def
+
+%%* We extend the df-tail command to stick in an Encoding vector (see
+%%* above for a discussion of the T1 and OT1 encodings), put in a
+%%* FontName (which will just be dvips's name for the font, i.e., Fa,
+%%* Fb, etc.) and give each font a separate FontBBox instead of
+%%* letting them all share a single one.
+
+/dvips.df-tail % id numcc maxcc df-tail
+ {
+ /nn 9 dict N
+ nn begin
+ %%
+ %% Choose an encoding based on the highest position occupied.
+ %%
+ dup 127 gt { T1Encoding } { OT1Encoding } ifelse
+ /Encoding X
+ /FontType 3 N
+ %%
+ %% It's ok for all the fonts to share a FontMatrix, but they
+ %% need to have separate FontBBoxes
+ %%
+ /FontMatrix fntrx N
+ /FontBBox [0 0 0 0] N
+ string /base X
+ array /BitMaps X
+ %%
+ %% And let's throw in a FontName for good measure
+ %%
+ dup ( ) cvs /FontName X
+ /BuildChar {CharBuilder} N
+ end
+ dup { /foo setfont }
+ 2 array copy cvx N
+ load
+ 0 nn put
+ /ctr 0 N
+ [
+} def
+
+%%* This is functionally equivalent to dvips's /D procedure, but it
+%%* also calculates the Font Bounding Box while defining the
+%%* characters.
+
+/dvips.D % char-data ch D - : define character bitmap in current font
+{
+ /cc X % char-data
+ dup type /stringtype ne {]} if % char-data
+
+ /ch-data X
+ nn /base get cc ctr put % (adds ctr to cc'th position of BASE)
+ nn /BitMaps get
+ ctr
+ ch-data % BitMaps ctr char-data
+ sf 1 ne {
+ dup dup length 1 sub dup 2 index S get sf div put
+ } if
+ put % puts char-data into BitMaps at index ctr
+ /ctr ctr 1 add N
+%%
+%% Make sure the Font Bounding Box encloses the Bounding Box of the
+%% current character
+%%
+ nn /FontBBox get % BB
+
+ dup % calculate new llx
+ dup 0 get
+ ch-xoff
+ min
+ 0 exch put
+
+ dup % calculate new lly
+ dup 1 get
+ ch-yoff ch-height sub
+ min
+ 1 exch put
+
+ dup % calculate new urx
+ dup 2 get
+ ch-dx ch-width add
+ max
+ 2 exch put
+
+ dup 3 get % calculate new ury
+ ch-yoff
+ max
+ 3 exch put
+
+} def
+
+%%* Define start-hook to replace df-tail and D by our versions.
+%%* Unfortunately, the user can redefine start-hook and thus bypass
+%%* these changes, but I don't see an obvious way around that.
+
+userdict /start-hook {
+ TeXDict /df-tail /dvips.df-tail load bind put
+ TeXDict /D /dvips.D load bind put
+} put
+
+%%* Introduce a symbolic constant for hyphens. (Need to make
+%%* allowance for hyphen being in different place?)
+
+/.hyphen 45 def
+
+% Write out a string. If it ends in a letter and a hyphen,
+% don't write the hyphen, and set .show.last to a hyphen;
+% otherwise, set .show.last to the character (or \000 if it was a hyphen).
+/.show.write % <string>
+ {
+ dup length 1 ge
+ { dup dup length 1 sub get % string last_char
+ dup .hyphen eq % string last_char hyphen?
+ { % string last_char
+ 1 index length 1 gt
+ { 1 index dup length 2 sub get }
+ { //.show.last 0 get }
+ ifelse % string last_char prev-char
+ currentfont /Encoding get exch get % look up prev-char
+ //.letter.chars exch known % is it a letter?
+ { % Remove the hyphen % string last_char
+ exch % last_char string
+ dup length 1 sub % last_char string len-1
+ 0 exch getinterval % last_char string-1
+ exch % string-1 last_char
+ }
+ { pop 0 } % string 0
+ ifelse
+ }
+ if
+ //.show.last 0 3 -1 roll put % store last_char
+ % in .show.last
+ % If .show.last ==
+ % hyphen, then
+ % last char of
+ % previous string
+ % was a hyphen
+ }
+ if % string
+ { % begin forall % c
+ dup currentfont /Encoding get exch get % c enc
+ dup //.char.map exch .knownget % c enc str bool
+ { % c enc str
+ .show.stdout exch writestring pop pop
+ }
+ { % c enc (c not in .char.map)
+ currentfont /Encoding get %%* BF1: added missing "get"
+ dup OT1Encoding eq %%* added OT1Encoding
+ exch % c bool enc
+ dup T1Encoding eq %%* added T1Encoding
+ exch % c bool enc
+ dup StandardEncoding eq % c bool enc bool
+ exch
+ ISOLatin1Encoding eq
+ or
+ or
+ { % Untranslated character in standard encoding ("normal" case)
+ pop .show.stdout exch write
+ }
+ { % Character in non-standard encoding, substitute
+ pop pop .show.stdout (*) writestring
+ }
+ ifelse
+ }
+ ifelse
+ }
+ forall
+} odef
+
+/.showstring1 { % string
+ currentpoint .coord % string x y
+ 3 -1 roll dup .showwidth % x y string dx dy
+ 1 index % x y string dx dy dx
+ 0 rmoveto % x y string dx dy
+ .dcoord pop % x y string width
+ SIMPLE
+ { % x y string width
+ 2 index % x y string width y
+ //.show.y .iget % x y string width y old.y
+ %%*
+ %%* Replaced test "has y changed" by "has y changed by more
+ %%* than the current font height" so that subscripts and
+ %%* superscripts won't cause line/paragraph breaks
+ %%*
+ sub abs dup % x y string width dy dy
+ //.show.height .iget
+ gt
+ { % x y string width dy
+
+ %%* Vertical position has changed by more than the font
+ %%* height, so we now try to figure out whether we've
+ %%* started a new paragraph or merely a new line, using a
+ %%* variety of heuristics.
+
+ %%* If any of the following is true, we start a new
+ %%* paragraph:
+
+ %%* (a) the current vertical shift is more than 1.1 times
+ %%* the previous vertical shift, where 1.1 is an
+ %%* arbitrarily chosen factor that could probably be
+ %%* refined.
+
+ dup % x y string width dy dy
+ //.show.dy .iget 1.1 mul
+ gt
+ exch
+
+ %%* Save the new vertical shift
+
+ //.show.dy exch .iput
+
+ %%* (b) The vertical shift is more than 1.3 times the
+ %%* "size" of the current font. I've removed this
+ %%* test since it's not really very useful.
+
+%%* //.show.dy .iget
+%%* //.show.height .iget 1.4 mul
+%%* gt % x y string width bool
+%%* .show.height .iget 0 gt and % only perform test if font
+%%* % height is nonzero
+%%* or
+
+ %%* (c) the first character of the new line is one of the
+ %%* .break.chars
+
+ 2 index length % x y string width newpar? len
+ 0 gt % x y string width newpar? len>0?
+ {
+ 2 index 0 get % x y string width newpar? s
+ currentfont /Encoding get
+ exch get % x y string width newpar? s_enc
+ //.break.chars exch known { pop true } if
+ }
+ if % x y string width newpar?
+
+ %%* (d) The indentation of the new line is greater than
+ %%* the indentation of the previous line.
+
+ 4 index
+ //.show.indent .iget
+ gt
+ or
+
+ % newpar?
+ { (\n\n) } % Paragraph
+ { % Line
+ %%*
+ %%* BF2: If last character on a line is
+ %%* a hyphen, we omit the hyphen and
+ %%* run the lines together. Of
+ %%* course, this will fail if a word
+ %%* with an explicit hyphen (e.g.,
+ %%* X-ray) is split across two lines.
+ %%* Oh, well. (What should we do
+ %%* about a hyphen that ends a
+ %%* "paragraph"? Perhaps that should
+ %%* inhibit a paragraph break.)
+ %%*
+ //.show.last 0 get .hyphen eq
+ { () }
+ { ( ) }
+ ifelse % x y string width char
+ }
+ ifelse
+ //print
+
+ //.show.y 3 index .iput % x y string width
+ //.show.x 4 index .iput % x y string width
+ //.show.indent 4 index .iput
+ }
+ { % x y string width dy
+ % If the word processor split a hyphenated word within
+ % the same line, put out the hyphen now.
+ pop
+ //.show.last 0 get .hyphen eq { (-) //print } if
+ }
+ ifelse
+ %%*
+ %%* If have moved more than 1 point to
+ %%* the right, interpret it as a
+ %%* space? This need to be looked at
+ %%* more closely.
+ %%*
+ 3 index % x y string width x
+ //.show.x .iget 10 add gt % x y string width bool
+ { ( ) //print }
+ if
+ % x y string width
+ 4 1 roll % width x y string
+ .show.write pop % width x
+ add //.show.x exch .iput % <empty>
+ }
+ { (S ) //print .show==4 }
+ ifelse
+} odef
+
+/.showstring
+ { dup () eq { pop } { .showstring1 } ifelse
+ } bind def
+
+% Redefine all the string display operators.
+
+/show {
+ .showfont
+ .showcolor
+ .showstring
+} codef
+
+% We define all the other operators in terms of .show1.
+
+/.show1.string ( ) def
+/.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
+/ashow
+ { .showfont .showcolor
+ { .show1 2 copy rmoveto } forall
+ pop pop
+ } codef
+/awidthshow
+ { .showfont .showcolor
+ { dup .show1 4 index eq { 4 index 4 index rmoveto } if
+ 2 copy rmoveto
+ }
+ forall
+ pop pop pop pop pop
+ } codef
+/widthshow
+ { .showfont .showcolor
+ //.show1.string 0 4 -1 roll put
+ { //.show1.string search not { exit } if
+ .showstring .showstring
+ 2 index 2 index rmoveto
+ } loop
+ .showstring pop pop
+ } codef
+/kshow
+ { .showfont .showcolor
+ %**************** Should construct a closure, in case the procedure
+ %**************** affects the o-stack.
+ { .show1 dup exec } forall pop
+ } codef
+
+% We don't really do the right thing with the Level 2 show operators,
+% but we do something semi-reasonable.
+/xshow { pop show } codef
+/yshow { pop show } codef
+/xyshow { pop show } codef
+/glyphshow
+ { currentfont /Encoding .knownget not { {} } if
+ 0 1 2 index length 1 sub
+ { % Stack: glyph encoding index
+ 2 copy get 3 index eq { exch pop exch pop null exit } if
+ }
+ for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
+ } codef
+
+end
+
+% Bind the operators we just defined, and all the others if we didn't
+% do it before. Also reenable 'bind' for future files.
+
+.bindoperators
+NOBIND currentdict systemdict ne and
+ { systemdict begin .bindoperators end }
+if
+NOBIND
+ { /bind /.bind load def }
+if
+
+% Make systemdict read-only if it wasn't already.
+
+systemdict wcheck { systemdict readonly pop } if
+
+% Restore the current local/global VM mode.
+
+exec
+
+
diff --git a/gs/lib/ps2epsi b/gs/lib/ps2epsi
new file mode 100755
index 000000000..a0164df47
--- /dev/null
+++ b/gs/lib/ps2epsi
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+tmpfile=/tmp/ps2epsi$$
+
+export outfile
+
+if [ $# -lt 1 -o $# -gt 2 ]; then
+ echo "Usage: `basename $0` file.ps [file.epsi]" 1>&2
+ exit 1
+fi
+
+infile=$1;
+
+if [ $# -eq 1 ]
+then
+ case "${infile}" in
+ *.ps) base=`basename ${infile} .ps` ;;
+ *.cps) base=`basename ${infile} .cps` ;;
+ *.eps) base=`basename ${infile} .eps` ;;
+ *.epsf) base=`basename ${infile} .epsf` ;;
+ *) base=`basename ${infile}` ;;
+ esac
+ outfile=${base}.epsi
+else
+ outfile=$2
+fi
+
+ls -l ${infile} |
+awk 'F==1 {
+ cd="%%CreationDate: " $6 " " $7 " " $8;
+ t="%%Title: " $9;
+ f="%%For:" U " " $3;
+ c="%%Creator: Ghostscript ps2epsi from " $9;
+ next;
+ }
+ /^%!/ {next;}
+ /^%%Title:/ {t=$0; next;}
+ /^%%Creator:/ {c=$0; next;}
+ /^%%CreationDate:/ {cd=$0; next;}
+ /^%%For:/ {f=$0; next;}
+ !/^%/ {
+ print "/ps2edict 30 dict def";
+ print "ps2edict begin";
+ print "/epsititle (" t "\\n) def";
+ print "/epsicreator (" c "\\n) def";
+ print "/epsicrdt (" cd "\\n) def";
+ print "/epsifor (" f "\\n) def";
+ print "end";
+ exit(0);
+ }
+ ' U="$USERNAME$LOGNAME" F=1 - F=2 ${infile} >$tmpfile
+
+gs -q -dNOPAUSE -r72 -sDEVICE=bit -sOutputFile=/dev/null $tmpfile ps2epsi.ps $tmpfile <${infile} 1>&2
+rm -f $tmpfile
+
+(
+cat << BEGINEPS
+save
+countdictstack
+mark
+newpath
+/showpage {} def
+%%EndProlog
+%%Page 1 1
+BEGINEPS
+
+cat ${infile} |
+tr -d '\015' |
+sed -e '/^%%BeginPreview:/,/%%EndPreview$/d' -e '/^%!PS-Adobe/d'\
+ -e '/^%%[A-Za-z][A-Za-z]*$/d' -e '/^%%[A-Za-z][A-Za-z]*: /d'
+
+cat << ENDEPS
+%%Trailer
+cleartomark
+countdictstack exch sub { end } repeat
+restore
+%%EOF
+ENDEPS
+
+) >> ${outfile}
+
+exit 0
diff --git a/gs/lib/ps2epsi.bat b/gs/lib/ps2epsi.bat
new file mode 100755
index 000000000..a32174a15
--- /dev/null
+++ b/gs/lib/ps2epsi.bat
@@ -0,0 +1,25 @@
+@echo off
+if "%1"=="" goto usage
+if "%2"=="" goto usage
+
+set infile=%1
+set outfile=%2
+
+rem Ghostscript uses %outfile% to define the output file
+gs -q -dNOPAUSE -sDEVICE=bit -sOutputFile=NUL ps2epsi.ps < %infile%
+
+rem We bracket the actual file with a few commands to help encapsulation
+echo /InitDictCount countdictstack def gsave save mark newpath > %outfile%
+
+rem Append the original onto the preview header
+copy %outfile% + %infile%
+
+echo countdictstack InitDictCount sub { end } repeat >> %outfile%
+echo cleartomark restore grestore >> %outfile%
+
+goto end
+
+:usage
+echo "Usage: ps2epsi <infile.ps> <outfile.epi>"
+
+:end
diff --git a/gs/lib/ps2epsi.ps b/gs/lib/ps2epsi.ps
new file mode 100644
index 000000000..1ce70ce78
--- /dev/null
+++ b/gs/lib/ps2epsi.ps
@@ -0,0 +1,253 @@
+% Copyright (C) 1990, 1995, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Convert an arbitrary PostScript file to an EPSI file.
+%
+% Original version contributed by
+% George Cameron <george@bio-medical-physics.aberdeen.ac.uk>
+% Patched 7/26/95 by
+% Greg P. Kochanski <gpk@bell-labs.com>
+% to add many new DSC comments and make the comments conforming.
+% Bug fix 9/29/97 by lpd <ghost@aladdin.com>: if the page size wasn't an
+% exact multiple of 8 bits, an incorrect bounding box (or a rangecheck
+% error) could occur.
+% Please do not contact these users if you have questions. They no longer
+% have the time, interest, or current expertise to keep this code working.
+% If you find bugs, please send proposed fixes to ghost@aladdin.com.
+%
+
+% Initialize, and redefine copypage and showpage.
+
+% ps2edict is defined in the pre-loaded code created by the ps2epsi script.
+% /ps2edict 25 dict def
+ps2edict begin
+
+ % The main procedure
+ /ps2epsi
+ { % Open the file
+ outfile (w) file /epsifile exch def
+ % Get the device parameters
+ currentdevice getdeviceprops .dicttomark
+ /HWSize get aload pop
+ /devheight exch def
+ /devwidth exch def
+ matrix defaultmatrix
+ /devmatrix exch def
+ % Make a corresponding memory device
+ devmatrix devwidth devheight <ff 00>
+ makeimagedevice
+ /arraydevice exch def
+ arraydevice setdevice % (does an erasepage)
+ /rowwidth devwidth 7 add 8 idiv def
+ /row rowwidth string def
+ % Replace the definition of showpage
+ userdict /showpage { ps2edict begin epsipage end } bind put
+ userdict /setfont { ps2edict begin epsisetfont end } bind put
+ } def
+
+ /epsifontdict 100 dict def
+
+ /epsisetfont
+ {
+ % code here keeps a list of font names in dictionary epsifontdict
+ /tmpfont exch def
+ /tmpfontname tmpfont /FontName get def
+ epsifontdict tmpfontname known not { epsifontdict tmpfontname 0 put } if
+ epsifontdict tmpfontname
+ epsifontdict tmpfontname get 1 add put
+ tmpfont setfont
+ } bind def
+
+% Get a scan line from the memory device, zeroing any bits beyond
+% the device width.
+ /getscanline % <device> <y> <string> getscanline -
+ {
+ dup 4 1 roll copyscanlines pop
+ 16#ff00 devwidth 7 and neg bitshift 255 and
+ dup 0 ne {
+ exch dup length 1 sub 2 copy get 4 -1 roll and put
+ } {
+ pop pop
+ } ifelse
+ } bind def
+
+ /margintest
+ {
+ { dup arraydevice exch row getscanline
+ -1 0 1 rowwidth 1 sub
+ { dup row exch get 0 ne { exit }{ pop } ifelse
+ } for
+ dup -1 ne { exch pop } if
+ -1 ne { exit } if pop
+ } for
+ } bind def
+
+
+ /epsiNameStr 200 string def
+ /epsiNpages 0 def
+ /epsiNpageStr 20 string def
+ /epsipage
+ {
+ /epsiNpages epsiNpages 1 add def
+ /loopcount devheight 1 sub def
+
+ % Find top margin
+ -1 0 1 loopcount margintest
+ dup -1 eq { (blank page!!\n) print quit }{ exch pop } ifelse
+ /tm exch def
+
+ % Find bottom margin
+ loopcount -1 0 margintest
+ /bm exch def
+
+ % Initialise limit variables
+ /loopcount rowwidth 1 sub def
+ /lm loopcount def /lmb 0 def
+ /rm 0 def /rmb 0 def
+
+ % Find left and right boundaries of image
+ tm 1 bm
+ { % Get more data
+ arraydevice exch row getscanline
+ % Scan from left to find first non-zero element
+ % We save first the element, then the index
+ -1 0 1 loopcount
+ { dup row exch get dup 0 ne { exch exit }{ pop pop } ifelse
+ } for
+ % If we found -1, row is blank ..
+ dup -1 ne
+ { % Find the leftmost index
+ dup lm lt
+ % If the new index is less, we save index and element
+ { /lm exch def /lmb exch def }
+ % If the index is equal, we or the bits together
+ { lm eq { lmb or /lmb exch def }{ pop } ifelse
+ } ifelse
+ % Now find the rightmost index
+ loopcount -1 0
+ { dup row exch get dup 0 ne { exch exit }{ pop pop } ifelse
+ } for
+ dup rm gt
+ % If the new index is greater, we save index and element
+ { /rm exch def /rmb exch def }
+ % If the index is equal, or the bits
+ { rm eq { rmb or /rmb exch def } { pop } ifelse
+ } ifelse
+ } if
+ pop
+ } for
+
+ % Now we find the real left & right bit positions
+ 256 0 1 7
+ { exch 2 div dup lmb le { pop exit }{ exch pop } ifelse
+ } for
+ /lmb exch def
+
+ 1 7 -1 0
+ { exch dup dup rmb and eq { pop exit }{ 2 mul exch pop } ifelse
+ } for
+ /rmb exch def
+
+ % Calculate the bounding box values
+ /llx lm 8 mul lmb add 1 sub def
+ /lly devheight bm sub 1 sub def
+ /urx rm 8 mul rmb add 1 add def
+ /ury devheight tm sub 1 add def
+
+ % Write out the magic string and bounding box information
+ epsifile (%!PS-Adobe-2.0 EPSF-1.2\n) writestring
+ epsifile epsititle writestring
+ epsifile epsicreator writestring
+ epsifile epsicrdt writestring
+ epsifile epsifor writestring
+ epsifile flushfile
+
+ % Write out the page count:
+ epsifile (%%Pages: ) writestring
+ epsifile epsiNpages epsiNpageStr cvs writestring
+ epsifile (\n) writestring
+ epsifile flushfile
+
+ % Write out the list of used fonts:
+ epsifile (%%DocumentFonts:) writestring
+ epsifontdict {
+ epsifile ( ) writestring
+ pop epsiNameStr cvs epsifile exch writestring
+ } forall
+ epsifile (\n) writestring
+ epsifile flushfile
+
+ epsifile (%%BoundingBox: ) writestring
+ epsifile llx write==only epsifile ( ) writestring
+ epsifile lly write==only epsifile ( ) writestring
+ epsifile urx write==only epsifile ( ) writestring
+ epsifile ury write==
+ epsifile (%%BeginPreview: ) writestring
+ epsifile urx llx sub 1 add write==only epsifile ( ) writestring
+ epsifile bm tm sub 1 add write==only epsifile ( 1 ) writestring
+ epsifile bm tm sub 1 add write==
+ epsifile flushfile
+
+ % Define character and bit widths for the output line buffer:
+ /cwidth rm lm sub 1 add 8 mul 7 add 8 idiv def
+ /bwidth cwidth 8 mul def
+ /owidth urx llx sub 1 add 7 add 8 idiv def
+ /out cwidth string def
+
+ % Create a 1-bit-high device for bitblt to align with the bbox
+ gsave
+ matrix cwidth 8 mul 1 <00 ff> makeimagedevice setdevice
+
+ % 'image' a zero string to clear the line device
+ bwidth 1 1 matrix cwidth string image
+
+ tm 1 bm
+ { % Get a scan line interval from the array device
+ arraydevice exch row copyscanlines lm cwidth getinterval
+ lmb 0 gt
+ { % 'image' it into the line device with the lmb offset
+ bwidth 1 1 [1 0 0 1 lmb 0] 5 -1 roll image
+ % Now we get the modified scan line
+ currentdevice 0 out copyscanlines 0 owidth getinterval
+ } if
+ % Write out the hex data
+ epsifile (% ) writestring
+ epsifile exch writehexstring
+ epsifile (\n) writestring
+ } for
+
+ epsifile (%%EndImage\n) writestring
+ epsifile (%%EndPreview\n) writestring
+ epsifile flushfile
+ grestore
+ erasepage initgraphics
+
+ DonePage 0 1 put
+ } bind def
+
+
+(outfile) getenv
+ { /outfile exch def
+ ps2epsi
+
+ /DonePage 1 string def
+ (%stdin) (r) file cvx execute0
+ DonePage 0 get 0 eq { showpage } if
+ } if
+
+end
+quit
diff --git a/gs/lib/ps2pdf b/gs/lib/ps2pdf
new file mode 100755
index 000000000..c2939dc89
--- /dev/null
+++ b/gs/lib/ps2pdf
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Convert PostScript to PDF.
+
+OPTIONS=""
+while true
+do
+ case "$1" in
+ -*) OPTIONS="$OPTIONS $1" ;;
+ *) break ;;
+ esac
+ shift
+done
+
+if [ $# -lt 1 -o $# -gt 2 ]; then
+ echo "Usage: `basename $0` [options...] input.ps [output.pdf]" 1>&2
+ exit 1
+fi
+
+infile=$1;
+
+if [ $# -eq 1 ]
+then
+ case "${infile}" in
+ *.ps) base=`basename ${infile} .ps` ;;
+ *) base=`basename ${infile}` ;;
+ esac
+ outfile=${base}.pdf
+else
+ outfile=$2
+fi
+
+# Doing an initial 'save' helps keep fonts from being flushed between pages.
+exec gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$outfile $OPTIONS -c save pop -f $infile
diff --git a/gs/lib/ps2pdf.bat b/gs/lib/ps2pdf.bat
new file mode 100644
index 000000000..b80e13fb6
--- /dev/null
+++ b/gs/lib/ps2pdf.bat
@@ -0,0 +1,62 @@
+@echo off
+rem Convert PostScript to PDF.
+
+rem NOTE: for questions about using this file on Windows NT, please
+rem contact Matt Sergeant (sergeant@geocities.com).
+
+set PS2PDFPARAMS=-q -dNOPAUSE -dBATCH -sDEVICE#pdfwrite
+set PS2PDFOPT=
+
+if "%OS%"=="Windows_NT" goto nt
+
+rem Run ps2pdf on any Microsoft OS. The executable must be named gs.
+
+set PS2PDFGS=gs
+
+:run
+if "%1"=="" goto usage
+if "%2"=="" goto usage
+:opt
+if "%3"=="" goto exec
+set PS2PDFOPT=%PS2PDFOPT% %1
+shift
+goto opt
+
+:exec
+rem Watcom C deletes = signs, so use # instead.
+rem Doing an initial 'save' helps keep fonts from being flushed between pages.
+%PS2PDFGS% %PS2PDFPARAMS% %PS2PDFOPT% -sOutputFile#%2 -c save pop -f %1
+goto end
+
+:usage
+echo "Usage: ps2pdf [options...] input.ps output.pdf"
+goto end
+
+rem Run ps2pdf on Windows NT. The executable must be named gswin32c.
+
+:nt
+set PS2PDFGS=gswin32c
+if not CMDEXTVERSION 1 goto run
+if "%1"=="" goto ntusage
+if "%2"=="" goto nooutfile
+if not "%3"=="" goto opt
+
+rem Watcom C deletes = signs, so use # instead.
+%PS2PDFGS% %PS2PDFPARAMS% -sOutputFile#%2 -c save pop -f %1
+goto end
+
+:ntusage
+echo "Usage: ps2pdf input.ps [output.pdf]"
+echo " or: ps2pdf [options...] input.ps output.pdf"
+goto end
+
+:nooutfile
+set PS2PDF=%1
+set PS2PDF=%PS2PDF:.PS=.PDF%
+%PS2PDFGS% %PS2PDFPARAMS% -sOutputFile#%PS2PDF% -c save pop -f %1
+
+:end
+rem Clean up.
+SET PS2PDFPARAMS=
+SET PS2PDFGS=
+SET PS2PDFOPT=
diff --git a/gs/lib/pv.sh b/gs/lib/pv.sh
new file mode 100755
index 000000000..70b7f3071
--- /dev/null
+++ b/gs/lib/pv.sh
@@ -0,0 +1,36 @@
+#!/bin/sh -f
+#
+# pv - preview a specified page of a dvi file in a Ghostscript window
+# usage: pv page file
+#
+# pv converts the given page to PostScript and displays it
+# in a Ghostscript window.
+#
+if [ $# -lt 2 ] ;then
+ echo usage: $0 'page_number file_name[.dvi]'
+ exit 1
+fi
+#
+# The following line used to appear here:
+#
+#RESOLUTION=100
+#
+# But according to Peter Dyballa
+# <pete@lovelace.informatik.uni-frankfurt.de>, "Modern versions of dvips are
+# taught to read configuration files which tell them the paths to PK, TFM,
+# VF and other files for example PostScript font programmes. These files
+# tell #dvips too which default resolution is used and therefore which
+# series of PK files (based on 300 DPI or 400 DPI or 600 DPI or even more)
+# are held on the system." So we have deleted this line, and also removed
+# the -D switch from the call of dvips below.
+#
+TEMPDIR=.
+PAGE=$1
+shift
+FILE=$1
+shift
+trap "rm -rf $TEMPDIR/$FILE.$$.pv" 0 1 2 15
+#dvips -D$RESOLUTION -p $PAGE -n 1 $FILE $* -o $FILE.$$.pv
+dvips -p $PAGE -n 1 $FILE $* -o $FILE.$$.pv
+gs $FILE.$$.pv
+exit 0
diff --git a/gs/lib/quit.ps b/gs/lib/quit.ps
new file mode 100644
index 000000000..ff604669b
--- /dev/null
+++ b/gs/lib/quit.ps
@@ -0,0 +1 @@
+quit
diff --git a/gs/lib/ras1.upp b/gs/lib/ras1.upp
new file mode 100644
index 000000000..beb3433f8
--- /dev/null
+++ b/gs/lib/ras1.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 1 Bit, 2 Colors (Ghostscript-Rendering)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceGray
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/SunRaster
+-dupComponentBits={1}
diff --git a/gs/lib/ras24.upp b/gs/lib/ras24.upp
new file mode 100644
index 000000000..c92f26e96
--- /dev/null
+++ b/gs/lib/ras24.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 24 Bit, 7 Colors (RGB-Error-Diffusion)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceRGB
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/SunRaster
+-dupComponentBits="{8 8 8}"
diff --git a/gs/lib/ras3.upp b/gs/lib/ras3.upp
new file mode 100644
index 000000000..96a0a2c70
--- /dev/null
+++ b/gs/lib/ras3.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 3 Bit, 7 Colors (RGB-Ghostscript)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceRGB
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/SunRaster
+-dupComponentBits="{1 1 1}"
diff --git a/gs/lib/ras32.upp b/gs/lib/ras32.upp
new file mode 100644
index 000000000..48307595b
--- /dev/null
+++ b/gs/lib/ras32.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 32 Bit, 6+1 Colors (CMYK-Error-Diffusion)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/SunRaster
+
diff --git a/gs/lib/ras4.upp b/gs/lib/ras4.upp
new file mode 100644
index 000000000..1a9330058
--- /dev/null
+++ b/gs/lib/ras4.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 4 Bit, 6+1 Colors (CMYK-Ghostscript)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYK
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/SunRaster
+-dupComponentBits="{1 1 1 1}"
diff --git a/gs/lib/ras8m.upp b/gs/lib/ras8m.upp
new file mode 100644
index 000000000..304ad535d
--- /dev/null
+++ b/gs/lib/ras8m.upp
@@ -0,0 +1,8 @@
+-supModel="SUN rasterfile, 8 Bit, 2 Colors (Error-Diffusion)"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceGray
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/SunRaster
+-dupComponentBits={8}
diff --git a/gs/lib/rm.bat b/gs/lib/rm.bat
new file mode 100755
index 000000000..ec73ac552
--- /dev/null
+++ b/gs/lib/rm.bat
@@ -0,0 +1,9 @@
+@echo off
+:next
+if '%1'=='' goto exit
+if '%1'=='-f' goto sh
+erase %1
+:sh
+shift
+goto next
+:exit
diff --git a/gs/lib/rollconv.ps b/gs/lib/rollconv.ps
new file mode 100644
index 000000000..072cd8c0f
--- /dev/null
+++ b/gs/lib/rollconv.ps
@@ -0,0 +1,372 @@
+%!
+% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% rollconv.ps
+% Utility program for converting Japanese fonts produced by Macromedia's
+% Rollup program to Type 0 fonts suitable for use with Ghostscript.
+%
+% Rollup produces the following files, where xxx is the font name:
+% xxx-H, xxx-SA, xxx-SB, xxx-SK, xxx-SR, xxx-UG
+% JIS83-1_COD
+% JIS83-1_CSA
+% The _COD and _CSA files are large files containing the actual
+% character outline data; they may theoretically be shared between
+% multiple fonts.
+%
+% rollconv.ps converts the above to files named:
+% fff.ps
+% fff.COD
+% fff.CSA
+% fff.CSR
+% where fff is a font file name provided by the user at conversion time.
+% The fff.ps file is the actual font file to be loaded with `run'
+% or placed in a Fontmap or a directory named by [GS_]FONTPATH;
+% the other two files must be present at runtime in a directory that is
+% on Ghostscript's search path (-I, GS_LIB, GS_LIB_DEFAULT).
+%
+% The normal way to invoke this program is
+% gsnd -- rollconv.ps xxx fff InDir CDir OutDir
+% (assuming that gsnd is an alias for gs -dNODISPLAY), where:
+% xxx is the font name;
+% fff is the base part of the output file name;
+% InDir is the name of the directory containing the xxx-* input files;
+% CDir is the name of the directory containing the _COD and _CSA
+% input files (typically the same as InDir);
+% OutDir is the name of the directory where the output should be written
+% (OutDir must already exist).
+% For example:
+% gsnd -- rollconv.ps HGGothicBPRO gothic /gs/k/rufonts/Gothic \
+% /gs/k/rufonts/Gothic /gs/k/gsfonts
+% To suppress output messages, you may insert -q:
+% gsnd -q -- rollconv.ps ...
+%
+% This program assumes that the files have been FTP'ed from a Macintosh and
+% therefore have 128 bytes of garbage at the beginning. If you have
+% transferred them in some manner that avoids this, change true to false
+% in the following line.
+/fromMac true def
+% The FontName of the converted font is xxx-83pv-RKSJ-H. In order to
+% use a converted font with Ghostscript, you may either load it explicitly
+% at run time, e.g.,
+% (gothic.ps) run
+% or you may add an entry to the Fontmap file, in the form:
+% /HGGothicBPRO-83pv-RKSJ-H (gothic.ps) ;
+% which will allow the font to be loaded automatically. After
+% loading the font, by either method, you can select it in the usual way:
+% /HGGothicBPRO-83pv-RKSJ-H findfont 36 scalefont setfont
+% or
+% /HGGothicBPRO-83pv-RKSJ-H 36 selectfont
+
+
+/macrfile % <filename> macrfile <file>
+ { (r) file
+ fromMac
+ { % Get rid of the initial Mac garbage (128 characters).
+ % The garbage at the end is unpredictable,
+ % so we'll just have to hope that it's all nulls.
+ dup =string 0 128 getinterval readstring pop pop
+ }
+ if
+ } bind def
+
+/convert % <FName> <OutBase> <InDir> <CDir> <OutDir> convert -
+ { /OutDir exch def
+ /CDir exch def
+ /InDir exch def
+ /OutBase exch def
+ /FName exch def
+
+ /inprefix InDir (/) concatstrings FName concatstrings (-) concatstrings def
+ /inh inprefix (H) concatstrings def
+
+ % Open the output file.
+
+/OutDot OutDir (/) concatstrings OutBase concatstrings (.) concatstrings def
+/outname OutDot (ps) concatstrings def
+QUIET not { (Writing ) print outname = flush } if
+/cdfromstr (\(pgfonts/) FName concatstrings (-JIS83-1_) concatstrings def
+/cdstr (\() OutBase concatstrings (.) concatstrings def
+/out outname (w) file def
+/buffer 65000 string def
+
+ % Copy the initial comments from the input file.
+
+inh macrfile
+ { dup =string readline pop
+ out 1 index writestring out (\n) writestring
+ (%%EndComments) eq { exit } if
+ }
+loop
+
+ % Write out our preamble.
+
+out (
+currentpacking true setpacking
+userdict /AltsysCFD3 known { (%END) .skipeof } if
+userdict /AltsysCFD3 25 dict dup begin
+/beint { 0 exch { exch 8 bitshift add } forall } bind def
+/rfile { findlibfile { exch pop } { (r) file } ifelse } bind def
+/str 500 string def
+/AltRO { } def
+/BuildCh % <font> <ccode> <bias> BuildCh -
+ { /bias exch def /ccode exch def begin % font
+ ccode dup 255 and dup bias lt exch 252 gt or { pop 127 } if
+ dup -8 bitshift -67 mul add % subfonts have 189 chars, not 256
+ bias sub buildch1
+ } bind def
+/BuildChr % <font> <ccode> BuildChr -
+ { /ccode exch def begin % font
+ ccode buildch1
+ } bind def
+/buildch1
+ { 6 mul PGOffsets add
+ FileNames 0 get rfile dup dup 4 -1 roll setfileposition
+ (xxxxxx) readstring pop exch closefile
+ dup 1 3 getinterval beint % COD offset
+ exch 4 2 getinterval beint % length
+ dup 0 eq
+ { pop pop currentdict end
+ 1000 0 0 0 1 1 0 -1000 500 1000 setcachedevice2
+ }
+ { dup str length gt { /str 1 index string store } if
+ FileNames 1 get rfile dup dup % offset length file file file
+ 5 -1 roll setfileposition % length file file
+ str 0 5 -1 roll getinterval readstring pop pop closefile
+ currentdict end ccode str 1183615869 internaldict /CCRun get exec
+ }
+ ifelse
+ } bind def
+/privates 100 dict def
+/BuildPr % <stdhw> <stdvw> BuildPr <dict>
+ { 2 copy 1000 mul add privates 1 index known
+ { privates exch get 3 1 roll pop pop
+ }
+ { 7 dict begin
+ /MinFeature{16 16}executeonly def
+ /BlueValues BlueValues def
+ /StdVW 3 -1 roll 1 array astore def
+ /StdHW 3 -1 roll 1 array astore def
+ /password 5839 def
+ /LanguageGroup 1 def
+ /Subrs Subrs def
+ currentdict readonly end
+ privates 2 index 2 index put exch pop
+ }
+ ifelse
+ } bind def
+/FullEncoding
+ systemdict { pop } forall
+ systemdict length 512 sub 1 255 { (x) dup 0 4 -1 roll put cvn } for
+768 packedarray def
+/BlueValues[-250 -250 1100 1100]readonly def
+/BuildChar{AltsysCFD3 begin 64 BuildCh end}bind def
+/CharStrings 1 dict
+dup /.notdef (¿1pyÊ8å) noaccess put
+readonly def
+/CDevProc
+ { pop pop pop pop 0 exch -1000 exch 2 div currentfont /FontBBox get 3 get
+ } bind def
+/FontMatrix[0.001 0.0 0.0 0.001 0.0 0.0]readonly def
+/Subrs [
+(¿1p|=-“D\âR) noaccess
+(¿1py¼öUz) noaccess
+(¿1py½Äži) noaccess
+(¿1pù) noaccess
+(¿1p|35r·I) noaccess
+] noaccess def
+end put
+%END
+) writestring
+
+ % Locate and copy the definition of NotDefFont.
+
+out (
+FontDirectory /NotDefFont known { (%END) .skipeof } if
+) writestring
+ { dup =string readline pop
+ dup (/NotDefFont) eq { exit } if pop
+ }
+loop out exch writestring out (\n) writestring
+ { dup =string readline pop
+ (definefont) search { pop pop pop exit } if
+ out exch writestring out (\n) writestring
+ }
+loop out (definefont pop
+%END
+) writestring
+
+ % Copy the definitions of the subfonts, moving the
+ % CharStrings of the Roman supplement to an external file.
+ % Stack for pattern procedures: infile line
+
+/CSRName OutDot (CSR) concatstrings def
+/csr CSRName (w) file def
+QUIET not { (Writing ) print CSRName = flush } if
+
+/encoding 256 array def
+
+/patterns [
+ % Patterns specific to the Roman supplement, in which
+ % the outlines are in an eexec section.
+ { (/Encoding 256 array) {
+ pop out (/Encoding ) writestring
+ { dup buffer readline pop
+ dup (dup) search { exit } if pop pop
+ }
+ loop
+ { % Stack: infile dupline postdup (dup) predup
+ pop pop exch pop
+ % The top element of the stack is a string beginning with
+ % an index and value to put into the Encoding.
+ token pop exch token pop exch pop encoding 3 1 roll put
+ dup buffer readline pop
+ dup (dup) search not { pop exit } if
+ }
+ loop
+ out encoding cvx write== out ( cvlit ) writestring
+ out exch writestring out (\n) writestring
+ } }
+ { (/FontType 1 def) {
+ pop out (/FontType 4 def\n) writestring
+ out (/BuildChar{AltsysCFD3 begin BuildChr end}bind def\n) writestring
+ out (/FileNames[) writestring
+ 2 { out OutBase (.CSR) concatstrings write==only } repeat
+ out (]def\n) writestring
+ } }
+ { (currentfile eexec) {
+ pop out (systemdict begin\n) writestring
+ dup 55665 /eexecDecode filter
+ } }
+ { (dup/CharStrings ) {
+ % Copy the individual CharStrings to the CSR file,
+ % recording the lengths and offsets.
+ pop out (dup/CharStrings AltsysCFD3 /CharStrings get put\n) writestring
+ /offsets 256 dict def
+ { dup token pop % char name
+ dup dup type /nametype eq exch xcheck not and not { pop exit } if
+ 1 index token pop % length of binary data
+ 2 index token pop pop % skip RD
+ 2 index buffer 0 3 index getinterval readstring pop % charstring
+ offsets 3 index csr fileposition 16 bitshift 4 index add put
+ csr exch writestring pop pop
+ dup buffer readline pop pop % skip ND
+ }
+ loop
+ % We skipped the 'end'; skip the 'readonly put' as well.
+ 2 { dup token pop pop } repeat
+ out (dup/PGOffsets ) writestring
+ out csr fileposition write=only
+ out ( put\n) writestring
+ encoding
+ { offsets exch .knownget not { 0 } if
+ 2 { csr 0 write } repeat
+ 4 { dup -24 bitshift csr exch write 8 bitshift } repeat pop
+ }
+ forall
+ } }
+ { (/OtherSubrs[) {
+ pop
+ { dup buffer readline pop
+ (]noaccess def) search { pop pop pop exit } if pop
+ }
+ loop
+ } }
+ { (/Subrs 5 array) {
+ pop out (/Subrs AltsysCFD3 /Subrs get def\n) writestring
+ 6 { dup buffer readline pop pop } repeat
+ } }
+ { (currentfile closefile) {
+ pop out (end % systemdict\n) writestring
+ closefile
+ } }
+ % Patterns for other supplements.
+ { (pgfonts/) {
+ { cdfromstr search not { exit } if
+ out exch writestring pop out cdstr writestring
+ }
+ loop out exch writestring out (\n) writestring
+ } }
+ { (/BuildChar{AltsysCFD3 begin 64 BuildCh end}bind def) {
+ pop out (\t/BuildChar AltsysCFD3 /BuildChar get def\n) writestring
+ } }
+ { (/CDevProc{pop pop pop pop 0 exch -1000 exch 2 div ) {
+ pop out (\t/CDevProc AltsysCFD3 /CDevProc get def\n) writestring
+ } }
+ { (/CharStrings 1 dict dup begin) {
+ pop out (\t/CharStrings AltsysCFD3 /CharStrings get def\n) writestring
+ 2 { dup buffer readline pop pop } repeat
+ } }
+ { (/FontMatrix[0.001 0.0 0.0 0.001 0.0 0.0]def) {
+ pop out (\t/FontMatrix AltsysCFD3 /FontMatrix get def\n) writestring
+ } }
+ { (/Private 14 dict dup begin) {
+ pop out (\t/Private) writestring
+ { dup buffer readline pop
+ (end def) search { pop pop pop exit } if
+ (/Std) search
+ { pop pop dup length 3 sub 3 exch getinterval
+ (]) search pop out ( ) writestring out exch writestring pop
+ }
+ if pop
+ }
+ loop out ( AltsysCFD3 begin BuildPr end def\n) writestring
+ } }
+ { (UniqueID) { pop } }
+ { () {
+ out exch writestring out (\n) writestring
+ } }
+] def
+[ (SR) (SA) (SK) (SB) (UG) ]
+ { 0 1 255 { encoding exch /.notdef put } for
+ inprefix exch concatstrings macrfile
+ { dup buffer readline not { pop exit } if
+ /patterns load
+ { 2 copy 0 get search { pop pop pop 1 get exec exit } if pop pop }
+ forall
+ }
+ loop closefile
+ }
+forall
+csr closefile
+
+ % Copy the definition of the root font.
+
+dup buffer readstring pop out exch writestring closefile
+out (
+setpacking
+) writestring
+out closefile
+
+ % Remove the Mac garbage from the outline files.
+
+[ (COD) (CSA) ]
+ { CDir (/) concatstrings (JIS83-1_) concatstrings
+ 1 index concatstrings macrfile
+ exch OutDot exch concatstrings
+ QUIET not { (Writing ) print dup = flush } if
+ (w) file
+ % Stack: infile outfile
+ { 1 index buffer readstring exch
+ % Stack: infile outfile noteof substring
+ 2 index exch writestring not { exit } if
+ }
+ loop closefile closefile
+ }
+forall
+
+ } bind def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark 5 eq
+ { convert
+ QUIET not { (Done.\n) print flush } if
+ }
+ { cleartomark
+ (Usage: gsnd -- rollconv.ps FName OutBase InDir CDir OutDir\n) print
+ ( e.g.: gsnd -- rollconv.ps HGMinchoE mincho HGfonts/Mincho HGfonts/Mincho HGfonts/gs\n) print flush
+ mark
+ }
+ ifelse
+ }
+if pop
diff --git a/gs/lib/showchar.ps b/gs/lib/showchar.ps
new file mode 100644
index 000000000..20f72f8b8
--- /dev/null
+++ b/gs/lib/showchar.ps
@@ -0,0 +1,94 @@
+% Copyright (C) 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% showchar.ps
+% Show the outline and rasterized forms of a character.
+
+/F where { pop } { /F /Times-Roman def } ifelse
+/P where { pop } { /P 16 def } ifelse
+/Rx where { pop } { /Rx 100 def } ifelse
+/Ry where { pop } { /Ry 100 def } ifelse
+/Cs where { pop } { /Cs (M) def } ifelse
+/Pr where { pop } { /Pr false def } ifelse
+/Delay where { pop } { /Delay 0 def } ifelse
+
+0 setgray
+(markpath.ps) runlibfile
+(markhint.ps) runlibfile
+/mmx [1 0 0 1 0 0] def
+/getpath % - getpath <pathproc>
+ { [
+ { /moveto cvx } { /lineto cvx } { /curveto cvx } { /closepath cvx }
+ pathforall
+ ] cvx
+ } def
+/bitselectfont % <fontname> <scale> bitselectfont -
+ { exch findfont exch scalefont setfont
+ % Compute the bounding box in device coordinates.
+ gsave [Rx 72 div 0 0 Ry 72 div 0 0] setmatrix
+ currentfont /FontMatrix get concat
+ currentfont /FontBBox get aload pop
+ transform ceiling cvi /ury exch def ceiling cvi /urx exch def
+ transform floor cvi /lly exch def floor cvi /llx exch def
+ /bbx urx llx sub def /bby ury lly sub def
+ grestore
+ } def
+/bitshow % <string> bitshow -
+ { /S exch def gsave
+ /W bbx 8 add 7 or 1 add def
+ /H bby 8 add def
+ /buf W 8 idiv string def
+ /M [Rx 72 div 0 0 Ry -72 div 4 llx sub H 4 sub] def
+ M W H <ff 00> makeimagedevice
+ /dev exch def
+ gsave dev setdevice
+ newpath 0 lly idtransform moveto
+ 0 setgray
+ gsave
+ /hpath S false charpath getpath def
+ grestore
+ S show grestore
+ 20 20 translate
+ 50000 Rx Ry .max P mul div dup scale
+ 0.7 setgray
+ 0 W H true M
+ { dup 1 add exch dev exch buf copyscanlines
+ } imagemask pop
+ 0 setlinewidth
+ gsave 0.5 1 0.5 setrgbcolor hpath exec mmx markpath grestore
+ 0 0.5 1 setrgbcolor hpath exec stroke
+ % Show the hints for Type 1 fonts also.
+ currentfont /FontType get 1 eq
+ { gsave 1 0 0 setrgbcolor
+ 0 lly M idtransform translate
+ currentfont /FontMatrix get
+ dup Pr markfonthints
+ currentfont /Encoding get S 0 get get exch Pr markcharhints
+ grestore
+ }
+ if
+ } def
+F P bitselectfont
+/S1 1 string def
+Cs
+ { /C exch def
+ currentfont /Encoding get C get /.notdef ne
+ { save S1 0 C put S1 bitshow
+ showpage restore
+ } if
+ } forall
+quit
diff --git a/gs/lib/showpage.ps b/gs/lib/showpage.ps
new file mode 100644
index 000000000..97a4789f7
--- /dev/null
+++ b/gs/lib/showpage.ps
@@ -0,0 +1 @@
+showpage
diff --git a/gs/lib/snowflak.ps b/gs/lib/snowflak.ps
new file mode 100644
index 000000000..1052ae75e
--- /dev/null
+++ b/gs/lib/snowflak.ps
@@ -0,0 +1,90 @@
+%!
+%% Elizabeth D. Zwicky
+%% zwicky@erg.sri.com
+%% multiflake
+
+/newflake
+{/seed usertime def
+seed srand
+/strokecolor [rand 99 mod 100 div
+ rand 99 mod 100 div
+ 100 rand 22 mod sub 100 div] def
+/fillcolor [rand 99 mod 100 div
+ 100 rand 22 mod sub 100 div
+ rand 99 mod 100 div] def
+/eofillcolor [rand 99 mod 100 div
+ rand 22 mod 100 div
+ 100 rand 22 mod sub 100 div] def
+
+/colorfill {fillcolor aload pop setrgbcolor fill } def
+/colorstroke {strokecolor aload pop setrgbcolor stroke } def
+/eocolorfill {eofillcolor aload pop setrgbcolor eofill } def
+/arm {0 0 moveto
+ 5 {3 {x y x y x y curveto} repeat} repeat
+ seed srand
+ 0 0 moveto
+ 5 {3 {x neg y x neg y x neg y curveto} repeat} repeat
+ seed srand
+} def
+
+ newpath
+
+0 0 moveto boxsize 0 rlineto 0 boxsize rlineto boxsize neg 0 rlineto
+0 0 lineto
+
+rand 99 mod 100 div
+100 rand 22 mod sub 100 div
+100 rand 22 mod sub 100 div
+ sethsbcolor fill
+seed srand
+boxsize 2 div boxsize 2 div translate
+
+%% If the device you are using can handle complex fills, replace the
+%% next three lines with:
+%%
+6 {arm 60 rotate} repeat
+gsave colorfill grestore gsave eocolorfill grestore colorstroke
+%%
+%% This will be not only faster, but prettier. On a LaserWriter or a
+%% Tektronix Phaser II PS it gives a limitcheck.
+
+%% 6 {arm 60 rotate colorfill} repeat
+%% 6 {arm 60 rotate eocolorfill} repeat
+%% 6 {arm 60 rotate} repeat colorstroke
+} def
+
+1 setlinewidth
+clippath pathbbox /ury exch def /urx exch def /lly exch def /llx exch def
+/minsize 250 def
+/pagewidth urx llx sub def
+/pageheight ury lly sub def
+/inwidth pagewidth minsize div def
+/inheight pageheight minsize div def
+
+/boxsize
+ inwidth inheight gt
+ {pagewidth inwidth truncate div}
+ {pageheight inheight truncate div}
+ ifelse
+def
+
+/inwidth pagewidth boxsize div cvi def
+/inheight pageheight boxsize div cvi def
+
+/x {rand 70 mod abs} def
+/y {rand 120 mod abs} def
+
+llx lly translate
+
+inheight {
+ inwidth {
+ gsave
+ newflake
+ grestore
+ boxsize 0 translate
+ } repeat
+ boxsize inwidth mul neg boxsize translate
+} repeat
+
+
+showpage
diff --git a/gs/lib/stc.upp b/gs/lib/stc.upp
new file mode 100644
index 000000000..3beaa2de6
--- /dev/null
+++ b/gs/lib/stc.upp
@@ -0,0 +1,53 @@
+-supModel="Epson Stylus Color I (and PRO Series), 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupWeaveYPasses=4
+-dupOutputPins=15
+-dupWeaveYFeeds="{15 15 15 15}"
+-dupWeaveInitialYFeeds="{1 1 1 13}"
+-dupWeaveInitialPins="{ 4 15 11 7}"
+-dupBlackTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 0A
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc1520h.upp b/gs/lib/stc1520h.upp
new file mode 100644
index 000000000..8afceb269
--- /dev/null
+++ b/gs/lib/stc1520h.upp
@@ -0,0 +1,58 @@
+-supModel="Epson Stylus Color 1520, 1440x720DpI, Inkjet Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2XY
+-r1440x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupCyanTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupMagentaTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupYellowTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveXPasses=2
+-dupOutputXStep=2
+-dupWeaveYPasses=4
+-dupOutputPins=62
+-dupWeaveYFeeds="{31 31 31 31 31 31 31 31}"
+-dupWeaveXStarts="{0 1 0 1 1 0 1 0}"
+-dupWeaveYOffset=18
+-dupWeaveInitialYFeeds="{ 3 3 3 3 3 3 3 31}"
+-dupWeaveInitialXStarts="{0 1 0 1 1 0 1 0}"
+-dupWeaveInitialPins="{ 13 20 27 34 41 48 55 62}"
+-dupFormatYabsolute
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 05
+ 1b2873 0100 02
+ 1b5501
+ 1b2865 0200 0001
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupXStepCommand="<1b285c 0400 a005 0100>"
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc2.upp b/gs/lib/stc2.upp
new file mode 100644
index 000000000..1bce58a73
--- /dev/null
+++ b/gs/lib/stc2.upp
@@ -0,0 +1,53 @@
+-supModel="Epson Stylus Color II / IIs, 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupWeaveYPasses=3
+-dupOutputPins=20
+-dupWeaveYFeeds="{20 20 20}"
+-dupWeaveInitialYFeeds="{1 1 19}"
+-dupWeaveInitialPins="{ 7 20 13}"
+-dupBlackTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 0A
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc2_h.upp b/gs/lib/stc2_h.upp
new file mode 100644
index 000000000..37e9b6f4e
--- /dev/null
+++ b/gs/lib/stc2_h.upp
@@ -0,0 +1,53 @@
+-supModel="Epson Stylus Color II, 720x720DpI, Special Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupWeaveYPasses=6
+-dupOutputPins=20
+-dupWeaveYFeeds="{20 20 19 22 16 23}"
+-dupWeaveInitialYFeeds="{1 1 1 1 1 19}"
+-dupWeaveInitialPins="{ 4 20 7 17 10 13}"
+-dupBlackTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 05
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc2s_h.upp b/gs/lib/stc2s_h.upp
new file mode 100644
index 000000000..e35a9d332
--- /dev/null
+++ b/gs/lib/stc2s_h.upp
@@ -0,0 +1,57 @@
+-supModel="Epson Stylus Color IIs, 720x720DpI, Special Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2XY
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.0000 0.0003 0.0027 0.0056 0.0085 0.0120 0.0156 0.0196
+ 0.0227 0.0260 0.0292 0.0323 0.0354 0.0386 0.0416 0.0450
+ 0.0503 0.0564 0.0630 0.0711 0.0799 0.0905 0.1038 0.1169
+ 0.1321 0.1522 0.1761 0.2011 0.2285 0.2678 0.3102 0.3637
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupFormatYabsolute
+-dupWeaveYPasses=6
+-dupWeaveXPasses=2
+-dupOutputPins=20
+-dupWeaveYFeeds="{10 10 10 10 10 11 10 10 10 10 10 9}"
+-dupWeaveXStarts="{0 1 0 1 0 1 0 1 0 1 0 1}"
+-dupWeaveInitialYFeeds="{ 1 1 1 1 1 1 1 1 1 1 1 1}"
+-dupWeaveInitialXStarts="{0 1 0 1 0 1 1 0 1 0 1 0}"
+-dupWeaveInitialPins="{ 2 17 5 20 8 13 6 11 9 14 2 17}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 05
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc500p.upp b/gs/lib/stc500p.upp
new file mode 100644
index 000000000..070a1f505
--- /dev/null
+++ b/gs/lib/stc500p.upp
@@ -0,0 +1,48 @@
+-supModel="Epson Stylus Color 500, 360x360DpI, not Weaved, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.0000 0.0008 0.0075 0.0155 0.0235 0.0331 0.0430 0.0540
+ 0.0625 0.0714 0.0804 0.0889 0.0973 0.1061 0.1143 0.1239
+ 0.1382 0.1551 0.1732 0.1956 0.2196 0.2488 0.2854 0.3215
+ 0.3633 0.4185 0.4841 0.5529 0.6284 0.7365 0.8529 1.0000
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0021 0.0152 0.0291 0.0418 0.0552 0.0681 0.0818
+ 0.0947 0.1082 0.1218 0.1347 0.1474 0.1607 0.1732 0.1877
+ 0.2029 0.2208 0.2393 0.2626 0.2866 0.3159 0.3528 0.3873
+ 0.4268 0.4797 0.5417 0.6042 0.6712 0.7692 0.8714 1.0000
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0021 0.0152 0.0291 0.0418 0.0552 0.0681 0.0818
+ 0.0947 0.1082 0.1218 0.1347 0.1474 0.1607 0.1732 0.1877
+ 0.2029 0.2208 0.2393 0.2626 0.2866 0.3159 0.3528 0.3873
+ 0.4268 0.4797 0.5417 0.6042 0.6712 0.7692 0.8714 1.0000
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0021 0.0152 0.0291 0.0418 0.0552 0.0681 0.0818
+ 0.0947 0.1082 0.1218 0.1347 0.1474 0.1607 0.1732 0.1877
+ 0.2029 0.2208 0.2393 0.2626 0.2866 0.3159 0.3528 0.3873
+ 0.4268 0.4797 0.5417 0.6042 0.6712 0.7692 0.8714 1.0000
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 01
+ 1b2855 0100 0A
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc500ph.upp b/gs/lib/stc500ph.upp
new file mode 100644
index 000000000..ad48edb34
--- /dev/null
+++ b/gs/lib/stc500ph.upp
@@ -0,0 +1,48 @@
+-supModel="Epson Stylus Color 500, 720x720DpI, not Weaved, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.0000 0.0003 0.0027 0.0056 0.0085 0.0120 0.0156 0.0196
+ 0.0227 0.0260 0.0292 0.0323 0.0354 0.0386 0.0416 0.0450
+ 0.0503 0.0564 0.0630 0.0711 0.0799 0.0905 0.1038 0.1169
+ 0.1321 0.1522 0.1761 0.2011 0.2285 0.2678 0.3102 0.3637
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0008 0.0055 0.0106 0.0152 0.0201 0.0248 0.0298
+ 0.0344 0.0393 0.0443 0.0490 0.0536 0.0585 0.0630 0.0683
+ 0.0738 0.0803 0.0870 0.0955 0.1042 0.1149 0.1283 0.1408
+ 0.1552 0.1744 0.1970 0.2197 0.2441 0.2797 0.3169 0.3637
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 01
+ 1b2855 0100 05
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc600ih.upp b/gs/lib/stc600ih.upp
new file mode 100644
index 000000000..e3dbee686
--- /dev/null
+++ b/gs/lib/stc600ih.upp
@@ -0,0 +1,58 @@
+-supModel="Epson Stylus Color 600, 1440x720DpI, Inkjet Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2XY
+-r1440x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupCyanTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupMagentaTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupYellowTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveXPasses=2
+-dupOutputXStep=2
+-dupWeaveYPasses=8
+-dupOutputPins=30
+-dupWeaveYFeeds="{15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15}"
+-dupWeaveXStarts="{0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0}"
+-dupWeaveYOffset=38
+-dupWeaveInitialYFeeds="{ 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 15}"
+-dupWeaveInitialXStarts="{0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0}"
+-dupWeaveInitialPins="{ 15 9 18 12 6 15 9 18 27 21 30 24 18 27 21 30}"
+-dupFormatYabsolute
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 05
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+ 1b5501
+ 1b2865 0200 0002
+ 1b284b 0200 0002
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupXStepCommand="<1b285c 0400 a005 0100 0000>"
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc600p.upp b/gs/lib/stc600p.upp
new file mode 100644
index 000000000..d28891f8e
--- /dev/null
+++ b/gs/lib/stc600p.upp
@@ -0,0 +1,34 @@
+-supModel="Epson Stylus Color 600, 720x720DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{ 0.0000 0.0329 0.0706 0.1160 0.2392 0.7955 }"
+-dupCyanTransfer="{ 0.0000 0.0452 0.0836 0.1215 0.1493 0.1749 }"
+-dupMagentaTransfer="{ 0.0000 0.0602 0.1133 0.1961 0.2945 0.3885 }"
+-dupYellowTransfer="{ 0.0000 0.0350 0.0914 0.1567 0.2430 0.2934 }"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveYPasses=8
+-dupOutputPins=32
+-dupWeaveYFeeds="{31 31 31 31 37 33 33 29}"
+-dupWeaveInitialYFeeds="{1 1 1 1 1 1 1 25}"
+-dupWeaveInitialPins="{ 4 24 28 32 19 15 11 7}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 05
+ 1b5501
+ 1b2865 0200 0002
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc600pl.upp b/gs/lib/stc600pl.upp
new file mode 100644
index 000000000..c1586d0b9
--- /dev/null
+++ b/gs/lib/stc600pl.upp
@@ -0,0 +1,34 @@
+-supModel="Epson Stylus Color 600, 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{ 0.0000 0.0553 0.1158 0.1998 0.4321 1.0000 }"
+-dupCyanTransfer="{ 0.0000 0.1188 0.2272 0.3745 0.5396 0.6145 }"
+-dupMagentaTransfer="{ 0.0000 0.0851 0.1512 0.2111 0.2606 0.2818 }"
+-dupYellowTransfer="{ 0.0000 0.0679 0.1742 0.3129 0.4587 0.5389 }"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveYPasses=4
+-dupOutputPins=32
+-dupWeaveYFeeds="{33 30 35 30}"
+-dupWeaveInitialYFeeds="{1 1 1 29}"
+-dupWeaveInitialPins="{ 8 16 32 23}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 0A
+ 1b5501
+ 1b2865 0200 0002
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc800ih.upp b/gs/lib/stc800ih.upp
new file mode 100644
index 000000000..4111982f9
--- /dev/null
+++ b/gs/lib/stc800ih.upp
@@ -0,0 +1,58 @@
+-supModel="Epson Stylus Color 800, 1440x720DpI, Inkjet Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2XY
+-r1440x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupCyanTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupMagentaTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupYellowTransfer="{
+ 0.00000000 0.00627451 0.01254902 0.02196078 0.02980392 0.03764706 0.04549020
+ 0.05490196 0.06431373 0.07215686 0.08156863 0.09098039 0.10196078 0.11450980
+ 0.12862745 0.14588235 0.16313725 0.18509804 0.20862745 0.25411765 0.40000000
+}"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveXPasses=2
+-dupOutputXStep=2
+-dupWeaveYPasses=4
+-dupOutputPins=62
+-dupWeaveYFeeds="{31 31 31 31 31 31 31 31}"
+-dupWeaveXStarts="{0 1 0 1 1 0 1 0}"
+-dupWeaveYOffset=18
+-dupWeaveInitialYFeeds="{ 3 3 3 3 3 3 3 31}"
+-dupWeaveInitialXStarts="{0 1 0 1 1 0 1 0}"
+-dupWeaveInitialPins="{ 13 20 27 34 41 48 55 62}"
+-dupFormatYabsolute
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 05
+ 1b2873 0100 02
+ 1b5501
+ 1b2865 0200 0001
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupXStepCommand="<1b285c 0400 a005 0100 0000>"
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc800p.upp b/gs/lib/stc800p.upp
new file mode 100644
index 000000000..7f7ba1821
--- /dev/null
+++ b/gs/lib/stc800p.upp
@@ -0,0 +1,34 @@
+-supModel="Epson Stylus Color 800, 720x720DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{ 0.0000 0.0329 0.0706 0.1160 0.2392 0.7955 }"
+-dupCyanTransfer="{ 0.0000 0.0602 0.1133 0.1961 0.2945 0.3885 }"
+-dupMagentaTransfer="{ 0.0000 0.0452 0.0836 0.1215 0.1493 0.1749 }"
+-dupYellowTransfer="{ 0.0000 0.0350 0.0914 0.1567 0.2430 0.2934 }"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveYPasses=4
+-dupOutputPins=64
+-dupWeaveYFeeds="{63 63 67 63}"
+-dupWeaveInitialYFeeds="{1 1 1 61}"
+-dupWeaveInitialPins="{ 16 64 47 31}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 05
+ 1b5501
+ 1b2865 0200 0002
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc800pl.upp b/gs/lib/stc800pl.upp
new file mode 100644
index 000000000..1b4c540a2
--- /dev/null
+++ b/gs/lib/stc800pl.upp
@@ -0,0 +1,34 @@
+-supModel="Epson Stylus Color 800, 360x360DpI, Plain Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupBlackTransfer="{ 0.0000 0.0553 0.1158 0.1998 0.4321 1.0000 }"
+-dupCyanTransfer="{ 0.0000 0.1188 0.2272 0.3745 0.5396 0.6145 }"
+-dupMagentaTransfer="{ 0.0000 0.0851 0.1512 0.2111 0.2606 0.2818 }"
+-dupYellowTransfer="{ 0.0000 0.0679 0.1742 0.3129 0.4587 0.5389 }"
+-dupOutputComponentOrder="{ 1 2 3 0 }"
+-dupWeaveYPasses=2
+-dupOutputPins=64
+-dupWeaveYFeeds="{63 65}"
+-dupWeaveInitialYFeeds="{1 65}"
+-dupWeaveInitialPins="{ 33 64}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2855 0100 0A
+ 1b5501
+ 1b2865 0200 0002
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc_h.upp b/gs/lib/stc_h.upp
new file mode 100644
index 000000000..a7e718911
--- /dev/null
+++ b/gs/lib/stc_h.upp
@@ -0,0 +1,53 @@
+-supModel="Epson Stylus Color I (and PRO Series), 720x720DpI, Special Paper"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/FSCMYK32
+-dupOutputFormat=/EscP2
+-r720x720
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupWeaveYPasses=8
+-dupOutputPins=15
+-dupWeaveYFeeds="{15 15 15 15 15 15 15 15}"
+-dupWeaveInitialYFeeds="{1 1 1 1 1 1 1 8}"
+-dupWeaveInitialPins="{ 15 13 11 9 7 5 3 1}"
+-dupBlackTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupCyanTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupMagentaTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupYellowTransfer="{
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 05
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
+
diff --git a/gs/lib/stc_l.upp b/gs/lib/stc_l.upp
new file mode 100644
index 000000000..31d61208e
--- /dev/null
+++ b/gs/lib/stc_l.upp
@@ -0,0 +1,26 @@
+-supModel="Epson Stylus Color I (and PRO Series), 360x360DpI, noWeave"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupComponentBits="{1 1 1 1}"
+-dupWeaveYPasses=4
+-dupOutputPins=15
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 00
+ 1b2855 0100 0A
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
diff --git a/gs/lib/stcany.upp b/gs/lib/stcany.upp
new file mode 100644
index 000000000..94319d4ca
--- /dev/null
+++ b/gs/lib/stcany.upp
@@ -0,0 +1,24 @@
+-supModel="Any Epson Stylus Color, 360x360DpI"
+-sDEVICE=uniprint
+-dNOPAUSE
+-dSAFER
+-dupColorModel=/DeviceCMYKgenerate
+-dupRendering=/ErrorDiffusion
+-dupOutputFormat=/EscP2
+-r360x360
+-dupMargins="{ 9.0 39.96 9.0 9.0}"
+-dupComponentBits="{1 1 1 1}"
+-dupBeginPageCommand="<
+ 1b40 1b40
+ 1b2847 0100 01
+ 1b2869 0100 01
+ 1b2855 0100 0A
+ 1b5500
+ 1b2843 0200 0000
+ 1b2863 0400 0000 0000
+>"
+-dupAdjustPageLengthCommand
+-dupAdjustTopMarginCommand
+-dupAdjustBottomMarginCommand
+-dupEndPageCommand="(\033@\014)"
+-dupAbortCommand="(\033@\15\12\12\12\12 Printout-Aborted\15\014)"
diff --git a/gs/lib/stcinfo.ps b/gs/lib/stcinfo.ps
new file mode 100644
index 000000000..7695d1b5a
--- /dev/null
+++ b/gs/lib/stcinfo.ps
@@ -0,0 +1,799 @@
+% Copyright (C) 1995 Aladdin Enterprises. All rights reserved
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% stcinfo.ps
+% Epson Stylus-Color Printer-Driver
+
+% The purpose of this file is to print & show Parameters of the
+% stcolor-driver. If not run on ghostscript/stcolor, it prints
+% something like a color-chart.
+
+% use either existing STCinfo-dictionary, retrieve new one or create dummy
+
+statusdict begin product end
+dup (Ghostscript) eq exch (Aladdin Ghostscript) eq or{
+
+ currentdevice getdeviceprops .dicttomark
+ dup /Name get (stcolor) eq /STCi_onstc exch def
+ /STCinfo where {/STCinfo get exch pop} if
+ /STCinfo exch def
+
+}{
+
+ /STCinfo 10 dict def
+ STCinfo begin /Name (unknown) def end
+ /STCi_onstc false def
+
+}ifelse
+
+% Next Block are procedures to generate the color-triangles.
+% you may wish to separate them, just look ahead for the name
+% given in the next line to achieve that.
+% Begin: colortri_procedures
+
+% Plot the CIE-XY-triangle (or something like that)
+
+% /colortri_mat Conversion matrix RGB -> XYZ
+% /colortri_bg procedure, that takes X/Y-Values and delivers the
+% "background color" as RGB-Values, default is:
+% {pop pop 0.85 dup dup}
+
+% The default matrix was taken from:
+% Color spaces FAQ - David Bourgin
+% Date: 15/6/94 (items 5.3 and 6 updated)
+% Last update: 29/6/94
+
+ /colortri_mat [ % RGB -> CIE XYZitu601-1 (D65)
+ 0.4306 0.3415 0.1784
+ 0.2220 0.7067 0.0713
+ 0.0202 0.1295 0.9394
+ ] def
+
+ /colortri_bg {pop pop 0.85 dup dup} bind def
+
+
+% +---------------------------------------------------------------------+
+% | Besides from fixing bugs, nothing should be changed below this line |
+% +---------------------------------------------------------------------+
+
+
+% Arbitrary operation on a pair of vectors, *CHANGES* 1st.
+% invoke: Vaccu Vop op vop
+ /vop {
+ bind 0 1 3 index length 1 sub {
+ 3 index 1 index get 3 index 2 index get 3 index exec 4 index 3 1 roll put
+ } for pop pop
+ } bind def
+
+ /vsub { {sub} vop } bind def % subtract two vectors
+ /vmul { {mul} vop } bind def % multiply two vectors
+
+% Compute sum of vectors elements
+ /vsum {0.0 exch{add}forall} bind def
+
+
+% Sum up products of elements
+ /veqn { [ 3 -1 roll {} forall ] exch vmul vsum } bind def
+
+% Find index of |maximum| in array
+ /imax {
+ dup 0 get abs 0 exch % array i v[i]
+ 1 1 4 index length 1 sub {
+ 3 index 1 index get abs dup 3 index gt {4 2 roll}if pop pop
+ } for
+ 3 -1 roll pop
+ } bind def
+
+% Procedure to *CHANGE* RGB-Values into XYZ-Values
+ /rgb2xyz {
+ 0 3 6 { colortri_mat exch 3 getinterval 1 index veqn exch } for astore
+ } bind def
+
+% Procedure to *CHANGE* transform rgb->xy
+ /rgb2xy {
+ rgb2xyz
+ dup 0 get 1 index 1 get 2 index vsum % XYZ X Y sum
+ dup 0 ne {
+ exch 1 index div 3 1 roll div % XYZ y x
+ 2 index exch 0 exch put % xYZ y
+ 1 index exch 1 exch put % xyZ
+ }{
+ pop pop pop dup 0 0 put dup 0 1 put
+ } ifelse
+ 0 2 getinterval
+ } bind def
+
+% So here we go with our procedure
+
+/colortri { %Usage: box #pixels
+ save
+ 1 index type /arraytype eq {exch 8}{3 1 roll} ifelse % Default scale
+ /colortri_scale exch def
+ /colortri_box exch def
+
+
+% Prepare some useful constants for xy -> RGB conversion
+
+ /colsum [ % Array with column-sums
+ 0 1 2{0 exch 3 1 index 6 add{colortri_mat exch get add}for}for
+ ] def
+
+ /Xrow colortri_mat 0 3 getinterval def % two rows from colortri_mat
+ /Yrow colortri_mat 3 3 getinterval def
+
+% Avoid allocating new arrays
+ /xcoeff 3 array def
+ /ycoeff 3 array def
+
+% Procedure to derive RGB-Values form X,Y
+ /xy2rgb{ aload pop
+ dup dup dup ycoeff astore colsum vmul Yrow vsub imax
+ 3 index dup dup xcoeff astore colsum vmul Xrow vsub imax
+ 3 -1 roll 1 index 1 index gt{
+ xcoeff ycoeff /xcoeff exch def /ycoeff exch def pop 3 -1 roll pop
+ }{
+ 3 1 roll pop pop
+ } ifelse
+ 1e-6 lt { % No Pivot ?
+ pop colortri_bg xcoeff astore pop
+ }{ % Have a Pivot
+ dup ycoeff exch get neg
+ 0 1 2 { dup ycoeff exch get 2 index div ycoeff 3 1 roll put} for
+ pop ycoeff 1 index 0 put
+
+ xcoeff 1 index get
+ 0 1 2 {
+ ycoeff 1 index get 2 index mul xcoeff 2 index get add
+ xcoeff 3 1 roll put
+ } for
+ pop xcoeff 1 index 0 put
+ xcoeff imax 1e-6 lt { % no Pivot ?
+ pop pop colortri_bg xcoeff astore pop
+ }{
+ dup 2 index or 3 exch sub
+ xcoeff 1 index get xcoeff 3 index get div neg
+ xcoeff exch 3 index exch put
+ xcoeff 1 index 1 put
+ ycoeff exch get ycoeff 2 index get xcoeff 4 -1 roll get mul add
+ xcoeff 3 1 roll put
+ 0 1 2 {
+ xcoeff exch get dup -0.0015 lt exch 1.0015 gt or {
+ colortri_bg xcoeff astore dup exit
+ } if
+ } for
+ pop pop xcoeff
+ } ifelse
+ } ifelse
+ } bind def
+
+% Compute the displayed range
+ [ 1 1 1 ] rgb2xy
+ dup 0 get /colortri_x0 exch def /colortri_dx colortri_x0 def
+ 1 get /colortri_y0 exch def /colortri_dy colortri_y0 def
+ [[0 0 1][0 1 0][0 1 1][1 0 0][1 0 1][1 1 0]] {
+ rgb2xy
+ dup 0 get
+ dup colortri_x0 lt {/colortri_x0 1 index def}if
+ dup colortri_dx gt {/colortri_dx 1 index def}if
+ pop 1 get
+ dup colortri_y0 lt {/colortri_y0 1 index def}if
+ dup colortri_dy gt {/colortri_dy 1 index def}if
+ pop
+ } forall
+ colortri_dx colortri_x0 sub /colortri_dx exch def
+ colortri_dy colortri_y0 sub /colortri_dy exch def
+%
+
+% determine the scale
+ colortri_box 2 get colortri_box 0 get sub colortri_dx div % fx
+ colortri_box 3 get colortri_box 1 get sub colortri_dy div % fx fy
+ gt { % fy limits
+ colortri_box 3 get colortri_box 1 get sub
+ dup colortri_dx mul colortri_dy div exch
+ }{ % fx limits
+ colortri_box 2 get colortri_box 0 get sub
+ dup colortri_dy mul colortri_dx div
+ } ifelse
+ dtransform abs colortri_scale div cvi /colortri_ny exch def
+ abs colortri_scale div cvi /colortri_nx exch def
+ colortri_nx colortri_scale mul colortri_ny colortri_scale mul
+ idtransform abs exch abs exch
+ colortri_box 0 get colortri_box 2 get 1 index sub 3 index sub 2 div add
+ colortri_box 1 get colortri_box 3 get 1 index sub 3 index sub 2 div add
+ transform .5 add cvi exch .5 add cvi exch itransform
+ translate scale
+
+% String & indices
+ /colortri_tmp colortri_nx 3 mul string def
+ /colortri_dx colortri_dx colortri_nx 1 sub div def
+ /colortri_dy colortri_dy colortri_ny 1 sub div def
+ /colortri_xy [ colortri_x0 colortri_y0 ] def
+ /colortri_ie colortri_tmp length 3 sub def
+
+ colortri_nx colortri_ny 8 [ colortri_nx 0 0 colortri_ny 0 0 ]
+ {
+ colortri_xy 0 colortri_x0 put
+ 0 3 colortri_ie {
+ colortri_tmp exch % buf ir
+ colortri_xy xy2rgb % buf ir rgb buf ib
+ 2 index 2 index 2 add 2 index 2 get 255 mul cvi put
+ 2 index 2 index 1 add 2 index 1 get 255 mul cvi put
+ 0 get 255 mul cvi put
+ colortri_xy dup 0 exch 0 get colortri_dx add put
+ }for
+ colortri_xy dup 1 exch 1 get colortri_dy add put
+ colortri_tmp
+ } bind
+ false 3 colorimage
+ restore
+} bind def
+
+% [ newpath clippath pathbbox ] colortri showpage % standalone usage
+
+% End: colortri_procedures
+
+% The next section is a group of procedures, that I for myself
+% do no more fully understand, but they do the Job.
+
+% Begin: stcinfo_procedures_1
+
+% fetch a parameter from the dictionary
+/STCiget { STCinfo exch get } bind def
+
+% action upon ProcessColorModel
+/STCimode {
+ /ProcessColorModel STCiget dup
+ /DeviceCMYK eq{pop 2}{/DeviceRGB eq{1}{0}ifelse}ifelse get exec
+} bind def
+
+% print given number of blanks
+/STCipspace {
+ dup 0 gt{ 1 exch 1 exch { pop ( ) print}for }{ pop } ifelse
+} bind def
+
+% print right or left-justified text
+/STCiprint {
+ dup 0 gt { dup 2 index length sub STCipspace } if
+ 1 index print
+ dup 0 lt { neg dup 2 index length sub STCipspace } if
+ pop pop
+} bind def
+
+% floating-point to fixed-length-string conversion
+
+/STCicvs { % number -> string
+
+% Prepare the result
+ 8 string dup 0 ( ) putinterval
+ exch
+
+% Make it unsigned
+ dup 0 lt {neg(-)}{( )}ifelse 0 get exch
+
+ dup 1000 lt 1 index 0 eq 2 index 0.001 ge or and { % floating point
+ (e+) 0
+ }{ % engineering
+ 0 {
+ 1 index 1000.0 ge
+ {3 add exch 1000 div exch}
+ {1 index 1 lt {3 sub exch 1000 mul exch}{exit}ifelse}
+ ifelse
+ }loop
+ dup 0 lt {neg(e-)}{(e+)}ifelse exch
+ }ifelse
+
+% string sign num esig e
+
+% always up to three Integer Digits plus sign
+ 2 index cvi 3 { % string sign num esig e int ind
+ 1 index 10 div cvi dup 10 mul 3 index exch sub cvi
+ (0123456789) exch get 8 index exch 3 index exch put
+ 3 -2 roll 1 sub exch pop dup 0 eq 2 index 0 eq or {exit} if
+ } loop exch pop % string sign num esig e ind
+ 5 index exch 6 -1 roll put % string num esig e
+
+% print either fraction or exponent
+ dup 0 eq { pop pop dup cvi sub % String fraction
+
+ dup 0.0 ne { % Fraction present
+ 0.0005 add 1 index 4 (.) putinterval
+ 5 1 7 { % string frac ind
+ exch 10 mul dup cvi exch 1 index sub % string ind ic nfrac
+ exch (0123456789) exch get 3 -1 roll % string nfrac chr ind
+ exch 3 index 3 1 roll put
+ } for
+ } if
+ pop
+
+ }{ 3 -1 roll pop % string esig e
+
+ exch 2 index exch 4 exch putinterval
+ 7 -1 6 { % string n i
+ 1 index 10 div cvi dup 10 mul 3 index exch sub cvi % string n i n/10
+ (0123456789) exch get 4 index exch 3 index exch put
+ exch pop exch pop
+ } for
+ pop
+ } ifelse
+
+} bind def
+
+% compute colorvalue-steps from transfer & coding
+/STCisteps { % xfer, coding => X-values, Y-Values
+% 2^nbits
+ 2 /BitsPerComponent STCiget dup 11 gt { pop 11 } if exp cvi
+
+% X & Y - Arrays (stack: xv:4 yv:3 xfer:2 coding:1 2^ni:0)
+ dup 1 add array 1 index array 5 2 roll
+
+% compute GS-Color-Value according to the coding-array
+
+ 1 index null eq { % no coding present
+
+ 0 1 2 index 1 sub {
+ dup 6 index exch dup 4 index div put
+ 4 index exch dup 3 index 1 sub div put
+ } for
+
+ }{ % coding-array given
+
+ 1.0 1 index 1 sub div % y step
+ 0 % current index
+ 0 1 4 index 1 sub { % over indices
+ dup 3 index mul
+ {
+ dup 3 index 1 add dup 8 index length ge {pop pop exit} if % i y
+ 7 index exch get le {exit} if
+ 2 index 1 add 3 1 roll 4 -1 roll pop
+ } loop
+ 5 index 3 index get sub
+ 5 index 3 index 1 add get 6 index 4 index get sub div
+ 2 index add 5 index length 1 sub div
+ 2 copy exch dup 0 eq {
+ 10 index exch 0.0 put pop
+ }{
+ dup 10 index exch 1 sub get 3 -1 roll add 2 div
+ 10 index 3 1 roll put
+ }ifelse
+ 7 index 3 1 roll put
+ } for % over indices
+ pop pop
+ } ifelse
+ 4 index 1 index 1.0 put
+
+% Replace the raw y-values by those computed from the transfer-array
+
+ 0 1 2 index 1 sub { % over indices, 2nd
+ dup 5 index exch get
+ dup 5 index length 1 sub mul cvi % -> iy
+ 5 index 1 index get
+ 1 index 1 add 7 index length lt {
+ dup 7 index 3 index 1 add get exch sub
+ 3 index 3 index 9 index length 1 sub div sub mul
+ 7 index length 1 sub mul add
+ } if
+ exch pop exch pop 5 index 3 1 roll put
+ } for % over indices, 2nd
+
+ pop pop pop
+} bind def
+
+/STCibar { % Window X-Values proc => Window
+ 0 1 3 index length 2 sub {
+ dup 3 index exch get exch
+ 1 add 3 index exch get
+ dup 2 index add 2 div 3 index exec % Color to average
+ 4 index 2 get 5 index 0 get sub exch 1 index mul 5 index 0 get add 3 1 roll
+ mul 4 index 0 get add 4 index 3 get 5 index 1 get
+ newpath
+ 2 index 1 index moveto
+ 3 index 1 index lineto
+ 3 index 2 index lineto
+ 2 index 2 index lineto
+ closepath fill
+ pop pop pop pop
+ } for
+ pop pop
+ 0 setgray
+ newpath
+ dup 0 get 1 index 1 get moveto
+ dup 2 get 1 index 1 get lineto
+ dup 2 get 1 index 3 get lineto
+ dup 0 get 1 index 3 get lineto
+ closepath stroke
+ pop
+} bind def
+
+% End: stcinfo_procedures_1
+
+% Begin: stcinfo_preparation
+
+% Compute used area from clippath
+
+/STCi_clip [
+ newpath clippath pathbbox
+ 2 sub 4 1 roll 2 sub 4 1 roll 2 add 4 1 roll 2 add 4 1 roll
+] def
+
+%
+% Perpare the texual messages, assume no stcolor if this fails
+%
+{
+ /STCi_stopped % A Special Mark
+
+% Textual Parameters (an array of pairs of strings)
+ /STCi_l1 0 def
+ /STCi_l2 0 def
+ /STCi_text [
+% Driver-Name & Version
+ (Parameters of)
+ /Name STCiget length /Version STCiget length add 1 add string
+ dup 0 /Name STCiget putinterval dup /Name STCiget length (-)putinterval
+ dup /Name STCiget length 1 add /Version STCiget putinterval
+% Dithering-Algorithm
+ (Dithering)
+ /Dithering STCiget
+ [{( \(Monochrome\))}{( \(RGB\))}{( \(CMYK\))}] STCimode
+ dup length 2 index length add string exch 1 index exch
+ 3 index length exch putinterval dup 3 1 roll exch 0 exch putinterval
+% Flags for the algorithm
+ (Flag4-0) 5 string
+ dup 0 /Flag4 STCiget {(T)}{(f)} ifelse putinterval
+ dup 1 /Flag3 STCiget {(T)}{(f)} ifelse putinterval
+ dup 2 /Flag2 STCiget {(T)}{(f)} ifelse putinterval
+ dup 3 /Flag1 STCiget {(T)}{(f)} ifelse putinterval
+ dup 4 /Flag0 STCiget {(T)}{(f)} ifelse putinterval
+
+% Bits Per Pixel & Bits Per Component
+ (BitsPerPixel) 10 string % (nn -> nxnn)
+ /BitsPerPixel STCiget 1 index cvs length % string used
+ dup 2 index exch ( -> ) putinterval 4 add dup 2 add exch 2 index exch
+ [{(1x)}{(3x)}{(4x)}] STCimode putinterval % String used
+ /BitsPerComponent STCiget 2 index 2 index 2 getinterval cvs length add
+ 0 exch getinterval
+
+ () ()
+% ColorAdjustMatrix
+ (ColorAdjustMatrix)
+ /ColorAdjustMatrix STCiget dup null eq {
+ pop (default)
+ }{
+ { STCicvs } forall
+ [{ % Monochrome
+ 26 string
+ dup 0 6 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 5 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 4 -1 roll putinterval
+ }{ % RGB
+ 26 string
+ dup 0 12 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 11 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 10 -1 roll putinterval
+
+ () 26 string
+ dup 0 11 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 10 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 9 -1 roll putinterval
+
+ () 26 string
+ dup 0 10 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 9 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 8 -1 roll putinterval
+ }{
+ 35 string
+ dup 0 19 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 18 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 17 -1 roll putinterval dup 26 ( ) putinterval
+ dup 27 16 -1 roll putinterval
+
+ () 35 string
+ dup 0 17 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 16 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 15 -1 roll putinterval dup 26 ( ) putinterval
+ dup 27 14 -1 roll putinterval
+
+ () 35 string
+ dup 0 15 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 14 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 13 -1 roll putinterval dup 26 ( ) putinterval
+ dup 27 12 -1 roll putinterval
+
+ () 35 string
+ dup 0 13 -1 roll putinterval dup 8 ( ) putinterval
+ dup 9 12 -1 roll putinterval dup 17 ( ) putinterval
+ dup 18 11 -1 roll putinterval dup 26 ( ) putinterval
+ dup 27 10 -1 roll putinterval
+
+ }
+ ] STCimode
+ } ifelse
+ () ()
+
+% Printer Model
+ (Printer-Model) /Model STCiget
+
+% Resolution
+ (Resolution) 15 string % (nnnnnxnnnnn DpI)
+ /HWResolution STCiget 0 get cvi 1 index cvs length
+ dup 2 index exch (x) putinterval 1 add dup 2 index exch 5 getinterval
+ /HWResolution STCiget 1 get cvi exch cvs length add dup 2 index
+ exch ( DpI) putinterval 4 add 0 exch getinterval
+
+% HWsize holds entire Page in Pixels,
+% .HWMargins is [left,bottom,right,top] in Points
+ (Printed Area) 18 string % (nnnnnxnnnnn Pixel)
+ /HWSize STCiget 0 get /.HWMargins STCiget dup 0 get exch 2 get add
+ /HWResolution STCiget 0 get mul 72.0 div sub cvi 1 index cvs length
+ dup 2 index exch (x) putinterval 1 add dup 2 index exch 5 getinterval
+ /HWSize STCiget 1 get /.HWMargins STCiget dup 1 get exch 3 get add
+ /HWResolution STCiget 1 get mul 72.0 div sub cvi exch cvs length add
+ dup 2 index exch ( Pixel) putinterval 6 add 0 exch getinterval
+
+ () ()
+% WeaveMode
+ (Weave-Mode)
+ /noWeave STCiget {
+ (noWeave)
+ }{
+ /Microweave STCiget {(Microweave)}{(Softweave)}ifelse
+ }ifelse
+% Unidirectional
+ (Unidirectional) /Unidirectional STCiget {(ON)}{(off)} ifelse
+% Output coding
+ (OutputCode) /OutputCode STCiget
+% number of heads
+ (escp_Band) /escp_Band STCiget 3 string cvs
+ (escp_Width) /escp_Width STCiget 5 string cvs
+ (escp_Height) /escp_Height STCiget 5 string cvs
+ (escp_Top) /escp_Top STCiget 5 string cvs
+ (escp_Bottom) /escp_Bottom STCiget 5 string cvs
+ ] def
+
+%
+% compute the Proper X & Y-Arrays
+%
+ [{ % Monochrome
+ /Ktransfer STCiget /Kcoding STCiget STCisteps
+ /STCi_yv [ 3 -1 roll ] def
+ /STCi_xv [ 3 -1 roll ] def
+ /STCi_col [[0 0 0]] def
+ /STCi_set [{1.0 exch sub setgray}] def
+ }{ % RGB
+ /Rtransfer STCiget /Rcoding STCiget STCisteps
+ /Gtransfer STCiget /Gcoding STCiget STCisteps
+ /Btransfer STCiget /Bcoding STCiget STCisteps
+ exch 4 -1 roll 6 -1 roll exch 3 -1 roll
+ /STCi_xv [ 5 2 roll ] def
+ /STCi_yv [ 5 2 roll ] def
+ /STCi_col [[1 0 0] [0 1 0] [0 0 1]] def
+ /STCi_set [
+ {1.0 exch sub 1 exch dup setrgbcolor}
+ {1.0 exch sub dup 1 exch setrgbcolor}
+ {1.0 exch sub dup 1 setrgbcolor}
+ ] def
+ }{ % CMYK
+ /Ctransfer STCiget /Ccoding STCiget STCisteps
+ /Mtransfer STCiget /Mcoding STCiget STCisteps exch 3 1 roll
+ /Ytransfer STCiget /Ycoding STCiget STCisteps exch 4 1 roll
+ /Ktransfer STCiget /Kcoding STCiget STCisteps exch 5 1 roll
+ /STCi_yv [ 6 2 roll ] def
+ /STCi_xv [ 6 2 roll ] def
+ /STCi_col [[0 1 1] [1 0 1] [1.0 0.5 0.0] [0 0 0]] def
+ /STCi_set [
+ { 0 0 0 setcmykcolor }
+ { 0 exch 0 0 setcmykcolor }
+ { 0 exch 0 exch 0 setcmykcolor }
+ { 0 exch 0 exch 0 exch setcmykcolor }
+ ] def
+ }
+ ]STCimode
+
+} stopped
+
+{ {/STCi_stopped eq {exit}if}loop true}
+{ {/STCi_stopped eq {exit}if}loop false} ifelse
+
+% End: stcinfo_preparation
+
+% The Next section does the real job
+
+% Begin: stcinfo_execution
+{
+ (%%[ stcinfo.ps: currentdevice is not supported -> colortri ]%%\n) print
+ STCi_clip colortri % The default action
+
+}{
+%
+% Print the text
+%
+ 0 2 STCi_text length 2 sub { dup 1 add exch
+ STCi_text exch get length dup STCi_l1 gt{/STCi_l1 exch def}{pop}ifelse
+ STCi_text exch get length dup STCi_l2 gt{/STCi_l2 exch def}{pop}ifelse
+ } for
+ /STCi_l2 STCi_l2 neg def
+ 0 2 STCi_text length 2 sub {
+ dup 1 add STCi_text exch get exch STCi_text exch get
+ 1 index length 0 gt {
+ dup STCi_l1 STCiprint length 0 gt {(: )}{( )}ifelse print print
+ }{
+ pop pop
+ } ifelse
+ (\n) print
+ } for
+%
+% Deactivate a present ColorAdjust Matrix, if any
+%
+ /ColorAdjustMatrix STCiget null ne STCi_onstc and {
+ mark
+ /ColorAdjustMatrix null
+ currentdevice putdeviceprops pop
+ } if
+%
+% "Show" the text
+%
+ /Times-Roman findfont 10 scalefont setfont
+ /STCi_l1 0 def
+ 0 2 STCi_text length 2 sub {
+ STCi_text exch get stringwidth pop dup STCi_l1 gt {
+ /STCi_l1 exch def
+ }{
+ pop
+ } ifelse
+ } for
+ STCi_l1 STCi_clip 0 get add /STCi_l1 exch def
+
+ STCi_clip 3 get 12 sub
+ 0 2 STCi_text length 2 sub {
+ STCi_text exch get dup length 0 gt {
+ dup stringwidth pop STCi_l1 exch sub 2 index moveto show
+ }{
+ pop
+ } ifelse
+ 12 sub
+ } for
+ pop
+
+ /Courier findfont 10 scalefont setfont
+ /STCi_l2 0 def
+ 1 2 STCi_text length 1 sub {
+ STCi_text exch get stringwidth pop dup STCi_l2 gt {
+ /STCi_l2 exch def
+ }{
+ pop
+ } ifelse
+ } for
+
+ STCi_clip 3 get 12 sub
+ 1 2 STCi_text length 1 sub {
+ STCi_text exch get dup length 0 gt {
+ STCi_l1 12 add 2 index moveto show
+ }{
+ pop
+ } ifelse
+ 12 sub
+ } for
+ pop
+
+%
+% compute the space for the graph-window
+%
+ STCi_l1 12 add STCi_l2 add 12 add dup STCi_clip 2 get exch sub % Extend
+ [ 3 -1 roll dup 3 index add STCi_clip 3 get dup 5 index sub 3 1 roll ]
+ /STCi_win exch def /STCi_l1 exch def
+
+% The "Axis"
+ newpath
+ STCi_win 0 get STCi_win 1 get 14 add moveto
+ STCi_win 2 get STCi_win 1 get 14 add lineto stroke
+
+ STCi_win 0 get 14 add STCi_win 1 get moveto
+ STCi_win 0 get 14 add STCi_win 3 get lineto stroke
+
+% The Labels
+ /Times-Roman findfont 10 scalefont setfont
+ (Postscript-color) dup stringwidth pop
+ STCi_win 2 get STCi_win 0 get sub 14 sub 1 index sub 2 div exch pop
+ STCi_win 0 get add 14 add STCi_win 1 get 4 add moveto show
+
+ gsave
+ STCi_win 0 get 10 add STCi_win 1 get 14 add translate 90 rotate
+ (Device-color) dup stringwidth pop
+ STCi_win 3 get STCi_win 1 get sub 14 sub 1 index sub 2 div exch pop
+ 0 moveto show
+ grestore
+
+% The Graphs
+ gsave
+ STCi_win 0 get 14 add STCi_win 1 get 14 add
+ STCi_win 2 get 2 index sub STCi_win 3 get 2 index sub
+ 4 2 roll translate
+ STCi_col 0 1 2 index length 1 sub {
+ 1 index 1 index get aload pop setrgbcolor
+ STCi_xv 1 index get STCi_yv 3 -1 roll get
+ newpath
+ 1 index 0 get 5 index mul 1 index 0 get 5 index mul moveto
+ 1 index 1 get 5 index mul 1 index 0 get 5 index mul lineto
+ 1 1 2 index length 1 sub {
+ 2 index 1 index get 6 index mul
+ 2 index 2 index get 6 index mul lineto
+ 2 index 1 index 1 add get 6 index mul
+ 2 index 2 index get 6 index mul lineto
+ pop
+ } for
+ stroke pop pop
+ } for
+ pop pop pop
+ grestore
+
+%
+% Find lowest Y from Text or graph
+%
+ STCi_win 1 get STCi_clip 3 get STCi_text length 2 div 12 mul sub
+ dup 2 index gt { pop } { exch pop } ifelse 12 sub
+
+%
+% compute the upper bar-window
+%
+ /STCi_win [
+ STCi_clip 0 get 4 -1 roll 36 sub STCi_clip 2 get 1 index 36 add
+ ] def
+
+%
+% Draw the required number of graphs
+%
+ [{ % Monochrome
+ STCi_win STCi_xv 0 get {setgray} STCibar
+ }{ % RGB
+ STCi_win STCi_xv 0 get {0 0 setrgbcolor} STCibar
+ STCi_win dup 1 exch 1 get 47 sub put
+ STCi_win dup 3 exch 3 get 47 sub put
+ STCi_win STCi_xv 1 get {0 0 3 1 roll setrgbcolor} STCibar
+ STCi_win dup 1 exch 1 get 47 sub put
+ STCi_win dup 3 exch 3 get 47 sub put
+ STCi_win STCi_xv 2 get {0 0 3 2 roll setrgbcolor} STCibar
+ }{ % CMYK
+ STCi_win STCi_xv 0 get {0 0 0 setcmykcolor} STCibar
+ STCi_win dup 1 exch 1 get 47 sub put
+ STCi_win dup 3 exch 3 get 47 sub put
+ STCi_win STCi_xv 1 get {0 0 0 4 1 roll setcmykcolor} STCibar
+ STCi_win dup 1 exch 1 get 47 sub put
+ STCi_win dup 3 exch 3 get 47 sub put
+ STCi_win STCi_xv 2 get {0 0 0 4 2 roll setcmykcolor} STCibar
+ STCi_win dup 1 exch 1 get 47 sub put
+ STCi_win dup 3 exch 3 get 47 sub put
+ STCi_win STCi_xv 3 get {0 0 0 4 3 roll setcmykcolor} STCibar
+ }
+ ] STCimode
+
+ STCi_win 1 STCi_clip 1 get put
+ STCi_win dup 3 exch 3 get 47 sub put
+
+%
+% Plot either one or two Color-Triangles
+%
+ /ColorAdjustMatrix STCiget null ne STCi_onstc and {
+ STCi_win 0 get STCi_win 2 get add 2 div
+ [STCi_win 0 get STCi_win 1 get 3 index STCi_win 3 get ] colortri
+ mark /ColorAdjustMatrix dup STCiget currentdevice putdeviceprops pop
+ [1 index STCi_win 1 get STCi_win 2 get STCi_win 3 get ] colortri
+ pop
+ }{
+ STCi_win colortri
+ } ifelse
+ newpath clippath stroke
+} ifelse
+showpage
diff --git a/gs/lib/stcolor.ps b/gs/lib/stcolor.ps
new file mode 100644
index 000000000..4ddbc89dd
--- /dev/null
+++ b/gs/lib/stcolor.ps
@@ -0,0 +1,171 @@
+% Copyright (C) 1995 Aladdin Enterprises. All rights reserved
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% stcolor.ps
+% Epson Stylus-Color Printer-Driver
+
+% The purpose of this file is to configure the stcolor-printer driver
+
+%
+% It is useless and dangerous to interpret the following code with anything
+% else than Ghostscript, so this condition is verified first. If this fails
+% a message is send to the output. If this message bothers you, remove it,
+% but I prefer to know why the device-setup failed.
+
+statusdict begin product end
+dup (Ghostscript) eq exch (Aladdin Ghostscript) eq or{
+
+% fetch the current device-parameters this is specific for Ghostscript.
+
+ /STCold currentdevice getdeviceprops .dicttomark def
+
+% Any Ghostscript-Driver has a Name, verify that the selected device is
+% stcolor, otherwise nothing than another message will be produced.
+
+ STCold /Name get (stcolor) eq {
+
+%
+% The main thing this file does, is to establish transfer-functions.
+% Here are two predefined arrays for 360x360Dpi and for 720x720DpI.
+% If resolution is 360x720 or 720x360 the average is used. You may
+% want to define other arrays here.
+%
+
+ /STCdeftransfer [ 0.0 1.0 ] def
+
+ /STCKtransfer360 [
+ 0.0000 0.0034 0.0185 0.0377 0.0574 0.0769 0.0952 0.1147
+ 0.1337 0.1540 0.1759 0.1985 0.2209 0.2457 0.2706 0.2949
+ 0.3209 0.3496 0.3820 0.4145 0.4505 0.4907 0.5344 0.5840
+ 0.6445 0.7093 0.8154 0.9816 0.9983 0.9988 0.9994 1.0000
+ ] def
+
+ /STCKtransfer720 [
+ 0.0000 0.0011 0.0079 0.0151 0.0217 0.0287 0.0354 0.0425
+ 0.0492 0.0562 0.0633 0.0700 0.0766 0.0835 0.0900 0.0975
+ 0.1054 0.1147 0.1243 0.1364 0.1489 0.1641 0.1833 0.2012
+ 0.2217 0.2492 0.2814 0.3139 0.3487 0.3996 0.4527 0.5195
+ ] def
+
+% compute the resolution
+
+ STCold /HWResolution get dup
+ 0 get exch 1 get mul sqrt /STCdpi exch def
+
+% pick the colormodel
+ STCold /ProcessColorModel get /STCcolor exch def
+
+
+ mark % prepare stack for "putdeviceprops"
+
+% warn for BitsPerPixel=30 with fsrgb
+ STCcolor /DeviceRGB eq STCold /BitsPerPixel get 32 eq and
+ {
+ (%%[ stcolor.ps: inefficient RGB-setup, recommend BitsPerPixel=24 ]%%\n)
+ print
+ } if
+
+% if the Dithering-Method is default (gscmyk), change it to fscmyk
+% this is achieved by pushing a name/value-pair onto the stack
+% if the selected algorithm uses another ProcessColorModel, it is necessary
+% to change the Value of STCcolor according to the new algorithm.
+
+ STCold /Dithering get (gscmyk) eq
+ {
+ /Dithering (hscmyk) % preferred dithering-method
+ } if % might be necessary to change STCcolor too
+
+%
+% select the array according to the resolution
+%
+ STCdpi 359.0 lt
+ { STCdeftransfer }
+ { STCdpi 361.0 lt
+ { STCKtransfer360 }
+ { STCdpi 719.0 gt
+ { STCKtransfer720 }
+ {
+ STCKtransfer360 length STCKtransfer720 length eq
+ {
+ 0 1 STCKtransfer360 length 1 sub
+ {
+ dup dup
+ STCKtransfer360 exch get
+ exch STCKtransfer720 exch get
+ add 2.0 div
+ STCKtransfer360 3 1 roll put
+ } for
+ }if
+ STCKtransfer360
+ } ifelse
+ }ifelse
+ } ifelse
+ /STCtransfer exch def
+
+%
+% Add the arrays. With Version 1.17 and above, it seems to be
+% a good idea, to use the transfer-arrays as coding-arrays too.
+%
+
+%
+% RGB-Model requires inversion of the transfer-arrays
+%
+ STCcolor /DeviceRGB eq
+ {
+ /RGBtransfer STCtransfer length array def
+ 0 1 STCtransfer length 1 sub
+ {
+ dup RGBtransfer length 1 sub exch sub exch
+ STCtransfer exch get 1.0 exch sub
+ RGBtransfer 3 1 roll put
+ } for
+
+ /Rtransfer RGBtransfer
+ /Gtransfer RGBtransfer
+ /Btransfer RGBtransfer
+
+ /Rcoding RGBtransfer
+ /Gcoding RGBtransfer
+ /Bcoding RGBtransfer
+
+ }{
+
+ /Ctransfer STCtransfer
+ /Mtransfer STCtransfer
+ /Ytransfer STCtransfer
+ /Ktransfer STCtransfer
+
+ /Ccoding STCtransfer
+ /Mcoding STCtransfer
+ /Ycoding STCtransfer
+ /Kcoding STCtransfer
+
+ } ifelse
+
+ counttomark 0 ne
+ {currentdevice putdeviceprops pop}{cleartomark}ifelse
+
+% decativate predefined correction
+
+ {} dup dup currenttransfer setcolortransfer
+
+ }{
+ (%%[ stcolor.ps: currentdevice is not stcolor - ignored ]%%\n) print
+ } ifelse
+}{
+ (%%[ stcolor.ps: interpreted not by Aladdin Ghostscript - ignored ]%%\n) print
+} ifelse
diff --git a/gs/lib/sysvlp.sh b/gs/lib/sysvlp.sh
new file mode 100755
index 000000000..1b839745f
--- /dev/null
+++ b/gs/lib/sysvlp.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# System V 3.2 lp interface for parallel, postscript printer
+# with ghostscript 2.5.n.
+#
+# Thanks to Arne Ludwig (arne@rrzbu.hanse.de) for this script.
+#
+
+DEVICE=lbp8
+GSHOME=/local/gs/2.5b2
+FONT=/local
+LIBDIR=/usr/spool/lp/admins/lp/interfaces
+#EHANDLER=$LIBDIR/ehandler.ps
+
+GS_LIB=$GSHOME:$FONT/fonts:$FONT/fonts/lw:$FONT/fonts/gs
+export GS_LIB
+
+copies=$4
+shift 5
+files="$*"
+
+# serial line settings
+# stty 19200 ixon ixoff 0<&1
+# stty 1200 tabs cread opost onlcr ixon ixany ff1 cr2 nl0 0<&1
+
+# Brother HL-4: switch to HP laserjet II+ emulation
+# echo "\033\015H\c"
+
+i=1
+while [ $i -le $copies ]
+do
+ for file in $files
+ do
+ $GSHOME/gs \
+ -sOUTPUTFILE=/tmp/psp$$.%02d \
+ -sDEVICE=$DEVICE \
+ $EHANDLER $file \
+ < /dev/null >> /usr/tmp/ps_log 2>&1
+
+ cat /tmp/psp$$.* 2>> /usr/tmp/ps_log
+ rm -f /tmp/psp$$.*
+ done
+ i=`expr $i + 1`
+done
+exit 0
diff --git a/gs/lib/t1tot2.ps b/gs/lib/t1tot2.ps
new file mode 100644
index 000000000..e41638797
--- /dev/null
+++ b/gs/lib/t1tot2.ps
@@ -0,0 +1,485 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% t1tot2.ps
+% Convert a Type 1 font with Type 1 CharStrings to Type 2.
+% **************** THIS FILE DOES NOT WORK. ****************
+% **************** DON'T TRY TO USE IT. ****************
+
+(type1ops.ps) runlibfile
+
+% ---------------- CharString conversion ---------------- %
+
+% In the following lists, implemented conversions are marked with a +.
+% The following conversions are required for each CharString:
+% + Remove lenIV initial bytes and decrypt.
+% + Move width to first stem/moveto.
+% + Move all hstem/vstem commands to the beginning,
+% including any from subroutines.
+% Fold side bearing into first moveto.
+% + Adjust Subr indices for bias.
+% + Remove all closepath.
+% Convert Flex othersubrs to new flex commands.
+% Convert hint replacement to -hm and hintmask.
+% Convert MM blend othersubrs to new blend command.
+% For seac, convert char bodies to subrs, add hint replacement.
+% + Make width relative to nominalWidthX, or omit if equal to
+% defaultWidthX.
+% The following patterns allow shortening CharStrings:
+% + rlineto+ => rlineto
+% + rlineto+ (hlineto | vlineto) rlineto+ => rlineto
+% + vlineto (hlineto vlineto)* [hlineto] => vlineto
+% + hlineto (vlineto hlineto)* [vlineto] => hlineto
+% + rrcurveto+ => rrcurveto
+% + rrcurveto+ rlineto => rcurveline
+% + rlineto+ rrcurveto => rlinecurve
+% + (vhcurveto hvcurveto)* [vhcurveto ["hrcurveto"] | "vrcurveto"] =>
+% vhcurveto
+% + (hvcurveto vhcurveto)* [hvcurveto ["vrcurveto"] | "hrcurveto"] =>
+% hvcurveto
+% "rvcurveto" (0 y1 x2 y2 0 y3 rrcurveto)* => vvcurveto
+% "hrcurveto" (x1 0 x2 y2 x3 0 rrcurveto)* => hhcurveto
+
+% Convert a CharString from Type 1 to Type 2.
+% Free variables: font, subrmap.
+
+/t1tot2cs { % <charstring1> <forsubr> t1tot2cs <charstring2>
+ 10 dict begin
+ /forsubr exch def
+ % Collect the hints, side bearing, and width.
+ /vhints 10 dict def
+ /hhints 10 dict def
+ /hmcount null def
+ /lsb null def
+ /width null def
+ forsubr not {
+ dup t1hintops t1scan pop
+ } if
+ t1t2ops t1scan
+ [
+ forsubr not {
+ % Insert the hints and width at the beginning.
+ width dup font /nominalWidthX .knownget { sub } if
+ exch font /defaultWidthX .knownget not { 0 } if
+ eq { pop } if
+ /hstem hhints hintlist
+ /vstem vhints hintlist
+ } if
+ counttomark 2 add -1 roll aload pop ]
+ % Convert the string back to encoded form.
+ DEBUG {
+ (++++ ) print [ 1 index { dup null eq { pop } if } forall ] == flush
+ } if
+ /lenIV 0 def % for charproc_string
+ charproc_string end
+} bind def
+/hintlist { % <hintop> <dict> hintlist -
+ dup length 0 eq {
+ pop pop
+ } {
+ dup length array dup 3 -1 roll {
+ exch put dup
+ } forall pop
+ % ****** SORT THE HINTS BY INCREASING v ******
+ { dup length 24 le { exit } if
+ dup 0 24 getinterval { aload pop 4 2 roll } forall
+ dup length 24 sub 24 exch getinterval
+ } loop
+ { aload pop 3 2 roll } forall
+ } ifelse
+} bind def
+/uneexec { % <string> <lenIV> uneexec <string>
+ dup 0 ge {
+ 2 copy mark /seed 4330 /lenIV 5 -1 roll .dicttomark /eexecDecode filter
+ % Stack: string lenIV filter
+ dup 4 -1 roll length 4 -1 roll sub string readstring pop
+ exch closefile
+ } {
+ pop
+ } ifelse
+} bind def
+/t1scan { % <charstring> <opsdict> t1scan <tokens>
+ 5 dict begin
+ /opsdict exch def
+ % Remove encryption and convert to symbolic form for processing.
+ font /lenIV .knownget not { 4 } if uneexec
+ 0 () /SubFileDecode filter /f exch def
+ /cstr [ 20 { null } repeat f charstack_read /END 20 { null } repeat ] def
+ DEBUG {
+ (**** ) print [ cstr { dup null eq { pop } if } forall ] == flush
+ } if
+ % Scan the unpacked string.
+ /i 20 def {
+ % The /END token will exit from this loop.
+ opsdict cstr i get .knownget { exec } if
+ /i i 1 add def
+ } loop
+ f closefile cstr end
+} bind def
+/ciget { % <di> ciget <token>
+ i add cstr exch get
+} bind def
+/ciput { % <di> <token> ciput -
+ exch i add exch cstr 3 1 roll put
+} bind def
+/ciswap { % <di> <dj> ciswap -
+ 2 copy exch ciget exch ciget 3 1 roll ciput ciput
+} bind def
+/ciskip { % <di> ciskip -
+ i add /i exch def
+} bind def
+
+% Hint scanning procedures.
+/addhint { % [<v> <dv>] <hintdict> addhint -
+ dup 2 index known { pop pop } { dup length 3 -1 roll exch put } ifelse
+} bind def
+
+/t1hintops mark /END { 0 null ciput exit } bind
+
+/vstem {
+ cstr i 2 sub 2 getinterval vhints addhint
+} bind
+/hstem {
+ cstr i 2 sub 2 getinterval hhints addhint
+} bind
+/callsubr {
+ %**** DOESN'T HANDLE FLEX YET ****
+ -1 ciget /pop eq {
+ % This must be a <#> 1 3 /callothersubr /pop /callsubr sequence.
+ hmcount null eq { /hmcount [ vhints length hhints length ] store } if
+ -5 ciget
+ } {
+ -1 ciget
+ } ifelse
+ subrmap 1 index .knownget { exch pop } if
+ dup null eq { pop } {
+ font /Private get /Subrs get exch get
+ t1hintops t1scan pop
+ } ifelse
+} bind
+/hsbw {
+ /lsb -2 ciget store
+ /width -1 ciget store
+} bind
+/vstem3 {
+ [ -6 ciget -5 ciget ] vhints addhint
+ [ -4 ciget -3 ciget ] vhints addhint
+ [ -2 ciget -1 ciget ] vhints addhint
+} bind
+/hstem3 {
+ [ -6 ciget -5 ciget ] hhints addhint
+ [ -4 ciget -3 ciget ] hhints addhint
+ [ -2 ciget -1 ciget ] hhints addhint
+} bind
+/sbw {
+ %**** WHAT ABOUT Y? ****
+ /lsb -4 ciget store
+ /width -2 ciget store
+} bind
+
+.dicttomark readonly def % t1hintops
+
+% Conversion procedures.
+/t1t2ops mark /END { 0 null ciput exit } bind
+
+/hstem {
+ % We handled the hints separately, drop them here.
+ -2 1 0 { null ciput } for
+} bind
+/vstem 1 index
+/rlineto {
+ 3 ciget /rlineto eq {
+ 0 null ciput
+ } {
+ 7 ciget /rrcurveto eq {
+ 0 null ciput
+ 7 /rlinecurve ciput
+ } {
+ 5 ciget /rlineto eq {
+ 2 ciget /hlineto eq {
+ 0 null ciput
+ 2 0 ciput
+ } {
+ 2 ciget /vlineto eq {
+ 0 0 ciput
+ 2 null ciput
+ } if
+ } ifelse
+ } if
+ } ifelse
+ } ifelse
+} bind
+/vlineto {
+ 2 ciget /hlineto eq {
+ 0 null ciput
+ 2 4 ciget /vlineto eq { null } { /vlineto } ifelse ciput
+ } if
+} bind
+/hlineto {
+ 2 ciget /vlineto eq {
+ 0 null ciput
+ 2 4 ciget /hlineto eq { null } { /hlineto } ifelse ciput
+ } if
+} bind
+/rrcurveto {
+ 7 ciget /rrcurveto eq {
+ 0 null ciput
+ } {
+ 3 ciget /rlineto eq {
+ 0 null ciput
+ 3 /rcurveline ciput
+ } {
+ %**** WRONG IF MULTIPLE RRCURVETO ****
+ -6 ciget 0 eq {
+ -6 null ciput
+ 0 /vhcurveto ciput
+ } {
+ -5 ciget 0 eq {
+ -5 null ciput
+ -1 -2 ciswap
+ 0 /hvcurveto ciput
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+} bind
+/callsubr {
+ -1 ciget subrmap 1 index .knownget { exch pop } if
+ % If the Subr was deleted because it was empty, delete the call.
+ dup null eq {
+ 0 null ciput
+ } {
+ % Subtract the subroutineNumberBias.
+ 107 sub
+ } ifelse -1 exch ciput
+} bind
+/vhcurveto {
+ 5 ciget /hvcurveto eq {
+ 0 null ciput
+ 10 ciget /vhcurveto eq {
+ 5 null ciput
+ } {
+ 12 ciget /rrcurveto eq 6 ciget 0 eq and {
+ 5 null ciput
+ 6 null ciput
+ 12 /vhcurveto ciput
+ 12 ciskip
+ } {
+ 5 /vhcurveto ciput
+ 5 ciskip
+ } ifelse
+ } ifelse
+ } {
+ 7 ciget /rrcurveto eq {
+ 1 ciget 0 eq {
+ 0 null ciput
+ 1 null ciput
+ 5 6 ciswap
+ 7 /vhcurveto ciput
+ 7 ciskip
+ } if
+ } if
+ } ifelse
+} bind
+/hvcurveto {
+ 5 ciget /vhcurveto eq {
+ 0 null ciput
+ 10 ciget /hvcurveto eq {
+ 5 null ciput
+ } {
+ 12 ciget /rrcurveto eq 7 ciget 0 eq and {
+ 5 null ciput
+ 7 null ciput
+ 10 11 ciswap
+ 12 /hvcurveto ciput
+ 12 ciskip
+ } {
+ 5 /hvcurveto ciput
+ 5 ciskip
+ } ifelse
+ } ifelse
+ } {
+ 7 ciget /rrcurveto eq {
+ 2 ciget 0 eq {
+ 0 null ciput
+ 2 null ciput
+ 7 /hvcurveto ciput
+ 7 ciskip
+ } if
+ } if
+ } ifelse
+} bind
+/closepath {
+ 0 null ciput
+} bind
+/hsbw {
+ % We handled this separately, drop it.
+ -2 1 0 { null ciput } for
+} bind
+/dotsection {
+ %**************** NYI ****************
+} bind
+/vstem3 {
+ % We handled the hints separately, drop them here.
+ -6 1 0 { null ciput } for
+} bind
+/hstem3 1 index
+/seac {
+ %**************** NYI ****************
+} bind
+/sbw {
+ % We handled this separately, drop it.
+ -4 1 0 { null ciput } for
+} bind
+/callothersubr {
+ -1 ciget 3 eq {
+ %**** HANDLE HINT REPLACEMENT ****
+ -2 ciget 1 eq 1 ciget /pop eq and 2 ciget /callsubr eq and {
+ 1 -3 ciget ciput
+ -3 1 0 { null ciput } for
+ } {
+ (**************** 3 callothersubr -- invalid call\n) print
+ /t1tot2cs cvx /rangecheck signalerror
+ } ifelse
+ } if
+} bind
+/pop {
+ %**************** NYI ****************
+} bind
+/setcurrentpoint {
+ %**************** NYI ****************
+} bind
+
+.dicttomark readonly def % t1t2ops
+
+% ---------------- Font conversion ---------------- %
+
+% Copy a font, and remove eexec encryption from it.
+/decryptfont { % <font> decryptfont <font'>
+ % Copy the font, CharStrings, Private, and Private.Subrs
+ dup length dict copy
+ dup /CharStrings 2 copy get dup length dict copy put
+ dup /Private 2 copy get dup length dict copy
+ dup /Subrs 2 copy get dup length array copy put
+ put
+ dup /lenIV .knownget not { 4 } if
+ 1 index /CharStrings get
+ % Stack: font' lenIV chars'
+ dup { 3 index uneexec 2 index 3 1 roll put } forall pop
+ 1 index /Private get /Subrs get
+ % Stack: font' lenIV Subrs'
+ 0 1 2 index length 1 sub {
+ 2 copy get dup type /stringtype eq {
+ % Stack: font' lenIV Subrs' index subr
+ 3 index uneexec
+ } if 2 index 3 1 roll put
+ } for pop pop dup /lenIV -1 put
+} def
+
+% Convert an entire font from Type 1 to Type 2.
+/t1tot2font { % <font> t1tot2font <font'>
+ 10 dict begin
+ /font exch def
+ /niv font /lenIV .knownget not { 4 } if def
+
+ % Print initial statistics.
+
+ (lenIV = ) print niv =
+ font /CharStrings get
+ dup length =only ( CharStrings, ) print
+ 0 exch { exch pop length add } forall =only ( bytes) =
+ font /Private get /Subrs get
+ dup length =only ( Subrs, ) print
+ 0 exch { length add } forall =only ( bytes) =
+ flush
+
+ % Remove CharString encryption from the font.
+
+ /font font decryptfont def
+ /chars font /CharStrings get dup length dict copy def
+ /subrs font /Private get /Subrs get def
+
+ % Remove empty Subrs, including Subrs 0-3.
+
+ /subrmap subrs length dict def
+ 0 1 3 { subrs exch <0b> put } for
+ 0 1 subrs length 1 sub {
+ subrs 1 index get true t1tot2cs
+ length 1 eq {
+ subrs 1 index null put
+ subrmap exch null put
+ } {
+ pop
+ } ifelse
+ } for
+
+ % Remove duplicate Subrs (!).
+
+ % Make an entry in subrdict for each distinct Subr:
+ % key = Subr charstring, value = (lowest) Subr index.
+ % At the same time, make entries in subrmap for any duplicates:
+ % key = higher index, value = lowest index.
+ /subrdict subrs length dict def
+ 0 0 1 subrs length 1 sub {
+ % Stack: toindex fromindex
+ subrs 1 index get subrdict 1 index .knownget {
+ % Stack: toindex fromindex subr firstindex
+ subrmap 4 -1 roll 3 -1 roll put pop
+ } {
+ dup null ne {
+ % Stack: toindex fromindex subr
+ subrmap 3 -1 roll 3 index put % fromindex => toindex
+ subrdict 1 index 3 index put % subr => toindex
+ subrs 2 index 3 -1 roll put % toindex => subr
+ 1 add
+ } {
+ pop pop
+ } ifelse
+ } ifelse
+ } for
+ /subrs1 subrs 0 4 -1 roll getinterval def
+ font /Private get /Subrs subrs1 put
+
+ % Convert the font.
+
+ /chars2 chars length dict def
+ chars { false t1tot2cs chars2 3 1 roll put } forall
+ /subrs2 subrs1 length array def
+ 0 1 subrs1 length 1 sub {
+ subrs1 1 index get true t1tot2cs
+ subrs2 3 1 roll put
+ } for
+ font /Private get /Subrs subrs2 put
+
+ % Print final statistics.
+
+ (CharStrings => ) print 0 chars2 { exch pop length add } forall =only
+ ( bytes) =
+ subrs2 length =only ( Subrs, ) print
+ 0 subrs2 { length add } forall =only ( bytes) =
+ flush
+
+ % Clean up the font.
+
+ font /lenIV undef
+ font /UniqueID undef
+ font /FID undef
+ font /CharStrings chars2 put
+ font /CharstringType 2 put
+
+ font end
+} bind def
diff --git a/gs/lib/test.ps b/gs/lib/test.ps
new file mode 100644
index 000000000..ef6ae2875
--- /dev/null
+++ b/gs/lib/test.ps
@@ -0,0 +1,9 @@
+186 0 0 setrgbcolor
+10 setlinewidth
+0 0 moveto 100 100 lineto stroke
+% This one gets 255 0 0 in .pmm
+
+0 153 153 setrgbcolor
+100 100 moveto 200 200 lineto stroke
+% This one gets 0 255 255 in .pmm
+showpage
diff --git a/gs/lib/tiger.ps b/gs/lib/tiger.ps
new file mode 100644
index 000000000..24a9dcec1
--- /dev/null
+++ b/gs/lib/tiger.ps
@@ -0,0 +1,2733 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%Creator: Adobe Illustrator(TM) 1.2d4
+%%For: OpenWindows Version 2
+%%Title: tiger.eps
+%%CreationDate: 4/12/90 3:20 AM
+%%DocumentProcSets: Adobe_Illustrator_1.2d1 0 0
+%%DocumentSuppliedProcSets: Adobe_Illustrator_1.2d1 0 0
+%%BoundingBox: 22 171 567 738
+%%EndComments
+
+%%BeginProcSet:Adobe_Illustrator_1.2d1 0 0
+
+/Adobe_Illustrator_1.2d1 dup 100 dict def load begin
+% definition operators
+/bdef {bind def} bind def
+/ldef {load def} bdef
+/xdef {exch def} bdef
+% graphic state operators
+/_K { 3 index add neg dup 0 lt {pop 0} if 3 1 roll } bdef
+/_k /setcmybcolor where {
+ /setcmybcolor get
+} {
+ { 1 sub 4 1 roll _K _K _K setrgbcolor pop } bind
+} ifelse def
+/g {/_b xdef /p {_b setgray} def} bdef
+/G {/_B xdef /P {_B setgray} def} bdef
+/k {/_b xdef /_y xdef /_m xdef /_c xdef /p {_c _m _y _b _k} def} bdef
+/K {/_B xdef /_Y xdef /_M xdef /_C xdef /P {_C _M _Y _B _k} def} bdef
+/d /setdash ldef
+/_i currentflat def
+/i {dup 0 eq {pop _i} if setflat} bdef
+/j /setlinejoin ldef
+/J /setlinecap ldef
+/M /setmiterlimit ldef
+/w /setlinewidth ldef
+% path construction operators
+/_R {.25 sub round .25 add} bdef
+/_r {transform _R exch _R exch itransform} bdef
+/c {_r curveto} bdef
+/C /c ldef
+/v {currentpoint 6 2 roll _r curveto} bdef
+/V /v ldef
+/y {_r 2 copy curveto} bdef
+/Y /y ldef
+/l {_r lineto} bdef
+/L /l ldef
+/m {_r moveto} bdef
+% path painting operators
+/n /newpath ldef
+/N /n ldef
+/F {p fill} bdef
+/f {closepath F} bdef
+/S {P stroke} bdef
+/s {closepath S} bdef
+/B {gsave F grestore S} bdef
+/b {closepath B} bdef
+end
+%%EndProcSet
+%%EndProlog
+
+%%Page: 1 1
+
+Adobe_Illustrator_1.2d1 begin
+
+.8 setgray
+clippath fill
+-110 -300 translate
+1.1 dup scale
+
+0 g
+0 G
+0 i
+0 J
+0 j
+0.172 w
+10 M
+[]0 d
+0 0 0 0 k
+
+177.696 715.715 m
+177.797 713.821 176.973 713.84 v
+176.149 713.859 159.695 761.934 139.167 759.691 C
+156.95 767.044 177.696 715.715 V
+b
+181.226 718.738 m
+180.677 716.922 179.908 717.221 v
+179.14 717.519 180.023 768.325 159.957 773.199 C
+179.18 774.063 181.226 718.738 V
+b
+208.716 676.41 m
+210.352 675.45 209.882 674.773 v
+209.411 674.096 160.237 686.898 150.782 668.541 C
+154.461 687.428 208.716 676.41 V
+b
+205.907 666.199 m
+207.763 665.803 207.529 665.012 v
+207.296 664.221 156.593 660.879 153.403 640.478 C
+150.945 659.563 205.907 666.199 V
+b
+201.696 671.724 m
+203.474 671.061 203.128 670.313 v
+202.782 669.565 152.134 673.654 146.002 653.936 C
+146.354 673.175 201.696 671.724 V
+b
+190.991 689.928 m
+192.299 688.554 191.66 688.033 v
+191.021 687.512 147.278 713.366 133.131 698.324 C
+141.872 715.467 190.991 689.928 V
+b
+183.446 685.737 m
+184.902 684.52 184.326 683.929 v
+183.75 683.339 137.362 704.078 125.008 687.531 C
+131.753 705.553 183.446 685.737 V
+b
+180.846 681.665 m
+182.454 680.657 181.964 679.994 v
+181.474 679.331 132.692 693.554 122.709 675.478 C
+126.934 694.251 180.846 681.665 V
+b
+191.58 681.051 m
+192.702 679.52 192.001 679.085 v
+191.3 678.65 151.231 709.898 135.273 696.793 C
+146.138 712.674 191.58 681.051 V
+b
+171.8 710 m
+172.4 708.2 171.6 708 v
+170.8 707.8 142.2 749.8 122.999 742.2 C
+138.2 754 171.8 710 V
+b
+172.495 703.021 m
+173.47 701.392 172.731 701.025 v
+171.993 700.657 135.008 735.501 117.899 723.939 C
+130.196 738.739 172.495 703.021 V
+b
+172.38 698.651 m
+173.502 697.12 172.801 696.685 v
+172.1 696.251 132.031 727.498 116.073 714.393 C
+126.938 730.274 172.38 698.651 V
+b
+0 J 1 w
+170.17 696.935 m
+170.673 690.887 171.661 684.318 173.4 681.199 C
+169.8 668.799 178.6 655.599 V
+178.2 648.399 179.8 645.199 V
+183.8 636.799 188.6 635.999 v
+192.484 635.352 201.207 632.283 211.068 630.879 c
+228.2 616.799 225 603.999 V
+224.6 587.599 221 585.999 V
+232.6 597.199 223 580.399 V
+218.6 561.599 l
+244.2 583.199 228.6 564.799 V
+218.6 538.799 l
+238.2 557.199 231 548.799 V
+227.8 539.999 l
+271 567.199 240.2 537.599 V
+248.2 541.199 252.6 538.399 V
+259.4 539.599 258.6 537.999 V
+237.8 527.599 234.2 509.199 V
+242.6 519.199 239.4 508.399 V
+239.8 496.799 l
+243.8 518.399 243.4 480.799 V
+262.6 498.799 251 477.999 V
+251 461.199 l
+266.2 477.599 259.8 464.799 V
+269.8 473.599 265.8 458.399 V
+265 447.999 269.4 459.199 V
+285.4 489.799 279.4 463.599 V
+278.6 444.399 283.4 459.199 V
+283.8 448.799 293 441.599 V
+291.8 492.399 304.6 456.399 V
+308.6 439.999 l
+311.4 449.199 311 454.399 V
+325.8 470.799 319 446.399 V
+334.2 469.199 331 455.999 V
+323.4 439.999 325 435.199 V
+341.8 469.999 343 471.599 V
+341 429.198 351.8 465.199 V
+357.4 453.199 354.6 448.799 V
+362.6 456.799 361.8 459.999 V
+366.4 468.199 369.2 454.599 V
+371 445.199 372.6 448.399 V
+376.6 424.398 377.8 447.199 V
+379.4 460.799 372.2 472.399 V
+373 475.599 370.2 479.599 v
+383.8 457.999 376.6 486.799 V
+387.801 478.799 389.001 478.799 V
+375.4 501.999 384.2 497.199 V
+379 507.599 397.001 495.599 V
+381 511.599 398.601 501.999 V
+406.601 495.599 399.001 505.599 V
+384.6 521.599 406.601 503.599 V
+418.201 487.199 419.001 484.399 V
+409.001 513.599 404.601 516.399 V
+413.001 552.799 454.201 537.199 V
+461.001 519.999 465.401 538.399 V
+478.201 544.799 489.401 517.199 V
+493.401 530.799 492.601 533.599 V
+499.401 532.399 498.601 533.599 V
+511.801 529.199 513.001 529.999 V
+519.801 523.199 520.201 526.799 V
+529.401 523.999 527.401 527.599 V
+536.201 511.999 536.601 508.399 V
+539.001 522.399 l
+541.001 519.599 l
+542.601 527.199 541.801 528.399 v
+541.001 529.599 561.801 521.599 566.601 500.799 C
+568.601 492.399 l
+574.601 507.199 573.001 511.199 V
+578.201 510.399 578.601 505.999 V
+582.601 529.199 577.801 535.199 V
+582.201 535.999 583.401 532.399 V
+583.401 539.599 l
+590.601 538.799 590.601 541.199 V
+595.001 545.199 597.001 540.399 V
+584.601 575.599 603.001 556.399 V
+610.201 545.599 606.601 564.399 v
+603.001 583.199 599.001 584.799 603.801 585.199 C
+604.601 588.799 602.601 590.399 v
+600.601 591.999 603.801 590.399 y
+608.601 586.399 603.401 608.399 V
+609.801 606.799 597.801 635.999 V
+600.601 638.399 596.601 646.799 V
+604.601 642.399 607.401 643.999 V
+607.001 645.599 603.801 649.599 V
+582.201 704.4 602.601 682.399 V
+614.451 668.849 608.051 691.649 V
+598.94 715.659 599.717 719.955 V
+170.17 696.935 l
+b
+0.2 0.55 0.85 0 k
+599.717 719.755 m
+600.345 719.574 602.551 718.45 603.801 716.8 C
+610.601 706 605.401 724.4 V
+596.201 753.2 605.001 742 V
+611.001 734.8 607.801 748.4 v
+603.936 764.827 601.401 771.2 y
+613.001 766.4 586.201 806 V
+595.001 802.4 l
+575.401 842 553.801 847.2 V
+545.801 853.2 l
+584.201 891.2 571.401 928 V
+564.601 933.2 555.001 924 V
+548.601 919.2 542.601 920.8 V
+511.801 919.6 509.801 919.6 v
+507.801 919.6 473.001 956.8 407.401 939.2 C
+402.201 937.2 397.801 938.4 V
+379.4 954.4 330.6 931.6 v
+320.6 929.6 319 929.6 v
+317.4 929.6 314.6 929.6 306.6 923.2 c
+298.6 916.8 298.2 916 296.2 914.4 C
+279.8 903.2 275 902.4 V
+263.4 896 259 886 V
+255.4 884.8 l
+253.8 877.6 253.4 876.4 V
+248.6 872.8 247.8 867.2 V
+239 861.2 239.4 856.8 V
+237.8 851.6 237 846.8 V
+229.8 842 230.6 839.2 V
+223 825.2 224.2 818.4 V
+217.8 818.8 215 816.4 V
+214.2 811.6 212.6 811.2 V
+209.8 810 212.2 806 V
+210.6 803.2 210.2 801.6 V
+211 798.8 206.6 793.2 V
+200.2 774.4 202.2 769.2 V
+202.6 764.4 199.8 762.8 V
+196.2 763.2 204.6 751.2 V
+205.4 750 202.2 747.6 V
+185 744 182.6 727.6 V
+169 712.8 169 707.6 v
+169 705.295 169.271 702.148 169.97 697.535 C
+169.4 689.199 197 688.399 v
+224.6 687.599 599.717 719.755 Y
+b
+184.4 697.4 m
+159.4 736.8 173.8 680.399 Y
+182.6 645.999 312.2 683.599 y
+481.001 714 492.201 718 v
+503.401 722 598.601 715.6 y
+593.001 732.4 L
+528.201 778.8 509.001 755.6 495.401 759.6 c
+481.801 763.6 484.201 754 481.001 753.2 c
+477.801 752.4 438.601 777.2 432.201 776.4 c
+425.801 775.6 400.459 799.351 415.401 767.6 c
+431.401 733.6 357 728.4 340.2 739.6 c
+323.4 750.8 347.4 721.2 Y
+365.8 701.2 331.4 718 y
+297 730.8 273 705.2 269.8 704.4 c
+266.6 703.6 261.8 700.4 261 706.8 c
+260.2 713.2 252.69 729.901 221 703.6 c
+201 686.999 187.2 709 Y
+184.4 697.4 L
+f
+0.09 0.5 0.772 0 k
+433.51 774.654 m
+427.11 773.854 401.743 797.593 416.71 765.854 c
+433.31 730.654 358.31 726.654 341.51 737.854 c
+324.709 749.054 348.71 719.454 Y
+367.11 699.454 332.709 716.254 y
+298.309 729.054 274.309 703.454 271.109 702.654 c
+267.909 701.854 263.109 698.654 262.309 705.054 c
+261.509 711.454 254.13 727.988 222.309 701.854 c
+201.073 684.508 187.582 705.963 Y
+184.382 695.854 L
+159.382 735.654 174.454 677.345 Y
+183.255 642.944 313.509 681.854 y
+482.31 712.254 493.51 716.254 v
+504.71 720.254 599.038 713.927 y
+593.51 731.236 L
+528.71 777.636 510.31 753.854 496.71 757.854 c
+483.11 761.854 485.51 752.254 482.31 751.454 c
+479.11 750.654 439.91 775.454 433.51 774.654 c
+f
+0.081 0.45 0.695 0 k
+434.819 772.909 m
+428.419 772.109 403.685 796.138 418.019 764.109 c
+434.219 727.908 359.619 724.908 342.819 736.108 c
+326.019 747.308 350.019 717.708 Y
+368.419 697.708 334.019 714.508 y
+299.619 727.308 275.618 701.708 272.418 700.908 c
+269.218 700.108 264.418 696.908 263.618 703.308 c
+262.818 709.708 255.57 726.075 223.618 700.108 c
+201.145 682.017 187.964 702.926 Y
+184.364 694.308 L
+160.564 733.308 175.109 674.29 Y
+183.909 639.89 314.819 680.108 y
+483.619 710.508 494.819 714.508 v
+506.019 718.508 599.474 712.254 y
+594.02 730.072 L
+529.219 776.472 511.619 752.109 498.019 756.109 c
+484.419 760.109 486.819 750.509 483.619 749.708 c
+480.419 748.908 441.219 773.709 434.819 772.909 c
+f
+0.072 0.4 0.618 0 k
+436.128 771.163 m
+429.728 770.363 404.999 794.395 419.328 762.363 c
+436.128 724.807 360.394 723.518 344.128 734.363 c
+327.328 745.563 351.328 715.963 Y
+369.728 695.963 335.328 712.763 y
+300.928 725.563 276.928 699.963 273.728 699.163 c
+270.528 698.363 265.728 695.163 264.928 701.563 c
+264.128 707.963 257.011 724.161 224.927 698.363 c
+201.218 679.526 188.345 699.89 Y
+184.345 692.763 L
+162.545 729.563 175.764 671.235 Y
+184.564 636.835 316.128 678.363 y
+484.928 708.763 496.129 712.763 v
+507.329 716.763 599.911 710.581 y
+594.529 728.908 L
+529.729 775.309 512.929 750.363 499.329 754.363 c
+485.728 758.363 488.128 748.763 484.928 747.963 c
+481.728 747.163 442.528 771.963 436.128 771.163 c
+f
+0.063 0.35 0.54 0 k
+437.438 769.417 m
+431.037 768.617 406.814 792.871 420.637 760.617 c
+437.438 721.417 362.237 721.417 345.437 732.617 c
+328.637 743.817 352.637 714.217 Y
+371.037 694.217 336.637 711.017 y
+302.237 723.817 278.237 698.217 275.037 697.417 c
+271.837 696.617 267.037 693.417 266.237 699.817 c
+265.437 706.217 258.452 722.248 226.237 696.617 c
+201.291 677.035 188.727 696.854 Y
+184.327 691.217 L
+164.527 726.018 176.418 668.181 Y
+185.218 633.78 317.437 676.617 y
+486.238 707.017 497.438 711.017 v
+508.638 715.017 600.347 708.908 y
+595.038 727.745 L
+530.238 774.145 514.238 748.617 500.638 752.617 c
+487.038 756.617 489.438 747.017 486.238 746.217 c
+483.038 745.417 443.838 770.217 437.438 769.417 c
+f
+0.054 0.3 0.463 0 k
+438.747 767.672 m
+432.347 766.872 406.383 790.323 421.947 758.872 c
+441.147 720.072 363.546 719.672 346.746 730.872 c
+329.946 742.072 353.946 712.472 Y
+372.346 692.472 337.946 709.272 y
+303.546 722.072 279.546 696.472 276.346 695.672 c
+273.146 694.872 268.346 691.672 267.546 698.072 c
+266.746 704.472 259.892 720.335 227.546 694.872 c
+201.364 674.544 189.109 693.817 Y
+184.309 689.672 L
+166.309 722.872 177.073 665.126 Y
+185.873 630.726 318.746 674.872 y
+487.547 705.272 498.747 709.272 v
+509.947 713.272 600.783 707.236 y
+595.547 726.581 L
+530.747 772.981 515.547 746.872 501.947 750.872 c
+488.347 754.872 490.747 745.272 487.547 744.472 c
+484.347 743.672 445.147 768.472 438.747 767.672 c
+f
+0.045 0.25 0.386 0 k
+440.056 765.927 m
+433.655 765.127 407.313 788.387 423.255 757.127 c
+443.656 717.126 364.855 717.926 348.055 729.126 c
+331.255 740.326 355.255 710.726 Y
+373.655 690.726 339.255 707.526 y
+304.855 720.326 280.855 694.726 277.655 693.926 c
+274.455 693.126 269.655 689.926 268.855 696.326 c
+268.055 702.726 261.332 718.422 228.855 693.126 c
+201.436 672.053 189.491 690.781 Y
+184.291 688.126 L
+168.291 718.326 177.727 662.071 Y
+186.527 627.671 320.055 673.126 y
+488.856 703.526 500.056 707.526 v
+511.256 711.526 601.22 705.563 y
+596.056 725.417 L
+531.256 771.817 516.856 745.126 503.256 749.126 c
+489.656 753.127 492.056 743.526 488.856 742.726 c
+485.656 741.926 446.456 766.727 440.056 765.927 c
+f
+0.036 0.2 0.309 0 k
+441.365 764.181 m
+434.965 763.381 407.523 786.056 424.565 755.381 c
+446.565 715.781 366.164 716.181 349.364 727.381 c
+332.564 738.581 356.564 708.981 Y
+374.964 688.981 340.564 705.781 y
+306.164 718.581 282.164 692.981 278.964 692.181 c
+275.764 691.381 270.964 688.181 270.164 694.581 c
+269.364 700.981 262.773 716.508 230.164 691.381 c
+201.509 669.562 189.873 687.744 Y
+184.273 686.581 L
+169.872 714.981 178.382 659.017 Y
+187.182 624.616 321.364 671.381 y
+490.165 701.781 501.365 705.781 v
+512.565 709.781 601.656 703.89 y
+596.565 724.254 L
+531.765 770.654 518.165 743.381 504.565 747.381 c
+490.965 751.381 493.365 741.781 490.165 740.981 c
+486.965 740.181 447.765 764.981 441.365 764.181 c
+f
+0.027 0.15 0.231 0 k
+442.674 762.435 m
+436.274 761.635 408.832 784.311 425.874 753.635 c
+447.874 714.035 367.474 714.435 350.674 725.635 c
+333.874 736.835 357.874 707.235 Y
+376.274 687.235 341.874 704.035 y
+307.473 716.835 283.473 691.235 280.273 690.435 c
+277.073 689.635 272.273 686.435 271.473 692.835 c
+270.673 699.235 264.214 714.595 231.473 689.635 c
+201.582 667.071 190.255 684.707 Y
+184.255 685.035 L
+170.654 711.436 179.037 655.962 Y
+187.837 621.562 322.673 669.635 y
+491.474 700.035 502.674 704.035 v
+513.874 708.035 602.093 702.217 y
+597.075 723.09 L
+532.274 769.49 519.474 741.635 505.874 745.635 c
+492.274 749.635 494.674 740.035 491.474 739.235 c
+488.274 738.435 449.074 763.235 442.674 762.435 c
+f
+0.018 0.1 0.154 0 k
+443.983 760.69 m
+437.583 759.89 410.529 782.777 427.183 751.89 c
+449.183 711.09 368.783 712.69 351.983 723.89 c
+335.183 735.09 359.183 705.49 Y
+377.583 685.49 343.183 702.29 y
+308.783 715.09 284.783 689.49 281.583 688.69 c
+278.382 687.89 273.582 684.69 272.782 691.09 c
+271.982 697.49 265.654 712.682 232.782 687.89 c
+201.655 664.58 190.637 681.671 Y
+184.236 683.49 L
+171.236 707.49 179.691 652.907 Y
+188.491 618.507 323.983 667.89 y
+492.783 698.29 503.983 702.29 v
+515.183 706.29 602.529 700.544 y
+597.583 721.926 L
+532.783 768.327 520.783 739.89 507.183 743.89 c
+493.583 747.89 495.983 738.29 492.783 737.49 c
+489.583 736.69 450.383 761.49 443.983 760.69 c
+f
+0.009 0.05 0.077 0 k
+445.292 758.945 m
+438.892 758.145 412.917 781.589 428.492 750.145 c
+449.692 707.344 370.092 710.944 353.292 722.144 c
+336.492 733.344 360.492 703.744 Y
+378.892 683.744 344.492 700.544 y
+310.092 713.344 286.092 687.744 282.892 686.944 c
+279.692 686.144 274.892 682.944 274.092 689.344 c
+273.292 695.744 267.095 710.768 234.092 686.144 c
+201.727 662.089 191.018 678.635 Y
+184.218 681.944 L
+171.418 705.144 180.346 649.853 Y
+189.146 615.453 325.292 666.144 y
+494.093 696.544 505.293 700.544 v
+516.493 704.544 602.965 698.872 y
+598.093 720.763 L
+533.292 767.163 522.093 738.144 508.493 742.144 c
+494.893 746.145 497.293 736.544 494.093 735.744 c
+490.892 734.944 451.692 759.745 445.292 758.945 c
+f
+1 g
+184.2 680.399 m
+171.4 702.4 181 646.799 Y
+189.8 612.399 326.6 664.399 y
+495.401 694.8 506.601 698.8 v
+517.801 702.8 603.401 697.2 y
+598.601 719.6 L
+533.801 766 523.401 736.4 509.801 740.4 c
+496.201 744.4 498.601 734.8 495.401 734 c
+492.201 733.2 453.001 758 446.601 757.2 c
+440.201 756.4 414.981 780.207 429.801 748.4 c
+452.028 700.693 369.041 710.773 354.6 720.4 c
+337.8 731.6 361.8 702 Y
+380.2 681.999 345.8 698.8 y
+311.4 711.6 287.4 685.999 284.2 685.199 c
+281 684.399 276.2 681.199 275.4 687.599 c
+274.6 694 268.535 708.856 235.4 684.399 c
+201.8 659.599 191.4 675.599 Y
+184.2 680.399 L
+f
+0 g
+225.8 650.399 m
+218.6 638.799 239.4 625.599 V
+240.8 624.199 222.8 628.399 V
+216.6 630.399 215 640.799 V
+210.2 645.199 205.4 650.799 v
+200.6 656.399 225.8 650.399 y
+f
+0.8 g
+365.8 698 m
+383.498 671.179 382.9 666.399 v
+381.6 655.999 381.4 646.399 384.6 642.399 c
+387.801 638.399 396.601 605.199 y
+396.201 603.999 408.601 641.999 V
+420.201 657.999 400.201 676.399 V
+365 705.2 365.8 698 v
+f
+0 g
+1 J 0.1 w
+245.8 623.599 m
+257 616.399 242.6 585.199 V
+249 587.599 l
+248.2 576.399 245 573.999 V
+252.2 577.199 l
+257 569.199 253 564.399 V
+269.8 556.399 269 549.999 V
+275.4 557.999 271.4 564.399 v
+267.4 570.799 260.2 566.799 261 585.199 C
+252.2 581.999 l
+257.8 590.799 257.8 597.199 V
+249.8 594.799 l
+265.269 621.377 254.6 622.799 v
+248.6 623.599 245.8 623.599 Y
+f
+0.8 g
+278.2 606.799 m
+281 611.199 278.2 610.399 v
+275.4 609.599 244.2 594.799 238.2 585.199 C
+272.6 609.599 278.2 606.799 V
+f
+288.6 598.799 m
+291.4 603.199 288.6 602.399 v
+285.8 601.599 254.6 586.799 248.6 577.199 C
+283 601.599 288.6 598.799 V
+f
+301.8 613.999 m
+304.6 618.399 301.8 617.599 v
+299 616.799 267.8 601.999 261.8 592.399 C
+296.2 616.799 301.8 613.999 V
+f
+278.6 570.399 m
+278.6 576.399 275.8 575.599 v
+273 574.799 237 557.199 231 547.599 C
+273 573.199 278.6 570.399 V
+f
+279.8 581.199 m
+281 585.999 278.2 585.199 V
+276.2 585.199 249.8 573.599 243.8 563.999 C
+273.4 585.599 279.8 581.199 V
+f
+265.4 533.599 m
+255.4 525.999 l
+265.8 533.599 269.4 532.399 V
+262.6 521.199 261.8 515.999 V
+272.2 528.799 277.8 528.399 V
+285.4 527.999 285.4 517.199 V
+291 527.599 294.2 527.199 V
+295.4 520.799 294.2 513.999 V
+298.2 521.599 302.2 519.999 V
+308.6 521.999 307.8 510.399 V
+307.8 499.999 307 497.199 V
+312.6 523.599 315 523.999 V
+323 525.199 327.8 516.399 V
+323.8 523.999 328.6 521.999 V
+339.4 520.399 342.6 513.599 V
+335.8 525.599 341.4 522.399 V
+348.2 522.399 349.4 515.999 V
+357.8 494.799 359.8 493.199 V
+352.2 514.799 353.8 514.799 V
+351.8 526.799 357 511.999 V
+353.8 525.999 359.4 525.199 v
+365 524.399 369.4 514.399 377.8 516.799 C
+387.401 511.199 389.401 580.399 V
+265.4 533.599 L
+f
+0 g
+0 J 1 w
+270.2 626.399 m
+285 632.399 325 626.399 V
+332.2 625.999 339 634.799 v
+345.8 643.599 372.6 650.799 379 648.799 C
+388.601 642.399 l
+389.401 641.199 l
+401.801 630.799 402.201 623.199 v
+402.601 615.599 387.801 567.599 378.2 551.599 c
+368.6 535.599 359 523.199 339.8 525.599 C
+319 529.599 293.4 525.599 v
+264.2 527.199 261.4 535.199 v
+258.6 543.199 272.6 558.399 y
+277 566.799 275.8 581.199 v
+274.6 595.599 275 623.599 270.2 626.399 c
+f
+0.1 0.6 0.45 0 k
+292.2 624.399 m
+300.6 605.999 271 540.799 y
+269 539.199 283.66 533.154 293.8 535.599 c
+304.746 538.237 345 533.999 Y
+368.6 549.599 381.4 593.999 y
+391.801 617.999 374.2 621.199 v
+356.6 624.399 292.2 624.399 y
+f
+0.1 0.6 0.45 0.2 k
+290.169 593.503 m
+293.495 606.293 295.079 618.094 292.2 624.399 c
+354.6 617.999 365.8 638.799 v
+370.041 646.674 384.801 615.999 384.4 606.399 c
+321.4 591.999 306.6 603.199 V
+290.169 593.503 L
+f
+0.1 0.6 0.45 0.25 k
+294.6 577.199 m
+296.6 569.999 294.2 565.999 V
+292.6 565.199 291.4 564.799 V
+292.6 561.199 298.6 559.599 V
+300.6 555.199 303 554.799 v
+305.4 554.399 310.2 548.799 314.2 549.999 c
+318.2 551.199 329.4 555.199 y
+335 558.399 343.8 554.799 V
+346.175 555.601 346.6 559.599 v
+347.1 564.299 350.2 567.999 352.2 569.999 c
+354.2 571.999 363.8 584.799 362.6 585.199 c
+361.4 585.599 294.6 577.199 Y
+f
+0 0.55 0.5 0 k
+290.2 625.599 m
+287.4 603.199 290.6 594.799 v
+293.8 586.399 293 584.399 292.2 580.399 c
+291.4 576.399 295.8 566.399 301.4 560.399 C
+313.4 558.799 l
+328.6 562.399 337.8 559.599 V
+346.794 558.256 350.2 573.199 V
+355 579.599 362.2 582.399 v
+369.4 585.199 376.6 626.799 372.6 634.799 c
+368.6 642.799 354.2 647.199 338.2 631.599 c
+322.2 615.999 320.2 632.799 290.2 625.599 C
+b
+0 0 0.2 0 k
+0.5 w
+291.8 550.799 m
+291 552.799 286.6 553.199 V
+264.2 556.799 255.8 569.199 V
+249 574.799 253.4 563.199 V
+263.8 542.799 270.6 539.999 V
+287 535.999 291.8 550.799 V
+b
+0 0.55 0.5 0.2 k
+1 w
+371.742 614.771 m
+372.401 622.677 374.354 631.291 372.6 634.799 c
+366.154 647.693 349.181 642.305 338.2 631.599 c
+322.2 615.999 320.2 632.799 290.2 625.599 C
+288.455 611.636 289.295 601.624 v
+326.6 613.199 327.4 607.599 V
+329 610.799 338.2 610.799 v
+347.4 610.799 370.142 611.971 371.742 614.771 C
+f
+0 g
+0 0.55 0.5 0.35 K
+2 w
+328.6 624.799 m
+333.4 619.999 329.8 610.399 V
+315.4 594.399 317.4 580.399 v
+S
+0 0 0.2 0 k
+0 G
+0.5 w
+280.6 539.999 m
+276.2 552.799 285 545.999 V
+289.8 543.999 288.6 542.399 v
+287.4 540.799 281.8 536.799 280.6 539.999 C
+b
+285.64 538.799 m
+282.12 549.039 289.16 543.599 V
+293.581 541.151 292.04 540.719 v
+287.48 539.439 292.04 536.879 285.64 538.799 C
+b
+290.44 538.799 m
+286.92 549.039 293.96 543.599 V
+298.335 541.289 296.84 540.719 v
+293.48 539.439 296.84 536.879 290.44 538.799 C
+b
+297.04 538.599 m
+293.52 548.839 300.56 543.399 V
+304.943 541.067 303.441 540.519 v
+300.48 539.439 303.441 536.679 297.04 538.599 C
+b
+303.52 538.679 m
+300 548.919 307.041 543.479 V
+310.881 541.879 309.921 540.599 v
+308.961 539.319 309.921 536.759 303.52 538.679 C
+b
+310.2 537.999 m
+305.4 550.399 314.6 543.999 V
+319.4 541.999 318.2 540.399 v
+317 538.799 318.2 535.599 310.2 537.999 C
+b
+0 g
+0.1 0.6 0.45 0.25 K
+2 w
+281.8 555.199 m
+295 557.999 301 554.799 V
+307 553.599 308.2 553.999 v
+309.4 554.399 312.6 554.799 y
+S
+315.8 546.399 m
+327.8 559.999 339.8 555.599 v
+346.816 553.026 345.8 556.399 346.6 559.199 c
+347.4 561.999 347.6 566.199 352.6 569.199 c
+S
+0 0 0.2 0 k
+0 G
+0.5 w
+333 562.399 m
+329 573.199 326.2 560.399 v
+323.4 547.599 320.2 543.999 318.6 541.199 C
+318.6 535.999 327 536.399 V
+337.8 536.799 338.2 539.599 v
+338.6 542.399 337 553.999 333 562.399 C
+b
+0 g
+0.1 0.6 0.45 0.25 K
+2 w
+347 555.199 m
+350.6 557.599 353 556.399 v
+S
+353.5 571.599 m
+356.4 576.499 361.2 577.299 v
+S
+0.7 g
+0 G
+1 w
+274.2 534.799 m
+292.2 531.599 296.6 533.199 V
+305.4 533.199 297 531.199 V
+284.2 531.199 276.2 532.399 V
+264.6 537.999 274.2 534.799 V
+f
+0 0 0.2 0 k
+0.5 w
+288.2 627.999 m
+305.8 627.999 307.8 627.199 V
+315 596.399 311.4 588.799 V
+310.2 585.999 307.4 591.599 V
+289 624.399 285.8 626.399 v
+282.6 628.399 287 627.999 288.2 627.999 C
+b
+211.1 630.699 m
+220 628.999 232.6 626.399 V
+237.4 603.999 240.6 599.199 v
+243.8 594.399 240.2 594.399 236.6 597.199 c
+233 599.999 218.2 613.999 216.2 618.399 c
+214.2 622.799 211.1 630.699 y
+b
+232.961 626.182 m
+238.761 624.634 239.77 622.419 v
+240.778 620.205 238.568 616.908 y
+237.568 613.603 236.366 615.765 v
+235.164 617.928 232.292 625.588 232.961 626.182 c
+b
+0 g
+233 626.399 m
+236.6 621.199 240.2 621.199 v
+243.8 621.199 244.182 621.612 247 620.999 c
+251.6 619.999 251.2 621.999 257.8 620.799 c
+260.44 620.319 263 621.199 265.8 619.999 c
+268.6 618.799 271.8 619.599 273 621.599 c
+274.2 623.599 279 627.799 Y
+266.2 625.999 263.4 625.199 V
+241 623.999 233 626.399 V
+f
+0 0 0.2 0 k
+277.6 626.199 m
+271.15 622.699 270.75 620.299 v
+270.35 617.899 276 614.199 y
+278.75 609.599 279.35 611.999 v
+279.95 614.399 278.4 625.799 277.6 626.199 c
+b
+240.115 620.735 m
+247.122 609.547 247.339 620.758 V
+247.896 622.016 246.136 622.038 v
+240.061 622.114 241.582 626.216 240.115 620.735 C
+b
+247.293 620.486 m
+255.214 609.299 254.578 620.579 V
+254.585 620.911 252.832 621.064 v
+248.085 621.478 248.43 625.996 247.293 620.486 C
+b
+254.506 620.478 m
+262.466 609.85 261.797 619.516 V
+261.916 620.749 260.262 621.05 v
+256.37 621.756 256.159 625.005 254.506 620.478 C
+b
+261.382 620.398 m
+269.282 608.837 269.63 618.618 V
+271.274 619.996 269.528 620.218 v
+263.71 620.958 264.508 625.412 261.382 620.398 C
+b
+0 0 0.2 0.1 k
+225.208 616.868 m
+217.55 618.399 l
+214.95 623.399 212.85 629.549 y
+219.2 628.549 231.7 625.749 V
+232.576 622.431 234.048 616.636 v
+225.208 616.868 l
+f
+290.276 621.53 m
+288.61 624.036 287.293 625.794 286.643 626.2 c
+283.63 628.083 287.773 627.706 288.902 627.706 C
+305.473 627.706 307.356 626.953 V
+307.88 624.711 308.564 621.32 V
+298.476 623.33 290.276 621.53 V
+f
+0.2 0.55 0.85 0 k
+1 w
+343.88 759.679 m
+371.601 755.719 397.121 791.359 398.881 801.04 c
+400.641 810.72 390.521 822.6 Y
+391.841 825.68 387.001 839.76 381.721 849 c
+376.441 858.24 360.54 857.266 343 858.24 c
+327.16 859.12 308.68 835.8 307.36 834.04 c
+306.04 832.28 312.2 793.999 313.52 788.279 c
+314.84 782.559 312.2 756.159 y
+346.44 765.259 316.16 763.639 343.88 759.679 c
+f
+0.08 0.44 0.68 0 k
+308.088 833.392 m
+306.792 831.664 312.84 794.079 314.136 788.463 c
+315.432 782.847 312.84 756.927 y
+345.512 765.807 316.728 764.271 343.944 760.383 c
+371.161 756.495 396.217 791.487 397.945 800.992 c
+399.673 810.496 389.737 822.16 Y
+391.033 825.184 386.281 839.008 381.097 848.08 c
+375.913 857.152 360.302 856.195 343.08 857.152 c
+327.528 858.016 309.384 835.12 308.088 833.392 c
+f
+0.06 0.33 0.51 0 k
+308.816 832.744 m
+307.544 831.048 313.48 794.159 314.752 788.647 c
+316.024 783.135 313.48 757.695 y
+344.884 766.855 317.296 764.903 344.008 761.087 c
+370.721 757.271 395.313 791.615 397.009 800.944 c
+398.705 810.272 388.953 821.72 Y
+390.225 824.688 385.561 838.256 380.473 847.16 c
+375.385 856.064 360.063 855.125 343.16 856.064 c
+327.896 856.912 310.088 834.44 308.816 832.744 c
+f
+0.04 0.22 0.34 0 k
+309.544 832.096 m
+308.296 830.432 314.12 794.239 315.368 788.831 c
+316.616 783.423 314.12 758.463 y
+343.556 767.503 317.864 765.535 344.072 761.791 c
+370.281 758.047 394.409 791.743 396.073 800.895 c
+397.737 810.048 388.169 821.28 Y
+389.417 824.192 384.841 837.504 379.849 846.24 c
+374.857 854.976 359.824 854.055 343.24 854.976 c
+328.264 855.808 310.792 833.76 309.544 832.096 c
+f
+0.02 0.11 0.17 0 k
+310.272 831.448 m
+309.048 829.816 314.76 794.319 315.984 789.015 c
+317.208 783.711 314.76 759.231 y
+342.628 768.151 318.432 766.167 344.136 762.495 c
+369.841 758.823 393.505 791.871 395.137 800.848 c
+396.769 809.824 387.385 820.84 Y
+388.609 823.696 384.121 836.752 379.225 845.32 c
+374.329 853.888 359.585 852.985 343.32 853.888 c
+328.632 854.704 311.496 833.08 310.272 831.448 c
+f
+1 g
+344.2 763.2 m
+369.4 759.6 392.601 792 394.201 800.8 c
+395.801 809.6 386.601 820.4 Y
+387.801 823.2 383.4 836 378.6 844.4 c
+373.8 852.8 359.346 851.914 343.4 852.8 c
+329 853.6 312.2 832.4 311 830.8 c
+309.8 829.2 315.4 794.4 316.6 789.2 c
+317.8 784 315.4 760 y
+340.9 768.6 319 766.8 344.2 763.2 c
+f
+0.8 g
+390.601 797.2 m
+362.8 789.6 351.2 791.2 V
+335.4 797.8 326.6 776 V
+323 768.8 321 766.8 v
+319 764.8 390.601 797.2 Y
+f
+0 g
+394.401 799.4 m
+365.4 787.2 355.4 787.6 v
+339 792.2 330.6 777.6 V
+322.2 768.4 319 766.8 V
+318.6 765.2 325 769.2 V
+335.4 764 l
+350.2 754.4 359.8 770.4 V
+363.8 781.6 363.8 783.6 v
+363.8 785.6 385 791.2 386.601 791.6 c
+388.201 792 394.801 796.2 394.401 799.4 C
+f
+0.4 0.2 0.8 0 k
+347 763.486 m
+340.128 763.486 331.755 767.351 331.755 773.6 c
+331.755 779.848 340.128 786.113 347 786.113 c
+353.874 786.113 359.446 781.048 359.446 774.8 c
+359.446 768.551 353.874 763.486 347 763.486 c
+f
+0.4 0.2 0.8 0.2 k
+343.377 780.17 m
+338.531 779.448 333.442 777.945 333.514 778.161 c
+335.054 782.78 341.415 786.113 347 786.113 c
+351.296 786.113 355.084 784.135 357.32 781.125 c
+352.004 781.455 343.377 780.17 v
+f
+1 g
+355.4 780.4 m
+351 783.6 351 781.4 V
+354.6 777 355.4 780.4 V
+f
+0 g
+345.4 772.274 m
+342.901 772.274 340.875 774.3 340.875 776.8 c
+340.875 779.299 342.901 781.325 345.4 781.325 c
+347.9 781.325 349.926 779.299 349.926 776.8 c
+349.926 774.3 347.9 772.274 345.4 772.274 c
+f
+0.2 0.55 0.85 0 k
+241.4 785.6 m
+238.2 806.8 240.6 811.2 V
+251.4 821.2 251 824.8 V
+250.6 842.8 249.4 843.6 v
+248.2 844.4 240.6 850.4 234.6 844 C
+224.2 826 225 819.6 V
+225 817.6 l
+217.4 818 215.8 816 V
+214.6 810.8 213.4 810.4 V
+210.6 808 212.6 805.2 V
+210.6 802.8 211 798.8 V
+218.6 794.8 L
+220.6 780.4 231.4 775.2 v
+236.236 772.871 239.4 779.6 241.4 785.6 c
+f
+1 g
+240.4 787.44 m
+237.52 806.52 239.68 810.48 V
+249.4 819.48 249.04 822.72 V
+248.68 838.92 247.6 839.64 v
+246.52 840.36 239.68 845.76 234.28 840 C
+224.92 823.8 225.64 818.04 V
+225.64 816.24 l
+218.8 816.6 217.36 814.8 V
+216.28 810.12 215.2 809.76 V
+212.68 807.6 214.48 805.08 V
+212.68 802.92 213.04 799.32 V
+219.88 795.72 L
+221.68 782.76 231.4 778.08 v
+235.752 775.985 238.6 782.04 240.4 787.44 c
+f
+0.075 0.412 0.637 0 k
+248.95 842.61 m
+247.86 843.47 240.37 849.24 234.52 843 C
+224.38 825.45 225.16 819.21 V
+225.16 817.26 l
+217.75 817.65 216.19 815.7 V
+215.02 810.63 213.85 810.24 V
+211.12 807.9 213.07 805.17 V
+211.12 802.83 211.51 798.93 V
+218.92 795.03 L
+220.87 780.99 231.4 775.92 v
+236.114 773.65 239.2 780.21 241.15 786.06 c
+238.03 806.73 240.37 811.02 V
+250.9 820.77 250.51 824.28 V
+250.12 841.83 248.95 842.61 V
+f
+0.05 0.275 0.425 0 k
+248.5 841.62 m
+247.52 842.54 240.14 848.08 234.44 842 C
+224.56 824.9 225.32 818.82 V
+225.32 816.92 l
+218.1 817.3 216.58 815.4 V
+215.44 810.46 214.3 810.08 V
+211.64 807.8 213.54 805.14 V
+211.64 802.86 212.02 799.06 V
+219.24 795.26 L
+221.14 781.58 231.4 776.64 v
+235.994 774.428 239 780.82 240.9 786.52 c
+237.86 806.66 240.14 810.84 V
+250.4 820.34 250.02 823.76 V
+249.64 840.86 248.5 841.62 V
+f
+0.025 0.137 0.212 0 k
+248.05 840.63 m
+247.18 841.61 239.91 846.92 234.36 841 C
+224.74 824.35 225.48 818.43 V
+225.48 816.58 l
+218.45 816.95 216.97 815.1 V
+215.86 810.29 214.75 809.92 V
+212.16 807.7 214.01 805.11 V
+212.16 802.89 212.53 799.19 V
+219.56 795.49 L
+221.41 782.17 231.4 777.36 v
+235.873 775.206 238.8 781.43 240.65 786.98 c
+237.69 806.59 239.91 810.66 V
+249.9 819.91 249.53 823.24 V
+249.16 839.89 248.05 840.63 V
+f
+1 g
+240.4 787.54 m
+237.52 806.52 239.68 810.48 V
+249.4 819.48 249.04 822.72 V
+248.68 838.92 247.6 839.64 V
+246.84 840.68 239.68 845.76 234.28 840 C
+224.92 823.8 225.64 818.04 V
+225.64 816.24 l
+218.8 816.6 217.36 814.8 V
+216.28 810.12 215.2 809.76 V
+212.68 807.6 214.48 805.08 V
+212.68 802.92 213.04 799.32 V
+219.88 795.72 L
+221.68 782.76 231.4 778.08 v
+235.752 775.985 238.6 782.14 240.4 787.54 c
+f
+0.8 g
+237.3 793.8 m
+215.7 804 214.8 804.8 V
+223.9 796.6 224.7 796.6 v
+225.5 796.6 237.3 793.8 Y
+f
+0 g
+220.2 800 m
+238.6 796.4 238.6 792 v
+238.6 789.088 238.357 775.669 233 777.2 c
+224.6 779.6 228.2 794 220.2 800 c
+f
+0.4 0.2 0.8 0 k
+228.6 796.2 m
+237.578 794.726 238.6 792 v
+239.2 790.4 239.863 782.092 234.4 781 c
+229.848 780.089 227.618 790.31 228.6 796.2 c
+f
+0 g
+314.595 753.651 m
+314.098 755.393 315.409 755.262 317.2 755.8 c
+319.2 756.4 331.4 760.2 332.2 762.8 c
+333 765.4 346.2 761 Y
+348 760.2 352.4 757.6 Y
+357.2 756.4 363.8 756 Y
+366.2 755 369.6 752.2 Y
+384.2 742 396.601 749.2 Y
+416.601 755.8 410.601 773 Y
+407.601 782 410.801 785.4 Y
+411.001 789.2 418.201 782.8 Y
+420.801 778.6 421.601 773.6 Y
+429.601 762.4 426.201 780.2 Y
+426.401 781.2 423.601 784.8 423.601 786 c
+423.601 787.2 421.801 790.6 Y
+418.801 794 421.201 801 Y
+423.001 814.8 420.801 813 Y
+419.601 814.8 410.401 804.8 Y
+408.201 801.4 402.201 799.8 Y
+399.401 798 396.001 799.4 Y
+393.401 799.8 387.801 792.8 Y
+390.601 793 393.001 788.6 395.401 788.4 c
+397.801 788.2 399.601 790.8 401.201 791.4 c
+402.801 792 405.601 786.2 Y
+406.001 783.6 400.401 778.8 Y
+400.001 774.2 398.401 775.8 Y
+395.401 776.4 394.201 772.6 393.201 768 c
+392.201 763.4 388.001 763 y
+386.401 755.6 385.2 758.6 Y
+385 764.2 379 758.4 Y
+377.8 756.4 373.2 758.6 Y
+366.4 760.6 368.8 762.6 Y
+370.6 764.8 381.8 762.6 Y
+384 764.2 376 768.2 Y
+375.4 770 376.4 774.4 Y
+377.6 777.6 384.4 783.2 Y
+393.801 784.4 391.001 786 Y
+384.801 791.2 379 783.6 Y
+376.8 777.4 359.4 762.4 Y
+354.6 759 357.2 765.8 353.2 762.4 c
+349.2 759 328.6 768 y
+317.038 769.193 314.306 753.451 310.777 756.571 c
+316.195 748.051 314.595 753.651 v
+f
+509.401 920 m
+483.801 912 481.001 893.2 V
+478.601 870.4 499.001 852.8 V
+499.401 846.4 501.401 843.2 v
+499.801 838.4 518.601 846 V
+545.801 854.4 l
+552.201 856.8 557.401 865.6 v
+562.601 874.4 577.801 893.2 574.201 918.4 C
+575.401 929.6 569.401 930 V
+561.001 931.6 553.801 924 V
+547.001 920.8 544.601 921.2 V
+509.401 920 L
+f
+564.022 920.99 m
+566.122 929.92 561.282 925.08 V
+554.242 919.36 546.761 919.36 V
+532.241 917.16 527.841 903.96 V
+523.881 877.12 531.801 871.4 V
+536.641 863.92 543.681 870.52 v
+550.722 877.12 566.222 907.35 564.022 920.99 C
+f
+0.2 g
+563.648 920.632 m
+565.738 929.376 560.986 924.624 V
+554.074 919.008 546.729 919.008 V
+532.473 916.848 528.153 903.888 V
+524.265 877.536 532.041 871.92 V
+536.793 864.576 543.705 871.056 v
+550.618 877.536 565.808 907.24 563.648 920.632 C
+f
+0.4 g
+563.274 920.274 m
+565.354 928.832 560.69 924.168 V
+553.906 918.656 546.697 918.656 V
+532.705 916.536 528.465 903.816 V
+524.649 877.952 532.281 872.44 V
+536.945 865.232 543.729 871.592 v
+550.514 877.952 565.394 907.13 563.274 920.274 C
+f
+0.6 g
+562.9 919.916 m
+564.97 928.288 560.394 923.712 V
+553.738 918.304 546.665 918.304 V
+532.937 916.224 528.777 903.744 V
+525.033 878.368 532.521 872.96 V
+537.097 865.888 543.753 872.128 v
+550.41 878.368 564.98 907.02 562.9 919.916 C
+f
+0.8 g
+562.526 919.558 m
+564.586 927.744 560.098 923.256 V
+553.569 917.952 546.633 917.952 V
+533.169 915.912 529.089 903.672 V
+525.417 878.784 532.761 873.48 V
+537.249 866.544 543.777 872.664 v
+550.305 878.784 564.566 906.91 562.526 919.558 C
+f
+1 g
+562.151 919.2 m
+564.201 927.2 559.801 922.8 V
+553.401 917.6 546.601 917.6 V
+533.401 915.6 529.401 903.6 V
+525.801 879.2 533.001 874 V
+537.401 867.2 543.801 873.2 v
+550.201 879.2 564.151 906.8 562.151 919.2 C
+f
+0.1 0.55 0.85 0.3 k
+350.6 716 m
+330.2 735.2 322.2 736 V
+287.8 740 273 722 V
+290.6 742.4 318.2 736.8 V
+296.6 741.2 284.2 738 V
+267.4 738 257.8 724 V
+255 719.2 l
+259 734 277.4 740 V
+300.2 744.8 311 740 V
+289.4 746.8 279.4 744.8 V
+249 747.2 236.2 720.8 V
+240.2 735.2 255 742.4 V
+268.6 751.2 289 748.4 V
+303.4 745.2 308.6 742.8 v
+313.8 740.4 312.6 743.2 304.2 748 C
+298.6 758 284.6 757.6 V
+241.8 754 231.4 742 V
+245 753.2 255.4 756 V
+277.8 764 286.2 763.2 V
+311 762.2 318.6 766.2 V
+307.4 761.2 310.6 758 v
+313.8 754.8 320.6 747.2 320.6 746 c
+320.6 744.8 344.8 722.7 348.4 718.3 C
+350.6 716 l
+f
+0.8 g
+1 J 0.1 w
+489 522 m
+473.5 558.5 461 568 V
+487 552 490.5 534 V
+490.5 524 489 522 V
+f
+536 514.5 m
+509.5 569.5 491 593.5 V
+534.5 556 539.5 529.5 V
+540 524 l
+537 526.5 l
+536.5 517.5 536 514.5 V
+f
+592.5 563 m
+530 622.5 528.5 625 V
+589 559 592 551.5 V
+590 560.5 592.5 563 V
+f
+404 519.5 m
+423.5 571.5 442.5 549 V
+457.5 539 457 536 V
+453 542.5 435 542 V
+416 545 404 519.5 V
+f
+594.5 647 m
+549.5 675.5 542 677 v
+530.193 679.361 591.5 648 596.5 637.5 C
+598.5 640 594.5 647 V
+f
+0 g
+0 J 1 w
+443.801 540.399 m
+464.201 542.399 471.001 549.199 V
+475.401 545.599 l
+493.001 583.999 l
+496.601 578.799 l
+511.001 593.599 510.201 601.599 v
+509.401 609.599 523.001 595.599 y
+522.201 607.199 529.401 600.399 V
+527.001 615.999 535.401 607.999 V
+524.864 638.156 547.401 612.399 v
+553.001 605.999 548.601 612.799 y
+522.601 660.799 544.201 646.399 v
+546.201 669.199 545.001 673.599 v
+543.801 677.999 541.801 700.4 537.001 705.6 c
+532.201 710.8 537.401 712.4 543.001 707.2 C
+531.801 731.2 545.001 719.2 V
+541.401 734.4 537.001 737.2 V
+531.401 754.4 546.601 743.6 V
+542.201 756 539.001 759.2 V
+527.401 786.8 534.601 782 V
+539.001 778.4 l
+532.201 792.4 538.601 788 v
+545.001 783.6 545.001 784 y
+523.801 817.2 544.201 799.6 V
+536.042 813.518 532.601 820.4 V
+513.801 840.8 528.201 834.4 V
+533.001 832.8 l
+524.201 842.8 516.201 844.4 v
+508.201 846 518.601 852.4 525.001 850.4 c
+531.401 848.4 547.001 840.8 y
+559.801 822 563.801 821.6 V
+543.801 829.2 549.801 821.2 V
+564.201 807.2 557.001 807.6 V
+551.001 800.4 555.801 791.6 V
+537.342 809.991 552.201 784.4 v
+559.001 768 l
+534.601 792.8 545.801 770.8 V
+563.001 747.2 565.001 746.8 v
+567.001 746.4 571.401 737.6 y
+567.001 739.6 l
+572.201 730.8 l
+561.001 742.8 567.001 729.6 V
+572.601 715.2 l
+552.201 737.2 565.801 707.6 V
+549.401 712.8 558.201 695.6 V
+556.601 679.599 557.001 674.399 v
+557.401 669.199 558.601 640.799 554.201 632.799 c
+549.801 624.799 560.201 605.599 562.201 601.599 c
+564.201 597.599 567.801 586.799 559.001 595.999 c
+550.201 605.199 554.601 599.599 556.601 590.799 c
+558.601 581.999 564.601 566.399 563.801 560.799 C
+562.601 559.599 559.401 563.199 V
+544.601 585.999 546.201 571.599 V
+545.001 563.599 541.801 554.799 V
+538.601 543.999 538.601 552.799 V
+535.401 569.599 532.601 561.999 v
+529.801 554.399 526.201 548.399 523.401 545.999 c
+520.601 543.599 515.401 566.399 514.201 555.999 C
+502.201 568.399 497.401 551.999 V
+485.801 535.599 l
+485.401 547.999 484.201 541.999 V
+454.201 535.999 443.801 540.399 V
+f
+409.401 897.2 m
+397.801 905.2 393.801 904.8 v
+389.801 904.4 421.401 913.6 462.601 886 C
+467.401 883.2 471.001 883.6 V
+474.201 881.2 471.401 877.6 V
+462.601 868 473.801 856.8 V
+492.201 850 486.601 858.8 V
+497.401 854.8 499.801 850.8 v
+502.201 846.8 501.001 850.8 y
+494.601 858 488.601 863.2 V
+483.401 865.2 480.601 873.6 v
+477.801 882 475.401 892 479.801 895.2 C
+475.801 890.8 476.601 894.8 v
+477.401 898.8 481.001 902.4 482.601 902.8 c
+484.201 903.2 500.601 919 507.401 919.4 C
+498.201 918 495.201 919 v
+492.201 920 465.601 931.4 459.601 932.6 C
+442.801 939.2 454.801 937.2 V
+490.601 933.4 508.801 920.2 V
+501.601 928.6 483.201 935.6 V
+461.001 948.2 425.801 943.2 V
+408.001 940 400.201 938.2 V
+397.601 938.8 397.001 939.2 v
+396.401 939.6 384.6 948.6 357 941.6 C
+340 937 331.4 932.2 V
+316.2 931 312.6 927.8 V
+294 913.2 292 912.4 v
+290 911.6 278.6 904 277.8 903.6 C
+302.4 910.2 304.8 912.6 v
+307.2 915 324.6 917.6 327 916.2 c
+329.4 914.8 337.8 915.4 328.2 914.8 C
+403.801 900 404.601 898 v
+405.401 896 409.401 897.2 y
+f
+0.2 0.55 0.85 0 k
+480.801 906.4 m
+470.601 913.8 468.601 913.8 v
+466.601 913.8 454.201 924 450.001 923.6 c
+445.801 923.2 433.601 933.2 406.201 925 C
+405.601 927 409.201 927.8 V
+415.601 930 416.001 930.6 V
+436.201 934.8 443.401 931.2 V
+452.601 928.6 458.801 922.4 V
+470.001 919.2 473.201 920.2 V
+482.001 918 482.401 916.2 V
+488.201 913.2 486.401 910.6 V
+486.801 909 480.801 906.4 V
+f
+468.33 908.509 m
+469.137 907.877 470.156 907.779 470.761 906.97 c
+470.995 906.656 470.706 906.33 470.391 906.233 c
+469.348 905.916 468.292 906.486 467.15 905.898 c
+466.748 905.691 466.106 905.873 465.553 906.022 c
+463.921 906.463 462.092 906.488 460.401 905.8 C
+458.416 906.929 456.056 906.345 453.975 907.346 c
+453.917 907.373 453.695 907.027 453.621 907.054 c
+450.575 908.199 446.832 907.916 444.401 910.2 C
+441.973 910.612 439.616 911.074 437.188 911.754 c
+435.37 912.263 433.961 913.252 432.341 914.084 c
+430.964 914.792 429.507 915.314 427.973 915.686 c
+426.11 916.138 424.279 916.026 422.386 916.546 c
+422.293 916.571 422.101 916.227 422.019 916.254 c
+421.695 916.362 421.405 916.945 421.234 916.892 c
+419.553 916.37 418.065 917.342 416.401 917 C
+415.223 918.224 413.495 917.979 411.949 918.421 c
+408.985 919.269 405.831 917.999 402.801 919 C
+406.914 920.842 411.601 919.61 415.663 921.679 c
+417.991 922.865 420.653 921.763 423.223 922.523 c
+423.71 922.667 424.401 922.869 424.801 922.2 C
+424.935 922.335 425.117 922.574 425.175 922.546 c
+427.625 921.389 429.94 920.115 432.422 919.049 c
+432.763 918.903 433.295 919.135 433.547 918.933 c
+435.067 917.717 437.01 917.82 438.401 916.6 C
+440.099 917.102 441.892 916.722 443.621 917.346 c
+443.698 917.373 443.932 917.032 443.965 917.054 c
+445.095 917.802 446.25 917.531 447.142 917.227 c
+447.48 917.112 448.143 916.865 448.448 916.791 c
+449.574 916.515 450.43 916.035 451.609 915.852 c
+451.723 915.834 451.908 916.174 451.98 916.146 c
+453.103 915.708 454.145 915.764 454.801 914.6 C
+454.936 914.735 455.101 914.973 455.183 914.946 c
+456.21 914.608 456.859 913.853 457.96 913.612 c
+458.445 913.506 459.057 912.88 459.633 912.704 c
+462.025 911.973 463.868 910.444 466.062 909.549 c
+466.821 909.239 467.697 909.005 468.33 908.509 c
+f
+391.696 922.739 m
+389.178 924.464 386.81 925.57 384.368 927.356 c
+384.187 927.489 383.827 927.319 383.625 927.441 c
+382.618 928.05 381.73 928.631 380.748 929.327 c
+380.209 929.709 379.388 929.698 378.88 929.956 c
+376.336 931.248 373.707 931.806 371.2 933 C
+371.882 933.638 373.004 933.394 373.6 934.2 C
+373.795 933.92 374.033 933.636 374.386 933.827 c
+376.064 934.731 377.914 934.884 379.59 934.794 c
+381.294 934.702 383.014 934.397 384.789 934.125 c
+385.096 934.078 385.295 933.555 385.618 933.458 c
+387.846 932.795 390.235 933.32 392.354 932.482 c
+393.945 931.853 395.515 931.03 396.754 929.755 c
+397.006 929.495 396.681 929.194 396.401 929 C
+396.789 929.109 397.062 928.903 397.173 928.59 c
+397.257 928.351 397.257 928.049 397.173 927.81 c
+397.061 927.498 396.782 927.397 396.408 927.346 c
+395.001 927.156 396.773 928.536 396.073 928.088 c
+394.8 927.274 395.546 925.868 394.801 924.6 C
+394.521 924.794 394.291 925.012 394.401 925.4 C
+394.635 924.878 394.033 924.588 393.865 924.272 c
+393.48 923.547 392.581 922.132 391.696 922.739 c
+f
+359.198 915.391 m
+356.044 916.185 352.994 916.07 349.978 917.346 c
+349.911 917.374 349.688 917.027 349.624 917.054 c
+348.258 917.648 347.34 918.614 346.264 919.66 c
+345.351 920.548 343.693 920.161 342.419 920.648 c
+342.095 920.772 341.892 921.284 341.591 921.323 c
+340.372 921.48 339.445 922.429 338.4 923 C
+340.736 923.795 343.147 923.764 345.609 924.148 c
+345.722 924.166 345.867 923.845 346 923.845 c
+346.136 923.845 346.266 924.066 346.4 924.2 C
+346.595 923.92 346.897 923.594 347.154 923.848 c
+347.702 924.388 348.258 924.198 348.798 924.158 c
+348.942 924.148 349.067 923.845 349.2 923.845 c
+349.336 923.845 349.467 924.156 349.6 924.156 c
+349.736 924.155 349.867 923.845 350 923.845 c
+350.136 923.845 350.266 924.066 350.4 924.2 C
+351.092 923.418 351.977 923.972 352.799 923.793 c
+353.837 923.566 354.104 922.418 355.178 922.12 c
+359.893 920.816 364.03 918.671 368.393 916.584 c
+368.7 916.437 368.91 916.189 368.8 915.8 C
+369.067 915.8 369.38 915.888 369.57 915.756 c
+370.628 915.024 371.669 914.476 372.366 913.378 c
+372.582 913.039 372.253 912.632 372.02 912.684 c
+367.591 913.679 363.585 914.287 359.198 915.391 c
+f
+345.338 871.179 m
+343.746 872.398 343.162 874.429 342.034 876.221 c
+341.82 876.561 342.094 876.875 342.411 876.964 c
+342.971 877.123 343.514 876.645 343.923 876.443 c
+345.668 875.581 347.203 874.339 349.2 874.2 C
+351.19 871.966 355.45 871.581 355.457 868.2 c
+355.458 867.341 354.03 868.259 353.6 867.4 C
+351.149 868.403 348.76 868.3 346.38 869.767 c
+345.763 870.148 346.093 870.601 345.338 871.179 c
+f
+317.8 923.756 m
+317.935 923.755 324.966 923.522 324.949 923.408 c
+324.904 923.099 317.174 922.05 316.81 922.22 c
+316.646 922.296 309.134 919.866 309 920 C
+309.268 920.135 317.534 923.756 317.8 923.756 c
+f
+0 g
+333.2 914 m
+318.4 912.2 314 911 v
+309.6 909.8 291 902.2 288 900.2 C
+274.6 894.8 257.6 874.8 V
+265.2 878.2 267.4 881 V
+281 893.6 280.8 891 V
+293 899.6 292.4 897.4 V
+316.8 908.6 314.8 905.4 V
+336.4 910 335.4 908 V
+354.2 903.6 351.4 903.4 V
+345.6 902.2 352 898.6 V
+348.6 894.2 343.2 898.2 v
+337.8 902.2 340.8 900 335.8 899 C
+333.2 898.2 328.6 902.2 V
+323 906.8 314.2 903.2 V
+283.6 890.6 281.6 890 V
+278 887.2 275.6 883.6 V
+269.8 879.2 266.8 877.8 V
+254 866.2 252.8 864.8 V
+249.4 859.6 248.6 859.2 V
+255 863 257 865 V
+271 875 276.4 875.8 V
+280.8 878.8 281.6 880.2 V
+296 889.4 300.2 889.4 V
+309.4 884.2 311.8 891.2 V
+317.6 893 323.2 891.8 V
+326.4 894.4 325.6 896.6 V
+327.2 898.4 328.2 894.6 V
+331.6 891 336.4 893 V
+340.4 893.2 338.4 890.8 V
+334 887 322.2 886.8 V
+309.8 886.2 293.4 878.6 V
+263.6 868.2 254.4 857.8 V
+248 849 242.6 847.8 V
+236.8 847 230.8 839.6 V
+240.6 845.4 249.6 845.4 V
+253.6 847.8 249.8 844.2 V
+246.2 836.6 247.8 831.2 V
+247.2 826 246.4 824.4 V
+238.6 811.6 238.6 809.2 v
+238.6 806.8 239.8 797 240.2 796.4 c
+240.6 795.8 239.2 798 243 795.6 c
+246.8 793.2 249.6 791.6 250.4 788.8 c
+251.2 786 248.4 794.2 248.2 796 c
+248 797.8 243.8 805 244.6 807.4 C
+245.6 806.4 246.4 805 V
+245.8 805.6 246.4 809.2 V
+247.2 814.4 248.6 817.6 v
+250 820.8 252 824.6 252.4 825.4 c
+252.8 826.2 252.8 832 254.2 829.4 C
+257.6 826.8 l
+254.8 829.4 257 831.6 V
+256 837.2 257.8 839.8 V
+264.8 848.2 266.4 849.2 v
+268 850.2 266.6 849.8 y
+272.6 854 266.8 852.4 V
+262.8 850.8 259.8 850.8 V
+252.2 848.8 256.2 853 v
+260.2 857.2 270.2 862.6 274 862.4 C
+274.8 860.8 l
+286 863.2 l
+284.8 862.4 l
+284.6 862.6 288.8 863 v
+293 863.4 298.8 862 300.2 863.8 c
+301.6 865.6 305 866.6 304.6 865.2 c
+304.2 863.8 304 861.8 y
+309 867.6 308.4 865.4 v
+307.8 863.2 299.6 858 298.2 851.8 C
+308.6 860 l
+312.2 863 l
+315.8 860.8 316 862.4 v
+316.2 864 320.8 869.8 322 869.6 c
+323.2 869.4 325.2 872.2 325 869.6 c
+324.8 867 332.4 861.6 y
+335.6 863.4 337 862 v
+338.4 860.6 342.6 881.8 y
+367.6 892.4 l
+411.201 895.8 l
+394.201 902.6 l
+333.2 914 l
+f
+0.2 0.55 0.85 0.5 K
+1 J 2 w
+351.4 715 m
+336.4 731.8 328 734.4 V
+314.6 741.2 290 733.4 v
+S
+324.8 735.8 m
+299.6 743.8 284.2 739.6 V
+265.8 737.6 257.4 723.8 v
+S
+321.2 737 m
+304.2 744.2 289.4 746.4 V
+272.8 749 256.2 741.8 V
+244 735.8 238.6 725.6 v
+S
+322.2 736.6 m
+306.8 747.6 305.8 749 V
+298.8 760 285.8 760.4 V
+264.4 759.6 247.2 751.6 v
+S
+0 G
+0 J 1 w
+320.895 745.593 m
+322.437 744.13 349.4 715.2 Y
+384.6 678.599 356.6 712.8 Y
+349 717.6 339.8 736.4 Y
+338.6 739.2 353.8 729.2 Y
+357.8 728.4 371.4 709.2 Y
+364.6 711.6 369.4 704.4 Y
+372.2 702.4 392.601 686.799 Y
+396.201 682.799 400.201 681.199 Y
+414.201 686.399 407.801 673.199 Y
+410.201 666.399 415.801 677.999 Y
+427.001 694.8 410.601 692.399 Y
+380.6 689.599 373.8 705.6 Y
+371.4 708 380.2 705.6 Y
+388.601 703.6 373 718 Y
+375.4 718 384.6 711.2 Y
+395.001 702 397.001 704 Y
+415.001 712.8 425.401 705.2 Y
+427.401 703.6 421.801 696.8 423.401 691.599 c
+425.001 686.399 429.801 673.999 Y
+427.401 672.399 427.801 661.599 Y
+444.601 638.399 435.001 640.399 Y
+419.401 640.799 434.201 633.199 Y
+437.401 631.199 446.201 623.999 Y
+443.401 625.199 441.801 619.999 Y
+446.601 615.999 443.801 611.199 Y
+437.801 609.999 436.601 605.999 Y
+443.401 597.999 433.401 597.599 Y
+437.001 593.199 432.201 581.199 Y
+427.401 581.199 421.001 575.599 Y
+423.401 570.799 413.001 565.199 Y
+404.601 563.599 407.401 556.799 Y
+399.401 550.799 397.001 534.799 Y
+396.201 524.399 393.801 521.199 399.001 523.199 c
+404.201 525.199 403.401 537.599 Y
+398.601 553.199 441.401 569.199 Y
+445.401 570.799 446.201 575.999 Y
+448.201 575.599 457.001 567.999 Y
+464.601 556.799 465.001 565.999 Y
+466.201 569.599 464.601 575.599 Y
+470.601 597.199 456.601 603.599 Y
+446.601 637.199 460.601 628.799 Y
+463.401 623.199 474.201 617.999 y
+477.801 620.399 L
+476.201 625.199 484.601 631.199 Y
+487.401 624.799 493.401 632.799 Y
+497.001 657.199 509.401 642.799 Y
+513.401 641.599 514.601 648.399 Y
+518.201 658.799 514.601 672.399 Y
+518.201 672.799 527.801 666.799 Y
+530.601 670.399 521.401 687.199 525.401 684.799 c
+529.401 682.399 533.801 680.799 Y
+534.601 682.799 524.601 695.199 Y
+520.201 698 515.001 718.4 Y
+522.201 714.8 512.201 730 Y
+512.201 733.2 518.201 744.4 Y
+517.401 751.2 518.201 750.8 Y
+521.001 749.6 529.001 748 522.201 754.4 c
+515.401 760.8 523.001 765.6 Y
+527.401 768.4 513.801 768 Y
+508.601 772.4 509.001 776.4 Y
+517.001 774.4 502.601 788.8 500.201 792.4 c
+497.801 796 507.401 801.2 Y
+520.601 804.8 509.001 808 Y
+489.401 807.6 500.201 818.4 Y
+506.201 818 504.601 820.4 Y
+499.401 821.6 489.801 828 Y
+485.801 831.6 489.401 830.8 Y
+506.201 829.6 477.401 840.8 Y
+485.401 840.8 467.401 851.2 Y
+465.401 852.8 462.201 860.4 Y
+456.201 865.6 451.401 872.4 Y
+451.001 876.8 446.201 881.6 Y
+434.601 895.2 429.001 894.8 Y
+414.201 898.4 409.001 897.6 Y
+356.2 893.2 l
+329.8 880.4 337.6 859.4 Y
+344 851 353.2 854.8 Y
+357.8 861 369.4 858.8 Y
+389.801 855.6 387.201 859.2 Y
+384.801 863.8 368.6 870 368.4 870.6 c
+368.2 871.2 359.4 874.6 Y
+356.4 875.8 352 885 Y
+348.8 888.4 364.6 882.6 Y
+363.4 881.6 370.8 877.6 Y
+388.201 878.6 398.801 867.8 Y
+409.601 851.2 409.801 859.4 Y
+412.601 868.8 400.801 890 Y
+401.201 892 409.401 885.4 Y
+410.801 887.4 411.601 881.6 Y
+411.801 879.2 415.601 871.2 Y
+418.401 858.2 422.001 865.6 Y
+426.601 856.2 L
+428.001 853.6 422.001 846 Y
+421.801 843.2 422.601 843.4 417.001 835.8 c
+411.401 828.2 414.801 823.8 Y
+413.401 817.2 422.201 817.6 Y
+424.801 815.4 428.201 815.4 Y
+430.001 813.4 432.401 814 Y
+434.001 817.8 440.201 815.8 Y
+441.601 818.2 449.801 818.6 Y
+450.801 821.2 451.201 822.8 454.601 823.4 c
+458.001 824 433.401 867 Y
+439.801 867.8 431.601 880.2 Y
+429.401 886.8 440.801 872.2 443.001 870.8 c
+445.201 869.4 446.201 867.2 444.601 867.4 c
+443.001 867.6 441.201 865.4 442.601 865.2 c
+444.001 865 457.001 850 460.401 839.8 c
+463.801 829.6 469.801 825.6 476.001 819.6 c
+482.201 813.6 481.401 789.4 Y
+481.001 780.6 487.001 770 Y
+489.001 766.2 484.801 748 Y
+482.801 745.8 484.201 745 Y
+485.201 743.8 492.001 730.6 Y
+490.201 730.8 493.801 727.2 Y
+499.001 721.2 492.601 724.2 Y
+486.601 725.8 493.601 716 Y
+494.801 714.2 485.801 718.8 Y
+476.601 719.4 488.201 712.2 Y
+496.801 705 485.401 709.4 Y
+480.801 711.2 484.001 704.4 Y
+487.201 702.8 504.401 695.8 Y
+504.801 691.999 501.801 686.999 Y
+502.201 682.999 500.001 679.599 Y
+498.801 671.399 498.201 670.599 Y
+494.001 670.399 486.601 656.599 Y
+484.801 653.999 474.601 641.999 Y
+472.601 634.999 454.601 642.199 Y
+448.001 638.799 450.001 642.199 Y
+449.601 644.399 454.401 650.399 Y
+461.401 652.999 458.801 663.799 Y
+462.801 665.199 451.601 667.999 451.801 669.199 c
+452.001 670.399 457.801 671.799 Y
+465.801 673.799 461.401 676.199 Y
+460.801 680.199 463.801 685.799 Y
+475.401 686.599 463.801 702.8 Y
+453.001 710.4 452.001 716.2 Y
+464.601 724.4 456.401 736.8 456.601 740.4 c
+456.801 744 458.001 765.6 Y
+456.001 771.8 453.001 785.4 Y
+455.201 790.6 462.601 803.2 Y
+465.401 807.4 474.201 812.2 472.001 815.2 c
+469.801 818.2 462.001 816.4 Y
+454.201 817.8 454.801 812.6 Y
+453.201 811.6 452.401 806.6 Y
+451.68 798.667 442.801 792.4 Y
+431.601 786.2 440.801 782.2 Y
+446.801 775.6 437.001 775.4 Y
+426.001 777.2 434.201 767 Y
+445.001 754.2 442.001 751.4 Y
+431.801 750.4 444.401 741.2 y
+443.601 743.2 443.801 741.4 v
+444.001 739.6 447.001 735.4 447.801 733.4 c
+448.601 731.4 444.601 731.2 Y
+445.201 721.6 429.801 725.8 y
+429.801 725.8 428.201 725.6 v
+426.601 725.4 415.401 726.2 409.601 728.4 c
+403.801 730.6 397.001 730.6 y
+393.001 728.8 385.4 729 v
+377.8 729.2 369.8 726.4 Y
+365.4 726.8 374 731.2 374.2 731 c
+374.4 730.8 380 736.4 372 735.8 c
+350.203 734.165 339.4 744.4 Y
+337.4 745.8 334.8 748.6 Y
+324.8 750.6 336.2 736.2 Y
+337.4 734.8 336 733.8 Y
+335.2 735.4 327.4 740.8 Y
+324.589 741.773 323.226 743.107 320.895 745.593 C
+f
+0.2 0.55 0.85 0.5 k
+1 J 2 w
+297 757.2 m
+308.6 751.6 311.2 748.8 v
+313.8 746 327.8 734.6 y
+322.4 736.6 319.8 738.4 v
+317.2 740.2 306.4 748.4 y
+302.6 754.4 297 757.2 v
+f
+0.4 0.2 0.8 0 k
+0 J 1 w
+238.991 788.397 m
+239.328 788.545 238.804 791.257 238.6 791.8 c
+237.578 794.526 228.6 796 y
+228.373 794.635 228.318 793.039 228.424 791.401 c
+233.292 785.882 238.991 788.397 v
+f
+0.4 0.2 0.8 0.2 k
+238.991 788.597 m
+238.542 788.439 238.976 791.331 238.8 791.8 c
+237.778 794.526 228.6 796.1 y
+228.373 794.735 228.318 793.139 228.424 791.501 c
+232.692 786.382 238.991 788.597 v
+f
+0 g
+234.6 788.454 m
+233.975 788.454 233.469 789.594 233.469 791 c
+233.469 792.405 233.975 793.545 234.6 793.545 c
+235.225 793.545 235.732 792.405 235.732 791 c
+235.732 789.594 235.225 788.454 234.6 788.454 c
+f
+234.6 791 m
+F
+189 690.399 m
+183.4 680.399 208.2 686.399 V
+222.2 687.599 224.6 689.999 V
+225.8 689.199 234.166 686.266 237 685.599 c
+243.8 683.999 252.2 694 y
+256.8 704.5 259.6 704.5 v
+262.4 704.5 259.2 702.9 y
+252.6 692.799 253 691.199 V
+247.8 671.199 231.8 670.399 V
+215.65 669.449 217 663.599 V
+225.8 665.999 228.2 663.599 V
+239 663.999 231 657.599 V
+224.2 645.999 l
+224.34 642.081 214.2 645.599 v
+204.4 648.999 194.1 661.899 y
+178.15 676.449 189 690.399 V
+f
+0.1 0.4 0.4 0 k
+187.8 686.399 m
+185.8 676.799 222.6 687.199 V
+227 687.199 229.4 686.399 v
+231.8 685.599 243.8 682.799 245.8 683.999 C
+238.6 670.399 227 671.999 V
+213.8 670.399 214.2 665.599 V
+218.2 658.399 223 655.999 V
+225.8 653.599 225.4 650.399 v
+225 647.199 222.2 645.599 220.2 644.799 c
+218.2 643.999 215 647.199 213.4 647.199 c
+211.8 647.199 203.4 653.599 199 658.399 c
+194.6 663.199 186.2 675.199 186.6 677.999 c
+187 680.799 187.8 686.399 Y
+f
+0.1 0.4 0.4 0.2 k
+191 668.949 m
+193.6 664.999 196.8 660.799 199 658.399 c
+203.4 653.599 211.8 647.199 213.4 647.199 c
+215 647.199 218.2 643.999 220.2 644.799 c
+222.2 645.599 225 647.199 225.4 650.399 c
+225.8 653.599 223 655.999 Y
+219.934 657.532 217.194 661.024 215.615 663.347 C
+215.8 660.799 210.6 661.599 v
+205.4 662.399 200.2 665.199 198.6 668.399 c
+197 671.599 194.6 673.999 196.2 670.399 c
+197.8 666.799 200.2 663.199 201.8 662.799 c
+203.4 662.399 203 661.199 200.6 661.599 c
+198.2 661.999 195.4 662.399 191 667.599 c
+F
+0.1 0.55 0.85 0.3 k
+188.4 689.999 m
+190.2 703.6 191.4 707.6 V
+190.6 714.4 193 718.6 v
+195.4 722.8 197.4 729 200.4 734.4 c
+203.4 739.8 203.6 743.8 207.6 745.4 c
+211.6 747 217.6 755.6 220.4 756.6 c
+223.2 757.6 223 756.8 y
+229.8 771.6 243.4 767.6 V
+227.2 770.4 243 779.8 V
+238.2 778.7 241.5 785.7 v
+243.701 790.368 243.2 783.6 232.2 771.8 C
+227.2 763.2 222 760.2 v
+216.8 757.2 204.8 750.2 203.6 746.4 c
+202.4 742.6 199.2 736.8 197.2 735.2 c
+195.2 733.6 192.4 729.4 192 726 C
+190.8 722 189.4 720.8 v
+188 719.6 187.8 716.4 187.8 714.4 c
+187.8 712.4 185.8 709.6 186 707.2 C
+186.8 688.199 186.4 686.199 V
+188.4 689.999 L
+f
+1 g
+179.8 685.399 m
+177.8 686.799 173.4 680.799 V
+180.7 647.799 180.7 646.399 V
+181.8 648.499 180.5 655.699 v
+179.2 662.899 178.3 675.599 y
+179.8 685.399 l
+f
+0.1 0.55 0.85 0.3 k
+201.4 746 m
+183.8 742.8 184.2 713.6 V
+183.4 688.799 l
+182.2 714.4 181 716 v
+179.8 717.6 183.8 728.8 180.6 722.8 C
+166.6 708.8 174.6 687.599 V
+176.1 684.299 173.1 688.899 V
+168.5 701.5 169.6 707.9 V
+169.8 710.1 171.7 712.9 V
+180.3 724.6 183 726.9 V
+184.8 741.3 200.2 746.5 V
+205.9 748.8 201.4 746 V
+f
+0 g
+340.8 812.2 m
+341.46 812.554 341.451 813.524 342.031 813.697 c
+343.18 814.041 343.344 815.108 343.862 815.892 c
+344.735 817.211 344.928 818.744 345.51 820.235 c
+345.782 820.935 345.809 821.89 345.496 822.55 c
+344.322 825.031 343.62 827.48 342.178 829.906 c
+341.91 830.356 341.648 831.15 341.447 831.748 c
+340.984 833.132 339.727 834.123 338.867 835.443 c
+338.579 835.884 339.104 836.809 338.388 836.893 c
+337.491 836.998 336.042 837.578 335.809 836.552 c
+335.221 833.965 336.232 831.442 337.2 829 C
+336.418 828.308 336.752 827.387 336.904 826.62 c
+337.614 823.014 336.416 819.662 335.655 816.188 c
+335.632 816.084 335.974 815.886 335.946 815.824 c
+334.724 813.138 333.272 810.693 331.453 808.312 c
+330.695 807.32 329.823 806.404 329.326 805.341 c
+328.958 804.554 328.55 803.588 328.8 802.6 C
+325.365 799.82 323.115 795.975 320.504 792.129 c
+320.042 791.449 320.333 790.24 320.884 789.971 c
+321.697 789.573 322.653 790.597 323.123 791.443 c
+323.512 792.141 323.865 792.791 324.356 793.434 c
+324.489 793.609 324.31 794.028 324.445 794.149 c
+327.078 796.496 328.747 799.432 331.2 801.8 C
+333.15 802.129 334.687 803.127 336.435 804.14 c
+336.743 804.319 337.267 804.07 337.557 804.265 c
+339.31 805.442 339.308 807.478 339.414 809.388 c
+339.464 810.272 339.66 811.589 340.8 812.2 c
+f
+331.959 816.666 m
+332.083 816.743 331.928 817.166 332.037 817.382 c
+332.199 817.706 332.602 817.894 332.764 818.218 c
+332.873 818.434 332.71 818.814 332.846 818.956 c
+335.179 821.403 335.436 824.427 334.4 827.4 C
+335.424 828.02 335.485 829.282 335.06 830.129 c
+334.207 831.829 334.014 833.755 333.039 835.298 c
+332.237 836.567 330.659 837.811 329.288 836.508 c
+328.867 836.108 328.546 835.321 328.824 834.609 c
+328.888 834.446 329.173 834.3 329.146 834.218 c
+329.039 833.894 328.493 833.67 328.487 833.398 c
+328.457 831.902 327.503 830.391 328.133 829.062 c
+328.905 827.433 329.724 825.576 330.4 823.8 C
+329.166 821.684 330.199 819.235 328.446 817.358 c
+328.31 817.212 328.319 816.826 328.441 816.624 c
+328.733 816.138 329.139 815.732 329.625 815.44 c
+329.827 815.319 330.175 815.317 330.375 815.441 c
+330.953 815.803 331.351 816.29 331.959 816.666 c
+f
+394.771 826.977 m
+396.16 825.185 396.45 822.39 394.401 821 C
+394.951 817.691 398.302 819.67 400.401 820.2 C
+400.292 820.588 400.519 820.932 400.802 820.937 c
+401.859 820.952 402.539 821.984 403.601 821.8 C
+404.035 823.357 405.673 824.059 406.317 825.439 c
+408.043 829.134 407.452 833.407 404.868 836.653 c
+404.666 836.907 404.883 837.424 404.759 837.786 c
+404.003 839.997 401.935 840.312 400.001 841 C
+398.824 844.875 398.163 848.906 396.401 852.6 C
+394.787 852.85 394.089 854.589 392.752 855.309 c
+391.419 856.028 390.851 854.449 390.892 853.403 c
+390.899 853.198 391.351 852.974 391.181 852.609 c
+391.105 852.445 390.845 852.334 390.845 852.2 c
+390.846 852.065 391.067 851.934 391.201 851.8 C
+390.283 850.98 388.86 850.503 388.565 849.358 c
+387.611 845.648 390.184 842.523 391.852 839.322 c
+392.443 838.187 391.707 836.916 390.947 835.708 c
+390.509 835.013 390.617 833.886 390.893 833.03 c
+391.645 830.699 393.236 828.96 394.771 826.977 c
+f
+357.611 808.591 m
+356.124 806.74 352.712 804.171 355.629 802.243 c
+355.823 802.114 356.193 802.11 356.366 802.244 c
+358.387 803.809 360.39 804.712 362.826 805.294 c
+362.95 805.323 363.224 804.856 363.593 805.017 c
+365.206 805.72 367.216 805.662 368.4 807 C
+372.167 806.776 375.732 807.892 379.123 809.2 c
+380.284 809.648 381.554 810.207 382.755 810.709 c
+384.131 811.285 385.335 812.213 386.447 813.354 c
+386.58 813.49 386.934 813.4 387.201 813.4 C
+387.161 814.263 388.123 814.39 388.37 815.012 c
+388.462 815.244 388.312 815.64 388.445 815.742 c
+390.583 817.372 391.503 819.39 390.334 821.767 c
+390.049 822.345 389.8 822.963 389.234 823.439 c
+388.149 824.35 387.047 823.496 386 823.8 C
+385.841 823.172 385.112 823.344 384.726 823.146 c
+383.867 822.707 382.534 823.292 381.675 822.854 c
+380.313 822.159 379.072 821.99 377.65 821.613 c
+377.338 821.531 376.56 821.627 376.4 821 C
+376.266 821.134 376.118 821.368 376.012 821.346 c
+374.104 820.95 372.844 820.736 371.543 819.044 c
+371.44 818.911 370.998 819.09 370.839 818.955 c
+369.882 818.147 369.477 816.913 368.376 816.241 c
+368.175 816.118 367.823 816.286 367.629 816.157 c
+366.983 815.726 366.616 815.085 365.974 814.638 c
+365.645 814.409 365.245 814.734 365.277 814.99 c
+365.522 816.937 366.175 818.724 365.6 820.6 C
+367.677 823.12 370.194 825.069 372 827.8 C
+372.015 829.966 372.707 832.112 372.594 834.189 c
+372.584 834.382 372.296 835.115 372.17 835.462 c
+371.858 836.316 372.764 837.382 371.92 838.106 c
+370.516 839.309 369.224 838.433 368.4 837 C
+366.562 836.61 364.496 835.917 362.918 837.151 c
+361.911 837.938 361.333 838.844 360.534 839.9 c
+359.549 841.202 359.884 842.638 359.954 844.202 c
+359.96 844.33 359.645 844.466 359.645 844.6 c
+359.646 844.735 359.866 844.866 360 845 C
+359.294 845.626 359.019 846.684 358 847 C
+358.305 848.092 357.629 848.976 356.758 849.278 c
+354.763 849.969 353.086 848.057 351.194 847.984 c
+350.68 847.965 350.213 849.003 349.564 849.328 c
+349.132 849.544 348.428 849.577 348.066 849.311 c
+347.378 848.807 346.789 848.693 346.031 848.488 c
+344.414 848.052 343.136 846.958 341.656 846.103 c
+340.171 845.246 339.216 843.809 338.136 842.489 c
+337.195 841.337 337.059 838.923 338.479 838.423 c
+340.322 837.773 341.626 840.476 343.592 840.15 c
+343.904 840.099 344.11 839.788 344 839.4 C
+344.389 839.291 344.607 839.52 344.8 839.8 C
+345.658 838.781 346.822 838.444 347.76 837.571 c
+348.73 836.667 350.476 837.085 351.491 836.088 c
+353.02 834.586 352.461 831.905 354.4 830.6 C
+353.814 829.287 353.207 828.01 352.872 826.583 c
+352.59 825.377 353.584 824.18 354.795 824.271 c
+356.053 824.365 356.315 825.124 356.8 826.2 C
+357.067 825.933 357.536 825.636 357.495 825.42 c
+357.038 823.033 356.011 821.04 355.553 818.609 c
+355.494 818.292 355.189 818.09 354.8 818.2 C
+354.332 814.051 350.28 811.657 347.735 808.492 c
+347.332 807.99 347.328 806.741 347.737 806.338 c
+349.14 804.951 351.1 806.497 352.8 807 C
+353.013 808.206 353.872 809.148 355.204 809.092 c
+355.46 809.082 355.695 809.624 356.019 809.754 c
+356.367 809.892 356.869 809.668 357.155 809.866 c
+358.884 811.061 360.292 812.167 362.03 813.356 c
+362.222 813.487 362.566 813.328 362.782 813.436 c
+363.107 813.598 363.294 813.985 363.617 814.17 c
+363.965 814.37 364.207 814.08 364.4 813.8 C
+363.754 813.451 363.75 812.494 363.168 812.292 c
+362.393 812.024 361.832 811.511 361.158 811.064 c
+360.866 810.871 360.207 811.119 360.103 810.94 c
+359.505 809.912 358.321 809.474 357.611 808.591 c
+f
+302.2 858 m
+292.962 860.872 281.8 835.2 V
+279.4 830 277 828 v
+274.6 826 263.4 822.4 261.4 818.4 C
+251 802.4 L
+265.8 818.4 269 820.8 V
+277 829.2 273.8 822.4 V
+259.8 811.6 261 802.4 V
+255.4 788 254.6 786 V
+270.6 818 273 819.2 v
+275.4 820.4 276.6 820.4 275.4 816.8 c
+274.2 813.2 273.8 796.8 271 794.8 C
+279 815.2 278.2 818.4 V
+281.4 822 283.8 816.8 V
+282.6 800.8 l
+287 788.8 l
+284.6 800 286.2 815.6 V
+284.2 826 288.2 820.4 v
+292.2 814.8 301.8 808.8 301.8 804 C
+296.6 821.6 287.4 826.4 V
+283.4 820.4 l
+282.2 822.4 l
+278.6 823.2 283 830 v
+287.4 836.8 287 837.6 y
+293.4 830.4 295 830.4 V
+308.2 838 309.4 813.6 V
+316.2 828 307 834.8 V
+292.2 836.8 293.4 842 V
+300.6 854.4 L
+304.2 859.6 302.6 856.8 y
+F
+282.2 841.6 m
+269.4 841.6 266.2 836.4 V
+259 826.8 l
+276.2 836.8 280.2 838 v
+284.2 839.2 282.2 841.6 Y
+f
+242.2 835.2 m
+240.2 834 239.8 831.2 v
+239.4 828.4 237 828 237.8 825.2 c
+238.6 822.4 240.6 820 240.6 824 c
+240.6 828 242.2 830 243 831.2 c
+243.8 832.4 245.4 836.8 242.2 835.2 c
+f
+233.4 774 m
+225 778 221.8 781.6 v
+218.6 785.2 219.052 780.034 214.2 780.4 c
+208.353 780.841 209.4 796.8 y
+205.4 789.2 l
+204.2 774.8 212.2 777.2 v
+216.107 778.372 217.4 776.8 215.8 776 c
+214.2 775.2 221.4 774.8 218.6 773.2 c
+215.8 771.6 230.2 776.8 227.8 766.4 C
+233.4 774 L
+f
+220.8 759.6 m
+205.4 755.2 201.8 764.8 V
+197 762.4 199.2 759.4 v
+201.4 756.4 202.6 756 y
+208 754.8 207.4 754 v
+206.8 753.2 204.4 749.8 y
+214.6 755.8 220.8 759.6 v
+f
+1 g
+449.201 681.399 m
+448.774 679.265 447.103 678.464 445.201 677.799 C
+443.284 678.757 440.686 681.863 438.801 679.799 C
+438.327 680.279 437.548 680.339 437.204 681.001 c
+436.739 681.899 437.011 682.945 436.669 683.743 c
+436.124 685.015 435.415 686.381 435.601 687.799 C
+437.407 688.511 438.002 690.417 437.528 692.18 c
+437.459 692.437 437.03 692.634 437.23 692.983 c
+437.416 693.306 437.734 693.533 438.001 693.8 C
+437.866 693.665 437.721 693.432 437.61 693.452 c
+437 693.558 437.124 694.195 437.254 694.582 c
+437.839 696.328 439.853 696.592 441.201 695.4 C
+441.457 695.965 441.966 695.771 442.401 695.8 C
+442.351 696.379 442.759 696.906 442.957 697.326 c
+443.475 698.424 445.104 697.318 445.901 697.93 c
+446.977 698.755 448.04 699.454 449.118 698.851 c
+450.927 697.838 452.636 696.626 453.835 694.885 c
+454.41 694.051 454.65 692.77 454.592 691.812 c
+454.554 691.165 453.173 691.517 452.83 690.588 c
+452.185 688.84 454.016 688.321 454.772 686.983 c
+454.97 686.634 454.706 686.33 454.391 686.232 c
+453.98 686.104 453.196 686.293 453.334 685.84 c
+454.306 682.647 451.55 681.969 449.201 681.399 C
+f
+439.6 661.799 m
+439.593 663.537 437.992 665.293 439.201 666.999 C
+439.336 666.865 439.467 666.644 439.601 666.644 c
+439.736 666.644 439.867 666.865 440.001 666.999 C
+441.496 664.783 445.148 663.855 445.006 661.009 c
+444.984 660.562 443.897 659.644 444.801 658.999 C
+442.988 657.651 442.933 655.281 442.001 653.399 C
+440.763 653.685 439.551 654.048 438.401 654.599 C
+438.753 656.085 438.636 657.769 439.456 659.089 c
+439.89 659.787 439.603 660.866 439.6 661.799 c
+f
+0.8 g
+273.4 670.799 m
+256.542 660.663 270.6 675.999 v
+279.4 685.599 289.4 691.199 y
+299.8 695.6 303.4 696.8 v
+307 698 322.2 703.2 325.4 703.6 c
+328.6 704 338.2 708 345 704 c
+351.8 700 359.8 695.6 y
+343.4 704 339.8 701.6 v
+336.2 699.2 329 699.6 323 696.4 C
+308.2 691.999 305 689.999 v
+301.8 687.999 291.4 676.399 289.8 677.199 c
+288.2 677.999 290.2 678.399 291.4 681.199 c
+292.6 683.999 290.6 685.599 282.6 679.199 c
+274.6 672.799 273.4 670.799 Y
+f
+0 g
+280.805 676.766 m
+282.215 689.806 290.693 688.141 V
+298.919 692.311 301.641 694.279 V
+309.78 695.981 311.09 696.598 v
+329.569 705.298 344.288 700.779 344.835 701.899 c
+345.381 703.018 365.006 695.901 368.615 691.815 c
+369.006 691.372 358.384 697.412 348.686 699.303 c
+340.413 700.917 318.811 699.056 307.905 693.52 c
+304.932 692.011 295.987 686.227 293.456 686.338 c
+290.925 686.45 280.805 676.766 Y
+f
+0.8 g
+277 651.199 m
+261.8 653.599 278.6 655.199 V
+296.6 657.199 300.6 662.399 V
+314.2 671.599 317 671.999 v
+319.8 672.399 349.8 679.599 350.2 681.999 c
+350.6 684.399 356.2 684.399 357.8 683.599 c
+359.4 682.799 358.6 681.599 355.8 680.799 c
+353 679.999 321.8 663.599 315.4 662.399 c
+309 661.199 297.4 653.599 292.6 652.399 c
+287.8 651.199 277 651.199 Y
+f
+0 g
+296.52 658.597 m
+287.938 659.426 296.539 660.245 V
+305.355 663.669 307.403 666.332 V
+314.367 671.043 315.8 671.247 v
+317.234 671.452 331.194 675.139 331.399 676.367 c
+331.604 677.596 365.67 690.177 370.09 686.987 c
+373.001 684.886 363.1 686.563 353.466 682.153 c
+352.111 681.533 318.258 666.946 314.981 666.332 c
+311.704 665.717 305.765 661.826 303.307 661.212 c
+300.85 660.597 296.52 658.597 Y
+f
+288.6 656.399 m
+293.8 656.799 292.6 655.199 v
+291.4 653.599 289 654.399 y
+288.6 656.399 l
+f
+281.4 654.799 m
+286.6 655.199 285.4 653.599 v
+284.2 651.999 281.8 652.799 y
+281.4 654.799 l
+f
+271 653.199 m
+276.2 653.599 275 651.999 v
+273.8 650.399 271.4 651.199 y
+271 653.199 l
+f
+263.4 652.399 m
+268.6 652.799 267.4 651.199 v
+266.2 649.599 263.8 650.399 y
+263.4 652.399 l
+f
+301.8 691.999 m
+306.2 691.999 305 690.399 v
+303.8 688.799 300.6 689.199 y
+301.8 691.999 l
+f
+291.8 686.399 m
+298.306 688.54 295.8 685.199 v
+294.6 683.599 292.2 684.399 y
+291.8 686.399 l
+f
+280.6 681.599 m
+285.8 681.999 284.6 680.399 v
+283.4 678.799 281 679.599 y
+280.6 681.599 l
+f
+273 675.599 m
+278.2 675.999 277 674.399 v
+275.8 672.799 273.4 673.599 y
+273 675.599 l
+f
+266.2 670.799 m
+271.4 671.199 270.2 669.599 v
+269 667.999 266.6 668.799 y
+266.2 670.799 l
+f
+305.282 664.402 m
+312.203 664.934 310.606 662.805 v
+309.009 660.675 305.814 661.74 y
+305.282 664.402 l
+f
+315.682 669.202 m
+322.603 669.734 321.006 667.605 v
+319.409 665.475 316.214 666.54 y
+315.682 669.202 l
+f
+326.482 673.602 m
+333.403 674.134 331.806 672.005 v
+330.209 669.875 327.014 670.94 y
+326.482 673.602 l
+f
+336.882 678.402 m
+343.803 678.934 342.206 676.805 v
+340.609 674.675 337.414 675.74 y
+336.882 678.402 l
+f
+309.282 696.402 m
+316.203 696.934 314.606 694.805 v
+313.009 692.675 309.014 692.94 y
+309.282 696.402 l
+f
+319.282 699.602 m
+326.203 700.134 324.606 698.005 v
+323.009 695.875 318.614 696.14 y
+319.282 699.602 l
+f
+296.6 659.599 m
+301.8 659.999 300.6 658.399 v
+299.4 656.799 297 657.599 y
+296.6 659.599 l
+f
+0.1 0.55 0.85 0.3 k
+223.4 758.8 m
+219 750 218.6 746.8 V
+219.4 755.6 220.6 757.6 v
+221.8 759.6 223.4 758.8 y
+f
+205 744.8 m
+201.8 730.4 202.2 727.6 V
+201 739.2 201.4 740.4 v
+201.8 741.6 205 744.8 y
+f
+0.8 g
+225.8 819.4 m
+225.6 816.2 l
+223.4 816 l
+237.6 803.4 238.2 795.8 V
+239 804 225.8 819.4 V
+f
+0 g
+229.784 818.135 m
+229.353 818.551 229.572 819.296 229.164 819.556 c
+228.355 820.072 230.462 820.129 230.234 820.845 c
+229.851 822.051 230.038 822.072 229.916 823.348 c
+229.859 823.946 230.447 825.486 230.832 825.926 c
+232.278 827.578 230.954 830.51 232.594 832.061 c
+232.898 832.35 233.274 832.902 233.559 833.32 c
+234.218 834.283 235.402 834.771 236.352 835.599 c
+236.67 835.875 236.469 836.702 237.038 836.61 c
+237.752 836.495 238.993 836.625 238.948 835.784 c
+238.835 833.664 237.506 831.944 236.226 830.276 C
+236.677 829.572 236.219 828.937 235.935 828.38 c
+234.6 825.76 234.789 822.919 234.615 820.079 c
+234.61 819.994 234.303 819.916 234.311 819.863 c
+234.664 817.528 235.248 815.329 236.127 813.1 c
+236.493 812.17 236.964 811.275 237.114 810.348 c
+237.225 809.662 237.328 808.829 236.92 808.124 C
+238.955 805.234 237.646 802.583 238.815 799.052 c
+239.022 798.427 240.714 796.513 240.251 796.674 c
+237.738 797.545 237.626 797.943 237.449 798.696 c
+237.303 799.319 236.973 800.696 236.736 801.298 c
+236.672 801.462 236.501 803.346 236.423 803.468 c
+234.91 805.85 236.268 805.674 234.898 808.032 C
+233.47 808.712 232.504 809.816 231.381 810.978 c
+231.183 811.182 232.326 811.906 232.145 812.119 c
+231.053 813.408 229.9 814.175 230.236 815.668 c
+230.391 816.358 230.528 817.415 229.784 818.135 c
+f
+226.2 816.4 m
+226.6 809.6 229 808 v
+231.4 806.4 230.2 807.2 227 808.4 c
+223.8 809.6 225 810.4 y
+222.2 810 224.6 808 v
+227 806 230.6 803.6 229 803.6 c
+227.4 803.6 219.8 807.6 219.8 810.4 c
+219.8 813.2 218.8 817.3 y
+219.9 818.1 224.7 818 V
+226.1 817.3 226.2 816.4 V
+f
+1 g
+1 J 0.1 w
+225.4 797.8 m
+216.88 800.591 198.4 797.2 V
+207.431 799.278 226.2 797 v
+236.5 795.75 225.4 797.8 Y
+b
+227.498 797.871 m
+219.252 801.389 200.547 799.608 V
+209.725 800.897 228.226 797.005 v
+238.38 794.869 227.498 797.871 Y
+b
+229.286 797.778 m
+221.324 801.899 202.539 801.514 V
+211.787 802.118 229.948 796.86 v
+239.914 793.975 229.286 797.778 Y
+b
+230.556 797.555 m
+223.732 801.862 206.858 802.96 V
+215.197 802.79 231.078 796.681 v
+239.794 793.328 230.556 797.555 Y
+b
+345.84 787.039 m
+344.91 786.395 345.124 787.576 v
+345.339 788.757 373.547 801.927 377.161 801.677 C
+346.913 788.471 345.84 787.039 V
+b
+342.446 786.4 m
+341.57 785.685 341.691 786.879 v
+341.812 788.073 368.899 803.418 372.521 803.452 C
+343.404 787.911 342.446 786.4 V
+b
+339.16 785.025 m
+338.332 784.253 338.374 785.453 v
+338.416 786.652 358.233 802.149 368.045 804.023 C
+350.015 795.896 339.16 785.025 V
+b
+336.284 783.162 m
+335.539 782.468 335.577 783.547 v
+335.615 784.627 353.449 798.574 362.28 800.26 C
+346.054 792.946 336.284 783.162 V
+b
+0.8 g
+0 J 1 w
+304.6 635.199 m
+289.4 637.599 306.2 639.199 V
+324.2 641.199 328.2 646.399 V
+341.8 655.599 344.6 655.999 v
+347.4 656.399 363.8 659.999 364.2 662.399 c
+364.6 664.799 370.6 667.199 372.2 666.399 c
+373.8 665.599 373.8 656.399 371 655.599 c
+368.2 654.799 349.4 647.599 343 646.399 c
+336.6 645.199 325 637.599 320.2 636.399 c
+315.4 635.199 304.6 635.199 Y
+f
+0 g
+377.6 672.599 m
+374.6 670.999 373.4 668.399 V
+367 657.799 352.8 654.599 V
+329.8 645.599 322 643.599 V
+308.6 638.599 301.2 639.399 V
+294.2 639.199 300.4 637.599 V
+320.6 639.599 324 641.399 V
+339.6 646.599 342.6 649.199 v
+345.6 651.799 363.8 656.799 366 658.799 c
+368.2 660.799 378 669.199 377.6 672.599 C
+f
+318.882 641.089 m
+324.111 641.315 322.958 639.766 v
+321.805 638.216 319.357 639.09 y
+318.882 641.089 l
+f
+311.68 639.737 m
+316.908 639.963 315.756 638.414 v
+314.603 636.864 312.155 637.737 y
+311.68 639.737 l
+f
+301.251 638.489 m
+306.48 638.716 305.327 637.166 v
+304.174 635.617 301.726 636.49 y
+301.251 638.489 l
+f
+293.617 637.945 m
+298.846 638.171 297.693 636.622 v
+296.54 635.072 294.092 635.946 y
+293.617 637.945 l
+f
+335.415 648.487 m
+342.375 648.788 340.84 646.726 v
+339.306 644.664 336.047 645.826 y
+335.415 648.487 l
+f
+345.73 652.912 m
+351.689 656.213 351.155 651.151 v
+350.885 648.595 346.362 650.251 y
+345.73 652.912 l
+f
+354.862 655.726 m
+362.021 659.427 360.287 653.965 v
+359.509 651.515 355.493 653.065 y
+354.862 655.726 l
+f
+364.376 660.551 m
+368.735 665.452 369.801 658.79 v
+370.207 656.252 365.008 657.89 y
+364.376 660.551 l
+f
+326.834 644.003 m
+332.062 644.23 330.91 642.68 v
+329.757 641.131 327.308 642.004 y
+326.834 644.003 l
+f
+1 g
+1 J 0.1 w
+362.434 765.397 m
+361.708 764.732 361.707 765.803 v
+361.707 766.873 379.191 780.137 388.034 781.521 C
+371.935 774.792 362.434 765.397 V
+b
+0 g
+0 J 1 w
+365.4 701.6 m
+387.401 679.199 396.601 675.599 V
+405.801 664.399 401.801 638.399 V
+398.601 630.799 395.401 651.599 V
+398.601 676.799 387.401 660.799 V
+379 670.699 385.4 670.399 V
+388.601 668.399 389.001 669.999 v
+389.401 671.599 381.4 685.199 364.2 699.6 c
+347 714 365.4 701.6 Y
+f
+1 g
+1 J 0.1 w
+307 662.799 m
+306.8 664.599 308.6 663.799 v
+310.4 662.999 404.601 656.799 436.201 632.799 C
+391.001 655.999 307 662.799 V
+b
+317.4 667.199 m
+317.2 668.999 319 668.199 v
+320.8 667.399 457.401 668.399 481.001 635.999 C
+459.001 661.199 317.4 667.199 V
+b
+329 671.199 m
+328.8 672.999 330.6 672.199 v
+332.4 671.399 505.801 684.399 529.401 651.999 C
+519.801 677.599 329 671.199 V
+b
+339 675.999 m
+338.8 677.799 340.6 676.999 v
+342.4 676.199 464.601 714.8 488.201 682.399 C
+474.801 707 339 675.999 V
+b
+281 653.199 m
+280.8 654.999 282.6 654.199 v
+284.4 653.399 302.2 651.199 304.2 612.399 C
+297 654.399 281 653.199 V
+b
+272.2 651.599 m
+272 653.399 273.8 652.599 v
+275.6 651.799 289.8 656.399 287 617.599 C
+288.2 652.799 272.2 651.599 V
+b
+264.2 651.199 m
+264 652.999 265.8 652.199 v
+267.6 651.399 283 650.799 270.6 628.399 C
+280.2 652.399 264.2 651.199 V
+b
+311.526 695.535 m
+311.082 693.536 312.631 694.753 v
+328.699 707.378 361.141 766.28 416.826 771.914 C
+378.518 784.024 311.526 695.535 V
+b
+322.726 697.335 m
+321.363 698.528 323.231 699.153 v
+325.099 699.778 437.541 772.28 476.826 764.314 C
+449.719 771.824 322.726 697.335 V
+b
+301.885 691.233 m
+301.376 689.634 303.087 690.61 v
+312.062 695.73 315.677 752.941 359.254 754.196 C
+326.843 768.91 301.885 691.233 V
+b
+281.962 680.207 m
+280.885 678.921 282.838 679.175 v
+293.084 680.507 314.489 721.778 358.928 716.699 C
+326.962 731.045 281.962 680.207 V
+b
+293.2 686.333 m
+292.389 684.864 294.258 685.489 v
+304.057 688.763 317.141 733.375 361.729 736.922 C
+327.603 744.865 293.2 686.333 V
+b
+274.922 675.088 m
+274.049 674.046 275.631 674.252 v
+283.93 675.331 301.268 708.76 337.264 704.646 C
+311.371 716.266 274.922 675.088 V
+b
+267.323 669.179 m
+266.318 668.134 267.909 668.252 v
+272.077 668.561 302.715 701.64 321.183 686.138 C
+309.168 704.861 267.323 669.179 V
+b
+336.855 701.102 m
+335.654 702.457 337.586 702.842 v
+339.518 703.226 460.221 760.939 498.184 748.073 C
+472.243 758.947 336.855 701.102 V
+b
+303.4 636.799 m
+303.2 638.599 305 637.799 v
+306.8 636.999 322.2 636.399 309.8 613.999 C
+319.4 637.999 303.4 636.799 V
+b
+313.8 638.399 m
+313.6 640.199 315.4 639.399 v
+317.2 638.599 335 636.399 337 597.599 C
+329.8 639.599 313.8 638.399 V
+b
+320.6 639.999 m
+320.4 641.799 322.2 640.999 v
+324 640.199 348.6 636.799 372.2 604.399 C
+336.6 641.199 320.6 639.999 V
+b
+328.225 642.028 m
+327.788 643.786 329.678 643.232 v
+331.568 642.678 352.002 644.577 390.099 610.401 C
+343.924 645.344 328.225 642.028 V
+b
+338.625 646.428 m
+338.188 648.186 340.078 647.632 v
+341.968 647.078 376.802 642.577 428.499 607.601 C
+354.324 649.744 338.625 646.428 V
+b
+298.2 657.999 m
+298 659.799 299.8 658.999 v
+301.6 658.199 355 655.599 385.4 628.799 C
+350.499 653.574 298.2 657.999 V
+b
+288.2 653.999 m
+288 655.799 289.8 654.999 v
+291.6 654.199 316.2 650.799 339.8 618.399 C
+304.2 655.199 288.2 653.999 V
+b
+349.503 651.038 m
+348.938 652.759 350.864 652.345 v
+352.79 651.932 387.86 649.996 441.981 618.902 C
+364.317 653.296 349.503 651.038 V
+b
+357.903 653.438 m
+357.338 655.159 359.264 654.745 v
+361.19 654.332 396.26 652.396 450.381 621.302 C
+373.317 656.096 357.903 653.438 V
+b
+367.503 658.438 m
+366.938 660.159 368.864 659.745 v
+370.79 659.332 413.86 654.996 503.582 620.702 C
+382.917 661.096 367.503 658.438 V
+b
+0 g
+0 J 1 w
+256.2 651.599 m
+261.4 651.999 260.2 650.399 v
+259 648.799 256.6 649.599 y
+256.2 651.599 l
+f
+287 637.599 m
+292.2 637.999 291 636.399 v
+289.8 634.799 287.4 635.599 y
+287 637.599 l
+f
+278.2 637.999 m
+283.4 638.399 282.2 636.799 v
+281 635.199 278.6 635.999 y
+278.2 637.999 l
+f
+182.831 649.818 m
+187.876 648.495 186.218 647.376 v
+184.561 646.256 182.554 647.798 y
+182.831 649.818 l
+f
+184.831 659.418 m
+189.876 658.095 188.218 656.976 v
+186.561 655.856 184.554 657.398 y
+184.831 659.418 l
+f
+177.631 663.818 m
+182.676 662.495 181.018 661.376 v
+179.361 660.256 177.354 661.798 y
+177.631 663.818 l
+f
+0.8 g
+1 J 0.1 w
+257.4 588.799 m
+255.8 588.799 251.8 586.799 V
+249.8 586.799 238.6 583.199 233 573.199 C
+245.4 582.799 257.4 588.799 V
+f
+345.116 496.153 m
+345.257 495.895 345.312 495.475 345.604 495.458 c
+346.262 495.418 347.495 495.117 347.37 495.753 c
+346.522 500.059 345.648 504.996 341.515 506.803 c
+340.876 507.082 339.434 506.669 339.36 505.785 c
+339.233 504.261 339.116 502.912 339.425 501.446 c
+339.725 500.025 341.883 500.015 342.8 501.399 C
+343.736 499.727 344.168 497.884 345.116 496.153 c
+f
+334.038 491.419 m
+334.786 490.006 334.659 488.147 336.074 487.584 c
+336.814 487.29 338.664 488.265 338.246 489.339 c
+337.444 491.4 337.056 493.639 335.667 495.45 c
+335.467 495.712 335.707 496.245 335.547 496.573 c
+334.953 497.793 333.808 498.528 332.4 498.199 C
+331.285 495.996 332.433 493.867 333.955 492.158 c
+334.091 492.006 333.925 491.63 334.038 491.419 c
+f
+294.436 496.609 m
+294.328 496.986 294.29 497.449 294.455 497.77 c
+294.986 498.803 295.779 499.925 295.442 500.947 c
+295.094 502.003 293.978 501.821 293.328 501.252 c
+292.193 500.258 292.144 498.432 291.453 497.073 c
+291.257 496.687 291.308 496.114 290.867 495.723 c
+290.393 495.302 289.953 493.778 290.049 493.207 c
+290.102 492.894 289.919 482.986 290.141 483.249 c
+290.76 483.982 293.81 493.716 293.879 494.608 c
+293.936 495.339 294.668 495.804 294.436 496.609 c
+f
+268.798 503.401 m
+271.432 505.9 274.222 508.861 273.78 512.573 c
+273.664 513.549 271.889 513.022 271.702 512.176 c
+270.9 508.551 268.861 505.89 266.293 503.498 c
+264.097 501.451 262.235 495.107 262 494.599 C
+265.697 499.855 267.954 502.601 268.798 503.401 c
+f
+255.224 509.365 m
+255.747 509.735 255.445 510.226 255.662 510.558 c
+256.615 512.016 257.916 513.262 257.934 515 c
+257.937 515.277 257.559 515.586 257.224 515.362 c
+256.947 515.178 256.605 515.048 256.497 514.918 c
+254.467 512.469 253.067 509.798 251.624 506.986 c
+251.441 506.629 250.297 502.138 250.61 502.027 c
+250.849 501.942 252.569 506.123 252.779 506.237 c
+254.042 506.923 254.054 508.538 255.224 509.365 c
+f
+271.957 489.821 m
+272.401 490.69 273.977 491.892 273.864 492.781 c
+273.746 493.709 274.214 495.152 273.302 494.464 c
+272.045 493.516 268.596 492.167 268.326 486.359 c
+268.3 485.788 271.274 488.481 271.957 489.821 c
+f
+286.4 506.999 m
+286.8 507.667 287.508 507.194 287.967 507.457 c
+288.615 507.829 289.226 508.387 289.518 509.036 c
+290.488 511.185 292.257 513.005 292.4 515.399 C
+290.909 516.804 290.23 514.764 289.6 513.799 C
+288.277 515.446 287.278 513.572 285.978 513.053 c
+285.908 513.025 285.695 513.372 285.62 513.345 c
+284.443 512.905 283.763 511.824 282.765 511.043 c
+282.594 510.909 282.189 511.089 282.042 510.953 c
+281.39 510.35 280.417 510.025 280.137 509.343 c
+279.027 506.636 275.887 504.541 274 496.999 C
+274.381 496.09 278.512 503.641 278.999 504.339 c
+279.835 505.535 279.953 502.678 281.229 503.344 c
+281.28 503.371 281.466 503.133 281.6 502.999 C
+281.794 503.279 282.012 503.508 282.4 503.399 C
+282.4 503.799 282.266 504.355 282.467 504.514 c
+283.704 505.491 283.62 506.559 284.4 507.799 C
+284.858 507.01 285.919 507.729 286.4 506.999 C
+f
+346.2 452.599 m
+353.6 472.999 349.2 484.199 V
+360.6 462.599 356 451.399 V
+355.6 461.799 351.6 466.799 V
+347.6 453.999 346.2 452.599 V
+f
+331.4 455.199 m
+336.8 463.999 328.8 482.399 V
+328 461.999 321.2 450.999 V
+335.4 471.199 331.4 455.199 V
+f
+321.4 457.199 m
+321.2 477.199 321.6 480.199 V
+317.8 463.599 307.6 453.999 V
+322 465.999 321.4 457.199 V
+f
+311.8 489.199 m
+317.8 475.599 307.8 457.199 V
+314.2 469.399 309.4 476.399 V
+312 479.799 311.8 489.199 V
+f
+292.6 457.599 m
+291.6 473.199 293.4 475.399 V
+293.6 481.799 293.2 482.799 V
+297.2 488.999 297.4 481.599 V
+298.8 473.799 301.6 469.199 V
+305.2 463.799 305 457.399 V
+295 487.599 292.6 457.599 V
+f
+289 485.199 m
+282.4 474.399 280.6 455.399 V
+279.2 461.599 283 475.999 V
+287.2 491.399 289 485.199 V
+f
+267.2 465.399 m
+272.2 470.799 273.6 475.799 V
+277.2 491.599 270.8 482.999 V
+271 474.999 262.8 467.599 V
+267.6 469.999 267.2 465.399 V
+f
+261.4 470.399 m
+264.8 487.799 265.6 488.599 V
+267.4 491.999 264.6 488.799 V
+255.8 469.599 251.8 462.999 V
+259.8 472.199 261.4 470.399 V
+f
+255.6 486.999 m
+267.2 509.399 245.4 483.599 V
+256.4 493.399 255.6 486.999 V
+f
+240.2 501.599 m
+245 520.399 247.6 520.199 V
+255.8 529.199 249.2 518.599 V
+243.2 508.999 243.8 499.199 V
+243.2 508.799 240.2 501.599 V
+f
+570.5 513 m
+558.5 523 556 526.5 V
+569.5 508 569.5 501 V
+572 508.5 570.5 513 V
+f
+576 535 m
+555 550 551.5 557.5 V
+578 528 578 523.5 V
+578.5 532.5 576 535 V
+f
+593 689 m
+581 697 579.5 695 V
+590 688.5 592.5 680 V
+591 689 593 689 V
+f
+601.5 608.5 m
+584 620.5 l
+603 603.5 603.5 599.5 V
+601.5 608.5 L
+f
+0 g
+1 w
+210.75 631 m
+232.75 626.25 l
+S
+261 469 m
+260.5 472.5 251.5 462 v
+S
+266.5 464 m
+268.5 470.5 262 466 v
+S
+320.5 455.5 m
+322 466.5 310.5 453.5 v
+S
+
+showpage
+
+%%Trailer
diff --git a/gs/lib/traceimg.ps b/gs/lib/traceimg.ps
new file mode 100644
index 000000000..993c4c673
--- /dev/null
+++ b/gs/lib/traceimg.ps
@@ -0,0 +1,43 @@
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% traceimg.ps
+% Trace the data supplied to the 'image' operator.
+
+% This code currently handles only the (Level 2) dictionary form of image,
+% with a single data source and 8-bit pixels.
+
+/traceimage % <dict> traceimage -
+ { currentcolorspace == (setcolorspace\n) print
+ (<<) print
+ dup { (\t) print exch ==only ( ) print == } forall
+ (>>\n) print flush
+ begin /i_left Width Height mul store /i_dict currentdict store end
+ { i_left 0 le { exit } if
+ i_dict /DataSource get exec
+ dup type /filetype eq
+ { i_buf 0 i_left 32 min getinterval readstring pop
+ } if
+ dup (%stdout) (w) file exch writehexstring (\n) print flush
+ i_left exch length sub /i_left exch def
+ } loop
+ } bind odef
+
+/image /traceimage load def
+/i_left 0 def
+/i_dict null def
+/i_buf 32 string def
diff --git a/gs/lib/traceop.ps b/gs/lib/traceop.ps
new file mode 100644
index 000000000..ef7405767
--- /dev/null
+++ b/gs/lib/traceop.ps
@@ -0,0 +1,79 @@
+% Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Trace individual operators or procedures.
+% <opref> is <opname> or <opname> <dict>
+% (dict defaults to dict where op is currently defined, if writable;
+% otherwise uses userdict)
+% <opref> traceop prints vmem usage before;
+% <opref> <numargs|preproc> prints arguments or runs proc before;
+% <opref> <numargs|preproc> <numresults|postproc>
+% also prints results or runs proc after.
+% If traceflush is true, flush the output after each printout.
+/traceflush true def
+
+currentpacking true setpacking
+.currentglobal true .setglobal
+
+% Define the default "before" action
+/tracebefore { vmstatus 3 traceprint pop pop pop } def
+
+% Define the default "after" action
+/traceafter { } def
+
+/traceprint
+ { dup type /integertype eq
+ { 1 sub -1 0 { ( ) print index ==only } for }
+ { exec }
+ ifelse
+ } bind def
+/traceend
+ { traceflush { flush } if
+ } bind def
+/traceop
+ { userdict begin
+ dup type dup /nametype eq exch /dicttype eq or { { tracebefore } } if
+ 1 index type dup /nametype eq exch /dicttype eq or { { traceafter } } if
+ /.tpost exch def /.tpre exch def
+ dup type /dicttype ne
+ { dup where not { userdict 1 index {} put userdict } if
+ } if
+ dup dup wcheck not
+ { (Warning: substituting userdict for non-writable dictionary.\n) print
+ pop userdict
+ } if
+ /.tddict exch def /.tdict exch def /.tname exch cvlit def
+ [ .tname /=only cvx ( ) /print cvx
+ /.tpre load /traceprint cvx /traceend cvx
+ .tdict .tname get
+ dup xcheck
+ { dup type dup /arraytype eq exch /packedarraytype eq or
+ { /exec cvx
+ } if
+ } if
+ /.tpost load /traceprint cvx (\n) /print cvx /traceend cvx
+ ] cvx
+ .tdict .tname get type /operatortype eq
+ { .tname exch .makeoperator
+ } if
+ .tddict exch .tname exch put end
+ } bind def
+/tracebind /bind load def % in case someone wants to put it back
+/bind { } def % disable
+
+.setglobal
+setpacking
diff --git a/gs/lib/type1enc.ps b/gs/lib/type1enc.ps
new file mode 100644
index 000000000..e436a32df
--- /dev/null
+++ b/gs/lib/type1enc.ps
@@ -0,0 +1,66 @@
+% Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% type1enc.ps
+% PostScript language versions of the Type 1 encryption/decryption algorithms.
+
+% This file is normally not needed with Ghostscript, since Ghostscript
+% implements these algorithms in C. For the specifications, see Chapter 7 of
+% "Adobe Type 1 Font Format," ISBN 0-201-57044-0, published by Addison-Wesley.
+
+/.type1crypt % <R> <from> <to> <proc> .type1crypt <R'> <to>
+ % (auxiliary procedure)
+ { 4 1 roll
+ 0 2 index length getinterval
+ 0 1 2 index length 1 sub
+ { % Stack: proc R from to index
+ 2 index 1 index get % proc R from to index C/P
+ 4 index -8 bitshift xor 3 copy put % proc R from to index P/C
+ 5 index exec % proc R from to C
+
+% Compute R' = ((R + C) * 52845 + 22719) mod 65536
+% without exceeding a 31-bit integer magnitude, given that
+% 0 <= R <= 65535 and 0 <= C <= 255.
+
+ 4 -1 roll add
+ dup 20077 mul % 52845 - 32768
+ exch 1 and 15 bitshift add % only care about 16 low-order bits
+ 22719 add 65535 and 3 1 roll
+ }
+ for exch pop 3 -1 roll pop
+ } bind def
+
+% <state> <fromString> <toString> .type1encrypt <newState> <toSubstring>
+% Encrypts fromString according to the algorithm for Adobe
+% Type 1 fonts, writing the result into toString.
+% toString must be at least as long as fromString or a
+% rangecheck error occurs. state is the initial state of
+% the encryption algorithm (a 16-bit non-negative
+% integer); newState is the new state of the algorithm.
+
+/.type1encrypt
+ { { exch pop } .type1crypt
+ } bind def
+
+% <state> <fromString> <toString> .type1decrypt <newState> <toSubstring>
+% Decrypts fromString according to the algorithm for Adobe
+% Type 1 fonts, writing the result into toString. Other
+% specifications are as for type1encrypt.
+
+/.type1decrypt
+ { { pop 2 index exch get } .type1crypt
+ } bind def
diff --git a/gs/lib/type1ops.ps b/gs/lib/type1ops.ps
new file mode 100644
index 000000000..e4e8fe967
--- /dev/null
+++ b/gs/lib/type1ops.ps
@@ -0,0 +1,238 @@
+% Copyright (C) 1992, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% type1ops.ps
+% Define the Type 1 font opcodes for use by Ghostscript utilities.
+% This includes both Type 1 and Type 2 CharStrings.
+
+% Define the default value of lenIV.
+
+/lenIV 4 def
+
+% Define the default CharString type.
+
+/CharstringType 1 def
+
+% ---------------- Encoding ---------------- %
+
+/Type1encode 70 dict
+
+ % Data types
+
+dup /nulltype {
+ pop ()
+} put
+dup /nametype {
+ Type1encode exch get
+} put
+dup /stringtype {
+} put
+dup /integertype {
+ dup dup -107 ge exch 107 le and {
+ 139 add (x) dup 0 4 -1 roll put
+ } {
+ dup dup -1131 ge exch 1131 le and {
+ dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
+ (xx) dup dup 0 4 index -8 bitshift put
+ 1 4 -1 roll 255 and put
+ } {
+ (\377xxxx) 1 1 4 {
+ dup 8 mul 32 sub 3 index exch bitshift 255 and
+ 2 index 3 1 roll put
+ } for exch pop
+ } ifelse
+ } ifelse
+} put
+
+ % Operators
+
+% Identical or similar in Type 1 and Type 2 CharStrings.
+/c_hstem 1 def dup /hstem <01> put
+/c_vstem 3 def dup /vstem <03> put
+/c_vmoveto 4 def dup /vmoveto <04> put
+/c_rlineto 5 def dup /rlineto <05> put
+/c_hlineto 6 def dup /hlineto <06> put
+/c_vlineto 7 def dup /vlineto <07> put
+/c_rrcurveto 8 def dup /rrcurveto <08> put
+/c_callsubr 10 def /s_callsubr <0a> def dup /callsubr s_callsubr put
+/c_return 11 def dup /return <0b> put
+/c_escape 12 def
+ /ce_div 12 def /s_div <0c0c> def dup /div s_div put
+/c_endchar 14 def /s_endchar <0e> def dup /endchar s_endchar put
+/c_rmoveto 21 def dup /rmoveto <15> put
+/c_hmoveto 22 def dup /hmoveto <16> put
+/c_vhcurveto 30 def dup /vhcurveto <1e> put
+/c_hvcurveto 31 def dup /hvcurveto <1f> put
+% Only in Type 1 CharStrings.
+/c_closepath 9 def dup /closepath <09> put
+/c_hsbw 13 def /s_hsbw <0d> def dup /hsbw s_hsbw put
+ /ce_dotsection 0 def /s_dotsection <0c06> def dup /dotsection s_dotsection put
+ /ce_vstem3 1 def /s_vstem3 <0c01> def dup /vstem3 s_vstem3 put
+ /ce_hstem3 2 def /s_hstem3 <0c02> def dup /hstem3 s_hstem3 put
+ /ce_seac 6 def /s_seac <0c06> def dup /seac s_seac put
+ /ce_sbw 7 def /s_sbw <0c07> def dup /sbw s_sbw put
+ /ce_callothersubr 16 def /s_callothersubr <0c10> def dup /callothersubr s_callothersubr put
+ /ce_pop 17 def /s_pop <0c11> def dup /pop s_pop put
+ /ce_setcurrentpoint 33 def /s_setcurrentpoint <0c21> def dup /setcurrentpoint s_setcurrentpoint put
+ /s_setcurrentpoint_hmoveto s_setcurrentpoint <8b16> concatstrings def
+% Only in Type 2 CharStrings.
+dup /blend <10> put
+dup /hstemhm <12> put
+dup /hintmask <13> put
+dup /cntrmask <14> put
+dup /vstemhm <17> put
+dup /rcurveline <18> put
+dup /rlinecurve <19> put
+dup /vvcurveto <1a> put
+dup /hhcurveto <1b> put
+dup /callgsubr <1d> put
+ dup /and <0c03> put
+ dup /or <0c04> put
+ dup /not <0c05> put
+ dup /store <0c08> put
+ dup /abs <0c09> put
+ dup /add <0c0a> put
+ dup /sub <0c0b> put
+ dup /load <0c0d> put
+ dup /neg <0c0c> put
+ dup /eq <0c0f> put
+ dup /drop <0c12> put
+ dup /put <0c14> put
+ dup /get <0c15> put
+ dup /ifelse <0c16> put
+ dup /random <0c17> put
+ dup /mul <0c18> put
+ dup /sqrt <0c1a> put
+ dup /dup <0c1b> put
+ dup /exch <0c1c> put
+ dup /index <0c1d> put
+ dup /roll <0c1e> put
+ dup /hflex <0c22> put
+ dup /flex <0c23> put
+ dup /hflex1 <0c24> put
+ dup /flex1 <0c25> put
+
+readonly def
+
+% ---------------- Decoding ---------------- %
+
+/Type1decode 512 array
+
+Type1encode {
+ dup type /stringtype eq {
+ dup length 1 eq { 0 get } { 1 get 256 add } ifelse
+ % stack: array key code
+ exch 2 index 3 1 roll put
+ } {
+ pop pop
+ } ifelse
+} forall
+
+dup 12 {
+ dup read pop dup Type1decode exch 256 add get dup null ne
+ { exch pop }
+ { pop 2 string dup 0 12 put dup 1 4 -1 roll put }
+ ifelse
+} put
+dup 28 { % Type 2 CharStrings only
+ dup read pop 128 xor 128 sub 8 bitshift
+ 1 index read pop add
+} put
+32 1 246 { 2 copy dup 139 sub put pop } for
+dup 247 { dup read pop 108 add } put
+dup 248 { dup read pop 364 add } put
+dup 249 { dup read pop 620 add } put
+dup 250 { dup read pop 876 add } put
+dup 251 { dup read pop 108 add neg } put
+dup 252 { dup read pop 364 add neg } put
+dup 253 { dup read pop 620 add neg } put
+dup 254 { dup read pop 876 add neg } put
+dup 255 { % Different for Type 1 and Type 2
+ dup read pop 128 xor 128 sub
+ 3 { 8 bitshift 1 index read pop add } repeat
+ CharstringType 2 eq { 65536.0 div } if
+} put
+
+readonly def
+
+% ---------------- Procedures ---------------- %
+
+% For these utilities, a CharString is represented by a sequence of
+% integers, reals, strings, and names, either in an array or on the stack.
+% Integers and reals represent themselves; strings are other data that
+% appears in the CharString; names are CharString operator names.
+% A CharString in an array is called a "charproc"; a CharString on
+% the stack is called a "charstack", and is delimited by a mark.
+% Individual elements are called "chartokens".
+
+% ------ Encoding ------ %
+
+% Get the string for a chartoken.
+% Note that this string may be overwritten by the next call.
+/chartoken_string { % <chartoken> chartoken_string <string>
+ dup type Type1encode exch get exec
+} bind def
+% Compute the length of a CharString.
+/chartoken_length { % <chartoken> chartoken_length <length>
+ chartoken_string length
+} bind def
+/charproc_length { % <charproc> charproc_length <length>
+ 0 exch { chartoken_length add } forall
+} bind def
+/charstack_length { % <charstack> charstack_length <charstack> <length>
+ counttomark 0 exch -1 1 { index chartoken_length add } for
+} bind def
+
+% Write a CharString to a file. Normally this will be a NullEncode filter
+% writing on a string of the correct length.
+/chartoken_write { % <file> <chartoken> chartoken_write -
+ chartoken_string writestring
+} bind def
+/charproc_write { % <file> <charproc> charproc_write -
+ { 1 index exch chartoken_write } forall pop
+} bind def
+% Note that the arguments of charstack_write are backwards.
+/charstack_write { % <charstack> <file> charstack_write -
+ counttomark 1 sub -1 1 { index 1 index exch chartoken_write } for
+ cleartomark
+} bind def
+
+% Convert a charproc or charstack to an *un*encrypted CharString.
+/charproc_string { % <charproc> charproc_string <string>
+ mark exch aload pop charstack_string
+} bind def
+/charstack_string { % <charstack> charstack_string <string>
+ charstack_length lenIV add string
+ dup dup length lenIV sub lenIV exch getinterval % skip lenIV
+ /NullEncode filter
+ exch 1 index counttomark 1 add 2 roll
+ charstack_write closefile
+% 4330 exch dup .type1encrypt exch pop readonly
+} bind def
+
+% ------ Decoding ------ %
+
+% Decode a CharString (unencrypted).
+/charstack_read { % <file> charstack_read <no-mark-charstack>
+ { dup read not { pop exit } if
+ Type1decode exch get dup null eq {
+ pop 1 string dup 0 4 -1 roll put
+ } {
+ exec
+ } ifelse exch
+ } loop
+} bind def
diff --git a/gs/lib/uninfo.ps b/gs/lib/uninfo.ps
new file mode 100644
index 000000000..251a532df
--- /dev/null
+++ b/gs/lib/uninfo.ps
@@ -0,0 +1,221 @@
+%!
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% uninfo.ps: Utilities for "printing" PostScript items, especially dictionaries
+% Usage:
+% (prefix-string) dict unprint
+
+% Maximum Print-Width
+/HSpwidth 80 def
+
+% any HScvs string
+/HScvs {
+% Number-Syntax
+ dup type % stack: any /anytype
+ dup /integertype eq 1 index /realtype eq or { pop
+ 16 string cvs
+ }{
+% Logical-Type
+ dup /booleantype eq { pop
+ 5 string cvs
+ }{
+% Identifiers
+ dup /nametype eq { pop
+ dup length 1 add string
+ dup 0 (/) putinterval
+ exch 1 index 1 1 index length 1 sub getinterval cvs pop
+ }{
+% Strings
+ dup /stringtype eq { pop
+% ------- Compute Length
+ 2 1 index { % stack: str len item
+ dup 32 lt 1 index 126 gt or { % need 4
+ pop 4 add
+ }{
+ dup 40 eq 1 index 41 eq or 1 index 92 eq or {
+ pop 2 add
+ }{
+ pop 1 add
+ } ifelse
+ } ifelse
+ } forall
+% ------- Allocate & Fill String
+ string dup 0 (\() putinterval 1
+ 3 -1 roll { % outstr pos item
+ dup 32 lt 1 index 126 gt or {
+ dup 7 le {
+ 2 index 2 index (\\00) putinterval
+ 8 3 index 3 index 3 add 1 getinterval cvrs
+ }{
+ dup 63 le {
+ 2 index 2 index (\\0) putinterval
+ 8 3 index 3 index 2 add 2 getinterval cvrs
+ }{
+ 2 index 2 index (\\) putinterval
+ 8 3 index 3 index 1 add 3 getinterval cvrs
+ } ifelse
+ } ifelse
+ pop 4 add
+ }{
+ dup 40 eq 1 index 41 eq or 1 index 92 eq or {
+ 2 index 2 index (\\) putinterval
+ exch 1 add exch
+ } if
+ 2 index exch 2 index exch put
+ 1 add
+ } ifelse
+ } forall
+ 1 index exch (\)) putinterval
+ }{ exch pop
+ dup length 1 add string
+ dup 0 (-) putinterval
+ exch 1 index 1 1 index length 1 sub getinterval cvs pop
+ dup dup length 4 sub (-) putinterval
+ 0 1 index length 3 sub getinterval
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} bind def
+
+% int HSpindent - indent-spaces
+/HSpindent {
+ dup 0 gt {
+ 1 1 3 -1 roll { pop ( ) print } for
+ }{
+ pop
+ } ifelse
+} bind def
+
+% indent array HSaprint -> Print an Array
+/HSaprint {
+ dup type /arraytype eq {
+ ( [) print
+ exch 1 add dup 1 add
+ 3 -1 roll { % rind pos item
+ HScvs dup length % rind pos str len
+ dup 3 index add HSpwidth ge {
+ (\n) print
+ 3 index HSpindent
+ 3 -1 roll pop
+ 2 index add
+ exch
+ }{
+ ( ) print
+ 2 index add 1 add
+ 3 -1 roll pop
+ exch
+ } ifelse
+ print
+ } forall
+ ( ]) print
+ pop pop
+ }{
+ ( ) print
+ HScvs print pop
+ } ifelse
+ (\n) print
+} bind def
+
+% dict HSdnames dict names (creates sorted name-strings)
+/HSdnames {
+% Build namelist, stack: dic
+ dup length 0 eq {
+ []
+ }{
+ [ 1 index {
+ pop dup type /nametype eq {
+ dup length string cvs
+ }{
+ pop
+ } ifelse
+ } forall
+ ]
+% Sort the namelist, stack: dic nam
+ 0 1 2 index length 2 sub { % stack: dic nam I
+ 2 copy get % stack: pre dic nam I nam[I]
+ 1 index 1 add 1 4 index length 1 sub { % stack: dic nam I nam[I] J
+ 3 index 1 index get % dic nam I S[I] J S[J]
+ 2 index 1 index gt { % swap them
+ 4 index 2 index 4 index put
+ 4 index 4 index 2 index put
+ 3 1 roll
+ } if
+ pop pop
+ } for
+ pop pop
+ } for
+ } ifelse
+} bind def
+
+% string:prefix dict:which unprint
+/unprint {
+ HSdnames % pre dic nam
+% compute the maximum length
+ 0 1 index { % pre dic nam maxlen nam[I]
+ length 2 copy lt { exch } if pop
+ } forall
+% Print out all the items, stack: pre dic nam maxlen
+ (\n) print
+ exch { % pre dic maxlen nam[I]
+% no prefix yet, -> flush right
+ 3 index length 0 eq {
+ dup length 2 index exch sub HSpindent
+ }{
+ 3 index print (/) print
+ } ifelse
+% print the name
+ dup print
+% prefix: fill up with blanks
+ 3 index length 0 ne {
+ dup length 2 index exch sub HSpindent
+ } if
+% now print the item itself, stack: pre dic maxlen nam[I]
+ 2 index 1 index cvn get dup type % stack: pre dic maxlen nam[i] item typ
+% Dict-Syntax
+ dup /dicttype eq { pop % stack: pre dic maxlen nam[i] item
+ ( ) print dup HScvs print
+ 4 index length 0 eq { % brand new prefix
+ 2 index string 0 1 5 index 1 sub { 1 index exch 32 put } for
+ dup 4 index 4 index length sub 5 -1 roll putinterval
+ }{
+ 4 index length 1 add 2 index length add string
+ dup 0 7 index putinterval
+ dup 6 index length (/) putinterval
+ dup 6 index length 1 add 5 -1 roll putinterval
+ } ifelse
+ exch unprint
+ }{
+ 3 -1 roll pop % tack: pre dic maxlen item typ
+% Array-Syntax
+ dup /arraytype eq { pop % stack: pre dic maxlen item
+ 3 index length dup 0 ne { 1 add } if 2 index add
+ exch HSaprint
+ }{ pop
+ ( ) print
+ HScvs print
+ (\n) print
+ } ifelse
+ } ifelse
+ } forall
+ pop pop length -1 eq { (\n) print } if
+} bind def
+
+/currentpagedevice where { % check for currentpagedevice
+ /currentpagedevice get exec () exch unprint
+} if
diff --git a/gs/lib/unix-lpr.sh b/gs/lib/unix-lpr.sh
new file mode 100755
index 000000000..8aafe476b
--- /dev/null
+++ b/gs/lib/unix-lpr.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+#
+# Unix lpr filter. The default setup sends output directly to a pipe,
+# which requires the Ghostscript process to fork, and thus may cause
+# small systems to run out of memory/swap space. An alternative strategy,
+# based on a suggestion by Andy Fyfe (andy@cs.caltech.edu), uses a named
+# pipe for output, which avoids the fork and can thus save a lot of memory.
+#
+# Unfortunately this approach can cause problems when a print job is aborted,
+# as the abort can cause one of the processes to die, leaving the process
+# at the other end of the pipe hanging forever.
+#
+# Because of this, the named pipe method has not been made the default,
+# but it may be restored by commenting out the lines referring to
+# 'gsoutput' and uncommenting the lines referring to 'gspipe'.
+#
+
+PBMPLUSPATH=/usr/local/bin
+PSFILTERPATH=/usr/local/lib/ghostscript
+LOCALPATH=/usr/local/bin
+X11HOME=/usr/X11R6
+
+PATH=/bin:/usr/bin:/usr/ucb:/usr/etc
+PATH=${PATH}\:${LOCALPATH}\:${PBMPLUSPATH}\:${PSFILTERPATH}
+LD_LIBRARY_PATH=${X11HOME}/lib
+
+export PATH LD_LIBRARY_PATH acctfile host user
+
+user= host= acctfile=/dev/null
+
+#
+# Redirect stdout to stderr (for the logfile) and open a new channel
+# connected to stdout for the raw data. This enables us to keep the
+# raw data separate from programmed postscript output and error messages.
+#
+exec 3>&1 1>&2
+
+#
+# Get username and hostname from filter parameters
+#
+while [ $# != 0 ]
+do case "$1" in
+ -n) user=$2 ; shift ;;
+ -h) host=$2 ; shift ;;
+ -*) ;;
+ *) acctfile=$1 ;;
+ esac
+ shift
+done
+
+#
+# Get the filter, printer device and queue type (direct/indirect)
+#
+filter=`basename $0`
+device=`dirname $0`
+type=`dirname ${device}`
+device=`basename ${device}`
+fdevname=$device
+type=`basename ${type}`
+
+#
+# Find the bpp and number of colors, if specified
+#
+
+colorspec="`echo ${device} | sed 's/.*\.[0-9][0-9]*\.\([0-9][0-9]*\)$/\1/'`"
+if test "$colorspec" = "${device}"
+then
+ colorspec=""
+else
+ device=`basename ${device} .$colorspec`
+ colorspec="-dColors=$colorspec"
+fi
+
+bpp="`echo ${device} | sed 's/.*\.\([0-9][0-9]*\)$/\1/'`"
+if test "$bppspec" = "${device}"
+then
+ bpp=1
+else
+ device=`basename ${device} .$bpp`
+fi
+
+#
+# Information for the logfile
+#
+lock=`dirname ${acctfile}`/lock
+cf=`tail -1 ${lock}`
+job=`egrep '^J' ${cf} | tail +2c`
+
+echo "gsbanner: ${host}:${user} Job: ${job} Date: `date`"
+echo "gsif: ${host}:${user} ${fdevname} start - `date`"
+
+#
+# Set the direct or indirect output destinations
+#
+#gspipe=/tmp/gspipe.$$
+#mknod ${gspipe} p
+
+case "${type}" in
+ direct)
+ gsoutput="cat 1>&3" ;;
+# cat ${gspipe} 1>&3 & ;;
+ indirect)
+ gsoutput="lpr -P${device}.raw" ;;
+# cat ${gspipe} | lpr -P${device}.raw & ;;
+esac
+
+(
+#
+# Any setup required may be done here (eg. setting gamma for colour printing)
+#
+#echo "{0.333 exp} dup dup currenttransfer setcolortransfer"
+
+#
+# The input data is filtered here, before being passed on to Ghostscript
+#
+case "${filter}" in
+ gsif) cat ;;
+ gsnf) psdit ;;
+ gstf) pscat ;;
+ gsgf) psplot ;;
+ gsvf) rasttopnm | pnmtops ;;
+ gsdf) dvi2ps -sqlw ;;
+ gscf|gsrf) echo "${filter}: filter not available" 1>&2 ; exit 0 ;;
+esac
+
+#
+# This is the postlude which does the accounting
+#
+echo "\
+(acctfile) getenv
+ { currentdevice /PageCount gsgetdeviceprop dup cvi 0 gt
+ { exch (a) file /acctfile exch def
+ /string 20 string def
+ string cvs dup length dup
+ 4 lt
+ { 4 exch sub
+ { acctfile ( ) writestring } repeat
+ } { pop } ifelse
+ acctfile exch writestring
+ acctfile (.00 ) writestring
+ acctfile (host) getenv
+ { string cvs } { (NOHOST) } ifelse writestring
+ acctfile (:) writestring
+ acctfile (user) getenv
+ { string cvs } { (NOUSER) } ifelse writestring
+ acctfile (\n) writestring
+ acctfile closefile
+ } { pop } ifelse
+ } if
+quit"
+) | gs -q -dNOPAUSE -sDEVICE=${device} -dBitsPerPixel=${bpp} $colorspec \
+ -sOutputFile=\|"${gsoutput}" -
+# -sOutputFile=${gspipe} -
+
+rm -f ${gspipe}
+#
+# End the logfile entry
+#
+echo "gsif: end - `date`"
+
diff --git a/gs/lib/unprot.ps b/gs/lib/unprot.ps
new file mode 100644
index 000000000..e54e5b6d5
--- /dev/null
+++ b/gs/lib/unprot.ps
@@ -0,0 +1,61 @@
+% Copyright (C) 1991, 1992 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Disable all access checks. This is useful for printing out
+% eexec-encrypted Type 1 fonts, and similar purposes.
+
+systemdict wcheck
+ { /protdict systemdict def
+ }
+ { (Please restart Ghostscript with the -dWRITESYSTEMDICT switch.\n) print
+ (Some access checks will remain active if you do not do this.\n) print
+ flush
+ /protdict userdict def
+ }
+ifelse
+
+protdict begin
+ /readonly. /readonly load def
+ /executeonly. /executeonly load def
+ /noaccess. /noaccess load def
+ /readonly { } odef
+ /readonly.. /readonly load def
+ /executeonly { } odef
+ /executeonly.. /executeonly load def
+ /noaccess { } odef
+ /noaccess.. /noaccess load def
+end
+
+% Disable the access checks.
+
+/unprot
+ { protdict begin
+ /readonly /readonly.. load def
+ /executeonly /executeonly.. load def
+ /noaccess /noaccess.. load def
+ end
+ } bind def
+
+% Re-enable the access checks.
+
+/reprot
+ { protdict begin
+ /readonly /readonly. load def
+ /executeonly /executeonly. load def
+ /noaccess /noaccess. load def
+ end
+ } bind def
diff --git a/gs/lib/viewcmyk.ps b/gs/lib/viewcmyk.ps
new file mode 100644
index 000000000..7baf31256
--- /dev/null
+++ b/gs/lib/viewcmyk.ps
@@ -0,0 +1,68 @@
+% Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Ghostscript.
+%
+% Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the Ghostscript General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute
+% Ghostscript, but only under the conditions described in the Ghostscript
+% General Public License. A copy of this license is supposed to have been
+% given to you along with Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+
+% viewcmyk.ps
+% Display a raw CMYK file.
+% Requires the colorimage operator.
+% If SCALE is defined, maps input pixels to output pixels with that scale;
+% if SCALE is undefined, scales the image to fit the page.
+% If BITS is defined, it is the number of bits per sample (1,2,4,8,12);
+% if BITS is undefined, its default value is 1.
+
+/viewcmyk % <filename> <width> viewcmyk -
+ { 20 dict begin
+ /w exch def
+ /fname exch def
+ /bpc /BITS where { pop BITS } { 1 } ifelse def
+ /f fname (r) file def
+ mark fname status pop pop pop /flen exch def cleartomark
+ /h flen w bpc 4 mul mul 7 add 8 idiv idiv def
+ (Dimensions: ) print [w h] == flush
+ % Set up scaling.
+ /SCALE where
+ { pop
+ % Map pixels SCALE-for-1. Assume orthogonal transformation.
+ w 1 0 dtransform add abs div SCALE mul
+ h 0 1 dtransform add abs div SCALE mul
+ }
+ { % Scale the image (uniformly) to fit the page.
+ clippath pathbbox pop pop translate
+ pathbbox 4 2 roll pop pop
+ h div w mul min dup
+ }
+ ifelse scale
+ w h bpc [w 0 0 h neg 0 h] f false 4 colorimage
+ showpage
+ f closefile
+ end
+ } bind def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark 2 eq
+ { cvi viewcmyk
+ }
+ { cleartomark
+ (Usage: gs -- viewcmyk.ps filename.cmyk width\n) print
+ ( e.g.: gs -- viewcmyk.ps my.cmyk 2550\n) print flush
+ }
+ ifelse
+ }
+ { pop
+ }
+ifelse
diff --git a/gs/lib/viewgif.ps b/gs/lib/viewgif.ps
new file mode 100644
index 000000000..e6572cc2d
--- /dev/null
+++ b/gs/lib/viewgif.ps
@@ -0,0 +1,162 @@
+% Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% viewgif.ps
+% Display a GIF file.
+
+/read1 % <file> read1 <int>
+ { read pop
+ } bind def
+/read2 % <file> read2 <int>
+ { dup read1 exch read1 8 bitshift add
+ } bind def
+
+/readGIFheader % <file> readGIFheader <dict>
+ { 20 dict begin
+ dup 6 string readstring pop
+ dup (GIF87a) eq exch (GIF89a) eq or not
+ { (Not a GIF file.\n) print cleartomark stop
+ } if
+ dup read2 /Width exch def
+ dup read2 /Height exch def
+ dup read1
+ dup 128 ge /GlobalColor exch def
+ dup -4 bitshift 7 and 1 add /BitsPerPixel exch def %***BOGUS?***
+ dup 8 and 0 ne /PaletteSorted exch def
+ 7 and 1 add dup /BitsPerPixel exch def
+ 1 exch bitshift /PaletteSize exch def
+ dup read1 /BackgroundIndex exch def
+ dup read1 15 add 64 div /AspectRatio exch def
+ GlobalColor
+ { PaletteSize 3 mul string readstring pop
+ /GlobalPalette exch def
+ } if
+ currentdict end
+ } bind def
+
+/readGIFimageHeader % <file> readGIFimageHeader <dict>
+ % Note: GIF header must be on dict stack
+ { 10 dict begin
+ { dup read1
+ dup (!) 0 get ne { exit } if pop % extension
+ dup read1 pop
+ { dup read1 dup 0 eq { pop exit } if { dup read1 pop } repeat
+ } loop
+ } loop
+ (,) 0 get ne
+ { (Not a GIF image.\n) print stop
+ } if
+ dup read2 /Left exch def
+ dup read2 /Top exch def
+ dup read2 /Width exch def
+ dup read2 /Height exch def
+ dup read1
+ dup 128 ge /LocalColor exch def
+ dup 64 and 0 ne /Interlaced exch def
+ LocalColor
+ { 7 and 1 add /BitsPerPixel exch def
+ 1 BitsPerPixel bitshift 3 mul string readstring pop
+ /Palette exch def
+ }
+ { pop pop /Palette GlobalPalette def
+ }
+ ifelse
+ currentdict end
+ } bind def
+
+/imageGIF % <imagedict> imageGIF
+ { /ImageOut where
+ { pop
+ % We know BitsPerComponent = 8, Decode = [0 255].
+ % and there is only a single data source which is
+ % either a filter or a string whose size is exactly
+ % the width of the row.
+ dup /DataSource get dup type /stringtype eq
+ { ImageOut exch writestring
+ }
+ { pop dup /Width get string
+ 1 index /Height get
+ { 1 index /DataSource get 1 index readstring pop
+ ImageOut exch writestring
+ }
+ repeat pop pop
+ }
+ ifelse
+ }
+ { image
+ }
+ ifelse
+ } bind def
+
+/viewGIF % <file|string> viewGIF -
+ { save 20 dict begin
+ /saved exch def
+ dup type /stringtype eq { (r) file } if
+ /F exch def
+ /ImageOutFile where { /ImageOut ImageOutFile (w) file def } if
+ F readGIFheader /Header exch def
+ currentdict Header end begin begin
+ DEBUG { Header { exch == == } forall (----------------\n) print flush } if
+ F readGIFimageHeader /ImageHeader exch def
+ currentdict ImageHeader end begin begin
+ DEBUG { ImageHeader { exch == == } forall (----------------\n) print flush } if
+ /D F
+ << /InitialCodeLength F read1
+ /FirstBitLowOrder true
+ /BlockData true
+ /EarlyChange 0
+ >> /LZWDecode filter def
+
+ [/Indexed /DeviceRGB 1 BitsPerPixel bitshift 1 sub Palette] setcolorspace
+ matrix currentmatrix
+ 0 1 3 { 2 copy get dup 0 ne { dup abs div } if 3 copy put pop pop } for
+ setmatrix
+ << /ImageType 1
+ /ImageMatrix [1 0 0 -1 0 Height]
+ /BitsPerComponent 8
+ /Decode [0 255]
+ Interlaced
+ { /Width Width /Height 1
+ /row Width string def
+ /DataSource row
+ >> /I exch def
+ /inter % <num> <denom> inter -
+ { /denom exch def /num exch def
+ gsave
+ /lines Height denom 1 sub add num sub denom idiv def
+ 0 num neg translate
+ /delta denom neg def
+ lines
+ { D row readstring pop pop
+ I imageGIF
+ 0 delta translate
+ } repeat
+ grestore
+ }
+ bind def
+ 0 8 inter
+ 4 8 inter
+ 2 4 inter
+ 1 2 inter
+ }
+ { /Width Width /Height Height
+ /DataSource D
+ >> imageGIF
+ }
+ ifelse
+ saved end end end restore
+ } bind def
diff --git a/gs/lib/viewjpeg.ps b/gs/lib/viewjpeg.ps
new file mode 100644
index 000000000..68d83396a
--- /dev/null
+++ b/gs/lib/viewjpeg.ps
@@ -0,0 +1,144 @@
+%! viewjpeg.ps Copyright (C) Thomas Merz 1994
+%
+% View JPEG files with Ghostscript
+%
+% This PostScript code relies on level 2 features.
+%
+% Only JPEG baseline, extended sequential, and progressive files
+% are supported. Note that Adobe PostScript level 2 does not include
+% progressive-JPEG support. Ghostscript with IJG JPEG v6 or later
+% will decode progressive JPEG, but only if you edit gsjmorec.h to
+% enable that feature.
+%
+% Author's address:
+% ------------------------------+
+% {(pstack exec quit) = flush } | Thomas Merz, Munich
+% pstack exec quit | voice +49/89/29160728
+% ------------------------------+ tm@muc.de http://www.muc.de/~tm/
+%
+% Updated by L. Peter Deutsch 20-May-1997:
+% move the usage example to the beginning
+% Updates by Tom Lane 6-Sep-1995
+
+% Usage example:
+% (jpeg-6/testimg.jpg) viewJPEG
+
+/languagelevel where {pop languagelevel 2 lt}{true} ifelse {
+ (JPEG needs PostScript Level 2!\n) print flush stop
+} if
+
+/JPEGdict 20 dict def
+JPEGdict begin
+
+/NoParamMarkers [ % JPEG markers without additional parameters
+ 16#D0 16#D1 16#D2 16#D3 16#D4 16#D5 16#D6 16#D7 16#D8 16#01
+] def
+
+/NotSupportedMarkers [ % JPEG markers not supported by PostScript level 2
+ 16#C3 16#C5 16#C6 16#C7 16#C8 16#C9 16#CA 16#CB 16#CD 16#CE 16#CF
+] def
+
+% Names of color spaces
+/ColorSpaceNames << /1 /DeviceGray /3 /DeviceRGB /4 /DeviceCMYK >> def
+
+% read one byte from file F
+% - ==> int --or-- stop context
+/NextByte {
+ F read not { (Read error in ViewJPEG!\n) print flush stop } if
+} bind def
+
+/SkipSegment { % read two bytes and skip that much data
+ NextByte 8 bitshift NextByte add 2 sub { NextByte pop } repeat
+} bind def
+
+% read width, height, and # of components from JPEG markers
+% and store in dict
+/readJPEGmarkers { % - ==> dict --or-- stop context
+ 5 dict begin
+
+ { % loop: read JPEG marker segments until we find SOFn marker or EOF
+ NextByte
+ 16#FF eq { % found marker
+ /markertype NextByte def
+ % Is it S0F0=baseline, SOF1=extended sequential, SOF2=progressive ?
+ markertype dup 16#C0 ge exch 16#C2 le and {
+ NextByte pop NextByte pop % segment length
+ % Ghostscript and Adobe PS accept only data precision 8
+ NextByte 8 ne {
+ (Error: not 8 bits per component!\n) print flush stop
+ } if
+
+ % Read crucial image parameters
+ /height NextByte 8 bitshift NextByte add def
+ /width NextByte 8 bitshift NextByte add def
+ /colors NextByte def
+
+ DEBUG { currentdict { exch == == } forall flush } if
+ exit
+ } if
+
+ % detect several segment types which are not compatible with PS
+ NotSupportedMarkers {
+ markertype eq {
+ (Marker ) print markertype ==
+ (not supported!\n) print flush stop
+ } if
+ } forall
+
+ % Skip segment if marker has parameters associated with it
+ true NoParamMarkers { markertype eq {pop false exit} if } forall
+ { SkipSegment } if
+ } if
+ } loop
+
+ currentdict dup /markertype undef
+ end
+} bind def
+
+end % JPEGdict
+
+% read image parameters from JPEG file and display the image
+/viewJPEG { % <file|string> ==> -
+ save
+ JPEGdict begin
+ /saved exch def
+ /scratch 1 string def
+ dup type /stringtype eq { (r) file } if
+ /F exch def
+
+ readJPEGmarkers begin
+ F 0 setfileposition % reset file pointer
+
+ % We use the whole clipping area for the image (at least in one dimension)
+ gsave clippath pathbbox grestore
+ /ury exch def /urx exch def
+ /lly exch def /llx exch def
+
+ llx lly translate
+ width height scale
+
+ % use whole width or height, whichever is appropriate
+ urx llx sub width div ury lly sub height div
+ 2 copy gt { exch } if pop % min
+ dup scale
+ ColorSpaceNames colors scratch cvs get setcolorspace
+
+ % prepare image dictionary
+ << /ImageType 1
+ /Width width
+ /Height height
+ /ImageMatrix [ width 0 0 height neg 0 height ]
+ /BitsPerComponent 8
+ % If 4-component (CMYK), assume data is inverted per Adobe Photoshop
+ colors 4 eq {
+ /Decode [ colors { 1 0 } repeat ]
+ } {
+ /Decode [ colors { 0 1 } repeat ]
+ } ifelse
+ /DataSource F /DCTDecode filter
+ >> image
+
+ end % image parameter dictionary
+
+ saved end restore
+} bind def
diff --git a/gs/lib/viewpbm.ps b/gs/lib/viewpbm.ps
new file mode 100644
index 000000000..16b9aab4e
--- /dev/null
+++ b/gs/lib/viewpbm.ps
@@ -0,0 +1,135 @@
+% Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Ghostscript.
+%
+% Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the Ghostscript General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute
+% Ghostscript, but only under the conditions described in the Ghostscript
+% General Public License. A copy of this license is supposed to have been
+% given to you along with Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+
+% viewpbm.ps
+% Display a PBM/PGM/PPM file.
+% Requires the Level 2 `image' operator (to handle variable pixel widths).
+% If SCALE is defined, maps input pixels to output pixels with that scale;
+% if SCALE is undefined, scales the image to fit the page.
+
+/s 100 string def
+/readmaxv
+ { f s readline pop cvx exec /maxv exch def
+ } bind def
+/readrow
+ { 0 1 row length 1 sub { row exch f token pop put } for
+ } bind def
+/read01 % <count> read01 <byte>
+ { 0 exch { f read pop 48 xor dup 1 le { exch dup add add } { pop } ifelse } repeat
+ } bind def
+/P1 % ASCII 1-bit white/black
+ { { /bpc 1 def /maxv 1 def /rsize w 7 add 8 idiv def
+ /wrem w 8 mod def
+ /ncomp 1 def /invert true def
+ }
+ { 0 1 w 8 idiv { row exch 8 read01 put } for
+ wrem 0 ne
+ { row rsize 1 sub wrem read01 8 wrem sub bitshift put
+ } if
+ row
+ }
+ runpbm
+ } bind def
+/P2 % ASCII 8-bit gray
+ { { /bpc 8 def readmaxv /rsize w def
+ /ncomp 1 def /invert false def
+ }
+ { readrow row }
+ runpbm
+ } bind def
+/P3 % ASCII 8-bit RGB
+ { { /bpc 8 def readmaxv /rsize w 3 mul def
+ /ncomp 3 def /invert false def /DeviceRGB setcolorspace
+ }
+ { readrow row }
+ runpbm
+ } bind def
+/P4 % Binary 1-bit white/black
+ { { /bpc 1 def /maxv 1 def /rsize w 7 add 8 idiv def
+ /ncomp 1 def /invert true def
+ }
+ { f row readstring pop }
+ runpbm
+ } bind def
+/P5 % Binary 8-bit gray
+ { { /bpc 8 def readmaxv /rsize w def
+ /ncomp 1 def /invert false def
+ }
+ { f row readstring pop }
+ runpbm
+ } bind def
+/P6 % Binary 8-bit RGB
+ { { /bpc 8 def readmaxv /rsize w 3 mul def
+ /ncomp 3 def /invert false def /DeviceRGB setcolorspace
+ }
+ { f row readstring pop }
+ runpbm
+ } bind def
+/viewpbm { run } def
+/runpbm % <initproc> <readproc> runpbm -
+ { /readproc exch def
+ /initproc exch def
+ currentfile /f exch def
+ f s readline pop % check for comment
+ (#) anchorsearch
+ { pop pop f s readline pop }
+ if
+ cvx exec /h exch def /w exch def
+ erasepage
+ /DeviceGray setcolorspace
+ initproc % sets bpc, maxv, rsize, ncomp, invert
+ /row rsize string def
+ /SCALE where
+ { pop
+ % Map pixels SCALE-for-1. Assume orthogonal transformation.
+ w 1 0 dtransform add abs div SCALE mul
+ h 0 1 dtransform add abs div SCALE mul
+ }
+ { % Scale the image (uniformly) to fit the page.
+ clippath pathbbox pop pop translate
+ pathbbox min exch pop exch pop ceiling
+ dup h mul w div
+ }
+ ifelse scale
+ 20 dict begin % image dictionary
+ /ImageType 1 def
+ /Width w def
+ /Height h def
+ /ImageMatrix [w 0 0 h neg 0 h] def
+ /BitsPerComponent bpc def
+ /Decode [ 0 255 maxv div invert { exch } if ncomp 1 sub { 2 copy } repeat ] def
+ /DataSource /readproc load def
+ currentdict end
+ image
+ showpage
+ } def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark 1 ge
+ { ] { viewpbm } forall
+ }
+ { cleartomark
+ (Usage: gs [--] viewpbm.ps filename.p*m ...\n) print
+ ( e.g.: gs [--] viewpbm.ps my.ppm another.ppm\n) print flush
+ }
+ ifelse
+ }
+ { pop
+ }
+ifelse
diff --git a/gs/lib/viewpcx.ps b/gs/lib/viewpcx.ps
new file mode 100644
index 000000000..09e0e2875
--- /dev/null
+++ b/gs/lib/viewpcx.ps
@@ -0,0 +1,133 @@
+% Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Ghostscript.
+%
+% Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the Ghostscript General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute
+% Ghostscript, but only under the conditions described in the Ghostscript
+% General Public License. A copy of this license is supposed to have been
+% given to you along with Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+
+% viewpcx.ps
+% Display a PCX file.
+% Requires the Level 2 `image' operator (to handle variable pixel widths).
+% If SCALE is defined, maps input pixels to output pixels with that scale;
+% if SCALE is undefined, scales the image to fit the page.
+% ****NOTE: Requires RLE compression; does not handle multi-plane
+% ****images with palette.
+
+/get2 % <string> <index> get2 <int>
+ { 2 copy get 3 1 roll 1 add get 8 bitshift add
+ } bind def
+/dsproc
+ { df s readstring pop % s gets filled in
+ s1 () ne { df s1 readstring pop pop } if % discard padding bytes
+ } def % don't bind, must be writable
+/viewpcx % <filename> viewpcx -
+ { 100 dict begin
+ /fname 1 index def
+ /f exch (r) file def
+ % Read and unpack the header.
+ /header f 128 string readstring pop def
+ /version header 1 get def
+ /bpp header 3 get def
+ /w header 8 get2 header 4 get2 sub 1 add def
+ /h header 10 get2 header 6 get2 sub 1 add def
+ /nplanes header 65 get def
+ /bpl header 66 get2 def
+ /palinfo header 68 get2 def
+ /nbits bpp nplanes mul def
+ version 5 eq
+ { nbits 8 le
+ { /cspace
+ [/Indexed /DeviceRGB 1 bpp bitshift 1 sub
+ f fileposition
+ 1 nbits bitshift 3 mul string
+ fname status pop pop pop exch pop
+ 1 index length sub f exch setfileposition
+ f exch readstring pop
+ exch f exch setfileposition
+ ] def
+ /decode [0 cspace 2 get] def
+ }
+ { /cspace /DeviceRGB def
+ /decode [0 1 0 1 0 1] def
+ }
+ ifelse
+ }
+ { /cspace
+ [/Indexed /DeviceRGB 1 bpp bitshift 1 sub
+ header 16 1 nbits bitshift 16 min 3 mul getinterval
+ ] def
+ /decode [0 cspace 2 get] def
+ }
+ ifelse
+ % Set up scaling.
+ /SCALE where
+ { pop
+ % Map pixels SCALE-for-1. Assume orthogonal transformation.
+ w 1 0 dtransform add abs div SCALE mul
+ h 0 1 dtransform add abs div SCALE mul
+ }
+ { % Scale the image (uniformly) to fit the page.
+ clippath pathbbox pop pop translate
+ pathbbox min exch pop exch pop ceiling
+ dup h w gt { w mul h div exch } { h mul w div } ifelse
+ }
+ ifelse scale
+ % Since the number of bytes per line is always even,
+ % it may not match the width specification.
+ /wbpl w bpp mul 7 add 8 idiv def
+ % Define the data source procedure.
+ /s1 bpl wbpl sub string def
+ /df f /PCXDecode filter def
+ /dsource [ nplanes
+ { /dsproc load copyarray
+ dup 1 wbpl string put
+ cvx bind readonly
+ }
+ repeat ] def
+ % Construct the image dictionary.
+ 20 dict begin % image dictionary
+ /ImageType 1 def
+ /Width w def
+ /Height h def
+ /ImageMatrix [w 0 0 h neg 0 h] def
+ /BitsPerComponent bpp def
+ /Decode decode def
+ /DataSource dsource dup length 1 gt
+ { /MultipleDataSources true def }
+ { 0 get }
+ ifelse def
+ currentdict end
+ % Finally, display the image.
+ cspace setcolorspace
+ image
+ showpage
+ df closefile
+ f closefile
+ end
+ } bind def
+
+% If the program was invoked from the command line, run it now.
+[ shellarguments
+ { counttomark 1 ge
+ { ] { viewpcx } forall
+ }
+ { cleartomark
+ (Usage: gs -- viewpcx.ps filename.pcx ...\n) print
+ ( e.g.: gs -- viewpcx.ps my.pcx another.pcx\n) print flush
+ }
+ ifelse
+ }
+ { pop
+ }
+ifelse
diff --git a/gs/lib/viewps2a.ps b/gs/lib/viewps2a.ps
new file mode 100644
index 000000000..03b89e15e
--- /dev/null
+++ b/gs/lib/viewps2a.ps
@@ -0,0 +1,33 @@
+% Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% Display a file produced by ps2ascii with no switch or with -dCOMPLEX.
+% This is just a procset to read in before the file to display.
+
+/init { 0.1 0.1 scale } bind def
+init
+/next { currentfile token pop } bind def
+/F { next next pop next exch selectfont } bind def
+/P { showpage init } bind def
+/S
+ { next next moveto
+ next dup stringwidth pop next exch div
+ gsave 1 scale show grestore
+ } bind def
+/C { next next next setrgbcolor } bind def
+/I { next next next next gsave 0.75 setgray rectfill grestore } bind def
+/R { next next next next rectfill } bind def
diff --git a/gs/lib/waterfal.ps b/gs/lib/waterfal.ps
new file mode 100644
index 000000000..9617d7242
--- /dev/null
+++ b/gs/lib/waterfal.ps
@@ -0,0 +1,74 @@
+% Copyright (C) 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% waterfal.ps
+% This file produces a 'waterfall' printout of fonts at various sizes.
+
+
+% Specify any desired set of up to 3 fonts here.
+/Fonts [/Courier /Helvetica] def
+
+% Specify any desired set of point sizes here.
+% The sum of the sizes should not exceed (roughly) 100.
+% For sizes larger than about 16, some characters may fall off the page.
+/Sizes [6 7 8 9 10 11 12 14 16] def
+
+/eol
+ { currentfont /FontBBox get aload pop
+ exch pop sub exch pop 0 exch
+ % Many Ghostscript fonts have incorrect FontBBoxes....
+ pop -1000
+ 1.15 mul currentfont /FontMatrix get dtransform
+ translate
+ 0 0 moveto
+ } def
+
+(landscap.ps) runlibfile
+clippath pathbbox newpath
+/ury exch def /urx exch def /lly exch def /llx exch def
+llx 18 add ury 18 sub translate
+% Read the current Y resolution without using Ghostscript-specific operators.
+gsave initmatrix 0 72 dtransform abs exch abs exch .max grestore
+round cvi /dpi exch def
+QUIET not
+ { (Creating waterfall printout at ) print dpi =only ( DPI.\n) print flush
+ }
+if
+
+newpath 0 setgray
+/Courier findfont 20 scalefont setfont
+
+Fonts
+ { save exch
+ findfont /basefont exch def
+ basefont 20 scalefont setfont eol
+ basefont /FontName get =string cvs show
+ ( ) show dpi =string cvs show ( DPI) show
+ Sizes
+ { dup /size exch def basefont exch scalefont setfont eol
+ size =string cvs show ( ) show
+ (qwertyuiop-asdfghjkl_zxcvbnm ) show
+ (QWERTYUIOP+ASDFGHJKL/ZXCVBNM ) show
+ (1470258369 .,:;?!) show
+ } forall
+ matrix currentmatrix aload pop
+ 7 -1 roll restore
+ 6 array astore setmatrix
+ } forall
+
+showpage
+quit
diff --git a/gs/lib/wftopfa b/gs/lib/wftopfa
new file mode 100755
index 000000000..2df09167d
--- /dev/null
+++ b/gs/lib/wftopfa
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gs -q -dNODISPLAY -- wftopfa.ps "$@"
diff --git a/gs/lib/wftopfa.ps b/gs/lib/wftopfa.ps
new file mode 100644
index 000000000..2b463dd46
--- /dev/null
+++ b/gs/lib/wftopfa.ps
@@ -0,0 +1,304 @@
+% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% wftopfa.ps
+% Convert a Wadalab base font to .PFA (or .PFB) format.
+
+(gs_ksb_e.ps) runlibfile
+(wrfont.ps) runlibfile
+
+/wftopfa_dict 100 dict def
+wftopfa_dict begin
+
+/KanjiSubEncoding dup .findencoding def
+
+% Initialize parameters.
+/init % - init -
+ { /chars 256 dict def
+ /version (001.001) def
+ /highcode 0 def
+ /StdHW [32] def
+ /StdVW [32] def
+ /UniqueID 20000000 def
+ /FontBase (Wadalab) def
+ /StdEncMode false def
+ /CustomEncMode false def
+ /Binary false def
+ /Encrypt true def
+ } bind def
+
+% Read definitions.
+/rdstring 5000 string def
+/readdefs % <filename> readdefs -
+ { (r) file
+ { dup rdstring readline not { pop exit } if
+ dup length 15 ge
+ { dup dup length 7 sub 7 getinterval (> CompD) eq
+ { token pop exch token pop exch pop
+ dup 0 get /highcode exch def
+ exch chars 3 1 roll put
+ }
+ { pop
+ }
+ ifelse
+ }
+ { pop
+ }
+ ifelse
+ }
+ loop closefile
+ } bind def
+
+% Write out the final font.
+/writepfa
+ { 4 string highcode 16#1000 add 16 2 index cvrs 0 (.r) putinterval
+ FontBase exch concatstrings /fullname exch def
+ UniqueID 20000000 eq { /UniqueID 4990000 highcode add def } if
+ /encoding CustomEncMode
+ { KanjiSubEncoding }
+ { StdEncMode { StandardEncoding } { ISOLatin1Encoding } ifelse }
+ ifelse def
+
+ /Font 30 dict def
+ Font begin
+ /FontInfo 20 dict def
+ FontInfo begin
+
+ % Write the clear text part.
+
+ /CreationDate (%Calendar%) currentdevparams
+ dup /Weekday get {(Sun )(Mon )(Tue )(Wed )(Thu )(Fri )(Sat )} exch get
+ 1 index /Month get 1 sub
+ {(Jan)(Feb)(Mar)(Apr)(May)(Jun)(Jul)(Aug)(Sep)(Oct)(Nov)(Dec)} exch get
+ concatstrings
+ {{/Day ( )} {/Hour ( )} {/Minute (:)} {/Second (:)} {/Year ( )}}
+ { dup 1 get 3 -1 roll exch concatstrings exch
+ 0 get 2 index exch get
+ dup 10 lt { =string cvs (0) exch concatstrings } { =string cvs } ifelse
+ concatstrings
+ }
+ forall exch pop readonly def
+ /VMusage 100000 def
+ /version version readonly def
+ /Notice (No copyright on this font. Original available from moe.ipl.t.u-tokyo.ac.jp:/Font. Converted by wftopfa.ps (Aladdin Enterprises).) readonly def
+ /FullName fullname readonly def
+ /FamilyName FontBase readonly def
+ /Weight (Regular) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch true def
+ /UnderlinePosition 0 def
+ /UnderlineThickness 0 def
+
+ end % FontInfo
+
+ /FontName fullname cvn def
+ /Encoding encoding def
+ /PaintType 0 def
+ /FontType 1 def
+ /FontMatrix [.001 0 0 .001 0 -0.16] readonly def
+ /UniqueID UniqueID def
+ /FontBBox [0 0 1000 1000] readonly def
+
+ /Private 20 dict def
+ Private begin
+
+ /-| {string currentfile exch readstring pop} readonly def
+ /|- {readonly def} readonly def
+ /| {readonly put} readonly def
+ /BlueValues [] readonly def
+ /OtherBlues [] readonly def
+ /MinFeature {16 16} readonly def
+ /StdHW StdHW def
+ /StdVW StdVW def
+ /ForceBold false def
+ /password 5839 def
+ /UniqueID UniqueID def
+ /OtherSubrs [] readonly def
+ /Subrs [
+ (\020\2771p|\020\024\020=-\223D\\\342R) readonly
+ (\020\2771py\274\366Uz) readonly
+ (\020\2771py\275\304\236i) readonly
+ (\020\2771p\371) readonly
+ (\020\2771p~\266+6\034\3446z) readonly
+ ] readonly def
+
+ end % Private
+
+ /CharStrings 256 dict def
+ chars
+ { exch =string cvs
+ dup 0 get highcode eq
+ { 1 get encoding exch get exch CharStrings 3 1 roll put }
+ { pop pop }
+ ifelse
+ }
+ forall
+
+ end % Font
+
+ Font /FontName get Font definefont setfont
+ (%stdout) (w) file writefont
+ } bind def
+
+% Scan the command line and process files.
+/options mark
+ /version { 2 copy get /version exch def 1 add } bind
+ /StdHW { 2 copy get cvx exec /StdHW exch def 1 add } bind
+ /StdVW { 2 copy get cvx exec /StdVW exch def 1 add } bind
+ /UniqueId { 2 copy get cvi /UniqueID exch def 1 add } bind
+ /UniqueID 1 index
+ /FontBase { 2 copy get /FontBase exch def 1 add } bind
+ /StdEnc { /StdEncMode true def } bind
+ /CustomEnc { /CustomEncMode true def } bind
+ /Binary { /Binary true def } bind
+ /noEncrypt { /Encrypt false def } bind
+.dicttomark def
+/wftopfa % [(arg1) ...] wftopfa -
+ { init dup 0
+ { dup 2 index length ge { exit } if
+ 2 copy get exch 1 add exch
+ options 1 index .knownget { exch pop exec } { readdefs } ifelse
+ }
+ loop pop pop
+ wrfont_dict /binary_CharStrings Binary put
+ wrfont_dict /eexec_encrypt Encrypt put
+ wrfont_dict /name_all_Encodings CustomEncMode put
+ writepfa
+ } bind def
+
+end % wftopfa_dict
+
+/wftopfa
+ { mark exch wftopfa_dict begin /saved save def { wftopfa } exec false%stopped
+ { cleartomark true } { cleartomark false } ifelse
+ saved end restore { stop } if
+ } bind def
+
+[ shellarguments
+ { ] wftopfa }
+ { pop }
+ifelse
+
+% ---------------- Root font ---------------- %
+
+% Define the Encoding for the root font.
+/wfrootencoding
+% \x00-\x3F
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0
+ 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
+% \x40-\x7F
+ 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 0 0 0 0 0 0 0 0 0 0 0
+% \x80-\xFF
+128 copy
+256 packedarray def
+
+% Define the template for the root font dictionary.
+/wfrootfontdict mark
+ /FontType 0
+ /FontMatrix [1 0 0 1 0 0]
+ /FMapType 2
+ /Encoding wfrootencoding
+.dicttomark def
+
+% Define a dummy (placeholder) Type 1 font for the FDepVector.
+/type1dummyfont % <fontname> type1dummyfont <font>
+ { mark /FontName 3 -1 roll
+ /FontType 1
+ /FontMatrix [.001 0 0 .001 0 0]
+ /FontBBox [0 0 1000 1000]
+ /Encoding /KanjiSubEncoding findencoding
+ /CharStrings 0 dict
+ /Private mark /BlueValues [] /password 5839 .dicttomark
+ .dicttomark dup /FontName get exch definefont
+ } bind def
+
+% Write a root font. Again, wrfont.ps does most of the work.
+/makerootfont % <rootname> makerootfont <font>
+ { wfrootfontdict dup length 4 add % FontName, FDepVector, PrefEnc, FID
+ dict copy begin
+ cvlit /FontName exch def
+ 4 dict begin
+ /len FontName length def
+ /str len 4 add string def
+ FontName str cvs pop
+ str len (.r) putinterval
+ /FDepVector [ 16#21 1 16#74
+ { dup wfrootencoding exch get 0 eq
+ { pop
+ }
+ { 16 str len 2 add 2 getinterval cvrs pop
+ str cvn type1dummyfont
+ }
+ ifelse
+ }
+ for end counttomark -1 roll dup counttomark 2 roll
+ ] def
+ FontName currentdict end definefont
+ } bind def
+/writerootfont % <rootname> writerootfont -
+ { save exch makerootfont setfont (%stdout) (w) file writefont restore
+ } bind def
+
+% ---------------- Converting entire fonts ---------------- %
+
+% Define the directory where the Wadalab fonts are stored.
+/wfdir (/home/ghost/kanji/w) def
+
+% Convert an entire Wadalab font.
+/writeentirefont % <fontname> <template*> writeentirefont -
+ { 2 dict begin
+ /templates exch def
+ /fontname exch def
+ [ templates
+ { wfdir (/) concatstrings exch concatstrings { copystring }
+ 100 string filenameforall
+ }
+ forall
+ wfdir (/wadalab-sym/*.ps) concatstrings { copystring }
+ 100 string filenameforall
+ ]
+ (%!\n) print
+ { /currentuserparams where
+ { pop currentuserparams /VMReclaim get -2 vmreclaim { vmreclaim } }
+ { { } }
+ ifelse
+ } == (exec\n) print
+ (/KanjiSubEncoding ) print /KanjiSubEncoding findencoding ==
+ (readonly def\n) print
+ { (%stderr) (w) file dup 2 index write== flushfile
+ mark exch (CustomEnc) (Binary) (noEncrypt)
+ (FontBase) fontname counttomark -1 roll ] wftopfa
+ }
+ forall
+ fontname cvn writerootfont
+ (exec\n) print
+ end
+ } def % don't bind, so we can print the procedure
+
+% Convert the Wadalab JIS 1&2 SaiMincho font.
+% To invoke this from the command line,
+% gs -dNODISPLAY -q wftopfa.ps -c writeSaiMincho0 flush quit >wmin0.ps
+% To make the resulting font loadable on demand, add to the Fontmap file:
+% /Wadalab-SaiMincho (wmin0.ps) ;
+/writeSaiMincho0
+ { (Wadalab-SaiMincho) [ (wadalab-mincho-0-8/*.ps) ] writeentirefont
+ } bind def
diff --git a/gs/lib/winmaps.ps b/gs/lib/winmaps.ps
new file mode 100644
index 000000000..8de0a14da
--- /dev/null
+++ b/gs/lib/winmaps.ps
@@ -0,0 +1,107 @@
+% Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% winmaps.ps - make maps between PostScript encodings and Windows
+% character sets.
+
+% Define the two Windows encodings.
+
+/ANSIEncoding
+ ISOLatin1Encoding 256 array copy
+ dup 16#90 /.notdef put
+ 16#93 1 16#9f { 2 copy /.notdef put pop } for
+def
+
+/OEMEncoding [
+ /.notdef /.notdef /.notdef /heart /diamond /club /spade /bullet
+ 8 { /.notdef } repeat
+ /.notdef /.notdef /.notdef /.notdef /paragraph /section /.notdef /.notdef
+ /arrowup /arrowdown /arrowright /arrowleft /.notdef /arrowboth /.notdef /.notdef
+ StandardEncoding 32 96 getinterval aload pop
+ /Ccedilla /udieresis /eacute /acircumflex /adieresis /agrave /aring /ccedilla
+ /ecircumflex /edieresis /egrave /idieresis /igrave /Adieresis /Aring
+ /Eacute /ae /AE /ocircumflex /odieresis /ograve /ucircumflex /ugrave
+ /ydieresis /Odieresis /Udieresis /cent /sterling /yen /.notdef /florin
+ /aacute /iacute /oacute /uacute /ntilde /Ntilde /ordfeminine /ordmasculine
+ /questiondown /.notdef /logicalnot /onehalf /onequarter /exclamdown /guillemotleft /guillemotright
+ 48 { /.notdef } repeat
+ /alpha /beta /Gamma /Pi /Sigma /sigma /mu /tau
+ /Phi /Theta /Omega /delta /infinity /phi /element /intersection
+ /equivalence /plusminus /greaterequal /lessequal /integraltp /integralbt /divide /.notdef
+ /degree /dotmath /periodcentered /radical /.notdef /twosuperior /.notdef /.notdef
+] def
+
+% Utility procedures
+
+/invertencoding % <array> invertencoding <dict>
+ { 256 dict exch dup length 1 sub -1 0
+ { % stack: dict array index
+ 2 copy get /.notdef ne
+ { 2 copy get exch 3 index 3 1 roll put }
+ { pop }
+ ifelse
+ } for
+ pop
+ } def
+
+/pmarray 256 array def
+/printmap % <chars> <decode> printmap -
+ { mark 3 1 roll exch
+ { 2 copy known { 1 index exch get } { pop 0 } ifelse exch
+ }
+ forall pop
+ pmarray 0 counttomark 2 sub getinterval astore
+ ([) print dup length =only 0 exch (] = {\n ) exch
+ { exch print =only
+ 1 add 15 and dup 0 eq { (,\n ) } { (, ) } ifelse
+ }
+ forall pop pop (\n};\n) print pop
+ } def
+
+/decodeStd StandardEncoding invertencoding def
+/decodeISO ISOLatin1Encoding
+ % Remove the redundant characters
+ dup length array copy
+ [8#222 8#225 8#230 8#233 8#240] { 2 copy /.notdef put pop } forall
+invertencoding def
+/decodeSym SymbolEncoding invertencoding def
+
+/decodeANSI ANSIEncoding invertencoding def
+/decodeOEM OEMEncoding invertencoding def
+
+% Construct the map from Symbol to OEM.
+
+(\nprivate const byte far_data gs_map_symbol_to_oem) print
+SymbolEncoding decodeOEM printmap
+
+% Construct the map from ISOLatin1 to OEM.
+
+(\nprivate const byte far_data gs_map_iso_to_oem) print
+ISOLatin1Encoding decodeOEM printmap
+
+% Construct the map from Standard to ISOLatin1.
+
+(\nprivate const byte far_data gs_map_std_to_iso) print
+StandardEncoding decodeISO printmap
+
+% Construct the map from ISOLatin1 to Standard.
+% The Windows driver doesn't need this, but the X11 driver does.
+
+(\nprivate const byte far_data gs_map_iso_to_std) print
+ISOLatin1Encoding decodeStd printmap
+
+quit
diff --git a/gs/lib/wmakebat.bat b/gs/lib/wmakebat.bat
new file mode 100644
index 000000000..3fb607c90
--- /dev/null
+++ b/gs/lib/wmakebat.bat
@@ -0,0 +1,2 @@
+wmakel -u -n -h %1 %2 %3 %4 %5 %6 %7 %8 %9 >_wm_temp.bat
+_wm_temp.bat
diff --git a/gs/lib/wrfont.ps b/gs/lib/wrfont.ps
new file mode 100644
index 000000000..1e9ba1be2
--- /dev/null
+++ b/gs/lib/wrfont.ps
@@ -0,0 +1,663 @@
+% Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% wrfont.ps
+% Write out a Type 1 font in readable, reloadable form.
+% Note that this does NOT work on protected fonts, such as Adobe fonts
+% (unless you have loaded unprot.ps first, in which case you may be
+% violating the Adobe license).
+
+% ****** NOTE: This file must be kept consistent with gs_pfile.ps.
+
+/wrfont_dict 100 dict def
+wrfont_dict begin
+
+% ------ Options ------ %
+
+% Define whether to use eexec encryption for the font.
+% eexec encryption is only useful for compatibility with Adobe Type Manager
+% and other programs; it only slows Ghostscript down.
+ /eexec_encrypt false def
+
+% Define whether to write out the CharStrings in binary or in hex.
+% Binary takes less space on the file, but isn't guaranteed portable.
+ /binary_CharStrings false def
+
+% Define whether to use binary token encodings when possible.
+% Binary tokens are smaller and load faster, but are a Level 2 feature.
+ /binary_tokens false def
+
+% Define whether to encrypt the CharStrings on the file. (CharStrings
+% are always encrypted in memory.) Unencrypted CharStrings load about
+% 20% slower, but make the files compress much better for transport.
+ /encrypt_CharStrings true def
+
+% Define whether the font must provide standard PostScript language
+% equivalents for any facilities it uses that are provided in Ghostscript
+% but are not part of the standard PostScript language.
+ /standard_only true def
+
+% Define the value of lenIV to use in writing out the font.
+% use_lenIV = 0 produces the smallest output, but this may not be
+% compatible with old Adobe interpreters. use_lenIV = -1 means
+% use the value of lenIV from the font.
+ /use_lenIV -1 def
+
+% Define whether to produce the smallest possible output, relying
+% as much as possible on Ghostscript-specific support code.
+% Taking full advantage of this requires the following settings:
+% binary_CharStrings = true, binary_tokens = true, standard_only = false.
+ /smallest_output false def
+
+% Define whether to write out all currently known Encodings by name,
+% or only StandardEncoding and ISOLatin1Encoding.
+ /name_all_Encodings false def
+
+% ---------------- Runtime support ---------------- %
+
+/.packedfilefilter where
+ { pop }
+ { (gs_pfile.ps) runlibfile }
+ifelse
+
+% ------ Output utilities ------ %
+
+% By convention, the output file is named psfile.
+
+% Define some utilities for writing the output file.
+ /wtstring 2000 string def
+ /wb {psfile exch write} bind def
+ /wnb {/wb load repeat} bind def
+ /w1 {psfile exch write} bind def
+ /ws {psfile exch writestring} bind def
+ /wl {ws (\n) ws} bind def
+ /wt {wtstring cvs ws ( ) ws} bind def
+ /wd % Write a dictionary.
+ { dup length wo {dict dup begin} wol { we } forall
+ {end} wol
+ } bind def
+ /wld % Write a large dictionary more efficiently.
+ % Ignore the readonly attributes.
+ { dup length wo {dict dup begin} wol
+ 0 exch
+ { exch wo wo () wl
+ 1 add dup 200 eq
+ { wo ({def} repeat) wl 0 }
+ if
+ }
+ forall
+ dup 0 ne
+ { wo ({def} repeat) wl }
+ { pop }
+ ifelse
+ (end) ws
+ } bind def
+ /we % Write a dictionary entry.
+ { exch wo wo /def cvx wo (\n) ws
+ } bind def
+ /wcs % Write a CharString (or Subrs entry)
+ { dup type /stringtype eq
+ { 4330 exch changelenIV 0 ge
+ { % Add some leading garbage bytes.
+ wtstring changelenIV 2 index length getinterval
+ .type1decrypt exch pop
+ wtstring exch 0 exch length changelenIV add getinterval
+ }
+ { % Drop some leading garbage bytes.
+ wtstring .type1decrypt exch pop
+ changelenIV neg 1 index length 1 index sub getinterval
+ }
+ ifelse
+ binary_tokens encrypt_CharStrings and
+ { % Suppress recognizing the readonly status of the string.
+ 4330 exch dup .type1encrypt exch pop wo
+ }
+ { encrypt_CharStrings
+ { 4330 exch dup .type1encrypt exch pop
+ } if
+ smallest_output
+ { wo
+ }
+ { readonly dup length wo
+ binary_tokens not { ( ) ws } if
+ readproc ws wx
+ }
+ ifelse
+ }
+ ifelse
+ }
+ { wo % PostScript procedure
+ }
+ ifelse
+ } bind def
+
+% Construct the inversion of the system name table.
+ /SystemNames where
+ { pop /snit 256 dict def
+ 0 1 255
+ { dup SystemNames exch get
+ dup null ne { exch snit 3 1 roll put } { pop pop } ifelse
+ }
+ for
+ }
+ { /snit 1 dict def
+ }
+ ifelse
+
+% Write an object, using binary tokens if requested and possible.
+ /woa % write in ascii
+ { psfile exch write==only
+ } bind def
+
+ % Lookup table for ASCII output.
+
+ /intbytes % int nbytes -> byte*
+ { { dup 255 and exch -8 bitshift } repeat pop
+ } bind def
+ /wotta 10 dict dup begin
+ { /booleantype /integertype }
+ { { ( ) ws woa } def }
+ forall
+ % Iterate over arrays so we can print operators.
+ /arraytype
+ { dup xcheck {(}) ({)} {(]) ([)} ifelse ws exch dup wol exch ws wop
+ } bind def
+ /dicttype
+ { ( ) ws wd } def
+ /nametype
+ { dup xcheck { ( ) ws } if woa
+ } bind def
+ % Map back operators to their names,
+ % so we can write procedures.
+ /nulltype
+ { pop ( null) ws
+ } bind def
+ /operatortype
+ { wtstring cvs cvn cvx wo
+ } bind def
+ % Convert reals to integers if possible.
+ /realtype
+ { dup cvi 1 index eq { cvi wo } { ( ) ws woa } ifelse
+ } bind def
+ % == truncates strings longer than 200 characters!
+ /stringtype
+ { (\() ws dup
+ { dup dup 32 lt exch 127 ge or
+ { (\\) ws dup -6 bitshift 48 add w1
+ dup -3 bitshift 7 and 48 add w1
+ 7 and 48 add
+ }
+ { dup dup -2 and 40 eq exch 92 eq or {(\\) ws} if
+ }
+ ifelse w1
+ }
+ forall
+ (\)) ws wop
+ } bind def
+ /packedarraytype
+ { ([) ws dup { wo } forall
+ encodingnames 1 index known
+ % This is an encoding, but not one of the standard ones.
+ % Use the built-in encoding only if it is available.
+ { encodingnames exch get wo
+ ({findencoding}stopped{pop) ws
+ (}{counttomark 1 add 1 roll cleartomark}ifelse)
+ }
+ { pop ()
+ }
+ ifelse
+ (/packedarray where{pop counttomark packedarray exch pop}{]readonly}ifelse) ws
+ wl
+ }
+ def
+ end def
+
+ % Lookup table for binary output.
+
+ /wottb 8 dict dup begin
+ wotta currentdict copy pop
+ /integertype
+ { dup dup 127 le exch -128 ge and
+ { 136 wb 255 and wb }
+ { dup dup 32767 le exch -32768 ge and
+ { 134 wb 2 intbytes wb wb }
+ { 132 wb 4 intbytes wb wb wb wb }
+ ifelse
+ }
+ ifelse
+ } bind def
+ /nametype
+ { dup snit exch known
+ { dup xcheck { 146 } { 145 } ifelse wb
+ snit exch get wb
+ }
+ { wotta /nametype get exec
+ }
+ ifelse
+ } bind def
+ /stringtype
+ { dup dup length dup 255 le { 142 2 } { 2 intbytes 143 3 } ifelse wnb
+ ws wop
+ } bind def
+ end def
+
+ /wop % Write object protection
+ { wcheck not { /readonly cvx wo } if
+ } bind def
+ /wo % Write an object.
+ { dup type binary_tokens { wottb } { wotta } ifelse
+ exch get exec
+ } bind def
+ /wol % Write a list of objects.
+ { { wo } forall
+ } bind def
+
+% Write a hex string for Subrs or CharStrings.
+ /wx % string ->
+ { binary_CharStrings
+ { ws
+ }
+ { % Some systems choke on very long lines, so
+ % we break up the hexstring into chunks of 50 characters.
+ { dup length 25 le {exit} if
+ dup 0 25 getinterval psfile exch writehexstring (\n) ws
+ dup length 25 sub 25 exch getinterval
+ } loop
+ psfile exch writehexstring
+ } ifelse
+ } bind def
+
+% ------ CharString encryption utilities ------ %
+
+/enc_dict 20 dict def
+1 dict begin
+/bind { } def % make sure we can print out the procedures
+enc_dict begin
+
+(type1enc.ps) runlibfile
+enc_dict /.type1decrypt undef % we don't need this
+
+end end
+
+enc_dict { 1 index where { pop pop pop } { def } ifelse } forall
+
+% ------ Other utilities ------ %
+
+% Test whether two values are equal (for default dictionary entries).
+ /valueeq % <obj1> <obj2> valueeq <bool>
+ { 2 copy eq
+ { pop pop true }
+ { % Special hack for comparing FontMatrix values
+ dup type /arraytype eq 2 index type /arraytype eq and
+ { dup length 2 index length eq
+ { true 0 1 3 index length 1 sub
+ { % Stack: arr1 arr2 true index
+ 3 index 1 index get 3 index 3 -1 roll get eq not
+ { pop false exit }
+ if
+ }
+ for 3 1 roll pop pop
+ }
+ { pop pop false
+ }
+ ifelse
+ }
+ { pop pop false
+ }
+ ifelse
+ }
+ ifelse
+ } bind def
+
+% ------ The main program ------ %
+
+% Define the dictionary of keys to skip because they are treated specially.
+/.fontskipkeys mark
+ /CharStrings dup
+ /Encoding dup
+ /FDepVector dup
+ /FID dup
+ /FontInfo dup
+ /Metrics dup
+ /Metrics2 dup
+ /Private dup
+.dicttomark def
+/.minfontskipkeys mark
+ .fontskipkeys { } forall
+ /FontName dup
+ /UniqueID dup
+.dicttomark def
+/.privateskipkeys mark
+ /ND dup
+ /NP dup
+ /RD dup
+ /Subrs dup
+.dicttomark def
+/.minprivateskipkeys mark
+ .privateskipkeys { } forall
+ /MinFeature dup
+ /Password dup
+ /UniqueID dup
+.dicttomark def
+
+% Define the procedures for the Private dictionary.
+% These must be defined without `bind',
+% for the sake of the DISKFONTS feature.
+4 dict begin
+ /-! {string currentfile exch readhexstring pop} def
+ /-| {string currentfile exch readstring pop} def
+ /|- {readonly def} def
+ /| {readonly put} def
+currentdict end /encrypted_procs exch def
+4 dict begin
+ /-! {string currentfile exch readhexstring pop
+ 4330 exch dup .type1encrypt exch pop} def
+ /-| {string currentfile exch readstring pop
+ 4330 exch dup .type1encrypt exch pop} def
+ /|- {readonly def} def
+ /| {readonly put} def
+currentdict end /unencrypted_procs exch def
+
+% Construct an inverse dictionary of encodings.
+/encodingnames mark
+ StandardEncoding /StandardEncoding
+ ISOLatin1Encoding /ISOLatin1Encoding
+ SymbolEncoding /SymbolEncoding
+ DingbatsEncoding /DingbatsEncoding
+ /resourceforall where
+ { pop (*) { cvn dup findencoding exch } 100 string /Encoding resourceforall }
+ if
+.dicttomark def
+
+% Invert the standard encodings.
+.knownEncodings length 256 mul dict begin
+ 0 .knownEncodings
+ { { currentdict 1 index known { pop } { 1 index def } ifelse
+ 1 add
+ }
+ forall
+ }
+ forall pop
+currentdict end /inverseencodings exch def
+
+/writefont % <psfile> writefont - (writes the current font)
+ { /psfile exch def
+ /Font currentfont def
+ /FontInfo Font /FontInfo .knownget not { 0 dict } if def
+ /FontType Font /FontType get def
+ /hasPrivate Font /Private known def
+ /Private hasPrivate { Font /Private get } { 0 dict } ifelse def
+ /readproc binary_CharStrings { (-| ) } { (-! ) } ifelse def
+ /privateprocs
+ encrypt_CharStrings binary_tokens not and
+ { encrypted_procs } { unencrypted_procs } ifelse
+ def
+ /addlenIV false def
+ /changelenIV use_lenIV 0 lt
+ { 0 }
+ { use_lenIV Private /lenIV .knownget not
+ { 4 /addlenIV use_lenIV 4 ne def } if sub }
+ ifelse def
+ /minimize
+ smallest_output
+ FontType 1 eq and
+ Font /UniqueID known and
+ def
+ (%!FontType) ws FontType wtstring cvs ws (-1.0: ) ws
+ currentfont /FontName get wt
+ FontInfo /version .knownget not { (001.001) } if wl
+ FontInfo /CreationDate .knownget { (%%Creation Date: ) ws wl } if
+ FontInfo /VMusage .knownget
+ { (%%VMusage: ) ws dup wt wtstring cvs wl }
+ if
+ (systemdict begin) wl
+
+% If we're going to use eexec, create the filters now.
+ /realpsfile psfile def
+ eexec_encrypt
+ { /eexecfilter psfile binary_CharStrings not
+ { pop /bxstring 35 string def
+ { pop dup length 0 ne
+ { realpsfile exch writehexstring realpsfile (\n) writestring }
+ { pop }
+ ifelse bxstring
+ }
+ /NullEncode filter dup /hexfilter exch def
+ }
+ if 55665 /eexecEncode filter def
+ }
+ if
+
+% Turn on binary tokens if relevant.
+ binary_tokens { (currentobjectformat 1 setobjectformat) wl } if
+
+% If the file has a UniqueID, write out a check against loading it twice.
+ minimize
+ { Font /FontName get wo
+ Font /UniqueID get wo
+ Private length addlenIV { 1 add } if wo
+ Font length 1 add wo % +1 for FontFile
+ ( .checkexistingfont) wl
+ }
+ { Font /UniqueID known
+ { ({} FontDirectory) ws Font /FontName get dup wo ( known) wl
+ ( {) ws wo ( findfont dup /UniqueID known) wl
+ ( { dup /UniqueID get) ws Font /UniqueID get wo ( eq exch /FontType get 1 eq and }) wl
+ ( { pop false } ifelse) wl
+ ( { pop save /restore load } if) wl
+ ( } if) wl
+ }
+ if
+ }
+ ifelse
+
+% If we are writing unencrypted CharStrings for a standard environment,
+% write out the encryption procedures.
+ privateprocs unencrypted_procs eq standard_only and
+ { (systemdict /.type1encrypt known) wl
+ ( { save /restore load } { { } } ifelse) wl
+ (userdict begin) wl
+ enc_dict { we } forall
+ (end exec) wl
+ }
+ if
+
+% Write out the creation of the font dictionary and FontInfo.
+ minimize not
+ { Font length 1 add wo {dict begin} wol % +1 for FontFile
+ }
+ if
+ (/FontInfo ) ws FontInfo wd {readonly def} wol
+
+% Write out the other fixed entries in the font dictionary.
+ Font begin
+ Font
+ { minimize
+ { .minfontskipkeys 2 index known
+ { pop pop
+ }
+ { //.compactfontdefault 2 index .knownget
+ { 1 index valueeq { pop pop } { we } ifelse }
+ { we }
+ ifelse
+ }
+ ifelse
+ }
+ { .fontskipkeys 2 index known { pop pop } { we } ifelse
+ }
+ ifelse
+ } forall
+ /Encoding
+ encodingnames Encoding known
+ name_all_Encodings
+ Encoding StandardEncoding eq or
+ Encoding ISOLatin1Encoding eq or and
+ { encodingnames Encoding get cvx }
+ { Encoding }
+ ifelse
+ dup /StandardEncoding cvx eq minimize and
+ { pop pop }
+ { we }
+ ifelse
+
+% Write the FDepVector, if any.
+ Font /FDepVector .knownget
+ { {/FDepVector [} wol
+ { /FontName get wo {findfont} wol () wl } forall
+ {] readonly def} wol
+ }
+ if
+
+% Write out the Metrics, if any.
+ Font /Metrics .knownget
+ { (/Metrics ) ws wld {readonly def} wol
+ }
+ if
+ Font /Metrics2 .knownget
+ { (/Metrics2 ) ws wld {readonly def} wol
+ }
+ if
+
+% Start the eexec-encrypted section, if applicable.
+ eexec_encrypt
+ { {currentdict currentfile eexec} wol () wl
+ /psfile eexecfilter store
+ (\000\000\000\000) ws {begin} wol
+ }
+ if
+
+% Create and initialize the Private dictionary, if any.
+ hasPrivate
+{
+ Private
+ minimize
+ { begin {Private dup begin}
+ }
+ { dup length privateprocs length add dict copy begin
+ privateprocs { readonly def } forall
+ /Private wo
+ currentdict length 1 add wo {dict dup begin}
+ }
+ ifelse wol () wl
+ currentdict
+ { 1 index minimize { .minprivateskipkeys } { .privateskipkeys } ifelse
+ exch known
+ { pop pop }
+ { 1 index /lenIV eq use_lenIV 0 ge and { pop use_lenIV } if we }
+ ifelse
+ } forall
+ addlenIV { /lenIV use_lenIV we } if
+}
+if
+
+% Write the Subrs entries, if any.
+ currentdict /Subrs known
+ { (/Subrs[) wl
+ Subrs
+ { dup null ne
+ { wcs minimize not { () wl } if }
+ { pop /null cvx wo }
+ ifelse
+ } forall
+ {] dup {readonly pop} forall readonly def} wol () wl
+ }
+ if
+
+% Wrap up the Private dictionary.
+ hasPrivate
+ { end % Private
+ minimize
+ { {end readonly pop} } % Private
+ { {end readonly def} } % Private in font
+ ifelse wol
+ }
+ if
+
+% Write the CharStrings entries.
+% Detect identical (eq) entries, which bdftops produces.
+ currentdict /CharStrings known
+{
+ /CharStrings wo CharStrings length wo
+ minimize
+ { encrypt_CharStrings not wo ( .readCharStrings) wl
+ CharStrings length dict
+ CharStrings
+ { exch inverseencodings 1 index .knownget not { dup } if wo
+ % Stack: vdict value key
+ 3 copy pop .knownget { wo pop pop } { 3 copy put pop wcs } ifelse
+ } forall
+ }
+ { {dict dup Private begin begin} wol () wl
+ CharStrings length dict
+ CharStrings
+ { 2 index 1 index known
+ { exch wo 1 index exch get wo {load def} wol () wl
+ }
+ { 2 index 1 index 3 index put
+ exch wo wcs ( |-) wl
+ }
+ ifelse
+ } forall
+ {end end} wol
+ }
+ ifelse
+ pop
+ { readonly def } % CharStrings in font
+ wol
+}
+if
+
+% Terminate the output.
+ end % Font
+ eexec_encrypt
+ { {end mark currentfile closefile} wol () wl
+ eexecfilter dup flushfile closefile % psfile is eexecfilter
+ binary_CharStrings not { hexfilter dup flushfile closefile } if
+ /psfile realpsfile store
+ 8
+ { (0000000000000000000000000000000000000000000000000000000000000000)
+ wl
+ }
+ repeat {cleartomark} wol
+ }
+ if
+ { FontName currentdict end definefont pop
+ }
+ wol
+ Font /UniqueID known { /exec cvx wo } if
+ binary_tokens { /setobjectformat cvx wo } if
+ ( end) wl % systemdict
+
+ } bind def
+
+% ------ Other utilities ------ %
+
+% Prune garbage characters and OtherSubrs out of the current font,
+% if the relevant dictionaries are writable.
+/prunefont
+ { currentfont /CharStrings get wcheck
+ { currentfont /CharStrings get dup [ exch
+ { pop dup (S????00?) .stringmatch not { pop } if
+ } forall
+ ] { 2 copy undef pop } forall pop
+ }
+ if
+ } bind def
+
+end % wrfont_dict
+
+/writefont { wrfont_dict begin writefont end } def
diff --git a/gs/lib/writecff.ps b/gs/lib/writecff.ps
new file mode 100644
index 000000000..6d7649461
--- /dev/null
+++ b/gs/lib/writecff.ps
@@ -0,0 +1,366 @@
+% Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% writecff.ps
+% Write out a Type 2 font as CFF.
+% **************** THIS FILE DOES NOT WORK. ****************
+% **************** DON'T TRY TO USE IT. ****************
+
+currentglobal true setglobal
+(gs_cff.ps) runlibfile
+setglobal
+
+50 dict begin
+
+% ---------------- Standard strings/names ---------------- %
+
+/FontSetInit /ProcSet findresource begin mark
+
+/StandardSIDs StandardStrings length 1.5 mul cvi dict
+dup 0 1 StandardStrings length 1 sub {
+ % Stack: mark /StdSIDs dict dict index
+ dup StandardStrings exch get exch put dup
+} for pop
+
+end counttomark 2 idiv { def } repeat pop
+
+% ---------------- Standard encodings ---------------- %
+
+% ---------------- Standard Charsets ---------------- %
+
+% ---------------- Output utilities ---------------- %
+
+% Free variables: f (output file), fpos (position in f).
+
+/advance { % <n> advance -
+ fpos add /fpos exch store
+} def
+/next { % <byte> next -
+ f exch write 1 advance
+} def
+/nextstring { % <string|name> nextstring -
+ dup type /nametype eq { .namestring } if
+ f 1 index writestring length advance
+} def
+/card8 % <card8> card8 -
+ /next load
+def
+/card16 { % <card16> card16 -
+ dup -8 bitshift next 255 and next
+} def
+/offset { % <offset> <offsize> offset -
+ 1 sub -1 0 { -8 mul 2 copy bitshift 255 and next pop } for pop
+} def
+/sid % <sid> sid -
+ /card16 load
+def
+/lenoffsize { % <length> lenoffsize <offsize>
+ dup 255 le { pop 1 } { -8 bitshift lenoffsize 1 add } ifelse
+} def
+/Index { % [<string|name|null> ...] Index -
+ % Calculate the maximum offset we need to be able to represent.
+ 1 1 index { dup null eq { pop } { length add } ifelse } forall lenoffsize
+ % stack: items offsize
+ 1 index length card16
+ dup next
+ 1 2 index {
+ % stack: items offsize pos item
+ 1 index 3 index offset
+ dup null eq { pop } { length add } ifelse
+ } forall exch offset { nextstring } forall
+} def
+/idIndex { % <dict> <base> idIndex -
+ 1 index length array 3 -1 roll {
+ 3 index sub 2 index exch 3 -1 roll put
+ } forall exch pop Index
+} def
+/stringid { % <string|name> stringid <sid>
+ StandardSIDs 1 index .knownget {
+ exch pop
+ } {
+ sids 1 index .knownget {
+ exch pop
+ } {
+ StandardSIDs length sids length add sids 3 -1 roll 2 index put
+ } ifelse
+ } ifelse
+} def
+/.valuetypedict mark
+ /booleantype { { 1 } { 0 } ifelse intvalue }
+ /arraytype { { value } forall }
+ /packedarraytype 1 index
+ /stringtype { stringid intvalue }
+ /nametype 1 index
+ /realtype { realvalue }
+ /integertype { intvalue }
+.dicttomark readonly def
+/value { % <obj> value -
+ dup type .valuetypedict exch get exec
+} def
+/.realchardict mark
+ 48 1 57 { dup 48 sub } for % digits
+ 46 10 69 11 101 11 % . E e
+ 45 { % - -- handle E- specially
+ dup 15 and 11 eq { 15 or 12 } {
+ dup 16#bf eq { pop 255 12 } { 14 } ifelse
+ } ifelse
+ }
+.dicttomark readonly def
+/realvalue { % <real> realvalue -
+ =string cvs 255 exch {
+ .realchardict exch get exec
+ 1 index 15 and 15 ne { exch next 255 exch } if
+ 1 index 240 and 240 eq { 4 bitshift 240 } { 15 } ifelse sub add
+ } forall next
+} def
+/intvalue { % <int> intvalue -
+ dup dup -107 ge exch 107 le and { 139 add next } {
+ dup dup -1131 ge exch 0 lt and { neg 16#fa94 add card16 } {
+ dup dup 1131 le exch 0 ge and { 16#f694 add card16 } {
+ dup dup -32768 ge exch 32767 le and {
+ 28 next 65535 and card16
+ } {
+ 29 next dup -16 bitshift 2 { 65535 and card16 } repeat
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/op { % <op> op -
+ dup 32 ge { 12 next 32 sub } if next
+} def
+/vdef { % <obj> <op> vdef -
+ exch value op
+} def
+/nedef { % <obj> <default> <op> nedef -
+ exch 2 index eq { pop pop } { vdef } ifelse
+} def
+/Dict { % <dict> <opsdict> Dict -
+ exch {
+ % stack: opsdict key value
+ 2 index 3 -1 roll .knownget {
+ dup type /integertype eq { vdef } { exec } ifelse
+ } {
+ pop
+ } ifelse
+ } forall pop
+} def
+/collect { % <proc> collect <string>
+ 10 dict begin
+ /str 500 string def
+ /spos 0 def
+ /fpos 0 def
+ /f {
+ pop length spos add /spos exch store
+ spos str length eq { /str str str concatstrings def } if
+ str spos str length spos sub getinterval
+ } /NullEncode filter def
+ exec f closefile
+ str 0 spos getinterval end
+} def
+
+% Write a forward reference in a Dict, and save its position.
+/forward { % <varname> <op> <offsize> forward -
+ {null null <1c 00 00> <1d 00 00 00 00>} exch get nextstring
+ exch fpos store op
+} def
+
+% ------ Top (font) dictionary ------ %
+
+/topkeyops mark
+ /version 0
+ /Notice 1
+ /Copyright 32
+ /FullName 2
+ /FamilyName 3
+ /Weight 4
+ /isFixedPatch { false 33 nedef }
+ /ItalicAngle { 0 34 nedef }
+ /UnderlinePosition { -100 35 nedef }
+ /UnderlineThickness { 50 36 nedef }
+ /PaintType { 0 37 nedef }
+ /CharstringType { 2 38 nedef }
+ /FontMatrix {
+ true 0 1 5 {
+ 2 index 1 index get {0.001 0 0 0.001 0 0} 3 -1 roll get eq and
+ } for
+ { pop } { 39 vdef } ifelse
+ }
+ /UniqueID 13
+ /FontBBox 5
+ /StrokeWidth { 0 40 nedef }
+ /XUID 14
+ /FontInfo { topkeyops Dict }
+ %**** charset, Encoding
+ /CharStrings { pop /charstringsoffset 17 offsetsize forward }
+ /Private { pop /privateoffset 18 offsetsize forward }
+.dicttomark readonly def
+
+% ------ Private dictionary ------ %
+
+/deltarray { % [<num> ...] <op> deltarray -
+ exch 0 exch { 1 index sub dup value add } forall pop op
+} def
+/privatekeyops mark
+ /BlueValues { 6 deltarray }
+ /OtherBlues { 7 deltarray }
+ /FamilyBlues { 8 deltarray }
+ /FamilyOtherBlues { 9 deltarray }
+ /BlueScale { 0.039625 41 nedef }
+ /BlueShift { 7 42 nedef }
+ /BlueFuzz { 1 43 nedef }
+ /StdHW 10
+ /StdVW 11
+ /StemSnapH { 44 deltarray }
+ /StemSnapV { 45 deltarray }
+ /ForceBold { false 46 nedef }
+ /ForceBoldThreshold { 0 47 nedef }
+ % Skip lenIV, it's always -1
+ /LanguageGroup { 0 49 nedef }
+ /ExpansionFactor { 0.06 50 nedef }
+ /initialRandomSeed { 0 51 nedef }
+ /Subrs { pop /subrsoffset 19 2 forward }
+ /defaultWidthX { 0 20 nedef }
+ /nominalWidthX { 0 21 nedef }
+.dicttomark readonly def
+
+% ------ Main program ------ %
+
+/putoffset { % <str> <index> <offset> <offsize> putoffset -
+ % The saved index points just beyond the end of the number,
+ % and we wrote a zero as the placeholder.
+ % Consequently, we don't need the offset size.
+ pop {
+ dup 0 eq { exit } if
+ exch 1 sub exch 3 copy 255 and put -8 bitshift
+ } loop pop pop pop
+} def
+
+/writecff { % <file> [<font> ...] writecff -
+ 30 dict begin
+ % The dictionary for each font contains:
+ % font - the original Type 2 font
+ % subrs - the Local Subrs Index
+ % chars - the CharStrings Index
+ % private - the Private Dict
+ % top - the Top Dict
+ % charspos - the offset of the CharStrings Dict relative to
+ % the start of all CharStrings
+ % privatepos - the offset of the Private Dict relative to
+ % the start of all Private Dicts
+ % subrsoffset - the offset of the Local Subrs offset
+ % reference in the Private Dict
+ % charstringsoffset - the offset of the CharStrings offset
+ % reference in the Top dict
+ % privateoffset - the offset of the Private Dict offset
+ % reference in the Top dict
+ [ exch { 12 dict begin /font exch cvlit def currentdict end } forall ]
+ /fonts exch def
+ /cff exch cvlit def
+
+ /f cff def
+ /fpos 0 def
+
+ % We need to pre-construct all the strings so that we know
+ % the offsets to fill in.
+
+ /names { [ fonts { /font get /FontName get } forall ] Index } collect def
+ /sids 20 dict def
+ /subrslength 0 def % only for estimating size
+ /charslength 0 def
+ /privatelength 0 def
+ fonts {
+ begin
+ font /Private get /Subrs .knownget {
+ { Index } collect
+ } {
+ <00 00>
+ } ifelse /subrs exch def
+ /subrslength subrslength subrs length add def
+ %****** FOLLOWING IS WRONG, WRONG, WRONG ******%
+ font /CharStrings get [ exch { exch pop } forall ] { Index } collect
+ /chars exch def
+ /charspos charslength def
+ /charslength charslength chars length add def
+ /subrsoffset null def
+ font /Private get { privatekeyops Dict } collect /private exch def
+ subrsoffset null ne {
+ private subrsoffset private length 2 putoffset
+ } if
+ /privatepos privatelength def
+ /privatelength privatelength private length add subrs length add def
+ } forall
+ % Estimate the size of a 0-based offset for the Top Dicts.
+ /offsetsize subrslength charslength add privatelength add
+ 60000 ge { 3 } { 2 } ifelse def
+ fonts {
+ begin
+ /charstringsoffset null def
+ /privateoffset null def
+ /top { font topkeyops Dict } collect def
+ end
+ } forall
+ /strings { sids StandardSIDs length idIndex } collect def
+
+ % Now we can write the real file.
+ % Header
+ DEBUG { (header ) print fpos == } if
+ <01 00 04 02> nextstring
+ % Name Index
+ DEBUG { (names ) print fpos == } if
+ names nextstring
+ % Top Dicts
+ DEBUG { (tops ) print fpos == } if
+ /charsbase fpos fonts { /top get length add } forall strings length add def
+ /privatebase charsbase charslength add def
+ fonts {
+ begin
+ top charstringsoffset charspos charsbase add offsetsize putoffset
+ top privateoffset privatepos privatebase add offsetsize putoffset
+ top nextstring
+ end
+ } forall
+ % String Index
+ DEBUG { (strings ) print fpos == } if
+ strings nextstring
+ % Charstrings Indexes
+ DEBUG { (charstrings) print } if
+ /charsbase fpos def
+ fonts {
+ DEBUG { ( ) print fpos =only } if /chars get nextstring
+ } forall
+ DEBUG { () = } if
+ % Private Dicts & Local Subr Indexes
+ DEBUG { (privates/subrs) print } if
+ fonts {
+ DEBUG { ( ) print fpos =only } if dup /private get nextstring
+ DEBUG { ( ) print fpos =only } if /subrs get nextstring
+ } forall
+ DEBUG { () = } if
+
+ DEBUG { (end ) print fpos = flush } if
+ end
+} def
+
+% ---------------- Wrap up ---------------- %
+
+currentdict readonly end
+/writecffdict exch def
+
+/writecff {
+ writecffdict begin writecff end
+} def
diff --git a/gs/lib/zeroline.ps b/gs/lib/zeroline.ps
new file mode 100644
index 000000000..25c9f9323
--- /dev/null
+++ b/gs/lib/zeroline.ps
@@ -0,0 +1,101 @@
+%!
+% Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of Aladdin Ghostscript.
+%
+% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+% or distributor accepts any responsibility for the consequences of using it,
+% or for whether it serves any particular purpose or works at all, unless he
+% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+% License (the "License") for full details.
+%
+% Every copy of Aladdin Ghostscript must include a copy of the License,
+% normally in a plain ASCII text file named PUBLIC. The License grants you
+% the right to copy, modify and redistribute Aladdin Ghostscript, but only
+% under certain conditions described in the License. Among other things, the
+% License requires that the copyright notice and this notice be preserved on
+% all copies.
+
+% zeroline.ps
+% Test file to determine how other PostScript implementations handle
+% filling zero-width lines under a variety of conditions.
+
+% Add a small "fan" of zero-width lines at different angles to the path.
+/fan
+ { currentpoint 100 0 rlineto
+ 2 copy moveto 100 20 rlineto
+ 2 copy moveto 100 100 rlineto
+ 2 copy moveto 20 100 rlineto
+ moveto 0 100 rlineto
+ } def
+
+% Append a rectangle to the current path.
+/rectappend
+ { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto
+ neg 0 rlineto closepath
+ } def
+% Fill a rectangle.
+/rectfill
+ { gsave newpath rectappend fill grestore
+ } def
+% Stroke a rectangle.
+/rectstroke
+ { gsave newpath rectappend stroke grestore
+ } def
+% Clip to a rectangle. Unlike the real rectclip,
+% this clear the current path.
+/rectclip
+ { newpath rectappend clip newpath
+ } def
+
+40 40 translate
+
+% Display fans of different colors on different backgrounds.
+gsave
+0 setgray
+0 0 120 120 rectstroke
+10 10 moveto fan fill
+140 0 translate
+0 setgray
+0 0 120 120 rectstroke
+0.8 setgray
+10 10 moveto fan fill
+140 0 translate
+0 setgray
+0 0 120 120 rectfill
+1 setgray
+10 10 moveto fan fill
+grestore
+0 140 translate
+
+% Display rectangles with two edges coincident.
+gsave
+newpath
+0 setgray
+0 0 40 40 rectappend
+0 0 20 20 rectappend
+eofill
+60 0 translate
+0 0 40 40 rectappend
+40 0 -20 20 rectappend
+fill
+grestore
+0 60 translate
+
+% Display superimposed lines.
+gsave
+/super
+ { currentpoint fan
+ 2 copy moveto 20 0 rmoveto 50 0 rlineto
+ 2 copy moveto 20 4 rmoveto 50 10 rlineto
+ 2 copy moveto 20 20 rmoveto 50 50 rlineto
+ 2 copy moveto 4 20 rmoveto 10 50 rlineto
+ moveto 0 20 rmoveto 0 50 rlineto
+ } def
+0 setgray
+0 0 moveto super fill
+140 0 translate 0 0 moveto super eofill
+grestore
+0 140 translate
+
+showpage
diff --git a/gs/libpng/CHANGES b/gs/libpng/CHANGES
new file mode 100644
index 000000000..11f03a439
--- /dev/null
+++ b/gs/libpng/CHANGES
@@ -0,0 +1,169 @@
+pngchange.txt - changes for libpng
+
+version 0.2
+ added reader into png.h
+ fixed small problems in stub file
+version 0.3
+ added pull reader
+ split up pngwrite.c to several files
+ added pnglib.txt
+ added example.c
+ cleaned up writer, adding a few new tranformations
+ fixed some bugs in writer
+ interfaced with zlib 0.5
+ added K&R support
+ added check for 64 KB blocks for 16 bit machines
+version 0.4
+ cleaned up code and commented code
+ simplified time handling into png_time
+ created png_color_16 and png_color_8 to handle color needs
+ cleaned up color type defines
+ fixed various bugs
+ made various names more consistant
+ interfaced with zlib 0.71
+ cleaned up zTXt reader and writer (using zlib's Reset functions)
+ split transformations into pngrtran.c and pngwtran.c
+version 0.5
+ interfaced with zlib 0.8
+ fixed many reading and writing bugs
+ saved using 3 spaces instead of tabs
+version 0.6
+ added png_large_malloc() and png_large_free()
+ added png_size_t
+ cleaned up some compiler warnings
+ added png_start_read_image()
+version 0.7
+ cleaned up lots of bugs
+ finished dithering and other stuff
+ added test program
+ changed name from pnglib to libpng
+version 0.71 [June, 1995]
+ changed pngtest.png for zlib 0.93
+ fixed error in libpng.txt and example.c
+version 0.8
+ cleaned up some bugs
+ added png_set_filler()
+ split up pngstub.c into pngmem.c, pngio.c, and pngerror.c
+ added #define's to remove unwanted code
+ moved png_info_init() to png.c
+ added old_size into png_realloc()
+ added functions to manually set filtering and compression info
+ changed compression parameters based on image type
+ optimized filter selection code
+ added version info
+ changed external functions passing floats to doubles (k&r problems?)
+ put all the configurable stuff in pngconf.h
+ enabled png_set_shift to work with paletted images on read
+ added png_read_update_info() - updates info structure with
+ transformations
+version 0.81 [August, 1995]
+ incorporated Tim Wegner's medium model code (thanks, Tim)
+version 0.82 [September, 1995]
+ [unspecified changes]
+version 0.85 [December, 1995]
+ added more medium model code (almost everything's a far)
+ added i/o, error, and memory callback functions
+ fixed some bugs (16 bit, 4 bit interlaced, etc.)
+ added first run progressive reader (barely tested)
+version 0.86 [January, 1996]
+ fixed bugs
+ improved documentation
+version 0.87 [January, 1996]
+ fixed medium model bugs
+ fixed other bugs introduced in 0.85 and 0.86
+ added some minor documentation
+version 0.88 [January, 1996]
+ fixed progressive bugs
+ replaced tabs with spaces
+ cleaned up documentation
+ added callbacks for read/write and warning/error functions
+version 0.89 [July, 1996]
+ added new initialization API to make libpng work better with shared libs
+ we now have png_create_read_struct(), png_create_write_struct(),
+ png_create_info_struct(), png_destroy_read_struct(), and
+ png_destroy_write_struct() instead of the separate calls to
+ malloc and png_read_init(), png_info_init(), and png_write_init()
+ changed warning/error callback functions to fix bug - this means you
+ should use the new initialization API if you were using the old
+ png_set_message_fn() calls, and that the old API no longer exists
+ so that people are aware that they need to change their code
+ changed filter selection API to allow selection of multiple filters
+ since it didn't work in previous versions of libpng anyways
+ optimized filter selection code
+ fixed png_set_background() to allow using an arbitrary RGB color for
+ paletted images
+ fixed gamma and background correction for paletted images, so
+ png_correct_palette is not needed unless you are correcting an
+ external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED
+ in pngconf.h) - if nobody uses this, it may disappear in the future.
+ fixed bug with Borland 64K memory allocation (Alexander Lehmann)
+ fixed bug in interlace handling (Smarasderagd, I think)
+ added more error checking for writing and image to reduce invalid files
+ separated read and write functions so that they won't both be linked
+ into a binary when only reading or writing functionality is used
+ new pngtest image also has interlacing and zTXt
+ updated documentation to reflect new API
+version 0.90 [January, 1997]
+ made CRC errors/warnings on critical and ancillary chunks configurable
+ libpng will use the zlib CRC routines by (compile-time) default
+ changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner)
+ added external C++ wrapper statements to png.h (Gilles Dauphin)
+ allow PNG file to be read when some or all of file signature has already
+ been read from the beginning of the stream. ****This affects the size
+ of info_struct and invalidates all programs that use a shared libpng****
+ fixed png_filler() declarations
+ fixed? background color conversions
+ fixed order of error function pointers to match documentation
+ current chunk name is now available in png_struct to reduce the number
+ of nearly identical error messages (will simplify multi-lingual
+ support when available)
+ try to get ready for unknown-chunk callback functions:
+ - previously read critical chunks are flagged, so the chunk handling
+ routines can determine if the chunk is in the right place
+ - all chunk handling routines have the same prototypes, so we will
+ be able to handle all chunks via a callback mechanism
+ try to fix Linux "setjmp" buffer size problems
+version 0.95 [March, 1997]
+ fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never
+ fixed bug in PNG file signature compares when start != 0
+ changed parameter type of png_set_filler(...filler...) from png_byte
+ to png_uint_32
+ added test for MACOS to ensure that both math.h and fp.h are not #included
+ added macros for libpng to be compiled as a Windows DLL (Andreas Kupries)
+ added "packswap" transformation, which changes the endianness of
+ packed-pixel bytes (Kevin Bracey)
+ added "strip_alpha" transformation, which removes the alpha channel of
+ input images without using it (not neccesarily a good idea)
+ added "swap_alpha" transformation, which puts the alpha channel in front
+ of the color bytes instead of after
+ removed all implicit variable tests which assume NULL == 0 (I think)
+ changed several variables to "png_size_t" to show 16/32-bit limitations
+ added new pCAL chunk read/write support
+ added experimental filter selection weighting (Greg Roelofs)
+ removed old png_set_rgbx() and png_set_xrgb() functions that have been
+ obsolete for about 2 years now (use png_set_filler() instead)
+ added macros to read 16- and 32-bit ints directly from buffer, to be
+ used only on those systems that support it (namely PowerPC and 680x0)
+ With some testing, this may become the default for MACOS/PPC systems.
+ only calculate CRC on data if we are going to use it
+ added macros for zTXt compression type PNG_zTXt_COMPRESSION_???
+ added macros for simple libpng debugging output selectable at compile time
+ removed PNG_READ_END_MODE in progressive reader (Smarasderagd)
+ more description of info_struct in libpng.txt and png.h
+ more instructions in example.c
+ more chunk types tested in pngtest.c
+ renamed pngrcb.c to pngset.c, and all png_read_<chunk> functions to be
+ png_set_<chunk>. We now have corresponding png_get_<chunk>
+ functions in pngget.c to get infomation in info_ptr. This isolates
+ the application from the internal organization of png_info_struct
+ (good for shared library implementations).
+version 0.96 [May, 1997]
+ fixed serious bug with < 8bpp images introduced in 0.95
+ fixed 256-color transparency bug (Greg Roelofs)
+ fixed up documentation (Greg Roelofs, Laszlo Nyul)
+ fixed "error" in pngconf.h for Linux setjmp() behaviour
+ fixed DOS medium model support (Tim Wegner)
+ fixed png_check_keyword() for case with error in static string text
+ added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul)
+ added typecasts to quiet compiler errors
+ added more debugging info
diff --git a/gs/libpng/README b/gs/libpng/README
new file mode 100644
index 000000000..9147674e0
--- /dev/null
+++ b/gs/libpng/README
@@ -0,0 +1,166 @@
+README for libpng 0.96
+
+This is the sixth (and hopefully last) beta release of libpng 1.0.
+The changes from libpng-0.90 include bug fixes, a C++ wrapper for
+png.h, some additions to the API, as well as internal changes to
+the library. See "CHANGES" for a detailed list of differences.
+
+****
+Note that some of the changes to the png_info structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library. The type of the
+"filler" parameter for png_set_filler() has changed from png_byte to
+png_uint_32, which will affect shared-library applications which use
+this function.
+
+To avoid problems with changes to the internals of png_info_struct,
+new APIs have been made available in 0.95 to avoid direct application
+access to info_ptr. These functions are the png_set_<chunk> and
+png_get_<chunk> functions. These functions should be used when
+accessing/storing the info_struct data, rather than manipulating it
+directly, to avoid such problems in the future.
+****
+
+Additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the info struct.
+Experimental functions include the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16->8 bit color
+conversion.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application. This also allows the reading of embedded PNG streams that
+do not have the PNG file signature. As well, it is now possible to set
+the library action on the detection of chunk CRC errors. It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The changes made to the library, and bugs fixed are based on discussions
+on the PNG implementation mailing list <png-implement@dworking.wustl.edu>
+and not on material submitted to Guy.
+
+For a detailed description on using libpng, read libpng.txt. For
+examples of libpng in a program, see example.c and pngtest.c. For usage
+information and restrictions (what little they are) on libpng, see
+png.h. For a description on using zlib (the compression library used by
+libpng) and zlib's restrictions, see zlib.h
+
+I have included a general makefile, as well as several machine and
+compiler specific ones, but you may have to modify one for your own needs.
+
+You should use zlib 1.0.4 or later to run this, but it MAY work with
+versions as old as zlib 0.95. Even so, there are bugs in older zlib
+versions which can cause the output of invalid compression streams for
+some images. You will definitely need zlib 1.0.4 or later if you are
+taking advantage of the MS-DOS "far" structure allocation for the small
+and medium memory models. You should also note that zlib is a
+compression library that is useful for more things than just PNG files.
+You can use zlib as a drop-in replacement for fread() and fwrite() if
+you are so inclined.
+
+zlib should be available at the same place that libpng is.
+If not, it should be at ftp.uu.net in /graphics/png
+Eventually, it will be at ftp.uu.net in /pub/archiving/zip/zlib
+
+You may also want a copy of the PNG specification. It is available
+as an Internet Draft, and RFC, and a W3C Recommendation. Failing
+these resources you can try ftp.uu.net in the /graphics/png directory.
+
+This code is currently being archived at ftp.uu.net in the
+/graphics/png directory, and on CompuServe, Lib 20 (PNG SUPPORT)
+at GO GRAPHSUP. If you can't find it in any of those places,
+e-mail me, and I'll help you find it.
+
+If you have any code changes, requests, problems, etc., please e-mail
+them to me. Also, I'd appreciate any make files or project files,
+and any modifications you needed to make to get libpng to compile,
+along with a #define variable to tell what compiler/system you are on.
+If you needed to add transformations to libpng, or wish libpng would
+provide the image in a different way, drop me a note (and code, if
+possible), so I can consider supporting the transformation.
+Finally, if you get any warning messages when compiling libpng
+(note: not zlib), and they are easy to fix, I'd appreciate the
+fix. Please mention "libpng" somewhere in the subject line. Thanks.
+
+This release was created and will be supported by myself (of course
+based in a large way on Guy's earlier work), and the PNG group.
+
+adilger@enel.ucalgary.ca
+png-implement@dworkin.wustl.edu
+
+You can reach Guy, the original libpng author, at (internet preferred):
+
+internet: schalnat@group42.com
+CompuServe: 75501,1625
+
+Please do not send general questions about PNG. Send them to
+the address in the specification. At the same time, please do
+not send libpng questions to that address, send them to me. I'll
+get them in the end anyway. If you have a question about something
+in the PNG specification that is related to using libpng, send it
+to me. Send me any questions that start with "I was using libpng,
+and ...". If in doubt, send questions to me. I'll bounce them
+to others, if necessary.
+
+Please do not send suggestions on how to change PNG. We have
+been discussing PNG for a couple years now, and it is official and
+finished. If you have suggestions for libpng, however, I'll
+gladly listen. Even if your suggestion is not used for version
+1.0, it may be used later.
+
+Files in this distribution:
+
+ CHANGES => Description of changes between libpng versions
+ README => This file
+ TODO => Things not implemented in the current library
+ ansi2knr.c => Converts files to K&R style function declarations
+ build.bat => MS-DOS batch file for Borland compiler
+ descrip.mms => VMS project file
+ example.c => Example code for using libpng functions
+ libpng.txt => Description of libpng and its functions
+ makefile => Default Unixish makefile
+ makefile.aco => ACORN makefile
+ makefile.ama => Amiga makefile
+ makefile.atr => Atari makefile
+ makefile.bor => Borland makefile
+ makefile.dj2 => DJGPP 2 makefile
+ makefile.elf => Unix ELF makefile
+ makefile.knr => Makefile which calls ansi2knr to convert files
+ makefile.mip => MIPS makefile
+ makefile.msc => Microsoft C makefile
+ makefile.std => Standard Unix makefile
+ makefile.tc => Turbo C makefile
+ makevms.com => VMS make program
+ png.c => Basic interface functions common to library
+ png.h => Library function and interface declarations
+ pngconf.h => System specific library configuration
+ pngerror.c => Error/warning message I/O functions
+ pngmem.c => Memory handling functions
+ pngpread.c => Progressive reading functions
+ pngread.c => Read data/helper high-level functions
+ pngrio.c => Lowest-level data read I/O functions
+ pngrtran.c => Read data transformation functions
+ pngrutil.c => Read data utility functions
+ pngset.c => Functions for storing data into the info_struct
+ pngtest.c => Library test program
+ pngtest.png => Library test sample image
+ pngtrans.c => Common data transformation functions
+ pngwio.c => Lowest-level write I/O functions
+ pngwrite.c => High-level write functions
+ pngwtran.c => Write data transformations
+ pngwutil.c => Write utility functions
+
+Good luck, and happy coding.
+
+-Andreas Eric Dilger
+ Internet: adilger@enel.ucalgary.ca
+ Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/
+
+-Guy Eric Schalnat
+ Group 42, Inc.
+ Internet: schalnat@group42.com
+ CompuServe: 75501,1625
+ Web: http://www.group42.com/
+
diff --git a/gs/libpng/TODO b/gs/libpng/TODO
new file mode 100644
index 000000000..605e591c7
--- /dev/null
+++ b/gs/libpng/TODO
@@ -0,0 +1,19 @@
+pngtodo.txt - list of things to do for libpng
+
+add "grayscale->palette" transformation and "palette->grayscale" detection
+improved dithering
+multi-lingual error and warning message support
+cHRM transformation
+sRGB chunk handling
+man pages for function calls
+high-level API for reading images
+final bug fixes
+better documentation
+better filter selection
+ (counting huffman bits/precompression? filter inertia? filter costs?)
+optional palette creation
+histogram creation
+support for application-defined chunk handlers
+keep up with public chunks
+better C++ wrapper/full C++ implementation?
+text conversion between different code pages (Latin-1 -> Mac and DOS)
diff --git a/gs/libpng/ansi2knr.c b/gs/libpng/ansi2knr.c
new file mode 100644
index 000000000..392421543
--- /dev/null
+++ b/gs/libpng/ansi2knr.c
@@ -0,0 +1,488 @@
+/* Copyright (C) 1989, 1991, 1993 Aladdin Enterprises. All rights reserved. */
+
+/* ansi2knr.c */
+/* Convert ANSI function declarations to K&R syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+to anyone for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing. Refer
+to the GNU General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+ansi2knr, but only under the conditions described in the GNU
+General Public License. A copy of this license is supposed to have been
+given to you along with ansi2knr so you can know your rights and
+responsibilities. It should be in a file named COPYING. Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
+*/
+
+/*
+---------- Here is the GNU GPL file COPYING, referred to above ----------
+----- These terms do NOT apply to the JPEG software itself; see README ------
+
+ GHOSTSCRIPT GENERAL PUBLIC LICENSE
+ (Clarified 11 Feb 1988)
+
+ Copyright (C) 1988 Richard M. Stallman
+ Everyone is permitted to copy and distribute verbatim copies of this
+ license, but changing it is not allowed. You can also use this wording
+ to make the terms for other programs.
+
+ The license agreements of most software companies keep you at the
+mercy of those companies. By contrast, our general public license is
+intended to give everyone the right to share Ghostscript. To make sure
+that you get the rights we want you to have, we need to make
+restrictions that forbid anyone to deny you these rights or to ask you
+to surrender the rights. Hence this license agreement.
+
+ Specifically, we want to make sure that you have the right to give
+away copies of Ghostscript, that you receive source code or else can get
+it if you want it, that you can change Ghostscript or use pieces of it
+in new free programs, and that you know you can do these things.
+
+ To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute
+copies of Ghostscript, 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 tell them their rights.
+
+ Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for Ghostscript. If Ghostscript is
+modified by someone else and passed on, we want its recipients to know
+that what they have is not what we distributed, so that any problems
+introduced by others will not reflect on our reputation.
+
+ Therefore we (Richard M. Stallman and the Free Software Foundation,
+Inc.) make the following terms which say what you must do to be allowed
+to distribute or change Ghostscript.
+
+
+ COPYING POLICIES
+
+ 1. You may copy and distribute verbatim copies of Ghostscript source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy a valid copyright and license
+notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
+Distributed by Free Software Foundation, Inc." (or with whatever year is
+appropriate); keep intact the notices on all files that refer to this
+License Agreement and to the absence of any warranty; and give any other
+recipients of the Ghostscript program a copy of this License Agreement
+along with the program. You may charge a distribution fee for the
+physical act of transferring a copy.
+
+ 2. You may modify your copy or copies of Ghostscript or any portion of
+it, and copy and distribute such modifications under the terms of
+Paragraph 1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish,
+ that in whole or in part contains or is a derivative of Ghostscript
+ or any part thereof, to be licensed at no charge to all third
+ parties on terms identical to those contained in this License
+ Agreement (except that you may choose to grant more extensive
+ warranty protection to some or all third parties, at your option).
+
+ c) You may charge a distribution fee for the physical act of
+ transferring a copy, and you may at your option offer warranty
+ protection in exchange for a fee.
+
+Mere aggregation of another unrelated program with this program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other program under the scope of these terms.
+
+ 3. You may copy and distribute Ghostscript (or a portion or derivative
+of it, under Paragraph 2) in object code or executable form under the
+terms of Paragraphs 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
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal
+ shipping charge) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+For an executable file, complete source code means all the source code for
+all modules it contains; but, as a special exception, it need not include
+source code for modules which are standard libraries that accompany the
+operating system on which the executable file runs.
+
+ 4. You may not copy, sublicense, distribute or transfer Ghostscript
+except as expressly provided under this License Agreement. Any attempt
+otherwise to copy, sublicense, distribute or transfer Ghostscript is
+void and your rights to use the program under this License agreement
+shall be automatically terminated. However, parties who have received
+computer software programs from you with this License Agreement will not
+have their licenses terminated so long as such parties remain in full
+compliance.
+
+ 5. If you wish to incorporate parts of Ghostscript into other free
+programs whose distribution conditions are different, write to the Free
+Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not
+yet worked out a simple rule that can be stated here, but we will often
+permit this. We 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.
+
+Your comments and suggestions about our licensing policies and our
+software are welcome! Please contact the Free Software Foundation,
+Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296.
+
+ NO WARRANTY
+
+ BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
+WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD
+M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES
+PROVIDE GHOSTSCRIPT "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 GHOSTSCRIPT IS WITH
+YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN
+ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE
+GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
+ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU
+HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM
+BY ANY OTHER PARTY.
+
+-------------------- End of file COPYING ------------------------------
+*/
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef BSD
+#include <strings.h>
+#else
+#ifdef VMS
+ extern int strlen(), strncmp();
+#else
+#include <string.h>
+#endif
+#endif
+
+/* malloc and free should be declared in stdlib.h, */
+/* but if you've got a K&R compiler, they probably aren't. */
+#ifdef MSDOS
+#include <malloc.h>
+#else
+#ifdef VMS
+ extern char *malloc();
+ extern void free();
+#else
+ extern char *malloc();
+ extern int free();
+#endif
+#endif
+
+/* Usage:
+ ansi2knr input_file [output_file]
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes functions by seeing a non-keyword identifier
+ * at the left margin, followed by a left parenthesis,
+ * with a right parenthesis as the last character on the line.
+ * It will recognize a multi-line header provided that the last character
+ * of the last line of the header is a right parenthesis,
+ * and no intervening line ends with a left brace or a semicolon.
+ * These algorithms ignore whitespace and comments, except that
+ * the function name must be the first thing on the line.
+ * The following constructs will confuse it:
+ * - Any other construct that starts at the left margin and
+ * follows the above syntax (such as a macro or function call).
+ * - Macros that tinker with the syntax of the function header.
+ */
+
+/* Scanning macros */
+#define isidchar(ch) (isalnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *skipspace();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+main(argc, argv)
+ int argc;
+ char *argv[];
+{ FILE *in, *out;
+#define bufsize 5000 /* arbitrary size */
+ char *buf;
+ char *line;
+ switch ( argc )
+ {
+ default:
+ printf("Usage: ansi2knr input_file [output_file]\n");
+ exit(0);
+ case 2:
+ out = stdout; break;
+ case 3:
+ out = fopen(argv[2], "w");
+ if ( out == NULL )
+ { fprintf(stderr, "Cannot open %s\n", argv[2]);
+ exit(1);
+ }
+ }
+ in = fopen(argv[1], "r");
+ if ( in == NULL )
+ { fprintf(stderr, "Cannot open %s\n", argv[1]);
+ exit(1);
+ }
+ fprintf(out, "#line 1 \"%s\"\n", argv[1]);
+ buf = malloc(bufsize);
+ line = buf;
+ while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+ { switch ( test1(buf) )
+ {
+ case 1: /* a function */
+ convert1(buf, out);
+ break;
+ case -1: /* maybe the start of a function */
+ line = buf + strlen(buf);
+ if ( line != buf + (bufsize - 1) ) /* overflow check */
+ continue;
+ /* falls through */
+ default: /* not a function */
+ fputs(buf, out);
+ break;
+ }
+ line = buf;
+ }
+ if ( line != buf ) fputs(buf, out);
+ free(buf);
+ fclose(out);
+ fclose(in);
+ return 0;
+}
+
+/* Skip over space and comments, in either direction. */
+char *
+skipspace(p, dir)
+ register char *p;
+ register int dir; /* 1 for forward, -1 for backward */
+{ for ( ; ; )
+ { while ( isspace(*p) ) p += dir;
+ if ( !(*p == '/' && p[dir] == '*') ) break;
+ p += dir; p += dir;
+ while ( !(*p == '*' && p[dir] == '/') )
+ { if ( *p == 0 ) return p; /* multi-line comment?? */
+ p += dir;
+ }
+ p += dir; p += dir;
+ }
+ return p;
+}
+
+/*
+ * Write blanks over part of a string.
+ */
+int
+writeblanks(start, end)
+ char *start;
+ char *end;
+{ char *p;
+ for ( p = start; p < end; p++ ) *p = ' ';
+ return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ * 0 - definitely not a function definition;
+ * 1 - definitely a function definition;
+ * -1 - may be the beginning of a function definition,
+ * append another line and look again.
+ */
+int
+test1(buf)
+ char *buf;
+{ register char *p = buf;
+ char *bend;
+ char *endfn;
+ int contin;
+ if ( !isidfirstchar(*p) )
+ return 0; /* no name at left margin */
+ bend = skipspace(buf + strlen(buf) - 1, -1);
+ switch ( *bend )
+ {
+ case ')': contin = 1; break;
+ case '{':
+ case ';': return 0; /* not a function */
+ default: contin = -1;
+ }
+ while ( isidchar(*p) ) p++;
+ endfn = p;
+ p = skipspace(p, 1);
+ if ( *p++ != '(' )
+ return 0; /* not a function */
+ p = skipspace(p, 1);
+ if ( *p == ')' )
+ return 0; /* no parameters */
+ /* Check that the apparent function name isn't a keyword. */
+ /* We only need to check for keywords that could be followed */
+ /* by a left parenthesis (which, unfortunately, is most of them). */
+ { static char *words[] =
+ { "asm", "auto", "case", "char", "const", "double",
+ "extern", "float", "for", "if", "int", "long",
+ "register", "return", "short", "signed", "sizeof",
+ "static", "switch", "typedef", "unsigned",
+ "void", "volatile", "while", 0
+ };
+ char **key = words;
+ char *kp;
+ int len = endfn - buf;
+ while ( (kp = *key) != 0 )
+ { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+ return 0; /* name is a keyword */
+ key++;
+ }
+ }
+ return contin;
+}
+
+int
+convert1(buf, out)
+ char *buf;
+ FILE *out;
+{ char *endfn;
+ register char *p;
+ char **breaks;
+ unsigned num_breaks = 2; /* for testing */
+ char **btop;
+ char **bp;
+ char **ap;
+ /* Pre-ANSI implementations don't agree on whether strchr */
+ /* is called strchr or index, so we open-code it here. */
+ for ( endfn = buf; *(endfn++) != '('; ) ;
+top: p = endfn;
+ breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+ if ( breaks == 0 )
+ { /* Couldn't allocate break table, give up */
+ fprintf(stderr, "Unable to allocate break table!\n");
+ fputs(buf, out);
+ return -1;
+ }
+ btop = breaks + num_breaks * 2 - 2;
+ bp = breaks;
+ /* Parse the argument list */
+ do
+ { int level = 0;
+ char *end = NULL;
+ if ( bp >= btop )
+ { /* Filled up break table. */
+ /* Allocate a bigger one and start over. */
+ free((char *)breaks);
+ num_breaks <<= 1;
+ goto top;
+ }
+ *bp++ = p;
+ /* Find the end of the argument */
+ for ( ; end == NULL; p++ )
+ { switch(*p)
+ {
+ case ',': if ( !level ) end = p; break;
+ case '(': level++; break;
+ case ')': if ( --level < 0 ) end = p; break;
+ case '/': p = skipspace(p, 1) - 1; break;
+ default: ;
+ }
+ }
+ p--; /* back up over terminator */
+ /* Find the name being declared. */
+ /* This is complicated because of procedure and */
+ /* array modifiers. */
+ for ( ; ; )
+ { p = skipspace(p - 1, -1);
+ switch ( *p )
+ {
+ case ']': /* skip array dimension(s) */
+ case ')': /* skip procedure args OR name */
+ { int level = 1;
+ while ( level )
+ switch ( *--p )
+ {
+ case ']': case ')': level++; break;
+ case '[': case '(': level--; break;
+ case '/': p = skipspace(p, -1) + 1; break;
+ default: ;
+ }
+ }
+ if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+ { /* We found the name being declared */
+ while ( !isidfirstchar(*p) )
+ p = skipspace(p, 1) + 1;
+ goto found;
+ }
+ break;
+ default: goto found;
+ }
+ }
+found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+ { p++;
+ if ( bp == breaks + 1 ) /* sole argument */
+ writeblanks(breaks[0], p);
+ else
+ writeblanks(bp[-1] - 1, p);
+ bp--;
+ }
+ else
+ { while ( isidchar(*p) ) p--;
+ *bp++ = p+1;
+ }
+ p = end;
+ }
+ while ( *p++ == ',' );
+ *bp = p;
+ /* Make a special check for 'void' arglist */
+ if ( bp == breaks+2 )
+ { p = skipspace(breaks[0], 1);
+ if ( !strncmp(p, "void", 4) )
+ { p = skipspace(p+4, 1);
+ if ( p == breaks[2] - 1 )
+ { bp = breaks; /* yup, pretend arglist is empty */
+ writeblanks(breaks[0], p + 1);
+ }
+ }
+ }
+ /* Put out the function name */
+ p = buf;
+ while ( p != endfn ) putc(*p, out), p++;
+ /* Put out the declaration */
+ for ( ap = breaks+1; ap < bp; ap += 2 )
+ { p = *ap;
+ while ( isidchar(*p) ) putc(*p, out), p++;
+ if ( ap < bp - 1 ) fputs(", ", out);
+ }
+ fputs(") ", out);
+ /* Put out the argument declarations */
+ for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';';
+ fputs(breaks[0], out);
+ free((char *)breaks);
+ return 0;
+}
diff --git a/gs/libpng/build.bat b/gs/libpng/build.bat
new file mode 100644
index 000000000..ec34b6f03
--- /dev/null
+++ b/gs/libpng/build.bat
@@ -0,0 +1,2 @@
+make -fmakefile.bor -B -DMODEL=m %1 %2 %3 libpng >buildm.out
+make -fmakefile.bor -B -DMODEL=l %1 %2 %3 libpng >buildl.out
diff --git a/gs/libpng/descrip.mms b/gs/libpng/descrip.mms
new file mode 100644
index 000000000..3584b0d78
--- /dev/null
+++ b/gs/libpng/descrip.mms
@@ -0,0 +1,52 @@
+
+cc_defs = /inc=$(ZLIBSRC)
+c_deb =
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+
+
+OBJS = png.obj, pngset.obj, pngget.obj, pngrutil.obj, pngtrans.obj,\
+ pngwutil.obj, pngread.obj, pngmem.obj, pngwrite.obj, pngrtran.obj,\
+ pngwtran.obj, pngrio.obj, pngwio.obj, pngerror.obj, pngpread.obj
+
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : pngtest.exe libpng.olb
+ @ write sys$output " pngtest available"
+
+libpng.olb : libpng.olb($(OBJS))
+ @ write sys$output " Libpng available"
+
+
+pngtest.exe : pngtest.obj libpng.olb
+ link pngtest,libpng.olb/lib,$(ZLIBSRC)libz.olb/lib
+
+test : pngtest.exe
+ run pngtest
+
+clean :
+ delete *.obj;*,*.exe;*
+
+
+# Other dependencies.
+png.obj : png.h, pngconf.h
+pngpread.obj : png.h, pngconf.h
+pngset.obj : png.h, pngconf.h
+pngget.obj : png.h, pngconf.h
+pngread.obj : png.h, pngconf.h
+pngrtran.obj : png.h, pngconf.h
+pngrutil.obj : png.h, pngconf.h
+pngerror.obj : png.h, pngconf.h
+pngmem.obj : png.h, pngconf.h
+pngrio.obj : png.h, pngconf.h
+pngwio.obj : png.h, pngconf.h
+pngtest.obj : png.h, pngconf.h
+pngtrans.obj : png.h, pngconf.h
+pngwrite.obj : png.h, pngconf.h
+pngwtran.obj : png.h, pngconf.h
+pngwutil.obj : png.h, pngconf.h
+
diff --git a/gs/libpng/example.c b/gs/libpng/example.c
new file mode 100644
index 000000000..20510adb2
--- /dev/null
+++ b/gs/libpng/example.c
@@ -0,0 +1,667 @@
+/* example.c - an example of using libpng */
+
+/* This is an example of how to use libpng to read and write PNG files.
+ The file libpng.txt is much more verbose then this. If you have not
+ read it, do so first. This was designed to be a starting point of an
+ implementation. This is not officially part of libpng, and therefore
+ does not require a copyright notice.
+
+ This file does not currently compile, because it is missing certain
+ parts, like allocating memory to hold an image. You will have to
+ supply these parts to get it to compile. For an example of a minimal
+ working PNG reader/writer, see pngtest.c, included in this distribution.
+*/
+
+#include <png.h>
+
+/* Check to see if a file is a PNG file using png_check_sig(). Returns
+ non-zero if the image is a PNG, and 0 if it isn't a PNG.
+
+ If this call is successful, and you are going to keep the file open,
+ you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
+ you have created the png_ptr, so that libpng knows your application
+ has read that many bytes from the start of the file. Make sure you
+ don't call png_set_sig_bytes() with more than 8 bytes read or give it
+ an incorrect number of bytes read, or you will either have read too
+ many bytes (your fault), or you are telling libpng to read the wrong
+ number of magic bytes (also your fault).
+
+ Many applications already read the first 2 or 4 bytes from the start
+ of the image to determine the file type, so it would be easiest just
+ to pass the bytes to png_check_sig() or even skip that if you know
+ you have a PNG file, and call png_set_sig_bytes().
+*/
+#define PNG_BYTES_TO_CHECK 4
+int check_if_png(char *file_name, FILE **fp)
+{
+ char buf[PNG_BYTES_TO_CHECK];
+
+ /* Open the prospective PNG file. */
+ if ((*fp = fopen(file_name, "rb")) != NULL);
+ return 0;
+
+ /* Read in the signature bytes */
+ if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
+ return 0;
+
+ /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */
+ return(png_check_sig(buf, PNG_BYTES_TO_CHECK));
+}
+
+/* Read a PNG file. You may want to return an error code if the read
+ fails (depending upon the failure). There are two "prototypes" given
+ here - one where we are given the filename, and we need to open the
+ file, and the other where we are given an open file (possibly with
+ some or all of the magic bytes read - see comments above). */
+**** prototype 1 ****
+void read_png(char *file_name) /* We need to open the file */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned int sig_read = 0;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ FILE *fp;
+
+ if ((fp = fopen(file_name, "rb")) == NULL)
+ return;
+**** prototype 2 ****
+void read_png(FILE *fp, unsigned int sig_read) /* file is already open */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+**** only use one prototype! ****
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also supply the
+ * the compiler header file version, so that we know if the application
+ * was compiled with a compatible version of the library. REQUIRED
+ */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return;
+ }
+
+ /* Allocate/initialize the memory for image information. REQUIRED. */
+ info_ptr = png_create_info_struct();
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return;
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fp);
+ /* If we get here, we had a problem reading the file */
+ return;
+ }
+
+ /* One of the following I/O initialization methods is REQUIRED */
+**** PNG file I/O method 1 ****
+ /* Set up the input control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+
+**** PNG file I/O method 2 ****
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call */
+ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+**** Use only one I/O method! ****
+
+ /* If we have already read some of the signature */
+ png_set_sig_bytes_read(png_ptr, sig_read);
+
+ /* The call to png_read_info() gives us all of the information from the
+ * PNG file before the first IDAT (image data chunk). REQUIRED
+ */
+ png_read_info(png_ptr, info_ptr);
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+/**** Set up the data transformations you want. Note that these are all
+ **** optional. Only call them if you want/need them. Many of the
+ **** transformations only work on specific types of images, and many
+ **** are mutually exclusive.
+ ****/
+
+ /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+ png_set_strip_16(png_ptr);
+
+ /* strip alpha bytes from the input data without combining with th
+ * background (not recommended) */
+ png_set_strip_alpha(png_ptr);
+
+ /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ png_set_packing(png_ptr);
+
+ /* change the order of packed pixels to least significant bit first
+ * (not useful if you are using png_set_packing). */
+ png_set_packswap(png_ptr);
+
+ /* expand paletted colors into true RGB triplets */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+
+ /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ /* expand paletted or RGB images with transparency to full alpha channels
+ * so the data will be available as RGBA quartets */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+
+ /* Set the background color to draw transparent and alpha images over.
+ * It is possible to set the red, green, and blue components directly
+ * for paletted images instead of supplying a palette index. Note that
+ * even if the PNG file supplies a background, you are not required to
+ * use it - you should use the (solid) application background if it has one.
+ */
+
+ png_color_16 my_background, *image_background);
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background);
+ png_set_background(png_ptr, image_background),
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+ /* Some suggestions as to how to get a screen gamma value */
+ if (/* We have a user-defined screen gamma value */)
+ {
+ screen_gamma = user-defined screen_gamma;
+ }
+ /* This is one way that applications share the same screen gamma value */
+ else if ((gamma_str = getenv("DISPLAY_GAMMA")) != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for PC monitors */
+ screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */
+ }
+
+ /* Tell libpng to handle the gamma conversion for you. The second call
+ * is a good guess for PC generated images, but it should be configurable
+ * by the user at run time by the user. It is strongly suggested that
+ * your application support gamma correction.
+ */
+ if (png_get_gAMA(png_ptr, info_ptr, &image_gamma);
+ png_set_gamma(png_ptr, screen_gamma, image_gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45);
+
+ /* Dither RGB files down to 8 bit palette or reduce palettes
+ to the number of colors available on your screen */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_uint_32 num_palette;
+ png_colorp palette;
+
+ /* This reduces the image to the application supplied palette */
+ if (we have our own palette)
+ {
+ /* An array of colors to which the image should be dithered */
+ png_color std_color_cube[MAX_SCREEN_COLORS];
+
+ png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
+ MAX_SCREEN_COLORS, NULL, 0);
+ }
+ /* This reduces the image to the palette supplied in the file */
+ else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)))
+ {
+ png_color16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr, &histogram);
+
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 0);
+ }
+ }
+
+ /* invert monocrome files to have 0 as white and 1 as black */
+ png_set_invert(png_ptr);
+
+ /* If you want to shift the pixel values from the range [0,255] or
+ * [0,65535] to the original [0,7] or [0,31], or whatever range the
+ * colors were originally in:
+ */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+ {
+ png_color8p sig_bit;
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_shift(png_ptr, sig_bit);
+ }
+
+ /* flip the RGB pixels to BGR (or RGBA to BGRA) */
+ png_set_bgr(png_ptr);
+
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ png_set_swap_alpha(png_ptr);
+
+ /* swap bytes of 16 bit files to least significant byte first */
+ png_set_swap(png_ptr);
+
+ /* Add filler (or alpha) byte (before/after each RGB triplet) */
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ /* Turn on interlace handling. REQUIRED if you are not using
+ * png_read_image(). To see how to handle interlacing passes,
+ * see the png_read_row() method below.
+ */
+ number_passes = png_set_interlace_handling(png_ptr);
+
+ /* optional call to gamma correct and add the background to the palette
+ * and update info structure. REQUIRED if you are expecting libpng to
+ * update the palette for you (ie you selected such a transform above).
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* allocate the memory to hold the image using the fields of info_ptr. */
+
+ /* the easiest way to read the image */
+ png_bytep row_pointers[height];
+
+ for (row = 0; row < height; row++)
+ {
+ row_pointers[row] = malloc(png_get_rowbytes(png_ptr, info_ptr));
+ }
+
+ /* Now it's time to read the image. One of these methods is REQUIRED */
+**** Read the entire image in one go ****
+ png_read_image(png_ptr, row_pointers);
+
+**** Read the image one or more scanlines at a time ****
+ /* the other way to read images - deal with interlacing */
+
+ for (pass = 0; pass < number_passes; pass++)
+ {
+[[[[[[[ Read the image a single row at a time ]]]]]]]
+ for (y = 0; y < height; y++)
+ {
+ png_bytep row_pointers = row[y];
+ png_read_rows(png_ptr, &row_pointers, NULL, 1);
+ }
+
+[[[[[[[ Read the image several rows at a time ]]]]]]]
+ for (y = 0; y < height; y += number_of_rows)
+ {
+<<<<<<<<<< Read the image using the "sparkle" effect. >>>>>>>>>>
+ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+
+<<<<<<<<<< Read the image using the "rectangle" effect >>>>>>>>>>
+ png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
+<<<<<<<<<< use only one of these two methods >>>>>>>>>>
+ }
+
+ /* if you want to display the image after every pass, do
+ so here */
+[[[[[[[ use only one of these two methods ]]]]]]]
+ }
+**** use only one of these two methods ****
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+
+ /* clean up after the read, and free any memory allocated - REQUIRED */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
+/* progressively read a file */
+
+int
+initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
+{
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible in case we are using dynamically
+ * linked libraries.
+ */
+ *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (*png_ptr == NULL)
+ {
+ *info_ptr = NULL;
+ return ERROR;
+ }
+
+ *info_ptr = png_create_info_struct(png_ptr);
+
+ if (*info_ptr == NULL)
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ if (setjmp((*png_ptr)->jmpbuf))
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ /* this one's new. You will need to provide all three
+ * function callbacks, even if you aren't using them all.
+ * These functions shouldn't be dependent on global or
+ * static variables if you are decoding several images
+ * simultaneously. You should store stream specific data
+ * in a separate struct, given as the second parameter,
+ * and retrieve the pointer from inside the callbacks using
+ * the function png_get_progressive_ptr(png_ptr).
+ */
+ png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
+ info_callback, row_callback, end_callback);
+
+ return OK;
+}
+
+int
+process_data(png_structp *png_ptr, png_infop *info_ptr,
+ png_bytep buffer, png_uint_32 length)
+{
+ if (setjmp((*png_ptr)->jmpbuf))
+ {
+ /* Free the png_ptr and info_ptr memory on error */
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ /* This one's new also. Simply give it chunks of data as
+ * they arrive from the data stream (in order, of course).
+ * On Segmented machines, don't give it any more than 64K.
+ * The library seems to run fine with sizes of 4K, although
+ * you can give it much less if necessary (I assume you can
+ * give it chunks of 1 byte, but I haven't tried with less
+ * than 256 bytes yet). When this function returns, you may
+ * want to display any rows that were generated in the row
+ * callback, if you aren't already displaying them there.
+ */
+ png_process_data(*png_ptr, *info_ptr, buffer, length);
+ return OK;
+}
+
+info_callback(png_structp png_ptr, png_infop info)
+{
+/* do any setup here, including setting any of the transformations
+ * mentioned in the Reading PNG files section. For now, you _must_
+ * call either png_start_read_image() or png_read_update_info()
+ * after all the transformations are set (even if you don't set
+ * any). You may start getting rows before png_process_data()
+ * returns, so this is your last chance to prepare for that.
+ */
+}
+
+row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+/* this function is called for every row in the image. If the
+ * image is interlacing, and you turned on the interlace handler,
+ * this function will be called for every row in every pass.
+ * Some of these rows will not be changed from the previous pass.
+ * When the row is not changed, the new_row variable will be NULL.
+ * The rows and passes are called in order, so you don't really
+ * need the row_num and pass, but I'm supplying them because it
+ * may make your life easier.
+ *
+ * For the non-NULL rows of interlaced images, you must call
+ * png_progressive_combine_row() passing in the row and the
+ * old row. You can call this function for NULL rows (it will
+ * just return) and for non-interlaced images (it just does the
+ * memcpy for you) if it will make the code easier. Thus, you
+ * can just do this for all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row, new_row);
+
+/* where old_row is what was displayed for previous rows. Note
+ * that the first pass (pass == 0 really) will completely cover
+ * the old row, so the rows do not have to be initialized. After
+ * the first pass (and only for interlaced images), you will have
+ * to pass the current row, and the function will combine the
+ * old row and the new row.
+ */
+}
+
+end_callback(png_structp png_ptr, png_infop info)
+{
+/* this function is called when the whole image has been read,
+ * including any chunks after the image (up to and including
+ * the IEND). You will usually have the same info chunk as you
+ * had in the header, although some data may have been added
+ * to the comments and time fields.
+ *
+ * Most people won't do much here, perhaps setting a flag that
+ * marks the image as finished.
+ */
+}
+
+/* write a png file */
+void write_png(char *file_name, ... other image information ...)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ /* open the file */
+ fp = fopen(file_name, "wb");
+ if (fp == NULL)
+ return;
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return;
+ }
+
+ /* Allocate/initialize the image information data. REQUIRED */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return;
+ }
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error hadnling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* If we get here, we had a problem reading the file */
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return;
+ }
+
+ /* One of the following I/O initialization functions is REQUIRED */
+**** I/O initialization method 1 ****
+ /* set up the output control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+**** I/O initialization method 2 ****
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call */
+ png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
+ user_IO_flush_function);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+**** only use 1 initialization method ****
+
+ /* Set the image information here. Width and height are up to 2^31,
+ * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+ * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+ * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+ * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
+ * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+ * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+ */
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
+ PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* set the palette if there is one. REQUIRED for indexed-color images */
+ palette = png_malloc(png_ptr, 256 * sizeof (png_color));
+ ... set palette colors ...
+ png_set_PLTE(png_ptr, info_ptr, palette, 256);
+
+ /* optional significant bit chunk */
+ /* if we are dealing with a grayscale image then */
+ sig_bit.gray = true_bit_depth;
+ /* otherwise, if we are dealing with a color image then */
+ sig_bit.red = true_red_bit_depth;
+ sig_bit.green = true_green_bit_depth;
+ sig_bit.blue = true_blue_bit_depth;
+ /* if the image has an alpha channel then */
+ sig_bit.alpha = true_alpha_bit_depth;
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+
+
+ /* Optional gamma chunk is strongly suggested if you have any guess
+ * as to the correct gamma of the image. */
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+
+ /* Optionally write comments into the image */
+ text_ptr[0].key = "Title";
+ text_ptr[0].text = "Mona Lisa";
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[1].key = "Author";
+ text_ptr[1].text = "Leonardo DaVinci";
+ text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[2].key = "Description";
+ text_ptr[2].text = "<long text>";
+ text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+ png_set_text(png_ptr, info_ptr, text_ptr, 2);
+
+ /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
+
+ /* Write the file header information. REQUIRED */
+ png_write_info(png_ptr, info_ptr);
+
+ /* Once we write out the header, the compression type on the text
+ * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+ * at the end.
+ */
+
+ /* set up the transformations you want. Note that these are
+ * all optional. Only call them if you want them. */
+
+ /* invert monocrome pixels */
+ png_set_invert(png_ptr);
+
+ /* Shift the pixels up to a legal bit depth and fill in
+ * as appropriate to correctly scale the image */
+ png_set_shift(png_ptr, &sig_bit);
+
+ /* pack pixels into bytes */
+ png_set_packing(png_ptr);
+
+ /* swap location of alpha bytes from ARGB to RGBA */
+ png_set_swap_alpha(png_ptr);
+
+ /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+ * RGB (4 channels -> 3 channels). The second parameter is not used. */
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+ /* flip BGR pixels to RGB */
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16-bit files to most significant byte first */
+ png_set_swap(png_ptr);
+
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ png_set_packswap(png_ptr);
+
+ /* turn on interlace handling if you are not using png_write_image() */
+ if (interlacing)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else
+ number_passes = 1;
+
+ /* The easiest way to write the image (you may have a different memory
+ * layout, however, so choose what fits your needs best). You need to
+ * use the first method if you aren't handling interlacing yourself.
+ */
+ png_byte row_pointers[height][width];
+
+ /* One of the following output methods is REQUIRED */
+**** write out the entire image data in one call ***
+ png_write_image(png_ptr, row_pointers);
+
+ /* the other way to write the image - deal with interlacing */
+
+**** write out the image data by one or more scanlines ****
+ /* The number of passes is either 1 for non-interlaced images,
+ * or 7 for interlaced images.
+ */
+ for (pass = 0; pass < number_passes; pass++)
+ {
+ /* Write a few rows at a time. */
+ png_write_rows(png_ptr, row_pointers, number_of_rows);
+
+ /* If you are only writing one row at a time, this works */
+ for (y = 0; y < height; y++)
+ {
+ png_bytep row_pointers = row[y];
+ png_write_rows(png_ptr, &row_pointers, 1);
+ }
+ }
+**** use only one output method ****
+
+ /* You can write optional chunks like tEXt, zTXt, and tIME at the end
+ * as well.
+ */
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ /* if you malloced the palette, free it here */
+ free(info_ptr->palette);
+
+ /* if you allocated any text comments, free them here */
+
+ /* clean up after the write, and free any memory allocated */
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
diff --git a/gs/libpng/libpng.a b/gs/libpng/libpng.a
new file mode 100644
index 000000000..bf458cba0
--- /dev/null
+++ b/gs/libpng/libpng.a
Binary files differ
diff --git a/gs/libpng/libpng.txt b/gs/libpng/libpng.txt
new file mode 100644
index 000000000..a603c3a4c
--- /dev/null
+++ b/gs/libpng/libpng.txt
@@ -0,0 +1,1519 @@
+libpng.txt - a description on how to use and modify libpng
+
+ libpng 1.0 beta 5 - version 0.95
+ Updated and distributed by Andreas Dilger <adilger@enel.ucalgary.ca>,
+ Copyright (c) 1996, 1997 Andreas Dilger
+ March 15, 1997
+ based on:
+
+ libpng 1.0 beta 2 - version 0.88
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ January 26, 1996
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995 Frank J. T. Wojcik
+ December 18, 1995 && January 20, 1996
+
+I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need.
+
+Libpng was written as a companion to the PNG specification, as a way
+to reduce the amount of time and effort it takes to support the PNG
+file format in application programs. Most users will not have to
+modify the library significantly; advanced users may want to modify it
+more. All attempts were made to make it as complete as possible,
+while keeping the code easy to understand. Currently, this library
+only supports C. Support for other languages is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of it's users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure.
+
+
+
+II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info were delevoped. The fields
+of png_info are still available for older applications, but it is
+suggested that applications use the new interfaces if at all possible.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+
+
+III. Reading
+
+Reading PNG files:
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file, briefly explaining the syntax and purpose of each one.
+See example.c and png.h for more detail. While Progressive reading
+is covered in the next section, you will still need some of the
+functions discussed in this section to read a PNG file.
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file, and it will
+return true or false (1 or 0) depending on whether the bytes could be
+part of a PNG file. Of course, the more bytes you pass in, the
+greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return;
+ }
+ fread(header, 1, number, fp);
+ is_png = png_check_sig(header, 0, number);
+ if (!is_png)
+ {
+ return;
+ }
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return;
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return;
+ }
+
+The error handling routines passed to png_create_read_struct() are only
+necessary if you are not using the libpng supplied error handling
+functions. When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass the
+jmpbuf field of your png_struct. If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_ function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+information on setjmp/longjmp. See the discussion on libpng error
+handling in the Customizing Libpng section below for more information on
+the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(fp);
+ return;
+ }
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+You are now ready to read all the file information up to the actual
+image data. You do this with a call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+Functions are used to get the information from the info_ptr:
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, &compression_type, &filter_type);
+
+ width - holds the width of the image in pixels (up to 2^31).
+ height - holds the height of the image in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the image channels.
+ (valid values are 1, 2, 4, 8, 16 and depend also on the
+ color_type. See also significant bits (sBIT) below).
+ color_type - describes which color/alpha channels are present.
+ PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTERLACE_TYPE_ADAM7
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE for PNG 1.0)
+ filter_type - (must be PNG_FILTER_TYPE_BASE for PNG 1.0)
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the color type
+ (valid values are 1 (GRAY, PALETTE), 2 (GRAY_ALPHA),
+ 3 (RGB), 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the file (if any). The
+ data is kept in the same offset it would be if the
+ whole signature were read (ie if an application had
+ already read in 4 bytes of signature before staring
+ libpng, the remaining 4 bytes would be in signature[4]
+ through signature[7] (see png_set_sig_bytes())).
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+ palette - the palette for the file (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written at (PNG_INFO_gAMA)
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for (PNG_INFO_sBIT)
+ the gray, red, green, and blue channels, whichever
+ are appropriate for the given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
+ trans - array of transparent entries for palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist); (PNG_INFO_hIST)
+ hist - histogram of palette (array of png_color_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+
+ num_text = png_get_text(png_ptr, info_ptr, &text_ptr);
+ text_ptr - array of png_text holding image comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current keyword.
+ text_ptr[i]->compression - type of compression used on "text"
+ PNG_TEXT_COMPRESSION_NONE or
+ PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
+ offset_x - positive offset from the left edge of the screen
+ offset_y - positive offset from the top edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
+ res_x - pixels/unit physical resolution in x direction
+ res_y - pixels/unit physical resolution in x direction
+ unit_type - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations or non-printing
+symbols. See the PNG specification for more details. There is also
+no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding pointer
+to a keyword and a pointer to a text string. Only the text string may
+be null. The keyword/text pairs are put into the array in the order
+that they are received. However, some or all of the text chunks may be
+after the image, so, to make sure you have read all the text chunks,
+don't mess with these until after you read the stuff after the image.
+This will be mentioned again below in the discussion that goes with
+png_read_end().
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do somthing with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGBRGBRGB format unless png_set_filler() is called to insert filler
+bytes, either before or after each RGB triplet. 16-bit RGB data will
+be returned RRGGBBRRGGBB, with the most significant byte of the color
+value first, unless png_set_strip_16() is called to transform it to
+regular RGBRGB triplets.
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background:
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image whave been "scaled" or "shifted" up to the next
+higher possible bit depth (eg from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_16p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 bytes. This code expands them
+into 4 bytes for windowing systems that need them in this format:
+
+ if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB)
+ png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);
+
+where "filler" is the number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+dispay (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+If you have a grayscale and you are using png_set_expand() to change to
+a higher bit-depth you must indicate if the supplied background gray
+is supplied in the original file bit depth (need_expand = 1) or in the
+expanded bit depth (need_expand = 0). Similarly, if you are reading
+a paletted image, you must indicate if you have supplied the background
+as a palette index that needs to be expanded (need_expand = 1). You can
+also specify an RGB triplet that isn't in the palette when setting your
+background for a paletted image.
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background),
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for the
+DISPLAY_GAMMA environment variable, which will hopefully be correctly set.
+
+ if (/* We have a user-defined screen gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same screen gamma value */
+ else if ((gamma_str = getenv("DISPLAY_GAMMA")) != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for PC monitors */
+ screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
+ {
+ png_color_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr, &histogram);
+ png_set_dither(png_ptr, palette, num_palette, max_screen_colors,
+ histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
+ MAX_SCREEN_COLORS, NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_GRAY)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code chages the storage to the
+other way (little-endian, ie. least significant bits first, eg. the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here.
+
+ number_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct display gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read int the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_TYPE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointers = row;
+ png_read_row(png_ptr, &row_pointers, NULL);
+
+If the file is interlaced (info_ptr->interlace_type != 0), things get
+somewhat harder. The only current (PNG Specification version 1.0)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_TYPE_ADAM7)
+is a someewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet. This results in a blocky
+image for the first pass, which gradually smoothes out as more pixels
+are read. The other method is the "sparkle" method, where pixels are
+draw only in their final locations, with the rest of the image remaining
+whatever colors they were initialized to before the start of the read.
+The first method usually looks better, but tends to be slower, as there
+are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images are valid images by themselves, or they can be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in row 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_TYPE_ADAM7)
+ number_passes = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the rectangle effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
+
+After you are finished reading the image, you can finish reading
+the file. If you are interested in comments or time, which may be
+stored either before or after the image data, you should pass the
+info_ptr pointer from the png_read_info() call, or you can pass a
+separate png_info struct if you want to keep the comments from
+before and after the image separate. If you are not interested, you
+can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+
+Reading PNG files progressively:
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+/* An example code fragment of how you would initialize the progressive
+ reader in your application. */
+int
+initialize_png_reader()
+{
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return -1;
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return -1;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new. You can provide functions to be called
+ when the header info is valid, when each row is completed,
+ and when the image is finished. If you aren't using all
+ functions, you can specify a NULL parameter. You can use
+ any struct as the user_ptr (cast to a void pointer for the
+ function call), and retrieve the pointer from inside the
+ callbacks using the function png_get_progressive_ptr(png_ptr);
+ which will return a void pointer, which you have to cast
+ appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+}
+
+/* A code fragment that you call as you recieve blocks of data */
+int
+process_data(png_bytep buffer, png_uint_32 length)
+{
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new also. Simply give it a chunk of data
+ from the file stream (in order, of course). On machines
+ with segmented memory models machines, don't give it any
+ more than 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if necessary
+ (I assume you can give it chunks of 1 byte, I haven't
+ tried less then 256 bytes yet). When this function returns,
+ you may want to display any rows that were generated in the
+ row callback if you don't already do so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+}
+
+/* This function is called (as set by png_set_progressive_fn() above)
+ when enough data has been supplied so all of the header has been read.
+ */
+void
+info_callback(png_structp png_ptr, png_infop info)
+{
+ /* Do any setup here, including setting any of the transformations
+ mentioned in the Reading PNG files section. For now, you _must_
+ call either png_start_read_image() or png_read_update_info()
+ after all the transformations are set (even if you don't set
+ any). You may start getting rows before png_process_data()
+ returns, so this is your last chance to prepare for that.
+ */
+}
+
+/* This function is called when each row of image data is complete */
+void
+row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+ /* If the image is interlaced, and you turned on the interlace
+ handler, this function will be called for every row in every pass.
+ Some of these rows will not be changed from the previous pass.
+ When the row is not changed, the new_row variable will be NULL.
+ The rows and passes are called in order, so you don't really
+ need the row_num and pass, but I'm supplying them because it
+ may make your life easier.
+
+ For the non-NULL rows of interlaced images, you must call
+ png_progressive_combine_row() passing in the row and the
+ old row. You can call this function for NULL rows (it will
+ just return) and for non-interlaced images (it just does the
+ memcpy for you) if it will make the code easier. Thus, you
+ can just do this for all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row, new_row);
+
+ /* where old_row is what was displayed for previous rows. Note
+ that the first pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be initialized. After
+ the first pass (and only for interlaced images), you will have
+ to pass the current row, and the function will combine the
+ old row and the new row.
+ */
+}
+
+void
+end_callback(png_structp png_ptr, png_infop info)
+{
+ /* This function is called after the whole image has been read,
+ including any chunks after the image (up to and including
+ the IEND). You will usually have the same info chunk as you
+ had in the header, although some data may have been added
+ to the comments and time fields.
+
+ Most people won't do much here, perhaps setting a flag that
+ marks the image as finished.
+ */
+}
+
+
+
+IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return;
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL.
+
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ (void *)user_error_ptr, user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return;
+ }
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp and pass the jmpbuf field of your png_struct. If you
+write the file from different routines, you will need to update
+the jmpbuf field every time you enter a new routine that will
+call a png_ function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return;
+ }
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid value is '0' (as of the
+06/96 PNG specification. The third parameter is a flag that indicates
+which filter type(s) are to be tested for each scanline. See the
+Compression Library for details on the specific filter types.
+
+
+ /* turn on or off filtering, and/or choose specific filters */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_PAETH);
+
+The png_set_compression_???() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.0, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type,
+ interlace_type,
+ width - holds the width of the image in pixels (up to 2^31).
+ height - holds the height of the image in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the image channels.
+ (valid values are 1, 2, 4, 8, 16 and depend also on the
+ color_type. See also significant bits (sBIT) below).
+ color_type - describes which color/alpha channels are present.
+ PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTER_LACE_TYPE_ADAM7
+ compression_type - (must be PNG_COMPRESSION_TYPE_DEFAULT for PNG 1.0)
+ filter_type - (must be PNG_FILTER_TYPE_DEFAULT for PNG 1.0)
+ Any or all of interlace_type, compression_type, of filter_type can be
+ NULL if you are not interested in their values.
+
+ png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+ palette - the palette for the file (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created at (PNG_INFO_gAMA)
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for (PNG_INFO_sBIT)
+ the gray, red, green, and blue channels, whichever
+ are appropriate for the given color type (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans, trans_values);
+ trans - array of transparent entries for palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist); (PNG_INFO_hIST)
+ hist - histogram of palette (array of png_color_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current keyword.
+ text_ptr[i]->compression - type of compression used on "text"
+ PNG_TEXT_COMPRESSION_NONE or
+ PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments in text_ptr
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+ offset_x - positive offset from the left edge of the screen
+ offset_y - positive offset from the top edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+ res_x - pixels/unit physical resolution in x direction
+ res_y - pixels/unit physical resolution in x direction
+ unit_type - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+If you want, you can use max_text to hold the size of the array, but
+libpng ignores it for writing (it does use it for reading). Each
+png_text structure holds a keyword-text value, and a compression type.
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion from other
+ image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recomendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are proved, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (ie 1996, rather than 96 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+You are now ready to write all the file information up to the actual
+image data. You do this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do somthing with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 bytes. This code tells
+the library to expect input data with 4 bytes per pixel
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is the value that will be put in the 4th byte, and the
+location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending
+upon whether the filler byte is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can get the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (ie 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, ie. least significant bits
+first, eg. the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert(png_ptr);
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush()ls is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytef *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you can't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers, number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, &row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of 6/96 -- PNG Specification
+version 1.0) defined interlacing scheme for PNG files is a
+compilcated interlace scheme, known as Adam7, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_passes = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_passes times.
+
+ png_write_rows(png_ptr, row_pointers, number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass the an appropriately filled png_info pointer. If you
+are not interested, you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+You must free any data you allocated for info_ptr, such as comments,
+palette, or histogram, before the call to png_destroy_write_struct();
+
+For a more compact example of writing a PNG image, see the file example.c.
+
+
+V. Modifying/Customizing libpng:
+
+There are two issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks which are user setable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively. To change
+these functions, call the approprate png_set_???_fn() function.
+
+Memory allocation is done through the functions png_large_malloc(),
+png_malloc(), png_realloc(), png_large_free(), and png_free(). These
+currently just call the standard C functions. The large functions must
+handle exactly 64K, but they don't have to handle more than that. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time.
+
+Input/Output in libpng is done throught png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp png_ptr, voidp io_ptr,
+ png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp png_ptr, voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn);
+
+ voidp io_ptr = png_get_io_ptr(png_ptr);
+
+The replacement I/O functions should have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr, png_bytep data,
+ png_uint_32 length);
+ void user_write_data(png_structp png_ptr, png_bytep data,
+ png_uint_32 length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp(), but you could change this to do things like
+exit() if you should wish. On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_STDIO defined. If
+you wish to change the behavior of the error functions, you will need to
+set up your own message callbacks. These functions are normally supplied
+at the time that the png_struct is created. It is also possible to change
+these functions after png_create_???_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_struct png_ptr, png_const_charp error_msg);
+ void user_warning_fn(png_struct png_ptr, png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details.
+
+If you need to read or write custom chunks, you will need to get deeper
+into the libpng code, as a mechanism has not yet been supplied for user
+callbacks with custom chunks. First, read the PNG specification, and have
+a first level of understanding of how it works. Pay particular attention
+to the sections that describe chunk names, and look at how other chunks
+were designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk that
+is similar to yours and copy off of it. More details can be found in the
+comments inside the code. A way of handling unknown chunks in a generic
+method, potentially via callback functions, would be best.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+Configuring for 16 bit platforms:
+
+You may need to change the png_large_malloc() and png_large_free()
+routines in pngmem.c, as these are requred to allocate 64K, although
+there is already support for many of the common DOS compilers. Also,
+you will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessable. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for DOS:
+
+For DOS users which only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+Configuring for Medium Model:
+
+Libpng's support for medium model has been tested on most of the popular
+complers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the row's of data are defined as png_bytepp which is a
+unsigned char far * far *.
+
+Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_???_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compliers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress as well as higher levels, and do so much faster.
+For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr, strategy);
+ png_set_compression_window_bits(png_ptr, window_bits);
+ png_set_compression_method(png_ptr, method);
+
+Controlling row filtering:
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. Filtering is enabled by default for
+RGB and grayscale images (with and without alpha), and for 8-bit
+paletted images, but not for paletted images with bit depths less
+than 8 bits/pixel. The 'method' parameter sets the main filtering
+method, which is currently only '0' in the PNG 1.0 specification.
+The 'filters' parameter sets which filter(s), if any, should be
+used for each scanline. Possible values are PNG_ALL_FILTERS and
+PNG_NO_FILTERS to turn filtering on and off, respectively.
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together '|' to specify one or more filters to use. These
+filters are described in more detail in the PNG specification. If
+you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types.
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP;
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] = {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_selection(png_ptr, PNG_FILTER_SELECTION_WEIGHTED,
+ 3, weights, costs);
+
+The weights are multiplying factors which indicate to libpng that row
+should be the same for successive rows unless another row filter is that
+many times better than the previous filter. In the above example, if
+the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduely influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+Removing unwanted object code:
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use an ability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space. All
+the reading and writing specific code are in seperate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections which are actually used will be loaded into memory.
+
+
+Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.88 are not
+distributed by the original libpng author, Guy Schalnat, but rather
+another member of the original PNG Group, Andreas Dilger. Guy is still
+alive and well, but he has moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destory() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. The
+preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications which do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a
+new name to force compilation errors with applications that try to use
+the old method.
diff --git a/gs/libpng/makefile b/gs/libpng/makefile
new file mode 100644
index 000000000..ebe000b4a
--- /dev/null
+++ b/gs/libpng/makefile
@@ -0,0 +1,68 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+CC=cc
+CFLAGS=-I$(ZLIBINC) -O # -g -DPNG_DEBUG=1
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+#RANLIB=echo
+RANLIB=ranlib
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ $(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ chmod 644 $(prefix)/include/pngconf.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+
diff --git a/gs/libpng/makefile.aco b/gs/libpng/makefile.aco
new file mode 100644
index 000000000..2cb089879
--- /dev/null
+++ b/gs/libpng/makefile.aco
@@ -0,0 +1,221 @@
+# Project: libpng
+
+
+# Toolflags:
+CCflags = -c -depend !Depend -IC:,Zlib: -g -throwback -DRISCOS -fnah
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags =
+LibFileflags = -c -l -o $@
+Squeezeflags = -o $@
+
+
+# Final targets:
+@.libpng-lib: @.o.png @.o.pngerror @.o.pngrio @.o.pngwio @.o.pngmem \
+ @.o.pngpread @.o.pngset @.o.pngget @.o.pngread @.o.pngrtran \
+ @.o.pngrutil @.o.pngtrans @.o.pngwrite @.o.pngwtran @.o.pngwutil
+ LibFile $(LibFileflags) @.o.png @.o.pngerror @.o.pngrio @.o.pngrtran \
+ @.o.pngmem @.o.pngpread @.o.pngset @.o.pngget @.o.pngread @.o.pngwio \
+ @.o.pngrutil @.o.pngtrans @.o.pngwrite @.o.pngwtran @.o.pngwutil
+@.mm-libpng-lib: @.mm.png @.mm.pngerror @.mm.pngrio @.mm.pngwio @.mm.pngmem \
+ @.mm.pngpread @.mm.pngset @.mm.pngget @.mm.pngread @.mm.pngrtran \
+ @.mm.pngrutil @.mm.pngtrans @.mm.pngwrite @.mm.pngwtran @.mm.pngwutil
+ LibFile $(LibFileflags) @.mm.png @.mm.pngerror @.mm.pngrio \
+ @.mm.pngwio @.mm.pngmem @.mm.pngpread @.mm.pngset @.mm.pngget \
+ @.mm.pngread @.mm.pngrtran @.mm.pngrutil @.mm.pngtrans @.mm.pngwrite \
+ @.mm.pngwtran @.mm.pngwutil
+
+
+# User-editable dependencies:
+# (C) Copyright 1997 Tom Tanner
+Test: @.pngtest
+ <Prefix$Dir>.pngtest
+ @remove <Prefix$Dir>.pngtest
+
+#It would be nice if you could stop "make" listing from here on!
+@.pngtest: @.o.pngtest @.libpng-lib C:o.Stubs Zlib:zlib_lib
+ Link $(Linkflags) @.o.pngtest @.libpng-lib C:o.Stubs Zlib:zlib_lib
+
+.SUFFIXES: .o .mm .c
+
+.c.mm:
+ MemCheck.CC cc $(ccflags) -o $@ LibPng:$<
+.c.o:
+ cc $(ccflags) -o $@ $<
+
+
+# Static dependencies:
+
+
+# Dynamic dependencies:
+o.pngtest: c.pngtest
+o.pngtest: h.png
+o.pngtest: Zlib:h.zlib
+o.pngtest: Zlib:h.zconf
+o.pngtest: h.pngconf
+mm.png: LibPng:c.png
+mm.png: LibPng:h.png
+mm.png: Zlib:h.zlib
+mm.png: Zlib:h.zconf
+mm.png: LibPng:h.pngconf
+mm.png: MemCheck:ANSI.h.stdio
+mm.pngerror: LibPng:c.pngerror
+mm.pngerror: LibPng:h.png
+mm.pngerror: Zlib:h.zlib
+mm.pngerror: Zlib:h.zconf
+mm.pngerror: LibPng:h.pngconf
+mm.pngerror: MemCheck:ANSI.h.stdio
+mm.pngrio: LibPng:c.pngrio
+mm.pngrio: LibPng:h.png
+mm.pngrio: Zlib:h.zlib
+mm.pngrio: Zlib:h.zconf
+mm.pngrio: LibPng:h.pngconf
+mm.pngrio: MemCheck:ANSI.h.stdio
+mm.pngwio: LibPng:c.pngwio
+mm.pngwio: LibPng:h.png
+mm.pngwio: Zlib:h.zlib
+mm.pngwio: Zlib:h.zconf
+mm.pngwio: LibPng:h.pngconf
+mm.pngwio: MemCheck:ANSI.h.stdio
+mm.pngmem: LibPng:c.pngmem
+mm.pngmem: LibPng:h.png
+mm.pngmem: Zlib:h.zlib
+mm.pngmem: Zlib:h.zconf
+mm.pngmem: LibPng:h.pngconf
+mm.pngmem: MemCheck:ANSI.h.stdio
+mm.pngpread: LibPng:c.pngpread
+mm.pngpread: LibPng:h.png
+mm.pngpread: Zlib:h.zlib
+mm.pngpread: Zlib:h.zconf
+mm.pngpread: LibPng:h.pngconf
+mm.pngpread: MemCheck:ANSI.h.stdio
+mm.pngset: LibPng:c.pngset
+mm.pngset: LibPng:h.png
+mm.pngset: Zlib:h.zlib
+mm.pngset: Zlib:h.zconf
+mm.pngset: LibPng:h.pngconf
+mm.pngset: MemCheck:ANSI.h.stdio
+mm.pngget: LibPng:c.pngget
+mm.pngget: LibPng:h.png
+mm.pngget: Zlib:h.zlib
+mm.pngget: Zlib:h.zconf
+mm.pngget: LibPng:h.pngconf
+mm.pngget: MemCheck:ANSI.h.stdio
+mm.pngread: LibPng:c.pngread
+mm.pngread: LibPng:h.png
+mm.pngread: Zlib:h.zlib
+mm.pngread: Zlib:h.zconf
+mm.pngread: LibPng:h.pngconf
+mm.pngread: MemCheck:ANSI.h.stdio
+mm.pngrtran: LibPng:c.pngrtran
+mm.pngrtran: LibPng:h.png
+mm.pngrtran: Zlib:h.zlib
+mm.pngrtran: Zlib:h.zconf
+mm.pngrtran: LibPng:h.pngconf
+mm.pngrtran: MemCheck:ANSI.h.stdio
+mm.pngrutil: LibPng:c.pngrutil
+mm.pngrutil: LibPng:h.png
+mm.pngrutil: Zlib:h.zlib
+mm.pngrutil: Zlib:h.zconf
+mm.pngrutil: LibPng:h.pngconf
+mm.pngrutil: MemCheck:ANSI.h.stdio
+mm.pngtrans: LibPng:c.pngtrans
+mm.pngtrans: LibPng:h.png
+mm.pngtrans: Zlib:h.zlib
+mm.pngtrans: Zlib:h.zconf
+mm.pngtrans: LibPng:h.pngconf
+mm.pngtrans: MemCheck:ANSI.h.stdio
+mm.pngwrite: LibPng:c.pngwrite
+mm.pngwrite: LibPng:h.png
+mm.pngwrite: Zlib:h.zlib
+mm.pngwrite: Zlib:h.zconf
+mm.pngwrite: LibPng:h.pngconf
+mm.pngwrite: MemCheck:ANSI.h.stdio
+mm.pngwtran: LibPng:c.pngwtran
+mm.pngwtran: LibPng:h.png
+mm.pngwtran: Zlib:h.zlib
+mm.pngwtran: Zlib:h.zconf
+mm.pngwtran: LibPng:h.pngconf
+mm.pngwtran: MemCheck:ANSI.h.stdio
+mm.pngwutil: LibPng:c.pngwutil
+mm.pngwutil: LibPng:h.png
+mm.pngwutil: Zlib:h.zlib
+mm.pngwutil: Zlib:h.zconf
+mm.pngwutil: LibPng:h.pngconf
+mm.pngwutil: MemCheck:ANSI.h.stdio
+o.png: c.png
+o.png: h.png
+o.png: Zlib:h.zlib
+o.png: Zlib:h.zconf
+o.png: h.pngconf
+o.pngerror: c.pngerror
+o.pngerror: h.png
+o.pngerror: Zlib:h.zlib
+o.pngerror: Zlib:h.zconf
+o.pngerror: h.pngconf
+o.pngrio: c.pngrio
+o.pngrio: h.png
+o.pngrio: Zlib:h.zlib
+o.pngrio: Zlib:h.zconf
+o.pngrio: h.pngconf
+o.pngwio: c.pngwio
+o.pngwio: h.png
+o.pngwio: Zlib:h.zlib
+o.pngwio: Zlib:h.zconf
+o.pngwio: h.pngconf
+o.pngmem: c.pngmem
+o.pngmem: h.png
+o.pngmem: Zlib:h.zlib
+o.pngmem: Zlib:h.zconf
+o.pngmem: h.pngconf
+o.pngpread: c.pngpread
+o.pngpread: h.png
+o.pngpread: Zlib:h.zlib
+o.pngpread: Zlib:h.zconf
+o.pngpread: h.pngconf
+o.pngset: c.pngset
+o.pngset: h.png
+o.pngset: Zlib:h.zlib
+o.pngset: Zlib:h.zconf
+o.pngset: h.pngconf
+o.pngget: c.pngget
+o.pngget: h.png
+o.pngget: Zlib:h.zlib
+o.pngget: Zlib:h.zconf
+o.pngget: h.pngconf
+o.pngread: c.pngread
+o.pngread: h.png
+o.pngread: Zlib:h.zlib
+o.pngread: Zlib:h.zconf
+o.pngread: h.pngconf
+o.pngrtran: c.pngrtran
+o.pngrtran: h.png
+o.pngrtran: Zlib:h.zlib
+o.pngrtran: Zlib:h.zconf
+o.pngrtran: h.pngconf
+o.pngrutil: c.pngrutil
+o.pngrutil: h.png
+o.pngrutil: Zlib:h.zlib
+o.pngrutil: Zlib:h.zconf
+o.pngrutil: h.pngconf
+o.pngtrans: c.pngtrans
+o.pngtrans: h.png
+o.pngtrans: Zlib:h.zlib
+o.pngtrans: Zlib:h.zconf
+o.pngtrans: h.pngconf
+o.pngwrite: c.pngwrite
+o.pngwrite: h.png
+o.pngwrite: Zlib:h.zlib
+o.pngwrite: Zlib:h.zconf
+o.pngwrite: h.pngconf
+o.pngwtran: c.pngwtran
+o.pngwtran: h.png
+o.pngwtran: Zlib:h.zlib
+o.pngwtran: Zlib:h.zconf
+o.pngwtran: h.pngconf
+o.pngwutil: c.pngwutil
+o.pngwutil: h.png
+o.pngwutil: Zlib:h.zlib
+o.pngwutil: Zlib:h.zconf
+o.pngwutil: h.pngconf
diff --git a/gs/libpng/makefile.ama b/gs/libpng/makefile.ama
new file mode 100644
index 000000000..366524d5c
--- /dev/null
+++ b/gs/libpng/makefile.ama
@@ -0,0 +1,42 @@
+# Commodore Amiga Makefile
+# makefile for libpng and SAS C V6.55 compiler
+# Copyright (C) 1995 Wolf Faust
+
+#compiler
+CC=sc
+#compiler flags
+# WARNING: a bug in V6.51 causes bad code with OPTGO
+# So use V6.55 or set NOOPTGO!!!!!!!!!
+CFLAGS= NOSTKCHK PARMS=REG OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL\
+ OPTLOOP OPTRDEP=4 OPTDEP=4 OPTCOMP=4 DEFINE=PNG_INTERNAL
+#linker flags
+LDFLAGS= SD ND BATCH
+#link libs
+LDLIBS= libpng.lib libgz.lib LIB:scm.lib LIB:sc.lib Lib:amiga.lib
+# linker
+LN= slink
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= oml
+# make directory command
+MKDIR= makedir
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o pngpread.o \
+pngread.o pngerror.o pngwrite.o pngrtran.o pngwtran.o pngrio.o pngwio.o pngmem.o
+
+all: libpng.lib pngtest
+
+libpng.lib: $(OBJS)
+-$(RM) libpng.lib
+$(AR) libpng.lib r $(OBJS)
+
+pngtest: pngtest.o libpng.lib
+$(LN) <WITH <
+$(LDFLAGS)
+TO pngtest
+FROM LIB:c.o pngtest.o
+LIB $(LDLIBS)
+<
+
+
diff --git a/gs/libpng/makefile.atr b/gs/libpng/makefile.atr
new file mode 100644
index 000000000..d490ce1dd
--- /dev/null
+++ b/gs/libpng/makefile.atr
@@ -0,0 +1,31 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+# modified for LC56/ATARI assumes libz.lib is in same dir and uses default
+# rules for library management
+#
+CFLAGS=-I..\zlib -O
+LBR = png.lib
+LDFLAGS=-lpng -lz -lm
+
+# where make install puts libpng.a and png.h
+
+OBJS = $(LBR)(png.o) $(LBR)(pngset.o) $(LBR)(pngget.o) $(LBR)(pngrutil.o)\
+ $(LBR)(pngtrans.o) $(LBR)(pngwutil.o)\
+ $(LBR)(pngread.o) $(LBR)(pngerror.o) $(LBR)(pngwrite.o)\
+ $(LBR)(pngrtran.o) $(LBR)(pngwtran.o)\
+ $(LBR)(pngmem.o) $(LBR)(pngrio.o) $(LBR)(pngwio.o) $(LBR)(pngpread.o)
+
+all: $(LBR) pngtest.ttp
+
+$(LBR): $(OBJS)
+
+pngtest.ttp: pngtest.o $(LBR)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o$@ pngtest.o
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/p
diff --git a/gs/libpng/makefile.bor b/gs/libpng/makefile.bor
new file mode 100644
index 000000000..0b7c0e611
--- /dev/null
+++ b/gs/libpng/makefile.bor
@@ -0,0 +1,168 @@
+# Makefile for libpng
+# Borland C++ 4.5 (Note: All modules are compiled in C mode)
+# Will work with C++ 4.02 also
+# To build the library, do:
+# "make -fmakefile.bor -DMODEL=m"
+# or: "make -fmakefile.bor -DMODEL=l"
+#
+# ------------- Borland C++ 4.5 -------------
+
+### Absolutely necessary for this makefile to work
+.AUTODEPEND
+
+## Useful user options
+
+# Usually defined in builtins.mak or the environment
+# Currently unused.
+!ifndef BCROOT
+BCROOT=N:\BC45
+!endif
+
+# Where zlib.h and zconf.h and zlib.lib are
+ZLIB_PATH=..\zlib
+
+!ifndef MODEL
+MODEL=l
+!endif
+
+#TARGET_CPU=3
+# 2 = 286, 3 = 386, etc.
+!ifndef TARGET_CPU
+TARGET_CPU=2
+!endif
+
+
+# Use this if you don't want Borland's fancy exception handling.
+NOEHLIB=noeh$(MODEL).lib
+
+!ifdef DEBUG
+CDEBUG=-v
+LDEBUG=-v
+!else
+CDEBUG=
+LDEBUG=
+!endif
+
+# STACKOFLOW=1
+!ifdef STACKOFLOW
+CDEBUG=$(CDEBUG) -N
+LDEBUG=$(LDEBUG) -N
+!endif
+
+
+## Compiler, linker, and lib stuff
+CC=bcc
+LD=bcc
+LIB=tlib
+
+MODELARG=-m$(MODEL)
+
+# -X- turns on dependency generation in the object file
+# -w sets all warnings on
+# -O2 optimize for speed
+# -Z global optimization
+CFLAGS=-O2 -Z -X- -w -I$(ZLIB_PATH) -$(TARGET_CPU) $(MODELARG) $(CDEBUG)
+
+# -M generate map file
+LDFLAGS=-M $(LDEBUG)
+
+O=obj
+
+## variables
+OBJS = \
+ png.$(O) \
+ pngerror.$(O) \
+ pngmem.$(O) \
+ pngpread.$(O) \
+ pngset.$(O) \
+ pngget.$(O) \
+ pngread.$(O) \
+ pngrio.$(O) \
+ pngrtran.$(O) \
+ pngrutil.$(O) \
+ pngtrans.$(O) \
+ pngwrite.$(O) \
+ pngwtran.$(O) \
+ pngwio.$(O) \
+ pngwutil.$(O)
+
+LIBOBJS = \
+ +png.$(O) \
+ +pngerror.$(O) \
+ +pngmem.$(O) \
+ +pngpread.$(O) \
+ +pngread.$(O) \
+ +pngset.$(O) \
+ +pngget.$(O) \
+ +pngrio.$(O) \
+ +pngrtran.$(O) \
+ +pngrutil.$(O) \
+ +pngtrans.$(O) \
+ +pngwrite.$(O) \
+ +pngwtran.$(O) \
+ +pngwio.$(O)
+ +pngwutil.$(O)
+
+LIBNAME=libpng$(MODEL).lib
+
+
+## Implicit rules
+# Braces let make "batch" calls to the compiler,
+# 2 calls instead of 12; space is important.
+.c.obj:
+ $(CC) $(CFLAGS) -c {$*.c }
+
+.c.exe:
+ $(CC) $(CFLAGS) $(LDFLAGS) $*.c
+
+
+## Major targets
+libpng: $(LIBNAME)
+
+pngtest: pngtest$(MODEL).exe
+
+test:
+ pngtest$(MODEL)
+
+
+## Minor Targets
+
+png.obj: png.c
+pngset.obj: pngset.c
+pngget.obj: pngget.c
+pngread.obj: pngread.c
+pngpread.obj: pngpread.c
+pngrtran.obj: pngrtran.c
+pngrutil.obj: pngrutil.c
+pngerror.obj: pngerror.c
+pngmem.obj: pngmem.c
+pngrio.obj: pngrio.c
+pngwio.obj: pngwio.c
+pngtrans.obj: pngtrans.c
+pngwrite.obj: pngwrite.c
+pngwtran.obj: pngwtran.c
+pngwutil.obj: pngwutil.c
+
+
+$(LIBNAME): $(OBJS)
+ -del $(LIBNAME)
+ $(LIB) $(LIBNAME) @&&|
+$(LIBOBJS), libpng$(MODEL)
+|
+
+
+pngtest$(MODEL).obj: pngtest.c
+ $(CC) $(CFLAGS) -opngtest$(MODEL) -c pngtest.c
+
+pngtest$(MODEL).exe: pngtest$(MODEL).obj
+ $(CC) $(MODELARG) $(LDFLAGS) -L$(ZLIB_PATH) pngtest$(MODEL).obj $(LIBNAME) zlib$(MODEL).lib $(NOEHLIB)
+
+
+# Clean up anything else you want
+clean:
+ -del *.obj
+ -del *.lib
+ -del *.lst
+
+
+# End of makefile for libpng
diff --git a/gs/libpng/makefile.dj2 b/gs/libpng/makefile.dj2
new file mode 100644
index 000000000..8ad042eb5
--- /dev/null
+++ b/gs/libpng/makefile.dj2
@@ -0,0 +1,52 @@
+# DJGPP (DOS gcc) makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=gcc
+CFLAGS=-I../zlib -O
+LDFLAGS=-L. -L../zlib/ -lpng -lz -lm
+
+RANLIB=ranlib
+
+# where make install puts libpng.a and png.h
+#prefix=/usr/local
+prefix=.
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o pngwtran.o \
+ pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ $(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+ coff2exe pngtest
+
+test: pngtest
+ ./pngtest
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+
diff --git a/gs/libpng/makefile.elf b/gs/libpng/makefile.elf
new file mode 100644
index 000000000..f63c35937
--- /dev/null
+++ b/gs/libpng/makefile.elf
@@ -0,0 +1,86 @@
+# makefile for libpng on (linux) ELF
+# Copyright (C) 1996, 1997 Andreas Dilger
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=gcc
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+WARNMORE=-Wwrite-strings -Wpointer-arith -Wshadow \
+ -Wmissing-declarations -Wtraditional -Wcast-align \
+ -Wstrict-prototypes -Wmissing-prototypes #-Wconversion
+CFLAGS=-I$(ZLIBINC) -Wall -O2 -fPIC # $(WARNMORE) # -g -DPNG_DEBUG=3
+LDFLAGS=-L. -Wl,-rpath,. -L$(ZLIBLIB) -Wl,-rpath,$(ZLIBLIB) -lpng -lz -lm
+
+RANLIB=ranlib
+#RANLIB=echo
+
+PNGMAJ = 0
+PNGMIN = 96
+PNGVER = $(PNGMAJ).$(PNGMIN)
+
+# where make install puts libpng.a, libpng.so*, and png.h
+prefix=/usr/local
+INCPATH=$(prefix)/include
+LIBPATH=$(prefix)/lib
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.so pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+libpng.so: libpng.so.$(PNGMAJ)
+ ln -sf libpng.so.$(PNGMAJ) libpng.so
+
+libpng.so.$(PNGMAJ): libpng.so.$(PNGVER)
+ ln -sf libpng.so.$(PNGVER) libpng.so.$(PNGMAJ)
+
+libpng.so.$(PNGVER): $(OBJS)
+ gcc -shared -Wl,-soname,libpng.so.$(PNGMAJ) -o libpng.so.$(PNGVER) $(OBJS)
+
+pngtest: pngtest.o libpng.so
+ $(CC) -o pngtest pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.so.$(PNGVER)
+ -@mkdir $(INCPATH) $(LIBPATH)
+ cp png.h pngconf.h $(INCPATH)
+ chmod 644 $(INCPATH)/png.h $(INCPATH)/pngconf.h
+ cp libpng.so.$(PNGVER) $(LIBPATH)
+ chmod 755 $(LIBPATH)/libpng.so.$(PNGVER)
+ -@/bin/rm $(LIBPATH)/libpng.so.$(PNGMAJ) $(LIBPATH)/libpng.so
+ (cd $(LIBPATH); ln -sf libpng.so.$(PNGVER) libpng.so.$(PNGMAJ); \
+ ln -sf libpng.so.$(PNGMAJ) libpng.so)
+
+clean:
+ rm -f *.o libpng.a libpng.so* pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
diff --git a/gs/libpng/makefile.knr b/gs/libpng/makefile.knr
new file mode 100644
index 000000000..13f83db66
--- /dev/null
+++ b/gs/libpng/makefile.knr
@@ -0,0 +1,73 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=cc
+CFLAGS=-I../zlib -O
+LDFLAGS=-L. -L../zlib/ -lpng -lz -lm
+# flags for ansi2knr
+ANSI2KNRFLAGS=
+
+RANLIB=ranlib
+#RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: ansi2knr libpng.a pngtest
+
+# general rule to allow ansi2knr to work
+.c.o:
+ ./ansi2knr $*.c T$*.c
+ $(CC) $(CFLAGS) -c T$*.c
+ rm -f T$*.c $*.o
+ mv T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libpng.a: ansi2knr $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a ansi2knr
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ chmod 644 $(prefix)/include/pngconf.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png ansi2knr
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
diff --git a/gs/libpng/makefile.mip b/gs/libpng/makefile.mip
new file mode 100644
index 000000000..fa157a226
--- /dev/null
+++ b/gs/libpng/makefile.mip
@@ -0,0 +1,62 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=cc
+CFLAGS=-I../zlib -O -systype sysv -DSYSV -w -Dmips
+#CFLAGS=-O
+LDFLAGS=-L. -L../zlib/ -lpng -lz -lm
+
+#RANLIB=ranlib
+RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ chmod 644 $(prefix)/include/pngconf.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
diff --git a/gs/libpng/makefile.msc b/gs/libpng/makefile.msc
new file mode 100644
index 000000000..c4ac7dbe9
--- /dev/null
+++ b/gs/libpng/makefile.msc
@@ -0,0 +1,86 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+# Assumes that zlib.lib, zconf.h, and zlib.h have been copied to ..\zlib
+
+# ------------- Microsoft C 5.1 and later -------------
+MODEL=-AL
+CFLAGS=-Oait -Gs -nologo -W2 $(MODEL) -I..\zlib
+#-Ox generates bad code with MSC 5.1
+CC=cl
+LD=link
+LDFLAGS=/e/st:0x1500/noe
+O=.obj
+
+#uncomment next to put error messages in a file
+ERRFILE= >> pngerrs
+
+# variables
+OBJS1 = png$(O) pngset$(O) pngget$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O)
+OBJS2 = pngmem$(O) pngpread$(O) pngread$(O) pngerror$(O) pngwrite$(O)
+OBJS3 = pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
+
+all: libpng.lib
+
+png$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngset$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngget$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngread$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngpread$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngrtran$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngrutil$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngerror$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngmem$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngrio$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngwio$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngtest$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngtrans$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngwrite$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngwtran$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngwutil$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+libpng.lib: $(OBJS1) $(OBJS2) $(OBJS3)
+ del libpng.lib
+ lib libpng $(OBJS1);
+ lib libpng $(OBJS2);
+ lib libpng $(OBJS3);
+
+pngtest.exe: pngtest.obj libpng.lib
+ $(LD) $(LDFLAGS) pngtest.obj,,,libpng.lib ..\zlib\zlib.lib ;
+
+test: pngtest.exe
+ pngtest
+
+# End of makefile for libpng
+
diff --git a/gs/libpng/makefile.std b/gs/libpng/makefile.std
new file mode 100644
index 000000000..ebe000b4a
--- /dev/null
+++ b/gs/libpng/makefile.std
@@ -0,0 +1,68 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+CC=cc
+CFLAGS=-I$(ZLIBINC) -O # -g -DPNG_DEBUG=1
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+#RANLIB=echo
+RANLIB=ranlib
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ $(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ chmod 644 $(prefix)/include/pngconf.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+
diff --git a/gs/libpng/makefile.sun b/gs/libpng/makefile.sun
new file mode 100644
index 000000000..ccd0a28b7
--- /dev/null
+++ b/gs/libpng/makefile.sun
@@ -0,0 +1,72 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+
+WARNMORE=-Wwrite-strings -Wpointer-arith -Wshadow -Wconversion \
+ -Wmissing-declarations -Wtraditional -Wcast-align \
+ -Wstrict-prototypes -Wmissing-prototypes
+CC=gcc
+CFLAGS=-I$(ZLIBINC) -O $(WARNMORE) -DPNG_DEBUG=4
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+RANLIB=ranlib
+#RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+ pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ $(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+ ./pngtest
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ cp pngconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ chmod 644 $(prefix)/include/pngconf.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+
diff --git a/gs/libpng/makefile.tc b/gs/libpng/makefile.tc
new file mode 100644
index 000000000..7e1fc91ea
--- /dev/null
+++ b/gs/libpng/makefile.tc
@@ -0,0 +1,78 @@
+# Makefile for libpng
+# TurboC++ 3.0 (Note: All modules are compiled in C mode)
+
+# To use, do "make -fmakefile.tc"
+
+# ------------- Turbo C++ 3.0 -------------
+MODEL=-ml
+CFLAGS=-O2 -Z $(MODEL) -I..\zlib
+CC=tcc
+LD=tcc
+LIB=tlib
+LDFLAGS=$(MODEL)
+O=.obj
+
+# variables
+OBJS1 = png$(O) pngset$(O) pngget$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O)
+OBJS2 = pngmem$(O) pngpread$(O) pngread$(O) pngerror$(O) pngwrite$(O)
+OBJS3 = pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
+OBJSL1 = +png$(O) +pngset$(O) +pngget$(O) +pngrutil$(O) +pngtrans$(O)
+OBJSL2 = +pngwutil$(O) +pngmem$(O) +pngpread$(O) +pngread$(O) +pngerror$(O)
+OBJSL3 = +pngwrite$(O) +pngrtran$(O) +pngwtran$(O) +pngrio$(O) +pngwio$(O)
+
+all: libpng.lib
+
+png$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngset$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngget$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngread$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngpread$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngrtran$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngrutil$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngerror$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngmem$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngrio$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngwio$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngtest$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngtrans$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngwrite$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngwtran$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+pngwutil$(O): png.h pngconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+libpng.lib: $(OBJS1) $(OBJS2) $(OBJS3)
+ $(LIB) libpng +$(OBJSL1)
+ $(LIB) libpng +$(OBJSL2)
+ $(LIB) libpng +$(OBJSL3)
+
+# End of makefile for libpng
diff --git a/gs/libpng/makevms.com b/gs/libpng/makevms.com
new file mode 100644
index 000000000..15f305a60
--- /dev/null
+++ b/gs/libpng/makevms.com
@@ -0,0 +1,125 @@
+$! make libpng under VMS
+$!
+$!
+$! Look for the compiler used
+$!
+$ zlibsrc = "[-.zlib]"
+$ ccopt="/include=''zlibsrc'"
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$ ccopt = "/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$ then
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ if f$search("SYS$SYSTEM:VAXC.EXE").eqs.""
+$ then
+$ comp = "__gcc__=1"
+$ CC :== GCC
+$ else
+$ comp = "__vaxc__=1"
+$ endif
+$ else
+$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$ ccopt = "/decc/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ endif
+$ endif
+$!
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Libpng sources ..."
+$ if f$search("SYS$SYSTEM:MMS.EXE").eqs.""
+$ then
+$ dele pngtest.obj;*
+$ CALL MAKE png.OBJ "cc ''CCOPT' png" -
+ png.c png.h pngconf.h
+$ CALL MAKE pngpread.OBJ "cc ''CCOPT' pngpread" -
+ pngpread.c png.h pngconf.h
+$ CALL MAKE pngset.OBJ "cc ''CCOPT' pngset" -
+ pngset.c png.h pngconf.h
+$ CALL MAKE pngget.OBJ "cc ''CCOPT' pngget" -
+ pngget.c png.h pngconf.h
+$ CALL MAKE pngread.OBJ "cc ''CCOPT' pngread" -
+ pngread.c png.h pngconf.h
+$ CALL MAKE pngpread.OBJ "cc ''CCOPT' pngpread" -
+ pngpread.c png.h pngconf.h
+$ CALL MAKE pngrtran.OBJ "cc ''CCOPT' pngrtran" -
+ pngrtran.c png.h pngconf.h
+$ CALL MAKE pngrutil.OBJ "cc ''CCOPT' pngrutil" -
+ pngrutil.c png.h pngconf.h
+$ CALL MAKE pngerror.OBJ "cc ''CCOPT' pngerror" -
+ pngerror.c png.h pngconf.h
+$ CALL MAKE pngmem.OBJ "cc ''CCOPT' pngmem" -
+ pngmem.c png.h pngconf.h
+$ CALL MAKE pngrio.OBJ "cc ''CCOPT' pngrio" -
+ pngrio.c png.h pngconf.h
+$ CALL MAKE pngwio.OBJ "cc ''CCOPT' pngwio" -
+ pngwio.c png.h pngconf.h
+$ CALL MAKE pngtrans.OBJ "cc ''CCOPT' pngtrans" -
+ pngtrans.c png.h pngconf.h
+$ CALL MAKE pngwrite.OBJ "cc ''CCOPT' pngwrite" -
+ pngwrite.c png.h pngconf.h
+$ CALL MAKE pngwtran.OBJ "cc ''CCOPT' pngwtran" -
+ pngwtran.c png.h pngconf.h
+$ CALL MAKE pngwutil.OBJ "cc ''CCOPT' pngwutil" -
+ pngwutil.c png.h pngconf.h
+$ write sys$output "Building Libpng ..."
+$ CALL MAKE libpng.OLB "lib/crea libpng.olb *.obj" *.OBJ
+$ write sys$output "Building pngtest..."
+$ CALL MAKE pngtest.OBJ "cc ''CCOPT' pngtest" -
+ pngtest.c png.h pngconf.h
+$ call make pngtest.exe -
+ "LINK pngtest,libpng.olb/lib,''zlibsrc'libgz.olb/lib" -
+ pngtest.obj libpng.olb
+$ write sys$output "Testing Libpng..."
+$ run pngtest
+$ else
+$ mms/macro=('comp',zlibsrc='zlibsrc')
+$ endif
+$ write sys$output "Libpng build completed"
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
+
diff --git a/gs/libpng/png.c b/gs/libpng/png.c
new file mode 100644
index 000000000..797351a14
--- /dev/null
+++ b/gs/libpng/png.c
@@ -0,0 +1,358 @@
+
+/* png.c - location for general purpose png functions
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#define PNG_NO_EXTERN
+#include "png.h"
+
+/* Version information for C files. This had better match the version
+ string defined in png.h */
+char png_libpng_ver[] = "0.95";
+
+/* Place to hold the signiture string for a PNG file. */
+png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+
+/* constant strings for known chunk types. If you need to add a chunk,
+ add a string holding the name here. If you want to make the code
+ portable to EBCDIC machines, use ASCII numbers, not characters. */
+png_byte FARDATA png_IHDR[5] = { 73, 72, 68, 82, '\0'};
+png_byte FARDATA png_IDAT[5] = { 73, 68, 65, 84, '\0'};
+png_byte FARDATA png_IEND[5] = { 73, 69, 78, 68, '\0'};
+png_byte FARDATA png_PLTE[5] = { 80, 76, 84, 69, '\0'};
+png_byte FARDATA png_bKGD[5] = { 98, 75, 71, 68, '\0'};
+png_byte FARDATA png_cHRM[5] = { 99, 72, 82, 77, '\0'};
+png_byte FARDATA png_gAMA[5] = {103, 65, 77, 65, '\0'};
+png_byte FARDATA png_hIST[5] = {104, 73, 83, 84, '\0'};
+png_byte FARDATA png_oFFs[5] = {111, 70, 70, 115, '\0'};
+png_byte FARDATA png_pCAL[5] = {112, 67, 65, 76, '\0'};
+png_byte FARDATA png_pHYs[5] = {112, 72, 89, 115, '\0'};
+png_byte FARDATA png_sBIT[5] = {115, 66, 73, 84, '\0'};
+png_byte FARDATA png_tEXt[5] = {116, 69, 88, 116, '\0'};
+png_byte FARDATA png_tIME[5] = {116, 73, 77, 69, '\0'};
+png_byte FARDATA png_tRNS[5] = {116, 82, 78, 83, '\0'};
+png_byte FARDATA png_zTXt[5] = {122, 84, 88, 116, '\0'};
+
+/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+/* start of interlace block */
+int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+/* offset to next interlace block */
+int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+/* start of interlace block in the y direction */
+int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+/* offset to next interlace block in the y direction */
+int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+/* width of interlace block */
+/* this is not currently used - if you need it, uncomment it here and
+ in png.h
+int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+*/
+
+/* height of interlace block */
+/* this is not currently used - if you need it, uncomment it here and
+ in png.h
+int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+*/
+
+/* mask to determine which pixels are valid in a pass */
+int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+
+/* mask to determine which pixels to overwrite while displaying */
+int FARDATA png_pass_dsp_mask[] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+
+
+/* Tells libpng that we have already handled the first "num_bytes" bytes
+ * of the PNG file signature. If the PNG data is embedded into another
+ * stream we can set num_bytes = 8 so that libpng will not attempt to read
+ * or write any of the magic bytes before it starts on the IHDR.
+ */
+void
+png_set_sig_bytes(png_structp png_ptr, int num_bytes)
+{
+ png_debug(1, "in png_set_sig_bytes\n");
+ if (num_bytes > 8)
+ png_error(png_ptr, "Too many bytes for PNG signature.");
+
+ png_ptr->sig_bytes = num_bytes < 0 ? 0 : num_bytes;
+}
+
+/* Checks whether the supplied bytes match the PNG signature. We allow
+ * checking less than the full 8-byte signature so that those apps that
+ * already read the first few bytes of a file to determine the file type
+ * can simply check the remaining bytes for extra assurance. Returns
+ * an integer less than, equal to, or greater than zero if sig is found,
+ * respectively, to be less than, to match, or be greater than the correct
+ * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ */
+int
+png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
+{
+ if (num_to_check > 8)
+ num_to_check = 8;
+ else if (num_to_check < 1)
+ return 0;
+
+ if (start > 7)
+ return 0;
+
+ if (start + num_to_check > 8)
+ num_to_check = 8 - start;
+
+ return (png_memcmp(&sig[start], &png_sig[start], num_to_check));
+}
+
+/* (Obsolete) function to check signature bytes. It does not allow one
+ to check a partial signature. This function will be removed in the
+ future - use png_sig_cmp(). */
+int
+png_check_sig(png_bytep sig, int num)
+{
+ return !png_sig_cmp(sig, (png_size_t)0, (png_size_t)num);
+}
+
+/* Function to allocate memory for zlib. */
+voidpf
+png_zalloc(voidpf png_ptr, uInt items, uInt size)
+{
+ png_voidp ptr;
+ png_uint_32 num_bytes;
+
+ num_bytes = (png_uint_32)items * size;
+ ptr = png_malloc((png_structp)png_ptr, num_bytes);
+ if (num_bytes > (png_uint_32)0x8000)
+ {
+ png_memset(ptr, 0, (png_size_t)0x8000L);
+ png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
+ (png_size_t)(num_bytes - (png_uint_32)0x8000L));
+ }
+ else
+ {
+ png_memset(ptr, 0, (png_size_t)num_bytes);
+ }
+ return (voidpf)(ptr);
+}
+
+/* function to free memory for zlib */
+void
+png_zfree(voidpf png_ptr, voidpf ptr)
+{
+ png_free((png_structp)png_ptr, (png_voidp)ptr);
+}
+
+/* Reset the CRC variable to 32 bits of 1's. Care must be taken
+ in case CRC is > 32 bits to leave the top bits 0. */
+void
+png_reset_crc(png_structp png_ptr)
+{
+ /* set CRC to all 1's */
+#ifdef PNG_USE_OWN_CRC
+ png_ptr->crc = 0xffffffffL;
+#else
+ png_ptr->crc = crc32(0, Z_NULL, 0);
+#endif
+}
+
+#ifdef PNG_USE_OWN_CRC
+/* Table of CRCs of all 8-bit messages. By default, we use the tables made
+ by zlib, to save some memory. If you wish to png_malloc() this
+ table, turn this into a pointer, and png_malloc() it in make_crc_table().
+ You may then want to hook it into png_struct and free it with the
+ destroy functions. Another alternative is to pre-fill the table. */
+static png_uint_32 crc_table[256];
+
+/* Flag: has the table been computed? Initially false. */
+static int crc_table_computed = 0;
+
+/* make the table for a fast crc */
+static void
+make_crc_table(void)
+{
+ png_uint_32 c;
+ int n, k;
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (png_uint_32)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? 0xedb88320L ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+}
+
+/* Update a running CRC with the bytes buf[0..len-1] - the CRC should be
+ initialized to all 1's, and the transmitted value is the 1's complement
+ of the final running CRC. */
+static png_uint_32
+update_crc(png_uint_32 crc, png_bytep buf, png_size_t len)
+{
+ png_uint_32 c;
+ png_bytep p;
+ png_uint_32 n;
+
+ c = crc;
+ p = buf;
+ n = len;
+
+ if (!crc_table_computed)
+ {
+ make_crc_table();
+ }
+
+ if (n > 0) do
+ {
+ c = crc_table[(png_byte)((c ^ (*p++)) & 0xff)] ^ (c >> 8);
+ } while (--n);
+
+ return c;
+}
+#endif /* PNG_USE_OWN_CRC */
+
+/* Calculate the CRC over a section of data. We can only pass as
+ much data to this routine as the largest single buffer size. We
+ also check that this data will actually be used before going to the
+ trouble of calculating it. */
+void
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+{
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ if (need_crc)
+#ifdef PNG_USE_OWN_CRC
+ png_ptr->crc = update_crc(png_ptr->crc, ptr, length);
+#else
+ png_ptr->crc = crc32(png_ptr->crc, ptr, length);
+#endif
+}
+
+/* Allocate the memory for an info_struct for the application. We don't
+ really need the png_ptr, but it could potentially be useful in the
+ future. This should be used in favour of malloc(sizeof(png_info))
+ and png_info_init() so that applications that want to use a shared
+ libpng don't have to be recompiled if png_info changes size. */
+png_infop
+png_create_info_struct(png_structp png_ptr)
+{
+ png_infop info_ptr;
+
+ png_debug(1, "in png_create_info_struct\n");
+ if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL)
+ {
+ png_info_init(info_ptr);
+ }
+
+ return info_ptr;
+}
+
+/* This function frees the memory associated with a single info struct.
+ Normally, one would use either png_destroy_read_struct() or
+ png_destroy_write_struct() to free an info struct, but this may be
+ useful for some applications. */
+void
+png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
+{
+ png_infop info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_info_struct\n");
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_info_destroy(png_ptr, info_ptr);
+
+ png_destroy_struct((png_voidp)info_ptr);
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+}
+
+/* Initialize the info structure. This is now an internal function (0.89)
+ and applications using it are urged to use png_create_info_struct()
+ instead. */
+void
+png_info_init(png_infop info_ptr)
+{
+ png_debug(1, "in png_info_init\n");
+ /* set everything to 0 */
+ png_memset(info_ptr, 0, sizeof (png_info));
+}
+
+/* This is an internal routine to free any memory that the info struct is
+ * pointing to before re-using it or freeing the struct itself. Recall
+ * that png_free() checks for NULL pointers for us.
+ */
+void
+png_info_destroy(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ int i;
+
+ png_debug(1, "in png_info_destroy\n");
+ if (info_ptr->text != NULL)
+ {
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_free(png_ptr, info_ptr->text[i].key);
+ }
+ png_free(png_ptr, info_ptr->text);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ if (info_ptr->pcal_params != NULL)
+ {
+ for (i = 0; i < info_ptr->pcal_nparams; i++)
+ {
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+ }
+ png_free(png_ptr, info_ptr->pcal_params);
+ }
+#endif
+
+ png_info_init(info_ptr);
+}
+
+/* This function returns a pointer to the io_ptr associated with the user
+ functions. The application should free any memory associated with this
+ pointer before png_write_destroy() or png_read_destroy() are called. */
+png_voidp
+png_get_io_ptr(png_structp png_ptr)
+{
+ return png_ptr->io_ptr;
+}
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the default input/output functions for the PNG file. If you
+ use your own read or write routines, you can call either png_set_read_fn()
+ or png_set_write_fn() instead of png_init_io(). */
+void
+png_init_io(png_structp png_ptr, FILE *fp)
+{
+ png_debug(1, "in png_init_io\n");
+ png_ptr->io_ptr = (png_voidp)fp;
+}
+#endif
diff --git a/gs/libpng/png.h b/gs/libpng/png.h
new file mode 100644
index 000000000..b3338ffc8
--- /dev/null
+++ b/gs/libpng/png.h
@@ -0,0 +1,1835 @@
+
+/* png.h - header file for PNG reference library
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+
+ BETA NOTICE:
+ This is a beta version. It reads and writes valid files on the
+ platforms I have, and has had a wide testing program. You may
+ have to modify the includes below to get it to work on your
+ system, and you may have to supply the correct compiler flags in
+ the makefile if you can't find a makefile suitable for your
+ operating system/compiler combination. Read libpng.txt for more
+ information, including how to contact the authors if you have any
+ problems, or if you want your compiler/platform to be supported in
+ the next official libpng release.
+
+ See libpng.txt for more information.
+
+ Contributing Authors:
+ John Bowler
+ Sam Bushell
+ Kevin Bracey
+ Andreas Dilger
+ Magnus Holmgren
+ Dave Martindale
+ Greg Roelofs
+ Guy Eric Schalnat
+ Paul Schmidt
+ Tom Tanner
+ Tim Wegner
+
+ The contributing authors would like to thank all those who helped
+ with testing, bug fixes, and patience. This wouldn't have been
+ possible without all of you.
+
+ Thanks to Frank J. T. Wojcik for helping with the documentation.
+
+ The PNG Reference Library is supplied "AS IS". The Contributing Authors
+ and Group 42, Inc. disclaim all warranties, expressed or implied,
+ including, without limitation, the warranties of merchantability and of
+ fitness for any purpose. The Contributing Authors and Group 42, Inc.
+ assume no liability for direct, indirect, incidental, special, exemplary,
+ or consequential damages, which may result from the use of the PNG
+ Reference Library, even if advised of the possibility of such damage.
+
+ Permission is hereby granted to use, copy, modify, and distribute this
+ source code, or portions hereof, for any purpose, without fee, subject
+ to the following restrictions:
+ 1. The origin of this source code must not be misrepresented.
+ 2. Altered versions must be plainly marked as such and must not be
+ misrepresented as being the original source.
+ 3. This Copyright notice may not be removed or altered from any source or
+ altered source distribution.
+
+ The Contributing Authors and Group 42, Inc. specifically permit, without
+ fee, and encourage the use of this source code as a component to
+ supporting the PNG file format in commercial products. If you use this
+ source code in a product, acknowledgment is not required but would be
+ appreciated.
+*/
+
+#ifndef _PNG_H
+#define _PNG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* This is not the place to learn how to use libpng. The file libpng.txt
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build. This file is useful for looking
+ * at the actual function definitions and structure components.
+ */
+
+/* include the compression library's header */
+#include "zlib.h"
+
+/* include all user configurable info */
+#include "pngconf.h"
+
+/* This file is arranged in several sections. The first section contains
+ * structure and type definitions. The second section contains the external
+ * library functions, while the third has the internal library functions,
+ * which applications aren't expected to use directly.
+ */
+
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "0.96"
+
+/* careful here. At one time, I wanted to use 082, but that would be octal.
+ * Version 1.0 will be 100 here, etc.
+ */
+#define PNG_LIBPNG_VER 96
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#ifndef PNG_NO_EXTERN
+/* Version information for C files, stored in png.c. This had better match
+ * the version above.
+ */
+extern char png_libpng_ver[];
+
+/* Structures to facilitate easy interlacing. See png.c for more details */
+extern int FARDATA png_pass_start[];
+extern int FARDATA png_pass_inc[];
+extern int FARDATA png_pass_ystart[];
+extern int FARDATA png_pass_yinc[];
+extern int FARDATA png_pass_mask[];
+extern int FARDATA png_pass_dsp_mask[];
+/* These aren't currently used. If you need them, see png.c for more details
+extern int FARDATA png_pass_width[];
+extern int FARDATA png_pass_height[];
+*/
+#endif /* PNG_NO_EXTERN */
+
+/* Three color definitions. The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
+typedef struct png_color_struct
+{
+ png_byte red;
+ png_byte green;
+ png_byte blue;
+} png_color;
+typedef png_color FAR * png_colorp;
+typedef png_color FAR * FAR * png_colorpp;
+
+typedef struct png_color_16_struct
+{
+ png_byte index; /* used for palette files */
+ png_uint_16 red; /* for use in red green blue files */
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 gray; /* for use in grayscale files */
+} png_color_16;
+typedef png_color_16 FAR * png_color_16p;
+typedef png_color_16 FAR * FAR * png_color_16pp;
+
+typedef struct png_color_8_struct
+{
+ png_byte red; /* for use in red green blue files */
+ png_byte green;
+ png_byte blue;
+ png_byte gray; /* for use in grayscale files */
+ png_byte alpha; /* for alpha channel files */
+} png_color_8;
+typedef png_color_8 FAR * png_color_8p;
+typedef png_color_8 FAR * FAR * png_color_8pp;
+
+/* png_text holds the text in a PNG file, and whether they are compressed
+ in the PNG file or not. The "text" field points to a regular C string. */
+typedef struct png_text_struct
+{
+ int compression; /* compression value, see PNG_TEXT_COMPRESSION_ */
+ png_charp key; /* keyword, 1-79 character description of "text" */
+ png_charp text; /* comment, may be an empty string (ie "") */
+ png_size_t text_length; /* length of "text" field */
+} png_text;
+typedef png_text FAR * png_textp;
+typedef png_text FAR * FAR * png_textpp;
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE -1
+#define PNG_TEXT_COMPRESSION_zTXt 0
+#define PNG_TEXT_COMPRESSION_LAST 1 /* Not a valid value */
+
+/* png_time is a way to hold the time in an machine independent way.
+ Two conversions are provided, both from time_t and struct tm. There
+ is no portable way to convert to either of these structures, as far
+ as I know. If you know of a portable way, send it to me. As a side
+ note - PNG is Year 2000 compliant! */
+typedef struct png_time_struct
+{
+ png_uint_16 year; /* full year, as in, 1995 */
+ png_byte month; /* month of year, 1 - 12 */
+ png_byte day; /* day of month, 1 - 31 */
+ png_byte hour; /* hour of day, 0 - 23 */
+ png_byte minute; /* minute of hour, 0 - 59 */
+ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
+} png_time;
+typedef png_time FAR * png_timep;
+typedef png_time FAR * FAR * png_timepp;
+
+/* png_info is a structure that holds the information in a PNG file so
+ * that the application can find out the characteristics of the image.
+ * If you are reading the file, this structure will tell you what is
+ * in the PNG file. If you are writing the file, fill in the information
+ * you want to put into the PNG file, then call png_write_info().
+ * The names chosen should be very close to the PNG specification, so
+ * consult that document for information about the meaning of each field.
+ *
+ * With libpng < 0.95, it was only possible to directly set and read the
+ * the values in the png_info_struct, which meant that the contents and
+ * order of the values had to remain fixed. With libpng 0.95 and later,
+ * however, * there are now functions which abstract the contents of
+ * png_info_struct from the application, so this makes it easier to use
+ * libpng with dynamic libraries, and even makes it possible to use
+ * libraries that don't have all of the libpng ancillary chunk-handing
+ * functionality.
+ *
+ * In any case, the order of the parameters in png_info_struct should NOT
+ * be changed for as long as possible to keep compatibility with applications
+ * that use the old direct-access method with png_info_struct.
+ */
+typedef struct png_info_struct
+{
+ /* the following are necessary for every PNG file */
+ png_uint_32 width; /* width of image in pixels (from IHDR) */
+ png_uint_32 height; /* height of image in pixels (from IHDR) */
+ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
+ png_size_t rowbytes; /* bytes needed to hold an untransformed row */
+ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
+ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
+ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+
+ /* The following is informational only on read, and not used on writes. */
+ png_byte channels; /* number of data channels per pixel (1, 3, 4)*/
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte spare_byte; /* to align the data, and for future use */
+ png_byte signature[8]; /* magic bytes read by libpng from start of file */
+
+ /* The rest of the data is optional. If you are reading, check the
+ * valid field to see if the information in these are valid. If you
+ * are writing, set the valid field to those chunks you want written,
+ * and initialize the appropriate fields below.
+ */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+ /* The gAMA chunk describes the gamma characteristics of the system
+ * on which the image was created, normally in the range [1.0, 2.5].
+ * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
+ */
+ float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* The tEXt and zTXt chunks contain human-readable textual data in
+ * uncompressed and compressed forms, respectively. The data in "text"
+ * is an array of pointers to uncompressed, null-terminated C strings.
+ * Each chunk has a keyword which describes the textual data contained
+ * in that chunk. Keywords are not required to be unique, and the text
+ * string may be empty. Any number of text chunks may be in an image.
+ */
+ int num_text; /* number of comments read/to write */
+ int max_text; /* current size of text array */
+ png_textp text; /* array of comments read/to write */
+#endif /* PNG_READ_tEXt/zTXt_SUPPORTED || PNG_WRITE_tEXt/zTXt_SUPPORTED */
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+ /* The tIME chunk holds the last time the displayed image data was
+ * modified. See the png_time struct for the contents of this struct.
+ */
+ png_time mod_time;
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+ /* The sBIT chunk specifies the number of significant high-order bits
+ * in the pixel data. Values are in the range [1, bit_depth], and are
+ * only specified for the channels in the pixel data. The contents of
+ * the low-order bits is not specified. Data is valid if
+ * (valid & PNG_INFO_sBIT) is non-zero.
+ */
+ png_color_8 sig_bit; /* significant bits in color channels */
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+ /* The tRNS chunk supplies transparency data for paletted images and
+ * other image types that don't need a full alpha channel. There are
+ * "num_trans" transparency values for a paletted image, stored in the
+ * same order as the palette colors, starting from index 0. Values
+ * for the data are in the range [0, 255], ranging from fully transparent
+ * to fully opaque, respectively. For non-paletted images, there is a
+ * single color specified which should be treated as fully transparent.
+ * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+ */
+ png_bytep trans; /* transparent values for paletted image */
+ png_color_16 trans_values; /* transparent color for non-palette image */
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+ /* The bKGD chunk gives the suggested image background color if the
+ * display program does not have its own background color and the image
+ * is needs to composited onto a background before display. The colors
+ * in "background" are normally in the same color space/depth as the
+ * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+ */
+ png_color_16 background;
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+ * and downwards from the top-left corner of the display, page, or other
+ * application-specific co-ordinate space. See the PNG_OFFSET_ defines
+ * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
+ */
+ png_uint_32 x_offset; /* x offset on page */
+ png_uint_32 y_offset; /* y offset on page */
+ png_byte offset_unit_type; /* offset units type */
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ /* The pHYs chunk gives the physical pixel density of the image for
+ * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+ */
+ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+ png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+ /* The hIST chunk contains the relative frequency or importance of the
+ * various palette entries, so that a viewer can intelligently select a
+ * reduced-color palette, if required. Data is an array of "num_palette"
+ * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+ * is non-zero.
+ */
+ png_uint_16p hist;
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+ /* The cHRM chunk describes the CIE color characteristics of the monitor
+ * on which the PNG was created. This data allows the viewer to do gamut
+ * mapping of the input image to ensure that the viewer sees the same
+ * colors in the image as the creator. Values are in the range
+ * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero.
+ */
+ float x_white;
+ float y_white;
+ float x_red;
+ float y_red;
+ float x_green;
+ float y_green;
+ float x_blue;
+ float y_blue;
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+ /* The pCAL chunk describes a transformation between the stored pixel
+ * values and original physcical data values used to create the image.
+ * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+ * range given by [pcal_X0, pcal_X1], and are further transformed by a
+ * (possibly non-linear) transformation function given by "pcal_type"
+ * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
+ * defines below, and the PNG-Group's Scientific Visualization extension
+ * chunks document png-scivis-19970203 for a complete description of the
+ * transformations and how they should be implemented, as well as the
+ * png-extensions document for a description of the ASCII parameter
+ * strings. Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+ */
+ png_charp pcal_purpose; /* pCAL chunk description string */
+ png_int_32 pcal_X0; /* minimum value */
+ png_int_32 pcal_X1; /* maximum value */
+ png_charp pcal_units; /* Latin-1 string giving physical units */
+ png_charpp pcal_params; /* ASCII strings containing parameter values */
+ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
+ png_byte pcal_nparams; /* number of parameters given in pcal_params */
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
+} png_info;
+typedef png_info FAR * png_infop;
+typedef png_info FAR * FAR * png_infopp;
+
+/* These describe the color_type field in png_info. */
+/* color type masks */
+#define PNG_COLOR_MASK_PALETTE 1
+#define PNG_COLOR_MASK_COLOR 2
+#define PNG_COLOR_MASK_ALPHA 4
+
+/* color types. Note that not all combinations are legal */
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+
+/* This is for compression type. PNG 1.0 only defines the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0 only defines the single type. */
+#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */
+#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type. These values should NOT be changed. */
+#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST 2 /* Not a valid value */
+
+/* These are for the oFFs chunk. These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST 2 /* Not a valid value */
+
+/* These are for the pCAL chunk. These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR 0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST 4 /* Not a valid value */
+
+/* These are for the pHYs chunk. These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER 1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST 2 /* Not a valid value */
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file. The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
+#define PNG_INFO_gAMA 0x0001
+#define PNG_INFO_sBIT 0x0002
+#define PNG_INFO_cHRM 0x0004
+#define PNG_INFO_PLTE 0x0008
+#define PNG_INFO_tRNS 0x0010
+#define PNG_INFO_bKGD 0x0020
+#define PNG_INFO_hIST 0x0040
+#define PNG_INFO_pHYs 0x0080
+#define PNG_INFO_oFFs 0x0100
+#define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
+
+/* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+ * the routines for other purposes.
+ */
+typedef struct png_row_info_struct
+{
+ png_uint_32 width; /* width of row */
+ png_size_t rowbytes; /* number of bytes in row */
+ png_byte color_type; /* color type of row */
+ png_byte bit_depth; /* bit depth of row */
+ png_byte channels; /* number of channels (1, 2, 3, or 4) */
+ png_byte pixel_depth; /* bits per pixel (depth * channels) */
+} png_row_info;
+
+typedef png_row_info FAR * png_row_infop;
+typedef png_row_info FAR * FAR * png_row_infopp;
+
+/* These are the function types for the I/O functions, and the functions which
+ * modify the default I/O functions to user I/O functions. The png_error_ptr
+ * type should match that of user supplied warning and error functions, while
+ * the png_rw_ptr type should match that of the user read/write data functions.
+ */
+typedef struct png_struct_def png_struct;
+typedef png_struct FAR * png_structp;
+
+typedef void (*png_error_ptr) PNGARG((png_structp, png_const_charp));
+typedef void (*png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
+typedef void (*png_flush_ptr) PNGARG((png_structp));
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+typedef void (*png_progressive_info_ptr) PNGARG((png_structp, png_infop));
+typedef void (*png_progressive_end_ptr) PNGARG((png_structp, png_infop));
+typedef void (*png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
+ png_uint_32, int));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+/* The structure that holds the information to read and write PNG files.
+ * The only people who need to care about what is inside of this are the
+ * people who will be modifying the library for their own special needs.
+ * It should NOT be accessed directly by an application, except to store
+ * the jmp_buf.
+ */
+
+struct png_struct_def
+{
+ jmp_buf jmpbuf; /* used in png_error */
+
+ png_error_ptr error_fn; /* function for printing errors and aborting */
+ png_error_ptr warning_fn; /* function for printing warnings */
+ png_voidp error_ptr; /* user supplied struct for error functions */
+ png_rw_ptr write_data_fn; /* function for writing output data */
+ png_rw_ptr read_data_fn; /* function for reading input data */
+ png_voidp io_ptr; /* ptr to application struct for I/O functions*/
+
+ png_uint_32 mode; /* tells us whre we are in the PNG file */
+ png_uint_32 flags; /* flags indicating various things to libpng */
+ png_uint_32 transformations; /* which transformations to perform */
+
+ z_stream zstream; /* pointer to decompression structure (below) */
+ png_bytep zbuf; /* buffer for zlib */
+ png_size_t zbuf_size; /* size of zbuf */
+ int zlib_level; /* holds zlib compression level */
+ int zlib_method; /* holds zlib compression method */
+ int zlib_window_bits; /* holds zlib compression window bits */
+ int zlib_mem_level; /* holds zlib compression memory level */
+ int zlib_strategy; /* holds zlib compression strategy */
+
+ png_uint_32 width; /* width of image in pixels */
+ png_uint_32 height; /* height of image in pixels */
+ png_uint_32 num_rows; /* number of rows in current pass */
+ png_uint_32 usr_width; /* width of row at start of write */
+ png_size_t rowbytes; /* size of row in bytes */
+ png_size_t irowbytes; /* size of current interlaced row in bytes */
+ png_uint_32 iwidth; /* width of current interlaced row in pixels */
+ png_uint_32 row_number; /* current row in interlace pass */
+ png_bytep prev_row; /* buffer to save previous (unfiltered) row */
+ png_bytep row_buf; /* buffer to save current (unfiltered) row */
+ png_bytep sub_row; /* buffer to save "sub" row when filtering */
+ png_bytep up_row; /* buffer to save "up" row when filtering */
+ png_bytep avg_row; /* buffer to save "avg" row when filtering */
+ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
+ png_row_info row_info; /* used for transformation routines */
+
+ png_uint_32 idat_size; /* current IDAT size for read */
+ png_uint_32 crc; /* current chunk CRC value */
+ png_colorp palette; /* palette from the input file */
+ png_uint_16 num_palette; /* number of color entries in palette */
+ png_uint_16 num_trans; /* number of transparency values */
+ png_byte chunk_name[5]; /* null-terminated name of current chunk */
+ png_byte compression; /* file compression type (always 0) */
+ png_byte filter; /* file filter type (always 0) */
+ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+ png_byte pass; /* current interlace pass (0 - 6) */
+ png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte usr_bit_depth; /* bit depth of users row */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte channels; /* number of channels in file */
+ png_byte usr_channels; /* channels at start of write */
+ png_byte sig_bytes; /* magic bytes read/written from start of file */
+
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+ png_byte filler; /* filler byte for 24->32-bit pixel expansion */
+#endif /* PNG_READ_FILLER_SUPPORTED */
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ png_byte background_gamma_type;
+ float background_gamma;
+ png_color_16 background; /* background color in screen gamma space */
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+#endif /* PNG_READ_GAMMA && PNG_READ_bKGD_SUPPORTED */
+#endif /* PNG_READ_bKGD_SUPPORTED */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_flush_ptr output_flush_fn;/* Function for flushing output */
+ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
+ png_uint_32 flush_rows; /* number of rows written since last flush */
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ int gamma_shift; /* number of "insignificant" bits 16-bit gamma */
+ float gamma; /* file gamma value */
+ float display_gamma; /* display gamma value */
+#endif /* PNG_READ_GAMMA_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep gamma_table; /* gamma table for 8 bit depth files */
+ png_bytep gamma_from_1; /* converts from 1.0 to screen */
+ png_bytep gamma_to_1; /* converts from file to 1.0 */
+ png_uint_16pp gamma_16_table; /* gamma table for 16 bit depth files */
+ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
+ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_WRITE_GAMMA_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined (PNG_READ_sBIT_SUPPORTED)
+ png_color_8 sig_bit; /* significant bits in each available channel */
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_READ_sBIT_SUPPORTED */
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+ png_color_8 shift; /* shift for significant bit tranformation */
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep trans; /* transparency values for paletted files */
+ png_color_16 trans_values; /* transparency values for non-paletted files */
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_READ_BACKGROUND_SUPPORTED */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_info_ptr info_fn; /* called after header data fully read */
+ png_progressive_row_ptr row_fn; /* called after each row is decoded */
+ png_progressive_end_ptr end_fn; /* called after image is complete */
+ png_bytep save_buffer_ptr; /* current location in save_buffer */
+ png_bytep save_buffer; /* buffer for previously read data */
+ png_bytep current_buffer_ptr; /* current location in current_buffer */
+ png_bytep current_buffer; /* buffer for recently used data */
+ png_uint_32 push_length; /* size of current input chunk */
+ png_uint_32 skip_length; /* bytes to skip in input data */
+ png_size_t save_buffer_size; /* amount of data now in save_buffer */
+ png_size_t save_buffer_max; /* total size of save_buffer */
+ png_size_t buffer_size; /* total amount of available input data */
+ png_size_t current_buffer_size; /* amount of data now in current_buffer */
+ int process_mode; /* what push library is currently doing */
+ int cur_palette; /* current push library palette index */
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ png_size_t current_text_size; /* current size of text input data */
+ png_size_t current_text_left; /* how much text left to read in input */
+ png_charp current_text; /* current text chunk buffer */
+ png_charp current_text_ptr; /* current location in current_text */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_READ_tEXt/zTXt_SUPPORTED */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* for the Borland special 64K segment handler */
+ png_bytepp offset_table_ptr;
+ png_bytep offset_table;
+ png_uint_16 offset_table_number;
+ png_uint_16 offset_table_count;
+ png_uint_16 offset_table_count_free;
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED&&__TURBOC__&&!_Windows&&!__FLAT__ */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_bytep palette_lookup; /* lookup table for dithering */
+ png_bytep dither_index; /* index translation for palette files */
+ png_uint_16p hist; /* histogram */
+#endif /* PNG_READ_DITHER_SUPPORTED */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_byte heuristic_method; /* heuristic for row filter selection */
+ png_byte num_prev_filters; /* number of weights for previous rows */
+ png_bytep prev_filters; /* filter type(s) of previous row(s) */
+ png_uint_16p filter_weights; /* weight(s) for previous line(s) */
+ png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
+ png_uint_16p filter_costs; /* relative filter calculation cost */
+ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+};
+
+typedef png_struct FAR * FAR * png_structpp;
+
+/* Here are the function definitions most commonly used. This is not
+ * the place to find out how to use libpng. See libpng.txt for the
+ * full explanation, see example.c for the summary. This just provides
+ * a simple one line of the use of each function.
+ */
+
+/* Tell lib we have already handled the first <num_bytes> magic bytes.
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
+ int num_bytes));
+
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file. Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise. Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
+ png_size_t num_to_check));
+
+/* Simple signature checking function. This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+extern PNG_EXPORT(png_structp,png_create_read_struct)
+ PNGARG((png_charp user_png_ver, voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warn_fn));
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory */
+extern PNG_EXPORT(png_structp,png_create_write_struct)
+ PNGARG((png_const_charp user_png_ver, voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+/* Allocate and initialize the info structure */
+extern PNG_EXPORT(png_infop,png_create_info_struct)
+ PNGARG((png_structp png_ptr));
+
+/* Initialize the info structure (old interface - NOT DLL EXPORTED) */
+extern void png_info_init PNGARG((png_infop info_ptr));
+
+/* Writes all the PNG information before the image. */
+extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the information before the actual image data. */
+extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* convert from a struct tm to png_time */
+extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
+ struct tm FAR * ttime));
+
+/* convert from time_t to png_time. Uses gmtime() */
+extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
+ time_t ttime));
+#endif /* PNG_WRITE_tIME_SUPPORTED */
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha if available. */
+extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_EXPAND_SUPPORTED */
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* Use blue, green, red order for pixels. */
+extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_BGR_SUPPORTED || PNG_WRITE_BGR_SUPPORTED */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* Expand the grayscale to 24 bit RGB if necessary. */
+extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Reduce RGB to grayscale. (Not yet implemented) */
+extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */
+
+extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
+ png_colorp palette));
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_ALPHA_SUPPORTED || PNG_WRITE_SWAP_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 24-bit RGB images. */
+extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
+ png_uint_32 filler, int flags));
+
+/* The values of the PNG_FILLER_ defines should NOT be changed */
+#define PNG_FILLER_BEFORE 0
+#define PNG_FILLER_AFTER 1
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* Swap bytes in 16 bit depth files. */
+extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_SUPPORTED || PNG_WRITE_SWAP_SUPPORTED */
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* Use 1 byte per pixel in 1, 2, or 4 bit depth files. */
+extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACK_SUPPORTED || PNG_WRITE_PACK_SUPPORTED */
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPOR)
+/* Swap packing order of pixels in bytes. */
+extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACKSWAP_SUPPORTED || PNG_WRITE_PACKSWAP_SUPPOR */
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Converts files to legal bit depths. */
+extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
+ png_color_8p true_bits));
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Have the code handle the interlacing. Returns the number of passes. */
+extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INTERLACING_SUPPORTED || PNG_WRITE_INTERLACING_SUPPORTED */
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+/* Invert monocrome files */
+extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INVERT_SUPPORTED || PNG_WRITE_INVERT_SUPPORTED */
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Handle alpha and tRNS by replacing with a background color. */
+extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma));
+#define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+#define PNG_BACKGROUND_GAMMA_SCREEN 1
+#define PNG_BACKGROUND_GAMMA_FILE 2
+#define PNG_BACKGROUND_GAMMA_UNIQUE 3
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip the second byte of information from a 16 bit depth file. */
+extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_16_TO_8_SUPPORTED */
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Turn on dithering, and reduce the palette to the number of colors available. */
+extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette, int maximum_colors,
+ png_uint_16p histogram, int full_dither));
+#endif /* PNG_READ_DITHER_SUPPORTED */
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Handle gamma correction. */
+extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
+ double screen_gamma, double default_file_gamma));
+#endif /* PNG_READ_GAMMA_SUPPORTED */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set how many lines between output flushes - 0 for no flushing */
+extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
+
+/* Flush the current PNG output buffer */
+extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* optional update palette with requested transformations */
+extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
+
+/* optional call to update the users info structure */
+extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read a one or more rows of image data.*/
+extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
+
+/* read a row of data.*/
+extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
+ png_bytep row,
+ png_bytep display_row));
+
+/* read the whole image into memory at once. */
+extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* write a row of image data */
+extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
+ png_bytep row));
+
+/* write a few rows of image data */
+extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_uint_32 num_rows));
+
+/* write the image data */
+extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* writes the end of the PNG file. */
+extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the end of the PNG file. */
+extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* free any memory associated with the png_info_struct */
+extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
+ png_infopp info_ptr_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
+ png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+
+/* free all memory used by the read (old method - NOT DLL EXPORTED) */
+extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_infop end_info_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_write_struct)
+ PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
+
+/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy PNGARG((png_structp png_ptr));
+
+/* set the libpng method of handling chunk CRC errors */
+extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
+ int crit_action, int ancil_action));
+
+/* Values for png_set_crc_action() to say how to handle CRC errors in
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein. Note that it is impossible to "discard" data in a critical
+ * chunk. For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard. These values should NOT be changed.
+ *
+ * value action:critical action:ancillary
+ */
+#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */
+#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */
+#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */
+#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */
+#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */
+#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */
+
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib. These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them. See the compression library
+ * header file (zlib.h) for an explination of the compression functions. */
+
+/* set the filtering method(s) used by libpng. Currently, the only valid
+ * value for "method" is 0 */
+extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
+ int filters));
+
+/* Flags for png_set_filter() to say which filters to use. The flags
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
+ */
+#define PNG_NO_FILTERS 0x00
+#define PNG_FILTER_NONE 0x08
+#define PNG_FILTER_SUB 0x10
+#define PNG_FILTER_UP 0x20
+#define PNG_FILTER_AVG 0x40
+#define PNG_FILTER_PAETH 0x80
+#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
+ PNG_FILTER_AVG | PNG_FILTER_PAETH)
+
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE 0
+#define PNG_FILTER_VALUE_SUB 1
+#define PNG_FILTER_VALUE_UP 2
+#define PNG_FILTER_VALUE_AVG 3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST 5
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows. Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters. This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified. Weights have no influence on
+ * the selection of the first row filter. Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type. Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs. There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs. Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found. If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
+ int heuristic_method, int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs));
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection. These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */
+
+/* Set the library compression level. Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression). Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations. In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
+ int level));
+
+extern PNG_EXPORT(void,png_set_compression_mem_level)
+ PNGARG((png_structp png_ptr, int mem_level));
+
+extern PNG_EXPORT(void,png_set_compression_strategy)
+ PNGARG((png_structp png_ptr, int strategy));
+
+extern PNG_EXPORT(void,png_set_compression_window_bits)
+ PNGARG((png_structp png_ptr, int window_bits));
+
+extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
+ int method));
+
+/* These next functions are called for input/output, memory, and error
+ * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf(). These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn(). See libpng.txt for
+ * more information.
+ */
+
+/* Initialize the input/output for the PNG file to the default functions. */
+extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, FILE *fp));
+
+/* Replace the (error and abort), and warning functions with user
+ * supplied functions. If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling. If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+
+/* Return the user pointer associated with the error functions */
+extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
+
+/* Replace the default data output functions with a user supplied one(s).
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ */
+extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+
+/* Replace the default data input function with a user supplied one. */
+extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr read_data_fn));
+
+/* Return the user pointer associated with the I/O functions */
+extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn));
+
+/* returns the user pointer associated with the push read functions */
+extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
+ PNGARG((png_structp png_ptr));
+
+/* function to be called when data becomes available */
+extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* function which combines rows. Not very much different than the
+ * png_combine_row() call. Is this even used?????
+ */
+extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+
+/* free's a pointer allocated by png_malloc() */
+extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
+
+#if defined(USE_FAR_KEYWORD) /* memory model conversion function */
+extern void *far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,int check));
+#endif /* USE_FAR_KEYWORD */
+
+/* Fatal error in PNG image of libpng - can't continue */
+extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
+ png_const_charp error));
+
+/* Non-fatal error in libpng. Can continue, but may have a problem. */
+extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored. The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr */
+extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row */
+extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+/* Returns number of color channels in image */
+extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+/* Returns pointer to signature string read from PNG header */
+extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p *background));
+#endif /* PNG_READ_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p background));
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *white_x, double *white_y, double *red_x,
+ double *red_y, double *green_x, double *green_y, double *blue_x,
+ double *blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double white_x, double white_y, double red_x,
+ double red_y, double green_x, double green_y, double blue_x, double blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p *hist));
+#endif /* PNG_READ_hIST_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p hist));
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
+ int *bit_depth, int *color_type, int *interlace_type,
+ int *compression_type, int *filter_type));
+
+extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type, int filter_type));
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *offset_x, png_uint_32 *offset_y,
+ int *unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 offset_x, png_uint_32 offset_y,
+ int unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+ int *type, int *nparams, png_charp *units, png_charpp *params));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
+ int type, int nparams, png_charp units, png_charpp params));
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp *palette, int *num_palette));
+
+extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp palette, int num_palette));
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p *sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+/* png_get_text also returns the number of text chunks in text_ptr */
+extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp *text_ptr, int *num_text));
+#endif /* PNG_READ_tEXt_SUPPORTED || PNG_READ_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif /* PNG_READ_tEXt_SUPPORTED || PNG_WRITE_tEXt_SUPPORTED ||
+ PNG_READ_zTXt_SUPPORTED || PNG_WRITE_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep *mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep *trans, int *num_trans,
+ png_color_16p *trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep trans, int num_trans,
+ png_color_16p trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
+
+/* Define PNG_DEBUG at compile time for debugging information. Higher
+ * numbers for PNG_DEBUG mean more debugging information. This has
+ * only been added since version 0.95 so it is not implemented throughout
+ * libpng yet, but more support will be added as needed.
+ */
+#if (PNG_DEBUG > 0)
+#ifndef PNG_DEBUG_FILE
+#define PNG_DEBUG_FILE stderr
+#endif /* PNG_DEBUG_FILE */
+
+#define png_debug(l,m) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))))
+#define png_debug1(l,m,p1) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))),p1)
+#define png_debug2(l,m,p1,p2) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))),p1,p2)
+#else
+#define png_debug(l, m)
+#define png_debug1(l, m, p1)
+#define png_debug2(l, m, p1, p2)
+#endif /* (PNG_DEBUG > 0) */
+
+/* These next functions are used internally in the code. They generally
+ * shouldn't be used unless you are writing code to add or replace some
+ * functionality in libpng. More information about most functions can
+ * be found in the files where the functions are located.
+ */
+
+#if defined(PNG_INTERNAL)
+
+/* Various modes of operation. Note that after an init, mode is set to
+ zero automatically when the structure is created. */
+#define PNG_BEFORE_IHDR 0x00
+#define PNG_HAVE_IHDR 0x01
+#define PNG_HAVE_PLTE 0x02
+#define PNG_HAVE_IDAT 0x04
+#define PNG_AFTER_IDAT 0x08
+#define PNG_HAVE_IEND 0x10
+
+/* push model modes */
+#define PNG_READ_SIG_MODE 0
+#define PNG_READ_CHUNK_MODE 1
+#define PNG_READ_IDAT_MODE 2
+#define PNG_SKIP_MODE 3
+#define PNG_READ_tEXt_MODE 4
+#define PNG_READ_zTXt_MODE 5
+#define PNG_READ_DONE_MODE 6
+#define PNG_ERROR_MODE 7
+
+/* flags for the transformations the PNG library does on the image data */
+#define PNG_BGR 0x0001
+#define PNG_INTERLACE 0x0002
+#define PNG_PACK 0x0004
+#define PNG_SHIFT 0x0008
+#define PNG_SWAP_BYTES 0x0010
+#define PNG_INVERT_MONO 0x0020
+#define PNG_DITHER 0x0040
+#define PNG_BACKGROUND 0x0080
+#define PNG_BACKGROUND_EXPAND 0x0100
+#define PNG_RGB_TO_GRAY 0x0200 /* Not currently implemented */
+#define PNG_16_TO_8 0x0400
+#define PNG_RGBA 0x0800
+#define PNG_EXPAND 0x1000
+#define PNG_GAMMA 0x2000
+#define PNG_GRAY_TO_RGB 0x4000
+#define PNG_FILLER 0x8000
+#define PNG_PACKSWAP 0x10000
+#define PNG_SWAP_ALPHA 0x20000
+#define PNG_STRIP_ALPHA 0x40000
+
+/* flags for png_create_struct */
+#define PNG_STRUCT_PNG 0x0001
+#define PNG_STRUCT_INFO 0x0002
+
+/* Scaling factor for filter heuristic weighting calculations */
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
+#define PNG_COST_SHIFT 3
+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
+
+/* flags for the png_ptr->flags rather than declaring a byte for each one */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
+#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
+#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
+#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
+#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
+#define PNG_FLAG_ZLIB_FINISHED 0x0020
+#define PNG_FLAG_ROW_INIT 0x0040
+#define PNG_FLAG_FILLER_AFTER 0x0080
+#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
+#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
+#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
+#define PNG_FLAG_FREE_PALETTE 0x1000
+#define PNG_FLAG_FREE_TRANS 0x2000
+#define PNG_FLAG_FREE_HIST 0x4000
+#define PNG_FLAG_HAVE_CHUNK_HEADER 0x8000
+#define PNG_FLAG_WROTE_tIME 0x10000
+
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+ PNG_FLAG_CRC_ANCILLARY_NOWARN)
+
+#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
+ PNG_FLAG_CRC_CRITICAL_IGNORE)
+
+#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
+ PNG_FLAG_CRC_CRITICAL_MASK)
+
+/* save typing and make code easier to understand */
+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
+ abs((int)((c1).green) - (int)((c2).green)) + \
+ abs((int)((c1).blue) - (int)((c2).blue)))
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#ifndef PNG_NO_EXTERN
+/* place to hold the signiture string for a PNG file. */
+extern png_byte FARDATA png_sig[];
+
+/* constant strings for known chunk types. If you need to add a chunk,
+ add a string holding the name here. See png.c for more details. We
+ can't selectively include these, since we still check for chunk in the
+ wrong locations with these labels. */
+extern png_byte FARDATA png_IHDR[];
+extern png_byte FARDATA png_IDAT[];
+extern png_byte FARDATA png_IEND[];
+extern png_byte FARDATA png_PLTE[];
+extern png_byte FARDATA png_bKGD[];
+extern png_byte FARDATA png_cHRM[];
+extern png_byte FARDATA png_gAMA[];
+extern png_byte FARDATA png_hIST[];
+extern png_byte FARDATA png_oFFs[];
+extern png_byte FARDATA png_pCAL[];
+extern png_byte FARDATA png_pHYs[];
+extern png_byte FARDATA png_sBIT[];
+extern png_byte FARDATA png_tEXt[];
+extern png_byte FARDATA png_tIME[];
+extern png_byte FARDATA png_tRNS[];
+extern png_byte FARDATA png_zTXt[];
+
+#endif /* PNG_NO_EXTERN */
+
+/* Inline macros to do direct reads of bytes from the input buffer. These
+ * require that you are using an architecture that uses PNG byte ordering
+ * (MSB first) and supports unaligned data storage. I think that PowerPC
+ * in big-endian mode and 680x0 are the only ones that will support this.
+ * The x86 line of processors definitely do not. The png_get_int_32()
+ * routine also assumes we are using two's complement format for negative
+ * values, which is almost certainly true.
+ */
+#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
+#if defined(PNG_READ_pCAL_SUPPORTED)
+#define png_get_int_32(buf) ( *((png_int_32p) (buf)))
+#endif /* PNG_READ_pCAL_SUPPORTED */
+#define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+#define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
+#else
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf));
+PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf));
+#endif /* PNG_BIG_ENDIAN_GET_SUPPORTED */
+
+/* Initialize png_ptr struct for reading, and allocate any other memory
+ * (old interface - NOT DLL EXPORTED) */
+extern void png_read_init PNGARG((png_structp png_ptr));
+
+/* Initialize png_ptr struct for writing, and allocate any other memory
+ * (old interface - NOT DLL EXPORTED) */
+extern void png_write_init PNGARG((png_structp png_ptr));
+
+/* allocate memory for an internal libpng struct */
+PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
+
+/* free memory from internal libpng struct */
+PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
+
+/* free any memory that info_ptr points to and reset struct. */
+PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* Function to allocate memory for zlib. */
+PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
+
+/* function to free memory for zlib */
+PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
+
+/* reset the CRC variable */
+PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
+
+/* Write the "data" buffer to whatever output you are using. */
+PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* read bytes into buf, and update png_ptr->crc */
+PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
+ png_size_t length));
+
+/* read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
+PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
+
+/* read the CRC from the file and compare it to the libpng calculated CRC */
+PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
+
+/* Calculate the CRC over a section of data. Note that we are only
+ * passing a maximum of 64K on systems that have this as a memory limit,
+ * since this is the maximum buffer size we can specify.
+ */
+PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
+ png_size_t length));
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
+#endif
+
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
+ * The only currently known PNG chunk that uses unsigned numbers is
+ * the ancillary extension chunk, pCAL.
+ */
+PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i));
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i));
+#endif
+
+/* place a 16 bit number into a buffer in PNG byte order */
+PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, png_uint_16 i));
+
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+PNG_EXTERN void png_write_chunk PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_bytep data, png_size_t length));
+
+/* Write the start of a PNG chunk - length and chunk name. */
+PNG_EXTERN void png_write_chunk_start PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_uint_32 length));
+
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+PNG_EXTERN void png_write_chunk_data PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+PNG_EXTERN void png_write_chunk_end PNGARG((png_structp png_ptr));
+
+/* simple function to write the signiture */
+PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
+
+/* write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ information. */
+PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
+ png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type));
+
+PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
+ png_uint_32 num_pal));
+
+PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
+ int color_type));
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr,
+ double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y));
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
+ png_color_16p values, int number, int color_type));
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
+ png_color_16p values, int color_type));
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
+ png_uint_32 num_hist));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
+ png_charp key, png_bytepp new_key));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len));
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len, int compression));
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
+ png_uint_32 x_offset, png_uint_32 y_offset, int unit_type));
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
+ png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
+ png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
+ int unit_type));
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
+ png_timep mod_time));
+#endif
+
+/* Called when finished processing a row of data */
+PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
+
+/* Internal use only. Called before first row of data */
+PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
+#endif
+
+/* combine a row of data, dealing with alpha, etc. if requested */
+PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
+ int mask));
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+/* expand an interlaced row */
+PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass, png_uint_32 transformations));
+#endif
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* grab pixels out of a row for an interlaced pass */
+PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass));
+#endif
+
+/* unfilter a row */
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
+ png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
+
+/* Choose the best filter to use and filter the row data */
+PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
+ png_row_infop row_info));
+
+/* Write out the filtered row. */
+PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
+ png_bytep filtered_row));
+/* finish a row while reading, dealing with interlacing passes, etc. */
+PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
+
+/* initialize the row buffers, etc. */
+PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
+/* optional call to update the users info structure */
+PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* these are the functions that do the transformations */
+#if defined(PNG_READ_FILLER_SUPPORTED)
+PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 filler, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPOR)
+PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+PNG_EXTERN void png_do_rgb_to_gray PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p sig_bits));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
+ png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
+
+# if defined(PNG_CORRECT_PALETTE_SUPPORTED)
+PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette));
+# endif
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 bit_depth));
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p bit_depth));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift));
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
+ png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
+PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
+ png_bytep row, png_color_16p trans_value));
+#endif
+
+/* The following decodes the appropriate chunks, and does error correction,
+ * then calls the appropriate callback for the chunk if it is valid */
+
+/* decode the IHDR chunk */
+PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+
+PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
+ png_bytep chunk_name));
+
+/* handle the transformations for reading and writing */
+PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
+
+PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t length));
+PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
+PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#endif /* PNG_INTERNAL */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* do not put anything past this line */
+#endif /* _PNG_H */
diff --git a/gs/libpng/pngconf.h b/gs/libpng/pngconf.h
new file mode 100644
index 000000000..eee01db5b
--- /dev/null
+++ b/gs/libpng/pngconf.h
@@ -0,0 +1,445 @@
+
+/* pngconf.c - machine configurable file for libpng
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+/* Any machine specific code is near the front of this file, so if you
+ are configuring libpng for a machine, you may want to read the section
+ starting here down to where it starts to typedef png_color, png_text,
+ and png_info */
+
+#ifndef PNGCONF_H
+#define PNGCONF_H
+
+/* This is the size of the compression buffer, and thus the size of
+ an IDAT chunk. Make this whatever size you feel is best for your
+ machine. One of these will be allocated per png_struct. When this
+ is full, it writes the data to the disk, and does some other
+ calculations. Making this an extreamly small size will slow
+ the library down, but you may want to experiment to determine
+ where it becomes significant, if you are concerned with memory
+ usage. Note that zlib allocates at least 32Kb also. For readers,
+ this describes the size of the buffer available to read the data in.
+ Unless this gets smaller then the size of a row (compressed),
+ it should not make much difference how big this is. */
+
+#define PNG_ZBUF_SIZE 8192
+
+/* If you are running on a machine where you cannot allocate more
+ than 64K of memory at once, uncomment this. While libpng will not
+ normally need that much memory in a chunk (unless you load up a very
+ large file), zlib needs to know how big of a chunk it can use, and
+ libpng thus makes sure to check any memory allocation to verify it
+ will fit into memory.
+#define PNG_MAX_MALLOC_64K
+*/
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+#define PNG_MAX_MALLOC_64K
+#endif
+
+/* This protects us against compilers which run on a windowing system
+ and thus don't have or would rather us not use the stdio types:
+ stdin, stdout, and stderr. The only one currently used is stderr
+ in png_error() and png_warning(). #defining PNG_NO_STDIO will
+ prevent these from being compiled and used. */
+
+/* #define PNG_NO_STDIO */
+
+/* for FILE. If you are not using standard io, you don't need this */
+#ifndef PNG_NO_STDIO
+#include <stdio.h>
+#endif
+
+/* This macro protects us against machines that don't have function
+ prototypes (ie K&R style headers). If your compiler does not handle
+ function prototypes, define this macro and use the included ansi2knr.
+ I've always been able to use _NO_PROTO as the indicator, but you may
+ need to drag the empty declaration out in front of here, or change the
+ ifdef to suit your own needs. */
+#ifndef PNGARG
+
+#ifdef OF /* zlib prototype munger */
+#define PNGARG(arglist) OF(arglist)
+#else
+
+#ifdef _NO_PROTO
+#define PNGARG(arglist) ()
+#else
+#define PNGARG(arglist) arglist
+#endif /* _NO_PROTO */
+
+#endif /* OF */
+
+#endif /* PNGARG */
+
+/* Try to determine if we are compiling on a Mac */
+#if defined(__MWERKS__) ||defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#define MACOS
+#endif
+
+/* enough people need this for various reasons to include it here */
+#if !defined(MACOS) && !defined(RISCOS)
+#include <sys/types.h>
+#endif
+
+/* This is an attempt to force a single setjmp behaviour on Linux. If
+ the X config stuff didn't define _BSD_SOURCE we wouldn't need this. */
+#ifdef linux
+#ifdef _BSD_SOURCE
+#define _PNG_SAVE_BSD_SOURCE
+#undef _BSD_SOURCE
+#endif
+#ifdef _SETJMP_H
+#error __png_h_already_includes_setjmp_h__
+#error __dont_include_it_again__
+#endif
+#endif /* linux */
+
+/* include setjmp.h for error handling */
+#include <setjmp.h>
+
+#ifdef linux
+#ifdef _PNG_SAVE_BSD_SOURCE
+#define _BSD_SOURCE
+#undef _PNG_SAVE_BSD_SOURCE
+#endif
+#endif /* linux */
+
+#ifdef BSD
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+/* Other defines for things like memory and the like can go here. */
+#ifdef PNG_INTERNAL
+#include <stdlib.h>
+/* Where do we need this???
+#include <ctype.h>
+*/
+
+/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
+ * aren't usually used outside the library (as far as I know), so it is
+ * debatable if they should be exported at all. In the future, when it is
+ * possible to have run-time registry of chunk-handling functions, some of
+ * these will be made available again.
+#define PNG_EXTERN extern
+ */
+#define PNG_EXTERN
+
+/* Other defines specific to compilers can go here. Try to keep
+ them inside an appropriate ifdef/endif pair for portability */
+
+#if defined(MACOS)
+/* We need to check that <math.h> hasn't already been included earlier
+ as it seems it doesn't agree with <fp.h>, yet we should really use
+ <fp.h> if possible. */
+#if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
+#include <fp.h>
+#endif
+#else
+#include <math.h>
+#endif
+
+/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not
+ stdlib.h like it should (I think). Or perhaps this is a C++
+ "feature"? */
+#ifdef __TURBOC__
+#include <mem.h>
+#include "alloc.h"
+#endif
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+/* This controls how fine the dithering gets. As this allocates
+ a largish chunk of memory (32K), those who are not as concerned
+ with dithering quality can decrease some or all of these. */
+#define PNG_DITHER_RED_BITS 5
+#define PNG_DITHER_GREEN_BITS 5
+#define PNG_DITHER_BLUE_BITS 5
+
+/* This controls how fine the gamma correction becomes when you
+ are only interested in 8 bits anyway. Increasing this value
+ results in more memory being used, and more pow() functions
+ being called to fill in the gamma tables. Don't set this
+ value less then 8, and even that may not work (I haven't tested
+ it). */
+
+#define PNG_MAX_GAMMA_8 11
+
+/* This controls how much a difference in gamma we can tolerate before
+ we actually start doing gamma conversion. */
+#define PNG_GAMMA_THRESHOLD 0.05
+
+#endif /* PNG_INTERNAL */
+
+/* The following uses const char * instead of char * for error
+ and warning message functions, so some compilers won't complain.
+ If you want to use const, define PNG_USE_CONST here. It is not
+ normally defined to make configuration easier, as it is not a
+ critical part of the code.
+ */
+#undef PNG_USE_CONST
+
+#ifdef PNG_USE_CONST
+# define PNG_CONST const
+#else
+# define PNG_CONST
+#endif
+
+/* The following defines give you the ability to remove code from the
+ library that you will not be using. I wish I could figure out how to
+ automate this, but I can't do that without making it seriously hard
+ on the users. So if you are not using an ability, change the #define
+ to and #undef, and that part of the library will not be compiled. If
+ your linker can't find a function, you may want to make sure the
+ ability is defined here. Some of these depend upon some others being
+ defined. I haven't figured out all the interactions here, so you may
+ have to experiment awhile to get everything to compile. If you are
+ creating or using a shared library, you probably shouldn't touch this,
+ as it will affect the size of the structures, and this will cause bad
+ things to happen if the library and/or application ever change. */
+
+/* Any transformations you will not be using can be undef'ed here */
+#define PNG_PROGRESSIVE_READ_SUPPORTED
+#define PNG_READ_OPT_PLTE_SUPPORTED
+#define PNG_READ_INTERLACING_SUPPORTED
+#define PNG_READ_EXPAND_SUPPORTED
+#define PNG_READ_SHIFT_SUPPORTED
+#define PNG_READ_PACK_SUPPORTED
+#define PNG_READ_BGR_SUPPORTED
+#define PNG_READ_SWAP_SUPPORTED
+#define PNG_READ_PACKSWAP_SUPPORTED
+#define PNG_READ_INVERT_SUPPORTED
+#define PNG_READ_DITHER_SUPPORTED
+#define PNG_READ_BACKGROUND_SUPPORTED
+#define PNG_READ_16_TO_8_SUPPORTED
+#define PNG_READ_FILLER_SUPPORTED
+#define PNG_READ_GAMMA_SUPPORTED
+#define PNG_READ_GRAY_TO_RGB_SUPPORTED
+#define PNG_READ_SWAP_ALPHA_SUPPORTED
+#define PNG_READ_STRIP_ALPHA_SUPPORTED
+
+#define PNG_WRITE_INTERLACING_SUPPORTED
+#define PNG_WRITE_SHIFT_SUPPORTED
+#define PNG_WRITE_PACK_SUPPORTED
+#define PNG_WRITE_BGR_SUPPORTED
+#define PNG_WRITE_SWAP_SUPPORTED
+#define PNG_WRITE_PACKSWAP_SUPPORTED
+#define PNG_WRITE_INVERT_SUPPORTED
+#define PNG_WRITE_FILLER_SUPPORTED /* This is the same as WRITE_STRIP_ALPHA */
+#define PNG_WRITE_FLUSH_SUPPORTED
+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+
+/* These are currently experimental features */
+#undef PNG_READ_16_TO_8_ACCURATE_SHIFT_SUPPORTED /* very little testing */
+#undef PNG_READ_COMPOSITE_NODIV_SUPPORTED /* very little testing */
+
+/* This is only for PowerPC big-endian and 680x0 systems */
+#undef PNG_READ_BIG_ENDIAN_SUPPORTED /* some testing */
+
+/* These functions are turned off by default, as they will be phased out. */
+#undef PNG_USE_OWN_CRC
+#undef PNG_USELESS_TESTS_SUPPORTED
+#undef PNG_CORRECT_PALETTE_SUPPORTED
+
+/* Any chunks you are not interested in, you can undef here. The
+ * ones that allocate memory may be expecially important (hIST,
+ * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info
+ * a bit smaller. OPT_PLTE only disables the optional palette in RGB
+ * and RGBA images.
+ */
+
+#define PNG_READ_bKGD_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
+#define PNG_READ_hIST_SUPPORTED
+#define PNG_READ_oFFs_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_tEXt_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
+#define PNG_READ_zTXt_SUPPORTED
+
+#define PNG_WRITE_bKGD_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
+#define PNG_WRITE_hIST_SUPPORTED
+#define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
+#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_SUPPORTED
+#define PNG_WRITE_zTXt_SUPPORTED
+
+/* need the time information for reading tIME chunks */
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+#include <time.h>
+#endif
+
+/* Some typedefs to get us started. These should be safe on most of the
+ * common platforms. The typedefs should be at least as large as the
+ * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
+ * don't have to be exactly that size. Some compilers dislike passing
+ * unsigned shorts as function parameters, so you may be better off using
+ * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may
+ * want to have unsigned int for png_uint_32 instead of unsigned long.
+ */
+
+typedef unsigned long png_uint_32;
+typedef long png_int_32;
+typedef unsigned short png_uint_16;
+typedef short png_int_16;
+typedef unsigned char png_byte;
+
+/* This is usually size_t. It is typedef'ed just in case you need it to
+ change (I'm not sure if you will or not, so I thought I'd be safe) */
+typedef size_t png_size_t;
+
+/* The following is needed for medium model support. It cannot be in the
+ * PNG_INTERNAL section. Needs modification for other compilers besides
+ * MSC. Model independent support declares all arrays and pointers to be
+ * large using the far keyword. The zlib version used must also support
+ * model independent data. As of version zlib 1.0.4, the necessary changes
+ * have been made in zlib. The USE_FAR_KEYWORD define triggers other
+ * changes that are needed. (Tim Wegner)
+ */
+
+/* Separate compiler dependencies (problem here is that zlib.h always
+ defines FAR. (SJT) */
+#ifdef __BORLANDC__
+#if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
+#define LDATA 1
+#else
+#define LDATA 0
+#endif
+
+#if !defined(__WIN32__) && !defined(__FLAT__)
+#define PNG_MAX_MALLOC_64K
+#if (LDATA != 1)
+#ifndef FAR
+#define FAR __far
+#endif
+#define USE_FAR_KEYWORD
+#endif /* LDATA != 1 */
+
+/* Possibly useful for moving data out of default segment.
+ Uncomment it if you want. Could also define FARDATA as
+ const if your compiler supports it. (SJT)
+# define FARDATA FAR
+*/
+#endif /* __WIN32__, __FLAT__ */
+
+#endif /* __BORLANDC__ */
+
+
+/* Suggest testing for specific compiler first before testing for
+ FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM,
+ making reliance oncertain keywords suspect. (SJT) */
+
+/* MSC Medium model */
+#if defined(FAR)
+# if defined(M_I86MM)
+# define USE_FAR_KEYWORD
+# define FARDATA FAR
+# include <dos.h>
+# endif
+#endif
+
+/* SJT: default case */
+#ifndef FAR
+# define FAR
+#endif
+
+/* At this point FAR is always defined */
+#ifndef FARDATA
+#define FARDATA
+#endif
+
+/* Add typedefs for pointers */
+typedef void FAR * png_voidp;
+typedef png_byte FAR * png_bytep;
+typedef png_uint_32 FAR * png_uint_32p;
+typedef png_int_32 FAR * png_int_32p;
+typedef png_uint_16 FAR * png_uint_16p;
+typedef png_int_16 FAR * png_int_16p;
+typedef PNG_CONST char FAR * png_const_charp;
+typedef char FAR * png_charp;
+typedef double FAR * png_doublep;
+
+/* Pointers to pointers; i.e. arrays */
+typedef png_byte FAR * FAR * png_bytepp;
+typedef png_uint_32 FAR * FAR * png_uint_32pp;
+typedef png_int_32 FAR * FAR * png_int_32pp;
+typedef png_uint_16 FAR * FAR * png_uint_16pp;
+typedef png_int_16 FAR * FAR * png_int_16pp;
+typedef PNG_CONST char FAR * FAR * png_const_charpp;
+typedef char FAR * FAR * png_charpp;
+typedef double FAR * FAR * png_doublepp;
+
+/* Pointers to pointers to pointers; i.e. pointer to array */
+typedef char FAR * FAR * FAR * png_charppp;
+
+/* libpng typedefs for types in zlib. If zlib changes
+ * or another compression library is used, then change these.
+ * Eliminates need to change all the source files.
+ */
+typedef charf * png_zcharp;
+typedef charf * FAR * png_zcharpp;
+typedef z_stream FAR * png_zstreamp;
+
+/* allow for compilation as dll under windows */
+#ifdef __WIN32DLL__
+#define PNG_EXPORT(type,symbol) __declspec(dllexport) type symbol
+#endif
+
+#ifndef PNG_EXPORT
+#define PNG_EXPORT(t,s) t s
+#endif
+
+
+/* User may want to use these so not in PNG_INTERNAL. Any library functions
+ that are passed far data must be model independent. */
+
+#if defined(USE_FAR_KEYWORD) /* memory model independent fns */
+/* use this to make far-to-near assignments */
+# define CHECK 1
+# define NOCHECK 0
+# define CVT_PTR(ptr) (far_to_near(png_ptr,ptr,CHECK))
+# define CVT_PTR_NOCHECK(ptr) (far_to_near(png_ptr,ptr,NOCHECK))
+# define png_strlen _fstrlen
+# define png_memcmp _fmemcmp /* SJT: added */
+# define png_memcpy _fmemcpy
+# define png_memset _fmemset
+#else /* use the usual functions */
+# define CVT_PTR(ptr) (ptr)
+# define CVT_PTR_NOCHECK(ptr) (ptr)
+# define png_strlen strlen
+# define png_memcmp memcmp /* SJT: added */
+# define png_memcpy memcpy
+# define png_memset memset
+#endif
+/* End of memory model independent support */
+
+/* Just a double check that someone hasn't tried to define something
+ * contradictory.
+ */
+#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K)
+#undef PNG_ZBUF_SIZE
+#define PNG_ZBUF_SIZE 65536
+#endif
+
+#endif /* PNGCONF_H */
+
diff --git a/gs/libpng/pngerror.c b/gs/libpng/pngerror.c
new file mode 100644
index 000000000..70a3ee057
--- /dev/null
+++ b/gs/libpng/pngerror.c
@@ -0,0 +1,112 @@
+
+/* pngerror.c - stub functions for i/o and memory allocation
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+
+ This file provides a location for all error handling. Users which
+ need special error handling are expected to write replacement functions
+ and use png_set_error_fn() to use those functions. See the instructions
+ at each function. */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+static void png_default_error PNGARG((png_structp png_ptr,
+ png_const_charp message));
+static void png_default_warning PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* This function is called whenever there is a fatal error. This function
+ should not be changed. If there is a need to handle errors differently,
+ you should supply a replacement error function and use png_set_error_fn()
+ to replace the error function at run-time. */
+void
+png_error(png_structp png_ptr, png_const_charp message)
+{
+ if (png_ptr->error_fn != NULL)
+ (*(png_ptr->error_fn))(png_ptr, message);
+
+ /* if the following returns or doesn't exist, use the default function,
+ which will not return */
+ png_default_error(png_ptr, message);
+}
+
+/* This function is called whenever there is a non-fatal error. This function
+ should not be changed. If there is a need to handle warnings differently,
+ you should supply a replacement warning function and use
+ png_set_error_fn() to replace the warning function at run-time. */
+void
+png_warning(png_structp png_ptr, png_const_charp message)
+{
+ if (png_ptr->warning_fn != NULL)
+ (*(png_ptr->warning_fn))(png_ptr, message);
+ else
+ png_default_warning(png_ptr, message);
+}
+
+/* This is the default error handling function. Note that replacements for
+ this function MUST NOT RETURN, or the program will likely crash. This
+ function is used by default, or if the program supplies NULL for the
+ error function pointer in png_set_error_fn(). */
+static void
+png_default_error(png_structp png_ptr, png_const_charp message)
+{
+#ifndef PNG_NO_STDIO
+ fprintf(stderr, "libpng error: %s\n", message);
+#endif
+
+#ifdef USE_FAR_KEYWORD
+ {
+ jmp_buf jmpbuf;
+ png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf));
+ longjmp(jmpbuf, 1);
+ }
+#else
+ longjmp(png_ptr->jmpbuf, 1);
+#endif
+}
+
+/* This function is called when there is a warning, but the library thinks
+ it can continue anyway. Replacement functions don't have to do anything
+ here if you don't want to. In the default configuration, png_ptr is
+ not used, but it is passed in case it may be useful. */
+static void
+png_default_warning(png_structp png_ptr, png_const_charp message)
+{
+ if (png_ptr == NULL)
+ return;
+
+#ifndef PNG_NO_STDIO
+ fprintf(stderr, "libpng warning: %s\n", message);
+#endif
+}
+
+/* This function is called when the application wants to use another method
+ of handling errors and warnings. Note that the error function MUST NOT
+ return to the calling routine or serious problems will occur. The return
+ method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) */
+void
+png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn)
+{
+ png_ptr->error_ptr = error_ptr;
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+}
+
+
+/* This function returns a pointer to the error_ptr associated with the user
+ functions. The application should free any memory associated with this
+ pointer before png_write_destroy and png_read_destroy are called. */
+png_voidp
+png_get_error_ptr(png_structp png_ptr)
+{
+ return png_ptr->error_ptr;
+}
+
+
+
diff --git a/gs/libpng/pngget.c b/gs/libpng/pngget.c
new file mode 100644
index 000000000..a2f0f8631
--- /dev/null
+++ b/gs/libpng/pngget.c
@@ -0,0 +1,300 @@
+
+/* pngget.c - retrieval of values from info struct
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+png_uint_32
+png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+{
+ if (info_ptr != NULL)
+ return(info_ptr->valid & flag);
+ else
+ return(0);
+}
+
+png_uint_32
+png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+{
+ if (info_ptr != NULL)
+ return(info_ptr->rowbytes);
+ else
+ return(0);
+}
+
+png_byte
+png_get_channels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (info_ptr != NULL)
+ return(info_ptr->channels);
+ else
+ return(0);
+}
+
+png_bytep
+png_get_signature(png_structp png_ptr, png_infop info_ptr)
+{
+ if (info_ptr != NULL)
+ return(info_ptr->signature);
+ else
+ return(NULL);
+}
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+png_uint_32
+png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
+ png_color_16p *background)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD &&
+ background != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "bKGD");
+ *background = &(info_ptr->background);
+ return (PNG_INFO_bKGD);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+png_uint_32
+png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double *white_x, double *white_y, double *red_x, double *red_y,
+ double *green_x, double *green_y, double *blue_x, double *blue_y)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM)
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = (double)info_ptr->x_white;
+ if (white_y != NULL)
+ *white_y = (double)info_ptr->y_white;
+ if (red_x != NULL)
+ *red_x = (double)info_ptr->x_red;
+ if (red_y != NULL)
+ *red_y = (double)info_ptr->y_red;
+ if (green_x != NULL)
+ *green_x = (double)info_ptr->x_green;
+ if (green_y != NULL)
+ *green_y = (double)info_ptr->y_green;
+ if (blue_x != NULL)
+ *blue_x = (double)info_ptr->x_blue;
+ if (blue_y != NULL)
+ *blue_y = (double)info_ptr->y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+png_uint_32
+png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA &&
+ file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *file_gamma = (double)info_ptr->gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+png_uint_32
+png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST && hist != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "hIST");
+ *hist = info_ptr->hist;
+ return (PNG_INFO_hIST);
+ }
+ return (0);
+}
+#endif
+
+png_uint_32
+png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+ int *color_type, int *interlace_type, int *compression_type,
+ int *filter_type)
+
+{
+ if (info_ptr != NULL && width != NULL && height != NULL &&
+ bit_depth != NULL && color_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "IHDR");
+ *width = info_ptr->width;
+ *height = info_ptr->height;
+ *bit_depth = info_ptr->bit_depth;
+ *color_type = info_ptr->color_type;
+ if (compression_type != NULL)
+ *compression_type = info_ptr->compression_type;
+ if (filter_type != NULL)
+ *filter_type = info_ptr->filter_type;
+ if (interlace_type != NULL)
+ *interlace_type = info_ptr->interlace_type;
+ return (1);
+ }
+ return (0);
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+png_uint_32
+png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *offset_x, png_uint_32 *offset_y, int *unit_type)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs &&
+ offset_x != NULL && offset_y != NULL && unit_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "oFFs");
+ *offset_x = info_ptr->x_offset;
+ *offset_y = info_ptr->y_offset;
+ *unit_type = (int)info_ptr->offset_unit_type;
+ return (PNG_INFO_oFFs);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+png_uint_32
+png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+ png_charp *units, png_charpp *params)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL &&
+ purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+ nparams != NULL && units != NULL && params != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pCAL");
+ *purpose = info_ptr->pcal_purpose;
+ *X0 = info_ptr->pcal_X0;
+ *X1 = info_ptr->pcal_X1;
+ *type = (int)info_ptr->pcal_type;
+ *nparams = (int)info_ptr->pcal_nparams;
+ *units = info_ptr->pcal_units;
+ *params = info_ptr->pcal_params;
+ return (PNG_INFO_pCAL);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+png_uint_32
+png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs &&
+ res_x != NULL && res_y != NULL && unit_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ *res_x = info_ptr->x_pixels_per_unit;
+ *res_y = info_ptr->y_pixels_per_unit;
+ *unit_type = (int)info_ptr->phys_unit_type;
+ return (PNG_INFO_pHYs);
+ }
+ return (0);
+}
+#endif
+
+png_uint_32
+png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
+ int *num_palette)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_PLTE && palette != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "PLTE");
+ *palette = info_ptr->palette;
+ *num_palette = info_ptr->num_palette;
+ png_debug1(3, "num_palette = %d\n", *num_palette);
+ return (PNG_INFO_PLTE);
+ }
+ return (0);
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+png_uint_32
+png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT && sig_bit != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sBIT");
+ *sig_bit = &(info_ptr->sig_bit);
+ return (PNG_INFO_sBIT);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+png_uint_32
+png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
+ int *num_text)
+{
+ if ((info_ptr != NULL) || (info_ptr->num_text > 0))
+ {
+ png_debug1(1, "in %s retrieval function\n",
+ (png_ptr->chunk_name[0] == '\0' ? "text" : png_ptr->chunk_name));
+ if (text_ptr != NULL)
+ *text_ptr = info_ptr->text;
+ if (num_text != NULL)
+ *num_text = info_ptr->num_text;
+ return (info_ptr->num_text);
+ }
+ return(0);
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+png_uint_32
+png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME && mod_time != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tIME");
+ *mod_time = &(info_ptr->mod_time);
+ return (PNG_INFO_tIME);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+png_uint_32
+png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+{
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tRNS");
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && trans != NULL)
+ {
+ *trans = info_ptr->trans;
+ }
+ else if (trans_values != NULL)
+ {
+ *trans_values = &(info_ptr->trans_values);
+ }
+ else
+ {
+ return (0);
+ }
+ *num_trans = info_ptr->num_trans;
+ return (PNG_INFO_tRNS);
+ }
+ return (0);
+}
+#endif
+
diff --git a/gs/libpng/pngmem.c b/gs/libpng/pngmem.c
new file mode 100644
index 000000000..92d275675
--- /dev/null
+++ b/gs/libpng/pngmem.c
@@ -0,0 +1,311 @@
+
+/* pngmem.c - stub functions for memory allocation
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+
+ This file provides a location for all memory allocation. Users which
+ need special memory handling are expected to modify the code in this file
+ to meet their needs. See the instructions at each function. */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Borland DOS special memory handler */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* if you change this, be sure to change the one in png.h also */
+
+/* Allocate memory for a png_struct. The malloc and memset can be replaced
+ by a single call to calloc() if this is thought to improve performance. */
+png_voidp
+png_create_struct(int type)
+{
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return (png_voidp)NULL;
+
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct(png_voidp struct_ptr)
+{
+ if (struct_ptr != NULL)
+ farfree (struct_ptr);
+}
+
+/* Allocate memory. For reasonable files, size should never exceed
+ * 64K. However, zlib may allocate more then 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * Borland seems to have a problem in DOS mode for exactly 64K.
+ * It gives you a segment with an offset of 8 (perhaps to store it's
+ * memory stuff). zlib doesn't like this at all, so we have to
+ * detect and deal with it. This code should not be needed in
+ * Windows or OS/2 modes, and only in 16 bit mode. This code has
+ * been updated by Alexander Lehmann for version 0.89 to waste less
+ * memory.
+ *
+ * Note that we can't use png_size_t for the "size" declaration,
+ * since on some systems a png_size_t is a 16-bit quantity, and as a
+ * result, we would be truncating potentially larger memory requests
+ * (which should cause a fatal error) and introducing major problems.
+ */
+png_voidp
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+ if (png_ptr == NULL || size == 0)
+ return ((voidp)NULL);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+ if (size == (png_uint_32)(65536L))
+ {
+ if (png_ptr->offset_table == NULL)
+ {
+ /* try to see if we need to do any of this fancy stuff */
+ ret = farmalloc(size);
+ if (ret == NULL || ((png_size_t)ret & 0xffff))
+ {
+ int num_blocks;
+ png_uint_32 total_size;
+ png_bytep table;
+ int i;
+ png_byte huge * hptr;
+
+ if (ret != NULL)
+ farfree(ret);
+ ret = NULL;
+
+ num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
+ if (num_blocks < 1)
+ num_blocks = 1;
+ if (png_ptr->zlib_mem_level >= 7)
+ num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
+ else
+ num_blocks++;
+
+ total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
+
+ table = farmalloc(total_size);
+
+ if (table == NULL)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ if ((png_size_t)table & 0xfff0)
+ {
+ png_error(png_ptr, "Farmalloc didn't return normalized pointer");
+ }
+
+ png_ptr->offset_table = table;
+ png_ptr->offset_table_ptr = farmalloc(num_blocks *
+ sizeof (png_bytep));
+
+ if (png_ptr->offset_table_ptr == NULL)
+ {
+ png_error(png_ptr, "Out of memory");
+ }
+
+ hptr = (png_byte huge *)table;
+ if ((png_size_t)hptr & 0xf)
+ {
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr += 16L;
+ }
+ for (i = 0; i < num_blocks; i++)
+ {
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr += 65536L;
+ }
+
+ png_ptr->offset_table_number = num_blocks;
+ png_ptr->offset_table_count = 0;
+ png_ptr->offset_table_count_free = 0;
+ }
+ }
+
+ if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
+ png_error(png_ptr, "Out of Memory");
+
+ ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
+ }
+ else
+ ret = farmalloc(size);
+
+ if (ret == NULL)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return ret;
+}
+
+/* free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed in case it
+ is needed. If ptr is NULL, return without taking any action. */
+void
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+ if (png_ptr->offset_table != NULL)
+ {
+ int i;
+
+ for (i = 0; i < png_ptr->offset_table_count; i++)
+ {
+ if (ptr == png_ptr->offset_table_ptr[i])
+ {
+ ptr = NULL;
+ png_ptr->offset_table_count_free++;
+ break;
+ }
+ }
+ if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
+ {
+ farfree(png_ptr->offset_table);
+ farfree(png_ptr->offset_table_ptr);
+ png_ptr->offset_table = NULL;
+ png_ptr->offset_table_ptr = NULL;
+ }
+ }
+
+ if (ptr != NULL)
+ farfree(ptr);
+}
+
+#else /* Not the Borland DOS special memory handler */
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably.*/
+png_voidp
+png_create_struct(int type)
+{
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return (png_voidp)NULL;
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ if ((struct_ptr = (png_voidp)halloc(size,1)) != NULL)
+# else
+ if ((struct_ptr = (png_voidp)malloc(size)) != NULL)
+# endif
+#endif
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct(png_voidp struct_ptr)
+{
+ if (struct_ptr != NULL)
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(struct_ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(struct_ptr);
+# else
+ free(struct_ptr);
+# endif
+#endif
+}
+
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that. */
+
+png_voidp
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+ if (png_ptr == NULL || size == 0)
+ return (NULL);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ ret = farmalloc((png_size_t)size);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ ret = halloc(size, 1);
+# else
+ ret = malloc(size);
+# endif
+#endif
+
+ if (ret == NULL)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return ret;
+}
+
+/* Free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed in case it
+ is needed. If ptr is NULL, return without taking any action. */
+void
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(ptr);
+# else
+ free(ptr);
+# endif
+#endif
+}
+
+#endif /* Not Borland DOS special memory handler */
+
diff --git a/gs/libpng/pngpread.c b/gs/libpng/pngpread.c
new file mode 100644
index 000000000..2fb1bd623
--- /dev/null
+++ b/gs/libpng/pngpread.c
@@ -0,0 +1,1102 @@
+
+/* pngpread.c - read a png file in push mode
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+
+void
+png_process_data(png_structp png_ptr, png_infop info_ptr,
+ png_bytep buffer, png_size_t buffer_size)
+{
+ png_push_restore_buffer(png_ptr, buffer, buffer_size);
+
+ while (png_ptr->buffer_size)
+ {
+ png_process_some_data(png_ptr, info_ptr);
+ }
+}
+
+/* What we do with the incoming data depends on what we were previously
+ * doing before we ran out of data...
+ */
+void
+png_process_some_data(png_structp png_ptr, png_infop info_ptr)
+{
+ switch (png_ptr->process_mode)
+ {
+ case PNG_READ_SIG_MODE:
+ {
+ png_push_read_sig(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_CHUNK_MODE:
+ {
+ png_push_read_chunk(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_IDAT_MODE:
+ {
+ png_push_read_IDAT(png_ptr);
+ break;
+ }
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ case PNG_READ_tEXt_MODE:
+ {
+ png_push_read_tEXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ case PNG_READ_zTXt_MODE:
+ {
+ png_push_read_zTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+ case PNG_SKIP_MODE:
+ {
+ png_push_crc_finish(png_ptr);
+ break;
+ }
+ default:
+ {
+ png_ptr->buffer_size = 0;
+ break;
+ }
+ }
+}
+
+/* Read any remaining signature bytes from the stream and compare them with
+ * the correct PNG signature. It is possible that this routine is called
+ * with bytes already read from the signature, whether because they have been
+ * checked by the calling application, or from multiple calls to this routine.
+ */
+void
+png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
+{
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ if (png_ptr->buffer_size < num_to_check)
+ {
+ num_to_check = png_ptr->buffer_size;
+ }
+
+ png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),
+ num_to_check);
+ png_ptr->sig_bytes += num_to_check;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ else
+ {
+ if (png_ptr->sig_bytes >= 8)
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+ }
+}
+
+void
+png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
+{
+ /* First we make sure we have enough data for the 4 byte chunk name
+ and the 4 byte chunk length before proceeding with decoding the
+ chunk data. To fully decode each of these chunks, we also make
+ sure we have enough data in the buffer for the 4 byte CRC at the
+ end of every chunk (except IDAT, which is handled separately). */
+ if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
+ }
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* If we reach an IDAT chunk, this means we have read all of the
+ header chunks, and we can start reading the image (or if this
+ is called after the image has been read - we have an error). */
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ if (png_ptr->push_length == 0)
+ return;
+
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ return;
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
+ png_ptr->process_mode = PNG_READ_DONE_MODE;
+ png_push_have_end(png_ptr, info_ptr);
+ }
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ {
+ png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ {
+ png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+ else
+ {
+ png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+ png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER;
+}
+
+void
+png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
+{
+ png_ptr->process_mode = PNG_SKIP_MODE;
+ png_ptr->skip_length = skip;
+}
+
+void
+png_push_crc_finish(png_structp png_ptr)
+{
+ if (png_ptr->skip_length && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->skip_length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->skip_length)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+}
+
+void
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
+{
+ png_bytep ptr;
+
+ ptr = buffer;
+ if (png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->save_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
+ length -= save_size;
+ ptr += save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->current_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+}
+
+void
+png_push_save_buffer(png_structp png_ptr)
+{
+ if (png_ptr->save_buffer_size)
+ {
+ if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
+ {
+ png_size_t i;
+ png_bytep sp;
+ png_bytep dp;
+
+ for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
+ i < png_ptr->save_buffer_size;
+ i++, sp++, dp++)
+ {
+ *dp = *sp;
+ }
+ }
+ }
+ if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
+ png_ptr->save_buffer_max)
+ {
+ png_size_t new_max;
+ png_bytep old_buffer;
+
+ new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
+ old_buffer = png_ptr->save_buffer;
+ png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, new_max);
+ png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ png_free(png_ptr, old_buffer);
+ png_ptr->save_buffer_max = new_max;
+ }
+ if (png_ptr->current_buffer_size)
+ {
+ png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+ png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
+ png_ptr->save_buffer_size += png_ptr->current_buffer_size;
+ png_ptr->current_buffer_size = 0;
+ }
+ png_ptr->save_buffer_ptr = png_ptr->save_buffer;
+ png_ptr->buffer_size = 0;
+}
+
+void
+png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ png_ptr->current_buffer = buffer;
+ png_ptr->current_buffer_size = buffer_length;
+ png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;
+ png_ptr->current_buffer_ptr = png_ptr->current_buffer;
+}
+
+void
+png_push_read_IDAT(png_structp png_ptr)
+{
+ if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
+
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_error(png_ptr, "Not enough compressed data");
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ }
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
+ save_size = png_ptr->idat_size;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->idat_size && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
+ save_size = png_ptr->idat_size;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->idat_size)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER;
+ }
+}
+
+void
+png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ int ret;
+
+ if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)
+ png_error(png_ptr, "Extra compression data");
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = (uInt)buffer_length;
+ while(1)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compressed data");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ else if (ret == Z_BUF_ERROR)
+ break;
+ else if (ret != Z_OK)
+ png_error(png_ptr, "Decompression Error");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ }
+ else
+ break;
+ }
+}
+
+void
+png_push_process_row(png_structp png_ptr)
+{
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+
+ switch (png_ptr->pass)
+ {
+ case 0:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 0; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 1:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 1; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 2)
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 3:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 3; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4)
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 5:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 5; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 6:
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ if (png_ptr->pass != 6)
+ break;
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ }
+ else
+#endif
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+}
+
+void
+png_read_push_finish_row(png_structp png_ptr)
+{
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (!(png_ptr->num_rows))
+ continue;
+ }
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->iwidth == 0);
+ }
+}
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+void
+png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
+ png_error(png_ptr, "Out of place tEXt");
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > 65535L) /* We can't hold the entire string in memory */
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - 65535L;
+ length = 65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr, length+1);
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = length;
+ png_ptr->current_text_left = length;
+ png_ptr->process_mode = PNG_READ_tEXt_MODE;
+}
+
+void
+png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+void
+png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
+ png_error(png_ptr, "Out of place zTXt");
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We can't handle zTXt chunks > 64K, since we don't have enough space
+ * to be able to store the uncompressed data. Actually, the threshold
+ * is probably around 32K, but it isn't as definite as 64K is.
+ */
+ if (length > 65535L)
+ {
+ png_warning(png_ptr, "zTXt chunk too large to fit in memory");
+ png_push_crc_skip(png_ptr, length);
+ return;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr, length+1);
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = length;
+ png_ptr->current_text_left = length;
+ png_ptr->process_mode = PNG_READ_zTXt_MODE;
+}
+
+void
+png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+ int ret;
+ png_size_t text_size, key_size;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt can't have zero text */
+ if (text == key + png_ptr->current_text_size)
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep )text;
+ png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
+ (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+ ret = Z_STREAM_END;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+ if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out +
+ key_size + 1);
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = png_malloc(png_ptr, text_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1);
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ if (ret == Z_STREAM_END)
+ break;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (ret != Z_STREAM_END)
+ {
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+ text_size -= key_size;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+/* This function is called when we haven't found a handler for this
+ chunk. In the future we will have code here which can handle
+ user-defined callback functions for unknown chunks before they are
+ ignored or cause an error. If there isn't a problem with the
+ chunk itself (ie a bad chunk name or a critical chunk), the chunk
+ is (currently) silently ignored. */
+void
+png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+ char msg[40];
+
+ sprintf(msg, "Unknown critical chunk %s", png_ptr->chunk_name);
+ png_error(png_ptr, msg);
+ }
+
+ png_push_crc_skip(png_ptr, length);
+}
+
+void
+png_push_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->info_fn != NULL)
+ (*(png_ptr->info_fn))(png_ptr, info_ptr);
+}
+
+void
+png_push_have_end(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->end_fn != NULL)
+ (*(png_ptr->end_fn))(png_ptr, info_ptr);
+}
+
+void
+png_push_have_row(png_structp png_ptr, png_bytep row)
+{
+ if (png_ptr->row_fn != NULL)
+ (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
+ (int)png_ptr->pass);
+}
+
+void
+png_progressive_combine_row (png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row)
+{
+ if (new_row != NULL)
+ png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
+}
+
+void
+png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn)
+{
+ png_ptr->info_fn = info_fn;
+ png_ptr->row_fn = row_fn;
+ png_ptr->end_fn = end_fn;
+
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+}
+
+png_voidp
+png_get_progressive_ptr(png_structp png_ptr)
+{
+ return png_ptr->io_ptr;
+}
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
diff --git a/gs/libpng/pngread.c b/gs/libpng/pngread.c
new file mode 100644
index 000000000..294ad6156
--- /dev/null
+++ b/gs/libpng/pngread.c
@@ -0,0 +1,750 @@
+
+/* pngread.c - read a PNG file
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Create a PNG structure for reading, and allocate any memory needed. */
+png_structp
+png_create_read_struct(png_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+ png_structp png_ptr;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+ png_debug(1, "in png_create_read_struct\n");
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+ {
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_destroy_struct(png_ptr);
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+
+ return (png_ptr);
+}
+
+
+/* Initialize PNG structure for reading, and allocate any memory needed.
+ This interface is depreciated in favour of the png_create_read_struct(),
+ and it will eventually disappear. */
+void
+png_read_init(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+
+ png_debug(1, "in png_read_init\n");
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+}
+
+/* Read the information before the actual image data. This has been
+ * changed in v0.90 to allow reading a file which already has the magic
+ * bytes read from the stream. You can tell libpng how many bytes have
+ * been read from the beginning of the stream (up to the maxumum of 8)
+ * via png_set_sig_bytes(), and we will only check the remaining bytes
+ * here. The application can then have access to the signature bytes we
+ * read if it is determined that this isn't a valid PNG file.
+ */
+void
+png_read_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_info\n");
+ /* save jump buffer and error functions */
+ /* If we haven't checked all of the PNG signature bytes, do so now. */
+ if (png_ptr->sig_bytes < 8)
+ {
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
+ png_ptr->sig_bytes = 8;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ }
+
+ while (1)
+ {
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ /* This should be a binary subdivision search or a hash for
+ * matching the chunk name rather than a linear search.
+ */
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ png_ptr->idat_size = length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ break;
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ }
+}
+
+/* optional call to update the users info_ptr structure */
+void
+png_read_update_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_update_info\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ png_read_transform_info(png_ptr, info_ptr);
+}
+
+/* initialize palette, background, etc, after transformations
+ are set, but before any reading takes place. This allows
+ the user to obtail a gamma corrected palette, for example.
+ If the user doesn't call this, we will do it ourselves. */
+void
+png_start_read_image(png_structp png_ptr)
+{
+ png_debug(1, "in png_start_read_image\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+}
+
+void
+png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
+{
+ int ret;
+ png_debug2(1, "in png_read_row (row %d, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* if interlaced and we do not need a new row, combine row and return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 7)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 7) || png_ptr->width < 5)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 7) != 4)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 4))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 2))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "Invalid attempt to read row data");
+
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ do
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf,
+ (png_size_t)png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression error");
+
+ } while (png_ptr->zstream.avail_out);
+
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ if (row != NULL)
+ png_combine_row(png_ptr, row,
+ png_pass_mask[png_ptr->pass]);
+ }
+ else
+#endif
+ {
+ if (row != NULL)
+ png_combine_row(png_ptr, row, 0xff);
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row, 0xff);
+ }
+ png_read_finish_row(png_ptr);
+}
+
+/* Read one or more rows of image data. If the image is interlaced,
+ and png_set_interlace_handling() has been called, the rows need to
+ to contain the contents of the rows from the previous pass. If
+ the image has alpha or transparency, and png_handle_alpha() has been
+ called, the rows contents must be initialized to the contents of the
+ screen. "row" holds the actual image, and pixels are placed in it
+ as they arrive. If the image is displayed after each pass, it will
+ appear to "sparkle" in. "display_row" can be used to display a
+ "chunky" progressive image, with finer detail added as it becomes
+ available. If you do not want this "chunky" display, you may pass
+ NULL for display_row. If you do not want the sparkle display, and
+ you have not called png_handle_alpha(), you may pass NULL for rows.
+ If you have called png_handle_alpha(), and the image has either an
+ alpha channel or a transparency chunk, you must provide a buffer for
+ rows. In this case, you do not have to provide a display_row buffer
+ also, but you may. If the image is not interlaced, or if you have
+ not called png_set_interlace_handling(), the display_row buffer will
+ be ignored, so pass NULL to it. */
+
+void
+png_read_rows(png_structp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows)
+{
+ png_uint_32 i;
+ png_bytepp rp;
+ png_bytepp dp;
+
+ png_debug(1, "in png_read_rows\n");
+ /* save jump buffer and error functions */
+ rp = row;
+ dp = display_row;
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr;
+ png_bytep dptr;
+
+ if (rp != NULL)
+ rptr = *rp;
+ else
+ rptr = NULL;
+ if (dp != NULL)
+ dptr = *dp;
+ else
+ dptr = NULL;
+ png_read_row(png_ptr, rptr, dptr);
+ if (row != NULL)
+ rp++;
+ if (display_row != NULL)
+ dp++;
+ }
+}
+
+/* Read the entire image. If the image has an alpha channel or a tRNS
+ chunk, and you have called png_handle_alpha(), you will need to
+ initialize the image to the current image that PNG will be overlaying.
+ We set the num_rows again here, in case it was incorrectly set in
+ png_read_start_row() by a call to png_read_update_info() or
+ png_start_read_image() if png_set_interlace_handling() wasn't called
+ prior to either of these functions like it should have been. You can
+ only call this function once. If you desire to have an image for
+ each pass of a interlaced image, use png_read_rows() instead */
+void
+png_read_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i;
+ int pass, j;
+ png_bytepp rp;
+
+ png_debug(1, "in png_read_image\n");
+ /* save jump buffer and error functions */
+ pass = png_set_interlace_handling(png_ptr);
+
+ png_ptr->num_rows = png_ptr->height; /* Make sure this is set correctly */
+
+ for (j = 0; j < pass; j++)
+ {
+ rp = image;
+ for (i = 0; i < png_ptr->height; i++)
+ {
+ png_read_row(png_ptr, *rp, NULL);
+ rp++;
+ }
+ }
+}
+
+/* Read the end of the PNG file. Will not read past the end of the
+ file, will verify the end is accurate, and will read any comments
+ or time information at the end of the file, if info is not NULL. */
+void
+png_read_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_debug(1, "in png_read_end\n");
+ /* save jump buffer and error functions */
+ png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+
+ do
+ {
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* Zero length IDATs are legal after the last IDAT has been
+ * read, but not after other chunks have been read.
+ */
+ if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ else
+ png_crc_finish(png_ptr, 0);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ } while (!(png_ptr->mode & PNG_HAVE_IEND));
+}
+
+/* free all memory used by the read */
+void
+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
+ png_infopp end_info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL, end_info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_read_struct\n");
+ /* save jump buffer and error functions */
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (end_info_ptr_ptr != NULL)
+ end_info_ptr = *end_info_ptr_ptr;
+
+ png_read_destroy(png_ptr, info_ptr, end_info_ptr);
+
+ if (info_ptr != NULL)
+ {
+ png_destroy_struct((png_voidp)info_ptr);
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (end_info_ptr != NULL)
+ {
+ png_destroy_struct((png_voidp)end_info_ptr);
+ *end_info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+ png_destroy_struct((png_voidp)png_ptr);
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+/* free all memory used by the read (old method) */
+void
+png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
+{
+ int i;
+ jmp_buf tmp_jmp;
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+
+ png_debug(1, "in png_read_destroy\n");
+ /* save jump buffer and error functions */
+ if (info_ptr != NULL)
+ png_info_destroy(png_ptr, info_ptr);
+
+ if (end_info_ptr != NULL)
+ png_info_destroy(png_ptr, end_info_ptr);
+
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_free(png_ptr, png_ptr->palette_lookup);
+ png_free(png_ptr, png_ptr->dither_index);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_table);
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_free(png_ptr, png_ptr->gamma_to_1);
+#endif
+ if (png_ptr->flags & PNG_FLAG_FREE_PALETTE)
+ png_free(png_ptr, png_ptr->palette);
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_bKGD_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_FREE_TRANS)
+ png_free(png_ptr, png_ptr->trans);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->gamma_16_table != NULL)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ }
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ if (png_ptr->gamma_16_from_1 != NULL)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
+ }
+ }
+ png_free(png_ptr, png_ptr->gamma_16_from_1);
+ if (png_ptr->gamma_16_to_1 != NULL)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+#endif
+
+ inflateEnd(&png_ptr->zstream);
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_free(png_ptr, png_ptr->save_buffer);
+#endif
+
+ /* Save the important info out of the png_struct, in case it is
+ * being used again.
+ */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
diff --git a/gs/libpng/pngrio.c b/gs/libpng/pngrio.c
new file mode 100644
index 000000000..1a7f0388c
--- /dev/null
+++ b/gs/libpng/pngrio.c
@@ -0,0 +1,137 @@
+
+/* pngrio.c - functions for data input
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+
+ This file provides a location for all input. Users which need
+ special handling are expected to write a function which has the same
+ arguments as this, and perform a similar function, but possibly has
+ a different input method. Note that you shouldn't change this
+ function, but rather write a replacement function and then make
+ libpng use it at run time with png_set_read_fn(...) */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Read the data from whatever input you are using. The default routine
+ reads from a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered reads. This should never be asked
+ to read more then 64K on a 16 bit machine. */
+void
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug1(4,"reading %d bytes\n", length);
+ if (png_ptr->read_data_fn != NULL)
+ (*(png_ptr->read_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL read function");
+}
+
+/* This is the function which does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (FILE *)png_ptr->io_ptr);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+ check = fread(n_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+ err = fread(buf, (png_size_t)1, read, io_ptr);
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "read Error");
+ }
+}
+#endif
+
+/* This function allows the application to supply a new input function
+ for libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png input data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the input functions. May be NULL.
+ read_data_fn - pointer to a new input function which takes as it's
+ arguments a pointer to a png_struct, a pointer to
+ a location where input data can be stored, and a 32-bit
+ unsigned int which is the number of bytes to be read.
+ To exit and output any fatal error messages the new write
+ function should call png_error(png_ptr, "Error msg"). */
+void
+png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+ if (read_data_fn != NULL)
+ png_ptr->read_data_fn = read_data_fn;
+ else
+ png_ptr->read_data_fn = png_default_read_data;
+
+ /* It is an error to write to a read device */
+ png_ptr->write_data_fn = NULL;
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->output_flush_fn = NULL;
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+}
+
diff --git a/gs/libpng/pngrtran.c b/gs/libpng/pngrtran.c
new file mode 100644
index 000000000..8df7d1f8f
--- /dev/null
+++ b/gs/libpng/pngrtran.c
@@ -0,0 +1,3153 @@
+
+/* pngrtran.c - transforms the data in a row for PNG readers
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines, we avoid an integer divide, which will be slower on
+ many machines. However, it does take more operations than the corresponding
+ divide method, so it may be slower on some RISC systems. There are two
+ shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+ The results may also be off by one for certain values. */
+
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite(composite, pixel, trans, background) \
+ { png_uint_16 temp = ((png_uint_16)(pixel) * (png_uint_16)(trans) + \
+ (png_uint_16)(background)*(png_uint_16)(255 - \
+ (png_uint_16)(trans)) + (png_uint_16)127); \
+ (composite) = (png_byte)(((temp >> 8) + temp) >> 8); }
+
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite_16(composite, pixel, trans, background) \
+ { png_uint_32 temp = ((png_uint_32)(pixel) * (png_uint_32)(trans) + \
+ (png_uint_32)(background)*(png_uint_32)(65535L - \
+ (png_uint_32)(trans)) + (png_uint_32)32767); \
+ (composite) = (png_uint_16)(((temp >> 16) + temp) >> 16); }
+#else
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite(composite, pixel, trans, background) \
+ (composite) = (png_byte)(((png_uint_16)(pixel) * (png_uint_16)(trans) + \
+ (png_uint_16)(background) * (png_uint_16)(255 - (png_uint_16)(trans)) + \
+ (png_uint_16)127) / 255)
+
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite_16(composite, pixel, trans, background) \
+ (composite) = (png_uint_16)(((png_uint_32)(pixel) * (png_uint_32)(trans) + \
+ (png_uint_32)(background)*(png_uint_32)(65535L - (png_uint_32)(trans)) + \
+ (png_uint_32)32767) / 65535L)
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* handle alpha and tRNS via a background color */
+void
+png_set_background(png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma)
+{
+ png_debug(1, "in png_set_background\n");
+ if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
+ {
+ png_warning(png_ptr, "Application must supply a known background gamma");
+ return;
+ }
+
+ png_ptr->transformations |= PNG_BACKGROUND;
+ png_memcpy(&(png_ptr->background), background_color,
+ sizeof(png_color_16));
+ png_ptr->background_gamma = (float)background_gamma;
+ png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
+ png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip 16 bit depth files to 8 bit depth */
+void
+png_set_strip_16(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_16\n");
+ png_ptr->transformations |= PNG_16_TO_8;
+}
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+void
+png_set_strip_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_alpha\n");
+ png_ptr->transformations |= PNG_STRIP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Dither file to 8 bit. Supply a palette, the current number
+ of elements in the palette, the maximum number of elements
+ allowed, and a histogram if possible. If the current number
+ of colors is greater then the maximum number, the palette will be
+ modified to fit in the maximum number. "full_dither" indicates
+ whether we need a dithering cube set up for RGB images, or if we
+ simply are reducing the number of colors in a paletted image. */
+
+typedef struct png_dsort_struct
+{
+ struct png_dsort_struct FAR * next;
+ png_byte left;
+ png_byte right;
+} png_dsort;
+typedef png_dsort FAR * png_dsortp;
+typedef png_dsort FAR * FAR * png_dsortpp;
+
+void
+png_set_dither(png_structp png_ptr, png_colorp palette,
+ int num_palette, int maximum_colors, png_uint_16p histogram,
+ int full_dither)
+{
+ png_debug(1, "in png_set_dither\n");
+ png_ptr->transformations |= PNG_DITHER;
+
+ if (!full_dither)
+ {
+ int i;
+
+ png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_index[i] = (png_byte)i;
+ }
+
+ if (num_palette > maximum_colors)
+ {
+ if (histogram != NULL)
+ {
+ /* This is easy enough, just throw out the least used colors.
+ Perhaps not the best solution, but good enough. */
+
+ int i;
+ png_bytep sort;
+
+ /* initialize an array to sort colors */
+ sort = (png_bytep)png_malloc(png_ptr, num_palette * sizeof (png_byte));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ sort[i] = (png_byte)i;
+
+ /* Find the least used palette entries by starting a
+ bubble sort, and running it until we have sorted
+ out enough colors. Note that we don't care about
+ sorting all the colors, just finding which are
+ least used. */
+
+ for (i = num_palette - 1; i >= maximum_colors; i--)
+ {
+ int done; /* to stop early if the list is pre-sorted */
+ int j;
+
+ done = 1;
+ for (j = 0; j < i; j++)
+ {
+ if (histogram[sort[j]] < histogram[sort[j + 1]])
+ {
+ png_byte t;
+
+ t = sort[j];
+ sort[j] = sort[j + 1];
+ sort[j + 1] = t;
+ done = 0;
+ }
+ }
+ if (done)
+ break;
+ }
+
+ /* swap the palette around, and set up a table, if necessary */
+ if (full_dither)
+ {
+ int j;
+
+ /* put all the useful colors within the max, but don't
+ move the others */
+ for (i = 0, j = num_palette; i < maximum_colors; i++)
+ {
+ if (sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+ while (sort[j] >= maximum_colors);
+ palette[i] = palette[j];
+ }
+ }
+ }
+ else
+ {
+ int j;
+
+ /* move all the used colors inside the max limit, and
+ develop a translation table */
+ for (i = 0, j = num_palette; i < maximum_colors; i++)
+ {
+ /* only move the colors we need to */
+ if (sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+ while (sort[j] >= maximum_colors);
+
+ tmp_color = palette[j];
+ palette[j] = palette[i];
+ palette[i] = tmp_color;
+ /* indicate where the color went */
+ png_ptr->dither_index[j] = (png_byte)i;
+ png_ptr->dither_index[i] = (png_byte)j;
+ }
+ }
+
+ /* find closest color for those colors we are not using */
+ for (i = 0; i < num_palette; i++)
+ {
+ if (png_ptr->dither_index[i] >= maximum_colors)
+ {
+ int min_d, k, min_k, d_index;
+
+ /* find the closest color to one we threw out */
+ d_index = png_ptr->dither_index[i];
+ min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
+ for (k = 1, min_k = 0; k < maximum_colors; k++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[d_index], palette[k]);
+
+ if (d < min_d)
+ {
+ min_d = d;
+ min_k = k;
+ }
+ }
+ /* point to closest color */
+ png_ptr->dither_index[i] = (png_byte)min_k;
+ }
+ }
+ }
+ png_free(png_ptr, sort);
+ }
+ else
+ {
+ /* This is much harder to do simply (and quickly). Perhaps
+ we need to go through a median cut routine, but those
+ don't always behave themselves with only a few colors
+ as input. So we will just find the closest two colors,
+ and throw out one of them (chosen somewhat randomly).
+ [I don't understand this at all, so if someone wants to
+ work on improving it, be my guest - AED]
+ */
+ int i;
+ int max_d;
+ int num_new_palette;
+ png_dsortpp hash;
+ png_bytep index_to_palette;
+ /* where the original index currently is in the palette */
+ png_bytep palette_to_index;
+ /* which original index points to this palette color */
+
+ /* initialize palette index arrays */
+ index_to_palette = (png_bytep)png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+ palette_to_index = (png_bytep)png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ {
+ index_to_palette[i] = (png_byte)i;
+ palette_to_index[i] = (png_byte)i;
+ }
+
+ hash = (png_dsortpp)png_malloc(png_ptr, 769 * sizeof (png_dsortp));
+ for (i = 0; i < 769; i++)
+ hash[i] = NULL;
+/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
+
+ num_new_palette = num_palette;
+
+ /* initial wild guess at how far apart the farthest pixel
+ pair we will be eliminating will be. Larger
+ numbers mean more areas will be allocated, Smaller
+ numbers run the risk of not saving enough data, and
+ having to do this all over again.
+
+ I have not done extensive checking on this number.
+ */
+ max_d = 96;
+
+ while (num_new_palette > maximum_colors)
+ {
+ for (i = 0; i < num_new_palette - 1; i++)
+ {
+ int j;
+
+ for (j = i + 1; j < num_new_palette; j++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[i], palette[j]);
+
+ if (d <= max_d)
+ {
+ png_dsortp t;
+
+ t = png_malloc(png_ptr, sizeof (png_dsort));
+ t->next = hash[d];
+ t->left = (png_byte)i;
+ t->right = (png_byte)j;
+ hash[d] = t;
+ }
+ }
+ }
+
+ for (i = 0; i <= max_d; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p;
+
+ for (p = hash[i]; p; p = p->next)
+ {
+ if (index_to_palette[p->left] < num_new_palette &&
+ index_to_palette[p->right] < num_new_palette)
+ {
+ int j, next_j;
+
+ if (num_new_palette & 1)
+ {
+ j = p->left;
+ next_j = p->right;
+ }
+ else
+ {
+ j = p->right;
+ next_j = p->left;
+ }
+
+ num_new_palette--;
+ palette[index_to_palette[j]] = palette[num_new_palette];
+ if (!full_dither)
+ {
+ int k;
+
+ for (k = 0; k < num_palette; k++)
+ {
+ if (png_ptr->dither_index[k] ==
+ index_to_palette[j])
+ png_ptr->dither_index[k] =
+ index_to_palette[next_j];
+ if (png_ptr->dither_index[k] ==
+ num_new_palette)
+ png_ptr->dither_index[k] =
+ index_to_palette[j];
+ }
+ }
+
+ index_to_palette[palette_to_index[num_new_palette]] =
+ index_to_palette[j];
+ palette_to_index[index_to_palette[j]] =
+ palette_to_index[num_new_palette];
+
+ index_to_palette[j] = (png_byte)num_new_palette;
+ palette_to_index[num_new_palette] = (png_byte)j;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ }
+
+ for (i = 0; i < 769; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p;
+
+ p = hash[i];
+ while (p)
+ {
+ png_dsortp t;
+
+ t = p->next;
+ png_free(png_ptr, p);
+ p = t;
+ }
+ }
+ hash[i] = 0;
+ }
+ max_d += 96;
+ }
+ png_free(png_ptr, hash);
+ png_free(png_ptr, palette_to_index);
+ png_free(png_ptr, index_to_palette);
+ }
+ num_palette = maximum_colors;
+ }
+ if (png_ptr->palette == NULL)
+ {
+ png_ptr->palette = palette;
+ }
+ png_ptr->num_palette = (png_uint_16)num_palette;
+
+ if (full_dither)
+ {
+ int i;
+ int total_bits, num_red, num_green, num_blue;
+ png_size_t num_entries;
+ png_bytep distance;
+
+ total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
+ PNG_DITHER_BLUE_BITS;
+
+ num_red = (1 << PNG_DITHER_RED_BITS);
+ num_green = (1 << PNG_DITHER_GREEN_BITS);
+ num_blue = (1 << PNG_DITHER_BLUE_BITS);
+ num_entries = ((png_size_t)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
+ num_entries * sizeof (png_byte));
+
+ png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
+
+ distance = (png_bytep)png_malloc(png_ptr, num_entries * sizeof(png_byte));
+
+ png_memset(distance, 0xff, num_entries * sizeof(png_byte));
+
+ for (i = 0; i < num_palette; i++)
+ {
+ int r, g, b, ir, ig, ib;
+
+ r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
+ g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
+ b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+
+ for (ir = 0; ir < num_red; ir++)
+ {
+ int dr, index_r;
+
+ dr = abs(ir - r);
+ index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+ for (ig = 0; ig < num_green; ig++)
+ {
+ int dg, dt, dm, index_g;
+
+ dg = abs(ig - g);
+ dt = dr + dg;
+ dm = ((dr > dg) ? dr : dg);
+ index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int d_index, db, dmax, d;
+
+ d_index = index_g | ib;
+ db = abs(ib - b);
+ dmax = ((dm > db) ? dm : db);
+ d = dmax + dt + db;
+
+ if (d < distance[d_index])
+ {
+ distance[d_index] = (png_byte)d;
+ png_ptr->palette_lookup[d_index] = (png_byte)i;
+ }
+ }
+ }
+ }
+ }
+
+ png_free(png_ptr, distance);
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Transform the image from the file_gamma to the screen_gamma. We
+ only do transformations on images where the file_gamma and screen_gamma
+ are not close reciprocals, otherwise it slows things down slightly, and
+ also needlessly introduces small errors. */
+void
+png_set_gamma(png_structp png_ptr, double screen_gamma, double file_gamma)
+{
+ png_debug(1, "in png_set_gamma\n");
+ if (fabs(screen_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
+ png_ptr->transformations |= PNG_GAMMA;
+ png_ptr->gamma = (float)file_gamma;
+ png_ptr->display_gamma = (float)screen_gamma;
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand paletted images to rgb, expand grayscale images of
+ less then 8 bit depth to 8 bit depth, and expand tRNS chunks
+ to alpha channels. */
+void
+png_set_expand(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+void
+png_set_gray_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_gray_to_rgb\n");
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Convert a RGB image to a grayscale of the given width. This would
+ allow us, for example, to convert a 24 bpp RGB image into an 8 or
+ 16 bpp grayscale image. (Not yet implemented.) */
+void
+png_set_rgb_to_gray(png_structp png_ptr, int gray_bits)
+{
+ png_debug(1, "in png_set_rgb_to_gray\n");
+ png_ptr->transformations |= PNG_RGB_TO_GRAY;
+ /* Need to do something with gray_bits here. */
+}
+#endif
+
+/* Initialize everything needed for the read. This includes modifying
+ the palette */
+void
+png_init_read_transformations(png_structp png_ptr)
+{
+ int color_type;
+
+ png_debug(1, "in png_init_read_transformations\n");
+ color_type = png_ptr->color_type;
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
+ {
+ if (color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ /* expand background chunk. */
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ png_ptr->background.gray *= (png_uint_16)0xff;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 2:
+ png_ptr->background.gray *= (png_uint_16)0x55;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 4:
+ png_ptr->background.gray *= (png_uint_16)0x11;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 8:
+ case 16:
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ }
+ }
+ else if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.red =
+ png_ptr->palette[png_ptr->background.index].red;
+ png_ptr->background.green =
+ png_ptr->palette[png_ptr->background.index].green;
+ png_ptr->background.blue =
+ png_ptr->palette[png_ptr->background.index].blue;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_ptr->background_1 = png_ptr->background;
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ png_build_gamma_table(png_ptr);
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int num_palette, i;
+ png_color back, back_1;
+ png_colorp palette;
+
+ palette = png_ptr->palette;
+ num_palette = png_ptr->num_palette;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g;
+
+ g = 1.0 / (png_ptr->background_gamma * png_ptr->display_gamma);
+
+ if (png_ptr->background_gamma_type==PNG_BACKGROUND_GAMMA_SCREEN||
+ fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+ }
+ else
+ {
+ back.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ g = 1.0 / png_ptr->background_gamma;
+
+ back_1.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back_1.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back_1.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else /* if (png_ptr->trans[i] != 0xff) */
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ else
+ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
+ {
+ double g, gs, m;
+
+ m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
+ g = 1.0;
+ gs = 1.0;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->display_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->display_gamma);
+ break;
+ }
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_ptr->background_1.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, g) * m + .5);
+ png_ptr->background_1.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, g) * m + .5);
+ png_ptr->background_1.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, g) * m + .5);
+ png_ptr->background.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, gs) * m + .5);
+ png_ptr->background.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, gs) * m + .5);
+ png_ptr->background.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, gs) * m + .5);
+ }
+ else
+ {
+ png_ptr->background_1.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, g) * m + .5);
+ png_ptr->background.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, gs) * m + .5);
+ }
+ }
+ }
+ else
+#endif
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int num_palette, i;
+ png_colorp palette;
+
+ palette = png_ptr->palette;
+ num_palette = png_ptr->num_palette;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND &&
+ color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int i;
+ png_color back;
+ png_colorp palette;
+
+ palette = png_ptr->palette;
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < png_ptr->num_trans; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ png_composite(palette[i].red, palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if ((png_ptr->transformations & PNG_SHIFT) &&
+ color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_16 i;
+ int sr, sg, sb;
+
+ sr = 8 - png_ptr->sig_bit.red;
+ if (sr < 0 || sr > 8)
+ sr = 0;
+ sg = 8 - png_ptr->sig_bit.green;
+ if (sg < 0 || sg > 8)
+ sg = 0;
+ sb = 8 - png_ptr->sig_bit.blue;
+ if (sb < 0 || sb > 8)
+ sb = 0;
+ for (i = 0; i < png_ptr->num_palette; i++)
+ {
+ png_ptr->palette[i].red >>= sr;
+ png_ptr->palette[i].green >>= sg;
+ png_ptr->palette[i].blue >>= sb;
+ }
+ }
+#endif
+}
+
+/* Modify the info structure to reflect the transformations. The
+ info should be updated so a PNG file could be written with it,
+ assuming the transformations result in valid PNG data. */
+void
+png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_transform_info\n");
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+ if (info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ info_ptr->num_trans = 0;
+ info_ptr->background = png_ptr->background;
+ }
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if ((png_ptr->transformations & PNG_16_TO_8) && info_ptr->bit_depth == 16)
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+ png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+ {
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ !(info_ptr->color_type & PNG_COLOR_MASK_COLOR))
+ info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+#endif
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+
+#if defined(PNG_STRIP_ALPHA_SUPPORTED)
+ if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
+ info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ info_ptr->channels--;
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if ((png_ptr->transformations & PNG_FILLER) &&
+ info_ptr->color_type & PNG_COLOR_TYPE_RGB &&
+ info_ptr->channels == 3)
+ {
+ info_ptr->channels = 4;
+ }
+#endif
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
+ info_ptr->bit_depth);
+
+ info_ptr->rowbytes =
+ (png_size_t)((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+}
+
+/* transform the row. The order of transformations is significant,
+ and is very touchy. If you add a transformation, take care to
+ decide how it fits in with the other transformations here. */
+void
+png_do_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_read_transformations\n");
+#if !defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (png_ptr->row_buf == NULL)
+ {
+ char msg[50];
+
+ sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
+ png_ptr->pass);
+ png_error(png_ptr, msg);
+ }
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+ }
+ else if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->num_trans)
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values));
+ else
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ NULL);
+ }
+ }
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_STRIP_ALPHA)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ PNG_FLAG_FILLER_AFTER);
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values), &(png_ptr->background),
+ &(png_ptr->background_1),
+ png_ptr->gamma_table, png_ptr->gamma_from_1,
+ png_ptr->gamma_to_1, png_ptr->gamma_16_table,
+ png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((png_ptr->transformations & PNG_GAMMA) &&
+ !(png_ptr->transformations & PNG_BACKGROUND) &&
+ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
+ png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->gamma_table, png_ptr->gamma_16_table,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ png_do_rgb_to_gray(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if (png_ptr->transformations & PNG_16_TO_8)
+ png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->dither_index);
+ }
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+}
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+/* unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
+ without changing the actual values. Thus, if you had a row with
+ a bit depth of 1, you would end up with bytes that only contained
+ the numbers 0 or 1. If you would rather they contain 0 and 255, use
+ png_do_shift() after this. */
+void
+png_do_unpack(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_unpack\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
+#else
+ if (row_info->bit_depth < 8)
+#endif
+ {
+ png_uint_32 shift, i;
+ png_bytep sp, dp;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x1);
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x3);
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((1 - ((row_info->width + 1) & 1)) << 2);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0xf);
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = (png_size_t)row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+/* reverse the effects of png_do_shift. This routine merely shifts the
+ pixels back to their significant bits values. Thus, if you have
+ a row of bit depth 8, but only 5 are significant, this will shift
+ the values back to 0 through 31 */
+void
+png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
+{
+ png_debug(1, "in png_do_unshift\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL && sig_bits != NULL &&
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift[4];
+ int channels, c;
+ png_uint_16 value;
+
+ channels = 0;
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->red;
+ shift[channels++] = row_info->bit_depth - sig_bits->green;
+ shift[channels++] = row_info->bit_depth - sig_bits->blue;
+ }
+ else
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->gray;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->alpha;
+ }
+
+ value = 0;
+
+ for (c = 0; c < channels; c++)
+ {
+ if (shift[c] <= 0)
+ shift[c] = 0;
+ else
+ value = 1;
+ }
+
+ if (!value)
+ return;
+
+ switch (row_info->bit_depth)
+ {
+ case 2:
+ {
+ png_bytep bp;
+ png_size_t i;
+
+ for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
+ {
+ *bp >>= 1;
+ *bp &= 0x55;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep bp;
+ png_byte mask;
+ png_size_t i;
+
+ mask = (png_byte)(((int)0xf0 >> shift[0]) & (int)0xf0) |
+ (png_byte)((int)0xf >> shift[0]);
+ for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
+ {
+ *bp >>= shift[0];
+ *bp &= mask;
+ }
+ break;
+ }
+ case 8:
+ {
+ png_bytep bp;
+ png_size_t i;
+
+ for (bp = row, i = 0; i < row_info->width; i++)
+ {
+ for (c = 0; c < row_info->channels; c++, bp++)
+ {
+ *bp >>= shift[c];
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ png_bytep bp;
+ png_size_t i;
+
+ for (bp = row, i = 0; i < row_info->width; i++)
+ {
+ for (c = 0; c < row_info->channels; c++, bp += 2)
+ {
+ value = (png_uint_16)((*bp << 8) + *(bp + 1));
+ value >>= shift[c];
+ *bp = (png_byte)(value >> 8);
+ *(bp + 1) = (png_byte)(value & 0xff);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* chop rows of bit depth 16 down to 8 */
+void
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_chop\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
+#else
+ if (row_info->bit_depth == 16)
+#endif
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_info->width * row_info->channels; i++, sp += 2, dp++)
+ {
+#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
+ /* This does a more accurate scaling of the 16-bit color
+ * value, rather than a simple low-byte truncation.
+ *
+ * What the ideal calculation should be:
+ *dp = (((((png_uint_32)(*sp) << 8) |
+ (png_uint_32)(*(sp + 1))) * 255 + 127) / 65535;
+
+ * Approximate calculation with shift/add instead of multiply/divide:
+ *dp = ((((png_uint_32)(*sp) << 8) |
+ (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
+
+ * What we actually do to avoid extra shifting and conversion: */
+ *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
+#else
+ *dp = *sp;
+#endif
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = (png_size_t)row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+void
+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from RGBA to ARGB */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row + row_info->rowbytes;
+ i < row_info->width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from RRGGBBAA to AARRGGBB */
+ else
+ {
+ png_bytep sp, dp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row + row_info->rowbytes;
+ i < row_info->width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from GA to AG */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row + row_info->rowbytes;
+ i < row_info->width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from GGAA to AAGG */
+ else
+ {
+ png_bytep sp, dp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row + row_info->rowbytes;
+ i < row_info->width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+/* Add filler channel if we have RGB color */
+void
+png_do_read_filler(png_row_infop row_info, png_bytep row,
+ png_uint_32 filler, png_uint_32 flags)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_read_filler\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_RGB && row_info->bit_depth == 8)
+ {
+ /* This changes the data from RGB to RGBX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ for (i = 1, sp = row + (png_size_t)row_info->width * 3,
+ dp = row + (png_size_t)row_info->width * 4;
+ i < row_info->width;
+ i++)
+ {
+ *(--dp) = (png_byte)filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = (png_byte)filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = (png_size_t)row_info->width * 4;
+ }
+ /* This changes the data from RGB to XRGB */
+ else
+ {
+ for (i = 0, sp = row + (png_size_t)row_info->width * 3,
+ dp = row + (png_size_t)row_info->width * 4;
+ i < row_info->width;
+ i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = (png_byte)filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = (png_size_t)row_info->width * 4;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* expand grayscale files to RGB, with or without alpha */
+void
+png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_gray_to_rgb\n");
+ if (row_info->bit_depth >= 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row + (png_size_t)row_info->width - 1,
+ dp = row + (png_size_t)row_info->width * 3 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ for (i = 0, sp = row + (png_size_t)row_info->width * 2 - 1,
+ dp = row + (png_size_t)row_info->width * 6 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ sp--;
+ sp--;
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row + (png_size_t)row_info->width * 2 - 1,
+ dp = row + (png_size_t)row_info->width * 4 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ for (i = 0, sp = row + (png_size_t)row_info->width * 4 - 1,
+ dp = row + (png_size_t)row_info->width * 8 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ sp--;
+ sp--;
+ }
+ }
+ }
+ row_info->channels += (png_byte)2;
+ row_info->color_type |= PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = (png_size_t)((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+/* build a grayscale palette. Palette is assumed to be 1 << bit_depth
+ large of png_color. This lets grayscale images be treated as
+ paletted. Most useful for gamma correction and simplification
+ of code. */
+void
+png_build_grayscale_palette(int bit_depth, png_colorp palette)
+{
+ int num_palette;
+ int color_inc;
+ int i;
+ int v;
+
+ png_debug(1, "in png_do_build_grayscale_palette\n");
+ if (palette == NULL)
+ return;
+
+ switch (bit_depth)
+ {
+ case 1:
+ num_palette = 2;
+ color_inc = 0xff;
+ break;
+ case 2:
+ num_palette = 4;
+ color_inc = 0x55;
+ break;
+ case 4:
+ num_palette = 16;
+ color_inc = 0x11;
+ break;
+ case 8:
+ num_palette = 256;
+ color_inc = 1;
+ break;
+ default:
+ num_palette = 0;
+ color_inc = 0;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = (png_byte)v;
+ palette[i].green = (png_byte)v;
+ palette[i].blue = (png_byte)v;
+ }
+}
+
+/* This function is currently unused. Do we really need it? */
+#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
+void
+png_correct_palette(png_structp png_ptr, png_colorp palette,
+ int num_palette)
+{
+ png_debug(1, "in png_correct_palette\n");
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((png_ptr->transformations & (PNG_GAMMA)) &&
+ (png_ptr->transformations & (PNG_BACKGROUND)))
+ {
+ png_color back, back_1;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g;
+
+ g = 1.0 / (png_ptr->background_gamma * png_ptr->display_gamma);
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
+ fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = png_ptr->background.red;
+ back.green = png_ptr->background.green;
+ back.blue = png_ptr->background.blue;
+ }
+ else
+ {
+ back.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ g = 1.0 / png_ptr->background_gamma;
+
+ back_1.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back_1.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back_1.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_32 i;
+
+ for (i = 0; i < (png_uint_32)num_palette; i++)
+ {
+ if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i] = back;
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ }
+ else
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int i;
+ png_color back;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i >= (int)png_ptr->num_trans ||
+ png_ptr->trans[i] == 0)
+ {
+ palette[i].red = back.red;
+ palette[i].green = back.green;
+ palette[i].blue = back.blue;
+ }
+ else if (i < (int)png_ptr->num_trans ||
+ png_ptr->trans[i] != 0xff)
+ {
+ png_composite(palette[i].red, png_ptr->palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, png_ptr->palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, png_ptr->palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+ else /* assume grayscale palette (what else could it be?) */
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i].red = (png_byte)png_ptr->background.red;
+ palette[i].green = (png_byte)png_ptr->background.green;
+ palette[i].blue = (png_byte)png_ptr->background.blue;
+ }
+ }
+ }
+ }
+#endif
+}
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Replace any alpha or transparency with the supplied background color.
+ "background" is already in the screen gamma, while "background_1" is
+ at a gamma of 1.0. Paletted files have already been taken care of. */
+void
+png_do_background(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ int shift;
+
+ png_debug(1, "in png_do_background\n");
+ if (background != NULL &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
+ (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ /* We currently don't do gamma correction for 2 and 4 bit */
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0x1) == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 7;
+ sp++;
+ }
+ else
+ shift--;
+ }
+ break;
+ }
+ case 2:
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0x3) == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0xf) == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ break;
+ }
+ case 8:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ if (v == trans_values->gray)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ if (v == trans_values->gray)
+ {
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 6)
+ {
+ png_uint_16 r, g, b;
+
+ r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v;
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row; i < row_info->width; i++, sp += 6)
+ {
+ png_uint_16 r, g, b;
+
+ r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a;
+
+ a = *(sp + 1);
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->gray);
+ *dp = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 2, dp++)
+ {
+ png_byte a;
+
+ a = *(sp + 1);
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background_1->gray);
+ }
+ }
+ }
+ }
+ else /* if (png_ptr->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a;
+
+ a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v, w;
+
+ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(v, g, a, background_1->gray);
+ w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+ *dp = (png_byte)((w >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(w & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a;
+
+ a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v;
+
+ g = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ png_composite_16(v, g, a, background_1->gray);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 4, dp += 3)
+ {
+ png_byte a;
+
+ a = *(sp + 3);
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ *(dp + 1) = gamma_table[*(sp + 1)];
+ *(dp + 2) = gamma_table[*(sp + 2)];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->red);
+ *dp = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 1)];
+ png_composite(w, v, a, background_1->green);
+ *(dp + 1) = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 2)];
+ png_composite(w, v, a, background_1->blue);
+ *(dp + 2) = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 4, dp += 3)
+ {
+ png_byte a;
+
+ a = *(sp + 3);
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ *(dp + 1) = *(sp + 1);
+ *(dp + 2) = *(sp + 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background->red);
+ png_composite(*(dp + 1), *(sp + 1), a,
+ background->green);
+ png_composite(*(dp + 2), *(sp + 2), a,
+ background->blue);
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a;
+
+ a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) +
+ (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v, w, x;
+
+ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(w, v, a, background->red);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *dp = (png_byte)((x >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ png_composite_16(w, v, a, background->green);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *(dp + 2) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ png_composite_16(w, v, a, background->blue);
+ x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
+ *(dp + 4) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(x & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a;
+
+ a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) +
+ (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 6);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 r, g, b, v;
+
+ r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+
+ png_composite_16(v, r, a, background->red);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ png_composite_16(v, g, a, background->green);
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ png_composite_16(v, g, a, background->green);
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ row_info->channels--;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = (png_size_t)((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Gamma correct the image, avoiding the alpha channel. Make sure
+ you do this after you deal with the trasparency issue on grayscale
+ or rgb images. If your bit depth is 8, use gamma_table, if it
+ is 16, use gamma_16_table and gamma_shift. Build these with
+ build_gamma_table(). */
+void
+png_do_gamma(png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift)
+{
+ png_bytep sp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_gamma\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+ (row_info->bit_depth == 16 && gamma_16_table != NULL)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ for (i = 0, sp = row; i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp += 2;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ if (row_info->bit_depth == 4)
+ {
+ for (i = 0, sp = row; i < row_info->width; i += 2)
+ {
+ int msb = *sp & 0xf0;
+ int lsb = *sp & 0x0f;
+
+ *sp = (((int)gamma_table[msb | msb >> 4] + 8) & 0xf0) |
+ (((int)gamma_table[lsb << 4 | lsb] + 8) >> 4);
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ for (i = 0, sp = row; i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* expands a palette row to an rgb or rgba row depending
+ upon whether you supply trans and num_trans */
+void
+png_do_expand_palette(png_row_infop row_info, png_bytep row,
+ png_colorp palette, png_bytep trans, int num_trans)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_expand_palette\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 1;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = (png_byte)value;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((row_info->width & 1) << 2);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = (png_byte)value;
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = (png_size_t)row_info->width;
+ }
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (trans != NULL)
+ {
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width << 2) - 1;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((int)(*sp) >= num_trans)
+ *dp-- = 0xff;
+ else
+ *dp-- = trans[*sp];
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = (png_size_t)row_info->width * 4;
+ row_info->color_type = 6;
+ row_info->channels = 4;
+ }
+ else
+ {
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width * 3) - 1;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = (png_size_t)row_info->width * 3;
+ row_info->color_type = 2;
+ row_info->channels = 3;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* if the bit depth < 8, it is expanded to 8. Also, if the
+ transparency value is supplied, an alpha channel is built. */
+void
+png_do_expand(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_value)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_expand\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_uint_16 gray = trans_value ? trans_value->gray : 0;
+
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ gray *= 0xff;
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 0xff;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ gray *= 0x55;
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = (png_byte)(value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ gray *= 0x11;
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((1 - ((row_info->width + 1) & 1)) << 2);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = (png_byte)(value | (value << 4));
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = (png_size_t)row_info->width;
+ }
+
+ if (trans_value != NULL)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width << 1) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*sp == gray)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (row_info->rowbytes << 1) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((png_uint_16)*(sp) |
+ ((png_uint_16)*(sp - 1) << 8)) == gray)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ row_info->channels = 2;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
+ row_info->rowbytes =
+ (png_size_t)((row_info->width * row_info->pixel_depth) >> 3);
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_info->width << 2) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*(sp - 2) == trans_value->red &&
+ *(sp - 1) == trans_value->green &&
+ *(sp - 0) == trans_value->blue)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_info->width << 3) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((((png_uint_16)*(sp - 4) |
+ ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
+ (((png_uint_16)*(sp - 2) |
+ ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
+ (((png_uint_16)*(sp - 0) |
+ ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ row_info->channels = 4;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
+ row_info->rowbytes =
+ (png_size_t)((row_info->width * row_info->pixel_depth) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+void
+png_do_dither(png_row_infop row_info, png_bytep row,
+ png_bytep palette_lookup, png_bytep dither_lookup)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ png_debug(1, "in png_do_dither\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_info->width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+
+ /* this looks real messy, but the compiler will reduce
+ it down to a reasonable formula. For example, with
+ 5 bits per color, we get:
+ p = (((r >> 3) & 0x1f) << 10) |
+ (((g >> 3) & 0x1f) << 5) |
+ ((b >> 3) & 0x1f);
+ */
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ palette_lookup != NULL && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_info->width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+ sp++;
+
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ (png_size_t)((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ dither_lookup && row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_info->width; i++, sp++)
+ {
+ *sp = dither_lookup[*sp];
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+static int png_gamma_shift[] =
+ {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
+
+/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
+ tables, we don't make a full table if we are reducing to 8-bit in
+ the future. Note also how the gamma_16 tables are segmented so that
+ we don't need to allocate > 64K chunks for a full 16-bit table. */
+void
+png_build_gamma_table(png_structp png_ptr)
+{
+ png_debug(1, "in png_build_gamma_table\n");
+ if (png_ptr->bit_depth <= 8)
+ {
+ int i;
+ double g;
+
+ g = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+
+ png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+ g = 1.0 / (png_ptr->display_gamma);
+
+ png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+ }
+#endif /* PNG_BACKGROUND_SUPPORTED */
+ }
+ else
+ {
+ double g;
+ int i, j, shift, num;
+ int sig_bit;
+ png_uint_32 ig;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit = (int)png_ptr->sig_bit.red;
+ if ((int)png_ptr->sig_bit.green > sig_bit)
+ sig_bit = png_ptr->sig_bit.green;
+ if ((int)png_ptr->sig_bit.blue > sig_bit)
+ sig_bit = png_ptr->sig_bit.blue;
+ }
+ else
+ {
+ sig_bit = (int)png_ptr->sig_bit.gray;
+ }
+
+ if (sig_bit > 0)
+ shift = 16 - sig_bit;
+ else
+ shift = 0;
+
+ if (png_ptr->transformations & PNG_16_TO_8)
+ {
+ if (shift < (16 - PNG_MAX_GAMMA_8))
+ shift = (16 - PNG_MAX_GAMMA_8);
+ }
+
+ if (shift > 8)
+ shift = 8;
+ if (shift < 0)
+ shift = 0;
+
+ png_ptr->gamma_shift = (png_byte)shift;
+
+ num = (1 << (8 - shift));
+
+ g = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+
+ png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
+ num * sizeof (png_uint_16p));
+
+ if ((png_ptr->transformations & PNG_16_TO_8) &&
+ !(png_ptr->transformations & PNG_BACKGROUND))
+ {
+ double fin, fout;
+ png_uint_32 last, max;
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ 256 * sizeof (png_uint_16));
+ }
+
+ g = 1.0 / g;
+ last = 0;
+ for (i = 0; i < 256; i++)
+ {
+ fout = ((double)i + 0.5) / 256.0;
+ fin = pow(fout, g);
+ max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
+ while (last <= max)
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)(
+ (png_uint_16)i | ((png_uint_16)i << 8));
+ last++;
+ }
+ }
+ while (last < ((png_uint_32)num << 8))
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
+ last++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ 256 * sizeof (png_uint_16));
+
+ ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_table[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
+ num * sizeof (png_uint_16p ));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ 256 * sizeof (png_uint_16));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_to_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ g = 1.0 / (png_ptr->display_gamma);
+
+ png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
+ num * sizeof (png_uint_16p));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ 256 * sizeof (png_uint_16));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_from_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+#endif /* PNG_BACKGROUND_SUPPORTED */
+ }
+}
+#endif
+
diff --git a/gs/libpng/pngrutil.c b/gs/libpng/pngrutil.c
new file mode 100644
index 000000000..f018526be
--- /dev/null
+++ b/gs/libpng/pngrutil.c
@@ -0,0 +1,2137 @@
+
+/* pngrutil.c - utilities to read a PNG file
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big endian format. */
+png_uint_32
+png_get_uint_32(png_bytep buf)
+{
+ png_uint_32 i;
+
+ i = ((png_uint_32)(*buf) << 24) +
+ ((png_uint_32)(*(buf + 1)) << 16) +
+ ((png_uint_32)(*(buf + 2)) << 8) +
+ (png_uint_32)(*(buf + 3));
+
+ return i;
+}
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* Grab a signed 32-bit integer from a buffer in big endian format. The
+ * data is stored in the PNG file in two's complement format, and it is
+ * assumed that the machine format for signed integers is the same. */
+png_int_32
+png_get_int_32(png_bytep buf)
+{
+ png_int_32 i;
+
+ i = ((png_int_32)(*buf) << 24) +
+ ((png_int_32)(*(buf + 1)) << 16) +
+ ((png_int_32)(*(buf + 2)) << 8) +
+ (png_int_32)(*(buf + 3));
+
+ return i;
+}
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+/* Grab an unsigned 16-bit integer from a buffer in big endian format. */
+png_uint_16
+png_get_uint_16(png_bytep buf)
+{
+ png_uint_16 i;
+
+ i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
+ (png_uint_16)(*(buf + 1)));
+
+ return i;
+}
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Set the action on getting a CRC error for an ancillary or critical chunk. */
+void
+png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
+{
+ png_debug(1, "in png_set_crc_action\n");
+ /* Tell libpng how we react to CRC errors in critical chunks */
+ switch (crit_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
+ PNG_FLAG_CRC_CRITICAL_IGNORE;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
+ png_warning(png_ptr, "Can't discard critical data on CRC error.");
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ break;
+ }
+
+ switch (ancil_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
+ PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* warn/discard data */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ break;
+ }
+}
+
+/* Read data, and (optionally) run it through the CRC. */
+void
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+{
+ png_read_data(png_ptr, buf, length);
+ png_calculate_crc(png_ptr, buf, length);
+}
+
+/* Optionally skip data and then check the CRC. Depending on whether we
+ are reading a ancillary or critical chunk, and how the program has set
+ things up, we may calculate the CRC on the data and print a message.
+ Returns '1' if there was a CRC error, '0' otherwise. */
+int
+png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+{
+ png_uint_32 i;
+
+ for (i = skip; i > (png_uint_32)png_ptr->zbuf_size; i -= png_ptr->zbuf_size)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ }
+ if (i)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, (png_size_t)i);
+ }
+
+ if (png_crc_error(png_ptr))
+ {
+ char msg[80];
+
+ sprintf(msg,"CRC error in %s", png_ptr->chunk_name);
+
+ if ((png_ptr->chunk_name[0] & 0x20 && /* Ancillary */
+ !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
+ (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
+ png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
+ {
+ png_warning(png_ptr, msg);
+ }
+ else
+ {
+ png_error(png_ptr, msg);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Compare the CRC stored in the PNG file with that calulated by libpng from
+ the data it has read thus far. */
+int
+png_crc_error(png_structp png_ptr)
+{
+ png_byte crc_bytes[4];
+ png_uint_32 crc;
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ png_read_data(png_ptr, crc_bytes, 4);
+
+ if (need_crc)
+ {
+ crc = png_get_uint_32(crc_bytes);
+#ifdef PNG_USE_OWN_CRC
+ return (((crc^0xffffffffL)&0xffffffffL) != (png_ptr->crc&0xffffffffL));
+#else
+ return (crc != png_ptr->crc);
+#endif
+ }
+ else
+ return 0;
+}
+
+
+/* read and check the IDHR chunk */
+void
+png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[13];
+ png_uint_32 width, height;
+ int bit_depth, color_type, compression_type, filter_type;
+ int interlace_type;
+
+ png_debug(1, "in png_handle_IHDR\n");
+
+ if (png_ptr->mode != PNG_BEFORE_IHDR)
+ png_error(png_ptr, "Out of place IHDR");
+
+ /* check the length */
+ if (length != 13)
+ png_error(png_ptr, "Invalid IHDR chunk");
+
+ png_ptr->mode |= PNG_HAVE_IHDR;
+
+ png_crc_read(png_ptr, buf, 13);
+ png_crc_finish(png_ptr, 0);
+
+ width = png_get_uint_32(buf);
+ height = png_get_uint_32(buf + 4);
+ bit_depth = buf[8];
+ color_type = buf[9];
+ compression_type = buf[10];
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
+ /* check for width and height valid values */
+ if (width == 0 || width > 2147483647 || height == 0 || height > 2147483647)
+ png_error(png_ptr, "Invalid image size in IHDR");
+
+ /* check other values */
+ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+ bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth in IHDR");
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ png_error(png_ptr, "Invalid color type in IHDR");
+
+ if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth) > 8 ||
+ ((color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
+ png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
+
+ if (interlace_type > PNG_INTERLACE_ADAM7)
+ png_error(png_ptr, "Unknown interlace method in IHDR");
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_error(png_ptr, "Unknown compression method in IHDR");
+
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ png_error(png_ptr, "Unknown filter method in IHDR");
+
+ /* set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->color_type = (png_byte)color_type;
+
+ /* find number of channels */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_PALETTE:
+ png_ptr->channels = 1;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ png_ptr->channels = 4;
+ break;
+ }
+
+ /* set up other useful info */
+ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
+ png_ptr->channels);
+ png_ptr->rowbytes = ((png_ptr->width *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
+ png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
+ png_debug1(3,"channels = %d\n", png_ptr->channels);
+ png_debug1(3,"rowbytes = %d\n", png_ptr->rowbytes);
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
+ color_type, interlace_type, compression_type, filter_type);
+}
+
+/* read and check the palette */
+void
+png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_colorp palette;
+ int num, i;
+
+ png_debug(1, "in png_handle_PLTE\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before PLTE");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid PLTE after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ png_error(png_ptr, "Duplicate PLTE chunk");
+
+ png_ptr->mode |= PNG_HAVE_PLTE;
+
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ if (length % 3)
+ {
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_warning(png_ptr, "Invalid palette chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else
+ {
+ png_error(png_ptr, "Invalid palette chunk");
+ }
+ }
+
+ num = (int)length / 3;
+ palette = (png_colorp)png_malloc(png_ptr, num * sizeof (png_color));
+ png_ptr->flags |= PNG_FLAG_FREE_PALETTE;
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ /* don't depend upon png_color being any order */
+ palette[i].red = buf[0];
+ palette[i].green = buf[1];
+ palette[i].blue = buf[2];
+ }
+
+ /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
+ whatever the normal CRC configuration tells us. However, if we
+ have an RGB image, the PLTE can be considered ancillary, so
+ we will act as though it is. */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_crc_finish(png_ptr, 0);
+ }
+ else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+ {
+ char msg[80];
+
+ sprintf(msg,"CRC error in %s", png_ptr->chunk_name);
+
+ /* If we don't want to use the data from an ancillary chunk,
+ we have two options: an error abort, or a warning and we
+ ignore the data in this chunk (which should be OK, since
+ it's considered ancillary for a RGB or RGBA image). */
+ if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
+ {
+ png_error(png_ptr, msg);
+ }
+ else
+ {
+ png_warning(png_ptr, msg);
+ png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
+ png_free(png_ptr, palette);
+ return;
+ }
+ }
+ /* Otherwise, we (optionally) emit a warning and use the chunk. */
+ else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ {
+ png_warning(png_ptr, msg);
+ }
+ }
+
+ png_ptr->palette = palette;
+ png_ptr->num_palette = (png_uint_16)num;
+ png_set_PLTE(png_ptr, info_ptr, palette, num);
+}
+
+void
+png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_IEND\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
+ {
+ png_error(png_ptr, "No image in file");
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT | PNG_HAVE_IEND;
+
+ if (length != 0)
+ {
+ png_warning(png_ptr, "Incorrect IEND chunk length");
+ }
+ png_crc_finish(png_ptr, length);
+}
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+void
+png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_uint_32 igamma;
+ float file_gamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_gAMA\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before gAMA");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid gAMA after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place gAMA chunk");
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA)
+ {
+ png_warning(png_ptr, "Duplicate gAMA chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 4)
+ {
+ png_warning(png_ptr, "Incorrect gAMA chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ igamma = png_get_uint_32(buf);
+ /* check for zero gamma */
+ if (igamma == 0)
+ return;
+
+ file_gamma = (float)igamma / (float)100000.0;
+ png_ptr->gamma = file_gamma;
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+}
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+void
+png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_sBIT\n");
+
+ buf[0] = buf[1] = buf[2] = buf[3] = 0;
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sBIT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sBIT chunk");
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT)
+ {
+ png_warning(png_ptr, "Duplicate sBIT chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 3;
+ else
+ truelen = (png_size_t)png_ptr->channels;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[1];
+ png_ptr->sig_bit.blue = buf[2];
+ png_ptr->sig_bit.alpha = buf[3];
+ }
+ else
+ {
+ png_ptr->sig_bit.gray = buf[0];
+ png_ptr->sig_bit.alpha = buf[1];
+ }
+ png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+void
+png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[4];
+ png_uint_32 val;
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+ png_debug(1, "in png_handle_cHRM\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid cHRM after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before cHRM");
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM)
+ {
+ png_warning(png_ptr, "Duplicate cHRM chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 32)
+ {
+ png_warning(png_ptr, "Incorrect cHRM chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ white_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ white_y = (float)val / (float)100000.0;
+
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point");
+ png_crc_finish(png_ptr, 24);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ red_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ red_y = (float)val / (float)100000.0;
+
+ if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
+ red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point");
+ png_crc_finish(png_ptr, 16);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ green_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ green_y = (float)val / (float)100000.0;
+
+ if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
+ green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point");
+ png_crc_finish(png_ptr, 8);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ blue_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ blue_y = (float)val / (float)100000.0;
+
+ if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
+ blue_x + blue_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point");
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+void
+png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_tRNS\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tRNS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid tRNS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+ {
+ png_warning(png_ptr, "Duplcate tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before tRNS");
+ }
+ else if (length > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
+ png_ptr->flags |= PNG_FLAG_FREE_TRANS;
+ png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
+ png_ptr->num_trans = (png_uint_16)length;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_byte buf[6];
+
+ if (length != 6)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, (png_size_t)length);
+ png_ptr->num_trans = 3;
+ png_ptr->trans_values.red = png_get_uint_16(buf);
+ png_ptr->trans_values.green = png_get_uint_16(buf + 2);
+ png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_byte buf[6];
+
+ if (length != 2)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
+ &(png_ptr->trans_values));
+}
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+void
+png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[6];
+
+ png_debug(1, "in png_handle_bKGD\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before bKGD");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid bKGD after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before bKGD");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD)
+ {
+ png_warning(png_ptr, "Duplicate bKGD chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 1;
+ else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ truelen = 6;
+ else
+ truelen = 2;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ /* We convert the index value into RGB components so that we can allow
+ * arbitrary RGB values for background when we have transparency, and
+ * so it is easy to determine the RGB values of the background color
+ * from the info_ptr struct. */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.index = buf[0];
+ png_ptr->background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
+ png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
+ png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
+ }
+ else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
+ {
+ png_ptr->background.red =
+ png_ptr->background.green =
+ png_ptr->background.blue =
+ png_ptr->background.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_ptr->background.red = png_get_uint_16(buf);
+ png_ptr->background.green = png_get_uint_16(buf + 2);
+ png_ptr->background.blue = png_get_uint_16(buf + 4);
+ }
+
+ png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+void
+png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int num, i;
+
+ png_debug(1, "in png_handle_hIST\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before hIST");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid hIST after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before hIST");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST)
+ {
+ png_warning(png_ptr, "Duplicate hIST chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != (png_uint_32)(2 * png_ptr->num_palette))
+ {
+ png_warning(png_ptr, "Incorrect hIST chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ num = (int)length / 2;
+ png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
+ num * sizeof (png_uint_16));
+ png_ptr->flags |= PNG_FLAG_FREE_HIST;
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[2];
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->hist[i] = png_get_uint_16(buf);
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+void
+png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_pHYs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pHYS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pHYS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_warning(png_ptr, "Duplicate pHYS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect pHYs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ res_x = png_get_uint_32(buf);
+ res_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+void
+png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 offset_x, offset_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_oFFs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before oFFs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid oFFs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_warning(png_ptr, "Duplicate oFFs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect oFFs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ offset_x = png_get_uint_32(buf);
+ offset_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* read the pCAL chunk (png-scivis-19970203) */
+void
+png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp purpose;
+ png_int_32 X0, X1;
+ png_byte type, nparams;
+ png_charp buf, units, endptr;
+ png_charpp params;
+ int i;
+
+ png_debug(1, "in png_handle_pCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL)
+ {
+ png_warning(png_ptr, "Duplicate pCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading pCAL chunk data (%d bytes)\n",
+ length + 1);
+ purpose = (png_charp)png_malloc(png_ptr, length + 1);
+ png_crc_read(png_ptr, (png_bytep)purpose, (png_size_t)length);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ purpose[length] = '\0'; /* null terminate the last string */
+
+ png_debug(3, "Finding end of pCAL purpose string\n");
+ for (buf = purpose; *buf != '\0'; buf++)
+ /* empty loop */;
+
+ endptr = purpose + length;
+
+ /* We need to have at least 12 bytes after the purpose string
+ in order to get the parameter information. */
+ if (endptr <= buf + 12)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+ X0 = png_get_int_32((png_bytep)buf+1);
+ X1 = png_get_int_32((png_bytep)buf+5);
+ type = buf[9];
+ nparams = buf[10];
+ units = buf + 11;
+
+ png_debug(3, "Checking pCAL equation type and number of parameters\n");
+ /* Check that we have the right number of parameters for known
+ equation types. */
+ if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
+ (type == PNG_EQUATION_BASE_E && nparams != 3) ||
+ (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
+ (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
+ {
+ png_warning(png_ptr, "Invalid pCAL parameters for equation type");
+ png_free(png_ptr, purpose);
+ return;
+ }
+ else if (type >= PNG_EQUATION_LAST)
+ {
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ }
+
+ /* Empty loop to move past the units string. */
+ for (buf = units; *buf != '\0'; buf++);
+
+ png_debug(3, "Allocating pCAL parameters array\n");
+ params = (png_charpp)png_malloc(png_ptr, nparams*sizeof(png_charp)) ;
+
+ /* Get pointers to the start of each parameter string. */
+ for (i = 0; i < nparams; i++)
+ {
+ buf++; /* Skip the null string terminator from previous parameter. */
+
+ png_debug1(3, "Reading pCAL parameter %d\n", i);
+ /* Empty loop to move past each paramter string */
+ for (params[i] = buf; *buf != '\0' && buf <= endptr; buf++);
+
+ /* Make sure we haven't run out of data yet */
+ if (buf > endptr)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+ return;
+ }
+ }
+
+ png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
+ units, params);
+
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+void
+png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[7];
+ png_time mod_time;
+
+ png_debug(1, "in png_handle_tIME\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Out of place tIME chunk");
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_warning(png_ptr, "Duplicate tIME chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ if (length != 7)
+ {
+ png_warning(png_ptr, "Incorrect tIME chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 7);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ mod_time.second = buf[6];
+ mod_time.minute = buf[5];
+ mod_time.hour = buf[4];
+ mod_time.day = buf[3];
+ mod_time.month = buf[2];
+ mod_time.year = png_get_uint_16(buf);
+
+ png_set_tIME(png_ptr, info_ptr, &mod_time);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+void
+png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ png_uint_32 skip = 0;
+
+ png_debug(1, "in png_handle_tEXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tEXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > 65535L)
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ skip = length - 65535L;
+ length = 65535L;
+ }
+#endif
+
+ key = (png_charp)png_malloc(png_ptr, length + 1);
+ png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[length] = '\0';
+
+ for (text = key; *text; text++)
+ /* empty loop to find end of key */ ;
+
+ if (text != key + (png_size_t)length)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void
+png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ static char msg[] = "Error decoding zTXt chunk";
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ int comp_type = PNG_TEXT_COMPRESSION_NONE;
+
+ png_debug(1, "in png_handle_zTXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before zTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > 65535L)
+ {
+ png_warning(png_ptr,"zTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ key = (png_charp)png_malloc(png_ptr, length + 1);
+ png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[length] = '\0';
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt must have some text after the keyword */
+ if (text == key + (png_size_t)length)
+ {
+ png_warning(png_ptr, "Zero length zTXt chunk");
+ }
+ else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt)
+ {
+ png_size_t text_size, key_size;
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep)text;
+ png_ptr->zstream.avail_in = (uInt)(length - (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ int ret;
+
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_warning(png_ptr, png_ptr->zstream.msg);
+ else
+ png_warning(png_ptr, msg);
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (text == NULL)
+ {
+ text_size = key_size + sizeof(msg) + 1;
+ text = (png_charp)png_malloc(png_ptr, text_size);
+ png_memcpy(text, key, key_size);
+ }
+
+ text[text_size - 1] = '\0';
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = length - (text - key) - 1;
+ text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+ png_memcpy(text + key_size, msg, text_size + 1);
+ break;
+ }
+ if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out +
+ key_size + 1);
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = png_malloc(png_ptr, text_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1);
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+ text_size -= key_size;
+ }
+ else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */
+ {
+ png_size_t text_size;
+ char umsg[50];
+
+ sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
+ png_warning(png_ptr, umsg);
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = (png_size_t)length - (text - key) - 1;
+ text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+ png_memcpy(text, msg, text_size + 1);
+ }
+
+ text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+ text_ptr->compression = comp_type;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+}
+#endif
+
+/* This function is called when we haven't found a handler for a
+ chunk. If there isn't a problem with the chunk itself (ie bad
+ chunk name, CRC, or a critical chunk), the chunk is silently ignored. */
+void
+png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_unknown\n");
+
+ /* In the future we can have code here that calls user-supplied
+ * callback functions for unknown chunks before they are ignored or
+ * cause an error.
+ */
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+ char msg[40];
+
+ sprintf(msg, "Unknown critical chunk %s", png_ptr->chunk_name);
+ png_error(png_ptr, msg);
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ png_crc_finish(png_ptr, length);
+}
+
+/* This function is called to verify that a chunk name is valid.
+ This function can't have the "critical chunk check" incorporated
+ into it, since in the future we will need to be able to call user
+ functions to handle unknown critical chunks after we check that
+ the chunk name itself is valid. */
+
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+
+void
+png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
+{
+ png_debug(1, "in png_check_chunk_name\n");
+ if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
+ isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+ {
+ char msg[45];
+
+ sprintf(msg, "Invalid chunk type 0x%02X 0x%02X 0x%02X 0x%02X",
+ chunk_name[0], chunk_name[1], chunk_name[2], chunk_name[3]);
+ png_error(png_ptr, msg);
+ }
+}
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixels is to be combined,
+ a zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+void
+png_combine_row(png_structp png_ptr, png_bytep row,
+ int mask)
+{
+ png_debug(1,"in png_combine_row\n");
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)((png_ptr->width *
+ png_ptr->row_info.pixel_depth + 7) >> 3));
+ }
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ default:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ png_byte m;
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ png_memcpy(dp, sp, pixel_bytes);
+ }
+
+ sp += pixel_bytes;
+ dp += pixel_bytes;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ }
+ }
+}
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+void
+png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+ png_uint_32 transformations)
+{
+ png_debug(1,"in png_do_read_interlace\n");
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ default:
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ sp = row + (row_info->width - 1) * pixel_bytes;
+ dp = row + (final_width - 1) * pixel_bytes;
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sp, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sp -= pixel_bytes;
+ }
+ break;
+ }
+ }
+ row_info->width = final_width;
+ row_info->rowbytes = ((final_width *
+ (png_uint_32)row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+void
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
+ png_bytep prev_row, int filter)
+{
+ png_debug(1, "in png_read_filter_row\n");
+ png_debug2(2,"row = %d, filter = %d\n", png_ptr->row_number, filter);
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+ case PNG_FILTER_VALUE_SUB:
+ {
+ png_uint_32 i;
+ int bpp;
+ png_bytep rp;
+ png_bytep lp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
+ i < row_info->rowbytes; i++, rp++, lp++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_UP:
+ {
+ png_uint_32 i;
+ png_bytep rp;
+ png_bytep pp;
+
+ for (i = 0, rp = row, pp = prev_row;
+ i < row_info->rowbytes; i++, rp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp)) & 0xff);
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_AVG:
+ {
+ png_uint_32 i;
+ int bpp;
+ png_bytep rp;
+ png_bytep pp;
+ png_bytep lp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = 0, rp = row, pp = prev_row;
+ i < (png_uint_32)bpp; i++, rp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp) / 2)) & 0xff);
+ }
+ for (lp = row; i < row_info->rowbytes; i++, rp++, lp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp + *lp) / 2) & 0xff);
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ int bpp;
+ png_uint_32 i;
+ png_bytep rp;
+ png_bytep pp;
+ png_bytep lp;
+ png_bytep cp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = 0, rp = row, pp = prev_row,
+ lp = row - bpp, cp = prev_row - bpp;
+ i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp;
+ if (i >= (png_uint_32)bpp)
+ {
+ c = *cp;
+ a = *lp;
+ }
+ else
+ {
+ a = c = 0;
+ }
+ p = a + b - c;
+ pa = abs(p - a);
+ pb = abs(p - b);
+ pc = abs(p - c);
+
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ }
+ break;
+ }
+ default:
+ png_error(png_ptr, "Bad adaptive filter type");
+ break;
+ }
+}
+
+void
+png_read_finish_row(png_structp png_ptr)
+{
+ png_debug(1, "in png_read_finish_row\n");
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (!(png_ptr->num_rows))
+ continue;
+ }
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->iwidth == 0);
+
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ {
+ char extra;
+ int ret;
+
+ png_ptr->zstream.next_out = (Byte *)&extra;
+ png_ptr->zstream.avail_out = (uInt)1;
+ do
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression Error");
+
+ if (!(png_ptr->zstream.avail_out))
+ png_error(png_ptr, "Extra compressed data");
+
+ } while (1);
+ png_ptr->zstream.avail_out = 0;
+ }
+
+ if (png_ptr->idat_size || png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compression data");
+
+ inflateReset(&png_ptr->zstream);
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+}
+
+void
+png_read_start_row(png_structp png_ptr)
+{
+ int max_pixel_depth;
+ png_uint_32 rowbytes;
+
+ png_debug(1, "in png_read_start_row\n");
+ png_ptr->zstream.avail_in = 0;
+ png_init_read_transformations(png_ptr);
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ else
+ png_ptr->num_rows = png_ptr->height;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->iwidth = png_ptr->width;
+ png_ptr->irowbytes = png_ptr->rowbytes + 1;
+ }
+ max_pixel_depth = png_ptr->pixel_depth;
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ max_pixel_depth = 8;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth < 8)
+ max_pixel_depth = 8;
+ if (png_ptr->num_trans)
+ max_pixel_depth *= 2;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (png_ptr->num_trans)
+ {
+ max_pixel_depth *= 4;
+ max_pixel_depth /= 3;
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & (PNG_FILLER))
+ {
+ if (max_pixel_depth < 32)
+ max_pixel_depth = 32;
+ }
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ {
+ if ((png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (max_pixel_depth <= 16)
+ max_pixel_depth = 32;
+ else if (max_pixel_depth <= 32)
+ max_pixel_depth = 64;
+ }
+ else
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 24;
+ else if (max_pixel_depth <= 16)
+ max_pixel_depth = 48;
+ }
+ }
+#endif
+
+ /* align the width on the next larger 8 pixels. Mainly used
+ for interlacing */
+ rowbytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
+ /* calculate the maximum bytes needed, adding a byte and a pixel
+ for safety sake */
+ rowbytes = ((rowbytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
+ 1 + ((max_pixel_depth + 7) >> 3);
+#ifdef PNG_MAX_MALLOC_64K
+ if (rowbytes > 65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, rowbytes);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (png_ptr->rowbytes + 1 > 65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
+
+ png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
+ png_debug1(3, "width = %d,\n", png_ptr->width);
+ png_debug1(3, "height = %d,\n", png_ptr->height);
+ png_debug1(3, "iwidth = %d,\n", png_ptr->iwidth);
+ png_debug1(3, "num_rows = %d\n", png_ptr->num_rows);
+ png_debug1(3, "rowbytes = %d,\n", png_ptr->rowbytes);
+ png_debug1(3, "irowbytes = %d,\n", png_ptr->irowbytes);
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+}
diff --git a/gs/libpng/pngset.c b/gs/libpng/pngset.c
new file mode 100644
index 000000000..b079164b8
--- /dev/null
+++ b/gs/libpng/pngset.c
@@ -0,0 +1,312 @@
+
+/* pngset.c - storage of image information into info struct
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+void
+png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+{
+ png_debug1(1, "in %s storage function\n", "bKGD");
+ if (info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->background), background, sizeof(png_color_16));
+ info_ptr->valid |= PNG_INFO_bKGD;
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+void
+png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double white_x, double white_y, double red_x, double red_y,
+ double green_x, double green_y, double blue_x, double blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->x_white = (float)white_x;
+ info_ptr->y_white = (float)white_y;
+ info_ptr->x_red = (float)red_x;
+ info_ptr->y_red = (float)red_y;
+ info_ptr->x_green = (float)green_x;
+ info_ptr->y_green = (float)green_y;
+ info_ptr->x_blue = (float)blue_x;
+ info_ptr->y_blue = (float)blue_y;
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+void
+png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+{
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->gamma = (float)file_gamma;
+ info_ptr->valid |= PNG_INFO_gAMA;
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+void
+png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+{
+ png_debug1(1, "in %s storage function\n", "hIST");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->hist = hist;
+ info_ptr->valid |= PNG_INFO_hIST;
+}
+#endif
+
+void
+png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
+{
+ png_debug1(1, "in %s storage function\n", "IHDR");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->width = width;
+ info_ptr->height = height;
+ info_ptr->bit_depth = (png_byte)bit_depth;
+ info_ptr->color_type =(png_byte) color_type;
+ info_ptr->compression_type = (png_byte)compression_type;
+ info_ptr->filter_type = (png_byte)filter_type;
+ info_ptr->interlace_type = (png_byte)interlace_type;
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+ info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+void
+png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 offset_x, png_uint_32 offset_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "oFFs");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->x_offset = offset_x;
+ info_ptr->y_offset = offset_y;
+ info_ptr->offset_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_oFFs;
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+void
+png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params)
+{
+ png_size_t length;
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "pCAL");
+ if (info_ptr == NULL)
+ return;
+
+ length = png_strlen(purpose) + 1;
+ png_debug1(3, "allocating purpose for info (%d bytes)\n", length);
+ info_ptr->pcal_purpose = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_purpose, purpose, length);
+
+ png_debug(3, "storing X0, X1, type, and nparams in info\n");
+ info_ptr->pcal_X0 = X0;
+ info_ptr->pcal_X1 = X1;
+ info_ptr->pcal_type = (png_byte)type;
+ info_ptr->pcal_nparams = (png_byte)nparams;
+
+ length = png_strlen(units) + 1;
+ png_debug1(3, "allocating units for info (%d bytes)\n", length);
+ info_ptr->pcal_units = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_units, units, length);
+
+ info_ptr->pcal_params = (png_charpp)png_malloc(png_ptr,
+ (nparams + 1) * sizeof(png_charp));
+ info_ptr->pcal_params[nparams] = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ length = png_strlen(params[i]) + 1;
+ png_debug2(3, "allocating parameter %d for info (%d bytes)\n", i, length);
+ info_ptr->pcal_params[i] = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_params[i], params[i], length);
+ }
+
+ info_ptr->valid |= PNG_INFO_pCAL;
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+void
+png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "pHYs");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->x_pixels_per_unit = res_x;
+ info_ptr->y_pixels_per_unit = res_y;
+ info_ptr->phys_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_pHYs;
+}
+#endif
+
+void
+png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
+ png_colorp palette, int num_palette)
+{
+ png_debug1(1, "in %s storage function\n", "PLTE");
+ if (info_ptr == NULL)
+ return;
+
+ info_ptr->palette = palette;
+ info_ptr->num_palette = (png_uint_16)num_palette;
+ info_ptr->valid |= PNG_INFO_PLTE;
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+void
+png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
+ png_color_8p sig_bit)
+{
+ png_debug1(1, "in %s storage function\n", "sBIT");
+ if (info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8));
+ info_ptr->valid |= PNG_INFO_sBIT;
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) || \
+ defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+void
+png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+ int num_text)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
+ "text" : png_ptr->chunk_name));
+
+ if (info_ptr == NULL || num_text == 0)
+ return;
+
+ /* Make sure we have enough space in the "text" array in info_struct
+ * to hold all of the incoming text_ptr objects.
+ */
+ if (info_ptr->num_text + num_text > info_ptr->max_text)
+ {
+ if (info_ptr->text != NULL)
+ {
+ png_textp old_text;
+ int old_max;
+
+ old_max = info_ptr->max_text;
+ info_ptr->max_text = info_ptr->num_text + num_text + 8;
+ old_text = info_ptr->text;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ info_ptr->max_text * sizeof (png_text));
+ png_memcpy(info_ptr->text, old_text, old_max * sizeof(png_text));
+ png_free(png_ptr, old_text);
+ }
+ else
+ {
+ info_ptr->max_text = num_text + 8;
+ info_ptr->num_text = 0;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ info_ptr->max_text * sizeof (png_text));
+ }
+ png_debug1(3, "allocated %d entries for info_ptr->text\n",
+ info_ptr->max_text);
+ }
+
+ for (i = 0; i < num_text; i++)
+ {
+ png_textp textp = &(info_ptr->text[info_ptr->num_text]);
+
+ if (text_ptr[i].text == NULL)
+ text_ptr[i].text = "";
+
+ if (text_ptr[i].text[0] == '\0')
+ {
+ textp->text_length = 0;
+ textp->compression = PNG_TEXT_COMPRESSION_NONE;
+ }
+ else
+ {
+ textp->text_length = png_strlen(text_ptr[i].text);
+ textp->compression = text_ptr[i].compression;
+ }
+ textp->text = text_ptr[i].text;
+ textp->key = text_ptr[i].key;
+ info_ptr->num_text++;
+ png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+ }
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+void
+png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+{
+ png_debug1(1, "in %s storage function\n", "tIME");
+ if (info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time));
+ info_ptr->valid |= PNG_INFO_tIME;
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+void
+png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep trans, int num_trans, png_color_16p trans_values)
+{
+ png_debug1(1, "in %s storage function\n", "tRNS");
+ if (info_ptr == NULL)
+ return;
+
+ if (trans != NULL)
+ {
+ info_ptr->trans = trans;
+ }
+
+ if (trans_values != NULL)
+ {
+ png_memcpy(&(info_ptr->trans_values), trans_values,
+ sizeof(png_color_16));
+ }
+ info_ptr->num_trans = (png_uint_16)num_trans;
+ info_ptr->valid |= PNG_INFO_tRNS;
+}
+#endif
+
diff --git a/gs/libpng/pngtest b/gs/libpng/pngtest
new file mode 100755
index 000000000..702cb5c12
--- /dev/null
+++ b/gs/libpng/pngtest
Binary files differ
diff --git a/gs/libpng/pngtest.c b/gs/libpng/pngtest.c
new file mode 100644
index 000000000..c26623391
--- /dev/null
+++ b/gs/libpng/pngtest.c
@@ -0,0 +1,377 @@
+
+/* pngtest.c - a simple test program to test libpng
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+#define PNG_DEBUG 0
+#endif
+
+#include "png.h"
+
+#ifdef __TURBOC__
+#include <mem.h>
+#endif
+
+/* defined so I can write to a file on gui/windowing platforms */
+/* #define STDERR stderr */
+#define STDERR stdout /* for DOS */
+
+/* input and output filenames */
+#ifdef RISCOS
+char *inname = "pngtest_png";
+char *outname = "pngout_png";
+#else
+char *inname = "pngtest.png";
+char *outname = "pngout.png";
+#endif
+
+char inbuf[256], outbuf[256];
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fpin, *fpout;
+ png_structp read_ptr, write_ptr;
+ png_infop read_info_ptr, write_info_ptr, end_info_ptr;
+ png_bytep row_buf;
+ png_uint_32 y;
+ png_uint_32 width, height;
+ int num_pass, pass;
+ int bit_depth, color_type;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+ row_buf = (png_bytep)NULL;
+
+ fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
+
+ if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
+ {
+ fprintf(STDERR,
+ "Warning: versions are different between png.h and png.c\n");
+ fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
+ }
+
+ if (argc > 1)
+ inname = argv[1];
+
+ if (argc > 2)
+ outname = argv[2];
+
+ if (argc > 3)
+ {
+ fprintf(stderr, "usage: %s [infile.png] [outfile.png]\n", argv[0]);
+ exit(1);
+ }
+
+ if ((fpin = fopen(inname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find input file %s\n", inname);
+ return 1;
+ }
+
+ if ((fpout = fopen(outname, "wb")) == NULL)
+ {
+ fprintf(STDERR, "Could not open output file %s\n", outname);
+ fclose(fpin);
+ return 1;
+ }
+
+ png_debug(0, "Allocating read and write structures\n");
+ read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+ write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+ png_debug(0, "Allocating read_info, write_info and end_info structures\n");
+ read_info_ptr = png_create_info_struct(read_ptr);
+ write_info_ptr = png_create_info_struct(read_ptr);
+ end_info_ptr = png_create_info_struct(read_ptr);
+
+ png_debug(0, "Setting jmpbuf for read struct\n");
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(read_ptr->jmpbuf))
+#endif
+ {
+ fprintf(STDERR, "libpng read error\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
+ }
+
+ png_debug(0, "Setting jmpbuf for write struct\n");
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(write_ptr->jmpbuf))
+#endif
+ {
+ fprintf(STDERR, "libpng write error\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
+ }
+
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+ png_debug(0, "Initializing input and output streams\n");
+ png_init_io(read_ptr, fpin);
+ png_init_io(write_ptr, fpout);
+
+ png_debug(0, "Reading info struct\n");
+ png_read_info(read_ptr, read_info_ptr);
+
+ png_debug(0, "Transferring info struct\n");
+ {
+ int interlace_type, compression_type, filter_type;
+
+ if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
+ &color_type, &interlace_type, &compression_type, &filter_type))
+ {
+ png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
+ color_type, interlace_type, compression_type, filter_type);
+ }
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
+ {
+ png_color_16p background;
+
+ if (png_get_bKGD(read_ptr, read_info_ptr, &background))
+ {
+ png_set_bKGD(write_ptr, write_info_ptr, background);
+ }
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
+ {
+ double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+ if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
+ &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ {
+ png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
+ red_y, green_x, green_y, blue_x, blue_y);
+ }
+ }
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
+ {
+ double gamma;
+
+ if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
+ {
+ png_set_gAMA(write_ptr, write_info_ptr, gamma);
+ }
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
+ {
+ png_uint_16p hist;
+
+ if (png_get_hIST(read_ptr, read_info_ptr, &hist))
+ {
+ png_set_hIST(write_ptr, write_info_ptr, hist);
+ }
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
+ {
+ png_uint_32 offset_x, offset_y;
+ int unit_type;
+
+ if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
+ {
+ png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
+ }
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
+ {
+ png_charp purpose, units;
+ png_charpp params;
+ png_int_32 X0, X1;
+ int type, nparams;
+
+ if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
+ &nparams, &units, &params))
+ {
+ png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
+ nparams, units, params);
+ }
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
+ {
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
+ {
+ png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
+ }
+ }
+#endif
+ {
+ png_colorp palette;
+ int num_palette;
+
+ if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
+ {
+ png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
+ }
+ }
+#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
+ {
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
+ {
+ png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
+ }
+ }
+#endif
+#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \
+ (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
+ {
+ png_textp text_ptr;
+ int num_text;
+
+ if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
+ {
+ png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text);
+ png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
+ }
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
+ {
+ png_timep mod_time;
+
+ if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
+ {
+ png_set_tIME(write_ptr, write_info_ptr, mod_time);
+ }
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
+ {
+ png_bytep trans;
+ int num_trans;
+ png_color_16p trans_values;
+
+ if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
+ &trans_values))
+ {
+ png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
+ trans_values);
+ }
+ }
+#endif
+
+ png_debug(0, "\nWriting info struct\n");
+ png_write_info(write_ptr, write_info_ptr);
+
+ row_buf = (png_bytep)png_malloc(read_ptr,
+ png_get_rowbytes(read_ptr, read_info_ptr));
+ if (row_buf == NULL)
+ {
+ fprintf(STDERR, "No memory to allocate row buffer\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
+ }
+
+ num_pass = png_set_interlace_handling(read_ptr);
+ png_set_interlace_handling(write_ptr);
+
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ for (y = 0; y < height; y++)
+ {
+ png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
+ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
+ }
+ }
+
+ png_debug(0, "Reading and writing end_info data\n");
+ png_read_end(read_ptr, end_info_ptr);
+ png_write_end(write_ptr, end_info_ptr);
+
+ png_debug(0, "Destroying data structs\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+
+ fclose(fpin);
+ fclose(fpout);
+
+ png_free(read_ptr, row_buf);
+
+ png_debug(0, "Opening files for comparison\n");
+ if ((fpin = fopen(inname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find file %s\n", inname);
+ return 1;
+ }
+
+ if ((fpout = fopen(outname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find file %s\n", outname);
+ fclose(fpin);
+ return 1;
+ }
+
+ while (1)
+ {
+ png_size_t num_in, num_out;
+
+ num_in = fread(inbuf, 1, 1, fpin);
+ num_out = fread(outbuf, 1, 1, fpout);
+
+ if (num_in != num_out)
+ {
+ fprintf(STDERR, "Files %s and %s are of a different size\n",
+ inname, outname);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
+ }
+
+ if (!num_in)
+ break;
+
+ if (png_memcmp(inbuf, outbuf, num_in))
+ {
+ fprintf(STDERR, "Files %s and %s are different\n", inname, outname);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
+ }
+ }
+
+ fclose(fpin);
+ fclose(fpout);
+ fprintf(STDERR, "libpng passes test\n");
+
+ return 0;
+}
+
diff --git a/gs/libpng/pngtest.png b/gs/libpng/pngtest.png
new file mode 100644
index 000000000..3bbeaee07
--- /dev/null
+++ b/gs/libpng/pngtest.png
Binary files differ
diff --git a/gs/libpng/pngtrans.c b/gs/libpng/pngtrans.c
new file mode 100644
index 000000000..05e4185a6
--- /dev/null
+++ b/gs/libpng/pngtrans.c
@@ -0,0 +1,565 @@
+
+/* pngtrans.c - transforms the data in a row (used by both readers and writers)
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* turn on bgr to rgb mapping */
+void
+png_set_bgr(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_bgr\n");
+ png_ptr->transformations |= PNG_BGR;
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* turn on 16 bit byte swapping */
+void
+png_set_swap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap\n");
+ if (png_ptr->bit_depth == 16)
+ png_ptr->transformations |= PNG_SWAP_BYTES;
+}
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* turn on pixel packing */
+void
+png_set_packing(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packing\n");
+ if (png_ptr->bit_depth < 8)
+ {
+ png_ptr->transformations |= PNG_PACK;
+ png_ptr->usr_bit_depth = 8;
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* turn on packed pixel swapping */
+void
+png_set_packswap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packswap\n");
+ if (png_ptr->bit_depth < 8)
+ png_ptr->transformations |= PNG_PACKSWAP;
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+void
+png_set_shift(png_structp png_ptr, png_color_8p true_bits)
+{
+ png_debug(1, "in png_set_shift\n");
+ png_ptr->transformations |= PNG_SHIFT;
+ png_ptr->shift = *true_bits;
+}
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || defined(PNG_WRITE_INTERLACING_SUPPORTED)
+int
+png_set_interlace_handling(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_interlace handling\n");
+ if (png_ptr->interlaced)
+ {
+ png_ptr->transformations |= PNG_INTERLACE;
+ return 7;
+ }
+
+ return 1;
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte on read, or remove a filler or alpha byte on write.
+ * The filler type has changed in v0.95 to allow future 2-byte fillers
+ * for 48-bit input data, as well as avoiding problems with some compilers
+ * which don't like bytes as parameters.
+ */
+void
+png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+{
+ png_debug(1, "in png_set_filler\n");
+ png_ptr->transformations |= PNG_FILLER;
+ png_ptr->filler = (png_byte)filler;
+ if (filler_loc == PNG_FILLER_AFTER)
+ png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
+ else
+ png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
+
+ /* This should probably go in the "do_filler" routine */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB && png_ptr->bit_depth == 8)
+ {
+ png_ptr->usr_channels = 4;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void
+png_set_swap_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap_alpha\n");
+ png_ptr->transformations |= PNG_SWAP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+void
+png_set_invert_mono(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_mono\n");
+ png_ptr->transformations |= PNG_INVERT_MONO;
+}
+
+/* invert monocrome grayscale data */
+void
+png_do_invert(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_invert\n");
+ if (row_info->bit_depth == 1 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_info->rowbytes; i++, rp++)
+ {
+ *rp = (png_byte)(~(*rp));
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* swaps byte order on 16 bit depth images */
+void
+png_do_swap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_swap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_byte t;
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width * row_info->channels;
+ i++, rp += 2)
+ {
+ t = *rp;
+ *rp = *(rp + 1);
+ *(rp + 1) = t;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+static png_byte onebppswaptable[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
+};
+
+static png_byte twobppswaptable[256] = {
+ 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
+ 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
+ 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
+ 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
+ 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
+ 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
+ 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
+ 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+ 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
+ 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
+ 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
+ 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
+ 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
+ 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
+ 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
+ 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
+ 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
+ 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
+ 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
+ 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
+ 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
+ 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
+ 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
+ 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
+ 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
+ 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
+ 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
+ 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
+ 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
+ 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
+ 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
+ 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
+};
+
+static png_byte fourbppswaptable[256] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
+ 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+ 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+ 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+ 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
+ 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+ 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
+ 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+ 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
+ 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+ 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
+ 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+ 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
+ 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+ 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
+ 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+ 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
+ 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+ 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
+ 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
+ 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+ 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
+ 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
+ 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
+ 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
+ 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
+ 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
+ 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+ 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
+};
+
+/* swaps pixel packing order within bytes */
+void
+png_do_packswap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_packswap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL
+#endif
+ row_info->bit_depth < 8)
+ {
+ png_bytep rp, end, table;
+
+ end = row + row_info->rowbytes;
+
+ if (row_info->bit_depth == 1)
+ table = onebppswaptable;
+ else if (row_info->bit_depth == 2)
+ table = twobppswaptable;
+ else if (row_info->bit_depth == 4)
+ table = fourbppswaptable;
+ else
+ return;
+
+ for (rp = row; rp < end; rp++)
+ *rp = table[*rp];
+ }
+}
+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+/* remove filler or alpha byte(s) */
+void
+png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+{
+ png_debug(1, "in png_do_strip_filler\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+/*
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB ||
+ row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+*/
+ if (row_info->channels == 4)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from RGBX or RGBA to RGB */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ for (i = 1, sp = row + 4, dp = row + 3; i < row_info->width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XRGB or ARGB to RGB */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_info->width * 3;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
+ for (i = 1, sp = row + 8, dp = row + 6; i < row_info->width; i++)
+ {
+ /* This could be (although memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
+ for (i = 0, sp = row + 2, dp = row; i < row_info->width; i++)
+ {
+ /* This could be (although memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 48;
+ row_info->rowbytes = row_info->width * 6;
+ }
+ row_info->channels = 3;
+ }
+/*
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY ||
+ row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+*/
+ else if (row_info->channels == 2)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from GX or GA to G */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ for (i = 1, sp = row + 2, dp = row + 1; i < row_info->width; i++)
+ {
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XG or AG to G */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_info->width;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ /* This converts from GGXX or GGAA to GG */
+ for (i = 1, sp = row + 4, dp = row + 2; i < row_info->width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+
+ /* This converts from XXGG or AAGG to GG */
+ for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+ {
+ sp += 2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_info->width * 2;
+ }
+ row_info->channels = 1;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* swaps red and blue bytes within a pixel */
+void
+png_do_bgr(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_bgr\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->bit_depth == 8)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_info->width; i++, rp += 3)
+ {
+ save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_info->width; i++, rp += 4)
+ {
+ save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_info->width; i++, rp += 6)
+ {
+ save[0] = *rp;
+ save[1] = *(rp + 1);
+ *rp = *(rp + 4);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 4) = save[0];
+ *(rp + 5) = save[1];
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_info->width; i++, rp += 8)
+ {
+ save[0] = *rp;
+ save[1] = *(rp + 1);
+ *rp = *(rp + 4);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 4) = save[0];
+ *(rp + 5) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+
diff --git a/gs/libpng/pngwio.c b/gs/libpng/pngwio.c
new file mode 100644
index 000000000..e4c96a7c1
--- /dev/null
+++ b/gs/libpng/pngwio.c
@@ -0,0 +1,193 @@
+
+/* pngwio.c - functions for data output
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+
+ This file provides a location for all output. Users which need
+ special handling are expected to write functions which have the same
+ arguments as these, and perform similar functions, but possibly use
+ different output methods. Note that you shouldn't change these
+ functions, but rather write replacement functions and then change
+ them at run time with png_set_write_fn(...) */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Write the data to whatever output you are using. The default routine
+ writes to a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered writes. This should never be asked
+ to write more then 64K on a 16 bit machine. */
+
+void
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ if (png_ptr->write_data_fn != NULL )
+ (*(png_ptr->write_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL write function");
+}
+
+/* This is the function which does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+ check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+ check = fwrite(near_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+ err = fwrite(buf, 1, written, io_ptr);
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+#endif
+
+/* This function is called to output any data pending writing (normally
+ to disk). After png_flush is called, there should be no data pending
+ writing in any buffers. */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+void
+png_flush(png_structp png_ptr)
+{
+ if (png_ptr->output_flush_fn != NULL)
+ (*(png_ptr->output_flush_fn))(png_ptr);
+}
+
+static void
+png_default_flush(png_structp png_ptr)
+{
+ FILE *io_ptr;
+ io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+}
+#endif
+
+/* This function allows the application to supply new output functions for
+ libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png output data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the output functions. May be NULL.
+ write_data_fn - pointer to a new output function which takes as its
+ arguments a pointer to a png_struct, a pointer to
+ data to be written, and a 32-bit unsigned int which is
+ the number of bytes to be written. The new write
+ function should call png_error(png_ptr, "Error msg")
+ to exit and output any fatal error messages.
+ flush_data_fn - pointer to a new flush function which takes as its
+ arguments a pointer to a png_struct. After a call to
+ the flush function, there should be no data in any buffers
+ or pending transmission. If the output method doesn't do
+ any buffering of ouput, a function prototype must still be
+ supplied although it doesn't have to do anything. If
+ PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
+ time, output_flush_fn will be ignored, although it must be
+ supplied for compatibility. */
+void
+png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+ if (write_data_fn != NULL)
+ png_ptr->write_data_fn = write_data_fn;
+ else
+ png_ptr->write_data_fn = png_default_write_data;
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ if (output_flush_fn != NULL)
+ png_ptr->output_flush_fn = output_flush_fn;
+ else
+ png_ptr->output_flush_fn = png_default_flush;
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+ /* It is an error to read while writing a png file */
+ png_ptr->read_data_fn = NULL;
+}
+
+#if defined(USE_FAR_KEYWORD)
+#if defined(_MSC_VER)
+void *far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ FP_OFF(near_ptr) = FP_OFF(ptr);
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(FP_SEG(ptr) != FP_SEG(far_ptr))
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# else
+void *far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ near_ptr = (void FAR *)ptr;
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(far_ptr != ptr)
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# endif
+# endif
diff --git a/gs/libpng/pngwrite.c b/gs/libpng/pngwrite.c
new file mode 100644
index 000000000..b571b0f78
--- /dev/null
+++ b/gs/libpng/pngwrite.c
@@ -0,0 +1,847 @@
+
+/* pngwrite.c - general routines to write a PNG file
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+/* get internal access to png.h */
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Writes all the PNG information. This is the suggested way to use the
+ * library. If you have a new chunk to add, make a function to write it,
+ * and put it in the correct location here. If you want the chunk written
+ * after the image data, put it in png_write_end(). I strongly encurage
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
+ * the chunk, as that will keep the code from breaking if you want to just
+ * write a plain PNG file. If you have long comments, I suggest writing
+ * them in png_write_end(), and compressing them.
+ */
+void
+png_write_info(png_structp png_ptr, png_infop info_ptr)
+{
+ int i;
+
+ png_debug(1, "in png_write_info\n");
+ png_write_sig(png_ptr); /* write PNG signature */
+ /* write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
+ info_ptr->filter_type, info_ptr->interlace_type);
+ /* the rest of these check to see if the valid field has the appropriate
+ flag set, and if it does, writes the chunk. */
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ png_write_gAMA(png_ptr, info_ptr->gamma);
+#endif
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ png_write_cHRM(png_ptr,
+ info_ptr->x_white, info_ptr->y_white,
+ info_ptr->x_red, info_ptr->y_red,
+ info_ptr->x_green, info_ptr->y_green,
+ info_ptr->x_blue, info_ptr->y_blue);
+#endif
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_write_PLTE(png_ptr, info_ptr->palette,
+ (png_uint_32)info_ptr->num_palette);
+ else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Valid palette required for paletted images\n");
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
+ info_ptr->num_trans, info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_hIST)
+ png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
+#endif
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
+ info_ptr->offset_unit_type);
+#endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pCAL)
+ png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
+ info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+ info_ptr->pcal_units, info_ptr->pcal_params);
+#endif
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
+ info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+ png_ptr->flags |= PNG_FLAG_WROTE_tIME;
+ }
+#endif
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* Check to see if we need to write text chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing header text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* If we want a compressed text chunk */
+ if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+}
+
+/* Writes the end of the PNG file. If you don't want to write comments or
+ time information, you can pass NULL for info. If you already wrote these
+ in png_write_info(), do not write them again here. If you have long
+ comments, I suggest writing them here, and compressing them. */
+void
+png_write_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_end\n");
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "No IDATs written into file");
+
+ /* see if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+ int i; /* local index variable */
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ /* check to see if user has supplied a time chunk */
+ if (info_ptr->valid & PNG_INFO_tIME &&
+ !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+#endif
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* loop through comment chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ /* write end of PNG file */
+ png_write_IEND(png_ptr);
+}
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+void
+png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
+{
+ png_debug(1, "in png_convert_from_struct_tm\n");
+ ptime->year = (png_uint_16)(1900 + ttime->tm_year);
+ ptime->month = (png_byte)(ttime->tm_mon + 1);
+ ptime->day = (png_byte)ttime->tm_mday;
+ ptime->hour = (png_byte)ttime->tm_hour;
+ ptime->minute = (png_byte)ttime->tm_min;
+ ptime->second = (png_byte)ttime->tm_sec;
+}
+
+void
+png_convert_from_time_t(png_timep ptime, time_t ttime)
+{
+ struct tm *tbuf;
+
+ png_debug(1, "in png_convert_from_time_t\n");
+ tbuf = gmtime(&ttime);
+ png_convert_from_struct_tm(ptime, tbuf);
+}
+#endif
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+png_structp
+png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+ png_structp png_ptr;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+ png_debug(1, "in png_create_write_struct\n");
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+ {
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_destroy_struct(png_ptr);
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
+
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+ return (png_ptr);
+}
+
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+void
+png_write_init(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+
+ png_debug(1, "in png_write_init\n");
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, NULL, NULL);
+#endif
+}
+
+/* write a few rows of image data. If the image is interlaced,
+ either you will have to write the 7 sub images, or, if you
+ have called png_set_interlace_handling(), you will have to
+ "write" the image seven times */
+void
+png_write_rows(png_structp png_ptr, png_bytepp row,
+ png_uint_32 num_rows)
+{
+ png_uint_32 i; /* row counter */
+ png_bytepp rp; /* row pointer */
+
+ png_debug(1, "in png_write_rows\n");
+ /* loop through the rows */
+ for (i = 0, rp = row; i < num_rows; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+}
+
+/* write the image. You only need to call this function once, even
+ if you are writing an interlaced image. */
+void
+png_write_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i; /* row index */
+ int pass, num_pass; /* pass variables */
+ png_bytepp rp; /* points to current row */
+
+ png_debug(1, "in png_write_image\n");
+ /* intialize interlace handling. If image is not interlaced,
+ this will set pass to 1 */
+ num_pass = png_set_interlace_handling(png_ptr);
+ /* loop through passes */
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ /* loop through image */
+ for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+ }
+}
+
+/* called by user to write a row of image data */
+void
+png_write_row(png_structp png_ptr, png_bytep row)
+{
+ png_debug(1, "in png_write_row\n");
+ /* initialize transformations and other stuff if first time */
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ png_write_start_row(png_ptr);
+ }
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* if interlaced and not interested in row, return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 7)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 7) || png_ptr->width < 5)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 7) != 4)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ /* set up row info for transformations */
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->usr_width;
+ png_ptr->row_info.channels = png_ptr->usr_channels;
+ png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_debug1(4, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
+ png_debug1(4, "row_info->width = %d\n", png_ptr->row_info.width);
+ png_debug1(4, "row_info->channels = %d\n", png_ptr->row_info.channels);
+ png_debug1(4, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
+ png_debug1(4, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
+ png_debug1(4, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
+
+ /* Copy user's row into buffer, leaving room for filter byte. */
+ png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* handle interlacing */
+ if (png_ptr->interlaced && png_ptr->pass < 6 &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_do_write_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass);
+ /* this should always get caught above, but still ... */
+ if (!(png_ptr->row_info.width))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ }
+#endif
+
+ /* handle other transformations */
+ if (png_ptr->transformations)
+ png_do_write_transformations(png_ptr);
+
+ /* Find a filter if necessary, filter the row and write it out. */
+ png_write_find_filter(png_ptr, &(png_ptr->row_info));
+}
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set the automatic flush interval or 0 to turn flushing off */
+void
+png_set_flush(png_structp png_ptr, int nrows)
+{
+ png_debug(1, "in png_set_flush\n");
+ png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+}
+
+/* flush the current output buffers now */
+void
+png_write_flush(png_structp png_ptr)
+{
+ int wrote_IDAT;
+
+ png_debug(1, "in png_write_flush\n");
+ /* We have already written out all of the data */
+ if (png_ptr->row_number >= png_ptr->num_rows)
+ return;
+
+ do
+ {
+ int ret;
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
+ wrote_IDAT = 0;
+
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ wrote_IDAT = 1;
+ }
+ } while(wrote_IDAT == 1);
+
+ /* If there is any data left to be output, write it into a new IDAT */
+ if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ png_ptr->flush_rows = 0;
+ png_flush(png_ptr);
+}
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* free all memory used by the write */
+void
+png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_write_struct\n");
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_destroy_struct((png_voidp)info_ptr);
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+ png_write_destroy(png_ptr);
+ png_destroy_struct((png_voidp)png_ptr);
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+
+/* Free any memory used in png_ptr struct (old method) */
+void
+png_write_destroy(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* save jump buffer */
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+
+ png_debug(1, "in png_write_destroy\n");
+ /* free any memory zlib uses */
+ deflateEnd(&png_ptr->zstream);
+
+ /* free our memory. png_free checks NULL for us. */
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+ png_free(png_ptr, png_ptr->sub_row);
+ png_free(png_ptr, png_ptr->up_row);
+ png_free(png_ptr, png_ptr->avg_row);
+ png_free(png_ptr, png_ptr->paeth_row);
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_free(png_ptr, png_ptr->prev_filters);
+ png_free(png_ptr, png_ptr->filter_weights);
+ png_free(png_ptr, png_ptr->inv_filter_weights);
+ png_free(png_ptr, png_ptr->filter_costs);
+ png_free(png_ptr, png_ptr->inv_filter_costs);
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+ /* reset structure */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
+
+/* Allow the application to select one or more row filters to use. */
+void
+png_set_filter(png_structp png_ptr, int method, int filters)
+{
+ png_debug(1, "in png_set_filter\n");
+ /* We allow 'method' only for future expansion of the base filter method. */
+ if (method == PNG_FILTER_TYPE_BASE)
+ {
+ switch (filters & (PNG_ALL_FILTERS | 0x07))
+ {
+ case 5:
+ case 6:
+ case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break;
+ case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break;
+ case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break;
+ case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break;
+ case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
+ default: png_ptr->do_filter = (png_byte)filters; break;
+ }
+
+ /* If we have allocated the row_buf, this means we have already started
+ * with the image and we should have allocated all of the filter buffers
+ * that have been selected. If prev_row isn't already allocated, then
+ * it is too late to start using the filters that need it, since we
+ * will be missing the data in the previous row. If an application
+ * wants to start and stop using particular filters during compression,
+ * it should start out with all of the filters, and then add and
+ * remove them after the start of compression.
+ */
+ if (png_ptr->row_buf != NULL)
+ {
+ if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Up filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_UP;
+ }
+ else
+ {
+ png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Average filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_AVG;
+ }
+ else
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH &&
+ png_ptr->paeth_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Paeth filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_PAETH;
+ }
+ else
+ {
+ png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+ if (png_ptr->do_filter == PNG_NO_FILTERS)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ }
+ }
+ else
+ png_error(png_ptr, "Unknown custom filter method");
+}
+
+/* This allows us to influence the way in which libpng chooses the "best"
+ * filter for the current scanline. While the "minimum-sum-of-absolute-
+ * differences metric is relatively fast and effective, there is some
+ * question as to whether it can be improved upon by trying to keep the
+ * filtered data going to zlib more consistent, hopefully resulting in
+ * better compression. */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
+void
+png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
+ int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs)
+{
+ int i;
+
+ png_debug(1, "in png_set_filter_heuristics\n");
+ if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
+ {
+ png_warning(png_ptr, "Unknown filter heuristic method");
+ return;
+ }
+
+ if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
+ {
+ heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
+ }
+
+ if (num_weights < 0 || filter_weights == NULL ||
+ heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
+ {
+ num_weights = 0;
+ }
+
+ png_ptr->num_prev_filters = num_weights;
+ png_ptr->heuristic_method = heuristic_method;
+
+ if (num_weights > 0)
+ {
+ if (png_ptr->prev_filters == NULL)
+ {
+ png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
+ sizeof(png_byte) * num_weights);
+
+ /* To make sure that the weighting starts out fairly */
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->prev_filters[i] = 255;
+ }
+ }
+
+ if (png_ptr->filter_weights == NULL)
+ {
+ png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ sizeof(png_uint_16) * num_weights);
+
+ png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ sizeof(png_uint_16) * num_weights);
+
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ }
+
+ for (i = 0; i < num_weights; i++)
+ {
+ if (filter_weights[i] < 0.0)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ else
+ {
+ png_ptr->inv_filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
+ png_ptr->filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
+ }
+ }
+ }
+
+ /* If, in the future, there are other filter methods, this would
+ * need to be based on png_ptr->filter.
+ */
+ if (png_ptr->filter_costs == NULL)
+ {
+ png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
+
+ png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
+
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ }
+
+ /* Here is where we set the relative costs of the different filters. We
+ * should take the desired compression level into account when setting
+ * the costs, so that Paeth, for instance, has a high relative cost at low
+ * compression levels, while it has a lower relative cost at higher
+ * compression settings. The filter types are in order of increasing
+ * relative cost, so it would be possible to do this with an algorithm.
+ */
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ if (filter_costs == NULL || filter_costs[i] < 0.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ else if (filter_costs[i] >= 1.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
+ png_ptr->filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
+ }
+ }
+}
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+void
+png_set_compression_level(png_structp png_ptr, int level)
+{
+ png_debug(1, "in png_set_compression_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
+ png_ptr->zlib_level = level;
+}
+
+void
+png_set_compression_mem_level(png_structp png_ptr, int mem_level)
+{
+ png_debug(1, "in png_set_compression_mem_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
+ png_ptr->zlib_mem_level = mem_level;
+}
+
+void
+png_set_compression_strategy(png_structp png_ptr, int strategy)
+{
+ png_debug(1, "in png_set_compression_strategy\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
+ png_ptr->zlib_strategy = strategy;
+}
+
+void
+png_set_compression_window_bits(png_structp png_ptr, int window_bits)
+{
+ if (window_bits > 15)
+ png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
+ png_ptr->zlib_window_bits = window_bits;
+}
+
+void
+png_set_compression_method(png_structp png_ptr, int method)
+{
+ png_debug(1, "in png_set_compression_method\n");
+ if (method != 8)
+ png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
+ png_ptr->zlib_method = method;
+}
+
diff --git a/gs/libpng/pngwtran.c b/gs/libpng/pngwtran.c
new file mode 100644
index 000000000..99d32a442
--- /dev/null
+++ b/gs/libpng/pngwtran.c
@@ -0,0 +1,392 @@
+
+/* pngwtran.c - transforms the data in a row for PNG writers
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* transform the data according to the users wishes. The order of
+ transformations is significant. */
+void
+png_do_write_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_write_transformations\n");
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->flags);
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->bit_depth);
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+}
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+/* pack pixels into bytes. Pass the true bit depth in bit_depth. The
+ row_info bit depth should be 8 (one pixel per byte). The channels
+ should be 1 (this only happens on grayscale and paletted images) */
+void
+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
+{
+ png_debug(1, "in png_do_pack\n");
+ if (row_info->bit_depth == 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->channels == 1)
+ {
+ switch ((int)bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int mask, v;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ mask = 0x80;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*sp != 0)
+ v |= mask;
+ sp++;
+ if (mask > 1)
+ mask >>= 1;
+ else
+ {
+ mask = 0x80;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ }
+ if (mask != 0x80)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ shift = 6;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x3);
+ v |= (value << shift);
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 2;
+ sp++;
+ }
+ if (shift != 6)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ shift = 4;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0xf);
+ v |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 4;
+
+ sp++;
+ }
+ if (shift != 4)
+ *dp = (png_byte)v;
+ break;
+ }
+ }
+ row_info->bit_depth = (png_byte)bit_depth;
+ row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* shift pixel values to take advantage of whole range. Pass the
+ true number of bits in bit_depth. The row should be packed
+ according to row_info->bit_depth. Thus, if you had a row of
+ bit depth 4, but the pixels only had values from 0 to 7, you
+ would pass 3 as bit_depth, and this routine would translate the
+ data to 0 to 15. */
+void
+png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
+{
+ png_debug(1, "in png_do_shift\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL &&
+#else
+ if (
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift_start[4], shift_dec[4];
+ png_uint_32 channels;
+
+ channels = 0;
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->red;
+ shift_dec[channels] = bit_depth->red;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->green;
+ shift_dec[channels] = bit_depth->green;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->blue;
+ shift_dec[channels] = bit_depth->blue;
+ channels++;
+ }
+ else
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->gray;
+ shift_dec[channels] = bit_depth->gray;
+ channels++;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
+ shift_dec[channels] = bit_depth->alpha;
+ channels++;
+ }
+
+ /* with low row dephts, could only be grayscale, so one channel */
+ if (row_info->bit_depth < 8)
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_byte mask;
+
+ if (bit_depth->gray == 1 && row_info->bit_depth == 2)
+ mask = 0x55;
+ else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
+ mask = 0x11;
+ else
+ mask = 0xff;
+
+ for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
+ {
+ png_uint_16 v;
+ int j;
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & mask);
+ }
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ png_bytep bp;
+ png_uint_32 i;
+
+ for (bp = row, i = 0; i < row_info->width; i++)
+ {
+ int c;
+
+ for (c = 0; c < channels; c++, bp++)
+ {
+ png_uint_16 v;
+ int j;
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & 0xff);
+ }
+ }
+ }
+ }
+ else
+ {
+ png_bytep bp;
+ png_uint_32 i;
+
+ for (bp = row, i = 0; i < row_info->width * row_info->channels; i++)
+ {
+ int c;
+
+ for (c = 0; c < channels; c++, bp += 2)
+ {
+ png_uint_16 value, v;
+ int j;
+
+ v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
+ value = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
+ else
+ value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
+ }
+ *bp = (png_byte)(value >> 8);
+ *(bp + 1) = (png_byte)(value & 0xff);
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void
+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from ARGB to RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row; i < row_info->width; i++)
+ {
+ save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AARRGGBB to RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row; i < row_info->width; i++)
+ {
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from AG to GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row; i < row_info->width; i++)
+ {
+ save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AAGG to GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0, sp = dp = row; i < row_info->width; i++)
+ {
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
diff --git a/gs/libpng/pngwutil.c b/gs/libpng/pngwutil.c
new file mode 100644
index 000000000..5aec80ce8
--- /dev/null
+++ b/gs/libpng/pngwutil.c
@@ -0,0 +1,1917 @@
+
+/* pngwutil.c - utilities to write a PNG file
+
+ libpng 1.0 beta 6 - version 0.96
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ Copyright (c) 1996, 1997 Andreas Dilger
+ May 12, 1997
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Place a 32-bit number into a buffer in PNG byte order. We work
+ * with unsigned numbers for convenience, although one supported
+ * ancillary chunk uses signed (two's complement) numbers.
+ */
+void
+png_save_uint_32(png_bytep buf, png_uint_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* The png_save_int_32 function assumes integers are stored in two's
+ complement format. If this isn't the case, then this routine needs to
+ be modified to write data in two's complement format. */
+void
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order. */
+void
+png_save_uint_16(png_bytep buf, png_uint_16 i)
+{
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+}
+
+/* Write a PNG chunk all at once. The type is an array of ASCII characters
+ representing the chunk name. The array must be at least 4 bytes in
+ length, and does not need to be null terminated. To be safe, pass the
+ pre-defined chunk names here, and if you need a new one, define it
+ where the others are defined. The length is the length of the data.
+ All the data must be present. If that is not possible, use the
+ png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
+ functions instead. */
+void
+png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
+ png_bytep data, png_size_t length)
+{
+ png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
+ png_write_chunk_data(png_ptr, data, length);
+ png_write_chunk_end(png_ptr);
+}
+
+/* Write the start of a PNG chunk. The type is the chunk type.
+ The total_length is the sum of the lengths of all the data you will be
+ passing in png_write_chunk_data() */
+void
+png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
+ png_uint_32 length)
+{
+ png_byte buf[4];
+ png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);
+
+ /* write the length */
+ png_save_uint_32(buf, length);
+ png_write_data(png_ptr, buf, (png_size_t)4);
+
+ /* write the chunk name */
+ png_write_data(png_ptr, chunk_name, (png_size_t)4);
+ /* reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
+}
+
+/* Write the data of a PNG chunk started with png_write_chunk_start().
+ Note that multiple calls to this function are allowed, and that the
+ sum of the lengths from these calls *must* add up to the total_length
+ given to png_write_chunk_start(). */
+void
+png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ /* write the data, and run the CRC over it */
+ if (data != NULL && length > 0)
+ {
+ png_calculate_crc(png_ptr, data, length);
+ png_write_data(png_ptr, data, length);
+ }
+}
+
+/* Finish a chunk started with png_write_chunk_start(). */
+void
+png_write_chunk_end(png_structp png_ptr)
+{
+ png_byte buf[4];
+
+ /* write the crc */
+#ifdef PNG_USE_OWN_CRC
+ png_save_uint_32(buf, ~png_ptr->crc);
+#else
+ png_save_uint_32(buf, png_ptr->crc);
+#endif
+
+ png_write_data(png_ptr, buf, (png_size_t)4);
+}
+
+/* Simple function to write the signature. If we have already written
+ * the magic bytes of the signature, or more likely, the PNG stream is
+ * being embedded into another stream and doesn't need its own signature,
+ * we should call png_set_sig_bytes() to tell libpng how many of the
+ * bytes have already been written. */
+void
+png_write_sig(png_structp png_ptr)
+{
+ /* write the rest of the 8 byte signature */
+ png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
+ (png_size_t)8 - png_ptr->sig_bytes);
+}
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ information. Note that the rest of this code depends upon this
+ information being correct. */
+void
+png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type)
+{
+ png_byte buf[13]; /* buffer to store the IHDR info */
+
+ png_debug(1, "in png_write_IHDR\n");
+ /* Check that we have valid input data from the application info */
+ switch (color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16: png_ptr->channels = 1; break;
+ default: png_error(png_ptr,"Invalid bit depth for grayscale image");
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGB image");
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8: png_ptr->channels = 1; break;
+ default: png_error(png_ptr, "Invalid bit depth for paletted image");
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGBA image");
+ png_ptr->channels = 4;
+ break;
+ default:
+ png_error(png_ptr, "Invalid image color type specified");
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid compression type specified");
+ compression_type = PNG_COMPRESSION_TYPE_BASE;
+ }
+
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid filter type specified");
+ filter_type = PNG_FILTER_TYPE_BASE;
+ }
+
+ if (interlace_type != PNG_INTERLACE_NONE &&
+ interlace_type != PNG_INTERLACE_ADAM7)
+ {
+ png_warning(png_ptr, "Invalid interlace type specified");
+ interlace_type = PNG_INTERLACE_ADAM7;
+ }
+
+ /* save off the relevent information */
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->color_type = (png_byte)color_type;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->width = width;
+ png_ptr->height = height;
+
+ png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
+ png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
+ /* set the usr info, so any transformations can modify it */
+ png_ptr->usr_width = png_ptr->width;
+ png_ptr->usr_bit_depth = png_ptr->bit_depth;
+ png_ptr->usr_channels = png_ptr->channels;
+
+ /* pack the header information into the buffer */
+ png_save_uint_32(buf, width);
+ png_save_uint_32(buf + 4, height);
+ buf[8] = (png_byte)bit_depth;
+ buf[9] = (png_byte)color_type;
+ buf[10] = (png_byte)compression_type;
+ buf[11] = (png_byte)filter_type;
+ buf[12] = (png_byte)interlace_type;
+
+ /* write the chunk */
+ png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
+ /* initialize zlib with PNG info */
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+ if (!(png_ptr->do_filter))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+ png_ptr->bit_depth < 8)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ else
+ png_ptr->do_filter = PNG_ALL_FILTERS;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
+ {
+ if (png_ptr->do_filter != PNG_FILTER_NONE)
+ png_ptr->zlib_strategy = Z_FILTERED;
+ else
+ png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
+ png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
+ png_ptr->zlib_mem_level = 8;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
+ png_ptr->zlib_window_bits = 15;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
+ png_ptr->zlib_method = 8;
+ deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
+ png_ptr->zlib_method, png_ptr->zlib_window_bits,
+ png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_ptr->mode = PNG_HAVE_IHDR;
+}
+
+/* write the palette. We are careful not to trust png_color to be in the
+ correct order for PNG, so people can redefine it to any convient
+ structure. */
+void
+png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
+{
+ png_uint_32 i;
+ png_colorp pal_ptr;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_PLTE\n");
+ if (num_pal == 0 || num_pal > 256)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_error(png_ptr, "Invalid number of colors in palette");
+ }
+ else
+ {
+ png_warning(png_ptr, "Invalid number of colors in palette");
+ return;
+ }
+ }
+
+ png_ptr->num_palette = (png_uint_16)num_pal;
+ png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
+
+ png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
+ for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
+ {
+ buf[0] = pal_ptr->red;
+ buf[1] = pal_ptr->green;
+ buf[2] = pal_ptr->blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+ png_write_chunk_end(png_ptr);
+ png_ptr->mode |= PNG_HAVE_PLTE;
+}
+
+/* write an IDAT chunk */
+void
+png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug(1, "in png_write_IDAT\n");
+ png_write_chunk(png_ptr, png_IDAT, data, length);
+ png_ptr->mode |= PNG_HAVE_IDAT;
+}
+
+/* write an IEND chunk */
+void
+png_write_IEND(png_structp png_ptr)
+{
+ png_debug(1, "in png_write_IEND\n");
+ png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
+ png_ptr->mode |= PNG_HAVE_IEND;
+}
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+/* write a gAMA chunk */
+void
+png_write_gAMA(png_structp png_ptr, double file_gamma)
+{
+ png_uint_32 igamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/100,000ths */
+ igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
+ png_save_uint_32(buf, igamma);
+ png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
+}
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+/* write the sBIT chunk */
+void
+png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
+{
+ png_byte buf[4];
+ png_size_t size;
+
+ png_debug(1, "in png_write_sBIT\n");
+ /* make sure we don't depend upon the order of PNG_COLOR_8 */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ int maxbits;
+
+ maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
+ if (sbit->red == 0 || sbit->red > maxbits ||
+ sbit->green == 0 || sbit->green > maxbits ||
+ sbit->blue == 0 || sbit->blue > maxbits)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->red;
+ buf[1] = sbit->green;
+ buf[2] = sbit->blue;
+ size = 3;
+ }
+ else
+ {
+ if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->gray;
+ size = 1;
+ }
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[size++] = sbit->alpha;
+ }
+
+ png_write_chunk(png_ptr, png_sBIT, buf, size);
+}
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+/* write the cHRM chunk */
+void
+png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y)
+{
+ png_uint_32 itemp;
+ png_byte buf[32];
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved int 1/100,000ths */
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point specified");
+ return;
+ }
+ itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
+ png_save_uint_32(buf, itemp);
+ itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 4, itemp);
+
+ if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
+ red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point specified");
+ return;
+ }
+ itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 8, itemp);
+ itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 12, itemp);
+
+ if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
+ green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point specified");
+ return;
+ }
+ itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 16, itemp);
+ itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 20, itemp);
+
+ if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
+ blue_x + blue_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point specified");
+ return;
+ }
+ itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 24, itemp);
+ itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 28, itemp);
+
+ png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
+}
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+/* write the tRNS chunk */
+void
+png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
+ int num_trans, int color_type)
+{
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_tRNS\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (num_trans <= 0 || num_trans > png_ptr->num_palette)
+ {
+ png_warning(png_ptr,"Invalid number of transparent colors specified");
+ return;
+ }
+ /* write the chunk out as it is */
+ png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
+ }
+ else if (color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ /* one 16 bit value */
+ png_save_uint_16(buf, tran->gray);
+ png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
+ }
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ {
+ /* three 16 bit values */
+ png_save_uint_16(buf, tran->red);
+ png_save_uint_16(buf + 2, tran->green);
+ png_save_uint_16(buf + 4, tran->blue);
+ png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_warning(png_ptr, "Can't write tRNS with and alpha channel");
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+/* write the background chunk */
+void
+png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
+{
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_bKGD\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (back->index > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Invalid background palette index");
+ return;
+ }
+ buf[0] = back->index;
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
+ }
+ else if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_save_uint_16(buf, back->red);
+ png_save_uint_16(buf + 2, back->green);
+ png_save_uint_16(buf + 4, back->blue);
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_save_uint_16(buf, back->gray);
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+/* write the histogram */
+void
+png_write_hIST(png_structp png_ptr, png_uint_16p hist, png_uint_32 num_hist)
+{
+ png_uint_32 i;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_hIST\n");
+ if (num_hist > png_ptr->num_palette)
+ {
+ png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
+ png_ptr->num_palette);
+ png_warning(png_ptr, "Invalid number of histogram entries specified");
+ return;
+ }
+
+ png_write_chunk_start(png_ptr, png_hIST, num_hist * 2);
+ for (i = 0; i < num_hist; i++)
+ {
+ png_save_uint_16(buf, hist[i]);
+ png_write_chunk_data(png_ptr, buf, (png_size_t)2);
+ }
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The new_key is allocated to hold the corrected keyword and must be freed
+ * by the calling routine. This avoids problems with trying to write to
+ * static keywords without having to have duplicate copies of the strings.
+ */
+png_size_t
+png_check_keyword(png_structp png_ptr, png_charp key, png_bytepp new_key)
+{
+ png_size_t key_len;
+ png_charp kp;
+ png_bytep dp;
+ int kflag;
+
+ png_debug(1, "in png_check_keyword\n");
+ *new_key = NULL;
+
+ if (key == NULL || (key_len = png_strlen(key)) == 0)
+ {
+ char msg[40];
+
+ sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
+ png_warning(png_ptr, msg);
+ return 0;
+ }
+
+ png_debug1(2, "Keyword to be checked is '%s'\n", key);
+
+ *new_key = (png_bytep)png_malloc(png_ptr, key_len + 1);
+
+ /* Replace non-printing characters with a blank and print a warning */
+ for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
+ {
+ if (*kp < 0x20 || ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
+ {
+ char msg[40];
+
+ sprintf(msg, "Invalid %s keyword character 0x%02X",
+ png_ptr->chunk_name, *kp);
+ png_warning(png_ptr, msg);
+ *dp = ' ';
+ }
+ else
+ {
+ *dp = *kp;
+ }
+ }
+ *dp = '\0';
+
+ /* Remove any trailing white space. */
+ kp = *new_key + key_len - 1;
+ if (*kp == ' ')
+ {
+ char msg[50];
+ sprintf(msg, "Trailing spaces removed from %s keyword",
+ png_ptr->chunk_name);
+
+ png_warning(png_ptr, msg);
+
+ while (*kp == ' ')
+ {
+ *(kp--) = '\0';
+ key_len--;
+ }
+ }
+
+ /* Remove any leading white space. */
+ kp = *new_key;
+ if (*kp == ' ')
+ {
+ char msg[50];
+ sprintf(msg, "Leading spaces removed from %s keyword",
+ png_ptr->chunk_name);
+
+ png_warning(png_ptr, msg);
+
+ while (*kp == ' ')
+ {
+ kp++;
+ key_len--;
+ }
+ }
+
+ png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
+
+ /* Remove multiple internal spaces. */
+ for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
+ {
+ if (*kp == ' ' && kflag == 0)
+ {
+ *(dp++) = *kp;
+ kflag = 1;
+ }
+ else if (*kp == ' ')
+ {
+ key_len--;
+ }
+ else
+ {
+ *(dp++) = *kp;
+ kflag = 0;
+ }
+ }
+ *dp = '\0';
+
+ if (key_len == 0)
+ {
+ char msg[40];
+
+ sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
+ png_warning(png_ptr, msg);
+ }
+
+ if (key_len > 79)
+ {
+ char msg[50];
+
+ sprintf(msg, "%s keyword length must be 1 - 79 characters",
+ png_ptr->chunk_name);
+ png_warning(png_ptr, msg);
+ new_key[79] = '\0';
+ key_len = 79;
+ }
+
+ return key_len;
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+/* write a tEXt chunk */
+void
+png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len)
+{
+ png_size_t key_len;
+ png_bytep new_key;
+
+ png_debug(1, "in png_write_tEXt\n");
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ char msg[40];
+
+ sprintf(msg, "Empty keyword in %s chunk", "tEXt");
+ png_warning(png_ptr, msg);
+ return;
+ }
+
+ if (text == NULL || *text == '\0')
+ text_len = 0;
+
+ /* make sure we include the 0 after the key */
+ png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
+ png_write_chunk_data(png_ptr, new_key, key_len + 1);
+ if (text_len)
+ png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+}
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+/* write a compressed text chunk */
+void
+png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len, int compression)
+{
+ png_size_t key_len;
+ char buf[1];
+ png_bytep new_key;
+ int i, ret;
+ png_charpp output_ptr = NULL; /* array of pointers to output */
+ int num_output_ptr = 0; /* number of output pointers used */
+ int max_output_ptr = 0; /* size of output_ptr */
+
+ png_debug(1, "in png_write_zTXt\n");
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ char msg[40];
+
+ sprintf(msg, "Empty keyword in %s chunk", "zTXt");
+ png_warning(png_ptr, msg);
+ return;
+ }
+
+ if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
+ {
+ png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
+ png_free(png_ptr, new_key);
+ return;
+ }
+
+ png_free(png_ptr, new_key);
+
+ if (compression >= PNG_TEXT_COMPRESSION_LAST)
+ {
+ char msg[50];
+ sprintf(msg, "Unknown zTXt compression type %d", compression);
+ png_warning(png_ptr, msg);
+ compression = PNG_TEXT_COMPRESSION_zTXt;
+ }
+
+ /* We can't write the chunk until we find out how much data we have,
+ * which means we need to run the compressor first, and save the
+ * output. This shouldn't be a problem, as the vast majority of
+ * comments should be reasonable, but we will set up an array of
+ * malloc'd pointers to be sure.
+ *
+ * If we knew the application was well behaved, we could simplify this
+ * greatly by assuming we can always malloc an output buffer large
+ * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
+ * and malloc this directly. The only time this would be a bad idea is
+ * if we can't malloc more than 64K and we have 64K of random input
+ * data, or if the input string is incredibly large (although this
+ * wouldn't cause a failure, just a slowdown due to swapping).
+ */
+
+ /* set up the compression buffers */
+ png_ptr->zstream.avail_in = (uInt)text_len;
+ png_ptr->zstream.next_in = (Bytef *)text;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
+
+ /* this is the same compression loop as in png_write_row() */
+ do
+ {
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ /* error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
+ {
+ /* make sure the output array has room */
+ if (num_output_ptr >= max_output_ptr)
+ {
+ int old_max;
+
+ old_max = max_output_ptr;
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = output_ptr;
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ max_output_ptr * sizeof (png_charpp));
+ png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ max_output_ptr * sizeof (png_charp));
+ }
+
+ /* save the data */
+ output_ptr[num_output_ptr] = png_malloc(png_ptr, png_ptr->zbuf_size);
+ png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ num_output_ptr++;
+
+ /* and reset the buffer */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ /* continue until we don't have anymore to compress */
+ } while (png_ptr->zstream.avail_in);
+
+ /* finish the compression */
+ do
+ {
+ /* tell zlib we are finished */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ /* we got an error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
+ {
+ /* check to make sure our output array has room */
+ if (num_output_ptr >= max_output_ptr)
+ {
+ int old_max;
+
+ old_max = max_output_ptr;
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = output_ptr;
+ /* This could be optimized to realloc() */
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ max_output_ptr * sizeof (png_charpp));
+ png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ max_output_ptr * sizeof (png_charp));
+ }
+
+ /* save off the data */
+ output_ptr[num_output_ptr] = png_malloc(png_ptr,
+ png_ptr->zbuf_size);
+ png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ num_output_ptr++;
+
+ /* and reset the buffer pointers */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* text length is number of buffers plus last buffer */
+ text_len = png_ptr->zbuf_size * num_output_ptr;
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
+
+ /* write start of chunk */
+ png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)(key_len+text_len+2));
+ /* write key */
+ png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
+ buf[0] = (png_byte)compression;
+ /* write compression */
+ png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
+
+ /* write saved output buffers, if any */
+ for (i = 0; i < num_output_ptr; i++)
+ {
+ png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
+ png_free(png_ptr, output_ptr[i]);
+ }
+ if (max_output_ptr != 0)
+ png_free(png_ptr, output_ptr);
+ /* write anything left in zbuf */
+ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
+ png_write_chunk_data(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ /* close the chunk */
+ png_write_chunk_end(png_ptr);
+
+ /* reset zlib for another zTXt or the image data */
+ deflateReset(&png_ptr->zstream);
+}
+#endif
+
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+/* write the oFFs chunk */
+void
+png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
+ png_uint_32 y_offset,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_oFFs\n");
+ if (unit_type >= PNG_OFFSET_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
+
+ png_save_uint_32(buf, x_offset);
+ png_save_uint_32(buf + 4, y_offset);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* write the pCAL chunk (png-scivis-19970203) */
+void
+png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
+ png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+{
+ png_size_t purpose_len, units_len, total_len;
+ png_uint_32p params_len;
+ png_byte buf[10];
+ png_bytep new_purpose;
+ int i;
+
+ png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
+ if (type >= PNG_EQUATION_LAST)
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+ purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+ png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
+ units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
+ png_debug1(3, "pCAL units length = %d\n", units_len);
+ total_len = purpose_len + units_len + 10;
+
+ params_len = (png_uint_32p)png_malloc(png_ptr, nparams*sizeof(png_uint_32));
+
+ /* Find the length of each parameter, making sure we don't count the
+ null terminator for the last parameter. */
+ for (i = 0; i < nparams; i++)
+ {
+ params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+ png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
+ total_len += (png_size_t)params_len[i];
+ }
+
+ png_debug1(3, "pCAL total length = %d\n", total_len);
+ png_write_chunk_start(png_ptr, png_pCAL, total_len);
+ png_write_chunk_data(png_ptr, new_purpose, purpose_len);
+ png_save_int_32(buf, X0);
+ png_save_int_32(buf + 4, X1);
+ buf[8] = (png_byte)type;
+ buf[9] = (png_byte)nparams;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)10);
+ png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
+
+ png_free(png_ptr, new_purpose);
+
+ for (i = 0; i < nparams; i++)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)params[i],
+ (png_size_t)params_len[i]);
+ }
+
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+/* write the pHYs chunk */
+void
+png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_pHYs\n");
+ if (unit_type >= PNG_RESOLUTION_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
+
+ png_save_uint_32(buf, x_pixels_per_unit);
+ png_save_uint_32(buf + 4, y_pixels_per_unit);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* write the tIME chunk. Use either png_convert_from_struct_tm()
+ or png_convert_from_time_t(), or fill in the structure yourself */
+void
+png_write_tIME(png_structp png_ptr, png_timep mod_time)
+{
+ png_byte buf[7];
+
+ png_debug(1, "in png_write_tIME\n");
+ if (mod_time->month > 12 || mod_time->month < 1 ||
+ mod_time->day > 31 || mod_time->day < 1 ||
+ mod_time->hour > 23 || mod_time->second > 60)
+ {
+ png_warning(png_ptr, "Invalid time specified for tIME chunk");
+ return;
+ }
+
+ png_save_uint_16(buf, mod_time->year);
+ buf[2] = mod_time->month;
+ buf[3] = mod_time->day;
+ buf[4] = mod_time->hour;
+ buf[5] = mod_time->minute;
+ buf[6] = mod_time->second;
+
+ png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
+}
+#endif
+
+/* initializes the row writing capability of libpng */
+void
+png_write_start_row(png_structp png_ptr)
+{
+ png_size_t buf_size;
+
+ png_debug(1, "in png_write_start_row\n");
+ buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
+ png_ptr->usr_bit_depth + 7) >> 3) + 1);
+
+ /* set up row buffer */
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
+ png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
+
+ /* set up filtering buffer, if using this filter */
+ if (png_ptr->do_filter & PNG_FILTER_SUB)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ /* We only need to keep the previous row if we are using one of these. */
+ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
+ {
+ /* set up previous row buffer */
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, buf_size);
+ png_memset(png_ptr->prev_row, 0, buf_size);
+
+ if (png_ptr->do_filter & PNG_FILTER_UP)
+ {
+ png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG)
+ {
+ png_ptr->avg_row = (png_bytep )png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH)
+ {
+ png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+ /* if interlaced, we need to set up width and height of pass */
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
+ png_pass_start[0]) / png_pass_inc[0];
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+}
+
+/* Internal use only. Called when finished processing a row of data. */
+void
+png_write_finish_row(png_structp png_ptr)
+{
+ int ret;
+
+ png_debug(1, "in png_write_finish_row\n");
+ /* next row */
+ png_ptr->row_number++;
+
+ /* see if we are done */
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ /* if interlaced, go to next pass */
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ if (png_ptr->transformations & PNG_INTERLACE)
+ {
+ png_ptr->pass++;
+ }
+ else
+ {
+ /* loop until we find a non-zero width or height pass */
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->usr_width = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
+
+ }
+
+ /* reset the row above the image for the next pass */
+ if (png_ptr->pass < 7)
+ {
+ if (png_ptr->prev_row != NULL)
+ png_memset(png_ptr->prev_row, 0,
+ (png_size_t) (((png_uint_32)png_ptr->usr_channels *
+ (png_uint_32)png_ptr->usr_bit_depth *
+ png_ptr->width + 7) >> 3) + 1);
+ return;
+ }
+ }
+
+ /* if we get here, we've just written the last row, so we need
+ to flush the compressor */
+ do
+ {
+ /* tell the compressor we are done */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ /* check for an error */
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* write any extra space */
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out);
+ }
+
+ deflateReset(&png_ptr->zstream);
+}
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* pick out the correct pixels for the interlace pass.
+
+ The basic idea here is to go through the row with a source
+ pointer and a destination pointer (sp and dp), and copy the
+ correct pixels for the pass. As the row gets compacted,
+ sp will always be >= dp, so we should never overwrite anything.
+ See the default: case for the easiest code to understand.
+ */
+void
+png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
+{
+ png_debug(1, "in png_do_write_interlace\n");
+ /* we don't have to do anything on the last pass (6) */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && pass < 6)
+#else
+ if (pass < 6)
+#endif
+ {
+ /* each pixel depth is handled seperately */
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ d = 0;
+ shift = 7;
+ for (i = png_pass_start[pass]; i < row_info->width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 3);
+ value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 7;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift--;
+
+ }
+ if (shift != 7)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ shift = 6;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_info->width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 2);
+ value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 2;
+ }
+ if (shift != 6)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ shift = 4;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_info->width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 1);
+ value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 4;
+ }
+ if (shift != 4)
+ *dp = (png_byte)d;
+ break;
+ }
+ default:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+
+ /* start at the beginning */
+ dp = row;
+ /* find out how many bytes each pixel takes up */
+ pixel_bytes = (row_info->pixel_depth >> 3);
+ /* loop through the row, only looking at the pixels that
+ matter */
+ for (i = png_pass_start[pass]; i < row_info->width;
+ i += png_pass_inc[pass])
+ {
+ /* find out where the original pixel is */
+ sp = row + i * pixel_bytes;
+ /* move the pixel */
+ if (dp != sp)
+ png_memcpy(dp, sp, pixel_bytes);
+ /* next pixel */
+ dp += pixel_bytes;
+ }
+ break;
+ }
+ }
+ /* set new row width */
+ row_info->width = (row_info->width +
+ png_pass_inc[pass] - 1 -
+ png_pass_start[pass]) /
+ png_pass_inc[pass];
+ row_info->rowbytes = ((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+
+ }
+}
+#endif
+
+/* This filters the row, chooses which filter to use, if it has not already
+ * been specified by the application, and then writes the row out with the
+ * chosen filter. */
+#define PNG_MAXSUM (~0x0UL >> 1)
+#define PNG_HISHIFT 10
+#define PNG_LOMASK 0xffffL
+#define PNG_HIMASK (~PNG_LOMASK >> PNG_HISHIFT)
+void
+png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
+{
+ png_bytep prev_row, best_row, row_buf;
+ png_uint_32 mins, bpp;
+
+ png_debug(1, "in png_write_find_filter\n");
+ /* find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) / 8;
+
+ prev_row = png_ptr->prev_row;
+ best_row = row_buf = png_ptr->row_buf;
+ mins = PNG_MAXSUM;
+
+ /* The prediction method we use is to find which method provides the
+ * smallest value when summing the absolute values of the distances
+ * from zero using anything >= 128 as negative numbers. This is known
+ * as the "minimum sum of absolute differences" heuristic. Other
+ * heruistics are the "weighted minumum sum of absolute differences"
+ * (experimental and can in theory improve compression), and the "zlib
+ * predictive" method (not implemented in libpng 0.95), which does test
+ * compressions of lines using different filter methods, and then chooses
+ * the (series of) filter(s) which give minimum compressed data size (VERY
+ * computationally expensive).
+ */
+
+ /* We don't need to test the 'no filter' case if this is the only filter
+ * that has been chosen, as it doesn't actually do anything to the data.
+ */
+ if (png_ptr->do_filter & PNG_FILTER_NONE &&
+ png_ptr->do_filter != PNG_FILTER_NONE)
+ {
+ png_bytep rp;
+ png_uint_32 sum = 0;
+ png_size_t i;
+ int v;
+
+ for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
+ {
+ v = *rp;
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
+
+ /* Reduce the sum if we match any of the previous rows */
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ /* Factor in the cost of this filter (this is here for completeness,
+ * but it makes no sense to have a "cost" for the NONE filter, as
+ * it has the minimum possible computational cost - none).
+ */
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+ mins = sum;
+ }
+
+ /* sub filter */
+ if (png_ptr->do_filter & PNG_FILTER_SUB)
+ {
+ png_bytep rp, dp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_size_t i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* We temporarily increase the "minumum sum" by the factor we
+ * would reduce the sum of this filter, so that we can do the
+ * early exit comparison without scaling the sum each time.
+ */
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ v = *dp = *rp;
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
+ {
+ sumlo = (sumlo * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->sub_row;
+ }
+ }
+
+ /* up filter */
+ if (png_ptr->do_filter & PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_size_t i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_UP)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_UP)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->up_row;
+ }
+ }
+
+ /* avg filter */
+ if (png_ptr->do_filter & PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_size_t i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_AVG)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_info->rowbytes;
+ i++, rp++, pp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->avg_row;
+ }
+ }
+
+ /* Paeth filter */
+ if (png_ptr->do_filter & PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_size_t i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_PAETH)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
+ i++, rp++, pp++, lp++, dp++, cp++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp;
+ c = *cp;
+ a = *lp;
+
+ p = a + b - c;
+ pa = abs(p - a);
+ pb = abs(p - b);
+ pc = abs(p - c);
+
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+
+ v = *dp = (png_byte)(((int)*rp - p) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (i = 0; i < png_ptr->num_prev_filters; i++)
+ {
+ if (png_ptr->prev_filters[i] == PNG_FILTER_PAETH)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ best_row = png_ptr->paeth_row;
+ }
+ }
+
+ /* Do the actual writing of the filtered row data from the chosen filter. */
+ png_write_filtered_row(png_ptr, best_row);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* Save the type of filter we picked this time for future calculations */
+ if (png_ptr->num_prev_filters > 0)
+ {
+ png_byte i;
+
+ for (i = 1; i < png_ptr->num_prev_filters; i++)
+ {
+ png_ptr->prev_filters[i] = png_ptr->prev_filters[i - 1];
+ }
+ png_ptr->prev_filters[i] = best_row[0];
+ }
+#endif
+}
+
+
+/* Do the actual writing of a previously filtered row. */
+void
+png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
+{
+ png_debug(1, "in png_write_filtered_row\n");
+ png_debug1(2, "filter = %d\n", filtered_row[0]);
+ /* set up the zlib input buffer */
+ png_ptr->zstream.next_in = filtered_row;
+ png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
+ /* repeat until we have compressed all the data */
+ do
+ {
+ int ret; /* return of zlib */
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* see if it is time to write another IDAT */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ /* repeat until all data has been compressed */
+ } while (png_ptr->zstream.avail_in);
+
+ /* swap the current and previous rows */
+ if (png_ptr->prev_row != NULL)
+ {
+ png_bytep tptr;
+
+ tptr = png_ptr->prev_row;
+ png_ptr->prev_row = png_ptr->row_buf;
+ png_ptr->row_buf = tptr;
+ }
+
+ /* finish row - updates counters and flushes zlib if last row */
+ png_write_finish_row(png_ptr);
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->flush_rows++;
+
+ if (png_ptr->flush_dist > 0 &&
+ png_ptr->flush_rows >= png_ptr->flush_dist)
+ {
+ png_write_flush(png_ptr);
+ }
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+}
+
diff --git a/gs/make.txt b/gs/make.txt
new file mode 100644
index 000000000..6a2f64e5c
--- /dev/null
+++ b/gs/make.txt
@@ -0,0 +1,1540 @@
+ Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, make.txt, describes how to build Ghostscript executables from
+source.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** Overview ********
+********
+
+This document describes how to build a Ghostscript executable from source
+code. There are 4 major steps to building Ghostscript:
+
+ 1) Acquire the source code.
+
+ 2) Unpack the source code.
+
+ 3) Prepare the makefiles, including making edits for your
+ operating environment and configuration choices.
+
+ 4) Invoke 'make'.
+
+The remaining sections of this document describes each of these steps in
+detail. Note that parts of these steps are platform-dependent.
+
+After you have built Ghostscript, please refer to install.txt for
+instructions on installing it.
+
+********
+******** Acquiring the source code ********
+********
+
+To build Ghostscript, you need the Ghostscript source code itself, and the
+source code for some third-party libraries that Ghostscript uses.
+
+Ghostscript itself
+------------------
+
+The authoritative distribution directory for Aladdin Ghostscript is
+ ftp://ftp.cs.wisc.edu/ghost/aladdin/gs###
+where ### is the Ghostscript version number. GNU Ghostscript should be
+available on all GNU sites.
+
+There are 3 different cases for retrieving the source files.
+
+(1) If neither (2) nor (3) below applies to you, you need:
+ ghostscript-#.##.tar.gz
+ ghostscript-fonts-std-#.##.tar.gz
+ ghostscript-fonts-other-#.##.tar.gz
+where #.## is the version number. (The second part of the version number
+may have either 1 or 2 digits.)
+
+(2) If you are building Aladdin Ghostscript (not GNU Ghostscript) on MS-DOS
+or MS Windows, and you don't have (and don't want to acquire) the tar and
+gzip programs, you can get:
+ gs###fn*.zip
+ gs###sr*.zip
+instead of the .tar.gz files, if the .zip files are available for the
+version you want.
+
+(3) If you are building Ghostscript on MS-DOS or MS Windows and using
+.tar.gz files, rename the files as
+ gs###sr.taz
+ gs###fn1.taz
+ gs###fn2.taz
+respectively when you retrieve them. You will need compatible PC executable
+versions of the tar and gzip programs in this case.
+
+Third-party libraries
+---------------------
+
+You need the source code for the Independent JPEG Group (IJG) library, the
+PNG library, and the zlib library in order to build Ghostscript. The
+authoritative distribution points for these libraries are, respectively:
+
+ IJG library:
+ ftp.uu.net:/graphics/jpeg/jpegsrc.v##.tar.gz
+ ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr##.zip
+ PNG library:
+ ftp://swrinde.nde.swri.edu/pub/png/src/
+ libpng-#.##.tar.gz
+ lpng###.zip (or possibly lbpng###.zip or lp###.zip)
+ zlib library:
+ ftp://ftp.uu.net/pub/archiving/zip/zlib/
+ zlib-#.#.#.tar.gz
+ zlib###.zip
+
+Get the .zip files if you are building on MS-DOS or MS Windows, the .tar.gz
+files for all other environments. Note that each of these libraries has its
+own version numbers that have nothing to do with Ghostscript version
+numbers; you should get the highest numbered version. (You may have to go
+back and get a lower-numbered version if you encounter difficulties in the
+build process, but don't worry about this yet.) If you're running Linux,
+you might check whether these libraries are already available in source form
+on your system, since many Linux distributors include them; but we advise
+you to get the highest version from the Net if you can.
+
+Even though the .zip archive of some old versions of the PNG library may be
+named something other than lpng###.zip, we'll refer to this archive as
+lpng###.zip below, so you might want to rename it after getting it to avoid
+confusion.
+
+********
+******** Unpacking the source code ********
+********
+
+Unfortunately, there are no generally accepted standards for how to package
+source code into archives, so the instructions for unpacking Ghostscript are
+longer than they should be.
+
+The Ghostscript sources normally go into a directory named gs#.##, where
+again #.## is the Ghostscript version number. For the remainder of this
+document, we will refer to the gs#.## directory as the "gs directory".
+
+To unpack a .tar.gz archive, you need the gzip and tar programs. Executable
+versions of these programs are normally available on all Unix systems, and
+are available from GNU sites (including source code) for other environments.
+The way to unpack a .tar.gz archive is
+ gzip -d -c somefile.tar.gz | tar -xf -
+If your version of tar supports the -z switch for automatic decompression,
+you can use
+ tar -zxf somefile.tar.gz
+
+To unpack a .zip archive in a Microsoft environment, you need the PKUNZIP
+program, which is normally delivered with the OS. To unpack a .zip archive,
+ PKUNZIP somefile.zip
+
+We won't say anything more here about unpacking the fonts, since that is not
+part of the build process per se, but of installation.
+
+Ghostscript itself
+------------------
+
+The ghostscript-#.##.tar.gz archive unpacks all of the Ghostscript files
+into the directory ./gs#.##.
+
+The gs###sr*.zip archives also include the subdirectory name gs#.##, but
+some versions of PKUNZIP discard the directory name and always unpack into
+the current directory. If your version of PKUNZIP does this, you must
+ MKDIR gs#.##
+ CD gs#.##
+before unpacking the archive.
+
+Third-party libraries
+---------------------
+
+The file names in the IJG archives (jpegsrc.v##.tar.gz or jpegsr##.zip)
+include a subdirectory name jpeg-##/, so you should unpack them in the same
+way as just described for the Ghostscript sources, except that you should
+make the gs directory current first, and the subdirectory name will be
+jpeg-##. (This will be a subdirectory of the gs directory, of course.)
+
+Unfortunately, the situation for the PNG and zlib libraries varies from
+release to release. If you are using the .tar.gz archives, then:
+
+ - Before unpacking libpng-#.##.tar.gz, make the gs directory
+ current. Unpacking will create a subdirectory named
+ libpng-#.##. Rename this subdirectory as libpng.
+
+ - Before unpacking zlib-#.#.#.tar.gz, make the gs directory
+ current. Unpacking will create a subdirectory named zlib or
+ zlib-#.#.#; if the latter, rename it as zlib.
+
+If you are using the .zip archives, and your version of PKUNZIP preserves
+directory information, follow the same steps as for the .tar.gz archives.
+If your version of PKUNZIP discards directory names:
+
+ - Before unpacking lpng###.zip, make the gs directory current, and
+ then
+ MKDIR libpng
+ CD libpng
+
+ - Before unpacking zlib###.zip or zlib-###.zip, make the gs
+ directory current, and then
+ MKDIR zlib
+ CD zlib
+
+********
+******** Makefile overview ********
+********
+
+The Ghostscript makefiles are very large and complex. Fortunately, the only
+makefiles you are likely to need to deal with are relatively small ones
+containing platform-specific information, as follows:
+
+ ansihead.mak - Unix with ANSI C compilers other than gcc
+ cc-head.mak - Unix with "traditional C" compilers
+ gcc-head.mak - Unix with gcc
+ watc.mak - MS-DOS with Watcom compilers
+ bcwin32.mak - MS Windows with Borland compilers
+ msvc32.mak - MS Windows with Microsoft Visual C++ version 4.n or 5.n
+ watcw32.mak - MS Windows with Watcom compilers
+ openvms.mak - OpenVMS
+ dgc-head.mak - DesqView/X with gcc
+ os2.mak - OS/2 with the gcc/emx compiler
+
+Since the contents of these files change from one Ghostscript version to
+another, sometimes substantially, and since they all include documentation
+for the various options, we won't duplicate most of that documentation here:
+after reading the information below, we strongly recommend that you read the
+entire makefile for your OS and compiler before building Ghostscript.
+
+In Ghostscript versions 5.0*, watcw32.mak doesn't work, so we won't describe
+it further.
+
+For completeness, the platform-independent makefiles are:
+
+ version.mak - identifies the version and release date
+ gs.mak - documentation and miscellany
+ lib.mak - the main makefile for the graphics engine
+ int.mak - the main makefile for the PostScript/PDF interpreter
+ jpeg.mak - the makefile for the IJG library
+ libpng.mak - the makefile for the PNG library
+ zlib.mak - the makefile for the zlib library
+ devs.mak - the makefile for the device drivers
+
+********
+******** Preparing the makefiles for your environment ********
+********
+
+You may need to edit the platform-specific makefile if you wish to change
+any of the following:
+
+ - The name of the makefile itself (MAKEFILE macro);
+
+ - The default search path(s) for the initialization and font files
+ (GS LIB_DEFAULT macro);
+
+ - The debugging options (DEBUG and TDEBUG macros);
+
+ - The set of device drivers to be included (DEVICE_DEVS
+ and DEVICE_DEVS1..15 macros);
+
+ - The set of optional features to be included (FEATURE_DEVS).
+
+The platform-specific makefile will include comments describing all of these
+items except the DEVICE_DEVS options; the available DEVICE_DEVS options
+(device drivers) are described in devs.mak, even though the file that must
+be edited is the platform-specific makefile. You should also check the
+JVERSION and PVERSION macros in the platform-specific makefile, and adjust
+them if they do not match the JPEG and PNG library versions you are using:
+see jpeg.mak and libpng.mak for more info.
+
+There are also platform-specific options described below under the
+individual platforms. See the "Options" section near the beginning of the
+relevant makefile for more information.
+
+If you are including a dot-matrix printer driver, you may wish to
+customize the default resolution parameters in devs.mak.
+
+Features and devices
+--------------------
+
+When compiling Ghostscript, you may configure it with any of a variety of
+features, and with any subset of the available device drivers. You will
+find the complete list of features in a comment at the beginning of the file
+gs.mak, and the complete list of drivers in a comment at the beginning of
+devs.mak.
+
+To find out what devices a particular makefile selects for inclusion in
+the executable, find the line in the makefile of the form
+ FEATURE_DEVS=<list of features>
+and
+ DEVICE_DEVS=<list of devices>
+ (similarly DEVICE_DEVS1... up to DEVICE_DEVS15)
+For example, if the makefile for Unix platforms defined
+ FEATURE_DEVS=level2.dev
+indicating that only the PostScript Level 2 facilities should be included,
+you might wish to add
+ FEATURE_DEVS=level2.dev pdf.dev
+to add the ability to interpret PDF files. (In fact, the current definition
+of FEATURE_DEVS in the Unix makefiles does include pdf.dev.) The Unix
+makefile also defines
+ DEVICE_DEVS=x11.dev
+ DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev ppm.dev ppmraw.dev
+indicating that the X11 driver and all of the Portable Bit/Gray/PixMap
+file drivers should be included. (In fact, it includes many more drivers
+than this: see the Unix makefiles for the full list.)
+
+You may edit the FEATURE* lines to select any desired set of features (as
+listed near the beginning of gs.mak), and the DEVICE_DEVS* line(s) to select
+any desired set of device drivers (as listed near the beginning of
+devs.mak). The first device listed in the definition of DEVICE_DEVS will be
+used as the default device (unless overridden from the command line with
+-sDEVICE=xxx, of course.) If you can't fit all the devices on a single
+line, you may add lines defining
+ DEVICE_DEVS2=<dev21>.dev ... <dev2n>.dev
+ DEVICE_DEVS3=<dev31>.dev ... <dev3n>.dev
+etc. up to DEVICE_DEVS15. Don't use continuation lines -- this doesn't
+work on some platforms.
+
+LZW compression
+---------------
+
+It is possible to substitute an LZW compressor for the LZW-compatible
+encoder provided with the standard fileset, by finding the two lines in
+lib.mak that read
+
+ lzwe_=slzwce.$(OBJ) slzwc.$(OBJ)
+ #lzwe_=slzwe.$(OBJ) slzwc.$(OBJ)
+
+and changing them to
+
+ #lzwe_=slzwce.$(OBJ) slzwc.$(OBJ)
+ lzwe_=slzwe.$(OBJ) slzwc.$(OBJ)
+
+If you do this, you are responsible for constructing or obtaining a file
+slzwe.c that implements LZW compression; such a file is not included in any
+current standard Ghostscript distribution, although you may be able to find
+one in distributions that predate Unisys' amnesty cutoff of January 1, 1995.
+You are also responsible for drawing your own conclusions about the
+applicability to LZW compression code of patents held by Unisys and/or IBM,
+and for obtaining any licenses you believe to be relevant.
+
+Creating 'makefile'
+-------------------
+
+As the final step in preparing the makefile, you need to associate the name
+'makefile' with the correct makefile for your environment as follows.
+
+On Unix systems, execute:
+ ln -s unix-gcc.mak makefile
+if you are using gcc, or
+ ln -s unixansi.mak makefile
+if you are using another ANSI C compiler, or
+ ln -s unix-cc.mak makefile
+if you are using a "traditional C" compiler. If your Unix system doesn't
+support symbolic links, omit the -s switch. Then, if you have edited any
+of the makefile components listed above, execute
+ tar_cat
+
+On MS Windows with the Borland compiler, execute:
+ echo !include "bcwin32.mak" >makefile
+
+On MS Windows with the Microsoft compiler, execute:
+ echo !include msvc32.mak >makefile
+
+On MS-DOS or MS Windows with the Watcom compiler, add the line
+ set DOS4G=quiet
+to your autoexec.bat file, and also execute:
+ set DOS4G=quiet
+Then execute:
+ echo !include watc.mak >makefile
+(for MS-DOS) or
+ echo !include watcw32.mak >makefile
+(for MS Windows).
+
+********
+******** Invoking 'make' ********
+********
+
+The command
+ make clean
+removes all the files created by the build process (relocatables,
+executables, and miscellaneous scratch files). If you want to save the
+executable, you should move it to another directory first.
+
+The command
+ make
+builds Ghostscript without debugging options.
+
+The command
+ make debug
+builds Ghostscript with debugging options and additional internal error
+checks. Ghostscript will be somewhat larger and slower, but it won't behave
+any differently unless you actually turn debugging options at execution time
+with the -DDEBUG or -Z command line switches (described in use.txt).
+
+On most platforms, these simple instructions don't quite work in one way or
+another: read the section on your platform below.
+
+Cross-compiling
+---------------
+
+If you are compiling Ghostscript on machine X with a cross-compiler that
+generates code for machine Y, you need to do one extra step. Rather than
+simply giving the command
+ make
+you must proceed in three steps. First,
+ make arch.h
+Then edit arch.h to reflect the architecture of machine Y. Then,
+ make
+
+********
+******** How to build Ghostscript from source (PC version) ********
+********
+
+The relevant makefiles are:
+ Borland C++ 4.x, 32-bit MS Windows (3.1 + Win32s, 95, NT): bcwin32.mak
+ Microsoft Visual C++ 4.x or 5.x, 32-bit MS Windows: msvc32.mak
+ Watcom C/386 or C++, 32-bit (extended) MS-DOS: watc.mak
+ Watcom C/386 or C++, 32-bit MS Windows (DOESN'T WORK YET): watcw32.mak
+ DJGPP, DESQview/X: dvx-gcc.mak
+ cygwin32 gcc: unix-gcc.mak (see below)
+The options were chosen to strike a balance between RAM consumption and
+likely usefulness.
+
+To build Ghostscript, you need MS-DOS version 3.3 or later, and Borland
+C/C++ (4.0 or later), Microsoft Visual C++ (version 4.0 or later), Watcom
+C/386 (version 8.5 or later) or C++ (any version), or the free djgpp + go32
+development system. Details are given below.
+
+As noted above, the default configuration generates an executable that
+assumes the directory where 'make' was run should be the final default
+directory for looking up the Ghostscript initialization and font files.
+
+To build the Ghostscript executable, all you need to do is give the
+command
+ make
+You must have COMMAND.COM in your path to build Ghostscript.
+
+There is a special 'make' target that simply attempts to compile all the
+.c files in the current directory. Some of these compilations will fail,
+but the ones that succeed will go considerably faster, because they don't
+individually pay the overhead of loading the compiler into memory. So a
+good strategy for building the executable for the first time, or after a
+change to a very widely used .h file, is:
+ make begin
+and then
+ make
+to do the compilations that failed the first time.
+
+Note: if you get the Ghostscript sources from a Unix 'tar' file and unpack
+the file on a MS-DOS machine, the files will all have linefeed instead of
+carriage return + linefeed as the line terminator, which may make the C
+compiler unhappy. I don't know the simplest way to fix this: just reading
+each file into an editor and writing it back out again may be sufficient.
+You will probably have to do this to the .c, .h, and .bat files.
+
+Borland environment
+-------------------
+
+To compile Ghostscript with the Borland environment, you need Borland C++
+(version 4.0 or later); specifically, the compiler, 'make' utility, and
+linker. You also need either the Borland assembler (version 1.0 or later)
+or the Microsoft assembler (version 4.0 or later).
+
+Besides the source files and the makefiles, you need:
+ turboc.cfg (the flags and switches for Turbo C)
+ gs.tr (the linker commands for the interpreter)
+ *.bat (a variety of batch files used in the build process)
+
+There are extensive comments in the aforementioned .mak files
+regarding various configuration parameters. If your configuration is
+different from the following, you should definitely read those
+comments and see if you want or need to change any of the parameters:
+ - The compiler files are in c:\bc and its subdirectories.
+ - You are using the Borland assembler (tasm).
+ - You want an executable that will run on any 32-bit PC-compatible,
+regardless of processor type (80386, 80486, Pentium, or compatible) and
+regardless of whether a math coprocessor (80x87) is present (only an issue
+with 80386 processors).
+
+NOTE: A user has reported the Borland C++ 4.00 + patch 1-6 doesn't produce a
+working executable of the current Ghostscript (5.03). We can't test this,
+since we no longer have this compiler.
+
+NOTE: Borland C++ 4.52 has a bug that causes the 32-bit Windows executable
+to fail during startup. Borland has provided a patch for this bug on the
+file bc45xp1.zip, accessible as a link from
+http://loki.borland.com/cpp/Patchs.htm.
+
+NOTE: Borland C++ 5.0 and 5.01 have a code generator bug that generates
+incorrect code for the construct !file_is_valid(). Do not attempt to
+compile Ghostscript with these compilers. If you want to report this bug to
+Borland, send them the result of compiling ziodev.c and tell them to look at
+the code generated for file_is_valid() and !file_is_valid(). We don't know
+whether Borland C++ 5.02 still has this problem.
+
+If building for the MS Windows Win32s environment, you need bcc32.cfg
+instead of turboc.cfg. The make process will stop after it has created
+genarch.exe. You should then run 'win genarch arch.h', wait until genarch
+has finished and then exit MS Windows. Then type 'make' again to restart
+the make process.
+
+If building for MS Windows NT, you also need bcc32.cfg instead of
+turboc.cfg, but the make process will run to completion automatically.
+
+Microsoft environment
+---------------------
+
+To compile Ghostscript with the Microsoft environment, you need Microsoft
+Visual C++ 4.0 or later with its associated `nmake' utility and linker. If
+you are using version 4.x, change the line in msvc32.mak that reads
+ MSVC_VERSION = 5
+to
+ MSVC_VERSION = 4
+before building.
+
+You may get error messages during compilation about /QI0f being an undefined
+switch, or the message
+ dwmain32.def: EXETYPE not supported for platform; ignored
+during linking. Ignore them.
+
+Watcom environment
+------------------
+
+Before compiling, change the definition of the WCVERSION macro in the
+makefile (watc.mak or watcw32.mak) to the version of the Watcom compiler you
+are using. This is necessary to handle some minor incompatibilities between
+versions.
+
+To build Ghostscript, execute
+
+ wmakebat
+
+This constructs a build script and then executes it. (This roundabout
+procedure is necessary because Watcom chose to implement wmake in a way that
+requires reading both the entire makefile and the entire current directory
+into the limited 640K MS-DOS address space.)
+
+Note that Watcom C/386 version 8.5 does not include wmakel (the 32-bit
+version of wmake). If this is the version that you have, use wmake instead,
+i.e., edit wmakebat.bat to change wmakel to wmake.
+
+If you get an "Error(F01): Out of memory" with Watcom 8.5, you may wish to
+try reducing the total size of the makefiles by editing devs.mak to remove
+drivers that you don't ever intend to use. If you still get this error,
+contact Watcom technical support; they will be able to send you the wmakel
+program, probably at no charge.
+
+DesqView/X and djgcc/djgpp environment
+--------------------------------------
+
+The name of the makefile for this environment is dvx-gcc.mak.
+
+The DesqView/X port of Ghostscript was contributed by Tom Brosnan
+(tjb@chalone.stanford.edu), with further contributions by Stephen Turnbull
+(turnbull@shako.sk.tsukuba.ac.jp). It uses djgcc (DJ Delorie's MSDOS port
+of gcc) for compiling. djgcc assumes that go32.exe is in your search path.
+You need to set an environment variable to tell go32 where to put any
+paging files, e.g.
+
+ set GO32TMP=e:/tmp
+
+If you don't have go32.exe, you can get it from Internet host
+oak.oakland.edu. The extender and minimum run-time environment are in the
+file djeoeXXX.zip, where XXX is the version number (currently 112).
+Patched versions of the extender (as well as other components) are found in
+the files djXXXmY.zip, XXX is again the compiler version, Y is the
+patchlevel. Y is currently 2. People who are just running the executable
+need only get the file with the highest level of Y that contains GO32.EXE
+and do "unzip -j djXXXmY go32.exe" (InfoZIP) or "pkunzip djXXXmY go32.exe"
+(PKWare), then move the extender to their PATH. If you do not have a
+hardware FPU, you will also need the floating point emulator EMU387 found
+in djeoeXXX.zip (and possibly in the patch releases as well). You MUST use
+an emulator designed to work with GO32; the emulators often found as TSRs
+will not work. See the file README found in djeoeXXX.zip, or the file
+README.1ST in pub/msdos/djgpp on Simtel for further information.
+
+The DJGPP v1.12 compiler suite is known to have problems with linking
+large file sets. If you run into this problem, you can work around it
+by using the v1.11 GO32 as follows:
+(1) get dj111m5.zip from turnbull.sk.tsukuba.ac.jp:/pub/djgpp/1.11
+(2) unzip GO32.EXE. Be careful not to overwrite other versions!
+(3) rename it, eg, to GO111M5.EXE
+(4) move the renamed GO32.EXE to your path
+(5) stubedit ld.exe: (the stubedit utility is part of djeoe112.zip)
+ (a) change the extender name to the one you chose in (3). The
+ .EXE extension may be omitted
+ (b) change the version required to 1.11
+ (c) accept the defaults for the remaining options.
+
+Stephen Turnbull observed the following two problems with DJGPP v2.0-beta2.
+
+(1) The v1.12 stdio.h defined a number of flags for manipulating the
+ various characteristics of the streams being processed, such as
+ _IORD, _IOWRT, etc. These are missing from v2.0-beta2. I don't
+ know enough about the new libc.a to guess whether this is an
+ oversight or these functions have a new (Posix?) interface.
+ [Caveat: In Ghostscript the compiler error can be silenced by
+ adding "#define _IOWRT 00002" to the file gp_dvx.c. I don't know
+ that this is correct in the new libraries. I suspect there is no
+ real loss in Ghostscript to removing the offending flag
+ manipulation from gp_open_printer() in gp_dvx.c, as it is a
+ performance optimization.]
+
+(2) The big problem is linking with third-party libraries not compiled
+ with v2.0. In particular, QuarterDeck's contributed Xlib
+ (compiled with DJGPP v1.12 (original release). Unfortunately,
+ v1.12 uses the usual macros for character classification and
+ implementation of the stdio streams. This leads to long lists of
+ complaints from the linker about undefined references to '_ctype_'
+ (the table of character type flags) and '_iob' (the table indexed
+ by file descriptors) when processing Xlib functions.
+
+cygwin32 gcc
+------------
+
+A user has reported that it is possible to compile Ghostscript for MS
+Windows NT using the cygwin32 gcc compiler, GNU make, and the unix-gcc.mak
+makefile, with only two small source code changes:
+
+ - Add a "b" to the call to fopen in "gp_open_scratch";
+ - Mirror the gp_ntfs logic for "gp_file_name_is_absolute".
+
+You can find more information about this compiler and environment on the Web
+at http://www.cygnus.com/misc/gnu-win32. Please note that Cygnus' licensing
+terms aren't quite as liberal about redistribution as either the GNU License
+or the Aladdin license, so you should read their license carefully if you
+want to redistribute the results of using their compiler.
+
+********
+******** How to build Ghostscript from source (Mac version) ********
+********
+
+There are additional Mac-specific source files in a separate distribution
+from the rest of Ghostscript. In addition to the standard Ghostscript
+sources, you will need the following files:
+
+ macgs-v1.0-src.sit - the source files, StuffIt archive.
+ manual.txt - the manual as unformatted text
+ readme.txt - this file
+
+These should be in the mac directory located in the same place you retrieved
+the rest of the Ghostscript distribution.
+
+The first file is a StuffIt archive. If you do not have a program to expand
+it, you should get the free StuffIt Expander program from your favorite
+Macintosh archive.
+
+In the standard method of building Ghostscript, all of these files (except
+the jpeg) get unpacked into one big directory. The jpeg stuff gets unpacked
+into a directory called jpeg-6 in the main directory. The Macintosh stuff
+also gets unpacked into its own directory, called 'Mac Specific'. However,
+if you like (and I do) you can divide up all these files into the following
+hierarchy:
+
+ Ghost Dev
+ files -- all *.ps, *.txt, and other non-build files
+ fonts -- all the fonts
+ src -- *.c, *.h, *.mak
+ jpeg-6 -- the jpeg files
+ Mac Specific -- the mac files
+ MPW Build -- empty directory used for building under MPW
+
+Once you get everything laid out, take a look at the file Worksheet in the
+mac specific folder for complete steps to build the system with either MPW
+or CodeWarrior.
+
+********
+******** How to build Ghostscript from source (Unix version) ********
+********
+
+The makefile distributed with Ghostscript selects the following devices
+for inclusion in the build:
+ Display: X Windows.
+ Printers: H-P DeskJets, LaserJets, and color DeskJets and PaintJets;
+ Canon BubbleJets.
+ File formats: Group 3 & Group 4 fax, JPEG, PCX, P*M (PBM/PGM/PPM),
+ TIFF, PostScript images, PNG, distilled PDF, PostScript, and EPS,
+ PCL XL ("PCL 6").
+
+The unix-*.mak files are actually generated mechanically from *head.mak,
+*tail.mak, unix-end.mak, and the platform-independent makefiles by a script
+called tar_cat. If for some reason your copy of Ghostscript doesn't include
+the unix-*.mak files, run tar_cat to construct them. If you wish to edit
+any part of the makefile,
+
+ DO NOT EDIT THE FILE NAMED makefile OR unix{ansi,-cc,-gcc}.mak.
+ EDIT THE ORIGINAL COMPONENT MAKEFILE (*head.mak, *tail.mak,
+ OR A PLATFORM-INDEPENDENT FILE) AND RUN tar_cat AGAIN.
+
+Consult tar_cat to find the names of the component files.
+
+The *head.mak files explicitly compile and link the libpng and zlib
+libraries into the executable. If your Unix system already includes these
+libraries (probably in /usr/lib/libpng.{a,so} and libz.{a,so}) and you would
+rather use the system copies, change the definition of SHARE_LIBPNG and/or
+SHARE_ZLIB from 0 to 1 in the relevant *head.mak file, run tar_cat, and
+recompile. Note that if you do this, you will get non-DEBUG versions of
+these libraries, even if you selected DEBUG in the Ghostscript makefile.
+
+The *head.mak files also compile and link the jpeg library into the
+executable. Ghostscript doesn't offer a SHARE option for this library,
+because in order to be compatible with Adobe interpreters, Ghostscript has
+to compile the code with the non-standard definition
+ #define D_MAX_BLOCKS_IN_MCU 64
+This is in contradiction to the JPEG standard, but at least some real
+PostScript files require this. A shared system library would not be
+compiled this way.
+
+If the X11 client header files are located in some directory which your
+compiler does not automatically search, you must change the XINCLUDE macro
+the makefile to include a specific -I switch. See the comment preceding
+XINCLUDE in the makefile.
+
+Currently Ghostscript is set up to compile and link in a generic Unix
+environment. Some Unix environments may require changing the LDFLAGS
+macro in the makefile.
+
+All you need to do to make an executable is invoke the shell command
+ make
+
+Ghostscript uses ANSI syntax for function definitions. Because of this,
+when compiling with cc, it must preprocess each .c file to convert it to
+the older syntax defined in Kernighan and Ritchie, which is what most
+current Unix compilers (other than gcc) support. This step is
+automatically performed by a utility called ansi2knr, which is included in
+the Ghostscript distribution. The makefile automatically builds ansi2knr.
+
+The ansi2knr preprocessing step is included in the makefile rule for
+compiling .c files. ansi2knr creates a file called _temp_$$.c to hold the
+converted code, where $$ is the process ID. If you want to change this name
+for some reason, it is defined in a small script file called ccgs.
+
+gcc and GNU make problems
+=========================
+
+There is an optimizer bug in gcc 2.7.0, 2.7.1, and 2.7.2 that causes these
+versions of gcc to generate incorrect code. You can work around this by
+adding the switch
+ -Dconst=
+to the compilation switches (CFLAGS). Alternatively, you can rebuild gcc
+with the following patch:
+
+*** clean-ss-951203/expr.c Sun Nov 26 08:18:07 1995
+--- ss-951203/expr.c Mon Dec 4 11:41:18 1995
+*************** expand_expr (exp, target, tmode, modifie
+*** 4582,4587 ****
+ through a pointer to const does not mean that the value there can
+ never change. Languages where it can never change should
+ also set TREE_STATIC. */
+! RTX_UNCHANGING_P (temp) = TREE_READONLY (exp) | TREE_STATIC (exp);
+ return temp;
+ }
+--- 4582,4588 ----
+ through a pointer to const does not mean that the value there can
+ never change. Languages where it can never change should
+ also set TREE_STATIC. */
+! RTX_UNCHANGING_P (temp) = TREE_READONLY (exp) & TREE_STATIC (exp);
+ return temp;
+ }
+
+If possible, compile with gcc 2.5.8, gcc 2.6.3, or gcc 2.7.2.1 or later,
+which don't have this bug. Note, however, that gcc has other problems on
+some platforms: please read the section below for your specific platform as
+well.
+
+Current versions of GNU `make' have no problems, but GNU make 3.59 can't
+handle the final linking step in some cases; use the platform's standard
+make (e.g., /bin/make) if this happens.
+
+Platform-specific notes
+=======================
+
+386 Unix
+--------
+ gcc versions older than 1.38 on Intel 80386 systems do not
+compile Ghostscript correctly using the -O option. Do not use -O in
+these environments.
+ gcc 1.39 under 386BSD has a bug that causes float-to-integer
+conversions to compile incorrectly. Do not use this version of gcc.
+ X11R5 may need #include <stddef.h> in x_.h.
+ Also see below regarding System V platforms.
+
+Alpha (AXP) with gcc
+--------------------
+ You don't have to use gcc on AXP systems: the following notes are
+relevant only if you do use it.
+ The code generator in gcc 2.7.2.1 is broken, so you cannot use this
+version on the Alpha. gcc 2.5.8 and 2.6.3 are probably OK. Versions of gcc
+before 2.5.0 are believed not to work.
+ If you really want to use gcc 2.7.x, here is a patch from a gcc
+maintainer:
+
+Tue Sep 24 19:37:00 1996 Jim Wilson <wilson@cygnus.com>
+
+ * reload.c (push_secondary_reload): Change reload_mode to mode in
+ SECONDARY_MEMORY_NEEDED and get_secondary_mem calls.
+
+*** reload.c.orig Sun Mar 9 14:05:23 1997
+--- reload.c Sun Mar 9 14:06:54 1997
+*************** push_secondary_reload (in_p, x, opnum, o
+*** 589,600 ****
+ set it up now. */
+
+ if (in_p && icode == CODE_FOR_nothing
+! && SECONDARY_MEMORY_NEEDED (class, reload_class, reload_mode))
+! get_secondary_mem (x, reload_mode, opnum, type);
+
+ if (! in_p && icode == CODE_FOR_nothing
+! && SECONDARY_MEMORY_NEEDED (reload_class, class, reload_mode))
+! get_secondary_mem (x, reload_mode, opnum, type);
+ #endif
+ }
+
+--- 589,600 ----
+ set it up now. */
+
+ if (in_p && icode == CODE_FOR_nothing
+! && SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
+! get_secondary_mem (x, mode, opnum, type);
+
+ if (! in_p && icode == CODE_FOR_nothing
+! && SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
+! get_secondary_mem (x, mode, opnum, type);
+ #endif
+ }
+
+
+Apollo
+------
+ You must run the compiler in ANSI-compatible mode (i.e., set AK=
+<null string> in the makefile); otherwise, it gives incorrect error
+messages for any function declared as returning a float value.
+ The Apollo compiler may not compile Ghostscript correctly. If you
+get unexpected crashes at run time, use gcc.
+
+AT&T 7040 R3
+------------
+ If Ghostscript crashes on startup, recompile with -O0 in order to
+avoid triggering compiler bugs.
+
+Convex
+------
+ Use unixansi.mak. Do not invoke optimization (-O1): there
+are compiler bugs that lead to incorrect code. Set CFLAGS to
+ -no -fn -tm c1
+
+DECStations
+-----------
+ You may get the following message (or a similar one) when compiling,
+due to a compiler bug:
+ cfe: Fatal: _temp_19086.c: Segmentation violation
+If this happens, try compiling with the -oldc switch.
+
+DECStations with Ultrix
+-----------------------
+ You may wish to set
+ GS_LIB_DEFAULT=$(gsdatadir):/usr/lib/DPS/outline/decwin:$(gsdatadir)/fonts
+in the makefile to add the Display PostScript font directory to the font
+search path.
+ You may need to use
+ make CFLAGS="-Olimit 2500"
+to tell the optimizer to allocate extra table space.
+ The Ultrix 4.4 C compiler has a bug that makes it compile gdevm1.c
+incorrectly. Insert the following line in the makefile rule for
+gdevm1.$(OBJ) (the body of the rule is empty in the standard distribution):
+ $(CCC) -oldc gdevm1.c
+
+Digital Unix
+------------
+ Use the unixansi.mak file for all Digital Unix compilers.
+For versions of Digital Unix before 4.0, set
+ CFLAGS=-std -Olimit 1000 -g3 -O2 $(XCFLAGS)
+ LDFLAGS=-lots $(XLDFLAGS)
+You may be able to omit the -g3.
+
+H-P RISC workstations
+---------------------
+ You can build Ghostscript on H-P machines with either GNU gcc or
+H-P's ANSI-capable cc. The minimal, non-ANSI-capable cc that ships with a
+"bare" HPUX system is *not* good enough. If your cc doesn't accept the -Aa
+switch then you need to get the full cc or gcc.
+ If you use H-P's compiler, be sure you have upgraded to a recent
+compiler release. Many bizarre symptoms have been reported from trying to
+build Ghostscript with older, buggier compilers, for example:
+ * Link step fails with a message about "max" not being defined.
+ * Build succeeds, but resulting executable fails to start up,
+with an error message like
+ Initializing... Unrecoverable error: typecheck in .registerencoding
+ Operand stack:
+ .notdef 0
+ * Build succeeds, but resulting executable produces a black
+background on the first page of output.
+ On HPUX 9.*, it is reported that you need at least compiler patch
+PHSS_5723 and dld.sl patch PHSS_5734 to build gs successfully. (As of late
+1997, those patches are long obsolete; the current patches are compiler
+PHSS_10357 and dld.sl PHSS_11246. It is unknown whether current gs releases
+will work with compiler/dld.sl versions older than these.)
+ On HPUX 10.*, we don't know what combinations of compiler version
+and switches work. On HPUX 10.20, it is reported that setting CC=c89 and
+"CFLAGS=+O3 $(XCFLAGS)" will work, contradicting the information in the next
+paragraph, but this may be dependent on the specific compiler version.
+ In either HPUX version, you need to set "CC=cc -Aa" (or use -Ae if
+you prefer), and set "CFLAGS=-D_HPUX_SOURCE -O $(XCFLAGS)". Higher levels
+of optimization than -O may work depending on your compiler revision; some
+users have reported success with +O3, some have not. Some users have
+reported needing -DNOSYSTIME and/or -D_POSIX_SOURCE in CFLAGS, but recent
+tests do not show these to be necessary.
+ If you use gcc, it is also a good idea to have a recent release.
+gcc 2.7.2.1 or later is recommended, but gcc 2.6.3 has been known to work
+with past gs releases. gcc versions earlier than 2.6.3 are known *not* to
+work, and you will also have trouble with gcc 2.7.* releases earlier than
+2.7.2.1. (You may be able to get a working executable with an older gcc by
+removing -O from CFLAGS. If you do have an up-to-spec gcc, you should be
+able to use -O2 without problems.)
+
+Intergraph Clipper
+------------------
+ Recommended settings are:
+ XCFLAGS=-w -Q -DSYSV -D__SVR3
+ EXTRALIBS=-lbsd -lc_s
+ CC=acc -knr
+ PLATFORM=sysv_
+Also, you will probably need to change the value of XLIBS from
+ XLIBS=Xt X11 Xext
+to
+ XLIBS=Xt_s X11_s Xext
+
+ISC Unix
+--------
+ For ISC Unix with gcc, an appropriate make invocation is:
+ make XCFLAGS="-D__SVR3 -posix" LDFLAGS="-shlib -posix" \
+ EXTRALIBS="-linet -lnsl_s"
+If this doesn't work for you, try removing the -shlib. ISC Unix may
+also need one or more of the following in EXTRALIBS: -lpt, -lc_s.
+See also under "386 Unix" above.
+
+Linux
+-----
+ If you are building on Linux with X11 R6 or later, you may get a
+list of error messages at link time about undefined references to various
+functions beginning with Smc and Ice. If this happens, make sure that XLIBS
+is set in the makefile to the list Xt SM ICE Xext X11 rather than just Xt
+Xext X11.
+ If you are running gcc version 2.6.3 or later, you may run into
+problems because of an incompatibility in object formats ("a.out" vs. ELF)
+with the XFree86 library. The typical symptom is that ld will complain that
+some X library is not found or a whole slew of Xlib or Xt functions are not
+found in the library (similar to the messages for omitting SM and ICE from
+XLIBS), or you will get a message when you start Ghostscript that the
+program or the shared library is in unrecognized format. If this happens,
+you might try adding the switches
+ -b i486-linuxaout
+to both CFLAGS and LDFLAGS in gcc-head.mak, and rebuilding from scratch
+("make clean" and then "make"). If this doesn't help, or if other strange
+things happen, contact your Linux supplier or support resource.
+
+MIPS
+----
+ There is apparently a bug in older versions of the MIPS C compiler
+which causes gxdither.c to compile incorrectly if optimization is enabled
+(-O). However, this bug is definitely fixed in MipsPRO C version 6.00; with
+this version, compiling with -O2 -mips2 produces good output.
+
+NCR 3550
+--------
+ If you are using the NCR C Development Toolkit, you must use -O0 to
+avoid triggering compiler bugs.
+
+NeXTSTEP
+--------
+ Current NeXTSTEP versions require changing the definition of INCLUDE
+in unixtail.mak (and ugcclib.mak, if you are using only the library) to
+ INCLUDE=/usr/include/bsd
+Don't forget to run tar_cat after you do this.
+
+For all NeXTSTEP systems, use unix-gcc.mak -- i.e., execute
+ ln -s unix-gcc.mak Makefile
+
+For NeXTSTEP versions before 3.2:
+ edit gcc-head.mak ->
+ change CC=gcc to CC=cc
+ add -D_NEXT_SOURCE to CFLAGS
+ change the two occurrences of sys/time.h to ansi/time.h, and
+ change <dirent.h> in gp_unifs.c to <sys/dirent.h>
+
+For NeXTSTEP 3.2 and later
+ edit gcc-head.mak ->
+ change CC=gcc to CC=cc
+ add -D_POSIX_SOURCE and remove -g in CFLAGS
+ remove -Wstrict-prototypes in GCFLAGS
+
+Add the following line to the end of Fontmap
+ /Ohlfs /Courier ;
+
+If you are running the Pencom co-Xist X server (Development version), the X
+headers and libraries are in the default places, so you should change the
+definitions of XINCLUDE and XLIBDIRS in the makefile to empty strings.
+
+Pyramid MIServer-S
+------------------
+ See AT&T 7040 R3.
+
+RS/6000
+-------
+ Many versions of the AIX C compiler have bugs that have prevented
+Ghostscript from compiling and linking properly. We believe that the
+current Ghostscript release works around these bugs, and that using the
+unix-cc.mak makefile with
+ CC=cc
+should work. You must also edit the makefile (unixansi.mak or
+unix-cc.mak) to change INSTALL to /usr/ucb/install. (If -DSYSV produces a
+complaint about the functions index and rindex not being defined, try
+removing it.) If the xlc 1.2.1 optimizer runs out of memory, you may need
+to add -qmaxmem=4000 to CFLAGS.
+ A user has reported that the AIX C compiler shipped with AIX 3.2.5
+only compiles Ghostscript if invoked with c89 -D_POSIX_SOURCE and *without*
+-O. On the other hand, another user reported successful compilation using
+the unix-ansi.mak makefile and the following command line:
+ make CC=c89 XCFLAGS="-DOSY_AIX -D_ALL_SOURCE -qnoro -qmaxmem=3000 -bfl" $*
+Apparently some (but not all) releases of the C library declare the hypot
+function: if the declaration in math_.h produces an error message, try
+removing it. Also, the IBM X11R3 server is known to be buggy: use the MIT
+X server if possible.
+ The xlc 1.3.0.x compiler provided in AIX 3.2.5+ definitely will not
+compile Ghostscript correctly if -O is used on all files. A user has
+reported that compiling the following files without -O is sufficient to
+produce a working executable: z*.c, gsmatrix.c, gxstroke.c.
+ Some installations of AIX 3.2.5 have what appears to be an incorrect
+or inconsistent version of libXt.a in /usr/lpp/X11/lib. If you get
+XtShellStrings and XtStrings as unresolved externals when linking, set
+XLIBDIRS=-L/usr/lpp/X11/lib/R5 -L/usr/lpp/X11/lib rather than just
+XLIBDIRS=-L/usr/lpp/X11/lib.
+
+SCO Unix/Xenix
+--------------
+ The SCO Unix C compiler apparently can't handle the Pn macros
+in std.h. If you get strange compilation errors on SCO Unix, see if
+you can get a compiler fix from SCO. Meanwhile, to use gcc with SCO
+ODT, see gcc-head.mak for the appropriate switch settings. See also
+under "386 Unix" above.
+ gcc 2.3.3 produces code that causes a core dump on machines
+that don't have hardware floating point, because of a bug in SCO's
+floating point emulator. Use a different compiler on these machines.
+ If you aren't using the X11 driver, you need to add -lsocket
+to the linker command (near the end of the unix-*.mak file) in order
+to get the date/time functions linked in.
+ If you want to use direct frame buffer addressing instead of X
+Windows, include the relevant frame buffer device(s) (ega.dev, vga.dev,
+etc.) and change gdevevga.c to gdevsco.c as indicated in devs.mak. Note:
+this does not work with SuperVGA displays, except for 800x600x16 mode.
+Note also: If the display looks "smeared", try recompiling gdevpcfb.c with
+-O0. Note also: if Ghostscript crashes, use the -q switch and/or redirect
+console output to a file.
+ If your compiler accepts the -Xt and -Xa switches, use -Xt.
+Even though this causes the compiler to use incorrect rules for
+computing the result types of << and >>, -Xa enables "optimizations"
+that produce incorrect code.
+ For SCO ODT 2.0, in addition to -D__SVR3 and -DSYSV, you need to
+specify -Dsco, -DUSG, and -DMALLOC_0_RETURNS_NULL. For SCO ODT, you need
+EXTRALIBS=-lX11 -lsocket -lmalloc, or maybe only -lsocket (depending on
+the version), and for SCO ODT 2.0, you also need to specify -lc_s. For
+SCO Xenix, you need EXTRALIBS=-lmalloc.
+ For all SCO systems, set XINCLUDE= and XLIBDIRS=.
+ Please also read the section on "System V Unix platforms" below.
+
+Silicon Graphics
+----------------
+ Compiler option -Olimit 2500 is required to be able to compile all
+the code with optimization.
+ Use compiler option -ansi with the SGI C compiler shipped with Irix
+5.2.
+ The SGI C compiler may produce warnings about "Undefined the ANSI
+standard library defined macro stdin/stdout/stderr". To suppress these
+warnings, add
+ -woff 608
+to the definition of CFLAGS.
+ The SGI C compiler shipped with Irix 6.1 and 6.2 will not compile
+deflate.c (part of zlib) properly with optimization. If you want to use the
+zlib decompression filter (which is required for interpreting PDF 1.2
+files), compile this file separately without -O.
+ The MIPSpro 7.1 compiler produces incorrect output if you use -O3 or
+-Ofast=ip32 -show. Use only -O2.
+ To install gcc 2.7.x on IRIX 6.x, please consult the Web page at
+http://reality.sgi.com/knobi/gcc-2.7.2.x-on-irix-6.2-6.3.
+
+Sun
+---
+ The Sun unbundled C compiler (SC1.0) doesn't compile Ghostscript
+properly if the -fast option is selected: Ghostscript core-dumps in
+build_gs_font. Use -g, or use gcc.
+ The Sun version of dbx often gives up with an error message when
+trying to load Ghostscript. If this happens, use gdb instead. (gdb is
+more reliable than dbx in other ways as well.)
+ There is a bug in some versions of zlib that results in an undefined
+symbol zmemcmp when compiling with Sun cc. Use gcc instead.
+
+ SunOS
+ -----
+ In SunOS 4.1.[23], you may get these undefined symbols when linking:
+ _get_wmShellWidgetClass
+ _get_applicationShellWidgetClass
+Compiling "-Bstatic -lXmu -Bdynamic" appears to work for SC1.0. For gcc,
+try adding "-static" to CFLAGS. To solve the problem if you are using
+OpenWindows 3.0 (X11R4-based Xt), please contact your local Sun office and
+request the following patches:
+ Patch i.d. Description
+ 100512-02 4.1.x OpenWindows 3.0 libXt Jumbo patch
+ 100573-03 4.1.x OpenWindows 3.0 undefined symbols when using
+ shared libXmu
+ Solaris
+ -------
+ Solaris 2.2 may require setting EXTRALIBS=-lsocket.
+ Solaris 2.3 and 2.4 seem to require EXTRALIBS=-lnsl -lsocket.
+ Solaris 2.n uses /usr/openwin/share/include for the X11 libraries
+rather than /usr/local/X/include.
+ Solaris 2.n typically makes Type 1 fonts available in
+/usr/openwin/lib/X11/fonts/Type1/outline.
+ For Solaris 2.n, you will need to change the definition of INSTALL
+in the makefile from install -c to /usr/ucb/install -c, since the Solaris
+version of 'install' requires
+ install -c <directory> [-m <mode>] <file>
+rather than
+ install [-c] [-m <mode>] <file> <directory>
+ You may need to set XLIBDIR to the directory that holds the X11
+libraries, as for other SVR4 systems. You should also set -DSVR4 in CFLAGS.
+ If you are using the SunPRO C compiler, do not use optimization
+level -xO3. On SPARC platforms, the compiler hangs; on Intel platforms, the
+generated code is incorrect. Also, do not use the -native flag on Intel
+platforms: this makes floating point computations unacceptably inaccurate.
+You may use -xcg92 (SPARC V8) and/or -dalign to get better performance.
+
+SVR4 Unix platforms
+-------------------
+ You may need to set EXTRALIBS=-lnsl.
+ Do *not* change PLATFORM=unix_ to PLATFORM=sysv_.
+ On SVR4 Unix platforms that use dynamic linking, you may need to
+define XLIBDIR as the name of the directory that holds the X Windows
+libraries. Do *not* prefix this with -L.
+ For SVR4.0 systems, set -DSVR4 -DSVR4_0 in the makefile; do *not*
+set -DSYSV. For SVR4.2 (or later) and Solaris 2.x systems, set -DSVR4 only
+(not -DSVR4_0 and not -DSYSV).
+
+System V Unix platforms
+-----------------------
+ If you are using a stock System V platform that lacks rename
+and gettimeofday, change PLATFORM=unix_ in the makefile to
+PLATFORM=sysv_.
+ You will probably need to change the definition of INSTALL (near
+the beginning of the makefile) from install to /usr/ucb/install.
+
+VAX with Ultrix
+---------------
+ The above information about DECStations with Ultrix may be
+applicable.
+
+********
+******** How to build Ghostscript from source (OS/2 version) ********
+********
+
+The relevant makefile is:
+ os2.mak
+The gcc/emx 0.9b (or later) compiler and the IBM NMAKE.EXE are required.
+
+For gcc/emx versions 0.9c and later, the LINK386 command must include
+$(COMPBASE)\lib\end.lib; version 0.9b requires omitting this. The current
+os2.mak file does include this file in the LINK386 command, so if you are
+using 0.9b, delete this file reference before building.
+
+Be sure you are using the standard OS/2 shell, CMD.EXE. Some other shells
+have bugs or differences that cause the makefile not to work.
+
+Before compiling or linking, you should execute
+ copy os2.mak makefile
+Then to start the make process type
+ nmake
+One DLL and two EXE's will be produced: gsdll2.dll (Ghostscript DLL),
+gsos2.exe (Ghostscript) and gspmdrv.exe (the Presentation Manager
+display driver).
+
+********
+******** How to build Ghostscript from source (VMS aka OpenVMS version) ****
+********
+
+Many versions of DEC's X server have bugs that produce broad bands of color
+where dither patterns should appear, or characters displayed white on top
+of black rectangles or not displayed at all. If this happens, please
+consult the X Windows section of the use.txt file to find out how to work
+around these bugs using X resources; also report the problem to DEC, or
+whoever supplied your X server.
+
+You may also wish to turn off the use of a backing pixmap with Ghostscript,
+either to work around X server memory limitations or bugs, or to obtain
+faster displaying at the expense of no redrawing when a Ghostscript window
+is restored from an icon or exposed after being occluded by another window.
+Again, use.txt contains information on how to do this.
+
+If you add compiled fonts to your system as described in the fonts.txt file,
+then add "ccfonts.dev" to the FEATURE_DEVS symbol in VMS-CC.MAK,
+VMS-GCC.MAK, VMS-DECC.MAK, or OPENVMS.MAK,
+ $ FEATURE_DEVS = "level2.dev ccfonts.dev"
+and then specify the font names with the ccfonts1 symbol
+ $ ccfonts1 = "Courier Courier_Oblique Courier_Bold Courier_BoldOblique"
+If the line gets too long, add another line of the same form, e.g.,
+ $ ccfonts1 = "Courier Courier_Oblique Courier_Bold Courier_BoldOblique"
+ $ ccfonts2 = "Times_Roman Times_Italic Times_Bold Times_BoldItalic"
+
+Using DCL command files
+-----------------------
+
+Up through Ghostscript version 5.0x, we have provided DCL command files for
+building Ghostscript. We will no longer support this method in future
+versions, since we have found it almost impossible to keep the DCL scripts
+consistent with the makefiles that are used on all other platforms, and
+since using a 'make' program has other benefits such as recompiling only
+files that have changed.
+
+The files VMS-CC.MAK, VMS-GCC.MAK, and VMS-DECC.MAK are OpenVMS DCL command
+files which build Ghostscript from scratch using, respectively, the VAX C
+compiler, CC, the Free Software Foundation's GNU C compiler, GCC, or the DEC
+C compiler, CC. Accordingly, you must have one of these compilers installed
+in order to build Ghostscript. (Other C compilers may work: CC and GCC are
+the only two compilers tested to date. DEC C V4.0 or later is required: the
+DEC C V1.3 run-time library has bugs that prevent Ghostscript from working.)
+These command files build and store the Ghostscript library in the object
+library GS.OLB. If you have DECwindows (X11) installed on your system, the
+executable image GS.EXE will also be built.
+
+Some environments use the DWTLIBSHR library for providing the X Windows
+intrinsics, and some use the XTSHR library. XTSHR is newer, and is part of
+the DECwindows/Motif product. However, DEC is still distributing versions
+of VMS with DWTLIBSHR. If your environment uses XTSHR, replace DWTLIBSHR in
+the list of link libraries with XTSHR.
+
+For OpenVMS VAX platforms with VAX C, issue the DCL command
+ $ @VMS-CC.MAK
+to build Ghostscript. For OpenVMS platforms with GNU C (either AXP or
+VAX), issue the DCL command
+ $ @VMS-GCC.MAK
+to build Ghostscript. For OpenVMS platforms with DEC C (either AXP or
+VAX), issue the DCL command
+ $ @VMS-DECC.MAK
+to build Ghostscript.
+
+The option "DEBUG" may be specified with either command file in order to
+build a debuggable Ghostscript configuration; e.g.,
+ $ @VMS-CC.MAK DEBUG
+
+Using GNU make
+--------------
+
+As of Ghostscript version 5.0, the file OPENVMS.MAK, together with some
+auxiliary .COM files, allows using GNU make for building Ghostscript on
+OpenVMS. To do this, use the command:
+
+ make -fopenvms.mak "OPENVMS={VAX,ALPHA}" "DECWINDOWS={1.2,<blank>}"
+
+i.e. specify either VAX or ALPHA as the value of the OPENVMS parameter, and
+either 1.2 or nothing (blank) as the value of DECWINDOWS. (Note that here
+the value VAX just means that you want to use the VAX C compiler: it doesn't
+imply that you are running on VAX hardware.) In Europe and other parts of
+the world where A4 paper size is used, you should also append "A4_PAPER=1"
+to the make line, to make A4 paper the default.
+
+Unfortunately, because of bugs in the DEC C compilers, GNU make doesn't
+compile properly on all versions of VMS. GNU make requires:
+ - On VAXen, VMS 7.1 or later (VMS 7.0 may work).
+ - On Alphas, VMS 6.2 or later.
+
+Also, GNU make, at least through version 3.75, requires some patches to run
+properly on VMS at all. We hope to be able to make available a precompiled
+executable with the patches in the near future. Meanwhile, however, here is
+a description of the necessary changes.
+
+The VAX and ALPHA edits have basically the same changes; the VAX C version
+has two edits in the [.GLOB] directory, to address a 'C' preprocessor
+limitation with VAX C. The remaining changes attempt to address the lack of
+consistency with "C" compilers and POSIX functionality, or the lack of it.
+
+Of course depending on what version of OpenVMS you have, and what versions
+of compilers (VAX C, DEC C on VAX or DEC on Alpha), these changes may be
+slightly different.
+
+=========================================================
+
+Steps to do GNU MAKE edits for VAX C version:
+
+1). Unpack the GNU make sources, version 3.75, from your favorite FTP
+site.
+2). Create an OpenVMS DCL command procedure containing the following
+lines
+ between the two markers "==========================" below.
+3). If you've never used EDIT/SUM before, you may want to read the
+following:
+ $ HELP DIFFERENCES / SLP, and
+ $ HELP EDIT / SUM
+4). Edits are done. Invoke the GNU make supplied command file
+MAKEFILE.COM,
+or if your have a prior version of GNU make, there is a makefile
+included with make.
+
+============================
+$ SUMSLP="EDIT/SUM"
+$ SUMSLP [.GLOB]FNMATCH.H/OUTPUT=[.GLOB]FNMATCH.H/UPDATE=SYS$INPUT:
+- 26, 27
+#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) || defined (WIN32))
+/
+$ SUMSLP [.GLOB]GLOB.H/OUTPUT=[.GLOB]GLOB.H/UPDATE=SYS$INPUT:
+- 28, 29
+#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) || defined (WIN32))
+/
+$ SUMSLP JOB.C/UPDATE=SYS$INPUT:
+- 641, 641
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 648, 648
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 657, 657
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 1316, 1316
+#ifdef HAVE_SIGSETMASK
+ (void) sigblock (fatal_signal_mask);
+#endif
+- 1392, 1392
+#ifdef HAVE_SIGSETMASK
+ (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
+#endif
+/
+$ SUMSLP JOB.H/UPDATE=SYS$INPUT:
+- 70, 70
+#if (__VMS_VER >= 70000000) && defined POSIX
+/
+$ SUMSLP MAIN.C/UPDATE=SYS$INPUT:
+- 398, 398
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 482, 482
+#if (__VMS_VER >= 70000000) && defined POSIX
+/
+$ SUMSLP VMSDIR.H/UPDATE=SYS$INPUT:
+- 7, 8
+#ifndef __SOCKET_TYPEDEFS
+ typedef unsigned long u_long;
+ typedef unsigned short u_short;
+#endif
+/
+============================
+
+Steps to do GNU MAKE edits for DEC C version:
+
+1). Unpack the GNU make sources, version 3.75. (in an empty directory)
+2). Create an OpenVMS DCL command procedure containing the following
+lines
+ between the two markers "==========================".
+3). If you've never used EDIT/SUM before, you may want to read the
+following:
+ $ HELP DIFFERENCES / SLP, and
+ $ HELP EDIT / SUM
+4). Edits are done. Invoke the GNU make supplied command file
+MAKEFILE.COM,
+or if your have a prior version of GNU make, there is a makefile
+included with make.
+
+============================
+$ SUMSLP="EDIT/SUM"
+$ SUMSLP CONFIG.H-VMS/UPDATE=SYS$INPUT:
+- 114, 114
+</* #define pid_t int */
+- 153, 153
+</* #define uid_t int */
+- 217, 217
+</* #define HAVE_SIGSETMASK 1 */
+/
+$ SUMSLP JOB.C/UPDATE=SYS$INPUT:
+- 641, 641
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 648, 648
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 657, 657
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 1316, 1316
+#ifdef HAVE_SIGSETMASK
+ (void) sigblock (fatal_signal_mask);
+#endif
+- 1392, 1392
+#ifdef HAVE_SIGSETMASK
+ (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
+#endif
+/
+$ SUMSLP JOB.H/UPDATE=SYS$INPUT:
+- 70, 70
+#if (__VMS_VER >= 70000000) && defined POSIX
+/
+$ SUMSLP MAIN.C/UPDATE=SYS$INPUT:
+- 398, 398
+#if (__VMS_VER >= 70000000) && defined POSIX
+- 482, 482
+#if (__VMS_VER >= 70000000) && defined POSIX
+/
+$ SUMSLP VMSDIR.H/UPDATE=SYS$INPUT:
+- 7, 8
+#ifndef __SOCKET_TYPEDEFS
+ typedef unsigned long u_long;
+ typedef unsigned short u_short;
+#endif
+============================
+
+********
+******** Other environments ********
+********
+
+QNX
+---
+
+The following notes are from John "Stosh" Muczynski, <STOSH@bauer.usa.com>.
+He is willing to answer questions as his time permits. He used the Watcom
+C16 compiler, version 9.5, with QNX version 4.20B. He had to modify the
+following files:
+
+SYS/PARAM.H
+Watcom doesn't supply a sys/param.h file. I defined it as
+--------------------------------clip here
+------------------------------
+/* CLK_TCK is used with the times() function and is defined in times.h
+*/
+#define HZ (CLK_TCK)
+--------------------------------clip here
+------------------------------
+It seems that HZ should be 1000 for QNX and not 100. The times()
+function appears to be POSIX 1003.1
+
+
+
+UNIXHEAD.MAK
+I modified unixhead.mak to support a qnx_ platform.
+--------------------------------clip here
+------------------------------
+PLATFORM=qnx_
+--------------------------------clip here
+------------------------------
+
+
+UNIXTAIL.MAK
+I modified unixtail.mak to support a qnx_ platform.
+--------------------------------clip here
+------------------------------
+# QNX 4.X
+qnx__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_qnx.$(OBJ) gp_qnxfs.$(OBJ)
+gp_unifn.$(OBJ)
+qnx_.dev: $(qnx__)
+ $(SETMOD) qnx_ $(qnx__)
+
+gp_qnx.$(OBJ): gp_qnx.c $(time__h) $(AK)
+
+gp_qnxfs.$(OBJ): gp_qnxfs.c $(AK) $(memory__h) $(string__h) $(gx_h)
+$(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+--------------------------------clip here
+------------------------------
+The change here is to copy the "sysv_" make lines into "qnx_"
+make lines and change (1) gp_sysv.* to gp_qnx.* and (2) gp_unifs.*
+to gpqnxfs.*
+
+I copied the gp_sysv.c source to gp_qnx.c and (a) deleted rename()
+because it is supported by the watcom compiler, (b) kept
+gettimeofday(), (c) added the gp_open_scratch_file() which doesn't
+use mktemp().
+
+I copied gp_unifs.c to gp_qnxfs.c and deleted the
+gp_open_scratch_file() because it uses mktemp() which watcom
+does not provide. Watcom does provide a tmpnam(char *buffer)
+function and more interestingly a FILE *tmpfile(void) function.
+If you ask I can fax you the manual pages.
+
+
+ANSIHEAD.MAK
+
+Compiler options:
+-----------------
+I used the Bauer "standard" options for compiling and linking under
+QNX:
+--------------------------------clip here
+------------------------------
+CFLAGS=-O -w4 -3 -mf $(XCFLAGS)
+LDFLAGS=-3 -N 64k -O -g -w3 -mf -fF $(XLDFLAGS)
+--------------------------------clip here
+------------------------------
+-N 64k gives a big stack size; I don't know if its necessary.
+The -mf on CFLAGS and LDFLAGS is very necessary (32-bit flat memory
+model).
+The -3 and -O and -g and -w3 and -w4 are just fluff.
+The -fF option doesn't make sense to me.
+
+********
+******** A guide to the source code ********
+********
+
+General
+-------
+
+There are very few machine dependencies in Ghostscript. A few of the .c
+files are machine-specific. These have names of the form
+ gp_<platform>.c
+specifically
+ gp_dosfb.c (MS-DOS)
+ gp_dosfs.c (MS-DOS and MS Windows)
+ gp_itbc.c (MS-DOS, Borland compilers)
+ gp_iwatc.c (MS-DOS, Watcom or Microsoft compiler)
+ gp_msdos.c (MS-DOS and MS Windows)
+ gp_ntfs.c (MS-Windows Win32s and Windows NT)
+ gp_os2.c (OS/2)
+ gp_os9.c (OS-9)
+ gp_unifs.c (Unix or OS-9)
+ gp_unix.c (Unix)
+ gp_sysv.c (System V Unix)
+ gp_vms.c (VMS)
+ gp_win32.c (MS-Windows Win32s and Windows NT)
+There are also some machine-specific conditionals in files with names
+<something>_.h. If you are going to extend Ghostscript to new
+machines or operating systems, you should check the *_.h files for
+ifdef's on things other than DEBUG, and you should probably count on
+making a new makefile and a new gp_ file.
+
+Library
+-------
+
+Files beginning with gs, gx, or gz (both .c and .h), other than gs.c and
+gserver.c, are the Ghostscript library. Files beginning with gdev are
+device drivers or related code, also part of the library. Other files
+beginning with g are library files that don't fall neatly into either the
+kernel or the driver category.
+
+Interpreter
+-----------
+
+gs.c is the main program for the interactive language interpreter; gserver.c
+is an alternative main program that is a rudimentary server. If you
+configure Ghostscript as a server rather than an interactive program, you
+will use gserver.c instead of gs.c.
+
+Files named z*.c are Ghostscript operator files. The names of the files
+generally follow the section headings of the operator summary in section
+6.2 of the PostScript manual.
+
+Files named i*.c, and *.h other than g*.h, are the rest of the
+interpreter. See the makefile for a little more information on how the
+files are divided functionally.
+
+Files named s*.c are a flexible stream package, including the Level 2
+PostScript 'filters' supported by Ghostscript.
diff --git a/gs/man/ansi2knr.1 b/gs/man/ansi2knr.1
new file mode 100644
index 000000000..f9ee5a631
--- /dev/null
+++ b/gs/man/ansi2knr.1
@@ -0,0 +1,36 @@
+.TH ANSI2KNR 1 "19 Jan 1996"
+.SH NAME
+ansi2knr \- convert ANSI C to Kernighan & Ritchie C
+.SH SYNOPSIS
+.I ansi2knr
+[--varargs] input_file [output_file]
+.SH DESCRIPTION
+If no output_file is supplied, output goes to stdout.
+.br
+There are no error messages.
+.sp
+.I ansi2knr
+recognizes function definitions by seeing a non-keyword identifier at the left
+margin, followed by a left parenthesis, with a right parenthesis as the last
+character on the line, and with a left brace as the first token on the
+following line (ignoring possible intervening comments). It will recognize a
+multi-line header provided that no intervening line ends with a left or right
+brace or a semicolon. These algorithms ignore whitespace and comments, except
+that the function name must be the first thing on the line.
+.sp
+The following constructs will confuse it:
+.br
+ - Any other construct that starts at the left margin and follows the
+above syntax (such as a macro or function call).
+.br
+ - Some macros that tinker with the syntax of the function header.
+.sp
+The --varargs switch is obsolete, and is recognized only for
+backwards compatibility. The present version of
+.I ansi2knr
+will always attempt to convert a ... argument to va_alist and va_dcl.
+.SH AUTHOR
+L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and
+continues to maintain the current version; most of the code in the current
+version is his work. ansi2knr also includes contributions by Francois
+Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>.
diff --git a/gs/man/gs.1 b/gs/man/gs.1
new file mode 100644
index 000000000..e464a55ce
--- /dev/null
+++ b/gs/man/gs.1
@@ -0,0 +1,406 @@
+'\" t
+.\"- -*- nroff -*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.\"
+.\"This file describes version 5.13 of Aladdin Ghostscript.
+.\"
+.\"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH GS 1 "27 April 1998"
+.SH NAME
+gs \- Aladdin Ghostscript interpreter/previewer
+.SH SYNOPSIS
+.B gs
+[
+.I options
+] [
+.I files
+] ...
+.br
+.SH DESCRIPTION
+Ghostscript is an implementation of Adobe Systems'
+PostScript (tm) and Portable Document Format (PDF) languages.
+.I Gs
+reads
+.I files
+in sequence and executes them as Ghostscript programs.
+After doing this, it reads further input from the standard input stream
+(normally the keyboard). Each line is interpreted separately.
+To exit from the interpreter, enter the `quit' command.
+The interpreter also exits gracefully if it encounters end-of-file.
+Typing the interrupt character (e.g. Control-C) is also safe.
+.PP
+The interpreter recognizes several switches described below, which may appear
+anywhere in the command line and apply to all files thereafter.
+.PP
+You can get a help message by invoking Ghostscript with the
+.B \-h
+or
+.B \-?
+option. This message also lists the available devices.
+.PP
+Ghostscript may be built with multiple output devices. Ghostscript
+normally opens the first one and directs output to it. To use device xyz
+as the initial output device, include the switch
+.nf
+ \-sDEVICE=xyz
+.fi
+in the command line. Note that this switch must precede the first .ps
+file, and only its first invocation has any effect. For example, for
+printer output in a normal configuration that includes an Epson printer
+driver, you might use the shell command
+.nf
+ gs \-sDEVICE=epson myfile.ps
+.fi
+instead of just
+.nf
+ gs myfile.ps
+.fi
+Alternatively, you can type
+.nf
+ (epson) selectdevice
+ (myfile.ps) run
+.fi
+All output then goes to the printer instead of the display until further
+notice. You can switch devices at any time by using the selectdevice
+procedure, e.g.,
+.nf
+ (vga) selectdevice
+.fi
+or
+.nf
+ (epson) selectdevice
+.fi
+As yet a third alternative, you can define an environment variable
+GS_DEVICE as the desired default device name. The order of precedence for
+these alternatives, highest to lowest, is:
+.nf
+ selectdevice
+ (command line)
+ GS_DEVICE
+ (first device in build list)
+.fi
+.PP
+To select the density on a printer, use
+.nf
+ gs \-sDEVICE=<device> \-r<xres>x<yres>
+.fi
+For example, on a 9-pin Epson-compatible printer, you can get the
+lowest-density (fastest) mode with
+.nf
+ gs \-sDEVICE=epson \-r60x72
+.fi
+and the highest-density mode with
+.nf
+ gs \-sDEVICE=epson \-r240x72.
+.fi
+.PP
+If you select a printer as the output device, Ghostscript also allows you
+to control where the device sends its output. Normally, output goes
+directly to a scratch file on Unix systems.
+To send the output to a series of files foo1.xyz,
+foo2.xyz, ..., use the switch
+.nf
+ \-sOutputFile=foo%d.xyz
+.fi
+The %d is a printf format specification; you can use
+other formats like %02d. Each file will receive one page of output.
+Alternatively, to send the output to a single file foo.xyz, with all
+the pages concatenated, use the switch
+.nf
+ \-sOutputFile=foo.xyz
+.fi
+.PP
+On Unix systems, you can send the output directly to a pipe. For
+example, to pipe the output to the command `lpr' (which, on many Unix
+systems, is the command that spools output for a printer), use the
+switch
+.nf
+ \-sOutputFile=\\|lpr
+.fi
+You can also send output to stdout for piping with the switch
+.nf
+ \-sOutputFile=\-
+.fi
+In this case you must also use the \-q switch, to prevent Ghostscript from
+writing messages to stdout.
+.PP
+To find out what devices are available, type
+.nf
+ devicenames ==
+.fi
+after starting up Ghostscript.
+Alternatively, you can use the \-h or \-? switch in the command line;
+the help message also lists the available devices.
+.PP
+To select a different paper size, use the command line switch
+.nf
+ -sPAPERSIZE=a_known_paper_size
+.fi
+e.g.,
+.nf
+ -sPAPERSIZE=a4
+.fi
+or
+.nf
+ -sPAPERSIZE=legal
+.fi
+As of this printing, the known paper sizes, defined in gs_statd.ps, are:
+.TS
+tab(>);
+l l l l l.
+.sp
+PAPERSIZE>X">Y">X cm>Y cm
+_
+11x17>11">17">27.94>43.18
+a0>33.0556">46.7778">83.9611>118.816
+a10>1.02778">1.45833">2.61056>3.70417
+a1>23.3889">33.0556">59.4078>83.9611
+a2>16.5278">23.3889">41.9806>59.4078
+a3>11.6944">16.5278">29.7039>41.9806
+a4>8.26389">11.6944">20.9903>29.7039
+a5>5.84722">8.26389">14.8519>20.9903
+a6>4.125">5.84722">10.4775>14.8519
+a7>2.91667">4.125">7.40833>10.4775
+a8>2.05556">2.91667">5.22111>7.40833
+a9>1.45833">2.05556">3.70417>5.22111
+archA>9">12">22.86>30.48
+archB>12">18">30.48>45.72
+archC>18">24">45.72>60.96
+archD>24">36">60.96>91.44
+archE>36">48">91.44>121.92
+b0>39.3889">55.6667">100.048>141.393
+b1>27.8333">39.3889">70.6967>100.048
+b2>19.6944">27.8333">50.0239>70.6967
+b3>13.9167">19.6944">35.3483>50.0239
+b4>9.84722">13.9167">25.0119>35.3483
+b5>6.95833">9.84722">17.6742>25.0119
+flsa>8.5">13">21.59>33.02
+flse>8.5">13">21.59>33.02
+halfletter>5.5">8.5">13.97>21.59
+ledger>17">11">43.18>27.94
+legal>8.5">14">21.59>35.56
+letter>8.5">11">21.59>27.94
+note>7.5">10">19.05>25.4
+.TE
+.SH "INITIALIZATION FILES"
+When looking for the initialization files (gs_*.ps), the files related
+to fonts, or the file for the `run' operator, Ghostscript first tries
+opening the file with the name as given (i.e., using the current
+working directory if none is specified). If this fails, and the file
+name doesn't specify an explicit directory or drive (i.e., doesn't
+begin with `/' on Unix systems), Ghostscript will try directories in the
+following order:
+.TP
+1.
+The directory/ies specified by the \-I switch(es) in the command
+line (see below), if any;
+.TP
+2.
+The directory/ies specified by the GS_LIB environment variable,
+if any;
+.TP
+3.
+The directory/ies specified by the GS_LIB_DEFAULT macro in the
+Ghostscript makefile (which has been set to
+"/usr/local/share/ghostscript/M.N:/usr/local/share/ghostscript/fonts"
+where M.N is the Ghostscript version number).
+.PP
+Each of these (GS_LIB_DEFAULT, GS_LIB, and \-I parameter) may be either
+a single directory, or a list of directories separated by a `:'.
+.SH X RESOURCES
+Ghostscript looks for the following resources under the program name
+`Ghostscript':
+.TP
+.B borderWidth
+The border width in pixels (default = 1).
+.TP
+.B borderColor
+The name of the border color (default = black).
+.TP
+.B geometry
+The window size and placement, WxH+X+Y (default is NULL).
+.TP
+.B xResolution
+The number of x pixels per inch (default is computed from WidthOfScreen
+and WidthMMOfScreen).
+.TP
+.B yResolution
+The number of y pixels per inch (default is computed from
+HeightOfScreen and HeightMMOfScreen).
+.TP
+.B useBackingPixmap
+Determines whether backing store is to be used for saving display window
+(default = true).
+.PP
+See the file `use.txt' for a more complete list of resources.
+.PP
+To set these resources, put them in a file (such as ~/.Xresources) in the
+following form:
+.sp
+.nf
+ Ghostscript*geometry: 612x792\-0+0
+ Ghostscript*xResolution: 72
+ Ghostscript*yResolution: 72
+.fi
+.PP
+Then load the defaults into the X server:
+.sp
+.nf
+ % xrdb \-merge ~/.Xresources
+.fi
+.SH OPTIONS
+.TP
+.BI \-\- " filename arg1 ..."
+Takes the next argument as a file name as usual, but takes all
+remaining arguments (even if they have the syntactic form of switches)
+and defines the name ARGUMENTS in userdict (not systemdict) as an
+array of those strings,
+.I before
+running the file. When Ghostscript
+finishes executing the file, it exits back to the shell.
+.TP
+.BI \-D name = token
+.TQ
+.BI \-d name = token
+Define a name in systemdict with the given definition. The token must
+be exactly one token (as defined by the `token' operator) and must not
+contain any whitespace.
+.TP
+.BI \-D name
+.TQ
+.BI \-d name
+Define a name in systemdict with value=null.
+.TP
+.BI \-S name = string
+.TQ
+.BI \-s name = string
+Define a name in systemdict with a given string as value. This is
+different from \-d. For example, \-dname=35 is equivalent to the
+program fragment
+.br
+ /name 35 def
+.br
+whereas
+\-s name=35 is equivalent to
+.br
+ /name (35) def
+.TP
+.B \-q
+Quiet startup \- suppress normal startup messages, and also do the
+equivalent of \-dQUIET.
+.TP
+.BI \-g number1 x number2
+Equivalent to
+.BI \-dDEVICEWIDTH= number1
+and
+.BI \-dDEVICEHEIGHT= number2 .
+This is for the benefit of devices (such as X11 windows)
+that require (or allow) width and height to be specified.
+.TP
+.BI \-r number
+.TQ
+.BI \-r number1 x number2
+Equivalent to
+.BI \-dDEVICEXRESOLUTION= number1
+and
+.BI \-dDEVICEYRESOLUTION= number2 .
+This is for the benefit of devices (such as printers)
+that support multiple X and Y resolutions.
+(If only one number is given, it is used for both X and Y resolutions.)
+.TP
+.BI \-I directories
+Adds the designated list of directories at the head of the
+search path for library files.
+.TP
+.B \-
+This is not really a switch. It indicates to Ghostscript that the
+standard input is coming from a file or a pipe. Ghostscript reads
+from stdin until reaching end-of-file, executing it like any other
+file, and then continues processing the command line. At the end of
+the command line, Ghostscript exits rather than going into its
+interactive mode.
+.PP
+Note that gs_init.ps makes systemdict read-only, so the values of names
+defined with \-D/d/S/s cannot be changed (although, of course, they can be
+superseded by definitions in userdict or other dictionaries.)
+.SH "SPECIAL NAMES"
+.TP
+.B \-dDISKFONTS
+Causes individual character outlines to be loaded from the disk
+the first time they are encountered. (Normally Ghostscript loads all the
+character outlines when it loads a font.) This may allow loading more
+fonts into RAM, at the expense of slower rendering.
+.TP
+.B \-dNOCACHE
+Disables character caching. Only useful for debugging.
+.TP
+.B \-dNOBIND
+Disables the `bind' operator. Only useful for debugging.
+.TP
+.B \-dNODISPLAY
+Suppresses the normal initialization of the output device.
+This may be useful when debugging.
+.TP
+.B \-dNOPAUSE
+Disables the prompt and pause at the end of each page.
+This may be desirable for applications where another program is
+`driving' Ghostscript.
+.TP
+.B \-dNOPLATFONTS
+Disables the use of fonts supplied by the underlying platform
+(e.g. X Windows). This may be needed if the platform
+fonts look undesirably different from the scalable fonts.
+.TP
+.B \-dSAFER
+Disables the deletefile and renamefile operators, and the
+ability to open files in any mode other than read-only. This may be
+desirable for spoolers or other sensitive environments.
+.TP
+.B \-dWRITESYSTEMDICT
+Leaves systemdict writable. This is necessary when running
+special utility programs such as font2c and pcharstr, which must bypass
+normal PostScript access protection.
+.TP
+.BI \-sDEVICE= device
+Selects an alternate initial output device, as described above.
+.TP
+.BI \-sOutputFile= filename
+Selects an alternate output file (or pipe) for the initial output
+device, as described above.
+.SH FILES
+.TP
+.B /usr/local/share/ghostscript/M.N/*
+Startup-files, utilities, and basic font definitions.
+.TP
+.B /usr/local/share/ghostscript/fonts/*
+Additional font definitions.
+.TP
+.B /usr/local/share/ghostscript/M.N/examples/*
+Demo Ghostscript files.
+.TP
+.B /usr/local/share/ghostscript/M.N/doc/*
+Assorted document files.
+.SH ENVIRONMENT
+.TP
+.B GS_OPTIONS
+String of options to be processed before the command line options.
+.TP
+.B GS_DEVICE
+Used to define the device used.
+.TP
+.B GS_FONTPATH
+Path names used to search for fonts
+.TP
+.B GS_LIB
+Path names for initialization files and fonts
+.TP
+.B TEMP
+Where temporary files are made
+.SH "SEE ALSO"
+The various Ghostscript document files (above).
+.SH BUGS
+See the network news group `comp.lang.postscript'.
diff --git a/gs/man/pdf2dsc.1 b/gs/man/pdf2dsc.1
new file mode 100644
index 000000000..2003b0b78
--- /dev/null
+++ b/gs/man/pdf2dsc.1
@@ -0,0 +1,52 @@
+.\" pdf2dsc.1: short documentation for pdf2dsc
+.\" Yves Arrouye <arrouye@debian.org>
+.TH PDF2DSC 1 "25 July 1996" "Ghostscript 4" "Ghostscript Tools"
+.SH NAME
+.B pdf2dsc
+\- generate a PS page list of a PDF document
+.SH SYNOPSIS
+.B pdf2dsc
+.I pdffile
+[
+.I dscfile
+]
+.SH DESCRIPTION
+.B pdf2dsc
+reads a Portable Document Format (PDF) document
+.I pdffile
+and creates a PostScript document
+.I dscfile
+that conforms to Adobe's Document Structuring Conventions (DSC)
+requirements.
+This new document simply tells Ghostscript to read the PDF file and to
+display pages one at a time.
+.PP
+The generated document can then be viewed with any PostScript viewer
+based on Ghostscript, like
+.BR ghostview (1)
+or
+.BR GSView ,
+which will let the user browse through the pages of the PDF document
+in any order.
+.PP
+If the output document name
+.I dscfile
+is not given on the command line, the name used is
+.I pdffile
+with any extension removed, followed by a
+.B .dsc
+extension.
+.SH CAVEATS
+The DSC document uses Ghostscript-specific procedures.
+In addition, the original PDF document must be accessible when the
+DSC document is read.
+.PP
+You need the
+.B pdf2dsc.ps
+file (originally by Russell Lang) that comes with Ghostscript releases
+3.53 and higher and a corresponding Ghostscript interpreter.
+.SH DOCUMENTATION
+Yves Arrouye <arrouye@debian.org>
+.SH SEE ALSO
+.BR gs (1),
+.BR ghostview (1)
diff --git a/gs/man/pdf2ps.1 b/gs/man/pdf2ps.1
new file mode 100644
index 000000000..a95169c53
--- /dev/null
+++ b/gs/man/pdf2ps.1
@@ -0,0 +1,21 @@
+.\"- -*- nroff -*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.\"
+.\"This file describes version 5.03 of Aladdin pdf2ps.
+.\"
+.\"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH pdf2ps 1 "10 November 1997"
+.SH NAME
+pdf2ps \- Aladdin Ghostscript PDF to PostScript translator
+.SH SYNOPSIS
+.B pdf2ps input.pdf output.ps
+.br
+.SH DESCRIPTION
+pdf2ps converts the Adobe Portable Document Format (PDF) file input.pdf to
+Level 2 PostScript in output.ps. pdf2ps uses gs(1). See
+/usr/local/lib/ghostscript/M.N/doc/use.txt for more details,
+where M.N is the Ghostscript version number.
diff --git a/gs/man/ps2ascii.1 b/gs/man/ps2ascii.1
new file mode 100644
index 000000000..eb0993456
--- /dev/null
+++ b/gs/man/ps2ascii.1
@@ -0,0 +1,37 @@
+.\"- -*- nroff -*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.\"
+.\"This file describes version 4.0 of Aladdin ps2ascii.
+.\"
+.\"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH ps2ascii 1 "20 June 1996"
+.SH NAME
+ps2ascii \- Aladdin Ghostscript PostScript or PDF to ASCII translator
+.SH SYNOPSIS
+.B ps2ascii [input.ps [output.txt]]
+.br
+.B ps2ascii input.pdf [output.txt]
+.br
+.SH DESCRIPTION
+
+ps2ascii extracts ASCII text from PostScript or PDF, using gs(1). If the
+pathname "input.ps" is not specified, PostScript is read from standard input;
+PDF input must come from an explicitly-named file, not standard input. If the
+pathname "output.txt" is not specified, the ASCII text is written to standard
+output.
+
+ps2ascii doesn't look at font encoding, and isn't very good at dealing with
+kerning, so for dealing with PostScript (but not currently PDF), you might
+consider pstotext(1).
+
+.SH SEE ALSO
+
+.B pstotext(1)
+
+.SH AUTHOR OF DOCUMENTATION
+
+.B Paul McJones <mcjones@pa.dec.com>
diff --git a/gs/man/ps2epsi.1 b/gs/man/ps2epsi.1
new file mode 100644
index 000000000..a0f5b9270
--- /dev/null
+++ b/gs/man/ps2epsi.1
@@ -0,0 +1,100 @@
+.TH ps2epsi 1 "September 1, 1997"
+.SH NAME
+ps2epsi \- generate conforming postscript
+
+.SH SYNOPSIS
+.B ps2epsi
+.I infile.ps
+[
+.I outfile.ps
+] (Unix)
+.br
+.B ps2epsi
+.I infile.ps outfile.epi
+ (MS-DOS)
+
+.SH DESCRIPTION
+.B ps2epsi
+is a utility, based on
+.I Ghostscript,
+which takes as input a postscript
+file and generates a new output file which conforms to Adobe's
+.I Encapsulated Postscript Interchange
+or EPSI format. This is a
+special form of encapsulated postscript (EPS) which adds a bitmap
+version of the final displayed page (in the form of postscript
+comments) to the beginning of the file. This bitmap can be used by
+programs which understand EPSI (usually word processors or DTP
+programs) to give a preview version of the postscript on screen. The
+displayed quality is often not very good (eg. low resolution, no
+colours), but the final printed version uses the real postscript,
+and thus has the normal postscript quality.
+
+.SH OPTIONS
+None.
+
+.SH UNIX USAGE
+Using the supplied shell script, the command is:
+.br
+ ps2epsi
+.I infile.ps
+[
+.I outfile.epsi
+]
+.br
+where
+.I infile.ps
+is the input file and
+.I outfile.epsi
+is the output EPSI file. If the output filename is omitted, it will
+be generated from the input filename.
+If a standard extension (.ps, .cps, .eps or .epsf) is
+used, it will be replaced with the output extension .epsi.
+
+.SH MSDOS USAGE
+Using the supplied batch file, the command is simply:
+.br
+ ps2epsi
+.I infile.ps outfile.epi
+.br
+where
+.I infile.ps
+is the original postscript file, and
+.I outfile.epi
+is the name of the output file.
+
+.SH LIMITATIONS
+Successful encapsulation of arbitrary postscript files cannot be
+guaranteed, as there are certain restrictions in what is permitted in
+a postscript file for it to be properly encapsulated.
+.B ps2epsi
+does a little extra work to try to help encapsulation, and it automatically
+calculates the bounding box (required for all encapsulated postscript
+files), so, most of the time, it does a pretty good job. There are
+bound to be cases, however, where the encapsulation will not work,
+because of the content of the original postscript file.
+
+.SH FRAMEMAKER
+The
+.I Framemaker
+DTP system is one application which understands EPSI
+files, and
+.B ps2epsi
+has been tested on a number of postscript diagrams
+from a variety of sources, using Framemaker 3.0 on a Sun.
+.I Framemaker
+on other platforms should be able to use these files,
+although I have not been able to test this.
+
+.SH FILES
+.nf
+ps2epsi.bat - MSDOS batch file
+ps2epsi - Unix shell script
+ps2epsi.ps - the Ghostscript program which does the work
+.fi
+
+.SH "SEE ALSO"
+gs(1)
+
+.SH AUTHOR
+George Cameron <george@bio-medical-physics.aberdeen.ac.uk>
diff --git a/gs/man/ps2pdf.1 b/gs/man/ps2pdf.1
new file mode 100644
index 000000000..ee9597528
--- /dev/null
+++ b/gs/man/ps2pdf.1
@@ -0,0 +1,35 @@
+.\"- -*- nroff -*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.\"
+.\"This file describes version 4.0 of Aladdin ps2pdf.
+.\"
+.\"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH ps2pdf 1 "19 June 1996"
+.SH NAME
+ps2pdf \- Aladdin Ghostscript PostScript to PDF translator
+.SH SYNOPSIS
+.B ps2pdf input.ps output.pdf
+.br
+.SH DESCRIPTION
+
+ps2pdf converts the PostScript file input.ps to the Adobe Portable
+Document Format (PDF) in output.pdf. ps2pdf uses gs(1). See
+/usr/local/lib/ghostscript/M.N/doc/use.doc for more details,
+where M.N is the Ghostscript version number.
+
+Currently ps2pdf does a reasonable job on filled/stroked graphics, on bitmap
+images, and on text in the 14 built-in PDF fonts in the intersection of
+Windows and ISO Latin-1 encodings. It converts all other text in the
+PostScript file to bitmaps in the PDF file (although it does only write the
+bitmap for each character once per page, and only on pages where the
+character is actually used). It does not compress the output at all, except
+for character bitmaps: it can't use LZW because of Unisys' patent claims,
+and it doesn't yet use other compression methods for images.
+
+.SH AUTHOR OF DOCUMENTATION
+
+.B L. Peter Deutsch <ghost@aladdin.com>
diff --git a/gs/new-user.txt b/gs/new-user.txt
new file mode 100644
index 000000000..ca97f8299
--- /dev/null
+++ b/gs/new-user.txt
@@ -0,0 +1,570 @@
+ Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, new-user.txt, provides background information for new users.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** An overview of Ghostscript ********
+********
+
+Ghostscript is the name of a set of software that provides:
+
+ - An interpreter for the PostScript (TM) language and the Adobe
+Portable Document Format (PDF -- sometimes confused with Acrobat, Adobe's
+PDF browser/editor product), and
+
+ - A set of C procedures (the Ghostscript library) that implement
+the graphics and filtering (data compression / decompression / conversion)
+capabilities that appear as primitive operations in the PostScript language
+and in PDF.
+
+How is Ghostscript licensed? Where can I find it?
+--------------------------------------------------
+
+Ghostscript is a copyrighted work (Aladdin Enterprises owns the copyright);
+it is not shareware or in the public domain. Different versions of it are
+distributed with three different licenses:
+
+ - Versions entitled "Aladdin Ghostscript" are distributed with a
+license called the Aladdin Free Public License that allows free use,
+copying, and distribution by end users, but does not allow commercial
+distribution. You can always get the current version of Aladdin Ghostscript
+with this license by Internet FTP from
+ ftp://ftp.cs.wisc.edu/ghost/aladdin/gsNNN/ghostscript*NNNN*
+or, if you run AFS, by direct reference to
+ /afs/cs.wisc.edu/public/ghost/aladdin/gsNNN/ghostscript*NNNN*
+where NNN is the version number without embedded dots (e.g., 503) and NNNN
+is the version number with dots (e.g., 5.03). If you do not have convenient
+access to the Internet, you can order Aladdin Ghostscript on a CD-R disk,
+along with some useful related programs and documentation: for more
+information, see
+ http://www.cs.wisc.edu/~ghost/cd.html
+or send e-mail to Russell Lang (see the e-mail address under "Previewers"
+below). Please note that this is not "commercial licensing"; you are still
+getting freely redistributable software, with no support and no warranty.
+
+ - Versions entitled "GNU Ghostscript" are distributed with the GNU
+General Public License, which allows free use, and free copying and
+redistribution under certain conditions (including, in some cases,
+commercial distribution). GNU Ghostscript versions are released
+approximately a year after the corresponding Aladdin Ghostscript version.
+You can always get the current version of GNU Ghostscript by Internet FTP
+from
+ ftp://ftp.cs.wisc.edu/ghost/gnu/gsNNN/ghostscript*NNNN*
+or, if you run AFS, by direct reference to
+ /afs/cs.wisc.edu/public/ghost/gnu/gsNNN/ghostscript*NNNN*
+or from any of the GNU distribution sites, such as ftp.uu.net:/systems/gnu
+or gatekeeper.dec.com:/pub/GNU; you can also get GNU Ghostscript on tape
+or CD-ROM from the Free Software Foundation. For a more complete list of
+sites, including sites outside the U.S., send e-mail to
+gnu@prep.ai.mit.edu.
+
+ - Versions of Ghostscript are also available for commercial
+licensing. See the next section for details.
+
+Aladdin Ghostscript and GNU Ghostscript come with NO WARRANTY and NO
+SUPPORT. If you have a question or a bug to report, please see the
+section "If you need help" below for information about what to do.
+
+The Ghostscript source code distribution, and the Ghostscript executable
+code, include the following libraries obtained from other parties:
+
+ - The Independent JPEG Group (IJG) library. The executable versions
+of Ghostscript are based in part on the work of the Independent JPEG Group.
+For more information, please see the file jpeg.mak in the main Ghostscript
+source directory, and the README file in the jpeg subdirectory of the
+Ghostscript source code.
+
+ - The PNG library created by Dave Martindale, Guy Eric Schalnat,
+Paul Schmidt, and Tim Wegner, of Group 42, Inc. For more information,
+please see the libpng.mak file in the main Ghostscript source directory, and
+the files readme.txt and png.h in the libpng subdirectory of the Ghostscript
+source code.
+
+ - The zlib library created by Jean-loup Gailly and Mark Adler. For
+more information, please see the zlib.mak file in the main Ghostscript
+source directory, and the README file in the zlib subdirectory of the
+Ghostscript source code.
+
+These libraries do NOT fall under either the GNU License or the Aladdin
+Ghostscript Free Public License; they come with their own licenses, which
+also allow free use and redistribution under appropriate circumstances and
+which appear in the files referenced just above. These libraries are
+entirely original works of their respective authors, and are provided "AS
+IS" with NO WARRANTY and NO SUPPORT.
+
+What if I want support?
+-----------------------
+
+Neither Aladdin Enterprises nor any organization known to us currently
+offers Ghostscript support for end-users -- that is, for people or companies
+who just want to use Ghostscript and not redistribute it as part of a
+product. Companies that include Ghostscript in their products under a
+commercial license (see next section) may offer support to end-users, but it
+would be support for the company's own product, not for Ghostscript per se.
+
+Nothing in the GNU or Aladdin Free licenses prevents anyone from providing
+support for Ghostscript, either free or commercial. Aladdin would be happy
+to include in the Ghostscript documentation the contact information for
+anyone who wants to offer such support.
+
+What about commercial use?
+--------------------------
+
+GNU Ghostscript may not be incorporated into commercial products which
+forbid copying or for which customers cannot obtain source code for no more
+than the cost of reproduction, although it may be distributed ("aggregated")
+with commercial products; Aladdin Ghostscript may not be incorporated into
+commercial products at all, and may only be distributed commercially under
+extremely limited circumstances. However, Ghostscript is also available for
+commercial licensing, which in addition to the right to incorporate
+Ghostscript into commercial products includes support, a limited warranty,
+high-quality fonts, and other benefits. For more information about
+commercial licensing of Ghostscript, please contact Aladdin Enterprises'
+commercial distribution partner, the only entity legally authorized to
+distribute Ghostscript per se on any terms other than the GNU or Aladdin
+free licenses:
+
+ Licensing Information
+ Artifex Software Inc.
+ 454 Las Gallinas Ave., suite 108
+ San Rafael, CA 94903 U.S.A.
+ voice +1-415-492-9861
+ fax +1-415-492-9862
+ e-mail: info@arsoft.com
+
+Artifex does not offer commercial support as a separate service; support is
+available only to OEM licensees (that is, licensees who will be
+redistributing Ghostscript in a product).
+
+What platforms does Ghostscript run on?
+---------------------------------------
+
+Ghostscript is written entirely in C (with some optional assembly-language
+accelerators for MS-DOS platforms), with special care taken to make it run
+properly on systems of either byte order and of various word lengths.
+
+GNU Ghostscript is known to run on the following platform families:
+
+ - A wide variety of Unix systems using X Windows version 11, release
+ 4, 5, and 6, including Sun-3, Sun-4, Sun-386i, and Sun
+ SPARCStation; generic 80386/486/Pentium machines running Linux,
+ 386/ix, FreeBSD, ISC Unix, SCO Unix, and Solaris; H-P 9000/300 and
+ 9000/800; DECStation 2100 and 3100; VAX running Ultrix and OSF/1;
+ Sequent Symmetry; Convex C1 and C2; Tektronix 4300; SGI Iris
+ Indigo; 4.4bsd Unix systems (FreeBSD (intel), NetBSD (intel,
+ sparc, m68k (apple, amiga, sun & hp) and vax) and 386BSD (intel)).
+
+ - Sun workstations (Sun-3, SPARC, Sun-386i) running SunView;
+
+ - VAX or AXP systems running VMS with X11R4/5 and DEC C or gcc.
+
+Aladdin Ghostscript is known to run on all of the above, and additionally
+the following platform families:
+
+ - IBM PC and compatibles with EGA, VGA, SuperVGA, or compatible
+ graphics under MS-DOS 3.1, 3.3, 5.0, or 6.22, and Microsoft
+ Windows 3.1, NT, or 95;
+
+ - IBM PC and compatibles under DR DOS 6.0;
+
+ - IBM PC and compatibles under OS/2 2.0, 2.1 and Warp 3.0.
+
+ - Macintosh with System 7 or later, both 680x0 and PowerPC native.
+ For specific information on the Macintosh implementation, please
+ see http://www.glyphic.com/glyphic/projects/macgs.html
+
+It is very likely that Ghostscript will run under other versions of MS-DOS,
+and other versions of Unix that support X11, but it has not been tested in
+these environments. (Ghostscript does not run well on PC-compatibles with
+Hercules display cards, since text and graphics output interfere with each
+other, but you can work around this by redirecting the text output to a file.)
+
+Ghostscript has also been ported to a number of platforms by users, who are
+willing to be contacted regarding problems on those specific platforms:
+
+ - For information and possibly precompiled binaries for NeXT
+ machines, contact Alan Barclay <escribe@wintermute.co.uk>,
+ in the U.K. at +44-1224-591779 (voice & fax).
+
+ - For information on a port to the Amiga, contact Andreas Maschke
+ (epgbc@cluster6.urz.uni-halle.de). This port includes drivers for
+ IFF (file format)
+ RETINA (graphics board) and
+ INTUI (Amiga Window system)
+ by Andreas Heitmann (andreas@gotcha.swb.de).
+
+ - For information on a port to the Atari ST, contact Tim
+ Gallivan (timg@landau.ph.utexas.edu).
+
+ - For information on a port to the Acorn Archimedes, contact
+ David Elworthy (David.Elworthy@cl.cam.ac.uk).
+
+********
+******** Related work
+********
+
+PDF encryption
+--------------
+
+A user outside the U.S. has created code that allows processing of encrypted
+PDF files. Unfortunately, current U.S. export control laws don't allow
+redistribution of this code from a site in the U.S., even though it's freely
+available to anyone anywhere in the world from its author's site, so you'll
+have to get this code from:
+
+ http://www.ozemail.com.au/~geoffk/pdfencrypt/pdf_sec.ps
+
+If that doesn't work, try:
+
+ http://www.ozemail.com.au/%7Egeoffk/pdfencrypt/pdf_sec.ps
+
+The patch consists entirely of PostScript code, so it can be added to a
+running version of Ghostscript -- you don't have to recompile anything. It
+is a single file that replaces the file pdf_sec.ps in the standard
+Ghostscript fileset.
+
+Previewers
+----------
+
+The Ghostscript user interface is very primitive, so several people have
+contributed screen previewers with better user interfaces.
+
+We know of two freely available X Windows screen previewers based on
+Ghostscript: Ghostview and GSPreview. For information on Ghostview, contact
+Tim Theisen (ghostview@cs.wisc.edu). For information on GSPreview, contact
+Richard Hesketh (rlh@ukc.ac.uk).
+
+There is a freely available previewer for OpenVMS (both VAX and AXP) called
+GhostView-VMS or gv-vms, derived from Tim Theisen's Ghostview 1.5 by
+Johannes Plass (PLASS@dipmza.physik.Uni-Mainz.DE). Some places you can find
+it are:
+ WWW:
+ http://www.wku.edu/htbin/fileserv?X11KIT
+ FTP:
+ site: ftp.wku.edu
+ file: VMS/FILESERV/X11Kit.ZIP
+ site: nic.switch.ch
+ file: mirror/vms/spc/macro32/savesets/x11kit.zip
+ site: ada.cenaath.cena.dgac.fr
+ files: DECWINDOWS/XAW3D/
+ site: axp.psl.ku.dk
+ files: DECWINDOWS/XAW3D/
+
+There is a freely available MS Windows screen previewer based on
+Ghostscript, called GSview, and a similar OS/2 previewer.
+GSview is available from
+ http://www.cs.wisc.edu/~ghost/gsview/
+For technical information on GSview for Windows or PM GSview, please contact
+Russell Lang (rjl@aladdin.com). (Aladdin provides Lang with a mail alias,
+but Lang is not an employee or agent of Aladdin.) These programs are also
+available for commercial licensing from Artifex Software Inc.
+
+Users have created two packages that provide a set of GSview-like commands
+that MS-DOS users can enter through the keyboard. One such package, created
+by GUST, the Polish TeX Users Group, is in the public domain. It is
+available from
+ ftp.pg.gda.pl:/pub/TeX/GUST/contrib/PS/ps_view/*
+and from sites in the CTAN network such as
+ ftp.dante.de:/tex-archive/support/ps_view/*
+The authors describe the package as follows:
+ Fast and easy previewing of PS documents!
+ a PostScript preamble providing an interactive environement
+ for previewing PostScript documents. The current version
+ can drive the current version of the Ghostscript interpreter
+ and assumes conformance of the document to the Adobe PostScript
+ structuring conventions.
+ Batch files provided for MS DOS, however ps_view can be adapted
+ to any operating system.
+For more information, e-mail to Boguslaw Jackowski <jacko@ipipan.gda.pl>.
+
+The other keyboard-based viewing package is available from
+ puccini.ujf-grenoble.fr:pub/contrib-ps/DOS-PSV/*
+and appears to be redistributable with no restrictions.
+
+Another user has created a Ghostscript-based bitmap previewing program for
+Linux that doesn't use X Windows, called BMV.
+
+ BMV is a very simple viewer of images in the pbm(5)-raw format
+ and front end for GhostScript, based on Svgalib library for Linux
+
+ BMV is distributed under GNU GPL (General Public License),
+ you can obtain a copy from many FTP sites if you are interested in details
+
+ Jan Kybic, Prosecka 681, Praha 9, Czech Republic, <kybic@earn.cvut.cz>
+
+ There is a port of BMV under SCO Unix by William Bader
+ <wbader@pluto.csee.lehigh.edu>. Contact him if you are interested.
+
+BMV is available from
+ ftp://sunsite.unc.edu/pub/Linux/apps/graphics/viewers/bmv-1.1.tar.gz
+
+Other programs
+--------------
+
+Mr. Norio Katayama (katayama@nacsis.ac.jp) has done some work on making
+Ghostscript work well with Kanji fonts. Please contact him for more
+information.
+
+An easy-to-install Kanji font for Ghostscript, with installation
+instructions, can be found at
+ http://www.cit.ics.saitama-u.ac.jp/~far/howto/gs-ttf.html
+
+An extensive list of Unix systems and the fonts available on them is
+available on
+ http://www.math.utah.edu/~beebe/#PostScript-fonts
+courtesy of Nelson H. F. Beebe.
+
+Genscript is a free replacement for the enscript program. Genscript
+converts ASCII files to PostScript and spools generated PostScript output to
+the specified printer or leaves it to file. Genscript can be easily
+extended to handle different output media and it has many options which can
+be used to customize printouts. You can find the current version on
+
+ ftp://prep.ai.mit.edu/pub/gnu/genscript-1.3.0.tar.gz
+
+ Genscript home page: http://www.iki.fi/~mtr/genscript/
+ (or http://www.hut.fi/~mtr/genscript/)
+
+There is a good free utility "pstotext" that works with Ghostscript to
+extract plain-text from PostScript files. It is much better than the
+ps2ascii utility distributed with Ghostscript. You can read the pstotext
+documentation at:
+
+ http://www.research.digital.com/SRC/virtualpaper/manpages/pstotext.1.html
+
+You can download pstotext from the following URL:
+
+ http://www.research.digital.com/SRC/virtualpaper/pstotext.html
+
+There is no formal technical support for pstotext, but the authors are happy
+to receive your questions and comments by e-mail at the following locations:
+
+ http://www.research.digital.com/SRC/virtualpaper/comments.html
+ mailto:mcjones@pa.dec.com
+ mailto:birrell@pa.dec.com
+
+For more information about the authors' Virtual Paper project, which
+attempts to make on-line reading of lengthy material (like research reports,
+manuals, or entire books) comfortable, read:
+
+ http://www.research.digital.com/SRC/virtualpaper
+
+Martin Lottermoser <Martin.Lottermoser@mch.sni.de> has developed a
+higher-quality driver for the H-P inkjet printers (currently, DeskJet 500,
+500C, 510, 520, 540, 550C, 560C, 850C, 855C). You can get information about
+his driver, called hpdj, from:
+
+ ftp://ftp.pdb.sni.de/pub/utilities/misc/hpdj.html
+
+Uli Wortmann <uli@bonk.ethz.ch> has developed a higher-quality driver for
+certain H-P inkjet printers (currently, DeskJet 670, 690, and 8xx). For
+more information and downloads, visit:
+
+ http://bonk.ethz.ch/software.html
+
+
+********
+******** If you need help ********
+********
+
+There is a Frequently Asked Questions file available for Internet anonymous
+FTP from
+ ftp://ftp.cs.wisc.edu/ghost/gsfaq.txt
+(i.e., FTP to ftp.cs.wisc.edu, file name /ghost/gsfaq.txt)
+or, if you run AFS, by direct reference to
+ /afs/cs.wisc.edu/public/ghost/gsfaq.txt
+and also available by HTTP (World Wide Web) from
+ http://www.cs.wisc.edu/~ghost/gsfaq.html
+It isn't updated very often, so it may be a little out of date.
+
+In December 1995, CompuServe announced that the Graphics Support Forum
+offers Message Section and Library 21, "Ghostscript", for technical
+assistance with Ghostscript. Ghostscript is available for downloading in
+Library 21, "Ghostscript." To access the Graphics Support Forum, GO
+GRAPHSUP. This service has no connection with Aladdin Enterprises.
+
+Aladdin Enterprises doesn't have the resources to respond to questions from
+users of the freely available versions of Ghostscript. (Responding to
+questions and bug reports is one of the benefits that Artifex Software
+provides to commercial users in exchange for the licensing fee.) If you
+have problems with Ghostscript, and you have access to the Internet, we
+suggest you post your question to one of the following Usenet newsgroups:
+
+ - If your question is about GNU Ghostscript (currently, versions
+3.33 and below), post it to the gnu.ghostscript.bug newsgroup. If you have
+access to Internet mail, but not news, send e-mail to
+bug-ghostscript@prep.ai.mit.edu, which is equivalent to posting to the
+gnu.ghostscript.bug newsgroup.
+
+ - If your question is about Aladdin Ghostscript (currently, versions
+above 3.33), post it to the comp.lang.postscript newsgroup. If you have
+access to Internet mail, but not news, send e-mail to
+comp.lang.postscript@aladdin.com, which is equivalent to posting to the
+comp.lang.postscript newsgroup. (We hope to establish a separate newsgroup
+for Aladdin Ghostscript in the future, since comp.lang.postscript was not
+intended for Ghostscript discussion per se.)
+
+There are hundreds of Ghostscript user sites all over the world, and often
+another user will be able to help you. If you are having trouble with
+a specific device driver, look in the file devs.mak and see if it is a
+user-maintained driver. If so, please contact the person listed there
+directly; please do not contact Aladdin Enterprises regarding
+user-maintained drivers.
+
+Aladdin Enterprises does want Ghostscript to be of high quality, so if you
+have been running Ghostscript and encounter a problem, we encourage you to
+post bugs to the newsgroups mentioned above. We will consider investigating
+problems reported to those newsgroups, or e-mailed directly to
+ghost@aladdin.com, if (and only if) the report meets all the following
+criteria:
+
+ - You are using the most recent version of Aladdin Ghostscript.
+
+ - You obtained Ghostscript directly from Aladdin Enterprises, or
+ from the FTP or AFS site on the Internet mentioned above (i.e., not
+ from a bulletin board system or a commercial system such as
+ CompuServe or GEnie).
+
+ - You have installed Ghostscript successfully, and used it
+ successfully on other input data.
+
+ - Your problem is reproducible, and you can mail us the input
+ data that evokes it (by e-mail, anonymous FTP, or PC diskette).
+ (But please do not send anything unless we ask you for it.)
+
+ - You created the bug report using the form in bug-form.txt,
+ completely filled out.
+
+Bug reports that include suggested fixes are especially welcome.
+
+As time permits, Aladdin Enterprises may also respond to e-mail from the
+following classes of users:
+
+ - Beta testers who have actually given us at least one report on
+ some beta version supplied to them.
+
+ - People developing drivers that are for, or applications that
+ are based on, Ghostscript and that will be made freely available.
+
+ - People who express serious interest in commercial licensing
+ of Ghostscript.
+
+Aladdin Enterprises owns or has access to the following hardware and
+software:
+
+ Pentium and 486 PCs with color SuperVGA displays;
+ Epson-compatible printer (the printer also is compatible with
+ the IBM Proprinter); various H-P printers. These systems run
+ MS-DOS 5.0 and 6.22 and Microsoft Windows 3.1 and 95 with
+ Borland C++ 4.0 (and several older versions), Watcom C++ 10.0,
+ and Microsoft Visual C++ 4.0, and Linux with gcc.
+
+ SPARCstation, SunOS 4.1, cc and gcc, X11R5 and SunView;
+ both monochrome and color displays.
+
+ DECstation, Ultrix.
+
+ IBM RS/6000 and PowerPC, Unix (AIX 3.n).
+
+ DEC AXP (Alpha), OSF/1.
+
+If your problem turns out to be specific to some other hardware or
+software configuration, it may take longer to track down, since we
+will have to rely on other users to help.
+
+Aladdin's contact information is as follows:
+
+ Aladdin Enterprises
+ P.O. box 60264
+ Palo Alto, CA 94306
+ phone +1-650-322-0103 (8:30 AM - noon, Pacific time)
+ fax +1-650-322-1734
+ ghost@aladdin.com
+
+Please do not contact us if all you want is help with the freely distributed
+versions of Ghostscript! Ghostscript is free, but our time is not. If you
+call for help, we will tell you politely that we cannot answer your
+question. Ghostscript's documentation, while not of commercial end-user
+quality, has been adequate for thousands of users (for many of whom English
+is a foreign language), so the answer to your question is very likely in it
+somewhere.
+
+********
+******** Things you can do to help ********
+********
+
+There are some projects that users could do that are somewhat
+decoupled from the main body of the code, and that would help improve
+Ghostscript:
+
+ - Making Ghostscript work with the free emx/gcc and rsx libraries
+would provide an alternative MS-DOS / Windows 95 / Windows NT implementation
+that doesn't require any proprietary, commercial compilers. If someone was
+willing to do the work, we would be happy to include this in our list of
+supported platforms and to distribute the makefiles. If interested, please
+consult the following URL:
+ http://www.leo.org/pub/comp/os/os2/leo/gnu/emx+gcc/index.html
+and then contact ghost@aladdin.com if you want to do the work.
+
+ - Someone is needed to take responsibility for texinfo and/or man
+page documentation for Ghostscript. What this would involve is updating
+this documentation during the beta test period for each release, and
+sending it to Aladdin to be included in the final fileset. (Aladdin would
+continue to supply the plain-text documentation as it currently exists.)
+
+ - Adobe has donated the specification of the Display PostScript C
+API to the X distribution, as well as the client-side implementation.
+Modifying Ghostscript to interface with this code as a substitute for a
+Display PostScript server might make Ghostscript a lot more useful, since
+it would then be "plug compatible" with Display PostScript in an important
+way. Contact ghost@aladdin.com if you would like to help with this.
+
+********
+******** Acknowledgements ********
+********
+
+Ghostscript was originally created, and is primarily developed and
+maintained, by L. Peter Deutsch, President of Aladdin Enterprises.
+
+Special thanks are due to Russell Lang, for the GSview for Windows and PM
+GSview programs and for contributing most of the code for the Microsoft
+Windows and OS/2 environments; to Tim Theisen, for the Ghostview program for
+X Windows and for major contributions to, and ongoing assistance with
+support of, the code for the X Windows environment; to Martin Fong, for the
+original port of Ghostscript to the Macintosh, and Mark Lentczner, for the
+current Macintosh port; and to the Independent JPEG Group, to Group 42,
+Inc., and to Jean-loup Gailly and Mark Adler, for creating the freely
+available libraries that Ghostscript uses.
+
+Special thanks are due to URW++ Design and Development Incorporated, of
+Hamburg, Germany (http://www.urwpp.de), for making a commercial-quality set
+of the 35 standard PostScript Type 1 fonts available for free distribution
+under the GNU and Aladdin licenses.
+
+Special thanks are due to Richard Stallman and the Free Software Foundation
+for originating the GNU License, for originally motivating the creation of
+Ghostscript, and for being the primary distributor of GNU Ghostscript on
+the Internet.
+
+The file helpers.txt contains a list of the many other people who have
+contributed significantly to improving Ghostscript.
diff --git a/gs/news b/gs/news
new file mode 100644
index 000000000..93f69963e
--- /dev/null
+++ b/gs/news
@@ -0,0 +1,5241 @@
+ Copyright (C) 1989, 1996, 1997, 1998 Aladdin Enterprises.
+ All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, NEWS, describes the changes in the most recent releases of
+Ghostscript. Changes in older releases are described in history*.txt.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Within each release, news appears in the following order: Documentation,
+Procedures, Utilities, Drivers, Platforms, Fonts, Interpreter, Streams
+(included under Interpreter through release 2.9.9), Library. Changes marked
+with a * were made available as patches to a previous release.
+
+Version 5.13 (4/27/98)
+======================
+
+This adds a significant set of changes to allow Ghostscript to run in
+multiple asynchronous threads with a suitable device driver. The
+separation of processing uses a modification of the banding (clist)
+mechanism.
+
+Drivers
+-------
+
+A sample asynchronous driver is provided to illustrate the mechanism for
+using multiple threads. (gdevasyn.c)
+
+Version 5.12 (4/14/98)
+======================
+
+This adds one fix to 5.11. We are less confident that this fix won't
+perturb other things, which is why we are putting it into its own fileset.
+
+Note that the 5.12 incremental fileset also includes all the changes in the
+5.11 fileset, to respond to a request not to "nest" incremental filesets.
+
+Drivers
+-------
+
+Fixes bugs:
+ - get_bits from a x11cmyk device caused an error. (gdevxalt.c)
+(5.23)
+
+Library
+-------
+
+Fixes bugs:
+ - RasterOp and transparency didn't work for devices with color
+representations other than 1-bit black and white, 8-bit gray, and 24-bit
+color. (gdevdflt.c, gdevmrop.c) (5.23)
+ - Drawing cached characters sometimes ignored the RasterOp and
+transparency setting. (gxccache.c) (5.23)
+
+Version 5.11 (4/10/98)
+======================
+
+This is an incremental fileset containing a few important bug fixes plus a
+couple of minor enhancements needed for other Aladdin projects. IMPORTANT
+NOTE: the bug fixes in 5.11 are drawn from various filesets 5.20 through
+5.22: the next fileset guaranteed to include all of them is 5.23. Each fix
+is labeled with the 5.2x fileset where it was first included.
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Font resources, unlike all other types of resources, couldn't be
+inherited from an ancestor Page(s) object. (pdf_font.ps) (5.20)
+ - An empty Differences array, which Acrobat Distiller 3.02 can emit,
+caused a rangecheck error. (pdf_font.ps) (5.22)
+
+Library
+-------
+
+Fixes bugs:
+ - When banding, filling a character within the PaintProc of a
+Pattern could produce memory access errors. (The problem was in
+gx_forward_fill_mask, which might affect filling characters in other
+situations as well.) (gdevnfwd.c) (5.23)
+ - When banding, dashed lines could cause an invalid memory access.
+This was apparently caused by an error in a fix made in 5.04. (gsline.c)
+(5.22)
+ - An error in computing the bounding box sometimes caused strokes to
+print incorrectly (for example, some graduated fills printed incorrectly).
+(gxstroke.c) (5.20)
+ - Some images didn't get clipped properly when banding. This was a
+fix for 5.03 that somehow didn't make it into 5.10. (gxclimag.c) (5.22)
+ - A rounding error in computing the size of portrait images could
+produce a spurious 1-pixel-wide line at the edge of the image. (gximage1.c)
+(5.23)
+ - Color-setting operators that "substitute the nearest legal value"
+didn't substitute it in storage, only when using it. E.g., after
+gs_setgray(pgs, 2.0), gs_currentgray(pgs) returned 2.0 rather than 1.0.
+This bug has been there since release 1.0! This release only fixes it for
+setgray, setrgbcolor, and setcmykcolor. (gscolor.c, gscolor1.c) (5.23)
+ - Images with non-zero data_x could cause an invalid memory access.
+(gximage.c, gximage0.c) (5.22)
+ - When banding, if FUTURE was defined, images with singular or
+nearly singular CTM or ImageMatrix could confuse things badly enough to
+cause memory access errors. (gxclimag.c) (5.23)
+
+Adds a multiple-bit-per-pixel analogue of gs_makebitmappattern,
+gs_makepixmappattern, for use by another Aladdin project. (lib.mak,
+gsbitmap.h, gscolor2.h, gxbitmap.h, gspcolor.c) (5.23)
+
+Version 5.10 (11/23/97)
+=======================
+
+This release, not originally planned, greatly reduces the size of PDF files
+produced by the pdfwrite device, fixes a number of minor problems in PDF
+output, and optionally produces output compatible with Acrobat 2.x, in order
+to address problems reported by NSF in processing these files as part of
+their FastLane electronic proposal submission process. Aside from that, and
+some localized bug fixes, it has minimal changes from 5.03.
+
+Known problems:
+ - ps2pdf sometimes produces output with links in an incorrect
+format (k/index.*) or missing or inactive links (k/rahtz/foo.ps).
+ - Setting HWSize by itself with setpagedevice has no effect.
+ - When shrinking oversize halftone cells, the current algorithm,
+which progressively halves the size, can produce non-monotonic behavior; GS
+should either use a monotonic algorithm or give a limitcheck.
+(k/jdscreen.ps)
+ - In Type 1 fonts, almost-vertical lines that straddle a stem edge
+produce uneven output.
+ - flushfile with a procedure-target stream doesn't pass the buffered
+data to the procedure.
+ - At some resolutions, gaps occur in some character outlines with
+certain Type 1 fonts. (? - no test file)
+ - The Watcom MS Windows makefile (watcw32.mak) doesn't work.
+ - The uniprint driver sometimes drops some output, and is very slow
+at 720x720 resolution.
+ - pdf2ps can't handle embedded TrueType and CFF fonts: it produces
+invalid output. (k/tjava8.pdf, p. 192)
+ - pdf2ps can't handle Patterns. (k/nissl.pdf)
+ - pdf2ps can't handle embedded fonts with CharProcs (characters
+defined by PDF objects). (k/be/iguide_unix.pdf)
+ - pdf2ps has other, undefined problems. (k/gfreeman/ps2.*,
+qsshort.*, wallp3.*)
+ - [e]pswrite core-dumps on certain files if GC is enabled. Work
+around this by including -dNOGC on the command line. (k/spong.pdf)
+ - [e]pswrite can't handle Patterns. (k/gfreeman/overpart.ps)
+ - [e]pswrite may produce incorrect line widths for stroked graphics.
+(k/gfreeman/walpart2.ps)
+ - Halftones look relatively coarse: we should be using a small-scale
+version of AccurateScreens (multiple small dot cells with an ordered dither
+cell visiting pattern) to get both fine screens and many levels.
+ - Since the x11alpha device uses saturation to emulate alpha,
+writing anti-aliased objects over dark areas produces incorrect output.
+(gdevxalt.c)
+ - Setting OutputFile=- should redirect stdout to stderr (or provide
+some other way to redirect stdout).
+ - Type 0 (Japanese / Chinese / ...) fonts are not supported in PDF
+files. (k/microw-j.pdf)
+ - Ghostscript can't load TrueType fonts where the amount of data
+either before or after the glyf section exceeds 64K. (k/baueti__.ttf)
+ - Ghostscript can't load TrueType fonts where the total data is more
+than 64K and the offset or length of the glyfs is odd.
+ - High-level output devices ([e]pswrite, pdfwrite, pxl*) always
+produce a single output file rather than a separate file for each page, even
+if there is a %d in the OutputFile name.
+ - ps2pdf doesn't handle the Distiller 3.0 named objects and BP/EP/SP
+pdfmarks. (k/pdfmark3.ps)
+
+Documentation
+-------------
+
+Fixes bugs:
+ - ansihead.mak referred to unix-ansi.mak, which is actually named
+unixansi.mak. (ansihead.mak)
+ - README referred to an "If you need help" section that was moved to
+new-user.txt. (README)
+
+Updates build information for HP-UX systems. (make.txt)
+
+Updates the information for getting Martin Lottermoser's hpdj driver.
+(new-user.txt)
+
+Improves the error message when a user tries to invoke gswin32c without
+explicitly selecting a device. (dwmainc.cpp)
+
+Removes the author's name and e-mail address from the pdf2ps man page, at
+his request. (pdf2ps.1)
+
+Improves the documentation for BandBufferSpace. (language.txt)
+
+Procedures
+----------
+
+Changes the VMS command files so that they don't echo the commands.
+(append_l.com, copy_one.com, rm_all.com, rm_one.com)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The "lp" command files all inappropriately set the top margin to
+0.1". (lp386.bat, lp386r2.bat, lpgs, lpgs.bat, lpr2, lpr2.bat)
+ - The lp386[r2].bat command files inappropriately set the
+LanguageLevel to 1. (lp386.bat, lp386r2.bat)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PDF writer got confused about the current color if the input
+contained text strings separated only by color changes. (gdevpdf.c)
+ - Some casts between const char * and const byte * were incorrect
+(warnings only). (gdevpdft.c)
+
+Adds a NoCancel parameter to the winpr2 device, which suppresses display of
+the dialog box. (gdevwpr2.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - An "extern" was omitted, causing a duplicate definition of
+build_function_procs. (ifunc.h)
+ - The global pseudo-operator table was too small, causing a
+limitcheck in ps2ascii. (iinit.c)
+ - setcolorspace with a Pattern space with no underlying space would
+cause an error if the current color space was a Pattern space. (zpcolor.c)
+ - The Decode key was optional, not required, in the dictionary form
+of image[mask]. (zimage2.c)
+
+Adds two more PCL/PJL reset sequences to the list of sequences to ignore.
+(gs_init.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Multi-screen color halftones could produce "seams". (gxcht.c)
+ - A bug in the gcc optimizer on H-P RISC workstations caused all
+curves to be output as lines. (gxpflat.c)
+ - If a non-standard OtherSubr was called before the [h]sbw in a Type
+1 font, a crash could occur. (gxhint3.c)
+ - gxclist.c didn't include string_.h. (gxclist.c)
+
+Version 5.07(limited) (10/31/97)
+================================
+
+A few more bug fixes for the 5.10 release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Some file and directory names hadn't been updated to match the new
+directory structure on the primary server. (make.txt, new-user.txt)
+
+Adds the URL for reaching URW++. (Fontmap.*)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Because the C % operator isn't equivalent to 'modulus' for
+negative numerators, gx_default_strip_tile_rectangle could crash in some
+cases. (gxdevice.h, gdevdflt.c)
+ - In the PDF writer, Dest values were correct (page numbers) for
+GoToR actions, but were incorrect (should be page object references) for
+other actions; also, Rect values were transformed, but should not be.
+(gdevpdfm.c)
+ - In the PDF writer, articles and bookmarks could attempt to write
+multiple Contents streams, which is not allowed. (gdevpdfx.h, gdevpdf.c,
+gdevpdfm.c)
+ - The PDF writer ignored PS (PostScript pass-through) pdfmarks.
+(gdevpdfm.c)
+ - The PDF writer didn't write out the color space parameters for
+CIE-based spaces. (gdevpdfi.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Suffix subclass structures with 4 added pointers skipped the first
+pointer in the superclass when garbage collecting, possibly causing invalid
+memory accesses. (gsstruct.h)
+ - An argument list incompatibility in a procedure used in a static
+structure initialization upset some compilers. (gsfunc.h, gsfunc0.c)
+
+Version 5.06(limited) (10/7/97)
+===============================
+
+This fixes a few more bugs in the PDF writer, and a few other very obscure
+problems. It also adds support for Functions and brings multiple contexts
+closer to working, neither of which we expect actually to be used any time
+soon. This is intended to be the candidate fileset for the 5.10 release,
+but since we had to tinker with a delicate part of the PDF writer to fix a
+problem affecting visual quality with Acrobat, there may be new bugs that
+will have to be fixed in yet another candidate fileset.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Jim McPherson's e-mail address was out of date. (devices.txt)
+ - Invoking ps2pdf with only a single file name is supported on some
+versions of Windows NT and OS/2, not only on Unix. (ps2pdf.txt)
+ - The ps2pdf documentation didn't indicate that ps2pdf can use the
+Windows "console mode" executable as well as the MS-DOS executable.
+(ps2pdf.txt)
+ - The list of which Distiller parameters actually have an effect was
+incorrect. (gdevpdfp.c)
+
+Notes that the cdj550 driver is compatible with the H-P 660C and 660Cse.
+(devs.mak, devices.txt)
+
+Adds a note about using Acrobat Reader fonts. (install.txt, use.txt)
+
+Notes that the LJ 5P, like the 5L, is not a PCL XL printer. (devs.mak)
+
+Notes problems and possible problems with certain versions of the Borland
+C++ compiler. (make.txt)
+
+Notes the change in -Z:. (use.txt)
+
+Updates the uniprint documentation for this release. (devices.txt)
+
+Expands the rationale for the large resolution in the bbox device.
+(gdevbbox.c)
+
+Notes that the H-P DeskJet 600 series can use the djet500 driver with -r600.
+(devs.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Vector devices didn't include a necessary dependency on the stream
+package. (lib.mak)
+ - There were several bugs in the ps2pdf.bat file. (ps2pdf.bat)
+
+Changes -Z: so it prints some summary lines as well as minimal information
+about banding. This makes the -ZA trace compatible with our memory leak
+tool. (iminst.h, imain.c)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2epsi sometimes produced a too-large bounding box, or even
+caused a rangecheck. (ps2epsi)
+
+At the advice of a user, removes the RESOLUTION=100 line from pv.sh.
+(pv.sh)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PDF writer produced incorrect output for stroke operations
+with unusual CTMs, because PDF, unlike PostScript, applies the CTM to the
+path at the time of the fill or stroke, not as the path is being
+constructed. (gdevpdfd.c)
+ - Vector devices returned an error, instead of falling back to the
+default implementations, when filling or stroking with a pattern.
+(gdevvec.c)
+ - The PDF writer freed an internal stream structure using the wrong
+allocator, possibly causing memory corruption. (gdevpdf.c)
+ - The uniprint driver had some compilation problems, and possibly
+other problems as well (consult the source file). (gdevupd.c, *.upp)
+ - With -dNOCACHE, the PDF writer wrote all text in the base 14 fonts
+twice, once as text and once as outlines. (gs_pdfwr.ps, gdevpdfd.c)
+ - The PDF writer didn't properly recognize Symbol and ZapfDingbats
+as being among the base 14 fonts. (gs_pdfwr.ps)
+ - When using Acrobat Reader with font smoothing turned on, the base
+14 fonts appeared too bold on the screen in files produced by ps2pdf,
+because Reader decides that a 100-unit font at 1 unit = 0.1 point should be
+bolder than a 10-unit font at 1 unit = 1 point. (gdevpdfx.h, gdevpdf.c,
+gdevpdft.c)
+ - The PDF writer didn't convert View/Page specifications for
+bookmark pdfmarks to a Dest key, causing bookmarks not to work.
+(gdevpdfm.c)
+
+Speeds up the PDF writer by only passing the encoding if it isn't
+StandardEncoding. (gs_pdfwr.ps, gdevpdft.c)
+
+Changes the PDF writer's handling of unencoded glyphs. Adds device
+parameters ReEncodeCharacters and ReAssignCharacters to control how
+unencoded glyphs are handled. (These parameters will go away when we handle
+variant encodings in full generality.) (gdevpdfx.h, gdevpdf.c, gdevpdfp.c,
+gdevpdft.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - setpagedevice didn't restore the stack properly if it failed.
+(gs_setpd.ps)
+ - 0 identmatrix didn't cause an error. (gs_init.ps)
+ - Devices expecting array-valued parameters didn't accept packed
+arrays. (iparam.c)
+
+Starts to de-implement support for special handling of the stacks on
+machines with 16:16 addressing. Currently this only happens if DPNEXT is
+defined. (istack.h)
+
+Brings multiple contexts closer to working. The interpreter can now run
+some very simple test cases. (int.mak, icontext.h, igstate.h, interp.h,
+istruct.h, icontext.c, interp.c, zcontext.c, zgstate.c)
+
+Adds support for FunctionType 0 Functions, which are used in PDF 1.2.
+(ifunc.h, iref.h, store.h, zfunc.c, zfunc0.c)
+
+Updates a few remaining pseudo-operators in gs_init.ps to take advantage of
+automatic operand and dictionary stack restoration: eexec, identmatrix,
+pathbbox. Not updated yet: filter. (gs_init.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Separation color spaces weren't supported. (gs_pdf.ps,
+pdf_draw.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The size argument to gs_free was wrong in an out-of-memory case.
+(This was irrelevant, since gs_free only uses the size argument for
+error-checking during debugging.) (gdevprn.c)
+ - When freeing a block on the C heap, if -Z@ was set, the block's
+header wasn't filled with the sentinel pattern. (Only relevant when
+debugging.) (gsmemory.c)
+ - The C heap allocator didn't fix up pointers properly when freeing
+a block, causing unpredictable memory corruption after a 'resize' call.
+(gsmemory.c)
+ - Using a show operator inside the procedure of a cshow with a
+composite font could cause an invalid access. (gschar.c)
+
+Adds support for FunctionType 0 Functions. (gsdsrc.h, gsfunc.h, gsfunc0.h,
+gxfunc.h, gsdsrc.c, gsfunc.c, gsfunc0.c)
+
+Moves the GC descriptor for arrays of constant strings to a place where it
+is more visible. (gscie.h, gsstruct.h, gscie.c, gsmemory.c)
+
+Version 5.05(limited) (9/24/97)
+===============================
+
+This fixes a few bugs found in the first few days of testing 5.04. There
+will probably be several more small incremental filesets before the next
+public release.
+
+Platforms
+---------
+
+Fixes bugs:
+ - The Windows code wouldn't compile with the latest MSVC++, because
+Microsoft changed the prototype for fprintf. (gp_msio.c)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A picky compiler complained about some omitted casts. (gdevpdf.c,
+gdevpdft.c)
+ - Writing a PDF file with any synthesized fonts could produce
+slightly garbled output or possibly even an invalid memory access, because a
+string was not terminated. (gdevpdft.c)
+ - When writing a PDF file, the first character of a string could get
+placed off the page, because of a matrix bookkeeping error. (gdevpdft.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - In case of an error, setpagedevice executed a 'stop'
+unconditionally, rather than just signalling an error through the error
+machinery. (gs_setpd.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Files with unknown operators caused errors, even if the BX
+operator was used to disable the error report. (pdf_base.ps)
+
+Version 5.04(limited) (9/21/97)
+===============================
+
+This is the first test fileset for the 5.10 release: see above.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - George Cameron's address was listed with a domain of .ukis rather
+than .uk. (devices.txt)
+ - The default value of ORIENT1 was given as false rather than true.
+(use.txt)
+ - The documentation for ps2pdf said one can omit the output file
+name, but this is only true on Unix systems. (ps2pdf.txt)
+ - The documentation for ps2pdf didn't make clear that the executable
+must be named gs on Microsoft OSs. (ps2pdf.txt)
+ - ht_cache is actually allocated with the first gstate, not on
+demand. (gsstate.c)
+
+Slightly improves the documentation of .type1execchar. (zchar1.c)
+
+Clarifies the distinction between Ghostscript (PostScript) commands and
+shell commands, for the benefit of users brainwashed by Microsoft.
+(use.txt)
+
+Improves the usage synopsis in the ps2epsi man page. (ps2epsi.1)
+
+Adds a reference to Uli Wortmann's H-P drivers. (new-user.txt)
+
+Improves the documentation of GS_FONTPATH, distinguishing it from GS_LIB and
+the search path. (use.txt)
+
+Notes that on some systems, one must substitute 'installbsd' for 'install'
+in the makefile and make other edits. (install.txt, ansihead.mak,
+cc-head.mak, gcc-head.mak)
+
+Notes that ps2epsi is no longer maintained. (ps2epsi.ps)
+
+Clarifies the availability of support. (new-user.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The uniprint driver was accidentally omitted from the default
+Watcom (MS-DOS) and OS/2 configurations. (watc.mak, os2.mak)
+ - The suggested compiler switches for Digital Unix were incorrect.
+(make.txt)
+ - The cp.cmd script file didn't work in the newest versions of OS/2.
+(cp.cmd)
+ - The compilation rules for some Windows-specific files didn't
+include ccf32.tr in their dependencies, which could cause the compilation to
+fail. (winint.mak)
+
+Removes the lev2min configuration, since we no longer support 16-bit Windows
+environments. (int.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2epsi.bat always appended to the output file, rather than
+writing over it. (There are probably other bugs in this script file.)
+(ps2epsi.bat)
+ - The output of pdf2ps didn't execute properly on some printers,
+especially Level 1 printers. (gs_pdf.ps)
+
+Makes ps2pdf do an initial 'save', which causes fonts to be retained better
+across pages. (ps2pdf, ps2pdf.bat)
+
+Adds an option to pcharstr.ps to produce C-like rather than PostScript-like
+output. (pcharstr.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The LaserJet III and higher printers weren't able to print in the
+narrow strip between 1/6" and 1/4" from the left edge of the page.
+(gdevdjet.c)
+ - The PCL XL drivers produced incorrect output which often caused a
+PCL XL NoCurrentFont error at the beginning of the second page. (gdevpx.c)
+ - The GC descriptors for the pswrite device and for PS/PDF devices
+were incorrect, causing the GC to smash memory. (gdevpsdf.h, gdevps.c)
+ - The pdfwrite device didn't have a GC descriptor at all. ******
+DISABLED because the device allocates all its temporary structures directly
+on the C heap. ****** (gdevpdf.c)
+ - When the PDF writer wrote out the Dest key in an action
+dictionary, it always used a page object instead of a page number, even if
+the page was in another file or didn't exist; it now always uses a page
+number. (gdevpdfm.c)
+ - The PDF writer gave an error if a file redefined any of the 14
+known fonts. (gs_pdfwr.ps)
+ - The PDF writer didn't handle copy_mono with a non-zero sourcex.
+(This probably had no effect in practice.) (gdevpdfi.c)
+
+Splits off gdevpdfd.c (driver drawing procedures) from gdevpdf.c, since the
+file was getting too large. (gdevpdfx.h, gdevpdf.c, gdevpdfd.c)
+
+Adds recognition of the CompressPages, CompatibilityLevel, and
+UseFlateCompression device (distiller) parameters to the PDF writer. If
+CompressPages is true (default), CompatibilityLevel is 1.2 (default), and
+UseFlateCompression is true (default), page contents will be compressed with
+Flate ("zip") compression; otherwise, they will not be compressed.
+
+Restructures the PDF writer to produce much smaller and faster PDF files, by
+restructuring its handling of text to defer all resources to the end of the
+file, eliminate duplicate Font resources, turn characters into Type 3 fonts
+rather than Image XObjects, use more efficient text positioning commands,
+and optionally (but by default) Flate-compress the contents streams. Also
+removes some unnecessary spaces in the output. (gdevpdfx.h, gdevpdf.c,
+gdevpdfd.c, gdevpdfi.c, gdevpdfm.c, gdevpdft.c)
+
+Improves the PDF writer so that it no longer converts stroke operations with
+non-uniform CTMs to fills, and doesn't bother to stroke empty paths at all.
+(gdevpdfd.c)
+
+Speeds up the "alternate" X devices substantially. (gdevxalt.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Filling a string with a Pattern caused a crash with the PDF
+writer. (gs_pdfwr.ps)
+ - Converting a file with no marks at all to PDF produced invalid
+output. (gdevpdf.c)
+ - .endpage, which is called at the end of every page, sometimes left
+2 extra values on the stack. (gs_setpd.ps)
+ - A definefont with a Type 1 font lacking a .notdef character didn't
+cause an invalidfont error. (bfont.h, zfont1.c, zfont2.c)
+ - On anti-aliased devices, characters from Type 1 fonts with an
+incorrect or missing FontBBox came out a factor of 2 or 4 too small if the
+character was small enough to cache. (zchar1.c)
+ - If a file redefined certain operators, loading Type 1 fonts could
+fail. This problem was fixed in an earlier release, and somehow the fix got
+undone. (gs_type1.ps)
+ - cshow didn't set the correct current font when running the
+procedure, and didn't restore it properly afterwards. (zchar.c, zchar2.c)
+ - With certain compilers, the interpreter loop caused unaligned
+memory accesses on DEC Alpha systems running Windows NT. (iref.h)
+
+Adds freelist validation to the memory checker. (ilocate.c)
+
+Changes the debugging switch for bypassing the garbage collector from
+compile-time to run-time. (igc.c)
+
+Adds the real operators for view clipping (but they don't do anything yet,
+because view clipping isn't implemented at the library level). (zdps.c,
+zvmem.c)
+
+Completes the implementation of defineusername. (zdps.c)
+
+Adds an implementation of wtranslation, by simply reading a device parameter
+of the same name. (gs_dps.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Lab color spaces weren't implemented, and gave an error.
+(gs_pdf.ps)
+ - Images only worked with built-in color spaces, not color space
+resources. (pdf_draw.ps)
+ - Embedded font subsets were treated as undefined. (pdf_font.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - strokepath sometimes clipped the path to the current clipping
+region, which it should never do. (gxstroke.c)
+ - The initial X/Y position for Type 2 charstrings (CFFs) sometimes
+was set incorrectly. (gstype2.c)
+ - Memory management for dash patterns was still incorrect (despite
+the fix in 4.36), possibly causing snarled freelists and invalid memory
+references. (gsline.c, gsstate.c)
+ - The saved gstate of a Pattern instance was freed properly when the
+instance was freed by reference counting as a result of setting the color or
+color space, but not when the instance was freed by reference counting
+anywhere else. (gspcolor.c)
+ - A test for whether to use a slower form of oversampling was
+incorrect. (Probably only a performance bug.) (gschar.c)
+ - cshow didn't set the correct current font when running the
+procedure, and didn't restore it properly afterwards. (gsfont.h, gschar.c,
+gsfont.c)
+
+Improves allocator validity checking when DEBUG is set. (gsalloc.c)
+
+Adds a couple of missing FontType values. (gxftype.h)
+
+Changes the default conversions between CMYK and RGB colors back to the
+Adobe rules documented in the Red Book, to reduce output differences from
+Adobe implementations. (gxdcconv.c)
+
+Adds a graphics state element for view clipping, under an #ifdef DPNEXT, and
+implementations of the view clipping operators (but not the logic for doing
+the actual clipping). (gsstate.h, gzstate.h, gsstate.c)
+
+Removes the redundant clip_rule variable from the graphics state (which
+wasn't used for anything). (gzstate.h, gspath.c)
+
+Version 5.03 (8/8/97)
+=====================
+
+The only reason for this release is to fix two serious bugs introduced
+between 5.01 and 5.02. We fixed a few other very localized and low-risk
+bugs at the same time.
+
+Documentation
+-------------
+
+Removes the "(if relevant)" from the bug reporting form, since about 25% of
+the forms are submitted without a URL or any other data. (bug-form.txt)
+
+Adds a discussion of single-use procedures to the style guide.
+(c-style.txt)
+
+Updates the information about obtaining Ghostscript on physical media.
+(new-user.txt)
+
+Updates the information about ps_view. (new-user.txt)
+
+Procedures
+----------
+
+Adds the uniprint driver to all platforms. (*.mak)
+
+Changes the contents of the pc.tar.gz archives:
+ - Adds *.upp.
+ - Removes *.res.
+ - Removes cp.bat, font2c.bat, mv.bat, rm.bat, wmakebat.bat,
+ cp.cmd, mv.cmd and rm.cmd, and gv-vms.hlp.
+
+Removes an obsolete script file. (tar_mv)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The uniprint driver didn't handle an increase in media height
+correctly. (gdevupd.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Printing to printers other than LPT1 under MS Windows no longer
+worked. (bug introduced in 5.02) (gp_mswin.c)
+ - Drag-and-drop didn't work under Windows NT (or other 32-bit
+Windows environments). (dwtext.cpp)
+ - Sequent systems needed an additional system header file.
+(time_.h)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The substitutions Myriad => Times and Minion => Helvetica were
+incorrect; they should be the other way around. (gs_fonts.ps)
+ - MyriadPkg wasn't recognized as a condensed font. (gs_fonts.ps)
+ - Univers wasn't recognized as mapping to Helvetica. (gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A line of debugging code, printing the sections of 3 regions of
+TrueType fonts being loaded, was accidentally left in. (gs_ttf.ps)
+ - TrueType fonts whose pre-glyf data had odd length were broken
+(typically gave a rangecheck error), because of the fix to treat the odd
+byte of individual sfnts strings as padding per Adobe documentation. (bug
+introduced in 5.02) (gs_ttf.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - If a real-number token in a CFF had an even number of nibbles, a
+unmatchedmark error would occur. (gs_cff.ps)
+ - If the strings Index in a CFF included an empty string, a
+rangecheck error would occur. (gs_cff.ps)
+ - CFFs with non-standard Encodings that included standard strings
+would get a typecheck error. (gs_cff.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Using %d in an OutputFile name didn't substitute the page number.
+(bug introduced in 5.02) (gsdevice.c)
+ - In Type 2 CharStrings, if a hintmask occurred at the beginning, it
+wasn't recognized as also incorporating the function of vstemhm.
+(gstype2.c)
+ - The data bytes for hintmask and cntrmask weren't printed for
+debugging. (gstype2.c)
+
+Version 5.02 (7/28/97)
+======================
+
+Because of an ISP failure that delayed the 5.0 announcement for 12 days, the
+5.01 release only responded to a few days of bug reports; 5.02 fixes some
+problems that should have been fixed in 5.01, as well as a large number of
+obscure problems uncovered by Genoa testing.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The documentation for building on the Intergraph Clipper was out
+of date. (make.txt)
+ - ESC was claimed to be a self-delimiting character. (gs_init.ps)
+ - Removes the documentation claiming that ^D and ^Z are
+self-delimiting. (language.txt)
+ - Document that -dSUBSTFONT doesn't create a font with the requested
+font name. (use.txt)
+ - Ghostscript was defined as compatible with PDF 1.1 rather than PDF
+1.2. (language.txt)
+ - The description of gcc problems on Alpha didn't make it clear that
+the use of gcc was optional, not required. (make.txt)
+ - The description of how to use GNU make on VMS systems was
+inaccurate. (make.txt)
+
+Improves the documentation for building on H-P RISC systems. (make.txt)
+
+Corrects the discussion of Cygnus' licensing terms for the cygwin32
+environment. (make.txt)
+
+Removes the apology for the poor quality of Ghostscript's TrueType
+rasterizer, since the quality is now quite good. (fonts.txt)
+
+Documents the fact that one must use # rather than = with Watcom C.
+(use.txt)
+
+Documents the updates and additions to the uniprint driver. (devices.txt)
+
+Adds some material to Aladdin's C style guide. (c-style.txt)
+
+Documents the fact that using gmake requires VMS 6.2 or later on Alphas and
+7.1 (perhaps 7.0) or later on VAXen. (make.txt)
+
+Adds an example EPS file. (psfiles.txt)
+
+Adds some information about compiling and linking under OS/2. (make.txt)
+
+Expands the description of XLIBDIR and XLIBDIRS. (*head.mak)
+
+Adds a new pointer to information on using a Kanji font with Ghostscript.
+(new-user.txt)
+
+Documents the use of /Resource/<category>/<resource> as the default place
+where resources are sought. (use.txt)
+
+Updates the documentation on building with MSVC++ to reflect the makefile
+changes. (make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - In openvms.mak, several ifdef tests were wrong. (openvms.mak)
+ - One CP command was slightly inconsistent with the others.
+(zlib.mak)
+ - If libz and libpng were both shared, libz was linked first,
+resulting in some undefined references. (libpng.mak)
+ - The VMS makefile didn't interact properly with VMS's version
+numbering facility. (copy_one.com)
+
+Updates the VMS DCL script one last time, to handle libpng version 96.
+(vms.mak)
+
+Restructures the MSVC++ makefiles to allow building the graphics library
+without the PostScript interpreter. (bcwin32.mak, msvc4.mak[deleted],
+msvc5.mak[deleted], msvc32.mak, msvccom.mak, watcw32.mak,
+wincom.mak[deleted], winint.mak, winlib.mak)
+
+Adds a makefile to create a library-only demo program under MSVC++, like the
+ones for Unix/gcc and MS-DOS/Watcom. (msvclib.mak)
+
+Adds an example EPS file. (ridt91.eps, unix-end.mak)
+
+Removes support for libpng release 0.88, which is now quite obsolete.
+(libpng.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - ps2pdf.bat, unlike ps2pdf, didn't accept options. (ps2pdf.bat)
+ - echogs used 'const' in one place, which wasn't accepted by some
+very old compilers. (echogs.c)
+ - pdf2ps output Orientation, which it shouldn't. (pdf_main.ps)
+
+Makes the usage message from ps2pdf.bat include the options, like ps2pdf.
+(ps2pdf.bat)
+
+Changes the printpath utility so that its output is legal PostScript code.
+(ppath.ps)
+
+Makes pdf2dsc add DSC comments for the bounding box (if a CropBox is
+available in the PDF file) and the orientation. (pdf2dsc.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The get_bits operation wasn't implemented for the vgalib driver.
+(gdevvglb.c)
+ - The dnj650c driver output an extra % near the end of the file.
+(gdevcdj.c)
+ - The definition of pprintd2 didn't have a line break before the
+procedure name, confusing ansi2knr. (gdevpstr.c)
+ - EPS files produced invalid PDF output. (gdevpdf.c)
+ - "Vector" output devices didn't recognize %d in output file names,
+or - for output to stdout. (gdevprn.h, gxdevice.h, gdevprn.c, gdevvec.c,
+gsdevice.c)
+ - With the pdfwrite driver, restore or grestore would cause a
+rangecheck error in .installpagedevice if a setpagedevice had been executed.
+(gdevpdfp.c)
+ - The pdfwrite driver produced garbage output for text rotated by
+angles that were only infinitesimally different from multiples of 90
+degrees. (gdevpdft.c)
+ - The pnm[raw] driver didn't handle anti-aliasing properly.
+(gdevpbm.c)
+ - The PDF writer didn't scale the parameters for [a][width]show
+correctly. (gs_pdfwr.ps, gdevpdft.c)
+
+Fixes some minor compilation warnings not affecting code functionality.
+(gdevbbox.c, gdevpdfm.c, gshtscr.c, gsmemory.c, gxccman.c, gxfill.c,
+gximage0.c)
+
+Fixes some bugs in the uniprint driver and adds some more printer models.
+(gdevupd.c, bjc610a*.upp, bjc610b*.upp, necp2x6.upp, stc1520h.upp)
+
+Makes a small change for clean compilation on BeOS. (gdevcdj.c)
+
+Updates the PNG driver to use updated API calls for allocating/initializing
+and freeing the PNG structures. (gdevpng.c)
+
+Platforms
+---------
+
+Refactors the MS Windows code to allow building the library without the
+interpreter. (gs_msio.c, gs_mslib.c, gp_mswin.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - definefont was executed twice on TrueType fonts. (No bad
+consequences, just unnecessary work.) (gs_ttf.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The fix for the 'stopped' around run_string_* in 5.01 was made
+incorrectly. (gs_init.ps)
+ - Many operators that expect a matrix operand didn't accept packed
+arrays. (iutil.c)
+ - The default CRD didn't have an explicit BlackPoint, which some
+Genoa tests require. (gs_lev2.ps)
+ - A stack protection fix caused setscreen and setcolorscreen with
+dictionary operands to give a typecheck. (gs_dps2.ps)
+ - Executing a string didn't handle tail recursion properly if the
+last token was followed by a single whitespace character. (interp.c)
+ - Clearing the error indication didn't set errorname to null.
+(gs_init.ps)
+ - Some unexpected items appeared on the execution stack, confusing
+some of the Genoa tests. (gs_init.ps, istack.h, istack.c, zcontrol.c)
+ - The dummy definitions for setucacheparams/ucachestatus didn't look
+enough like the real ones. (gs_dps2.ps)
+ - Insideness tests didn't work, because the hit detection device
+width and height weren't set up. (zupath.c)
+ - defineuserobject didn't use the same algorithm for growing the
+array as Adobe interpreters. (gs_dps2.ps)
+ - eq and ne didn't work correctly on save objects. (iutil.c)
+ - findfont used =string internally, interfering with PostScript
+programs that also used it. (gs_fonts.ps)
+ - cshow didn't set up scaled versions of base fonts as the current
+font. (zchar2.c)
+ - defineresource didn't make the resource value read-only.
+(gs_res.ps)
+ - If inustroke got an error, it could return without an error
+indication and without changing the stack. (zupath.c)
+ - The arrays returned by different invocations of currentcolorspace
+with the same device color space weren't guaranteed to be eq. (gs_lev2.ps)
+ - Out-of-range integers followed by a '.' were converted to names
+rather than reals. (iscan.c, iscannum.c)
+ - resourceforall caused an invalidaccess error if currentglobal was
+true but the procedure, template, or scratch string was in local VM.
+(gs_res.ps)
+ - In many places, integer values were converted to floats rather
+than doubles, losing precision. (ichar.h, icharout.h, ifont.h, iutil.h,
+idparam.c, iparam.c, iutil.c, zchar.c, zchar1.c, zchar42.c, zcharout.c,
+zcie.c, zcolor.c, zcolor1.c, zcolor2.c, zcontrol.c, zcsindex.c, zcssepr.c,
+zdpnext.c, zdps1.c, zfont.c, zfont2.c, zgstate.c, zhsb.c, zht.c, zmath.c,
+zmatrix.c, zmedia2.c, zpath.c, zpath1.c, zupath.c)
+ - The TransformPQR procedure in the default CRD didn't pop its
+auxiliary operands from the stack. (gs_lev2.ps)
+ - Because of an incorrect stack depth check, setcolorrendering
+sometimes produced a stackunderflow. (zcrd.c)
+ - sethalftone caused an invalidaccess error if the HalfTone type was
+not 5, the dictionary was in local VM, and the current VM was global.
+(gs_dps2.ps)
+ - writeobject and printobject caused an invalidaccess error if the
+object being written was in local VM and the current VM was global.
+(gs_btokn.ps)
+ - ustrokepath appended the strokepath segments to the current path,
+rather than replacing the path. (zupath.c)
+ - restore incorrectly purged from the character cache any characters
+in a font being freed, even if the font had a UID. (zfont.c)
+ - The definition of zimage_opaque_setup confused ansi2knr.
+(zimage.c)
+ - Type 42 fonts that included the padding byte in each sfnts string
+didn't work if sfnts had more than one string. (zfont42.c)
+ - Doing a garbage collection at the same time as handling a
+stackoverflow failed to update the object that needed re-execution, causing
+the interpreter to execute random data. (interp.c)
+ - %stdout and %stderr weren't flushed if they were closed
+explicitly. (ziodev.c)
+
+For greater Adobe compatibility:
+ - Changes setdash to limit dash patterns to 11 elements. (This is
+enforced at the PostScript level: the graphics library doesn't have a
+limit.) (gs_init.ps)
+ - Changes ^D and ^Z so they are not self-delimiting characters, and
+changes ^K so it is not a whitespace character. (gs_init.ps, iscan.c,
+scantab.c)
+ - Makes = cause an error on non-read-accessible objects rather than
+printing them as --nostringval--. (gs_init.ps)
+ - When -dSUBSTFONT= is used, makes findfont return the actual named
+font, rather than a copy with the FontName changed to the requested one.
+(gs_fonts.ps)
+ - CFF fonts with a non-default FontMatrix caused an error.
+(gs_cff.ps)
+
+Fixes some minor compilation warnings not affecting code functionality.
+(iparam.c, zfcmap.c)
+
+Strengthens the test of o-stack validity in the main interpreter loop in
+debug mode. (interp.c)
+
+Changes the filling rule for Type 1 fonts from winding-number to even-odd.
+This affects no properly designed fonts, and seems to match Adobe
+interpreters better. (zchar1.c)
+
+Implements non-standard Encodings in CFF fonts. (gs_cff.ps)
+
+Changes the default halftone screen for 600 dpi printers from 85 to 106 lpi,
+which reduces the number of halftone levels from 50 to 32 but produces
+visually better output. (gs_init.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Pattern color spaces weren't supported. (gs_pdf.ps, pdf_draw.ps)
+
+Causes references to undefined named Destinations to be ignored rather than
+giving an error. (pdf_main.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - A 'const' was omitted in a declaration, upsetting several
+compilers. (gxclread.c)
+ - arct and arcto gave an error for negative radii. (gspath1.c)
+ - The collinearity check for arct[o] could cause some arcs to be
+rendered as single points. (gspath1.c)
+ - Uncolored patterns sometimes came out blank, because the color
+wasn't set before calling the PaintProc. (gspcolor.c)
+ - The phase for masking colored patterns was wrong, producing
+incorrect output. (gspcolor.c)
+ - reversepath always appended the current position to the new path,
+rather than only doing so if the path just consisted of a single moveto.
+(gxpath2.c)
+ - cshow didn't restore the current font properly. (gschar.h,
+gschar.c)
+ - The check for whether characters can be cached didn't consider
+PaintType values other than 0 and 2. (gschar.c)
+ - The bounding box device didn't handle PageCount properly.
+(gdevbbox.c)
+ - Uncached fonts with a next_char procedure didn't set the glyph
+properly. (gschar.c)
+ - Parallelograms with ax < bx, ay < by, and the 'a' edge to the
+right of the 'b' edge weren't filled, causing pixels to be omitted from some
+highly skewed images. (gdevddrw.c)
+ - 12-bit-per-pixel images in portrait orientation filled each scan
+line with the value of the last pixel -- i.e., didn't work. (gximage4.c)
+ - The path representation of a clipping path could include some
+inappropriate, leftover path segments. (gxcpath.c)
+ - The angle for the miter check was computed in device space rather
+than in user space. (gxstroke.c)
+ - TrueType fonts were lumpy, and the accents of accented characters
+were placed incorrectly. (gstype42.c)
+ - Some macros used for generating device prototypes didn't
+parenthesize all uses of their parameters, causing possible errors if the
+parameters were expressions rather than numeric constants. (gdevprn.h)
+ - When banding, strip halftones (typically produced by
+AccurateScreens) sometimes didn't have the correct phase. (gxbitmap.h,
+gxclread.c)
+ - A minor change was required for correct compilation with Microsoft
+VC++. (memory_.h)
+ - Under certain conditions, character shapes could get wildly
+distorted by hints. (bug introduced in 5.01) (gxhint3.c)
+
+For greater Adobe compatibility:
+ - Changes reversepath so that the implicit line created by closepath
+is not considered a "segment". (gxpath2.c)
+
+Fixes some minor compilation warnings not affecting code functionality.
+(gstype1.c)
+
+Changes the font and scaled-font caches so that if the font has a UID
+(UniqueID or XUID), the UID and FontType are both considered part of the
+key, and we don't cache fonts with non-zero PaintType. (The Red Book says
+that changing anything except the Encoding should also change or remove the
+UID, but some files don't do this. The current fix is probably not
+sufficient, but it is a step in the right direction.) (gxfcache.h,
+gxccache.c, gxccman.c)
+
+Splits off the definitions of font_type and fbit_type into a separate file,
+since gxfcache.h now needs font_type. (gxfcache.h, gxfont.h, gxftype.h)
+
+Makes the Flex feature in Type 1 fonts conform to the published
+specification, rather than always producing curves. The comment in the code
+(and in the NEWS entry for release 2.6) says that this breaks some very old
+Adobe fonts: if this turns out to be a problem, we'll figure out a test that
+will do the right thing for these fonts. (gstype1.c)
+
+Provides 'double' versions of some API functions to accommodate the
+increased use of doubles in the interpreter. (gschar.h, gschar.c)
+
+Adds a compile-time option to force the use of strip halftones, for
+debugging. (gshtscr.c)
+
+Changes the hint snapping algorithm in the Type 1 rasterizer so that it will
+only change a stem width by a maximum of 1/2 pixel rather than 1 pixel.
+This appears to help with dropouts at certain sizes. (gxhint2.c)
+
+Makes a few changes for clean compilation on BeOS. (stdpre.h, stat_.h,
+gxcpath.c)
+
+Version 5.01 (6/22/97)
+======================
+
+This fixes a few bugs reported in the 5.0 release. This will be a
+commercially supported release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - README referred to an obsolete file devarch.txt. (README)
+ - The comment on flip4x12 had a typo. (gsflip.c)
+ - The algorithm comments for adjusted_y_spans_pixel weren't precise
+enough. (gxfill.c)
+ - The usage message printed by the ps2pdf script didn't indicate
+that one can now insert options before the input file name. (ps2pdf)
+ - The file searching documentation didn't indicate that paths
+beginning with ./ or ../ are considered "explicit" and not subject to
+searching. (use.txt)
+ - The description of SEARCH_HERE_FIRST in the per-platform makefiles
+indicated that it only applied to initialization files, not to files
+specified on the command line as well. (*.mak)
+ - There were still some references to 16-bit implementations.
+(install.txt)
+
+Clarifies that -dNODISPLAY also suppresses output to other devices.
+(use.txt)
+
+Adds the e-mail address for reporting problems to the bug report form, and
+also a space to report makefile changes. (bug-form.txt)
+
+Adds a note under -g indicating that it fixes the media size. (use.txt)
+
+Adds an explanation of why Ghostscript can't use the system libraries for
+the JPEG package. (make.txt)
+
+Notes that ps2ai doesn't work properly with Adobe's Helvetica-Oblique font,
+and other fonts whose original FontMatrix involves skewing or rotation.
+(psfiles.txt)
+
+Updates the uniprint documentation slightly. (devices.txt)
+
+Notes that the new lj5 drivers do not work with the LJ5L. (devs.mak)
+
+Modifies the Aladdin Free Public License slightly to make it clearer that
+the exception for freely redistributable CD-ROMs only applies if the CD-ROM
+is being distributed by itself, not with anything else commercial. (This
+has always been the case, but the previous wording wasn't clear enough.)
+(PUBLIC)
+
+Notes that gcc with -O still has code generation problems on H-P RISC
+machines. (make.txt)
+
+Adds a pointer to Martin Lottermoser's hpdj driver. (new-user.txt)
+
+Enhances and reorganizes the documentation for building Ghostscript, in
+response to user feedback. (make.txt, install.txt)
+
+Adds a description of the EPSF recognition feature. (language.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - string__h was misspelled string_h in one place. (lib.mak)
+ - gs_dps.ps wasn't installed by "make install". (unix-end.mak)
+ - ccgs (used with non-ANSI C compilers) didn't do the right thing
+with -DPNG_USE_CONST. (ccgs)
+
+Adds support for version 96 of libpng, and updates all the makefiles to
+reference it. (libpng.mak, *.mak)
+
+Updates the MSVC makefiles to get rid of some warning messages and provide a
+way to specify a library path for the final link. (msvc*.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The usage message for the gslp utility had a minor typo.
+(gslp.ps)
+ - The "line printer" utility didn't expand tabs properly when
+producing PostScript output. (gslp.ps)
+ - The gslp utility didn't automatically include the date. (gslp)
+ - The line printer scripts didn't pass the script name to the
+utility program, so the usage message didn't use the correct name. (gsbj*,
+gsdj*, gslj*, gslp*, lp*)
+
+Modifies the gslp utility so that invoking it with no arguments prints the
+usage message. (gslp.ps)
+
+Adds the ability to specify the number of bits per component to the
+CMYK-viewing utility. (viewcmyk.ps)
+
+Changes the ps2pdf script so that on Windows NT, as on Unix, it allows
+omitting the output file name, automatically replacing the extension of the
+input file with .pdf. (ps2pdf.bat)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Some compilers didn't accept a #define with the macro name on the
+next line. (gdevpx.c)
+ - The procedure dash_pattern_eq was defined in two places.
+(gdevpdf.c)
+ - The uniprint driver sometimes dropped some output or got confused,
+because of a misunderstanding about how to update device procedure vectors
+properly. (gdevupd.c)
+ - The PostScript and EPS writers produced binary output for images,
+which generally can't be sent to PostScript printers. (gdevpsdf.h,
+gdevpdf.c, gdevps.c)
+ - The EPS writer put a %%EOF at the end of the file, which might
+cause problems for some spoolers if the file is embedded in another.
+(gdevps.c)
+
+Changes the implementation of printer drivers so that they flush the output
+stream after each page. We aren't absolutely sure that this is a good idea,
+but it prevents certain anomalous behavior where the last page isn't ejected
+properly. (gdevprn.c)
+
+Implements a long-delayed update to the mgr drivers, to restore the color
+mapping to an older one. (gdevmgr.h, gdevmgr.c)
+
+Updates the uniprint driver with a number of changes from its author.
+(gdevupd.c)
+
+Platforms
+---------
+
+Adds the JPEG, Postscript, and PCL XL drivers, which are included on all
+other platforms, to the MS Windows platforms. (bcwin32.mak, msvc4.mak,
+msvc5.mak, watcw32.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - composefont defined the resource with the font name and font
+directory interchanged. (gs_cmap.ps)
+ - With dFIXEDMEDIA, documents requesting other sizes caused an error
+instead of clipping the page. (gs_init.ps)
+ - PageSize Policy = 7 wasn't implemented. (However, the current
+implementation is wrong.) (gs_setpd.ps, zmedia2.c)
+ - FontType resource 42 wasn't defined even if Type 42 fonts were
+supported; similarly for FontType 9, 10, and 11 for CIDFonts. (gs_cidfn.ps,
+gs_res.ps)
+ - The error handling machinery would break if the name /errordict
+was redefined. (gs_init.ps)
+ - Level 1 systems got an /undefined in .doneshowpage. (zdevice.c,
+zdevice2.c)
+ - Because of an initialization order problem, copy didn't work on
+gstates. (zgeneric.c)
+
+Adds a naive implementation of findcolorrendering. (gs_lev2.ps, gs_res.ps)
+
+Removes the 'stopped' around run_string[_begin/continue/end] so that, as in
+4.03, errors print a hex dump and exit with a non-zero code instead of
+printing a readable message and continuing. (We aren't sure that this
+change didn't undo the fix in 5.0 regarding calling startjob from
+run_string.) (gs_init.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - stdin redirection failed for PDF files even if the new stdin was
+seekable. This was fixed in 4.02, but the fix stopped working with the
+introduction of .runexec. (pdf_main.ps)
+
+Makes the cross-reference reader accept a startxref value that points at the
+EOL before the xref line. The Adobe documentation doesn't allow this, but
+some real files are this way. (pdf_main.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The bounding box of a completely empty path was reported as
+garbage. (gxpath2.c)
+ - Stroking a path with more than one segment didn't produce correct
+output when anti-aliasing was used. (gspaint.c)
+ - The alpha-buffer device returned an incorrect clipping box,
+causing output to be discarded. (gdevabuf.c)
+ - gx_forward_get_clipping_box passed the wrong device to the target
+procedure, producing incorrect results. (gdevnfwd.c)
+ - The sin/cos procedure did some unnecessary computations
+(performance bug only). (gsmisc.c)
+ - The procedure for adjusting the ends of curves to match the
+tangents did some unnecessary computations (performance bug only).
+(gxpcopy.c)
+ - RAM-based banding always gave an invalidfileaccess error, due to a
+typo in memfile_fopen. (gxclmem.c)
+ - The algorithms for deciding whether a line is thin still weren't
+correct. (gxstroke.c)
+ - The fill adjustment values for the any-part-of-pixel case (adjust
+= 0.5) were (0.5-epsilon, 0.5+epsilon), which colored inappropriate
+additional pixels if the higher coordinate was integral. With considerable
+trepidation, we have changed this to (0.5-epsilon,0.5), which does the right
+thing in every case we can think of. (gxfill.c)
+ - When banding, paths were clipped to only 0.5 pixel outside their
+bounding box, which may be slightly too conservative; 1 pixel is safer.
+(gxclpath.c)
+ - The algorithm for testing whether an adjusted Y value spanned a
+pixel center was incorrect, causing some pixels to get colored incorrectly.
+(gxfill.c)
+ - 24-bit devices could cause a memory fault, by accessing a pointer
+just beyond the end of the line pointer array. (gdevm24.c)
+ - Astonishingly enough, the determination of which hints were
+applicable to a given segment of a Type 1 character was wrong in several
+different places. Fixing this in a way that correctly handled all allowed
+permutations of the coordinate system was not simple. (gxfont1.h,
+gxhint1.c, gxhint3.c)
+ - The debugging printout macros didn't include the syntactic hack to
+prevent an 'else' from begin assigned to the wrong 'if'. (gdebug.h)
+ - The bbox device was accidentally limited to 130 x 130 pixels (not
+130" x 130"). (bug introduced in 5.0) (gdevbbox.c)
+ - The bbox device didn't recognize PageBoundingBox in put_params,
+causing a possible /undefined error on [g]restore. (gdevbbox.c)
+ - setlinewidth didn't take the absolute value of its operand.
+(zgstate.c)
+ - Some code formatting was slightly off. (gximage5.c)
+ - Some extra pixels were written for Interpolated images, but they
+were immediately overwritten, so the output was correct. (gximage5.c)
+
+Changes the data flipping API from a macro to a procedure, adds a return
+value, and makes the individual flipping procedures private. (gsflip.h,
+gsflip.c)
+
+Adds (under an #ifdef FUTURE) code to allow passing multi-plane images
+through the band list. (gxclpath.h, gxclimag.c, gxclread.c)
+
+Adds (under an #ifdef FUTURE) code to allow passing interpolated images
+through the band list. NOTE: interpolated images will appear slightly
+different than without banding, because the part of the image intersecting
+each band will be scaled slightly differently in the (device) Y direction.
+(gxclpath.h, gxclimag.c, gxclread.c, gximage.c)
+
+Changes Type 1 hinting so that when it moves points on a curve, it does so
+by properly scaling the curve in the given direction. (gxhint3.c)
+
+Version 5.0 (6/6/97)
+====================
+
+This is the first public release since 4.03.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Fontmap.Sol was incorrectly referred to as Fontmap.Solaris.
+(use.txt)
+ - There was still a reference to pstoppm in the documentation.
+(psfiles.txt)
+ - The JPEG DOS source site information was out of date. (jpeg.mak)
+ - The list of devices included in the distributed Unix makefiles was
+out of date. (make.txt)
+ - The MCU size limitation on the DCT filters was documented
+incorrectly. (current.txt)
+ - The URL for the uniprint driver home page was incorrect.
+(devices.txt)
+ - The makefiles referred to sfilefd.c, which is now named sfxfd.c.
+(gs.mak, *.mak)
+
+Adds a VMS help file. (gs-vms.hlp)
+
+Removes documentation for Digital Unix (OSF/1) 1.2 and 1.3, which are now
+long obsolete, and updates the documentation for current versions.
+(make.txt)
+
+Notes that there may be a problem with libpng version 0.95. (libpng.mak)
+
+Adds some specific documentation for the JPEG drivers. (devices.txt)
+
+Adds a suggestion that people compiling Ghostscript check the values of
+JVERSION and PVERSION. (make.txt)
+
+Removes the requirement for setting the LIB environment variable when
+compiling with MSVC. (make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - There were a number of small errors in the new OpenVMS makefile.
+(openvms.mak)
+ - The MSVC makefiles omitted a necessary switch to work around some
+"unspecified Pentium bugs". (msvccom.mak)
+ - The Borland makefile wasn't even close to working; fixing it
+required moving the compilation rule for genarch.exe into the
+compiler-specific makefiles. (bcwin32.mak, msvccom.mak, watcw32.mak,
+wincom.mak)
+ - There were some (harmless) undefined macro references in the MSVC
+makefile. (msvccom.mak)
+
+Makes it unnecessary to set the LIB environment variable for MSVC.
+(msvc4.mak, msvc5.mak, wincom.mak)
+
+Adds a note on compiling with the cygwin32 gcc compiler for Windows NT.
+(make.txt)
+
+Updates vms.mak yet again, hopefully for the last time. (vms.mak)
+
+Moves the CGM, JPEG, and MIFF file formats from DEVICE_DEVS8 to
+DEVICE_DEVS14 to shorten command lines; adds pcxcmyk to all platforms that
+include PCX format at all; adds jpeggray to all platforms that include jpeg.
+(devs.mak, *.mak)
+
+Adds -DPNG_USE_CONST for compiling libpng, to get rid of compiler warning
+messages. (gs.mak)
+
+Removes obsolete makefiles from the fileset. (tccommon.mak, tctail.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - restore was broken if -dNOBIND was invoked. This fix should have
+been in the 4.81 fileset, but was left out due to operator error.
+(gs_dps1.ps)
+ - Some compilers complained about macro argument replacement within
+a string literal. (isave.c)
+ -dSAFER didn't allow opening the %stdxxx files, which caused the
+combination of -dSAFER and -dNOBIND to cause an infinite error.
+(gs_init.ps)
+ - If C code used run_string to execute a startjob, an error
+occurred. (gs_init.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - Some compilers complained about macro argument replacement within
+a string literal. (gxclbits.c, gdevpdfi.c)
+ - At certain resolutions, a 1-pixel line of the wrong color could
+appear at one edge of landscape-oriented monobit images. (This is the 4th
+or 5th time we have "fixed" this one infuriatingly fragile piece of code.)
+(gxfixed.h, gximage1.c)
+ - The optimized code for landscape monobit images overlooked the
+possibility of partial images, causing parts of images to be translated and
+possibly clipped. (Yes, it's that same fragile piece of code.)
+(gximage1.c)
+ - The bounding box device allowed resetting its resolution, which
+could cause limitchecks from coordinate overflow. Our fix is to initialize
+the device to a very high resolution (4000 dpi), which reduces the maximum
+page size it can handle to about 130" on a side. (gdevbbox.c)
+ - The bounding box device wasn't identified as a page device.
+(gdevbbox.c)
+ - The bounding box device used alone disregarded changes in page
+size. (gdevbbox.c)
+ - One old compiler didn't allow a structure member name to be the
+same as a typedef name. (gximage.h, gximage.c, gximage4.c)
+ - The height and band intersection computations for banded images
+still weren't right, leading to inconsistencies in the band list and errors
+in the output (typically, thin horizontal white stripes at band boundaries).
+(gxclimag.c)
+
+Adds an extensive memory dump facility to the standard allocator.
+Eventually this should be moved into a separate file, but it would be too
+disruptive to do this just before a release. (gsalloc.c)
+
+Version 4.81 (6/1/97)
+=====================
+
+This is a last-minute set of bug fixes before the 5.0 release.
+
+Documentation
+-------------
+
+Adds some overlooked helpers to the list. (helpers.txt)
+
+Procedures
+----------
+
+Makes a distinction between 2-part and 3-digit version numbers.
+(version.mak, vms.mak)
+
+Utilities
+---------
+
+Develops the Type 1 to CFF converter a little further; it is still NOT
+USABLE. (t1tot2.ps)
+
+Removes the pstoppm.ps script, since the p*m drivers supersede it.
+(pstoppm.ps, unix-end.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PDF writer sometimes omitted an ET command before setting the
+clip path. (gdevpdf.c)
+ - The PDF writer didn't initialize the "vector" state, leading to
+some redundant output (performance bug only). (gdevpdf.c)
+ - The PDF writer wrote clip paths even when they included the entire
+page (performance bug only). (gdevpdf.c)
+
+Changes the PDF writer so that it recognizes not only the 14 built-in fonts
+but any font with the same UniqueID and metrics. This covers some common
+cases of re-registering a font with a variant Encoding. (gs_pdfwr.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - SEARCH_HERE_FIRST was accidentally set to 0 on MS Windows
+platforms. (bcwin32.mak, msvc4.mak, msvc5.mak, watcw32.mak)
+
+Adds code to remove "" around arguments in the command line passed to
+WinMain (MS Windows platforms). (dwmain.cpp, dwmainc.cpp)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - setsystemparams was broken. (gs_lev2.ps)
+ - restore was broken if -dNOBIND was invoked. (gs_dps1.ps)
+ - deviceinfo returned much more information than it should.
+(gs_dps.ps)
+ - The fix for the default EndPage procedures not popping their page
+count operand from the stack was wrong. (gs_init.ps, gs_setpd.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The saved character origin took the translation component of the
+FontMatrix into account, which caused charpath on fonts with non-zero
+translation in the FontMatrix to produce incorrect results. (gschar.c)
+
+Removes incorrect access attributes on a couple of files. (gdevpdfm.c,
+gxclist.h)
+
+Version 4.80(limited) (5/28/97)
+=====================
+
+This is the candidate fileset for the 5.0 release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The one-line description of the color image rendering module was
+incorrect. (gximage3.c)
+ - Some of the VMS documentation was out of date. (make.txt,
+use.txt)
+ - The description of the file name separator for -sFONTMAP= was
+wrong. (use.txt)
+ - PSFile was misspelled PSfile. (use.txt)
+ - There were some minor typos. (gstype1.h)
+ - The build instructions had a lot of obsolete information for PC
+environments, and didn't cover Microsoft Visual C++. (make.txt)
+
+Explains that -sPAPERSIZE= only specifies the default papersize, and that
+forcing a particular paper size also requires -dFIXEDMEDIA. (use.txt)
+
+Adds information about building with GNU make on OpenVMS. (make.txt)
+
+Clarifies the meaning of EOFC for streams. (strimpl.h)
+
+Documents the new dictionary argument for the eexecDecode filter.
+(language.doc)
+
+Procedures
+----------
+
+Fixes bugs:
+ - gs_epsf.ps didn't get installed on Unix systems. (unix-end.mak)
+ - The code wouldn't build with libpng 0.95b. (libpng.mak)
+ - One of the VMS scripts used CC_QUAL instead of CC_DEF.
+(vms-cc.mak)
+ - version.mak wasn't included in a dependency list. (unix-end.mak)
+
+Brings the VMS DCL script up to date again (for the last time, we hope).
+(vms.mak)
+
+Modifies all platform-independent uses of upper-case command line arguments
+to deal properly with VMS, where the shell converts all command line
+arguments to lower case, without requiring quotation. (devs.mak, gs.mak,
+int.mak, lib.mak, zlib.mak)
+
+Moves the compilation rules for the third-party libraries into gs.mak, so
+they can be used to compile the callers as well. (gs.mak, jpeg.mak,
+libpng.mak, zlib.mak)
+
+Adds a set of files that allow building on OpenVMS using GNU make (slightly
+patched). The timing on this is unfortunate, but we've wanted this for a
+very long time. NOTE: be sure to look in the OpenVMS section of make.txt
+for information on patching GNU make. (openvms.mak, append_l.com,
+rm_all.com, rm_one.com, copy_one.com)
+
+Adds new makefiles for building on 32-bit Windows with Borland, Watcom, and
+Microsoft Visual C++ (versions 4.x and 5.0). The timing on this is
+unfortunate too, but having this capability is so important that we couldn't
+pass it up. (bcwin32.mak, msvc4.mak, msvc5.mak, msvccom.mak, watcw32.mak,
+wincom.mak)
+
+Removes now-obsolete makefiles. (dwcommon.mak, msc.mak, msvcwint.mak,
+mscbegin.bat, watcwin.mak)
+
+Utilities
+---------
+
+Extends echogs to work in VMS environments, where the shell converts all
+command line arguments to lower case, without requiring quotation.
+(echogs.c)
+
+Adds a sketch of a utility for converting Type 1 fonts to CFF. DOESN'T WORK
+YET: DON'T TRY TO USE IT. (t1tot2.ps, type1ops.ps, writecff.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A type declaration wasn't compatible with libpng 0.95.
+(gdevpng.c)
+ - kshow wasn't handled properly when producing PDF output.
+(gs_pdfwr.ps)
+ - The PDF writer put out unnecessary ET/BT commands. (gdevpdfx.h,
+gdevpdf.c, gdevpdfi.c, gdevpdfm.c, gdevpdft.c)
+ - The PCL XL writer put out real numbers for the miter limit, which
+are not allowed (!). (gdevpx.c)
+ - The PCL XL writer didn't combine successive curves into a single
+curve command (performance bug only). (gdevpx.c)
+ - The PCL XL writer could write uncompressed images with a tag
+saying they were compressed. (gdevpx.c)
+ - The PCL XL writer always selected U.S. letter paper, rather than
+the requested size. (gdevpxen.h, gdevpx.c)
+ - The PCL XL writer reselected the paper size on every page, even if
+it hadn't changed. (gdevpx.c)
+ - The PCL XL writer always used shorts for line and curve
+coordinates, rather than using bytes when possible (performance bug only).
+(gdevpx.c)
+ - Because of a compiler bug, a macro with argument conflicted with a
+variable name. (gdevpdfx.h, gdevpdf.c)
+ - A picky compiler objected to an extern for an undefined structure.
+(gdevpsdf.h)
+ - The PDF writer sometimes didn't reset the clipping path, causing
+bitmaps or rectangle to disappear. (gdevpdf.c, gdevpdfi.c)
+ - The PDF writer produced invalid output if the first page was
+blank. (gdevpdf.c)
+ - The AutoRotatePages parameter for PostScript and PDF output (which
+doesn't actually do anything yet) incorrectly expected a Boolean value
+rather than an enumeration. (gdevpsdf.h, gdevpsdf.c)
+ - Some places returned -1 for an error without calling gs_note_error
+or gs_return_error. (gdevm1.c, gdevmpla.c, gdevrun.c, gxclpath.c)
+ - The PCL XL writer produced extremely large files because it didn't
+download character bitmaps. (OK, this isn't really a bug fix.) (gdevpx.c)
+ - The forwarding implementation of get_page_device didn't do the
+right thing. (gdevnfwd.c)
+ - The x11alpha device didn't implement get_params properly, leading
+to anomalous behavior. (gdevxalt.c)
+ - The PDF writer produced incorrect Count values for outlines: the
+count only counted descendant leaves, omitting intermediate nodes.
+(gdevpdfm.c)
+
+Removes an assumption that images have at most 4 components. (gdevpdfi.c)
+
+Adds an x11gray2 device, primarily for debugging. (devs.mak, gdevxalt.c)
+
+Updates the unified printer driver with a newer version. (uninfo.ps,
+gdevupd.c, *.upp)
+
+Platforms
+---------
+
+Adds the P*M devices and the X11 devices (commented out) to the OS/2
+makefile. (os2.mak)
+
+Updates the MS Windows platform to be compatible with Microsoft Visual C++
+(as well as Watcom and Borland compilers). (gsdll32.def, gdevmswn.h,
+gp_mswin.h, gsdll.h, dwimg.cpp, dwmain.cpp, dwmainc.cpp, dwtext.cpp,
+gdevwdib.c, gdevwprn.c, gdevwpr2.c, gp_mswin.c, gsdll.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Certain synthetic fonts incorrectly were loaded into local rather
+than global VM. (These fonts are not part of the standard distribution.)
+(gs_fonts.ps, gs_pfile.ps, *ss*.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The FAKEFONTS scan could leave junk on the stack. (gs_fonts.ps)
+ - Dynamically loading known encodings on demand left junk on the
+stack, causing a typecheck error. (gs_res.ps)
+ - Some 'static' declarations were missing (gcc lossage). (iname.c)
+ - Some internal operators didn't have names, leading to unhelpful
+error printout. (zfileio.c)
+ - The resource "operators" didn't always restore the stacks properly
+on an error. (gs_res.ps)
+ - The CID font code left a garbage value on the stack during
+loading. (gs_cidfn.ps)
+ - The defineresource implementation for built-in resources like
+FMapType didn't leave the resource "value" on the stack. (gs_res.ps)
+ - If an operator defined by a procedure was bound into a packed
+procedure, the stack-protection feature wasn't effective. (interp.c)
+ - findfont didn't restore the stack if it failed. (gs_res.ps)
+ - The showpage count passed to the BeginPage and EndPage procedures
+was incremented only if a page was printed, rather than for every invocation
+of showpage. (gs_init.ps, zdevice2.c)
+ - The default EndPage procedures didn't pop their page count operand
+from the stack. (gs_init.ps, gs_setpd.ps)
+ - If the argument of findfont wasn't a name or a string, and no font
+with that key had been registered, an error occurred. (gs_fonts.ps,
+gs_res.ps)
+
+Updates most of the remaining pseudo-operators to take advantage of stack
+protection. (gs_btokn.ps, gs_cmap.ps, gs_dps1.ps, gs_dps2.ps, gs_fonts.ps,
+gs_lev2.ps, gs_pdfwr.ps)
+
+Splits the image operators into a separate file from the path painting
+operators. (This should have been done a long time ago.) (iimage.h,
+zimage.c, zpaint.c)
+
+Adds more of the implementation of the NeXT alpha and compositing
+operations, under an #ifdef DPNEXT. (iimage.h, zcolor1.c, zdpnext.c,
+zimage.c)
+
+Adds more of the implementation of DPS contexts. These are still not
+usable. (icontext.h, icontext.c, zcontext.c, zmath.c)
+
+Changes the help message to describe -dBATCH instead of -c quit.
+(imainarg.c)
+
+Recognizes the dictionary argument for the eexecDecode filter. (zmisc1.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The tracing message when starting to decode 1-D fax data reported
+the run_color incorrectly. (scfd.c)
+ - In the CCITTFaxDecode filter, if a buffer boundary fell between a
+makeup code and a final zero-length termination code, an ioerror could
+occur. (scfd.c)
+ - Per Adobe, in the CCITTFaxDecode filter, EndOfBlock = true should
+cause Rows to be ignored. (scfd.c)
+ - If an output stream returned EOFC, an infinite loop might result.
+This problem (and the fix) are in the same fragile code as the EOD fix in
+4.74, and we may again have introduced a new bug. (stream.c)
+
+Changes the eexecDecode filter so that instead of a number, it can take a
+dictionary with two keys, seed and lenIV. (Having eexecDecode skip initial
+bytes at all was a design bug that is too late to fix.) (sfilter.h,
+seexec.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The default mapping from RGB+alpha to RGB didn't lighten
+(premultiply) the color according to the alpha value. (gxcmap.c)
+ - The angle error metric for rational tangent screen parameters
+should be simply the difference in angle, not a ratio. (gshtscr.c)
+ - gs_setcolorscreen and gs_sethalftone didn't initialize an
+allocator pointer, leading to memory access errors. (gsht1.c)
+ - If a banded image was clipped, an invalid band list could be
+produced. (gxclimag.c)
+ - A picky compiler wouldn't allow an enum to be &&'ed with a
+boolean. (gschar.c)
+ - A short-sighted compiler didn't allow the use of actual procedure
+names (as opposed to procedure variables) in a conditional expression.
+(gxfill.c)
+ - A compiler objected to a name longer than 31 characters. (gzht.h,
+gsht.c, gxclread.c)
+ - The height computations for banded images were not consistent,
+possibly leading to invalid band lists. (gxclimag.c)
+ - copypage didn't reset the band writer and band reader bookkeeping
+consistently, leading to incorrect output and possible errors. (gxcldev.h,
+gxclist.c, gxclread.c)
+ - When banding, changing the halftone could lead to accessing memory
+after freeing it. (gxclread.c)
+ - When using disk files for band storage, showpage didn't actually
+delete or truncate the band list file, possibly causing subsequent copypage
+operations to become confused. (gxclfile.c)
+ - When banding, having more than one image operator in progress at a
+time confused the rasterizing pass and could produce arbitrary errors. From
+PostScript, this can only happen in the case of an image whose data source
+was a procedure-based stream that itself invoked an image operator: this is
+a senseless and perverse thing to do, but it shouldn't break the code (and a
+Genoa CET file actually does it). (gxclist.h, gxclimag.c, gxclist.c)
+ - Some picky compilers objected to negating unsigned values.
+(gsuid.h, gsht.c, gsmemory.c, gxpcopy.c)
+ - When banding, if a 90- or 270-degree rotated monobit image was
+clipped, invalid memory accesses could occur. (gximage.h, gximage1.c)
+ - The showpage count passed to the BeginPage and EndPage procedures
+was incremented only if a page was printed, rather than for every invocation
+of showpage. Fixing this requires removing the incrementing of the count
+from the library level altogether. (gsdevice.c)
+ - When rendering a subrectangle of an image, the X DDA was
+initialized incorrectly, causing possible errors. We think this only
+affected certain banded images. (gxdda.h)
+
+Adds a provision for images with an alpha component, under an #ifdef DPNEXT.
+****** THE BANDING CODE HAS NOT BEEN UPDATED YET. ****** (gsiparam.h,
+gxcmap.h, gxdither.h, gximage.h, gsimage.c, gxclimag.c, gxclread.c,
+gxcmap.c, gximage.c, gximage3.c, gximage4.c ****** NOT DONE YET ******,
+gximage5.c)
+
+Adds a return_if_error macro to capture the common idiom of making a call
+and then returning its value if that value is negative (error). (gserror.h)
+
+Version 4.74(limited) (5/5/97)
+=====================
+
+This fileset is supposed to fix all remaining errors reported by the Genoa
+CET, and is intended to be the last incremental test fileset before the 5.0
+release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Mark procedures are *not* executed in the normal return case.
+(estack.h)
+ - The line_params element of a gs_imager_state is *not* allocated
+separately. (gsstate.c)
+ - The value passed to the PDF writer for text is a dictionary, not
+an array. (gdevpdft.c)
+
+Improves the documentation of gstate memory management. (gsstate.c)
+
+Documents end_status = EOFC for writing streams. (stream.h, strimpl.h)
+
+Clarifies memory management for halftones and device halftones. (gsht1.h,
+gxdht.h, gxht.h, gzht.h)
+
+Removes the "experimental" tag from the PostScript and EPS writers.
+(devs.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The viewpcx utility scaled images improperly. (viewpcx.ps)
+ - If a PDF file used F instead of f for filling a path, pdf2ps
+didn't output the fill operation. (pdf_base.ps)
+
+Changes the ps2pdf script so that, like pdf2ps, it allows debugging
+switches. (ps2pdf)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The vgalib driver didn't clip monobit images properly.
+(gdevvglb.c)
+ - The X driver asked for exposure events to be reported, but never
+read them, causing the event queue to grow indefinitely. (gdevxini.c)
+ - The "vector" drivers and the PDF writer didn't properly keep track
+of whether the current clipping region was the default one. (gs_pdfwr.ps,
+gdevvec.h, gdevvec.c, gdevpdf.c, gdevpdft.c)
+ - The PDF writer had word and character spacing interchanged.
+(gdevpdft.c)
+ - The PDF writer scaled word and character spacing incorrectly.
+(gdevpdft.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The user object operators didn't leave the stack in a clean state
+if they failed. (gs_dps2.ps)
+ - UserObjects wasn't actually defined. (gs_dps2.ps)
+ - deviceinfo and set/currenthalftonephase were defined even if the
+dps feature wasn't selected. (int.mak, gs_dps.ps, gs_dps1.ps, gs_lev2.ps,
+zdps.c, zdps1.c)
+ - The dps feature didn't automatically include the level2 feature,
+which it needs. (int.mak)
+ - The DPS user names mechanism didn't work, since the user names
+array was subject to save and restore. (It still doesn't really work --
+there is no provision for expanding the user names array, which is created
+with length 0.) (gs_btokn.ps, ivmspace.h, zbseq.c, zdps.c)
+ - The DPS context operators didn't do all the necessary error
+checking. (zcontext.c)
+ - The debugging printout for names printed the name index in hex
+without identifying it as such. (idebug.c)
+ - Adding the first non-name key (or name key with a name index
+beyond 4K) to a dictionary that had any deleted entries could cause some
+entries to apparently disappear. (idict.c)
+ - If a sub-table of the name table was freed during garbage
+collection, memory could be left in an inconsistent state. (iname.c, igc.c)
+ - findfont didn't restore the stacks reliably if an error occurred.
+(gs_fonts.ps)
+ - definefont with an invalid Type 0 font sometimes added a FID entry
+(with a dangling pointer) if it failed. (Recovering properly from a VMerror
+during font creation would require a much more complicated fix than this,
+but since we expect a garbage collection to occur in that case, we aren't
+concerned about it.) (zfont0.c)
+ - Reading parameter values from a dictionary could access beyond the
+end of the array that keeps track of which entries had been referenced.
+(idict.h, idict.c, iparam.c)
+ - Halftone data was allocated in the current VM rather than in the
+same VM as the halftone dictionary or procedure. (Fixing this includes
+updating code as necessary for the change in halftone and device halftone
+allocation.) (iht.h, ivmspace.h, zht.c, zht1.c, zht2.c)
+ - Closed non-executable files on the e-stack could cause a restore
+to be invalid. (zvmem.c)
+
+Adds skeleton code for the NeXT Display PostScript alpha and compositing
+operators. This is not ready for use yet! (errors.h, gs_dpnxt.ps,
+zdpsnext.c)
+
+Implements more of state saving and restoring for Display PostScript
+contexts. This is not ready for use yet either. (int.mak, icontext.h,
+istack.h, icontext.c, zcontext.c)
+
+Adds stub code for the Display PostScript view clip operators. (gs_dps.ps,
+zdps.c)
+
+Removes the obsolete PPM-writing operator. (int.mak, vms.mak, *.mak,
+zwppm.c)
+
+Makes the random number generator state public so it can be stored in the
+context state. (zmath.c)
+
+Changes the flag for forcing global garbage collection to a run-time
+variable, for debugging. (igc.c)
+
+Changes the handling of job control so that it doesn't use procedures that
+produce an execstackoverflow when being printed. (gs_init.ps)
+
+Updates code as necessary for the change in reference counting. (zcie.c,
+zcrd.c)
+
+Updates code as necessary for the change in off-stack gstate copying.
+(zdps1.c)
+
+Removes a small bit of obsolete code. (interp.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - An output stream that was not the last one in a pipeline could
+incorrectly be asked to write its EOD marker more than once. (The fix is
+very fragile and may have introduced new bugs.) (stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The gx_device_halftone_release procedure was declared in two
+different header files. (gzht.h)
+ - Off-stack copying of gstates could lead to a situation where
+different parts of a single gstate were owned by different allocators; this
+could cause them to be freed improperly, corrupting memory. We fixed this
+partly by making the mixed ownership situation work, and partly by copying
+more of the gstate when off-stack gstates are involved. Unfortunately, the
+fixes are subtle and may have introduced new bugs. (gsstate.h, gsht.c,
+gsht1.c, gspcolor.c, gsstate.c)
+ - If an error occurred while creating a Pattern instance, the
+partially initialized instance structure wasn't freed. (gspcolor.c)
+ - Halftones and device halftones didn't allocate their clones or
+their subsidiary structures with the correct allocator. (gsht.c, gsht1.c)
+ - The error statement when allocating a reference-counted object had
+to be a control transfer. (gsrefct.h)
+ - Copying gstates incorrectly copied the memory and saved pointers,
+and the pointer to the dash pattern. (gsstate.c)
+ - Flatness values less than 0.5 produced far more line segments than
+necessary (roughly the square of the required number). Fixing this may have
+bad effects on character quality -- this remains to be seen. (gxpflat.c)
+ - An error during installation of a halftone could leave things in
+an inconsistent state. (gsht.c)
+ - The API didn't provide enough flexibility with respect to memory
+management for halftones, or guarantee consistent allocation of a halftone
+and its subelements. (gsht1.h, gsht.c, gsht1.c, gshtscr.c)
+ - Releasing a path didn't clear enough pointers to ensure clean
+garbage collection. (gxpath.c)
+ - Finalizing or discarding a (cached) scaled font didn't properly
+unlink it from the scaled_fonts list. (gsfont.c)
+ - Invoking an image operator within the BuildChar procedure for a
+charpath caused an infinite loop. (gsimage.c)
+ - The bookkeeping for the scaled font cache was incorrect: the count
+didn't always get decremented when a scaled font was freed. (gsfont.c)
+ - "High level" masked images were written incorrectly in the band
+list as black-and-white images. (gxclimag.c)
+ - For "high level" images with fewer than 4 samples per pixel,
+non-standard Decode values were written incorrectly in the band list.
+(gxclimag.c)
+ - The color wasn't set correctly for "high level" masked images.
+(gxclimag.c)
+ - The fastest case of monobit image rendering could get a memory
+access error if the image lay partly outside the page. (gximage1.c)
+ - Clipping with an empty path was a no-op, rather than clipping out
+everything. (gxcpath.c)
+
+Makes reference-counted objects remember which allocator owns them: this
+entails a NON-BACKWARD-COMPATIBLE change to some of the macros for reference
+counting. This was necessary to fix the off-stack gstate copying problem.
+(gsrefct.h, gscie.c, gscolor.c, gscolor1.c, gscolor2.c, gscsepr.c,
+gsstate.c, gxclread.c)
+
+Refactors the unpacking of image data, to make unpacking available as a
+general facility. (gximage.h, gxsample.h, gximage.c, gximage0.c,
+gximage1.c, gximage4.c, gxsample.c)
+
+Enhances -Z? so that before freeing an object, it checks that the object was
+owned by the correct allocator. (gsalloc.c)
+
+Version 4.73(limited) (4/19/97)
+=====================
+
+This is an incremental bug fix release made primarily to provide a
+synchronization point for an upcoming trip.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A reference to the uniprint documentation was incorrect.
+(current.txt)
+ - -Olimit 1000 is not enough now for DEC Ultrix, 1200 is required;
+this is also required for SGI IRIX. (make.txt)
+
+Adds argument/result comments to all the operators defined in gs_lev2.ps.
+(Eventually we will do this for all operators defined as PostScript
+procedures.) (gs_lev2.ps)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The makefiles didn't provide a default value for GCONFIG_EXTRAS.
+(gs.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - pdf2ps didn't work with TrueType or compressed Type 1 fonts.
+(gs_pdf.ps, pdf_2ps.ps, pdf_font.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A cast from byte to char was omitted. (gdevpdfm.c)
+
+Platforms
+---------
+
+Updates the VMS script (again). (vms.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - A module that used strlen didn't include string_.h. (zdevice.c)
+ - Because of some bad PostScript code in FrameMaker output, identity
+rather than unity black generation and undercolor removal functions are
+required on black-and-white devices. (gs_init.ps)
+ - A harmless internal error during initialization left bogus
+information in $error. (gs_cidfn.ps)
+ - startjob didn't clear the execution stack. Fixing this required
+NON-BACKWARD-COMPATIBLE changes to the internal operators .instopped, .stop,
+and .stopped, which are not supposed to be used by any external code.
+(startjob will still give errors if executed in a file that isn't being
+piped from stdin; this will take longer to fix.) (gs_init.ps, gs_lev2.ps,
+iref.h, imain.c, interp.c, zcontrol.c, zfile.c)
+
+Adds a new .execn operator, part of the startjob changes, that allows
+pushing multiple items on the exec stack. Eventually this will allow us to
+get rid of many dynamically created closures. (zcontrol.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Landscape-mode PDF files weren't rotated properly. (gs_pdf.ps,
+pdf_main.ps)
+
+Makes the default PDF configuration notify users more informatively when
+encountering an encrypted file. (pdf_sec.ps)
+
+Streams
+-------
+
+Makes the RunLengthEncode filter always generate optimally compressed
+output. We did this because we thought one of the Genoa CET files loops
+forever if this is not the case; but we were wrong. (srle.c)
+
+Library
+-------
+
+Fixes bugs:
+ - If one coordinate of a position or distance overflowed the
+internal representable range, the other coordinate became garbage. (bug
+introduced in 4.70) (gspath.c)
+ - The bounding box computation for strokes was slightly too large
+(sometimes much too large). (gxpaint.h, gdevbbox.c, gxclpath.c, gxstroke.c)
+
+Adds (under an #if 0) an experimental alternate halftone cell choice
+algorithm. (gshtscr.c)
+
+Adds a better comment to a particularly obscure line of C code.
+(gxclimag.c)
+
+Version 4.72(limited) (4/14/97)
+=====================
+
+This is another bug fix release, motivated mostly by Genoa testing. It also
+updates the new uniprint driver with a major revision, and upgrades CFF
+support a little bit.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - -dNOGC only disables default automatic garbage collection, not all
+garbage collection. (use.txt)
+ - Apparently a different set of flags is needed for newer H-P
+compilers. (make.txt)
+
+Replaces the tiny FAQ with a pointer to the on-line FAQ. (use.txt)
+
+Updates the documentation for the uniprint driver. (devices.txt)
+
+Clarifies the fact that Ghostscript reads Fontmap files from *all*
+directories in the search list. (use.txt)
+
+Notes that building on Linux may require SM and ICE in the list of X
+libraries. (make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - An -include type42 was omitted from the level2 module description.
+(int.mak)
+ - A mention of $(ECHOGS) in the rule for sfile should have been
+$(ECHOGS_XE). (lib.mak)
+ - The pcx2up sample device should have been put in devs.mak rather
+than lib.mak. (devs.mak, lib.mak)
+ - scanchar.h and scantab.c belong in the library, not the
+interpreter. (devs.mak, int.mak, lib.mak)
+ - Some _h definitions were used before being defined, or weren't
+defined at all. (devs.mak, lib.mak)
+ - The JPEG driver was missing a dependency. (devs.mak)
+ - The PDF writer was missing a dependency. (devs.mak)
+ - Building Level 1 systems was no longer possible. (int.mak)
+
+Updates the VMS build scripts. (vms.mak, vms-decc.mak)
+
+Adds *.upp to the list of files installed under Unix. (unix-end.mak)
+
+Adds rules to the Unix makefiles to build two library files: gs.a,
+consisting of the entire PostScript/PDF interpreter lacking only gs.c, and
+gslib.a, consisting of the graphics library without the gslib.c test driver.
+(ansihead.mak, cc-head.mak, gcc-head.mak, unixtail.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The PS/EPS writers could generate a reference to an undefined
+name. (gdevps.c)
+ - The PDF writer produced incorrect output for multi-level outlines.
+(gdevpdfm.c)
+ - The PDF writer didn't convert /Action to /A, and /Action/Subtype
+to /S, in Annot dictionaries. (gdevpdfm.c)
+ - The PDF writer didn't work in Level 1 systems. (gs_pdfwr.ps)
+ - The PDF writer didn't transform /Rect and /R values to current
+user coordinates. (gs_pdfwr.ps, gdevpdfx.h, gdevpdfm.c)
+ - The PNG writer could refer to the 3 predefined stdio files even in
+environments where this was undesirable. (gdevpng.c)
+ - The PDF writer had a compiled-in limit of 100 pages of output.
+(gdevpdfx.h, gdevpdf.c)
+
+Updates the uniprint driver with a major revision that uses device
+parameters that can be set from the command line, rather than PostScript
+code, for configuration choices. (gdevupd.c, *.upp)
+
+Platforms
+---------
+
+Fixes bugs:
+ - gp_enumerate_files_next had no way to return an error. (gp.h,
+gp_dosfe.c, gp_ntfs.c, gp_os2.c, gp_unifs.c, gp_vms.c) ****** NOT
+IMPLEMENTED YET ******
+ - On the Watcom platform, CPU_TYPE >= 486 didn't automatically set
+FPU_TYPE to 387. (wccommon.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Caching the current device in userdict could create dangling
+references. (gs_init.ps, gs_pdfwr.ps, zdevice.c)
+ - If an error occurred in a BuildChar or BuildGlyph procedure, the
+graphics state stack wasn't restored. (ichar.h, zchar.c, zchar2.c)
+ - There was an obsolete check for a structure when cleaning up after
+a show operator. (zchar.c)
+ - Attempting to show a character with no associated glyph in a Type
+3 font with a BuildGlyph procedure caused an error. (zchar.c)
+ - noaccess on a read-only dictionary didn't give an error.
+(ztype.c)
+ - The dictionary passed to a Pattern's PaintProc was the original
+template, not the copy made by makepattern. (gs_lev2.ps)
+ - Invalid font parameters could result in partially constructed
+fonts, which caused problems for restore. (zfont0.c, zfont2.c)
+ - Files run under job control caused an error when terminating.
+(gs_init.ps)
+ - setpagedevice didn't protect itself against malfunctioning
+BeginPage or EndPage procedures. (The protection is still not perfect.)
+(gs_setpd.ps)
+ - .type42execchar called font_param redundantly. (zchar42.c)
+ - The font operators didn't protect themselves well enough against
+bogus font dictionaries. (zfont.c, zfont0.c)
+ - If an error occurred within a stringwidth, the graphics state
+stack wasn't restored properly. (zchar.c)
+ - If an error occurred within the PaintProc of a form, the graphics
+state stack was left with an extra entry. (gs_lev2.ps)
+ - Registering a font under a second name could corrupt data
+structures. (zfont2.c)
+ - Different scalings of the same font should have "equal" fontIDs,
+to match the Adobe implementations. (iutil.c)
+ - Errors detected by PostScript code during initialization either
+allowed execution to continue or produced a hex stack dump, instead of just
+producing a message and exiting. (interp.c)
+ - The memory validator didn't validate chunks at previous save
+levels. (ilocate.c)
+ - The Level 1 size of systemdict was too small. (iinit.c)
+ - Attempting to define a Category resource in local VM gave a
+typecheck error rather than an invalidaccess. (gs_res.ps)
+ - Building Level 1 systems was no longer possible. (zusparam.c)
+
+Rearranges the interpreter code slightly so that all operator invocations go
+through a single procedure when debugging. (interp.c)
+
+Adds a -K<numK> switch to limit the total amount of memory that Ghostscript
+can acquire. (imainarg.c)
+
+Makes the memory validator check packed refs more carefully. (ilocate.c)
+
+Makes the memory validator check explicitly for pointers to freed objects.
+(igc.c, ilocate.c)
+
+Makes the memory validator check dictionaries more carefully. (ilocate.c)
+
+Makes the memory validator check refs embedded in structures. (ilocate.c)
+
+Adds a debugging option that bypasses the garbage collector entirely.
+(igc.c)
+
+Adds debugging options to validate memory before/after save/restore.
+(zvmem.c)
+
+Removes the patch for the uniprint driver, since it is no longer needed.
+(gs_init.ps)
+
+Implements real-number operands in CFF fonts. (gs_cff.ps)
+
+Implements non-default charsets in CFF fonts. (gs_cff.ps)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - The PDF 1.2 "marked content" operators weren't defined.
+(pdf_main.ps)
+ - Streams with binary data whose first character was an EOL (\n)
+didn't parse properly. Unfortunately, the way we fixed this may break some
+other files. (pdf_base.ps)
+ - PDF 1.2 #nn escape syntax in names wasn't recognized. ****** This
+is implemented with an inefficient hack that should be moved down into C.
+However, I don't want to risk introducing new bugs during the beta test
+period. ****** (pdf_base.ps)
+ - The interpreter had a limit of 64K objects. Removing this limit
+required changing a basic data structure -- admittedly a risky thing to do
+during beta test. (pdf_base.ps, pdf_main.ps)
+ - TJ didn't multiply the offsets by the font size, causing incorrect
+character positioning. (gs_pdf.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The ASCIIHexDecode filter read an extra character in case of
+error. (sstring.c)
+
+Adds more tracing output to the CCITTFaxDecode stream. (scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The allocator client name for rendering bitmap patterns was
+incorrect. (Only affects tracing output.) (gspcolor.c)
+ - The check for exceeding the overall allocation limit was
+incorrect, because of unsigned arithmetic. (Only affects limitation of
+total allocation, which is only used for debugging and benchmarking.)
+(gsmemory.c)
+ - The 0'th component of colored screens wasn't passed through the
+band list, possibly causing access errors when rasterizing. (gxclimag.c,
+gxclread.c)
+ - setbbox could get an overflow without detecting it. (gsdps1.c)
+ - Images with only one component but MultipleDataSources = true
+could cause a memory access error. (gximage.c)
+ - The buffer for unpacking 12-bit-per-sample image data was too
+small, causing memory corruption. (gximage.c)
+ - 12-bit-per-sample images with multiple data sources sometimes
+didn't pass correct pointers to image_data. (gsimage.c)
+ - If an image data stream reached EOF before supplying enough data
+for the entire image, memory corruption could occur. (zpaint.c)
+ - When a device halftone was freed, some pointers in the halftone
+cache weren't cleared, leading to possible dangling references. (gsstate.c)
+ - Invalid font parameters could result in partially constructed
+fonts, which caused problems for restore. (gxfont0.h, gsfont.c)
+ - If an error occurred within a stringwidth, the graphics state
+stack wasn't restored properly. (gschar.c)
+ - The (static) limit on the size of a command line argument was too
+small. (gsargs.h)
+ - Building Level 1 systems was no longer possible. (gxdht.h,
+gsht.c, gsht1.c)
+ - Truncation instead of rounding caused colors on gray-scale devices
+to come out very slightly too dark. (gxcmap.c)
+ - The Decode mapping table constructed for images was slightly
+inaccurate for ranges other than [0 1] or [1 0]. (gximage.c)
+
+Version 4.71(limited) (3/31/97)
+=====================
+
+This is a bug fix release during the beta test period.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - A larger value of -Olimit is now needed to optimize gxclread.c.
+(make.txt)
+ - Some comments were incorrect. (gdevbbox.h, sfilter1.c)
+
+Updates the GPL with a newer version from FSF. (COPYLEFT)
+
+Notes that the gcc 2.7.x code generation bug is fixed in 2.7.2.1.
+(make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some streams required by high-level drivers were incorrectly
+grouped with the interpreter rather than the library. (int.mak, lib.mak)
+ - The choice of implementation for file streams was buried in an
+obscure place, rather than being included in the configuration definitions
+at the head of each makefile. (We believe there are no more such buried
+parameters.) This involved a NON-BACKWARD-COMPATIBLE change in the way this
+choice was specified. (lib.mak, *.mak)
+ - Some dependencies were missing. (lib.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A variable was used before being initialized, causing get_bits
+(and raster ops) to fail when using alternate X devices. (bug introduced in
+4.70.) (gdevxalt.c)
+ - Some 'private' declarations were omitted. (It is infuriating that
+gcc doesn't check for this!) (gdevps.c, gdevpx.c)
+ - A few character strings were used as byte arrays without a cast.
+(gdevpx.c)
+ - The EPS writer didn't write a correct bounding box, and didn't
+write it at the beginning of the file. (gdevvec.h, gsstruct.h, gdevps.c,
+gdevvec.c)
+ - x_copy_color specified an incorrect (too large) image width.
+Apparently this only mattered because it could cause invalid memory
+accesses. (gdevx.c)
+ - x_copy_mono also specified too large an image width. It's not
+clear this made any difference. (gdevx.c)
+ - The default implementation of strip_copy_rop didn't clamp Y values
+to legal values for get_bits. (gdevmrop.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Some initialization files prematurely switched the interpreter
+into Level 2 mode, causing some Level 2 operators not to be defined. (bug
+introduced in 4.60 or later.) (gs_cff.ps, gs_cidfn.ps, gs_cmap.ps,
+gs_init.ps, gs_res.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The choice of procedure names for the file-descriptor-based
+implementation of file streams was buried in a .c file, rather than being
+chosen in the makefile. (sfile.c[deleted], sfileno.c[deleted], sfxstdio.c,
+sfxfd.c, sfxboth.c)
+
+Library
+-------
+
+Fixes bugs:
+ - rcurveto was broken -- it drew curves to random points. (bug
+introduced in 4.61.) (gspath.c)
+ - A trailing comma in an enum definition upset some compilers. (bug
+introduced in 4.70.) (gstype1.h)
+ - Type 1 fonts with hint replacement could produce anomalous or
+clipped output, or even missing lines. (Also cleans up some out-of-date
+formatting.) (gxtype1.h, gstype1.c, gxhint2.c)
+ - Removes some conditionals for choosing between old and new
+algorithms. (gxhint3.c)
+ - makebitmappattern required that the bitmap consist of only a
+single tile repetition. (gspcolor.c)
+ - Some computations on RasterOps didn't take transparency into
+account properly. (gdevmrop.c)
+ - The structure definition for imager and graphics states had an
+incorrect offset for line_params, causing the garbage collector not to mark
+or relocate dash patterns, possibly causing memory faults, FPEs, or invalid
+output. (bug introduced since 4.03.) (gsstate.c)
+ - 'show' operators gave a limitcheck for unreasonable coordinates,
+even if limit clamping was enabled. (gschar.c)
+
+Implements banded filling and stroking with colored halftones, in addition
+to pure colors and binary halftones. Since we are in a beta test period,
+actual use of this feature (but *not* all the code implementing it) is
+disabled under an #ifdef FUTURE. (gsdcolor.h, gxcldev.h, gxclpath.h,
+gxdht.h, gxhttype.h, gsht.c, gxclimag.c, gxclpath.c, gxclread.c)
+
+Version 4.70(limited) (3/26/97)
+=====================
+
+This fileset fixes the one outstanding compilation problem on PC platforms
+and the old problem of limitchecks for out-of-bounds coordinates, and adds a
+variety of new features, including the ability to save away the band lists
+for pages and rasterize them later and/or elsewhere in any order and
+combination. This is the first "serious beta" candidate for the next
+general release.
+
+Fileset numbers 4.62 through 4.69 were skipped deliberately.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The list of special -d and -s switches was out of date. (use.txt)
+ - The name of the zlibDecode filter was incorrectly written
+zlibEncode. (language.txt)
+
+Documents where to find out how to install gcc 2.7.x on SGI IRIX 6.x.
+(make.txt)
+
+Documents a makefile patch required on NeXTStep. (make.txt)
+
+Documents how to patch gcc to fix the AXP code generation bug. (make.txt)
+
+Adds documentation for the new unified printer driver. (devices.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - 'make distclean' didn't remove a couple of files. (gs.mak)
+ - A library module didn't include a necessary dependency. (lib.mak)
+ - A new .ps file wasn't installed properly. (unix-end.mak)
+ - File write dates weren't updated properly on PC platforms, causing
+unnecessary rebuilding. (cp.bat, gs.mak, msc.mak, msvcwint.mak, os2.mak,
+tccommon.mak, wccommon.mak, zlib.mak)
+ - An unnecessary explicit compilation line for gdevcdj.c caused
+problems in the Mac environment. (devs.mak)
+ - The VMS scripts were out of sync again. (vms.mak)
+ - The VMS build scripts didn't include the new JPEG driver.
+(vms-*.mak)
+ - A number of makefile macros were referenced before being defined.
+(devs.mak, lib.mak, int.mak, *.mak)
+ - libpng.mak didn't work with PVERSION=90. (libpng.mak, zlib.mak)
+
+Separates install-scripts from install-exec and install-data.
+(unix-end.mak)
+
+Moves the definition of SEARCH_HERE_FIRST from iminst.h to the makefiles.
+(*.mak, iminst.h, iconf.c, imain.c)
+
+Adds a -dBATCH switch that causes Ghostscript to exit after processing the
+files named on the command line. (gs_init.ps)
+
+Adds the PostScript, EPS, and PCL XL writers, and the color and gray-scale
+JPEG drivers, to all Unix configurations. (ansihead.mak, cc-head.mak,
+gcc-head.mak)
+
+Drivers
+-------
+
+NOTE: because of a change in an internal interface (clist_output_page), the
+cp50 driver no longer works. This is a user-contributed driver for which we
+take no responsibility.
+
+Fixes bugs:
+ - gdevcdj.c wasn't compatible with ansi2knr. (gdevcdj.c)
+ - 'private' was omitted from some declarations. (gdevjpeg.c)
+ - The PostScript writer didn't keep track of the current color
+properly. (gdevps.c)
+ - RESOLUTION was misspelled in a header. (gdevbjc.h)
+ - Some compilers objected to the use of a floating point initial
+resolution value. (gdevbjc.h)
+ - Some compilers didn't allow static initialization of a union.
+(gsdcolor.h)
+ - If a TIFF driver got an error when initializing the CCITTFax
+encoder, it returned a bogus error code. (gdevtfax.c)
+ - The PDF writer produced incorrect output for Indexed color space
+images. (gdevpdfi.c)
+ - For many fatal error conditions, the X driver called exit()
+instead of returning an error. (gdevx*.c)
+
+Adds new drivers:
+ - epswrite, an EPS-writing driver (instead of making EPS output a
+parametric option of the PostScript-writing device). (devs.mak, gdevps.c)
+ - pcxcmyk, a 4-bit CMYK PCX driver. This is probably only useful
+for debugging CMYK color rendering. (gdevpcx.c)
+ - jpeggray, a JPEG driver that produces gray-scale rather than color
+output. Thanks to Tom Lane for contributing this. (gdevjpeg.c)
+ - uniprint, a unified printer driver for a wide variety of inkjet
+printers. Thanks to Gunther Hess for contributing this. (gdevupd.c)
+
+Adds the resolution (pHYs) to the output of the PNG drivers. (gdevpng.c)
+
+Adds recognition of the ASCII85EncodePages parameter to the PostScript and
+EPS writers. (gdevps.c)
+
+Makes the new JPEG driver write a JFIF header, which contains the image
+resolution. (gdevjpeg.c)
+
+Changes the "vector" device support interface so relative movement can be
+detected easily. THIS IS STILL SUBJECT TO CHANGE WITHOUT NOTICE.
+(gdevvec.h, gdevpsdf.c, gdevps.c, gdevpx.c, gdevvec.c)
+
+Changes the PostScript, EPS, and PDF writers to recognize curves and lines
+that can be represented more efficiently. (gdevpsdf.h, gdevpsdf.c,
+gdevps.c)
+
+Adds a new parameter to the PDF writer, FirstObjectNumber. This defines the
+first object number that will be used in the output. The default, and
+minimum, value is 1; the maximum value is approximately 2^31. This is for
+the benefit of dvipdf; we don't expect it to be used otherwise. In fact,
+using it appears to produce files that Adobe Acrobat Reader won't accept,
+even though the files are perfectly compliant with the published PDF
+specification. (gdevpdfx.h, gdevpdf.c, gdevpdfp.c)
+
+Platforms
+---------
+
+Removes the makefile for the 16-bit Borland C++ platform. This was the last
+supported 16-bit platform; we expect to gradually drop all 16-bit
+concessions from the code itself. (bcwin.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The initial size of systemdict was too small, causing the
+interpreter to slow down substantially. (iinit.c)
+ - A library module depended on an interpreter module. (zcsindex.c)
+ - A logically necessary (but accidentally always available) #include
+was missing. (ifont.h)
+
+Moves set/currentoverprint to a more appropriate module. (zcolor2.c,
+zcssepr.c)
+
+Changes the default transfer functions so that they do something reasonable
+when given operands outside the legal [0..1] range. We only do this to work
+around a bug in FrameMaker output, which uses the transfer function as the
+screen function (!). (gs_init.ps)
+
+Changes the CMap construction algorithm to use the new, more compact
+representation. (zfcmap.c)
+
+Adds support for Adobe's Compact Font Format. Many individual features are
+not implemented yet: see the comment in the source code for details.
+(gs_cff.ps)
+
+Adds support for Type 2 charstrings in Type 1 fonts. (ifont.h, zfont1.c)
+
+Changes the Type 1 character rendering operator for the library change in
+Type 1 fonts. (zchar1.c, zfont1.c)
+
+Initializes the graphics state limit clamp flag to true. (zgstate.c)
+
+Temporarily adds a configuration file for the new unified printer driver,
+and arranges for it to be read at startup. This arrangement will be
+replaced very soon by a different one based on command line parameters.
+(gs_init.ps, uniprint.ps)
+
+Interpreter (PDF)
+-----------------
+
+Adds support for Compact Font Format fonts. (pdf_font.ps)
+
+Streams
+-------
+
+Adds a glue procedure needed for the new jpeggray driver. (sjpeg.h,
+sjpege.c)
+
+Removes the width limit of 32K in the CCITTFaxEncode filter. The new limit
+is absurdly large (about 50M). (scf.h, scfx.h, scfe.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A library module depended on an interpreter module. (gxcolor2.h,
+gscolor2.c)
+ - When rendering a band, clipping was sometimes used when it wasn't
+necessary. (Performance only.) (gxclread.c)
+ - Stroking didn't check the path against the device clipping box in
+the absence of an explicit (non-default) clipping path. (Performance only.)
+(gxstroke.c)
+ - A reference to an opaque type upset a couple of compilers.
+(gxclread.c)
+ - Negative 32-bit numbers in Type 1 fonts didn't work properly on
+64-bit systems. (gstype1.c)
+ - A logically necessary (but accidentally always available) #include
+was missing. (gxbitmap.h)
+ - A header wasn't protected against double inclusion. (gxclist.h)
+ - Clipping devices didn't store their actual width and height.
+(gxcpath.c)
+ - The slow-case check for thin lines was incorrect. (gxstroke.c)
+ - Images didn't compute their clipping boxes correctly if there
+wasn't an explicit clipping path. (This must be a very recent bug, since it
+creates an overflow condition that prevents monochrome images from being
+rendered at all.) (gximage.c)
+
+Moves set/currentoverprint to a more appropriate module. For clients of
+gs_set/currentoverprint, this is a NON-BACKWARD-COMPATIBLE CHANGE, since the
+header file is now separate. (gscolor2.h, gscsepr.h, gscolor2.c, gscsepr.c)
+
+Replace the MetroWerks work-around with a different, more general one.
+(gdevmem.h, gdevmem.c, gxdevice.h)
+
+Speeds up the Type 1 interpreter a little. (gstype1.c, gxhint3.c)
+
+Redesigns the internal representation of CMaps to be more space-efficient.
+(gxfcmap.h, gschar0.c, gsfcmap.c)
+
+Implements a facility for saving away pages and rendering them later.
+Currently this requires the pages to be represented as band lists on files,
+and only allows X translation when rendering. This involves adding the
+following new printer device parameters:
+ BandHeight
+ BandWidth
+ BandBufferSpace
+Also changes the names of the printer device parameter elements from
+use_buffer_space to BufferSpace and from max_bitmap to MaxBitmap for
+consistency. (gdevprn.h, gxcldev.h, gxclio.h, gxclist.h, gxclmem.h,
+gxclpage.h, gxdevmem.h, gdevmem.c, gdevp2up.c, gdevprn.c, gxclmem.c,
+gxclpath.c, gxclread.c)
+
+Changes the band list implementation API to allow closing a file without
+deleting it, and to allow reopening an existing file. This is a
+NON-BACKWARD-COMPATIBLE change to a deep internal interface. (gxclio.h,
+gxclmem.h, gxclfile.c, gxclist.c, gxclmem.c)
+
+Speeds up rendering of colored halftones, by recognizing cases where one or
+more planes don't actually require screening, unrolling a loop, and doing
+basic clipping before halftoning. (gxcht.c)
+
+Adds a graphics state parameter, gs_set/currentlimitclamp, that changes the
+handling of out-of-range coordinates to clamp them in a way that produces
+approximately the intended output most of the time, rather than causing a
+limitcheck. Currently this is only designed to work with the basic path
+construction operations ([r]moveto, [r]lineto, [r]curveto, closepath); it
+does not work with many other operations such as show, flattenpath or the
+rectangle operations. Note also that while currentpoint will return the
+correct (unclamped) value, reading out the path with pathforall will return
+clamped values. This involves NON-BACKWARD-COMPATIBLE changes to the path
+structure (but not to any public interfaces). (gxpath.h, gxtype1.h,
+gzpath.h, gzstate.h, gspath.c, gspath1.c, gsstate.c, gstype1.c, gxpaint.c,
+gxpath.c, gxpath2.c, gxpcopy.c)
+
+Adds support for Type 2 charstrings. Some features are not implemented yet:
+see gstype2.c for details. (gscrypt1.h, gstype1.h, gxfont1.h, gxop1.h,
+gxtype1.h, gstype1.c, gstype2.c, gxhint2.c, gxhint3.c, gxtype1.c)
+
+Version 4.61(limited) (3/13/97)
+=====================
+
+This fileset cleans up many compiler warnings. It adds support for
+CMap-encoded fonts, and a driver that writes JPEG images.
+
+Documentation
+-------------
+
+Corrects an error in the description of the internal CodeMap structure.
+(gs_cmap.ps)
+
+Documents the fact that the optimizer in gcc 2.7.2.1 is broken on AXP
+machines. (make.txt)
+
+Corrects the name of the .setglobal/.currentglobal procedures. (zvmem2.c)
+
+Updates current.txt in preparation for the release. (current.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The VMS script was out of date again. (vms.mak)
+ - CIDFont support unnecessarily required composite font support.
+(int.mak)
+ - CMap and CIDFont support had improper dependencies on
+initialization order. (lib.mak, int.mak)
+ - Some dependencies were missing in the JPEG library code.
+(jpeg.mak)
+
+Adds the new JPEG driver to all standard configurations. (*.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A dependency was omitted from the makefile. (devs.mak, gdevps.c)
+
+Cleans up some warnings from picky compilers. Some of these actually
+indicated problems, such as unreachable code. (gdevpdfx.h, gdevbj10.c,
+gdevcdj.c, gdevpdfp.c, gdevstc.c)
+
+Adds a JPEG-writing driver. Currently this only produces RGB output and
+only has a QFactor parameter, but eventually it could take all the other
+parameters of the DCTEncode filter. (devs.mak, int.mak, lib.mak,
+gdevjpeg.c)
+
+Refactors the PDF and PostScript output drivers so that both of them
+understand all the relevant documented PDF distiller parameters. (The
+PostScript driver currently disregards nearly all of them.) (gdevpdfx.h,
+gdevpsdf.h, gdevvec.h, gdevpdf*.c, gdevps.c, gdevpsdf.c, gdevpx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The MetroWerks C compiler gave an inexplicable error on a
+particular initialization. (gdevmem.h, gdevmem.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The insideness testing operators sometimes reported hits
+incorrectly. (zupath.c)
+ - Mixed-type arithmetic used floats rather than doubles when
+converting integers, possibly leading to loss of precision. (zarith.c,
+zrelbit.c)
+ - composefont was defined in a private dictionary, not in
+systemdict. (gs_cmap.ps)
+ - composefont didn't work, for several different reasons.
+(gs_cmap.ps)
+ - After a Type 1 font called an OtherSubr, an invalid memory access
+usually occurred, because of an incorrect attempt to free a data structure.
+(zchar1.c)
+ - 2 .setlanguagelevel gave an error if globaldict hadn't been
+defined yet. (zmisc2.c)
+
+Cleans up some warnings from picky compilers. Some of these actually
+indicated problems, such as unreachable code, or failure to check for
+(implausible) out-of-range data. (idict.c, idparam.c, igc.c, iinit.c,
+imain.c, iscan.c, zbseq.c, zchar1.c, zdps1.c)
+
+Adjusts clients for a change in the internal character cache structure and
+the introduction of the font next-glyph procedure. (zfont.c, zfont0.c)
+
+Refactors the Level 1 / Level 2 interpreter split slightly so that composite
+fonts don't require all of Level 2. (int.mak, gs_dps1.ps, gs_dps2.ps)
+
+Adds FMapType 9 (CMap-encoded) composite font support. (int.mak,
+gs_cmap.ps, ifont.h, zfcmap.c, zfont.c, zfont0.c)
+
+Interpreter (PDF)
+-----------------
+
+Adds recognition of /Identity values for BG, UCR, and TR functions in
+ExtGState resources. (General function values still aren't recognized.)
+(pdf_draw.ps)
+
+Centralizes the handling of inherited attributes. (pdf_draw.ps,
+pdf_main.ps)
+
+Starts to add support for Type 0 fonts. (pdf_font.ps, pdf_main.ps)
+
+Streams
+-------
+
+Cleans up some warnings from picky compilers. Some of these actually
+indicated problems, such as unreachable code. (shc.h, scfd.c, sfilter2.c,
+siscale.c, stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Some picky compilers disliked certain conditional expressions.
+(gxclread.c)
+ - Some picky compilers couldn't handle an extraneous semicolon.
+(gdevvec.h)
+ - A cast from byte ** to const byte ** was missing. (gdevvec.c)
+ - Resizing the levels array of a halftone order when banding could
+cause invalid memory accesses. (bug introduced in 4.60) (gxclread.c)
+ - One picky compiler didn't allow taking the address of an extern
+undefined structure. (lib.mak, gxclread.c)
+ - When rendering Type 1 fonts, character overshoot was usually
+suppressed when it shouldn't have been, often producing "squashed"
+characters. (gxhint1.c)
+ - On systems where sizeof(long) > sizeof(int), coordinate values of
+more than 22 bits were passed through the band list incorrectly, producing
+incorrect output. (gxclread.c)
+
+Cleans up some warnings from picky compilers. Some of these actually
+indicated problems, such as unreachable code or (hypothetical) loss of
+precision. (gsdevice.c, gshsb.c, gsht.c, gsstate.c, gstype1.c, gxclimag.c,
+gxclpath.c, gxclread.c, gxpdash.c)
+
+Makes using font hints conditional, for debugging. (gxhint1.c)
+
+Adds library-level support for FMapType 9 (CMap-encoded) composite fonts.
+There is still no support for rearranged fonts. (gsccode.h, gsfcmap.h,
+gsstruct.h, gxfcache.h, gxfcmap.h, gxfont.h, gxfont0.h, gschar.c, gschar0.c,
+gsfcmap.c, gsfont.c, gsfont0.c)
+
+Splits band list control and utilities from rectangle-oriented commands,
+because a file was getting too big. (gxclist.c, gxclrect.c)
+
+Moves the temporary file names for command lists from the printer device
+structure to the command list structure; moves opening and closing the
+temporary files from gdev_prn_alloc/free to clist_open/close. (gdevprn.h,
+gxclist.h, gdevprn.c, gxclist.c, gxclread.c)
+
+Changes the command list storage implementation interface to pass the file
+name to the clist_rewind and clist_fseek functions, for the benefit of OSs
+that require closing and reopening a file to switch between reading and
+writing. This is a NON-BACKWARD-COMPATIBLE change in a non-public
+interface. (gxclio.h, gxclmem.h, gxclfile.c, gxclist.c, gxclmem.c)
+
+Changes the get_outline procedure in Type 42 fonts to return the length of
+the outline data as well as the pointer. This is a NON-BACKWARD-COMPATIBLE
+change in a semi-public interface. (gxfont42.h, gstype42.c)
+
+Version 4.60(limited) (3/2/97)
+=====================
+
+This fileset moves color rendering up from the graphics state to the imager
+state so that color rendering can happen after banding. It also shifts
+image rendering to the rendering pass of banding for many common cases
+(often referred to inaccurately as "high-level image" capability). The
+changes involved are substantial and in some respects subtle, so
+unfortunately it is quite possible that some new bugs have been introduced.
+
+This fileset also includes improvements to the new PCL XL driver
+(pxlmono/color), and introduces an experimental PostScript driver (pswrite).
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The argument list of colorimage was incorrect. (zcolor1.c)
+ - false .charboxpath incorrectly claimed to create the correct path
+even when the CTM was not well-behaved. (language.txt)
+ - The discussion of the "main program" files was out of date.
+(make.txt)
+
+Updates the OS/2 EMX documentation. (make.txt)
+
+Modifies the Aladdin Ghostscript Free Public License slightly so it may be
+applied to other software packages. (PUBLIC)
+
+Updates inaccurate build documentation for several Unix platforms.
+(make.txt, ansihead.mak, cc-head.mak, gcc-head.mak, libpng.mak)
+
+Notes a problem with the MIPSpro 7.1 compiler. (make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Most makefiles didn't include version.mak. (msc.mak,
+msvcwint.mak, os2.mak, tctail.mak, wctail.mak)
+ - There was an incorrect dependency for the Windows printer device.
+(devs.mak)
+
+Moves the PDF writer to devs.mak. (devs.mak, int.mak)
+
+Updates the main VMS script to be structured like version.mak. (vms.mak)
+
+Drivers
+-------
+
+Factors out the stream-writing procedures from the PDF writer, so they can
+be shared with the new PostScript writer. (gdevpdfs.h => gdevpstr.h,
+gdevpdfx.h, gdevpsdf.h, gdevpdf.c, gdevpdfi.c, gdevpdfs.c => gdevpstr.c,
+gdevpdft.c, gdevpsdf.c)
+
+Adds a PostScript writer (pswrite), similar to the PDF and PCL XL drivers.
+Currently this handles fill/stroke graphics and Level 1 images; everything
+else (including text) is turned into bitmaps. (devs.mak, gdevps.c)
+
+Changes the names of the PCL XL drivers from hpxmono/color to pxlmono/color.
+(devs.mak, gdevpx.c)
+
+Updates the "vector" device support interface. THIS IS STILL SUBJECT TO
+CHANGE WITHOUT NOTICE. (gdevvec.h, gdevpx.c, gdevvec.c)
+
+Makes the vgalib driver a page device. This seems bizarre, but it's
+necessary for setpagedevice to work with it. (gdevvglb.c)
+
+Updates some drivers for the new color mapping interfaces. (gdevpx.c)
+
+Updates the user-contributed Canon LBP-8II and LIPS III driver.
+(gdevlbp8.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The workaround for Ultrix's incorrect implementation of sh -e
+still didn't work. (unixtail.mak)
+ - The definition of offset_of didn't work on the Mac. (stdpre.h)
+
+Updates the OS/2 EMX linker command per input from a user. (os2.mak)
+
+Fonts
+-----
+
+Adds .pss (apparently used by Adobe for Multiple Master font instances) to
+the list of extensions skipped by the GS_FONTPATH directory scanner.
+(gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Programs that rebind null, true, and/or false could cause all
+kinds of problems. We've only fixed a couple of the places that might be
+affected (findfont, quit), by wrapping an explicit "systemdict begin/end"
+around the code; fixing this completely would probably require wrapping this
+implicitly around almost every pseudo-operator, which would be too
+expensive. (gs_fonts.ps, gs_lev2.ps)
+ - In a Level 2 system, grestoreall stopped one level too early.
+(zdevice2.c)
+ - setpagedevice didn't restore the stack properly if it got an
+error. (gs_setpd.ps)
+
+Changes the GC pointer enumeration interface to reduce the number of
+'discarding const' warnings. See under Library below. (igc.c)
+
+Updates the interpreter for the change in the imager / graphics state split.
+(zpcolor.c)
+
+Makes the stack-restoring behavior of pseudo-operators non-optional.
+(interp.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - PDFDocEncoding and WinAnsiEncoding incorrectly had `minus' at
+position 45 rather than `hyphen'. (gs_pdf_e.ps, gs_wan_e.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - A header file wasn't protected against double inclusion.
+(stream.h)
+ - any_abs was redefined. (spngp.c)
+ - The CCITTFaxDecode filter didn't fully initialize the "previous
+line" for 2-D decoding, so if the very first line of data was 2-D, an
+out-of-bounds memory access could occur. (scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - gs_image_next could read too much data, causing errors at the
+interpreter level. (gsimage.c)
+ - The bitmaps stored in the Pattern cache were usually freed,
+leaving dangling pointers. (gsdcolor.h, gxpcache.h, gxpcolor.h, gsstate.c,
+gxpcmap.c)
+ - There was still one assignment to a const structure, and there
+were some unnecessary const-discarding casts. (gxclread.c)
+ - If a character in a Type 3 font was defined by executing 'show'
+type commands, charpath did the wrong thing (didn't pick up the paths
+created by the inner show). Similarly, if it uses 'stroke', true charpath
+did the wrong thing (appended the path rather than the strokepath path).
+(gxchar.h, gschar.c, gspaint.c)
+ - A header file wasn't protected against double inclusion.
+(gserror.h)
+ - The new fast implementation of rectfill didn't handle rectangles
+with negative width/height. (bug introduced in 4.32) (gsdps1.c)
+ - Reading banded high-level images calculated the image height
+incorrectly, (usually) causing a rangecheck. (gxclread.c)
+ - When reading band data, a memory fault could occur if the halftone
+cache hadn't been allocated yet. (gxht.c)
+ - The imager state data for high-level images wasn't written soon
+enough. (gxclimag.c)
+ - High-level images computed bounding boxes incorrectly, so they
+could write some garbage data in the band list, and could also fail to write
+some information. (gsmatrix.h, gxmatrix.h, gxclimag.c)
+ - High-level images wrote the raster value incorrectly in the band
+list. (gxclimag.c)
+ - Images with non-zero initial source X and non-portrait orientation
+were displaced on the page. (In practice, this only applied to some banded
+high-level images.) (gximage.c)
+ - The bounding box device didn't forward output_page calls, causing
+pages to be dropped or overprinted. (gdevbbox.c)
+ - The band renderer considered all non-zero return codes as errors,
+rather than only negative codes. (gxclread.c)
+ - An unnecessary extern hadn't been removed. (gxclimag.c)
+ - Some macros didn't parenthesize uses of their arguments, causing
+syntax errors. (gsrefct.h)
+ - The screen phase and color_info weren't set correctly when
+rendering bands. (gsstate.h, gsht.c, gxclread.c)
+ - A header file didn't declare all the opaque types it used.
+(gsdevice.h)
+ - Indexed color spaces didn't work with banded images. (They still
+don't -- the check for writing the color space, and the code for reading the
+table or map, are incomplete.) (gxclist.h, gxclpath.h, gxclimag.c,
+gxclpath.c, gxclread.c)
+
+In preparation for implementing post-banding halftoning:
+
+ - Moves color rendering information, including alpha value, from
+graphics state to imager state; also moves the allocator pointer. This is
+quite a subtle change, and may have a significant bug tail. (gxdcolor.h,
+gxht.h, gxistate.h, gzstate.h, gschar.c, gsdps1.c, gspaint.c, gsstate.c,
+gxclread.c)
+
+ - Changes all the relevant color space and color mapping procedures
+so they take a const gs_imager_state * (and, in some cases, a [const]
+gx_device *) instead of a const gs_state *. This is a
+non-backward-compatible change, but it only affects internal interfaces.
+(gsdcolor.h, gxcmap.h, gxcspace.h, gxdcconv.h, gxdcolor.h, gxdither.h,
+gxpcolor.h, gzht.h, gschar.c, gscie.c, gscolor.c, gscolor1.c, gscolor2.c,
+gscsepr.c, gsdevice.c, gsimage.c, gspcolor.c, gxcht.c, gxcmap.c, gxdcconv.c,
+gxdcolor.c, gxht.c, gximage.c, gximage[2345].c, gxpcmap.c)
+
+ - Changes the color and color space reference count adjustment
+procedures similarly, to take a gs_memory_t * instead of a gs_state_t *.
+(gxcspace.h, gscie.c, gscolor.c, gscolor2.c, gscsepr.c, gspcolor.c)
+
+ - Changes the gs_halftone in the graphics state from being part of
+the gs_state_contents to being an independent reference-counted object.
+This too may have a significant bug tail. (gxht.h, gxistate.h, gsht.c,
+gsstate.c)
+
+ - Changes the image processing code so it no longer assumes that the
+gs_imager_state is actually a gs_state. (gximage.h, gximage.c, gximage2.c,
+gximage3.c, gximage4.c, gximage5.c)
+
+ - Adds a unique ID value to device halftones, so that it's possible
+to detect (non-)changes quickly. (gxdht.h, gsht.c)
+
+Finishes the code for writing and reading color rendering information in the
+band list. This involves changes to several band list opcodes. (gsht.h,
+gsht1.h, gxcldev.h, gxclist.h, gxclpath.h, gxdht.h, gzht.h, gsht.c, gsht1.c,
+gxclbits.c, gxclimag.c, gxclist.c, gxclread.c)
+
+Changes the garbage collector pointer enumeration procedure interface
+slightly to reduce the number of 'discarding const' warnings. THIS IS A
+NON-BACKWARD-COMPATIBLE CHANGE for anyone who didn't use the
+ENUM_PTRS_BEGIN[_PROC] macro to start a pointer enumeration procedure (which
+should be no one). (gsstruct.h, gsmemory.c)
+
+Corrects a few more needlessly const-discarding casts. (gxfcache.h,
+gxccache.c)
+
+Checks for file reading errors when rasterizing bands. (gxclread.c)
+
+Version 4.51(limited) (2/9/97)
+=====================
+
+This version contains a more reasonable high-level PCL XL driver. The VMS
+build script is working again, we think.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The gsdll_h macro wasn't defined all the places it was needed.
+(devs.mak, os2.mak)
+
+Drivers
+-------
+
+Continues to develop the "vector" driver infrastructure and the PCL XL
+driver. EVERYTHING IN THESE FILES IS SUBJECT TO CHANGE WITHOUT NOTICE.
+(gdevvec.h, gdevvec.c)
+
+Brings the PCL XL driver up to usable quality for graphics. Most
+fill/stroke graphics, and portrait-orientation bitmap images up to 8 bits
+per pixel, are converted directly to their PCL XL equivalents. Text is
+still treated as bitmaps. Both gray-scale and color output are now
+supported. (devs.mak, gdevpx.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - When using gsos2.exe with gsdll2.dll, reducing the size of the
+page bitmap caused a limitcheck error with the message
+ Failed to decommit memory in pm_alloc_bitmap, rc = 87 (gdevpm.c)
+ - The scripts that construct gconfig_.h failed on Ultrix, because
+Ultrix's implementation of sh -e is incorrect. (unixtail.mak, ugcclib.mak)
+ - Some systems that have sys/times.h don't define CLK_TCK, making a
+compilation fail. (time_.h)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - An omitted semicolon wasn't detected by gcc. (idict.c)
+
+Removes a source of unnecessary duplication by getting the revision number
+and date from version.mak. (gs.mak, int.mak, version.mak, gscdef.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The minimum buffer sizes for the RunLengthDecode filter hadn't
+been changed to reflect the algorithm improvement made in release 4.38.
+(srld.c)
+
+Changes the RunLengthEncode filter so it can make progress with only a
+2-byte output buffer. (srlx.h, srle.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Because of a typo, the slow general algorithm was always used for
+monochrome images. (Performance bug only, but a serious one.) (gximage2.c)
+ - Dots (zero-length lines with round caps and zero dot length)
+caused an infinite loop. (bug introduced in 4.40) (gxstroke.c)
+ - Some image data unpacking procedures were always required, but
+weren't always included. (bug introduced in 4.50) (gximage.c, gximage0.c,
+gximage3.c)
+ - Images with 8 bits per pixel and non-identity Decode produced
+garbage. (bug introduced later than 4.03) (gximage0.c)
+ - Some necessary casts and omitted punctuation weren't detected by
+gcc. (gxpath.h, gsargs.c, gsstate.c, gxclread.c, gxpdash.c)
+ - The band list became confused if a band had no commands at all.
+(gxclread.c)
+ - If a path included a closepath followed by a moveto to the same
+point, it could be written incorrectly in the band list. (bug probably
+introduced in 3.60) (gxclpath.c)
+
+Changes some internal computations for arcs from float to double for greater
+accuracy. (gspath1.c)
+
+Version 4.50(limited) (1/31/97)
+=====================
+
+This release contains an experimental high-level PCL XL driver, a little
+more support for CID/CMap fonts, and the usual bug fixes. NOTE: the VMS
+build script is known to be out of sync with the makefiles again; we still
+don't see any alternative to constant struggles with this problem.
+
+Documentation
+-------------
+
+Corrects the -h message, which gave an incorrect file name for the bug
+report form. (imainarg.c)
+
+Removes documentation for 16-bit MS-DOS platforms with the Borland compiler.
+(fonts.txt, make.txt, new-user.txt, use.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The Watcom library makefile didn't define the directory
+information for libpng and zlib. (watclib.mak)
+
+Moves the selection of band list implementation (file- vs. RAM-based) and
+the compression filter for RAM-based band lists up to the top-level
+makefiles. Again, this is a NON-BACKWARD-COMPATIBLE procedure change.
+(lib.mak, *.mak)
+
+Moves the selection of version number for all platforms (except VMS, as
+usual) to a separate file. This will reduce the number of files that need
+editing when the version number changes. (ansihead.mak, cc-head.mak,
+gcc-head.mak, ugcclib.mak, version.mak, tar_cat)
+
+Drivers
+-------
+
+Fixes bugs:
+ - An error in the (unsupported) SGI RGB driver could cause crashes
+or incorrect output. (gdevsgi.c)
+
+Starts to create a framework for structured output ("vector") drivers (PDF,
+PostScript, PCL XL, etc.) (gdevbbox.h, gdevvec.h, gsdcolor.h, gsstruct.h,
+gxdevice.h, gdevvec.c)
+
+Moves default page size parameters to a more accessible header. (gdevprn.h,
+gxdevice.h, gdevx.c)
+
+Adds a driver that produces properly structured PCL XL output. This is
+highly experimental and not ready for use yet. (gdevpx.c)
+
+Platforms
+---------
+
+Removes support for 16-bit MS-DOS platforms with the Borland compiler. For
+the moment, 16-bit MS Windows is still supported. (bc.mak, bcflags.mak,
+bclib.mak, tc.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - File-based CIDFonts (with delayed, incremental loading of
+character outlines) didn't work. (gs_cidfn.ps)
+
+Finishes implementing the definition of CMap resources, except for
+rearranged fonts. (gs_cidfn.ps, gs_cmap.ps)
+
+Adds a little more CMap support code. (zcid.c)
+
+Removes the .setcurrentfile operator, since it doesn't solve the problem it
+was intended to address. (zcontrol.c)
+
+Adapts the interpreter to use the new argument processing code.
+(imainarg.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxDecode filter could access as much as 3 bytes beyond
+the end of a buffer, causing an invalid memory access. (This is essentially
+the same bug that was fixed for the CCITTFaxEncode filter in 4.38.)
+(scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Painting an image without having set up any halftone could cause a
+crash. (gxht.c)
+ - In a very obscure case, an occasional scan line of landscape
+images could get corrupted. (gximage0.c)
+ - Because of a rounding error, patterns could fail to be painted in
+certain cases. (gxpcolor.h, gspcolor.c, gxpcmap.c)
+ - Very large line widths or miter limits could cause the computation
+of stroke expansion to overflow. (gxpaint.h, gdevbbox.c, gxclpath.c,
+gxstroke.c)
+ - The phase could be incorrect for simple patterns. (gspcolor.c)
+ - The default implementation of copy_mono used an incorrect
+RasterOp. (gdevdflt.c)
+ - The default implementation of fill_masked didn't increment the row
+pointer, causing characters to appear as solid rectangular blocks.
+(gxdcolor.c)
+
+Eliminates an unnecessary gsave and grestore from rectfill and rectstroke if
+the path was null. (gsdps1.c)
+
+Adds a limit on the amount of space that the default (C heap) allocator will
+allocate, and a record of the maximum amount allocated, to help testing
+embedded products. (gsmemory.c)
+
+Changes the band list algorithm for deciding how many replicas of a halftone
+tile to store in the tile cache. The previous algorithm was too liberal,
+which could cause the cache to overflow and many unnecessary bitmaps to be
+written in the band list. (gxclbits.c)
+
+Writes clipping with a rectangle more compactly in the band list.
+(gxfixed.h, gxclpath.c)
+
+Adds new band list commands for representing 90- and 180-degree arcs
+compactly. (gxclpath.h, gxclpath.c, gxclread.c)
+
+Repackages handling of general monochrome images, color images, and 12-bit
+and interpolated images, so that they are included optionally rather than in
+all configurations. (int.mak, lib.mak, gximage.h, gximage.c,
+gximage[12345].c)
+
+Changes the structure definition for devices to include no-op pointer
+enumeration and relocation, so they can have subclasses. (gxdevice.h)
+
+Adds a library facility for processing command line arguments with
+@-expansion. (gsargs.h, gsargs.c)
+
+Version 4.41(private) (1/21/97)
+=====================
+
+This release adds a PCL XL output driver, and a few performance
+improvements.
+
+Procedures
+----------
+
+Fixes bugs:
+ - The zlib library used an incorrect header file when compiling.
+(zlib.mak)
+
+Changes the names of the preprocessor symbols indicating the presence of
+system header files to be consistent with the ones used by GNU configure.
+(dvx-tail.mak, ugcclib.mak, unixtail.mak, vms.mak; dirent_.h, time_.h;
+gp_unix.c)
+
+Changes the method for choosing the compression filter for RAM-based band
+lists. This is a NON-BACKWARD-COMPATIBLE change in the makefile. (lib.mak)
+
+Drivers
+-------
+
+Adds black-and-white and 8-bit gray PCL XL (PCL 6) drivers for the LaserJet
+5 and 6 family. This driver is extremely simple and just emits bitmaps;
+future drivers will use more PCL XL high-level constructs. (gdevlj56.c)
+
+Fonts
+-----
+
+Updates the free font distribution to add the URW Grotesk and Antiqua fonts.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - gs -h and -v returned with a non-zero exit code on all platforms.
+(This is necessary under Windows, to keep the message visible on the screen,
+but nowhere else.) (imainarg.c)
+ - Resizing a dictionary could exceed dict_max_size, causing memory
+corruption. (dstack.h, idict.h, idict.c, zdict.c)
+
+Adds .setlinecap and .setlinejoin that can use the extended range of line
+cap/join values, and redefines setlinecap and setlinejoin in terms of them.
+(gs_init.ps, zgstate.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxDecode filter with EncodedByteAlign = true skipped to
+a byte boundary before checking for an EOL. This may be wrong if EndOfLine
+= true; we aren't at all sure what should happen if EndOfLine = false.
+(scfd.c)
+
+Adds a "no wrapper" option to the zlib streams, to optionally suppress the
+time-consuming integrity checksum computation. (szlibx.h, szlibc.c,
+szlibd.c, szlibe.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Dashed lines with zero-length drawn segments (dots) that fell
+exactly on a corner produced inappropriate output. (pcl/test19.pxs)
+(gxpdash.c, gxstroke.c)
+ - Dashed lines didn't set the segment notes properly. (gxpdash.c)
+ - The bounding box device didn't free a bookkeeping structure at the
+end of processing an image. (gdevbbox.c)
+ - Curve points could get computed incorrectly when using emulated
+floating point. (gxpcopy.c)
+ - The 1-element cache for curve_x_at_y didn't work if Y was
+decreasing. (gxfixed.h, gxpcopy.c)
+
+Distinguishes between error and informational exits. (stdpre.h)
+
+Defines and checks maximum values for line cap and join parameters.
+(gslparam.h, gsline.c)
+
+Removes the 'not last' segment note, since it is not used for anything.
+(gxpath.h, gspath1.c, gxpath2.c, gxpcopy.c, gxpflat.c, gxstroke.c)
+
+Changes the memory freeing algorithm for RAM-based band lists back to the
+original one, since the "improved" one had more bugs than it was worth
+chasing. (gxclmem.c)
+
+Speeds up the A * B / C algorithm a little. (gsmisc.c)
+
+Speeds up curve_x_at_y by recognizing more cases that don't require the slow
+A * B / C algorithm. (gxpcopy.c)
+
+Changes the path filling code so it uses fill-by-trapezoids even if
+fill_adjust is zero, as long as the flatness is at least 1 pixel.
+(gxfill.c)
+
+Removes the (unneeded) floating point operations from gx_curve_log2_samples.
+(gxpflat.c)
+
+Changes the memory-based implementation of band lists so that it constructs
+the compressor and decompressor by calling procedures rather than
+instantiating templates: this allows setting filter parameters to
+non-default values. (gxclmem.h, gxcllzw.c, gxclmem.c, gxclzlib.c)
+
+Version 4.40(private) (1/13/97)
+=====================
+
+This version finally handles the last graphics model discrepancies between
+PostScript and PCL, by correctly implementing null joins, minimum dot
+lengths, and tangent-aligned curve ends. It also contains some significant
+performance improvements, and as usual a few bug fixes.
+
+Documentation
+-------------
+
+Documents the new accurate curves and path dashing operators.
+(language.txt)
+
+Utilities
+---------
+
+Adds switches for genconf to set and unset a prefix for file names.
+(genconf.c)
+
+Drivers
+-------
+
+Adds recognition of the new Distiller 3.0 parameters to the PDF writer.
+(None of them have any effect yet.) (gs_pdfwr.ps, gdevpdfx.h, gdevpdf.c,
+gdevpdfp.c)
+
+Converts all the output functions in the PDF writer from being file-based to
+using streams, in anticipation of adding compression. (gdevpdfs.h,
+gdevpdfx.h, gdevpdf*.c, gdevpdfs.c)
+
+Interpreter
+-----------
+
+Adds operators for accessing the new accurate curves flag in the graphics
+state. (zgstate.c)
+
+Adds an operator for invoking gs_dashpath. (zpath1.c)
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - Indexed color spaces whose base space was a CIE space caused an
+error. (pdf_draw.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - A pointer was declared const incorrectly. (gxcpath.c)
+ - Filling with a pattern often failed to pass a non-null bitmap ID,
+causing excessive writing in the band list. (Performance bug only.)
+(gspcolor.c)
+ - The bounding box device didn't discount copy_mono or draw_line
+operations drawing in white. (gdevbbox.c)
+ - The bounding box device didn't read out the bounding box correctly
+as the PageBoundingBox device parameter. (It did return it correctly
+through the gx_device_bbox_bbox procedure.) (gdevbbox.c)
+ - The default implementation of fill_triangle drew nothing or
+incorrect output if the corners of the triangle were specified in certain
+orders (ax < 0 or bx < 0) (i.e., the previous "fix" had a bug).
+(gdevddrw.c)
+
+Changes tile size from always being set in all bands to being 'known' by
+bands individually. (gxclist.h, gxcldev.h, gxclbits.c, gxclist.c)
+
+Computes an additional value in advance when rendering images. (gximage.h,
+gximage1.c, gximage2.c)
+
+Replaces some slow loops with calls of memmove. (gxclmem.c)
+
+Provides a fixed-point implementation of A * B / C for machines with slow
+floating point. (gxfixed.h, gsmisc.c)
+
+Extends the "device color" type to implement filling masked regions as well
+as rectangles. (gxdcolor.h, gdevdflt.c, gspcolor.c, gxcht.c, gxdcolor.c,
+gxht.c)
+
+Makes unclipped monobit portrait and landscape images and image masks use
+the new masked fill capability of device colors. (gximage.h, gximage.c,
+gximage1.c, gximage2.c)
+
+Adds a macro for determining pointer alignment. (stdpre.h, gdevdflt.c)
+
+When floating point is slow, uses a different, faster algorithm for
+gx_curve_x_at_y. (gxpcopy.c)
+
+Improves performance by adding a one-element cache for gx_curve_x_at_y.
+(gzpath.h, gxpcopy.c)
+
+Reduces overhead when banded images are pre-rasterized (currently, always).
+(gxclimag.c)
+
+Adds a rendering cost estimate field to each band in a band list. This
+field isn't actually used for anything yet; eventually, the intent is that
+bands with a high cost will get rendered, and stored in compressed form,
+before starting the engine. (gxclist.h)
+
+Adds the concept of 'notes' for path segments, to allow remember what
+segments constitute a single curve or arc. Currently we set these properly
+for everything except dashed paths. (gxclpath.h, gxpath.h, gzpath.h,
+gspath1.c, gxclpath.c, gxclread.c, gxpath.c, gxpath2.c, gxpcopy.c)
+
+When the dot length is non-zero, changes curve stroking to always use bevel
+joins within each curve rather than the current join. This prevents a
+"bristly" look with no join and butt caps. (gxstroke.c)
+
+Adds an "accurate curves" capability that makes the last line segment of a
+flattened curve actually be tangent to the curve, which in turn makes
+flat-end caps be correctly perpendicular to the tangent. (gxpath.h,
+gxpcopy.c)
+
+Adds an "accurate curves" flag in the graphics state. (gsline.h,
+gxclpath.h, gxistate.h, gsline.c, gspath.c, gspath1.c, gxclpath.c,
+gxclread.c, gxfill.c, gxstroke.c)
+
+Changes the meaning of "no join" (gs_join_none) so that instead of producing
+no join and butt caps, it produces whatever the current cap is. This is
+compatible with the H-P definition. (gxstroke.c)
+
+Implements non-zero dot length for dash patterns. (gxpdash.c)
+
+Splits off the curve flattening algorithms into a separate file.
+(gxpcopy.c, gxpflat.c)
+
+Version 4.39(limited) (1/1/97)
+=====================
+
+This version was created only to accompany a release of the PCL XL
+interpreter. It was withdrawn the day after it was released, because the
+tools used to produce it put the wrong files in the filesets.
+
+Documentation
+-------------
+
+Adds a more detailed description of the third-party ps_view viewer
+interface. (new-user.txt)
+
+Corrects an error in a reference to the PSLRM. (lib.txt)
+
+Documents the change in .makeoperator. (language.txt)
+
+Updates the FTP location of the zlib sources. (zlib.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The Unix library makefile didn't include the necessary definitions
+for libpng and zlib. (ugcclib.mak)
+
+Allows selecting the compression filters for memory-based band lists in the
+makefile. Makes zlib (deflate) the default compressor for memory-based band
+lists. (lib.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - prfont.ps wouldn't print unencoded characters in Type 42 fonts.
+(prfont.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The H-P monochrome driver didn't put out enough initialization
+commands at the beginning of each page to make each page printable
+independently. (gdevdjet.c)
+
+Interpreter
+-----------
+
+Changes ref_stack_count_inline so it never does a procedure call.
+(istack.h)
+
+Changes .makeoperator so that operator procedures save the stack depths, and
+restore the stack pointers (if possible) if the operator encounters an
+error. This is a NON-BACKWARD-COMPATIBLE CHANGE; it requires rewriting the
+'stop' and 'stopped' pseudo-operators (and, if there were any, any other
+pseudo-operators that interact with the error handling machinery) in C.
+(gs_init.ps, interp.c, zcontrol.c)
+
+Adds recognition of the LeadingEdge, MediaClass, and RollFedMedia keys in a
+page device dictionary, per the Adobe supplement for their version 2017
+interpreter. This involves a NON-BACKWARD-COMPATIBLE change to the
+(undocumented) .matchpagesize operator. (gs_setpd.ps, zmedia2.c)
+
+Makes necessary changes for compatibility with the added parameters for the
+zlib filters. (zfzlib.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The zlib encoder returned EOFC when it should have returned 0.
+(szlibe.c)
+
+Adds optional parameters and reset procedures for the zlib filters.
+(szlibx.h, szlibc.c, szlibd.c, szlibe.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Displaying characters with a non-standard RasterOp could cause an
+invalid memory access. (gdevdflt.c)
+ - Banding sometimes used an incorrect RasterOp. (gxclread.c)
+ - When banding, mixing Patterns and halftones could confuse the
+bookkeeping of tile size, leading to incorrect generation of the band list
+and error messages or confusion when rasterizing. (gxclist.h, gxclbits.c,
+gxclread.c)
+ - If only the dash pattern offset changed, and not any of the other
+dash-related parameters, the new offset wasn't written in the band list,
+causing incorrect output. (gxclpath.c)
+ - Oversized halftone tiles didn't report their error code properly.
+(gxclbits.c)
+ - Oversized halftone tiles with RasterOp caused an error.
+(gxclist.c)
+ - When banding, RasterOp transfers that crossed a band boundary
+didn't access the correct source data on bands other than the first.
+(gxclist.c)
+ - There were redundant copies of the code for writing a RasterOp
+value in the band list. (gxclimag.c, gxclpath.c)
+ - Oversized patterns or halftones produced garbled output.
+(gxclbits.c)
+ - The check for oversized patterns or halftones was slightly
+incorrect, leading to the possibility of writing out a tile that would
+overflow the reading buffer and corrupt memory. (gxclbits.c)
+ - When banding, RasterOp wasn't applied to fill and stroke
+operations, and wasn't applied correctly to characters. (gdevdflt.c,
+gxclimag.c, gxclread.c)
+ - The RasterOp-related optimizations for black-and-white images
+sometimes produced incorrect output. (gximage.c, gximage2.c)
+ - The default implementation of fill_triangle didn't draw anything
+if the corners of the triangle were specified in certain orders (ax < 0 or
+bx < 0). (gdevddrw.c)
+ - Painting with a Pattern could pass out-of-range phase values to
+driver procedures. (gspcolor.c)
+ - Because of an off-by-1 error, halftones or patterns passed through
+the band list could write past the end of their allocated space in the band
+tile cache, leading to incorrect output or possible arithmetic exceptions or
+memory access errors. (gsbitops.c)
+
+Adds -Z: for printing only the minimal command list statistics. (gxclist.c,
+gxclread.c)
+
+Expands band list tracing so it includes all of the data associated with the
+command, not just the command name and a few command parameters.
+(gxclread.c)
+
+Adds free lists for strings. Currently these are only used in
+non-garbage-collected environments. (gxalloc.h, gsalloc.c, gsnogc.c)
+
+Adds a procedure for copying a path structure, and an (internal) accessor
+for the current path in the graphics state. (gxpath.h, gspath.c, gxpath.c)
+
+Speeds up filling characters with halftones a little bit. (gdevdflt.c)
+
+Changes the memory-based implementation of band lists so it can use any
+compression / decompression filter, so it only compresses when it has
+allocated a specified amount of buffer storage, and so it releases its
+buffer storage at the end of each page. (gxclmem.h, gxclmem.c)
+
+Speeds up counting the number of 1-bits in a byte, which is used in some
+image processing algorithms. (gsbittab.h, gsbittab.c)
+
+Reduces the band list space required for changing tile size. (gxcldev.h,
+gxclbits.c, gxclread.c)
+
+Version 4.38(limited) (12/20/96)
+=====================
+
+Adds support for a couple of undocumented features in Type 1 fonts.
+
+Interpreter
+-----------
+
+Adds handling of the Type 1 font subroutineNumberBias (an optional entry in
+the Private dictionary) and lenIV = -1 features at the interpreter level.
+(zchar1.c, zfont1.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - The CCITTFaxEncode filter could access as much as 3 bytes beyond
+the end of a buffer, causing an invalid memory access. (scfe.c)
+
+Changes the RunLengthDecode filter so it can make progress (produce output)
+with only a 1-byte output buffer. (srlx.h, srld.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The sine and cosine of multiples of 90 degrees weren't exact.
+(gxfarith.h, gsmisc.c)
+ - The expanded bounding box computation for strokes didn't take into
+account the possibility of overflow. (gxstroke.c)
+ - The allocator didn't fill freed strings with the 'free' mark.
+(gsalloc.c)
+ - When using a pattern with RasterOp, the phase was computed
+incorrectly, leading to anomalous filling patterns. (gspcolor.c)
+ - Patterns with a non-zero translation in the matrix passed to
+makepattern didn't translate the pattern origin properly. (gxcolor2.h,
+gxpcolor.h, gspcolor.c)
+
+Adds a subroutineNumberBias field to Type 1 fonts. This is an undocumented
+feature of the Type 1 font format. (gxfont1.h, gstype1.c)
+
+Interprets lenIV = -1 in Type 1 fonts as meaning that the CharStrings are
+unencrypted. This too is an undocumented feature of the Type 1 format.
+(gxfont1.h, gxtype1.h, gstype1.c, gstype2.c)
+
+Changes gs_clippath so it returns more reasonable outlines. (There are too
+many programs that rely on being able to stroke the result of clippath, even
+though both the Adobe and H-P literature specifically say the results are
+unpredictable.) (gxcpath.h, gxcpath.c)
+
+Version 4.37(limited) (12/10/96)
+=====================
+
+This version implements separate halftone phase for source and texture,
+required for PCL XL implementation.
+
+Fonts
+-----
+
+Fixes bugs:
+ - Loading a native TrueType font without a 'post' table caused an
+error. (gs_ttf.ps)
+
+Interpreter
+-----------
+
+Extends the interpreter to handle the new separate halftone phases for the
+RasterOp source and texture. (gs_dps1.ps, zdps1.c)
+
+Makes a small change to accommodate a library change supporting Type 2
+charstrings. (zfont1.c)
+
+Interpreter (PDF)
+-----------------
+
+Implements the FontFile2 key for embedded TrueType fonts. (pdf_font.ps)
+
+Starts to implement the FontFile3 key for compressed Type 1 fonts. This
+code is currently disabled, because none of the necessary underlying C is
+written yet. (pdf_font.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The floating point emulator often returned incorrect results (too
+many bugs to list). (This is not used in any standard configuration.)
+(gsfemu.c)
+ - The new copy_for procedure for gstates incorrectly declared an
+argument as const. (gxstate.h, gsstate.c)
+ - If a curve had to be split twice along the same axis to make it
+monotonic, the split points could still be returned in the wrong order,
+possibly causing curved edges to turn into straight lines, and the algorithm
+still produced the wrong results if the curve had to be split twice along a
+single axis. This is the second time we have "fixed" these problems and the
+4th time we have "fixed" the curve monotonizing algorithm. (gxpcopy.c)
+ - Setting halftones cause a memory leak, because the subsidiary
+objects of the device halftone weren't freed properly. Fixing this required
+changing the graphics state implementation from allocating a device halftone
+for each gstate to managing the device halftone with reference counting.
+(gxdht.h, gzstate.h, gsht.c, gsstate.c)
+
+Provides an optimized version of ldexp for FPU-less configurations, and
+changes one key algorithm to use it. (gxfixed.h, gsmisc.c, gxpcopy.c)
+
+Speeds up imagemask with a halftone a little. (This will eventually require
+more serious optimization.) (gximage2.c)
+
+Adds a -Z* switch for tracing varieties of image rendering. (gximage.c)
+
+Recognizes that if the logical operation is equivalent to D = S (after
+accounting for a constant texture, if any), or if it is equivalent to D = ~S
+or D = D {&,|}{S,~S} and D and S are both monobit and both colors are pure,
+imaging with RasterOp can be executed without invoking RasterOp. (gsropt.h,
+gximage.c)
+
+Makes coordinate transformations with landscape matrices execute as fast as
+with portrait matrices. (gxmatrix.h, gscoord.c, gsmatrix.c)
+
+Adds some sketch code for interpreting Type 2 charstrings. It compiles, but
+it makes no pretense of being runnable. (gstype1.h, gxop1.h, gxtype1.h,
+gstype2.h, gxfont1.h, gstype1.c, gstype2.c)
+
+Extends the library to allow setting separate halftone phases for the
+RasterOp source and texture, which is needed to implement halftone screens
+that behave like those in H-P's PCL XL printers. (gscsel.h, gsstate.h,
+gxcmap.h, gxcspace.h, gxdcolor.h, gxdither.h, gxpcolor.h, gzht.h, gzstate.h,
+gscie.c, gscsepr.c, gsht.c, gspcolor.c, gxcht.c, gxcmap.c, gxdcolor.c,
+gxht.c, gximage.c, gximage[2345].c, gspcmap.c) ****** STILL NEED TO UPDATE
+BANDING CODE, grep FOR phase ******
+
+Removes the rc_header member from the gs_halftone structure, since we don't
+need it after all. (gxht.h)
+
+Version 4.36(limited) (12/3/96)
+=====================
+
+This version fixes a number of library bugs related to RasterOp, Patterns,
+and memory management.
+
+Documentation
+-------------
+
+Changes the definition of texture transparency to match the peculiar H-P
+specification. (drivers.txt, language.txt)
+
+Drivers
+-------
+
+Fixes bugs:
+ - x_get_bits didn't flush updates to the frame buffer, leading to
+possibly incorrect data being returned. (gdevx.c)
+ - x_get_bits added padding to the scan line being copied, possibly
+corrupting memory. (gdevx.c)
+
+Changes the x11mono driver to define white = 0, black = 1 to more closely
+model black-and-white printers. (This is an internal change that doesn't
+affect the output.) (gdevxalt.c)
+
+Interpreter
+-----------
+
+Removes some code that is no longer needed, by virtue of the fix for the
+memory leak in Pattern remapping. (zpcolor.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Patterns wider than 1024 bits caused a rangecheck. (gxclip2.h,
+gxclip2.c)
+ - Dash patterns never got freed. The fix for this slows down gsave
+and grestore slightly, but we don't see any way around it. (gsline.c,
+gsstate.c)
+ - If the CTM was very non-uniform in X and Y, stroke sometimes
+didn't recognize thin lines as being thin, leading to dropouts.
+(gxstroke.c)
+ - RasterOps that didn't use S or T still took S or T transparency
+into account. (gdevmrop.c)
+ - RasterOps with no source didn't handle the possibility that the
+device color for black might have a value other than 0. (gxdcolor.h,
+gspcolor.c, gxcht.c, gxdcolor.c, gxht.c)
+ - White pixels in halftones on black-and-white devices apparently
+are *not* supposed to be treated as opaque for RasterOp. (gxcht.c, gxht.c)
+ - clippath caused memory to be lost until a restore or a garbage
+collection. (gspath.c)
+ - Clipping lists weren't ever freed, and clipping paths sometimes
+weren't freed, causing memory to be lost until a restore or a garbage
+collection. (gzacpath.h, gxacpath.c, gxcpath.c)
+ - Freeing a pattern instance referenced a pointer after it had been
+freed, causing an invalid memory access. (gspcolor.c)
+ - Remapping a Pattern color lost track of the temporary gstate,
+memory devices, and possibly the mask, causing memory to be lost until a
+restore or GC. (gxpcolor.h, gxpcmap.c)
+ - Remapping a Pattern color could cause paths to be marked as
+shared, preventing them from being freed until a restore or GC. (gxpcmap.c)
+
+Enhances the non-tracing garbage collector so that if there are no strings
+allocated at all, it resets the string allocation pointers. (gsnogc.c)
+
+Optimizes the black-and-white RasterOp implementation by recognizing cases
+that can be implemented directly by fill_rectangle, copy_mono, or
+tile_rectangle. (gdevmrop.h, gsropt.h, gdevmrop.c, gsroptab.c)
+
+Changes -ZA so it no longer produces [P] tracing messages for path
+construction. (gxpath.c)
+
+Adds a gx_pattern_cache_winnow procedure for selectively removing entries
+from the Pattern cache, similar to gx_purge_selected_cached_chars.
+(gscolor2.h, gxpcolor.h, gxpcmap.c)
+
+Adds the Pattern UID to Pattern cache entries. (gxpcolor.h, gxpcmap.c)
+****** MUST HANDLE XUID POINTERS ON GC (RELOC) & RESTORE (CLEAR LIKE HT
+CACHE) ******
+
+Makes gs_gstate free the path representation of the clipping path if it's a
+rectangle, since reconstructing it is cheap and otherwise the path segments
+would not be freeable until a restore or GC. (gsstate.c)
+
+Extends the "client data" interface for gstates so that the copy procedure
+can determine why it is being called. (gxstate.h, gsstate.c)
+
+Version 4.35(limited) (11/24/96)
+=====================
+
+This contains the usual bug fixes, and two minor enhancements: an option for
+handling EPSF files with binary headers, and support for file-based
+resources.
+
+Documentation
+-------------
+
+Documents the new EPSF-reading capability. (gs.mak)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some obsolete definitions were accidentally left in the rules for
+compiling fonts into the executable. (int.mak)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - initgraphics left the current color space in an inconsistent
+state. (bug introduced in 4.32) (zgstate.c)
+ - restore didn't properly rebind FontDirectory to either Local or
+SharedFontDirectory according to the current VM selection. (gs_dps1.ps)
+ - If FontDirectory was redefined, many things broke. (gs_ccfnt.ps,
+gs_dps1.ps, gs_fonts.ps, gs_pdfwr.ps)
+ - If a resource provided a file name but the file couldn't be
+opened, an error occurred. (gs_res.ps)
+ - flushfile didn't work with procedure-based streams. (zfileio.c)
+
+Adds a feature (epsf.dev) that allows the interpreter to recognize and
+handle MS-DOS EPSF files with a binary header. (int.mak, gs_epsf.ps,
+gs_init.ps, pdf_main.ps)
+
+Adds (internal) .getuserparam and .getsystemparam operators for getting the
+value of a single user or system parameter. (gs_lev2.ps, zusparam.c)
+
+To support file-based resources, implements the FontResourceDir,
+GenericResourceDir, and GenericResourcePathSep system parameters, and
+ResourceFileName for the built-in resource categories. (gs_init.ps,
+gs_lev2.ps, gs_res.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - The 2-D CCITTFaxDecode filter became confused if a buffer boundary
+fell between a horizontal make-up code and its terminating code, typically
+causing an ioerror. (scfd.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Using the null color could confuse the reference counts for color
+spaces, causing memory access errors. (gscolor.c)
+ - Images with CombineWithColor = true caused memory access error,
+because a structure element wasn't initialized. (gdevmrop.c)
+ - gs_setnullcolor tried to return an error code, even though it was
+declared as returning void. (Why doesn't gcc catch this??) (gscolor.h,
+gscolor.c)
+ - gs_setnullcolor was declared inconsistently as taking a const or
+non-const argument. (gscolor.h)
+ - Small color tiles in the band list were not read in correctly.
+(gxclread.c)
+ - The band list could get confused, causing ioerrors, invalid memory
+accesses, or garbled output, because the algorithms for computing the size
+of bitmaps when writing and when reading had gotten inconsistent. This code
+has been broken and "fixed" at least 4 or 5 times. (gxcldev.h, gxclbits.c,
+gxclread.c)
+ - When using banding, characters that extended off the page
+vertically in the -Y direction came out garbled. (gxclimag.c)
+ - The bounding box device didn't compute the box correctly for
+trapezoids. (gdevbbox.c)
+ - The fastest case of rendering monochrome images could cause
+unaligned data accesses. (bug introduced recently.) (gximage.h,
+gximage1.c)
+ - TrueType characters with no contours could cause an invalid memory
+access. (gstype42.c)
+ - Composite TrueType characters weren't rendered properly.
+(gstype42.c)
+
+Adds a get_outline procedure to the Type 42 font header, to provide a
+callback for getting the outline data for a glyph. (gxfont42.h, gstype42.c)
+
+Version 4.34(limited) (11/18/96)
+=====================
+
+This release adds a little more support for CID-keyed fonts and for PCL
+emulation, and a bit more of the machinery for passing images through the
+band list.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The RasterOp source device wasn't listed as an internal device in
+drivers.txt. (drivers.txt)
+
+Corrects a statement regarding the pstotext license. (new-user.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The Watcom makefile for the library didn't work properly if
+certain variables were overridden from the command line. (watclib.mak)
+ - The library code inadvertently depended on an interpreter header
+file. (*.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - Some very picky compilers complained about assigning 0 to a
+variable of an enum type. (gdevpdfx.h, gdevpdf.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Some very picky compilers didn't like a cast from a pointer type
+to an int type. (idebug.c)
+ - Some very picky (and non-ANSI-compliant) compilers didn't allow
+assigning an int to a variable of enumerated type. (zfont2.c, zht2.c)
+ - The library code inadvertently depended on an interpreter header
+file. (iref.h)
+
+Restructures the font building code slightly to support CID fonts better.
+(gs_cidfn.ps, bfont.h, zcid.c, zfont0.c, zfont1.c, zfont2.c, zfont42.c)
+
+Adds a .setcurrentfile operator to allow disk-based fonts to keep their file
+open. (gs_cidfn.ps, zcontrol.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - Some very picky compilers didn't like the computation (const byte
+*)0 - 1. (stream.c)
+ - A cast to ulong was omitted. (smtf.c)
+ - Some compilers got confused by typedefs in the zlib header files.
+(szlibd.c, szlibe.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A header file didn't select the proper system header on all POSIX
+systems. (malloc_.h)
+ - A subclass/superclass type discrepancy upset some compilers.
+(gsline.h, gsline.c, gxpdash.c)
+ - Some very picky compilers didn't accept the previous definition of
+the offset_of macro. (stdpre.h)
+ - Some very picky (and non-ANSI-compliant) compilers didn't like
+mixing int and enumerated types. (gsropt.h, gzstate.h, gdevmrop.c,
+gdevrrgb.c, gsrop.c, gxclist.c)
+ - A cast was missing. (gslib.c)
+ - The gs_setxxxtransparent procedures interpreted their argument
+backwards (i.e., as "opaque" rather than "transparent"). (gsrop.c)
+ - Intersecting clipping paths didn't reset the logical operation to
+the default, causing a possible crash. (gsrop.h, gsrop.c, gxacpath.c)
+ - Pattern accumulation didn't reset the logical operation to the
+default, possibly causing incorrect output. (gspcolor.c)
+ - If a Type 1 character ended with a curve and a closepath, a
+microscopic line could result, causing output anomalies. (gstype1.c)
+ - Stroking a path with a mix of thin and non-thin lines could cause
+extraneous lines to appear. (gxstroke.c)
+ - Zero-width rectangles were painted even when fill adjustment was
+turned off. (gxpaint.c, gxstroke.c)
+ - The algorithm for dividing a curve into monotonic pieces could
+produce incorrect results, causing anomalies when filling curved regions
+with zero fill adjustment. (gxpcopy.c)
+ - The algorithms for outside clipping were wrong, causing some
+inside regions not to be clipped. (gxcpath.c)
+ - The white pixels in halftones weren't treated as unconditionally
+opaque for RasterOp. (gxht.c, gxcht.c)
+ - Images with RasterOp didn't work properly. (gdevmrop.c,
+gximage[2345].c, gxpcmap.c)
+ - The library code inadvertently depended on an interpreter header
+file. (gxalloc.h, genarch.c)
+ - An important optimization for stroking (recognizing portrait,
+landscape, and unscaled CTMs) was commented out. WE DON'T HAVE ANY RECORD
+OF WHY WE DID THIS, AND RESTORING IT MAY INTRODUCE NEW BUGS. (gxstroke.c)
+ - Bitmap images with non-zero data_x values were passed through the
+band list incorrectly, possibly causing vertical "streaks" in the output.
+(gxcldev.h, gxclread.c)
+ - If a curve had to be split twice along the same axis to make it
+monotonic, the split points were returned in the wrong order, possibly
+causing curved edges to turn into straight lines. (gxpcopy.c)
+
+Changes the debugging printout format for paths so the output can be
+processed mechanically more easily. (gxpath.c)
+
+Adds gs_glyphpath, like charpath but taking a glyph rather than a string of
+character codes. (gschar.h, gschar.c)
+
+Adds an internal concept of a "null color", a color that doesn't actually
+mark any pixels. (gscolor.h, gsdcolor.h, gxdcolor.h, gscolor.c, gxdcolor.c)
+
+Takes the next incremental steps towards passing images through the band
+list:
+ - Implements the ability to pass some color mapping information
+(transfer functions, black generation, undercolor removal) through the band
+list. (gxclist.h, gxclimag.c, gxclist.c, gxclread.c)
+
+Version 4.33(limited) (11/6/96)
+=====================
+
+This release fixes yet another obscure bug in the recently rewritten fast
+loops for image rendering. (These loops have caused more problems than any
+other single module of the entire library.) It also adds preliminary
+support for CID-keyed fonts (CIDFonts only, not CMaps yet) and some library
+extensions for supporting HP-GL/2.
+
+Documentation
+-------------
+
+Adds considerable new material to the C style document. (c-style.txt)
+
+Changes -cckr to -ansi in the SGI build procedure. (make.txt)
+
+Corrects an error in the description of the .type42execchar operator.
+(gs_typ42.ps)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The 'man' pages were installed in the documentation directory as
+well as in the man directory. (unix-end.mak)
+
+Interpreter
+-----------
+
+Adds support for CID-keyed fonts. There is no CMap support yet, and some
+things are done with hacks. (int.mak, gs_cidfn.ps, gs_cmap.ps, ichar.h,
+zchar.c, zchar2.c, zchar42.c, zfont2.c, zfont42.c, zcid.c)
+
+Adds operators for accessing the new dash adaptation and dot length
+parameters in the graphics state. (gs_init.ps, zgstate.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The fast case of monobit image rendering could overwrite memory.
+(gximage1.c)
+ - The new fast implementation of rectfill didn't check for
+fixed-point overflow. (gsdps1.c)
+ - Internally, fonts with no name all appeared to have the same name,
+possibly confusing the xfont machinery. (gxccman.c)
+ - A cast to remove const was omitted, upsetting some compilers.
+(gximage1.c)
+ - The driver's stroke_path routine was not called if the logical
+operation was not the default one. (gxpaint.c)
+
+Adds support for CID-keyed fonts. (gsccode.h, gxfont.h)
+
+Adds a new "dash pattern adaptation" flag in the imager state. When this
+flag is set and a dash pattern is in effect, each line segment will receive
+an integral number of repetitions of the dash pattern (if necessary, rounded
+up). (gsline.h, gxline.h, gsline.c, gsstate.c, gxpdash.c)
+
+Adds a new "dot length" parameter to the imager state. If this parameter is
+non-zero, it gives a length for rendering dots (zero-length lines). See
+language.txt for details. (gsline.h, gxline.h, gsline.c, gsstate.c,
+gxstroke.c)
+
+Extends band lists so they can handle dash pattern adaptation and dot
+length. (gxcldev.h, gxclpath.h, gxclpath.c, gxclread.c)
+
+Adds a floating point emulator to allow more realistic profiling of
+configurations without a FPU. (gsfemu.c)
+
+Version 4.32(limited) (11/1/96)
+=====================
+
+This fixes a couple more bugs, most notably the infamous "pixel stripe" bug.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The documentation said that Ghostscript could not interpret
+encrypted PDF files. (language.txt)
+ - A number of Ghostscript's extensions to the PostScript language
+were missing. (language.txt)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A compiler complained about initializing an unsigned variable with
+a negative value. (gdevx.c)
+ - An off-by-1 allocation error could cause memory overwriting.
+(gdevepsc.c)
+
+Platforms
+---------
+
+Declares a pointer 'const' that is actually only used for reading.
+(gp_unifs.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The code for adding nominal UnderlinePosition and
+UnderlineThickness entries to FontInfo assumed (incorrectly) that all Type 1
+fonts had FontBBox entries. (gs_type1.ps)
+
+Brings CIDFont support closer to reality. It doesn't work yet, though.
+(gs_cidfn.ps, gs_fonts.ps, gs_init.ps, gs_res.ps, gs_typ42.ps)
+
+Interpreter
+-----------
+
+Removes a redundant implementation of initgraphics. (gs_init.ps)
+
+Speeds up rectfill a little for the common case (4 numbers on the stack).
+(zdps1.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Zero-width, 1-bit-deep, landscape or portrait images could
+overwrite memory ad lib. (gximage1.c)
+ - A procedure was declared 'static' inconsistently, upsetting many
+compilers (but not gcc, which, in contradiction to the ANSI standard,
+doesn't check this properly). (gxcpath.c)
+ - A local variable was initialized with a value computed from a
+variable that hadn't been set yet, leading to possibly incorrect coloring of
+the first run of pixels in images with 12 bits per sample. (gximage4.c)
+ - A compiler complained about initializing an unsigned variable with
+a negative value. (shcgen.c)
+ - A rounding problem could produce a vertical stripe of 1 (or on
+very large images possibly more) incorrect pixels at the right edge of a
+1-bit-deep image. (gxdda.h, gximage1.c)
+
+Speeds up gs_rectfill substantially for the portrait/landscape case with a
+rectangular clipping region. (gsdps1.c)
+
+Adds a parameter so we can include gx_line_params in subclasses. (gzline.h)
+
+Version 4.31(limited) (10/27/96)
+=====================
+
+This is primarily a bug fix release for 4.30, which we had hoped wouldn't be
+necessary....
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The comment describing the order of coefficients in a CTM written
+on the band list was wrong. (gxclpath.h)
+
+Procedures
+----------
+
+Fixes bugs:
+ - bug-form.txt wasn't installed by 'make install'. (unix-end.mak)
+ - The default flags in ugcclib.mak didn't take the gcc code
+generation bug into account. (ugcclib.mak)
+
+Platforms
+---------
+
+Fixes bugs:
+ - MetroWerks CodeWarrior predefines true and false, causing
+compilation errors on the Mac. (stdpre.h)
+
+Interpreter
+-----------
+
+Updates code for the change in the ENUM_PTR macros. (iscan.c)
+
+Changes the allocator to keep track of "lost" ref space separately, to allow
+an independent check on its activities. (gxalloc.h, ialloc.c, isave.c)
+
+Changes the garbage collector API slightly to allow implementation of the
+API in applications other than PostScript interpreters. (ivmspace.h,
+ireclaim.c, igc.c)
+
+Interpreter (PDF)
+-----------------
+
+Implements the PDF 1.1 BX and EX operators. (pdf_base.ps, pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - Some (harmless) pointer incompatibilities upset some compilers.
+(szlibd.c, szlibe.c)
+
+Updates code for the change in the ENUM_PTR macros. (stream.c)
+
+Library
+-------
+
+Fixes bugs:
+ - A label in the ENUM_PTR procedure generating macros was often not
+referenced, leading to compiler warnings. (gsstruct.h, gxxfont.h,
+gdevmem.c, gschar.c, gscolor2.c, gsdevice.c, gsfont0.c, gsht.c, gsstate.c,
+gxcpath.c, gximage.c)
+ - Using the gstate version of setflat rather than the imager version
+caused compiler warnings (and, in some cases, errors). (gstype1.c)
+ - Non-standard ImageMatrix values for banded images didn't work.
+(This wasn't actually used.) (gxclread.c)
+ - imagemask with a halftone and portrait orientation colored some
+inappropriate pixels. (bug introduced in 4.30) (gximage2.c)
+ - When banding, if a character straddled a band boundary the first
+time it occurred, all occurrences of it were clipped. (bug introduced in
+4.2x or 4.30) (gxclimag.c)
+ - Degenerate clipping rectangles sometimes got turned into
+non-degenerate ones by swapping the min and max coordinates. (gxcpath.c)
+ - Resizing an object either allocated a new object unnecessarily
+(performance bug only), or in very rare cases could corrupt memory.
+(gsalloc.c)
+ - Very small objects didn't get put on a free list when freed.
+(Performance bug only.) (gsalloc.c)
+ - Some pointers were incorrectly declared 'const', upsetting some
+compilers. (gxclread.c)
+
+Adds more tracing output for -ZL. (gxclread.c)
+
+Changes the -Za tracing output slightly to aid mechanical analysis of
+allocation traces: allocation events now always include a '+', deallocation
+events always include a '-', and the address is always the address of the
+object data and not the header. (gsalloc.c, gsmemory.c)
+
+Changes the allocator to keep track of "lost" object and string space
+separately, to allow an independent check on its activities. (gxalloc.h,
+gsalloc.c)
+
+Changes the allocator to use 'memmove' in an obvious place. (gsalloc.c)
+
+Provides a garbage collector API at the library level to allow
+implementation of the API in applications other than PostScript
+interpreters. (gsgc.h)
+
+Version 4.30(limited) (10/23/96)
+=====================
+
+The main purpose of this release is to implement a substantial change in the
+"high level" image API, after which we believe this API will be stable.
+
+Documentation
+-------------
+
+Documents the changes in the begin_image and image_data device procedures.
+(drivers.txt)
+
+Drivers
+-------
+
+Speeds up the PDF writer a little by reducing the amount of allocation,
+which was causing very frequent garbage collections. (gs_pdfwr.ps,
+gdevpdft.c)
+
+Updates the PDF writer for the change in begin_image/image_data.
+(gdevpdfi.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Some versions of the SGI IRIX compiler have a bug that causes them
+to try to expand macros that require arguments even when the macro name
+isn't followed by a left parenthesis. (gdevsgi.h, gdevsgi.c)
+ - The IBM RS6000 compilers now provide <stdlib.h>, so our
+definitions of malloc and free caused a conflict. (malloc_.h)
+
+Fonts
+-----
+
+Fixes bugs:
+ - Many Fontmaps included obsolete references to an old
+Helvetica-Narrow font. (Fontmap.*)
+
+Makes the GS_FONTPATH directory scanner a little more liberal about what
+files it examines: it will now examine any file whose first line begins with
+%!PS-Adobe or %!FontType. (gs_fonts.ps)
+
+To match an apparent Adobe convention, augments findfont so that if a font
+isn't in the Fontmap, it will try to load a file whose name is the same as
+the font name. (gs_fonts.ps)
+
+To make some questionable Apple font inquiry code work, augments the
+FAKEFONTS facility so that it sets the FontType of fake fonts to 1.
+(gs_fonts.ps)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - .checkpassword, .putdeviceparams, .putdevparams, setsystemparams,
+and setuserparams didn't free the results byte array, causing a memory leak
+(until the next garbage collection). (zdevice.c, ziodev.c, zusparam.c)
+
+Library
+-------
+
+Fixes bugs:
+ - The code for emulating floating point multiplication with
+conversion to fixed point didn't detect overflow correctly, which could
+produce incorrect results instead of a limitcheck. (gsmisc.c)
+ - A macro cast a pointer incorrectly, leading to spurious compiler
+warnings. (gxfixed.h)
+ - The code for emulating fixed-to-float conversion computed the
+exponent incorrectly. (gsmisc.c)
+ - The algorithm for advancing a DDA a given number of steps (not
+actually used anywhere before this version) was wrong. (gxdda.h)
+ - The clipping box returned by clipping devices was incorrect,
+causing parts of the page to disappear. (bug introduced in 4.20)
+(gxcpath.c)
+
+Changes the begin_image and image_data device procedures:
+ - begin_image now takes an optional subrectangle instead of a set of
+shape flags.
+ - image_data now always takes complete rows of pixels, takes a
+source X offset, and returns 1 when it has received all the data.
+
+The change in begin_image and image_data is a NON-BACKWARD-COMPATIBLE CHANGE
+IN A PUBLIC INTERFACE; however, this interface was still designated "subject
+to change", per the notes for release 3.67 and the documentation in
+drivers.txt. (gsiparam.h, gxclpath.h, gxdda.h, gxdevice.h, gximage.h,
+gdevbbox.c, gdevnfwd.c, gsimage.c, gxclimag.c, gxclread.c, gximage.c,
+gximage?.c)
+
+Version 4.21(limited) (10/17/96)
+=====================
+
+The purpose of this release is to fix bugs reported in 4.0x, 4.10, and 4.20.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The Ghostscript man page had a .TH in the middle. (gs.1)
+
+Procedures
+----------
+
+Fixes bugs:
+ - The shared version of zlib was always called libgz; on most
+systems, it is now called libz (but not on Red Hat Linux, where libz is a
+library for dealing with time zones). (*.mak, gs.mak, libpng.mak, zlib.mak)
+ - The pdf2dsc.1 man page wasn't installed on Unix systems.
+(unix-end.mak)
+ - font2c generated procedures named gsf_xxx, but genconf assumed
+they were named gs_f_xxx. (int.mak)
+
+Drivers
+-------
+
+Updates the user-contributed LBP-8II driver to correct unspecified problems.
+(gdevlbp8.c)
+
+Adds a user-contributed driver for Avance Logic SuperVGA cards.
+(gdevsvga.c, devs.mak)
+
+Platforms
+---------
+
+Fixes bugs:
+ - On Windows NT, a 32-bit parameter was truncated to 16 bits,
+preventing drawing of scroll bars of the image window when the window is
+uncovered. (dwimg.cpp)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The free URW Grotesk and Antiqua fonts were omitted from the
+distribution.
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Defining a new global instance of a built-in resource
+(ColorRendering, ColorSpace, Form, Halftone, Pattern, ProcSet) caused an
+invalidaccess error. (gs_res.ps)
+ - pathbbox with no current path left an extra item on the stack when
+the error occurred. (gs_init.ps)
+ - findresource for an undefined resource instance didn't preserve
+the contents of the stack. (gs_res.ps)
+
+Adds a new file providing a procedural interface with a very rudimentary
+form of job encapsulation. (gserver.c)
+
+Changes the initial value of MaxOpStack to 20000, for the sake of a few
+badly-behaved files. (gs_init.ps, pdf_base.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - If the image operators failed to allocated their bookkeeping
+structure, the result was a crash rather than VMerror. (gximage.c)
+ - gx_default_fill_triangle (currently used only to implement the
+fastest case of stroke) had a typo that could cause a numeric exception or
+incorrect output, and another typo that could produce incorrect output.
+(gdevddrw.c)
+ - When banding, if the first occurrence of a character fell partly
+off the page, all occurrences of that character on the page could be clipped
+or mangled. (gxclbits.c, gxclimag.c)
+ - When testing whether it's worthwhile compressing a bitmap for
+banding, the compressor was allowed to generate a lot more output than
+needed to make the test. (gxclbits.c)
+ - Certain cases of unrotated gray-scale images dropped the first or
+last pixel of each scan line. (gximage2.c)
+ - In rare cases, a run of pixels in a image could get erroneously
+displayed in the same color as the previous run, because of a cache
+bookkeeping bug. (gximage3.c)
+ - The sample driver for the library had gotten inconsistent with a
+header file. (gslib.c)
+ - A declaration was followed by an extraneous semicolon, which upset
+some compilers. (gxht.h)
+ - Missing parentheses caused a test for thin lines to be incorrect.
+(gxstroke.c)
+
+Version 4.20(limited) (10/13/96)
+=====================
+
+This release has internal changes for future support of banded image
+processing, but no externally visible changes. Its primary purpose is to
+incorporate speedups for clipped images. It does *not* incorporate fixes
+for all problems reported in 4.0x or 4.10.
+
+Documentation
+-------------
+
+Documents the new get_clipping_box device procedure. (drivers.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - There were many, many minor inconsistencies between the makefiles
+and the source code. (We finally have an automated tool to detect these.)
+(devs.mak, int.mak, lib.mak, unixtail.mak; gsutil.c, zwppm.c)
+ - Some makefile rules weren't properly terminated by a blank line.
+(lib.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - The comments in gslp.ps had gotten out of date. (gslp.ps)
+
+Adds --no-eject-file and --no-eject-formfeed switches to gslp.ps, to allow
+packing files in multi-column printouts. (gslp.ps)
+
+Drivers
+-------
+
+Adds a user-contributed driver for the Epson LP-8000 laser printer.
+(gdevlp8k.c)
+
+Adds a DisplayMode parameter to the vgalib device. (gdevvglb.c)
+
+Removes the requirement of typing a character at the end of each page using
+the vgalib driver. THIS IS A USER-VISIBLE, NON-BACKWARD-COMPATIBLE CHANGE.
+(gdevvglb.c)
+
+Interpreter
+-----------
+
+Updates code to accommodate the new get_clipping_box device procedure.
+(zupath.c)
+
+Library
+-------
+
+Fixes bugs:
+ - When a CTM was passed through the band list, it didn't get
+translated to match the band coordinate system. (This had no effect,
+because the translation part of the CTM was never used.) (gxclread.c)
+
+Adds a ',' debugging switch to disable high-level operations when banding.
+(gxclpath.c)
+
+Adds an optional get_clipping_box device procedure, so that filling and
+stroking can clip more aggressively. (gdevmem.h, gdevprn.h, gxdevice.h,
+gxpaint.h, gxpath.h, gzacpath.h, gdevdflt.c, gdevht.c, gdevnfwd.c,
+gxacpath.c, gxclip2.c, gxclist.c, gxcpath.c, gxpcmap.c, gxfill.c,
+gxstroke.c)
+
+Speeds up clipped filling and stroking, by checking against the device
+clipping box. (gxfill.c, gxstroke.c)
+
+Adds the ability to clip with a rectangle a clipping path being accumulated,
+and uses it to do more aggressive clipping when banding. (gzacpath.h,
+gxacpath.c, gxclread.c)
+
+Speeds up clipping of objects lying partly above or below the clipping
+region. (gxcpath.c)
+
+Speeds up clipping vertically-oriented objects (such as 90 degree rotated
+images or vertical rectangles) with convex clipping regions, by checking for
+vertical rectangles contained in multiple clipping rectangles. (gxcpath.c)
+
+Speeds up the handling of 90 degree rotated gray-scale images. (gximage2.c)
+
+Enhances the band list so that it can contain commands for a range of bands,
+not just a single band or all bands. (gxcldev.h, gxclist.h, gxclbits.c,
+gxclist.c, gxclread.c)
+
+Adds an operation to the DDA structure, for eventual support of clipped
+images. (gxdda.h)
+
+Factors out some macros useful for generating bit-transformation tables.
+(gsbittab.h, gsbittab.c, gsflip.c)
+
+Version 4.10(limited) (9/25/96)
+=====================
+
+This release adds local garbage collection, and a number of performance
+improvements for garbage collection in general. We will support it for one
+or two OEMs, but it is not a public release.
+
+Documentation
+-------------
+
+Moves documentation for all releases before 4.0 to history3.txt. (NEWS,
+history3.txt)
+
+Utilities
+---------
+
+Fixes bugs:
+ - pdf2dsc.ps didn't have a proper license notice. (pdf2dsc.ps)
+
+Drivers
+-------
+
+Adds a psgray driver, like psmono, to produce 8-bit gray PostScript (level
+1) images. (devs.mak, *.mak, gdevpsim.c)
+
+Changes the psmono driver to allow runs of up to 255 repeated bytes.
+(gdevpsim.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - setdevice erased the page even if this wasn't necessary.
+(zdevice.c)
+
+Speeds up the garbage collector, primarily by speeding up pointer
+relocation. (int.mak, ipacked.h, iref.h, ialloc.c, igc.c, igcref.c)
+
+Actually implements local garbage collection. (igc.h, ivmspace.h, igc.c,
+igcref.c, igcstr.c, ireclaim.c)
+
+Adds some additional error checking for the -Z? switch. (ilocate.c)
+
+Moves a utility for color mapping from the interpreter to the library.
+(icolor.h, zcolor.c)
+
+Adds a MinScreenLevels user parameter. (zusparam.c)
+
+Interpreter (PDF)
+-----------------
+
+Adds partial support for the PDF 1.2 gs operator, reverse engineered from a
+PDF 1.2 file. (pdf_draw.ps)
+
+Library
+-------
+
+Fixes bugs:
+ - The test for "thin" stroked lines incorrectly claimed some
+non-thin lines were thin. (gxstroke.c)
+ - The computations for halftone cells didn't work for non-square
+pixels. (gxdht.h, gsht.c, gsht1.c, gshtscr.c)
+
+Speeds up the garbage collector a little. (gsstruct.h, gxalloc.h,
+gxfcache.h, gsfont.c)
+
+Replaces references to private statically allocated color spaces with
+references to shared dynamically allocated ones, which are guaranteed to be
+fully filled-in. (gscie.c)
+
+Moves a utility for color mapping from the interpreter to the library.
+(gxfmap.h, gxcmap.c)
+
+Makes available an imager analogue of setmatrix. (gscoord.h, gscoord.c)
+
+Adds a parameter to control the minimum number of halftone screen levels.
+If a halftone cell has fewer pixels than this number, it will be replicated
+(similar to what AccurateScreens does) until the replicated screen has
+enough levels. (gxht.h, gshtscr.c)
+
+Version 4.03 (9/23/96)
+============
+
+This was an emergency re-release of 4.02 to fix the stdin redirection
+problem. It has essentially no other changes.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Solaris 2.x has /usr/ucb/install, not installbsd. (make.txt)
+
+Updates current.txt to mention the ability to share libpng and libgz.
+(current.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - A rule assumed that the makefile was named `makefile'.
+(unixtail.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The stcolor drivers had an off-by-1 error that could cause them to
+write into unallocated memory. (gdevstc.c)
+ - The Imagen driver wouldn't compile with gcc. (gdevimgn.c)
+
+Fonts
+-----
+
+Fixes bugs:
+ - The Solaris fontmap had gotten out of date. (Fontmap.Sol)
+
+Streams
+-------
+
+Fixes bugs:
+ - The test for stdin being non-seekable could leave the file error
+flag set, which caused an infinite loop when trying to read from the file
+later. (sfile.c, sfileno.c)
+
+Version 4.02 (9/19/96)
+============
+
+This release fixes a few more bugs, and adds the ability to read encrypted
+PDF files and some PDF 1.2 files.
+
+This release was withdrawn after a few days because the stdin redirection
+fix, which was made at the last minute, cause Ghostview to hang.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - The list of required support files was incorrect. (install.txt)
+ - The descriptions of file name lookup weren't accurate. (use.txt)
+ - A J should have been an H. (gxbitmap.h)
+
+Updates the documentation about encrypted PDF files. (new-user.txt)
+
+Documents what the 13 base PDF fonts are. (ps2pdf.txt)
+
+Fixes a tiny typo. (c-style.txt)
+
+Adds a user-contributed man page for the new pdf2dsc script. (pdf2dsc.1)
+
+Updates the government restricted rights notice in the Aladdin Ghostscript
+Free Public License. (PUBLIC)
+
+Adds the URL of test files to the bug report form. (new-user.txt)
+
+Puts the bug reporting form in a separate file. (readme, bug-form.txt,
+new-user.txt)
+
+Notes that map_xxx_color procedures should not return gx_no_color_index.
+(drivers.txt)
+
+Notes that Ghostscript supports the Flate filters. (language.txt)
+
+Documents the use of the system libpng and zlib. (make.txt, gs.mak)
+
+Notes that Borland C++ 5.0 and 5.01 will not compile Ghostscript correctly.
+(make.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Using both DELAYBIND and SAFER caused problems. (pstotext uses
+DELAYBIND.) (gs_init.ps)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Some pdf2ps machinery interfered with the PDF interpreter.
+(pdf_2ps.ps, pdf_main.ps)
+ - In the output of pdf2ps, page numbers in link destinations were
+too high by 1. (pdf_main.ps)
+ - viewpbm didn't handle value ranges other than [0..255] correctly.
+(viewpbm.ps)
+
+Adds a user-contributed shell script to invoke pdf2dsc.ps. (pdf2dsc,
+unix-end.mak)
+
+Adds a switch to the genconf utility to set the prefix for generated
+procedure names. (genconf.c)
+
+Adds the option of using system libraries (possibly shared) for libpng
+and/or zlib. (*head.mak, msc*.mak, os2.mak, tccommon.mak, wccommon.mak;
+libpng.mak, zlib.mak)
+
+Drivers
+-------
+
+Fixes bugs:
+ - The X11 display devices ignored the -DA4 compile-time option.
+(gdevx.c)
+ - The garbage collector could scramble the state of the CGM drivers.
+(gxdevice.h, gdevcgm.c)
+ - An identifier of more than 31 characters upset the VAX DEC C
+compiler. (gdevcgml.h, gdevcgml.c)
+ - In case of an error in trying to set the CoreDistVersion distiller
+parameter, a variable could be used without initialization. (gdevpdfp.c)
+ - When DEBUG is selected, the X Windows driver referenced _Xdebug,
+which is not defined in (at least the VMS version of) DECWindows. (x_.h,
+gdevxini.c)
+ - Some map_cmyk_color implementations could return "transparent".
+(gdevbit.c)
+ - Setting GraphicsAlphaBits or TextAlphaBits in the P*M drivers
+caused an error. (gdevpbm.c)
+ - If a user cancelled printing under MS Windows, a confusing error
+resulted, and a temporary file wasn't deleted. (gdevwpr2.c)
+ - The map_color_rgb procedure for the bit devices produced incorrect
+results. (This probably had no effect in practice.) (gdevbit.c)
+ - The os2prn device produced incorrect output. (gdevos2p.c)
+ - The OS/2 PM device didn't detect PM applications correctly.
+(gdevpm.c)
+ - The MS Windows printer driver didn't automatically detect the
+printer's color capabilities. (gdevwpr2.c)
+ - The BJC-610 driver didn't print at 720 dpi. (gdevcdj.c)
+ - The static prototypes of many devices didn't include the far_data
+keyword. (gdev3852.c, gdev4081.c, gdevbgi.c, gdevcgm.c, gdevht.c,
+gdevimgn.c, gdevl256.c, gdevmrop.c, gdevn533.c, gdevnfwd.c, gdevnp6.c,
+gdevo182.c, gdevpcfb.c, gdevpdf.c, gdevpe.c, gdevpm.c, gdevs3ga.c,
+gdevsnfb.c, gdevsppr.c, gdevsun.c, gdevsvga.c, gdevtknk.c, gdevvglb.c,
+gdevwddb.c, gdevwprn.c, gdevx.c, gdevxalt.c)
+ - The (original) deskjet driver collapsed print lines towards the
+left margin. (gdevdjet.c)
+
+Adds to the pgm/pgnm/ppm/pnm[raw] drivers the ability to set the maximum
+pixel value, by setting any of the Gray/Red/Green/BlueValues device
+parameters. (gdevpbm.c)
+
+Adds pkm[raw] drivers, which do all their internal computations in CMYK and
+convert the data to RGB as they write the file. (gdevpbm.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The VMS script referred to old versions of the third-party
+libraries. (vms.mak)
+ - Under VMS with DEC C, attempting to open a new file fails.
+(gp_vms.c)
+ - If you tried to print (gp_printfile) under Windows on a system
+with no printers installed, Ghostscript caused a GPF. (gp_mswin.c)
+
+Restores support for a non-DLL MS Windows platform. (bcwin32.mak,
+dwnodll.cpp)
+
+Adds a new MS Windows DLL call, gsdll_get_bitmap. (gsdll16.def,
+gsdll32.def, dll.txt, gdevwdib.c)
+
+Fixes a variety of other small Windows- and OS/2-related problems, mostly
+related to printing. (gp_mswin.h, dpmainc.c, dwmain.cpp, dwmainc.cpp,
+gdevmswn.c, gdevpm.c, gdevwpr2.c, gp_mswin.c)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - The value of /newerror in $error was true at the end of
+initialization. We now reset it after each internal use of stopped if
+necessary. (gs_dps1.ps, gs_fform.ps, gs_fonts.ps, gs_init.ps, gs_pdf.ps,
+gs_res.ps, gs_type1.ps)
+ - setpagedevice (and finddevice) didn't recognize Default.
+(gs_init.ps)
+ - When running with -dNODISPLAY, calling gssetresolution would cause
+a crash. (gs_init.ps)
+ - A particular combination of save, .forgetsave, and garbage
+collection could cause a memory access error in restore. (isave.c)
+ - Some references to systemdict were affected if a user redefined
+the name /systemdict. (gs_cmdl.ps, gs_fonts.ps, gs_kanji.ps, gs_dps1.ps,
+gs_init.ps, gs_res.ps, gs_statd.ps, gs_type1.ps)
+ - The insideness testing operators caused an invalid memory access.
+(drivers.txt, zupath.c)
+ - If a readline reached an input buffer boundary between the \r and
+\n of a 2-character EOL, an error could occur. (zfileio.c)
+ - setdevparams caused an error. (gs_lev2.ps)
+
+Changes file names beginning with ./ or ../ so they are recognized as
+"absolute" and not subject to the search path. (gp_dosfs.c, gp_ntfs.c,
+gp_os2.c, gp_unifn.c)
+
+Changes the exit code for -h or --help from 0 to 1, so an invoking program
+will keep the output around for the user to look at. (imainarg.c)
+
+Adds the FlateEncode and FlateDecode filters; adds PNG pixel prediction to
+the LZW filters. These additions are required for PDF 1.2 and will be part
+of PostScript Level 3. (int.mak, lib.mak, zfdecode.c, zfilter2.c, zfzlib.c,
+zfpngp.c [deleted])
+
+Interpreter (PDF)
+-----------------
+
+Fixes bugs:
+ - The copyright notices on some files didn't mention the Aladdin
+free license. (pdf_*.ps)
+ - Some references to systemdict were affected if a user redefined
+the name /systemdict. (pdf_font.ps)
+ - The value of /newerror in $error was true at the end of
+initialization. We now reset it after each internal use of stopped if
+necessary. (pdf_main.ps)
+ - stdin redirection failed for PDF files even if the new stdin was
+seekable. (pdf_main.ps)
+ - The Rotate key rotated pages in the wrong direction.
+(pdf_main.ps)
+
+Adds a minimal "security socket" to the interpreter. This does not include
+any actual decryption code; such code is available elsewhere (see
+new-user.txt). (int.mak, pdf_base.ps, pdf_main.ps, pdf_sec.ps)
+
+Adds a PDF 1.2 capability:
+ - The destination in a Dest array can be a page number as well as a
+page object. (pdf_main.ps)
+
+Streams
+-------
+
+Fixes bugs:
+ - stdin was assumed to be non-seekable. (sfile.c, sfileno.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Garbage collection could corrupt a pointer in Type 0 fonts.
+(gxfont0.h, gsfont0.c)
+ - When applying hints to a Type 1 font outline, the last point could
+sometimes get moved twice, causing output anomalies. (gxhint3.c)
+ - An #include needed for debugging was missing. (gxcmap.h)
+ - Graphics states included a no-longer-used private color space
+object. (gsstate.c)
+ - Images could get clipped randomly in the X direction. (I don't
+understand why this problem hasn't shown up more often, since it's been
+there since release 4.00.) (gximage.c)
+ - The arct and arcto operators failed to draw the line to the
+starting point of the arc. (bug introduced in 4.01) (gspath1.c)
+ - Prefix subclasses of simple structures caused an invalid memory
+access. (gsstruct.h)
+ - The variable fheight was sometimes unused. (gstype1.c)
+ - igcd and imod didn't have prototypes in an appropriate header
+file, and were declared extern in several places. (gsdcolor.h, gsline.h,
+gxarith.h, gxdht.h, gsht.c, gshtscr.c, gsimage.c, gsline.c, gstype1.c,
+gxclimag.c)
+ - When using a non-identity RenderTable in a CIE rendering
+dictionary, all colors came out too light. (gscie.c)
+ - When using anti-aliased graphics, stroked lines were rendered too
+thin. (gspaint.c)
+ - The default map_cmyk_color implementations could return
+"transparent". (gxcmap.c)
+ - The number of bits of alpha requested when rendering anti-aliased
+characters could exceed 4. (gschar.c)
+ - Multi-screen halftones could cause errors or infinite looping when
+banding. (This problem predates 4.0; I don't know why it didn't show up
+before.) (gxcldev.h, gxclist.c, gxclread.c)
+ - Skewed or rotated gray-scale images, or masks with a halftoned
+color, omitted one line of pixels and displaced the image by one pixel.
+(gximage2.c)
+
+Adds an implementation of realloc, for systems that don't have one that
+works. I don't know how to determine this automatically, so for the moment,
+the code uses our own implementation on Linux (where realloc is known to be
+broken, at least in some releases) and nowhere else. (malloc_.h,
+gsmemory.c, gsmisc.c)
+
+Removes the "OLD" algorithms from the Type 1 hinting source code, since they
+are no longer executed. (If necessary, they can be retrieved from an older
+version.) (gxhint3.c)
+
+Version 4.01 (7/10/96)
+============
+
+This fixes a few minor bugs discovered since the 4.0 release.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - An installation directory name was wrong. (make.txt,
+unix-lpr.txt)
+ - A URL was wrong. (devices.txt)
+ - A reference to use.doc hadn't been updated. (gs.1)
+ - Some references to /usr/local/lib hadn't been updated. (gs.1)
+ - The NEWS file and history* files still referred to *.doc rather
+than *.txt. (NEWS, history*.txt)
+
+Adds a note about compilation on Digital Unix. (make.txt)
+
+Clarifies that calling gs_exit calls gs_finit automatically. (imain.h)
+
+Adds a pointer to the PDF encryption patch. (Ridiculous U.S. export control
+laws don't allow including the patch itself in the main fileset.)
+(new-user.txt)
+
+Adds a help file for VMS. (gs-vms.hlp)
+
+Procedures
+----------
+
+Fixes bugs:
+ - vms.mak had gotten out of sync with the makefiles (again).
+(vms.mak)
+ - DEVICE{WIDTH,HEIGHT}POINTS didn't override PAPERSIZE.
+(gs_init.ps)
+ - The Microsoft C makefiles had gotten out of date. (msc.mak)
+
+The (few) GNU-Licensed drivers were accidentally omitted from the fileset.
+
+Modifies a makefile for greater reusability. (watclib.mak)
+
+Adds a 'debug' target for making Unix debugging configurations.
+(unix-end.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Some uses of 'run' should be changed to runlibfile. (bdftops.ps,
+impath.ps, markhint.ps, packfile.ps, showchar.ps, waterfal.ps, wftopfa.ps,
+wrfont.ps)
+ - Some debugging code hadn't been removed. (gslp.ps)
+
+Adds a new utility, viewcmyk.ps, for viewing 4-bit CMYK data. (psfiles.txt,
+unix-end.mak, viewcmyk.ps)
+
+Improves pdf2dsc by including Title and CreationDate DSC comments (these are
+displayed by Ghostview) and reducing the size of typical output files by a
+factor of about 3. (pdf2dsc.ps)
+
+Incorporates major changes (claimed to be improvements) to ps2ascii
+contributed by a user. If you have problems with it, please contact him,
+not Aladdin. (ps2ascii.ps)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The X value of a bounding box could be computed incorrectly.
+(gdevbbox.c)
+
+Platforms
+---------
+
+Fixes bugs:
+ - The Windows DLL sometimes didn't clean up properly. (dll.txt,
+dpmainc.c, dwdll.cpp, dwmain.cpp, dwmainc.cpp, gsdll.c, gsdll.h)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - Reading from a filter could hang forever, because a buffer was
+allocated 1 byte too small. (zfilter.c)
+ - The search path could become garbage under some circumstances.
+(imain.c)
+ - A dangling reference to a stack-allocated variable could corrupt
+memory if a client mixed interpreter calls and direct C calls. (interp.c)
+ - Printing an object to a procedure-based filter could cause an
+invalid memory access. (zfileio.c)
+
+Library
+-------
+
+Fixes bugs:
+ - Setting parameters for an unopened device could cause an access
+error or invoke the wrong put_params procedure. (gsdparam.c)
+ - Reading from a filter could hang forever, because a buffer was
+allocated 1 byte too small. (stream.h)
+ - If the current device was the nullpage device, doing a [g]save,
+selecting a different device, and doing a [g]restore caused an error.
+(gsdparam.c)
+
+Adds the ability to append arcs without the initial lineto, for PCL
+emulation. (gspath.h, gspath1.c)
+
+Version 4.0 (6/28/96)
+===========
+
+This is the first public release since 3.53, with a few more last-minute
+patches beyond 3.70.
+
+Documentation
+-------------
+
+Fixes bugs:
+ - Many makefiles still referred to .doc files rather than .txt.
+(cfonts.mak, devs.mak, gs.mak, int.mak, libpng.mak, unix-end.mak, watc.mak,
+watcwin.mak, wccommon.mak, zlib.mak)
+ - Some FONTPATH-related information was out of date. (use.txt)
+ - The installation directory for fonts was incorrect. (install.txt)
+ - The libpng and zlib versions were out of date. (libpng.mak,
+zlib.mak)
+ - Some information about GSview was incorrect or incomplete.
+(new-user.txt)
+ - make.txt said it described installation as well as building.
+(make.txt)
+
+Notes that the current release of zlib won't compile and link correctly with
+Sun cc. (make.txt)
+
+Adds a little more detail to the C style document. (c-style.txt)
+
+Procedures
+----------
+
+Fixes bugs:
+ - Some documentation files weren't installed. (unix-end.mak)
+ - Some dependencies were incorrect. (bcwin32.mak)
+ - 'make begin' and 'make clean' deleted too many and/or the wrong
+files. (bcwin.mak, bcwin32.mak)
+ - libpng.mak didn't work with libpng version 0.89c. (libpng.mak)
+ - -d<var>=<name> was equivalent to -d<var>=/<name>, and there was no
+way to set a variable to true, false, or null. (use.txt, gs_init.ps,
+iinit.c, imainarg.c)
+
+Removes the modules.lis file, which is no longer used.
+
+Undoes detecting automatically the need to run tar_cat -- the mechanism
+didn't work, and caused confusion. (unix-end.mak)
+
+Updates the makefiles to libpng version 0.89, but allows them to work with
+either 0.88 or 0.89. (*.mak)
+
+Utilities
+---------
+
+Fixes bugs:
+ - Showing the details of a protected font caused an error.
+(markhint.ps)
+
+Drivers
+-------
+
+Fixes bugs:
+ - A copyright notice was wrong. (gs_pdfwr.ps)
+ - PDF link annotations could get written with two Dest keys.
+(gdevpdfm.c)
+ - MakeProcInstance and FreeProcInstance were called on platforms
+where it wasn't appropriate. (gdevwpr2.c, gdevwprn.c, gp_mswin.c)
+ - On X servers that return very large values for the "virtual
+screen" size in millimeters but correct values for the screen size in
+pixels, a rangecheck could occur. (gdevxini.c)
+ - The bounding box device could return garbage if stroke or fill was
+ever invoked with an empty path. (gdevbbox.c)
+
+Replaces the LBP8 driver with a revised one contributed by a user.
+(gdevlbp8.c, devs.mak)
+
+Platforms
+---------
+
+Fixes bugs:
+ - Some Windows menu parameters were incorrect. (gsdll16.rc,
+gsdll32.rc)
+
+Interpreter
+-----------
+
+Fixes bugs:
+ - .getdevparams sometimes returned duplicate entries for /Type.
+(ziodev2.c)
+ - File names weren't parsed or concatenated properly on all
+platforms. (gs_fonts.ps, zfile.c)
+ - Filter lookahead caused problems with special files. (zfproc.c)
+ - If a TransformPQR procedure in a CIE color rendering dictionary
+didn't pop its 4 array arguments, an error occurred. (gs_lev2.ps, zcrd.c)
+
+Streams
+-------
+
+Fixes bugs:
+ - Filter lookahead caused problems with special files. (bug
+introduced in 3.70) (stream.h)
+
+Library
+-------
+
+Fixes bugs:
+ - .getdevparams sometimes returned duplicate entries for /Type.
+(gxiodev.h, gsiodev.c)
+
+Versions before 4.0
+===================
+
+See the files history3.txt, history2.txt, and history1.txt.
diff --git a/gs/ps2image.ps b/gs/ps2image.ps
new file mode 100644
index 000000000..1006b4633
--- /dev/null
+++ b/gs/ps2image.ps
@@ -0,0 +1,4 @@
+%!
+(\n\n****** The ps2image utility no longer exists.\n\
+****** Use the psmono device instead.\n\n\n) print
+flush stop
diff --git a/gs/ps2pdf.txt b/gs/ps2pdf.txt
new file mode 100644
index 000000000..08a92ce4b
--- /dev/null
+++ b/gs/ps2pdf.txt
@@ -0,0 +1,110 @@
+ Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, ps2pdf.txt, contains some information about Ghostscript's
+PostScript to PDF converter.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+About ps2pdf
+============
+
+ps2pdf is a work-alike for a large subset of Adobe's Acrobat Distiller (TM)
+product: it converts PostScript files to PDF files.
+
+ps2pdf is implemented as a very small shell script (batch file) that invokes
+Ghostscript selecting a special "output device" called pdfwrite. In order
+to use ps2pdf, you must have included the pdfwrite device in the DEVICE_DEVS
+list at the time Ghostscript was built. Currently, this device is included
+in the makefiles for all 32- and 64-bit platforms.
+
+The usage for ps2pdf is:
+ ps2pdf input.ps output.pdf
+or, on Unix systems and some versions of Windows NT and OS/2 only,
+ ps2pdf input.ps
+which is equivalent to
+ ps2pdf input.ps input.pdf
+
+The ps2pdf script assumes that the Ghostscript executable is named gs. On
+MS-DOS and MS Windows, you will need to edit the script (ps2pdf.bat) if the
+MS-DOS executable is named gs386: look for the line that says
+ set PS2PDFGS=gs
+and change it to
+ set PS2PDFGS=gs386
+Note that to run ps2pdf on MS Windows, you need the MS-DOS executable: the
+Windows Program Manager's 'run' command doesn't allow you to run .bat files.
+Alternatively, you can run the "console mode" Windows executable by changing
+the above line to
+ set PS2PDFGS=gswin32c
+
+Limitations
+===========
+
+The most serious limitation of ps2pdf is that text in any font other than
+the 14 Adobe base fonts (Courier, Times, and Helvetica families, Symbol, and
+Zapf Dingbats) is converted to bitmaps. ps2pdf also usually converts
+strings to bitmaps if the string is in one of the 14 base fonts but it
+contains a character that uses a non-standard encoding.
+
+ps2pdf currently does not implement any of the image resampling or
+compression options of Distiller. It does implement setdistillerparams, and
+recognizes all of the parameters documented in Adobe Technical Note #5151
+except for the ImageDict parameters, but the only ones that actually have
+any effect are ASCII85EncodePages, CompressPages, CompatibilityLevel, and
+UseFlateCompression. It could implement LZWEncode, but doesn't do so
+because of Unisys' threats regarding the Welch patent: instead, it treats
+LZWEncode as calling for Flate compression.
+
+Known problems
+==============
+
+In some cases, PDF files created using ps2pdf work with Adobe Acrobat on
+Unix but fail using the Windows version of Acrobat. One error that has been
+observed using versions of Acrobat reader for Windows is: "There was an
+error processing a page. A rasterizer error occurred." This error has been
+observed using both Acrobat version 2.1 and the Alpha 2 release of Adobe
+Amber. (Adobe may have fixed this problem by now.)
+
+Benefits of using ps2pdf
+========================
+
+Despite the limitations of ps2pdf, the class of "suitable" documents is a
+large one. Many users report that the combination of of ps2pdf with Acrobat
+is be superior to using a generic PostScript viewer (psview or ghostview),
+particularly for documents with many pages where the navigational support in
+PDF files reduces the overhead involved in navigating conventional
+PostScript documents.
+
+For certain documents, ps2pdf is much faster than Adobe Distiller, and may
+be suitable for run-time conversions. [Note from George White: I haven't
+seen a head to head comparison, but distiller seems slower when running on
+what should be a faster system (e.g., distiller on a PPC Mac vs a 25 mhz
+'040 NeXT running ps2pdf), so I think this is fair -- also, one of Mark
+Doyle's postings indicated that distiller was not fast enough for use as a
+run-time server. In contrast, I find that I can use ps2pdf as a
+post-processor during routine document creation.]
+
+Acknowledgements
+================
+
+Thanks to George N. White III of the Ocean Sciences Division of the Bedford
+Institute of Oceanography in Dartmouth, Nova Scotia <aa056@chebucto.ns.ca>,
+for extensive testing of early versions of ps2pdf, and for contributing most
+of this writeup.
diff --git a/gs/psfiles.txt b/gs/psfiles.txt
new file mode 100644
index 000000000..7e440c2df
--- /dev/null
+++ b/gs/psfiles.txt
@@ -0,0 +1,241 @@
+ Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, psfiles.txt, describes the .ps files distributed with
+Ghostscript, other than fonts.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Generally used system files
+---------------------------
+
+gs_init.ps - Ghostscript reads this automatically when it starts up. It
+contains definitions of many standard procedures and initialization for a
+wide variety of things.
+
+gs_btokn.ps - gs_init.ps reads this in if the btoken feature is included in
+the configuration. It provides support for binary tokens.
+
+gs_ccfnt.ps - gs_init.ps reads this in if the ccfonts feature is included
+in the configuration. It provides support for compiled fonts.
+
+gs_fonts.ps - gs_init.ps reads this in. It initializes Ghostscript's font
+machinery and provides some utility procedures that work with fonts.
+
+gs_statd.ps - gs_init.ps reads this in. It creates a dummy statusdict and
+some other environmental odds and ends for the benefit of PostScript files
+that really want to be printed on a LaserWriter.
+
+gs_dps1.ps - gs_init.ps reads this in if the dps feature is included in
+the configuration. It provides support for various Display PostScript and
+Level 2 features.
+
+gs_lev2.ps - gs_init.ps reads this in if the Ghostscript interpreter
+includes Level 2 PostScript functions. It contains definitions of
+procedures and miscellaneous initialization for the Level 2 functions.
+
+gs_res.ps - gs_init.ps reads this in if the Level 2 resource machinery is
+included. Currently, this is the case for all Level 2 configurations.
+
+gs_type1.ps - gs_init.ps reads this in if the Ghostscript interpreter
+includes Type 1 font capability (which it normally does).
+
+gs_*_e.ps - These files define the Encodings known to Ghostscript. All of
+them except gs_std_e.ps and gs_iso_e.ps are loaded only if referenced.
+
+More obscure system files
+-------------------------
+
+gs_cmdl.ps - This file is not used yet. Eventually it will replace C code
+that parses the Ghostscript command line.
+
+gs_diskf.ps - This file implements the -dDISKFONTS feature (diskfont.dev).
+See use.txt for a description of this feature.
+
+gs_kanji.ps - This file provides support for the Wadalab free Kanji font.
+It is not included automatically in any configuration.
+
+gs_pdfwr.ps - This file contains some patches for providing information to
+the pdfwrite driver. It is included only if the pdfwrite driver is
+included.
+
+gs_pfile.ps - This file provides runtime support for packed fonts. It is
+not included automatically in any configuration.
+
+PDF-specific system files
+-------------------------
+
+gs_pdf.ps - The ProcSet that provides runtime support for PDF files.
+pdf2ps copies this into its output.
+
+gs_l2img.ps - The ProcSet that emulates the PostScript Level 2 'image'
+operator on Level 1 systems. pdf2ps copies this into its output if the
+PSLevel1 option was selected.
+
+pdf_2ps.ps - The additions to the PDF interpreter that allow it to convert
+PDF to PostScript.
+
+pdf_base.ps - Utilities for interpreting PDF objects and streams.
+
+pdf_draw.ps - The interpreter for drawing-related PDF operations.
+
+pdf_font.ps - Code for handling fonts in PDF files.
+
+pdf_main.ps - Document- and page-level control for interpreting PDF files.
+
+Art
+---
+
+chess.ps - A black-and-white chessboard.
+
+golfer.ps - A gray-scale picture of a stylishly dressed woman swinging a
+golf club.
+
+escher.ps - A colored version of a hexagonally symmetric Escher drawing of
+interlocking butterflies. Can be printed on monochrome devices, with
+somewhat less dramatic results.
+
+cheq.ps - A chessboard "font" used by chess.ps (obtained from the Adobe
+file server).
+
+snowflak.ps - A rectangular grid of intricate colored snowflakes.
+(Renders very slowly.)
+
+colorcir.ps - A set of nested ellipses made up of colored bars.
+
+tiger.ps - A dramatic colored picture of a tiger's head.
+
+ridt.eps - The RIDT '91 logo. Note that since this is an EPS file, you will
+have to add
+ -c showpage
+at the end of the command line to print it or convert it to a raster file.
+
+Utilities
+---------
+
+For more information on these utility programs, see the comments at the
+beginning of the files. The ones marked with * have batch files or shell
+scripts of the same name (e.g., bdftops, bdftops.bat) to invoke them
+conveniently.
+
+align.ps - a test page for determining the proper margin and offset
+parameters for your printer.
+
+bench.ps - a file useful for running benchmarks.
+
+* bdftops.ps - a utility for converting BDF fonts to outline form: see
+fonts.txt for more information.
+
+caption.ps - a file for putting a caption in a box at the bottom of each
+page, useful for trade show demos.
+
+docie.ps - an emulation of the CIE color mapping algorithms.
+
+* gslp.ps - a utility for doing "line printing" of plain text files.
+
+impath.ps - a utility for reconstructing outlines from bitmap images,
+used by bdftops.
+
+landscap.ps - a file that you can put in front of your own files to get
+them rendered in landscape mode.
+
+level1.ps - a file that turns off any Level 2 features.
+
+packfile.ps - a utility for compressing fonts into a single file.
+
+prfont.ps - a utility to print a font catalog.
+
+* ps2ascii.ps - a utility for extracting the ASCII text from PostScript
+source files. It redefines many operators. For more information, see the
+comments in the file.
+
+ps2ai.ps - a utility for converting an arbitrary PostScript file into a form
+compatible with Adobe Illustrator. NOTE: ps2ai doesn't work properly with
+Adobe's Helvetica-Oblique font, and other fonts whose original FontMatrix
+involves skewing or rotation.
+
+* ps2epsi.ps - a utility for converting an arbitrary PostScript file into
+EPSI form.
+
+quit.ps - a file containing just the word "quit". (The -c switch now makes
+this unnecessary; this file exists for backward compatibility.)
+
+rollconv.ps - a utility for converting files produced by Macromedia's Rollup
+program to a Type 0 form directly usable by Ghostscript.
+
+showpage.ps - a file containing just the word "showpage". (The -c switch
+now makes this unnecessary; this file exists for backward compatibility.)
+
+viewcmyk.ps - a utility for displaying CMYK files.
+
+viewgif.ps - a utility for displaying GIF files.
+
+viewjpeg.ps - a utility for displaying JPEG files.
+
+viewpcx.ps - a utility for displaying PCX files.
+
+viewpbm.ps - a utility for displaying PBM/PGM/PPM files.
+
+waterfal.ps - a utility to print a "waterfall" of fonts at different
+sizes.
+
+Development tools
+-----------------
+
+acctest.ps - a utility that checks whether the interpreter enforces access
+restrictions.
+
+decrypt.ps - a utility for decrypting the eexec section of a font.
+
+markpath.ps - a utility for showing the points on a path.
+
+pcharstr.ps - a utility for printing out the CharStrings and Subrs in a
+Type 1 font.
+
+ppath.ps - a couple of utilities for printing out the current path, for
+debugging.
+
+traceop.ps - a utility for tracing uses of any procedure or operator
+for debugging.
+
+type1enc.ps - the Type 1 font format encryption and decryption algorithms,
+written in PostScript.
+
+uninfo.ps - some utilities for printing out PostScript data structures.
+
+unprot.ps - a prologue to disable access checking.
+
+viewps2a.ps - a utility for displaying the output of ps2ascii.ps.
+
+winmaps.ps - a utility for creating mappings between the Adobe encodings
+and the Microsoft Windows character sets.
+
+wrfont.ps - a utility for writing out an unprotected Type 1 font, such as
+the standard Ghostscript fonts.
+
+zeroline.ps - a utility for testing how interpreters handle zero-width
+lines.
+
+Odds and ends
+-------------
+
+lines.ps - a test program for line joins and caps.
+
+type1ops.ps - the Type 1 font format opcodes.
diff --git a/gs/public.txt b/gs/public.txt
new file mode 100644
index 000000000..9cffd3e51
--- /dev/null
+++ b/gs/public.txt
@@ -0,0 +1,75 @@
+ Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRALTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, public.txt, provides additional information about Aladdin
+Ghostscript releases that is not relevant to GNU Ghostscript releases.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+Other freely available fonts
+----------------------------
+
+We've received the following information about some other freely available
+fonts, including Cyrillic fonts.
+
+ 1. Cyrillic extension of the Computer Modern fonts
+ was created by N. Glonty and A. Samarin
+ at 1989 and uploaded into `/tex-archive/fonts/cmcyr' directory of CTAN.
+
+ 2. In the beginning of the 1993 year `Paradissa Fonts Collection'
+ was created by Basil K. Malyshev.
+ This collection contains typefaces:
+ - Computer Modern, designed by D. Knuth;
+ - Euler, designed by H. Zapf;
+ - Cyrillic Extension of the Computer Modern,
+ designed by N. Glonty and A. Samarin;
+ - Special LaTeX fonts.
+ Totally it contains 165 fonts
+ in ATM compatible PostScript Type 1 format
+ with AFM and PFM files.
+ This collection was uploaded in
+ `/tex-archive/fonts/postscript/cm' directory of CTAN.
+
+ CTAN -- Comprehensive TeX Archive Network which is supported
+ by three hosts `ftp.tex.ac.uk', `ftp.dante.de', `ftp.shsu.edu'.
+
+These fonts are covered by the following license:
+
+Paradissa fonts collection.
+Copyright (C) 1993, Basil K. Malyshev. All Rights Reserved.
+
+ Licensing agreement
+
+The author of this fonts grants to any individual or non-commercial
+organization the right to use and to make an unlimited number of copies of
+full collection or selected fonts when this is done WITHOUT CHARGE
+and has attached this licence agreement.
+
+This fonts cannot be sold or distributed with any commercial product
+without written authorization from the author.
+If you want to charge a small fee for distribute fonts as is or with
+any software, you should contact the author.
+
+This restriction is not intended to apply to connect time charges,
+or flat rate connection/download fees for electronic bulletin board services.
+
+Basil K. Malyshev (E-Mail: malyshev@mx.ihep.su), 22-Dec-1993, Protvino, Russia.
+
+----------------------------------------------------------------
diff --git a/gs/readme b/gs/readme
new file mode 100644
index 000000000..06c8ede33
--- /dev/null
+++ b/gs/readme
@@ -0,0 +1,187 @@
+ Copyright (C) 1989, 1996, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+****************************************************
+* This file describes version 5.13 of Ghostscript. *
+****************************************************
+
+If this is your first contact with Ghostscript, we suggest you read the file
+new-user.txt before continuing with this README file. new-user.txt gives an
+overview of:
+
+ - what Ghostscript does (PostScript and PDF previewing, conversion,
+ and printing);
+
+ - what its licensing terms are (free for ordinary use);
+
+ - what platforms it runs on (every platform you're likely to be
+ interested in);
+
+ - where to find some useful programs that enhance Ghostscript (like
+ user-friendly previewers for Unix, VMS, MS Windows, MS-DOS, and
+ Macintosh).
+
+ - what to do if you have problems (the "If you need help" section).
+
+The rest of this README file is a road map to the documentation files that
+are part of the fileset. If you are a new user, we suggest you look through
+it now. After that, we recommend you read install.txt, which tells you how
+to install Ghostscript, and make.txt, which tells you how to compile
+Ghostscript from source code (which is required before installation on Unix
+and VMS systems).
+
+********
+******** Documentation overview ********
+********
+
+There is a Ghostscript World Wide Web home page at
+ http://www.cs.wisc.edu/~ghost/index.html
+
+All the file names mentioned in the documentation, except for README and
+NEWS, are in lower case, which is the usual convention for Unix systems. On
+MS-DOS systems, all file names are actually upper-case.
+
+What should I read if I'm a new user?
+-------------------------------------
+
+If you are a new user of Ghostscript, you should start by reading:
+
+> new-user.txt - information specifically for new users.
+
+Then read as many of the following as seem relevant:
+
+> install.txt - information about how install Ghostscript.
+
+> use.txt - information about to use Ghostscript. Some of this information
+is also contained in gs.1 - a `man' page for Ghostscript.
+
+> The catalog at the beginning of devs.mak, which lists all the devices for
+which Ghostscript is able to produce output (although if you got Ghostscript
+in binary form, it will only include a subset of these devices).
+
+> devices.txt - more detailed information about some specific devices that
+Ghostscript knows about.
+
+> ps2epsi.txt, unix-lpr.txt - more detailed information about some of
+the shell scripts and batch files distributed with Ghostscript.
+
+> bug-form.txt - a form to use for reporting problems (but remember that
+Ghostscript comes with NO WARRANTY and NO SUPPORT).
+
+If you have Aladdin Ghostscript, as opposed to the GNU Ghostscript releases
+distributed by the Free Software Foundation, you should read (or at least
+skim through):
+
+> public.txt - additional information about Aladdin Ghostscript releases
+that is not relevant to GNU Ghostscript releases.
+
+If you are going to compile Ghostscript, rather than just use an executable
+you got from somewhere, you should read:
+
+> make.txt - how to compile and link Ghostscript. (You should also read
+install.txt in this case.)
+
+If you run into any questions, or if you are going to be using Ghostscript
+extensively, you should at least skim, and probably eventually read:
+
+> fonts.txt - information about the fonts distributed with
+Ghostscript, including how to add or replace fonts.
+
+> language.txt - A description of the Ghostscript language, and its
+differences from the documented PostScript language.
+
+> psfiles.txt - information about the .ps files distributed with
+Ghostscript (other than fonts).
+
+There is also a FAQ (Frequently Asked Questions) file available on the
+Internet. See "If you need help" in new-user.txt for the location.
+
+What should I read if I'm not a new user?
+-----------------------------------------
+
+When you receive a new release of Ghostscript, you should start by reading:
+
+> README - this file.
+
+> current.txt - information about problems, and major changes and new
+features in the current release.
+
+If you have used a previous release of Ghostscript, you probably should also
+read any more recent sections of:
+
+> NEWS - a complete, detailed history of changes in the most recent
+Ghostscript releases.
+
+What if I'm a developer?
+------------------------
+
+If you are going to be writing a new driver for Ghostscript, you
+should read:
+
+> drivers.txt - the interface between Ghostscript and device drivers.
+
+> xfonts.txt - the interface between Ghostscript and platform-supplied
+fonts. (Read drivers.txt first.)
+
+If you are considering distributing Ghostscript (either Aladdin or GNU
+versions) in conjunction with a commercial product, you should read the
+PUBLIC license carefully, and you should also read:
+
+> commprod.txt - additional clarification of the circumstances under which
+Ghostscript can be distributed with a commercial product.
+
+If you intend to use Ghostscript in the form of a DLL under OS/2 or
+Microsoft Windows, you should read:
+
+> dll.txt - documentation on Ghostscript as a DLL.
+
+If you intend to use Ghostscript as part of another program and not
+as a DLL, rather than as a self-contained executable application, you
+should start by reading either (if you will be using Ghostscript as a
+callable PostScript language interpreter):
+
+> imain.h - the documented API for Ghostscript not as a DLL.
+
+or (if you are going to use just the Ghostscript graphics library):
+
+> lib.txt - information about the structure of and APIs for the
+Ghostscript library.
+
+Other files
+-----------
+
+> ps2epsi.txt - documentation for the PostScript to EPSI conversion
+utility.
+
+> helpers.txt - a note of thanks to all the people who have helped with
+Ghostscript development.
+
+> hershey.txt - information about the Hershey fonts, which are the
+basis of some of the Ghostscript fonts.
+
+> history*.txt - a history of changes in older Ghostscript releases.
+
+> humor.txt - a humorous comment on Ghostscript contributed by a user.
+
+> unix-lpr.txt - information about how to integrate Ghostscript with
+Unix printer spooling.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+PostScript is a trademark of Adobe Systems, Incorporated.
diff --git a/gs/src/_vc_temp.mak b/gs/src/_vc_temp.mak
new file mode 100755
index 000000000..1a898bb7c
--- /dev/null
+++ b/gs/src/_vc_temp.mak
@@ -0,0 +1,10 @@
+MSVC_VERSION=5
+DEVSTUDIO=c:\progra~1\devstudio
+FEATURE_DEVS=dps2lib.dev path1lib.dev patlib.dev rld.dev roplib.dev ttflib.dev
+DEVICE_DEVS=djet500.dev ljet4.dev pcxmono.dev pcxgray.dev bbox.dev
+BAND_LIST_STORAGE=memory
+BAND_LIST_COMPRESSOR=zlib
+FPU_TYPE=0
+CPU_TYPE=486
+CONFIG=5
+!include msvclib.mak
diff --git a/gs/src/ansi2knr.c b/gs/src/ansi2knr.c
new file mode 100644
index 000000000..64a4578a2
--- /dev/null
+++ b/gs/src/ansi2knr.c
@@ -0,0 +1,546 @@
+/* ansi2knr.c */
+/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone for the
+consequences of using it or for whether it serves any particular purpose or
+works at all, unless he says so in writing. Refer to the GNU General Public
+License (the "GPL") for full details.
+
+Everyone is granted permission to copy, modify and redistribute ansi2knr,
+but only under the conditions described in the GPL. A copy of this license
+is supposed to have been given to you along with ansi2knr so you can know
+your rights and responsibilities. It should be in a file named COPYLEFT.
+Among other things, the copyright notice and this notice must be preserved
+on all copies.
+
+We explicitly state here what we believe is already implied by the GPL: if
+the ansi2knr program is distributed as a separate set of sources and a
+separate executable file which are aggregated on a storage medium together
+with another program, this in itself does not bring the other program under
+the GPL, nor does the mere fact that such a program or the procedures for
+constructing it invoke the ansi2knr executable bring any other part of the
+program under the GPL.
+*/
+
+/*
+ * Usage:
+ ansi2knr input_file [output_file]
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes function definitions by seeing a non-keyword
+ * identifier at the left margin, followed by a left parenthesis,
+ * with a right parenthesis as the last character on the line,
+ * and with a left brace as the first token on the following line
+ * (ignoring possible intervening comments).
+ * It will recognize a multi-line header provided that no intervening
+ * line ends with a left or right brace or a semicolon.
+ * These algorithms ignore whitespace and comments, except that
+ * the function name must be the first thing on the line.
+ * The following constructs will confuse it:
+ * - Any other construct that starts at the left margin and
+ * follows the above syntax (such as a macro or function call).
+ * - Some macros that tinker with the syntax of the function header.
+ */
+
+/*
+ * The original and principal author of ansi2knr is L. Peter Deutsch
+ * <ghost@aladdin.com>. Other authors are noted in the change history
+ * that follows (in reverse chronological order):
+ lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with
+ compilers that don't understand void, as suggested by
+ Tom Lane
+ lpd 96-01-15 changed to require that the first non-comment token
+ on the line following a function header be a left brace,
+ to reduce sensitivity to macros, as suggested by Tom Lane
+ <tgl@sss.pgh.pa.us>
+ lpd 95-06-22 removed #ifndefs whose sole purpose was to define
+ undefined preprocessor symbols as 0; changed all #ifdefs
+ for configuration symbols to #ifs
+ lpd 95-04-05 changed copyright notice to make it clear that
+ including ansi2knr in a program does not bring the entire
+ program under the GPL
+ lpd 94-12-18 added conditionals for systems where ctype macros
+ don't handle 8-bit characters properly, suggested by
+ Francois Pinard <pinard@iro.umontreal.ca>;
+ removed --varargs switch (this is now the default)
+ lpd 94-10-10 removed CONFIG_BROKETS conditional
+ lpd 94-07-16 added some conditionals to help GNU `configure',
+ suggested by Francois Pinard <pinard@iro.umontreal.ca>;
+ properly erase prototype args in function parameters,
+ contributed by Jim Avera <jima@netcom.com>;
+ correct error in writeblanks (it shouldn't erase EOLs)
+ lpd 89-xx-xx original version
+ */
+
+/* Most of the conditionals here are to make ansi2knr work with */
+/* or without the GNU configure machinery. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_CONFIG_H
+
+/*
+ For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
+ This will define HAVE_CONFIG_H and so, activate the following lines.
+ */
+
+# if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+#else /* not HAVE_CONFIG_H */
+
+/* Otherwise do it the hard way */
+
+# ifdef BSD
+# include <strings.h>
+# else
+# ifdef VMS
+ extern int strlen(), strncmp();
+# else
+# include <string.h>
+# endif
+# endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+/*
+ malloc and free should be declared in stdlib.h,
+ but if you've got a K&R compiler, they probably aren't.
+ */
+# ifdef MSDOS
+# include <malloc.h>
+# else
+# ifdef VMS
+ extern char *malloc();
+ extern void free();
+# else
+ extern char *malloc();
+ extern int free();
+# endif
+# endif
+
+#endif
+
+/*
+ * The ctype macros don't always handle 8-bit characters correctly.
+ * Compensate for this here.
+ */
+#ifdef isascii
+# undef HAVE_ISASCII /* just in case */
+# define HAVE_ISASCII 1
+#else
+#endif
+#if STDC_HEADERS || !HAVE_ISASCII
+# define is_ascii(c) 1
+#else
+# define is_ascii(c) isascii(c)
+#endif
+
+#define is_space(c) (is_ascii(c) && isspace(c))
+#define is_alpha(c) (is_ascii(c) && isalpha(c))
+#define is_alnum(c) (is_ascii(c) && isalnum(c))
+
+/* Scanning macros */
+#define isidchar(ch) (is_alnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *skipspace();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{ FILE *in, *out;
+#define bufsize 5000 /* arbitrary size */
+ char *buf;
+ char *line;
+ char *more;
+ /*
+ * In previous versions, ansi2knr recognized a --varargs switch.
+ * If this switch was supplied, ansi2knr would attempt to convert
+ * a ... argument to va_alist and va_dcl; if this switch was not
+ * supplied, ansi2knr would simply drop any such arguments.
+ * Now, ansi2knr always does this conversion, and we only
+ * check for this switch for backward compatibility.
+ */
+ int convert_varargs = 1;
+
+ if ( argc > 1 && argv[1][0] == '-' )
+ { if ( !strcmp(argv[1], "--varargs") )
+ { convert_varargs = 1;
+ argc--;
+ argv++;
+ }
+ else
+ { fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
+ exit(1);
+ }
+ }
+ switch ( argc )
+ {
+ default:
+ printf("Usage: ansi2knr input_file [output_file]\n");
+ exit(0);
+ case 2:
+ out = stdout;
+ break;
+ case 3:
+ out = fopen(argv[2], "w");
+ if ( out == NULL )
+ { fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+ exit(1);
+ }
+ }
+ in = fopen(argv[1], "r");
+ if ( in == NULL )
+ { fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+ exit(1);
+ }
+ fprintf(out, "#line 1 \"%s\"\n", argv[1]);
+ buf = malloc(bufsize);
+ line = buf;
+ while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+ {
+test: line += strlen(line);
+ switch ( test1(buf) )
+ {
+ case 2: /* a function header */
+ convert1(buf, out, 1, convert_varargs);
+ break;
+ case 1: /* a function */
+ /* Check for a { at the start of the next line. */
+ more = ++line;
+f: if ( line >= buf + (bufsize - 1) ) /* overflow check */
+ goto wl;
+ if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
+ goto wl;
+ switch ( *skipspace(more, 1) )
+ {
+ case '{':
+ /* Definitely a function header. */
+ convert1(buf, out, 0, convert_varargs);
+ fputs(more, out);
+ break;
+ case 0:
+ /* The next line was blank or a comment: */
+ /* keep scanning for a non-comment. */
+ line += strlen(line);
+ goto f;
+ default:
+ /* buf isn't a function header, but */
+ /* more might be. */
+ fputs(buf, out);
+ strcpy(buf, more);
+ line = buf;
+ goto test;
+ }
+ break;
+ case -1: /* maybe the start of a function */
+ if ( line != buf + (bufsize - 1) ) /* overflow check */
+ continue;
+ /* falls through */
+ default: /* not a function */
+wl: fputs(buf, out);
+ break;
+ }
+ line = buf;
+ }
+ if ( line != buf )
+ fputs(buf, out);
+ free(buf);
+ fclose(out);
+ fclose(in);
+ return 0;
+}
+
+/* Skip over space and comments, in either direction. */
+char *
+skipspace(p, dir)
+ register char *p;
+ register int dir; /* 1 for forward, -1 for backward */
+{ for ( ; ; )
+ { while ( is_space(*p) )
+ p += dir;
+ if ( !(*p == '/' && p[dir] == '*') )
+ break;
+ p += dir; p += dir;
+ while ( !(*p == '*' && p[dir] == '/') )
+ { if ( *p == 0 )
+ return p; /* multi-line comment?? */
+ p += dir;
+ }
+ p += dir; p += dir;
+ }
+ return p;
+}
+
+/*
+ * Write blanks over part of a string.
+ * Don't overwrite end-of-line characters.
+ */
+int
+writeblanks(start, end)
+ char *start;
+ char *end;
+{ char *p;
+ for ( p = start; p < end; p++ )
+ if ( *p != '\r' && *p != '\n' )
+ *p = ' ';
+ return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ * 0 - definitely not a function definition;
+ * 1 - definitely a function definition;
+ * 2 - definitely a function prototype (NOT USED);
+ * -1 - may be the beginning of a function definition,
+ * append another line and look again.
+ * The reason we don't attempt to convert function prototypes is that
+ * Ghostscript's declaration-generating macros look too much like
+ * prototypes, and confuse the algorithms.
+ */
+int
+test1(buf)
+ char *buf;
+{ register char *p = buf;
+ char *bend;
+ char *endfn;
+ int contin;
+
+ if ( !isidfirstchar(*p) )
+ return 0; /* no name at left margin */
+ bend = skipspace(buf + strlen(buf) - 1, -1);
+ switch ( *bend )
+ {
+ case ';': contin = 0 /*2*/; break;
+ case ')': contin = 1; break;
+ case '{': return 0; /* not a function */
+ case '}': return 0; /* not a function */
+ default: contin = -1;
+ }
+ while ( isidchar(*p) )
+ p++;
+ endfn = p;
+ p = skipspace(p, 1);
+ if ( *p++ != '(' )
+ return 0; /* not a function */
+ p = skipspace(p, 1);
+ if ( *p == ')' )
+ return 0; /* no parameters */
+ /* Check that the apparent function name isn't a keyword. */
+ /* We only need to check for keywords that could be followed */
+ /* by a left parenthesis (which, unfortunately, is most of them). */
+ { static char *words[] =
+ { "asm", "auto", "case", "char", "const", "double",
+ "extern", "float", "for", "if", "int", "long",
+ "register", "return", "short", "signed", "sizeof",
+ "static", "switch", "typedef", "unsigned",
+ "void", "volatile", "while", 0
+ };
+ char **key = words;
+ char *kp;
+ int len = endfn - buf;
+
+ while ( (kp = *key) != 0 )
+ { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+ return 0; /* name is a keyword */
+ key++;
+ }
+ }
+ return contin;
+}
+
+/* Convert a recognized function definition or header to K&R syntax. */
+int
+convert1(buf, out, header, convert_varargs)
+ char *buf;
+ FILE *out;
+ int header; /* Boolean */
+ int convert_varargs; /* Boolean */
+{ char *endfn;
+ register char *p;
+ /*
+ * The breaks table contains pointers to the beginning and end
+ * of each argument.
+ */
+ char **breaks;
+ unsigned num_breaks = 2; /* for testing */
+ char **btop;
+ char **bp;
+ char **ap;
+ char *vararg = 0;
+
+ /* Pre-ANSI implementations don't agree on whether strchr */
+ /* is called strchr or index, so we open-code it here. */
+ for ( endfn = buf; *(endfn++) != '('; )
+ ;
+top: p = endfn;
+ breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+ if ( breaks == 0 )
+ { /* Couldn't allocate break table, give up */
+ fprintf(stderr, "Unable to allocate break table!\n");
+ fputs(buf, out);
+ return -1;
+ }
+ btop = breaks + num_breaks * 2 - 2;
+ bp = breaks;
+ /* Parse the argument list */
+ do
+ { int level = 0;
+ char *lp = NULL;
+ char *rp;
+ char *end = NULL;
+
+ if ( bp >= btop )
+ { /* Filled up break table. */
+ /* Allocate a bigger one and start over. */
+ free((char *)breaks);
+ num_breaks <<= 1;
+ goto top;
+ }
+ *bp++ = p;
+ /* Find the end of the argument */
+ for ( ; end == NULL; p++ )
+ { switch(*p)
+ {
+ case ',':
+ if ( !level ) end = p;
+ break;
+ case '(':
+ if ( !level ) lp = p;
+ level++;
+ break;
+ case ')':
+ if ( --level < 0 ) end = p;
+ else rp = p;
+ break;
+ case '/':
+ p = skipspace(p, 1) - 1;
+ break;
+ default:
+ ;
+ }
+ }
+ /* Erase any embedded prototype parameters. */
+ if ( lp )
+ writeblanks(lp + 1, rp);
+ p--; /* back up over terminator */
+ /* Find the name being declared. */
+ /* This is complicated because of procedure and */
+ /* array modifiers. */
+ for ( ; ; )
+ { p = skipspace(p - 1, -1);
+ switch ( *p )
+ {
+ case ']': /* skip array dimension(s) */
+ case ')': /* skip procedure args OR name */
+ { int level = 1;
+ while ( level )
+ switch ( *--p )
+ {
+ case ']': case ')': level++; break;
+ case '[': case '(': level--; break;
+ case '/': p = skipspace(p, -1) + 1; break;
+ default: ;
+ }
+ }
+ if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+ { /* We found the name being declared */
+ while ( !isidfirstchar(*p) )
+ p = skipspace(p, 1) + 1;
+ goto found;
+ }
+ break;
+ default:
+ goto found;
+ }
+ }
+found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+ { if ( convert_varargs )
+ { *bp++ = "va_alist";
+ vararg = p-2;
+ }
+ else
+ { p++;
+ if ( bp == breaks + 1 ) /* sole argument */
+ writeblanks(breaks[0], p);
+ else
+ writeblanks(bp[-1] - 1, p);
+ bp--;
+ }
+ }
+ else
+ { while ( isidchar(*p) ) p--;
+ *bp++ = p+1;
+ }
+ p = end;
+ }
+ while ( *p++ == ',' );
+ *bp = p;
+ /* Make a special check for 'void' arglist */
+ if ( bp == breaks+2 )
+ { p = skipspace(breaks[0], 1);
+ if ( !strncmp(p, "void", 4) )
+ { p = skipspace(p+4, 1);
+ if ( p == breaks[2] - 1 )
+ { bp = breaks; /* yup, pretend arglist is empty */
+ writeblanks(breaks[0], p + 1);
+ }
+ }
+ }
+ /* Put out the function name and left parenthesis. */
+ p = buf;
+ while ( p != endfn ) putc(*p, out), p++;
+ /* Put out the declaration. */
+ if ( header )
+ { fputs(");", out);
+ for ( p = breaks[0]; *p; p++ )
+ if ( *p == '\r' || *p == '\n' )
+ putc(*p, out);
+ }
+ else
+ { for ( ap = breaks+1; ap < bp; ap += 2 )
+ { p = *ap;
+ while ( isidchar(*p) )
+ putc(*p, out), p++;
+ if ( ap < bp - 1 )
+ fputs(", ", out);
+ }
+ fputs(") ", out);
+ /* Put out the argument declarations */
+ for ( ap = breaks+2; ap <= bp; ap += 2 )
+ (*ap)[-1] = ';';
+ if ( vararg != 0 )
+ { *vararg = 0;
+ fputs(breaks[0], out); /* any prior args */
+ fputs("va_dcl", out); /* the final arg */
+ fputs(bp[0], out);
+ }
+ else
+ fputs(breaks[0], out);
+ }
+ free((char *)breaks);
+ return 0;
+}
diff --git a/gs/src/ansihead.mak b/gs/src/ansihead.mak
new file mode 100644
index 000000000..4af7f1d28
--- /dev/null
+++ b/gs/src/ansihead.mak
@@ -0,0 +1,283 @@
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/ANSI C/X11 configuration.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unixansi.mak #
+# or makefile. Edit ansihead.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime initialization and
+# font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler. If the standard compiler for your
+# platform is ANSI-compatible, leave this line commented out; if not,
+# uncomment the line and insert the proper definition.
+
+#CC=some_C_compiler
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the other compilation flags. Add at most one of the following:
+# -Aa -w -D_HPUX_SOURCE for the HP 400.
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+XCFLAGS=
+
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS and some others want -X; Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# Apollos running DomainOS don't support -X (and -x has no effect).
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+XLIBDIRS=-L/usr/local/X/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=jpeg.dev jpeggray.dev pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=ansihead.mak
+
+# Define the ANSI-to-K&R dependency (none for ANSI compilers).
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCAUX=$(CC)
+CCLEAF=$(CCC)
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile is generic.
+# tar_cat concatenates this makefile with the generic makefiles.
diff --git a/gs/src/append_l.com b/gs/src/append_l.com
new file mode 100644
index 000000000..f33a3d9c0
--- /dev/null
+++ b/gs/src/append_l.com
@@ -0,0 +1,19 @@
+$ Verif = F$Verify(0)
+$ ! OpenVMS command file to emulate behavior of:
+$ !
+$ ! Appending a string to the end of a new or existing file
+$ !
+$ OPEN="OPEN"
+$ WRITE="WRITE"
+$ CLOSE="CLOSE"
+$ IF F$SEARCH("''P1'") .EQS. "" THEN OPEN/WRITE TEXT_FILE 'P1'
+$ IF F$SEARCH("''P1'") .NES. "" THEN OPEN/APPEND TEXT_FILE 'P1'
+$ IF P2 .NES. "" THEN WRITE TEXT_FILE "''P2'"
+$ IF P3 .NES. "" THEN WRITE TEXT_FILE "''P3'"
+$ IF P4 .NES. "" THEN WRITE TEXT_FILE "''P4'"
+$ IF P5 .NES. "" THEN WRITE TEXT_FILE "''P5'"
+$ IF P6 .NES. "" THEN WRITE TEXT_FILE "''P6'"
+$ IF P7 .NES. "" THEN WRITE TEXT_FILE "''P7'"
+$ IF P8 .NES. "" THEN WRITE TEXT_FILE "''P8'"
+$ CLOSE TEXT_FILE
+$ xxx = F$Verify(Verif)
diff --git a/gs/src/bcc32.cfg b/gs/src/bcc32.cfg
new file mode 100644
index 000000000..6f80f44e2
--- /dev/null
+++ b/gs/src/bcc32.cfg
@@ -0,0 +1,5 @@
+-wdup -wret -wstr -w-stu -wsus -wvoi -wzst
+-waus -wdef -w-eff -w-par -w-pia -w-rch -wrvl
+-w-amb -w-amp -w-nod -w-stv -wuse
+-wapt -w-cln -wcpt -wdgn -wrpt -w-sig -w-ucp
+-N
diff --git a/gs/src/bcwin32.mak b/gs/src/bcwin32.mak
new file mode 100644
index 000000000..5bfbefb8f
--- /dev/null
+++ b/gs/src/bcwin32.mak
@@ -0,0 +1,434 @@
+# Copyright (C) 1989-1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# bcwin32.mak
+# makefile for (MS-Windows 3.1/Win32s / Windows 95 / Windows NT) +
+# Borland C++ 4.5 platform.
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+GS_DOCDIR=c:/gs
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with \;.
+# Use / to indicate directories, not a single \.
+
+GS_LIB_DEFAULT=.;c:/gs\;c:/gs/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+DEBUG=0
+
+# Setting TDEBUG=1 includes symbol table information for the debugger,
+# and also enables stack checking. Code is substantially slower and larger.
+
+TDEBUG=0
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+NOPRIVATE=0
+
+# Define the names of the executable files.
+
+GS=gswin32
+GSCONSOLE=gswin32c
+GSDLL=gsdll32
+
+# To build two small executables and a large DLL use MAKEDLL=1.
+# To build two large executables use MAKEDLL=0.
+
+MAKEDLL=1
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# Define any other compilation flags.
+
+CFLAGS=
+
+# ------ Platform-specific options ------ #
+
+# Define the drive, directory, and compiler name for the Borland C files.
+# COMPDIR contains the compiler and linker (normally \bc\bin).
+# INCDIR contains the include files (normally \bc\include).
+# LIBDIR contains the library files (normally \bc\lib).
+# COMP is the full C compiler name (bcc32 for Borland C++).
+# COMPCPP is the full C++ compiler path name (bcc32 for Borland C++).
+# COMPAUX is the compiler name for DOS utilities (bcc for Borland C++).
+# RCOMP is the resource compiler name (brcc32 for Borland C++).
+# LINK is the full linker path name (normally \bc\bin\tlink32).
+# Note that these prefixes are always followed by a \,
+# so if you want to use the current directory, use an explicit '.'.
+
+COMPBASE=c:\bc
+COMPDIR=$(COMPBASE)\bin
+INCDIR=$(COMPBASE)\include
+LIBDIR=$(COMPBASE)\lib
+COMP=$(COMPDIR)\bcc32
+COMPCPP=$(COMP)
+COMPAUX=$(COMPDIR)\bcc
+RCOMP=$(COMPDIR)\brcc32
+LINK=$(COMPDIR)\tlink32
+
+# If you don't have an assembler, set USE_ASM=0. Otherwise, set USE_ASM=1,
+# and set ASM to the name of the assembler you are using. This can be
+# a full path name if you want. Normally it will be masm or tasm.
+
+USE_ASM=0
+ASM=tasm
+
+# Define the processor architecture. (always i386)
+
+CPU_FAMILY=i386
+
+# Define the processor (CPU) type. (386, 486 or 586)
+
+CPU_TYPE=386
+
+# Define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If you have a 486 or Pentium CPU, you should normally set FPU_TYPE to 387,
+# since most of these CPUs include the equivalent of an 80387 on-chip;
+# however, the 486SX and the Cyrix 486SLC do not have an on-chip FPU, so if
+# you have one of these CPUs and no external FPU, set FPU_TYPE to -1 or 0.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+FPU_TYPE=0
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev ttfont.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=mswindll.dev mswinprn.dev mswinpr2.dev
+DEVICE_DEVS2=epson.dev eps9high.dev eps9mid.dev epsonc.dev ibmpro.dev
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=djet500c.dev declj250.dev lj250.dev jetp3852.dev r4081.dev lbp8.dev uniprint.dev
+DEVICE_DEVS6=st800.dev stcolor.dev bj10e.dev bj200.dev m8510.dev necp6.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=t4693d2.dev t4693d4.dev t4693d8.dev tek4696.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=bmpmono.dev bmp16.dev bmp256.dev bmp16m.dev tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options ---------------------------- #
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=bcwin32.mak winlib.mak winint.mak
+
+# Define the current directory prefix and shell invocations.
+
+D=\\
+
+EXP=
+EXPP=
+SH=
+SHP=
+
+# Define the arguments for genconf.
+
+#CONFILES=-p %s+ -o $(ld_tr) -l lib.tr
+# We can't use $(ld_tr) because Borland make expands macro usages in
+# macro definitions at definition time, not at use time.
+CONFILES=-p %s+ -o ld$(CONFIG).tr -l lib.tr
+
+# Define the generic compilation flags.
+
+PLATOPT=
+
+INTASM=
+PCFBASM=
+
+# Make sure we get the right default target for make.
+
+dosdefault: default gs16spl.exe
+
+# Define the compilation flags.
+
+!if $(CPU_TYPE)>500
+ASMCPU=/DFOR80386 /DFOR80486
+CPFLAGS=-DFOR80486 -DFOR80386
+!else if $(CPU_TYPE)>400
+ASMCPU=/DFOR80386 /DFOR80486
+CPFLAGS=-DFOR80486 -DFOR80386
+!else
+ASMCPU=/DFOR80386
+CPFLAGS=-DFOR80386
+!endif
+
+!if $(CPU_TYPE) >= 486 || $(FPU_TYPE) > 0
+ASMFPU=/DFORFPU
+!else
+!if $(FPU_TYPE) < 0
+ASMFPU=/DNOFPU
+!else
+ASMFPU=
+!endif
+!endif
+FPFLAGS=
+FPLIB=
+
+!if $(NOPRIVATE)!=0
+CP=-DNOPRIVATE
+!else
+CP=
+!endif
+
+!if $(DEBUG)!=0
+CD=-DDEBUG
+!else
+CD=
+!endif
+
+!if $(TDEBUG)!=0
+CT=-v
+LCT=-v -m -s
+CO= # no optimization when debugging
+ASMDEBUG=/DDEBUG
+!else
+CT=
+LCT=
+CO=-Z -O2
+!endif
+
+!if $(DEBUG)!=0 || $(TDEBUG)!=0
+CS=-N
+!else
+CS=
+!endif
+
+# Specify output object name
+CCOBJNAME=-o
+
+# Specify function prolog type
+COMPILE_FOR_DLL=-WDE
+COMPILE_FOR_EXE=-WE
+COMPILE_FOR_CONSOLE_EXE=-WC
+
+GENOPT=$(CP) $(CD) $(CT) $(CS)
+
+CCFLAGS0=$(GENOPT) $(PLATOPT) $(CPFLAGS) $(FPFLAGS) $(CFLAGS) $(XCFLAGS)
+CCFLAGS=$(CCFLAGS0)
+CC=$(COMP) @ccf32.tr
+CPP=$(COMPCPP) @ccf32.tr
+!if $(MAKEDLL)
+WX=$(COMPILE_FOR_DLL)
+!else
+WX=$(COMPILE_FOR_EXE)
+!endif
+CCC=$(CC) $(WX) $(CO) -c
+CCD=$(CC) $(WX) -c
+CCINT=$(CC) $(WX) -c
+CCCF=$(CCC)
+CCLEAF=$(CCC)
+
+# Compiler for auxiliary programs
+
+CCAUX=$(COMPAUX) -ml -I$(INCDIR) -L$(LIBDIR) -O
+
+# Compiler for Windows headers includes
+
+CCCWIN=$(CCC)
+
+# Define the generic compilation rules.
+
+.c.obj:
+ $(CCC) { $<}
+
+.cpp.obj:
+ $(CCC) { $<}
+
+# Define the files to be removed by `make clean'.
+# nmake expands macros when encountered, not when used,
+# so this must precede the !include statements.
+
+BEGINFILES2=gs16spl.exe
+
+# Include the generic makefiles.
+
+!include winlib.mak
+!include winint.mak
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+ccf32.tr: $(MAKEFILE) makefile
+ echo -a1 -d -r -G -N -X -I$(INCDIR) $(CCFLAGS0) -DCHECK_INTERRUPTS > ccf32.tr
+
+# Since we are running in a Windows environment with a different compiler
+# for the DOS utilities, we have to invoke genarch by hand:
+$(GENARCH_XE): genarch.c $(stdpre_h) $(iref_h) ccf32.tr
+ $(COMP) -I$(INCDIR) -L$(LIBDIR) -O genarch.c
+ echo ***** Run "win genarch arch.h", then continue make. *****
+
+# -------------------------------- Library -------------------------------- #
+
+# See winlib.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+LIBCTR=libc32.tr
+
+$(LIBCTR): $(MAKEFILE) $(ECHOGS_XE)
+ echogs -w $(LIBCTR) $(LIBDIR)\import32.lib+
+ echogs -a $(LIBCTR) $(LIBDIR)\cw32.lib
+
+!if $(MAKEDLL)
+# The graphical small EXE loader
+$(GS_XE): $(GSDLL).dll $(DWOBJ) $(GSCONSOLE).exe
+ $(LINK) /Tpe $(LCT) @&&!
+$(LIBDIR)\c0w32 +
+$(DWOBJ) +
+,$(GS_XE),$(GS), +
+$(LIBDIR)\import32 +
+$(LIBDIR)\cw32, +
+dwmain32.def, +
+$(GS).res
+!
+
+# The console mode small EXE loader
+$(GSCONSOLE).exe: $(OBJC) $(GS).res dw32c.def
+ $(LINK) /Tpe /ap $(LCT) $(DEBUGLINK) @&&!
+$(LIBDIR)\c0w32 +
+$(OBJC) +
+,$(GSCONSOLE).exe,$(GSCONSOLE), +
+$(LIBDIR)\import32 +
+$(LIBDIR)\cw32, +
+dw32c.def, +
+$(GS).res
+!
+
+# The big DLL
+$(GSDLL).dll: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(GSDLL).res
+ $(LINK) $(LCT) /Tpd $(LIBDIR)\c0d32 gsdll @$(ld_tr) $(INTASM) ,$(GSDLL).dll,$(GSDLL),@lib.tr @$(LIBCTR),$(GSDLL).def,$(GSDLL).res
+
+!else
+# The big graphical EXE
+$(GS_XE): $(GSCONSOLE).exe $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(DWOBJNO) $(GS).res dwmain32.def
+ copy $(ld_tr) gswin32.tr
+ echo $(DWOBJNO) + >> gswin32.tr
+ $(LINK) $(LCT) /Tpe $(LIBDIR)\c0w32 gsdll @gswin32.tr $(INTASM) ,$(GS_XE),$(GS),@lib.tr @$(LIBCTR),dwmain32.def,$(GS).res
+ -del gswin32.tr
+
+# The big console mode EXE
+$(GSCONSOLE).exe: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(OBJCNO) $(GS).res dw32c.def
+ copy $(ld_tr) gswin32.tr
+ echo $(OBJCNO) + >> gswin32.tr
+ $(LINK) $(LCT) /Tpe /ap $(LIBDIR)\c0w32 gsdll @gswin32.tr $(INTASM) ,$(GSCONSOLE),$(GSCONSOLE),@lib.tr @$(LIBCTR),dw32c.def,$(GS).res
+ -del gswin32.tr
+!endif
+
+# Access to 16 spooler from Win32s
+
+gs16spl.exe: gs16spl.c gs16spl.rc
+ $(CCAUX) -W -ms -c -v -I$(INCDIR) $*.c
+ $(COMPDIR)\brcc -i$(INCDIR) -r $*.rc
+ $(COMPDIR)\tlink /Twe /c /m /s /l @&&!
+$(LIBDIR)\c0ws +
+$*.obj +
+,$*.exe,$*, +
+$(LIBDIR)\import +
+$(LIBDIR)\mathws +
+$(LIBDIR)\cws, +
+$*.def
+!
+ $(COMPDIR)\rlink -t $*.res $*.exe
+
+# end of makefile
+
+
+
diff --git a/gs/src/bench.c b/gs/src/bench.c
new file mode 100644
index 000000000..229560913
--- /dev/null
+++ b/gs/src/bench.c
@@ -0,0 +1,360 @@
+/* pop (%!) .skipeof */
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* bench.c */
+/* Simple hardware benchmarking suite (C and PostScript) */
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * Read the CPU time (in seconds since an implementation-defined epoch)
+ * into ptm[0], and fraction (in nanoseconds) into ptm[1].
+ */
+extern void gp_get_usertime(long ptm[2]);
+
+/* Patchup for GS externals */
+FILE *gs_stdout;
+FILE *gs_stderr;
+const char gp_scratch_file_name_prefix[] = "gs_";
+void gp_init_console() { }
+FILE *gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ return NULL; }
+void gp_set_printer_binary(int prnfno, int binary) { }
+void gs_exit(n)
+{ exit(n); }
+void lprintf_file_and_line(FILE *f, const char *file, int line)
+{ fprintf(f, "%s(%d): ", file, line); }
+
+/* Loop unrolling macros */
+#define do10(x) x;x;x;x;x; x;x;x;x;x
+
+/* Define the actual benchmarks. */
+static int
+iadd(int a, int n, char **msg)
+{ int b = 0, i;
+ for ( i = n / 20; --i >= 0; ) { do10((b += a, b += i)); }
+ *msg = "integer adds";
+ return b;
+}
+static int
+imul(int a, int n, char **msg)
+{ int b = 1, i;
+ for ( i = n / 20; --i > 0; ) { do10((b *= a, b *= i)); }
+ *msg = "integer multiplies";
+ return b;
+}
+static int
+idiv(int a, int n, char **msg)
+{ int b = 1, i;
+ for ( i = n / 20; --i > 0; ) { b += 999999; do10((b /= a, b /= i)); }
+ *msg = "integer divides";
+ return b;
+}
+static int
+fadd(float a, int n, char **msg)
+{ float b = 0;
+ int i;
+ for ( i = n / 10; --i >= 0; ) { do10((b += a)); }
+ *msg = "floating adds";
+ return b;
+}
+static int
+fmul(float a, int n, char **msg)
+{ float b = 1;
+ int i;
+ for ( i = n / 10; --i >= 0; ) { do10((b *= a)); }
+ *msg = "floating multiplies";
+ return b;
+}
+static int
+fdiv(float a, int n, char **msg)
+{ float b = 1;
+ int i;
+ for ( i = n / 10; --i >= 0; ) { do10((b /= a)); }
+ *msg = "floating divides";
+ return b;
+}
+static int
+fconv(int a, int n, char **msg)
+{ int b[10];
+ float f[10];
+ int i;
+ b[0] = a;
+ for ( i = n / 20; --i >= 0; )
+ f[0] = b[0], f[1] = b[1], f[2] = b[2], f[3] = b[3], f[4] = b[4],
+ f[5] = b[5], f[6] = b[6], f[7] = b[7], f[8] = b[8], f[9] = b[9],
+ b[0] = f[1], b[1] = f[2], b[2] = f[3], b[3] = f[4], b[4] = f[5],
+ b[5] = f[6], b[6] = f[7], b[7] = f[8], b[8] = f[9], b[9] = f[0];
+ *msg = "float/int conversions";
+ return b[0];
+}
+static int
+mfast(int *m, int n, char **msg)
+{ int i;
+ m[0] = n;
+ for ( i = n / 20; --i >= 0; )
+ m[9] = m[8], m[8] = m[7], m[7] = m[6], m[6] = m[5], m[5] = m[4],
+ m[4] = m[3], m[3] = m[2], m[2] = m[1], m[1] = m[0], m[0] = m[9];
+ *msg = "fast memory accesses";
+ return m[0];
+}
+static int
+mslow(int *m, int n, char **msg)
+{ int *p;
+ int i, k = 0;
+ m[0] = n;
+ for ( i = n / 20; --i >= 0; k = (k + 397) & 0x3ffff )
+ p = m + k,
+ p[0] = p[100], p[20] = p[120], p[40] = p[140],
+ p[60] = p[160], p[80] = p[180],
+ p[200] = p[300], p[220] = p[320], p[240] = p[340],
+ p[260] = p[360], p[280] = p[380];
+ *msg = "slow memory accesses";
+ return m[0];
+}
+
+int
+main(int argc, const char *argv[])
+{ int i;
+ int *mem = malloc(1100000);
+
+ gs_stdout = stdout;
+ gs_stderr = stderr;
+ for ( i = 0; ; ++i )
+ { long t0[2], t1[2];
+ char *msg;
+ int n;
+ gp_get_usertime(t0);
+ switch ( i )
+ {
+ case 0: iadd(0, n = 10000000, &msg); break;
+ case 1: imul(1, n = 1000000, &msg); break;
+ case 2: idiv(1, n = 1000000, &msg); break;
+ case 3: fadd(3.14, n = 10000000, &msg); break;
+ case 4: fmul(1.0000001, n = 10000000, &msg); break;
+ case 5: fdiv(1.0000001, n = 1000000, &msg); break;
+ case 6: fconv(12345, n = 10000000, &msg); break;
+ case 7: mfast(mem, n = 10000000, &msg); break;
+ case 8: mslow(mem, n = 1000000, &msg); break;
+ default: free(mem); exit(0);
+ }
+ gp_get_usertime(t1);
+ printf("Time for %9d %s = %g ms\n", n, msg,
+ (t1[0] - t0[0]) * 1000.0 + (t1[1] - t0[1]) / 1000000.0);
+ fflush(stdout);
+ }
+}
+
+/*
+ Output from SPARCstation 10, gcc -O bench.c gp_unix.c:
+
+Time for 10000000 integer adds = 113.502 ms
+Time for 1000000 integer multiplies = 467.965 ms
+Time for 1000000 integer divides = 594.328 ms
+Time for 10000000 floating adds = 641.21 ms
+Time for 10000000 floating multiplies = 643.357 ms
+Time for 1000000 floating divides = 131.995 ms
+Time for 10000000 float/int conversions = 602.061 ms
+Time for 10000000 fast memory accesses = 201.048 ms
+Time for 1000000 slow memory accesses = 552.606 ms
+
+ Output from 486DX/25, wcl386 -oit bench.c gp_iwatc.c gp_msdos.c:
+
+Time for 10000000 integer adds = 490 ms
+Time for 1000000 integer multiplies = 770 ms
+Time for 1000000 integer divides = 1860 ms
+Time for 10000000 floating adds = 4070 ms
+Time for 10000000 floating multiplies = 4450 ms
+Time for 1000000 floating divides = 2470 ms
+Time for 10000000 float/int conversions = 25650 ms
+Time for 10000000 fast memory accesses = 990 ms
+Time for 1000000 slow memory accesses = 330 ms
+
+ */
+
+/*
+ The rest of this file contains a similar benchmark in PostScript.
+
+%!
+/timer % <str> <N> <proc> timer
+ { bind 2 copy usertime mark 4 2 roll repeat cleartomark usertime exch sub
+ % Stack: str N proc dt
+ exch pop
+ (Time for ) print exch =only ( ) print exch =only (: ) print
+ =only ( ms
+) print flush
+ } def
+
+(x 20 integer adds) 5000 { 0
+ 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add
+ 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add
+pop } timer
+
+(x 20 integer multiplies) 5000 { 1
+ 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul
+ 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul
+pop } timer
+
+(x 20 integer divides) 5000 { 1000000000
+ 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv
+ 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv
+pop } timer
+
+(x 20 floating adds) 5000 { 0.0
+1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add
+1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add
+pop } timer
+
+(x 20 floating multiplies) 5000 { 1.0
+2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul
+2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul
+pop } timer
+
+(x 20 floating divides) 5000 { 1.0
+2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div
+2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div
+pop } timer
+
+(x 20 float/int conversions) 5000 { 12345.0
+ cvi cvr cvi cvr cvi cvr cvi cvr cvi cvr
+ cvi cvr cvi cvr cvi cvr cvi cvr cvi cvr
+pop } timer
+
+/S 2048 string def
+(x 10000(byte) fast memory accesses) 1000 {
+//S 1024 1000 getinterval //S copy pop
+//S 1024 1000 getinterval //S copy pop
+//S 1024 1000 getinterval //S copy pop
+//S 1024 1000 getinterval //S copy pop
+//S 1024 1000 getinterval //S copy pop
+} timer
+
+/A [ 500 { 2048 string } repeat ] def
+(x 500 x 2000(byte) slower memory accesses) 10 {
+0 1 499 {
+//A exch get dup 1024 1000 getinterval exch copy pop
+} for
+} timer
+
+/Times-Roman findfont 36 scalefont setfont
+currentcacheparams pop pop 0 1 index setcacheparams
+/D [4 0 0 4 0 0] 1440 1440 <00 ff> makeimagedevice def
+D setdevice
+72 72 translate
+gsave 15 rotate
+0 0 moveto (A) show
+(x 10 (A) show (cache)) 100 {
+0 0 moveto
+(A) show (A) show (A) show (A) show (A) show
+(A) show (A) show (A) show (A) show (A) show
+} timer grestore
+
+0 setcachelimit
+gsave 10 rotate
+(x 10 (A) show (no cache)) 10 {
+0 0 moveto
+(A) show (A) show (A) show (A) show (A) show
+(A) show (A) show (A) show (A) show (A) show
+} timer grestore
+
+quit
+
+ Results for SUN Sparc 2 (rated at 25 MIPS according to manual)
+
+./gs
+Now in gs_init.ps
+TextAlphaBits defined GraphicsAlphaBits defined
+Aladdin Ghostscript 3.50 (1995-9-24)
+(c) 1995 Aladdin Enterprises, Menlo Park, CA. All rights reserved. This
+software comes with NO WARRANTY: see the file PUBLIC for details. Leaving
+gs_init.ps
+GS>(ben1.c) run
+Time for 5000 x 20 integer adds: 171 ms
+Time for 5000 x 20 integer multiplies: 504 ms
+Time for 5000 x 20 integer divides: 334 ms
+Time for 5000 x 20 floating adds: 148 ms
+Time for 5000 x 20 floating multiplies: 165 ms
+Time for 5000 x 20 floating divides: 194 ms
+Time for 5000 x 20 float/int conversions: 121 ms
+Time for 1000 x 10000(byte) fast memory accesses: 112 ms
+Time for 10 x 500 x 2000(byte) slower memory accesses: 236 ms
+Loading NimbusRomanNo9L-Regular font from
+[...]/n021003l.gsf... 1739080 414724 2564864 1251073 0
+done. Time for 100 x 10 (A) show (cache): 144 ms
+Time for 10 x 10 (A) show (no cache): 538 ms
+
+ Output from SPARCstation 10, gs 3.60 compiled with gcc -g -O -DDEBUG:
+
+gsnd bench.c
+Aladdin Ghostscript 3.60 (1995-10-23)
+Copyright (C) 1995 Aladdin Enterprises, Menlo Park, CA. All rights reserved.
+This software comes with NO WARRANTY: see the file PUBLIC for details.
+Time for 5000 x 20 integer adds: 192 ms
+Time for 5000 x 20 integer multiplies: 561 ms
+Time for 5000 x 20 integer divides: 396 ms
+Time for 5000 x 20 floating adds: 202 ms
+Time for 5000 x 20 floating multiplies: 247 ms
+Time for 5000 x 20 floating divides: 243 ms
+Time for 5000 x 20 float/int conversions: 157 ms
+Time for 1000 x 10000(byte) fast memory accesses: 136 ms
+Time for 10 x 500 x 2000(byte) slower memory accesses: 235 ms
+Loading Temps-RomanSH font from /opt/home/peter/gs/fonts/soho/tersh___.pfb... 1759156 432729 2564864 1251025 0 done.
+Time for 100 x 10 (A) show (cache): 161 ms
+Time for 10 x 10 (A) show (no cache): 449 ms
+
+ Output from 486DX/25, gs 2.6.1 compiled with wcc386 -oi[t]:
+
+gsndt bench.c
+Initializing... done.
+Ghostscript 2.6.1 (5/28/93)
+Copyright (C) 1990-1993 Aladdin Enterprises, Menlo Park, CA.
+ All rights reserved.
+Ghostscript comes with NO WARRANTY: see the file COPYING for details.
+Time for 5000 x 20 integer adds: 550 ms
+Time for 5000 x 20 integer multiplies: 940 ms
+Time for 5000 x 20 integer divides: 880 ms
+Time for 5000 x 20 floating adds: 550 ms
+Time for 5000 x 20 floating multiplies: 660 ms
+Time for 5000 x 20 floating divides: 930 ms
+Time for 5000 x 20 float/int conversions: 830 ms
+Time for 1000 x 10000(byte) fast memory accesses: 660 ms
+Time for 10 x 500 x 2000(byte) slower memory accesses: 540 ms
+Loading Temps-RomanSH font from c:\gs\fonts\softhorz\tersh___.pfb... 1298792 1207949 0 done.
+Time for 100 x 10 (A) show (cache): 13520 ms
+Time for 10 x 10 (A) show (no cache): 1310 ms
+
+ Output from 486DX/25, gs 3.52 compiled with wcc386 -oi[t]:
+
+Aladdin Ghostscript 3.52 (1995-10-2)
+Copyright (c) 1995 Aladdin Enterprises, Menlo Park, CA. All rights reserved.
+This software comes with NO WARRANTY: see the file PUBLIC for details.
+Time for 5000 x 20 integer adds: 660 ms
+Time for 5000 x 20 integer multiplies: 1100 ms
+Time for 5000 x 20 integer divides: 940 ms
+Time for 5000 x 20 floating adds: 710 ms
+Time for 5000 x 20 floating multiplies: 830 ms
+Time for 5000 x 20 floating divides: 1040 ms
+Time for 5000 x 20 float/int conversions: 820 ms
+Time for 1000 x 10000(byte) fast memory accesses: 660 ms
+Time for 10 x 500 x 1000(byte) slower memory accesses: 600 ms
+Loading Temps-RomanSH font from c:\gs\fonts\softhorz\tersh___.pfb... 1678548 375231 2564864 1250964 0 done.
+Time for 100 x 10 (A) show (cache): 2520 ms
+Time for 10 x 10 (A) show (no cache): 1600 ms
+
+ */
diff --git a/gs/src/bfont.h b/gs/src/bfont.h
new file mode 100644
index 000000000..3d140030f
--- /dev/null
+++ b/gs/src/bfont.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* bfont.h */
+/* Interpreter internal routines and data needed for building fonts */
+/* Requires gxfont.h */
+#include "ifont.h"
+
+/* In zfont.c */
+int add_FID(P2(ref *pfdict, gs_font *pfont));
+font_proc_make_font(zdefault_make_font);
+font_proc_make_font(zbase_make_font);
+/* The global font directory */
+extern gs_font_dir *ifont_dir;
+
+/* Structure for passing BuildChar and BuildGlyph procedures. */
+typedef struct build_proc_refs_s {
+ ref BuildChar;
+ ref BuildGlyph;
+} build_proc_refs;
+
+/* Options for collecting parameters from a font dictionary. */
+/* The comment indicates where the option is tested. */
+typedef enum {
+ bf_options_none = 0,
+ bf_Encoding_optional = 1, /* build_gs_font */
+ bf_FontBBox_required = 2, /* build_gs_simple_font */
+ bf_UniqueID_ignored = 4, /* build_gs_simple_font */
+ bf_CharStrings_optional = 8, /* build_gs_primitive_font */
+ bf_notdef_required = 16 /* build_gs_primitive_font */
+} build_font_options_t;
+
+/* In zfont2.c */
+int build_proc_name_refs(P3(build_proc_refs *pbuild,
+ const char _ds *bcstr,
+ const char _ds *bgstr));
+int build_gs_font_procs(P2(os_ptr, build_proc_refs *));
+int build_gs_primitive_font(P6(os_ptr, gs_font_base **, font_type,
+ gs_memory_type_ptr_t, const build_proc_refs *,
+ build_font_options_t));
+int build_gs_simple_font(P6(os_ptr, gs_font_base **, font_type,
+ gs_memory_type_ptr_t, const build_proc_refs *,
+ build_font_options_t));
+void lookup_gs_simple_font_encoding(P1(gs_font_base *));
+int build_gs_font(P6(os_ptr, gs_font **, font_type,
+ gs_memory_type_ptr_t, const build_proc_refs *,
+ build_font_options_t));
+int define_gs_font(P1(gs_font *));
diff --git a/gs/src/bseq.h b/gs/src/bseq.h
new file mode 100644
index 000000000..91b8941f2
--- /dev/null
+++ b/gs/src/bseq.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 1990, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* bseq.h */
+/* Definitions for Level 2 binary object sequences */
+
+/* Binary object sequence element types */
+typedef enum {
+ bs_null = 0,
+ bs_integer = 1,
+ bs_real = 2,
+ bs_name = 3,
+ bs_boolean = 4,
+ bs_string = 5,
+ bs_eval_name = 6,
+ bs_array = 9,
+ bs_mark = 10,
+ /*
+ * We extend the PostScript language definition by allowing
+ * dictionaries in binary object sequences. The data for
+ * a dictionary is like that for an array, with the following
+ * changes:
+ * - If the size is an even number, the value is the index of
+ * the first of a series of alternating keys and values.
+ * - If the size is 1, the value is the index of another
+ * object (which must also be a dictionary, and must not have
+ * size = 1); this object represents the same object as that one.
+ */
+ bs_dictionary = 15
+} bin_seq_type;
+#define bs_executable 128
+
+/* Definition of an object in a binary object sequence. */
+typedef struct {
+ byte tx; /* type and executable flag */
+ byte unused;
+ union {
+ bits16 w;
+ byte b[2];
+ } size;
+ union {
+ bits32 w;
+ float f;
+ byte b[4];
+ } value;
+} bin_seq_obj;
diff --git a/gs/src/btoken.h b/gs/src/btoken.h
new file mode 100644
index 000000000..f880e6fc9
--- /dev/null
+++ b/gs/src/btoken.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 1990 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* btoken.h */
+/* Definitions for Level 2 binary tokens */
+
+/* Binary token types */
+typedef enum {
+ bt_seq = 128,
+ bt_seq_IEEE_msb = 128, /* binary object sequence, */
+ /* IEEE floats, big-endian */
+ bt_seq_IEEE_lsb = 129, /* ditto, little-endian */
+ bt_seq_native_msb = 130, /* ditto, native floats, big-endian */
+ bt_seq_native_lsb = 131, /* ditto, little-endian */
+ bt_int32_msb = 132,
+ bt_int32_lsb = 133,
+ bt_int16_msb = 134,
+ bt_int16_lsb = 135,
+ bt_int8 = 136,
+ bt_fixed = 137,
+ bt_float_IEEE_msb = 138,
+ bt_float_IEEE_lsb = 139,
+ bt_float_native = 140,
+ bt_boolean = 141,
+ bt_string_256 = 142,
+ bt_string_64k_msb = 143,
+ bt_string_64k_lsb = 144,
+ bt_litname_system = 145,
+ bt_execname_system = 146,
+ bt_litname_user = 147,
+ bt_execname_user = 148,
+ bt_num_array = 149
+} bt_char;
+#define bt_char_min 128
+#define bt_char_max 159
+
+/* Define the number of required initial bytes for binary tokens */
+/* (including the token type byte). */
+extern const byte bin_token_bytes[]; /* in iscan2.c */
+#define bin_token_bytes_values\
+ 4, 4, 4, 4, 5, 5, 3, 3, 2, 2, 5, 5, 5,\
+ 2, 2, 3, 3, 2, 2, 2, 2, 4,\
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* undefined */
+#define binary_token_bytes(btchar)\
+ (bin_token_bytes[(btchar) - bt_char_min])
diff --git a/gs/src/cc-head.mak b/gs/src/cc-head.mak
new file mode 100644
index 000000000..8f15e7bee
--- /dev/null
+++ b/gs/src/cc-head.mak
@@ -0,0 +1,287 @@
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/cc/X11 configuration.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unix-cc.mak #
+# or makefile. Edit cc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+#GENOPT=-DDEBUG
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the other compilation flags. Add at most one of the following:
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# Also add -Xa if your compiler accepts it.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+XCFLAGS=
+
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS and some others want -X; Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+XLIBDIRS=-L/usr/local/X/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+# Sun's cc can't compile gdevcdj.c.
+#DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS4=
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS6=
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=jpeg.dev jpeggray.dev pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=cc-head.mak
+
+# Define the ANSI-to-K&R dependency.
+
+# This should be ansi2knr$(XEAUX), or $(ANSI2KNR_XE), but these macros
+# haven't been defined yet, and some buggy 'make' programs expand macros in
+# definitions at the time of definition rather than at the time of use.
+AK=ansi2knr
+
+# Define the compilation rules and flags.
+
+CCC=$(SHP)ccgs "$(CC) $(CCFLAGS) -c"
+# We compile ansi2knr, and only ansi2knr, unmodified.
+CCA2K=$(CC)
+CCAUX=$(SHP)ccgs "$(CC)"
+CCLEAF=$(CCC)
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
diff --git a/gs/src/ccfont.h b/gs/src/ccfont.h
new file mode 100644
index 000000000..8a381ad96
--- /dev/null
+++ b/gs/src/ccfont.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ccfont.h */
+/* Header for fonts compiled into C. */
+
+#ifndef ccfont_INCLUDED
+# define ccfont_INCLUDED
+
+/* Include all the things a compiled font needs. */
+#include "std.h"
+#include "gsmemory.h"
+#include "iref.h"
+#include "ivmspace.h" /* for avm_foreign */
+#include "store.h"
+
+/* Define type-specific refs for initializing arrays. */
+#define ref_(t) struct { struct tas_s tas; t value; }
+#define boolean_v(b) { {t_boolean<<r_type_shift}, (ushort)(b) }
+#define integer_v(i) { {t_integer<<r_type_shift}, (long)(i) }
+#define null_v() { {t_null<<r_type_shift} }
+#define real_v(v) { {t_real<<r_type_shift}, (float)(v) }
+
+/* Define other initialization structures. */
+typedef struct { byte encx, charx; } charindex;
+/*
+ * We represent mostly-string arrays by byte strings. Each element
+ * starts with length bytes. If the first length byte is not 255,
+ * it and the following byte define a big-endian length of a string or name.
+ * If the first two bytes are (255,255), this element is null.
+ * Otherwise, the initial 255 is followed by a 2-byte big-endian length
+ * of a string that must be scanned as a token.
+ */
+typedef const char *cfont_string_array;
+
+/* Support routines in iccfont.c */
+typedef struct {
+ const charindex *enc_keys; /* keys from encoding vectors */
+ uint num_enc_keys;
+ uint num_str_keys;
+ uint extra_slots; /* (need extra for fonts) */
+ uint dict_attrs; /* protection for dictionary */
+ uint value_attrs; /* protection for values */
+ /* (only used for string dicts) */
+} cfont_dict_keys;
+/* We pass a procedure vector to the font initialization routine */
+/* to avoid having externs, which compromise sharability. */
+/* On MS-DOS, each compiled font has its own data segment, */
+/* so all of these procedures must be declared 'huge' for Borland C. */
+typedef struct cfont_procs_s {
+ int huge (*ref_dict_create)(P4(ref *, const cfont_dict_keys *,
+ cfont_string_array, const ref *));
+ int huge (*string_dict_create)(P4(ref *, const cfont_dict_keys *,
+ cfont_string_array,
+ cfont_string_array));
+ int huge (*num_dict_create)(P5(ref *, const cfont_dict_keys *,
+ cfont_string_array, const ref *,
+ const char *));
+ int huge (*name_array_create)(P3(ref *, cfont_string_array, int));
+ int huge (*string_array_create)(P4(ref *, cfont_string_array,
+ int /*size*/,
+ uint /*protection*/));
+ int huge (*name_create)(P2(ref *, const char *));
+ int huge (*ref_from_string)(P3(ref *, const char *, uint));
+} cfont_procs;
+
+/*
+ * In order to make it possible for third parties to compile fonts (into
+ * a shared library, on systems that support such things), we define
+ * a tiny procedural interface for getting access to the compiled font table.
+ */
+typedef huge int ccfont_fproc(P2(const cfont_procs *, ref *));
+/* There should be some consts in the *** below, but a number of */
+/* C compilers don't handle const properly in such situations. */
+extern int ccfont_fprocs(P2(int *, ccfont_fproc ***));
+#define ccfont_version 17 /* for checking against libraries */
+
+#endif /* ccfont_INCLUDED */
diff --git a/gs/src/ccgs b/gs/src/ccgs
new file mode 100644
index 000000000..49cc5dfcd
--- /dev/null
+++ b/gs/src/ccgs
@@ -0,0 +1,40 @@
+# This file is a hack. If `make' had macros with parameters,
+# this file would be unnecessary!
+if ( test -n "$6" ) then
+ ./ansi2knr $6 _temp_$$.c
+ $1 $2 $3 _temp_$$.c
+ rm -f $5
+ mv _temp_$$.o $5
+else
+# Modified this bit here for more compilation flags ...
+if ( test -n "$5" ) then
+ ./ansi2knr $5 _temp_$$.c
+ $1 $2 $3 $4 _temp_$$.c
+ if ( test "$2" != "-o" ) then
+ rm -f `basename $5 .c` .o
+ mv _temp_$$.o `basename $5 .c`.o
+ fi
+else
+if ( test -n "$4" ) then
+ ./ansi2knr $4 _temp_$$.c
+ $1 $2 $3 _temp_$$.c
+ if ( test "$2" != "-o" ) then
+ rm -f `basename $4 .c`.o
+ mv _temp_$$.o `basename $4 .c`.o
+ fi
+else
+if ( test -n "$3" ) then
+ ./ansi2knr $3 _temp_$$.c
+ $1 $2 _temp_$$.c
+ rm -f `basename $3 .c`.o
+ mv _temp_$$.o `basename $3 .c`.o
+else
+ ./ansi2knr $2 _temp_$$.c
+ $1 _temp_$$.c
+ rm -f `basename $2 .c`.o
+ mv _temp_$$.o `basename $2 .c`.o
+fi
+fi
+fi
+fi
+rm -f _temp_$$.c
diff --git a/gs/src/cfonts.mak b/gs/src/cfonts.mak
new file mode 100644
index 000000000..777783dde
--- /dev/null
+++ b/gs/src/cfonts.mak
@@ -0,0 +1,442 @@
+# Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile for compiling PostScript Type 1 fonts into C.
+# For more information about fonts, consult the Fontmap file,
+# and also fonts.txt.
+
+# Edit the following 2 lines to reflect your environment.
+OBJ=o
+CCCF=gcc -c -O
+
+CFONTS=.
+FONT2C=font2c
+
+# ---------------------------------------------------------------- #
+
+# This file supports two slightly different font sets:
+# the de facto commercial standard set of 35 PostScript fonts, and a slightly
+# larger set distributed with the free version of the software.
+
+fonts_standard_o: \
+ AvantGarde_o Bookman_o Courier_o \
+ Helvetica_o NewCenturySchlbk_o Palatino_o \
+ TimesRoman_o Symbol_o ZapfChancery_o ZapfDingbats_o
+
+fonts_standard_c: \
+ AvantGarde_c Bookman_c Courier_c \
+ Helvetica_c NewCenturySchlbk_c Palatino_c \
+ TimesRoman_c Symbol_c ZapfChancery_c ZapfDingbats_c
+
+fonts_free_o: fonts_standard_o \
+ CharterBT_o Cyrillic_o Kana_o Utopia_o
+
+fonts_free_c: fonts_standard_c \
+ CharterBT_c Cyrillic_c Kana_c Utopia_c
+
+# ---------------------------------------------------------------- #
+# #
+# Standard 35 fonts #
+# #
+# ---------------------------------------------------------------- #
+
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+
+# ---------------- Avant Garde ----------------
+
+AvantGarde_c: $(CFONTS)/0agk.c $(CFONTS)/0agko.c $(CFONTS)/0agd.c \
+ $(CFONTS)/0agdo.c
+
+$(CFONTS)/0agk.c:
+ $(FONT2C) AvantGarde-Book $(CFONTS)/0agk.c agk
+
+$(CFONTS)/0agko.c:
+ $(FONT2C) AvantGarde-BookOblique $(CFONTS)/0agko.c agko
+
+$(CFONTS)/0agd.c:
+ $(FONT2C) AvantGarde-Demi $(CFONTS)/0agd.c agd
+
+$(CFONTS)/0agdo.c:
+ $(FONT2C) AvantGarde-DemiOblique $(CFONTS)/0agdo.c agdo
+
+AvantGarde_o: 0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+
+0agk.$(OBJ): $(CFONTS)/0agk.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0agk.c
+
+0agko.$(OBJ): $(CFONTS)/0agko.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0agko.c
+
+0agd.$(OBJ): $(CFONTS)/0agd.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0agd.c
+
+0agdo.$(OBJ): $(CFONTS)/0agdo.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0agdo.c
+
+# ---------------- Bookman ----------------
+
+Bookman_c: $(CFONTS)/0bkl.c $(CFONTS)/0bkli.c $(CFONTS)/0bkd.c \
+ $(CFONTS)/0bkdi.c
+
+$(CFONTS)/0bkl.c:
+ $(FONT2C) Bookman-Light $(CFONTS)/0bkl.c bkl
+
+$(CFONTS)/0bkli.c:
+ $(FONT2C) Bookman-LightItalic $(CFONTS)/0bkli.c bkli
+
+$(CFONTS)/0bkd.c:
+ $(FONT2C) Bookman-Demi $(CFONTS)/0bkd.c bkd
+
+$(CFONTS)/0bkdi.c:
+ $(FONT2C) Bookman-DemiItalic $(CFONTS)/0bkdi.c bkdi
+
+Bookman_o: 0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+
+0bkl.$(OBJ): $(CFONTS)/0bkl.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0bkl.c
+
+0bkli.$(OBJ): $(CFONTS)/0bkli.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0bkli.c
+
+0bkd.$(OBJ): $(CFONTS)/0bkd.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0bkd.c
+
+0bkdi.$(OBJ): $(CFONTS)/0bkdi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0bkdi.c
+
+# ---------------- Courier ----------------
+
+Courier_c: $(CFONTS)/0crr.c $(CFONTS)/0cri.c $(CFONTS)/0crb.c \
+ $(CFONTS)/0crbi.c
+
+$(CFONTS)/0crr.c:
+ $(FONT2C) Courier $(CFONTS)/0crr.c crr
+
+$(CFONTS)/0cri.c:
+ $(FONT2C) Courier-Italic $(CFONTS)/0cri.c cri
+
+$(CFONTS)/0crb.c:
+ $(FONT2C) Courier-Bold $(CFONTS)/0crb.c crb
+
+$(CFONTS)/0crbi.c:
+ $(FONT2C) Courier-BoldItalic $(CFONTS)/0crbi.c crbi
+
+Courier_o: 0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+
+0crr.$(OBJ): $(CFONTS)/0crr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0crr.c
+
+0cri.$(OBJ): $(CFONTS)/0cri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0cri.c
+
+0crb.$(OBJ): $(CFONTS)/0crb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0crb.c
+
+0crbi.$(OBJ): $(CFONTS)/0crbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0crbi.c
+
+# ---------------- Helvetica ----------------
+
+Helvetica_c: $(CFONTS)/0hvr.c $(CFONTS)/0hvro.c \
+ $(CFONTS)/0hvb.c $(CFONTS)/0hvbo.c $(CFONTS)/0hvrrn.c \
+ $(CFONTS)/0hvrorn.c $(CFONTS)/0hvbrn.c $(CFONTS)/0hvborn.c
+
+$(CFONTS)/0hvr.c:
+ $(FONT2C) Helvetica $(CFONTS)/0hvr.c hvr
+
+$(CFONTS)/0hvro.c:
+ $(FONT2C) Helvetica-Oblique $(CFONTS)/0hvro.c hvro
+
+$(CFONTS)/0hvb.c:
+ $(FONT2C) Helvetica-Bold $(CFONTS)/0hvb.c hvb
+
+$(CFONTS)/0hvbo.c:
+ $(FONT2C) Helvetica-BoldOblique $(CFONTS)/0hvbo.c hvbo
+
+$(CFONTS)/0hvrrn.c:
+ $(FONT2C) Helvetica-Narrow $(CFONTS)/0hvrrn.c hvrrn
+
+$(CFONTS)/0hvrorn.c:
+ $(FONT2C) Helvetica-Narrow-Oblique $(CFONTS)/0hvrorn.c hvrorn
+
+$(CFONTS)/0hvbrn.c:
+ $(FONT2C) Helvetica-Narrow-Bold $(CFONTS)/0hvbrn.c hvbrn
+
+$(CFONTS)/0hvborn.c:
+ $(FONT2C) Helvetica-Narrow-BoldOblique $(CFONTS)/0hvborn.c hvborn
+
+Helvetica_o: 0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ) \
+ 0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+
+0hvr.$(OBJ): $(CFONTS)/0hvr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvr.c
+
+0hvro.$(OBJ): $(CFONTS)/0hvro.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvro.c
+
+0hvb.$(OBJ): $(CFONTS)/0hvb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvb.c
+
+0hvbo.$(OBJ): $(CFONTS)/0hvbo.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvbo.c
+
+0hvrrn.$(OBJ): $(CFONTS)/0hvrrn.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvrrn.c
+
+0hvrorn.$(OBJ): $(CFONTS)/0hvrorn.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvrorn.c
+
+0hvbrn.$(OBJ): $(CFONTS)/0hvbrn.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvbrn.c
+
+0hvborn.$(OBJ): $(CFONTS)/0hvborn.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0hvborn.c
+
+# ---------------- New Century Schoolbook ----------------
+
+NewCenturySchlbk_c: $(CFONTS)/0ncr.c $(CFONTS)/0ncri.c $(CFONTS)/0ncb.c \
+ $(CFONTS)/0ncbi.c
+
+$(CFONTS)/0ncr.c:
+ $(FONT2C) NewCenturySchlbk-Roman $(CFONTS)/0ncr.c ncr
+
+$(CFONTS)/0ncri.c:
+ $(FONT2C) NewCenturySchlbk-Italic $(CFONTS)/0ncri.c ncri
+
+$(CFONTS)/0ncb.c:
+ $(FONT2C) NewCenturySchlbk-Bold $(CFONTS)/0ncb.c ncb
+
+$(CFONTS)/0ncbi.c:
+ $(FONT2C) NewCenturySchlbk-BoldItalic $(CFONTS)/0ncbi.c ncbi
+
+NewCenturySchlbk_o: 0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+
+0ncr.$(OBJ): $(CFONTS)/0ncr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0ncr.c
+
+0ncri.$(OBJ): $(CFONTS)/0ncri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0ncri.c
+
+0ncb.$(OBJ): $(CFONTS)/0ncb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0ncb.c
+
+0ncbi.$(OBJ): $(CFONTS)/0ncbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0ncbi.c
+
+# ---------------- Palatino ----------------
+
+Palatino_c: $(CFONTS)/0plr.c $(CFONTS)/0plri.c $(CFONTS)/0plb.c \
+ $(CFONTS)/0plbi.c
+
+$(CFONTS)/0plr.c:
+ $(FONT2C) Palatino-Roman $(CFONTS)/0plr.c plr
+
+$(CFONTS)/0plri.c:
+ $(FONT2C) Palatino-Italic $(CFONTS)/0plri.c plri
+
+$(CFONTS)/0plb.c:
+ $(FONT2C) Palatino-Bold $(CFONTS)/0plb.c plb
+
+$(CFONTS)/0plbi.c:
+ $(FONT2C) Palatino-BoldItalic $(CFONTS)/0plbi.c plbi
+
+Palatino_o: 0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+
+0plr.$(OBJ): $(CFONTS)/0plr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0plr.c
+
+0plri.$(OBJ): $(CFONTS)/0plri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0plri.c
+
+0plb.$(OBJ): $(CFONTS)/0plb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0plb.c
+
+0plbi.$(OBJ): $(CFONTS)/0plbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0plbi.c
+
+# ---------------- Times Roman ----------------
+
+TimesRoman_c: $(CFONTS)/0tmr.c $(CFONTS)/0tmri.c $(CFONTS)/0tmb.c \
+ $(CFONTS)/0tmbi.c
+
+$(CFONTS)/0tmr.c:
+ $(FONT2C) Times-Roman $(CFONTS)/0tmr.c tmr
+
+$(CFONTS)/0tmri.c:
+ $(FONT2C) Times-Italic $(CFONTS)/0tmri.c tmri
+
+$(CFONTS)/0tmb.c:
+ $(FONT2C) Times-Bold $(CFONTS)/0tmb.c tmb
+
+$(CFONTS)/0tmbi.c:
+ $(FONT2C) Times-BoldItalic $(CFONTS)/0tmbi.c tmbi
+
+TimesRoman_o: 0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+
+0tmr.$(OBJ): $(CFONTS)/0tmr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0tmr.c
+
+0tmri.$(OBJ): $(CFONTS)/0tmri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0tmri.c
+
+0tmb.$(OBJ): $(CFONTS)/0tmb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0tmb.c
+
+0tmbi.$(OBJ): $(CFONTS)/0tmbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0tmbi.c
+
+# ---------------- Symbol ----------------
+
+Symbol_c: $(CFONTS)/0syr.c
+
+$(CFONTS)/0syr.c:
+ $(FONT2C) Symbol $(CFONTS)/0syr.c syr
+
+Symbol_o: 0syr.$(OBJ)
+
+0syr.$(OBJ): $(CFONTS)/0syr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0syr.c
+
+# ---------------- Zapf Chancery ----------------
+
+ZapfChancery_c: $(CFONTS)/0zcmi.c
+
+$(CFONTS)/0zcmi.c:
+ $(FONT2C) ZapfChancery-MediumItalic $(CFONTS)/0zcmi.c zcmi
+
+ZapfChancery_o: 0zcmi.$(OBJ)
+
+0zcmi.$(OBJ): $(CFONTS)/0zcmi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0zcmi.c
+
+# ---------------- Zapf Dingbats ----------------
+
+ZapfDingbats_c: $(CFONTS)/0zdr.c
+
+$(CFONTS)/0zdr.c:
+ $(FONT2C) ZapfDingbats $(CFONTS)/0zdr.c zdr
+
+ZapfDingbats_o: 0zdr.$(OBJ)
+
+0zdr.$(OBJ): $(CFONTS)/0zdr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/0zdr.c
+
+# ---------------------------------------------------------------- #
+# #
+# Additional fonts #
+# #
+# ---------------------------------------------------------------- #
+
+# ---------------- Bitstream Charter ----------------
+
+CharterBT_c: $(CFONTS)/bchr.c $(CFONTS)/bchri.c $(CFONTS)/bchb.c \
+ $(CFONTS)/bchbi.c
+
+$(CFONTS)/bchr.c:
+ $(FONT2C) Charter-Roman $(CFONTS)/bchr.c chr
+
+$(CFONTS)/bchri.c:
+ $(FONT2C) Charter-Italic $(CFONTS)/bchri.c chri
+
+$(CFONTS)/bchb.c:
+ $(FONT2C) Charter-Bold $(CFONTS)/bchb.c chb
+
+$(CFONTS)/bchbi.c:
+ $(FONT2C) Charter-BoldItalic $(CFONTS)/bchbi.c chbi
+
+CharterBT_o: bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+
+bchr.$(OBJ): $(CFONTS)/bchr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/bchr.c
+
+bchri.$(OBJ): $(CFONTS)/bchri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/bchri.c
+
+bchb.$(OBJ): $(CFONTS)/bchb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/bchb.c
+
+bchbi.$(OBJ): $(CFONTS)/bchbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/bchbi.c
+
+# ---------------- Cyrillic ----------------
+
+Cyrillic_c: $(CFONTS)/fcyr.c $(CFONTS)/fcyri.c
+
+$(CFONTS)/fcyr.c:
+ $(FONT2C) Cyrillic $(CFONTS)/fcyr.c fcyr
+
+$(CFONTS)/fcyri.c:
+ $(FONT2C) Cyrillic-Italic $(CFONTS)/fcyri.c fcyri
+
+Cyrillic_o: fcyr.$(OBJ) fcyri.$(OBJ)
+
+fcyr.$(OBJ): $(CFONTS)/fcyr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/fcyr.c
+
+fcyri.$(OBJ): $(CFONTS)/fcyri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/fcyri.c
+
+# ---------------- Kana ----------------
+
+Kana_c: $(CFONTS)/fhirw.c $(CFONTS)/fkarw.c
+
+$(CFONTS)/fhirw.c:
+ $(FONT2C) Calligraphic-Hiragana $(CFONTS)/fhirw.c fhirw
+
+$(CFONTS)/fkarw.c:
+ $(FONT2C) Calligraphic-Katakana $(CFONTS)/fkarw.c fkarw
+
+Kana_o: fhirw.$(OBJ) fkarw.$(OBJ)
+
+fhirw.$(OBJ): $(CFONTS)/fhirw.c $(CCFONT)
+ $(CCCF) $(CFONTS)/fhirw.c
+
+fkarw.$(OBJ): $(CFONTS)/fkarw.c $(CCFONT)
+ $(CCCF) $(CFONTS)/fkarw.c
+
+# ---------------- Utopia ----------------
+
+Utopia_c: $(CFONTS)/putr.c $(CFONTS)/putri.c $(CFONTS)/putb.c \
+ $(CFONTS)/putbi.c
+
+$(CFONTS)/putr.c:
+ $(FONT2C) Utopia-Regular $(CFONTS)/putr.c utr
+
+$(CFONTS)/putri.c:
+ $(FONT2C) Utopia-Italic $(CFONTS)/putri.c utri
+
+$(CFONTS)/putb.c:
+ $(FONT2C) Utopia-Bold $(CFONTS)/putb.c utb
+
+$(CFONTS)/putbi.c:
+ $(FONT2C) Utopia-BoldItalic $(CFONTS)/putbi.c utbi
+
+Utopia_o: putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+
+putr.$(OBJ): $(CFONTS)/putr.c $(CCFONT)
+ $(CCCF) $(CFONTS)/putr.c
+
+putri.$(OBJ): $(CFONTS)/putri.c $(CCFONT)
+ $(CCCF) $(CFONTS)/putri.c
+
+putb.$(OBJ): $(CFONTS)/putb.c $(CCFONT)
+ $(CCCF) $(CFONTS)/putb.c
+
+putbi.$(OBJ): $(CFONTS)/putbi.c $(CCFONT)
+ $(CCCF) $(CFONTS)/putbi.c
diff --git a/gs/src/copy_one.com b/gs/src/copy_one.com
new file mode 100644
index 000000000..64c8d8f79
--- /dev/null
+++ b/gs/src/copy_one.com
@@ -0,0 +1,14 @@
+$ Verif = F$Verify(0)
+$ ! OpenVMS command file to emulate behavior of:
+$ !
+$ ! Define the command for copying one file to another
+$ !
+$ COPY="COPY/LOG"
+$ FILE = F$SEARCH(P1)
+$ IF P2 .EQS. "." THEN P2 = "[]"
+$ IF FILE .NES. ""
+$ THEN
+$ FFILE = F$ELEMENT(0, ";", FILE)
+$ COPY 'FFILE' 'P2'
+$ ENDIF
+$ xxx = F$Verify(Verif)
diff --git a/gs/src/cp.cmd b/gs/src/cp.cmd
new file mode 100755
index 000000000..e6ad951c7
--- /dev/null
+++ b/gs/src/cp.cmd
@@ -0,0 +1,2 @@
+@copy /B %1 %2
+@if not "%2"=="." touch %2
diff --git a/gs/src/ctype_.h b/gs/src/ctype_.h
new file mode 100644
index 000000000..88034b94b
--- /dev/null
+++ b/gs/src/ctype_.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ctype_.h */
+/* Wrapper for ctype.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/* ... and that's the only reason for having this file at all. */
+#include <ctype.h>
diff --git a/gs/src/devs.mak b/gs/src/devs.mak
new file mode 100644
index 000000000..ff10b8d05
--- /dev/null
+++ b/gs/src/devs.mak
@@ -0,0 +1,1626 @@
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for device drivers.
+
+# Define the name of this makefile.
+DEVS_MAK=devs.mak
+
+###### --------------------------- Catalog -------------------------- ######
+
+# It is possible to build configurations with an arbitrary collection of
+# device drivers, although some drivers are supported only on a subset
+# of the target platforms. The currently available drivers are:
+
+# MS-DOS displays (note: not usable with Desqview/X):
+# MS-DOS EGA and VGA:
+# ega EGA (640x350, 16-color)
+# vga VGA (640x480, 16-color)
+# MS-DOS SuperVGA:
+# * ali SuperVGA using Avance Logic Inc. chipset, 256-color modes
+# * atiw ATI Wonder SuperVGA, 256-color modes
+# * s3vga SuperVGA using S3 86C911 chip (e.g., Diamond Stealth board)
+# svga16 Generic SuperVGA in 800x600, 16-color mode
+# * tseng SuperVGA using Tseng Labs ET3000/4000 chips, 256-color modes
+# * tvga SuperVGA using Trident chipset, 256-color modes
+# ****** NOTE: The vesa device does not work with the Watcom (32-bit MS-DOS)
+# ****** compiler or executable.
+# vesa SuperVGA with VESA standard API driver
+# MS-DOS other:
+# bgi Borland Graphics Interface (CGA) [MS-DOS only]
+# * herc Hercules Graphics display [MS-DOS only]
+# * pe Private Eye display
+# Other displays:
+# MS Windows:
+# mswindll Microsoft Windows 3.1 DLL [MS Windows only]
+# mswinprn Microsoft Windows 3.0, 3.1 DDB printer [MS Windows only]
+# mswinpr2 Microsoft Windows 3.0, 3.1 DIB printer [MS Windows only]
+# OS/2:
+# * os2pm OS/2 Presentation Manager [OS/2 only]
+# * os2dll OS/2 DLL bitmap [OS/2 only]
+# * os2prn OS/2 printer [OS/2 only]
+# Unix and VMS:
+# ****** NOTE: For direct frame buffer addressing under SCO Unix or Xenix,
+# ****** edit the definition of EGAVGA below.
+# * att3b1 AT&T 3b1/Unixpc monochrome display [3b1 only]
+# * lvga256 Linux vgalib, 256-color VGA modes [Linux only]
+# * sonyfb Sony Microsystems monochrome display [Sony only]
+# * sunview SunView window system [SunOS only]
+# + vgalib Linux PC with VGALIB [Linux only]
+# x11 X Windows version 11, release >=4 [Unix and VMS only]
+# x11alpha X Windows masquerading as a device with alpha capability
+# x11cmyk X Windows masquerading as a 1-bit-per-plane CMYK device
+# x11gray2 X Windows as a 2-bit gray-scale device
+# x11mono X Windows masquerading as a black-and-white device
+# Platform-independent:
+# * sxlcrt CRT sixels, e.g. for VT240-like terminals
+# Printers:
+# * ap3250 Epson AP3250 printer
+# * appledmp Apple Dot Matrix Printer (should also work with Imagewriter)
+# bj10e Canon BubbleJet BJ10e
+# * bj200 Canon BubbleJet BJ200
+# * bjc600 Canon Color BubbleJet BJC-600, BJC-4000 and BJC-70
+# also good for Apple printers like the StyleWriter 2x00
+# * bjc800 Canon Color BubbleJet BJC-800
+# * ccr CalComp Raster format
+# * cdeskjet H-P DeskJet 500C with 1 bit/pixel color
+# * cdjcolor H-P DeskJet 500C with 24 bit/pixel color and
+# high-quality color (Floyd-Steinberg) dithering;
+# also good for DeskJet 540C and Citizen Projet IIc (-r200x300)
+# * cdjmono H-P DeskJet 500C printing black only;
+# also good for DeskJet 510, 520, and 540C (black only)
+# * cdj500 H-P DeskJet 500C (same as cdjcolor)
+# * cdj550 H-P DeskJet 550C/560C/660C/660Cse
+# * cp50 Mitsubishi CP50 color printer
+# * declj250 alternate DEC LJ250 driver
+# + deskjet H-P DeskJet and DeskJet Plus
+# djet500 H-P DeskJet 500; use -r600 for DJ 600 series
+# * djet500c H-P DeskJet 500C alternate driver
+# (does not work on 550C or 560C)
+# * dnj650c H-P DesignJet 650C
+# epson Epson-compatible dot matrix printers (9- or 24-pin)
+# * eps9mid Epson-compatible 9-pin, interleaved lines
+# (intermediate resolution)
+# * eps9high Epson-compatible 9-pin, interleaved lines
+# (triple resolution)
+# * epsonc Epson LQ-2550 and Fujitsu 3400/2400/1200 color printers
+# * ibmpro IBM 9-pin Proprinter
+# * imagen Imagen ImPress printers
+# * iwhi Apple Imagewriter in high-resolution mode
+# * iwlo Apple Imagewriter in low-resolution mode
+# * iwlq Apple Imagewriter LQ in 320 x 216 dpi mode
+# * jetp3852 IBM Jetprinter ink-jet color printer (Model #3852)
+# + laserjet H-P LaserJet
+# * la50 DEC LA50 printer
+# * la70 DEC LA70 printer
+# * la70t DEC LA70 printer with low-resolution text enhancement
+# * la75 DEC LA75 printer
+# * la75plus DEC LA75plus printer
+# * lbp8 Canon LBP-8II laser printer
+# * lips3 Canon LIPS III laser printer in English (CaPSL) mode
+# * ln03 DEC LN03 printer
+# * lj250 DEC LJ250 Companion color printer
+# + ljet2p H-P LaserJet IId/IIp/III* with TIFF compression
+# + ljet3 H-P LaserJet III* with Delta Row compression
+# + ljet3d H-P LaserJet IIID with duplex capability
+# + ljet4 H-P LaserJet 4 (defaults to 600 dpi)
+# + lj4dith H-P LaserJet 4 with Floyd-Steinberg dithering
+# + ljetplus H-P LaserJet Plus
+# lj5mono H-P LaserJet 5 & 6 family (PCL XL), bitmap:
+# see below for restrictions & advice
+# lj5gray H-P LaserJet 5 & 6 family, gray-scale bitmap;
+# see below for restrictions & advice
+# * lp2563 H-P 2563B line printer
+# * lp8000 Epson LP-8000 laser printer
+# * lq850 Epson LQ850 printer at 360 x 360 DPI resolution;
+# also good for Canon BJ300 with LQ850 emulation
+# * m8510 C.Itoh M8510 printer
+# * necp6 NEC P6/P6+/P60 printers at 360 x 360 DPI resolution
+# * nwp533 Sony Microsystems NWP533 laser printer [Sony only]
+# * oce9050 OCE 9050 printer
+# * oki182 Okidata MicroLine 182
+# * okiibm Okidata MicroLine IBM-compatible printers
+# * paintjet alternate H-P PaintJet color printer
+# * pj H-P PaintJet XL driver
+# * pjetxl alternate H-P PaintJet XL driver
+# * pjxl H-P PaintJet XL color printer
+# * pjxl300 H-P PaintJet XL300 color printer;
+# also good for PaintJet 1200C
+# (pxlmono) H-P black-and-white PCL XL printers (LaserJet 5 and 6 family)
+# (pxlcolor) H-P color PCL XL printers (none available yet)
+# * r4081 Ricoh 4081 laser printer
+# * sj48 StarJet 48 inkjet printer
+# * sparc SPARCprinter
+# * st800 Epson Stylus 800 printer
+# * stcolor Epson Stylus Color
+# * t4693d2 Tektronix 4693d color printer, 2 bits per R/G/B component
+# * t4693d4 Tektronix 4693d color printer, 4 bits per R/G/B component
+# * t4693d8 Tektronix 4693d color printer, 8 bits per R/G/B component
+# * tek4696 Tektronix 4695/4696 inkjet plotter
+# * uniprint Unified printer driver -- Configurable Color ESC/P-,
+# ESC/P2-, HP-RTL/PCL mono/color driver
+# * xes Xerox XES printers (2700, 3700, 4045, etc.)
+# Fax systems:
+# * dfaxhigh DigiBoard, Inc.'s DigiFAX software format (high resolution)
+# * dfaxlow DigiFAX low (normal) resolution
+# Fax file format:
+# ****** NOTE: all of these drivers adjust the page size to match
+# ****** one of the three CCITT standard sizes (U.S. letter with A4 width,
+# ****** A4, or B4).
+# faxg3 Group 3 fax, with EOLs but no header or EOD
+# faxg32d Group 3 2-D fax, with EOLs but no header or EOD
+# faxg4 Group 4 fax, with EOLs but no header or EOD
+# tiffcrle TIFF "CCITT RLE 1-dim" (= Group 3 fax with no EOLs)
+# tiffg3 TIFF Group 3 fax (with EOLs)
+# tiffg32d TIFF Group 3 2-D fax
+# tiffg4 TIFF Group 4 fax
+# High-level file formats:
+# epswrite EPS output (like PostScript Distillery)
+# pdfwrite PDF output (like Adobe Acrobat Distiller)
+# pswrite PostScript output (like PostScript Distillery)
+# pxlmono Black-and-white PCL XL
+# pxlcolor Color PCL XL
+# Other raster file formats and devices:
+# bit Plain bits, monochrome
+# bitrgb Plain bits, RGB
+# bitcmyk Plain bits, CMYK
+# bmpmono Monochrome MS Windows .BMP file format
+# bmp16 4-bit (EGA/VGA) .BMP file format
+# bmp256 8-bit (256-color) .BMP file format
+# bmp16m 24-bit .BMP file format
+# cgmmono Monochrome (black-and-white) CGM -- LOW LEVEL OUTPUT ONLY
+# cgm8 8-bit (256-color) CGM -- DITTO
+# cgm24 24-bit color CGM -- DITTO
+# * cif CIF file format for VLSI
+# jpeg JPEG format, RGB output
+# jpeggray JPEG format, gray output
+# miff24 ImageMagick MIFF format, 24-bit direct color, RLE compressed
+# * mgrmono 1-bit monochrome MGR devices
+# * mgrgray2 2-bit gray scale MGR devices
+# * mgrgray4 4-bit gray scale MGR devices
+# * mgrgray8 8-bit gray scale MGR devices
+# * mgr4 4-bit (VGA) color MGR devices
+# * mgr8 8-bit color MGR devices
+# pcxmono PCX file format, monochrome (1-bit black and white)
+# pcxgray PCX file format, 8-bit gray scale
+# pcx16 PCX file format, 4-bit planar (EGA/VGA) color
+# pcx256 PCX file format, 8-bit chunky color
+# pcx24b PCX file format, 24-bit color (3 8-bit planes)
+# pcxcmyk PCX file format, 4-bit chunky CMYK color
+# pbm Portable Bitmap (plain format)
+# pbmraw Portable Bitmap (raw format)
+# pgm Portable Graymap (plain format)
+# pgmraw Portable Graymap (raw format)
+# pgnm Portable Graymap (plain format), optimizing to PBM if possible
+# pgnmraw Portable Graymap (raw format), optimizing to PBM if possible
+# pnm Portable Pixmap (plain format) (RGB), optimizing to PGM or PBM
+# if possible
+# pnmraw Portable Pixmap (raw format) (RGB), optimizing to PGM or PBM
+# if possible
+# ppm Portable Pixmap (plain format) (RGB)
+# ppmraw Portable Pixmap (raw format) (RGB)
+# pkm Portable inKmap (plain format) (4-bit CMYK => RGB)
+# pkmraw Portable inKmap (raw format) (4-bit CMYK => RGB)
+# pngmono Monochrome Portable Network Graphics (PNG)
+# pnggray 8-bit gray Portable Network Graphics (PNG)
+# png16 4-bit color Portable Network Graphics (PNG)
+# png256 8-bit color Portable Network Graphics (PNG)
+# png16m 24-bit color Portable Network Graphics (PNG)
+# psmono PostScript (Level 1) monochrome image
+# psgray PostScript (Level 1) 8-bit gray image
+# sgirgb SGI RGB pixmap format
+# tiff12nc TIFF 12-bit RGB, no compression
+# tiff24nc TIFF 24-bit RGB, no compression (NeXT standard format)
+# tifflzw TIFF LZW (tag = 5) (monochrome)
+# tiffpack TIFF PackBits (tag = 32773) (monochrome)
+
+# User-contributed drivers marked with * require hardware or software
+# that is not available to Aladdin Enterprises. Please contact the
+# original contributors, not Aladdin Enterprises, if you have questions.
+# Contact information appears in the driver entry below.
+#
+# Drivers marked with a + are maintained by Aladdin Enterprises with
+# the assistance of users, since Aladdin Enterprises doesn't have access to
+# the hardware for these either.
+
+# If you add drivers, it would be nice if you kept each list
+# in alphabetical order.
+
+###### ----------------------- End of catalog ----------------------- ######
+
+# As noted in gs.mak, DEVICE_DEVS and DEVICE_DEVS1..15 select the devices
+# that should be included in a given configuration. By convention, these
+# are used as follows. Each of these must be limited to about 10 devices
+# so as not to overflow the 120 character limit on MS-DOS command lines.
+# DEVICE_DEVS - the default device, and any display devices.
+# DEVICE_DEVS1 - additional display devices if needed.
+# DEVICE_DEVS2 - dot matrix printers.
+# DEVICE_DEVS3 - H-P monochrome printers.
+# DEVICE_DEVS4 - H-P color printers.
+# DEVICE_DEVS5 - additional H-P printers if needed.
+# DEVICE_DEVS6 - other ink-jet and laser printers.
+# DEVICE_DEVS7 - fax file formats.
+# DEVICE_DEVS8 - PCX file formats.
+# DEVICE_DEVS9 - PBM/PGM/PPM file formats.
+# DEVICE_DEVS10 - black-and-white TIFF file formats.
+# DEVICE_DEVS11 - BMP and color TIFF file formats.
+# DEVICE_DEVS12 - PostScript image and 'bit' file formats.
+# DEVICE_DEVS13 - PNG file formats.
+# DEVICE_DEVS14 - CGM, JPEG, and MIFF file formats.
+# DEVICE_DEVS15 - high-level (PostScript and PDF) file formats.
+# Feel free to disregard this convention if it gets in your way.
+
+# If you want to add a new device driver, the examples below should be
+# enough of a guide to the correct form for the makefile rules.
+# Note that all drivers other than displays must include page.dev in their
+# dependencies and use $(SETPDEV) rather than $(SETDEV) in their rule bodies.
+
+# All device drivers depend on the following:
+GDEV=$(AK) $(ECHOGS_XE) $(gserrors_h) $(gx_h) $(gxdevice_h)
+
+# "Printer" drivers depend on the following:
+PDEVH=$(AK) $(gdevprn_h)
+
+# Define the header files for device drivers. Every header file used by
+# more than one device driver family must be listed here.
+gdev8bcm_h=gdev8bcm.h
+gdevpccm_h=gdevpccm.h
+gdevpcfb_h=gdevpcfb.h $(dos__h)
+gdevpcl_h=gdevpcl.h
+gdevsvga_h=gdevsvga.h
+gdevx_h=gdevx.h
+
+###### ----------------------- Device support ----------------------- ######
+
+# Provide a mapping between StandardEncoding and ISOLatin1Encoding.
+gdevemap.$(OBJ): gdevemap.c $(AK) $(std_h)
+
+# Implement dynamic color management for 8-bit mapped color displays.
+gdev8bcm.$(OBJ): gdev8bcm.c $(AK) \
+ $(gx_h) $(gxdevice_h) $(gdev8bcm_h)
+
+###### ------------------- MS-DOS display devices ------------------- ######
+
+# There are really only three drivers: an EGA/VGA driver (4 bit-planes,
+# plane-addressed), a SuperVGA driver (8 bit-planes, byte addressed),
+# and a special driver for the S3 chip.
+
+# PC display color mapping
+gdevpccm.$(OBJ): gdevpccm.c $(AK) \
+ $(gx_h) $(gsmatrix_h) $(gxdevice_h) $(gdevpccm_h)
+
+### ----------------------- EGA and VGA displays ----------------------- ###
+
+# The shared MS-DOS makefile defines PCFBASM as either gdevegaa.$(OBJ)
+# or an empty string.
+
+gdevegaa.$(OBJ): gdevegaa.asm
+
+# NOTE: for direct frame buffer addressing under SCO Unix or Xenix,
+# change gdevevga to gdevsco in the following line. Also, since
+# SCO's /bin/as does not support the "out" instructions, you must build
+# the gnu assembler and have it on your path as "as".
+EGAVGA=gdevevga.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+#EGAVGA=gdevsco.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevevga.$(OBJ): gdevevga.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+ $(CCD) gdevevga.c
+
+gdevsco.$(OBJ): gdevsco.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+
+# Common code for MS-DOS and SCO.
+gdevpcfb.$(OBJ): gdevpcfb.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gdevpccm_h) $(gdevpcfb_h) $(gsparam_h)
+ $(CCD) gdevpcfb.c
+
+# The EGA/VGA family includes EGA and VGA. Many SuperVGAs in 800x600,
+# 16-color mode can share the same code; see the next section below.
+
+ega.dev: $(EGAVGA)
+ $(SETDEV) ega $(EGAVGA)
+
+vga.dev: $(EGAVGA)
+ $(SETDEV) vga $(EGAVGA)
+
+### ------------------------- SuperVGA displays ------------------------ ###
+
+# SuperVGA displays in 16-color, 800x600 mode are really just slightly
+# glorified VGA's, so we can handle them all with a single driver.
+# The way to select them on the command line is with
+# -sDEVICE=svga16 -dDisplayMode=NNN
+# where NNN is the display mode in decimal. See use.txt for the modes
+# for some popular display chipsets.
+
+svga16.dev: $(EGAVGA)
+ $(SETDEV) svga16 $(EGAVGA)
+
+# More capable SuperVGAs have a wide variety of slightly differing
+# interfaces, so we need a separate driver for each one.
+
+SVGA=gdevsvga.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevsvga.$(OBJ): gdevsvga.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gsparam_h) $(gxarith_h) $(gdevpccm_h) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevsvga.c
+
+# The SuperVGA family includes: Avance Logic Inc., ATI Wonder, S3,
+# Trident, Tseng ET3000/4000, and VESA.
+
+ali.dev: $(SVGA)
+ $(SETDEV) ali $(SVGA)
+
+atiw.dev: $(SVGA)
+ $(SETDEV) atiw $(SVGA)
+
+tseng.dev: $(SVGA)
+ $(SETDEV) tseng $(SVGA)
+
+tvga.dev: $(SVGA)
+ $(SETDEV) tvga $(SVGA)
+
+vesa.dev: $(SVGA)
+ $(SETDEV) vesa $(SVGA)
+
+# The S3 driver doesn't share much code with the others.
+
+s3vga_=gdevs3ga.$(OBJ) gdevsvga.$(OBJ) gdevpccm.$(OBJ)
+s3vga.dev: $(SVGA) $(s3vga_)
+ $(SETDEV) s3vga $(SVGA)
+ $(ADDMOD) s3vga -obj $(s3vga_)
+
+gdevs3ga.$(OBJ): gdevs3ga.c $(GDEV) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevs3ga.c
+
+### ------------ The BGI (Borland Graphics Interface) device ----------- ###
+
+cgaf.$(OBJ): $(BGIDIR)\cga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\cga
+
+egavgaf.$(OBJ): $(BGIDIR)\egavga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\egavga
+
+# Include egavgaf.$(OBJ) for debugging only.
+bgi_=gdevbgi.$(OBJ) cgaf.$(OBJ)
+bgi.dev: $(bgi_)
+ $(SETDEV) bgi $(bgi_)
+ $(ADDMOD) bgi -lib $(LIBDIR)\graphics
+
+gdevbgi.$(OBJ): gdevbgi.c $(GDEV) $(MAKEFILE) $(gxxfont_h)
+ $(CCC) -DBGI_LIB="$(BGIDIRSTR)" gdevbgi.c
+
+### ------------------- The Hercules Graphics display ------------------- ###
+
+herc_=gdevherc.$(OBJ)
+herc.dev: $(herc_)
+ $(SETDEV) herc $(herc_)
+
+gdevherc.$(OBJ): gdevherc.c $(GDEV) $(dos__h) $(gsmatrix_h) $(gxbitmap_h)
+ $(CCC) gdevherc.c
+
+### ---------------------- The Private Eye display ---------------------- ###
+### Note: this driver was contributed by a user: ###
+### please contact narf@media-lab.media.mit.edu if you have questions. ###
+
+pe_=gdevpe.$(OBJ)
+pe.dev: $(pe_)
+ $(SETDEV) pe $(pe_)
+
+gdevpe.$(OBJ): gdevpe.c $(GDEV) $(memory__h)
+
+###### ----------------------- Other displays ------------------------ ######
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gsdll_h=gsdll.h
+
+gdevmswn_h=gdevmswn.h $(GDEV)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ gp_mswin.h
+
+gdevmswn.$(OBJ): gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h) \
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(CCCWIN) gdevmswn.c
+
+gdevmsxf.$(OBJ): gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCCWIN) gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+gdevwdib.$(OBJ): gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(CCCWIN) gdevwdib.c
+
+mswindll_=gdevmswn.$(OBJ) gdevmsxf.$(OBJ) gdevwdib.$(OBJ) \
+ gdevemap.$(OBJ) gdevpccm.$(OBJ)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=gdevwprn.$(OBJ) gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+gdevwprn.$(OBJ): gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(CCCWIN) gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+gdevwpr2.$(OBJ): gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) gp_mswin.h
+ $(CCCWIN) gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+gdevpm.$(OBJ): gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) gdevpm.h
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+os2prn.$(OBJ): os2prn.c $(gp_h)
+
+### -------------- The AT&T 3b1 Unixpc monochrome display --------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Andy Fyfe (andy@cs.caltech.edu) if you have questions. ###
+
+att3b1_=gdev3b1.$(OBJ)
+att3b1.dev: $(att3b1_)
+ $(SETDEV) att3b1 $(att3b1_)
+
+gdev3b1.$(OBJ): gdev3b1.c $(GDEV)
+
+### ---------------------- Linux PC with vgalib ------------------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the lvga256 driver, please contact ###
+### Ludger Kunz (ludger.kunz@fernuni-hagen.de). ###
+### For questions about the vgalib driver, please contact ###
+### Erik Talvola (talvola@gnu.ai.mit.edu). ###
+
+lvga256_=gdevl256.$(OBJ)
+lvga256.dev: $(lvga256_)
+ $(SETDEV) lvga256 $(lvga256_)
+ $(ADDMOD) lvga256 -lib vga vgagl
+
+gdevl256.$(OBJ): gdevl256.c $(GDEV)
+
+vgalib_=gdevvglb.$(OBJ) gdevpccm.$(OBJ)
+vgalib.dev: $(vgalib_)
+ $(SETDEV) vgalib $(vgalib_)
+ $(ADDMOD) vgalib -lib vga
+
+gdevvglb.$(OBJ): gdevvglb.c $(GDEV) $(gdevpccm_h) $(gsparam_h)
+
+### ------------------- Sony NeWS frame buffer device ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Mike Smolenski (mike@intertech.com) if you have questions. ###
+
+# This is implemented as a 'printer' device.
+sonyfb_=gdevsnfb.$(OBJ)
+sonyfb.dev: $(sonyfb_) page.dev
+ $(SETPDEV) sonyfb $(sonyfb_)
+
+gdevsnfb.$(OBJ): gdevsnfb.c $(PDEVH)
+
+### ------------------------ The SunView device ------------------------ ###
+### Note: this driver is maintained by a user: if you have questions, ###
+### please contact Andreas Stolcke (stolcke@icsi.berkeley.edu). ###
+
+sunview_=gdevsun.$(OBJ)
+sunview.dev: $(sunview_)
+ $(SETDEV) sunview $(sunview_)
+ $(ADDMOD) sunview -lib suntool sunwindow pixrect
+
+gdevsun.$(OBJ): gdevsun.c $(GDEV) $(malloc__h)\
+ $(gscdefs_h) $(gserrors_h) $(gsmatrix_h)
+
+### -------------------------- The X11 device -------------------------- ###
+
+# Aladdin Enterprises does not support Ghostview. For more information
+# about Ghostview, please contact Tim Theisen (ghostview@cs.wisc.edu).
+
+# See the main makefile for the definition of XLIBS.
+x11_=gdevx.$(OBJ) gdevxini.$(OBJ) gdevxxf.$(OBJ) gdevemap.$(OBJ)
+x11.dev: $(x11_)
+ $(SETDEV) x11 $(x11_)
+ $(ADDMOD) x11 -lib $(XLIBS)
+
+# See the main makefile for the definition of XINCLUDE.
+GDEVX=$(GDEV) x_.h gdevx.h $(MAKEFILE)
+gdevx.$(OBJ): gdevx.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevx.c
+
+gdevxini.$(OBJ): gdevxini.c $(GDEVX) $(math__h) $(memory__h) $(gserrors_h)
+ $(CCC) $(XINCLUDE) gdevxini.c
+
+gdevxxf.$(OBJ): gdevxxf.c $(GDEVX) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCC) $(XINCLUDE) gdevxxf.c
+
+# Alternate X11-based devices to help debug other drivers.
+# x11alpha pretends to have 4 bits of alpha channel.
+# x11cmyk pretends to be a CMYK device with 1 bit each of C,M,Y,K.
+# x11gray2 pretends to be a 2-bit gray-scale device.
+# x11mono pretends to be a black-and-white device.
+x11alt_=$(x11_) gdevxalt.$(OBJ)
+x11alpha.dev: $(x11alt_)
+ $(SETDEV) x11alpha $(x11alt_)
+ $(ADDMOD) x11alpha -lib $(XLIBS)
+
+x11cmyk.dev: $(x11alt_)
+ $(SETDEV) x11cmyk $(x11alt_)
+ $(ADDMOD) x11cmyk -lib $(XLIBS)
+
+x11gray2.dev: $(x11alt_)
+ $(SETDEV) x11gray2 $(x11alt_)
+ $(ADDMOD) x11gray2 -lib $(XLIBS)
+
+x11mono.dev: $(x11alt_)
+ $(SETDEV) x11mono $(x11alt_)
+ $(ADDMOD) x11mono -lib $(XLIBS)
+
+gdevxalt.$(OBJ): gdevxalt.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevxalt.c
+
+### ------------------------- DEC sixel displays ------------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Phil Keegstra (keegstra@tonga.gsfc.nasa.gov) if you have questions. ###
+
+# This is a "printer" device, but it probably shouldn't be.
+# I don't know why the implementor chose to do it this way.
+sxlcrt_=gdevln03.$(OBJ)
+sxlcrt.dev: $(sxlcrt_) page.dev
+ $(SETPDEV) sxlcrt $(sxlcrt_)
+
+###### --------------- Memory-buffered printer devices --------------- ######
+
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users. ###
+### If you have questions about the DMP driver, please contact ###
+### Mark Wedel (master@cats.ucsc.edu). ###
+### If you have questions about the Imagewriter drivers, please contact ###
+### Jonathan Luckey (luckey@rtfm.mlb.fl.us). ###
+### If you have questions about the Imagewriter LQ driver, please ###
+### contact Scott Barker (barkers@cuug.ab.ca). ###
+
+appledmp_=gdevadmp.$(OBJ)
+
+gdevadmp.$(OBJ): gdevadmp.c $(PDEVH)
+
+appledmp.dev: $(appledmp_) page.dev
+ $(SETPDEV) appledmp $(appledmp_)
+
+iwhi.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwhi $(appledmp_)
+
+iwlo.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlo $(appledmp_)
+
+iwlq.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlq $(appledmp_)
+
+### ------------ The Canon BubbleJet BJ10e and BJ200 devices ------------ ###
+
+bj10e_=gdevbj10.$(OBJ)
+
+bj10e.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj10e $(bj10e_)
+
+bj200.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj200 $(bj10e_)
+
+gdevbj10.$(OBJ): gdevbj10.c $(PDEVH)
+
+### ------------- The CalComp Raster Format ----------------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Ernst Muellner (ernst.muellner@oenzl.siemens.de) if you have ###
+### questions. ###
+
+ccr_=gdevccr.$(OBJ)
+ccr.dev: $(ccr_) page.dev
+ $(SETPDEV) ccr $(ccr_)
+
+gdevccr.$(OBJ): gdevccr.c $(PDEVH)
+
+### ----------- The H-P DeskJet and LaserJet printer devices ----------- ###
+
+### These are essentially the same device.
+### NOTE: printing at full resolution (300 DPI) requires a printer
+### with at least 1.5 Mb of memory. 150 DPI only requires .5 Mb.
+### Note that the lj4dith driver is included with the H-P color printer
+### drivers below.
+
+HPPCL=gdevpcl.$(OBJ)
+HPMONO=gdevdjet.$(OBJ) $(HPPCL)
+
+gdevpcl.$(OBJ): gdevpcl.c $(PDEVH) $(gdevpcl_h)
+
+gdevdjet.$(OBJ): gdevdjet.c $(PDEVH) $(gdevpcl_h)
+
+deskjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) deskjet $(HPMONO)
+
+djet500.dev: $(HPMONO) page.dev
+ $(SETPDEV) djet500 $(HPMONO)
+
+laserjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) laserjet $(HPMONO)
+
+ljetplus.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljetplus $(HPMONO)
+
+### Selecting ljet2p provides TIFF (mode 2) compression on LaserJet III,
+### IIIp, IIId, IIIsi, IId, and IIp.
+
+ljet2p.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet2p $(HPMONO)
+
+### Selecting ljet3 provides Delta Row (mode 3) compression on LaserJet III,
+### IIIp, IIId, IIIsi.
+
+ljet3.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3 $(HPMONO)
+
+### Selecting ljet3d also provides duplex printing capability.
+
+ljet3d.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3d $(HPMONO)
+
+### Selecting ljet4 also provides Delta Row compression on LaserJet IV series.
+
+ljet4.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet4 $(HPMONO)
+
+lp2563.dev: $(HPMONO) page.dev
+ $(SETPDEV) lp2563 $(HPMONO)
+
+oce9050.dev: $(HPMONO) page.dev
+ $(SETPDEV) oce9050 $(HPMONO)
+
+### ------------------ The H-P LaserJet 5 and 6 devices ----------------- ###
+
+### These drivers use H-P's new PCL XL printer language, like H-P's
+### LaserJet 5 Enhanced driver for MS Windows. We don't recommend using
+### them:
+### - If you have a LJ 5L or 5P, which isn't a "real" LaserJet 5,
+### use the ljet4 driver instead. (The lj5 drivers won't work.)
+### - If you have any other model of LJ 5 or 6, use the pxlmono
+### driver, which often produces much more compact output.
+
+gdevpxat_h=gdevpxat.h
+gdevpxen_h=gdevpxen.h
+gdevpxop_h=gdevpxop.h
+
+ljet5_=gdevlj56.$(OBJ) $(HPPCL)
+lj5mono.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5mono $(ljet5_)
+
+lj5gray.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5gray $(ljet5_)
+
+gdevlj56.$(OBJ): gdevlj56.c $(PDEVH) $(gdevpcl_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h)
+
+### The H-P DeskJet, PaintJet, and DesignJet family color printer devices.###
+### Note: there are two different 500C drivers, both contributed by users.###
+### If you have questions about the djet500c driver, ###
+### please contact AKayser@et.tudelft.nl. ###
+### If you have questions about the cdj* drivers, ###
+### please contact g.cameron@biomed.abdn.ac.uk. ###
+### If you have questions about the dnj560c driver, ###
+### please contact koert@zen.cais.com. ###
+### If you have questions about the lj4dith driver, ###
+### please contact Eckhard.Rueggeberg@ts.go.dlr.de. ###
+### If you have questions about the BJC600/BJC4000, BJC800, or ESCP ###
+### drivers, please contact Yves.Arrouye@imag.fr. ###
+
+cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+cdeskjet.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdeskjet $(cdeskjet_)
+
+cdjcolor.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjcolor $(cdeskjet_)
+
+cdjmono.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjmono $(cdeskjet_)
+
+cdj500.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj500 $(cdeskjet_)
+
+cdj550.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj550 $(cdeskjet_)
+
+declj250.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) declj250 $(cdeskjet_)
+
+dnj650c.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) dnj650c $(cdeskjet_)
+
+lj4dith.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) lj4dith $(cdeskjet_)
+
+pj.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pj $(cdeskjet_)
+
+pjxl.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl $(cdeskjet_)
+
+pjxl300.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl300 $(cdeskjet_)
+
+# Note: the BJC600 driver also works for the BJC4000.
+bjc600.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc600 $(cdeskjet_)
+
+bjc800.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc800 $(cdeskjet_)
+
+escp.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) escp $(cdeskjet_)
+
+# NB: you can also customise the build if required, using
+# -DBitsPerPixel=<number> if you wish the default to be other than 24
+# for the generic drivers (cdj500, cdj550, pjxl300, pjtest, pjxltest).
+gdevcdj.$(OBJ): gdevcdj.c $(std_h) $(PDEVH) gdevbjc.h\
+ $(gsparam_h) $(gsstate_h) $(gxlum_h)\
+ $(gdevpcl_h)
+
+djet500c_=gdevdjtc.$(OBJ) $(HPPCL)
+djet500c.dev: $(djet500c_) page.dev
+ $(SETPDEV) djet500c $(djet500c_)
+
+gdevdjtc.$(OBJ): gdevdjtc.c $(PDEVH) $(malloc__h) $(gdevpcl_h)
+
+### -------------------- The Mitsubishi CP50 printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Michael Hu (michael@ximage.com) if you have questions. ###
+
+cp50_=gdevcp50.$(OBJ)
+cp50.dev: $(cp50_) page.dev
+ $(SETPDEV) cp50 $(cp50_)
+
+gdevcp50.$(OBJ): gdevcp50.c $(PDEVH)
+
+### ----------------- The generic Epson printer device ----------------- ###
+### Note: most of this code was contributed by users. Please contact ###
+### the following people if you have questions: ###
+### eps9mid - Guenther Thomsen (thomsen@cs.tu-berlin.de) ###
+### eps9high - David Wexelblat (dwex@mtgzfs3.att.com) ###
+### ibmpro - James W. Birdsall (jwbirdsa@picarefy.picarefy.com) ###
+
+epson_=gdevepsn.$(OBJ)
+
+epson.dev: $(epson_) page.dev
+ $(SETPDEV) epson $(epson_)
+
+eps9mid.dev: $(epson_) page.dev
+ $(SETPDEV) eps9mid $(epson_)
+
+eps9high.dev: $(epson_) page.dev
+ $(SETPDEV) eps9high $(epson_)
+
+gdevepsn.$(OBJ): gdevepsn.c $(PDEVH)
+
+### ----------------- The IBM Proprinter printer device ---------------- ###
+
+ibmpro.dev: $(epson_) page.dev
+ $(SETPDEV) ibmpro $(epson_)
+
+### -------------- The Epson LQ-2550 color printer device -------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Dave St. Clair (dave@exlog.com) if you have questions. ###
+
+epsonc_=gdevepsc.$(OBJ)
+epsonc.dev: $(epsonc_) page.dev
+ $(SETPDEV) epsonc $(epsonc_)
+
+gdevepsc.$(OBJ): gdevepsc.c $(PDEVH)
+
+### ------------- The Epson ESC/P 2 language printer devices ------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the Stylus 800 and AP3250 drivers, please contact ###
+### Richard Brown (rab@tauon.ph.unimelb.edu.au). ###
+### For questions about the Stylus Color drivers, please contact ###
+### Gunther Hess (gunther@elmos.de). ###
+
+ESCP2=gdevescp.$(OBJ)
+
+gdevescp.$(OBJ): gdevescp.c $(PDEVH)
+
+ap3250.dev: $(ESCP2) page.dev
+ $(SETPDEV) ap3250 $(ESCP2)
+
+st800.dev: $(ESCP2) page.dev
+ $(SETPDEV) st800 $(ESCP2)
+
+stcolor1_=gdevstc.$(OBJ) gdevstc1.$(OBJ) gdevstc2.$(OBJ)
+stcolor2_=gdevstc3.$(OBJ) gdevstc4.$(OBJ)
+stcolor.dev: $(stcolor1_) $(stcolor2_) page.dev
+ $(SETPDEV) stcolor $(stcolor1_)
+ $(ADDMOD) stcolor -obj $(stcolor2_)
+
+gdevstc.$(OBJ): gdevstc.c gdevstc.h $(PDEVH)
+
+gdevstc1.$(OBJ): gdevstc1.c gdevstc.h $(PDEVH)
+
+gdevstc2.$(OBJ): gdevstc2.c gdevstc.h $(PDEVH)
+
+gdevstc3.$(OBJ): gdevstc3.c gdevstc.h $(PDEVH)
+
+gdevstc4.$(OBJ): gdevstc4.c gdevstc.h $(PDEVH)
+
+### --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+### For questions about this driver, please contact: ###
+### Gunther Hess (gunther@elmos.de) ###
+
+uniprint_=gdevupd.$(OBJ)
+uniprint.dev: $(uniprint_) page.dev
+ $(SETPDEV) uniprint $(uniprint_)
+
+gdevupd.$(OBJ): gdevupd.c $(PDEVH) $(gsparam_h)
+
+### -------------- cdj850 - HP 850c Driver under development ------------- ###
+### Since this driver is in the development-phase it is not distributed ###
+### with ghostscript, but it is available via anonymous ftp from: ###
+### ftp://bonk.ethz.ch ###
+### For questions about this driver, please contact: ###
+### Uli Wortmann (E-Mail address inside the driver-package) ###
+
+cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+cdj850.dev: $(cdeskjet8_) page.dev
+ $(SETPDEV) cdj850 $(cdeskjet8_)
+
+### ------------ The H-P PaintJet color printer device ----------------- ###
+### Note: this driver also supports the DEC LJ250 color printer, which ###
+### has a PaintJet-compatible mode, and the PaintJet XL. ###
+### If you have questions about the XL, please contact Rob Reiss ###
+### (rob@moray.berkeley.edu). ###
+
+PJET=gdevpjet.$(OBJ) $(HPPCL)
+
+gdevpjet.$(OBJ): gdevpjet.c $(PDEVH) $(gdevpcl_h)
+
+lj250.dev: $(PJET) page.dev
+ $(SETPDEV) lj250 $(PJET)
+
+paintjet.dev: $(PJET) page.dev
+ $(SETPDEV) paintjet $(PJET)
+
+pjetxl.dev: $(PJET) page.dev
+ $(SETPDEV) pjetxl $(PJET)
+
+### -------------- Imagen ImPress Laser Printer device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Alan Millar (AMillar@bolis.sf-bay.org) if you have questions. ###
+### Set USE_BYTE_STREAM if using parallel interface; ###
+### Don't set it if using 'ipr' spooler (default). ###
+### You may also add -DA4 if needed for A4 paper. ###
+
+imagen_=gdevimgn.$(OBJ)
+imagen.dev: $(imagen_) page.dev
+ $(SETPDEV) imagen $(imagen_)
+
+gdevimgn.$(OBJ): gdevimgn.c $(PDEVH)
+ $(CCC) gdevimgn.c # for ipr spooler
+# $(CCC) -DUSE_BYTE_STREAM gdevimgn.c # for parallel
+
+### ------- The IBM 3852 JetPrinter color inkjet printer device -------- ###
+### Note: this driver was contributed by users: please contact ###
+### Kevin Gift (kgift@draper.com) if you have questions. ###
+### Note that the paper size that can be addressed by the graphics mode ###
+### used in this driver is fixed at 7-1/2 inches wide (the printable ###
+### width of the jetprinter itself.) ###
+
+jetp3852_=gdev3852.$(OBJ)
+jetp3852.dev: $(jetp3852_) page.dev
+ $(SETPDEV) jetp3852 $(jetp3852_)
+
+gdev3852.$(OBJ): gdev3852.c $(PDEVH) $(gdevpcl_h)
+
+### ---------- The Canon LBP-8II and LIPS III printer devices ---------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about these drivers, please contact ###
+### Lauri Paatero, lauri.paatero@paatero.pp.fi ###
+
+lbp8_=gdevlbp8.$(OBJ)
+lbp8.dev: $(lbp8_) page.dev
+ $(SETPDEV) lbp8 $(lbp8_)
+
+lips3.dev: $(lbp8_) page.dev
+ $(SETPDEV) lips3 $(lbp8_)
+
+gdevlbp8.$(OBJ): gdevlbp8.c $(PDEVH)
+
+### ----------- The DEC LN03/LA50/LA70/LA75 printer devices ------------ ###
+### Note: this driver was contributed by users: please contact ###
+### Ulrich Mueller (ulm@vsnhd1.cern.ch) if you have questions. ###
+### For questions about LA50 and LA75, please contact ###
+### Ian MacPhedran (macphed@dvinci.USask.CA). ###
+### For questions about the LA70, please contact ###
+### Bruce Lowekamp (lowekamp@csugrad.cs.vt.edu). ###
+### For questions about the LA75plus, please contact ###
+### Andre' Beck (Andre_Beck@IRS.Inf.TU-Dresden.de). ###
+
+ln03_=gdevln03.$(OBJ)
+ln03.dev: $(ln03_) page.dev
+ $(SETPDEV) ln03 $(ln03_)
+
+la50.dev: $(ln03_) page.dev
+ $(SETPDEV) la50 $(ln03_)
+
+la70.dev: $(ln03_) page.dev
+ $(SETPDEV) la70 $(ln03_)
+
+la75.dev: $(ln03_) page.dev
+ $(SETPDEV) la75 $(ln03_)
+
+la75plus.dev: $(ln03_) page.dev
+ $(SETPDEV) la75plus $(ln03_)
+
+gdevln03.$(OBJ): gdevln03.c $(PDEVH)
+
+# LA70 driver with low-resolution text enhancement.
+
+la70t_=gdevla7t.$(OBJ)
+la70t.dev: $(la70t_) page.dev
+ $(SETPDEV) la70t $(la70t_)
+
+gdevla7t.$(OBJ): gdevla7t.c $(PDEVH)
+
+### -------------- The Epson LP-8000 laser printer device -------------- ###
+### Note: this driver was contributed by a user: please contact Oleg ###
+### Oleg Fat'yanov <faty1@rlem.titech.ac.jp> if you have questions.###
+
+lp8000_=gdevlp8k.$(OBJ)
+lp8000.dev: $(lp8000_) page.dev
+ $(SETPDEV) lp8000 $(lp8000_)
+
+gdevlp8k.$(OBJ): gdevlp8k.c $(PDEVH)
+
+### -------------- The C.Itoh M8510 printer device --------------------- ###
+### Note: this driver was contributed by a user: please contact Bob ###
+### Smith <bob@snuffy.penfield.ny.us> if you have questions. ###
+
+m8510_=gdev8510.$(OBJ)
+m8510.dev: $(m8510_) page.dev
+ $(SETPDEV) m8510 $(m8510_)
+
+gdev8510.$(OBJ): gdev8510.c $(PDEVH)
+
+### -------------- 24pin Dot-matrix printer with 360DPI ---------------- ###
+### Note: this driver was contributed by users. Please contact: ###
+### Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) for ###
+### questions about the NEC P6; ###
+### Christian Felsch (felsch@tu-harburg.d400.de) for ###
+### questions about the Epson LQ850. ###
+
+dm24_=gdevdm24.$(OBJ)
+gdevdm24.$(OBJ): gdevdm24.c $(PDEVH)
+
+necp6.dev: $(dm24_) page.dev
+ $(SETPDEV) necp6 $(dm24_)
+
+lq850.dev: $(dm24_) page.dev
+ $(SETPDEV) lq850 $(dm24_)
+
+### ----------------- The Okidata MicroLine 182 device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Maarten Koning (smeg@bnr.ca) if you have questions. ###
+
+oki182_=gdevo182.$(OBJ)
+oki182.dev: $(oki182_) page.dev
+ $(SETPDEV) oki182 $(oki182_)
+
+gdevo182.$(OBJ): gdevo182.c $(PDEVH)
+
+### ------------- The Okidata IBM compatible printer device ------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Charles Mack (chasm@netcom.com) if you have questions. ###
+
+okiibm_=gdevokii.$(OBJ)
+okiibm.dev: $(okiibm_) page.dev
+ $(SETPDEV) okiibm $(okiibm_)
+
+gdevokii.$(OBJ): gdevokii.c $(PDEVH)
+
+### ------------- The Ricoh 4081 laser printer device ------------------ ###
+### Note: this driver was contributed by users: ###
+### please contact kdw@oasis.icl.co.uk if you have questions. ###
+
+r4081_=gdev4081.$(OBJ)
+r4081.dev: $(r4081_) page.dev
+ $(SETPDEV) r4081 $(r4081_)
+
+
+gdev4081.$(OBJ): gdev4081.c $(PDEVH)
+
+### -------------------- Sony NWP533 printer device -------------------- ###
+### Note: this driver was contributed by a user: please contact Tero ###
+### Kivinen (kivinen@joker.cs.hut.fi) if you have questions. ###
+
+nwp533_=gdevn533.$(OBJ)
+nwp533.dev: $(nwp533_) page.dev
+ $(SETPDEV) nwp533 $(nwp533_)
+
+gdevn533.$(OBJ): gdevn533.c $(PDEVH)
+
+### ------------------------- The SPARCprinter ------------------------- ###
+### Note: this driver was contributed by users: please contact Martin ###
+### Schulte (schulte@thp.uni-koeln.de) if you have questions. ###
+### He would also like to hear from anyone using the driver. ###
+### Please consult the source code for additional documentation. ###
+
+sparc_=gdevsppr.$(OBJ)
+sparc.dev: $(sparc_) page.dev
+ $(SETPDEV) sparc $(sparc_)
+
+gdevsppr.$(OBJ): gdevsppr.c $(PDEVH)
+
+### ----------------- The StarJet SJ48 device -------------------------- ###
+### Note: this driver was contributed by a user: if you have questions, ###
+### . ###
+### please contact Mats Akerblom (f86ma@dd.chalmers.se). ###
+
+sj48_=gdevsj48.$(OBJ)
+sj48.dev: $(sj48_) page.dev
+ $(SETPDEV) sj48 $(sj48_)
+
+gdevsj48.$(OBJ): gdevsj48.c $(PDEVH)
+
+### ----------------- Tektronix 4396d color printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karl Hakimian (hakimian@haney.eecs.wsu.edu) ###
+### if you have questions. ###
+
+t4693d_=gdev4693.$(OBJ)
+t4693d2.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d2 $(t4693d_)
+
+t4693d4.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d4 $(t4693d_)
+
+t4693d8.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d8 $(t4693d_)
+
+gdev4693.$(OBJ): gdev4693.c $(PDEVH)
+
+### -------------------- Tektronix ink-jet printers -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karsten Spang (spang@nbivax.nbi.dk) if you have questions. ###
+
+tek4696_=gdevtknk.$(OBJ)
+tek4696.dev: $(tek4696_) page.dev
+ $(SETPDEV) tek4696 $(tek4696_)
+
+gdevtknk.$(OBJ): gdevtknk.c $(PDEVH) $(malloc__h)
+
+### ----------------- The Xerox XES printer device --------------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Peter Flass (flass@lbdrscs.bitnet) if you have questions. ###
+
+xes_=gdevxes.$(OBJ)
+xes.dev: $(xes_) page.dev
+ $(SETPDEV) xes $(xes_)
+
+gdevxes.$(OBJ): gdevxes.c $(PDEVH)
+
+###### ------------------------- Fax devices ------------------------- ######
+
+### --------------- Generic PostScript system compatible fax ------------ ###
+
+# This code doesn't work yet. Don't even think about using it.
+
+PSFAX=gdevpfax.$(OBJ)
+
+psfax_=$(PSFAX)
+psfax.dev: $(psfax_) page.dev
+ $(SETPDEV) psfax $(psfax_)
+ $(ADDMOD) psfax -iodev Fax
+
+gdevpfax.$(OBJ): gdevpfax.c $(PDEVH) $(gsparam_h) $(gxiodev_h)
+
+### ------------------------- The DigiFAX device ------------------------ ###
+### This driver outputs images in a format suitable for use with ###
+### DigiBoard, Inc.'s DigiFAX software. Use -sDEVICE=dfaxhigh for ###
+### high resolution output, -sDEVICE=dfaxlow for normal output. ###
+### Note: this driver was contributed by a user: please contact ###
+### Rick Richardson (rick@digibd.com) if you have questions. ###
+
+dfax_=gdevdfax.$(OBJ) gdevtfax.$(OBJ)
+
+dfaxlow.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxlow $(dfax_)
+ $(ADDMOD) dfaxlow -include cfe
+
+dfaxhigh.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxhigh $(dfax_)
+ $(ADDMOD) dfaxhigh -include cfe
+
+gdevdfax.$(OBJ): gdevdfax.c $(PDEVH) $(scfx_h) $(strimpl_h)
+
+### --------------See under TIFF below for fax-format TIFF -------------- ###
+
+###### ------------------- High-level file formats ------------------- ######
+
+# Support for PostScript and PDF
+
+gdevpsdf_h=gdevpsdf.h $(gdevvec_h) $(strimpl_h)
+gdevpstr_h=gdevpstr.h
+
+gdevpsdf.$(OBJ): gdevpsdf.c $(stdio__h) $(string__h)\
+ $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsparam_h) $(gstypes_h)\
+ $(gxdevice_h)\
+ $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpstr.$(OBJ): gdevpstr.c $(math__h) $(stdio__h) $(string__h)\
+ $(gdevpstr_h) $(stream_h)
+
+# PostScript and EPS writers
+
+pswrite1_=gdevps.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pswrite2_=scantab.$(OBJ) sfilter2.$(OBJ)
+pswrite_=$(pswrite1_) $(pswrite2_)
+epswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) epswrite $(pswrite1_)
+ $(ADDMOD) epswrite $(pswrite2_)
+ $(ADDMOD) epswrite -include vector
+
+pswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) pswrite $(pswrite1_)
+ $(ADDMOD) pswrite $(pswrite2_)
+ $(ADDMOD) pswrite -include vector
+
+gdevps.$(OBJ): gdevps.c $(GDEV) $(math__h) $(time__h)\
+ $(gscdefs_h) $(gscspace_h) $(gsparam_h) $(gsiparam_h) $(gsmatrix_h)\
+ $(gxdcolor_h)\
+ $(sa85x_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+# PDF writer
+# Note that gs_pdfwr.ps will only actually be loaded if the configuration
+# includes a PostScript interpreter.
+
+pdfwrite1_=gdevpdf.$(OBJ) gdevpdfd.$(OBJ) gdevpdfi.$(OBJ) gdevpdfm.$(OBJ)
+pdfwrite2_=gdevpdfp.$(OBJ) gdevpdft.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pdfwrite3_=gsflip.$(OBJ) scantab.$(OBJ) sfilter2.$(OBJ) sstring.$(OBJ)
+pdfwrite_=$(pdfwrite1_) $(pdfwrite2_) $(pdfwrite3_)
+pdfwrite.dev: $(ECHOGS_XE) $(pdfwrite_) \
+ cmyklib.dev cfe.dev dcte.dev lzwe.dev rle.dev vector.dev
+ $(SETDEV) pdfwrite $(pdfwrite1_)
+ $(ADDMOD) pdfwrite $(pdfwrite2_)
+ $(ADDMOD) pdfwrite $(pdfwrite3_)
+ $(ADDMOD) pdfwrite -ps gs_pdfwr
+ $(ADDMOD) pdfwrite -include cmyklib cfe dcte lzwe rle vector
+
+gdevpdfx_h=gdevpdfx.h $(gsparam_h) $(gxdevice_h) $(gxline_h) $(stream_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpdf.$(OBJ): gdevpdf.c $(math__h) $(memory__h) $(string__h) $(time__h)\
+ $(gp_h)\
+ $(gdevpdfx_h) $(gscdefs_h) $(gserrors_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)\
+ $(scanchar_h) $(scfx_h) $(slzwx_h) $(sstring_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) gdevpdf.c
+
+gdevpdfd.$(OBJ): gdevpdfd.c $(math__h)\
+ $(gdevpdfx_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+gdevpdfi.$(OBJ): gdevpdfi.c $(math__h) $(memory__h) $(gx_h) \
+ $(gdevpdfx_h) $(gscie_h) $(gscolor2_h) $(gserrors_h) $(gsflip_h)\
+ $(gxcspace_h) $(gxistate_h) \
+ $(sa85x_h) $(scfx_h) $(srlx_h) $(strimpl_h)
+
+gdevpdfm.$(OBJ): gdevpdfm.c $(memory__h) $(string__h) $(gx_h) \
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h) $(scanchar_h)
+
+gdevpdfp.$(OBJ): gdevpdfp.c $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h)
+
+gdevpdft.$(OBJ): gdevpdft.c $(math__h) $(memory__h) $(string__h) $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h)\
+ $(scommon_h)
+
+# High-level PCL XL writer
+
+pxl_=gdevpx.$(OBJ)
+pxlmono.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlmono $(pxl_)
+ $(ADDMOD) pxlmono -include vector
+
+pxlcolor.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlcolor $(pxl_)
+ $(ADDMOD) pxlcolor -include vector
+
+gdevpx.$(OBJ): gdevpx.c $(math__h) $(memory__h) $(string__h)\
+ $(gx_h) $(gsccolor_h) $(gsdcolor_h) $(gserrors_h)\
+ $(gxcspace_h) $(gxdevice_h) $(gxpath_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h) $(gdevvec_h)\
+ $(srlx_h) $(strimpl_h)
+
+###### --------------------- Raster file formats --------------------- ######
+
+### --------------------- The "plain bits" devices ---------------------- ###
+
+bit_=gdevbit.$(OBJ)
+
+bit.dev: $(bit_) page.dev
+ $(SETPDEV) bit $(bit_)
+
+bitrgb.dev: $(bit_) page.dev
+ $(SETPDEV) bitrgb $(bit_)
+
+bitcmyk.dev: $(bit_) page.dev
+ $(SETPDEV) bitcmyk $(bit_)
+
+gdevbit.$(OBJ): gdevbit.c $(PDEVH) $(gsparam_h) $(gxlum_h)
+
+### ------------------------- .BMP file formats ------------------------- ###
+
+bmp_=gdevbmp.$(OBJ) gdevpccm.$(OBJ)
+
+gdevbmp.$(OBJ): gdevbmp.c $(PDEVH) $(gdevpccm_h)
+
+bmpmono.dev: $(bmp_) page.dev
+ $(SETPDEV) bmpmono $(bmp_)
+
+bmp16.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16 $(bmp_)
+
+bmp256.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp256 $(bmp_)
+
+bmp16m.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16m $(bmp_)
+
+### ------------- BMP driver that serves as demo of async rendering ---- ###
+devasync_=gdevasyn.$(OBJ) gdevpccm.$(OBJ) gxsync.$(OBJ)
+
+gdevasyn.$(OBJ): gdevasyn.c $(AK) $(stdio__h) $(gdevprna_h) $(gdevpccm_h)\
+ $(gserrors_h) $(gpsync_h)
+
+asynmono.dev: $(devasync_) page.dev async.dev
+ $(SETPDEV) asynmono $(devasync_)
+ $(ADDMOD) asynmono -include async
+
+
+### -------------------------- CGM file format ------------------------- ###
+### This driver is under development. Use at your own risk. ###
+### The output is very low-level, consisting only of rectangles and ###
+### cell arrays. ###
+
+cgm_=gdevcgm.$(OBJ) gdevcgml.$(OBJ)
+
+gdevcgml_h=gdevcgml.h
+gdevcgmx_h=gdevcgmx.h $(gdevcgml_h)
+
+gdevcgm.$(OBJ): gdevcgm.c $(GDEV) $(memory__h)\
+ $(gsparam_h) $(gdevpccm_h) $(gdevcgml_h)
+
+gdevcgml.$(OBJ): gdevcgml.c $(memory__h) $(stdio__h)\
+ $(gdevcgmx_h)
+
+cgmmono.dev: $(cgm_)
+ $(SETDEV) cgmmono $(cgm_)
+
+cgm8.dev: $(cgm_)
+ $(SETDEV) cgm8 $(cgm_)
+
+cgm24.dev: $(cgm_)
+ $(SETDEV) cgm24 $(cgm_)
+
+### -------------------- The CIF file format for VLSI ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Frederic Petrot (petrot@masi.ibp.fr) if you have questions. ###
+
+cif_=gdevcif.$(OBJ)
+cif.dev: $(cif_) page.dev
+ $(SETPDEV) cif $(cif_)
+
+gdevcif.$(OBJ): gdevcif.c $(PDEVH)
+
+### ------------------------- JPEG file format ------------------------- ###
+
+jpeg_=gdevjpeg.$(OBJ)
+
+# RGB output
+jpeg.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeg $(jpeg_)
+ $(ADDMOD) jpeg -include sdcte
+
+# Gray output
+jpeggray.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeggray $(jpeg_)
+ $(ADDMOD) jpeggray -include sdcte
+
+gdevjpeg.$(OBJ): gdevjpeg.c $(stdio__h) $(PDEVH)\
+ $(sdct_h) $(sjpeg_h) $(stream_h) $(strimpl_h) jpeglib.h
+
+### ------------------------- MIFF file format ------------------------- ###
+### Right now we support only 24-bit direct color, but we might add more ###
+### formats in the future. ###
+
+miff_=gdevmiff.$(OBJ)
+
+miff24.dev: $(miff_) page.dev
+ $(SETPDEV) miff24 $(miff_)
+
+gdevmiff.$(OBJ): gdevmiff.c $(PDEVH)
+
+### --------------------------- MGR devices ---------------------------- ###
+### Note: these drivers were contributed by a user: please contact ###
+### Carsten Emde (carsten@ce.pr.net.ch) if you have questions. ###
+
+MGR=gdevmgr.$(OBJ) gdevpccm.$(OBJ)
+
+gdevmgr.$(OBJ): gdevmgr.c $(PDEVH) $(gdevpccm_h) gdevmgr.h
+
+mgrmono.dev: $(MGR) page.dev
+ $(SETPDEV) mgrmono $(MGR)
+
+mgrgray2.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray2 $(MGR)
+
+mgrgray4.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray4 $(MGR)
+
+mgrgray8.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray8 $(MGR)
+
+mgr4.dev: $(MGR) page.dev
+ $(SETPDEV) mgr4 $(MGR)
+
+mgr8.dev: $(MGR) page.dev
+ $(SETPDEV) mgr8 $(MGR)
+
+### ------------------------- PCX file formats ------------------------- ###
+
+pcx_=gdevpcx.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpcx.$(OBJ): gdevpcx.c $(PDEVH) $(gdevpccm_h) $(gxlum_h)
+
+pcxmono.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxmono $(pcx_)
+
+pcxgray.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxgray $(pcx_)
+
+pcx16.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx16 $(pcx_)
+
+pcx256.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx256 $(pcx_)
+
+pcx24b.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx24b $(pcx_)
+
+pcxcmyk.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxcmyk $(pcx_)
+
+# The 2-up PCX device is here only as an example, and for testing.
+pcx2up.dev: $(LIB_MAK) $(ECHOGS_XE) gdevp2up.$(OBJ) page.dev pcx256.dev
+ $(SETPDEV) pcx2up gdevp2up.$(OBJ)
+ $(ADDMOD) pcx2up -include pcx256
+
+gdevp2up.$(OBJ): gdevp2up.c $(AK)\
+ $(gdevpccm_h) $(gdevprn_h) $(gxclpage_h)
+
+### ------------------- Portable Bitmap file formats ------------------- ###
+### For more information, see the pbm(5), pgm(5), and ppm(5) man pages. ###
+
+pxm_=gdevpbm.$(OBJ)
+
+gdevpbm.$(OBJ): gdevpbm.c $(PDEVH) $(gscdefs_h) $(gxlum_h)
+
+### Portable Bitmap (PBM, plain or raw format, magic numbers "P1" or "P4")
+
+pbm.dev: $(pxm_) page.dev
+ $(SETPDEV) pbm $(pxm_)
+
+pbmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pbmraw $(pxm_)
+
+### Portable Graymap (PGM, plain or raw format, magic numbers "P2" or "P5")
+
+pgm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgm $(pxm_)
+
+pgmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgmraw $(pxm_)
+
+# PGM with automatic optimization to PBM if this is possible.
+
+pgnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnm $(pxm_)
+
+pgnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnmraw $(pxm_)
+
+### Portable Pixmap (PPM, plain or raw format, magic numbers "P3" or "P6")
+
+ppm.dev: $(pxm_) page.dev
+ $(SETPDEV) ppm $(pxm_)
+
+ppmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) ppmraw $(pxm_)
+
+# PPM with automatic optimization to PGM or PBM if possible.
+
+pnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pnm $(pxm_)
+
+pnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pnmraw $(pxm_)
+
+### Portable inKmap (CMYK internally, converted to PPM=RGB at output time)
+
+pkm.dev: $(pxm_) page.dev
+ $(SETPDEV) pkm $(pxm_)
+
+pkmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pkmraw $(pxm_)
+
+### --------------- Portable Network Graphics file format --------------- ###
+### Requires libpng 0.81 and zlib 0.95 (or more recent versions). ###
+### See libpng.mak and zlib.mak for more details. ###
+
+png_=gdevpng.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpng.$(OBJ): gdevpng.c $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(PSRC)png.h
+ $(CCCP) gdevpng.c
+
+pngmono.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pngmono $(png_)
+ $(ADDMOD) pngmono -include libpng
+
+pnggray.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pnggray $(png_)
+ $(ADDMOD) pnggray -include libpng
+
+png16.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16 $(png_)
+ $(ADDMOD) png16 -include libpng
+
+png256.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png256 $(png_)
+ $(ADDMOD) png256 -include libpng
+
+png16m.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16m $(png_)
+ $(ADDMOD) png16m -include libpng
+
+### ---------------------- PostScript image format ---------------------- ###
+### These devices make it possible to print Level 2 files on a Level 1 ###
+### printer, by converting them to a bitmap in PostScript format. ###
+
+ps_=gdevpsim.$(OBJ)
+
+gdevpsim.$(OBJ): gdevpsim.c $(PDEVH)
+
+psmono.dev: $(ps_) page.dev
+ $(SETPDEV) psmono $(ps_)
+
+psgray.dev: $(ps_) page.dev
+ $(SETPDEV) psgray $(ps_)
+
+# Someday there will be RGB and CMYK variants....
+
+### -------------------------- SGI RGB pixmaps -------------------------- ###
+
+sgirgb_=gdevsgi.$(OBJ)
+
+gdevsgi.$(OBJ): gdevsgi.c $(PDEVH) gdevsgi.h
+
+sgirgb.dev: $(sgirgb_) page.dev
+ $(SETPDEV) sgirgb $(sgirgb_)
+
+### -------------------- Plain or TIFF fax encoding --------------------- ###
+### Use -sDEVICE=tiffg3 or tiffg4 and ###
+### -r204x98 for low resolution output, or ###
+### -r204x196 for high resolution output ###
+### These drivers recognize 3 page sizes: letter, A4, and B4. ###
+
+gdevtifs_h=gdevtifs.h
+
+tfax_=gdevtfax.$(OBJ)
+tfax.dev: $(tfax_) cfe.dev lzwe.dev rle.dev tiffs.dev
+ $(SETMOD) tfax $(tfax_)
+ $(ADDMOD) tfax -include cfe lzwe rle tiffs
+
+gdevtfax.$(OBJ): gdevtfax.c $(PDEVH)\
+ $(gdevtifs_h) $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)
+
+### Plain G3/G4 fax with no header
+
+faxg3.dev: tfax.dev
+ $(SETDEV) faxg3 -include tfax
+
+faxg32d.dev: tfax.dev
+ $(SETDEV) faxg32d -include tfax
+
+faxg4.dev: tfax.dev
+ $(SETDEV) faxg4 -include tfax
+
+### ---------------------------- TIFF formats --------------------------- ###
+
+tiffs_=gdevtifs.$(OBJ)
+tiffs.dev: $(tiffs_) page.dev
+ $(SETMOD) tiffs $(tiffs_)
+ $(ADDMOD) tiffs -include page
+
+gdevtifs.$(OBJ): gdevtifs.c $(PDEVH) $(stdio__h) $(time__h) \
+ $(gdevtifs_h) $(gscdefs_h) $(gstypes_h)
+
+# Black & white, G3/G4 fax
+
+tiffcrle.dev: tfax.dev
+ $(SETDEV) tiffcrle -include tfax
+
+tiffg3.dev: tfax.dev
+ $(SETDEV) tiffg3 -include tfax
+
+tiffg32d.dev: tfax.dev
+ $(SETDEV) tiffg32d -include tfax
+
+tiffg4.dev: tfax.dev
+ $(SETDEV) tiffg4 -include tfax
+
+# Black & white, LZW compression
+
+tifflzw.dev: tfax.dev
+ $(SETDEV) tifflzw -include tfax
+
+# Black & white, PackBits compression
+
+tiffpack.dev: tfax.dev
+ $(SETDEV) tiffpack -include tfax
+
+# RGB, no compression
+
+tiffrgb_=gdevtfnx.$(OBJ)
+
+tiff12nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff12nc $(tiffrgb_)
+ $(ADDMOD) tiff12nc -include tiffs
+
+tiff24nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff24nc $(tiffrgb_)
+ $(ADDMOD) tiff24nc -include tiffs
+
+gdevtfnx.$(OBJ): gdevtfnx.c $(PDEVH) $(gdevtifs_h)
diff --git a/gs/src/dgc-head.mak b/gs/src/dgc-head.mak
new file mode 100644
index 000000000..deeb082a7
--- /dev/null
+++ b/gs/src/dgc-head.mak
@@ -0,0 +1,267 @@
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for DesqView/X/gcc/X11 configuration.
+# Note: this makefile assumes you are using gcc in ANSI mode.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit dvx-gcc.mak #
+# or makefile. Edit dgc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = c:/bin
+bindir = c:/bin
+gsdatadir = c:/gs
+gsfontdir = c:/gsfonts
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a ;.
+
+GS_LIB_DEFAULT="$(gsdatadir);$(gsfontdir)"
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library (-lpng).
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library (-lgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler.
+
+CC=gcc
+
+# Define the other compilation flags.
+# Add -DBSD4_2 for 4.2bsd systems.
+# Add -DSYSV for System V or DG/UX.
+# Add -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# Add -DSVR4 (not -DSYSV) for System V release 4.
+# XCFLAGS can be set from the command line.
+# We don't include -ansi, because this gets in the way of the platform-
+# specific stuff that <math.h> typically needs; nevertheless, we expect
+# gcc to accept ANSI-style function prototypes and function definitions.
+XCFLAGS=
+
+# Under DJGPP, since we strip the executable by default, we may as
+# well *not* use '-g'.
+
+# CFLAGS=-g -O $(XCFLAGS)
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=-lsys -lc
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=
+
+# Define the directory/ies and library names for the X11 library files.
+# The former can be null if these files are in the default linker search path.
+# Unfortunately, Quarterdeck's old libraries did not conform to the
+# X11 conventions for naming, in that the main Xlib library was called
+# libx.a, not libx11.a. To make things worse, both are provided in
+# the v2.00 library. Creation dates indicate that 'libx.a' is left
+# over from a previous build (or this could just be on my system, but
+# others who have upgraded from the early version will have the same
+# problem---SJT). Thus I will make the default to look for
+# 'libx11.a', since v1.0x does *not* have it and the linker will
+# complain. With the reverse default, the linker will find to the
+# obsolete library on some systems.
+
+# XLIBDIRS includes a prefix -L; XLIBDIR does not.
+XLIBDIRS=
+XLIBDIR=
+# reverse the comments if you have QDDVX10x or the prerelease version
+# of QDLIB200 (still available on some Simtel mirrors, unfortunately)
+# XLIBS=Xt Xext X
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=paintjet.dev pjetxl.dev uniprint.dev
+DEVICE_DEVS6=
+DEVICE_DEVS7=
+DEVICE_DEVS8=
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=
+DEVICE_DEVS14=
+DEVICE_DEVS15=
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=dgc-head.mak
+
+# Define the ANSI-to-K&R dependency. (gcc accepts ANSI syntax.)
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCLEAF=$(CCC) -fomit-frame-pointer
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
diff --git a/gs/src/dirent_.h b/gs/src/dirent_.h
new file mode 100644
index 000000000..0f7ab2b6a
--- /dev/null
+++ b/gs/src/dirent_.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1993, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* dirent_.h */
+/* Generic substitute for Unix dirent.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/* The location (or existence) of certain system headers is */
+/* environment-dependent. We detect this in the makefile */
+/* and conditionally define switches in gconfig_.h. */
+#include "gconfig_.h"
+
+/* Directory entries may be defined in quite a number of different */
+/* header files. The following switches are defined in gconfig_.h. */
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+typedef struct dirent dir_entry;
+#else /* sys/ndir or ndir or sys/dir, i.e., no dirent */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+typedef struct direct dir_entry;
+#endif /* sys/ndir or ndir or sys/dir */
diff --git a/gs/src/dodebug.h b/gs/src/dodebug.h
new file mode 100644
index 000000000..4ad1f06fc
--- /dev/null
+++ b/gs/src/dodebug.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* Force debugging code for a single file. */
+
+#undef dstderr
+#define dstderr stdout
+#define DEBUG
+static char gs_debug[128] = {
+ 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1
+};
diff --git a/gs/src/dos_.h b/gs/src/dos_.h
new file mode 100644
index 000000000..b98586a5b
--- /dev/null
+++ b/gs/src/dos_.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 1991, 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* dos_.h */
+/* Generic MS-DOS interface */
+
+/* This file is needed because the various DOS compilers */
+/* provide slightly different procedures for interfacing to DOS and */
+/* the I/O hardware, and because the Watcom compiler is 32-bit. */
+#include <dos.h>
+#if defined(__WATCOMC__) || defined(_MSC_VER)
+
+/* ---------------- Microsoft C/C++, all models; */
+/* ---------------- Watcom compiler, 32-bit flat model. */
+/* ---------------- inp/outp prototypes are in conio.h, not dos.h. */
+
+# include <conio.h>
+# define inport(px) inpw(px)
+# define inportb(px) inp(px)
+# define outport(px,w) outpw(px,w)
+# define outportb(px,b) outp(px,b)
+# define enable() _enable()
+# define disable() _disable()
+# define PTR_OFF(ptr) ((ushort)(uint)(ptr))
+/* Define the structure and procedures for file enumeration. */
+#define ff_name name
+#define dos_findfirst(n,b) _dos_findfirst(n, _A_NORMAL | _A_RDONLY, b)
+#define dos_findnext(b) _dos_findnext(b)
+
+/* Define things that differ between Watcom and Microsoft. */
+# ifdef __WATCOMC__
+# define MK_PTR(seg,off) (((seg) << 4) + (off))
+# define int86 int386
+# define int86x int386x
+# define rshort w
+# define ff_struct_t struct find_t
+# else
+# define MK_PTR(seg,off) (((ulong)(seg) << 16) + (off))
+# define cputs _cputs
+# define fdopen _fdopen
+# define O_BINARY _O_BINARY
+# define REGS _REGS
+# define rshort x
+# define ff_struct_t struct _find_t
+# define stdprn _stdprn
+# endif
+
+#else /* not Watcom or Microsoft */
+
+/* ---------------- Borland compiler, 16:16 pseudo-segmented model. */
+/* ---------------- ffblk is in dir.h, not dos.h. */
+#include <dir.h>
+# define MK_PTR(seg,off) MK_FP(seg,off)
+# define PTR_OFF(ptr) FP_OFF(ptr)
+/* Define the regs union tag for short registers. */
+# define rshort x
+/* Define the structure and procedures for file enumeration. */
+#define ff_struct_t struct ffblk
+#define dos_findfirst(n,b) findfirst(n, b, 0)
+#define dos_findnext(b) findnext(b)
+
+#endif
diff --git a/gs/src/dpmainc.c b/gs/src/dpmainc.c
new file mode 100644
index 000000000..e792160c5
--- /dev/null
+++ b/gs/src/dpmainc.c
@@ -0,0 +1,310 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+/* dpmainc.c */
+/* Ghostscript DLL loader for OS/2 */
+/* For WINDOWCOMPAT (console mode) application */
+
+/* Russell Lang 1996-06-05 */
+
+#define INCL_DOS
+#define INCL_WIN
+#include <os2.h>
+#include <stdio.h>
+#include <string.h>
+#include "gscdefs.h"
+#define GS_REVISION gs_revision
+#include "gsdll.h"
+
+#define MAXSTR 256
+const char *szDllName = "GSDLL2.DLL";
+char start_string[] = "systemdict /start get exec\n";
+int debug = FALSE;
+
+/* main structure with info about the GS DLL */
+typedef struct tagGSDLL {
+ BOOL valid; /* true if loaded */
+ HMODULE hmodule; /* handle to module */
+ /* pointers to DLL functions */
+ PFN_gsdll_revision revision;
+ PFN_gsdll_init init;
+ PFN_gsdll_exit exit;
+ PFN_gsdll_execute_begin execute_begin;
+ PFN_gsdll_execute_cont execute_cont;
+ PFN_gsdll_execute_end execute_end;
+ PFN_gsdll_get_bitmap get_bitmap;
+ PFN_gsdll_lock_device lock_device;
+ /* pointer to os2dll device */
+ char *device;
+} GSDLL;
+GSDLL gsdll;
+
+void
+gs_addmess(char *str)
+{
+ fputs(str, stdout);
+}
+
+/* free GS DLL */
+/* This should only be called when gsdll_execute has returned */
+/* TRUE means no error */
+BOOL
+gs_free_dll(void)
+{
+char buf[MAXSTR];
+APIRET rc;
+ if (gsdll.hmodule == (HMODULE)NULL)
+ return TRUE;
+ rc = DosFreeModule(gsdll.hmodule);
+ if (rc) {
+ sprintf(buf,"DosFreeModule returns %d\n", rc);
+ gs_addmess(buf);
+ sprintf(buf,"Unloaded GSDLL\n\n");
+ gs_addmess(buf);
+ }
+ return !rc;
+}
+
+void
+gs_load_dll_cleanup(void)
+{
+char buf[MAXSTR];
+ gs_free_dll();
+ fprintf(stdout, "Can't load Ghostscript DLL %s", szDllName);
+}
+
+/* load GS DLL if not already loaded */
+/* return TRUE if OK */
+BOOL
+gs_load_dll(void)
+{
+char buf[MAXSTR+40];
+APIRET rc;
+char *p;
+int i;
+long revision;
+const char *dllname;
+PTIB pptib;
+PPIB pppib;
+char szExePath[MAXSTR];
+char fullname[1024];
+const char *shortname;
+
+ if ( (rc = DosGetInfoBlocks(&pptib, &pppib)) != 0 ) {
+ fprintf(stdout,"Couldn't get pid, rc = \n", rc);
+ return FALSE;
+ }
+
+ /* get path to EXE */
+ if ( (rc = DosQueryModuleName(pppib->pib_hmte, sizeof(szExePath), szExePath)) != 0 ) {
+ fprintf(stdout,"Couldn't get module name, rc = %d\n", rc);
+ return FALSE;
+ }
+ if ((p = strrchr(szExePath,'\\')) != (char *)NULL) {
+ p++;
+ *p = '\0';
+ }
+
+ dllname = szDllName;
+ if (debug) {
+ sprintf(buf, "Trying to load %s\n", dllname);
+ gs_addmess(buf);
+ }
+ memset(buf, 0, sizeof(buf));
+ rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
+ if (rc) {
+ /* failed */
+ /* try again, with path of EXE */
+ if ((shortname = strrchr((char *)szDllName, '\\')) == (const char *)NULL)
+ shortname = szDllName;
+ strcpy(fullname, szExePath);
+ if ((p = strrchr(fullname,'\\')) != (char *)NULL)
+ p++;
+ else
+ p = fullname;
+ *p = '\0';
+ strcat(fullname, shortname);
+ dllname = fullname;
+ if (debug) {
+ sprintf(buf, "Trying to load %s\n", dllname);
+ gs_addmess(buf);
+ }
+ rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
+ if (rc) {
+ /* failed again */
+ /* try once more, this time on system search path */
+ dllname = shortname;
+ if (debug) {
+ sprintf(buf, "Trying to load %s\n", dllname);
+ gs_addmess(buf);
+ }
+ rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
+ }
+ }
+
+
+ if (rc == 0) {
+ if (debug)
+ gs_addmess("Loaded Ghostscript DLL\n");
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_REVISION", (PFN *)(&gsdll.revision)))!=0) {
+ sprintf(buf, "Can't find GSDLL_REVISION, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ /* check DLL version */
+ gsdll.revision(NULL, NULL, &revision, NULL);
+ if (revision != GS_REVISION) {
+ sprintf(buf, "Wrong version of DLL found.\n Found version %ld\n Need version %ld\n", revision, (long)GS_REVISION);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_INIT", (PFN *)(&gsdll.init)))!=0) {
+ sprintf(buf, "Can't find GSDLL_INIT, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_EXECUTE_BEGIN", (PFN *)(&gsdll.execute_begin)))!=0) {
+ sprintf(buf, "Can't find GSDLL_EXECUTE_BEGIN, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_EXECUTE_CONT", (PFN *)(&gsdll.execute_cont)))!=0) {
+ sprintf(buf, "Can't find GSDLL_EXECUTE_CONT, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_EXECUTE_END", (PFN *)(&gsdll.execute_end)))!=0) {
+ sprintf(buf, "Can't find GSDLL_EXECUTE_END, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_EXIT", (PFN *)(&gsdll.exit)))!=0) {
+ sprintf(buf, "Can't find GSDLL_EXIT, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_GET_BITMAP", (PFN *)(&gsdll.get_bitmap)))!=0) {
+ sprintf(buf, "Can't find GSDLL_GET_BITMAP, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSDLL_LOCK_DEVICE", (PFN *)(&gsdll.lock_device)))!=0) {
+ sprintf(buf, "Can't find GSDLL_LOCK_DEVICE, rc = %d\n", rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ }
+ else {
+ sprintf(buf, "Can't load Ghostscript DLL %s \nDosLoadModule rc = %d\n", szDllName, rc);
+ gs_addmess(buf);
+ gs_load_dll_cleanup();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+int
+read_stdin(char FAR *str, int len)
+{
+int ch;
+int count = 0;
+ while (count < len) {
+ ch = fgetc(stdin);
+ if (ch == EOF)
+ return count;
+ *str++ = ch;
+ count++;
+ if (ch == '\n')
+ return count;
+ }
+ return count;
+}
+
+int
+gsdll_callback(int message, char *str, unsigned long count)
+{
+char *p;
+ switch (message) {
+ case GSDLL_STDIN:
+ return read_stdin(str, count);
+ case GSDLL_STDOUT:
+ if (str != (char *)NULL)
+ fwrite(str, 1, count, stdout);
+ fflush(stdout);
+ return count;
+ case GSDLL_DEVICE:
+ if (count)
+ fprintf(stdout, "os2dll device not supported in this version of Ghostscript\n");
+ fprintf(stdout,"Callback: DEVICE %p %s\n", str,
+ count ? "open" : "close");
+ break;
+ case GSDLL_SYNC:
+ fprintf(stdout,"Callback: SYNC %p\n", str);
+ break;
+ case GSDLL_PAGE:
+ fprintf(stdout,"Callback: PAGE %p\n", str);
+ break;
+ case GSDLL_SIZE:
+ fprintf(stdout,"Callback: SIZE %p width=%d height=%d\n", str,
+ (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
+ break;
+ case GSDLL_POLL:
+ return 0; /* no error */
+ default:
+ fprintf(stdout,"Callback: Unknown message=%d\n",message);
+ break;
+ }
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+int code;
+ if (!gs_load_dll()) {
+ fprintf(stderr, "Can't load %s\n", szDllName);
+ return -1;
+ }
+ code = gsdll.init(gsdll_callback, (HWND)NULL, argc, argv);
+ if (!code)
+ code = gsdll.execute_begin();
+ if (!code) {
+ code = gsdll.execute_cont(start_string, strlen(start_string));
+ if (!code) {
+ gsdll.execute_end();
+ gsdll.exit();
+ }
+ else
+ code = gsdll.exit();
+ }
+ gs_free_dll();
+ if (code == GSDLL_INIT_QUIT)
+ return 0;
+ return code;
+}
diff --git a/gs/src/dstack.h b/gs/src/dstack.h
new file mode 100644
index 000000000..51e3340a4
--- /dev/null
+++ b/gs/src/dstack.h
@@ -0,0 +1,279 @@
+/* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* dstack.h */
+/* Definitions for the dictionary stack */
+#include "istack.h"
+
+/* Define the dictionary stack and systemdict. */
+extern ref_stack d_stack;
+extern ref ref_systemdict;
+#define systemdict (&ref_systemdict)
+
+/* Define the dictionary stack pointers. */
+typedef s_ptr ds_ptr;
+typedef const_s_ptr const_ds_ptr;
+#define dsbot (d_stack.bot)
+#define dsp (d_stack.p)
+#define dstop (d_stack.top)
+
+/* Macro to ensure enough room on the dictionary stack */
+#define check_dstack(n)\
+ if ( dstop - dsp < (n) )\
+ { d_stack.requested = (n); return_error(e_dictstackoverflow); }
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool dict_is_permanent_on_dstack(P1(const ref *));
+
+/*
+ * Switching between Level 1 and Level 2 involves inserting and removing
+ * globaldict on the dictionary stack. Instead of truly inserting and
+ * removing entries, we replace globaldict by a copy of systemdict in
+ * Level 1 mode. min_dstack_size, the minimum number of entries, does not
+ * change depending on language level; the countdictstack and dictstack
+ * operators must take this into account.
+ */
+extern uint min_dstack_size;
+
+/*
+ * The dictionary stack is implemented as a linked list of blocks;
+ * operators that access the entire d-stack must take this into account.
+ * These are:
+ * countdictstack dictstack
+ * In addition, name lookup requires searching the entire stack, not just
+ * the top block, and the underflow check for the dictionary stack
+ * (`end' operator) is not just a check for underflowing the top block.
+ */
+
+/*
+ * Cache a value for fast checking of def operations.
+ * If the top entry on the dictionary stack is a writable dictionary,
+ * dsspace is the space of the dictionary; if it is a non-writable
+ * dictionary, dsspace = -1. Then def is legal precisely if
+ * r_space(pvalue) <= dsspace. Note that in order for this trick to work,
+ * the result of r_space must be a signed integer; some compilers treat
+ * enums as unsigned, probably in violation of the ANSI standard.
+ */
+extern int dsspace;
+#define dtop_can_store(pvalue) ((int)r_space(pvalue) <= dsspace)
+/*
+ * Cache values for fast name lookup. If the top entry on the dictionary
+ * stack is a readable dictionary with packed keys, dtop_keys, dtop_npairs,
+ * and dtop_values are keys.value.packed, npairs, and values.value.refs
+ * for that dictionary; otherwise, these variables point to a dummy
+ * empty dictionary.
+ */
+extern const ref_packed *dtop_keys;
+extern uint dtop_npairs;
+extern ref *dtop_values;
+/*
+ * Reset the cached top values. Every routine that alters the
+ * dictionary stack (including changing the protection or size of the
+ * top dictionary on the stack) must call this.
+ */
+void dict_set_top(P0());
+
+/*
+ * Define a special fast entry for name lookup in the interpreter.
+ * The key is known to be a name; search the entire dict stack.
+ * Return the pointer to the value slot.
+ * If the name isn't found, just return 0.
+ */
+ref *dict_find_name_by_index(P1(uint nidx));
+#define dict_find_name(pnref) dict_find_name_by_index(name_index(pnref))
+
+/* Define the hashing function for names. */
+/* We don't have to scramble the index, because */
+/* indices are assigned in a scattered order (see name_ref in iname.c). */
+#define dict_name_index_hash(nidx) (nidx)
+
+/*
+ * Define an extra-fast macro for name lookup, optimized for
+ * a single-probe lookup in the top dictionary on the stack.
+ * Amazingly enough, this seems to hit over 90% of the time
+ * (aside from operators, of course, which are handled either with
+ * the special cache pointer or with 'bind').
+ */
+#define dict_find_name_by_index_inline(nidx,htemp)\
+ (dtop_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ dtop_npairs) + 1] == pt_tag(pt_literal_name) + (nidx) ?\
+ dtop_values + htemp : dict_find_name_by_index(nidx))
+/*
+ * Define a similar macro that only checks the top dictionary on the stack.
+ */
+#define if_dict_find_name_by_index_top(nidx,htemp,pvslot)\
+ if ( ((dtop_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ dtop_npairs) + 1] == pt_tag(pt_literal_name) + (nidx)) ?\
+ ((pvslot) = dtop_values + (htemp), 1) :\
+ 0)\
+ )
+
+/*
+Notes on dictionary lookup performance
+--------------------------------------
+
+We mark heavily used operations with a * below; moderately heavily used
+operations with a +.
+
+The following operations change the dictionary stack:
+ +begin, +end
+ readonly (on a dictionary that is on the stack)
+ noaccess (on a dictionary that is on the stack)
+We implement cleardictstack as a series of ends.
+
+The following operations change the contents of dictionaries:
+ *def, +put
+ undef
+ restore
+ .setmaxlength
+We implement store in PostScript, and copy as a series of puts. Many
+other operators also do puts (e.g., ScaleMatrix in makefont,
+Implementation in makepattern, ...). Note that put can do an implicit
+.setmaxlength (if it has to grow the dictionary).
+
+The following operations look up keys on the dictionary stack:
+ *(interpreter name lookup)
+ load
+ where
+
+Current design
+--------------
+
+Each name has a pointer that has one of 3 states:
+ - This name has no definitions.
+ - This name has exactly one definition, in systemdict or userdict.
+ In this case, the pointer points to the value slot.
+ - This name has some other status.
+
+We cache some pointers to the top dictionary on the stack if it is a
+readable dictionary with packed keys, which allows us to do fast,
+single-probe lookups in this dictionary. We also cache a value that
+allows us to do a fast check for stores into the top dictionary
+(writability + space check).
+
+Full shallow binding
+--------------------
+
+We implement shallow binding with a pointer in each name that points to
+the value slot that holds the name's definition. If the name is
+undefined, or if we don't know where the slot is, the binding pointer
+points to a ref with a special type t__invalid, which cannot occur
+anywhere else. "Clearing" the pointer means setting it to point to this
+ref.
+
+We also maintain a pair of pointers that bracket the value region of the
+top dictionary on the stack, for fast checking in def. If the top
+dictionary is readonly or noaccess, the pointers designate an empty area.
+We call this the "def region" cache.
+
+We implement the above operations as follows:
+ begin - push the dictionary on the stack; set the pointers of
+ all name keys to point to the corresponding value slots.
+ end - pop the stack; clear the pointers of all name keys.
+ readonly - if the dictionary is the top one on the stack,
+ reset the def region cache.
+ noaccess - clear the pointers of all name keys. (This is overly
+ conservative, but this is a very rare operation.)
+ Also reset the def region cache if the dictionary is
+ the top one on the stack.
+ def - if the key is a name and its pointer points within the cached
+ def region, store the value through the pointer; otherwise,
+ look up the key in the top dictionary, store the value,
+ and if the key is a name, set its pointer to the value slot.
+ put - if the key is a name and wasn't in the dictionary before,
+ clear its pointer. (Conservative, but rare.)
+ undef - if the key is a name, clear its pointer. (Overly
+ conservative, but rare.)
+ restore - if either the old or the new value of a change is a name
+ (possibly in a packed array), clear its pointer. This is
+ conservative, but easy to detect, and probably not *too*
+ conservative.
+ .setmaxlength - clear all the pointers, like noaccess.
+ (name lookup) - fetch the value through the pointer and dispatch
+ on its type; if the type is t__invalid, do a full search
+ and set the pointer. This avoids a separate check for a
+ clear pointer in the usual case where the pointer is valid.
+ load - if the pointer is clear, do a search and set the pointer;
+ then fetch the value.
+ where - always do a full search and set the pointer.
+ (Conservative, but rare.)
+
+One place where shallow binding will result in major new overhead is the
+extra push of systemdict for loading fonts. This probably isn't a problem
+in real life.
+
+Adaptive shallow binding
+------------------------
+
+We do validity checking for the name value cache using an epoch counter.
+For each dictionary D, we keep an on-stack flag F. Each dictionary stack
+entry is <D,M,F,E> where D is the actual dictionary, M is a mark vector of
+V bits (V is a system constant, probably 64), F is D's former on-stack
+flag, and E is the epoch at which the entry was made. For each name K, we
+keep a cache <P,E> where P is a pointer to the dictionary value slot that
+holds the current value of K, and E is an epoch value; the cache is valid
+if K->E >= dsp->E. Here is what happens for each operation:
+
+****** Still need to handle names defined only in systemdict or userdict?
+
+To initialize:
+ Epoch = 0
+To clear the cache entry for K:
+ *K = <ptr to invalid value, 0>
+begin(D):
+ *++dsp = <D, {0...}, D->F, ++Epoch>
+ set D->F
+value = lookup(K):
+ if K->E >= dsp->E
+ value = *K->P
+ else
+ do lookup as usual
+ *K = <ptr to value, Epoch>
+ set dp->M[i mod V] where dp is the dstack slot of the dictionary
+ where K was found and i is the index within that dictionary
+end:
+ for each i such that dsp->M[i] is set,
+ clear the cache entry for dsp->D->keys[i, i+V, ...]
+ dsp->D->F = dsp->F
+ --dsp
+noaccess(D):
+ if D->F is set,
+ clear the cache entries for all name keys of D
+readonly(D):
+ << nothing >>
+.setmaxlength(D,N):
+ same as noaccess
+restore:
+ If either the old or the new value of a change is a name
+ (possibly in a packed array), clear its cache entry. This is
+ conservative, but easy to detect, and probably not *too*
+ conservative.
+def(K,V):
+ if K->P points into dsp->D
+ *K->P = V
+ else
+ put the new value in dsp->D
+ set *K and dsp->M[i mod V] as for a lookup
+put(D,K,V):
+ if K is already defined in D, do nothing special
+ otherwise, if D->F isn't set, do nothing special
+ otherwise, clear K's cache entry
+undef(D,K):
+ if D->F is set,
+ clear K's cache entry
+*/
diff --git a/gs/src/dvx-gcc.mak b/gs/src/dvx-gcc.mak
new file mode 100755
index 000000000..d6667a476
--- /dev/null
+++ b/gs/src/dvx-gcc.mak
@@ -0,0 +1,5696 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile fragment containing the current revision identification.
+
+# Define the name of this makefile.
+VERSION_MAK=version.mak
+
+# Major and minor version numbers.
+# MINOR0 is different from MINOR only if MINOR is a single digit.
+GS_VERSION_MAJOR=5
+GS_VERSION_MINOR=13
+GS_VERSION_MINOR0=13
+# Revision date: year x 10000 + month x 100 + day.
+GS_REVISIONDATE=19980427
+
+# Derived values
+GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0)
+GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR)
+GS_REVISION=$(GS_VERSION)
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for DesqView/X/gcc/X11 configuration.
+# Note: this makefile assumes you are using gcc in ANSI mode.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit dvx-gcc.mak #
+# or makefile. Edit dgc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = c:/bin
+bindir = c:/bin
+gsdatadir = c:/gs
+gsfontdir = c:/gsfonts
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a ;.
+
+GS_LIB_DEFAULT="$(gsdatadir);$(gsfontdir)"
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library (-lpng).
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library (-lgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler.
+
+CC=gcc
+
+# Define the other compilation flags.
+# Add -DBSD4_2 for 4.2bsd systems.
+# Add -DSYSV for System V or DG/UX.
+# Add -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# Add -DSVR4 (not -DSYSV) for System V release 4.
+# XCFLAGS can be set from the command line.
+# We don't include -ansi, because this gets in the way of the platform-
+# specific stuff that <math.h> typically needs; nevertheless, we expect
+# gcc to accept ANSI-style function prototypes and function definitions.
+XCFLAGS=
+
+# Under DJGPP, since we strip the executable by default, we may as
+# well *not* use '-g'.
+
+# CFLAGS=-g -O $(XCFLAGS)
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=-lsys -lc
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=
+
+# Define the directory/ies and library names for the X11 library files.
+# The former can be null if these files are in the default linker search path.
+# Unfortunately, Quarterdeck's old libraries did not conform to the
+# X11 conventions for naming, in that the main Xlib library was called
+# libx.a, not libx11.a. To make things worse, both are provided in
+# the v2.00 library. Creation dates indicate that 'libx.a' is left
+# over from a previous build (or this could just be on my system, but
+# others who have upgraded from the early version will have the same
+# problem---SJT). Thus I will make the default to look for
+# 'libx11.a', since v1.0x does *not* have it and the linker will
+# complain. With the reverse default, the linker will find to the
+# obsolete library on some systems.
+
+# XLIBDIRS includes a prefix -L; XLIBDIR does not.
+XLIBDIRS=
+XLIBDIR=
+# reverse the comments if you have QDDVX10x or the prerelease version
+# of QDLIB200 (still available on some Simtel mirrors, unfortunately)
+# XLIBS=Xt Xext X
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=paintjet.dev pjetxl.dev uniprint.dev
+DEVICE_DEVS6=
+DEVICE_DEVS7=
+DEVICE_DEVS8=
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=
+DEVICE_DEVS14=
+DEVICE_DEVS15=
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=dgc-head.mak
+
+# Define the ANSI-to-K&R dependency. (gcc accepts ANSI syntax.)
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCLEAF=$(CCC) -fomit-frame-pointer
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
+# Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile, common to all Desqview/X configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name.
+
+PLATFORM=dvx_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=.bat
+O=-o ./
+OBJ=o
+XE=.exe
+XEAUX=.exe
+
+# Define the current directory prefix and command invocations.
+
+CAT=type
+D=\\
+EXP=
+SHELL=
+SH=
+SHP=
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p -pl &-l%%s -ol ld.tr
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+# Patch a couple of PC-specific things that aren't relevant to DV/X builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Generic makefile, common to all platforms.
+# The platform-specific makefiles `include' this file.
+# They define the following symbols:
+# GS - the name of the executable (without the extension, if any).
+# GS_LIB_DEFAULT - the default directory/ies for searching for the
+# initialization and font files at run time.
+# SEARCH_HERE_FIRST - the default setting of -P (whether or not to
+# look for files in the current directory first).
+# GS_DOCDIR - the directory where documentation will be available
+# at run time.
+# JSRCDIR - the directory where the IJG JPEG library source code
+# is stored (at compilation time).
+# JVERSION - the major version number of the IJG JPEG library.
+# PSRCDIR, PVERSION - the same for libpng.
+# ZSRCDIR - the same for zlib.
+# SHARE_LIBPNG - normally 0; if set to 1, asks the linker to use
+# an existing compiled libpng (-lpng) instead of compiling and
+# linking libpng explicitly.
+# LIBPNG_NAME, the name of the shared libpng, currently always
+# png (libpng, -lpng).
+# SHARE_ZLIB - normally 0; if set to 1, asks the linker to use
+# an existing compiled zlib (-lgz or -lz) instead of compiling
+# and linking libgz/libz explicitly.
+# ZLIB_NAME - the name of the shared zlib, either gz (for libgz, -lgz)
+# or z (for libz, -lz).
+# CONFIG - a configuration ID, added at the request of a customer,
+# that is supposed to help in maintaining multiple variants in
+# a single directory. Normally this is an empty string;
+# it may be any string that is legal as part of a file name.
+# DEVICE_DEVS - the devices to include in the executable.
+# See devs.mak for details.
+# DEVICE_DEVS1...DEVICE_DEVS15 - additional devices, if the definition
+# of DEVICE_DEVS doesn't fit on one line. See devs.mak for details.
+# FEATURE_DEVS - what features to include in the executable.
+# Normally this is one of:
+# level1 - a standard PostScript Level 1 language
+# interpreter.
+# level2 - a standard PostScript Level 2 language
+# interpreter.
+# pdf - a PDF-capable interpreter.
+# You may include both level1 and pdf, or both level2 and pdf.
+# The following feature may be added to either of the standard
+# configurations:
+# ccfonts - precompile fonts into C, and link them
+# with the executable. See fonts.txt for details.
+# The remaining features are of interest primarily to developers
+# who want to "mix and match" features to create custom
+# configurations:
+# dps - (partial) support for Display PostScript extensions:
+# see language.txt for details.
+# btoken - support for binary token encodings.
+# Included automatically in the dps and level2 features.
+# cidfont - (currently partial) support for CID-keyed fonts.
+# color - support for the Level 1 CMYK color extensions.
+# Included automatically in the dps and level2 features.
+# compfont - support for composite (type 0) fonts.
+# Included automatically in the level2 feature.
+# dct - support for DCTEncode/Decode filters.
+# Included automatically in the level2 feature.
+# epsf - support for recognizing and skipping the binary
+# header of MS-DOS EPSF files.
+# filter - support for Level 2 filters (other than eexec,
+# ASCIIHexEncode/Decode, NullEncode, PFBDecode,
+# RunLengthEncode/Decode, and SubFileDecode, which are
+# always included, and DCTEncode/Decode,
+# which are separate).
+# Included automatically in the level2 feature.
+# fzlib - support for zlibEncode/Decode filters.
+# ttfont - support for TrueType fonts.
+# type1 - support for Type 1 fonts and eexec;
+# normally included automatically in all configurations.
+# type42 - support for Type 42 (embedded TrueType) fonts.
+# Included automatically in the level2 feature.
+# There are quite a number of other sub-features that can be
+# selectively included in or excluded from a configuration,
+# but the above are the ones that are most likely to be of
+# interest.
+# COMPILE_INITS - normally 0; if set to 1, compiles the PostScript
+# language initialization files (gs_init.ps et al) into the
+# executable, eliminating the need for these files to be present
+# at run time.
+# BAND_LIST_STORAGE - normally file; if set to memory, stores band
+# lists in memory (with compression if needed).
+# BAND_LIST_COMPRESSOR - normally zlib: selects the compression method
+# to use for band lists in memory.
+# FILE_IMPLEMENTATION - normally stdio; if set to fd, uses file
+# descriptors instead of buffered stdio for file I/O; if set to
+# both, provides both implementations with different procedure
+# names for the fd-based implementation (see sfxfd.c for
+# more information).
+# EXTEND_NAMES - a value N between 0 and 6, indicating that the name
+# table should have a capacity of 2^(16+N) names. This normally
+# should be set to 0 (or left undefined), since non-zero values
+# result in a larger fixed space overhead and slightly slower code.
+# EXTEND_NAMES is ignored in 16-bit environments.
+#
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+# GS_INIT - the name of the initialization file for the interpreter,
+# normally gs_init.ps.
+# PLATFORM - a "device" name for the platform, so that platforms can
+# add various kinds of resources like devices and features.
+# CMD - the suffix for shell command files (e.g., null or .bat).
+# (This is only needed in a few places.)
+# D - the directory separator character (\ for MS-DOS, / for Unix).
+# O - the string for specifying the output file from the C compiler
+# (-o for MS-DOS, -o ./ for Unix).
+# OBJ - the extension for relocatable object files (e.g., o or obj).
+# XE - the extension for executable files (e.g., null or .exe).
+# XEAUX - the extension for the executable files (e.g., null or .exe)
+# for the utility programs (ansi2knr and those compiled with
+# CCAUX).
+# BEGINFILES - the list of files that `make begin' and `make clean'
+# should delete.
+# CCA2K - the C invocation for the ansi2knr program, which is the only
+# one that doesn't use ANSI C syntax. (It is only needed if
+# the main C compiler also isn't an ANSI compiler.)
+# CCAUX - the C invocation for auxiliary programs (echogs, genarch,
+# genconf, geninit).
+# CCBEGIN - the compilation command for `make begin', normally
+# $(CCC) *.c.
+# CCC - the C invocation for normal compilation.
+# CCD - the C invocation for files that store into frame buffers or
+# device registers. Needed because some optimizing compilers
+# will eliminate necessary stores.
+# CCCF - the C invocation for compiled fonts and other large,
+# self-contained data modules. Needed because MS-DOS
+# requires using the 'huge' memory model for these.
+# CCINT - the C invocation for compiling the main interpreter module,
+# normally the same as CCC: this is needed because the
+# Borland compiler generates *worse* code for this module
+# (but only this module) when optimization (-O) is turned on.
+# CCLEAF - the C invocation for compiling modules that contain only
+# leaf procedures, which don't need to build stack frames.
+# This is needed only because many compilers aren't able to
+# recognize leaf procedures on their own.
+# AK - if source files must be converted from ANSI to K&R syntax,
+# this is $(ANSI2KNR_XE); if not, it is null.
+# If a particular platform requires other utility programs
+# to be built, AK must include them too.
+# SHP - the prefix for invoking a shell script in the current directory
+# (null for MS-DOS, $(SH) ./ for Unix).
+# EXPP, EXP - the prefix for invoking an executable program in the
+# current directory (null for MS-DOS, ./ for Unix).
+# SH - the shell for scripts (null on MS-DOS, sh on Unix).
+# CONFILES - the arguments for genconf to generate the appropriate
+# linker control files (various).
+# CP_ - the command for copying one file to another. Because of
+# limitations in the MS-DOS/MS Windows environment, the
+# second argument must either be '.' (in which case the
+# write date may be either preserved or set to the current
+# date) or a file name (in which case the write date is
+# always updated).
+# RM_ - the command for deleting (a) file(s) (including wild cards,
+# but limited to a single file or pattern).
+# RMN_ = the command for deleting multiple files / patterns.
+#
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+# Define the name of this makefile.
+GS_MAK=gs.mak
+
+# Define the names of the executables.
+GS_XE=$(GS)$(XE)
+ANSI2KNR_XE=ansi2knr$(XEAUX)
+ECHOGS_XE=echogs$(XEAUX)
+GENARCH_XE=genarch$(XEAUX)
+GENCONF_XE=genconf$(XEAUX)
+GENINIT_XE=geninit$(XEAUX)
+
+# Define the names of the CONFIG-dependent header files.
+# gconfig*.h and gconfx*.h are generated dynamically.
+gconfig_h=gconfxx$(CONFIG).h
+gconfigf_h=gconfxc$(CONFIG).h
+
+# Watcom make insists that rules have a non-empty body!
+all default: $(GS_XE)
+ $(RM_) _temp_*
+
+distclean maintainer-clean realclean: clean
+ $(RM_) makefile
+
+clean: mostlyclean
+ $(RM_) arch.h
+ $(RM_) $(GS_XE)
+
+mostlyclean:
+ $(RMN_) *.$(OBJ) *.a core gmon.out
+ $(RMN_) *.dev *.d_* devs*.tr gconfig*.h gconfx*.h j*.h o*.tr l*.tr
+ $(RMN_) deflate.h zutil.h
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) _temp_* _temp_*.* *.map *.sym
+ $(RMN_) $(ANSI2KNR_XE) $(ECHOGS_XE) $(GENARCH_XE) $(GENCONF_XE) $(GENINIT_XE)
+ $(RMN_) gs_init.c $(BEGINFILES)
+
+# Remove only configuration-dependent information.
+config-clean:
+ $(RMN_) *.dev devs*.tr gconfig*.h gconfx*.h o*.tr l*.tr
+
+# A rule to do a quick and dirty compilation attempt when first installing
+# the interpreter. Many of the compilations will fail:
+# follow this with 'make'.
+
+begin:
+ $(RMN_) arch.h gconfig*.h gconfx*.h $(GENARCH_XE) $(GS_XE)
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) gs_init.c $(BEGINFILES)
+ make arch.h gconfigv.h
+ - $(CCBEGIN)
+ $(RMN_) gconfig.$(OBJ) gdev*.$(OBJ) gp_*.$(OBJ) gscdefs.$(OBJ) gsmisc.$(OBJ)
+ $(RMN_) icfontab.$(OBJ) iconfig.$(OBJ) iinit.$(OBJ) interp.$(OBJ)
+
+# Auxiliary programs
+
+arch.h: $(GENARCH_XE)
+ $(EXPP) $(EXP)genarch arch.h
+
+# Macros for constructing the *.dev files that describe features and
+# devices.
+SETDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-obj
+SETPDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-include -lpage -l-obj
+SETMOD=$(EXP)echogs -e .dev -w- -l-obj
+ADDMOD=$(EXP)echogs -e .dev -a-
+
+# Define the compilation commands for the third-party libraries.
+CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR) -DPNG_USE_CONST
+CCCJ=$(CCC) -I. -I$(JSRCDIR)
+CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+
+######################## How to define new 'features' #######################
+#
+# One defines new 'features' exactly like devices (see devs.mak for details).
+# For example, one would define a feature abc by adding the following to
+# gs.mak:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_)
+# $(SETMOD) abc $(abc_)
+# $(ADDMOD) abc -obj ... [if needed]
+# $(ADDMOD) abc -oper ... [if appropriate]
+# $(ADDMOD) abc -ps ... [if appropriate]
+#
+# If the abc feature requires the presence of some other features jkl and
+# pqr, then the rules must look like this:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_) jkl.dev pqr.dev
+# $(SETMOD) abc $(abc_)
+# ...
+# $(ADDMOD) abc -include jkl pqr
+
+# --------------------- Configuration-dependent files --------------------- #
+
+# gconfig.h shouldn't have to depend on DEVS_ALL, but that would
+# involve rewriting gsconfig to only save the device name, not the
+# contents of the <device>.dev files.
+# FEATURE_DEVS must precede DEVICE_DEVS so that devices can override
+# features in obscure cases.
+
+DEVS_ALL=$(PLATFORM).dev $(FEATURE_DEVS) \
+ $(DEVICE_DEVS) $(DEVICE_DEVS1) \
+ $(DEVICE_DEVS2) $(DEVICE_DEVS3) $(DEVICE_DEVS4) $(DEVICE_DEVS5) \
+ $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
+ $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
+ $(DEVICE_DEVS14) $(DEVICE_DEVS15)
+
+devs_tr=devs.tr$(CONFIG)
+$(devs_tr): $(GS_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w $(devs_tr) - -include $(PLATFORM).dev
+ $(EXP)echogs -a $(devs_tr) - $(FEATURE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS1)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS2)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS3)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS4)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS5)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS6)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS7)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS8)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS9)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS10)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS11)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS12)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS13)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS14)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS15)
+
+# GCONFIG_EXTRAS can be set on the command line.
+# Note that it consists of arguments for echogs, i.e.,
+# it isn't just literal text.
+GCONFIG_EXTRAS=
+
+ld_tr=ld$(CONFIG).tr
+$(gconfig_h) $(ld_tr) lib.tr: \
+ $(GS_MAK) $(MAKEFILE) version.mak $(GENCONF_XE) $(ECHOGS_XE) $(devs_tr) $(DEVS_ALL) libcore.dev
+ $(EXP)genconf $(devs_tr) libcore.dev -h $(gconfig_h) $(CONFILES)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_LIB_DEFAULT -x 2022 $(GS_LIB_DEFAULT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u SEARCH_HERE_FIRST -s $(SEARCH_HERE_FIRST)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_DOCDIR -x 2022 $(GS_DOCDIR) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_INIT -x 2022 $(GS_INIT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISION -s $(GS_REVISION)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISIONDATE -s $(GS_REVISIONDATE)
+ $(EXP)echogs -a $(gconfig_h) $(GCONFIG_EXTRAS)
+
+################################################################
+# The other platform-independent makefiles are concatenated
+# (or included) after this one:
+# lib.mak
+# int.mak
+# jpeg.mak
+# libpng.mak
+# zlib.mak
+# devs.mak
+################################################################
+# Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for graphics library and other support code.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+LIB_MAK=lib.mak
+
+# Define the inter-dependencies of the .h files.
+# Since not all versions of `make' defer expansion of macros,
+# we must list these in bottom-to-top order.
+
+# Generic files
+
+arch_h=arch.h
+stdpre_h=stdpre.h
+std_h=std.h $(arch_h) $(stdpre_h)
+
+# Platform interfaces
+
+gp_h=gp.h
+gpcheck_h=gpcheck.h
+gpsync_h=gpsync.h
+
+# Configuration definitions
+
+# gconfig*.h are generated dynamically.
+gconfig__h=gconfig_.h
+gconfigv_h=gconfigv.h
+gscdefs_h=gscdefs.h
+
+# C library interfaces
+
+# Because of variations in the "standard" header files between systems, and
+# because we must include std.h before any file that includes sys/types.h,
+# we define local include files named *_.h to substitute for <*.h>.
+
+vmsmath_h=vmsmath.h
+
+dos__h=dos_.h
+ctype__h=ctype_.h $(std_h)
+dirent__h=dirent_.h $(std_h) $(gconfig__h)
+errno__h=errno_.h $(std_h)
+malloc__h=malloc_.h $(std_h)
+math__h=math_.h $(std_h) $(vmsmath_h)
+memory__h=memory_.h $(std_h)
+stat__h=stat_.h $(std_h)
+stdio__h=stdio_.h $(std_h)
+string__h=string_.h $(std_h)
+time__h=time_.h $(std_h) $(gconfig__h)
+windows__h=windows_.h
+
+# Miscellaneous
+
+gdebug_h=gdebug.h
+gsalloc_h=gsalloc.h
+gsargs_h=gsargs.h
+gserror_h=gserror.h
+gserrors_h=gserrors.h
+gsexit_h=gsexit.h
+gsgc_h=gsgc.h
+gsio_h=gsio.h
+gsmdebug_h=gsmdebug.h
+gsmemraw_h=gsmemraw.h
+gsmemory_h=gsmemory.h $(gsmemraw_h)
+gsrefct_h=gsrefct.h
+gsstruct_h=gsstruct.h
+gstypes_h=gstypes.h
+gx_h=gx.h $(stdio__h) $(gdebug_h) $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
+
+GX=$(AK) $(gx_h)
+GXERR=$(GX) $(gserrors_h)
+
+###### Support
+
+### Include files
+
+gsbitmap_h=gsbitmap.h $(gsstruct_h)
+gsbitops_h=gsbitops.h
+gsbittab_h=gsbittab.h
+gsflip_h=gsflip.h
+gsuid_h=gsuid.h
+gsutil_h=gsutil.h
+gxarith_h=gxarith.h
+gxbitmap_h=gxbitmap.h $(gsbitmap_h) $(gstypes_h)
+gxfarith_h=gxfarith.h $(gconfigv_h) $(gxarith_h)
+gxfixed_h=gxfixed.h
+gxobj_h=gxobj.h $(gxbitmap_h)
+# Out of order
+gxalloc_h=gxalloc.h $(gsalloc_h) $(gxobj_h)
+
+### Executable code
+
+gsalloc.$(OBJ): gsalloc.c $(GX) $(memory__h) $(string__h) \
+ $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsargs.$(OBJ): gsargs.c $(ctype__h) $(stdio__h) $(string__h)\
+ $(gsargs_h) $(gsexit_h) $(gsmemory_h)
+
+gsbitops.$(OBJ): gsbitops.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gsbitops_h) $(gstypes_h)
+
+gsbittab.$(OBJ): gsbittab.c $(AK) $(stdpre_h) $(gsbittab_h)
+
+# gsfemu is only used in FPU-less configurations, and currently only with gcc.
+# We thought using CCLEAF would produce smaller code, but it actually
+# produces larger code!
+gsfemu.$(OBJ): gsfemu.c $(AK) $(std_h)
+
+# gsflip is not part of the standard configuration: it's rather large,
+# and no standard facility requires it.
+gsflip.$(OBJ): gsflip.c $(GX) $(gsbittab_h) $(gsflip_h)
+ $(CCLEAF) gsflip.c
+
+gsmemory.$(OBJ): gsmemory.c $(GX) $(malloc__h) $(memory__h) \
+ $(gsmdebug_h) $(gsrefct_h) $(gsstruct_h) $(gsmemraw_h)
+
+gsmisc.$(OBJ): gsmisc.c $(GXERR) $(gconfigv_h) \
+ $(malloc__h) $(math__h) $(memory__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h)
+
+# gsnogc currently is only used in library-only configurations.
+gsnogc.$(OBJ): gsnogc.c $(GX)\
+ $(gsgc_h) $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsutil.$(OBJ): gsutil.c $(AK) $(memory__h) $(string__h) $(gconfigv_h)\
+ $(gstypes_h) $(gsuid_h) $(gsutil_h)
+
+###### Low-level facilities and utilities
+
+### Include files
+
+gdevbbox_h=gdevbbox.h
+gdevmem_h=gdevmem.h $(gsbitops_h)
+gdevmrop_h=gdevmrop.h
+
+gsccode_h=gsccode.h
+gsccolor_h=gsccolor.h $(gsstruct_h)
+gscsel_h=gscsel.h
+gscolor1_h=gscolor1.h
+gscoord_h=gscoord.h
+gscpm_h=gscpm.h
+gsdevice_h=gsdevice.h
+gsfcmap_h=gsfcmap.h $(gsccode_h)
+gsfont_h=gsfont.h
+gshsb_h=gshsb.h
+gsht_h=gsht.h
+gsht1_h=gsht1.h $(gsht_h)
+gsiparam_h=gsiparam.h
+gsjconf_h=gsjconf.h $(std_h)
+gslib_h=gslib.h
+gslparam_h=gslparam.h
+gsmatrix_h=gsmatrix.h
+gspaint_h=gspaint.h
+gsparam_h=gsparam.h
+gsparams_h=gsparams.h $(gsparam_h)
+gspath2_h=gspath2.h
+gspenum_h=gspenum.h
+gsropt_h=gsropt.h
+gsxfont_h=gsxfont.h
+# Out of order
+gschar_h=gschar.h $(gsccode_h) $(gscpm_h)
+gscolor2_h=gscolor2.h $(gsccolor_h) $(gsuid_h) $(gxbitmap_h)
+gsimage_h=gsimage.h $(gsiparam_h)
+gsline_h=gsline.h $(gslparam_h)
+gspath_h=gspath.h $(gspenum_h)
+gsrop_h=gsrop.h $(gsropt_h)
+
+gxbcache_h=gxbcache.h $(gxbitmap_h)
+gxchar_h=gxchar.h $(gschar_h)
+gxcindex_h=gxcindex.h
+gxcvalue_h=gxcvalue.h
+gxclio_h=gxclio.h
+gxclip2_h=gxclip2.h
+gxcolor2_h=gxcolor2.h $(gscolor2_h) $(gsrefct_h) $(gxbitmap_h)
+gxcoord_h=gxcoord.h $(gscoord_h)
+gxcpath_h=gxcpath.h
+gxdda_h=gxdda.h
+gxdevrop_h=gxdevrop.h
+gxdevmem_h=gxdevmem.h
+gxdither_h=gxdither.h
+gxfcmap_h=gxfcmap.h $(gsfcmap_h) $(gsuid_h)
+gxfont0_h=gxfont0.h
+gxfrac_h=gxfrac.h
+gxftype_h=gxftype.h
+gxhttile_h=gxhttile.h
+gxhttype_h=gxhttype.h
+gxiodev_h=gxiodev.h $(stat__h)
+gxline_h=gxline.h $(gslparam_h)
+gxlum_h=gxlum.h
+gxmatrix_h=gxmatrix.h $(gsmatrix_h)
+gxpaint_h=gxpaint.h
+gxpath_h=gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h)
+gxpcache_h=gxpcache.h
+gxpcolor_h=gxpcolor.h $(gxpcache_h)
+gxsample_h=gxsample.h
+gxstate_h=gxstate.h
+gxtmap_h=gxtmap.h
+gxxfont_h=gxxfont.h $(gsccode_h) $(gsmatrix_h) $(gsuid_h) $(gsxfont_h)
+# The following are out of order because they include other files.
+gsdcolor_h=gsdcolor.h $(gsccolor_h) $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+gxdcolor_h=gxdcolor.h $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gxdevice_h=gxdevice.h $(stdio__h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h) \
+ $(gsropt_h) $(gsstruct_h) $(gsxfont_h) \
+ $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)
+gxdht_h=gxdht.h $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+gxctable_h=gxctable.h $(gxfixed_h) $(gxfrac_h)
+gxfcache_h=gxfcache.h $(gsuid_h) $(gsxfont_h) $(gxbcache_h) $(gxftype_h)
+gxfont_h=gxfont.h $(gsfont_h) $(gsuid_h) $(gsstruct_h) $(gxftype_h)
+gscie_h=gscie.h $(gsrefct_h) $(gxctable_h)
+gscsepr_h=gscsepr.h
+gscspace_h=gscspace.h
+gxdcconv_h=gxdcconv.h $(gxfrac_h)
+gxfmap_h=gxfmap.h $(gsrefct_h) $(gxfrac_h) $(gxtmap_h)
+gxistate_h=gxistate.h $(gscsel_h) $(gsropt_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+gxband_h=gxband.h $(gxclio_h)
+gxclist_h=gxclist.h $(gscspace_h) $(gxbcache_h) $(gxclio_h) $(gxistate_h) $(gxband_h)
+gxcmap_h=gxcmap.h $(gscsel_h) $(gxcvalue_h) $(gxfmap_h)
+gxcspace_h=gxcspace.h $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gsstruct_h) $(gxfrac_h)
+gxht_h=gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gscolor_h=gscolor.h $(gxtmap_h)
+gsstate_h=gsstate.h $(gscolor_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
+
+gzacpath_h=gzacpath.h
+gzcpath_h=gzcpath.h $(gxcpath_h)
+gzht_h=gzht.h $(gscsel_h) $(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
+gzline_h=gzline.h $(gxline_h)
+gzpath_h=gzpath.h $(gsstruct_h) $(gxpath_h)
+gzstate_h=gzstate.h $(gscpm_h) $(gsrefct_h) $(gsstate_h)\
+ $(gxdcolor_h) $(gxistate_h) $(gxstate_h)
+
+gdevprn_h=gdevprn.h $(memory__h) $(string__h) $(gx_h) \
+ $(gserrors_h) $(gsmatrix_h) $(gsparam_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxdevmem_h) $(gxclist_h)
+
+sa85x_h=sa85x.h
+sbtx_h=sbtx.h
+scanchar_h=scanchar.h
+scommon_h=scommon.h $(gsmemory_h) $(gstypes_h) $(gsstruct_h)
+sdct_h=sdct.h
+shc_h=shc.h $(gsbittab_h)
+siscale_h=siscale.h $(gconfigv_h)
+sjpeg_h=sjpeg.h
+slzwx_h=slzwx.h
+spcxx_h=spcxx.h
+spdiffx_h=spdiffx.h
+spngpx_h=spngpx.h
+srlx_h=srlx.h
+sstring_h=sstring.h
+strimpl_h=strimpl.h $(scommon_h) $(gstypes_h) $(gsstruct_h)
+szlibx_h=szlibx.h
+# Out of order
+scf_h=scf.h $(shc_h)
+scfx_h=scfx.h $(shc_h)
+gximage_h=gximage.h $(gsiparam_h) $(gxcspace_h) $(gxdda_h) $(gxsample_h)\
+ $(siscale_h) $(strimpl_h)
+
+### Executable code
+
+# gconfig and gscdefs are handled specially. Currently they go in psbase
+# rather than in libcore, which is clearly wrong.
+gconfig=gconfig$(CONFIG)
+$(gconfig).$(OBJ): gconf.c $(GX) \
+ $(gscdefs_h) $(gconfig_h) $(gxdevice_h) $(gxiodev_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gconf.c $(gconfig).c
+ $(CCC) $(gconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+
+gscdefs=gscdefs$(CONFIG)
+$(gscdefs).$(OBJ): gscdef.c $(stdpre_h) $(gscdefs_h) $(gconfig_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gscdef.c $(gscdefs).c
+ $(CCC) $(gscdefs).c
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+
+gxacpath.$(OBJ): gxacpath.c $(GXERR) \
+ $(gsdcolor_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxpaint_h) \
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)
+
+gxbcache.$(OBJ): gxbcache.c $(GX) $(memory__h) \
+ $(gsmdebug_h) $(gxbcache_h)
+
+gxccache.$(OBJ): gxccache.c $(GXERR) $(gpcheck_h) \
+ $(gscspace_h) $(gsimage_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxdevmem_h) $(gxfcache_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxhttile_h) $(gxmatrix_h) $(gxxfont_h) \
+ $(gzstate_h) $(gzpath_h) $(gzcpath_h)
+
+gxccman.$(OBJ): gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfont_h) $(gxfcache_h) $(gxchar_h)\
+ $(gxxfont_h) $(gzstate_h) $(gzpath_h)
+
+gxcht.$(OBJ): gxcht.c $(GXERR) $(memory__h)\
+ $(gsutil_h)\
+ $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h)\
+ $(gxmatrix_h) $(gzht_h)
+
+gxcmap.$(OBJ): gxcmap.c $(GXERR) \
+ $(gsccolor_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gxdither_h) \
+ $(gxfarith_h) $(gxfrac_h) $(gxlum_h) $(gzstate_h)
+
+gxcpath.$(OBJ): gxcpath.c $(GXERR)\
+ $(gscoord_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gzpath_h) $(gzcpath_h)
+
+gxdcconv.$(OBJ): gxdcconv.c $(GX) \
+ $(gsdcolor_h) $(gxcmap_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gxfarith_h) $(gxistate_h) $(gxlum_h)
+
+gxdcolor.$(OBJ): gxdcolor.c $(GX) \
+ $(gsbittab_h) $(gxdcolor_h) $(gxdevice_h)
+
+gxdither.$(OBJ): gxdither.c $(GX) \
+ $(gsstruct_h) $(gsdcolor_h) \
+ $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
+
+gxfill.$(OBJ): gxfill.c $(GXERR) $(math__h) \
+ $(gsstruct_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h) \
+ $(gxistate_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+gxht.$(OBJ): gxht.c $(GXERR) $(memory__h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+
+gximage.$(OBJ): gximage.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h) $(gsstruct_h)\
+ $(gxfixed_h) $(gxfrac_h) $(gxarith_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gzpath_h) $(gzstate_h)\
+ $(gzcpath_h) $(gxdevmem_h) $(gximage_h) $(gdevmrop_h)
+
+gximage0.$(OBJ): gximage0.c $(GXERR) $(memory__h)\
+ $(gxcpath_h) $(gxdevice_h) $(gximage_h)
+
+gximage1.$(OBJ): gximage1.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsbittab_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gximage2.$(OBJ): gximage2.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gxpaint.$(OBJ): gxpaint.c $(GX) \
+ $(gxdevice_h) $(gxhttile_h) $(gxpaint_h) $(gxpath_h) $(gzstate_h)
+
+gxpath.$(OBJ): gxpath.c $(GXERR) \
+ $(gsstruct_h) $(gxfixed_h) $(gzpath_h)
+
+gxpath2.$(OBJ): gxpath2.c $(GXERR) $(math__h) \
+ $(gxfixed_h) $(gxarith_h) $(gzpath_h)
+
+gxpcopy.$(OBJ): gxpcopy.c $(GXERR) $(math__h) $(gconfigv_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxpdash.$(OBJ): gxpdash.c $(GX) $(math__h) \
+ $(gscoord_h) $(gsline_h) $(gsmatrix_h) \
+ $(gxfixed_h) $(gzline_h) $(gzpath_h)
+
+gxpflat.$(OBJ): gxpflat.c $(GX)\
+ $(gxarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxsample.$(OBJ): gxsample.c $(GX)\
+ $(gxsample_h)
+
+gxstroke.$(OBJ): gxstroke.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gscoord_h) $(gsdcolor_h) $(gsdevice_h) \
+ $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) \
+ $(gxhttile_h) $(gxistate_h) $(gxmatrix_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzline_h) $(gzpath_h)
+
+###### Higher-level facilities
+
+gschar.$(OBJ): gschar.c $(GXERR) $(memory__h) $(string__h)\
+ $(gspath_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxarith_h) $(gxmatrix_h) $(gxcoord_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxfcache_h) $(gzpath_h) $(gzstate_h)
+
+gscolor.$(OBJ): gscolor.c $(GXERR) \
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
+
+gscoord.$(OBJ): gscoord.c $(GXERR) $(math__h) \
+ $(gsccode_h) $(gxcoord_h) $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) $(gxfont_h) \
+ $(gxmatrix_h) $(gxpath_h) $(gzstate_h)
+
+gsdevice.$(OBJ): gsdevice.c $(GXERR) $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
+ $(gscdefs_h) $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstruct_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gzstate_h)
+
+gsdevmem.$(OBJ): gsdevmem.c $(GXERR) $(math__h) $(memory__h) \
+ $(gxarith_h) $(gxdevice_h) $(gxdevmem_h)
+
+gsdparam.$(OBJ): gsdparam.c $(GXERR) $(memory__h) $(string__h) \
+ $(gsparam_h) $(gxdevice_h) $(gxfixed_h)
+
+gsfont.$(OBJ): gsfont.c $(GXERR) $(memory__h)\
+ $(gschar_h) $(gsstruct_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)
+
+gsht.$(OBJ): gsht.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gshtscr.$(OBJ): gshtscr.c $(GXERR) $(math__h) \
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gsimage.$(OBJ): gsimage.c $(GXERR) $(memory__h)\
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxdevice_h) $(gzstate_h)
+
+gsimpath.$(OBJ): gsimpath.c $(GXERR) \
+ $(gsmatrix_h) $(gsstate_h) $(gspath_h)
+
+gsinit.$(OBJ): gsinit.c $(memory__h) $(stdio__h) \
+ $(gdebug_h) $(gp_h) $(gscdefs_h) $(gslib_h) $(gsmemory_h)
+
+gsiodev.$(OBJ): gsiodev.c $(GXERR) $(errno__h) $(string__h) \
+ $(gp_h) $(gsparam_h) $(gxiodev_h)
+
+gsline.$(OBJ): gsline.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsline_h) $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gzline_h)
+
+gsmatrix.$(OBJ): gsmatrix.c $(GXERR) $(math__h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h)
+
+gspaint.$(OBJ): gspaint.c $(GXERR) $(math__h) $(gpcheck_h)\
+ $(gspaint_h) $(gspath_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdevmem_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxpaint_h)\
+ $(gzpath_h) $(gzstate_h)
+
+gsparam.$(OBJ): gsparam.c $(GXERR) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsstruct_h)
+
+gsparams.$(OBJ): gsparams.c $(gx_h) $(memory__h) $(gserrors_h) $(gsparam_h)
+
+gspath.$(OBJ): gspath.c $(GXERR) \
+ $(gscoord_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+gsstate.$(OBJ): gsstate.c $(GXERR) $(memory__h)\
+ $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h) \
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+
+###### The internal devices
+
+### The built-in device implementations:
+
+# The bounding box device is not normally a free-standing device.
+# To configure it as one for testing, change SETMOD to SETDEV, and also
+# define TEST in gdevbbox.c.
+bbox.dev: $(LIB_MAK) $(ECHOGS_XE) gdevbbox.$(OBJ)
+ $(SETMOD) bbox gdevbbox.$(OBJ)
+
+gdevbbox.$(OBJ): gdevbbox.c $(GXERR) $(math__h) $(memory__h) \
+ $(gdevbbox_h) $(gsdevice_h) $(gsparam_h) \
+ $(gxcpath_h) $(gxdevice_h) $(gxistate_h) $(gxpaint_h) $(gxpath_h)
+
+gdevddrw.$(OBJ): gdevddrw.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h)
+
+gdevdflt.$(OBJ): gdevdflt.c $(GXERR) $(gpcheck_h)\
+ $(gsbittab_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)
+
+gdevnfwd.$(OBJ): gdevnfwd.c $(GX) \
+ $(gxdevice_h)
+
+# The render/RGB device is only here as an example, but we can configure
+# it as a real device for testing.
+rrgb.dev: $(LIB_MAK) $(ECHOGS_XE) gdevrrgb.$(OBJ) page.dev
+ $(SETPDEV) rrgb gdevrrgb.$(OBJ)
+
+gdevrrgb.$(OBJ): gdevrrgb.c $(AK)\
+ $(gdevprn_h)
+
+### The memory devices:
+
+gdevabuf.$(OBJ): gdevabuf.c $(GXERR) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmem.$(OBJ): gdevmem.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm1.$(OBJ): gdevm1.c $(GX) $(memory__h) $(gsrop_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm2.$(OBJ): gdevm2.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm4.$(OBJ): gdevm4.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm8.$(OBJ): gdevm8.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm16.$(OBJ): gdevm16.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm24.$(OBJ): gdevm24.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm32.$(OBJ): gdevm32.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmpla.$(OBJ): gdevmpla.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+# Create a pseudo-"feature" for the entire graphics library.
+
+LIB1s=gsalloc.$(OBJ) gsbitops.$(OBJ) gsbittab.$(OBJ)
+LIB2s=gschar.$(OBJ) gscolor.$(OBJ) gscoord.$(OBJ) gsdevice.$(OBJ) gsdevmem.$(OBJ)
+LIB3s=gsdparam.$(OBJ) gsfont.$(OBJ) gsht.$(OBJ) gshtscr.$(OBJ)
+LIB4s=gsimage.$(OBJ) gsimpath.$(OBJ) gsinit.$(OBJ) gsiodev.$(OBJ)
+LIB5s=gsline.$(OBJ) gsmatrix.$(OBJ) gsmemory.$(OBJ) gsmisc.$(OBJ)
+LIB6s=gspaint.$(OBJ) gsparam.$(OBJ) gsparams.$(OBJ) gspath.$(OBJ) gsstate.$(OBJ) gsutil.$(OBJ)
+LIB1x=gxacpath.$(OBJ) gxbcache.$(OBJ)
+LIB2x=gxccache.$(OBJ) gxccman.$(OBJ) gxcht.$(OBJ) gxcmap.$(OBJ) gxcpath.$(OBJ)
+LIB3x=gxdcconv.$(OBJ) gxdcolor.$(OBJ) gxdither.$(OBJ) gxfill.$(OBJ) gxht.$(OBJ)
+LIB4x=gximage.$(OBJ) gximage0.$(OBJ) gximage1.$(OBJ) gximage2.$(OBJ)
+LIB5x=gxpaint.$(OBJ) gxpath.$(OBJ) gxpath2.$(OBJ) gxpcopy.$(OBJ)
+LIB6x=gxpdash.$(OBJ) gxpflat.$(OBJ) gxsample.$(OBJ) gxstroke.$(OBJ)
+LIB1d=gdevabuf.$(OBJ) gdevddrw.$(OBJ) gdevdflt.$(OBJ) gdevnfwd.$(OBJ)
+LIB2d=gdevmem.$(OBJ) gdevm1.$(OBJ) gdevm2.$(OBJ) gdevm4.$(OBJ) gdevm8.$(OBJ)
+LIB3d=gdevm16.$(OBJ) gdevm24.$(OBJ) gdevm32.$(OBJ) gdevmpla.$(OBJ)
+LIBs=$(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s)
+LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d)
+LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
+libs.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBs)
+ $(EXP)echogs -w libs.dev $(LIB1s)
+ $(EXP)echogs -a libs.dev $(LIB2s)
+ $(EXP)echogs -a libs.dev $(LIB3s)
+ $(EXP)echogs -a libs.dev $(LIB4s)
+ $(EXP)echogs -a libs.dev $(LIB5s)
+ $(EXP)echogs -a libs.dev $(LIB6s)
+ $(ADDMOD) libs -init gscolor
+
+libx.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBx)
+ $(EXP)echogs -w libx.dev $(LIB1x)
+ $(EXP)echogs -a libx.dev $(LIB2x)
+ $(EXP)echogs -a libx.dev $(LIB3x)
+ $(EXP)echogs -a libx.dev $(LIB4x)
+ $(EXP)echogs -a libx.dev $(LIB5x)
+ $(EXP)echogs -a libx.dev $(LIB6x)
+ $(ADDMOD) libx -init gximage1 gximage2
+
+libd.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBd)
+ $(EXP)echogs -w libd.dev $(LIB1d)
+ $(EXP)echogs -a libd.dev $(LIB2d)
+ $(EXP)echogs -a libd.dev $(LIB3d)
+
+# roplib shouldn't be required....
+libcore.dev: $(LIB_MAK) $(ECHOGS_XE)\
+ libs.dev libx.dev libd.dev iscale.dev roplib.dev
+ $(SETMOD) libcore
+ $(ADDMOD) libcore -dev nullpage
+ $(ADDMOD) libcore -include libs libx libd iscale roplib
+
+# ---------------- Stream support ---------------- #
+# Currently the only things in the library that use this are clists
+# and file streams.
+
+stream_h=stream.h $(scommon_h)
+
+stream.$(OBJ): stream.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+# ---------------- File streams ---------------- #
+# Currently only the high-level drivers use these, but more drivers will
+# probably use them eventually.
+
+sfile_=sfx$(FILE_IMPLEMENTATION).$(OBJ) stream.$(OBJ)
+sfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(sfile_)
+ $(SETMOD) sfile $(sfile_)
+
+sfxstdio.$(OBJ): sfxstdio.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxfd.$(OBJ): sfxfd.c $(AK) $(stdio__h) $(errno__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxboth.$(OBJ): sfxboth.c sfxstdio.c sfxfd.c
+
+# ---------------- CCITTFax filters ---------------- #
+# These are used by clists, some drivers, and Level 2 in general.
+
+cfe_=scfe.$(OBJ) scfetab.$(OBJ) shc.$(OBJ)
+cfe.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfe_)
+ $(SETMOD) cfe $(cfe_)
+
+scfe.$(OBJ): scfe.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfetab.$(OBJ): scfetab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+shc.$(OBJ): shc.c $(AK) $(std_h) $(scommon_h) $(shc_h)
+
+cfd_=scfd.$(OBJ) scfdtab.$(OBJ)
+cfd.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfd_)
+ $(SETMOD) cfd $(cfd_)
+
+scfd.$(OBJ): scfd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfdtab.$(OBJ): scfdtab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+# ---------------- DCT (JPEG) filters ---------------- #
+# These are used by Level 2, and by the JPEG-writing driver.
+
+# Common code
+
+sdctc_=sdctc.$(OBJ) sjpegc.$(OBJ)
+
+sdctc.$(OBJ): sdctc.c $(AK) $(stdio__h)\
+ $(sdct_h) $(strimpl_h)\
+ jpeglib.h
+
+sjpegc.$(OBJ): sjpegc.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Encoding (compression)
+
+sdcte_=$(sdctc_) sdcte.$(OBJ) sjpege.$(OBJ)
+sdcte.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdcte_) jpege.dev
+ $(SETMOD) sdcte $(sdcte_)
+ $(ADDMOD) sdcte -include jpege
+
+sdcte.$(OBJ): sdcte.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpege.$(OBJ): sjpege.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Decoding (decompression)
+
+sdctd_=$(sdctc_) sdctd.$(OBJ) sjpegd.$(OBJ)
+sdctd.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdctd_) jpegd.dev
+ $(SETMOD) sdctd $(sdctd_)
+ $(ADDMOD) sdctd -include jpegd
+
+sdctd.$(OBJ): sdctd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpegd.$(OBJ): sjpegd.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h)\
+ jerror.h jpeglib.h
+
+# ---------------- LZW filters ---------------- #
+# These are used by Level 2 in general.
+
+slzwe_=slzwce
+#slzwe_=slzwe
+lzwe_=$(slzwe_).$(OBJ) slzwc.$(OBJ)
+lzwe.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwe_)
+ $(SETMOD) lzwe $(lzwe_)
+
+# We need slzwe.dev as a synonym for lzwe.dev for BAND_LIST_STORAGE = memory.
+slzwe.dev: lzwe.dev
+ $(CP_) lzwe.dev slzwe.dev
+
+slzwce.$(OBJ): slzwce.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwe.$(OBJ): slzwe.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwc.$(OBJ): slzwc.c $(AK) $(std_h)\
+ $(slzwx_h) $(strimpl_h)
+
+lzwd_=slzwd.$(OBJ) slzwc.$(OBJ)
+lzwd.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwd_)
+ $(SETMOD) lzwd $(lzwd_)
+
+# We need slzwd.dev as a synonym for lzwd.dev for BAND_LIST_STORAGE = memory.
+slzwd.dev: lzwd.dev
+ $(CP_) lzwd.dev slzwd.dev
+
+slzwd.$(OBJ): slzwd.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+# ---------------- PCX decoding filter ---------------- #
+# This is an adhoc filter not used by anything in the standard configuration.
+
+pcxd_=spcxd.$(OBJ)
+pcxd.dev: $(LIB_MAK) $(ECHOGS_XE) $(pcxd_)
+ $(SETMOD) pcxd $(pcxd_)
+
+spcxd.$(OBJ): spcxd.c $(AK) $(stdio__h) $(memory__h) \
+ $(spcxx_h) $(strimpl_h)
+
+# ---------------- Pixel-difference filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pdiff_=spdiff.$(OBJ)
+pdiff.dev: $(LIB_MAK) $(ECHOGS_XE) $(pdiff_)
+ $(SETMOD) pdiff $(pdiff_)
+
+spdiff.$(OBJ): spdiff.c $(AK) $(stdio__h)\
+ $(spdiffx_h) $(strimpl_h)
+
+# ---------------- PNG pixel prediction filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pngp_=spngp.$(OBJ)
+pngp.dev: $(LIB_MAK) $(ECHOGS_XE) $(pngp_)
+ $(SETMOD) pngp $(pngp_)
+
+spngp.$(OBJ): spngp.c $(AK) $(memory__h)\
+ $(spngpx_h) $(strimpl_h)
+
+# ---------------- RunLength filters ---------------- #
+# These are used by clists and also by Level 2 in general.
+
+rle_=srle.$(OBJ)
+rle.dev: $(LIB_MAK) $(ECHOGS_XE) $(rle_)
+ $(SETMOD) rle $(rle_)
+
+srle.$(OBJ): srle.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+rld_=srld.$(OBJ)
+rld.dev: $(LIB_MAK) $(ECHOGS_XE) $(rld_)
+ $(SETMOD) rld $(rld_)
+
+srld.$(OBJ): srld.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+# ---------------- String encoding/decoding filters ---------------- #
+# These are used by the PostScript and PDF writers, and also by the
+# PostScript interpreter.
+
+scantab.$(OBJ): scantab.c $(AK) $(stdpre_h)\
+ $(scanchar_h) $(scommon_h)
+
+sfilter2.$(OBJ): sfilter2.c $(AK) $(memory__h) $(stdio__h)\
+ $(sa85x_h) $(scanchar_h) $(sbtx_h) $(strimpl_h)
+
+sstring.$(OBJ): sstring.c $(AK) $(stdio__h) $(memory__h) $(string__h)\
+ $(scanchar_h) $(sstring_h) $(strimpl_h)
+
+# ---------------- zlib filters ---------------- #
+# These are used by clists and are also available as filters.
+
+szlibc_=szlibc.$(OBJ)
+
+szlibc.$(OBJ): szlibc.c $(AK) $(std_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibc.c
+
+szlibe_=$(szlibc_) szlibe.$(OBJ)
+szlibe.dev: $(LIB_MAK) $(ECHOGS_XE) zlibe.dev $(szlibe_)
+ $(SETMOD) szlibe $(szlibe_)
+ $(ADDMOD) szlibe -include zlibe
+
+szlibe.$(OBJ): szlibe.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibe.c
+
+szlibd_=$(szlibc_) szlibd.$(OBJ)
+szlibd.dev: $(LIB_MAK) $(ECHOGS_XE) zlibd.dev $(szlibd_)
+ $(SETMOD) szlibd $(szlibd_)
+ $(ADDMOD) szlibd -include zlibd
+
+szlibd.$(OBJ): szlibd.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibd.c
+
+# ---------------- Command lists ---------------- #
+
+gxcldev_h=gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
+ $(strimpl_h) $(scfx_h) $(srlx_h)
+gxclpage_h=gxclpage.h $(gxclio_h)
+gxclpath_h=gxclpath.h $(gxfixed_h)
+
+# Command list package. Currently the higher-level facilities are required,
+# but eventually they will be optional.
+clist.dev: $(LIB_MAK) $(ECHOGS_XE) clbase.dev clpath.dev
+ $(SETMOD) clist -include clbase clpath
+
+# Base command list facility.
+clbase1_=gxclist.$(OBJ) gxclbits.$(OBJ) gxclpage.$(OBJ)
+clbase2_=gxclread.$(OBJ) gxclrect.$(OBJ) stream.$(OBJ)
+clbase_=$(clbase1_) $(clbase2_)
+clbase.dev: $(LIB_MAK) $(ECHOGS_XE) $(clbase_) cl$(BAND_LIST_STORAGE).dev \
+ cfe.dev cfd.dev rle.dev rld.dev
+ $(SETMOD) clbase $(clbase1_)
+ $(ADDMOD) clbase -obj $(clbase2_)
+ $(ADDMOD) clbase -include cl$(BAND_LIST_STORAGE) cfe cfd rle rld
+
+gdevht_h=gdevht.h $(gzht_h)
+
+gdevht.$(OBJ): gdevht.c $(GXERR) \
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+
+gxclist.$(OBJ): gxclist.c $(GXERR) $(memory__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)
+
+gxclbits.$(OBJ): gxclbits.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h)
+
+gxclpage.$(OBJ): gxclpage.c $(AK)\
+ $(gdevprn_h) $(gxcldev_h) $(gxclpage_h)
+
+# (gxclread shouldn't need gxclpath.h)
+gxclread.$(OBJ): gxclread.c $(GXERR) $(memory__h) $(gp_h) $(gpcheck_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscoord_h) $(gsdevice_h) $(gsstate_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcspace_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)\
+ $(gxhttile_h) $(gxpaint_h) $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h)
+
+gxclrect.$(OBJ): gxclrect.c $(GXERR)\
+ $(gsutil_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h)
+
+# Higher-level command list facilities.
+clpath_=gxclimag.$(OBJ) gxclpath.$(OBJ)
+clpath.dev: $(LIB_MAK) $(ECHOGS_XE) $(clpath_) psl2cs.dev
+ $(SETMOD) clpath $(clpath_)
+ $(ADDMOD) clpath -include psl2cs
+ $(ADDMOD) clpath -init climag clpath
+
+gxclimag.$(OBJ): gxclimag.c $(GXERR) $(math__h) $(memory__h)\
+ $(gscspace_h)\
+ $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpath_h) $(gxfmap_h)\
+ $(siscale_h) $(strimpl_h)
+
+gxclpath.$(OBJ): gxclpath.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcolor2_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+# Implement band lists on files.
+
+clfile_=gxclfile.$(OBJ)
+clfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
+ $(SETMOD) clfile $(clfile_)
+
+gxclfile.$(OBJ): gxclfile.c $(stdio__h) $(string__h) \
+ $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
+
+# Implement band lists in memory (RAM).
+
+clmemory_=gxclmem.$(OBJ) gxcl$(BAND_LIST_COMPRESSOR).$(OBJ)
+clmemory.dev: $(LIB_MAK) $(ECHOGS_XE) $(clmemory_) s$(BAND_LIST_COMPRESSOR)e.dev s$(BAND_LIST_COMPRESSOR)d.dev
+ $(SETMOD) clmemory $(clmemory_)
+ $(ADDMOD) clmemory -include s$(BAND_LIST_COMPRESSOR)e s$(BAND_LIST_COMPRESSOR)d
+ $(ADDMOD) clmemory -init cl_$(BAND_LIST_COMPRESSOR)
+
+gxclmem_h=gxclmem.h $(gxclio_h) $(strimpl_h)
+
+gxclmem.$(OBJ): gxclmem.c $(GXERR) $(LIB_MAK) $(memory__h) \
+ $(gxclmem_h)
+
+# Implement the compression method for RAM-based band lists.
+
+gxcllzw.$(OBJ): gxcllzw.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(slzwx_h)
+
+gxclzlib.$(OBJ): gxclzlib.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(szlibx_h)
+ $(CCCZ) gxclzlib.c
+
+# ---------------- Page devices ---------------- #
+# We include this here, rather than in devs.mak, because it is more like
+# a feature than a simple device.
+
+page_=gdevprn.$(OBJ)
+page.dev: $(LIB_MAK) $(ECHOGS_XE) $(page_) clist.dev
+ $(SETMOD) page $(page_)
+ $(ADDMOD) page -include clist
+
+gdevprn.$(OBJ): gdevprn.c $(ctype__h) \
+ $(gdevprn_h) $(gp_h) $(gsparam_h) $(gxclio_h)
+
+# ---------------- Vector devices ---------------- #
+# We include this here for the same reasons as page.dev.
+
+gdevvec_h=gdevvec.h $(gdevbbox_h) $(gsropt_h) $(gxdevice_h) $(gxistate_h) $(stream_h)
+
+vector_=gdevvec.$(OBJ)
+vector.dev: $(LIB_MAK) $(ECHOGS_XE) $(vector_) bbox.dev sfile.dev
+ $(SETMOD) vector $(vector_)
+ $(ADDMOD) vector -include bbox sfile
+
+gdevvec.$(OBJ): gdevvec.c $(GXERR) $(math__h) $(memory__h) $(string__h)\
+ $(gdevvec_h) $(gp_h) $(gscspace_h) $(gsparam_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxfixed_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+# ---------------- Image scaling filter ---------------- #
+
+iscale_=siscale.$(OBJ)
+iscale.dev: $(LIB_MAK) $(ECHOGS_XE) $(iscale_)
+ $(SETMOD) iscale $(iscale_)
+
+siscale.$(OBJ): siscale.c $(AK) $(math__h) $(memory__h) $(stdio__h) \
+ $(siscale_h) $(strimpl_h)
+
+# ---------------- RasterOp et al ---------------- #
+# Currently this module is required, but it should be optional.
+
+roplib_=gdevmrop.$(OBJ) gsrop.$(OBJ) gsroptab.$(OBJ)
+roplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(roplib_)
+ $(SETMOD) roplib $(roplib_)
+ $(ADDMOD) roplib -init roplib
+
+gdevrun.$(OBJ): gdevrun.c $(GXERR) $(memory__h) \
+ $(gxdevice_h) $(gxdevmem_h)
+
+gdevmrop.$(OBJ): gdevmrop.c $(GXERR) $(memory__h) \
+ $(gsbittab_h) $(gsropt_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) \
+ $(gdevmrop_h)
+
+gsrop.$(OBJ): gsrop.c $(GXERR) \
+ $(gsrop_h) $(gzstate_h)
+
+gsroptab.$(OBJ): gsroptab.c $(stdpre_h) $(gsropt_h)
+ $(CCLEAF) gsroptab.c
+
+# ---------------- Async rendering ---------------- #
+
+gsmemfix_h=gsmemfix.h $(gsmemraw_h)
+gxsync_h=gxsync.h $(gpsync_h) $(gsmemory_h)
+gxpageq_h=gxpageq.h $(gsmemory_h) $(gxband_h) $(gxsync_h)
+gsmemlok_h=gsmemlok.h $(gsmemory_h) $(gxsync_h)
+gdevprna_h=gdevprna.h $(gdevprn_h) $(gxsync_h)
+
+async_=gdevprna.$(OBJ) gxsync.$(OBJ) gxpageq.$(OBJ) gsmemlok.$(OBJ)\
+ gsmemfix.$(OBJ)
+async.dev: $(INT_MAK) $(ECHOGS_XE) $(async_) clist.dev
+ $(SETMOD) async $(async_)
+
+gdevprna.$(OBJ): gdevprna.c $(AK) $(ctype__h) $(gdevprna_h) $(gsparam_h)\
+ $(gsdevice_h) $(gxcldev_h) $(gxclpath_h) $(gxpageq_h) $(gsmemory_h)\
+ $(gsmemlok_h) $(gsmemfix_h)
+
+gsmemfix.$(OBJ): gsmemfix.c $(AK) $(memory__h) $(gsmemraw_h) $(gsmemfix_h)
+
+gxsync.$(OBJ): gxsync.c $(AK) $(gxsync_h) $(memory__h) $(gx_h) $(gserrors_h)\
+ $(gsmemory_h)
+
+gxpageq.$(OBJ): gxpageq.c $(GXERR) $(gxdevice_h) $(gxclist_h)\
+ $(gxpageq_h) $(gserrors_h)
+
+gsmemlok.$(OBJ): gsmemlok.c $(GXERR) $(gsmemlok_h) $(gserrors_h)
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+cmaplib_=gsfcmap.$(OBJ)
+cmaplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmaplib_)
+ $(SETMOD) cmaplib $(cmaplib_)
+
+gsfcmap.$(OBJ): gsfcmap.c $(GXERR)\
+ $(gsstruct_h) $(gxfcmap_h)
+
+psf0lib_=gschar0.$(OBJ) gsfont0.$(OBJ)
+psf0lib.dev: $(LIB_MAK) $(ECHOGS_XE) cmaplib.dev $(psf0lib_)
+ $(SETMOD) psf0lib $(psf0lib_)
+ $(ADDMOD) psf0lib -include cmaplib
+
+gschar0.$(OBJ): gschar0.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxfixed_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gsfcmap_h) $(gxfont_h) $(gxfont0_h) $(gxchar_h)
+
+gsfont0.$(OBJ): gsfont0.c $(GXERR) $(memory__h)\
+ $(gsmatrix_h) $(gsstruct_h) $(gxfixed_h) $(gxdevmem_h) $(gxfcache_h)\
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxdevice_h)
+
+# ---------------- Pattern color ---------------- #
+
+patlib_=gspcolor.$(OBJ) gxclip2.$(OBJ) gxpcmap.$(OBJ)
+patlib.dev: $(LIB_MAK) $(ECHOGS_XE) cmyklib.dev psl2cs.dev $(patlib_)
+ $(SETMOD) patlib -include cmyklib psl2cs
+ $(ADDMOD) patlib -obj $(patlib_)
+
+gspcolor.$(OBJ): gspcolor.c $(GXERR) $(math__h) \
+ $(gsimage_h) $(gspath_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcoord_h) $(gxclip2_h) $(gxcspace_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfixed_h) $(gxmatrix_h) $(gxpath_h) $(gxpcolor_h) $(gzstate_h)
+
+gxclip2.$(OBJ): gxclip2.c $(GXERR) $(memory__h) \
+ $(gsstruct_h) $(gxclip2_h) $(gxdevice_h) $(gxdevmem_h)
+
+gxpcmap.$(OBJ): gxpcmap.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h)\
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1lib_=gxtype1.$(OBJ) gxhint1.$(OBJ) gxhint2.$(OBJ) gxhint3.$(OBJ)
+
+gscrypt1_h=gscrypt1.h
+gstype1_h=gstype1.h
+gxfont1_h=gxfont1.h
+gxop1_h=gxop1.h
+gxtype1_h=gxtype1.h $(gscrypt1_h) $(gstype1_h) $(gxop1_h)
+
+gxtype1.$(OBJ): gxtype1.c $(GXERR) $(math__h)\
+ $(gsccode_h) $(gsline_h) $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+gxhint1.$(OBJ): gxhint1.c $(GXERR)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint2.$(OBJ): gxhint2.c $(GXERR) $(memory__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint3.$(OBJ): gxhint3.c $(GXERR) $(math__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 1 charstrings
+
+psf1lib_=gstype1.$(OBJ)
+psf1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf1lib_) $(type1lib_)
+ $(SETMOD) psf1lib $(psf1lib_)
+ $(ADDMOD) psf1lib $(type1lib_)
+ $(ADDMOD) psf1lib -init gstype1
+
+gstype1.$(OBJ): gstype1.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 2 charstrings
+
+psf2lib_=gstype2.$(OBJ)
+psf2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf2lib_) $(type1lib_)
+ $(SETMOD) psf2lib $(psf2lib_)
+ $(ADDMOD) psf2lib $(type1lib_)
+ $(ADDMOD) psf2lib -init gstype2
+
+gstype2.$(OBJ): gstype2.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+ttflib_=gstype42.$(OBJ)
+ttflib.dev: $(LIB_MAK) $(ECHOGS_XE) $(ttflib_)
+ $(SETMOD) ttflib $(ttflib_)
+
+gxfont42_h=gxfont42.h
+
+gstype42.$(OBJ): gstype42.c $(GXERR) $(memory__h) \
+ $(gsccode_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont42_h) $(gxistate_h) $(gxpath_h)
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+cmyklib_=gscolor1.$(OBJ) gsht1.$(OBJ)
+cmyklib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmyklib_)
+ $(SETMOD) cmyklib $(cmyklib_)
+ $(ADDMOD) cmyklib -init gscolor1
+
+gscolor1.$(OBJ): gscolor1.c $(GXERR) \
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gzstate_h)
+
+gsht1.$(OBJ): gsht1.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+colimlib_=gximage3.$(OBJ)
+colimlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(colimlib_)
+ $(SETMOD) colimlib $(colimlib_)
+ $(ADDMOD) colimlib -init gximage3
+
+gximage3.$(OBJ): gximage3.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcconv_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h)\
+ $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzpath_h) $(gzstate_h)
+
+# ---------------- HSB color ---------------- #
+
+hsblib_=gshsb.$(OBJ)
+hsblib.dev: $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
+ $(SETMOD) hsblib $(hsblib_)
+
+gshsb.$(OBJ): gshsb.c $(GX) \
+ $(gscolor_h) $(gshsb_h) $(gxfrac_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1lib_=gspath1.$(OBJ)
+path1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(path1lib_)
+ $(SETMOD) path1lib $(path1lib_)
+
+gspath1.$(OBJ): gspath1.c $(GXERR) $(math__h) \
+ $(gscoord_h) $(gspath_h) $(gsstruct_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) $(gzpath_h)
+
+# --------------- Level 2 color space and color image support --------------- #
+
+psl2cs_=gscolor2.$(OBJ)
+psl2cs.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2cs_)
+ $(SETMOD) psl2cs $(psl2cs_)
+
+gscolor2.$(OBJ): gscolor2.c $(GXERR) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h)
+
+psl2lib_=gximage4.$(OBJ) gximage5.$(OBJ)
+psl2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2lib_) colimlib.dev psl2cs.dev
+ $(SETMOD) psl2lib $(psl2lib_)
+ $(ADDMOD) psl2lib -init gximage4 gximage5
+ $(ADDMOD) psl2lib -include colimlib psl2cs
+
+gximage4.$(OBJ): gximage4.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+gximage5.$(OBJ): gximage5.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+# ---------------- Display Postscript / Level 2 support ---------------- #
+
+dps2lib_=gsdps1.$(OBJ)
+dps2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dps2lib_)
+ $(SETMOD) dps2lib $(dps2lib_)
+
+gsdps1.$(OBJ): gsdps1.c $(GXERR) $(math__h)\
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gspath2_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- Display Postscript extensions ---------------- #
+
+gsdps_h=gsdps.h
+
+dpslib_=gsdps.$(OBJ)
+dpslib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dpslib_)
+ $(SETMOD) dpslib $(dpslib_)
+
+gsdps.$(OBJ): gsdps.c $(GX) $(gsdps_h)\
+ $(gsdps_h) $(gspath_h) $(gxdevice_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- CIE color ---------------- #
+
+cielib_=gscie.$(OBJ) gxctable.$(OBJ)
+cielib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cielib_)
+ $(SETMOD) cielib $(cielib_)
+
+gscie.$(OBJ): gscie.c $(GXERR) $(math__h) \
+ $(gscie_h) $(gscolor2_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gzstate_h)
+
+gxctable.$(OBJ): gxctable.c $(GX) \
+ $(gxfixed_h) $(gxfrac_h) $(gxctable_h)
+
+# ---------------- Separation colors ---------------- #
+
+seprlib_=gscsepr.$(OBJ)
+seprlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(seprlib_)
+ $(SETMOD) seprlib $(seprlib_)
+
+gscsepr.$(OBJ): gscsepr.c $(GXERR)\
+ $(gscsepr_h) $(gsmatrix_h) $(gsrefct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+
+# ---------------- Functions ---------------- #
+
+gsdsrc_h=gsdsrc.h $(gsstruct_h)
+gsfunc_h=gsfunc.h
+gsfunc0_h=gsfunc0.h $(gsdsrc_h) $(gsfunc_h)
+gxfunc_h=gxfunc.h $(gsfunc_h) $(gsstruct_h)
+
+# Generic support, and FunctionType 0.
+funclib_=gsdsrc.$(OBJ) gsfunc.$(OBJ) gsfunc0.$(OBJ)
+funclib.dev: $(LIB_MAK) $(ECHOGS_XE) $(funclib_)
+ $(SETMOD) funclib $(funclib_)
+
+gsdsrc.$(OBJ): gsdsrc.c $(GX) $(memory__h)\
+ $(gsdsrc_h) $(gserrors_h) $(stream_h)
+
+gsfunc.$(OBJ): gsfunc.c $(GX)\
+ $(gserrors_h) $(gxfunc_h)
+
+gsfunc0.$(OBJ): gsfunc0.c $(GX) $(math__h)\
+ $(gserrors_h) $(gsfunc0_h) $(gxfunc_h)
+
+# ----------------------- Platform-specific modules ----------------------- #
+# Platform-specific code doesn't really belong here: this is code that is
+# shared among multiple platforms.
+
+# Frame buffer implementations.
+
+gp_nofb.$(OBJ): gp_nofb.c $(GX) \
+ $(gp_h) $(gxdevice_h)
+
+gp_dosfb.$(OBJ): gp_dosfb.c $(AK) $(malloc__h) $(memory__h)\
+ $(gx_h) $(gp_h) $(gserrors_h) $(gxdevice_h)
+
+# MS-DOS file system, also used by Desqview/X.
+gp_dosfs.$(OBJ): gp_dosfs.c $(AK) $(dos__h) $(gp_h) $(gx_h)
+
+# MS-DOS file enumeration, *not* used by Desqview/X.
+gp_dosfe.$(OBJ): gp_dosfe.c $(AK) $(stdio__h) $(memory__h) $(string__h) \
+ $(dos__h) $(gstypes_h) $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h)
+
+# Other MS-DOS facilities.
+gp_msdos.$(OBJ): gp_msdos.c $(AK) $(dos__h) $(stdio__h) $(string__h)\
+ $(gsmemory_h) $(gstypes_h) $(gp_h)
+
+# Unix(-like) file system, also used by Desqview/X.
+gp_unifs.$(OBJ): gp_unifs.c $(AK) $(memory__h) $(string__h) $(gx_h) $(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+
+# Unix(-like) file name syntax, *not* used by Desqview/X.
+gp_unifn.$(OBJ): gp_unifn.c $(AK) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+# Main program for library testing
+
+gslib.$(OBJ): gslib.c $(AK) $(math__h) \
+ $(gx_h) $(gp_h) $(gserrors_h) $(gsmatrix_h) $(gsstate_h) $(gscspace_h) \
+ $(gscdefs_h) $(gscolor2_h) $(gscoord_h) $(gslib_h) $(gsparam_h) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxalloc_h) $(gxdevice_h)
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for language interpreters.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+INT_MAK=int.mak
+
+# ======================== Interpreter support ======================== #
+
+# This is support code for all interpreters, not just PostScript and PDF.
+# It knows about the PostScript data types, but isn't supposed to
+# depend on anything outside itself.
+
+errors_h=errors.h
+idebug_h=idebug.h
+idict_h=idict.h
+igc_h=igc.h
+igcstr_h=igcstr.h
+iname_h=iname.h
+inamedef_h=inamedef.h $(gconfigv_h) $(iname_h)
+ipacked_h=ipacked.h
+iref_h=iref.h
+isave_h=isave.h
+isstate_h=isstate.h
+istruct_h=istruct.h $(gsstruct_h)
+iutil_h=iutil.h
+ivmspace_h=ivmspace.h $(gsgc_h)
+opdef_h=opdef.h
+# Nested include files
+ghost_h=ghost.h $(gx_h) $(iref_h)
+imemory_h=imemory.h $(gsalloc_h) $(ivmspace_h)
+ialloc_h=ialloc.h $(imemory_h)
+iastruct_h=iastruct.h $(gxobj_h) $(ialloc_h)
+iastate_h=iastate.h $(gxalloc_h) $(ialloc_h) $(istruct_h)
+store_h=store.h $(ialloc_h)
+
+GH=$(AK) $(ghost_h)
+
+isupport1_=ialloc.$(OBJ) igc.$(OBJ) igcref.$(OBJ) igcstr.$(OBJ)
+isupport2_=ilocate.$(OBJ) iname.$(OBJ) isave.$(OBJ)
+isupport_=$(isupport1_) $(isupport2_)
+isupport.dev: $(INT_MAK) $(ECHOGS_XE) $(isupport_)
+ $(SETMOD) isupport $(isupport1_)
+ $(ADDMOD) isupport -obj $(isupport2_)
+ $(ADDMOD) isupport -init igcref
+
+ialloc.$(OBJ): ialloc.c $(AK) $(memory__h) $(gx_h)\
+ $(errors_h) $(gsstruct_h) $(gxarith_h)\
+ $(iastate_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+# igc.c, igcref.c, and igcstr.c should really be in the dpsand2 list,
+# but since all the GC enumeration and relocation routines refer to them,
+# it's too hard to separate them out from the Level 1 base.
+igc.$(OBJ): igc.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsmdebug_h) $(gsstruct_h) $(gsutil_h) \
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(inamedef_h) \
+ $(ipacked_h) $(isave_h) $(isstate_h) $(istruct_h) $(opdef_h)
+
+igcref.$(OBJ): igcref.c $(GH) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idebug_h) $(igc_h) $(iname_h) $(ipacked_h) $(store_h)
+
+igcstr.$(OBJ): igcstr.c $(GH) $(memory__h)\
+ $(gsmdebug_h) $(gsstruct_h) $(iastate_h) $(igcstr_h)
+
+ilocate.$(OBJ): ilocate.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(iname_h)\
+ $(ipacked_h) $(isstate_h) $(iutil_h) $(ivmspace_h)\
+ $(store_h)
+
+iname.$(OBJ): iname.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h) $(gxobj_h)\
+ $(errors_h) $(imemory_h) $(inamedef_h) $(isave_h) $(store_h)
+
+isave.$(OBJ): isave.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h) $(gsutil_h)\
+ $(iastate_h) $(inamedef_h) $(isave_h) $(isstate_h) $(ivmspace_h)\
+ $(ipacked_h) $(store_h)
+
+### Include files
+
+idparam_h=idparam.h
+ilevel_h=ilevel.h
+iparam_h=iparam.h $(gsparam_h)
+istack_h=istack.h
+iutil2_h=iutil2.h
+opcheck_h=opcheck.h
+opextern_h=opextern.h
+# Nested include files
+dstack_h=dstack.h $(istack_h)
+estack_h=estack.h $(istack_h)
+ostack_h=ostack.h $(istack_h)
+oper_h=oper.h $(iutil_h) $(opcheck_h) $(opdef_h) $(opextern_h) $(ostack_h)
+
+idebug.$(OBJ): idebug.c $(GH) $(string__h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(ostack_h) $(opdef_h) $(ipacked_h) $(store_h)
+
+idict.$(OBJ): idict.c $(GH) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idebug_h) $(ivmspace_h) $(inamedef_h) $(ipacked_h)\
+ $(isave_h) $(store_h) $(iutil_h) $(idict_h) $(dstack_h)
+
+idparam.$(OBJ): idparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(gsmatrix_h) $(gsuid_h)\
+ $(idict_h) $(idparam_h) $(ilevel_h) $(imemory_h) $(iname_h) $(iutil_h)\
+ $(oper_h) $(store_h)
+
+iparam.$(OBJ): iparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(iname_h) $(imemory_h) $(iparam_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(opcheck_h) $(store_h)
+
+istack.$(OBJ): istack.c $(GH) $(memory__h) \
+ $(errors_h) $(gsstruct_h) $(gsutil_h) \
+ $(ialloc_h) $(istack_h) $(istruct_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iutil.$(OBJ): iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\
+ $(gsccode_h) $(gsmatrix_h) $(gsutil_h) $(gxfont_h)\
+ $(errors_h) $(idict_h) $(imemory_h) $(iutil_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(oper_h) $(store_h)
+
+# ======================== PostScript Level 1 ======================== #
+
+###### Include files
+
+files_h=files.h
+fname_h=fname.h
+ichar_h=ichar.h
+icharout_h=icharout.h
+icolor_h=icolor.h
+icontext_h=icontext.h $(imemory_h) $(istack_h)
+icsmap_h=icsmap.h
+ifont_h=ifont.h $(gsccode_h) $(gsstruct_h)
+iht_h=iht.h
+iimage_h=iimage.h
+imain_h=imain.h $(gsexit_h)
+imainarg_h=imainarg.h
+iminst_h=iminst.h $(imain_h)
+interp_h=interp.h
+iparray_h=iparray.h
+iscannum_h=iscannum.h
+istream_h=istream.h
+main_h=main.h $(iminst_h)
+overlay_h=overlay.h
+sbwbs_h=sbwbs.h
+sfilter_h=sfilter.h $(gstypes_h)
+shcgen_h=shcgen.h
+smtf_h=smtf.h
+# Nested include files
+bfont_h=bfont.h $(ifont_h)
+ifilter_h=ifilter.h $(istream_h) $(ivmspace_h)
+igstate_h=igstate.h $(gsstate_h) $(gxstate_h) $(istruct_h)
+iscan_h=iscan.h $(sa85x_h) $(sstring_h)
+sbhc_h=sbhc.h $(shc_h)
+# Include files for optional features
+ibnum_h=ibnum.h
+
+### Initialization and scanning
+
+iconfig=iconfig$(CONFIG)
+$(iconfig).$(OBJ): iconf.c $(stdio__h) \
+ $(gconfig_h) $(gscdefs_h) $(gsmemory_h) \
+ $(files_h) $(iminst_h) $(iref_h) $(ivmspace_h) $(opdef_h) $(stream_h)
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) iconf.c $(iconfig).c
+ $(CCC) $(iconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+
+iinit.$(OBJ): iinit.c $(GH) $(string__h)\
+ $(gscdefs_h) $(gsexit_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h)\
+ $(ilevel_h) $(iname_h) $(interp_h) $(opdef_h)\
+ $(ipacked_h) $(iparray_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iscan.$(OBJ): iscan.c $(GH) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h) $(files_h)\
+ $(ilevel_h) $(iutil_h) $(iscan_h) $(iscannum_h) $(istruct_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(iparray_h) $(istream_h) $(ostack_h) $(store_h)\
+ $(stream_h) $(strimpl_h) $(sfilter_h) $(scanchar_h)
+
+iscannum.$(OBJ): iscannum.c $(GH) $(math__h)\
+ $(errors_h) $(iscannum_h) $(scanchar_h) $(scommon_h) $(store_h)
+
+### Streams
+
+sfilter1.$(OBJ): sfilter1.c $(AK) $(stdio__h) $(memory__h) \
+ $(sfilter_h) $(strimpl_h)
+
+###### Operators
+
+OP=$(GH) $(errors_h) $(oper_h)
+
+### Non-graphics operators
+
+zarith.$(OBJ): zarith.c $(OP) $(math__h) $(store_h)
+
+zarray.$(OBJ): zarray.c $(OP) $(memory__h) $(ialloc_h) $(ipacked_h) $(store_h)
+
+zcontrol.$(OBJ): zcontrol.c $(OP) $(string__h)\
+ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)
+
+zdict.$(OBJ): zdict.c $(OP) \
+ $(dstack_h) $(idict_h) $(ilevel_h) $(iname_h) $(ipacked_h) $(ivmspace_h) \
+ $(store_h)
+
+zfile.$(OBJ): zfile.c $(OP) $(memory__h) $(string__h) $(gp_h)\
+ $(gsstruct_h) $(gxiodev_h) \
+ $(ialloc_h) $(estack_h) $(files_h) $(fname_h) $(ilevel_h) $(interp_h) $(iutil_h)\
+ $(isave_h) $(main_h) $(sfilter_h) $(stream_h) $(strimpl_h) $(store_h)
+
+zfileio.$(OBJ): zfileio.c $(OP) $(gp_h) \
+ $(files_h) $(ifilter_h) $(store_h) $(stream_h) $(strimpl_h) \
+ $(gsmatrix_h) $(gxdevice_h) $(gxdevmem_h)
+
+zfilter.$(OBJ): zfilter.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sfilter_h) $(srlx_h) $(sstring_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zfname.$(OBJ): zfname.c $(OP) $(memory__h)\
+ $(fname_h) $(gxiodev_h) $(ialloc_h) $(stream_h)
+
+zfproc.$(OBJ): zfproc.c $(GH) $(memory__h)\
+ $(errors_h) $(oper_h)\
+ $(estack_h) $(files_h) $(gsstruct_h) $(ialloc_h) $(ifilter_h) $(istruct_h)\
+ $(store_h) $(stream_h) $(strimpl_h)
+
+zgeneric.$(OBJ): zgeneric.c $(OP) $(memory__h)\
+ $(idict_h) $(estack_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(store_h)
+
+ziodev.$(OBJ): ziodev.c $(OP) $(memory__h) $(stdio__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsstruct_h) $(gxiodev_h)\
+ $(files_h) $(ialloc_h) $(ivmspace_h) $(store_h) $(stream_h)
+
+zmath.$(OBJ): zmath.c $(OP) $(math__h) $(gxfarith_h) $(store_h)
+
+zmisc.$(OBJ): zmisc.c $(OP) $(gscdefs_h) $(gp_h) \
+ $(errno__h) $(memory__h) $(string__h) \
+ $(ialloc_h) $(idict_h) $(dstack_h) $(iname_h) $(ivmspace_h) $(ipacked_h) $(store_h)
+
+zpacked.$(OBJ): zpacked.c $(OP) \
+ $(ialloc_h) $(idict_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(iparray_h) \
+ $(istack_h) $(store_h)
+
+zrelbit.$(OBJ): zrelbit.c $(OP) $(gsutil_h) $(store_h) $(idict_h)
+
+zstack.$(OBJ): zstack.c $(OP) $(memory__h)\
+ $(ialloc_h) $(istack_h) $(store_h)
+
+zstring.$(OBJ): zstring.c $(OP) $(memory__h)\
+ $(gsutil_h)\
+ $(ialloc_h) $(iname_h) $(ivmspace_h) $(store_h)
+
+zsysvm.$(OBJ): zsysvm.c $(GH)\
+ $(ialloc_h) $(ivmspace_h) $(oper_h) $(store_h)
+
+ztoken.$(OBJ): ztoken.c $(OP) \
+ $(estack_h) $(files_h) $(gsstruct_h) $(iscan_h) \
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+ztype.$(OBJ): ztype.c $(OP) $(math__h) $(memory__h) $(string__h)\
+ $(dstack_h) $(idict_h) $(imemory_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zvmem.$(OBJ): zvmem.c $(OP)\
+ $(dstack_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(isave_h) $(store_h) $(stream_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h)
+
+### Graphics operators
+
+zchar.$(OBJ): zchar.c $(OP)\
+ $(gsstruct_h) $(gxarith_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxchar_h) $(gxdevice_h) $(gxfont_h) $(gzpath_h) $(gzstate_h)\
+ $(dstack_h) $(estack_h) $(ialloc_h) $(ichar_h) $(idict_h) $(ifont_h)\
+ $(ilevel_h) $(iname_h) $(igstate_h) $(ipacked_h) $(store_h)
+
+# zcharout is used for Type 1 and Type 42 fonts only.
+zcharout.$(OBJ): zcharout.c $(OP)\
+ $(gschar_h) $(gxdevice_h) $(gxfont_h)\
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h)\
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zcolor.$(OBJ): zcolor.c $(OP) \
+ $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gxdevice_h) $(gxcmap_h) \
+ $(ialloc_h) $(icolor_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zdevice.$(OBJ): zdevice.c $(OP) $(string__h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gxdevice_h) $(store_h)
+
+zfont.$(OBJ): zfont.c $(OP)\
+ $(gschar_h) $(gsstruct_h) $(gxdevice_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(isave_h) $(ivmspace_h)\
+ $(bfont_h) $(store_h)
+
+zfont2.$(OBJ): zfont2.c $(OP) $(memory__h) $(string__h)\
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(bfont_h) $(idict_h) $(idparam_h) $(ilevel_h) $(iname_h) $(istruct_h)\
+ $(ipacked_h) $(store_h)
+
+zgstate.$(OBJ): zgstate.c $(OP) $(math__h)\
+ $(gsmatrix_h) $(ialloc_h) $(idict_h) $(igstate_h) $(istruct_h) $(store_h)
+
+zht.$(OBJ): zht.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+zimage.$(OBJ): zimage.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ifilter_h) $(igstate_h) $(iimage_h) $(ilevel_h) \
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(store_h) $(stream_h)
+
+zmatrix.$(OBJ): zmatrix.c $(OP)\
+ $(gsmatrix_h) $(igstate_h) $(gscoord_h) $(store_h)
+
+zpaint.$(OBJ): zpaint.c $(OP)\
+ $(gspaint_h) $(igstate_h)
+
+zpath.$(OBJ): zpath.c $(OP) $(math__h) \
+ $(gsmatrix_h) $(gspath_h) $(igstate_h) $(store_h)
+
+# Define the base PostScript language interpreter.
+# This is the subset of PostScript Level 1 required by our PDF reader.
+
+INT1=idebug.$(OBJ) idict.$(OBJ) idparam.$(OBJ)
+INT2=iinit.$(OBJ) interp.$(OBJ) iparam.$(OBJ) ireclaim.$(OBJ)
+INT3=iscan.$(OBJ) iscannum.$(OBJ) istack.$(OBJ) iutil.$(OBJ)
+INT4=scantab.$(OBJ) sfilter1.$(OBJ) sstring.$(OBJ) stream.$(OBJ)
+Z1=zarith.$(OBJ) zarray.$(OBJ) zcontrol.$(OBJ) zdict.$(OBJ)
+Z1OPS=zarith zarray zcontrol zdict
+Z2=zfile.$(OBJ) zfileio.$(OBJ) zfilter.$(OBJ) zfname.$(OBJ) zfproc.$(OBJ)
+Z2OPS=zfile zfileio zfilter zfproc
+Z3=zgeneric.$(OBJ) ziodev.$(OBJ) zmath.$(OBJ) zmisc.$(OBJ) zpacked.$(OBJ)
+Z3OPS=zgeneric ziodev zmath zmisc zpacked
+Z4=zrelbit.$(OBJ) zstack.$(OBJ) zstring.$(OBJ) zsysvm.$(OBJ)
+Z4OPS=zrelbit zstack zstring zsysvm
+Z5=ztoken.$(OBJ) ztype.$(OBJ) zvmem.$(OBJ)
+Z5OPS=ztoken ztype zvmem
+Z6=zchar.$(OBJ) zcolor.$(OBJ) zdevice.$(OBJ) zfont.$(OBJ) zfont2.$(OBJ)
+Z6OPS=zchar zcolor zdevice zfont zfont2
+Z7=zgstate.$(OBJ) zht.$(OBJ) zimage.$(OBJ) zmatrix.$(OBJ) zpaint.$(OBJ) zpath.$(OBJ)
+Z7OPS=zgstate zht zimage zmatrix zpaint zpath
+# We have to be a little underhanded with *config.$(OBJ) so as to avoid
+# circular definitions.
+INT_OBJS=imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ) \
+ $(INT1) $(INT2) $(INT3) $(INT4) \
+ $(Z1) $(Z2) $(Z3) $(Z4) $(Z5) $(Z6) $(Z7)
+INT_CONFIG=$(gconfig).$(OBJ) $(gscdefs).$(OBJ) $(iconfig).$(OBJ) \
+ iccinit$(COMPILE_INITS).$(OBJ)
+INT_ALL=$(INT_OBJS) $(INT_CONFIG)
+# We omit libcore.dev, which should be included here, because problems
+# with the Unix linker require libcore to appear last in the link list
+# when libcore is really a library.
+# We omit $(INT_CONFIG) from the dependency list because they have special
+# dependency requirements and are added to the link list at the very end.
+# zfilter.c shouldn't include the RLE and RLD filters, but we don't want to
+# change this now.
+psbase.dev: $(INT_MAK) $(ECHOGS_XE) $(INT_OBJS)\
+ isupport.dev rld.dev rle.dev sfile.dev
+ $(SETMOD) psbase imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ)
+ $(ADDMOD) psbase -obj $(INT_CONFIG)
+ $(ADDMOD) psbase -obj $(INT1)
+ $(ADDMOD) psbase -obj $(INT2)
+ $(ADDMOD) psbase -obj $(INT3)
+ $(ADDMOD) psbase -obj $(INT4)
+ $(ADDMOD) psbase -obj $(Z1)
+ $(ADDMOD) psbase -oper $(Z1OPS)
+ $(ADDMOD) psbase -obj $(Z2)
+ $(ADDMOD) psbase -oper $(Z2OPS)
+ $(ADDMOD) psbase -obj $(Z3)
+ $(ADDMOD) psbase -oper $(Z3OPS)
+ $(ADDMOD) psbase -obj $(Z4)
+ $(ADDMOD) psbase -oper $(Z4OPS)
+ $(ADDMOD) psbase -obj $(Z5)
+ $(ADDMOD) psbase -oper $(Z5OPS)
+ $(ADDMOD) psbase -obj $(Z6)
+ $(ADDMOD) psbase -oper $(Z6OPS)
+ $(ADDMOD) psbase -obj $(Z7)
+ $(ADDMOD) psbase -oper $(Z7OPS)
+ $(ADDMOD) psbase -iodev stdin stdout stderr lineedit statementedit
+ $(ADDMOD) psbase -include isupport rld rle sfile
+
+# -------------------------- Feature definitions -------------------------- #
+
+# ---------------- Full Level 1 interpreter ---------------- #
+
+level1.dev: $(INT_MAK) $(ECHOGS_XE) psbase.dev bcp.dev hsb.dev path1.dev type1.dev
+ $(SETMOD) level1 -include psbase bcp hsb path1 type1
+ $(ADDMOD) level1 -emulator PostScript PostScriptLevel1
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+color.dev: $(INT_MAK) $(ECHOGS_XE) cmyklib.dev colimlib.dev cmykread.dev
+ $(SETMOD) color -include cmyklib colimlib cmykread
+
+cmykread_=zcolor1.$(OBJ) zht1.$(OBJ)
+cmykread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmykread_)
+ $(SETMOD) cmykread $(cmykread_)
+ $(ADDMOD) cmykread -oper zcolor1 zht1
+
+zcolor1.$(OBJ): zcolor1.c $(OP) \
+ $(gscolor1_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) \
+ $(ialloc_h) $(icolor_h) $(iimage_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zht1.$(OBJ): zht1.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h)\
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+# ---------------- HSB color ---------------- #
+
+hsb_=zhsb.$(OBJ)
+hsb.dev: $(INT_MAK) $(ECHOGS_XE) $(hsb_) hsblib.dev
+ $(SETMOD) hsb $(hsb_)
+ $(ADDMOD) hsb -include hsblib
+ $(ADDMOD) hsb -oper zhsb
+
+zhsb.$(OBJ): zhsb.c $(OP) \
+ $(gshsb_h) $(igstate_h) $(store_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1_=zpath1.$(OBJ)
+path1.dev: $(INT_MAK) $(ECHOGS_XE) $(path1_) path1lib.dev
+ $(SETMOD) path1 $(path1_)
+ $(ADDMOD) path1 -include path1lib
+ $(ADDMOD) path1 -oper zpath1
+
+zpath1.$(OBJ): zpath1.c $(OP) $(memory__h)\
+ $(ialloc_h) $(estack_h) $(gspath_h) $(gsstruct_h) $(igstate_h) $(store_h)
+
+# ================ Level-independent PostScript options ================ #
+
+# ---------------- BCP filters ---------------- #
+
+bcp_=sbcp.$(OBJ) zfbcp.$(OBJ)
+bcp.dev: $(INT_MAK) $(ECHOGS_XE) $(bcp_)
+ $(SETMOD) bcp $(bcp_)
+ $(ADDMOD) bcp -oper zfbcp
+
+sbcp.$(OBJ): sbcp.c $(AK) $(stdio__h) \
+ $(sfilter_h) $(strimpl_h)
+
+zfbcp.$(OBJ): zfbcp.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# ---------------- Incremental font loading ---------------- #
+# (This only works for Type 1 fonts without eexec encryption.)
+
+diskfont.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) diskfont -ps gs_diskf
+
+# ---------------- Double-precision floats ---------------- #
+
+double_=zdouble.$(OBJ)
+double.dev: $(INT_MAK) $(ECHOGS_XE) $(double_)
+ $(SETMOD) double $(double_)
+ $(ADDMOD) double -oper zdouble
+
+zdouble.$(OBJ): zdouble.c $(OP) $(ctype__h) $(math__h) $(memory__h) $(string__h) \
+ $(gxfarith_h) $(store_h)
+
+# ---------------- EPSF files with binary headers ---------------- #
+
+epsf.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) epsf -ps gs_epsf
+
+# ---------------- RasterOp ---------------- #
+# This should be a separable feature in the core also....
+
+rasterop.dev: $(INT_MAK) $(ECHOGS_XE) roplib.dev ropread.dev
+ $(SETMOD) rasterop -include roplib ropread
+
+ropread_=zrop.$(OBJ)
+ropread.dev: $(INT_MAK) $(ECHOGS_XE) $(ropread_)
+ $(SETMOD) ropread $(ropread_)
+ $(ADDMOD) ropread -oper zrop
+
+zrop.$(OBJ): zrop.c $(OP) $(memory__h)\
+ $(gsrop_h) $(gsutil_h) $(gxdevice_h)\
+ $(idict_h) $(idparam_h) $(igstate_h) $(store_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1.dev: $(INT_MAK) $(ECHOGS_XE) psf1lib.dev psf1read.dev
+ $(SETMOD) type1 -include psf1lib psf1read
+
+psf1read_=seexec.$(OBJ) zchar1.$(OBJ) zcharout.$(OBJ) zfont1.$(OBJ) zmisc1.$(OBJ)
+psf1read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf1read_)
+ $(SETMOD) psf1read $(psf1read_)
+ $(ADDMOD) psf1read -oper zchar1 zfont1 zmisc1
+ $(ADDMOD) psf1read -ps gs_type1
+
+seexec.$(OBJ): seexec.c $(AK) $(stdio__h) \
+ $(gscrypt1_h) $(scanchar_h) $(sfilter_h) $(strimpl_h)
+
+zchar1.$(OBJ): zchar1.c $(OP) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h) $(gzstate_h) \
+ $(estack_h) $(ialloc_h) $(ichar_h) $(icharout_h) \
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zfont1.$(OBJ): zfont1.c $(OP) \
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont1_h) \
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(store_h)
+
+zmisc1.$(OBJ): zmisc1.c $(OP) $(memory__h)\
+ $(gscrypt1_h)\
+ $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# -------------- Compact Font Format and Type 2 charstrings ------------- #
+
+cff.dev: $(INT_MAK) $(ECHOGS_XE) gs_cff.ps psl2int.dev
+ $(SETMOD) cff -ps gs_cff
+
+type2.dev: $(INT_MAK) $(ECHOGS_XE) type1.dev psf2lib.dev
+ $(SETMOD) type2 -include psf2lib
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+# Native TrueType support
+ttfont.dev: $(INT_MAK) $(ECHOGS_XE) type42.dev
+ $(SETMOD) ttfont -include type42
+ $(ADDMOD) ttfont -ps gs_mro_e gs_wan_e gs_ttf
+
+# Type 42 (embedded TrueType) support
+type42read_=zchar42.$(OBJ) zcharout.$(OBJ) zfont42.$(OBJ)
+type42.dev: $(INT_MAK) $(ECHOGS_XE) $(type42read_) ttflib.dev
+ $(SETMOD) type42 $(type42read_)
+ $(ADDMOD) type42 -include ttflib
+ $(ADDMOD) type42 -oper zchar42 zfont42
+ $(ADDMOD) type42 -ps gs_typ42
+
+zchar42.$(OBJ): zchar42.c $(OP) \
+ $(gsmatrix_h) $(gspaint_h) $(gspath_h) \
+ $(gxfixed_h) $(gxchar_h) $(gxfont_h) $(gxfont42_h) \
+ $(gxistate_h) $(gxpath_h) $(gzstate_h) \
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h) \
+ $(ifont_h) $(igstate_h) $(store_h)
+
+zfont42.$(OBJ): zfont42.c $(OP) \
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h) $(gxfont42_h) \
+ $(bfont_h) $(idict_h) $(idparam_h) $(store_h)
+
+# ======================== Precompilation options ======================== #
+
+# ---------------- Precompiled fonts ---------------- #
+# See fonts.txt for more information.
+
+ccfont_h=ccfont.h $(std_h) $(gsmemory_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+CCFONT=$(OP) $(ccfont_h)
+
+# List the fonts we are going to compile.
+# Because of intrinsic limitations in `make', we have to list
+# the object file names and the font names separately.
+# Because of limitations in the DOS shell, we have to break the fonts up
+# into lists that will fit on a single line (120 characters).
+# The rules for constructing the .c files from the fonts themselves,
+# and for compiling the .c files, are in cfonts.mak, not here.
+# For example, to compile the Courier fonts, you should invoke
+# make -f cfonts.mak Courier_o
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+ccfonts_ps=gs_ccfnt
+ccfonts1_=0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+ccfonts1=agk agko agd agdo
+ccfonts2_=0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+ccfonts2=bkl bkli bkd bkdi
+ccfonts3_=0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+ccfonts3=crr cri crb crbi
+ccfonts4_=0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ)
+ccfonts4=hvr hvro hvb hvbo
+ccfonts5_=0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+ccfonts5=hvrrn hvrorn hvbrn hvborn
+ccfonts6_=0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+ccfonts6=ncr ncri ncb ncbi
+ccfonts7_=0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+ccfonts7=plr plri plb plbi
+ccfonts8_=0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+ccfonts8=tmr tmri tmb tmbi
+ccfonts9_=0syr.$(OBJ) 0zcmi.$(OBJ) 0zdr.$(OBJ)
+ccfonts9=syr zcmi zdr
+# The free distribution includes Bitstream Charter, Utopia, and
+# freeware Cyrillic and Kana fonts. We only provide for compiling
+# Charter and Utopia.
+ccfonts10free_=bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+ccfonts10free=chr chri chb chbi
+ccfonts11free_=putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+ccfonts11free=utr utri utb utbi
+# Uncomment the alternatives in the next 4 lines if you want
+# Charter and Utopia compiled in.
+#ccfonts10_=$(ccfonts10free_)
+ccfonts10_=
+#ccfonts10=$(ccfonts10free)
+ccfonts10=
+#ccfonts11_=$(ccfonts11free_)
+ccfonts11_=
+#ccfonts11=$(ccfonts11free)
+ccfonts11=
+# Add your own fonts here if desired.
+ccfonts12_=
+ccfonts12=
+ccfonts13_=
+ccfonts13=
+ccfonts14_=
+ccfonts14=
+ccfonts15_=
+ccfonts15=
+
+# It's OK for ccfonts_.dev not to be CONFIG-dependent, because it only
+# exists during the execution of the following rule.
+# font2c has the prefix "gs" built into it, so we need to instruct
+# genconf to use the same one.
+$(gconfigf_h): $(MAKEFILE) $(INT_MAK) $(GENCONF_XE)
+ $(SETMOD) ccfonts_ -font $(ccfonts1)
+ $(ADDMOD) ccfonts_ -font $(ccfonts2)
+ $(ADDMOD) ccfonts_ -font $(ccfonts3)
+ $(ADDMOD) ccfonts_ -font $(ccfonts4)
+ $(ADDMOD) ccfonts_ -font $(ccfonts5)
+ $(ADDMOD) ccfonts_ -font $(ccfonts6)
+ $(ADDMOD) ccfonts_ -font $(ccfonts7)
+ $(ADDMOD) ccfonts_ -font $(ccfonts8)
+ $(ADDMOD) ccfonts_ -font $(ccfonts9)
+ $(ADDMOD) ccfonts_ -font $(ccfonts10)
+ $(ADDMOD) ccfonts_ -font $(ccfonts11)
+ $(ADDMOD) ccfonts_ -font $(ccfonts12)
+ $(ADDMOD) ccfonts_ -font $(ccfonts13)
+ $(ADDMOD) ccfonts_ -font $(ccfonts14)
+ $(ADDMOD) ccfonts_ -font $(ccfonts15)
+ $(EXP)genconf ccfonts_.dev -n gs -f $(gconfigf_h)
+
+# We separate icfontab.dev from ccfonts.dev so that a customer can put
+# compiled fonts into a separate shared library.
+
+icfontab=icfontab$(CONFIG)
+
+# Define ccfont_table separately, so it can be set from the command line
+# to select an alternate compiled font table.
+ccfont_table=$(icfontab)
+
+$(icfontab).dev: $(MAKEFILE) $(INT_MAK) $(ECHOGS_XE) $(icfontab).$(OBJ) \
+ $(ccfonts1_) $(ccfonts2_) $(ccfonts3_) $(ccfonts4_) $(ccfonts5_) \
+ $(ccfonts6_) $(ccfonts7_) $(ccfonts8_) $(ccfonts9_) $(ccfonts10_) \
+ $(ccfonts11_) $(ccfonts12_) $(ccfonts13_) $(ccfonts14_) $(ccfonts15_)
+ $(SETMOD) $(icfontab) -obj $(icfontab).$(OBJ)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts1_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts2_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts3_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts4_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts5_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts6_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts7_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts8_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts9_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts10_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts11_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts12_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts13_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts14_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts15_)
+
+$(icfontab).$(OBJ): icfontab.c $(AK) $(ccfont_h) $(gconfigf_h)
+ $(CP_) $(gconfigf_h) gconfigf.h
+ $(CCCF) icfontab.c
+
+# Strictly speaking, ccfonts shouldn't need to include type1,
+# since one could choose to precompile only Type 0 fonts,
+# but getting this exactly right would be too much work.
+ccfonts=ccfonts$(CONFIG)
+$(ccfonts).dev: $(MAKEFILE) $(INT_MAK) type1.dev iccfont.$(OBJ) \
+ $(ccfont_table).dev
+ $(SETMOD) $(ccfonts) -include type1
+ $(ADDMOD) $(ccfonts) -include $(ccfont_table)
+ $(ADDMOD) $(ccfonts) -obj iccfont.$(OBJ)
+ $(ADDMOD) $(ccfonts) -oper ccfonts
+ $(ADDMOD) $(ccfonts) -ps $(ccfonts_ps)
+
+iccfont.$(OBJ): iccfont.c $(GH) $(string__h)\
+ $(gsstruct_h) $(ccfont_h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(ifont_h) $(iname_h) $(isave_h) $(iutil_h)\
+ $(oper_h) $(ostack_h) $(store_h) $(stream_h) $(strimpl_h) $(sfilter_h) $(iscan_h)
+ $(CCCF) iccfont.c
+
+# ---------------- Compiled initialization code ---------------- #
+
+# We select either iccinit0 or iccinit1 depending on COMPILE_INITS.
+
+iccinit0.$(OBJ): iccinit0.c $(stdpre_h)
+ $(CCCF) iccinit0.c
+
+iccinit1.$(OBJ): gs_init.$(OBJ)
+ $(CP_) gs_init.$(OBJ) iccinit1.$(OBJ)
+
+# All the gs_*.ps files should be prerequisites of gs_init.c,
+# but we don't have any convenient list of them.
+gs_init.c: $(GS_INIT) $(GENINIT_XE) $(gconfig_h)
+ $(EXP)geninit $(GS_INIT) $(gconfig_h) -c gs_init.c
+
+gs_init.$(OBJ): gs_init.c $(stdpre_h)
+ $(CCCF) gs_init.c
+
+# ======================== PostScript Level 2 ======================== #
+
+level2.dev: $(INT_MAK) $(ECHOGS_XE) \
+ cidfont.dev cie.dev cmapread.dev compfont.dev dct.dev devctrl.dev dpsand2.dev\
+ filter.dev level1.dev pattern.dev psl2lib.dev psl2read.dev sepr.dev\
+ type42.dev xfilter.dev
+ $(SETMOD) level2 -include cidfont cie cmapread compfont
+ $(ADDMOD) level2 -include dct devctrl dpsand2 filter
+ $(ADDMOD) level2 -include level1 pattern psl2lib psl2read
+ $(ADDMOD) level2 -include sepr type42 xfilter
+ $(ADDMOD) level2 -emulator PostScript PostScriptLevel2
+
+# Define basic Level 2 language support.
+# This is the minimum required for CMap and CIDFont support.
+
+psl2int_=iutil2.$(OBJ) zmisc2.$(OBJ) zusparam.$(OBJ)
+psl2int.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2int_) dps2int.dev
+ $(SETMOD) psl2int $(psl2int_)
+ $(ADDMOD) psl2int -include dps2int
+ $(ADDMOD) psl2int -oper zmisc2 zusparam
+ $(ADDMOD) psl2int -ps gs_lev2 gs_res
+
+iutil2.$(OBJ): iutil2.c $(GH) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsutil_h)\
+ $(errors_h) $(opcheck_h) $(imemory_h) $(iutil_h) $(iutil2_h)
+
+zmisc2.$(OBJ): zmisc2.c $(OP) $(memory__h) $(string__h)\
+ $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(ilevel_h) $(iname_h) $(iutil2_h) $(ivmspace_h) $(store_h)
+
+# Note that zusparam includes both Level 1 and Level 2 operators.
+zusparam.$(OBJ): zusparam.c $(OP) $(memory__h) $(string__h)\
+ $(gscdefs_h) $(gsfont_h) $(gsstruct_h) $(gsutil_h) $(gxht_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(iname_h) $(iutil2_h) $(store_h)
+
+# Define full Level 2 support.
+
+psl2read_=zcolor2.$(OBJ) zcsindex.$(OBJ) zht2.$(OBJ) zimage2.$(OBJ)
+# Note that zmisc2 includes both Level 1 and Level 2 operators.
+psl2read.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2read_) psl2int.dev dps2read.dev
+ $(SETMOD) psl2read $(psl2read_)
+ $(ADDMOD) psl2read -include psl2int dps2read
+ $(ADDMOD) psl2read -oper zcolor2_l2 zcsindex_l2
+ $(ADDMOD) psl2read -oper zht2_l2 zimage2_l2
+
+zcolor2.$(OBJ): zcolor2.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+zcsindex.$(OBJ): zcsindex.c $(OP) $(memory__h) \
+ $(gscolor_h) $(gsstruct_h) $(gxfixed_h) $(gxcolor2_h) $(gxcspace_h) $(gsmatrix_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zht2.$(OBJ): zht2.c $(OP) \
+ $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(estack_h) $(ialloc_h) $(icolor_h) $(idict_h) $(idparam_h) $(igstate_h) \
+ $(iht_h) $(store_h)
+
+zimage2.$(OBJ): zimage2.c $(OP) $(math__h) $(memory__h)\
+ $(gscolor_h) $(gscolor2_h) $(gscspace_h) $(gsimage_h) $(gsmatrix_h)\
+ $(idict_h) $(idparam_h) $(iimage_h) $(ilevel_h) $(igstate_h)
+
+# ---------------- Device control ---------------- #
+# This is a catch-all for setpagedevice and IODevices.
+
+devctrl_=zdevice2.$(OBJ) ziodev2.$(OBJ) zmedia2.$(OBJ) zdevcal.$(OBJ)
+devctrl.dev: $(INT_MAK) $(ECHOGS_XE) $(devctrl_)
+ $(SETMOD) devctrl $(devctrl_)
+ $(ADDMOD) devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+ $(ADDMOD) devctrl -iodev null ram calendar
+ $(ADDMOD) devctrl -ps gs_setpd
+
+zdevice2.$(OBJ): zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(store_h)\
+ $(gxdevice_h) $(gsstate_h)
+
+ziodev2.$(OBJ): ziodev2.c $(OP) $(string__h) $(gp_h)\
+ $(gxiodev_h) $(stream_h) $(files_h) $(iparam_h) $(iutil2_h) $(store_h)
+
+zmedia2.$(OBJ): zmedia2.c $(OP) $(math__h) $(memory__h) \
+ $(gsmatrix_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+
+zdevcal.$(OBJ): zdevcal.c $(GH) $(time__h) \
+ $(gxiodev_h) $(iparam_h) $(istack_h)
+
+# ---------------- Filters other than the ones in sfilter.c ---------------- #
+
+# Standard Level 2 decoding filters only. The PDF configuration uses this.
+fdecode_=scantab.$(OBJ) sfilter2.$(OBJ) zfdecode.$(OBJ)
+fdecode.dev: $(INT_MAK) $(ECHOGS_XE) $(fdecode_) cfd.dev lzwd.dev pdiff.dev pngp.dev rld.dev
+ $(SETMOD) fdecode $(fdecode_)
+ $(ADDMOD) fdecode -include cfd lzwd pdiff pngp rld
+ $(ADDMOD) fdecode -oper zfdecode
+
+zfdecode.$(OBJ): zfdecode.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sa85x_h) $(scf_h) $(scfx_h) $(sfilter_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) \
+ $(store_h) $(stream_h) $(strimpl_h)
+
+# Complete Level 2 filter capability.
+filter_=zfilter2.$(OBJ)
+filter.dev: $(INT_MAK) $(ECHOGS_XE) fdecode.dev $(filter_) cfe.dev lzwe.dev rle.dev
+ $(SETMOD) filter -include fdecode
+ $(ADDMOD) filter -obj $(filter_)
+ $(ADDMOD) filter -include cfe lzwe rle
+ $(ADDMOD) filter -oper zfilter2
+
+zfilter2.$(OBJ): zfilter2.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(store_h) \
+ $(sfilter_h) $(scfx_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) $(strimpl_h)
+
+# Extensions beyond Level 2 standard.
+xfilter_=sbhc.$(OBJ) sbwbs.$(OBJ) shcgen.$(OBJ) smtf.$(OBJ) \
+ zfilterx.$(OBJ)
+xfilter.dev: $(INT_MAK) $(ECHOGS_XE) $(xfilter_) pcxd.dev pngp.dev
+ $(SETMOD) xfilter $(xfilter_)
+ $(ADDMOD) xfilter -include pcxd
+ $(ADDMOD) xfilter -oper zfilterx
+
+sbhc.$(OBJ): sbhc.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(sbhc_h) $(shcgen_h) $(strimpl_h)
+
+sbwbs.$(OBJ): sbwbs.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(sbwbs_h) $(sfilter_h) $(strimpl_h)
+
+shcgen.$(OBJ): shcgen.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gserror_h) $(gserrors_h) $(gsmemory_h)\
+ $(scommon_h) $(shc_h) $(shcgen_h)
+
+smtf.$(OBJ): smtf.c $(AK) $(stdio__h) \
+ $(smtf_h) $(strimpl_h)
+
+zfilterx.$(OBJ): zfilterx.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(store_h) $(sfilter_h) $(sbhc_h) $(sbtx_h) $(sbwbs_h) $(shcgen_h)\
+ $(smtf_h) $(spcxx_h) $(strimpl_h)
+
+# ---------------- Binary tokens ---------------- #
+
+btoken_=iscanbin.$(OBJ) zbseq.$(OBJ)
+btoken.dev: $(INT_MAK) $(ECHOGS_XE) $(btoken_)
+ $(SETMOD) btoken $(btoken_)
+ $(ADDMOD) btoken -oper zbseq_l2
+ $(ADDMOD) btoken -ps gs_btokn
+
+bseq_h=bseq.h
+btoken_h=btoken.h
+
+iscanbin.$(OBJ): iscanbin.c $(GH) $(math__h) $(memory__h) $(errors_h)\
+ $(gsutil_h) $(ialloc_h) $(ibnum_h) $(idict_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(ivmspace_h)\
+ $(bseq_h) $(btoken_h) $(dstack_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zbseq.$(OBJ): zbseq.c $(OP) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(isave_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)\
+ $(iname_h) $(ibnum_h) $(btoken_h) $(bseq_h)
+
+# ---------------- User paths & insideness testing ---------------- #
+
+upath_=zupath.$(OBJ) ibnum.$(OBJ)
+upath.dev: $(INT_MAK) $(ECHOGS_XE) $(upath_)
+ $(SETMOD) upath $(upath_)
+ $(ADDMOD) upath -oper zupath_l2
+
+zupath.$(OBJ): zupath.c $(OP) \
+ $(idict_h) $(dstack_h) $(iutil_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h) \
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstate_h) \
+ $(gxfixed_h) $(gxdevice_h) $(gzpath_h) $(gzstate_h)
+
+# -------- Additions common to Display PostScript and Level 2 -------- #
+
+dpsand2.dev: $(INT_MAK) $(ECHOGS_XE) btoken.dev color.dev upath.dev dps2lib.dev dps2read.dev
+ $(SETMOD) dpsand2 -include btoken color upath dps2lib dps2read
+
+dps2int_=zvmem2.$(OBJ) zdps1.$(OBJ)
+# Note that zvmem2 includes both Level 1 and Level 2 operators.
+dps2int.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2int_)
+ $(SETMOD) dps2int $(dps2int_)
+ $(ADDMOD) dps2int -oper zvmem2 zdps1_l2
+ $(ADDMOD) dps2int -ps gs_dps1
+
+dps2read_=ibnum.$(OBJ) zchar2.$(OBJ)
+dps2read.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2read_) dps2int.dev
+ $(SETMOD) dps2read $(dps2read_)
+ $(ADDMOD) dps2read -include dps2int
+ $(ADDMOD) dps2read -oper ireclaim_l2 zchar2_l2
+ $(ADDMOD) dps2read -ps gs_dps2
+
+ibnum.$(OBJ): ibnum.c $(GH) $(math__h) $(memory__h)\
+ $(errors_h) $(stream_h) $(ibnum_h) $(imemory_h) $(iutil_h)
+
+zchar2.$(OBJ): zchar2.c $(OP)\
+ $(gschar_h) $(gsmatrix_h) $(gspath_h) $(gsstruct_h)\
+ $(gxchar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(ichar_h) $(estack_h) $(ifont_h) $(iname_h) $(igstate_h)\
+ $(store_h) $(stream_h) $(ibnum_h)
+
+zdps1.$(OBJ): zdps1.c $(OP) \
+ $(gsmatrix_h) $(gspath_h) $(gspath2_h) $(gsstate_h) \
+ $(ialloc_h) $(ivmspace_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h)
+
+zvmem2.$(OBJ): zvmem2.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Display PostScript ---------------- #
+
+dps_=zdps.$(OBJ) icontext.$(OBJ) zcontext.$(OBJ)
+dps.dev: $(INT_MAK) $(ECHOGS_XE) dpslib.dev level2.dev $(dps_)
+ $(SETMOD) dps -include dpslib level2
+ $(ADDMOD) dps -obj $(dps_)
+ $(ADDMOD) dps -oper zcontext zdps
+ $(ADDMOD) dps -ps gs_dps
+
+icontext.$(OBJ): icontext.c $(GH)\
+ $(gsstruct_h) $(gxalloc_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(ostack_h)\
+ $(icontext_h) $(igstate_h) $(interp_h) $(store_h)
+
+zdps.$(OBJ): zdps.c $(OP)\
+ $(gsdps_h) $(gsstate_h) $(igstate_h) $(iname_h) $(store_h)
+
+zcontext.$(OBJ): zcontext.c $(OP) $(gp_h) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h) $(gsutil_h) $(gxalloc_h)\
+ $(icontext_h) $(idict_h) $(igstate_h) $(istruct_h)\
+ $(dstack_h) $(estack_h) $(ostack_h) $(store_h)
+
+# The following #ifdef ... #endif are just a comment to mark a DPNEXT area.
+#ifdef DPNEXT
+
+# ---------------- NeXT Display PostScript ---------------- #
+#**************** NOT READY FOR USE YET ****************#
+
+# There should be a gsdpnext.c, but there isn't yet.
+#dpsnext_=zdpnext.$(OBJ) gsdpnext.$(OBJ)
+dpsnext_=zdpnext.$(OBJ)
+dpsnext.dev: $(INT_MAK) $(ECHOGS_XE) dps.dev $(dpsnext_) gs_dpnxt.ps
+ $(SETMOD) dpsnext -include dps
+ $(ADDMOD) dpsnext -obj $(dpsnext_)
+ $(ADDMOD) dpsnext -oper zdpnext
+ $(ADDMOD) dpsnext -ps gs_dpnxt
+
+zdpnext.$(OBJ): zdpnext.c $(OP)\
+ $(gscspace_h) $(gsiparam_h) $(gsmatrix_h) $(gxcvalue_h) $(gxsample_h)\
+ $(ialloc_h) $(igstate_h) $(iimage_h)
+
+# See above re the following.
+#endif /* DPNEXT */
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+compfont.dev: $(INT_MAK) $(ECHOGS_XE) psf0lib.dev psf0read.dev
+ $(SETMOD) compfont -include psf0lib psf0read
+
+# We always include zfcmap.$(OBJ) because zfont0.c refers to it,
+# and it's not worth the trouble to exclude.
+psf0read_=zchar2.$(OBJ) zfcmap.$(OBJ) zfont0.$(OBJ)
+psf0read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf0read_)
+ $(SETMOD) psf0read $(psf0read_)
+ $(ADDMOD) psf0read -oper zfont0 zchar2 zfcmap
+
+zfcmap.$(OBJ): zfcmap.c $(OP)\
+ $(gsmatrix_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxfcmap_h) $(gxfont_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifont_h) $(iname_h) $(store_h)
+
+zfont0.$(OBJ): zfont0.c $(OP)\
+ $(gschar_h) $(gsstruct_h)\
+ $(gxdevice_h) $(gxfcmap_h) $(gxfixed_h) $(gxfont_h) $(gxfont0_h) $(gxmatrix_h)\
+ $(gzstate_h)\
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h)\
+ $(store_h)
+
+# ---------------- CMap support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cmapread_=zfcmap.$(OBJ)
+cmapread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmapread_) cmaplib.dev psl2int.dev
+ $(SETMOD) cmapread $(cmapread_)
+ $(ADDMOD) cmapread -include cmaplib psl2int
+ $(ADDMOD) cmapread -oper zfcmap
+ $(ADDMOD) cmapread -ps gs_cmap
+
+# ---------------- CIDFont support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cidread_=zcid.$(OBJ)
+cidfont.dev: $(INT_MAK) $(ECHOGS_XE) psf1read.dev psl2int.dev type42.dev\
+ $(cidread_)
+ $(SETMOD) cidfont $(cidread_)
+ $(ADDMOD) cidfont -include psf1read psl2int type42
+ $(ADDMOD) cidfont -ps gs_cidfn
+ $(ADDMOD) cidfont -oper zcid
+
+zcid.$(OBJ): zcid.c $(OP)\
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h)\
+ $(bfont_h) $(iname_h) $(store_h)
+
+# ---------------- CIE color ---------------- #
+
+cieread_=zcie.$(OBJ) zcrd.$(OBJ)
+cie.dev: $(INT_MAK) $(ECHOGS_XE) $(cieread_) cielib.dev
+ $(SETMOD) cie $(cieread_)
+ $(ADDMOD) cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) cie -include cielib
+
+icie_h=icie.h
+
+zcie.$(OBJ): zcie.c $(OP) $(math__h) $(memory__h) \
+ $(gscolor2_h) $(gscie_h) $(gsstruct_h) $(gxcspace_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zcrd.$(OBJ): zcrd.c $(OP) $(math__h) \
+ $(gscspace_h) $(gscolor2_h) $(gscie_h) $(gsstruct_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Pattern color ---------------- #
+
+pattern.dev: $(INT_MAK) $(ECHOGS_XE) patlib.dev patread.dev
+ $(SETMOD) pattern -include patlib patread
+
+patread_=zpcolor.$(OBJ)
+patread.dev: $(INT_MAK) $(ECHOGS_XE) $(patread_)
+ $(SETMOD) patread $(patread_)
+ $(ADDMOD) patread -oper zpcolor_l2
+
+zpcolor.$(OBJ): zpcolor.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+# ---------------- Separation color ---------------- #
+
+seprread_=zcssepr.$(OBJ)
+sepr.dev: $(INT_MAK) $(ECHOGS_XE) $(seprread_) seprlib.dev
+ $(SETMOD) sepr $(seprread_)
+ $(ADDMOD) sepr -oper zcssepr_l2
+ $(ADDMOD) sepr -include seprlib
+
+zcssepr.$(OBJ): zcssepr.c $(OP) \
+ $(gscolor_h) $(gscsepr_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Functions ---------------- #
+
+ifunc_h=ifunc.h
+
+# Generic support, and FunctionType 0.
+funcread_=zfunc.$(OBJ) zfunc0.$(OBJ)
+func.dev: $(INT_MAK) $(ECHOGS_XE) $(funcread_) funclib.dev
+ $(SETMOD) func $(funcread_)
+ $(ADDMOD) func -oper zfunc zfunc0
+ $(ADDMOD) func -include funclib
+
+zfunc.$(OBJ): zfunc.c $(OP) $(memory__h)\
+ $(gsfunc_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h) $(store_h)
+
+zfunc0.$(OBJ): zfunc0.c $(OP) $(memory__h)\
+ $(gsdsrc_h) $(gsfunc_h) $(gsfunc0_h)\
+ $(stream_h)\
+ $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)
+
+# ---------------- DCT filters ---------------- #
+# The definitions for jpeg*.dev are in jpeg.mak.
+
+dct.dev: $(INT_MAK) $(ECHOGS_XE) dcte.dev dctd.dev
+ $(SETMOD) dct -include dcte dctd
+
+# Common code
+
+dctc_=zfdctc.$(OBJ)
+
+zfdctc.$(OBJ): zfdctc.c $(GH) $(memory__h) $(stdio__h)\
+ $(errors_h) $(opcheck_h)\
+ $(idict_h) $(idparam_h) $(imemory_h) $(ipacked_h) $(iutil_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h)\
+ jpeglib.h
+
+# Encoding (compression)
+
+dcte_=$(dctc_) zfdcte.$(OBJ)
+dcte.dev: $(INT_MAK) $(ECHOGS_XE) sdcte.dev $(dcte_)
+ $(SETMOD) dcte -include sdcte
+ $(ADDMOD) dcte -obj $(dcte_)
+ $(ADDMOD) dcte -oper zfdcte
+
+zfdcte.$(OBJ): zfdcte.c $(OP) $(memory__h) $(stdio__h)\
+ $(idict_h) $(idparam_h) $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# Decoding (decompression)
+
+dctd_=$(dctc_) zfdctd.$(OBJ)
+dctd.dev: $(INT_MAK) $(ECHOGS_XE) sdctd.dev $(dctd_)
+ $(SETMOD) dctd -include sdctd
+ $(ADDMOD) dctd -obj $(dctd_)
+ $(ADDMOD) dctd -oper zfdctd
+
+zfdctd.$(OBJ): zfdctd.c $(OP) $(memory__h) $(stdio__h)\
+ $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# ---------------- zlib/Flate filters ---------------- #
+
+fzlib.dev: $(INT_MAK) $(ECHOGS_XE) zfzlib.$(OBJ) szlibe.dev szlibd.dev
+ $(SETMOD) fzlib -include szlibe szlibd
+ $(ADDMOD) fzlib -obj zfzlib.$(OBJ)
+ $(ADDMOD) fzlib -oper zfzlib
+
+zfzlib.$(OBJ): zfzlib.c $(OP) \
+ $(errors_h) $(idict_h) $(ifilter_h) \
+ $(spdiffx_h) $(spngpx_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) zfzlib.c
+
+# ================================ PDF ================================ #
+
+# We need most of the Level 2 interpreter to do PDF, but not all of it.
+# In fact, we don't even need all of a Level 1 interpreter.
+
+# Because of the way the PDF encodings are defined, they must get loaded
+# before we install the Level 2 resource machinery.
+# On the other hand, the PDF .ps files must get loaded after
+# level2dict is defined.
+pdfmin.dev: $(INT_MAK) $(ECHOGS_XE)\
+ psbase.dev color.dev dps2lib.dev dps2read.dev\
+ fdecode.dev type1.dev pdffonts.dev psl2lib.dev psl2read.dev pdfread.dev
+ $(SETMOD) pdfmin -include psbase color dps2lib dps2read
+ $(ADDMOD) pdfmin -include fdecode type1
+ $(ADDMOD) pdfmin -include pdffonts psl2lib psl2read pdfread
+ $(ADDMOD) pdfmin -emulator PDF
+
+pdf.dev: $(INT_MAK) $(ECHOGS_XE)\
+ pdfmin.dev cff.dev cidfont.dev cie.dev compfont.dev cmapread.dev dctd.dev\
+ func.dev ttfont.dev type2.dev
+ $(SETMOD) pdf -include pdfmin cff cidfont cie cmapread compfont dctd
+ $(ADDMOD) pdf -include func ttfont type2
+
+# Reader only
+
+pdffonts.dev: $(INT_MAK) $(ECHOGS_XE) \
+ gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps
+ $(SETMOD) pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+
+# pdf_2ps must be the last .ps file loaded.
+pdfread.dev: $(INT_MAK) $(ECHOGS_XE) fzlib.dev
+ $(SETMOD) pdfread -include fzlib
+ $(ADDMOD) pdfread -ps gs_pdf gs_l2img
+ $(ADDMOD) pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+ $(ADDMOD) pdfread -ps pdf_2ps
+
+# ============================= Main program ============================== #
+
+gs.$(OBJ): gs.c $(GH) \
+ $(imain_h) $(imainarg_h) $(iminst_h)
+
+imainarg.$(OBJ): imainarg.c $(GH) $(ctype__h) $(memory__h) $(string__h) \
+ $(gp_h) \
+ $(gsargs_h) $(gscdefs_h) $(gsdevice_h) $(gsmdebug_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(errors_h) $(estack_h) $(files_h) \
+ $(ialloc_h) $(imain_h) $(imainarg_h) $(iminst_h) \
+ $(iname_h) $(interp_h) $(iscan_h) $(iutil_h) $(ivmspace_h) \
+ $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+imain.$(OBJ): imain.c $(GH) $(memory__h) $(string__h)\
+ $(gp_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h) $(gxdevice_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(interp_h)\
+ $(isave_h) $(iscan_h) $(ivmspace_h)\
+ $(main_h) $(oper_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+interp.$(OBJ): interp.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(iastruct_h) $(inamedef_h) $(idict_h) $(interp_h) $(ipacked_h)\
+ $(iscan_h) $(isave_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(oper_h) $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(CCINT) interp.c
+
+ireclaim.$(OBJ): ireclaim.c $(GH) \
+ $(errors_h) $(gsstruct_h) $(iastate_h) $(opdef_h) $(store_h) \
+ $(dstack_h) $(estack_h) $(ostack_h)
+# Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Independent JPEG Group library code.
+
+# NOTE: This makefile is only known to work with the following versions
+# of the IJG library: 6, 6a.
+# As of May 11, 1996, version 6a is the current version.
+#
+# You can get the IJG library by Internet anonymous FTP from the following
+# places:
+# Standard distribution (tar + gzip format, Unix end-of-line):
+# ftp.uu.net:/graphics/jpeg/jpegsrc.v*.tar.gz
+# ftp.cs.wisc.edu:/ghost/jpegsrc.v*.tar.gz
+# MS-DOS archive (PKZIP a.k.a. zip format, MS-DOS end-of-line):
+# ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr*.zip
+# ftp.cs.wisc.edu:/ghost/jpeg-*.zip
+# The first site named above (ftp.uu.net and ftp.simtel.net) is supposed
+# to be the master distribution site, so it may have a more up-to-date
+# version; the ftp.cs.wisc.edu site is the master distribution site for
+# Ghostscript, so it will always have IJG library versions known to be
+# compatible with Ghostscript.
+#
+# If the version number, and hence the subdirectory name, changes, you
+# will probably want to change the definitions of JSRCDIR and possibly
+# JVERSION (in the platform-specific makefile, not here) to reflect this,
+# since that way you can use the IJG archive without change.
+#
+# NOTE: For some obscure reason (probably a bug in djtarx), if you are
+# compiling on a DesqView/X system, you should use the zip version of the
+# IJG library, not the tar.gz version.
+
+# Define the name of this makefile.
+JPEG_MAK=jpeg.mak
+
+# JSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the IJG library sources are stored.
+#JSRCDIR=jpeg-6a
+# JVERSION is defined in the platform-specific makefile, not here,
+# as the IJG library major version number (currently "5" or "6").
+#JVERSION=6
+
+JSRC=$(JSRCDIR)$(D)
+# CCCJ is defined in gs.mak.
+#CCCJ=$(CCC) -I. -I$(JSRCDIR)
+
+# We keep all of the IJG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+# However, we need our own version of jconfig.h, and our own "wrapper" for
+# jmorecfg.h. We also need a substitute for jerror.c, in order to
+# keep the error strings out of the automatic data segment in
+# 16-bit environments. For v5*, we also need our own version of jpeglib.h
+# in order to change MAX_BLOCKS_IN_MCU for Adobe compatibility.
+# (This need will go away when IJG v6 is released.)
+
+# Because this file is included after lib.mak, we can't use _h macros
+# to express indirect dependencies; instead, we build the dependencies
+# into the rules for copying the files.
+jconfig_h=jconfig.h
+jerror_h=jerror.h
+jmorecfg_h=jmorecfg.h
+jpeglib_h=jpeglib.h
+
+jconfig.h: gsjconf.h $(std_h)
+ $(CP_) gsjconf.h jconfig.h
+
+jmorecfg.h: gsjmorec.h jmcorig.h
+ $(CP_) gsjmorec.h jmorecfg.h
+
+jmcorig.h: $(JSRC)jmorecfg.h
+ $(CP_) $(JSRC)jmorecfg.h jmcorig.h
+
+jpeglib.h: jlib$(JVERSION).h jconfig.h jmorecfg.h
+ $(CP_) jlib$(JVERSION).h jpeglib.h
+
+jlib5.h: gsjpglib.h
+ $(CP_) gsjpglib.h jlib5.h
+
+jlib6.h: $(JSRC)jpeglib.h
+ $(CP_) $(JSRC)jpeglib.h jlib6.h
+
+# To ensure that the compiler finds our versions of jconfig.h and jmorecfg.h,
+# regardless of the compiler's search rule, we must copy up all .c files,
+# and all .h files that include either of these files, directly or
+# indirectly. The only such .h files currently are jinclude.h and jpeglib.h.
+# (Currently, we supply our own version of jpeglib.h -- see above.)
+# Also, to avoid including the JSRCDIR directory name in our source files,
+# we must also copy up any other .h files that our own code references.
+# Currently, the only such .h files are jerror.h and jversion.h.
+
+JHCOPY=jinclude.h jpeglib.h jerror.h jversion.h
+
+jinclude.h: $(JSRC)jinclude.h
+ $(CP_) $(JSRC)jinclude.h jinclude.h
+
+#jpeglib.h: $(JSRC)jpeglib.h
+# $(CP_) $(JSRC)jpeglib.h jpeglib.h
+
+jerror.h: $(JSRC)jerror.h
+ $(CP_) $(JSRC)jerror.h jerror.h
+
+jversion.h: $(JSRC)jversion.h
+ $(CP_) $(JSRC)jversion.h jversion.h
+
+# In order to avoid having to keep the dependency lists for the IJG code
+# accurate, we simply make all of them depend on the only files that
+# we are ever going to change, and on all the .h files that must be copied up.
+# This is too conservative, but only hurts us if we are changing our own
+# j*.h files, which happens only rarely during development.
+
+JDEP=$(AK) $(jconfig_h) $(jerror_h) $(jmorecfg_h) $(JHCOPY)
+
+# Code common to compression and decompression.
+
+jpegc_=jcomapi.$(OBJ) jutils.$(OBJ) sjpegerr.$(OBJ) jmemmgr.$(OBJ)
+jpegc.dev: $(JPEG_MAK) $(ECHOGS_XE) $(jpegc_)
+ $(SETMOD) jpegc $(jpegc_)
+
+jcomapi.$(OBJ): $(JSRC)jcomapi.c $(JDEP)
+ $(CP_) $(JSRC)jcomapi.c .
+ $(CCCJ) jcomapi.c
+ $(RM_) jcomapi.c
+
+jutils.$(OBJ): $(JSRC)jutils.c $(JDEP)
+ $(CP_) $(JSRC)jutils.c .
+ $(CCCJ) jutils.c
+ $(RM_) jutils.c
+
+# Note that sjpegerr replaces jerror.
+sjpegerr.$(OBJ): sjpegerr.c $(JDEP)
+ $(CCCF) sjpegerr.c
+
+jmemmgr.$(OBJ): $(JSRC)jmemmgr.c $(JDEP)
+ $(CP_) $(JSRC)jmemmgr.c .
+ $(CCCJ) jmemmgr.c
+ $(RM_) jmemmgr.c
+
+# Encoding (compression) code.
+
+jpege.dev: jpege$(JVERSION).dev
+ $(CP_) jpege$(JVERSION).dev jpege.dev
+
+jpege5=jcapi.$(OBJ)
+jpege6=jcapimin.$(OBJ) jcapistd.$(OBJ) jcinit.$(OBJ)
+
+jpege_1=jccoefct.$(OBJ) jccolor.$(OBJ) jcdctmgr.$(OBJ)
+jpege_2=jchuff.$(OBJ) jcmainct.$(OBJ) jcmarker.$(OBJ) jcmaster.$(OBJ)
+jpege_3=jcparam.$(OBJ) jcprepct.$(OBJ) jcsample.$(OBJ) jfdctint.$(OBJ)
+
+jpege5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege5) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege5 $(jpege5)
+ $(ADDMOD) jpege5 -include jpegc
+ $(ADDMOD) jpege5 -obj $(jpege_1)
+ $(ADDMOD) jpege5 -obj $(jpege_2)
+ $(ADDMOD) jpege5 -obj $(jpege_3)
+
+jpege6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege6) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege6 $(jpege6)
+ $(ADDMOD) jpege6 -include jpegc
+ $(ADDMOD) jpege6 -obj $(jpege_1)
+ $(ADDMOD) jpege6 -obj $(jpege_2)
+ $(ADDMOD) jpege6 -obj $(jpege_3)
+
+# jcapi.c is v5* only
+jcapi.$(OBJ): $(JSRC)jcapi.c $(JDEP)
+ $(CP_) $(JSRC)jcapi.c .
+ $(CCCJ) jcapi.c
+ $(RM_) jcapi.c
+
+# jcapimin.c is new in v6
+jcapimin.$(OBJ): $(JSRC)jcapimin.c $(JDEP)
+ $(CP_) $(JSRC)jcapimin.c .
+ $(CCCJ) jcapimin.c
+ $(RM_) jcapimin.c
+
+# jcapistd.c is new in v6
+jcapistd.$(OBJ): $(JSRC)jcapistd.c $(JDEP)
+ $(CP_) $(JSRC)jcapistd.c .
+ $(CCCJ) jcapistd.c
+ $(RM_) jcapistd.c
+
+# jcinit.c is new in v6
+jcinit.$(OBJ): $(JSRC)jcinit.c $(JDEP)
+ $(CP_) $(JSRC)jcinit.c .
+ $(CCCJ) jcinit.c
+ $(RM_) jcinit.c
+
+jccoefct.$(OBJ): $(JSRC)jccoefct.c $(JDEP)
+ $(CP_) $(JSRC)jccoefct.c .
+ $(CCCJ) jccoefct.c
+ $(RM_) jccoefct.c
+
+jccolor.$(OBJ): $(JSRC)jccolor.c $(JDEP)
+ $(CP_) $(JSRC)jccolor.c .
+ $(CCCJ) jccolor.c
+ $(RM_) jccolor.c
+
+jcdctmgr.$(OBJ): $(JSRC)jcdctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jcdctmgr.c .
+ $(CCCJ) jcdctmgr.c
+ $(RM_) jcdctmgr.c
+
+jchuff.$(OBJ): $(JSRC)jchuff.c $(JDEP)
+ $(CP_) $(JSRC)jchuff.c .
+ $(CCCJ) jchuff.c
+ $(RM_) jchuff.c
+
+jcmainct.$(OBJ): $(JSRC)jcmainct.c $(JDEP)
+ $(CP_) $(JSRC)jcmainct.c .
+ $(CCCJ) jcmainct.c
+ $(RM_) jcmainct.c
+
+jcmarker.$(OBJ): $(JSRC)jcmarker.c $(JDEP)
+ $(CP_) $(JSRC)jcmarker.c .
+ $(CCCJ) jcmarker.c
+ $(RM_) jcmarker.c
+
+jcmaster.$(OBJ): $(JSRC)jcmaster.c $(JDEP)
+ $(CP_) $(JSRC)jcmaster.c .
+ $(CCCJ) jcmaster.c
+ $(RM_) jcmaster.c
+
+jcparam.$(OBJ): $(JSRC)jcparam.c $(JDEP)
+ $(CP_) $(JSRC)jcparam.c .
+ $(CCCJ) jcparam.c
+ $(RM_) jcparam.c
+
+jcprepct.$(OBJ): $(JSRC)jcprepct.c $(JDEP)
+ $(CP_) $(JSRC)jcprepct.c .
+ $(CCCJ) jcprepct.c
+ $(RM_) jcprepct.c
+
+jcsample.$(OBJ): $(JSRC)jcsample.c $(JDEP)
+ $(CP_) $(JSRC)jcsample.c .
+ $(CCCJ) jcsample.c
+ $(RM_) jcsample.c
+
+jfdctint.$(OBJ): $(JSRC)jfdctint.c $(JDEP)
+ $(CP_) $(JSRC)jfdctint.c .
+ $(CCCJ) jfdctint.c
+ $(RM_) jfdctint.c
+
+# Decompression code
+
+jpegd.dev: jpegd$(JVERSION).dev
+ $(CP_) jpegd$(JVERSION).dev jpegd.dev
+
+jpegd5=jdapi.$(OBJ)
+jpegd6=jdapimin.$(OBJ) jdapistd.$(OBJ) jdinput.$(OBJ) jdphuff.$(OBJ)
+
+jpegd_1=jdcoefct.$(OBJ) jdcolor.$(OBJ)
+jpegd_2=jddctmgr.$(OBJ) jdhuff.$(OBJ) jdmainct.$(OBJ) jdmarker.$(OBJ)
+jpegd_3=jdmaster.$(OBJ) jdpostct.$(OBJ) jdsample.$(OBJ) jidctint.$(OBJ)
+
+jpegd5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd5) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd5 $(jpegd5)
+ $(ADDMOD) jpegd5 -include jpegc
+ $(ADDMOD) jpegd5 -obj $(jpegd_1)
+ $(ADDMOD) jpegd5 -obj $(jpegd_2)
+ $(ADDMOD) jpegd5 -obj $(jpegd_3)
+
+jpegd6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd6) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd6 $(jpegd6)
+ $(ADDMOD) jpegd6 -include jpegc
+ $(ADDMOD) jpegd6 -obj $(jpegd_1)
+ $(ADDMOD) jpegd6 -obj $(jpegd_2)
+ $(ADDMOD) jpegd6 -obj $(jpegd_3)
+
+# jdapi.c is v5* only
+jdapi.$(OBJ): $(JSRC)jdapi.c $(JDEP)
+ $(CP_) $(JSRC)jdapi.c .
+ $(CCCJ) jdapi.c
+ $(RM_) jdapi.c
+
+# jdapimin.c is new in v6
+jdapimin.$(OBJ): $(JSRC)jdapimin.c $(JDEP)
+ $(CP_) $(JSRC)jdapimin.c .
+ $(CCCJ) jdapimin.c
+ $(RM_) jdapimin.c
+
+# jdapistd.c is new in v6
+jdapistd.$(OBJ): $(JSRC)jdapistd.c $(JDEP)
+ $(CP_) $(JSRC)jdapistd.c .
+ $(CCCJ) jdapistd.c
+ $(RM_) jdapistd.c
+
+jdcoefct.$(OBJ): $(JSRC)jdcoefct.c $(JDEP)
+ $(CP_) $(JSRC)jdcoefct.c .
+ $(CCCJ) jdcoefct.c
+ $(RM_) jdcoefct.c
+
+jdcolor.$(OBJ): $(JSRC)jdcolor.c $(JDEP)
+ $(CP_) $(JSRC)jdcolor.c .
+ $(CCCJ) jdcolor.c
+ $(RM_) jdcolor.c
+
+jddctmgr.$(OBJ): $(JSRC)jddctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jddctmgr.c .
+ $(CCCJ) jddctmgr.c
+ $(RM_) jddctmgr.c
+
+jdhuff.$(OBJ): $(JSRC)jdhuff.c $(JDEP)
+ $(CP_) $(JSRC)jdhuff.c .
+ $(CCCJ) jdhuff.c
+ $(RM_) jdhuff.c
+
+# jdinput.c is new in v6
+jdinput.$(OBJ): $(JSRC)jdinput.c $(JDEP)
+ $(CP_) $(JSRC)jdinput.c .
+ $(CCCJ) jdinput.c
+ $(RM_) jdinput.c
+
+jdmainct.$(OBJ): $(JSRC)jdmainct.c $(JDEP)
+ $(CP_) $(JSRC)jdmainct.c .
+ $(CCCJ) jdmainct.c
+ $(RM_) jdmainct.c
+
+jdmarker.$(OBJ): $(JSRC)jdmarker.c $(JDEP)
+ $(CP_) $(JSRC)jdmarker.c .
+ $(CCCJ) jdmarker.c
+ $(RM_) jdmarker.c
+
+jdmaster.$(OBJ): $(JSRC)jdmaster.c $(JDEP)
+ $(CP_) $(JSRC)jdmaster.c .
+ $(CCCJ) jdmaster.c
+ $(RM_) jdmaster.c
+
+# jdphuff.c is new in v6
+jdphuff.$(OBJ): $(JSRC)jdphuff.c $(JDEP)
+ $(CP_) $(JSRC)jdphuff.c .
+ $(CCCJ) jdphuff.c
+ $(RM_) jdphuff.c
+
+jdpostct.$(OBJ): $(JSRC)jdpostct.c $(JDEP)
+ $(CP_) $(JSRC)jdpostct.c .
+ $(CCCJ) jdpostct.c
+ $(RM_) jdpostct.c
+
+jdsample.$(OBJ): $(JSRC)jdsample.c $(JDEP)
+ $(CP_) $(JSRC)jdsample.c .
+ $(CCCJ) jdsample.c
+ $(RM_) jdsample.c
+
+jidctint.$(OBJ): $(JSRC)jidctint.c $(JDEP)
+ $(CP_) $(JSRC)jidctint.c .
+ $(CCCJ) jidctint.c
+ $(RM_) jidctint.c
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for PNG (Portable Network Graphics) code.
+
+# This partial makefile compiles the png library for use in the Ghostscript
+# PNG drivers. You can get the source code for this library from:
+# ftp://swrinde.nde.swri.edu/pub/png/src/
+# The makefile is known to work with the following library versions:
+# 0.89, 0.90, 0.95, and 0.96. NOTE: the archive for libpng 0.95 may
+# be inconsistent: if you have compilation problems, use an older version.
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+#
+# The specification for the PNG file format is available from:
+# http://www.group42.com/png.htm
+# http://www.w3.org/pub/WWW/TR/WD-png
+
+# Define the name of this makefile.
+LIBPNG_MAK=libpng.mak
+
+# PSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the PNG library sources are stored.
+#PSRCDIR=libpng
+# PVERSION is defined in the platform-specific makefile, not here,
+# as the libpng version number ("89", "90", "95", or "96").
+#PVERSION=96
+
+PSRC=$(PSRCDIR)$(D)
+# CCCP is defined in gs.mak.
+#CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR)
+
+# We keep all of the PNG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+PDEP=$(AK)
+
+png_1=png.$(OBJ) pngmem.$(OBJ) pngerror.$(OBJ)
+png_2=pngtrans.$(OBJ) pngwrite.$(OBJ) pngwtran.$(OBJ) pngwutil.$(OBJ)
+
+# libpng modules
+
+png.$(OBJ): $(PSRC)png.c $(PDEP)
+ $(CCCP) $(PSRC)png.c
+
+# version 0.89 uses pngwio.c
+pngwio.$(OBJ): $(PSRC)pngwio.c $(PDEP)
+ $(CCCP) $(PSRC)pngwio.c
+
+pngmem.$(OBJ): $(PSRC)pngmem.c $(PDEP)
+ $(CCCP) $(PSRC)pngmem.c
+
+pngerror.$(OBJ): $(PSRC)pngerror.c $(PDEP)
+ $(CCCP) $(PSRC)pngerror.c
+
+pngtrans.$(OBJ): $(PSRC)pngtrans.c $(PDEP)
+ $(CCCP) $(PSRC)pngtrans.c
+
+pngwrite.$(OBJ): $(PSRC)pngwrite.c $(PDEP)
+ $(CCCP) $(PSRC)pngwrite.c
+
+pngwtran.$(OBJ): $(PSRC)pngwtran.c $(PDEP)
+ $(CCCP) $(PSRC)pngwtran.c
+
+pngwutil.$(OBJ): $(PSRC)pngwutil.c $(PDEP)
+ $(CCCP) $(PSRC)pngwutil.c
+
+# Define the version of libpng.dev that we are actually using.
+libpng.dev: $(MAKEFILE) libpng_$(SHARE_LIBPNG).dev
+ $(CP_) libpng_$(SHARE_LIBPNG).dev libpng.dev
+
+# Define the shared version of libpng.
+# Note that it requires libz, which must be searched *after* libpng.
+libpng_1.dev: $(MAKEFILE) $(LIBPNG_MAK) $(ECHOGS_XE) zlibe.dev
+ $(SETMOD) libpng_1 -lib $(LIBPNG_NAME)
+ $(ADDMOD) libpng_1 -include zlibe
+
+# Define the non-shared version of libpng.
+libpng_0.dev: $(LIBPNG_MAK) $(ECHOGS_XE) $(png_1) $(png_2)\
+ zlibe.dev libpng$(PVERSION).dev
+ $(SETMOD) libpng_0 $(png_1)
+ $(ADDMOD) libpng_0 $(png_2)
+ $(ADDMOD) libpng_0 -include zlibe libpng$(PVERSION)
+
+libpng89.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ)
+ $(SETMOD) libpng89 pngwio.$(OBJ)
+
+libpng90.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng90 pngwio.$(OBJ) -include crc32
+
+libpng95.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng95 pngwio.$(OBJ) -include crc32
+
+libpng96.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng96 pngwio.$(OBJ) -include crc32
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for zlib library code.
+
+# This partial makefile compiles the zlib library for use in Ghostscript.
+# You can get the source code for this library from:
+# ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib104.zip (zlib 1.0.4)
+# or zlib-1.0.4.tar.gz
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+
+# Define the name of this makefile.
+ZLIB_MAK=zlib.mak
+
+# ZSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the zlib sources are stored.
+#ZSRCDIR=zlib
+ZSRC=$(ZSRCDIR)$(D)
+# We would like to define
+#CCCZ=$(CCC) -I$(ZSRCDIR) -Dverbose=-1
+# but the Watcom C compiler has strange undocumented restrictions on what can
+# follow a -D=, and it doesn't allow negative numbers. Instead, we define
+# (in gs.mak):
+#CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+# and handle the definition of verbose in a different, more awkward way.
+
+# We keep all of the zlib code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+ZDEP=$(AK)
+
+# Contrary to what some portability bigots assert as fact, C compilers are
+# not consistent about where they start searching for #included files:
+# some always start by looking in the same directory as the .c file being
+# compiled, before using the search path specified with -I on the command
+# line, while others do not do this. For this reason, we must explicitly
+# copy and then delete all the .c files, because they need to obtain our
+# modified version of zutil.h. We must also copy all header files that
+# reference zutil.h directly or indirectly.
+
+# Code common to compression and decompression.
+
+zlibc_=zutil.$(OBJ)
+zlibc.dev: $(ZLIB_MAK) $(ECHOGS_XE) $(zlibc_)
+ $(SETMOD) zlibc $(zlibc_)
+
+zutil.h: $(ZSRC)zutil.h $(ECHOGS_XE)
+ $(EXP)echogs -w zutil.h -x 23 define verbose -s - -1
+ $(EXP)echogs -a zutil.h -+R $(ZSRC)zutil.h
+
+zutil.$(OBJ): $(ZSRC)zutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)zutil.c .
+ $(CCCZ) zutil.c
+ $(RM_) zutil.c
+
+# Encoding (compression) code.
+
+deflate.h: $(ZSRC)deflate.h zutil.h
+ $(CP_) $(ZSRC)deflate.h .
+
+zlibe.dev: $(MAKEFILE) zlibe_$(SHARE_ZLIB).dev
+ $(CP_) zlibe_$(SHARE_ZLIB).dev zlibe.dev
+
+zlibe_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibe_1 -lib $(ZLIB_NAME)
+
+zlibe_=adler32.$(OBJ) deflate.$(OBJ) trees.$(OBJ)
+zlibe_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibe_)
+ $(SETMOD) zlibe_0 $(zlibe_)
+ $(ADDMOD) zlibe_0 -include zlibc
+
+adler32.$(OBJ): $(ZSRC)adler32.c $(ZDEP)
+ $(CP_) $(ZSRC)adler32.c .
+ $(CCCZ) adler32.c
+ $(RM_) adler32.c
+
+deflate.$(OBJ): $(ZSRC)deflate.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)deflate.c .
+ $(CCCZ) deflate.c
+ $(RM_) deflate.c
+
+trees.$(OBJ): $(ZSRC)trees.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)trees.c .
+ $(CCCZ) trees.c
+ $(RM_) trees.c
+
+# The zlib filters per se don't need crc32, but libpng versions starting
+# with 0.90 do.
+
+crc32.dev: $(MAKEFILE) crc32_$(SHARE_ZLIB).dev
+ $(CP_) crc32_$(SHARE_ZLIB).dev crc32.dev
+
+crc32_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) crc32_1 -lib $(ZLIB_NAME)
+
+crc32_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) crc32.$(OBJ)
+ $(SETMOD) crc32_0 crc32.$(OBJ)
+
+crc32.$(OBJ): $(ZSRC)crc32.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)crc32.c .
+ $(CCCZ) crc32.c
+ $(RM_) crc32.c
+
+# Decoding (decompression) code.
+
+zlibd.dev: $(MAKEFILE) zlibd_$(SHARE_ZLIB).dev
+ $(CP_) zlibd_$(SHARE_ZLIB).dev zlibd.dev
+
+zlibd_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibd_1 -lib $(ZLIB_NAME)
+
+zlibd1_=infblock.$(OBJ) infcodes.$(OBJ) inffast.$(OBJ)
+zlibd2_=inflate.$(OBJ) inftrees.$(OBJ) infutil.$(OBJ)
+zlibd_ = $(zlibd1_) $(zlibd2_)
+zlibd_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibd_)
+ $(SETMOD) zlibd_0 $(zlibd1_)
+ $(ADDMOD) zlibd_0 -obj $(zlibd2_)
+ $(ADDMOD) zlibd_0 -include zlibc
+
+infblock.$(OBJ): $(ZSRC)infblock.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infblock.c .
+ $(CCCZ) infblock.c
+ $(RM_) infblock.c
+
+infcodes.$(OBJ): $(ZSRC)infcodes.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infcodes.c .
+ $(CCCZ) infcodes.c
+ $(RM_) infcodes.c
+
+inffast.$(OBJ): $(ZSRC)inffast.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inffast.c .
+ $(CCCZ) inffast.c
+ $(RM_) inffast.c
+
+inflate.$(OBJ): $(ZSRC)inflate.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inflate.c .
+ $(CCCZ) inflate.c
+ $(RM_) inflate.c
+
+inftrees.$(OBJ): $(ZSRC)inftrees.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inftrees.c .
+ $(CCCZ) inftrees.c
+ $(RM_) inftrees.c
+
+infutil.$(OBJ): $(ZSRC)infutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infutil.c .
+ $(CCCZ) infutil.c
+ $(RM_) infutil.c
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for device drivers.
+
+# Define the name of this makefile.
+DEVS_MAK=devs.mak
+
+###### --------------------------- Catalog -------------------------- ######
+
+# It is possible to build configurations with an arbitrary collection of
+# device drivers, although some drivers are supported only on a subset
+# of the target platforms. The currently available drivers are:
+
+# MS-DOS displays (note: not usable with Desqview/X):
+# MS-DOS EGA and VGA:
+# ega EGA (640x350, 16-color)
+# vga VGA (640x480, 16-color)
+# MS-DOS SuperVGA:
+# * ali SuperVGA using Avance Logic Inc. chipset, 256-color modes
+# * atiw ATI Wonder SuperVGA, 256-color modes
+# * s3vga SuperVGA using S3 86C911 chip (e.g., Diamond Stealth board)
+# svga16 Generic SuperVGA in 800x600, 16-color mode
+# * tseng SuperVGA using Tseng Labs ET3000/4000 chips, 256-color modes
+# * tvga SuperVGA using Trident chipset, 256-color modes
+# ****** NOTE: The vesa device does not work with the Watcom (32-bit MS-DOS)
+# ****** compiler or executable.
+# vesa SuperVGA with VESA standard API driver
+# MS-DOS other:
+# bgi Borland Graphics Interface (CGA) [MS-DOS only]
+# * herc Hercules Graphics display [MS-DOS only]
+# * pe Private Eye display
+# Other displays:
+# MS Windows:
+# mswindll Microsoft Windows 3.1 DLL [MS Windows only]
+# mswinprn Microsoft Windows 3.0, 3.1 DDB printer [MS Windows only]
+# mswinpr2 Microsoft Windows 3.0, 3.1 DIB printer [MS Windows only]
+# OS/2:
+# * os2pm OS/2 Presentation Manager [OS/2 only]
+# * os2dll OS/2 DLL bitmap [OS/2 only]
+# * os2prn OS/2 printer [OS/2 only]
+# Unix and VMS:
+# ****** NOTE: For direct frame buffer addressing under SCO Unix or Xenix,
+# ****** edit the definition of EGAVGA below.
+# * att3b1 AT&T 3b1/Unixpc monochrome display [3b1 only]
+# * lvga256 Linux vgalib, 256-color VGA modes [Linux only]
+# * sonyfb Sony Microsystems monochrome display [Sony only]
+# * sunview SunView window system [SunOS only]
+# + vgalib Linux PC with VGALIB [Linux only]
+# x11 X Windows version 11, release >=4 [Unix and VMS only]
+# x11alpha X Windows masquerading as a device with alpha capability
+# x11cmyk X Windows masquerading as a 1-bit-per-plane CMYK device
+# x11gray2 X Windows as a 2-bit gray-scale device
+# x11mono X Windows masquerading as a black-and-white device
+# Platform-independent:
+# * sxlcrt CRT sixels, e.g. for VT240-like terminals
+# Printers:
+# * ap3250 Epson AP3250 printer
+# * appledmp Apple Dot Matrix Printer (should also work with Imagewriter)
+# bj10e Canon BubbleJet BJ10e
+# * bj200 Canon BubbleJet BJ200
+# * bjc600 Canon Color BubbleJet BJC-600, BJC-4000 and BJC-70
+# also good for Apple printers like the StyleWriter 2x00
+# * bjc800 Canon Color BubbleJet BJC-800
+# * ccr CalComp Raster format
+# * cdeskjet H-P DeskJet 500C with 1 bit/pixel color
+# * cdjcolor H-P DeskJet 500C with 24 bit/pixel color and
+# high-quality color (Floyd-Steinberg) dithering;
+# also good for DeskJet 540C and Citizen Projet IIc (-r200x300)
+# * cdjmono H-P DeskJet 500C printing black only;
+# also good for DeskJet 510, 520, and 540C (black only)
+# * cdj500 H-P DeskJet 500C (same as cdjcolor)
+# * cdj550 H-P DeskJet 550C/560C/660C/660Cse
+# * cp50 Mitsubishi CP50 color printer
+# * declj250 alternate DEC LJ250 driver
+# + deskjet H-P DeskJet and DeskJet Plus
+# djet500 H-P DeskJet 500; use -r600 for DJ 600 series
+# * djet500c H-P DeskJet 500C alternate driver
+# (does not work on 550C or 560C)
+# * dnj650c H-P DesignJet 650C
+# epson Epson-compatible dot matrix printers (9- or 24-pin)
+# * eps9mid Epson-compatible 9-pin, interleaved lines
+# (intermediate resolution)
+# * eps9high Epson-compatible 9-pin, interleaved lines
+# (triple resolution)
+# * epsonc Epson LQ-2550 and Fujitsu 3400/2400/1200 color printers
+# * ibmpro IBM 9-pin Proprinter
+# * imagen Imagen ImPress printers
+# * iwhi Apple Imagewriter in high-resolution mode
+# * iwlo Apple Imagewriter in low-resolution mode
+# * iwlq Apple Imagewriter LQ in 320 x 216 dpi mode
+# * jetp3852 IBM Jetprinter ink-jet color printer (Model #3852)
+# + laserjet H-P LaserJet
+# * la50 DEC LA50 printer
+# * la70 DEC LA70 printer
+# * la70t DEC LA70 printer with low-resolution text enhancement
+# * la75 DEC LA75 printer
+# * la75plus DEC LA75plus printer
+# * lbp8 Canon LBP-8II laser printer
+# * lips3 Canon LIPS III laser printer in English (CaPSL) mode
+# * ln03 DEC LN03 printer
+# * lj250 DEC LJ250 Companion color printer
+# + ljet2p H-P LaserJet IId/IIp/III* with TIFF compression
+# + ljet3 H-P LaserJet III* with Delta Row compression
+# + ljet3d H-P LaserJet IIID with duplex capability
+# + ljet4 H-P LaserJet 4 (defaults to 600 dpi)
+# + lj4dith H-P LaserJet 4 with Floyd-Steinberg dithering
+# + ljetplus H-P LaserJet Plus
+# lj5mono H-P LaserJet 5 & 6 family (PCL XL), bitmap:
+# see below for restrictions & advice
+# lj5gray H-P LaserJet 5 & 6 family, gray-scale bitmap;
+# see below for restrictions & advice
+# * lp2563 H-P 2563B line printer
+# * lp8000 Epson LP-8000 laser printer
+# * lq850 Epson LQ850 printer at 360 x 360 DPI resolution;
+# also good for Canon BJ300 with LQ850 emulation
+# * m8510 C.Itoh M8510 printer
+# * necp6 NEC P6/P6+/P60 printers at 360 x 360 DPI resolution
+# * nwp533 Sony Microsystems NWP533 laser printer [Sony only]
+# * oce9050 OCE 9050 printer
+# * oki182 Okidata MicroLine 182
+# * okiibm Okidata MicroLine IBM-compatible printers
+# * paintjet alternate H-P PaintJet color printer
+# * pj H-P PaintJet XL driver
+# * pjetxl alternate H-P PaintJet XL driver
+# * pjxl H-P PaintJet XL color printer
+# * pjxl300 H-P PaintJet XL300 color printer;
+# also good for PaintJet 1200C
+# (pxlmono) H-P black-and-white PCL XL printers (LaserJet 5 and 6 family)
+# (pxlcolor) H-P color PCL XL printers (none available yet)
+# * r4081 Ricoh 4081 laser printer
+# * sj48 StarJet 48 inkjet printer
+# * sparc SPARCprinter
+# * st800 Epson Stylus 800 printer
+# * stcolor Epson Stylus Color
+# * t4693d2 Tektronix 4693d color printer, 2 bits per R/G/B component
+# * t4693d4 Tektronix 4693d color printer, 4 bits per R/G/B component
+# * t4693d8 Tektronix 4693d color printer, 8 bits per R/G/B component
+# * tek4696 Tektronix 4695/4696 inkjet plotter
+# * uniprint Unified printer driver -- Configurable Color ESC/P-,
+# ESC/P2-, HP-RTL/PCL mono/color driver
+# * xes Xerox XES printers (2700, 3700, 4045, etc.)
+# Fax systems:
+# * dfaxhigh DigiBoard, Inc.'s DigiFAX software format (high resolution)
+# * dfaxlow DigiFAX low (normal) resolution
+# Fax file format:
+# ****** NOTE: all of these drivers adjust the page size to match
+# ****** one of the three CCITT standard sizes (U.S. letter with A4 width,
+# ****** A4, or B4).
+# faxg3 Group 3 fax, with EOLs but no header or EOD
+# faxg32d Group 3 2-D fax, with EOLs but no header or EOD
+# faxg4 Group 4 fax, with EOLs but no header or EOD
+# tiffcrle TIFF "CCITT RLE 1-dim" (= Group 3 fax with no EOLs)
+# tiffg3 TIFF Group 3 fax (with EOLs)
+# tiffg32d TIFF Group 3 2-D fax
+# tiffg4 TIFF Group 4 fax
+# High-level file formats:
+# epswrite EPS output (like PostScript Distillery)
+# pdfwrite PDF output (like Adobe Acrobat Distiller)
+# pswrite PostScript output (like PostScript Distillery)
+# pxlmono Black-and-white PCL XL
+# pxlcolor Color PCL XL
+# Other raster file formats and devices:
+# bit Plain bits, monochrome
+# bitrgb Plain bits, RGB
+# bitcmyk Plain bits, CMYK
+# bmpmono Monochrome MS Windows .BMP file format
+# bmp16 4-bit (EGA/VGA) .BMP file format
+# bmp256 8-bit (256-color) .BMP file format
+# bmp16m 24-bit .BMP file format
+# cgmmono Monochrome (black-and-white) CGM -- LOW LEVEL OUTPUT ONLY
+# cgm8 8-bit (256-color) CGM -- DITTO
+# cgm24 24-bit color CGM -- DITTO
+# * cif CIF file format for VLSI
+# jpeg JPEG format, RGB output
+# jpeggray JPEG format, gray output
+# miff24 ImageMagick MIFF format, 24-bit direct color, RLE compressed
+# * mgrmono 1-bit monochrome MGR devices
+# * mgrgray2 2-bit gray scale MGR devices
+# * mgrgray4 4-bit gray scale MGR devices
+# * mgrgray8 8-bit gray scale MGR devices
+# * mgr4 4-bit (VGA) color MGR devices
+# * mgr8 8-bit color MGR devices
+# pcxmono PCX file format, monochrome (1-bit black and white)
+# pcxgray PCX file format, 8-bit gray scale
+# pcx16 PCX file format, 4-bit planar (EGA/VGA) color
+# pcx256 PCX file format, 8-bit chunky color
+# pcx24b PCX file format, 24-bit color (3 8-bit planes)
+# pcxcmyk PCX file format, 4-bit chunky CMYK color
+# pbm Portable Bitmap (plain format)
+# pbmraw Portable Bitmap (raw format)
+# pgm Portable Graymap (plain format)
+# pgmraw Portable Graymap (raw format)
+# pgnm Portable Graymap (plain format), optimizing to PBM if possible
+# pgnmraw Portable Graymap (raw format), optimizing to PBM if possible
+# pnm Portable Pixmap (plain format) (RGB), optimizing to PGM or PBM
+# if possible
+# pnmraw Portable Pixmap (raw format) (RGB), optimizing to PGM or PBM
+# if possible
+# ppm Portable Pixmap (plain format) (RGB)
+# ppmraw Portable Pixmap (raw format) (RGB)
+# pkm Portable inKmap (plain format) (4-bit CMYK => RGB)
+# pkmraw Portable inKmap (raw format) (4-bit CMYK => RGB)
+# pngmono Monochrome Portable Network Graphics (PNG)
+# pnggray 8-bit gray Portable Network Graphics (PNG)
+# png16 4-bit color Portable Network Graphics (PNG)
+# png256 8-bit color Portable Network Graphics (PNG)
+# png16m 24-bit color Portable Network Graphics (PNG)
+# psmono PostScript (Level 1) monochrome image
+# psgray PostScript (Level 1) 8-bit gray image
+# sgirgb SGI RGB pixmap format
+# tiff12nc TIFF 12-bit RGB, no compression
+# tiff24nc TIFF 24-bit RGB, no compression (NeXT standard format)
+# tifflzw TIFF LZW (tag = 5) (monochrome)
+# tiffpack TIFF PackBits (tag = 32773) (monochrome)
+
+# User-contributed drivers marked with * require hardware or software
+# that is not available to Aladdin Enterprises. Please contact the
+# original contributors, not Aladdin Enterprises, if you have questions.
+# Contact information appears in the driver entry below.
+#
+# Drivers marked with a + are maintained by Aladdin Enterprises with
+# the assistance of users, since Aladdin Enterprises doesn't have access to
+# the hardware for these either.
+
+# If you add drivers, it would be nice if you kept each list
+# in alphabetical order.
+
+###### ----------------------- End of catalog ----------------------- ######
+
+# As noted in gs.mak, DEVICE_DEVS and DEVICE_DEVS1..15 select the devices
+# that should be included in a given configuration. By convention, these
+# are used as follows. Each of these must be limited to about 10 devices
+# so as not to overflow the 120 character limit on MS-DOS command lines.
+# DEVICE_DEVS - the default device, and any display devices.
+# DEVICE_DEVS1 - additional display devices if needed.
+# DEVICE_DEVS2 - dot matrix printers.
+# DEVICE_DEVS3 - H-P monochrome printers.
+# DEVICE_DEVS4 - H-P color printers.
+# DEVICE_DEVS5 - additional H-P printers if needed.
+# DEVICE_DEVS6 - other ink-jet and laser printers.
+# DEVICE_DEVS7 - fax file formats.
+# DEVICE_DEVS8 - PCX file formats.
+# DEVICE_DEVS9 - PBM/PGM/PPM file formats.
+# DEVICE_DEVS10 - black-and-white TIFF file formats.
+# DEVICE_DEVS11 - BMP and color TIFF file formats.
+# DEVICE_DEVS12 - PostScript image and 'bit' file formats.
+# DEVICE_DEVS13 - PNG file formats.
+# DEVICE_DEVS14 - CGM, JPEG, and MIFF file formats.
+# DEVICE_DEVS15 - high-level (PostScript and PDF) file formats.
+# Feel free to disregard this convention if it gets in your way.
+
+# If you want to add a new device driver, the examples below should be
+# enough of a guide to the correct form for the makefile rules.
+# Note that all drivers other than displays must include page.dev in their
+# dependencies and use $(SETPDEV) rather than $(SETDEV) in their rule bodies.
+
+# All device drivers depend on the following:
+GDEV=$(AK) $(ECHOGS_XE) $(gserrors_h) $(gx_h) $(gxdevice_h)
+
+# "Printer" drivers depend on the following:
+PDEVH=$(AK) $(gdevprn_h)
+
+# Define the header files for device drivers. Every header file used by
+# more than one device driver family must be listed here.
+gdev8bcm_h=gdev8bcm.h
+gdevpccm_h=gdevpccm.h
+gdevpcfb_h=gdevpcfb.h $(dos__h)
+gdevpcl_h=gdevpcl.h
+gdevsvga_h=gdevsvga.h
+gdevx_h=gdevx.h
+
+###### ----------------------- Device support ----------------------- ######
+
+# Provide a mapping between StandardEncoding and ISOLatin1Encoding.
+gdevemap.$(OBJ): gdevemap.c $(AK) $(std_h)
+
+# Implement dynamic color management for 8-bit mapped color displays.
+gdev8bcm.$(OBJ): gdev8bcm.c $(AK) \
+ $(gx_h) $(gxdevice_h) $(gdev8bcm_h)
+
+###### ------------------- MS-DOS display devices ------------------- ######
+
+# There are really only three drivers: an EGA/VGA driver (4 bit-planes,
+# plane-addressed), a SuperVGA driver (8 bit-planes, byte addressed),
+# and a special driver for the S3 chip.
+
+# PC display color mapping
+gdevpccm.$(OBJ): gdevpccm.c $(AK) \
+ $(gx_h) $(gsmatrix_h) $(gxdevice_h) $(gdevpccm_h)
+
+### ----------------------- EGA and VGA displays ----------------------- ###
+
+# The shared MS-DOS makefile defines PCFBASM as either gdevegaa.$(OBJ)
+# or an empty string.
+
+gdevegaa.$(OBJ): gdevegaa.asm
+
+# NOTE: for direct frame buffer addressing under SCO Unix or Xenix,
+# change gdevevga to gdevsco in the following line. Also, since
+# SCO's /bin/as does not support the "out" instructions, you must build
+# the gnu assembler and have it on your path as "as".
+EGAVGA=gdevevga.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+#EGAVGA=gdevsco.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevevga.$(OBJ): gdevevga.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+ $(CCD) gdevevga.c
+
+gdevsco.$(OBJ): gdevsco.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+
+# Common code for MS-DOS and SCO.
+gdevpcfb.$(OBJ): gdevpcfb.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gdevpccm_h) $(gdevpcfb_h) $(gsparam_h)
+ $(CCD) gdevpcfb.c
+
+# The EGA/VGA family includes EGA and VGA. Many SuperVGAs in 800x600,
+# 16-color mode can share the same code; see the next section below.
+
+ega.dev: $(EGAVGA)
+ $(SETDEV) ega $(EGAVGA)
+
+vga.dev: $(EGAVGA)
+ $(SETDEV) vga $(EGAVGA)
+
+### ------------------------- SuperVGA displays ------------------------ ###
+
+# SuperVGA displays in 16-color, 800x600 mode are really just slightly
+# glorified VGA's, so we can handle them all with a single driver.
+# The way to select them on the command line is with
+# -sDEVICE=svga16 -dDisplayMode=NNN
+# where NNN is the display mode in decimal. See use.txt for the modes
+# for some popular display chipsets.
+
+svga16.dev: $(EGAVGA)
+ $(SETDEV) svga16 $(EGAVGA)
+
+# More capable SuperVGAs have a wide variety of slightly differing
+# interfaces, so we need a separate driver for each one.
+
+SVGA=gdevsvga.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevsvga.$(OBJ): gdevsvga.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gsparam_h) $(gxarith_h) $(gdevpccm_h) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevsvga.c
+
+# The SuperVGA family includes: Avance Logic Inc., ATI Wonder, S3,
+# Trident, Tseng ET3000/4000, and VESA.
+
+ali.dev: $(SVGA)
+ $(SETDEV) ali $(SVGA)
+
+atiw.dev: $(SVGA)
+ $(SETDEV) atiw $(SVGA)
+
+tseng.dev: $(SVGA)
+ $(SETDEV) tseng $(SVGA)
+
+tvga.dev: $(SVGA)
+ $(SETDEV) tvga $(SVGA)
+
+vesa.dev: $(SVGA)
+ $(SETDEV) vesa $(SVGA)
+
+# The S3 driver doesn't share much code with the others.
+
+s3vga_=gdevs3ga.$(OBJ) gdevsvga.$(OBJ) gdevpccm.$(OBJ)
+s3vga.dev: $(SVGA) $(s3vga_)
+ $(SETDEV) s3vga $(SVGA)
+ $(ADDMOD) s3vga -obj $(s3vga_)
+
+gdevs3ga.$(OBJ): gdevs3ga.c $(GDEV) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevs3ga.c
+
+### ------------ The BGI (Borland Graphics Interface) device ----------- ###
+
+cgaf.$(OBJ): $(BGIDIR)\cga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\cga
+
+egavgaf.$(OBJ): $(BGIDIR)\egavga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\egavga
+
+# Include egavgaf.$(OBJ) for debugging only.
+bgi_=gdevbgi.$(OBJ) cgaf.$(OBJ)
+bgi.dev: $(bgi_)
+ $(SETDEV) bgi $(bgi_)
+ $(ADDMOD) bgi -lib $(LIBDIR)\graphics
+
+gdevbgi.$(OBJ): gdevbgi.c $(GDEV) $(MAKEFILE) $(gxxfont_h)
+ $(CCC) -DBGI_LIB="$(BGIDIRSTR)" gdevbgi.c
+
+### ------------------- The Hercules Graphics display ------------------- ###
+
+herc_=gdevherc.$(OBJ)
+herc.dev: $(herc_)
+ $(SETDEV) herc $(herc_)
+
+gdevherc.$(OBJ): gdevherc.c $(GDEV) $(dos__h) $(gsmatrix_h) $(gxbitmap_h)
+ $(CCC) gdevherc.c
+
+### ---------------------- The Private Eye display ---------------------- ###
+### Note: this driver was contributed by a user: ###
+### please contact narf@media-lab.media.mit.edu if you have questions. ###
+
+pe_=gdevpe.$(OBJ)
+pe.dev: $(pe_)
+ $(SETDEV) pe $(pe_)
+
+gdevpe.$(OBJ): gdevpe.c $(GDEV) $(memory__h)
+
+###### ----------------------- Other displays ------------------------ ######
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gsdll_h=gsdll.h
+
+gdevmswn_h=gdevmswn.h $(GDEV)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ gp_mswin.h
+
+gdevmswn.$(OBJ): gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h) \
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(CCCWIN) gdevmswn.c
+
+gdevmsxf.$(OBJ): gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCCWIN) gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+gdevwdib.$(OBJ): gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(CCCWIN) gdevwdib.c
+
+mswindll_=gdevmswn.$(OBJ) gdevmsxf.$(OBJ) gdevwdib.$(OBJ) \
+ gdevemap.$(OBJ) gdevpccm.$(OBJ)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=gdevwprn.$(OBJ) gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+gdevwprn.$(OBJ): gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(CCCWIN) gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+gdevwpr2.$(OBJ): gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) gp_mswin.h
+ $(CCCWIN) gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+gdevpm.$(OBJ): gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) gdevpm.h
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+os2prn.$(OBJ): os2prn.c $(gp_h)
+
+### -------------- The AT&T 3b1 Unixpc monochrome display --------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Andy Fyfe (andy@cs.caltech.edu) if you have questions. ###
+
+att3b1_=gdev3b1.$(OBJ)
+att3b1.dev: $(att3b1_)
+ $(SETDEV) att3b1 $(att3b1_)
+
+gdev3b1.$(OBJ): gdev3b1.c $(GDEV)
+
+### ---------------------- Linux PC with vgalib ------------------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the lvga256 driver, please contact ###
+### Ludger Kunz (ludger.kunz@fernuni-hagen.de). ###
+### For questions about the vgalib driver, please contact ###
+### Erik Talvola (talvola@gnu.ai.mit.edu). ###
+
+lvga256_=gdevl256.$(OBJ)
+lvga256.dev: $(lvga256_)
+ $(SETDEV) lvga256 $(lvga256_)
+ $(ADDMOD) lvga256 -lib vga vgagl
+
+gdevl256.$(OBJ): gdevl256.c $(GDEV)
+
+vgalib_=gdevvglb.$(OBJ) gdevpccm.$(OBJ)
+vgalib.dev: $(vgalib_)
+ $(SETDEV) vgalib $(vgalib_)
+ $(ADDMOD) vgalib -lib vga
+
+gdevvglb.$(OBJ): gdevvglb.c $(GDEV) $(gdevpccm_h) $(gsparam_h)
+
+### ------------------- Sony NeWS frame buffer device ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Mike Smolenski (mike@intertech.com) if you have questions. ###
+
+# This is implemented as a 'printer' device.
+sonyfb_=gdevsnfb.$(OBJ)
+sonyfb.dev: $(sonyfb_) page.dev
+ $(SETPDEV) sonyfb $(sonyfb_)
+
+gdevsnfb.$(OBJ): gdevsnfb.c $(PDEVH)
+
+### ------------------------ The SunView device ------------------------ ###
+### Note: this driver is maintained by a user: if you have questions, ###
+### please contact Andreas Stolcke (stolcke@icsi.berkeley.edu). ###
+
+sunview_=gdevsun.$(OBJ)
+sunview.dev: $(sunview_)
+ $(SETDEV) sunview $(sunview_)
+ $(ADDMOD) sunview -lib suntool sunwindow pixrect
+
+gdevsun.$(OBJ): gdevsun.c $(GDEV) $(malloc__h)\
+ $(gscdefs_h) $(gserrors_h) $(gsmatrix_h)
+
+### -------------------------- The X11 device -------------------------- ###
+
+# Aladdin Enterprises does not support Ghostview. For more information
+# about Ghostview, please contact Tim Theisen (ghostview@cs.wisc.edu).
+
+# See the main makefile for the definition of XLIBS.
+x11_=gdevx.$(OBJ) gdevxini.$(OBJ) gdevxxf.$(OBJ) gdevemap.$(OBJ)
+x11.dev: $(x11_)
+ $(SETDEV) x11 $(x11_)
+ $(ADDMOD) x11 -lib $(XLIBS)
+
+# See the main makefile for the definition of XINCLUDE.
+GDEVX=$(GDEV) x_.h gdevx.h $(MAKEFILE)
+gdevx.$(OBJ): gdevx.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevx.c
+
+gdevxini.$(OBJ): gdevxini.c $(GDEVX) $(math__h) $(memory__h) $(gserrors_h)
+ $(CCC) $(XINCLUDE) gdevxini.c
+
+gdevxxf.$(OBJ): gdevxxf.c $(GDEVX) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCC) $(XINCLUDE) gdevxxf.c
+
+# Alternate X11-based devices to help debug other drivers.
+# x11alpha pretends to have 4 bits of alpha channel.
+# x11cmyk pretends to be a CMYK device with 1 bit each of C,M,Y,K.
+# x11gray2 pretends to be a 2-bit gray-scale device.
+# x11mono pretends to be a black-and-white device.
+x11alt_=$(x11_) gdevxalt.$(OBJ)
+x11alpha.dev: $(x11alt_)
+ $(SETDEV) x11alpha $(x11alt_)
+ $(ADDMOD) x11alpha -lib $(XLIBS)
+
+x11cmyk.dev: $(x11alt_)
+ $(SETDEV) x11cmyk $(x11alt_)
+ $(ADDMOD) x11cmyk -lib $(XLIBS)
+
+x11gray2.dev: $(x11alt_)
+ $(SETDEV) x11gray2 $(x11alt_)
+ $(ADDMOD) x11gray2 -lib $(XLIBS)
+
+x11mono.dev: $(x11alt_)
+ $(SETDEV) x11mono $(x11alt_)
+ $(ADDMOD) x11mono -lib $(XLIBS)
+
+gdevxalt.$(OBJ): gdevxalt.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevxalt.c
+
+### ------------------------- DEC sixel displays ------------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Phil Keegstra (keegstra@tonga.gsfc.nasa.gov) if you have questions. ###
+
+# This is a "printer" device, but it probably shouldn't be.
+# I don't know why the implementor chose to do it this way.
+sxlcrt_=gdevln03.$(OBJ)
+sxlcrt.dev: $(sxlcrt_) page.dev
+ $(SETPDEV) sxlcrt $(sxlcrt_)
+
+###### --------------- Memory-buffered printer devices --------------- ######
+
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users. ###
+### If you have questions about the DMP driver, please contact ###
+### Mark Wedel (master@cats.ucsc.edu). ###
+### If you have questions about the Imagewriter drivers, please contact ###
+### Jonathan Luckey (luckey@rtfm.mlb.fl.us). ###
+### If you have questions about the Imagewriter LQ driver, please ###
+### contact Scott Barker (barkers@cuug.ab.ca). ###
+
+appledmp_=gdevadmp.$(OBJ)
+
+gdevadmp.$(OBJ): gdevadmp.c $(PDEVH)
+
+appledmp.dev: $(appledmp_) page.dev
+ $(SETPDEV) appledmp $(appledmp_)
+
+iwhi.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwhi $(appledmp_)
+
+iwlo.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlo $(appledmp_)
+
+iwlq.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlq $(appledmp_)
+
+### ------------ The Canon BubbleJet BJ10e and BJ200 devices ------------ ###
+
+bj10e_=gdevbj10.$(OBJ)
+
+bj10e.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj10e $(bj10e_)
+
+bj200.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj200 $(bj10e_)
+
+gdevbj10.$(OBJ): gdevbj10.c $(PDEVH)
+
+### ------------- The CalComp Raster Format ----------------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Ernst Muellner (ernst.muellner@oenzl.siemens.de) if you have ###
+### questions. ###
+
+ccr_=gdevccr.$(OBJ)
+ccr.dev: $(ccr_) page.dev
+ $(SETPDEV) ccr $(ccr_)
+
+gdevccr.$(OBJ): gdevccr.c $(PDEVH)
+
+### ----------- The H-P DeskJet and LaserJet printer devices ----------- ###
+
+### These are essentially the same device.
+### NOTE: printing at full resolution (300 DPI) requires a printer
+### with at least 1.5 Mb of memory. 150 DPI only requires .5 Mb.
+### Note that the lj4dith driver is included with the H-P color printer
+### drivers below.
+
+HPPCL=gdevpcl.$(OBJ)
+HPMONO=gdevdjet.$(OBJ) $(HPPCL)
+
+gdevpcl.$(OBJ): gdevpcl.c $(PDEVH) $(gdevpcl_h)
+
+gdevdjet.$(OBJ): gdevdjet.c $(PDEVH) $(gdevpcl_h)
+
+deskjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) deskjet $(HPMONO)
+
+djet500.dev: $(HPMONO) page.dev
+ $(SETPDEV) djet500 $(HPMONO)
+
+laserjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) laserjet $(HPMONO)
+
+ljetplus.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljetplus $(HPMONO)
+
+### Selecting ljet2p provides TIFF (mode 2) compression on LaserJet III,
+### IIIp, IIId, IIIsi, IId, and IIp.
+
+ljet2p.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet2p $(HPMONO)
+
+### Selecting ljet3 provides Delta Row (mode 3) compression on LaserJet III,
+### IIIp, IIId, IIIsi.
+
+ljet3.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3 $(HPMONO)
+
+### Selecting ljet3d also provides duplex printing capability.
+
+ljet3d.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3d $(HPMONO)
+
+### Selecting ljet4 also provides Delta Row compression on LaserJet IV series.
+
+ljet4.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet4 $(HPMONO)
+
+lp2563.dev: $(HPMONO) page.dev
+ $(SETPDEV) lp2563 $(HPMONO)
+
+oce9050.dev: $(HPMONO) page.dev
+ $(SETPDEV) oce9050 $(HPMONO)
+
+### ------------------ The H-P LaserJet 5 and 6 devices ----------------- ###
+
+### These drivers use H-P's new PCL XL printer language, like H-P's
+### LaserJet 5 Enhanced driver for MS Windows. We don't recommend using
+### them:
+### - If you have a LJ 5L or 5P, which isn't a "real" LaserJet 5,
+### use the ljet4 driver instead. (The lj5 drivers won't work.)
+### - If you have any other model of LJ 5 or 6, use the pxlmono
+### driver, which often produces much more compact output.
+
+gdevpxat_h=gdevpxat.h
+gdevpxen_h=gdevpxen.h
+gdevpxop_h=gdevpxop.h
+
+ljet5_=gdevlj56.$(OBJ) $(HPPCL)
+lj5mono.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5mono $(ljet5_)
+
+lj5gray.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5gray $(ljet5_)
+
+gdevlj56.$(OBJ): gdevlj56.c $(PDEVH) $(gdevpcl_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h)
+
+### The H-P DeskJet, PaintJet, and DesignJet family color printer devices.###
+### Note: there are two different 500C drivers, both contributed by users.###
+### If you have questions about the djet500c driver, ###
+### please contact AKayser@et.tudelft.nl. ###
+### If you have questions about the cdj* drivers, ###
+### please contact g.cameron@biomed.abdn.ac.uk. ###
+### If you have questions about the dnj560c driver, ###
+### please contact koert@zen.cais.com. ###
+### If you have questions about the lj4dith driver, ###
+### please contact Eckhard.Rueggeberg@ts.go.dlr.de. ###
+### If you have questions about the BJC600/BJC4000, BJC800, or ESCP ###
+### drivers, please contact Yves.Arrouye@imag.fr. ###
+
+cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+cdeskjet.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdeskjet $(cdeskjet_)
+
+cdjcolor.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjcolor $(cdeskjet_)
+
+cdjmono.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjmono $(cdeskjet_)
+
+cdj500.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj500 $(cdeskjet_)
+
+cdj550.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj550 $(cdeskjet_)
+
+declj250.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) declj250 $(cdeskjet_)
+
+dnj650c.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) dnj650c $(cdeskjet_)
+
+lj4dith.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) lj4dith $(cdeskjet_)
+
+pj.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pj $(cdeskjet_)
+
+pjxl.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl $(cdeskjet_)
+
+pjxl300.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl300 $(cdeskjet_)
+
+# Note: the BJC600 driver also works for the BJC4000.
+bjc600.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc600 $(cdeskjet_)
+
+bjc800.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc800 $(cdeskjet_)
+
+escp.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) escp $(cdeskjet_)
+
+# NB: you can also customise the build if required, using
+# -DBitsPerPixel=<number> if you wish the default to be other than 24
+# for the generic drivers (cdj500, cdj550, pjxl300, pjtest, pjxltest).
+gdevcdj.$(OBJ): gdevcdj.c $(std_h) $(PDEVH) gdevbjc.h\
+ $(gsparam_h) $(gsstate_h) $(gxlum_h)\
+ $(gdevpcl_h)
+
+djet500c_=gdevdjtc.$(OBJ) $(HPPCL)
+djet500c.dev: $(djet500c_) page.dev
+ $(SETPDEV) djet500c $(djet500c_)
+
+gdevdjtc.$(OBJ): gdevdjtc.c $(PDEVH) $(malloc__h) $(gdevpcl_h)
+
+### -------------------- The Mitsubishi CP50 printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Michael Hu (michael@ximage.com) if you have questions. ###
+
+cp50_=gdevcp50.$(OBJ)
+cp50.dev: $(cp50_) page.dev
+ $(SETPDEV) cp50 $(cp50_)
+
+gdevcp50.$(OBJ): gdevcp50.c $(PDEVH)
+
+### ----------------- The generic Epson printer device ----------------- ###
+### Note: most of this code was contributed by users. Please contact ###
+### the following people if you have questions: ###
+### eps9mid - Guenther Thomsen (thomsen@cs.tu-berlin.de) ###
+### eps9high - David Wexelblat (dwex@mtgzfs3.att.com) ###
+### ibmpro - James W. Birdsall (jwbirdsa@picarefy.picarefy.com) ###
+
+epson_=gdevepsn.$(OBJ)
+
+epson.dev: $(epson_) page.dev
+ $(SETPDEV) epson $(epson_)
+
+eps9mid.dev: $(epson_) page.dev
+ $(SETPDEV) eps9mid $(epson_)
+
+eps9high.dev: $(epson_) page.dev
+ $(SETPDEV) eps9high $(epson_)
+
+gdevepsn.$(OBJ): gdevepsn.c $(PDEVH)
+
+### ----------------- The IBM Proprinter printer device ---------------- ###
+
+ibmpro.dev: $(epson_) page.dev
+ $(SETPDEV) ibmpro $(epson_)
+
+### -------------- The Epson LQ-2550 color printer device -------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Dave St. Clair (dave@exlog.com) if you have questions. ###
+
+epsonc_=gdevepsc.$(OBJ)
+epsonc.dev: $(epsonc_) page.dev
+ $(SETPDEV) epsonc $(epsonc_)
+
+gdevepsc.$(OBJ): gdevepsc.c $(PDEVH)
+
+### ------------- The Epson ESC/P 2 language printer devices ------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the Stylus 800 and AP3250 drivers, please contact ###
+### Richard Brown (rab@tauon.ph.unimelb.edu.au). ###
+### For questions about the Stylus Color drivers, please contact ###
+### Gunther Hess (gunther@elmos.de). ###
+
+ESCP2=gdevescp.$(OBJ)
+
+gdevescp.$(OBJ): gdevescp.c $(PDEVH)
+
+ap3250.dev: $(ESCP2) page.dev
+ $(SETPDEV) ap3250 $(ESCP2)
+
+st800.dev: $(ESCP2) page.dev
+ $(SETPDEV) st800 $(ESCP2)
+
+stcolor1_=gdevstc.$(OBJ) gdevstc1.$(OBJ) gdevstc2.$(OBJ)
+stcolor2_=gdevstc3.$(OBJ) gdevstc4.$(OBJ)
+stcolor.dev: $(stcolor1_) $(stcolor2_) page.dev
+ $(SETPDEV) stcolor $(stcolor1_)
+ $(ADDMOD) stcolor -obj $(stcolor2_)
+
+gdevstc.$(OBJ): gdevstc.c gdevstc.h $(PDEVH)
+
+gdevstc1.$(OBJ): gdevstc1.c gdevstc.h $(PDEVH)
+
+gdevstc2.$(OBJ): gdevstc2.c gdevstc.h $(PDEVH)
+
+gdevstc3.$(OBJ): gdevstc3.c gdevstc.h $(PDEVH)
+
+gdevstc4.$(OBJ): gdevstc4.c gdevstc.h $(PDEVH)
+
+### --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+### For questions about this driver, please contact: ###
+### Gunther Hess (gunther@elmos.de) ###
+
+uniprint_=gdevupd.$(OBJ)
+uniprint.dev: $(uniprint_) page.dev
+ $(SETPDEV) uniprint $(uniprint_)
+
+gdevupd.$(OBJ): gdevupd.c $(PDEVH) $(gsparam_h)
+
+### -------------- cdj850 - HP 850c Driver under development ------------- ###
+### Since this driver is in the development-phase it is not distributed ###
+### with ghostscript, but it is available via anonymous ftp from: ###
+### ftp://bonk.ethz.ch ###
+### For questions about this driver, please contact: ###
+### Uli Wortmann (E-Mail address inside the driver-package) ###
+
+cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+cdj850.dev: $(cdeskjet8_) page.dev
+ $(SETPDEV) cdj850 $(cdeskjet8_)
+
+### ------------ The H-P PaintJet color printer device ----------------- ###
+### Note: this driver also supports the DEC LJ250 color printer, which ###
+### has a PaintJet-compatible mode, and the PaintJet XL. ###
+### If you have questions about the XL, please contact Rob Reiss ###
+### (rob@moray.berkeley.edu). ###
+
+PJET=gdevpjet.$(OBJ) $(HPPCL)
+
+gdevpjet.$(OBJ): gdevpjet.c $(PDEVH) $(gdevpcl_h)
+
+lj250.dev: $(PJET) page.dev
+ $(SETPDEV) lj250 $(PJET)
+
+paintjet.dev: $(PJET) page.dev
+ $(SETPDEV) paintjet $(PJET)
+
+pjetxl.dev: $(PJET) page.dev
+ $(SETPDEV) pjetxl $(PJET)
+
+### -------------- Imagen ImPress Laser Printer device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Alan Millar (AMillar@bolis.sf-bay.org) if you have questions. ###
+### Set USE_BYTE_STREAM if using parallel interface; ###
+### Don't set it if using 'ipr' spooler (default). ###
+### You may also add -DA4 if needed for A4 paper. ###
+
+imagen_=gdevimgn.$(OBJ)
+imagen.dev: $(imagen_) page.dev
+ $(SETPDEV) imagen $(imagen_)
+
+gdevimgn.$(OBJ): gdevimgn.c $(PDEVH)
+ $(CCC) gdevimgn.c # for ipr spooler
+# $(CCC) -DUSE_BYTE_STREAM gdevimgn.c # for parallel
+
+### ------- The IBM 3852 JetPrinter color inkjet printer device -------- ###
+### Note: this driver was contributed by users: please contact ###
+### Kevin Gift (kgift@draper.com) if you have questions. ###
+### Note that the paper size that can be addressed by the graphics mode ###
+### used in this driver is fixed at 7-1/2 inches wide (the printable ###
+### width of the jetprinter itself.) ###
+
+jetp3852_=gdev3852.$(OBJ)
+jetp3852.dev: $(jetp3852_) page.dev
+ $(SETPDEV) jetp3852 $(jetp3852_)
+
+gdev3852.$(OBJ): gdev3852.c $(PDEVH) $(gdevpcl_h)
+
+### ---------- The Canon LBP-8II and LIPS III printer devices ---------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about these drivers, please contact ###
+### Lauri Paatero, lauri.paatero@paatero.pp.fi ###
+
+lbp8_=gdevlbp8.$(OBJ)
+lbp8.dev: $(lbp8_) page.dev
+ $(SETPDEV) lbp8 $(lbp8_)
+
+lips3.dev: $(lbp8_) page.dev
+ $(SETPDEV) lips3 $(lbp8_)
+
+gdevlbp8.$(OBJ): gdevlbp8.c $(PDEVH)
+
+### ----------- The DEC LN03/LA50/LA70/LA75 printer devices ------------ ###
+### Note: this driver was contributed by users: please contact ###
+### Ulrich Mueller (ulm@vsnhd1.cern.ch) if you have questions. ###
+### For questions about LA50 and LA75, please contact ###
+### Ian MacPhedran (macphed@dvinci.USask.CA). ###
+### For questions about the LA70, please contact ###
+### Bruce Lowekamp (lowekamp@csugrad.cs.vt.edu). ###
+### For questions about the LA75plus, please contact ###
+### Andre' Beck (Andre_Beck@IRS.Inf.TU-Dresden.de). ###
+
+ln03_=gdevln03.$(OBJ)
+ln03.dev: $(ln03_) page.dev
+ $(SETPDEV) ln03 $(ln03_)
+
+la50.dev: $(ln03_) page.dev
+ $(SETPDEV) la50 $(ln03_)
+
+la70.dev: $(ln03_) page.dev
+ $(SETPDEV) la70 $(ln03_)
+
+la75.dev: $(ln03_) page.dev
+ $(SETPDEV) la75 $(ln03_)
+
+la75plus.dev: $(ln03_) page.dev
+ $(SETPDEV) la75plus $(ln03_)
+
+gdevln03.$(OBJ): gdevln03.c $(PDEVH)
+
+# LA70 driver with low-resolution text enhancement.
+
+la70t_=gdevla7t.$(OBJ)
+la70t.dev: $(la70t_) page.dev
+ $(SETPDEV) la70t $(la70t_)
+
+gdevla7t.$(OBJ): gdevla7t.c $(PDEVH)
+
+### -------------- The Epson LP-8000 laser printer device -------------- ###
+### Note: this driver was contributed by a user: please contact Oleg ###
+### Oleg Fat'yanov <faty1@rlem.titech.ac.jp> if you have questions.###
+
+lp8000_=gdevlp8k.$(OBJ)
+lp8000.dev: $(lp8000_) page.dev
+ $(SETPDEV) lp8000 $(lp8000_)
+
+gdevlp8k.$(OBJ): gdevlp8k.c $(PDEVH)
+
+### -------------- The C.Itoh M8510 printer device --------------------- ###
+### Note: this driver was contributed by a user: please contact Bob ###
+### Smith <bob@snuffy.penfield.ny.us> if you have questions. ###
+
+m8510_=gdev8510.$(OBJ)
+m8510.dev: $(m8510_) page.dev
+ $(SETPDEV) m8510 $(m8510_)
+
+gdev8510.$(OBJ): gdev8510.c $(PDEVH)
+
+### -------------- 24pin Dot-matrix printer with 360DPI ---------------- ###
+### Note: this driver was contributed by users. Please contact: ###
+### Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) for ###
+### questions about the NEC P6; ###
+### Christian Felsch (felsch@tu-harburg.d400.de) for ###
+### questions about the Epson LQ850. ###
+
+dm24_=gdevdm24.$(OBJ)
+gdevdm24.$(OBJ): gdevdm24.c $(PDEVH)
+
+necp6.dev: $(dm24_) page.dev
+ $(SETPDEV) necp6 $(dm24_)
+
+lq850.dev: $(dm24_) page.dev
+ $(SETPDEV) lq850 $(dm24_)
+
+### ----------------- The Okidata MicroLine 182 device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Maarten Koning (smeg@bnr.ca) if you have questions. ###
+
+oki182_=gdevo182.$(OBJ)
+oki182.dev: $(oki182_) page.dev
+ $(SETPDEV) oki182 $(oki182_)
+
+gdevo182.$(OBJ): gdevo182.c $(PDEVH)
+
+### ------------- The Okidata IBM compatible printer device ------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Charles Mack (chasm@netcom.com) if you have questions. ###
+
+okiibm_=gdevokii.$(OBJ)
+okiibm.dev: $(okiibm_) page.dev
+ $(SETPDEV) okiibm $(okiibm_)
+
+gdevokii.$(OBJ): gdevokii.c $(PDEVH)
+
+### ------------- The Ricoh 4081 laser printer device ------------------ ###
+### Note: this driver was contributed by users: ###
+### please contact kdw@oasis.icl.co.uk if you have questions. ###
+
+r4081_=gdev4081.$(OBJ)
+r4081.dev: $(r4081_) page.dev
+ $(SETPDEV) r4081 $(r4081_)
+
+
+gdev4081.$(OBJ): gdev4081.c $(PDEVH)
+
+### -------------------- Sony NWP533 printer device -------------------- ###
+### Note: this driver was contributed by a user: please contact Tero ###
+### Kivinen (kivinen@joker.cs.hut.fi) if you have questions. ###
+
+nwp533_=gdevn533.$(OBJ)
+nwp533.dev: $(nwp533_) page.dev
+ $(SETPDEV) nwp533 $(nwp533_)
+
+gdevn533.$(OBJ): gdevn533.c $(PDEVH)
+
+### ------------------------- The SPARCprinter ------------------------- ###
+### Note: this driver was contributed by users: please contact Martin ###
+### Schulte (schulte@thp.uni-koeln.de) if you have questions. ###
+### He would also like to hear from anyone using the driver. ###
+### Please consult the source code for additional documentation. ###
+
+sparc_=gdevsppr.$(OBJ)
+sparc.dev: $(sparc_) page.dev
+ $(SETPDEV) sparc $(sparc_)
+
+gdevsppr.$(OBJ): gdevsppr.c $(PDEVH)
+
+### ----------------- The StarJet SJ48 device -------------------------- ###
+### Note: this driver was contributed by a user: if you have questions, ###
+### . ###
+### please contact Mats Akerblom (f86ma@dd.chalmers.se). ###
+
+sj48_=gdevsj48.$(OBJ)
+sj48.dev: $(sj48_) page.dev
+ $(SETPDEV) sj48 $(sj48_)
+
+gdevsj48.$(OBJ): gdevsj48.c $(PDEVH)
+
+### ----------------- Tektronix 4396d color printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karl Hakimian (hakimian@haney.eecs.wsu.edu) ###
+### if you have questions. ###
+
+t4693d_=gdev4693.$(OBJ)
+t4693d2.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d2 $(t4693d_)
+
+t4693d4.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d4 $(t4693d_)
+
+t4693d8.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d8 $(t4693d_)
+
+gdev4693.$(OBJ): gdev4693.c $(PDEVH)
+
+### -------------------- Tektronix ink-jet printers -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karsten Spang (spang@nbivax.nbi.dk) if you have questions. ###
+
+tek4696_=gdevtknk.$(OBJ)
+tek4696.dev: $(tek4696_) page.dev
+ $(SETPDEV) tek4696 $(tek4696_)
+
+gdevtknk.$(OBJ): gdevtknk.c $(PDEVH) $(malloc__h)
+
+### ----------------- The Xerox XES printer device --------------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Peter Flass (flass@lbdrscs.bitnet) if you have questions. ###
+
+xes_=gdevxes.$(OBJ)
+xes.dev: $(xes_) page.dev
+ $(SETPDEV) xes $(xes_)
+
+gdevxes.$(OBJ): gdevxes.c $(PDEVH)
+
+###### ------------------------- Fax devices ------------------------- ######
+
+### --------------- Generic PostScript system compatible fax ------------ ###
+
+# This code doesn't work yet. Don't even think about using it.
+
+PSFAX=gdevpfax.$(OBJ)
+
+psfax_=$(PSFAX)
+psfax.dev: $(psfax_) page.dev
+ $(SETPDEV) psfax $(psfax_)
+ $(ADDMOD) psfax -iodev Fax
+
+gdevpfax.$(OBJ): gdevpfax.c $(PDEVH) $(gsparam_h) $(gxiodev_h)
+
+### ------------------------- The DigiFAX device ------------------------ ###
+### This driver outputs images in a format suitable for use with ###
+### DigiBoard, Inc.'s DigiFAX software. Use -sDEVICE=dfaxhigh for ###
+### high resolution output, -sDEVICE=dfaxlow for normal output. ###
+### Note: this driver was contributed by a user: please contact ###
+### Rick Richardson (rick@digibd.com) if you have questions. ###
+
+dfax_=gdevdfax.$(OBJ) gdevtfax.$(OBJ)
+
+dfaxlow.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxlow $(dfax_)
+ $(ADDMOD) dfaxlow -include cfe
+
+dfaxhigh.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxhigh $(dfax_)
+ $(ADDMOD) dfaxhigh -include cfe
+
+gdevdfax.$(OBJ): gdevdfax.c $(PDEVH) $(scfx_h) $(strimpl_h)
+
+### --------------See under TIFF below for fax-format TIFF -------------- ###
+
+###### ------------------- High-level file formats ------------------- ######
+
+# Support for PostScript and PDF
+
+gdevpsdf_h=gdevpsdf.h $(gdevvec_h) $(strimpl_h)
+gdevpstr_h=gdevpstr.h
+
+gdevpsdf.$(OBJ): gdevpsdf.c $(stdio__h) $(string__h)\
+ $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsparam_h) $(gstypes_h)\
+ $(gxdevice_h)\
+ $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpstr.$(OBJ): gdevpstr.c $(math__h) $(stdio__h) $(string__h)\
+ $(gdevpstr_h) $(stream_h)
+
+# PostScript and EPS writers
+
+pswrite1_=gdevps.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pswrite2_=scantab.$(OBJ) sfilter2.$(OBJ)
+pswrite_=$(pswrite1_) $(pswrite2_)
+epswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) epswrite $(pswrite1_)
+ $(ADDMOD) epswrite $(pswrite2_)
+ $(ADDMOD) epswrite -include vector
+
+pswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) pswrite $(pswrite1_)
+ $(ADDMOD) pswrite $(pswrite2_)
+ $(ADDMOD) pswrite -include vector
+
+gdevps.$(OBJ): gdevps.c $(GDEV) $(math__h) $(time__h)\
+ $(gscdefs_h) $(gscspace_h) $(gsparam_h) $(gsiparam_h) $(gsmatrix_h)\
+ $(gxdcolor_h)\
+ $(sa85x_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+# PDF writer
+# Note that gs_pdfwr.ps will only actually be loaded if the configuration
+# includes a PostScript interpreter.
+
+pdfwrite1_=gdevpdf.$(OBJ) gdevpdfd.$(OBJ) gdevpdfi.$(OBJ) gdevpdfm.$(OBJ)
+pdfwrite2_=gdevpdfp.$(OBJ) gdevpdft.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pdfwrite3_=gsflip.$(OBJ) scantab.$(OBJ) sfilter2.$(OBJ) sstring.$(OBJ)
+pdfwrite_=$(pdfwrite1_) $(pdfwrite2_) $(pdfwrite3_)
+pdfwrite.dev: $(ECHOGS_XE) $(pdfwrite_) \
+ cmyklib.dev cfe.dev dcte.dev lzwe.dev rle.dev vector.dev
+ $(SETDEV) pdfwrite $(pdfwrite1_)
+ $(ADDMOD) pdfwrite $(pdfwrite2_)
+ $(ADDMOD) pdfwrite $(pdfwrite3_)
+ $(ADDMOD) pdfwrite -ps gs_pdfwr
+ $(ADDMOD) pdfwrite -include cmyklib cfe dcte lzwe rle vector
+
+gdevpdfx_h=gdevpdfx.h $(gsparam_h) $(gxdevice_h) $(gxline_h) $(stream_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpdf.$(OBJ): gdevpdf.c $(math__h) $(memory__h) $(string__h) $(time__h)\
+ $(gp_h)\
+ $(gdevpdfx_h) $(gscdefs_h) $(gserrors_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)\
+ $(scanchar_h) $(scfx_h) $(slzwx_h) $(sstring_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) gdevpdf.c
+
+gdevpdfd.$(OBJ): gdevpdfd.c $(math__h)\
+ $(gdevpdfx_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+gdevpdfi.$(OBJ): gdevpdfi.c $(math__h) $(memory__h) $(gx_h) \
+ $(gdevpdfx_h) $(gscie_h) $(gscolor2_h) $(gserrors_h) $(gsflip_h)\
+ $(gxcspace_h) $(gxistate_h) \
+ $(sa85x_h) $(scfx_h) $(srlx_h) $(strimpl_h)
+
+gdevpdfm.$(OBJ): gdevpdfm.c $(memory__h) $(string__h) $(gx_h) \
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h) $(scanchar_h)
+
+gdevpdfp.$(OBJ): gdevpdfp.c $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h)
+
+gdevpdft.$(OBJ): gdevpdft.c $(math__h) $(memory__h) $(string__h) $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h)\
+ $(scommon_h)
+
+# High-level PCL XL writer
+
+pxl_=gdevpx.$(OBJ)
+pxlmono.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlmono $(pxl_)
+ $(ADDMOD) pxlmono -include vector
+
+pxlcolor.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlcolor $(pxl_)
+ $(ADDMOD) pxlcolor -include vector
+
+gdevpx.$(OBJ): gdevpx.c $(math__h) $(memory__h) $(string__h)\
+ $(gx_h) $(gsccolor_h) $(gsdcolor_h) $(gserrors_h)\
+ $(gxcspace_h) $(gxdevice_h) $(gxpath_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h) $(gdevvec_h)\
+ $(srlx_h) $(strimpl_h)
+
+###### --------------------- Raster file formats --------------------- ######
+
+### --------------------- The "plain bits" devices ---------------------- ###
+
+bit_=gdevbit.$(OBJ)
+
+bit.dev: $(bit_) page.dev
+ $(SETPDEV) bit $(bit_)
+
+bitrgb.dev: $(bit_) page.dev
+ $(SETPDEV) bitrgb $(bit_)
+
+bitcmyk.dev: $(bit_) page.dev
+ $(SETPDEV) bitcmyk $(bit_)
+
+gdevbit.$(OBJ): gdevbit.c $(PDEVH) $(gsparam_h) $(gxlum_h)
+
+### ------------------------- .BMP file formats ------------------------- ###
+
+bmp_=gdevbmp.$(OBJ) gdevpccm.$(OBJ)
+
+gdevbmp.$(OBJ): gdevbmp.c $(PDEVH) $(gdevpccm_h)
+
+bmpmono.dev: $(bmp_) page.dev
+ $(SETPDEV) bmpmono $(bmp_)
+
+bmp16.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16 $(bmp_)
+
+bmp256.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp256 $(bmp_)
+
+bmp16m.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16m $(bmp_)
+
+### ------------- BMP driver that serves as demo of async rendering ---- ###
+devasync_=gdevasyn.$(OBJ) gdevpccm.$(OBJ) gxsync.$(OBJ)
+
+gdevasyn.$(OBJ): gdevasyn.c $(AK) $(stdio__h) $(gdevprna_h) $(gdevpccm_h)\
+ $(gserrors_h) $(gpsync_h)
+
+asynmono.dev: $(devasync_) page.dev async.dev
+ $(SETPDEV) asynmono $(devasync_)
+ $(ADDMOD) asynmono -include async
+
+
+### -------------------------- CGM file format ------------------------- ###
+### This driver is under development. Use at your own risk. ###
+### The output is very low-level, consisting only of rectangles and ###
+### cell arrays. ###
+
+cgm_=gdevcgm.$(OBJ) gdevcgml.$(OBJ)
+
+gdevcgml_h=gdevcgml.h
+gdevcgmx_h=gdevcgmx.h $(gdevcgml_h)
+
+gdevcgm.$(OBJ): gdevcgm.c $(GDEV) $(memory__h)\
+ $(gsparam_h) $(gdevpccm_h) $(gdevcgml_h)
+
+gdevcgml.$(OBJ): gdevcgml.c $(memory__h) $(stdio__h)\
+ $(gdevcgmx_h)
+
+cgmmono.dev: $(cgm_)
+ $(SETDEV) cgmmono $(cgm_)
+
+cgm8.dev: $(cgm_)
+ $(SETDEV) cgm8 $(cgm_)
+
+cgm24.dev: $(cgm_)
+ $(SETDEV) cgm24 $(cgm_)
+
+### -------------------- The CIF file format for VLSI ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Frederic Petrot (petrot@masi.ibp.fr) if you have questions. ###
+
+cif_=gdevcif.$(OBJ)
+cif.dev: $(cif_) page.dev
+ $(SETPDEV) cif $(cif_)
+
+gdevcif.$(OBJ): gdevcif.c $(PDEVH)
+
+### ------------------------- JPEG file format ------------------------- ###
+
+jpeg_=gdevjpeg.$(OBJ)
+
+# RGB output
+jpeg.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeg $(jpeg_)
+ $(ADDMOD) jpeg -include sdcte
+
+# Gray output
+jpeggray.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeggray $(jpeg_)
+ $(ADDMOD) jpeggray -include sdcte
+
+gdevjpeg.$(OBJ): gdevjpeg.c $(stdio__h) $(PDEVH)\
+ $(sdct_h) $(sjpeg_h) $(stream_h) $(strimpl_h) jpeglib.h
+
+### ------------------------- MIFF file format ------------------------- ###
+### Right now we support only 24-bit direct color, but we might add more ###
+### formats in the future. ###
+
+miff_=gdevmiff.$(OBJ)
+
+miff24.dev: $(miff_) page.dev
+ $(SETPDEV) miff24 $(miff_)
+
+gdevmiff.$(OBJ): gdevmiff.c $(PDEVH)
+
+### --------------------------- MGR devices ---------------------------- ###
+### Note: these drivers were contributed by a user: please contact ###
+### Carsten Emde (carsten@ce.pr.net.ch) if you have questions. ###
+
+MGR=gdevmgr.$(OBJ) gdevpccm.$(OBJ)
+
+gdevmgr.$(OBJ): gdevmgr.c $(PDEVH) $(gdevpccm_h) gdevmgr.h
+
+mgrmono.dev: $(MGR) page.dev
+ $(SETPDEV) mgrmono $(MGR)
+
+mgrgray2.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray2 $(MGR)
+
+mgrgray4.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray4 $(MGR)
+
+mgrgray8.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray8 $(MGR)
+
+mgr4.dev: $(MGR) page.dev
+ $(SETPDEV) mgr4 $(MGR)
+
+mgr8.dev: $(MGR) page.dev
+ $(SETPDEV) mgr8 $(MGR)
+
+### ------------------------- PCX file formats ------------------------- ###
+
+pcx_=gdevpcx.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpcx.$(OBJ): gdevpcx.c $(PDEVH) $(gdevpccm_h) $(gxlum_h)
+
+pcxmono.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxmono $(pcx_)
+
+pcxgray.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxgray $(pcx_)
+
+pcx16.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx16 $(pcx_)
+
+pcx256.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx256 $(pcx_)
+
+pcx24b.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx24b $(pcx_)
+
+pcxcmyk.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxcmyk $(pcx_)
+
+# The 2-up PCX device is here only as an example, and for testing.
+pcx2up.dev: $(LIB_MAK) $(ECHOGS_XE) gdevp2up.$(OBJ) page.dev pcx256.dev
+ $(SETPDEV) pcx2up gdevp2up.$(OBJ)
+ $(ADDMOD) pcx2up -include pcx256
+
+gdevp2up.$(OBJ): gdevp2up.c $(AK)\
+ $(gdevpccm_h) $(gdevprn_h) $(gxclpage_h)
+
+### ------------------- Portable Bitmap file formats ------------------- ###
+### For more information, see the pbm(5), pgm(5), and ppm(5) man pages. ###
+
+pxm_=gdevpbm.$(OBJ)
+
+gdevpbm.$(OBJ): gdevpbm.c $(PDEVH) $(gscdefs_h) $(gxlum_h)
+
+### Portable Bitmap (PBM, plain or raw format, magic numbers "P1" or "P4")
+
+pbm.dev: $(pxm_) page.dev
+ $(SETPDEV) pbm $(pxm_)
+
+pbmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pbmraw $(pxm_)
+
+### Portable Graymap (PGM, plain or raw format, magic numbers "P2" or "P5")
+
+pgm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgm $(pxm_)
+
+pgmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgmraw $(pxm_)
+
+# PGM with automatic optimization to PBM if this is possible.
+
+pgnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnm $(pxm_)
+
+pgnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnmraw $(pxm_)
+
+### Portable Pixmap (PPM, plain or raw format, magic numbers "P3" or "P6")
+
+ppm.dev: $(pxm_) page.dev
+ $(SETPDEV) ppm $(pxm_)
+
+ppmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) ppmraw $(pxm_)
+
+# PPM with automatic optimization to PGM or PBM if possible.
+
+pnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pnm $(pxm_)
+
+pnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pnmraw $(pxm_)
+
+### Portable inKmap (CMYK internally, converted to PPM=RGB at output time)
+
+pkm.dev: $(pxm_) page.dev
+ $(SETPDEV) pkm $(pxm_)
+
+pkmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pkmraw $(pxm_)
+
+### --------------- Portable Network Graphics file format --------------- ###
+### Requires libpng 0.81 and zlib 0.95 (or more recent versions). ###
+### See libpng.mak and zlib.mak for more details. ###
+
+png_=gdevpng.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpng.$(OBJ): gdevpng.c $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(PSRC)png.h
+ $(CCCP) gdevpng.c
+
+pngmono.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pngmono $(png_)
+ $(ADDMOD) pngmono -include libpng
+
+pnggray.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pnggray $(png_)
+ $(ADDMOD) pnggray -include libpng
+
+png16.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16 $(png_)
+ $(ADDMOD) png16 -include libpng
+
+png256.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png256 $(png_)
+ $(ADDMOD) png256 -include libpng
+
+png16m.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16m $(png_)
+ $(ADDMOD) png16m -include libpng
+
+### ---------------------- PostScript image format ---------------------- ###
+### These devices make it possible to print Level 2 files on a Level 1 ###
+### printer, by converting them to a bitmap in PostScript format. ###
+
+ps_=gdevpsim.$(OBJ)
+
+gdevpsim.$(OBJ): gdevpsim.c $(PDEVH)
+
+psmono.dev: $(ps_) page.dev
+ $(SETPDEV) psmono $(ps_)
+
+psgray.dev: $(ps_) page.dev
+ $(SETPDEV) psgray $(ps_)
+
+# Someday there will be RGB and CMYK variants....
+
+### -------------------------- SGI RGB pixmaps -------------------------- ###
+
+sgirgb_=gdevsgi.$(OBJ)
+
+gdevsgi.$(OBJ): gdevsgi.c $(PDEVH) gdevsgi.h
+
+sgirgb.dev: $(sgirgb_) page.dev
+ $(SETPDEV) sgirgb $(sgirgb_)
+
+### -------------------- Plain or TIFF fax encoding --------------------- ###
+### Use -sDEVICE=tiffg3 or tiffg4 and ###
+### -r204x98 for low resolution output, or ###
+### -r204x196 for high resolution output ###
+### These drivers recognize 3 page sizes: letter, A4, and B4. ###
+
+gdevtifs_h=gdevtifs.h
+
+tfax_=gdevtfax.$(OBJ)
+tfax.dev: $(tfax_) cfe.dev lzwe.dev rle.dev tiffs.dev
+ $(SETMOD) tfax $(tfax_)
+ $(ADDMOD) tfax -include cfe lzwe rle tiffs
+
+gdevtfax.$(OBJ): gdevtfax.c $(PDEVH)\
+ $(gdevtifs_h) $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)
+
+### Plain G3/G4 fax with no header
+
+faxg3.dev: tfax.dev
+ $(SETDEV) faxg3 -include tfax
+
+faxg32d.dev: tfax.dev
+ $(SETDEV) faxg32d -include tfax
+
+faxg4.dev: tfax.dev
+ $(SETDEV) faxg4 -include tfax
+
+### ---------------------------- TIFF formats --------------------------- ###
+
+tiffs_=gdevtifs.$(OBJ)
+tiffs.dev: $(tiffs_) page.dev
+ $(SETMOD) tiffs $(tiffs_)
+ $(ADDMOD) tiffs -include page
+
+gdevtifs.$(OBJ): gdevtifs.c $(PDEVH) $(stdio__h) $(time__h) \
+ $(gdevtifs_h) $(gscdefs_h) $(gstypes_h)
+
+# Black & white, G3/G4 fax
+
+tiffcrle.dev: tfax.dev
+ $(SETDEV) tiffcrle -include tfax
+
+tiffg3.dev: tfax.dev
+ $(SETDEV) tiffg3 -include tfax
+
+tiffg32d.dev: tfax.dev
+ $(SETDEV) tiffg32d -include tfax
+
+tiffg4.dev: tfax.dev
+ $(SETDEV) tiffg4 -include tfax
+
+# Black & white, LZW compression
+
+tifflzw.dev: tfax.dev
+ $(SETDEV) tifflzw -include tfax
+
+# Black & white, PackBits compression
+
+tiffpack.dev: tfax.dev
+ $(SETDEV) tiffpack -include tfax
+
+# RGB, no compression
+
+tiffrgb_=gdevtfnx.$(OBJ)
+
+tiff12nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff12nc $(tiffrgb_)
+ $(ADDMOD) tiff12nc -include tiffs
+
+tiff24nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff24nc $(tiffrgb_)
+ $(ADDMOD) tiff24nc -include tiffs
+
+gdevtfnx.$(OBJ): gdevtfnx.c $(PDEVH) $(gdevtifs_h)
+# Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile, common to all Desqview/X configurations.
+
+# This is the last part of the makefile for Desqview/X configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Desqview/X platform
+
+dvx__=gp_nofb.$(OBJ) gp_dvx.$(OBJ) gp_unifs.$(OBJ) gp_dosfs.$(OBJ)
+dvx_.dev: $(dvx__)
+ $(SETMOD) dvx_ $(dvx__)
+
+gp_dvx.$(OBJ): gp_dvx.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h) $(dos__h)
+ $(CCC) -D__DVX__ gp_dvx.c
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c $(stdio__h) $(string__h) $(malloc__h)
+ $(CC) -o ansi2knr $(CFLAGS) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c
+ $(CC) -o echogs $(CFLAGS) echogs.c
+ strip echogs
+ coff2exe echogs
+ del echogs
+
+$(GENARCH_XE): genarch.c $(stdpre_h)
+ $(CC) -o genarch genarch.c
+ strip genarch
+ coff2exe genarch
+ del genarch
+
+$(GENCONF_XE): genconf.c $(stdpre_h)
+ $(CC) -o genconf genconf.c
+ strip genconf
+ coff2exe genconf
+ del genconf
+
+$(GENINIT_XE): geninit.c $(stdio__h) $(string__h)
+ $(CC) -o geninit geninit.c
+ strip geninit
+ coff2exe geninit
+ del geninit
+
+# Construct gconfig_.h to reflect the environment.
+INCLUDE=/djgpp/include
+gconfig_.h: dvx-tail.mak $(ECHOGS_XE)
+ echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H
+ echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H
+
+# ----------------------------- Main program ------------------------------ #
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Interpreter main program
+
+$(GS_XE): ld.tr gs.$(OBJ) $(INT_ALL) $(LIB_ALL) $(DEVS_ALL)
+ $(CP_) ld.tr _temp_
+ echo $(EXTRALIBS) -lm >>_temp_
+ $(CC) $(LDFLAGS) $(XLIBDIRS) -o $(GS) gs.$(OBJ) @_temp_
+ strip $(GS)
+ coff2exe $(GS)
+ del $(GS)
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix and Desqview/X configurations.
+
+# This is the very last part of the makefile for these configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define a rule for building profiling configurations.
+pg:
+ make GENOPT='' CFLAGS='-pg -O $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+# Define a rule for building debugging configurations.
+debug:
+ make GENOPT='-DDEBUG' CFLAGS='-g -O $(GCFLAGS) $(XCFLAGS)'
+
+# The rule for gconfigv.h is here because it is shared between Unix and
+# DV/X environments.
+gconfigv.h: unix-end.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# The following rules are equivalent to what tar_cat does.
+# The rm -f is so that we don't overwrite a file that `make'
+# may currently be reading from.
+GENERIC_MAK_LIST=$(GS_MAK) $(LIB_MAK) $(INT_MAK) $(JPEG_MAK) $(LIBPNG_MAK) $(ZLIB_MAK) $(DEVS_MAK)
+UNIX_MAK_LIST=dvx-gcc.mak unixansi.mak unix-cc.mak unix-gcc.mak
+
+unix.mak: $(UNIX_MAK_LIST)
+
+DVX_GCC_MAK=$(VERSION_MAK) dgc-head.mak dvx-head.mak $(GENERIC_MAK_LIST) dvx-tail.mak unix-end.mak
+dvx-gcc.mak: $(DVX_GCC_MAK)
+ rm -f dvx-gcc.mak
+ $(CAT) $(DVX_GCC_MAK) >dvx-gcc.mak
+
+UNIXANSI_MAK=$(VERSION_MAK) ansihead.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unixansi.mak: $(UNIXANSI_MAK)
+ rm -f unixansi.mak
+ $(CAT) $(UNIXANSI_MAK) >unixansi.mak
+
+UNIX_CC_MAK=$(VERSION_MAK) cc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-cc.mak: $(UNIX_CC_MAK)
+ rm -f unix-cc.mak
+ $(CAT) $(UNIX_CC_MAK) >unix-cc.mak
+
+UNIX_GCC_MAK=$(VERSION_MAK) gcc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-gcc.mak: $(UNIX_GCC_MAK)
+ rm -f unix-gcc.mak
+ $(CAT) $(UNIX_GCC_MAK) >unix-gcc.mak
+
+# Installation
+
+TAGS:
+ etags -t *.c *.h
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+install-exec: $(GS)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(scriptdir)
+ sh -c 'for f in gsbj gsdj gsdj500 gslj gslp gsnd bdftops font2c \
+pdf2dsc pdf2ps printafm ps2ascii ps2epsi ps2pdf wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pfbtogs.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps gs_pdf.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps pdf_2ps.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/dvx-head.mak b/gs/src/dvx-head.mak
new file mode 100644
index 000000000..5c165ef37
--- /dev/null
+++ b/gs/src/dvx-head.mak
@@ -0,0 +1,70 @@
+# Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile, common to all Desqview/X configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name.
+
+PLATFORM=dvx_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=.bat
+O=-o ./
+OBJ=o
+XE=.exe
+XEAUX=.exe
+
+# Define the current directory prefix and command invocations.
+
+CAT=type
+D=\\
+EXP=
+SHELL=
+SH=
+SHP=
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p -pl &-l%%s -ol ld.tr
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+# Patch a couple of PC-specific things that aren't relevant to DV/X builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
diff --git a/gs/src/dvx-tail.mak b/gs/src/dvx-tail.mak
new file mode 100644
index 000000000..eb11ac310
--- /dev/null
+++ b/gs/src/dvx-tail.mak
@@ -0,0 +1,91 @@
+# Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile, common to all Desqview/X configurations.
+
+# This is the last part of the makefile for Desqview/X configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Desqview/X platform
+
+dvx__=gp_nofb.$(OBJ) gp_dvx.$(OBJ) gp_unifs.$(OBJ) gp_dosfs.$(OBJ)
+dvx_.dev: $(dvx__)
+ $(SETMOD) dvx_ $(dvx__)
+
+gp_dvx.$(OBJ): gp_dvx.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h) $(dos__h)
+ $(CCC) -D__DVX__ gp_dvx.c
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c $(stdio__h) $(string__h) $(malloc__h)
+ $(CC) -o ansi2knr $(CFLAGS) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c
+ $(CC) -o echogs $(CFLAGS) echogs.c
+ strip echogs
+ coff2exe echogs
+ del echogs
+
+$(GENARCH_XE): genarch.c $(stdpre_h)
+ $(CC) -o genarch genarch.c
+ strip genarch
+ coff2exe genarch
+ del genarch
+
+$(GENCONF_XE): genconf.c $(stdpre_h)
+ $(CC) -o genconf genconf.c
+ strip genconf
+ coff2exe genconf
+ del genconf
+
+$(GENINIT_XE): geninit.c $(stdio__h) $(string__h)
+ $(CC) -o geninit geninit.c
+ strip geninit
+ coff2exe geninit
+ del geninit
+
+# Construct gconfig_.h to reflect the environment.
+INCLUDE=/djgpp/include
+gconfig_.h: dvx-tail.mak $(ECHOGS_XE)
+ echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H
+ echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H
+
+# ----------------------------- Main program ------------------------------ #
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Interpreter main program
+
+$(GS_XE): ld.tr gs.$(OBJ) $(INT_ALL) $(LIB_ALL) $(DEVS_ALL)
+ $(CP_) ld.tr _temp_
+ echo $(EXTRALIBS) -lm >>_temp_
+ $(CC) $(LDFLAGS) $(XLIBDIRS) -o $(GS) gs.$(OBJ) @_temp_
+ strip $(GS)
+ coff2exe $(GS)
+ del $(GS)
diff --git a/gs/src/dw32c.def b/gs/src/dw32c.def
new file mode 100644
index 000000000..b1ab6ac4c
--- /dev/null
+++ b/gs/src/dw32c.def
@@ -0,0 +1,6 @@
+NAME GSWIN32C
+DESCRIPTION 'Ghostscript Interpreter'
+CODE MOVEABLE DISCARDABLE PRELOAD
+DATA MULTIPLE MOVEABLE PRELOAD
+HEAPSIZE 256
+STACKSIZE 32768
diff --git a/gs/src/dwdll.cpp b/gs/src/dwdll.cpp
new file mode 100644
index 000000000..6e3ae1f73
--- /dev/null
+++ b/gs/src/dwdll.cpp
@@ -0,0 +1,343 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwdll.cpp
+
+// gsdll class for MS-Windows
+
+#define STRICT
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+extern "C" {
+#include "gsdll.h"
+}
+
+#include "dwdll.h" // gsdll_class
+
+static char not_loaded[] = "DLL is not loaded";
+static char func_null[] = "A function pointer to the DLL is NULL";
+static char not_init[] = "Not initialized";
+
+int
+gsdll_class::load(const HINSTANCE in_hinstance,
+ const char *name, const long need_version)
+{
+char fullname[1024];
+const char *shortname;
+char *p;
+long version;
+
+ // Don't load if already loaded
+ if (hmodule)
+ return 0;
+ hinstance = in_hinstance;
+ initialized = FALSE;
+
+
+ // Try to load DLL first with given path
+ hmodule = LoadLibrary(name);
+ if (hmodule < (HINSTANCE)HINSTANCE_ERROR) {
+ // failed
+ // try again, with path of EXE
+ if ((shortname = strrchr((char *)name, '\\')) == (const char *)NULL)
+ shortname = name;
+ GetModuleFileName(hinstance, fullname, sizeof(fullname));
+ if ((p = strrchr(fullname,'\\')) != (char *)NULL)
+ p++;
+ else
+ p = fullname;
+ *p = '\0';
+ strcat(fullname, shortname);
+ hmodule = LoadLibrary(fullname);
+ if (hmodule < (HINSTANCE)HINSTANCE_ERROR) {
+ // failed again
+ // try once more, this time on system search path
+ hmodule = LoadLibrary(shortname);
+ if (hmodule < (HINSTANCE)HINSTANCE_ERROR) {
+ sprintf(last_error, "Couldn't load DLL, LoadLibrary error code %d", (int)hmodule);
+ hmodule = (HINSTANCE)0;
+ return 1;
+ }
+ }
+ }
+
+ // DLL is now loaded
+ // Get pointers to functions
+ c_revision = (PFN_gsdll_revision) GetProcAddress(hmodule, "gsdll_revision");
+ if (c_revision == NULL) {
+ sprintf(last_error, "Can't find gsdll_revision\n");
+ unload();
+ return 1;
+ }
+ // check DLL version
+ c_revision(NULL, NULL, &version, NULL);
+ if (version != need_version) {
+ sprintf(last_error, "Wrong version of DLL found.\n Found version %ld\n Need version %ld\n", version, need_version);
+ unload();
+ return 1;
+ }
+
+ // continue loading other functions */
+ c_init = (PFN_gsdll_init) GetProcAddress(hmodule, "gsdll_init");
+ if (c_init == NULL) {
+ sprintf(last_error, "Can't find gsdll_init\n");
+ unload();
+ return 1;
+ }
+ c_execute_begin = (PFN_gsdll_execute_begin) GetProcAddress(hmodule, "gsdll_execute_begin");
+ if (c_execute_begin == NULL) {
+ sprintf(last_error, "Can't find gsdll_execute_begin\n");
+ unload();
+ return 1;
+ }
+ c_execute_cont = (PFN_gsdll_execute_cont) GetProcAddress(hmodule, "gsdll_execute_cont");
+ if (c_execute_cont == NULL) {
+ sprintf(last_error, "Can't find gsdll_execute_cont\n");
+ unload();
+ return 1;
+ }
+ c_execute_end = (PFN_gsdll_execute_end) GetProcAddress(hmodule, "gsdll_execute_end");
+ if (c_execute_end == NULL) {
+ sprintf(last_error, "Can't find gsdll_execute_end\n");
+ unload();
+ return 1;
+ }
+ c_exit = (PFN_gsdll_exit) GetProcAddress(hmodule, "gsdll_exit");
+ if (c_exit == NULL) {
+ sprintf(last_error, "Can't find gsdll_exit\n");
+ unload();
+ return 1;
+ }
+ c_lock_device = (PFN_gsdll_lock_device) GetProcAddress(hmodule, "gsdll_lock_device");
+ if (c_lock_device == NULL) {
+ sprintf(last_error, "Can't find gsdll_lock_device\n");
+ unload();
+ return 1;
+ }
+ c_copy_dib = (PFN_gsdll_copy_dib) GetProcAddress(hmodule, "gsdll_copy_dib");
+ if (c_copy_dib == NULL) {
+ sprintf(last_error, "Can't find gsdll_copy_dib\n");
+ unload();
+ return 1;
+ }
+ c_copy_palette = (PFN_gsdll_copy_palette) GetProcAddress(hmodule, "gsdll_copy_palette");
+ if (c_copy_palette == NULL) {
+ sprintf(last_error, "Can't find gsdll_copy_palette\n");
+ unload();
+ return 1;
+ }
+ c_draw = (PFN_gsdll_draw) GetProcAddress(hmodule, "gsdll_draw");
+ if (c_draw == NULL) {
+ sprintf(last_error, "Can't find gsdll_draw\n");
+ unload();
+ return 1;
+ }
+ return 0;
+}
+
+int
+gsdll_class::unload(void)
+{
+ // exit Ghostscript interpreter
+ if (initialized) {
+ if (!execute_code)
+ c_execute_end();
+ c_exit();
+#ifndef __WIN32__
+ FreeProcInstance((FARPROC)callback);
+#endif
+ callback = NULL;
+ }
+
+ // Set functions to NULL to prevent use
+ c_revision = NULL;
+ c_init = NULL;
+ c_execute_begin = NULL;
+ c_execute_cont = NULL;
+ c_execute_end = NULL;
+ c_exit = NULL;
+ c_lock_device = NULL;
+ c_copy_dib = NULL;
+ c_copy_palette = NULL;
+ c_draw = NULL;
+
+ // need to do more than this
+ device = NULL;
+
+ // Don't do anything else if already unloaded
+ if (hmodule == (HINSTANCE)NULL)
+ return 0;
+
+ FreeLibrary(hmodule);
+ return 0;
+}
+
+int
+gsdll_class::revision(char FAR * FAR *product, char FAR * FAR *copyright,
+ long FAR *revision, long FAR *revisiondate)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!c_revision)
+ return c_revision(product, copyright, revision, revisiondate);
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::init(GSDLL_CALLBACK in_callback, HWND hwnd, int argc, char FAR * FAR *argv)
+{
+int rc;
+ execute_code = 0;
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (initialized) {
+ strcpy(last_error, "Already initialized");
+ return 1;
+ }
+ if (in_callback == (GSDLL_CALLBACK)NULL) {
+ strcpy(last_error, "Callback not provided");
+ return 1;
+ }
+
+#ifdef __WIN32__
+ callback = in_callback;
+#else
+ callback = (GSDLL_CALLBACK)MakeProcInstance((FARPROC)in_callback, hinstance);
+#endif
+
+ if (c_init && c_execute_begin) {
+ rc = c_init(callback, hwnd, argc, argv);
+ if (rc) {
+ if (rc == GSDLL_INIT_IN_USE)
+ sprintf(last_error, "gsdll_init returns %d\nDLL already in use", rc);
+ else
+ sprintf(last_error, "gsdll_init returns %d\n", rc);
+ return rc;
+ }
+ else {
+ if ((rc = c_execute_begin()) != 0)
+ sprintf(last_error, "gsdll_execute_begin returns %d", rc);
+ else
+ initialized = TRUE;
+ return rc;
+ }
+ }
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::restart(int argc, char FAR * FAR *argv)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!initialized) {
+ strcpy(last_error, not_init);
+ return 1;
+ }
+ if (c_execute_end && c_exit) {
+ if (!execute_code)
+ c_execute_end();
+ c_exit();
+#ifndef __WIN32__
+ FreeProcInstance((FARPROC)callback);
+#endif
+ // ignore return codes since they we may be aborting from an error
+ initialized = FALSE;
+ return init(callback, hwnd, argc, argv);
+ }
+
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::get_last_error(char *str, int len)
+{
+ strncpy(str, last_error,
+ (len < sizeof(last_error) ? len : sizeof(last_error)));
+ return 0;
+}
+
+
+int
+gsdll_class::execute(const char FAR *str, int len)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!initialized) {
+ strcpy(last_error, not_init);
+ return 1;
+ }
+ if (c_execute_cont) {
+ execute_code = c_execute_cont(str, len);
+ return execute_code;
+ }
+
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::draw(const char FAR *device, HDC hdc, int dx, int dy, int wx, int wy, int sx, int sy)
+{
+RECT source, dest;
+ source.left = sx;
+ source.right = sx+wx;
+ source.top = sy;
+ source.bottom = sy+wy;
+
+ dest.left = dx;
+ dest.right = dx+wx;
+ dest.top = dy;
+ dest.bottom = dy+wy;
+ c_draw((unsigned char FAR *)device, hdc, &dest, &source);
+ return 0;
+}
+
+HPALETTE
+gsdll_class::copy_palette(const char FAR *device)
+{
+ return c_copy_palette((unsigned char FAR *)device);
+}
+
+
+HGLOBAL
+gsdll_class::copy_dib(const char FAR *device)
+{
+ return c_copy_dib((unsigned char FAR *)device);
+}
+
+
+int
+gsdll_class::lock_device(const char FAR *device, int lock)
+{
+ return c_lock_device((unsigned char FAR *)device, lock);
+}
diff --git a/gs/src/dwdll.h b/gs/src/dwdll.h
new file mode 100644
index 000000000..805e2c3e5
--- /dev/null
+++ b/gs/src/dwdll.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwdll.h
+
+// gsdll_class for MS-Windows
+
+#ifndef _GSDLL_H
+extern "C" {
+#include "gsdll.h"
+}
+#endif
+
+#ifndef _GSDLL_CLASS_H
+#define _GSDLL_CLASS_H
+
+
+class gsdll_class {
+ // instance of caller
+ HINSTANCE hinstance;
+ // handle to DLL. Non-zero of loaded.
+ HINSTANCE hmodule;
+ // handle to parent window. Can be NULL.
+ HWND hwnd;
+ // text description of last error
+ char last_error[128];
+ // true if init and execute_begin have been called
+ BOOL initialized;
+ // return code from last c_execute_end
+ int execute_code;
+
+ // pointer to callback from DLL
+ GSDLL_CALLBACK callback;
+
+ // pointers to DLL functions
+ PFN_gsdll_revision c_revision;
+ PFN_gsdll_init c_init;
+ PFN_gsdll_execute_begin c_execute_begin;
+ PFN_gsdll_execute_cont c_execute_cont;
+ PFN_gsdll_execute_end c_execute_end;
+ PFN_gsdll_exit c_exit;
+ PFN_gsdll_lock_device c_lock_device;
+ PFN_gsdll_copy_dib c_copy_dib;
+ PFN_gsdll_copy_palette c_copy_palette;
+ PFN_gsdll_draw c_draw;
+
+ // pointer to os2dll or mswindll device
+ // this needs to be extended to support multiple devices
+ // also need to have one window per device
+ char FAR *device;
+
+
+public:
+ // Load DLL
+ // Arguments:
+ // instance of calling EXE
+ // name of DLL, may include path
+ // expected version number of DLL
+ // Returns:
+ // zero on success
+ // non-zero on error. Error message available from get_last_error()
+ // do nothing if DLL already loaded
+ int load(const HINSTANCE hinstance, const char *name, const long version);
+
+ // Get revision number of DLL
+ int revision(char FAR * FAR *, char FAR * FAR *, long FAR *, long FAR *);
+
+ // Unload DLL
+ int unload(void);
+
+ // Initialise DLL
+ // Arguments:
+ // pointer to C callback function
+ // window handle of parent
+ // argc (normal C command line)
+ // argv (normal C command line)
+ int init(GSDLL_CALLBACK callback, HWND hwnd, int argc, char FAR * FAR *argv);
+
+ // Restart DLL
+ int restart(int argc, char FAR * FAR *argv);
+
+ // Execute string
+ int execute(const char FAR *, int len);
+
+ // Get last error string
+ int get_last_error(char *str, int len);
+
+ // lock device
+ int gsdll_class::lock_device(const char FAR *device, int lock);
+
+ // draw bitmap
+ int gsdll_class::draw(const char FAR *device, HDC hdc, int dx, int dy, int wx, int wy, int sx, int sy);
+
+ // copy bitmap
+ HGLOBAL gsdll_class::copy_dib(const char FAR *device);
+
+ // copy palette
+ HPALETTE gsdll_class::copy_palette(const char FAR *device);
+};
+#endif // _GSDLL_CLASS_H
+
+
diff --git a/gs/src/dwimg.cpp b/gs/src/dwimg.cpp
new file mode 100644
index 000000000..9cdcc56bd
--- /dev/null
+++ b/gs/src/dwimg.cpp
@@ -0,0 +1,415 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+// dwimg.cpp
+
+
+#define STRICT
+#include <windows.h>
+#include <shellapi.h>
+extern "C" {
+#include "gsdll.h"
+}
+#include "dwmain.h"
+#include "dwdll.h"
+#include "dwimg.h"
+
+extern gsdll_class gsdll;
+
+char szImgName[] = "Ghostscript Image";
+#define M_COPY_CLIP 1
+#if defined(_MSC_VER) && defined(__WIN32__)
+#define _export
+#else
+#define max(a,b) ( (a>b) ? a : b )
+#define min(a,b) ( (a<b) ? a : b )
+#endif
+
+// Forward references
+LRESULT CALLBACK _export WndImgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+HINSTANCE ImageWindow::hInstance;
+HWND ImageWindow::hwndtext;
+ImageWindow *ImageWindow::first;
+
+
+// friend
+ImageWindow *
+FindImageWindow(char FAR *dev)
+{
+ ImageWindow *iw;
+ for (iw = ImageWindow::first; iw!=0; iw=iw->next) {
+ if (iw->device == dev)
+ return iw;
+ }
+ return NULL;
+}
+
+
+// open window for device and add to list
+void
+ImageWindow::open(char FAR *dev)
+{
+ // register class if first window
+ if (first == (ImageWindow *)NULL)
+ register_class();
+
+ // add to list
+ if (first)
+ next = first;
+ first = this;
+
+ // remember device handle
+ device = dev;
+
+ // open window
+ create_window();
+}
+
+// close window and remove from list
+void
+ImageWindow::close(void)
+{
+ DestroyWindow(hwnd);
+
+ // remove from list
+ if (this == first) {
+ first = this->next;
+ }
+ else {
+ ImageWindow *tmp;
+ for (tmp = first; tmp!=0; tmp=tmp->next) {
+ if (this == tmp->next)
+ tmp->next = this->next;
+ }
+ }
+
+}
+
+
+void
+ImageWindow::register_class(void)
+{
+ WNDCLASS wndclass;
+
+ /* register the window class for graphics */
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndImgProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(LONG);
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance,(LPSTR)MAKEINTRESOURCE(GSIMAGE_ICON));
+ wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szImgName;
+ RegisterClass(&wndclass);
+}
+
+void
+ImageWindow::create_window(void)
+{
+ HMENU sysmenu;
+
+ cxClient = cyClient = 0;
+ nVscrollPos = nVscrollMax = 0;
+ nHscrollPos = nHscrollMax = 0;
+
+ // create window
+ hwnd = CreateWindow(szImgName, (LPSTR)szImgName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, hInstance, (void FAR *)this);
+ ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
+
+ // modify the menu to have the new items we want
+ sysmenu = GetSystemMenu(hwnd, 0); // get the sysmenu
+ AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
+}
+
+
+void
+ImageWindow::sync(void)
+{
+ if ( !IsWindow(hwnd) ) // some clod closed the window
+ create_window();
+
+ if ( !IsIconic(hwnd) ) { /* redraw window */
+ InvalidateRect(hwnd, NULL, 1);
+ UpdateWindow(hwnd);
+ }
+}
+
+
+void
+ImageWindow::page(void)
+{
+ if (IsIconic(hwnd)) // useless as an Icon so fix it
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ BringWindowToTop(hwnd);
+
+ sync();
+}
+
+
+void
+ImageWindow::size(int x, int y)
+{
+ width = x;
+ height = y;
+}
+
+
+/* image window */
+LRESULT CALLBACK _export
+WndImgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ ImageWindow *iw;
+ if (message == WM_CREATE) {
+ // Object is stored in window extra data.
+ // Nothing must try to use the object before WM_CREATE
+ // initializes it here.
+ iw = (ImageWindow *)(((CREATESTRUCT FAR *)lParam)->lpCreateParams);
+ SetWindowLong(hwnd, 0, (LONG)iw);
+ }
+
+ // call the object window procedure
+ iw = (ImageWindow *)GetWindowLong(hwnd, 0);
+ return iw->WndProc(hwnd, message, wParam, lParam);
+}
+
+/* graphics window */
+LRESULT
+ImageWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+ int nVscrollInc, nHscrollInc;
+
+ switch(message) {
+ case WM_SYSCOMMAND:
+ // copy to clipboard
+ if (LOWORD(wParam) == M_COPY_CLIP) {
+ HGLOBAL hglobal;
+ HPALETTE hpalette;
+ gsdll.lock_device(device, 1);
+ hglobal = gsdll.copy_dib(device);
+ if (hglobal == (HGLOBAL)NULL) {
+ MessageBox(hwnd, "Not enough memory to Copy to Clipboard",
+ szImgName, MB_OK | MB_ICONEXCLAMATION);
+ gsdll.lock_device(device, 0);
+ return 0;
+ }
+ OpenClipboard(hwnd);
+ EmptyClipboard();
+ SetClipboardData(CF_DIB, hglobal);
+ hpalette = gsdll.copy_palette(device);
+ if (hpalette)
+ SetClipboardData(CF_PALETTE, hpalette);
+ CloseClipboard();
+ gsdll.lock_device(device, 0);
+ return 0;
+ }
+ break;
+ case WM_CREATE:
+ // enable drag-drop
+ DragAcceptFiles(hwnd, TRUE);
+ break;
+ case WM_SIZE:
+ if (wParam == SIZE_MINIMIZED)
+ return(0);
+ cyClient = HIWORD(lParam);
+ cxClient = LOWORD(lParam);
+
+ cyAdjust = min(height, cyClient) - cyClient;
+ cyClient += cyAdjust;
+
+ nVscrollMax = max(0, height - cyClient);
+ nVscrollPos = min(nVscrollPos, nVscrollMax);
+
+ SetScrollRange(hwnd, SB_VERT, 0, nVscrollMax, FALSE);
+ SetScrollPos(hwnd, SB_VERT, nVscrollPos, TRUE);
+
+ cxAdjust = min(width, cxClient) - cxClient;
+ cxClient += cxAdjust;
+
+ nHscrollMax = max(0, width - cxClient);
+ nHscrollPos = min(nHscrollPos, nHscrollMax);
+
+ SetScrollRange(hwnd, SB_HORZ, 0, nHscrollMax, FALSE);
+ SetScrollPos(hwnd, SB_HORZ, nHscrollPos, TRUE);
+
+ if ((wParam==SIZENORMAL) && (cxAdjust!=0 || cyAdjust!=0)) {
+ GetWindowRect(GetParent(hwnd),&rect);
+ MoveWindow(GetParent(hwnd),rect.left,rect.top,
+ rect.right-rect.left+cxAdjust,
+ rect.bottom-rect.top+cyAdjust, TRUE);
+ cxAdjust = cyAdjust = 0;
+ }
+ return(0);
+ case WM_VSCROLL:
+ switch(LOWORD(wParam)) {
+ case SB_TOP:
+ nVscrollInc = -nVscrollPos;
+ break;
+ case SB_BOTTOM:
+ nVscrollInc = nVscrollMax - nVscrollPos;
+ break;
+ case SB_LINEUP:
+ nVscrollInc = -cyClient/16;
+ break;
+ case SB_LINEDOWN:
+ nVscrollInc = cyClient/16;
+ break;
+ case SB_PAGEUP:
+ nVscrollInc = min(-1,-cyClient);
+ break;
+ case SB_PAGEDOWN:
+ nVscrollInc = max(1,cyClient);
+ break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION:
+#ifdef __WIN32__
+ nVscrollInc = HIWORD(wParam) - nVscrollPos;
+#else
+ nVscrollInc = LOWORD(lParam) - nVscrollPos;
+#endif
+ break;
+ default:
+ nVscrollInc = 0;
+ }
+ if ((nVscrollInc = max(-nVscrollPos,
+ min(nVscrollInc, nVscrollMax - nVscrollPos)))!=0) {
+ nVscrollPos += nVscrollInc;
+ ScrollWindow(hwnd,0,-nVscrollInc,NULL,NULL);
+ SetScrollPos(hwnd,SB_VERT,nVscrollPos,TRUE);
+ UpdateWindow(hwnd);
+ }
+ return(0);
+ case WM_HSCROLL:
+ switch(LOWORD(wParam)) {
+ case SB_LINEUP:
+ nHscrollInc = -cxClient/16;
+ break;
+ case SB_LINEDOWN:
+ nHscrollInc = cyClient/16;
+ break;
+ case SB_PAGEUP:
+ nHscrollInc = min(-1,-cxClient);
+ break;
+ case SB_PAGEDOWN:
+ nHscrollInc = max(1,cxClient);
+ break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION:
+#ifdef __WIN32__
+ nHscrollInc = HIWORD(wParam) - nHscrollPos;
+#else
+ nHscrollInc = LOWORD(lParam) - nHscrollPos;
+#endif
+ break;
+ default:
+ nHscrollInc = 0;
+ }
+ if ((nHscrollInc = max(-nHscrollPos,
+ min(nHscrollInc, nHscrollMax - nHscrollPos)))!=0) {
+ nHscrollPos += nHscrollInc;
+ ScrollWindow(hwnd,-nHscrollInc,0,NULL,NULL);
+ SetScrollPos(hwnd,SB_HORZ,nHscrollPos,TRUE);
+ UpdateWindow(hwnd);
+ }
+ return(0);
+ case WM_KEYDOWN:
+ switch(LOWORD(wParam)) {
+ case VK_HOME:
+ SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L);
+ break;
+ case VK_END:
+ SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0L);
+ break;
+ case VK_PRIOR:
+ SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L);
+ break;
+ case VK_NEXT:
+ SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L);
+ break;
+ case VK_UP:
+ SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L);
+ break;
+ case VK_DOWN:
+ SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L);
+ break;
+ case VK_LEFT:
+ SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L);
+ break;
+ case VK_RIGHT:
+ SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L);
+ break;
+ case VK_RETURN:
+ BringWindowToTop(hwndtext);
+ break;
+ }
+ return(0);
+ case WM_CHAR:
+ // send on all characters to text window
+ if (hwndtext)
+ SendMessage(hwndtext, message, wParam, lParam);
+ return 0;
+ case WM_PAINT:
+ {
+ int sx,sy,wx,wy,dx,dy;
+ hdc = BeginPaint(hwnd, &ps);
+ SetMapMode(hdc, MM_TEXT);
+ SetBkMode(hdc,OPAQUE);
+ gsdll.lock_device(device, 1);
+ rect = ps.rcPaint;
+ dx = rect.left; /* destination */
+ dy = rect.top;
+ wx = rect.right-rect.left; /* width */
+ wy = rect.bottom-rect.top;
+ sx = rect.left; /* source */
+ sy = rect.top;
+ sx += nHscrollPos; /* scrollbars */
+ sy += nVscrollPos;
+ if (sx+wx > width)
+ wx = width - sx;
+ if (sy+wy > height)
+ wy = height - sy;
+
+ gsdll.draw(device, hdc, dx, dy, wx, wy, sx, sy);
+ gsdll.lock_device(device, 0);
+
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+ case WM_DROPFILES:
+ SendMessage(hwndtext, message, wParam, lParam);
+ break;
+ case WM_DESTROY:
+ DragAcceptFiles(hwnd, FALSE);
+ break;
+
+ }
+
+not_ours:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
diff --git a/gs/src/dwimg.h b/gs/src/dwimg.h
new file mode 100644
index 000000000..ad468a093
--- /dev/null
+++ b/gs/src/dwimg.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwimg.h
+
+class ImageWindow {
+ static ImageWindow *first;
+ ImageWindow *next;
+
+ HWND hwnd;
+ char FAR *device; // handle to Ghostscript device
+ int width, height;
+
+ // Window scrolling stuff
+ int cxClient, cyClient;
+ int cxAdjust, cyAdjust;
+ int nVscrollPos, nVscrollMax;
+ int nHscrollPos, nHscrollMax;
+
+ void register_class(void);
+
+public:
+ static HINSTANCE hInstance; // instance of EXE
+ static HWND hwndtext; // handle to text window
+ friend ImageWindow *FindImageWindow(char FAR *dev);
+ void open(char FAR *dev);
+ void close(void);
+ void sync(void);
+ void page(void);
+ void size(int x, int y);
+ void create_window(void);
+ LRESULT WndProc(HWND, UINT, WPARAM, LPARAM);
+};
+
+
diff --git a/gs/src/dwmain.cpp b/gs/src/dwmain.cpp
new file mode 100644
index 000000000..75d573e2e
--- /dev/null
+++ b/gs/src/dwmain.cpp
@@ -0,0 +1,412 @@
+/* Copyright (C) 1996, 1997, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwmain.cpp
+// Ghostscript DLL loader for Windows
+
+#define STRICT
+#include <windows.h>
+#include <shellapi.h>
+#ifndef __WIN32__
+#include <toolhelp.h>
+static BOOL dllfix(void);
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dos.h>
+extern "C" {
+#include "gscdefs.h"
+#define GSREVISION gs_revision
+#include "gsdll.h"
+}
+#include "dwmain.h"
+#include "dwdll.h"
+#include "dwtext.h"
+#include "dwimg.h"
+
+#if defined(_MSC_VER) && defined(__WIN32__)
+#define _export
+#endif
+
+/* public handles */
+HINSTANCE ghInstance;
+
+/* redirected stdio */
+TextWindow tw;
+
+const LPSTR szAppName = "Ghostscript";
+
+#ifdef __WIN32__
+const LPSTR szIniName = "GSWIN32.INI";
+const char *szDllName = "GSDLL32.DLL";
+#else
+const LPSTR szIniName = "GSWIN.INI";
+const char *szDllName = "GSDLL16.DLL";
+#endif
+const LPSTR szIniSection = "Text";
+
+int dll_exit_status;
+
+int FAR _export gsdll_callback(int message, char FAR *str, unsigned long count);
+
+// the Ghostscript DLL class
+gsdll_class gsdll;
+
+char start_string[] = "systemdict /start get exec\n";
+
+// program really starts at WinMain
+int
+new_main(int argc, char *argv[])
+{
+typedef char FAR * FARARGV_PTR;
+FARARGV_PTR *far_argv;
+int rc;
+
+ // load DLL
+ if (gsdll.load(ghInstance, szDllName, GSREVISION)) {
+ char buf[256];
+ gsdll.get_last_error(buf, sizeof(buf));
+ tw.puts(buf);
+ return 1;
+ }
+
+
+#ifdef __WIN32__
+ far_argv = argv;
+#else
+ far_argv = new FARARGV_PTR[argc+1];
+ if (!far_argv)
+ return 1;
+ for (int i = 0; i<argc; i++)
+ far_argv[i] = argv[i]; // convert from near to far pointers
+ far_argv[i+1] = NULL;
+#endif
+
+ // initialize the interpreter
+ rc = gsdll.init(gsdll_callback, tw.get_handle(), argc, far_argv);
+ if (rc == GSDLL_INIT_QUIT) {
+ gsdll.unload();
+ return 0;
+ }
+ if (rc) {
+ char buf[256];
+ gsdll.get_last_error(buf, sizeof(buf));
+ tw.puts(buf);
+ gsdll.unload();
+#ifndef __WIN32__
+ if (rc == GSDLL_INIT_IN_USE)
+ dllfix(); // offer option to unload NASTY!
+#endif
+ return rc;
+ }
+
+ // if (!batch)
+ gsdll.execute(start_string, strlen(start_string));
+
+#ifdef UNUSED
+ int len;
+ char line[256];
+ do {
+ len = tw.read_line(line, sizeof(line));
+ } while ( len && !gsdll.execute(line, len) );
+#endif
+
+ gsdll.unload();
+
+ return 0;
+}
+
+
+/* our exit handler */
+/* also called from Text Window WM_CLOSE */
+void win_exit(void)
+{
+ if (dll_exit_status) {
+ /* display message box so error messages in text window can be read */
+ char buf[80];
+ if (IsIconic(tw.get_handle()))
+ ShowWindow(tw.get_handle(), SW_SHOWNORMAL);
+ BringWindowToTop(tw.get_handle()); /* make text window visible */
+ sprintf(buf, "Exit code %d\nSee text window for details",dll_exit_status);
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ }
+}
+
+void
+set_font(void)
+{
+ int fontsize;
+ char fontname[256];
+ char buf[32];
+
+ // read ini file
+ GetPrivateProfileString(szIniSection, "FontName", "Courier New", fontname, sizeof(fontname), szIniName);
+ fontsize = GetPrivateProfileInt(szIniSection, "FontSize", 10, szIniName);
+
+ // set font
+ tw.font(fontname, fontsize);
+
+ // write ini file
+ WritePrivateProfileString(szIniSection, "FontName", fontname, szIniName);
+ sprintf(buf, "%d", fontsize);
+ WritePrivateProfileString(szIniSection, "FontSize", buf, szIniName);
+}
+
+int PASCAL
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
+{
+#if defined(_MSC_VER) /* MSC doesn't give us _argc and _argv[] so ... */
+#define MAXCMDTOKENS 128
+ int _argc=0;
+ LPSTR _argv[MAXCMDTOKENS];
+ LPSTR p, q;
+#ifdef __WIN32__
+ _argv[_argc] = "gswin32.exe";
+#else
+ _argv[_argc] = "gswin.exe";
+#endif
+ // Parse command line handling quotes.
+ p = lpszCmdLine;
+ while (*p) {
+ // for each argument
+ while ((*p) && (*p == ' '))
+ p++; // skip over leading spaces
+ if (*p == '\042') {
+ p++; // skip "
+ q = p;
+ // scan to end of argument
+ // doesn't handle embedded quotes
+ while ((*p) && (*p != '\042'))
+ p++;
+ _argv[++_argc] = q;
+ if (*p)
+ *p++ = '\0';
+ }
+ else if (*p) {
+ // delimited by spaces
+ q = p;
+ while ((*p) && (*p != ' '))
+ p++;
+ _argv[++_argc] = q;
+ if (*p)
+ *p++ = '\0';
+ }
+ }
+ _argv[++_argc] = (LPSTR)NULL;
+#endif
+
+ if (hPrevInstance) {
+ MessageBox((HWND)NULL,"Can't run twice", szAppName, MB_ICONHAND | MB_OK);
+ return FALSE;
+ }
+
+ /* copy the hInstance into a variable so it can be used */
+ ghInstance = hInstance;
+
+
+ /* start up the text window */
+ if (!hPrevInstance) {
+ HICON hicon = LoadIcon(hInstance, (LPSTR)MAKEINTRESOURCE(GSTEXT_ICON));
+ tw.register_class(hInstance, hicon);
+ }
+ set_font();
+ tw.size(80, 80);
+ tw.drag("(", ") run\r");
+
+ // create the text window
+ if (tw.create(szAppName, cmdShow))
+ exit(1);
+
+ // initialize for image windows
+ ImageWindow::hwndtext = tw.get_handle();
+ ImageWindow::hInstance = hInstance;
+
+ dll_exit_status = new_main(_argc, _argv);
+
+ win_exit();
+
+ tw.destroy();
+
+ return dll_exit_status;
+}
+
+
+int FAR _export
+gsdll_callback(int message, char FAR *str, unsigned long count)
+{
+char buf[256];
+ImageWindow *iw;
+ switch (message) {
+ case GSDLL_POLL:
+ {
+ MSG msg;
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ // If text window closed then abort Ghostscript
+ if (!IsWindow(tw.get_handle()))
+ return -1;
+ break;
+ case GSDLL_STDIN:
+ return tw.read_line(str, count);
+ case GSDLL_STDOUT:
+ if (str != (char *)NULL)
+ tw.write_buf(str, count);
+ return count;
+ case GSDLL_DEVICE:
+#ifdef DEBUG
+ sprintf(buf,"Callback: DEVICE %p %s\n", (char *)str,
+ count ? "open" : "close");
+ tw.puts(buf);
+#endif
+ if (count) {
+ iw = new ImageWindow;
+ iw->open(str);
+ }
+ else {
+ iw = FindImageWindow(str);
+ iw->close();
+ }
+ break;
+ case GSDLL_SYNC:
+#ifdef DEBUG
+ sprintf(buf,"Callback: SYNC %p\n", (char *)str);
+ tw.puts(buf);
+#endif
+ iw = FindImageWindow(str);
+ iw->sync();
+ break;
+ case GSDLL_PAGE:
+#ifdef DEBUG
+ sprintf(buf,"Callback: PAGE %p\n", (char *)str);
+ tw.puts(buf);
+#endif
+ iw = FindImageWindow(str);
+ iw->page();
+ break;
+ case GSDLL_SIZE:
+#ifdef DEBUG
+ sprintf(buf,"Callback: SIZE %p width=%d height=%d\n", (char *)str,
+ (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
+ tw.puts(buf);
+#endif
+ iw = FindImageWindow(str);
+ iw->size( (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
+ break;
+ default:
+ sprintf(buf,"Callback: Unknown message=%d\n",message);
+ tw.puts(buf);
+ break;
+ }
+ return 0;
+}
+
+
+#ifndef __WIN32__
+// This is a hack to cope with a GPF occuring in either Ghostscript
+// or a driver loaded by Ghostscript. If a GPF occurs, gswin16.exe
+// is unloaded, but not gsdll16.dll.
+// Attempts to reload gswin16.exe will fail because gsdll16.dll
+// is already in use. If this occurs, this code will unload
+// gsdll16.dll, EVEN IF SOMEONE ELSE IS USING IT.
+
+// The DLL module name as it appears in the module definition file
+#define GSDLLNAME "GSDLL16"
+// These are the names of EXE modules that are known users
+// of the Ghostscript DLL.
+// If one of these is running, it is not safe to unload the DLL.
+#define GSEXE "GSWIN16"
+
+typedef HMODULE (WINAPI *TOOLMFN)(MODULEENTRY FAR *, LPCSTR);
+
+static BOOL
+dllfix(void)
+{
+HMODULE hdll; // module handle of DLL
+HMODULE hgswin16; // module handle of Ghostscript
+MODULEENTRY me_dll; // to contain details about DLL module
+MODULEENTRY me_gswin16; // details about Ghostscript
+HINSTANCE htool; // module handle of TOOLHELP.DLL
+TOOLMFN lpfnModuleFindName = NULL;
+char buf[256];
+BOOL err = FALSE;
+
+ // load TOOLHELP.DLL
+ htool = LoadLibrary("TOOLHELP.DLL");
+ if ( htool <= HINSTANCE_ERROR )
+ err = TRUE;
+
+ // get address of toolhelp function
+ if (!err) {
+ lpfnModuleFindName = (TOOLMFN)GetProcAddress(htool, "ModuleFindName");
+ err = !lpfnModuleFindName;
+ }
+
+ // find handle for DLL
+ if (!err) {
+ memset(&me_dll, 0, sizeof(me_dll));
+ me_dll.dwSize = sizeof(me_dll);
+ hdll = lpfnModuleFindName(&me_dll, GSDLLNAME);
+ }
+
+ // look for Ghostscript EXE module
+ // This should be found because we are it
+ if (!err) {
+ memset(&me_gswin16, 0, sizeof(me_gswin16));
+ me_gswin16.dwSize = sizeof(me_gswin16);
+ hgswin16 = lpfnModuleFindName(&me_gswin16, GSEXE);
+ }
+
+#ifdef DEBUG
+ // for debugging, show what we have found
+ if (hdll) {
+ wsprintf(buf, "Found %s\nModule Handle=%d\nModule Usage=%d\nModule Path=%s",
+ me_dll.szModule, me_dll.hModule, me_dll.wcUsage, me_dll.szExePath);
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK);
+ }
+ if (hgswin16) {
+ wsprintf(buf, "Found %s\nModule Handle=%d\nModule Usage=%d\nModule Path=%s",
+ me_gswin16.szModule, me_gswin16.hModule, me_gswin16.wcUsage,
+ me_gswin16.szExePath);
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK);
+ }
+#endif
+
+ // if DLL loaded and Ghostscript is not running...
+ if (!err &&
+ hdll && // Ghostscript DLL loaded
+ (hgswin16 && me_gswin16.wcUsage == 1) // Only one copy of Ghostscript EXE
+ ) {
+ wsprintf(buf, "%s is loaded but does not appear to be in use by Ghostscript. Unload it?", GSDLLNAME);
+ if (MessageBox((HWND)NULL, buf, szAppName, MB_YESNO | MB_ICONHAND) == IDYES)
+ // If DLL is really in use, we about to cause a disaster
+ while (GetModuleUsage(hdll))
+ FreeLibrary(hdll);
+ }
+
+ if (htool)
+ FreeLibrary(htool);
+ return err;
+}
+#endif
+
diff --git a/gs/src/dwmain.h b/gs/src/dwmain.h
new file mode 100644
index 000000000..cafe03d33
--- /dev/null
+++ b/gs/src/dwmain.h
@@ -0,0 +1,5 @@
+// dwmain.h
+
+#define GSTEXT_ICON 50
+#define GSIMAGE_ICON 51
+
diff --git a/gs/src/dwmain.rc b/gs/src/dwmain.rc
new file mode 100644
index 000000000..3b5591870
--- /dev/null
+++ b/gs/src/dwmain.rc
@@ -0,0 +1,30 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+/* dwmain.rc */
+#include <windows.h>
+#include "dwmain.h"
+
+GSTEXT_ICON ICON gstext.ico
+GSIMAGE_ICON ICON gsgraph.ico
+
+#ifndef DS_3DLOOK
+#define DS_3DLOOK 0x0004L /* for Windows 95 look */
+#endif
+
diff --git a/gs/src/dwmain16.def b/gs/src/dwmain16.def
new file mode 100644
index 000000000..5771c3e1b
--- /dev/null
+++ b/gs/src/dwmain16.def
@@ -0,0 +1,7 @@
+NAME GSWIN16
+DESCRIPTION 'Ghostscript Interpreter'
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE PRELOAD
+DATA MULTIPLE MOVEABLE PRELOAD
+HEAPSIZE 256
+STACKSIZE 16384
diff --git a/gs/src/dwmain32.def b/gs/src/dwmain32.def
new file mode 100644
index 000000000..1bf8603a4
--- /dev/null
+++ b/gs/src/dwmain32.def
@@ -0,0 +1,7 @@
+NAME GSWIN32
+DESCRIPTION 'Ghostscript Interpreter'
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE PRELOAD
+DATA MULTIPLE MOVEABLE PRELOAD
+HEAPSIZE 256
+STACKSIZE 32768
diff --git a/gs/src/dwmainc.cpp b/gs/src/dwmainc.cpp
new file mode 100644
index 000000000..6ab6daeb1
--- /dev/null
+++ b/gs/src/dwmainc.cpp
@@ -0,0 +1,219 @@
+/* Copyright (C) 1996, 1997, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwmainc.cpp
+// Ghostscript DLL loader for Windows 95/NT
+// For WINDOWCOMPAT (console mode) application
+
+#define STRICT
+#include <windows.h>
+#include <shellapi.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dos.h>
+extern "C" {
+#include "gscdefs.h"
+#define GSREVISION gs_revision
+#include "gsdll.h"
+}
+#include "dwmain.h"
+#include "dwdll.h"
+
+#if defined(_MSC_VER) && defined(__WIN32__)
+#define _export
+#endif
+
+/* public handles */
+HINSTANCE ghInstance;
+
+const char *szDllName = "GSDLL32.DLL";
+
+
+int FAR _export gsdll_callback(int message, char FAR *str, unsigned long count);
+
+// the Ghostscript DLL class
+gsdll_class gsdll;
+
+char start_string[] = "systemdict /start get exec\n";
+
+// program really starts at WinMain
+int
+new_main(int argc, char *argv[])
+{
+typedef char FAR * FARARGV_PTR;
+int rc;
+
+ // load DLL
+ if (gsdll.load(ghInstance, szDllName, GSREVISION)) {
+ char buf[256];
+ gsdll.get_last_error(buf, sizeof(buf));
+ fputs(buf, stdout);
+ return 1;
+ }
+
+ // initialize the interpreter
+ rc = gsdll.init(gsdll_callback, (HWND)NULL, argc, argv);
+ if (rc == GSDLL_INIT_QUIT) {
+ gsdll.unload();
+ return 0;
+ }
+ if (rc) {
+ char buf[256];
+ gsdll.get_last_error(buf, sizeof(buf));
+ fputs(buf, stdout);
+ gsdll.unload();
+ return rc;
+ }
+
+ // if (!batch)
+ gsdll.execute(start_string, strlen(start_string));
+
+ gsdll.unload();
+
+ return 0;
+}
+
+
+#if defined(_MSC_VER)
+/* MSVC Console EXE needs main() */
+int
+main(int argc, char *argv[])
+{
+ /* need to get instance handle */
+ ghInstance = GetModuleHandle(NULL);
+
+ return new_main(argc, argv);
+}
+#else
+/* Borland Console EXE needs WinMain() */
+#pragma argsused // ignore warning about unused arguments in next function
+
+int PASCAL
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
+{
+#if defined(_MSC_VER) /* MSC doesn't give us _argc and _argv[] so ... */
+#define MAXCMDTOKENS 128
+ int _argc=0;
+ LPSTR _argv[MAXCMDTOKENS];
+ LPSTR p, q;
+#ifdef __WIN32__
+ _argv[_argc] = "gswin32.exe";
+#else
+ _argv[_argc] = "gswin.exe";
+#endif
+ // Parse command line handling quotes.
+ p = lpszCmdLine;
+ while (*p) {
+ // for each argument
+ while ((*p) && (*p == ' '))
+ p++; // skip over leading spaces
+ if (*p == '\042') {
+ p++; // skip "
+ q = p;
+ // scan to end of argument
+ // doesn't handle embedded quotes
+ while ((*p) && (*p != '\042'))
+ p++;
+ _argv[++_argc] = q;
+ if (*p)
+ *p++ = '\0';
+ }
+ else if (*p) {
+ // delimited by spaces
+ q = p;
+ while ((*p) && (*p != ' '))
+ p++;
+ _argv[++_argc] = q;
+ if (*p)
+ *p++ = '\0';
+ }
+ }
+ _argv[++_argc] = (LPSTR)NULL;
+#endif
+
+ if (hPrevInstance) {
+ fputs("Can't run twice", stdout);
+ return FALSE;
+ }
+
+ /* copy the hInstance into a variable so it can be used */
+ ghInstance = hInstance;
+
+ return new_main(_argc, _argv);
+}
+#endif
+
+
+int
+read_stdin(char FAR *str, int len)
+{
+int ch;
+int count = 0;
+ while (count < len) {
+ ch = fgetc(stdin);
+ if (ch == EOF)
+ return count;
+ *str++ = ch;
+ count++;
+ if (ch == '\n')
+ return count;
+ }
+ return count;
+}
+
+
+int FAR _export
+gsdll_callback(int message, char FAR *str, unsigned long count)
+{
+char buf[256];
+ switch (message) {
+ case GSDLL_POLL:
+ // Don't check message queue because we don't
+ // create any windows.
+ // May want to return error code if abort wanted
+ break;
+ case GSDLL_STDIN:
+ return read_stdin(str, count);
+ case GSDLL_STDOUT:
+ fwrite(str, 1, count, stdout);
+ fflush(stdout);
+ return count;
+ case GSDLL_DEVICE:
+ if (count) {
+ fputs("mswindll device not supported by the command\n\
+line version of Ghostscript. Select a different device using\n\
+-sDEVICE= as described in use.txt.\n", stdout);
+ }
+ break;
+ case GSDLL_SYNC:
+ break;
+ case GSDLL_PAGE:
+ break;
+ case GSDLL_SIZE:
+ break;
+ default:
+ sprintf(buf,"Callback: Unknown message=%d\n",message);
+ fputs(buf, stdout);
+ break;
+ }
+ return 0;
+}
+
+
diff --git a/gs/src/dwnodll.cpp b/gs/src/dwnodll.cpp
new file mode 100644
index 000000000..57516768a
--- /dev/null
+++ b/gs/src/dwnodll.cpp
@@ -0,0 +1,349 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwnodll.cpp
+
+// gsdll class for MS-Windows
+
+// Alternate implementation which doesn't use a DLL at all.
+// Instead Ghostscript is statically linked in to the EXE
+// and this code makes dw*.c think that it really does have
+// the GS DLL loaded.
+
+
+#define STRICT
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+extern "C" {
+#include "gsdll.h"
+}
+
+#include "dwdll.h" // gsdll_class
+
+static char not_loaded[] = "DLL is not loaded";
+static char func_null[] = "A function pointer to the DLL is NULL";
+static char not_init[] = "Not initialized";
+
+int
+gsdll_class::load(const HINSTANCE in_hinstance,
+ const char *name, const long need_version)
+{
+ // Don't load if already loaded
+ if (hmodule)
+ return 0;
+ hinstance = in_hinstance;
+ initialized = FALSE;
+
+ // Act like we have loaded the DLL
+ // Use the caller instance so that resources are loaded correctly
+ hmodule = hinstance;
+
+// Need to cause the same thing to happen in gp_mswin.c
+
+
+ // Get pointers to functions
+ // Under Win32, nothing special is needed.
+ // Under Win16, the functions are _export and hence need a
+ // thunk created by MakeProcInstance
+#ifdef __WIN32__
+ c_revision = gsdll_revision;
+ c_init = gsdll_init;
+ c_execute_begin = gsdll_execute_begin;
+ c_execute_cont = gsdll_execute_cont;
+ c_execute_end = gsdll_execute_end;
+ c_exit = gsdll_exit;
+ c_lock_device = gsdll_lock_device;
+ c_copy_dib = gsdll_copy_dib;
+ c_copy_palette = gsdll_copy_palette;
+ c_draw = gsdll_draw;
+#else
+ c_revision = (PFN_gsdll_revision) MakeProcInstance(gsdll_revision, hmodule);
+ if (c_revision == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_revision\n");
+ unload();
+ return 1;
+ }
+ // check DLL version
+ c_revision(NULL, NULL, &version, NULL);
+ if (version != need_version) {
+ sprintf(last_error, "Wrong version of DLL found.\n Found version %ld\n Need version %ld\n", version, need_version);
+ unload();
+ return 1;
+ }
+
+ // continue loading other functions */
+ c_init = (PFN_gsdll_init) MakeProcInstance(gsdll_init, hmodule);
+ if (c_init == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_init\n");
+ unload();
+ return 1;
+ }
+ c_execute_begin = (PFN_gsdll_execute_begin) MakeProcInstance(gsdll_execute_begin, hmodule);
+ if (c_execute_begin == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_execute_begin\n");
+ unload();
+ return 1;
+ }
+ c_execute_cont = (PFN_gsdll_execute_cont) MakeProcInstance(gsdll_execute_cont, hmodule);
+ if (c_execute_cont == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_execute_cont\n");
+ unload();
+ return 1;
+ }
+ c_execute_end = (PFN_gsdll_execute_end) MakeProcInstance(gsdll_execute_end, hmodule);
+ if (c_execute_end == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_execute_end\n");
+ unload();
+ return 1;
+ }
+ c_exit = (PFN_gsdll_exit) MakeProcInstance(gsdll_exit, hmodule);
+ if (c_exit == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_exit\n");
+ unload();
+ return 1;
+ }
+ c_lock_device = (PFN_gsdll_lock_device) MakeProcInstance(gsdll_lock_device, hmodule);
+ if (c_lock_device == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_lock_device\n");
+ unload();
+ return 1;
+ }
+ c_copy_dib = (PFN_gsdll_copy_dib) MakeProcInstance(gsdll_copy_dib, hmodule);
+ if (c_copy_dib == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_copy_dib\n");
+ unload();
+ return 1;
+ }
+ c_copy_palette = (PFN_gsdll_copy_palette) MakeProcInstance(gsdll_copy_palette, hmodule);
+ if (c_copy_palette == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_copy_palette\n");
+ unload();
+ return 1;
+ }
+ c_draw = (PFN_gsdll_draw) MakeProcInstance(gsdll_draw, hmodule);
+ if (c_draw == NULL) {
+ sprintf(last_error, "Can't make prolog for gsdll_draw\n");
+ unload();
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int
+gsdll_class::unload(void)
+{
+ // exit Ghostscript interpreter
+ if (initialized) {
+ if (!execute_code)
+ c_execute_end();
+ c_exit();
+#ifndef __WIN32__
+ FreeProcInstance((FARPROC)callback);
+#endif
+ callback = NULL;
+ }
+
+ // For Win16, must free the thunks.
+#ifndef __WIN32__
+// is it safe to call these with NULL pointers?
+ FreeProcInstance(c_revision);
+ FreeProcInstance(c_init);
+ FreeProcInstance(c_execute_begin);
+ FreeProcInstance(c_execute_cont);
+ FreeProcInstance(c_execute_end);
+ FreeProcInstance(c_exit);
+ FreeProcInstance(c_lock_device);
+ FreeProcInstance(c_copy_dib);
+ FreeProcInstance(c_copy_palette);
+ FreeProcInstance(c_draw);
+#endif
+
+ // Set functions to NULL to prevent use
+ c_revision = NULL;
+ c_init = NULL;
+ c_execute_begin = NULL;
+ c_execute_cont = NULL;
+ c_execute_end = NULL;
+ c_exit = NULL;
+ c_lock_device = NULL;
+ c_copy_dib = NULL;
+ c_copy_palette = NULL;
+ c_draw = NULL;
+
+ // need to do more than this
+ device = NULL;
+
+ // Don't do anything else if already unloaded
+ if (hmodule == (HINSTANCE)NULL)
+ return 0;
+
+ return 0;
+}
+
+int
+gsdll_class::revision(char FAR * FAR *product, char FAR * FAR *copyright,
+ long FAR *revision, long FAR *revisiondate)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!c_revision)
+ return c_revision(product, copyright, revision, revisiondate);
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::init(GSDLL_CALLBACK in_callback, HWND hwnd, int argc, char FAR * FAR *argv)
+{
+int rc;
+ execute_code = 0;
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (initialized) {
+ strcpy(last_error, "Already initialized");
+ return 1;
+ }
+ if (in_callback == (GSDLL_CALLBACK)NULL) {
+ strcpy(last_error, "Callback not provided");
+ return 1;
+ }
+
+#ifdef __WIN32__
+ callback = in_callback;
+#else
+ callback = (GSDLL_CALLBACK)MakeProcInstance((FARPROC)in_callback, hinstance);
+#endif
+
+ if (c_init && c_execute_begin) {
+ rc = c_init(callback, hwnd, argc, argv);
+ if (rc) {
+ sprintf(last_error, "gsdll_init returns %d\nDLL already in use", rc);
+ return rc;
+ }
+ else {
+ if ((rc = c_execute_begin()) != 0)
+ sprintf(last_error, "gsdll_execute_begin returns %d", rc);
+ else
+ initialized = TRUE;
+ return rc;
+ }
+ }
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::restart(int argc, char FAR * FAR *argv)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!initialized) {
+ strcpy(last_error, not_init);
+ return 1;
+ }
+ if (c_execute_end && c_exit) {
+ if (!execute_code)
+ c_execute_end();
+ c_exit();
+#ifndef __WIN32__
+ FreeProcInstance((FARPROC)callback);
+#endif
+ // ignore return codes since they we may be aborting from an error
+ initialized = FALSE;
+ return init(callback, hwnd, argc, argv);
+ }
+
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::get_last_error(char *str, int len)
+{
+ strncpy(str, last_error,
+ (len < sizeof(last_error) ? len : sizeof(last_error)));
+ return 0;
+}
+
+
+int
+gsdll_class::execute(const char FAR *str, int len)
+{
+ if (!hmodule) {
+ strcpy(last_error, not_loaded);
+ return 1;
+ }
+ if (!initialized) {
+ strcpy(last_error, not_init);
+ return 1;
+ }
+ if (c_execute_cont) {
+ execute_code = c_execute_cont(str, len);
+ return execute_code;
+ }
+
+ strcpy(last_error, func_null);
+ return 1;
+}
+
+int
+gsdll_class::draw(const char FAR *device, HDC hdc, int dx, int dy, int wx, int wy, int sx, int sy)
+{
+RECT source, dest;
+ source.left = sx;
+ source.right = sx+wx;
+ source.top = sy;
+ source.bottom = sy+wy;
+
+ dest.left = dx;
+ dest.right = dx+wx;
+ dest.top = dy;
+ dest.bottom = dy+wy;
+ c_draw((unsigned char FAR *)device, hdc, &dest, &source);
+ return 0;
+}
+
+HPALETTE
+gsdll_class::copy_palette(const char FAR *device)
+{
+ return c_copy_palette((unsigned char FAR *)device);
+}
+
+
+HGLOBAL
+gsdll_class::copy_dib(const char FAR *device)
+{
+ return c_copy_dib((unsigned char FAR *)device);
+}
+
+
+int
+gsdll_class::lock_device(const char FAR *device, int lock)
+{
+ return c_lock_device((unsigned char FAR *)device, lock);
+}
diff --git a/gs/src/dwtext.cpp b/gs/src/dwtext.cpp
new file mode 100644
index 000000000..03176b839
--- /dev/null
+++ b/gs/src/dwtext.cpp
@@ -0,0 +1,964 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwtext.cpp
+
+
+// Microsoft Windows 3.n text window for Ghostscript.
+
+#include <stdlib.h>
+#include <string.h> // use only far items
+#include <ctype.h>
+
+#define STRICT
+#include <windows.h>
+#include <windowsx.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include "dwtext.h"
+
+#if defined(_MSC_VER) && defined(__WIN32__)
+#define _export
+#else
+#define max(a,b) ( (a>b) ? a : b )
+#define min(a,b) ( (a<b) ? a : b )
+#endif
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+/* sysmenu */
+#define M_COPY_CLIP 1
+
+LRESULT CALLBACK _export WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+static const char* TextWinClassName = "rjlTextWinClass";
+static const POINT TextWinMinSize = {16, 4};
+
+void
+TextWindow::error(char *message)
+{
+ MessageBox((HWND)NULL,message,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
+}
+
+/* Bring Cursor into text window */
+void
+TextWindow::to_cursor(void)
+{
+int nXinc=0;
+int nYinc=0;
+int cxCursor;
+int cyCursor;
+ cyCursor = CursorPos.y * CharSize.y;
+ if ( (cyCursor + CharSize.y > ScrollPos.y + ClientSize.y)
+// || (cyCursor < ScrollPos.y) ) {
+// change to scroll to end of window instead of just making visible
+// so that ALL of error message can be seen
+ || (cyCursor < ScrollPos.y+ClientSize.y) ) {
+ nYinc = max(0, cyCursor + CharSize.y - ClientSize.y) - ScrollPos.y;
+ nYinc = min(nYinc, ScrollMax.y - ScrollPos.y);
+ }
+ cxCursor = CursorPos.x * CharSize.x;
+ if ( (cxCursor + CharSize.x > ScrollPos.x + ClientSize.x)
+ || (cxCursor < ScrollPos.x) ) {
+ nXinc = max(0, cxCursor + CharSize.x - ClientSize.x/2) - ScrollPos.x;
+ nXinc = min(nXinc, ScrollMax.x - ScrollPos.x);
+ }
+ if (nYinc || nXinc) {
+ ScrollPos.y += nYinc;
+ ScrollPos.x += nXinc;
+ ScrollWindow(hwnd,-nXinc,-nYinc,NULL,NULL);
+ SetScrollPos(hwnd,SB_VERT,ScrollPos.y,TRUE);
+ SetScrollPos(hwnd,SB_HORZ,ScrollPos.x,TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+void
+TextWindow::new_line(void)
+{
+ CursorPos.x = 0;
+ CursorPos.y++;
+ if (CursorPos.y >= ScreenSize.y) {
+ int i = ScreenSize.x * (ScreenSize.y - 1);
+ _fmemmove(ScreenBuffer, ScreenBuffer+ScreenSize.x, i);
+ _fmemset(ScreenBuffer + i, ' ', ScreenSize.x);
+ CursorPos.y--;
+ ScrollWindow(hwnd,0,-CharSize.y,NULL,NULL);
+ UpdateWindow(hwnd);
+ }
+ if (CursorFlag)
+ to_cursor();
+// TextMessage();
+}
+
+/* Update count characters in window at cursor position */
+/* Updates cursor position */
+void
+TextWindow::update_text(int count)
+{
+HDC hdc;
+int xpos, ypos;
+ xpos = CursorPos.x*CharSize.x - ScrollPos.x;
+ ypos = CursorPos.y*CharSize.y - ScrollPos.y;
+ hdc = GetDC(hwnd);
+ SelectFont(hdc, hfont);
+ TextOut(hdc,xpos,ypos,
+ (LPSTR)(ScreenBuffer + CursorPos.y*ScreenSize.x + CursorPos.x),
+ count);
+ (void)ReleaseDC(hwnd,hdc);
+ CursorPos.x += count;
+ if (CursorPos.x >= ScreenSize.x)
+ new_line();
+}
+
+
+void
+TextWindow::size(int width, int height)
+{
+ ScreenSize.x = max(width, TextWinMinSize.x);
+ ScreenSize.y = max(height, TextWinMinSize.y);
+}
+
+void
+TextWindow::font(const char *name, int size)
+{
+ // reject inappropriate arguments
+ if (name == NULL)
+ return;
+ if (size < 4)
+ return;
+
+ // set new name and size
+ fontname = new char[strlen(name)+1];
+ if (fontname == NULL)
+ return;
+ strcpy(fontname, name);
+ fontsize = size;
+
+ // make a new font
+ LOGFONT lf;
+ TEXTMETRIC tm;
+ LPSTR p;
+ HDC hdc;
+
+ // if window not open, hwnd == 0 == HWND_DESKTOP
+ hdc = GetDC(hwnd);
+ _fmemset(&lf, 0, sizeof(LOGFONT));
+ _fstrncpy(lf.lfFaceName,fontname,LF_FACESIZE);
+ lf.lfHeight = -MulDiv(fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ lf.lfPitchAndFamily = FIXED_PITCH;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ if ( (p = _fstrstr(fontname," Italic")) != (LPSTR)NULL ) {
+ lf.lfFaceName[ (unsigned int)(p-fontname) ] = '\0';
+ lf.lfItalic = TRUE;
+ }
+ if ( (p = _fstrstr(fontname," Bold")) != (LPSTR)NULL ) {
+ lf.lfFaceName[ (unsigned int)(p-fontname) ] = '\0';
+ lf.lfWeight = FW_BOLD;
+ }
+ if (hfont)
+ DeleteFont(hfont);
+
+ hfont = CreateFontIndirect((LOGFONT FAR *)&lf);
+
+ /* get text size */
+ SelectFont(hdc, hfont);
+ GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
+ CharSize.y = tm.tmHeight;
+ CharSize.x = tm.tmAveCharWidth;
+ CharAscent = tm.tmAscent;
+ if (bFocus)
+ CreateCaret(hwnd, 0, CharSize.x, 2+CaretHeight);
+ ReleaseDC(hwnd, hdc);
+
+ // redraw window if necessary
+ if (hwnd != HWND_DESKTOP) {
+ // INCOMPLETE
+ }
+}
+
+
+
+// Set drag strings
+void
+TextWindow::drag(const char *pre, const char *post)
+{
+ // remove old strings
+ delete DragPre;
+ DragPre = NULL;
+ delete DragPost;
+ DragPost = NULL;
+
+ // add new strings
+ DragPre = new char[strlen(pre)+1];
+ if (DragPre)
+ strcpy(DragPre, pre);
+ DragPost = new char[strlen(post)+1];
+ if (DragPost)
+ strcpy(DragPost, post);
+}
+
+// Text Window constructor
+TextWindow::TextWindow(void)
+{
+ // make sure everything is null
+ memset(this, 0, sizeof(TextWindow));
+
+ // set some defaults
+ font("Courier New", 10);
+ size(80, 24);
+ KeyBufSize = 2048;
+ CursorFlag = 1; // scroll to cursor after \n or \r
+}
+
+// TextWindow destructor
+TextWindow::~TextWindow(void)
+{
+ if (hwnd)
+ DestroyWindow(hwnd);
+ if (hfont)
+ DeleteFont(hfont);
+
+ delete KeyBuf;
+ delete ScreenBuffer;
+ delete DragPre;
+ delete DragPost;
+}
+
+// register the window class
+int
+TextWindow::register_class(HINSTANCE hinst, HICON hicon)
+{
+ hInstance = hinst;
+ hIcon = hicon;
+
+ // register window class
+ WNDCLASS wndclass;
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndTextProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(void FAR *);
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = hIcon ? hIcon : LoadIcon(NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = TextWinClassName;
+ return RegisterClass(&wndclass);
+}
+
+// Show the window
+int
+TextWindow::create(LPSTR app_name, int show_cmd)
+{
+ HMENU sysmenu;
+
+ Title = app_name;
+ nCmdShow = show_cmd;
+ quitnow = FALSE;
+
+ // make sure we have some sensible defaults
+ if (KeyBufSize < 256)
+ KeyBufSize = 256;
+
+ CursorPos.x = CursorPos.y = 0;
+ bFocus = FALSE;
+ bGetCh = FALSE;
+ CaretHeight = 0;
+
+
+ // allocate buffers
+ KeyBufIn = KeyBufOut = KeyBuf = new BYTE[KeyBufSize];
+ if (KeyBuf == NULL) {
+ error("Out of memory");
+ return 1;
+ }
+ ScreenBuffer = new BYTE[ScreenSize.x * ScreenSize.y];
+ if (ScreenBuffer == NULL) {
+ error("Out of memory");
+ return 1;
+ }
+ _fmemset(ScreenBuffer, ' ', ScreenSize.x * ScreenSize.y);
+
+ hwnd = CreateWindow(TextWinClassName, Title,
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, hInstance, this);
+
+ if (hwnd == NULL) {
+ MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
+ return 1;
+ }
+
+ ShowWindow(hwnd, nCmdShow);
+ sysmenu = GetSystemMenu(hwnd,0); /* get the sysmenu */
+ AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
+
+ return 0;
+}
+
+int
+TextWindow::destroy(void)
+{
+ if (hwnd) {
+ DestroyWindow(hwnd);
+ hwnd = (HWND)NULL;
+ }
+ return 0;
+}
+
+
+
+int
+TextWindow::putch(int ch)
+{
+int pos;
+ switch(ch) {
+ case '\r':
+ CursorPos.x = 0;
+ if (CursorFlag)
+ to_cursor();
+ break;
+ case '\n':
+ new_line();
+ break;
+ case 7:
+ MessageBeep(-1);
+ if (CursorFlag)
+ to_cursor();
+ break;
+ case '\t':
+ {
+ for ( int n = 8 - (CursorPos.x % 8); n>0; n-- )
+ putch(' ');
+ }
+ break;
+ case 0x08:
+ case 0x7f:
+ CursorPos.x--;
+ if (CursorPos.x < 0) {
+ CursorPos.x = ScreenSize.x - 1;
+ CursorPos.y--;
+ }
+ if (CursorPos.y < 0)
+ CursorPos.y = 0;
+ break;
+ default:
+ pos = CursorPos.y*ScreenSize.x + CursorPos.x;
+ ScreenBuffer[pos] = ch;
+ update_text(1);
+ }
+ return ch;
+}
+
+void
+TextWindow::write_buf(LPSTR str, int cnt)
+{
+BYTE FAR *p;
+int count, limit;
+ while (cnt>0) {
+ p = ScreenBuffer + CursorPos.y*ScreenSize.x + CursorPos.x;
+ limit = ScreenSize.x - CursorPos.x;
+ for (count=0; (count < limit) && (cnt>0) && (isprint(*str) || *str=='\t'); count++) {
+ if (*str=='\t') {
+ for ( int n = 8 - ((CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ )
+ *p++ = ' ';
+ str++;
+ count--;
+ }
+ else {
+ *p++ = *str++;
+ }
+ cnt--;
+ }
+ if (count>0) {
+ update_text(count);
+ }
+ if (cnt > 0) {
+ if (*str=='\n') {
+ new_line();
+ str++;
+ cnt--;
+ }
+ else if (!isprint(*str) && *str!='\t') {
+ putch(*str++);
+ cnt--;
+ }
+ }
+ }
+}
+
+// Put string to window
+void
+TextWindow::puts(LPSTR str)
+{
+ write_buf(str, lstrlen(str));
+}
+
+
+/* TRUE if key hit, FALSE if no key */
+inline int
+TextWindow::kbhit(void)
+{
+ return (KeyBufIn != KeyBufOut);
+}
+
+/* get character from keyboard, no echo */
+/* need to add extended codes */
+int
+TextWindow::getch(void)
+{
+ int ch;
+ to_cursor();
+ bGetCh = TRUE;
+ if (bFocus) {
+ SetCaretPos(CursorPos.x*CharSize.x - ScrollPos.x,
+ CursorPos.y*CharSize.y + CharAscent - CaretHeight - ScrollPos.y);
+ ShowCaret(hwnd);
+ }
+
+ MSG msg;
+ do {
+ if (!quitnow && GetMessage(&msg, (HWND)NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ else
+ return EOF; /* window closed */
+ } while (!kbhit());
+
+ ch = *KeyBufOut++;
+ if (ch=='\r')
+ ch = '\n';
+ if (KeyBufOut - KeyBuf >= KeyBufSize)
+ KeyBufOut = KeyBuf; // wrap around
+ if (bFocus)
+ HideCaret(hwnd);
+ bGetCh = FALSE;
+ return ch;
+}
+
+// Read line from keyboard
+// Return at most 'len' characters
+// Does NOT add null terminating character
+// This does is NOT the same as fgets
+int
+TextWindow::read_line(LPSTR line, int len)
+{
+LPSTR dest = line;
+LPSTR limit = dest + len - 1; // leave room for '\n'
+int ch;
+ if (dest > limit)
+ return 0;
+ while ( (ch = getch()) != '\n' ) {
+ switch(ch) {
+ case EOF:
+ case 26: // ^Z == EOF
+ return 0;
+ case '\b': // ^H
+ case 0x7f: // DEL
+ if (dest > line) {
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ --dest;
+ }
+ break;
+ case 21: // ^U
+ while (dest > line) {
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ --dest;
+ }
+ break;
+ default:
+ if (dest == limit)
+ MessageBeep(-1);
+ else {
+ *dest++ = ch;
+ putch(ch);
+ }
+ break;
+ }
+ }
+ *dest++ = ch;
+ putch(ch);
+ return (dest-line);
+}
+
+// Read a string from the keyboard, of up to len characters
+// (not including trailing NULL)
+int
+TextWindow::gets(LPSTR line, int len)
+{
+LPSTR dest = line;
+LPSTR limit = dest + len; // don't leave room for '\0'
+int ch;
+ do {
+ if (dest >= limit)
+ break;
+ ch = getch();
+ switch(ch) {
+ case 26: // ^Z == EOF
+ return 0;
+ case '\b': // ^H
+ case 0x7f: // DEL
+ if (dest > line) {
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ --dest;
+ }
+ break;
+ case 21: // ^U
+ while (dest > line) {
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ --dest;
+ }
+ break;
+ default:
+ *dest++ = ch;
+ putch(ch);
+ break;
+ }
+ } while (ch != '\n');
+
+ *dest = '\0';
+ return (dest-line);
+}
+
+
+/* Windows 3.1 drag-drop feature */
+void
+TextWindow::drag_drop(HDROP hdrop)
+{
+ int i, cFiles;
+ LPSTR p;
+ if ( (DragPre==(LPSTR)NULL) || (DragPost==(LPSTR)NULL) )
+ return;
+ char szFile[256];
+
+ cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
+ for (i=0; i<cFiles; i++) {
+ DragQueryFile(hdrop, i, szFile, 80);
+ for (p=DragPre; *p; p++)
+ SendMessage(hwnd,WM_CHAR,*p,1L);
+ for (p=szFile; *p; p++) {
+ if (*p == '\\')
+ SendMessage(hwnd,WM_CHAR,'/',1L);
+ else
+ SendMessage(hwnd,WM_CHAR,*p,1L);
+ }
+ for (p=DragPost; *p; p++)
+ SendMessage(hwnd,WM_CHAR,*p,1L);
+ }
+ DragFinish(hdrop);
+}
+
+
+void
+TextWindow::copy_to_clipboard(void)
+{
+ int size, count;
+ HGLOBAL hGMem;
+ LPSTR cbuf, cp;
+ TEXTMETRIC tm;
+ UINT type;
+ HDC hdc;
+ int i;
+
+ size = ScreenSize.y * (ScreenSize.x + 2) + 1;
+ hGMem = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)size);
+ cbuf = cp = (LPSTR)GlobalLock(hGMem);
+ if (cp == (LPSTR)NULL)
+ return;
+
+ for (i=0; i<ScreenSize.y; i++) {
+ count = ScreenSize.x;
+ _fmemcpy(cp, ScreenBuffer + ScreenSize.x*i, count);
+ /* remove trailing spaces */
+ for (count=count-1; count>=0; count--) {
+ if (cp[count]!=' ')
+ break;
+ cp[count] = '\0';
+ }
+ cp[++count] = '\r';
+ cp[++count] = '\n';
+ cp[++count] = '\0';
+ cp += count;
+ }
+ size = _fstrlen(cbuf) + 1;
+ GlobalUnlock(hGMem);
+ hGMem = GlobalReAlloc(hGMem, (DWORD)size, GHND | GMEM_SHARE);
+ /* find out what type to put into clipboard */
+ hdc = GetDC(hwnd);
+ SelectFont(hdc, hfont);
+ GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
+ if (tm.tmCharSet == OEM_CHARSET)
+ type = CF_OEMTEXT;
+ else
+ type = CF_TEXT;
+ ReleaseDC(hwnd, hdc);
+ /* give buffer to clipboard */
+ OpenClipboard(hwnd);
+ EmptyClipboard();
+ SetClipboardData(type, hGMem);
+ CloseClipboard();
+}
+
+/* text window */
+LRESULT CALLBACK _export
+WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ TextWindow *tw;
+ if (message == WM_CREATE) {
+ // Object is stored in window extra data.
+ // Nothing must try to use the object before WM_CREATE
+ // initializes it here.
+ tw = (TextWindow *)(((CREATESTRUCT FAR *)lParam)->lpCreateParams);
+ SetWindowLong(hwnd, 0, (LONG)tw);
+ }
+
+ // call the object window procedure
+ tw = (TextWindow *)GetWindowLong(hwnd, 0);
+ return tw->WndProc(hwnd, message, wParam, lParam);
+}
+
+
+// member window procedure
+LRESULT
+TextWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+ int nYinc, nXinc;
+
+ switch(message) {
+ case WM_SYSCOMMAND:
+ switch(LOWORD(wParam)) {
+ case M_COPY_CLIP:
+ copy_to_clipboard();
+ return 0;
+ }
+ break;
+ case WM_SETFOCUS:
+ bFocus = TRUE;
+ CreateCaret(hwnd, 0, CharSize.x, 2+CaretHeight);
+ SetCaretPos(CursorPos.x*CharSize.x - ScrollPos.x,
+ CursorPos.y*CharSize.y + CharAscent
+ - CaretHeight - ScrollPos.y);
+ if (bGetCh)
+ ShowCaret(hwnd);
+ break;
+ case WM_KILLFOCUS:
+ DestroyCaret();
+ bFocus = FALSE;
+ break;
+ case WM_SIZE:
+ ClientSize.y = HIWORD(lParam);
+ ClientSize.x = LOWORD(lParam);
+
+ ScrollMax.y = max(0, CharSize.y*ScreenSize.y - ClientSize.y);
+ ScrollPos.y = min(ScrollPos.y, ScrollMax.y);
+
+ SetScrollRange(hwnd, SB_VERT, 0, ScrollMax.y, FALSE);
+ SetScrollPos(hwnd, SB_VERT, ScrollPos.y, TRUE);
+
+ ScrollMax.x = max(0, CharSize.x*ScreenSize.x - ClientSize.x);
+ ScrollPos.x = min(ScrollPos.x, ScrollMax.x);
+
+ SetScrollRange(hwnd, SB_HORZ, 0, ScrollMax.x, FALSE);
+ SetScrollPos(hwnd, SB_HORZ, ScrollPos.x, TRUE);
+
+ if (bFocus && bGetCh) {
+ SetCaretPos(CursorPos.x*CharSize.x - ScrollPos.x,
+ CursorPos.y*CharSize.y + CharAscent
+ - CaretHeight - ScrollPos.y);
+ ShowCaret(hwnd);
+ }
+ return(0);
+ case WM_VSCROLL:
+ switch(LOWORD(wParam)) {
+ case SB_TOP:
+ nYinc = -ScrollPos.y;
+ break;
+ case SB_BOTTOM:
+ nYinc = ScrollMax.y - ScrollPos.y;
+ break;
+ case SB_LINEUP:
+ nYinc = -CharSize.y;
+ break;
+ case SB_LINEDOWN:
+ nYinc = CharSize.y;
+ break;
+ case SB_PAGEUP:
+ nYinc = min(-1,-ClientSize.y);
+ break;
+ case SB_PAGEDOWN:
+ nYinc = max(1,ClientSize.y);
+ break;
+ case SB_THUMBPOSITION:
+#ifdef __WIN32__
+ nYinc = HIWORD(wParam) - ScrollPos.y;
+#else
+ nYinc = LOWORD(lParam) - ScrollPos.y;
+#endif
+ break;
+ default:
+ nYinc = 0;
+ }
+ if ( (nYinc = max(-ScrollPos.y,
+ min(nYinc, ScrollMax.y - ScrollPos.y)))
+ != 0 ) {
+ ScrollPos.y += nYinc;
+ ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
+ SetScrollPos(hwnd,SB_VERT,ScrollPos.y,TRUE);
+ UpdateWindow(hwnd);
+ }
+ return(0);
+ case WM_HSCROLL:
+ switch(LOWORD(wParam)) {
+ case SB_LINEUP:
+ nXinc = -CharSize.x;
+ break;
+ case SB_LINEDOWN:
+ nXinc = CharSize.x;
+ break;
+ case SB_PAGEUP:
+ nXinc = min(-1,-ClientSize.x);
+ break;
+ case SB_PAGEDOWN:
+ nXinc = max(1,ClientSize.x);
+ break;
+ case SB_THUMBPOSITION:
+#ifdef __WIN32__
+ nXinc = HIWORD(wParam) - ScrollPos.x;
+#else
+ nXinc = LOWORD(lParam) - ScrollPos.x;
+#endif
+ break;
+ default:
+ nXinc = 0;
+ }
+ if ( (nXinc = max(-ScrollPos.x,
+ min(nXinc, ScrollMax.x - ScrollPos.x)))
+ != 0 ) {
+ ScrollPos.x += nXinc;
+ ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
+ SetScrollPos(hwnd,SB_HORZ,ScrollPos.x,TRUE);
+ UpdateWindow(hwnd);
+ }
+ return(0);
+ case WM_KEYDOWN:
+ if (GetKeyState(VK_SHIFT) < 0) {
+ switch(wParam) {
+ case VK_HOME:
+ SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
+ break;
+ case VK_END:
+ SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
+ break;
+ case VK_PRIOR:
+ SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
+ break;
+ case VK_NEXT:
+ SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
+ break;
+ case VK_UP:
+ SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
+ break;
+ case VK_DOWN:
+ SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
+ break;
+ case VK_LEFT:
+ SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
+ break;
+ case VK_RIGHT:
+ SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
+ break;
+ }
+ }
+ else {
+ switch(wParam) {
+ case VK_HOME:
+ case VK_END:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_UP:
+ case VK_DOWN:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_DELETE:
+ { /* store key in circular buffer */
+ long count = KeyBufIn - KeyBufOut;
+ if (count < 0) count += KeyBufSize;
+ if (count < KeyBufSize-2) {
+ *KeyBufIn++ = 0;
+ if (KeyBufIn - KeyBuf >= KeyBufSize)
+ KeyBufIn = KeyBuf; /* wrap around */
+ *KeyBufIn++ = HIWORD(lParam) & 0xff;
+ if (KeyBufIn - KeyBuf >= KeyBufSize)
+ KeyBufIn = KeyBuf; /* wrap around */
+ }
+ }
+ }
+ }
+ break;
+ case WM_CHAR:
+ { /* store key in circular buffer */
+ long count = KeyBufIn - KeyBufOut;
+ if (count < 0) count += KeyBufSize;
+ if (count < KeyBufSize-1) {
+ *KeyBufIn++ = wParam;
+ if (KeyBufIn - KeyBuf >= KeyBufSize)
+ KeyBufIn = KeyBuf; /* wrap around */
+ }
+ }
+ return(0);
+ case WM_PAINT:
+ {
+ POINT source, width, dest;
+ hdc = BeginPaint(hwnd, &ps);
+ SelectFont(hdc, hfont);
+ SetMapMode(hdc, MM_TEXT);
+ SetBkMode(hdc,OPAQUE);
+ GetClientRect(hwnd, &rect);
+ source.x = (rect.left + ScrollPos.x) / CharSize.x; /* source */
+ source.y = (rect.top + ScrollPos.y) / CharSize.y;
+ dest.x = source.x * CharSize.x - ScrollPos.x; /* destination */
+ dest.y = source.y * CharSize.y - ScrollPos.y;
+ width.x = ((rect.right + ScrollPos.x + CharSize.x - 1) / CharSize.x) - source.x; /* width */
+ width.y = ((rect.bottom + ScrollPos.y + CharSize.y - 1) / CharSize.y) - source.y;
+ if (source.x < 0)
+ source.x = 0;
+ if (source.y < 0)
+ source.y = 0;
+ if (source.x+width.x > ScreenSize.x)
+ width.x = ScreenSize.x - source.x;
+ if (source.y+width.y > ScreenSize.y)
+ width.y = ScreenSize.y - source.y;
+ /* for each line */
+ while (width.y>0) {
+ TextOut(hdc,dest.x,dest.y,
+ (LPSTR)(ScreenBuffer + source.y*ScreenSize.x + source.x),
+ width.x);
+ dest.y += CharSize.y;
+ source.y++;
+ width.y--;
+ }
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+ case WM_DROPFILES:
+ drag_drop((HDROP)wParam);
+ break;
+ case WM_CREATE:
+ {
+ RECT crect, wrect;
+
+ TextWindow::hwnd = hwnd;
+
+ GetClientRect(hwnd, &crect);
+ if ( (CharSize.y*ScreenSize.y < crect.bottom)
+ || (CharSize.x*ScreenSize.x < crect.right) ) {
+ /* shrink size */
+ GetWindowRect(hwnd,&wrect);
+ MoveWindow(hwnd, wrect.left, wrect.top,
+ wrect.right-wrect.left + (CharSize.x*ScreenSize.x - crect.right),
+ wrect.bottom-wrect.top + (CharSize.y*ScreenSize.y - crect.bottom),
+ TRUE);
+ }
+ if ( (DragPre!=(LPSTR)NULL) && (DragPost!=(LPSTR)NULL) )
+ DragAcceptFiles(hwnd, TRUE);
+ }
+ break;
+ case WM_CLOSE:
+ break;
+ case WM_DESTROY:
+ DragAcceptFiles(hwnd, FALSE);
+ if (hfont)
+ DeleteFont(hfont);
+ hfont = (HFONT)0;
+ quitnow = TRUE;
+ PostQuitMessage(0);
+ break;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+
+
+
+#ifdef NOTUSED
+// test program
+#pragma argsused
+
+int PASCAL
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
+{
+
+// make a test window
+TextWindow* textwin = new TextWindow(hInstance);
+ if (!hPrevInstance) {
+ HICON hicon = LoadIcon(NULL, IDI_APPLICATION);
+ textwin->register_class(hicon);
+ }
+ textwin->font("Courier New", 10);
+ textwin->size(80, 80);
+ textwin->drag("(", ") run\r");
+
+ // show the text window
+ if (!textwin->show("Application Name", nCmdShow)) {
+ // do the real work here
+ // TESTING
+ int ch;
+ int len;
+ char *line = new char[256];
+ while ( (len = textwin->read_line(line, 256-1)) != 0 ) {
+ textwin->write_buf(line, len);
+ }
+/*
+ while ( textwin->gets(line, 256-1) ) {
+ textwin->puts(line);
+ }
+*/
+/*
+ while ( (ch = textwin->getch()) != 4 )
+ textwin->putch(ch);
+*/
+ }
+ else {
+
+ }
+
+ // clean up
+ delete textwin;
+
+ // end program
+ return 0;
+}
+#endif
diff --git a/gs/src/dwtext.h b/gs/src/dwtext.h
new file mode 100644
index 000000000..210adcad8
--- /dev/null
+++ b/gs/src/dwtext.h
@@ -0,0 +1,144 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+// dwtext.h
+// Text Window class
+
+
+#ifdef _WINDOWS
+#define _Windows
+#endif
+
+
+/* ================================== */
+/* text window class */
+
+
+class TextWindow {
+ HINSTANCE hInstance; /* required */
+ LPSTR Title; /* required */
+ HICON hIcon; /* optional */
+
+ BYTE FAR *ScreenBuffer;
+ POINT ScreenSize; /* optional */
+ char *DragPre; /* optional */
+ char *DragPost; /* optional */
+ int nCmdShow; /* optional */
+ HWND hwnd;
+
+ BYTE FAR *KeyBuf;
+ BYTE FAR *KeyBufIn;
+ BYTE FAR *KeyBufOut;
+ unsigned int KeyBufSize;
+ BOOL quitnow;
+
+ BOOL bFocus;
+ BOOL bGetCh;
+ char *fontname; // font name
+ int fontsize; // font size in pts
+ HFONT hfont;
+ int CharAscent;
+
+ int CaretHeight;
+ int CursorFlag;
+ POINT CursorPos;
+ POINT ClientSize;
+ POINT CharSize;
+ POINT ScrollPos;
+ POINT ScrollMax;
+
+ void error(char *message);
+ void new_line(void);
+ void update_text(int count);
+ void drag_drop(HDROP hdrop);
+ void copy_to_clipboard(void);
+
+public:
+ // constructor
+ TextWindow(void);
+
+ // destructor
+ ~TextWindow(void);
+
+ // register window class
+ int register_class(HINSTANCE hinst, HICON hicon);
+
+ // test if a key has been pressed
+ // return TRUE if key hit
+ // return FALSE if no key
+ int kbhit(void);
+
+ // Get a character from the keyboard, waiting if necessary
+ int getch(void);
+
+ // Get a line from the keyboard
+ // store line in buf, with no more than len characters
+ // including null character
+ // return number of characters read
+ int gets(LPSTR buf, int len);
+
+ // Get a line from the keyboard
+ // store line in buf, with no more than len characters
+ // line is not null terminated
+ // return number of characters read
+ int read_line(LPSTR buf, int len);
+
+ // Put a character to the window
+ int putch(int ch);
+
+ // Write cnt character from buf to the window
+ void write_buf(LPSTR buf, int cnt);
+
+ // Put a string to the window
+ void puts(LPSTR str);
+
+ // Scroll window to make cursor visible
+ void to_cursor(void);
+
+ // Create and show window with given name and min/max/normal state
+ // return 0 on success, non-zero on error
+ int create(LPSTR title, int cmdShow);
+
+ // Destroy window
+ int destroy(void);
+
+ // Set window font and size
+ // a must choose monospaced
+ void font(const char *fontname, int fontsize);
+
+ // Set screen size in characters
+ void size(int width, int height);
+
+ // Set pre drag and post drag strings
+ // If a file is dropped on the window, the following will
+ // be poked into the keyboard buffer:
+ // the pre_drag string
+ // the file name
+ // the post_drag string
+ void drag(const char *pre_drag, const char *post_drag);
+
+ // member window procedure
+ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+ // provide access to window handle
+ HWND get_handle(void) { return hwnd; };
+};
+
+/* ================================== */
+
diff --git a/gs/src/echogs.c b/gs/src/echogs.c
new file mode 100644
index 000000000..044f3d953
--- /dev/null
+++ b/gs/src/echogs.c
@@ -0,0 +1,294 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* echogs.c */
+/* 'echo'-like utility */
+#include <stdio.h>
+/* Some brain-damaged environments (e.g. Sun) don't include */
+/* prototypes for fputc/fputs in stdio.h! */
+extern int fputc(), fputs();
+/* Some systems have time_t in sys/types.h rather than time.h. */
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h> /* for ctime */
+/* The VMS environment uses different values for success/failure exits: */
+#ifdef VMS
+#include <stdlib.h>
+# define exit_OK 1
+# define exit_FAILED 18
+#else
+# define exit_OK 0
+# define exit_FAILED 1
+#endif
+
+/*
+ * This program exists solely to get around omissions, problems, and
+ * incompatibilities in various shells and utility environments.
+ * Don't count on it staying the same from one release to another!
+ */
+
+/*
+ * Usage:
+ echogs [-e .extn] [-(w|a)[b][-] file] [-h] [-n]
+ (-d|-D | -f|-F | -x hexstring | -(l|q|Q) string | -(l|q|Q)string |
+ -s | -u string | -i | -r file | -R file | -X)*
+ [-] string*
+ * Echoes string(s), or the binary equivalent of hexstring(s).
+ * If -w, writes to file; if -a, appends to file; if neither,
+ * writes to stdout. -wb and -ab open the file in binary mode.
+ * -w and -a search forward for the next argument that is not a switch.
+ * An appended - means the same as - alone, taking effect after the file
+ * argument.
+ * -e specifies an extension to be added to the file name.
+ * If -h, write the output in hex instead of literally.
+ * If -n, does not append a newline to the output.
+ * -d or -D means insert the date and time.
+ * -f or -F means insert the file name passed as the argument of -w or -a.
+ * -q means write the next string literally.
+ * -l or -Q means the same as -q followed by -s.
+ * -s means write a space.
+ * -u means convert the next string to upper case.
+ * -i means read from stdin, treating each line as an argument.
+ * -r means read from a named file in the same way.
+ * -R means copy a named file with no interpretation
+ * (but convert to hex if -h is in effect).
+ * -X means treat any following literals as hex rather than string data.
+ * - alone means treat the rest of the line as literal data,
+ * even if the first string begins with a -.
+ * -+<letter> is equivalent to -<Letter>, i.e., it upper-cases the letter.
+ * Inserts spaces automatically between the trailing strings,
+ * but nowhere else; in particular,
+ echogs -q a b
+ * writes 'ab', in contrast to
+ echogs -q a -s b
+ * which writes 'a b'.
+ */
+
+static int hputc(), hputs();
+
+main(int argc, char *argv[])
+{ FILE *out = stdout;
+ FILE *in;
+ char *extn = "";
+ char fmode[4];
+#define FNSIZE 100
+ char *fnparam;
+ char fname[FNSIZE];
+ int newline = 1;
+ int interact = 0;
+ int (*eputc)() = fputc, (*eputs)() = fputs;
+#define LINESIZE 1000
+ char line[LINESIZE];
+ char sw = 0, sp = 0, hexx = 0;
+ char **argp = argv + 1;
+ int nargs = argc - 1;
+ if ( nargs > 0 && !strcmp(*argp, "-e") )
+ { if ( nargs < 2 ) return 1;
+ extn = argp[1];
+ argp += 2, nargs -= 2;
+ }
+ if ( nargs > 0 && (*argp)[0] == '-' &&
+ ((*argp)[1] == 'w' || (*argp)[1] == 'a')
+ )
+ { size_t len = strlen(*argp);
+ int i;
+ if ( len > 4 ) return 1;
+ for ( i = 1; i < nargs; i++ )
+ if ( argp[i][0] != '-' ) break;
+ if ( i == nargs ) return 1;
+ fnparam = argp[i];
+ strcpy(fmode, *argp + 1);
+ strcpy(fname, fnparam);
+ strcat(fname, extn);
+ if ( fmode[len-2] == '-' )
+ { fmode[len-2] = 0;
+ argp[i] = "-";
+ argp++, nargs--;
+ }
+ else
+ { for ( ; i > 1; i-- )
+ argp[i] = argp[i-1];
+ argp += 2, nargs -= 2;
+ }
+ }
+ else
+ strcpy(fname, "");
+ if ( nargs > 0 && !strcmp(*argp, "-h") )
+ { eputc = hputc, eputs = hputs;
+ argp++, nargs--;
+ }
+ if ( nargs > 0 && !strcmp(*argp, "-n") )
+ { newline = 0;
+ argp++, nargs--;
+ }
+ if ( strlen(fname) != 0 )
+ { out = fopen(fname, fmode);
+ if ( out == 0 ) return 1;
+ }
+ while ( 1 )
+ { char *arg;
+ if ( interact )
+ { if ( fgets(line, LINESIZE, in) == NULL )
+ { interact = 0;
+ if ( in != stdin ) fclose(in);
+ continue;
+ }
+ /* Remove the terminating \n. */
+ line[strlen(line) - 1] = 0;
+ arg = line;
+ }
+ else
+ { if ( nargs == 0 ) break;
+ arg = *argp;
+ argp++, nargs--;
+ }
+ if ( sw == 0 && arg[0] == '-' )
+ { char chr = arg[1];
+
+ sp = 0;
+swc: switch ( chr )
+ {
+ case '+': /* upper-case command */
+ ++arg;
+ chr = toupper(arg[1]);
+ goto swc;
+ case 'l': /* literal string, then -s */
+ chr = 'Q';
+ /* falls through */
+ case 'q': /* literal string */
+ case 'Q': /* literal string, then -s */
+ if ( arg[2] != 0 )
+ { (*eputs)(arg + 2, out);
+ if ( chr == 'Q' )
+ (*eputc)(' ', out);
+ break;
+ }
+ /* falls through */
+ case 'r': /* read from a file */
+ case 'R':
+ case 'u': /* upper-case string */
+ case 'x': /* hex string */
+ sw = chr;
+ break;
+ case 's': /* write a space */
+ (*eputc)(' ', out);
+ break;
+ case 'i': /* read interactively */
+ interact = 1;
+ in = stdin;
+ break;
+ case 'd': /* insert date/time */
+ case 'D':
+ { time_t t;
+ char str[26];
+ time(&t);
+ strcpy(str, ctime(&t));
+ str[24] = 0; /* remove \n */
+ (*eputs)(str, out);
+ } break;
+ case 'f': /* insert file name */
+ case 'F':
+ (*eputs)(fnparam, out);
+ break;
+ case 'X': /* treat literals as hex */
+ hexx = 1;
+ break;
+ case 0: /* just '-' */
+ sw = '-';
+ break;
+ }
+ }
+ else
+ switch ( sw )
+ {
+ case 0:
+ case '-':
+ if ( hexx ) goto xx;
+ if ( sp ) (*eputc)(' ', out);
+ (*eputs)(arg, out);
+ sp = 1;
+ break;
+ case 'q':
+ sw = 0;
+ (*eputs)(arg, out);
+ break;
+ case 'Q':
+ sw = 0;
+ (*eputs)(arg, out);
+ (*eputc)(' ', out);
+ break;
+ case 'r':
+ sw = 0;
+ in = fopen(arg, "r");
+ if ( in == NULL ) exit(exit_FAILED);
+ interact = 1;
+ break;
+ case 'R':
+ sw = 0;
+ in = fopen(arg, "r");
+ if ( in == NULL ) exit(exit_FAILED);
+ { int count;
+ while ( (count = fread(line, 1, 1, in)) > 0 )
+ (*eputc)(line[0], out);
+ }
+ fclose(in);
+ break;
+ case 'u':
+ { char *up;
+ for ( up = arg; *up; up++ )
+ (*eputc)(toupper(*up), out);
+ } sw = 0;
+ break;
+ case 'x':
+xx: { char *xp;
+ unsigned int xchr = 1;
+ for ( xp = arg; *xp; xp++ )
+ { char ch = *xp;
+ if ( !isxdigit(ch) ) return 1;
+ xchr <<= 4;
+ xchr += (isdigit(ch) ? ch - '0' :
+ (isupper(ch) ? tolower(ch) : ch)
+ - 'a' + 10);
+ if ( xchr >= 0x100 )
+ { (*eputc)(xchr & 0xff, out);
+ xchr = 1;
+ }
+ }
+ } sw = 0;
+ break;
+ }
+ }
+ if ( newline ) (*eputc)('\n', out);
+ if ( out != stdout ) fclose(out);
+ return exit_OK;
+}
+
+static int
+hputc(int ch, FILE *out)
+{ static char *hex = "0123456789abcdef";
+ putc(hex[ch >> 4], out);
+ putc(hex[ch & 0xf], out);
+ return 0;
+}
+
+static int
+hputs(char *str, FILE *out)
+{ while ( *str ) hputc(*str++ & 0xff, out);
+ return 0;
+}
diff --git a/gs/src/errno_.h b/gs/src/errno_.h
new file mode 100644
index 000000000..729ca77cf
--- /dev/null
+++ b/gs/src/errno_.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* errno_.h */
+/* Generic substitute for Unix errno.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/* All environments provide errno.h, but in some of them, errno.h */
+/* only defines the error numbers, and doesn't declare errno. */
+#include <errno.h>
+#ifndef errno /* in case it was #defined (very implausible!) */
+extern int errno;
+#endif
diff --git a/gs/src/errors.h b/gs/src/errors.h
new file mode 100644
index 000000000..0e67e755f
--- /dev/null
+++ b/gs/src/errors.h
@@ -0,0 +1,177 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* errors.h */
+/* Definition of error codes */
+
+/*
+ * A procedure that may return an error always returns
+ * a non-negative value (zero, unless otherwise noted) for success,
+ * or negative for failure.
+ * We use ints rather than an enum to avoid a lot of casting.
+ */
+
+/*
+ * The following peculiar structure allows us to include this file
+ * wherever error code definitions are needed, and use the same file
+ * to generate the table of error names by setting INCLUDE_ERROR_NAMES.
+ */
+
+# ifdef INCLUDE_ERROR_NAMES
+
+/* Define the error name table */
+const char _ds *gs_error_names[] = {
+#define _e_(code,name) name,
+
+# else /* !INCLUDE_ERROR_NAMES */
+
+extern const char _ds *gs_error_names[];
+# define _e_(code,name)
+
+#endif /* (!)INCLUDE_ERROR_NAMES */
+
+ /* ------ PostScript Level 1 errors ------ */
+
+#define e_unknownerror (-1) /* unknown error */
+ _e_(e_unknown, "unknownerror")
+#define e_dictfull (-2)
+ _e_(e_dictfull, "dictfull")
+#define e_dictstackoverflow (-3)
+ _e_(e_dictstackoverflow, "dictstackoverflow")
+#define e_dictstackunderflow (-4)
+ _e_(e_dictstackunderflow, "dictstackunderflow")
+#define e_execstackoverflow (-5)
+ _e_(e_execstackoverflow, "execstackoverflow")
+#define e_interrupt (-6)
+/* We also need to define gs_error_interrupt, for gpcheck.h. */
+#undef gs_error_interrupt
+#define gs_error_interrupt e_interrupt
+ _e_(e_interrupt, "interrupt")
+#define e_invalidaccess (-7)
+ _e_(e_invalidaccess, "invalidaccess")
+#define e_invalidexit (-8)
+ _e_(e_invalidexit, "invalidexit")
+#define e_invalidfileaccess (-9)
+ _e_(e_invalidfileaccess, "invalidfileaccess")
+#define e_invalidfont (-10)
+ _e_(e_invalidfont, "invalidfont")
+#define e_invalidrestore (-11)
+ _e_(e_invalidrestore, "invalidrestore")
+#define e_ioerror (-12)
+ _e_(e_ioerror, "ioerror")
+#define e_limitcheck (-13)
+ _e_(e_limitcheck, "limitcheck")
+#define e_nocurrentpoint (-14)
+ _e_(e_nocurrentpoint, "nocurrentpoint")
+#define e_rangecheck (-15)
+ _e_(e_rangecheck, "rangecheck")
+#define e_stackoverflow (-16)
+ _e_(e_stackoverflow, "stackoverflow")
+#define e_stackunderflow (-17)
+ _e_(e_stackunderflow, "stackunderflow")
+#define e_syntaxerror (-18)
+ _e_(e_syntaxerror, "syntaxerror")
+#define e_timeout (-19)
+ _e_(e_timeout, "timeout")
+#define e_typecheck (-20)
+ _e_(e_typecheck, "typecheck")
+#define e_undefined (-21)
+ _e_(e_undefined, "undefined")
+#define e_undefinedfilename (-22)
+ _e_(e_undefinedfilename, "undefinedfilename")
+#define e_undefinedresult (-23)
+ _e_(e_undefinedresult, "undefinedresult")
+#define e_unmatchedmark (-24)
+ _e_(e_unmatchedmark, "unmatchedmark")
+#define e_VMerror (-25)
+ _e_(e_VMerror, "VMerror")
+
+ /* ------ Additional Level 2 and DPS errors ------ */
+
+#define e_configurationerror (-26)
+ _e_(e_configurationerror, "configurationerror")
+#define e_invalidcontext (-27)
+ _e_(e_invalidcontext, "invalidcontext")
+#define e_undefinedresource (-28)
+ _e_(e_undefinedresource, "undefinedresource")
+#define e_unregistered (-29)
+ _e_(e_unregistered, "unregistered")
+/* invalidid is for the NeXT DPS extension. */
+#define e_invalidid (-30)
+ _e_(e_invalidid, "invalidid")
+
+# ifdef INCLUDE_ERROR_NAMES
+
+/* End of error name table */
+ 0
+};
+
+# endif /* INCLUDE_ERROR_NAMES */
+
+ /* ------ Pseudo-errors used internally ------ */
+
+/*
+ * Internal code for a fatal error.
+ * gs_interpret also returns this for a .quit with a positive exit code.
+ */
+#define e_Fatal (-100)
+
+/*
+ * Internal code for the .quit operator.
+ * The real quit code is an integer on the operand stack.
+ * gs_interpret returns this only for a .quit with a zero exit code.
+ */
+#define e_Quit (-101)
+
+/*
+ * Internal code for a normal exit from the interpreter.
+ * Do not use outside of interp.c.
+ */
+#define e_InterpreterExit (-102)
+
+/*
+ * Internal code that indicates that a procedure has been inserted
+ * on the e-stack at (former) esp+2, to be executed before retrying
+ * the current token. This is used for color remapping
+ * involving a call back into the interpreter -- inelegant, but effective.
+ */
+#define e_InsertProc (-103)
+
+/*
+ * Internal code to indicate we have underflowed the top block
+ * of the e-stack.
+ */
+#define e_ExecStackUnderflow (-104)
+
+/*
+ * Internal code for the vmreclaim operator with a positive operand.
+ * We need to handle this as an error because otherwise the interpreter
+ * won't reload enough of its state when the operator returns.
+ */
+#define e_VMreclaim (-105)
+
+/*
+ * Internal code for requesting more input from run_string.
+ */
+#define e_NeedInput (-106)
+
+/*
+ * Define which error codes require re-executing the current object.
+ */
+#define error_is_interrupt(ecode)\
+ ((ecode) == e_interrupt || (ecode) == e_timeout)
diff --git a/gs/src/estack.h b/gs/src/estack.h
new file mode 100644
index 000000000..82f4987b9
--- /dev/null
+++ b/gs/src/estack.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* estack.h */
+/* Definitions for the execution stack */
+#include "istack.h"
+
+/* Define the execution stack pointers. */
+typedef s_ptr es_ptr;
+typedef const_s_ptr const_es_ptr;
+extern ref_stack e_stack;
+#define esbot (e_stack.bot)
+#define esp (e_stack.p)
+#define estop (e_stack.top)
+
+/*
+ * To improve performance, we cache the currentfile pointer
+ * (i.e., `shallow-bind' it in Lisp terminology). The invariant is as
+ * follows: either esfile points to the currentfile slot on the estack
+ * (i.e., the topmost slot with an executable file), or it is 0.
+ * To maintain the invariant, it is sufficient that whenever a routine
+ * pushes or pops anything on the estack, if the object *might* be
+ * an executable file, invoke esfile_clear_cache(); alternatively,
+ * immediately after pushing an object, invoke esfile_check_cache().
+ */
+extern ref *esfile;
+#define esfile_clear_cache() (esfile = 0)
+#define esfile_set_cache(pref) (esfile = (pref))
+#define esfile_check_cache()\
+ if ( r_has_type_attrs(esp, t_file, a_executable) )\
+ esfile_set_cache(esp)
+
+/*
+ * The execution stack is used for three purposes:
+ *
+ * - Procedures being executed are held here. They always have
+ * type = t_array, t_mixedarray, or t_shortarray, with a_executable set.
+ * More specifically, the e-stack holds the as yet unexecuted tail of the
+ * procedure.
+ *
+ * - if, ifelse, etc. push arguments to be executed here.
+ * They may be any kind of object whatever.
+ *
+ * - Control operators (filenameforall, for, repeat, loop, forall,
+ * pathforall, run, stopped, ...) mark the stack by pushing whatever state
+ * they need to save or keep track of and then an object with type = t_null,
+ * attrs = a_executable, size = es_xxx (see below), and value.opproc = a
+ * cleanup procedure that will get called whenever the execution stack is
+ * about to get cut back beyond this point because of an error, stop, exit,
+ * or quit. (Executable null objects can't ever appear on the e-stack
+ * otherwise: if a control operator pushes one, it gets popped immediately.)
+ * The cleanup procedure is called with esp pointing just BELOW the mark,
+ * i.e., the mark has already been popped.
+ *
+ * The loop operators also push whatever state they need,
+ * followed by an operator object that handles continuing the loop.
+ *
+ * Note that there are many internal operators that need to be handled like
+ * looping operators -- for example, all the 'show' operators, since they
+ * may call out to BuildChar procedures.
+ */
+
+/* Macro for marking the execution stack */
+#define make_mark_estack(ep, es_idx, proc)\
+ make_tasv(ep, t_null, a_executable, es_idx, opproc, proc)
+#define push_mark_estack(es_idx, proc)\
+ (++esp, make_mark_estack(esp, es_idx, proc))
+#define r_is_estack_mark(ep)\
+ r_has_type_attrs(ep, t_null, a_executable)
+#define estack_mark_index(ep) r_size(ep)
+#define set_estack_mark_index(ep, es_idx) r_set_size(ep, es_idx)
+
+/* Macro for pushing an operator on the execution stack */
+/* to represent a continuation procedure */
+#define make_op_estack(ep, proc)\
+ make_oper(ep, 0, proc)
+#define push_op_estack(proc)\
+ (++esp, make_op_estack(esp, proc))
+
+/* Macro to ensure enough room on the execution stack */
+#define check_estack(n)\
+ if ( esp > estop - (n) )\
+ { int es_code_ = ref_stack_extend(&e_stack, n);\
+ if ( es_code_ < 0 ) return es_code_;\
+ }
+
+/* Macro to ensure enough entries on the execution stack */
+#define check_esp(n)\
+ if ( esp < esbot + ((n) - 1) )\
+ { e_stack.requested = (n); return_error(e_ExecStackUnderflow); }
+
+/* Define the various kinds of execution stack marks. */
+#define es_other 0 /* internal use */
+#define es_show 1 /* show operators */
+#define es_for 2 /* iteration operators */
+#define es_stopped 3 /* stopped operator */
+
+/*
+ * Pop a given number of elements off the execution stack,
+ * executing cleanup procedures as necessary.
+ */
+void pop_estack(P1(uint));
+
+/*
+ * The execution stack is implemented as a linked list of blocks;
+ * operators that can push or pop an unbounded number of values, or that
+ * access the entire o-stack, must take this into account. These are:
+ * exit .stop .instopped countexecstack execstack currentfile
+ * pop_estack(exit, stop, error recovery)
+ * gs_show_find(all the show operators)
+ * In addition, for e-stack entries created by control operators, we must
+ * ensure that the mark and its data are never separated. We do this
+ * by ensuring that when splitting the top block, at least N items
+ * are kept in the new top block above the bottommost retained mark,
+ * where N is the largest number of data items associated with a mark.
+ * Finally, in order to avoid specific checks for underflowing a block,
+ * we put a guard entry at the bottom of each block except the top one
+ * that contains a procedure that returns an internal "exec stack block
+ * underflow" error.
+ */
diff --git a/gs/src/files.h b/gs/src/files.h
new file mode 100644
index 000000000..4189f698b
--- /dev/null
+++ b/gs/src/files.h
@@ -0,0 +1,137 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* files.h */
+/* Common declarations for zfile.c and zfileio.c */
+/* Requires stream.h */
+
+/*
+ * In many places below, a do {...} while (0) avoids problems with a possible
+ * enclosing 'if'.
+ */
+
+/*
+ * File objects store a pointer to a stream in value.pfile.
+ * A file object is valid if its "size" matches the read_id or write_id
+ * (as appropriate) in the stream it points to. This arrangement
+ * allows us to detect closed files reliably, while allowing us to
+ * reuse closed streams for new files.
+ */
+#define fptr(pref) (pref)->value.pfile
+#define make_file(pref,a,id,s)\
+ make_tasv(pref,t_file,a,id,pfile,s)
+
+/* The stdxxx files. We have to access them through procedures, */
+/* because they might have to be opened when referenced. */
+int zget_stdin(P1(stream **));
+int zget_stdout(P1(stream **));
+int zget_stderr(P1(stream **));
+extern bool gs_stdin_is_interactive;
+/* An invalid (closed) file. */
+extern stream *invalid_file_entry;
+
+/* Macros for checking file validity. */
+#define file_is_valid(svar,op)\
+ (svar = fptr(op), (svar->read_id | svar->write_id) == r_size(op))
+#define check_file(svar,op)\
+ do\
+ { check_type(*(op), t_file);\
+ if ( !file_is_valid(svar, op) ) return_error(e_invalidaccess);\
+ }\
+ while (0)
+
+/*
+ * If a file is open for both reading and writing, its read_id, write_id,
+ * and stream procedures and modes reflect the current mode of use;
+ * an id check failure will switch it to the other mode.
+ */
+int file_switch_to_read(P1(const ref *));
+#define check_read_file(svar,op)\
+ do\
+ { check_read_type(*(op), t_file);\
+ check_read_known_file(svar, op, return);\
+ }\
+ while (0)
+#define check_read_known_file(svar,op,error_return)\
+ check_read_known_file_else(svar, op, error_return, svar = invalid_file_entry)
+/* The do... avoids problems with a possible enclosed 'if'. */
+#define check_read_known_file_else(svar,op,error_return,invalid_action)\
+ do\
+ { svar = fptr(op);\
+ if ( svar->read_id != r_size(op) )\
+ { if ( svar->read_id == 0 && svar->write_id == r_size(op) )\
+ { int fcode = file_switch_to_read(op);\
+ if ( fcode < 0 ) error_return(fcode);\
+ }\
+ else do { invalid_action; } while (0); /* closed or reopened file */\
+ }\
+ }\
+ while (0)
+int file_switch_to_write(P1(const ref *));
+#define check_write_file(svar,op)\
+ do\
+ { check_write_type(*(op), t_file);\
+ check_write_known_file(svar, op, return);\
+ }\
+ while (0)
+#define check_write_known_file(svar,op,error_return)\
+ do\
+ { svar = fptr(op);\
+ if ( svar->write_id != r_size(op) )\
+ { int fcode = file_switch_to_write(op);\
+ if ( fcode < 0 ) error_return(fcode);\
+ }\
+ }\
+ while (0)
+
+/* Data exported by zfile.c. */
+ /* for zfilter.c and ziodev.c */
+extern const uint file_default_buffer_size;
+
+/* Procedures exported by zfile.c. */
+ /* for gs.c */
+FILE *lib_fopen(P1(const char *));
+ /* for gsmain.c */
+int lib_file_open(P6(const char *, uint, byte *, uint, uint *, ref *));
+ /* for iccinit.c */
+int file_read_string(P3(const byte *, uint, ref *));
+ /* for os_open in ziodev.c */
+#ifdef iodev_proc_fopen /* in gxiodev.h */
+int file_open_stream(P6(const char *, uint, const char *, uint,
+ stream **, iodev_proc_fopen_t));
+#endif
+ /* for zfilter.c */
+int filter_open(P6(const char *, uint, ref *, const stream_procs _ds *,
+ const stream_template *, const stream_state *));
+ /* for zfileio.c */
+void make_stream_file(P3(ref *, stream *, const char *));
+ /* for ziodev.c */
+int file_close_finish(P1(stream *));
+int file_close_disable(P1(stream *));
+int file_close_file(P1(stream *));
+ /* for gsmain.c, interp.c */
+int file_close(P1(ref *));
+ /* for ziodev.c */
+stream *file_alloc_stream(P2(gs_memory_t *, client_name_t));
+ /* for isave.c */
+void file_save(P0());
+/*void file_restore(P1(const alloc_save_t *));*/
+
+/* Procedures exported by zfileio.c. */
+ /* for ziodev.c */
+int zreadline_from(P5(stream *, byte *, uint, uint *, bool *));
diff --git a/gs/src/fname.h b/gs/src/fname.h
new file mode 100644
index 000000000..c01106dad
--- /dev/null
+++ b/gs/src/fname.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* fname.h */
+/* File name parsing interface */
+/* Requires gxiodev.h */
+
+/* Parsed file name type. Note that the file name may be either a */
+/* gs_string (no terminator) or a C string (null terminator). */
+typedef struct parsed_file_name_s {
+ gx_io_device *iodev;
+ const char *fname;
+ uint len;
+} parsed_file_name;
+int parse_file_name(P2(const ref *, parsed_file_name *));
+int parse_real_file_name(P3(const ref *, parsed_file_name *, client_name_t));
+int terminate_file_name(P2(parsed_file_name *, client_name_t));
+void free_file_name(P2(parsed_file_name *, client_name_t));
diff --git a/gs/src/gcc-head.mak b/gs/src/gcc-head.mak
new file mode 100644
index 000000000..b0af7b01e
--- /dev/null
+++ b/gs/src/gcc-head.mak
@@ -0,0 +1,295 @@
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/gcc/X11 configuration.
+# Note: this makefile assumes you are using gcc in ANSI mode.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unix-gcc.mak #
+# or makefile. Edit gcc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+#GENOPT=-DDEBUG
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler.
+
+CC=gcc
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the default gcc flags.
+# To work around the gcc 2.7.x optimizer bug,
+# add -Dconst= and remove -Wcast-qual and -Wwrite-strings.
+
+#GCFLAGS=-Wall -Wcast-qual -Wpointer-arith -Wstrict-prototypes -Wwrite-strings
+GCFLAGS=-Dconst= -Wall -Wpointer-arith -Wstrict-prototypes
+
+# Define the other compilation flags. Add at most one of the following:
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+# We don't include -ansi, because this gets in the way of the platform-
+# specific stuff that <math.h> typically needs; nevertheless, we expect
+# gcc to accept ANSI-style function prototypes and function definitions.
+XCFLAGS=
+
+CFLAGS=-O $(GCFLAGS) $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+#XLIBDIRS=-L/usr/local/X/lib
+XLIBDIRS=-L/usr/X11/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11gray2.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=gcc-head.mak
+
+# Define the ANSI-to-K&R dependency. (gcc accepts ANSI syntax.)
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCAUX=$(CC)
+#We can't use -fomit-frame-pointer with -pg....
+#CCLEAF=$(CCC)
+CCLEAF=$(CCC) -fomit-frame-pointer
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
diff --git a/gs/src/gconf.c b/gs/src/gconf.c
new file mode 100644
index 000000000..36afa75b9
--- /dev/null
+++ b/gs/src/gconf.c
@@ -0,0 +1,121 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gconf.c */
+/* Configuration tables */
+#include "gx.h"
+#include "gscdefs.h" /* interface */
+#include "gconfig.h" /* for #defines */
+/*
+ * Since we only declare variables of type gx_device *,
+ * it should be sufficient to define struct gx_device_s as
+ * an abstract (undefined) structure. However, the VAX VMS compiler
+ * isn't happy with this, so we have to include the full definition.
+ */
+#include "gxdevice.h"
+#include "gxiodev.h"
+
+/*
+ * The makefile generates the file gconfig.h, which consists of
+ * lines of the form
+ * device_(gs_xxx_device)
+ * for each installed device;
+ * emulator_("emulator")
+ * for each known emulator;
+ * init_(gs_xxx_init)
+ * for each initialization procedure;
+ * io_device_(gs_iodev_xxx)
+ * for each known IODevice;
+ * oper_(xxx_op_defs)
+ * for each operator option;
+ * psfile_("gs_xxxx.ps")
+ * for each optional initialization file.
+ *
+ * We include this file multiple times to generate various different
+ * source structures. (It's a hack, but we haven't come up with anything
+ * more satisfactory.)
+ */
+
+/* ---------------- Resources (devices, inits, IODevices) ---------------- */
+
+/* Declare devices, init procedures, and IODevices as extern. */
+#define device_(dev) extern far_data gx_device dev;
+#define init_(proc) extern void proc(P1(gs_memory_t *));
+#define io_device_(iodev) extern gx_io_device iodev;
+#include "gconfig.h"
+#undef init_
+#undef io_device_
+#undef device_
+
+/* Set up the initialization procedure table. */
+extern_gx_init_table();
+#define init_(proc) proc,
+void (*gx_init_table[])(P1(gs_memory_t *)) = {
+#include "gconfig.h"
+ 0
+};
+#undef init_
+
+/* Set up the IODevice table. The first entry must be %os%, */
+/* since it is the default for files with no explicit device specified. */
+extern_gx_io_device_table();
+extern gx_io_device gs_iodev_os;
+#define io_device_(iodev) &iodev,
+gx_io_device *gx_io_device_table[] = {
+ &gs_iodev_os,
+#include "gconfig.h"
+ 0
+};
+#undef io_device_
+uint gx_io_device_table_count = countof(gx_io_device_table) - 1;
+
+/* Set up the device table. */
+#define device_(dev) &dev,
+private const gx_device *gx_device_list[] = {
+#include "gconfig.h"
+ 0
+};
+#undef device_
+
+/*
+ * Allocate structure descriptors for the devices.
+ * We can't fill in the structure sizes, because we don't know them
+ * statically, and we also don't know statically which devices are
+ * forwarders; so we fill all of this in when we need to
+ * (in gs_copydevice in gsdevice.c).
+ */
+#define device_(dev) { 0 },
+/* Because of a bug in the Borland C++ 4.5 compiler, */
+/* we can't declare the following far_data but not static. */
+static /*private*/ far_data gs_memory_struct_type_t gx_device_st_list[] = {
+#include "gconfig.h"
+ { 0 }
+};
+#undef device_
+
+/* Return the list of device prototypes, the list of their structure */
+/* descriptors, and (as the value) the length of the lists. */
+extern_gs_lib_device_list();
+int
+gs_lib_device_list(const gx_device ***plist, gs_memory_struct_type_t **pst)
+{ if ( plist != 0 )
+ *plist = gx_device_list;
+ if ( pst != 0 )
+ *pst = gx_device_st_list;
+ return countof(gx_device_list) - 1;
+}
diff --git a/gs/src/gdebug.h b/gs/src/gdebug.h
new file mode 100644
index 000000000..89b4f61fc
--- /dev/null
+++ b/gs/src/gdebug.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdebug.h */
+/* Debugging machinery definitions */
+
+#ifndef gdebug_INCLUDED
+# define gdebug_INCLUDED
+
+/* Define the array of debugging flags, indexed by character code. */
+extern char gs_debug[128];
+#define gs_debug_c(c)\
+ ((c)>='a' && (c)<='z' ? gs_debug[c] | gs_debug[(c)^32] : gs_debug[c])
+#ifdef DEBUG
+# define gs_if_debug_c(c) gs_debug_c(c)
+#else
+# define gs_if_debug_c(c) 0
+#endif
+/* Define an alias for a specialized debugging flag */
+/* that used to be a separate variable. */
+#define gs_log_errors gs_debug['#']
+
+/* If debugging, direct all error output to gs_debug_out. */
+extern FILE *gs_debug_out;
+#ifdef DEBUG
+#undef dstderr
+#define dstderr gs_debug_out
+#undef estderr
+#define estderr gs_debug_out
+#endif
+
+/* Redefine eprintf_program_name and lprintf_file_and_line as procedures */
+/* so one can set breakpoints on them. */
+#undef eprintf_program_name
+extern void eprintf_program_name(P2(FILE *, const char *));
+#undef lprintf_file_and_line
+extern void lprintf_file_and_line(P3(FILE *, const char *, int));
+
+/* Insert code conditionally if debugging. */
+#ifdef DEBUG
+# define do_debug(x) x
+#else
+# define do_debug(x)
+#endif
+
+/* Debugging printout macros. */
+/* The do...while construct is to avoid capturing a following 'else'. */
+#ifdef DEBUG
+# define if_debug0(c,s)\
+ do { if (gs_debug_c(c)) dprintf(s); } while (0)
+# define if_debug1(c,s,a1)\
+ do { if (gs_debug_c(c)) dprintf1(s,a1); } while (0)
+# define if_debug2(c,s,a1,a2)\
+ do { if (gs_debug_c(c)) dprintf2(s,a1,a2); } while (0)
+# define if_debug3(c,s,a1,a2,a3)\
+ do { if (gs_debug_c(c)) dprintf3(s,a1,a2,a3); } while (0)
+# define if_debug4(c,s,a1,a2,a3,a4)\
+ do { if (gs_debug_c(c)) dprintf4(s,a1,a2,a3,a4); } while (0)
+# define if_debug5(c,s,a1,a2,a3,a4,a5)\
+ do { if (gs_debug_c(c)) dprintf5(s,a1,a2,a3,a4,a5); } while (0)
+# define if_debug6(c,s,a1,a2,a3,a4,a5,a6)\
+ do { if (gs_debug_c(c)) dprintf6(s,a1,a2,a3,a4,a5,a6); } while (0)
+# define if_debug7(c,s,a1,a2,a3,a4,a5,a6,a7)\
+ do { if (gs_debug_c(c)) dprintf7(s,a1,a2,a3,a4,a5,a6,a7); } while (0)
+# define if_debug8(c,s,a1,a2,a3,a4,a5,a6,a7,a8)\
+ do { if (gs_debug_c(c)) dprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8); } while (0)
+# define if_debug9(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9)\
+ do { if (gs_debug_c(c)) dprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9); } while (0)
+# define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)\
+ do { if (gs_debug_c(c)) dprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } while (0)
+# define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)\
+ do { if (gs_debug_c(c)) dprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); } while (0)
+# define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\
+ do { if (gs_debug_c(c)) dprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); } while (0)
+#else
+# define if_debug0(c,s) DO_NOTHING
+# define if_debug1(c,s,a1) DO_NOTHING
+# define if_debug2(c,s,a1,a2) DO_NOTHING
+# define if_debug3(c,s,a1,a2,a3) DO_NOTHING
+# define if_debug4(c,s,a1,a2,a3,a4) DO_NOTHING
+# define if_debug5(c,s,a1,a2,a3,a4,a5) DO_NOTHING
+# define if_debug6(c,s,a1,a2,a3,a4,a5,a6) DO_NOTHING
+# define if_debug7(c,s,a1,a2,a3,a4,a5,a6,a7) DO_NOTHING
+# define if_debug8(c,s,a1,a2,a3,a4,a5,a6,a7,a8) DO_NOTHING
+# define if_debug9(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9) DO_NOTHING
+# define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING
+# define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING
+# define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING
+#endif
+
+/* Debugging support procedures in gsmisc.c */
+void debug_dump_bytes(P3(const byte *from, const byte *to,
+ const char *msg));
+void debug_dump_bitmap(P4(const byte *from, uint raster, uint height,
+ const char *msg));
+void debug_print_string(P2(const byte *str, uint len));
+
+#endif /* gdebug_INCLUDED */
diff --git a/gs/src/gdev3852.c b/gs/src/gdev3852.c
new file mode 100644
index 000000000..5eb2d758b
--- /dev/null
+++ b/gs/src/gdev3852.c
@@ -0,0 +1,187 @@
+/* Copyright (C) 1989, 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+This driver program created by Kevin M. Gift <kgift@draper.com> in Sept. 1992.
+Modified 3/93 to correct bug in cnt_2prn size.
+Modified 3/93 to dimension page back to 8.5, which seems to
+ work better than the actual page width of 7.6, ie. it uses
+ the full printing width of the printer.
+ It was modeled after the V2.4.1 HP Paintjet driver (gdevpjet.c) */
+
+/* gdev3852.c */
+/* IBM 3852 JetPrinter color ink jet driver for Ghostscript */
+
+#include "gdevprn.h"
+#include "gdevpcl.h"
+
+/* X_DPI and Y_DPI must be the same - use the maximum graphics resolution */
+/* for this printer */
+#define X_DPI 84
+#define Y_DPI 84
+
+/* We round up LINE_SIZE to a multiple of 8 bytes */
+/* because that's the unit of transposition from pixels to planes. */
+/* Should = 96 (KMG) */
+#define LINE_SIZE ((X_DPI * 86 / 10 + 63) / 64 * 8)
+
+/* The device descriptor */
+private dev_proc_print_page(jetp3852_print_page);
+private gx_device_procs jetp3852_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
+gx_device_printer far_data gs_jetp3852_device =
+ prn_device(jetp3852_procs, "jetp3852",
+ 86, /* width_10ths, 8.6" (?) */
+ 110, /* height_10ths, 11" */
+ X_DPI, Y_DPI,
+ 0.0, 0, 0.0, 0, /* left, bottom, right, top margins */
+ 3, jetp3852_print_page);
+
+
+/* ------ Internal routines ------ */
+
+/* Send the page to the printer. */
+private int
+jetp3852_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+#define DATA_SIZE (LINE_SIZE * 8)
+
+ unsigned int cnt_2prn;
+ unsigned int count,tempcnt;
+ unsigned char vtp,cntc1,cntc2;
+ int line_size_color_plane;
+
+ byte data[DATA_SIZE];
+ byte plane_data[LINE_SIZE * 3];
+
+ /* Set initial condition for printer */
+ fputs("\033@",prn_stream);
+
+ /* Send each scan line in turn */
+ { int lnum;
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int num_blank_lines = 0;
+ for ( lnum = 0; lnum < pdev->height; lnum++ )
+ { byte _ss *end_data = data + line_size;
+ gdev_prn_copy_scan_lines(pdev, lnum,
+ (byte *)data, line_size);
+ /* Remove trailing 0s. */
+ while ( end_data > data && end_data[-1] == 0 )
+ end_data--;
+ if ( end_data == data )
+ { /* Blank line */
+ num_blank_lines++;
+ }
+ else
+ { int i;
+ byte _ss *odp;
+ byte _ss *row;
+
+ /* Pad with 0s to fill out the last */
+ /* block of 8 bytes. */
+ memset(end_data, 0, 7);
+
+ /* Transpose the data to get pixel planes. */
+ for ( i = 0, odp = plane_data; i < DATA_SIZE;
+ i += 8, odp++
+ )
+ { /* The following is for 16-bit machines */
+#define spread3(c)\
+ { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
+ static ulong spr40[8] = spread3(0x40);
+ static ulong spr8[8] = spread3(8);
+ static ulong spr2[8] = spread3(2);
+ register byte _ss *dp = data + i;
+ register ulong pword =
+ (spr40[dp[0]] << 1) +
+ (spr40[dp[1]]) +
+ (spr40[dp[2]] >> 1) +
+ (spr8[dp[3]] << 1) +
+ (spr8[dp[4]]) +
+ (spr8[dp[5]] >> 1) +
+ (spr2[dp[6]]) +
+ (spr2[dp[7]] >> 1);
+ odp[0] = (byte)(pword >> 16);
+ odp[LINE_SIZE] = (byte)(pword >> 8);
+ odp[LINE_SIZE*2] = (byte)(pword);
+ }
+ /* Skip blank lines if any */
+ if ( num_blank_lines > 0 )
+ {
+ if (lnum == 0)
+ { /* Skip down the page from the top */
+ /* set line spacing = 1/8 inch */
+ fputs("\0330",prn_stream);
+ /* Set vertical tab */
+ vtp = (num_blank_lines / 8);
+ fprintf(prn_stream,"\033B%c\000",vtp);
+ /* Do vertical tab */
+ fputs("\013",prn_stream);
+ num_blank_lines = 0;
+ }
+ else
+ { /* Do "dot skips" */
+ while(num_blank_lines > 255)
+ {
+ fputs("\033e\377",prn_stream);
+ num_blank_lines -= 255;
+ }
+ vtp = num_blank_lines;
+ fprintf(prn_stream,"\033e%c",vtp);
+ num_blank_lines = 0;
+ }
+ }
+
+ /* Transfer raster graphics in the order R, G, B. */
+ /* Apparently it is stored in B, G, R */
+ /* Calculate the amount of data to send by what */
+ /* Ghostscript tells us the scan line_size in (bytes) */
+
+ count = line_size / 3;
+ line_size_color_plane = count / 3;
+ cnt_2prn = line_size_color_plane * 3 + 5;
+ tempcnt = cnt_2prn;
+ cntc1 = (tempcnt & 0xFF00) >> 8;
+ cntc2 = (tempcnt & 0x00FF);
+ fprintf(prn_stream, "\033[O%c%c\200\037",cntc2,cntc1);
+ fputc('\000',prn_stream);
+ fputs("\124\124",prn_stream);
+
+ for ( row = plane_data + LINE_SIZE * 2, i = 0;
+ i < 3; row -= LINE_SIZE, i++ )
+ { int jj;
+ byte ctemp;
+ odp = row;
+ /* Complement bytes */
+ for (jj=0; jj< line_size_color_plane; jj++)
+ { ctemp = *odp;
+ *odp++ = ~ctemp;
+ }
+ fwrite(row, sizeof(byte),
+ line_size_color_plane, prn_stream);
+ }
+ }
+ }
+ }
+
+ /* eject page */
+ fputs("\014", prn_stream);
+
+ return 0;
+}
diff --git a/gs/src/gdev3b1.c b/gs/src/gdev3b1.c
new file mode 100644
index 000000000..77d7f6d9e
--- /dev/null
+++ b/gs/src/gdev3b1.c
@@ -0,0 +1,791 @@
+/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+ * gdev3b1.c
+ *
+ * This is a driver for the AT&T 3b1/7300/UnixPC console display.
+ *
+ * The image is built in a buffer the size of the page. Once complete,
+ * a screen-sized subset is copied to the screen, and one can scroll
+ * through the entire image (move with "vi" or arrow keys).
+ *
+ * Written by Andy Fyfe, andy@cs.caltech.edu.
+ *
+ * There are a couple of undesirable "features" that I have found no
+ * way to work around.
+ *
+ * 1) Gs attempts to save the contents of the window before using it, and
+ * then restores the contents afterward. However, if the gs window is
+ * not the current window, and there are small windows present, then
+ * the saved image is incorrect, and thus the screen will not be correctly
+ * restored. This seems to be a bug in the 3b1 window driver. Making
+ * the gs window current before saving its contents is not an acceptable
+ * solution.
+ *
+ * 2) Gs will enable the scrolling/help/cancel icons if the window has
+ * a border. Changing these border icons has the side effect of making
+ * the gs window current. This does circumvent the first problem though.
+ */
+
+/*
+ * About the ATT3B1_PERF flag (notes by Andy Fyfe):
+ *
+ * I am unable to profile gs on the 3b1, so I added ATT3B1_PERF as a
+ * quick way to find out how much time was spent in the 3b1 driver,
+ * through dynamically suppressing parts of the code at run time by
+ * setting environment variables. I can then get the time spent in
+ * those parts by comparing the results of "time gs ....".
+ *
+ * At one point this was very useful, and led to a fairly substantial
+ * speedup of the fill and copy_mono routines. It also showed that I
+ * wasn't going to get too much more, overall, by further attempts to
+ * optimize the 3b1 driver. So those parts of the code controlled by
+ * ATT3B1_PERF have really now outlived their usefulness.
+ */
+
+#include "gx.h"
+#include "gxdevice.h"
+#include "gserrors.h"
+
+#include <errno.h>
+#include <sys/window.h>
+#include <sys/termio.h>
+
+typedef struct gx_device_att3b1_s {
+ gx_device_common;
+ int fd; /* window file descriptor */
+ uchar *screen; /* pointer to screen image */
+ ushort line_size; /* size of screen line in bytes */
+ ulong screen_size; /* size of screen image in bytes */
+ int page_num; /* page number */
+#ifdef ATT3B1_PERF
+ char *no_output, *no_fill, *no_copy;
+#endif
+} gx_device_att3b1;
+#define att3b1dev ((gx_device_att3b1 *)dev)
+
+#define XDPI 100 /* to get a more-or-less square aspect ratio */
+#define YDPI 72
+#define XSIZE (8.5 * XDPI) /* 8.5 x 11 inch page, by default */
+#define YSIZE (11 * YDPI)
+
+static const ushort masks[] = { 0,
+ 0x0001, 0x0003, 0x0007, 0x000f,
+ 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff,
+ 0x1fff, 0x3fff, 0x7fff, 0xffff,
+};
+static uchar reverse_bits[256] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
+
+dev_proc_open_device(att3b1_open);
+dev_proc_close_device(att3b1_close);
+dev_proc_fill_rectangle(att3b1_fill_rectangle);
+dev_proc_copy_mono(att3b1_copy_mono);
+dev_proc_output_page(att3b1_output_page);
+
+private gx_device_procs att3b1_procs = {
+ att3b1_open,
+ gx_default_get_initial_matrix,
+ gx_default_sync_output,
+ att3b1_output_page,
+ att3b1_close,
+ gx_default_map_rgb_color,
+ gx_default_map_color_rgb,
+ att3b1_fill_rectangle,
+ gx_default_tile_rectangle,
+ att3b1_copy_mono,
+ gx_default_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits
+};
+
+gx_device_att3b1 gs_att3b1_device = {
+ std_device_std_body(gx_device_att3b1, &att3b1_procs, "att3b1",
+ XSIZE, YSIZE, XDPI, YDPI),
+ { 0 }, /* std_procs */
+ -1, 0, 0, /* fd, screen, line_size, */
+ 0, 0, /* screen size, page */
+#ifdef ATT3B1_PERF
+ 0, 0, 0, /* no_output, no_fill, no_copy */
+#endif
+};
+
+int
+att3b1_open(gx_device *dev)
+{
+ struct uwdata uw;
+
+#ifdef ATT3B1_PERF
+ char *getenv(const char *);
+#endif
+
+ if (att3b1dev->fd >= 0) {
+ close(att3b1dev->fd);
+ att3b1dev->fd = -1;
+ }
+
+ if (att3b1dev->screen != NULL) {
+ gs_free((char *)att3b1dev->screen,
+ att3b1dev->screen_size, 1, "att3b1_open");
+ att3b1dev->screen = 0;
+ att3b1dev->screen_size = 0;
+ }
+
+ att3b1dev->fd = open("/dev/tty", 2);
+ if (att3b1dev->fd < 0) {
+ lprintf1("att3b1_open: open /dev/tty failed [%d]\n", errno);
+ return_error(gs_error_ioerror);
+ }
+
+ /* Verify that /dev/tty is associated with a console window. */
+ if (ioctl(att3b1dev->fd, WIOCGETD, &uw) < 0) {
+ lprintf1("att3b1_open: can not obtain window data [%d]\n", errno);
+ lprintf("att3b1_open: the att3b1 device requires a console window\n");
+ att3b1_close(dev);
+ return_error(gs_error_ioerror);
+ }
+
+ /* we need an even number of bytes per line */
+ att3b1dev->line_size = ((att3b1dev->width + 15) / 16) * 2;
+ att3b1dev->screen_size = att3b1dev->line_size * att3b1dev->height;
+
+ att3b1dev->screen =
+ (uchar *)gs_malloc(att3b1dev->screen_size, 1, "att3b1_open");
+ if (att3b1dev->screen == NULL) {
+ att3b1_close(dev);
+ return_error(gs_error_VMerror);
+ }
+
+ att3b1dev->page_num = 1;
+
+#ifdef ATT3B1_PERF
+ att3b1dev->no_output = getenv("GS_NOOUTPUT");
+ att3b1dev->no_fill = getenv("GS_NOFILL");
+ att3b1dev->no_copy = getenv("GS_NOCOPY");
+#endif
+
+ return 0;
+}
+
+int
+att3b1_close(gx_device *dev)
+{
+ if (att3b1dev->fd >= 0) {
+ close(att3b1dev->fd);
+ att3b1dev->fd = -1;
+ }
+
+ if (att3b1dev->screen != NULL) {
+ gs_free((char *)att3b1dev->screen,
+ att3b1dev->screen_size, 1, "att3b1_close");
+ att3b1dev->screen = 0;
+ att3b1dev->screen_size = 0;
+ }
+
+ return 0;
+}
+
+int
+att3b1_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index colour)
+{
+ uint o, b, wl, wr, w2;
+ ushort *p, *q, maskl, maskr;
+
+#ifdef ATT3B1_PERF
+ if (att3b1dev->no_fill) return 0;
+#endif
+
+ fit_fill(dev, x, y, w, h);
+
+ /* following fit_fill, we can assume x, y, w, h are unsigned. */
+
+ p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] +
+ (uint)x/16;
+ o = (uint)x % 16;
+ b = 16 - o;
+ wl = ((uint)w < b) ? (uint)w : b;
+ maskl = masks[wl] << o;
+ w -= wl;
+ wr = (uint)w % 16;
+ maskr = masks[wr];
+
+ if (colour == 0) {
+ maskl = ~maskl;
+ maskr = ~maskr;
+ while (h-- > 0) {
+ q = p;
+ w2 = w;
+ *q++ &= maskl;
+ while (w2 >= 16) {
+ *q++ = 0;
+ w2 -= 16;
+ }
+ *q &= maskr;
+ p += (att3b1dev->line_size / 2);
+ }
+ }
+ else {
+ while (h-- > 0) {
+ q = p;
+ w2 = w;
+ *q++ |= maskl;
+ while (w2 >= 16) {
+ *q++ = 0xffff;
+ w2 -= 16;
+ }
+ *q |= maskr;
+ p += (att3b1dev->line_size / 2);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef __GNUC__
+#define rotate(value, count) \
+ asm("ror%.l %2,%0" : "=d" (value) : "0" (value), "d" (count))
+#else
+#define rotate(value, count) \
+ value = (value >> count) | (value << (32-count))
+#endif
+
+int
+att3b1_copy_mono(gx_device *dev, const uchar *data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ gx_color_index colour0, gx_color_index colour1)
+{
+ const ushort *src_p, *src_q;
+ ushort *dst_p, *dst_q;
+ ulong bits, mask, *p;
+ uint src_o, src_b, dst_o, dst_b, op;
+ uint w1, w2;
+
+#ifdef ATT3B1_PERF
+ if (att3b1dev->no_copy) return 0;
+#endif
+
+ if (colour1 == colour0) /* vacuous case */
+ return att3b1_fill_rectangle(dev, x, y, width, height, colour0);
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+
+ /* following fit_copy, we can assume x, y, width, height are unsigned. */
+
+ /*
+ * In what follows, we're assuming that each row of the input bitmap
+ * is short-aligned, that is, that both "data" and "raster" are even.
+ */
+ src_p = ((const ushort *)data) + (uint)data_x/16;
+ src_o = (uint)data_x % 16;
+ src_b = 16 - src_o;
+
+ dst_p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] +
+ (uint)x/16;
+ dst_o = (uint)x % 16;
+ dst_b = 16 - dst_o;
+
+ op = (int)colour0 * 3 + (int)colour1 + 4;
+
+ while (height-- > 0) {
+ w2 = width;
+ src_q = src_p;
+ dst_q = dst_p;
+
+ while (w2 > 0) {
+ w1 = (w2 < 16) ? w2 : 16;
+ mask = masks[w1];
+ /*
+ * We are assuming that the bitmap "data" is typically aligned.
+ * Thus the test for this special case is typically a win over
+ * a 16-bit shift.
+ */
+ if (src_o == 0)
+ bits = *src_q++;
+ else {
+ bits = *((ulong *)src_q) >> src_b;
+ bits &= 0xffff;
+ src_q++;
+ }
+ if (w1 <= 8)
+ bits = reverse_bits[bits>>8];
+ else
+ bits = (reverse_bits[bits&0xff] << 8) | reverse_bits[bits>>8];
+ /*
+ * While the input bit map is assumed to be typically aligned, we
+ * assume that the place in the image is not. Thus we don't
+ * separate out the aligned case. Doing so would cost a test,
+ * and only reduce the average shift by about 1.
+ */
+ p = (ulong *)dst_q;
+ switch(op) {
+ case 1: /* not src and dst */
+ bits = ~(bits & mask);
+ rotate(bits,dst_b);
+ *p &= bits;
+ break;
+ case 2: /* src or dst */
+ bits = bits & mask;
+ rotate(bits,dst_b);
+ *p |= bits;
+ break;
+ case 3: /* src and dst */
+ bits = bits | ~mask;
+ rotate(bits,dst_b);
+ *p &= bits;
+ break;
+ case 5: /* src */
+ rotate(bits,dst_b);
+ rotate(mask,dst_b);
+ *p = (*p & ~mask) | (bits & mask);
+ break;
+ case 6: /* not src or dst */
+ bits = ~bits & mask;
+ rotate(bits,dst_b);
+ *p |= bits;
+ break;
+ case 7: /* not src */
+ rotate(bits,dst_b);
+ rotate(mask,dst_b);
+ *p = (*p & ~mask) | (~bits & mask);
+ break;
+ }
+ dst_q++;
+ w2 -= w1;
+ }
+
+ src_p += (raster / 2);
+ dst_p += (att3b1dev->line_size / 2);
+ }
+
+ return 0;
+}
+
+static int getKeyboard(gx_device *);
+
+const char *help_msg[] = {
+ "h, j, k, l, UP, DOWN, LEFT, RIGHT move the page (0.25\" h, 0.5\" v)",
+ "H, J, K, L, BEG, END move to far edge of the page",
+ "^U, ^D, ROLL UP, ROLL DOWN scroll up or down (1/2 screen height)",
+ "^F, ^B, PAGE UP, PAGE DOWN scroll up or down (full screen height)",
+ "c, C centre page horizontally, vertically",
+ "<, >, ^, _ fine movements (single pixel)",
+ "^L, ^R, r, HOME move to default position",
+ "=, MARK make current position the default",
+ "I invert the image (black <-> white)",
+ "q, x, ^C, EXIT, CANCL, n, f, NEXT,",
+ " SPACE, RETURN, ENTER end the page",
+ "?, HELP help screen",
+};
+
+static void
+do_help(gx_device *dev)
+{
+ int i;
+ struct utdata ut;
+
+ /* we would like to save the cursor position, but we can't */
+ write(att3b1dev->fd, "\033[2J\033[H", 7);
+
+ /* write help screen */
+ for (i=0; i < sizeof(help_msg)/sizeof(help_msg[0]); ++i) {
+ write(att3b1dev->fd, help_msg[i], strlen(help_msg[i]));
+ write(att3b1dev->fd, "\n", 1);
+ }
+ ut.ut_num = WTXTSLK1;
+ strcpy(ut.ut_text, "Press any key to continue");
+ ioctl(att3b1dev->fd, WIOCSETTEXT, &ut);
+
+ /* wait for keyboard input */
+ i = getKeyboard(dev);
+
+ /* clear screen and put cursor at the bottom of the screen */
+ write(att3b1dev->fd, "\033[2J\033[99;1H", 11);
+}
+
+int
+att3b1_output_page(gx_device *dev, int num_copies, int flush)
+{
+ struct urdata ur;
+ struct utdata ut, ut_orig;
+ struct uwdata uw;
+ int uflags;
+ struct termio old, new;
+ int xorigin, yorigin;
+ static int def_xorigin = 0, def_yorigin = 0;
+ int screen_width, screen_height;
+ int inverted = 0;
+ int error = 0;
+ int ch;
+ ushort *p;
+ ushort save_image[WINWIDTH * WINHEIGHT / 16];
+
+#ifdef ATT3B1_PERF
+ if (att3b1dev->no_output) return 0;
+#endif
+
+ /*
+ * initialize, and save screen state
+ */
+
+ if (ioctl(att3b1dev->fd, WIOCGETD, &uw) < 0) {
+ lprintf1("att3b1_output_page: window WIOCGETD ioctl failed [%d]\n",
+ errno);
+ att3b1_close(dev);
+ return_error(gs_error_ioerror);
+ }
+
+ /*
+ * we assume, henceforth, that screen ioctl calls will succeed
+ */
+
+ write(att3b1dev->fd, "\a\033[=1C", 6);
+
+ uflags = uw.uw_uflags;
+ if (!(uflags & NBORDER)) {
+ uw.uw_uflags = BORDHSCROLL | BORDVSCROLL | BORDHELP | BORDCANCEL;
+ ioctl(att3b1dev->fd, WIOCSETD, &uw);
+ }
+
+ ut_orig.ut_num = WTXTSLK1;
+ ioctl(att3b1dev->fd, WIOCGETTEXT, &ut_orig);
+
+ /* This isn't necessary, but helps a bit when the following attempt
+ to get the current screen image fails (without any indication). */
+ memset(save_image, '\0', sizeof(save_image));
+
+ ur.ur_srcbase = 0;
+ ur.ur_srcwidth = 0;
+ ur.ur_srcx = 0;
+ ur.ur_srcy = 0;
+ ur.ur_dstbase = save_image;
+ ur.ur_dstwidth = WINWIDTH / 8;
+ ur.ur_dstx = 0;
+ ur.ur_dsty = 0;
+ ur.ur_width = uw.uw_width;
+ ur.ur_height = uw.uw_height;
+ ur.ur_srcop = SRCSRC;
+ ur.ur_dstop = DSTSRC;
+ ur.ur_pattern = 0;
+ ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
+
+ ioctl(att3b1dev->fd, TCGETA, &old);
+ new = old;
+ new.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+ new.c_cc[VMIN] = 1;
+ ioctl(att3b1dev->fd, TCSETAF, &new);
+
+ screen_width = (uw.uw_width < att3b1dev->width) ? uw.uw_width
+ : att3b1dev->width;
+ screen_height = (uw.uw_height < att3b1dev->height) ? uw.uw_height
+ : att3b1dev->height;
+
+ write(att3b1dev->fd, "\033[2J", 4);
+
+ ur.ur_srcwidth = att3b1dev->line_size;
+ ur.ur_width = screen_width;
+ ur.ur_height = screen_height;
+ ur.ur_dstbase = 0;
+ ur.ur_dstwidth = 0;
+
+ /*
+ * allow one to move the screen window through the entire image
+ */
+
+ xorigin = def_xorigin;
+ yorigin = def_yorigin;
+
+ while (1) {
+ /* Things go bad if ur_srcx >= 2048 */
+ ur.ur_srcbase = (ushort *)att3b1dev->screen + (xorigin >> 4);
+ ur.ur_srcx = xorigin & 15;
+ ur.ur_srcy = yorigin;
+
+ if (ioctl(att3b1dev->fd, WIOCRASTOP, &ur) < 0) {
+ lprintf1(
+ "att3b1_output_page: window WIOCRASTOP ioctl failed [%d]\n",
+ errno);
+ error = gs_error_ioerror;
+ }
+
+ ut.ut_num = WTXTSLK1;
+ sprintf(ut.ut_text,
+ "%s %d, top right (%d,%d), size (%d,%d), press '?' for help.",
+ flush ? "Showpage" : "Copypage", att3b1dev->page_num, xorigin, yorigin,
+ att3b1dev->width, att3b1dev->height);
+ ioctl(att3b1dev->fd, WIOCSETTEXT, &ut);
+
+ ch = error ? 'q' : getKeyboard(dev);
+
+ switch(ch) {
+ case 'h':
+ xorigin -= ((uint)(int)att3b1dev->x_pixels_per_inch+3)/4;
+ break;
+
+ case 'k':
+ yorigin -= ((uint)(int)att3b1dev->y_pixels_per_inch+1)/2;
+ break;
+
+ case 'l':
+ xorigin += ((uint)(int)att3b1dev->x_pixels_per_inch+3)/4;
+ break;
+
+ case 'j':
+ yorigin += ((uint)(int)att3b1dev->y_pixels_per_inch+1)/2;
+ break;
+
+ case 'H':
+ xorigin = 0;
+ break;
+
+ case 'K':
+ yorigin = 0;
+ break;
+
+ case 'L':
+ xorigin = att3b1dev->width - screen_width;
+ break;
+
+ case 'J':
+ yorigin = att3b1dev->height - screen_height;
+ break;
+
+ case '<':
+ xorigin -= 1;
+ break;
+
+ case '>':
+ xorigin += 1;
+ break;
+
+ case '^':
+ yorigin -= 1;
+ break;
+
+ case '_':
+ yorigin += 1;
+ break;
+
+
+ case '\025': /* control-U */
+ yorigin -= screen_height/2;
+ break;
+
+ case '\004': /* control-D */
+ yorigin += screen_height/2;
+ break;
+
+ case '\002': /* control-B */
+ yorigin -= screen_height;
+ break;
+
+ case '\006': /* control-F */
+ yorigin += screen_height;
+ break;
+
+ case '\f':
+ case 'r' :
+ case '\022': /* control-R */
+ xorigin = def_xorigin;
+ yorigin = def_yorigin;
+ break;
+
+ case 'c': /* centre horizontally */
+ xorigin = (att3b1dev->width - screen_width) / 2;
+ break;
+
+ case 'C': /* centre vertically */
+ yorigin = (att3b1dev->height - screen_height) / 2;
+ break;
+
+ case '=':
+ def_xorigin = xorigin;
+ def_yorigin = yorigin;
+ break;
+
+ case 'I':
+ for (p = (ushort *)att3b1dev->screen;
+ p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
+ *p = ~ *p;
+ inverted = !inverted;
+ break;
+
+ case '?':
+ do_help(dev);
+ break;
+
+ case -1:
+ error = gs_error_ioerror;
+ /* fall through, for cleanup */
+
+ case 'q':
+ case 'x':
+ case '\003': /* control-C */
+ case 'n':
+ case 'f':
+ case ' ':
+ case '\n':
+ case '\r':
+ if (flush)
+ att3b1dev->page_num++;
+ else if (inverted) /* restore inverted image for copypage */
+ for (p = (ushort *)att3b1dev->screen;
+ p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
+ *p = ~ *p;
+ if (!(uflags & NBORDER)) {
+ ioctl(att3b1dev->fd, WIOCGETD, &uw); /*window may have moved*/
+ uw.uw_uflags = uflags;
+ ioctl(att3b1dev->fd, WIOCSETD, &uw);
+ }
+ ur.ur_srcbase = save_image;
+ ur.ur_srcwidth = WINWIDTH / 8;
+ ur.ur_width = uw.uw_width;
+ ur.ur_height = uw.uw_height;
+ ur.ur_srcx = 0;
+ ur.ur_srcy = 0;
+ ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
+ ioctl(att3b1dev->fd, WIOCSETTEXT, &ut_orig);
+ ioctl(att3b1dev->fd, TCSETAF, &old);
+ write(att3b1dev->fd, "\033[=0C", 5);
+
+ if (error) {
+ att3b1_close(dev);
+ return_error(error);
+ }
+ else
+ return 0;
+ }
+
+ if (xorigin >= att3b1dev->width - screen_width)
+ xorigin = att3b1dev->width - screen_width;
+ if (xorigin < 0)
+ xorigin = 0;
+ if (yorigin >= att3b1dev->height - screen_height)
+ yorigin = att3b1dev->height - screen_height;
+ if (yorigin < 0)
+ yorigin = 0;
+ }
+}
+
+static int
+get_char(gx_device *dev)
+{
+ char ch;
+ int count;
+
+ count = read(att3b1dev->fd, &ch, 1);
+ if (count == 0)
+ return 'q';
+ else if (count < 0)
+ return -1;
+ else
+ return ch;
+}
+
+static int
+getKeyboard(gx_device *dev)
+{
+ char ch;
+
+ ch = get_char(dev);
+
+ if (ch != '\033')
+ return ch;
+
+ /*
+ * If the char is escape, interpret the escape sequence and return
+ * an equivalent single character.
+ *
+ * Note that a mouse click on a window border icon is translated
+ * to the corresponding key, for example, the "up" icon generates
+ * roll-up/page-up/beg for the left/middle/right mouse button.
+ */
+
+ switch (get_char(dev)) {
+ case '[':
+ switch(get_char(dev)) {
+ case 'A': /* up arrow */
+ return 'k';
+ case 'T': /* shift up arrow (roll up) */
+ return '\025';
+ case 'B': /* down arrow */
+ return 'j';
+ case 'S': /* shift down arrow (roll down) */
+ return '\004';
+ case 'C': /* right arrow */
+ return 'l';
+ case 'D': /* left arrow */
+ return 'h';
+ case 'H': /* home */
+ return 'r';
+ case 'U': /* page down */
+ return '\006';
+ case 'V': /* page up */
+ return '\002';
+ }
+ break;
+ case 'O':
+ switch(get_char(dev)) {
+ case 'm': /* help */
+ case 'M': /* shift help */
+ return '?';
+ case 'k': /* exit */
+ case 'K': /* shift exit */
+ case 'w': /* cancl */
+ case 'W': /* shift cancl */
+ return 'q';
+ }
+ break;
+ case 'N':
+ switch(get_char(dev)) {
+ case 'h': /* next */
+ return 'f';
+ case 'i': /* mark */
+ return '=';
+ case 'L': /* shift right arrow */
+ return 'l';
+ case 'K': /* shift left arrow */
+ return 'h';
+ }
+ break;
+ case '9': /* Beg */
+ return 'K';
+ case '0': /* End */
+ return 'J';
+ }
+ return '\0';
+}
diff --git a/gs/src/gdev4081.c b/gs/src/gdev4081.c
new file mode 100644
index 000000000..16a276c1e
--- /dev/null
+++ b/gs/src/gdev4081.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1991, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdev4081.c */
+/* Ricoh 4081 laser printer driver */
+#include "gdevprn.h"
+
+#define X_DPI 300 /* pixels per inch */
+#define Y_DPI 300 /* pixels per inch */
+
+/* The device descriptor */
+private dev_proc_print_page(r4081_print_page);
+gx_device_printer far_data gs_r4081_device =
+ prn_device(prn_std_procs, "r4081",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ X_DPI, Y_DPI,
+ 0.25, 0.16, 0.25, 0.16, /* margins */
+ 1, r4081_print_page);
+
+/* ------ Internal routines ------ */
+
+
+/* Send the page to the printer. */
+private int
+r4081_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int out_size = ((pdev->width + 7) & -8) ;
+ byte *out = (byte *)gs_malloc(out_size, 1, "r4081_print_page(out)");
+ int lnum = 0;
+ int last = pdev->height;
+
+ /* Check allocations */
+ if ( out == 0 )
+ { if ( out )
+ gs_free((char *)out, out_size, 1,
+ "r4081_print_page(out)");
+ return -1;
+ }
+
+ /* find the first line which has something to print */
+ while ( lnum < last )
+ {
+ gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+ if ( out[0] != 0 ||
+ memcmp((char *)out, (char *)out+1, line_size-1)
+ )
+ break;
+ lnum ++;
+ }
+
+ /* find the last line which has something to print */
+ while (last > lnum) {
+ gdev_prn_copy_scan_lines(pdev, last-1, (byte *)out, line_size);
+ if ( out[0] != 0 ||
+ memcmp((char *)out, (char *)out+1, line_size-1)
+ )
+ break;
+ last --;
+ }
+
+ /* Initialize the printer and set the starting position. */
+ fprintf(prn_stream,"\033\rP\033\022YB2 \033\022G3,%d,%d,1,1,1,%d@",
+ out_size, last-lnum, (lnum+1)*720/Y_DPI);
+
+ /* Print lines of graphics */
+ while ( lnum < last )
+ {
+ gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+ fwrite(out, sizeof(char), line_size, prn_stream);
+ lnum ++;
+ }
+
+ /* Eject the page and reinitialize the printer */
+ fputs("\f\033\rP", prn_stream);
+
+ gs_free((char *)out, out_size, 1, "r4081_print_page(out)");
+ return 0;
+}
diff --git a/gs/src/gdev4693.c b/gs/src/gdev4693.c
new file mode 100644
index 000000000..94d174304
--- /dev/null
+++ b/gs/src/gdev4693.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 1992 Washington State University. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted.
+ * This software is provided "as is" without express or implied warranty.
+ */
+
+/* gdev4693.c */
+/* Driver for the Tektronix 4693d color plotter. */
+#include "gdevprn.h"
+
+/* Thanks to Karl Hakimian (hakimian@yoda.eecs.wsu.edu) */
+/* for contributing this code to Aladdin Enterprises. */
+
+#define X_DPI 100
+#define Y_DPI 100
+#define WIDTH_10THS 85
+#define HEIGHT_10THS 110
+
+private dev_proc_print_page(t4693d_print_page);
+private dev_proc_map_rgb_color(gdev_t4693d_map_rgb_color);
+private dev_proc_map_color_rgb(gdev_t4693d_map_color_rgb);
+
+private gx_device_procs t4693d_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gdev_t4693d_map_rgb_color, gdev_t4693d_map_color_rgb);
+
+#define t4693d_prn_device(name,depth,max_rgb) {prn_device_body( \
+ gx_device_printer,t4693d_procs,name, \
+ WIDTH_10THS, HEIGHT_10THS, X_DPI, Y_DPI, 0.25, 0.25, 0.25, 0.25, \
+ 3,depth,max_rgb,max_rgb,max_rgb + 1,max_rgb + 1, \
+ t4693d_print_page)}
+
+gx_device_printer gs_t4693d2_device = t4693d_prn_device("t4693d2",8, 3);
+gx_device_printer gs_t4693d4_device = t4693d_prn_device("t4693d4",16, 15);
+gx_device_printer gs_t4693d8_device = t4693d_prn_device("t4693d8",24, 255);
+
+private gx_color_index
+gdev_t4693d_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ ushort bitspercolor = prn_dev->color_info.depth / 3;
+ ulong max_value = (1 << bitspercolor) - 1;
+
+ if (bitspercolor == 5) {
+ bitspercolor--;
+ max_value = (1 << bitspercolor) - 1;
+ }
+
+ return ((r*max_value/gx_max_color_value) << (bitspercolor*2)) +
+ ((g*max_value/gx_max_color_value) << bitspercolor) +
+ (b*max_value/gx_max_color_value);
+}
+
+private int
+gdev_t4693d_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
+{
+ gx_color_value gray = color*gx_max_color_value/dev->color_info.max_gray;
+ prgb[0] = gray;
+ prgb[1] = gray;
+ prgb[2] = gray;
+ return(0);
+}
+
+private int
+t4693d_print_page(gx_device_printer *dev, FILE *ps_stream)
+{
+ char header[32];
+ int depth = prn_dev->color_info.depth;
+ int line_size = gdev_mem_bytes_per_scan_line(prn_dev);
+ byte *data = (byte *)gs_malloc(line_size, 1, "t4693d_print_page");
+ char *p;
+ ushort data_size = line_size/prn_dev->width;
+ int checksum;
+ int lnum;
+ int i;
+#if !arch_is_big_endian
+ byte swap;
+#endif
+
+ if (data == 0) return_error(gs_error_VMerror);
+ /* build header. */
+ p = header;
+ *p++ = 0x14; /* Print request */
+ *p++ = 0xc0|20; /* Length of header */
+ *p++ = 0xc0 | ((prn_dev->width >> 6)&0x3f);
+ *p++ = 0x80 | (prn_dev->width&0x3f);
+ *p++ = 0xc0 | ((prn_dev->height >> 6)&0x3f);
+ *p++ = 0x80 | (prn_dev->height&0x3f);
+ *p++ = 0xc1; /* Handshake */
+ *p++ = 0xc0; /* Get number of prints from printer. */
+ *p++ = 0xc0; /* Get pixel shape from printer. */
+ *p++ = (depth == 8) ? 0xcb : (depth == 16) ? 0xcc : 0xcd;
+ *p++ = 0xc1; /* Pixel-data order 1. */
+ *p++ = 0xc3; /* Interpolate to maximum size. */
+ *p++ = 0xc3; /* Full color range 1. */
+ *p++ = 0xc0; /* Color conversion from printer. */
+ *p++ = 0xc0; /* Color manipulation from printer. */
+ *p++ = 0xc0; /* B/W inversion from printer. */
+ *p++ = 0xc3; /* Portrait mode centered. */
+ *p++ = 0xc9; /* Use printer default for media and printing. */
+ *p++ = 0x95;
+ *p++ = 0x81;
+
+ for (checksum = 0, i = 0; &header[i] != p; i++)
+ checksum += header[i];
+
+ *p++ = ((checksum%128)&0x7f) | 0x80;
+ *p = 0x02; /* end of line. */
+ /* write header */
+ if (fwrite(header,1,22,ps_stream) != 22) {
+ fprintf(stderr,"Could not write header (t4693d).\n");
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return_error(gs_error_ioerror);
+ }
+
+ for (lnum = 0; lnum < prn_dev->height; lnum++) {
+ gdev_prn_copy_scan_lines(prn_dev,lnum,data,line_size);
+
+ for (i = 0; i < line_size; i += data_size) {
+
+ switch (depth) {
+ case 8:
+ data[i] &= 0x3f;
+ break;
+ case 16:
+#if arch_is_big_endian
+ data[i] &= 0x0f;
+#else
+ swap = data[i];
+ data[i] = data[i + 1]&0x0f;
+ data[i + 1] = swap;
+#endif
+ break;
+ case 24:
+ break;
+ default:
+ fprintf(stderr,"Bad depth (%d) t4693d.\n",depth);
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return_error(gs_error_rangecheck);
+ }
+
+ if (fwrite(&data[i],1,data_size,ps_stream) != data_size) {
+ fprintf(stderr,"Could not write pixel (t4693d).\n");
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return_error(gs_error_ioerror);
+ }
+
+ }
+
+ if (fputc(0x02,ps_stream) != 0x02) {
+ fprintf(stderr,"Could not write EOL (t4693d).\n");
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return_error(gs_error_ioerror);
+ }
+
+ }
+
+ if (fputc(0x01,ps_stream) != 0x01) {
+ fprintf(stderr,"Could not write EOT (t4693d).\n");
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return_error(gs_error_ioerror);
+ }
+
+ gs_free(data, line_size, 1, "t4693d_print_page");
+ return(0);
+}
diff --git a/gs/src/gdev8510.c b/gs/src/gdev8510.c
new file mode 100644
index 000000000..d414aa174
--- /dev/null
+++ b/gs/src/gdev8510.c
@@ -0,0 +1,144 @@
+/* Copyright (C) 1990, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+ * gdev8510.c
+ *
+ * C.Itoh M8510 printer driver for ghostscript.
+ * by Bob Smith <bob@snuffy.penfield.ny.us>
+ */
+
+#include "gdevprn.h"
+
+/* The device descriptor */
+private dev_proc_print_page(m8510_print_page);
+gx_device_printer far_data gs_m8510_device =
+ prn_device(prn_std_procs, "m8510",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ 160, /* x_dpi */
+ 144, /* y_dpi */
+ 0,0,0.5,0, /* left, bottom, right, and top margins */
+ 1, m8510_print_page);
+
+/* ------ forward declarations ------ */
+
+private void m8510_output_run(P4(gx_device_printer *pdev,
+ byte *out, int pass, FILE *prn_stream));
+
+/* ------ internal routines ------ */
+
+/* Send the page to the printer. */
+private int
+m8510_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte *in1 = (byte *) gs_malloc(8, line_size, "m8510_print_page(in1)");
+ byte *in2 = (byte *) gs_malloc(8, line_size, "m8510_print_page(in2)");
+ byte *out = (byte *) gs_malloc(8, line_size, "m8510_print_page(out)");
+ int lnum = 0;
+ int code = 0;
+ byte *inp, *in_end, *outp;
+ int i;
+
+ if (in1 == 0 || in2 == 0 || out == 0) {
+ code = gs_error_VMerror;
+ gs_note_error(code);
+ goto out;
+ }
+
+ /*
+ * Initialize the printer.
+ * NLQ mode, proportional print (160x144 dpi).
+ * and 16/144" linefeeds.
+ */
+ fwrite("\033m2\033P\033T16", 1, 9, prn_stream);
+
+ /* Transfer pixels to printer */
+ while ( lnum < pdev->height ) {
+ /* get a raster */
+ for (i = 7; i >= 0; i--) {
+ gdev_prn_copy_scan_lines(pdev, lnum, &in1[i*line_size], line_size);
+ lnum++;
+ gdev_prn_copy_scan_lines(pdev, lnum, &in2[i*line_size], line_size);
+ lnum++;
+ }
+
+ /* Transpose the 1st pass of data. */
+ in_end = in1 + line_size;
+ for (inp = in1, outp = out; inp < in_end; inp++, outp += 8)
+ gdev_prn_transpose_8x8(inp, line_size, outp, 1);
+
+ /* send the 1st line */
+ m8510_output_run(pdev, out, 0, prn_stream);
+
+ /* Transpose the 2nd pass of data. */
+ in_end = in2 + line_size;
+ for (inp = in2, outp = out; inp < in_end; inp++, outp += 8)
+ gdev_prn_transpose_8x8(inp, line_size, outp, 1);
+
+ /* send the 2nd line */
+ m8510_output_run(pdev, out, 1, prn_stream);
+ }
+
+ /* reset the printer. */
+ fwrite("\033c1", 1, 3, prn_stream);
+ fflush(prn_stream);
+
+out:;
+ if (out) gs_free((char *) out, 8, line_size, "m8510_print_page(out)");
+ if (in2) gs_free((char *) in2, 8, line_size, "m8510_print_page(in2)");
+ if (in1) gs_free((char *) in1, 8, line_size, "m8510_print_page(in1)");
+
+ return code;
+}
+
+private void
+m8510_output_run(gx_device_printer *pdev,
+ byte *out, int pass, FILE *prn_stream)
+{
+ byte *out_end = out + pdev->width;
+ char tmp[10];
+ int count;
+
+ /*
+ * Remove trailing 0s.
+ * out must be a multiple of 8 bytes.
+ */
+ while (out_end > out
+ && out_end[-1] == 0
+ && out_end[-2] == 0
+ && out_end[-3] == 0
+ && out_end[-4] == 0
+ && out_end[-5] == 0
+ && out_end[-6] == 0
+ && out_end[-7] == 0
+ && out_end[-8] == 0)
+ out_end -= 8;
+
+ /* Transfer the line of data. */
+ count = out_end - out;
+ if (count) {
+ sprintf(tmp, "\033g%03d", count/8);
+ fwrite(tmp, 1, 5, prn_stream);
+ fwrite(out, 1, count, prn_stream);
+ fwrite("\r", 1, 1, prn_stream);
+ }
+
+ if (pass) fwrite("\n", 1, 1, prn_stream);
+}
diff --git a/gs/src/gdev8bcm.c b/gs/src/gdev8bcm.c
new file mode 100644
index 000000000..137b2c296
--- /dev/null
+++ b/gs/src/gdev8bcm.c
@@ -0,0 +1,76 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdev8bcm.c */
+/* Dynamic color mapping for 8-bit displays */
+#include "gx.h"
+#include "gxdevice.h"
+#include "gdev8bcm.h"
+
+/* Initialize an 8-bit color map. */
+void
+gx_8bit_map_init(gx_8bit_color_map *pcm, int max_count)
+{ int i;
+ pcm->count = 0;
+ pcm->max_count = max_count;
+ for ( i = 0; i < gx_8bit_map_size; i++ )
+ pcm->map[i].rgb = gx_8bit_no_rgb;
+}
+
+/* Look up a color in an 8-bit color map. */
+/* Return <0 if not found. */
+int
+gx_8bit_map_rgb_color(const gx_8bit_color_map *pcm, gx_color_value r,
+ gx_color_value g, gx_color_value b)
+{ ushort rgb = gx_8bit_rgb_key(r, g, b);
+ const gx_8bit_map_entry *pme =
+ &pcm->map[(rgb * gx_8bit_map_spreader) % gx_8bit_map_size];
+ for ( ; ; pme++ )
+ { if ( pme->rgb == rgb )
+ return pme->index;
+ else if ( pme->rgb == gx_8bit_no_rgb )
+ break;
+ }
+ if ( pme != &pcm->map[gx_8bit_map_size] )
+ return pme - &pcm->map[gx_8bit_map_size];
+ /* We ran off the end; wrap around and continue. */
+ pme = &pcm->map[0];
+ for ( ; ; pme++ )
+ { if ( pme->rgb == rgb )
+ return pme->index;
+ else if ( pme->rgb == gx_8bit_no_rgb )
+ return pme - &pcm->map[gx_8bit_map_size];
+ }
+}
+
+/* Add a color to an 8-bit color map after an unsuccessful lookup, */
+/* and return its index. Return <0 if the map is full. */
+int
+gx_8bit_add_rgb_color(gx_8bit_color_map *pcm, gx_color_value r,
+ gx_color_value g, gx_color_value b)
+{ int index;
+ gx_8bit_map_entry *pme;
+ if ( gx_8bit_map_is_full(pcm) )
+ return -1;
+ index = gx_8bit_map_rgb_color(pcm, r, g, b);
+ if ( index >= 0 ) /* shouldn't happen */
+ return index;
+ pme = &pcm->map[-index];
+ pme->rgb = gx_8bit_rgb_key(r, g, b);
+ return (pme->index = pcm->count++);
+}
diff --git a/gs/src/gdev8bcm.h b/gs/src/gdev8bcm.h
new file mode 100644
index 000000000..209837803
--- /dev/null
+++ b/gs/src/gdev8bcm.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdev8bcm.h */
+/* Dynamic color mapping for 8-bit displays */
+/* Requires gxdevice.h (for gx_color_value) */
+
+/*
+ * The MS-DOS, MS Windows, and X Windows drivers all use (at least on
+ * some platforms) an 8-bit color map in which some fraction is reserved
+ * for a pre-allocated cube and some or all of the remainder is
+ * allocated dynamically. Since looking up colors in this map can be
+ * a major performance bottleneck, we provide an efficient implementation
+ * that can be shared among drivers.
+ *
+ * As a performance compromise, we only look up the top 5 bits of the
+ * RGB value in the color map. This compromises color quality very little,
+ * and allows substantial optimizations.
+ */
+
+#define gx_8bit_map_size 323
+#define gx_8bit_map_spreader 123 /* approx. 323 - (1.618 * 323) */
+typedef struct gx_8bit_map_entry_s {
+ ushort rgb; /* key = 0rrrrrgggggbbbbb */
+#define gx_8bit_no_rgb ((ushort)0xffff)
+#define gx_8bit_rgb_key(r, g, b)\
+ (((r >> (gx_color_value_bits - 5)) << 10) +\
+ ((g >> (gx_color_value_bits - 5)) << 5) +\
+ (b >> (gx_color_value_bits - 5)))
+ short index; /* value */
+} gx_8bit_map_entry;
+typedef struct gx_8bit_color_map_s {
+ int count; /* # of occupied entries */
+ int max_count; /* max # of occupied entries */
+ gx_8bit_map_entry map[gx_8bit_map_size + 1];
+} gx_8bit_color_map;
+
+/* Initialize an 8-bit color map. */
+void gx_8bit_map_init(P2(gx_8bit_color_map *, int));
+
+/* Look up a color in an 8-bit color map. */
+/* Return -1 if not found. */
+int gx_8bit_map_rgb_color(P4(const gx_8bit_color_map *, gx_color_value,
+ gx_color_value, gx_color_value));
+
+/* Test whether an 8-bit color map has room for more entries. */
+#define gx_8bit_map_is_full(pcm)\
+ ((pcm)->count == (pcm)->max_count)
+
+/* Add a color to an 8-bit color map. */
+/* Return -1 if the map is full. */
+int gx_8bit_add_rgb_color(P4(gx_8bit_color_map *, gx_color_value,
+ gx_color_value, gx_color_value));
diff --git a/gs/src/gdevabuf.c b/gs/src/gdevabuf.c
new file mode 100644
index 000000000..0a7e932f9
--- /dev/null
+++ b/gs/src/gdevabuf.c
@@ -0,0 +1,364 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevabuf.c */
+/* Alpha-buffering memory devices */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/* ================ Alpha devices ================ */
+
+/*
+ * These devices store 2 or 4 bits of alpha. They are a hybrid of a
+ * monobit device (for color mapping) and a 2- or 4-bit device (for painting).
+ * Currently, we only use them for character rasterizing, but they might be
+ * useful for other things someday.
+ */
+
+/* We can't initialize the device descriptor statically very well, */
+/* so we patch up the image2 or image4 descriptor. */
+private dev_proc_map_rgb_color(mem_alpha_map_rgb_color);
+private dev_proc_map_color_rgb(mem_alpha_map_color_rgb);
+private dev_proc_map_rgb_alpha_color(mem_alpha_map_rgb_alpha_color);
+private dev_proc_get_alpha_bits(mem_alpha_get_alpha_bits);
+private dev_proc_copy_alpha(mem_alpha_copy_alpha);
+
+void
+gs_make_mem_alpha_device(gx_device_memory *adev, gs_memory_t *mem,
+ gx_device *target, int alpha_bits)
+{ gs_make_mem_device(adev, gdev_mem_device_for_bits(alpha_bits),
+ mem, 0, target);
+ /* This is a black-and-white device ... */
+ adev->color_info = gdev_mem_device_for_bits(1)->color_info;
+ /* ... but it has multiple bits per pixel ... */
+ adev->color_info.depth = alpha_bits;
+ /* ... and different color mapping. */
+ set_dev_proc(adev, map_rgb_color, mem_alpha_map_rgb_color);
+ set_dev_proc(adev, map_color_rgb, mem_alpha_map_color_rgb);
+ set_dev_proc(adev, map_rgb_alpha_color, mem_alpha_map_rgb_alpha_color);
+ set_dev_proc(adev, get_alpha_bits, mem_alpha_get_alpha_bits);
+ set_dev_proc(adev, copy_alpha, mem_alpha_copy_alpha);
+}
+
+/* Reimplement color mapping. */
+private gx_color_index
+mem_alpha_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+ return (color == 0 || color == gx_no_color_index ? color :
+ (gx_color_index)((1 << mdev->log2_alpha_bits) - 1));
+}
+private int
+mem_alpha_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ return
+ gx_forward_map_color_rgb(dev,
+ (color == 0 ? color : (gx_color_index)1),
+ prgb);
+}
+private gx_color_index
+mem_alpha_map_rgb_alpha_color(gx_device *dev, gx_color_value r,
+ gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+ return (color == 0 || color == gx_no_color_index ? color :
+ (gx_color_index)(alpha >> (gx_color_value_bits -
+ mdev->log2_alpha_bits)));
+}
+private int
+mem_alpha_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return 1 << mdev->log2_alpha_bits;
+}
+/* Implement alpha copying. */
+private int
+mem_alpha_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ /* Just use copy_color. */
+ return (color == 0 ?
+ (*dev_proc(dev, fill_rectangle))(dev, x, y, width, height,
+ color) :
+ (*dev_proc(dev, copy_color))(dev, data, data_x, raster, id,
+ x, y, width, height));
+}
+
+/* ================ Alpha-buffer device ================ */
+
+/*
+ * This device converts graphics sampled at a higher resolution to
+ * alpha values at a lower resolution. It does this by accumulating
+ * the bits of a band and then converting the band to alphas.
+ * In order to make this work, the client of the device must promise
+ * only to visit each band at most once, except possibly for a single
+ * scan line overlapping the adjacent band, and must promise only to write
+ * a single color into the output. In particular, this works
+ * within a single call on gx_fill_path (if the fill loop is constrained
+ * to process bands of limited height on each pass) or a single masked image
+ * scanned in Y order, but not across such calls and not for other
+ * kinds of painting operations.
+ *
+ * We implement this device as a subclass of a monobit memory device.
+ * (We put its state in the definition of gx_device_memory just because
+ * actual subclassing introduces a lot of needless boilerplate.)
+ * We only allocate enough bits for one band. The height of the band
+ * must be a multiple of the Y scale factor; the minimum height
+ * of the band is twice the Y scale factor.
+ *
+ * The bits in storage are actually a sliding window on the true
+ * oversampled image. To avoid having to copy the bits around when we
+ * move the window, we adjust the mapping between the client's Y values
+ * and our own, as follows:
+ * Client Stored
+ * ------ ------
+ * y0..y0+m-1 n-m..n-1
+ * y0+m..y0+n-1 0..n-m-1
+ * where n and m are multiples of the Y scale factor and 0 <= m <= n <=
+ * the height of the band. (In the device structure, m is called
+ * mapped_start and n is called mapped_height.) This allows us to slide
+ * the window incrementally in either direction without copying any bits.
+ */
+
+/* Procedures */
+private dev_proc_close_device(mem_abuf_close);
+private dev_proc_copy_mono(mem_abuf_copy_mono);
+private dev_proc_fill_rectangle(mem_abuf_fill_rectangle);
+private dev_proc_get_clipping_box(mem_abuf_get_clipping_box);
+
+/* The device descriptor. */
+private const gx_device_memory far_data mem_alpha_buffer_device =
+ mem_device("image(alpha buffer)", 0, 1,
+ gx_forward_map_rgb_color, gx_forward_map_color_rgb,
+ mem_abuf_copy_mono, gx_default_copy_color, mem_abuf_fill_rectangle,
+ gx_no_strip_copy_rop);
+
+/* Make an alpha-buffer memory device. */
+/* We use abuf instead of alpha_buffer because */
+/* gcc under VMS only retains 23 characters of procedure names. */
+void
+gs_make_mem_abuf_device(gx_device_memory *adev, gs_memory_t *mem,
+ gx_device *target, const gs_log2_scale_point *pscale,
+ int alpha_bits, int mapped_x)
+{ gs_make_mem_device(adev, &mem_alpha_buffer_device, mem, 0, target);
+ adev->max_fill_band = 1 << pscale->y;
+ adev->log2_scale = *pscale;
+ adev->log2_alpha_bits = alpha_bits >> 1; /* works for 1,2,4 */
+ adev->mapped_x = mapped_x;
+ set_dev_proc(adev, close_device, mem_abuf_close);
+ set_dev_proc(adev, get_clipping_box, mem_abuf_get_clipping_box);
+}
+
+/* Test whether a device is an alpha-buffering device. */
+bool
+gs_device_is_abuf(const gx_device *dev)
+{ /* We can't just compare the procs, or even an individual proc, */
+ /* because we might be tracing. Instead, check the identity of */
+ /* the device name. */
+ return dev->dname == mem_alpha_buffer_device.dname;
+}
+
+/* Internal routine to flush a block of the buffer. */
+/* A block is a group of scan lines whose initial Y is a multiple */
+/* of the Y scale and whose height is equal to the Y scale. */
+private int
+abuf_flush_block(gx_device_memory *adev, int y)
+{ gx_device *target = adev->target;
+ int block_height = 1 << adev->log2_scale.y;
+ int alpha_bits = 1 << adev->log2_alpha_bits;
+ int ddepth =
+ (adev->width >> adev->log2_scale.x) << adev->log2_alpha_bits;
+ uint draster = bitmap_raster(ddepth);
+ int buffer_y = y - adev->mapped_y + adev->mapped_start;
+ byte *bits;
+
+ if ( buffer_y >= adev->height )
+ buffer_y -= adev->height;
+ bits = scan_line_base(adev, buffer_y);
+ { /*
+ * Many bits are typically zero. Save time by computing
+ * an accurate X bounding box before compressing.
+ * Unfortunately, in order to deal with alpha nibble swapping
+ * (see gsbitops.c), we can't expand the box only to pixel
+ * boundaries:
+ int alpha_mask = -1 << adev->log2_alpha_bits;
+ * Instead, we must expand it to byte boundaries,
+ */
+ int alpha_mask = ~7;
+ gs_int_rect bbox;
+ int width;
+
+ bits_bounding_box(bits, block_height, adev->raster, &bbox);
+ bbox.p.x &= alpha_mask;
+ bbox.q.x = (bbox.q.x + ~alpha_mask) & alpha_mask;
+ width = bbox.q.x - bbox.p.x;
+ bits_compress_scaled(bits, bbox.p.x, width, block_height,
+ adev->raster, bits, draster, &adev->log2_scale,
+ adev->log2_alpha_bits);
+ return (*dev_proc(target, copy_alpha))(target,
+ bits, 0, draster, gx_no_bitmap_id,
+ (adev->mapped_x + bbox.p.x) >>
+ adev->log2_scale.x,
+ y >> adev->log2_scale.y,
+ width >> adev->log2_scale.x, 1,
+ adev->save_color, alpha_bits);
+ }
+}
+/* Flush the entire buffer. */
+private int
+abuf_flush(gx_device_memory *adev)
+{ int y, code = 0;
+ int block_height = 1 << adev->log2_scale.y;
+ for ( y = 0; y < adev->mapped_height; y += block_height )
+ if ( (code = abuf_flush_block(adev, adev->mapped_y + y)) < 0 )
+ return code;
+ adev->mapped_height = adev->mapped_start = 0;
+ return 0;
+}
+
+/* Close the device, flushing the buffer. */
+private int
+mem_abuf_close(gx_device *dev)
+{ int code = abuf_flush(mdev);
+ if ( code < 0 )
+ return code;
+ return mem_close(dev);
+}
+
+/*
+ * Framework for mapping a requested imaging operation to the buffer.
+ * For now, we assume top-to-bottom transfers and use a very simple algorithm.
+ */
+typedef struct y_transfer_s {
+ int y_next;
+ int height_left;
+ int transfer_y;
+ int transfer_height;
+} y_transfer;
+private void near
+y_transfer_init(y_transfer *pyt, gx_device *dev, int ty, int th)
+{ int bh = 1 << mdev->log2_scale.y;
+ if ( ty < mdev->mapped_y || ty > mdev->mapped_y + mdev->mapped_height )
+ { abuf_flush(mdev);
+ mdev->mapped_y = ty & -bh;
+ mdev->mapped_height = bh;
+ memset(scan_line_base(mdev, 0), 0, bh * mdev->raster);
+ }
+ pyt->y_next = ty;
+ pyt->height_left = th;
+ pyt->transfer_height = 0;
+}
+/* while ( yt.height_left > 0 ) { y_transfer_next(&yt, mdev); ... } */
+private void near
+y_transfer_next(y_transfer *pyt, gx_device *dev)
+{ int my = mdev->mapped_y, mh = mdev->mapped_height;
+ int ms = mdev->mapped_start;
+ int ty = pyt->y_next += pyt->transfer_height;
+ int th = pyt->height_left;
+ int bh = 1 << mdev->log2_scale.y;
+ /* From here on, we know that my <= ty <= my + mh. */
+ int tby, tbh;
+ if ( ty == my + mh )
+ { /* Add a new block at my1. */
+ if ( mh == mdev->height )
+ { abuf_flush_block(mdev, my);
+ mdev->mapped_y = my += bh;
+ if ( (mdev->mapped_start = ms += bh) == mh )
+ mdev->mapped_start = ms = 0;
+ }
+ else
+ { /* Because we currently never extend backwards, */
+ /* we know we can't wrap around in this case. */
+ mdev->mapped_height = mh += bh;
+ }
+ memset(scan_line_base(mdev, (ms == 0 ? mh : ms) - bh),
+ 0, bh * mdev->raster);
+ }
+ /* Now we know that my <= ty < my + mh. */
+ tby = ty - my + ms;
+ if ( tby < mdev->height )
+ { tbh = mdev->height - ms;
+ if ( tbh > mh ) tbh = mh;
+ tbh -= tby - ms;
+ }
+ else /* wrap around */
+ { tby -= mdev->height;
+ tbh = ms + mh - dev->height - tby;
+ }
+ if_debug7('v', "[v]my=%d, mh=%d, ms=%d, ty=%d, th=%d, tby=%d, tbh=%d\n",
+ my, mh, ms, ty, th, tby, tbh);
+ if ( tbh > th ) tbh = th;
+ pyt->height_left = th - tbh;
+ pyt->transfer_y = tby;
+ pyt->transfer_height = tbh;
+}
+
+/* Copy a monobit image. */
+private int
+mem_abuf_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ y_transfer yt;
+ if ( zero != gx_no_color_index || one == gx_no_color_index )
+ return_error(gs_error_undefinedresult);
+ x -= mdev->mapped_x;
+ fit_copy_xwh(dev, base, sourcex, sraster, id, x, y, w, h); /* don't limit y */
+ mdev->save_color = one;
+ y_transfer_init(&yt, dev, y, h);
+ while ( yt.height_left > 0 )
+ { y_transfer_next(&yt, dev);
+ (*dev_proc(&mem_mono_device, copy_mono))(dev,
+ base + (yt.y_next - y) * sraster,
+ sourcex, sraster, gx_no_bitmap_id,
+ x, yt.transfer_y, w, yt.transfer_height,
+ gx_no_color_index, (gx_color_index)1);
+ }
+ return 0;
+}
+
+/* Fill a rectangle. */
+private int
+mem_abuf_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ y_transfer yt;
+ x -= mdev->mapped_x;
+ fit_fill_xyw(dev, x, y, w, h); /* don't limit h */
+ /* or check w <= 0, h <= 0 */
+ mdev->save_color = color;
+ y_transfer_init(&yt, dev, y, h);
+ while ( yt.height_left > 0 )
+ { y_transfer_next(&yt, dev);
+ (*dev_proc(&mem_mono_device, fill_rectangle))(dev,
+ x, yt.transfer_y, w, yt.transfer_height,
+ (gx_color_index)1);
+ }
+ return 0;
+}
+
+/* Get the clipping box. We must scale this up by the number of alpha bits. */
+private void
+mem_abuf_get_clipping_box(gx_device *dev, gs_fixed_rect *pbox)
+{ gx_device *tdev = mdev->target;
+
+ (*dev_proc(tdev, get_clipping_box))(tdev, pbox);
+ pbox->p.x <<= mdev->log2_scale.x;
+ pbox->p.y <<= mdev->log2_scale.y;
+ pbox->q.x <<= mdev->log2_scale.x;
+ pbox->q.y <<= mdev->log2_scale.y;
+}
diff --git a/gs/src/gdevadmp.c b/gs/src/gdevadmp.c
new file mode 100644
index 000000000..4c24bd8c6
--- /dev/null
+++ b/gs/src/gdevadmp.c
@@ -0,0 +1,407 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+ * This is a modification of Mark Wedel's Apple DMP and
+ * Jonathan Luckey's Imagewriter II driver to
+ * support the Imagewriter LQ's higher resolution (320x216):
+ * appledmp: 120dpi x 72dpi is still supported (yuck)
+ * iwlo: 160dpi x 72dpi
+ * iwhi: 160dpi x 144dpi
+ * iwlq: 320dpi x 216dpi
+ *
+ * This is also my first attempt to work with gs. I have not included the LQ's
+ * ability to print in colour. Perhaps at a later date I will tackle that.
+ *
+ * BTW, to get your Imagewriter LQ serial printer to work with a PC, attach it
+ * with a nullmodem serial cable.
+ *
+ * Scott Barker (barkers@cuug.ab.ca)
+ */
+
+/*
+ * This is a modification of Mark Wedel's Apple DMP driver to
+ * support 2 higher resolutions:
+ * appledmp: 120dpi x 72dpi is still supported (yuck)
+ * iwlo: 160dpi x 72dpi
+ * iwhi: 160dpi x 144dpi
+ *
+ * The Imagewriter II is a bit odd. In pinfeed mode, it thinks its
+ * First line is 1 inch from the top of the page. If you set the top
+ * form so that it starts printing at the top of the page, and print
+ * to near the bottom, it thinks it has run onto the next page and
+ * the formfeed will skip a whole page. As a work around, I reverse
+ * the paper about a 1.5 inches at the end of the page before the
+ * formfeed to make it think its on the 'right' page. bah. hack!
+ *
+ * This is my first attempt to work with gs, so your milage may vary
+ *
+ * Jonathan Luckey (luckey@rtfm.mlb.fl.us)
+ */
+
+/* This is a bare bones driver I developed for my apple Dot Matrix Printer.
+ * This code originally was from the epson driver, but I removed a lot
+ * of stuff that was not needed.
+ *
+ * The Dot Matrix Printer was a predecessor to the apple Imagewriter. Its
+ * main difference being that it was parallel.
+ *
+ * This code should work fine on Imagewriters, as they have a superset
+ * of commands compared to the DMP printer.
+ *
+ * This driver does not produce the smalles output files possible. To
+ * do that, it should look through the output strings and find repeat
+ * occurances of characters, and use the escape sequence that allows
+ * printing repeat sequences. However, as I see it, this the limiting
+ * factor in printing is not transmission speed to the printer itself,
+ * but rather, how fast the print head can move. This is assuming the
+ * printer is set up with a reasonable speed (9600 bps)
+ *
+ * WHAT THE CODE DOES AND DOES NOT DO:
+ *
+ * To print out images, it sets the printer for unidirection printing
+ * and 15 cpi (120 dpi). IT sets line feed to 1/9 of an inch (72 dpi).
+ * When finished, it sets things back to bidirection print, 1/8" line
+ * feeds, and 12 cpi. There does not appear to be a way to reset
+ * things to initial values.
+ *
+ * This code does not set for 8 bit characters (which is required). It
+ * also assumes that carriage return/newline is needed, and not just
+ * carriage return. These are all switch settings on the DMP, and
+ * I have configured them for 8 bit data and cr only.
+ *
+ * You can search for the strings Init and Reset to find the strings
+ * that set up the printer and clear things when finished, and change
+ * them to meet your needs.
+ *
+ * Also, you need to make sure that the printer daemon (assuming unix)
+ * doesn't change the data as it is being printed. I have set my
+ * printcap file (sunos 4.1.1) with the string:
+ * ms=pass8,-opost
+ * and it works fine.
+ *
+ * Feel free to improve this code if you want. However, please make
+ * sure that the old DMP will still be supported by any changes. This
+ * may mean making an imagewriter device, and just copying this file
+ * to something like gdevimage.c.
+ *
+ * The limiting factor of the DMP is the vertical resolution. However, I
+ * see no way to do anything about this. Horizontal resolution could
+ * be increased by using 17 cpi (136 dpi). I believe the Imagewriter
+ * supports 24 cpi (192 dpi). However, the higher dpi, the slower
+ * the printing.
+ *
+ * Dot Matrix Code by Mark Wedel (master@cats.ucsc.edu)
+ */
+
+
+#include "gdevprn.h"
+
+/* The device descriptors */
+private dev_proc_print_page(dmp_print_page);
+
+/* Standard DMP device */
+gx_device_printer far_data gs_appledmp_device =
+prn_device(prn_std_procs, "appledmp",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ 120, 72, /* X_DPI, Y_DPI */
+ 0, 0.5, 0.5, 0, /* margins */
+ 1, dmp_print_page);
+
+
+/* lowrez Imagewriter device */
+gx_device_printer far_data gs_iwlo_device =
+prn_device(prn_std_procs, "iwlo",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ 160, 72, /* X_DPI, Y_DPI */
+ 0, 0.5, 0.5, 0, /* margins */
+ 1, dmp_print_page);
+
+
+/* hirez Imagewriter device */
+gx_device_printer far_data gs_iwhi_device =
+prn_device(prn_std_procs, "iwhi",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ 160, 144, /* X_DPI, Y_DPI */
+ 0, 0.5, 0.5, 0, /* margins */
+ 1, dmp_print_page);
+
+
+/* LQ hirez Imagewriter device */
+gx_device_printer far_data gs_iwlq_device =
+prn_device(prn_std_procs, "iwlq",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ 320, 216,
+ 0, 0, 0.5, 0, /* margins */
+ 1, dmp_print_page);
+
+
+/* ------ Internal routines ------ */
+
+#define DMP 1
+#define IWLO 2
+#define IWHI 3
+#define IWLQ 4
+
+/* Send the page to the printer. */
+private int
+dmp_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int dev_type;
+
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ /* Note that in_size is a multiple of 8. */
+ int in_size = line_size * 8;
+
+ byte *buf1 = (byte *)gs_malloc(in_size, 1, "dmp_print_page(buf1)");
+ byte *buf2 = (byte *)gs_malloc(in_size, 1, "dmp_print_page(buf2)");
+ byte *prn = (byte *)gs_malloc(3*in_size, 1, "dmp_print_page(prn)");
+
+ byte *in = buf1;
+ byte *out = buf2;
+ int lnum = 0;
+
+ /* Check allocations */
+ if ( buf1 == 0 || buf2 == 0 || prn == 0 )
+ {
+ if ( buf1 )
+ gs_free((char *)buf1, in_size, 1,
+ "dmp_print_page(buf1)");
+ if ( buf2 )
+ gs_free((char *)buf2, in_size, 1,
+ "dmp_print_page(buf2)");
+ if ( prn )
+ gs_free((char *)prn, in_size, 1,
+ "dmp_print_page(prn)");
+ return_error(gs_error_VMerror);
+ }
+
+ if ( pdev->y_pixels_per_inch == 216 )
+ dev_type = IWLQ;
+ else if ( pdev->y_pixels_per_inch == 144 )
+ dev_type = IWHI;
+ else if ( pdev->x_pixels_per_inch == 160 )
+ dev_type = IWLO;
+ else
+ dev_type = DMP;
+
+ /* Initialize the printer and reset the margins. */
+
+ fputs("\r\n\033>\033T16", prn_stream);
+
+ switch(dev_type)
+ {
+ case IWLQ:
+ fputs("\033P\033a3", prn_stream);
+ break;
+ case IWHI:
+ case IWLO:
+ fputs("\033P", prn_stream);
+ break;
+ case DMP:
+ default:
+ fputs("\033q", prn_stream);
+ break;
+ }
+
+ /* Print lines of graphics */
+ while ( lnum < pdev->height )
+ {
+ byte *inp;
+ byte *in_end;
+ byte *out_end;
+ int lcnt,ltmp;
+ int count, passes;
+ byte *prn_blk, *prn_end, *prn_tmp;
+
+/* The apple DMP printer seems to be odd in that the bit order on
+ * each line is reverse what might be expected. Meaning, an
+ * underscore would be done as a series of 0x80, while on overscore
+ * would be done as a series of 0x01. So we get each
+ * scan line in reverse order.
+ */
+
+ switch (dev_type)
+ {
+ case IWLQ: passes = 3; break;
+ case IWHI: passes = 2; break;
+ case IWLO:
+ case DMP:
+ default: passes = 1; break;
+ }
+
+ for (count = 0; count < passes; count++)
+ {
+ for (lcnt=0; lcnt<8; lcnt++)
+ {
+ switch(dev_type)
+ {
+ case IWLQ: ltmp = lcnt + 8*count; break;
+ case IWHI: ltmp = 2*lcnt + count; break;
+ case IWLO:
+ case DMP:
+ default: ltmp = lcnt; break;
+ }
+
+ if ((lnum+ltmp)>pdev->height)
+ memset(in+lcnt*line_size,0,line_size);
+ else
+ gdev_prn_copy_scan_lines(pdev,
+ lnum+ltmp, in + line_size*(7 - lcnt),
+ line_size);
+ }
+
+ out_end = out;
+ inp = in;
+ in_end = inp + line_size;
+ for ( ; inp < in_end; inp++, out_end += 8 )
+ {
+ gdev_prn_transpose_8x8(inp, line_size,
+ out_end, 1);
+ }
+
+ out_end = out;
+
+ switch (dev_type)
+ {
+ case IWLQ: prn_end = prn + count; break;
+ case IWHI: prn_end = prn + in_size*count; break;
+ case IWLO:
+ case DMP:
+ default: prn_end = prn; break;
+ }
+
+ while ( (int)(out_end-out) < in_size)
+ {
+ *prn_end = *(out_end++);
+ if ((dev_type) == IWLQ) prn_end += 3;
+ else prn_end++;
+ }
+ }
+
+ switch (dev_type)
+ {
+ case IWLQ:
+ prn_blk = prn;
+ prn_end = prn_blk + in_size * 3;
+ while (prn_end > prn && prn_end[-1] == 0 &&
+ prn_end[-2] == 0 && prn_end[-3] == 0)
+ {
+ prn_end -= 3;
+ }
+ while (prn_blk < prn_end && prn_blk[0] == 0 &&
+ prn_blk[1] == 0 && prn_blk[2] == 0)
+ {
+ prn_blk += 3;
+ }
+ if (prn_end != prn_blk)
+ {
+ if ((prn_blk - prn) > 7)
+ fprintf(prn_stream,"\033U%04d%c%c%c",
+ (int)((prn_blk - prn)/3),
+ 0, 0, 0);
+ else
+ prn_blk = prn;
+ fprintf(prn_stream,"\033C%04d",
+ (int)((prn_end - prn_blk)/3));
+ fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
+ prn_stream);
+ }
+ break;
+ case IWHI:
+ for (count = 0; count < 2; count++)
+ {
+ prn_blk = prn_tmp = prn + in_size*count;
+ prn_end = prn_blk + in_size;
+ while (prn_end > prn_blk && prn_end[-1] == 0)
+ prn_end--;
+ while (prn_blk < prn_end && prn_blk[0] == 0)
+ prn_blk++;
+ if (prn_end != prn_blk)
+ {
+ if ((prn_blk - prn_tmp) > 7)
+ fprintf(prn_stream,
+ "\033V%04d%c",
+ (int)(prn_blk-prn_tmp),
+ 0);
+ else
+ prn_blk = prn_tmp;
+ fprintf(prn_stream,"\033G%04d",
+ (int)(prn_end - prn_blk));
+ fwrite(prn_blk, 1,
+ (int)(prn_end - prn_blk),
+ prn_stream);
+ }
+ if (!count) fputs("\033T01\r\n",prn_stream);
+ }
+ fputs("\033T15",prn_stream);
+ break;
+ case IWLO:
+ case DMP:
+ default:
+ prn_blk = prn;
+ prn_end = prn_blk + in_size;
+ while (prn_end > prn_blk && prn_end[-1] == 0)
+ prn_end--;
+ while (prn_blk < prn_end && prn_blk[0] == 0)
+ prn_blk++;
+ if (prn_end != prn_blk)
+ {
+ if ((prn_blk - prn) > 7)
+ fprintf(prn_stream,"\033V%04d%c",
+ (int)(prn_blk - prn), 0);
+ else
+ prn_blk = prn;
+ fprintf(prn_stream,"\033G%04d",
+ (int)(prn_end - prn_blk));
+ fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
+ prn_stream);
+ }
+ break;
+ }
+
+ fputs("\r\n",prn_stream);
+
+ switch (dev_type)
+ {
+ case IWLQ: lnum += 24 ; break;
+ case IWHI: lnum += 16 ; break;
+ case IWLO:
+ case DMP:
+ default: lnum += 8 ; break;
+ }
+ }
+
+ /* ImageWriter will skip a whole page if too close to end */
+ /* so skip back more than an inch */
+ if ( !(dev_type == DMP) )
+ fputs("\033T99\n\n\033r\n\n\n\n\033f", prn_stream);
+
+ /* Formfeed and Reset printer */
+ fputs("\033T16\f\033<\033B\033E", prn_stream);
+ fflush(prn_stream);
+
+ gs_free((char *)prn, in_size, 1, "dmp_print_page(prn)");
+ gs_free((char *)buf2, in_size, 1, "dmp_print_page(buf2)");
+ gs_free((char *)buf1, in_size, 1, "dmp_print_page(buf1)");
+ return 0;
+}
diff --git a/gs/src/gdevasyn.c b/gs/src/gdevasyn.c
new file mode 100644
index 000000000..afb3339d8
--- /dev/null
+++ b/gs/src/gdevasyn.c
@@ -0,0 +1,661 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevasyn.c */
+/* .BMP file format output drivers: Demo of ASYNC rendering */
+
+/* Initial version 2/2/98 by John Desrosiers (soho@crl.com) */
+
+#include "stdio_.h"
+#include "gserrors.h"
+#include "gdevprna.h"
+#include "gdevpccm.h"
+#include "gpsync.h"
+
+/* ------ The device descriptors ------ */
+
+/* Define data type for this device based on prn_device */
+typedef struct gx_device_async_s {
+ gx_device_common;
+ gx_prn_device_common;
+ int buffered_page_exists;
+ long file_offset_to_data;
+ int copies_printed;
+} gx_device_async;
+
+/* Define initializer for device */
+#define async_device(procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\
+{ prn_device_std_margins_body(gx_device_async, procs, dname,\
+ w10, h10, xdpi, ydpi, lm, tm, lm, bm, rm, tm, color_bits, print_page),\
+ 0, 0L\
+}
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+private dev_proc_open_device(bmp_writer_open);
+private dev_proc_open_render_device(bmp_reader_open_render_device);
+private dev_proc_print_page_copies(bmp_reader_print_page_copies);
+private dev_proc_buffer_page(bmp_reader_buffer_page);
+private dev_proc_output_page(bmp_reader_output_page);
+private dev_proc_put_params(bmp_put_params);
+private dev_proc_get_hardware_params(bmp_get_hardware_params);
+private dev_proc_start_render_thread(bmp_reader_start_render_thread);
+private dev_proc_get_space_params(bmp_get_space_params);
+#define default_print_page 0 /* not needed becoz print_page_copies def'd */
+
+/* Monochrome. */
+
+private gx_device_procs asyncmono_procs =
+ prn_procs(bmp_writer_open, gdev_prn_output_page, gdev_prn_close);
+gx_device_async far_data gs_asynmono_device =
+ async_device(asyncmono_procs, "asyncmono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, default_print_page);
+
+/* 4-bit planar (EGA/VGA-style) color. */
+
+private gx_device_procs async16_procs =
+ prn_color_procs(bmp_writer_open, gdev_prn_output_page, gdev_prn_close,
+ pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
+gx_device_async far_data gs_asyn16_device =
+ async_device(async16_procs, "async16",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 4, default_print_page);
+
+/* 8-bit (SuperVGA-style) color. */
+/* (Uses a fixed palette of 3,3,2 bits.) */
+
+private gx_device_procs async256_procs =
+ prn_color_procs(bmp_writer_open, gdev_prn_output_page, gdev_prn_close,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_async far_data gs_asyn256_device =
+ async_device(async256_procs, "async256",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 8, default_print_page);
+
+/* 24-bit color. */
+
+private dev_proc_map_rgb_color(map_16m_rgb_color);
+private dev_proc_map_color_rgb(map_16m_color_rgb);
+private gx_device_procs async16m_procs =
+ prn_color_procs(bmp_writer_open, gdev_prn_output_page, gdev_prn_close,
+ map_16m_rgb_color, map_16m_color_rgb);
+gx_device_async far_data gs_asyn16m_device =
+ async_device(async16m_procs, "async16m",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 24, default_print_page);
+
+/* ------ Private definitions ------ */
+
+/* All multi-byte quantities are stored LSB-first! */
+typedef ushort word;
+#if arch_sizeof_int == 4
+typedef uint dword;
+#else
+# if arch_sizeof_long == 4
+typedef ulong dword;
+# endif
+#endif
+#if arch_is_big_endian
+# define assign_word(a,v) a = ((v) >> 8) + ((v) << 8)
+# define assign_dword(a,v)\
+ a = ((v) >> 24) + (((v) >> 8) & 0xff00L) +\
+ (((dword)(v) << 8) & 0xff0000L) + ((dword)(v) << 24)
+#else
+# define assign_word(a,v) a = (v)
+# define assign_dword(a,v) a = (v)
+#endif
+
+typedef struct bmp_file_header_s {
+
+ /* BITMAPFILEHEADER */
+
+ /*
+ * This structure actually begins with two bytes
+ * containing the characters 'BM', but we must omit them,
+ * because some compilers would insert padding to force
+ * the size member to a 32- or 64-bit boundary.
+ */
+
+ /*byte typeB, typeM;*/ /* always 'BM' */
+ dword size; /* total size of file */
+ word reserved1;
+ word reserved2;
+ dword offBits; /* offset of bits from start of file */
+
+} bmp_file_header;
+#define sizeof_bmp_file_header (2 + sizeof(bmp_file_header))
+
+typedef struct bmp_info_header_s {
+
+ /* BITMAPINFOHEADER */
+
+ dword size; /* size of info header in bytes */
+ dword width; /* width in pixels */
+ dword height; /* height in pixels */
+ word planes; /* # of planes, always 1 */
+ word bitCount; /* bits per pixel */
+ dword compression; /* compression scheme, always 0 */
+ dword sizeImage; /* size of bits */
+ dword xPelsPerMeter; /* X pixels per meter */
+ dword yPelsPerMeter; /* Y pixels per meter */
+ dword clrUsed; /* # of colors used */
+ dword clrImportant; /* # of important colors */
+
+ /* This is followed by (1 << bitCount) bmp_quad structures, */
+ /* unless bitCount == 24. */
+
+} bmp_info_header;
+
+typedef struct bmp_quad_s {
+
+ /* RGBQUAD */
+
+ byte blue, green, red, reserved;
+
+} bmp_quad;
+
+/* --------- Forward decl's ---------- */
+private int write_bmp_header(P2(gx_device_async *, FILE *));
+private void bmp_reader_thread(P1(void *));
+
+/* ------------ Writer Instance procedures ---------- */
+/* Writer's open procedure */
+private int
+bmp_writer_open(
+ gx_device *pdev /* Driver instance to open */
+)
+{ gx_device_async * const pwdev = (gx_device_async *)pdev;
+ int max_width;
+ int max_raster;
+ int min_band_height;
+ int max_src_image_row;
+
+ /* Set up device's printer proc vector to point to this driver, since */
+ /* there are no convenient macros for setting them up in static template. */
+ init_async_render_procs(pwdev, bmp_reader_start_render_thread,
+ bmp_reader_buffer_page, bmp_reader_print_page_copies);
+ set_dev_proc(pdev, put_params, bmp_put_params);
+ set_dev_proc(pdev, get_hardware_params, bmp_get_hardware_params);
+ set_dev_proc(pdev, output_page, bmp_reader_output_page); /* hack */
+ pwdev->printer_procs.get_space_params = bmp_get_space_params;
+ pwdev->printer_procs.open_render_device
+ = bmp_reader_open_render_device; /* Included for tutorial value */
+
+ /* Determine MAXIMUM parameters this device will have to support over lifetime */
+ /* See comments for bmp_get_space_params() */
+ max_width = DEFAULT_WIDTH_10THS * 60; /* figure max wid = default @ 600dpi */
+ min_band_height = max( 1, (DEFAULT_HEIGHT_10THS * 60) / 100 );
+ max_raster = (max_width * pwdev->color_info.depth) / 8; /* doesn't need to be super accurate */
+ max_src_image_row = max_width * 3 * 2;
+
+ /* Special writer open routine for async interpretation */
+ /* Starts render thread */
+ return gdev_prn_async_write_open( (gx_device_printer *)pdev,
+ max_raster, min_band_height, max_src_image_row );
+}
+
+/* -------------- Renderer instance procedures ----------*/
+
+/* Thread to do rendering, started by bmp_reader_start_render_thread */
+private void
+bmp_reader_thread(void *params)
+{
+ gdev_prn_async_render_thread( (gdev_prn_start_render_params *)params );
+}
+
+private int /* rets 0 ok, -ve error if couldn't start thread */
+bmp_reader_start_render_thread(gdev_prn_start_render_params *params)
+{ return gp_create_thread(bmp_reader_thread, params);
+}
+
+private int
+bmp_reader_open_render_device(gx_device_printer *ppdev)
+{ gx_device_async * const prdev = (gx_device_async *)ppdev;
+
+ /* Do anything that needs to be done at open time here... */
+ prdev->copies_printed = 0;
+
+ /* Cascade down to the default handler */
+ return gdev_prn_async_render_open(ppdev);
+}
+
+/* Generic routine to send the page to the printer. */
+private int
+bmp_reader_output_page(gx_device *pdev, int num_copies, int flush)
+{ /* This kluge opens the printer page with the positionable attribute */
+ /* since we need to seek back & forth to support partial rendering */
+ if ( num_copies > 0 || !flush )
+ { int code = gdev_prn_open_printer_positionable(pdev, 1, 1);
+ if ( code < 0 )
+ return code;
+ }
+ return gdev_prn_output_page(pdev, num_copies, flush);
+}
+
+private int
+bmp_reader_print_page_copies(gx_device_printer *pdev, FILE *prn_stream,
+ int num_copies)
+{ gx_device_async * const prdev = (gx_device_async *)pdev;
+ gx_device * const dev = (gx_device *)pdev;
+ int code = 0;
+ int y;
+ byte *raster_data;
+ int raster;
+ ulong bmp_raster;
+
+ /* BMP format is single page, so discard all but 1st printable page */
+ /* This logic isn't quite right since we can't truncate file if num_pages == 0 */
+ if (prdev->copies_printed > 0)
+ return 0;
+
+ /* If there's data in buffer, need to process w/overlays */
+ if (prdev->buffered_page_exists)
+ {
+ code = bmp_reader_buffer_page(pdev, prn_stream, num_copies);
+ goto done;
+ }
+
+ /* Write header & seek to its end */
+ raster = gx_device_raster(dev, 1);
+ bmp_raster = raster + (-raster & 3); /* BMP scan lines are padded to 32 bits. */
+ fseek(prn_stream, 0L, SEEK_SET);
+ if ( ( code = write_bmp_header(prdev, prn_stream) ) < 0 )
+ goto done;
+
+ /* Write out the bands top to bottom */
+ /* Finish the job even if num_copies == 0 to avoid invalid output file */
+ for ( y = prdev->height - 1; y >= 0; y-- )
+ { if ( ( code = dev_proc(dev, get_bits)(dev, y, 0, &raster_data) ) < 0 )
+ goto done;
+ if ( fwrite( (const char *)raster_data, bmp_raster, 1, prn_stream ) < 1 )
+ { code = gs_error_ioerror;
+ goto done;
+ }
+ }
+done: if (code >= 0 && prdev->copies_printed > 0)
+ prdev->copies_printed = num_copies;
+ prdev->buffered_page_exists = 0;
+ return code;
+}
+
+/* Buffer a (partial) rasterized page & optionally print result multiple times. */
+private int
+bmp_reader_buffer_page(gx_device_printer *pdev, FILE *file, int num_copies)
+{ gx_device_async * const prdev = (gx_device_async *)pdev;
+ gx_device * const dev = (gx_device *)pdev;
+ int code = 0;
+
+ /* BMP format is single page, so discard all but 1st page */
+ if (prdev->copies_printed > 0)
+ return 0;
+
+ /* If there's no data in buffer, no need to do any overlays */
+ if (!prdev->buffered_page_exists)
+ {
+ code = bmp_reader_print_page_copies(pdev, file, num_copies);
+ goto done;
+ }
+
+ /* Overlay file's bits on top of existing file */
+ /* There are two choices for doing this: get_overlay_bits vs. */
+ /* the combination of locate_overlay_buffer and get_bits. If you */
+ /* already have a buffer in a format compatible with GS's format, */
+ /* use get_overlay_bits. If you'd rather use the buffer already */
+ /* in the device, use locate_overlay_buffer, copy the bits into */
+ /* the returned buffer, then get_bits. */
+ /* */
+ /* Either way, try to do entire bands at a shot for much */
+ /* greater efficiency. */
+
+ /* Seek to beginning of data portion of file */
+ if ( fseek(file, prdev->file_offset_to_data, SEEK_SET) )
+ {
+ code = gs_error_ioerror;
+ goto done;
+ }
+
+ { byte *raster_data;
+ int raster = gx_device_raster(dev, 1);
+ ulong bmp_raster = raster + (-raster & 3); /* BMP scan lines are padded to 32 bits. */
+ int max_band_height
+ = (*pdev->printer_procs.locate_overlay_buffer)(pdev, 0, &raster_data);
+ int band;
+ byte buffer;
+ int file_raster_good = min(raster, bmp_raster);
+ long file_raster_slop = bmp_raster - file_raster_good;
+
+ /* iterate thru bands from top to bottom */
+ /* This is done an entire band at a time for efficiency */
+ for (band = (pdev->height - 1) / max_band_height; band >= 0; --band)
+ {
+ int band_base_line = max_band_height * band;
+ int band_height = (*pdev->printer_procs.locate_overlay_buffer)
+ (pdev, band_base_line, &raster_data);
+ int line;
+
+ /* Fill in overlay buffer with a band from the BMP file. */
+ /* Need to do this backward since BMP is top to bottom */
+ for (line = band_height - 1; line >= 0; --line)
+ if ( fread(raster_data + line * bmp_raster, file_raster_good, 1, file)
+ < 1 || fseek(file, file_raster_slop, SEEK_CUR) )
+ { code = gs_error_ioerror;
+ goto done;
+ }
+
+ /* Rewind & write out buffer with contents of get_bits */
+ if ( fseek(file, -(file_raster_good + file_raster_slop) * band_height,
+ SEEK_CUR) )
+ { code = gs_error_ioerror;
+ goto done;
+ }
+ for (line = band_height - 1; line >= 0; --line)
+ { if ( ( code = dev_proc(dev, get_bits)
+ (dev, line + band_base_line, 0, &raster_data) ) < 0 )
+ goto done;
+ if ( fwrite(raster_data, file_raster_good, 1, file) < 1
+ || fseek(file, file_raster_slop, SEEK_CUR) )
+ { code = gs_error_ioerror;
+ goto done;
+ }
+ }
+ }
+ }
+
+done: if (code >= 0 && prdev->copies_printed > 0)
+ prdev->copies_printed = num_copies;
+ prdev->buffered_page_exists = (code >= 0);
+ return code;
+}
+
+/*------------ Procedures common to writer & renderer -------- */
+
+/* Compute space parameters */
+private void
+bmp_get_space_params(const gx_device_printer *pdev,
+ gdev_prn_space_params *space_params)
+{ /* Plug params into device before opening it
+ *
+ * You ask "How did you come up with these #'s?" You asked, so...
+ *
+ * To answer clearly, let me begin by recapitulating how command list (clist)
+ * device memory allocation works in the non-overlapped case: When the
+ * device is opened, a buffer is allocated. How big? For starters,
+ * it must be >= PRN_MIN_BUFFER_SPACE, and as we'll see, must be
+ * sufficient to satisfy the rest of the band params. If you don't specify
+ * a size for it in space_params.band.BandBufferSpace, the open routine'll
+ * usa a heuristic where it tries to use PRN_BUFFER_SPACE, then works its
+ * way down by 2's if that much memory isn't available.
+ *
+ * The device proceeds to divide the buffer into several parts:
+ * one of them is used for the same thing during writing
+ * & rasterizing; the other parts are redivided and used
+ * differently writing and rasterizing. The limiting factor
+ * dictating memory requirements is the rasterizer's render buffer.
+ * This buffer needs to be able to contain a bitmap that covers
+ * an entire band. Memory consumption is whatever is needed to hold
+ * N rows of data aligned on word boundaries, + sizeof(pointer) for
+ * each of N rows. Whatever is left over in the rasterized is
+ * allocated to a tile cache. You want to make sure that cache
+ * is at least 50KB.
+ *
+ * For example, take a 600 dpi b/w device at 8.5 x 11 inches.
+ * For the whole device, that's 6600 rows @ 638 bytes = ~4.2 MB total.
+ * If the device is divided into 100 bands, each band's rasterizer
+ * buffer is 62K. Add on a 50K tile cache, and you get a 112KB
+ * (+ add a little slop) total device buffer size.
+ *
+ * Now that we've covered the rasterizer, let's switch back to the
+ * writer. The writer must have a tile cache *exactly* the same
+ * size as the reader. This means that the space to divide up
+ * for the writer is equal is size to the rasterizer's band buffer.
+ * This space is divided into 2 sections: per-band bookeeping info
+ * and a command buffer. The bookeeping info currently uses ~72
+ * bytes for each band. The rest is the command buffer.
+ *
+ * To continue the same 112KB example, we have 62KB to slice up.
+ * We need 72 bytes * 100 bands = 7.2KB, leaving a 55K command buffer.
+ *
+ * A larger command buffer has some performance (see gxclmem.c comments)
+ * advantages in the general case, but is critical in one special
+ * case: high-level images. Whenever possible, images are transmitted
+ * across the band buffer in their original resolution and
+ * bits/pixel. The alternative fallback behavior can be horribly slow.
+ * Here, the relevant restriction is that at least one entire source
+ * image row must fit into the command buffer. This means that, in
+ * our example, an RGB source image would have to be <= 18K pixels
+ * wide. If the image is sampled at the same resolution as the
+ * hardware (600 dpi), that means the row would be limited to a very
+ * reasonable 30 inches. However, if the source image is sampled at
+ * 2400 dpi, that limit is only 7.5 inches. The situation gets
+ * worse as bands get smaller, but the implementor must decide
+ * on the tradeoff point.
+ *
+ * The moral of the story is that you should never make a band
+ * so small that its buffer limits the command buffer excessively.
+ * Again, Max image row bytes = band buffer size - # bands * 72.
+ *
+ * In the overlapped case, everything is exactly as above, except
+ * that two identical devices, each with an identical buffer, are
+ * allocated: one for the writer, and one for the rasterizer. Because
+ * it's critical to allocate identical buffers, I *strongly* recommend
+ * setting these params in the writer's open routine:
+ * space_params.band.BandBufferSpace, .BandWidth and .BandHeight.
+ * If you don't force these values to a known value, the memory
+ * allocation heuristic may not come to the same result for both
+ * copies of the device, since the first allocation will diminish
+ * the amount of free memory.
+ *
+ * There is room for an important optimization here: allocate the
+ * writer's space with enough memory for a generous command buffer,
+ * but allocate the reader with only enough memory for a band
+ * rasterization buffer and the tile cache. To do this, observe that
+ * the space_params struct has two sizes: BufferSpace vs. BandBufferSpace.
+ * To start, BandBufferSpace is always <= BufferSpace. On the reader side,
+ * BandBufferSpace is divided between the tile cache and the rendering
+ * buffer -- that's all the memory that's needed to rasterize. On the
+ * writer's side, BandBufferSpace is divided the same way:
+ * the tile cache (which must be identical to the reader's) is carved out,
+ * and the space that would have been used for a rasterizing buffer is
+ * used as a command buffer. However, you can further increase the cmd buf
+ * further by setting BufferSize (not BandBufferSize) to a higher number
+ * than BandBufferSize. In that case, the command buffer is increased by
+ * the difference (BufferSize - BandBufferSize). There is logic in
+ * the memory allocation for printers that will automatically use BufferSize
+ * for writers (or non-async printers), and BandBufferSize for readers.
+ *
+ * Note: per the comments in gxclmem.c, the banding logic will perform
+ * better with 1MB or better for the command list.
+ */
+
+ /* This will give us a very "ungenerous" buffer. */
+ /* Here, my arbitrary rule for min image row is: twice the dest width */
+ /* in full RGB. */
+ int render_space;
+ int writer_space;
+ const int tile_cache_space = 50 * 1024;
+ const int min_image_rows = 2;
+ int min_row_space
+ = min_image_rows * ( 3 * ( pdev->width + sizeof(int) - 1 ) );
+ int min_band_count = max(1, pdev->height / 100); /* make bands >= 1% of total */
+ space_params->band.BandWidth = pdev->width;
+ space_params->band.BandHeight
+ = (pdev->height + min_band_count - 1) / min_band_count;
+
+ render_space = gdev_mem_data_size( (gx_device_memory *)pdev,
+ space_params->band.BandWidth,
+ space_params->band.BandHeight );
+ /* need to include minimal writer requirements to satisfy rasterizer init */
+ writer_space = /* add 5K slop for good measure */
+ 5000 + (72 + 8) * ( (pdev->height / space_params->band.BandHeight) + 1 );
+ space_params->band.BandBufferSpace
+ = max(render_space, writer_space) + tile_cache_space;
+ space_params->BufferSpace
+ = max(render_space, writer_space + min_row_space) + tile_cache_space;
+}
+
+/* Set device parameters. */
+/* IMPORTANT: async drivers must NOT CLOSE the device while doing set_params.*/
+/* IMPORTANT: async drivers must NOT CLOSE the device while doing set_params.*/
+/* IMPORTANT: async drivers must NOT CLOSE the device while doing set_params.*/
+/* IMPORTANT: async drivers must NOT CLOSE the device while doing set_params.*/
+private int
+bmp_put_params(gx_device *pdev, gs_param_list *plist)
+{
+ /* This driver does nothing interesting except cascade down to */
+ /* gdev_prn_put_params, which is something it would have to do */
+ /* even if it did do something interesting here. */
+ return gdev_prn_put_params(pdev, plist);
+}
+
+/* Get hardware-detected parameters. */
+/* This proc defines a only one param: a useless value for testing */
+int
+bmp_get_hardware_params(gx_device *dev, gs_param_list *plist)
+{ static char *test_value = "Test value";
+ static char *test_name = "TestValue";
+ int code = 0;
+
+ if ( param_requested(plist, test_name) )
+ { gs_param_string param_str;
+ param_string_from_string(param_str, test_value); /* value must be persistent to use this macro */
+ code = param_write_string(plist, test_name, &param_str);
+ }
+ return code;
+}
+
+/* ---------- Utility procedures ---------- */
+
+/* Write out page's header in BMP format. */
+/* This routine is used for all formats. */
+private int
+write_bmp_header(gx_device_async *prdev, FILE *file)
+{ int raster = gdev_prn_raster( (gx_device_printer *)prdev );
+ /* BMP scan lines are padded to 32 bits. */
+ ulong bmp_raster = raster + (-raster & 3);
+ int height = prdev->height;
+ int depth = prdev->color_info.depth;
+ int quads = (depth <= 8 ? sizeof(bmp_quad) << depth : 0);
+ int y;
+ int code = 0; /* return code */
+
+ /* Write the file header. */
+
+ fputc('B', file);
+ fputc('M', file);
+ { bmp_file_header fhdr;
+ assign_dword(fhdr.size,
+ sizeof_bmp_file_header +
+ sizeof(bmp_info_header) + quads +
+ bmp_raster * height);
+ assign_word(fhdr.reserved1, 0);
+ assign_word(fhdr.reserved2, 0);
+ assign_dword(fhdr.offBits,
+ sizeof_bmp_file_header +
+ sizeof(bmp_info_header) + quads);
+ if ( fwrite((const char *)&fhdr, 1, sizeof(fhdr), file) != sizeof(fhdr) )
+ { code = gs_error_ioerror;
+ goto bmp_done;
+ }
+ }
+
+ /* Write the info header. */
+
+ { bmp_info_header ihdr;
+ assign_dword(ihdr.size, sizeof(ihdr));
+ assign_dword(ihdr.width, prdev->width);
+ assign_dword(ihdr.height, height);
+ assign_word(ihdr.planes, 1);
+ assign_word(ihdr.bitCount, depth);
+ assign_dword(ihdr.compression, 0);
+ assign_dword(ihdr.sizeImage, bmp_raster * height);
+ /* Even though we could compute the resolution correctly, */
+ /* the convention seems to be to leave it unspecified. */
+ assign_dword(ihdr.xPelsPerMeter, 0);
+ /*(dword)(prdev->x_pixels_per_inch * (1000.0 / 30.48)));*/
+ assign_dword(ihdr.yPelsPerMeter, 0);
+ /*(dword)(prdev->y_pixels_per_inch * (1000.0 / 30.48)));*/
+ assign_dword(ihdr.clrUsed, 0);
+ assign_dword(ihdr.clrImportant, 0);
+ if ( fwrite((const char *)&ihdr, 1, sizeof(ihdr), file) != sizeof(ihdr) )
+ { code = gs_error_ioerror;
+ goto bmp_done;
+ }
+ }
+
+ /* Write the palette. */
+
+ if ( depth <= 8 )
+ { int i;
+ gx_color_value rgb[3];
+ bmp_quad q;
+ q.reserved = 0;
+ for ( i = 0; i != 1 << depth; i++ )
+ { (*dev_proc(prdev, map_color_rgb))((gx_device *)prdev,
+ (gx_color_index)i, rgb);
+ q.red = gx_color_value_to_byte(rgb[0]);
+ q.green = gx_color_value_to_byte(rgb[1]);
+ q.blue = gx_color_value_to_byte(rgb[2]);
+ fwrite((const char *)&q, sizeof(q), 1, file);
+ }
+ }
+
+ /* Save the file offset where data begins */
+ if ( ( prdev->file_offset_to_data = ftell(file) ) == -1L )
+ { code = gs_error_ioerror;
+ goto bmp_done;
+ }
+
+bmp_done:
+ return code;
+}
+
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that Windows expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+map_16m_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return gx_color_value_to_byte(r) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(b) << 16);
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+map_16m_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ prgb[2] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color & 0xff);
+ return 0;
+}
diff --git a/gs/src/gdevbbox.c b/gs/src/gdevbbox.c
new file mode 100644
index 000000000..92cc258ec
--- /dev/null
+++ b/gs/src/gdevbbox.c
@@ -0,0 +1,759 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbbox.c */
+/* Device for tracking bounding box */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gsdevice.h" /* requires gsmatrix.h */
+#include "gdevbbox.h"
+#include "gxistate.h"
+#include "gxpaint.h"
+#include "gxpath.h"
+#include "gxcpath.h"
+
+/* Define TEST to create an output_page procedure for testing. */
+/*#define TEST*/
+
+/* GC descriptor */
+public_st_device_bbox();
+
+/* Device procedures */
+private dev_proc_open_device(bbox_open_device);
+private dev_proc_close_device(gx_forward_close_device); /* see below */
+private dev_proc_output_page(bbox_output_page);
+private dev_proc_fill_rectangle(bbox_fill_rectangle);
+private dev_proc_copy_mono(bbox_copy_mono);
+private dev_proc_copy_color(bbox_copy_color);
+private dev_proc_draw_line(bbox_draw_line);
+private dev_proc_get_params(bbox_get_params);
+private dev_proc_put_params(bbox_put_params);
+private dev_proc_copy_alpha(bbox_copy_alpha);
+private dev_proc_fill_path(bbox_fill_path);
+private dev_proc_stroke_path(bbox_stroke_path);
+private dev_proc_fill_mask(bbox_fill_mask);
+private dev_proc_fill_trapezoid(bbox_fill_trapezoid);
+private dev_proc_fill_parallelogram(bbox_fill_parallelogram);
+private dev_proc_fill_triangle(bbox_fill_triangle);
+private dev_proc_draw_thin_line(bbox_draw_thin_line);
+private dev_proc_begin_image(bbox_begin_image);
+private dev_proc_image_data(bbox_image_data);
+private dev_proc_end_image(bbox_end_image);
+private dev_proc_strip_tile_rectangle(bbox_strip_tile_rectangle);
+private dev_proc_strip_copy_rop(bbox_strip_copy_rop);
+
+/* The device prototype */
+#ifndef TEST
+private const
+#endif
+/*
+ * The bbox device sets the resolution to some value R (currently 4000), and
+ * the page size in device pixels to slightly smaller than the largest
+ * representable values (around 500K), leaving a little room for stroke
+ * widths, rounding, etc. If an input file (or the command line) resets the
+ * resolution to a value R' > R, the page size in pixels will get multiplied
+ * by R'/R, and will thereby exceed the representable range, causing a
+ * limitcheck. That is why the bbox device must set the resolution to a
+ * value larger than that of any real device. A consequence of this is that
+ * the page size in inches is limited to the maximum representable pixel
+ * size divided by R, which gives a limit of about 120" in each dimension.
+ */
+#define max_coord (min(max_int, fixed2int(max_fixed)) - 1000)
+#define max_resolution 4000
+gx_device_bbox far_data gs_bbox_device = {
+ std_device_std_body(gx_device_bbox, 0, "bbox",
+ max_coord, max_coord,
+ max_resolution, max_resolution),
+ { bbox_open_device,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ bbox_output_page,
+ gx_forward_close_device,
+ NULL, /* map_rgb_color */
+ NULL, /* map_color_rgb */
+ bbox_fill_rectangle,
+ NULL, /* tile_rectangle */
+ bbox_copy_mono,
+ bbox_copy_color,
+ bbox_draw_line,
+ NULL, /* get_bits */
+ bbox_get_params,
+ bbox_put_params,
+ NULL, /* map_cmyk_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device,
+ NULL, /* get_alpha_bits */
+ bbox_copy_alpha,
+ NULL, /* get_band */
+ NULL, /* copy_rop */
+ bbox_fill_path,
+ bbox_stroke_path,
+ bbox_fill_mask,
+ bbox_fill_trapezoid,
+ bbox_fill_parallelogram,
+ bbox_fill_triangle,
+ bbox_draw_thin_line,
+ bbox_begin_image,
+ bbox_image_data,
+ bbox_end_image,
+ bbox_strip_tile_rectangle,
+ bbox_strip_copy_rop,
+ NULL, /* get_clipping_box */
+ NULL /* get_hardware_params */
+ },
+ 0 /* target */
+};
+#undef max_coord
+#undef max_resolution
+
+/* Copy device parameters back from the target. */
+private void
+bbox_copy_params(gx_device_bbox *bdev)
+{ gx_device *tdev = bdev->target;
+ if ( tdev != 0 )
+ { /* This is kind of scatter-shot.... */
+#define copy_param(p) bdev->p = tdev->p
+#define copy_array_param(p) memcpy(bdev->p, tdev->p, sizeof(bdev->p))
+ copy_param(width);
+ copy_param(height);
+ copy_array_param(MediaSize);
+ copy_array_param(ImagingBBox);
+ copy_param(ImagingBBox_set);
+ copy_array_param(HWResolution);
+ copy_array_param(MarginsHWResolution);
+ copy_array_param(Margins);
+ copy_array_param(HWMargins);
+ copy_param(color_info);
+#undef copy_param
+#undef copy_array_param
+ }
+ if ( dev_proc(bdev, map_rgb_color) != 0 )
+ bdev->white =
+ (*dev_proc(bdev, map_rgb_color))
+ ((gx_device *)bdev, gx_max_color_value, gx_max_color_value,
+ gx_max_color_value);
+}
+
+#define bdev ((gx_device_bbox *)dev)
+
+#define gx_dc_is_white(pdevc, bdev)\
+ (gx_dc_is_pure(pdevc) && gx_dc_pure_color(pdevc) == (bdev)->white)
+
+/* Note that some of the "forward" procedures don't exist. */
+/* We open-code all but this one below. */
+private int
+gx_forward_close_device(gx_device *dev)
+{ gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 : (*dev_proc(tdev, close_device))(tdev));
+}
+
+/* Bounding box utilities */
+
+private void near
+bbox_initialize(gs_fixed_rect *pr)
+{ pr->p.x = pr->p.y = max_fixed;
+ pr->q.x = pr->q.y = min_fixed;
+}
+
+private void near
+bbox_add_rect(gs_fixed_rect *pr, fixed x0, fixed y0, fixed x1, fixed y1)
+{ if ( x0 < pr->p.x )
+ pr->p.x = x0;
+ if ( y0 < pr->p.y )
+ pr->p.y = y0;
+ if ( x1 > pr->q.x )
+ pr->q.x = x1;
+ if ( y1 > pr->q.y )
+ pr->q.y = y1;
+}
+private void near
+bbox_add_point(gs_fixed_rect *pr, fixed x, fixed y)
+{ bbox_add_rect(pr, x, y, x, y);
+}
+private void near
+bbox_add_int_rect(gs_fixed_rect *pr, int x0, int y0, int x1, int y1)
+{ bbox_add_rect(pr, int2fixed(x0), int2fixed(y0), int2fixed(x1),
+ int2fixed(y1));
+}
+
+#define rect_is_page(dev, x, y, w, h)\
+ (x <= 0 && y <= 0 && w >= x + dev->width && h >= y + dev->height)
+
+/* ---------------- Open/close/page ---------------- */
+
+/* Initialize a bounding box device. */
+void
+gx_device_bbox_init(gx_device_bbox *dev, gx_device *target)
+{ *dev = gs_bbox_device;
+ gx_device_forward_fill_in_procs((gx_device_forward *)dev);
+ bdev->target = target;
+ bbox_copy_params(dev);
+}
+
+/* Read back the bounding box in 1/72" units. */
+void
+gx_device_bbox_bbox(gx_device_bbox *dev, gs_rect *pbbox)
+{ gs_matrix mat;
+ gs_rect dbox;
+
+ gs_deviceinitialmatrix((gx_device *)dev, &mat);
+ dbox.p.x = fixed2float(bdev->bbox.p.x);
+ dbox.p.y = fixed2float(bdev->bbox.p.y);
+ dbox.q.x = fixed2float(bdev->bbox.q.x);
+ dbox.q.y = fixed2float(bdev->bbox.q.y);
+ gs_bbox_transform_inverse(&dbox, &mat, pbbox);
+}
+
+
+private int
+bbox_open_device(gx_device *dev)
+{ bbox_initialize(&bdev->bbox);
+#ifdef TEST
+ gx_device_forward_fill_in_procs((gx_device_forward *)dev);
+#endif
+ /* gx_forward_open_device doesn't exist */
+ { gx_device *tdev = bdev->target;
+ int code = (tdev == 0 ? 0 : (*dev_proc(tdev, open_device))(tdev));
+ bbox_copy_params(bdev);
+ return code;
+ }
+}
+
+private int
+bbox_output_page(gx_device *dev, int num_copies, int flush)
+{
+#ifdef TEST
+ gs_rect bbox;
+
+ /* Print the page bounding box. */
+ gx_device_bbox_bbox((gx_device_bbox *)dev, &bbox);
+ dprintf2("[gdevbbox] lower left = %f %f\n", bbox.p.x, bbox.p.y);
+ dprintf2("[gdevbbox] upper right = %f %f\n", bbox.q.x, bbox.q.y);
+#endif
+ /* Propagate the PageCount to the target, */
+ /* since it changes every time gs_output_page is called. */
+ if ( bdev->target )
+ bdev->target->PageCount = dev->PageCount;
+ return gx_forward_output_page(dev, num_copies, flush);
+}
+
+/* ---------------- Low-level drawing ---------------- */
+
+private int
+bbox_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ /* Check for erasing the entire page. */
+ if ( rect_is_page(dev, x, y, w, h) )
+ bbox_initialize(&bdev->bbox);
+ else if ( color != bdev->white )
+ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* gx_forward_fill_rectangle doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_rectangle))(tdev, x, y, w, h, color));
+ }
+}
+
+private int
+bbox_copy_mono(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ if ( (one != gx_no_color_index && one != bdev->white) ||
+ (zero != gx_no_color_index && zero != bdev->white)
+ )
+ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* gx_forward_copy_mono doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, copy_mono))(tdev, data, dx, raster, id,
+ x, y, w, h, zero, one));
+ }
+}
+
+private int
+bbox_copy_color(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h)
+{ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* gx_forward_copy_color doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, copy_color))(tdev, data, dx, raster, id,
+ x, y, w, h));
+ }
+}
+
+private int
+bbox_draw_line(gx_device *dev,
+ int x0, int y0, int x1, int y1, gx_color_index color)
+{ int xp, yp, xq, yq;
+ if ( x0 < x1 )
+ xp = x0, xq = x1 + 1;
+ else
+ xp = x1, xq = x0 + 1;
+ if ( y0 < y1 )
+ yp = y0, yq = y1 + 1;
+ else
+ yp = y1, yq = y0 + 1;
+ if ( color != bdev->white )
+ bbox_add_int_rect(&bdev->bbox, xp, yp, xq, yq);
+ /* gx_forward_draw_line doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, draw_line))(tdev, x0, y0, x1, y1, color));
+ }
+}
+
+private int
+bbox_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* gx_forward_copy_alpha doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, copy_alpha))(tdev, data, data_x, raster, id,
+ x, y, w, h, color, depth));
+ }
+}
+
+private int
+bbox_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{ if ( rect_is_page(dev, x, y, w, h) )
+ bbox_initialize(&bdev->bbox);
+ else
+ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, strip_tile_rectangle))(tdev, tiles, x, y,
+ w, h, color0, color1, px, py));
+ }
+}
+
+private int
+bbox_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int w, int h,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ /* gx_forward_strip_copy_rop doesn't exist */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, strip_copy_rop))(tdev,
+ sdata, sourcex, sraster, id,
+ scolors, textures, tcolors,
+ x, y, w, h,
+ phase_x, phase_y, lop));
+ }
+}
+
+/* ---------------- Parameters ---------------- */
+
+/* We implement get_params to provide a way to read out the bounding box. */
+private int
+bbox_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_forward_get_params(dev, plist);
+ gs_param_float_array bba;
+ float bbox[4];
+
+ if ( code < 0 )
+ return code;
+ bbox[0] = fixed2float(bdev->bbox.p.x);
+ bbox[1] = fixed2float(bdev->bbox.p.y);
+ bbox[2] = fixed2float(bdev->bbox.q.x);
+ bbox[3] = fixed2float(bdev->bbox.q.y);
+ bba.data = bbox, bba.size = 4, bba.persistent = false;
+ return param_write_float_array(plist, "PageBoundingBox", &bba);
+}
+
+/* We implement put_params to ensure that we keep the important */
+/* device parameters up to date, and to prevent an /undefined error */
+/* from PageBoundingBox. */
+private int
+bbox_put_params(gx_device *dev, gs_param_list *plist)
+{ int code;
+ int ecode = 0;
+ gs_param_name param_name;
+ gs_param_float_array bba;
+
+ code = param_read_float_array(plist, (param_name = "PageBoundingBox"),
+ &bba);
+ switch ( code )
+ {
+ case 0:
+ if ( bba.size != 4 )
+ { ecode = gs_note_error(gs_error_rangecheck);
+ goto e;
+ }
+ break;
+ default:
+ ecode = code;
+e: param_signal_error(plist, param_name, ecode);
+ case 1:
+ bba.data = 0;
+ }
+
+ code = gx_forward_put_params(dev, plist);
+ if ( ecode < 0 )
+ code = ecode;
+ if ( code >= 0 && bba.data != 0 )
+ { bdev->bbox.p.x = float2fixed(bba.data[0]);
+ bdev->bbox.p.y = float2fixed(bba.data[1]);
+ bdev->bbox.q.x = float2fixed(bba.data[2]);
+ bdev->bbox.q.y = float2fixed(bba.data[3]);
+ }
+ bbox_copy_params(bdev);
+ return code;
+}
+
+/* ---------------- Polygon drawing ---------------- */
+
+private fixed
+edge_x_at_y(const gs_fixed_edge *edge, fixed y)
+{ return fixed_mult_quo(edge->end.x - edge->start.x,
+ y - edge->start.y,
+ edge->end.y - edge->start.y) + edge->start.x;
+}
+private int
+bbox_fill_trapezoid(gx_device *dev,
+ const gs_fixed_edge *left, const gs_fixed_edge *right,
+ fixed ybot, fixed ytop, bool swap_axes,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ if ( !gx_dc_is_white(pdevc, bdev) )
+ { fixed x0l =
+ (left->start.y == ybot ? left->start.x :
+ edge_x_at_y(left, ybot));
+ fixed x1l =
+ (left->end.y == ytop ? left->end.x :
+ edge_x_at_y(left, ytop));
+ fixed x0r =
+ (right->start.y == ybot ? right->start.x :
+ edge_x_at_y(right, ybot));
+ fixed x1r =
+ (right->end.y == ytop ? right->end.x :
+ edge_x_at_y(right, ytop));
+ fixed xminl = min(x0l, x1l), xmaxl = max(x0l, x1l);
+ fixed xminr = min(x0r, x1r), xmaxr = max(x0r, x1r);
+ fixed x0 = min(xminl, xminr), x1 = max(xmaxl, xmaxr);
+
+ if ( swap_axes )
+ bbox_add_rect(&bdev->bbox, ybot, x0, ytop, x1);
+ else
+ bbox_add_rect(&bdev->bbox, x0, ybot, x1, ytop);
+ }
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_trapezoid))
+ (tdev, left, right, ybot, ytop, swap_axes, pdevc, lop));
+ }
+}
+
+private int
+bbox_fill_parallelogram(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ if ( !gx_dc_is_white(pdevc, bdev) )
+ { fixed pax = px + ax, pay = py + ay;
+ bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
+ bbox_add_rect(&bdev->bbox, pax, pay, pax + bx, pay + by);
+ }
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_parallelogram))(tdev, px, py, ax, ay,
+ bx, by, pdevc, lop));
+ }
+}
+
+private int
+bbox_fill_triangle(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ if ( !gx_dc_is_white(pdevc, bdev) )
+ { bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
+ bbox_add_point(&bdev->bbox, px + ax, py + ay);
+ }
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_triangle))(tdev, px, py, ax, ay,
+ bx, by, pdevc, lop));
+ }
+}
+
+private int
+bbox_draw_thin_line(gx_device *dev,
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ if ( !gx_dc_is_white(pdevc, bdev) )
+ bbox_add_rect(&bdev->bbox, fx0, fy0, fx1, fy1);
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, draw_thin_line))(tdev, fx0, fy0, fx1, fy0,
+ pdevc, lop));
+ }
+}
+
+/* ---------------- High-level drawing ---------------- */
+
+#define adjust_box(pbox, adj)\
+ ((pbox)->p.x -= (adj).x, (pbox)->p.y -= (adj).y,\
+ (pbox)->q.x += (adj).x, (pbox)->q.y += (adj).y)
+
+private int
+bbox_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
+ const gx_fill_params *params, const gx_device_color *pdevc,
+ const gx_clip_path *pcpath)
+{ gx_device *tdev = bdev->target;
+
+ if ( !gx_dc_is_white(pdevc, bdev) )
+ { gs_fixed_rect ibox;
+ gs_fixed_point adjust;
+
+ if ( gx_path_bbox(ppath, &ibox) < 0 )
+ return 0;
+ adjust = params->adjust;
+ if ( params->fill_zero_width )
+ gx_adjust_if_empty(&ibox, &adjust);
+ adjust_box(&ibox, adjust);
+ if ( pcpath != NULL &&
+ !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
+ ibox.q.x, ibox.q.y)
+ )
+ { /* Let the target do the drawing, but break down the */
+ /* fill path into pieces for computing the bounding box. */
+ bdev->target = NULL;
+ gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
+ bdev->target = tdev;
+ }
+ else
+ { /* Just use the path bounding box. */
+ bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
+ ibox.q.y);
+ }
+ }
+ /* Skip the call if there is no target. */
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_path))(tdev, pis, ppath, params, pdevc,
+ pcpath));
+}
+
+private int
+bbox_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
+ const gx_stroke_params *params,
+ const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
+{ gx_device *tdev = bdev->target;
+
+ if ( !gx_dc_is_white(pdevc, bdev) )
+ { gs_fixed_rect ibox;
+ gs_fixed_point expand;
+
+ if ( gx_path_bbox(ppath, &ibox) < 0 )
+ return 0;
+ if ( gx_stroke_path_expansion(pis, ppath, &expand) < 0 )
+ ibox.p.x = ibox.p.y = min_fixed, ibox.q.x = ibox.q.y = max_fixed;
+ else
+ adjust_box(&ibox, expand);
+ if ( pcpath != NULL &&
+ !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
+ ibox.q.x, ibox.q.y)
+ )
+ { /* Let the target do the drawing, but break down the */
+ /* fill path into pieces for computing the bounding box. */
+ bdev->target = NULL;
+ gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath);
+ bdev->target = tdev;
+ }
+ else
+ { /* Just use the path bounding box. */
+ bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
+ ibox.q.y);
+ }
+ }
+ /* Skip the call if there is no target. */
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, stroke_path))(tdev, pis, ppath, params,
+ pdevc, pcpath));
+}
+
+private int
+bbox_fill_mask(gx_device *dev,
+ const byte *data, int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ gx_device *tdev = bdev->target;
+
+ if ( pcpath != NULL &&
+ !gx_cpath_includes_rectangle(pcpath, int2fixed(x), int2fixed(y),
+ int2fixed(x + w),
+ int2fixed(y + h))
+ )
+ { /* Let the target do the drawing, but break down the */
+ /* image into pieces for computing the bounding box. */
+ bdev->target = NULL;
+ gx_default_fill_mask(dev, data, dx, raster, id, x, y, w, h,
+ pdcolor, depth, lop, pcpath);
+ bdev->target = tdev;
+ }
+ else
+ { /* Just use the mask bounding box. */
+ bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
+ }
+ /* Skip the call if there is no target. */
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, fill_mask))(tdev, data, dx, raster, id, x, y,
+ w, h, pdcolor, depth, lop, pcpath));
+}
+
+/* ------ Bitmap imaging ------ */
+
+typedef struct bbox_image_enum_s {
+ gs_memory_t *memory;
+ gs_matrix matrix; /* map from image space to device space */
+ const gx_clip_path *pcpath;
+ void *target_info;
+ int x0, x1;
+ int y, height;
+} bbox_image_enum;
+gs_private_st_ptrs2(st_bbox_image_enum, bbox_image_enum, "bbox_image_enum",
+ bbox_image_enum_enum_ptrs, bbox_image_enum_reloc_ptrs, pcpath, target_info);
+
+private int
+bbox_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *memory, void **pinfo)
+{ int code;
+ gs_matrix mat;
+ bbox_image_enum *pbe;
+
+ if ( (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0
+ )
+ return code;
+ pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum,
+ "bbox_begin_image");
+ if ( pbe == 0 )
+ return_error(gs_error_VMerror);
+ pbe->memory = memory;
+ pbe->matrix = mat;
+ pbe->pcpath = pcpath;
+ pbe->target_info = 0; /* in case no target */
+ if ( prect )
+ { pbe->x0 = prect->p.x, pbe->x1 = prect->q.x;
+ pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y;
+ }
+ else
+ { pbe->x0 = 0, pbe->x1 = pim->Width;
+ pbe->y = 0, pbe->height = pim->Height;
+ }
+ *pinfo = pbe;
+ /* Skip the call if there is no target. */
+ { gx_device *tdev = bdev->target;
+ return (tdev == 0 ? 0 :
+ (*dev_proc(tdev, begin_image))(tdev, pis, pim, format, prect,
+ pdcolor, pcpath, memory,
+ &pbe->target_info));
+ }
+}
+
+private int
+bbox_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ gx_device *tdev = bdev->target;
+ bbox_image_enum *pbe = info;
+ const gx_clip_path *pcpath = pbe->pcpath;
+ gs_rect sbox, dbox;
+ gs_point corners[4];
+ gs_fixed_rect ibox;
+
+ sbox.p.x = pbe->x0;
+ sbox.p.y = pbe->y;
+ sbox.q.x = pbe->x1;
+ sbox.q.y = pbe->y += height;
+ gs_bbox_transform_only(&sbox, &pbe->matrix, corners);
+ gs_points_bbox(corners, &dbox);
+ ibox.p.x = float2fixed(dbox.p.x);
+ ibox.p.y = float2fixed(dbox.p.y);
+ ibox.q.x = float2fixed(dbox.q.x);
+ ibox.q.y = float2fixed(dbox.q.y);
+ if ( pcpath != NULL &&
+ !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
+ ibox.q.x, ibox.q.y)
+ )
+ { /* Let the target do the drawing, but drive two triangles */
+ /* through the clipping path to get an accurate bounding box. */
+ gx_device_clip cdev;
+ gx_drawing_color devc;
+ fixed x0 = float2fixed(corners[0].x),
+ y0 = float2fixed(corners[0].y);
+ fixed bx2 = float2fixed(corners[2].x) - x0,
+ by2 = float2fixed(corners[2].y) - y0;
+
+ gx_make_clip_path_device(&cdev, pcpath);
+ cdev.target = dev;
+ (*dev_proc(&cdev, open_device))((gx_device *)&cdev);
+ color_set_pure(&devc, 0); /* any color will do */
+ bdev->target = NULL;
+ gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
+ float2fixed(corners[1].x) - x0,
+ float2fixed(corners[1].y) - y0,
+ bx2, by2, &devc, lop_default);
+ gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
+ float2fixed(corners[3].x) - x0,
+ float2fixed(corners[3].y) - y0,
+ bx2, by2, &devc, lop_default);
+ bdev->target = tdev;
+ }
+ else
+ { /* Just use the bounding box. */
+ bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
+ }
+ /* Skip the call if there is no target. */
+ return (tdev == 0 ? pbe->y >= pbe->height :
+ (*dev_proc(tdev, image_data))(tdev, pbe->target_info, planes,
+ data_x, raster, height));
+}
+
+private int
+bbox_end_image(gx_device *dev, void *info, bool draw_last)
+{ bbox_image_enum *pbe = info;
+ void *target_info = pbe->target_info;
+ /* Skip the call if there is no target. */
+ gx_device *tdev = bdev->target;
+ int code =
+ (tdev == 0 ? 0 :
+ (*dev_proc(tdev, end_image))(tdev, target_info, draw_last));
+
+ gs_free_object(pbe->memory, pbe, "bbox_end_image");
+ return code;
+}
diff --git a/gs/src/gdevbbox.h b/gs/src/gdevbbox.h
new file mode 100644
index 000000000..9dad0f3fa
--- /dev/null
+++ b/gs/src/gdevbbox.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbbox.h */
+/* Interface to bounding box device */
+/* Requires gxdevice.h */
+
+/*
+ * This device keeps track of the per-page bounding box, and also forwards
+ * all drawing commands to a target. It isn't normally a free-standing
+ * device, but it's used as a component (e.g., by the EPS writer).
+ *
+ * To set up a bounding box device that doesn't do any drawing:
+ * gx_device_bbox *bdev =
+ * gs_alloc_struct_immovable(some_memory,
+ * gx_device_bbox, &st_device_bbox,
+ * "some identifying string for debugging");
+ * gx_device_bbox_init(bdev, NULL);
+ * Non-drawing bounding box devices have an "infinite" page size.
+ *
+ * To set up a bounding box device that draws to another device tdev:
+ * gx_device_bbox *bdev =
+ * gs_alloc_struct_immovable(some_memory,
+ * gx_device_bbox, &st_device_bbox,
+ * "some identifying string for debugging");
+ * gx_device_bbox_init(bdev, tdev);
+ * Bounding box devices that draw to a real device appear to have the
+ * same page size as that device.
+ *
+ * To intercept the end-of-page to call a routine eop of your own:
+ * dev_proc_output_page(eop); -- declare a prototype for eop
+ * bdev.std_procs.output_page = eop;
+ * ...
+ * int eop(gx_device *dev, int num_copies, int flush)
+ * { gs_rect bbox;
+ * gx_device_bbox_bbox((gx_device_bbox *)dev, &bbox);
+ * << do whatever you want >>
+ * return gx_forward_output_page(dev, num_copies, flush);
+ * }
+ */
+#define gx_device_bbox_common\
+ gx_device_forward_common;\
+ /* The following are updated dynamically. */\
+ gs_fixed_rect bbox;\
+ gx_color_index white
+typedef struct gx_device_bbox_s {
+ gx_device_bbox_common;
+} gx_device_bbox;
+extern_st(st_device_bbox);
+#define public_st_device_bbox() /* in gdevbbox.c */\
+ gs_public_st_suffix_add0_final(st_device_bbox, gx_device_bbox,\
+ "gx_device_bbox", device_bbox_enum_ptrs, device_bbox_reloc_ptrs,\
+ gx_device_finalize, st_device_forward)
+
+/* Initialize a bounding box device. */
+void gx_device_bbox_init(P2(gx_device_bbox *dev, gx_device *target));
+
+/* Read back the bounding box in 1/72" units. */
+void gx_device_bbox_bbox(P2(gx_device_bbox *dev, gs_rect *pbbox));
diff --git a/gs/src/gdevbgi.c b/gs/src/gdevbgi.c
new file mode 100644
index 000000000..a9ee6df9a
--- /dev/null
+++ b/gs/src/gdevbgi.c
@@ -0,0 +1,661 @@
+/* Copyright (C) 1989, 1990, 1991, 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbgi.c */
+/* Driver for Borland Graphics Interface (BGI) */
+#include <string.h>
+#include <stdlib.h>
+#include <conio.h>
+#include <graphics.h>
+#include <mem.h>
+#include "gserrors.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxxfont.h"
+
+#ifndef BGI_LIB /* may be set in makefile */
+# define BGI_LIB ""
+#endif
+
+/*
+ * BGI supports these video cards:
+ * Hercules, CGA, MCGA, EGA, VGA, AT&T 400, IBM 8514, PC3270.
+ * Highest resolution mode is used with all these video cards.
+ * EGA and VGA display 16 colors, the rest are black-and-white only.
+ * In addition, the environment variable BGIUSER may be used
+ * to define a user-supplied Super VGA driver: see the use.doc file
+ * for details.
+ */
+#define SUPER_VGA 999 /* bogus # for user-defined driver */
+
+/* See gxdevice.h for the definitions of the procedures. */
+
+dev_proc_open_device(bgi_open);
+dev_proc_close_device(bgi_close);
+dev_proc_map_rgb_color(bgi_map_rgb_color);
+dev_proc_map_color_rgb(bgi_map_color_rgb);
+dev_proc_fill_rectangle(bgi_fill_rectangle);
+dev_proc_tile_rectangle(bgi_tile_rectangle);
+dev_proc_copy_mono(bgi_copy_mono);
+dev_proc_copy_color(bgi_copy_color);
+dev_proc_draw_line(bgi_draw_line);
+dev_proc_get_xfont_procs(bgi_get_xfont_procs);
+
+/* The device descriptor */
+typedef struct gx_device_bgi_s gx_device_bgi;
+struct gx_device_bgi_s {
+ gx_device_common;
+ int display_mode;
+ struct text_info text_mode;
+};
+#define bgi_dev ((gx_device_bgi *)dev)
+private gx_device_procs bgi_procs = {
+ bgi_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ bgi_close,
+ bgi_map_rgb_color,
+ bgi_map_color_rgb,
+ bgi_fill_rectangle,
+ bgi_tile_rectangle,
+ bgi_copy_mono,
+ bgi_copy_color,
+ bgi_draw_line,
+ NULL, /* get_bits */
+ NULL, /* get_props */
+ NULL, /* put_props */
+ NULL,
+ bgi_get_xfont_procs
+};
+gx_device_bgi far_data gs_bgi_device = {
+ std_device_std_body(gx_device_bgi, &bgi_procs, "bgi",
+ 0, 0, /* width and height are set in bgi_open */
+ 1, 1 /* density is set in bgi_open */
+ )
+};
+
+/* Detection procedure for user-defined driver. */
+private int huge
+detectVGA(void)
+{ return gs_bgi_device.display_mode;
+}
+
+/* Open the BGI driver for graphics mode */
+int
+bgi_open(gx_device *dev)
+{ int driver, mode;
+ char *bgi_user = getenv("BGIUSER");
+ char *bgi_path = getenv("BGIPATH");
+
+ gettextinfo(&bgi_dev->text_mode);
+
+ if ( bgi_path == NULL )
+ bgi_path = BGI_LIB;
+ if ( bgi_user != NULL )
+ { /* A user-supplied driver is specified as "mode.dname", */
+ /* where mode is a hex number and dname is the name */
+ /* of the driver file. */
+ char dname[40];
+ if ( strlen(bgi_user) > sizeof(dname) ||
+ sscanf(bgi_user, "%x.%s", &mode, dname) != 2
+ )
+ { eprintf("BGIUSER not in form nn.dname.\n");
+ exit(1);
+ }
+ gs_bgi_device.display_mode = mode; /* sigh.... */
+ installuserdriver(dname, detectVGA);
+ driver = DETECT;
+ initgraph(&driver, &mode, bgi_path);
+ driver = SUPER_VGA;
+ }
+ else /* not user-defined driver */
+ { /* We include the CGA driver in the executable, */
+ /* so end-users don't have to have the BGI files. */
+ if ( registerfarbgidriver(CGA_driver_far) < 0 )
+ { eprintf("BGI: Can't register CGA driver!\n");
+ exit(1);
+ }
+
+ detectgraph(&driver, &mode);
+ if ( driver < 0 )
+ { eprintf("BGI: No graphics hardware detected!\n");
+ exit(1);
+ }
+
+ if ( driver == EGA64 )
+ { /* Select 16 color video mode if video card is EGA with 64 Kb of memory */
+ mode = EGA64LO;
+ }
+
+ /* Initialize graphics mode. */
+
+ /* Following patch for AT&T 6300 is courtesy of */
+ /* Allan Wax, Xerox Corp. */
+ if ( driver == CGA )
+ { /* The actual hardware might be an AT&T 6300. */
+ /* Try initializing it that way. */
+ int save_mode = mode;
+ driver = ATT400, mode = ATT400HI;
+ initgraph(&driver, &mode, bgi_path);
+ if ( graphresult() != grOk )
+ { /* Nope, it was a real CGA. */
+ closegraph();
+ driver = CGA, mode = save_mode;
+ initgraph(&driver, &mode, bgi_path);
+ }
+ }
+ else
+ initgraph(&driver, &mode, bgi_path);
+ }
+
+ { int code = graphresult();
+ if ( code != grOk )
+ { eprintf1("Error initializing BGI driver: %s\n",
+ grapherrormsg(code));
+ exit(1);
+ }
+ }
+
+ setactivepage(1);
+ setvisualpage(1);
+ /* Set parameters that were unknown before opening device */
+
+ /* Size and nominal density of screen. */
+ /* The following algorithm maps an appropriate fraction of */
+ /* the display screen to an 8.5" x 11" coordinate space. */
+ /* This may or may not be what is desired! */
+ if ( dev->width == 0 )
+ dev->width = getmaxx() + 1;
+ if ( dev->height == 0 )
+ dev->height = getmaxy() + 1;
+ if ( dev->y_pixels_per_inch == 1 )
+ { /* Get the aspect ratio from the driver. */
+ int arx, ary;
+ getaspectratio(&arx, &ary);
+ dev->y_pixels_per_inch = dev->height / 11.0;
+ dev->x_pixels_per_inch =
+ dev->y_pixels_per_inch * ((float)ary / arx);
+ }
+
+ /* Find out if the device supports color */
+ /* (default initialization is monochrome). */
+ /* We only recognize 16-color devices right now. */
+ if ( getmaxcolor() > 1 )
+ { static gx_device_color_info bgi_16color = dci_color(4, 2, 3);
+ dev->color_info = bgi_16color;
+ }
+ return 0;
+}
+
+/* Close the BGI driver */
+int
+bgi_close(gx_device *dev)
+{ closegraph();
+ textmode(bgi_dev->text_mode.currmode);
+ return 0;
+}
+
+/* Map a r-g-b color to the 16 colors available with an EGA/VGA video card. */
+gx_color_index
+bgi_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return (gx_color_index)
+ ((r > gx_max_color_value / 4 ? 4 : 0) +
+ (g > gx_max_color_value / 4 ? 2 : 0) +
+ (b > gx_max_color_value / 4 ? 1 : 0) +
+ (r > gx_max_color_value / 4 * 3 ||
+ g > gx_max_color_value / 4 * 3 ? 8 : 0));
+}
+
+/* Map a color code to r-g-b. Surprisingly enough, this is algorithmic. */
+int
+bgi_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+#define icolor (int)color
+ gx_color_value one =
+ (icolor & 8 ? gx_max_color_value : gx_max_color_value / 3);
+ prgb[0] = (icolor & 4 ? one : 0);
+ prgb[1] = (icolor & 2 ? one : 0);
+ prgb[2] = (icolor & 1 ? one : 0);
+ return 0;
+#undef icolor
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+int
+bgi_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ const byte *ptr_line = base + (sourcex >> 3);
+ int left_bit = 0x80 >> (sourcex & 7);
+ int dest_y = y, end_x = x + w;
+ int invert = 0;
+ int color;
+
+ if ( zero == gx_no_color_index )
+ { if ( one == gx_no_color_index ) return 0;
+ color = (int)one;
+ }
+ else
+ { if ( one == gx_no_color_index )
+ { color = (int)zero;
+ invert = -1;
+ }
+ else
+ { /* Pre-clear the rectangle to zero */
+ setfillstyle(SOLID_FILL, (int)zero);
+ bar(x, y, x + w - 1, y + h - 1);
+ color = (int)one;
+ }
+ }
+
+ while ( h-- ) /* for each line */
+ { const byte *ptr_source = ptr_line;
+ register int dest_x = x;
+ register int bit = left_bit;
+ while ( dest_x < end_x ) /* for each bit in the line */
+ { if ( (*ptr_source ^ invert) & bit )
+ putpixel(dest_x, dest_y, color);
+ dest_x++;
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, ptr_source++;
+ }
+ dest_y++;
+ ptr_line += raster;
+ }
+ return 0;
+}
+
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 4 bits instead of 1 when device driver has color. */
+int
+bgi_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ if ( gx_device_has_color(dev) )
+ { /* color device, four bits per pixel */
+ const byte *line = base + (sourcex >> 1);
+ int dest_y = y, end_x = x + w;
+
+ if ( w <= 0 ) return 0;
+ while ( h-- ) /* for each line */
+ { const byte *source = line;
+ register int dest_x = x;
+ if ( sourcex & 1 ) /* odd nibble first */
+ { int color = *source++ & 0xf;
+ putpixel(dest_x, dest_y, color);
+ dest_x++;
+ }
+ /* Now do full bytes */
+ while ( dest_x < end_x )
+ { int color = *source >> 4;
+ putpixel(dest_x, dest_y, color);
+ dest_x++;
+ if ( dest_x < end_x )
+ { color = *source++ & 0xf;
+ putpixel(dest_x, dest_y, color);
+ dest_x++;
+ }
+ }
+ dest_y++;
+ line += raster;
+ }
+ }
+ else /* monochrome device: one bit per pixel */
+ { /* bitmap is the same as bgi_copy_mono: one bit per pixel */
+ bgi_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
+ (gx_color_index)BLACK, (gx_color_index)WHITE);
+ }
+ return 0;
+}
+
+
+/* Fill a rectangle. */
+int
+bgi_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ setfillstyle(SOLID_FILL, (int)color);
+ bar(x, y, x + w - 1, y + h - 1);
+ return 0;
+}
+
+
+/* Tile a rectangle. If neither color is transparent, */
+/* pre-clear the rectangle to color0 and just tile with color1. */
+/* This is faster because of how bgi_copy_mono is implemented. */
+/* Note that this also does the right thing for colored tiles. */
+int
+bgi_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
+ int px, int py)
+{ int tw = tile->size.x, th = tile->size.y;
+ int rw, rh, tx, ty;
+ int code;
+ byte image[4+4+256];
+ if ( w >> 1 < tw || h >> 1 < th ||
+ czero == gx_no_color_index || cone == gx_no_color_index ||
+ imagesize(x, y, x + tw - 1, y + th - 1) > sizeof(image)
+ )
+ { if ( czero != gx_no_color_index && cone != gx_no_color_index )
+ { bgi_fill_rectangle(dev, x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
+ }
+ /* Handle edge strips. We know w and h are both large. */
+ rh = h % th;
+ if ( rh )
+ { code = gx_default_tile_rectangle(dev, tile, x, y + h - rh, w, rh, czero, cone, px, py);
+ if ( code < 0 ) return code;
+ h -= rh;
+ }
+ rw = w % tw;
+ if ( rw )
+ { code = gx_default_tile_rectangle(dev, tile, x + w - rw, y, rw, h, czero, cone, px, py);
+ if ( code < 0 ) return code;
+ w -= rw;
+ }
+ /* Now w and h are multiples of tw and th respectively, */
+ /* and greater than 1. Start by doing one tile the slow way. */
+ code = gx_default_tile_rectangle(dev, tile, x, y, tw, th, czero, cone, px, py);
+ if ( code < 0 ) return code;
+ /* Now replicate the tile. */
+ getimage(x, y, x + tw - 1, y + th - 1, &image[0]);
+ for ( ty = h; (ty -= th) >= 0; )
+ { for ( tx = w; (tx -= tw) >= 0; )
+ putimage(x + tx, y + ty, &image[0], COPY_PUT);
+ }
+ return 0;
+}
+
+
+/* Draw a line */
+int
+bgi_draw_line(gx_device *dev, int x0, int y0, int x1, int y1,
+ gx_color_index color)
+{ setcolor((int)color);
+ setlinestyle(SOLID_LINE, 0, NORM_WIDTH); /* solid, one pixel wide */
+ line(x0, y0, x1, y1);
+ return 0;
+}
+
+/* ------ Platform font procedures ------ */
+
+/*
+ * Note: Stroked BGI fonts lie about their height and baseline:
+ * the textheight is actually the position of the baseline,
+ * and the only way to find the actual height is to scan the bits.
+ */
+
+/* Define xfont procedures. */
+private xfont_proc_lookup_font(bgi_lookup_font);
+private xfont_proc_char_xglyph(bgi_char_xglyph);
+private xfont_proc_char_metrics(bgi_char_metrics);
+private xfont_proc_render_char(bgi_render_char);
+private xfont_proc_release(bgi_release);
+private gx_xfont_procs bgi_xfont_procs = {
+ bgi_lookup_font,
+ bgi_char_xglyph,
+ bgi_char_metrics,
+ bgi_render_char,
+ bgi_release
+};
+
+/* Return the xfont procedure record. */
+gx_xfont_procs *
+bgi_get_xfont_procs(gx_device *dev)
+{ return &bgi_xfont_procs;
+}
+
+/* Define a BGI xfont. */
+typedef struct bgi_xfont_s {
+ gx_xfont_common common;
+ const char _ds *fname;
+ int index; /* BGI font index */
+ gs_int_point ratio; /* scaling ratio for character */
+ int base_size; /* height of 4x 'A' */
+ int baseline;
+} bgi_xfont;
+gs_private_st_simple(st_bgi_xfont, bgi_xfont, "bgi_xfont");
+
+/* Different versions of Turbo C and Borland C++ have different fonts.... */
+private bgi_xfont all_fonts[] = {
+ { { &bgi_xfont_procs}, "Courier", DEFAULT_FONT },
+#ifdef SANSSERIF_FONT
+ { { &bgi_xfont_procs}, "Helvetica", SANSSERIF_FONT },
+#else
+# ifdef SANS_SERIF_FONT
+ { { &bgi_xfont_procs}, "Helvetica", SANS_SERIF_FONT },
+# endif
+#endif
+#ifdef SIMPLEX_FONT
+ { { &bgi_xfont_procs}, "Times-Roman", SIMPLEX_FONT },
+#endif
+#ifdef BOLD_FONT
+ { { &bgi_xfont_procs}, "Times-Bold", BOLD_FONT }
+#endif
+};
+
+/* Keep a record of a character temporarily rendered to the screen. */
+typedef struct char_image_s {
+ char str[2];
+ gs_int_point size;
+ uint image_size;
+ char *image;
+} char_image;
+
+/* Forward references */
+private bgi_xfont *char_set_font(P1(gx_xfont *));
+private int char_set_image(P2(byte, char_image *));
+private void char_bbox(P3(bgi_xfont *, char_image *, gs_int_rect *));
+private void char_restore_image(P1(char_image *));
+
+/* Look up a font. */
+gx_xfont *
+bgi_lookup_font(gx_device *dev, const byte *fname, uint len,
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,
+ gs_memory_t *mem)
+{ float px, py;
+ int i;
+ if ( pmat->xy != 0 || pmat->yx != 0 || pmat->xx <= 0 || pmat->yy >= 0 )
+ return NULL; /* unsupported transformation */
+ px = pmat->xx * 1000;
+ py = pmat->yy * -1000;
+ for ( i = 0; i < countof(all_fonts); i++ )
+ { bgi_xfont *pf = &all_fonts[i];
+ if ( strlen(pf->fname) == len && !memcmp(pf->fname, fname, len) )
+ { long rx, ry;
+ bgi_xfont *spf;
+ settextstyle(pf->index, HORIZ_DIR, 1);
+ if ( pf->base_size == 0 ) /* not set yet */
+ { setusercharsize(1, 1, 1, 1);
+ pf->base_size = textheight("A");
+ }
+ rx = px * 64 / pf->base_size;
+ ry = py * 64 / pf->base_size;
+ if ( rx <= 0 || ry <= 0 )
+ return NULL;
+ spf = gs_alloc_struct(mem, bgi_xfont,
+ &st_bgi_xfont, "bgi_lookup_font");
+ if ( spf == 0 )
+ return NULL;
+ *spf = *pf;
+ spf->ratio.x = rx;
+ spf->ratio.y = ry;
+ char_set_font((gx_xfont *)spf);
+ spf->baseline = textheight("A"); /* (see above) */
+ return (gx_xfont *)spf;
+ }
+ }
+ return NULL; /* unsupported font name */
+}
+
+/* Convert a character name or index to an xglyph code. */
+gx_xglyph
+bgi_char_xglyph(gx_xfont *xf, gs_char chr, int encoding_index,
+ gs_glyph glyph, gs_proc_glyph_name_t glyph_name_proc)
+{ if ( (encoding_index & ~1) != 0 || /* Standard & ISOLatin1 only */
+ chr < 32 || chr > 126 /* ASCII only */
+ )
+ return gx_no_xglyph;
+ return chr;
+}
+
+/* Get the metrics for a character. */
+int
+bgi_char_metrics(gx_xfont *xf, gx_xglyph xg, int wmode,
+ gs_point *pwidth, gs_int_rect *pbbox)
+{ bgi_xfont *pf = char_set_font(xf);
+ char_image ci;
+ if ( wmode != 0 )
+ return gs_error_undefined;
+ if ( char_set_image((byte)xg, &ci) < 0 )
+ return gs_error_ioerror;
+ char_bbox(pf, &ci, pbbox);
+ pwidth->x = textwidth(ci.str);
+ pwidth->y = 0;
+ if ( pwidth->x == pbbox->q.x && pbbox->p.x == 0 )
+ { /* This is a badly designed font with no inter-character */
+ /* spacing. Add 1 pixel. */
+ pwidth->x++;
+ }
+ char_restore_image(&ci);
+ return 0;
+}
+
+/* Render a character. */
+int
+bgi_render_char(gx_xfont *xf, gx_xglyph xg, gx_device *target,
+ int xo, int yo, gx_color_index color, int required)
+{ bgi_xfont *pf = char_set_font(xf);
+ char_image ci;
+ gs_int_rect bbox;
+ int xi, yi;
+ if ( target->dname == gs_bgi_device.dname )
+ { /* Write directly to a BGI device. */
+ ci.str[0] = (char)xg;
+ ci.str[1] = 0;
+ setcolor((int)color);
+ outtextxy(xo, yo - pf->baseline, ci.str);
+ return 0;
+ }
+ if ( !required )
+ return gs_error_ioerror; /* any error will do */
+ if ( char_set_image((byte)xg, &ci) < 0 )
+ return gs_error_ioerror;
+ char_bbox(pf, &ci, &bbox);
+ for ( yi = bbox.p.y; yi < bbox.q.y; yi++ )
+ { for ( xi = bbox.p.x; xi < bbox.q.x; xi++ )
+ if ( getpixel(xi, yi + pf->baseline) != WHITE )
+ { (*dev_proc(target, fill_rectangle))(target,
+ xi + xo, yi + yo, 1, 1, color);
+ }
+ }
+ char_restore_image(&ci);
+ return 0;
+}
+
+/* Release an xfont. */
+private int
+bgi_release(gx_xfont *xf, gs_memory_t *mem)
+{ if ( mem != NULL )
+ gs_free_object(mem, xf, "bgi_release");
+ return 0;
+}
+
+/* ------ Font utilities ------ */
+
+/* Set up a font. */
+private bgi_xfont *
+char_set_font(gx_xfont *xf)
+{ bgi_xfont *pf = (bgi_xfont *)xf;
+ settextstyle(pf->index, HORIZ_DIR, 0);
+ setusercharsize(pf->ratio.x, 64, pf->ratio.y, 64);
+ return pf;
+}
+
+/* Write a character onto the screen. */
+private int
+char_set_image(byte ch, char_image *pci)
+{ char *str = pci->str;
+ int w, h;
+ uint size;
+ char *image;
+ str[0] = ch;
+ str[1] = 0;
+ w = textwidth(str);
+ h = textheight(str) << 1; /* (see above) */
+ if ( w != 0 && h != 0 )
+ { size = imagesize(0, 0, w - 1, h - 1);
+ image = malloc(size);
+ if ( image == 0 ) return -1; /* allocation failed */
+ getimage(0, 0, w - 1, h - 1, image);
+ setfillstyle(SOLID_FILL, WHITE);
+ bar(0, 0, w - 1, h - 1); /* clear */
+ setcolor(BLACK);
+ outtextxy(0, 0, str);
+ }
+ else
+ { size = 0;
+ image = 0;
+ }
+ pci->size.x = w;
+ pci->size.y = h;
+ pci->image_size = size;
+ pci->image = image;
+ return 0;
+}
+
+/* Find the bounding box of a character. */
+/* The character is already on the screen. */
+private void
+char_bbox(bgi_xfont *pf, char_image *pci, gs_int_rect *pbbox)
+{ int x0 = pci->size.x, y0 = pci->size.y, x1 = -1, y1 = 0;
+ int x, y;
+ int base = pf->baseline;
+ for ( y = pci->size.y; --y >= 0; )
+ for ( x = pci->size.x; --x >= 0; )
+ if ( getpixel(x, y) != WHITE )
+ { if ( x < x0 ) x0 = x;
+ if ( x > x1 ) x1 = x;
+ if ( y < y0 ) y0 = y;
+ if ( y > y1 ) y1 = y;
+ }
+ if ( x0 > x1 ) /* blank */
+ pbbox->p.x = pbbox->q.x = pbbox->p.y = pbbox->q.y = 0;
+ else
+ { pbbox->p.x = x0;
+ pbbox->p.y = y0 - base;
+ pbbox->q.x = x1 + 1;
+ pbbox->q.y = y1 + 1 - base;
+ }
+}
+
+/* Restore the image under the character. */
+private void
+char_restore_image(char_image *pci)
+{ if ( pci->image != 0 ) /* might have been empty */
+ { putimage(0, 0, pci->image, COPY_PUT);
+ free(pci->image);
+ }
+}
diff --git a/gs/src/gdevbit.c b/gs/src/gdevbit.c
new file mode 100644
index 000000000..723d7222e
--- /dev/null
+++ b/gs/src/gdevbit.c
@@ -0,0 +1,341 @@
+/* Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbit.c */
+/* "Plain bits" devices to measure rendering time. */
+#include "gdevprn.h"
+#include "gsparam.h"
+#include "gxlum.h"
+
+/*
+ * When debugging problems on large CMYK devices, we have to be able to
+ * modify the output at this stage. These parameters are not set in any
+ * normal configuration.
+ */
+/* Define whether to trim off top and bottom white space. */
+/*#define TRIM_TOP_BOTTOM*/
+/* Define left and right trimming margins. */
+/* Note that this is only approximate: we trim to byte boundaries. */
+/*#define TRIM_LEFT 400*/
+/*#define TRIM_RIGHT 400*/
+/* Define whether to expand each bit to a byte. */
+/* Also convert black-and-white to proper gray (inverting if monobit). */
+/*#define EXPAND_BITS_TO_BYTES*/
+
+/* Define the device parameters. */
+#ifndef X_DPI
+# define X_DPI 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+/* The device descriptor */
+private dev_proc_map_rgb_color(bit_mono_map_rgb_color);
+private dev_proc_map_rgb_color(bit_map_rgb_color);
+private dev_proc_map_color_rgb(bit_map_color_rgb);
+private dev_proc_map_cmyk_color(bit_map_cmyk_color);
+private dev_proc_put_params(bit_put_params);
+private dev_proc_print_page(bit_print_page);
+#define bit_procs(map_rgb_color, map_cmyk_color)\
+{ gdev_prn_open,\
+ gx_default_get_initial_matrix,\
+ NULL, /* sync_output */\
+ gdev_prn_output_page,\
+ gdev_prn_close,\
+ map_rgb_color,\
+ bit_map_color_rgb,\
+ NULL, /* fill_rectangle */\
+ NULL, /* tile_rectangle */\
+ NULL, /* copy_mono */\
+ NULL, /* copy_color */\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ gdev_prn_get_params,\
+ bit_put_params,\
+ map_cmyk_color,\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ gx_page_device_get_page_device /* get_page_device */\
+}
+
+private gx_device_procs bitmono_procs =
+ bit_procs(bit_mono_map_rgb_color, NULL);
+gx_device_printer far_data gs_bit_device =
+{ prn_device_body(gx_device_printer, bitmono_procs, "bit",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1,1,1,0,2,1, bit_print_page)
+};
+
+private gx_device_procs bitrgb_procs =
+ bit_procs(bit_map_rgb_color, NULL);
+gx_device_printer far_data gs_bitrgb_device =
+{ prn_device_body(gx_device_printer, bitrgb_procs, "bitrgb",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 3,4,1,1,2,2, bit_print_page)
+};
+
+private gx_device_procs bitcmyk_procs =
+ bit_procs(NULL, bit_map_cmyk_color);
+gx_device_printer far_data gs_bitcmyk_device =
+{ prn_device_body(gx_device_printer, bitcmyk_procs, "bitcmyk",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 4,4,1,1,2,2, bit_print_page)
+};
+
+/* Map gray to color. */
+/* Note that 1-bit monochrome is a special case. */
+private gx_color_index
+bit_mono_map_rgb_color(gx_device *dev, gx_color_value red,
+ gx_color_value green, gx_color_value blue)
+{ int bpc = dev->color_info.depth;
+ int drop = sizeof(gx_color_value) * 8 - bpc;
+ gx_color_value gray =
+ (red * (unsigned long)lum_red_weight +
+ green * (unsigned long)lum_green_weight +
+ blue * (unsigned long)lum_blue_weight +
+ (lum_all_weights / 2))
+ / lum_all_weights;
+ return (bpc == 1 ? gx_max_color_value - gray : gray) >> drop;
+}
+
+/* Map RGB to color. */
+private gx_color_index
+bit_map_rgb_color(gx_device *dev, gx_color_value red,
+ gx_color_value green, gx_color_value blue)
+{ int bpc = dev->color_info.depth / 3;
+ int drop = sizeof(gx_color_value) * 8 - bpc;
+ return ((((red >> drop) << bpc) + (green >> drop)) << bpc) +
+ (blue >> drop);
+}
+
+/* Map color to RGB. This has 3 separate cases, but since it is rarely */
+/* used, we do a case test rather than providing 3 separate routines. */
+private int
+bit_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3])
+{ int depth = dev->color_info.depth;
+ int ncomp = dev->color_info.num_components;
+ int bpc = depth / ncomp;
+ uint mask = (1 << bpc) - 1;
+#define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
+
+ switch ( ncomp )
+ {
+ case 1: /* gray */
+ rgb[0] = rgb[1] = rgb[2] =
+ (depth == 1 ? (color ? 0 : gx_max_color_value) :
+ cvalue(color));
+ break;
+ case 3: /* RGB */
+ { gx_color_index cshift = color;
+ rgb[2] = cvalue(cshift & mask); cshift >>= bpc;
+ rgb[1] = cvalue(cshift & mask);
+ rgb[0] = cvalue(cshift >> bpc);
+ }
+ break;
+ case 4: /* CMYK */
+ /* Map CMYK back to RGB. */
+ { gx_color_index cshift = color;
+ uint c, m, y, k;
+
+ k = cshift & mask; cshift >>= bpc;
+ y = cshift & mask; cshift >>= bpc;
+ m = cshift & mask;
+ c = cshift >> bpc;
+ /* We use our improved conversion rule.... */
+ rgb[0] = cvalue((mask - c) * (mask - k) / mask);
+ rgb[1] = cvalue((mask - m) * (mask - k) / mask);
+ rgb[2] = cvalue((mask - y) * (mask - k) / mask);
+ }
+ break;
+ }
+ return 0;
+#undef cvalue
+}
+
+/* Map CMYK to color. */
+private gx_color_index
+bit_map_cmyk_color(gx_device *dev, gx_color_value cyan,
+ gx_color_value magenta, gx_color_value yellow, gx_color_value black)
+{ int bpc = dev->color_info.depth / 4;
+ int drop = sizeof(gx_color_value) * 8 - bpc;
+ gx_color_index color =
+ ((((((cyan >> drop) << bpc) +
+ (magenta >> drop)) << bpc) +
+ (yellow >> drop)) << bpc) +
+ (black >> drop);
+
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/* Set parameters. We allow setting the number of bits per component. */
+private int
+bit_put_params(gx_device *pdev, gs_param_list *plist)
+{ gx_device_color_info save_info;
+ int ncomps = pdev->color_info.num_components;
+ int bpc = pdev->color_info.depth / ncomps;
+ int v;
+ int ecode = 0;
+ int code;
+ static const byte depths[4][8] = {
+ { 1, 2, 0, 4, 8, 0, 0, 8 },
+ { 0 },
+ { 4, 8, 0, 16, 16, 0, 0, 24 },
+ { 4, 8, 0, 16, 32, 0, 0, 32 }
+ };
+ const char _ds *vname;
+
+ if ( (code = param_read_int(plist, (vname = "GrayValues"), &v)) != 1 ||
+ (code = param_read_int(plist, (vname = "RedValues"), &v)) != 1 ||
+ (code = param_read_int(plist, (vname = "GreenValues"), &v)) != 1 ||
+ (code = param_read_int(plist, (vname = "BlueValues"), &v)) != 1
+ )
+ { if ( code < 0 )
+ ecode = code;
+ else switch ( v )
+ {
+ case 2: bpc = 1; break;
+ case 4: bpc = 2; break;
+ case 16: bpc = 4; break;
+ case 32: bpc = 5; break;
+ case 256: bpc = 8; break;
+ default: param_signal_error(plist, vname,
+ ecode = gs_error_rangecheck);
+ }
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ /* Temporarily reset the color_info so that gdev_prn_put_params */
+ /* won't complain. */
+ save_info = pdev->color_info;
+ if ( code != 1 )
+ { pdev->color_info.depth = depths[ncomps - 1][bpc - 1];
+ pdev->color_info.max_gray = pdev->color_info.max_color =
+ (pdev->color_info.dither_grays =
+ pdev->color_info.dither_colors =
+ (1 << bpc)) - 1;
+ }
+ ecode = gdev_prn_put_params(pdev, plist);
+ if ( ecode < 0 )
+ { pdev->color_info = save_info;
+ return ecode;
+ }
+ if ( code != 1 )
+ { if ( pdev->is_open )
+ gs_closedevice(pdev);
+ }
+ return 0;
+}
+
+/* Send the page to the printer. */
+private int
+bit_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ /* Just dump the bits on the file. */
+ /* If the file is 'nul', don't even do the writes. */
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte *in = (byte *)gs_malloc(line_size, 1, "bit_print_page(in)");
+ byte *data;
+ int nul = !strcmp(pdev->fname, "nul");
+ int lnum = 0, bottom = pdev->height;
+
+ if ( in == 0 )
+ return_error(gs_error_VMerror);
+#ifdef TRIM_TOP_BOTTOM
+ { gx_color_index white =
+ (pdev->color_info.num_components == 4 ? 0 :
+ (*dev_proc(pdev, map_rgb_color))
+ ((gx_device *)pdev, gx_max_color_value, gx_max_color_value,
+ gx_max_color_value));
+#define color_index_bits (sizeof(gx_color_index) * 8)
+ const gx_color_index *p;
+ const gx_color_index *end;
+ int depth = pdev->color_info.depth;
+ int end_bits = ((long)line_size * depth) % color_index_bits;
+ gx_color_index end_mask =
+ (end_bits == 0 ? 0 : -1 << (color_index_bits - end_bits));
+ int i;
+
+ for ( i = depth; i < color_index_bits; i += depth )
+ white |= white << depth;
+ /* Remove bottom white space. */
+ for ( ; bottom - lnum > 1; --bottom )
+ { gdev_prn_get_bits(pdev, bottom - 1, in, &data);
+ p = (const gx_color_index *)data;
+ end = p + line_size / sizeof(gx_color_index);
+ for ( ; p < end; ++p )
+ if ( *p != white )
+ goto bx;
+ if ( end_mask != 0 && ((*end ^ white) & end_mask) != 0 )
+ goto bx;
+ }
+ /* Remove top white space. */
+bx: for ( ; lnum < bottom; ++lnum )
+ { gdev_prn_get_bits(pdev, lnum, in, &data);
+ p = (const gx_color_index *)data;
+ end = p + line_size / sizeof(gx_color_index);
+ for ( ; p < end; ++p )
+ if ( *p != white )
+ goto tx;
+ if ( end_mask != 0 && ((*end ^ white) & end_mask) != 0 )
+ goto tx;
+ }
+tx: ;
+ }
+#endif
+ for ( ; lnum < bottom; ++lnum )
+ { gdev_prn_get_bits(pdev, lnum, in, &data);
+ if ( !nul )
+ { const byte *row = data;
+ uint len = line_size;
+#ifdef TRIM_LEFT
+ row += (TRIM_LEFT * pdev->color_info.depth) >> 3;
+#endif
+#ifdef TRIM_RIGHT
+ len = data + ((TRIM_RIGHT * pdev->color_info.depth + 7) >> 3) - row;
+#endif
+#ifdef EXPAND_BITS_TO_BYTES
+ { uint i;
+ byte invert = (pdev->color_info.depth == 1 ? 0xff : 0);
+ for ( i = 0; i < len; ++i )
+ { byte b = row[i] ^ invert;
+ putc(-(b >> 7) & 0xff, prn_stream);
+ putc(-((b >> 6) & 1) & 0xff, prn_stream);
+ putc(-((b >> 5) & 1) & 0xff, prn_stream);
+ putc(-((b >> 4) & 1) & 0xff, prn_stream);
+ putc(-((b >> 3) & 1) & 0xff, prn_stream);
+ putc(-((b >> 2) & 1) & 0xff, prn_stream);
+ putc(-((b >> 1) & 1) & 0xff, prn_stream);
+ putc(-(b & 1) & 0xff, prn_stream);
+ }
+ }
+#else
+ fwrite(row, 1, len, prn_stream);
+#endif
+ }
+ }
+ gs_free((char *)in, line_size, 1, "bit_print_page(in)");
+ return 0;
+}
diff --git a/gs/src/gdevbj10.c b/gs/src/gdevbj10.c
new file mode 100644
index 000000000..76cd48771
--- /dev/null
+++ b/gs/src/gdevbj10.c
@@ -0,0 +1,385 @@
+/* Copyright (C) 1990, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbj10.c */
+/* Canon Bubble Jet BJ-10e and BJ200 printer driver */
+#include "gdevprn.h"
+
+/*
+ * The following is taken from the BJ200 Programmer's manual. The top
+ * margin is 3mm (0.12"), and the bottom margin is 6.4mm (0.25"). The
+ * left and right margin depend on the type of paper -- US letter or
+ * A4 -- but ultimately rest on a print width of 203.2mm (8"). For letter
+ * paper, the left margin (and hence the right) is 6.4mm (0.25"), while
+ * for A4 paper, both are 3.4mm (0.13").
+ *
+ * The bottom margin requires a bit of care. The image is printed
+ * as strips, each about 3.4mm wide. We can only attain the bottom
+ * margin if the final strip coincides with it. Note that each strip
+ * is generated using only 48 of the available 64 jets, and the absence
+ * of those bottom 16 jets makes our bottom margin, in effect, about
+ * 1.1mm (0.04") larger.
+ *
+ * The bj200 behaves, in effect, as though the origin were at the first
+ * printable position, rather than the top left corner of the page, so
+ * we add a translation to the initial matrix to compensate for this.
+ *
+ * Except for the details of getting the margins correct, the bj200 is
+ * no different from the bj10e, and uses the same routine to print each
+ * page.
+ *
+ * NOTE: The bj200 has a DIP switch called "Text scale mode" and if
+ * set, it allows the printer to get 66 lines on a letter-sized page
+ * by reducing the line spacing by a factor of 14/15. If this DIP
+ * switch is set, the page image printed by ghostscript will also be
+ * similarly squeezed. Thus text scale mode is something ghostscript
+ * would like to disable.
+ *
+ * According to the bj200 manual, which describes the bj10 commands,
+ * the printer can be reset either to the settings determined by the
+ * DIP switches, or to the factory defaults, and then some of those
+ * settings can be specifically overriden. Unfortunately, the text
+ * scale mode and horizontal print position (for letter vs A4 paper)
+ * can not be overriden. On my bj200, the factory settings are for
+ * no text scaling and letter paper, thus using the factory defaults
+ * also implies letter paper. I don't know if this is necessarily
+ * true for bj200's sold elsewhere, or for other printers that use
+ * the same command set.
+ *
+ * If your factory defaults are in fact the same, you can compile
+ * the driver with USE_FACTORY_DEFAULTS defined, in which case the
+ * printer will be reset to the factory defaults for letter paper,
+ * and reset to the DIP switch settings for A4 paper. In this case,
+ * with letter-sized paper, the text scale mode will be disabled.
+ * Further, by leaving the horizontal print position DIP switch set
+ * for A4 paper, gs will be able to print on either A4 or letter
+ * paper without changing the DIP switch. Since it's not clear that
+ * the factory defaults are universal, the default behaviour is not
+ * to define USE_FACTORY_DEFAULTS, and the printer will always be
+ * reset to the DIP switch defaults.
+ */
+
+#define BJ200_TOP_MARGIN 0.12
+#define BJ200_BOTTOM_MARGIN 0.29
+#define BJ200_LETTER_SIDE_MARGIN 0.25
+#define BJ200_A4_SIDE_MARGIN 0.13
+
+private dev_proc_open_device(bj200_open);
+
+private dev_proc_print_page(bj10e_print_page);
+
+private gx_device_procs prn_bj200_procs =
+ prn_procs(bj200_open, gdev_prn_output_page, gdev_prn_close);
+
+gx_device_printer far_data gs_bj200_device =
+ prn_device(prn_bj200_procs, "bj200",
+ DEFAULT_WIDTH_10THS,
+ DEFAULT_HEIGHT_10THS,
+ 360, /* x_dpi */
+ 360, /* y_dpi */
+ 0, 0, 0, 0, /* margins filled in by bj200_open */
+ 1, bj10e_print_page);
+
+/*
+ * (<simon@pogner.demon.co.uk>, aka <sjwright@cix.compulink.co.uk>):
+ * My bj10ex, which as far as I can tell is just like a bj10e, works
+ * fine with the bj200 setup here.
+ */
+
+gx_device_printer far_data gs_bj10e_device =
+ prn_device(prn_bj200_procs, "bj10e",
+ DEFAULT_WIDTH_10THS,
+ DEFAULT_HEIGHT_10THS,
+ 360, /* x_dpi */
+ 360, /* y_dpi */
+ 0,0,0,0, /* margins */
+ 1, bj10e_print_page);
+
+/*
+ * Notes on the BJ10e/BJ200 command set.
+ *
+
+According to the BJ200 manual, the "set initial condition" sequence (ESC [
+K) has 2 bytes which can override the DIP switches -- these are the last 2
+bytes. Several bits are listed as "reserved" -- one or more may possibly
+affect the sheet feeder. The first is referred to as <P1>, with the
+following meaning:
+ 1 0
+bit 7 ignore/process P1 ignore process
+bit 6 reserved
+bit 5 alarm disabled enabled
+bit 4 automatic CR CR+LF CR
+bit 3 automatic LF CR+LF LF
+bit 2 page length 12 inches 11 inches
+bit 1 style for zero slashed not slashed
+bit 0 character set set 2 set 1
+
+The last byte is <P2>, with the following meaning:
+ 1 0
+bit 7 ignore/process P2 ignore process
+bit 6 code page 850 437
+bit 5 reserved
+bit 4 reserved
+bit 3 reserved
+bit 2 reserved
+bit 1 reserved
+bit 0 reserved
+
+The automatic CR setting is important to gs, but the rest shouldn't matter
+(gs doesn't print characters or send LF, and it explicitly sets the page
+length). The sequence ESC 5 <n> controls automatic CR -- if <n> is 0x00,
+it is turned off (CR only) and if <n> is 0x01, it is turned on (CR + LF).
+So we do following: Change the initialization string to so that the last 2
+of the 9 bytes are \200 rather than \000. Then add
+ |* Turn off automatic carriage return, otherwise we get line feeds. *|
+ fwrite("\0335\000", 1, 3, prn_stream);
+after the initialization. (Actually, instead of setting the last 2 bytes
+to \200, we suppress them altogether by changing the byte count from \004
+to \002 (the byte count is the 4th (low 8 bits) and 5th (high 8 bits) bytes
+in the initialization sequence).)
+
+*/
+
+/* ------ Internal routines ------ */
+
+/* Open the printer, and set the margins. */
+private int
+bj200_open(gx_device *pdev)
+{
+ /* Change the margins according to the paper size.
+ The top and bottom margins don't seem to depend on the
+ page length, but on the paper handling mechanism;
+ The side margins do depend on the paper width, as the
+ printer centres the 8" print line on the page. */
+
+ static const float a4_margins[4] =
+ { BJ200_A4_SIDE_MARGIN, BJ200_BOTTOM_MARGIN,
+ BJ200_A4_SIDE_MARGIN, BJ200_TOP_MARGIN
+ };
+ static const float letter_margins[4] =
+ { BJ200_LETTER_SIDE_MARGIN, BJ200_BOTTOM_MARGIN,
+ BJ200_LETTER_SIDE_MARGIN, BJ200_TOP_MARGIN
+ };
+
+ gx_device_set_margins(pdev,
+ (pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
+ a4_margins : letter_margins),
+ true);
+ return gdev_prn_open(pdev);
+}
+
+/* Send the page to the printer. */
+private int
+bj10e_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int line_size = gx_device_raster((gx_device *)pdev, 0);
+ int xres = pdev->x_pixels_per_inch;
+ int yres = pdev->y_pixels_per_inch;
+ int mode = (yres == 180 ?
+ (xres == 180 ? 11 : 12) :
+ (xres == 180 ? 14 : 16));
+ int bytes_per_column = (yres == 180) ? 3 : 6;
+ int bits_per_column = bytes_per_column * 8;
+ int skip_unit = bytes_per_column * 3;
+ byte *in = (byte *)gs_malloc(8, line_size, "bj10e_print_page(in)");
+ byte *out = (byte *)gs_malloc(bits_per_column, line_size, "bj10e_print_page(out)");
+ int lnum = 0;
+ int skip = 0;
+ int code = 0;
+ int last_row = dev_print_scan_lines(pdev);
+ int limit = last_row - bits_per_column;
+
+ if ( in == 0 || out == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto fin;
+ }
+
+ /* Initialize the printer. */
+#ifdef USE_FACTORY_DEFAULTS
+ /* Check for U.S. letter vs. A4 paper. */
+ fwrite(( pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
+ "\033[K\002\000\000\044" /*A4--DIP switch defaults*/ :
+ "\033[K\002\000\004\044" /*letter--factory defaults*/ ),
+ 1, 7, prn_stream);
+#else
+ fwrite("\033[K\002\000\000\044", 1, 7, prn_stream);
+#endif
+
+ /* Turn off automatic carriage return, otherwise we get line feeds. */
+ fwrite("\0335\000", 1, 3, prn_stream);
+
+ /* Set vertical spacing. */
+ fwrite("\033[\\\004\000\000\000", 1, 7, prn_stream);
+ fputc(yres & 0xff, prn_stream);
+ fputc(yres >> 8, prn_stream);
+
+ /* Set the page length. This is the printable length, in inches. */
+ fwrite("\033C\000", 1, 3, prn_stream);
+ fputc((last_row + yres - 1)/yres, prn_stream);
+
+ /* Transfer pixels to printer. The last row we can print is defined
+ by "last_row". Only the bottom of the print head can print at the
+ bottom margin, and so we align the final printing pass. The print
+ head is kept from moving below "limit", which is exactly one pass
+ above the bottom margin. Once it reaches this limit, we make our
+ final printing pass of a full "bits_per_column" rows. */
+ while ( lnum < last_row )
+ {
+ byte *in_data;
+ byte *in_end = in + line_size;
+ byte *out_beg = out;
+ byte *out_end = out + bytes_per_column * pdev->width;
+ byte *outl = out;
+ int bnum;
+
+ /* Copy 1 scan line and test for all zero. */
+ code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ if ( code < 0 ) goto xit;
+ /* The mem... or str... functions should be faster than */
+ /* the following code, but all systems seem to implement */
+ /* them so badly that this code is faster. */
+ { register const long *zip = (const long *)in_data;
+ register int zcnt = line_size;
+ register const byte *zipb;
+ for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
+ { if ( zip[0] | zip[1] | zip[2] | zip[3] )
+ goto notz;
+ }
+ zipb = (const byte *)zip;
+ while ( --zcnt >= 0 )
+ {
+ if ( *zipb++ )
+ goto notz;
+ }
+ /* Line is all zero, skip */
+ lnum++;
+ skip++;
+ continue;
+notz: ;
+ }
+
+ /* Vertical tab to the appropriate position. Note here that
+ we make sure we don't move below limit. */
+ if ( lnum > limit )
+ { skip -= (lnum - limit);
+ lnum = limit;
+ }
+ while ( skip > 255 )
+ { fputs("\033J\377", prn_stream);
+ skip -= 255;
+ }
+ if ( skip )
+ fprintf(prn_stream, "\033J%c", skip);
+
+ /* If we've printed as far as "limit", then reset "limit"
+ to "last_row" for the final printing pass. */
+ if ( lnum == limit )
+ limit = last_row;
+ skip = 0;
+
+ /* Transpose in blocks of 8 scan lines. */
+ for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
+ { int lcnt = min(8, limit - lnum);
+ byte *inp = in;
+ byte *outp = outl;
+ lcnt = gdev_prn_copy_scan_lines(pdev,
+ lnum, in, lcnt * line_size);
+ if ( lcnt < 0 )
+ { code = lcnt;
+ goto xit;
+ }
+ if ( lcnt < 8 )
+ memset(in + lcnt * line_size, 0,
+ (8 - lcnt) * line_size);
+ for ( ; inp < in_end; inp++, outp += bits_per_column )
+ { gdev_prn_transpose_8x8(inp, line_size,
+ outp, bytes_per_column);
+ }
+ outl++;
+ lnum += lcnt;
+ skip += lcnt;
+ }
+
+ /* Send the bits to the printer. We alternate horizontal
+ skips with the data. The horizontal skips are in units
+ of 1/120 inches, so we look at the data in groups of
+ 3 columns, since 3/360 = 1/120, and 3/180 = 2/120. */
+ outl = out;
+ do
+ { int count;
+ int n;
+ byte *out_ptr;
+
+ /* First look for blank groups of columns. */
+ while(outl < out_end)
+ { n = count = min(out_end - outl, skip_unit);
+ out_ptr = outl;
+ while ( --count >= 0 )
+ { if ( *out_ptr++ )
+ break;
+ }
+ if ( count >= 0 )
+ break;
+ else
+ outl = out_ptr;
+ }
+ if (outl >= out_end)
+ break;
+ if (outl > out_beg)
+ { count = (outl - out_beg) / skip_unit;
+ if ( xres == 180 ) count <<= 1;
+ fprintf(prn_stream, "\033d%c%c",
+ count & 0xff, count >> 8);
+ }
+
+ /* Next look for non-blank groups of columns. */
+ out_beg = outl;
+ outl += n;
+ while(outl < out_end)
+ { n = count = min(out_end - outl, skip_unit);
+ out_ptr = outl;
+ while ( --count >= 0 )
+ { if ( *out_ptr++ )
+ break;
+ }
+ if ( count < 0 )
+ break;
+ else
+ outl += n;
+ }
+ count = outl - out_beg + 1;
+ fprintf(prn_stream, "\033[g%c%c%c",
+ count & 0xff, count >> 8, mode);
+ fwrite(out_beg, 1, count - 1, prn_stream);
+ out_beg = outl;
+ outl += n;
+ }
+ while ( out_beg < out_end );
+
+ fputc('\r', prn_stream);
+ }
+
+ /* Eject the page */
+xit: fputc(014, prn_stream); /* form feed */
+ fflush(prn_stream);
+fin: if ( out != 0 )
+ gs_free((char *)out, bits_per_column, line_size,
+ "bj10e_print_page(out)");
+ if ( in != 0 )
+ gs_free((char *)in, 8, line_size, "bj10e_print_page(in)");
+ return code;
+}
diff --git a/gs/src/gdevbjc.h b/gs/src/gdevbjc.h
new file mode 100644
index 000000000..77ad6c399
--- /dev/null
+++ b/gs/src/gdevbjc.h
@@ -0,0 +1,282 @@
+/* Copyright (C) 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbjc.h */
+/*
+ * Definitions for Canon BJC printers and the associated drivers.
+ *
+ * Copyright (C) Yves Arrouye <Yves.Arrouye@imag.fr>, 1995, 1996.
+ *
+ */
+
+/*
+ * Please do read the definitions here and change the defaults if needed.
+ *
+ * Values that can be changed are all called BJC_DEFAULT_* for generic
+ * values and BJC600_DEFAULT_* or BJC800_DEFAULT_* for specific values.
+ *
+ */
+
+#ifndef _GDEV_BJC_H
+#define _GDEV_CDJ_H
+
+/*
+ * Drivers names. I don't expect you to change them!
+ *
+ */
+
+#define BJC_BJC600 "bjc600"
+#define BJC_BJC800 "bjc800"
+
+#define BJC_BJC600_VERSION 2.1700
+#define BJC_BJC600_VERSIONSTR "2.17.00 5/23/96 Yves Arrouye"
+
+#define BJC_BJC800_VERSION 2.1700
+#define BJC_BJC800_VERSIONSTR "2.17.00 5/23/96 Yves Arrouye"
+
+/*
+ * Hardware limits. May be adjusted eventually.
+ *
+ */
+
+#define BJC_PRINT_LIMIT (3. / 25.4) /* In inches. */
+#define BJC_A3_PRINT_LIMIT (8. / 25.4) /* In inches. */
+
+#define BJC_HARD_LOWER_LIMIT (7. / 25.4) /* In inches. */
+#define BJC_USED_LOWER_LIMIT (9.54 / 25.4) /* In inches. */
+#define BJC_RECD_LOWER_LIMIT (12.7 / 25.4) /* In inches. */
+
+#ifdef USE_RECOMMENDED_MARGINS
+#define BJC_LOWER_LIMIT BJC_RECD_LOWER_LIMIT
+#undef BJC_DEFAULT_CENTEREDAREA
+#define BJC_DEFAULT_CENTEREDAREA
+#else
+#ifdef USE_TIGHT_MARGINS
+#define BJC_LOWER_LIMIT BJC_HARD_LOWER_LIMIT /* In inches. */
+#else
+#define BJC_LOWER_LIMIT BJC_USED_LOWER_LIMIT /* In inches. */
+#endif
+#endif
+
+#ifndef BJC600_MEDIAWEIGHT_THICKLIMIT
+#define BJC600_MEDIAWEIGHT_THICKLIMIT 105 /* In g/m2. */
+#endif
+#ifndef BJC800_MEDIAWEIGHT_THICKLIMIT
+#define BJC800_MEDIAWEIGHT_THICKLIMIT BJC600_MEDIAWEIGHT_THICKLIMIT
+#endif
+
+#define BJC_HEAD_ROWS 64 /* Number of heads. Do not change! */
+
+/*
+ * Margins resulting from the limits specified above.
+ *
+ * The margins are Left, Bottom, Right, Top and are expressed in inches.
+ * You should not change them, better change the limits above.
+ *
+ */
+
+#define BJC_MARGINS_LETTER \
+ (6.5 / 25.4), BJC_LOWER_LIMIT, (6.5 / 25.4), BJC_PRINT_LIMIT
+#define BJC_MARGINS_A4 \
+ (3.4 / 25.4), BJC_LOWER_LIMIT, (3.4 / 25.4), BJC_PRINT_LIMIT
+#define BJC_MARGINS_A3 \
+ (4.0 / 25.4), BJC_LOWER_LIMIT, (4.0 / 25.4), BJC_A3_PRINT_LIMIT
+
+/*
+ * Drivers options names.
+ *
+ */
+
+#define BJC_DEVINFO_VERSION "Version"
+#define BJC_DEVINFO_VERSIONSTRING "VersionString"
+
+#define BJC_DEVINFO_OUTPUTFACEUP "OutputFaceUp"
+
+#define BJC_OPTION_MANUALFEED "ManualFeed"
+#define BJC_OPTION_DITHERINGTYPE "DitheringType"
+#define BJC_OPTION_MEDIATYPE "MediaType"
+#define BJC_OPTION_MEDIAWEIGHT "MediaWeight"
+#define BJC_OPTION_PRINTQUALITY "PrintQuality"
+#define BJC_OPTION_COLORCOMPONENTS "ColorComponents"
+#define BJC_OPTION_PRINTCOLORS "PrintColors"
+#define BJC_OPTION_MONOCHROMEPRINT "MonochromePrint"
+
+/*
+ * Definitions of parameters (options) values.
+ *
+ */
+
+#define BJC_MEDIA_PLAINPAPER 0
+#define BJC_MEDIA_COATEDPAPER 1
+#define BJC_MEDIA_TRANSPARENCYFILM 2
+#define BJC_MEDIA_BACKPRINTFILM 3 /* Unused */
+#define BJC_MEDIA_ENVELOPE 8
+#define BJC_MEDIA_CARD 9
+#define BJC_MEDIA_OTHER 15
+
+#define BJC_DITHER_NONE 0
+#define BJC_DITHER_FS 1
+
+#define BJC_QUALITY_NORMAL 0
+#define BJC_QUALITY_HIGH 1
+#define BJC_QUALITY_DRAFT 2
+#define BJC_QUALITY_LOW 3
+
+#define BJC_COLOR_ALLBLACK 0
+#define BJC_COLOR_CYAN 1
+#define BJC_COLOR_MAGENTA 2
+#define BJC_COLOR_YELLOW 4
+#define BJC_COLOR_BLACK 8
+
+#define BJC_COLOR_CMY (BJC_COLOR_CYAN | BJC_COLOR_MAGENTA | BJC_COLOR_YELLOW)
+#define BJC_COLOR_CMYK (BJC_COLOR_CMY | BJC_COLOR_BLACK)
+
+/* Some compilers complain if this is a floating point value.... */
+#define BJC_RESOLUTION_BASE 90
+
+#define BJC_RESOLUTION_LOW (1 * BJC_RESOLUTION_BASE)
+#define BJC_RESOLUTION_MEDIUM (2 * BJC_RESOLUTION_BASE)
+#define BJC_RESOLUTION_NORMAL (4 * BJC_RESOLUTION_BASE)
+
+/*
+ * Default values for parameters (long).
+ *
+ * Generic values are first given, and driver-specific values are by default
+ * those generic values.
+ *
+ */
+
+#ifndef BJC_DEFAULT_MEDIATYPE
+#define BJC_DEFAULT_MEDIATYPE BJC_MEDIA_PLAINPAPER
+#endif
+#ifndef BJC_DEFAULT_PRINTQUALITY
+#define BJC_DEFAULT_PRINTQUALITY BJC_QUALITY_NORMAL
+#endif
+
+#ifndef BJC_DEFAULT_DITHERINGTYPE
+#define BJC_DEFAULT_DITHERINGTYPE BJC_DITHER_FS
+#endif
+
+#ifndef BJC_DEFAULT_MANUALFEED
+#define BJC_DEFAULT_MANUALFEED false
+#endif
+#ifndef BJC_DEFAULT_MONOCHROMEPRINT
+#define BJC_DEFAULT_MONOCHROMEPRINT false
+#endif
+
+#ifndef BJC_DEFAULT_RESOLUTION
+#define BJC_DEFAULT_RESOLUTION BJC_RESOLUTION_NORMAL
+#endif
+
+/* If you change the bits per pixel, change the color components. For
+ bpp = 1 color components = 1, bpp = 8 color components = { 1, 4},
+ bpp = { 16, 24, 32 } color components = 4, comps = { 3 }, bpp = { 24 }. */
+
+#ifndef BJC_DEFAULT_BITSPERPIXEL
+#define BJC_DEFAULT_BITSPERPIXEL 24
+#endif
+#ifndef BJC_DEFAULT_COLORCOMPONENTS
+#define BJC_DEFAULT_COLORCOMPONENTS 4
+#endif
+
+/* You should not have to change these defaults */
+
+#ifndef BJC_DEFAULT_PRINTCOLORS
+#define BJC_DEFAULT_PRINTCOLORS BJC_COLOR_CMYK
+#endif
+#ifndef BJC_DEFAULT_MONOCHROMEPRINT
+#define BJC_DEFAULT_MONOCHROMEPRINT false
+#endif
+#ifndef BJC_DEFAULT_SETMEDIAWEIGHT
+#define BJC_DEFAULT_SETMEDIAWEIGHT 0
+#endif
+#ifndef BJC_DEFAULT_MEDIAWEIGHT
+#define BJC_DEFAULT_MEDIAWEIGHT 80
+#endif
+
+/*
+ * Default values for the specific BJC drivers.
+ *
+ */
+
+#ifndef BJC600_DEFAULT_MEDIATYPE
+#define BJC600_DEFAULT_MEDIATYPE BJC_DEFAULT_MEDIATYPE
+#endif
+#ifndef BJC600_DEFAULT_PRINTQUALITY
+#define BJC600_DEFAULT_PRINTQUALITY BJC_DEFAULT_PRINTQUALITY
+#endif
+#ifndef BJC600_DEFAULT_DITHERINGTYPE
+#define BJC600_DEFAULT_DITHERINGTYPE BJC_DEFAULT_DITHERINGTYPE
+#endif
+#ifndef BJC600_DEFAULT_MANUALFEED
+#define BJC600_DEFAULT_MANUALFEED BJC_DEFAULT_MANUALFEED
+#endif
+#ifndef BJC600_DEFAULT_MONOCHROMEPRINT
+#define BJC600_DEFAULT_MONOCHROMEPRINT BJC_DEFAULT_MONOCHROMEPRINT
+#endif
+#ifndef BJC600_DEFAULT_RESOLUTION
+#define BJC600_DEFAULT_RESOLUTION BJC_DEFAULT_RESOLUTION
+#endif
+#ifndef BJC600_DEFAULT_BITSPERPIXEL
+#define BJC600_DEFAULT_BITSPERPIXEL BJC_DEFAULT_BITSPERPIXEL
+#endif
+#ifndef BJC600_DEFAULT_COLORCOMPONENTS
+#define BJC600_DEFAULT_COLORCOMPONENTS BJC_DEFAULT_COLORCOMPONENTS
+#endif
+#ifndef BJC600_DEFAULT_PRINTCOLORS
+#define BJC600_DEFAULT_PRINTCOLORS BJC_DEFAULT_PRINTCOLORS
+#endif
+#ifndef BJC600_DEFAULT_SETMEDIAWEIGHT
+#define BJC600_DEFAULT_SETMEDIAWEIGHT BJC_DEFAULT_SETMEDIAWEIGHT
+#endif
+#ifndef BJC600_DEFAULT_MEDIAWEIGHT
+#define BJC600_DEFAULT_MEDIAWEIGHT BJC_DEFAULT_MEDIAWEIGHT
+#endif
+
+#ifndef BJC800_DEFAULT_MEDIATYPE
+#define BJC800_DEFAULT_MEDIATYPE BJC_DEFAULT_MEDIATYPE
+#endif
+#ifndef BJC800_DEFAULT_PRINTQUALITY
+#define BJC800_DEFAULT_PRINTQUALITY BJC_DEFAULT_PRINTQUALITY
+#endif
+#ifndef BJC800_DEFAULT_DITHERINGTYPE
+#define BJC800_DEFAULT_DITHERINGTYPE BJC_DEFAULT_DITHERINGTYPE
+#endif
+#ifndef BJC800_DEFAULT_MANUALFEED
+#define BJC800_DEFAULT_MANUALFEED BJC_DEFAULT_MANUALFEED
+#endif
+#ifndef BJC800_DEFAULT_RESOLUTION
+#define BJC800_DEFAULT_RESOLUTION BJC_DEFAULT_RESOLUTION
+#endif
+#ifndef BJC800_DEFAULT_BITSPERPIXEL
+#define BJC800_DEFAULT_BITSPERPIXEL BJC_DEFAULT_BITSPERPIXEL
+#endif
+#ifndef BJC800_DEFAULT_COLORCOMPONENTS
+#define BJC800_DEFAULT_COLORCOMPONENTS BJC_DEFAULT_COLORCOMPONENTS
+#endif
+#ifndef BJC800_DEFAULT_PRINTCOLORS
+#define BJC800_DEFAULT_PRINTCOLORS BJC_DEFAULT_PRINTCOLORS
+#endif
+#ifndef BJC800_DEFAULT_SETMEDIAWEIGHT
+#define BJC800_DEFAULT_SETMEDIAWEIGHT BJC_DEFAULT_SETMEDIAWEIGHT
+#endif
+#ifndef BJC800_DEFAULT_MEDIAWEIGHT
+#define BJC800_DEFAULT_MEDIAWEIGHT BJC_DEFAULT_MEDIAWEIGHT
+#endif
+
+#endif /* _GDEVBJC_H */
diff --git a/gs/src/gdevbmp.c b/gs/src/gdevbmp.c
new file mode 100644
index 000000000..ae182e4cc
--- /dev/null
+++ b/gs/src/gdevbmp.c
@@ -0,0 +1,264 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevbmp.c */
+/* .BMP file format output drivers */
+#include "gdevprn.h"
+#include "gdevpccm.h"
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+private dev_proc_print_page(bmp_print_page);
+
+/* Monochrome. */
+
+gx_device_printer far_data gs_bmpmono_device =
+ prn_device(prn_std_procs, "bmpmono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, bmp_print_page);
+
+/* 4-bit planar (EGA/VGA-style) color. */
+
+private gx_device_procs bmp16_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
+gx_device_printer far_data gs_bmp16_device =
+ prn_device(bmp16_procs, "bmp16",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 4, bmp_print_page);
+
+/* 8-bit (SuperVGA-style) color. */
+/* (Uses a fixed palette of 3,3,2 bits.) */
+
+private gx_device_procs bmp256_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_printer far_data gs_bmp256_device =
+ prn_device(bmp256_procs, "bmp256",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 8, bmp_print_page);
+
+/* 24-bit color. */
+
+private dev_proc_map_rgb_color(map_16m_rgb_color);
+private dev_proc_map_color_rgb(map_16m_color_rgb);
+private gx_device_procs bmp16m_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ map_16m_rgb_color, map_16m_color_rgb);
+gx_device_printer far_data gs_bmp16m_device =
+ prn_device(bmp16m_procs, "bmp16m",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 24, bmp_print_page);
+
+/* ------ Private definitions ------ */
+
+/* All multi-byte quantities are stored LSB-first! */
+typedef ushort word;
+#if arch_sizeof_int == 4
+typedef uint dword;
+#else
+# if arch_sizeof_long == 4
+typedef ulong dword;
+# endif
+#endif
+#if arch_is_big_endian
+# define assign_word(a,v) a = ((v) >> 8) + ((v) << 8)
+# define assign_dword(a,v)\
+ a = ((v) >> 24) + (((v) >> 8) & 0xff00L) +\
+ (((dword)(v) << 8) & 0xff0000L) + ((dword)(v) << 24)
+#else
+# define assign_word(a,v) a = (v)
+# define assign_dword(a,v) a = (v)
+#endif
+
+typedef struct bmp_file_header_s {
+
+ /* BITMAPFILEHEADER */
+
+ /*
+ * This structure actually begins with two bytes
+ * containing the characters 'BM', but we must omit them,
+ * because some compilers would insert padding to force
+ * the size member to a 32- or 64-bit boundary.
+ */
+
+ /*byte typeB, typeM;*/ /* always 'BM' */
+ dword size; /* total size of file */
+ word reserved1;
+ word reserved2;
+ dword offBits; /* offset of bits from start of file */
+
+} bmp_file_header;
+#define sizeof_bmp_file_header (2 + sizeof(bmp_file_header))
+
+typedef struct bmp_info_header_s {
+
+ /* BITMAPINFOHEADER */
+
+ dword size; /* size of info header in bytes */
+ dword width; /* width in pixels */
+ dword height; /* height in pixels */
+ word planes; /* # of planes, always 1 */
+ word bitCount; /* bits per pixel */
+ dword compression; /* compression scheme, always 0 */
+ dword sizeImage; /* size of bits */
+ dword xPelsPerMeter; /* X pixels per meter */
+ dword yPelsPerMeter; /* Y pixels per meter */
+ dword clrUsed; /* # of colors used */
+ dword clrImportant; /* # of important colors */
+
+ /* This is followed by (1 << bitCount) bmp_quad structures, */
+ /* unless bitCount == 24. */
+
+} bmp_info_header;
+
+typedef struct bmp_quad_s {
+
+ /* RGBQUAD */
+
+ byte blue, green, red, reserved;
+
+} bmp_quad;
+
+/* Write out a page in BMP format. */
+/* This routine is used for all formats. */
+private int
+bmp_print_page(gx_device_printer *pdev, FILE *file)
+{ int raster = gdev_prn_raster(pdev);
+ /* BMP scan lines are padded to 32 bits. */
+ ulong bmp_raster = raster + (-raster & 3);
+ int height = pdev->height;
+ int depth = pdev->color_info.depth;
+ int quads = (depth <= 8 ? sizeof(bmp_quad) << depth : 0);
+ byte *row = (byte *)gs_malloc(bmp_raster, 1, "bmp file buffer");
+ int y;
+ int code = 0; /* return code */
+
+ if ( row == 0 ) /* can't allocate row buffer */
+ return_error(gs_error_VMerror);
+
+ /* Write the file header. */
+
+ fputc('B', file);
+ fputc('M', file);
+ { bmp_file_header fhdr;
+ assign_dword(fhdr.size,
+ sizeof_bmp_file_header +
+ sizeof(bmp_info_header) + quads +
+ bmp_raster * height);
+ assign_word(fhdr.reserved1, 0);
+ assign_word(fhdr.reserved2, 0);
+ assign_dword(fhdr.offBits,
+ sizeof_bmp_file_header +
+ sizeof(bmp_info_header) + quads);
+ if ( fwrite((const char *)&fhdr, 1, sizeof(fhdr), file) != sizeof(fhdr) )
+ { code = gs_error_ioerror;
+ goto bmp_done;
+ }
+ }
+
+ /* Write the info header. */
+
+ { bmp_info_header ihdr;
+ assign_dword(ihdr.size, sizeof(ihdr));
+ assign_dword(ihdr.width, pdev->width);
+ assign_dword(ihdr.height, height);
+ assign_word(ihdr.planes, 1);
+ assign_word(ihdr.bitCount, depth);
+ assign_dword(ihdr.compression, 0);
+ assign_dword(ihdr.sizeImage, bmp_raster * height);
+ /* Even though we could compute the resolution correctly, */
+ /* the convention seems to be to leave it unspecified. */
+ assign_dword(ihdr.xPelsPerMeter, 0);
+ /*(dword)(pdev->x_pixels_per_inch * (1000.0 / 30.48)));*/
+ assign_dword(ihdr.yPelsPerMeter, 0);
+ /*(dword)(pdev->y_pixels_per_inch * (1000.0 / 30.48)));*/
+ assign_dword(ihdr.clrUsed, 0);
+ assign_dword(ihdr.clrImportant, 0);
+ if ( fwrite((const char *)&ihdr, 1, sizeof(ihdr), file) != sizeof(ihdr) )
+ { code = gs_error_ioerror;
+ goto bmp_done;
+ }
+ }
+
+ /* Write the palette. */
+
+ if ( depth <= 8 )
+ { int i;
+ gx_color_value rgb[3];
+ bmp_quad q;
+ q.reserved = 0;
+ for ( i = 0; i != 1 << depth; i++ )
+ { (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
+ (gx_color_index)i, rgb);
+ q.red = gx_color_value_to_byte(rgb[0]);
+ q.green = gx_color_value_to_byte(rgb[1]);
+ q.blue = gx_color_value_to_byte(rgb[2]);
+ fwrite((const char *)&q, sizeof(q), 1, file);
+ }
+ }
+
+ /* Write the contents of the image. */
+ /* BMP files want the image in bottom-to-top order! */
+
+ for ( y = height - 1; y >= 0; y-- )
+ { gdev_prn_copy_scan_lines(pdev, y, row, raster);
+ fwrite((const char *)row, bmp_raster, 1, file);
+ }
+
+bmp_done:
+ gs_free((char *)row, bmp_raster, 1, "bmp file buffer");
+
+ return code;
+}
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that Windows expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+map_16m_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return gx_color_value_to_byte(r) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(b) << 16);
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+map_16m_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ prgb[2] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color & 0xff);
+ return 0;
+}
diff --git a/gs/src/gdevccr.c b/gs/src/gdevccr.c
new file mode 100644
index 000000000..18c314977
--- /dev/null
+++ b/gs/src/gdevccr.c
@@ -0,0 +1,294 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevccr.c */
+/* CalComp Raster Format driver */
+#include "gdevprn.h"
+
+/*
+ * Please contact the author, Ernst Muellner (ernst.muellner@oenzl.siemens.de),
+ * if you have any questions about this driver.
+ */
+
+#define CCFILESTART(p) putc(0x02, p)
+#define CCFILEEND(p) putc(0x04, p)
+#define CCNEWPASS(p) putc(0x0c, p)
+#define CCEMPTYLINE(p) putc(0x0a, p)
+#define CCLINESTART(len,p) do{ putc(0x1b,p);putc(0x4b,p);putc(len>>8,p); \
+ putc(len&0xff,p);} while(0)
+
+#define CPASS (0)
+#define MPASS (1)
+#define YPASS (2)
+#define NPASS (3)
+
+
+typedef struct cmyrow_s
+ {
+ int current;
+ int _cmylen[NPASS];
+ int is_used;
+ char cname[4];
+ char mname[4];
+ char yname[4];
+ unsigned char *_cmybuf[NPASS];
+ } cmyrow;
+
+#define clen _cmylen[CPASS]
+#define mlen _cmylen[MPASS]
+#define ylen _cmylen[YPASS]
+#define cmylen _cmylen
+
+#define cbuf _cmybuf[CPASS]
+#define mbuf _cmybuf[MPASS]
+#define ybuf _cmybuf[YPASS]
+#define cmybuf _cmybuf
+
+private int alloc_rb( cmyrow **rb, int rows);
+private int alloc_line( cmyrow *row, int cols);
+private void add_cmy8(cmyrow *rb, char c, char m, char y);
+private void write_cpass(cmyrow *buf, int rows, int pass, FILE * pstream);
+private void free_rb_line( cmyrow *rbuf, int rows, int cols);
+
+struct gx_device_ccr_s {
+ gx_device_common;
+ gx_prn_device_common;
+ /* optional parameters */
+};
+typedef struct gx_device_ccr_s gx_device_ccr;
+
+#define bdev ((gx_device_ccr *)pdev)
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 300
+#define Y_DPI 300
+#define DEFAULT_WIDTH_10THS_A3 117
+#define DEFAULT_HEIGHT_10THS_A3 165
+
+/* Macro for generating ccr device descriptors. */
+#define ccr_prn_device(procs, dev_name, margin, num_comp, depth, max_gray, max_rgb, print_page)\
+{ prn_device_body(gx_device_ccr, procs, dev_name,\
+ DEFAULT_WIDTH_10THS_A3, DEFAULT_HEIGHT_10THS_A3, X_DPI, Y_DPI,\
+ margin, margin, margin, margin,\
+ num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\
+ print_page)\
+}
+
+/* For CCR, we need our own color mapping procedures. */
+private dev_proc_map_rgb_color(ccr_map_rgb_color);
+private dev_proc_map_color_rgb(ccr_map_color_rgb);
+
+
+/* And of course we need our own print-page routine. */
+private dev_proc_print_page(ccr_print_page);
+
+/* The device procedures */
+private gx_device_procs ccr_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ ccr_map_rgb_color, ccr_map_color_rgb);
+
+/* The device descriptors themselves */
+gx_device_ccr far_data gs_ccr_device =
+ ccr_prn_device(ccr_procs, "ccr", 0.2, 3, 8, 1, 1,
+ ccr_print_page);
+
+/* ------ Color mapping routines ------ */
+/* map an rgb color to a ccr cmy bitmap */
+private gx_color_index
+ccr_map_rgb_color(gx_device *pdev, ushort r, ushort g, ushort b)
+{
+ register int shift = gx_color_value_bits - 1;
+ r>>=shift;
+ g>>=shift;
+ b>>=shift;
+
+ r=1-r; g=1-g; b=1-b; /* rgb -> cmy */
+ return r<<2 | g<<1 | b;
+}
+
+/* map an ccr cmy bitmap to a rgb color */
+private int
+ccr_map_color_rgb(gx_device *pdev, gx_color_index color, ushort rgb[3])
+{
+ rgb[2]=(1-(color >>2))*gx_max_color_value; /* r */
+ rgb[1]=(1-( (color & 0x2) >> 1))*gx_max_color_value; /* g */
+ rgb[0]=(1-(color & 0x1))*gx_max_color_value; /* b */
+ return 0;
+}
+/* ------ print page routine ------ */
+
+
+private int
+ccr_print_page(gx_device_printer *pdev, FILE *pstream)
+{
+ cmyrow *linebuf;
+ int line_size = gdev_prn_raster((gx_device *)pdev);
+ int pixnum = pdev->width;
+ int lnum = pdev->height;
+ int l, p, b;
+ int cmy, c, m, y;
+ byte *in;
+ byte *data;
+
+ if((in = (byte *)gs_malloc(line_size, 1, "gsline")) == NULL)
+ return_error(gs_error_VMerror);
+
+ if(alloc_rb( &linebuf, lnum))
+ {
+ gs_free(in, line_size, 1, "gsline");
+ return_error(gs_error_VMerror);
+ }
+
+ for ( l = 0; l < lnum; l++ )
+ { gdev_prn_get_bits(pdev, l, in, &data);
+ if(alloc_line(&linebuf[l], pixnum))
+ {
+ gs_free(in, line_size, 1, "gsline");
+ free_rb_line( linebuf, lnum, pixnum );
+ return_error(gs_error_VMerror);
+ }
+ for ( p=0; p< pixnum; p+=8)
+ {
+ c=m=y=0;
+ for(b=0; b<8; b++)
+ {
+ c <<= 1; m <<= 1; y <<= 1;
+ if(p+b < pixnum)
+ cmy = *data;
+ else
+ cmy = 0;
+
+ c |= cmy>>2;
+ m |= (cmy>>1) & 0x1;
+ y |= cmy & 0x1;
+ data++;
+ }
+ add_cmy8(&linebuf[l], c, m, y);
+ }
+ }
+CCFILESTART(pstream);
+write_cpass(linebuf, lnum, YPASS, pstream);
+CCNEWPASS(pstream);
+write_cpass(linebuf, lnum, MPASS, pstream);
+CCNEWPASS(pstream);
+write_cpass(linebuf, lnum, CPASS, pstream);
+CCFILEEND(pstream);
+
+/* clean up */
+gs_free(in, line_size, 1, "gsline");
+free_rb_line( linebuf, lnum, pixnum );
+return 0;
+}
+
+
+/* ------ Internal routines ------ */
+
+
+private int alloc_rb( cmyrow **rb, int rows)
+ {
+ *rb = (cmyrow*) gs_malloc(rows, sizeof(cmyrow), "rb");
+ if( *rb == 0)
+ return_error(gs_error_VMerror);
+ else
+ {
+ int r;
+ for(r=0; r<rows; r++)
+ {
+ sprintf((*rb)[r].cname, "C%02x", r);
+ sprintf((*rb)[r].mname, "M%02x", r);
+ sprintf((*rb)[r].yname, "Y%02x", r);
+ (*rb)[r].is_used=0;
+ }
+ return 0;
+ }
+}
+
+private int alloc_line( cmyrow *row, int cols)
+{
+ int suc;
+ suc=((row->cbuf = (char *) gs_malloc(cols,1, row->cname)) &&
+ (row->mbuf = (char *) gs_malloc(cols,1, row->mname)) &&
+ (row->ybuf = (char *) gs_malloc(cols,1, row->yname)));
+ if(suc == 0)
+ {
+ gs_free(row->cbuf, cols,1, row->cname);
+ gs_free(row->mbuf, cols,1, row->mname);
+ gs_free(row->ybuf, cols,1, row->yname);
+
+ return_error(gs_error_VMerror);
+ }
+ row->is_used = 1;
+ row->current = row->clen = row->mlen = row->ylen = 0;
+ return 0;
+}
+
+private void add_cmy8(cmyrow *rb, char c, char m, char y)
+{
+ int cur=rb->current;
+ rb->cbuf[cur]=c;
+ if(c)
+ rb->clen=cur+1;
+ rb->mbuf[cur]=m;
+ if(m)
+ rb->mlen=cur+1;
+ rb->ybuf[cur]=y;
+ if(y)
+ rb->ylen=cur+1;
+ rb->current++;
+ return;
+}
+
+private void write_cpass(cmyrow *buf, int rows, int pass, FILE * pstream)
+{
+ int row, len;
+ for(row=0; row<rows; row++)
+ {
+ len=buf[row].cmylen[pass];
+ if(len == 0)
+ CCEMPTYLINE(pstream);
+ else
+ {
+ CCLINESTART(len,pstream);
+ fwrite( buf[row].cmybuf[pass], len, 1, pstream);
+ }
+ }
+ return;
+}
+
+private void free_rb_line( cmyrow *rbuf, int rows, int cols)
+{
+ int i;
+ for(i=0; i<rows; i++)
+ {
+ if(rbuf[i].is_used)
+ {
+ gs_free(rbuf[i].cbuf, cols, 1, rbuf[i].cname);
+ gs_free(rbuf[i].mbuf, cols, 1, rbuf[i].mname);
+ gs_free(rbuf[i].ybuf, cols, 1, rbuf[i].yname);
+ rbuf[i].is_used = 0;
+ }
+ else
+ break;
+ }
+ gs_free( rbuf, rows, sizeof(cmyrow), "rb");
+ return;
+}
diff --git a/gs/src/gdevcdj.c b/gs/src/gdevcdj.c
new file mode 100644
index 000000000..152a66da1
--- /dev/null
+++ b/gs/src/gdevcdj.c
@@ -0,0 +1,3916 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcdj.c */
+/* H-P and Canon colour printer drivers */
+
+/****************************************************************
+ * The code in this file has gotten completely out of hand.
+ * Too many users have made too many "improvements" without
+ * regard to the overall structure; the last three "improvements"
+ * required me to spend several hours fixing each one so that
+ * the code worked again at all. For this reason, no further
+ * changes to this file will be accepted. I am planning eventually
+ * to get these drivers rewritten from scratch.
+ * L. Peter Deutsch
+ * Aladdin Enterprises
+ * February 28, 1996
+ ****************************************************************/
+
+/*
+ * Important compilation notes (YA).
+ *
+ * You may also try the cdj550cmyk driver after having defined
+ * USE_CDJ550_CMYK and added the needed definition in devs.mak. Not tried!
+ * (I have a BJC!) If you ty that, please report success/failure to me,
+ * Yves.Arrouye@imag.fr. Also note that modes descriptions of CMYK printing
+ * is done under the BJC section of devices.doc.
+ *
+ * CMYK to RGB conversion is made a la GhostScript unless you define
+ * the preprocessor symbol USE_ADOBE_CMYK_RGB.
+ *
+ * Ghostscript: R = (1.0 - C) * (1.0 - K)
+ * Adobe: R = 1.0 - min(1.0, C + K)
+ *
+ * (and similarly for G and B). Ghostscript claims its method achieves
+ * better results.
+ *
+ * For the BJC drivers, define BJC_DEFAULT_CENTEREDAREA if you want to
+ * have the same top and bottom margins (default to use the tallest
+ * imageable area available, usually with a top margin smaller than
+ * the bottom one). Defining USE_RECOMMENDED_MARGINS has the same
+ * effect and also sets these margins to 12.4 mm. Other compilation
+ * defines are explained in devices.doc.
+ *
+ * You can also define BJC_INIT_800_AS_600 to not use BJC-800-specific code
+ * in the page initialization sequence (normally not useful to you at all,
+ * just for my debugging of the driver margins).
+ *
+ */
+
+#include "std.h" /* to stop stdlib.h redefining types */
+#include <stdlib.h> /* for rand() */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+#include "gsparam.h"
+#include "gsstate.h"
+
+/* Conversion stuff. */
+#include "gxlum.h"
+
+/* Canon stuff */
+
+#include "gdevbjc.h"
+
+/***
+ *** This file contains multiple drivers. The main body of code, and all
+ *** but the DesignJet driver, were contributed by George Cameron;
+ *** please contact g.cameron@biomed.abdn.ac.uk if you have questions.
+ * 1 - cdj500: HP DeskJet 500C
+ * 2 - cdj550: HP DeskJet 550C
+ * 3 - pjxl300: HP PaintJet XL300
+ * 4 - pj: HP PaintJet
+ * 5 - pjxl: HP PaintJet XL
+ * 6 - declj250: DEC LJ250
+ *** The DesignJet 650C driver was contributed by Koert Zeilstra;
+ *** please contact koert@zen.cais.com if you have questions.
+ * 7 - dnj650c HP DesignJet 650C
+ *** The LaserJet 4 driver with dithering was contributed by Eckhard
+ *** Rueggeberg; please contact eckhard@ts.go.dlr.de if you have questions.
+ * 8 - lj4dith: HP LaserJet 4 with dithering
+ *** The ESC/P driver (for Epson ESC/P compatible printers) was written by
+ *** Yoshio Kuniyoshi <yoshio@nak.math.keio.ac.jp>, but is not maintained at
+ *** the moment.
+ * 9 - esc/p: Epson ESC/P-compatible printers
+ *** The BJC600 driver (which also works for BJC4000) was written first
+ *** by Yoshio Kuniyoshi <yoshio@nak.math.keio.ac.jp> and later modified by
+ *** Yves Arrouye <Yves.Arrouye@imag.fr>. The current driver has been
+ *** completely rewritten by me (YA) for good color handling.
+ * 10 - bjc600: BJC 600//4000 printers
+ *** The BJC800 driver is based on the bjc600 one. By YA too.
+ * 11 - bjc800: BJC 800 printer
+ ***/
+
+/*
+ * All of the HP-like drivers have 8-bit (monochrome), 16-bit and 24-bit
+ * (colour) and for the DJ 550C 32-bit, (colour, cmyk mode)
+ * options in addition to the usual 1-bit and 3-bit modes
+ * It is also possible to set various printer-specific parameters
+ * from the gs command line, eg.
+ *
+ * gs -sDEVICE=cdj550 -dBitsPerPixel=16 -dDepletion=1 -dShingling=2 tiger.ps
+ *
+ * Please consult the appropriate section in the devices.doc file for
+ * further details on all these drivers.
+ *
+ * All of the BJC-like drivers have 1-bit and 8-bit monochrome modes, 8-bit,
+ * 16-bit, 24-bit and 32-bit colour cmyk mode (the 8-bit monochrome mode
+ * is called "4-bit". If you want to add a CMYK printer, look at the
+ * bjc6000/bjc800 devices declarations and initialization.
+ *
+ * If you want to support different color components for the same depth
+ * on a non-CMYK printer, look how this is done for CMYK printers in
+ * cdj_set_bpp.
+ *
+ */
+
+/*
+ * This taken from gsdparam.c. I hope it will be useable directly some day.
+ *
+ */
+
+#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
+ switch ( ncode = pread(plist, (oname = pname), &pa) )\
+ {\
+ case 0:\
+ if ( pa.size != psize )\
+ code = gs_error_rangecheck;\
+ else {
+/* The body of the processing code goes here. */
+/* If it succeeds, it should do a 'break'; */
+/* if it fails, it should set ecode and fall through. */
+#define END_PARAM(pa, e)\
+ }\
+ goto e;\
+ default:\
+ code = ncode;\
+e: param_signal_error(plist, oname, code);\
+ case 1:\
+ pa.data = 0; /* mark as not filled */\
+ }
+
+private int cdj_param_check_bytes(P5(gs_param_list *, gs_param_name, const byte *, uint, bool));
+private int cdj_param_check_float(P4(gs_param_list *, gs_param_name, floatp, bool));
+#define cdj_param_check_string(plist, pname, str, defined)\
+ cdj_param_check_bytes(plist, pname, (const byte *)str, strlen(str), defined)
+
+/*
+ * Drivers stuff.
+ *
+ */
+
+#define DESKJET_PRINT_LIMIT 0.04 /* 'real' top margin? */
+#define PAINTJET_PRINT_LIMIT 0.0 /* This is a guess.. */
+#define ESC_P_PRINT_LIMIT 0.335
+
+/* Margins are left, bottom, right, top. */
+#define DESKJET_MARGINS_LETTER 0.25, 0.50, 0.25, 0.167
+#define DESKJET_MARGINS_A4 0.125, 0.50, 0.143, 0.167
+#define LJET4_MARGINS 0.26, 0.0, 0.0, 0.0
+/* The PaintJet and DesignJet seem to have the same margins */
+/* regardless of paper size. */
+#define PAINTJET_MARGINS 0.167, 0.167, 0.167, 0.167
+#define DESIGNJET_MARGINS 0.167, 0.167, 0.167, 0.167
+
+/*
+ * With ESC/P commands, BJC-600 can print no more than 8 inches width.
+ * So it can't use full width of letter size paper. Since non printable
+ * left side area is 0.134 inch, we set up margins as follows.
+ *
+ * Note to readers: the bjc drivers series do *not* use ESC/P commands
+ * but raster ops. Configuration of these drivers can be done through
+ * the gdevbjc.h file.
+ *
+ */
+#define ESC_P_MARGINS_LETTER 0.134, 0.276+0.2, 0.366+0.01, 0.335
+#define ESC_P_MARGINS_A4 0.134, 0.276+0.2, 0.166+0.01, 0.335
+
+/* Define bits-per-pixel for generic drivers - default is 24-bit mode */
+#ifndef BITSPERPIXEL
+# define BITSPERPIXEL 24
+#endif
+
+#define W sizeof(word)
+#define I sizeof(int)
+
+
+#define invert_word(v)\
+ ((v) >> 24) + (((v) >> 8) & 0xff00L) +\
+ (((word)(v) << 8) & 0xff0000L) + ((word)(v) << 24)
+
+
+/* Printer types */
+#define DJ500C 0
+#define DJ550C 1
+#define PJXL300 2
+#define PJ180 3
+#define PJXL180 4
+#define DECLJ250 5
+#define DNJ650C 6
+#define LJ4DITH 7
+#define ESC_P 8
+#define BJC600 9
+#define BJC800 10
+
+/* No. of ink jets (used to minimise head movements) */
+#define HEAD_ROWS_MONO 50
+#define HEAD_ROWS_COLOUR 16
+
+/* Colour mapping procedures */
+private dev_proc_map_cmyk_color (gdev_cmyk_map_cmyk_color);
+private dev_proc_map_rgb_color (gdev_cmyk_map_rgb_color);
+private dev_proc_map_color_rgb (gdev_cmyk_map_color_rgb);
+
+private dev_proc_map_rgb_color (gdev_pcl_map_rgb_color);
+private dev_proc_map_color_rgb (gdev_pcl_map_color_rgb);
+
+/* Print-page, parameters and miscellaneous procedures */
+private dev_proc_open_device(dj500c_open);
+private dev_proc_open_device(dj550c_open);
+private dev_proc_open_device(dnj650c_open);
+private dev_proc_open_device(lj4dith_open);
+private dev_proc_open_device(pj_open);
+private dev_proc_open_device(pjxl_open);
+private dev_proc_open_device(pjxl300_open);
+private dev_proc_open_device(escp_open);
+private dev_proc_open_device(bjc_open);
+
+private dev_proc_print_page(declj250_print_page);
+private dev_proc_print_page(dj500c_print_page);
+private dev_proc_print_page(dj550c_print_page);
+private dev_proc_print_page(dnj650c_print_page);
+private dev_proc_print_page(lj4dith_print_page);
+private dev_proc_print_page(pj_print_page);
+private dev_proc_print_page(pjxl_print_page);
+private dev_proc_print_page(pjxl300_print_page);
+private dev_proc_print_page(escp_print_page);
+private dev_proc_print_page(bjc_print_page);
+
+private dev_proc_get_params(cdj_get_params);
+private dev_proc_get_params(pjxl_get_params);
+private dev_proc_get_params(bjc_get_params);
+#define ep_get_params cdj_get_params
+
+private dev_proc_put_params(cdj_put_params);
+private dev_proc_put_params(pj_put_params);
+private dev_proc_put_params(pjxl_put_params);
+private dev_proc_put_params(bjc_put_params);
+#define ep_put_params cdj_put_params
+
+/* The device descriptors */
+
+#define gx_prn_colour_device_common \
+ gx_prn_device_common; \
+ short cmyk; /* 0: not CMYK-capable, > 0: printing CMYK, */ \
+ /* < 0 : CMYK-capable, not printing CMYK */ \
+ uint default_depth; /* Used only for CMYK-capable printers now. */ \
+ uint correction
+
+typedef struct gx_device_cdj_s gx_device_cdj;
+struct gx_device_cdj_s {
+ gx_device_common;
+ gx_prn_colour_device_common;
+ int shingling; /* Interlaced, multi-pass printing */
+ int depletion; /* 'Intelligent' dot-removal */
+};
+
+typedef struct gx_device_pjxl_s gx_device_pjxl;
+struct gx_device_pjxl_s {
+ gx_device_common;
+ gx_prn_colour_device_common;
+ int printqual; /* Mechanical print quality */
+ int rendertype; /* Driver or printer dithering control */
+};
+
+typedef struct gx_device_hp_s gx_device_hp;
+struct gx_device_hp_s {
+ gx_device_common;
+ gx_prn_colour_device_common;
+};
+
+typedef struct gx_device_hp_s gx_device_pj;
+
+typedef struct gx_device_bjc600_s gx_device_bjc600;
+typedef struct gx_device_bjc800_s gx_device_bjc800;
+
+typedef struct gx_device_bjc800_s gx_device_bjc;
+
+#define bjc_params_common \
+ bool manualFeed; /* Use manual feed */ \
+ int mediaType; /* Cf. strings below */ \
+ bool mediaWeight_isSet; /* Say if weight is an integer or null */ \
+ int mediaWeight; /* Weigth of the media */ \
+ int printQuality; /* Cf. strings below */ \
+ bool ditheringType; /* Do dithering */ \
+ int colorComponents; /* The number of *desired* color comps */ \
+ int printColors /* 0: Transparent, \
+ 1: C, 2: M, 4: Y, 7: K (Color decomp). \
+ if > 8, print in black ink. */
+
+typedef struct {
+ bjc_params_common;
+
+ bool monochromePrint; /* Print with black only */
+} bjc600_params;
+
+typedef struct {
+ bjc_params_common;
+} bjc_params;
+
+typedef bjc_params bjc800_params;
+
+#define gx_bjc_device_common \
+ gx_device_common; \
+ gx_prn_colour_device_common; \
+ int ptype; \
+ float printLimit
+
+struct gx_device_bjc600_s {
+ gx_bjc_device_common;
+ bjc600_params bjc_p;
+};
+struct gx_device_bjc800_s {
+ gx_bjc_device_common;
+ bjc800_params bjc_p;
+};
+
+typedef struct {
+ gx_device_common;
+ gx_prn_colour_device_common;
+} gx_device_colour_prn;
+
+/* Use the cprn_device macro to access generic fields (like cmyk,
+ default_depth and correction), and specific macros for specific
+ devices. */
+
+#define cprn_device ((gx_device_colour_prn*) pdev)
+
+#define cdj ((gx_device_cdj *)pdev)
+#define pjxl ((gx_device_pjxl *)pdev)
+#define pj ((gx_device_pj *)pdev)
+
+#define bjc ((gx_device_bjc*) pdev)
+#define bjc600 ((gx_device_bjc600*) pdev)
+#define bjc800 ((gx_device_bjc800*) pdev)
+
+#define bjcparams (bjc->bjc_p)
+#define bjc600params (bjc600->bjc_p)
+#define bjc800params (bjc800->bjc_p)
+
+#define bjcversion(p) (((gx_device_bjc*) pdev)->ptype == BJC800 ? \
+ BJC_BJC800_VERSION : BJC_BJC600_VERSION)
+#define bjcversionstring(p) (((gx_device_bjc*) pdev)->ptype == BJC800 ? \
+ BJC_BJC800_VERSIONSTR : BJC_BJC600_VERSIONSTR)
+
+#define bjcthickpaper(l) \
+ (bjcparams.mediaWeight_isSet && bjcparams.mediaWeight > l)
+#define bjc600thickpaper() bjcthickpaper(BJC600_MEDIAWEIGHT_THICKLIMIT)
+#define bjc800thickpaper() bjcthickpaper(BJC800_MEDIAWEIGHT_THICKLIMIT)
+
+/* The basic structure for all printers. Note the presence of the cmyk, depth
+ and correct fields even if soem are not used by all printers. */
+
+#define prn_colour_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page, cmyk, correct)\
+ prn_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page), cmyk, depth /* default */, correct
+
+/* Note: the computation of color_info values here must match */
+/* the computation in the cdj_set_bpp procedure below. */
+
+#define prn_hp_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\
+ prn_colour_device_body(dtype, procs, dev_name,\
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\
+ (bpp == 32 ? 4 : (bpp == 1 || bpp == 8) ? 1 : 3), bpp,\
+ (bpp >= 8 ? 255 : 1), (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0),\
+ (bpp >= 8 ? 5 : 2), (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0),\
+ print_page, 0 /* cmyk */, correct)
+
+#define prn_cmyk_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\
+ prn_colour_device_body(dtype, procs, dev_name,\
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\
+ ((bpp == 1 || bpp == 4) ? 1 : 4), bpp,\
+ (bpp > 8 ? 255 : 1), (1 << (bpp >> 2)) - 1, /* max_gray, max_color */\
+ (bpp > 8 ? 5 : 2), (bpp > 8 ? 5 : bpp > 1 ? 2 : 0),\
+ print_page, 1 /* cmyk */, correct)
+
+#define bjc_device(dtype, p, d, x, y, b, pp, c) \
+ prn_cmyk_colour_device(dtype, p, d, x, y, b, pp, c)
+
+#define cdj_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction, shingling, depletion)\
+{ prn_hp_colour_device(gx_device_cdj, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction),\
+ shingling,\
+ depletion\
+}
+
+#define pjxl_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, printqual, rendertype)\
+{ prn_hp_colour_device(gx_device_pjxl, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0), \
+ printqual,\
+ rendertype\
+}
+
+#define pj_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page)\
+{ prn_hp_colour_device(gx_device_pj, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0) }
+
+#define bjc600_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, t, mf, mt, mws, mw, pq, dt, cc, pc, mp) \
+{ bjc_device(gx_device_bjc600, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0),\
+ t, 0., { mf, mt, mws, mw, pq, dt, cc, pc, mp }\
+}
+#define bjc800_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, t, mf, mt, mws, mw, pq, dt, cc, pc) \
+{ bjc_device(gx_device_bjc800, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0),\
+ t, 0., { mf, mt, mws, mw, pq, dt, cc, pc }\
+}
+
+#define hp_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\
+ proc_colour_open,\
+ gx_default_get_initial_matrix,\
+ gx_default_sync_output,\
+ gdev_prn_output_page,\
+ gdev_prn_close,\
+ gdev_pcl_map_rgb_color,\
+ gdev_pcl_map_color_rgb,\
+ NULL, /* fill_rectangle */\
+ NULL, /* tile_rectangle */\
+ NULL, /* copy_mono */\
+ NULL, /* copy_color */\
+ NULL, /* draw_line */\
+ gx_default_get_bits,\
+ proc_get_params,\
+ proc_put_params\
+}
+
+#define cmyk_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\
+ proc_colour_open,\
+ gx_default_get_initial_matrix,\
+ gx_default_sync_output,\
+ gdev_prn_output_page,\
+ gdev_prn_close,\
+ NULL /* map_rgb_color */,\
+ gdev_cmyk_map_color_rgb,\
+ NULL /* fill_rectangle */,\
+ NULL /* tile_rectangle */,\
+ NULL /* copy_mono */,\
+ NULL /* copy_color */,\
+ NULL /* draw_line */,\
+ gx_default_get_bits,\
+ proc_get_params,\
+ proc_put_params,\
+ gdev_cmyk_map_cmyk_color\
+}
+
+private gx_device_procs cdj500_procs =
+hp_colour_procs(dj500c_open, cdj_get_params, cdj_put_params);
+
+private gx_device_procs cdj550_procs =
+hp_colour_procs(dj550c_open, cdj_get_params, cdj_put_params);
+
+#ifdef USE_CDJ550_CMYK
+private gx_device_procs cdj550cmyk_procs =
+cmyk_colour_procs(dj550c_open, cdj_get_params, cdj_put_params);
+#endif
+
+private gx_device_procs dnj650c_procs =
+hp_colour_procs(dnj650c_open, cdj_get_params, cdj_put_params);
+
+private gx_device_procs lj4dith_procs =
+hp_colour_procs(lj4dith_open, cdj_get_params, cdj_put_params);
+
+private gx_device_procs pj_procs =
+hp_colour_procs(pj_open, gdev_prn_get_params, pj_put_params);
+
+private gx_device_procs pjxl_procs =
+hp_colour_procs(pjxl_open, pjxl_get_params, pjxl_put_params);
+
+private gx_device_procs pjxl300_procs =
+hp_colour_procs(pjxl300_open, pjxl_get_params, pjxl_put_params);
+
+private gx_device_procs bjc_procs =
+cmyk_colour_procs(bjc_open, bjc_get_params, bjc_put_params);
+
+private gx_device_procs escp_procs =
+hp_colour_procs(escp_open, ep_get_params, ep_put_params);
+
+gx_device_cdj far_data gs_cdjmono_device =
+cdj_device(cdj500_procs, "cdjmono", 300, 300, 1,
+ dj500c_print_page, 4, 0, 1);
+
+gx_device_cdj far_data gs_cdeskjet_device =
+cdj_device(cdj500_procs, "cdeskjet", 300, 300, 3,
+ dj500c_print_page, 4, 2, 1);
+
+gx_device_cdj far_data gs_cdjcolor_device =
+cdj_device(cdj500_procs, "cdjcolor", 300, 300, 24,
+ dj500c_print_page, 4, 2, 1);
+
+gx_device_cdj far_data gs_cdj500_device =
+cdj_device(cdj500_procs, "cdj500", 300, 300, BITSPERPIXEL,
+ dj500c_print_page, 4, 2, 1);
+
+gx_device_cdj far_data gs_cdj550_device =
+cdj_device(cdj550_procs, "cdj550", 300, 300, BITSPERPIXEL,
+ dj550c_print_page, 0, 2, 1);
+
+#ifdef USE_CDJ550_CMYK
+gx_device_cdj far_data gs_cdj550cmyk_device = {
+ prn_cmyk_colour_device(cdj550cmyk_procs, "cdj550cmyk", 300, 300,
+ BITSPERPIXEL, dj550c_print_page, 0), 2, 1
+};
+#endif
+
+gx_device_pj far_data gs_declj250_device =
+pj_device(pj_procs, "declj250", 180, 180, BITSPERPIXEL,
+ declj250_print_page);
+
+gx_device_cdj far_data gs_dnj650c_device =
+cdj_device(dnj650c_procs, "dnj650c", 300, 300, BITSPERPIXEL,
+ dnj650c_print_page, 0, 2, 1);
+
+gx_device_cdj far_data gs_lj4dith_device =
+cdj_device(lj4dith_procs, "lj4dith", 600, 600, 8,
+ lj4dith_print_page, 4, 0, 1);
+
+gx_device_pj far_data gs_pj_device =
+pj_device(pj_procs, "pj", 180, 180, BITSPERPIXEL,
+ pj_print_page);
+
+gx_device_pjxl far_data gs_pjxl_device =
+pjxl_device(pjxl_procs, "pjxl", 180, 180, BITSPERPIXEL,
+ pjxl_print_page, 0, 0);
+
+gx_device_pjxl far_data gs_pjxl300_device =
+pjxl_device(pjxl300_procs, "pjxl300", 300, 300, BITSPERPIXEL,
+ pjxl300_print_page, 0, 0);
+
+gx_device_cdj far_data gs_escp_device =
+cdj_device(escp_procs, "escp", 360, 360, 8,
+ escp_print_page, 0, 0, 1);
+
+gx_device_cdj far_data gs_escpc_device =
+cdj_device(escp_procs, "escpc", 360, 360, 24,
+ escp_print_page, 0, 0, 1);
+
+/* Args of bjc drivers are manualFeed, mediaType, printQuality, printColor,
+ mediaWeight_isSet, mediaWeight, (monochromePrint) */
+
+gx_device_bjc600 far_data gs_bjc600_device =
+ bjc600_device(
+ bjc_procs,
+ BJC_BJC600,
+ BJC600_DEFAULT_RESOLUTION,
+ BJC600_DEFAULT_RESOLUTION,
+ BJC600_DEFAULT_BITSPERPIXEL,
+ bjc_print_page,
+ BJC600,
+ BJC600_DEFAULT_MANUALFEED,
+ BJC600_DEFAULT_MEDIATYPE,
+ BJC600_DEFAULT_SETMEDIAWEIGHT,
+ BJC600_DEFAULT_MEDIAWEIGHT,
+ BJC600_DEFAULT_PRINTQUALITY,
+ BJC600_DEFAULT_DITHERINGTYPE,
+ BJC600_DEFAULT_COLORCOMPONENTS,
+ BJC600_DEFAULT_PRINTCOLORS,
+ BJC600_DEFAULT_MONOCHROMEPRINT);
+
+gx_device_bjc800 far_data gs_bjc800_device =
+ bjc800_device(
+ bjc_procs,
+ BJC_BJC800,
+ BJC800_DEFAULT_RESOLUTION,
+ BJC800_DEFAULT_RESOLUTION,
+ BJC800_DEFAULT_BITSPERPIXEL,
+ bjc_print_page,
+ BJC800,
+ BJC800_DEFAULT_MANUALFEED,
+ BJC800_DEFAULT_MEDIATYPE,
+ BJC800_DEFAULT_SETMEDIAWEIGHT,
+ BJC800_DEFAULT_MEDIAWEIGHT,
+ BJC800_DEFAULT_PRINTQUALITY,
+ BJC800_DEFAULT_DITHERINGTYPE,
+ BJC600_DEFAULT_COLORCOMPONENTS,
+ BJC800_DEFAULT_PRINTCOLORS);
+
+/* Forward references */
+private int gdev_pcl_mode1compress(P3(const byte *, const byte *, byte *));
+private int gdev_pcl_mode9compress(P4(int, const byte *, const byte *, byte *));
+private int hp_colour_open(P2(gx_device *, int));
+private int hp_colour_print_page(P3(gx_device_printer *, FILE *, int));
+private int near cdj_put_param_int(P6(gs_param_list *, gs_param_name, int *, int, int, int));
+private uint gdev_prn_rasterwidth(P2(const gx_device_printer *, int));
+private int cdj_put_param_bpp(P5(gx_device *, gs_param_list *, int, int, int));
+private int cdj_set_bpp(P3(gx_device *, int, int));
+private void cdj_expand_line(P5(word *, int, short, int, int));
+private int bjc_fscmyk(P5(byte**, byte*[4][4], int**, int, int));
+
+/* String parameters manipulation */
+
+typedef struct {
+ const char* p_name;
+ int p_value;
+} stringParamDescription;
+
+private const byte* paramValueToString(P2(const stringParamDescription*, int));
+private int paramStringValue(P4(const stringParamDescription*,
+ const byte*, int, int*));
+
+private int put_param_string(P6(gs_param_list*, const byte*,
+ gs_param_string*, const stringParamDescription*, int *, int));
+private int get_param_string(P7(gs_param_list*, const byte*,
+ gs_param_string*, const stringParamDescription*, int, bool, int));
+
+/* Open the printer and set up the margins. */
+private int
+dj500c_open(gx_device *pdev)
+{ return hp_colour_open(pdev, DJ500C);
+}
+
+private int
+dj550c_open(gx_device *pdev)
+{ return hp_colour_open(pdev, DJ550C);
+}
+
+private int
+dnj650c_open(gx_device *pdev)
+{ return hp_colour_open(pdev, DNJ650C);
+}
+
+private int
+lj4dith_open(gx_device *pdev)
+{ return hp_colour_open(pdev, LJ4DITH);
+}
+
+private int
+pjxl300_open(gx_device *pdev)
+{ return hp_colour_open(pdev, PJXL300);
+}
+
+private int
+pj_open(gx_device *pdev)
+{ return hp_colour_open(pdev, PJ180);
+}
+
+private int
+pjxl_open(gx_device *pdev)
+{ return hp_colour_open(pdev, PJXL180);
+}
+
+private int
+escp_open(gx_device *pdev)
+{ return hp_colour_open(pdev, ESC_P);
+}
+
+private int
+bjc_open(gx_device *pdev)
+{ return hp_colour_open(pdev, bjc->ptype);
+}
+
+private int
+hp_colour_open(gx_device *pdev, int ptype)
+{ /* Change the margins if necessary. */
+ static const float dj_a4[4] = { DESKJET_MARGINS_A4 };
+ static const float dj_letter[4] = { DESKJET_MARGINS_LETTER };
+ static const float lj4_all[4] = { LJET4_MARGINS };
+ static const float pj_all[4] = { PAINTJET_MARGINS };
+ static const float dnj_all[4] = { DESIGNJET_MARGINS };
+ static const float ep_a4[4] = { ESC_P_MARGINS_A4 };
+ static const float ep_letter[4] = { ESC_P_MARGINS_LETTER };
+
+ static float bjc_a3[4] = { BJC_MARGINS_A3 }; /* Not const! */
+ static float bjc_letter[4] = { BJC_MARGINS_LETTER }; /* Not const! */
+ static float bjc_a4[4] = { BJC_MARGINS_A4 }; /* Not const! */
+
+ const float _ds *m = (float _ds*) 0;
+
+ /* Set up colour params if put_params has not already done so */
+ if (pdev->color_info.num_components == 0)
+ { int code = cdj_set_bpp(pdev, pdev->color_info.depth,
+ pdev->color_info.num_components);
+ if ( code < 0 )
+ return code;
+ }
+
+ switch (ptype) {
+ case DJ500C:
+ case DJ550C:
+ m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? dj_a4 :
+ dj_letter);
+ break;
+ case DNJ650C:
+ m = dnj_all;
+ break;
+ case LJ4DITH:
+ m = lj4_all;
+ break;
+ case PJ180:
+ case PJXL300:
+ case PJXL180:
+ m = pj_all;
+ break;
+ case ESC_P:
+ m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? ep_a4 :
+ ep_letter);
+ break;
+ case BJC600:
+ case BJC800:
+ switch (gdev_pcl_paper_size(pdev)) {
+ case PAPER_SIZE_LEGAL:
+ case PAPER_SIZE_LETTER:
+ m = bjc_letter;
+ break;
+
+ case PAPER_SIZE_A0:
+ case PAPER_SIZE_A1:
+ case PAPER_SIZE_A3:
+ m = bjc_a3;
+ break;
+
+ default:
+ m = bjc_a4;
+ }
+
+#ifndef USE_FIXED_MARGINS
+ if (ptype == BJC800) {
+ ((float _ds*) m)[1] = BJC_HARD_LOWER_LIMIT;
+ }
+#endif
+
+ bjc->printLimit = m[3]; /* The real hardware limit. */
+
+#ifdef BJC_DEFAULT_CENTEREDAREA
+ if (m[3] < m[1]) {
+ ((float _ds*) m)[3] = m[1]; /* Top margin = bottom one. */
+ } else {
+ ((float _ds*) m)[1] = m[3]; /* Bottom margin = top one. */
+ }
+#endif
+
+ break;
+
+ /*NOTREACHED*/
+
+ /*
+ * The margins must be set so that the resulting page length will be
+ * expressed exactly as a multiple of tenthes of inches.
+ *
+ */
+
+ /**/ {
+ float _ds *bjcm = (float _ds*) m;
+
+ byte pdimen = (byte)
+ (pdev->height / pdev->y_pixels_per_inch * 10.
+ - bjcm[3] * 10. - bjcm[1] * 10. + .5) + 1;
+ do {
+ --pdimen;
+ bjcm[1] = pdev->height / pdev->y_pixels_per_inch
+ - bjcm[3] - (float) pdimen / 10.;
+ } while (bjcm[1] < BJC_LOWER_LIMIT);
+ }
+
+ break;
+ }
+ gx_device_set_margins(pdev, m, true);
+ return gdev_prn_open(pdev);
+}
+
+/* Added parameters for DeskJet 5xxC */
+
+/* Get parameters. In addition to the standard and printer
+ * parameters, we supply shingling and depletion parameters,
+ * and control over the bits-per-pixel used in output rendering */
+private int
+cdj_get_params(gx_device *pdev, gs_param_list *plist)
+{ int code = gdev_prn_get_params(pdev, plist);
+ if ( code < 0 ||
+ (code = param_write_int(plist, "BlackCorrect", (int *)&cdj->correction)) < 0 ||
+ (code = param_write_int(plist, "Shingling", &cdj->shingling)) < 0 ||
+ (code = param_write_int(plist, "Depletion", &cdj->depletion)) < 0
+ )
+ return code;
+
+ return code;
+}
+
+/* Put parameters. */
+private int
+cdj_put_params(gx_device *pdev, gs_param_list *plist)
+{ int correction = cdj->correction;
+ int shingling = cdj->shingling;
+ int depletion = cdj->depletion;
+ int bpp = 0;
+ int code = 0;
+
+ code = cdj_put_param_int(plist, "BlackCorrect", &correction, 0, 9, code);
+ code = cdj_put_param_int(plist, "Shingling", &shingling, 0, 2, code);
+ code = cdj_put_param_int(plist, "Depletion", &depletion, 1, 3, code);
+ code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);
+
+ if ( code < 0 )
+ return code;
+ code = cdj_put_param_bpp(pdev, plist, bpp, bpp, 0);
+ if ( code < 0 )
+ return code;
+
+ cdj->correction = correction;
+ cdj->shingling = shingling;
+ cdj->depletion = depletion;
+ return 0;
+}
+
+/* Added parameters for PaintJet XL and PaintJet XL300 */
+
+/* Get parameters. In addition to the standard and printer
+ * parameters, we supply print_quality and render_type
+ * parameters, together with bpp control. */
+private int
+pjxl_get_params(gx_device *pdev, gs_param_list *plist)
+{ int code = gdev_prn_get_params(pdev, plist);
+ if ( code < 0 ||
+ (code = param_write_int(plist, "PrintQuality", &pjxl->printqual)) < 0 ||
+ (code = param_write_int(plist, "RenderType", &pjxl->rendertype)) < 0
+ )
+ return code;
+
+ return code;
+}
+
+/* Put parameters. */
+private int
+pjxl_put_params(gx_device *pdev, gs_param_list *plist)
+{ int printqual = pjxl->printqual;
+ int rendertype = pjxl->rendertype;
+ int bpp = 0, real_bpp = 0;
+ int code = 0;
+
+ code = cdj_put_param_int(plist, "PrintQuality", &printqual, -1, 1, code);
+ code = cdj_put_param_int(plist, "RenderType", &rendertype, 0, 10, code);
+ code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);
+
+ if ( code < 0 )
+ return code;
+ real_bpp = bpp;
+ if ( rendertype > 0 )
+ { /* If printer is doing the dithering, we must have a
+ * true-colour mode, ie. 16 or 24 bits per pixel */
+ if ( bpp > 0 && bpp < 16 )
+ real_bpp = 24;
+ }
+ code = cdj_put_param_bpp(pdev, plist, bpp, real_bpp, 0);
+ if ( code < 0 )
+ return code;
+
+ pjxl->printqual = printqual;
+ pjxl->rendertype = rendertype;
+ return 0;
+}
+
+/* Added parameters for PaintJet */
+
+/* Put parameters. In addition to the standard and printer */
+/* parameters, we allow control of the bits-per-pixel */
+private int
+pj_put_params(gx_device *pdev, gs_param_list *plist)
+{ int bpp = 0;
+ int code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, 0);
+
+ if ( code < 0 )
+ return code;
+ return cdj_put_param_bpp(pdev, plist, bpp, bpp, 0);
+}
+
+private stringParamDescription bjc_processColorsStrings[] = {
+ { "DeviceGray", 1 },
+ { "DeviceRGB", 3 },
+ { "DeviceCMYK", 4 },
+ { 0 }
+};
+
+private stringParamDescription bjc_mediaTypeStrings[] = {
+ { "PlainPaper", BJC_MEDIA_PLAINPAPER },
+ { "CoatedPaper", BJC_MEDIA_COATEDPAPER },
+ { "TransparencyFilm", BJC_MEDIA_TRANSPARENCYFILM },
+ { "Envelope", BJC_MEDIA_ENVELOPE },
+ { "Card", BJC_MEDIA_CARD},
+ { "Other", BJC_MEDIA_OTHER },
+ { 0 }
+};
+
+private stringParamDescription bjc600_printQualityStrings[] = {
+ { "Normal", 0 },
+ { "High", 1 },
+ { "Draft", 2 },
+ { 0 }
+};
+
+private stringParamDescription bjc800_printQualityStrings[] = {
+ { "Normal", 0 },
+ { "High", 1 },
+ { "Low", 3 },
+ { "Draft", 4 },
+ { 0 },
+};
+
+private stringParamDescription bjc_ditheringTypeStrings[] = {
+ { "None", BJC_DITHER_NONE },
+ { "Floyd-Steinberg", BJC_DITHER_FS },
+ { 0 }
+};
+
+private int
+bjc_get_params(gx_device *pdev, gs_param_list *plist)
+{
+ int code = gdev_prn_get_params(pdev, plist);
+ int ncode;
+
+ gs_param_string pmedia;
+ gs_param_string pquality;
+ gs_param_string dithering;
+
+ if (code < 0) return_error(code);
+
+ if ((ncode = param_write_bool(plist, BJC_OPTION_MANUALFEED,
+ &bjcparams.manualFeed)) < 0) {
+ code = ncode;
+ }
+
+ code = get_param_string(plist, (unsigned char *)BJC_OPTION_MEDIATYPE, &pmedia,
+ bjc_mediaTypeStrings, bjcparams.mediaType, true, code);
+
+ code = get_param_string(plist, (unsigned char *)BJC_OPTION_PRINTQUALITY, &pquality,
+ (bjc->ptype == BJC800 ? bjc800_printQualityStrings :
+ bjc600_printQualityStrings), bjcparams.printQuality,
+ true, code);
+
+ code = get_param_string(plist, (unsigned char *)BJC_OPTION_DITHERINGTYPE, &dithering,
+ bjc_ditheringTypeStrings, bjcparams.ditheringType, true, code);
+
+ if ((ncode = param_write_int(plist, BJC_OPTION_PRINTCOLORS,
+ &bjcparams.printColors)) < 0) {
+ code = ncode;
+ }
+
+ if ((ncode = (bjcparams.mediaWeight_isSet ?
+ param_write_int(plist, BJC_OPTION_MEDIAWEIGHT,
+ &bjcparams.mediaWeight) :
+ param_write_null(plist, BJC_OPTION_MEDIAWEIGHT))) < 0) {
+ code = ncode;
+ }
+
+ if (bjc->ptype != BJC800) {
+ if ((ncode = param_write_bool(plist, BJC_OPTION_MONOCHROMEPRINT,
+ &bjc600params.monochromePrint)) < 0) {
+ code = ncode;
+ }
+ }
+
+ /**/ {
+ float version;
+ gs_param_string versionString;
+
+ bool bTrue = true;
+
+ version = bjcversion(pdev);
+ versionString.data = (byte *)bjcversionstring(pdev);
+
+ versionString.size = strlen((char *)versionString.data);
+ versionString.persistent = true;
+
+ if ((ncode = param_write_float(plist, BJC_DEVINFO_VERSION,
+ &version)) < 0) {
+ code = ncode;
+ }
+ if ((ncode = param_write_string(plist, BJC_DEVINFO_VERSIONSTRING,
+ &versionString)) < 0) {
+ code = ncode;
+ }
+
+ if ((ncode = param_write_bool(plist, BJC_DEVINFO_OUTPUTFACEUP,
+ &bTrue)) < 0) {
+ code = ncode;
+ }
+ }
+
+ return code;
+}
+
+/* Put properties for the bjc drivers. */
+
+private int
+bjc_put_params(gx_device *pdev, gs_param_list *plist)
+{
+ int bpp = 0, ccomps = 0;
+
+ int code = 0;
+ int ncode;
+
+ bool aBool = true;
+
+ const char* oname = (const char*) 0;
+
+ bjc600_params new600Params;
+ bjc800_params new800Params;
+
+ bjc_params* params;
+
+ gs_param_string pprocesscolors;
+ gs_param_string pmedia;
+ gs_param_string pquality;
+
+ gs_param_float_array hwra;
+
+ if (bjc->ptype != BJC800) {
+ new600Params = bjc600params;
+ params = (bjc_params*) &new600Params;
+ } else {
+ new800Params = bjc800params;
+ params = (bjc_params*) &new800Params;
+ }
+
+ if ((code = cdj_put_param_int(plist, "BitsPerPixel",
+ &bpp, 1, 32, code)) != 1) {
+ bpp = pdev->color_info.depth;
+ }
+
+ if ((code = put_param_string(plist, (unsigned char *)"ProcessColorModel",
+ &pprocesscolors, bjc_processColorsStrings, &ccomps, code)) != 1) {
+ ccomps = pdev->color_info.num_components;
+ }
+
+ if ((ncode = param_read_bool(plist, oname = BJC_OPTION_MANUALFEED,
+ &params->manualFeed)) < 0) {
+ param_signal_error(plist, oname, code = ncode);
+ }
+
+ code = put_param_string(plist, (unsigned char *)BJC_OPTION_MEDIATYPE, &pmedia,
+ bjc_mediaTypeStrings, &params->mediaType, code);
+
+ code = cdj_put_param_int(plist, BJC_OPTION_PRINTCOLORS,
+ &params->printColors, 0, 15, code);
+
+ code = put_param_string(plist, (unsigned char *)BJC_OPTION_PRINTQUALITY, &pquality,
+ (bjc->ptype == BJC800 ? bjc800_printQualityStrings :
+ bjc600_printQualityStrings), &params->printQuality, code);
+
+ switch (ncode = param_read_int(plist,
+ oname = BJC_OPTION_MEDIAWEIGHT, &params->mediaWeight)) {
+ case 0:
+ if (params->mediaWeight <= 0) {
+ ncode = gs_error_rangecheck;
+ } else {
+ params->mediaWeight_isSet = 1;
+ break;
+ }
+ goto mwe;
+
+ default:
+ if ((ncode = param_read_null(plist, oname)) == 0) {
+ params->mediaWeight_isSet = 0;
+ break;
+ }
+mwe: param_signal_error(plist, oname, code = ncode);
+
+ case 1:
+ break;
+ }
+
+ if (bjc->ptype != BJC800) {
+ bjc600_params* params600 = (bjc600_params*) params;
+ if ((ncode = param_read_bool(plist,
+ oname = BJC_OPTION_MONOCHROMEPRINT,
+ &params600->monochromePrint)) < 0) {
+ param_signal_error(plist, oname, code = ncode);
+ }
+ }
+
+ if ((ncode = cdj_param_check_float(plist, BJC_DEVINFO_VERSION,
+ bjcversion(pdev), true)) < 0) {
+ code = ncode;
+ }
+ if ((ncode = cdj_param_check_string(plist, BJC_DEVINFO_VERSIONSTRING,
+ bjcversionstring(pdev), true)) < 0) {
+ code = ncode;
+ }
+
+ if ((ncode = param_read_bool(plist, oname = BJC_DEVINFO_OUTPUTFACEUP,
+ &aBool)) < 0) {
+ param_signal_error(plist, oname, code = ncode);
+ } else if (aBool != true) {
+ param_signal_error(plist, oname, code = ncode = gs_error_rangecheck);
+ }
+
+ /* Check for invalid resolution. The array macros are taken from
+ gsdparam.c and modified to use oname, ncode and code instead
+ of param_name, code and ecode respectively. */
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
+ if ( hwra.data[0] <= 0 || hwra.data[1] <= 0 ||
+ hwra.data[0] != hwra.data[1] )
+ ncode = gs_error_rangecheck;
+ else {
+#ifdef BJC_STRICT
+ if (hwra.data[0] != BJC_RESOLUTION_LOW &&
+ hwra.data[0] != BJC_RESOLUTION_NORMAL &&
+ hwra.data[0] != BJC_RESOLUTION_HIGH) {
+ ncode = gs_error_rangecheck;
+ }
+#else
+ /* A small hack for checking resolution without logarithms. */
+
+ /**/ {
+ int n;
+
+ for (n = 0; n < 8 * sizeof(n) / BJC_RESOLUTION_BASE; ++n) {
+ float res = BJC_RESOLUTION_BASE * (1 << n);
+
+ if (res == hwra.data[0]) break;
+
+ if (res > hwra.data[0]) {
+ ncode = gs_error_rangecheck;
+ }
+ }
+
+ if (n == 8 * sizeof(n)) {
+ ncode = gs_error_rangecheck;
+ }
+ }
+#endif
+ if (ncode < 0) {
+ code = ncode;
+ } else {
+ break;
+ }
+ }
+ END_PARAM(hwra, hwre)
+
+ if ((ncode = cdj_put_param_bpp(pdev, plist, bpp, bpp, ccomps)) < 0) {
+ code = ncode;
+ }
+
+ if (code < 0)
+ return code;
+
+ if (bpp == 1) {
+ params->ditheringType = BJC_DITHER_NONE;
+ }
+
+ /* Write values that did change */
+
+ if (bjc->ptype != BJC800) {
+ bjc600params = new600Params;
+ } else {
+ bjc800params = new800Params;
+ }
+
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/* The DeskJet500C can compress (mode 9) */
+private int
+dj500c_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, DJ500C);
+}
+
+/* The DeskJet550C can compress (mode 9) */
+private int
+dj550c_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, DJ550C);
+}
+
+/* The DesignJet650C can compress (mode 1) */
+private int
+dnj650c_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, DNJ650C);
+}
+
+private int
+lj4dith_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, LJ4DITH);
+}
+
+/* The PJXL300 can compress (modes 2 & 3) */
+private int
+pjxl300_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{ int ret_code;
+ /* Ensure we're operating in PCL mode */
+ fputs("\033%-12345X@PJL enter language = PCL\n", prn_stream);
+ ret_code = hp_colour_print_page(pdev, prn_stream, PJXL300);
+ /* Reenter switch-configured language */
+ fputs("\033%-12345X", prn_stream);
+ return ret_code;
+}
+
+/* The PaintJet XL can compress (modes 2 & 3) */
+private int
+pjxl_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, PJXL180);
+}
+
+/* The PaintJet can compress (mode 1) */
+private int
+pj_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, PJ180);
+}
+
+/* The LJ250 can compress (mode 1) */
+private int
+declj250_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{ int ret_code;
+ fputs("\033%8", prn_stream); /* Enter PCL emulation mode */
+ ret_code = hp_colour_print_page(pdev, prn_stream, DECLJ250);
+ fputs("\033%@", prn_stream); /* Exit PCL emulation mode */
+ return ret_code;
+}
+
+/* The BJC-600 cannot compress w/o raster image commands. */
+private int
+escp_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, ESC_P);
+}
+
+/* The BJC-600 can compress w/ raster image commands. */
+private int
+bjc_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ return hp_colour_print_page(pdev, prn_stream, bjc->ptype);
+}
+
+/* MACROS FOR DITHERING (we use macros for compact source and faster code) */
+/* Floyd-Steinberg dithering. Often results in a dramatic improvement in
+ * subjective image quality, but can also produce dramatic increases in
+ * amount of printer data generated and actual printing time!! Mode 9 2D
+ * compression is still useful for fairly flat colour or blank areas but its
+ * compression is much less effective in areas where the dithering has
+ * effectively randomised the dot distribution. */
+
+#define SHIFT ((I * 8) - 13)
+#define RSHIFT ((I * 8) - 16)
+#define RANDOM (((rand() << RSHIFT) % (MAXVALUE / 2)) - MAXVALUE / 4);
+#define MINVALUE 0
+#define MAXVALUE (255 << SHIFT)
+#define THRESHOLD (128 << SHIFT)
+#define C 8
+
+#define FSdither(inP, out, errP, Err, Bit, Offset, Element)\
+ oldErr = Err;\
+ Err = (errP[Element] + ((Err * 7 + C) >> 4) + ((int)inP[Element] << SHIFT));\
+ if (Err > THRESHOLD) {\
+ out |= Bit;\
+ Err -= MAXVALUE;\
+ }\
+ errP[Element + Offset] += ((Err * 3 + C) >> 4);\
+ errP[Element] = ((Err * 5 + oldErr + C) >> 4);
+
+/* Here we rely on compiler optimisation to remove lines of the form
+ * (if (1 >= 4) {...}, ie. the constant boolean expressions */
+
+/* The original code is in the #else part. Since by default NEW_DITHER
+ is not defined, the old code is used. No enhancement is visible for the
+ bjc600 drivers with the new code, anyway :-( */
+
+#ifdef NEW_DITHER
+
+#define FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, n)\
+{\
+ if (scan == 0) { /* going_up */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ int oldErr;\
+ bitmask = 0x80;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
+ if (n >= 4) {\
+ FSdither(dp, k, ep, kErr, bitmask, -n, 0);\
+ }\
+ if (n >= 3) {\
+ FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
+ FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
+ }\
+ FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
+ dp += n, ep += n;\
+ }\
+ if (n >= 4)\
+ *kP++ = k;\
+ if (n >= 3) {\
+ *cP++ = c;\
+ *mP++ = m;\
+ }\
+ *yP++ = y;\
+ }\
+ } else { /* going_down */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ int oldErr;\
+ bitmask = 0x01;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
+ dp -= n, ep -= n;\
+ FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
+ if (n >= 3) {\
+ FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
+ FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
+ }\
+ if (n >= 4) {\
+ FSdither(dp, k, ep, kErr, bitmask, n, 0);\
+ }\
+ }\
+ *--yP = y;\
+ if (n >= 3)\
+ { *--mP = m;\
+ *--cP = c;\
+ }\
+ if (n >= 4)\
+ *--kP = k;\
+ }\
+ }\
+}
+
+#else
+
+#define FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, n)\
+{\
+ if (scan == 0) { /* going_up */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ int oldErr;\
+ bitmask = 0x80;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
+ if (n >= 4) {\
+ if (*dp) {\
+ FSdither(dp, k, ep, kErr, bitmask, -n, 0);\
+ cErr = mErr = yErr = 0;\
+ } else {\
+ FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
+ FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
+ FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
+ }\
+ } else {\
+ if (n >= 3) {\
+ FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
+ FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
+ }\
+ FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
+ }\
+ dp += n, ep += n;\
+ }\
+ if (n >= 4)\
+ *kP++ = k;\
+ if (n >= 3) {\
+ *cP++ = c;\
+ *mP++ = m;\
+ }\
+ *yP++ = y;\
+ }\
+ } else { /* going_down */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ int oldErr;\
+ bitmask = 0x01;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
+ dp -= n, ep -= n;\
+ if (n >= 4) {\
+ if (*dp) {\
+ FSdither(dp, k, ep, kErr, bitmask, n, 0);\
+ cErr = mErr = yErr = 0;\
+ } else {\
+ FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
+ FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
+ FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
+ }\
+ } else {\
+ FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
+ if (n >= 3) {\
+ FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
+ FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
+ }\
+ }\
+ }\
+ *--yP = y;\
+ if (n >= 3)\
+ { *--mP = m;\
+ *--cP = c;\
+ }\
+ if (n >= 4)\
+ *--kP = k;\
+ }\
+ }\
+}
+
+#endif
+
+/* END MACROS FOR DITHERING */
+
+#define CPbit(inP, out, Bit, Element)\
+ if (inP[Element]) {\
+ out |= Bit;\
+ }
+
+#define COPYline(scan, i, j, plane_size, cP, mP, yP, kP, n)\
+{\
+ if (scan == 0) { /* going_up */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ bitmask = 0x80;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
+ if (n >= 4) {\
+ CPbit(dp, k, bitmask, 0);\
+ } \
+ if (n >= 3) {\
+ CPbit(dp, c, bitmask, n - 3);\
+ CPbit(dp, m, bitmask, n - 2);\
+ }\
+ CPbit(dp, y, bitmask, n - 1);\
+ dp += n, ep += n;\
+ }\
+ if (n >= 4)\
+ *kP++ = k;\
+ if (n >= 3) {\
+ *cP++ = c;\
+ *mP++ = m;\
+ }\
+ *yP++ = y;\
+ }\
+ } else { /* going_down */\
+ for (i = 0; i < plane_size; i++) {\
+ byte c, y, m, k, bitmask;\
+ bitmask = 0x01;\
+ for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
+ dp -= n, ep -= n;\
+ if (n >= 4) {\
+ CPbit(dp, k, bitmask, 0);\
+ }\
+ if (n >= 3) {\
+ CPbit(dp, m, bitmask, n - 2);\
+ CPbit(dp, c, bitmask, n - 3);\
+ }\
+ CPbit(dp, y, bitmask, n - 1);\
+ }\
+ *--yP = y;\
+ if (n >= 3)\
+ { *--mP = m;\
+ *--cP = c;\
+ }\
+ if (n >= 4)\
+ *--kP = k;\
+ }\
+ }\
+}
+
+/* Some convenient shorthand .. */
+#define x_dpi (pdev->x_pixels_per_inch)
+#define y_dpi (pdev->y_pixels_per_inch)
+#define CONFIG_16BIT "\033*v6W\000\003\000\005\006\005"
+#define CONFIG_24BIT "\033*v6W\000\003\000\010\010\010"
+
+/* To calculate buffer size as next greater multiple of both parameter and W */
+#define calc_buffsize(a, b) (((((a) + ((b) * W) - 1) / ((b) * W))) * W)
+
+
+/*
+ * Miscellaneous functions for Canon BJC-600 printers in raster command mode.
+ */
+#define fputshort(n, f) fputc((n)%256,f);fputc((n)/256,f)
+
+private int
+bjc_cmd(byte cmd, int argsize, byte* arg, gx_device_printer* pdev,
+ FILE* stream)
+{
+ fputs("\033(", stream);
+ putc(cmd, stream);
+ fputshort(argsize, stream);
+ fwrite(arg, sizeof(byte), argsize, stream);
+
+ return 0;
+}
+
+
+private int
+bjc_raster_cmd_sub(char c, int rastsize, byte* data, FILE* stream)
+{
+ fputs("\033(A", stream);
+ fputshort(rastsize + 1, stream);
+ putc(c, stream);
+ fwrite(data, sizeof(byte), rastsize, stream);
+ putc('\015', stream);
+
+ return 0;
+}
+
+private int
+bjc_raster_cmd(int c_id, int rastsize, byte* data, gx_device_printer* pdev,
+ FILE* stream)
+{
+ if (bjcparams.printColors == BJC_COLOR_ALLBLACK) {
+ bjc_raster_cmd_sub('K', rastsize, data, stream);
+ } else if (pdev->color_info.num_components == 1) {
+ if (bjcparams.printColors & BJC_COLOR_BLACK) {
+ bjc_raster_cmd_sub('K', rastsize, data, stream);
+ } else {
+ if (bjcparams.printColors & BJC_COLOR_YELLOW)
+ bjc_raster_cmd_sub('Y', rastsize, data, stream);
+ if (bjcparams.printColors & BJC_COLOR_MAGENTA)
+ bjc_raster_cmd_sub('M', rastsize, data, stream);
+ if (bjcparams.printColors & BJC_COLOR_CYAN)
+ bjc_raster_cmd_sub('C', rastsize, data, stream);
+ }
+ }else { /* Color decomposition */
+ private byte ymckCodes[] = {
+ BJC_COLOR_YELLOW,
+ BJC_COLOR_MAGENTA,
+ BJC_COLOR_CYAN,
+ BJC_COLOR_BLACK,
+ };
+
+ if (bjcparams.printColors & (int) ymckCodes[c_id]) {
+ bjc_raster_cmd_sub("YMCK"[c_id], rastsize, data, stream);
+ }
+ }
+
+ return 0;
+}
+
+private int
+bjc_init_page(gx_device_printer* pdev, FILE* stream)
+{
+ byte pagemargins[3], resolution[2], paperloading[2];
+
+ /* Compute page margins. */
+
+ pagemargins[0] = (byte) ((float) pdev->height / pdev->y_pixels_per_inch
+ * 10 + .5);
+ pagemargins[1] = (byte) 1;
+ pagemargins[2] = (byte) ((pdev->width / pdev->x_pixels_per_inch * 10) -
+ pdev->HWMargins[0] / 7.2 - pdev->HWMargins[2] / 7.2 + .5);
+
+ /* Cheat to keep margins into bounds (while waiting to have the right
+ margins for big papers. */
+
+ switch (bjc->ptype) {
+ case BJC800:
+ if (pagemargins[2] > 114) pagemargins[2] = 114;
+ break;
+
+ default:
+ if (pagemargins[2] > 80) pagemargins[2] = 80;
+ break;
+ }
+
+ /* Initialize resolution argument. */
+
+ resolution[0] = (byte) ((int)pdev->x_pixels_per_inch / 256);
+ resolution[1] = (byte) ((int)pdev->x_pixels_per_inch % 256);
+
+ /* Initialize paper loading argument. */
+
+ paperloading[0] = 0x10 + ((1 - bjcparams.manualFeed) << 2);
+ paperloading[1] = bjcparams.mediaType << 4;
+
+ /* Reinitialize printer in raster mode. */
+
+ fputs("\033[K", stream);
+ fputshort(2, stream);
+ fputc(0x00, stream);
+ fputc(0x0f, stream);
+
+ /* Set page mode on (ignore data at end of page) */
+
+ bjc_cmd('a', 1, (byte*) "\001", pdev, stream);
+
+ /* Set page margins */
+
+ bjc_cmd('g', 3, pagemargins, pdev, stream);
+
+ /* Set compression on (this is PackBits compression a la TIFF/Mac) */
+
+ bjc_cmd('b', 1, (byte*) "\001", pdev, stream);
+
+ /* Set paper loading. */
+
+ bjc_cmd('l', 2, paperloading, pdev, stream);
+
+ /* Set printing method. */
+
+#ifndef BJC_INIT_800_AS_600
+ if (bjc->ptype == BJC800) {
+#else
+ if (0) {
+#endif
+ byte printmode[2];
+
+ printmode[0] = bjcparams.printQuality;
+
+ /* Modes not used are 3 (CN, Color Normal) and 2 (TP+ (?)) */
+
+ switch (bjcparams.printQuality) {
+ case BJC_QUALITY_DRAFT:
+ printmode[0] = 4; /* Draft */
+ break;
+ }
+
+ printmode[1] = (bjcparams.mediaType >= BJC_MEDIA_ENVELOPE ? 1 :
+ bjc800thickpaper());
+
+ bjc_cmd('c', 2, printmode, pdev, stream);
+ } else /* BJC600 */ {
+ byte printmeth[3];
+
+ printmeth[0] = 0x10 + ((1 - bjcparams.manualFeed) << 2);
+ printmeth[1] = (bjcparams.mediaType << 4) + bjcparams.printQuality;
+ printmeth[2] = (bjcparams.printQuality == BJC_QUALITY_HIGH ?
+ 0x10 : 0) + (bjcparams.mediaType >= BJC_MEDIA_ENVELOPE ? 1 :
+ bjc600thickpaper());
+
+ bjc_cmd('c', 3, printmeth, pdev, stream);
+ }
+
+ /* Set raster resolution */
+
+ bjc_cmd('d', 2, resolution, pdev, stream);
+
+ return 0;
+}
+
+private int
+bjc_v_skip(int n, gx_device_printer* pdev, FILE* stream)
+{
+ if (n) {
+ fputs("\033(e", stream);
+ putc(2, stream);
+ putc(0, stream);
+ putc(n / 256, stream);
+ putc(n % 256, stream);
+ }
+
+ return 0;
+}
+
+private int
+bjc_finish_page(gx_device_printer* pdev, FILE* stream)
+{
+ bjc_cmd('a', 1, (byte*) "\000", pdev, stream);
+ bjc_cmd('b', 1, (byte*) "\000", pdev, stream);
+ fputc('\014', stream);
+ fputs("\033@", stream);
+
+ return 0;
+}
+
+/* 1D runlength compression for BJC-600
+ * this code is borrowed from gdevpcl.c:gdev_pcl_mode2compress.
+ */
+private int
+bjc_compress(const byte *row, const byte *end_row, byte *compressed)
+{
+ register const byte *exam = row;
+ register byte *cptr = compressed; /* output pointer into compressed bytes */
+
+
+ while ( exam < end_row ) {
+ /* Search ahead in the input looking for a run */
+ /* of at least 4 identical bytes. */
+ const byte *compr = exam;
+ const byte *end_dis;
+ const byte *next;
+ register byte test, test2;
+
+ test = *exam;
+ while ( exam < end_row ) {
+ test2 = *++exam;
+ if ( test == test2 )
+ break;
+ test = test2;
+ }
+
+
+ /* Find out how long the run is */
+ end_dis = exam - 1;
+ if ( exam == end_row ) { /* no run */
+ next = --end_row;
+ } else {
+
+ next = exam + 1;
+ while ( next < end_row && *next == test ) next++;
+ }
+
+
+ /* Now [compr..end_dis) should be encoded as dissimilar, */
+ /* and [end_dis..next) should be encoded as similar. */
+ /* Note that either of these ranges may be empty. */
+
+
+ for ( ; ; ) { /* Encode up to 128 dissimilar bytes */
+ uint count = end_dis - compr; /* uint for faster switch */
+ switch ( count ) { /* Use memcpy only if it's worthwhile. */
+ case 6: cptr[6] = compr[5];
+ case 5: cptr[5] = compr[4];
+ case 4: cptr[4] = compr[3];
+ case 3: cptr[3] = compr[2];
+ case 2: cptr[2] = compr[1];
+ case 1: cptr[1] = compr[0];
+ *cptr = count - 1;
+ cptr += count + 1;
+ case 0: /* all done */
+ break;
+ default:
+ if ( count > 128 ) count = 128;
+ *cptr++ = count - 1;
+ memcpy(cptr, compr, count);
+ cptr += count, compr += count;
+ continue;
+ }
+ break;
+ }
+
+
+ { /* Encode up to 128 similar bytes. */
+ /* Note that count may be <0 at end of row. */
+ int count = next - end_dis;
+ if (next < end_row || test != 0)
+ while ( count > 0 ) {
+
+ int this = (count > 128 ? 128 : count);
+ *cptr++ = 257 - this;
+ *cptr++ = (byte)test;
+ count -= this;
+ }
+ exam = next;
+ }
+ }
+ return cptr - compressed;
+}
+
+/*
+ * For the ESC/P mode, resolution is fixed as 360dpi and we must transform
+ * image data to serialized data.
+ */
+private word *ep_storage;
+private uint ep_storage_size_words;
+private byte *ep_raster_buf[4][BJC_HEAD_ROWS], *ep_print_buf;
+private int ep_num_comps, ep_plane_size, img_rows=BJC_HEAD_ROWS;
+
+
+#define row_bytes (img_rows / 8)
+#define row_words (row_bytes / sizeof(word))
+#define min_rows (32) /* for optimization of text image printing */
+
+
+private int
+ep_print_image(FILE *prn_stream, char cmd, byte *data, int size)
+{
+ static int ln_idx=0, vskip1=0, vskip2=0, real_rows;
+ int i;
+ static const char color[4] = {4,1,2,0};
+
+
+ switch (cmd) {
+ case 3: /* Black */
+ case 2: /* Cyan */
+ case 1: /* Magenta */
+ case 0: /* Yellow */
+ memcpy(ep_raster_buf[((int) cmd)][ln_idx+vskip2], data, size);
+ return 0;
+ case 'B': /* blank line skip */
+ if (!ln_idx) {
+ vskip1 += size;
+ } else if (size >= img_rows - (ln_idx+vskip2) || ln_idx+vskip2 >= min_rows) {
+ /* The 'I' cmd must precede 'B' cmd! */
+ vskip2 += size;
+ ep_print_image(prn_stream, 'F', 0, 0); /* flush and reset status */
+ } else {
+ vskip2 += size;
+ }
+ return 0;
+ case 'I': /* Increment index */
+ ln_idx += vskip2 + 1;
+ vskip2 = 0;
+ if (ln_idx < img_rows) return 0;
+ /* if ep_raster_buf filled up, then fall through here and flush buffer */
+ case 'F': /* flush print buffer */
+ if (!ln_idx) return 0; /* The end of the page. */
+
+
+ /* before print the image, perform vertical skip. */
+ while (vskip1 >= (255*2)) {
+ fputs("\033J\377", prn_stream); /* n/180in. feeding */
+ vskip1 -= (255*2);
+ }
+ if (vskip1 > 255) {
+ fputs("\033J\200", prn_stream);
+ vskip1 -= 256;
+ }
+ if (vskip1) {
+ /* n/360in. feeding */
+ fputs("\033|J", prn_stream); putc(0, prn_stream); putc(vskip1, prn_stream);
+ }
+
+
+ /* Optimize the number of nozzles to be used. */
+ if (ln_idx > 56) { /* use 64 nozzles */
+ real_rows = 64;
+ } else if (ln_idx > 48) { /* use 56 nozzles */
+ real_rows = 56;
+ } else if (ln_idx > 32) { /* use 48 nozzles */
+ real_rows = 48;
+ } else { /* use 32 nozzles */
+ real_rows = 32;
+ }
+
+
+ for (i = 0; i < ep_num_comps; i++) {
+ int lnum, hskip, print_size, img_rows;
+ byte *p0, *p1, *p2, *p3;
+ byte *inp, *inbuf, *outp, *outbuf;
+
+
+ img_rows = real_rows; /* Note that this img_rows is not the one that
+ * defined out of this function. */
+ outbuf = ep_print_buf;
+
+
+ /* Transpose raster image for serial printer image */
+ for (lnum=0; lnum < img_rows; lnum+=8, outbuf++) {
+ inbuf = inp = ep_raster_buf[i][lnum];
+ for (outp = outbuf; inp < inbuf+ep_plane_size; inp++, outp += img_rows) {
+ memflip8x8(inp, ep_plane_size, outp, row_bytes);
+ }
+ }
+
+
+ /* Set color */
+ if (ep_num_comps == 1) {
+ /* Don't set color (to enable user setting). */
+ putc('\015', prn_stream);
+ } else {
+ /* set color to one of CMYK. */
+ fputs("\015\033r", prn_stream);
+ putc(color[i], prn_stream);
+ }
+
+
+ *(outp = ep_print_buf + ep_plane_size * img_rows) = 1; /* sentinel */
+
+
+ p0 = p3 = ep_print_buf;
+
+
+ /* print image p0 to p1 and h skip p1 to p2 if p2<outp,
+ * then make p0=p2 and continue */
+ while (p0 < outp) {
+ static const word zeros[8] = {0,0,0,0,0,0,0,0};
+
+
+ if (p3 < outp) {
+ /* p1 is the head of running zeros. */
+ /* note that h skip unit is 1/180inch */
+ for (p1 = p3; !memcmp(p3, zeros, row_bytes*2); p3 += row_bytes*2);
+ /* p2 is the head of non zero image. */
+ p2 = p3;
+ redo:
+ for (p3 += row_bytes; memcmp(p3, zeros, row_bytes); p3 += row_bytes);
+ if (p3 < outp && memcmp(p3+row_bytes, zeros, row_bytes)) goto redo;
+ } else p1 = p2 = outp;
+
+
+ if (p0 < p1) { /* print the image between p0 and p1 */
+ print_size = ((p1 < outp) ? p1 : outp) - p0;
+ fputs("\033|B", prn_stream); putc(img_rows, prn_stream);
+ fputshort(print_size, prn_stream);
+ fwrite(p0, sizeof(byte), print_size, prn_stream);
+ }
+ if (p1 < p2) { /* skip running zeros from p1 to p2 */
+ hskip = (((p2 < outp) ? p2 : outp) - p1) / row_bytes / 2;
+ fputs("\033\\", prn_stream);
+ fputshort(hskip, prn_stream);
+ }
+ p0 = p2;
+ }
+ }
+ return ep_print_image(prn_stream, 'R', 0, vskip2 + ln_idx);
+ case 'R': /* Reset status */
+ ln_idx = 0;
+ vskip1 = size;
+ vskip2 = 0;
+ memset(ep_storage, 0, ep_storage_size_words * W);
+ return 0;
+ default: /* This should not happen */
+ fprintf(stderr, "ep_print_image: illegal command character `%c'.\n", cmd);
+ return 1;
+ }
+
+
+ /* NOT REACHED */
+}
+
+
+/* Send the page to the printer. Compress each scan line. */
+private int
+hp_colour_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype)
+{
+ uint raster_width = gdev_prn_rasterwidth(pdev, 1);
+/* int line_size = gdev_prn_rasterwidth(pdev, 0); */
+ int line_size = gdev_prn_raster(pdev);
+ int line_size_words = (line_size + W - 1) / W;
+ int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
+ int num_comps = pdev->color_info.num_components;
+ int bits_per_pixel = pdev->color_info.depth;
+ int storage_bpp = bits_per_pixel;
+ int expanded_bpp = bits_per_pixel;
+ int plane_size, databuff_size;
+ int combined_escapes = 1;
+ int errbuff_size = 0;
+ int outbuff_size = 0;
+ int compression = 0;
+ int scan = 0;
+ int *errors[2];
+ const char *cid_string = (const char*) 0;
+ byte *data[4], *plane_data[4][4], *out_data;
+ byte *out_row, *out_row_alt;
+ word *storage;
+ uint storage_size_words;
+
+ /* Tricks and cheats ... */
+ switch (ptype) {
+ case DJ550C:
+ if (num_comps == 3 && !cprn_device->cmyk)
+ num_comps = 4; /* 4-component printing */
+ break;
+ case ESC_P:
+ if (bits_per_pixel == 24) /* prefer 3-component printing for bpp=24. */
+ num_comps = 3;
+ else
+ if (num_comps != 1)
+ num_comps = 4;
+ break;
+ case PJXL300:
+ case PJXL180:
+ if (pjxl->rendertype > 0) {
+ if (bits_per_pixel < 16)
+ pjxl->rendertype = 0;
+ else {
+ /* Control codes for CID sequence */
+ cid_string = (bits_per_pixel == 16) ? CONFIG_16BIT : CONFIG_24BIT;
+ /* Pretend we're a monobit device so we send the data out unchanged */
+ bits_per_pixel = storage_bpp = expanded_bpp = 1;
+ num_comps = 1;
+ }
+ }
+ break;
+ }
+
+ if (cprn_device->cmyk <= 0) {
+ if (storage_bpp == 8 && num_comps >= 3)
+ bits_per_pixel = expanded_bpp = 3; /* Only 3 bits of each byte used */
+ }
+
+ plane_size = calc_buffsize(line_size, storage_bpp);
+ ep_plane_size = plane_size;
+
+ if (bits_per_pixel == 1) { /* Data printed direct from i/p */
+ databuff_size = 0; /* so no data buffer required, */
+ outbuff_size = plane_size * 4; /* but need separate output buffers */
+ }
+
+ if (bits_per_pixel > 4) { /* Error buffer for FS dithering */
+ storage_bpp = expanded_bpp =
+ num_comps * 8; /* 8, 24 or 32 bits */
+
+ if (cprn_device->cmyk > 0) { /* Use CMYK dithering algorithm. */
+ errbuff_size = 4 * (5 + 1 + 1 + line_size + 1 + 2) * I;
+ } else { /* Use original (RGB) dithering. */
+ errbuff_size = /* 4n extra values for line ends */
+ calc_buffsize((plane_size * expanded_bpp + num_comps * 4) * I, 1);
+ }
+ }
+
+ databuff_size = plane_size * storage_bpp;
+
+ storage_size_words = ((plane_size + plane_size) * num_comps +
+ databuff_size + errbuff_size + outbuff_size) / W;
+
+ storage = (ulong *) gs_malloc(storage_size_words, W, "hp_colour_print_page");
+ ep_storage_size_words = (plane_size * (num_comps + 1)) / W * img_rows
+ + 16; /* Redundant space for sentinel and aligning. */
+ ep_storage = (word *) gs_malloc(ep_storage_size_words, W, "ep_print_buffer");
+
+ /*
+ * The principal data pointers are stored as pairs of values, with
+ * the selection being made by the 'scan' variable. The function of the
+ * scan variable is overloaded, as it controls both the alternating
+ * raster scan direction used in the Floyd-Steinberg dithering and also
+ * the buffer alternation required for line-difference compression.
+ *
+ * Thus, the number of pointers required is as follows:
+ *
+ * errors: 2 (scan direction only)
+ * data: 4 (scan direction and alternating buffers)
+ * plane_data: 4 (scan direction and alternating buffers)
+ */
+
+ if (storage == 0 || ep_storage == 0) /* can't allocate working area */
+ return_error(gs_error_VMerror);
+ else {
+ int i, j;
+ byte *p = out_data = out_row = (byte *)storage;
+ byte *ep_p = (byte *)ep_storage;
+ data[0] = data[1] = data[2] = p;
+ data[3] = p + databuff_size;
+ out_row_alt = out_row + plane_size * 2;
+ if (bits_per_pixel > 1) {
+ p += databuff_size;
+ }
+ if (bits_per_pixel > 4) {
+ errors[0] = (int *)p + num_comps * 2;
+ errors[1] = errors[0] + databuff_size;
+ p += errbuff_size;
+ }
+ for (i = 0; i < num_comps; i++) {
+ plane_data[0][i] = plane_data[2][i] = p;
+ p += plane_size;
+ }
+ for (i = 0; i < num_comps; i++) {
+ plane_data[1][i] = p;
+ plane_data[3][i] = p + plane_size;
+ p += plane_size;
+ }
+ if (bits_per_pixel == 1) {
+ out_data = out_row = p; /* size is outbuff_size * 4 */
+ out_row_alt = out_row + plane_size * 2;
+ data[1] += databuff_size; /* coincides with plane_data pointers */
+ data[3] += databuff_size;
+ }
+ for (i = 0; i < num_comps; i++) {
+ for (j = 0; j < img_rows; j++) {
+ ep_raster_buf[i][j] = ep_p;
+ ep_p += plane_size;
+ }
+ /* Make a sentinel and align to word size. */
+ ep_print_buf = (byte *)((word)(ep_p + sizeof(word)) & ~(sizeof(word)-1));
+ }
+ ep_num_comps = num_comps;
+ }
+
+ /* Initialize printer. */
+ if (ptype == BJC600 || ptype == BJC800) {
+ bjc_init_page(pdev, prn_stream);
+ } else {
+ if (ptype == LJ4DITH) {
+ fputs("\033*rB", prn_stream);
+ } else {
+ fputs("\033*rbC", prn_stream); /* End raster graphics */
+ }
+ fprintf(prn_stream, "\033*t%dR", (int)x_dpi);
+ /* Set resolution */
+ }
+
+ /* Clear temp storage */
+ memset(storage, 0, storage_size_words * W);
+
+#define DOFFSET (dev_t_margin(pdev) - DESKJET_PRINT_LIMIT) /* Print position */
+#define POFFSET (dev_t_margin(pdev) - PAINTJET_PRINT_LIMIT)
+#define EOFFSET (dev_t_margin(pdev) - ESC_P_PRINT_LIMIT)
+#define BOFFSET (dev_t_margin(pdev) - bjc->printLimit)
+ switch (ptype) {
+ case LJ4DITH:
+ /* Page size, orientation, top margin & perforation skip */
+ fprintf(prn_stream, "\033&l26A\033&l0o0e0L\033*r0F" );
+ fprintf(prn_stream, "\033*p0x0Y" ); /* These Offsets are hacked ! */
+ fprintf(prn_stream, "\033&u600D\033*r1A" );
+ /* Select data compression */
+ compression = 3;
+ combined_escapes = 0;
+ break;
+ case DJ500C:
+ case DJ550C:
+ /* Page size, orientation, top margin & perforation skip */
+ fprintf(prn_stream, "\033&l%daolE", paper_size);
+ /* Set depletion and shingling levels */
+ fprintf(prn_stream, "\033*o%dd%dQ", cdj->depletion, cdj->shingling);
+ /* Move to top left of printed area */
+ fprintf(prn_stream, "\033*p%dY", (int)(300 * DOFFSET));
+ /* Set number of planes ((-)1 is mono, (-)3 is (cmy)rgb, -4 is cmyk),
+ * and raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds-%du0A", raster_width, num_comps);
+ /* Select data compression */
+ compression = 9;
+ break;
+ case DNJ650C:
+ fprintf (prn_stream, "\033%%0B"); /* Enter HPGL/2 mode */
+ fprintf (prn_stream, "BP5,1"); /* Turn off autorotation */
+ fprintf (prn_stream, "PS%d,%d",
+ (int)((pdev->height/pdev->y_pixels_per_inch)*1016),
+ (int)((pdev->width/pdev->x_pixels_per_inch)*1016)); /* Set length/width of page */
+ fprintf (prn_stream, "PU"); /* Pen up */
+ fprintf (prn_stream, "PA%d,%d", 0, 0); /* Move pen to upper-left */
+ fprintf (prn_stream, "\033%%1A"); /* Enter HP-RTL mode */
+ fprintf (prn_stream, "\033&a1N"); /* No negative motion - allow plotting
+ while receiving */
+ { static const char temp[] = {
+ 033, '*', 'v', '6', 'W',
+ 000 /* color model */,
+ 000 /* pixel encoding mode */,
+ 003 /* number of bits per index */,
+ 010 /* bits red */,
+ 010 /* bits green */,
+ 010 /* bits blue */
+ };
+ fwrite (temp, 1, sizeof(temp), prn_stream);
+ }
+
+ /* Set raster width */
+ fprintf(prn_stream, "\033*r%dS", raster_width);
+ /* Start raster graphics */
+ fprintf(prn_stream, "\033*r1A");
+
+ /* Select data compression */
+ compression = 1;
+ /* No combined escapes for raster transfers */
+ combined_escapes = 0;
+ break;
+ case PJXL300:
+ /* Page size, orientation, top margin & perforation skip */
+ fprintf(prn_stream, "\033&l%daolE", paper_size);
+ /* Set no-negative-motion mode, for faster (unbuffered) printing */
+ fprintf(prn_stream, "\033&a1N");
+ /* Set print quality */
+ fprintf(prn_stream, "\033*o%dQ", pjxl->printqual);
+ /* Move to top left of printed area */
+ fprintf(prn_stream, "\033*p%dY", (int)(300 * POFFSET));
+ /* Configure colour setup */
+ if (pjxl->rendertype > 0) {
+ /* Set render type */
+ fprintf(prn_stream, "\033*t%dJ", pjxl->rendertype);
+ /* Configure image data */
+ fputs(cid_string, prn_stream);
+ /* Set raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds1A", raster_width);
+ } else {
+ /* Set number of planes (1 is mono, 3 is rgb),
+ * and raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds-%du0A", raster_width, num_comps);
+ }
+ /* No combined escapes for raster transfers */
+ combined_escapes = 0;
+ break;
+ case PJXL180:
+ /* Page size, orientation, top margin & perforation skip */
+ fprintf(prn_stream, "\033&l%daolE", paper_size);
+ /* Set print quality */
+ fprintf(prn_stream, "\033*o%dQ", pjxl->printqual);
+ /* Move to top left of printed area */
+ fprintf(prn_stream, "\033*p%dY", (int)(180 * POFFSET));
+ /* Configure colour setup */
+ if (pjxl->rendertype > 0) {
+ /* Set render type */
+ fprintf(prn_stream, "\033*t%dJ", pjxl->rendertype);
+ /* Configure image data */
+ fputs(cid_string, prn_stream);
+ /* Set raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds1A", raster_width);
+ } else {
+ /* Set number of planes (1 is mono, 3 is rgb),
+ * and raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds%du0A", raster_width, num_comps);
+ }
+ break;
+ case PJ180:
+ case DECLJ250:
+ /* Disable perforation skip */
+ fprintf(prn_stream, "\033&lL");
+ /* Move to top left of printed area */
+ fprintf(prn_stream, "\033&a%dV", (int)(720 * POFFSET));
+ /* Set number of planes (1 is mono, 3 is rgb),
+ * and raster width, then start raster graphics */
+ fprintf(prn_stream, "\033*r%ds%du0A", raster_width, num_comps);
+ if (ptype == DECLJ250) {
+ /* No combined escapes for raster transfers */
+ combined_escapes = 0;
+ /* From here on, we're a standard Paintjet .. */
+ ptype = PJ180;
+ }
+ /* Select data compression */
+ compression = 1;
+ break;
+ case ESC_P:
+ /* Move to top left of printed area (must be modified for large movement(YK))*/
+ if ((int)(EOFFSET*360)) fprintf(prn_stream, "\033|J%c%c", 0, (int)(360*EOFFSET));
+ combined_escapes = 0;
+ break;
+ case BJC600:
+ case BJC800:
+ /* Move to top left of printed area */
+ bjc_v_skip((int)(pdev->HWResolution[1] * BOFFSET), pdev, prn_stream);
+ combined_escapes = 0;
+ compression = 2; /* BJC600 uses the same method as mode 2 compression */
+ break;
+ }
+
+ /* Unfortunately, the Paintjet XL300 PCL interpreter introduces a
+ * version of the PCL language which is different to all earlier HP
+ * colour and mono inkjets, in that it loses the very useful ability
+ * to use combined escape sequences with the raster transfer
+ * commands. In this respect, it is incompatible even with the older
+ * 180 dpi PaintJet and PaintJet XL printers! Another regrettable
+ * omission is that 'mode 9' compression is not supported, as this
+ * mode can give both computational and PCL file size advantages. */
+
+ if (combined_escapes) {
+ /* From now on, all escape commands start with \033*b, so we
+ * combine them (if the printer supports this). */
+ fputs("\033*b", prn_stream);
+ /* Set compression if the mode has been defined. */
+ if (compression)
+ fprintf(prn_stream, "%dm", compression);
+ }
+ else if (ptype == BJC600 || ptype == BJC800)
+ ; /* Currently, nothing to do. */
+ else
+ if (compression)
+ fprintf(prn_stream, "\033*b%dM", compression);
+
+ /* Send each scan line in turn */
+ {
+ int cErr, mErr, yErr, kErr;
+ int this_pass, lnum, i;
+ int start_rows;
+ int lend, num_blank_lines = 0;
+
+ word rmask = ~(word) 0 << ((-pdev->width * storage_bpp) & (W * 8 - 1));
+
+ lend = pdev->height - (dev_t_margin(pdev) + dev_b_margin(pdev)) * y_dpi;
+
+ switch (ptype) {
+ case BJC600:
+ case BJC800:
+ start_rows = BJC_HEAD_ROWS;
+ break;
+
+ /* Inhibit blank line printing for RGB-only printers, since in
+ * this case 'blank' means black! Also disabled for XL300 due to
+ * an obscure bug in the printer's firmware */
+
+ case PJ180:
+ case PJXL180:
+ case PJXL300:
+ start_rows = -1;
+ break;
+
+ default:
+ start_rows = (num_comps == 1) ? HEAD_ROWS_MONO - 1 :
+ HEAD_ROWS_COLOUR - 1;
+ break;
+ }
+
+ cErr = mErr = yErr = kErr = 0;
+
+ if (bits_per_pixel > 4) { /* Randomly seed initial error buffer */
+ if (cprn_device->cmyk > 0 && expanded_bpp == 32) {
+ bjc_fscmyk(data, plane_data, errors, plane_size, -1);
+ } else {
+ int *ep = errors[0];
+ for (i = 0; i < databuff_size; i++) {
+ *ep++ = RANDOM;
+ }
+ }
+ }
+
+ this_pass = start_rows;
+ for (lnum = 0; lnum < lend; lnum++) {
+ word *data_words = (word *)data[scan];
+ register word *end_data = data_words + line_size_words;
+
+ gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);
+
+ /* Mask off 1-bits beyond the line width. */
+ end_data[-1] &= rmask;
+
+ /* Remove trailing 0s. */
+ while (end_data > data_words && end_data[-1] == 0)
+ end_data--;
+ if (ptype != DNJ650C) /* DesignJet can't skip blank lines ? ? */
+ if (end_data == data_words) { /* Blank line */
+ num_blank_lines++;
+ continue;
+ }
+ /* Skip blank lines if any */
+ if (num_blank_lines > 0) {
+ if (ptype == ESC_P) {
+ ep_print_image(prn_stream, 'B', 0, num_blank_lines);
+ } else if (ptype == BJC600 || ptype == BJC800) {
+ bjc_v_skip(num_blank_lines, pdev, prn_stream);
+ } else if (num_blank_lines < this_pass) {
+ /* Moving down from current position
+ * causes head motion on the DeskJets, so
+ * if the number of lines is within the
+ * current pass of the print head, we're
+ * better off printing blanks. */
+ this_pass -= num_blank_lines;
+ if (combined_escapes) {
+ fputc('y', prn_stream); /* Clear current and seed rows */
+ for (; num_blank_lines; num_blank_lines--)
+ fputc('w', prn_stream);
+ } else {
+#if 0
+/**************** The following code has been proposed ****************/
+/**************** as a replacement: ****************/
+ fputs("\033*b1Y", prn_stream); /* Clear current and seed rows */
+ if ( num_blank_lines > 1 )
+ fprintf(prn_stream, "\033*b%dY", num_blank_lines - 1);
+ num_blank_lines = 0;
+#else
+ fputs("\033*bY", prn_stream); /* Clear current and seed rows */
+ if (ptype == DNJ650C) {
+ fprintf (prn_stream, "\033*b%dY", num_blank_lines);
+ num_blank_lines = 0;
+ }
+ else {
+ for (; num_blank_lines; num_blank_lines--)
+ fputs("\033*bW", prn_stream);
+ }
+#endif
+ }
+ } else {
+ if (combined_escapes)
+ fprintf(prn_stream, "%dy", num_blank_lines);
+ else
+ fprintf(prn_stream, "\033*b%dY", num_blank_lines);
+ }
+ memset(plane_data[1 - scan][0], 0, plane_size * num_comps);
+ num_blank_lines = 0;
+ this_pass = start_rows;
+ }
+ { /* Printing non-blank lines */
+ register byte *kP = plane_data[scan + 2][3];
+ register byte *cP = plane_data[scan + 2][2];
+ register byte *mP = plane_data[scan + 2][1];
+ register byte *yP = plane_data[scan + 2][0];
+ register byte *dp = data[scan + 2];
+ register int *ep = errors[scan];
+ int zero_row_count;
+ int i, j;
+ byte *odp;
+
+ if (this_pass)
+ this_pass--;
+ else
+ this_pass = start_rows;
+
+ if (expanded_bpp > bits_per_pixel) { /* Expand line if required */
+ cdj_expand_line(data_words, line_size,
+ cprn_device->cmyk,
+ bits_per_pixel, expanded_bpp);
+ }
+
+ /* In colour modes, we have some bit-shuffling to do before
+ * we can print the data; in FS mode we also have the
+ * dithering to take care of. */
+ switch (expanded_bpp) { /* Can be 1, 3, 8, 24 or 32 */
+ case 3:
+ /* Transpose the data to get pixel planes. */
+ for (i = 0, odp = plane_data[scan][0]; i < databuff_size;
+ i += 8, odp++) { /* The following is for 16-bit
+ * machines */
+#define spread3(c)\
+ { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
+ static ulong spr40[8] = spread3(0x40);
+ static ulong spr08[8] = spread3(8);
+ static ulong spr02[8] = spread3(2);
+ register byte *dp = data[scan] + i;
+ register ulong pword =
+ (spr40[dp[0]] << 1) +
+ (spr40[dp[1]]) +
+ (spr40[dp[2]] >> 1) +
+ (spr08[dp[3]] << 1) +
+ (spr08[dp[4]]) +
+ (spr08[dp[5]] >> 1) +
+ (spr02[dp[6]]) +
+ (spr02[dp[7]] >> 1);
+ odp[0] = (byte) (pword >> 16);
+ odp[plane_size] = (byte) (pword >> 8);
+ odp[plane_size * 2] = (byte) (pword);
+ }
+ break;
+
+ case 8:
+ switch (ptype) {
+ case BJC600:
+ case BJC800:
+ if (bjcparams.ditheringType == BJC_DITHER_NONE) {
+ COPYline(scan, i, j, plane_size, cP, mP, yP, kP, 1);
+ break;
+ }
+
+ default:
+ FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
+ cP, mP, yP, kP, 1);
+ }
+ break;
+ case 24:
+ FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
+ cP, mP, yP, kP, 3);
+ break;
+ case 32:
+ if (cprn_device->cmyk > 0) {
+ bjc_fscmyk(data, plane_data, errors, plane_size, scan);
+ } else {
+ FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
+ cP, mP, yP, kP, 4);
+ }
+ break;
+
+ } /* switch(expanded_bpp) */
+
+ /* Make sure all black is in the k plane */
+
+ if (num_comps == 4 && (cprn_device->cmyk <= 0 || expanded_bpp != 32)) {
+ register word *kp = (word *)plane_data[scan][3];
+ register word *cp = (word *)plane_data[scan][2];
+ register word *mp = (word *)plane_data[scan][1];
+ register word *yp = (word *)plane_data[scan][0];
+ if (bits_per_pixel > 4) { /* Done as 4 planes */
+ for (i = 0; i < plane_size / W; i++) {
+ word bits = *cp & *mp & *yp;
+ *kp++ |= bits;
+ bits = ~bits;
+ *cp++ &= bits;
+ *mp++ &= bits;
+ *yp++ &= bits;
+ }
+ } else { /* This has really been done as 3 planes */
+ for (i = 0; i < plane_size / W; i++) {
+ word bits = *cp & *mp & *yp;
+ *kp++ = bits;
+ bits = ~bits;
+ *cp++ &= bits;
+ *mp++ &= bits;
+ *yp++ &= bits;
+ }
+ }
+ }
+
+ /* Transfer raster graphics in the order (K), C, M, Y */
+
+ for (zero_row_count = 0, i = num_comps - 1; i >= 0; i--) {
+ int output_plane = 1;
+ int out_count = 0;
+
+ switch (ptype) {
+ case DJ500C: /* Always compress using mode 9 */
+ case DJ550C:
+ out_count = gdev_pcl_mode9compress(plane_size,
+ plane_data[scan][i],
+ plane_data[1 - scan][i],
+ out_data);
+
+ /* This optimisation allows early termination of the
+ * row, but this doesn't work correctly in an alternating
+ * mode 2 / mode 3 regime, so we only use it with mode 9
+ * compression */
+ if (out_count == 0)
+ { output_plane = 0; /* No further output for this plane */
+ if (i == 0)
+ fputc('w', prn_stream);
+ else
+ zero_row_count++;
+ }
+ else
+ { for (; zero_row_count; zero_row_count--)
+ fputc('v', prn_stream);
+ }
+ break;
+ case PJ180:
+ case DNJ650C:
+ if (num_comps > 1)
+ { word *wp = (word *)plane_data[scan][i];
+ for (j = 0; j < plane_size / W; j++, wp++)
+ *wp = ~*wp;
+ }
+ out_count = gdev_pcl_mode1compress((const byte *)
+ plane_data[scan][i],
+ (const byte *)
+ plane_data[scan][i] + plane_size - 1,
+ out_data);
+ break;
+ case PJXL180: /* Need to invert data as CMY not supported */
+ if (num_comps > 1)
+ { word *wp = (word *)plane_data[scan][i];
+ for (j = 0; j < plane_size / W; j++, wp++)
+ *wp = ~*wp;
+ }
+ /* fall through .. */
+ case PJXL300: /* Compression modes 2 and 3 are both
+ * available. Try both and see which one
+ * produces the least output data. */
+ case LJ4DITH:
+ { const byte *plane = plane_data[scan][i];
+ byte *prev_plane = plane_data[1 - scan][i];
+ const word *row = (word *)plane;
+ const word *end_row = row + plane_size/W;
+ int count2 = gdev_pcl_mode2compress(row, end_row, out_row_alt);
+ int count3 = gdev_pcl_mode3compress(plane_size, plane, prev_plane, out_row);
+ int penalty = combined_escapes ? strlen("#m") : strlen("\033*b#M");
+ int penalty2 = (compression == 2 ? 0 : penalty);
+ int penalty3 = (compression == 3 ? 0 : penalty);
+
+ if (count3 + penalty3 < count2 + penalty2)
+ { if ( compression != 3 ) {
+ if (combined_escapes)
+ fputs("3m", prn_stream);
+ else
+ fputs("\033*b3M", prn_stream);
+ compression = 3;
+ }
+ out_data = out_row;
+ out_count = count3;
+ }
+ else
+ { if ( compression != 2 ) {
+ if (combined_escapes)
+ fputs("2m", prn_stream);
+ else
+ fputs("\033*b2M", prn_stream);
+ compression = 2;
+ }
+ out_data = out_row_alt;
+ out_count = count2;
+ }
+ }
+ break;
+ case BJC600:
+ case BJC800:
+ { const byte *plane = (byte *)plane_data[scan][i];
+ int count2 = bjc_compress(plane, plane + plane_size, out_row_alt);
+
+ out_data = out_row_alt;
+ out_count = count2;
+ }
+ break;
+ }
+ if (output_plane) {
+ if (combined_escapes)
+ fprintf(prn_stream, "%d%c", out_count, "wvvv"[i]);
+ else if (ptype == BJC600 || ptype == BJC800) {
+ if (out_count)
+ bjc_raster_cmd(num_comps == 1 ? 3 : i,
+ out_count, out_data, pdev, prn_stream);
+ if (i == 0) bjc_v_skip(1, pdev, prn_stream);
+ } else if (ptype == ESC_P)
+ ep_print_image(prn_stream, i, plane_data[scan][i], plane_size);
+ else
+ fprintf(prn_stream, "\033*b%d%c", out_count, "WVVV"[i]);
+ if (ptype < ESC_P)
+ fwrite(out_data, sizeof(byte), out_count, prn_stream);
+ }
+
+ } /* Transfer Raster Graphics ... */
+ if (ptype == ESC_P)
+ ep_print_image(prn_stream, 'I', 0, 0); /* increment line index */
+ scan = 1 - scan; /* toggle scan direction */
+ } /* Printing non-blank lines */
+ } /* for lnum ... */
+ } /* send each scan line in turn */
+
+ if (combined_escapes)
+ fputs("0M", prn_stream);
+
+ /* end raster graphics */
+ if (ptype == BJC600 || ptype == BJC800) {
+ bjc_finish_page(pdev, prn_stream);
+ }
+ else if (ptype != ESC_P)
+ fputs("\033*rbC\033E", prn_stream);
+
+ /* eject page */
+ if (ptype == PJ180)
+ fputc('\f', prn_stream);
+ else if (ptype == DNJ650C)
+ fputs ("\033*rC\033%0BPG;", prn_stream);
+ else if (ptype == BJC600 || ptype == BJC800)
+ ; /* Already done */
+ else if (ptype == ESC_P) {
+ ep_print_image(prn_stream, 'F', 0, 0); /* flush print buffer */
+ fputs("\014\033@", prn_stream); /* reset after eject page */
+ } else
+ fputs("\033&l0H", prn_stream);
+
+ /* free temporary storage */
+ gs_free((char *) ep_storage, ep_storage_size_words, W, "ep_print_buffer");
+ gs_free((char *) storage, storage_size_words, W, "hp_colour_print_page");
+
+ return 0;
+}
+
+/*
+ * Mode 9 2D compression for the HP DeskJet 5xxC. This mode can give
+ * very good compression ratios, especially if there are areas of flat
+ * colour (or blank areas), and so is 'highly recommended' for colour
+ * printing in particular because of the very large amounts of data which
+ * can be generated
+ */
+private int
+gdev_pcl_mode9compress(int bytecount, const byte * current, const byte * previous, byte * compressed)
+{
+ register const byte *cur = current;
+ register const byte *prev = previous;
+ register byte *out = compressed;
+ const byte *end = current + bytecount;
+
+ while (cur < end) { /* Detect a run of unchanged bytes. */
+ const byte *run = cur;
+ register const byte *diff;
+ int offset;
+ while (cur < end && *cur == *prev) {
+ cur++, prev++;
+ }
+ if (cur == end)
+ break; /* rest of row is unchanged */
+ /* Detect a run of changed bytes. */
+ /* We know that *cur != *prev. */
+ diff = cur;
+ do {
+ prev++;
+ cur++;
+ }
+ while (cur < end && *cur != *prev);
+ /* Now [run..diff) are unchanged, and */
+ /* [diff..cur) are changed. */
+ offset = diff - run;
+ {
+ const byte *stop_test = cur - 4;
+ int dissimilar, similar;
+
+ while (diff < cur) {
+ const byte *compr = diff;
+ const byte *next; /* end of run */
+ byte value = 0;
+ while (diff <= stop_test &&
+ ((value = *diff) != diff[1] ||
+ value != diff[2] ||
+ value != diff[3]))
+ diff++;
+
+ /* Find out how long the run is */
+ if (diff > stop_test) /* no run */
+ next = diff = cur;
+ else {
+ next = diff + 4;
+ while (next < cur && *next == value)
+ next++;
+ }
+
+#define MAXOFFSETU 15
+#define MAXCOUNTU 7
+ /* output 'dissimilar' bytes, uncompressed */
+ if ((dissimilar = diff - compr)) {
+ int temp, i;
+
+ if ((temp = --dissimilar) > MAXCOUNTU)
+ temp = MAXCOUNTU;
+ if (offset < MAXOFFSETU)
+ *out++ = (offset << 3) | (byte) temp;
+ else {
+ *out++ = (MAXOFFSETU << 3) | (byte) temp;
+ offset -= MAXOFFSETU;
+ while (offset >= 255) {
+ *out++ = 255;
+ offset -= 255;
+ }
+ *out++ = offset;
+ }
+ if (temp == MAXCOUNTU) {
+ temp = dissimilar - MAXCOUNTU;
+ while (temp >= 255) {
+ *out++ = 255;
+ temp -= 255;
+ }
+ *out++ = (byte) temp;
+ }
+ for (i = 0; i <= dissimilar; i++)
+ *out++ = *compr++;
+ offset = 0;
+ } /* end uncompressed */
+#define MAXOFFSETC 3
+#define MAXCOUNTC 31
+ /* output 'similar' bytes, run-length encoded */
+ if ((similar = next - diff)) {
+ int temp;
+
+ if ((temp = (similar -= 2)) > MAXCOUNTC)
+ temp = MAXCOUNTC;
+ if (offset < MAXOFFSETC)
+ *out++ = 0x80 | (offset << 5) | (byte) temp;
+ else {
+ *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp;
+ offset -= MAXOFFSETC;
+ while (offset >= 255) {
+ *out++ = 255;
+ offset -= 255;
+ }
+ *out++ = offset;
+ }
+ if (temp == MAXCOUNTC) {
+ temp = similar - MAXCOUNTC;
+ while (temp >= 255) {
+ *out++ = 255;
+ temp -= 255;
+ }
+ *out++ = (byte) temp;
+ }
+ *out++ = value;
+ offset = 0;
+ } /* end compressed */
+ diff = next;
+ }
+ }
+ }
+ return out - compressed;
+}
+
+/*
+ * Row compression for the H-P PaintJet.
+ * Compresses data from row up to end_row, storing the result
+ * starting at compressed. Returns the number of bytes stored.
+ * The compressed format consists of a byte N followed by a
+ * data byte that is to be repeated N+1 times.
+ * In the worst case, the `compressed' representation is
+ * twice as large as the input.
+ * We complement the bytes at the same time, because
+ * we accumulated the image in complemented form.
+ */
+private int
+gdev_pcl_mode1compress(const byte *row, const byte *end_row, byte *compressed)
+{ register const byte *in = row;
+ register byte *out = compressed;
+ while ( in < end_row )
+ { byte test = *in++;
+ const byte *run = in;
+ while ( in < end_row && *in == test ) in++;
+ /* Note that in - run + 1 is the repetition count. */
+ while ( in - run > 255 )
+ { *out++ = 255;
+ *out++ = test;
+ run += 256;
+ }
+ *out++ = in - run;
+ *out++ = test;
+ }
+ return out - compressed;
+}
+
+/*
+ * Map a CMYK color to a color index. We just use depth / 4 bits per color
+ * to produce the color index.
+ *
+ * Important note: CMYK values are stored in the order K, C, M, Y because of
+ * the way the HP drivers work.
+ *
+ */
+
+#define gx_color_value_to_bits(cv, b) \
+ ((cv) >> (gx_color_value_bits - (b)))
+#define gx_bits_to_color_value(cv, b) \
+ ((cv) << (gx_color_value_bits - (b)))
+
+#define gx_cmyk_value_bits(c, m, y, k, b) \
+ ((gx_color_value_to_bits((k), (b)) << (3 * (b))) | \
+ (gx_color_value_to_bits((c), (b)) << (2 * (b))) | \
+ (gx_color_value_to_bits((m), (b)) << (b)) | \
+ (gx_color_value_to_bits((y), (b))))
+
+#define gx_value_cmyk_bits(v, c, m, y, k, b) \
+ (k) = gx_bits_to_color_value(((v) >> (3 * (b))) & ((1 << (b)) - 1), (b)), \
+ (c) = gx_bits_to_color_value(((v) >> (2 * (b))) & ((1 << (b)) - 1), (b)), \
+ (m) = gx_bits_to_color_value(((v) >> (b)) & ((1 << (b)) - 1), (b)), \
+ (y) = gx_bits_to_color_value((v) & ((1 << (b)) - 1), (b))
+
+private gx_color_index
+gdev_cmyk_map_cmyk_color(gx_device* pdev,
+ gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,
+ gx_color_value black) {
+
+ gx_color_index color;
+
+ switch (pdev->color_info.depth) {
+ case 1:
+ color = (cyan | magenta | yellow | black) > gx_max_color_value / 2 ?
+ (gx_color_index) 1 : (gx_color_index) 0;
+ break;
+
+ default: {
+ int nbits = pdev->color_info.depth;
+
+ if (cyan == magenta && magenta == yellow) {
+
+ /* Convert CMYK to gray -- Red Book 6.2.2 */
+
+ float bpart = ((float) cyan) * (lum_red_weight / 100.) +
+ ((float) magenta) * (lum_green_weight / 100.) +
+ ((float) yellow) * (lum_blue_weight / 100.) +
+ (float) black;
+
+ cyan = magenta = yellow = (gx_color_index) 0;
+ black = (gx_color_index) (bpart > gx_max_color_value ?
+ gx_max_color_value : bpart);
+ }
+
+ color = gx_cmyk_value_bits(cyan, magenta, yellow, black,
+ nbits >> 2);
+ }
+ }
+
+ return color;
+}
+
+/* Mapping of RGB colors to gray values. */
+
+private gx_color_index
+gdev_cmyk_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b)
+{
+
+ if (gx_color_value_to_byte(r & g & b) == 0xff) {
+ return (gx_color_index) 0; /* White */
+ } else {
+ gx_color_value c = gx_max_color_value - r;
+ gx_color_value m = gx_max_color_value - g;
+ gx_color_value y = gx_max_color_value - b;
+
+ switch (pdev->color_info.depth) {
+ case 1:
+ return (c | m | y) > gx_max_color_value / 2 ?
+ (gx_color_index) 1 : (gx_color_index) 0;
+ /*NOTREACHED*/
+ break;
+
+ case 8:
+ return ((ulong) c * lum_red_weight * 10
+ + (ulong) m * lum_green_weight * 10
+ + (ulong) y * lum_blue_weight * 10)
+ >> (gx_color_value_bits + 2);
+ /*NOTREACHED*/
+ break;
+ }
+ }
+
+ return (gx_color_index) 0; /* This should never happen. */
+}
+
+/* Mapping of CMYK colors. */
+
+private int
+gdev_cmyk_map_color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ switch (pdev->color_info.depth) {
+ case 1:
+ prgb[0] = prgb[1] = prgb[2] = gx_max_color_value * (1 - color);
+ break;
+
+ case 8:
+ if (pdev->color_info.num_components == 1) {
+ gx_color_value value = (gx_color_value) color ^ 0xff;
+
+ prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
+
+ break;
+ }
+
+ default: {
+ unsigned long bcyan, bmagenta, byellow, black;
+ int nbits = pdev->color_info.depth;
+
+ gx_value_cmyk_bits(color, bcyan, bmagenta, byellow, black,
+ nbits >> 2);
+
+#ifdef USE_ADOBE_CMYK_RGB
+
+ /* R = 1.0 - min(1.0, C + K), etc. */
+
+ bcyan += black, bmagenta += black, byellow += black;
+ prgb[0] = (bcyan > gx_max_color_value ? (gx_color_value) 0 :
+ gx_max_color_value - bcyan);
+ prgb[1] = (bmagenta > gx_max_color_value ? (gx_color_value) 0 :
+ gx_max_color_value - bmagenta);
+ prgb[2] = (byellow > gx_max_color_value ? (gx_color_value) 0 :
+ gx_max_color_value - byellow);
+
+#else
+
+ /* R = (1.0 - C) * (1.0 - K), etc. */
+
+ prgb[0] = (gx_color_value)
+ ((ulong)(gx_max_color_value - bcyan) *
+ (gx_max_color_value - black) / gx_max_color_value);
+ prgb[1] = (gx_color_value)
+ ((ulong)(gx_max_color_value - bmagenta) *
+ (gx_max_color_value - black) / gx_max_color_value);
+ prgb[2] = (gx_color_value)
+ ((ulong)(gx_max_color_value - byellow) *
+ (gx_max_color_value - black) / gx_max_color_value);
+
+#endif
+
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Map a r-g-b color to a color index.
+ * We complement the colours, since we're using cmy anyway, and
+ * because the buffering routines expect white to be zero.
+ * Includes colour balancing, following HP recommendations, to try
+ * and correct the greenish cast resulting from an equal mix of the
+ * c, m, y, inks by reducing the cyan component to give a truer black.
+ */
+
+/* Simple black generation/under-color removal with BG(k) = UG(k) = k. YA. */
+
+#define bg_and_ucr(c, c_v, m, m_v, y, y_v, k) \
+ do { \
+ register byte cv = c_v, mv = m_v, yv = y_v, kv; \
+ \
+ kv = (cv > mv ? mv : cv); \
+ kv = (yv > k ? k : y); \
+ y = yv - kv; m = mv - kv; c = cv -kv; k = kv; \
+ } while (0)
+
+private gx_color_index
+gdev_pcl_map_rgb_color(gx_device *pdev, gx_color_value r,
+ gx_color_value g, gx_color_value b)
+{
+ if (gx_color_value_to_byte(r & g & b) == 0xff)
+ return (gx_color_index)0; /* white */
+ else {
+ int correction = cprn_device->correction;
+ gx_color_value c = gx_max_color_value - r;
+ gx_color_value m = gx_max_color_value - g;
+ gx_color_value y = gx_max_color_value - b;
+
+ /* Colour correction for better blacks when using the colour ink
+ * cartridge (on the DeskJet 500C only). We reduce the cyan component
+ * by some fraction (eg. 4/5) to correct the slightly greenish cast
+ * resulting from an equal mix of the three inks */
+ if (correction) {
+ ulong maxval, minval, range;
+
+ maxval = c >= m ? (c >= y ? c : y) : (m >= y ? m : y);
+ if (maxval > 0) {
+ minval = c <= m ? (c <= y ? c : y) : (m <= y? m : y);
+ range = maxval - minval;
+
+#define shift (gx_color_value_bits - 12)
+ c = ((c >> shift) * (range + (maxval * correction))) /
+ ((maxval * (correction + 1)) >> shift);
+ }
+ }
+
+ switch (pdev->color_info.depth) {
+ case 1:
+ return ((c | m | y) > gx_max_color_value / 2 ?
+ (gx_color_index)1 : (gx_color_index)0);
+ case 8:
+ if (pdev->color_info.num_components >= 3)
+#define gx_color_value_to_1bit(cv) ((cv) >> (gx_color_value_bits - 1))
+ return (gx_color_value_to_1bit(c) +
+ (gx_color_value_to_1bit(m) << 1) +
+ (gx_color_value_to_1bit(y) << 2));
+ else
+#define red_weight 306
+#define green_weight 601
+#define blue_weight 117
+ return ((((ulong)c * red_weight +
+ (ulong)m * green_weight +
+ (ulong)y * blue_weight)
+ >> (gx_color_value_bits + 2)));
+ case 16:
+#define gx_color_value_to_5bits(cv) ((cv) >> (gx_color_value_bits - 5))
+#define gx_color_value_to_6bits(cv) ((cv) >> (gx_color_value_bits - 6))
+ return (gx_color_value_to_5bits(y) +
+ (gx_color_value_to_6bits(m) << 5) +
+ (gx_color_value_to_5bits(c) << 11));
+ case 24:
+ return (gx_color_value_to_byte(y) +
+ (gx_color_value_to_byte(m) << 8) +
+ ((ulong)gx_color_value_to_byte(c) << 16));
+ case 32:
+ { return ((c == m && c == y) ? ((ulong)gx_color_value_to_byte(c) << 24)
+ : (gx_color_value_to_byte(y) +
+ (gx_color_value_to_byte(m) << 8) +
+ ((ulong)gx_color_value_to_byte(c) << 16)));
+ }
+ }
+ }
+ return (gx_color_index)0; /* This never happens */
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+gdev_pcl_map_color_rgb(gx_device *pdev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ /* For the moment, we simply ignore any black correction */
+ switch (pdev->color_info.depth) {
+ case 1:
+ prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
+ break;
+ case 8:
+ if (pdev->color_info.num_components >= 3)
+ { gx_color_value c = (gx_color_value)color ^ 7;
+ prgb[0] = -(c & 1);
+ prgb[1] = -((c >> 1) & 1);
+ prgb[2] = -(c >> 2);
+ }
+ else
+ { gx_color_value value = (gx_color_value)color ^ 0xff;
+ prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
+ }
+ break;
+ case 16:
+ { gx_color_value c = (gx_color_value)color ^ 0xffff;
+ ushort value = c >> 11;
+ prgb[0] = ((value << 11) + (value << 6) + (value << 1) +
+ (value >> 4)) >> (16 - gx_color_value_bits);
+ value = (c >> 6) & 0x3f;
+ prgb[1] = ((value << 10) + (value << 4) + (value >> 2))
+ >> (16 - gx_color_value_bits);
+ value = c & 0x1f;
+ prgb[2] = ((value << 11) + (value << 6) + (value << 1) +
+ (value >> 4)) >> (16 - gx_color_value_bits);
+ }
+ break;
+ case 24:
+ { gx_color_value c = (gx_color_value)color ^ 0xffffff;
+ prgb[0] = gx_color_value_from_byte(c >> 16);
+ prgb[1] = gx_color_value_from_byte((c >> 8) & 0xff);
+ prgb[2] = gx_color_value_from_byte(c & 0xff);
+ }
+ break;
+ case 32:
+#define gx_maxcol gx_color_value_from_byte(gx_color_value_to_byte(gx_max_color_value))
+ { gx_color_value w = gx_maxcol - gx_color_value_from_byte(color >> 24);
+ prgb[0] = w - gx_color_value_from_byte((color >> 16) & 0xff);
+ prgb[1] = w - gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[2] = w - gx_color_value_from_byte(color & 0xff);
+ }
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Convert and expand scanlines:
+ *
+ * For devices with 3 components:
+ *
+ * (a) 16 -> 24 bit (1-stage)
+ * (b) 16 -> 32 bit (2-stage)
+ * or (c) 24 -> 32 bit (1-stage)
+ *
+ * For devices with 4 components:
+ *
+ * (a) 16 -> 32 bit (1-stage)
+ * (b) 8 -> 32 bit (2-stage)
+ * or (c) 24 -> 32 bit (1-stage)
+ *
+ */
+
+private void
+cdj_expand_line(word *line, int linesize, short cmyk, int bpp, int ebpp)
+{
+ int endline = linesize;
+ byte *start = (byte *)line;
+ register byte *in, *out;
+
+ if (cmyk > 0) {
+ if (bpp == 8) {
+ in = start + endline;
+ out = start + (endline *= 2);
+
+ while (in > start) {
+ register byte b0;
+ register byte bs0, bs1, bs2, bs3;
+
+ b0 = *--in;
+
+ bs0 = b0 & 0x03;
+ bs1 = (b0 >> 2) & 0x03;
+ bs2 = (b0 >> 4) & 0x03;
+ bs3 = (b0 >> 6) & 0x03;
+
+ *--out = (bs0 << 2) + bs0 + (bs1 << 6) + (bs1 << 4);
+ *--out = (bs2 << 2) + bs2 + (bs3 << 6) + (bs3 << 4);
+ }
+ }
+
+ if (bpp == 24) {
+ endline = (endline + 2) / 3;
+
+ in = start + endline * 3;
+ out = start + endline * 4;
+
+ while (in > start) {
+ register byte b0, b1, b2;
+
+ b0 = *--in;
+ b1 = *--in;
+ b2 = *--in;
+
+ *--out = (b0 << 2) + ((b0 >> 4) & 0x03);
+ *--out = ((b1 & 0x0f) << 4) + ((b0 >> 6) << 2)
+ + ((b1 >> 2) & 0x03);
+ *--out = ((b2 & 0x03) << 6) + ((b1 >> 4) << 2) + (b2 & 0x03);
+ *--out = (b2 & 0xfc) + ((b2 >> 6) & 0x03);
+ }
+ } else if (ebpp == 32) {
+ endline = (endline + 1) / 2;
+
+ in = start + endline * 2;
+ out = start + (endline *= 4);
+
+ while (in > start) {
+ register byte b0, b1;
+
+ b0 = *--in;
+ b1 = *--in;
+
+ *--out = (b0 << 4) + ((b0 >> 4) & 0x07);
+ *--out = (b0 & 0xf0) + ((b0 >> 4) & 0xf);
+ *--out = (b1 << 4) + ((b1 >> 4) & 0x0f);
+ *--out = (b1 & 0xf0) + ((b1 >> 4) & 0xf);
+ }
+ }
+ } else /* cmyk > 0 */ {
+ if (bpp == 16) /* 16 to 24 (cmy) if required */
+ { register byte b0, b1;
+ endline = ((endline + 1) / 2);
+ in = start + endline * 2;
+ out = start + (endline *= 3);
+
+ while (in > start)
+ { b0 = *--in;
+ b1 = *--in;
+ *--out = (b0 << 3) + ((b0 >> 2) & 0x7);
+ *--out = (b1 << 5) + ((b0 >> 3) & 0x1c) + ((b1 >> 1) & 0x3);
+ *--out = (b1 & 0xf8) + (b1 >> 5);
+ }
+ }
+
+ if (ebpp == 32) /* 24/32 (cmy) to 32 (cmyk) if required */
+ { register byte c, m, y;
+ endline = ((endline + 2) / 3);
+ in = start + endline * 3;
+ out = start + endline * 4;
+
+ while (in > start)
+ {
+ y = *--in;
+ m = *--in;
+ c = *--in;
+
+ if (c == y && c == m) {
+ *--out = 0, *--out = 0, *--out = 0;
+ *--out = c;
+ } else {
+ *--out = y, *--out = m, *--out = c;
+ *--out = 0;
+ }
+ }
+ }
+ }
+}
+
+private int near
+cdj_put_param_int(gs_param_list *plist, gs_param_name pname, int *pvalue,
+ int minval, int maxval, int ecode)
+{ int code, value;
+ switch ( code = param_read_int(plist, pname, &value) )
+ {
+ default:
+ return code;
+ case 1:
+ return ecode;
+ case 0:
+ if ( value < minval || value > maxval )
+ param_signal_error(plist, pname, gs_error_rangecheck);
+ *pvalue = value;
+ return (ecode < 0 ? ecode : 1);
+ }
+}
+
+private int
+cdj_set_bpp(gx_device *pdev, int bpp, int ccomps)
+{ gx_device_color_info *ci = &pdev->color_info;
+
+ if (ccomps && bpp == 0) {
+ if (cprn_device->cmyk) {
+ switch (ccomps) {
+ default:
+ return gs_error_rangecheck;
+ /*NOTREACHED*/
+ break;
+
+ case 1:
+ bpp = 1;
+ break;
+
+ case 3:
+ bpp = 24;
+ break;
+
+ case 4:
+ switch (ci->depth) {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+
+ default:
+ bpp = cprn_device->default_depth;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ if (bpp == 0) {
+ bpp = ci->depth; /* Use the current setting. */
+ }
+
+ if (cprn_device->cmyk < 0) {
+
+ /* Reset procedures because we may have been in another mode. */
+
+ dev_proc(pdev, map_cmyk_color) = gdev_cmyk_map_cmyk_color;
+ dev_proc(pdev, map_rgb_color) = NULL;
+ dev_proc(pdev, map_color_rgb) = gdev_cmyk_map_color_rgb;
+
+ if (pdev->is_open) gs_closedevice(pdev);
+ }
+
+ /* Check for valid bpp values */
+
+ switch ( bpp )
+ {
+ case 16:
+ case 32:
+ if (cprn_device->cmyk && ccomps && ccomps != 4) goto bppe;
+ break;
+
+ case 24:
+ if (!cprn_device->cmyk || ccomps == 0 || ccomps == 4) {
+ break;
+ } else if (ccomps == 1) {
+ goto bppe;
+ } else {
+
+ /* 3 components 24 bpp printing for CMYK device. */
+
+ cprn_device->cmyk = -1;
+ }
+ break;
+
+ case 8:
+ if (cprn_device->cmyk) {
+ if (ccomps) {
+ if (ccomps == 3) {
+ cprn_device->cmyk = -1;
+ bpp = 3;
+ } else if (ccomps != 1 && ccomps != 4) {
+ goto bppe;
+ }
+ }
+ if (ccomps != 1) break;
+ } else {
+ break;
+ }
+
+ case 1:
+ if (ccomps != 1) goto bppe;
+
+ if (cprn_device->cmyk && bpp != pdev->color_info.depth) {
+ dev_proc(pdev, map_cmyk_color) = NULL;
+ dev_proc(pdev, map_rgb_color) = gdev_cmyk_map_rgb_color;
+
+ if (pdev->is_open) {
+ gs_closedevice(pdev);
+ }
+ }
+ break;
+
+ case 3:
+ if (!cprn_device->cmyk) {
+ break;
+ }
+
+ default:
+bppe: return gs_error_rangecheck;
+ }
+
+
+ if (cprn_device->cmyk == -1) {
+ dev_proc(pdev, map_cmyk_color) = NULL;
+ dev_proc(pdev, map_rgb_color) = gdev_pcl_map_rgb_color;
+ dev_proc(pdev, map_color_rgb) = gdev_pcl_map_color_rgb;
+
+ if (pdev->is_open) {
+ gs_closedevice(pdev);
+ }
+ }
+
+ switch (ccomps) {
+ case 0:
+ break;
+
+ case 1:
+ if (bpp != 1 && bpp != 8) goto cce;
+ break;
+
+ case 4:
+ if (cprn_device->cmyk) {
+ if (bpp >= 8) break;
+ }
+
+ case 3:
+ if (bpp == 1 || bpp == 3 || bpp == 8 || bpp == 16
+ || bpp == 24 || bpp == 32) {
+ break;
+ }
+
+cce: default: return gs_error_rangecheck;
+ }
+
+ if (cprn_device->cmyk) {
+ if (cprn_device->cmyk > 0) {
+ ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 4);
+ } else {
+ ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 3);
+ }
+ if (bpp != 1 && ci->num_components == 1) { /* We do dithered grays. */
+ bpp = bpp < 8 ? 8 : bpp;
+ }
+
+ ci->max_color = (1 << (bpp >> 2)) - 1;
+ ci->max_gray = (bpp >= 8 ? 255 : 1);
+
+ if (ci->num_components == 1) {
+ ci->dither_grays = (bpp >= 8 ? 5 : 2);
+ ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
+ } else {
+ ci->dither_grays = (bpp > 8 ? 5 : 2);
+ ci->dither_colors = (bpp > 8 ? 5 : bpp > 1 ? 2 : 0);
+ }
+ } else {
+ ci->num_components = (bpp == 1 || bpp == 8 ? 1 : 3);
+ ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0);
+ ci->max_gray = (bpp >= 8 ? 255 : 1);
+ ci->dither_grays = (bpp >= 8 ? 5 : 2);
+ ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
+ }
+
+ ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp);
+
+ return 0;
+}
+
+/* new_bpp == save_bpp or new_bpp == 0 means don't change bpp.
+ ccomps == 0 means don't change number of color comps.
+ If new_bpp != 0, it must be the value of the BitsPerPixel element of
+ the plist; real_bpp may differ from new_bpp.
+*/
+private int
+cdj_put_param_bpp(gx_device *pdev, gs_param_list *plist, int new_bpp,
+ int real_bpp, int ccomps)
+{
+ if (new_bpp == 0 && ccomps == 0)
+ return gdev_prn_put_params(pdev, plist);
+ else
+ {
+ gx_device_color_info save_info;
+ int save_bpp;
+ int code;
+
+ save_info = pdev->color_info;
+ save_bpp = save_info.depth;
+#define save_ccomps save_info.num_components
+ if ( save_bpp == 8 && save_ccomps == 3 && !cprn_device->cmyk)
+ save_bpp = 3;
+ code = cdj_set_bpp(pdev, real_bpp, ccomps);
+ if ( code < 0 ) {
+ param_signal_error(plist, "BitsPerPixel", code);
+ param_signal_error(plist, "ProcessColorModel", code);
+ return code;
+ }
+ pdev->color_info.depth = new_bpp; /* cdj_set_bpp maps 3/6 to 8 */
+ code = gdev_prn_put_params(pdev, plist);
+ if ( code < 0 )
+ { cdj_set_bpp(pdev, save_bpp, save_ccomps);
+ return code;
+ }
+ cdj_set_bpp(pdev, real_bpp, ccomps); /* reset depth if needed */
+ if ((cdj->color_info.depth != save_bpp ||
+ (ccomps != 0 && ccomps != save_ccomps))
+ && pdev->is_open )
+ return gs_closedevice(pdev);
+ return 0;
+#undef save_ccomps
+ }
+}
+
+/* This returns either the number of pixels in a scan line, or the number
+ * of bytes required to store the line, both clipped to the page margins */
+private uint
+gdev_prn_rasterwidth(const gx_device_printer *pdev, int pixelcount)
+{
+ ulong raster_width =
+ pdev->width - pdev->x_pixels_per_inch * (dev_l_margin(pdev) + dev_r_margin(pdev));
+ return (pixelcount ?
+ (uint)raster_width :
+ (uint)((raster_width * pdev->color_info.depth + 7) >> 3));
+}
+
+/* Functions for manipulation params strings */
+
+private const byte*
+paramValueToString(const stringParamDescription* params, int value)
+{
+
+ for (; params->p_name; ++params) {
+ if (params->p_value == value) {
+ return (const byte *)params->p_name;
+ }
+ }
+
+ return (const byte*) 0;
+}
+
+private int
+paramStringValue(const stringParamDescription* params,
+ const byte* name, int namelen, int* value)
+{
+
+ for (; params->p_name; ++params) {
+ if (strncmp(params->p_name, (char *)name, namelen) == 0 &&
+ params->p_name[namelen] == 0) {
+ *value = params->p_value;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+private int
+put_param_string(gs_param_list* plist,
+ const byte* pname, gs_param_string* pstring,
+ const stringParamDescription* params, int *pvalue, int code)
+{
+
+ int ncode;
+
+ if ((ncode = param_read_string(plist, (char *)pname, pstring)) < 0) {
+ param_signal_error(plist, (char *)pname, code = ncode);
+ } else if (ncode == 1) {
+ pstring->data = 0, pstring->size = 0;
+ } else {
+ int value = 0;
+
+ if (paramStringValue(params, pstring->data, pstring->size,
+ &value) == 0) {
+ param_signal_error(plist, (char *)pname, code = gs_error_rangecheck);
+ } else {
+ *pvalue = value;
+ }
+ }
+
+ return code;
+}
+
+private int
+get_param_string(gs_param_list* plist,
+ const byte* pname, gs_param_string* pstring,
+ const stringParamDescription* params, int pvalue, bool persist, int code)
+{
+
+ int ncode;
+
+ pstring->data = paramValueToString(params, pvalue);
+
+ if (pstring->data == (byte*) 0) {
+ param_signal_error(plist, (char *)pname, ncode = gs_error_unknownerror);
+ } else {
+ pstring->size = strlen((char *)pstring->data);
+ pstring->persistent = persist;
+ }
+
+ if ((ncode = param_write_string(plist, (char *)pname, pstring)) < 0) {
+ code = ncode;
+ }
+
+ return code;
+}
+
+/*
+ * This taken from gsdparam.c. I hope it will be useable directly some day.
+ *
+ */
+
+private int
+cdj_param_check_bytes(gs_param_list *plist, gs_param_name pname, const byte *str,
+ uint size, bool defined)
+{ int code;
+ gs_param_string new_value;
+ switch ( code = param_read_string(plist, pname, &new_value) )
+ {
+ case 0:
+ if ( defined && new_value.size == size &&
+ !memcmp((const char *)str, (const char *)new_value.data,
+ size)
+ )
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if ( param_read_null(plist, pname) == 0 )
+ return 1;
+e: param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+
+/* This is original code. */
+
+private int
+cdj_param_check_float(gs_param_list *plist, gs_param_name pname, floatp fval,
+ bool defined)
+{ int code;
+ float new_value;
+ switch ( code = param_read_float(plist, pname, &new_value) )
+ {
+ case 0:
+ if ( defined && new_value == fval)
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if ( param_read_null(plist, pname) == 0 )
+ return 1;
+e: param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+
+/* The following dithering algorithm has been kindly given to me (YA) by
+ * Klaus-Gunther Hess, I just adapted it for use with the code here. */
+
+/*
+
+(From KGH:)
+
+Just about the features of the code:
+
+ - Stored Color-Values are BYTES in the order C-M-Y-K.
+ (Indices need to change with gdevcdj.c)
+
+ - There are individual THRESHOLDs and SPOTSIZEs for
+ the color-components. The following relation should
+ be maintained:
+ SPOTSIZE = 2 * THRESHOLD + 1
+ (The internal calculation is dedicated for limiting
+ ink-density at the 720x720DpI-Resolution of the
+ Epson-Printers, without loss of dynamic color-range)
+
+ - In addition to that there are EMIN & EMAX-Values
+ for the components. The Values are computed from
+ the dithering-algorithm and can be replaced by
+ constants, if neither the implementation nor
+ THRESHOLD and SPOTSIZE can change.
+
+ - The algorithm is tuned for speed. (K-only, if gray-
+ levels are detected, with EMIN/EMAX-clipping of
+ stored CMY-Errors. [Notice: cerr, merr, yerr are
+ *not* reset to zero! Clearing them would cause
+ regular patterns & "Halos" to appear!])
+
+*/
+
+/*
+ * Macros, that represent the undisturbed dithering-algorithm
+ *
+ * FSerror: compute the desired Value
+ * FSdecide: decision based on the value computed by FSerror
+ * FSdiffuse: distribute remaining error among pixels
+ */
+
+#define FSerror(Val,Erow,Ecol) (Val + Erow + ((7 * Ecol)>>4))
+
+#define FSdecide(Error,Threshold,Spotsize,Pixel,Bit) \
+ if(Error > Threshold) {\
+ Pixel |= Bit;\
+ Error -= Spotsize;\
+ }
+
+#define FSdiffuse(Error,Erow,Ecol,Eprev)\
+ Eprev += (3 * Error + 8)>>4;\
+ Erow = (5 * Error + Ecol + 8)>>4;\
+ Ecol = Error;
+
+/*
+ * some aliases for values from the device-structure
+ */
+#define DIRECTION direction[0]
+#define CMYK_THRESHOLD(I) threshold[I]
+#define SPOTSIZE(I) spotsize[I]
+#define EMIN(I) emin[I]
+#define EMAX(I) emax[I]
+#define NPIXEL (plane_size * 8)
+
+#define IDX_C 1
+#define IDX_M 2
+#define IDX_Y 3
+#define IDX_K 0
+
+#define ODX_C 2
+#define ODX_M 1
+#define ODX_Y 0
+#define ODX_K 3
+
+private int
+bjc_fscmyk(byte** inplanes, byte* outplanes[4][4], int** errplanes,
+ int plane_size, int scan) {
+
+ byte* err = (byte*) errplanes[0];
+
+/* =========================================================== */
+ if(scan < 0) { /* scan < 0 -> initialize private buffer */
+/* =========================================================== */
+
+ int p,i,v;
+ int *direction,*threshold,*spotsize,*emin,*emax;
+ int *errv,*errc;
+/*
+ * allocate the error-buffer
+ */
+ /*KGHorig
+ i = 4 * (5 + 1 + 1 + sd->stc.prt_pixels + 1) * sizeof(errv[0]);
+ if((sd->stc.err_size < i) || (NULL == sd->stc.err)) {
+ if(NULL != sd->stc.err)
+ gs_free(sd->stc.err,sd->stc.err_size,1,"stcm/err");
+ sd->stc.err_size = i;
+ sd->stc.err = gs_malloc(sd->stc.err_size,1,"stcm/err");
+ if(sd->stc.err == NULL) return_error(gs_error_VMerror);
+ }
+ */
+
+ direction = (int *) err;
+ threshold = direction + 4;
+ spotsize = threshold + 4;
+ emin = spotsize + 4;
+ emax = emin + 4;
+ errc = emax + 4;
+ errv = errc + 2*4;
+/*
+ * compute initial values
+ */
+ DIRECTION = -1;
+ for(i = 0; i < 4; ++i) {
+ int j;
+ float maxv = 1.0;
+ /*KGHorig
+ if((sd->stc.xfer[i].size < 1) || (sd->stc.xfer[i].data == NULL)) {
+ maxv = 1.0;
+ } else {
+ maxv = 1.0/255.0;
+ for(j = 0; j < sd->stc.xfer[i].size; ++j)
+ if(maxv < sd->stc.xfer[i].data[j])
+ maxv = sd->stc.xfer[i].data[j];
+ }
+ */
+ CMYK_THRESHOLD(i) = 127.0 / maxv + 0.5;
+ SPOTSIZE(i) = ((int) CMYK_THRESHOLD(i)<<1)+1;
+ j = CMYK_THRESHOLD(i); /* Maximum Error-Value */
+ errc[3] = 0;
+ FSdiffuse(CMYK_THRESHOLD(i),errv[0],errc[0],errv[-4]);
+ FSdiffuse(CMYK_THRESHOLD(i),errv[0],errc[0],errv[-4]);
+ EMAX(i) = errv[0];
+ errc[0] = 0;
+ FSdiffuse((-CMYK_THRESHOLD(i)),errv[0],errc[0],errv[-4]);
+ FSdiffuse((-CMYK_THRESHOLD(i)),errv[0],errc[0],errv[-4]);
+ EMIN(i) = errv[0];
+ }
+
+#ifdef CDJ_DEBUG_FS
+ for(i = 0; i < 4; ++i) fprintf(stderr,
+ "CMYK_THRESHOLD(%d)=%5d, spotsize(%d)=%5d, emin(%d)=%5d, emax(%d)=%5d\n",
+ i,CMYK_THRESHOLD(i),i,SPOTSIZE(i),i,EMIN(i),i,EMAX(i));
+#endif
+
+ for(i = 0; i < 4; ++i) errc[i] = 0;
+
+ for(p = 0; p < NPIXEL; ++p) {
+ for(i = 0; i < 4; ++i) {
+ /*KHGOrig
+ if(sd->stc.flags & STCDFLAG0) v = 0;
+ */
+ if (0) v = 0; /* Must provide a default for that. */
+ else v = (rand() % SPOTSIZE(i)) - CMYK_THRESHOLD(i);
+ FSdiffuse(v,errv[i],errc[i],errv[i-4]);
+ }
+ errv += i;
+ }
+
+/* =========================================================== */
+ } else { /* scan >= 0 -> scanline-processing */
+/* =========================================================== */
+
+ int w,p,dir,thedir;
+ byte *out[4],pixel[4],bit;
+ /*KGHorig
+ int *width = outplanes[scan];
+ */
+ int *direction = (int *) err;
+ int *threshold = direction + 4;
+ int *spotsize = threshold + 4;
+ int *emin = spotsize + 4;
+ int *emax = emin + 4;
+ int *errc = emax + 4;
+ int *errv = errc + 2*4;
+ int kerr,cerr,merr,yerr;
+
+ byte* in;
+
+ /*KGHorig
+ if(sd->stc.flags & STCDFLAG1) {
+ */
+ if (0) { /* Eventually will provide a flag for this. */
+ cerr = merr = yerr = kerr = 0;
+ } else {
+ cerr = errc[0];
+ merr = errc[1];
+ yerr = errc[2];
+ kerr = errc[3];
+ }
+
+ out[0] = outplanes[scan + 2][ODX_C];
+ out[1] = outplanes[scan + 2][ODX_M];
+ out[2] = outplanes[scan + 2][ODX_Y];
+ out[3] = outplanes[scan + 2][ODX_K];
+ pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
+
+ if(DIRECTION < 0) { /* scan == 0, run backward */
+ w = NPIXEL;
+ in = inplanes[2] + 4 * (NPIXEL - 1);
+ errv += (w-1)<<2;
+ dir = -4;
+ /*KGHorig
+ if(w > 8) for(p = 0; p < 4; ++p) out[p] += (w-1)>>3;
+ */
+ thedir = -1;
+ for (p = 0; p < 4; ++p) {
+ out[p] += plane_size - 1;
+ }
+ } else { /* run forward */
+ w = 1;
+ in = inplanes[3] - 4 * NPIXEL;
+ dir = 4;
+ thedir = 1;
+ for (p = 0; p < 4; ++p) {
+ out[p] -= plane_size;
+ }
+ } /* run backward/forward */
+
+ /*KGHorig
+ if(0 == (sd->stc.flags & STCDFLAG1)) DIRECTION = -DIRECTION;
+ */
+ if (1) DIRECTION = -DIRECTION; /* Scan in other direction. */
+
+ bit = 0x80>>((w-1) & 7);
+ w = (w+7)>>3;
+
+ for(p = NPIXEL; p; --p) { /* loop over pixels */
+
+ int cmy = in[IDX_C] | in[IDX_M] | in[IDX_Y];
+ int kv = FSerror(in[IDX_K],errv[3],kerr);
+ int cv;
+
+ FSdecide(kv,CMYK_THRESHOLD(3),SPOTSIZE(3),pixel[3],bit);
+
+ if(cmy) {
+
+ if(pixel[3] & bit) { /* black known to fire */
+
+ FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
+
+ cv = FSerror(in[IDX_C],errv[0],cerr);
+ cv -= SPOTSIZE(0);
+ if ((cv+CMYK_THRESHOLD(0)) < 0) cv = -CMYK_THRESHOLD(0);
+ FSdiffuse(cv,errv[0],cerr,errv[0-dir]);
+
+ cv = FSerror(in[IDX_M],errv[1],merr);
+ cv -= SPOTSIZE(1);
+ if ((cv+CMYK_THRESHOLD(1)) < 0) cv = -CMYK_THRESHOLD(1);
+
+ FSdiffuse(cv,errv[1],merr,errv[1-dir]);
+
+ cv = FSerror(in[IDX_Y],errv[2],yerr);
+ cv -= SPOTSIZE(2);
+ if ((cv+CMYK_THRESHOLD(2)) < 0) cv = -CMYK_THRESHOLD(2);
+ FSdiffuse(cv,errv[2],yerr,errv[2-dir]);
+
+ } else {
+
+ cv = FSerror(in[IDX_C],errv[0],cerr);
+ FSdecide(cv,CMYK_THRESHOLD(0),SPOTSIZE(0),pixel[0],bit);
+ FSdiffuse(cv,errv[0],cerr,errv[0-dir]);
+
+ cv = FSerror(in[IDX_M],errv[1],merr);
+ FSdecide(cv,CMYK_THRESHOLD(1),SPOTSIZE(1),pixel[1],bit);
+ FSdiffuse(cv,errv[1],merr,errv[1-dir]);
+
+ cv = FSerror(in[IDX_Y],errv[2],yerr);
+ FSdecide(cv,CMYK_THRESHOLD(2),SPOTSIZE(2),pixel[2],bit);
+ FSdiffuse(cv,errv[2],yerr,errv[2-dir]);
+
+ if(pixel[0] & pixel[1] & pixel[2] & bit) {
+ pixel[0] &= ~bit;
+ pixel[1] &= ~bit;
+ pixel[2] &= ~bit;
+ pixel[3] |= bit;
+ kv -= SPOTSIZE(3);
+ if ((kv+CMYK_THRESHOLD(3)) < 0) kv = -CMYK_THRESHOLD(0);
+ FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
+ }
+ }
+
+ } else {
+
+ FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
+
+ if( errv[0] > EMAX(0)) errv[0] = EMAX(0);
+ else if(errv[0] < EMIN(0)) errv[0] = EMIN(0);
+
+ if( errv[1] > EMAX(1)) errv[1] = EMAX(1);
+ else if(errv[1] < EMIN(1)) errv[1] = EMIN(1);
+
+ if( errv[2] > EMAX(2)) errv[2] = EMAX(2);
+ else if(errv[2] < EMIN(2)) errv[2] = EMIN(2);
+
+ }
+
+/*
+ * Adjust indices
+ */
+ bit = dir > 0 ? (bit>>1) : (bit<<1);
+ if(bit == 0) {
+ /*KGHorig
+ if(((*out[0] = pixel[0]) != 0) && (width[0] < w)) width[0] = w;
+ if(((*out[1] = pixel[1]) != 0) && (width[1] < w)) width[1] = w;
+ if(((*out[2] = pixel[2]) != 0) && (width[2] < w)) width[2] = w;
+ if(((*out[3] = pixel[3]) != 0) && (width[3] < w)) width[3] = w;
+ */
+ *out[0] = pixel[0];
+ *out[1] = pixel[1];
+ *out[2] = pixel[2];
+ *out[3] = pixel[3];
+ out[0] += thedir; out[1] += thedir;
+ out[2] += thedir; out[3] += thedir;
+ pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
+
+ if(dir > 0) bit = 0x80;
+ else bit = 0x01;
+ w += dir>>2;
+ }
+
+ in += dir;
+ errv += dir;
+ } /* loop over pixels */
+
+ /*KGHorig
+ if(0 == (sd->stc.flags & STCDFLAG1)) {
+ */
+ if (1) {
+ cerr = errc[0] = cerr;
+ merr = errc[1] = merr;
+ yerr = errc[2] = yerr;
+ kerr = errc[3] = kerr;
+ }
+
+/* =========================================================== */
+ } /* initialization or scanline-Processing */
+/* =========================================================== */
+
+ return 0;
+}
+
diff --git a/gs/src/gdevcgm.c b/gs/src/gdevcgm.c
new file mode 100644
index 000000000..d8db7ff0b
--- /dev/null
+++ b/gs/src/gdevcgm.c
@@ -0,0 +1,474 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcgm.c */
+/* CGM (Computer Graphics Metafile) driver */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gsparam.h"
+#include "gdevcgml.h"
+#include "gdevpccm.h"
+
+/**************** Future optimizations:
+ Do tile_rectangle with pattern
+ Keep track of painted area,
+ do masked copy_mono with cell array if possible
+ ****************/
+
+#define fname_size 80
+
+typedef struct gx_device_cgm_s {
+ gx_device_common;
+ char fname[fname_size + 1];
+ FILE *file;
+ cgm_state *st;
+ bool in_picture;
+} gx_device_cgm;
+/* GC descriptor */
+gs_private_st_suffix_add1_final(st_device_cgm, gx_device_cgm,
+ "gx_device_cgm", device_cgm_enum_ptrs, device_cgm_reloc_ptrs,
+ gx_device_finalize, st_device, st);
+
+/* Device procedures */
+private dev_proc_open_device(cgm_open);
+private dev_proc_output_page(cgm_output_page);
+private dev_proc_close_device(cgm_close);
+private dev_proc_fill_rectangle(cgm_fill_rectangle);
+#if 0
+private dev_proc_tile_rectangle(cgm_tile_rectangle);
+#else
+#define cgm_tile_rectangle NULL
+#endif
+private dev_proc_copy_mono(cgm_copy_mono);
+private dev_proc_copy_color(cgm_copy_color);
+private dev_proc_get_params(cgm_get_params);
+private dev_proc_put_params(cgm_put_params);
+
+/* In principle, all the drawing operations should be polymorphic, */
+/* but it's just as easy just to test the depth, since we're not */
+/* very concerned about performance. */
+#define cgm_device(dname, depth, max_value, dither, map_rgb_color, map_color_rgb)\
+{ std_device_color_stype_body(gx_device_cgm, 0, dname, &st_device_cgm,\
+ 850, 1100, 100, 100, depth, max_value, dither),\
+ { cgm_open,\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ cgm_output_page,\
+ cgm_close,\
+ map_rgb_color,\
+ map_color_rgb,\
+ cgm_fill_rectangle,\
+ cgm_tile_rectangle,\
+ cgm_copy_mono,\
+ cgm_copy_color,\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ cgm_get_params,\
+ cgm_put_params\
+ },\
+ { 0 }, /* fname */\
+ 0, /* file */\
+ 0, /* st */\
+ 0 /*false*/ /* in_picture */\
+}
+
+gx_device_cgm far_data gs_cgmmono_device =
+ cgm_device("cgmmono", 1, 1, 2,
+ gx_default_map_rgb_color, gx_default_w_b_map_color_rgb);
+
+gx_device_cgm far_data gs_cgm8_device =
+ cgm_device("cgm8", 8, 6, 7,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+
+gx_device_cgm far_data gs_cgm24_device =
+ cgm_device("cgm24", 24, 255, 255,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+
+/* Define allocator procedures for the CGM library. */
+private void *
+cgm_gs_alloc(void *private_data, uint size)
+{ gx_device_cgm *cdev = private_data;
+ gs_memory_t *mem =
+ (cdev->memory == 0 ? &gs_memory_default : cdev->memory);
+ return gs_alloc_bytes(mem, size, "cgm_gs_alloc");
+}
+private void
+cgm_gs_free(void *private_data, void *obj)
+{ gx_device_cgm *cdev = private_data;
+ gs_memory_t *mem =
+ (cdev->memory == 0 ? &gs_memory_default : cdev->memory);
+ gs_free_object(mem, obj, "cgm_gs_free");
+}
+
+/* ---------------- Utilities ---------------- */
+
+/* Convert a CGM result code to our error values. */
+private int near
+cgm_error_code(cgm_result result)
+{ switch ( result )
+ {
+ default:
+ case cgm_result_wrong_state: return gs_error_unknownerror;
+ case cgm_result_out_of_range: return gs_error_rangecheck;
+ case cgm_result_io_error: return gs_error_ioerror;
+ }
+}
+#define check_result(result)\
+ if ( result != cgm_result_ok ) return_error(cgm_error_code(result))
+
+/* ---------------- Device control ---------------- */
+
+/* Open the device */
+private int
+cgm_open(gx_device *dev)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ cgm_allocator cal;
+ static const int elements[] = { -1, 1 };
+ cgm_metafile_elements meta;
+ cgm_result result;
+
+ cdev->file = fopen(cdev->fname, "wb");
+ if ( cdev->file == 0 )
+ return_error(gs_error_ioerror);
+ cal.private_data = cdev;
+ cal.alloc = cgm_gs_alloc;
+ cal.free = cgm_gs_free;
+ cdev->st = cgm_initialize(cdev->file, &cal);
+ if ( cdev->st == 0 )
+ return_error(gs_error_VMerror);
+ result = cgm_BEGIN_METAFILE(cdev->st, "", 0);
+ check_result(result);
+ meta.metafile_version = 1;
+ meta.vdc_type = cgm_vdc_integer;
+ meta.integer_precision = sizeof(cgm_int) * 8;
+ meta.index_precision = sizeof(cgm_int) * 8;
+ meta.color_precision = 8;
+ /* If we use color indices at all, they are only 1 byte. */
+ meta.color_index_precision = 8;
+ meta.maximum_color_index = (1L << cdev->color_info.depth) - 1;
+ meta.metafile_element_list = elements,
+ meta.metafile_element_list_count = countof(elements) / 2;
+ result = cgm_set_metafile_elements(cdev->st, &meta,
+ cgm_set_METAFILE_VERSION |
+ cgm_set_VDC_TYPE |
+ cgm_set_INTEGER_PRECISION |
+ cgm_set_INDEX_PRECISION |
+ cgm_set_COLOR_PRECISION |
+ cgm_set_COLOR_INDEX_PRECISION |
+ cgm_set_MAXIMUM_COLOR_INDEX |
+ cgm_set_METAFILE_ELEMENT_LIST);
+ check_result(result);
+ cdev->in_picture = false;
+ return 0;
+}
+
+/* Output a page */
+private int
+cgm_output_page(gx_device *dev, int num_copies, int flush)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ if ( cdev->in_picture )
+ { cgm_result result = cgm_END_PICTURE(cdev->st);
+ check_result(result);
+ cdev->in_picture = false;
+ }
+ return 0;
+}
+
+/* Close the device */
+private int
+cgm_close(gx_device *dev)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ int code = cgm_output_page(dev, 1, 0);
+ cgm_result result;
+
+ if ( code < 0 )
+ return code;
+ result = cgm_END_METAFILE(cdev->st);
+ check_result(result);
+ result = cgm_terminate(cdev->st);
+ check_result(result);
+ cdev->st = 0;
+ fclose(cdev->file);
+ cdev->file = 0;
+ return 0;
+}
+
+/* Get parameters. CGM devices add OutputFile to the default set. */
+private int
+cgm_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ int code = gx_default_get_params(dev, plist);
+ gs_param_string ofns;
+
+ if ( code < 0 ) return code;
+ ofns.data = (const byte *)cdev->fname,
+ ofns.size = strlen(cdev->fname),
+ ofns.persistent = false;
+ return param_write_string(plist, "OutputFile", &ofns);
+}
+
+/* Put parameters. */
+private int
+cgm_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ int ecode = 0;
+ int code;
+ const char _ds *param_name;
+ gs_param_string ofs;
+
+ switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofs) )
+ {
+ case 0:
+ if ( ofs.size > fname_size )
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto ofe;
+ default:
+ ecode = code;
+ofe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ ofs.data = 0;
+ break;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gx_default_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ if ( ofs.data != 0 )
+ { /* Close the file if it's open. */
+ if ( cdev->file != 0 )
+ { fclose(cdev->file);
+ cdev->file = 0;
+ }
+ memcpy(cdev->fname, ofs.data, ofs.size);
+ cdev->fname[ofs.size] = 0;
+ cdev->file = fopen(cdev->fname, "wb");
+ if ( cdev->file == 0 )
+ return_error(gs_error_ioerror);
+ }
+
+ return 0;
+}
+
+/* ---------------- Drawing ---------------- */
+
+/* Set the corner points for a rectangle. It appears (although */
+/* this is not obvious from the CGM specification) that rectangles */
+/* are specified with closed, rather than half-open, intervals. */
+#define cgm_set_rect(points, xo, yo, w, h)\
+ points[1].integer.x = (points[0].integer.x = xo) + (w) - 1,\
+ points[1].integer.y = (points[0].integer.y = yo) + (h) - 1
+
+/* Set the points for a cell array. */
+#define cgm_set_cell_points(pqr, xo, yo, w, h)\
+ pqr[0].integer.x = (xo),\
+ pqr[0].integer.y = (yo),\
+ pqr[1].integer.x = (xo) + (w),\
+ pqr[1].integer.y = (yo) + (h),\
+ pqr[2].integer.x = (xo) + (w),\
+ pqr[2].integer.y = (yo)
+
+/* Begin a picture if necessary. */
+#define begin_picture(cdev)\
+ if ( !cdev->in_picture ) cgm_begin_picture(cdev)
+private int
+cgm_begin_picture(gx_device_cgm *cdev)
+{ cgm_picture_elements pic;
+ cgm_result result;
+ cgm_edge_width edge;
+
+ result = cgm_BEGIN_PICTURE(cdev->st, "", 0);
+ check_result(result);
+ pic.scaling_mode = cgm_scaling_abstract;
+ pic.color_selection_mode =
+ (cdev->color_info.depth <= 8 ?
+ cgm_color_selection_indexed :
+ cgm_color_selection_direct);
+ pic.line_width_specification_mode = cgm_line_marker_absolute;
+ pic.edge_width_specification_mode = cgm_line_marker_absolute;
+ cgm_set_rect(pic.vdc_extent, 0, 0, cdev->width, cdev->height);
+ result = cgm_set_picture_elements(cdev->st, &pic,
+ cgm_set_SCALING_MODE |
+ cgm_set_COLOR_SELECTION_MODE |
+ cgm_set_LINE_WIDTH_SPECIFICATION_MODE |
+ cgm_set_EDGE_WIDTH_SPECIFICATION_MODE |
+ cgm_set_VDC_EXTENT);
+ check_result(result);
+ result = cgm_BEGIN_PICTURE_BODY(cdev->st);
+ check_result(result);
+ result = cgm_VDC_INTEGER_PRECISION(cdev->st,
+ (cdev->width <= 0x7fff &&
+ cdev->height <= 0x7fff ?
+ 16 : sizeof(cdev->width) * 8));
+ check_result(result);
+ edge.absolute.integer = 0;
+ result = cgm_EDGE_WIDTH(cdev->st, &edge);
+ check_result(result);
+ if ( cdev->color_info.depth <= 8 )
+ { cgm_color colors[256];
+ int i;
+ for ( i = 0; i < (1 << cdev->color_info.depth); i++ )
+ { gx_color_value rgb[3];
+ (*dev_proc(cdev, map_color_rgb))((gx_device *)cdev,
+ (gx_color_index)i, rgb);
+ colors[i].rgb.r =
+ rgb[0] >> (gx_color_value_bits - 8);
+ colors[i].rgb.g =
+ rgb[1] >> (gx_color_value_bits - 8);
+ colors[i].rgb.b =
+ rgb[2] >> (gx_color_value_bits - 8);
+ }
+ result = cgm_COLOR_TABLE(cdev->st, 0, colors,
+ 1 << cdev->color_info.depth);
+ check_result(result);
+ }
+ cdev->in_picture = true;
+ return 0;
+}
+
+/* Convert a gx_color_index to a CGM color. */
+private void
+cgm_color_from_color_index(cgm_color *pcc, const gx_device_cgm *cdev,
+ gx_color_index color)
+{ if ( cdev->color_info.depth <= 8 )
+ pcc->index = color;
+ else
+ { pcc->rgb.r = color >> 16;
+ pcc->rgb.g = (color >> 8) & 255;
+ pcc->rgb.b = color & 255;
+ }
+}
+
+/* Fill a rectangle. */
+private int
+cgm_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ cgm_color fill_color;
+ cgm_point points[2];
+ cgm_result result;
+
+ fit_fill(dev, x, y, w, h);
+ if ( !cdev->in_picture )
+ { /* Check for erasepage. */
+ if ( color == (*dev_proc(dev, map_rgb_color))(dev,
+ gx_max_color_value, gx_max_color_value,
+ gx_max_color_value)
+ )
+ return 0;
+ cgm_begin_picture(cdev);
+ }
+ cgm_color_from_color_index(&fill_color, cdev, color);
+ result = cgm_FILL_COLOR(cdev->st, &fill_color);
+ check_result(result);
+ result = cgm_INTERIOR_STYLE(cdev->st, cgm_interior_style_solid);
+ check_result(result);
+ cgm_set_rect(points, x, y, w, h);
+ result = cgm_RECTANGLE(cdev->st, &points[0], &points[1]);
+ check_result(result);
+ return 0;
+}
+
+#if 0
+/* Tile a rectangle. We should do this with a pattern if possible. */
+private int
+cgm_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one,
+ int px, int py)
+{
+}
+#endif
+
+/* Copy a monochrome bitmap. Unfortunately, CGM doesn't provide a */
+/* masked fill operation; if one of the colors is transparent, */
+/* we have to do the copy by filling lots of tiny little rectangles. */
+/* A much better way to implement this would be to remember whether */
+/* the destination region is still white; if so, we can use a cell array */
+/* (or, even better, a pattern). However, we still need the slow method */
+/* for the case where we don't know the background color or it isn't white. */
+private int
+cgm_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ /* The current implementation is about as inefficient as */
+ /* one could possibly imagine! */
+ int ix, iy;
+ cgm_result result;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ begin_picture(cdev);
+ if ( zero == 0 && one == 1 && cdev->color_info.depth == 1 )
+ { cgm_point pqr[3];
+ cgm_set_cell_points(pqr, x, y, w, h);
+ result = cgm_CELL_ARRAY(cdev->st, pqr, w, h, 1,
+ cgm_cell_mode_packed,
+ base, sourcex, raster);
+ check_result(result);
+ }
+ else
+ { result = cgm_INTERIOR_STYLE(cdev->st, cgm_interior_style_solid);
+ check_result(result);
+ for ( iy = 0; iy < h; iy++ )
+ for ( ix = 0; ix < w; ix++ )
+ { int px = ix + sourcex;
+ const byte *pixel = &base[iy * raster + (px >> 3)];
+ byte mask = 0x80 >> (px & 7);
+ gx_color_index color = (*pixel & mask ? one : zero);
+ if ( color != gx_no_color_index )
+ { cgm_color fill_color;
+ cgm_point points[2];
+ cgm_color_from_color_index(&fill_color, cdev, color);
+ cgm_set_rect(points, x, y, 1, 1);
+ result = cgm_RECTANGLE(cdev->st, &points[0], &points[1]);
+ check_result(result);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+cgm_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ gx_device_cgm *cdev = (gx_device_cgm *)dev;
+ int depth = cdev->color_info.depth;
+ uint source_bit = sourcex * depth;
+ cgm_point pqr[3];
+ cgm_result result;
+
+ if ( depth == 1 )
+ return cgm_copy_mono(dev, base, sourcex, raster, id,
+ x, y, w, h,
+ (gx_color_index)0, (gx_color_index)1);
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ begin_picture(cdev);
+ cgm_set_cell_points(pqr, x, y, w, h);
+ result = cgm_CELL_ARRAY(cdev->st, pqr, w, h, 0, cgm_cell_mode_packed,
+ base, source_bit, raster);
+ check_result(result);
+ return 0;
+}
diff --git a/gs/src/gdevcgml.c b/gs/src/gdevcgml.c
new file mode 100644
index 000000000..fa1439cc5
--- /dev/null
+++ b/gs/src/gdevcgml.c
@@ -0,0 +1,990 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcgml.c */
+/* CGM-writing library */
+#include "memory_.h"
+#include "stdio_.h"
+#include "gdevcgmx.h"
+
+/* Forward references to command-writing procedures */
+private void begin_command(P2(cgm_state *, cgm_op_index));
+#define OP(op) begin_command(st, op)
+private cgm_result end_command(P1(cgm_state *));
+#define END_OP (void)end_command(st)
+#define END return end_command(st)
+/* Parameters */
+private void put_int(P3(cgm_state *, cgm_int, int));
+#define CI(ci) put_int(st, ci, st->metafile.color_index_precision)
+#define I(i) put_int(st, i, st->metafile.integer_precision)
+#define IX(ix) put_int(st, ix, st->metafile.index_precision)
+#define E(e) put_int(st, (int)(e), 16)
+private void put_real(P3(cgm_state *, cgm_real, const cgm_precision *));
+#define R(r) put_real(st, r, &st->metafile.real_precision)
+private void put_vdc(P2(cgm_state *, const cgm_vdc *));
+#define VDC(vdc) put_vdc(st, vdc)
+#define VDC2(vdc1, vdc2) VDC(vdc1); VDC(vdc2)
+#define VDC4(vdc1, vdc2, vdc3, vdc4) VDC2(vdc1, vdc2); VDC2(vdc3, vdc4)
+private void put_vdc_r(P3(cgm_state *, const cgm_line_marker_extent *, cgm_line_marker_specification_mode));
+#define VDC_R(vdcr, mode) put_vdc_r(st, vdcr, mode)
+private void put_point(P2(cgm_state *, const cgm_point *));
+#define P(p) put_point(st, p)
+private void put_points(P3(cgm_state *, const cgm_point *, int));
+#define nP(p, n) put_points(st, p, n)
+private void put_string(P3(cgm_state *, const char *, uint));
+#define S(s, l) put_string(st, s, l)
+private void put_color(P2(cgm_state *, const cgm_color *));
+#define CO(co) put_color(st, co)
+private void put_rgb(P2(cgm_state *, const cgm_rgb *));
+#define CD(cd) put_rgb(st, cd)
+/* Other data types */
+#define put_byte(st, b)\
+ if ( st->command_count == command_max_count ) write_command(st, false);\
+ st->command[st->command_count++] = (byte)(b)
+private void put_bytes(P3(cgm_state *, const byte *, uint));
+private void write_command(P2(cgm_state *, bool));
+private void put_real_precision(P2(cgm_state *, const cgm_precision *));
+
+/* ================ Public routines ================ */
+
+/* ---------------- Initialize/terminate ---------------- */
+
+/* Initialize a CGM writer. */
+cgm_state *
+cgm_initialize(FILE *file, const cgm_allocator *cal)
+{ cgm_state *st = (*cal->alloc)(cal->private_data, sizeof(cgm_state));
+ if ( st == 0 )
+ return 0;
+ st->file = file;
+ st->allocator = *cal;
+ /* Initialize metafile elements. */
+ st->metafile.vdc_type = cgm_vdc_integer;
+ st->metafile.integer_precision = 16;
+ st->metafile.real_precision.representation = cgm_representation_fixed;
+ st->metafile.real_precision.exponent_or_whole_width = 16;
+ st->metafile.real_precision.fraction_width = 16;
+ st->metafile.index_precision = 16;
+ st->metafile.color_precision = 8;
+ st->metafile.color_index_precision = 8;
+ st->metafile.maximum_color_index = 63;
+ /* color_value_extent */
+ /*st->metafile.character_coding_announcer = 0;*/
+ /* Initialize picture elements. */
+ st->picture.scaling_mode = cgm_scaling_abstract;
+ st->picture.color_selection_mode = cgm_color_selection_indexed;
+ st->picture.line_width_specification_mode = cgm_line_marker_absolute;
+ st->picture.marker_size_specification_mode = cgm_line_marker_absolute;
+ st->picture.edge_width_specification_mode = cgm_line_marker_absolute;
+ /* vdc_extent */
+ /* background_color */
+ /* Initialize control elements. */
+ st->vdc_integer_precision = st->metafile.integer_precision;
+ st->vdc_real_precision = st->metafile.real_precision;
+ st->transparency = cgm_transparency_on;
+ /* clip_rectangle */
+ st->clip_indicator = cgm_clip_on;
+ /* Initialize other state elements. */
+ st->line_bundle_index = 1;
+ st->line_type = cgm_line_solid;
+ /* line_width */
+ /* line_color */
+ st->marker_bundle_index = 1;
+ st->marker_type = cgm_marker_asterisk;
+ /* marker_size */
+ /* marker_color */
+ st->text_bundle_index = 1;
+ st->text_font_index = 1;
+ st->text_precision = cgm_text_precision_string;
+ st->character_expansion_factor = 1.0;
+ st->character_spacing = 0.0;
+ /* text_color */
+ /* character_height */
+ /* character_orientation */
+ st->text_path = cgm_text_path_right;
+ /* text_alignment */
+ st->character_set_index = 1;
+ st->alternate_character_set_index = 1;
+ st->fill_bundle_index = 1;
+ st->interior_style = cgm_interior_style_hollow;
+ st->hatch_index = cgm_hatch_horizontal;
+ st->pattern_index = 1;
+ st->edge_bundle_index = 1;
+ st->edge_type = cgm_edge_solid;
+ /* edge_width */
+ st->edge_visibility = false;
+ /* fill_reference_point */
+ /* pattern_table */
+ /* pattern_size */
+ /* color_table */
+ memset(st->source_flags, (byte)cgm_aspect_source_individual,
+ sizeof(st->source_flags));
+ return st;
+}
+
+/* Terminate a CGM writer. */
+cgm_result
+cgm_terminate(cgm_state *st)
+{ (*st->allocator.free)(st->allocator.private_data, st);
+ return cgm_result_ok;
+}
+
+/* ---------------- Metafile elements ---------------- */
+
+cgm_result
+cgm_BEGIN_METAFILE(cgm_state *st, const char *str, uint len)
+{ OP(BEGIN_METAFILE);
+ S(str, len);
+ END;
+}
+
+cgm_result
+cgm_set_metafile_elements(cgm_state *st, const cgm_metafile_elements *meta, long mask)
+{ if ( (mask & cgm_set_METAFILE_VERSION) )
+ { OP(METAFILE_VERSION);
+ I(meta->metafile_version);
+ END_OP;
+ st->metafile.metafile_version = meta->metafile_version;
+ }
+ if ( (mask & cgm_set_METAFILE_DESCRIPTION) )
+ { OP(METAFILE_DESCRIPTION);
+ S(meta->metafile_description.chars, meta->metafile_description.length);
+ END_OP;
+ st->metafile.metafile_description = meta->metafile_description;
+ }
+ if ( (mask & cgm_set_VDC_TYPE) )
+ { OP(VDC_TYPE);
+ E(meta->vdc_type);
+ END_OP;
+ st->metafile.vdc_type = meta->vdc_type;
+ }
+ if ( (mask & cgm_set_INTEGER_PRECISION) )
+ { OP(INTEGER_PRECISION);
+ I(meta->integer_precision);
+ END_OP;
+ st->metafile.integer_precision = meta->integer_precision;
+ }
+ if ( (mask & cgm_set_REAL_PRECISION) )
+ { OP(REAL_PRECISION);
+ put_real_precision(st, &meta->real_precision);
+ END_OP;
+ st->metafile.real_precision = meta->real_precision;
+ }
+ if ( (mask & cgm_set_INDEX_PRECISION) )
+ { OP(INDEX_PRECISION);
+ I(meta->index_precision);
+ END_OP;
+ st->metafile.index_precision = meta->index_precision;
+ }
+ if ( (mask & cgm_set_COLOR_PRECISION) )
+ { OP(COLOR_PRECISION);
+ I(meta->color_precision);
+ END_OP;
+ st->metafile.color_index_precision = meta->color_index_precision;
+ }
+ if ( (mask & cgm_set_COLOR_INDEX_PRECISION) )
+ { OP(COLOR_INDEX_PRECISION);
+ I(meta->color_index_precision);
+ END_OP;
+ st->metafile.color_index_precision = meta->color_index_precision;
+ }
+ if ( (mask & cgm_set_MAXIMUM_COLOR_INDEX) )
+ { OP(MAXIMUM_COLOR_INDEX);
+ CI(meta->maximum_color_index);
+ END_OP;
+ st->metafile.maximum_color_index = meta->maximum_color_index;
+ }
+ if ( (mask & cgm_set_METAFILE_ELEMENT_LIST) )
+ { int i;
+ const int *p;
+ OP(METAFILE_ELEMENT_LIST);
+ for ( i = 0, p = meta->metafile_element_list;
+ i < meta->metafile_element_list_count;
+ i++, p += 2
+ )
+ { I(p[0]); I(p[1]);
+ }
+ END_OP;
+ st->metafile.metafile_element_list =
+ meta->metafile_element_list;
+ st->metafile.metafile_element_list_count =
+ meta->metafile_element_list_count;
+ }
+ /* element list */
+ if ( (mask & cgm_set_FONT_LIST) )
+ { int i;
+ OP(FONT_LIST);
+ for ( i = 0; i < meta->font_list_count; ++i )
+ S(meta->font_list[i].chars, meta->font_list[i].length);
+ END_OP;
+ st->metafile.font_list = meta->font_list;
+ st->metafile.font_list_count = meta->font_list_count;
+ }
+ /* character set list */
+ /* character coding announcer */
+ return st->result;
+}
+
+cgm_result
+cgm_END_METAFILE(cgm_state *st)
+{ OP(END_METAFILE);
+ END;
+}
+
+/* ---------------- Picture elements ---------------- */
+
+cgm_result
+cgm_BEGIN_PICTURE(cgm_state *st, const char *str, uint len)
+{ OP(BEGIN_PICTURE);
+ S(str, len);
+ END;
+}
+
+cgm_result
+cgm_set_picture_elements(cgm_state *st, const cgm_picture_elements *pic, long mask)
+{ if ( (mask & cgm_set_SCALING_MODE) )
+ { OP(SCALING_MODE);
+ E(pic->scaling_mode);
+ R(pic->scale_factor);
+ st->picture.scaling_mode = pic->scaling_mode;
+ st->picture.scale_factor = pic->scale_factor;
+ END_OP;
+ }
+ if ( (mask & cgm_set_COLOR_SELECTION_MODE) )
+ { OP(COLOR_SELECTION_MODE);
+ E(pic->color_selection_mode);
+ END_OP;
+ st->picture.color_selection_mode = pic->color_selection_mode;
+ }
+ if ( (mask & cgm_set_LINE_WIDTH_SPECIFICATION_MODE) )
+ { OP(LINE_WIDTH_SPECIFICATION_MODE);
+ E(pic->line_width_specification_mode);
+ END_OP;
+ st->picture.line_width_specification_mode = pic->line_width_specification_mode;
+ }
+ if ( (mask & cgm_set_MARKER_SIZE_SPECIFICATION_MODE) )
+ { OP(MARKER_SIZE_SPECIFICATION_MODE);
+ E(pic->marker_size_specification_mode);
+ END_OP;
+ st->picture.marker_size_specification_mode = pic->marker_size_specification_mode;
+ }
+ if ( (mask & cgm_set_EDGE_WIDTH_SPECIFICATION_MODE) )
+ { OP(EDGE_WIDTH_SPECIFICATION_MODE);
+ E(pic->edge_width_specification_mode);
+ END_OP;
+ st->picture.edge_width_specification_mode = pic->edge_width_specification_mode;
+ }
+ if ( (mask & cgm_set_VDC_EXTENT) )
+ { OP(VDC_EXTENT);
+ P(&pic->vdc_extent[0]);
+ P(&pic->vdc_extent[1]);
+ END_OP;
+ st->picture.vdc_extent[0] = pic->vdc_extent[0];
+ st->picture.vdc_extent[1] = pic->vdc_extent[1];
+ }
+ if ( (mask & cgm_set_BACKGROUND_COLOR) )
+ { OP(BACKGROUND_COLOR);
+ CD(&pic->background_color.rgb);
+ END;
+ st->picture.background_color = pic->background_color;
+ }
+ return st->result;
+}
+
+cgm_result
+cgm_BEGIN_PICTURE_BODY(cgm_state *st)
+{ OP(BEGIN_PICTURE_BODY);
+ END;
+}
+
+cgm_result
+cgm_END_PICTURE(cgm_state *st)
+{ OP(END_PICTURE);
+ END;
+}
+
+/* ---------------- Control elements ---------------- */
+
+cgm_result
+cgm_VDC_INTEGER_PRECISION(cgm_state *st, int precision)
+{ if ( st->vdc_integer_precision != precision )
+ { OP(VDC_INTEGER_PRECISION);
+ I(precision); st->vdc_integer_precision = precision;
+ END;
+ }
+ else
+ return cgm_result_ok;
+}
+
+cgm_result
+cgm_VDC_REAL_PRECISION(cgm_state *st, const cgm_precision *precision)
+{ OP(VDC_REAL_PRECISION);
+ put_real_precision(st, precision); st->vdc_real_precision = *precision;
+ END;
+}
+
+cgm_result
+cgm_AUXILIARY_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(AUXILIARY_COLOR);
+ CO(color); st->auxiliary_color = *color;
+ END;
+}
+
+cgm_result
+cgm_TRANSPARENCY(cgm_state *st, cgm_transparency transparency)
+{ OP(TRANSPARENCY);
+ E(transparency); st->transparency = transparency;
+ END;
+}
+
+cgm_result
+cgm_CLIP_RECTANGLE(cgm_state *st, const cgm_point rectangle[2])
+{ OP(CLIP_RECTANGLE);
+ P(&rectangle[0]); st->clip_rectangle[0] = rectangle[0];
+ P(&rectangle[1]); st->clip_rectangle[1] = rectangle[1];
+ END;
+}
+
+cgm_result
+cgm_CLIP_INDICATOR(cgm_state *st, cgm_clip_indicator clip)
+{ OP(CLIP_INDICATOR);
+ E(clip); st->clip_indicator = clip;
+ END;
+}
+
+/* ---------------- Graphical primitive elements ---------------- */
+
+cgm_result
+cgm_POLYLINE(cgm_state *st, const cgm_point *vertices, int count)
+{ OP(POLYLINE);
+ nP(vertices, count);
+ END;
+}
+
+cgm_result
+cgm_DISJOINT_POLYLINE(cgm_state *st, const cgm_point *endpoints, int count)
+{ OP(DISJOINT_POLYLINE);
+ nP(endpoints, count);
+ END;
+}
+
+cgm_result
+cgm_POLYMARKER(cgm_state *st, const cgm_point *positions, int count)
+{ OP(POLYMARKER);
+ nP(positions, count);
+ END;
+}
+
+cgm_result
+cgm_TEXT(cgm_state *st, const cgm_point *position, bool final, const char *str, uint len)
+{ OP(TEXT);
+ P(position); E(final); S(str, len);
+ END;
+}
+
+cgm_result
+cgm_RESTRICTED_TEXT(cgm_state *st, const cgm_vdc *delta_width, const cgm_vdc *delta_height, const cgm_point *position, bool final, const char *str, uint len)
+{ OP(RESTRICTED_TEXT);
+ VDC2(delta_width, delta_height); P(position); E(final); S(str, len);
+ END;
+}
+
+cgm_result
+cgm_APPEND_TEXT(cgm_state *st, bool final, const char *str, uint len)
+{ OP(APPEND_TEXT);
+ E(final); S(str, len);
+ END;
+}
+
+cgm_result
+cgm_POLYGON(cgm_state *st, const cgm_point *vertices, int count)
+{ OP(POLYGON);
+ nP(vertices, count);
+ END;
+}
+
+cgm_result
+cgm_POLYGON_SET(cgm_state *st, const cgm_polygon_edge *vertices, int count)
+{ int i;
+ OP(POLYGON);
+ for ( i = 0; i < count; ++i )
+ { P(&vertices[i].vertex);
+ E(vertices[i].edge_out);
+ }
+ END;
+}
+
+cgm_result
+cgm_CELL_ARRAY(cgm_state *st, const cgm_point *pqr /*[3]*/, cgm_int nx, cgm_int ny, cgm_int local_color_precision, cgm_cell_representation_mode mode, const byte *values, uint source_bit, uint raster)
+{ int precision = local_color_precision;
+ int bits_per_pixel;
+ uint row_bytes;
+ const byte *row = values + (source_bit >> 3);
+ int bit = source_bit & 7;
+ int y;
+
+ /* Currently we ignore the cell representation_mode, and always */
+ /* produce cell arrays in 'packed' format. */
+ mode = cgm_cell_mode_packed;
+ OP(CELL_ARRAY);
+ nP(pqr, 3); I(nx); I(ny); I(local_color_precision); E(mode);
+ if ( precision == 0 )
+ precision = (st->picture.color_selection_mode ==
+ cgm_color_selection_indexed ?
+ st->metafile.color_index_precision :
+ st->metafile.color_precision);
+ bits_per_pixel =
+ (st->picture.color_selection_mode == cgm_color_selection_indexed ?
+ precision : precision * 3);
+ row_bytes = (bits_per_pixel * nx + 7) >> 3;
+ for ( y = 0; y < ny; y++, row += raster )
+ { if ( bit == 0 )
+ put_bytes(st, row, row_bytes);
+ else
+ { uint i;
+ for ( i = 0; i < row_bytes; i++ )
+ { byte b = (row[i] << bit) +
+ (row[i+1] >> (8 - bit));
+ put_byte(st, b);
+ }
+ }
+ if ( (row_bytes & 1) )
+ { put_byte(st, 0);
+ }
+ }
+ END;
+}
+
+cgm_result
+cgm_RECTANGLE(cgm_state *st, const cgm_point *corner1, const cgm_point *corner2)
+{ OP(RECTANGLE);
+ P(corner1); P(corner2);
+ END;
+}
+
+cgm_result
+cgm_CIRCLE(cgm_state *st, const cgm_point *center, const cgm_vdc *radius)
+{ OP(CIRCLE);
+ P(center); VDC(radius);
+ END;
+}
+
+cgm_result
+cgm_CIRCULAR_ARC_3_POINT(cgm_state *st, const cgm_point *start, const cgm_point *intermediate, const cgm_point *end)
+{ OP(CIRCULAR_ARC_3_POINT);
+ P(start); P(intermediate); P(end);
+ END;
+}
+
+cgm_result
+cgm_CIRCULAR_ARC_3_POINT_CLOSE(cgm_state *st, const cgm_point *start, const cgm_point *intermediate, const cgm_point *end, cgm_arc_closure closure)
+{ OP(CIRCULAR_ARC_3_POINT_CLOSE);
+ P(start); P(intermediate); P(end); E(closure);
+ END;
+}
+
+cgm_result
+cgm_CIRCULAR_ARC_CENTER(cgm_state *st, const cgm_point *center, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, const cgm_vdc *radius)
+{ OP(CIRCULAR_ARC_CENTER);
+ P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius);
+ END;
+}
+
+cgm_result
+cgm_CIRCULAR_ARC_CENTER_CLOSE(cgm_state *st, const cgm_point *center, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, const cgm_vdc *radius, cgm_arc_closure closure)
+{ OP(CIRCULAR_ARC_CENTER_CLOSE);
+ P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius);
+ E(closure);
+ END;
+}
+
+cgm_result
+cgm_ELLIPSE(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end)
+{ OP(ELLIPSE);
+ P(center); P(cd1_end); P(cd2_end);
+ END;
+}
+
+cgm_result
+cgm_ELLIPTICAL_ARC(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end)
+{ OP(ELLIPTICAL_ARC);
+ P(center); P(cd1_end); P(cd2_end);
+ VDC4(dx_start, dy_start, dx_end, dy_end);
+ END;
+}
+
+cgm_result
+cgm_ELLIPTICAL_ARC_CLOSE(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, cgm_arc_closure closure)
+{ OP(ELLIPTICAL_ARC_CLOSE);
+ P(center); P(cd1_end); P(cd2_end);
+ VDC4(dx_start, dy_start, dx_end, dy_end); E(closure);
+ END;
+}
+
+/* ---------------- Attribute elements ---------------- */
+
+cgm_result
+cgm_LINE_BUNDLE_INDEX(cgm_state *st, cgm_int index)
+{ OP(LINE_BUNDLE_INDEX);
+ IX(index); st->line_bundle_index = index;
+ END;
+}
+
+cgm_result
+cgm_LINE_TYPE(cgm_state *st, cgm_line_type line_type)
+{ OP(LINE_TYPE);
+ IX((int)line_type); st->line_type = line_type;
+ END;
+}
+
+cgm_result
+cgm_LINE_WIDTH(cgm_state *st, const cgm_line_width *line_width)
+{ OP(LINE_WIDTH);
+ VDC_R(line_width, st->picture.line_width_specification_mode);
+ st->line_width = *line_width;
+ END;
+}
+
+cgm_result
+cgm_LINE_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(LINE_COLOR);
+ CO(color); st->line_color = *color;
+ END;
+}
+
+cgm_result
+cgm_MARKER_BUNDLE_INDEX(cgm_state *st, cgm_int index)
+{ OP(MARKER_BUNDLE_INDEX);
+ IX(index); st->marker_bundle_index = index;
+ END;
+}
+
+cgm_result
+cgm_MARKER_TYPE(cgm_state *st, cgm_marker_type marker_type)
+{ OP(MARKER_TYPE);
+ IX((int)marker_type); st->marker_type = marker_type;
+ END;
+}
+
+cgm_result
+cgm_MARKER_SIZE(cgm_state *st, const cgm_marker_size *marker_size)
+{ OP(MARKER_SIZE);
+ VDC_R(marker_size, st->picture.marker_size_specification_mode);
+ st->marker_size = *marker_size;
+ END;
+}
+
+cgm_result
+cgm_MARKER_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(MARKER_COLOR);
+ CO(color); st->marker_color = *color;
+ END;
+}
+
+cgm_result
+cgm_TEXT_BUNDLE_INDEX(cgm_state *st, cgm_int index)
+{ OP(TEXT_BUNDLE_INDEX);
+ IX(index); st->text_bundle_index = index;
+ END;
+}
+
+cgm_result
+cgm_TEXT_FONT_INDEX(cgm_state *st, cgm_int index)
+{ OP(TEXT_FONT_INDEX);
+ IX(index); st->text_font_index = index;
+ END;
+}
+
+cgm_result
+cgm_TEXT_PRECISION(cgm_state *st, cgm_text_precision precision)
+{ OP(TEXT_PRECISION);
+ E(precision); st->text_precision = precision;
+ END;
+}
+
+cgm_result
+cgm_CHARACTER_EXPANSION_FACTOR(cgm_state *st, cgm_real factor)
+{ OP(CHARACTER_EXPANSION_FACTOR);
+ R(factor); st->character_expansion_factor = factor;
+ END;
+}
+
+cgm_result
+cgm_CHARACTER_SPACING(cgm_state *st, cgm_real spacing)
+{ OP(CHARACTER_SPACING);
+ R(spacing); st->character_spacing = spacing;
+ END;
+}
+
+cgm_result
+cgm_TEXT_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(TEXT_COLOR);
+ CO(color); st->text_color = *color;
+ END;
+}
+
+cgm_result
+cgm_CHARACTER_HEIGHT(cgm_state *st, const cgm_vdc *height)
+{ OP(CHARACTER_HEIGHT);
+ VDC(height); st->character_height = *height;
+ END;
+}
+
+cgm_result
+cgm_CHARACTER_ORIENTATION(cgm_state *st, const cgm_vdc *x_up, const cgm_vdc *y_up, const cgm_vdc *x_base, const cgm_vdc *y_base)
+{ OP(CHARACTER_ORIENTATION);
+ VDC4(x_up, y_up, x_base, y_base);
+ st->character_orientation[0] = *x_up;
+ st->character_orientation[1] = *y_up;
+ st->character_orientation[2] = *x_base;
+ st->character_orientation[3] = *y_base;
+ END;
+}
+
+cgm_result
+cgm_TEXT_PATH(cgm_state *st, cgm_text_path text_path)
+{ OP(TEXT_PATH);
+ E(text_path); st->text_path = text_path;
+ END;
+}
+
+cgm_result
+cgm_TEXT_ALIGNMENT(cgm_state *st, cgm_text_alignment_horizontal align_h, cgm_text_alignment_vertical align_v, cgm_real align_cont_h, cgm_real align_cont_v)
+{ OP(TEXT_ALIGNMENT);
+ E(align_h); E(align_v); R(align_cont_h); R(align_cont_v);
+ END;
+}
+
+cgm_result
+cgm_CHARACTER_SET_INDEX(cgm_state *st, cgm_int index)
+{ OP(CHARACTER_SET_INDEX);
+ IX(index); st->character_set_index = index;
+ END;
+}
+
+/* See gdevcgml.c for why this isn't named cgm_ALTERNATE_.... */
+cgm_result
+cgm_ALT_CHARACTER_SET_INDEX(cgm_state *st, cgm_int index)
+{ OP(ALTERNATE_CHARACTER_SET_INDEX);
+ IX(index); st->alternate_character_set_index = index;
+ END;
+}
+
+cgm_result
+cgm_FILL_BUNDLE_INDEX(cgm_state *st, cgm_int index)
+{ OP(FILL_BUNDLE_INDEX);
+ IX(index); st->fill_bundle_index = index;
+ END;
+}
+
+cgm_result
+cgm_INTERIOR_STYLE(cgm_state *st, cgm_interior_style interior_style)
+{ OP(INTERIOR_STYLE);
+ E(interior_style); st->interior_style = interior_style;
+ END;
+}
+
+cgm_result
+cgm_FILL_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(FILL_COLOR);
+ CO(color); st->fill_color = *color;
+ END;
+}
+
+cgm_result
+cgm_HATCH_INDEX(cgm_state *st, cgm_hatch_index hatch_index)
+{ OP(HATCH_INDEX);
+ IX((int)hatch_index); st->hatch_index = hatch_index;
+ END;
+}
+
+cgm_result
+cgm_PATTERN_INDEX(cgm_state *st, cgm_int index)
+{ OP(PATTERN_INDEX);
+ IX(index); st->pattern_index = index;
+ END;
+}
+
+cgm_result
+cgm_EDGE_BUNDLE_INDEX(cgm_state *st, cgm_int index)
+{ OP(EDGE_BUNDLE_INDEX);
+ IX(index); st->edge_bundle_index = index;
+ END;
+}
+
+cgm_result
+cgm_EDGE_TYPE(cgm_state *st, cgm_edge_type edge_type)
+{ OP(EDGE_TYPE);
+ IX((int)edge_type); st->edge_type = edge_type;
+ END;
+}
+
+cgm_result
+cgm_EDGE_WIDTH(cgm_state *st, const cgm_edge_width *edge_width)
+{ OP(EDGE_WIDTH);
+ VDC_R(edge_width, st->picture.edge_width_specification_mode);
+ st->edge_width = *edge_width;
+ END;
+}
+
+cgm_result
+cgm_EDGE_COLOR(cgm_state *st, const cgm_color *color)
+{ OP(EDGE_COLOR);
+ CO(color);
+ END;
+}
+
+cgm_result
+cgm_EDGE_VISIBILITY(cgm_state *st, bool visibility)
+{ OP(EDGE_VISIBILITY);
+ E(visibility); st->edge_visibility = visibility;
+ END;
+}
+
+cgm_result
+cgm_FILL_REFERENCE_POINT(cgm_state *st, const cgm_point *reference_point)
+{ OP(FILL_REFERENCE_POINT);
+ P(reference_point); st->fill_reference_point = *reference_point;
+ END;
+}
+
+/* PATTERN_TABLE */
+
+cgm_result
+cgm_PATTERN_SIZE(cgm_state *st, const cgm_vdc *x_height, const cgm_vdc *y_height, const cgm_vdc *x_width, const cgm_vdc *y_width)
+{ OP(PATTERN_SIZE);
+ VDC4(x_height, y_height, x_width, y_width);
+ st->pattern_size[0] = *x_height;
+ st->pattern_size[1] = *y_height;
+ st->pattern_size[2] = *x_width;
+ st->pattern_size[3] = *y_width;
+ END;
+}
+
+cgm_result
+cgm_COLOR_TABLE(cgm_state *st, cgm_int index, const cgm_color *values, int count)
+{ int i;
+ OP(COLOR_TABLE);
+ CI(index);
+ for ( i = 0; i < count; ++i )
+ CD(&values[i].rgb);
+ END;
+}
+
+cgm_result cgm_ASPECT_SOURCE_FLAGS(cgm_state *st, const cgm_aspect_source_flag *flags, int count)
+{ int i;
+ OP(ASPECT_SOURCE_FLAGS);
+ for ( i = 0; i < count; ++i )
+ { E(flags[i].type); E(flags[i].source);
+ st->source_flags[flags[i].type] = (byte)flags[i].source;
+ }
+ END;
+}
+
+/* ================ Internal routines ================ */
+
+/* Begin a command. */
+private void
+begin_command(cgm_state *st, cgm_op_index op)
+{ uint op_word = (uint)op << cgm_op_id_shift;
+ st->command[0] = (byte)(op_word >> 8);
+ st->command[1] = (byte)(op_word);
+ st->command_count = 4; /* leave room for extension */
+ st->command_first = true;
+ st->result = cgm_result_ok;
+}
+
+/* Write the buffer for a partial command. */
+/* Note that we always write an even number of bytes. */
+private void
+write_command(cgm_state *st, bool last)
+{ byte *command = st->command;
+ int count = st->command_count;
+ if ( st->command_first )
+ { if ( count <= 34 )
+ { command[2] = command[0];
+ command[3] = command[1] + count - 4;
+ command += 2, count -= 2;
+ }
+ else
+ { int pcount = count - 4;
+ command[1] |= 31;
+ command[2] = (byte)(pcount >> 8);
+ if ( !last ) command[2] |= 0x80;
+ command[3] = (byte)pcount;
+ }
+ st->command_first = false;
+ }
+ else
+ { int pcount = count - 2;
+ command[0] = (byte)(pcount >> 8);
+ if ( !last ) command[0] |= 0x80;
+ command[1] = (byte)pcount;
+ }
+ fwrite(command, sizeof(byte), count + (count & 1), st->file);
+ st->command_count = 2; /* leave room for extension header */
+ if ( ferror(st->file) )
+ st->result = cgm_result_io_error;
+}
+
+/* End a command. */
+private cgm_result
+end_command(cgm_state *st)
+{ write_command(st, true);
+ return st->result;
+}
+
+/* Put an integer value. */
+private void
+put_int(cgm_state *st, cgm_int value, int precision)
+{ switch ( precision )
+ {
+ case 32:
+ put_byte(st, value >> 24);
+ case 24:
+ put_byte(st, value >> 16);
+ case 16:
+ put_byte(st, value >> 8);
+ case 8:
+ put_byte(st, value);
+ }
+}
+
+/* Put a real value. */
+private void
+put_real(cgm_state *st, cgm_real value, const cgm_precision *pr)
+{ if ( pr->representation == cgm_representation_floating )
+ {
+ }
+ else
+ { /* Casting to integer simply discards the fraction, */
+ /* so we need to be careful with negative values. */
+ long whole = (long)value;
+ double fpart;
+ if ( value < whole ) --whole;
+ fpart = value - whole;
+ put_int(st, whole, pr->exponent_or_whole_width);
+ if ( pr->fraction_width == 16 )
+ { uint fraction = (uint)(fpart * (1.0 * 0x10000));
+ put_int(st, fraction, 16);
+ }
+ else /* pr->fraction_width == 32 */
+ { ulong fraction =
+ (ulong)(fpart * (1.0 * 0x10000 * 0x10000));
+ put_int(st, fraction, 32);
+ }
+ }
+}
+
+/* Put a real precision. */
+private void
+put_real_precision(cgm_state *st, const cgm_precision *precision)
+{ I((int)precision->representation);
+ I(precision->exponent_or_whole_width);
+ I(precision->fraction_width);
+}
+
+/* Put a VDC. */
+private void
+put_vdc(cgm_state *st, const cgm_vdc *pvdc)
+{ if ( st->metafile.vdc_type == cgm_vdc_integer )
+ put_int(st, pvdc->integer, st->vdc_integer_precision);
+ else
+ put_real(st, pvdc->real, &st->vdc_real_precision);
+}
+
+/* Put a VDC or a real. */
+private void
+put_vdc_r(cgm_state *st, const cgm_line_marker_extent *extent,
+ cgm_line_marker_specification_mode mode)
+{ if ( mode == cgm_line_marker_absolute )
+ VDC(&extent->absolute);
+ else
+ R(extent->scaled);
+}
+
+/* Put a point (pair of VDCs). */
+private void
+put_point(cgm_state *st, const cgm_point *ppt)
+{ if ( st->metafile.vdc_type == cgm_vdc_integer )
+ { put_int(st, ppt->integer.x, st->vdc_integer_precision);
+ put_int(st, ppt->integer.y, st->vdc_integer_precision);
+ }
+ else
+ { put_real(st, ppt->real.x, &st->vdc_real_precision);
+ put_real(st, ppt->real.y, &st->vdc_real_precision);
+ }
+}
+
+/* Put a list of points. */
+private void
+put_points(cgm_state *st, const cgm_point *ppt, int count)
+{ int i;
+ for ( i = 0; i < count; i++ )
+ P(ppt + i);
+}
+
+/* Put bytes. */
+private void
+put_bytes(cgm_state *st, const byte *data, uint length)
+{ int count;
+ while ( length > (count = command_max_count - st->command_count) )
+ { memcpy(st->command + st->command_count, data, count);
+ st->command_count += count;
+ write_command(st, false);
+ data += count;
+ length -= count;
+ }
+ memcpy(st->command + st->command_count, data, length);
+ st->command_count += length;
+}
+
+/* Put a string. */
+private void
+put_string(cgm_state *st, const char *data, uint length)
+{ /* The CGM specification seems to imply that the continuation */
+ /* mechanism for commands and the mechanism for strings */
+ /* are orthogonal; we take this interpretation. */
+ if ( length >= 255 )
+ { put_byte(st, 255);
+ while ( length > 32767 )
+ { put_int(st, 65535, 2);
+ put_bytes(st, (const byte *)data, 32767);
+ data += 32767;
+ length -= 32767;
+ }
+ }
+ put_byte(st, length);
+ put_bytes(st, (const byte *)data, length);
+}
+
+/* Put a color. */
+private void
+put_color(cgm_state *st, const cgm_color *color)
+{ if ( st->picture.color_selection_mode == cgm_color_selection_indexed )
+ CI(color->index);
+ else
+ CD(&color->rgb);
+}
+
+/* Put an RGB value. */
+private void
+put_rgb(cgm_state *st, const cgm_rgb *rgb)
+{ put_int(st, rgb->r, st->metafile.color_precision);
+ put_int(st, rgb->g, st->metafile.color_precision);
+ put_int(st, rgb->b, st->metafile.color_precision);
+}
diff --git a/gs/src/gdevcgml.h b/gs/src/gdevcgml.h
new file mode 100644
index 000000000..eebe84374
--- /dev/null
+++ b/gs/src/gdevcgml.h
@@ -0,0 +1,403 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcgml.h */
+/* Interface definitions for CGM-writing library */
+
+/* The names in the following follow the CGM standard exactly, */
+/* except that we have substituted the American spellings of */
+/* color (colour) and center (centre). */
+
+/* ================ Types ================ */
+
+/* Define the abstract type for the CGM writer state. */
+typedef struct cgm_state_s cgm_state;
+
+/* Define the type for the allocator used by the CGM writer. */
+typedef struct cgm_allocator_s {
+ void *private_data;
+ void *(*alloc)(P2(void *, uint));
+ void (*free)(P2(void *, void *));
+} cgm_allocator;
+
+/* Define types for CGM coordinates. */
+typedef int cgm_int;
+typedef double cgm_real;
+typedef union cgm_vdc_s {
+ cgm_int integer;
+ cgm_real real;
+} cgm_vdc;
+typedef struct cgm_int_point_s {
+ cgm_int x, y;
+} cgm_int_point;
+typedef struct cgm_real_point_s {
+ cgm_real x, y;
+} cgm_real_point;
+typedef union cgm_point_s {
+ cgm_int_point integer;
+ cgm_real_point real;
+} cgm_point;
+
+/* Define types for colors. */
+typedef struct cgm_rgb_s {
+ cgm_int r, g, b;
+} cgm_rgb;
+typedef union cgm_color_s {
+ cgm_int index;
+ cgm_rgb rgb;
+} cgm_color;
+
+/*
+ * Define other types used in CGM elements or API calls.
+ * If cgm_xxx is an enumerated type, let xxx' be xxx with any of the
+ * following words dropped: mode, specification, type; then the values
+ * of the enumerated type are named cgm_xxx'_yyy.
+ */
+typedef enum {
+ cgm_vdc_integer = 0,
+ cgm_vdc_real
+} cgm_vdc_type;
+typedef struct cgm_string_s {
+ const char *chars;
+ uint length;
+} cgm_string;
+typedef enum {
+ cgm_scaling_abstract = 0,
+ cgm_scaling_metric
+} cgm_scaling_mode;
+typedef enum {
+ cgm_color_selection_indexed = 0,
+ cgm_color_selection_direct
+} cgm_color_selection_mode;
+typedef enum {
+ cgm_line_marker_absolute = 0,
+ cgm_line_marker_scaled
+} cgm_line_marker_specification_mode;
+typedef cgm_line_marker_specification_mode
+ cgm_line_width_specification_mode, cgm_marker_size_specification_mode,
+ cgm_edge_width_specification_mode;
+typedef union cgm_line_marker_extent_s {
+ cgm_vdc absolute;
+ cgm_real scaled;
+} cgm_line_marker_extent;
+typedef cgm_line_marker_extent
+ cgm_line_width, cgm_marker_size, cgm_edge_width;
+typedef enum {
+ cgm_transparency_off = 0,
+ cgm_transparency_on
+} cgm_transparency;
+typedef enum {
+ cgm_clip_off = 0,
+ cgm_clip_on
+} cgm_clip_indicator;
+typedef struct cgm_precision_s {
+ enum { cgm_representation_floating, cgm_representation_fixed } representation;
+ int exponent_or_whole_width;
+ int fraction_width;
+} cgm_precision;
+typedef enum {
+ cgm_line_solid = 1,
+ cgm_line_dash,
+ cgm_line_dot,
+ cgm_line_dash_dot,
+ cgm_line_dash_dot_dot
+} cgm_line_type;
+typedef enum {
+ cgm_marker_dot = 1,
+ cgm_marker_plus,
+ cgm_marker_asterisk,
+ cgm_marker_circle,
+ cgm_marker_cross
+} cgm_marker_type;
+typedef enum {
+ cgm_text_precision_string = 0,
+ cgm_text_precision_character,
+ cgm_text_precision_stroke
+} cgm_text_precision;
+typedef enum {
+ cgm_text_path_right = 0,
+ cgm_text_path_left,
+ cgm_text_path_up,
+ cgm_text_path_down
+} cgm_text_path;
+typedef enum {
+ cgm_text_horizontal_normal = 0,
+ cgm_text_horizontal_left,
+ cgm_text_horizontal_center,
+ cgm_text_horizontal_right,
+ cgm_text_horizontal_continuous
+} cgm_text_alignment_horizontal;
+typedef enum {
+ cgm_text_vertical_normal = 0,
+ cgm_text_vertical_top,
+ cgm_text_vertical_cap,
+ cgm_text_vertical_half,
+ cgm_text_vertical_base,
+ cgm_text_vertical_bottom,
+ cgm_text_vertical_continuous
+} cgm_text_alignment_vertical;
+typedef enum {
+ cgm_interior_style_hollow = 0,
+ cgm_interior_style_solid,
+ cgm_interior_style_pattern,
+ cgm_interior_style_hatch,
+ cgm_interior_style_empty
+} cgm_interior_style;
+typedef enum {
+ cgm_hatch_horizontal = 1,
+ cgm_hatch_vertical,
+ cgm_hatch_positive_slope,
+ cgm_hatch_negative_slope,
+ cgm_hatch_combined_v_h_slant,
+ cgm_hatch_combined_l_r_slant
+} cgm_hatch_index;
+typedef enum {
+ cgm_arc_closure_pie = 0,
+ cgm_arc_closure_chord
+} cgm_arc_closure;
+typedef enum {
+ cgm_edge_out_invisible = 0,
+ cgm_edge_out_visible,
+ cgm_edge_out_close_invisible,
+ cgm_edge_out_close_visible
+} cgm_edge_out;
+typedef struct cgm_polygon_edge_s {
+ cgm_point vertex;
+ cgm_edge_out edge_out;
+} cgm_polygon_edge;
+typedef enum {
+ cgm_cell_mode_run_length = 0,
+ cgm_cell_mode_packed
+} cgm_cell_representation_mode;
+typedef enum {
+ cgm_edge_solid = 1,
+ cgm_edge_dash,
+ cgm_edge_dot,
+ cgm_edge_dash_dot,
+ cgm_edge_dash_dot_dot
+} cgm_edge_type;
+typedef enum {
+ cgm_aspect_source_individual = 0,
+ cgm_aspect_source_bundled
+} cgm_aspect_source;
+typedef enum {
+ cgm_aspect_line_type = 0,
+ cgm_aspect_line_width,
+ cgm_aspect_line_color,
+ cgm_aspect_marker_type,
+ cgm_aspect_marker_size,
+ cgm_aspect_marker_color,
+ cgm_aspect_text_font_index,
+ cgm_aspect_text_precision,
+ cgm_aspect_character_expansion_factor,
+ cgm_aspect_character_spacing,
+ cgm_aspect_text_color,
+ cgm_aspect_interior_style,
+ cgm_aspect_fill_color,
+ cgm_aspect_hatch_index,
+ cgm_aspect_pattern_index,
+ cgm_aspect_edge_type,
+ cgm_aspect_edge_width,
+ cgm_aspect_edge_color
+} cgm_aspect_type;
+typedef struct cgm_aspect_source_flag_s {
+ cgm_aspect_type type;
+ cgm_aspect_source source;
+} cgm_aspect_source_flag;
+
+/* ================ API ================ */
+
+typedef enum {
+ cgm_result_ok = 0,
+ cgm_result_wrong_state = -1,
+ cgm_result_out_of_range = -2,
+ cgm_result_io_error = -3,
+ cgm_result_out_of_memory = -4
+} cgm_result;
+
+/* ---------------- Initialize/terminate ---------------- */
+
+cgm_state *cgm_initialize(P2(FILE *, const cgm_allocator *));
+cgm_result cgm_terminate(P1(cgm_state *));
+
+/* ---------------- Metafile elements ---------------- */
+
+typedef struct cgm_metafile_elements_s {
+ cgm_int metafile_version;
+ cgm_string metafile_description;
+ cgm_vdc_type vdc_type;
+ int integer_precision;
+ cgm_precision real_precision;
+ int index_precision;
+ int color_precision;
+ int color_index_precision;
+ cgm_int maximum_color_index;
+ cgm_color color_value_extent[2];
+ const int *metafile_element_list;
+ int metafile_element_list_count;
+ const cgm_string *font_list;
+ int font_list_count;
+ /* character_set_list */
+ /* character_coding_announcer */
+} cgm_metafile_elements;
+#define cgm_set_METAFILE_VERSION (1L<<0)
+#define cgm_set_METAFILE_DESCRIPTION (1L<<1)
+#define cgm_set_VDC_TYPE (1L<<2)
+#define cgm_set_INTEGER_PRECISION (1L<<3)
+#define cgm_set_REAL_PRECISION (1L<<4)
+#define cgm_set_INDEX_PRECISION (1L<<5)
+#define cgm_set_COLOR_PRECISION (1L<<6)
+#define cgm_set_COLOR_INDEX_PRECISION (1L<<7)
+#define cgm_set_MAXIMUM_COLOR_INDEX (1L<<8)
+#define cgm_set_COLOR_VALUE_EXTENT (1L<<9)
+#define cgm_set_METAFILE_ELEMENT_LIST (1L<<10)
+#define cgm_set_FONT_LIST (1L<<11)
+#define cgm_set_CHARACTER_SET_LIST (1L<<12)
+#define cgm_set_CHARACTER_CODING_ANNOUNCER (1L<<13)
+
+cgm_result
+ cgm_BEGIN_METAFILE(P3(cgm_state *, const char *, uint)),
+ cgm_set_metafile_elements(P3(cgm_state *,
+ const cgm_metafile_elements *, long)),
+ cgm_END_METAFILE(P1(cgm_state *));
+
+/* ---------------- Picture elements ---------------- */
+
+typedef struct cgm_picture_elements_s {
+ cgm_scaling_mode scaling_mode;
+ cgm_real scale_factor;
+ cgm_color_selection_mode color_selection_mode;
+ cgm_line_width_specification_mode line_width_specification_mode;
+ cgm_marker_size_specification_mode marker_size_specification_mode;
+ cgm_edge_width_specification_mode edge_width_specification_mode;
+ cgm_point vdc_extent[2];
+ cgm_color background_color;
+} cgm_picture_elements;
+#define cgm_set_SCALING_MODE (1L<<0)
+#define cgm_set_COLOR_SELECTION_MODE (1L<<1)
+#define cgm_set_LINE_WIDTH_SPECIFICATION_MODE (1L<<2)
+#define cgm_set_MARKER_SIZE_SPECIFICATION_MODE (1L<<3)
+#define cgm_set_EDGE_WIDTH_SPECIFICATION_MODE (1L<<4)
+#define cgm_set_VDC_EXTENT (1L<<5)
+#define cgm_set_BACKGROUND_COLOR (1L<<6)
+
+cgm_result
+ cgm_BEGIN_PICTURE(P3(cgm_state *, const char *, uint)),
+ cgm_set_picture_elements(P3(cgm_state *,
+ const cgm_picture_elements *, long)),
+ cgm_BEGIN_PICTURE_BODY(P1(cgm_state *)),
+ cgm_END_PICTURE(P1(cgm_state *));
+
+/* ---------------- Control elements ---------------- */
+
+cgm_result
+ cgm_VDC_INTEGER_PRECISION(P2(cgm_state *, int)),
+ cgm_VDC_REAL_PRECISION(P2(cgm_state *, const cgm_precision *)),
+ cgm_AUXILIARY_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_TRANSPARENCY(P2(cgm_state *, cgm_transparency)),
+ cgm_CLIP_RECTANGLE(P2(cgm_state *, const cgm_point [2])),
+ cgm_CLIP_INDICATOR(P2(cgm_state *, cgm_clip_indicator));
+
+/* ---------------- Graphical primitive elements ---------------- */
+
+cgm_result
+ cgm_POLYLINE(P3(cgm_state *, const cgm_point *, int)),
+ cgm_DISJOINT_POLYLINE(P3(cgm_state *, const cgm_point *, int)),
+ cgm_POLYMARKER(P3(cgm_state *, const cgm_point *, int)),
+ cgm_TEXT(P5(cgm_state *, const cgm_point *, bool, const char *, uint)),
+ cgm_RESTRICTED_TEXT(P7(cgm_state *, const cgm_vdc *, const cgm_vdc *,
+ const cgm_point *, bool, const char *, uint)),
+ cgm_APPEND_TEXT(P4(cgm_state *, bool, const char *, uint)),
+ cgm_POLYGON(P3(cgm_state *, const cgm_point *, int)),
+ cgm_POLYGON_SET(P3(cgm_state *, const cgm_polygon_edge *, int)),
+ cgm_CELL_ARRAY(P9(cgm_state *, const cgm_point * /*[3]*/, cgm_int,
+ cgm_int, cgm_int, cgm_cell_representation_mode,
+ const byte *, uint, uint)),
+ cgm_RECTANGLE(P3(cgm_state *, const cgm_point *, const cgm_point *)),
+ cgm_CIRCLE(P3(cgm_state *, const cgm_point *, const cgm_vdc *)),
+ cgm_CIRCULAR_ARC_3_POINT(P4(cgm_state *, const cgm_point *,
+ const cgm_point *, const cgm_point *)),
+ cgm_CIRCULAR_ARC_3_POINT_CLOSE(P5(cgm_state *, const cgm_point *,
+ const cgm_point *,
+ const cgm_point *, cgm_arc_closure)),
+ cgm_CIRCULAR_ARC_CENTER(P7(cgm_state *, const cgm_point *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *)),
+ cgm_CIRCULAR_ARC_CENTER_CLOSE(P8(cgm_state *, const cgm_point *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, cgm_arc_closure)),
+ cgm_ELLIPSE(P4(cgm_state *, const cgm_point *, const cgm_point *,
+ const cgm_point *)),
+ cgm_ELLIPTICAL_ARC(P8(cgm_state *, const cgm_point *,
+ const cgm_point *, const cgm_point *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *)),
+ cgm_ELLIPTICAL_ARC_CLOSE(P9(cgm_state *, const cgm_point *,
+ const cgm_point *, const cgm_point *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *,
+ cgm_arc_closure));
+
+/* ---------------- Attribute elements ---------------- */
+
+cgm_result
+ cgm_LINE_BUNDLE_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_LINE_TYPE(P2(cgm_state *, cgm_line_type)),
+ cgm_LINE_WIDTH(P2(cgm_state *, const cgm_line_width *)),
+ cgm_LINE_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_MARKER_BUNDLE_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_MARKER_TYPE(P2(cgm_state *, cgm_marker_type)),
+ cgm_MARKER_SIZE(P2(cgm_state *, const cgm_marker_size *)),
+ cgm_MARKER_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_TEXT_BUNDLE_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_TEXT_FONT_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_TEXT_PRECISION(P2(cgm_state *, cgm_text_precision)),
+ cgm_CHARACTER_EXPANSION_FACTOR(P2(cgm_state *, cgm_real)),
+ cgm_CHARACTER_SPACING(P2(cgm_state *, cgm_real)),
+ cgm_TEXT_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_CHARACTER_HEIGHT(P2(cgm_state *, const cgm_vdc *)),
+ cgm_CHARACTER_ORIENTATION(P5(cgm_state *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *)),
+ cgm_TEXT_PATH(P2(cgm_state *, cgm_text_path)),
+ cgm_TEXT_ALIGNMENT(P5(cgm_state *, cgm_text_alignment_horizontal,
+ cgm_text_alignment_vertical,
+ cgm_real, cgm_real)),
+ cgm_CHARACTER_SET_INDEX(P2(cgm_state *, cgm_int)),
+ /* The following should be cgm_ALTERNATE_..., but the VAX DEC C */
+ /* compiler gives an error for names longer than 31 characters. */
+ cgm_ALT_CHARACTER_SET_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_FILL_BUNDLE_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_INTERIOR_STYLE(P2(cgm_state *, cgm_interior_style)),
+ cgm_FILL_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_HATCH_INDEX(P2(cgm_state *, cgm_hatch_index)),
+ cgm_PATTERN_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_EDGE_BUNDLE_INDEX(P2(cgm_state *, cgm_int)),
+ cgm_EDGE_TYPE(P2(cgm_state *, cgm_edge_type)),
+ cgm_EDGE_WIDTH(P2(cgm_state *, const cgm_edge_width *)),
+ cgm_EDGE_COLOR(P2(cgm_state *, const cgm_color *)),
+ cgm_EDGE_VISIBILITY(P2(cgm_state *, bool)),
+ cgm_FILL_REFERENCE_POINT(P2(cgm_state *, const cgm_point *)),
+/* PATTERN_TABLE */
+ cgm_PATTERN_SIZE(P5(cgm_state *, const cgm_vdc *, const cgm_vdc *,
+ const cgm_vdc *, const cgm_vdc *)),
+ cgm_COLOR_TABLE(P4(cgm_state *, cgm_int, const cgm_color *, int)),
+ cgm_ASPECT_SOURCE_FLAGS(P3(cgm_state *,
+ const cgm_aspect_source_flag *, int));
diff --git a/gs/src/gdevcgmx.h b/gs/src/gdevcgmx.h
new file mode 100644
index 000000000..d9d6e7fbb
--- /dev/null
+++ b/gs/src/gdevcgmx.h
@@ -0,0 +1,182 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcgmx.h */
+/* Internal definitions for CGM-writing library */
+#include "gdevcgml.h"
+
+/* Define the internal representations of the CGM opcodes. */
+#define cgm_op_class_shift 7
+#define cgm_op_id_shift 5
+typedef enum {
+ /* Class 0 */
+ BEGIN_METAFILE = (0 << cgm_op_class_shift) + 1,
+ END_METAFILE,
+ BEGIN_PICTURE,
+ BEGIN_PICTURE_BODY,
+ END_PICTURE,
+ /* Class 1 */
+ METAFILE_VERSION = (1 << cgm_op_class_shift) + 1,
+ METAFILE_DESCRIPTION,
+ VDC_TYPE,
+ INTEGER_PRECISION,
+ REAL_PRECISION,
+ INDEX_PRECISION,
+ COLOR_PRECISION,
+ COLOR_INDEX_PRECISION,
+ MAXIMUM_COLOR_INDEX,
+ COLOR_VALUE_EXTENT,
+ METAFILE_ELEMENT_LIST,
+ METAFILE_DEFAULTS_REPLACEMENT,
+ FONT_LIST,
+ CHARACTER_SET_LIST,
+ CHARACTER_CODING_ANNOUNCER,
+ /* Class 2 */
+ SCALING_MODE = (2 << cgm_op_class_shift) + 1,
+ COLOR_SELECTION_MODE,
+ LINE_WIDTH_SPECIFICATION_MODE,
+ MARKER_SIZE_SPECIFICATION_MODE,
+ EDGE_WIDTH_SPECIFICATION_MODE,
+ VDC_EXTENT,
+ BACKGROUND_COLOR,
+ /* Class 3 */
+ VDC_INTEGER_PRECISION = (3 << cgm_op_class_shift) + 1,
+ VDC_REAL_PRECISION,
+ AUXILIARY_COLOR,
+ TRANSPARENCY,
+ CLIP_RECTANGLE,
+ CLIP_INDICATOR,
+ /* Class 4 */
+ POLYLINE = (4 << cgm_op_class_shift) + 1,
+ DISJOINT_POLYLINE,
+ POLYMARKER,
+ TEXT,
+ RESTRICTED_TEXT,
+ APPEND_TEXT,
+ POLYGON,
+ POLYGON_SET,
+ CELL_ARRAY,
+ GENERALIZED_DRAWING_PRIMITIVE,
+ RECTANGLE,
+ CIRCLE,
+ CIRCULAR_ARC_3_POINT,
+ CIRCULAR_ARC_3_POINT_CLOSE,
+ CIRCULAR_ARC_CENTER,
+ CIRCULAR_ARC_CENTER_CLOSE,
+ ELLIPSE,
+ ELLIPTICAL_ARC,
+ ELLIPTICAL_ARC_CLOSE,
+ /* Class 5 */
+ LINE_BUNDLE_INDEX = (5 << cgm_op_class_shift) + 1,
+ LINE_TYPE,
+ LINE_WIDTH,
+ LINE_COLOR,
+ MARKER_BUNDLE_INDEX,
+ MARKER_TYPE,
+ MARKER_SIZE,
+ MARKER_COLOR,
+ TEXT_BUNDLE_INDEX,
+ TEXT_FONT_INDEX,
+ TEXT_PRECISION,
+ CHARACTER_EXPANSION_FACTOR,
+ CHARACTER_SPACING,
+ TEXT_COLOR,
+ CHARACTER_HEIGHT,
+ CHARACTER_ORIENTATION,
+ TEXT_PATH,
+ TEXT_ALIGNMENT,
+ CHARACTER_SET_INDEX,
+ ALTERNATE_CHARACTER_SET_INDEX,
+ FILL_BUNDLE_INDEX,
+ INTERIOR_STYLE,
+ FILL_COLOR,
+ HATCH_INDEX,
+ PATTERN_INDEX,
+ EDGE_BUNDLE_INDEX,
+ EDGE_TYPE,
+ EDGE_WIDTH,
+ EDGE_COLOR,
+ EDGE_VISIBILITY,
+ FILL_REFERENCE_POINT,
+ PATTERN_TABLE,
+ PATTERN_SIZE,
+ COLOR_TABLE,
+ ASPECT_SOURCE_FLAGS,
+ /* Class 6 */
+ ESCAPE = (6 << cgm_op_class_shift) + 1,
+ /* Class 7 */
+ MESSAGE = (7 << cgm_op_class_shift) + 1,
+ APPLICATION_DATA
+} cgm_op_index;
+
+/* Define the state of the CGM writer. */
+/*typedef struct cgm_state_s cgm_state;*/ /* in gdevcgml.h */
+struct cgm_state_s {
+ /* The following are set at initialization time. */
+ FILE *file;
+ cgm_allocator allocator;
+ /* The following are set by specific calls. */
+ cgm_metafile_elements metafile;
+ cgm_picture_elements picture;
+ int vdc_integer_precision;
+ cgm_precision vdc_real_precision;
+ cgm_color auxiliary_color;
+ cgm_transparency transparency;
+ cgm_point clip_rectangle[2];
+ cgm_clip_indicator clip_indicator;
+ int line_bundle_index;
+ cgm_line_type line_type;
+ cgm_line_width line_width;
+ cgm_color line_color;
+ int marker_bundle_index;
+ cgm_marker_type marker_type;
+ cgm_marker_size marker_size;
+ cgm_color marker_color;
+ int text_bundle_index;
+ int text_font_index;
+ cgm_text_precision text_precision;
+ cgm_real character_expansion_factor;
+ cgm_real character_spacing;
+ cgm_color text_color;
+ cgm_vdc character_height;
+ cgm_vdc character_orientation[4];
+ cgm_text_path text_path;
+ /****** text_alignment ******/
+ int character_set_index;
+ int alternate_character_set_index;
+ int fill_bundle_index;
+ cgm_interior_style interior_style;
+ cgm_color fill_color;
+ cgm_hatch_index hatch_index;
+ int pattern_index;
+ int edge_bundle_index;
+ cgm_edge_type edge_type;
+ cgm_edge_width edge_width;
+ bool edge_visibility;
+ cgm_point fill_reference_point;
+ /****** pattern_table ******/
+ cgm_vdc pattern_size[4];
+ /****** color_table ******/
+ byte /*cgm_aspect_source*/ source_flags[18];
+ /* The following change dynamically. */
+#define command_max_count 400 /* (must be even) */
+ byte command[command_max_count];
+ int command_count;
+ bool command_first;
+ cgm_result result;
+};
diff --git a/gs/src/gdevcif.c b/gs/src/gdevcif.c
new file mode 100644
index 000000000..c8240b44d
--- /dev/null
+++ b/gs/src/gdevcif.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcif.c */
+/* The `Fake bitmapped device to estimate rendering time'
+ slightly modified to produce CIF files from PostScript.
+ So anyone can put a nice logo free on its chip!
+ Frederic Petrot, petrot@masi.ibp.fr */
+
+#include "gdevprn.h"
+
+/* Define the device parameters. */
+#ifndef X_DPI
+# define X_DPI 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+/* The device descriptor */
+private dev_proc_print_page(cif_print_page);
+gx_device_printer far_data gs_cif_device =
+ prn_device(prn_std_procs, "cif",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0,
+ 1, cif_print_page);
+
+/* Send the page to the output. */
+private int
+cif_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int lnum;
+ byte *in = (byte *)gs_malloc(line_size, 1, "cif_print_page(in)");
+ char *s;
+ int scanline, scanbyte;
+ int length, start; /* length is the number of successive 1 bits, */
+ /* start is the set of 1 bit start position */
+
+ if (in == 0)
+ return_error(gs_error_VMerror);
+
+ if ((s = strchr(pdev->fname, '.')) == NULL)
+ length = strlen(pdev->fname) + 1;
+ else
+ length = s - pdev->fname;
+ s = (char *)gs_malloc(length, sizeof(char), "cif_print_page(s)");
+
+ strncpy(s, pdev->fname, length);
+ *(s + length) = '\0';
+ fprintf(prn_stream, "DS1 25 1;\n9 %s;\nLCP;\n", s);
+ gs_free(s, length, 1, "cif_print_page(s)");
+
+ for (lnum = 0; lnum < pdev->height; lnum++) {
+ gdev_prn_copy_scan_lines(pdev, lnum, in, line_size);
+ length = 0;
+ for (scanline = 0; scanline < line_size; scanline++)
+#ifdef TILE /* original, simple, inefficient algorithm */
+ for (scanbyte = 0; scanbyte < 8; scanbyte++)
+ if (((in[scanline] >> scanbyte) & 1) != 0)
+ fprintf(prn_stream, "B4 4 %d %d;\n",
+ (scanline * 8 + (7 - scanbyte)) * 4,
+ (pdev->height - lnum) * 4);
+#else /* better algorithm */
+ for (scanbyte = 7; scanbyte >= 0; scanbyte--)
+ /* cheap linear reduction of rectangles in lines */
+ if (((in[scanline] >> scanbyte) & 1) != 0) {
+ if (length == 0)
+ start = (scanline * 8 + (7 - scanbyte));
+ length++;
+ } else {
+ if (length != 0)
+ fprintf(prn_stream, "B%d 4 %d %d;\n", length * 4,
+ start * 4 + length * 2,
+ (pdev->height - lnum) * 4);
+ length = 0;
+ }
+#endif
+ }
+ fprintf(prn_stream, "DF;\nC1;\nE\n");
+ gs_free(in, line_size, 1, "cif_print_page(in)");
+ return 0;
+}
diff --git a/gs/src/gdevcp50.c b/gs/src/gdevcp50.c
new file mode 100644
index 000000000..538f4211e
--- /dev/null
+++ b/gs/src/gdevcp50.c
@@ -0,0 +1,223 @@
+/* Copyright (C) 1991, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevcp50.c */
+/* Mitsubishi CP50 color printer driver */
+#include "gdevprn.h"
+#define ppdev ((gx_device_printer *)pdev)
+
+/***
+ *** Note: this driver was contributed by a user. Please contact
+ *** Michael Hu (michael@ximage.com) if you have questions.
+ ***/
+
+/* The value of X_PIXEL and Y_PIXEL is gained by experiment */
+#define X_PIXEL 474
+#define Y_PIXEL 800
+
+/* The value of FIRST_LINE and LAST_LINE is gained by experiment */
+/* Note: LAST-LINE - FIRST_LINE + 1 should close to Y_PIXEL */
+#define FIRST_LINE 140
+#define LAST_LINE 933
+
+/* The value of FIRST is gained by experiment */
+/* There are 60 pixel(RGB) in the right clipped margin */
+#define FIRST_COLUMN 180
+
+/* The value of X_DPI and Y_DPI is gained by experiment */
+#define X_DPI 154 /* pixels per inch */
+#define Y_DPI 187 /* pixels per inch */
+
+/* The device descriptor */
+private dev_proc_print_page(cp50_print_page);
+private dev_proc_output_page(cp50_output_page);
+
+private dev_proc_map_rgb_color(cp50_rgb_color);
+private dev_proc_map_color_rgb(cp50_color_rgb);
+
+private gx_device_procs cp50_procs =
+ prn_color_procs(gdev_prn_open, cp50_output_page, gdev_prn_close,
+ cp50_rgb_color, cp50_color_rgb);
+
+gx_device_printer far_data gs_cp50_device =
+ prn_device(cp50_procs, "cp50",
+ 39, /* width_10ths, 100mm */
+ 59, /* height_10ths,150mm */
+ X_DPI, Y_DPI,
+ 0.39, 0.91, 0.43, 0.75, /* margins */
+ 24, cp50_print_page);
+
+int copies;
+
+/* ------ Internal routines ------ */
+
+
+/* Send the page to the printer. */
+private int
+cp50_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte *out = (byte *)gs_malloc(line_size, 1, "cp50_print_page(out)");
+ byte *r_plane = (byte *)gs_malloc(X_PIXEL*Y_PIXEL, 1, "cp50_print_page(r_plane)");
+ byte *g_plane = (byte *)gs_malloc(X_PIXEL*Y_PIXEL, 1, "cp50_print_page(g_plane)");
+ byte *b_plane = (byte *)gs_malloc(X_PIXEL*Y_PIXEL, 1, "cp50_print_page(b_plane)");
+ byte *t_plane = (byte *)gs_malloc(X_PIXEL*Y_PIXEL, 1, "cp50_print_page(t_plane)");
+ int lnum = FIRST_LINE;
+ int last = LAST_LINE;
+ int lines = X_PIXEL;
+ byte hi_lines, lo_lines;
+ byte num_copies;
+ int i,j;
+
+
+/*fprintf(prn_stream, "%d,%d,%d,", pdev->width, pdev->height, line_size);*/
+
+ /* Check allocations */
+ if ( out == 0 || r_plane == 0 || g_plane == 0 || b_plane == 0 ||
+ t_plane == 0)
+ { if ( out )
+ gs_free((char *)out, line_size, 1,
+ "cp50_print_page(out)");
+ if (r_plane)
+ gs_free((char *)r_plane, X_PIXEL*Y_PIXEL, 1,
+ "cp50_print_page(r_plane)");
+ if (g_plane)
+ gs_free((char *)g_plane, X_PIXEL*Y_PIXEL, 1,
+ "cp50_print_page(g_plane)");
+ if (b_plane)
+ gs_free((char *)b_plane, X_PIXEL*Y_PIXEL, 1,
+ "cp50_print_page(b_plane)");
+ if (t_plane)
+ gs_free((char *)t_plane, X_PIXEL*Y_PIXEL, 1,
+ "cp50_print_page(t_plane)");
+ return -1;
+ }
+
+ /* set each plane as white */
+ memset(r_plane, -1, X_PIXEL*Y_PIXEL);
+ memset(g_plane, -1, X_PIXEL*Y_PIXEL);
+ memset(b_plane, -1, X_PIXEL*Y_PIXEL);
+ memset(t_plane, -1, X_PIXEL*Y_PIXEL);
+
+ /* Initialize the printer */ /* see programmer manual for CP50 */
+ fprintf(prn_stream,"\033\101");
+ fprintf(prn_stream,"\033\106\010\001");
+ fprintf(prn_stream,"\033\106\010\003");
+
+ /* set number of copies */
+ fprintf(prn_stream,"\033\116");
+ num_copies = copies & 0xFF;
+ fwrite(&num_copies, sizeof(char), 1, prn_stream);
+
+ /* download image */
+ hi_lines = lines >> 8;
+ lo_lines = lines & 0xFF;
+
+ fprintf(prn_stream,"\033\123\062");
+ fwrite(&hi_lines, sizeof(char), 1, prn_stream);
+ fwrite(&lo_lines, sizeof(char), 1, prn_stream);
+ fprintf(prn_stream,"\001"); /* dummy */
+
+ /* Print lines of graphics */
+ while ( lnum <= last )
+ {
+ int i, col;
+ gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+ /*fwrite(out, sizeof(char), line_size, prn_stream);*/
+ for(i=0; i<X_PIXEL; i++)
+ {
+ col = (lnum-FIRST_LINE) * X_PIXEL + i;
+ r_plane[col] = out[i*3+FIRST_COLUMN];
+ g_plane[col] = out[i*3+1+FIRST_COLUMN];
+ b_plane[col] = out[i*3+2+FIRST_COLUMN];
+ }
+ lnum ++;
+ }
+
+ /* rotate each plane and download it */
+ for(i=0;i<X_PIXEL;i++)
+ for(j=Y_PIXEL-1;j>=0;j--)
+ t_plane[(Y_PIXEL-1-j)+i*Y_PIXEL] = r_plane[i+j*X_PIXEL];
+ fwrite(t_plane, sizeof(char), X_PIXEL*Y_PIXEL, prn_stream);
+
+ for(i=0;i<X_PIXEL;i++)
+ for(j=Y_PIXEL-1;j>=0;j--)
+ t_plane[(Y_PIXEL-1-j)+i*Y_PIXEL] = g_plane[i+j*X_PIXEL];
+ fwrite(t_plane, sizeof(char), X_PIXEL*Y_PIXEL, prn_stream);
+
+ for(i=0;i<X_PIXEL;i++)
+ for(j=Y_PIXEL-1;j>=0;j--)
+ t_plane[(Y_PIXEL-1-j)+i*Y_PIXEL] = b_plane[i+j*X_PIXEL];
+ fwrite(t_plane, sizeof(char), X_PIXEL*Y_PIXEL, prn_stream);
+
+
+ gs_free((char *)out, line_size, 1, "cp50_print_page(out)");
+ gs_free((char *)r_plane, X_PIXEL*Y_PIXEL, 1, "cp50_print_page(r_plane)");
+ gs_free((char *)g_plane, X_PIXEL*Y_PIXEL, 1, "cp50_print_page(g_plane)");
+ gs_free((char *)b_plane, X_PIXEL*Y_PIXEL, 1, "cp50_print_page(b_plane)");
+ gs_free((char *)t_plane, X_PIXEL*Y_PIXEL, 1, "cp50_print_page(t_plane)");
+
+ return 0;
+}
+
+int private
+cp50_output_page(gx_device *pdev, int num_copies, int flush)
+{ int code, outcode, closecode;
+
+ code = gdev_prn_open_printer(pdev, 1);
+ if ( code < 0 ) return code;
+
+ copies = num_copies; /* using global variable to pass */
+
+ /* Print the accumulated page description. */
+ outcode = (*ppdev->printer_procs.print_page)(ppdev, ppdev->file);
+ if ( code < 0 ) return code;
+
+ closecode = gdev_prn_close_printer(pdev);
+ if ( code < 0 ) return code;
+
+ if ( ppdev->buffer_space ) /* reinitialize clist for writing */
+ code = (*gs_clist_device_procs.output_page)(pdev, num_copies, flush);
+
+ if ( outcode < 0 ) return outcode;
+ if ( closecode < 0 ) return closecode;
+ return code;
+}
+
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that Windows expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+cp50_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return ((ulong)gx_color_value_to_byte(r) << 16)+
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ gx_color_value_to_byte(b);
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+cp50_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ prgb[2] = gx_color_value_from_byte(color & 0xff);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color >> 16);
+ return 0;
+}
diff --git a/gs/src/gdevddrw.c b/gs/src/gdevddrw.c
new file mode 100644
index 000000000..4368e5e28
--- /dev/null
+++ b/gs/src/gdevddrw.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevddrw.c */
+/* Default polygon and image drawing device procedures */
+#include "math_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+
+/* ---------------- Polygon and line drawing ---------------- */
+
+/* Define the 'remainder' analogue of fixed_mult_quo. */
+private fixed
+fixed_mult_rem(fixed a, fixed b, fixed c)
+{ double prod = (double)a * b;
+ return (fixed)(prod - floor(prod / c) * c);
+}
+
+/*
+ * Fill a trapezoid. Requires:
+ * {left,right}->start.y <= ybot <= ytop <= {left,right}->end.y.
+ * Lines where left.x >= right.x will not be drawn. Thanks to Paul Haeberli
+ * for an early floating point version of this algorithm.
+ */
+typedef struct trap_line_s {
+ int di; fixed df; /* dx/dy ratio = di + df/h */
+ fixed ldi, ldf; /* increment per scan line = ldi + ldf/h */
+ fixed x, xf; /* current value */
+ fixed h;
+} trap_line;
+int
+gx_default_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left,
+ const gs_fixed_edge *right, fixed ybot, fixed ytop, bool swap_axes,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ const fixed ymin = fixed_pixround(ybot) + fixed_half;
+ const fixed ymax = fixed_pixround(ytop);
+ if ( ymin >= ymax ) return 0; /* no scan lines to sample */
+ { int iy = fixed2int_var(ymin);
+ const int iy1 = fixed2int_var(ymax);
+ trap_line l, r;
+ int rxl, rxr, ry;
+ const fixed
+ x0l = left->start.x, x1l = left->end.x,
+ x0r = right->start.x, x1r = right->end.x,
+ dxl = x1l - x0l, dxr = x1r - x0r;
+ const fixed /* partial pixel offset to first line to sample */
+ ysl = ymin - left->start.y,
+ ysr = ymin - right->start.y;
+ fixed fxl;
+ bool fill_direct = color_writes_pure(pdevc, lop);
+ gx_color_index cindex;
+ dev_proc_fill_rectangle((*fill_rect));
+ int max_rect_height = 1; /* max height to do fill as rectangle */
+ int code;
+
+ if_debug2('z', "[z]y=[%d,%d]\n", iy, iy1);
+
+ if ( fill_direct )
+ cindex = pdevc->colors.pure,
+ fill_rect = dev_proc(dev, fill_rectangle);
+ l.h = left->end.y - left->start.y;
+ r.h = right->end.y - right->start.y;
+ l.x = x0l + (fixed_half - fixed_epsilon);
+ r.x = x0r + (fixed_half - fixed_epsilon);
+ ry = iy;
+
+#define fill_trap_rect(x,y,w,h)\
+ (fill_direct ?\
+ (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\
+ (*fill_rect)(dev, x, y, w, h, cindex)) :\
+ swap_axes ? gx_fill_rectangle_device_rop(y, x, h, w, pdevc, dev, lop) :\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop))
+
+ /* Compute the dx/dy ratios. */
+ /* dx# = dx#i + (dx#f / h#). */
+#define compute_dx(tl, d, ys)\
+ if ( d >= 0 )\
+ { if ( d < tl.h ) tl.di = 0, tl.df = d;\
+ else tl.di = (int)(d / tl.h), tl.df = d - tl.di * tl.h,\
+ tl.x += ys * tl.di;\
+ }\
+ else\
+ { if ( (tl.df = d + tl.h) >= 0 /* d >= -tl.h */ ) tl.di = -1, tl.x -= ys;\
+ else tl.di = (int)-((tl.h - 1 - d) / tl.h), tl.df = d - tl.di * tl.h,\
+ tl.x += ys * tl.di;\
+ }
+
+ /* Compute the x offsets at the first scan line to sample. */
+ /* We need to be careful in computing ys# * dx#f {/,%} h# */
+ /* because the multiplication may overflow. We know that */
+ /* all the quantities involved are non-negative, and that */
+ /* ys# is usually than 1 (as a fixed, of course); this gives us */
+ /* a cheap conservative check for overflow in the multiplication. */
+#define ymult_limit (max_fixed / fixed_1)
+#define ymult_quo(ys, tl)\
+ (ys < fixed_1 && tl.df < ymult_limit ? ys * tl.df / tl.h :\
+ fixed_mult_quo(ys, tl.df, tl.h))
+
+ /*
+ * It's worth checking for dxl == dxr, since this is the case
+ * for parallelograms (including stroked lines).
+ * Also check for left or right vertical edges.
+ */
+ if ( fixed_floor(l.x) == fixed_pixround(x1l) )
+ { /* Left edge is vertical, we don't need to increment. */
+ l.di = 0, l.df = 0;
+ fxl = 0;
+ }
+ else
+ { compute_dx(l, dxl, ysl);
+ fxl = ymult_quo(ysl, l);
+ l.x += fxl;
+ }
+ if ( fixed_floor(r.x) == fixed_pixround(x1r) )
+ { /* Right edge is vertical. If both are vertical, */
+ /* we have a rectangle. */
+ if ( l.di == 0 && l.df == 0 )
+ max_rect_height = max_int;
+ else
+ r.di = 0, r.df = 0;
+ }
+ /* The test for fxl != 0 is required because the right edge */
+ /* might cross some pixel centers even if the left edge doesn't. */
+ else if ( dxr == dxl && fxl != 0 )
+ { if ( l.di == 0 )
+ r.di = 0, r.df = l.df;
+ else /* too hard to do adjustments right */
+ compute_dx(r, dxr, ysr);
+ if ( ysr == ysl && r.h == l.h )
+ r.x += fxl;
+ else
+ r.x += ymult_quo(ysr, r);
+ }
+ else
+ { compute_dx(r, dxr, ysr);
+ r.x += ymult_quo(ysr, r);
+ }
+ rxl = fixed2int_var(l.x);
+ rxr = fixed2int_var(r.x);
+
+ /*
+ * Take a shortcut if we're only sampling a single scan line,
+ * or if we have a rectangle.
+ */
+ if ( iy1 - iy <= max_rect_height )
+ { iy = iy1;
+ if_debug2('z', "[z]rectangle, x=[%d,%d]\n", rxl, rxr);
+ goto last;
+ }
+
+ /* Compute one line's worth of dx/dy. */
+ /* dx# * fixed_1 = ld#i + (ld#f / h#). */
+#define compute_ldx(tl, ys)\
+ if ( tl.df < ymult_limit )\
+ { if ( tl.df == 0 ) /* vertical edge, worth checking for */\
+ tl.ldi = int2fixed(tl.di),\
+ tl.ldf = 0,\
+ tl.xf = -tl.h;\
+ else\
+ tl.ldi = int2fixed(tl.di) + int2fixed(tl.df) / tl.h,\
+ tl.ldf = int2fixed(tl.df) % tl.h,\
+ tl.xf = (ys < fixed_1 ? ys * tl.df % tl.h :\
+ fixed_mult_rem(ys, tl.df, tl.h)) - tl.h;\
+ }\
+ else\
+ tl.ldi = int2fixed(tl.di) + fixed_mult_quo(fixed_1, tl.df, tl.h),\
+ tl.ldf = fixed_mult_rem(fixed_1, tl.df, tl.h),\
+ tl.xf = fixed_mult_rem(ys, tl.df, tl.h) - tl.h
+ compute_ldx(l, ysl);
+ if ( dxr == dxl && ysr == ysl && r.h == l.h )
+ r.ldi = l.ldi, r.ldf = l.ldf, r.xf = l.xf;
+ else
+ { compute_ldx(r, ysr);
+ }
+#undef compute_ldx
+
+ while ( ++iy != iy1 )
+ { int ixl, ixr;
+#define step_line(tl)\
+ tl.x += tl.ldi;\
+ if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= tl.h, tl.x++;
+ step_line(l);
+ step_line(r);
+#undef step_line
+ ixl = fixed2int_var(l.x);
+ ixr = fixed2int_var(r.x);
+ if ( ixl != rxl || ixr != rxr )
+ { code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
+ if ( code < 0 ) goto xit;
+ rxl = ixl, rxr = ixr, ry = iy;
+ }
+ }
+last: code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
+xit: if ( code < 0 && fill_direct )
+ return_error(code);
+ return_if_interrupt();
+ return code;
+ }
+}
+
+/* Fill a parallelogram whose points are p, p+a, p+b, and p+a+b. */
+/* We should swap axes to get best accuracy, but we don't. */
+/* We must be very careful to follow the center-of-pixel rule in all cases. */
+int
+gx_default_fill_parallelogram(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ fixed t;
+ fixed qx, qy, ym;
+ dev_proc_fill_trapezoid((*fill_trapezoid));
+ gs_fixed_edge left, right;
+ int code;
+
+ /* Ensure ay >= 0, by >= 0. */
+ if ( ay < 0 )
+ px += ax, py += ay, ax = -ax, ay = -ay;
+ if ( by < 0 )
+ px += bx, py += by, bx = -bx, by = -by;
+ qx = px + ax + bx;
+ /* Make a special fast check for rectangles. */
+ if ( (ay | bx) == 0 || (by | ax) == 0 )
+ { /* If a point falls exactly on the middle of a pixel, */
+ /* we must round it down, not up. */
+ int rx = fixed2int_pixround(px);
+ int ry = fixed2int_pixround(py);
+ /* Exactly one of (ax,bx) and one of (ay,by) is non-zero. */
+ int w = fixed2int_pixround(qx) - rx;
+ if ( w < 0 ) rx += w, w = -w;
+ return gx_fill_rectangle_device_rop(rx, ry, w,
+ fixed2int_pixround(py + ay + by) - ry,
+ pdevc, dev, lop);
+ }
+ /*
+ * Not a rectangle. Ensure that the 'a' line is to the left of
+ * the 'b' line. Testing ax <= bx is neither sufficient nor
+ * necessary: in general, we need to compare the slopes.
+ */
+#define swap(r, s) (t = r, r = s, s = t)
+ if ( (ax ^ bx) < 0 )
+ { /* In this case, the test ax <= bx is sufficient. */
+ if ( ax > bx )
+ swap(ax, bx), swap(ay, by);
+ }
+ else
+ { /*
+ * Compare the slopes. We know that ay >= 0, by >= 0,
+ * and ax and bx have the same sign; the lines are in the
+ * correct order iff
+ * ay/ax >= by/bx, or
+ * ay*bx >= by*ax
+ * Eventually we can probably find a better way to test this,
+ * without using floating point.
+ */
+ if ( (double)ay * bx < (double)by * ax )
+ swap(ax, bx), swap(ay, by);
+ }
+ fill_trapezoid = dev_proc(dev, fill_trapezoid);
+ qy = py + ay + by;
+ left.start.x = right.start.x = px;
+ left.start.y = right.start.y = py;
+ left.end.x = px + ax;
+ left.end.y = py + ay;
+ right.end.x = px + bx;
+ right.end.y = py + by;
+#define rounded_same(p1, p2)\
+ (fixed_pixround(p1) == fixed_pixround(p2))
+ if ( ay < by )
+ { if ( !rounded_same(py, left.end.y) )
+ { code = (*fill_trapezoid)(dev, &left, &right, py, left.end.y,
+ false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ left.start = left.end;
+ left.end.x = qx, left.end.y = qy;
+ ym = right.end.y;
+ if ( !rounded_same(left.start.y, ym) )
+ { code = (*fill_trapezoid)(dev, &left, &right, left.start.y, ym,
+ false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ right.start = right.end;
+ right.end.x = qx, right.end.y = qy;
+ }
+ else
+ { if ( !rounded_same(py, right.end.y) )
+ { code = (*fill_trapezoid)(dev, &left, &right, py, right.end.y,
+ false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ right.start = right.end;
+ right.end.x = qx, right.end.y = qy;
+ ym = left.end.y;
+ if ( !rounded_same(right.start.y, ym) )
+ { code = (*fill_trapezoid)(dev, &left, &right, right.start.y, ym,
+ false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ left.start = left.end;
+ left.end.x = qx, left.end.y = qy;
+ }
+ if ( !rounded_same(ym, qy) )
+ return (*fill_trapezoid)(dev, &left, &right, ym, qy,
+ false, pdevc, lop);
+ else
+ return 0;
+#undef rounded_same
+#undef swap
+}
+
+/* Fill a triangle whose points are p, p+a, and p+b. */
+/* We should swap axes to get best accuracy, but we don't. */
+int
+gx_default_fill_triangle(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ fixed t;
+ fixed ym;
+ dev_proc_fill_trapezoid((*fill_trapezoid)) =
+ dev_proc(dev, fill_trapezoid);
+ gs_fixed_edge left, right;
+ int code;
+
+ /* Ensure ay >= 0, by >= 0. */
+ if ( ay < 0 )
+ px += ax, py += ay, bx -= ax, by -= ay, ax = -ax, ay = -ay;
+ if ( by < 0 )
+ px += bx, py += by, ax -= bx, ay -= by, bx = -bx, by = -by;
+ /* Ensure ay <= by. */
+#define swap(r, s) (t = r, r = s, s = t)
+ if ( ay > by )
+ swap(ax, bx), swap(ay, by);
+#undef swap
+ /*
+ * Make a special check for a flat bottom or top,
+ * which we can handle with a single call on fill_trapezoid.
+ */
+ left.start.x = right.start.x = px;
+ left.start.y = right.start.y = py;
+ if ( ay == 0 ) {
+ /* Flat top */
+ if ( ax < 0 )
+ left.start.x = px + ax;
+ else
+ right.start.x = px + ax;
+ left.end.x = right.end.x = px + bx;
+ left.end.y = right.end.y = py + by;
+ ym = py;
+ } else if ( ay == by ) {
+ /* Flat bottom */
+ if ( ax < bx )
+ left.end.x = px + ax, right.end.x = px + bx;
+ else
+ left.end.x = px + bx, right.end.x = px + ax;
+ left.end.y = right.end.y = py + by;
+ ym = py;
+ } else {
+ ym = py + ay;
+ if ( fixed_mult_quo(bx, ay, by) < ax ) {
+ /* The 'b' line is to the left of the 'a' line. */
+ left.end.x = px + bx, left.end.y = py + by;
+ right.end.x = px + ax, right.end.y = py + ay;
+ code = (*fill_trapezoid)(dev, &left, &right, py, ym,
+ false, pdevc, lop);
+ right.start = right.end;
+ right.end = left.end;
+ } else {
+ /* The 'a' line is to the left of the 'b' line. */
+ left.end.x = px + ax, left.end.y = py + ay;
+ right.end.x = px + bx, right.end.y = py + by;
+ code = (*fill_trapezoid)(dev, &left, &right, py, ym,
+ false, pdevc, lop);
+ left.start = left.end;
+ left.end = right.end;
+ }
+ if ( code < 0 )
+ return code;
+ }
+ return (*fill_trapezoid)(dev, &left, &right, ym, right.end.y,
+ false, pdevc, lop);
+}
+
+/* Draw a one-pixel-wide line. */
+int
+gx_default_draw_thin_line(gx_device *dev,
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ int ix = fixed2int_var(fx0);
+ int iy = fixed2int_var(fy0);
+ int itox = fixed2int_var(fx1);
+ int itoy = fixed2int_var(fy1);
+
+ return_if_interrupt();
+ if ( itoy == iy ) /* horizontal line */
+ { return (ix <= itox ?
+ gx_fill_rectangle_device_rop(ix, iy, itox - ix + 1, 1,
+ pdevc, dev, lop) :
+ gx_fill_rectangle_device_rop(itox, iy, ix - itox + 1, 1,
+ pdevc, dev, lop)
+ );
+ }
+ if ( itox == ix ) /* vertical line */
+ { return (iy <= itoy ?
+ gx_fill_rectangle_device_rop(ix, iy, 1, itoy - iy + 1,
+ pdevc, dev, lop) :
+ gx_fill_rectangle_device_rop(ix, itoy, 1, iy - itoy + 1,
+ pdevc, dev, lop)
+ );
+ }
+ if ( color_writes_pure(pdevc, lop) &&
+ (*dev_proc(dev, draw_line))(dev, ix, iy, itox, itoy,
+ pdevc->colors.pure) >= 0
+ )
+ return 0;
+ { fixed h = fy1 - fy0;
+ fixed w = fx1 - fx0;
+ fixed tf;
+ bool swap_axes;
+ gs_fixed_edge left, right;
+
+#define fswap(a, b) tf = a, a = b, b = tf
+ if ( (w < 0 ? -w : w) <= (h < 0 ? -h : h) )
+ { if ( h < 0 )
+ fswap(fx0, fx1), fswap(fy0, fy1),
+ h = -h;
+ right.start.x = (left.start.x = fx0 - fixed_half) + fixed_1;
+ right.end.x = (left.end.x = fx1 - fixed_half) + fixed_1;
+ left.start.y = right.start.y = fy0;
+ left.end.y = right.end.y = fy1;
+ swap_axes = false;
+ }
+ else
+ { if ( w < 0 )
+ fswap(fx0, fx1), fswap(fy0, fy1),
+ w = -w;
+ right.start.x = (left.start.x = fy0 - fixed_half) + fixed_1;
+ right.end.x = (left.end.x = fy1 - fixed_half) + fixed_1;
+ left.start.y = right.start.y = fx0;
+ left.end.y = right.end.y = fx1;
+ swap_axes = true;
+ }
+ return (*dev_proc(dev, fill_trapezoid))(dev, &left, &right,
+ left.start.y, left.end.y,
+ swap_axes, pdevc, lop);
+#undef fswap
+ }
+}
+
+/* Stub out the obsolete procedure. */
+int
+gx_default_draw_line(gx_device *dev,
+ int x0, int y0, int x1, int y1, gx_color_index color)
+{ return -1;
+}
diff --git a/gs/src/gdevdfax.c b/gs/src/gdevdfax.c
new file mode 100644
index 000000000..5ea19c5ae
--- /dev/null
+++ b/gs/src/gdevdfax.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevdfax.c */
+/* DigiBoard fax device. */
+/***
+ *** Note: this driver is maintained by a user: please contact
+ *** Rick Richardson (rick@digibd.com) if you have questions.
+ ***/
+#include "gdevprn.h"
+#include "strimpl.h"
+#include "scfx.h"
+
+/* Import the key routines from gdevtfax.c. */
+int gdev_fax_open(P1(gx_device *));
+void gdev_fax_init_state(P2(stream_CFE_state *, const gx_device_printer *));
+int gdev_fax_print_page(P3(gx_device_printer *, FILE *, stream_CFE_state *));
+
+/* Define the device parameters. */
+#define X_DPI 204
+#define Y_DPI 196
+
+/* The device descriptors */
+
+private dev_proc_open_device(dfax_prn_open);
+private dev_proc_print_page(dfax_print_page);
+
+struct gx_device_dfax_s {
+ gx_device_common;
+ gx_prn_device_common;
+ long pageno;
+ uint iwidth; /* width of image data in pixels */
+};
+typedef struct gx_device_dfax_s gx_device_dfax;
+
+private gx_device_procs dfax_procs =
+ prn_procs(dfax_prn_open, gdev_prn_output_page, gdev_prn_close);
+
+gx_device_dfax far_data gs_dfaxlow_device =
+{ prn_device_std_body(gx_device_dfax, dfax_procs, "dfaxlow",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI/2,
+ 0,0,0,0, /* margins */
+ 1, dfax_print_page)
+};
+
+gx_device_dfax far_data gs_dfaxhigh_device =
+{ prn_device_std_body(gx_device_dfax, dfax_procs, "dfaxhigh",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, dfax_print_page)
+};
+
+#define dfdev ((gx_device_dfax *)dev)
+
+/* Open the device, adjusting the paper size. */
+private int
+dfax_prn_open(gx_device *dev)
+{ dfdev->pageno = 0;
+ return gdev_fax_open(dev);
+}
+
+/* Print a DigiFAX page. */
+private int
+dfax_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ stream_CFE_state state;
+ static char hdr[64] = "\000PC Research, Inc\000\000\000\000\000\000";
+ int code;
+
+ gdev_fax_init_state(&state, dev);
+ state.EndOfLine = true;
+ state.EncodedByteAlign = true;
+
+ /* Start a page: write the header */
+ hdr[24] = 0; hdr[28] = 1;
+ hdr[26] = ++dfdev->pageno; hdr[27] = dfdev->pageno >> 8;
+ if (dev->y_pixels_per_inch == Y_DPI)
+ { hdr[45] = 0x40; hdr[29] = 1; } /* high res */
+ else
+ { hdr[45] = hdr[29] = 0; } /* low res */
+ fseek(prn_stream, 0, SEEK_END);
+ fwrite(hdr, sizeof(hdr), 1, prn_stream);
+
+ /* Write the page */
+ code = gdev_fax_print_page(dev, prn_stream, &state);
+
+ /* Fixup page count */
+ fseek(prn_stream, 24L, SEEK_SET);
+ hdr[24] = dfdev->pageno; hdr[25] = dfdev->pageno >> 8;
+ fwrite(hdr+24, 2, 1, prn_stream);
+
+ return code;
+}
+
+#undef dfdev
diff --git a/gs/src/gdevdflt.c b/gs/src/gdevdflt.c
new file mode 100644
index 000000000..c4bcc0810
--- /dev/null
+++ b/gs/src/gdevdflt.c
@@ -0,0 +1,911 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevdflt.c */
+/* Default device implementation */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbittab.h"
+#include "gsropt.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+
+/* ---------------- Default device procedures ---------------- */
+
+/* Define the default implementations of RasterOp procedures. */
+/* If the RasterOp option is linked in, it initializes these */
+/* to different values. */
+dev_proc_copy_rop((*gx_default_copy_rop_proc)) = gx_no_copy_rop;
+dev_proc_copy_rop((*gx_forward_copy_rop_proc)) = gx_no_copy_rop;
+dev_proc_strip_copy_rop((*gx_default_strip_copy_rop_proc)) = gx_no_strip_copy_rop;
+dev_proc_strip_copy_rop((*gx_forward_strip_copy_rop_proc)) = gx_no_strip_copy_rop;
+
+/* Fill in NULL procedures in a device procedure record. */
+void
+gx_device_fill_in_procs(register gx_device *dev)
+{ gx_device_set_procs(dev);
+ fill_dev_proc(dev, open_device, gx_default_open_device);
+ fill_dev_proc(dev, get_initial_matrix, gx_default_get_initial_matrix);
+ fill_dev_proc(dev, sync_output, gx_default_sync_output);
+ fill_dev_proc(dev, output_page, gx_default_output_page);
+ fill_dev_proc(dev, close_device, gx_default_close_device);
+ fill_dev_proc(dev, map_rgb_color, gx_default_map_rgb_color);
+ fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
+ /* NOT fill_rectangle */
+ fill_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle);
+ fill_dev_proc(dev, copy_mono, gx_default_copy_mono);
+ fill_dev_proc(dev, copy_color, gx_default_copy_color);
+ fill_dev_proc(dev, draw_line, gx_default_draw_line);
+ fill_dev_proc(dev, get_bits, gx_default_get_bits);
+ fill_dev_proc(dev, get_params, gx_default_get_params);
+ fill_dev_proc(dev, put_params, gx_default_put_params);
+ fill_dev_proc(dev, map_cmyk_color, gx_default_map_cmyk_color);
+ fill_dev_proc(dev, get_xfont_procs, gx_default_get_xfont_procs);
+ fill_dev_proc(dev, get_xfont_device, gx_default_get_xfont_device);
+ fill_dev_proc(dev, map_rgb_alpha_color, gx_default_map_rgb_alpha_color);
+ fill_dev_proc(dev, get_page_device, gx_default_get_page_device);
+ fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
+ fill_dev_proc(dev, copy_alpha, gx_default_copy_alpha);
+ fill_dev_proc(dev, get_band, gx_default_get_band);
+ fill_dev_proc(dev, copy_rop, gx_default_copy_rop_proc);
+ fill_dev_proc(dev, fill_path, gx_default_fill_path);
+ fill_dev_proc(dev, stroke_path, gx_default_stroke_path);
+ fill_dev_proc(dev, fill_mask, gx_default_fill_mask);
+ fill_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid);
+ fill_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram);
+ fill_dev_proc(dev, fill_triangle, gx_default_fill_triangle);
+ fill_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
+ fill_dev_proc(dev, begin_image, gx_default_begin_image);
+ fill_dev_proc(dev, image_data, gx_default_image_data);
+ fill_dev_proc(dev, end_image, gx_default_end_image);
+ fill_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle);
+ fill_dev_proc(dev, strip_copy_rop, gx_default_strip_copy_rop_proc);
+ fill_dev_proc(dev, get_clipping_box, gx_default_get_clipping_box);
+ fill_dev_proc(dev, get_hardware_params, gx_default_get_hardware_params);
+}
+
+int
+gx_default_open_device(gx_device *dev)
+{ return 0;
+}
+
+/* Get the initial matrix for a device with inverted Y. */
+/* This includes essentially all printers and displays. */
+void
+gx_default_get_initial_matrix(gx_device *dev, register gs_matrix *pmat)
+{ pmat->xx = dev->HWResolution[0] / 72.0; /* x_pixels_per_inch */
+ pmat->xy = 0;
+ pmat->yx = 0;
+ pmat->yy = dev->HWResolution[1] / -72.0; /* y_pixels_per_inch */
+ /****** tx/y is WRONG for devices with ******/
+ /****** arbitrary initial matrix ******/
+ pmat->tx = 0;
+ pmat->ty = dev->height;
+}
+/* Get the initial matrix for a device with upright Y. */
+/* This includes just a few printers and window systems. */
+void
+gx_upright_get_initial_matrix(gx_device *dev, register gs_matrix *pmat)
+{ pmat->xx = dev->HWResolution[0] / 72.0; /* x_pixels_per_inch */
+ pmat->xy = 0;
+ pmat->yx = 0;
+ pmat->yy = dev->HWResolution[1] / 72.0; /* y_pixels_per_inch */
+ /****** tx/y is WRONG for devices with ******/
+ /****** arbitrary initial matrix ******/
+ pmat->tx = 0;
+ pmat->ty = 0;
+}
+
+int
+gx_default_sync_output(gx_device *dev)
+{ return 0;
+}
+
+int
+gx_default_output_page(gx_device *dev, int num_copies, int flush)
+{ return (*dev_proc(dev, sync_output))(dev);
+}
+
+int
+gx_default_close_device(gx_device *dev)
+{ return 0;
+}
+
+/* By default, implement tile_rectangle using strip_tile_rectangle. */
+int
+gx_default_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{ gx_strip_bitmap tiles;
+ *(gx_tile_bitmap *)&tiles = *tile;
+ tiles.shift = tiles.rep_shift = 0;
+ return (*dev_proc(dev, strip_tile_rectangle))
+ (dev, &tiles, x, y, w, h, color0, color1, px, py);
+}
+
+/* Implement copy_mono by filling lots of small rectangles. */
+/* This is very inefficient, but it works as a default. */
+int
+gx_default_copy_mono(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ bool invert;
+ gx_color_index color;
+ gx_device_color devc;
+
+ fit_copy(dev, data, dx, raster, id, x, y, w, h);
+ if ( one != gx_no_color_index )
+ { invert = false;
+ color = one;
+ if ( zero != gx_no_color_index )
+ { int code = (*dev_proc(dev, fill_rectangle))
+ (dev, x, y, w, h, zero);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ else
+ { invert = true;
+ color = zero;
+ }
+ color_set_pure(&devc, color);
+ return gx_dc_default_fill_masked
+ (&devc, data, dx, raster, id, x, y, w, h, dev, rop3_T, invert);
+}
+
+/* Implement copy_color by filling lots of small rectangles. */
+/* This is very inefficient, but it works as a default. */
+int
+gx_default_copy_color(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int depth = dev->color_info.depth;
+ byte mask;
+ dev_proc_fill_rectangle((*fill));
+ const byte *row;
+ int iy;
+
+ if ( depth == 1 )
+ return (*dev_proc(dev, copy_mono))(dev, data, dx, raster, id,
+ x, y, w, h,
+ (gx_color_index)0, (gx_color_index)1);
+ fit_copy(dev, data, dx, raster, id, x, y, w, h);
+ fill = dev_proc(dev, fill_rectangle);
+ mask = (byte)((1 << depth) - 1);
+ for ( row = data, iy = 0; iy < h; row += raster, ++iy )
+ { int ix;
+ gx_color_index c0 = gx_no_color_index;
+ const byte *ptr = row + ((dx * depth) >> 3);
+ int i0;
+
+ for ( i0 = ix = 0; ix < w; ++ix )
+ { gx_color_index color;
+
+ if ( depth >= 8 )
+ { color = *ptr++;
+ switch ( depth )
+ {
+ case 32: color = (color << 8) + *ptr++;
+ case 24: color = (color << 8) + *ptr++;
+ case 16: color = (color << 8) + *ptr++;
+ }
+ }
+ else
+ { uint dbit = (-(ix + dx + 1) * depth) & 7;
+ color = (*ptr >> dbit) & mask;
+ if ( dbit == 0 )
+ ptr++;
+ }
+ if ( color != c0 )
+ { if ( ix > i0 )
+ { int code = (*fill)
+ (dev, i0 + x, iy + y, ix - i0, 1, c0);
+ if ( code < 0 )
+ return code;
+ }
+ c0 = color;
+ i0 = ix;
+ }
+ }
+ if ( ix > i0 )
+ { int code = (*fill)(dev, i0 + x, iy + y, ix - i0, 1, c0);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
+
+int
+gx_default_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ return_error(gs_error_unknownerror);
+}
+
+gx_xfont_procs *
+gx_default_get_xfont_procs(gx_device *dev)
+{ return NULL;
+}
+
+gx_device *
+gx_default_get_xfont_device(gx_device *dev)
+{ return dev;
+}
+
+gx_device *
+gx_default_get_page_device(gx_device *dev)
+{ return NULL;
+}
+gx_device *
+gx_page_device_get_page_device(gx_device *dev)
+{ return dev;
+}
+
+int
+gx_default_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return 1;
+}
+
+int
+gx_no_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ return_error(gs_error_unknownerror);
+}
+
+int
+gx_default_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ /* This might be called with depth = 1.... */
+ if ( depth == 1 )
+ return (*dev_proc(dev, copy_mono))(dev, data, data_x, raster, id,
+ x, y, width, height,
+ gx_no_color_index, color);
+ /*
+ * Simulate alpha by weighted averaging of RGB values.
+ * This is very slow, but functionally correct.
+ */
+ { const byte *row;
+ gs_memory_t *mem = dev->memory ? dev->memory : &gs_memory_default;
+ int bpp = dev->color_info.depth;
+ uint in_size = gx_device_raster(dev, false);
+ byte *lin;
+ uint out_size;
+ byte *lout;
+ int code = 0;
+ gx_color_value color_rgb[3];
+ int ry;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ row = data;
+ out_size = bitmap_raster(width * bpp);
+ lin = gs_alloc_bytes(mem, in_size, "copy_alpha(lin)");
+ lout = gs_alloc_bytes(mem, out_size, "copy_alpha(lout)");
+ if ( lin == 0 || lout == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ (*dev_proc(dev, map_color_rgb))(dev, color, color_rgb);
+ for ( ry = y; ry < y + height; row += raster, ++ry )
+ { byte *line;
+ int sx, rx;
+ declare_line_accum(lout, bpp, x);
+
+ code = (*dev_proc(dev, get_bits))(dev, ry, lin, &line);
+ if ( code < 0 )
+ break;
+ for ( sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx )
+ { gx_color_index previous = gx_no_color_index;
+ gx_color_index composite;
+ int alpha2, alpha;
+
+ if ( depth == 2 ) /* map 0 - 3 to 0 - 15 */
+ alpha = ((row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5;
+ else
+ alpha2 = row[sx >> 1],
+ alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
+blend: if ( alpha == 15 )
+ { /* Just write the new color. */
+ composite = color;
+ }
+ else
+ { if ( previous == gx_no_color_index )
+ { /* Extract the old color. */
+ if ( bpp < 8 )
+ { const uint bit = rx * bpp;
+ const byte *src = line + (bit >> 3);
+ previous =
+ (*src >> (8 - (bit + bpp))) &
+ ((1 << bpp) - 1);
+ }
+ else
+ { const byte *src = line + (rx * (bpp >> 3));
+ previous = 0;
+ switch ( bpp >> 3 )
+ {
+ case 4:
+ previous += (gx_color_index)*src++ << 24;
+ case 3:
+ previous += (gx_color_index)*src++ << 16;
+ case 2:
+ previous += (gx_color_index)*src++ << 8;
+ case 1:
+ previous += *src++;
+ }
+ }
+ }
+ if ( alpha == 0 )
+ { /* Just write the old color. */
+ composite = previous;
+ }
+ else
+ { /* Blend RGB values. */
+ gx_color_value rgb[3];
+
+ (*dev_proc(dev, map_color_rgb))(dev, previous, rgb);
+#if arch_ints_are_short
+# define b_int long
+#else
+# define b_int int
+#endif
+#define make_shade(old, clr, alpha, amax) \
+ (old) + (((b_int)(clr) - (b_int)(old)) * (alpha) / (amax))
+ rgb[0] = make_shade(rgb[0], color_rgb[0], alpha, 15);
+ rgb[1] = make_shade(rgb[1], color_rgb[1], alpha, 15);
+ rgb[2] = make_shade(rgb[2], color_rgb[2], alpha, 15);
+#undef b_int
+#undef make_shade
+ composite =
+ (*dev_proc(dev, map_rgb_color))(dev, rgb[0],
+ rgb[1], rgb[2]);
+ if ( composite == gx_no_color_index )
+ { /* The device can't represent this color. */
+ /* Move the alpha value towards 0 or 1. */
+ if ( alpha == 7 ) /* move 1/2 towards 1 */
+ ++alpha;
+ alpha = (alpha & 8) | (alpha >> 1);
+ goto blend;
+ }
+ }
+ }
+ line_accum(composite, bpp);
+ }
+ line_accum_copy(dev, lout, bpp, x, rx, raster, ry);
+ }
+out: gs_free_object(mem, lout, "copy_alpha(lout)");
+ gs_free_object(mem, lin, "copy_alpha(lin)");
+ return code;
+ }
+}
+
+int
+gx_default_get_band(gx_device *dev, int y, int *band_start)
+{ return 0;
+}
+
+int
+gx_no_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return_error(gs_error_unknownerror); /* not implemented */
+}
+int
+gx_default_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return (*gx_default_copy_rop_proc)
+ (dev, sdata, sourcex, sraster, id, scolors, texture, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+}
+
+int
+gx_default_fill_mask(gx_device *orig_dev,
+ const byte *data, int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ gx_device *dev;
+ gx_device_clip cdev;
+ gx_color_index colors[2];
+ gx_strip_bitmap *tile;
+
+ if ( gx_dc_is_pure(pdcolor) )
+ { tile = 0;
+ colors[0] = gx_no_color_index;
+ colors[1] = gx_dc_pure_color(pdcolor);
+ }
+ else if ( gx_dc_is_binary_halftone(pdcolor) )
+ { tile = gx_dc_binary_tile(pdcolor);
+ colors[0] = gx_dc_binary_color0(pdcolor);
+ colors[1] = gx_dc_binary_color1(pdcolor);
+ }
+ else
+ return_error(gs_error_unknownerror); /* not implemented */
+ if ( pcpath != 0 )
+ { gx_make_clip_path_device(&cdev, pcpath);
+ cdev.target = orig_dev;
+ dev = (gx_device *)&cdev;
+ (*dev_proc(dev, open_device))(dev);
+ }
+ else
+ dev = orig_dev;
+ if ( depth > 1 )
+ { /****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/
+ return (*dev_proc(dev, copy_alpha))
+ (dev, data, dx, raster, id, x, y, w, h, colors[1], depth);
+ }
+ if ( lop != lop_default )
+ { gx_color_index scolors[2];
+
+ scolors[0] = /* white */
+ (*dev_proc(dev, map_rgb_color))
+ (dev, gx_max_color_value, gx_max_color_value, gx_max_color_value);
+ scolors[1] = /* black */
+ (*dev_proc(dev, map_rgb_color))
+ (dev, (gx_color_value)0, (gx_color_value)0, (gx_color_value)0);
+ if ( tile == 0 )
+ colors[0] = colors[1]; /* pure color */
+ /* We want to write only where the mask is a 1, */
+ /* so enable source transparency. */
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, data, dx, raster, id, scolors, tile, colors,
+ x, y, w, h,
+ gx_dc_phase(pdcolor).x, gx_dc_phase(pdcolor).y,
+ /*
+ * We have to include S in the operation, otherwise
+ * S_transparent will be ignored.
+ */
+ lop | (rop3_S | lop_S_transparent));
+ }
+ if ( tile == 0 )
+ { return (*dev_proc(dev, copy_mono))
+ (dev, data, dx, raster, id, x, y, w, h,
+ gx_no_color_index, colors[1]);
+ }
+ /*
+ * Use the same approach as the default copy_mono (above). We
+ * should really clip to the intersection of the bounding boxes of
+ * the device and the clipping path, but it's too much work.
+ */
+ fit_copy(orig_dev, data, dx, raster, id, x, y, w, h);
+ { dev_proc_strip_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, strip_tile_rectangle);
+ const byte *row = data + (dx >> 3);
+ int dx_bit = dx & 7;
+ int wdx = w + dx_bit;
+ int iy;
+
+ for ( row = data, iy = 0; iy < h; row += raster, iy++ )
+ { int ix;
+ for ( ix = dx_bit; ix < wdx; )
+ { int i0;
+ uint b;
+ uint len;
+ int code;
+
+ /* Skip 0-bits. */
+ b = row[ix >> 3];
+ len = byte_bit_run_length[ix & 7][b ^ 0xff];
+ if ( len )
+ { ix += ((len - 1) & 7) + 1;
+ continue;
+ }
+ /* Scan 1-bits. */
+ i0 = ix;
+ for ( ; ; )
+ { b = row[ix >> 3];
+ len = byte_bit_run_length[ix & 7][b];
+ if ( !len )
+ break;
+ ix += ((len - 1) & 7) + 1;
+ if ( ix >= wdx )
+ { ix = wdx;
+ break;
+ }
+ if ( len < 8 )
+ break;
+ }
+ /* Now color the run from i0 to ix. */
+ code = (*tile_proc)
+ (dev, tile, i0 - dx_bit + x, iy + y, ix - i0, 1,
+ colors[0], colors[1],
+ gx_dc_phase(pdcolor).x, gx_dc_phase(pdcolor).y);
+ if ( code < 0 )
+ return code;
+#undef row_bit
+ }
+ }
+ }
+ return 0;
+}
+
+/* Default implementation of strip_tile_rectangle */
+int
+gx_default_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{ /* Fill the rectangle in chunks. */
+ int width = tiles->size.x;
+ int height = tiles->size.y;
+ int raster = tiles->raster;
+ int rwidth = tiles->rep_width;
+ int rheight = tiles->rep_height;
+ int shift = tiles->shift;
+
+ fit_fill_xy(dev, x, y, w, h);
+
+#ifdef DEBUG
+if ( gs_debug_c('t') )
+ { int ptx, pty;
+ const byte *ptp = tiles->data;
+ dprintf3("[t]tile %dx%d raster=%d;",
+ tiles->size.x, tiles->size.y, tiles->raster);
+ dprintf6(" x,y=%d,%d w,h=%d,%d p=%d,%d\n",
+ x, y, w, h, px, py);
+ for ( pty = 0; pty < tiles->size.y; pty++ )
+ { dprintf(" ");
+ for ( ptx = 0; ptx < tiles->raster; ptx++ )
+ dprintf1("%3x", *ptp++);
+ }
+ dputc('\n');
+ }
+#endif
+
+ if ( dev_proc(dev, tile_rectangle) != gx_default_tile_rectangle )
+ { if ( shift == 0 )
+ { /*
+ * Temporarily patch the tile_rectangle procedure in the
+ * device so we don't get into a recursion loop if the
+ * device has a tile_rectangle procedure that conditionally
+ * calls the strip_tile_rectangle procedure.
+ */
+ dev_proc_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, tile_rectangle);
+ int code;
+
+ set_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle);
+ code = (*tile_proc)
+ (dev, (const gx_tile_bitmap *)tiles, x, y, w, h,
+ color0, color1, px, py);
+ set_dev_proc(dev, tile_rectangle, tile_proc);
+ return code;
+ }
+ /* We should probably optimize this case too, for the benefit */
+ /* of window systems, but we don't yet. */
+ }
+
+ { /*
+ * Note: we can't do the following computations until after
+ * the fit_fill_xy.
+ */
+ int xoff =
+ (shift == 0 ? px :
+ px + (y + py) / rheight * tiles->rep_shift);
+ int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */
+ (x + xoff) & (rwidth - 1) :
+ (x + xoff) % rwidth);
+ int ry = ((rheight & (rheight - 1)) == 0 ? /* power of 2 */
+ (y + py) & (rheight - 1) :
+ (y + py) % rheight);
+ int icw = width - irx;
+ int ch = height - ry;
+ byte *row = tiles->data + ry * raster;
+ dev_proc_copy_mono((*proc_mono));
+ dev_proc_copy_color((*proc_color));
+ int code;
+
+ if ( color0 == gx_no_color_index && color1 == gx_no_color_index )
+ proc_color = dev_proc(dev, copy_color);
+ else
+ proc_color = 0, proc_mono = dev_proc(dev, copy_mono);
+
+/****** SHOULD ALSO PASS id IF COPYING A FULL TILE ******/
+#define real_copy_tile(srcx, tx, ty, tw, th)\
+ code =\
+ (proc_color != 0 ?\
+ (*proc_color)(dev, row, srcx, raster, gx_no_bitmap_id, tx, ty, tw, th) :\
+ (*proc_mono)(dev, row, srcx, raster, gx_no_bitmap_id, tx, ty, tw, th, color0, color1));\
+ if ( code < 0 ) return_error(code);\
+ return_if_interrupt()
+#ifdef DEBUG
+#define copy_tile(sx, tx, ty, tw, th)\
+ if ( gs_debug_c('t') )\
+ dprintf5(" copy sx=%d x=%d y=%d w=%d h=%d\n",\
+ sx, tx, ty, tw, th);\
+ real_copy_tile(sx, tx, ty, tw, th)
+#else
+#define copy_tile(sx, tx, ty, tw, th)\
+ real_copy_tile(sx, tx, ty, tw, th)
+#endif
+ if ( ch >= h )
+ { /* Shallow operation */
+ if ( icw >= w )
+ { /* Just one (partial) tile to transfer. */
+ copy_tile(irx, x, y, w, h);
+ }
+ else
+ { int ex = x + w;
+ int fex = ex - width;
+ int cx = x + icw;
+
+ copy_tile(irx, x, y, icw, h);
+ while ( cx <= fex )
+ { copy_tile(0, cx, y, width, h);
+ cx += width;
+ }
+ if ( cx < ex )
+ { copy_tile(0, cx, y, ex - cx, h);
+ }
+ }
+ }
+ else if ( icw >= w && shift == 0 )
+ { /* Narrow operation, no shift */
+ int ey = y + h;
+ int fey = ey - height;
+ int cy = y + ch;
+
+ copy_tile(irx, x, y, w, ch);
+ row = tiles->data;
+ do
+ { ch = (cy > fey ? ey - cy : height);
+ copy_tile(irx, x, cy, w, ch);
+ }
+ while ( (cy += ch) < ey );
+ }
+ else
+ { /* Full operation. If shift != 0, some scan lines */
+ /* may be narrow. We could test shift == 0 in advance */
+ /* and use a slightly faster loop, but right now */
+ /* we don't bother. */
+ int ex = x + w, ey = y + h;
+ int fex = ex - width, fey = ey - height;
+ int cx, cy;
+
+ for ( cy = y; ; )
+ { if ( icw >= w )
+ { copy_tile(irx, x, cy, w, ch);
+ }
+ else
+ { copy_tile(irx, x, cy, icw, ch);
+ cx = x + icw;
+ while ( cx <= fex )
+ { copy_tile(0, cx, cy, width, ch);
+ cx += width;
+ }
+ if ( cx < ex )
+ { copy_tile(0, cx, cy, ex - cx, ch);
+ }
+ }
+ if ( (cy += ch) >= ey ) break;
+ ch = (cy > fey ? ey - cy : height);
+ if ( (irx += shift) >= rwidth )
+ irx -= rwidth;
+ icw = width - irx;
+ row = tiles->data;
+ }
+ }
+#undef copy_tile
+#undef real_copy_tile
+ }
+ return 0;
+}
+
+int
+gx_no_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return_error(gs_error_unknownerror); /* not implemented */
+}
+int
+gx_default_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return (*gx_default_strip_copy_rop_proc)
+ (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+}
+
+void
+gx_default_get_clipping_box(gx_device *dev, gs_fixed_rect *pbox)
+{ pbox->p.x = 0;
+ pbox->p.y = 0;
+ pbox->q.x = int2fixed(dev->width);
+ pbox->q.y = int2fixed(dev->height);
+}
+void
+gx_get_largest_clipping_box(gx_device *dev, gs_fixed_rect *pbox)
+{ pbox->p.x = min_fixed;
+ pbox->p.y = min_fixed;
+ pbox->q.x = max_fixed;
+ pbox->q.y = max_fixed;
+}
+
+/* The following is not really a device procedure. See gxdevice.h. */
+
+/* Create an ordinary memory device for page or band buffering. */
+int
+gx_default_make_buffer_device(gx_device_memory *mdev,
+ gx_device *target, gs_memory_t *mem, bool for_band)
+{ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(target->color_info.depth);
+
+ if ( mdproto == 0 )
+ return_error(gs_error_rangecheck);
+ if ( target == (gx_device *)mdev )
+ mdev->std_procs = mdproto->std_procs;
+ else
+ gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0),
+ (target == (gx_device *)mdev ? 0 : target));
+ return 0;
+}
+
+/* ---------------- Default per-instance procedures ---------------- */
+
+int
+gx_default_install(gx_device *dev, gs_state *pgs)
+{ return 0;
+}
+
+int
+gx_default_begin_page(gx_device *dev, gs_state *pgs)
+{ return 0;
+}
+
+int
+gx_default_end_page(gx_device *dev, int reason, gs_state *pgs)
+{ return (reason != 2 ? 1 : 0);
+}
+
+/* ---------------- Unaligned copy operations ---------------- */
+
+/*
+ * Implementing unaligned operations in terms of the standard aligned
+ * operations requires adjusting the bitmap origin and/or the raster to be
+ * aligned. Adjusting the origin is simple; adjusting the raster requires
+ * doing the operation one scan line at a time.
+ */
+int
+gx_copy_mono_unaligned(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
+ uint offset = alignment_mod(data, align_bitmap_mod);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /* Adjust the origin. */
+ data -= offset;
+ dx += offset << 3;
+
+ /* Adjust the raster. */
+ if ( !step )
+ { /* No adjustment needed. */
+ return (*copy_mono)(dev, data, dx, raster, id,
+ x, y, w, h, zero, one);
+ }
+
+ /* Do the transfer one scan line at a time. */
+ { const byte *p = data;
+ int d = dx;
+ int code = 0;
+ int i;
+
+ for ( i = 0; i < h && code >= 0;
+ ++i, p += raster - step, d += step << 3
+ )
+ code = (*copy_mono)(dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, w, 1, zero, one);
+ return code;
+ }
+}
+
+int
+gx_copy_color_unaligned(gx_device *dev, const byte *data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height)
+{ dev_proc_copy_color((*copy_color)) = dev_proc(dev, copy_color);
+ int depth = dev->color_info.depth;
+ uint offset = (uint)(data - (const byte *)0) & (align_bitmap_mod - 1);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /*
+ * Adjust the origin.
+ * We have to do something very special for 24-bit data,
+ * because that is the only depth that doesn't divide
+ * align_bitmap_mod exactly. In particular, we need to find
+ * M*B + R == 0 mod 3, where M is align_bitmap_mod, R is the
+ * offset value just calculated, and B is an integer unknown;
+ * the new value of offset will be M*B + R.
+ */
+ if ( depth == 24 )
+ offset += (offset % 3) *
+ (align_bitmap_mod * (3 - (align_bitmap_mod % 3)));
+ data -= offset;
+ data_x += (offset << 3) / depth;
+
+ /* Adjust the raster. */
+ if ( !step )
+ { /* No adjustment needed. */
+ return (*copy_color)(dev, data, data_x, raster, id,
+ x, y, width, height);
+ }
+
+ /* Do the transfer one scan line at a time. */
+ { const byte *p = data;
+ int d = data_x;
+ int dstep = (step << 3) / depth;
+ int code = 0;
+ int i;
+
+ for ( i = 0; i < height && code >= 0;
+ ++i, p += raster - step, d += dstep
+ )
+ code = (*copy_color)(dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, width, 1);
+ return code;
+ }
+}
+
+int
+gx_copy_alpha_unaligned(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ dev_proc_copy_alpha((*copy_alpha)) = dev_proc(dev, copy_alpha);
+ uint offset = (uint)(data - (const byte *)0) & (align_bitmap_mod - 1);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /* Adjust the origin. */
+ data -= offset;
+ data_x += (offset << 3) / depth;
+
+ /* Adjust the raster. */
+ if ( !step )
+ { /* No adjustment needed. */
+ return (*copy_alpha)(dev, data, data_x, raster, id,
+ x, y, width, height, color, depth);
+ }
+
+ /* Do the transfer one scan line at a time. */
+ { const byte *p = data;
+ int d = data_x;
+ int dstep = (step << 3) / depth;
+ int code = 0;
+ int i;
+
+ for ( i = 0; i < height && code >= 0;
+ ++i, p += raster - step, d += dstep
+ )
+ code = (*copy_alpha)(dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, width, 1, color, depth);
+ return code;
+ }
+}
diff --git a/gs/src/gdevdjet.c b/gs/src/gdevdjet.c
new file mode 100644
index 000000000..953d25ad5
--- /dev/null
+++ b/gs/src/gdevdjet.c
@@ -0,0 +1,608 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevdjet.c */
+/* HP LaserJet/DeskJet driver for Ghostscript */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+
+/*
+ * Thanks for various improvements to:
+ * Jim Mayer (mayer@wrc.xerox.com)
+ * Jan-Mark Wams (jms@cs.vu.nl)
+ * Frans van Hoesel (hoesel@chem.rug.nl)
+ * George Cameron (g.cameron@biomed.abdn.ac.uk)
+ * Nick Duffek (nsd@bbc.com)
+ * Thanks for the LJIIID duplex capability to:
+ * PDP (Philip) Brown (phil@3soft-uk.com)
+ * Thanks for the OCE 9050 driver to:
+ * William Bader (wbader@EECS.Lehigh.Edu)
+ */
+
+/*
+ * You may select a default resolution of 75, 100, 150, 300, or
+ * (LJ4 only) 600 DPI in the makefile, or an actual resolution
+ * on the gs command line.
+ *
+ * If the preprocessor symbol A4 is defined, the default paper size is
+ * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
+ *
+ * To determine the proper "margin" settings for your printer, see the
+ * file align.ps.
+ */
+
+/* Define the default, maximum resolutions. */
+#ifdef X_DPI
+# define X_DPI2 X_DPI
+#else
+# define X_DPI 300
+# define X_DPI2 600
+#endif
+#ifdef Y_DPI
+# define Y_DPI2 Y_DPI
+#else
+# define Y_DPI 300
+# define Y_DPI2 600
+#endif
+
+/*
+ * For all DeskJet Printers:
+ *
+ * Maximum printing width = 2400 dots = 8"
+ * Maximum recommended printing height = 3100 dots = 10 1/3"
+ *
+ * All Deskjets have 1/2" unprintable bottom margin.
+ * The recommendation comes from the HP Software Developer's Guide for
+ * the DeskJet 500, DeskJet PLUS, and DeskJet printers, version C.01.00
+ * of 12/1/90.
+ *
+ * Note that the margins defined just below here apply only to the DeskJet;
+ * the paper size, width and height apply to the LaserJet as well.
+ */
+
+/* Margins are left, bottom, right, top. */
+/* from Frans van Hoesel hoesel@rugr86.rug.nl. */
+/* A4 has a left margin of 1/8 inch and at a printing width of
+ * 8 inch this give a right margin of 0.143. The 0.09 top margin is
+ * not the actual margin - which is 0.07 - but compensates for the
+ * inexact paperlength which is set to 117 10ths.
+ * Somebody should check for letter sized paper. I left it at 0.07".
+ */
+#define DESKJET_MARGINS_LETTER 0.2, 0.45, 0.3, 0.05
+#define DESKJET_MARGINS_A4 0.125, 0.5, 0.143, 0.09
+/* Similar margins for the LaserJet. */
+/* These are defined in the PCL 5 Technical Reference Manual. */
+/* Note that for PCL 5 printers, we get the printer to translate the */
+/* coordinate system: the margins only define the unprintable area. */
+#define LASERJET_MARGINS_A4 0.167, 0.167, 0.167, 0.167
+#define LASERJET_MARGINS_LETTER 0.167, 0.167, 0.167, 0.167
+
+/* The number of blank lines that make it worthwhile to reposition */
+/* the cursor. */
+#define MIN_SKIP_LINES 7
+
+/* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
+#define W sizeof(word)
+
+/* Printer types */
+#define LJ 0
+#define LJplus 1
+#define LJ2p 2
+#define LJ3 3
+#define DJ 4
+#define DJ500 5
+#define LJ4 6
+#define LP2563B 7
+#define LJ3D 8
+#define OCE9050 9
+
+/*
+ * The notion that there is such a thing as a "PCL printer" is a fiction:
+ * no two "PCL" printers, even at the same PCL level, have identical
+ * command sets. The command strings below were established by hearsay
+ * and by trial and error. (The H-P documentation isn't fully accurate
+ * either; for example, it doesn't reveal that the DeskJet printers
+ * implement anything beyond PCL 3.)
+ */
+
+/* Printer capabilities */
+typedef enum {
+ mode_0, /* PCL 3, use <ESC>*p+<n>Y for vertical spacing */
+ mode_0ns, /* PCL 3 but no vertical spacing */
+ mode_2, /* PCL 4, use <ESC>*b<n>Y for vertical spacing */
+ mode_2p, /* PCL 4 but no vertical spacing */
+ mode_3, /* PCL 5, use <ESC>*b<n>Y and clear seed row */
+ /* (includes mode 2) */
+ mode_3ns /* PCL 5 but no vertical spacing */
+} compression_modes;
+
+/* The device descriptors */
+private dev_proc_open_device(hpjet_open);
+private dev_proc_close_device(hpjet_close);
+private dev_proc_print_page(djet_print_page);
+private dev_proc_print_page(djet500_print_page);
+private dev_proc_print_page(ljet_print_page);
+private dev_proc_print_page(ljetplus_print_page);
+private dev_proc_print_page(ljet2p_print_page);
+private dev_proc_print_page(ljet3_print_page);
+private dev_proc_print_page(ljet3d_print_page);
+private dev_proc_print_page(ljet4_print_page);
+private dev_proc_print_page(lp2563_print_page);
+private dev_proc_print_page(oce9050_print_page);
+
+private gx_device_procs prn_hp_procs =
+ prn_params_procs(hpjet_open, gdev_prn_output_page, hpjet_close,
+ gdev_prn_get_params, gdev_prn_put_params);
+
+gx_device_printer far_data gs_deskjet_device =
+ prn_device(prn_hp_procs, "deskjet",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins filled in by hpjet_open */
+ 1, djet_print_page);
+
+gx_device_printer far_data gs_djet500_device =
+ prn_device(prn_hp_procs, "djet500",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins filled in by hpjet_open */
+ 1, djet500_print_page);
+
+gx_device_printer far_data gs_laserjet_device =
+ prn_device(prn_hp_procs, "laserjet",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.05, 0.25, 0.55, 0.25, /* margins */
+ 1, ljet_print_page);
+
+gx_device_printer far_data gs_ljetplus_device =
+ prn_device(prn_hp_procs, "ljetplus",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.05, 0.25, 0.55, 0.25, /* margins */
+ 1, ljetplus_print_page);
+
+gx_device_printer far_data gs_ljet2p_device =
+ prn_device(prn_hp_procs, "ljet2p",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.20, 0.25, 0.25, 0.25, /* margins */
+ 1, ljet2p_print_page);
+
+gx_device_printer far_data gs_ljet3_device =
+ prn_device(prn_hp_procs, "ljet3",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.20, 0.25, 0.25, 0.25, /* margins */
+ 1, ljet3_print_page);
+
+gx_device_printer far_data gs_ljet3d_device =
+ prn_device(prn_hp_procs, "ljet3d",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.20, 0.25, 0.25, 0.25, /* margins */
+ 1, ljet3d_print_page);
+
+gx_device_printer far_data gs_ljet4_device =
+ prn_device(prn_hp_procs, "ljet4",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI2, Y_DPI2,
+ 0, 0, 0, 0, /* margins */
+ 1, ljet4_print_page);
+
+gx_device_printer far_data gs_lp2563_device =
+ prn_device(prn_hp_procs, "lp2563",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins */
+ 1, lp2563_print_page);
+
+gx_device_printer far_data gs_oce9050_device =
+ prn_device(prn_hp_procs, "oce9050",
+ 24 * 10, 24 * 10, /* 24 inch roll (can print 32" also) */
+ 400, 400, /* 400 dpi */
+ 0, 0, 0, 0, /* margins */
+ 1, oce9050_print_page);
+
+/* Forward references */
+private int hpjet_print_page(P6(gx_device_printer *pdev, FILE *prn_stream,
+ int ptype, int dots_per_inch,
+ compression_modes cmodes,
+ const char *page_init));
+
+#define ppdev ((gx_device_printer *)pdev)
+
+/* Open the printer, adjusting the margins if necessary. */
+private int
+hpjet_open(gx_device *pdev)
+{ /* Change the margins if necessary. */
+ const float _ds *m = 0;
+ bool move_origin = true;
+
+ if ( ppdev->printer_procs.print_page == djet_print_page ||
+ ppdev->printer_procs.print_page == djet500_print_page
+ )
+ { static const float m_a4[4] = { DESKJET_MARGINS_A4 };
+ static const float m_letter[4] = { DESKJET_MARGINS_LETTER };
+ m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
+ m_letter);
+ }
+ else if ( ppdev->printer_procs.print_page == oce9050_print_page ||
+ ppdev->printer_procs.print_page == lp2563_print_page
+ )
+ ;
+ else /* LaserJet */
+ { static const float m_a4[4] = { LASERJET_MARGINS_A4 };
+ static const float m_letter[4] = { LASERJET_MARGINS_LETTER };
+ m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
+ m_letter);
+ move_origin = false;
+ }
+ if ( m != 0 )
+ gx_device_set_margins(pdev, m, move_origin);
+ /* If this is a LJIIID, enable Duplex. */
+ if ( ppdev->printer_procs.print_page == ljet3d_print_page )
+ ppdev->Duplex = true, ppdev->Duplex_set = 0;
+ return gdev_prn_open(pdev);
+}
+
+/* hpjet_close is only here to eject odd numbered pages in duplex mode. */
+private int
+hpjet_close(gx_device *pdev)
+{ if ( ppdev->Duplex_set >= 0 && ppdev->Duplex )
+ { gdev_prn_open_printer(pdev, 1);
+ fputs("\033&l0H", ppdev->file) ;
+ }
+ return gdev_prn_close(pdev);
+}
+
+#undef ppdev
+
+/* ------ Internal routines ------ */
+
+/* The DeskJet can compress (mode 2) */
+private int
+djet_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, DJ, 300, mode_2,
+ "\033&k1W\033*b2M");
+}
+/* The DeskJet500 can compress (modes 2&3) */
+private int
+djet500_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, DJ500, 300, mode_3,
+ "\033&k1W");
+}
+/* The LaserJet series II can't compress */
+private int
+ljet_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LJ, 300, mode_0,
+ "\033*b0M");
+}
+/* The LaserJet Plus can't compress */
+private int
+ljetplus_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LJplus, 300, mode_0,
+ "\033*b0M");
+}
+/* LaserJet series IIp & IId compress (mode 2) */
+/* but don't support *p+ or *b vertical spacing. */
+private int
+ljet2p_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LJ2p, 300, mode_2p,
+ "\033*r0F\033*b2M");
+}
+/* All LaserJet series IIIs (III,IIId,IIIp,IIIsi) compress (modes 2&3) */
+/* They also need their coordinate system translated slightly. */
+private int
+ljet3_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LJ3, 300, mode_3,
+ "\033&l-180u36Z\033*r0F");
+}
+/* LaserJet IIId is same as LaserJet III, except for duplex */
+private int
+ljet3d_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LJ3D, 300, mode_3,
+ "\033&l-180u36Z\033*r0F");
+}
+/* LaserJet 4 series compresses, and it needs a special sequence to */
+/* allow it to specify coordinates at 600 dpi. */
+/* It too needs its coordinate system translated slightly. */
+private int
+ljet4_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int dots_per_inch = (int)pdev->y_pixels_per_inch;
+ char real_init[60];
+
+ sprintf(real_init, "\033&l-180u36Z\033*r0F\033&u%dD", dots_per_inch);
+ return hpjet_print_page(pdev, prn_stream, LJ4, dots_per_inch, mode_3,
+ real_init);
+}
+/* The 2563B line printer can't compress */
+/* and doesn't support *p+ or *b vertical spacing. */
+private int
+lp2563_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return hpjet_print_page(pdev, prn_stream, LP2563B, 300, mode_0ns,
+ "\033*b0M");
+}
+/* The Oce line printer has TIFF compression */
+/* and doesn't support *p+ or *b vertical spacing. */
+private int
+oce9050_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int code;
+
+ /* Switch to HP_RTL. */
+ fputs("\033%1B", prn_stream); /* Enter HPGL/2 mode */
+ fputs("BP", prn_stream); /* Begin Plot */
+ fputs("IN;", prn_stream); /* Initialize (start plot) */
+ fputs("\033%1A", prn_stream); /* Enter PCL mode */
+
+ code = hpjet_print_page(pdev, prn_stream, OCE9050, 400, mode_3ns,
+ "\033*b3M");
+
+ /* Return to HPGL/2 mode. */
+ fputs("\033%1B", prn_stream); /* Enter HPGL/2 mode */
+ if ( code == 0 )
+ { fputs("PU", prn_stream); /* Pen Up */
+ fputs("SP0", prn_stream); /* Pen Select */
+ fputs("PG;", prn_stream); /* Advance Full Page */
+ fputs("\033E", prn_stream); /* Reset */
+ }
+
+ return code;
+}
+
+/* Send the page to the printer. For speed, compress each scan line, */
+/* since computer-to-printer communication time is often a bottleneck. */
+private int
+hpjet_print_page(gx_device_printer *pdev, FILE *prn_stream, int ptype,
+ int dots_per_inch, compression_modes cmodes, const char *page_init)
+{ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int line_size_words = (line_size + W - 1) / W;
+ uint storage_size_words = line_size_words * 8; /* data, out_row, out_row_alt, prev_row */
+ word *storage = (ulong *)gs_malloc(storage_size_words, W,
+ "hpjet_print_page");
+ word
+ *data_words,
+ *out_row_words,
+ *out_row_alt_words,
+ *prev_row_words;
+#define data ((byte *)data_words)
+#define out_row ((byte *)out_row_words)
+#define out_row_alt ((byte *)out_row_alt_words)
+#define prev_row ((byte *)prev_row_words)
+ byte *out_data;
+ int x_dpi = pdev->x_pixels_per_inch;
+ int y_dpi = pdev->y_pixels_per_inch;
+ int y_dots_per_pixel = dots_per_inch / y_dpi;
+ int num_rows = dev_print_scan_lines(pdev);
+
+ int out_count;
+ int compression = -1;
+ static const char *from2to3 = "\033*b3M";
+ static const char *from3to2 = "\033*b2M";
+ int penalty_from2to3 = strlen(from2to3);
+ int penalty_from3to2 = strlen(from3to2);
+ int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
+ int code = 0;
+ bool dup = pdev->Duplex;
+ bool dupset = pdev->Duplex_set >= 0;
+
+ if ( storage == 0 ) /* can't allocate working area */
+ return_error(gs_error_VMerror);
+ data_words = storage;
+ out_row_words = data_words + (line_size_words * 2);
+ out_row_alt_words = out_row_words + (line_size_words * 2);
+ prev_row_words = out_row_alt_words + (line_size_words * 2);
+ /* Clear temp storage */
+ memset(data, 0, storage_size_words * W);
+
+ /* Initialize printer. */
+ if ( pdev->PageCount == 0 )
+ { fputs("\033E", prn_stream); /* reset printer */
+ /* If the printer supports it, set the paper size */
+ /* based on the actual requested size. */
+ if ( !(ptype == LJ || ptype == LJplus ) )
+ { fprintf(prn_stream, "\033&l%dA", paper_size);
+ }
+ /* If printer can duplex, set duplex mode appropriately. */
+ if ( ptype == LJ3D )
+ { if ( dupset && dup )
+ fputs("\033&l1S",prn_stream);
+ else if ( dupset && !dup )
+ fputs("\033&l0S",prn_stream);
+ else /* default to duplex for this printer */
+ fputs("\033&l1S",prn_stream);
+ }
+ }
+
+ /* Put out per-page initialization. */
+ fputs("\033&l0o0l0E", prn_stream);
+ fputs(page_init, prn_stream);
+
+ /* End raster graphics, position cursor at top. */
+ fputs("\033*rB\033*p0x0Y", prn_stream);
+
+ /* The DeskJet and DeskJet Plus reset everything upon */
+ /* receiving \033*rB, so we must reinitialize graphics mode. */
+ if ( ptype == DJ )
+ fputs(page_init, prn_stream);
+
+ /* Set resolution. */
+ fprintf(prn_stream, "\033*t%dR", x_dpi);
+
+ /* Send each scan line in turn */
+ { int lnum;
+ int num_blank_lines = 0;
+ word rmask = ~(word)0 << (-pdev->width & (W * 8 - 1));
+
+ /* Transfer raster graphics. */
+ for ( lnum = 0; lnum < num_rows; lnum++ )
+ { register word *end_data =
+ data_words + line_size_words;
+ code = gdev_prn_copy_scan_lines(pdev, lnum,
+ (byte *)data, line_size);
+ if ( code < 0 )
+ break;
+ /* Mask off 1-bits beyond the line width. */
+ end_data[-1] &= rmask;
+ /* Remove trailing 0s. */
+ while ( end_data > data_words && end_data[-1] == 0 )
+ end_data--;
+ if ( end_data == data_words )
+ { /* Blank line */
+ num_blank_lines++;
+ continue;
+ }
+
+ /* We've reached a non-blank line. */
+ /* Put out a spacing command if necessary. */
+ if ( num_blank_lines == lnum )
+ { /* We're at the top of a page. */
+ if ( cmodes == mode_2p || cmodes == mode_0ns )
+ { /* Start raster graphics. */
+ fputs("\033*r1A", prn_stream);
+ for ( ; num_blank_lines; num_blank_lines-- )
+ fputs("\033*bW", prn_stream);
+ }
+ else if ( cmodes == mode_3ns )
+ { /* Start raster graphics. */
+ fputs("\033*r1A", prn_stream);
+#if 1 /* don't waste paper */
+ if ( num_blank_lines > 0 )
+ fputs("\033*b0W", prn_stream);
+ num_blank_lines = 0;
+#else
+ for ( ; num_blank_lines; num_blank_lines-- )
+ fputs("\033*b0W", prn_stream);
+#endif
+ }
+ else
+ { if ( num_blank_lines > 0 )
+ fprintf(prn_stream, "\033*p+%dY",
+ num_blank_lines * y_dots_per_pixel);
+ /* Start raster graphics. */
+ fputs("\033*r1A", prn_stream);
+ }
+ }
+ /* Skip blank lines if any */
+ else if ( num_blank_lines != 0 )
+ { /* For Canon LBP4i and some others: */
+ /* <ESC>*b<n>Y doesn't properly clear the seed */
+ /* row if we are in compression mode 3. */
+ if ( (num_blank_lines < MIN_SKIP_LINES &&
+ compression != 3) ||
+ cmodes == mode_3ns ||
+ cmodes == mode_2p || cmodes == mode_0ns
+ )
+ { /* Moving down from current position */
+ /* causes head motion on the DeskJet, so */
+ /* if the number of lines is small, */
+ /* we're better off printing blanks. */
+ if ( cmodes == mode_3ns && compression != 2 )
+ { /* Switch to mode 2 */
+ fputs(from3to2, prn_stream);
+ compression = 2;
+ }
+ if ( cmodes == mode_3 || cmodes == mode_3ns )
+ { /* Must clear the seed row. */
+ fputs("\033*b1Y", prn_stream);
+ num_blank_lines--;
+ }
+ if ( cmodes == mode_3ns )
+ {
+ for ( ; num_blank_lines; num_blank_lines-- )
+ fputs("\033*b0W", prn_stream);
+ }
+ else
+ {
+ for ( ; num_blank_lines; num_blank_lines-- )
+ fputs("\033*bW", prn_stream);
+ }
+ }
+ else if ( cmodes == mode_0 ) /* PCL 3 */
+ { fprintf(prn_stream, "\033*p+%dY",
+ num_blank_lines * y_dots_per_pixel);
+ }
+ else
+ { fprintf(prn_stream, "\033*b%dY",
+ num_blank_lines);
+ }
+ /* Clear the seed row (only matters for */
+ /* mode 3 compression). */
+ memset(prev_row, 0, line_size);
+ }
+ num_blank_lines = 0;
+
+ /* Choose the best compression mode */
+ /* for this particular line. */
+ switch (cmodes)
+ {
+ case mode_3:
+ case mode_3ns:
+ { /* Compression modes 2 and 3 are both */
+ /* available. Try both and see which one */
+ /* produces the least output data. */
+ int count3 = gdev_pcl_mode3compress(line_size, data,
+ prev_row, out_row);
+ int count2 = gdev_pcl_mode2compress(data_words, end_data,
+ out_row_alt);
+ int penalty3 =
+ (compression == 3 ? 0 : penalty_from2to3);
+ int penalty2 =
+ (compression == 2 ? 0 : penalty_from3to2);
+ if ( count3 + penalty3 < count2 + penalty2)
+ { if ( compression != 3 )
+ fputs(from2to3, prn_stream);
+ compression = 3;
+ out_data = out_row;
+ out_count = count3;
+ }
+ else
+ { if ( compression != 2 )
+ fputs(from3to2, prn_stream);
+ compression = 2;
+ out_data = out_row_alt;
+ out_count = count2;
+ }
+ break;
+ }
+ case mode_2:
+ case mode_2p:
+ out_data = out_row;
+ out_count = gdev_pcl_mode2compress(data_words, end_data,
+ out_row);
+ break;
+ default:
+ out_data = data;
+ out_count = (byte *)end_data - data;
+ }
+
+ /* Transfer the data */
+ fprintf(prn_stream, "\033*b%dW", out_count);
+ fwrite(out_data, sizeof(byte), out_count,
+ prn_stream);
+ }
+ }
+
+ /* end raster graphics and eject page */
+ fputs("\033*rB\f", prn_stream);
+
+ /* free temporary storage */
+ gs_free((char *)storage, storage_size_words, W, "hpjet_print_page");
+
+ return code;
+}
diff --git a/gs/src/gdevdjtc.c b/gs/src/gdevdjtc.c
new file mode 100644
index 000000000..f744597b0
--- /dev/null
+++ b/gs/src/gdevdjtc.c
@@ -0,0 +1,276 @@
+/* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevdjtc.c */
+/* HP DeskJet 500C driver */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+#include "malloc_.h"
+
+/***
+ *** Note: this driver was contributed by a user, Alfred Kayser:
+ *** please contact AKayser@et.tudelft.nl if you have questions.
+ ***/
+
+#ifndef SHINGLING /* Interlaced, multi-pass printing */
+#define SHINGLING 1 /* 0 = none, 1 = 50%, 2 = 25%, 2 is best & slowest */
+#endif
+
+#ifndef DEPLETION /* 'Intelligent' dot-removal */
+#define DEPLETION 1 /* 0 = none, 1 = 25%, 2 = 50%, 1 best for graphics? */
+#endif /* Use 0 for transparencies */
+
+#define X_DPI 300
+#define Y_DPI 300
+/* bytes per line for DeskJet Color */
+#define LINE_SIZE ((X_DPI * 85 / 10 + 63) / 64 * 8)
+
+/* The device descriptors */
+private dev_proc_print_page(djet500c_print_page);
+
+private gx_device_procs djet500c_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
+
+gx_device_printer far_data gs_djet500c_device =
+ prn_device(djet500c_procs, "djet500c",
+ 85, /* width_10ths, 8.5" */
+ 120, /* height_10ths, 12" */
+ X_DPI, Y_DPI,
+ 0.25, 0.25, 0.25, 0.25, /* margins */
+ 3, djet500c_print_page);
+
+/* Forward references */
+private int djet500c_print_page(P2(gx_device_printer *, FILE *));
+
+static int mode2compress(P3(byte *row, byte *end_row, byte *compressed));
+
+/* The DeskJet 500C uses additive colors in separate planes. */
+/* We only keep one bit of color, with 1 = R, 2 = G, 4 = B. */
+/* Because the buffering routines assume 0 = white, */
+/* we complement all the color components. */
+
+/* Send the page to the printer. For speed, compress each scan line, */
+/* since computer-to-printer communication time is often a bottleneck. */
+/* The DeskJet Color can compress (mode 2) */
+
+private int
+djet500c_print_page(gx_device_printer *pdev, FILE *fprn)
+{
+ byte *bitData=NULL;
+ byte *plane1=NULL;
+ byte *plane2=NULL;
+ byte *plane3=NULL;
+ int bitSize=0;
+ int planeSize=0;
+
+ /* select the most compressed mode available & clear tmp storage */
+ /* put printer in known state */
+ fputs("\033E",fprn);
+
+ /* ends raster graphics to set raster graphics resolution */
+ fputs("\033*rbC", fprn); /* was \033*rB */
+
+ /* set raster graphics resolution -- 300 dpi */
+ fputs("\033*t300R", fprn);
+
+ /* A4, skip perf, def. paper tray */
+ fputs("\033&l26a0l1H", fprn);
+
+ /* RGB Mode */
+ fputs("\033*r3U", fprn);
+
+ /* set depletion level */
+ fprintf(fprn, "\033*o%dD", DEPLETION);
+
+ /* set shingling level */
+ fprintf(fprn, "\033*o%dQ", SHINGLING);
+
+ /* move to top left of page & set current position */
+ fputs("\033*p0x0Y", fprn); /* cursor pos: 0,0 */
+
+ fputs("\033*b2M", fprn); /* mode 2 compression for now */
+
+ fputs("\033*r0A", fprn); /* start graf. left */
+
+ /* Send each scan line in turn */
+ { int lnum;
+ int num_blank_lines = 0;
+ int lineSize = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ if (lineSize>bitSize)
+ {
+ if (bitData) free(bitData);
+ bitSize=lineSize;
+ bitData=(byte*)malloc(bitSize+16);
+ }
+ for (lnum=0; lnum<pdev->height; lnum++)
+ {
+ byte *endData;
+
+ gdev_prn_copy_scan_lines(pdev, lnum, bitData, lineSize);
+
+ /* Remove trailing 0s. */
+ endData = bitData + lineSize;
+ while ( (endData>bitData) && (endData[-1] == 0) )
+ endData--;
+ if (endData == bitData)
+ num_blank_lines++;
+ else
+ { int count, k, i, lineLen;
+
+ /* Pad with 0s to fill out the last */
+ /* block of 8 bytes. */
+ memset(endData, 0, 7);
+
+ lineLen=((endData-bitData)+7)/8; /* Round to next 8multiple */
+ if (planeSize<lineLen)
+ {
+ if (plane1) free(plane1);
+ if (plane2) free(plane2);
+ if (plane3) free(plane3);
+ planeSize=lineLen;
+ plane1=(byte*)malloc(planeSize+8);
+ plane2=(byte*)malloc(planeSize+8);
+ plane3=(byte*)malloc(planeSize+8);
+ }
+ /* Transpose the data to get pixel planes. */
+ for (k=i=0; k<lineLen; i+=8, k++)
+ {
+ register ushort t, c;
+
+ /* Three smaller loops are better optimizable and use less
+ vars, so most of them can be in registers even on pc's */
+ for (c=t=0;t<8;t++)
+ c = (c<<1) | (bitData[t+i]&4);
+ plane3[k] = ~(byte)(c>>2);
+ for (c=t=0;t<8;t++)
+ c = (c<<1) | (bitData[t+i]&2);
+ plane2[k] = ~(byte)(c>>1);
+ for (c=t=0;t<8;t++)
+ c = (c<<1) | (bitData[t+i]&1);
+ plane1[k] = ~(byte)(c);
+ }
+
+ /* Skip blank lines if any */
+ if (num_blank_lines > 0)
+ { /* move down from current position */
+ fprintf(fprn, "\033*b%dY", num_blank_lines);
+ num_blank_lines = 0;
+ }
+
+ /* Transfer raster graphics */
+ /* in the order R, G, B. */
+ /* lineLen is at least bitSize/8, so bitData can easily be used to store
+ lineLen of bytes */
+ /* P.s. mode9 compression is akward(??) to use, because the lineLenght's
+ are different, so we are stuck with mode 2, which is good enough */
+
+ /* set the line width */
+ fprintf(fprn, "\033*r%dS", lineLen*8);
+
+ count = mode2compress(plane1, plane1 + lineLen, bitData);
+ fprintf(fprn, "\033*b%dV", count);
+ fwrite(bitData, sizeof(byte), count, fprn);
+ count = mode2compress(plane2, plane2 + lineLen, bitData);
+ fprintf(fprn, "\033*b%dV", count);
+ fwrite(bitData, sizeof(byte), count, fprn);
+ count = mode2compress(plane3, plane3 + lineLen, bitData);
+ fprintf(fprn, "\033*b%dW", count);
+ fwrite(bitData, sizeof(byte), count, fprn);
+ }
+ }
+ }
+ /* end raster graphics */
+ fputs("\033*rbC", fprn); /* was \033*rB */
+ fputs("\033*r1U", fprn); /* back to 1 plane */
+
+ /* put printer in known state */
+ fputs("\033E",fprn);
+
+ /* eject page */
+ fputs("\033&l0H", fprn);
+
+ /* release allocated memory */
+ if (bitData) free(bitData);
+ if (plane1) free(plane1);
+ if (plane2) free(plane2);
+ if (plane3) free(plane3);
+
+ return 0;
+}
+
+
+/*
+ * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
+ * Compresses data from row up to end_row, storing the result
+ * starting at compressed. Returns the number of bytes stored.
+ * Runs of K<=127 literal bytes are encoded as K-1 followed by
+ * the bytes; runs of 2<=K<=127 identical bytes are encoded as
+ * 257-K followed by the byte.
+ * In the worst case, the result is N+(N/127)+1 bytes long,
+ * where N is the original byte count (end_row - row).
+ * I can't use the general pcl version, because it assume even linelength's
+ */
+
+static int
+mode2compress(byte *row, byte *end_row, byte *compressed)
+{
+ register byte *exam; /* word being examined in the row to compress */
+ register byte *cptr = compressed; /* output pointer into compressed bytes */
+ int i, count, len;
+ byte test;
+
+ exam = row;
+ while (1)
+ {
+ test = *exam++;
+ /* Advance exam until test==*exam or exam==end_row */
+ while ((test != *exam) && (exam < end_row))
+ test = *exam++;
+ /* row points to start of differing bytes,
+ exam points to start of consequtive series
+ or to end of row */
+ if (exam<end_row) exam--;
+ len=exam-row;
+ while (len>0)
+ {
+ count=len;
+ if (count>127) count=127;
+ *cptr++=count-1;
+ for (i=0;i<count;i++) *cptr++ = *row++;
+ len-=count;
+ }
+ if (exam>=end_row) break; /* done */
+ exam++; /* skip first same byte */
+ while ((test == *exam) && (exam < end_row)) /* skip all same bytes */
+ exam++;
+ /* exam points now first different word or to end of data */
+ len = exam-row;
+ while (len>0)
+ {
+ count=len;
+ if (count>127) count=127;
+ *cptr++=(257-count);
+ *cptr++=test;
+ len-=count;
+ }
+ if (exam>=end_row) break; /* end of data */
+ row = exam; /* row points to first dissimular byte */
+ }
+ return (cptr-compressed);
+}
diff --git a/gs/src/gdevdm24.c b/gs/src/gdevdm24.c
new file mode 100644
index 000000000..2ae646d2c
--- /dev/null
+++ b/gs/src/gdevdm24.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+#include "gdevprn.h"
+
+
+/* gdevdm24.c */
+/* High-res 24Dot-matrix printer driver */
+
+/* Supported printers
+ * NEC P6 and similar, implemented by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ * Epson LQ850, implemented by Christian Felsch (felsch@tu-harburg.d400.de)
+ */
+
+/* Driver for NEC P6 */
+private dev_proc_print_page (necp6_print_page);
+gx_device_printer far_data gs_necp6_device =
+ prn_device (prn_std_procs, "necp6",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ 360, 360,
+ 0, 0, 0.5, 0, /* margins */
+ 1, necp6_print_page);
+
+
+/* Driver for Epson LQ850 */
+/* I've tested this driver on a BJ300 with LQ850 emulation and there it produce correct 360x360dpi output. */
+private dev_proc_print_page (lq850_print_page);
+gx_device_printer gs_lq850_device =
+ prn_device (prn_std_procs, "lq850",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ 360, 360,
+ 0, 0, 0.5, 0, /* margins */
+ 1, lq850_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Forward references */
+private void dot24_output_run (P4 (byte *, int, int, FILE *));
+private void dot24_improve_bitmap (P2 (byte *, int));
+
+/* Send the page to the printer. */
+private int
+dot24_print_page (gx_device_printer *pdev, FILE *prn_stream, char *init_string, int init_len)
+{
+ int xres = pdev->x_pixels_per_inch;
+ int yres = pdev->y_pixels_per_inch;
+ int x_high = (xres == 360);
+ int y_high = (yres == 360);
+ int bits_per_column = (y_high ? 48 : 24);
+ uint line_size = gdev_prn_raster (pdev);
+ uint in_size = line_size * bits_per_column;
+ byte *in = (byte *) gs_malloc (in_size, 1, "dot24_print_page (in)");
+ uint out_size = ((pdev->width + 7) & -8) * 3;
+ byte *out = (byte *) gs_malloc (out_size, 1, "dot24_print_page (out)");
+ int y_passes = (y_high ? 2 : 1);
+ int dots_per_space = xres / 10; /* pica space = 1/10" */
+ int bytes_per_space = dots_per_space * 3;
+ int skip = 0, lnum = 0, ypass;
+
+ /* Check allocations */
+ if (in == 0 || out == 0)
+ {
+ if (out)
+ gs_free ((char *) out, out_size, 1, "dot24_print_page (out)");
+ if (in)
+ gs_free ((char *) in, in_size, 1, "dot24_print_page (in)");
+ return_error (gs_error_VMerror);
+ }
+
+ /* Initialize the printer and reset the margins. */
+ fwrite (init_string, init_len - 1, sizeof (char), prn_stream);
+ fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2,
+ prn_stream);
+
+ /* Print lines of graphics */
+ while (lnum < pdev->height)
+ {
+ byte *inp;
+ byte *in_end;
+ byte *out_end;
+ byte *out_blk;
+ register byte *outp;
+ int lcnt;
+
+ /* Copy 1 scan line and test for all zero. */
+ gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
+ if (in[0] == 0
+ && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
+ {
+ lnum++;
+ skip += 2 - y_high;
+ continue;
+ }
+
+ /* Vertical tab to the appropriate position. */
+ while ((skip >> 1) > 255)
+ {
+ fputs ("\033J\377", prn_stream);
+ skip -= 255 * 2;
+ }
+
+ if (skip)
+ {
+ if (skip >> 1)
+ fprintf (prn_stream, "\033J%c", skip >> 1);
+ if (skip & 1)
+ fputc ('\n', prn_stream);
+ }
+
+ /* Copy the rest of the scan lines. */
+ if (y_high)
+ {
+ inp = in + line_size;
+ for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
+ if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
+ line_size))
+ {
+ memset (inp, 0, (24 - lcnt) * line_size);
+ break;
+ }
+ inp = in + line_size * 24;
+ for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
+ if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
+ line_size))
+ {
+ memset (inp, 0, (24 - lcnt) * line_size);
+ break;
+ }
+ }
+ else
+ {
+ lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
+ in_size - line_size);
+ if (lcnt < 24)
+ /* Pad with lines of zeros. */
+ memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
+ }
+
+ for (ypass = 0; ypass < y_passes; ypass++)
+ {
+ out_end = out;
+ inp = in;
+ if (ypass)
+ inp += line_size * 24;
+ in_end = inp + line_size;
+
+ for (; inp < in_end; inp++, out_end += 24)
+ {
+ memflip8x8 (inp, line_size, out_end, 3);
+ memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3);
+ memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3);
+ }
+ /* Remove trailing 0s. */
+ while (out_end - 3 >= out && out_end[-1] == 0
+ && out_end[-2] == 0 && out_end[-3] == 0)
+ out_end -= 3;
+
+ for (out_blk = outp = out; outp < out_end;)
+ {
+ /* Skip a run of leading 0s. */
+ /* At least 10 are needed to make tabbing worth it. */
+
+ if (outp[0] == 0 && outp + 12 <= out_end
+ && outp[1] == 0 && outp[2] == 0
+ && outp[3] == 0 && outp[4] == 0 && outp[5] == 0
+ && outp[6] == 0 && outp[7] == 0 && outp[8] == 0
+ && outp[9] == 0 && outp[10] == 0 && outp[11] == 0)
+ {
+ byte *zp = outp;
+ int tpos;
+ byte *newp;
+ outp += 12;
+ while (outp + 3 <= out_end
+ && outp[0] == 0 && outp[1] == 0 && outp[2] == 0)
+ outp += 3;
+ tpos = (outp - out) / bytes_per_space;
+ newp = out + tpos * bytes_per_space;
+ if (newp > zp + 10)
+ {
+ /* Output preceding bit data. */
+ /* only false at beginning of line */
+ if (zp > out_blk)
+ {
+ if (x_high)
+ dot24_improve_bitmap (out_blk, (int) (zp - out_blk));
+ dot24_output_run (out_blk, (int) (zp - out_blk),
+ x_high, prn_stream);
+ }
+ /* Tab over to the appropriate position. */
+ fprintf (prn_stream, "\033D%c%c\t", tpos, 0);
+ out_blk = outp = newp;
+ }
+ }
+ else
+ outp += 3;
+ }
+ if (outp > out_blk)
+ {
+ if (x_high)
+ dot24_improve_bitmap (out_blk, (int) (outp - out_blk));
+ dot24_output_run (out_blk, (int) (outp - out_blk), x_high,
+ prn_stream);
+ }
+
+ fputc ('\r', prn_stream);
+ if (ypass < y_passes - 1)
+ fputc ('\n', prn_stream);
+ }
+ skip = 48 - y_high;
+ lnum += bits_per_column;
+ }
+
+ /* Eject the page and reinitialize the printer */
+ fputs ("\f\033@", prn_stream);
+ fflush (prn_stream);
+
+ gs_free ((char *) out, out_size, 1, "dot24_print_page (out)");
+ gs_free ((char *) in, in_size, 1, "dot24_print_page (in)");
+
+ return 0;
+}
+
+/* Output a single graphics command. */
+private void
+dot24_output_run (byte *data, int count, int x_high, FILE *prn_stream)
+{
+ int xcount = count / 3;
+ fputc (033, prn_stream);
+ fputc ('*', prn_stream);
+ fputc ((x_high ? 40 : 39), prn_stream);
+ fputc (xcount & 0xff, prn_stream);
+ fputc (xcount >> 8, prn_stream);
+ fwrite (data, 1, count, prn_stream);
+}
+
+/* If xdpi == 360, the P6 / LQ850 cannot print adjacent pixels. Clear the
+ second last pixel of every run of set pixels, so that the last pixel
+ is always printed. */
+private void
+dot24_improve_bitmap (byte *data, int count)
+{
+ int i;
+ register byte *p = data + 6;
+
+ for (i = 6; i < count; i += 3, p += 3)
+ {
+ p[-6] &= ~(~p[0] & p[-3]);
+ p[-5] &= ~(~p[1] & p[-2]);
+ p[-4] &= ~(~p[2] & p[-1]);
+ }
+ p[-6] &= ~p[-3];
+ p[-5] &= ~p[-2];
+ p[-4] &= ~p[-1];
+
+}
+
+
+private int
+necp6_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ char necp6_init_string [] = "\033@\033P\033l\000\r\034\063\001\033Q";
+
+ return dot24_print_page(pdev, prn_stream, necp6_init_string, sizeof(necp6_init_string));
+}
+
+
+private int
+lq850_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ char lq850_init_string [] = "\033@\033P\033l\000\r\033\053\001\033Q";
+
+ return dot24_print_page(pdev, prn_stream, lq850_init_string, sizeof(lq850_init_string));
+}
+
diff --git a/gs/src/gdevegaa.asm b/gs/src/gdevegaa.asm
new file mode 100644
index 000000000..d2de0e365
--- /dev/null
+++ b/gs/src/gdevegaa.asm
@@ -0,0 +1,277 @@
+; Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
+;
+; This file is part of Aladdin Ghostscript.
+;
+; Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+; or distributor accepts any responsibility for the consequences of using it,
+; or for whether it serves any particular purpose or works at all, unless he
+; or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+; License (the "License") for full details.
+;
+; Every copy of Aladdin Ghostscript must include a copy of the License,
+; normally in a plain ASCII text file named PUBLIC. The License grants you
+; the right to copy, modify and redistribute Aladdin Ghostscript, but only
+; under certain conditions described in the License. Among other things, the
+; License requires that the copyright notice and this notice be preserved on
+; all copies.
+
+; gdevegaasm.asm
+; Assembly code for Ghostscript PC frame buffer driver
+
+gdevegaasm_TEXT SEGMENT BYTE PUBLIC 'CODE'
+ ASSUME CS:gdevegaasm_TEXT
+
+; Note: Turbo C uses si and di for register variables, so
+; we have to preserve them.
+
+; Normal entry and exit. Arguments are relative to bp.
+enterp macro
+ push bp
+ mov bp,sp
+ x = 6 ; offset of arguments,
+ ; large code model
+ endm
+leavep macro
+ pop bp
+ endm
+; Fast entry and exit, for procedures that don't use bx until
+; they've fetched all their arguments. Arguments are relative to ss:bx.
+enterf macro
+ mov bx,sp
+ x = 4 ; offset of arguments,
+ ; large code model
+ endm
+leavef macro
+ endm
+
+; Fast call to VESA set-page routine.
+; void vesa_call_set_page(void (*set_page_proc)(int), int page_no, int win_no)
+ PUBLIC _vesa_call_set_page
+_vesa_call_set_page proc far
+ enterf
+ mov ax,4f05h
+ mov dx,ss:[bx+x+4] ; page_no
+ push ss:[bx+x+2] ; set_page_proc
+ push ss:[bx+x]
+ mov bx,ss:[bx+x+6] ; win_no
+ ret
+_vesa_call_set_page endp
+
+; Structure for operation parameters.
+; Note that this structure is shared with C code.
+; Not all parameters are used for every operation.
+; typedef struct rop_params_s {
+p_dest equ 0 ; fb_ptr dest; /* pointer to frame buffer */
+p_draster equ 4 ; int draster; /* raster of frame buffer */
+p_src equ 6 ; const byte far *src; /* pointer to source data */
+p_sraster equ 10 ; int sraster; /* source raster */
+p_width equ 12 ; int width; /* width in bytes */
+p_height equ 14 ; int height; /* height in scan lines */
+p_shift equ 16 ; int shift; /* amount to right shift source */
+p_invert equ 18 ; int invert; /* 0 or -1 to invert source */
+p_data equ 20 ; int data; /* data for fill */
+; } rop_params;
+
+; void memsetcol(rop_params _ss *rop)
+; { byte far *addr = rop->dest;
+; int yc = rop->height;
+; while ( yc-- )
+; { byte discard = *addr;
+; *addr = rop->data;
+; addr += rop->draster;
+; }
+; }
+ PUBLIC _memsetcol
+_memsetcol proc far
+ enterf
+ push ds
+ mov ax,ss
+ mov ds,ax
+ mov bx,[bx+x] ; rop
+ mov cx,[bx].p_height
+ jcxz msc0 ; height == 0
+ mov ax,[bx].p_data
+ mov dx,[bx].p_draster
+ lds bx,[bx].p_dest
+; Unroll the loop -- two copies.
+ inc cx ;round up to nearest word. cx>=2 now.
+ shr cx,1 ;make byte count into word count.
+ jnc msc2 ;if it had been odd, do a half word first.
+msc1: mov ah,[bx]
+ mov [bx],al
+ add bx,dx
+msc2: mov ah,[bx]
+ mov [bx],al
+ add bx,dx
+ loop msc1
+ pop ds
+msc0: leavef
+ ret
+_memsetcol ENDP
+
+; void memsetrect(rop_params _ss *rop)
+; { byte far *addr = rop->dest;
+; int yc = rop->height;
+; while ( yc-- )
+; { int cnt = rop->width;
+; while ( cnt-- ) *addr++ = rop->data;
+; addr += rop->drast - rop->width;
+; }
+; }
+ PUBLIC _memsetrect
+_memsetrect proc far
+ enterf
+ push ds
+ mov ax,ss
+ mov ds,ax
+ mov bx,[bx+x] ; rop
+ mov cx,[bx].p_height
+ jcxz msr0 ; height == 0
+ push si
+ push di
+ mov ax,[bx].p_data
+ les di,[bx].p_dest
+ cld
+ mov dx,[bx].p_draster
+ mov si,cx ; si = height
+ mov cx,[bx].p_width
+ sub dx,cx
+ cmp cx,10
+ ja msrl ; large count, use fast loop
+; Small count, rep stosb is faster.
+msrs: mov cx,[bx].p_width
+ rep stosb
+ add di,dx
+ dec si ; count reps
+ jnz msrs
+ pop di
+ pop si
+msr0: pop ds
+ leavef
+ ret
+; Large count, loop by words rather than bytes.
+msrl: mov ah,al ;we may be storing words...
+msr1: mov cx,[bx].p_width
+ test di,1 ;test for an even address
+ je msr2 ;if even, we can store words.
+ stosb ;otherwise we need to even it out.
+ dec cx ;(cx is at least one here)
+msr2: shr cx,1 ;convert byte count into word count
+ rep stosw ;store them puppies as fast as we can.
+ jnc msr3 ;if an odd number, store it, too.
+ stosb ;(no need to dec cx here).
+msr3: add di,dx
+ dec si ; count reps
+ jnz msr1
+ pop di
+ pop si
+ pop ds
+ leavef
+ ret
+_memsetrect ENDP
+
+; void memrwcol(rop_params _ss *rop)
+; { byte far *dp = rop->dest;
+; const byte far *sp = rop->src;
+; int yc = rop->height;
+; int shift = rop->shift;
+; while ( yc-- )
+; { byte discard = *dp;
+; *dp = ((*sp >> shift) + (*sp << (8 - shift))) ^ rop->invert;
+; dp += rop->draster, sp += rop->sraster;
+; }
+; }
+ PUBLIC _memrwcol
+_memrwcol proc far
+ enterp
+ push ds
+ mov ax,ss
+ mov ds,ax
+ mov bx,[bp+x] ; rop
+ cmp word ptr [bx].p_height,0
+ jz short mrw0
+ push si
+ push di
+; Register usage:
+; ds:si = sp, es:di = dp, bx = sraster, dx = draster, cl = shift,
+; ch = invert, ah = low byte of yc.
+ push [bx].p_height
+ mov dx,[bx].p_draster
+ mov ax,[bx].p_sraster
+ mov cl,[bx].p_shift
+ mov ch,[bx].p_invert
+ les di,[bx].p_dest
+ lds si,[bx].p_src
+ mov bx,ax
+ mov ah,[bp-8] ; low byte of yc
+ test ah,ah
+ jz mrw2
+mrw1: mov al,[si]
+ ror al,cl
+ xor al,ch
+ xchg es:[di],al
+ add si,bx
+ add di,dx
+ dec ah
+ jnz mrw1
+mrw2: dec byte ptr [bp-7] ; high byte of yc
+ jge mrw1
+ add sp,2 ; pop yc
+ pop di
+ pop si
+mrw0: pop ds
+ leavep
+ ret
+_memrwcol ENDP
+
+; void memrwcol2(rop_params _ss *rop)
+; { byte far *dp = rop->dest;
+; const byte far *sp = rop->src;
+; int yc = rop->height;
+; int shift = rop->shift;
+; while ( yc-- )
+; { byte discard = *dp;
+; *dp = ((sp[1] >> shift) + (*sp << (8 - shift))) ^ rop->invert;
+; dp += rop->draster, sp += rop->sraster;
+; }
+; }
+ PUBLIC _memrwcol2
+_memrwcol2 proc far
+ enterp
+ push ds
+ mov ax,ss
+ mov ds,ax
+ mov bx,[bp+x] ; rop
+ cmp word ptr [bx].p_height,0
+ jz short mrw20
+ push si
+ push di
+; Register usage:
+; ds:si = sp, es:di = dp, bx = sraster, dx = draster, cl = shift,
+; ch = invert.
+ push [bx].p_height
+ mov dx,[bx].p_draster
+ mov ax,[bx].p_sraster
+ mov cl,[bx].p_shift
+ mov ch,[bx].p_invert
+ les di,[bx].p_dest
+ lds si,[bx].p_src
+ mov bx,ax
+mrw21: mov ax,[si] ; bytes are in wrong order...
+ ror ax,cl
+ xor ah,ch ; ... so result is in ah
+ xchg es:[di],ah
+ add si,bx
+ add di,dx
+ dec word ptr [bp-8] ; yc
+ jg mrw21
+ add sp,2 ; pop yc
+ pop di
+ pop si
+mrw20: pop ds
+ leavep
+ ret
+_memrwcol2 ENDP
+
+gdevegaasm_TEXT ENDS
+ END
diff --git a/gs/src/gdevemap.c b/gs/src/gdevemap.c
new file mode 100644
index 000000000..9b838d030
--- /dev/null
+++ b/gs/src/gdevemap.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevemap.c */
+/* Mappings between StandardEncoding and ISOLatin1Encoding */
+#include "std.h"
+
+const byte far_data gs_map_std_to_iso[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 173, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 161, 162, 163, 0, 165, 0, 167, 164, 0, 0, 171, 0, 0, 0, 0,
+ 0, 0, 0, 0, 183, 0, 182, 0, 0, 0, 0, 187, 0, 0, 0, 191,
+ 0, 145, 180, 147, 148, 175, 150, 151, 168, 0, 154, 184, 0, 157, 158, 159,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 198, 0, 170, 0, 0, 0, 0, 0, 216, 0, 186, 0, 0, 0, 0,
+ 0, 230, 0, 0, 0, 144, 0, 0, 0, 248, 0, 223, 0, 0, 0, 0
+};
+
+const byte far_data gs_map_iso_to_std[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 245, 193, 194, 195, 196, 197, 198, 199, 200, 0, 202, 203, 0, 205, 206, 207,
+ 32, 161, 162, 163, 168, 165, 0, 167, 200, 0, 227, 171, 0, 45, 0, 197,
+ 0, 0, 0, 0, 194, 0, 182, 180, 203, 0, 235, 187, 0, 0, 0, 191,
+ 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 251,
+ 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0
+};
diff --git a/gs/src/gdevepsc.c b/gs/src/gdevepsc.c
new file mode 100644
index 000000000..a3a0af026
--- /dev/null
+++ b/gs/src/gdevepsc.c
@@ -0,0 +1,458 @@
+/* Copyright (C) 1989, 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevepsc.c */
+/* Epson color dot-matrix printer driver by dave@exlog.com */
+#include "gdevprn.h"
+
+/*
+ * For 9-pin printers, you may select
+ * X_DPI = 60, 120, or 240
+ * Y_DPI = 60 or 72
+ * For 24-pin printers, you may select
+ * X_DPI = 60, 120, 180, 240, or 360
+ * Y_DPI = 60, 72, 180, or 216
+ * Note that a given printer implements *either* Y_DPI = 60 | 180 *or*
+ * Y_DPI = 72 | 216; no attempt is made to check this here.
+ * Note that X_DPI = 180 or 360 requires Y_DPI > 100;
+ * this isn't checked either. Finally, note that X_DPI=240 and
+ * X_DPI=360 are double-density modes requiring two passes to print.
+ *
+ * The values of X_DPI and Y_DPI may be set at compile time:
+ * see gdevs.mak.
+ *
+ * At some time in the future, we could simulate 24-bit output on
+ * 9-pin printers by using fractional vertical positioning;
+ * we could even implement an X_DPI=360 mode by using the
+ * ESC++ command that spaces vertically in units of 1/360"
+ * (not supported on many printers.)
+ */
+
+#ifndef X_DPI
+# define X_DPI 180 /* pixels per inch */
+#endif
+#ifndef Y_DPI
+# define Y_DPI 180 /* pixels per inch */
+#endif
+
+/*
+** Colors for EPSON LQ-2550.
+**
+** We map VIOLET to BLUE since this is the best we can do.
+*/
+#define BLACK 0
+#define MAGENTA 1
+#define CYAN 2
+#define VIOLET 3
+#define YELLOW 4
+#define RED 5
+#define GREEN 6
+#define WHITE 7
+
+/*
+** The offset in this array correspond to
+** the ESC-r n value
+*/
+static char rgb_color[2][2][2] = {
+ BLACK, VIOLET, GREEN,
+ CYAN, RED, MAGENTA,
+ YELLOW, WHITE,
+ };
+
+/* Map an RGB color to a printer color. */
+#define cv_shift (sizeof(gx_color_value) * 8 - 1)
+private gx_color_index
+epson_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+if (gx_device_has_color(dev))
+ {
+/* use ^7 so WHITE is 0 for internal calculations */
+ return (gx_color_index)rgb_color[r >> cv_shift][g >> cv_shift][b >> cv_shift] ^ 7;
+ }
+else
+ {
+ return gx_default_map_rgb_color(dev, r, g, b);
+ }
+}
+
+/* Map the printer color back to RGB. */
+private int
+epson_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+#define c1 gx_max_color_value
+if (gx_device_has_color(dev))
+ switch ((ushort)color ^ 7)
+ {
+ case BLACK:
+ prgb[0] = 0; prgb[1] = 0; prgb[2] = 0; break;
+ case VIOLET:
+ prgb[0] = 0; prgb[1] = 0; prgb[2] = c1; break;
+ case GREEN:
+ prgb[0] = 0; prgb[1] = c1; prgb[2] = 0; break;
+ case CYAN:
+ prgb[0] = 0; prgb[1] = c1; prgb[2] = c1; break;
+ case RED:
+ prgb[0] = c1; prgb[1] = 0; prgb[2] = 0; break;
+ case MAGENTA:
+ prgb[0] = c1; prgb[1] = 0; prgb[2] = c1; break;
+ case YELLOW:
+ prgb[0] = c1; prgb[1] = c1; prgb[2] = 0; break;
+ case WHITE:
+ prgb[0] = c1; prgb[1] = c1; prgb[2] = c1; break;
+ }
+ else
+ return gx_default_map_color_rgb(dev, color, prgb);
+ return 0;
+}
+
+/* The device descriptor */
+private dev_proc_print_page(epsc_print_page);
+
+private gx_device_procs epson_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ epson_map_rgb_color, epson_map_color_rgb);
+
+gx_device_printer far_data gs_epsonc_device =
+ prn_device(epson_procs, "epsonc",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0.25, 0, /* margins */
+ 3, epsc_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Forward references */
+private void epsc_output_run(P6(byte *, int, int, char, FILE *, int));
+
+/* Send the page to the printer. */
+#define DD 0x80 /* double density flag */
+private int
+epsc_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ static char graphics_modes_9[5] =
+ { -1, 0 /*60*/, 1 /*120*/, -1, DD+3 /*240*/
+ };
+ static char graphics_modes_24[7] =
+ { -1, 32 /*60*/, 33 /*120*/, 39 /*180*/,
+ -1, -1, DD+40 /*360*/
+ };
+ int y_24pin = pdev->y_pixels_per_inch > 72;
+ int y_mult = (y_24pin ? 3 : 1);
+ int line_size = (pdev->width + 7) >> 3; /* always mono */
+ int in_size = line_size * (8 * y_mult);
+ byte *in = (byte *)gs_malloc(in_size+1, 1, "epsc_print_page(in)");
+ int out_size = ((pdev->width + 7) & -8) * y_mult;
+ byte *out = (byte *)gs_malloc(out_size+1, 1, "epsc_print_page(out)");
+ int x_dpi = pdev->x_pixels_per_inch;
+ char start_graphics =
+ (y_24pin ? graphics_modes_24 : graphics_modes_9)[x_dpi / 60];
+ int first_pass = (start_graphics & DD ? 1 : 0);
+ int last_pass = first_pass * 2;
+ int dots_per_space = x_dpi / 10; /* pica space = 1/10" */
+ int bytes_per_space = dots_per_space * y_mult;
+ int skip = 0, lnum = 0, pass;
+/* declare color buffer and related vars */
+ byte *color_in;
+ int color_line_size, color_in_size;
+ int spare_bits = (pdev->width % 8); /* left over bits to go to margin */
+ int whole_bits = pdev->width - spare_bits;
+
+ /* Check allocations */
+ if ( in == 0 || out == 0 )
+ { if ( in ) gs_free((char *)in, in_size+1, 1, "epsc_print_page(in)");
+ if ( out ) gs_free((char *)out, out_size+1, 1, "epsc_print_page(out)");
+ return -1;
+ }
+
+ /* Initialize the printer and reset the margins. */
+ fwrite("\033@\033P\033l\000\033Q\377\033U\001\r", 1, 14, prn_stream);
+
+/* Create color buffer */
+ if (gx_device_has_color(pdev))
+ {
+ color_line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ color_in_size = color_line_size * (8 * y_mult);
+ if((color_in = (byte *)gs_malloc(color_in_size+1, 1,
+ "epsc_print_page(color)")) == 0)
+ {
+ gs_free((char *)in, in_size+1, 1, "epsc_print_page(in)");
+ gs_free((char *)out, out_size+1, 1, "epsc_print_page(out)");
+ return(-1);
+ }
+ }
+ else
+ {
+ color_in = in;
+ color_in_size = in_size;
+ color_line_size = line_size;
+ }
+
+ /* Print lines of graphics */
+ while ( lnum < pdev->height )
+ {
+ int lcnt;
+ byte *nextcolor = NULL; /* position where next color appears */
+ byte *nextmono = NULL; /* position to map next color */
+
+ /* Copy 1 scan line and test for all zero. */
+ gdev_prn_copy_scan_lines(pdev, lnum, color_in, color_line_size);
+
+ if ( color_in[0] == 0 &&
+ !memcmp((char *)color_in, (char *)color_in + 1, color_line_size - 1)
+ )
+ { lnum++;
+ skip += 3 / y_mult;
+ continue;
+ }
+
+ /* Vertical tab to the appropriate position. */
+ while ( skip > 255 )
+ { fputs("\033J\377", prn_stream);
+ skip -= 255;
+ }
+ if ( skip )
+ fprintf(prn_stream, "\033J%c", skip);
+
+ /* Copy the rest of the scan lines. */
+ lcnt = 1 + gdev_prn_copy_scan_lines(pdev, lnum + 1,
+ color_in + color_line_size, color_in_size - color_line_size);
+
+ if ( lcnt < 8 * y_mult )
+ {
+ memset((char *)(color_in + lcnt * color_line_size), 0,
+ color_in_size - lcnt * color_line_size);
+ if (gx_device_has_color(pdev)) /* clear the work buffer */
+ memset((char *)(in + lcnt * line_size), 0,
+ in_size - lcnt * line_size);
+ }
+
+/*
+** We need to create a normal epson scan line from our color scan line
+** We do this by setting a bit in the "in" buffer if the pixel byte is set
+** to any color. We then search for any more pixels of that color, setting
+** "in" accordingly. If any other color is found, we save it for the next
+** pass. There may be up to 7 passes.
+** In the future, we should make the passes so as to maximize the
+** life of the color ribbon (i.e. go lightest to darkest).
+*/
+ do
+ {
+ byte *inp = in;
+ byte *in_end = in + line_size;
+ byte *out_end = out;
+ byte *out_blk;
+ register byte *outp;
+
+ if (gx_device_has_color(pdev))
+ {
+ register i,j;
+ register byte *outbuf, *realbuf;
+ byte current_color;
+ int end_next_bits = whole_bits;
+ int lastbits;
+
+/* Move to the point in the scanline that has a new color */
+ if (nextcolor)
+ {
+ realbuf = nextcolor;
+ outbuf = nextmono;
+ memset((char *)in, 0, (nextmono - in));
+ i = nextcolor - color_in;
+ nextcolor = NULL;
+ end_next_bits = (i / color_line_size) * color_line_size
+ + whole_bits;
+ }
+ else
+ {
+ i = 0;
+ realbuf = color_in;
+ outbuf = in;
+ nextcolor = NULL;
+ }
+/* move thru the color buffer, turning on the appropriate
+** bit in the "mono" buffer", setting pointers to the next
+** color and changing the color output of the epson
+*/
+ for (current_color = 0; i <= color_in_size && outbuf < in + in_size; outbuf++)
+ {
+/* Remember, line_size is rounded up to next whole byte
+** whereas color_line_size is the proper length
+** We only want to set the proper bits in the last line_size byte.
+*/
+ if (spare_bits && i == end_next_bits)
+ {
+ end_next_bits = whole_bits + i + spare_bits;
+ lastbits = 8 - spare_bits;
+ }
+ else
+ lastbits = 0;
+
+ for (*outbuf = 0, j = 8; --j >= lastbits && i <= color_in_size;
+ realbuf++,i++)
+ {
+ if (*realbuf)
+ {
+ if (current_color > 0)
+ {
+ if (*realbuf == current_color)
+ {
+ *outbuf |= 1 << j;
+ *realbuf = 0; /* throw this byte away */
+ }
+ /* save this location for next pass */
+ else if (nextcolor == NULL)
+ {
+ nextcolor = realbuf - (7 - j);
+ nextmono = outbuf;
+ }
+ }
+ else
+ {
+ *outbuf |= 1 << j;
+ current_color = *realbuf; /* set color */
+ *realbuf = 0;
+ }
+ }
+ }
+ }
+ *outbuf = 0; /* zero the end, for safe keeping */
+/* Change color on the EPSON, current_color must be set
+** but lets check anyway
+*/
+ if (current_color)
+ fprintf(prn_stream,"\033r%d",current_color ^ 7);
+ }
+
+ /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
+ /* because that's how the printer wants the data. */
+ /* If we are in a 24-pin mode, we have to transpose */
+ /* groups of 3 lines at a time. */
+
+ if ( y_24pin )
+ { for ( ; inp < in_end; inp++, out_end += 24 )
+ { gdev_prn_transpose_8x8(inp, line_size, out_end, 3);
+ gdev_prn_transpose_8x8(inp + line_size * 8, line_size, out_end + 1, 3);
+ gdev_prn_transpose_8x8(inp + line_size * 16, line_size, out_end + 2, 3);
+ }
+ /* Remove trailing 0s. */
+ while ( out_end > out && out_end[-1] == 0 &&
+ out_end[-2] == 0 && out_end[-3] == 0
+ )
+ out_end -= 3;
+ }
+ else
+ { for ( ; inp < in_end; inp++, out_end += 8 )
+ { gdev_prn_transpose_8x8(inp, line_size, out_end, 1);
+ }
+ /* Remove trailing 0s. */
+ while ( out_end > out && out_end[-1] == 0 )
+ out_end--;
+ }
+
+ for ( pass = first_pass; pass <= last_pass; pass++ )
+ {
+ for ( out_blk = outp = out; outp < out_end; )
+ { /* Skip a run of leading 0s. */
+ /* At least 10 are needed to make tabbing worth it. */
+ /* We do everything by 3's to avoid having to make */
+ /* different cases for 9- and 24-pin. */
+
+ if ( *outp == 0 && outp + 12 <= out_end &&
+ outp[1] == 0 && outp[2] == 0 &&
+ (outp[3] | outp[4] | outp[5]) == 0 &&
+ (outp[6] | outp[7] | outp[8]) == 0 &&
+ (outp[9] | outp[10] | outp[11]) == 0
+ )
+ { byte *zp = outp;
+ int tpos;
+ byte *newp;
+ outp += 12;
+ while ( outp + 3 <= out_end && *outp == 0 &&
+ outp[1] == 0 && outp[2] == 0
+ )
+ outp += 3;
+ tpos = (outp - out) / bytes_per_space;
+ newp = out + tpos * bytes_per_space;
+ if ( newp > zp + 10 )
+ { /* Output preceding bit data. */
+ if ( zp > out_blk ) /* only false at */
+ /* beginning of line */
+ epsc_output_run(out_blk, (int)(zp - out_blk),
+ y_mult, start_graphics,
+ prn_stream, pass);
+ /* Tab over to the appropriate position. */
+ fprintf(prn_stream, "\033D%c%c\t", tpos, 0);
+ out_blk = outp = newp;
+ }
+ }
+ else
+ outp += y_mult;
+ }
+ if ( outp > out_blk )
+ epsc_output_run(out_blk, (int)(outp - out_blk),
+ y_mult, start_graphics,
+ prn_stream, pass);
+
+ fputc('\r', prn_stream);
+ }
+ } while (nextcolor);
+ skip = 24;
+ lnum += 8 * y_mult;
+ }
+
+ /* Eject the page and reinitialize the printer */
+ fputs("\f\033@", prn_stream);
+
+
+ gs_free((char *)out, out_size+1, 1, "epsc_print_page(out)");
+ gs_free((char *)in, in_size+1, 1, "epsc_print_page(in)");
+ if (gx_device_has_color(pdev))
+ gs_free((char *)color_in, color_in_size+1, 1, "epsc_print_page(rin)");
+ return 0;
+}
+
+/* Output a single graphics command. */
+/* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
+private void
+epsc_output_run(byte *data, int count, int y_mult,
+ char start_graphics, FILE *prn_stream, int pass)
+{ int xcount = count / y_mult;
+ fputc(033, prn_stream);
+ if ( !(start_graphics & ~3) )
+ { fputc("KLYZ"[start_graphics], prn_stream);
+ }
+ else
+ { fputc('*', prn_stream);
+ fputc(start_graphics & ~DD, prn_stream);
+ }
+ fputc(xcount & 0xff, prn_stream);
+ fputc(xcount >> 8, prn_stream);
+ if ( !pass )
+ fwrite((char *)data, 1, count, prn_stream);
+ else
+ { /* Only write every other column of y_mult bytes. */
+ int which = pass;
+ byte *dp = data;
+ register int i, j;
+ for ( i = 0; i < xcount; i++, which++ )
+ for ( j = 0; j < y_mult; j++, dp++ )
+ { putc(((which & 1) ? *dp : 0), prn_stream);
+ }
+ }
+}
diff --git a/gs/src/gdevepsn.c b/gs/src/gdevepsn.c
new file mode 100644
index 000000000..65d7f08d2
--- /dev/null
+++ b/gs/src/gdevepsn.c
@@ -0,0 +1,497 @@
+/* Copyright (C) 1989-1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevepsn.c */
+/*
+ * Epson (and similar) dot-matrix printer driver for Ghostscript.
+ *
+ * Four devices are defined here: 'epson', 'eps9mid', 'eps9high', and 'ibmpro'.
+ * The 'epson' device is the generic device, for 9-pin and 24-pin printers.
+ * 'eps9high' is a special mode for 9-pin printers where scan lines are
+ * interleaved in multiple passes to produce high vertical resolution at
+ * the expense of several passes of the print head. 'eps9mid' is a special
+ * mode for 9 pin printers too, scan lines are interleaved but with next
+ * vertical line. 'ibmpro' is for the IBM ProPrinter, which has slightly
+ * (but only slightly) different control codes.
+ *
+ * Thanks to David Wexelblat (dwex@mtgzfs3.att.com) for the 'eps9high' code,
+ * to Guenther Thomsen (thomsen@cs.tu-berlin.de) for the 'eps9mid' code,
+ * and to James W. Birdsall (jwbirdsa@picarefy.picarefy.com) for the
+ * 'ibmpro' modifications.
+ */
+#include "gdevprn.h"
+
+/*
+ * Define whether the printer is archaic -- so old that it doesn't
+ * support settable tabs, pitch, or left margin. (This should be a
+ * run-time property....) Note: the IBM ProPrinter is archaic.
+ */
+/*#define ARCHAIC 1*/
+
+/*
+ * Define whether the printer is a Panasonic 9-pin printer,
+ * which sometimes doesn't recognize a horizontal tab command
+ * when a line contains a lot of graphics commands,
+ * requiring a "backspace, space" sequence before a tab.
+ */
+/*#define TAB_HICCUP 1*/
+
+/*
+ * Define the minimum distance for which it's worth converting white space
+ * into a tab. This can be specified in pixels (to save transmission time),
+ * in tenths of an inch (for printers where tabs provoke actual head motion),
+ * or both. The distance must meet BOTH criteria for the driver to tab,
+ * so an irrelevant criterion should be set to 0 rather than infinite.
+ */
+#define MIN_TAB_PIXELS 10
+#define MIN_TAB_10THS 15
+
+/*
+ * Valid values for X_DPI:
+ *
+ * For 9-pin printers: 60, 120, 240
+ * For 24-pin printers: 60, 120, 180, 240, 360
+ *
+ * The value specified at compile time is the default value used if the
+ * user does not specify a resolution at runtime.
+ */
+#ifndef X_DPI
+# define X_DPI 240
+#endif
+
+/*
+ * For Y_DPI, a given printer will support a base resolution of 60 or 72;
+ * check the printer manual. The Y_DPI value must be a multiple of this
+ * base resolution. Valid values for Y_DPI:
+ *
+ * For 9-pin printers: 1*base_res
+ * For 24-pin printers: 1*base_res, 3*base_res
+ *
+ * The value specified at compile time is the default value used if the
+ * user does not specify a resolution at runtime.
+ */
+
+#ifndef Y_BASERES
+# define Y_BASERES 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI (1*Y_BASERES)
+#endif
+
+/* The device descriptors */
+private dev_proc_print_page(epson_print_page);
+private dev_proc_print_page(eps9mid_print_page);
+private dev_proc_print_page(eps9high_print_page);
+private dev_proc_print_page(ibmpro_print_page);
+
+/* Standard Epson device */
+gx_device_printer far_data gs_epson_device =
+ prn_device(prn_std_procs, "epson",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.2, 0.0, 0.0, 0.0, /* margins */
+ 1, epson_print_page);
+
+/* Mid-res (interleaved, 1 pass per line) 9-pin device */
+gx_device_printer far_data gs_eps9mid_device =
+ prn_device(prn_std_procs, "eps9mid",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, 3*Y_BASERES,
+ 0.2, 0.0, 0, 0.0, /* margins */
+ 1, eps9mid_print_page);
+
+
+/* High-res (interleaved) 9-pin device */
+gx_device_printer far_data gs_eps9high_device =
+ prn_device(prn_std_procs, "eps9high",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, 3*Y_BASERES,
+ 0.2, 0.0, 0.0, 0.0, /* margins */
+ 1, eps9high_print_page);
+
+/* IBM ProPrinter device */
+gx_device_printer far_data gs_ibmpro_device =
+ prn_device(prn_std_procs, "ibmpro",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.2, 0.0, 0.0, 0.0, /* margins */
+ 1, ibmpro_print_page);
+
+/* ------ Driver procedures ------ */
+
+/* Forward references */
+private void eps_output_run(P6(byte *, int, int, char, FILE *, int));
+
+/* Send the page to the printer. */
+#define DD 0x40 /* double density flag */
+private int
+eps_print_page(gx_device_printer *pdev, FILE *prn_stream, int y_9pin_high,
+ const char *init_string, int init_length, const char *end_string,
+ int archaic, int tab_hiccup)
+{
+ static const char graphics_modes_9[5] =
+ {
+ -1, 0 /*60*/, 1 /*120*/, -1, DD+3 /*240*/
+ };
+
+ static const char graphics_modes_24[7] =
+ {
+ -1, 32 /*60*/, 33 /*120*/, 39 /*180*/,
+ -1, -1, DD+40 /*360*/
+ };
+
+ int y_24pin = (y_9pin_high ? 0 : pdev->y_pixels_per_inch > 72);
+ int in_y_mult = ((y_24pin | y_9pin_high) ? 3 : 1);
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ /* Note that in_size is a multiple of 8. */
+ int in_size = line_size * (8 * in_y_mult);
+ byte *buf1 = (byte *)gs_malloc(in_size, 1, "eps_print_page(buf1)");
+ byte *buf2 = (byte *)gs_malloc(in_size, 1, "eps_print_page(buf2)");
+ byte *in = buf1;
+ byte *out = buf2;
+ int out_y_mult = (y_24pin ? 3 : 1);
+ int x_dpi = pdev->x_pixels_per_inch;
+ char start_graphics =
+ (y_24pin ? graphics_modes_24 : graphics_modes_9)[x_dpi / 60];
+ int first_pass = (start_graphics & DD ? 1 : 0);
+ int last_pass = first_pass * (y_9pin_high == 2 ? 1 : 2);
+ int y_passes = (y_9pin_high ? 3 : 1);
+ int dots_per_space = x_dpi / 10; /* pica space = 1/10" */
+ int bytes_per_space = dots_per_space * out_y_mult;
+ int tab_min_pixels = x_dpi * MIN_TAB_10THS / 10;
+ int skip = 0, lnum = 0, pass, ypass;
+
+ /* Check allocations */
+ if ( buf1 == 0 || buf2 == 0 )
+ { if ( buf1 )
+ gs_free((char *)buf1, in_size, 1, "eps_print_page(buf1)");
+ if ( buf2 )
+ gs_free((char *)buf2, in_size, 1, "eps_print_page(buf2)");
+ return_error(gs_error_VMerror);
+ }
+
+ /* Initialize the printer and reset the margins. */
+ fwrite(init_string, 1, init_length, prn_stream);
+ if ( init_string[init_length - 1] == 'Q' )
+ fputc((int)(pdev->width / pdev->x_pixels_per_inch * 10) + 2,
+ prn_stream);
+
+ /* Calculate the minimum tab distance. */
+ if ( tab_min_pixels < max(MIN_TAB_PIXELS, 3) )
+ tab_min_pixels = max(MIN_TAB_PIXELS, 3);
+ tab_min_pixels -= tab_min_pixels % 3; /* simplify life */
+
+ /* Print lines of graphics */
+ while ( lnum < pdev->height )
+ {
+ byte *in_data;
+ byte *inp;
+ byte *in_end;
+ byte *out_end;
+ byte *out_blk;
+ register byte *outp;
+ int lcnt;
+
+ /* Copy 1 scan line and test for all zero. */
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ if ( in_data[0] == 0 &&
+ !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
+ )
+ {
+ lnum++;
+ skip += 3 / in_y_mult;
+ continue;
+ }
+
+ /* Vertical tab to the appropriate position. */
+ while ( skip > 255 )
+ {
+ fputs("\033J\377", prn_stream);
+ skip -= 255;
+ }
+ if ( skip )
+ {
+ fprintf(prn_stream, "\033J%c", skip);
+ }
+
+ /* Copy the the scan lines. */
+ lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+ if ( lcnt < 8 * in_y_mult )
+ { /* Pad with lines of zeros. */
+ memset(in + lcnt * line_size, 0,
+ in_size - lcnt * line_size);
+ }
+
+ if ( y_9pin_high == 2 )
+ { /* Force printing of every dot in one pass */
+ /* by reducing vertical resolution */
+ /* (ORing with the next line of data). */
+ /* This is necessary because some Epson compatibles */
+ /* can't print neighboring dots. */
+ int i;
+ for ( i = 0; i < line_size * in_y_mult; ++i )
+ in_data[i] |= in_data[i + line_size];
+ }
+
+ if ( y_9pin_high )
+ { /* Shuffle the scan lines */
+ byte *p;
+ int i;
+ static const char index[] =
+ { 0, 8, 16, 1, 9, 17,
+ 2, 10, 18, 3, 11, 19,
+ 4, 12, 20, 5, 13, 21,
+ 6, 14, 22, 7, 15, 23
+ };
+
+ for ( i = 0; i < 24; i++ )
+ {
+ memcpy(out+(index[i]*line_size),
+ in+(i*line_size), line_size);
+ }
+ p = in;
+ in = out;
+ out = p;
+ }
+
+ for ( ypass = 0; ypass < y_passes; ypass++ )
+ {
+ for ( pass = first_pass; pass <= last_pass; pass++ )
+ {
+ /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
+ /* because that's how the printer wants the data. */
+ /* If we are in a 24-pin mode, we have to transpose */
+ /* groups of 3 lines at a time. */
+
+ if ( pass == first_pass )
+ {
+ out_end = out;
+ inp = in;
+ in_end = inp + line_size;
+
+ if ( y_24pin )
+ {
+ for ( ; inp < in_end; inp++, out_end += 24 )
+ {
+ gdev_prn_transpose_8x8(inp, line_size, out_end, 3);
+ gdev_prn_transpose_8x8(inp + line_size * 8,
+ line_size, out_end + 1, 3);
+ gdev_prn_transpose_8x8(inp + line_size * 16,
+ line_size, out_end + 2, 3);
+ }
+ /* Remove trailing 0s. */
+ while ( out_end > out && out_end[-1] == 0 &&
+ out_end[-2] == 0 && out_end[-3] == 0)
+ {
+ out_end -= 3;
+ }
+ }
+ else
+ {
+ for ( ; inp < in_end; inp++, out_end += 8 )
+ {
+ gdev_prn_transpose_8x8(inp + (ypass * 8*line_size),
+ line_size, out_end, 1);
+ }
+ /* Remove trailing 0s. */
+ while ( out_end > out && out_end[-1] == 0 )
+ {
+ out_end--;
+ }
+ }
+ }
+
+ for ( out_blk = outp = out; outp < out_end; )
+ {
+ /* Skip a run of leading 0s. At least */
+ /* tab_min_pixels are needed to make tabbing */
+ /* worth it. We do everything by 3's to */
+ /* avoid having to make different cases */
+ /* for 9- and 24-pin. */
+ if ( !archaic &&
+ *outp == 0 && out_end - outp >= tab_min_pixels &&
+ (outp[1] | outp[2]) == 0 &&
+ !memcmp((char *)outp, (char *)outp + 3,
+ tab_min_pixels - 3)
+ )
+ {
+ byte *zp = outp;
+ int tpos;
+ byte *newp;
+
+ outp += tab_min_pixels;
+ while ( outp + 3 <= out_end &&
+ *outp == 0 &&
+ outp[1] == 0 && outp[2] == 0 )
+ {
+ outp += 3;
+ }
+ tpos = (outp - out) / bytes_per_space;
+ newp = out + tpos * bytes_per_space;
+ if ( newp > zp + 10 )
+ {
+ /* Output preceding bit data.*/
+ if ( zp > out_blk )
+ {
+ /* only false at beginning of line */
+ eps_output_run(out_blk, (int)(zp - out_blk),
+ out_y_mult, start_graphics,
+ prn_stream,
+ (y_9pin_high == 2 ?
+ (1 + ypass) & 1 : pass));
+ }
+ /* Tab over to the appropriate position. */
+ if ( tab_hiccup )
+ fputs("\010 ", prn_stream); /* bksp, space */
+ /* The following statement is broken up */
+ /* to work around a bug in emx/gcc. */
+ fprintf(prn_stream, "\033D%c", tpos);
+ fputc(0, prn_stream);
+ fputc('\t', prn_stream);
+ out_blk = outp = newp;
+ }
+ }
+ else
+ {
+ outp += out_y_mult;
+ }
+ }
+ if ( outp > out_blk )
+ {
+ eps_output_run(out_blk, (int)(outp - out_blk),
+ out_y_mult, start_graphics,
+ prn_stream,
+ (y_9pin_high == 2 ? (1 + ypass) & 1 : pass));
+ }
+
+ fputc('\r', prn_stream);
+ }
+ if ( ypass < y_passes - 1 )
+ fputs("\033J\001", prn_stream);
+ }
+ skip = 24 - y_passes + 1; /* no skip on last Y pass */
+ lnum += 8 * in_y_mult;
+ }
+
+ /* Eject the page and reinitialize the printer */
+ fputs(end_string, prn_stream);
+ fflush(prn_stream);
+
+ gs_free((char *)buf2, in_size, 1, "eps_print_page(buf2)");
+ gs_free((char *)buf1, in_size, 1, "eps_print_page(buf1)");
+ return 0;
+}
+
+/* Output a single graphics command. */
+/* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
+private void
+eps_output_run(byte *data, int count, int y_mult,
+ char start_graphics, FILE *prn_stream, int pass)
+{
+ int xcount = count / y_mult;
+
+ fputc(033, prn_stream);
+ if ( !(start_graphics & ~3) )
+ {
+ fputc("KLYZ"[start_graphics], prn_stream);
+ }
+ else
+ {
+ fputc('*', prn_stream);
+ fputc(start_graphics & ~DD, prn_stream);
+ }
+ fputc(xcount & 0xff, prn_stream);
+ fputc(xcount >> 8, prn_stream);
+ if ( !pass )
+ {
+ fwrite(data, 1, count, prn_stream);
+ }
+ else
+ {
+ /* Only write every other column of y_mult bytes. */
+ int which = pass;
+ register byte *dp = data;
+ register int i, j;
+
+ for ( i = 0; i < xcount; i++, which++ )
+ {
+ for ( j = 0; j < y_mult; j++, dp++ )
+ {
+ putc(((which & 1) ? *dp : 0), prn_stream);
+ }
+ }
+ }
+}
+
+/* The print_page procedures are here, to avoid a forward reference. */
+#ifndef ARCHAIC
+# define ARCHAIC 0
+#endif
+#ifndef TAB_HICCUP
+# define TAB_HICCUP 0
+#endif
+
+#define ESC 0x1b
+private const char eps_init_string[] = {
+#if ARCHAIC
+ ESC, '@', 'r', ESC, 'Q'
+#else
+ ESC, '@', ESC, 'P', ESC, 'l', 0, '\r', ESC, 'Q'
+#endif
+};
+
+private int
+epson_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ return eps_print_page(pdev, prn_stream, 0, eps_init_string,
+ sizeof(eps_init_string), "\f\033@",
+ ARCHAIC, TAB_HICCUP);
+}
+
+private int
+eps9high_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ return eps_print_page(pdev, prn_stream, 1, eps_init_string,
+ sizeof(eps_init_string), "\f\033@",
+ ARCHAIC, TAB_HICCUP);
+}
+
+private int
+eps9mid_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ return eps_print_page(pdev, prn_stream, 2, eps_init_string,
+ sizeof(eps_init_string), "\f\033@",
+ ARCHAIC, TAB_HICCUP);
+}
+
+private int
+ibmpro_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ /*
+ * IBM Proprinter Guide to Operations, p. 4-5: "DC1: Select Printer: Sets
+ * the printer to accept data from your computer." Prevents printer from
+ * interpreting first characters as literal text.
+ */
+#define DC1 0x11
+ static const char ibmpro_init_string[] = {
+ DC1, ESC, '3', 0x30
+ };
+#undef DC1
+ return eps_print_page(pdev, prn_stream, 0, ibmpro_init_string,
+ sizeof(ibmpro_init_string), "\f", 1, 0);
+}
diff --git a/gs/src/gdevescp.c b/gs/src/gdevescp.c
new file mode 100644
index 000000000..2cde86d3f
--- /dev/null
+++ b/gs/src/gdevescp.c
@@ -0,0 +1,415 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevescp.c */
+/*
+ * Epson 'ESC/P 2' language printer driver.
+ *
+ * This driver uses the ESC/P2 language raster graphics commands with
+ * compression. The driver skips vertical white space, provided that
+ * the white space is >= 24/band_size (<~ 1.7mm @ 360dpi!) high. There
+ * is no attempt to skip horizontal white space, but the compression
+ * greatly reduces the significance of this (a nearly blank line would
+ * take about 45 bytes). The driver compresses the data one scan line at
+ * a time, even though this is not enforced by the hardware. The reason
+ * I have done this is that, since the driver skips data outside the
+ * margins, we would have to set up a extra pointers to keep track of
+ * the data from the previous scan line. Doing this would add extra
+ * complexity at a small saving of disk space.
+ *
+ * These are the only possible optimisations that remain, and would
+ * greatly increase the complexity of the driver. At this point, I don't
+ * consider them necessary, but I might consider implementing them if
+ * enough people encourage me to do so.
+ *
+ * Richard Brown (rab@tauon.ph.unimelb.edu.au)
+ *
+ */
+
+#include "gdevprn.h"
+
+/*
+ * Valid values for X_DPI and Y_DPI: 180, 360
+ *
+ * The value specified at compile time is the default value used if the
+ * user does not specify a resolution at runtime.
+ */
+#ifndef X_DPI
+# define X_DPI 360
+#endif
+
+#ifndef Y_DPI
+# define Y_DPI 360
+#endif
+
+/*
+ * Margin definitions: Stylus 800 printer driver:
+ *
+ * The commented margins are from the User's Manual.
+ *
+ * The values actually used here are more accurate for my printer.
+ * The Stylus paper handling is quite sensitive to these settings.
+ * If you find that the printer uses an extra page after every real
+ * page, you'll need to increase the top and/or bottom margin.
+ */
+
+#define STYLUS_L_MARGIN 0.13 /*0.12*/
+#define STYLUS_B_MARGIN 0.56 /*0.51*/
+#define STYLUS_T_MARGIN 0.34 /*0.12*/
+#ifdef A4
+# define STYLUS_R_MARGIN 0.18 /*0.15*/
+#else
+# define STYLUS_R_MARGIN 0.38
+#endif
+
+/*
+ * Epson AP3250 Margins:
+ */
+
+#define AP3250_L_MARGIN 0.18
+#define AP3250_B_MARGIN 0.51
+#define AP3250_T_MARGIN 0.34
+#define AP3250_R_MARGIN 0.28 /* US paper */
+
+/* The device descriptor */
+private dev_proc_print_page(escp2_print_page);
+
+/* Stylus 800 device */
+gx_device_printer far_data gs_st800_device =
+ prn_device(prn_std_procs, "st800",
+ DEFAULT_WIDTH_10THS,
+ DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ STYLUS_L_MARGIN, STYLUS_B_MARGIN, STYLUS_R_MARGIN, STYLUS_T_MARGIN,
+ 1, escp2_print_page);
+
+/* AP3250 device */
+gx_device_printer far_data gs_ap3250_device =
+ prn_device(prn_std_procs, "ap3250",
+ DEFAULT_WIDTH_10THS,
+ DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ AP3250_L_MARGIN, AP3250_B_MARGIN, AP3250_R_MARGIN, AP3250_T_MARGIN,
+ 1, escp2_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Send the page to the printer. */
+private int
+escp2_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int line_size = gdev_prn_raster((gx_device_printer *)pdev);
+ int band_size = 24; /* 1, 8, or 24 */
+ int in_size = line_size * band_size;
+
+ byte *buf1 = (byte *)gs_malloc(in_size, 1, "escp2_print_page(buf1)");
+ byte *buf2 = (byte *)gs_malloc(in_size, 1, "escp2_print_page(buf2)");
+ byte *in = buf1;
+ byte *out = buf2;
+
+ int skip, lnum, top, bottom, left, width;
+ int auto_feed = 1;
+ int count, i;
+
+ /*
+ ** Check for valid resolution:
+ **
+ ** XDPI YDPI
+ ** 360 360
+ ** 360 180
+ ** 180 180
+ */
+
+ if( !( (pdev->x_pixels_per_inch == 180 &&
+ pdev->y_pixels_per_inch == 180) ||
+ (pdev->x_pixels_per_inch == 360 &&
+ (pdev->y_pixels_per_inch == 360 ||
+ pdev->y_pixels_per_inch == 180) )) )
+ return_error(gs_error_rangecheck);
+
+ /*
+ ** Check buffer allocations:
+ */
+
+ if ( buf1 == 0 || buf2 == 0 )
+ { if ( buf1 )
+ gs_free((char *)buf1, in_size, 1, "escp2_print_page(buf1)");
+ if ( buf2 )
+ gs_free((char *)buf2, in_size, 1, "escp2_print_page(buf2)");
+ return_error(gs_error_VMerror);
+ }
+
+ /*
+ ** Reset printer, enter graphics mode:
+ */
+
+ fwrite("\033@\033(G\001\000\001", 1, 8, prn_stream);
+
+#ifdef A4
+ /*
+ ** After reset, the Stylus is set up for US letter paper.
+ ** We need to set the page size appropriately for A4 paper.
+ ** For some bizarre reason the ESC/P2 language wants the bottom
+ ** margin measured from the *top* of the page:
+ */
+
+ fwrite("\033(U\001\0\n\033(C\002\0t\020\033(c\004\0\0\0t\020",
+ 1, 22, prn_stream);
+#endif
+
+ /*
+ ** Set the line spacing to match the band height:
+ */
+
+ if( pdev->y_pixels_per_inch == 360 )
+ fwrite("\033(U\001\0\012\033+\030", 1, 9, prn_stream);
+ else
+ fwrite("\033(U\001\0\024\033+\060", 1, 9, prn_stream);
+
+ /*
+ ** If the printer has automatic page feeding, then the paper
+ ** will already be positioned at the top margin value, so we
+ ** start printing the image from there. Similarly, we must not
+ ** try to print or even line feed past the bottom margin, since
+ ** the printer will automatically load a new page.
+ ** Printers without this feature may actually need to be told
+ ** to skip past the top margin.
+ */
+
+ if( auto_feed ) {
+ top = dev_t_margin(pdev) * pdev->y_pixels_per_inch;
+ bottom = pdev->height - dev_b_margin(pdev) * pdev->y_pixels_per_inch;
+ } else {
+ top = 0;
+ bottom = pdev->height;
+ }
+
+ /*
+ ** Make left margin and width sit on byte boundaries:
+ */
+
+ left = ( (int) (dev_l_margin(pdev) * pdev->x_pixels_per_inch) ) >> 3;
+
+ width = ((pdev->width - (int)(dev_r_margin(pdev) * pdev->x_pixels_per_inch)) >> 3) - left;
+
+ /*
+ ** Print the page:
+ */
+
+ for ( lnum = top, skip = 0 ; lnum < bottom ; )
+ {
+ byte *in_data;
+ byte *inp;
+ byte *in_end;
+ byte *outp;
+ register byte *p, *q;
+ int lcnt;
+
+ /*
+ ** Check buffer for 0 data. We can't do this mid-band
+ */
+
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ while ( in_data[0] == 0 &&
+ !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
+ lnum < bottom )
+ {
+ lnum++;
+ skip++;
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ }
+
+ if(lnum == bottom ) break; /* finished with this page */
+
+ /*
+ ** Skip blank lines if we need to:
+ */
+
+ if( skip ) {
+ fwrite("\033(v\002\000", 1, 5, prn_stream);
+ fputc(skip & 0xff, prn_stream);
+ fputc(skip >> 8, prn_stream);
+ skip = 0;
+ }
+
+ lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+
+ /*
+ ** Check to see if we don't have enough data to fill an entire
+ ** band. Padding here seems to work (the printer doesn't jump
+ ** to the next (blank) page), although the ideal behaviour
+ ** would probably be to reduce the band height.
+ **
+ ** Pad with nulls:
+ */
+
+ if( lcnt < band_size )
+ memset(in + lcnt * line_size, 0, in_size - lcnt * line_size);
+
+ /*
+ ** Now we have a band of data: try to compress it:
+ */
+
+ for( outp = out, i = 0 ; i < band_size ; i++ ) {
+
+ /*
+ ** Take margins into account:
+ */
+
+ inp = in + i * line_size + left;
+ in_end = inp + width;
+
+ /*
+ ** walk through input buffer, looking for repeated data:
+ ** Since we need more than 2 repeats to make the compression
+ ** worth it, we can compare pairs, since it doesn't matter if we
+ **
+ */
+
+ for( p = inp, q = inp + 1 ; q < in_end ; ) {
+
+ if( *p != *q ) {
+
+ p += 2;
+ q += 2;
+
+ } else {
+
+ /*
+ ** Check behind us, just in case:
+ */
+
+ if( p > inp && *p == *(p-1) )
+ p--;
+
+ /*
+ ** walk forward, looking for matches:
+ */
+
+ for( q++ ; *q == *p && q < in_end ; q++ ) {
+ if( (q-p) >= 128 ) {
+ if( p > inp ) {
+ count = p - inp;
+ while( count > 128 ) {
+ *outp++ = '\177';
+ memcpy(outp, inp, 128); /* data */
+ inp += 128;
+ outp += 128;
+ count -= 128;
+ }
+ *outp++ = (char) (count - 1); /* count */
+ memcpy(outp, inp, count); /* data */
+ outp += count;
+ }
+ *outp++ = '\201'; /* Repeat 128 times */
+ *outp++ = *p;
+ p += 128;
+ inp = p;
+ }
+ }
+
+ if( (q - p) > 2 ) { /* output this sequence */
+ if( p > inp ) {
+ count = p - inp;
+ while( count > 128 ) {
+ *outp++ = '\177';
+ memcpy(outp, inp, 128); /* data */
+ inp += 128;
+ outp += 128;
+ count -= 128;
+ }
+ *outp++ = (char) (count - 1); /* byte count */
+ memcpy(outp, inp, count); /* data */
+ outp += count;
+ }
+ count = q - p;
+ *outp++ = (char) (256 - count + 1);
+ *outp++ = *p;
+ p += count;
+ inp = p;
+ } else /* add to non-repeating data list */
+ p = q;
+ if( q < in_end )
+ q++;
+ }
+ }
+
+ /*
+ ** copy remaining part of line:
+ */
+
+ if( inp < in_end ) {
+
+ count = in_end - inp;
+
+ /*
+ ** If we've had a long run of varying data followed by a
+ ** sequence of repeated data and then hit the end of line,
+ ** it's possible to get data counts > 128.
+ */
+
+ while( count > 128 ) {
+ *outp++ = '\177';
+ memcpy(outp, inp, 128); /* data */
+ inp += 128;
+ outp += 128;
+ count -= 128;
+ }
+
+ *outp++ = (char) (count - 1); /* byte count */
+ memcpy(outp, inp, count); /* data */
+ outp += count;
+ }
+ }
+
+ /*
+ ** Output data:
+ */
+
+ fwrite("\033.\001", 1, 3, prn_stream);
+
+ if(pdev->y_pixels_per_inch == 360)
+ fputc('\012', prn_stream);
+ else
+ fputc('\024', prn_stream);
+
+ if(pdev->x_pixels_per_inch == 360)
+ fputc('\012', prn_stream);
+ else
+ fputc('\024', prn_stream);
+
+ fputc(band_size, prn_stream);
+
+ fputc((width << 3) & 0xff, prn_stream);
+ fputc( width >> 5, prn_stream);
+
+ fwrite(out, 1, (outp - out), prn_stream);
+
+ fwrite("\r\n", 1, 2, prn_stream);
+ lnum += band_size;
+ }
+
+ /* Eject the page and reinitialize the printer */
+
+ fputs("\f\033@", prn_stream);
+ fflush(prn_stream);
+
+ gs_free((char *)buf2, in_size, 1, "escp2_print_page(buf2)");
+ gs_free((char *)buf1, in_size, 1, "escp2_print_page(buf1)");
+ return 0;
+}
diff --git a/gs/src/gdevevga.c b/gs/src/gdevevga.c
new file mode 100644
index 000000000..e12c08116
--- /dev/null
+++ b/gs/src/gdevevga.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevevga.c */
+/* IBM PC EGA and VGA display drivers */
+/* All of the real code is in gdevpcfb.c. */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevpcfb.h"
+
+/* ------ Internal routines ------ */
+
+/* We can't catch signals.... */
+void
+pcfb_set_signals(gx_device *dev)
+{
+}
+
+/* Read the device state */
+void
+pcfb_get_state(pcfb_bios_state *pbs)
+{ registers regs;
+ regs.h.ah = 0xf;
+ int86(0x10, &regs, &regs);
+ pbs->display_mode = regs.h.al;
+ pbs->text_page = regs.h.bh;
+ regs.h.ah = 0x3;
+ int86(0x10, &regs, &regs);
+ pbs->text_cursor_mode = regs.rshort.cx;
+ regs.rshort.ax = 0x1130;
+ regs.h.bh = 0;
+ int86(0x10, &regs, &regs);
+ switch ( regs.rshort.cx )
+ {
+ case 0x08: pbs->text_font = 0x1112; break; /* 8 x 8 */
+ case 0x10: pbs->text_font = 0x1114; break; /* 8 x 16 */
+ default: pbs->text_font = 0x1111; /* 8 x 14 */
+ }
+ regs.h.ah = 0x8;
+ regs.h.bh = pbs->text_page;
+ int86(0x10, &regs, &regs);
+ pbs->text_attribute = regs.h.ah;
+ pbs->border_color = (regs.h.ah >> 4);
+ regs.rshort.ax = 0x1a00;
+ int86(0x10, &regs, &regs);
+ if ( regs.h.al == 0x1a && regs.h.bl == 0x8 )
+ { regs.rshort.ax = 0x1008;
+ int86(0x10, &regs, &regs);
+ pbs->border_color = regs.h.bh;
+ }
+ if ( pbs->display_mode != 3 )
+ { pbs->display_mode = 3;
+ pbs->text_font = 0x1112;
+ pbs->text_cursor_mode = 0x0607;
+ pbs->text_attribute = 7;
+ pbs->text_page = 0;
+ }
+}
+
+/* Set the device mode */
+void
+pcfb_set_mode(int mode)
+{ registers regs;
+ regs.h.ah = 0;
+ regs.h.al = mode;
+ int86(0x10, &regs, &regs);
+}
+
+/* Restore the device state */
+void
+pcfb_set_state(const pcfb_bios_state *pbs)
+{ registers regs;
+ pcfb_set_mode(pbs->display_mode);
+ regs.rshort.ax = 0x500; /* force display of page 0 */
+ int86(0x10, &regs, &regs);
+ regs.rshort.ax = pbs->text_font;
+ regs.h.bl = 0;
+ int86(0x10, &regs, &regs);
+ regs.h.ah = 0x3;
+ regs.h.bh = 0;
+ int86(0x10, &regs, &regs); /* Get cursor to reset MCGA */
+ regs.h.al = pbs->text_page;
+ regs.h.ah = 0x5;
+ int86(0x10, &regs, &regs);
+ regs.rshort.cx = pbs->text_cursor_mode;
+ regs.h.ah = 0x1;
+ int86(0x10, &regs, &regs);
+ regs.rshort.ax = 0x1001;
+ regs.h.bh = pbs->border_color;
+ int86(0x10, &regs, &regs);
+}
diff --git a/gs/src/gdevherc.c b/gs/src/gdevherc.c
new file mode 100644
index 000000000..d7fdca568
--- /dev/null
+++ b/gs/src/gdevherc.c
@@ -0,0 +1,482 @@
+/* Copyright (C) 1990, 1991, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevherc.c */
+/* IBM PC-compatible Hercules Graphics display driver */
+/* using direct access to frame buffer */
+
+#define FB_RASTER 90
+#define SCREEN_HEIGHT 350
+#define SCREEN_ASPECT_RATIO (54.0/35.0)
+#define VIDEO_MODE 0x07
+#define regen 0xb0000000L
+
+#define interrupt /* patch ANSI incompatibility */
+#include "dos_.h"
+typedef union REGS registers;
+#include "gx.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gxbitmap.h"
+#include "gxdevice.h"
+
+/* outportb is defined in dos_.h */
+#define outport2(port, index, data)\
+ (outportb(port, index), outportb((port)+1, data))
+/* Define the nominal page height in inches. */
+#ifdef A4
+# define PAGE_HEIGHT_INCHES 11.69
+#else
+# define PAGE_HEIGHT_INCHES 11.0
+#endif
+
+/* Dimensions of screen */
+#define screen_size_x (FB_RASTER * 8)
+#define screen_size_y SCREEN_HEIGHT
+/* Other display parameters */
+#define raster_x FB_RASTER
+#define aspect_ratio SCREEN_ASPECT_RATIO
+#define graphics_video_mode VIDEO_MODE
+
+/* Procedures */
+
+ /* See gxdevice.h for the definitions of the procedures. */
+
+dev_proc_open_device(herc_open);
+dev_proc_close_device(herc_close);
+dev_proc_fill_rectangle(herc_fill_rectangle);
+dev_proc_copy_mono(herc_copy_mono);
+dev_proc_copy_color(herc_copy_color);
+
+/* The device descriptor */
+private gx_device_procs herc_procs = {
+ herc_open,
+ gx_default_get_initial_matrix,
+ gx_default_sync_output,
+ gx_default_output_page,
+ herc_close,
+ gx_default_map_rgb_color,
+ gx_default_map_color_rgb,
+ herc_fill_rectangle,
+ gx_default_tile_rectangle,
+ herc_copy_mono,
+ herc_copy_color
+};
+
+gx_device far_data gs_herc_device = {
+ std_device_std_body(gx_device, &herc_procs, "herc",
+ screen_size_x, screen_size_y,
+ /* The following parameters map an appropriate fraction of */
+ /* the screen to a full-page coordinate space. */
+ /* This may or may not be what is desired! */
+ (screen_size_y * aspect_ratio) / PAGE_HEIGHT_INCHES, /* x dpi */
+ screen_size_y / PAGE_HEIGHT_INCHES /* y dpi */
+ )
+};
+
+
+/* Forward declarations */
+private int herc_get_mode(P0());
+private void herc_set_mode(P1(int));
+
+/* Save the HERC mode */
+private int herc_save_mode = -1;
+
+/* Reinitialize the herc for text mode */
+int
+herc_close(gx_device *dev)
+{ if ( herc_save_mode >= 0 ) herc_set_mode(herc_save_mode);
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Read the device mode */
+private int
+herc_get_mode(void)
+{ registers regs;
+ regs.h.ah = 0xf;
+ int86(0x10, &regs, &regs);
+ return regs.h.al;
+}
+
+/* Set the device mode */
+private void
+herc_set_mode(int mode)
+{ registers regs;
+ regs.h.ah = 0;
+ regs.h.al = mode;
+ int86(0x10, &regs, &regs);
+}
+
+
+/****************************************************************/
+/* Hercules graphics card functions */
+/* */
+/* -- Taken from Jan/Feb 1988 issue of Micro Cornucopia #39 */
+/* */
+/* --rewritten for MSC 5.1 on 02/18/91 by Phillip Conrad */
+/****************************************************************/
+
+
+static const char paramg[12] = {0x35, 0x2d, 0x2e, 0x07, 0x5b, 0x02,
+ 0x57, 0x57, 0x02, 0x03, 0x00, 0x00};
+/* (Never used)
+static const char paramt[12] = {0x61, 0x50, 0x52, 0x0f, 0x19, 0x06,
+ 0x19, 0x19, 0x02, 0x0d, 0x0b, 0x0c};
+*/
+
+/* Type and macro for frame buffer pointers. */
+/*** Intimately tied to the 80x86 (x<2) addressing architecture. ***/
+typedef byte far *fb_ptr;
+# define mk_fb_ptr(x, y)\
+ (fb_ptr)((regen) + ((0x2000 * ((y) % 4) + (90 * ((y) >> 2))) + ((int)(x) >> 3)))
+
+
+/* Structure for operation parameters. */
+/* Note that this structure is known to assembly code. */
+/* Not all parameters are used for every operation. */
+typedef struct rop_params_s {
+ fb_ptr dest; /* pointer to frame buffer */
+ int draster; /* raster of frame buffer */
+ const byte far *src; /* pointer to source data */
+ int sraster; /* source raster */
+ int width; /* width in bytes */
+ int height; /* height in scan lines */
+ int shift; /* amount to right shift source */
+ int invert; /* 0 or -1 to invert source */
+ int data; /* data for fill */
+ int x_pos; /*>>added--2/24/91 */
+ int y_pos;
+} rop_params;
+
+/* Define the device port and register numbers, and the regen map base */
+#define seq_addr 0x3b4 /* changed for HERC card (6845 ports)*/
+#define graph_mode 0x3b8
+#define graph_stat 0x3ba
+#define graph_config 0x3bf
+
+#ifndef regen
+#define regen 0xa0000000L
+#endif
+
+
+/* Initialize the display for Hercules graphics mode */
+int
+herc_open(gx_device *dev)
+{ int i;
+ if ( herc_save_mode < 0 ) herc_save_mode = herc_get_mode();
+/* herc_set_mode(graphics_video_mode); */
+ outportb(graph_config,3);
+ for(i=0;i<sizeof(paramg);i++)
+ {
+ outport2(seq_addr,i,paramg[i]);
+
+ }
+ outportb(graph_mode,0x0a); /* set page 0 */
+ for(i=0;i<0x3FFFL;i++) /* clear the screen */
+ {
+ int far *loc = (int far *)( regen +(2L*i));
+ *loc = 0;
+ }
+
+ return 0;
+}
+
+/* Macro for testing bit-inclusion */
+#define bit_included_in(x,y) !((x)&~(y))
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+int
+herc_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
+{ rop_params params;
+#define czero (int)izero
+#define cone (int)ione
+ int dleft, sleft, count;
+ int invert, zmask, omask;
+ byte mask, rmask;
+
+ if ( cone == czero ) /* vacuous case */
+ return herc_fill_rectangle(dev, x, y, w, h, izero);
+
+ /* clip */
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ params.dest = mk_fb_ptr(x, y);
+ params.draster = raster_x;
+ params.src = base + (sourcex >> 3);
+ params.sraster = raster;
+ params.height = h;
+ params.shift = (x - sourcex) & 7;
+ params.y_pos = y;
+ params.x_pos = x;
+ params.width = w;
+
+ if(czero > cone) params.invert = -1;
+
+ /* Macros for writing partial bytes. */
+ /* bits has already been inverted by xor'ing with invert. */
+
+#define write_byte_masked(ptr, bits, mask)\
+ *ptr = ((bits | ~mask | zmask) & (*ptr | (bits & mask & omask)))
+
+#define write_byte(ptr, bits)\
+ *ptr = ((bits | zmask) & (*ptr | (bits & omask)))
+
+ invert = (czero == 1 || cone == 0 ? -1 : 0);
+/* invert = (czero == 1 || cone == 1 ? -1 : 0); */
+ zmask = (czero == 0 || cone == 0 ? 0 : -1);
+ omask = (czero == 1 || cone == 1 ? -1 : 0);
+
+#undef czero
+#undef cone
+
+ /* Actually copy the bits. */
+
+ sleft = 8 - (sourcex & 7);
+ dleft = 8 - (x & 7);
+ mask = 0xff >> (8 - dleft);
+ count = w;
+ if ( w < dleft )
+ mask -= mask >> w,
+ rmask = 0;
+ else
+ rmask = 0xff00 >> ((w - dleft) & 7);
+
+ if (sleft == dleft) /* optimize the aligned case */
+ {
+ w -= dleft;
+ while ( --h >= 0 )
+ {
+ register const byte *bptr = params.src;
+ register byte *optr = mk_fb_ptr(params.x_pos,params.y_pos);
+ register int bits = *bptr ^ invert; /* first partial byte */
+
+ count = w;
+
+ write_byte_masked(optr, bits, mask);
+
+ /* Do full bytes. */
+
+ while ((count -= 8) >= 0)
+ {
+ bits = *++bptr ^ invert;
+ params.x_pos += 8;
+ optr = mk_fb_ptr(params.x_pos,params.y_pos);
+ write_byte(optr, bits);
+ }
+ /* Do last byte */
+
+ if (count > -8)
+ {
+ bits = *++bptr ^ invert;
+ params.x_pos += 8;
+ optr = mk_fb_ptr(params.x_pos,params.y_pos);
+ write_byte_masked(optr, bits, rmask);
+ }
+/* dest += BPL; */
+ params.y_pos++;
+ params.x_pos = x;
+ params.src += raster;
+ }
+ }
+ else
+ {
+ int skew = (sleft - dleft) & 7;
+ int cskew = 8 - skew;
+
+ while (--h >= 0)
+ {
+ const byte *bptr = params.src;
+ byte *optr = mk_fb_ptr(params.x_pos,params.y_pos);
+ register int bits;
+
+ count = w;
+
+ /* Do the first partial byte */
+
+ if (sleft >= dleft)
+ {
+ bits = *bptr >> skew;
+ }
+ else /* ( sleft < dleft ) */
+ {
+ bits = *bptr++ << cskew;
+ if (count > sleft)
+ bits += *bptr >> skew;
+ }
+ bits ^= invert;
+ write_byte_masked(optr, bits, mask);
+ count -= dleft;
+ params.x_pos += 8;
+ optr = mk_fb_ptr(params.x_pos,params.y_pos);
+
+ /* Do full bytes. */
+
+ while ( count >= 8 )
+ {
+ bits = *bptr++ << cskew;
+ bits += *bptr >> skew;
+ bits ^= invert;
+ write_byte(optr, bits);
+ count -= 8;
+ params.x_pos += 8;
+ optr = mk_fb_ptr(params.x_pos,params.y_pos);
+ }
+
+ /* Do last byte */
+
+ if (count > 0)
+ {
+ bits = *bptr++ << cskew;
+ if (count > skew)
+ bits += *bptr >> skew;
+ bits ^= invert;
+ write_byte_masked(optr, bits, rmask);
+ }
+/* dest += BPL;
+ line += raster;
+*/
+ params.y_pos++;
+ params.x_pos = x;
+ params.src += raster;
+ }
+ }
+ return 0;
+}
+
+/* Copy a color pixelmap. This is just like a bitmap, */
+int
+herc_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ return herc_copy_mono(dev, base, sourcex, raster, id,
+ x, y, w, h,(gx_color_index)0, (gx_color_index)1);
+}
+
+# define mk_fb_yptr(x, y)\
+ (fb_ptr)((regen) + ((0x2000 * ((y) % 4) + (90 * ((y) >> 2))) + x))
+
+/* Fill a rectangle. */
+int
+herc_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ rop_params params;
+
+ int x2, y2, xlen;
+ byte led, red, d;
+ byte far *ptr;
+ int xloc;
+
+ fit_fill(dev, x, y, w, h);
+
+ params.dest = mk_fb_ptr(x, y);
+ params.y_pos = y;
+ params.x_pos = x;
+
+ x2 = x + w - 1;
+ y2 = y + h - 1;
+
+ xlen = (x2 >> 3) - (x >> 3) - 1;
+ led = 0xff >> (x & 7);
+ red = 0xff << (7 - (x2 & 7));
+
+ ptr = mk_fb_ptr(x,y);
+
+ if (color)
+ {
+ /* here to set pixels */
+
+ if (xlen == -1)
+ {
+ /* special for rectangles that fit in a byte */
+
+ d = led & red;
+ for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
+ {
+ *ptr |= d;
+ params.y_pos++;
+ }
+ return 0;
+ }
+
+ /* normal fill */
+
+ xloc = params.x_pos >> 3;
+ for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
+ { register int x_count = xlen;
+ register byte far *p = ptr;
+ *p |= led;
+/* params.x_pos += 8; */
+ xloc++;
+ p = mk_fb_yptr(xloc,params.y_pos);
+ while ( x_count-- ) {
+ *p = 0xff;
+/* params.x_pos += 8; */
+ xloc++;
+ p = mk_fb_yptr(xloc,params.y_pos);
+ }
+ *p |= red;
+/* params.x_pos = x; */
+ xloc = params.x_pos >> 3;
+ params.y_pos++;
+ }
+ }
+
+ /* here to clear pixels */
+
+ led = ~led;
+ red = ~red;
+
+ if (xlen == -1)
+ {
+ /* special for rectangles that fit in a byte */
+
+ d = led | red;
+ for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
+ {
+ *ptr &= d;
+ params.y_pos++;
+ }
+ return 0;
+ }
+
+ /* normal fill */
+
+ xloc = x >> 3;
+ for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
+ { register int x_count = xlen;
+ register byte far *p = ptr;
+ *p &= led;
+/* params.x_pos += 8; */
+ xloc++;
+ p = mk_fb_yptr(xloc,params.y_pos);
+ while ( x_count-- ) {
+ *p = 0x00;
+/* params.x_pos += 8; */
+ xloc++;
+ p = mk_fb_yptr(xloc,params.y_pos);
+ }
+ *p &= red;
+/* params.x_pos = x; */
+ xloc = params.x_pos >> 3;
+ params.y_pos++;
+ }
+ return 0;
+}
diff --git a/gs/src/gdevht.c b/gs/src/gdevht.c
new file mode 100644
index 000000000..472b87e09
--- /dev/null
+++ b/gs/src/gdevht.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevht.c */
+/* Halftoning device implementation */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevht.h"
+#include "gxdcolor.h"
+#include "gxdcconv.h"
+#include "gxdither.h"
+
+/* The device procedures */
+private dev_proc_open_device(ht_open);
+private dev_proc_map_rgb_color(ht_map_rgb_color);
+private dev_proc_map_color_rgb(ht_map_color_rgb);
+private dev_proc_fill_rectangle(ht_fill_rectangle);
+private dev_proc_map_cmyk_color(ht_map_cmyk_color);
+private dev_proc_map_rgb_alpha_color(ht_map_rgb_alpha_color);
+private const gx_device_ht far_data gs_ht_device =
+{ std_device_dci_body(gx_device_ht, 0, "halftoner",
+ 0, 0, 1, 1,
+ 1, 8, 255, 0, 0, 0),
+ { ht_open,
+ gx_forward_get_initial_matrix,
+ gx_forward_sync_output,
+ gx_forward_output_page,
+ gx_default_close_device,
+ ht_map_rgb_color,
+ ht_map_color_rgb,
+ ht_fill_rectangle,
+ gx_default_tile_rectangle,
+ gx_default_copy_mono,
+ gx_default_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ ht_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ ht_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ gx_default_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ gx_default_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ gx_default_strip_tile_rectangle,
+ gx_default_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_forward_get_hardware_params,
+ }
+};
+
+/*
+ * Define the packing of two target colors and a halftone level into
+ * a gx_color_index. Since C doesn't let us cast between a structure
+ * and a scalar, we have to use explicit shifting and masking.
+ */
+#define cx_bits (sizeof(gx_color_index) * 8)
+#define cx_color_mask ((1 << ht_target_max_depth) - 1)
+#define cx_color0(color) ((color) >> (cx_bits - ht_target_max_depth))
+#define cx_color1(color) (((color) >> (ht_level_depth)) & cx_color_mask)
+#define cx_level(color) ((color) & ((1 << ht_level_depth) - 1))
+#define cx_values(c0, c1, lev)\
+ ( ((((c0) << ht_target_max_depth) + (c1)) << ht_level_depth) + (lev) )
+
+/* Open the device. Right now we just make some error checks. */
+private int
+ht_open(gx_device *dev)
+{ if ( htdev->target == 0 ||
+ htdev->target->color_info.depth > ht_target_max_depth
+ )
+ return_error(gs_error_rangecheck);
+ htdev->phase.x = imod(-htdev->ht_phase.x, htdev->dev_ht->lcm_width);
+ htdev->phase.y = imod(-htdev->ht_phase.y, htdev->dev_ht->lcm_height);
+ return 0;
+}
+
+/* Map from RGB or CMYK colors to the packed representation. */
+private gx_color_index
+ht_finish_map_color(int code, const gx_device_color *pdevc)
+{ if ( code < 0 )
+ return gx_no_color_index;
+ if ( pdevc->type == &gx_dc_pure )
+ return cx_values(pdevc->colors.pure, 0, 0);
+ if ( pdevc->type == &gx_dc_ht_binary )
+ return cx_values(pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->colors.binary.b_level);
+ lprintf("bad type in ht color mapping!");
+ return gx_no_color_index;
+}
+private gx_color_index
+ht_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return ht_map_rgb_alpha_color(dev, r, g, b, gx_max_color_value);
+}
+gx_color_index
+ht_map_cmyk_color(gx_device *dev, gx_color_value c, gx_color_value m,
+ gx_color_value y, gx_color_value k)
+{ gx_device_color devc;
+ frac fc = cv2frac(k);
+ frac fk = cv2frac(k);
+ int code =
+ (c == m & m == y ?
+ gx_render_device_gray(color_cmyk_to_gray(fc, fc, fc, fk, NULL),
+ gx_max_color_value,
+ &devc, htdev->target, htdev->dev_ht,
+ &htdev->ht_phase) :
+ gx_render_device_color(fc, cv2frac(m), cv2frac(y),
+ fk, false, gx_max_color_value,
+ &devc, htdev->target, htdev->dev_ht,
+ &htdev->ht_phase));
+ return ht_finish_map_color(code, &devc);
+}
+gx_color_index
+ht_map_rgb_alpha_color(gx_device *dev, gx_color_value r,
+ gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ gx_device_color devc;
+ int code =
+ (r == g & g == b ?
+ gx_render_device_gray(cv2frac(r), alpha,
+ &devc, htdev->target, htdev->dev_ht,
+ &htdev->ht_phase) :
+ gx_render_device_color(cv2frac(r), cv2frac(g), cv2frac(b),
+ frac_0, false, alpha,
+ &devc, htdev->target, htdev->dev_ht,
+ &htdev->ht_phase));
+ return ht_finish_map_color(code, &devc);
+}
+
+/* Map back to an RGB color. */
+private int
+ht_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_color_index color0 = cx_color0(color);
+ uint level = cx_level(color);
+ gx_device *tdev = htdev->target;
+ dev_proc_map_color_rgb((*map)) = dev_proc(tdev, map_color_rgb);
+
+ if ( level == 0 )
+ return (*map)(tdev, color0, prgb);
+ { gx_color_index color1 = cx_color1(color);
+ gx_color_value rgb0[3], rgb1[3];
+ uint num_levels = htdev->dev_ht->order.num_levels;
+ int i;
+
+ (*map)(tdev, color0, rgb0);
+ (*map)(tdev, color1, rgb1);
+ for ( i = 0; i < 3; ++i )
+ prgb[i] = rgb0[i] +
+ (rgb1[i] - rgb0[i]) * (ulong)level / num_levels;
+ return 0;
+ }
+}
+
+/* Fill a rectangle by tiling with a halftone. */
+private int
+ht_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_color_index color0 = cx_color0(color);
+ uint level = cx_level(color);
+ gx_device *tdev = htdev->target;
+
+ if ( level == 0 )
+ return (*dev_proc(tdev, fill_rectangle))
+ (tdev, x, y, w, h, color0);
+ { gx_color_index color1 = cx_color1(color);
+ const gx_ht_order *porder = &htdev->dev_ht->order;
+ gx_ht_cache *pcache = porder->cache;
+ gx_ht_tile *tile;
+
+ /* Ensure that the tile cache is current. */
+ if ( pcache->order.bits != porder->bits )
+ gx_ht_init_cache(pcache, porder);
+ /* Ensure that the tile we want is cached. */
+ tile = gx_render_ht(pcache, level);
+ if ( tile == 0 )
+ return_error(gs_error_Fatal);
+ /* Fill the rectangle with the tile. */
+ return (*dev_proc(tdev, tile_rectangle))
+ (tdev, &tile->tile, x, y, w, h, color0, color1,
+ htdev->phase.x, htdev->phase.y);
+ }
+}
diff --git a/gs/src/gdevht.h b/gs/src/gdevht.h
new file mode 100644
index 000000000..42f1c0fc8
--- /dev/null
+++ b/gs/src/gdevht.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevht.h */
+/* Definitions for halftoning device */
+/* Requires gxdevice.h */
+#include "gzht.h"
+
+/*
+ * A halftoning device converts between a non-halftoned device color space
+ * (e.g., 8-bit gray) and a halftoned space (e.g., 1-bit black and white).
+ * Currently, the target space must not exceed 8 bits per pixel, so that
+ * we can pack two target colors and a halftone level into a gx_color_index.
+ */
+#define ht_target_max_depth 8
+#define ht_level_depth (sizeof(gx_color_index) * 8 - ht_target_max_depth * 2)
+typedef struct gx_device_ht_s {
+ gx_device_forward_common;
+ /* Following are set before opening. */
+ const gx_device_halftone *dev_ht;
+ gs_int_point ht_phase; /* halftone phase from gstate */
+ /* Following are computed when device is opened. */
+ gs_int_point phase; /* halftone tile offset */
+} gx_device_ht;
+
+/* Macro for casting gx_device argument */
+#define htdev ((gx_device_ht *)dev)
diff --git a/gs/src/gdevimgn.c b/gs/src/gdevimgn.c
new file mode 100644
index 000000000..48dc9ce04
--- /dev/null
+++ b/gs/src/gdevimgn.c
@@ -0,0 +1,572 @@
+/* Copyright (C) 1992, 1993, 1994, 1996 by Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ---------------------------------------------------------- */
+/* gdevimgn.c - version 1.4 */
+/* Imagen ImPRESS printer driver */
+
+/* This driver uses the Impress bitmap operation to print the
+ page image. */
+/* -------------------------------------------------------- */
+
+/* Written by Alan Millar (AMillar@bolis.sf-bay.org) August 4 1992.
+ Basic bitmap dump. */
+/* Updated by Alan Millar Sept 21 1992. Added resolution handling
+ for 75, 150, and 300 dpi. */
+/* Updated by Alan Millar June 05 1993. General cleanup for
+ beta test release. */
+/* Updated by Alan Millar June 21 1993. v1.3. Combined multipage
+ output into single imPress document. Quote fewer special
+ chars in byte stream mode. imPress document header options
+ can be set from environment variable IMPRESSHEADER */
+/* Updated by Alan Millar July 04 1993. v1.4.
+ New makefile option USE_BYTE_STREAM instead of changing source.
+ Swatch output redone to eliminate ALL blank swatches (swatchMap).
+ Buffer copying changed to multi-byte operations (BIGTYPE).
+ Page margins and A4 paper settings fixed, at least for Canon CX.
+ */
+
+/* -------------------------------------------------------- */
+/* Instructions:
+
+ - Add "imagen.dev" to DEVICE_DEVS in the makefile. For example:
+ DEVICE_DEVS2=laserjet.dev imagen.dev
+
+ - Include or exclude USE_BYTE_STREAM in makefile as appropriate
+ If you are compiling on Unix, re-run "tar_cat" to update the makefile
+ from devs.mak
+
+ - At run time, specify the resolution on the GS command line
+ by using -r300 or -r150 or -r75
+ - At run time, specify any imPress document options in
+ the IMPRESSHEADER environment variable.
+ */
+
+/* -------------------------------------------------------- */
+/* Hardware/software combinations tested:
+ - ImageStation IP3 8/300 with parallel byte-stream interface,
+ using GS 2.6.1 on Linux with GCC 2.3.3;
+ earlier using GS 2.5.1 on MS-Dos with Turbo C++ 1.0
+ - Sequenced-packet-protocol interface untested.
+ */
+/* -------------------------------------------------------- */
+/* Bugs/Enhancements:
+ - Driver does not use any Impress language features for
+ drawing lines/arcs
+ - Driver does not use resident or downloadable fonts.
+ - Buffer output instead of system call for each byte?
+ */
+
+/* -------------------------------------------------------- */
+#include "gdevprn.h"
+/* #include <stdio.h> should not be used in drivers */
+#include <stdlib.h>
+
+/* -------------------------------------------------------- */
+/* Working Constants */
+
+/* Byte stream quoting: convert special characters to hex.
+ Specify by including/excluding -DUSE_BYTE_STREAM in makefile.
+ This should match printer's hardware interface configuration.
+ If printer interface is serial with sequenced-packet-protocol
+ spooler software (ImageStation config# 11 = 01), then don't use it.
+ Imagen "ipr" spooler software should not use byte stream.
+ If printer interface is Centronics parallel byte stream,
+ (ImageStation config# 11 = 03), then use byte stream. */
+
+#ifdef USE_BYTE_STREAM
+# define BYTE_STREAM 1
+#else
+# define BYTE_STREAM 0
+#endif
+
+/* Byte stream quote character (ImageStation config# 15).
+ Only needed when using byte stream */
+#define QUOTE_CHAR (char) 0x02
+/* Byte stream end-of-file character (ImageStation config# 14). */
+#define EOF_CHAR (char) 0x04
+/* Other special characters to quote. Put them here if spooler or
+ hardware uses flow control, etc. If not needed, set to
+ a redundant value such as EOF_CHAR */
+#define EXTRA_QUOTE1 (char) 0x11 /* ^Q */
+#define EXTRA_QUOTE2 (char) 0x13 /* ^S */
+#define EXTRA_QUOTE3 EOF_CHAR
+#define EXTRA_QUOTE4 EOF_CHAR
+
+/* -------------------------------------------------------- */
+/* imPress header default options.
+ Can be overridden at run-time with IMPRESSHEADER env variable */
+
+#define IMPRESSHEADER "jobheader onerror, prerasterization off"
+
+/* -------------------------------------------------------- */
+
+#define CANON_CX
+
+/* Printer engine max resolution. 300 for Canon CX models such as
+ ImageStation IP3. Others (240?) unverified */
+#ifdef CANON_CX
+# define MAX_DPI 300
+#endif
+#ifndef MAX_DPI
+# define MAX_DPI 300
+#endif
+
+/* Determine imPress scaling factor from GS resolution.
+ Magnify can be 0, 1, or 2.
+ 0 = MAX_DPI, 1 = MAX_DPI / 2, 2 = MAX_DPI / 4
+ Assuming MAX_DPI is 300, you can specify -r75 or -r150
+ or -r300 on the GS command line */
+#define getMagnification ( \
+ ( pdev->x_pixels_per_inch > (MAX_DPI >> 1) ) ? 0 : \
+ ( pdev->x_pixels_per_inch > (MAX_DPI >> 2) ) ? 1 : \
+ 2 )
+
+/* Page dimensions from gdevprn.h - specify -DA4 in makefile for A4 paper */
+#define WIDTH_10THS DEFAULT_WIDTH_10THS
+#define HEIGHT_10THS DEFAULT_HEIGHT_10THS
+
+/* Width in inches of unprintable edge of paper. May need fine tuning.
+ Canon CX engine in ImageStation IP3 8/300 will only print 8 inches
+ wide on any paper size. May vary for other engines */
+
+#ifdef CANON_CX
+# define MARG_L 0.15
+# define MARG_R ( (float)WIDTH_10THS / 10.0 - 8.0 - MARG_L)
+#endif
+#ifndef MARG_L
+# define MARG_L 0.2
+#endif
+#ifndef MARG_R
+# define MARG_R 0.2
+#endif
+#define MARG_T 0.1
+#define MARG_B 0.2
+
+
+/* Flag for displaying debug messages at run-time. Higher
+ number = higher detail */
+#define IM_DEBUG 0
+#define DebugMsg(Level,P1,P2) if (Level<=IM_DEBUG) {fprintf(stderr,P1,P2 );}
+
+/*-------------------------------------------*/
+ /* Impress bitmaps are made up of 32x32 bit swatches.
+ A swatch is four bytes (32 bits) wide by 32 bytes high,
+ totalling 128 bytes. */
+#define HorzBytesPerSw 4
+#define HorzBitsPerSw (HorzBytesPerSw * 8)
+#define VertBytesPerSw 32
+#define TotalBytesPerSw (HorzBytesPerSw * VertBytesPerSw)
+
+/*-------------------------------------------*/
+/* Attempt at optimization to something faster than byte-by-byte copying.
+ imPress swatches are 4 bytes wide, so type must align on a 4-byte
+ boundary. Swatch interleaving restricts the copy to 4 bytes in a row.
+ Type must be numeric where value is zero when all bytes in it are zero. */
+#if arch_sizeof_long == 4
+# define BIGTYPE unsigned long int
+#else
+# if arch_sizeof_short == 4
+# define BIGTYPE unsigned short int
+# else
+# if arch_sizeof_short == 2
+# define BIGTYPE unsigned short
+# endif
+# endif
+#endif
+#ifndef BIGTYPE
+#define BIGTYPE byte
+#endif
+
+#define BIGSIZE ( sizeof( BIGTYPE ) )
+
+/*-------------------------------------------*/
+/* IMAGEN imPress Command opcodes */
+/* from DVIIMP.C */
+#define iSP 128 /* advance one space */
+#define iSP1 129 /* advance one space + 1 pixel */
+#define iMPLUS 131 /* Move one pixel forward */
+#define iMMINUS 132 /* Move one pixel back */
+#define iMMOVE 133 /* Move in main advance direction */
+#define iSMOVE 134 /* Move in secondary advance direction */
+
+#define iABS_H 135 /* Move to H position */
+#define iREL_H 136 /* Move in H direction */
+#define iABS_V 137 /* Move to V position */
+#define iREL_V 138 /* Move in V direction */
+
+#define iCRLF 197 /* move to beginning of next line */
+
+#define iSET_HV_SYSTEM 205 /* Define new coordinate system */
+#define iSET_ADV_DIRS 206 /* Define advance directions */
+
+#define iPAGE 213 /* Set H and V to 0 */
+#define iENDPAGE 219 /* print the current page */
+
+#define iBITMAP 235 /* Print a full bitmap */
+#define iSET_MAGNIFICATION 236
+ /* magnify the page by 1, 2, 4 */
+#define iNOOP 254 /* no operation */
+#define iEOF 255 /* end of impress document */
+
+/*-------------------------------------------*/
+/*-------------------------------------------*/
+/* The device descriptor */
+
+private dev_proc_print_page(imagen_print_page);
+private dev_proc_open_device(imagen_prn_open);
+private dev_proc_close_device(imagen_prn_close);
+
+gx_device_procs imagen_procs =
+ prn_procs(imagen_prn_open, gdev_prn_output_page, imagen_prn_close);
+
+#define ppdev ((gx_device_printer *)pdev)
+
+/*-------------------------------------------*/
+gx_device_printer far_data gs_imagen_device =
+ prn_device(/*prn_std_procs*/ imagen_procs,
+ "imagen",
+ WIDTH_10THS,
+ HEIGHT_10THS,
+ MAX_DPI, /* x_dpi */
+ MAX_DPI, /* y_dpi */
+ MARG_L,MARG_R,MARG_T,MARG_B, /* margins */
+ 1, imagen_print_page);
+
+/*-------------------------------------------*/
+
+/*-------------------------------------------*/
+private void
+iWrite(FILE *Out, byte Val)
+{ /* iWrite */
+ char *hexList = "0123456789ABCDEF";
+
+ /* if we are doing byte-stream, quote characters that would otherwise
+ match EOF and QUOTE itself, or other special chars */
+ /* Imagen quoting takes one character and writes out the QUOTE
+ character followed by the hex digits of the quoted character */
+ if (BYTE_STREAM &&
+ ( Val == QUOTE_CHAR || Val == EOF_CHAR
+ || Val == EXTRA_QUOTE1 || Val == EXTRA_QUOTE2
+ || Val == EXTRA_QUOTE3 || Val == EXTRA_QUOTE4 ) ) {
+ fputc (QUOTE_CHAR, Out);
+ fputc ((char) hexList[Val / 0x10], Out);
+ fputc ((char) hexList[Val % 0x10], Out);
+ } else { /* quoted char */
+ /* Not doing quoting, just send it out */
+ fputc(Val, Out);
+ } /* quoted char */
+} /* iWrite */
+
+/* Write out 16bit, high byte first */
+void
+iWrite2(FILE *Out, int Val)
+{ /* iWrite2 */
+ iWrite(Out,(byte) (Val >> 8) & 0x00FF );
+ iWrite(Out,(byte) Val & 0x00FF );
+} /* iWrite2 */
+
+/* --------------------------------------------------------- */
+
+private int
+imagen_prn_open(gx_device *pdev)
+{ /* imagen_prn_open */
+ int code;
+
+ char *impHeader;
+
+ /* ----------------------------------------- */
+ DebugMsg(1,"%s\n","Start of imagen_prn_open");
+ DebugMsg(2,"BIGSIZE = %ld \n",BIGSIZE);
+
+ code = gdev_prn_open(pdev);
+ if ( code < 0 ) return code;
+
+ /* ----------------------------------------- */
+
+ DebugMsg(2,"opening file: %s\n",ppdev->fname);
+ code = gdev_prn_open_printer(pdev, 1);
+ if ( code < 0 ) return code;
+
+ impHeader = getenv("IMPRESSHEADER");
+ if (impHeader == NULL ) {
+ impHeader = IMPRESSHEADER ;
+ } /* if impHeader */
+
+ fprintf(ppdev->file,"@document(language impress, %s)",impHeader);
+
+ code = gdev_prn_close_printer(pdev);
+ if ( code < 0 ) return code;
+
+ /* ----------------------------------------- */
+ DebugMsg(1,"%s\n","End of imagen_prn_open");
+
+ return code;
+} /* imagen_prn_open */
+
+private int
+imagen_prn_close(gx_device *pdev)
+{ /* imagen_prn_close */
+ int code;
+
+ /* ----------------------------------------- */
+ DebugMsg(1,"%s\n","Start of imagen_prn_close");
+
+ code = gdev_prn_open_printer(pdev, 1);
+ if ( code < 0 ) return code;
+
+ /* Write imPress end of document marker */
+ iWrite(ppdev->file,iEOF);
+
+ /* And byte stream end of file */
+ if (BYTE_STREAM) {
+ /* DON'T use iWrite because actual EOF should not be quoted! */
+ fputc(EOF_CHAR,ppdev->file);
+ } /* if byte stream */
+
+ fflush(ppdev->file);
+
+ code = gdev_prn_close_printer(pdev);
+ if ( code < 0 ) return code;
+
+ code = gdev_prn_close(pdev);
+
+ DebugMsg(1,"%s\n","End of imagen_prn_close");
+
+ return(code);
+} /* imagen_prn_close */
+
+/*-------------------------------------------*/
+/* Send the page to the printer. */
+private int
+imagen_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ /* input buffer: one line of bytes rasterized by gs */
+ byte *in = (byte *)gs_malloc(BIGSIZE, line_size / BIGSIZE + 1,
+ "imagen_print_page(in)");
+ /* output buffer: 32 lines, interleaved into imPress swatches */
+ byte *out;
+ /* working pointer into output buffer */
+ byte *swatch;
+ byte *temp;
+ /* map of which swatches in a row are completely blank, or are non-blank */
+ byte *swatchMap;
+ /* starting line number on page of a row of swatches */
+ int lnum ;
+ /* line number within a row of swatches */
+ int swatchLine;
+ /* ending line number of row of swatches */
+ int lastLine;
+ /* how many swatches can fit on a row */
+ int swatchCount;
+ /* index into row of non-blank swatch */
+ int startSwatch;
+ int endSwatch;
+ /* Scaling factor for resolution */
+ int Magnify;
+ /* page totals */
+ int totalBlankSwatches;
+ int totalGreySwatches;
+
+ /* ----------------------------------------- */
+ /* Start of routine */
+ /* ----------------------------------------- */
+
+ DebugMsg(1,"%s\n","Start of imagen_print_page");
+
+ /* ----------------------------------------- */
+ Magnify = getMagnification ;
+
+ /* Impress bitmaps are made up of 32x32 bit swatches.
+ A swatch is four bytes wide by 32 bytes high.
+ See how many swatches will fit horizontally. */
+
+ swatchCount = (line_size + HorzBytesPerSw - 1) / HorzBytesPerSw;
+
+ totalBlankSwatches = 0 ;
+ totalGreySwatches = 0 ;
+ DebugMsg(2,"Swatch count = %d\n",swatchCount);
+ DebugMsg(2,"Line size = %d\n",line_size );
+
+ out = (byte *)gs_malloc(TotalBytesPerSw , swatchCount + 1,
+ "imagen_print_page(out)");
+
+ swatchMap = (byte *)gs_malloc(BIGSIZE,swatchCount / BIGSIZE + 1,
+ "imagen_print_page(swatchMap)" );
+
+ if ( in == 0 || out == 0 )
+ return -1;
+
+ /* Initialize the page */
+ iWrite(prn_stream,iPAGE);
+
+ /* Tell ImPress what resolution we will be using */
+ iWrite(prn_stream,iSET_MAGNIFICATION);
+ iWrite(prn_stream,Magnify);
+
+ /*------------------------------------------------------*/
+ /* main loop down page */
+ lnum = 0;
+ while (lnum <= pdev->height) {
+
+ /* erase swatch map. */
+ for (swatch = swatchMap; swatch < swatchMap + swatchCount ;
+ swatch += BIGSIZE ) {
+ * (BIGTYPE *)swatch = (BIGTYPE) 0;
+ } /* for */
+
+ /* get scan lines to fill swatches */
+ swatchLine = 0;
+ lastLine = VertBytesPerSw - 1;
+
+ /* Check if we don't have a full-height row of swatches at end of page */
+ if (lnum + lastLine > pdev->height ) {
+ /* back up last row so it overlaps with previous. Not a problem
+ on a laser printer, because the overlapping part will be identical */
+ lnum = pdev->height - lastLine ;
+ }; /* not full height */
+
+ DebugMsg (3,"lnum = %d \n",lnum);
+
+ /* ------------------------------------------------------- */
+ /* get 32 lines and interleave into a row of swatches */
+ for (swatchLine = 0 ; swatchLine <= lastLine; swatchLine++) {
+ /* blank out end of buffer for BIGSIZE overlap */
+ for (temp = in + line_size; temp < in + line_size + BIGSIZE;temp++){
+ *temp = 0;
+ } /* for temp */
+
+ /* get one line */
+ gdev_prn_copy_scan_lines(pdev, lnum + swatchLine, in, line_size);
+ DebugMsg(5,"Got scan line %d ", lnum + swatchLine);
+ DebugMsg(5,"line %d \n", swatchLine);
+
+ /* interleave scan line into swatch buffer */
+ /* a swatch is a 4 byte * 32 byte square. Swatches are placed
+ next to each other. The first scan line maps into the first
+ four bytes of the first swatch, then the first four of the second
+ swatch, etc.
+ To get this on the page:
+ A1 A1 A1 A1 B1 B1 B1 B1 C1 C1 C1 C1
+ A2 A2 A2 A2 B2 B2 B2 B2 C2 C2 C2 C2
+ ...
+ A32 A32 A32 A32 B32 B32 B32 B32 C32 C32 C32 C32
+ You have to send it as:
+ A1 A1 A1 A1 A2 ... A32 B1 B1 .. B32 C1 C1 ... C32 */
+
+ /* set initial offset into swatch buffer based on which
+ line in the swatch we are processing */
+ swatch = out + swatchLine * HorzBytesPerSw;
+ DebugMsg(5,"offset: swatch = %d \n",(int) (swatch - out) );
+ temp = in;
+ while ( temp < in + line_size ) {
+ /* copy multi-byte to swatch buffer */
+ * (BIGTYPE *)swatch = * (BIGTYPE *)temp;
+ if ( * (BIGTYPE *)temp ) {
+ /* mark map if not blank */
+ swatchMap[(swatch - out)/TotalBytesPerSw] = (byte) 1 ;
+ } /* if not zero */
+
+ temp += (BIGSIZE > HorzBytesPerSw) ? HorzBytesPerSw : BIGSIZE ;
+ swatch += (BIGSIZE > HorzBytesPerSw) ? HorzBytesPerSw : BIGSIZE ;
+
+ /* if we copied four bytes, skip to next swatch */
+ if ( ((temp - in) % HorzBytesPerSw ) == 0 ) {
+ swatch += (TotalBytesPerSw - HorzBytesPerSw) ;
+ } /* if need to skip */
+ } /* while < line_size */
+
+ } /* for swatchLine */
+
+ /* ------------------------------------------------- */
+ /* we now have full swatches. */
+ /* Send to printer */
+
+ /* go through swatch map to find non-blank swatches.
+ Skip over completely blank swatches */
+ startSwatch = 0;
+ while (startSwatch < swatchCount ) {
+ if (swatchMap[startSwatch] == 0 ) {
+ /* skip blank swatch */
+ DebugMsg(6,"Skip blank %d \n",startSwatch);
+ totalBlankSwatches++;
+ startSwatch++;
+ } else { /* if swatch == 0 */
+ /* we hit a non-blank swatch. */
+ totalGreySwatches++;
+
+ /* See how many there are in a row */
+ endSwatch = startSwatch;
+ while ( (endSwatch < swatchCount) && swatchMap[endSwatch] ) {
+ endSwatch++;
+ totalGreySwatches++;
+ } /* while */
+ /* endSwatch is one past last non-blank swatch */
+ DebugMsg(6,"Grey swatches %d ",startSwatch);
+ DebugMsg(6,"until %d \n",endSwatch);
+
+ /* vertical position: scan line, shifted for magnification */
+ iWrite(prn_stream, iABS_V);
+ iWrite2(prn_stream, lnum << Magnify);
+
+ /* horizontal position = swatch number * 32 bits/swatch */
+ iWrite(prn_stream,iABS_H);
+ iWrite2(prn_stream, startSwatch * HorzBitsPerSw << Magnify );
+ iWrite(prn_stream,iBITMAP); /* start bitmap */
+ iWrite(prn_stream,0x07); /* bit OR with page */
+ iWrite(prn_stream,(endSwatch - startSwatch)); /* horizontal
+ number of swatches */
+ iWrite(prn_stream, 1) ; /* vertical number of swatches */
+ /* write out swatch buffer */
+ for (swatch = out + startSwatch * TotalBytesPerSw;
+ swatch < out + endSwatch * TotalBytesPerSw; swatch++) {
+ iWrite(prn_stream,*swatch);
+ } /* for swatch */
+
+ /* swatches have been printed, see if there are still
+ more in this row */
+ startSwatch = endSwatch;
+ } /* if swatch == 0 */
+
+ } /* while startSwatch */
+
+ /* Whole row of swatches is done. Go on to next row of swatches */
+ lnum += lastLine + 1;
+
+ } /* while lnum */
+
+ /* Eject the page */
+ iWrite(prn_stream,iENDPAGE);
+
+ fflush(prn_stream);
+
+ gs_free((char *)swatchMap, BIGSIZE, swatchCount / BIGSIZE + 1,
+ "imagen_print_page(swatchMap)" );
+ gs_free((char *)out, TotalBytesPerSw, swatchCount+1, "imagen_print_page(out)");
+ gs_free((char *)in, BIGSIZE, line_size / BIGSIZE + 1, "imagen_print_page(in)");
+ /* ----------------------------------------- */
+
+ DebugMsg(1,"Debug: Grey: %d \n",totalGreySwatches);
+ DebugMsg(1,"Debug: Blank: %d \n",totalBlankSwatches );
+ DebugMsg(1,"%s\n","End of imagen_print_page");
+
+ /* ----------------------------------------- */
+ return 0;
+
+} /* imagen_print_page */
diff --git a/gs/src/gdevjpeg.c b/gs/src/gdevjpeg.c
new file mode 100644
index 000000000..96883f0c3
--- /dev/null
+++ b/gs/src/gdevjpeg.c
@@ -0,0 +1,288 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevjpeg.c */
+/* JPEG output driver */
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "gdevprn.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* Structure for the JPEG-writing device. */
+typedef struct gx_device_jpeg_s {
+ gx_device_common;
+ gx_prn_device_common;
+ /* Additional parameters */
+ int JPEGQ; /* quality on IJG scale */
+ float QFactor; /* quality per DCTEncode conventions */
+ /* JPEGQ overrides QFactor if both are specified. */
+} gx_device_jpeg;
+
+/* The device descriptor */
+private dev_proc_get_params(jpeg_get_params);
+private dev_proc_put_params(jpeg_put_params);
+private dev_proc_print_page(jpeg_print_page);
+
+/* ------ The device descriptors ------ */
+
+/* Default X and Y resolution. */
+#ifndef X_DPI
+# define X_DPI 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+/* 24-bit color */
+
+private const gx_device_procs jpeg_procs =
+ prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color,
+ gx_default_rgb_map_color_rgb,
+ jpeg_get_params, jpeg_put_params);
+
+gx_device_jpeg far_data gs_jpeg_device =
+{ prn_device_std_body(gx_device_jpeg, jpeg_procs, "jpeg",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI, 0,0,0,0, 24, jpeg_print_page),
+ 0, /* JPEGQ: 0 indicates not specified */
+ 0.0 /* QFactor: 0 indicates not specified */
+};
+
+/* 8-bit gray */
+
+private const gx_device_procs jpeggray_procs =
+ prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_gray_map_rgb_color,
+ gx_default_gray_map_color_rgb,
+ jpeg_get_params, jpeg_put_params);
+
+gx_device_jpeg far_data gs_jpeggray_device =
+{ prn_device_body(gx_device_jpeg, jpeggray_procs, "jpeggray",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI, 0,0,0,0,
+ 1,8,255,0,256,0,
+ jpeg_print_page),
+ 0, /* JPEGQ: 0 indicates not specified */
+ 0.0 /* QFactor: 0 indicates not specified */
+};
+
+/* Get parameters. */
+private int
+jpeg_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_jpeg *jdev = (gx_device_jpeg *)dev;
+ int code = gdev_prn_get_params(dev, plist);
+ int ecode;
+
+ if ( code < 0 )
+ return code;
+
+ if ((ecode = param_write_int(plist, "JPEGQ", &jdev->JPEGQ)) < 0)
+ code = ecode;
+ if ((ecode = param_write_float(plist, "QFactor", &jdev->QFactor)) < 0)
+ code = ecode;
+
+ return code;
+}
+
+/* Put parameters. */
+private int
+jpeg_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_jpeg *jdev = (gx_device_jpeg *)dev;
+ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ int jq = jdev->JPEGQ;
+ float qf = jdev->QFactor;
+
+ switch ( code = param_read_int(plist, (param_name = "JPEGQ"), &jq) )
+ {
+ case 0:
+ if ( jq < 0 || jq > 100 )
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto jqe;
+ default:
+ ecode = code;
+jqe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+
+ switch ( code = param_read_float(plist, (param_name = "QFactor"), &qf) )
+ {
+ case 0:
+ if ( qf < 0.0 || qf > 1.0e6 )
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto qfe;
+ default:
+ ecode = code;
+qfe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gdev_prn_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ jdev->JPEGQ = jq;
+ jdev->QFactor = qf;
+ return 0;
+}
+
+/* Send the page to the file. */
+private int
+jpeg_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ gx_device_jpeg *jdev = (gx_device_jpeg *)pdev;
+ gs_memory_t *mem = pdev->memory;
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte *in = gs_alloc_bytes(mem, line_size, "jpeg_print_page(in)");
+ /* The current implementation of the DCTE filter */
+ /* requires that we allocate this with gs_malloc! */
+ jpeg_compress_data *jcdp =
+ gs_malloc(1, sizeof(*jcdp), "jpeg_print_page(jpeg_compress_data)");
+ byte *fbuf = 0;
+ uint fbuf_size;
+ byte *jbuf = 0;
+ uint jbuf_size;
+ int lnum;
+ int code;
+ stream_DCT_state state;
+ stream fstrm, jstrm;
+
+ static const stream_procs filter_write_procs =
+ { s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+ };
+
+ if ( jcdp == 0 || in == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto fail;
+ }
+ /* Create the DCT decoder state. */
+ state.template = &jcdp->template;
+ state.memory = 0;
+ state.QFactor = 1.0; /* disable quality adjustment in zfdcte.c */
+ state.ColorTransform = 1; /* default for RGB */
+ /* We insert no markers, allowing the IJG library to emit */
+ /* the format it thinks best. */
+ state.NoMarker = true; /* do not insert our own Adobe marker */
+ state.Markers.data = 0;
+ state.Markers.size = 0;
+ state.data.compress = jcdp;
+ if ( (code = gs_jpeg_create_compress(&state)) < 0 )
+ goto fail;
+ jcdp->cinfo.image_width = pdev->width;
+ jcdp->cinfo.image_height = pdev->height;
+ switch (pdev->color_info.depth) {
+ case 24:
+ jcdp->cinfo.input_components = 3;
+ jcdp->cinfo.in_color_space = JCS_RGB;
+ break;
+ case 8:
+ jcdp->cinfo.input_components = 1;
+ jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ }
+ /* Set compression parameters. */
+ if ( (code = gs_jpeg_set_defaults(&state)) < 0 )
+ goto done;
+ if (jdev->JPEGQ > 0)
+ { code = gs_jpeg_set_quality(&state, jdev->JPEGQ, TRUE);
+ if ( code < 0 )
+ goto done;
+ }
+ else if (jdev->QFactor > 0.0)
+ { code = gs_jpeg_set_linear_quality(&state,
+ (int) (min(jdev->QFactor, 100.0)
+ * 100.0 + 0.5),
+ TRUE);
+ if ( code < 0 )
+ goto done;
+ }
+ jcdp->cinfo.restart_interval = 0;
+ jcdp->cinfo.density_unit = 1; /* dots/inch (no #define or enum) */
+ jcdp->cinfo.X_density = pdev->HWResolution[0];
+ jcdp->cinfo.Y_density = pdev->HWResolution[1];
+ /* Create the filter. */
+ jcdp->template = s_DCTE_template;
+ /* Make sure we get at least a full scan line of input. */
+ state.scan_line_size = jcdp->cinfo.input_components *
+ jcdp->cinfo.image_width;
+ jcdp->template.min_in_size =
+ max(s_DCTE_template.min_in_size, state.scan_line_size);
+ /* Make sure we can write the user markers in a single go. */
+ jcdp->template.min_out_size =
+ max(s_DCTE_template.min_out_size, state.Markers.size);
+
+ /* Set up the streams. */
+ fbuf_size = max(512 /* arbitrary */, jcdp->template.min_out_size);
+ jbuf_size = jcdp->template.min_in_size;
+ if ( (fbuf = gs_alloc_bytes(mem, fbuf_size, "jpeg_print_page(fbuf)")) == 0 ||
+ (jbuf = gs_alloc_bytes(mem, jbuf_size, "jpeg_print_page(jbuf)")) == 0
+ )
+ { code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ swrite_file(&fstrm, prn_stream, fbuf, fbuf_size);
+ s_std_init(&jstrm, jbuf, jbuf_size, &filter_write_procs,
+ s_mode_write);
+ jstrm.memory = mem;
+ jstrm.state = (stream_state *)&state;
+ jstrm.procs.process = state.template->process;
+ jstrm.strm = &fstrm;
+ if ( state.template->init )
+ (*state.template->init)(jstrm.state);
+
+ /* Copy the data to the output. */
+ for ( lnum = 0; lnum < pdev->height; ++lnum )
+ { byte *data;
+ uint ignore_used;
+
+ gdev_prn_get_bits(pdev, lnum, in, &data);
+ sputs(&jstrm, data, state.scan_line_size, &ignore_used);
+ }
+
+ /* Wrap up. */
+ sclose(&jstrm);
+ sflush(&fstrm);
+ jcdp = 0;
+done:
+ gs_free_object(mem, jbuf, "jpeg_print_page(jbuf)");
+ gs_free_object(mem, fbuf, "jpeg_print_page(fbuf)");
+ if ( jcdp )
+ gs_jpeg_destroy(&state); /* frees *jcdp */
+ gs_free_object(mem, in, "jpeg_print_page(in)");
+ return code;
+fail:
+ if ( jcdp )
+ gs_free(jcdp, 1, sizeof(*jcdp),
+ "jpeg_print_page(jpeg_compress_data)");
+ gs_free_object(mem, in, "jpeg_print_page(in)");
+ return code;
+#undef jcdp
+}
diff --git a/gs/src/gdevl256.c b/gs/src/gdevl256.c
new file mode 100644
index 000000000..c01fd159d
--- /dev/null
+++ b/gs/src/gdevl256.c
@@ -0,0 +1,311 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevl256.c */
+/* Ghostscript driver for 256-color VGA modes with Linux and vgalib */
+/* This Driver was derived from the BGI-Driver. It was written
+ only for my own purpose. I never planned to release it or send
+ it to others. So, if something doesn't work, you may send
+ me a short note, but don't expect me to correct it. I will
+ try my very best, but i have some work to do.
+
+ Ludger Kunz | ____________|Tel.: 02371/566-230
+ FernUniversitaet Hagen| /| / / \ |FAX: 02371/52212
+ Lehrgebiet ES | / |/ /_ \ |EMAIL:
+ Frauenstuhlweg 31 | / |\ / \ |ludger.kunz@fernuni-hagen.de
+ 58644 Iserlohn |/___|_\/_______\|
+ */
+#include "gx.h"
+#include "gxdevice.h"
+#include "gserrors.h"
+
+#include <errno.h>
+#include <vga.h>
+#include <vgagl.h>
+
+/* The color map for dynamically assignable colors. */
+#define first_dc_index 64
+private int next_dc_index;
+
+#define dc_hash_size 293 /* prime, >num_dc */
+typedef struct {
+ ushort rgb, index;
+} dc_entry;
+private dc_entry dynamic_colors[dc_hash_size + 1];
+
+#define XDPI 60 /* to get a more-or-less square aspect ratio */
+#define YDPI 60
+
+#ifndef A4 /*Letter size*/
+#define YSIZE (20.0 * YDPI / 2.5)
+#define XSIZE (8.5 / 11)*YSIZE /* 8.5 x 11 inch page, by default */
+#else /* A4 paper */
+#define XSIZE 8.3 /*8.27*/
+#define YSIZE 11.7 /*11.69*/
+#endif
+
+
+/* The device descriptor */
+typedef struct gx_device_lvga256 {
+ gx_device_common;
+} gx_device_lvga256;
+
+#define lvga256dev ((gx_device_lvga256 *)dev)
+
+private dev_proc_open_device (lvga256_open);
+private dev_proc_close_device (lvga256_close);
+private dev_proc_map_rgb_color (lvga256_map_rgb_color);
+private dev_proc_map_color_rgb (lvga256_map_color_rgb);
+private dev_proc_fill_rectangle (lvga256_fill_rectangle);
+private dev_proc_tile_rectangle (lvga256_tile_rectangle);
+private dev_proc_copy_mono (lvga256_copy_mono);
+private dev_proc_copy_color (lvga256_copy_color);
+private dev_proc_draw_line (lvga256_draw_line);
+
+private gx_device_procs lvga256_procs =
+{
+ lvga256_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ lvga256_close,
+ lvga256_map_rgb_color,
+ lvga256_map_color_rgb,
+ lvga256_fill_rectangle,
+ lvga256_tile_rectangle,
+ lvga256_copy_mono,
+ lvga256_copy_color,
+ lvga256_draw_line
+};
+
+gx_device_lvga256 far_data gs_lvga256_device =
+{ std_device_color_body(gx_device_lvga256, &lvga256_procs, "lvga256",
+ 0, 0, /* width and height are set in lvga256_open */
+ 1, 1, /* density is set in lvga256_open */
+ /*dci_color(*/8, 31, 4/*)*/)
+};
+
+/* Open the LINUX driver for graphics mode */
+int
+lvga256_open (gx_device * dev)
+{
+ int vgamode;
+ int width, height;
+
+ vga_init();
+ vgamode = vga_getdefaultmode ();
+ if (vgamode == -1)
+ vgamode = G320x200x256;
+ vga_setmode (vgamode);
+ gl_setcontextvga (vgamode);
+ width = vga_getxdim();
+ height = vga_getydim();
+ dev->y_pixels_per_inch = height / 12.0;
+ dev->x_pixels_per_inch = dev->y_pixels_per_inch;
+ gx_device_set_width_height(dev, width, height);
+ {
+ int c;
+
+ for (c = 0; c < 64; c++) {
+ static const byte c2[10] =
+ {0, 42, 0, 0, 0, 0, 0, 0, 21, 63};
+
+ gl_setpalettecolor (c, c2[(c >> 2) & 9], c2[(c >> 1) & 9], c2[c & 9]);
+ }
+ }
+ /* Initialize the dynamic color table. */
+ memset (dynamic_colors, 0, (dc_hash_size + 1) * sizeof (dc_entry));
+ next_dc_index = first_dc_index;
+
+ return 0;
+}
+
+/* Close the LINUX driver */
+int
+lvga256_close (gx_device * dev)
+{
+ vga_setmode (TEXT);
+ return 0;
+}
+
+/* Map a r-g-b color to a palette index. */
+/* The first 64 entries of the color map are set */
+/* for compatibility with the older display modes: */
+/* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
+gx_color_index
+lvga256_map_rgb_color (gx_device * dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+#define cv_bits(v,n) (v >> (gx_color_value_bits - n))
+ ushort r5 = cv_bits (r, 5), g5 = cv_bits (g, 5), b5 = cv_bits (b, 5);
+ static const byte cube_bits[32] =
+ {0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 9
+ };
+ uint cx = ((uint) cube_bits[r5] << 2) + ((uint) cube_bits[g5] << 1) +
+ (uint) cube_bits[b5];
+ ushort rgb;
+ register dc_entry _ds *pdc;
+
+ /* Check for a color on the cube. */
+ if (cx < 64)
+ return (gx_color_index) cx;
+ /* Not on the cube, check the dynamic color table. */
+ rgb = (r5 << 10) + (g5 << 5) + b5;
+ for (pdc = &dynamic_colors[rgb % dc_hash_size]; pdc->rgb != 0; pdc++) {
+ if (pdc->rgb == rgb)
+ return (gx_color_index) (pdc->index);
+ }
+ if (pdc == &dynamic_colors[dc_hash_size]) { /* Wraparound */
+ for (pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++) {
+ if (pdc->rgb == rgb)
+ return (gx_color_index) (pdc->index);
+ }
+ }
+ if (next_dc_index == 256) { /* No space left, report failure. */
+ return gx_no_color_index;
+ }
+ /* Not on the cube, and not in the dynamic table. */
+ /* Put in the dynamic table if space available. */
+ {
+ int i = next_dc_index++;
+
+ pdc->rgb = rgb;
+ pdc->index = i;
+ gl_setpalettecolor (i,cv_bits (r, 6), cv_bits (g, 6), cv_bits (b, 6));
+ return (gx_color_index) i;
+ }
+}
+
+int
+lvga256_map_color_rgb (gx_device * dev, gx_color_index color,
+ unsigned short prgb[3])
+{
+/* gl_getpalettecolor (color,(int *)&prgb[0],(int *)&prgb[1],(int *)&prgb[2]);*/
+ prgb[0]=gx_max_color_value;
+ prgb[1]=gx_max_color_value;
+ prgb[2]=gx_max_color_value;
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+int
+lvga256_copy_mono (gx_device * dev,
+ const byte * base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+ const byte *ptr_line = base + (sourcex >> 3);
+ int left_bit = 0x80 >> (sourcex & 7);
+ int dest_y = y, end_x = x + w;
+ int invert = 0;
+ int color;
+
+ fit_copy (dev,base, sourcex, raster, id, x, y, w, h);
+ if (zero == gx_no_color_index) {
+ if (one == gx_no_color_index)
+ return 0;
+ color = (int) one;
+ }
+ else {
+ if (one == gx_no_color_index) {
+ color = (int) zero;
+ invert = -1;
+ }
+ else { /* Pre-clear the rectangle to zero */
+ gl_fillbox (x, y, w, h, 0);
+ color = (int) one;
+ }
+ }
+ while (h--) { /* for each line */
+ const byte *ptr_source = ptr_line;
+ register int dest_x = x;
+ register int bit = left_bit;
+
+ while (dest_x < end_x) { /* for each bit in the line */
+ if ((*ptr_source ^ invert) & bit) {
+ gl_setpixel (dest_x, dest_y, color);
+ }
+ dest_x++;
+ if ((bit >>= 1) == 0)
+ bit = 0x80, ptr_source++;
+ }
+ dest_y++;
+ ptr_line += raster;
+ }
+ return 0;
+}
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 4 bits instead of 1 when device driver has color. */
+int
+lvga256_copy_color (gx_device * dev,
+ const byte * base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ fit_copy (dev,base, sourcex, raster, id, x, y, w, h);
+ if (gx_device_has_color (dev)) { /* color device, four bits per pixel */
+ const byte *line = base + sourcex;
+
+ gl_putbox (x, y, w, h, line);
+ }
+ else { /* monochrome device: one bit per pixel */
+ /* bit map is the same as lvga256_copy_mono: one bit per pixel */
+ lvga256_copy_mono (dev, base, sourcex, raster, id, x, y, w, h,
+ (gx_color_index) 0, (gx_color_index) 255);
+ }
+ return 0;
+}
+
+/* Fill a rectangle. */
+int
+lvga256_fill_rectangle (gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ fit_fill (dev,x,y,w,h);
+ gl_fillbox (x, y, w, h, color);
+ return 0;
+}
+
+/* Tile a rectangle. If neither color is transparent, */
+/* pre-clear the rectangle to color0 and just tile with color1. */
+/* This is faster because of how lvga256_copy_mono is implemented. */
+/* Note that this also does the right thing for colored tiles. */
+int
+lvga256_tile_rectangle (gx_device * dev, const gx_tile_bitmap * tile,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
+ int px, int py)
+{
+ if (czero != gx_no_color_index && cone != gx_no_color_index) {
+ lvga256_fill_rectangle (dev, x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ return gx_default_tile_rectangle (dev, tile, x, y, w, h, czero, cone, px, py);
+}
+
+/* Draw a line */
+int
+lvga256_draw_line (gx_device * dev, int x0, int y0, int x1, int y1,
+ gx_color_index color)
+{
+ gl_line (x0, y0, x1, y1, color);
+ return 0;
+}
diff --git a/gs/src/gdevlbp8.c b/gs/src/gdevlbp8.c
new file mode 100644
index 000000000..19ea00bb6
--- /dev/null
+++ b/gs/src/gdevlbp8.c
@@ -0,0 +1,213 @@
+/* Copyright (C) 1991, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevlbp8.c */
+/* Canon LBP-8II and LIPS III driver */
+#include "gdevprn.h"
+
+/*
+ Modifications:
+ 2.2.97 Lauri Paatero
+ Changed CSI command into ESC [. DCS commands may still need to be changed
+ (to ESC P).
+ 4.9.96 Lauri Paatero
+ Corrected LBP-8II margins again. Real problem was that (0,0) is NOT
+ in upper left corner.
+ Now using relative addressing for vertical addressing. This avoids
+problems
+ when printing to paper with wrong size.
+ 18.6.96 Lauri Paatero, lauri.paatero@paatero.pp.fi
+ Corrected LBP-8II margins.
+ Added logic to recognize (and optimize away) long strings of 00's in data.
+ For LBP-8II removed use of 8-bit CSI (this does not work if 8-bit character
+ set has been configured in LBP-8II. (Perhaps this should also be done
+ for LBP-8III?)
+ Original versions:
+ LBP8 driver: Tom Quinn (trq@prg.oxford.ac.uk)
+ LIPS III driver: Kenji Okamoto (okamoto@okamoto.cias.osakafu-u.ac.jp)
+*/
+
+
+#define X_DPI 300
+#define Y_DPI 300
+#define LINE_SIZE ((X_DPI * 85 / 10 + 7) / 8) /* bytes per line */
+
+/* The device descriptors */
+private dev_proc_print_page(lbp8_print_page);
+private dev_proc_print_page(lips3_print_page);
+
+gx_device_printer far_data gs_lbp8_device =
+ prn_device(prn_std_procs, "lbp8",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.16, 0.2, 0.32, 0.21, /* margins: left, bottom, right, top */
+ 1, lbp8_print_page);
+
+gx_device_printer far_data gs_lips3_device =
+ prn_device(prn_std_procs, "lips3",
+ 82, /* width_10ths, 8.3" */
+ 117, /* height_10ths, 11.7" */
+ X_DPI, Y_DPI,
+ 0.16, 0.27, 0.23, 0.27, /* margins */
+ 1, lips3_print_page);
+
+/* ------ Internal routines ------ */
+
+#define ESC 0x1b
+#define CSI 0233
+#define DCS 0220
+#define ST 0234
+
+static const char lbp8_init[] = {
+ ESC, ';', ESC, 'c', ESC, ';', /* reset, ISO */
+ ESC, '[', '2', '&', 'z', /* fullpaint mode */
+ ESC, '[', '1', '4', 'p', /* select page type (A4) */
+ ESC, '[', '1', '1', 'h', /* set mode */
+ ESC, '[', '7', ' ', 'I', /* select unit size (300dpi)*/
+ ESC, '[', '6', '3', 'k', /* Move 63 dots up (to top of printable area) */
+};
+
+static const char *lbp8_end = NULL;
+
+static const char lips3_init[] = {
+ ESC, '<', /* soft reset */
+ DCS, '0', 'J', ST, /* JOB END */
+ DCS, '3', '1', ';', '3', '0', '0', ';', '2', 'J', ST, /* 300dpi, LIPS3 JOB START */
+ ESC, '<', /* soft reset */
+ DCS, '2', 'y', 'P', 'r', 'i', 'n', 't', 'i', 'n', 'g', '(', 'g', 's', ')', ST, /* Printing (gs) display */
+ ESC, '[', '?', '1', 'l', /* auto cr-lf disable */
+ ESC, '[', '?', '2', 'h', /* auto ff disable */
+ ESC, '[', '1', '1', 'h', /* set mode */
+ ESC, '[', '7', ' ', 'I', /* select unit size (300dpi)*/
+ ESC, '[', 'f' /* move to home position */
+};
+
+static const char lips3_end[] = {
+ DCS, '0', 'J', ST /* JOB END */
+};
+
+/* Send the page to the printer. */
+private int
+can_print_page(gx_device_printer *pdev, FILE *prn_stream,
+ const char *init, int init_size, const char *end, int end_size)
+{
+ char data[LINE_SIZE*2];
+ char *out_data;
+ int last_line_nro = 0;
+
+ fwrite(init, init_size, 1, prn_stream); /* initialize */
+
+ /* Send each scan line in turn */
+ {
+ int lnum;
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte rmask = (byte)(0xff << (-pdev->width & 7));
+
+ for ( lnum = 0; lnum < pdev->height; lnum++ ) {
+ char *end_data = data + LINE_SIZE;
+ gdev_prn_copy_scan_lines(pdev, lnum,
+ (byte *)data, line_size);
+ /* Mask off 1-bits beyond the line width. */
+ end_data[-1] &= rmask;
+ /* Remove trailing 0s. */
+ while ( end_data > data && end_data[-1] == 0 )
+ end_data--;
+ if ( end_data != data ) {
+ int num_cols = 0;
+ int out_count;
+ int zero_count;
+ out_data = data;
+
+ /* move down */
+ fprintf(prn_stream, "%c[%de",
+ ESC, lnum-last_line_nro );
+ last_line_nro = lnum;
+
+ while (out_data < end_data) {
+ /* Remove leading 0s*/
+ while(out_data < end_data && *out_data == 0) {
+ num_cols += 8;
+ out_data++;
+ }
+
+ out_count = end_data - out_data;
+ zero_count = 0;
+
+ /* if there is a lot data, find if there is sequence of zeros */
+ if (out_count>22) {
+
+ out_count = 1;
+
+ while(out_data+out_count+zero_count < end_data) {
+ if (out_data[zero_count+out_count] != 0) {
+ out_count += 1+zero_count;
+ zero_count = 0;
+ }
+ else {
+ zero_count++;
+ if (zero_count>20)
+ break;
+ }
+ }
+
+ }
+
+ if (out_count==0)
+ break;
+
+ /* move down and across*/
+ fprintf(prn_stream, "%c[%d`",
+ ESC, num_cols );
+ /* transfer raster graphic command */
+ fprintf(prn_stream, "%c[%d;%d;300;.r",
+ ESC, out_count, out_count);
+
+ /* send the row */
+ fwrite(out_data, sizeof(char),
+ out_count, prn_stream);
+
+ out_data += out_count+zero_count;
+ num_cols += 8*(out_count+zero_count);
+ }
+ }
+ }
+ }
+
+ /* eject page */
+ fprintf(prn_stream, "%c=", ESC);
+
+ /* terminate */
+ if (end != NULL)
+ fwrite(end, end_size, 1, prn_stream);
+
+ return 0;
+}
+
+/* Print an LBP-8 page. */
+private int
+lbp8_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return can_print_page(pdev, prn_stream, lbp8_init, sizeof(lbp8_init),
+ lbp8_end, sizeof(lbp8_end));
+}
+
+/* Print a LIPS III page. */
+private int
+lips3_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ return can_print_page(pdev, prn_stream, lips3_init, sizeof(lips3_init),
+ lips3_end, sizeof(lips3_end));
+}
diff --git a/gs/src/gdevlj56.c b/gs/src/gdevlj56.c
new file mode 100644
index 000000000..b83036633
--- /dev/null
+++ b/gs/src/gdevlj56.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevlj56.c */
+/* H-P LaserJet 5 & 6 drivers for Ghostscript */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+#include "gdevpxat.h"
+#include "gdevpxen.h"
+#include "gdevpxop.h"
+
+/* Define the default resolution. */
+#ifndef X_DPI
+# define X_DPI 600
+#endif
+#ifndef Y_DPI
+# define Y_DPI 600
+#endif
+
+/* Define the number of blank lines that make it worthwhile to */
+/* start a new image. */
+#define MIN_SKIP_LINES 2
+
+/* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
+#define W sizeof(word)
+
+private dev_proc_open_device(ljet5_open);
+private dev_proc_close_device(ljet5_close);
+private dev_proc_print_page(ljet5_print_page);
+
+private gx_device_procs ljet5_procs =
+ prn_procs(ljet5_open, gdev_prn_output_page, ljet5_close);
+
+gx_device_printer far_data gs_lj5mono_device =
+ prn_device(ljet5_procs, "lj5mono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0,
+ 1, ljet5_print_page);
+
+private gx_device_procs lj5gray_procs =
+ prn_color_procs(ljet5_open, gdev_prn_output_page, ljet5_close,
+ gx_default_gray_map_rgb_color,
+ gx_default_gray_map_color_rgb);
+
+gx_device_printer far_data gs_lj5gray_device = {
+ prn_device_body(gx_device_printer, lj5gray_procs, "lj5gray",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0,
+ 1, 8, 255, 0, 256, 1, ljet5_print_page)
+};
+
+#define ppdev ((gx_device_printer *)pdev)
+
+/* Write a 'canned' data sequence. */
+#define fwrite_bytes(bytes, strm) fwrite(bytes, 1, sizeof(bytes), strm)
+
+/* Utilities for writing data values. */
+/* H-P printers only support little-endian data, so that's what we emit. */
+#define da(a) pxt_attr_ubyte, (a)
+private void
+put_a(px_attribute_t a, FILE *prn_stream)
+{ fputc(pxt_attr_ubyte, prn_stream);
+ fputc(a, prn_stream);
+}
+#define dub(b) pxt_ubyte, (byte)(b)
+#define ds(i) (byte)(i), (byte)((i) >> 8)
+private void
+put_s(uint i, FILE *prn_stream)
+{ fputc((byte)i, prn_stream);
+ fputc((byte)(i >> 8), prn_stream);
+}
+#define dus(i) pxt_uint16, ds(i)
+private void
+put_us(uint i, FILE *prn_stream)
+{ fputc(pxt_uint16, prn_stream);
+ put_s(i, prn_stream);
+}
+#define dusp(ix,iy) pxt_uint16_xy, ds(ix), ds(iy)
+private void
+put_usp(uint ix, uint iy, FILE *prn_stream)
+{ fputc(pxt_uint16_xy, prn_stream);
+ put_s(ix, prn_stream);
+ put_s(iy, prn_stream);
+}
+#define dss(i) pxt_sint16, ds(i)
+private void
+put_ss(int i, FILE *prn_stream)
+{ fputc(pxt_sint16, prn_stream);
+ put_s((uint)i, prn_stream);
+}
+#define dl(l) ds(l), ds((l) >> 16)
+private void
+put_l(ulong l, FILE *prn_stream)
+{ put_s((uint)l, prn_stream);
+ put_s((uint)(l >> 16), prn_stream);
+}
+
+/* Open the printer, writing the stream header. */
+private int
+ljet5_open(gx_device *pdev)
+{ int code = gdev_prn_open(pdev);
+
+ if ( code < 0 )
+ return code;
+ code = gdev_prn_open_printer(pdev, true);
+ if ( code < 0 )
+ return code;
+ { FILE *prn_stream = ppdev->file;
+ static const byte stream_header[] = {
+ da(pxaUnitsPerMeasure),
+ dub(0), da(pxaMeasure),
+ dub(eErrorPage), da(pxaErrorReport),
+ pxtBeginSession,
+ dub(0), da(pxaSourceType),
+ dub(eBinaryLowByteFirst), da(pxaDataOrg),
+ pxtOpenDataSource
+ };
+
+ fputs("\033%-12345X@PJL ENTER LANGUAGE = PCLXL\n", prn_stream);
+ fputs(") HP-PCL XL;1;1\n", prn_stream);
+ put_usp((uint)(pdev->HWResolution[0] + 0.5),
+ (uint)(pdev->HWResolution[1] + 0.5), prn_stream);
+ fwrite_bytes(stream_header, prn_stream);
+ }
+ return 0;
+}
+
+/* Close the printer, writing the stream trailer. */
+private int
+ljet5_close(gx_device *pdev)
+{ int code = gdev_prn_open_printer(pdev, true);
+
+ if ( code < 0 )
+ return code;
+ { FILE *prn_stream = ppdev->file;
+ static const byte stream_trailer[] = {
+ pxtCloseDataSource,
+ pxtEndSession,
+ 033, '%', '-', '1', '2', '3', '4', '5', 'X'
+ };
+
+ fwrite_bytes(stream_trailer, prn_stream);
+ }
+ return gdev_prn_close(pdev);
+}
+
+/* Send the page to the printer. For now, just send the whole image. */
+private int
+ljet5_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ uint line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ uint line_size_words = (line_size + W - 1) / W;
+ uint out_size = line_size + (line_size / 127) + 1;
+ word *line = (word *)gs_malloc(line_size_words, W, "ljet5(line)");
+ byte *out = gs_malloc(out_size, 1, "ljet5(out)");
+ int code = 0;
+ int lnum;
+
+ if ( line == 0 || out == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+
+ /* Write the page header. */
+ { static const byte page_header[] = {
+ dub(ePortraitOrientation), da(pxaOrientation),
+ dub(eLetterPaper), da(pxaMediaSize),
+ dub(eAutoSelect), da(pxaMediaSource),
+ pxtBeginPage,
+ dusp(0, 0), da(pxaPoint),
+ pxtSetCursor
+ };
+ static const byte mono_header[] = {
+ dub(eGray), da(pxaColorSpace),
+ dub(e8Bit), da(pxaPaletteDepth),
+ pxt_ubyte_array, pxt_ubyte, 2, 0xff, 0x00, da(pxaPaletteData),
+ pxtSetColorSpace
+ };
+ static const byte gray_header[] = {
+ dub(eGray), da(pxaColorSpace),
+ pxtSetColorSpace
+ };
+
+ fwrite_bytes(page_header, prn_stream);
+ if ( pdev->color_info.depth == 1 )
+ fwrite_bytes(mono_header, prn_stream);
+ else
+ fwrite_bytes(gray_header, prn_stream);
+ }
+
+ /* Write the image header. */
+ { static const byte mono_image_header[] = {
+ da(pxaDestinationSize),
+ dub(eIndexedPixel), da(pxaColorMapping),
+ dub(e1Bit), da(pxaColorDepth),
+ pxtBeginImage
+ };
+ static const byte gray_image_header[] = {
+ da(pxaDestinationSize),
+ dub(eDirectPixel), da(pxaColorMapping),
+ dub(e8Bit), da(pxaColorDepth),
+ pxtBeginImage
+ };
+
+ put_us(pdev->width, prn_stream);
+ put_a(pxaSourceWidth, prn_stream);
+ put_us(pdev->height, prn_stream);
+ put_a(pxaSourceHeight, prn_stream);
+ put_usp(pdev->width, pdev->height, prn_stream);
+ if ( pdev->color_info.depth == 1 )
+ fwrite_bytes(mono_image_header, prn_stream);
+ else
+ fwrite_bytes(gray_image_header, prn_stream);
+ }
+
+ /* Write the image data, compressing each line. */
+ for ( lnum = 0; lnum < pdev->height; ++lnum )
+ { int ncompr;
+ static const byte line_header[] = {
+ da(pxaStartLine),
+ dus(1), da(pxaBlockHeight),
+ dub(eRLECompression), da(pxaCompressMode),
+ pxtReadImage
+ };
+
+ code = gdev_prn_copy_scan_lines(pdev, lnum, (byte *)line, line_size);
+ if ( code < 0 )
+ goto fin;
+ put_us(lnum, prn_stream);
+ fwrite_bytes(line_header, prn_stream);
+ ncompr = gdev_pcl_mode2compress(line, line + line_size_words, out);
+ if ( ncompr <= 255 )
+ { fputc(pxt_dataLengthByte, prn_stream);
+ fputc(ncompr, prn_stream);
+ }
+ else
+ { fputc(pxt_dataLength, prn_stream);
+ put_l(ncompr, prn_stream);
+ }
+ fwrite(out, 1, ncompr, prn_stream);
+ }
+
+ /* Finish up. */
+fin:
+ fputc(pxtEndImage, prn_stream);
+ fputc(pxtEndPage, prn_stream);
+done:
+ if ( out )
+ gs_free(out, out_size, 1, "ljet5(out)");
+ if ( line )
+ gs_free(line, line_size_words, W, "ljet5(out)");
+ return code;
+}
diff --git a/gs/src/gdevlp8k.c b/gs/src/gdevlp8k.c
new file mode 100644
index 000000000..ff1ff00c7
--- /dev/null
+++ b/gs/src/gdevlp8k.c
@@ -0,0 +1,412 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevlp8k.c */
+
+/* EPSON LP-8000 ESC-sequence Laser Printer driver for Ghostscript.
+
+This driver structure is most close to that of the Epson 'ESC/P 2' language
+printer driver "gdevescp.c" contributed by Richard Brown, but all the control
+sequences and data formats are totally different.
+
+The main driver strategy is as follows. The driver scans lines, skips empty
+ones, removes leading and trailing zeros for other lines, compresses the
+non-zero rest of each line and finally outputs the data.
+
+At the moment the driver supports only 300x300 DPI resolution. If somebody
+needs 240x240, another valid value for LP-8000 printer, he or she can try to
+play with the corresponding values in initialization and termination
+strings. Or I shall spend some extra time for hacking, if enough people
+encourage me to do it. (The only available in our laboratory "Operation
+guide" in Japanese does not contain any information about it. And LP-8000
+driver for Japanese Windows does not support this mode either.)
+
+
+The output data format is the following.
+
+1. Initialization string, pretty long and sophisticated, I don't know why it
+was necessary.
+
+2. Data bits for each line. The most general format includes both starting X
+and Y values as well as data type (simple or compressed).
+
+3. Termination string.
+
+
+ DATA FORMATS
+
+1. A simple (non-compressed) data format. By evident reasons it is NOT
+SUPPORTED by the driver and is discussed here just as a starting point for
+the future explanations. "\035" here is an alias for 0x1d ESC-character :
+
+"\035" "Starting X point in ASCII format" "X"
+"\035" "Starting Y point in ASCII format" "Y"
+"\035" "Number of data BYTES for this printer line in ASCII format" ";"
+"Number of POINTS to print in this line (equals to the
+(Number of BYTES)*8)" ";"
+"1;obi{I" "data BYTES for this line in BINARY format"
+
+Both X and Y printer coordinates are 60 pixels shifted from the corresponding
+coordinates of the Ghostscript display, that is X = x - 60, Y = y - 60. For
+example, 1 inch left margin requires the value of 300 - 60 = 240 for
+starting X printer coordinate. Similar, 1.5 inch top margin requires Y
+values to start from 300*1.5 - 60 = 390.
+
+The shortest possible abbreviation for the simple data format string is
+
+"\035" "Starting Y point in ASCII format" "Y"
+"\035" "Number of data BYTES for this printer line in ASCII format" ";"
+"Number of POINTS to print in this line (equals to the
+(Number of BYTES)*8)" ";"
+"1;obi{I" "data BYTES for this line in BINARY format"
+
+In this case the value of the starting X point is assumed to be equal to
+that for the previous line.
+
+An example of the data output for 2 printer lines
+
+"\035"315X"\035"240Y"\035"2;16;1;obi{I"0ff0""\035"241Y"\035"3;24;1;obi{I"0f000f"
+
+Here "0ff0" is an alias for 0x0f 0xf0 binary data, etc. The first line of the
+above example starts from X=315, Y=240 and consists of 2 data bytes
+resulting in 4 blank (white) points followed by 8 black points followed by 4
+white points on the paper. The second line starts from X=315, Y=241 and
+contains 3 data bytes resulting in output of 4 white, 4 black, 12 white and
+finally 4 black points.
+
+2. Compressed data format (SUPPORTED BY THE DRIVER).
+
+General description is as follows.
+
+"\035" "Starting X point in ASCII format" "X"
+"\035" "Starting Y point in ASCII format" "Y"
+"\035" "3bcI"
+"\035" "Total number of compressed BYTES in ASCII format" ";"
+"Number of POINTS to print in this line" ";"
+"1;obi{I" "compressed data BYTES for this line in BINARY format"
+"\035" "0bcI"
+
+Additional ESC-sequences "\035" "3bcI" and "\035" "0bcI" mean start and end
+of the compressed data format, respectively. As in the discussed above case
+of a non-compressed data format, the shortest abbreviation has the form of
+
+"\035" "Starting Y point in ASCII format" "Y"
+"\035" "Total number of compressed BYTES in ASCII format" ";"
+"Number of POINTS to print in this line" ";"
+"1;obi{I" "compressed data BYTES for this line in BINARY format"
+
+COMPRESSED DATA BYTES FORMAT has the form of
+
+"d1 d2 d3 d4 d4 count_d4 d5 d6 d6 count_d6 ... d(n-1) d(n-1) count_d(n-1) dn"
+
+Here dx (x = 1 ... n) means data in a BINARY format. Any 2 repeated bytes
+MUST follow by the count, otherwise the printer will interpret the next
+data byte as a counter. The count value indicates how many bytes of the
+same value should be INSERTED after the repeated ones. So, the total number of
+repeated bytes is (count + 2), not count. If there are only 2 equal data
+bytes somewhere in the data stream, they MUST follow by zero.
+
+Example of 2 compressed data strings.
+
+"\035"105X"\035"320Y"\035"3bcI"\035"3;2048;1;obi{I"0000fe"
+"\035"105X"\035"321Y"\035"11;2048;1;obi{I"0000021fffffe5fc000011"
+
+The first one containing 3 bytes of compressed data will result in empty
+(zero) line of 2048 blank points started from X=105, Y=320. The second one
+containing 11 compressed data bytes will produce the picture of 4*8 + 3 = 35
+white points followed by 5 + 16 + 0xe5*8 + 6 = 1859 black points followed by
+2 + 8*19 = 154 white points (total 2048 points) started from X=105, Y=321.
+
+Strictly speaking, it was not necessary to adjust the number of points to
+the byte boundary. I did it for the sake of simplicity. One more argument in
+favor of this step is that the error of positioning does not exceed (7 /
+300) inches or (7 / 118) cm, that is 0.6 mm, which is negligible, I guess.
+
+
+ADDITIONAL INFORMATION
+
+It is also possible to use LP-8000 printer with 180x180 DPI resolution as an
+"ibmpro" device from gdevepsn.c The only thing which should be corrected, is
+the value 0x30 in static const char ibmpro_init_string[]. Decimal 36
+fixes the 1,5 times elongation along the vertical axis. It is also
+recommended to choose the appropriate values for all margins. In my case it
+was 0.2, 0.6, 0, 0.3 in the device descriptor instead of the 0.2, 0.95, 0,
+1.0
+
+Nevertheless, typical Latex file looked so ugly after printing in this mode,
+that I preferred to spend several days for hacking the format of the Japanese
+Windows printer output for 300 DPI resolution and create my own driver.
+
+Any suggestions, corrections, critical comments, etc. are welcome!
+
+Oleg Fat'yanov <faty1@rlem.titech.ac.jp>
+
+*/
+
+
+#include "gdevprn.h"
+
+#ifndef X_DPI
+#define X_DPI 300
+#endif
+
+#ifndef Y_DPI
+#define Y_DPI 300
+#endif
+
+#define L_MARGIN 0.25
+#define B_MARGIN 0.25
+#define R_MARGIN 0.25
+#define T_MARGIN 0.25
+
+private dev_proc_print_page(lp8000_print_page);
+
+gx_device_printer far_data gs_lp8000_device =
+ prn_device(prn_std_procs, "lp8000",
+ DEFAULT_WIDTH_10THS,
+ DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ L_MARGIN, B_MARGIN, R_MARGIN, T_MARGIN,
+ 1, lp8000_print_page);
+
+
+private int
+lp8000_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int in_size = line_size;
+
+ byte *buf1 = (byte *)gs_malloc(in_size, 1, "lp8000_print_page(buf1)");
+ byte *buf2 = (byte *)gs_malloc(in_size, 1, "lp8000_print_page(buf2)");
+ byte *in = buf1;
+ byte *out = buf2;
+
+ int lnum, top, bottom, left, width;
+ int count, i, left1, left2, left0;
+
+/* Check memory allocations */
+
+ if ( buf1 == 0 || buf2 == 0 )
+ { if ( buf1 )
+ gs_free((char *)buf1, in_size, 1, "lp8000_print_page(buf1)");
+
+ if ( buf2 )
+ gs_free((char *)buf2, in_size, 1, "lp8000_print_page(buf2)");
+
+ return_error(gs_error_VMerror);
+ }
+
+/* Initialize the printer */
+
+ fwrite("\033\001@EJL \n",1,8,prn_stream);
+ fwrite("@EJL EN LA=ESC/PAGE\n",1,20,prn_stream);
+ fwrite("\035rhE\033\001@EJL \n",1,12,prn_stream);
+ fwrite("@EJL SE LA=ESC/PAGE\n",1,20,prn_stream);
+ fwrite("@EJL SET PU=1 PS=A4 ZO=OFF\n",1,27,prn_stream);
+ fwrite("@EJL EN LA=ESC/PAGE\n",1,20,prn_stream);
+ fwrite("\0350;0.24muE\0352;300;300drE",1,23,prn_stream);
+ fwrite("\0350;300;300drE\0351tsE\0351mmE",1,23,prn_stream);
+ fwrite("\0357isE\0355iaF\0355ipP\03514psE\0350poE",1,26,prn_stream);
+ fwrite("\03560;60loE\0350X\0350Y",1,15,prn_stream);
+ fwrite("\0350;0;2360;3388caE",1,17,prn_stream);
+ fwrite("\0351cmE\0350alfP",1,11,prn_stream);
+ fwrite("\0350affP\0350boP\0350abP",1,16,prn_stream);
+ fwrite("\0354ilG\0350bcI\0350sarG",1,16,prn_stream);
+ fwrite("\0351;0;100spE\0352owE",1,16,prn_stream);
+
+/* Here the common part of the initialization string ends */
+
+
+/* Calculate the PRINTER_LEFT_MARGIN = device_left_margin - 60 adjusted to
+the byte boundary. Save this value for future comparison and set the
+starting X value of the printer line.
+*/
+ left1 = (int) (L_MARGIN * pdev->x_pixels_per_inch) - 60;
+ left1 = (left1 >> 3) << 3;
+ left0 = left1;
+
+ fwrite("\035",1,1,prn_stream);
+ fprintf(prn_stream,"%d",left1);
+ fwrite("X",1,1,prn_stream);
+
+ /* Set the compressed data format */
+ fwrite("\0353bcI",1,5,prn_stream);
+
+ top = T_MARGIN * pdev->y_pixels_per_inch;
+ bottom = pdev->height - B_MARGIN * pdev->y_pixels_per_inch;
+
+ left = ( (int) (L_MARGIN * pdev->x_pixels_per_inch) ) >> 3 ;
+ width = ((pdev->width - (int)(R_MARGIN * pdev->x_pixels_per_inch)) >> 3) - left;
+
+ /*
+ ** Print the page:
+ */
+
+ for ( lnum = top; lnum < bottom ; )
+
+
+ {
+ byte *in_data;
+ byte *inp;
+ byte *in_end;
+ byte *outp;
+ register byte *p, *q;
+ int lcnt;
+
+ /*
+ ** Check buffer for 0 data.
+ */
+
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ while ( in_data[0] == 0 &&
+ !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
+ lnum < bottom )
+ {
+ lnum++;
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ }
+
+ if(lnum == bottom ) break;
+ /* finished with this page */
+
+
+ lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+
+ inp = in + left;
+ in_end = inp + width;
+
+/* Remove trailing 0s form the scan line data */
+
+ while (in_end > inp && in_end[-1] == 0)
+ {
+ in_end--;
+ }
+
+/* Remove leading 0s form the scan line data */
+
+ for(left2 = 0; inp < in_end && inp[0] == 0; inp++,left2++);
+
+/* Recalculate starting X value */
+
+ left2 = left1 + (left2 << 3);
+
+
+
+/* Compress non-zero data for this line*/
+
+ outp = out;
+
+ for( p = inp, q = inp + 1 ; q < in_end ; )
+ {
+ if( *p != *q++ )
+ {
+ /*
+ Copy non-repeated bytes
+ to the output buffer
+ */
+ *outp++ = *p++;
+ }
+ else
+ {
+ for (count = 2; ( *p == *q ) && (q < in_end); q++, count++);
+
+ /*
+ Copy repeated bytes and counts to the output buffer.
+ As long as count is <= 255, additional step is necessary
+ for a long repeated sequence
+ */
+
+ while (count > 257)
+ {
+ *outp++ = *p;
+ *outp++ = *p;
+ *outp++ = 255;
+ p += 257;
+ count -=257;
+ }
+ *outp++ = *p;
+ *outp++ = *p;
+ *outp++ = count - 2;
+ p += count;
+ q = p+1;
+ }
+ }
+
+/* The next line is necessary just in case of a single non-repeated byte at
+the end of the input buffer */
+
+if (p == (in_end - 1)) *outp++ = *p;
+
+/* End of the compression procedure */
+
+
+/* Set a new value of the starting X point, if necessary */
+
+if (left2 != left0)
+ {
+ left0 = left2;
+ fwrite("\035",1,1,prn_stream);
+ fprintf(prn_stream,"%d",left2);
+ fwrite("X",1,1,prn_stream);
+ }
+
+/* Output the data string to the printer.
+Y coordinate of the printer equals (lnum - 60)
+*/
+
+ fwrite("\035",1,1,prn_stream);
+ fprintf(prn_stream,"%d",lnum-60);
+ fwrite("Y\035",1,2,prn_stream);
+ fprintf(prn_stream,"%d;",(outp - out));
+ fprintf(prn_stream,"%d;",(in_end - inp) << 3);
+ fwrite("1;0bi{I",1,7,prn_stream);
+ fwrite(out,1,(outp - out),prn_stream);
+
+ lnum++;
+
+ }
+
+/* Send the termination string */
+
+ fwrite("\0350bcI",1,5,prn_stream);
+ fwrite("\0351coO",1,5,prn_stream);
+ fwrite("\035rhE",1,4,prn_stream);
+
+ fwrite("\033\001@EJL \n",1,8,prn_stream);
+ fwrite("@EJL SE LA=ESC/PAGE\n",1,20,prn_stream);
+ fwrite("@EJL SET PU=1 PS=A4 ZO=OFF\n",1,27,prn_stream);
+ fwrite("@EJL EN LA=ESC/PAGE\n",1,20,prn_stream);
+ fwrite("\0350;0.24muE\0352;300;300drE",1,23,prn_stream);
+ fwrite("\0350;300;300drE\0351tsE\0351mmE",1,23,prn_stream);
+ fwrite("\0357isE\0355iaF\0355ipP\03514psE\0350poE",1,26,prn_stream);
+ fwrite("\03560;60loE\0350X\0350Y",1,15,prn_stream);
+ fwrite("\0350;0;2360;3388caE",1,17,prn_stream);
+ fwrite("\0351cmE\0350alfP",1,11,prn_stream);
+ fwrite("\0350affP\0350boP\0350abP",1,16,prn_stream);
+ fwrite("\0354ilG\0350bcI\0350sarG",1,16,prn_stream);
+ fwrite("\035rhE",1,4,prn_stream);
+ fwrite("\033\001@EJL \n",1,8,prn_stream);
+ fwrite("\033\001@EJL \n",1,8,prn_stream);
+
+ fflush(prn_stream);
+
+ gs_free((char *)buf2, in_size, 1, "lp8000_print_page(buf2)");
+ gs_free((char *)buf1, in_size, 1, "lp8000_print_page(buf1)");
+ return 0;
+}
diff --git a/gs/src/gdevm1.c b/gs/src/gdevm1.c
new file mode 100644
index 000000000..715590ec5
--- /dev/null
+++ b/gs/src/gdevm1.c
@@ -0,0 +1,685 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm1.c */
+/* Monobit "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+extern dev_proc_strip_copy_rop(mem_mono_strip_copy_rop); /* in gdevmrop.c */
+
+/* Optionally, use the slow RasterOp implementations for testing. */
+/*#define USE_COPY_ROP*/
+
+#ifdef USE_COPY_ROP
+#include "gsrop.h"
+#endif
+
+/* ================ Standard (byte-oriented) device ================ */
+
+/* We went to a lot of trouble to optimize mem_mono_tile_rectangle. */
+/* It has a substantial effect on the total time at high resolutions. */
+/* However, it takes quite a lot of code, so we omit it on 16-bit systems. */
+#define OPTIMIZE_TILE (arch_sizeof_int > 2)
+
+/* Procedures */
+private dev_proc_map_rgb_color(mem_mono_map_rgb_color);
+private dev_proc_map_color_rgb(mem_mono_map_color_rgb);
+private dev_proc_copy_mono(mem_mono_copy_mono);
+private dev_proc_fill_rectangle(mem_mono_fill_rectangle);
+#if OPTIMIZE_TILE
+private dev_proc_strip_tile_rectangle(mem_mono_strip_tile_rectangle);
+#else
+# define mem_mono_strip_tile_rectangle gx_default_strip_tile_rectangle
+#endif
+
+/* The device descriptor. */
+/* The instance is public. */
+const gx_device_memory far_data mem_mono_device =
+ mem_full_alpha_device("image1", 0, 1, mem_open,
+ mem_mono_map_rgb_color, mem_mono_map_color_rgb,
+ mem_mono_copy_mono, gx_default_copy_color, mem_mono_fill_rectangle,
+ mem_get_bits, gx_default_map_cmyk_color, gx_no_copy_alpha,
+ mem_mono_strip_tile_rectangle, mem_mono_strip_copy_rop);
+
+/* Map color to/from RGB. This may be inverted. */
+private gx_color_index
+mem_mono_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return (gx_default_w_b_map_rgb_color(dev, r, g, b) ^
+ mdev->palette.data[0]) & 1;
+}
+private int
+mem_mono_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ return gx_default_w_b_map_color_rgb(dev,
+ (color ^ mdev->palette.data[0]) & 1,
+ prgb);
+}
+
+/* Fill a rectangle with a color. */
+private int
+mem_mono_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+#ifdef USE_COPY_ROP
+ return mem_mono_copy_rop(dev, NULL, 0, 0, gx_no_bitmap_id, NULL,
+ NULL, NULL,
+ x, y, w, h, 0, 0,
+ (color ? rop3_1 : rop3_0));
+#else
+ fit_fill(dev, x, y, w, h);
+ bits_fill_rectangle(scan_line_base(mdev, y), x, mdev->raster,
+ -(mono_fill_chunk)color, w, h);
+ return 0;
+#endif
+}
+
+/* Convert x coordinate to byte offset in scan line. */
+#define x_to_byte(x) ((x) >> 3)
+
+/* Copy a monochrome bitmap. */
+#undef mono_masks
+#define mono_masks mono_copy_masks
+
+/* Fetch a chunk from the source. */
+/* The source data are always stored big-endian. */
+/* Note that the macros always cast cptr, */
+/* so it doesn't matter what the type of cptr is. */
+/* cshift = chunk_bits - shift. */
+#undef chunk
+#if arch_is_big_endian
+# define chunk uint
+# define cfetch_right(cptr, shift, cshift)\
+ (cfetch_aligned(cptr) >> shift)
+# define cfetch_left(cptr, shift, cshift)\
+ (cfetch_aligned(cptr) << shift)
+/* Fetch a chunk that straddles a chunk boundary. */
+# define cfetch2(cptr, cskew, skew)\
+ (cfetch_left(cptr, cskew, skew) +\
+ cfetch_right((const chunk *)(cptr) + 1, skew, cskew))
+#else /* little-endian */
+# define chunk bits16
+private const bits16 right_masks2[9] = {
+ 0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0x0f0f, 0x0707, 0x0303, 0x0101, 0x0000
+};
+private const bits16 left_masks2[9] = {
+ 0xffff, 0xfefe, 0xfcfc, 0xf8f8, 0xf0f0, 0xe0e0, 0xc0c0, 0x8080, 0x0000
+};
+# define ccont(cptr, off) (((const chunk *)(cptr))[off])
+# define cfetch_right(cptr, shift, cshift)\
+ ((shift) < 8 ?\
+ ((ccont(cptr, 0) >> (shift)) & right_masks2[shift]) +\
+ (ccont(cptr, 0) << (cshift)) :\
+ ((chunk)*(const byte *)(cptr) << (cshift)) & 0xff00)
+# define cfetch_left(cptr, shift, cshift)\
+ ((shift) < 8 ?\
+ ((ccont(cptr, 0) << (shift)) & left_masks2[shift]) +\
+ (ccont(cptr, 0) >> (cshift)) :\
+ ((ccont(cptr, 0) & 0xff00) >> (cshift)) & 0xff)
+/* Fetch a chunk that straddles a chunk boundary. */
+/* We can avoid testing the shift amount twice */
+/* by expanding the cfetch_left/right macros in-line. */
+# define cfetch2(cptr, cskew, skew)\
+ ((cskew) < 8 ?\
+ ((ccont(cptr, 0) << (cskew)) & left_masks2[cskew]) +\
+ (ccont(cptr, 0) >> (skew)) +\
+ (((chunk)(((const byte *)(cptr))[2]) << (cskew)) & 0xff00) :\
+ (((ccont(cptr, 0) & 0xff00) >> (skew)) & 0xff) +\
+ ((ccont(cptr, 1) >> (skew)) & right_masks2[skew]) +\
+ (ccont(cptr, 1) << (cskew)))
+#endif
+/* Since source and destination are both always big-endian, */
+/* fetching an aligned chunk never requires byte swapping. */
+# define cfetch_aligned(cptr)\
+ (*(const chunk *)(cptr))
+
+/* copy_function and copy_shift get added together for dispatch */
+typedef enum {
+ copy_or = 0, copy_store, copy_and, copy_funny
+} copy_function;
+/* copy_right/left is not an enum, because compilers complain about */
+/* an enumeration clash when these are added to a copy_function. */
+#define copy_right ((copy_function)0)
+#define copy_left ((copy_function)4)
+typedef struct {
+ short invert;
+ ushort op; /* copy_function */
+} copy_mode;
+/* Map from <c0,c1> to copy_mode. */
+#define cm(i,op) { i, (ushort)op }
+private copy_mode copy_modes[9] = {
+ cm(-1, copy_funny), /* NN */
+ cm(-1, copy_and), /* N0 */
+ cm(0, copy_or), /* N1 */
+ cm(0, copy_and), /* 0N */
+ cm(0, copy_funny), /* 00 */
+ cm(0, copy_store), /* 01 */
+ cm(-1, copy_or), /* 1N */
+ cm(-1, copy_store), /* 10 */
+ cm(0, copy_funny), /* 11 */
+};
+private int
+mem_mono_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{
+#ifdef USE_COPY_ROP
+ return mem_mono_copy_rop(dev, base, sourcex, sraster, id, NULL,
+ NULL, NULL,
+ x, y, w, h, 0, 0,
+ ((zero == gx_no_color_index ? rop3_D :
+ zero == 0 ? rop3_0 : rop3_1) & ~rop3_S) |
+ ((one == gx_no_color_index ? rop3_D :
+ one == 0 ? rop3_0 : rop3_1) & rop3_S));
+#else /* !USE_COPY_ROP */
+ register const byte *bptr; /* actually chunk * */
+ int dbit, wleft;
+ uint mask;
+ copy_mode mode;
+#define function (copy_function)(mode.op)
+ declare_scan_ptr_as(dbptr, byte *);
+#define optr ((chunk *)dbptr)
+ register int skew;
+ register uint invert;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+#if gx_no_color_index_value != -1 /* hokey! */
+ if ( zero == gx_no_color_index ) zero = -1;
+ if ( one == gx_no_color_index ) one = -1;
+#endif
+#define izero (int)zero
+#define ione (int)one
+ mode = copy_modes[izero + izero + izero + ione + 4];
+#undef izero
+#undef ione
+ invert = (uint)(int)mode.invert; /* load register */
+ setup_rect_as(dbptr, byte *);
+ bptr = base + ((sourcex & ~chunk_align_bit_mask) >> 3);
+ dbit = x & chunk_align_bit_mask;
+ skew = dbit - (sourcex & chunk_align_bit_mask);
+/* Macros for writing partial chunks. */
+/* The destination pointer is always named optr, */
+/* and must be declared as chunk *. */
+/* cinvert may be temporarily redefined. */
+#define cinvert(bits) ((bits) ^ invert)
+#define write_or_masked(bits, mask, off)\
+ optr[off] |= (cinvert(bits) & mask)
+#define write_store_masked(bits, mask, off)\
+ optr[off] = ((optr[off] & ~mask) | (cinvert(bits) & mask))
+#define write_and_masked(bits, mask, off)\
+ optr[off] &= (cinvert(bits) | ~mask)
+/* Macros for writing full chunks. */
+#define write_or(bits) *optr |= cinvert(bits)
+#define write_store(bits) *optr = cinvert(bits)
+#define write_and(bits) *optr &= cinvert(bits)
+/* Macro for incrementing to next chunk. */
+#define next_x_chunk\
+ bptr += chunk_bytes; dbptr += chunk_bytes
+/* Common macro for the end of each scan line. */
+#define end_y_loop(sdelta, ddelta)\
+ if ( --h == 0 ) break;\
+ bptr += sdelta; dbptr += ddelta
+ if ( (wleft = w + dbit - chunk_bits) <= 0 )
+ { /* The entire operation fits in one (destination) chunk. */
+ set_mono_thin_mask(mask, w, dbit);
+#define write_single(wr_op, src)\
+ for ( ; ; )\
+ { wr_op(src, mask, 0);\
+ end_y_loop(sraster, draster);\
+ }
+#define write1_loop(src)\
+ switch ( function ) {\
+ case copy_or: write_single(write_or_masked, src); break;\
+ case copy_store: write_single(write_store_masked, src); break;\
+ case copy_and: write_single(write_and_masked, src); break;\
+ default: goto funny;\
+ }
+ if ( skew >= 0 ) /* single -> single, right/no shift */
+ { if ( skew == 0 ) /* no shift */
+ { write1_loop(cfetch_aligned(bptr));
+ }
+ else /* right shift */
+ { int cskew = chunk_bits - skew;
+ write1_loop(cfetch_right(bptr, skew, cskew));
+ }
+ }
+ else if ( wleft <= skew ) /* single -> single, left shift */
+ { int cskew = chunk_bits + skew;
+ skew = -skew;
+ write1_loop(cfetch_left(bptr, skew, cskew));
+ }
+ else /* double -> single */
+ { int cskew = -skew;
+ skew += chunk_bits;
+ write1_loop(cfetch2(bptr, cskew, skew));
+ }
+#undef write1_loop
+#undef write_single
+ }
+ else if ( wleft <= skew )
+ { /* 1 source chunk -> 2 destination chunks. */
+ /* This is an important special case for */
+ /* both characters and halftone tiles. */
+ uint rmask;
+ int cskew = chunk_bits - skew;
+ set_mono_left_mask(mask, dbit);
+ set_mono_right_mask(rmask, wleft);
+#undef cinvert
+#define cinvert(bits) (bits) /* pre-inverted here */
+#if arch_is_big_endian /* no byte swapping */
+# define write_1to2(wr_op)\
+ for ( ; ; )\
+ { register uint bits = cfetch_aligned(bptr) ^ invert;\
+ wr_op(bits >> skew, mask, 0);\
+ wr_op(bits << cskew, rmask, 1);\
+ end_y_loop(sraster, draster);\
+ }
+#else /* byte swapping */
+# define write_1to2(wr_op)\
+ for ( ; ; )\
+ { wr_op(cfetch_right(bptr, skew, cskew) ^ invert, mask, 0);\
+ wr_op(cfetch_left(bptr, cskew, skew) ^ invert, rmask, 1);\
+ end_y_loop(sraster, draster);\
+ }
+#endif
+ switch ( function )
+ {
+ case copy_or: write_1to2(write_or_masked); break;
+ case copy_store: write_1to2(write_store_masked); break;
+ case copy_and: write_1to2(write_and_masked); break;
+ default: goto funny;
+ }
+#undef cinvert
+#define cinvert(bits) ((bits) ^ invert)
+#undef write_1to2
+ }
+ else
+ { /* More than one source chunk and more than one */
+ /* destination chunk are involved. */
+ uint rmask;
+ int words = (wleft & ~chunk_bit_mask) >> 3;
+ uint sskip = sraster - words;
+ uint dskip = draster - words;
+ register uint bits;
+ set_mono_left_mask(mask, dbit);
+ set_mono_right_mask(rmask, wleft & chunk_bit_mask);
+ if ( skew == 0 ) /* optimize the aligned case */
+ {
+#define write_aligned(wr_op, wr_op_masked)\
+ for ( ; ; )\
+ { int count = wleft;\
+ /* Do first partial chunk. */\
+ wr_op_masked(cfetch_aligned(bptr), mask, 0);\
+ /* Do full chunks. */\
+ while ( (count -= chunk_bits) >= 0 )\
+ { next_x_chunk; wr_op(cfetch_aligned(bptr)); }\
+ /* Do last chunk */\
+ if ( count > -chunk_bits )\
+ { wr_op_masked(cfetch_aligned(bptr + chunk_bytes), rmask, 1); }\
+ end_y_loop(sskip, dskip);\
+ }
+ switch ( function )
+ {
+ case copy_or:
+ write_aligned(write_or, write_or_masked);
+ break;
+ case copy_store:
+ write_aligned(write_store, write_store_masked);
+ break;
+ case copy_and:
+ write_aligned(write_and, write_and_masked);
+ break;
+ default:
+ goto funny;
+ }
+#undef write_aligned
+ }
+ else /* not aligned */
+ { int ccase =
+ (skew >= 0 ? copy_right :
+ ((bptr += chunk_bytes), copy_left))
+ + (int)function;
+ int cskew = -skew & chunk_bit_mask;
+ skew &= chunk_bit_mask;
+ for ( ; ; )
+ { int count = wleft;
+#define prefetch_right\
+ bits = cfetch_right(bptr, skew, cskew)
+#define prefetch_left\
+ bits = cfetch2(bptr - chunk_bytes, cskew, skew)
+#define write_unaligned(wr_op, wr_op_masked)\
+ wr_op_masked(bits, mask, 0);\
+ /* Do full chunks. */\
+ while ( count >= chunk_bits )\
+ { bits = cfetch2(bptr, cskew, skew);\
+ next_x_chunk; wr_op(bits); count -= chunk_bits;\
+ }\
+ /* Do last chunk */\
+ if ( count > 0 )\
+ { bits = cfetch_left(bptr, cskew, skew);\
+ if ( count > skew ) bits += cfetch_right(bptr + chunk_bytes, skew, cskew);\
+ wr_op_masked(bits, rmask, 1);\
+ }
+ switch ( ccase )
+ {
+ case copy_or + copy_left:
+ prefetch_left; goto uor;
+ case copy_or + copy_right:
+ prefetch_right;
+uor: write_unaligned(write_or, write_or_masked);
+ break;
+ case copy_store + copy_left:
+ prefetch_left; goto ustore;
+ case copy_store + copy_right:
+ prefetch_right;
+ustore: write_unaligned(write_store, write_store_masked);
+ break;
+ case copy_and + copy_left:
+ prefetch_left; goto uand;
+ case copy_and + copy_right:
+ prefetch_right;
+uand: write_unaligned(write_and, write_and_masked);
+ break;
+ default:
+ goto funny;
+ }
+ end_y_loop(sskip, dskip);
+#undef write_unaligned
+#undef prefetch_left
+#undef prefetch_right
+ }
+ }
+ }
+#undef end_y_loop
+#undef next_x_chunk
+ return 0;
+ /* Handle the funny cases that aren't supposed to happen. */
+funny: return (invert ? gs_note_error(-1) :
+ mem_mono_fill_rectangle(dev, x, y, w, h, zero));
+#undef optr
+#endif /* !USE_COPY_ROP */
+}
+
+#if OPTIMIZE_TILE /**************** ****************/
+
+/* Strip-tile with a monochrome halftone. */
+/* This is a performance bottleneck for monochrome devices, */
+/* so we re-implement it, even though it takes a lot of code. */
+private int
+mem_mono_strip_tile_rectangle(gx_device *dev,
+ register const gx_strip_bitmap *tiles,
+ int tx, int y, int tw, int th, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{
+#ifdef USE_COPY_ROP
+ return mem_mono_strip_copy_rop(dev, NULL, 0, 0, tile->id, NULL,
+ tiles, NULL,
+ tx, y, tw, th, px, py,
+ ((color0 == gx_no_color_index ? rop3_D :
+ color0 == 0 ? rop3_0 : rop3_1) & ~rop3_T) |
+ ((color1 == gx_no_color_index ? rop3_D :
+ color1 == 0 ? rop3_0 : rop3_1) & rop3_T));
+#else /* !USE_COPY_ROP */
+ register uint invert;
+ int sraster;
+ uint tile_bits_size;
+ const byte *base;
+ const byte *end;
+ int x, rw, w, h;
+ register const byte *bptr; /* actually chunk * */
+ int dbit, wleft;
+ uint mask;
+ byte *dbase;
+ declare_scan_ptr_as(dbptr, byte *);
+#define optr ((chunk *)dbptr)
+ register int skew;
+
+ /* This implementation doesn't handle strips yet. */
+ if ( color0 != (color1 ^ 1) || tiles->shift != 0 )
+ return gx_default_strip_tile_rectangle(dev, tiles, tx, y, tw, th,
+ color0, color1, px, py);
+ fit_fill(dev, tx, y, tw, th);
+ invert = -(uint)color0;
+ sraster = tiles->raster;
+ base = tiles->data + ((y + py) % tiles->rep_height) * sraster;
+ tile_bits_size = tiles->size.y * sraster;
+ end = tiles->data + tile_bits_size;
+#undef end_y_loop
+#define end_y_loop(sdelta, ddelta)\
+ if ( --h == 0 ) break;\
+ if ( end - bptr <= sdelta ) /* wrap around */\
+ bptr -= tile_bits_size;\
+ bptr += sdelta; dbptr += ddelta
+ draster = mdev->raster;
+ dbase = scan_line_base(mdev, y);
+ x = tx;
+ rw = tw;
+ /*
+ * The outermost loop here works horizontally, one iteration per
+ * copy of the tile. Note that all iterations except the first
+ * have sourcex = 0.
+ */
+ { int sourcex = (x + px) % tiles->rep_width;
+ w = tiles->size.x - sourcex;
+ bptr = base + ((sourcex & ~chunk_align_bit_mask) >> 3);
+ dbit = x & chunk_align_bit_mask;
+ skew = dbit - (sourcex & chunk_align_bit_mask);
+ }
+outer: if ( w > rw )
+ w = rw;
+ h = th;
+ dbptr = dbase + ((x >> 3) & -chunk_align_bytes);
+ if ( (wleft = w + dbit - chunk_bits) <= 0 )
+ { /* The entire operation fits in one (destination) chunk. */
+ set_mono_thin_mask(mask, w, dbit);
+#define write1_loop(src)\
+ for ( ; ; )\
+ { write_store_masked(src, mask, 0);\
+ end_y_loop(sraster, draster);\
+ }
+ if ( skew >= 0 ) /* single -> single, right/no shift */
+ { if ( skew == 0 ) /* no shift */
+ { write1_loop(cfetch_aligned(bptr));
+ }
+ else /* right shift */
+ { int cskew = chunk_bits - skew;
+ write1_loop(cfetch_right(bptr, skew, cskew));
+ }
+ }
+ else if ( wleft <= skew ) /* single -> single, left shift */
+ { int cskew = chunk_bits + skew;
+ skew = -skew;
+ write1_loop(cfetch_left(bptr, skew, cskew));
+ }
+ else /* double -> single */
+ { int cskew = -skew;
+ skew += chunk_bits;
+ write1_loop(cfetch2(bptr, cskew, skew));
+ }
+#undef write1_loop
+ }
+ else if ( wleft <= skew )
+ { /* 1 source chunk -> 2 destination chunks. */
+ /* This is an important special case for */
+ /* both characters and halftone tiles. */
+ uint rmask;
+ int cskew = chunk_bits - skew;
+ set_mono_left_mask(mask, dbit);
+ set_mono_right_mask(rmask, wleft);
+#if arch_is_big_endian /* no byte swapping */
+#undef cinvert
+#define cinvert(bits) (bits) /* pre-inverted here */
+ for ( ; ; )
+ { register uint bits = cfetch_aligned(bptr) ^ invert;
+ write_store_masked(bits >> skew, mask, 0);
+ write_store_masked(bits << cskew, rmask, 1);
+ end_y_loop(sraster, draster);
+ }
+#undef cinvert
+#define cinvert(bits) ((bits) ^ invert)
+#else /* byte swapping */
+ for ( ; ; )
+ { write_store_masked(cfetch_right(bptr, skew, cskew), mask, 0);
+ write_store_masked(cfetch_left(bptr, cskew, skew), rmask, 1);
+ end_y_loop(sraster, draster);
+ }
+#endif
+ }
+ else
+ { /* More than one source chunk and more than one */
+ /* destination chunk are involved. */
+ uint rmask;
+ int words = (wleft & ~chunk_bit_mask) >> 3;
+ uint sskip = sraster - words;
+ uint dskip = draster - words;
+ register uint bits;
+#define next_x_chunk\
+ bptr += chunk_bytes; dbptr += chunk_bytes
+
+ set_mono_right_mask(rmask, wleft & chunk_bit_mask);
+ if ( skew == 0 ) /* optimize the aligned case */
+ { if ( dbit == 0 )
+ mask = 0;
+ else
+ set_mono_left_mask(mask, dbit);
+ for ( ; ; )
+ { int count = wleft;
+ /* Do first partial chunk. */
+ if ( mask )
+ write_store_masked(cfetch_aligned(bptr), mask, 0);
+ else
+ write_store(cfetch_aligned(bptr));
+ /* Do full chunks. */
+ while ( (count -= chunk_bits) >= 0 )
+ { next_x_chunk;
+ write_store(cfetch_aligned(bptr));
+ }
+ /* Do last chunk */
+ if ( count > -chunk_bits )
+ { write_store_masked(cfetch_aligned(bptr + chunk_bytes), rmask, 1);
+ }
+ end_y_loop(sskip, dskip);
+ }
+ }
+ else /* not aligned */
+ { bool case_right =
+ (skew >= 0 ? true :
+ ((bptr += chunk_bytes), false));
+ int cskew = -skew & chunk_bit_mask;
+
+ skew &= chunk_bit_mask;
+ set_mono_left_mask(mask, dbit);
+ for ( ; ; )
+ { int count = wleft;
+ if ( case_right )
+ bits = cfetch_right(bptr, skew, cskew);
+ else
+ bits = cfetch2(bptr - chunk_bytes, cskew, skew);
+ write_store_masked(bits, mask, 0);
+ /* Do full chunks. */
+ while ( count >= chunk_bits )
+ { bits = cfetch2(bptr, cskew, skew);
+ next_x_chunk;
+ write_store(bits);
+ count -= chunk_bits;
+ }
+ /* Do last chunk */
+ if ( count > 0 )
+ { bits = cfetch_left(bptr, cskew, skew);
+ if ( count > skew )
+ bits += cfetch_right(bptr + chunk_bytes, skew, cskew);
+ write_store_masked(bits, rmask, 1);
+ }
+ end_y_loop(sskip, dskip);
+ }
+ }
+ }
+#undef end_y_loop
+#undef next_x_chunk
+#undef optr
+ if ( (rw -= w) > 0 )
+ { x += w;
+ w = tiles->size.x;
+ bptr = base;
+ skew = dbit = x & chunk_align_bit_mask;
+ goto outer;
+ }
+ return 0;
+#endif /* !USE_COPY_ROP */
+}
+
+#endif /**************** ****************/
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+private dev_proc_copy_mono(mem1_word_copy_mono);
+private dev_proc_fill_rectangle(mem1_word_fill_rectangle);
+#define mem1_word_strip_tile_rectangle gx_default_strip_tile_rectangle
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_mono_word_device =
+ mem_full_alpha_device("image1w", 0, 1, mem_open,
+ mem_mono_map_rgb_color, mem_mono_map_color_rgb,
+ mem1_word_copy_mono, gx_default_copy_color, mem1_word_fill_rectangle,
+ mem_word_get_bits, gx_default_map_cmyk_color, gx_no_copy_alpha,
+ mem1_word_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem1_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ byte *base;
+ uint raster;
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x, w, h, true);
+ bits_fill_rectangle(base, x, raster, -(mono_fill_chunk)color, w, h);
+ mem_swap_byte_rect(base, raster, x, w, h, true);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem1_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte *row;
+ uint raster;
+ bool store;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x, w, h, store);
+ mem_mono_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x, w, h, false);
+ return 0;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevm16.c b/gs/src/gdevm16.c
new file mode 100644
index 000000000..19e0996a3
--- /dev/null
+++ b/gs/src/gdevm16.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm16.c */
+/* 16-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+#undef chunk
+#define chunk byte
+
+/* The 16 bits are divided 5 for red, 6 for green, and 5 for blue. */
+/* Note that the bits must always be kept in big-endian order. */
+
+/* Procedures */
+declare_mem_map_procs(mem_true16_map_rgb_color, mem_true16_map_color_rgb);
+declare_mem_procs(mem_true16_copy_mono, mem_true16_copy_color, mem_true16_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_true16_device =
+ mem_device("image16", 16, 0,
+ mem_true16_map_rgb_color, mem_true16_map_color_rgb,
+ mem_true16_copy_mono, mem_true16_copy_color, mem_true16_fill_rectangle,
+ gx_no_strip_copy_rop);
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+mem_true16_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return ((r >> (gx_color_value_bits - 5)) << 11) +
+ ((g >> (gx_color_value_bits - 6)) << 5) +
+ (b >> (gx_color_value_bits - 5));
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+mem_true16_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ ushort value = color >> 11;
+ prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
+ value = (color >> 6) & 0x7f;
+ prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) >> (16 - gx_color_value_bits);
+ value = color & 0x3f;
+ prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
+ return 0;
+}
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) << 1)
+
+/* Fill a rectangle with a color. */
+private int
+mem_true16_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{
+#if arch_is_big_endian
+# define color16 ((ushort)color)
+#else
+ ushort color16 = ((uint)(byte)color << 8) + ((ushort)color >> 8);
+#endif
+ declare_scan_ptr(dest);
+ fit_fill(dev, x, y, w, h);
+ setup_rect(dest);
+ while ( h-- > 0 )
+ { ushort *pptr = (ushort *)dest;
+ int cnt = w;
+ do { *pptr++ = color16; } while ( --cnt > 0 );
+ inc_ptr(dest, draster);
+ }
+ return 0;
+#undef color16
+}
+
+/* Copy a monochrome bitmap. */
+private int
+mem_true16_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{
+#if arch_is_big_endian
+# define zero16 ((ushort)zero)
+# define one16 ((ushort)one)
+#else
+ ushort zero16 = ((uint)(byte)zero << 8) + ((ushort)zero >> 8);
+ ushort one16 = ((uint)(byte)one << 8) + ((ushort)one >> 8);
+#endif
+ const byte *line;
+ int first_bit;
+ declare_scan_ptr(dest);
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ first_bit = 0x80 >> (sourcex & 7);
+ while ( h-- > 0 )
+ { register ushort *pptr = (ushort *)dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++;
+ register int bit = first_bit;
+ int count = w;
+ do
+ { if ( sbyte & bit )
+ { if ( one != gx_no_color_index )
+ *pptr = one16;
+ }
+ else
+ { if ( zero != gx_no_color_index )
+ *pptr = zero16;
+ }
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ pptr++;
+ }
+ while ( --count > 0 );
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ return 0;
+#undef zero16
+#undef one16
+}
+
+/* Copy a color bitmap. */
+private int
+mem_true16_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
+ return 0;
+}
diff --git a/gs/src/gdevm2.c b/gs/src/gdevm2.c
new file mode 100644
index 000000000..a3b2957a6
--- /dev/null
+++ b/gs/src/gdevm2.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm2.c */
+/* 2-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/**************** NOTE: copy_rop only works for gray scale ****************/
+extern dev_proc_strip_copy_rop(mem_gray_strip_copy_rop);
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+#define fpat(byt) mono_fill_make_pattern(byt)
+
+/* Procedures */
+declare_mem_procs(mem_mapped2_copy_mono, mem_mapped2_copy_color, mem_mapped2_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_mapped2_device =
+ mem_device("image2", 2, 0,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem_mapped2_copy_mono, mem_mapped2_copy_color, mem_mapped2_fill_rectangle,
+ mem_gray_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) >> 2)
+
+/* Define the 2-bit fill patterns. */
+static const mono_fill_chunk tile_patterns[4] =
+{ fpat(0x00), fpat(0x55), fpat(0xaa), fpat(0xff)
+};
+
+/* Fill a rectangle with a color. */
+private int
+mem_mapped2_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ fit_fill(dev, x, y, w, h);
+ bits_fill_rectangle(scan_line_base(mdev, y), x << 1, mdev->raster,
+ tile_patterns[color], w << 1, h);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem_mapped2_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ const byte *line;
+ int first_bit;
+ byte first_mask, b0, b1, bxor, left_mask, right_mask;
+ static const byte btab[4] = { 0, 0x55, 0xaa, 0xff };
+ static const byte bmask[4] = { 0xc0, 0x30, 0xc, 3 };
+ static const byte lmask[4] = { 0, 0xc0, 0xf0, 0xfc };
+ declare_scan_ptr(dest);
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ first_bit = 0x80 >> (sourcex & 7);
+ first_mask = bmask[x & 3];
+ left_mask = lmask[x & 3];
+ right_mask = ~lmask[(x + w) & 3];
+ if ( (x & 3) + w <= 4 )
+ left_mask = right_mask = left_mask | right_mask;
+ b0 = btab[zero & 3];
+ b1 = btab[one & 3];
+ bxor = b0 ^ b1;
+ while ( h-- > 0 )
+ { register byte *pptr = (byte *)dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++;
+ register int bit = first_bit;
+ register byte mask = first_mask;
+ int count = w;
+
+ /* We have 4 cases, of which only 2 really matter. */
+ if ( one != gx_no_color_index )
+ { if ( zero != gx_no_color_index )
+ { /* Copying an opaque bitmap. */
+ byte data =
+ (*pptr & left_mask) | (b0 & ~left_mask);
+ do
+ { if ( sbyte & bit )
+ data ^= bxor & mask;
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ if ( (mask >>= 2) == 0 )
+ mask = 0xc0, *pptr++ = data, data = b0;
+ }
+ while ( --count > 0 );
+ if ( mask != 0xc0 )
+ *pptr =
+ (*pptr & right_mask) | (data & ~right_mask);
+ }
+ else
+ { /* Filling a mask. */
+ do
+ { if ( sbyte & bit )
+ *pptr = (*pptr & ~mask) + (b1 & mask);
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ if ( (mask >>= 2) == 0 )
+ mask = 0xc0, pptr++;
+ }
+ while ( --count > 0 );
+ }
+ }
+ else
+ { /* Some other case. */
+ do
+ { if ( !(sbyte & bit) )
+ { if ( zero != gx_no_color_index )
+ *pptr = (*pptr & ~mask) + (b0 & mask);
+ }
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ if ( (mask >>= 2) == 0 )
+ mask = 0xc0, pptr++;
+ }
+ while ( --count > 0 );
+ }
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem_mapped2_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int code;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ /* Use monobit copy_mono. */
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 1;
+ code = (*dev_proc(&mem_mono_device, copy_mono))
+ (dev, base, sourcex << 1, sraster, id,
+ x << 1, y, w << 1, h, (gx_color_index)0, (gx_color_index)1);
+ /* Restore the correct width. */
+ dev->width >>= 1;
+ return code;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+declare_mem_procs(mem2_word_copy_mono, mem2_word_copy_color, mem2_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_mapped2_word_device =
+ mem_full_device("image2w", 2, 0, mem_open,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem2_word_copy_mono, mem2_word_copy_color, mem2_word_fill_rectangle,
+ mem_word_get_bits, gx_default_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem2_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ byte *base;
+ uint raster;
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true);
+ bits_fill_rectangle(base, x << 1, raster,
+ tile_patterns[color], w << 1, h);
+ mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem2_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte *row;
+ uint raster;
+ bool store;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x << 1, w << 1, h, store);
+ mem_mapped2_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x << 1, w << 1, h, false);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem2_word_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int code;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ /* Use monobit copy_mono. */
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 1;
+ code = (*dev_proc(&mem_mono_word_device, copy_mono))
+ (dev, base, sourcex << 1, sraster, id,
+ x << 1, y, w << 1, h, (gx_color_index)0, (gx_color_index)1);
+ /* Restore the correct width. */
+ dev->width >>= 1;
+ return code;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevm24.c b/gs/src/gdevm24.c
new file mode 100644
index 000000000..0c82e03e5
--- /dev/null
+++ b/gs/src/gdevm24.c
@@ -0,0 +1,490 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm24.c */
+/* 24-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+extern dev_proc_strip_copy_rop(mem_gray8_rgb24_strip_copy_rop); /* in gdevmrop.c */
+#define mem_true24_strip_copy_rop mem_gray8_rgb24_strip_copy_rop
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+
+/* Procedures */
+declare_mem_procs(mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle);
+private dev_proc_copy_alpha(mem_true24_copy_alpha);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_true24_device =
+ mem_full_alpha_device("image24", 24, 0, mem_open,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
+ mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle,
+ mem_get_bits, gx_default_map_cmyk_color, mem_true24_copy_alpha,
+ gx_default_strip_tile_rectangle, mem_true24_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) * 3)
+
+/* Unpack a color into its bytes. */
+#define declare_unpack_color(r, g, b, color)\
+ byte r = (byte)(color >> 16);\
+ byte g = (byte)((uint)color >> 8);\
+ byte b = (byte)color
+/* Put a 24-bit color into the bitmap. */
+#define put3(ptr, r, g, b)\
+ (ptr)[0] = r, (ptr)[1] = g, (ptr)[2] = b
+/* Put 4 bytes of color into the bitmap. */
+#define putw(ptr, wxyz)\
+ *(bits32 *)(ptr) = (wxyz)
+/* Load the 3-word 24-bit-color cache. */
+/* Free variables: [m]dev, rgbr, gbrg, brgb. */
+#if arch_is_big_endian
+# define set_color24_cache(crgb, r, g, b)\
+ mdev->color24.rgbr = rgbr = ((bits32)(crgb) << 8) | (r),\
+ mdev->color24.gbrg = gbrg = (rgbr << 8) | (g),\
+ mdev->color24.brgb = brgb = (gbrg << 8) | (b),\
+ mdev->color24.rgb = (crgb)
+#else
+# define set_color24_cache(crgb, r, g, b)\
+ mdev->color24.rgbr = rgbr =\
+ ((bits32)(r) << 24) | ((bits32)(b) << 16) |\
+ ((bits16)(g) << 8) | (r),\
+ mdev->color24.brgb = brgb = (rgbr << 8) | (b),\
+ mdev->color24.gbrg = gbrg = (brgb << 8) | (g),\
+ mdev->color24.rgb = (crgb)
+#endif
+
+/* Fill a rectangle with a color. */
+private int
+mem_true24_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ declare_unpack_color(r, g, b, color);
+ declare_scan_ptr(dest);
+
+ /*
+ * In order to avoid testing w > 0 and h > 0 twice, we defer
+ * executing setup_rect, and use fit_fill_xywh instead of
+ * fit_fill.
+ */
+ fit_fill_xywh(dev, x, y, w, h);
+ if ( w >= 5 )
+ { if ( h <= 0 )
+ return 0;
+ setup_rect(dest);
+ if ( r == g && r == b)
+ {
+#if 1
+ /* We think we can do better than the library's memset.... */
+ int bcntm7 = w * 3 - 7;
+ register bits32 cword = color | (color << 24);
+ while ( h-- > 0 )
+ { register byte *pptr = dest;
+ byte *limit = pptr + bcntm7;
+ /* We want to store full words, but we have to */
+ /* guarantee that they are word-aligned. */
+ switch ( x & 3 )
+ {
+ case 3: *pptr++ = (byte)cword;
+ case 2: *pptr++ = (byte)cword;
+ case 1: *pptr++ = (byte)cword;
+ case 0: ;
+ }
+ /* Even with w = 5, we always store at least */
+ /* 3 full words, regardless of the starting x. */
+ *(bits32 *)pptr =
+ ((bits32 *)pptr)[1] =
+ ((bits32 *)pptr)[2] = cword;
+ pptr += 12;
+ while ( pptr < limit )
+ { *(bits32 *)pptr =
+ ((bits32 *)pptr)[1] = cword;
+ pptr += 8;
+ }
+ switch ( pptr - limit )
+ {
+ case 0: pptr[6] = (byte)cword;
+ case 1: pptr[5] = (byte)cword;
+ case 2: pptr[4] = (byte)cword;
+ case 3: *(bits32 *)pptr = cword;
+ break;
+ case 4: pptr[2] = (byte)cword;
+ case 5: pptr[1] = (byte)cword;
+ case 6: pptr[0] = (byte)cword;
+ case 7: ;
+ }
+ inc_ptr(dest, draster);
+ }
+#else
+ int bcnt = w * 3;
+ while ( h-- > 0 )
+ { memset(dest, r, bcnt);
+ inc_ptr(dest, draster);
+ }
+#endif
+ }
+ else
+ { int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */
+ bits32 rgbr, gbrg, brgb;
+ if ( mdev->color24.rgb == color )
+ rgbr = mdev->color24.rgbr,
+ gbrg = mdev->color24.gbrg,
+ brgb = mdev->color24.brgb;
+ else
+ set_color24_cache(color, r, g, b);
+ while ( h-- > 0 )
+ { register byte *pptr = dest;
+ int w1 = ww;
+ switch ( x3 )
+ {
+ case 1:
+ put3(pptr, r, g, b);
+ pptr += 3; break;
+ case 2:
+ pptr[0] = r; pptr[1] = g;
+ putw(pptr + 2, brgb);
+ pptr += 6; break;
+ case 3:
+ pptr[0] = r;
+ putw(pptr + 1, gbrg);
+ putw(pptr + 5, brgb);
+ pptr += 9; break;
+ case 0:
+ ;
+ }
+ while ( w1 >= 4 )
+ { putw(pptr, rgbr);
+ putw(pptr + 4, gbrg);
+ putw(pptr + 8, brgb);
+ pptr += 12;
+ w1 -= 4;
+ }
+ switch ( w1 )
+ {
+ case 1:
+ put3(pptr, r, g, b);
+ break;
+ case 2:
+ putw(pptr, rgbr);
+ pptr[4] = g; pptr[5] = b;
+ break;
+ case 3:
+ putw(pptr, rgbr);
+ putw(pptr + 4, gbrg);
+ pptr[8] = b;
+ break;
+ case 0:
+ ;
+ }
+ inc_ptr(dest, draster);
+ }
+ }
+ }
+ else if ( h > 0 ) /* w < 5 */
+ {
+ setup_rect(dest);
+ switch ( w )
+ {
+ case 4:
+ do
+ { dest[9] = dest[6] = dest[3] = dest[0] = r;
+ dest[10] = dest[7] = dest[4] = dest[1] = g;
+ dest[11] = dest[8] = dest[5] = dest[2] = b;
+ inc_ptr(dest, draster);
+ }
+ while ( --h );
+ break;
+ case 3:
+ do
+ { dest[6] = dest[3] = dest[0] = r;
+ dest[7] = dest[4] = dest[1] = g;
+ dest[8] = dest[5] = dest[2] = b;
+ inc_ptr(dest, draster);
+ }
+ while ( --h );
+ break;
+ case 2:
+ do
+ { dest[3] = dest[0] = r;
+ dest[4] = dest[1] = g;
+ dest[5] = dest[2] = b;
+ inc_ptr(dest, draster);
+ }
+ while ( --h );
+ break;
+ case 1:
+ do
+ { dest[0] = r, dest[1] = g, dest[2] = b;
+ inc_ptr(dest, draster);
+ }
+ while ( --h );
+ break;
+ case 0:
+ default:
+ ;
+ }
+ }
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+private int
+mem_true24_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ const byte *line;
+ int sbit;
+ int first_bit;
+ declare_scan_ptr(dest);
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ sbit = sourcex & 7;
+ first_bit = 0x80 >> sbit;
+ if ( zero != gx_no_color_index )
+ { /* Loop for halftones or inverted masks */
+ /* (never used). */
+ declare_unpack_color(r0, g0, b0, zero);
+ declare_unpack_color(r1, g1, b1, one);
+ while ( h-- > 0 )
+ { register byte *pptr = dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++;
+ register int bit = first_bit;
+ int count = w;
+ do
+ { if ( sbyte & bit )
+ { if ( one != gx_no_color_index )
+ put3(pptr, r1, g1, b1);
+ }
+ else
+ put3(pptr, r0, g0, b0);
+ pptr += 3;
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ }
+ while ( --count > 0 );
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ }
+ else if ( one != gx_no_color_index )
+ { /* Loop for character and pattern masks. */
+ /* This is used heavily. */
+ declare_unpack_color(r1, g1, b1, one);
+ int first_mask = first_bit << 1;
+ int first_count, first_skip;
+ if ( sbit + w > 8 )
+ first_mask -= 1,
+ first_count = 8 - sbit;
+ else
+ first_mask -= first_mask >> w,
+ first_count = w;
+ first_skip = first_count * 3;
+ while ( h-- > 0 )
+ { register byte *pptr = dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++ & first_mask;
+ int count = w - first_count;
+ if ( sbyte )
+ { register int bit = first_bit;
+ do
+ { if ( sbyte & bit )
+ put3(pptr, r1, g1, b1);
+ pptr += 3;
+ }
+ while ( (bit >>= 1) & first_mask );
+ }
+ else
+ pptr += first_skip;
+ while ( count >= 8 )
+ { sbyte = *sptr++;
+ if ( sbyte & 0xf0 )
+ { if ( sbyte & 0x80 )
+ put3(pptr, r1, g1, b1);
+ if ( sbyte & 0x40 )
+ put3(pptr + 3, r1, g1, b1);
+ if ( sbyte & 0x20 )
+ put3(pptr + 6, r1, g1, b1);
+ if ( sbyte & 0x10 )
+ put3(pptr + 9, r1, g1, b1);
+ }
+ if ( sbyte & 0xf )
+ { if ( sbyte & 8 )
+ put3(pptr + 12, r1, g1, b1);
+ if ( sbyte & 4 )
+ put3(pptr + 15, r1, g1, b1);
+ if ( sbyte & 2 )
+ put3(pptr + 18, r1, g1, b1);
+ if ( sbyte & 1 )
+ put3(pptr + 21, r1, g1, b1);
+ }
+ pptr += 24;
+ count -= 8;
+ }
+ if ( count > 0 )
+ { register int bit = 0x80;
+ sbyte = *sptr++;
+ do
+ { if ( sbyte & bit )
+ put3(pptr, r1, g1, b1);
+ pptr += 3;
+ bit >>= 1;
+ }
+ while ( --count > 0 );
+ }
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ }
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem_true24_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
+ return 0;
+}
+
+/* Copy an alpha map. */
+private int
+mem_true24_copy_alpha(gx_device *dev, const byte *base, int sourcex,
+ int sraster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{ const byte *line;
+ declare_scan_ptr(dest);
+ declare_unpack_color(r, g, b, color);
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base;
+ while ( h-- > 0 )
+ { register byte *pptr = dest;
+ int sx;
+
+ for ( sx = sourcex; sx < sourcex + w; ++sx, pptr += 3 )
+ { int alpha2, alpha;
+
+ if ( depth == 2 ) /* map 0 - 3 to 0 - 15 */
+ alpha =
+ ((line[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5;
+ else
+ alpha2 = line[sx >> 1],
+ alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
+ if ( alpha == 15 )
+ { /* Just write the new color. */
+ put3(pptr, r, g, b);
+ }
+ else if ( alpha != 0 )
+ { /* Blend RGB values. */
+#define make_shade(old, clr, alpha, amax) \
+ (old) + (((int)(clr) - (int)(old)) * (alpha) / (amax))
+ pptr[0] = make_shade(pptr[0], r, alpha, 15);
+ pptr[1] = make_shade(pptr[1], g, alpha, 15);
+ pptr[2] = make_shade(pptr[2], b, alpha, 15);
+#undef make_shade
+ }
+ }
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ return 0;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+declare_mem_procs(mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_true24_word_device =
+ mem_full_device("image24w", 24, 0, mem_open,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
+ mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle,
+ mem_word_get_bits, gx_default_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem24_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ byte *base;
+ uint raster;
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x * 24, w * 24, h, true);
+ mem_true24_fill_rectangle(dev, x, y, w, h, color);
+ mem_swap_byte_rect(base, raster, x * 24, w * 24, h, false);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem24_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte *row;
+ uint raster;
+ bool store;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x * 24, w * 24, h, store);
+ mem_true24_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem24_word_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ byte *row;
+ uint raster;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(row, raster, x * 24, w * 24, h, true);
+ bytes_copy_rectangle(row + x * 3, raster, base + sourcex * 3, sraster,
+ w * 3, h);
+ mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
+ return 0;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevm32.c b/gs/src/gdevm32.c
new file mode 100644
index 000000000..044375002
--- /dev/null
+++ b/gs/src/gdevm32.c
@@ -0,0 +1,228 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm32.c */
+/* 32-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+
+/* Procedures */
+declare_mem_procs(mem_true32_copy_mono, mem_true32_copy_color, mem_true32_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_true32_device =
+ mem_full_device("image32", 24, 8, mem_open,
+ gx_default_map_rgb_color, gx_default_map_color_rgb,
+ mem_true32_copy_mono, mem_true32_copy_color, mem_true32_fill_rectangle,
+ mem_get_bits, gx_default_cmyk_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) << 2)
+
+/* Swap the bytes of a color if needed. */
+#define color_swap_bytes(color)\
+ (((color) >> 24) + (((color) >> 8) & 0xff00) +\
+ (((color) & 0xff00) << 8) + ((color) << 24))
+#if arch_is_big_endian
+# define arrange_bytes(color) (color)
+#else
+# define arrange_bytes(color) color_swap_bytes(color)
+#endif
+
+/* Fill a rectangle with a color. */
+private int
+mem_true32_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ bits32 a_color;
+ declare_scan_ptr(dest);
+
+ fit_fill(dev, x, y, w, h);
+ a_color = arrange_bytes(color);
+ setup_rect(dest);
+ if ( w <= 4 )
+ switch ( w )
+ {
+ /*case 0:*/ /* not possible */
+#define dest32 ((bits32 *)dest)
+ case 1:
+ do
+ { dest32[0] = a_color;
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+ break;
+ case 2:
+ do
+ { dest32[1] = dest32[0] = a_color;
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+ break;
+ case 3:
+ do
+ { dest32[2] = dest32[1] = dest32[0] = a_color;
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+ break;
+ case 4:
+ do
+ { dest32[3] = dest32[2] = dest32[1] = dest32[0] = a_color;
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+ break;
+ default: /* not possible */
+ ;
+ }
+ else if ( a_color == 0 )
+ do
+ { memset(dest, 0, w << 2);
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+ else
+ do
+ { bits32 *pptr = dest32;
+ int cnt = w;
+ do
+ { pptr[3] = pptr[2] = pptr[1] = pptr[0] = a_color;
+ pptr += 4;
+ }
+ while ( (cnt -= 4) > 4 );
+ do { *pptr++ = a_color; } while ( --cnt > 0 );
+ inc_ptr(dest, draster);
+ }
+ while ( --h > 0 );
+#undef dest32
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+private int
+mem_true32_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ bits32 a_zero = arrange_bytes(zero);
+ bits32 a_one = arrange_bytes(one);
+ const byte *line;
+ int first_bit;
+ declare_scan_ptr(dest);
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ first_bit = 0x80 >> (sourcex & 7);
+ while ( h-- > 0 )
+ { register bits32 *pptr = (bits32 *)dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++;
+ register int bit = first_bit;
+ int count = w;
+ do
+ { if ( sbyte & bit )
+ { if ( one != gx_no_color_index )
+ *pptr = a_one;
+ }
+ else
+ { if ( zero != gx_no_color_index )
+ *pptr = a_zero;
+ }
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ pptr++;
+ }
+ while ( --count > 0 );
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem_true32_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
+ return 0;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+declare_mem_procs(mem32_word_copy_mono, mem32_word_copy_color, mem32_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_true32_word_device =
+ mem_full_device("image32w", 24, 8, mem_open,
+ gx_default_map_rgb_color, gx_default_map_color_rgb,
+ mem32_word_copy_mono, mem32_word_copy_color, mem32_word_fill_rectangle,
+ mem_word_get_bits, gx_default_cmyk_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem32_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ return mem_true32_fill_rectangle(dev, x, y, w, h,
+ color_swap_bytes(color));
+}
+
+/* Copy a bitmap. */
+private int
+mem32_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ return mem_true32_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, color_swap_bytes(zero),
+ color_swap_bytes(one));
+}
+
+/* Copy a color bitmap. */
+private int
+mem32_word_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ byte *row;
+ uint raster;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ bytes_copy_rectangle(row + (x << 2), raster, base + (sourcex << 2),
+ sraster, w << 2, h);
+ mem_swap_byte_rect(row, raster, x << 5, w << 5, h, false);
+ return 0;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevm4.c b/gs/src/gdevm4.c
new file mode 100644
index 000000000..ce7f9bafc
--- /dev/null
+++ b/gs/src/gdevm4.c
@@ -0,0 +1,202 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm4.c */
+/* 4-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/**************** NOTE: copy_rop only works for gray scale ****************/
+extern dev_proc_strip_copy_rop(mem_gray_strip_copy_rop);
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+#define fpat(byt) mono_fill_make_pattern(byt)
+
+/* Procedures */
+declare_mem_procs(mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_mapped4_device =
+ mem_device("image4", 4, 0,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle,
+ mem_gray_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) >> 1)
+
+/* Define the 4-bit fill patterns. */
+static const mono_fill_chunk tile_patterns[16] =
+ { fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33),
+ fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77),
+ fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb),
+ fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff)
+ };
+
+
+/* Fill a rectangle with a color. */
+private int
+mem_mapped4_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ fit_fill(dev, x, y, w, h);
+ bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster,
+ tile_patterns[color], w << 2, h);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem_mapped4_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ const byte *line;
+ int first_bit;
+ byte first_mask, b0, b1;
+ declare_scan_ptr(dest);
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ first_bit = 0x80 >> (sourcex & 7);
+ first_mask = (x & 1 ? 0xf : 0xf0);
+ b0 = ((byte)zero << 4) + (byte)zero;
+ b1 = ((byte)one << 4) + (byte)one;
+ while ( h-- > 0 )
+ { register byte *pptr = (byte *)dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++;
+ register int bit = first_bit;
+ register byte mask = first_mask;
+ int count = w;
+ do
+ { if ( sbyte & bit )
+ { if ( one != gx_no_color_index )
+ *pptr = (*pptr & ~mask) + (b1 & mask);
+ }
+ else
+ { if ( zero != gx_no_color_index )
+ *pptr = (*pptr & ~mask) + (b0 & mask);
+ }
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, sbyte = *sptr++;
+ if ( (mask = ~mask) == 0xf0 )
+ pptr++;
+ }
+ while ( --count > 0 );
+ line += sraster;
+ inc_ptr(dest, draster);
+ }
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem_mapped4_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int code;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ /* Use monobit copy_mono. */
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 2;
+ code = (*dev_proc(&mem_mono_device, copy_mono))
+ (dev, base, sourcex << 2, sraster, id,
+ x << 2, y, w << 2, h, (gx_color_index)0, (gx_color_index)1);
+ /* Restore the correct width. */
+ dev->width >>= 2;
+ return code;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_mapped4_word_device =
+ mem_full_device("image4w", 4, 0, mem_open,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle,
+ mem_word_get_bits, gx_default_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem4_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ byte *base;
+ uint raster;
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
+ bits_fill_rectangle(base, x << 2, raster,
+ tile_patterns[color], w << 2, h);
+ mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem4_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte *row;
+ uint raster;
+ bool store;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store);
+ mem_mapped4_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem4_word_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int code;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ /* Use monobit copy_mono. */
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 2;
+ code = (*dev_proc(&mem_mono_word_device, copy_mono))
+ (dev, base, sourcex << 2, sraster, id,
+ x << 2, y, w << 2, h, (gx_color_index)0, (gx_color_index)1);
+ /* Restore the correct width. */
+ dev->width >>= 2;
+ return code;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevm8.c b/gs/src/gdevm8.c
new file mode 100644
index 000000000..ebd4d2540
--- /dev/null
+++ b/gs/src/gdevm8.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevm8.c */
+/* 8-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/**************** NOTE: copy_rop only works for gray scale ****************/
+extern dev_proc_strip_copy_rop(mem_gray8_rgb24_strip_copy_rop); /* in gdevmrop.c */
+#define mem_gray8_strip_copy_rop mem_gray8_rgb24_strip_copy_rop
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+
+/* Procedures */
+declare_mem_procs(mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory far_data mem_mapped8_device =
+ mem_device("image8", 8, 0,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle,
+ mem_gray8_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) (x)
+
+/* Fill a rectangle with a color. */
+private int
+mem_mapped8_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ fit_fill(dev, x, y, w, h);
+ bytes_fill_rectangle(scan_line_base(mdev, y) + x, mdev->raster,
+ (byte)color, w, h);
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+/* We split up this procedure because of limitations in the bcc32 compiler. */
+private void mapped8_copy01(P9(chunk *, const byte *, int, int, uint,
+ int, int, byte, byte));
+private void mapped8_copyN1(P8(chunk *, const byte *, int, int, uint,
+ int, int, byte));
+private void mapped8_copy0N(P8(chunk *, const byte *, int, int, uint,
+ int, int, byte));
+private int
+mem_mapped8_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ const byte *line;
+ int first_bit;
+ declare_scan_ptr(dest);
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ first_bit = 0x80 >> (sourcex & 7);
+#define is_color(c) ((int)(c) != (int)gx_no_color_index)
+ if ( is_color(one) )
+ { if ( is_color(zero) )
+ mapped8_copy01(dest, line, first_bit, sraster, draster,
+ w, h, (byte)zero, (byte)one);
+ else
+ mapped8_copyN1(dest, line, first_bit, sraster, draster,
+ w, h, (byte)one);
+ }
+ else if ( is_color(zero) )
+ mapped8_copy0N(dest, line, first_bit, sraster, draster,
+ w, h, (byte)zero);
+#undef is_color
+ return 0;
+}
+/* Macros for copy loops */
+#define COPY_BEGIN\
+ while ( h-- > 0 )\
+ { register byte *pptr = dest;\
+ const byte *sptr = line;\
+ register int sbyte = *sptr;\
+ register uint bit = first_bit;\
+ int count = w;\
+ do\
+ {
+#define COPY_END\
+ if ( (bit >>= 1) == 0 )\
+ bit = 0x80, sbyte = *++sptr;\
+ pptr++;\
+ }\
+ while ( --count > 0 );\
+ line += sraster;\
+ inc_ptr(dest, draster);\
+ }
+/* Halftone coloring */
+private void
+mapped8_copy01(chunk *dest, const byte *line, int first_bit,
+ int sraster, uint draster, int w, int h, byte b0, byte b1)
+{ COPY_BEGIN
+ *pptr = (sbyte & bit ? b1 : b0);
+ COPY_END
+}
+/* Stenciling */
+private void
+mapped8_copyN1(chunk *dest, const byte *line, int first_bit,
+ int sraster, uint draster, int w, int h, byte b1)
+{ COPY_BEGIN
+ if ( sbyte & bit )
+ *pptr = b1;
+ COPY_END
+}
+/* Reverse stenciling */
+private void
+mapped8_copy0N(chunk *dest, const byte *line, int first_bit,
+ int sraster, uint draster, int w, int h, byte b0)
+{ COPY_BEGIN
+ if ( !(sbyte & bit) )
+ *pptr = b0;
+ COPY_END
+}
+#undef COPY_BEGIN
+#undef COPY_END
+
+/* Copy a color bitmap. */
+private int
+mem_mapped8_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
+ return 0;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !arch_is_big_endian
+
+/* Procedures */
+declare_mem_procs(mem8_word_copy_mono, mem8_word_copy_color, mem8_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory far_data mem_mapped8_word_device =
+ mem_full_device("image8w", 8, 0, mem_open,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem8_word_copy_mono, mem8_word_copy_color, mem8_word_fill_rectangle,
+ mem_word_get_bits, gx_default_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Fill a rectangle with a color. */
+private int
+mem8_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ byte *base;
+ uint raster;
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x << 3, w << 3, h, true);
+ bytes_fill_rectangle(base + x, raster, (byte)color, w, h);
+ mem_swap_byte_rect(base, raster, x << 3, w << 3, h, true);
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem8_word_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte *row;
+ uint raster;
+ bool store;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x << 3, w << 3, h, store);
+ mem_mapped8_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x << 3, w << 3, h, false);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+mem8_word_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ byte *row;
+ uint raster;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(row, raster, x << 3, w << 3, h, true);
+ mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
+ mem_swap_byte_rect(row, raster, x << 3, w << 3, h, false);
+ return 0;
+}
+
+#endif /* !arch_is_big_endian */
diff --git a/gs/src/gdevmem.c b/gs/src/gdevmem.c
new file mode 100644
index 000000000..b88dd492c
--- /dev/null
+++ b/gs/src/gdevmem.c
@@ -0,0 +1,377 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmem.c */
+/* Generic "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/* Structure descriptor */
+public_st_device_memory();
+
+/* GC procedures */
+#define mptr ((gx_device_memory *)vptr)
+private ENUM_PTRS_BEGIN(device_memory_enum_ptrs) {
+ return (*st_device_forward.enum_ptrs)(vptr, sizeof(gx_device_forward), index-2, pep);
+ }
+ case 0: ENUM_RETURN((mptr->foreign_bits ? NULL : (void *)mptr->base));
+ ENUM_STRING_PTR(1, gx_device_memory, palette);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_memory_reloc_ptrs) {
+ if ( !mptr->foreign_bits )
+ { byte *base_old = mptr->base;
+ long reloc;
+ int y;
+ RELOC_PTR(gx_device_memory, base);
+ reloc = base_old - mptr->base;
+ for ( y = 0; y < mptr->height; y++ )
+ mptr->line_ptrs[y] -= reloc;
+ /* Relocate line_ptrs, which also points into the data area. */
+ mptr->line_ptrs = (byte **)((byte *)mptr->line_ptrs - reloc);
+ }
+ RELOC_CONST_STRING_PTR(gx_device_memory, palette);
+ (*st_device_forward.reloc_ptrs)(vptr, sizeof(gx_device_forward), gcst);
+} RELOC_PTRS_END
+#undef mptr
+
+/* Define the palettes for monobit devices. */
+private const byte b_w_palette_string[6] = { 0xff,0xff,0xff, 0,0,0 };
+const gs_const_string mem_mono_b_w_palette = { b_w_palette_string, 6 };
+private const byte w_b_palette_string[6] = { 0,0,0, 0xff,0xff,0xff };
+const gs_const_string mem_mono_w_b_palette = { w_b_palette_string, 6 };
+
+/* ------ Generic code ------ */
+
+/* Return the appropriate memory device for a given */
+/* number of bits per pixel (0 if none suitable). */
+const gx_device_memory *
+gdev_mem_device_for_bits(int bits_per_pixel)
+{ switch ( bits_per_pixel )
+ {
+ case 1: return &mem_mono_device;
+ case 2: return &mem_mapped2_device;
+ case 4: return &mem_mapped4_device;
+ case 8: return &mem_mapped8_device;
+ case 16: return &mem_true16_device;
+ case 24: return &mem_true24_device;
+ case 32: return &mem_true32_device;
+ default: return 0;
+ }
+}
+/* Do the same for a word-oriented device. */
+const gx_device_memory *
+gdev_mem_word_device_for_bits(int bits_per_pixel)
+{ switch ( bits_per_pixel )
+ {
+ case 1: return &mem_mono_word_device;
+ case 2: return &mem_mapped2_word_device;
+ case 4: return &mem_mapped4_word_device;
+ case 8: return &mem_mapped8_word_device;
+ case 24: return &mem_true24_word_device;
+ case 32: return &mem_true32_word_device;
+ default: return 0;
+ }
+}
+
+/* Make a memory device. */
+/* Note that the default for monobit devices is white = 0, black = 1. */
+void
+gs_make_mem_device(gx_device_memory *dev, const gx_device_memory *mdproto,
+ gs_memory_t *mem, int page_device, gx_device *target)
+{ *dev = *mdproto;
+ dev->memory = mem;
+ dev->stype = &st_device_memory;
+ switch ( page_device )
+ {
+ case -1:
+ dev->std_procs.get_page_device = gx_default_get_page_device;
+ break;
+ case 1:
+ dev->std_procs.get_page_device = gx_page_device_get_page_device;
+ break;
+ }
+ dev->target = target;
+ if ( target != 0 )
+ { /* Forward the color mapping operations to the target. */
+ gx_device_forward_color_procs((gx_device_forward *)dev);
+ }
+ if ( dev->color_info.depth == 1 )
+ gdev_mem_mono_set_inverted(dev,
+ (target == 0 ||
+ (*dev_proc(target, map_rgb_color))
+ (target, (gx_color_value)0, (gx_color_value)0,
+ (gx_color_value)0) != 0));
+}
+/* Make a monobit memory device. This is never a page device. */
+/* Note that white=0, black=1. */
+void
+gs_make_mem_mono_device(gx_device_memory *dev, gs_memory_t *mem,
+ gx_device *target)
+{ *dev = mem_mono_device;
+ dev->memory = mem;
+ dev->std_procs.get_page_device = gx_default_get_page_device;
+ mdev->target = target;
+ gdev_mem_mono_set_inverted(dev, true);
+}
+
+
+/* Define whether a monobit memory device is inverted (black=1). */
+void
+gdev_mem_mono_set_inverted(gx_device_memory *dev, bool black_is_1)
+{ if ( black_is_1 )
+ dev->palette = mem_mono_b_w_palette;
+ else
+ dev->palette = mem_mono_w_b_palette;
+}
+
+/* Compute the size of the bitmap storage, */
+/* including the space for the scan line pointer table. */
+/* Note that scan lines are padded to a multiple of align_bitmap_mod bytes, */
+/* and additional padding may be needed if the pointer table */
+/* must be aligned to an even larger modulus. */
+private ulong
+mem_bitmap_bits_size(const gx_device_memory *dev, int width, int height)
+{ return round_up((ulong)height *
+ bitmap_raster(width * dev->color_info.depth),
+ max(align_bitmap_mod, arch_align_ptr_mod));
+}
+ulong
+gdev_mem_data_size(const gx_device_memory *dev, int width, int height)
+{ return mem_bitmap_bits_size(dev, width, height) +
+ (ulong)height * sizeof(byte *);
+
+}
+/*
+ * Do the inverse computation: given a width (in pixels) and a buffer size,
+ * compute the maximum height.
+ */
+int
+gdev_mem_max_height(const gx_device_memory *dev, int width, ulong size)
+{ ulong max_height = size /
+ (bitmap_raster(width * dev->color_info.depth) + sizeof(byte *));
+ int height = (int)min(max_height, max_int);
+
+ /*
+ * Because of alignment rounding, the just-computed height might
+ * be too large by a small amount. Adjust it the easy way.
+ */
+ while ( gdev_mem_data_size(dev, width, height) > size )
+ --height;
+ return height;
+}
+
+/* Open a memory device, allocating the data area if appropriate, */
+/* and create the scan line table. */
+private void mem_set_line_ptrs(P3(gx_device_memory *, byte **, byte *));
+int
+mem_open(gx_device *dev)
+{ if ( mdev->bitmap_memory != 0 )
+ { /* Allocate the data now. */
+ ulong size = gdev_mem_bitmap_size(mdev);
+ if ( (uint)size != size )
+ return_error(gs_error_limitcheck);
+ mdev->base = gs_alloc_bytes(mdev->bitmap_memory, (uint)size,
+ "mem_open");
+ if ( mdev->base == 0 )
+ return_error(gs_error_VMerror);
+ mdev->foreign_bits = false;
+ }
+/*
+ * Macro for adding an offset to a pointer when setting up the
+ * scan line table. This isn't just pointer arithmetic, because of
+ * the segmenting considerations discussed in gdevmem.h.
+ */
+#define huge_ptr_add(base, offset)\
+ ((void *)((byte huge *)(base) + (offset)))
+ mem_set_line_ptrs(mdev,
+ huge_ptr_add(mdev->base,
+ mem_bitmap_bits_size(mdev, mdev->width,
+ mdev->height)),
+ mdev->base);
+ return 0;
+}
+/* Set up the scan line pointers of a memory device. */
+/* Sets line_ptrs, base, raster; uses width, height, color_info.depth. */
+private void
+mem_set_line_ptrs(gx_device_memory *devm, byte **line_ptrs, byte *base)
+{ byte **pptr = devm->line_ptrs = line_ptrs;
+ byte **pend = pptr + devm->height;
+ byte *scan_line = devm->base = base;
+ uint raster = devm->raster = gdev_mem_raster(devm);
+
+ while ( pptr < pend )
+ { *pptr++ = scan_line;
+ scan_line = huge_ptr_add(scan_line, raster);
+ }
+}
+
+/* Return the initial transformation matrix */
+void
+mem_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+{ pmat->xx = mdev->initial_matrix.xx;
+ pmat->xy = mdev->initial_matrix.xy;
+ pmat->yx = mdev->initial_matrix.yx;
+ pmat->yy = mdev->initial_matrix.yy;
+ pmat->tx = mdev->initial_matrix.tx;
+ pmat->ty = mdev->initial_matrix.ty;
+}
+
+/* Test whether a device is a memory device */
+bool
+gs_device_is_memory(const gx_device *dev)
+{ /* We can't just compare the procs, or even an individual proc, */
+ /* because we might be tracing. Instead, check the identity of */
+ /* the device name. */
+ const gx_device_memory *bdev =
+ gdev_mem_device_for_bits(dev->color_info.depth);
+ if ( bdev != 0 && bdev->dname == dev->dname )
+ return true;
+ bdev = gdev_mem_word_device_for_bits(dev->color_info.depth);
+ return (bdev != 0 && bdev->dname == dev->dname);
+}
+
+/* Close a memory device, freeing the data area if appropriate. */
+int
+mem_close(gx_device *dev)
+{ if ( mdev->bitmap_memory != 0 )
+ gs_free_object(mdev->bitmap_memory, mdev->base, "mem_close");
+ return 0;
+}
+
+/* Copy a scan line to a client. */
+#undef chunk
+#define chunk byte
+int
+mem_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ byte *src;
+ if ( y < 0 || y >= dev->height )
+ return_error(gs_error_rangecheck);
+ src = scan_line_base(mdev, y);
+ if ( actual_data == 0 )
+ memcpy(str, src, gx_device_raster(dev, 0));
+ else
+ *actual_data = src;
+ return 0;
+}
+
+#if !arch_is_big_endian
+
+/* Swap byte order in a rectangular subset of a bitmap. */
+/* If store = true, assume the rectangle will be overwritten, */
+/* so don't swap any bytes where it doesn't matter. */
+/* The caller has already done a fit_fill or fit_copy. */
+void
+mem_swap_byte_rect(byte *base, uint raster, int x, int w, int h, bool store)
+{ int xbit = x & 31;
+ if ( store )
+ { if ( xbit + w > 64 )
+ { /* Operation spans multiple words. */
+ /* Just swap the words at the left and right edges. */
+ if ( xbit != 0 )
+ mem_swap_byte_rect(base, raster, x, 1, h, false);
+ x += w - 1;
+ xbit = x & 31;
+ if ( xbit == 31 )
+ return;
+ w = 1;
+ }
+ }
+ /* Swap the entire rectangle (or what's left of it). */
+ { byte *row = base + ((x >> 5) << 2);
+ int nw = (xbit + w + 31) >> 5;
+ int ny;
+ for ( ny = h; ny > 0; row += raster, --ny )
+ { int nx = nw;
+ bits32 *pw = (bits32 *)row;
+ do
+ { bits32 w = *pw;
+ *pw++ = (w >> 24) + ((w >> 8) & 0xff00) +
+ ((w & 0xff00) << 8) + (w << 24);
+ }
+ while ( --nx);
+ }
+ }
+}
+
+/* Copy a word-oriented scan line to the client, swapping bytes as needed. */
+int
+mem_word_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ byte *src;
+ uint raster = gx_device_raster(dev, 0); /* only doing 1 scan line */
+ if ( y < 0 || y >= dev->height )
+ return_error(gs_error_rangecheck);
+ src = scan_line_base(mdev, y);
+ /* We use raster << 3 rather than dev->width so that */
+ /* the right thing will happen if depth > 1. */
+ mem_swap_byte_rect(src, raster, 0, raster << 3, 1, false);
+ memcpy(str, src, raster);
+ if ( actual_data != 0 )
+ *actual_data = str;
+ mem_swap_byte_rect(src, raster, 0, raster << 3, 1, false);
+ return 0;
+}
+
+#endif /* !arch_is_big_endian */
+
+/* Map a r-g-b color to a color index for a mapped color memory device */
+/* (2, 4, or 8 bits per pixel.) */
+/* This requires searching the palette. */
+gx_color_index
+mem_mapped_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ byte br = gx_color_value_to_byte(r);
+ byte bg = gx_color_value_to_byte(g);
+ byte bb = gx_color_value_to_byte(b);
+ register const byte *pptr = mdev->palette.data;
+ int cnt = mdev->palette.size;
+ const byte *which = 0; /* initialized only to pacify gcc */
+ int best = 256*3;
+
+ while ( (cnt -= 3) >= 0 )
+ { register int diff = *pptr - br;
+ if ( diff < 0 ) diff = -diff;
+ if ( diff < best ) /* quick rejection */
+ { int dg = pptr[1] - bg;
+ if ( dg < 0 ) dg = -dg;
+ if ( (diff += dg) < best ) /* quick rejection */
+ { int db = pptr[2] - bb;
+ if ( db < 0 ) db = -db;
+ if ( (diff += db) < best )
+ which = pptr, best = diff;
+ }
+ }
+ pptr += 3;
+ }
+ return (gx_color_index)((which - mdev->palette.data) / 3);
+}
+
+/* Map a color index to a r-g-b color for a mapped color memory device. */
+int
+mem_mapped_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ const byte *pptr = mdev->palette.data + (int)color * 3;
+ prgb[0] = gx_color_value_from_byte(pptr[0]);
+ prgb[1] = gx_color_value_from_byte(pptr[1]);
+ prgb[2] = gx_color_value_from_byte(pptr[2]);
+ return 0;
+}
diff --git a/gs/src/gdevmem.h b/gs/src/gdevmem.h
new file mode 100644
index 000000000..0b99fbffd
--- /dev/null
+++ b/gs/src/gdevmem.h
@@ -0,0 +1,214 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmem.h */
+/* Private definitions for memory devices. */
+
+#include "gsbitops.h"
+
+/*
+ The representation for a "memory" device is simply a
+ contiguous bitmap stored in something like the PostScript
+ representation, i.e., each scan line (in left-to-right order), padded
+ to a multiple of bitmap_align_mod bytes, followed immediately by
+ the next one.
+
+ The representation of strings in the interpreter limits
+ the size of a string to 64K-1 bytes, which means we can't simply use
+ a string for the contents of a memory device.
+ We get around this problem by making the client read out the
+ contents of a memory device bitmap in pieces.
+
+ On 80x86 PCs running in 16-bit mode, there may be no way to
+ obtain a contiguous block of storage larger than 64K bytes,
+ which typically isn't big enough for a full-screen bitmap.
+ We take the following compromise position: if the PC is running in
+ native mode (pseudo-segmenting), we limit the bitmap to 64K;
+ if the PC is running in protected mode (e.g., under MS Windows),
+ we assume that blocks larger than 64K have sequential segment numbers,
+ and that the client arranges things so that an individual scan line,
+ the scan line pointer table, and any single call on a drawing routine
+ do not cross a segment boundary.
+
+ Even though the scan lines are stored contiguously, we store a table
+ of their base addresses, because indexing into it is faster than
+ the multiplication that would otherwise be needed.
+*/
+
+/*
+ * Macros for scan line access.
+ * x_to_byte is different for each number of bits per pixel.
+ * Note that these macros depend on the definition of chunk:
+ * each procedure that uses the scanning macros should #define
+ * (not typedef) chunk as either uint or byte.
+ */
+#define declare_scan_ptr(ptr) declare_scan_ptr_as(ptr, chunk *)
+#define declare_scan_ptr_as(ptr,ptype)\
+ register ptype ptr; uint draster
+#define setup_rect(ptr) setup_rect_as(ptr, chunk *)
+#define setup_rect_as(ptr,ptype)\
+ draster = mdev->raster;\
+ ptr = (ptype)(scan_line_base(mdev, y) +\
+ (x_to_byte(x) & -chunk_align_bytes))
+
+/* ------ Generic macros ------ */
+
+/* Macro for declaring the essential device procedures. */
+dev_proc_get_initial_matrix(mem_get_initial_matrix);
+dev_proc_close_device(mem_close);
+#define declare_mem_map_procs(map_rgb_color, map_color_rgb)\
+ private dev_proc_map_rgb_color(map_rgb_color);\
+ private dev_proc_map_color_rgb(map_color_rgb)
+#define declare_mem_procs(copy_mono, copy_color, fill_rectangle)\
+ private dev_proc_copy_mono(copy_mono);\
+ private dev_proc_copy_color(copy_color);\
+ private dev_proc_fill_rectangle(fill_rectangle)
+
+/* The following are used for all except planar or word-oriented devices. */
+dev_proc_open_device(mem_open);
+dev_proc_get_bits(mem_get_bits);
+/* The following are for word-oriented devices. */
+#if arch_is_big_endian
+# define mem_word_get_bits mem_get_bits
+#else
+dev_proc_get_bits(mem_word_get_bits);
+#endif
+/* The following are used for the non-true-color devices. */
+dev_proc_map_rgb_color(mem_mapped_map_rgb_color);
+dev_proc_map_color_rgb(mem_mapped_map_color_rgb);
+
+/*
+ * Macro for generating the device descriptor.
+ * Various compilers have problems with the obvious definition
+ * for max_value, namely:
+ * (depth >= 8 ? 255 : (1 << depth) - 1)
+ * I tried changing (1 << depth) to (1 << (depth & 15)) to forestall bogus
+ * error messages about invalid shift counts, but the H-P compiler chokes
+ * on this. Since the only values of depth we ever plan to support are
+ * powers of 2 (and 24), we just go ahead and enumerate them.
+ */
+#define max_value_gray(rgb_depth, gray_depth)\
+ (gray_depth ? (1 << gray_depth) - 1 : max_value_rgb(rgb_depth, 0))
+#define max_value_rgb(rgb_depth, gray_depth)\
+ (rgb_depth >= 8 ? 255 : rgb_depth == 4 ? 15 : rgb_depth == 2 ? 3 :\
+ rgb_depth == 1 ? 1 : (1 << gray_depth) - 1)
+#define mem_full_alpha_device(name, rgb_depth, gray_depth, open, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, get_bits, map_cmyk_color, copy_alpha, strip_tile_rectangle, strip_copy_rop)\
+{ std_device_dci_body(gx_device_memory, 0, name,\
+ 0, 0, 72, 72,\
+ (rgb_depth ? 3 : 0) + (gray_depth ? 1 : 0), /* num_components */\
+ rgb_depth + gray_depth, /* depth */\
+ max_value_gray(rgb_depth, gray_depth), /* max_gray */\
+ max_value_rgb(rgb_depth, gray_depth), /* max_color */\
+ max_value_gray(rgb_depth, gray_depth) + 1, /* dither_grays */\
+ max_value_rgb(rgb_depth, gray_depth) + 1 /* dither_colors */\
+ ),\
+ { open, /* differs */\
+ mem_get_initial_matrix,\
+ gx_default_sync_output,\
+ gx_default_output_page,\
+ mem_close,\
+ map_rgb_color, /* differs */\
+ map_color_rgb, /* differs */\
+ fill_rectangle, /* differs */\
+ gx_default_tile_rectangle,\
+ copy_mono, /* differs */\
+ copy_color, /* differs */\
+ gx_default_draw_line,\
+ get_bits, /* differs */\
+ gx_default_get_params,\
+ gx_default_put_params,\
+ map_cmyk_color, /* differs */\
+ gx_forward_get_xfont_procs,\
+ gx_forward_get_xfont_device,\
+ gx_default_map_rgb_alpha_color,\
+ gx_forward_get_page_device,\
+ gx_default_get_alpha_bits, /* default is no alpha */\
+ copy_alpha, /* differs */\
+ gx_default_get_band,\
+ gx_default_copy_rop,\
+ gx_default_fill_path,\
+ gx_default_stroke_path,\
+ gx_default_fill_mask,\
+ gx_default_fill_trapezoid,\
+ gx_default_fill_parallelogram,\
+ gx_default_fill_triangle,\
+ gx_default_draw_thin_line,\
+ gx_default_begin_image,\
+ gx_default_image_data,\
+ gx_default_end_image,\
+ strip_tile_rectangle, /* differs */\
+ strip_copy_rop, /* differs */\
+ gx_default_get_clipping_box,\
+ gx_default_get_hardware_params\
+ },\
+ 0, /* target */\
+ mem_device_init_private /* see gxdevmem.h */\
+}
+#define mem_full_device(name, rgb_depth, gray_depth, open, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, get_bits, map_cmyk_color, strip_tile_rectangle, strip_copy_rop)\
+ mem_full_alpha_device(name, rgb_depth, gray_depth, open, map_rgb_color,\
+ map_color_rgb, copy_mono, copy_color, fill_rectangle,\
+ get_bits, map_cmyk_color, gx_default_copy_alpha,\
+ strip_tile_rectangle, strip_copy_rop)
+#define mem_device(name, rgb_depth, gray_depth, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, strip_copy_rop)\
+ mem_full_device(name, rgb_depth, gray_depth, mem_open, map_rgb_color,\
+ map_color_rgb, copy_mono, copy_color, fill_rectangle,\
+ mem_get_bits, gx_default_map_cmyk_color,\
+ gx_default_strip_tile_rectangle, strip_copy_rop)
+
+/* Swap a rectangle of bytes, for converting between word- and */
+/* byte-oriented representation. */
+void mem_swap_byte_rect(P6(byte *, uint, int, int, int, bool));
+
+/* Copy a rectangle of bytes from a source to a destination. */
+#define mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h)\
+ bytes_copy_rectangle(scan_line_base(mdev, y) + x_to_byte(x),\
+ (mdev)->raster,\
+ base + x_to_byte(sourcex), sraster,\
+ x_to_byte(w), h)
+
+/* Macro for casting gx_device argument */
+#define mdev ((gx_device_memory *)dev)
+
+/* ------ Implementations ------ */
+
+extern const gx_device_memory far_data mem_mono_device;
+extern const gx_device_memory far_data mem_mapped2_device;
+extern const gx_device_memory far_data mem_mapped4_device;
+extern const gx_device_memory far_data mem_mapped8_device;
+extern const gx_device_memory far_data mem_true16_device;
+extern const gx_device_memory far_data mem_true24_device;
+extern const gx_device_memory far_data mem_true32_device;
+extern const gx_device_memory far_data mem_planar_device;
+#if arch_is_big_endian
+# define mem_mono_word_device mem_mono_device
+# define mem_mapped2_word_device mem_mapped2_device
+# define mem_mapped4_word_device mem_mapped4_device
+# define mem_mapped8_word_device mem_mapped8_device
+# define mem_true24_word_device mem_true24_device
+# define mem_true32_word_device mem_true32_device
+#else
+extern const gx_device_memory far_data mem_mono_word_device;
+extern const gx_device_memory far_data mem_mapped2_word_device;
+extern const gx_device_memory far_data mem_mapped4_word_device;
+extern const gx_device_memory far_data mem_mapped8_word_device;
+extern const gx_device_memory far_data mem_true24_word_device;
+extern const gx_device_memory far_data mem_true32_word_device;
+#endif
+/* Provide standard palettes for 1-bit devices. */
+extern const gs_const_string mem_mono_b_w_palette; /* black=1, white=0 */
+extern const gs_const_string mem_mono_w_b_palette; /* black=0, white=1 */
diff --git a/gs/src/gdevmgr.c b/gs/src/gdevmgr.c
new file mode 100644
index 000000000..a00c78105
--- /dev/null
+++ b/gs/src/gdevmgr.c
@@ -0,0 +1,433 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmgr.c */
+/* MGR device driver */
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "gdevmgr.h"
+
+/* Structure for MGR devices, which extend the generic printer device. */
+struct gx_device_mgr_s {
+ gx_device_common;
+ gx_prn_device_common;
+ /* Add MGR specific variables */
+ int mgr_depth;
+};
+typedef struct gx_device_mgr_s gx_device_mgr;
+
+static struct nclut clut[256];
+
+private unsigned int clut2mgr(P2(int, int));
+private void swap_bwords(P2(unsigned char *, int));
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+/* Macro for generating MGR device descriptors. */
+#define mgr_prn_device(procs, dev_name, num_comp, depth, mgr_depth,\
+ max_gray, max_rgb, dither_gray, dither_rgb, print_page)\
+{ prn_device_body(gx_device_mgr, procs, dev_name,\
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI,\
+ 0, 0, 0, 0,\
+ num_comp, depth, max_gray, max_rgb, dither_gray, dither_rgb,\
+ print_page),\
+ mgr_depth\
+}
+
+/* For all mgr variants we do some extra things at opening time. */
+/* private dev_proc_open_device(gdev_mgr_open); */
+#define gdev_mgr_open gdev_prn_open /* no we don't! */
+
+/* And of course we need our own print-page routines. */
+private dev_proc_print_page(mgr_print_page);
+private dev_proc_print_page(mgrN_print_page);
+private dev_proc_print_page(cmgrN_print_page);
+
+/* The device procedures */
+private gx_device_procs mgr_procs =
+ prn_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close);
+private gx_device_procs mgrN_procs =
+ prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
+private gx_device_procs cmgr4_procs =
+ prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
+ pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
+private gx_device_procs cmgr8_procs =
+ prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
+ mgr_8bit_map_rgb_color, mgr_8bit_map_color_rgb);
+
+/* The device descriptors themselves */
+gx_device_mgr far_data gs_mgrmono_device =
+ mgr_prn_device( mgr_procs, "mgrmono", 1, 1, 1, 1, 0, 2, 0, mgr_print_page);
+gx_device_mgr far_data gs_mgrgray2_device =
+ mgr_prn_device(mgrN_procs, "mgrgray2",1, 8, 2, 255, 0, 4, 0, mgrN_print_page);
+gx_device_mgr far_data gs_mgrgray4_device =
+ mgr_prn_device(mgrN_procs, "mgrgray4",1, 8, 4, 255, 0,16, 0, mgrN_print_page);
+gx_device_mgr far_data gs_mgrgray8_device =
+ mgr_prn_device(mgrN_procs, "mgrgray8",1, 8, 8, 255, 0, 0, 0, mgrN_print_page);
+gx_device_mgr far_data gs_mgr4_device =
+ mgr_prn_device(cmgr4_procs, "mgr4", 3, 8, 4, 1, 1, 4, 3, cmgrN_print_page);
+gx_device_mgr far_data gs_mgr8_device =
+ mgr_prn_device(cmgr8_procs, "mgr8", 3, 8, 8, 255, 255, 6, 5, cmgrN_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Define a "cursor" that keeps track of where we are in the page. */
+typedef struct mgr_cursor_s {
+ gx_device_mgr *dev;
+ int bpp; /* bits per pixel */
+ uint line_size; /* bytes per scan line */
+ byte *data; /* output row buffer */
+ int lnum; /* row within page */
+} mgr_cursor;
+
+/* Begin an MGR output page. */
+/* Write the header information and initialize the cursor. */
+private int
+mgr_begin_page(gx_device_mgr *bdev, FILE *pstream, mgr_cursor _ss *pcur)
+{ struct b_header head;
+ uint line_size =
+ gdev_prn_raster((gx_device_printer *)bdev) + 3;
+ byte *data = (byte *)gs_malloc(line_size, 1, "mgr_begin_page");
+ if ( data == 0 )
+ return_error(gs_error_VMerror);
+
+ /* Write the header */
+ B_PUTHDR8(&head, bdev->width, bdev->height, bdev->mgr_depth);
+ fprintf(pstream, "");
+ if ( fwrite(&head, 1, sizeof(head), pstream) < sizeof(head) )
+ return_error(gs_error_ioerror);
+ fflush(pstream);
+
+ /* Initialize the cursor. */
+ pcur->dev = bdev;
+ pcur->bpp = bdev->color_info.depth;
+ pcur->line_size = line_size;
+ pcur->data = data;
+ pcur->lnum = 0;
+ return 0;
+}
+
+/* Advance to the next row. Return 0 if more, 1 if done. */
+private int
+mgr_next_row(mgr_cursor _ss *pcur)
+{ if ( pcur->lnum >= pcur->dev->height )
+ { gs_free((char *)pcur->data, pcur->line_size, 1,
+ "mgr_next_row(done)");
+ return 1;
+ }
+ gdev_prn_copy_scan_lines((gx_device_printer *)pcur->dev,
+ pcur->lnum++, pcur->data, pcur->line_size);
+ return 0;
+}
+
+/* ------ Individual page printing routines ------ */
+
+#define bdev ((gx_device_mgr *)pdev)
+
+/* Print a monochrome page. */
+private int
+mgr_print_page(gx_device_printer *pdev, FILE *pstream)
+{ mgr_cursor cur;
+ int mgr_wide;
+ int code = mgr_begin_page(bdev, pstream, &cur);
+ if ( code < 0 ) return code;
+
+ mgr_wide = bdev->width;
+ if (mgr_wide & 7)
+ mgr_wide += 8 - (mgr_wide & 7);
+
+ while ( !(code = mgr_next_row(&cur)) )
+ { if ( fwrite(cur.data, sizeof(char), mgr_wide / 8, pstream) <
+ mgr_wide / 8)
+ return_error(gs_error_ioerror);
+ }
+ return (code < 0 ? code : 0);
+}
+
+
+/* Print a gray-mapped page. */
+static unsigned char bgreytable[16], bgreybacktable[16];
+static unsigned char bgrey256table[256], bgrey256backtable[256];
+/* private */
+int
+mgrN_print_page(gx_device_printer *pdev, FILE *pstream)
+{ mgr_cursor cur;
+ int i = 0, j, k, mgr_wide;
+ uint mgr_line_size;
+ byte *bp, *data = NULL, *dp;
+
+ int code = mgr_begin_page(bdev, pstream, &cur);
+ if ( code < 0 ) return code;
+
+ mgr_wide = bdev->width;
+ if ( bdev->mgr_depth == 2 && mgr_wide & 3 )
+ mgr_wide += 4 - (mgr_wide & 3);
+ if ( bdev->mgr_depth == 4 && mgr_wide & 1 )
+ mgr_wide++;
+ mgr_line_size = mgr_wide / ( 8 / bdev->mgr_depth );
+
+ if ( bdev->mgr_depth == 4 )
+ for ( i = 0; i < 16; i++ ) {
+ bgreytable[i] = mgrlut[LUT_BGREY][RGB_RED][i];
+ bgreybacktable[bgreytable[i]] = i;
+ }
+
+ if ( bdev->mgr_depth == 8 ) {
+ for ( i = 0; i < 16; i++ ) {
+ bgrey256table[i] = mgrlut[LUT_BGREY][RGB_RED][i] << 4;
+ bgrey256backtable[bgrey256table[i]] = i;
+ }
+ for ( i = 16,j = 0; i < 256; i++ ) {
+ for ( k = 0; k < 16; k++ )
+ if ( j == mgrlut[LUT_BGREY][RGB_RED][k] << 4 ) {
+ j++;
+ break;
+ }
+ bgrey256table[i] = j;
+ bgrey256backtable[j++] = i;
+ }
+ }
+
+ if ( bdev->mgr_depth != 8 )
+ data = (byte *)gs_malloc(mgr_line_size, 1, "mgrN_print_page");
+
+ while ( !(code = mgr_next_row(&cur)) )
+ {
+ switch (bdev->mgr_depth) {
+ case 2:
+ for (i = 0,dp = data,bp = cur.data; i < mgr_line_size; i++) {
+ *dp = *(bp++) & 0xc0;
+ *dp |= (*(bp++) & 0xc0) >> 2;
+ *dp |= (*(bp++) & 0xc0) >> 4;
+ *(dp++) |= (*(bp++) & 0xc0) >> 6;
+ }
+ if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
+ return_error(gs_error_ioerror);
+ break;
+
+ case 4:
+ for (i = 0,dp = data, bp = cur.data; i < mgr_line_size; i++) {
+ *dp = bgreybacktable[*(bp++) >> 4] << 4;
+ *(dp++) |= bgreybacktable[*(bp++) >> 4];
+ }
+ if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
+ return_error(gs_error_ioerror);
+ break;
+
+ case 8:
+ for (i = 0,bp = cur.data; i < mgr_line_size; i++, bp++)
+ *bp = bgrey256backtable[*bp];
+ if ( fwrite(cur.data, sizeof(cur.data[0]), mgr_line_size, pstream)
+ < mgr_line_size )
+ return_error(gs_error_ioerror);
+ break;
+ }
+ }
+ if (bdev->mgr_depth != 8)
+ gs_free((char *)data, mgr_line_size, 1, "mgrN_print_page(done)");
+
+ if (bdev->mgr_depth == 2) {
+ for (i = 0; i < 4; i++) {
+ clut[i].colnum = i;
+ clut[i].red = clut[i].green = clut[i].blue = clut2mgr(i, 2);
+ }
+ }
+ if (bdev->mgr_depth == 4) {
+ for (i = 0; i < 16; i++) {
+ clut[i].colnum = i;
+ clut[i].red = clut[i].green = clut[i].blue = clut2mgr(bgreytable[i], 4);
+ }
+ }
+ if (bdev->mgr_depth == 8) {
+ for (i = 0; i < 256; i++) {
+ clut[i].colnum = i;
+ clut[i].red = clut[i].green = clut[i].blue = clut2mgr(bgrey256table[i], 8);
+ }
+ }
+#if !arch_is_big_endian
+ swap_bwords( (unsigned char *) clut, sizeof( struct nclut ) * i );
+#endif
+ if ( fwrite(&clut, sizeof(struct nclut), i, pstream) < i )
+ return_error(gs_error_ioerror);
+ return (code < 0 ? code : 0);
+}
+
+/* Print a color page. */
+private int
+cmgrN_print_page(gx_device_printer *pdev, FILE *pstream)
+{ mgr_cursor cur;
+ int i = 0, j, mgr_wide, r, g, b, colors8 = 0;
+ uint mgr_line_size;
+ byte *bp, *data, *dp;
+ ushort prgb[3];
+ unsigned char table[256], backtable[256];
+
+ int code = mgr_begin_page(bdev, pstream, &cur);
+ if ( code < 0 ) return code;
+
+ mgr_wide = bdev->width;
+ if (bdev->mgr_depth == 4 && mgr_wide & 1)
+ mgr_wide++;
+ mgr_line_size = mgr_wide / (8 / bdev->mgr_depth);
+ data = (byte *)gs_malloc(mgr_line_size, 1, "cmgrN_print_page");
+
+ if ( bdev->mgr_depth == 8 ) {
+ memset( table, 0, sizeof(table) );
+ for ( r = 0; r <= 6; r++ )
+ for ( g = 0; g <= 6; g++ )
+ for ( b = 0; b <= 6; b++ )
+ if ( r == g && g == b )
+ table[ r + (256-7) ] = 1;
+ else
+ table[ (r << 5) + (g << 2) + (b >> 1) ] = 1;
+ for ( i = j = 0; i < sizeof(table); i++ )
+ if ( table[i] == 1 ) {
+ backtable[i] = j;
+ table[j++] = i;
+ }
+ colors8 = j;
+ }
+ while ( !(code = mgr_next_row(&cur)) )
+ {
+ switch (bdev->mgr_depth) {
+ case 4:
+ for (i = 0,dp = data, bp = cur.data; i < mgr_line_size; i++) {
+ *dp = *(bp++) << 4;
+ *(dp++) |= *(bp++) & 0x0f;
+ }
+ if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
+ return_error(gs_error_ioerror);
+ break;
+
+ case 8:
+ for (i = 0,bp = cur.data; i < mgr_line_size; i++, bp++)
+ *bp = backtable[*bp] + MGR_RESERVEDCOLORS;
+ if ( fwrite(cur.data, sizeof(cur.data[0]), mgr_line_size, pstream) < mgr_line_size )
+ return_error(gs_error_ioerror);
+ break;
+ }
+ }
+ gs_free((char *)data, mgr_line_size, 1, "cmgrN_print_page(done)");
+
+ if (bdev->mgr_depth == 4) {
+ for (i = 0; i < 16; i++) {
+ pc_4bit_map_color_rgb((gx_device *)0, (gx_color_index) i, prgb);
+ clut[i].colnum = i;
+ clut[i].red = clut2mgr(prgb[0], 16);
+ clut[i].green = clut2mgr(prgb[1], 16);
+ clut[i].blue = clut2mgr(prgb[2], 16);
+ }
+ }
+ if (bdev->mgr_depth == 8) {
+ for (i = 0; i < colors8; i++) {
+ mgr_8bit_map_color_rgb((gx_device *)0, (gx_color_index)
+ table[i], prgb);
+ clut[i].colnum = MGR_RESERVEDCOLORS + i;
+ clut[i].red = clut2mgr(prgb[0], 16);
+ clut[i].green = clut2mgr(prgb[1], 16);
+ clut[i].blue = clut2mgr(prgb[2], 16);
+ }
+ }
+#if !arch_is_big_endian
+ swap_bwords( (unsigned char *) clut, sizeof( struct nclut ) * i );
+#endif
+ if ( fwrite(&clut, sizeof(struct nclut), i, pstream) < i )
+ return_error(gs_error_ioerror);
+ return (code < 0 ? code : 0);
+}
+
+
+/* Color mapping routines for 8-bit color with a fixed palette */
+/* (3 bits of R, 3 bits of G, 2 bits of B). */
+/* We have to trade off even spacing of colors along each axis */
+/* against the desire to have real gray shades; */
+/* MGR compromises by using a 7x7x4 "cube" with extra gray shades */
+/* (1/6, 1/2, and 5/6), instead of the obvious 8x8x4. */
+
+gx_color_index
+mgr_8bit_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ uint rv = r / (gx_max_color_value / 7 + 1);
+ uint gv = g / (gx_max_color_value / 7 + 1);
+ uint bv = b / (gx_max_color_value / 7 + 1);
+ return (gx_color_index)
+ (rv == gv && gv == bv ? rv + (256-7) :
+ (rv << 5) + (gv << 2) + (bv >> 1));
+}
+int
+mgr_8bit_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ static const gx_color_value ramp[8] =
+ { 0, gx_max_color_value / 6, gx_max_color_value / 3,
+ gx_max_color_value / 2, 2 * (gx_max_color_value / 3),
+ 5 * (gx_max_color_value / 6), gx_max_color_value,
+ /* The 8th entry is not actually ever used, */
+ /* except to fill out the palette. */
+ gx_max_color_value
+ };
+#define icolor (uint)color
+ if ( icolor >= 256-7 )
+ { prgb[0] = prgb[1] = prgb[2] = ramp[icolor - (256-7)];
+ }
+ else
+ { prgb[0] = ramp[(icolor >> 5) & 7];
+ prgb[1] = ramp[(icolor >> 2) & 7];
+ prgb[2] = ramp[(icolor & 3) << 1];
+ }
+#undef icolor
+ return 0;
+}
+
+
+/* convert the 8-bit look-up table into the standard MGR look-up table */
+private unsigned int
+clut2mgr(
+ register int v, /* value in clut */
+ register int bits /* number of bits in clut */
+)
+{
+ register unsigned int i;
+
+ i = (unsigned int) 0xffffffff / ((1<<bits)-1);
+ return((v*i)/0x10000);
+}
+
+
+/*
+ * s w a p _ b w o r d s
+ */
+private void
+swap_bwords(register unsigned char *p, int n)
+{
+ register unsigned char c;
+
+ n /= 2;
+
+ for (; n > 0; n--, p += 2) {
+ c = p[0];
+ p[0] = p[1];
+ p[1] = c;
+ }
+}
diff --git a/gs/src/gdevmgr.h b/gs/src/gdevmgr.h
new file mode 100644
index 000000000..bcd1d7c15
--- /dev/null
+++ b/gs/src/gdevmgr.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmgr.h */
+/* Common header file for MGR devices */
+
+#define MGR_RESERVEDCOLORS 16
+
+/* Color mapping routines for 8-bit color (with a fixed palette). */
+dev_proc_map_rgb_color(mgr_8bit_map_rgb_color);
+dev_proc_map_color_rgb(mgr_8bit_map_color_rgb);
+
+
+/* extract from dump.h */
+
+/*
+ * format for saved bitmaps
+ */
+
+#define B_PUTHDR8(hdr, w, h, d) ( \
+ (hdr)->magic[0] = 'y', (hdr)->magic[1] = 'z', \
+ (hdr)->h_wide = (((w) >> 6) & 0x3f) + ' ', \
+ (hdr)->l_wide = ((w) & 0x3f) + ' ', \
+ (hdr)->h_high = (((h) >> 6) & 0x3f) + ' ', \
+ (hdr)->l_high = ((h) & 0x3f) + ' ', \
+ (hdr)->depth = ((d) & 0x3f) + ' ', \
+ (hdr)->_reserved = ' ' )
+
+struct b_header {
+ char magic[2]; /* magics */
+ char h_wide; /* upper byte width (biased with 0x20) */
+ char l_wide; /* lower byte width (biased with 0x20) */
+ char h_high; /* upper byte height (biased with 0x20) */
+ char l_high; /* lower byte height (biased with 0x20) */
+ char depth; /* depth (biased with 0x20) */
+ char _reserved; /* for alignment */
+};
+
+/*
+ * Color lookup table information
+ */
+struct nclut {
+ unsigned short colnum;
+ unsigned short red, green, blue;
+} ;
+
+
+/* extract from color.h */
+
+/*
+ * MGR Color Definitions
+ */
+
+#define LUT_BW 0
+#define LUT_GREY 1
+#define LUT_BGREY 2
+#define LUT_VGA 3
+#define LUT_BCT 4
+#define LUT_USER 5
+#define LUT 6
+#define LUT_8 LUT
+
+#define RGB_RED 0
+#define RGB_GREEN 1
+#define RGB_BLUE 2
+#define RGB 3
+
+#define LUTENTRIES 16
+
+#define BW_RED 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0
+#define BW_GREEN BW_RED
+#define BW_BLUE BW_RED
+
+#define GREY_RED 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#define GREY_GREEN GREY_RED
+#define GREY_BLUE GREY_RED
+
+#define BGREY_RED 1, 0, 2, 8, 4, 3, 13, 11, 7, 6, 10, 12, 14, 5, 9, 15
+#define BGREY_GREEN BGREY_RED
+#define BGREY_BLUE BGREY_RED
+
+#define VGA_RED 0, 0, 0, 0, 8, 8, 8, 12, 8, 0, 0, 0, 15, 15, 15, 15
+#define VGA_GREEN 0, 0, 8, 8, 0, 0, 8, 12, 8, 0, 15, 15, 0, 0, 15, 15
+#define VGA_BLUE 0, 8, 0, 8, 0, 8, 0, 12, 8, 15, 0, 15, 0, 15, 0, 15
+
+#define BCT_RED 1, 7, 6, 15, 14, 3, 13, 11, 7, 13, 13, 15, 15, 5, 9, 15
+#define BCT_GREEN 1, 7, 13, 12, 5, 3, 13, 11, 7, 14, 15, 15, 14, 5, 9, 15
+#define BCT_BLUE 1, 14, 6, 8, 5, 3, 13, 11, 7, 15, 14, 12, 13, 5, 9, 15
+
+#define USER_RED 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+#define USER_GREEN USER_RED
+#define USER_BLUE USER_RED
+
+static char mgrlut[LUT][RGB][LUTENTRIES] = {
+ { { BW_RED }, { BW_GREEN }, { BW_BLUE } },
+ { { GREY_RED }, { GREY_GREEN }, { GREY_BLUE } },
+ { { BGREY_RED }, { BGREY_GREEN }, { BGREY_BLUE } },
+ { { VGA_RED }, { VGA_GREEN }, { VGA_BLUE } },
+ { { BCT_RED }, { BCT_GREEN }, { BCT_BLUE } },
+ { { USER_RED }, { USER_GREEN }, { USER_BLUE } }
+};
diff --git a/gs/src/gdevmiff.c b/gs/src/gdevmiff.c
new file mode 100644
index 000000000..fbd7ce1b7
--- /dev/null
+++ b/gs/src/gdevmiff.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmiff.c */
+/* MIFF file format driver */
+#include "gdevprn.h"
+
+/* ------ The device descriptor ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+private dev_proc_print_page(miff24_print_page);
+
+private gx_device_procs miff24_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+gx_device_printer far_data gs_miff24_device =
+ prn_device(miff24_procs, "miff24",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 24, miff24_print_page);
+
+/* Print one page in 24-bit RLE direct color format. */
+private int
+miff24_print_page(gx_device_printer *pdev, FILE *file)
+{ int raster = gx_device_raster((gx_device *)pdev, true);
+ byte *line = (byte *)gs_malloc(raster, 1, "miff line buffer");
+ int y;
+ int code = 0; /* return code */
+
+ if ( line == 0 ) /* can't allocate line buffer */
+ return_error(gs_error_VMerror);
+ fputs("id=ImageMagick\n", file);
+ fputs("class=DirectClass\n", file);
+ fprintf(file, "columns=%d\n", pdev->width);
+ fputs("compression=RunlengthEncoded\n", file);
+ fprintf(file, "rows=%d\n", pdev->height);
+ fputs(":\n", file);
+ for ( y = 0; y < pdev->height; ++y )
+ { byte *row;
+ byte *end;
+
+ code = gdev_prn_get_bits(pdev, y, line, &row);
+ if ( code < 0 )
+ break;
+ end = row + pdev->width * 3;
+ while ( row < end )
+ { int count = 0;
+ while ( count < 255 && row < end - 3 &&
+ row[0] == row[3] && row[1] == row[4] &&
+ row[2] == row[5]
+ )
+ ++count, row += 3;
+ putc(row[0], file);
+ putc(row[1], file);
+ putc(row[2], file);
+ putc(count, file);
+ row += 3;
+ }
+ }
+ gs_free((char *)line, lsize, 1, "miff line buffer");
+
+ return code;
+}
diff --git a/gs/src/gdevmpla.c b/gs/src/gdevmpla.c
new file mode 100644
index 000000000..2201575e3
--- /dev/null
+++ b/gs/src/gdevmpla.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmpla.c */
+/* Any-depth planar "memory" (stored bitmap) devices */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/*
+ * Planar memory devices store the bits by planes instead of by chunks.
+ * The plane corresponding to the least significant bit of the color index
+ * is stored first.
+ *
+ * The current implementations are quite inefficient.
+ * We may improve them someday if anyone cares.
+ */
+
+/* Procedures */
+declare_mem_map_procs(mem_planar_map_rgb_color, mem_planar_map_color_rgb);
+declare_mem_procs(mem_planar_copy_mono, mem_planar_copy_color, mem_planar_fill_rectangle);
+
+/* The device descriptor. */
+/* The instance is public. */
+/* The default instance has depth = 1, but clients may set this */
+/* to other values before opening the device. */
+private dev_proc_open_device(mem_planar_open);
+private dev_proc_get_bits(mem_planar_get_bits);
+const gx_device_memory far_data mem_planar_device =
+ mem_full_device("image(planar)", 0, 1, mem_planar_open,
+ mem_planar_map_rgb_color, mem_planar_map_color_rgb,
+ mem_planar_copy_mono, mem_planar_copy_color, mem_planar_fill_rectangle,
+ mem_planar_get_bits, gx_default_map_cmyk_color,
+ gx_default_strip_tile_rectangle, gx_no_strip_copy_rop);
+
+/* Open a planar memory device. */
+private int
+mem_planar_open(gx_device *dev)
+{ /* Temporarily reset the parameters, and call */
+ /* the generic open procedure. */
+ int depth = dev->color_info.depth;
+ int height = dev->height;
+ int code;
+
+ dev->height *= depth;
+ dev->color_info.depth = 1;
+ code = mem_open(dev);
+ dev->height = height;
+ dev->color_info.depth = depth;
+ return code;
+}
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+mem_planar_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ int depth = dev->color_info.depth;
+ return (*dev_proc(gdev_mem_device_for_bits(depth), map_rgb_color))
+ (dev, r, g, b);
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+mem_planar_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ int depth = dev->color_info.depth;
+ return (*dev_proc(gdev_mem_device_for_bits(depth), map_color_rgb))
+ (dev, color, prgb);
+}
+
+/* Fill a rectangle with a color. */
+private int
+mem_planar_fill_rectangle(gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ byte **ptrs = mdev->line_ptrs;
+ int i;
+ for ( i = 0; i < dev->color_info.depth;
+ i++, mdev->line_ptrs += dev->height
+ )
+ (*dev_proc(&mem_mono_device, fill_rectangle))(dev,
+ x, y, w, h, (color >> i) & 1);
+ mdev->line_ptrs = ptrs;
+ return 0;
+}
+
+/* Copy a bitmap. */
+private int
+mem_planar_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ byte **ptrs = mdev->line_ptrs;
+ int i;
+ for ( i = 0; i < dev->color_info.depth;
+ i++, mdev->line_ptrs += dev->height
+ )
+ (*dev_proc(&mem_mono_device, copy_mono))(dev,
+ base, sourcex, sraster, id, x, y, w, h,
+ (zero == gx_no_color_index ? gx_no_color_index :
+ (zero >> i) & 1),
+ (one == gx_no_color_index ? gx_no_color_index :
+ (one >> i) & 1));
+ mdev->line_ptrs = ptrs;
+ return 0;
+}
+
+/* Copy a color bitmap. */
+/* This is very slow and messy. */
+private int
+mem_planar_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ byte **ptrs = mdev->line_ptrs;
+ int depth = dev->color_info.depth;
+ int wleft = w;
+ int hleft = h;
+ const byte *srow = base;
+ int ynext = y;
+#define max_w 32
+ union _b {
+ long l[max_w / sizeof(long)];
+ byte b[max_w / 8];
+ } buf;
+
+ while ( wleft > max_w )
+ { mem_planar_copy_color(dev, base,
+ sourcex + wleft - max_w, sraster, gx_no_bitmap_id,
+ x + wleft - max_w, y, max_w, h);
+ wleft -= max_w;
+ }
+ for ( ; hleft > 0;
+ srow += sraster, ynext++, hleft--,
+ mdev->line_ptrs += dev->height
+ )
+ { int i;
+ for ( i = 0; i < depth;
+ i++, mdev->line_ptrs += dev->height
+ )
+ { int sx, bx;
+ memset(buf.b, 0, sizeof(buf.b));
+ for ( sx = 0, bx = sourcex * depth + depth - 1 - i;
+ sx < w; sx++, bx += depth
+ )
+ if ( srow[bx >> 3] & (0x80 >> (bx & 7)) )
+ buf.b[sx >> 3] |= 0x80 >> (sx & 7);
+ (*dev_proc(&mem_mono_device, copy_mono))(dev,
+ buf.b, 0, sizeof(buf), gx_no_bitmap_id,
+ x, ynext, w, 1,
+ (gx_color_index)0, (gx_color_index)1);
+ }
+ mdev->line_ptrs = ptrs;
+ }
+ return 0;
+}
+
+/* Copy bits back from a planar memory device. */
+/****** NOT IMPLEMENTED YET ******/
+private int
+mem_planar_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ return_error(-1);
+}
diff --git a/gs/src/gdevmrop.c b/gs/src/gdevmrop.c
new file mode 100644
index 000000000..33610057c
--- /dev/null
+++ b/gs/src/gdevmrop.c
@@ -0,0 +1,1333 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmrop.c */
+/* RasterOp / transparency / render algorithm implementation for */
+/* memory devices */
+#include "memory_.h"
+#include "gx.h"
+#include "gsbittab.h"
+#include "gserrors.h"
+#include "gsropt.h"
+#include "gxcindex.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxdevrop.h"
+#include "gdevmrop.h"
+
+/* Define whether we implement transparency correctly, or whether we */
+/* implement it as documented in the H-P manuals. */
+#define TRANSPARENCY_PER_H_P
+
+/**************** NOTE: ****************
+ * The 16- and 32-bit cases aren't implemented.
+ ***************** ****************/
+
+/* Forward references */
+private gs_rop3_t gs_transparent_rop(P1(gs_logical_operation_t lop));
+
+#define chunk byte
+
+/* Calculate the X offset for a given Y value, */
+/* taking shift into account if necessary. */
+#define x_offset(px, ty, textures)\
+ ((textures)->shift == 0 ? (px) :\
+ (px) + (ty) / (textures)->rep_height * (textures)->rep_shift)
+
+/* ---------------- Initialization ---------------- */
+
+void
+gs_roplib_init(gs_memory_t *mem)
+{ /* Replace the default and forwarding copy_rop procedures. */
+ gx_default_copy_rop_proc = gx_real_default_copy_rop;
+ gx_forward_copy_rop_proc = gx_forward_copy_rop;
+ gx_default_strip_copy_rop_proc = gx_real_default_strip_copy_rop;
+ gx_forward_strip_copy_rop_proc = gx_forward_strip_copy_rop;
+}
+
+/* ---------------- Debugging aids ---------------- */
+
+#ifdef DEBUG
+
+private void
+trace_copy_rop(const char *cname, gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ dprintf4("%s: dev=0x%lx(%s) depth=%d\n",
+ cname, (ulong)dev, dev->dname, dev->color_info.depth);
+ dprintf4(" source data=0x%lx x=%d raster=%u id=%lu colors=",
+ (ulong)sdata, sourcex, sraster, (ulong)id);
+ if ( scolors )
+ dprintf2("(%lu,%lu);\n", scolors[0], scolors[1]);
+ else
+ dputs("none;\n");
+ if ( textures )
+ dprintf8(" textures=0x%lx size=%dx%d(%dx%d) raster=%u shift=%d(%d)",
+ (ulong)textures, textures->size.x, textures->size.y,
+ textures->rep_width, textures->rep_height,
+ textures->raster, textures->shift, textures->rep_shift);
+ else
+ dputs(" textures=none");
+ if ( tcolors )
+ dprintf2(" colors=(%lu,%lu)\n", tcolors[0], tcolors[1]);
+ else
+ dputs(" colors=none\n");
+ dprintf7(" rect=(%d,%d),(%d,%d) phase=(%d,%d) op=0x%x\n",
+ x, y, x + width, y + height, phase_x, phase_y,
+ (uint)lop);
+ if ( gs_debug_c('B') ) {
+ if ( sdata )
+ debug_dump_bitmap(sdata, sraster, height, "source bits");
+ if ( textures && textures->data )
+ debug_dump_bitmap(textures->data, textures->raster,
+ textures->size.y, "textures bits");
+ }
+}
+
+#endif
+
+/* ---------------- Monobit RasterOp ---------------- */
+
+int
+mem_mono_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gx_device_memory *mdev = (gx_device_memory *)dev;
+ gs_rop3_t rop = gs_transparent_rop(lop); /* handle transparency */
+ gx_strip_bitmap no_texture;
+ bool invert;
+ uint draster = mdev->raster;
+ uint traster;
+ int line_count;
+ byte *drow;
+ const byte *srow;
+ int ty;
+
+ /* If map_rgb_color isn't the default one for monobit memory */
+ /* devices, palette might not be set; set it now if needed. */
+ if ( mdev->palette.data == 0 )
+ gdev_mem_mono_set_inverted(mdev,
+ (*dev_proc(dev, map_rgb_color))
+ (dev, (gx_color_value)0,
+ (gx_color_value)0, (gx_color_value)0)
+ != 0);
+ invert = mdev->palette.data[0] != 0;
+
+#ifdef DEBUG
+ if ( gs_debug_c('b') )
+ trace_copy_rop("mem_mono_strip_copy_rop",
+ dev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+ if ( gs_debug_c('B') )
+ debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
+ height, "initial dest bits");
+#endif
+
+ /*
+ * RasterOp is defined as operating in RGB space; in the monobit
+ * case, this means black = 0, white = 1. However, most monobit
+ * devices use the opposite convention. To make this work,
+ * we must precondition the Boolean operation by swapping the
+ * order of bits end-for-end and then inverting.
+ */
+
+ if ( invert )
+ rop = byte_reverse_bits[rop] ^ 0xff;
+
+ /*
+ * From this point on, rop works in terms of device pixel values,
+ * not RGB-space values.
+ */
+
+ /* Modify the raster operation according to the source palette. */
+ if ( scolors != 0 )
+ { /* Source with palette. */
+ switch ( (int)((scolors[1] << 1) + scolors[0]) )
+ {
+ case 0: rop = rop3_know_S_0(rop); break;
+ case 1: rop = rop3_invert_S(rop); break;
+ case 2: break;
+ case 3: rop = rop3_know_S_1(rop); break;
+ }
+ }
+
+ /* Modify the raster operation according to the texture palette. */
+ if ( tcolors != 0 )
+ { /* Texture with palette. */
+ switch ( (int)((tcolors[1] << 1) + tcolors[0]) )
+ {
+ case 0: rop = rop3_know_T_0(rop); break;
+ case 1: rop = rop3_invert_T(rop); break;
+ case 2: break;
+ case 3: rop = rop3_know_T_1(rop); break;
+ }
+ }
+
+ /* Handle constant source and/or texture, and other special cases. */
+ { gx_color_index color0, color1;
+
+ switch ( rop_usage_table[rop] )
+ {
+ case rop_usage_none:
+ /* We're just filling with a constant. */
+ return (*dev_proc(dev, fill_rectangle))
+ (dev, x, y, width, height, (gx_color_index)(rop & 1));
+ case rop_usage_D:
+ /* This is either D (no-op) or ~D. */
+ if ( rop == rop3_D )
+ return 0;
+ /* Code no_S inline, then finish with no_T. */
+ fit_fill(dev, x, y, width, height);
+ sdata = mdev->base;
+ sourcex = x;
+ sraster = 0;
+ goto no_T;
+ case rop_usage_S:
+ /* This is either S or ~S, which copy_mono can handle. */
+ if ( rop == rop3_S )
+ color0 = 0, color1 = 1;
+ else
+ color0 = 1, color1 = 0;
+do_copy: return (*dev_proc(dev, copy_mono))
+ (dev, sdata, sourcex, sraster, id, x, y, width, height,
+ color0, color1);
+ case rop_usage_DS:
+ /* This might be a case that copy_mono can handle. */
+#define copy_case(c0, c1) color0 = c0, color1 = c1; goto do_copy;
+ switch ( (uint)rop ) /* cast shuts up picky compilers */
+ {
+ case rop3_D & rop3_not(rop3_S): copy_case(gx_no_color_index, 0);
+ case rop3_D | rop3_S: copy_case(gx_no_color_index, 1);
+ case rop3_D & rop3_S: copy_case(0, gx_no_color_index);
+ case rop3_D | rop3_not(rop3_S): copy_case(1, gx_no_color_index);
+ default: ;
+ }
+#undef copy_case
+ fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
+no_T: /* Texture is not used; textures may be garbage. */
+ no_texture.data = mdev->base; /* arbitrary */
+ no_texture.raster = 0;
+ no_texture.size.x = width;
+ no_texture.size.y = height;
+ no_texture.rep_width = no_texture.rep_height = 1;
+ no_texture.rep_shift = no_texture.shift = 0;
+ textures = &no_texture;
+ break;
+ case rop_usage_T:
+ /* This is either T or ~T, which tile_rectangle can handle. */
+ if ( rop == rop3_T )
+ color0 = 0, color1 = 1;
+ else
+ color0 = 1, color1 = 0;
+do_tile: return (*dev_proc(dev, strip_tile_rectangle))
+ (dev, textures, x, y, width, height, color0, color1,
+ phase_x, phase_y);
+ case rop_usage_DT:
+ /* This might be a case that tile_rectangle can handle. */
+#define tile_case(c0, c1) color0 = c0, color1 = c1; goto do_tile;
+ switch ( (uint)rop ) /* cast shuts up picky compilers */
+ {
+ case rop3_D & rop3_not(rop3_T): tile_case(gx_no_color_index, 0);
+ case rop3_D | rop3_T: tile_case(gx_no_color_index, 1);
+ case rop3_D & rop3_T: tile_case(0, gx_no_color_index);
+ case rop3_D | rop3_not(rop3_T): tile_case(1, gx_no_color_index);
+ default: ;
+ }
+#undef tile_case
+ fit_fill(dev, x, y, width, height);
+ /* Source is not used; sdata et al may be garbage. */
+ sdata = mdev->base; /* arbitrary, as long as all */
+ /* accesses are valid */
+ sourcex = x; /* guarantee no source skew */
+ sraster = 0;
+ break;
+ default: /* rop_usage_[D]ST */
+ fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
+ }
+ }
+
+#ifdef DEBUG
+ if_debug1('b', "final rop=0x%x\n", rop);
+#endif
+
+ /* Set up transfer parameters. */
+ line_count = height;
+ srow = sdata;
+ drow = scan_line_base(mdev, y);
+ traster = textures->raster;
+ ty = y + phase_y;
+
+ /* Loop over scan lines. */
+ for ( ; line_count-- > 0; drow += draster, srow += sraster, ++ty )
+ { int sx = sourcex;
+ int dx = x;
+ int w = width;
+ const byte *trow =
+ textures->data + (ty % textures->rep_height) * traster;
+ int xoff = x_offset(phase_x, ty, textures);
+ int nw;
+
+ /* Loop over (horizontal) copies of the tile. */
+ for ( ; w > 0; sx += nw, dx += nw, w -= nw )
+ { int dbit = dx & 7;
+ int sbit = sx & 7;
+ int sskew = sbit - dbit;
+ int tx = (dx + xoff) % textures->rep_width;
+ int tbit = tx & 7;
+ int tskew = tbit - dbit;
+ int left = nw = min(w, textures->size.x - tx);
+ byte lmask = 0xff >> dbit;
+ byte rmask = 0xff << (~(dbit + nw - 1) & 7);
+ byte mask = lmask;
+ int nx = 8 - dbit;
+ byte *dptr = drow + (dx >> 3);
+ const byte *sptr = srow + (sx >> 3);
+ const byte *tptr = trow + (tx >> 3);
+
+ if ( sskew < 0 )
+ --sptr, sskew += 8;
+ if ( tskew < 0 )
+ --tptr, tskew += 8;
+ for ( ; left > 0;
+ left -= nx, mask = 0xff, nx = 8,
+ ++dptr, ++sptr, ++tptr
+ )
+ { byte dbyte = *dptr;
+#define fetch1(ptr, skew)\
+ (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr)
+ byte sbyte = fetch1(sptr, sskew);
+ byte tbyte = fetch1(tptr, tskew);
+#undef fetch1
+ byte result =
+ (*rop_proc_table[rop])(dbyte, sbyte, tbyte);
+ if ( left <= nx )
+ mask &= rmask;
+ *dptr = (mask == 0xff ? result :
+ (result & mask) | (dbyte & ~mask));
+ }
+ }
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('B') )
+ debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
+ height, "final dest bits");
+#endif
+ return 0;
+}
+
+/* ---------------- Fake RasterOp for 2- and 4-bit devices ---------------- */
+
+int
+mem_gray_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gx_color_index scolors2[2];
+ const gx_color_index *real_scolors = scolors;
+ gx_color_index tcolors2[2];
+ const gx_color_index *real_tcolors = tcolors;
+ gx_strip_bitmap texture2;
+ const gx_strip_bitmap *real_texture = textures;
+ long tdata;
+ int depth = dev->color_info.depth;
+ int log2_depth = depth >> 1; /* works for 2, 4 */
+ gx_color_index max_pixel = (1 << depth) - 1;
+ int code;
+
+#ifdef DEBUG
+ if ( gs_debug_c('b') )
+ trace_copy_rop("mem_gray_strip_copy_rop",
+ dev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+#endif
+ if ( gx_device_has_color(dev) ||
+ (lop & (lop_S_transparent | lop_T_transparent)) ||
+ (scolors && /* must be (0,0) or (max,max) */
+ ((scolors[0] | scolors[1]) != 0) &&
+ ((scolors[0] & scolors[1]) != max_pixel)) ||
+ (tcolors && (tcolors[0] != tcolors[1]))
+ ) {
+ /* We can't fake it: do it the slow, painful way. */
+ return gx_real_default_strip_copy_rop(dev,
+ sdata, sourcex, sraster, id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+ }
+ if ( scolors )
+ { /* Must be a solid color: see above. */
+ scolors2[0] = scolors2[1] = scolors[0] & 1;
+ real_scolors = scolors2;
+ }
+ if ( textures )
+ { texture2 = *textures;
+ texture2.size.x <<= log2_depth;
+ texture2.rep_width <<= log2_depth;
+ texture2.shift <<= log2_depth;
+ texture2.rep_shift <<= log2_depth;
+ real_texture = &texture2;
+ }
+ if ( tcolors )
+ { /* For polybit textures with colors other than */
+ /* all 0s or all 1s, fabricate the data. */
+ if ( tcolors[0] != 0 && tcolors[0] != max_pixel )
+ { real_tcolors = 0;
+ *(byte *)&tdata = (byte)tcolors[0] << (8 - depth);
+ texture2.data = (byte *)&tdata;
+ texture2.raster = align_bitmap_mod;
+ texture2.size.x = texture2.rep_width = depth;
+ texture2.size.y = texture2.rep_height = 1;
+ texture2.id = gx_no_bitmap_id;
+ texture2.shift = texture2.rep_shift = 0;
+ real_texture = &texture2;
+ }
+ else
+ { tcolors2[0] = tcolors2[1] = tcolors[0] & 1;
+ real_tcolors = tcolors2;
+ }
+ }
+ dev->width <<= log2_depth;
+ code = mem_mono_strip_copy_rop(dev, sdata,
+ (real_scolors == NULL ? sourcex << log2_depth : sourcex),
+ sraster, id, real_scolors, real_texture, real_tcolors,
+ x << log2_depth, y, width << log2_depth, height,
+ phase_x << log2_depth, phase_y, lop);
+ dev->width >>= log2_depth;
+ return code;
+}
+
+/* ---------------- RasterOp with 8-bit gray / 24-bit RGB ---------------- */
+
+int
+mem_gray8_rgb24_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gx_device_memory *mdev = (gx_device_memory *)dev;
+ gs_rop3_t rop = lop_rop(lop);
+ gx_color_index const_source = gx_no_color_index;
+ gx_color_index const_texture = gx_no_color_index;
+ uint draster = mdev->raster;
+ int line_count;
+ byte *drow;
+ int depth = dev->color_info.depth;
+ int bpp = depth >> 3; /* bytes per pixel, 1 or 3 */
+ gx_color_index all_ones = ((gx_color_index)1 << depth) - 1;
+ gx_color_index strans =
+ (lop & lop_S_transparent ? all_ones : gx_no_color_index);
+ gx_color_index ttrans =
+ (lop & lop_T_transparent ? all_ones : gx_no_color_index);
+
+ /* Check for constant source. */
+ if ( scolors != 0 && scolors[0] == scolors[1] )
+ { /* Constant source */
+ const_source = scolors[0];
+ if ( const_source == 0 )
+ rop = rop3_know_S_0(rop);
+ else if ( const_source == all_ones )
+ rop = rop3_know_S_1(rop);
+ }
+ else if ( !rop3_uses_S(rop) )
+ const_source = 0; /* arbitrary */
+
+ /* Check for constant texture. */
+ if ( tcolors != 0 && tcolors[0] == tcolors[1] )
+ { /* Constant texture */
+ const_texture = tcolors[0];
+ if ( const_texture == 0 )
+ rop = rop3_know_T_0(rop);
+ else if ( const_texture == all_ones )
+ rop = rop3_know_T_1(rop);
+ }
+ else if ( !rop3_uses_T(rop) )
+ const_texture = 0; /* arbitrary */
+
+ /*
+ * If this is an 8-bit device but not gray-scale, we have to use
+ * the slow algorithm that converts values to and from RGB.
+ */
+ if ( bpp == 1 && gx_device_has_color(dev) && rop != rop3_D &&
+ (rop | (lop & lop_S_transparent)) != rop3_S &&
+ (rop | (lop & lop_T_transparent)) != rop3_T &&
+ rop != rop3_0 && rop != rop3_1
+ )
+ return gx_real_default_strip_copy_rop(dev,
+ sdata, sourcex, sraster, id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+ /* Adjust coordinates to be in bounds. */
+ if ( const_source == gx_no_color_index )
+ { fit_copy(dev, sdata, sourcex, sraster, id,
+ x, y, width, height);
+ }
+ else
+ { fit_fill(dev, x, y, width, height);
+ }
+
+ /* Set up transfer parameters. */
+ line_count = height;
+ drow = scan_line_base(mdev, y) + x * bpp;
+
+ /*
+ * There are 18 cases depending on whether each of the source and
+ * texture is constant, 1-bit, or multi-bit, and on whether the
+ * depth is 8 or 24 bits. We divide first according to constant
+ * vs. non-constant, and then according to 1- vs. multi-bit, and
+ * finally according to pixel depth. This minimizes source code,
+ * but not necessarily time, since we do some of the divisions
+ * within 1 or 2 levels of loop.
+ */
+
+#define dbit(base, i) ((base)[(i) >> 3] & (0x80 >> ((i) & 7)))
+/* 8-bit */
+#define cbit8(base, i, colors)\
+ (dbit(base, i) ? (byte)colors[1] : (byte)colors[0])
+#define rop_body_8()\
+ if ( s_pixel == strans || /* So = 0, s_tr = 1 */\
+ t_pixel == ttrans /* Po = 0, p_tr = 1 */\
+ )\
+ continue;\
+ *dptr = (*rop_proc_table[rop])(*dptr, s_pixel, t_pixel)
+/* 24-bit */
+#define get24(ptr)\
+ (((gx_color_index)(ptr)[0] << 16) | ((gx_color_index)(ptr)[1] << 8) | (ptr)[2])
+#define put24(ptr, pixel)\
+ (ptr)[0] = (byte)((pixel) >> 16),\
+ (ptr)[1] = (byte)((uint)(pixel) >> 8),\
+ (ptr)[2] = (byte)(pixel)
+#define cbit24(base, i, colors)\
+ (dbit(base, i) ? colors[1] : colors[0])
+#define rop_body_24()\
+ if ( s_pixel == strans || /* So = 0, s_tr = 1 */\
+ t_pixel == ttrans /* Po = 0, p_tr = 1 */\
+ )\
+ continue;\
+ { gx_color_index d_pixel = get24(dptr);\
+ d_pixel = (*rop_proc_table[rop])(d_pixel, s_pixel, t_pixel);\
+ put24(dptr, d_pixel);\
+ }
+
+ if ( const_texture != gx_no_color_index ) /**** Constant texture ****/
+ {
+ if ( const_source != gx_no_color_index ) /**** Constant source & texture ****/
+ {
+ for ( ; line_count-- > 0; drow += draster )
+ { byte *dptr = drow;
+ int left = width;
+ if ( bpp == 1 ) /**** 8-bit destination ****/
+#define s_pixel (byte)const_source
+#define t_pixel (byte)const_texture
+ for ( ; left > 0; ++dptr, --left )
+ { rop_body_8();
+ }
+#undef s_pixel
+#undef t_pixel
+ else /**** 24-bit destination ****/
+#define s_pixel const_source
+#define t_pixel const_texture
+ for ( ; left > 0; dptr += 3, --left )
+ { rop_body_24();
+ }
+#undef s_pixel
+#undef t_pixel
+ }
+ }
+ else /**** Data source, const texture ****/
+ { const byte *srow = sdata;
+ for ( ; line_count-- > 0; drow += draster, srow += sraster )
+ { byte *dptr = drow;
+ int left = width;
+ if ( scolors ) /**** 1-bit source ****/
+ { int sx = sourcex;
+ if ( bpp == 1 ) /**** 8-bit destination ****/
+#define t_pixel (byte)const_texture
+ for ( ; left > 0; ++dptr, ++sx, --left )
+ { byte s_pixel = cbit8(srow, sx, scolors);
+ rop_body_8();
+ }
+#undef t_pixel
+ else /**** 24-bit destination ****/
+#define t_pixel const_texture
+ for ( ; left > 0; dptr += 3, ++sx, --left )
+ { bits32 s_pixel = cbit24(srow, sx, scolors);
+ rop_body_24();
+ }
+#undef t_pixel
+ }
+ else if ( bpp == 1) /**** 8-bit source & dest ****/
+ { const byte *sptr = srow + sourcex;
+#define t_pixel (byte)const_texture
+ for ( ; left > 0; ++dptr, ++sptr, --left )
+ { byte s_pixel = *sptr;
+ rop_body_8();
+ }
+#undef t_pixel
+ }
+ else /**** 24-bit source & dest ****/
+ { const byte *sptr = srow + sourcex * 3;
+#define t_pixel const_texture
+ for ( ; left > 0; dptr += 3, sptr += 3, --left )
+ { bits32 s_pixel = get24(sptr);
+ rop_body_24();
+ }
+#undef t_pixel
+ }
+ }
+ }
+ }
+ else if ( const_source != gx_no_color_index ) /**** Const source, data texture ****/
+ { uint traster = textures->raster;
+ int ty = y + phase_y;
+
+ for ( ; line_count-- > 0; drow += draster, ++ty )
+ { /* Loop over copies of the tile. */
+ int dx = x, w = width, nw;
+ byte *dptr = drow;
+ const byte *trow =
+ textures->data + (ty % textures->size.y) * traster;
+ int xoff = x_offset(phase_x, ty, textures);
+
+ for ( ; w > 0; dx += nw, w -= nw )
+ { int tx = (dx + xoff) % textures->rep_width;
+ int left = nw = min(w, textures->size.x - tx);
+ const byte *tptr = trow;
+
+ if ( tcolors ) /**** 1-bit texture ****/
+ { if ( bpp == 1 ) /**** 8-bit dest ****/
+#define s_pixel (byte)const_source
+ for ( ; left > 0; ++dptr, ++tx, --left )
+ { byte t_pixel = cbit8(tptr, tx, tcolors);
+ rop_body_8();
+ }
+#undef s_pixel
+ else /**** 24-bit dest ****/
+#define s_pixel const_source
+ for ( ; left > 0; dptr += 3, ++tx, --left )
+ { bits32 t_pixel = cbit24(tptr, tx, tcolors);
+ rop_body_24();
+ }
+#undef s_pixel
+ }
+ else if ( bpp == 1 ) /**** 8-bit T & D ****/
+ { tptr += tx;
+#define s_pixel (byte)const_source
+ for ( ; left > 0; ++dptr, ++tptr, --left )
+ { byte t_pixel = *tptr;
+ rop_body_8();
+ }
+#undef s_pixel
+ }
+ else /**** 24-bit T & D ****/
+ { tptr += tx * 3;
+#define s_pixel const_source
+ for ( ; left > 0; dptr += 3, tptr += 3, --left )
+ { bits32 t_pixel = get24(tptr);
+ rop_body_24();
+ }
+#undef s_pixel
+ }
+ }
+ }
+ }
+ else /**** Data source & texture ****/
+ {
+ uint traster = textures->raster;
+ int ty = y + phase_y;
+ const byte *srow = sdata;
+
+ /* Loop over scan lines. */
+ for ( ; line_count-- > 0; drow += draster, srow += sraster, ++ty )
+ { /* Loop over copies of the tile. */
+ int sx = sourcex;
+ int dx = x;
+ int w = width;
+ int nw;
+ byte *dptr = drow;
+ const byte *trow =
+ textures->data + (ty % textures->size.y) * traster;
+ int xoff = x_offset(phase_x, ty, textures);
+
+ for ( ; w > 0; dx += nw, w -= nw )
+ { /* Loop over individual pixels. */
+ int tx = (dx + xoff) % textures->rep_width;
+ int left = nw = min(w, textures->size.x - tx);
+ const byte *tptr = trow;
+
+ /*
+ * For maximum speed, we should split this loop
+ * into 7 cases depending on source & texture
+ * depth: (1,1), (1,8), (1,24), (8,1), (8,8),
+ * (24,1), (24,24). But since we expect these
+ * cases to be relatively uncommon, we just
+ * divide on the destination depth.
+ */
+ if ( bpp == 1 ) /**** 8-bit destination ****/
+ { const byte *sptr = srow + sx;
+ tptr += tx;
+ for ( ; left > 0; ++dptr, ++sptr, ++tptr, ++sx, ++tx, --left )
+ { byte s_pixel =
+ (scolors ? cbit8(srow, sx, scolors) : *sptr);
+ byte t_pixel =
+ (tcolors ? cbit8(tptr, tx, tcolors) : *tptr);
+ rop_body_8();
+ }
+ }
+ else /**** 24-bit destination ****/
+ { const byte *sptr = srow + sx * 3;
+ tptr += tx * 3;
+ for ( ; left > 0; dptr += 3, sptr += 3, tptr += 3, ++sx, ++tx, --left )
+ { bits32 s_pixel =
+ (scolors ? cbit24(srow, sx, scolors) :
+ get24(sptr));
+ bits32 t_pixel =
+ (tcolors ? cbit24(tptr, tx, tcolors) :
+ get24(tptr));
+ rop_body_24();
+ }
+ }
+ }
+ }
+ }
+#undef rop_body_8
+#undef rop_body_24
+#undef dbit
+#undef cbit8
+#undef cbit24
+ return 0;
+}
+
+/* ---------------- Default copy_rop implementations ---------------- */
+
+/*
+ * We do the conversion between packed and standard formats explicitly here,
+ * because this code must be usable with 5.1x. If it weren't for that,
+ * we would simply use get_bits_rectangle, which already has the ability
+ * to convert between representations.
+ */
+
+private void
+unpack_to_standard(gx_device *dev, byte *dest, const byte *src, int sourcex,
+ int width, int depth, int src_depth)
+{ dev_proc_map_color_rgb((*map)) = dev_proc(dev, map_color_rgb);
+ byte *dp = dest;
+ int bit_x = sourcex * src_depth;
+ const byte *sp = src + (bit_x >> 3);
+ uint mask = (1 << src_depth) - 1;
+ int shift = (~bit_x & 7) + 1;
+ int x;
+
+ for ( x = width; --x >= 0; ) {
+ gx_color_index pixel;
+ gx_color_value rgb[3];
+
+ if ( (shift -= src_depth) < 0 )
+ shift += 8, ++sp;
+ pixel = (*sp >> shift) & mask;
+ (*map)(dev, pixel, rgb);
+ *dp++ = gx_color_value_to_byte(rgb[0]);
+ if ( depth > 8 ) {
+ *dp++ = gx_color_value_to_byte(rgb[1]);
+ *dp++ = gx_color_value_to_byte(rgb[2]);
+ }
+ }
+}
+
+private void
+unpack_colors_to_standard(gx_device *dev, gx_color_index real_colors[2],
+ const gx_color_index *colors, int depth)
+{ int i;
+
+ for ( i = 0; i < 2; ++i ) {
+ gx_color_value rgb[3];
+ gx_color_index pixel;
+
+ (*dev_proc(dev, map_color_rgb))(dev, colors[i], rgb);
+ pixel = gx_color_value_to_byte(rgb[0]);
+ if ( depth > 8 ) {
+ pixel = (pixel << 16) +
+ (gx_color_value_to_byte(rgb[1]) << 8) +
+ gx_color_value_to_byte(rgb[2]);
+ }
+ real_colors[i] = pixel;
+ }
+}
+
+private gx_color_index
+map_rgb_to_color_via_cmyk(gx_device *dev, gx_color_value r,
+ gx_color_value g, gx_color_value b)
+{ gx_color_value c = gx_max_color_value - r;
+ gx_color_value m = gx_max_color_value - g;
+ gx_color_value y = gx_max_color_value - b;
+ gx_color_value k = (c < m ? min(c, y) : min(m, y));
+
+ return (*dev_proc(dev, map_cmyk_color))(dev, c - k, m - k, y - k, k);
+}
+private void
+pack_from_standard(gx_device *dev, byte *dest, int destx, const byte *src,
+ int width, int depth, int src_depth)
+{ dev_proc_map_rgb_color((*map)) =
+ (dev->color_info.num_components == 4 ?
+ map_rgb_to_color_via_cmyk : dev_proc(dev, map_rgb_color));
+ int bit_x = destx * depth;
+ byte *dp = dest + (bit_x >> 3);
+ int shift = (~bit_x & 7) + 1;
+ byte buf = (shift == 8 ? 0 : *dp & (0xff00 >> shift));
+ const byte *sp = src;
+ int x;
+
+ for ( x = width; --x >= 0; ) {
+ byte vr, vg, vb;
+ gx_color_value r, g, b;
+ gx_color_index pixel;
+ byte chop = 0x1;
+
+ if ( (shift -= depth) < 0 )
+ shift += 8, *dp++ = buf, buf = 0;
+ vr = *sp++;
+ if ( src_depth > 8 ) {
+ vg = *sp++;
+ vb = *sp++;
+ } else
+ vb = vg = vr;
+ /*
+ * We have to map back to some pixel value, even if the color
+ * isn't accurate.
+ */
+ for ( ; ; ) {
+ r = gx_color_value_from_byte(vr);
+ g = gx_color_value_from_byte(vg);
+ b = gx_color_value_from_byte(vb);
+ pixel = (*map)(dev, r, g, b);
+ if ( pixel != gx_no_color_index )
+ break;
+ /* Reduce the color accuracy and try again. */
+ vr = (vr >= 0x80 ? vr | chop : vr & ~chop);
+ vg = (vg >= 0x80 ? vg | chop : vg & ~chop);
+ vb = (vb >= 0x80 ? vb | chop : vb & ~chop);
+ chop <<= 1;
+ }
+ buf += (byte)(pixel << shift);
+ }
+ if ( width > 0 )
+ *dp = (shift == 0 ? buf : buf + (*dp & ((1 << shift) - 1)));
+}
+
+int
+gx_real_default_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ /*
+ * The default implementation uses get_bits to read out the
+ * pixels, the memory device implementation to do the operation,
+ * and copy_color to write the pixels back. Note that if the
+ * device is already a memory device, we need to convert the
+ * pixels to standard representation (8-bit gray or 24-bit RGB),
+ * do the operation, and convert them back. This is very slow,
+ * but we don't see a better way.
+ */
+ bool expand = gs_device_is_memory(dev);
+ int depth = dev->color_info.depth;
+ int rop_depth = (!expand ? depth : gx_device_has_color(dev) ? 24 : 8);
+ gs_memory_t *mem = (dev->memory ? dev->memory : &gs_memory_default);
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(rop_depth);
+ gx_device_memory mdev;
+ uint draster = gx_device_raster(dev, true);
+ bool uses_d = rop3_uses_D(gs_transparent_rop(lop));
+ bool expand_s, expand_t;
+ byte *row = 0;
+ byte *dest_row = 0;
+ byte *source_row = 0;
+ byte *texture_row = 0;
+ gx_color_index source_colors[2];
+ const gx_color_index *real_scolors = scolors;
+ gx_color_index texture_colors[2];
+ const gx_color_index *real_tcolors = tcolors;
+ gx_strip_bitmap rop_texture;
+ const gx_strip_bitmap *real_texture = textures;
+ int code;
+ int py;
+
+#ifdef DEBUG
+ if ( gs_debug_c('b') )
+ trace_copy_rop("gx_default_strip_copy_rop",
+ dev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+#endif
+ if ( mdproto == 0 )
+ return_error(gs_error_rangecheck);
+ if ( sdata == 0 )
+ { fit_fill(dev, x, y, width, height);
+ }
+ else
+ { fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
+ }
+ gs_make_mem_device(&mdev, mdproto, 0, -1, dev);
+ mdev.width = width;
+ mdev.height = 1;
+ mdev.bitmap_memory = mem;
+ if ( expand ) {
+ if ( rop_depth == 8 ) {
+ /* Mark 8-bit standard device as gray-scale only. */
+ mdev.color_info.num_components = 1;
+ }
+ } else
+ mdev.color_info = dev->color_info;
+ code = (*dev_proc(&mdev, open_device))((gx_device *)&mdev);
+ if ( code < 0 )
+ return code;
+
+#define ALLOC_BUF(buf, size, cname)\
+ {\
+ buf = gs_alloc_bytes(mem, size, cname);\
+ if ( buf == 0 ) {\
+ code = gs_note_error(gs_error_VMerror);\
+ goto out;\
+ }\
+ }
+
+ ALLOC_BUF(row, draster, "copy_rop row");
+ if ( expand ) {
+ /* We may need intermediate buffers for all 3 operands. */
+ ALLOC_BUF(dest_row, bitmap_raster(dev->width * rop_depth),
+ "copy_rop dest_row");
+ expand_s = scolors == 0 && rop3_uses_S(gs_transparent_rop(lop));
+ if ( expand_s ) {
+ ALLOC_BUF(source_row, bitmap_raster(width * rop_depth),
+ "copy_rop source_row");
+ }
+ if ( scolors ) {
+ unpack_colors_to_standard(dev, source_colors, scolors, rop_depth);
+ real_scolors = source_colors;
+ }
+ expand_t = tcolors == 0 && rop3_uses_T(gs_transparent_rop(lop));
+ if ( expand_t ) {
+ ALLOC_BUF(texture_row,
+ bitmap_raster(textures->rep_width * rop_depth),
+ "copy_rop texture_row");
+ rop_texture = *textures;
+ real_texture = &rop_texture;
+ }
+ if ( tcolors ) {
+ unpack_colors_to_standard(dev, texture_colors, tcolors, rop_depth);
+ real_tcolors = texture_colors;
+ }
+ } else {
+ dest_row = row;
+ }
+
+#undef ALLOC_BUF
+
+ for ( py = y; py < y + height; ++py )
+ { byte *data;
+ int sx = sourcex;
+ const byte *source_data = sdata + (py - y) * sraster;
+
+ if ( uses_d )
+ { code = (*dev_proc(dev, get_bits))(dev, py, row, &data);
+ if ( code < 0 )
+ break;
+ if ( expand ) {
+ /* Convert the destination data to standard format. */
+ unpack_to_standard(dev, dest_row, data, 0, dev->width,
+ rop_depth, depth);
+ data = dest_row;
+ }
+ code = (*dev_proc(&mdev, copy_color))((gx_device *)&mdev,
+ data, x, draster, gx_no_bitmap_id,
+ 0, 0, width, 1);
+ if ( code < 0 )
+ return code;
+ }
+ if ( expand ) {
+ /* Convert the source and texture to standard format. */
+ if ( expand_s ) {
+ unpack_to_standard(dev, source_row, source_data, sx, width,
+ rop_depth, depth);
+ source_data = source_row;
+ sx = 0;
+ }
+ if ( expand_t ) {
+ int rep_y = (phase_y + y) % rop_texture.rep_height;
+
+ unpack_to_standard(dev, texture_row,
+ textures->data + rep_y * rop_texture.raster,
+ 0, textures->rep_width, rop_depth, depth);
+ rop_texture.data = texture_row;
+ }
+ }
+ code = (*dev_proc(&mdev, strip_copy_rop))((gx_device *)&mdev,
+ source_data, sx, sraster /*ad lib*/, gx_no_bitmap_id,
+ real_scolors, real_texture, real_tcolors,
+ 0, 0, width, 1, phase_x + x, phase_y + y,
+ lop);
+ if ( code < 0 )
+ break;
+ code = (*dev_proc(&mdev, get_bits))((gx_device *)&mdev,
+ 0, dest_row, &data);
+ if ( code < 0 )
+ break;
+ if ( expand ) {
+ /* Convert the result back to the device's format. */
+ pack_from_standard(dev, row, 0, data, width, depth, rop_depth);
+ data = row;
+ }
+ code = (*dev_proc(dev, copy_color))(dev,
+ data, 0, draster, gx_no_bitmap_id,
+ x, py, width, 1);
+ if ( code < 0 )
+ break;
+ }
+out:
+ if ( dest_row != row ) {
+ gs_free_object(mem, texture_row, "copy_rop texture_row");
+ gs_free_object(mem, source_row, "copy_rop source_row");
+ gs_free_object(mem, dest_row, "copy_rop dest_row");
+ }
+ gs_free_object(mem, row, "copy_rop row");
+ (*dev_proc(&mdev, close_device))((gx_device *)&mdev);
+ return code;
+}
+
+/* ------ Implementation of related functions ------ */
+
+int
+gx_real_default_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ const gx_strip_bitmap *textures;
+ gx_strip_bitmap tiles;
+
+ if ( texture == 0 )
+ textures = 0;
+ else
+ { *(gx_tile_bitmap *)&tiles = *texture;
+ tiles.rep_shift = tiles.shift = 0;
+ textures = &tiles;
+ }
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+}
+
+int
+gx_forward_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gx_device *tdev = ((gx_device_forward *)dev)->target;
+ dev_proc_copy_rop((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_copy_rop;
+ else
+ proc = dev_proc(tdev, copy_rop);
+ return (*proc)(tdev, sdata, sourcex, sraster, id, scolors,
+ texture, tcolors, x, y, width, height,
+ phase_x, phase_y, lop);
+}
+
+int
+gx_forward_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gx_device *tdev = ((gx_device_forward *)dev)->target;
+ dev_proc_strip_copy_rop((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_strip_copy_rop;
+ else
+ proc = dev_proc(tdev, strip_copy_rop);
+ return (*proc)(tdev, sdata, sourcex, sraster, id, scolors,
+ textures, tcolors, x, y, width, height,
+ phase_x, phase_y, lop);
+}
+
+int
+gx_copy_rop_unaligned(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ const gx_strip_bitmap *textures;
+ gx_strip_bitmap tiles;
+
+ if ( texture == 0 )
+ textures = 0;
+ else
+ { *(gx_tile_bitmap *)&tiles = *texture;
+ tiles.rep_shift = tiles.shift = 0;
+ textures = &tiles;
+ }
+ return gx_strip_copy_rop_unaligned
+ (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y, lop);
+}
+
+int
+gx_strip_copy_rop_unaligned(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ dev_proc_strip_copy_rop((*copy_rop)) = dev_proc(dev, strip_copy_rop);
+ int depth = (scolors == 0 ? dev->color_info.depth : 1);
+ int step = sraster & (align_bitmap_mod - 1);
+
+ /* Adjust the origin. */
+ if ( sdata != 0 )
+ { uint offset =
+ (uint)(sdata - (const byte *)0) & (align_bitmap_mod - 1);
+ /* See copy_color above re the following statement. */
+ if ( depth == 24 )
+ offset += (offset % 3) *
+ (align_bitmap_mod * (3 - (align_bitmap_mod % 3)));
+ sdata -= offset;
+ sourcex += (offset << 3) / depth;
+ }
+
+ /* Adjust the raster. */
+ if ( !step || sdata == 0 ||
+ (scolors != 0 && scolors[0] == scolors[1])
+ )
+ { /* No adjustment needed. */
+ return (*copy_rop)(dev, sdata, sourcex, sraster, id, scolors,
+ textures, tcolors, x, y, width, height,
+ phase_x, phase_y, lop);
+ }
+
+ /* Do the transfer one scan line at a time. */
+ { const byte *p = sdata;
+ int d = sourcex;
+ int dstep = (step << 3) / depth;
+ int code = 0;
+ int i;
+
+ for ( i = 0; i < height && code >= 0;
+ ++i, p += sraster - step, d += dstep
+ )
+ code = (*copy_rop)(dev, p, d, sraster, gx_no_bitmap_id, scolors,
+ textures, tcolors, x, y + i, width, 1,
+ phase_x, phase_y, lop);
+ return code;
+ }
+}
+
+/* ---------------- RasterOp texture device ---------------- */
+
+public_st_device_rop_texture();
+
+/* Device for clipping with a region. */
+private dev_proc_fill_rectangle(rop_texture_fill_rectangle);
+private dev_proc_copy_mono(rop_texture_copy_mono);
+private dev_proc_copy_color(rop_texture_copy_color);
+
+/* The device descriptor. */
+private const gx_device_rop_texture far_data gs_rop_texture_device =
+{ std_device_std_body(gx_device_rop_texture, 0, "rop source",
+ 0, 0, 1, 1),
+ { NULL, /* open_device */
+ gx_forward_get_initial_matrix,
+ NULL, /* default_sync_output */
+ NULL, /* output_page */
+ NULL, /* close_device */
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ rop_texture_fill_rectangle,
+ NULL, /* tile_rectangle */
+ rop_texture_copy_mono,
+ rop_texture_copy_color,
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ NULL, /* get_alpha_bits (no alpha) */
+ gx_no_copy_alpha, /* shouldn't be called */
+ gx_forward_get_band,
+ gx_no_copy_rop, /* shouldn't be called */
+ NULL, /* fill_path */
+ NULL, /* stroke_path */
+ NULL, /* fill_mask */
+ NULL, /* fill_trapezoid */
+ NULL, /* fill_parallelogram */
+ NULL, /* fill_triangle */
+ NULL, /* draw_thin_line */
+ NULL, /* begin_image */
+ NULL, /* image_data */
+ NULL, /* end_image */
+ NULL, /* strip_tile_rectangle */
+ NULL, /* strip_copy_rop */
+ gx_forward_get_clipping_box,
+ gx_forward_get_hardware_params
+ },
+ 0, /* target */
+ lop_default, /* log_op */
+ NULL /* texture */
+};
+#define rtdev ((gx_device_rop_texture *)dev)
+
+/* Initialize a RasterOp source device. */
+void
+gx_make_rop_texture_device(gx_device_rop_texture *dev, gx_device *target,
+ gs_logical_operation_t log_op, const gx_device_color *texture)
+{ *dev = gs_rop_texture_device;
+ /* Drawing operations are defaulted, non-drawing are forwarded. */
+ gx_device_fill_in_procs((gx_device *)dev);
+ dev->color_info = target->color_info;
+ dev->target = target;
+ dev->log_op = log_op;
+ dev->texture = texture;
+}
+
+/* Fill a rectangle */
+private int
+rop_texture_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_rop_source_t source;
+
+ source.sdata = NULL;
+ source.sourcex = 0;
+ source.sraster = 0;
+ source.id = gx_no_bitmap_id;
+ source.scolors[0] = source.scolors[1] = color;
+ source.use_scolors = true;
+ return gx_device_color_fill_rectangle(rtdev->texture,
+ x, y, w, h, rtdev->target,
+ rtdev->log_op, &source);
+}
+
+/* Copy a monochrome rectangle */
+private int
+rop_texture_copy_mono(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{ gx_rop_source_t source;
+ gs_logical_operation_t lop = rtdev->log_op;
+
+ source.sdata = data;
+ source.sourcex = sourcex;
+ source.sraster = raster;
+ source.id = id;
+ source.scolors[0] = color0;
+ source.scolors[1] = color1;
+ source.use_scolors = true;
+ /* Adjust the logical operation per transparent colors. */
+ if ( color0 == gx_no_color_index )
+ lop = rop3_use_D_when_S_0(lop);
+ else if ( color1 == gx_no_color_index )
+ lop = rop3_use_D_when_S_1(lop);
+ return gx_device_color_fill_rectangle(rtdev->texture,
+ x, y, w, h, rtdev->target,
+ lop, &source);
+}
+
+/* Copy a color rectangle */
+private int
+rop_texture_copy_color(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ gx_rop_source_t source;
+
+ source.sdata = data;
+ source.sourcex = sourcex;
+ source.sraster = raster;
+ source.id = id;
+ source.scolors[0] = source.scolors[1] = gx_no_color_index;
+ source.use_scolors = true;
+ return gx_device_color_fill_rectangle(rtdev->texture,
+ x, y, w, h, rtdev->target,
+ rtdev->log_op, &source);
+}
+
+/* ---------------- Internal routines ---------------- */
+
+/* Compute the effective RasterOp for the 1-bit case, */
+/* taking transparency into account. */
+private gs_rop3_t
+gs_transparent_rop(gs_logical_operation_t lop)
+{ gs_rop3_t rop = lop_rop(lop);
+ /*
+ * The algorithm for computing an effective RasterOp is presented,
+ * albeit obfuscated, in the H-P PCL5 technical documentation.
+ * Define So ("source opaque") and Po ("pattern opaque") as masks
+ * that have 1-bits precisely where the source or pattern
+ * respectively are not white (transparent).
+ * One applies the original RasterOp to compute an intermediate
+ * result R, and then computes the final result as
+ * (R & M) | (D & ~M) where M depends on transparencies as follows:
+ * s_tr p_tr M
+ * 0 0 1
+ * 0 1 ~So | Po (? Po ?)
+ * 1 0 So
+ * 1 1 So & Po
+ * The s_tr = 0, p_tr = 1 case seems wrong, but it's clearly
+ * specified that way in the "PCL 5 Color Technical Reference
+ * Manual."
+ *
+ * In the 1-bit case, So = ~S and Po = ~P, so we can apply the
+ * above table directly.
+ */
+#define So rop3_not(rop3_S)
+#define Po rop3_not(rop3_T)
+#ifdef TRANSPARENCY_PER_H_P
+# define MPo (rop3_uses_S(rop) ? rop3_not(So) | Po : Po)
+#else
+# define MPo Po
+#endif
+ /*
+ * If the operation doesn't use S or T, we must disregard the
+ * corresponding transparency flag.
+ */
+#define source_transparent ((lop & lop_S_transparent) && rop3_uses_S(rop))
+#define pattern_transparent ((lop & lop_T_transparent) && rop3_uses_T(rop))
+ gs_rop3_t mask =
+ (source_transparent ?
+ (pattern_transparent ? So & Po : So) :
+ (pattern_transparent ? MPo : rop3_1));
+#undef MPo
+ return (rop & mask) | (rop3_D & ~mask);
+}
diff --git a/gs/src/gdevmrop.h b/gs/src/gdevmrop.h
new file mode 100644
index 000000000..0a0bd0697
--- /dev/null
+++ b/gs/src/gdevmrop.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmrop.h */
+/* Interfaces to RasterOp implementation */
+/* Requires gxdevmem.h, gsropt.h */
+
+/* Define the table of RasterOp implementation procedures. */
+extern const far_data rop_proc rop_proc_table[256];
+
+/* Define the table of RasterOp operand usage. */
+extern const far_data byte /*rop_usage_t*/ rop_usage_table[256];
+
+/*
+ * PostScript colors normally act as the texture for RasterOp, with a null
+ * (all zeros) source. For images with CombineWithColor = true, we need
+ * a way to use the image data as the source. We implement this with a
+ * device that applies RasterOp with a specified texture to drawing
+ * operations, treating the drawing color as source rather than texture.
+ * The texture is a gx_device_color; it may be any type of PostScript color,
+ * even a Pattern.
+ */
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+
+#ifndef gx_device_rop_texture_DEFINED
+# define gx_device_rop_texture_DEFINED
+typedef struct gx_device_rop_texture_s gx_device_rop_texture;
+#endif
+
+struct gx_device_rop_texture_s {
+ gx_device_forward_common;
+ gs_logical_operation_t log_op;
+ const gx_device_color *texture;
+};
+extern_st(st_device_rop_texture);
+#define public_st_device_rop_texture()\
+ gs_public_st_suffix_add1(st_device_rop_texture, gx_device_rop_texture,\
+ "gx_device_rop_texture", device_rop_texture_enum_ptrs, device_rop_texture_reloc_ptrs,\
+ st_device_forward, texture)
+
+/* Initialize a RasterOp source device. */
+void gx_make_rop_texture_device(P4(gx_device_rop_texture *rsdev,
+ gx_device *target,
+ gs_logical_operation_t lop,
+ const gx_device_color *texture));
diff --git a/gs/src/gdevmswn.c b/gs/src/gdevmswn.c
new file mode 100644
index 000000000..7a21c96df
--- /dev/null
+++ b/gs/src/gdevmswn.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmswn.c */
+/*
+ * Microsoft Windows 3.n driver for Ghostscript.
+ * Original version by Russell Lang and Maurice Castro with help from
+ * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
+ * created from gdevbgi.c and gnuplot/term/win.trm 5th June 1992.
+ * Extensively modified by L. Peter Deutsch, Aladdin Enterprises.
+ */
+#include "gdevmswn.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gsparam.h"
+#include "gdevpccm.h"
+#include "gsdll.h"
+
+/* Forward references */
+private int win_set_bits_per_pixel(P2(gx_device_win *, int));
+
+#define TIMER_ID 1
+
+/* Open the win driver */
+int
+win_open(gx_device *dev)
+{ HDC hdc;
+ int code;
+
+ if (dev->width == INITIAL_WIDTH)
+ dev->width = (int)(8.5 * dev->x_pixels_per_inch);
+ if (dev->height == INITIAL_HEIGHT)
+ dev->height = (int)(11.0 * dev->y_pixels_per_inch);
+
+ if (wdev->BitsPerPixel == 0) {
+ int depth;
+ /* Set parameters that were unknown before opening device */
+ /* Find out if the device supports color */
+ /* We recognize 1, 4, 8, 24 bit/pixel devices */
+ hdc = GetDC(NULL); /* get hdc for desktop */
+ depth = GetDeviceCaps(hdc,PLANES) * GetDeviceCaps(hdc,BITSPIXEL);
+ if (depth > 8) {
+ wdev->BitsPerPixel = 24;
+ }
+ else if (depth >= 8) {
+ wdev->BitsPerPixel = 8;
+ }
+ else if (depth >= 4) {
+ wdev->BitsPerPixel = 4;
+ }
+ else {
+ wdev->BitsPerPixel = 1;
+ }
+ ReleaseDC(NULL,hdc);
+ wdev->mapped_color_flags = 0;
+ }
+
+ if ( (code = win_set_bits_per_pixel(wdev, wdev->BitsPerPixel)) < 0 )
+ return code;
+
+ if (wdev->nColors > 0) {
+ /* create palette for display */
+ if ((wdev->limgpalette = win_makepalette(wdev))
+ == (LPLOGPALETTE)NULL)
+ return win_nomemory();
+ wdev->himgpalette = CreatePalette(wdev->limgpalette);
+ }
+
+ return 0;
+}
+
+/* Make the output appear on the screen. */
+int
+win_sync_output(gx_device *dev)
+{
+ (*pgsdll_callback)(GSDLL_SYNC, (unsigned char *)wdev, 0);
+ return(0);
+}
+
+/* Make the window visible, and display the output. */
+int
+win_output_page(gx_device *dev, int copies, int flush)
+{
+ (*pgsdll_callback)(GSDLL_PAGE, (unsigned char *)wdev, 0);
+ return 0;
+}
+
+/* Close the win driver */
+int
+win_close(gx_device *dev)
+{
+ /* Free resources */
+ if (wdev->nColors > 0) {
+ gs_free(wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
+ DeleteObject(wdev->himgpalette);
+ gs_free((char *)(wdev->limgpalette), 1, sizeof(LOGPALETTE) +
+ (1<<(wdev->color_info.depth)) * sizeof(PALETTEENTRY),
+ "win_close");
+ }
+ return(0);
+}
+
+/* Map a r-g-b color to the colors available under Windows */
+gx_color_index
+win_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+ switch(wdev->BitsPerPixel) {
+ case 24:
+ return (((unsigned long)b >> (gx_color_value_bits - 8)) << 16) +
+ (((unsigned long)g >> (gx_color_value_bits - 8)) << 8) +
+ (((unsigned long)r >> (gx_color_value_bits - 8)));
+ case 8: {
+ int i;
+ LPLOGPALETTE lpal = wdev->limgpalette;
+ PALETTEENTRY *pep;
+ byte cr, cg, cb;
+ int mc_index;
+ byte mc_mask;
+
+ /* Check for a color in the palette of 64. */
+ { static const byte pal64[32] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1
+ };
+ if ( pal64[r >> (gx_color_value_bits - 5)] &&
+ pal64[g >> (gx_color_value_bits - 5)] &&
+ pal64[b >> (gx_color_value_bits - 5)]
+ )
+ return (gx_color_index)(
+ ((r >> (gx_color_value_bits - 2)) << 4) +
+ ((g >> (gx_color_value_bits - 2)) << 2) +
+ (b >> (gx_color_value_bits - 2))
+ );
+ }
+
+ /* map colors to 0->255 in 32 steps */
+ cr = win_color_value(r);
+ cg = win_color_value(g);
+ cb = win_color_value(b);
+
+ /* Search in palette, skipping the first 64. */
+ mc_index = ((cr >> 3) << 7) + ((cg >> 3) << 2) + (cb >> 6);
+ mc_mask = 0x80 >> ((cb >> 3) & 7);
+ if ( wdev->mapped_color_flags[mc_index] & mc_mask )
+ for ( i = wdev->nColors, pep = &lpal->palPalEntry[i];
+ --pep, --i >= 64;
+ )
+ { if ( cr == pep->peRed &&
+ cg == pep->peGreen &&
+ cb == pep->peBlue
+ )
+ return((gx_color_index)i); /* found it */
+ }
+
+ /* next try adding it to palette */
+ i = wdev->nColors;
+ if (i < 220) { /* allow 36 for windows and other apps */
+ LPLOGPALETTE lipal = wdev->limgpalette;
+ wdev->nColors = i+1;
+
+ DeleteObject(wdev->himgpalette);
+ lipal->palPalEntry[i].peFlags = 0;
+ lipal->palPalEntry[i].peRed = cr;
+ lipal->palPalEntry[i].peGreen = cg;
+ lipal->palPalEntry[i].peBlue = cb;
+ lipal->palNumEntries = wdev->nColors;
+ wdev->himgpalette = CreatePalette(lipal);
+
+ wdev->mapped_color_flags[mc_index] |= mc_mask;
+ return((gx_color_index)i); /* return new palette index */
+ }
+
+ return(gx_no_color_index); /* not found - dither instead */
+ }
+ case 4:
+ if ((r == g) && (g == b) && (r >= gx_max_color_value / 3 * 2 - 1)
+ && (r < gx_max_color_value / 4 * 3))
+ return ((gx_color_index)8); /* light gray */
+ return pc_4bit_map_rgb_color(dev, r, g, b);
+ }
+ return (gx_default_map_rgb_color(dev,r,g,b));
+}
+
+/* Map a color code to r-g-b. */
+int
+win_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_color_value one;
+ switch(wdev->BitsPerPixel) {
+ case 24:
+ one = (gx_color_value) (gx_max_color_value / 255);
+ prgb[0] = ((color) & 255) * one;
+ prgb[1] = ((color>>8) & 255) * one;
+ prgb[2] = ((color>>16) & 255) * one;
+ break;
+ case 8:
+ if (!dev->is_open)
+ return -1;
+ one = (gx_color_value) (gx_max_color_value / 255);
+ prgb[0] = wdev->limgpalette->palPalEntry[(int)color].peRed * one;
+ prgb[1] = wdev->limgpalette->palPalEntry[(int)color].peGreen * one;
+ prgb[2] = wdev->limgpalette->palPalEntry[(int)color].peBlue * one;
+ break;
+ case 4:
+ if (color == 8) /* VGA light gray */
+ prgb[0] = prgb[1] = prgb[2] = (gx_max_color_value / 4 * 3);
+ else
+ pc_4bit_map_color_rgb(dev, color, prgb);
+ break;
+ default:
+ prgb[0] = prgb[1] = prgb[2] =
+ (int)color ? gx_max_color_value : 0;
+ }
+ return 0;
+}
+
+/* Get Win parameters */
+int
+win_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_default_get_params(dev, plist);
+ return code;
+}
+
+/* Put parameters. */
+private int
+win_put_alpha_param(gs_param_list *plist, gs_param_name param_name, int *pa,
+ bool alpha_ok)
+{ int code = param_read_int(plist, param_name, pa);
+ switch ( code )
+ {
+ case 0:
+ switch ( *pa )
+ {
+ case 1:
+ return 0;
+ case 2: case 4:
+ if ( alpha_ok )
+ return 0;
+ default:
+ code = gs_error_rangecheck;
+ }
+ default:
+ param_signal_error(plist, param_name, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+
+/* Set window parameters -- size and resolution. */
+/* We implement this ourselves so that we can do it without */
+/* closing and opening the device. */
+int
+win_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0, code;
+ bool is_open = dev->is_open;
+ int width = dev->width;
+ int height = dev->height;
+ int old_bpp = dev->color_info.depth;
+ int bpp = old_bpp;
+ byte *old_flags = wdev->mapped_color_flags;
+ int atext = wdev->alpha_text, agraphics = wdev->alpha_graphics;
+ bool alpha_ok;
+
+ /* Handle extra parameters */
+
+ switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
+ {
+ case 0:
+ if ( dev->is_open && bpp != old_bpp )
+ ecode = gs_error_rangecheck;
+ else
+ { /* Don't release existing mapped_color_flags. */
+ if ( bpp != 8 )
+ wdev->mapped_color_flags = 0;
+ code = win_set_bits_per_pixel(wdev, bpp);
+ if ( code < 0 )
+ ecode = code;
+ else
+ break;
+ }
+ goto bppe;
+ default:
+ ecode = code;
+bppe: param_signal_error(plist, "BitsPerPixel", ecode);
+ case 1:
+ break;
+ }
+
+ alpha_ok = wdev->color_info.depth >= 8;
+ if ( (code = win_put_alpha_param(plist, "TextAlphaBits", &wdev->alpha_text, alpha_ok)) < 0 )
+ ecode = code;
+ if ( (code = win_put_alpha_param(plist, "GraphicsAlphaBits", &wdev->alpha_graphics, alpha_ok)) < 0 )
+ ecode = code;
+
+ if ( ecode >= 0 )
+ { /* Prevent gx_default_put_params from closing the device. */
+ dev->is_open = false;
+ ecode = gx_default_put_params(dev, plist);
+ dev->is_open = is_open;
+ }
+ if ( ecode < 0 )
+ { /* If we allocated mapped_color_flags, release it. */
+ if ( wdev->mapped_color_flags != 0 && old_flags == 0 )
+ gs_free(wdev->mapped_color_flags, 4096, 1,
+ "win_put_params");
+ wdev->mapped_color_flags = old_flags;
+ if ( bpp != old_bpp )
+ win_set_bits_per_pixel(wdev, old_bpp);
+ wdev->alpha_text = atext;
+ wdev->alpha_graphics = agraphics;
+ return ecode;
+ }
+ if ( wdev->mapped_color_flags == 0 && old_flags != 0 )
+ { /* Release old mapped_color_flags. */
+ gs_free(old_flags, 4096, 1, "win_put_params");
+ }
+
+ /* Hand off the change to the implementation. */
+ if ( is_open && (bpp != old_bpp ||
+ dev->width != width || dev->height != height)
+ )
+ { int ccode;
+ (*wdev->free_bitmap)(wdev);
+ ccode = (*wdev->alloc_bitmap)(wdev, (gx_device *)wdev);
+ if ( ccode < 0 )
+ { /* Bad news! Some of the other device parameters */
+ /* may have changed. We don't handle this. */
+ /* This is ****** WRONG ******. */
+ dev->width = width;
+ dev->height = height;
+ win_set_bits_per_pixel(wdev, old_bpp);
+ wdev->alpha_text = atext;
+ wdev->alpha_graphics = agraphics;
+ (*wdev->alloc_bitmap)(wdev, dev);
+ return ccode;
+ }
+ }
+
+ return 0;
+}
+
+/* Get the number of alpha bits. */
+int
+win_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return (type == go_text ? wdev->alpha_text : wdev->alpha_graphics);
+}
+
+/* ------ Internal routines ------ */
+
+#undef wdev
+
+
+
+/* out of memory error message box */
+int
+win_nomemory(void)
+{
+ MessageBox((HWND)NULL,(LPSTR)"Not enough memory",(LPSTR) szAppName, MB_ICONSTOP);
+ return gs_error_limitcheck;
+}
+
+
+LPLOGPALETTE
+win_makepalette(gx_device_win *wdev)
+{ int i, val;
+ LPLOGPALETTE logpalette;
+ logpalette = (LPLOGPALETTE)gs_malloc(1, sizeof(LOGPALETTE) +
+ (1<<(wdev->color_info.depth)) * sizeof(PALETTEENTRY),
+ "win_makepalette");
+ if (logpalette == (LPLOGPALETTE)NULL)
+ return(0);
+ logpalette->palVersion = 0x300;
+ logpalette->palNumEntries = wdev->nColors;
+ for (i=0; i<wdev->nColors; i++) {
+ logpalette->palPalEntry[i].peFlags = 0;
+ switch (wdev->nColors) {
+ case 64:
+ /* colors are rrggbb */
+ logpalette->palPalEntry[i].peRed = ((i & 0x30)>>4)*85;
+ logpalette->palPalEntry[i].peGreen = ((i & 0xC)>>2)*85;
+ logpalette->palPalEntry[i].peBlue = (i & 3)*85;
+ break;
+ case 16:
+ /* colors are irgb */
+ val = (i & 8 ? 255 : 128);
+ logpalette->palPalEntry[i].peRed = i & 4 ? val : 0;
+ logpalette->palPalEntry[i].peGreen = i & 2 ? val : 0;
+ logpalette->palPalEntry[i].peBlue = i & 1 ? val : 0;
+ if (i == 8) { /* light gray */
+ logpalette->palPalEntry[i].peRed =
+ logpalette->palPalEntry[i].peGreen =
+ logpalette->palPalEntry[i].peBlue = 192;
+ }
+ break;
+ case 2:
+ logpalette->palPalEntry[i].peRed =
+ logpalette->palPalEntry[i].peGreen =
+ logpalette->palPalEntry[i].peBlue = (i ? 255 : 0);
+ break;
+ }
+ }
+ return(logpalette);
+}
+
+
+private int
+win_set_bits_per_pixel(gx_device_win *wdev, int bpp)
+{
+static const gx_device_color_info win_24bit_color = dci_color(24,255,255);
+static const gx_device_color_info win_8bit_color = dci_color(8,31,4);
+static const gx_device_color_info win_ega_color = dci_pc_4bit;
+static const gx_device_color_info win_vga_color = dci_pc_4bit;
+static const gx_device_color_info win_mono_color = dci_black_and_white;
+ HDC hdc;
+ switch(bpp) {
+ case 24:
+ wdev->color_info = win_24bit_color;
+ wdev->nColors = -1;
+ break;
+ case 8:
+ /* use 64 static colors and 166 dynamic colors from 8 planes */
+ wdev->color_info = win_8bit_color;
+ wdev->nColors = 64;
+ break;
+ case 4:
+ hdc = GetDC(NULL);
+ if (GetDeviceCaps(hdc, VERTRES) <= 350)
+ wdev->color_info = win_ega_color;
+ else
+ wdev->color_info = win_vga_color;
+ ReleaseDC(NULL,hdc);
+ wdev->nColors = 16;
+ break;
+ case 1:
+ wdev->color_info = win_mono_color;
+ wdev->nColors = 2;
+ break;
+ default:
+ return (gs_error_rangecheck);
+ }
+ wdev->BitsPerPixel = bpp;
+
+ /* If necessary, allocate and clear the mapped color flags. */
+ if ( bpp == 8 )
+ { if ( wdev->mapped_color_flags == 0 )
+ { wdev->mapped_color_flags = gs_malloc(4096, 1, "win_set_bits_per_pixel");
+ if ( wdev->mapped_color_flags == 0 )
+ return_error(gs_error_VMerror);
+ }
+ memset(wdev->mapped_color_flags, 0, 4096);
+ }
+ else
+ { gs_free(wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
+ wdev->mapped_color_flags = 0;
+ }
+ return 0;
+}
+
diff --git a/gs/src/gdevmswn.h b/gs/src/gdevmswn.h
new file mode 100644
index 000000000..8d3af3c32
--- /dev/null
+++ b/gs/src/gdevmswn.h
@@ -0,0 +1,109 @@
+/* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmswn.h */
+/* Shared definitions for Microsoft Windows 3.n drivers */
+#include "string_.h"
+#include <stdlib.h>
+#include "dos_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "memory_.h"
+
+#include "windows_.h"
+#include <shellapi.h>
+#include "gp_mswin.h"
+
+typedef struct gx_device_win_s gx_device_win;
+
+/* Utility routines in gdevmswn.c */
+LPLOGPALETTE win_makepalette(P1(gx_device_win *));
+int win_nomemory(P0());
+void win_update(P1(gx_device_win *));
+
+/* Device procedures shared by all implementations. */
+/* Implementations may wrap their own code around _open and _close. */
+dev_proc_open_device(win_open);
+dev_proc_sync_output(win_sync_output);
+dev_proc_output_page(win_output_page);
+dev_proc_close_device(win_close);
+dev_proc_map_rgb_color(win_map_rgb_color);
+dev_proc_map_color_rgb(win_map_color_rgb);
+dev_proc_get_params(win_get_params);
+dev_proc_put_params(win_put_params);
+dev_proc_get_xfont_procs(win_get_xfont_procs);
+dev_proc_get_alpha_bits(win_get_alpha_bits);
+
+/* Common part of the device descriptor. */
+
+#define win_proc_copy_to_clipboard(proc)\
+ void proc(P1(gx_device_win *))
+
+#define win_proc_repaint(proc)\
+ void proc(P8(gx_device_win *, HDC, int, int, int, int, int, int))
+
+#define win_proc_alloc_bitmap(proc)\
+ int proc(P2(gx_device_win *, gx_device *))
+
+#define win_proc_free_bitmap(proc)\
+ void proc(P1(gx_device_win *))
+
+#define win_gsview_sizeof 80
+
+#define gx_device_win_common\
+ int BitsPerPixel;\
+ int nColors;\
+ int alpha_text;\
+ int alpha_graphics;\
+ byte *mapped_color_flags;\
+ /* Implementation-specific procedures */\
+ win_proc_alloc_bitmap((*alloc_bitmap));\
+ win_proc_free_bitmap((*free_bitmap));\
+ /* Handles */\
+ HPALETTE himgpalette;\
+ LPLOGPALETTE limgpalette
+
+/* The basic window device */
+struct gx_device_win_s {
+ gx_device_common;
+ gx_device_win_common;
+};
+
+/* Initial values for width and height */
+#define INITIAL_RESOLUTION 96.0
+#define INITIAL_WIDTH (INITIAL_RESOLUTION * 85 / 10 + 1)
+#define INITIAL_HEIGHT (INITIAL_RESOLUTION * 11 + 1)
+
+/* A macro for casting the device argument */
+#define wdev ((gx_device_win *)dev)
+
+/* RasterOp codes */
+#define rop_write_at_1s 0xE20746L /* BitBlt: write brush at 1's */
+#define rop_write_at_0s 0xB8074AL /* BitBlt: write brush at 0's */
+#define rop_write_0_at_1s 0x220326L /* BitBlt: ~S & D */
+#define rop_write_0_at_0s 0x8800C6L /* BitBlt: S & D */
+#define rop_write_1s 0xFF0062L /* write 1's */
+#define rop_write_0s 0x000042L /* write 0's */
+#define rop_write_pattern 0xF00021L /* PatBlt: write brush */
+
+/* Compress a gx_color_value into an 8-bit Windows color value, */
+/* using only the high order 5 bits. */
+#define win_color_value(z)\
+ ((((z) >> (gx_color_value_bits - 5)) << 3) +\
+ ((z) >> (gx_color_value_bits - 3)))
diff --git a/gs/src/gdevmsxf.c b/gs/src/gdevmsxf.c
new file mode 100644
index 000000000..cb34c6c39
--- /dev/null
+++ b/gs/src/gdevmsxf.c
@@ -0,0 +1,451 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevmsxf.c */
+/* External font (xfont) implementation for Microsoft Windows. */
+#include "ctype_.h"
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gdevmswn.h"
+#include "gsutil.h"
+#include "gxxfont.h"
+#include "gsstruct.h"
+
+/* Imported from gdevemap.c */
+extern const byte far_data gs_map_std_to_iso[256];
+
+/* Declare the xfont procedures */
+private xfont_proc_lookup_font(win_lookup_font);
+private xfont_proc_char_xglyph(win_char_xglyph);
+private xfont_proc_char_metrics(win_char_metrics);
+private xfont_proc_render_char(win_render_char);
+private xfont_proc_release(win_release);
+private gx_xfont_procs win_xfont_procs = {
+ win_lookup_font,
+ win_char_xglyph,
+ win_char_metrics,
+ win_render_char,
+ win_release
+};
+
+/* Return the xfont procedure record. */
+gx_xfont_procs *
+win_get_xfont_procs(gx_device *dev)
+{ return &win_xfont_procs;
+}
+
+/* Define a Windows xfont. */
+typedef struct win_xfont_s win_xfont;
+struct win_xfont_s {
+ gx_xfont_common common;
+ LOGFONT lf;
+ TEXTMETRIC tm;
+ HFONT hFont;
+ gx_device_win *dev; /* for GetDC */
+ int invert_y;
+ int y_offset;
+};
+gs_private_st_dev_ptrs1(st_win_xfont, win_xfont, "win_xfont",
+ win_xfont_enum_ptrs, win_xfont_reloc_ptrs, dev);
+#define wxf ((win_xfont *)xf)
+
+/* Forward references */
+private HDC near win_get_dc(P1(gx_device_win *));
+private void near win_release_dc(P2(gx_device_win *, HDC));
+private int win_select_font(P2(HDC, win_xfont *));
+
+/* Map from PostScript to Windows character codes. */
+/* (These tables were generated by winmaps.ps.) */
+
+private const byte far_data gs_map_symbol_to_oem[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 0, 35, 0, 37, 38, 0, 40, 41, 0, 43, 44, 0, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 0, 0, 0, 0, 0, 231, 225, 0, 0, 0, 0, 0, 0, 0, 0,
+ 226, 232, 0, 227, 0, 0, 0, 233, 0, 0, 0, 91, 0, 93, 0, 95,
+ 0, 223, 224, 0, 234, 0, 236, 0, 0, 0, 0, 0, 0, 229, 0, 0,
+ 0, 0, 0, 228, 230, 0, 0, 0, 0, 0, 0, 123, 124, 125, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 242, 0, 235, 0, 5, 4, 3, 6, 29, 27, 24, 26, 25,
+ 247, 240, 0, 241, 0, 0, 0, 7, 245, 0, 239, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 237, 0,
+ 0, 0, 0, 0, 0, 0, 250, 248, 169, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 243, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+private const byte far_data gs_map_iso_to_oem[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 172, 154, 155, 0, 156, 0, 21, 0, 0, 165, 173, 169, 45, 0, 0,
+ 247, 240, 252, 0, 0, 229, 20, 249, 0, 0, 166, 174, 171, 170, 0, 167,
+ 0, 0, 0, 0, 141, 142, 145, 128, 0, 143, 0, 0, 0, 0, 0, 0,
+ 0, 164, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 153, 0, 0, 0,
+ 133, 159, 131, 0, 132, 134, 144, 135, 138, 130, 136, 137, 140, 160, 0, 139,
+ 0, 163, 148, 161, 146, 0, 147, 245, 0, 150, 162, 149, 129, 0, 0, 151
+};
+
+/* Correlate PostScript font names with Windows font names. */
+/* This table should be an external resource, like Fontmap, */
+/* but that will have to wait till later. */
+
+typedef struct font_entry_s {
+ const char _ds *key;
+ const char _ds *value;
+ uint pitchAndFamily;
+} font_entry;
+
+private const font_entry font_names[] = {
+ {"Courier", "Courier New", FIXED_PITCH | FF_MODERN},
+ {"Helvetica", "Arial", VARIABLE_PITCH | FF_SWISS},
+ {"Helvetica", "Helv", VARIABLE_PITCH | FF_SWISS},
+ {"Times", "Times New Roman", VARIABLE_PITCH | FF_ROMAN},
+ {"Times", "Tms Rmn", VARIABLE_PITCH | FF_ROMAN}
+};
+
+/* Look up a font. */
+private int /*bool*/ map_logical_font(P2(HDC, win_xfont *));
+gx_xfont *
+win_lookup_font(gx_device *dev, const byte *fname, uint len,
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,
+ gs_memory_t *mem)
+{ win_xfont f;
+ win_xfont *wf;
+ uint name_len = min(len, LF_FACESIZE-1);
+ const font_entry _ds *pfe;
+ HDC hdc;
+ /* Only handle simple cases for now. */
+ if ( pmat->xy != 0 || pmat->yx != 0 || pmat->xx <= 0 ||
+ fabs(fabs(pmat->yy) - pmat->xx) > 0.00002
+ )
+ return NULL;
+ f.lf.lfHeight = pmat->xx * 1000;
+ /* Don't trust Windows with very small sizes. */
+ if ( f.lf.lfHeight < 6 || f.lf.lfHeight >= 36 )
+ return NULL;
+ f.lf.lfWidth = 0;
+ f.lf.lfEscapement = 0;
+ f.lf.lfOrientation = 0;
+ f.lf.lfWeight =
+ (string_match(fname, len, "*Bold*", 6, NULL) ?
+ FW_BOLD : FW_REGULAR);
+ f.lf.lfItalic =
+ string_match(fname, len, "*Italic*", 8, NULL) ||
+ string_match(fname, len, "*Oblique*", 9, NULL);
+ f.lf.lfUnderline = 0;
+ f.lf.lfStrikeOut = 0;
+ f.lf.lfCharSet =
+ (encoding_index == 2 ? SYMBOL_CHARSET : ANSI_CHARSET);
+ f.lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
+ f.lf.lfClipPrecision = CLIP_STROKE_PRECIS;
+ f.lf.lfQuality = PROOF_QUALITY;
+ f.hFont = 0;
+ f.invert_y = pmat->yy >= 0;
+ hdc = win_get_dc(wdev);
+ if ( hdc == NULL )
+ return NULL;
+ for ( pfe = font_names; pfe != &font_names[countof(font_names)]; pfe++ )
+ if ( !strncmp(pfe->key, fname, strlen(pfe->key)) )
+ { /* Found a match. */
+ strcpy(f.lf.lfFaceName, pfe->value);
+ f.lf.lfPitchAndFamily = pfe->pitchAndFamily;
+ if ( map_logical_font(hdc, &f) )
+ break;
+ }
+ if ( f.hFont == 0 )
+ { /* No matches in the table, try with the given name. */
+ uint len;
+ memcpy(f.lf.lfFaceName, fname, name_len); /* default */
+ for ( len = 0; len < name_len; len++ )
+ if ( !isalnum(fname[len]) )
+ break;
+ f.lf.lfFaceName[len] = 0;
+ f.lf.lfPitchAndFamily = 0; /* default */
+ if ( !map_logical_font(hdc, &f) )
+ { win_release_dc(wdev, hdc);
+ return NULL;
+ }
+ }
+ GetTextMetrics(hdc, &f.tm);
+ win_release_dc(wdev, hdc);
+ f.y_offset = (!f.invert_y ? f.tm.tmAscent : f.tm.tmDescent);
+ wf = gs_alloc_struct(mem, win_xfont, &st_win_xfont, "win_lookup_font");
+ if ( wf == 0 )
+ { DeleteObject(f.hFont);
+ return NULL;
+ }
+ f.common.procs = &win_xfont_procs;
+ f.dev = wdev;
+ *wf = f;
+ return (gx_xfont *)wf;
+}
+/* Map the logical font, and see if the result is satisfactory. */
+private int /*bool*/
+map_logical_font(HDC hdc, win_xfont *xf)
+{ char szFaceName[LF_FACESIZE];
+ xf->hFont = CreateFontIndirect(&xf->lf);
+ if ( xf->hFont == 0 )
+ return 0;
+ /* Check the face name */
+ SelectObject(hdc, xf->hFont);
+ GetTextFace(hdc, sizeof(szFaceName), szFaceName);
+ if ( !strncmp(xf->lf.lfFaceName, szFaceName, strlen(xf->lf.lfFaceName)) )
+ return 1;
+ DeleteObject(xf->hFont);
+ xf->hFont = 0;
+ return 0;
+}
+
+/* Convert a character name or index to an xglyph code. */
+gx_xglyph
+win_char_xglyph(gx_xfont *xf, gs_char chr, int encoding_index,
+ gs_glyph glyph, gs_proc_glyph_name_t glyph_name_proc)
+{ if ( chr == gs_no_char )
+ return gx_no_xglyph; /* can't look up names yet */
+ if ( encoding_index == 0 )
+ { /* Map StandardEncoding to ISOLatin1Encoding. */
+ /* We lose a couple of characters that exist in both */
+ /* StandardEncoding and the Windows OEM encoding but not in */
+ /* the ISOLatin1Encoding; we won't worry about this */
+ /* for now. */
+ chr = gs_map_std_to_iso[chr];
+ encoding_index = 1;
+ }
+ if ( wxf->hFont == NULL )
+ { /* TEXTMETRICS not filled in yet */
+ HDC hdc = win_get_dc(wxf->dev);
+ int code;
+ if ( hdc == NULL )
+ return gx_no_xglyph;
+ code = win_select_font(hdc, wxf);
+ win_release_dc(wxf->dev, hdc);
+ if ( code < 0 )
+ return gx_no_xglyph;
+ }
+ switch ( wxf->tm.tmCharSet )
+ {
+ case ANSI_CHARSET:
+ if ( encoding_index == 1 && (chr < 0x7f || chr > 0x9f ||
+ chr == 0x91 || chr == 0x92)
+ )
+ break;
+ return gx_no_xglyph;
+ case OEM_CHARSET:
+ switch ( encoding_index )
+ {
+ case 1: /* ISOLatin1 */
+ chr = gs_map_iso_to_oem[chr];
+ break;
+ case 2: /* Symbol */
+ chr = gs_map_symbol_to_oem[chr];
+ break;
+ default:
+ return gx_no_xglyph;
+ }
+ break;
+ default:
+ return gx_no_xglyph;
+ }
+ return (chr != 0 && chr >= wxf->tm.tmFirstChar &&
+ chr <= wxf->tm.tmLastChar ?
+ (gx_xglyph)chr : gx_no_xglyph);
+}
+
+/* Get the metrics for a character. */
+int
+win_char_metrics(gx_xfont *xf, gx_xglyph xg, int wmode,
+ gs_point *pwidth, gs_int_rect *pbbox)
+{ int code;
+ HDC hdc;
+ char chr = (char)xg;
+ if ( wmode != 0 )
+ return gs_error_undefined;
+ hdc = win_get_dc(wxf->dev);
+ if ( hdc == NULL )
+ return gs_error_limitcheck;
+ if ( (code = win_select_font(hdc, wxf)) < 0 )
+ { win_release_dc(wxf->dev, hdc);
+ return code;
+ }
+#ifdef __WIN32__
+ { SIZE sz;
+ GetTextExtentPoint(hdc, &chr, 1, &sz);
+ pwidth->x = sz.cx;
+ }
+#else
+ { DWORD extent;
+ extent = GetTextExtent(hdc, &chr, 1);
+ pwidth->x = LOWORD(extent);
+ }
+#endif
+ win_release_dc(wxf->dev, hdc);
+ pwidth->y = 0;
+ pbbox->p.x = 0;
+ pbbox->q.x = pwidth->x;
+ if ( wxf->invert_y )
+ { pbbox->p.y = -wxf->tm.tmDescent;
+ pbbox->q.y = wxf->tm.tmAscent;
+ }
+ else
+ { pbbox->p.y = -wxf->tm.tmAscent;
+ pbbox->q.y = wxf->tm.tmDescent;
+ }
+ return 0;
+}
+
+/* Render a character. */
+int
+win_render_char(gx_xfont *xf, gx_xglyph xg, gx_device *dev,
+ int xo, int yo, gx_color_index color, int required)
+{ char chr = (char)xg;
+ int code;
+#ifdef NOTUSED /* we don't own any windows so we can no longer do this */
+ if ( dev->dname == gs_mswin_device.dname &&
+ wdev->hdctext != NULL && !wxf->invert_y
+ )
+ { /* Display the character directly */
+ HDC hdc = wdev->hdctext;
+ PALETTEENTRY *pal = &wdev->limgpalette->palPalEntry[color];
+ if ( (code = win_select_font(hdc, wxf)) < 0 )
+ return code;
+ SetTextColor(hdc, RGB(pal->peRed, pal->peGreen, pal->peBlue));
+ SetBkMode(hdc, TRANSPARENT);
+ TextOut(hdc, xo, yo - wxf->y_offset, &chr, 1);
+ }
+ else
+#endif
+ if ( !required )
+ code = -1; /* too hard */
+ else
+ { /* Display on an intermediate bitmap, then copy the bits. */
+ gs_point wxy;
+ gs_int_rect bbox;
+ int w, h, wbm, raster;
+ gx_device_win *fdev = wxf->dev;
+ HBITMAP hbm;
+ byte *bits;
+ code = (*xf->common.procs->char_metrics)(xf, xg, 0,
+ &wxy, &bbox);
+ if ( code < 0 )
+ return code;
+ w = bbox.q.x - bbox.p.x;
+ h = bbox.q.y - bbox.p.y;
+ wbm = round_up(w, align_bitmap_mod * 8);
+ raster = wbm >> 3;
+ bits = gs_malloc(h, raster, "win_render_char");
+ if ( bits == 0 )
+ return gs_error_limitcheck;
+ hbm = CreateBitmap(wbm, h, 1, 1, NULL);
+ if ( hbm == NULL )
+ { code = gs_error_limitcheck;
+ }
+ else
+ { HDC hdcwin = win_get_dc(fdev);
+ HDC hdcbit = CreateCompatibleDC(hdcwin);
+ dev_proc_copy_mono((*copy_mono)) =
+ dev_proc(dev, copy_mono);
+ int y = yo - wxf->y_offset;
+ SetMapMode(hdcbit, GetMapMode(hdcwin));
+ win_select_font(hdcbit, wxf);
+ SelectObject(hdcbit, hbm);
+ PatBlt(hdcbit, 0, 0, wbm, h, rop_write_0s);
+ SetTextColor(hdcbit, 0xffffffL); /* 1 */
+ SetBkMode(hdcbit, TRANSPARENT);
+ TextOut(hdcbit, 0, 0, &chr, 1);
+ GetBitmapBits(hbm, (DWORD)raster * h, bits);
+ DeleteDC(hdcbit);
+ win_release_dc(fdev, hdcwin);
+ DeleteObject(hbm);
+ if ( !wxf->invert_y )
+ code = (*copy_mono)(dev, bits, 0,
+ raster, gx_no_bitmap_id,
+ xo, y, w, h,
+ gx_no_color_index, color);
+ else
+ { /* Copy scan lines in reverse order. */
+ int i;
+ y += h - 1;
+ for ( i = 0; i < h; i++ )
+ (*copy_mono)(dev, bits + i * raster,
+ 0, raster, gx_no_bitmap_id,
+ xo, y - i, w, 1,
+ gx_no_color_index, color);
+ }
+ }
+ gs_free(bits, h, raster, "win_render_char");
+ }
+ return (code < 0 ? code : 0);
+}
+
+/* Release an xfont. */
+private int
+win_release(gx_xfont *xf, gs_memory_t *mem)
+{ if ( wxf->hFont )
+ { DeleteObject(wxf->hFont);
+ wxf->hFont = 0;
+ }
+ if ( mem != NULL )
+ gs_free_object(mem, xf, "win_release");
+ return 0;
+}
+
+/* ------ Font utilities ------ */
+
+#undef wdev
+#undef wxf
+
+/* Get a DC for the font's device. */
+private HDC near
+win_get_dc(gx_device_win *wdev)
+{
+ /* Since we don't have a window, use the desktop */
+ /* Don't draw into it! */
+ return GetDC(HWND_DESKTOP);
+}
+
+/* Release a DC for the font's device. */
+private void near
+win_release_dc(gx_device_win *wdev, HDC hdc)
+{ ReleaseDC(HWND_DESKTOP, hdc);
+}
+
+/* Make an xfont current, possibly remapping it from a logical font. */
+private int
+win_select_font(HDC hdc, win_xfont *wxf)
+{ HFONT hFont = wxf->hFont;
+ if ( hFont == NULL )
+ { /* The font was released to free up resources. */
+ /* Re-acquire it now. */
+ wxf->hFont = CreateFontIndirect(&wxf->lf);
+ if ( wxf->hFont == NULL )
+ return gs_error_limitcheck;
+ }
+ SelectObject(hdc, wxf->hFont);
+ return 0;
+}
diff --git a/gs/src/gdevn533.c b/gs/src/gdevn533.c
new file mode 100644
index 000000000..152ec8f29
--- /dev/null
+++ b/gs/src/gdevn533.c
@@ -0,0 +1,209 @@
+/* Copyright (C) 1989, 1990, 1991, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevn533.c */
+/* Sony NWP-533 driver for GhostScript */
+#include "gdevprn.h"
+#include <sys/ioctl.h>
+#include <newsiop/lbp.h>
+
+/***
+ *** Note: this driver was contributed by a user, Tero Kivinen:
+ *** please contact kivinen@joker.cs.hut.fi if you have questions.
+ ***/
+
+#define A4_PAPER 1
+
+#ifdef A4_PAPER
+#define PAPER_XDOTS A4_XDOTS
+#define PAPER_YDOTS A4_YDOTS
+#else
+#define PAPER_XDOTS B4_XDOTS
+#define PAPER_YDOTS B4_YDOTS
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* The device descriptor */
+private dev_proc_open_device(nwp533_open);
+private dev_proc_print_page(nwp533_print_page);
+private dev_proc_close_device(nwp533_close);
+private gx_device_procs nwp533_procs =
+ prn_procs(nwp533_open, gdev_prn_output_page, nwp533_close);
+
+gx_device_printer far_data gs_nwp533_device =
+ prn_device(nwp533_procs, "nwp533",
+ PAPER_XDOTS * 10.0 / DPI, /* width_10ths */
+ PAPER_YDOTS * 10.0 / DPI, /* height_10ths */
+ DPI, /* x_dpi */
+ DPI, /* y_dpi */
+ 0,0,0,0, /* margins */
+ 1, nwp533_print_page);
+
+/* return True if should retry - False if should quit */
+private int
+analyze_error(int printer_file)
+{
+ struct lbp_stat status;
+ char *detail = NULL, *old_detail = NULL;
+ int waiting = TRUE;
+ int retry_after_return = TRUE;
+
+ if(ioctl(printer_file, LBIOCRESET, 0) < 0)
+ {
+ perror("ioctl(LBIOCRESET)");
+ return FALSE;
+ }
+ if (ioctl(printer_file, LBIOCSTATUS, &status) < 0)
+ {
+ perror("ioctl(LBIOCSTATUS)");
+ return FALSE;
+ }
+
+ do
+ {
+ /* Is there an error */
+ if(status.stat[0] & (ST0_CALL | ST0_REPRINT_REQ | ST0_WAIT | ST0_PAUSE))
+ {
+ if(status.stat[1] & ST1_NO_CARTRIGE)/* mispelled? */
+ detail = "No cartridge - waiting";
+ else if(status.stat[1] & ST1_NO_PAPER)
+ detail = "Out of paper - waiting";
+ else if(status.stat[1] & ST1_JAM)
+ detail = "Paper jam - waiting";
+ else if(status.stat[1] & ST1_OPEN)
+ detail = "Door open - waiting";
+ else if(status.stat[1] & ST1_TEST)
+ detail = "Test printing - waiting";
+ else {
+ waiting = FALSE;
+ retry_after_return = FALSE;
+
+ if(status.stat[2] & ST2_FIXER)
+ detail = "Fixer trouble - quiting";
+ else if(status.stat[2] & ST2_SCANNER)
+ detail = "Scanner trouble - quiting";
+ else if(status.stat[2] & ST2_MOTOR)
+ detail = "Scanner motor trouble - quiting";
+ else if(status.stat[5] & ST5_NO_TONER)
+ detail = "No toner - quiting";
+ }
+ }
+ else
+ {
+ waiting = FALSE;
+ }
+ if(detail != NULL && detail != old_detail)
+ {
+ perror(detail);
+ old_detail = detail;
+ }
+ if(waiting)
+ {
+ ioctl(1, LBIOCRESET, 0);
+ sleep(5);
+ ioctl(1, LBIOCSTATUS, &status);
+ }
+ }
+ while(waiting);
+ return retry_after_return;
+}
+
+private int
+nwp533_open(gx_device *dev)
+{
+ gx_device_printer *pdev = (gx_device_printer *) dev;
+
+ if (pdev->fname[0] == '\0')
+ {
+ strcpy(pdev->fname, "/dev/lbp");
+ }
+ return gdev_prn_open(dev);
+}
+
+private int
+nwp533_close(gx_device *dev)
+{
+ if (((gx_device_printer *) dev)->file != NULL)
+ {
+ int printer_file;
+
+ printer_file = fileno(((gx_device_printer *) dev)->file);
+ restart2:
+ if(ioctl(printer_file, LBIOCSTOP, 0) < 0)
+ {
+ if(analyze_error(printer_file))
+ goto restart2;
+ perror("Waiting for device");
+ return_error(gs_error_ioerror);
+ }
+ }
+ return gdev_prn_close(dev);
+}
+
+/* Send the page to the printer. */
+private int
+nwp533_print_page(gx_device_printer *dev, FILE *prn_stream)
+{
+ int lnum;
+ int line_size = gdev_mem_bytes_per_scan_line(dev);
+ byte *in;
+ int printer_file;
+ printer_file = fileno(prn_stream);
+
+ if (line_size % 4 != 0)
+ {
+ line_size += 4 - (line_size % 4);
+ }
+ in = (byte *) gs_malloc(line_size, 1, "nwp533_output_page(in)");
+ restart:
+ if(ioctl(printer_file, LBIOCSTOP, 0) < 0)
+ {
+ if(analyze_error(printer_file))
+ goto restart;
+ perror("Waiting for device");
+ return_error(gs_error_ioerror);
+ }
+ lseek(printer_file, 0, 0);
+
+ for ( lnum = 0; lnum < dev->height; lnum++)
+ {
+ gdev_prn_copy_scan_lines(prn_dev, lnum, in, line_size);
+ if(write(printer_file, in, line_size) != line_size)
+ {
+ perror("Writting to output");
+ return_error(gs_error_ioerror);
+ }
+ }
+ retry:
+ if(ioctl(printer_file, LBIOCSTART, 0) < 0)
+ {
+ if(analyze_error(printer_file))
+ goto retry;
+ perror("Starting print");
+ return_error(gs_error_ioerror);
+ }
+ gs_free(in, line_size, 1, "nwp533_output_page(in)");
+
+ return 0;
+}
diff --git a/gs/src/gdevnfwd.c b/gs/src/gdevnfwd.c
new file mode 100644
index 000000000..3cddeca64
--- /dev/null
+++ b/gs/src/gdevnfwd.c
@@ -0,0 +1,560 @@
+/* Copyright (C) 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevnfwd.c */
+/* Null and forwarding device implementation */
+#include "gx.h"
+#include "gxdevice.h"
+
+/* ---------------- Forwarding procedures ---------------- */
+
+#define fdev ((gx_device_forward *)dev)
+
+/* Fill in NULL procedures in a forwarding device procedure record. */
+/* We don't fill in: open_device, close_device, or the lowest-level */
+/* drawing operations. */
+void
+gx_device_forward_fill_in_procs(register gx_device_forward *dev)
+{ gx_device_set_procs((gx_device *)dev);
+ /* NOT open_device */
+ fill_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
+ fill_dev_proc(dev, sync_output, gx_forward_sync_output);
+ fill_dev_proc(dev, output_page, gx_forward_output_page);
+ /* NOT close_device */
+ fill_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
+ fill_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
+ /* NOT fill_rectangle */
+ /* NOT tile_rectangle */
+ /* NOT copy_mono */
+ /* NOT copy_color */
+ /* NOT draw_line (OBSOLETE) */
+ fill_dev_proc(dev, get_bits, gx_forward_get_bits);
+ fill_dev_proc(dev, get_params, gx_forward_get_params);
+ fill_dev_proc(dev, put_params, gx_forward_put_params);
+ fill_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
+ fill_dev_proc(dev, get_xfont_procs, gx_forward_get_xfont_procs);
+ fill_dev_proc(dev, get_xfont_device, gx_forward_get_xfont_device);
+ fill_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color);
+ fill_dev_proc(dev, get_page_device, gx_forward_get_page_device);
+ fill_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits);
+ /* NOT copy_alpha */
+ fill_dev_proc(dev, get_band, gx_forward_get_band);
+ fill_dev_proc(dev, copy_rop, gx_forward_copy_rop_proc);
+ fill_dev_proc(dev, fill_path, gx_forward_fill_path);
+ fill_dev_proc(dev, stroke_path, gx_forward_stroke_path);
+ fill_dev_proc(dev, fill_mask, gx_forward_fill_mask);
+ fill_dev_proc(dev, fill_trapezoid, gx_forward_fill_trapezoid);
+ fill_dev_proc(dev, fill_parallelogram, gx_forward_fill_parallelogram);
+ fill_dev_proc(dev, fill_triangle, gx_forward_fill_triangle);
+ fill_dev_proc(dev, draw_thin_line, gx_forward_draw_thin_line);
+ fill_dev_proc(dev, begin_image, gx_forward_begin_image);
+ fill_dev_proc(dev, image_data, gx_forward_image_data);
+ fill_dev_proc(dev, end_image, gx_forward_end_image);
+ /* NOT strip_tile_rectangle */
+ fill_dev_proc(dev, strip_copy_rop, gx_forward_strip_copy_rop_proc);
+ fill_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box);
+ fill_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
+ gx_device_fill_in_procs((gx_device *)dev);
+}
+
+/* Forward the color mapping procedures from a device to its target. */
+void
+gx_device_forward_color_procs(gx_device_forward *dev)
+{ set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
+ set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
+ set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
+ set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color);
+}
+
+void
+gx_forward_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+{ gx_device *tdev = fdev->target;
+ if ( tdev == 0 )
+ gx_default_get_initial_matrix(dev, pmat);
+ else
+ (*dev_proc(tdev, get_initial_matrix))(tdev, pmat);
+}
+
+int
+gx_forward_sync_output(gx_device *dev)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_sync_output(dev) :
+ (*dev_proc(tdev, sync_output))(tdev));
+}
+
+int
+gx_forward_output_page(gx_device *dev, int num_copies, int flush)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_output_page(dev, num_copies, flush) :
+ (*dev_proc(tdev, output_page))(tdev, num_copies, flush));
+}
+
+gx_color_index
+gx_forward_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_map_rgb_color(dev, r, g, b) :
+ (*dev_proc(tdev, map_rgb_color))(tdev, r, g, b));
+}
+
+int
+gx_forward_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_map_color_rgb(dev, color, prgb) :
+ (*dev_proc(tdev, map_color_rgb))(tdev, color, prgb));
+}
+
+int
+gx_forward_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{ gx_device *tdev = fdev->target;
+ dev_proc_tile_rectangle((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_tile_rectangle;
+ else
+ proc = dev_proc(tdev, tile_rectangle);
+ return (*proc)(tdev, tile, x, y, w, h, color0, color1, px, py);
+}
+
+int
+gx_forward_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_get_bits(dev, y, data, actual_data) :
+ (*dev_proc(tdev, get_bits))(tdev, y, data, actual_data));
+}
+
+int
+gx_forward_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_get_params(dev, plist) :
+ (*dev_proc(tdev, get_params))(tdev, plist));
+}
+
+int
+gx_forward_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_put_params(dev, plist) :
+ (*dev_proc(tdev, put_params))(tdev, plist));
+}
+
+gx_color_index
+gx_forward_map_cmyk_color(gx_device *dev, gx_color_value c, gx_color_value m,
+ gx_color_value y, gx_color_value k)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_map_cmyk_color(dev, c, m, y, k) :
+ (*dev_proc(tdev, map_cmyk_color))(tdev, c, m, y, k));
+}
+
+gx_xfont_procs *
+gx_forward_get_xfont_procs(gx_device *dev)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_get_xfont_procs(dev) :
+ (*dev_proc(tdev, get_xfont_procs))(tdev));
+}
+
+gx_device *
+gx_forward_get_xfont_device(gx_device *dev)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_get_xfont_device(dev) :
+ (*dev_proc(tdev, get_xfont_device))(tdev));
+}
+
+gx_color_index
+gx_forward_map_rgb_alpha_color(gx_device *dev, gx_color_value r,
+ gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ?
+ gx_default_map_rgb_alpha_color(dev, r, g, b, alpha) :
+ (*dev_proc(tdev, map_rgb_alpha_color))(tdev, r, g, b, alpha));
+}
+
+gx_device *
+gx_forward_get_page_device(gx_device *dev)
+{ gx_device *tdev = fdev->target;
+ gx_device *pdev;
+
+ if ( tdev == 0 )
+ return gx_default_get_page_device(dev);
+ pdev = (*dev_proc(tdev, get_page_device))(tdev);
+ return (pdev == tdev ? dev : pdev);
+}
+
+int
+gx_forward_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ?
+ gx_default_get_alpha_bits(dev, type) :
+ (*dev_proc(tdev, get_alpha_bits))(tdev, type));
+}
+
+int
+gx_forward_get_band(gx_device *dev, int y, int *band_start)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ?
+ gx_default_get_band(dev, y, band_start) :
+ (*dev_proc(tdev, get_band))(tdev, y, band_start));
+}
+
+int
+gx_forward_fill_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_fill_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ gx_device *tdev = fdev->target;
+ dev_proc_fill_path((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_fill_path;
+ else
+ proc = dev_proc(tdev, fill_path);
+ return (*proc)(tdev, pis, ppath, params, pdcolor, pcpath);
+}
+
+int
+gx_forward_stroke_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ gx_device *tdev = fdev->target;
+ dev_proc_stroke_path((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_stroke_path;
+ else
+ proc = dev_proc(tdev, stroke_path);
+ return (*proc)(tdev, pis, ppath, params, pdcolor, pcpath);
+}
+
+int
+gx_forward_fill_mask(gx_device *dev,
+ const byte *data, int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ gx_device *tdev = fdev->target;
+ dev_proc_fill_mask((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_fill_mask;
+ else
+ proc = dev_proc(tdev, fill_mask);
+ return (*proc)(tdev, data, dx, raster, id, x, y, w, h, pdcolor, depth,
+ lop, pcpath);
+}
+
+int
+gx_forward_fill_trapezoid(gx_device *dev,
+ const gs_fixed_edge *left, const gs_fixed_edge *right,
+ fixed ybot, fixed ytop, bool swap_axes,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ gx_device *tdev = fdev->target;
+ dev_proc_fill_trapezoid((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_fill_trapezoid;
+ else
+ proc = dev_proc(tdev, fill_trapezoid);
+ return (*proc)(tdev, left, right, ybot, ytop, swap_axes, pdcolor, lop);
+}
+
+int
+gx_forward_fill_parallelogram(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ gx_device *tdev = fdev->target;
+ dev_proc_fill_parallelogram((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_fill_parallelogram;
+ else
+ proc = dev_proc(tdev, fill_parallelogram);
+ return (*proc)(tdev, px, py, ax, ay, bx, by, pdcolor, lop);
+}
+
+int
+gx_forward_fill_triangle(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ gx_device *tdev = fdev->target;
+ dev_proc_fill_triangle((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_fill_triangle;
+ else
+ proc = dev_proc(tdev, fill_triangle);
+ return (*proc)(tdev, px, py, ax, ay, bx, by, pdcolor, lop);
+}
+
+int
+gx_forward_draw_thin_line(gx_device *dev,
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ gx_device *tdev = fdev->target;
+ dev_proc_draw_thin_line((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_draw_thin_line;
+ else
+ proc = dev_proc(tdev, draw_thin_line);
+ return (*proc)(tdev, fx0, fy0, fx1, fy1, pdcolor, lop);
+}
+
+int
+gx_forward_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *memory, void **pinfo)
+{ gx_device *tdev = fdev->target;
+ dev_proc_begin_image((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_begin_image;
+ else
+ proc = dev_proc(tdev, begin_image);
+ return (*proc)(tdev, pis, pim, format, prect, pdcolor, pcpath,
+ memory, pinfo);
+}
+
+int
+gx_forward_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ gx_device *tdev = fdev->target;
+ dev_proc_image_data((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_image_data;
+ else
+ proc = dev_proc(tdev, image_data);
+ return (*proc)(tdev, info, planes, data_x, raster, height);
+}
+
+int
+gx_forward_end_image(gx_device *dev,
+ void *info, bool draw_last)
+{ gx_device *tdev = fdev->target;
+ dev_proc_end_image((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_end_image;
+ else
+ proc = dev_proc(tdev, end_image);
+ return (*proc)(tdev, info, draw_last);
+}
+
+int
+gx_forward_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{ gx_device *tdev = fdev->target;
+ dev_proc_strip_tile_rectangle((*proc));
+
+ if ( tdev == 0 )
+ tdev = dev, proc = gx_default_strip_tile_rectangle;
+ else
+ proc = dev_proc(tdev, strip_tile_rectangle);
+ return (*proc)(tdev, tiles, x, y, w, h, color0, color1, px, py);
+}
+
+void
+gx_forward_get_clipping_box(gx_device *dev, gs_fixed_rect *pbox)
+{ gx_device *tdev = fdev->target;
+
+ if ( tdev == 0 )
+ gx_default_get_clipping_box(dev, pbox);
+ else
+ (*dev_proc(tdev, get_clipping_box))(tdev, pbox);
+}
+
+int
+gx_forward_get_hardware_params(gx_device *dev, gs_param_list *plist)
+{ gx_device *tdev = fdev->target;
+ return (tdev == 0 ? gx_default_get_hardware_params(dev, plist) :
+ (*dev_proc(tdev, get_hardware_params))(tdev, plist));
+}
+
+/* ---------------- The null device(s) ---------------- */
+
+private dev_proc_fill_rectangle(null_fill_rectangle);
+private dev_proc_copy_mono(null_copy_mono);
+private dev_proc_copy_color(null_copy_color);
+private dev_proc_put_params(null_put_params);
+private dev_proc_copy_alpha(null_copy_alpha);
+private dev_proc_copy_rop(null_copy_rop);
+private dev_proc_fill_path(null_fill_path);
+private dev_proc_stroke_path(null_stroke_path);
+private dev_proc_fill_trapezoid(null_fill_trapezoid);
+private dev_proc_fill_parallelogram(null_fill_parallelogram);
+private dev_proc_fill_triangle(null_fill_triangle);
+private dev_proc_draw_thin_line(null_draw_thin_line);
+/* We would like to have null implementations of begin/data/end image, */
+/* but we can't do this, because image_data must keep track of the */
+/* Y position so it can return 1 when done. */
+private dev_proc_strip_copy_rop(null_strip_copy_rop);
+
+#define null_procs(get_page_device) {\
+ gx_default_open_device,\
+ gx_forward_get_initial_matrix,\
+ gx_default_sync_output,\
+ gx_default_output_page,\
+ gx_default_close_device,\
+ gx_forward_map_rgb_color,\
+ gx_forward_map_color_rgb,\
+ null_fill_rectangle,\
+ gx_default_tile_rectangle,\
+ null_copy_mono,\
+ null_copy_color,\
+ gx_default_draw_line,\
+ gx_default_get_bits,\
+ gx_forward_get_params,\
+ null_put_params,\
+ gx_forward_map_cmyk_color,\
+ gx_forward_get_xfont_procs,\
+ gx_forward_get_xfont_device,\
+ gx_forward_map_rgb_alpha_color,\
+ get_page_device, /* differs */\
+ gx_forward_get_alpha_bits,\
+ null_copy_alpha,\
+ gx_forward_get_band,\
+ null_copy_rop,\
+ null_fill_path,\
+ null_stroke_path,\
+ gx_default_fill_mask,\
+ null_fill_trapezoid,\
+ null_fill_parallelogram,\
+ null_fill_triangle,\
+ null_draw_thin_line,\
+ gx_default_begin_image,\
+ gx_default_image_data,\
+ gx_default_end_image,\
+ gx_default_strip_tile_rectangle,\
+ null_strip_copy_rop,\
+ gx_default_get_clipping_box,\
+ gx_forward_get_hardware_params\
+}
+
+gx_device_null far_data gs_null_device = {
+ std_device_std_body_open(gx_device_null, 0, "null",
+ 0, 0, 72, 72),
+ null_procs(gx_default_get_page_device /* not a page device */),
+ 0 /* target */
+};
+
+gx_device_null far_data gs_nullpage_device = {
+ std_device_std_body_open(gx_device_null, 0, "nullpage",
+ 0, 0, 72, 72),
+ null_procs(gx_page_device_get_page_device /* a page device */),
+ 0 /* target */
+};
+
+private int
+null_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ return 0;
+}
+private int
+null_copy_mono(gx_device *dev, const byte *data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ return 0;
+}
+private int
+null_copy_color(gx_device *dev, const byte *data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height)
+{ return 0;
+}
+private int
+null_put_params(gx_device *dev, gs_param_list *plist)
+{ /* We must defeat attempts to reset the size; */
+ /* otherwise this is equivalent to gx_forward_put_params. */
+ gx_device *tdev = fdev->target;
+ int code;
+
+ if ( tdev != 0 )
+ return (*dev_proc(tdev, put_params))(tdev, plist);
+ code = gx_default_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+ dev->width = dev->height = 0;
+ return code;
+}
+private int
+null_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ return 0;
+}
+private int
+null_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return 0;
+}
+private int
+null_fill_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_fill_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ return 0;
+}
+private int
+null_stroke_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ return 0;
+}
+private int
+null_fill_trapezoid(gx_device *dev,
+ const gs_fixed_edge *left, const gs_fixed_edge *right,
+ fixed ybot, fixed ytop, bool swap_axes,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ return 0;
+}
+private int
+null_fill_parallelogram(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ return 0;
+}
+private int
+null_fill_triangle(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ return 0;
+}
+private int
+null_draw_thin_line(gx_device *dev,
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
+{ return 0;
+}
+private int
+null_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ return 0;
+}
+
+#undef fdev
diff --git a/gs/src/gdevnp6.c b/gs/src/gdevnp6.c
new file mode 100644
index 000000000..02237ddf1
--- /dev/null
+++ b/gs/src/gdevnp6.c
@@ -0,0 +1,257 @@
+/* Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevnp6.c */
+/* NEC dot-matrix printer driver: */
+/* tested on P6, should also work on P6+ and similar models. */
+#include "gdevprn.h"
+
+/* Thanks to Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) */
+/* for improvements to this code. */
+
+/* The device descriptors */
+private dev_proc_print_page (necp6_print_page);
+gx_device_printer far_data gs_necp6_device =
+ prn_device (prn_std_procs, "necp6",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ 360, 360,
+ 0, 0, 0.5, 0, /* margins */
+ 1, necp6_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Forward references */
+private void necp6_output_run (P4 (byte *, int, int, FILE *));
+private void necp6_improve_bitmap (P2 (byte *, int));
+
+/* Send the page to the printer. */
+private int
+necp6_print_page (gx_device_printer *pdev, FILE *prn_stream)
+{
+ int xres = pdev->x_pixels_per_inch;
+ int yres = pdev->y_pixels_per_inch;
+ int x_high = (xres == 360);
+ int y_high = (yres == 360);
+ int bits_per_column = (y_high ? 48 : 24);
+ uint line_size = gdev_prn_raster (pdev);
+ uint in_size = line_size * bits_per_column;
+ byte *in = (byte *) gs_malloc (in_size, 1, "necp6_print_page (in)");
+ uint out_size = ((pdev->width + 7) & -8) * 3;
+ byte *out = (byte *) gs_malloc (out_size, 1, "necp6_print_page (out)");
+ int y_passes = (y_high ? 2 : 1);
+ int dots_per_space = xres / 10; /* pica space = 1/10" */
+ int bytes_per_space = dots_per_space * 3;
+ int skip = 0, lnum = 0, ypass;
+
+ /* Check allocations */
+ if (in == 0 || out == 0)
+ {
+ if (out)
+ gs_free ((char *) out, out_size, 1, "necp6_print_page (out)");
+ if (in)
+ gs_free ((char *) in, in_size, 1, "necp6_print_page (in)");
+ return_error (gs_error_VMerror);
+ }
+
+ /* Initialize the printer and reset the margins. */
+#define init_string "\033@\033P\033l\000\r\034\063\001\033Q"
+ fwrite (init_string, sizeof (init_string) - 1, sizeof (char), prn_stream);
+ fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2,
+ prn_stream);
+
+ /* Print lines of graphics */
+ while (lnum < pdev->height)
+ {
+ byte *inp;
+ byte *in_end;
+ byte *out_end;
+ byte *out_blk;
+ register byte *outp;
+ int lcnt;
+
+ /* Copy 1 scan line and test for all zero. */
+ gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
+ if (in[0] == 0
+ && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
+ {
+ lnum++;
+ skip += 2 - y_high;
+ continue;
+ }
+
+ /* Vertical tab to the appropriate position. */
+ while ((skip >> 1) > 255)
+ {
+ fputs ("\033J\377", prn_stream);
+ skip -= 255 * 2;
+ }
+
+ if (skip)
+ {
+ if (skip >> 1)
+ fprintf (prn_stream, "\033J%c", skip >> 1);
+ if (skip & 1)
+ fputc ('\n', prn_stream);
+ }
+
+ /* Copy the rest of the scan lines. */
+ if (y_high)
+ {
+ inp = in + line_size;
+ for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
+ if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
+ line_size))
+ {
+ memset (inp, 0, (24 - lcnt) * line_size);
+ break;
+ }
+ inp = in + line_size * 24;
+ for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
+ if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
+ line_size))
+ {
+ memset (inp, 0, (24 - lcnt) * line_size);
+ break;
+ }
+ }
+ else
+ {
+ lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
+ in_size - line_size);
+ if (lcnt < 24)
+ /* Pad with lines of zeros. */
+ memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
+ }
+
+ for (ypass = 0; ypass < y_passes; ypass++)
+ {
+ out_end = out;
+ inp = in;
+ if (ypass)
+ inp += line_size * 24;
+ in_end = inp + line_size;
+
+ for (; inp < in_end; inp++, out_end += 24)
+ {
+ memflip8x8 (inp, line_size, out_end, 3);
+ memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3);
+ memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3);
+ }
+ /* Remove trailing 0s. */
+ while (out_end - 3 >= out && out_end[-1] == 0
+ && out_end[-2] == 0 && out_end[-3] == 0)
+ out_end -= 3;
+
+ for (out_blk = outp = out; outp < out_end;)
+ {
+ /* Skip a run of leading 0s. */
+ /* At least 10 are needed to make tabbing worth it. */
+
+ if (outp[0] == 0 && outp + 12 <= out_end
+ && outp[1] == 0 && outp[2] == 0
+ && outp[3] == 0 && outp[4] == 0 && outp[5] == 0
+ && outp[6] == 0 && outp[7] == 0 && outp[8] == 0
+ && outp[9] == 0 && outp[10] == 0 && outp[11] == 0)
+ {
+ byte *zp = outp;
+ int tpos;
+ byte *newp;
+ outp += 12;
+ while (outp + 3 <= out_end
+ && outp[0] == 0 && outp[1] == 0 && outp[2] == 0)
+ outp += 3;
+ tpos = (outp - out) / bytes_per_space;
+ newp = out + tpos * bytes_per_space;
+ if (newp > zp + 10)
+ {
+ /* Output preceding bit data. */
+ /* only false at beginning of line */
+ if (zp > out_blk)
+ {
+ if (x_high)
+ necp6_improve_bitmap (out_blk, (int) (zp - out_blk));
+ necp6_output_run (out_blk, (int) (zp - out_blk),
+ x_high, prn_stream);
+ }
+ /* Tab over to the appropriate position. */
+ fprintf (prn_stream, "\033D%c%c\t", tpos, 0);
+ out_blk = outp = newp;
+ }
+ }
+ else
+ outp += 3;
+ }
+ if (outp > out_blk)
+ {
+ if (x_high)
+ necp6_improve_bitmap (out_blk, (int) (outp - out_blk));
+ necp6_output_run (out_blk, (int) (outp - out_blk), x_high,
+ prn_stream);
+ }
+
+ fputc ('\r', prn_stream);
+ if (ypass < y_passes - 1)
+ fputc ('\n', prn_stream);
+ }
+ skip = 48 - y_high;
+ lnum += bits_per_column;
+ }
+
+ /* Eject the page and reinitialize the printer */
+ fputs ("\f\033@", prn_stream);
+ fflush (prn_stream);
+
+ gs_free ((char *) out, out_size, 1, "necp6_print_page (out)");
+ gs_free ((char *) in, in_size, 1, "necp6_print_page (in)");
+
+ return 0;
+}
+
+/* Output a single graphics command. */
+private void
+necp6_output_run (byte *data, int count, int x_high, FILE *prn_stream)
+{
+ int xcount = count / 3;
+ fputc (033, prn_stream);
+ fputc ('*', prn_stream);
+ fputc ((x_high ? 40 : 39), prn_stream);
+ fputc (xcount & 0xff, prn_stream);
+ fputc (xcount >> 8, prn_stream);
+ fwrite (data, 1, count, prn_stream);
+}
+
+/* If xdpi == 360, the NEC P6 cannot print adjacent pixels. Clear the
+ second last pixel of every run of set pixels, so that the last pixel
+ is always printed. */
+private void
+necp6_improve_bitmap (byte *data, int count)
+{
+ int i;
+ register byte *p = data + 6;
+
+ for (i = 6; i < count; i += 3, p += 3)
+ {
+ p[-6] &= ~(~p[0] & p[-3]);
+ p[-5] &= ~(~p[1] & p[-2]);
+ p[-4] &= ~(~p[2] & p[-1]);
+ }
+ p[-6] &= ~p[-3];
+ p[-5] &= ~p[-2];
+ p[-4] &= ~p[-1];
+
+}
diff --git a/gs/src/gdevo182.c b/gs/src/gdevo182.c
new file mode 100644
index 000000000..9f79fc3d7
--- /dev/null
+++ b/gs/src/gdevo182.c
@@ -0,0 +1,311 @@
+/* Copyright (C) 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevoki.c */
+/* Okidata Microline 182 printer driver */
+
+/* Contributed by Maarten Koning (smeg@bnr.ca) April 4, 1993 */
+
+/****************************************************************
+
+I use this driver from Unix with the following aliases:
+
+alias psp "gs -q -sDEVICE=oki182 -sOutputFile=\|lpr - <\!*"
+alias psphigh "gs -q -sDEVICE=oki182 -r144 -sOutputFile=\|lpr - <\!*"
+
+ps. I have my printer DIP switches set to the following (as viewed
+ while standing in front of your printer looking down into the
+ config access hatch located at the top of your printer
+ in the centre back).
+
+Upper Upper Bottom
+Left Right (at right)
+
+ x x x
+ x x x
+ x x x
+x x x
+ x x x
+ x x x
+x x x
+ x x x
+
+The upper DIP switches are on a SuperSpeed Serial
+card that will do 19200 baud. I have it set at 9600
+baud since that seems sufficient to keep the printer
+busy.
+
+The important thing is to be in 8-bit mode so that
+the graphics data can't match any Okidata commands
+(This driver sets the high bit of graphics data to 1).
+
+****************************************************************/
+
+#include "gdevprn.h"
+
+/*
+ * Available resolutions are 72x72 or 144x144;
+ * (144x72) would be possible to do also, but I didn't bother)
+ */
+
+/* The device descriptor */
+
+private dev_proc_print_page(oki_print_page);
+
+gx_device_printer far_data gs_oki182_device =
+ prn_device(prn_std_procs, "oki182",
+ 80, /* width_10ths, 8.0" */
+ 110, /* height_10ths, 11" */
+ 72, /* x_dpi */
+ 72, /* y_dpi */
+ 0, 0, 0, 0, /* margins */
+ 1, oki_print_page);
+
+/* ------ internal routines ------ */
+
+/* out is a pointer to an array of 7 scan lines,
+ lineSize is the number of bytes between a pixel and
+ the pixel directly beneath it.
+ scanBits is the number of bits in each scan line
+ out is a pointer to an array of column data, which
+ is how the Okidata wants the graphics image.
+
+ each column of graphics data is 7 bits high and
+ is encoded in a byte - highest pixel in the column
+ is the lowest bit in the byte. The upper bit of the
+ byte is set so that the okidata doesn't mistake
+ graphic image data for graphic commands.
+*/
+
+private void
+oki_transpose(byte *in, byte *out, int scanBits, register int lineSize)
+{
+ register bitMask = 0x80;
+ register byte *inPtr;
+ register byte outByte;
+
+ while (scanBits-- > 0) {
+
+ inPtr = in;
+
+ if (*inPtr & bitMask)
+ outByte = 0x81;
+ else
+ outByte = 0x80;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x02;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x04;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x08;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x10;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x20;
+ if (*(inPtr += lineSize) & bitMask)
+ outByte += 0x40;
+
+ *out++ = outByte;
+
+ if ((bitMask >>= 1) == 0) {
+ bitMask = 0x80;
+ in ++;
+ }
+ }
+}
+
+/* This routine tries to compress a sequence of okidata
+ graphic bytes by trimming off leading and trailing
+ zeros. Trailing zeros can be thrown away and leading
+ zeros can be replaced with a much smaller number of spaces.
+
+ 'in' is a pointer to the graphic bytes to be compressed.
+ origWidth is the number of bytes pointed to by 'in'.
+ highRes is non-zero when 144x144 mode is being used.
+
+ numSpaces is set to the number of spaces that should
+ be printed before the compressed image. newWidth is
+ the new number of bytes that the return value of this
+ function points to.
+
+ xxx - A future enhancement would be to replace long sequences
+ of embedded zeros with exit.graphics-<n> spaces-enter.graphics
+*/
+private byte *
+oki_compress(byte *in, int origWidth, int highRes,
+ int *numSpaces, int *newWidth)
+{
+ int spaces = 0;
+ int columns_per_space = 6;
+
+ byte *in_end = in + origWidth;
+
+ /* remove trailing zeros (which are realy 0x80's) */
+ while (in_end > in && in_end[-1] == 0x80)
+ in_end --;
+
+ if (highRes)
+ columns_per_space = 12;
+
+ /* remove leading zeros that can be replaced by spaces */
+ while(in < in_end && in[0] == 0x80 && memcmp((char *)in,
+ (char *)in + 1, columns_per_space - 1) == 0) {
+ spaces++;
+ in += columns_per_space;
+ }
+
+ *numSpaces = spaces;
+
+ /* just in case we compressed this line out of existance */
+ if (in_end > in)
+ *newWidth = in_end - in;
+ else
+ *newWidth = 0;
+
+ return(in);
+}
+
+/* Send the page to the printer. */
+
+private int
+oki_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ int highRes = pdev->y_pixels_per_inch > 100;
+ int bits_per_column = 7;
+ int i, spaces, width;
+ int lcnt;
+
+ int line_size = gdev_prn_raster((gx_device_printer *)pdev);
+
+ byte *in = (byte *)gs_malloc(16, line_size, "oki_print_page(in)");
+
+ byte *out1 = (byte *)gs_malloc(8, line_size, "oki_print_page(out1)");
+ byte *out2 = (byte *)gs_malloc(8, line_size, "oki_print_page(out2)");
+
+ byte *out3;
+
+ int lnum = 0;
+ int skip = 0;
+ int code = 0;
+
+ if ( in == 0 || out1 == 0 || out2 == 0)
+ { code = gs_error_VMerror;
+ gs_note_error(code);
+ goto bail;
+ }
+
+ /* Initialize the printer. */
+ /* CAN; 72x72; left margin = 001; disable skip over perforation */
+ fwrite("\030\034\033%C001\033%S0", 1, 12, prn_stream);
+
+ if (highRes) {
+ fwrite("\033R", 1, 2, prn_stream);
+ bits_per_column = 14;
+ }
+
+ /* Transfer pixels to printer */
+ while ( lnum < pdev->height ) {
+
+ /* Copy 1 scan line and test for all zero. */
+ code = gdev_prn_copy_scan_lines(pdev, lnum, in, line_size);
+ if ( code < 0 )
+ goto xit;
+
+ /* if line is all zero, skip */
+ if ( in[0] == 0 && !memcmp((char *)in, (char *)in + 1,
+ line_size - 1)) {
+ lnum++;
+ if (highRes)
+ skip++;
+ else
+ skip += 2;
+ continue;
+ }
+
+ /* use fine line feed to get to the appropriate position. */
+ while ( skip > 127 ) {
+ fputs("\033%5\177", prn_stream);
+ skip -= 127;
+ }
+ if ( skip )
+ fprintf(prn_stream, "\033%%5%c",
+ (char) (skip & 0xff));
+ skip = 0;
+
+ /* get the rest of the scan lines */
+ code = gdev_prn_copy_scan_lines(pdev, lnum + 1,
+ in + line_size, (bits_per_column - 1) * line_size);
+
+ if ( code < 0 )
+ goto xit;
+
+ lcnt = code + 1; /* since we already grabbed one line */
+
+ if ( lcnt < bits_per_column )
+ memset(in + lcnt * line_size, 0,
+ (bits_per_column - lcnt) * line_size);
+
+ if (highRes) {
+ oki_transpose(in, out1, pdev->width, 2 * line_size);
+ oki_transpose(in + line_size, out2,
+ pdev->width, 2 * line_size);
+ } else
+ oki_transpose(in, out1, pdev->width, line_size);
+
+ out3 = oki_compress(out1, pdev->width, highRes,
+ &spaces, &width);
+
+ for (i=0; i < spaces; i++)
+ putc(' ', prn_stream);
+
+ fwrite("\003", 1, 1, prn_stream);
+ fwrite(out3, 1, width, prn_stream);
+
+ if (highRes) {
+ /* exit graphics; carriage return; 1 bit line feed */
+ fprintf(prn_stream, "\003\002\015\033%%5%c", (char) 1);
+ out3 = oki_compress(out2, pdev->width, highRes,
+ &spaces, &width);
+ for (i=0; i < spaces; i++)
+ putc(' ', prn_stream);
+ fwrite("\003", 1, 1, prn_stream);
+ fwrite(out3, 1, width, prn_stream);
+ fprintf(prn_stream, "\003\002\015\033%%5%c", (char) 13);
+ } else
+ fwrite("\003\016\003\002", 1, 4, prn_stream);
+
+ lnum += bits_per_column;
+ }
+
+ /* Eject the page */
+xit:
+ fputc(014, prn_stream); /* form feed */
+ fflush(prn_stream);
+
+bail:
+ if ( out1 != 0 )
+ gs_free((char *)out1, 8, line_size, "oki_print_page(out1)");
+
+ if ( out2 != 0 )
+ gs_free((char *)out2, 8, line_size, "oki_print_page(out2)");
+
+ if ( in != 0 )
+ gs_free((char *)in, 16, line_size, "oki_print_page(in)");
+
+ return code;
+}
diff --git a/gs/src/gdevokii.c b/gs/src/gdevokii.c
new file mode 100644
index 000000000..9da633ebb
--- /dev/null
+++ b/gs/src/gdevokii.c
@@ -0,0 +1,327 @@
+/* Copyright (C) 1989, 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevokii.c */
+/*
+ * Okidata IBM compatible dot-matrix printer driver for Ghostscript.
+ *
+ * This device is for the Okidata Microline IBM compatible 9 pin dot
+ * matrix printers. It is derived from the Epson 9 pin printer driver
+ * using the standard 1/72" vertical pin spacing and the 60/120/240
+ * dpi horizontal resolutions. The vertical feed resolution however
+ * is 1/144" and the Okidata implements the standard 1/216" requests
+ * through "scaling":
+ *
+ * (power on)
+ * "\033J\001" (vertical feed 1/216") => Nothing happens
+ * "\033J\001" (vertical feed 1/216") => Advance 1/144"
+ * "\033J\001" (vertical feed 1/216") => Advance 1/144"
+ * "\033J\001" (vertical feed 1/216") => Nothing happens
+ * (and so on)
+ *
+ * The simple minded accounting used here keep track of when the
+ * page actually advances assumes the printer starts in a "power on"
+ * state.
+ *
+ * Supported resolutions are:
+ *
+ * 60x72 60x144
+ * 120x72 120x144
+ * 240x72 240x144
+ *
+ */
+#include "gdevprn.h"
+
+/*
+ * Valid values for X_DPI:
+ *
+ * 60, 120, 240
+ *
+ * The value specified at compile time is the default value used if the
+ * user does not specify a resolution at runtime.
+ */
+
+#ifndef X_DPI
+# define X_DPI 120
+#endif
+
+/*
+ * Valid values for Y_DPI:
+ *
+ * 72, 144
+ *
+ * The value specified at compile time is the default value used if the
+ * user does not specify a resolution at runtime.
+ */
+
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+/* The device descriptor */
+private dev_proc_print_page(okiibm_print_page);
+
+/* Okidata IBM device */
+gx_device_printer far_data gs_okiibm_device =
+ prn_device(prn_std_procs, "okiibm",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0.25, 0.0, 0.25, 0.0, /* margins */
+ 1, okiibm_print_page);
+
+/* ------ Internal routines ------ */
+
+/* Forward references */
+private void okiibm_output_run(P6(byte *, int, int, char, FILE *, int));
+
+/* Send the page to the printer. */
+private int
+okiibm_print_page1(gx_device_printer *pdev, FILE *prn_stream, int y_9pin_high,
+ const char *init_string, int init_length,
+ const char *end_string, int end_length)
+{
+ static const char graphics_modes_9[5] =
+ {
+ -1, 0 /*60*/, 1 /*120*/, -1, 3 /*240*/
+ };
+
+ int in_y_mult = (y_9pin_high ? 2 : 1);
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ /* Note that in_size is a multiple of 8. */
+ int in_size = line_size * (8 * in_y_mult);
+ byte *buf1 = (byte *)gs_malloc(in_size, 1, "okiibm_print_page(buf1)");
+ byte *buf2 = (byte *)gs_malloc(in_size, 1, "okiibm_print_page(buf2)");
+ byte *in = buf1;
+ byte *out = buf2;
+ int out_y_mult = 1;
+ int x_dpi = pdev->x_pixels_per_inch;
+ char start_graphics = graphics_modes_9[x_dpi / 60];
+ int first_pass = (start_graphics == 3 ? 1 : 0);
+ int last_pass = first_pass * 2;
+ int y_passes = (y_9pin_high ? 2 : 1);
+ int skip = 0, lnum = 0, pass, ypass;
+ int y_step = 0;
+
+ /* Check allocations */
+ if ( buf1 == 0 || buf2 == 0 )
+ { if ( buf1 )
+ gs_free((char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
+ if ( buf2 )
+ gs_free((char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
+ return_error(gs_error_VMerror);
+ }
+
+ /* Initialize the printer. */
+ fwrite(init_string, 1, init_length, prn_stream);
+
+ /* Print lines of graphics */
+ while ( lnum < pdev->height )
+ {
+ byte *in_data;
+ byte *inp;
+ byte *in_end;
+ byte *out_end;
+ int lcnt;
+
+ /* Copy 1 scan line and test for all zero. */
+ gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ if ( in_data[0] == 0 &&
+ !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
+ )
+ {
+ lnum++;
+ skip += 2 / in_y_mult;
+ continue;
+ }
+
+ /*
+ * Vertical tab to the appropriate position.
+ * The skip count is in 1/144" steps. If total
+ * vertical request is not a multiple od 1/72"
+ * we need to make sure the page is actually
+ * going to advance.
+ */
+ if ( skip & 1 )
+ {
+ int n = 1 + (y_step == 0 ? 1 : 0);
+ fprintf(prn_stream, "\033J%c", n);
+ y_step = (y_step + n) % 3;
+ skip -= 1;
+ }
+ skip = skip / 2 * 3;
+ while ( skip > 255 )
+ {
+ fputs("\033J\377", prn_stream);
+ skip -= 255;
+ }
+ if ( skip )
+ {
+ fprintf(prn_stream, "\033J%c", skip);
+ }
+
+ /* Copy the the scan lines. */
+ lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+ if ( lcnt < 8 * in_y_mult )
+ { /* Pad with lines of zeros. */
+ memset(in + lcnt * line_size, 0,
+ in_size - lcnt * line_size);
+ }
+
+ if ( y_9pin_high )
+ { /* Shuffle the scan lines */
+ byte *p;
+ int i;
+ static const char index[] =
+ { 0, 2, 4, 6, 8, 10, 12, 14,
+ 1, 3, 5, 7, 9, 11, 13, 15
+ };
+ for ( i = 0; i < 16; i++ )
+ {
+ memcpy( out + (i * line_size),
+ in + (index[i] * line_size),
+ line_size);
+ }
+ p = in;
+ in = out;
+ out = p;
+ }
+
+ for ( ypass = 0; ypass < y_passes; ypass++ )
+ {
+ for ( pass = first_pass; pass <= last_pass; pass++ )
+ {
+ /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
+ /* because that's how the printer wants the data. */
+
+ if ( pass == first_pass )
+ {
+ out_end = out;
+ inp = in;
+ in_end = inp + line_size;
+
+ for ( ; inp < in_end; inp++, out_end += 8 )
+ {
+ gdev_prn_transpose_8x8(inp + (ypass * 8 * line_size),
+ line_size, out_end, 1);
+ }
+ /* Remove trailing 0s. */
+ while ( out_end > out && out_end[-1] == 0 )
+ {
+ out_end--;
+ }
+ }
+
+ /* Transfer whatever is left and print. */
+ if ( out_end > out )
+ {
+ okiibm_output_run(out, (int)(out_end - out),
+ out_y_mult, start_graphics,
+ prn_stream, pass);
+ }
+ fputc('\r', prn_stream);
+ }
+ if ( ypass < y_passes - 1 )
+ {
+ int n = 1 + (y_step == 0 ? 1 : 0);
+ fprintf(prn_stream, "\033J%c", n);
+ y_step = (y_step + n) % 3;
+ }
+ }
+ skip = 16 - y_passes + 1; /* no skip on last Y pass */
+ lnum += 8 * in_y_mult;
+ }
+
+ /* Reinitialize the printer. */
+ fwrite(end_string, 1, end_length, prn_stream);
+ fflush(prn_stream);
+
+ gs_free((char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
+ gs_free((char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
+ return 0;
+}
+
+/* Output a single graphics command. */
+/* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
+private void
+okiibm_output_run(byte *data, int count, int y_mult,
+ char start_graphics, FILE *prn_stream, int pass)
+{
+ int xcount = count / y_mult;
+
+ fputc(033, prn_stream);
+ fputc("KLYZ"[start_graphics], prn_stream);
+ fputc(xcount & 0xff, prn_stream);
+ fputc(xcount >> 8, prn_stream);
+ if ( !pass )
+ {
+ fwrite(data, 1, count, prn_stream);
+ }
+ else
+ {
+ /* Only write every other column of y_mult bytes. */
+ int which = pass;
+ register byte *dp = data;
+ register int i, j;
+
+ for ( i = 0; i < xcount; i++, which++ )
+ {
+ for ( j = 0; j < y_mult; j++, dp++ )
+ {
+ putc(((which & 1) ? *dp : 0), prn_stream);
+ }
+ }
+ }
+}
+
+/* The print_page procedures are here, to avoid a forward reference. */
+
+private const char okiibm_init_string[] = { 0x18 };
+private const char okiibm_end_string[] = { 0x0c };
+private const char okiibm_one_direct[] = { 0x1b, 0x55, 0x01 };
+private const char okiibm_two_direct[] = { 0x1b, 0x55, 0x00 };
+
+private int
+okiibm_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ char init_string[16], end_string[16];
+ int init_length, end_length;
+
+ init_length = sizeof(okiibm_init_string);
+ memcpy(init_string, okiibm_init_string, init_length);
+
+ end_length = sizeof(okiibm_end_string);
+ memcpy(end_string, okiibm_end_string, end_length);
+
+ if ( pdev->y_pixels_per_inch > 72 &&
+ pdev->x_pixels_per_inch > 60 )
+ {
+ /* Unidirectional printing for the higher resolutions. */
+ memcpy( init_string + init_length, okiibm_one_direct,
+ sizeof(okiibm_one_direct) );
+ init_length += sizeof(okiibm_one_direct);
+
+ memcpy( end_string + end_length, okiibm_two_direct,
+ sizeof(okiibm_two_direct) );
+ end_length += sizeof(okiibm_two_direct);
+ }
+
+ return okiibm_print_page1( pdev, prn_stream,
+ pdev->y_pixels_per_inch > 72 ? 1 : 0,
+ init_string, init_length,
+ end_string, end_length );
+}
diff --git a/gs/src/gdevos2p.c b/gs/src/gdevos2p.c
new file mode 100644
index 000000000..d8fa806cf
--- /dev/null
+++ b/gs/src/gdevos2p.c
@@ -0,0 +1,701 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevos2p.c */
+/*
+ * OS/2 printer device
+ * by Russell Lang.
+ * Derived from mswinpr2 device by Russell Lang and
+ * L. Peter Deutsch, Aladdin Enterprises.
+ */
+
+/* This device works when GS is a DLL loaded by a PM program */
+/* It does not work when GS is a text mode EXE */
+
+/* This driver uses the printer default size and resolution and
+ * ignores page size and resolution set using -gWIDTHxHEIGHT and
+ * -rXxY. You must still set the correct PageSize to get the
+ * correct clipping path. If you don't specify a value for
+ * -dBitsPerPixel, the depth will be obtained from the printer
+ * device context.
+ */
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_DEV
+#define INCL_GPIBITMAPS
+#define INCL_SPL
+#define INCL_SPLDOSPRINT
+#define INCL_SPLERRORS
+
+#include <os2.h>
+
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "gp.h"
+
+extern HWND hwndtext; /* in gp_os2.h */
+extern const char *gs_product;
+
+typedef struct tagOS2QL {
+ PRQINFO3 *prq; /* queue list */
+ ULONG len; /* bytes in queue list (for gs_free) */
+ int defqueue; /* default queue */
+ int nqueues; /* number of queues */
+} OS2QL;
+
+#ifndef NERR_BufTooSmall
+#define NERR_BufTooSmall 2123 /* For SplEnumQueue */
+#endif
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_os2prn_s gx_device_os2prn;
+#undef opdev
+#define opdev ((gx_device_os2prn *)dev)
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(os2prn_open);
+private dev_proc_close_device(os2prn_close);
+private dev_proc_print_page(os2prn_print_page);
+private dev_proc_map_rgb_color(os2prn_map_rgb_color);
+private dev_proc_map_color_rgb(os2prn_map_color_rgb);
+private dev_proc_put_params(os2prn_put_params);
+private dev_proc_get_params(os2prn_get_params);
+
+private void os2prn_set_bpp(gx_device *dev, int depth);
+private int os2prn_get_queue_list(OS2QL *ql);
+private void os2prn_free_queue_list(OS2QL *ql);
+int os2prn_get_printer(OS2QL *ql);
+
+private gx_device_procs os2prn_procs =
+ prn_color_params_procs(os2prn_open, gdev_prn_output_page, os2prn_close,
+ os2prn_map_rgb_color, os2prn_map_color_rgb,
+ os2prn_get_params, os2prn_put_params);
+
+
+/* The device descriptor */
+struct gx_device_os2prn_s {
+ gx_device_common;
+ gx_prn_device_common;
+ HAB hab;
+ HDC hdc;
+ HPS hps;
+ char queue_name[256]; /* OS/2 printer queue name */
+ int newframe; /* false before first page */
+ OS2QL ql;
+ int clipbox[4]; /* llx, lly, urx, ury in pixels */
+ HDC hdcMem;
+ HPS hpsMem;
+};
+
+gx_device_os2prn far_data gs_os2prn_device = {
+ prn_device_std_body(gx_device_os2prn, os2prn_procs, "os2prn",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72, 72,
+ 0, 0, 0, 0,
+ 0, os2prn_print_page), /* depth = 0 */
+ 0, /* hab */
+ 0, /* hdc */
+ 0, /* hps */
+ "" /* queue_name */
+};
+
+/* Open the os2prn driver */
+private int
+os2prn_open(gx_device *dev)
+{ int code;
+ PTIB pptib;
+ PPIB pppib;
+ DEVOPENSTRUC dop;
+ ULONG cbBuf;
+ ULONG cbNeeded;
+ APIRET rc;
+ PBYTE pbuf;
+ char *p;
+ SIZEL sizlPage;
+ LONG caps[2];
+ HCINFO hcinfo;
+ LONG nforms;
+ float m[4];
+ int depth;
+ FILE *pfile;
+ int i;
+ char *prefix = "\\\\spool\\"; /* 8 characters long */
+
+ PRQINFO3 *pprq;
+ gx_device_os2prn *oprn;
+
+ oprn = opdev;
+
+ if (DosGetInfoBlocks(&pptib, &pppib)) {
+ fprintf(stderr,"\nos2prn_open: Couldn't get pid\n");
+ return gs_error_limitcheck;
+ }
+ if (pppib->pib_ultype != 3) {
+ /* if caller is not PM app */
+ fprintf(stderr,"os2prn device can only be used from a PM application\n");
+ return gs_error_limitcheck;
+ }
+
+ opdev->hab = WinQueryAnchorBlock(hwndtext);
+ opdev->newframe = 0;
+
+ if (os2prn_get_queue_list(&opdev->ql))
+ return gs_error_limitcheck;
+
+ if (opdev->queue_name[0] == '\0') {
+ /* obtain printer name from filename */
+ p = opdev->fname;
+ for (i=0; i<8; i++) {
+ if (prefix[i] == '\\') {
+ if ((*p != '\\') && (*p != '/'))
+ break;
+ }
+ else if (tolower(*p) != prefix[i])
+ break;
+ p++;
+ }
+ if (i==8 && (strlen(p)!=0))
+ strcpy(opdev->queue_name, p);
+ }
+
+ pprq = NULL;
+ if (opdev->queue_name[0] != '\0') {
+ for (i=0; i<opdev->ql.nqueues; i++) {
+ if (strcmp(opdev->ql.prq[i].pszName, opdev->queue_name) == 0) {
+ pprq = &(opdev->ql.prq[i]);
+ break;
+ }
+ }
+ }
+ else {
+ /* use default queue */
+ pprq = &(opdev->ql.prq[opdev->ql.defqueue]);
+ }
+ if (pprq == (PRQINFO3 *)NULL) {
+ fprintf(stderr, "Invalid os2prn queue name -sOS2QUEUE=\042%s\042\n", opdev->queue_name);
+ fprintf(stderr, "Valid device names are:\n");
+ for (i=0; i<opdev->ql.nqueues; i++) {
+ fprintf(stderr, " -sOS2QUEUE=\042%s\042\n", opdev->ql.prq[i].pszName);
+ }
+ return gs_error_rangecheck;
+ }
+
+
+ /* open printer device */
+ memset(&dop, 0, sizeof(dop));
+ dop.pszLogAddress = pprq->pszName; /* queue name */
+ p = strchr(pprq->pszDriverName, '.');
+ if (p != (char *)NULL)
+ *p = '\0';
+ dop.pszDriverName = pprq->pszDriverName;
+ dop.pszDataType = "PM_Q_STD";
+ dop.pdriv = pprq->pDriverData;
+ opdev->hdc = DevOpenDC(opdev->hab, OD_QUEUED, "*", 9L, (PDEVOPENDATA)&dop, (HDC)NULL);
+ if (opdev->hdc == DEV_ERROR) {
+ ERRORID eid = WinGetLastError(opdev->hab);
+ fprintf(stderr, "DevOpenDC for printer error 0x%x\n", eid);
+ return gs_error_limitcheck;
+ }
+
+ os2prn_free_queue_list(&opdev->ql);
+
+ /* find out resolution of printer */
+ /* this is returned in pixels/metre */
+ DevQueryCaps(opdev->hdc, CAPS_HORIZONTAL_RESOLUTION, 2, caps);
+ dev->x_pixels_per_inch = (int)(caps[0] * 0.0254 + 0.5);
+ dev->y_pixels_per_inch = (int)(caps[1] * 0.0254 + 0.5);
+
+ /* find out page size and margins */
+ /* these are returned in millimetres */
+ nforms = DevQueryHardcopyCaps(opdev->hdc, 0, 0, &hcinfo);
+ for (i=0; i<nforms; i++) {
+ DevQueryHardcopyCaps(opdev->hdc, i, 1, &hcinfo);
+ if (hcinfo.flAttributes & HCAPS_CURRENT)
+ break; /* this is the default page size */
+ }
+ /* GS size is in pixels */
+ dev->width = hcinfo.cx * caps[0] / 1000;
+ dev->height = hcinfo.cy * caps[1] / 1000;
+ /* GS margins are in inches */
+ m[0] /*left*/ = hcinfo.xLeftClip / 25.4;
+ m[1] /*bottom*/ = hcinfo.yBottomClip / 25.4;
+ m[2] /*right*/ = (hcinfo.cx - hcinfo.xRightClip) / 25.4;
+ m[3] /*top*/ = (hcinfo.cy - hcinfo.yTopClip) / 25.4;
+ gx_device_set_margins(dev, m, true);
+ /* set bounding box in pixels for later drawing */
+ opdev->clipbox[0] = (int)(hcinfo.xLeftClip / 25.4 * dev->x_pixels_per_inch+1); /* round inwards */
+ opdev->clipbox[1] = (int)(hcinfo.yBottomClip / 25.4 * dev->y_pixels_per_inch+1);
+ opdev->clipbox[2] = (int)(hcinfo.xRightClip / 25.4 * dev->x_pixels_per_inch);
+ opdev->clipbox[3] = (int)(hcinfo.yTopClip / 25.4 * dev->y_pixels_per_inch);
+
+ /* get presentation space */
+ sizlPage.cx = dev->width;
+ sizlPage.cy = dev->height;
+ opdev->hps = GpiCreatePS(opdev->hab, opdev->hdc, &sizlPage,
+ PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
+
+ depth = dev->color_info.depth;
+ if (depth == 0) {
+ /* Set parameters that were unknown before opening device */
+ /* Find out if the device supports color */
+ /* We recognize 1, 3, 8 and 24 bit color devices */
+ DevQueryCaps(opdev->hdc, CAPS_COLOR_PLANES, 2, caps);
+ /* caps[0] is #color planes, caps[1] is #bits per plane */
+ depth = caps[0] * caps[1];
+ }
+ os2prn_set_bpp(dev, depth);
+
+ /* create a memory DC compatible with printer */
+ opdev->hdcMem = DevOpenDC(opdev->hab, OD_MEMORY, "*", 0L, NULL, opdev->hdc);
+ if (opdev->hdcMem == DEV_ERROR) {
+ ERRORID eid = WinGetLastError(opdev->hab);
+ fprintf(stderr, "DevOpenDC for memory error 0x%x\n", eid);
+ return gs_error_limitcheck;
+ }
+ sizlPage.cx = dev->width;
+ sizlPage.cy = dev->height;
+ opdev->hpsMem = GpiCreatePS(opdev->hab, opdev->hdcMem, &sizlPage,
+ PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC );
+ if (opdev->hpsMem == GPI_ERROR) {
+ ERRORID eid = WinGetLastError(opdev->hab);
+ fprintf(stderr, "GpiCreatePS for memory error 0x%x\n", eid);
+ return gs_error_limitcheck;
+ }
+
+ if (DevEscape(opdev->hdc, DEVESC_STARTDOC, (LONG)strlen(gs_product),
+ (char *)gs_product, NULL, NULL) == DEVESC_ERROR) {
+ ERRORID eid = WinGetLastError(opdev->hab);
+ fprintf(stderr, "DEVESC_STARTDOC error 0x%x\n", eid);
+ return gs_error_limitcheck;
+ }
+
+ /* gdev_prn_open opens a temporary file which we don't want */
+ /* so we specify the name now so we can delete it later */
+ pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
+ opdev->fname, "wb");
+ fclose(pfile);
+ code = gdev_prn_open(dev);
+
+ return code;
+}
+
+/* Close the os2prn driver */
+private int
+os2prn_close(gx_device *dev)
+{ int code;
+ LONG lOut;
+ USHORT usJobID;
+ /* tell printer that all is finished */
+ DevEscape(opdev->hdc, DEVESC_ENDDOC, 0L, NULL, &lOut, (PBYTE)&usJobID);
+ /* Free resources */
+ GpiAssociate(opdev->hps, (HDC)NULL);
+ GpiDestroyPS(opdev->hps);
+ DevCloseDC(opdev->hdc);
+
+ if (opdev->hpsMem != GPI_ERROR)
+ GpiDestroyPS(opdev->hpsMem);
+ if (opdev->hdcMem != DEV_ERROR)
+ DevCloseDC(opdev->hdcMem);
+
+ code = gdev_prn_close(dev);
+ /* delete unwanted temporary file */
+ unlink(opdev->fname);
+ return code;
+}
+
+/* Get os2pm parameters */
+int
+os2prn_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gdev_prn_get_params(dev, plist);
+ gs_param_string qs;
+ qs.data = opdev->queue_name, qs.size = strlen(qs.data),
+ qs.persistent = false;
+ code < 0 ||
+ (code = param_write_string(plist, "OS2QUEUE", &qs)) < 0;
+ return code;
+}
+
+
+
+/* We implement this ourselves so that we can change BitsPerPixel */
+/* before the device is opened */
+int
+os2prn_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0, code;
+ int old_bpp = dev->color_info.depth;
+ int bpp = old_bpp;
+ gs_param_string qs;
+
+ /* Handle extra parameters */
+ switch ( code = param_read_string(plist, "OS2QUEUE", &qs) )
+ {
+ case 0:
+ if ( qs.size == strlen(opdev->queue_name) &&
+ !memcmp(opdev->queue_name, qs.data, qs.size)
+ )
+ { qs.data = 0;
+ break;
+ }
+ if ( dev->is_open )
+ ecode = gs_error_rangecheck;
+ else if ( qs.size >= sizeof(opdev->queue_name))
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto qe;
+ default:
+ ecode = code;
+qe: param_signal_error(plist, "OS2QUEUE", ecode);
+ case 1:
+ qs.data = 0;
+ break;
+ }
+
+ switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
+ {
+ case 0:
+ if ( dev->is_open )
+ ecode = gs_error_rangecheck;
+ else
+ { /* change dev->color_info is valid before device is opened */
+ os2prn_set_bpp(dev, bpp);
+ break;
+ }
+ goto bppe;
+ default:
+ ecode = code;
+bppe: param_signal_error(plist, "BitsPerPixel", ecode);
+ case 1:
+ break;
+ }
+
+ if ( ecode >= 0 )
+ ecode = gdev_prn_put_params(dev, plist);
+
+ if ( ( ecode >= 0 ) && ( qs.data != 0 ) )
+ { memcpy(opdev->queue_name, qs.data, qs.size);
+ opdev->queue_name[qs.size] = 0;
+ }
+
+ return ecode;
+}
+
+
+
+/* ------ Internal routines ------ */
+
+#undef opdev
+#define opdev ((gx_device_os2prn *)pdev)
+
+/************************************************/
+
+
+/* ------ Private definitions ------ */
+
+
+/* new os2prn_print_page routine */
+
+/* Write BMP header to memory, then send bitmap to printer */
+/* one scan line at a time */
+private int
+os2prn_print_page(gx_device_printer *pdev, FILE *file)
+{ int raster = gdev_prn_raster(pdev);
+ /* BMP scan lines are padded to 32 bits. */
+ ulong bmp_raster = (raster+3) & (~3);
+ ulong bmp_raster_multi;
+ int height = pdev->height;
+ int depth = pdev->color_info.depth;
+ byte *row;
+ int y;
+ int code = 0; /* return code */
+ POINTL apts[4];
+ APIRET rc;
+ POINTL aptsb[4];
+ HBITMAP hbmp, hbmr;
+ int i, lines;
+ int ystart, yend;
+ int yslice;
+
+ struct bmi_s {
+ BITMAPINFOHEADER2 h;
+ RGB2 pal[256];
+ } bmi;
+
+ yslice = 65535 / bmp_raster;
+ bmp_raster_multi = bmp_raster * yslice;
+ row = (byte *)gs_malloc(bmp_raster_multi, 1, "bmp file buffer");
+ if ( row == 0 ) /* can't allocate row buffer */
+ return_error(gs_error_VMerror);
+
+ if (opdev->newframe)
+ DevEscape(opdev->hdc, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL);
+ opdev->newframe = 1;
+
+ /* Write the info header. */
+
+ memset(&bmi.h, 0, sizeof(bmi.h));
+ bmi.h.cbFix = sizeof(bmi.h);
+ bmi.h.cx = pdev->width; /* opdev->mdev.width; */
+ /* bmi.h.cy = height; */
+ bmi.h.cy = yslice; /* size for memory PS */
+ bmi.h.cPlanes = 1;
+ bmi.h.cBitCount = pdev->color_info.depth;
+
+ /* Write the palette. */
+
+ if ( depth <= 8 )
+ { int i;
+ gx_color_value rgb[3];
+ PRGB2 pq;
+ bmi.h.cclrUsed = 1 << depth;
+ bmi.h.cclrImportant = 1 << depth;
+ for ( i = 0; i != 1 << depth; i++ )
+ { (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
+ (gx_color_index)i, rgb);
+ pq = &bmi.pal[i];
+ pq->bRed = gx_color_value_to_byte(rgb[0]);
+ pq->bGreen = gx_color_value_to_byte(rgb[1]);
+ pq->bBlue = gx_color_value_to_byte(rgb[2]);
+ pq->fcOptions = 0;
+ }
+ }
+ else {
+ bmi.h.cclrUsed = 0;
+ bmi.h.cclrImportant = 0;
+ }
+
+ /* for GpiDrawBits */
+ /* target is inclusive */
+ apts[0].x = 0;
+ apts[0].y = 0; /* filled in later */
+ apts[1].x = pdev->width-1;
+ apts[1].y = 0; /* filled in later */
+ /* source is not inclusive of top & right borders */
+ apts[2].x = 0;
+ apts[2].y = 0;
+ apts[3].x = pdev->width;
+ apts[3].y = 0; /* filled in later */
+
+ /* for GpiBitBlt */
+ /* target is not inclusive */
+ aptsb[0].x = opdev->clipbox[0];
+ aptsb[0].y = 0; /* filled in later */
+ aptsb[1].x = opdev->clipbox[2];
+ aptsb[1].y = 0; /* filled in later */
+ /* source is not inclusive */
+ aptsb[2].x = opdev->clipbox[0];
+ aptsb[2].y = 0;
+ aptsb[3].x = opdev->clipbox[2];
+ aptsb[3].y = 0; /* filled in later */
+
+ /* write the bits */
+ ystart = opdev->clipbox[3];
+ yend = opdev->clipbox[1];
+ y = ystart;
+ while (y > yend) {
+ /* create a bitmap for the memory DC */
+ hbmp = GpiCreateBitmap(opdev->hpsMem, &bmi.h, 0L, NULL, NULL);
+ if (hbmp == GPI_ERROR)
+ goto bmp_done;
+ hbmr = GpiSetBitmap(opdev->hpsMem, hbmp);
+
+ /* copy slice to memory bitmap */
+ if (y > yend + yslice)
+ lines = yslice;
+ else
+ lines = y - yend;
+ y -= lines;
+ for (i=lines-1; i>=0; i--)
+ gdev_prn_copy_scan_lines(pdev, ystart-1 - (y+i), row + (bmp_raster*i), raster);
+ apts[0].y = 0; /* target */
+ apts[1].y = lines;
+ apts[3].y = lines-1; /* source */
+ /* copy DIB bitmap to memory bitmap */
+ rc = GpiDrawBits(opdev->hpsMem, row, (BITMAPINFO2 *)&bmi, 4, apts,
+ (depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
+
+ /* copy slice to printer */
+ aptsb[0].y = y;
+ aptsb[1].y = y+lines;
+ aptsb[3].y = lines;
+ rc = GpiBitBlt(opdev->hps, opdev->hpsMem, 4, aptsb, ROP_SRCCOPY, BBO_IGNORE);
+
+ /* delete bitmap */
+ if (hbmr != HBM_ERROR)
+ GpiSetBitmap(opdev->hpsMem, (ULONG)0);
+ hbmr = HBM_ERROR;
+ if (hbmp != GPI_ERROR)
+ GpiDeleteBitmap(hbmp);
+ hbmp = GPI_ERROR;
+ }
+
+bmp_done:
+ if (row)
+ gs_free((char *)row, bmp_raster_multi, 1, "bmp file buffer");
+
+ return code;
+}
+
+/* combined color mappers */
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that OS/2 expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+os2prn_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+ switch(dev->color_info.depth) {
+ case 1:
+ return gdev_prn_map_rgb_color(dev, r, g, b);
+ case 4:
+ /* use only 8 colors */
+ return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
+ (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
+ (b > (gx_max_color_value / 2 + 1) ? 1 : 0) ;
+ case 8:
+ return pc_8bit_map_rgb_color(dev, r, g, b);
+ case 24:
+ return gx_color_value_to_byte(r) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(b) << 16);
+ }
+ return 0; /* error */
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+os2prn_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ switch(dev->color_info.depth) {
+ case 1:
+ gdev_prn_map_color_rgb(dev, color, prgb);
+ break;
+ case 4:
+ /* use only 8 colors */
+ prgb[0] = (color & 4) ? gx_max_color_value : 0;
+ prgb[1] = (color & 2) ? gx_max_color_value : 0;
+ prgb[2] = (color & 1) ? gx_max_color_value : 0;
+ break;
+ case 8:
+ pc_8bit_map_color_rgb(dev, color, prgb);
+ break;
+ case 24:
+ prgb[2] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color & 0xff);
+ break;
+ }
+ return 0;
+}
+
+void
+os2prn_set_bpp(gx_device *dev, int depth)
+{
+ if (depth > 8) {
+ static const gx_device_color_info os2prn_24color = dci_std_color(24);
+ dev->color_info = os2prn_24color;
+ }
+ else if ( depth >= 8 ) {
+ /* 8-bit (SuperVGA-style) color. */
+ /* (Uses a fixed palette of 3,3,2 bits.) */
+ static const gx_device_color_info os2prn_8color = dci_pc_8bit;
+ dev->color_info = os2prn_8color;
+ }
+ else if ( depth >= 3) {
+ /* 3 plane printer */
+ /* suitable for impact dot matrix CMYK printers */
+ /* create 4-bit bitmap, but only use 8 colors */
+ static const gx_device_color_info os2prn_4color = {3, 4, 1, 1, 2, 2};
+ dev->color_info = os2prn_4color;
+ }
+ else { /* default is black_and_white */
+ static const gx_device_color_info os2prn_1color = dci_std_color(1);
+ dev->color_info = os2prn_1color;
+ }
+}
+
+/* Get list of queues from SplEnumQueue */
+/* returns 0 if OK, non-zero for error */
+private int
+os2prn_get_queue_list(OS2QL *ql)
+{
+ SPLERR splerr;
+ USHORT jobCount;
+ ULONG cbBuf;
+ ULONG cTotal;
+ ULONG cReturned;
+ ULONG cbNeeded;
+ ULONG ulLevel;
+ ULONG i;
+ PSZ pszComputerName;
+ PBYTE pBuf;
+ PPRQINFO3 prq;
+
+ ulLevel = 3L;
+ pszComputerName = (PSZ)NULL ;
+ splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L, /* cbBuf */
+ &cReturned, &cTotal,
+ &cbNeeded, NULL);
+ if ( splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall ) {
+ pBuf = gs_malloc(cbNeeded, 1, "OS/2 printer device info buffer");
+ ql->prq = (PRQINFO3 *)pBuf;
+ if (ql->prq != (PRQINFO3 *)NULL) {
+ ql->len = cbNeeded;
+ cbBuf = cbNeeded ;
+ splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
+ &cReturned, &cTotal,
+ &cbNeeded, NULL);
+ if (splerr == NO_ERROR) {
+ /* Set pointer to point to the beginning of the buffer. */
+ prq = (PPRQINFO3)pBuf ;
+ /* cReturned has the count of the number of PRQINFO3 structures. */
+ ql->nqueues = cReturned;
+ ql->defqueue = 0;
+ for (i=0;i < cReturned ; i++) {
+ if ( prq->fsType & PRQ3_TYPE_APPDEFAULT )
+ ql->defqueue = i;
+ prq++;
+ }/*endfor cReturned */
+ }
+ }
+ }
+ else {
+ /* If we are here we had a bad error code. Print it and some other info.*/
+ fprintf(stdout, "SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
+ splerr, cTotal, cReturned, cbNeeded) ;
+ }
+ if (splerr)
+ return splerr;
+ return 0;
+}
+
+
+private void
+os2prn_free_queue_list(OS2QL *ql)
+{
+ gs_free((char *)ql->prq, ql->len, 1, "os2prn queue list");
+ ql->prq = NULL;
+ ql->len = 0;
+ ql->defqueue = 0;
+ ql->nqueues = 0;
+}
diff --git a/gs/src/gdevp2up.c b/gs/src/gdevp2up.c
new file mode 100644
index 000000000..6b6f01de3
--- /dev/null
+++ b/gs/src/gdevp2up.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevp2up.c */
+/* A "2-up" PCX device for testing page objects. */
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "gxclpage.h"
+
+extern gx_device_printer gs_pcx256_device;
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+/*
+ * Define the size of the rendering buffer.
+ */
+#define RENDER_BUFFER_SPACE 500000
+
+/* This device only supports SVGA 8-bit color. */
+
+private dev_proc_open_device(pcx2up_open);
+private dev_proc_print_page(pcx2up_print_page);
+
+typedef struct gx_device_2up_s {
+ gx_device_common;
+ gx_prn_device_common;
+ bool have_odd_page;
+ gx_saved_page odd_page;
+} gx_device_2up;
+
+private const gx_device_procs pcx2up_procs =
+ prn_color_procs(pcx2up_open, gdev_prn_output_page, gdev_prn_close,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_2up far_data gs_pcx2up_device =
+{ prn_device_body(gx_device_2up, pcx2up_procs, "pcx2up",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 3,8,6,6,7,7, pcx2up_print_page)
+};
+
+/* Open the device. We reimplement this to force banding with */
+/* delayed rasterizing. */
+private int
+pcx2up_open(gx_device *dev)
+{ gx_device_printer *pdev = (gx_device_printer *)dev;
+ int code;
+ gdev_prn_space_params save_params;
+
+ save_params = pdev->space_params;
+ pdev->space_params.MaxBitmap = 0; /* force banding */
+ pdev->space_params.band.BandWidth =
+ dev->width * 2 + (int)(dev->HWResolution[0] * 2.0);
+ pdev->space_params.band.BandBufferSpace = RENDER_BUFFER_SPACE;
+ code = gdev_prn_open(dev);
+ pdev->space_params = save_params;
+ ((gx_device_2up *)dev)->have_odd_page = false;
+ return code;
+}
+
+/* Write the page. */
+private int
+pcx2up_print_page(gx_device_printer *pdev, FILE *file)
+{ gx_device_2up *pdev2 = (gx_device_2up *)pdev;
+ const gx_device_printer *prdev_template =
+ (const gx_device_printer *)&gs_pcx2up_device;
+
+ if ( !pdev2->have_odd_page )
+ { /* This is the odd page, just save it. */
+ pdev2->have_odd_page = true;
+ return gdev_prn_save_page(pdev, &pdev2->odd_page, 1);
+ }
+ else
+ { /* This is the even page, do 2-up output. */
+ gx_saved_page even_page;
+ gx_placed_page pages[2];
+ int x_offset = (int)(pdev->HWResolution[0] * 0.5);
+ int y_offset = (int)(pdev->HWResolution[1] * 0.5);
+ int code = gdev_prn_save_page(pdev, &even_page, 1);
+ int prdev_size = prdev_template->params_size;
+ gx_device_printer *prdev;
+#define rdev ((gx_device *)prdev)
+
+ if ( code < 0 )
+ return code;
+ /* Create the placed page list. */
+ pages[0].page = &pdev2->odd_page;
+ pages[0].offset.x = x_offset;
+ pages[0].offset.y = 0 /*y_offset*/;
+ pages[1].page = &even_page;
+ pages[1].offset.x = pdev->width + x_offset * 3;
+ pages[1].offset.y = 0 /*y_offset*/;
+ /* Create and open a device for rendering. */
+ prdev = (gx_device_printer *)
+ gs_alloc_bytes(pdev->memory, prdev_size,
+ "pcx2up_print_page(device)");
+ if ( prdev == 0 )
+ return_error(gs_error_VMerror);
+ memcpy(prdev, prdev_template, prdev_size);
+ gx_device_fill_in_procs(rdev);
+ prdev->std_procs.open_device =
+ gs_pcx256_device.std_procs.open_device;
+ prdev->printer_procs.print_page =
+ gs_pcx256_device.printer_procs.print_page;
+ prdev->space_params.band =
+ pages[0].page->info.band_params; /* either one will do */
+ prdev->space_params.MaxBitmap = 0;
+ prdev->space_params.BufferSpace =
+ prdev->space_params.band.BandBufferSpace;
+ prdev->width = prdev->space_params.band.BandWidth;
+ prdev->OpenOutputFile = false;
+ code = (*dev_proc(rdev, open_device))(rdev);
+ if ( code < 0 )
+ return code;
+ rdev->is_open = true;
+ prdev->file = pdev->file;
+ /* Render the pages. */
+ code = gdev_prn_render_pages(prdev, pages, 2);
+ /* Clean up. */
+ if ( pdev->file != 0 )
+ prdev->file = 0; /* don't close it */
+ gs_closedevice(rdev);
+ pdev2->have_odd_page = false;
+ return code;
+#undef rdev
+ }
+}
diff --git a/gs/src/gdevpbm.c b/gs/src/gdevpbm.c
new file mode 100644
index 000000000..57ea90670
--- /dev/null
+++ b/gs/src/gdevpbm.c
@@ -0,0 +1,717 @@
+/* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpbm.c */
+/* Portable Bit/Gray/PixMap drivers */
+#include "gdevprn.h"
+#include "gscdefs.h"
+#include "gxlum.h"
+
+/* Thanks are due to Jos Vos (jos@bull.nl) for an earlier P*M driver, */
+/* on which this one is based. */
+
+/*
+ * There are 6 (pairs of) drivers here:
+ * pbm[raw] - outputs PBM (black and white).
+ * pgm[raw] - outputs PGM (gray-scale).
+ * pgnm[raw] - outputs PBM if the page contains only black and white,
+ * otherwise PGM.
+ * ppm[raw] - outputs PPM (RGB).
+ * pnm[raw] - outputs PBM if the page contains only black and white,
+ * otherwise PGM if the page contains only gray shades,
+ * otherwise PPM.
+ * pkm[raw] - computes internally in CMYK, outputs PPM (RGB).
+ */
+
+/*
+ * The code here is designed to work with variable depths for PGM and PPM.
+ * The code will work with any of the values in brackets, but the
+ * Ghostscript imager requires that depth be a power of 2 or be 24,
+ * so the actual allowed values are more limited.
+ * pgm,pgnm: 1, 2, 4, 8, 16. [1-16]
+ * pgmraw,pgnmraw: 1, 2, 4, 8. [1-8]
+ * ppm,pnm: 4(3x1), 8(3x2), 16(3x5), 24(3x8), 32(3x10). [3-32]
+ * ppmraw,pnmraw: 4(3x1), 8(3x2), 16(3x5), 24(3x8). [3-24]
+ * pkm, pkmraw: 4(4x1), 8(4x2), 16(4x4), 32(4x8). [4-32]
+ */
+
+/* Structure for P*M devices, which extend the generic printer device. */
+
+#define MAX_COMMENT 70 /* max user-supplied comment */
+struct gx_device_pbm_s {
+ gx_device_common;
+ gx_prn_device_common;
+ /* Additional state for P*M devices */
+ char magic; /* n for "Pn" */
+ char comment[MAX_COMMENT + 1]; /* comment for head of file */
+ byte is_raw; /* 1 if raw format, 0 if plain */
+ byte optimize; /* 1 if optimization OK, 0 if not */
+ byte uses_color; /* 0 if image is black and white, */
+ /* 1 if gray (PGM or PPM only), */
+ /* 2 or 3 if colored (PPM only) */
+ int alpha_text; /* # of alpha bits for text (1,2,4) */
+ int alpha_graphics; /* ditto for graphics (1,2,4) */
+ dev_proc_copy_alpha((*save_copy_alpha));
+};
+typedef struct gx_device_pbm_s gx_device_pbm;
+
+#define bdev ((gx_device_pbm *)pdev)
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+/* Macro for generating P*M device descriptors. */
+#define pbm_prn_device(procs, dev_name, magic, is_raw, num_comp, depth, max_gray, max_rgb, optimize, print_page)\
+{ prn_device_body(gx_device_pbm, procs, dev_name,\
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI,\
+ 0, 0, 0, 0,\
+ num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\
+ print_page),\
+ magic,\
+ { 0 },\
+ is_raw,\
+ optimize,\
+ 0, 1, 1, 0\
+}
+
+/* For all but PBM, we need our own color mapping and alpha procedures. */
+private dev_proc_map_rgb_color(pgm_map_rgb_color);
+private dev_proc_map_rgb_color(ppm_map_rgb_color);
+private dev_proc_map_color_rgb(pgm_map_color_rgb);
+private dev_proc_map_color_rgb(ppm_map_color_rgb);
+private dev_proc_map_cmyk_color(pkm_map_cmyk_color);
+private dev_proc_map_color_rgb(pkm_map_color_rgb);
+private dev_proc_put_params(ppm_put_params);
+private dev_proc_get_alpha_bits(ppm_get_alpha_bits);
+private dev_proc_copy_alpha(pnm_copy_alpha);
+
+/* We need to initialize uses_color when opening the device, */
+/* and after each showpage. */
+private dev_proc_open_device(ppm_open);
+private dev_proc_output_page(ppm_output_page);
+
+/* And of course we need our own print-page routines. */
+private dev_proc_print_page(pbm_print_page);
+private dev_proc_print_page(pgm_print_page);
+private dev_proc_print_page(ppm_print_page);
+private dev_proc_print_page(pkm_print_page);
+
+/* The device procedures */
+
+private gx_device_procs pbm_procs =
+ prn_procs(gdev_prn_open, ppm_output_page, gdev_prn_close);
+
+/* See gdevprn.h for the template for the following. */
+#define pgpm_procs(p_map_rgb_color, p_map_color_rgb, p_map_cmyk_color) {\
+ ppm_open, NULL, NULL, ppm_output_page, gdev_prn_close,\
+ p_map_rgb_color, p_map_color_rgb, NULL, NULL, NULL, NULL, NULL, NULL,\
+ gdev_prn_get_params, ppm_put_params,\
+ p_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device,\
+ ppm_get_alpha_bits\
+}
+
+private gx_device_procs pgm_procs =
+ pgpm_procs(pgm_map_rgb_color, pgm_map_color_rgb, NULL);
+private gx_device_procs ppm_procs =
+ pgpm_procs(ppm_map_rgb_color, ppm_map_color_rgb, NULL);
+private gx_device_procs pkm_procs =
+ pgpm_procs(NULL, pkm_map_color_rgb, pkm_map_cmyk_color);
+
+/* The device descriptors themselves */
+gx_device_pbm far_data gs_pbm_device =
+ pbm_prn_device(pbm_procs, "pbm", '1', 0, 1, 1, 1, 0, 0,
+ pbm_print_page);
+gx_device_pbm far_data gs_pbmraw_device =
+ pbm_prn_device(pbm_procs, "pbmraw", '4', 1, 1, 1, 1, 1, 0,
+ pbm_print_page);
+gx_device_pbm far_data gs_pgm_device =
+ pbm_prn_device(pgm_procs, "pgm", '2', 0, 1, 8, 255, 0, 0,
+ pgm_print_page);
+gx_device_pbm far_data gs_pgmraw_device =
+ pbm_prn_device(pgm_procs, "pgmraw", '5', 1, 1, 8, 255, 0, 0,
+ pgm_print_page);
+gx_device_pbm far_data gs_pgnm_device =
+ pbm_prn_device(pgm_procs, "pgnm", '2', 0, 1, 8, 255, 0, 1,
+ pgm_print_page);
+gx_device_pbm far_data gs_pgnmraw_device =
+ pbm_prn_device(pgm_procs, "pgnmraw", '5', 1, 1, 8, 255, 0, 1,
+ pgm_print_page);
+gx_device_pbm far_data gs_ppm_device =
+ pbm_prn_device(ppm_procs, "ppm", '3', 0, 3, 24, 255, 255, 0,
+ ppm_print_page);
+gx_device_pbm far_data gs_ppmraw_device =
+ pbm_prn_device(ppm_procs, "ppmraw", '6', 1, 3, 24, 255, 255, 0,
+ ppm_print_page);
+gx_device_pbm far_data gs_pnm_device =
+ pbm_prn_device(ppm_procs, "pnm", '3', 0, 3, 24, 255, 255, 1,
+ ppm_print_page);
+gx_device_pbm far_data gs_pnmraw_device =
+ pbm_prn_device(ppm_procs, "pnmraw", '6', 1, 3, 24, 255, 255, 1,
+ ppm_print_page);
+gx_device_pbm far_data gs_pkm_device =
+ pbm_prn_device(pkm_procs, "pkm", '3', 0, 4, 4, 1, 1, 0,
+ pkm_print_page);
+gx_device_pbm far_data gs_pkmraw_device =
+ pbm_prn_device(pkm_procs, "pkmraw", '6', 1, 4, 4, 1, 1, 0,
+ pkm_print_page);
+
+/* ------ Initialization ------ */
+
+/* Set the copy_alpha procedure if necessary. */
+private void
+ppm_set_copy_alpha(gx_device *pdev)
+{ if ( pdev->std_procs.copy_alpha != pnm_copy_alpha )
+ { bdev->save_copy_alpha = pdev->std_procs.copy_alpha;
+ if ( pdev->color_info.depth > 4 )
+ pdev->std_procs.copy_alpha = pnm_copy_alpha;
+ }
+}
+
+private int
+ppm_open(gx_device *pdev)
+{ int code = gdev_prn_open(pdev);
+
+ if ( code < 0 )
+ return code;
+ bdev->uses_color = 0;
+ ppm_set_copy_alpha(pdev);
+ return code;
+}
+
+/* Print a page, and reset uses_color if this is a showpage. */
+private int
+ppm_output_page(gx_device *pdev, int num_copies, int flush)
+{ int code = gdev_prn_output_page(pdev, num_copies, flush);
+
+ if ( code < 0 )
+ return code;
+ if ( flush )
+ bdev->uses_color = 0;
+ return code;
+}
+
+/* ------ Color mapping routines ------ */
+
+/* Map an RGB color to a PGM gray value. */
+/* Keep track of whether the image is black-and-white or gray. */
+private gx_color_index
+pgm_map_rgb_color(gx_device *pdev, ushort r, ushort g, ushort b)
+{ /* We round the value rather than truncating it. */
+ gx_color_value gray =
+ ((r * (ulong)lum_red_weight) +
+ (g * (ulong)lum_green_weight) +
+ (b * (ulong)lum_blue_weight) +
+ (lum_all_weights / 2)) / lum_all_weights
+ * pdev->color_info.max_gray / gx_max_color_value;
+ if ( !(gray == 0 || gray == pdev->color_info.max_gray) )
+ bdev->uses_color = 1;
+ return gray;
+}
+
+/* Map a PGM gray value back to an RGB color. */
+private int
+pgm_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
+{ gx_color_value gray =
+ color * gx_max_color_value / dev->color_info.max_gray;
+ prgb[0] = gray;
+ prgb[1] = gray;
+ prgb[2] = gray;
+ return 0;
+}
+
+/* Map an RGB color to a PPM color tuple. */
+/* Keep track of whether the image is black-and-white, gray, or colored. */
+private gx_color_index
+ppm_map_rgb_color(gx_device *pdev, ushort r, ushort g, ushort b)
+{ uint bitspercolor = pdev->color_info.depth / 3;
+ ulong max_value = pdev->color_info.max_color;
+ gx_color_value rc = r * max_value / gx_max_color_value;
+ gx_color_value gc = g * max_value / gx_max_color_value;
+ gx_color_value bc = b * max_value / gx_max_color_value;
+ if ( rc == gc && gc == bc ) /* black-and-white or gray */
+ { if ( !(rc == 0 || rc == max_value) )
+ bdev->uses_color |= 1; /* gray */
+ }
+ else /* color */
+ bdev->uses_color = 2;
+ return ((((ulong)rc << bitspercolor) + gc) << bitspercolor) + bc;
+}
+
+/* Map a PPM color tuple back to an RGB color. */
+private int
+ppm_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
+{ uint bitspercolor = dev->color_info.depth / 3;
+ uint colormask = (1 << bitspercolor) - 1;
+ uint max_rgb = dev->color_info.max_color;
+
+ prgb[0] = ((color >> (bitspercolor * 2)) & colormask) *
+ (ulong)gx_max_color_value / max_rgb;
+ prgb[1] = ((color >> bitspercolor) & colormask) *
+ (ulong)gx_max_color_value / max_rgb;
+ prgb[2] = (color & colormask) *
+ (ulong)gx_max_color_value / max_rgb;
+ return 0;
+}
+
+/* Map a CMYK color to a pixel value. */
+private gx_color_index
+pkm_map_cmyk_color(gx_device *pdev, ushort c, ushort m, ushort y, ushort k)
+{ uint bitspercolor = pdev->color_info.depth >> 2;
+ ulong max_value = pdev->color_info.max_color;
+ uint cc = c * max_value / gx_max_color_value;
+ uint mc = m * max_value / gx_max_color_value;
+ uint yc = y * max_value / gx_max_color_value;
+ uint kc = k * max_value / gx_max_color_value;
+ gx_color_index color =
+ ((((((ulong)cc << bitspercolor) + mc) << bitspercolor) + yc)
+ << bitspercolor) + kc;
+
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/* Map a CMYK pixel value to RGB. */
+private int
+pkm_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3])
+{ gx_color_index cshift = color;
+ int bpc = dev->color_info.depth >> 2;
+ uint mask = (1 << bpc) - 1;
+ uint max_value = dev->color_info.max_color;
+ uint c, m, y, k;
+
+ k = cshift & mask; cshift >>= bpc;
+ y = cshift & mask; cshift >>= bpc;
+ m = cshift & mask;
+ c = cshift >> bpc;
+#define cvalue(c)\
+ ((gx_color_value)((ulong)(c) * gx_max_color_value / max_value))
+ /* We use our improved conversion rule.... */
+ rgb[0] = cvalue((max_value - c) * (max_value - k) / max_value);
+ rgb[1] = cvalue((max_value - m) * (max_value - k) / max_value);
+ rgb[2] = cvalue((max_value - y) * (max_value - k) / max_value);
+#undef cvalue
+ return 0;
+}
+
+/* ------ Alpha capability ------ */
+
+/* Put parameters. */
+private int
+ppm_put_alpha_param(gs_param_list *plist, gs_param_name param_name, int *pa,
+ bool alpha_ok)
+{ int code = param_read_int(plist, param_name, pa);
+ switch ( code )
+ {
+ case 0:
+ switch ( *pa )
+ {
+ case 1:
+ return 0;
+ case 2: case 4:
+ if ( alpha_ok )
+ return 0;
+ default:
+ code = gs_error_rangecheck;
+ }
+ default:
+ param_signal_error(plist, param_name, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+private int
+ppm_put_params(gx_device *pdev, gs_param_list *plist)
+{ gx_device_color_info save_info;
+ int ncomps = pdev->color_info.num_components;
+ int bpc = pdev->color_info.depth / ncomps;
+ int ecode = 0;
+ int code;
+ int atext = bdev->alpha_text, agraphics = bdev->alpha_graphics;
+ bool alpha_ok;
+ long v;
+ const char _ds *vname;
+
+ save_info = pdev->color_info;
+ if ( (code = param_read_long(plist, (vname = "GrayValues"), &v)) != 1 ||
+ (code = param_read_long(plist, (vname = "RedValues"), &v)) != 1 ||
+ (code = param_read_long(plist, (vname = "GreenValues"), &v)) != 1 ||
+ (code = param_read_long(plist, (vname = "BlueValues"), &v)) != 1
+ )
+ { if ( code < 0 )
+ ecode = code;
+ else if ( v < 2 || v > (bdev->is_raw || ncomps > 1 ? 256 : 65536L) )
+ param_signal_error(plist, vname,
+ ecode = gs_error_rangecheck);
+ else if ( v == 2 )
+ bpc = 1;
+ else if ( v <= 4 )
+ bpc = 2;
+ else if ( v <= 16 )
+ bpc = 4;
+ else if ( v <= 32 && ncomps == 3 )
+ bpc = 5;
+ else if ( v <= 256 )
+ bpc = 8;
+ else
+ bpc = 16;
+ if ( ecode >= 0 )
+ { static const byte depths[4][16] = {
+ { 1, 2, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 16 },
+ { 0 },
+ { 4, 8, 0, 16, 16, 0, 0, 24 },
+ { 4, 8, 0, 16, 0, 0, 0, 24 },
+ };
+ pdev->color_info.depth = depths[ncomps - 1][bpc - 1];
+ pdev->color_info.max_gray = pdev->color_info.max_color =
+ (pdev->color_info.dither_grays =
+ pdev->color_info.dither_colors = (int)v) - 1;
+ }
+ }
+ alpha_ok = bpc >= 5;
+ if ( (code = ppm_put_alpha_param(plist, "TextAlphaBits", &bdev->alpha_text, alpha_ok)) < 0 )
+ ecode = code;
+ if ( (code = ppm_put_alpha_param(plist, "GraphicsAlphaBits", &bdev->alpha_graphics, alpha_ok)) < 0 )
+ ecode = code;
+ if ( (code = ecode) < 0 ||
+ (code = gdev_prn_put_params(pdev, plist)) < 0
+ )
+ { bdev->alpha_text = atext;
+ bdev->alpha_graphics = agraphics;
+ pdev->color_info = save_info;
+ }
+ ppm_set_copy_alpha(pdev);
+ return code;
+}
+
+/* Get the number of alpha bits. */
+private int
+ppm_get_alpha_bits(gx_device *pdev, graphics_object_type type)
+{ return (type == go_text ? bdev->alpha_text : bdev->alpha_graphics);
+}
+
+/* Copy an alpha map, noting whether we may generate some non-black/white */
+/* colors through blending. */
+private int
+pnm_copy_alpha(gx_device *pdev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ if ( pdev->color_info.depth < 24 ||
+ (color >> 8) == (color & 0xffff)
+ )
+ bdev->uses_color |= 1;
+ else
+ bdev->uses_color |= 2;
+ return (*bdev->save_copy_alpha)(pdev, data, data_x, raster, id,
+ x, y, width, height, color, depth);
+}
+
+/* ------ Internal routines ------ */
+
+/* Print a page using a given row printing routine. */
+private int
+pbm_print_page_loop(gx_device_printer *pdev, char magic, FILE *pstream,
+ int (*row_proc)(P4(gx_device_printer *, byte *, int, FILE *)))
+{ uint raster = gdev_prn_raster(pdev);
+ byte *data = (byte *)gs_malloc(raster, 1, "pbm_begin_page");
+ int lnum = 0;
+ int code = 0;
+ if ( data == 0 )
+ return_error(gs_error_VMerror);
+ fprintf(pstream, "P%c\n", magic);
+ if ( bdev->comment[0] )
+ fprintf(pstream, "# %s\n", bdev->comment);
+ else
+ fprintf(pstream, "# Image generated by %s (device=%s)\n",
+ gs_product, pdev->dname);
+ fprintf(pstream, "%d %d\n", pdev->width, pdev->height);
+ switch ( magic )
+ {
+ case '1': /* pbm */
+ case '4': /* pbmraw */
+ break;
+ default:
+ fprintf(pstream, "%d\n", pdev->color_info.max_gray);
+ }
+ for ( ; lnum < pdev->height; lnum++ )
+ { byte *row;
+ code = gdev_prn_get_bits(pdev, lnum, data, &row);
+ if ( code < 0 ) break;
+ code = (*row_proc)(pdev, row, pdev->color_info.depth, pstream);
+ if ( code < 0 ) break;
+ }
+ gs_free((char *)data, raster, 1, "pbm_print_page_loop");
+ return (code < 0 ? code : 0);
+}
+
+/* ------ Individual page printing routines ------ */
+
+/* Print a monobit page. */
+private int
+pbm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ if ( bdev->is_raw )
+ fwrite(data, 1, (pdev->width + 7) >> 3, pstream);
+ else
+ { byte *bp;
+ uint x, mask;
+ for ( bp = data, x = 0, mask = 0x80; x < pdev->width; )
+ { putc((*bp & mask ? '1' : '0'), pstream);
+ if ( ++x == pdev->width || !(x & 63) )
+ putc('\n', pstream);
+ if ( (mask >>= 1) == 0 )
+ bp++, mask = 0x80;
+ }
+ }
+ return 0;
+}
+private int
+pbm_print_page(gx_device_printer *pdev, FILE *pstream)
+{ return pbm_print_page_loop(pdev, bdev->magic, pstream, pbm_print_row);
+}
+
+/* Print a gray-mapped page. */
+private int
+pgm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ /* Note that bpp <= 8 for raw format, bpp <= 16 for plain. */
+ uint mask = (1 << depth) - 1;
+ byte *bp;
+ uint x;
+ int shift;
+ if ( bdev->is_raw && depth == 8 )
+ fwrite(data, 1, pdev->width, pstream);
+ else
+ for ( bp = data, x = 0, shift = 8 - depth; x < pdev->width; )
+ { uint pixel;
+ if ( shift < 0 ) /* bpp = 16 */
+ { pixel = ((uint)*bp << 8) + bp[1];
+ bp += 2;
+ }
+ else
+ { pixel = (*bp >> shift) & mask;
+ if ( (shift -= depth) < 0 )
+ bp++, shift += 8;
+ }
+ ++x;
+ if ( bdev->is_raw )
+ putc(pixel, pstream);
+ else
+ fprintf(pstream, "%d%c", pixel,
+ (x == pdev->width || !(x & 15) ? '\n' : ' '));
+ }
+ return 0;
+}
+private int
+pxm_pbm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ /* Compress a PGM or PPM row to a PBM row. */
+ /* This doesn't have to be very fast. */
+ /* Note that we have to invert the data as well. */
+ int delta = (depth + 7) >> 3;
+ byte *src = data + delta - 1; /* always big-endian */
+ byte *dest = data;
+ int x;
+ byte out_mask = 0x80;
+ byte out = 0;
+ if ( depth >= 8 )
+ { /* One or more bytes per source pixel. */
+ for ( x = 0; x < pdev->width; x++, src += delta )
+ { if ( !(*src & 1) )
+ out |= out_mask;
+ out_mask >>= 1;
+ if ( !out_mask )
+ out_mask = 0x80,
+ *dest++ = out,
+ out = 0;
+ }
+ }
+ else
+ { /* Multiple source pixels per byte. */
+ byte in_mask = 0x100 >> depth;
+ for ( x = 0; x < pdev->width; x++ )
+ { if ( !(*src & in_mask) )
+ out |= out_mask;
+ in_mask >>= depth;
+ if ( !in_mask )
+ in_mask = 0x100 >> depth,
+ src++;
+ out_mask >>= 1;
+ if ( !out_mask )
+ out_mask = 0x80,
+ *dest++ = out,
+ out = 0;
+ }
+ }
+ if ( out_mask != 0x80 )
+ *dest = out;
+ return pbm_print_row(pdev, data, 1, pstream);
+}
+private int
+pgm_print_page(gx_device_printer *pdev, FILE *pstream)
+{ return (bdev->uses_color == 0 && bdev->optimize ?
+ pbm_print_page_loop(pdev, bdev->magic - 1, pstream,
+ pxm_pbm_print_row) :
+ pbm_print_page_loop(pdev, bdev->magic, pstream,
+ pgm_print_row) );
+}
+
+/* Print a color-mapped page. */
+private int
+ppgm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream, bool color)
+{ /* If color=false, write only one value per pixel; */
+ /* if color=true, write 3 values per pixel. */
+ /* Note that depth <= 24 for raw format, depth <= 32 for plain. */
+ uint bpe = depth / 3; /* bits per r/g/b element */
+ uint mask = (1 << bpe) - 1;
+ byte *bp;
+ uint x;
+ uint eol_mask = (color ? 7 : 15);
+ int shift;
+ if ( bdev->is_raw && depth == 24 && color )
+ fwrite(data, 1, pdev->width * (depth / 8), pstream);
+ else
+ for ( bp = data, x = 0, shift = 8 - depth; x < pdev->width; )
+ { bits32 pixel = 0;
+ uint r, g, b;
+ switch ( depth >> 3 )
+ {
+ case 4:
+ pixel = (bits32)*bp << 24; bp++;
+ /* falls through */
+ case 3:
+ pixel += (bits32)*bp << 16; bp++;
+ /* falls through */
+ case 2:
+ pixel += (uint)*bp << 8; bp++;
+ /* falls through */
+ case 1:
+ pixel += *bp; bp++;
+ break;
+ case 0: /* bpp == 4, bpe == 1 */
+ pixel = *bp >> shift;
+ if ( (shift -= depth) < 0 )
+ bp++, shift += 8;
+ break;
+ }
+ ++x;
+ b = pixel & mask; pixel >>= bpe;
+ g = pixel & mask; pixel >>= bpe;
+ r = pixel & mask;
+ if ( bdev->is_raw )
+ { if ( color )
+ { putc(r, pstream);
+ putc(g, pstream);
+ }
+ putc(b, pstream);
+ }
+ else
+ { if ( color )
+ fprintf(pstream, "%d %d ", r, g);
+ fprintf(pstream, "%d%c", b,
+ (x == pdev->width || !(x & eol_mask) ?
+ '\n' : ' '));
+ }
+ }
+ return 0;
+}
+private int
+ppm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ return ppgm_print_row(pdev, data, depth, pstream, true);
+}
+private int
+ppm_pgm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ return ppgm_print_row(pdev, data, depth, pstream, false);
+}
+private int
+ppm_print_page(gx_device_printer *pdev, FILE *pstream)
+{ return (bdev->uses_color >= 2 || !bdev->optimize ?
+ pbm_print_page_loop(pdev, bdev->magic, pstream,
+ ppm_print_row) :
+ bdev->uses_color == 1 ?
+ pbm_print_page_loop(pdev, bdev->magic - 1, pstream,
+ ppm_pgm_print_row) :
+ pbm_print_page_loop(pdev, bdev->magic - 2, pstream,
+ pxm_pbm_print_row) );
+}
+
+/* Print a faux CMYK page. */
+private int
+pkm_print_row(gx_device_printer *pdev, byte *data, int depth,
+ FILE *pstream)
+{ byte *bp;
+ uint x;
+ int shift;
+ ulong max_value = pdev->color_info.max_color;
+ uint mask = (depth >= 8 ? 0xff : (1 << depth) - 1);
+
+ for ( bp = data, x = 0, shift = 8 - depth; x < pdev->width; )
+ { bits32 pixel = 0;
+ gx_color_value rgb[3];
+ uint r, g, b;
+
+ switch ( depth >> 3 )
+ {
+ case 4:
+ pixel = (bits32)*bp << 24; bp++;
+ /* falls through */
+ case 3:
+ pixel += (bits32)*bp << 16; bp++;
+ /* falls through */
+ case 2:
+ pixel += (uint)*bp << 8; bp++;
+ /* falls through */
+ case 1:
+ pixel += *bp; bp++;
+ break;
+ case 0: /* bpp == 4 */
+ pixel = (*bp >> shift) & mask;
+ if ( (shift -= depth) < 0 )
+ bp++, shift += 8;
+ break;
+ }
+ ++x;
+ pkm_map_color_rgb((gx_device *)pdev, pixel, rgb);
+ r = rgb[0] * max_value / gx_max_color_value;
+ g = rgb[1] * max_value / gx_max_color_value;
+ b = rgb[2] * max_value / gx_max_color_value;
+ if ( bdev->is_raw )
+ { putc(r, pstream);
+ putc(g, pstream);
+ putc(b, pstream);
+ }
+ else
+ { fprintf(pstream, "%d %d %d%c", r, g, b,
+ (x == pdev->width || !(x & 7) ?
+ '\n' : ' '));
+ }
+ }
+ return 0;
+}
+private int
+pkm_print_page(gx_device_printer *pdev, FILE *pstream)
+{ return pbm_print_page_loop(pdev, bdev->magic, pstream,
+ pkm_print_row);
+}
diff --git a/gs/src/gdevpccm.c b/gs/src/gdevpccm.c
new file mode 100644
index 000000000..bedeed78b
--- /dev/null
+++ b/gs/src/gdevpccm.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpccm.c */
+/* Support routines for PC color mapping */
+#include "gx.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gxdevice.h"
+#include "gdevpccm.h" /* interface */
+
+/* Color mapping routines for EGA/VGA-style color. */
+/* Colors are 4 bits: 8=intensity, 4=R, 2=G, 1=B. */
+
+/* Define the color spectrum */
+#define v_black 0
+#define v_blue 1
+#define v_green 2
+#define v_cyan 3
+#define v_red 4
+#define v_magenta 5
+#define v_brown 6
+#define v_white 7
+#define v_dgray 8 /* dark gray is not very usable */
+#define v_lblue 9
+#define v_lgreen 10
+#define v_lcyan 11
+#define v_lred 12
+#define v_lmagenta 13
+#define v_yellow 14
+#define v_bwhite 15
+
+/* ------ EGA/VGA (4-bit) color mapping ------ */
+
+gx_color_index
+pc_4bit_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+#define Nb gx_color_value_bits
+ static const byte grays[4] = { v_black, v_dgray, v_white, v_bwhite };
+#define tab3(v0,v1,v23) { v0, v1, v23, v23 }
+ static const byte g0r0[4] = tab3(v_black,v_blue,v_lblue);
+ static const byte g0r1[4] = tab3(v_red,v_magenta,v_lmagenta);
+ static const byte g0r2[4] = tab3(v_lred,v_lmagenta,v_lmagenta);
+ static const byte _ds *g0[4] = tab3(g0r0, g0r1, g0r2);
+ static const byte g1r0[4] = tab3(v_green,v_cyan,v_lcyan);
+ static const byte g1r1[4] = tab3(v_brown,v_white,v_lcyan);
+ static const byte g1r2[4] = tab3(v_yellow,v_lred,v_lmagenta);
+ static const byte _ds *g1[4] = tab3(g1r0, g1r1, g1r2);
+ static const byte g2r0[4] = tab3(v_lgreen,v_lgreen,v_lcyan);
+ static const byte g2r1[4] = tab3(v_lgreen,v_lgreen,v_lcyan);
+ static const byte g2r2[4] = tab3(v_yellow,v_yellow,v_bwhite);
+ static const byte _ds *g2[4] = tab3(g2r0, g2r1, g2r2);
+ static const byte _ds * _ds *ga[4] = tab3(g0, g1, g2);
+#undef tab3
+#define q4mask (-1 << (Nb - 2))
+ if ( !((r ^ g) & q4mask) && !((g ^ b) & q4mask) ) /* gray */
+#undef q4mask
+ return (gx_color_index)grays[r >> (Nb - 2)];
+ else
+#define q3cv(v) ((v - (v >> 2)) >> (Nb - 2))
+ return (gx_color_index)ga[q3cv(g)][q3cv(r)][q3cv(b)];
+#undef q3cv
+#undef Nb
+}
+int
+pc_4bit_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+#define icolor (int)color
+ gx_color_value one;
+ switch ( icolor )
+ {
+ case v_white: /* "dark white" */
+ prgb[0] = prgb[1] = prgb[2] =
+ gx_max_color_value - (gx_max_color_value / 3);
+ return 0;
+ case v_dgray:
+ prgb[0] = prgb[1] = prgb[2] = gx_max_color_value / 3;
+ return 0;
+ }
+ one = (icolor & 8 ? gx_max_color_value : gx_max_color_value / 2);
+ prgb[0] = (icolor & 4 ? one : 0);
+ prgb[1] = (icolor & 2 ? one : 0);
+ prgb[2] = (icolor & 1 ? one : 0);
+ return 0;
+#undef icolor
+}
+
+/* ------ SVGA 8-bit color mapping ------ */
+
+/*
+ * For 8-bit color, we use a fixed palette with approximately
+ * 3 bits of R, 3 bits of G, and 2 bits of B.
+ * We have to trade off even spacing of colors along each axis
+ * against the desire to have real gray shades;
+ * we compromise by using a 7x7x5 "cube" with extra gray shades
+ * (1/6, 1/3, 2/3, and 5/6), instead of the obvious 8x8x4.
+ */
+
+gx_color_index
+pc_8bit_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ uint rv = r / (gx_max_color_value / 7 + 1);
+ uint gv = g / (gx_max_color_value / 7 + 1);
+ return (gx_color_index)
+ (rv == gv && gv == b / (gx_max_color_value / 7 + 1) ?
+ rv + (256-7) :
+ (rv * 7 + gv) * 5 + b / (gx_max_color_value / 5 + 1));
+}
+int
+pc_8bit_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ static const gx_color_value ramp7[8] =
+ { 0,
+ gx_max_color_value / 6,
+ gx_max_color_value / 3,
+ gx_max_color_value / 2,
+ gx_max_color_value - (gx_max_color_value / 3),
+ gx_max_color_value - (gx_max_color_value / 6),
+ gx_max_color_value,
+ /* The 8th entry is not actually ever used, */
+ /* except to fill out the palette. */
+ gx_max_color_value
+ };
+ static const gx_color_value ramp5[5] =
+ { 0,
+ gx_max_color_value / 4,
+ gx_max_color_value / 2,
+ gx_max_color_value - (gx_max_color_value / 4),
+ gx_max_color_value
+ };
+#define icolor (uint)color
+ if ( icolor >= 256-7 )
+ { prgb[0] = prgb[1] = prgb[2] = ramp7[icolor - (256-7)];
+ }
+ else
+ { prgb[0] = ramp7[icolor / 35];
+ prgb[1] = ramp7[(icolor / 5) % 7];
+ prgb[2] = ramp5[icolor % 5];
+ }
+#undef icolor
+ return 0;
+}
+
+/* Write a palette on a file. */
+int
+pc_write_palette(gx_device *dev, uint max_index, FILE *file)
+{ uint i, c;
+ gx_color_value rgb[3];
+ for ( i = 0; i < max_index; i++ )
+ { (*dev_proc(dev, map_color_rgb))(dev, (gx_color_index)i, rgb);
+ for ( c = 0; c < 3; c++ )
+ { byte b = rgb[c] >> (gx_color_value_bits - 8);
+ fputc(b, file);
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gdevpccm.h b/gs/src/gdevpccm.h
new file mode 100644
index 000000000..5407c8871
--- /dev/null
+++ b/gs/src/gdevpccm.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpccm.h */
+/* Interface to PC color mapping utilities */
+/* Requires gxdevice.h */
+
+/* Color mapping routines for EGA/VGA-style color. */
+dev_proc_map_rgb_color(pc_4bit_map_rgb_color);
+dev_proc_map_color_rgb(pc_4bit_map_color_rgb);
+#define dci_pc_4bit { 3, 4, 3, 2, 4, 3 }
+
+/* Color mapping routines for 8-bit color (with a fixed palette). */
+dev_proc_map_rgb_color(pc_8bit_map_rgb_color);
+dev_proc_map_color_rgb(pc_8bit_map_color_rgb);
+#define dci_pc_8bit { 3, 8, 6, 6, 7, 7 }
+
+/* Write the palette on a file. */
+int pc_write_palette(P3(gx_device *, uint, FILE *));
diff --git a/gs/src/gdevpcfb.c b/gs/src/gdevpcfb.c
new file mode 100644
index 000000000..9d91983de
--- /dev/null
+++ b/gs/src/gdevpcfb.c
@@ -0,0 +1,900 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpcfb.c */
+/* IBM PC frame buffer (EGA/VGA) drivers */
+#include "memory_.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gdevpccm.h"
+#include "gdevpcfb.h"
+
+/* Macro for casting gx_device argument */
+#define fb_dev ((gx_device_ega *)dev)
+
+/* Procedure record */
+private dev_proc_map_rgb_color(ega0_map_rgb_color);
+private dev_proc_map_rgb_color(ega1_map_rgb_color);
+#define ega2_map_rgb_color pc_4bit_map_rgb_color
+private dev_proc_map_color_rgb(ega01_map_color_rgb);
+#define ega2_map_color_rgb pc_4bit_map_color_rgb
+#if ega_bits_of_color == 0
+# define ega_map_rgb_color ega0_map_rgb_color
+# define ega_map_color_rgb ega01_map_color_rgb
+#else
+# if ega_bits_of_color == 1
+# define ega_map_rgb_color ega1_map_rgb_color
+# define ega_map_color_rgb ega01_map_color_rgb
+# else
+# define ega_map_rgb_color ega2_map_rgb_color
+# define ega_map_color_rgb ega2_map_color_rgb
+# endif
+#endif
+#define ega_std_procs(get_params, put_params)\
+ ega_open,\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ NULL, /* output_page */\
+ ega_close,\
+ ega_map_rgb_color,\
+ ega_map_color_rgb,\
+ ega_fill_rectangle,\
+ ega_tile_rectangle,\
+ ega_copy_mono,\
+ ega_copy_color,\
+ NULL, /* draw_line */\
+ ega_get_bits,\
+ get_params,\
+ put_params,\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ gx_page_device_get_page_device
+
+private gx_device_procs ega_procs = {
+ ega_std_procs(NULL, NULL)
+};
+
+private dev_proc_get_params(svga16_get_params);
+private dev_proc_put_params(svga16_put_params);
+private gx_device_procs svga16_procs = {
+ ega_std_procs(svga16_get_params, svga16_put_params)
+};
+
+/* All the known instances */
+ /* EGA */
+gx_device_ega far_data gs_ega_device =
+ ega_device("ega", ega_procs, 80, 350, 48.0/35.0, 0x10);
+ /* VGA */
+gx_device_ega far_data gs_vga_device =
+ ega_device("vga", ega_procs, 80, 480, 1.0, 0x12);
+ /* Generic SuperVGA, 800x600, 16-color mode */
+gx_device_ega far_data gs_svga16_device =
+ ega_device("svga16", svga16_procs, 100, 600, 1.0, 0x29 /*Tseng*/);
+
+/* Save the BIOS state */
+private pcfb_bios_state pcfb_save_state = { -1 };
+
+/* Initialize the EGA for graphics mode */
+int
+ega_open(gx_device *dev)
+{ /* Adjust the device resolution. */
+ /* This is a hack, pending refactoring of the put_params machinery. */
+ switch ( fb_dev->video_mode )
+ {
+ case 0x10: /* EGA */
+ gx_device_adjust_resolution(dev, 640, 350, 1); break;
+ case 0x12: /* VGA */
+ gx_device_adjust_resolution(dev, 640, 480, 1); break;
+ default: /* 800x600 SuperVGA */
+ gx_device_adjust_resolution(dev, 800, 600, 1); break;
+ }
+ if ( pcfb_save_state.display_mode < 0 )
+ pcfb_get_state(&pcfb_save_state);
+ /* Do implementation-specific initialization */
+ pcfb_set_signals(dev);
+ pcfb_set_mode(fb_dev->video_mode);
+ set_s_map(-1); /* enable all maps */
+ return 0;
+}
+
+/* Reinitialize the EGA for text mode */
+int
+ega_close(gx_device *dev)
+{ if ( pcfb_save_state.display_mode >= 0 )
+ pcfb_set_state(&pcfb_save_state);
+ return 0;
+}
+
+/* Get/put the display mode parameter. */
+int
+svga16_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_default_get_params(dev, plist);
+ if ( code < 0 )
+ return code;
+ return param_write_int(plist, "DisplayMode", &fb_dev->video_mode);
+}
+int
+svga16_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ int imode = fb_dev->video_mode;
+ const char _ds *param_name;
+
+ switch ( code = param_read_int(plist, (param_name = "DisplayMode"), &imode) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gx_default_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ if ( imode != fb_dev->video_mode )
+ { if ( dev->is_open )
+ gs_closedevice(dev);
+ fb_dev->video_mode = imode;
+ }
+
+ return 0;
+}
+
+/* Map a r-g-b color to an EGA color code. */
+#define Nb gx_color_value_bits
+private gx_color_index
+ega0_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ return pc_4bit_map_rgb_color(dev, r, r, r);
+}
+private gx_color_index
+ega1_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+#define cvtop (gx_color_value)(1 << (Nb - 1))
+ return pc_4bit_map_rgb_color(dev, r & cvtop, g & cvtop, b & cvtop);
+}
+#undef Nb
+
+/* Map a color code to r-g-b. */
+#define icolor (int)color
+private int
+ega01_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+#define one (gx_max_color_value / 2 + 1)
+ prgb[0] = (icolor & 4 ? one : 0);
+ prgb[1] = (icolor & 2 ? one : 0);
+ prgb[2] = (icolor & 1 ? one : 0);
+ return 0;
+#undef one
+}
+#undef icolor
+
+/* ------ Internal routines ------ */
+
+/* Structure for operation parameters. */
+/* Note that this structure is known to assembly code. */
+/* Not all parameters are used for every operation. */
+typedef struct rop_params_s {
+ fb_ptr dest; /* pointer to frame buffer */
+ int draster; /* raster of frame buffer */
+ const byte *src; /* pointer to source data */
+ int sraster; /* source raster */
+ int width; /* width in bytes */
+ int height; /* height in scan lines */
+ int shift; /* amount to right shift source */
+ int invert; /* 0 or -1 to invert source */
+ int data; /* data for fill */
+} rop_params;
+typedef rop_params _ss *rop_ptr;
+
+/* Assembly language routines */
+
+#if USE_ASM
+void memsetcol(P1(rop_ptr)); /* dest, draster, height, data */
+#else
+#define memsetcol cmemsetcol
+private void
+cmemsetcol(rop_ptr rop)
+{ byte *addr = rop->dest;
+ int yc = rop->height;
+ byte data = rop->data;
+ int draster = rop->draster;
+ while ( yc-- )
+ { byte_discard(*addr);
+ *addr = data;
+ addr += draster;
+ }
+}
+#endif
+
+#if USE_ASM
+void memsetrect(P1(rop_ptr)); /* dest, draster, width, height, data */
+#else
+#define memsetrect cmemsetrect
+private void
+cmemsetrect(rop_ptr rop)
+{ int yc = rop->height;
+ int width = rop->width;
+ if ( yc <= 0 || width <= 0 ) return;
+ { byte *addr = rop->dest;
+ byte data = rop->data;
+ if ( width > 5 ) /* use memset */
+ { int skip = rop->draster;
+ do
+ { memset(addr, data, width);
+ addr += skip;
+ }
+ while ( --yc );
+ }
+ else /* avoid the fixed overhead */
+ { int skip = rop->draster - width;
+ do
+ { int cnt = width;
+ do { *addr++ = data; } while ( --cnt );
+ addr += skip;
+ }
+ while ( --yc );
+ }
+ }
+}
+#endif
+
+#if USE_ASM
+void memrwcol(P1(rop_ptr)); /* dest, draster, src, sraster, height, shift, invert */
+# define memrwcol0(rop) memrwcol(rop) /* same except shift = 0 */
+#else
+# define memrwcol cmemrwcol
+# define memrwcol0 cmemrwcol0
+private void
+cmemrwcol(rop_ptr rop)
+{ byte *dp = rop->dest;
+ const byte *sp = rop->src;
+ int yc = rop->height;
+ int shift = rop->shift;
+ byte invert = rop->invert;
+ int sraster = rop->sraster, draster = rop->draster;
+ while ( yc-- )
+ { byte_discard(*dp);
+ *dp = ((*sp >> shift) + (*sp << (8 - shift))) ^ invert;
+ dp += draster, sp += sraster;
+ }
+}
+private void
+cmemrwcol0(rop_ptr rop)
+{ byte *dp = rop->dest;
+ const byte *sp = rop->src;
+ int yc = rop->height;
+ byte invert = rop->invert;
+ int sraster = rop->sraster, draster = rop->draster;
+ if ( yc > 0 ) do
+ { byte_discard(*dp);
+ *dp = *sp ^ invert;
+ dp += draster, sp += sraster;
+ }
+ while ( --yc );
+}
+#endif
+
+#if USE_ASM
+void memrwcol2(P1(rop_ptr)); /* dest, draster, src, sraster, height, shift, invert */
+#else
+#define memrwcol2 cmemrwcol2
+private void
+cmemrwcol2(rop_ptr rop)
+{ byte *dp = rop->dest;
+ const byte *sp = rop->src;
+ int yc = rop->height;
+ int shift = rop->shift;
+ byte invert = rop->invert;
+ int sraster = rop->sraster, draster = rop->draster;
+ while ( yc-- )
+ { byte_discard(*dp);
+ *dp = ((sp[1] >> shift) + (*sp << (8 - shift))) ^ invert;
+ dp += draster, sp += sraster;
+ }
+}
+#endif
+
+/* Forward definitions */
+int ega_write_dot(P4(gx_device *, int, int, gx_color_index));
+private void near fill_rectangle(P4(rop_ptr, int, int, int));
+private void near fill_row_only(P4(byte *, int, int, int));
+
+/* Clean up after writing */
+#define dot_end()\
+ set_g_mask(0xff) /* all bits on */
+
+/* Write a dot using the EGA color codes. */
+/* This doesn't have to be efficient. */
+int
+ega_write_dot(gx_device *dev, int x, int y, gx_color_index color)
+{ byte data[4];
+ data[0] = (byte)color;
+ return ega_copy_color(dev, data, 1, 4, gx_no_bitmap_id, x, y, 1, 1);
+}
+
+/* Macro for testing bit-inclusion */
+#define bit_included_in(x,y) !((x)&~(y))
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+int
+ega_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
+{ rop_params params;
+#define czero (int)izero
+#define cone (int)ione
+ int dleft, count;
+ byte mask, rmask;
+ fb_ptr save_dest;
+ int other_color = -1;
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ params.dest = mk_fb_ptr(x, y);
+ params.draster = fb_dev->raster;
+ params.src = base + (sourcex >> 3);
+ params.sraster = raster;
+ params.height = h;
+ params.shift = (x - sourcex) & 7;
+ /* Analyze the 16 possible cases: each of izero and ione may be */
+ /* 0, 0xf, transparent, or some other color. */
+ switch ( czero )
+ {
+ case no_color:
+ switch ( cone )
+ {
+ default: /* (T, other) */
+ /* Must do 2 passes */
+ other_color = cone;
+ save_dest = params.dest;
+ /* falls through */
+ case 0: /* (T, 0) */
+ set_g_function(gf_AND);
+ params.invert = -1;
+ break;
+ case 0xf: /* (T, 0xf) */
+ set_g_function(gf_OR);
+ params.invert = 0;
+ break;
+ case no_color: /* (T, T) */
+ return 0; /* nothing to do */
+ }
+ break;
+ case 0:
+ params.invert = 0;
+ switch ( cone )
+ {
+ default: /* (0, other) */
+ set_g_const(0);
+ set_g_const_map(cone ^ 0xf);
+ /* falls through */
+ case 0xf: /* (0, 0xf) */
+ break;
+ case no_color: /* (0, T) */
+ set_g_function(gf_AND);
+ break;
+ }
+ break;
+ case 0xf:
+ params.invert = -1;
+ switch ( cone )
+ {
+ case 0: /* (0xf, 0) */
+ break;
+ default: /* (0xf, other) */
+ set_g_const(0xf);
+ set_g_const_map(cone);
+ break;
+ case no_color: /* (0xf, T) */
+ set_g_function(gf_OR);
+ /* falls through */
+ }
+ break;
+ default:
+ switch ( cone )
+ {
+ default: /* (other, not T) */
+ if ( bit_included_in(czero, cone) )
+ { set_g_const(czero);
+ set_g_const_map(czero ^ cone ^ 0xf);
+ params.invert = 0;
+ break;
+ }
+ else if ( bit_included_in(cone, czero) )
+ { set_g_const(cone);
+ set_g_const_map(cone ^ czero ^ 0xf);
+ params.invert = -1;
+ break;
+ }
+ /* No way around it, fill with one color first. */
+ save_dest = params.dest;
+ fill_rectangle((rop_ptr)&params, x & 7, w, cone);
+ params.dest = save_dest;
+ set_g_function(gf_XOR);
+ set_s_map(czero ^ cone);
+ other_color = -2; /* must reset s_map at end */
+ params.invert = -1;
+ break;
+ case no_color: /* (other, T) */
+ /* Must do 2 passes */
+ other_color = czero;
+ save_dest = params.dest;
+ set_g_function(gf_AND);
+ params.invert = 0;
+ break;
+ }
+ break;
+ }
+ /* Actually copy the bits. */
+ dleft = 8 - (x & 7);
+ mask = 0xff >> (8 - dleft);
+ count = w - dleft;
+ if ( count < 0 )
+ mask -= mask >> w,
+ rmask = 0;
+ else
+ rmask = 0xff00 >> (count & 7);
+ /* params: dest, src, sraster, height, shift, invert */
+ /* Smashes params.src, params.dest, count. */
+copy: set_g_mask(mask);
+ if ( params.shift == 0 ) /* optimize the aligned case */
+ { /* Do left column */
+ memrwcol0((rop_ptr)&params);
+ /* Do center */
+ if ( (count -= 8) >= 0 )
+ { out_g_mask(0xff);
+ do
+ { params.src++, params.dest++;
+ memrwcol0((rop_ptr)&params);
+ }
+ while ( (count -= 8) >= 0 );
+ }
+ /* Do right column */
+ if ( rmask )
+ { params.src++, params.dest++;
+ out_g_mask(rmask);
+ memrwcol0((rop_ptr)&params);
+ }
+ }
+ else
+ { /* Do left column */
+ int sleft = 8 - (sourcex & 7);
+ if ( sleft >= dleft )
+ { /* Source fits in one byte */
+ memrwcol((rop_ptr)&params);
+ }
+ else if ( w <= sleft )
+ { /* Source fits in one byte, thin case */
+ memrwcol((rop_ptr)&params);
+ goto fin;
+ }
+ else
+ { memrwcol2((rop_ptr)&params);
+ params.src++;
+ }
+ /* Do center */
+ if ( (count -= 8) >= 0 )
+ { out_g_mask(0xff);
+ do
+ { params.dest++;
+ memrwcol2((rop_ptr)&params);
+ params.src++;
+ }
+ while ( (count -= 8) >= 0 );
+ }
+ /* Do right column */
+ if ( rmask )
+ { out_g_mask(rmask);
+ params.dest++;
+ if ( count + 8 <= params.shift )
+ memrwcol((rop_ptr)&params);
+ else
+ memrwcol2((rop_ptr)&params);
+ }
+ }
+fin: if ( other_color != -1 )
+ { if ( other_color >= 0 )
+ { /* Do the second pass on (T, other) or (other, T). */
+ count = w - dleft;
+ params.src = base + (sourcex >> 3);
+ params.dest = save_dest;
+ params.invert ^= -1;
+ set_s_map(other_color);
+ set_g_function(gf_OR);
+ other_color = -2;
+ goto copy;
+ }
+ else
+ { /* Finished second pass, restore s_map */
+ set_s_map(-1);
+ }
+ }
+ set_g_function(gf_WRITE);
+ set_g_const_map(0);
+ dot_end();
+ return 0;
+#undef czero
+#undef cone
+}
+
+/* Copy a color pixelmap. This is just like a bitmap, */
+/* except that each pixel takes 4 bits instead of 1. */
+int
+ega_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ const byte *line = base + (sourcex >> 1);
+ unsigned mask = 0x80 >> (x & 7);
+ int px = sourcex & 1;
+ fb_ptr fb_line;
+ int fb_raster = fb_dev->raster;
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ fb_line = mk_fb_ptr(x, y);
+ set_g_mode(gm_FILL);
+ select_g_mask();
+ for ( ; ; px++ )
+ { const byte *bptr = line;
+ fb_ptr fbptr = fb_line;
+ int py = h;
+ out_g_mask(mask);
+ if ( px & 1 )
+ { do
+ { byte_discard(*fbptr); /* latch frame buffer data */
+ *fbptr = *bptr;
+ bptr += raster;
+ fbptr += fb_raster;
+ }
+ while ( --py );
+ line++;
+ }
+ else
+ { do
+ { byte_discard(*fbptr); /* latch frame buffer data */
+ *fbptr = *bptr >> 4;
+ bptr += raster;
+ fbptr += fb_raster;
+ }
+ while ( --py );
+ }
+ if ( !--w )
+ break;
+ if ( (mask >>= 1) == 0 )
+ mask = 0x80, fb_line++;
+ }
+ set_g_mode(gm_DATA);
+ dot_end();
+ return 0;
+}
+
+/* Fill a rectangle. */
+int
+ega_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ rop_params params;
+ fit_fill(dev, x, y, w, h);
+ params.dest = mk_fb_ptr(x, y);
+ if ( h == 1 )
+ fill_row_only(params.dest, x & 7, w, (int)color);
+ else
+ { params.draster = fb_dev->raster;
+ params.height = h;
+ fill_rectangle((rop_ptr)&params, x & 7, w, (int)color);
+ dot_end();
+ }
+ return 0;
+}
+
+/* Tile a rectangle. Note that the two colors must both be supplied, */
+/* i.e. neither one can be gx_no_color_index (transparent): */
+/* a transparent color means that the tile is colored, not a mask. */
+int
+ega_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
+ int px, int py)
+#define zero (int)czero
+#define one (int)cone
+{ rop_params params;
+ int xmod, width_bytes;
+ int tile_height = tile->size.y;
+ int xbit;
+ int lcount;
+ int mask, rmask;
+ byte narrow;
+ byte again;
+ int const_bits, maps;
+ int ymod, yleft;
+ fit_fill(dev, x, y, w, h);
+ /* We only handle the easiest cases directly. */
+ if ( (tile->size.x & 7) || one == -1 || zero == -1 || px || py )
+ return gx_default_tile_rectangle(dev, tile, x, y, w, h,
+ czero, cone, px, py);
+ /* Following is similar to aligned case of copy_mono */
+ params.dest = mk_fb_ptr(x, y);
+ params.draster = fb_dev->raster;
+ params.sraster = tile->raster;
+ params.shift = 0;
+ xbit = x & 7;
+ /* Set up the graphics registers */
+ const_bits = (zero ^ one) ^ 0xf;
+ if ( const_bits )
+ { set_g_const(zero); /* either color will do */
+ set_g_const_map(const_bits);
+ }
+ if ( (maps = zero & ~one) != 0 )
+ { set_s_map(maps += const_bits);
+ params.invert = -1;
+ again = one & ~zero;
+ }
+ else
+ { maps = one & ~zero;
+ set_s_map(maps += const_bits);
+ params.invert = 0;
+ again = 0;
+ }
+ xmod = (x % tile->size.x) >> 3;
+ width_bytes = tile->size.x >> 3;
+ mask = 0xff >> xbit;
+ if ( w + xbit <= 8 )
+ mask -= mask >> w,
+ rmask = 0,
+ narrow = 1;
+ else
+ { rmask = (0xff00 >> ((w + x) & 7)) & 0xff;
+ if ( xbit ) w += xbit - 8;
+ else mask = 0, --xmod, --params.dest;
+ narrow = 0;
+ }
+ ymod = y % tile_height;
+tile: yleft = tile_height - ymod;
+ params.src = tile->data + ymod * params.sraster + xmod;
+ lcount = h;
+ if ( narrow ) /* Optimize narrow case */
+ { set_g_mask(mask);
+ if ( lcount > yleft )
+ { params.height = yleft;
+ memrwcol0((rop_ptr)&params);
+ params.dest += yleft * params.draster;
+ params.src = tile->data + xmod;
+ params.height = tile_height;
+ lcount -= yleft;
+ while ( lcount >= tile_height )
+ { memrwcol0((rop_ptr)&params);
+ params.dest += tile_height * params.draster;
+ lcount -= tile_height;
+ }
+ }
+ if ( lcount )
+ { params.height = lcount;
+ memrwcol0((rop_ptr)&params);
+ }
+ }
+ else
+ { fb_ptr line = params.dest;
+ int xpos = width_bytes - xmod;
+ while ( 1 )
+ { int xleft = xpos;
+ int count = w;
+ params.height = (lcount > yleft ? yleft : lcount);
+ /* Do first byte, if not a full byte. */
+ if ( mask )
+ { set_g_mask(mask);
+ memrwcol0((rop_ptr)&params);
+ }
+ /* Do full bytes */
+ if ( (count -= 8) >= 0 )
+ { set_g_mask(0xff);
+ do
+ { if ( !--xleft )
+ xleft = width_bytes,
+ params.src -= width_bytes;
+ ++params.src, ++params.dest;
+ memrwcol0((rop_ptr)&params);
+ }
+ while ( (count -= 8) >= 0 );
+ }
+ /* Do last byte */
+ if ( rmask )
+ { if ( !--xleft )
+ xleft = width_bytes,
+ params.src -= width_bytes;
+ set_g_mask(rmask);
+ ++params.src, ++params.dest;
+ memrwcol0((rop_ptr)&params);
+ }
+ if ( (lcount -= params.height) == 0 ) break;
+ params.dest = line += params.height * params.draster;
+ params.src = tile->data + xmod;
+ yleft = tile_height;
+ }
+ }
+ /* Now do the second color if needed */
+ if ( again )
+ { maps = again + const_bits;
+ set_s_map(maps);
+ again = 0;
+ params.dest = mk_fb_ptr(x, y);
+ if ( mask == 0 ) params.dest--;
+ params.invert = 0;
+ goto tile;
+ }
+ if ( maps != 0xf )
+ set_s_map(-1);
+ if ( const_bits )
+ set_g_const_map(0);
+ dot_end();
+ return 0;
+}
+
+/* Read scan lines back from the frame buffer. */
+int
+ega_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ /* The maximum width for an EGA/VGA device is 800 pixels.... */
+ int width_bytes = (dev->width + 7) >> 3;
+ int i;
+ bits32 *dest;
+ const byte *src;
+ const byte *end;
+ byte planes[100*4];
+ /* Plane 0 is the least significant plane. */
+ /* We know we're on a little-endian machine.... */
+#define spread4(v)\
+ v+0x00000000, v+0x08000000, v+0x80000000, v+0x88000000,\
+ v+0x00080000, v+0x08080000, v+0x80080000, v+0x88080000,\
+ v+0x00800000, v+0x08800000, v+0x80800000, v+0x88800000,\
+ v+0x00880000, v+0x08880000, v+0x80880000, v+0x88880000
+ static const bits32 far_data spread8[256] =
+ { spread4(0x0000), spread4(0x0800),
+ spread4(0x8000), spread4(0x8800),
+ spread4(0x0008), spread4(0x0808),
+ spread4(0x8008), spread4(0x8808),
+ spread4(0x0080), spread4(0x0880),
+ spread4(0x8080), spread4(0x8880),
+ spread4(0x0088), spread4(0x0888),
+ spread4(0x8088), spread4(0x8888)
+ };
+
+ if ( y < 0 || y >= dev->height || dev->width > 800 )
+ return_error(gs_error_rangecheck);
+ /* Read 4 planes into the holding buffer. */
+ for ( i = 0; i < 4; ++i )
+ { set_g_read_plane(i);
+ memcpy(planes + 100 * i, mk_fb_ptr(0, y), width_bytes);
+ }
+ /* Now assemble the final data from the planes. */
+ for ( dest = (bits32 *)data, src = planes, end = src + width_bytes;
+ src < end; ++dest, ++src
+ )
+ *dest = (((((spread8[src[0]] >> 1) | spread8[src[100]]) >> 1) |
+ spread8[src[200]]) >> 1) | spread8[src[300]];
+ if ( actual_data != 0 )
+ *actual_data = data;
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Mask table for rectangle fill. */
+static const byte rmask_tab[9] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+ };
+
+/* Fill a rectangle specified by pointer into frame buffer, */
+/* starting bit within byte, width, and height. */
+/* Smashes rop->dest. */
+private void near
+fill_rectangle(register rop_ptr rop, int bit, int w, int color)
+ /* rop: dest, draster, height */
+{ set_g_const(color);
+ set_g_const_map(0xf);
+ select_g_mask();
+ if ( bit + w <= 8 )
+ { /* Less than one byte */
+ out_g_mask(rmask_tab[w] >> bit);
+ memsetcol(rop);
+ }
+ else
+ { byte right_mask;
+ if ( bit )
+ { out_g_mask(0xff >> bit);
+ memsetcol(rop);
+ rop->dest++;
+ w += bit - 8;
+ }
+ if ( w >= 8 )
+ { out_g_mask(0xff); /* all bits */
+ rop->width = w >> 3;
+ memsetrect(rop);
+ rop->dest += rop->width;
+ w &= 7;
+ }
+ if ( (right_mask = rmask_tab[w]) != 0 )
+ { out_g_mask(right_mask);
+ memsetcol(rop);
+ }
+ }
+ set_g_const_map(0);
+}
+
+/* Fill a single row specified by pointer into frame buffer, */
+/* starting bit within byte, and width; clean up afterwards. */
+#define r_m_w(ptr) (*(ptr))++ /* read & write, data irrelevant */
+private void near
+fill_row_only(byte *dest, int bit, int w, int color)
+ /* rop: dest */
+{ if ( bit + w <= 8 )
+ { /* Less than one byte. */
+ /* Optimize filling with black or white. */
+ switch ( color )
+ {
+ case 0:
+ set_g_mask(rmask_tab[w] >> bit);
+ *dest &= color; /* read, then write 0s; */
+ /* some compilers optimize &= 0 to a store. */
+ out_g_mask(0xff); /* dot_end */
+ break;
+ case 0xf:
+ set_g_mask(rmask_tab[w] >> bit);
+ *dest |= 0xff; /* read, then write 1s; */
+ /* some compilers optimize &= 0 to a store. */
+ out_g_mask(0xff); /* dot_end */
+ break;
+ default:
+ set_g_const(color);
+ set_g_const_map(0xf);
+ set_g_mask(rmask_tab[w] >> bit);
+ r_m_w(dest);
+ out_g_mask(0xff); /* dot_end */
+ set_g_const_map(0);
+ }
+ }
+ else
+ { byte right_mask;
+ int byte_count;
+ set_g_const(color);
+ set_g_const_map(0xf);
+ select_g_mask();
+ if ( bit )
+ { out_g_mask(0xff >> bit);
+ r_m_w(dest);
+ dest++;
+ w += bit - 8;
+ }
+ byte_count = w >> 3;
+ if ( (right_mask = rmask_tab[w & 7]) != 0 )
+ { out_g_mask(right_mask);
+ r_m_w(dest + byte_count);
+ }
+ out_g_mask(0xff);
+ if ( byte_count )
+ { memset(dest, 0, byte_count); /* data irrelevant */
+ }
+ set_g_const_map(0);
+ }
+}
diff --git a/gs/src/gdevpcfb.h b/gs/src/gdevpcfb.h
new file mode 100644
index 000000000..d4c80dd09
--- /dev/null
+++ b/gs/src/gdevpcfb.h
@@ -0,0 +1,191 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpcfb.h */
+/* IBM PC frame buffer definitions */
+#ifdef __MSDOS__
+# include "dos_.h"
+typedef union REGS registers;
+#endif
+
+/* For testing, the 16-color display may be defined as a monochrome, */
+/* 8-color, or 16-color device. */
+#define ega_bits_of_color 2 /* 0, 1, or 2 */
+#define rgb_max ega_bits_of_color
+
+/* Define the short (integer) version of "transparent" color. */
+/* ****** Depends on gx_no_color_index being all 1's. ******/
+#define no_color ((int)gx_no_color_index)
+
+/* Procedures */
+
+ /* See gxdevice.h for the definitions of the procedures. */
+
+dev_proc_open_device(ega_open);
+dev_proc_close_device(ega_close);
+dev_proc_fill_rectangle(ega_fill_rectangle);
+dev_proc_tile_rectangle(ega_tile_rectangle);
+dev_proc_copy_mono(ega_copy_mono);
+dev_proc_copy_color(ega_copy_color);
+dev_proc_get_bits(ega_get_bits);
+
+/* Structure for saving state of BIOS variables. */
+typedef struct pcfb_bios_state_s {
+ int display_mode; /* must be first, see pcfb_save_state */
+ /* in gdevpcfb.c */
+ byte text_page;
+ uint text_cursor_mode;
+ uint text_font;
+ byte text_attribute;
+ byte border_color;
+} pcfb_bios_state;
+
+/* Procedures used by gdevpcfb.c */
+void pcfb_set_signals(P1(gx_device *));
+void pcfb_get_state(P1(pcfb_bios_state *));
+void pcfb_set_mode(P1(int));
+void pcfb_set_state(P1(const pcfb_bios_state *));
+
+/* Types for frame buffer pointers. */
+typedef byte *fb_ptr;
+typedef volatile byte *volatile_fb_ptr;
+
+/* Define the nominal page height in inches. */
+#ifdef A4
+# define PAGE_HEIGHT_INCHES 11.69
+#else
+# define PAGE_HEIGHT_INCHES 11.0
+#endif
+
+/* The device descriptor */
+typedef struct gx_device_ega_s gx_device_ega;
+struct gx_device_ega_s {
+ gx_device_common;
+ int raster; /* frame buffer bytes per line */
+ int fb_seg_mult; /* multiplier for segment part */
+ /* of frame buffer pointer */
+ int fb_byte_mult; /* multiplier for word part ditto */
+#define mk_fb_ptr(x, y)\
+ (fb_dev->fb_byte_mult == 0 ?\
+ (fb_ptr)MK_PTR(regen + (y) * (fb_dev->fb_seg_mult), (x) >> 3) :\
+ (fb_ptr)MK_PTR(regen + ((y) >> 4) * (fb_dev->fb_seg_mult),\
+ (((y) & 15) * fb_dev->fb_byte_mult) + ((x) >> 3)))
+ int video_mode;
+};
+
+/* Macro for creating instances */
+/* The initial parameters map an appropriate fraction of */
+/* the screen to a full-page coordinate space. */
+/* This may or may not be what is desired! */
+#define ega_device(dev_name, procs, fb_raster, screen_height, aspect_ratio, video_mode)\
+ { std_device_dci_body(gx_device_ega, &procs, dev_name,\
+ fb_raster * 8, screen_height,\
+ (screen_height * (aspect_ratio)) / PAGE_HEIGHT_INCHES, /* x dpi */\
+ screen_height / PAGE_HEIGHT_INCHES, /* y dpi */\
+ (rgb_max ? 3 : 1), /* num_components */\
+ 4, /* depth */\
+ (rgb_max ? rgb_max : 1), /* max_gray */\
+ rgb_max,\
+ (rgb_max ? rgb_max + 1 : 2), /* dither_grays */\
+ (rgb_max ? rgb_max + 1 : 0) /* dither_colors */\
+ ),\
+ { 0 }, /* std_procs */\
+ fb_raster,\
+ (fb_raster & 15 ? fb_raster : fb_raster >> 4),\
+ (fb_raster & 15 ? fb_raster : 0),\
+ video_mode\
+ }
+
+/* Define the device port and register numbers, and the regen map base */
+#define seq_addr 0x3c4
+#define s_map 2
+#define set_s_map(mask) outport2(seq_addr, s_map, mask)
+#define graph_addr 0x3ce
+#define g_const 0 /* set/reset */
+#define set_g_const(color) outport2(graph_addr, g_const, color)
+#define g_const_map 1 /* enable set/reset */
+#define set_g_const_map(map) outport2(graph_addr, g_const_map, map)
+#define g_function 3
+# define gf_WRITE 0
+# define gf_AND 8
+# define gf_OR 0x10
+# define gf_XOR 0x18
+#define set_g_function(func) outport2(graph_addr, g_function, func)
+#define g_read_plane 4
+#define set_g_read_plane(plane) outport2(graph_addr, g_read_plane, plane)
+#define g_mode 5
+# define gm_DATA 0
+# define gm_FILL 2
+#define set_g_mode(mode) outport2(graph_addr, g_mode, mode)
+#define g_mask 8
+#define set_g_mask(mask) outport2(graph_addr, g_mask, mask)
+#define select_g_mask() outportb(graph_addr, g_mask)
+#define out_g_mask(mask) outportb(graph_addr+1, mask)
+#define regen 0xa000
+
+/* Define access to the frame buffer and the video registers */
+/* according to whether we are on a DOS system or a Unix system. */
+
+#if defined(M_UNIX) || defined(M_XENIX) || defined(UNIX) || defined(SYSV) || defined(__linux__)
+
+ /* SCO Unix/Xenix, AT&T SVR4, or Linux. */
+
+#undef outportb
+
+#if defined(__GNUC__)
+ /* Inline assembly version for gcc */
+ /* Under SCO, requires installing the gnu assembler as "as" */
+static inline void outportb(int port, int data)
+{
+ __asm__ volatile ("outb %0,%1" : :
+ "a" ((unsigned char) data),
+ "d" ((unsigned short) port));
+}
+static inline void outport2(int port, int index, int data)
+{
+ __asm__ volatile ("movb %0,%%ah; movb %1,%%al; outw %%ax,%2" : :
+ "qmi" ((unsigned char) data),
+ "qmi" ((unsigned char) index),
+ "d" ((unsigned short) port) :
+ "eax");
+}
+#else
+void outportb(P2(uint, byte));
+void outport2(P3(uint, byte, byte));
+#endif
+
+/* Redefine mk_fb_ptr -- no segmented addressing. */
+
+#undef mk_fb_ptr
+extern fb_ptr fb_addr;
+#define mk_fb_ptr(x, y) (fb_addr + (y) * (fb_dev->raster) + ((x) >> 3))
+
+#else
+
+ /* MS-DOS */
+
+/* outportb is defined in dos_.h */
+#define outport2(port, index, data)\
+ (outportb(port, index), outportb((port)+1, data))
+
+#endif
+
+/* Fetch and discard a byte. Prevent the compiler from */
+/* optimizing this away. */
+static unsigned char byte_discard_;
+#define byte_discard(expr) byte_discard_ = (expr)
diff --git a/gs/src/gdevpcl.c b/gs/src/gdevpcl.c
new file mode 100644
index 000000000..06ca4b7e5
--- /dev/null
+++ b/gs/src/gdevpcl.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpcl.c */
+/* Utilities for PCL printers */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+
+/* ------ Get paper size ------ */
+
+/* Get the paper size code, based on width and height. */
+int
+gdev_pcl_paper_size(gx_device *dev)
+{ float height_inches = dev->height / dev->y_pixels_per_inch;
+ return
+ (height_inches >= 44.4 ? PAPER_SIZE_A0 :
+ height_inches >= 32.0 ? PAPER_SIZE_A1 :
+ height_inches >= 22.2 ? PAPER_SIZE_A2 :
+ height_inches >= 15.9 ? PAPER_SIZE_A3 :
+ height_inches >= 11.8 ? PAPER_SIZE_LEGAL :
+ height_inches >= 11.1 ? PAPER_SIZE_A4 :
+ PAPER_SIZE_LETTER);
+}
+
+/* ------ Color mapping ------ */
+
+/* The PaintJet and DeskJet 500C use additive colors in separate planes. */
+/* We only keep one bit of color, with 1 = R, 2 = G, 4 = B. */
+/* Because the buffering routines assume 0 = white, */
+/* we complement all the color components. */
+#define cv_shift (sizeof(gx_color_value) * 8 - 1)
+
+/* Map an RGB color to a printer color. */
+gx_color_index
+gdev_pcl_3bit_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ return (((b >> cv_shift) << 2) + ((g >> cv_shift) << 1) + (r >> cv_shift)) ^ 7;
+}
+
+/* Map the printer color back to RGB. */
+int
+gdev_pcl_3bit_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ ushort cc = (ushort)color ^ 7;
+ prgb[0] = -(cc & 1);
+ prgb[1] = -((cc >> 1) & 1);
+ prgb[2] = -(cc >> 2);
+ return 0;
+}
+
+/* ------ Compression ------ */
+
+/*
+ * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
+ * Compresses data from row up to end_row, storing the result
+ * starting at compressed. Returns the number of bytes stored.
+ * Runs of K<=127 literal bytes are encoded as K-1 followed by
+ * the bytes; runs of 2<=K<=127 identical bytes are encoded as
+ * 257-K followed by the byte.
+ * In the worst case, the result is N+(N/127)+1 bytes long,
+ * where N is the original byte count (end_row - row).
+ * To speed up the search, we examine an entire word at a time.
+ * We will miss a few blocks of identical bytes; tant pis.
+ */
+int
+gdev_pcl_mode2compress(const word *row, const word *end_row, byte *compressed)
+{ register const word *exam = row; /* word being examined in the row to compress */
+ register byte *cptr = compressed; /* output pointer into compressed bytes */
+
+ while ( exam < end_row )
+ { /* Search ahead in the input looking for a run */
+ /* of at least 4 identical bytes. */
+ const byte *compr = (const byte *)exam;
+ const byte *end_dis;
+ const word *next;
+ register word test = *exam;
+ while ( ((test << 8) ^ test) > 0xff )
+ { if ( ++exam >= end_row )
+ break;
+ test = *exam;
+ }
+
+ /* Find out how long the run is */
+ end_dis = (const byte *)exam;
+ if ( exam == end_row ) /* no run */
+ { /* See if any of the last 3 "dissimilar" bytes are 0. */
+ if ( end_dis > compr && end_dis[-1] == 0 )
+ { if ( end_dis[-2] != 0 ) end_dis--;
+ else if ( end_dis[-3] != 0 ) end_dis -= 2;
+ else end_dis -= 3;
+ }
+ next = --end_row;
+ }
+ else
+ { next = exam + 1;
+ while ( next < end_row && *next == test )
+ next++;
+ /* See if any of the last 3 "dissimilar" bytes */
+ /* are the same as the repeated byte. */
+ if ( end_dis > compr && end_dis[-1] == (byte)test )
+ { if ( end_dis[-2] != (byte)test ) end_dis--;
+ else if ( end_dis[-3] != (byte)test ) end_dis -= 2;
+ else end_dis -= 3;
+ }
+ }
+
+ /* Now [compr..end_dis) should be encoded as dissimilar, */
+ /* and [end_dis..next) should be encoded as similar. */
+ /* Note that either of these ranges may be empty. */
+
+ for ( ; ; )
+ { /* Encode up to 127 dissimilar bytes */
+ uint count = end_dis - compr; /* uint for faster switch */
+ switch ( count )
+ { /* Use memcpy only if it's worthwhile. */
+ case 6: cptr[6] = compr[5];
+ case 5: cptr[5] = compr[4];
+ case 4: cptr[4] = compr[3];
+ case 3: cptr[3] = compr[2];
+ case 2: cptr[2] = compr[1];
+ case 1: cptr[1] = compr[0];
+ *cptr = count - 1;
+ cptr += count + 1;
+ case 0: /* all done */
+ break;
+ default:
+ if ( count > 127 ) count = 127;
+ *cptr++ = count - 1;
+ memcpy(cptr, compr, count);
+ cptr += count, compr += count;
+ continue;
+ }
+ break;
+ }
+
+ { /* Encode up to 127 similar bytes. */
+ /* Note that count may be <0 at end of row. */
+ int count = (const byte *)next - end_dis;
+ while ( count > 0 )
+ { int this = (count > 127 ? 127 : count);
+ *cptr++ = 257 - this;
+ *cptr++ = (byte)test;
+ count -= this;
+ }
+ exam = next;
+ }
+ }
+ return (cptr - compressed);
+}
+
+/*
+ * Mode 3 compression routine for the HP LaserJet III family.
+ * Compresses bytecount bytes starting at current, storing the result
+ * in compressed, comparing against and updating previous.
+ * Returns the number of bytes stored. In the worst case,
+ * the number of bytes is bytecount+(bytecount/8)+1.
+ */
+int
+gdev_pcl_mode3compress(int bytecount, const byte *current, byte *previous, byte *compressed)
+{ register const byte *cur = current;
+ register byte *prev = previous;
+ register byte *out = compressed;
+ const byte *end = current + bytecount;
+ while ( cur < end )
+ { /* Detect a maximum run of unchanged bytes. */
+ const byte *run = cur;
+ register const byte *diff;
+ const byte *stop;
+ int offset, cbyte;
+ while ( cur < end && *cur == *prev )
+ { cur++, prev++;
+ }
+ if ( cur == end ) break; /* rest of row is unchanged */
+ /* Detect a run of up to 8 changed bytes. */
+ /* We know that *cur != *prev. */
+ diff = cur;
+ stop = (end - cur > 8 ? cur + 8 : end);
+ do
+ { *prev++ = *cur++;
+ }
+ while ( cur < stop && *cur != *prev );
+ /* Now [run..diff) are unchanged, and */
+ /* [diff..cur) are changed. */
+ /* Generate the command byte(s). */
+ offset = diff - run;
+ cbyte = (cur - diff - 1) << 5;
+ if ( offset < 31 )
+ *out++ = cbyte + offset;
+ else
+ { *out++ = cbyte + 31;
+ offset -= 31;
+ while ( offset >= 255 )
+ *out++ = 255, offset -= 255;
+ *out++ = offset;
+ }
+ /* Copy the changed data. */
+ while ( diff < cur )
+ *out++ = *diff++;
+ }
+ return out - compressed;
+}
diff --git a/gs/src/gdevpcl.h b/gs/src/gdevpcl.h
new file mode 100644
index 000000000..463ac3e92
--- /dev/null
+++ b/gs/src/gdevpcl.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpcl.h */
+/* Interface to PCL utilities for printer drivers */
+/* Requires gdevprn.h */
+
+/* Define the PCL paper size codes. */
+#define PAPER_SIZE_LETTER 2
+#define PAPER_SIZE_LEGAL 3
+#define PAPER_SIZE_A4 26
+#define PAPER_SIZE_A3 27
+#define PAPER_SIZE_A2 28
+#define PAPER_SIZE_A1 29
+#define PAPER_SIZE_A0 30
+
+/* Get the paper size code, based on width and height. */
+int gdev_pcl_paper_size(P1(gx_device *));
+
+/* Color mapping procedures for 3-bit-per-pixel RGB printers */
+dev_proc_map_rgb_color(gdev_pcl_3bit_map_rgb_color);
+dev_proc_map_color_rgb(gdev_pcl_3bit_map_color_rgb);
+
+/* Row compression routines */
+typedef ulong word;
+int gdev_pcl_mode2compress(P3(const word *row, const word *end_row, byte *compressed)),
+ gdev_pcl_mode3compress(P4(int bytecount, const byte *current, byte *previous, byte *compressed));
diff --git a/gs/src/gdevpcx.c b/gs/src/gdevpcx.c
new file mode 100644
index 000000000..ac175e85a
--- /dev/null
+++ b/gs/src/gdevpcx.c
@@ -0,0 +1,461 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpcx.c */
+/* PCX file format drivers */
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "gxlum.h"
+
+/* Thanks to Phil Conrad for donating the original version */
+/* of these drivers to Aladdin Enterprises. */
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+/* Monochrome. */
+
+private dev_proc_print_page(pcxmono_print_page);
+
+/* Use the default RGB->color map, so we get black=0, white=1. */
+private const gx_device_procs pcxmono_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_map_rgb_color, gx_default_map_color_rgb);
+gx_device_printer far_data gs_pcxmono_device =
+ prn_device(pcxmono_procs, "pcxmono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, pcxmono_print_page);
+
+/* Chunky 8-bit gray scale. */
+
+private dev_proc_print_page(pcx256_print_page);
+
+private const gx_device_procs pcxgray_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
+gx_device_printer far_data gs_pcxgray_device =
+{ prn_device_body(gx_device_printer, pcxgray_procs, "pcxgray",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1,8,255,0,256,0, pcx256_print_page)
+};
+
+/* 4-bit planar (EGA/VGA-style) color. */
+
+private dev_proc_print_page(pcx16_print_page);
+
+private const gx_device_procs pcx16_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
+gx_device_printer far_data gs_pcx16_device =
+{ prn_device_body(gx_device_printer, pcx16_procs, "pcx16",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 3,4,3,2,4,3, pcx16_print_page)
+};
+
+/* Chunky 8-bit (SuperVGA-style) color. */
+/* (Uses a fixed palette of 3,3,2 bits.) */
+
+private const gx_device_procs pcx256_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_printer far_data gs_pcx256_device =
+{ prn_device_body(gx_device_printer, pcx256_procs, "pcx256",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 3,8,6,6,7,7, pcx256_print_page)
+};
+
+/* 24-bit color, 3 8-bit planes. */
+
+private dev_proc_print_page(pcx24b_print_page);
+
+private const gx_device_procs pcx24b_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+gx_device_printer far_data gs_pcx24b_device =
+ prn_device(pcx24b_procs, "pcx24b",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 24, pcx24b_print_page);
+
+/* 4-bit chunky CMYK color. */
+
+private dev_proc_print_page(pcxcmyk_print_page);
+
+private gx_color_index
+pcx_cmyk_map_cmyk_color(gx_device *dev,
+ gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
+{
+#define cv_bit(v) ((v) >> (gx_color_value_bits - 1))
+ return (gx_color_index)
+ (cv_bit(k) + (cv_bit(y) << 1) + (cv_bit(m) << 2) + (cv_bit(c) << 3));
+#undef cv_bit
+}
+private int
+pcx_cmyk_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ if ( color & 1 )
+ prgb[0] = prgb[1] = prgb[2] = 0;
+ else
+ prgb[0] = (color & 8 ? 0 : gx_max_color_value),
+ prgb[1] = (color & 4 ? 0 : gx_max_color_value),
+ prgb[2] = (color & 2 ? 0 : gx_max_color_value);
+ return 0;
+}
+private const gx_device_procs pcxcmyk_procs = {
+ gdev_prn_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ gdev_prn_output_page,
+ gdev_prn_close,
+ NULL, /* map_rgb_color */
+ pcx_cmyk_map_color_rgb,
+ NULL, /* fill_rectangle */
+ NULL, /* tile_rectangle */
+ NULL, /* copy_mono */
+ NULL, /* copy_color */
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ gdev_prn_get_params,
+ gdev_prn_put_params,
+ pcx_cmyk_map_cmyk_color, /* map_cmyk_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device
+};
+gx_device_printer far_data gs_pcxcmyk_device =
+{ prn_device_body(gx_device_printer, pcxcmyk_procs, "pcxcmyk",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 4,4,1,1,2,2, pcxcmyk_print_page)
+};
+
+/* ------ Private definitions ------ */
+
+/* All two-byte quantities are stored LSB-first! */
+#if arch_is_big_endian
+# define assign_ushort(a,v) a = ((v) >> 8) + ((v) << 8)
+#else
+# define assign_ushort(a,v) a = (v)
+#endif
+
+typedef struct pcx_header_s {
+ byte manuf; /* always 0x0a */
+ byte version; /* version info = 0,2,3,5 */
+ byte encoding; /* 1=RLE */
+ byte bpp; /* bits per pixel per plane */
+ ushort x1; /* X of upper left corner */
+ ushort y1; /* Y of upper left corner */
+ ushort x2; /* x1 + width - 1 */
+ ushort y2; /* y1 + height - 1 */
+ ushort hres; /* horz. resolution (dots per inch) */
+ ushort vres; /* vert. resolution (dots per inch) */
+ byte palette[16*3]; /* color palette */
+ byte reserved;
+ byte nplanes; /* number of color planes */
+ ushort bpl; /* number of bytes per line (uncompressed) */
+ ushort palinfo; /* palette info 1=color, 2=grey */
+ byte xtra[58]; /* fill out header to 128 bytes */
+} pcx_header;
+/* Define the prototype header. */
+private const pcx_header far_data pcx_header_prototype = {
+ 10, /* manuf */
+ 5, /* version */
+ 1, /* encoding */
+ 0, /* bpp (variable) */
+ 00, 00, /* x1, y1 */
+ 00, 00, /* x2, y2 (variable) */
+ 00, 00, /* hres, vres (variable) */
+ {0,0,0, 0,0,0, 0,0,0, 0,0,0, /* palette (variable) */
+ 0,0,0, 0,0,0, 0,0,0, 0,0,0,
+ 0,0,0, 0,0,0, 0,0,0, 0,0,0,
+ 0,0,0, 0,0,0, 0,0,0, 0,0,0},
+ 0, /* reserved */
+ 0, /* nplanes (variable) */
+ 00, /* bpl (variable) */
+ 00, /* palinfo (variable) */
+ { 0,0, 0,0,0,0,0,0,0,0, /* xtra */
+ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
+};
+
+/*
+** version info for PCX is as follows
+**
+** 0 == 2.5
+** 2 == 2.8 w/palette info
+** 3 == 2.8 without palette info
+** 5 == 3.0 (includes palette)
+**
+*/
+
+/*
+ * Define the DCX header. We don't actually use this yet.
+ * All quantities are stored little-endian!
+ bytes 0-3: ID = 987654321
+ bytes 4-7: file offset of page 1
+ [... up to 1023 entries ...]
+ bytes N-N+3: 0 to mark end of page list
+ * This is followed by the pages in order, each of which is a PCX file.
+ */
+#define dcx_magic 987654321
+#define dcx_max_pages 1023
+
+/* Forward declarations */
+private void pcx_write_rle(P4(const byte *, const byte *, int, FILE *));
+private int pcx_write_page(P4(gx_device_printer *, FILE *, pcx_header _ss *, bool));
+
+/* Write a monochrome PCX page. */
+private int
+pcxmono_print_page(gx_device_printer *pdev, FILE *file)
+{ pcx_header header;
+
+ header = pcx_header_prototype;
+ header.version = 2;
+ header.bpp = 1;
+ header.nplanes = 1;
+ /* Set the first two entries of the short palette. */
+ memcpy((byte *)header.palette, "\000\000\000\377\377\377", 6);
+ return pcx_write_page(pdev, file, &header, false);
+}
+
+/* Write an "old" PCX page. */
+static const byte pcx_ega_palette[16*3] = {
+ 0x00,0x00,0x00, 0x00,0x00,0xaa, 0x00,0xaa,0x00, 0x00,0xaa,0xaa,
+ 0xaa,0x00,0x00, 0xaa,0x00,0xaa, 0xaa,0xaa,0x00, 0xaa,0xaa,0xaa,
+ 0x55,0x55,0x55, 0x55,0x55,0xff, 0x55,0xff,0x55, 0x55,0xff,0xff,
+ 0xff,0x55,0x55, 0xff,0x55,0xff, 0xff,0xff,0x55, 0xff,0xff,0xff
+};
+private int
+pcx16_print_page(gx_device_printer *pdev, FILE *file)
+{ pcx_header header;
+
+ header = pcx_header_prototype;
+ header.version = 2;
+ header.bpp = 1;
+ header.nplanes = 4;
+ /* Fill the EGA palette appropriately. */
+ memcpy((byte *)header.palette, pcx_ega_palette,
+ sizeof(pcx_ega_palette));
+ return pcx_write_page(pdev, file, &header, true);
+}
+
+/* Write a "new" PCX page. */
+private int
+pcx256_print_page(gx_device_printer *pdev, FILE *file)
+{ pcx_header header;
+ int code;
+
+ header = pcx_header_prototype;
+ header.bpp = 8;
+ header.nplanes = 1;
+ code = pcx_write_page(pdev, file, &header, false);
+ if ( code >= 0 )
+ { /* Write out the palette. */
+ fputc(0x0c, file);
+ code = pc_write_palette((gx_device *)pdev, 256, file);
+ }
+ return code;
+}
+
+/* Write a 24-bit color PCX page. */
+private int
+pcx24b_print_page(gx_device_printer *pdev, FILE *file)
+{ pcx_header header;
+
+ header = pcx_header_prototype;
+ header.bpp = 8;
+ header.nplanes = 3;
+ return pcx_write_page(pdev, file, &header, true);
+}
+
+/* Write a 4-bit chunky CMYK color PCX page. */
+static const byte pcx_cmyk_palette[16*3] = {
+ 0xff,0xff,0xff, 0x00,0x00,0x00, 0xff,0xff,0x00, 0x0f,0x0f,0x00,
+ 0xff,0x00,0xff, 0x0f,0x00,0x0f, 0xff,0x00,0x00, 0x0f,0x00,0x00,
+ 0x00,0xff,0xff, 0x00,0x0f,0x0f, 0x00,0xff,0x00, 0x00,0x0f,0x00,
+ 0x00,0x00,0xff, 0x00,0x00,0x0f, 0x1f,0x1f,0x1f, 0x0f,0x0f,0x0f,
+};
+private int
+pcxcmyk_print_page(gx_device_printer *pdev, FILE *file)
+{ pcx_header header;
+
+ header = pcx_header_prototype;
+ header.version = 2;
+ header.bpp = 4;
+ header.nplanes = 1;
+ /* Fill the palette appropriately. */
+ memcpy((byte *)header.palette, pcx_cmyk_palette,
+ sizeof(pcx_cmyk_palette));
+ return pcx_write_page(pdev, file, &header, false);
+}
+
+/* Write out a page in PCX format. */
+/* This routine is used for all formats. */
+/* The caller has set header->bpp, nplanes, and palette. */
+private int
+pcx_write_page(gx_device_printer *pdev, FILE *file, pcx_header _ss *phdr,
+ bool planar)
+{ int raster = gdev_prn_raster(pdev);
+ uint rsize = round_up((pdev->width * phdr->bpp + 7) >> 3, 2); /* PCX format requires even */
+ int height = pdev->height;
+ int depth = pdev->color_info.depth;
+ uint lsize = raster + rsize;
+ byte *line = (byte *)gs_malloc(lsize, 1, "pcx file buffer");
+ byte *plane = line + raster;
+ int y;
+ int code = 0; /* return code */
+ if ( line == 0 ) /* can't allocate line buffer */
+ return_error(gs_error_VMerror);
+
+ /* Fill in the variable entries in the header struct. */
+
+ assign_ushort(phdr->x2, pdev->width-1);
+ assign_ushort(phdr->y2, height-1);
+ assign_ushort(phdr->hres, (int)pdev->x_pixels_per_inch);
+ assign_ushort(phdr->vres, (int)pdev->y_pixels_per_inch);
+ assign_ushort(phdr->bpl, (planar || depth == 1 ? rsize :
+ raster + (raster & 1)));
+ assign_ushort(phdr->palinfo, (depth > 1 ? 1 : 2));
+
+ /* Write the header. */
+
+ if ( fwrite((const char *)phdr, 1, 128, file) < 128 )
+ { code = gs_error_ioerror;
+ goto pcx_done;
+ }
+
+ /* Write the contents of the image. */
+ for ( y = 0; y < height; y++ )
+ { byte *row;
+ byte *end;
+
+ code = gdev_prn_get_bits(pdev, y, line, &row);
+ if ( code < 0 ) break;
+ end = row + raster;
+ if ( !planar )
+ { /* Just write the bits. */
+ if ( raster & 1 )
+ { /* Round to even, with predictable padding. */
+ *end = end[-1];
+ ++end;
+ }
+ pcx_write_rle(row, end, 1, file);
+ }
+ else
+ switch ( depth )
+ {
+
+ case 4:
+ { byte *pend = plane + rsize;
+ int shift;
+
+ for ( shift = 0; shift < 4; shift++ )
+ { register byte *from, *to;
+ register int bright = 1 << shift;
+ register int bleft = bright << 4;
+
+ for ( from = row, to = plane;
+ from < end; from += 4
+ )
+ { *to++ =
+ (from[0] & bleft ? 0x80 : 0) |
+ (from[0] & bright ? 0x40 : 0) |
+ (from[1] & bleft ? 0x20 : 0) |
+ (from[1] & bright ? 0x10 : 0) |
+ (from[2] & bleft ? 0x08 : 0) |
+ (from[2] & bright ? 0x04 : 0) |
+ (from[3] & bleft ? 0x02 : 0) |
+ (from[3] & bright ? 0x01 : 0);
+ }
+ /* We might be one byte short of rsize. */
+ if ( to < pend )
+ *to = to[-1];
+ pcx_write_rle(plane, pend, 1, file);
+ }
+ }
+ break;
+
+ case 24:
+ { int pnum;
+ for ( pnum = 0; pnum < 3; ++pnum )
+ { pcx_write_rle(row + pnum, row + raster, 3, file);
+ if ( pdev->width & 1 )
+ fputc(0, file); /* pad to even */
+ }
+ }
+ break;
+
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ goto pcx_done;
+
+ }
+ }
+
+pcx_done:
+ gs_free((char *)line, lsize, 1, "pcx file buffer");
+
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/* Write one line in PCX run-length-encoded format. */
+private void
+pcx_write_rle(const byte *from, const byte *end, int step, FILE *file)
+{ int max_run = step * 63;
+ while ( from < end )
+ { byte data = *from;
+ from += step;
+ if ( data != *from || from == end )
+ { if ( data >= 0xc0 )
+ putc(0xc1, file);
+ }
+ else
+ { const byte *start = from;
+ while ( (from < end) && (*from == data) )
+ from += step;
+ /* Now (from - start) / step + 1 is the run length. */
+ while ( from - start >= max_run )
+ { putc(0xff, file);
+ putc(data, file);
+ start += max_run;
+ }
+ if ( from > start || data >= 0xc0 )
+ putc((from - start) / step + 0xc1, file);
+ }
+ putc(data, file);
+ }
+}
diff --git a/gs/src/gdevpdf.c b/gs/src/gdevpdf.c
new file mode 100644
index 000000000..d0e6274b6
--- /dev/null
+++ b/gs/src/gdevpdf.c
@@ -0,0 +1,1337 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdf.c */
+/* PDF-writing driver */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "time_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gscdefs.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxpaint.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gdevpdfx.h"
+#include "scanchar.h"
+#include "strimpl.h" /* for short-sighted compilers */
+#include "scfx.h" /* s_CFE_template is default */
+#include "sstring.h"
+#include "szlibx.h"
+
+/*
+ ****** DISABLE GC because we still allocate all temporary data
+ ****** on the C heap.
+ */
+#define DISABLE_GC
+
+/* Optionally substitute other filters for FlateEncode for debugging. */
+#if 1
+# define compression_filter_name "FlateDecode"
+# define compression_filter_template s_zlibE_template
+# define compression_filter_state stream_zlib_state
+#else
+# include "slzwx.h"
+# define compression_filter_name "LZWDecode"
+# define compression_filter_template s_LZWE_template
+# define compression_filter_state stream_LZW_state
+#endif
+
+/* Define the size of the internal stream buffer. */
+/* (This is not a limitation, it only affects performance.) */
+#define sbuf_size 512
+
+/*
+ * Define the offset that indicates that a file position is in the
+ * resource file (rfile) rather than the main (contents) file.
+ * Must be a power of 2, and larger than the largest possible output file.
+ */
+#define rfile_base_position min_long
+
+/* GC descriptors */
+private_st_device_pdfwrite();
+private_st_pdf_resource();
+private_st_pdf_font();
+private_st_pdf_char_proc();
+
+/* GC procedures */
+#define pdev ((gx_device_pdf *)vptr)
+private ENUM_PTRS_BEGIN(device_pdfwrite_enum_ptrs) {
+#ifdef DISABLE_GC /* **************** */
+ return 0;
+#else /* **************** */
+ index -= gx_device_pdf_num_ptrs + gx_device_pdf_num_strings;
+ if ( index < num_resource_types * num_resource_chains )
+ ENUM_RETURN(pdev->resources[index / num_resource_chains].chains[index % num_resource_chains);
+ index -= num_resource_types;
+ if ( index < pdev->outline_depth )
+ ENUM_RETURN_STRING_PTR(gx_device_pdf, outline_levels[index].first.action_string);
+ index -= pdev->outline_depth;
+ if ( index < pdev->outline_depth )
+ ENUM_RETURN_STRING_PTR(gx_device_pdf, outline_levels[index].last.action_string);
+ index -= pdev->outline_depth;
+ ENUM_PREFIX(st_device_psdf, 0);
+#endif /* **************** */
+ }
+#ifndef DISABLE_GC /* **************** */
+#define e1(i,elt) ENUM_PTR(i, gx_device_pdf, elt);
+ gx_device_pdf_do_ptrs(e1)
+#undef e1
+#define e1(i,elt) ENUM_STRING_PTR(i + gx_device_pdf_num_ptrs, gx_device_pdf, elt);
+ gx_device_pdf_do_strings(e1)
+#undef e1
+#endif /* **************** */
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_pdfwrite_reloc_ptrs) {
+#ifndef DISABLE_GC /* **************** */
+ RELOC_PREFIX(st_device_psdf);
+#define r1(i,elt) RELOC_PTR(gx_device_pdf,elt);
+ gx_device_pdf_do_ptrs(r1)
+#undef r1
+#define r1(i,elt) RELOC_STRING_PTR(gx_device_pdf,elt);
+ gx_device_pdf_do_strings(r1)
+#undef r1
+ { int i, j;
+ for ( i = 0; i < num_resource_types; ++i )
+ for ( j = 0; j < num_resource_chains; ++j )
+ RELOC_PTR(gx_device_pdf, resources[i].chains[j]);
+ for ( i = 0; i < pdev->outline_depth; ++i ) {
+ RELOC_STRING_PTR(gx_device_pdf, outline_levels[i].first.action_string);
+ RELOC_STRING_PTR(gx_device_pdf, outline_levels[i].last.action_string);
+ }
+ }
+#endif /* **************** */
+} RELOC_PTRS_END
+#undef pdev
+/* Even though device_pdfwrite_finalize is the same as gx_device_finalize, */
+/* we need to implement it separately because st_composite_final */
+/* declares all 3 procedures as private. */
+private void
+device_pdfwrite_finalize(void *vpdev)
+{ gx_device_finalize(vpdev);
+}
+
+/* Device procedures */
+private dev_proc_open_device(pdf_open);
+private dev_proc_output_page(pdf_output_page);
+private dev_proc_close_device(pdf_close);
+extern dev_proc_fill_rectangle(gdev_pdf_fill_rectangle); /* in gdevpdfd.c */
+extern dev_proc_copy_mono(gdev_pdf_copy_mono); /* in gdevpdfi.c */
+extern dev_proc_copy_color(gdev_pdf_copy_color); /* in gdevpdfi.c */
+extern dev_proc_get_params(gdev_pdf_get_params); /* in gdevpdfp.c */
+extern dev_proc_put_params(gdev_pdf_put_params); /* in gdevpdfp.c */
+extern dev_proc_fill_path(gdev_pdf_fill_path); /* in gdevpdfd.c */
+extern dev_proc_stroke_path(gdev_pdf_stroke_path); /* in gdevpdfd.c */
+extern dev_proc_fill_mask(gdev_pdf_fill_mask); /* in gdevpdfi.c */
+extern dev_proc_begin_image(gdev_pdf_begin_image); /* in gdevpdfi.c */
+extern dev_proc_image_data(gdev_pdf_image_data); /* in gdevpdfi.c */
+extern dev_proc_end_image(gdev_pdf_end_image); /* in gdevpdfi.c */
+
+#ifndef X_DPI
+# define X_DPI 720
+#endif
+#ifndef Y_DPI
+# define Y_DPI 720
+#endif
+
+gx_device_pdf far_data gs_pdfwrite_device =
+{ std_device_color_stype_body(gx_device_pdf, 0, "pdfwrite",
+ &st_device_pdfwrite,
+ 85*X_DPI/10, 110*Y_DPI/10, X_DPI, Y_DPI, 24, 255, 255),
+ { pdf_open,
+ gx_upright_get_initial_matrix,
+ NULL, /* sync_output */
+ pdf_output_page,
+ pdf_close,
+ gx_default_rgb_map_rgb_color,
+ gx_default_rgb_map_color_rgb,
+ gdev_pdf_fill_rectangle,
+ NULL, /* tile_rectangle */
+ gdev_pdf_copy_mono,
+ gdev_pdf_copy_color,
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ gdev_pdf_get_params,
+ gdev_pdf_put_params,
+ NULL, /* map_cmyk_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device,
+ NULL, /* get_alpha_bits */
+ NULL, /* copy_alpha */
+ NULL, /* get_band */
+ NULL, /* copy_rop */
+ gdev_pdf_fill_path,
+ gdev_pdf_stroke_path,
+ gdev_pdf_fill_mask,
+ NULL, /* fill_trapezoid */
+ NULL, /* fill_parallelogram */
+ NULL, /* fill_triangle */
+ NULL, /* draw_thin_line */
+ gdev_pdf_begin_image,
+ gdev_pdf_image_data,
+ gdev_pdf_end_image
+ },
+ psdf_initial_values(0 /*false*/), /* (!ASCII85EncodePages) */
+ 1.2, /* CompatibilityLevel */
+ 0/*false*/, /* DoThumbnails */
+ 1/*true*/, /* ReAssignCharacters */
+ 1/*true*/, /* ReEncodeCharacters */
+ 1, /* FirstObjectNumber */
+ 0/*false*/, /* binary_ok */
+ pdf_compress_none, /* compression */
+ { 0 }, /* tfname */
+ 0, /* tfile */
+ { 0 }, /* rfname */
+ 0, /* rfile */
+ 0, /* rstrm */
+ 0, /* rstrmbuf */
+ 0, /* rsave_strm */
+ 0, /* open_font */
+ 0, /* embedded_encoding_id */
+ 0, /* next_id */
+ 0, /* root_id */
+ 0, /* info_id */
+ 0, /* pages_id */
+ 0, /* outlines_id */
+ 0, /* next_page */
+ 0, /* contents_id */
+ pdf_in_none, /* context */
+ 0, /* contents_length_id */
+ 0, /* contents_pos */
+ NoMarks, /* procsets */
+ -1, /* flatness */
+ { gx_line_params_initial }, /* line_params */
+ { pdf_text_state_default }, /* text */
+ { 0 }, /* space_char_ids */
+ 0, /* page_ids */
+ 0, /* num_page_ids */
+ 0, /* pages_referenced */
+ { { { 0 } } }, /* resources */
+ 0, /* annots */
+ 0, /* last_resource */
+ { 0, 0 }, /* catalog_string */
+ { 0, 0 }, /* pages_string */
+ { 0, 0 }, /* page_string */
+ { { { 0 } } }, /* outline_levels */
+ 0, /* outline_depth */
+ 0, /* closed_outline_depth */
+ 0, /* outlines_open */
+ 0, /* articles */
+ 0 /* named_dests */
+};
+
+/* ---------------- Utilities ---------------- */
+
+/* ------ Document ------ */
+
+/* Initialize the IDs allocated at startup. */
+void
+pdf_initialize_ids(gx_device_pdf *pdev)
+{ pdev->next_id = pdev->FirstObjectNumber;
+ pdev->root_id = pdf_obj_ref(pdev);
+ pdev->pages_id = pdf_obj_ref(pdev);
+}
+
+/* Open the document if necessary. */
+void
+pdf_open_document(gx_device_pdf *pdev)
+{ if ( !is_in_document(pdev) && pdf_stell(pdev) == 0 )
+ { stream *s = pdev->strm;
+
+ pprintd1(s, "%%PDF-1.%d\n",
+ (pdev->CompatibilityLevel >= 1.2 ? 2 : 1));
+ pdev->binary_ok = !pdev->params.ASCII85EncodePages;
+ if ( pdev->binary_ok )
+ pputs(s, "%\307\354\217\242\n");
+ }
+ /*
+ * Determine the compression method. Currently this does nothing.
+ * It also isn't clear whether the compression method can now be
+ * changed in the course of the document.
+ *
+ * The following algorithm is per an update to TN # 5151 by
+ * Adobe Developer Support.
+ */
+ if ( !pdev->params.CompressPages )
+ pdev->compression = pdf_compress_none;
+ else if ( pdev->CompatibilityLevel < 1.2 )
+ pdev->compression = pdf_compress_LZW;
+ else if ( pdev->params.UseFlateCompression )
+ pdev->compression = pdf_compress_Flate;
+ else
+ pdev->compression = pdf_compress_LZW;
+}
+
+/* ------ Objects ------ */
+
+/* Allocate an object ID. */
+private long
+pdf_next_id(gx_device_pdf *pdev)
+{ return (pdev->next_id)++;
+}
+
+/* Return the current position in the output. */
+/* Note that this may be in either the main file or the resource file. */
+long
+pdf_stell(gx_device_pdf *pdev)
+{ stream *s = pdev->strm;
+ long pos = stell(s);
+
+ if ( s == pdev->rstrm )
+ pos += rfile_base_position;
+ return pos;
+}
+
+/* Allocate an ID for a future object. */
+long
+pdf_obj_ref(gx_device_pdf *pdev)
+{ long id = pdf_next_id(pdev);
+ long pos = pdf_stell(pdev);
+
+ fwrite(&pos, sizeof(pos), 1, pdev->tfile);
+ return id;
+}
+
+/* Begin an object, optionally allocating an ID. */
+long
+pdf_open_obj(gx_device_pdf *pdev, long id)
+{ stream *s = pdev->strm;
+
+ if ( id <= 0 )
+ { id = pdf_obj_ref(pdev);
+ }
+ else
+ { long pos = pdf_stell(pdev);
+ FILE *tfile = pdev->tfile;
+ long tpos = ftell(tfile);
+
+ fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
+ SEEK_SET);
+ fwrite(&pos, sizeof(pos), 1, tfile);
+ fseek(tfile, tpos, SEEK_SET);
+ }
+ pprintld1(s, "%ld 0 obj\n", id);
+ return id;
+}
+
+/* End an object. */
+int
+pdf_end_obj(gx_device_pdf *pdev)
+{ pputs(pdev->strm, "endobj\n");
+ return 0;
+}
+
+/* ------ Graphics ------ */
+
+/* Reset the graphics state parameters to initial values. */
+void
+pdf_reset_graphics(gx_device_pdf *pdev)
+{ color_set_pure(&pdev->fill_color, 0); /* black */
+ color_set_pure(&pdev->stroke_color, 0); /* ditto */
+ pdev->flatness = -1;
+ { static const gx_line_params lp_initial = { gx_line_params_initial };
+ pdev->line_params = lp_initial;
+ }
+}
+
+/* Set the fill or stroke color. */
+int
+pdf_set_color(gx_device_pdf *pdev, gx_color_index color,
+ gx_drawing_color *pdcolor, const char *rgs)
+{ if ( gx_dc_pure_color(pdcolor) != color )
+ { int code;
+
+ /*
+ * In principle, we can set colors in either stream or text
+ * context. However, since we currently enclose all text
+ * strings inside a gsave/grestore, this causes us to lose
+ * track of the color when we leave text context. Therefore,
+ * we require stream context for setting colors.
+ */
+#if 0
+ switch ( pdev->context )
+ {
+ case pdf_in_stream:
+ case pdf_in_text:
+ break;
+ case pdf_in_none:
+ code = pdf_open_page(pdev, pdf_in_stream);
+ goto open;
+ case pdf_in_string:
+ code = pdf_open_page(pdev, pdf_in_text);
+open: if ( code < 0 )
+ return code;
+ }
+#else
+ code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+#endif
+ color_set_pure(pdcolor, color);
+ psdf_set_color((gx_device_vector *)pdev, pdcolor, rgs);
+ }
+ return 0;
+}
+
+/* Write matrix values. */
+void
+pdf_put_matrix(gx_device_pdf *pdev, const char *before,
+ const gs_matrix *pmat, const char *after)
+{ stream *s = pdev->strm;
+
+ if ( before )
+ pputs(s, before);
+ pprintg6(s, "%g %g %g %g %g %g ",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+ if ( after )
+ pputs(s, after);
+}
+
+/*
+ * Write a string in its shortest form ( () or <> ). Note that
+ * this form is different depending on whether binary data are allowed.
+ * We wish PDF supported ASCII85 strings ( <~ ~> ), but it doesn't.
+ */
+void
+pdf_put_string(gx_device_pdf *pdev, const byte *str, uint size)
+{ uint added = 0;
+ uint i;
+ const stream_template *template;
+ stream *s = pdev->strm;
+
+ if ( pdev->binary_ok )
+ { /* Only need to escape (, ), \, CR, EOL. */
+ pputc(s, '(');
+ for ( i = 0; i < size; ++i )
+ { byte ch = str[i];
+
+ switch ( ch )
+ {
+ case char_CR:
+ pputs(s, "\\r");
+ continue;
+ case char_EOL:
+ pputs(s, "\\n");
+ continue;
+ case '(': case ')': case '\\':
+ pputc(s, '\\');
+ }
+ pputc(s, ch);
+ }
+ pputc(s, ')');
+ return;
+ }
+
+ for ( i = 0; i < size; ++i )
+ { byte ch = str[i];
+
+ if ( ch == 0 || ch >= 127 )
+ added += 3;
+ else if ( strchr("()\\\n\r\t\b\f", ch) != 0 )
+ ++added;
+ else if ( ch < 32 )
+ added += 3;
+ }
+
+ if ( added < size )
+ { /* More efficient to represent as PostScript string. */
+ template = &s_PSSE_template;
+ pputc(s, '(');
+ }
+ else
+ { /* More efficient to represent as hex string. */
+ template = &s_AXE_template;
+ pputc(s, '<');
+ }
+
+ { byte buf[100]; /* size is arbitrary */
+ stream_cursor_read r;
+ stream_cursor_write w;
+ int status;
+
+ r.ptr = str - 1;
+ r.limit = r.ptr + size;
+ w.limit = buf + sizeof(buf) - 1;
+ do
+ { w.ptr = buf - 1;
+ status =
+ (*template->process)(NULL, &r, &w, true);
+ pwrite(s, buf, (uint)(w.ptr + 1 - buf));
+ }
+ while ( status == 1 );
+ }
+}
+
+/* ------ Page contents ------ */
+
+private const stream_procs filter_write_procs =
+{ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+};
+
+/* Handle transitions between contexts. */
+private int
+ none_to_stream(P1(gx_device_pdf *)),
+ stream_to_text(P1(gx_device_pdf *)),
+ string_to_text(P1(gx_device_pdf *)),
+ text_to_stream(P1(gx_device_pdf *)),
+ stream_to_none(P1(gx_device_pdf *));
+private int (*context_procs[4][4])(P1(gx_device_pdf *)) = {
+ {0, none_to_stream, none_to_stream, none_to_stream},
+ {stream_to_none, 0, stream_to_text, stream_to_text},
+ {text_to_stream, text_to_stream, 0, 0},
+ {string_to_text, string_to_text, string_to_text, 0}
+};
+/* Enter stream context. */
+private int
+none_to_stream(gx_device_pdf *pdev)
+{ stream *s;
+
+ if ( pdev->contents_id != 0 )
+ return_error(gs_error_Fatal); /* only 1 contents per page */
+ pdev->contents_id = pdf_begin_obj(pdev);
+ pdev->contents_length_id = pdf_obj_ref(pdev);
+ s = pdev->strm;
+ pprintld1(s, "<</Length %ld 0 R", pdev->contents_length_id);
+ if ( pdev->compression == pdf_compress_Flate )
+ pprints1(s, "/Filter /%s", compression_filter_name);
+ pputs(s, ">>\nstream\n");
+ pdev->contents_pos = pdf_stell(pdev);
+ if ( pdev->compression == pdf_compress_Flate )
+ { /* Set up the Flate filter. */
+ const stream_template *template = &compression_filter_template;
+ stream *es = s_alloc(pdev->pdf_memory, "PDF compression stream");
+ byte *buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
+ "PDF compression buffer");
+ compression_filter_state *st =
+ gs_alloc_struct(pdev->pdf_memory, compression_filter_state,
+ template->stype, "PDF compression state");
+
+ if ( es == 0 || st == 0 || buf == 0 )
+ return_error(gs_error_VMerror);
+ s_std_init(es, buf, sbuf_size, &filter_write_procs,
+ s_mode_write);
+ st->memory = pdev->pdf_memory;
+ st->template = template;
+ es->state = (stream_state *)st;
+ es->procs.process = template->process;
+ es->strm = s;
+ (*template->set_defaults)((stream_state *)st);
+ (*template->init)((stream_state *)st);
+ pdev->strm = s = es;
+ }
+ /* Scale the coordinate system. */
+ pprintg2(s, "%g 0 0 %g 0 0 cm\n",
+ 72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
+ /* Do a level of gsave for the clipping path. */
+ pputs(s, "q\n");
+ return pdf_in_stream;
+}
+/* Enter text context from stream context. */
+private int
+stream_to_text(gx_device_pdf *pdev)
+{ /*
+ * Bizarrely enough, Acrobat Reader cares how the final font size is
+ * obtained -- the CTM (cm), text matrix (Tm), and font size (Tf)
+ * are *not* all equivalent. In particular, it seems to use the
+ * product of the text matrix and font size to decide how to
+ * anti-alias characters. Therefore, we have to temporarily patch
+ * the CTM so that the scale factors are unity. What a nuisance!
+ */
+ pprintg2(pdev->strm, "q %g 0 0 %g 0 0 cm BT\n",
+ pdev->HWResolution[0] / 72.0, pdev->HWResolution[1] / 72.0);
+ pdev->procsets |= Text;
+ gs_make_identity(&pdev->text.matrix);
+ pdev->text.line_start.x = pdev->text.line_start.y = 0;
+ pdev->text.buffer_count = 0;
+ return pdf_in_text;
+}
+/* Exit string context to text context. */
+private int
+string_to_text(gx_device_pdf *pdev)
+{ pdf_put_string(pdev, pdev->text.buffer, pdev->text.buffer_count);
+ pputs(pdev->strm, "Tj\n");
+ pdev->text.buffer_count = 0;
+ return pdf_in_text;
+}
+/* Exit text context to stream context. */
+private int
+text_to_stream(gx_device_pdf *pdev)
+{ pputs(pdev->strm, "ET Q\n");
+ pdev->text.font = 0; /* because of Q */
+ return pdf_in_stream;
+}
+/* Exit stream context. */
+private int
+stream_to_none(gx_device_pdf *pdev)
+{ stream *s = pdev->strm;
+ long length;
+
+ if ( pdev->compression == pdf_compress_Flate )
+ { /* Terminate the Flate filter. */
+ stream *fs = s->strm;
+
+ sclose(s);
+ gs_free_object(pdev->pdf_memory, s->cbuf, "zlib buffer");
+ gs_free_object(pdev->pdf_memory, s, "zlib stream");
+ pdev->strm = s = fs;
+ }
+ length = pdf_stell(pdev) - pdev->contents_pos;
+ pputs(s, "endstream\n");
+ pdf_end_obj(pdev);
+ pdf_open_obj(pdev, pdev->contents_length_id);
+ pprintld1(s, "%ld\n", length);
+ pdf_end_obj(pdev);
+ return pdf_in_none;
+}
+
+/* Begin a page contents part. */
+int
+pdf_open_contents(gx_device_pdf *pdev, pdf_context context)
+{ int (*proc)(P1(gx_device_pdf *));
+
+ while ( (proc = context_procs[pdev->context][context]) != 0 )
+ { int code = (*proc)(pdev);
+ if ( code < 0 )
+ return code;
+ pdev->context = (pdf_context)code;
+ }
+ pdev->context = context;
+ return 0;
+}
+
+/* Close the current contents part if we are in one. */
+int
+pdf_close_contents(gx_device_pdf *pdev, bool last)
+{ if ( pdev->context == pdf_in_none )
+ return 0;
+ if ( last )
+ { /* Exit from the clipping path gsave. */
+ pdf_open_contents(pdev, pdf_in_stream);
+ pputs(pdev->strm, "Q\n");
+ pdev->text.font = 0;
+ }
+ return pdf_open_contents(pdev, pdf_in_none);
+}
+
+/* ------ Resources et al ------ */
+
+/* Define the hash function for gs_ids. */
+#define gs_id_hash(rid) ((rid) + ((rid) / num_resource_chains))
+
+/* Define the names of the resource types. */
+private const char *resource_names[] =
+ { pdf_resource_type_names };
+
+/* Define the allocator descriptors for the resource types. */
+private const gs_memory_struct_type_t *resource_structs[] =
+ { pdf_resource_type_structs };
+
+/* Find a resource of a given type by gs_id. */
+pdf_resource *
+pdf_find_resource_by_gs_id(gx_device_pdf *pdev, pdf_resource_type type,
+ gs_id rid)
+{ pdf_resource **pchain =
+ &pdev->resources[type].chains[gs_id_hash(rid) % num_resource_chains];
+ pdf_resource **pprev = pchain;
+ pdf_resource *pres;
+
+ for ( ; (pres = *pprev) != 0; pprev = &pres->next )
+ if ( pres->rid == rid ) {
+ if ( pprev != pchain ) {
+ *pprev = pres->next;
+ pres->next = *pchain;
+ *pchain = pres;
+ }
+ return pres;
+ }
+ return 0;
+}
+
+/* Begin an object logically separate from the contents. */
+long
+pdf_open_separate(gx_device_pdf *pdev, long id)
+{ pdf_open_document(pdev);
+ pdev->rsave_strm = pdev->strm;
+ pdev->strm = pdev->rstrm;
+ return pdf_open_obj(pdev, id);
+}
+
+/* Begin an aside (resource, annotation, ...). */
+private int
+pdf_alloc_aside(gx_device_pdf *pdev, pdf_resource **plist,
+ const gs_memory_struct_type_t *pst, pdf_resource **ppres)
+{ pdf_resource *pres;
+
+ if ( pst == NULL )
+ pst = &st_pdf_resource;
+ pres =
+ gs_alloc_struct(pdev->pdf_memory, pdf_resource, pst, "begin_aside");
+ if ( pres == 0 )
+ return_error(gs_error_VMerror);
+ pres->next = *plist;
+ *plist = pres;
+ pres->prev = pdev->last_resource;
+ pdev->last_resource = pres;
+ *ppres = pres;
+ return 0;
+}
+int
+pdf_begin_aside(gx_device_pdf *pdev, pdf_resource **plist,
+ const gs_memory_struct_type_t *pst, pdf_resource **ppres)
+{ long id = pdf_begin_separate(pdev);
+ int code;
+
+ if ( id < 0 )
+ return id;
+ code = pdf_alloc_aside(pdev, plist, pst, ppres);
+ if ( code < 0 )
+ return code;
+ (*ppres)->id = id;
+ return 0;
+}
+
+/* Begin a resource of a given type. */
+int
+pdf_begin_resource(gx_device_pdf *pdev, pdf_resource_type type, gs_id rid,
+ pdf_resource **ppres)
+{ int code = pdf_begin_aside(pdev,
+ &pdev->resources[type].chains[gs_id_hash(rid) % num_resource_chains],
+ resource_structs[type], ppres);
+
+ if ( code < 0 )
+ return code;
+ if ( resource_names[type] != 0 )
+ { stream *s = pdev->strm;
+
+ pprints1(s, "<< /Type /%s", resource_names[type]);
+ pprintld1(s, " /Name /R%ld", (*ppres)->id);
+ }
+ return code;
+}
+
+/* Allocate a resource, but don't open the stream. */
+int
+pdf_alloc_resource(gx_device_pdf *pdev, pdf_resource_type type, gs_id rid,
+ pdf_resource **ppres)
+{ int code = pdf_alloc_aside(pdev,
+ &pdev->resources[type].chains[gs_id_hash(rid) % num_resource_chains],
+ resource_structs[type], ppres);
+
+ if ( code < 0 )
+ return code;
+ (*ppres)->id = pdf_obj_ref(pdev);
+ return 0;
+}
+
+/* End an aside or other separate object. */
+int
+pdf_end_aside(gx_device_pdf *pdev)
+{ int code = pdf_end_obj(pdev);
+
+ pdev->strm = pdev->rsave_strm;
+ return code;
+}
+/* End a resource. */
+int
+pdf_end_resource(gx_device_pdf *pdev)
+{ return pdf_end_aside(pdev);
+}
+
+/* ------ Pages ------ */
+
+/* Reset the state of the current page. */
+void
+pdf_reset_page(gx_device_pdf *pdev, bool first_page)
+{ pdev->contents_id = 0;
+ pdf_reset_graphics(pdev);
+ pdev->procsets = NoMarks;
+ { int i, j;
+ for ( i = 0; i < num_resource_types; ++i )
+ if ( first_page ||
+ !(i == resourceFont || resource_names[i] == 0)
+ )
+ for ( j = 0; j < num_resource_chains; ++j )
+ pdev->resources[i].chains[j] = 0;
+ }
+ pdev->page_string.data = 0;
+ { static const pdf_text_state text_default =
+ { pdf_text_state_default };
+ pdev->text = text_default;
+ }
+}
+
+/* Get or assign the ID for a page. */
+/* Returns 0 if the page number is out of range. */
+long
+pdf_page_id(gx_device_pdf *pdev, int page_num)
+{ long page_id;
+
+ if ( page_num >= pdev->num_page_ids )
+ { /* Grow the page_ids array. */
+ uint new_num_ids =
+ max(page_num + 10, pdev->num_page_ids << 1);
+ /* resize_object for a byte array takes a new object size */
+ /* in bytes. This is a quirk of the API that we probably */
+ /* won't ever be able to fix.... */
+ long *new_ids = gs_resize_object(pdev->pdf_memory, pdev->page_ids,
+ new_num_ids * sizeof(long),
+ "pdf_page_id(resize page_ids)");
+
+ if ( new_ids == 0 )
+ return 0;
+ pdev->page_ids = new_ids;
+ pdev->num_page_ids = new_num_ids;
+ }
+ if ( page_num < 1 )
+ return 0;
+ while ( page_num > pdev->pages_referenced )
+ pdev->page_ids[pdev->pages_referenced++] = 0;
+ if ( (page_id = pdev->page_ids[page_num - 1]) == 0 )
+ pdev->page_ids[page_num - 1] = page_id = pdf_obj_ref(pdev);
+ return page_id;
+}
+
+/* Write saved page- or document-level information. */
+int
+pdf_write_saved_string(gx_device_pdf *pdev, gs_string *pstr)
+{ if ( pstr->data != 0 )
+ { pwrite(pdev->strm, pstr->data, pstr->size);
+ gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
+ "pdf_write_saved_string");
+ pstr->data = 0;
+ }
+ return 0;
+}
+
+/* Open a page for writing. */
+int
+pdf_open_page(gx_device_pdf *pdev, pdf_context context)
+{ if ( !is_in_page(pdev) )
+ { if ( pdf_page_id(pdev, pdev->next_page + 1) == 0 )
+ return_error(gs_error_VMerror);
+ pdf_open_document(pdev);
+ }
+ /* Note that context may be pdf_in_none here. */
+ return pdf_open_contents(pdev, context);
+}
+
+/* Close the current page. */
+private int
+pdf_close_page(gx_device_pdf *pdev)
+{ stream *s;
+ int page_num = ++(pdev->next_page);
+ long page_id;
+
+ /* If the very first page is blank, we need to open the document */
+ /* before doing anything else. */
+ pdf_open_document(pdev);
+ pdf_close_contents(pdev, true);
+ page_id = pdf_page_id(pdev, page_num);
+ pdf_open_obj(pdev, page_id);
+ s = pdev->strm;
+ pprintd2(s, "<<\n/Type /Page\n/MediaBox [0 0 %d %d]\n",
+ (int)(pdev->MediaSize[0]), (int)(pdev->MediaSize[1]));
+ pprintld1(s, "/Parent %ld 0 R\n", pdev->pages_id);
+ pputs(s, "/Resources << /ProcSet [/PDF");
+ if ( pdev->procsets & ImageB )
+ pputs(s, " /ImageB");
+ if ( pdev->procsets & ImageC )
+ pputs(s, " /ImageC");
+ if ( pdev->procsets & ImageI )
+ pputs(s, " /ImageI");
+ if ( pdev->procsets & Text )
+ pputs(s, " /Text");
+ pputs(s, "]\n");
+ { int i;
+
+ for ( i = 0; i < num_resource_types; ++i )
+ if ( !(i == resourceFont || resource_names[i] == 0) )
+ { bool first = true;
+ int j;
+ const pdf_resource *pres;
+
+ for ( j = 0; j < num_resource_chains; ++j ) {
+ for ( pres = pdev->resources[i].chains[j];
+ pres != 0; pres = pres->next
+ ) {
+ if ( first )
+ pprints1(s, "/%s<<", resource_names[i]), first = false;
+ pprintld2(s, "/R%ld\n%ld 0 R", pres->id, pres->id);
+ }
+ pdev->resources[i].chains[j] = 0;
+ }
+ if ( !first )
+ pputs(s, ">>\n");
+ }
+ }
+ /* Put out references to just those fonts used on this page. */
+ { bool first = true;
+ int j;
+ pdf_font *font;
+
+ for ( j = 0; j < num_resource_chains; ++j )
+ for ( font = (pdf_font *)pdev->resources[resourceFont].chains[j];
+ font != 0; font = font->next
+ )
+ if ( font->used_on_page ) {
+ if ( first )
+ pputs(s, "/Font <<\n"), first = false;
+ if ( font->frname[0] )
+ pprints1(s, "/%s", font->frname);
+ else
+ pprintld1(s, "/R%ld", font->id);
+ pprintld1(s, " %ld 0 R\n", font->id);
+ font->used_on_page = false;
+ }
+ if ( !first )
+ pputs(s, ">>\n");
+ }
+ pputs(s, ">>\n");
+ if ( pdev->contents_id == 0 )
+ pputs(s, "/Contents []\n");
+ else
+ pprintld1(s, "/Contents %ld 0 R\n", pdev->contents_id);
+ pdf_write_saved_string(pdev, &pdev->page_string);
+ { const pdf_resource *pres = pdev->annots;
+ bool any = false;
+ for ( ; pres != 0; pres = pres->next )
+ if ( pres->rid == page_num - 1 )
+ { if ( !any )
+ { pputs(s, "/Annots [\n");
+ any = true;
+ }
+ pprintld1(s, "%ld 0 R\n", pres->id);
+ }
+ if ( any )
+ pputs(s, "]\n");
+ }
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+ pdf_reset_page(pdev, false);
+ return 0;
+}
+
+/* Write the default entries of the Info dictionary. */
+int
+pdf_write_default_info(gx_device_pdf *pdev)
+{ stream *s = pdev->strm;
+ /* Reading the time without using time_t is a challenge.... */
+ long t[2]; /* time_t can't be longer than 2 longs. */
+ struct tm ltime;
+ char buf[20];
+
+ time((void *)t);
+ ltime = *localtime((void *)t);
+ sprintf(buf, "%04d%02d%02d%02d%02d%02d",
+ ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
+ ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
+ pprints1(s, "/CreationDate (D:%s)\n", buf);
+ sprintf(buf, "%1.2f", gs_revision / 100.0);
+ pprints2(s, "/Producer (%s %s)\n", gs_product, buf);
+ return 0;
+}
+
+/* ---------------- Device open/close ---------------- */
+
+/* Close and remove temporary files. */
+private void
+pdf_close_files(gx_device_pdf *pdev)
+{ gs_free_object(pdev->pdf_memory, pdev->rstrmbuf,
+ "pdf_close_files(rstrmbuf)");
+ pdev->rstrmbuf = 0;
+ gs_free_object(pdev->pdf_memory, pdev->rstrm,
+ "pdf_close_files(rstrm)");
+ pdev->rstrm = 0;
+ if ( pdev->rfile != 0 )
+ { fclose(pdev->rfile);
+ pdev->rfile = 0;
+ unlink(pdev->rfname);
+ }
+ if ( pdev->tfile != 0 )
+ { fclose(pdev->tfile);
+ pdev->tfile = 0;
+ unlink(pdev->tfname);
+ }
+}
+
+/* Open the device. */
+private int
+pdf_open(gx_device *dev)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ char fmode[4];
+ int code;
+
+ pdev->pdf_memory = &gs_memory_default; /* as good as any */
+ strcpy(fmode, "w+");
+ strcat(fmode, gp_fmode_binary_suffix);
+ pdev->tfile =
+ gp_open_scratch_file(gp_scratch_file_name_prefix,
+ pdev->tfname, fmode);
+ if ( pdev->tfile == 0 )
+ return_error(gs_error_invalidfileaccess);
+ pdev->rfile =
+ gp_open_scratch_file(gp_scratch_file_name_prefix,
+ pdev->rfname, fmode);
+ if ( pdev->rfile == 0 )
+ { code = gs_note_error(gs_error_invalidfileaccess);
+ goto fail;
+ }
+ pdev->rstrm = s_alloc(pdev->pdf_memory, "pdf_open(rstrm)");
+ pdev->rstrmbuf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
+ "pdf_open(rstrmbuf)");
+ if ( pdev->rstrm == 0 || pdev->rstrmbuf == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto fail;
+ }
+ swrite_file(pdev->rstrm, pdev->rfile, pdev->rstrmbuf, sbuf_size);
+ code = gdev_vector_open_file((gx_device_vector *)pdev, sbuf_size);
+ if ( code < 0 )
+ goto fail;
+ gdev_vector_init((gx_device_vector *)pdev);
+ /* Set in_page so the vector routines won't try to call */
+ /* any vector implementation procedures. */
+ pdev->in_page = true;
+ pdf_initialize_ids(pdev);
+ pdev->outlines_id = 0;
+ pdev->next_page = 0;
+ memset(pdev->space_char_ids, 0, sizeof(pdev->space_char_ids));
+ pdev->page_ids = (void *)
+ gs_alloc_byte_array(pdev->pdf_memory, initial_num_page_ids,
+ sizeof(*pdev->page_ids), "pdf_open(page_ids)");
+ if ( pdev->page_ids == 0 )
+ { code = gs_error_VMerror;
+ goto fail;
+ }
+ pdev->num_page_ids = initial_num_page_ids;
+ pdev->pages_referenced = 0;
+ pdev->catalog_string.data = 0;
+ pdev->pages_string.data = 0;
+ pdev->outline_levels[0].first.id = 0;
+ pdev->outline_levels[0].left = max_int;
+ pdev->outline_depth = 0;
+ pdev->closed_outline_depth = 0;
+ pdev->outlines_open = 0;
+ pdev->articles = 0;
+ pdev->named_dests = 0;
+ pdf_reset_page(pdev, true);
+
+ return 0;
+fail:
+ pdf_close_files(pdev);
+ return code;
+}
+
+/* Wrap up ("output") a page. */
+private int
+pdf_output_page(gx_device *dev, int num_copies, int flush)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ return pdf_close_page(pdev);
+}
+
+/* Write out the CharProcs for an embedded font. */
+/* We thought that Acrobat 2.x required this to be an indirect object, */
+/* but we were wrong. */
+private int
+pdf_write_char_procs(gx_device_pdf *pdev, const pdf_font *pef,
+ gs_int_rect *pbbox, int widths[256])
+{ stream *s = pdev->strm;
+ const pdf_char_proc *pcp;
+ int w;
+
+ pputs(s, "<<");
+ /* Write real characters. */
+ for ( pcp = pef->char_procs; pcp; pcp = pcp->char_next ) {
+ pbbox->p.y = min(pbbox->p.y, pcp->y_offset);
+ pbbox->q.x = max(pbbox->q.x, pcp->width);
+ pbbox->q.y = max(pbbox->q.y, pcp->height + pcp->y_offset);
+ widths[pcp->char_code] = pcp->x_width;
+ pprintld2(s, "/a%ld\n%ld 0 R", (long)pcp->char_code, pcp->id);
+ }
+ /* Write space characters. */
+ for ( w = 0; w < countof(pef->spaces); ++w ) {
+ byte ch = pef->spaces[w];
+ if ( ch ) {
+ pprintld2(s, "/a%ld\n%ld 0 R", (long)ch,
+ pdev->space_char_ids[w]);
+ widths[ch] = w + x_space_min;
+ }
+ }
+ pputs(s, ">>");
+ return 0;
+}
+
+/* Write out the Widths for an embedded font similarly. */
+private int
+pdf_write_widths(gx_device_pdf *pdev, const pdf_font *pef, int widths[256])
+{ stream *s = pdev->strm;
+ int i;
+
+ pputs(s, "[");
+ for ( i = 0; i < pef->num_chars; ++i )
+ pprintd1(s, (i & 15 ? " %d" : ("\n%d")), widths[i]);
+ pputs(s, "]");
+ return 0;
+}
+
+/* Close the device. */
+private int
+pdf_close(gx_device *dev)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ stream *s;
+ FILE *tfile = pdev->tfile;
+ long xref;
+ long named_dests_id = 0;
+ long resource_pos;
+
+ /*
+ * If this is an EPS file, or if the file has produced no marks
+ * at all, we need to tidy up a little so as not to produce
+ * illegal PDF. We recognize EPS files as having some contents
+ * but no showpage.
+ */
+ if ( pdev->next_page == 0 )
+ { pdf_open_document(pdev);
+ if ( pdev->contents_id != 0 )
+ { pdf_close_page(pdev);
+ }
+ }
+
+ /*
+ * Write out fonts. For base fonts, write the encoding
+ * differences.
+ */
+
+ { int j;
+ const pdf_font *pef;
+
+ s = pdev->strm;
+ for ( j = 0; j < num_resource_chains; ++j )
+ for ( pef = (const pdf_font *)pdev->resources[resourceFont].chains[j];
+ pef != 0; pef = pef->next
+ ) {
+ pdf_open_obj(pdev, pef->id);
+ if ( font_is_embedded(pef) ) {
+ gs_int_rect bbox;
+ int widths[256];
+
+ memset(&bbox, 0, sizeof(bbox));
+ memset(widths, 0, sizeof(widths));
+ pprints1(s, "<</Type/Font/Name/%s/Subtype/Type3", pef->frname);
+ pprintld1(s, "/Encoding %ld 0 R", pdev->embedded_encoding_id);
+ pprintd1(s, "/FirstChar 0/LastChar %d/CharProcs",
+ pef->num_chars - 1);
+ pdf_write_char_procs(pdev, pef, &bbox, widths);
+ pprintd4(s, "/FontBBox[%d %d %d %d]/FontMatrix[1 0 0 1 0 0]/Widths",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ pdf_write_widths(pdev, pef, widths);
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+ } else {
+ pprintld1(s, "<</Type/Font/Name/R%ld/Subtype/Type1/BaseFont/",
+ pef->id);
+ pwrite(s, pef->fname.chars, pef->fname.size);
+ if ( pef->differences != 0 )
+ pprintld1(s, "/Encoding %ld 0 R", pef->diff_id);
+ pputs(s, ">>\n");
+ if ( pef->differences != 0 ) {
+ int prev = 256;
+ int i;
+
+ pdf_end_obj(pdev);
+ pdf_open_obj(pdev, pef->diff_id);
+ pputs(s, "<</Type/Encoding/Differences[");
+ for ( i = 0; i < 256; ++i )
+ if ( pef->differences[i].data != 0 ) {
+ if ( i != prev + 1 )
+ pprintd1(s, "\n%d", i);
+ pputs(s, "/");
+ pwrite(s, pef->differences[i].data,
+ pef->differences[i].size);
+ prev = i;
+ }
+ pputs(s, "]>>\n");
+ }
+ }
+ pdf_end_obj(pdev);
+ }
+ }
+
+ /* Create the root (Catalog). */
+
+ pdf_open_obj(pdev, pdev->pages_id);
+ pputs(s, "<< /Type /Pages /Kids [\n");
+ { int i;
+ for ( i = 0; i < pdev->next_page; ++i )
+ pprintld1(s, "%ld 0 R\n", pdev->page_ids[i]);
+ }
+ pprintd1(s, "] /Count %d\n", pdev->next_page);
+ pdf_write_saved_string(pdev, &pdev->pages_string);
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+ if ( pdev->outlines_id != 0 )
+ { pdfmark_close_outline(pdev); /* depth must be zero! */
+ pdf_open_obj(pdev, pdev->outlines_id);
+ pprintd1(s, "<< /Count %d", pdev->outlines_open);
+ pprintld2(s, " /First %ld 0 R /Last %ld 0 R >>\n",
+ pdev->outline_levels[0].first.id,
+ pdev->outline_levels[0].last.id);
+ pdf_end_obj(pdev);
+ }
+ if ( pdev->articles != 0 )
+ { pdf_article *part;
+ /* Write the first and last beads of each article. */
+ for ( part = pdev->articles; part != 0; part = part->next )
+ { if ( part->last.id == 0 )
+ { /* Only one bead in the article. */
+ part->first.prev_id = part->first.next_id = part->first.id;
+ }
+ else
+ { /* More than one bead in the article. */
+ part->first.prev_id = part->last.id;
+ part->last.next_id = part->first.id;
+ pdfmark_write_article(pdev, &part->last);
+ }
+ pdfmark_write_article(pdev, &part->first);
+ }
+ }
+ if ( pdev->named_dests != 0 )
+ { pdf_named_dest *pnd;
+ named_dests_id = pdf_begin_obj(pdev);
+ pputs(s, "<<\n");
+ while ( (pnd = pdev->named_dests) != 0 )
+ { pdev->named_dests = pnd->next;
+ pwrite(s, pnd->key.data, pnd->key.size);
+ pprints1(s, " %s\n", pnd->dest);
+ gs_free_string(pdev->pdf_memory, pnd->key.data, pnd->key.size,
+ "pdf_close(named_dest key)");
+ gs_free_object(pdev->pdf_memory, pnd, "pdf_close(named_dest)");
+ }
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+ }
+ pdf_open_obj(pdev, pdev->root_id);
+ pprintld1(s, "<< /Type /Catalog /Pages %ld 0 R\n", pdev->pages_id);
+ if ( pdev->outlines_id != 0 )
+ pprintld1(s, "/Outlines %ld 0 R\n", pdev->outlines_id);
+ if ( pdev->articles != 0 )
+ { pdf_article *part;
+ pputs(s, "/Threads [ ");
+ while ( (part = pdev->articles) != 0 )
+ { pdev->articles = part->next;
+ pprintld1(s, "%ld 0 R\n", part->id);
+ gs_free_string(pdev->pdf_memory, part->title.data,
+ part->title.size, "pdf_close(article title)");
+ gs_free_object(pdev->pdf_memory, part, "pdf_close(article)");
+ }
+ pputs(s, "]\n");
+ }
+ if ( named_dests_id != 0 )
+ pprintld1(s, "/Dests %ld 0 R\n", named_dests_id);
+ pdf_write_saved_string(pdev, &pdev->catalog_string);
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+
+ /* Create the Info directory. */
+ /* This is supposedly optional, but some readers may require it. */
+
+ if ( pdev->info_id == 0 )
+ { pdev->info_id = pdf_begin_obj(pdev);
+ pputs(s, "<< ");
+ pdf_write_default_info(pdev);
+ pputs(s, ">>\n");
+ pdf_end_obj(pdev);
+ }
+
+ /* Copy the resources into the main file. */
+
+ s = pdev->strm;
+ resource_pos = stell(s);
+ sflush(pdev->rstrm);
+ { FILE *rfile = pdev->rfile;
+ long res_end = ftell(rfile);
+ byte buf[sbuf_size];
+
+ fseek(rfile, 0L, SEEK_SET);
+ while ( res_end > 0 )
+ { uint count = min(res_end, sbuf_size);
+
+ fread(buf, 1, sbuf_size, rfile);
+ pwrite(s, buf, count);
+ res_end -= count;
+ }
+ }
+
+ /* Write the cross-reference section. */
+
+ xref = pdf_stell(pdev);
+ if ( pdev->FirstObjectNumber == 1 )
+ pprintld1(s, "xref\n0 %ld\n0000000000 65535 f \n",
+ pdev->next_id);
+ else
+ pprintld2(s, "xref\n0 1\n0000000000 65535 f \n%ld %ld\n",
+ pdev->FirstObjectNumber,
+ pdev->next_id - pdev->FirstObjectNumber);
+ fseek(tfile, 0L, SEEK_SET);
+ { long i;
+ for ( i = pdev->FirstObjectNumber; i < pdev->next_id; ++i )
+ { ulong pos;
+ char str[21];
+
+ fread(&pos, sizeof(pos), 1, tfile);
+ if ( pos & rfile_base_position )
+ pos += resource_pos - rfile_base_position;
+ sprintf(str, "%010ld 00000 n \n", pos);
+ pputs(s, str);
+ }
+ }
+
+ /* Write the trailer. */
+
+ pputs(s, "trailer\n");
+ pprintld3(s, "<< /Size %ld /Root %ld 0 R /Info %ld 0 R\n",
+ pdev->next_id, pdev->root_id, pdev->info_id);
+ pputs(s, ">>\n");
+ pprintld1(s, "startxref\n%ld\n%%%%EOF\n", xref);
+
+ /* Release the resource records. */
+
+ { pdf_resource *pres;
+ pdf_resource *prev;
+ for ( prev = pdev->last_resource; (pres = prev) != 0; )
+ { prev = pres->prev;
+ gs_free_object(pdev->pdf_memory, pres, "pdf_resource");
+ }
+ pdev->last_resource = 0;
+ }
+
+ gs_free_object(pdev->pdf_memory, pdev->page_ids, "page_ids");
+ pdev->page_ids = 0;
+ pdev->num_page_ids = 0;
+
+ gdev_vector_close_file((gx_device_vector *)pdev);
+ pdf_close_files(pdev);
+ return 0;
+}
diff --git a/gs/src/gdevpdfd.c b/gs/src/gdevpdfd.c
new file mode 100644
index 000000000..5c6a7f810
--- /dev/null
+++ b/gs/src/gdevpdfd.c
@@ -0,0 +1,381 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdfd.c */
+/* Driver drawing procedures for PDF-writing driver */
+#include "math_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxpaint.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gdevpdfx.h"
+
+/* ---------------- Drawing ---------------- */
+
+/* Fill a rectangle. */
+int
+gdev_pdf_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code;
+
+ /* Make a special check for the initial fill with white, */
+ /* which shouldn't cause the page to be opened. */
+ if ( color == 0xffffff && !is_in_page(pdev) )
+ return 0;
+ code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ /* Make sure we aren't being clipped. */
+ pdf_put_clip_path(pdev, NULL);
+ pdf_set_color(pdev, color, &pdev->fill_color, "rg");
+ pprintd4(pdev->strm, "%d %d %d %d re f\n", x, y, w, h);
+ return 0;
+}
+
+/* ---------------- Path drawing ---------------- */
+
+/* ------ Utilities ------ */
+
+/* Put a path on the output file. If do_close is false and the last */
+/* path component is a closepath, omit it and return 1. */
+private int
+pdf_put_path(gx_device_pdf *pdev, const gx_path *ppath, bool do_close,
+ const gs_matrix *pmat)
+{ stream *s = pdev->strm;
+ gs_fixed_rect rbox;
+ const subpath *next;
+ gs_path_enum cenum;
+
+ /* If do_close is false, we recognize rectangles specially. */
+ if ( !do_close && ppath->subpath_count == 1 &&
+ ppath->curve_count == 0 &&
+ gx_subpath_is_rectangle(ppath->first_subpath, &rbox, &next) &&
+ (pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat))
+ )
+ { gs_point p, q;
+
+ p.x = fixed2float(rbox.p.x), p.y = fixed2float(rbox.p.y);
+ q.x = fixed2float(rbox.q.x), q.y = fixed2float(rbox.q.y);
+ if ( pmat )
+ { gs_point_transform_inverse(p.x, p.y, pmat, &p);
+ gs_point_transform_inverse(q.x, q.y, pmat, &q);
+ }
+ pprintg4(s, "%g %g %g %g re\n",
+ p.x, p.y, q.x - p.x, q.y - p.y);
+ return 0;
+ }
+ gx_path_enum_init(&cenum, ppath);
+ for ( ; ; )
+ { gs_fixed_point vs[3];
+ gs_point vp[3];
+ const char *format;
+ int pe_op = gx_path_enum_next(&cenum, vs);
+
+sw: switch ( pe_op )
+ {
+ case 0: /* done */
+ return 0;
+ case gs_pe_moveto:
+ format = "%g %g m\n";
+ goto do1;
+ case gs_pe_lineto:
+ format = "%g %g l\n";
+do1: vp[0].x = fixed2float(vs[0].x), vp[0].y = fixed2float(vs[0].y);
+ if ( pmat )
+ gs_point_transform_inverse(vp[0].x, vp[0].y, pmat, &vp[0]);
+ pprintg2(s, format, vp[0].x, vp[0].y);
+ break;
+ case gs_pe_curveto:
+ vp[0].x = fixed2float(vs[0].x), vp[0].y = fixed2float(vs[0].y);
+ vp[1].x = fixed2float(vs[1].x), vp[1].y = fixed2float(vs[1].y);
+ vp[2].x = fixed2float(vs[2].x), vp[2].y = fixed2float(vs[2].y);
+ if ( pmat )
+ { gs_point_transform_inverse(vp[0].x, vp[0].y, pmat, &vp[0]);
+ gs_point_transform_inverse(vp[1].x, vp[1].y, pmat, &vp[1]);
+ gs_point_transform_inverse(vp[2].x, vp[2].y, pmat, &vp[2]);
+ }
+ pprintg6(s, "%g %g %g %g %g %g c\n",
+ vp[0].x, vp[0].y, vp[1].x, vp[1].y, vp[2].x, vp[2].y);
+ break;
+ case gs_pe_closepath:
+ if ( do_close )
+ { pputs(s, "h\n");
+ break;
+ }
+ pe_op = gx_path_enum_next(&cenum, vs);
+ if ( pe_op != 0 )
+ { pputs(s, "h\n");
+ goto sw;
+ }
+ return 1;
+ }
+ }
+}
+
+/* Test whether we will need to put the clipping path. */
+bool
+pdf_must_put_clip_path(gx_device_pdf *pdev, const gx_clip_path *pcpath)
+{ if ( pcpath == NULL )
+ return pdev->clip_path_id != pdev->no_clip_path_id;
+ if ( pdev->clip_path_id == pcpath->id )
+ return false;
+ if ( gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
+ int2fixed(pdev->width),
+ int2fixed(pdev->height))
+ )
+ return pdev->clip_path_id != pdev->no_clip_path_id;
+ return true;
+}
+
+/* Put a clipping path on the output file. */
+int
+pdf_put_clip_path(gx_device_pdf *pdev, const gx_clip_path *pcpath)
+{ stream *s = pdev->strm;
+
+ if ( pcpath == NULL ) {
+ if ( pdev->clip_path_id == pdev->no_clip_path_id )
+ return 0;
+ pputs(s, "Q\nq\n");
+ pdev->clip_path_id = pdev->no_clip_path_id;
+ } else {
+ if ( pdev->clip_path_id == pcpath->id )
+ return 0;
+ if ( gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
+ int2fixed(pdev->width),
+ int2fixed(pdev->height))
+ ) {
+ if ( pdev->clip_path_id == pdev->no_clip_path_id )
+ return 0;
+ pputs(s, "Q\nq\n");
+ pdev->clip_path_id = pdev->no_clip_path_id;
+ } else {
+ pputs(s, "Q\nq\nW\n");
+ if ( pcpath->segments_valid )
+ pdf_put_path(pdev, &pcpath->path, true, NULL);
+ else
+ { /* Write out the rectangles. */
+ const gx_clip_rect *prect = pcpath->list.head;
+
+ if ( prect == 0 )
+ prect = &pcpath->list.single;
+ for ( ; prect != 0; prect = prect->next )
+ if ( prect->xmax > prect->xmin && prect->ymax > prect->ymin )
+ pprintg4(s, "%g %g %g %g re\n",
+ prect->xmin, prect->ymin,
+ prect->xmax - prect->xmin,
+ prect->ymax - prect->ymin);
+ }
+ pputs(s, "n\n");
+ pdev->clip_path_id = pcpath->id;
+ }
+ }
+ pdev->text.font = 0;
+ if ( pdev->context == pdf_in_text )
+ pdev->context = pdf_in_stream;
+ pdf_reset_graphics(pdev);
+ return 0;
+}
+
+/* ------ Driver procedures ------ */
+
+/* Fill a path. */
+int
+gdev_pdf_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
+ const gx_fill_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code;
+ /*
+ * HACK: we fill an empty path in order to set the clipping path
+ * and the color for writing text. If it weren't for this, we
+ * could detect and skip empty paths before putting out the clip
+ * path or the color. We also clip with an empty path in order
+ * to advance currentpoint for show operations without actually
+ * drawing anything.
+ */
+ bool have_path;
+
+ /*
+ * Check for an empty clipping path.
+ */
+ if ( pcpath ) {
+ gs_fixed_rect box;
+
+ gx_cpath_outer_box(pcpath, &box);
+ if ( box.p.x >= box.q.x || box.p.y >= box.q.y )
+ return 0; /* empty clipping path */
+ }
+ if ( !gx_dc_is_pure(pdcolor) )
+ return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ /*
+ * Make a special check for the initial fill with white,
+ * which shouldn't cause the page to be opened.
+ */
+ if ( gx_dc_pure_color(pdcolor) == 0xffffff && !is_in_page(pdev) )
+ return 0;
+ have_path = !gx_path_is_void(ppath);
+ if ( have_path || pdev->context == pdf_in_none ||
+ pdf_must_put_clip_path(pdev, pcpath)
+ )
+ { code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ }
+ pdf_put_clip_path(pdev, pcpath);
+ pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->fill_color, "rg");
+ if ( have_path )
+ { stream *s = pdev->strm;
+
+ if ( params->flatness != pdev->flatness )
+ { pprintg1(s, "%g i\n", params->flatness);
+ pdev->flatness = params->flatness;
+ }
+ pdf_put_path(pdev, ppath, false, NULL);
+ pputs(s, (params->rule < 0 ? "f\n" : "f*\n"));
+ }
+ return 0;
+}
+
+/* Compare two dash patterns. */
+private bool
+pdf_dash_pattern_eq(const float *stored, const gx_dash_params *set, float scale)
+{ int i;
+ for ( i = 0; i < set->pattern_size; ++i )
+ if ( stored[i] != (float)(set->pattern[i] * scale) )
+ return false;
+ return true;
+}
+
+/* Stroke a path. */
+int
+gdev_pdf_stroke_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ stream *s;
+ int code;
+ int pattern_size = pis->line_params.dash.pattern_size;
+ double scale;
+ bool set_ctm;
+ gs_matrix mat;
+ const gs_matrix *pmat;
+ int i;
+
+ if ( gx_path_is_void(ppath) )
+ return 0; /* won't mark the page */
+ if ( !gx_dc_is_pure(pdcolor) )
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ /*
+ * If the CTM is not uniform, stroke width depends on angle.
+ * We'd like to avoid resetting the CTM, so we check for uniform
+ * CTMs explicitly. Note that in PDF, unlike PostScript, it is
+ * the CTM at the time of the stroke operation, not the CTM at
+ * the time the path was constructed, that is used for transforming
+ * the points of the path; so if we have to reset the CTM, we must
+ * do it before constructing the path, and inverse-transform all
+ * the coordinates.
+ */
+ if ( pis->ctm.xy == 0 && pis->ctm.yx == 0 )
+ { scale = fabs(pis->ctm.xx);
+ set_ctm = fabs(pis->ctm.yy) != scale;
+ }
+ else if ( pis->ctm.xx == 0 && pis->ctm.yy == 0 )
+ { scale = fabs(pis->ctm.xy);
+ set_ctm = fabs(pis->ctm.yx) != scale;
+ }
+ else if ( (pis->ctm.xx == pis->ctm.yy && pis->ctm.xy == -pis->ctm.yx)||
+ (pis->ctm.xx == -pis->ctm.yy && pis->ctm.xy == pis->ctm.yx)
+ )
+ { scale = hypot(pis->ctm.xx, pis->ctm.xy);
+ set_ctm = false;
+ }
+ else
+ set_ctm = true;
+ if ( set_ctm ) {
+ scale = 1;
+ mat.xx = pis->ctm.xx / pdev->scale.x;
+ mat.xy = pis->ctm.xy / pdev->scale.y;
+ mat.yx = pis->ctm.yx / pdev->scale.x;
+ mat.yy = pis->ctm.yy / pdev->scale.y;
+ mat.tx = mat.ty = 0;
+ pmat = &mat;
+ } else {
+ pmat = 0;
+ }
+
+ pdf_put_clip_path(pdev, pcpath);
+ pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->stroke_color, "RG");
+ s = pdev->strm;
+ if ( (float)(pis->line_params.dash.offset * scale) != pdev->line_params.dash.offset ||
+ pattern_size != pdev->line_params.dash.pattern_size ||
+ pattern_size > max_dash ||
+ (pattern_size != 0 &&
+ !pdf_dash_pattern_eq(pdev->dash_pattern, &pis->line_params.dash,
+ scale))
+ )
+ { pputs(s, "[ ");
+ pdev->line_params.dash.pattern_size = pattern_size;
+ for ( i = 0; i < pattern_size; ++i )
+ { float element = pis->line_params.dash.pattern[i] * scale;
+ if ( i < max_dash )
+ pdev->dash_pattern[i] = element;
+ pprintg1(s, "%g ", element);
+ }
+ pdev->line_params.dash.offset =
+ pis->line_params.dash.offset * scale;
+ pprintg1(s, "] %g d\n", pdev->line_params.dash.offset);
+ }
+ if ( params->flatness != pdev->flatness )
+ { pprintg1(s, "%g i\n", params->flatness);
+ pdev->flatness = params->flatness;
+ }
+ if ( (float)(pis->line_params.half_width * scale) != pdev->line_params.half_width )
+ { pdev->line_params.half_width = pis->line_params.half_width * scale;
+ pprintg1(s, "%g w\n", pdev->line_params.half_width * 2);
+ }
+ if ( pis->line_params.miter_limit != pdev->line_params.miter_limit )
+ { pprintg1(s, "%g M\n", pis->line_params.miter_limit);
+ gx_set_miter_limit(&pdev->line_params,
+ pis->line_params.miter_limit);
+ }
+ if ( pis->line_params.cap != pdev->line_params.cap )
+ { pprintd1(s, "%d J\n", pis->line_params.cap);
+ pdev->line_params.cap = pis->line_params.cap;
+ }
+ if ( pis->line_params.join != pdev->line_params.join )
+ { pprintd1(s, "%d j\n", pis->line_params.join);
+ pdev->line_params.join = pis->line_params.join;
+ }
+ if ( set_ctm )
+ pdf_put_matrix(pdev, "q ", &mat, "cm\n");
+ code = pdf_put_path(pdev, ppath, false, pmat);
+ if ( code < 0 )
+ return code;
+ pputs(s, (code ? "s" : "S"));
+ pputs(s, (set_ctm ? " Q\n" : "\n"));
+ return 0;
+}
diff --git a/gs/src/gdevpdfi.c b/gs/src/gdevpdfi.c
new file mode 100644
index 000000000..133056f50
--- /dev/null
+++ b/gs/src/gdevpdfi.c
@@ -0,0 +1,1023 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdfi.c */
+/* Image handling for PDF-writing driver */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsflip.h"
+#include "gdevpdfx.h"
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gscie.h */
+#include "gscie.h" /* requires gscspace.h */
+#include "gxistate.h"
+#include "strimpl.h"
+#include "sa85x.h"
+#include "scfx.h"
+#include "srlx.h"
+
+/* We need color space types for constructing temporary color spaces. */
+extern const gs_color_space_type
+ gs_color_space_type_DeviceGray,
+ gs_color_space_type_DeviceRGB,
+ gs_color_space_type_DeviceCMYK,
+ gs_color_space_type_Indexed;
+
+/* ---------------- Utilities ---------------- */
+
+/* ------ Binary data ------ */
+
+/* Define the structure for the filters for writing binary data. */
+typedef struct pdf_binary_writer_s {
+ stream *strm;
+ stream es; /* no state for A85E */
+ byte encode_buf[256];
+ stream cs; /* client provides (initialized) state */
+ byte compress_buf[256];
+} pdf_binary_writer;
+
+private const stream_procs filter_write_procs =
+{ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+};
+
+/* Begin writing binary data. */
+/* If css is not NULL, it is the compressor stream state. */
+private int
+pdf_begin_binary(gx_device_pdf *pdev, pdf_binary_writer *pbw,
+ stream_state *css)
+{ stream *s = pdev->strm;
+
+ /* If not binary, set up the encoding stream. */
+ if ( !pdev->binary_ok )
+ { stream *es = &pbw->es;
+ s_std_init(es, pbw->encode_buf, sizeof(pbw->encode_buf),
+ &filter_write_procs, s_mode_write);
+ es->template = &s_A85E_template;
+ es->procs.process = es->template->process;
+ es->strm = s;
+ s = es;
+ }
+ /* If compressing, set up the compression stream. */
+ if ( css )
+ { stream *cs = (stream *)&pbw->cs;
+ const stream_template *template = css->template;
+ s_std_init(cs, pbw->compress_buf, sizeof(pbw->compress_buf),
+ &filter_write_procs, s_mode_write);
+ css->memory = pdev->pdf_memory;
+ cs->state = css;
+ cs->procs.process = template->process;
+ if ( template->init )
+ (*template->init)(css);
+ cs->strm = s;
+ s = cs;
+ }
+ pbw->strm = s;
+ return 0;
+}
+
+/* Finish writing binary data. */
+private int
+pdf_end_binary(gx_device_pdf *pdev, pdf_binary_writer *pbw)
+{ stream *s = pbw->strm;
+
+ /* Close the filters in reverse order. */
+ /* Stop before we try to close the file stream. */
+ while ( s != pdev->strm )
+ { stream *next = s->strm;
+ /* We have to open-code sclose, because we want to release */
+ /* the stream state but not try to free it. */
+ stream_state *st = s->state;
+ stream_proc_release((*release)) = st->template->release;
+ (*s->procs.close)(s);
+ if ( release != 0 )
+ (*release)(st);
+ s = next;
+ }
+ sflush(s); /* flush the file stream buffer */
+ return 0;
+}
+
+/* ------ Images ------ */
+
+/* Test whether a cached CIE procedure is the identity function. */
+#define cie_cache_is_identity(pc)\
+ ((pc)->floats.params.is_identity)
+#define cie_cache3_is_identity(pca)\
+ (cie_cache_is_identity(&(pca)[0]) &&\
+ cie_cache_is_identity(&(pca)[1]) &&\
+ cie_cache_is_identity(&(pca)[2]))
+
+/*
+ * Test whether a cached CIE procedure is an exponential. A cached
+ * procedure is exponential iff f(x) = k*(x^p). We make a very cursory
+ * check for this: we require that f(0) = 0, set k = f(1), set p =
+ * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
+ * two arbitrarily chosen values between 0 and 1. Naturally all this is
+ * done with some slop.
+ */
+#define ia (gx_cie_cache_size / 3)
+#define ib (gx_cie_cache_size * 2 / 3)
+#define iv(i) ((i) / (double)(gx_cie_cache_size - 1))
+#define a iv(ia)
+#define b iv(ib)
+
+private bool
+cie_values_are_exponential(floatp va, floatp vb, floatp k,
+ float *pexpt)
+{ double p;
+
+ if ( fabs(k) < 0.001 )
+ return false;
+ if ( va == 0 || (va > 0) != (k > 0) )
+ return false;
+ p = log(va / k) / log(a);
+ if ( fabs(vb - k * pow(b, p)) >= 0.001 )
+ return false;
+ *pexpt = p;
+ return true;
+}
+
+private bool
+cie_scalar_cache_is_exponential(const gx_cie_scalar_cache *pc, float *pexpt)
+{ double k, va, vb;
+
+ if ( fabs(pc->floats.values[0]) >= 0.001 )
+ return false;
+ k = pc->floats.values[gx_cie_cache_size - 1];
+ va = pc->floats.values[ia];
+ vb = pc->floats.values[ib];
+ return cie_values_are_exponential(va, vb, k, pexpt);
+}
+#define cie_scalar3_cache_is_exponential(pca, expts)\
+ (cie_scalar_cache_is_exponential(&(pca)[0], &(expts)[0]) &&\
+ cie_scalar_cache_is_exponential(&(pca)[1], &(expts)[1]) &&\
+ cie_scalar_cache_is_exponential(&(pca)[2], &(expts)[2]))
+
+private bool
+cie_vector_cache_is_exponential(const gx_cie_vector_cache *pc, float *pexpt)
+{ double k, va, vb;
+
+ if ( fabs(pc->vecs.values[0].u) >= 0.001 )
+ return false;
+ k = pc->vecs.values[gx_cie_cache_size - 1].u;
+ va = pc->vecs.values[ia].u;
+ vb = pc->vecs.values[ib].u;
+ return cie_values_are_exponential(va, vb, k, pexpt);
+}
+#define cie_vector3_cache_is_exponential(pca, expts)\
+ (cie_vector_cache_is_exponential(&(pca)[0], &(expts)[0]) &&\
+ cie_vector_cache_is_exponential(&(pca)[1], &(expts)[1]) &&\
+ cie_vector_cache_is_exponential(&(pca)[2], &(expts)[2]))
+
+#undef ia
+#undef ib
+#undef iv
+#undef a
+#undef b
+
+/* Define the long and short versions of the keys in an image dictionary, */
+/* and other strings for images. */
+typedef struct pdf_image_names_s {
+ const char *ASCII85Decode;
+ const char *BitsPerComponent;
+ const char *CalCMYK;
+ const char *CalGray;
+ const char *CalRGB;
+ const char *CCITTFaxDecode;
+ const char *ColorSpace;
+ const char *Decode;
+ const char *DecodeParms;
+ const char *DeviceCMYK;
+ const char *DeviceGray;
+ const char *DeviceRGB;
+ const char *Filter;
+ const char *Height;
+ const char *ImageMask;
+ const char *Indexed;
+ const char *Interpolate;
+ const char *Width;
+} pdf_image_names;
+private const pdf_image_names image_names_full = {
+ "/ASCII85Decode", "/BitsPerComponent",
+ "/CalCMYK", "/CalGray", "/CalRGB", "/CCITTFaxDecode", "/ColorSpace",
+ "/Decode", "/DecodeParms", "/DeviceCMYK", "/DeviceGray", "/DeviceRGB",
+ "/Filter", "/Height", "/ImageMask", "/Indexed", "/Interpolate", "/Width",
+};
+private const pdf_image_names image_names_short = {
+ "/A85", "/BPC",
+ /* We need CalRGB to work around a bug in some Adobe products. */
+ "/CC", "/CG", /*"/CR"*/ "/CalRGB", "/CCF", "/CS",
+ "/D", "/DP", "/CMYK", "/G", "/RGB",
+ "/F", "/H", "/IM", "/I", "/I", "/W",
+};
+
+/* Write out image parameters for either an in-line image or image resource. */
+/* decode_parms, if supplied, must start with /, [, or <<. */
+private int
+pdf_write_image_params(gx_device_pdf *pdev, const gs_image_t *pim,
+ const char *filter_name, const char *decode_parms,
+ const pdf_image_names *pin)
+{ stream *s = pdev->strm;
+ const gs_color_space *pcs = pim->ColorSpace;
+ const char *cs_name;
+ int num_components;
+ float indexed_decode[2];
+ const float *default_decode = NULL;
+
+ if ( pim->ImageMask )
+ { pprints1(s, "%s true", pin->ImageMask);
+ pdev->procsets |= ImageB;
+ num_components = 1;
+ }
+ else
+ { const gs_color_space *pbcs = pcs;
+ const gs_indexed_params *pip = 0;
+ const gs_cie_common *pciec;
+
+ pputs(s, pin->ColorSpace);
+csw: switch ( gs_color_space_get_index(pbcs) )
+ {
+ case gs_color_space_index_DeviceGray:
+ pdev->procsets |= ImageB;
+ cs_name = pin->DeviceGray;
+ break;
+ case gs_color_space_index_DeviceRGB:
+ pdev->procsets |= ImageC;
+ cs_name = pin->DeviceRGB;
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ pdev->procsets |= ImageC;
+ cs_name = pin->DeviceCMYK;
+ break;
+ case gs_color_space_index_CIEA:
+ pdev->procsets |= ImageB;
+ pprints1(s, "[%s<<", pin->CalGray);
+ { const gs_cie_a *pcie = pbcs->params.a;
+ float expts[3];
+
+ if ( cie_cache3_is_identity(pcie->common.caches.DecodeLMN) )
+ cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts[0]);
+ else
+ discard(cie_scalar3_cache_is_exponential(pcie->common.caches.DecodeLMN, expts));
+ if ( expts[0] != 1 )
+ pprintg1(s, "/Gamma %g", expts[0]);
+ pciec = (const gs_cie_common *)pcie;
+ }
+cal: pprintg3(s, "/WhitePoint[%g %g %g]",
+ pciec->points.WhitePoint.u,
+ pciec->points.WhitePoint.v,
+ pciec->points.WhitePoint.w);
+ if ( pciec->points.BlackPoint.u != 0 ||
+ pciec->points.BlackPoint.v != 0 ||
+ pciec->points.BlackPoint.w != 0
+ )
+ pprintg3(s, "/BlackPoint[%g %g %g]",
+ pciec->points.BlackPoint.u,
+ pciec->points.BlackPoint.v,
+ pciec->points.BlackPoint.w);
+ pputs(s, ">>]");
+ cs_name = 0;
+ break;
+ case gs_color_space_index_CIEABC:
+ pdev->procsets |= ImageC;
+ pprints1(s, "[%s<<", pin->CalRGB);
+ { const gs_cie_abc *pcie = pbcs->params.abc;
+ const gs_matrix3 *pmat;
+ float expts[3];
+
+ if ( pcie->common.MatrixLMN.is_identity &&
+ cie_cache3_is_identity(pcie->common.caches.DecodeLMN)
+ ) {
+ discard(cie_vector3_cache_is_exponential(pcie->caches.DecodeABC, expts));
+ pmat = &pcie->MatrixABC;
+ } else {
+ discard(cie_scalar3_cache_is_exponential(pcie->common.caches.DecodeLMN, expts));
+ pmat = &pcie->common.MatrixLMN;
+ }
+ if ( expts[0] != 1 || expts[1] != 1 || expts[2] != 1 )
+ pprintg3(s, "/Gamma[%g %g %g]", expts[0], expts[1],
+ expts[2]);
+ if ( !pmat->is_identity ) {
+ pprintg3(s, "/Matrix[%g %g %g",
+ pmat->cu.u, pmat->cu.v, pmat->cu.w);
+ pprintg6(s, " %g %g %g %g %g %g]",
+ pmat->cv.u, pmat->cv.v, pmat->cv.w,
+ pmat->cw.u, pmat->cw.v, pmat->cw.w);
+ }
+ pciec = (const gs_cie_common *)pcie;
+ }
+ goto cal;
+ case gs_color_space_index_Indexed:
+ pdev->procsets |= ImageI;
+ pprints1(s, "[%s", pin->Indexed);
+ pip = &pcs->params.indexed;
+ pbcs = (const gs_color_space *)&pip->base_space;
+ indexed_decode[0] = 0;
+ indexed_decode[1] = (1 << pim->BitsPerComponent) - 1;
+ default_decode = indexed_decode;
+ goto csw;
+ default: /* shouldn't happen */
+ return_error(gs_error_rangecheck);
+ }
+ if ( cs_name )
+ pprints1(s, " %s", cs_name);
+ num_components = gs_color_space_num_components(pbcs);
+ if ( pip )
+ { register const char _ds *hex_digits = "0123456789abcdef";
+ int i;
+
+ pprintd1(s, " %d\n<", pip->hival);
+ for ( i = 0; i < (pip->hival + 1) * num_components; ++i )
+ { byte b = pip->lookup.table.data[i];
+ pputc(s, hex_digits[b >> 4]);
+ pputc(s, hex_digits[b & 0xf]);
+ }
+ pputs(s, ">\n]");
+ num_components = 1;
+ }
+ }
+/* Some compilers try to substitute macro args in string literals! */
+#define pprintsd(strm, str, v)\
+ (pputs(strm, str), pprintd1(strm, " %d", v))
+ pprintsd(s, pin->Width, pim->Width);
+ pprintsd(s, pin->Height, pim->Height);
+ pprintsd(s, pin->BitsPerComponent, pim->BitsPerComponent);
+#undef pprintsd
+ { int i;
+ for ( i = 0; i < num_components * 2; ++i )
+ if ( pim->Decode[i] !=
+ (default_decode ? default_decode[i] : i & 1)
+ )
+ break;
+ if ( i < num_components * 2 )
+ { char sepr = '[';
+ pputs(s, pin->Decode);
+ for ( i = 0; i < num_components * 2; sepr = ' ', ++i )
+ { pputc(s, sepr);
+ pprintg1(s, "%g", pim->Decode[i]);
+ }
+ pputc(s, ']');
+ }
+ }
+ if ( pim->Interpolate )
+ pprints1(s, "%s true", pin->Interpolate);
+ if ( filter_name )
+ { if ( pdev->binary_ok )
+ pprints2(s, "%s%s", pin->Filter, filter_name);
+ else
+ pprints3(s, "%s[%s%s]", pin->Filter, pin->ASCII85Decode,
+ filter_name);
+ if ( decode_parms )
+ pprints2(s,
+ (pdev->binary_ok ? "%s%s" : "%s[null%s]"),
+ pin->DecodeParms, decode_parms);
+ }
+ else if ( !pdev->binary_ok )
+ pprints2(s, "%s%s", pin->Filter, pin->ASCII85Decode);
+ return 0;
+}
+
+/* Fill in the image parameters for a device space bitmap. */
+/* PDF images are always specified top-to-bottom. */
+private void
+pdf_make_bitmap_matrix(gs_matrix *pmat, int x, int y, int w, int h)
+{ pmat->xx = w;
+ pmat->xy = 0;
+ pmat->yx = 0;
+ pmat->yy = -h;
+ pmat->tx = x;
+ pmat->ty = y + h;
+}
+private void
+pdf_make_bitmap_image(gs_image_t *pim, int x, int y, int w, int h)
+{ pim->Width = w;
+ pim->Height = h;
+ pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h);
+}
+
+/* Put out the gsave and matrix for an image. */
+private void
+pdf_put_image_matrix(gx_device_pdf *pdev, const gs_matrix *pmat)
+{ pdf_put_matrix(pdev, "q\n", pmat, "cm\n");
+}
+
+/* ------ Image writing ------ */
+
+/* Define the structure for writing an image. */
+typedef struct pdf_image_writer_s {
+ pdf_binary_writer binary;
+ const pdf_image_names *pin;
+ const char *begin_data;
+ pdf_resource *pres; /* XObject resource iff not in-line */
+ long length_id; /* id of length object (forward reference) */
+ long start_pos; /* starting file position of data */
+} pdf_image_writer;
+
+/* Begin writing an image. */
+private int
+pdf_begin_write_image(gx_device_pdf *pdev, pdf_image_writer *piw, bool in_line)
+{ if ( in_line )
+ { stream *s = pdev->strm;
+
+ piw->pres = 0;
+ pputs(s, "BI\n");
+ piw->pin = &image_names_short;
+ piw->begin_data = (pdev->binary_ok ? "ID " : "ID\n");
+ }
+ else
+ { int code = pdf_begin_resource(pdev, resourceXObject, gs_no_id,
+ &piw->pres);
+ stream *s = pdev->strm;
+
+ if ( code < 0 )
+ return code;
+ piw->length_id = pdf_obj_ref(pdev);
+ pprintld1(s, " /Subtype /Image /Length %ld 0 R\n",
+ piw->length_id);
+ piw->pin = &image_names_full;
+ piw->begin_data = ">>\nstream\n";
+ }
+ return 0;
+}
+
+/* Begin writing the image data. */
+private int
+pdf_begin_image_data(gx_device_pdf *pdev, pdf_image_writer *piw,
+ const gs_image_t *pim, const char *filter_name, const char *decode_parms)
+{ stream *s = pdev->strm;
+ int code = pdf_write_image_params(pdev, pim, filter_name, decode_parms,
+ piw->pin);
+
+ if ( code < 0 )
+ return code;
+ pprints1(s, "\n%s", piw->begin_data);
+ piw->start_pos = pdf_stell(pdev);
+ return 0;
+}
+
+/* Finish writing an image. */
+/* Return 0 if resource, 1 if in-line, or an error code. */
+private int
+pdf_end_write_image(gx_device_pdf *pdev, pdf_image_writer *piw)
+{ stream *s = pdev->strm;
+
+ if ( piw->pres ) /* image resource */
+ { long length;
+
+ pputs(s, "\n");
+ length = pdf_stell(pdev) - piw->start_pos;
+ pputs(s, "endstream\n");
+ pdf_end_resource(pdev);
+ pdf_open_separate(pdev, piw->length_id);
+ s = pdev->strm;
+ pprintld1(s, "%ld\n", length);
+ pdf_end_separate(pdev);
+ return 0;
+ }
+ else /* in-line image */
+ { pputs(s, "\nEI\nQ\n");
+ return 1;
+ }
+}
+
+/* Put out a reference to an image resource. */
+private int
+pdf_do_image(gx_device_pdf *pdev, const pdf_resource *pres,
+ const gs_matrix *pimat)
+{ int code = pdf_open_contents(pdev, pdf_in_stream);
+
+ if ( code < 0 )
+ return code;
+ if ( pimat )
+ pdf_put_image_matrix(pdev, pimat);
+ pprintld1(pdev->strm, "/R%ld Do\nQ\n", pres->id);
+ return 0;
+}
+
+/* ---------------- Driver procedures ---------------- */
+
+/* ------ Low-level calls ------ */
+
+/* Copy a monochrome bitmap or mask. */
+int
+gdev_pdf_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code;
+ gs_color_space cs;
+ byte palette[6];
+ gs_image_t image;
+ int yi;
+ pdf_image_writer writer;
+ pdf_stream_position ipos;
+ pdf_resource *pres = 0;
+ byte invert = 0;
+
+ if ( w <= 0 || h <= 0 )
+ return 0;
+ /* Make sure we aren't being clipped. */
+ if ( pdf_must_put_clip_path(pdev, NULL) )
+ { code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ pdf_put_clip_path(pdev, NULL);
+ }
+ /* We have 3 cases: mask, inverse mask, and solid. */
+ if ( zero == gx_no_color_index )
+ { if ( one == gx_no_color_index )
+ return 0;
+ /* If a mask has an id, assume it's a character. */
+ if ( id != gx_no_bitmap_id && sourcex == 0 )
+ { pdf_set_color(pdev, one, &pdev->fill_color, "rg");
+ pres = pdf_find_resource_by_gs_id(pdev, resourceCharProc, id);
+ if ( pres == 0 )
+ { /* Define the character in an embedded font. */
+ pdf_char_proc *pcp;
+ int y_offset;
+ int max_y_offset =
+ (pdev->open_font == 0 ? 0 :
+ pdev->open_font->max_y_offset);
+
+ gs_image_t_init_mask(&image, false);
+ invert = 0xff;
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ y_offset =
+ image.ImageMatrix.ty - (int)(pdev->text.current.y + 0.5);
+ if ( x < pdev->text.current.x ||
+ y_offset < -max_y_offset || y_offset > max_y_offset
+ )
+ y_offset = 0;
+ /*
+ * The Y axis of the text matrix is inverted,
+ * so we need to negate the Y offset appropriately.
+ */
+ code = pdf_begin_char_proc(pdev, w, h, 0, y_offset, id,
+ &pcp, &ipos);
+ if ( code < 0 )
+ return code;
+ y_offset = -y_offset;
+ pprintd3(pdev->strm, "0 0 0 %d %d %d d1\n", y_offset,
+ w, h + y_offset);
+ pprintd3(pdev->strm, "%d 0 0 %d 0 %d cm\n", w, h,
+ y_offset);
+ code = pdf_begin_write_image(pdev, &writer, true);
+ if ( code < 0 )
+ return code;
+ pcp->rid = id;
+ pres = (pdf_resource *)pcp;
+ goto wr;
+ }
+ pdf_make_bitmap_matrix(&image.ImageMatrix, x, y, w, h);
+ goto rx;
+ }
+ pdf_set_color(pdev, one, &pdev->fill_color, "rg");
+ gs_image_t_init_mask(&image, false);
+ invert = 0xff;
+ }
+ else if ( one == gx_no_color_index )
+ { gs_image_t_init_mask(&image, false);
+ pdf_set_color(pdev, zero, &pdev->fill_color, "rg");
+ }
+ else if ( zero == 0 && one == 0xffffff )
+ { gs_image_t_init_gray(&image);
+ }
+ else if ( zero == 0xffffff && one == 0 )
+ { gs_image_t_init_gray(&image);
+ invert = 0xff;
+ }
+ else
+ { gs_image_t_init_color(&image);
+ cs.type = &gs_color_space_type_Indexed;
+ cs.params.indexed.hival = 1;
+ palette[0] = (byte)(zero >> 16);
+ palette[1] = (byte)(zero >> 8);
+ palette[2] = (byte)(zero);
+ palette[3] = (byte)(one >> 16);
+ palette[4] = (byte)(one >> 8);
+ palette[5] = (byte)(one);
+ cs.params.indexed.lookup.table.data = palette;
+ cs.params.indexed.lookup.table.size = 6;
+ cs.params.indexed.use_proc = false;
+ image.BitsPerComponent = 1;
+ image.ColorSpace = &cs;
+ }
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ { ulong nbytes = (ulong)((w + 7) >> 3) * h;
+ bool in_line = nbytes <= 4000;
+
+ if ( in_line )
+ pdf_put_image_matrix(pdev, &image.ImageMatrix);
+ code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ code = pdf_begin_write_image(pdev, &writer, in_line);
+ if ( code < 0 )
+ return code;
+ }
+wr: /*
+ * There are 3 different cases at this point:
+ * - Writing an in-line image (pres == 0, writer.pres == 0);
+ * - Writing an XObject image (pres == 0, writer.pres != 0);
+ * - Writing the image for a CharProc (pres != 0).
+ * We handle them with in-line code followed by a switch,
+ * rather than making the shared code into a procedure,
+ * simply because there would be an awful lot of parameters
+ * that would need to be passed.
+ */
+ { char decode_parms[80];
+
+ sprintf(decode_parms,
+ "<</K -1/Columns %d%s>>",
+ w, (invert ? "" : "/BlackIs1 true"));
+ pdf_begin_image_data(pdev, &writer, &image,
+ writer.pin->CCITTFaxDecode, decode_parms);
+ }
+ { stream_CFE_state csstate;
+ csstate.template = &s_CFE_template;
+ (*csstate.template->set_defaults)((stream_state *)&csstate);
+ csstate.K = -1;
+ csstate.Columns = w;
+ csstate.Rows = h;
+ csstate.BlackIs1 = invert == 0;
+ pdf_begin_binary(pdev, &writer.binary, (stream_state *)&csstate);
+ for ( yi = 0; yi < h; ++yi )
+ { const byte *data = base + yi * raster + (sourcex >> 3);
+ int sbit = sourcex & 7;
+
+ if ( sbit == 0 )
+ { int nbytes = (w + 7) >> 3;
+ int i;
+
+ for ( i = 0; i < nbytes; ++data, ++i )
+ sputc(writer.binary.strm, *data ^ invert);
+ }
+ else
+ { int wleft = w;
+ int rbit = 8 - sbit;
+
+ for ( ; wleft + sbit > 8; ++data, wleft -= 8 )
+ sputc(writer.binary.strm,
+ ((*data << sbit) + (data[1] >> rbit)) ^ invert);
+ if ( wleft > 0 )
+ sputc(writer.binary.strm,
+ ((*data << sbit) ^ invert) &
+ (byte)(0xff00 >> wleft));
+ }
+ }
+ pdf_end_binary(pdev, &writer.binary);
+ }
+ if ( !pres )
+ { switch ( pdf_end_write_image(pdev, &writer) )
+ {
+ default: /* error */
+ return code;
+ case 1:
+ return 0;
+ case 0:
+ return pdf_do_image(pdev, writer.pres, &image.ImageMatrix);
+ }
+ }
+ pputs(pdev->strm, "\nEI\n");
+ code = pdf_end_char_proc(pdev, &ipos);
+ if ( code < 0 )
+ return code;
+rx: { gs_matrix imat;
+
+ imat = image.ImageMatrix;
+ imat.xx /= w;
+ imat.xy /= h;
+ imat.yx /= w;
+ imat.yy /= h;
+ return pdf_do_char_image(pdev, (const pdf_char_proc *)pres, &imat);
+ }
+}
+
+/* Copy a color bitmap. */
+int
+gdev_pdf_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int depth = dev->color_info.depth;
+ int bytes_per_pixel = depth >> 3;
+ int code = pdf_open_page(pdev, pdf_in_stream);
+ int yi;
+ gs_image_t image;
+ gs_color_space cs;
+ pdf_image_writer writer;
+ ulong nbytes;
+
+ if ( code < 0 )
+ return code;
+ if ( w <= 0 || h <= 0 )
+ return 0;
+ /* Make sure we aren't being clipped. */
+ pdf_put_clip_path(pdev, NULL);
+ gs_image_t_init_color(&image);
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ image.BitsPerComponent = 8;
+ cs.type = (bytes_per_pixel == 3 ? &gs_color_space_type_DeviceRGB :
+ bytes_per_pixel == 4 ? &gs_color_space_type_DeviceCMYK :
+ &gs_color_space_type_DeviceGray);
+ image.ColorSpace = &cs;
+ nbytes = (ulong)w * bytes_per_pixel * h;
+ pdf_put_image_matrix(pdev, &image.ImageMatrix);
+ code = pdf_begin_write_image(pdev, &writer, nbytes <= 4000);
+ if ( code < 0 )
+ return code;
+ code = pdf_begin_image_data(pdev, &writer, &image, NULL, NULL);
+ if ( code < 0 )
+ return code;
+ pdf_begin_binary(pdev, &writer.binary, NULL);
+ for ( yi = 0; yi < h; ++yi )
+ { uint ignore;
+ sputs(writer.binary.strm,
+ base + sourcex * bytes_per_pixel + yi * raster,
+ w * bytes_per_pixel, &ignore);
+ }
+ pdf_end_binary(pdev, &writer.binary);
+ code = pdf_end_write_image(pdev, &writer);
+ switch ( code )
+ {
+ default: return code; /* error */
+ case 1: return 0;
+ case 0: ;
+ }
+ return pdf_do_image(pdev, writer.pres, &image.ImageMatrix);
+}
+
+/* Fill a mask. */
+int
+gdev_pdf_fill_mask(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code;
+
+ if ( width <= 0 || height <= 0 )
+ return 0;
+ if ( depth > 1 || !gx_dc_is_pure(pdcolor) != 0 )
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, width, height, pdcolor, depth, lop,
+ pcpath);
+ if ( pdf_must_put_clip_path(pdev, pcpath) )
+ { code = pdf_open_page(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ pdf_put_clip_path(pdev, pcpath);
+ }
+ return gdev_pdf_copy_mono(dev, data, data_x, raster, id,
+ x, y, width, height,
+ gx_no_color_index,
+ gx_dc_pure_color(pdcolor));
+}
+
+/* ------ High-level calls ------ */
+
+/* Define the structure for keeping track of progress through an image. */
+typedef struct pdf_image_enum_s {
+ gs_memory_t *memory;
+ void *default_info;
+ int width;
+ int num_planes;
+ int bits_per_pixel; /* bits per pixel (per plane) */
+ int rows_left;
+ pdf_image_writer writer;
+} pdf_image_enum;
+/* We can disregard the pointers in the writer by allocating */
+/* the image enumerator as immovable. This is a hack, of course. */
+gs_private_st_ptrs1(st_pdf_image_enum, pdf_image_enum, "pdf_image_enum",
+ pdf_image_enum_enum_ptrs, pdf_image_enum_reloc_ptrs, default_info);
+
+/* Test whether we can handle a given color space. */
+private bool
+pdf_can_handle_color_space(const gs_color_space *pcs)
+{ gs_color_space_index index = gs_color_space_get_index(pcs);
+
+ if ( index == gs_color_space_index_Indexed )
+ { if ( pcs->params.indexed.use_proc )
+ return false;
+ index =
+ gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
+ }
+ switch ( index ) {
+ case gs_color_space_index_DeviceGray:
+ case gs_color_space_index_DeviceRGB:
+ case gs_color_space_index_DeviceCMYK:
+ return true;
+ case gs_color_space_index_Separation:
+ case gs_color_space_index_Pattern:
+ return false; /****** OK in PDF 1.2 ******/
+ case gs_color_space_index_CIEA:
+ { /* Check that we can represent this as a CalGray space. */
+ const gs_cie_a *pcie = pcs->params.a;
+ float expts[3];
+
+ return (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
+ pcie->MatrixA.w == 1 &&
+ pcie->common.MatrixLMN.is_identity &&
+ ((cie_cache_is_identity(&pcie->caches.DecodeA) &&
+ cie_scalar3_cache_is_exponential(pcie->common.caches.DecodeLMN, expts) &&
+ expts[1] == expts[0] && expts[2] == expts[0]) ||
+ (cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts[0]) &&
+ cie_cache3_is_identity(pcie->common.caches.DecodeLMN)))
+ );
+ }
+ case gs_color_space_index_CIEABC:
+ { /* Check that we can represent this as a CalRGB space. */
+ const gs_cie_abc *pcie = pcs->params.abc;
+ float expts[3];
+
+ return ((cie_cache3_is_identity(pcie->caches.DecodeABC) &&
+ pcie->MatrixABC.is_identity &&
+ cie_scalar3_cache_is_exponential(pcie->common.caches.DecodeLMN, expts)) ||
+ (cie_vector3_cache_is_exponential(pcie->caches.DecodeABC, expts) &&
+ cie_cache3_is_identity(pcie->common.caches.DecodeLMN) &&
+ pcie->common.MatrixLMN.is_identity)
+ );
+ }
+ default: /* CIEBasedDEF[G], LL3 spaces */
+ return false;
+ }
+}
+
+/* Start processing an image. */
+int
+gdev_pdf_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, void **pinfo)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code = pdf_open_page(pdev, pdf_in_stream);
+ pdf_image_enum *pie;
+ const gs_color_space *pcs = pim->ColorSpace;
+ int num_components =
+ (pim->ImageMask ? 1 : gs_color_space_num_components(pcs));
+ gs_int_rect rect;
+ ulong nbytes;
+
+ if ( code < 0 )
+ return code;
+ if ( prect )
+ rect = *prect;
+ else
+ { rect.p.x = rect.p.y = 0;
+ rect.q.x = pim->Width, rect.q.y = pim->Height;
+ }
+ /* See above for why we allocate the enumerator as immovable. */
+ pie = gs_alloc_struct_immovable(mem, pdf_image_enum,
+ &st_pdf_image_enum,
+ "pdf_begin_image");
+ if ( pie == 0 )
+ return_error(gs_error_VMerror);
+ pie->memory = mem;
+ *pinfo = pie;
+ if ( (pim->ImageMask ?
+ (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
+ !pdf_can_handle_color_space(pim->ColorSpace)) ||
+ prect
+ )
+ { int code = gx_default_begin_image(dev, pis, pim, format, prect,
+ pdcolor, pcpath, mem,
+ &pie->default_info);
+ if ( code < 0 )
+ gs_free_object(mem, pie, "pdf_begin_image");
+ return code;
+ }
+ pie->default_info = 0;
+ pie->width = rect.q.x - rect.p.x;
+ switch ( format )
+ {
+ case gs_image_format_chunky:
+ pie->num_planes = 1; break;
+ case gs_image_format_component_planar:
+ pie->num_planes = num_components; break;
+ case gs_image_format_bit_planar:
+ pie->num_planes = num_components * pim->BitsPerComponent; break;
+ }
+ pie->bits_per_pixel =
+ pim->BitsPerComponent * num_components / pie->num_planes;
+ pie->rows_left = rect.q.y - rect.p.y;
+ pdf_put_clip_path(pdev, pcpath);
+ if ( pim->ImageMask )
+ pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->fill_color,
+ "rg");
+ /****** DOESN'T DO COMPRESSION YET ******/
+ { gs_matrix mat;
+ gs_matrix bmat;
+ int code;
+
+ pdf_make_bitmap_matrix(&bmat, -rect.p.x, -rect.p.y,
+ pim->Width, pim->Height);
+ if ( (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&bmat, &mat, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0
+ )
+ { gs_free_object(mem, pie, "pdf_begin_image");
+ return code;
+ }
+ pdf_put_image_matrix(pdev, &mat);
+ }
+ nbytes = (((ulong)pie->width * pie->bits_per_pixel + 7) >> 3) *
+ pie->rows_left;
+ code = pdf_begin_write_image(pdev, &pie->writer, nbytes <= 4000);
+ if ( code < 0 )
+ return code;
+ code = pdf_begin_image_data(pdev, &pie->writer, pim, NULL, NULL);
+ if ( code < 0 )
+ return code;
+ pdf_begin_binary(pdev, &pie->writer.binary, NULL);
+ return 0;
+}
+
+/* Process the next piece of an image. */
+int
+gdev_pdf_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ pdf_image_enum *pie = info;
+ int h = height;
+ uint y_offset = 0;
+ uint bcount;
+ uint ignore;
+ int nplanes = pie->num_planes;
+#define row_bytes 180 /* must be 0 mod 3, 4, 6, 9 */
+ byte row[row_bytes];
+
+ if ( pie->default_info )
+ return gx_default_image_data(dev, pie->default_info, planes, data_x,
+ raster, height);
+ if ( h > pie->rows_left )
+ h = pie->rows_left;
+ pie->rows_left -= h;
+ bcount = ((data_x + pie->width) * pie->bits_per_pixel + 7) >> 3;
+ for ( ; h > 0; y_offset += raster, --h )
+ { if ( nplanes > 1 )
+ { /* Flip the data in blocks before writing. */
+ uint offset = y_offset;
+ uint count = bcount;
+
+ while ( count )
+ { uint flip_count = min(count, row_bytes / nplanes);
+ image_flip_planes(row, planes, offset, flip_count, nplanes,
+ pie->bits_per_pixel);
+ sputs(pie->writer.binary.strm, row, flip_count * nplanes,
+ &ignore);
+ count -= flip_count;
+ offset += flip_count;
+ }
+ }
+ else
+ sputs(pie->writer.binary.strm, planes[0] + y_offset, bcount,
+ &ignore);
+ }
+ return !pie->rows_left;
+#undef row_bytes
+}
+
+/* Clean up by releasing the buffers. */
+int
+gdev_pdf_end_image(gx_device *dev, void *info, bool draw_last)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ pdf_image_enum *pie = info;
+ int code;
+
+ if ( pie->default_info )
+ code = gx_default_end_image(dev, pie->default_info, draw_last);
+ else
+ { code = pdf_end_binary(pdev, &pie->writer.binary);
+ if ( code < 0 )
+ return code;
+ code = pdf_end_write_image(pdev, &pie->writer);
+ switch ( code )
+ {
+ default: return code; /* error */
+ case 1: return 0;
+ case 0: ;
+ }
+ code = pdf_do_image(pdev, pie->writer.pres, NULL);
+ }
+ gs_free_object(pie->memory, pie, "pdf_end_image");
+ return code;
+}
diff --git a/gs/src/gdevpdfm.c b/gs/src/gdevpdfm.c
new file mode 100644
index 000000000..66cc7c338
--- /dev/null
+++ b/gs/src/gdevpdfm.c
@@ -0,0 +1,788 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdfm.c */
+/* pdfmark processing for PDF-writing driver */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gdevpdfx.h"
+#include "scanchar.h"
+
+/* GC descriptors */
+private_st_pdf_article();
+private_st_pdf_named_dest();
+
+/*
+ * The pdfmark pseudo-parameter indicates the occurrence of a pdfmark
+ * operator in the input file. Its "value" is the arguments of the operator,
+ * passed through essentially unchanged:
+ * (key, value)*, CTM, type
+ */
+
+/*
+ * Define the pdfmark types we know about.
+ */
+#define pdfmark_proc(proc)\
+ int proc(P4(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,\
+ const gs_matrix *pctm))
+typedef struct pdfmark_name_s {
+ const char *mname;
+ pdfmark_proc((*proc));
+} pdfmark_name;
+private pdfmark_proc(pdfmark_ANN);
+private pdfmark_proc(pdfmark_LNK);
+private pdfmark_proc(pdfmark_OUT);
+private pdfmark_proc(pdfmark_ARTICLE);
+private pdfmark_proc(pdfmark_DEST);
+private pdfmark_proc(pdfmark_PS);
+private pdfmark_proc(pdfmark_PAGES);
+private pdfmark_proc(pdfmark_PAGE);
+private pdfmark_proc(pdfmark_DOCINFO);
+private pdfmark_proc(pdfmark_DOCVIEW);
+private const pdfmark_name mark_names[] = {
+ { "ANN", pdfmark_ANN },
+ { "LNK", pdfmark_LNK },
+ { "OUT", pdfmark_OUT },
+ { "ARTICLE", pdfmark_ARTICLE },
+ { "DEST", pdfmark_DEST },
+ { "PS", pdfmark_PS },
+ { "PAGES", pdfmark_PAGES },
+ { "PAGE", pdfmark_PAGE },
+ { "DOCINFO", pdfmark_DOCINFO },
+ { "DOCVIEW", pdfmark_DOCVIEW },
+ { 0, 0 }
+};
+
+/* ---------------- Public entry points ---------------- */
+
+/* Compare a C string and a gs_param_string. */
+bool
+pdf_key_eq(const gs_param_string *pcs, const char *str)
+{ return (strlen(str) == pcs->size &&
+ !strncmp(str, (const char *)pcs->data, pcs->size));
+}
+
+/* Process a pdfmark. */
+int
+pdfmark_process(gx_device_pdf *pdev, const gs_param_string_array *pma)
+{ const gs_param_string *data = pma->data;
+ uint size = pma->size;
+ const gs_param_string *pts = &data[size - 1];
+ gs_matrix ctm;
+ int i;
+
+ if ( (size & 1) || size < 2 ||
+ sscanf((const char *)pts[-1].data, "[%g %g %g %g %g %g]",
+ &ctm.xx, &ctm.xy, &ctm.yx, &ctm.yy, &ctm.tx, &ctm.ty) != 6
+ )
+ return_error(gs_error_rangecheck);
+ /*
+ * Our coordinate system is scaled so that user space is always
+ * default user space. Adjust the CTM to match this.
+ */
+ { double xscale = 72.0 / pdev->HWResolution[0],
+ yscale = 72.0 / pdev->HWResolution[1];
+
+ ctm.xx *= xscale, ctm.xy *= yscale;
+ ctm.yx *= xscale, ctm.yy *= yscale;
+ ctm.tx *= xscale, ctm.ty *= yscale;
+ }
+ for ( i = 0; mark_names[i].mname != 0; ++i )
+ if ( pdf_key_eq(pts, mark_names[i].mname) )
+ return (*mark_names[i].proc)(pdev, data, size - 2, &ctm);
+ return 0;
+}
+
+/* ---------------- Utilities ---------------- */
+
+/* Find a key in a dictionary. */
+private bool
+pdfmark_find_key(const char *key, const gs_param_string *pairs, uint count,
+ gs_param_string *pstr)
+{ uint i;
+ for ( i = 0; i < count; i += 2 )
+ if ( pdf_key_eq(&pairs[i], key) )
+ { *pstr = pairs[i + 1];
+ return true;
+ }
+ pstr->data = 0;
+ pstr->size = 0;
+ return false;
+}
+
+/* Scan an integer out of a parameter string. */
+private int
+pdfmark_scan_int(const gs_param_string *pstr, int *pvalue)
+{
+#define max_int_str 20
+ uint size = pstr->size;
+ char str[max_int_str + 1];
+
+ if ( size > max_int_str )
+ return_error(gs_error_limitcheck);
+ memcpy(str, pstr->data, size);
+ str[size] = 0;
+ return(sscanf(str, "%d", pvalue) == 1 ? 0 :
+ gs_note_error(gs_error_rangecheck));
+#undef max_int_str
+}
+
+/*
+ * Get the page number for a page referenced by number or as /Next or /Prev.
+ * The result may be 0 if the page number is 0 or invalid.
+ */
+private int
+pdfmark_page_number(gx_device_pdf *pdev, const gs_param_string *pnstr)
+{ int page = pdev->next_page + 1;
+
+ if ( pnstr->data == 0 )
+ ;
+ else if ( pdf_key_eq(pnstr, "/Next") )
+ ++page;
+ else if ( pdf_key_eq(pnstr, "/Prev") )
+ --page;
+ else if ( pdfmark_scan_int(pnstr, &page) < 0 )
+ page = 0;
+ return page;
+}
+
+/* Construct a destination string specified by /Page and/or /View. */
+/* Return 0 if none (but still fill in a default), 1 if present, */
+/* <0 if error. */
+private int
+pdfmark_make_dest(char dstr[max_dest_string], gx_device_pdf *pdev,
+ const gs_param_string *pairs, uint count)
+{ gs_param_string page_string, view_string;
+ bool present =
+ pdfmark_find_key("Page", pairs, count, &page_string) |
+ pdfmark_find_key("View", pairs, count, &view_string);
+ int page = pdfmark_page_number(pdev, &page_string);
+ gs_param_string action;
+ int len;
+
+ if ( view_string.size == 0 )
+ param_string_from_string(view_string, "[/XYZ 0 0 1]");
+ if ( page == 0 )
+ strcpy(dstr, "[null ");
+ else if ( pdfmark_find_key("Action", pairs, count, &action) &&
+ pdf_key_eq(&action, "/GoToR")
+ )
+ sprintf(dstr, "[%d ", page - 1);
+ else
+ sprintf(dstr, "[%ld 0 R ", pdf_page_id(pdev, page));
+ len = strlen(dstr);
+ if ( len + view_string.size > max_dest_string )
+ return_error(gs_error_limitcheck);
+ if ( view_string.data[0] != '[' ||
+ view_string.data[view_string.size - 1] != ']'
+ )
+ return_error(gs_error_rangecheck);
+ memcpy(dstr + len, view_string.data + 1, view_string.size - 1);
+ dstr[len + view_string.size - 1] = 0;
+ return present;
+}
+
+/* Write pairs for a dictionary. */
+private void
+pdfmark_write_pair(stream *s, const gs_param_string *pair)
+{ pputc(s, '/');
+ pwrite(s, pair->data, pair->size);
+ pputc(s, ' ');
+ pwrite(s, pair[1].data, pair[1].size);
+ pputc(s, '\n');
+}
+
+/* Scan a Rect value. */
+private int
+pdfmark_scan_rect(gs_rect *prect, const gs_param_string *str,
+ const gs_matrix *pctm)
+{ uint size = str->size;
+ double v[4];
+#define max_rect_string_size 100
+ char chars[max_rect_string_size + 3];
+ int end_check;
+
+ if ( str->size > max_rect_string_size )
+ return_error(gs_error_limitcheck);
+ memcpy(chars, str->data, size);
+ strcpy(chars + size, " 0");
+ if ( sscanf(chars, "[%lg %lg %lg %lg]%d",
+ &v[0], &v[1], &v[2], &v[3], &end_check) != 5
+ )
+ return_error(gs_error_rangecheck);
+ gs_point_transform(v[0], v[1], pctm, &prect->p);
+ gs_point_transform(v[2], v[3], pctm, &prect->q);
+ return 0;
+}
+
+/* Write a Rect value. */
+private void
+pdfmark_write_rect(stream *s, const char *key, const gs_rect *prect)
+{ pprints1(s, "/%s ", key);
+ pprintg4(s, "[%g %g %g %g]\n",
+ prect->p.x, prect->p.y, prect->q.x, prect->q.y);
+}
+
+/* Copy an annotation dictionary. */
+private int
+pdfmark_annot(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm, const char *subtype)
+{ pdf_resource *pres;
+ int code = pdf_begin_aside(pdev, &pdev->annots, NULL, &pres);
+ stream *s = pdev->strm;
+ bool subtype_present = false;
+ bool add_dest = false;
+ bool dest_present = false;
+ uint i;
+
+ if ( code < 0 )
+ return code;
+ pres->rid = pdev->next_page;
+ pputs(s, "<< /Type /Annot\n");
+ for ( i = 0; i < count; i += 2 )
+ { const gs_param_string *pair = &pairs[i];
+ long src_pg;
+
+ if ( pdf_key_eq(pair, "SrcPg") &&
+ sscanf((const char *)pair[1].data, "%ld", &src_pg) == 1
+ )
+ pres->rid = src_pg - 1;
+ else if ( pdf_key_eq(pair, "Page") || pdf_key_eq(pair, "View") )
+ add_dest = true;
+ /*
+ * For some unfathomable reason, PDF requires /A instead of
+ * /Action, and /S instead of /Subtype in the Action dictionary.
+ * Handle this here.
+ */
+ else if ( pdf_key_eq(pair, "Action") )
+ { const byte *astr = pair[1].data;
+ const uint asize = pair[1].size;
+ uint i;
+
+ pputs(s, "/A ");
+ /* Search for the next occurrence of /Subtype. */
+ for ( i = 0; i < asize; ++i )
+ if ( asize - i > 8 && !memcmp(astr + i, "/Subtype", 8) &&
+ scan_char_decoder[astr[i + 8]] > ctype_name
+ )
+ { pputs(s, "/S");
+ i += 7;
+ }
+ else
+ pputc(s, astr[i]);
+ pputc(s, '\n');
+ }
+ else if ( pdf_key_eq(pair, "Rect") )
+ { gs_rect rect;
+
+ code = pdfmark_scan_rect(&rect, pair + 1, pctm);
+ if ( code < 0 )
+ return code;
+ pdfmark_write_rect(s, "Rect", &rect);
+ }
+ else
+ { pdfmark_write_pair(s, pair);
+ if ( pdf_key_eq(pair, "Dest") )
+ dest_present = true;
+ else if ( pdf_key_eq(pair, "Subtype") )
+ subtype_present = true;
+ }
+ }
+ if ( add_dest && !dest_present )
+ { char dest[max_dest_string];
+ int code = pdfmark_make_dest(dest, pdev, pairs, count);
+ if ( code >= 0 )
+ pprints1(s, "/Dest %s\n", dest);
+ }
+ if ( !subtype_present )
+ pprints1(s, "/Subtype /%s ", subtype);
+ pputs(s, ">>\n");
+ pdf_end_aside(pdev);
+ return 0;
+}
+
+/* ANN pdfmark */
+private int
+pdfmark_ANN(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ return pdfmark_annot(pdev, pairs, count, pctm, "Text");
+}
+
+/* LNK pdfmark (obsolescent) */
+private int
+pdfmark_LNK(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ return pdfmark_annot(pdev, pairs, count, pctm, "Link");
+}
+
+/* Save pairs in a string. */
+private bool
+pdf_key_member(const gs_param_string *pcs, const char * const keys[])
+{ const char * const *pkey;
+ for ( pkey = keys; *pkey != 0; ++pkey )
+ if ( pdf_key_eq(pcs, *pkey) )
+ return true;
+ return false;
+}
+#define pdfmark_size_pair(pair)\
+ ((pair)[0].size + (pair)[1].size + 3)
+private byte *
+pdfmark_save_pair(byte *next, const gs_param_string *pair)
+{ uint len;
+
+ *next++ = '/';
+ memcpy(next, pair[0].data, len = pair[0].size);
+ next += len;
+ *next++ = ' ';
+ memcpy(next, pair[1].data, len = pair[1].size);
+ next += len;
+ *next++ = '\n';
+ return next;
+}
+private int
+pdfmark_save_edited_pairs(const gx_device_pdf *pdev,
+ const gs_param_string *pairs, uint count, const char * const skip_keys[],
+ const gs_param_string *add_pairs, uint add_count, gs_string *pstr)
+{ uint i, size;
+ byte *data;
+ byte *next;
+
+ for ( i = 0, size = 0; i < count; i += 2 )
+ if ( !pdf_key_member(&pairs[i], skip_keys) )
+ size += pdfmark_size_pair(&pairs[i]);
+ for ( i = 0; i < add_count; i += 2 )
+ size += pdfmark_size_pair(&add_pairs[i]);
+ if ( pstr->data == 0 )
+ data = gs_alloc_string(pdev->pdf_memory, size, "pdfmark_save_pairs");
+ else
+ data = gs_resize_string(pdev->pdf_memory, pstr->data, pstr->size,
+ size, "pdfmark_save_pairs");
+ if ( data == 0 )
+ return_error(gs_error_VMerror);
+ next = data;
+ for ( i = 0; i < count; i += 2 )
+ if ( !pdf_key_member(&pairs[i], skip_keys) )
+ next = pdfmark_save_pair(next, &pairs[i]);
+ for ( i = 0; i < add_count; i += 2 )
+ next = pdfmark_save_pair(next, &add_pairs[i]);
+ pstr->data = data;
+ pstr->size = size;
+ return 0;
+}
+static const char * const no_skip_pairs[] = { 0 };
+#define pdfmark_save_pairs(pdev, pairs, count, pstr)\
+ pdfmark_save_edited_pairs(pdev, pairs, count, no_skip_pairs, NULL, 0, pstr)
+
+/* Write out one node of the outline tree. */
+private int
+pdfmark_write_outline(gx_device_pdf *pdev, pdf_outline_node *pnode,
+ long next_id)
+{ stream *s;
+
+ pdf_open_separate(pdev, pnode->id);
+ s = pdev->strm;
+ pputs(s, "<< ");
+ pdf_write_saved_string(pdev, &pnode->action_string);
+ if ( pnode->count )
+ pprintd1(s, "/Count %d ", pnode->count);
+ pprintld1(s, "/Parent %ld 0 R\n", pnode->parent_id);
+ if ( pnode->prev_id )
+ pprintld1(s, "/Prev %ld 0 R\n", pnode->prev_id);
+ if ( next_id )
+ pprintld1(s, "/Next %ld 0 R\n", next_id);
+ if ( pnode->first_id )
+ pprintld2(s, "/First %ld 0 R /Last %ld 0 R\n",
+ pnode->first_id, pnode->last_id);
+ pputs(s, ">>\n");
+ pdf_end_separate(pdev);
+ return 0;
+}
+
+/* Adjust the parent's count when writing an outline node. */
+private void
+pdfmark_adjust_parent_count(pdf_outline_level *plevel)
+{ pdf_outline_level *parent = plevel - 1;
+ int count = plevel->last.count;
+
+ if ( count > 0 )
+ { if ( parent->last.count < 0 )
+ parent->last.count -= count;
+ else
+ parent->last.count += count;
+ }
+}
+
+/* Close the current level of the outline tree. */
+int
+pdfmark_close_outline(gx_device_pdf *pdev)
+{ int depth = pdev->outline_depth;
+ pdf_outline_level *plevel = &pdev->outline_levels[depth];
+ int code;
+
+ code = pdfmark_write_outline(pdev, &plevel->last, 0);
+ if ( code < 0 )
+ return code;
+ if ( depth > 0 )
+ { plevel[-1].last.last_id = plevel->last.id;
+ pdfmark_adjust_parent_count(plevel);
+ --plevel;
+ if ( plevel->last.count < 0 )
+ pdev->closed_outline_depth--;
+ pdev->outline_depth--;
+ }
+ return 0;
+}
+
+/* OUT pdfmark */
+private int
+pdfmark_OUT(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ int depth = pdev->outline_depth;
+ pdf_outline_level *plevel = &pdev->outline_levels[depth];
+ int sub_count = 0;
+ uint i;
+ pdf_outline_node node;
+ int code;
+
+ for ( i = 0; i < count; i += 2 )
+ { const gs_param_string *pair = &pairs[i];
+
+ if ( pdf_key_eq(pair, "Count") )
+ pdfmark_scan_int(pair + 1, &sub_count);
+ }
+ if ( sub_count != 0 && depth == max_outline_depth - 1 )
+ return_error(gs_error_limitcheck);
+ node.action_string.data = 0;
+ { static const char * const skip_out[] =
+ { "Page", "View", "Count", 0 };
+ char dest[max_dest_string];
+
+ if ( pdfmark_make_dest(dest, pdev, pairs, count) ) {
+ gs_param_string add_dest[2];
+
+ param_string_from_string(add_dest[0], "Dest");
+ param_string_from_string(add_dest[1], dest);
+ code = pdfmark_save_edited_pairs(pdev, pairs, count, skip_out,
+ add_dest, 2,
+ &node.action_string);
+ } else {
+ code = pdfmark_save_edited_pairs(pdev, pairs, count, skip_out + 2,
+ NULL, 0, &node.action_string);
+ }
+ if ( code < 0 )
+ return code;
+ }
+ if ( pdev->outlines_id == 0 )
+ pdev->outlines_id = pdf_obj_ref(pdev);
+ node.id = pdf_obj_ref(pdev);
+ node.parent_id =
+ (depth == 0 ? pdev->outlines_id : plevel[-1].last.id);
+ node.prev_id = plevel->last.id;
+ node.first_id = node.last_id = 0;
+ node.count = sub_count;
+ /* Add this node to the outline at the current level. */
+ if ( plevel->first.id == 0 )
+ { /* First node at this level. */
+ if ( depth > 0 )
+ plevel[-1].last.first_id = node.id;
+ node.prev_id = 0;
+ plevel->first = node;
+ }
+ else
+ { /* Write out the previous node. */
+ if ( depth > 0 )
+ pdfmark_adjust_parent_count(plevel);
+ pdfmark_write_outline(pdev, &plevel->last, node.id);
+ }
+ plevel->last = node;
+ plevel->left--;
+ if ( !pdev->closed_outline_depth )
+ pdev->outlines_open++;
+ /* If this node has sub-nodes, descend one level. */
+ if ( sub_count != 0 )
+ { pdev->outline_depth++;
+ ++plevel;
+ plevel->left = (sub_count > 0 ? sub_count : -sub_count);
+ plevel->first.id = 0;
+ if ( sub_count < 0 )
+ pdev->closed_outline_depth++;
+ }
+ else
+ { while ( (depth = pdev->outline_depth) > 0 &&
+ pdev->outline_levels[depth].left == 0
+ )
+ pdfmark_close_outline(pdev);
+ }
+ return 0;
+}
+
+/* Write an article bead. */
+int
+pdfmark_write_article(gx_device_pdf *pdev, const pdf_bead *pbead)
+{ stream *s;
+
+ pdf_open_separate(pdev, pbead->id);
+ s = pdev->strm;
+ pprintld3(s,
+ "<<\n/T %ld 0 R\n/V %ld 0 R\n/N %ld 0 R\n",
+ pbead->article_id, pbead->prev_id, pbead->next_id);
+ pprints1(s, "/Dest %s\n", pbead->dest);
+ pdfmark_write_rect(s, "R", &pbead->rect);
+ pputs(s, ">>\n");
+ return pdf_end_separate(pdev);
+}
+
+/* ARTICLE pdfmark */
+private int
+pdfmark_ARTICLE(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ gs_param_string title;
+ gs_param_string rectstr;
+ gs_rect rect;
+ long bead_id;
+ pdf_article *part;
+ int code;
+
+ if ( !pdfmark_find_key("Title", pairs, count, &title) ||
+ !pdfmark_find_key("Rect", pairs, count, &rectstr)
+ )
+ return_error(gs_error_rangecheck);
+ if ( (code = pdfmark_scan_rect(&rect, &rectstr, pctm)) < 0 )
+ return code;
+ /****** Should save other keys for Info dictionary ******/
+
+ /* Find the article with this title, or create one. */
+ bead_id = pdf_obj_ref(pdev);
+ for ( part = pdev->articles; part != 0; part = part->next )
+ if ( !bytes_compare(part->title.data, part->title.size,
+ title.data, title.size) )
+ break;
+ if ( part == 0 )
+ { /* Create the article. */
+ byte *str;
+
+ part = gs_alloc_struct(pdev->pdf_memory, pdf_article,
+ &st_pdf_article, "pdfmark_ARTICLE");
+ str = gs_alloc_string(pdev->pdf_memory, title.size,
+ "article title");
+ if ( part == 0 || str == 0 )
+ return_error(gs_error_VMerror);
+ part->next = pdev->articles;
+ pdev->articles = part;
+ memcpy(str, title.data, title.size);
+ part->title.data = str;
+ part->title.size = title.size;
+ part->id = pdf_begin_separate(pdev);
+ part->first.id = part->last.id = 0;
+ pprintld1(pdev->strm, "<</F %ld 0 R>>\n", bead_id);
+ pdf_end_separate(pdev);
+ }
+
+ /* Add the bead to the article. */
+ /* This is similar to what we do for outline nodes. */
+ if ( part->last.id == 0 )
+ { part->first.next_id = bead_id;
+ part->last.id = part->first.id;
+ }
+ else
+ { part->last.next_id = bead_id;
+ pdfmark_write_article(pdev, &part->last);
+ }
+ part->last.prev_id = part->last.id;
+ part->last.id = bead_id;
+ part->last.article_id = part->id;
+ part->last.next_id = 0;
+ part->last.rect = rect;
+ pdfmark_make_dest(part->last.dest, pdev, pairs, count);
+ if ( part->first.id == 0 )
+ { /* This is the first bead of the article. */
+ part->first = part->last;
+ part->last.id = 0;
+ }
+
+ return 0;
+}
+
+/* DEST pdfmark */
+private int
+pdfmark_DEST(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ char dest[max_dest_string];
+ gs_param_string key;
+ pdf_named_dest *pnd;
+ byte *str;
+
+ if ( !pdfmark_find_key("Dest", pairs, count, &key) ||
+ !pdfmark_make_dest(dest, pdev, pairs, count)
+ )
+ return_error(gs_error_rangecheck);
+ pnd = gs_alloc_struct(pdev->pdf_memory, pdf_named_dest,
+ &st_pdf_named_dest, "pdfmark_DEST");
+ str = gs_alloc_string(pdev->pdf_memory, key.size,
+ "named_dest key");
+ if ( pnd == 0 || str == 0 )
+ return_error(gs_error_VMerror);
+ pnd->next = pdev->named_dests;
+ memcpy(str, key.data, key.size);
+ pnd->key.data = str;
+ pnd->key.size = key.size;
+ strcpy(pnd->dest, dest);
+ pdev->named_dests = pnd;
+ return 0;
+}
+
+/* Write the contents of pass-through code. */
+/* We are inside the stream dictionary, in a 'separate' object. */
+private int
+pdfmark_write_ps(gx_device_pdf *pdev, const gs_param_string *psource)
+{ stream *s = pdev->strm;
+ long length_id = pdf_obj_ref(pdev);
+ long start_pos, length;
+
+ pprintld1(s, " /Length %ld 0 R >> stream\n", length_id);
+ start_pos = pdf_stell(pdev);
+ if ( psource->size < 2 || psource->data[0] != '(' ||
+ psource->data[psource->size - 1] != ')'
+ )
+ lprintf1("bad PS passthrough: %s\n", psource->data);
+ else
+ { /****** SHOULD REMOVE ESCAPES ******/
+ pwrite(s, psource->data + 1, psource->size - 2);
+ }
+ pputs(s, "\n");
+ length = pdf_stell(pdev) - start_pos;
+ pputs(s, "endstream\n");
+ pdf_end_separate(pdev);
+ pdf_open_separate(pdev, length_id);
+ pprintld1(s, "%ld\n", length);
+ pdf_end_separate(pdev);
+ return 0;
+}
+
+/* PS pdfmark */
+private int
+pdfmark_PS(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ stream *s;
+ gs_param_string source;
+ gs_param_string level1;
+
+ if ( !pdfmark_find_key("DataSource", pairs, count, &source) )
+ return_error(gs_error_rangecheck);
+ pdfmark_find_key("Level1", pairs, count, &level1);
+ if ( level1.data == 0 && source.size <= 100 &&
+ pdev->CompatibilityLevel >= 1.2
+ )
+ { /* Insert the PostScript code in-line */
+ int code = pdf_open_contents(pdev, pdf_in_stream);
+
+ if ( code < 0 )
+ return code;
+ s = pdev->strm;
+ pwrite(s, source.data, source.size);
+ pputs(s, " PS\n");
+ }
+ else
+ { /* Put the PostScript code in a resource. */
+ pdf_resource *pres;
+ int code = pdf_begin_resource(pdev, resourceXObject, gs_no_id,
+ &pres);
+
+ if ( code < 0 )
+ return code;
+ s = pdev->strm;
+ pputs(s, " /Subtype /PS");
+ if ( level1.data != 0 )
+ { long level1_id = pdf_obj_ref(pdev);
+
+ pprintld1(s, " /Level1 %ld 0 R", level1_id);
+ pdfmark_write_ps(pdev, &source);
+ pdf_open_separate(pdev, level1_id);
+ pputs(pdev->strm, "<<");
+ pdfmark_write_ps(pdev, &level1);
+ }
+ else
+ pdfmark_write_ps(pdev, &source);
+ code = pdf_open_contents(pdev, pdf_in_stream);
+ if ( code < 0 )
+ return code;
+ pprintld1(pdev->strm, "/R%ld Do\n", pres->id);
+ }
+ return 0;
+}
+
+/* PAGES pdfmark */
+private int
+pdfmark_PAGES(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ return pdfmark_save_pairs(pdev, pairs, count, &pdev->pages_string);
+}
+
+/* PAGE pdfmark */
+private int
+pdfmark_PAGE(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ return pdfmark_save_pairs(pdev, pairs, count, &pdev->page_string);
+}
+
+/* DOCINFO pdfmark */
+private int
+pdfmark_DOCINFO(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ long info_id = pdf_begin_separate(pdev);
+ stream *s = pdev->strm;
+ uint i;
+
+ if ( info_id < 0 )
+ return info_id;
+ pputs(s, "<<\n");
+ for ( i = 0; i < count; i += 2 )
+ if ( !pdf_key_eq(&pairs[i], "CreationDate") &&
+ !pdf_key_eq(&pairs[i], "Producer")
+ )
+ pdfmark_write_pair(s, &pairs[i]);
+ pdf_write_default_info(pdev);
+ pputs(s, ">>\n");
+ pdf_end_separate(pdev);
+ pdev->info_id = info_id;
+ return 0;
+}
+
+/* DOCVIEW pdfmark */
+private int
+pdfmark_DOCVIEW(gx_device_pdf *pdev, const gs_param_string *pairs, uint count,
+ const gs_matrix *pctm)
+{ char dest[max_dest_string];
+
+ if ( pdfmark_make_dest(dest, pdev, pairs, count) )
+ { gs_param_string add_dest[2];
+ static const char * const skip_dest[] =
+ { "Page", "View", 0 };
+
+ param_string_from_string(add_dest[0], "OpenAction");
+ param_string_from_string(add_dest[1], dest);
+ return pdfmark_save_edited_pairs(pdev, pairs, count, skip_dest,
+ add_dest, 2,
+ &pdev->catalog_string);
+ }
+ else
+ return pdfmark_save_pairs(pdev, pairs, count, &pdev->catalog_string);
+}
diff --git a/gs/src/gdevpdfp.c b/gs/src/gdevpdfp.c
new file mode 100644
index 000000000..7487676cc
--- /dev/null
+++ b/gs/src/gdevpdfp.c
@@ -0,0 +1,189 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdfp.c */
+/* Get/put parameters for PDF-writing driver */
+#include "gx.h"
+#include "gserrors.h"
+#include "gdevpdfx.h"
+
+/*
+ * The pdfwrite device supports the following "real" parameters:
+ * OutputFile <string>
+ * (all the Distiller parameters except *ImageDict)
+ * Currently, very few Distiller parameters actually have any effect.
+ *
+ * The device also supports the following write-only pseudo-parameters that
+ * serve only to communicate other information from the PostScript file.
+ * Their "value" is an array of strings, some of which may be the result
+ * of converting arbitrary PostScript objects to string form.
+ * pdfmark - see gdevpdfm.c
+ * show - see gdevpdft.c
+ */
+
+private const int CoreDistVersion = 3000; /* Distiller 3.0 */
+
+/* ---------------- Get parameters ---------------- */
+
+/* Get parameters. */
+int
+gdev_pdf_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int code = gdev_psdf_get_params(dev, plist);
+
+ if ( code < 0 ||
+ (code = param_write_float(plist, "CompatibilityLevel",
+ &pdev->CompatibilityLevel)) < 0 ||
+ (code = param_write_int(plist, "CoreDistVersion",
+ (int *)&CoreDistVersion)) < 0 ||
+ /* ****** DoThumbnails is OBSOLETE ****** */
+ (code = param_write_bool(plist, "DoThumbnails",
+ &pdev->DoThumbnails)) < 0 ||
+ (code = param_write_bool(plist, "ReAssignCharacters",
+ &pdev->ReAssignCharacters)) < 0 ||
+ (code = param_write_bool(plist, "ReEncodeCharacters",
+ &pdev->ReEncodeCharacters)) < 0 ||
+ (code = param_write_long(plist, "FirstObjectNumber",
+ &pdev->FirstObjectNumber)) < 0
+ )
+ ;
+ return code;
+}
+
+/* ---------------- Put parameters ---------------- */
+
+/* Put parameters. */
+int
+gdev_pdf_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_pdf *pdev = (gx_device_pdf *)dev;
+ int ecode = 0;
+ int code;
+ float cl = pdev->CompatibilityLevel;
+ bool dt = pdev->DoThumbnails;
+ bool rac = pdev->ReAssignCharacters;
+ bool rec = pdev->ReEncodeCharacters;
+ long fon = pdev->FirstObjectNumber;
+ gs_param_name param_name;
+
+ /* General parameters. */
+
+ switch ( code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+
+ { int cdv = CoreDistVersion;
+ ecode = psdf_put_int_param(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
+ if ( cdv != CoreDistVersion )
+ param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
+ }
+ /* ****** DoThumbnails is OBSOLETE ****** */
+ ecode = psdf_put_bool_param(plist, "DoThumbnails", &dt, ecode);
+
+ ecode = psdf_put_bool_param(plist, "ReAssignCharacters", &rac, ecode);
+ ecode = psdf_put_bool_param(plist, "ReEncodeCharacters", &rec, ecode);
+ switch ( code = param_read_long(plist, (param_name = "FirstObjectNumber"), &fon) )
+ {
+ case 0:
+ /*
+ * Setting this parameter is only legal if the file
+ * has just been opened and nothing has been written,
+ * or if we are setting it to the same value.
+ */
+ if ( fon == pdev->FirstObjectNumber )
+ break;
+ if ( fon <= 0 || fon > 0x7fff0000 ||
+ (pdev->next_id != 0 &&
+ pdev->next_id !=
+ pdev->FirstObjectNumber + pdf_num_initial_ids)
+ )
+ ecode = gs_error_rangecheck;
+ else
+ break;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+
+ /* Handle pseudo-parameters. */
+
+ { gs_param_string_array ppa;
+ switch ( code = param_read_string_array(plist,
+ (param_name = "pdfmark"),
+ &ppa) )
+ {
+ case 0:
+ pdf_open_document(pdev);
+ code = pdfmark_process(pdev, &ppa);
+ if ( code >= 0 )
+ break;
+ /* falls through for errors */
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+ }
+
+ { gs_param_dict ppd;
+ switch ( code = param_begin_read_dict(plist,
+ (param_name = "show"),
+ &ppd, false) )
+ {
+ case 0:
+ pdf_open_document(pdev);
+ code = pdfshow_process(pdev, &ppd);
+ param_end_read_dict(plist, param_name, &ppd);
+ if ( code >= 0 )
+ break;
+ /* falls through for errors */
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gdev_psdf_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ pdev->CompatibilityLevel = cl;
+ pdev->DoThumbnails = dt;
+ pdev->ReAssignCharacters = rac;
+ pdev->ReEncodeCharacters = rec;
+ if ( fon != pdev->FirstObjectNumber )
+ { pdev->FirstObjectNumber = fon;
+ if ( pdev->tfile != 0 )
+ { fseek(pdev->tfile, 0L, SEEK_SET);
+ pdf_initialize_ids(pdev);
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gdevpdft.c b/gs/src/gdevpdft.c
new file mode 100644
index 000000000..7e0c18deb
--- /dev/null
+++ b/gs/src/gdevpdft.c
@@ -0,0 +1,755 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpdft.c */
+/* Text handling for PDF-writing driver. */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gdevpdfx.h"
+#include "scommon.h"
+
+/*
+ * When a base font is selected, we have many alternatives for how to handle
+ * characters whose encoding doesn't match their encoding in the base font's
+ * built-in encoding. If a character's glyph doesn't match the character's
+ * glyph in the encoding built up so far, we check if the font has that
+ * glyph at all; if not, we fall back to a bitmap. Otherwise, we use one
+ * or both of the following algorithms:
+ *
+ * 1. If this is the first time a character at this position has been
+ * seen, assign its glyph to that position in the encoding.
+ * We do this step if the device parameter ReAssignCharacters is true.
+ * (This is the default.)
+ *
+ * 2. If the glyph is present in the encoding at some other position,
+ * substitute that position for the character; otherwise, assign the
+ * glyph to an unoccupied (.notdef) position.
+ * We do this step if the device parameter ReEncodeCharacters is true.
+ * (This is the default.)
+ *
+ * 3. Finally, fall back to using bitmaps (for the entire string).
+ *
+ * If it is essential that all strings in the output contain exactly the
+ * same character codes as the input, set ReEncodeCharacters to false. If
+ * it is important that strings be searchable, but some non-searchable
+ * strings can be tolerated, the defaults are appropriate. If searchability
+ * is not important, set ReAssignCharacters to false.
+ */
+
+/*
+ * The show pseudo-parameter is currently the way that the PostScript code
+ * passes show operations to the PDF writer. It is a hack! Its "value"
+ * is a dictionary with the following keys and values:
+ * /String (str)
+ * /Values [cx cy char ax ay px py]
+ * /FontName /fontname
+ * /Matrix [xx xy yx yy tx ty]
+ * /Encoding [e0 .. e255] (optional)
+ * /BaseEncoding [e0 ... e255] (optional)
+% /CharStrings << charnames => anything >> (optional)
+ * Note that px/y and tx/y are floating point values in device space;
+ * cx/y and ax/y are in text space. The matrix is the concatenation of
+ * FontMatrix
+ * inverse of base FontMatrix
+ * CTM
+ * This represents the transformation from a 1-unit-based character space
+ * to device space. The base encoding is StandardEncoding for all fonts
+ * except Symbol and ZapfDingbats; the encodings are not passed if the
+ * encoding is eq to the base encoding, since in this case no check for
+ * whether the string is encodable in the base encoding is needed.
+ */
+
+/* Define the 14 standard built-in fonts. */
+private const char *standard_font_names[] = {
+ "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
+ "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
+ "Symbol",
+ "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
+ "ZapfDingbats",
+ 0
+};
+
+/* Define StandardEncoding. */
+private const char notdef_string[] = ".notdef";
+#define notdef notdef_string
+private const char *std_enc_strings[256] = {
+ /* \00x */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* \04x */
+ "space", "exclam", "quotedbl", "numbersign",
+ "dollar", "percent", "ampersand", "quoteright",
+ "parenleft", "parenright", "asterisk", "plus",
+ "comma", "hyphen", "period", "slash",
+ "zero", "one", "two", "three",
+ "four", "five", "six", "seven",
+ "eight", "nine", "colon", "semicolon",
+ "less", "equal", "greater", "question",
+ /* \10x */
+ "at", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "bracketleft",
+ "backslash", "bracketright", "asciicircum", "underscore",
+ /* \14x */
+ "quoteleft", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", notdef,
+ /* \20x */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* \24x */
+ notdef, "exclamdown", "cent", "sterling",
+ "fraction", "yen", "florin", "section",
+ "currency", "quotesingle", "quotedblleft", "guillemotleft",
+ "guilsinglleft", "guilsinglright", "fi", "fl",
+ notdef, "endash", "dagger", "daggerdbl",
+ "periodcentered", notdef, "paragraph", "bullet",
+ "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright",
+ "ellipsis", "perthousand", notdef, "questiondown",
+ /* \30x */
+ notdef, "grave", "acute", "circumflex",
+ "tilde", "macron", "breve", "dotaccent",
+ "dieresis", notdef, "ring", "cedilla",
+ notdef, "hungarumlaut", "ogonek", "caron",
+ "emdash", notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef,
+ /* \34x", */
+ notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
+ "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef, notdef,
+ notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef,
+ "lslash", "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
+};
+#undef notdef
+
+/* Forward references */
+private int pdf_set_font_and_size(P3(gx_device_pdf *pdev, pdf_font *font,
+ floatp size));
+private int pdf_set_text_matrix(P2(gx_device_pdf *pdev,
+ const gs_matrix *pmat));
+private int pdf_append_chars(P3(gx_device_pdf *pdev, const byte *str,
+ uint size));
+private int pdf_check_encoding(P6(gx_device_pdf *pdev, gs_param_string *pstr,
+ const gs_param_dict *ptd,
+ byte *strbuf, int max_strbuf,
+ pdf_font *ppf));
+
+/* Process a show operation. */
+int
+pdfshow_process(gx_device_pdf *pdev, const gs_param_dict *ptd)
+{
+#define plist (ptd->list)
+ gs_param_string str, fnstr;
+ gs_param_float_array va;
+#define v_cx va.data[0]
+#define v_cy va.data[1]
+#define v_cch (int)va.data[2]
+#define v_ax va.data[3]
+#define v_ay va.data[4]
+#define v_px va.data[5]
+#define v_py va.data[6]
+ gs_param_float_array ma;
+ int code;
+ pdf_font *ppf;
+ stream *s;
+ double sx = pdev->HWResolution[0] / 72.0,
+ sy = pdev->HWResolution[1] / 72.0;
+ float size;
+ byte strbuf[200];
+
+ if ( (code = param_read_string(plist, "String", &str)) )
+ return_error(gs_error_rangecheck);
+ if ( str.size == 0 )
+ return 0; /* nothing to do */
+ /* Find or create the font resource. */
+ if ( (code = param_read_string(plist, "FontName", &fnstr)) )
+ return_error(gs_error_rangecheck);
+ { int i;
+
+ for ( i = 0; i < num_resource_chains; ++i )
+ for ( ppf = (pdf_font *)pdev->resources[resourceFont].chains[i];
+ ppf != 0; ppf = ppf->next
+ )
+ if ( !bytes_compare(ppf->fname.chars, ppf->fname.size,
+ fnstr.data, fnstr.size)
+ )
+ goto found;
+found: DO_NOTHING;
+ }
+ if ( ppf == 0 ) {
+ /*
+ * Currently, we only handle the built-in fonts. By doing
+ * things in this order, we may wind up including some base
+ * fonts that aren't actually needed, but it's unlikely.
+ */
+ const char **ppfn;
+
+ for ( ppfn = standard_font_names; *ppfn; ++ppfn )
+ if ( strlen(*ppfn) == fnstr.size &&
+ !strncmp(*ppfn, (const char *)fnstr.data, fnstr.size)
+ )
+ break;
+ if ( !*ppfn )
+ return_error(gs_error_undefined);
+ /*
+ * Allocate the font resource, but don't write it yet,
+ * because we don't know yet whether it will need
+ * a modified Encoding.
+ */
+ code = pdf_alloc_resource(pdev, resourceFont, gs_no_id,
+ (pdf_resource **)&ppf);
+ if ( code < 0 )
+ return_error(gs_error_undefined);
+ memcpy(ppf->fname.chars, fnstr.data, fnstr.size);
+ ppf->fname.size = fnstr.size;
+ ppf->frname[0] = 0; /* not an embedded font */
+ memset(ppf->chars_used, 0, sizeof(ppf->chars_used));
+ ppf->differences = 0;
+ ppf->num_chars = 0; /* ditto */
+ ppf->char_procs = 0; /* for GC */
+ }
+ /* Check that all characters can be encoded. */
+ code = pdf_check_encoding(pdev, &str, ptd, strbuf, sizeof(strbuf), ppf);
+ if ( code < 0 )
+ return code;
+ /* Read and check the rest of the parameters now. */
+ if ( (code = param_read_float_array(plist, "Values", &va)) ||
+ va.size != 7 ||
+ (code = param_read_float_array(plist, "Matrix", &ma)) ||
+ ma.size != 6
+ )
+ return_error(gs_error_rangecheck);
+ if ( v_cy != 0 || (v_cch != 32 && v_cx != 0) || v_ay != 0 )
+ return_error(gs_error_undefined);
+ /* Try to find a reasonable size value. This isn't necessary, */
+ /* but it's worth the effort. */
+ size = fabs(ma.data[0]) / sx;
+ if ( size < 0.01 )
+ size = fabs(ma.data[1]) / sy;
+ if ( size < 0.01 )
+ size = 1;
+ /* We attempt to eliminate redundant parameter settings. */
+ pdf_set_font_and_size(pdev, ppf, size);
+ { float chars = v_ax * size;
+
+ if ( pdev->text.character_spacing != chars )
+ { code = pdf_open_contents(pdev, pdf_in_text);
+ if ( code < 0 )
+ return code;
+ s = pdev->strm;
+ pprintg1(s, "%g Tc\n", chars);
+ pdev->text.character_spacing = chars;
+ }
+ }
+ { float words = v_cx * size;
+
+ if ( pdev->text.word_spacing != words )
+ { code = pdf_open_contents(pdev, pdf_in_text);
+ if ( code < 0 )
+ return code;
+ s = pdev->strm;
+ pprintg1(s, "%g Tw\n", words);
+ pdev->text.word_spacing = words;
+ }
+ }
+ { gs_matrix tmat;
+
+ tmat.xx = ma.data[0] / size;
+ tmat.xy = ma.data[1] / size;
+ tmat.yx = ma.data[2] / size;
+ tmat.yy = ma.data[3] / size;
+ tmat.tx = v_px + ma.data[4];
+ tmat.ty = v_py + ma.data[5];
+ pdf_set_text_matrix(pdev, &tmat);
+ }
+
+ /* If we re-encoded the string, pdf_check_encoding changed */
+ /* str.data to strbuf. */
+ return pdf_append_chars(pdev, str.data, str.size);
+}
+
+/* Create an encoding differences vector for a font. */
+private int
+pdf_create_differences(gx_device_pdf *pdev, pdf_font *ppf)
+{ gs_const_string *pdiff = ppf->differences;
+ int i;
+
+ if ( pdiff != 0 )
+ return 0;
+ ppf->diff_id = pdf_obj_ref(pdev);
+ pdiff = gs_alloc_struct_array(pdev->pdf_memory, 256, gs_const_string,
+ &st_const_string_element,
+ "differences");
+ if ( pdiff == 0 )
+ return_error(gs_error_VMerror);
+ for ( i = 0; i < 256; ++i )
+ pdiff[i].data = 0, pdiff[i].size = 0;
+ ppf->differences = pdiff;
+ return 0;
+}
+
+/*
+ * Check whether the encodings are compatible, and if not,
+ * whether we can re-encode the string using the base encoding.
+ */
+private int
+pdf_check_encoding(gx_device_pdf *pdev, gs_param_string *pstr,
+ const gs_param_dict *ptd, byte *strbuf, int max_strbuf, pdf_font *ppf)
+{ gs_param_string_array ea, bea;
+ int code;
+ gs_const_string *pdiff = ppf->differences;
+ uint i;
+
+ ea.data = bea.data = 0;
+ switch ( (code = param_read_name_array(ptd->list, "Encoding", &ea)) )
+ {
+ default:
+ return code;
+ case 0:
+ if ( ea.size != 256 )
+ return_error(gs_error_rangecheck);
+ case 1:
+ DO_NOTHING;
+ }
+ switch ( (code = param_read_name_array(ptd->list, "BaseEncoding", &bea)) )
+ {
+ default:
+ return code;
+ case 0:
+ if ( bea.size != 256 )
+ return_error(gs_error_rangecheck);
+ case 1:
+ DO_NOTHING;
+ }
+
+ if ( ea.data == bea.data && pdiff == 0 ) {
+ /*
+ * Just note the characters that have been used with their
+ * original encodings.
+ */
+ for ( i = 0; i < pstr->size; ++i ) {
+ byte chr = pstr->data[i];
+
+ ppf->chars_used[chr >> 3] |= 1 << (chr & 7);
+ }
+ return 0; /* encodings are the same */
+ }
+ for ( i = 0; i < pstr->size; ++i )
+ { byte chr = pstr->data[i];
+#define set_encoded(sdata, ssize, ch)\
+ (pdiff != 0 && pdiff[ch].data != 0 ?\
+ (sdata = pdiff[ch].data, ssize = pdiff[ch].size) :\
+ bea.data == 0 ?\
+ (sdata = (const byte *)std_enc_strings[ch],\
+ ssize = strlen((const char *)sdata)) :\
+ (sdata = bea.data[ch].data, ssize = bea.data[ch].size))
+ const byte *fedata;
+ uint fesize;
+ const byte *edata;
+ uint esize;
+
+ set_encoded(fedata, fesize, chr);
+ if ( ea.data == 0 )
+ esize = strlen(edata = (const byte *)std_enc_strings[chr]);
+ else
+ edata = ea.data[chr].data, esize = ea.data[chr].size;
+ if ( edata == fedata ||
+ (esize == fesize &&
+ !memcmp(edata, fedata, esize))
+ )
+ ppf->chars_used[chr >> 3] |= 1 << (chr & 7);
+ else
+ {
+ if ( pdev->ReAssignCharacters ) {
+ /*
+ * If this is the first time we've seen this character,
+ * assign the glyph to its position in the encoding.
+ */
+ if ( (pdiff == 0 || pdiff[chr].data == 0) &&
+ !(ppf->chars_used[chr >> 3] & (1 << (chr & 7)))
+ ) {
+ int code = pdf_create_differences(pdev, ppf);
+
+ if ( code < 0 )
+ return code;
+ pdiff = ppf->differences;
+ /*
+ * Since the entry in ea is the string for a name,
+ * or a const C string, we don't need to copy it.
+ */
+ pdiff[chr].data = edata;
+ pdiff[chr].size = esize;
+ continue;
+ }
+ }
+ if ( pdev->ReEncodeCharacters ) {
+ /*
+ * Look for the character at some other position in the
+ * encoding.
+ */
+ int c;
+
+ for ( c = 0; c < 256; ++c ) {
+ set_encoded(fedata, fesize, c);
+ if ( esize == fesize && !memcmp(edata, fedata, esize) )
+ break;
+ }
+ if ( c == 256 ) {
+ /*
+ * The character isn't encoded anywhere. Look for a
+ * never-referenced .notdef position where we can put
+ * it.
+ */
+ int code;
+
+ for ( c = 0; c < 256; ++c ) {
+ set_encoded(fedata, fesize, c);
+ if ( !bytes_compare(fedata, fesize,
+ (const byte *)".notdef", 7) &&
+ !(ppf->chars_used[c >> 3] & (1 << (c & 7)))
+ )
+ break;
+ }
+ if ( c == 256 ) /* no .notdef positions left */
+ return_error(gs_error_undefined);
+ code = pdf_create_differences(pdev, ppf);
+ if ( code < 0 )
+ return code;
+ ppf->differences[c].data = edata;
+ ppf->differences[c].size = esize;
+ }
+ /*
+ * It really simplifies things if we can buffer
+ * the entire string locally in one piece....
+ */
+ if ( pstr->data != strbuf ) {
+ if ( pstr->size > max_strbuf )
+ return_error(gs_error_limitcheck);
+ memcpy(strbuf, pstr->data, pstr->size);
+ pstr->data = strbuf;
+ }
+ strbuf[i] = (byte)c;
+ continue;
+ }
+ return_error(gs_error_undefined);
+ }
+ }
+ return 0;
+}
+
+/* ---------------- Embedded fonts ---------------- */
+
+/*
+ * Set the current font and size, writing a Tf command if needed.
+ */
+private int
+pdf_set_font_and_size(gx_device_pdf *pdev, pdf_font *font, floatp size)
+{ if ( font != pdev->text.font || size != pdev->text.size )
+ { int code = pdf_open_contents(pdev, pdf_in_text);
+ stream *s = pdev->strm;
+
+ if ( code < 0 )
+ return code;
+ if ( font->frname[0] )
+ pprints1(s, "/%s ", font->frname);
+ else
+ pprintld1(s, "/R%ld ", font->id);
+ pprintg1(s, "%g Tf\n", size);
+ pdev->text.font = font;
+ pdev->text.size = size;
+ }
+ font->used_on_page = true;
+ return 0;
+}
+
+/* Assign a code for a char_proc. */
+private int
+assign_char_code(gx_device_pdf *pdev)
+{ pdf_font *font = pdev->open_font;
+
+ if ( font == 0 )
+ { /* This is the very first embedded font. */
+ /* Create the (canned) Encoding array. */
+ long id = pdf_begin_separate(pdev);
+ stream *s = pdev->strm;
+ int i;
+
+ /*
+ * Even though the PDF reference documentation says that a
+ * BaseEncoding key is required unless the encoding is
+ * "based on the base font's encoding" (and there is no base
+ * font in this case), Acrobat 2.1 gives an error if the
+ * BaseEncoding key is present.
+ */
+ pputs(s, "<</Type/Encoding/Differences[0");
+ for ( i = 0; i < 256; ++i )
+ { if ( !(i & 15) )
+ pputs(s, "\n");
+ pprintd1(s, "/a%d", i);
+ }
+ pputs(s, "\n] >>\n");
+ pdf_end_separate(pdev);
+ pdev->embedded_encoding_id = id;
+ }
+ if ( font == 0 || font->num_chars == 256 )
+ { /* Start a new embedded font. */
+ pdf_resource *pres;
+ int code = pdf_alloc_resource(pdev, resourceFont, gs_no_id, &pres);
+ char *pc;
+
+ if ( code < 0 )
+ return code;
+ font = (pdf_font *)pres;
+ font->fname.size = 0;
+ font->used_on_page = false;
+ if ( pdev->open_font == 0 )
+ memset(font->frname, 0, sizeof(font->frname));
+ else
+ strcpy(font->frname, pdev->open_font->frname);
+ for ( pc = font->frname; *pc == 'Z'; ++pc )
+ *pc = '@';
+ if ( (*pc)++ == 0 )
+ *pc = 'A', pc[1] = 0;
+ font->differences = 0;
+ font->num_chars = 0;
+ font->char_procs = 0;
+ font->max_y_offset = 0;
+ memset(font->spaces, 0, sizeof(font->spaces));
+ pdev->open_font = font;
+ }
+ return font->num_chars++;
+}
+
+/*
+ * Set the text matrix for writing text.
+ * The translation component of the matrix is the text origin.
+ * If the non-translation components of the matrix differ from the
+ * current ones, write a Tm command; otherwise, write either a Td command
+ * or a Tj command using space pseudo-characters.
+ * Do not write a \n after the command.
+ */
+private int
+set_text_distance(gs_point *pdist, const gs_point *ppt, const gs_matrix *pmat)
+{ double rounded;
+
+ gs_distance_transform_inverse(pmat->tx - ppt->x, pmat->ty - ppt->y,
+ pmat, pdist);
+ /* If the distance is very close to integers, round it. */
+ if ( fabs(pdist->x - (rounded = floor(pdist->x + 0.5))) < 0.0005 )
+ pdist->x = rounded;
+ if ( fabs(pdist->y - (rounded = floor(pdist->y + 0.5))) < 0.0005 )
+ pdist->y = rounded;
+ return 0;
+}
+private int
+pdf_set_text_matrix(gx_device_pdf *pdev, const gs_matrix *pmat)
+{ stream *s = pdev->strm;
+ double sx = 72.0 / pdev->HWResolution[0],
+ sy = 72.0 / pdev->HWResolution[1];
+ int code;
+
+ if ( pmat->xx == pdev->text.matrix.xx &&
+ pmat->xy == pdev->text.matrix.xy &&
+ pmat->yx == pdev->text.matrix.yx &&
+ pmat->yy == pdev->text.matrix.yy &&
+ /*
+ * If we aren't already in text context, BT will reset
+ * the text matrix.
+ */
+ (pdev->context == pdf_in_text || pdev->context == pdf_in_string)
+ )
+ { /* Use Td or a pseudo-character. */
+ gs_point dist;
+
+ set_text_distance(&dist, &pdev->text.current, pmat);
+ if ( dist.y == 0 && dist.x >= x_space_min &&
+ dist.x <= x_space_max &&
+ pdev->text.font != 0 &&
+ font_is_embedded(pdev->text.font)
+ )
+ { /* Use a pseudo-character. */
+ int dx = (int)dist.x;
+ int dx_i = dx - x_space_min;
+ byte space_char = pdev->text.font->spaces[dx_i];
+
+ if ( space_char == 0 )
+ { if ( pdev->text.font != pdev->open_font )
+ goto td;
+ code = assign_char_code(pdev);
+ if ( code <= 0 )
+ goto td;
+ space_char =
+ pdev->open_font->spaces[dx_i] =
+ (byte)code;
+ if ( pdev->space_char_ids[dx_i] == 0 )
+ { /* Create the space char_proc now. */
+ char spstr[3 + 14 + 1];
+ stream *s;
+
+ sprintf(spstr, "%d 0 0 0 0 0 d1\n", dx);
+ pdev->space_char_ids[dx_i] = pdf_begin_separate(pdev);
+ s = pdev->strm;
+ pprintd1(s, "<</Length %d>>\nstream\n", strlen(spstr));
+ pprints1(s, "%sendstream\n", spstr);
+ pdf_end_separate(pdev);
+ }
+ }
+ pdf_append_chars(pdev, &space_char, 1);
+ pdev->text.current.x += dist.x * pmat->xx;
+ return 0;
+ }
+td: /* Use Td. */
+ code = pdf_open_page(pdev, pdf_in_text);
+ if ( code < 0 )
+ return code;
+ set_text_distance(&dist, &pdev->text.line_start, pmat);
+ pprintg2(s, "%g %g Td", dist.x, dist.y);
+ }
+ else
+ { /* Use Tm. */
+ code = pdf_open_page(pdev, pdf_in_text);
+ if ( code < 0 )
+ return code;
+ /*
+ * See stream_to_text in gdevpdf.c for why we need the following
+ * matrix adjustments.
+ */
+ pprintg6(pdev->strm, "%g %g %g %g %g %g Tm",
+ pmat->xx * sx, pmat->xy * sy,
+ pmat->yx * sx, pmat->yy * sy,
+ pmat->tx * sx, pmat->ty * sy);
+ pdev->text.matrix = *pmat;
+ }
+ pdev->text.line_start.x = pmat->tx;
+ pdev->text.line_start.y = pmat->ty;
+ pdev->text.current.x = pmat->tx;
+ pdev->text.current.y = pmat->ty;
+ return 0;
+}
+
+/* Append characters to a string being accumulated. */
+private int
+pdf_append_chars(gx_device_pdf *pdev, const byte *str, uint size)
+{ const byte *p = str;
+ uint left = size;
+
+ while ( left )
+ if ( pdev->text.buffer_count == max_text_buffer )
+ { int code = pdf_open_contents(pdev, pdf_in_text);
+
+ if ( code < 0 )
+ return code;
+ }
+ else
+ { int code = pdf_open_contents(pdev, pdf_in_string);
+ uint copy;
+
+ if ( code < 0 )
+ return code;
+ copy = min(max_text_buffer - pdev->text.buffer_count, left);
+ memcpy(pdev->text.buffer + pdev->text.buffer_count, p, copy);
+ pdev->text.buffer_count += copy;
+ p += copy;
+ left -= copy;
+ }
+ return 0;
+}
+
+/* Begin a CharProc for an embedded (bitmap) font. */
+int
+pdf_begin_char_proc(gx_device_pdf *pdev, int w, int h, int x_width,
+ int y_offset, gs_id id, pdf_char_proc **ppcp, pdf_stream_position *ppos)
+{ pdf_resource *pres;
+ pdf_char_proc *pcp;
+ int char_code = assign_char_code(pdev);
+ pdf_font *font = pdev->open_font;
+ int code;
+
+ if ( char_code < 0 )
+ return char_code;
+ code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
+ if ( code < 0 )
+ return code;
+ pcp = (pdf_char_proc *)pres;
+ pcp->font = font;
+ pcp->char_next = font->char_procs;
+ font->char_procs = pcp;
+ pcp->char_code = char_code;
+ pcp->width = w;
+ pcp->height = h;
+ pcp->x_width = x_width;
+ pcp->y_offset = y_offset;
+ font->max_y_offset = max(font->max_y_offset, h + (h >> 2));
+ *ppcp = pcp;
+ { stream *s = pdev->strm;
+ /*
+ * The resource file is positionable, so rather than use an
+ * object reference for the length, we'll go back and fill it in
+ * at the end of the definition. Take 10K as the longest
+ * definition we can handle.
+ */
+ pputs(s, "<</Length >>\nstream\n");
+ ppos->start_pos = stell(s);
+ }
+ return 0;
+}
+
+/* End a CharProc. */
+int
+pdf_end_char_proc(gx_device_pdf *pdev, pdf_stream_position *ppos)
+{ stream *s = pdev->strm;
+ long start_pos = ppos->start_pos;
+ long end_pos = stell(s);
+ long length = end_pos - start_pos;
+
+ if ( length > 9999 )
+ return_error(gs_error_limitcheck);
+ sseek(s, start_pos - 14);
+ pprintd1(s, "%d", length);
+ sseek(s, end_pos);
+ pputs(s, "endstream\n");
+ pdf_end_separate(pdev);
+ return 0;
+}
+
+/* Put out a reference to an image as a character in an embedded font. */
+int
+pdf_do_char_image(gx_device_pdf *pdev, const pdf_char_proc *pcp,
+ const gs_matrix *pimat)
+{ pdf_set_font_and_size(pdev, pcp->font, 1.0);
+ { gs_matrix tmat;
+
+ tmat = *pimat;
+ tmat.ty -= pcp->y_offset;
+ pdf_set_text_matrix(pdev, &tmat);
+ }
+ pdf_append_chars(pdev, &pcp->char_code, 1);
+ pdev->text.current.x += pcp->x_width * pdev->text.matrix.xx;
+ return 0;
+}
diff --git a/gs/src/gdevpdfx.h b/gs/src/gdevpdfx.h
new file mode 100644
index 000000000..692d3d990
--- /dev/null
+++ b/gs/src/gdevpdfx.h
@@ -0,0 +1,445 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* Internal definitions for PDF-writing driver. */
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gxline.h"
+#include "stream.h"
+#include "gdevpstr.h"
+#include "gdevpsdf.h"
+
+/* ---------------- Statically allocated sizes ---------------- */
+/* These should all really be dynamic.... */
+
+/* Define the maximum size of the output file name. */
+#define fname_size 80
+
+/* Define the maximum number of contents fragments on a page. */
+#define max_contents_ids 300
+
+/* Define the maximum depth of an outline tree. */
+/* Note that there is no limit on the breadth of the tree. */
+#define max_outline_depth 8
+
+/* Define the maximum size of a destination array string. */
+#define max_dest_string 80
+
+/* ================ Types and structures ================ */
+
+/* ---------------- Resources ---------------- */
+
+typedef enum {
+ resourceFont,
+ resourceEncoding,
+ resourceFontDescriptor,
+ resourceColorSpace,
+ resourceXObject,
+ resourceCharProc,
+ num_resource_types
+} pdf_resource_type;
+#define pdf_resource_type_names\
+ "Font", "Encoding", "FontDescriptor", "ColorSpace", "XObject", 0
+#define pdf_resource_type_structs\
+ &st_pdf_font, &st_pdf_resource, &st_pdf_resource, &st_pdf_resource,\
+ &st_pdf_resource, &st_pdf_char_proc
+
+#define pdf_resource_common(typ)\
+ typ *next; /* next resource of this type */\
+ pdf_resource *prev; /* previously allocated resource */\
+ gs_id rid; /* optional key */\
+ long id
+typedef struct pdf_resource_s pdf_resource;
+struct pdf_resource_s {
+ pdf_resource_common(pdf_resource);
+};
+#define private_st_pdf_resource()\
+ gs_private_st_ptrs2(st_pdf_resource, pdf_resource, "pdf_resource",\
+ pdf_resource_enum_ptrs, pdf_resource_reloc_ptrs, next, prev)
+
+/* Font resources */
+typedef struct pdf_char_proc_s pdf_char_proc; /* forward reference */
+typedef struct pdf_font_s pdf_font;
+typedef struct pdf_font_name_s {
+ byte chars[40]; /* arbitrary, must be large enough for */
+ /* the 14 built-in fonts */
+ uint size;
+} pdf_font_name;
+struct pdf_font_s {
+ pdf_resource_common(pdf_font);
+ pdf_font_name fname;
+ bool used_on_page;
+ char frname[6+1]; /* xxxxxx\0 */
+ /* Encoding differences for base fonts. */
+ byte chars_used[32]; /* 1 bit per character code */
+ gs_const_string *differences;
+ long diff_id;
+ /* Bookkeeping for embedded fonts. */
+ int num_chars;
+#define font_is_embedded(font) ((font)->num_chars != 0)
+ pdf_char_proc *char_procs;
+ int max_y_offset;
+ /* Pseudo-characters for spacing. */
+ /* The range should be determined by the device resolution.... */
+#define x_space_min 24
+#define x_space_max 150
+ byte spaces[x_space_max - x_space_min + 1];
+};
+#define private_st_pdf_font()\
+ gs_private_st_suffix_add2(st_pdf_font, pdf_font, "pdf_font",\
+ pdf_font_enum_ptrs, pdf_font_reloc_ptrs, st_pdf_resource,\
+ differences, char_procs)
+
+/* CharProc pseudo-resources for embedded fonts */
+struct pdf_char_proc_s {
+ pdf_resource_common(pdf_char_proc);
+ pdf_font *font;
+ pdf_char_proc *char_next; /* next char_proc for same font */
+ int width, height;
+ int x_width; /* X escapement */
+ int y_offset; /* of character (0,0) */
+ byte char_code;
+};
+#define private_st_pdf_char_proc()\
+ gs_private_st_suffix_add2(st_pdf_char_proc, pdf_char_proc,\
+ "pdf_char_proc", pdf_char_proc_enum_ptrs,\
+ pdf_char_proc_reloc_ptrs, st_pdf_resource, font, char_next)
+
+/* ---------------- Other auxiliary structures ---------------- */
+
+/* Outline nodes and levels */
+typedef struct pdf_outline_node_s {
+ long id, parent_id, prev_id, first_id, last_id;
+ int count;
+ gs_string action_string;
+} pdf_outline_node;
+typedef struct pdf_outline_level_s {
+ pdf_outline_node first;
+ pdf_outline_node last;
+ int left;
+} pdf_outline_level;
+
+/* Articles */
+typedef struct pdf_bead_s {
+ long id, article_id, prev_id, next_id;
+ char dest[max_dest_string];
+ gs_rect rect;
+} pdf_bead;
+typedef struct pdf_article_s pdf_article;
+struct pdf_article_s {
+ pdf_article *next;
+ gs_string title;
+ long id;
+ pdf_bead first;
+ pdf_bead last;
+};
+#define private_st_pdf_article()\
+ gs_private_st_ptrs1_strings1(st_pdf_article, pdf_article, "pdf_article",\
+ pdf_article_enum_ptrs, pdf_article_reloc_ptrs, next, title)
+
+/* Named destinations */
+typedef struct pdf_named_dest_s pdf_named_dest;
+struct pdf_named_dest_s {
+ pdf_named_dest *next;
+ gs_string key;
+ char dest[max_dest_string];
+};
+#define private_st_pdf_named_dest()\
+ gs_private_st_ptrs1_strings1(st_pdf_named_dest, pdf_named_dest,\
+ "pdf_named_dest", pdf_named_dest_enum_ptrs, pdf_named_dest_reloc_ptrs,\
+ next, key)
+
+/* ---------------- The device structure ---------------- */
+
+/* Text state */
+typedef struct pdf_text_state_s {
+ /* State parameters */
+ float character_spacing;
+ pdf_font *font;
+ floatp size;
+ float word_spacing;
+ float horizontal_scaling;
+ /* Bookkeeping */
+ gs_matrix matrix; /* relative to device space, not user space */
+ gs_point line_start;
+ gs_point current;
+#define max_text_buffer 200 /* arbitrary, but overflow costs 5 chars */
+ byte buffer[max_text_buffer];
+ int buffer_count;
+} pdf_text_state;
+#define pdf_text_state_default\
+ 0, NULL, 0, 0, 100,\
+ { identity_matrix_body }, { 0, 0 }, { 0, 0 }, { 0 }, 0
+
+/* Resource lists */
+#define num_resource_chains 16
+typedef struct pdf_resource_list_s {
+ pdf_resource *chains[num_resource_chains];
+} pdf_resource_list;
+
+/* Define the bookkeeping for an open stream. */
+typedef struct pdf_stream_position_s {
+ long length_id;
+ long start_pos;
+} pdf_stream_position;
+
+/* Define the device structure. */
+typedef enum {
+ NoMarks = 0,
+ ImageB = 1,
+ ImageC = 2,
+ ImageI = 4,
+ Text = 8
+} pdf_procset;
+typedef enum {
+ pdf_in_none,
+ pdf_in_stream,
+ pdf_in_text,
+ pdf_in_string
+} pdf_context;
+typedef struct gx_device_pdf_s {
+ gx_device_psdf_common;
+ /* PDF-specific distiller parameters */
+ float CompatibilityLevel;
+ bool DoThumbnails; /* ****** OBSOLETE ****** */
+ /* End of distiller parameters */
+ /* Other parameters */
+ bool ReAssignCharacters;
+ bool ReEncodeCharacters;
+ long FirstObjectNumber;
+ /* End of parameters */
+ bool binary_ok; /* if true, OK to output binary info */
+ /* End of settable parameters. */
+ /* Following are set when device is opened. */
+ enum {
+ pdf_compress_none,
+ pdf_compress_LZW, /* not currently used, thanks to Unisys */
+ pdf_compress_Flate
+ } compression;
+#define pdf_memory v_memory
+ char tfname[fname_size + 1];
+ FILE *tfile;
+ char rfname[fname_size + 1];
+ FILE *rfile;
+ stream *rstrm;
+ byte *rstrmbuf;
+ stream *rsave_strm;
+ pdf_font *open_font;
+ long embedded_encoding_id;
+ /* ................ */
+ long next_id;
+ /* The following 2 IDs, and only these, are allocated */
+ /* when the file is opened. */
+ long root_id;
+ long info_id;
+#define pdf_num_initial_ids 2
+ long pages_id;
+ long outlines_id;
+ int next_page;
+ long contents_id;
+ pdf_context context;
+ long contents_length_id;
+ long contents_pos;
+ pdf_procset procsets; /* used on this page */
+ float flatness; /****** SHOULD USE state ******/
+ /* The line width, dash offset, and dash pattern */
+ /* are in default user space units. */
+ gx_line_params line_params; /* current values */
+ /****** SHOULD USE state ******/
+ pdf_text_state text;
+ long space_char_ids[x_space_max - x_space_min + 1];
+#define initial_num_page_ids 50
+ long *page_ids;
+ int num_page_ids;
+ int pages_referenced;
+ pdf_resource_list resources[num_resource_types];
+ pdf_resource *annots; /* rid = page # */
+ pdf_resource *last_resource;
+ gs_string catalog_string;
+ gs_string pages_string;
+ gs_string page_string;
+ pdf_outline_level outline_levels[max_outline_depth];
+ int outline_depth;
+ int closed_outline_depth;
+ int outlines_open;
+ pdf_article *articles;
+ pdf_named_dest *named_dests;
+} gx_device_pdf;
+#define is_in_page(pdev)\
+ ((pdev)->contents_id != 0)
+#define is_in_document(pdev)\
+ (is_in_page(pdev) || (pdev)->last_resource != 0)
+
+/* Enumerate the individual pointers in a gx_device_pdf */
+#define gx_device_pdf_do_ptrs(m)\
+ m(0,rstrm) m(1,rstrmbuf) m(2,rsave_strm) m(3,open_font)\
+ m(4,line_params.dash.pattern) m(5,text.font) m(6,page_ids) m(7,annots)\
+ m(8,last_resource) m(9,articles) m(10,named_dests)
+#define gx_device_pdf_num_ptrs 11 /* + num_resource_types */
+#define gx_device_pdf_do_strings(m)\
+ m(0,catalog_string) m(1,pages_string) m(2,page_string)
+#define gx_device_pdf_num_strings 3 /* + max_outline_depth * 2 */
+#define st_device_pdf_max_ptrs\
+ (st_device_psdf_max_ptrs + gx_device_pdf_num_ptrs +\
+ gx_device_pdf_num_strings + num_resource_types * num_resource_chains +\
+ max_outline_depth * 2)
+
+#define private_st_device_pdfwrite() /* in gdevpdf.c */\
+ gs_private_st_composite_final(st_device_pdfwrite, gx_device_pdf,\
+ "gx_device_pdf", device_pdfwrite_enum_ptrs, device_pdfwrite_reloc_ptrs,\
+ device_pdfwrite_finalize)
+
+/* ================ Utility procedures ================ */
+
+/* ---------------- Exported by gdevpdf.c ---------------- */
+
+/* ------ Document ------ */
+
+/* Initialize the IDs allocated at startup. */
+void pdf_initialize_ids(P1(gx_device_pdf *pdev));
+
+/* Open the document if necessary. */
+void pdf_open_document(P1(gx_device_pdf *pdev));
+
+/* ------ Objects ------ */
+
+/* Allocate an ID for a future object. */
+long pdf_obj_ref(P1(gx_device_pdf *pdev));
+
+/* Read the current position in the output stream. */
+long pdf_stell(P1(gx_device_pdf *pdev));
+
+/* Begin an object, optionally allocating an ID. */
+long pdf_open_obj(P2(gx_device_pdf *pdev, long id));
+
+/* Begin an object, allocating an ID. */
+#define pdf_begin_obj(pdev) pdf_open_obj(pdev, 0)
+
+/* End an object. */
+int pdf_end_obj(P1(gx_device_pdf *pdev));
+
+/* ------ Graphics ------ */
+
+/* Reset the graphics state parameters to initial values. */
+void pdf_reset_graphics(P1(gx_device_pdf *pdev));
+
+/* Set the fill or stroke color. */
+int pdf_set_color(P4(gx_device_pdf *pdev, gx_color_index color,
+ gx_drawing_color *pdcolor, const char *rgs));
+
+/* Write matrix values. */
+void pdf_put_matrix(P4(gx_device_pdf *pdev, const char *before,
+ const gs_matrix *pmat, const char *after));
+
+/* Write a string in its shortest form ( () or <> ). */
+void pdf_put_string(P3(gx_device_pdf *pdev, const byte *str, uint size));
+
+/* ------ Page contents ------ */
+
+/* Open a page contents part. */
+/* Return an error if the page has too many contents parts. */
+int pdf_open_contents(P2(gx_device_pdf *pdev, pdf_context context));
+
+/* Close the current contents part if we are in one. */
+int pdf_close_contents(P2(gx_device_pdf *pdev, bool last));
+
+/* ------ Resources et al ------ */
+
+/* Begin an object logically separate from the contents. */
+/* (I.e., an object in the resource file.) */
+long pdf_open_separate(P2(gx_device_pdf *pdev, long id));
+#define pdf_begin_separate(pdev) pdf_open_separate(pdev, 0L)
+
+/* Begin an aside (resource, annotation, ...). */
+int pdf_begin_aside(P4(gx_device_pdf *pdev, pdf_resource **plist,
+ const gs_memory_struct_type_t *pst,
+ pdf_resource **ppres));
+
+/* Begin a resource of a given type. */
+int pdf_begin_resource(P4(gx_device_pdf *pdev, pdf_resource_type type,
+ gs_id rid, pdf_resource **ppres));
+
+/* Allocate a resource, but don't open the stream. */
+int pdf_alloc_resource(P4(gx_device_pdf *pdev, pdf_resource_type type,
+ gs_id rid, pdf_resource **ppres));
+
+/* Find a resource of a given type by gs_id. */
+pdf_resource *pdf_find_resource_by_gs_id(P3(gx_device_pdf *pdev,
+ pdf_resource_type type,
+ gs_id rid));
+
+/* End a separate object. */
+#define pdf_end_separate(pdev) pdf_end_aside(pdev)
+
+/* End an aside. */
+int pdf_end_aside(P1(gx_device_pdf *pdev));
+
+/* End a resource. */
+int pdf_end_resource(P1(gx_device_pdf *pdev));
+
+/* ------ Pages ------ */
+
+/* Get or assign the ID for a page. */
+/* Returns 0 if the page number is out of range. */
+long pdf_page_id(P2(gx_device_pdf *pdev, int page_num));
+
+/* Open a page for writing. */
+int pdf_open_page(P2(gx_device_pdf *pdev, pdf_context context));
+
+/* Write saved page- or document-level information. */
+int pdf_write_saved_string(P2(gx_device_pdf *pdev, gs_string *pstr));
+
+/* Write the default entries of the Info dictionary. */
+int pdf_write_default_info(P1(gx_device_pdf *pdev));
+
+/* ------ Path drawing ------ */
+
+bool pdf_must_put_clip_path(P2(gx_device_pdf *pdev, const gx_clip_path *pcpath));
+
+int pdf_put_clip_path(P2(gx_device_pdf *pdev, const gx_clip_path *pcpath));
+
+/* ---------------- Exported by gdevpdfm.c ---------------- */
+
+/* Compare a C string and a gs_param_string. */
+bool pdf_key_eq(P2(const gs_param_string *pcs, const char *str));
+
+/* Process a pdfmark (called from pdf_put_params). */
+int pdfmark_process(P2(gx_device_pdf *pdev, const gs_param_string_array *pma));
+
+/* Close the current level of the outline tree. */
+int pdfmark_close_outline(P1(gx_device_pdf *pdev));
+
+/* Write an article bead. */
+int pdfmark_write_article(P2(gx_device_pdf *pdev, const pdf_bead *pbead));
+
+/* ---------------- Exported by gdevpdft.c ---------------- */
+
+/* Process a show operation (called from pdf_put_params). */
+int pdfshow_process(P2(gx_device_pdf *pdev, const gs_param_dict *ptd));
+
+/* Begin a CharProc for an embedded (bitmap) font. */
+int pdf_begin_char_proc(P8(gx_device_pdf *pdev, int w, int h, int x_width,
+ int y_offset, gs_id id, pdf_char_proc **ppcp,
+ pdf_stream_position *ppos));
+
+/* End a CharProc. */
+int pdf_end_char_proc(P2(gx_device_pdf *pdev, pdf_stream_position *ppos));
+
+/* Put out a reference to an image as a character in an embedded font. */
+int pdf_do_char_image(P3(gx_device_pdf *pdev, const pdf_char_proc *pcp,
+ const gs_matrix *pimat));
diff --git a/gs/src/gdevpe.c b/gs/src/gdevpe.c
new file mode 100644
index 000000000..b2367217c
--- /dev/null
+++ b/gs/src/gdevpe.c
@@ -0,0 +1,362 @@
+/* Copyright (C) 1989, 1990, 1991, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpe.c Private Eye display driver
+ Hacked by Fran Taylor, Reflection Technology Inc. */
+
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+
+char *getenv(char *name);
+
+typedef struct gx_device_pe_s {
+ gx_device_common;
+ byte *fbaddr;
+ unsigned regs;
+} gx_device_pe;
+#define pedev ((gx_device_pe *)dev)
+
+typedef struct {
+ ushort reg, val;
+} regval;
+
+#define XSIZE 720
+#define YSIZE 280
+#define BPL 90
+#define XPPI 160.0
+#define YPPI 96.0
+#define DEFAULT_ADDRESS ((byte *) 0xb8000000)
+#define DEFAULT_REGISTERS 0x3d0
+
+dev_proc_open_device(pe_open);
+dev_proc_close_device(pe_close);
+dev_proc_fill_rectangle(pe_fill_rectangle);
+dev_proc_copy_mono(pe_copy_mono);
+
+private gx_device_procs pe_procs =
+{ pe_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ pe_close,
+ NULL, /* map_rgb_color */
+ NULL, /* map_color_rgb */
+ pe_fill_rectangle,
+ NULL, /* tile_rectangle */
+ pe_copy_mono,
+ NULL /* copy_color */
+};
+
+gx_device_pe far_data gs_pe_device =
+{ std_device_std_body(gx_device_pe, &pe_procs, "pe",
+ XSIZE, YSIZE, XPPI, YPPI),
+ { 0 }, /* std_procs */
+ DEFAULT_ADDRESS, DEFAULT_REGISTERS
+};
+
+static regval peinit[] = {{0x04, 0x1e}, {0x05, 0x00},
+ {0x04, 0x0c}, {0x05, 0x21},
+ {0x04, 0x0d}, {0x05, 0x98},
+ {0x08, 0x00}, {0x08, 0x1e},
+ {0x04, 0x1e}, {0x05, 0x01}};
+
+static regval pedone[] = {{0x04, 0x1e}, {0x05, 0x10},
+ {0x04, 0x0a}, {0x05, 0x00},
+ {0x04, 0x0b}, {0x05, 0x07},
+ {0x04, 0x0c}, {0x05, 0x00},
+ {0x04, 0x0d}, {0x05, 0x00},
+ {0x04, 0x0e}, {0x05, 0x00},
+ {0x04, 0x0f}, {0x05, 0x00},
+ {0x08, 0x00}, {0x08, 0x29}};
+
+int pe_open(gx_device *dev)
+{
+ char *str;
+ int i;
+
+ if ((str = getenv("PEFBADDR")) != 0)
+ {
+ if (!sscanf(str, "%lx", &(pedev->fbaddr)))
+ {
+ eprintf("Private Eye: PEFBADDR environment string format error\n");
+ exit(1);
+ }
+ }
+
+ if ((str = getenv("PEREGS")) != 0)
+ {
+ if (!sscanf(str, "%x", &(pedev->regs)))
+ {
+ eprintf("Private Eye: PEREGS environment string format error\n");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < 10; i++)
+ outportb(pedev->regs + peinit[i].reg, peinit[i].val);
+
+ return 0;
+}
+
+int pe_close(gx_device *dev)
+{
+ int i;
+
+ /* restore the screen */
+ for (i = 0; i < 16; i++)
+ outportb(pedev->regs + pedone[i].reg, pedone[i].val);
+
+ /* clear the frame buffer */
+ memset(pedev->fbaddr, 0, 4000);
+
+ return 0;
+}
+
+int pe_fill_rectangle(gx_device *dev, int x1, int y1, int w, int h,
+ gx_color_index color)
+{
+ int x2, y2, xlen;
+ byte led, red, d;
+ byte *ptr;
+
+ /* cull */
+
+ if ((w <= 0) || (h <= 0) || (x1 > XSIZE) || (y1 > YSIZE))
+ return 0;
+
+ x2 = x1 + w - 1;
+ y2 = y1 + h - 1;
+
+ /* cull some more */
+
+ if ((x2 < 0) || (y2 < 0))
+ return 0;
+
+ /* clip */
+
+ if (x1 < 0) x1 = 0;
+ if (x2 > XSIZE-1) x2 = XSIZE-1;
+ if (y1 < 0) y1 = 0;
+ if (y2 > YSIZE-1) y2 = YSIZE-1;
+
+ w = x2 - x1 + 1;
+ h = y2 - y1 + 1;
+ xlen = (x2 >> 3) - (x1 >> 3) - 1;
+ led = 0xff >> (x1 & 7);
+ red = 0xff << (7 - (x2 & 7));
+
+ ptr = pedev->fbaddr + (y1 * BPL) + (x1 >> 3);
+
+ if (color)
+ {
+ /* here to set pixels */
+
+ if (xlen == -1)
+ {
+ /* special for rectangles that fit in a byte */
+
+ d = led & red;
+ for(; h >= 0; h--, ptr += BPL)
+ *ptr |= d;
+ return 0;
+ }
+
+ /* normal fill */
+
+ for(; h >= 0; h--, ptr += BPL)
+ { register int x = xlen;
+ register byte *p = ptr;
+ *p++ |= led;
+ while ( x-- ) *p++ = 0xff;
+ *p |= red;
+ }
+ }
+
+ /* here to clear pixels */
+
+ led = ~led;
+ red = ~red;
+
+ if (xlen == -1)
+ {
+ /* special for rectangles that fit in a byte */
+
+ d = led | red;
+ for(; h >= 0; h--, ptr += BPL)
+ *ptr &= d;
+ return 0;
+ }
+
+ /* normal fill */
+
+ for(; h >= 0; h--, ptr += BPL)
+ { register int x = xlen;
+ register byte *p = ptr;
+ *p++ &= led;
+ while ( x-- ) *p++ = 0x00;
+ *p &= red;
+ }
+ return 0;
+}
+
+int pe_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+ const byte *line;
+ int sleft, dleft;
+ int mask, rmask;
+ int invert, zmask, omask;
+ byte *dest;
+ int offset;
+
+#define izero (int)zero
+#define ione (int)one
+
+if ( ione == izero ) /* vacuous case */
+ return pe_fill_rectangle(dev, x, y, w, h, zero);
+
+ /* clip */
+
+ if ((x > XSIZE) || (y > YSIZE) || ((x + w) < 0) || ((y + h) < 0))
+ return 0;
+
+ offset = x >> 3;
+ dest = pedev->fbaddr + (y * BPL) + offset;
+ line = base + (sourcex >> 3);
+ sleft = 8 - (sourcex & 7);
+ dleft = 8 - (x & 7);
+ mask = 0xff >> (8 - dleft);
+ if ( w < dleft )
+ mask -= mask >> w;
+ else
+ rmask = 0xff00 >> ((w - dleft) & 7);
+
+ /* Macros for writing partial bytes. */
+ /* bits has already been inverted by xor'ing with invert. */
+
+#define write_byte_masked(ptr, bits, mask)\
+ *ptr = ((bits | ~mask | zmask) & *ptr | (bits & mask & omask))
+
+#define write_byte(ptr, bits)\
+ *ptr = ((bits | zmask) & *ptr | (bits & omask))
+
+/* if ( dev->invert )
+ {
+ if ( izero != (int)gx_no_color_index ) zero ^= 1;
+ if ( ione != (int)gx_no_color_index ) one ^= 1;
+ } */
+ invert = (izero == 1 || ione == 0 ? -1 : 0);
+ zmask = (izero == 0 || ione == 0 ? 0 : -1);
+ omask = (izero == 1 || ione == 1 ? -1 : 0);
+
+#undef izero
+#undef ione
+
+ if (sleft == dleft) /* optimize the aligned case */
+ {
+ w -= dleft;
+ while ( --h >= 0 )
+ {
+ register const byte *bptr = line;
+ int count = w;
+ register byte *optr = dest;
+ register int bits = *bptr ^ invert; /* first partial byte */
+
+ write_byte_masked(optr, bits, mask);
+
+ /* Do full bytes. */
+
+ while ((count -= 8) >= 0)
+ {
+ bits = *++bptr ^ invert;
+ ++optr;
+ write_byte(optr, bits);
+ }
+
+ /* Do last byte */
+
+ if (count > -8)
+ {
+ bits = *++bptr ^ invert;
+ ++optr;
+ write_byte_masked(optr, bits, rmask);
+ }
+ dest += BPL;
+ line += raster;
+ }
+ }
+ else
+ {
+ int skew = (sleft - dleft) & 7;
+ int cskew = 8 - skew;
+
+ while (--h >= 0)
+ {
+ const byte *bptr = line;
+ int count = w;
+ byte *optr = dest;
+ register int bits;
+
+ /* Do the first partial byte */
+
+ if (sleft >= dleft)
+ {
+ bits = *bptr >> skew;
+ }
+ else /* ( sleft < dleft ) */
+ {
+ bits = *bptr++ << cskew;
+ if (count > sleft)
+ bits += *bptr >> skew;
+ }
+ bits ^= invert;
+ write_byte_masked(optr, bits, mask);
+ count -= dleft;
+ optr++;
+
+ /* Do full bytes. */
+
+ while ( count >= 8 )
+ {
+ bits = *bptr++ << cskew;
+ bits += *bptr >> skew;
+ bits ^= invert;
+ write_byte(optr, bits);
+ count -= 8;
+ optr++;
+ }
+
+ /* Do last byte */
+
+ if (count > 0)
+ {
+ bits = *bptr++ << cskew;
+ if (count > skew)
+ bits += *bptr >> skew;
+ bits ^= invert;
+ write_byte_masked(optr, bits, rmask);
+ }
+ dest += BPL;
+ line += raster;
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gdevpipe.c b/gs/src/gdevpipe.c
new file mode 100644
index 000000000..a34bcaf6f
--- /dev/null
+++ b/gs/src/gdevpipe.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpipe.c */
+/* %pipe% IODevice */
+#include "errno_.h"
+#include "stdio_.h"
+#include "string_.h"
+#include "gserror.h"
+#include "gstypes.h"
+#include "gsmemory.h" /* for gxiodev.h */
+#include "stream.h"
+#include "gxiodev.h"
+
+/* popen isn't POSIX-standard, so we declare it here. */
+/* Because of inconsistent (and sometimes incorrect) header files, */
+/* we must omit the argument list. */
+extern FILE *popen( /* P2(const char *, const char *) */ );
+extern int pclose(P1(FILE *));
+
+/* The pipe IODevice */
+private iodev_proc_fopen(pipe_fopen);
+private iodev_proc_fclose(pipe_fclose);
+gx_io_device gs_iodev_pipe = {
+ "%pipe%", "FileSystem",
+ { iodev_no_init, iodev_no_open_device,
+ NULL /*iodev_os_open_file*/, pipe_fopen, pipe_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ iodev_no_get_params, iodev_no_put_params
+ }
+};
+
+/* The file device procedures */
+
+private int
+pipe_fopen(gx_io_device *iodev, const char *fname, const char *access,
+ FILE **pfile, char *rfname, uint rnamelen)
+{ /* The OSF/1 1.3 library doesn't include const in the */
+ /* prototype for popen.... */
+ errno = 0;
+ *pfile = popen((char *)fname, (char *)access);
+ if ( *pfile == NULL )
+ return_error(gs_fopen_errno_to_code(errno));
+ if ( rfname != NULL )
+ strcpy(rfname, fname);
+ return 0;
+}
+
+private int
+pipe_fclose(gx_io_device *iodev, FILE *file)
+{ pclose(file);
+ return 0;
+}
diff --git a/gs/src/gdevpjet.c b/gs/src/gdevpjet.c
new file mode 100644
index 000000000..547217d11
--- /dev/null
+++ b/gs/src/gdevpjet.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 1991, 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpjet.c */
+/* H-P PaintJet, PaintJet XL, and DEC LJ250 drivers. */
+/* Thanks to Rob Reiss (rob@moray.berkeley.edu) for the PaintJet XL */
+/* modifications. */
+#include "gdevprn.h"
+#include "gdevpcl.h"
+
+/* X_DPI and Y_DPI must be the same, and may be either 90 or 180. */
+#define X_DPI 180
+#define Y_DPI 180
+
+/* We round up LINE_SIZE to a multiple of 8 bytes */
+/* because that's the unit of transposition from pixels to planes. */
+#define LINE_SIZE ((X_DPI * 85 / 10 + 63) / 64 * 8)
+
+/* The device descriptors */
+private dev_proc_print_page(lj250_print_page);
+private dev_proc_print_page(paintjet_print_page);
+private dev_proc_print_page(pjetxl_print_page);
+private int pj_common_print_page(P4(gx_device_printer *, FILE *, int, const char *));
+private gx_device_procs paintjet_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
+gx_device_printer far_data gs_lj250_device =
+ prn_device(paintjet_procs, "lj250",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ X_DPI, Y_DPI,
+ 0.25, 0, 0.25, 0, /* margins */
+ 3, lj250_print_page);
+gx_device_printer far_data gs_paintjet_device =
+ prn_device(paintjet_procs, "paintjet",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ X_DPI, Y_DPI,
+ 0.25, 0, 0.25, 0, /* margins */
+ 3, paintjet_print_page);
+private gx_device_procs pjetxl_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
+gx_device_printer far_data gs_pjetxl_device =
+ prn_device(pjetxl_procs, "pjetxl",
+ 85, /* width_10ths, 8.5" */
+ 110, /* height_10ths, 11" */
+ X_DPI, Y_DPI,
+ 0.25, 0, 0, 0, /* margins */
+ 3, pjetxl_print_page);
+
+/* Forward references */
+private int compress1_row(P3(const byte *, const byte *, byte *));
+
+/* ------ Internal routines ------ */
+
+/* Send a page to the LJ250. We need to enter and exit */
+/* the PaintJet emulation mode. */
+private int
+lj250_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ fputs("\033%8", prn_stream); /* Enter PCL emulation mode */
+ /* ends raster graphics to set raster graphics resolution */
+ fputs("\033*rB", prn_stream);
+ /* Exit PCL emulation mode after printing */
+ return pj_common_print_page(pdev, prn_stream, 0, "\033*r0B\014\033%@");
+}
+
+/* Send a page to the PaintJet. */
+private int
+paintjet_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ /* ends raster graphics to set raster graphics resolution */
+ fputs("\033*rB", prn_stream);
+ return pj_common_print_page(pdev, prn_stream, 0, "\033*r0B\014");
+}
+
+/* Send a page to the PaintJet XL. */
+private int
+pjetxl_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ /* Initialize PaintJet XL for printing */
+ fputs("\033E", prn_stream);
+ /* The XL has a different vertical origin, who knows why?? */
+ return pj_common_print_page(pdev, prn_stream, -360, "\033*rC");
+}
+
+/* Send the page to the printer. Compress each scan line. */
+private int
+pj_common_print_page(gx_device_printer *pdev, FILE *prn_stream, int y_origin,
+ const char *end_page)
+{
+#define DATA_SIZE (LINE_SIZE * 8)
+ byte *data =
+ (byte *)gs_malloc(DATA_SIZE, 1,
+ "paintjet_print_page(data)");
+ byte *plane_data =
+ (byte *)gs_malloc(LINE_SIZE * 3, 1,
+ "paintjet_print_page(plane_data)");
+ if ( data == 0 || plane_data == 0 )
+ { if ( data )
+ gs_free((char *)data, DATA_SIZE, 1,
+ "paintjet_print_page(data)");
+ if ( plane_data )
+ gs_free((char *)plane_data, LINE_SIZE * 3, 1,
+ "paintjet_print_page(plane_data)");
+ return_error(gs_error_VMerror);
+ }
+
+ /* set raster graphics resolution -- 90 or 180 dpi */
+ fprintf(prn_stream, "\033*t%dR", X_DPI);
+
+ /* set the line width */
+ fprintf(prn_stream, "\033*r%dS", DATA_SIZE);
+
+ /* set the number of color planes */
+ fprintf(prn_stream, "\033*r%dU", 3); /* always 3 */
+
+ /* move to top left of page */
+ fprintf(prn_stream, "\033&a0H\033&a%dV", y_origin);
+
+ /* select data compression */
+ fputs("\033*b1M", prn_stream);
+
+ /* start raster graphics */
+ fputs("\033*r1A", prn_stream);
+
+ /* Send each scan line in turn */
+ { int lnum;
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int num_blank_lines = 0;
+ for ( lnum = 0; lnum < pdev->height; lnum++ )
+ { byte *end_data = data + line_size;
+ gdev_prn_copy_scan_lines(pdev, lnum,
+ (byte *)data, line_size);
+ /* Remove trailing 0s. */
+ while ( end_data > data && end_data[-1] == 0 )
+ end_data--;
+ if ( end_data == data )
+ { /* Blank line */
+ num_blank_lines++;
+ }
+ else
+ { int i;
+ byte *odp;
+ byte *row;
+
+ /* Pad with 0s to fill out the last */
+ /* block of 8 bytes. */
+ memset(end_data, 0, 7);
+
+ /* Transpose the data to get pixel planes. */
+ for ( i = 0, odp = plane_data; i < DATA_SIZE;
+ i += 8, odp++
+ )
+ { /* The following is for 16-bit machines */
+#define spread3(c)\
+ { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
+ static ulong spr40[8] = spread3(0x40);
+ static ulong spr8[8] = spread3(8);
+ static ulong spr2[8] = spread3(2);
+ register byte *dp = data + i;
+ register ulong pword =
+ (spr40[dp[0]] << 1) +
+ (spr40[dp[1]]) +
+ (spr40[dp[2]] >> 1) +
+ (spr8[dp[3]] << 1) +
+ (spr8[dp[4]]) +
+ (spr8[dp[5]] >> 1) +
+ (spr2[dp[6]]) +
+ (spr2[dp[7]] >> 1);
+ odp[0] = (byte)(pword >> 16);
+ odp[LINE_SIZE] = (byte)(pword >> 8);
+ odp[LINE_SIZE*2] = (byte)(pword);
+ }
+ /* Skip blank lines if any */
+ if ( num_blank_lines > 0 )
+ { /* move down from current position */
+ fprintf(prn_stream, "\033&a+%dV",
+ num_blank_lines * (720 / Y_DPI));
+ num_blank_lines = 0;
+ }
+
+ /* Transfer raster graphics */
+ /* in the order R, G, B. */
+ for ( row = plane_data + LINE_SIZE * 2, i = 0;
+ i < 3; row -= LINE_SIZE, i++
+ )
+ { byte temp[LINE_SIZE * 2];
+ int count = compress1_row(row, row + LINE_SIZE, temp);
+ fprintf(prn_stream, "\033*b%d%c",
+ count, "VVW"[i]);
+ fwrite(temp, sizeof(byte),
+ count, prn_stream);
+ }
+ }
+ }
+ }
+
+ /* end the page */
+ fputs(end_page, prn_stream);
+
+ gs_free((char *)data, DATA_SIZE, 1, "paintjet_print_page(data)");
+ gs_free((char *)plane_data, LINE_SIZE * 3, 1, "paintjet_print_page(plane_data)");
+
+ return 0;
+}
+
+/*
+ * Row compression for the H-P PaintJet.
+ * Compresses data from row up to end_row, storing the result
+ * starting at compressed. Returns the number of bytes stored.
+ * The compressed format consists of a byte N followed by a
+ * data byte that is to be repeated N+1 times.
+ * In the worst case, the `compressed' representation is
+ * twice as large as the input.
+ * We complement the bytes at the same time, because
+ * we accumulated the image in complemented form.
+ */
+private int
+compress1_row(const byte *row, const byte *end_row,
+ byte *compressed)
+{ register const byte *in = row;
+ register byte *out = compressed;
+ while ( in < end_row )
+ { byte test = *in++;
+ const byte *run = in;
+ while ( in < end_row && *in == test ) in++;
+ /* Note that in - run + 1 is the repetition count. */
+ while ( in - run > 255 )
+ { *out++ = 255;
+ *out++ = ~test;
+ run += 256;
+ }
+ *out++ = in - run;
+ *out++ = ~test;
+ }
+ return out - compressed;
+}
diff --git a/gs/src/gdevpm.c b/gs/src/gdevpm.c
new file mode 100644
index 000000000..dc1c190f4
--- /dev/null
+++ b/gs/src/gdevpm.c
@@ -0,0 +1,1262 @@
+/* Copyright (C) 1992, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpm.c */
+/*
+ * OS/2 Presentation manager driver
+ * By Russell Lang (based on gdevmswn.c and gdevwdib.c)
+ *
+ * If Ghostscript is a PM application, stdin/stdout are not
+ * provided and so no text window is available.
+ * If Ghostscript is a windowed text application, a message queue
+ * can't be created so a PM window for graphics can't be created.
+ * The solution used here is to have two programs - gsos2.exe is a
+ * text application and the outboard PM driver is gspmdrv.exe.
+ * Another solution may be to make Ghostscript a PM application
+ * and use VIO calls to provide a text window.
+ *
+ * If PM GSview starts Ghostscript, PM GSview displays the
+ * bitmap instead of the PM driver (gspmdrv.exe).
+ *
+ * Since Ghostscript is not a PM application, this driver creates a
+ * BMP bitmap in a named shared memory block and a second process
+ * gspmdrv.exe reads this memory block and provides the PM window.
+ * Communication to gspmdrv.exe is via the shared memory block
+ * and semaphores.
+ */
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_WINWINDOWMGR
+#define INCL_DEV
+#define INCL_GPIBITMAPS
+
+#include <os2.h>
+#include "string_.h"
+#include <stdlib.h>
+#include "gx.h"
+#include "gserrors.h"
+#include "gsexit.h" /* for gs_exit_status */
+#include "gxdevice.h"
+
+#include "gp.h"
+#include "gpcheck.h"
+#include "gsparam.h"
+#include "gdevpccm.h"
+
+#include "gxdevmem.h"
+#include "gdevpm.h"
+#ifdef __DLL__
+#include "gsdll.h"
+#endif
+
+#define MIN_COMMIT 4096 /* memory is committed in these size chunks */
+#define ID_NAME "GSPMDRV_%u_%u"
+
+/* Initial values for width and height */
+#define INITIAL_RESOLUTION 96
+#define INITIAL_WIDTH (INITIAL_RESOLUTION * 85 / 10 + 1)
+#define INITIAL_HEIGHT (INITIAL_RESOLUTION * 11 + 1)
+
+/* A macro for casting the device argument */
+#define pmdev ((gx_device_pm *)dev)
+
+
+#define pm_gsview_sizeof 80
+typedef struct gx_device_pm_s gx_device_pm;
+
+#define gx_device_pm_common\
+ int BitsPerPixel;\
+ int alpha_text;\
+ int alpha_graphics;\
+ int UpdateInterval;\
+ char GSVIEW[pm_gsview_sizeof];\
+ BOOL dll;\
+ int nColors;\
+ BOOL updating;\
+ HTIMER update_timer;\
+ HEV sync_event;\
+ HEV next_event;\
+ HMTX bmp_mutex;\
+ HQUEUE drv_queue;\
+ HQUEUE term_queue;\
+ ULONG session_id;\
+ PID process_id;\
+ PID gspid;\
+ unsigned char *bitmap;\
+ ULONG committed;\
+ PBITMAPINFO2 bmi
+
+/* The device descriptor */
+struct gx_device_pm_s {
+ gx_device_common;
+ gx_device_pm_common;
+ gx_device_memory mdev;
+};
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(pm_open);
+private dev_proc_get_initial_matrix(pm_get_initial_matrix);
+private dev_proc_sync_output(pm_sync_output);
+private dev_proc_output_page(pm_output_page);
+private dev_proc_close_device(pm_close);
+private dev_proc_map_rgb_color(pm_map_rgb_color);
+private dev_proc_map_color_rgb(pm_map_color_rgb);
+private dev_proc_fill_rectangle(pm_fill_rectangle);
+private dev_proc_copy_mono(pm_copy_mono);
+private dev_proc_copy_color(pm_copy_color);
+private dev_proc_get_bits(pm_get_bits);
+private dev_proc_get_params(pm_get_params);
+private dev_proc_put_params(pm_put_params);
+private dev_proc_get_alpha_bits(pm_get_alpha_bits);
+
+private gx_device_procs pm_procs = {
+ pm_open,
+ pm_get_initial_matrix,
+ pm_sync_output,
+ pm_output_page,
+ pm_close,
+ pm_map_rgb_color,
+ pm_map_color_rgb,
+ pm_fill_rectangle,
+ NULL, /* tile rectangle */
+ pm_copy_mono,
+ pm_copy_color,
+ NULL, /* draw line */
+ pm_get_bits,
+ pm_get_params,
+ pm_put_params,
+ NULL, /* map_cmyk_color */
+ gx_default_get_xfont_procs,
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device,
+ pm_get_alpha_bits
+};
+#ifdef __DLL__
+gx_device_pm far_data gs_os2dll_device = {
+ std_device_std_body(gx_device_pm, &pm_procs, "os2dll",
+ INITIAL_WIDTH, INITIAL_HEIGHT,
+ INITIAL_RESOLUTION, INITIAL_RESOLUTION),
+ { 0 }, /* std_procs */
+ 8, /* BitsPerPixel */
+ 1, 1, /* alpha */
+ 5000, /* UpdateInterval */
+ "\0", /* GSVIEW */
+ 1 /* is DLL device */
+};
+#endif
+gx_device_pm far_data gs_os2pm_device = {
+ std_device_std_body(gx_device_pm, &pm_procs, "os2pm",
+ INITIAL_WIDTH, INITIAL_HEIGHT,
+ INITIAL_RESOLUTION, INITIAL_RESOLUTION),
+ { 0 }, /* std_procs */
+ 8, /* BitsPerPixel */
+ 1, 1, /* alpha */
+ 5000, /* UpdateInterval */
+ "\0", /* GSVIEW */
+ 0 /* is not DLL device */
+};
+
+/* Compress a gx_color_value into an 8-bit PM color value, */
+/* using only the high order 5 bits. */
+#define pm_color_value(z)\
+ ((((z) >> (gx_color_value_bits - 5)) << 3) +\
+ ((z) >> (gx_color_value_bits - 3)))
+
+/* prototypes for internal procedures */
+private void pm_makepalette(gx_device_pm *);
+private void pm_update(gx_device_pm *);
+private uint pm_set_bits_per_pixel(gx_device_pm *, int);
+private uint pm_palette_size(gx_device_pm *);
+private int pm_alloc_bitmap(gx_device_pm *, gx_device *);
+private int pm_run_gspmdrv(gx_device_pm *);
+private void pm_write_bmp(gx_device_pm *);
+
+/* Open the pm driver */
+int
+pm_open(gx_device *dev)
+{
+ int ccode;
+ CHAR id[128];
+ CHAR name[128];
+ PTIB pptib;
+ PPIB pppib;
+
+ if (!pmdev->dll && (_osmode == DOS_MODE)) {
+ fprintf(stderr,"os2pm driver can't be used under DOS\n");
+ return gs_error_limitcheck;
+ }
+
+ if (DosGetInfoBlocks(&pptib, &pppib)) {
+ fprintf(stderr,"\npm_open: Couldn't get pid\n");
+ return gs_error_limitcheck;
+ }
+#ifdef __DLL__
+ if (pppib->pib_ultype == 3) /* if caller is PM app */
+ pmdev->gspid = pppib->pib_ulpid; /* use caller pid */
+ else
+#endif
+ pmdev->gspid = pppib->pib_ulppid; /* use parent (CMD.EXE) pid */
+ sprintf(id, ID_NAME, pmdev->gspid, (ULONG)dev);
+
+ /* Allocate, but don't commit, enough memory for the largest */
+ /* possible bitmap (13Mbytes = A3 x 150dpi x 24bits) */
+#ifdef __DLL__
+ if (pmdev->dll) {
+ /* We don't need to use shared memory for the DLL */
+ if (DosAllocMem((PPVOID)&pmdev->bitmap,
+ 13*1024*1024, PAG_READ | PAG_WRITE)) {
+ fprintf(stderr,"pm_open: failed allocating BMP memory\n");
+ return gs_error_limitcheck;
+ }
+ }
+ else
+#endif
+ {
+ /* Shared memory is common to all processes so we don't want to allocate too much */
+ sprintf(name, SHARED_NAME, *pmdev->GSVIEW ? pmdev->GSVIEW : id);
+ if (DosAllocSharedMem((PPVOID)&pmdev->bitmap, name,
+ 13*1024*1024, PAG_READ | PAG_WRITE)) {
+ fprintf(stderr,"pm_open: failed allocating shared BMP memory %s\n", name);
+ return gs_error_limitcheck;
+ }
+ }
+
+ /* commit one page so there is enough storage for a */
+ /* bitmap header and palette */
+ if (DosSetMem(pmdev->bitmap, MIN_COMMIT, PAG_COMMIT | PAG_DEFAULT)) {
+ DosFreeMem(pmdev->bitmap);
+ fprintf(stderr,"pm_open: failed committing BMP memory\n");
+ return gs_error_limitcheck;
+ }
+ pmdev->committed = MIN_COMMIT;
+
+ if (pmdev->dll) {
+ /* Create mutex - used for preventing another thread from accessing */
+ /* bitmap while we are changing the bitmap size. Initially unowned. */
+ sprintf(name, MUTEX_NAME, id);
+ if (DosCreateMutexSem(name, &(pmdev->bmp_mutex), 0, FALSE)) {
+ DosFreeMem(pmdev->bitmap);
+ DosCloseEventSem(pmdev->sync_event);
+ DosCloseQueue(pmdev->drv_queue);
+ fprintf(stderr,"pm_open: failed to create mutex semaphore %s\n", name);
+ return gs_error_limitcheck;
+ }
+ }
+ else {
+ if (*pmdev->GSVIEW) {
+ APIRET rc;
+ /* GSview has already created the necessary objects */
+ /* so we use Open instead of Create */
+ rc = 0;
+ if (!rc) {
+ sprintf(name, NEXT_NAME, pmdev->GSVIEW);
+ rc = DosOpenEventSem(name, &pmdev->next_event);
+ }
+ if (!rc) {
+ sprintf(name, MUTEX_NAME, pmdev->GSVIEW);
+ rc = DosOpenMutexSem(name, &pmdev->bmp_mutex);
+ }
+ if (!rc) {
+ PID owner_pid;
+ sprintf(name, QUEUE_NAME, pmdev->GSVIEW);
+ rc = DosOpenQueue(&owner_pid, &pmdev->drv_queue, name);
+ }
+ if (rc) {
+ DosFreeMem(pmdev->bitmap);
+ DosCloseEventSem(pmdev->next_event);
+ fprintf(stderr, "pm_open: failed to open %s, rc = %u\n", name, rc);
+ return gs_error_limitcheck;
+ }
+ }
+ else { /* not GSVIEW */
+ /* Create update event semaphore */
+ sprintf(name, SYNC_NAME, id);
+ if (DosCreateEventSem(name, &(pmdev->sync_event), 0, FALSE)) {
+ DosFreeMem(pmdev->bitmap);
+ fprintf(stderr,"pm_open: failed to create event semaphore %s\n", name);
+ return gs_error_limitcheck;
+ }
+ /* Create mutex - used for preventing gspmdrv from accessing */
+ /* bitmap while we are changing the bitmap size. Initially unowned. */
+ sprintf(name, MUTEX_NAME, id);
+ if (DosCreateMutexSem(name, &(pmdev->bmp_mutex), 0, FALSE)) {
+ DosFreeMem(pmdev->bitmap);
+ DosCloseEventSem(pmdev->sync_event);
+ DosCloseQueue(pmdev->drv_queue);
+ fprintf(stderr,"pm_open: failed to create mutex semaphore %s\n", name);
+ return gs_error_limitcheck;
+ }
+ }
+ }
+
+ if ( (pm_set_bits_per_pixel(pmdev, pmdev->BitsPerPixel) < 0) ||
+ (gdev_mem_device_for_bits(dev->color_info.depth) == 0) )
+ {
+ if (!pmdev->dll) {
+ if (*pmdev->GSVIEW) {
+ DosCloseQueue(pmdev->drv_queue);
+ DosCloseEventSem(pmdev->next_event);
+ }
+ else
+ DosCloseEventSem(pmdev->sync_event);
+ }
+ DosCloseMutexSem(pmdev->bmp_mutex);
+ DosFreeMem(pmdev->bitmap);
+ return gs_error_limitcheck;
+ }
+
+ /* initialise bitmap header */
+ pmdev->bmi = (PBITMAPINFO2)pmdev->bitmap;
+ pmdev->bmi->cbFix = 40; /* OS/2 2.0 and Windows 3.0 compatible */
+ pmdev->bmi->cx = dev->width;
+ pmdev->bmi->cy = dev->height;
+ pmdev->bmi->cPlanes = 1;
+ pmdev->bmi->cBitCount = dev->color_info.depth;
+ pmdev->bmi->ulCompression = BCA_UNCOMP;
+ pmdev->bmi->cbImage = 0;
+ pmdev->bmi->cxResolution = (ULONG)(dev->x_pixels_per_inch / 25.4 * 1000);
+ pmdev->bmi->cyResolution = (ULONG)(dev->y_pixels_per_inch / 25.4 * 1000);
+ if (pmdev->BitsPerPixel <= 8) {
+ pmdev->bmi->cclrUsed = 1<<(pmdev->BitsPerPixel);
+ pmdev->bmi->cclrImportant = pmdev->nColors;
+ }
+ else {
+ pmdev->bmi->cclrUsed = 0;
+ pmdev->bmi->cclrImportant = 0;
+ }
+
+ pm_makepalette(pmdev);
+
+ /* commit pages */
+ ccode = pm_alloc_bitmap((gx_device_pm *)dev, dev);
+ if (ccode < 0) {
+ if (!pmdev->dll) {
+ if (*pmdev->GSVIEW) {
+ DosCloseQueue(pmdev->drv_queue);
+ DosCloseEventSem(pmdev->next_event);
+ }
+ else
+ DosCloseEventSem(pmdev->sync_event);
+ }
+ DosCloseMutexSem(pmdev->bmp_mutex);
+ DosFreeMem(pmdev->bitmap);
+ return ccode;
+ }
+
+ if (*pmdev->GSVIEW)
+ return 0; /* GSview will handle displaying */
+
+#ifdef __DLL__
+ if (pmdev->dll) {
+ /* notify caller about new device */
+ (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)pmdev, 1);
+ return 0; /* caller will handle displaying */
+ }
+#endif
+
+ ccode = pm_run_gspmdrv(pmdev);
+ if (ccode < 0) {
+ DosFreeMem(pmdev->bitmap);
+ DosCloseEventSem(pmdev->sync_event);
+ DosCloseMutexSem(pmdev->bmp_mutex);
+ }
+
+ return ccode;
+}
+
+/* Get the initial matrix. BMPs, unlike most displays, */
+/* put (0,0) in the lower left corner. */
+private void
+pm_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+{ pmat->xx = dev->x_pixels_per_inch / 72.0;
+ pmat->xy = 0;
+ pmat->yx = 0;
+ pmat->yy = dev->y_pixels_per_inch / 72.0;
+ pmat->tx = 0;
+ pmat->ty = 0;
+ if (*pmdev->GSVIEW)
+ pm_update((gx_device_pm *)dev); /* let GSVIEW know we are drawing */
+}
+
+/* Make the output appear on the screen. */
+int
+pm_sync_output(gx_device *dev)
+{
+#ifdef __DLL__
+ if (pmdev->dll) {
+ (*pgsdll_callback)(GSDLL_SYNC, (unsigned char *)dev, 0);
+ return 0;
+ }
+#endif
+
+ /* tell gspmdrv or GSview process to update display */
+ if (*pmdev->GSVIEW) {
+ APIRET rc;
+ rc = DosWriteQueue(pmdev->drv_queue, GS_SYNC, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_sync_output: DosWriteQueue error %d\n",rc);
+ }
+ else {
+ if (pmdev->updating)
+ DosStopTimer(pmdev->update_timer);
+ DosPostEventSem(pmdev->sync_event);
+ }
+ pmdev->updating = FALSE;
+ return(0);
+}
+
+/* Make the output appear on the screen */
+/* and bring image window to foreground. */
+int
+pm_output_page(gx_device *dev, int copies, int flush)
+{
+int code;
+APIRET rc;
+#ifdef DEBUG
+ pm_write_bmp(pmdev);
+#endif
+#ifdef __DLL__
+ if (pmdev->dll) {
+ (*pgsdll_callback)(GSDLL_PAGE, (unsigned char *)dev, 0);
+ return 0;
+ }
+#endif
+
+ if (*pmdev->GSVIEW) {
+ if (copies == -2) {
+ rc = DosWriteQueue(pmdev->drv_queue, GS_END, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_output_page: DosWriteQueue error %d\n",rc);
+ }
+ else if (copies == -1) {
+ rc = DosWriteQueue(pmdev->drv_queue, GS_BEGIN, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_output_page: DosWriteQueue error %d\n",rc);
+ }
+ else {
+ ULONG count;
+ pmdev->updating = FALSE;
+ /* signal GSview that another page is ready */
+ rc = DosWriteQueue(pmdev->drv_queue, GS_PAGE, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_output_page: DosWriteQueue error %d\n",rc);
+ /* wait for GSview to signal we can move on to next page */
+ DosWaitEventSem(pmdev->next_event, SEM_INDEFINITE_WAIT);
+ DosResetEventSem(pmdev->next_event, &count);
+ }
+ code = 0;
+ }
+ else {
+ code = pm_sync_output(dev);
+ rc = DosSelectSession(pmdev->session_id);
+ if (rc) {
+ DosSleep(2000); /* give gspmdrv.exe a chance to run */
+ rc = DosSelectSession(pmdev->session_id);
+ if (rc == ERROR_SMG_NO_TARGET_WINDOW) {
+ DosSleep(5000); /* give gspmdrv.exe a chance to run */
+ rc = DosSelectSession(pmdev->session_id); /* try yet again */
+ }
+ if ( (rc == ERROR_SMG_SESSION_NOT_FOUND) ||
+ (rc == ERROR_SMG_INVALID_SESSION_ID) ){
+ /* someone has killed the session */
+ REQUESTDATA Request;
+ ULONG DataLength;
+ PVOID DataAddress;
+ PULONG QueueEntry;
+ BYTE ElemPriority;
+ /* Close gspmdrv driver */
+ DosStopSession(STOP_SESSION_SPECIFIED, pmdev->session_id);
+ Request.pid = pmdev->gspid;
+ Request.ulData = 0;
+ /* wait for termination queue, queue is then closed by session manager */
+ DosReadQueue(pmdev->term_queue, &Request, &DataLength,
+ &DataAddress, 0, DCWW_WAIT, &ElemPriority, (HEV)NULL);
+ DosCloseQueue(pmdev->term_queue);
+ pmdev->term_queue = (HQUEUE)0;
+ /* restart it */
+ pm_run_gspmdrv(pmdev);
+ DosSleep(2000); /* give gspmdrv.exe a chance to run */
+ rc = DosSelectSession(pmdev->session_id);
+ }
+ if (rc == ERROR_SMG_SESSION_NOT_FOREGRND)
+ DosBeep(400,50);
+ else if (rc)
+ fprintf(stderr,"pm_output_page: Select Session error code %u\n", rc);
+ }
+ }
+ return code;
+}
+
+/* Close the pm driver */
+int
+pm_close(gx_device *dev)
+{
+APIRET rc;
+#ifdef __DLL__
+ if (pmdev->dll) {
+ DosRequestMutexSem(pmdev->bmp_mutex, 60000);
+ (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 0);
+ DosReleaseMutexSem(pmdev->bmp_mutex);
+ }
+ else
+#endif
+ {
+ if (*pmdev->GSVIEW) {
+ if (gs_exit_status) {
+ ULONG count;
+ /* pause so error messages can be read */
+ DosResetEventSem(pmdev->next_event, &count);
+ DosWriteQueue(pmdev->drv_queue, GS_ERROR, 0, NULL, 0);
+ DosWaitEventSem(pmdev->next_event, SEM_INDEFINITE_WAIT);
+ DosResetEventSem(pmdev->next_event, &count);
+ }
+ rc = DosWriteQueue(pmdev->drv_queue, GS_CLOSE, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_close: DosWriteQueue error %d\n",rc);
+ }
+ else {
+ REQUESTDATA Request;
+ ULONG DataLength;
+ PVOID DataAddress;
+ PULONG QueueEntry;
+ BYTE ElemPriority;
+ /* Close gspmdrv driver */
+ DosStopSession(STOP_SESSION_SPECIFIED, pmdev->session_id);
+ Request.pid = pmdev->gspid;
+ Request.ulData = 0;
+ /* wait for termination queue, queue is then closed by session manager */
+ DosReadQueue(pmdev->term_queue, &Request, &DataLength,
+ &DataAddress, 0, DCWW_WAIT, &ElemPriority, (HEV)NULL);
+ /* queue needs to be closed by us */
+ DosCloseQueue(pmdev->term_queue);
+ }
+ }
+ /* release memory */
+ DosFreeMem(pmdev->bitmap);
+ pmdev->bitmap = (unsigned char *)NULL;
+ pmdev->committed = 0;
+
+ if (!pmdev->dll) {
+ /* close objects */
+ if (*pmdev->GSVIEW) {
+ DosCloseQueue(pmdev->drv_queue);
+ DosCloseEventSem(pmdev->next_event);
+ }
+ else {
+ DosCloseEventSem(pmdev->sync_event);
+ /* stop update timer */
+ if (pmdev->updating)
+ DosStopTimer(pmdev->update_timer);
+ pmdev->updating = FALSE;
+ }
+ }
+
+ DosCloseMutexSem(pmdev->bmp_mutex);
+ return(0);
+}
+
+
+/* Map a r-g-b color to the colors available under PM */
+gx_color_index
+pm_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+ switch(dev->color_info.depth) {
+ case 24:
+ return ((b >> (gx_color_value_bits - 8)) << 16) +
+ ((g >> (gx_color_value_bits - 8)) << 8) +
+ ((r >> (gx_color_value_bits - 8)));
+ case 8: {
+ int i;
+ RGB2 *prgb;
+ byte cr, cg, cb;
+
+ /* map colors to 0->255 in 32 steps */
+ cr = pm_color_value(r);
+ cg = pm_color_value(g);
+ cb = pm_color_value(b);
+
+ prgb = (RGB2 *)((PBYTE)pmdev->bmi + pmdev->bmi->cbFix);
+ /* search in palette */
+ for ( i = 0; i < pmdev->nColors; i++, prgb++ )
+ { if ( !((cr ^ prgb->bRed) & 0xf8) &&
+ !((cg ^ prgb->bGreen) & 0xf8) &&
+ !((cb ^ prgb->bBlue) & 0xf8)
+ )
+ return((gx_color_index)i); /* found it */
+ }
+
+ /* next try adding it to palette */
+ if (i < 230) { /* allow 26 for PM and other apps */
+ prgb->bRed = cr;
+ prgb->bGreen = cg;
+ prgb->bBlue = cb;
+ prgb->fcOptions = 0;
+ pmdev->nColors = i+1;
+ pmdev->bmi->cclrImportant = pmdev->nColors;
+ if (*pmdev->GSVIEW) {
+ APIRET rc;
+ rc = DosWriteQueue(pmdev->drv_queue, GS_PALCHANGE, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_sync_output: DosWriteQueue error %d\n",rc);
+ }
+ return((gx_color_index)i); /* return new palette index */
+ }
+
+ return(gx_no_color_index); /* not found - dither instead */
+ }
+ case 4:
+ if ((r == g) && (g == b) && (r >= gx_max_color_value / 3 * 2 - 1)
+ && (r < gx_max_color_value / 4 * 3))
+ return ((gx_color_index)8); /* light gray */
+ return pc_4bit_map_rgb_color(dev, r, g, b);
+ }
+ return (gx_default_map_rgb_color(dev,r,g,b));
+}
+
+/* Map a color code to r-g-b. */
+int
+pm_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_color_value one;
+ switch(dev->color_info.depth) {
+ case 24:
+ one = (gx_color_value) (gx_max_color_value / 255);
+ prgb[0] = ((color) & 255) * one;
+ prgb[1] = ((color>>8) & 255) * one;
+ prgb[2] = ((color>>16) & 255) * one;
+ break;
+ case 8:
+ if (!dev->is_open)
+ return -1;
+ {
+ RGB2 *argb = (RGB2 *)((PBYTE)pmdev->bmi + pmdev->bmi->cbFix);
+ one = (gx_color_value) (gx_max_color_value / 255);
+ prgb[0] = argb[(int)color].bRed * one;
+ prgb[1] = argb[(int)color].bGreen * one;
+ prgb[2] = argb[(int)color].bBlue * one;
+ }
+ break;
+ case 4:
+ if (color == 8) /* VGA light gray */
+ prgb[0] = prgb[1] = prgb[2] = (gx_max_color_value / 4 * 3);
+ else
+ pc_4bit_map_color_rgb(dev, color, prgb);
+ break;
+ default:
+ prgb[0] = prgb[1] = prgb[2] =
+ (int)color ? gx_max_color_value : 0;
+ }
+ return 0;
+}
+
+#define pmmdev ((gx_device *)&pmdev->mdev)
+#define pmmproc(proc) (*dev_proc(&pmdev->mdev, proc))
+
+/* Fill a rectangle. */
+private int
+pm_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ pmmproc(fill_rectangle)(pmmdev, x, y, w, h, color);
+ pm_update((gx_device_pm *)dev);
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+private int
+pm_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+ pmmproc(copy_mono)(pmmdev, base, sourcex, raster, id,
+ x, y, w, h, zero, one);
+ pm_update((gx_device_pm *)dev);
+ return 0;
+}
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
+private int
+pm_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ pmmproc(copy_color)(pmmdev, base, sourcex, raster, id,
+ x, y, w, h);
+ pm_update((gx_device_pm *)dev);
+ return 0;
+}
+
+int
+pm_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{
+ return pmmproc(get_bits)(pmmdev, y, str, actual_data);
+}
+/* Get PM parameters */
+int
+pm_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_default_get_params(dev, plist);
+ gs_param_string gvs;
+ gvs.data = pmdev->GSVIEW, gvs.size = strlen(gvs.data),
+ gvs.persistent = false;
+ code < 0 ||
+ (code = param_write_int(plist, "UpdateInterval", &pmdev->UpdateInterval)) < 0 ||
+ (code = param_write_string(plist, "GSVIEW", &gvs)) < 0;
+ return code;
+}
+
+/* Put parameters. */
+private int
+pm_put_alpha_param(gs_param_list *plist, gs_param_name param_name, int *pa,
+ bool alpha_ok)
+{ int code = param_read_int(plist, param_name, pa);
+ switch ( code )
+ {
+ case 0:
+ switch ( *pa )
+ {
+ case 1:
+ return 0;
+ case 2: case 4:
+ if ( alpha_ok )
+ return 0;
+ default:
+ code = gs_error_rangecheck;
+ }
+ default:
+ param_signal_error(plist, param_name, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+
+
+/* Set PM parameters -- size and resolution. */
+/* We implement this ourselves so that we can do it without */
+/* closing and opening the device. */
+/* Also set BitsPerPixel and GSVIEW if device not open */
+int
+pm_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0, code;
+ bool reopen = false;
+ bool is_open = dev->is_open;
+ int width = dev->width;
+ int height = dev->height;
+ int old_bpp = dev->color_info.depth;
+ int bpp = old_bpp;
+ int uii = pmdev->UpdateInterval;
+ gs_param_string gsvs;
+ int atext = pmdev->alpha_text, agraphics = pmdev->alpha_graphics;
+ bool alpha_ok;
+
+ /* Handle extra parameters */
+ switch ( code = param_read_string(plist, "GSVIEW", &gsvs) )
+ {
+ case 0:
+ if ( gsvs.size == strlen(pmdev->GSVIEW) &&
+ !memcmp(pmdev->GSVIEW, gsvs.data, gsvs.size)
+ )
+ { gsvs.data = 0;
+ break;
+ }
+ if ( dev->is_open )
+ ecode = gs_error_rangecheck;
+ else if ( gsvs.size >= pm_gsview_sizeof )
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto gsve;
+ default:
+ ecode = code;
+gsve: param_signal_error(plist, "GSVIEW", ecode);
+ case 1:
+ gsvs.data = 0;
+ break;
+ }
+
+ switch ( code = param_read_int(plist, "UpdateInterval", &uii) )
+ {
+ case 0:
+ if ( uii < 0 )
+ ecode = gs_error_rangecheck;
+ else
+ break;
+ goto uie;
+ default:
+ ecode = code;
+uie: param_signal_error(plist, "UpdateInterval", ecode);
+ case 1:
+ break;
+ }
+
+ switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
+ {
+ case 0:
+ if ( dev->is_open && bpp != old_bpp )
+ ecode = gs_error_rangecheck;
+ else
+ { code = pm_set_bits_per_pixel(pmdev, bpp);
+ if ( code < 0 )
+ ecode = code;
+ else
+ break;
+ }
+ goto bppe;
+ default:
+ ecode = code;
+bppe: param_signal_error(plist, "BitsPerPixel", ecode);
+ case 1:
+ break;
+ }
+
+ alpha_ok = pmdev->color_info.depth >= 8;
+ if ( (code = pm_put_alpha_param(plist, "TextAlphaBits", &pmdev->alpha_text, alpha_ok)) < 0 )
+ ecode = code;
+ if ( (code = pm_put_alpha_param(plist, "GraphicsAlphaBits", &pmdev->alpha_graphics, alpha_ok)) < 0 )
+ ecode = code;
+
+ if ( ecode >= 0 )
+ { /* Prevent gx_default_put_params from closing the device. */
+ dev->is_open = false;
+ ecode = gx_default_put_params(dev, plist);
+ dev->is_open = is_open;
+ }
+ if ( ecode < 0 )
+ {
+ if ( bpp != old_bpp )
+ pm_set_bits_per_pixel(pmdev, old_bpp);
+ pmdev->alpha_text = atext;
+ pmdev->alpha_graphics = agraphics;
+ return ecode;
+ }
+
+ /* Hand off the change to the implementation. */
+ /* obtain mutex - to prevent gspmdrv from using bitmap */
+ /* while we change its size */
+ if (DosRequestMutexSem(pmdev->bmp_mutex, 20000) == ERROR_TIMEOUT)
+ fprintf(stderr, "pm_put_params: mutex timeout\n");
+ if ( is_open && (old_bpp != bpp ||
+ dev->width != width || dev->height != height)
+ )
+ { int ccode;
+ ccode = pm_alloc_bitmap(pmdev, dev);
+ if ( ccode < 0 )
+ { /* Bad news! Some of the other device parameters */
+ /* may have changed. We don't handle this. */
+ /* This is ****** WRONG ******. */
+ dev->width = width;
+ dev->height = height;
+ pm_set_bits_per_pixel(pmdev, old_bpp);
+ pmdev->alpha_text = atext;
+ pmdev->alpha_graphics = agraphics;
+ pm_alloc_bitmap(pmdev, dev);
+ DosReleaseMutexSem(pmdev->bmp_mutex);
+ return ccode;
+ }
+ reopen = true;
+ }
+ pmdev->UpdateInterval = uii;
+ if ( gsvs.data != 0 )
+ { memcpy(pmdev->GSVIEW, gsvs.data, gsvs.size);
+ pmdev->GSVIEW[gsvs.size] = 0;
+ }
+
+ if ( dev->is_open && reopen ) {
+ /* need to update bitmap info header also */
+ pmdev->bmi->cx = dev->width;
+ pmdev->bmi->cy = dev->height;
+ /* update bit count and palette */
+ pmdev->bmi->cBitCount = dev->color_info.depth;
+ pmdev->bmi->cclrUsed = 1<<(pmdev->BitsPerPixel);
+ pmdev->bmi->cclrImportant = pmdev->nColors;
+ pm_makepalette(pmdev);
+ /* erase bitmap - before window gets redrawn */
+ (*dev_proc(dev, fill_rectangle))(dev,
+ 0, 0, dev->width, dev->height,
+ pm_map_rgb_color(dev, gx_max_color_value,
+ gx_max_color_value, gx_max_color_value));
+ /* cause scroll bars to be redrawn */
+ /* need to signal gspmdrv that bitmap size has changed */
+ /* or perhaps gspmdrv can check if the bitmap size has */
+ /* before each use */
+
+#ifdef __DLL__
+ if (pmdev->dll)
+ (*pgsdll_callback)(GSDLL_SIZE, (unsigned char *)dev,
+ (dev->width & 0xffff) + ( (dev->height & 0xffff)<<16) );
+#endif
+ }
+
+ /* release bmp mutex */
+ DosReleaseMutexSem(pmdev->bmp_mutex);
+ return 0;
+}
+
+
+/* Get the number of alpha bits. */
+int
+pm_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return (type == go_text ? pmdev->alpha_text : pmdev->alpha_graphics);
+}
+
+
+#ifdef __DLL__
+/* ------ DLL routines ------ */
+/* store at pbitmap the address of the bitmap */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+unsigned long GSDLLAPI
+gsdll_get_bitmap(unsigned char *device, unsigned char **pbitmap)
+{
+gx_device *dev = (gx_device *)device;
+ *pbitmap = (unsigned char *)(pmdev->bmi );
+ return 0;
+}
+
+/* Lock the device (so it's size cannot be changed) if flag = TRUE */
+/* or unlock the device if flag = FALSE */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+int GSDLLAPI
+gsdll_lock_device(unsigned char *device, int flag)
+{
+gx_device *dev = (gx_device *)device;
+APIRET rc;
+ if (flag)
+ rc = DosRequestMutexSem(pmdev->bmp_mutex, 60000);
+ else
+ rc = DosReleaseMutexSem(pmdev->bmp_mutex);
+ return rc;
+}
+
+#endif /* __DLL__ */
+
+/* ------ Internal routines ------ */
+
+#undef pmdev
+
+
+/* start gspmdrv.exe */
+private int
+pm_run_gspmdrv(gx_device_pm *pmdev)
+{
+ int ccode;
+ PCHAR pdrvname = "gspmdrv.exe";
+ CHAR error_message[256];
+ CHAR term_queue_name[128];
+ CHAR id[128];
+ CHAR arg[1024];
+ STARTDATA sdata;
+ APIRET rc;
+ PTIB pptib;
+ PPIB pppib;
+ CHAR progname[256];
+ PCHAR tail;
+
+ sprintf(id, ID_NAME, pmdev->gspid, (ULONG)pmdev);
+
+ /* Create termination queue - used to find out when gspmdrv terminates */
+ sprintf(term_queue_name, "\\QUEUES\\TERMQ_%s", id);
+ if (DosCreateQueue(&(pmdev->term_queue), QUE_FIFO, term_queue_name)) {
+ fprintf(stderr,"pm_run_gspmdrv: failed to create termination queue\n");
+ return gs_error_limitcheck;
+ }
+
+ /* get full path to gsos2.exe and hence path to gspmdrv.exe */
+ if ( (rc = DosGetInfoBlocks(&pptib, &pppib)) != 0 ) {
+ fprintf(stderr,"pm_run_gspmdrv: Couldn't get module handle, rc = %d\n", rc);
+ return gs_error_limitcheck;
+ }
+ if ( (rc = DosQueryModuleName(pppib->pib_hmte, sizeof(progname)-1, progname)) != 0 ) {
+ fprintf(stderr,"pm_run_gspmdrv: Couldn't get module name, rc = %d\n", rc);
+ return gs_error_limitcheck;
+ }
+ if ((tail = strrchr(progname,'\\')) != (PCHAR)NULL)
+ {
+ tail++;
+ *tail = '\0';
+ }
+ else
+ tail = progname;
+ strcat(progname, pdrvname);
+
+ /* Open the PM driver session gspmdrv.exe */
+ /* arguments are: */
+ /* (1) -d (display) option */
+ /* (2) id string */
+ sprintf(arg, "-d %s", id);
+
+ /* because gspmdrv.exe is a different EXE type to gs.exe,
+ * we must use start session not DosExecPgm() */
+ sdata.Length = sizeof(sdata);
+ sdata.Related = SSF_RELATED_CHILD; /* to be a child */
+ sdata.FgBg = SSF_FGBG_BACK; /* start in background */
+ sdata.TraceOpt = 0;
+ sdata.PgmTitle = "Ghostscript PM driver session";
+ sdata.PgmName = progname;
+ sdata.PgmInputs = arg;
+ sdata.TermQ = term_queue_name;
+ sdata.Environment = pppib->pib_pchenv; /* use Parent's environment */
+ sdata.InheritOpt = 0; /* Can't inherit from parent because different sesison type */
+ sdata.SessionType = SSF_TYPE_DEFAULT; /* default is PM */
+ sdata.IconFile = NULL;
+ sdata.PgmHandle = 0;
+ sdata.PgmControl = 0;
+ sdata.InitXPos = 0;
+ sdata.InitYPos = 0;
+ sdata.InitXSize = 0;
+ sdata.InitYSize = 0;
+ sdata.ObjectBuffer = error_message;
+ sdata.ObjectBuffLen = sizeof(error_message);
+
+ rc = DosStartSession(&sdata, &pmdev->session_id, &pmdev->process_id);
+ if (rc == ERROR_FILE_NOT_FOUND) {
+ sdata.PgmName = pdrvname;
+ rc = DosStartSession(&sdata, &pmdev->session_id, &pmdev->process_id);
+ }
+ if (rc) {
+ fprintf(stderr,"pm_run_gspmdrv: failed to run %s, rc = %d\n", sdata.PgmName, rc);
+ fprintf(stderr,"pm_run_gspmdrv: error_message: %s\n", error_message);
+ return gs_error_limitcheck;
+ }
+
+ return 0;
+
+}
+
+/* Allocate the backing bitmap. */
+private int
+pm_alloc_bitmap(gx_device_pm *pmdev, gx_device *param_dev)
+{
+ gx_device_memory mdev;
+ byte *base;
+ ulong data_size;
+ uint ptr_size;
+ uint pal_size;
+ uint raster;
+ ULONG rc;
+ ULONG needed;
+
+ /* Finish initializing the bitmap. */
+
+ gs_make_mem_device(&mdev, gdev_mem_device_for_bits(pmdev->color_info.depth), 0, 0, (gx_device *)pmdev);
+ mdev.width = param_dev->width;
+ mdev.height = param_dev->height;
+ /* BMP files need width rounded up so that a scan line is */
+ /* a multiple of 4 bytes. */
+ /* This is currently done by gdev_mem_raster(). */
+ /* It may be better to do it here explicitly in case */
+ /* gdev_mem_raster changes. */
+ raster = gdev_mem_raster(&mdev);
+ data_size = (ulong)raster * mdev.height;
+ ptr_size = sizeof(byte **) * mdev.height;
+ pal_size = pm_palette_size(pmdev);
+ needed = pmdev->bmi->cbFix + pal_size + data_size + ptr_size;
+ /* round up to page boundary */
+ needed = (needed + MIN_COMMIT - 1) & (~(MIN_COMMIT-1));
+ if (needed > pmdev->committed) {
+ /* commit more memory */
+ if (rc = DosSetMem(pmdev->bitmap + pmdev->committed,
+ needed - pmdev->committed,
+ PAG_COMMIT | PAG_DEFAULT)) {
+ fprintf(stderr,"No memory in pm_alloc_bitmap, rc = %d\n",rc);
+ return gs_error_limitcheck;
+ }
+ pmdev->committed = needed;
+ }
+ /* Shared memory can't be decommitted */
+#ifdef __DLL__
+ if (pmdev->dll && (needed < pmdev->committed)) {
+ /* decommit memory */
+ if (rc = DosSetMem(pmdev->bitmap + needed,
+ pmdev->committed - needed,
+ PAG_DECOMMIT)) {
+ fprintf(stderr,"Failed to decommit memory in pm_alloc_bitmap, rc = %d\n",rc);
+ return gs_error_limitcheck;
+ }
+ pmdev->committed = needed;
+ }
+#endif
+
+ /* Nothing can go wrong now.... */
+ base = pmdev->bitmap + pmdev->bmi->cbFix + pm_palette_size(pmdev);
+ pmdev->mdev = mdev;
+ pmdev->mdev.base = (byte *)base;
+ pmmproc(open_device)((gx_device *)&pmdev->mdev);
+ pmdev->bmi->cbImage = data_size;
+ return 0;
+}
+
+private void
+pm_makepalette(gx_device_pm *pmdev)
+{
+ int i, val;
+ RGB2 *argb = (RGB2 *)( (PBYTE)pmdev->bmi + pmdev->bmi->cbFix );
+ if (pmdev->BitsPerPixel > 8)
+ return; /* these don't use a palette */
+
+ for (i=0; i<pmdev->nColors; i++) {
+ switch (pmdev->nColors) {
+ case 64:
+ /* colors are rrggbb */
+ argb[i].bRed = ((i & 0x30)>>4)*85;
+ argb[i].bGreen = ((i & 0xC)>>2)*85;
+ argb[i].bBlue = (i & 3)*85;
+ argb[i].fcOptions = 0;
+ /* zero unused entries */
+ argb[i+64].bRed = argb[i+64].bGreen = argb[i+64].bBlue = 0;
+ argb[i+64].fcOptions = 0;
+ argb[i+128].bRed = argb[i+128].bGreen = argb[i+128].bBlue = 0;
+ argb[i+128].fcOptions = 0;
+ argb[i+192].bRed = argb[i+192].bGreen = argb[i+192].bBlue = 0;
+ argb[i+192].fcOptions = 0;
+ break;
+ case 16:
+ /* colors are irgb */
+ val = (i & 8 ? 255 : 128);
+ argb[i].bRed = i & 4 ? val : 0;
+ argb[i].bGreen = i & 2 ? val : 0;
+ argb[i].bBlue = i & 1 ? val : 0;
+ if (i == 8) { /* light gray */
+ argb[i].bRed =
+ argb[i].bGreen =
+ argb[i].bBlue = 192;
+ argb[i].fcOptions = 0;
+ }
+ break;
+ case 2:
+ argb[i].bRed =
+ argb[i].bGreen =
+ argb[i].bBlue = (i ? 255 : 0);
+ argb[i].fcOptions = 0;
+ break;
+ }
+ }
+}
+
+
+/* Cause display to be updated periodically */
+private void
+pm_update(gx_device_pm *pmdev)
+{
+ if (pmdev->updating)
+ return;
+ if (!pmdev->UpdateInterval)
+ return;
+ if (*pmdev->GSVIEW) {
+ APIRET rc;
+ rc = DosWriteQueue(pmdev->drv_queue, GS_UPDATING, 0, NULL, 0);
+ if (rc)
+ fprintf(stderr,"pm_update: DosWriteQueue error %d\n",rc);
+ }
+ else {
+ DosStartTimer(pmdev->UpdateInterval, (HSEM)pmdev->sync_event,
+ &pmdev->update_timer);
+ }
+ pmdev->updating = TRUE;
+}
+
+private uint
+pm_set_bits_per_pixel(gx_device_pm *pmdev, int bpp)
+{
+static const gx_device_color_info pm_24bit_color = dci_color(24,255,255);
+static const gx_device_color_info pm_8bit_color = dci_color(8,31,4);
+static const gx_device_color_info pm_4bit_color = dci_pc_4bit;
+static const gx_device_color_info pm_2color = dci_black_and_white;
+ switch (bpp) {
+ case 24:
+ pmdev->color_info = pm_24bit_color;
+ pmdev->nColors = (1<<24);
+ break;
+ case 8:
+ /* use 64 static colors and 166 dynamic colors from 8 planes */
+ pmdev->color_info = pm_8bit_color;
+ pmdev->nColors = 64;
+ break;
+ case 4:
+ pmdev->color_info = pm_4bit_color;
+ pmdev->nColors = 16;
+ break;
+ case 1:
+ pmdev->color_info = pm_2color;
+ pmdev->nColors = 2;
+ break;
+ default:
+ return (gs_error_rangecheck);
+ }
+ pmdev->BitsPerPixel = bpp;
+ return 0;
+}
+
+/* return length of BMP palette in bytes */
+private uint
+pm_palette_size(gx_device_pm *pmdev)
+{
+ switch(pmdev->color_info.depth) {
+ case 24:
+ return 0;
+ case 8:
+ return 256*sizeof(RGB2);
+ case 4:
+ return 16*sizeof(RGB2);
+ }
+ /* must be two color */
+ return 2*sizeof(RGB2);
+}
+
+/* This is used for testing */
+/* Write out a BMP file to "out.bmp" */
+private void
+pm_write_bmp(gx_device_pm *pmdev)
+{
+ BITMAPFILEHEADER2 bmfh;
+ uint bmfh_length = sizeof(BITMAPFILEHEADER2) - sizeof(BITMAPINFOHEADER2);
+ uint length; /* bitmap length */
+ ULONG fh; /* file handle */
+ ULONG action;
+ ULONG count;
+ bmfh.usType = 0x4d42; /* "BM" */
+ length = pmdev->bmi->cbFix + pm_palette_size(pmdev)
+ + ( (gdev_mem_raster(&pmdev->mdev) * pmdev->mdev.height) );
+ bmfh.cbSize = bmfh_length + length;
+ bmfh.xHotspot = bmfh.yHotspot = 0;
+ bmfh.offBits = bmfh_length + pmdev->bmi->cbFix + pm_palette_size(pmdev);
+ if (DosOpen("out.bmp", /* filename */
+ &fh, /* pointer to handle */
+ &action, /* pointer to result */
+ 0, /* initial length */
+ FILE_NORMAL, /* normal file */
+ OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
+ OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
+ 0)) {
+ fprintf(stderr,"error opening out.bmp\n");
+ return;
+ }
+ if (DosWrite(fh, (PBYTE)&bmfh, bmfh_length, &count))
+ fprintf(stderr,"error writing header for out.bmp\n");
+ if (DosWrite(fh, pmdev->bitmap, length, &count))
+ fprintf(stderr,"error writing out.bmp\n");
+ if (DosClose(fh))
+ fprintf(stderr,"error closing out.bmp\n");
+}
diff --git a/gs/src/gdevpm.h b/gs/src/gdevpm.h
new file mode 100644
index 000000000..f9e7ab6c4
--- /dev/null
+++ b/gs/src/gdevpm.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpm.h */
+/* Defines common to gdevpm.c, gspmdrv.c and PM GSview */
+
+#define SHARED_NAME "\\SHAREMEM\\%s"
+#define SYNC_NAME "\\SEM32\\SYNC_%s"
+#define NEXT_NAME "\\SEM32\\NEXT_%s"
+#define MUTEX_NAME "\\SEM32\\MUTEX_%s"
+#define QUEUE_NAME "\\QUEUES\\%s"
+
+#define GS_UPDATING 1
+#define GS_SYNC 2
+#define GS_PAGE 3
+#define GS_CLOSE 4
+#define GS_ERROR 5
+#define GS_PALCHANGE 6
+#define GS_BEGIN 7
+#define GS_END 8
diff --git a/gs/src/gdevpng.c b/gs/src/gdevpng.c
new file mode 100644
index 000000000..916989f81
--- /dev/null
+++ b/gs/src/gdevpng.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpng.c */
+/* PNG (Portable Network Graphics) Format. Pronounced "ping". */
+/* lpd 1997-07-20: changed from using gs_malloc/png_xxx_int to png_create_xxx
+ * for allocating structures, and from gs_free to png_write_destroy for
+ * freeing them. */
+/* lpd 1997-5-7: added PNG_LIBPNG_VER conditional for operand types of
+ * dummy png_push_fill_buffer. */
+/* lpd 1997-4-13: Added PNG_NO_STDIO to remove library access to stderr. */
+/* lpd 1997-3-14: Added resolution (pHYs) to output. */
+/* lpd 1996-6-24: Added #ifdef for compatibility with old libpng versions. */
+/* lpd 1996-6-11: Edited to remove unnecessary color mapping code. */
+/* lpd (L. Peter Deutsch) 1996-4-7: Modified for libpng 0.88. */
+/* Original version by Russell Lang 1995-07-04 */
+
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "gscdefs.h"
+
+#define PNG_INTERNAL
+#define PNG_NO_STDIO
+#include "png.h"
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+private dev_proc_print_page(png_print_page);
+
+/* Monochrome. */
+
+gx_device_printer far_data gs_pngmono_device =
+ prn_device(prn_std_procs, "pngmono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, png_print_page);
+
+/* 4-bit planar (EGA/VGA-style) color. */
+
+private gx_device_procs png16_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
+gx_device_printer far_data gs_png16_device =
+ prn_device(png16_procs, "png16",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 4, png_print_page);
+
+/* 8-bit (SuperVGA-style) color. */
+/* (Uses a fixed palette of 3,3,2 bits.) */
+
+private gx_device_procs png256_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_printer far_data gs_png256_device =
+ prn_device(png256_procs, "png256",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 8, png_print_page);
+
+/* 8-bit gray */
+
+private gx_device_procs pnggray_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
+gx_device_printer far_data gs_pnggray_device =
+{ prn_device_body(gx_device_printer, pnggray_procs, "pnggray",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1,8,255,0,256,0, png_print_page)
+};
+
+/* 24-bit color. */
+
+private gx_device_procs png16m_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+gx_device_printer far_data gs_png16m_device =
+ prn_device(png16m_procs, "png16m",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 24, png_print_page);
+
+
+/* ------ Private definitions ------ */
+
+/* Write out a page in PNG format. */
+/* This routine is used for all formats. */
+private int
+png_print_page(gx_device_printer *pdev, FILE *file)
+{ int raster = gdev_prn_raster(pdev);
+ /* PNG structures */
+ byte *row = (byte *)gs_malloc(raster, 1, "png raster buffer");
+ png_struct *png_ptr =
+ png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_info *info_ptr =
+ png_create_info_struct(png_ptr);
+ int height = pdev->height;
+ int depth = pdev->color_info.depth;
+ int y;
+ int code = 0; /* return code */
+ const char *software_key = "Software";
+ char software_text[256];
+ png_text text_png;
+
+ if ( row == 0 || png_ptr == 0 || info_ptr == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+
+ /* set error handling */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* If we get here, we had a problem reading the file */
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+
+ /* set up the output control */
+ png_init_io(png_ptr, file);
+
+ /* set the file information here */
+ info_ptr->width = pdev->width;
+ info_ptr->height = pdev->height;
+ /* resolution is in pixels per meter vs. dpi */
+ info_ptr->x_pixels_per_unit =
+ (png_uint_32)(pdev->HWResolution[0] * (100.0 / 2.54));
+ info_ptr->y_pixels_per_unit =
+ (png_uint_32)(pdev->HWResolution[1] * (100.0 / 2.54));
+ info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
+ info_ptr->valid |= PNG_INFO_pHYs;
+ switch(depth) {
+ case 24:
+ info_ptr->bit_depth = 8;
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case 8:
+ info_ptr->bit_depth = 8;
+ if (gx_device_has_color(pdev))
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ else
+ info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case 4:
+ info_ptr->bit_depth = 4;
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ break;
+ case 1:
+ info_ptr->bit_depth = 1;
+ info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
+ /* invert monocrome pixels */
+ png_set_invert_mono(png_ptr);
+ break;
+ }
+
+ /* set the palette if there is one */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+ int i;
+ int num_colors = 1<<depth;
+ gx_color_value rgb[3];
+
+ info_ptr->palette = gs_malloc(256 * sizeof (png_color), 1, "png palette");
+ if ( info_ptr->palette == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ info_ptr->num_palette = num_colors;
+ info_ptr->valid |= PNG_INFO_PLTE;
+ for (i=0; i<num_colors; i++) {
+ (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
+ (gx_color_index)i, rgb);
+ info_ptr->palette[i].red = gx_color_value_to_byte(rgb[0]);
+ info_ptr->palette[i].green = gx_color_value_to_byte(rgb[1]);
+ info_ptr->palette[i].blue = gx_color_value_to_byte(rgb[2]);
+ }
+ }
+
+ /* add comment */
+ sprintf(software_text, "%s %d.%02d", gs_product,
+ (int)(gs_revision / 100), (int)(gs_revision % 100));
+ text_png.compression = -1; /* uncompressed */
+ text_png.key = (char *)software_key; /* not const, unfortunately */
+ text_png.text = software_text;
+ text_png.text_length = strlen(software_text);
+ info_ptr->text = &text_png;
+ info_ptr->num_text = 1;
+
+ /* write the file information */
+ png_write_info(png_ptr, info_ptr);
+
+ /* don't write the comments twice */
+ info_ptr->num_text = 0;
+ info_ptr->text = NULL;
+
+ /* Write the contents of the image. */
+ for ( y = 0; y < height; y++ )
+ { gdev_prn_copy_scan_lines(pdev, y, row, raster);
+ png_write_rows(png_ptr, &row, 1);
+ }
+
+ /* write the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ /* if you malloced the palette, free it here */
+ if (info_ptr->palette)
+ gs_free(info_ptr->palette, 256 * sizeof (png_color), 1, "png palette");
+
+done:
+ /* free the structures */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ gs_free((char *)row, raster, 1, "png raster buffer");
+
+ return code;
+}
+
+/*
+ * Patch around a static reference to a never-used procedure.
+ * This could be avoided if we were willing to edit pngconf.h to
+ * #undef PNG_PROGRESSIVE_READ_SUPPORTED
+ */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+# if PNG_LIBPNG_VER >= 95
+# define PPFB_LENGTH_T png_size_t
+# else
+# define PPFB_LENGTH_T png_uint_32
+# endif
+void
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer,
+ PPFB_LENGTH_T length)
+{
+}
+#endif
diff --git a/gs/src/gdevprn.c b/gs/src/gdevprn.c
new file mode 100644
index 000000000..0641b1a45
--- /dev/null
+++ b/gs/src/gdevprn.c
@@ -0,0 +1,919 @@
+/* Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevprn.c */
+/* Generic printer driver support */
+#include "ctype_.h"
+#include "gdevprn.h"
+#include "gp.h"
+#include "gsparam.h"
+#include "gxclio.h"
+
+/* ---------------- Standard device procedures ---------------- */
+
+/* Macros for casting the pdev argument */
+#define ppdev ((gx_device_printer *)pdev)
+#define pmemdev ((gx_device_memory *)pdev)
+#define pcldev (&((gx_device_clist *)pdev)->common)
+#define pcwdev (&((gx_device_clist *)pdev)->writer)
+#define pcrdev (&((gx_device_clist *)pdev)->reader)
+
+/* Define the standard printer procedure vector. */
+gx_device_procs prn_std_procs =
+ prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close);
+
+/* --------------- Forward decl's ------------------------- */
+int gdev_prn_reallocate_memory(P4(gx_device_printer *,
+ gdev_prn_space_params *, int, int));
+
+
+/* ------ Open/close ------ */
+
+/* Open a generic printer device. */
+/* Specific devices may wish to extend this. */
+int
+gdev_prn_open(gx_device *pdev)
+{ int code;
+ ppdev->file = NULL;
+ code
+ = gdev_prn_allocate_memory(pdev, gdev_prn_allocate_allocate, 0, 0, 0);
+ if ( code < 0 )
+ return code;
+ if ( ppdev->OpenOutputFile )
+ code = gdev_prn_open_printer(pdev, 1);
+ return code;
+}
+
+/* Generic closing for the printer device. */
+/* Specific devices may wish to extend this. */
+int
+gdev_prn_close(gx_device *pdev)
+{ gdev_prn_allocate_memory(pdev, gdev_prn_allocate_free, 0, 0, 0);
+ if ( ppdev->file != NULL )
+ { if ( ppdev->file != stdout )
+ gp_close_printer(ppdev->file, ppdev->fname);
+ ppdev->file = NULL;
+ }
+ return 0;
+}
+
+private int /* returns 0 ok, else -ve error cde */
+gdev_prn_setup_as_command_list(gx_device *pdev, gs_memory_t *buffer_memory,
+ byte **the_memory, const gdev_prn_space_params *space_params,
+ bool bufferSpace_is_exact)
+{
+ uint space;
+ int code;
+ gx_device_clist * const pclist_dev = (gx_device_clist *)pdev;
+ bool reallocate = *the_memory != 0;
+ byte *base;
+
+ /* Try to allocate based simply on param-requested buffer size */
+ for ( space = space_params->BufferSpace; ; )
+ { base = reallocate
+ ? gs_resize_object(buffer_memory, *the_memory, space,
+ "cmd list buffer")
+ : gs_alloc_bytes(buffer_memory, space,
+ "cmd list buffer");
+ if (base != 0)
+ break;
+ if ( bufferSpace_is_exact || (space >>= 1) < PRN_MIN_BUFFER_SPACE )
+ break;
+ }
+ if (base == 0)
+ return(gs_error_VMerror);
+ else
+ *the_memory = base;
+
+ /* Try opening the command list, to see if we allocated */
+ /* enough buffer space. */
+open_c:
+ ppdev->buf = base;
+ ppdev->buffer_space = space;
+
+ clist_init_params(pclist_dev, base, space, pdev,
+ ppdev->printer_procs.make_buffer_device,
+ space_params->band, ppdev->is_async_renderer,
+ ppdev->bandlist_memory == 0 ? &gs_memory_default : ppdev->bandlist_memory,
+ ppdev->free_up_bandlist_memory, ppdev->clist_disable_mask);
+ code = (*gs_clist_device_procs.open_device)( (gx_device *)pcldev );
+ if ( code < 0 )
+ { /* If there wasn't enough room, and we haven't */
+ /* already shrunk the buffer, try enlarging it. */
+ if ( code == gs_error_limitcheck &&
+ space >= space_params->BufferSpace &&
+ !bufferSpace_is_exact
+ )
+ { space <<= 1;
+ if (reallocate)
+ { base = gs_resize_object(buffer_memory,
+ *the_memory, space,
+ "cmd list buf(retry open)");
+ if (base != 0)
+ *the_memory = base;
+ }
+ else
+ { gs_free_object(buffer_memory, base,
+ "cmd list buf(retry open)");
+ *the_memory =
+ base = gs_alloc_bytes(buffer_memory, space,
+ "cmd list buf(retry open)");
+ }
+ ppdev->buf = *the_memory;
+ if (base != 0)
+ goto open_c;
+ }
+ /* Failure. */
+ if (!reallocate)
+ { gs_free_object(buffer_memory, base, "cmd list buf");
+ ppdev->buffer_space = 0;
+ *the_memory = 0;
+ }
+ }
+
+ return code;
+}
+
+private bool /* ret true if device was cmd list, else false */
+gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
+{ bool is_command_list;
+ if (ppdev->buffer_space != 0)
+ { /* Close cmd list device & point to the storage */
+ (*gs_clist_device_procs.close_device)( (gx_device *)pcldev );
+ *the_memory = ppdev->buf;
+ ppdev->buf = 0;
+ ppdev->buffer_space = 0;
+ is_command_list = true;
+ }
+ else
+ { /* point at the device bitmap, no need to close mem dev */
+ *the_memory = pmemdev->base;
+ pmemdev->base = 0;
+ is_command_list = false;
+ }
+
+ /* Reset device proc vector to default */
+ if (ppdev->orig_procs.open_device != 0)
+ pdev->std_procs = ppdev->orig_procs;
+ ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of std_procs */
+
+ return is_command_list;
+}
+
+int /* ret 0 ok, -ve error code */
+gdev_prn_allocate_memory(gx_device *pdev,
+ gdev_prn_allocate_action action, gdev_prn_space_params *new_space_params,
+ int new_width, int new_height)
+{ byte *the_memory = 0;
+ gdev_prn_space_params save_params;
+ int save_width, save_height;
+ bool is_command_list;
+ bool save_is_command_list;
+ int ecode = 0;
+ int pass;
+ int reallocate = (action == gdev_prn_allocate_reallocate);
+ gs_memory_t *buffer_memory
+ = ppdev->buffer_memory == 0 ? &gs_memory_default : ppdev->buffer_memory;
+
+ /* Free or reallocate: find allocated memory & tear down buffer device */
+ if (action == gdev_prn_allocate_free || action == gdev_prn_allocate_reallocate)
+ { save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
+ if (action == gdev_prn_allocate_free)
+ { /* Free allocated memory for good */
+ gs_free_object(buffer_memory, the_memory, "print buffer(close)");
+ return 0;
+ }
+ }
+
+ /* Re/allocate memory */
+ ppdev->orig_procs = pdev->std_procs;
+ for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass )
+ { ulong mem_space;
+ byte *base = 0;
+ int bufferSpace_is_default = false;
+ gdev_prn_space_params space_params = ppdev->space_params;
+
+ if (reallocate)
+ switch (pass)
+ {
+ case 1:
+ /* Setup device to get reallocated */
+ save_params = ppdev->space_params;
+ ppdev->space_params = *new_space_params;
+ save_width = ppdev->width;
+ ppdev->width = new_width;
+ save_height = ppdev->height;
+ ppdev->height = new_height;
+ break;
+ case 2: /* only comes here if reallocate */
+ /* Restore device to previous contents */
+ ppdev->space_params = save_params;
+ ppdev->width = save_width;
+ ppdev->height = save_height;
+ break;
+ }
+
+ /* Init clist/mem device-specific fields */
+ memset( ppdev->skip, 0, sizeof(ppdev->skip) );
+ mem_space = gdev_mem_bitmap_size(pmemdev);
+
+ /* Compute desired space params: never use the space_params as-is. */
+ /* Rather, give the dev-specific driver a chance to adjust them. */
+ space_params.BufferSpace = 0;
+ (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
+ if (ppdev->is_async_renderer && space_params.band.BandBufferSpace != 0)
+ space_params.BufferSpace = space_params.band.BandBufferSpace;
+ else if (space_params.BufferSpace == 0)
+ if (space_params.band.BandBufferSpace > 0)
+ space_params.BufferSpace = space_params.band.BandBufferSpace;
+ else
+ { space_params.BufferSpace = PRN_BUFFER_SPACE;
+ bufferSpace_is_default = true;
+ }
+
+ /* Determine if we can use a full bitmap buffer, or have to use banding */
+ if (pass > 1)
+ is_command_list = save_is_command_list;
+ else
+ { is_command_list = space_params.banding_type == BandingAlways ||
+ mem_space >= space_params.MaxBitmap ||
+ mem_space != (uint)mem_space; /* too big to allocate */
+ }
+ if (!is_command_list)
+ { /* Try to allocate memory for full memory buffer */
+ base = reallocate
+ ? gs_resize_object( buffer_memory, the_memory,
+ (uint)mem_space, "printer buffer" )
+ : gs_alloc_bytes( buffer_memory, (uint)mem_space,
+ "printer_buffer" );
+ if (base == 0)
+ is_command_list = true;
+ else
+ the_memory = base;
+ }
+ if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
+ && buffer_memory == &gs_memory_default)
+ { /* before using full memory buffer, ensure enough working mem left */
+ byte * left = gs_alloc_bytes( buffer_memory,
+ PRN_MIN_MEMORY_LEFT, "printer mem left");
+ if (left == 0)
+ is_command_list = true;
+ else
+ gs_free_object(buffer_memory, left, "printer mem left");
+ }
+
+ if (is_command_list)
+ { /* Buffer the image in a command list. */
+ /* Release the buffer if we allocated it. */
+ int code;
+ if (!reallocate)
+ { gs_free_object(buffer_memory, the_memory,
+ "printer buffer(open)");
+ the_memory = 0;
+ }
+ if (space_params.banding_type == BandingNever)
+ { ecode = gs_error_VMerror;
+ continue;
+ }
+ code = gdev_prn_setup_as_command_list(pdev, buffer_memory,
+ &the_memory, &space_params, !bufferSpace_is_default);
+ if (ecode == 0)
+ ecode = code;
+
+ if ( code >= 0 || (reallocate && pass > 1) )
+ ppdev->std_procs = gs_clist_device_procs;
+ }
+ else
+ { /* Render entirely in memory. */
+ int code;
+ ppdev->buffer_space = 0;
+ code = (*ppdev->printer_procs.make_buffer_device)
+ (pmemdev, pdev, buffer_memory, false);
+ if ( code < 0 ) /* Catastrophic. Shouldn't ever happen */
+ { gs_free_object(buffer_memory, base, "printer buffer");
+ pdev->std_procs = ppdev->orig_procs;
+ ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of std_procs */
+ return_error(code);
+ }
+ pmemdev->base = base;
+ }
+ if (ecode == 0)
+ break;
+ }
+
+ if (ecode >= 0 || reallocate) /* even if realloc failed */
+ { /* Synthesize the procedure vector. */
+ /* Rendering operations come from the memory or clist device, */
+ /* non-rendering come from the printer device. */
+#define copy_proc(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
+ copy_proc(get_initial_matrix);
+ copy_proc(output_page);
+ copy_proc(close_device);
+ copy_proc(map_rgb_color);
+ copy_proc(map_color_rgb);
+ copy_proc(get_params);
+ copy_proc(put_params);
+ copy_proc(map_cmyk_color);
+ copy_proc(get_xfont_procs);
+ copy_proc(get_xfont_device);
+ copy_proc(map_rgb_alpha_color);
+ /* All printers are page devices, even if they didn't use the */
+ /* standard macros for generating their procedure vectors. */
+ set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
+ copy_proc(get_alpha_bits);
+ copy_proc(get_clipping_box);
+ copy_proc(get_hardware_params);
+#undef copy_proc
+ /* If using a command list, already opened the device. */
+ if (is_command_list)
+ return ecode;
+ else
+ return (*dev_proc(pdev, open_device))(pdev);
+ }
+ else
+ { pdev->std_procs = ppdev->orig_procs;
+ ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of std_procs */
+ return ecode;
+ }
+}
+
+
+
+/* ------------- Stubs related only to async rendering ------- */
+int /* rets 0 ok, -ve error if couldn't start thread */
+gx_default_start_render_thread(gdev_prn_start_render_params *params)
+{ return gs_error_unknownerror;
+}
+
+/* Open the renderer's copy of a device. */
+/* This is overriden in gdevprna.c */
+int
+gx_default_open_render_device(gx_device_printer *pdev)
+{ return gs_error_unknownerror;
+}
+
+/* Close the renderer's copy of a device. */
+int
+gx_default_close_render_device(gx_device_printer *pdev)
+{ return gdev_prn_close( (gx_device *)pdev );
+}
+
+/* ------ Get/put parameters ------ */
+
+/* Get parameters. Printer devices add several more parameters */
+/* to the default set. */
+int
+gdev_prn_get_params(gx_device *pdev, gs_param_list *plist)
+{ int code = gx_default_get_params(pdev, plist);
+ gs_param_string ofns;
+
+ if ( code < 0 ||
+ (code = param_write_long(plist, "MaxBitmap", &ppdev->space_params.MaxBitmap)) < 0 ||
+ (code = param_write_long(plist, "BufferSpace", &ppdev->space_params.BufferSpace)) < 0 ||
+ (code = param_write_int(plist, "BandWidth", &ppdev->space_params.band.BandWidth)) < 0 ||
+ (code = param_write_int(plist, "BandHeight", &ppdev->space_params.band.BandHeight)) < 0 ||
+ (code = param_write_long(plist, "BandBufferSpace", &ppdev->space_params.band.BandBufferSpace)) < 0 ||
+ (code = (ppdev->NumCopies_set ?
+ param_write_int(plist, "NumCopies", &ppdev->NumCopies) :
+ param_write_null(plist, "NumCopies"))) < 0 ||
+ (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 ||
+ (ppdev->Duplex_set >= 0 &&
+ (code = (ppdev->Duplex_set ?
+ param_write_bool(plist, "Duplex", &ppdev->Duplex) :
+ param_write_null(plist, "Duplex"))) < 0)
+ )
+ return code;
+
+ ofns.data = (const byte *)ppdev->fname,
+ ofns.size = strlen(ppdev->fname),
+ ofns.persistent = false;
+ return param_write_string(plist, "OutputFile", &ofns);
+}
+
+/* Put parameters. */
+int
+gdev_prn_put_params(gx_device *pdev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ const char _ds *param_name;
+ bool is_open = pdev->is_open;
+ int nci = ppdev->NumCopies;
+ bool ncset = ppdev->NumCopies_set;
+ bool oof = ppdev->OpenOutputFile;
+ bool duplex;
+ int duplex_set = -1;
+ int width = pdev->width;
+ int height = pdev->height;
+ gdev_prn_space_params sp, save_sp;
+ gs_param_string ofs;
+ gs_param_dict mdict;
+
+ sp = ppdev->space_params;
+ save_sp = sp;
+ switch ( code = param_read_int(plist, (param_name = "NumCopies"), &nci) )
+ {
+ case 0:
+ if ( nci < 0 )
+ ecode = gs_error_rangecheck;
+ else
+ { ncset = true;
+ break;
+ }
+ goto nce;
+ default:
+ if ( (code = param_read_null(plist, param_name)) == 0 )
+ { ncset = false;
+ break;
+ }
+ ecode = code; /* can't be 1 */
+nce: param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+
+ switch ( code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+
+ if ( ppdev->Duplex_set >= 0 ) /* i.e., Duplex is supported */
+ switch ( code = param_read_bool(plist, (param_name = "Duplex"),
+ &duplex) )
+ {
+ case 0:
+ duplex_set = 1;
+ break;
+ default:
+ if ( (code = param_read_null(plist, param_name)) == 0 )
+ { duplex_set = 0;
+ break;
+ }
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ ;
+ }
+
+#define CHECK_PARAM_CASES(bad, label)\
+ case 0: if ( bad ) ecode = gs_error_rangecheck; else break; goto label;\
+ default: ecode = code;\
+ label: param_signal_error(plist, param_name, ecode);\
+ case 1: break
+
+ switch ( code = param_read_long(plist, (param_name = "MaxBitmap"), &sp.MaxBitmap) )
+ {
+ CHECK_PARAM_CASES( (sp.params_are_read_only
+ ? sp.MaxBitmap != save_sp.MaxBitmap : sp.MaxBitmap < 10000), mbe );
+ }
+
+ switch ( code = param_read_long(plist, (param_name = "BufferSpace"), &sp.BufferSpace) )
+ {
+ CHECK_PARAM_CASES( (sp.params_are_read_only
+ ? sp.BufferSpace != save_sp.BufferSpace : sp.BufferSpace < 10000), bse );
+ }
+
+ switch ( code = param_read_int(plist, (param_name = "BandWidth"), &sp.band.BandWidth) )
+ {
+ CHECK_PARAM_CASES( (sp.params_are_read_only
+ ? sp.band.BandWidth != save_sp.band.BandWidth : sp.band.BandWidth < 0),
+ bwe );
+ }
+
+ switch ( code = param_read_int(plist, (param_name = "BandHeight"), &sp.band.BandHeight) )
+ {
+ CHECK_PARAM_CASES( (sp.params_are_read_only
+ ? sp.band.BandHeight != save_sp.band.BandHeight : sp.band.BandHeight < 0),
+ bhe );
+ }
+
+ switch ( code = param_read_long(plist, (param_name = "BandBufferSpace"), &sp.band.BandBufferSpace) )
+ {
+ CHECK_PARAM_CASES( (sp.params_are_read_only
+ ? sp.band.BandBufferSpace != save_sp.band.BandBufferSpace
+ : sp.band.BandBufferSpace < 0), bbse );
+ }
+#undef CHECK_PARAM_CASES
+
+ switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofs) )
+ {
+ case 0:
+ if ( ofs.size >= prn_fname_sizeof )
+ ecode = gs_error_limitcheck;
+ else
+ { /* Check the validity of any % formats. */
+ uint i;
+ bool pagenum = false;
+ for ( i = 0; i < ofs.size; ++i )
+ if ( ofs.data[i] == '%' )
+ { if ( i+1 < ofs.size && ofs.data[i+1] == '%' )
+ continue;
+ if ( pagenum ) /* more than one %, */
+ i = ofs.size - 1; /* force error */
+ pagenum = true;
+sw: if ( ++i == ofs.size )
+ { ecode = gs_error_rangecheck;
+ goto ofe;
+ }
+ switch ( ofs.data[i] )
+ {
+ case ' ': case '#': case '+': case '-':
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9': case 'l':
+ goto sw;
+ case 'd': case 'i': case 'u': case 'o':
+ case 'x': case 'X':
+ continue;
+ default:
+ ecode = gs_error_rangecheck;
+ goto ofe;
+ }
+ }
+ break;
+ }
+ goto ofe;
+ default:
+ ecode = code;
+ofe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ ofs.data = 0;
+ break;
+ }
+
+ /* Read InputAttributes and OutputAttributes just for the type */
+ /* check and to indicate that they aren't undefined. */
+#define read_media(pname)\
+ switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
+ {\
+ case 0:\
+ param_end_read_dict(plist, pname, &mdict);\
+ break;\
+ default:\
+ ecode = code;\
+ param_signal_error(plist, param_name, ecode);\
+ case 1:\
+ ;\
+ }
+
+ read_media("InputAttributes");
+ read_media("OutputAttributes");
+
+ if ( ecode < 0 )
+ return ecode;
+ /* Prevent gx_default_put_params from closing the printer. */
+ pdev->is_open = false;
+ code = gx_default_put_params(pdev, plist);
+ pdev->is_open = is_open;
+ if ( code < 0 )
+ return code;
+
+ ppdev->NumCopies = nci;
+ ppdev->NumCopies_set = ncset;
+ ppdev->OpenOutputFile = oof;
+ if ( duplex_set >= 0 )
+ { ppdev->Duplex = duplex;
+ ppdev->Duplex_set = duplex_set;
+ }
+ ppdev->space_params = sp;
+
+ /* If necessary, free and reallocate the printer memory. */
+ /* Will not reallocate if device is not open */
+ code = gdev_prn_reallocate_memory(ppdev, &save_sp, width, height);
+ if (code < 0)
+ return code;
+
+ /* If filename changed, close file */
+ if ( ofs.data != 0 &&
+ bytes_compare(ofs.data, ofs.size,
+ (const byte *)ppdev->fname, strlen(ppdev->fname))
+ )
+ { /* Close the file if it's open. */
+ if ( ppdev->file != NULL && ppdev->file != stdout )
+ gp_close_printer(ppdev->file, ppdev->fname);
+ ppdev->file = NULL;
+ memcpy(ppdev->fname, ofs.data, ofs.size);
+ ppdev->fname[ofs.size] = 0;
+ }
+
+ /* If the device is open and OpenOutputFile is true, */
+ /* open the OutputFile now. (If the device isn't open, */
+ /* this will happen when it is opened.) */
+ if ( pdev->is_open && oof )
+ { code = gdev_prn_open_printer(pdev, 1);
+ if ( code < 0 )
+ return code;
+ }
+
+ return 0;
+}
+
+/* Put InputAttributes and OutputAttributes. */
+int
+gdev_prn_input_page_size(int index, gs_param_dict *pdict,
+ floatp width_points, floatp height_points)
+{ input_media media;
+ media.PageSize[0] = width_points;
+ media.PageSize[1] = height_points;
+ media.MediaColor = 0;
+ media.MediaWeight = 0;
+ media.MediaType = 0;
+ return gdev_prn_input_media(index, pdict, &media);
+}
+private int
+finish_media(gs_param_list *mlist, gs_param_name key, const char *media_type)
+{ int code = 0;
+ if ( media_type != 0 )
+ { gs_param_string as;
+ param_string_from_string(as, media_type);
+ code = param_write_string(mlist, key, &as);
+ }
+ return code;
+}
+int
+gdev_prn_input_media(int index, gs_param_dict *pdict, const input_media *pim)
+{ char key[25];
+ gs_param_dict mdict;
+ int code;
+ gs_param_string as;
+
+ sprintf(key, "%d", index);
+ mdict.size = 4;
+ code = param_begin_write_dict(pdict->list, key, &mdict, false);
+ if ( code < 0 )
+ return code;
+ if ( pim->PageSize[0] != 0 && pim->PageSize[1] != 0 )
+ { gs_param_float_array psa;
+ psa.data = pim->PageSize, psa.size = 2, psa.persistent = false;
+ code = param_write_float_array(mdict.list, "PageSize",
+ &psa);
+ if ( code < 0 )
+ return code;
+ }
+ if ( pim->MediaColor != 0 )
+ { param_string_from_string(as, pim->MediaColor);
+ code = param_write_string(mdict.list, "MediaColor",
+ &as);
+ if ( code < 0 )
+ return code;
+ }
+ if ( pim->MediaWeight != 0 )
+ { /* We do the following silly thing in order to avoid */
+ /* having to work around the 'const' in the arg list. */
+ float weight = pim->MediaWeight;
+ code = param_write_float(mdict.list, "MediaWeight",
+ &weight);
+ if ( code < 0 )
+ return code;
+ }
+ code = finish_media(mdict.list, "MediaType", pim->MediaType);
+ if ( code < 0 )
+ return code;
+ return param_end_write_dict(pdict->list, key, &mdict);
+}
+int
+gdev_prn_output_media(int index, gs_param_dict *pdict, const output_media *pom)
+{ char key[25];
+ gs_param_dict mdict;
+ int code;
+
+ sprintf(key, "%d", index);
+ mdict.size = 4;
+ code = param_begin_write_dict(pdict->list, key, &mdict, false);
+ if ( code < 0 )
+ return code;
+ code = finish_media(mdict.list, "OutputType", pom->OutputType);
+ if ( code < 0 )
+ return code;
+ return param_end_write_dict(pdict->list, key, &mdict);
+}
+
+/* ------ Others ------ */
+
+/* Default routines to override current space_params */
+void
+gdev_prn_default_get_space_params(const gx_device_printer *printer_dev,
+ gdev_prn_space_params *space_params)
+{ return;
+}
+
+/* Generic routine to send the page to the printer. */
+int /* 0 ok, -ve error, or 1 if successfully upgraded to buffer_page */
+gdev_prn_output_page(gx_device *pdev, int num_copies, int flush)
+{ int outcode = 0, closecode = 0, errcode = 0, endcode = 0;
+ bool upgraded_copypage = false;
+
+ if ( num_copies > 0 || !flush )
+ { int code = gdev_prn_open_printer(pdev, 1);
+ if ( code < 0 )
+ return code;
+
+ /* If copypage request, try to do it using buffer_page */
+ if ( !flush && (*ppdev->printer_procs.buffer_page)
+ (ppdev, ppdev->file, num_copies) >= 0 )
+ {
+ upgraded_copypage = true;
+ flush = true;
+ }
+ else if (num_copies > 0)
+ /* Print the accumulated page description. */
+ outcode =
+ (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
+ num_copies);
+ fflush(ppdev->file);
+ errcode =
+ ( ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0 );
+ if (!upgraded_copypage)
+ closecode = gdev_prn_close_printer(pdev);
+ }
+ endcode = ( ppdev->buffer_space ? clist_finish_page(pdev, flush) : 0 );
+
+ if ( outcode < 0 )
+ return outcode;
+ if ( errcode < 0 )
+ return errcode;
+ if ( closecode < 0 )
+ return closecode;
+ if ( endcode < 0 )
+ return endcode;
+ return upgraded_copypage ? 0 : 1;
+}
+
+/* Print multiple copies of a page by calling print_page multiple times. */
+int
+gx_default_print_page_copies(gx_device_printer *pdev, FILE *prn_stream,
+ int num_copies)
+{ int i = num_copies;
+ int code = 0;
+ while ( code >= 0 && i-- > 0 )
+ code = (*pdev->printer_procs.print_page)(pdev, prn_stream);
+ return code;
+}
+
+/* Buffer a (partial) rasterized page & optionally print result multiple times. */
+/* Default implementation returns error, since the driver needs to override */
+/* this (in procedure vector) in configurations where this call may occur. */
+int
+gx_default_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
+ int num_copies)
+{ return gs_error_unknownerror;
+}
+
+/* ---------------- Driver services ---------------- */
+
+/* Return the number of scan lines that should actually be passed */
+/* to the device. */
+int
+gdev_prn_print_scan_lines(gx_device *pdev)
+{ int height = pdev->height;
+ gs_matrix imat;
+ float yscale;
+ int top, bottom, offset, end;
+
+ (*dev_proc(pdev, get_initial_matrix))(pdev, &imat);
+ yscale = imat.yy * 72.0; /* Y dpi, may be negative */
+ top = (int)(dev_t_margin(pdev) * yscale);
+ bottom = (int)(dev_b_margin(pdev) * yscale);
+ offset = (int)(dev_y_offset(pdev) * yscale);
+ if ( yscale < 0 )
+ { /* Y=0 is top of page */
+ end = -offset + height + bottom;
+ }
+ else
+ { /* Y=0 is bottom of page */
+ end = offset + height - top;
+ }
+ return min(height, end);
+}
+
+/* Open the current page for printing. */
+int
+gdev_prn_open_printer_positionable(gx_device *pdev, bool binary_mode,
+ bool positionable)
+{
+ if ( ppdev->file != 0 )
+ { ppdev->file_is_new = false;
+ return 0;
+ }
+ { int code = gx_device_open_output_file(pdev, ppdev->fname,
+ binary_mode, positionable, &ppdev->file);
+ if ( code < 0 )
+ return code;
+ }
+ ppdev->file_is_new = true;
+ return 0;
+}
+
+/* Open the current page for printing. */
+int
+gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
+{ return gdev_prn_open_printer_positionable(pdev, binary_mode, false);
+}
+
+/* Copy a scan line from the buffer to the printer. */
+int
+gdev_prn_get_bits(gx_device_printer *pdev, int y, byte *str, byte **actual_data)
+{ int code = (*dev_proc(pdev, get_bits))((gx_device *)pdev, y, str, actual_data);
+ uint line_size = gdev_prn_raster(pdev);
+ int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
+ if ( code < 0 ) return code;
+ if ( last_bits != 0 )
+ { byte *dest = (actual_data != 0 ? *actual_data : str);
+ dest[line_size - 1] &= 0xff << last_bits;
+ }
+ return 0;
+}
+/* Copy scan lines to a buffer. Return the number of scan lines, */
+/* or <0 if error. */
+int
+gdev_prn_copy_scan_lines(gx_device_printer *pdev, int y, byte *str, uint size)
+{ uint line_size = gdev_prn_raster(pdev);
+ int count = size / line_size;
+ int i;
+ byte *dest = str;
+ count = min(count, pdev->height - y);
+ for ( i = 0; i < count; i++, dest += line_size )
+ { int code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
+ if ( code < 0 ) return code;
+ }
+ return count;
+}
+
+/* Like get_bits, but accepts initial raster contents */
+int
+gdev_prn_get_overlay_bits(gx_device_printer *pdev, int y, int lineCount, byte *data)
+{ if (pdev->buffer_space)
+ /* Command lists have built-in support for this function */
+ return clist_get_overlay_bits(pdev, y, lineCount, data);
+ else
+ /* Memory devices cannot support this function. */
+ return gs_error_unknownerror;
+}
+
+/* Find out where the band buffer for a given line is going to fall on the */
+/* next call to get_bits. */
+int /* rets # lines from y till end of buffer, or -ve error code */
+gdev_prn_locate_overlay_buffer(gx_device_printer *pdev, int y, byte **data)
+{ if (ppdev->buffer_space)
+ /* Command lists have built-in support for this function */
+ return clist_locate_overlay_buffer(pdev, y, data);
+ else
+ /* Memory devices cannot support this function. */
+ return gs_error_unknownerror;
+}
+
+/* Close the current page. */
+int
+gdev_prn_close_printer(gx_device *pdev)
+{ if ( strchr(ppdev->fname, '%') ) /* file per page */
+ { gp_close_printer(ppdev->file, ppdev->fname);
+ ppdev->file = NULL;
+ }
+ return 0;
+}
+
+/* If necessary, free and reallocate the printer memory after changing params */
+int /* rets 0 ok, else -ve error code */
+gdev_prn_reallocate_memory(gx_device_printer *prdev,
+ gdev_prn_space_params *old_sp, int old_width, int old_height)
+{ int code = 0;
+ gx_device * const pdev = (gx_device *)prdev;
+
+ if ( prdev->is_open &&
+ ( memcmp(&prdev->space_params, old_sp, sizeof(*old_sp)) != 0 ||
+ prdev->width != old_width || prdev->height != old_height )
+ )
+ { int new_width = prdev->width;
+ int new_height = prdev->height;
+ gdev_prn_space_params new_sp = prdev->space_params;
+
+ prdev->width = old_width;
+ prdev->height = old_height;
+ prdev->space_params = *old_sp;
+ code = gdev_prn_allocate_memory(pdev,
+ gdev_prn_allocate_reallocate, &new_sp, new_width, new_height);
+ /* If this fails, device should be usable w/old params, but */
+ /* band files may not be open. */
+ }
+ return code;
+}
+
diff --git a/gs/src/gdevprn.h b/gs/src/gdevprn.h
new file mode 100644
index 000000000..e1af88ccb
--- /dev/null
+++ b/gs/src/gdevprn.h
@@ -0,0 +1,524 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevprn.h */
+/* Common header file for memory-buffered printers */
+
+#ifndef gdevprn_INCLUDED
+# define gdevprn_INCLUDED
+
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gsutil.h" /* for memflip8x8 */
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclist.h"
+#include "gsparam.h"
+
+/*
+ * Define the parameters for the printer rendering method.
+ * If the entire bitmap fits in PRN_MAX_BITMAP, and there is at least
+ * PRN_MIN_MEMORY_LEFT memory left after allocating it, render in RAM,
+ * otherwise use a command list with a size of PRN_BUFFER_SPACE.
+ * (These are parameters that can be changed by a client program.)
+ */
+/* Define parameters for machines with little dinky RAMs.... */
+#define PRN_MAX_BITMAP_SMALL 32000
+#define PRN_BUFFER_SPACE_SMALL 25000
+#define PRN_MIN_MEMORY_LEFT_SMALL 32000
+/* Define parameters for machines with great big hulking RAMs.... */
+#define PRN_MAX_BITMAP_LARGE 10000000L
+#define PRN_BUFFER_SPACE_LARGE 1000000L
+#define PRN_MIN_MEMORY_LEFT_LARGE 500000L
+/* Define parameters valid on all machines. */
+#define PRN_MIN_BUFFER_SPACE 10000 /* give up if less than this */
+/* Now define conditional parameters. */
+#if arch_small_memory
+# define PRN_MAX_BITMAP PRN_MAX_BITMAP_SMALL
+# define PRN_BUFFER_SPACE PRN_BUFFER_SPACE_SMALL
+# define PRN_MIN_MEMORY_LEFT PRN_MIN_MEMORY_LEFT_SMALL
+#else
+/****** These should really be conditional on gs_debug_c('.') if
+ ****** DEBUG is defined, but they're used in static initializers,
+ ****** so we can't do it.
+ ******/
+# if 0 /****** # ifdef DEBUG ******/
+# define PRN_MAX_BITMAP\
+ (gs_debug_c('.') ? PRN_MAX_BITMAP_SMALL : PRN_MAX_BITMAP_LARGE)
+# define PRN_BUFFER_SPACE\
+ (gs_debug_c('.') ? PRN_BUFFER_SPACE_SMALL : PRN_BUFFER_SPACE_LARGE)
+# define PRN_MIN_MEMORY_LEFT\
+ (gs_debug_c('.') ? PRN_MIN_MEMORY_LEFT_SMALL : PRN_MIN_MEMORY_LEFT_LARGE)
+# else
+# define PRN_MAX_BITMAP PRN_MAX_BITMAP_LARGE
+# define PRN_BUFFER_SPACE PRN_BUFFER_SPACE_LARGE
+# define PRN_MIN_MEMORY_LEFT PRN_MIN_MEMORY_LEFT_LARGE
+# endif
+#endif
+
+#if !defined(gx_device_printer_defined)
+ #define gx_device_printer_defined
+/* Define the abstract type for a printer device. */
+typedef struct gx_device_printer_s gx_device_printer;
+#endif /* !defined(gx_device_printer_defined) */
+
+/* Define abstract type for some band device procedures' arguments */
+typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params;
+
+#if !defined(gx_page_queue_defined)
+# define gx_page_queue_defined
+typedef struct gx_page_queue_s gx_page_queue;
+#endif /* !defined(gx_page_queue_defined) */
+
+#if !defined(gdev_prn_space_params_defined)
+# define gdev_prn_space_params_defined
+typedef struct gdev_prn_space_params_s gdev_prn_space_params;
+#endif /* !defined(gdev_prn_space_params_defined) */
+
+/*
+ * Define the special procedures for band devices.
+ */
+typedef struct gx_printer_device_procs_s {
+
+ /*
+ * Print the page on the output file. Required only for devices
+ * where output_page is gdev_prn_output_page; ignored for other
+ * devices.
+ */
+#define dev_proc_print_page(proc)\
+ int proc(P2(gx_device_printer *, FILE *))
+ dev_proc_print_page((*print_page));
+
+ /* Print the page on the output file, with a given # of copies. */
+#define dev_proc_print_page_copies(proc)\
+ int proc(P3(gx_device_printer *, FILE *, int))
+ dev_proc_print_page_copies((*print_page_copies));
+
+ /* Initialize the memory device for a page or a band. */
+ /* (The macro definition is in gxdevice.h.) */
+ dev_proc_make_buffer_device((*make_buffer_device));
+
+ /* Compute effective space params. These results effectively override */
+ /* the space_params in the device, but does not replace them; that is */
+ /* to say that computed space params are temps used for computation. */
+ /* Procedure must fill in only those space_params that it wishes to */
+ /* override, using curr width, height, margins, etc. */
+ /* Caller is gdevprn.open & gdevprn.put_params, calls driver or dflt */
+#define dev_proc_get_space_params(proc)\
+ void proc(P2(const gx_device_printer *, gdev_prn_space_params *))
+ dev_proc_get_space_params((*get_space_params));
+
+ /* Only for gx_device_printer devices that overlap interpretating */
+ /* and rasterizing. Since there are 2 instances of the device (1 for */
+ /* writing the cmd list & 1 for rasterizing it), and each device */
+ /* is associated with an different thread, this function is called to */
+ /* start the rasterizer's thread. Once started, the rasterizer thread */
+ /* must call down to gdev_prn_asnyc_render_thread, which will only return */
+ /* after device closes. */
+ /* Caller is gdevprna.open, calls driver implementation or dflt */
+#define dev_proc_start_render_thread(proc)\
+ int proc(P1(gdev_prn_start_render_params *))
+ dev_proc_start_render_thread((*start_render_thread));
+
+ /* Only for gx_device_printer devices that overlap interpretating */
+ /* and rasterizing. Since there are 2 instances of the device (1 for */
+ /* writing the cmd list & 1 for rasterizing it), these fns are called */
+ /* to open/close the rasterizer's instance, once the writer's instance has */
+ /* been created & init'd. These procs must cascade down to */
+ /* gdev_prn_async_render_open/close. */
+ /* Caller is gdevprna, calls driver implementation or dflt */
+#define dev_proc_open_render_device(proc)\
+ int proc(P1(gx_device_printer *))
+ dev_proc_open_render_device((*open_render_device));
+
+#define dev_proc_close_render_device(proc)\
+ int proc(P1(gx_device_printer *))
+ dev_proc_close_render_device((*close_render_device));
+
+ /* Buffer a page on the output device. An page may or may not have been */
+ /* fully rendered, but the rasterizer needs to realize the page to free */
+ /* up resources or support copypage. Printing a page */
+ /* may involve zero or more buffer_page's. All buffer_page output is */
+ /* overlaid in the buffer until a terminating print_page */
+ /* or print_page_copies clears the buffer. Note that, after */
+ /* the first buffer_page, the driver must use the */
+ /* get_overlay_bits function instead of get_bits. The difference is */
+ /* that get_overlay_bits requires the caller to supply the same */
+ /* buffered bitmap that was computed as a result of a previous */
+ /* buffer_page, so that get_overlay_bits can add further */
+ /* marks to the existing buffered image. NB that output must be */
+ /* accumulated in buffer even if num_copies == 0. */
+ /* Caller is expected to be gdevprn, calls driver implementation or dflt */
+#define dev_proc_buffer_page(proc)\
+ int proc(P3(gx_device_printer *, FILE *, int))
+ dev_proc_buffer_page((*buffer_page));
+
+ /* Transform a given set of bits by marking it per the current page */
+ /* description. This is a different version of get_bits, where */
+ /* this procedure accepts a bitmap and merely adds further marks, */
+ /* without clearing the bits. */
+ /* Driver implementation is expected to be the caller */
+#define dev_proc_get_overlay_bits(proc)\
+ int proc(P4(gx_device_printer *, int, int, byte *))
+ dev_proc_get_overlay_bits((*get_overlay_bits));
+
+ /* Find out where the band buffer for a given line is going to fall on the */
+ /* next call to get_bits. This is an alternative to get_overlay_bits */
+ /* in cases where the client doesn't own a suitably formatted buffer */
+ /* to deposit bits into. When using this function, do a locate_overlay_buffer,*/
+ /* copy the background data into the returned buffer, then do get_bits */
+ /* to get the transformed data. */
+ /* IMPORTANT: the locate_overlay_buffer for a specific range of lines must */
+ /* immediately be followed by one or more get_bits for the same line */
+ /* range with no other intervening driver calls. If this condition is */
+ /* violated, results are undefined. */
+#define dev_proc_locate_overlay_buffer(proc)\
+ int proc(P3(gx_device_printer *, int, byte **))
+ dev_proc_locate_overlay_buffer((*locate_overlay_buffer));
+
+} gx_printer_device_procs;
+
+/* ------ Printer device definition ------ */
+
+/* Structure for generic printer devices. */
+/* This must be preceded by gx_device_common. */
+/* Printer devices are actually a union of a memory device */
+/* and a clist device, plus some additional state. */
+#define prn_fname_sizeof 80
+typedef enum
+ {BandingAuto = 0, BandingAlways, BandingNever}
+gdev_prn_banding_type;
+struct gdev_prn_space_params_s {
+ long MaxBitmap; /* max size of non-buffered bitmap */
+ long BufferSpace; /* space to use for buffer */
+ gx_band_params band; /* see gxclist.h */
+ bool params_are_read_only; /* true if put_parms may not modify this struct */
+ gdev_prn_banding_type banding_type; /* used to force banding or bitmap */
+}; /* typedef above */
+#define gx_prn_device_common\
+ byte skip[max(sizeof(gx_device_memory), sizeof(gx_device_clist)) -\
+ sizeof(gx_device) + sizeof(double) /* padding */];\
+ gx_printer_device_procs printer_procs;\
+ /* ------ Device parameters that must be set ------ */\
+ /* ------ before calling the device open routine. ------ */\
+ gdev_prn_space_params space_params;\
+ char fname[prn_fname_sizeof]; /* OutputFile */\
+ /* ------ Other device parameters ------ */\
+ int NumCopies;\
+ bool NumCopies_set;\
+ bool OpenOutputFile;\
+ bool Duplex;\
+ int Duplex_set; /* -1 = not supported */\
+ /* ------ End of parameters ------ */\
+ bool file_is_new; /* true iff file just opened */\
+ FILE *file; /* output file */\
+ long buffer_space; /* amount of space for clist buffer, */\
+ /* 0 means not using clist */\
+ byte *buf; /* buffer for rendering */\
+ /* ---- Begin async rendering support --- */\
+ gs_memory_t *buffer_memory; /* allocator for command list */\
+ gs_memory_t *bandlist_memory; /* allocator for bandlist files */\
+ proc_free_up_bandlist_memory((*free_up_bandlist_memory)); /* if nz, proc to free some bandlist memory */\
+ gx_page_queue *page_queue; /* if <> 0,page queue for gdevprna NOT GC'd */\
+ bool is_async_renderer; /* device is only the rendering part of async device */\
+ struct gx_device_printer_s *async_renderer; /* in async writer, pointer to async renderer */\
+ int clist_disable_mask; /* mask of clist options to disable */\
+ /* ---- End async rendering support --- */\
+ gx_device_procs orig_procs /* original (std_)procs */
+
+/* The device descriptor */
+struct gx_device_printer_s {
+ gx_device_common;
+ gx_prn_device_common;
+};
+
+/* Macro for casting gx_device argument */
+#define prn_dev ((gx_device_printer *)dev)
+
+/* Define a typedef for the sake of ansi2knr. */
+typedef dev_proc_print_page((*dev_proc_print_page_t));
+
+/* Standard device procedures for printers */
+dev_proc_open_device(gdev_prn_open);
+dev_proc_open_render_device(gx_default_open_render_device);
+dev_proc_close_render_device(gx_default_close_render_device);
+dev_proc_output_page(gdev_prn_output_page);
+dev_proc_close_device(gdev_prn_close);
+#define gdev_prn_map_rgb_color gx_default_b_w_map_rgb_color
+#define gdev_prn_map_color_rgb gx_default_b_w_map_color_rgb
+dev_proc_get_params(gdev_prn_get_params);
+dev_proc_put_params(gdev_prn_put_params);
+dev_proc_get_space_params(gdev_prn_default_get_space_params);
+
+/* Macro for generating procedure table */
+#define prn_procs(p_open, p_output_page, p_close)\
+ prn_color_procs(p_open, p_output_page, p_close, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb)
+#define prn_params_procs(p_open, p_output_page, p_close, p_get_params, p_put_params)\
+ prn_color_params_procs(p_open, p_output_page, p_close, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb, p_get_params, p_put_params)
+#define prn_color_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb)\
+ prn_color_params_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb, gdev_prn_get_params, gdev_prn_put_params)
+/* See gdev_prn_open for explanation of the NULLs below. */
+#define prn_color_params_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb, p_get_params, p_put_params) {\
+ p_open,\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ p_output_page,\
+ p_close,\
+ p_map_rgb_color,\
+ p_map_color_rgb,\
+ NULL, /* fill_rectangle */\
+ NULL, /* tile_rectangle */\
+ NULL, /* copy_mono */\
+ NULL, /* copy_color */\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ p_get_params,\
+ p_put_params,\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ gx_page_device_get_page_device,\
+ NULL, /* get_alpha_bits */\
+ NULL, /* copy_alpha */\
+ NULL, /* get_band */\
+ NULL, /* copy_rop */\
+ NULL, /* fill_path */\
+ NULL, /* stroke_path */\
+ NULL, /* fill_mask */\
+ NULL, /* fill_trapezoid */\
+ NULL, /* fill_parallelogram */\
+ NULL, /* fill_triangle */\
+ NULL, /* draw_thin_line */\
+ NULL, /* begin_image */\
+ NULL, /* image_data */\
+ NULL, /* end_image */\
+ NULL, /* strip_tile_rectangle */\
+ NULL, /* strip_copy_rop, */\
+ NULL, /* get_clipping_box */\
+ NULL /* get_hardware_params */\
+}
+
+/* The standard printer device procedures */
+/* (using gdev_prn_open/output_page/close). */
+extern gx_device_procs prn_std_procs;
+
+/*
+ * Define macros for generating the device structure,
+ * analogous to the std_device_body macros in gxdevice.h
+ * Note that the macros are broken up so as to be usable for devices that
+ * add further initialized state to the printer device.
+ *
+ * The 'margin' values provided here specify the unimageable region
+ * around the edges of the page (in inches), and the left and top margins
+ * also specify the displacement of the device (0,0) point from the
+ * upper left corner. We should provide macros that allow specifying
+ * all 6 values independently, but we don't yet.
+ */
+#define prn_device_body_rest_(print_page)\
+ { 0 }, /* std_procs */\
+ { 0 }, /* skip */\
+ { print_page,\
+ gx_default_print_page_copies,\
+ gx_default_make_buffer_device,\
+ gdev_prn_default_get_space_params,\
+ gx_default_start_render_thread,\
+ gx_default_open_render_device,\
+ gx_default_close_render_device,\
+ gx_default_buffer_page,\
+ gdev_prn_get_overlay_bits,\
+ gdev_prn_locate_overlay_buffer,\
+ },\
+ { PRN_MAX_BITMAP, PRN_BUFFER_SPACE,\
+ { band_params_initial_values },\
+ 0/*false*/, /* params_are_read_only */\
+ BandingAuto /* banding_type */\
+ },\
+ { 0 }, /* fname */\
+ 1, 0/*false*/, /* NumCopies[_set] */\
+ 0/*false*/, /* OpenOutputFile */\
+ 0/*false*/, -1, /* Duplex[_set] */\
+ 0/*false*/, 0, 0, 0, /* buf */\
+ &gs_memory_default, /* buffer_memory */\
+ &gs_memory_default, /* bandlist_memory */\
+ 0, /* free_up_bandlist_memory */\
+ 0, /* page_queue */\
+ 0/*false*/, /* is_async_renderer */\
+ 0, /* async_renderer */\
+ 0, /* clist_disable_mask */\
+ { 0 } /* ... orig_procs */
+
+/* The Sun cc compiler won't allow \ within a macro argument list. */
+/* This accounts for the short parameter names here and below. */
+#define prn_device_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)\
+ std_device_full_body(dtype, &procs, dname,\
+ (int)((long)(w10) * (xdpi) / 10),\
+ (int)((long)(h10) * (ydpi) / 10),\
+ xdpi, ydpi,\
+ ncomp, depth, mg, mc, dg, dc,\
+ -(lo) * (xdpi), -(to) * (ydpi),\
+ (lm) * 72.0, (bm) * 72.0,\
+ (rm) * 72.0, (tm) * 72.0\
+ ),\
+ prn_device_body_rest_(print_page)
+
+#define prn_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)\
+ prn_device_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi,\
+ lm, tm, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)
+
+#define prn_device_std_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\
+ std_device_std_color_full_body(dtype, &procs, dname,\
+ (int)((long)(w10) * (xdpi) / 10),\
+ (int)((long)(h10) * (ydpi) / 10),\
+ xdpi, ydpi, color_bits,\
+ -(lo) * (xdpi), -(to) * (ydpi),\
+ (lm) * 72.0, (bm) * 72.0,\
+ (rm) * 72.0, (tm) * 72.0\
+ ),\
+ prn_device_body_rest_(print_page)
+
+#define prn_device_std_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\
+ prn_device_std_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi,\
+ lm, tm, lm, bm, rm, tm, color_bits, print_page)
+
+#define prn_device_margins(procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\
+{ prn_device_std_margins_body(gx_device_printer, procs, dname,\
+ w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\
+}
+
+#define prn_device(procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\
+ prn_device_margins(procs, dname, w10, h10, xdpi, ydpi,\
+ lm, tm, lm, bm, rm, tm, color_bits, print_page)\
+
+/* ------ Utilities ------ */
+/* These are defined in gdevprn.c. */
+
+int gdev_prn_open_printer(P2(gx_device *dev, bool binary_mode));
+int gdev_prn_open_printer_positionable(P3(gx_device *dev, bool binary_mode, bool positionable));
+#define gdev_prn_file_is_new(pdev) ((pdev)->file_is_new)
+#define gdev_prn_raster(pdev) gx_device_raster((gx_device *)(pdev), 0)
+int gdev_prn_get_bits(P4(gx_device_printer *, int, byte *, byte **));
+int gdev_prn_copy_scan_lines(P4(gx_device_printer *, int, byte *, uint));
+int gdev_prn_close_printer(P1(gx_device *));
+
+/* Define the InputAttributes and OutputAttributes of a device. */
+/* The device get_params procedure would call these. */
+
+typedef struct input_media_s {
+ float PageSize[2];
+ const char *MediaColor;
+ float MediaWeight;
+ const char *MediaType;
+} input_media;
+#define gdev_prn_begin_input_media(plist, pdict, count)\
+ ((pdict)->size = (count),\
+ param_begin_write_dict(plist, "InputAttributes", pdict, true))
+int gdev_prn_input_page_size(P4(int index, gs_param_dict *pdict,
+ floatp width_points, floatp height_points));
+int gdev_prn_input_media(P3(int index, gs_param_dict *pdict,
+ const input_media *pim));
+#define gdev_prn_end_input_media(plist, pdict)\
+ param_end_write_dict(plist, "InputAttributes", pdict)
+
+typedef struct output_media_s {
+ const char *OutputType;
+} output_media;
+#define gdev_prn_begin_output_media(plist, pdict, count)\
+ ((pdict)->size = (count),\
+ param_begin_write_dict(plist, "OutputAttributes", pdict, true))
+int gdev_prn_output_media(P3(int index, gs_param_dict *pdict,
+ const output_media *pom));
+#define gdev_prn_end_output_media(plist, pdict)\
+ param_end_write_dict(plist, "OutputAttributes", pdict)
+
+/* The default print_page_copies procedure just calls print_page */
+/* the given number of times. */
+dev_proc_print_page_copies(gx_default_print_page_copies);
+
+/* The default buffer_page returns an error */
+dev_proc_buffer_page(gx_default_buffer_incomplete_page);
+
+/* The default get_overlay_bits */
+dev_proc_get_overlay_bits(gdev_prn_get_overlay_bits);
+
+/* Define the number of scan lines that should actually be passed */
+/* to the device. */
+int gdev_prn_print_scan_lines(P1(gx_device *));
+
+/* Free and reallocate the printer memory */
+typedef enum {
+ gdev_prn_allocate_allocate,
+ gdev_prn_allocate_free,
+ gdev_prn_allocate_reallocate
+} gdev_prn_allocate_action;
+int gdev_prn_allocate_memory(P5(gx_device *, gdev_prn_allocate_action, gdev_prn_space_params *, int, int));
+
+/* Default start_render_thread (for async rendering only -- see gdevprna.c) */
+dev_proc_start_render_thread(gx_default_start_render_thread);
+
+/* Default buffer_page */
+dev_proc_buffer_page(gx_default_buffer_page);
+
+/* Default locate_overlay_buffer */
+dev_proc_locate_overlay_buffer(gdev_prn_locate_overlay_buffer);
+
+/* BACKWARD COMPATIBILITY */
+#define dev_print_scan_lines(dev)\
+ gdev_prn_print_scan_lines((gx_device *)(dev))
+#define gdev_mem_bytes_per_scan_line(dev)\
+ gdev_prn_raster((gx_device_printer *)(dev))
+#define gdev_prn_transpose_8x8(inp,ils,outp,ols)\
+ memflip8x8(inp,ils,outp,ols)
+
+/* ------ Printer device types ------ */
+/**************** THE FOLLOWING CODE IS NOT USED YET. ****************/
+
+#if 0 /**************** VMS linker gets upset ****************/
+extern_st(st_prn_device);
+#endif
+int gdev_prn_initialize(P3(gx_device *, const char _ds *, dev_proc_print_page((*))));
+void gdev_prn_init_color(P4(gx_device *, int, dev_proc_map_rgb_color((*)), dev_proc_map_color_rgb((*))));
+
+#define prn_device_type(dtname, initproc, pageproc)\
+private dev_proc_print_page(pageproc);\
+device_type(dtname, st_prn_device, initproc)
+
+/****** FOLLOWING SHOULD CHECK __PROTOTYPES__ ******/
+#define prn_device_type_mono(dtname, dname, initproc, pageproc)\
+private dev_proc_print_page(pageproc);\
+private int \
+initproc(gx_device *dev)\
+{ return gdev_prn_initialize(dev, dname, pageproc);\
+}\
+device_type(dtname, st_prn_device, initproc)
+
+/****** DITTO ******/
+#define prn_device_type_color(dtname, dname, depth, initproc, pageproc, rcproc, crproc)\
+private dev_proc_print_page(pageproc);\
+private int \
+initproc(gx_device *dev)\
+{ int code = gdev_prn_initialize(dev, dname, pageproc);\
+ gdev_prn_init_color(dev, depth, rcproc, crproc);\
+ return code;\
+}\
+device_type(dtname, st_prn_device, initproc)
+
+#endif /* gdevprn_INCLUDED */
diff --git a/gs/src/gdevprna.h b/gs/src/gdevprna.h
new file mode 100644
index 000000000..a2fc8a070
--- /dev/null
+++ b/gs/src/gdevprna.h
@@ -0,0 +1,174 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevprna.h */
+/* Generic asynchronous printer driver support */
+/**/
+/* Initial version 2/1/1998 by John Desrosiers (soho@crl.com) */
+
+
+#if !defined(gdevprna_h_INCLUDED)
+# define gdevprna_h_INCLUDED
+
+# include "gdevprn.h"
+# include "gxsync.h"
+
+/*
+ * General
+ * -------
+ * Async drivers actually create two separate instances of the device at
+ * the same time. The first (the writer instance) is only used in the
+ * interpretation operation; it feeds rendering commands into the command
+ * lists. The second device instance is used only for rendering the
+ * commands placed into the command list by the writer.
+
+ * The writer builds a command list for an entire page; the command list
+ * is only queued for rendering once a page's command list is completely
+ * built. The only exception to this rule is when the interpreter runs
+ * out of memory, or when no free command list memory is available. In
+ * such cases, the interpreter queues a "partial page" consisting of all
+ * command list data written so far, plus a command indicating that the
+ * page description is not complete. After queuing the partial page, the
+ * interpereter waits until the rendering process has freed enough
+ * command list memory to enable the interpreter to proceed.
+
+ * To avoid deadlocks when the system runs out of memory, special
+ * memory allocation provisions are made on both the writer and
+ * renderer sides. On the writer side, enough "reserve" bandlist
+ * memory is set aside at startup time to cover the needs of queuing a
+ * partial page to the renderer. The renderer operates out of a fixed
+ * memory space; that way, it can always complete rendering pages with
+ * the memory it has. To this end, the writer protects the renderer
+ * from consuming unbounded amounts of memory by a) never putting
+ * complex paths into the command list, b) pre-clipping any output
+ * unless the clip path consists of a single rectangle, c) never putting
+ * high-level images into the clip path unless the image in question
+ * meets some very stringent requirements, such as only being rotated by
+ * even multiples of 90 degrees and having source-image data rows which
+ * fit into the command buffer in one piece. These restrictions are what
+ * dictate the "restricted bandlist format."
+
+ * Note that the renderer's instance of the device driver uses the
+ * renderer's memory. That implies that it must also operate in a small,
+ * fixed amount of memory, and must do all memory allocation using the
+ * memory allocator pointed to by the render device's ->memory member.
+
+ * Opening the Device
+ * ------------------
+ * The writer instance is opened first. This occurs when the system
+ * calls the "standard" open procedure via the device's procedure
+ * vector. The driver must implement the open function, but must call
+ * down to gdev_prn_async_write_open instead of calling down to
+ * gdev_prn_open. Before calling down to gdev_prn_async_write_open, the
+ * driver must:
+ * a - init several procedure vectors, to wit: start_render_thread,
+ * buffer_page, print_page_copies,
+ * b - init space_params.band.BandWidth, space_params.band.BandHeight,
+ * space_params.BufferSpace (see extended comments in gdevasyn.c
+ * for details on computing appropriate values).
+ * c - if it implements those functions, the driver must init the
+ * procedure vectors for: put_params, get_hardware_params,
+ * output_page, open_render_device.
+ * Notice that there are two procedure vectors: the usual std_procs, and
+ * the printer-specific printer_procs.
+
+ * Since partial page support imposes extra requirements on drivers,
+ * such support can be disabled by zeroing out (in the async writer open
+ * routine, after calling down to gdev_prn_async_write_open) the
+ * free_up_bandlist_memory member of the driver structure. Doing so
+ * will, of course, cause interpretation to fail if memory runs out.
+
+ * Once the driver calls down to gdev_prn_async_write_open, the async
+ * support logic will create a second instance of the driver for
+ * rendering, but will not open it just yet. Instead, the async logic
+ * will attempt to synchronize the two device instances.
+
+ * Synchrnonizing the instances
+ * ----------------------------
+ * While still in the gdev_prn_async_write_open routine, the async logic
+ * will call printer_procs.start_render_thread (which the driver is
+ * required to implement). start_render_thread must somehow either start a new
+ * thread or rendez-vous with an existing thread for use in rendering,
+ * then return. start_render_thread must also have caused the render thread
+ * to call gdev_prn_async_render_thread, passing it as an argument a magic
+ * cookie passed to start_render_thread. start_render_thread will only
+ * return once the device has been closed and all renering has been
+ * completed.
+
+ * The render device will be opened on the render device's thread, by
+ * calling printer_procs.open_render_device.
+
+ * Rendering Operation
+ * -------------------
+ * During rendering, the device will not see rendering operations -- the
+ * first "rendering" operations the driver will see is when the renderer
+ * instance's print_page_copies or buffer_page routines get called. In
+ * both cases, the appropriate routine must then perform get_bits calls
+ * on the async logic in order to retrieve rendered bits, then transmit
+ * them to the appropriate device buffers.
+
+ * The complication that is introduced is that which is related to
+ * partial pages: A buffer_page call instructs the driver to grab the
+ * rendered bits, but to keep the rendered bits available for later
+ * instead of marking on media. This implies that a buffer_page call
+ * opens a context where subsequent buffer_page's and print_page_copies'
+ * must first initialize the rendering buffers with the previous
+ * rendering results before calling get_bits. Drivers use the
+ * locate_overlay_buffer function to initialize the driver's rendering
+ * buffers. The first print_page_copies closes the context that was
+ * opened by the initial buffer_page -- the driver must go back to
+ * normal rendering until a new buffer_page comes along.
+ */
+
+/* -------------- Type declarations --------------- */
+
+struct gdev_prn_start_render_params_s {
+ gx_device_printer *writer_device;/* writer dev that points to render dev */
+ gx_semaphore_t *open_semaphore; /* signal this once open_code is set */
+ int open_code; /* RETURNS status of open of reader device */
+};
+/* typedef is in gdevprn.h */
+/* typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params;*/
+
+
+/* -------- Macros used to initialize render-specific structures ------ */
+
+#define init_async_render_procs(xpdev, xstart_render_thread,\
+ xbuffer_page, xprint_page_copies)\
+ { (xpdev)->printer_procs.start_render_thread = (xstart_render_thread);\
+ (xpdev)->printer_procs.buffer_page = (xbuffer_page);\
+ (xpdev)->printer_procs.print_page_copies = (xprint_page_copies);\
+ }
+
+
+/* -------------- Global procedure declarations --------- */
+/* Open this printer device in ASYNC (overlapped) mode.
+ *
+ * This routine is always called by the concrete device's xx_open routine
+ * in lieu of gdev_prn_open.
+ */
+int
+gdev_prn_async_write_open(P4(gx_device_printer *pdev, int max_raster, int min_band_height, int max_src_image_row));
+
+/* Called directly by the real driver of an async device. This is the */
+/* rendering loop, which reqiures its own thread for as long as the */
+/* device is open. This proc only returns after the device is closed.*/
+int /* rets 0 ok, -ve error code */
+gdev_prn_async_render_thread(P1(gdev_prn_start_render_params *));
+
+#endif /*!defined(gdevprna_h_INCLUDED)*/
diff --git a/gs/src/gdevps.c b/gs/src/gdevps.c
new file mode 100644
index 000000000..d311bc720
--- /dev/null
+++ b/gs/src/gdevps.c
@@ -0,0 +1,798 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevps.c */
+/* PostScript-writing driver */
+#include "math_.h"
+#include "time_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscdefs.h"
+#include "gsmatrix.h" /* for gsiparam.h */
+#include "gsiparam.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gscspace.h"
+#include "gxdcolor.h"
+#include "gdevpsdf.h"
+#include "gdevpstr.h"
+#include "strimpl.h"
+#include "sa85x.h"
+
+/****************************************************************
+ * Notes:
+ * ASCII85EncodePages should use ASCIIHexEncode if LanguageLevel < 2.
+ * Images are never compressed; in fact, none of the other
+ * Distiller parameters do anything.
+ ****************************************************************/
+
+/* ---------------- Device definition ---------------- */
+
+/* Define the size of the internal stream buffer. */
+/* (This is not a limitation: it only affects performance.) */
+#define sbuf_size 512
+
+/* Device procedures */
+private dev_proc_open_device(psw_open);
+private dev_proc_output_page(psw_output_page);
+private dev_proc_close_device(psw_close);
+private dev_proc_copy_mono(psw_copy_mono);
+private dev_proc_copy_color(psw_copy_color);
+private dev_proc_put_params(psw_put_params);
+private dev_proc_get_params(psw_get_params);
+private dev_proc_fill_mask(psw_fill_mask);
+private dev_proc_begin_image(psw_begin_image);
+private dev_proc_image_data(psw_image_data);
+private dev_proc_end_image(psw_end_image);
+
+#define X_DPI 720
+#define Y_DPI 720
+
+typedef struct gx_device_pswrite_s {
+ gx_device_psdf_common;
+ /* Settable parameters */
+#define LanguageLevel_default 2.0
+ float LanguageLevel;
+ /* End of parameters */
+ bool ProduceEPS;
+ bool first_page;
+ long bbox_position;
+ stream *image_stream;
+ byte *image_buf;
+#define num_cached_images 137
+ gx_bitmap_id image_cache[num_cached_images];
+} gx_device_pswrite;
+
+gs_private_st_suffix_add2_final(st_device_pswrite, gx_device_pswrite,
+ "gx_device_pswrite", device_pswrite_enum_ptrs, device_pswrite_reloc_ptrs,
+ gx_device_finalize, st_device_psdf, image_stream, image_buf);
+
+#define psw_procs\
+ { psw_open,\
+ gx_upright_get_initial_matrix,\
+ NULL, /* sync_output */\
+ psw_output_page,\
+ psw_close,\
+ gx_default_rgb_map_rgb_color,\
+ gx_default_rgb_map_color_rgb,\
+ gdev_vector_fill_rectangle,\
+ NULL, /* tile_rectangle */\
+ psw_copy_mono,\
+ psw_copy_color,\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ psw_get_params,\
+ psw_put_params,\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ gx_page_device_get_page_device,\
+ NULL, /* get_alpha_bits */\
+ NULL, /* copy_alpha */\
+ NULL, /* get_band */\
+ NULL, /* copy_rop */\
+ gdev_vector_fill_path,\
+ gdev_vector_stroke_path,\
+ psw_fill_mask,\
+ gdev_vector_fill_trapezoid,\
+ gdev_vector_fill_parallelogram,\
+ gdev_vector_fill_triangle,\
+ NULL /****** WRONG ******/, /* draw_thin_line */\
+ psw_begin_image,\
+ psw_image_data,\
+ psw_end_image,\
+ NULL, /* strip_tile_rectangle */\
+ NULL/******psw_strip_copy_rop******/\
+ }
+
+gx_device_pswrite far_data gs_pswrite_device =
+{ std_device_dci_type_body(gx_device_pswrite, 0, "pswrite",
+ &st_device_pswrite,
+ DEFAULT_WIDTH_10THS*X_DPI/10, DEFAULT_HEIGHT_10THS*Y_DPI/10,
+ X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256),
+ psw_procs,
+ psdf_initial_values(1 /*true*/), /* (ASCII85EncodePages) */
+ LanguageLevel_default, /* LanguageLevel */
+ 0/*false*/ /* ProduceEPS */
+};
+
+gx_device_pswrite far_data gs_epswrite_device =
+{ std_device_dci_type_body(gx_device_pswrite, 0, "epswrite",
+ &st_device_pswrite,
+ DEFAULT_WIDTH_10THS*X_DPI/10, DEFAULT_HEIGHT_10THS*Y_DPI/10,
+ X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256),
+ psw_procs,
+ psdf_initial_values(1 /*true*/), /* (ASCII85EncodePages) */
+ LanguageLevel_default, /* LanguageLevel */
+ 1/*true*/ /* ProduceEPS */
+};
+
+/* Vector device implementation */
+private int psw_beginpage(P1(gx_device_vector *vdev));
+private int psw_setcolors(P2(gx_device_vector *vdev,
+ const gx_drawing_color *pdc));
+private int psw_endpath(P2(gx_device_vector *vdev, gx_path_type_t type));
+private const gx_device_vector_procs psw_vector_procs = {
+ /* Page management */
+ psw_beginpage,
+ /* Imager state */
+ psdf_setlinewidth,
+ psdf_setlinecap,
+ psdf_setlinejoin,
+ psdf_setmiterlimit,
+ psdf_setdash,
+ psdf_setflat,
+ psdf_setlogop,
+ /* Other state */
+ psw_setcolors, /* fill & stroke colors are the same */
+ psw_setcolors,
+ /* Paths */
+ psdf_dopath,
+ psdf_dorect,
+ psdf_beginpath,
+ psdf_moveto,
+ psdf_lineto,
+ psdf_curveto,
+ psdf_closepath,
+ psw_endpath
+};
+
+/* ---------------- File header ---------------- */
+
+private const char *psw_ps_header[] = {
+"%!PS-Adobe-3.0",
+"%%Pages: (atend)",
+0
+};
+
+private const char *psw_eps_header[] = {
+"%!PS-Adobe-3.0 EPSF-3.0",
+0
+};
+
+private const char *psw_header[] = {
+"%%EndComments",
+"%%BeginProlog",
+"% This copyright applies to everything between here and the %%EndProlog:",
+0
+};
+
+private const char *psw_prolog[] = {
+"%%BeginResource: procset GS_pswrite_ProcSet",
+"/GS_pswrite_ProcSet 40 dict dup begin",
+"/!{bind def}bind def/X{load def}!",
+"/rg/setrgbcolor X/g/setgray X/w/setlinewidth X/J/setlinecap X",
+"/j/setlinejoin X/M/setmiterlimit X/d/setdash X/i/setflat X",
+"/m/moveto X/l/lineto X/c/curveto X/h/closepath X",
+"/lx{0 rlineto}!/ly{0 exch rlineto}!/v{currentpoint 6 2 roll c}!/y{2 copy c}!",
+"/re{4 -2 roll m exch dup lx exch ly neg lx h}!",
+"/q/gsave X/Q/grestore X/f/fill X/f*/eofill X/S/stroke X/rf{re f}!",
+"/Y{initclip clip newpath}!/Y*{initclip eoclip newpath}!/rY{re Y}!",
+"/@/currentfile X/|{string readstring pop}!",
+ /* <w> <h> <x> <y> <bps/inv> <src> Ix <w> <h> <bps/inv> <mtx> <src> */
+"/Ix{[1 0 0 1 9 -1 roll neg 9 -1 roll neg]exch}!",
+"/It{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!",
+0
+};
+
+private const char *psw_1_prolog[] = {
+0
+};
+
+private const char *psw_1_5_prolog[] = {
+"/Ic{Ix false 1 colorimage}!",
+0
+};
+
+private const char *psw_2_prolog[] = {
+"/@85{@/ASCII85Decode filter}!",
+0
+};
+
+private const char *psw_end_prolog[] = {
+"end def",
+"%%EndResource",
+"%%EndProlog",
+0
+};
+
+private void
+psw_put_lines(stream *s, const char **lines)
+{ int i;
+ for ( i = 0; lines[i] != 0; ++i )
+ pprints1(s, "%s\n", lines[i]);
+}
+
+/* ---------------- Utilities ---------------- */
+
+/* Reset the image cache. */
+private void
+image_cache_reset(gx_device_pswrite *pdev)
+{ int i;
+ for ( i = 0; i < num_cached_images; ++i )
+ pdev->image_cache[i] = gx_no_bitmap_id;
+}
+
+/* Look up or enter an image ID in the cache. */
+/* If id is gx_no_bitmap_id or enter is false, do not enter it. */
+private bool
+image_cache_lookup(gx_device_pswrite *pdev, gx_bitmap_id id, bool enter)
+{ int i;
+
+ if ( id == gx_no_bitmap_id )
+ return false;
+ i = id % num_cached_images;
+ if ( pdev->image_cache[i] == id )
+ return true;
+ if ( enter )
+ pdev->image_cache[i] = id;
+ return false;
+}
+
+/* Set up to write a device-pixel image. */
+/* Return false if the image is empty. */
+private bool
+psw_image_setup(gx_device_pswrite *pdev, int x, int y, int w, int h)
+{ stream *s = pdev->strm;
+
+ if ( w <= 0 || h <= 0 )
+ return false;
+ pprintd4(s, "%d %d %d %d ", w, h, x, y);
+ return true;
+}
+
+/* Prepare the encoding stream for image data. */
+/* Return 1 if we are using ASCII85 encoding. */
+private const stream_procs filter_write_procs =
+{ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+};
+private int
+psw_image_stream_setup(gx_device_pswrite *pdev)
+{ pdev->image_stream = gdev_vector_stream((gx_device_vector *)pdev);
+ if ( pdev->LanguageLevel >= 2 && pdev->params.ASCII85EncodePages )
+ { gs_memory_t *mem = pdev->v_memory;
+ stream *prev_stream = pdev->image_stream;
+ uint buf_size = 200; /* arbitrary */
+ byte *buf = pdev->image_buf =
+ gs_alloc_bytes(mem, buf_size, "psw_set_image_stream(buf)");
+ stream *es = pdev->image_stream =
+ s_alloc(mem, "psw_set_image_stream(stream)");
+
+ if ( es == 0 || buf == 0 )
+ { return_error(gs_error_VMerror);
+ }
+ s_std_init(es, buf, buf_size, &filter_write_procs, s_mode_write);
+ es->template = &s_A85E_template;
+ es->procs.process = es->template->process;
+ es->strm = prev_stream;
+ return 1;
+ }
+ return 0;
+}
+
+/* Clean up after writing an image. */
+private void
+psw_image_cleanup(gx_device_pswrite *pdev)
+{ gs_memory_t *mem = pdev->v_memory;
+
+ if ( pdev->image_stream != 0 && pdev->image_stream != pdev->strm )
+ { sclose(pdev->image_stream);
+ gs_free_object(mem, pdev->image_stream, "psw_image_cleanup(stream)");
+ pdev->image_stream = 0;
+ }
+ if ( pdev->image_buf )
+ { gs_free_object(mem, pdev->image_buf, "psw_image_cleanup(buf)");
+ pdev->image_buf = 0;
+ }
+}
+
+/* Write data for an image. */
+/****** IGNORES data_x ******/
+private void
+psw_put_bits(stream *s, const byte *data, int data_x_bit, uint raster,
+ uint width_bits, int height)
+{ int y;
+ for ( y = 0; y < height; ++y )
+ pwrite(s, data + (data_x_bit >> 3) + y * raster,
+ (width_bits + 7) >> 3);
+}
+private int
+psw_image_write(gx_device_pswrite *pdev, const char *imagestr,
+ const byte *data, int data_x_bit, uint raster, gx_bitmap_id id,
+ uint width_bits, int height)
+{ stream *s = pdev->strm;
+ int code;
+ const char *source;
+
+ if ( image_cache_lookup(pdev, id, false) )
+ { pprintld1(s, "I%ld ", id);
+ pprints1(s, "%s\n", imagestr);
+ return 0;
+ }
+ code = psw_image_stream_setup(pdev);
+ if ( code < 0 )
+ return code;
+ source = (code ? "@85" : "@");
+ if ( id == gx_no_bitmap_id || width_bits * (ulong)height > 8000 ||
+ width_bits == 0 || height == 0
+ )
+ { pprints2(s, "%s %s\n", source, imagestr);
+ psw_put_bits(pdev->image_stream, data, data_x_bit, raster,
+ width_bits, height);
+ psw_image_cleanup(pdev);
+ spputc(s, '\n');
+ }
+ else
+ { char str[40];
+
+ image_cache_lookup(pdev, id, true);
+ sprintf(str, "/I%ld %s %ld |\n",
+ id, source, ((width_bits + 7) >> 3) * (ulong)height);
+ pputs(s, str);
+ psw_put_bits(pdev->image_stream, data, data_x_bit, raster,
+ width_bits, height);
+ psw_image_cleanup(pdev);
+ pprintld1(s, "\ndef I%ld ", id);
+ pprints1(s, "%s\n", imagestr);
+ }
+ return 0;
+}
+
+/* Print a matrix. */
+private void
+psw_put_matrix(stream *s, const gs_matrix *pmat)
+{ pprintg6(s, "[%g %g %g %g %g %g]",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+}
+
+/* ---------------- Vector device implementation ---------------- */
+
+#define pdev ((gx_device_pswrite *)vdev)
+
+private int
+psw_beginpage(gx_device_vector *vdev)
+{ stream *s = vdev->strm;
+ long page = vdev->PageCount + 1;
+
+ if ( pdev->first_page )
+ { psw_put_lines(s,
+ (pdev->ProduceEPS ? psw_eps_header : psw_ps_header));
+ if ( ftell(vdev->file) < 0 )
+ { /* File is not seekable. */
+ pdev->bbox_position = -1;
+ pputs(s, "%%BoundingBox: (atend)\n");
+ }
+ else
+ { /* File is seekable, leave room to rewrite bbox. */
+ pdev->bbox_position = stell(s);
+ pputs(s, "................................................................\n");
+ }
+ pprints1(s, "%%%%Creator: %s ", gs_product);
+ pprintld1(s, "%ld ", (long)gs_revision);
+ pprints1(s, "(%s)\n", vdev->dname);
+ { struct tm tms;
+ time_t t;
+ char date_str[25];
+
+ time(&t);
+ tms = *localtime(&t);
+ sprintf(date_str, "%d/%02d/%02d %02d:%02d:%02d",
+ tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
+ tms.tm_hour, tms.tm_min, tms.tm_sec);
+ pprints1(s, "%%%%CreationDate: %s\n", date_str);
+ }
+ if ( pdev->params.ASCII85EncodePages )
+ pputs(s, "%%DocumentData: Clean7Bit\n");
+ if ( pdev->LanguageLevel == 2.0 )
+ pputs(s, "%%LanguageLevel: 2\n");
+ else if ( pdev->LanguageLevel == 1.5 )
+ pputs(s, "%%Extensions: CMYK\n");
+ psw_put_lines(s, psw_header);
+ pprints1(s, "%% %s\n", gs_copyright);
+ psw_put_lines(s, psw_prolog);
+ if ( pdev->LanguageLevel < 1.5 )
+ psw_put_lines(s, psw_1_prolog);
+ else
+ { psw_put_lines(s, psw_1_5_prolog);
+ if ( pdev->LanguageLevel > 1.5 )
+ psw_put_lines(s, psw_2_prolog);
+ }
+ psw_put_lines(s, psw_end_prolog);
+ }
+ pprintld2(s, "%%%%Page: %ld %ld\n%%%%BeginPageSetup\n", page, page);
+ pprintg2(s, "save GS_pswrite_ProcSet begin %g %g scale\n%%%%EndPageSetup\n",
+ 72.0 / vdev->HWResolution[0], 72.0 / vdev->HWResolution[1]);
+ return 0;
+}
+
+private int
+psw_setcolors(gx_device_vector *vdev, const gx_drawing_color *pdc)
+{ /* PostScript only keeps track of a single color. */
+ vdev->fill_color = *pdc;
+ vdev->stroke_color = *pdc;
+ return psdf_setfillcolor(vdev, pdc);
+}
+
+private int
+psw_endpath(gx_device_vector *vdev, gx_path_type_t type)
+{ stream *s = vdev->strm;
+ const char *star = (type & gx_path_type_even_odd ? "*" : "");
+
+ if ( type & gx_path_type_fill )
+ { if ( type & (gx_path_type_stroke | gx_path_type_clip) )
+ pprints1(s, "q f%s Q ", star);
+ else
+ pprints1(s, "f%s\n", star);
+ }
+ if ( type & gx_path_type_stroke )
+ { if ( type & gx_path_type_clip )
+ pputs(s, "q S Q ");
+ else
+ pputs(s, "S\n");
+ }
+ if ( type & gx_path_type_clip )
+ pprints1(s, "Y%s\n", star);
+ return 0;
+}
+
+#undef pdev
+
+/* ---------------- Driver procedures ---------------- */
+
+#define vdev ((gx_device_vector *)dev)
+#define pdev ((gx_device_pswrite *)dev)
+
+/* ------ Open/close/page ------ */
+
+/* Open the device. */
+private int
+psw_open(gx_device *dev)
+{ vdev->v_memory = dev->memory; /****** WRONG ******/
+ vdev->vec_procs = &psw_vector_procs;
+ { int code = gdev_vector_open_file_bbox(vdev, 512, true);
+ if ( code < 0 )
+ return code;
+ }
+ gdev_vector_init(vdev);
+ pdev->first_page = true;
+ image_cache_reset(pdev);
+ return 0;
+}
+
+/* Wrap up ("output") a page. */
+private int
+psw_output_page(gx_device *dev, int num_copies, int flush)
+{ stream *s = gdev_vector_stream(vdev);
+ if ( num_copies != 1 )
+ pprintd1(s, "userdict /#copies %d put\n", num_copies);
+ pprints1(s, "end %s restore\n%%%%PageTrailer\n",
+ (flush ? "showpage" : "copypage"));
+ sflush(s);
+ vdev->in_page = false;
+ pdev->first_page = false;
+ gdev_vector_reset(vdev);
+ image_cache_reset(pdev);
+ return 0;
+}
+
+/* Close the device. */
+/* Note that if this is being called as a result of finalization, */
+/* the stream may no longer exist; but the file will still be open. */
+private int
+psw_close(gx_device *dev)
+{ FILE *f = vdev->file;
+
+ fprintf(f, "%%%%Trailer\n%%%%Pages: %ld\n", dev->PageCount);
+ { gs_rect bbox;
+ long save_pos;
+
+ gx_device_bbox_bbox(vdev->bbox_device, &bbox);
+ if ( pdev->bbox_position >= 0 )
+ { save_pos = ftell(f);
+ fseek(f, pdev->bbox_position, SEEK_SET);
+ }
+ fprintf(f, "%%%%BoundingBox: %d %d %d %d\n",
+ (int)floor(bbox.p.x), (int)floor(bbox.p.y),
+ (int)ceil(bbox.q.x), (int)ceil(bbox.q.y));
+ if ( pdev->bbox_position >= 0 )
+ { fputc('%', f);
+ fseek(f, save_pos, SEEK_SET);
+ }
+ }
+ if ( !pdev->ProduceEPS )
+ fputs("%%EOF\n", f);
+ gdev_vector_close_file(vdev);
+ return 0;
+}
+
+/* ---------------- Get/put parameters ---------------- */
+
+/* Get parameters. */
+private int
+psw_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gdev_psdf_get_params(dev, plist);
+ int ecode;
+
+ if ( code < 0 )
+ return code;
+ if ( (ecode = param_write_float(plist, "LanguageLevel", &pdev->LanguageLevel)) < 0 )
+ return ecode;
+ return code;
+}
+
+/* Put parameters. */
+private int
+psw_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ float ll = pdev->LanguageLevel;
+
+ switch ( code = param_read_float(plist, (param_name = "LanguageLevel"), &ll) )
+ {
+ case 0:
+ if ( ll == 1.0 || ll == 1.5 || ll == 2.0 )
+ break;
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ ;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gdev_psdf_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ pdev->LanguageLevel = ll;
+ return code;
+}
+
+/* ---------------- Images ---------------- */
+
+/* Copy a monochrome bitmap. */
+private int
+psw_copy_mono(gx_device *dev, const byte *data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ gx_drawing_color color;
+ const char *op;
+ int code = 0;
+
+ (*dev_proc(vdev->bbox_device, copy_mono))
+ ((gx_device *)vdev->bbox_device, data, data_x, raster, id,
+ x, y, w, h, zero, one);
+ if ( one == gx_no_color_index )
+ { color_set_pure(&color, zero);
+ code = gdev_vector_update_fill_color((gx_device_vector *)pdev,
+ &color);
+ op = "If";
+ }
+ else if ( zero == vdev->black && one == vdev->white )
+ op = "1 I";
+ else
+ { if ( zero != gx_no_color_index )
+ { code = (*dev_proc(dev, fill_rectangle))(dev, x, y, w, h, zero);
+ if ( code < 0 )
+ return code;
+ }
+ color_set_pure(&color, one);
+ code = gdev_vector_update_fill_color((gx_device_vector *)pdev,
+ &color);
+ op = "It";
+ }
+ if ( code < 0 )
+ return 0;
+ return (psw_image_setup(pdev, x, y, w, h) ?
+ psw_image_write(pdev, op, data, data_x, raster, id,
+ w, h) : 0);
+}
+
+/* Copy a color bitmap. */
+private int
+psw_copy_color(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int depth = dev->color_info.depth;
+
+ (*dev_proc(vdev->bbox_device, copy_color))
+ ((gx_device *)vdev->bbox_device, data, data_x, raster, id,
+ x, y, w, h);
+ if ( !psw_image_setup(pdev, x, y, w, h) )
+ return 0;
+ pprintd1(pdev->strm, " %d", depth);
+ return psw_image_write(pdev, "Ic", data, data_x * depth,
+ raster, id, w * depth, h);
+}
+
+/* Fill a mask. */
+private int
+psw_fill_mask(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ if ( depth > 1 ||
+ gdev_vector_update_fill_color(vdev, pdcolor) < 0 ||
+ gdev_vector_update_clip_path(vdev, pcpath) < 0 ||
+ gdev_vector_update_log_op(vdev, lop) < 0
+ )
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, w, h, pdcolor, depth, lop, pcpath);
+ (*dev_proc(vdev->bbox_device, fill_mask))
+ ((gx_device *)vdev->bbox_device, data, data_x, raster, id,
+ x, y, w, h, pdcolor, depth, lop, pcpath);
+ return (psw_image_setup(pdev, x, y, w, h) ?
+ psw_image_write(pdev, "It",
+ data, data_x, raster, id, w, h) : 0);
+}
+
+/* ---------------- High-level images ---------------- */
+
+/* Start processing an image. */
+private int
+psw_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, void **pinfo)
+{ gdev_vector_image_enum_t *pie =
+ gs_alloc_struct(mem, gdev_vector_image_enum_t,
+ &st_vector_image_enum, "psw_begin_image");
+ const gs_color_space *pcs = pim->ColorSpace;
+ gs_color_space_index index;
+ int num_components;
+ bool can_do = prect == 0;
+ int code;
+
+ if ( pie == 0 )
+ return_error(gs_error_VMerror);
+ pie->memory = mem;
+ *pinfo = pie;
+ if ( !pim->ImageMask )
+ { index = gs_color_space_get_index(pcs);
+ num_components = gs_color_space_num_components(pcs);
+ }
+ if ( pdev->LanguageLevel < 2 && !pim->ImageMask )
+ { /*
+ * Restrict ourselves to Level 1 images: device color spaces, [0
+ * 1] decode, bits per component <= 8, no CombineWithColor.
+ */
+ if ( pim->BitsPerComponent > 8 || pim->CombineWithColor )
+ can_do = false;
+ else
+ { int i;
+
+ switch ( index )
+ {
+ case gs_color_space_index_DeviceGray:
+ case gs_color_space_index_DeviceRGB:
+ case gs_color_space_index_DeviceCMYK:
+ for ( i = 0; i < num_components * 2; ++i )
+ if ( pim->Decode[i] != (i & 1) )
+ can_do = false;
+ break;
+ default:
+ can_do = false;
+ }
+ }
+ }
+ if ( !can_do ||
+ gdev_vector_begin_image(vdev, pis, pim, format, prect, pdcolor,
+ pcpath, mem, pie) < 0 ||
+ (code = psw_image_stream_setup(pdev)) < 0
+ )
+ return gx_default_begin_image(dev, pis, pim, format, prect,
+ pdcolor, pcpath, mem,
+ &pie->default_info);
+ /* Write the image/colorimage/imagemask preamble. */
+ { stream *s = gdev_vector_stream((gx_device_vector *)pdev);
+ const char *source = (code ? "@85" : "@");
+ gs_matrix imat;
+
+ pputs(s, "q");
+ (*dev_proc(dev, get_initial_matrix))(dev, &imat);
+ gs_matrix_scale(&imat, 72.0 / dev->HWResolution[0],
+ 72.0 / dev->HWResolution[1], &imat);
+ gs_matrix_invert(&imat, &imat);
+ gs_matrix_multiply(&ctm_only(pis), &imat, &imat);
+ psw_put_matrix(s, &imat);
+ pprintd2(s, "concat\n%d %d ", pie->width, pie->height);
+ if ( pim->ImageMask )
+ { pputs(s, (pim->Decode[0] == 0 ? "false" : "true"));
+ psw_put_matrix(s, &pim->ImageMatrix);
+ pprints1(s, "%s imagemask\n", source);
+ }
+ else
+ { pprintd1(s, "%d", pim->BitsPerComponent);
+ psw_put_matrix(s, &pim->ImageMatrix);
+ if ( index == gs_color_space_index_DeviceGray )
+ pprints1(s, "%s image\n", source);
+ else
+ { if ( format == gs_image_format_chunky )
+ pprints1(s, "%s false", source);
+ else
+ pprints2(s, "%s %strue", source,
+ "dup dup dup " + (16 - num_components * 4));
+ pprintd1(s, " %d colorimage\n", num_components);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Process the next piece of an image. */
+private int
+psw_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ gdev_vector_image_enum_t *pie = info;
+
+ if ( pie->default_info )
+ return gx_default_image_data(dev, pie->default_info, planes,
+ data_x, raster, height);
+ (*dev_proc(vdev->bbox_device, image_data))
+ ((gx_device *)vdev->bbox_device, pie->bbox_info,
+ planes, data_x, raster, height);
+ { int plane;
+ for ( plane = 0; plane < pie->num_planes; ++plane )
+ psw_put_bits(pdev->image_stream, planes[plane],
+ data_x * pie->bits_per_pixel, raster,
+ pie->bits_per_row, height);
+ }
+ return (pie->y += height) >= pie->height;
+}
+
+/* Clean up by releasing the buffers. */
+private int
+psw_end_image(gx_device *dev, void *info, bool draw_last)
+{ gdev_vector_image_enum_t *pie = info;
+ int code;
+
+ code = gdev_vector_end_image(vdev, (gdev_vector_image_enum_t *)pie,
+ draw_last, pdev->white);
+ if ( code > 0 )
+ { psw_image_cleanup(pdev);
+ pputs(pdev->strm, "\nQ\n");
+ }
+ return code;
+}
diff --git a/gs/src/gdevpsdf.c b/gs/src/gdevpsdf.c
new file mode 100644
index 000000000..b56207061
--- /dev/null
+++ b/gs/src/gdevpsdf.c
@@ -0,0 +1,613 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpsdf.c */
+/* Common output syntax and parameters for PostScript and PDF writers */
+#include "stdio_.h"
+#include "string_.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "gstypes.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gdevpsdf.h"
+#include "gdevpstr.h"
+#include "strimpl.h" /* for short-sighted compilers */
+#include "scfx.h"
+#include "slzwx.h"
+#include "srlx.h"
+
+/* Structure descriptor */
+public_st_device_psdf();
+
+/* ---------------- Get/put Distiller parameters ---------------- */
+
+typedef struct psdf_image_filter_name_s {
+ const char *pname;
+ const stream_template *template;
+} psdf_image_filter_name;
+typedef struct psdf_image_param_names_s {
+ const char *ACSDict; /* not used for mono */
+ const char *AntiAlias;
+ const char *AutoFilter; /* not used for mono */
+ const char *Depth;
+ const char *Dict;
+ const char *Downsample;
+ const char *DownsampleType;
+ const char *Encode;
+ const char *Filter;
+ const char *Resolution;
+} psdf_image_param_names;
+private const psdf_image_param_names Color_names = {
+ "ColorACSImageDict", "AntiAliasColorImages", "AutoFilterColorImages",
+ "ColorImageDepth", "ColorImageDict",
+ "DownsampleColorImages", "ColorImageDownsampleType", "EncodeColorImages",
+ "ColorImageFilter", "ColorImageResolution"
+};
+private const psdf_image_filter_name Poly_filters[] = {
+ /*{"DCTEncode", &s_DCTE_template},*/
+ {"LZWEncode", &s_LZWE_template},
+ {0, 0}
+};
+private const psdf_image_param_names Gray_names = {
+ "GrayACSImageDict", "AntiAliasGrayImages", "AutoFilterGrayImages",
+ "GrayImageDepth", "GrayImageDict",
+ "DownsampleGrayImages", "GrayImageDownsampleType", "EncodeGrayImages",
+ "GrayImageFilter", "GrayImageResolution"
+};
+private const psdf_image_param_names Mono_names = {
+ 0, "AntiAliasMonoImages", 0,
+ "MonoImageDepth", "MonoImageDict",
+ "DownsampleMonoImages", "MonoImageDownsampleType", "EncodeMonoImages",
+ "MonoImageFilter", "MonoImageResolution"
+};
+private const psdf_image_filter_name Mono_filters[] = {
+ {"CCITTFaxEncode", &s_CFE_template},
+ {"LZWEncode", &s_LZWE_template},
+ {"RunLengthEncode", &s_RLE_template},
+ {0, 0}
+};
+private const char *AutoRotatePages_names[] = {
+ "None", "All", "PageByPage", 0
+};
+private const char *ColorConversionStrategy_names[] = {
+ "LeaveColorUnchanged", "UseDeviceDependentColor",
+ "UseDeviceIndependentColor", 0
+};
+private const char *DownsampleType_names[] = {
+ "Average", "Subsample", 0
+};
+private const char *TransferFunctionInfo_names[] = {
+ "Preserve", "Apply", "Remove", 0
+};
+private const char *UCRandBGInfo_names[] = {
+ "Preserve", "Remove", 0
+};
+
+/* -------- Get parameters -------- */
+
+/* Get a set of image-related parameters. */
+private int
+psdf_get_image_params(gs_param_list *plist,
+ const psdf_image_param_names *pnames, psdf_image_params *params)
+{ int code;
+ gs_param_string dsts, fs;
+
+ param_string_from_string(dsts,
+ DownsampleType_names[params->DownsampleType]);
+ if (
+ /* ACSDict */
+ (code = param_write_bool(plist, pnames->AntiAlias,
+ &params->AntiAlias)) < 0 ||
+ (pnames->AutoFilter != 0 &&
+ (code = param_write_bool(plist, pnames->AutoFilter,
+ &params->AutoFilter)) < 0) ||
+ (code = param_write_int(plist, pnames->Depth,
+ &params->Depth)) < 0 ||
+ /* Dict */
+ (code = param_write_bool(plist, pnames->Downsample,
+ &params->Downsample)) < 0 ||
+ (code = param_write_name(plist, pnames->DownsampleType,
+ &dsts)) < 0 ||
+ (code = param_write_bool(plist, pnames->Encode,
+ &params->Encode)) < 0 ||
+ (code = (params->Filter == 0 ? 0 :
+ (param_string_from_string(fs, params->Filter),
+ param_write_name(plist, pnames->Filter, &fs)))) < 0 ||
+ (code = param_write_int(plist, pnames->Resolution,
+ &params->Resolution)) < 0
+ )
+ ;
+ return code;
+}
+
+/* Get parameters. */
+int
+gdev_psdf_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_psdf *pdev = (gx_device_psdf *)dev;
+ int code = gdev_vector_get_params(dev, plist);
+ gs_param_string arps, ccss, tfis, ucrbgis;
+
+ if ( code < 0 )
+ return code;
+ param_string_from_string(arps,
+ AutoRotatePages_names[(int)pdev->params.AutoRotatePages]);
+ param_string_from_string(ccss,
+ ColorConversionStrategy_names[(int)pdev->params.ColorConversionStrategy]);
+ param_string_from_string(tfis,
+ TransferFunctionInfo_names[(int)pdev->params.TransferFunctionInfo]);
+ param_string_from_string(ucrbgis,
+ UCRandBGInfo_names[(int)pdev->params.UCRandBGInfo]);
+ if (
+ /* General parameters */
+
+ (code = param_write_bool(plist, "ASCII85EncodePages",
+ &pdev->params.ASCII85EncodePages)) < 0 ||
+ (code = param_write_name(plist, "AutoRotatePages",
+ &arps)) < 0 ||
+ (code = param_write_bool(plist, "CompressPages",
+ &pdev->params.CompressPages)) < 0 ||
+ (code = param_write_long(plist, "ImageMemory",
+ &pdev->params.ImageMemory)) < 0 ||
+ (code = param_write_bool(plist, "LZWEncodePages",
+ &pdev->params.LZWEncodePages)) < 0 ||
+ (code = param_write_bool(plist, "PreserveHalftoneInfo",
+ &pdev->params.PreserveHalftoneInfo)) < 0 ||
+ (code = param_write_bool(plist, "PreserveOPIComments",
+ &pdev->params.PreserveOPIComments)) < 0 ||
+ (code = param_write_bool(plist, "PreserveOverprintSettings",
+ &pdev->params.PreserveOverprintSettings)) < 0 ||
+ (code = param_write_name(plist, "TransferFunctionInfo", &tfis)) < 0 ||
+ (code = param_write_name(plist, "UCRandBGInfo", &ucrbgis)) < 0 ||
+ (code = param_write_bool(plist, "UseFlateCompression",
+ &pdev->params.UseFlateCompression)) < 0 ||
+
+ /* Color sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Color_names, &pdev->params.ColorImage)) < 0 ||
+ (code = param_write_name(plist, "ColorConversionStrategy",
+ &ccss)) < 0 ||
+ (code = param_write_bool(plist, "ConvertCMYKImagesToRGB",
+ &pdev->params.ConvertCMYKImagesToRGB)) < 0 ||
+ (code = param_write_bool(plist, "ConvertImagesToIndexed",
+ &pdev->params.ConvertImagesToIndexed)) < 0 ||
+
+ /* Gray sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Gray_names, &pdev->params.GrayImage)) < 0 ||
+
+ /* Mono sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Mono_names, &pdev->params.MonoImage)) < 0 ||
+
+ /* Font embedding parameters */
+
+ (code = param_write_name_array(plist, "AlwaysEmbed", &pdev->params.AlwaysEmbed)) < 0 ||
+ (code = param_write_name_array(plist, "NeverEmbed", &pdev->params.NeverEmbed)) < 0 ||
+ (code = param_write_bool(plist, "EmbedAllFonts", &pdev->params.EmbedAllFonts)) < 0 ||
+ (code = param_write_bool(plist, "SubsetFonts", &pdev->params.SubsetFonts)) < 0 ||
+ (code = param_write_int(plist, "MaxSubsetPct", &pdev->params.MaxSubsetPct)) < 0
+ )
+ ;
+ return code;
+}
+
+/* -------- Put parameters -------- */
+
+/* Compare a C string and a gs_param_string. */
+bool
+psdf_key_eq(const gs_param_string *pcs, const char *str)
+{ return (strlen(str) == pcs->size &&
+ !strncmp(str, (const char *)pcs->data, pcs->size));
+}
+
+/* Get an enumerated value. */
+private int
+psdf_put_enum_param(gs_param_list *plist, gs_param_name param_name, int *pvalue,
+ const char **pnames, int ecode)
+{ gs_param_string ens;
+ int code = param_read_name(plist, param_name, &ens);
+
+ switch ( code )
+ {
+ case 1:
+ return ecode;
+ case 0:
+ { int i;
+ for ( i = 0; pnames[i] != 0; ++i )
+ if ( psdf_key_eq(&ens, pnames[i]) )
+ { *pvalue = i;
+ return 0;
+ }
+ }
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, code);
+ }
+ return code;
+}
+
+/* Put a Boolean or integer parameter. */
+int
+psdf_put_bool_param(gs_param_list *plist, gs_param_name param_name,
+ bool *pval, int ecode)
+{ int code;
+
+ switch ( code = param_read_bool(plist, param_name, pval) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+int
+psdf_put_int_param(gs_param_list *plist, gs_param_name param_name,
+ int *pval, int ecode)
+{ int code;
+
+ switch ( code = param_read_int(plist, param_name, pval) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* Put [~](Always|Never)Embed parameters. */
+private int
+psdf_put_embed_param(gs_param_list *plist, gs_param_name notpname,
+ gs_param_string_array *psa, int ecode)
+{ gs_param_name pname = notpname + 1;
+ int code;
+ gs_param_string_array nsa;
+
+ /***** Storage management is incomplete ******/
+ /***** Doesn't do incremental add/delete ******/
+ switch ( code = param_read_name_array(plist, pname, psa) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, pname, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ switch ( code = param_read_name_array(plist, notpname, &nsa) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, notpname, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* Put a set of image-related parameters. */
+private int
+psdf_put_image_params(gs_param_list *plist, const psdf_image_param_names *pnames,
+ const psdf_image_filter_name *pifn, psdf_image_params *params, int ecode)
+{ gs_param_string fs;
+ int dsti = params->DownsampleType;
+ int code;
+
+ if ( pnames->ACSDict )
+ { /* ACSDict */
+ }
+ ecode = psdf_put_bool_param(plist, pnames->AntiAlias,
+ &params->AntiAlias, ecode);
+ if ( pnames->AutoFilter )
+ ecode = psdf_put_bool_param(plist, pnames->AutoFilter,
+ &params->AutoFilter, ecode);
+ ecode = psdf_put_int_param(plist, pnames->Depth,
+ &params->Depth, ecode);
+ /* Dict */
+ ecode = psdf_put_bool_param(plist, pnames->Downsample,
+ &params->Downsample, ecode);
+ if ( (ecode = psdf_put_enum_param(plist, pnames->DownsampleType,
+ &dsti, DownsampleType_names,
+ ecode)) >= 0
+ )
+ params->DownsampleType = (enum psdf_downsample_type)dsti;
+ ecode = psdf_put_bool_param(plist, pnames->Encode,
+ &params->Encode, ecode);
+ switch ( code = param_read_string(plist, pnames->Filter, &fs) )
+ {
+ case 0:
+ { const psdf_image_filter_name *pn = pifn;
+ while ( pn->pname != 0 && !psdf_key_eq(&fs, pn->pname) )
+ pn++;
+ if ( pn->pname == 0 )
+ { ecode = gs_error_rangecheck;
+ goto ipe;
+ }
+ params->Filter = pn->pname;
+ params->filter_template = pn->template;
+ break;
+ }
+ default:
+ ecode = code;
+ipe: param_signal_error(plist, pnames->Filter, ecode);
+ case 1:
+ break;
+ }
+ ecode = psdf_put_int_param(plist, pnames->Resolution,
+ &params->Resolution, ecode);
+ if ( ecode >= 0 )
+ { /* Force parameters to acceptable values. */
+ if ( params->Resolution < 1 )
+ params->Resolution = 1;
+ switch ( params->Depth )
+ {
+ default:
+ params->Depth = -1;
+ case 1: case 2: case 4: case 8:
+ case -1:
+ break;
+ }
+ }
+ return ecode;
+}
+
+/* Put parameters. */
+int
+gdev_psdf_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_psdf *pdev = (gx_device_psdf *)dev;
+ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ psdf_distiller_params params;
+
+ /* General parameters. */
+
+ params = pdev->params;
+
+ ecode = psdf_put_bool_param(plist, "ASCII85EncodePages",
+ &params.ASCII85EncodePages, ecode);
+ { int arpi = params.AutoRotatePages;
+ ecode = psdf_put_enum_param(plist, "AutoRotatePages", &arpi,
+ AutoRotatePages_names, ecode);
+ params.AutoRotatePages = (enum psdf_auto_rotate_pages)arpi;
+ }
+ ecode = psdf_put_bool_param(plist, "CompressPages",
+ &params.CompressPages, ecode);
+ switch ( code = param_read_long(plist, (param_name = "ImageMemory"), &params.ImageMemory) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ ecode = psdf_put_bool_param(plist, "LZWEncodePages",
+ &params.LZWEncodePages, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveHalftoneInfo",
+ &params.PreserveHalftoneInfo, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOPIComments",
+ &params.PreserveOPIComments, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOverprintSettings",
+ &params.PreserveOverprintSettings, ecode);
+ { int tfii = params.TransferFunctionInfo;
+ ecode = psdf_put_enum_param(plist, "TransferFunctionInfo", &tfii,
+ TransferFunctionInfo_names, ecode);
+ params.TransferFunctionInfo = (enum psdf_transfer_function_info)tfii;
+ }
+ { int ucrbgi = params.UCRandBGInfo;
+ ecode = psdf_put_enum_param(plist, "UCRandBGInfo", &ucrbgi,
+ UCRandBGInfo_names, ecode);
+ params.UCRandBGInfo = (enum psdf_ucr_and_bg_info)ucrbgi;
+ }
+ ecode = psdf_put_bool_param(plist, "UseFlateCompression",
+ &params.UseFlateCompression, ecode);
+
+ /* Color sampled image parameters */
+
+ ecode = psdf_put_image_params(plist, &Color_names, Poly_filters,
+ &params.ColorImage, ecode);
+ { int ccsi = params.ColorConversionStrategy;
+ ecode = psdf_put_enum_param(plist, "ColorConversionStrategy", &ccsi,
+ ColorConversionStrategy_names, ecode);
+ params.ColorConversionStrategy =
+ (enum psdf_color_conversion_strategy)ccsi;
+ }
+ ecode = psdf_put_bool_param(plist, "ConvertCMYKImagesToRGB",
+ &params.ConvertCMYKImagesToRGB, ecode);
+ ecode = psdf_put_bool_param(plist, "ConvertImagesToIndexed",
+ &params.ConvertImagesToIndexed, ecode);
+
+ /* Gray sampled image parameters */
+
+ ecode = psdf_put_image_params(plist, &Gray_names, Poly_filters,
+ &params.GrayImage, ecode);
+
+ /* Mono sampled image parameters */
+
+ ecode = psdf_put_image_params(plist, &Mono_names, Mono_filters,
+ &params.MonoImage, ecode);
+
+ /* Font embedding parameters */
+
+ ecode = psdf_put_embed_param(plist, "~AlwaysEmbed",
+ &params.AlwaysEmbed, ecode);
+ ecode = psdf_put_embed_param(plist, "~NeverEmbed",
+ &params.NeverEmbed, ecode);
+ ecode = psdf_put_bool_param(plist, "EmbedAllFonts",
+ &params.EmbedAllFonts, ecode);
+ ecode = psdf_put_bool_param(plist, "SubsetFonts",
+ &params.SubsetFonts, ecode);
+ ecode = psdf_put_int_param(plist, "MaxSubsetPct",
+ &params.MaxSubsetPct, ecode);
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gdev_vector_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ pdev->params = params; /* OK to update now */
+ return 0;
+}
+
+/* ---------------- Utilities ---------------- */
+
+int
+psdf_set_color(gx_device_vector *vdev, const gx_drawing_color *pdc,
+ const char *rgs)
+{ if ( !gx_dc_is_pure(pdc) )
+ return_error(gs_error_rangecheck);
+ { stream *s = gdev_vector_stream(vdev);
+ gx_color_index color = gx_dc_pure_color(pdc);
+ float r = (color >> 16) / 255.0;
+ float g = ((color >> 8) & 0xff) / 255.0;
+ float b = (color & 0xff) / 255.0;
+
+ if ( r == g && g == b )
+ pprintg1(s, "%g", r), pprints1(s, " %s\n", rgs + 1);
+ else
+ pprintg3(s, "%g %g %g", r, g, b), pprints1(s, " %s\n", rgs);
+ }
+ return 0;
+}
+
+/* ---------------- Vector implementation procedures ---------------- */
+
+int
+psdf_setlinewidth(gx_device_vector *vdev, floatp width)
+{ pprintg1(gdev_vector_stream(vdev), "%g w\n", width);
+ return 0;
+}
+
+int
+psdf_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
+{ pprintd1(gdev_vector_stream(vdev), "%d J\n", cap);
+ return 0;
+}
+
+int
+psdf_setlinejoin(gx_device_vector *vdev, gs_line_join join)
+{ pprintd1(gdev_vector_stream(vdev), "%d j\n", join);
+ return 0;
+}
+
+int
+psdf_setmiterlimit(gx_device_vector *vdev, floatp limit)
+{ pprintg1(gdev_vector_stream(vdev), "%g M\n", limit);
+ return 0;
+}
+
+int
+psdf_setdash(gx_device_vector *vdev, const float *pattern, uint count,
+ floatp offset)
+{ stream *s = gdev_vector_stream(vdev);
+ int i;
+
+ pputs(s, "[ ");
+ for ( i = 0; i < count; ++i )
+ pprintg1(s, "%g ", pattern[i]);
+ pprintg1(s, "] %g d\n", offset);
+ return 0;
+}
+
+int
+psdf_setflat(gx_device_vector *vdev, floatp flatness)
+{ pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness);
+ return 0;
+}
+
+int
+psdf_setlogop(gx_device_vector *vdev, gs_logical_operation_t lop,
+ gs_logical_operation_t diff)
+{ /****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/
+ return 0;
+}
+
+int
+psdf_setfillcolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
+{ return psdf_set_color(vdev, pdc, "rg");
+}
+
+int
+psdf_setstrokecolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
+{ return psdf_set_color(vdev, pdc, "RG");
+}
+
+int
+psdf_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1, fixed y1,
+ gx_path_type_t type)
+{ int code = (*vdev_proc(vdev, beginpath))(vdev, type);
+ if ( code < 0 )
+ return code;
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n",
+ fixed2float(x0), fixed2float(y0),
+ fixed2float(x1 - x0), fixed2float(y1 - y0));
+ return (*vdev_proc(vdev, endpath))(vdev, type);
+}
+
+int
+psdf_beginpath(gx_device_vector *vdev, gx_path_type_t type)
+{ return 0;
+}
+
+int
+psdf_moveto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y,
+ bool first)
+{ pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y);
+ return 0;
+}
+
+int
+psdf_lineto(gx_device_vector *vdev, floatp xy, floatp y0, floatp x, floatp y)
+{ pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y);
+ return 0;
+}
+
+int
+psdf_curveto(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
+{ if ( x1 == x0 && y1 == y0 )
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n",
+ x2, y2, x3, y3);
+ else if ( x3 == x2 && y3 == y2 )
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n",
+ x1, y1, x2, y2);
+ else
+ pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n",
+ x1, y1, x2, y2, x3, y3);
+ return 0;
+}
+
+int
+psdf_closepath(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x_start, floatp y_start)
+{ pputs(gdev_vector_stream(vdev), "h\n");
+ return 0;
+}
+
+/* endpath is deliberately omitted. */
diff --git a/gs/src/gdevpsdf.h b/gs/src/gdevpsdf.h
new file mode 100644
index 000000000..bdb1ca2af
--- /dev/null
+++ b/gs/src/gdevpsdf.h
@@ -0,0 +1,191 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpsdf.h */
+/* Common output syntax and parameters for PostScript and PDF writers */
+#include "gdevvec.h"
+/* We shouldn't need the following, but some picky compilers don't allow */
+/* externs for undefined structure types. */
+#include "strimpl.h"
+
+/* ---------------- Distiller parameters ---------------- */
+
+/* Parameters for controlling distillation of images. */
+typedef struct psdf_image_params_s {
+ /* ACSDict */
+ bool AntiAlias;
+ bool AutoFilter;
+ int Depth;
+ /* Dict */
+ bool Downsample;
+ enum psdf_downsample_type {
+ ds_Average,
+ ds_Subsample
+ } DownsampleType;
+ bool Encode;
+ const char *Filter;
+ int Resolution;
+ const stream_template *filter_template;
+} psdf_image_params;
+#define psdf_image_param_defaults(f, ft)\
+ /*ACSDict,*/ 0/*false*/, 0/*false*/, -1, /*Dict,*/ 0/*false*/,\
+ ds_Subsample, 1/*true*/, f, 72, ft
+
+/* Declare templates for default image compression filters. */
+extern const stream_template s_CFE_template;
+
+/* Complete distiller parameters. */
+typedef struct psdf_distiller_params_s {
+
+ /* General parameters */
+
+ bool ASCII85EncodePages;
+ enum psdf_auto_rotate_pages {
+ arp_None,
+ arp_All,
+ arp_PageByPage
+ } AutoRotatePages;
+ bool CompressPages;
+ long ImageMemory;
+ bool LZWEncodePages;
+ bool PreserveHalftoneInfo;
+ bool PreserveOPIComments;
+ bool PreserveOverprintSettings;
+ enum psdf_transfer_function_info {
+ tfi_Preserve,
+ tfi_Apply,
+ tfi_Remove
+ } TransferFunctionInfo;
+ enum psdf_ucr_and_bg_info {
+ ucrbg_Preserve,
+ ucrbg_Remove
+ } UCRandBGInfo;
+ bool UseFlateCompression;
+#define psdf_general_param_defaults(ascii)\
+ ascii, arp_None, 1/*true*/, 250000, 0/*false*/,\
+ 0/*false*/, 0/*false*/, 0/*false*/, tfi_Apply, ucrbg_Remove, 1/*true*/
+
+ /* Color sampled image parameters */
+
+ psdf_image_params ColorImage;
+ enum psdf_color_conversion_strategy {
+ ccs_LeaveColorUnchanged,
+ ccs_UseDeviceDependentColor,
+ ccs_UseDeviceIndependentColor
+ } ColorConversionStrategy;
+ bool ConvertCMYKImagesToRGB;
+ bool ConvertImagesToIndexed;
+#define psdf_color_image_param_defaults\
+ { psdf_image_param_defaults(0, 0) },\
+ ccs_LeaveColorUnchanged, 1/*true*/, 0/*false*/
+
+ /* Grayscale sampled image parameters */
+
+ psdf_image_params GrayImage;
+#define psdf_gray_image_param_defaults\
+ { psdf_image_param_defaults(0, 0) }
+
+ /* Monochrome sampled image parameters */
+
+ psdf_image_params MonoImage;
+#define psdf_mono_image_param_defaults\
+ { psdf_image_param_defaults("CCITTFaxEncode", &s_CFE_template) }
+
+ /* Font embedding parameters */
+
+ gs_param_string_array AlwaysEmbed;
+ gs_param_string_array NeverEmbed;
+ bool EmbedAllFonts;
+ bool SubsetFonts;
+ int MaxSubsetPct;
+#define psdf_font_param_defaults\
+ { 0, 0, 1/*true*/ }, { 0, 0, 1/*true*/ },\
+ 1/*true*/, 1/*true*/, 20
+
+} psdf_distiller_params;
+
+/* Define the extended device structure. */
+#define gx_device_psdf_common\
+ gx_device_vector_common;\
+ psdf_distiller_params params
+typedef struct gx_device_psdf_s {
+ gx_device_psdf_common;
+} gx_device_psdf;
+#define psdf_initial_values(ascii)\
+ vector_initial_values,\
+ { psdf_general_param_defaults(ascii),\
+ psdf_color_image_param_defaults,\
+ psdf_gray_image_param_defaults,\
+ psdf_mono_image_param_defaults,\
+ psdf_font_param_defaults\
+ }
+
+/* st_device_psdf is never instantiated per se, but we still need to */
+/* extern its descriptor for the sake of subclasses. */
+extern_st(st_device_psdf);
+#define public_st_device_psdf() /* in gdevpsdf.c */\
+ gs_public_st_suffix_add0_final(st_device_psdf, gx_device_psdf,\
+ "gx_device_psdf", device_psdf_enum_ptrs,\
+ device_psdf_reloc_ptrs, gx_device_finalize, st_device_vector)
+#define st_device_psdf_max_ptrs (st_device_vector_max_ptrs)
+
+/* Get/put parameters. */
+dev_proc_get_params(gdev_psdf_get_params);
+dev_proc_put_params(gdev_psdf_put_params);
+
+/* Put a Boolean or integer parameter. */
+int psdf_put_bool_param(P4(gs_param_list *plist, gs_param_name param_name,
+ bool *pval, int ecode));
+int psdf_put_int_param(P4(gs_param_list *plist, gs_param_name param_name,
+ int *pval, int ecode));
+
+/* ---------------- Vector implementation procedures ---------------- */
+
+ /* Imager state */
+int psdf_setlinewidth(P2(gx_device_vector *vdev, floatp width));
+int psdf_setlinecap(P2(gx_device_vector *vdev, gs_line_cap cap));
+int psdf_setlinejoin(P2(gx_device_vector *vdev, gs_line_join join));
+int psdf_setmiterlimit(P2(gx_device_vector *vdev, floatp limit));
+int psdf_setdash(P4(gx_device_vector *vdev, const float *pattern,
+ uint count, floatp offset));
+int psdf_setflat(P2(gx_device_vector *vdev, floatp flatness));
+int psdf_setlogop(P3(gx_device_vector *vdev, gs_logical_operation_t lop,
+ gs_logical_operation_t diff));
+ /* Other state */
+int psdf_setfillcolor(P2(gx_device_vector *vdev, const gx_drawing_color *pdc));
+int psdf_setstrokecolor(P2(gx_device_vector *vdev, const gx_drawing_color *pdc));
+ /* Paths */
+#define psdf_dopath gdev_vector_dopath
+int psdf_dorect(P6(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
+ fixed y1, gx_path_type_t type));
+int psdf_beginpath(P2(gx_device_vector *vdev, gx_path_type_t type));
+int psdf_moveto(P6(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x, floatp y, bool first));
+int psdf_lineto(P5(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x, floatp y));
+int psdf_curveto(P9(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x1, floatp y1, floatp x2,
+ floatp y2, floatp x3, floatp y3));
+int psdf_closepath(P5(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x_start, floatp y_start));
+
+/* ---------------- Other procedures ---------------- */
+
+/* Set the fill or stroke color. rgs is "rg" or "RG". */
+int psdf_set_color(P3(gx_device_vector *vdev, const gx_drawing_color *pdc,
+ const char *rgs));
diff --git a/gs/src/gdevpsim.c b/gs/src/gdevpsim.c
new file mode 100644
index 000000000..84079af8c
--- /dev/null
+++ b/gs/src/gdevpsim.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpsim.c */
+/* PostScript image output device */
+#include "gdevprn.h"
+
+/*
+ * This driver does what the ps2image utility used to do:
+ * It produces a bitmap in the form of a PostScript file that can be
+ * fed to any PostScript printer. It uses a run-length compression
+ * method that executes quickly (unlike some produced by PostScript
+ * drivers!).
+ *
+ * There are two drivers here, one for 1-bit black-and-white and one
+ * for 8-bit gray. In fact, the same code could also handles 2- and
+ * 4-bit gray output.
+ */
+
+/* Define the device parameters. */
+#ifndef X_DPI
+# define X_DPI 300
+#endif
+#ifndef Y_DPI
+# define Y_DPI 300
+#endif
+
+/* The device descriptor */
+private dev_proc_print_page(psmono_print_page);
+
+gx_device_printer far_data gs_psmono_device =
+ prn_device(prn_std_procs, "psmono",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins */
+ 1, psmono_print_page);
+
+private const gx_device_procs psgray_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
+
+gx_device_printer far_data gs_psgray_device = {
+ prn_device_body(gx_device_printer, psgray_procs, "psgray",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins */
+ 1, 8, 255, 0, 256, 1, psmono_print_page)
+};
+
+/*
+ * The following setup code gets written to the PostScript file.
+ * We would have to break it up anyway because the Watcom compiler has
+ * a limit of 512 characters in a single token, so we make a virtue out of
+ * necessity and make each line a separate string.
+ */
+private const char far_data *psmono_setup[] = {
+"%!PS",
+" /maxrep 255 def % max repeat count",
+" % Initialize the strings for filling runs (lazily).",
+" /.ImageFill",
+" { maxrep string dup 0 1 maxrep 1 sub { 3 index put dup } for",
+" .ImageFills 4 2 roll put",
+" } bind def",
+" /.ImageFills [ 0 1 255 {",
+" /.ImageFill cvx 2 array astore cvx",
+" } for ] def",
+" % Initialize the procedure table for input dispatching.",
+" /.ImageProcs [",
+" % Stack: <buffer> <file> <xdigits> <previous> <byte>",
+" 32 { { pop .ImageItem } } repeat",
+" 16 { { % 0x20-0x2f: (N-0x20) data bytes follow",
+" 32 sub 3 -1 roll add 3 index exch 0 exch getinterval 2 index exch",
+" readhexstring pop exch pop 0 exch dup",
+" } bind } repeat",
+" 16 { { % 0x30-0x3f: prefix hex digit (N-0x30) to next count",
+" 48 sub 3 -1 roll add 4 bitshift exch .ImageItem",
+" } bind } repeat",
+" 32 { { % 0x40-0x5f: repeat last data byte (N-0x40) times",
+" 64 sub 3 -1 roll add .ImageFills 2 index dup length 1 sub get get exec",
+" exch 0 exch getinterval 0 3 1 roll",
+" } bind } repeat",
+" 160 { { pop .ImageItem } } repeat",
+" ] readonly def",
+" % Read one item from a compressed image.",
+" % Stack contents: <buffer> <file> <xdigits> <previous>",
+" /.ImageItem",
+" { 2 index read pop dup .ImageProcs exch get exec",
+" } bind def",
+" % Read and print an entire compressed image.",
+" /.ImageRead % <xres> <yres> <width> <height> <bpc> .ImageRead -",
+" { gsave [",
+ /* Stack: xres yres width height bpc -mark- */
+" 6 -2 roll exch 72 div 0 0 4 -1 roll -72 div 0 7 index",
+ /* Stack: width height bpc -mark- xres/72 0 0 -yres/72 0 height */
+" ] { .ImageItem }",
+ /* Stack: width height bpc <matrix> <proc> */
+" 4 index 3 index mul 7 add 8 idiv string currentfile 0 ()",
+ /* Stack: width height bpc <matrix> <proc> <buffer> <file> 0 () */
+" 9 4 roll",
+ /* Stack: <buffer> <file> 0 () width height bpc <matrix> <proc> */
+" image pop pop pop pop",
+" grestore showpage",
+" } def"
+};
+
+#define data_run_code 0x20
+#define xdigit_code 0x30
+#define max_data_per_line 35
+#define repeat_run_code 0x40
+#define max_repeat_run_code 31
+#define max_repeat_run 255
+
+/* Send the page to the printer. */
+private void write_data_run(P4(const byte *, int, FILE *, byte));
+private int
+psmono_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int lnum;
+ byte *line = (byte *)gs_malloc(line_size, 1, "psmono_print_page");
+ byte invert = (pdev->color_info.depth == 1 ? 0xff : 0);
+
+ if ( line == 0 )
+ return_error(gs_error_VMerror);
+
+ /* If this is the first page of the file, */
+ /* write the setup code. */
+ if ( gdev_prn_file_is_new(pdev) )
+ { int i;
+ for ( i = 0; i < countof(psmono_setup); i++ )
+ fprintf(prn_stream, "%s\r\n", psmono_setup[i]);
+ }
+
+ /* Write the .ImageRead command. */
+ fprintf(prn_stream,
+ "%g %g %d %d %d .ImageRead\r\n",
+ pdev->HWResolution[0], pdev->HWResolution[1],
+ pdev->width, pdev->height, pdev->color_info.depth);
+
+ /* Compress each scan line in turn. */
+ for ( lnum = 0; lnum < pdev->height; lnum++ )
+ { const byte *p;
+ int left = line_size;
+ byte *data;
+ gdev_prn_get_bits(pdev, lnum, line, &data);
+ p = data;
+ /* Loop invariant: p + left = data + line_size. */
+#define min_repeat_run 10
+ while ( left >= min_repeat_run )
+ { /* Detect a maximal run of non-repeated data. */
+ const byte *p1 = p;
+ int left1 = left;
+ byte b;
+ int count, count_left;
+
+ while ( left1 >= min_repeat_run &&
+ ((b = *p1) != p1[1] ||
+ b != p1[2] || b != p1[3] || b != p1[4] ||
+ b != p1[5] || b != p1[6] || b != p1[7] ||
+ b != p1[8] || b != p1[9])
+ )
+ ++p1, --left1;
+ if ( left1 < min_repeat_run )
+ break; /* no repeated data left */
+ write_data_run(p, (int)(p1 - p + 1), prn_stream,
+ invert);
+ /* Detect a maximal run of repeated data. */
+ p = ++p1 + (min_repeat_run - 1);
+ left = --left1 - (min_repeat_run - 1);
+ while ( left > 0 && *p == b )
+ ++p, --left;
+ for ( count = p - p1; count > 0;
+ count -= count_left
+ )
+ { count_left = min(count, max_repeat_run);
+ if ( count_left > max_repeat_run_code )
+ fputc(xdigit_code + (count_left >> 4),
+ prn_stream),
+ fputc(repeat_run_code + (count_left & 0xf),
+ prn_stream);
+ else
+ putc(repeat_run_code + count_left,
+ prn_stream);
+ }
+ }
+ /* Write the remaining data, if any. */
+ write_data_run(p, left, prn_stream, invert);
+ }
+
+ /* Clean up and return. */
+ fputs("\r\n", prn_stream);
+ gs_free((char *)line, line_size, 1, "psmono_print_page");
+ return 0;
+}
+
+/* Write a run of data on the file. */
+private void
+write_data_run(const byte *data, int count, FILE *f, byte invert)
+{ register const byte *p = data;
+ register const char _ds *hex_digits = "0123456789abcdef";
+ int left = count;
+ char line[sizeof(count) * 2 + max_data_per_line * 2 + 3];
+ char *q = line;
+
+ /* Write the count. */
+
+ if ( !count )
+ return;
+ { int shift = sizeof(count) * 8;
+ while ( (shift -= 4) > 0 && (count >> shift) == 0 ) ;
+ for ( ; shift > 0; shift -= 4 )
+ *q++ = xdigit_code + ((count >> shift) & 0xf);
+ *q++ = data_run_code + (count & 0xf);
+ }
+
+ /* Write the data. */
+
+ while ( left > 0 )
+ { register int wcount = min(left, max_data_per_line);
+ left -= wcount;
+ for ( ; wcount > 0; ++p, --wcount )
+ { byte b = *p ^ invert;
+ *q++ = hex_digits[b >> 4];
+ *q++ = hex_digits[b & 0xf];
+ }
+ *q++ = '\r';
+ *q++ = '\n';
+ fwrite(line, 1, q - line, f);
+ q = line;
+ }
+
+}
diff --git a/gs/src/gdevpstr.c b/gs/src/gdevpstr.c
new file mode 100644
index 000000000..6d4ccf431
--- /dev/null
+++ b/gs/src/gdevpstr.c
@@ -0,0 +1,143 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpstr.c */
+/* Stream output for PostScript- and PDF-writing drivers */
+#include "math_.h" /* for fabs */
+#include "stdio_.h" /* for stream.h */
+#include "string_.h" /* for strchr */
+#include "gdevpstr.h"
+#include "stream.h"
+
+/* ------ Output ------ */
+
+/* Put a byte array on a stream. */
+int
+pwrite(stream *s, const void *ptr, uint count)
+{ uint used;
+
+ sputs(s, (const byte *)ptr, count, &used);
+ return (int)used;
+}
+
+/* Put a string on a stream. */
+int
+pputs(stream *s, const char *str)
+{ uint len = strlen(str);
+ uint used;
+ int status = sputs(s, (const byte *)str, len, &used);
+
+ return (status >= 0 && used == len ? 0 : EOF);
+}
+
+/* Print a format string up to the first variable substitution. */
+/* Return a pointer to the %, or to the terminating 0 if no % found. */
+private const char *
+pprintf_scan(stream *s, const char *format)
+{ const char *fp = format;
+
+ for ( ; *fp != 0; ++fp )
+ { if ( *fp == '%' )
+ { if ( fp[1] != '%' )
+ break;
+ ++fp;
+ }
+ sputc(s, *fp);
+ }
+ return fp;
+}
+
+/* Print (an) int value(s) using a format. */
+const char *
+pprintd1(stream *s, const char *format, int v)
+{ const char *fp = pprintf_scan(s, format);
+ char str[25];
+
+#ifdef DEBUG
+ if ( *fp == 0 || fp[1] != 'd') /* shouldn't happen! */
+ lprintf1("Bad format in pprintd1: %s\n", format);
+#endif
+ sprintf(str, "%d", v);
+ pputs(s, str);
+ return pprintf_scan(s, fp + 2);
+}
+const char *
+pprintd2(stream *s, const char *format, int v1, int v2)
+{ return pprintd1(s, pprintd1(s, format, v1), v2);
+}
+
+/* Print (a) floating point number(s) using a format. */
+/* See gdevpdfx.h for why this is needed. */
+const char *
+pprintg1(stream *s, const char *format, floatp v)
+{ const char *fp = pprintf_scan(s, format);
+ char str[50];
+
+#ifdef DEBUG
+ if ( *fp == 0 || fp[1] != 'g' ) /* shouldn't happen! */
+ lprintf1("Bad format in pprintg: %s\n", format);
+#endif
+ sprintf(str, "%g", v);
+ if ( strchr(str, 'e') )
+ { /* Bad news. Try again using f-format. */
+ sprintf(str, (fabs(v) > 1 ? "%1.1f" : "%1.8f"), v);
+ }
+ pputs(s, str);
+ return pprintf_scan(s, fp + 2);
+}
+const char *
+pprintg2(stream *s, const char *format, floatp v1, floatp v2)
+{ return pprintg1(s, pprintg1(s, format, v1), v2);
+}
+const char *
+pprintg4(stream *s, const char *format, floatp v1, floatp v2, floatp v3,
+ floatp v4)
+{ return pprintg2(s, pprintg2(s, format, v1, v2), v3, v4);
+}
+
+/* Print a long value using a format. */
+const char *
+pprintld1(stream *s, const char *format, long v)
+{ const char *fp = pprintf_scan(s, format);
+ char str[25];
+
+#ifdef DEBUG
+ if ( *fp == 0 || fp[1] != 'l' || fp[2] != 'd') /* shouldn't happen! */
+ lprintf1("Bad format in pprintld: %s\n", format);
+#endif
+ sprintf(str, "%ld", v);
+ pputs(s, str);
+ return pprintf_scan(s, fp + 3);
+}
+
+/* Print (a) string(s) using a format. */
+const char *
+pprints1(stream *s, const char *format, const char *str)
+{ const char *fp = pprintf_scan(s, format);
+
+#ifdef DEBUG
+ if ( *fp == 0 || fp[1] != 's' ) /* shouldn't happen! */
+ lprintf1("Bad format in pprints: %s\n", format);
+#endif
+ pputs(s, str);
+ return pprintf_scan(s, fp + 2);
+}
+const char *
+pprints2(stream *s, const char *format, const char *str1, const char *str2)
+{ return pprints1(s, pprints1(s, format, str1), str2);
+}
diff --git a/gs/src/gdevpstr.h b/gs/src/gdevpstr.h
new file mode 100644
index 000000000..74cb18e12
--- /dev/null
+++ b/gs/src/gdevpstr.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpstr.h */
+/* Stream output for PostScript- and PDF-writing drivers. */
+
+/* Define an opaque type for streams. */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+#endif
+
+/* Put a character on a stream. */
+#define pputc(s, c) spputc(s, c)
+
+/* Put a byte array on a stream. */
+int pwrite(P3(stream *s, const void *ptr, uint count));
+
+/* Put a string on a stream. */
+int pputs(P2(stream *s, const char *str));
+
+/*
+ * Print (a) floating point number(s) using a format. This is needed
+ * because %f format always prints a fixed number of digits after the
+ * decimal point, and %g format may use %e format, which PDF disallows.
+ * These functions return a pointer to the next %-element of the format, or
+ * to the terminating 0.
+ */
+const char *pprintg1(P3(stream *s, const char *format, floatp v));
+const char *pprintg2(P4(stream *s, const char *format, floatp v1, floatp v2));
+#define pprintg3(s, format, v1, v2, v3)\
+ pprintg2(s, pprintg1(s, format, v1), v2, v3)
+const char *pprintg4(P6(stream *s, const char *format, floatp v1, floatp v2,
+ floatp v3, floatp v4));
+#define pprintg6(s, format, v1, v2, v3, v4, v5, v6)\
+ pprintg2(s, pprintg4(s, format, v1, v2, v3, v4), v5, v6)
+
+/* Print (an) int value(s) using a format. */
+const char *pprintd1(P3(stream *s, const char *format, int v));
+const char *pprintd2(P4(stream *s, const char *format, int v1, int v2));
+#define pprintd3(s, format, v1, v2, v3)\
+ pprintd1(s, pprintd2(s, format, v1, v2), v3)
+#define pprintd4(s, format, v1, v2, v3, v4)\
+ pprintd2(s, pprintd2(s, format, v1, v2), v3, v4)
+
+/* Print a long value using a format. */
+const char *pprintld1(P3(stream *s, const char *format, long v));
+#define pprintld2(s, format, v1, v2)\
+ pprintld1(s, pprintld1(s, format, v1), v2)
+#define pprintld3(s, format, v1, v2, v3)\
+ pprintld2(s, pprintld1(s, format, v1), v2, v3)
+
+/* Print (a) string(s) using a format. */
+const char *pprints1(P3(stream *s, const char *format, const char *str));
+const char *pprints2(P4(stream *s, const char *format, const char *str1,
+ const char *str2));
+#define pprints3(s, format, str1, str2, str3)\
+ pprints2(s, pprints1(s, format, str1), str2, str3)
diff --git a/gs/src/gdevpx.c b/gs/src/gdevpx.c
new file mode 100644
index 000000000..300b4065f
--- /dev/null
+++ b/gs/src/gdevpx.c
@@ -0,0 +1,1566 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpx.c */
+/* H-P PCL XL driver */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccolor.h"
+#include "gsdcolor.h"
+#include "gxcspace.h" /* for color mapping for images */
+#include "gxdevice.h"
+#include "gxpath.h"
+#include "gdevvec.h"
+#include "strimpl.h"
+#include "srlx.h"
+#include "gdevpxat.h"
+#include "gdevpxen.h"
+#include "gdevpxop.h"
+
+/* ---------------- Device definition ---------------- */
+
+/* Define the default resolution. */
+#ifndef X_DPI
+# define X_DPI 600
+#endif
+#ifndef Y_DPI
+# define Y_DPI 600
+#endif
+
+/* Structure definition */
+#define num_points 100 /* must be >= 3 and <= 255 */
+typedef enum {
+ points_none,
+ points_lines,
+ points_curves
+} point_type_t;
+typedef struct gx_device_pclxl_s {
+ gx_device_vector_common;
+ /* Additional state information */
+ pxeMediaSize_t media_size;
+ gx_path_type_t fill_rule; /* ...winding_number or ...even_odd */
+ gx_path_type_t clip_rule; /* ditto */
+ pxeColorSpace_t color_space;
+ struct pal_ {
+ int size; /* # of bytes */
+ byte data[256 * 3]; /* up to 8-bit samples */
+ } palette;
+ struct pts_ { /* buffer for accumulating path points */
+ gs_int_point current; /* current point as of start of data */
+ point_type_t type;
+ int count;
+ gs_int_point data[num_points];
+ } points;
+ struct ch_ { /* cache for downloaded characters */
+#define max_cached_chars 400
+#define max_char_data 500000
+#define max_char_size 5000
+#define char_hash_factor 247
+ ushort table[max_cached_chars * 3 / 2];
+ struct cd_ {
+ gs_id id; /* key */
+ uint size;
+ } data[max_cached_chars];
+ int next_in; /* next data element to fill in */
+ int next_out; /* next data element to discard */
+ int count; /* of occupied data elements */
+ ulong used;
+ } chars;
+ bool font_set;
+} gx_device_pclxl;
+gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
+ "gx_device_pclxl", device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
+ gx_device_finalize, st_device_vector);
+
+#define pclxl_device_body(dname, depth)\
+ std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
+ DEFAULT_WIDTH_10THS * X_DPI / 10,\
+ DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
+ X_DPI, Y_DPI,\
+ (depth > 8 ? 3 : 1), depth,\
+ (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
+ (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
+
+/* Driver procedures */
+private dev_proc_open_device(pclxl_open_device);
+private dev_proc_output_page(pclxl_output_page);
+private dev_proc_close_device(pclxl_close_device);
+private dev_proc_copy_mono(pclxl_copy_mono);
+private dev_proc_copy_color(pclxl_copy_color);
+private dev_proc_fill_mask(pclxl_fill_mask);
+/*private dev_proc_draw_thin_line(pclxl_draw_thin_line);*/
+private dev_proc_begin_image(pclxl_begin_image);
+private dev_proc_image_data(pclxl_image_data);
+private dev_proc_end_image(pclxl_end_image);
+private dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
+#define pclxl_device_procs(map_rgb_color, map_color_rgb)\
+ { pclxl_open_device,\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ pclxl_output_page,\
+ pclxl_close_device,\
+ map_rgb_color, /* differs */\
+ map_color_rgb, /* differs */\
+ gdev_vector_fill_rectangle,\
+ NULL, /* tile_rectangle */\
+ pclxl_copy_mono,\
+ pclxl_copy_color,\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ gdev_vector_get_params,\
+ gdev_vector_put_params,\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ gx_page_device_get_page_device,\
+ NULL, /* get_alpha_bits */\
+ NULL, /* copy_alpha */\
+ NULL, /* get_band */\
+ NULL, /* copy_rop */\
+ gdev_vector_fill_path,\
+ gdev_vector_stroke_path,\
+ pclxl_fill_mask,\
+ gdev_vector_fill_trapezoid,\
+ gdev_vector_fill_parallelogram,\
+ gdev_vector_fill_triangle,\
+ NULL /****** WRONG ******/, /* draw_thin_line */\
+ pclxl_begin_image,\
+ pclxl_image_data,\
+ pclxl_end_image,\
+ NULL, /* strip_tile_rectangle */\
+ pclxl_strip_copy_rop\
+ }
+
+gx_device_pclxl far_data gs_pxlmono_device = {
+ pclxl_device_body("pxlmono", 8),
+ pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
+};
+
+gx_device_pclxl far_data gs_pxlcolor_device = {
+ pclxl_device_body("pxlcolor", 24),
+ pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
+};
+
+/* ---------------- Output utilities ---------------- */
+
+/* Write a sequence of bytes. */
+#define put_lit(s, bytes) put_bytes(s, bytes, sizeof(bytes))
+private void
+put_bytes(stream *s, const byte *data, uint count)
+{ uint used;
+
+ sputs(s, data, count, &used);
+}
+
+/* Utilities for writing data values. */
+/* H-P printers only support little-endian data, so that's what we emit. */
+#define da(a) pxt_attr_ubyte, (a)
+private void
+put_a(stream *s, px_attribute_t a)
+{ sputc(s, pxt_attr_ubyte);
+ sputc(s, a);
+}
+#define dub(b) pxt_ubyte, (byte)(b)
+private void
+put_ub(stream *s, byte b)
+{ sputc(s, pxt_ubyte);
+ sputc(s, b);
+}
+#define put_uba(s, b, a)\
+ (put_ub(s, b), put_a(s, a))
+#define ds(i) (byte)(i), (byte)((i) >> 8)
+private void
+put_s(stream *s, uint i)
+{ sputc(s, (byte)i);
+ sputc(s, (byte)(i >> 8));
+}
+#define dus(i) pxt_uint16, ds(i)
+private void
+put_us(stream *s, uint i)
+{ sputc(s, pxt_uint16);
+ put_s(s, i);
+}
+#define put_usa(s, i, a)\
+ (put_us(s, i), put_a(s, a))
+private void
+put_u(stream *s, uint i)
+{ if ( i <= 255 )
+ put_ub(s, i);
+ else
+ put_us(s, i);
+}
+#define dusp(ix,iy) pxt_uint16_xy, ds(ix), ds(iy)
+private void
+put_usp(stream *s, uint ix, uint iy)
+{ sputc(s, pxt_uint16_xy);
+ put_s(s, ix);
+ put_s(s, iy);
+}
+private void
+put_usq_fixed(stream *s, fixed x0, fixed y0, fixed x1, fixed y1)
+{ sputc(s, pxt_uint16_box);
+ put_s(s, fixed2int(x0));
+ put_s(s, fixed2int(y0));
+ put_s(s, fixed2int(x1));
+ put_s(s, fixed2int(y1));
+}
+#define dss(i) pxt_sint16, ds(i)
+private void
+put_ss(stream *s, int i)
+{ sputc(s, pxt_sint16);
+ put_s(s, (uint)i);
+}
+#define dssp(ix,iy) pxt_sint16_xy, ds(ix), ds(iy)
+private void
+put_ssp(stream *s, int ix, int iy)
+{ sputc(s, pxt_sint16_xy);
+ put_s(s, (uint)ix);
+ put_s(s, (uint)iy);
+}
+#define dl(l) ds(l), ds((l) >> 16)
+private void
+put_l(stream *s, ulong l)
+{ put_s(s, (uint)l);
+ put_s(s, (uint)(l >> 16));
+}
+private void
+put_r(stream *s, floatp r)
+{ /* Convert to single-precision IEEE float. */
+ int exp;
+ long mantissa = (long)(frexp(r, &exp) * 0x1000000);
+
+ if ( exp < -126 )
+ mantissa = 0, exp = 0; /* unnormalized */
+ if ( mantissa < 0 )
+ exp += 128, mantissa = -mantissa;
+ /* All quantities are little-endian. */
+ spputc(s, (byte)mantissa);
+ spputc(s, (byte)(mantissa >> 8));
+ spputc(s, (byte)(((exp + 127) << 7) + ((mantissa >> 16) & 0x7f)));
+ spputc(s, (exp + 127) >> 1);
+}
+private void
+put_rl(stream *s, floatp r)
+{ sputc(s, pxt_real32);
+ put_r(s, r);
+}
+private void
+put_data_length(stream *s, uint num_bytes)
+{ if ( num_bytes > 255 )
+ { spputc(s, pxt_dataLength);
+ put_l(s, (ulong)num_bytes);
+ }
+ else
+ { spputc(s, pxt_dataLengthByte);
+ spputc(s, (byte)num_bytes);
+ }
+}
+
+#define put_ac(s, a, op)\
+do { static const byte ac_[] = { da(a), op }; put_lit(s, ac_); } while ( 0 )
+#define return_put_ac(s, a, op)\
+do { put_ac(s, a, op); return 0; } while ( 0 )
+
+/* ---------------- Other utilities ---------------- */
+
+#define vxdev ((gx_device_vector *)xdev)
+
+/* Initialize for a page. */
+private void
+pclxl_page_init(gx_device_pclxl *xdev)
+{ gdev_vector_init(vxdev);
+ xdev->in_page = false;
+ xdev->fill_rule = gx_path_type_winding_number;
+ xdev->clip_rule = gx_path_type_winding_number;
+ xdev->color_space = eNoColorSpace;
+ xdev->palette.size = 0;
+ xdev->font_set = false;
+}
+
+/* Test whether a RGB color is actually a gray shade. */
+#define rgb_is_gray(ci) ((ci) >> 8 == ((ci) & 0xffff))
+
+/* Set the color space and (optionally) palette. */
+private void
+pclxl_set_color_space(gx_device_pclxl *xdev, pxeColorSpace_t color_space)
+{ if ( xdev->color_space != color_space )
+ { stream *s = gdev_vector_stream(vxdev);
+ put_ub(s, color_space);
+ put_ac(s, pxaColorSpace, pxtSetColorSpace);
+ xdev->color_space = color_space;
+ }
+}
+private void
+pclxl_set_color_palette(gx_device_pclxl *xdev, pxeColorSpace_t color_space,
+ const byte *palette, uint palette_size)
+{ if ( xdev->color_space != color_space ||
+ xdev->palette.size != palette_size ||
+ memcmp(xdev->palette.data, palette, palette_size)
+ )
+ { stream *s = gdev_vector_stream(vxdev);
+ static const byte csp_[] = {
+ da(pxaColorSpace),
+ dub(e8Bit), da(pxaPaletteDepth),
+ pxt_ubyte_array
+ };
+
+ put_ub(s, color_space);
+ put_lit(s, csp_);
+ put_u(s, palette_size);
+ put_bytes(s, palette, palette_size);
+ put_ac(s, pxaPaletteData, pxtSetColorSpace);
+ xdev->color_space = color_space;
+ xdev->palette.size = palette_size;
+ memcpy(xdev->palette.data, palette, palette_size);
+ }
+}
+
+/* Set a drawing RGB color. */
+private int
+pclxl_set_color(gx_device_pclxl *xdev, const gx_drawing_color *pdc,
+ px_attribute_t null_source, px_tag_t op)
+{ stream *s = gdev_vector_stream(vxdev);
+ if ( gx_dc_is_pure(pdc) )
+ { gx_color_index color = gx_dc_pure_color(pdc);
+ if ( xdev->color_info.num_components == 1 || rgb_is_gray(color) )
+ { pclxl_set_color_space(xdev, eGray);
+ put_uba(s, (byte)color, pxaGrayLevel);
+ }
+ else
+ { pclxl_set_color_space(xdev, eRGB);
+ spputc(s, pxt_ubyte_array);
+ put_ub(s, 3);
+ spputc(s, (byte)(color >> 16));
+ spputc(s, (byte)(color >> 8));
+ spputc(s, (byte)color);
+ put_a(s, pxaRGBColor);
+ }
+ }
+ else if ( gx_dc_is_null(pdc) )
+ put_uba(s, 0, null_source);
+ else
+ return_error(gs_error_rangecheck);
+ spputc(s, op);
+ return 0;
+}
+
+/* Test whether we can handle a given color space in an image. */
+private bool
+pclxl_can_handle_color_space(const gs_color_space *pcs)
+{ gs_color_space_index index = gs_color_space_get_index(pcs);
+ if ( index == gs_color_space_index_Indexed )
+ { if ( pcs->params.indexed.use_proc )
+ return false;
+ index =
+ gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
+ }
+ return !(index == gs_color_space_index_Separation ||
+ index == gs_color_space_index_Pattern);
+}
+
+/* Set brush, pen, and mode for painting a path. */
+private void
+pclxl_set_paints(gx_device_pclxl *xdev, gx_path_type_t type)
+{ stream *s = gdev_vector_stream(vxdev);
+ gx_path_type_t rule = type & gx_path_type_rule;
+
+ if ( !(type & gx_path_type_fill) &&
+ !gx_dc_is_null(&xdev->fill_color)
+ )
+ { static const byte nac_[] = {
+ dub(0), da(pxaNullBrush), pxtSetBrushSource
+ };
+ put_lit(s, nac_);
+ color_set_null(&xdev->fill_color);
+ if ( rule != xdev->fill_rule )
+ { put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
+ eNonZeroWinding));
+ put_ac(s, pxaFillMode, pxtSetFillMode);
+ xdev->fill_rule = rule;
+ }
+ }
+ if ( !(type & gx_path_type_stroke) &&
+ !gx_dc_is_null(&xdev->stroke_color)
+ )
+ { static const byte nac_[] = {
+ dub(0), da(pxaNullPen), pxtSetPenSource
+ };
+ put_lit(s, nac_);
+ color_set_null(&xdev->stroke_color);
+ }
+}
+
+/* Set the cursor. */
+private int
+pclxl_set_cursor(gx_device_pclxl *xdev, int x, int y)
+{ stream *s = gdev_vector_stream(vxdev);
+ put_ssp(s, x, y);
+ return_put_ac(s, pxaPoint, pxtSetCursor);
+}
+
+/* ------ Paths ------ */
+
+/* Flush any buffered path points. */
+private void
+put_np(stream *s, int count, pxeDataType_t dtype)
+{ put_uba(s, count, pxaNumberOfPoints);
+ put_uba(s, dtype, pxaPointType);
+}
+private int
+pclxl_flush_points(gx_device_pclxl *xdev)
+{ int count = xdev->points.count;
+
+ if ( count )
+ { stream *s = gdev_vector_stream(vxdev);
+ px_tag_t op;
+ int x = xdev->points.current.x, y = xdev->points.current.y;
+ int uor = 0, sor = 0;
+ pxeDataType_t data_type;
+ int i, di;
+ byte diffs[num_points * 2];
+
+ /*
+ * Writing N lines using a point list requires 11 + 4*N or 11 +
+ * 2*N bytes, as opposed to 8*N bytes using separate commands;
+ * writing N curves requires 11 + 12*N or 11 + 6*N bytes
+ * vs. 22*N. So it's always shorter to write curves with a
+ * list (except for N = 1 with full-size coordinates, but since
+ * the difference is only 1 byte, we don't bother to ever use
+ * the non-list form), but lines are shorter only if N >= 3
+ * (again, with a 1-byte difference if N = 2 and byte
+ * coordinates).
+ */
+ switch ( xdev->points.type )
+ {
+ case points_none:
+ return 0;
+ case points_lines:
+ op = pxtLinePath;
+ if ( count < 3 )
+ { for ( i = 0; i < count; ++i )
+ { put_ssp(s, xdev->points.data[i].x,
+ xdev->points.data[i].y);
+ put_a(s, pxaEndPoint);
+ spputc(s, op);
+ }
+ goto zap;
+ }
+ /* See if we can use byte values. */
+ for ( i = di = 0; i < count; ++i, di += 2 )
+ { int dx = xdev->points.data[i].x - x;
+ int dy = xdev->points.data[i].y - y;
+
+ diffs[di] = (byte)dx;
+ diffs[di + 1] = (byte)dy;
+ uor |= dx | dy;
+ sor |= (dx + 0x80) | (dy + 0x80);
+ x += dx, y += dy;
+ }
+ if ( !(uor & ~0xff) )
+ data_type = eUByte;
+ else if ( !(sor & ~0xff) )
+ data_type = eSByte;
+ else
+ break;
+ op = pxtLineRelPath;
+ /* Use byte values. */
+useb: put_np(s, count, data_type);
+ spputc(s, op);
+ put_data_length(s, count * 2); /* 2 bytes per point */
+ put_bytes(s, diffs, count * 2);
+ goto zap;
+ case points_curves:
+ op = pxtBezierPath;
+ /* See if we can use byte values. */
+ for ( i = di = 0; i < count; i += 3, di += 6 )
+ { int dx1 = xdev->points.data[i].x - x;
+ int dy1 = xdev->points.data[i].y - y;
+ int dx2 = xdev->points.data[i + 1].x - x;
+ int dy2 = xdev->points.data[i + 1].y - y;
+ int dx = xdev->points.data[i + 2].x - x;
+ int dy = xdev->points.data[i + 2].y - y;
+
+ diffs[di] = (byte)dx1;
+ diffs[di + 1] = (byte)dy1;
+ diffs[di + 2] = (byte)dx2;
+ diffs[di + 3] = (byte)dy2;
+ diffs[di + 4] = (byte)dx;
+ diffs[di + 5] = (byte)dy;
+ uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
+ sor |= (dx1 + 0x80) | (dy1 + 0x80) |
+ (dx2 + 0x80) | (dy2 + 0x80) |
+ (dx + 0x80) | (dy + 0x80);
+ x += dx, y += dy;
+ }
+ if ( !(uor & ~0xff) )
+ data_type = eUByte;
+ else if ( !(sor & ~0xff) )
+ data_type = eSByte;
+ else
+ break;
+ op = pxtBezierRelPath;
+ goto useb;
+ default: /* can't happen */
+ return_error(gs_error_unknownerror);
+ }
+ put_np(s, count, eSInt16);
+ spputc(s, op);
+ put_data_length(s, count * 4); /* 2 UInt16s per point */
+ for ( i = 0; i < count; ++i )
+ { put_s(s, xdev->points.data[i].x);
+ put_s(s, xdev->points.data[i].y);
+ }
+zap: xdev->points.type = points_none;
+ xdev->points.count = 0;
+ }
+ return 0;
+}
+
+/* ------ Images ------ */
+
+/* Begin an image. */
+private void
+pclxl_write_begin_image(gx_device_pclxl *xdev, uint width, uint height,
+ uint dest_width, uint dest_height)
+{ stream *s = gdev_vector_stream(vxdev);
+
+ put_usa(s, width, pxaSourceWidth);
+ put_usa(s, height, pxaSourceHeight);
+ put_usp(s, dest_width, dest_height);
+ put_ac(s, pxaDestinationSize, pxtBeginImage);
+}
+
+/* Write rows of an image. */
+/****** IGNORES data_bit ******/
+private void
+pclxl_write_image_data(gx_device_pclxl *xdev, const byte *data, int data_bit,
+ uint raster, uint width_bits, int y, int height)
+{ stream *s = gdev_vector_stream(vxdev);
+ uint width_bytes = (width_bits + 7) >> 3;
+ bool compress = width_bytes >= 8;
+ uint num_bytes = round_up(width_bytes, 4) * height;
+ int i;
+
+ put_usa(s, y, pxaStartLine);
+ put_usa(s, height, pxaBlockHeight);
+ if ( compress )
+ { stream_RLE_state rlstate;
+ stream_cursor_write w;
+ stream_cursor_read r;
+ /*
+ * H-P printers required that all the data for an operator be
+ * contained in a single data block. Thus, we must allocate
+ * a temporary buffer for the compressed data. Currently we
+ * don't go to the trouble of breaking the data up into scan
+ * lines if we can't allocate a buffer large enough for the
+ * entire transfer.
+ */
+ byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
+ "pclxl_write_image_data");
+
+ if ( buf == 0 )
+ goto nc;
+ s_RLE_set_defaults_inline(&rlstate);
+ rlstate.EndOfData = false;
+ s_RLE_init_inline(&rlstate);
+ w.ptr = buf - 1;
+ w.limit = w.ptr + num_bytes;
+ /*
+ * If we ever overrun the buffer, it means that the compressed
+ * data was larger than the uncompressed. If this happens,
+ * write the data uncompressed.
+ */
+ for ( i = 0; i < height; ++i )
+ { r.ptr = data + i * raster - 1;
+ r.limit = r.ptr + width_bytes;
+ if ( (*s_RLE_template.process)
+ ((stream_state *)&rlstate, &r, &w, false) != 0 ||
+ r.ptr != r.limit
+ )
+ goto ncfree;
+ r.ptr = (const byte *)"\000\000\000\000\000";
+ r.limit = r.ptr + (-width_bytes & 3);
+ if ( (*s_RLE_template.process)
+ ((stream_state *)&rlstate, &r, &w, false) != 0 ||
+ r.ptr != r.limit
+ )
+ goto ncfree;
+ }
+ r.ptr = r.limit;
+ if ( (*s_RLE_template.process)
+ ((stream_state *)&rlstate, &r, &w, true) != 0
+ )
+ goto ncfree;
+ { uint count = w.ptr + 1 - buf;
+
+ put_ub(s, eRLECompression);
+ put_ac(s, pxaCompressMode, pxtReadImage);
+ put_data_length(s, count);
+ put_bytes(s, buf, count);
+ }
+ return;
+ncfree: gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
+nc: ;
+ }
+ /* Write the data uncompressed. */
+ put_ub(s, eNoCompression);
+ put_ac(s, pxaCompressMode, pxtReadImage);
+ put_data_length(s, num_bytes);
+ for ( i = 0; i < height; ++i )
+ { put_bytes(s, data + i * raster, width_bytes);
+ put_bytes(s, (const byte *)"\000\000\000\000", -width_bytes & 3);
+ }
+}
+
+/* End an image. */
+private void
+pclxl_write_end_image(gx_device_pclxl *xdev)
+{ spputc(xdev->strm, pxtEndImage);
+}
+
+/* ------ Fonts ------ */
+
+/* Write a string (single- or double-byte). */
+private void
+put_string(stream *s, const byte *data, uint len, bool wide)
+{ if ( wide ) {
+ spputc(s, pxt_uint16_array);
+ put_u(s, len);
+ put_bytes(s, data, len * 2);
+ } else {
+ spputc(s, pxt_ubyte_array);
+ put_u(s, len);
+ put_bytes(s, data, len);
+ }
+}
+
+/* Write a 16-bit big-endian value. */
+private void
+put_us_be(stream *s, uint i)
+{ spputc(s, (byte)(i >> 8));
+ spputc(s, (byte)i);
+}
+
+/* Define a bitmap font. The client must call put_string */
+/* with the font name immediately before calling this procedure. */
+private void
+pclxl_define_bitmap_font(gx_device_pclxl *xdev)
+{ stream *s = gdev_vector_stream(vxdev);
+ static const byte bfh_[] = {
+ da(pxaFontName), dub(0), da(pxaFontFormat),
+ pxtBeginFontHeader,
+ dus(8 + 6 + 4 + 6), da(pxaFontHeaderLength),
+ pxtReadFontHeader,
+ pxt_dataLengthByte, 8 + 6 + 4 + 6,
+ 0, 0, 0, 0,
+ 254, 0, (max_cached_chars + 255) >> 8, 0,
+ 'B', 'R', 0, 0, 0, 4
+ };
+ static const byte efh_[] = {
+ 0xff, 0xff, 0, 0, 0, 0,
+ pxtEndFontHeader
+ };
+
+ put_lit(s, bfh_);
+ put_us_be(s, (uint)(xdev->HWResolution[0] + 0.5));
+ put_us_be(s, (uint)(xdev->HWResolution[1] + 0.5));
+ put_lit(s, efh_);
+}
+
+/* Set the font. The client must call put_string */
+/* with the font name immediately before calling this procedure. */
+private void
+pclxl_set_font(gx_device_pclxl *xdev)
+{ stream *s = gdev_vector_stream(vxdev);
+ static const byte sf_[] = {
+ da(pxaFontName), dub(1), da(pxaCharSize), dus(0), da(pxaSymbolSet),
+ pxtSetFont
+ };
+
+ put_lit(s, sf_);
+}
+
+/* Define a character in a bitmap font. The client must call put_string */
+/* with the font name immediately before calling this procedure. */
+private void
+pclxl_define_bitmap_char(gx_device_pclxl *xdev, uint ccode,
+ const byte *data, uint raster, uint width_bits, uint height)
+{ stream *s = gdev_vector_stream(vxdev);
+ uint width_bytes = (width_bits + 7) >> 3;
+ uint size = 10 + width_bytes * height;
+ uint i;
+
+ put_ac(s, pxaFontName, pxtBeginChar);
+ put_u(s, ccode);
+ put_a(s, pxaCharCode);
+ if ( size > 0xffff ) {
+ spputc(s, pxt_uint32);
+ put_l(s, (ulong)size);
+ } else
+ put_us(s, size);
+ put_ac(s, pxaCharDataSize, pxtReadChar);
+ put_data_length(s, size);
+ put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
+ put_us_be(s, width_bits);
+ put_us_be(s, height);
+ for ( i = 0; i < height; ++i )
+ put_bytes(s, data + i * raster, width_bytes);
+ spputc(s, pxtEndChar);
+}
+
+/* Write the name of the only font we define. */
+private void
+pclxl_write_font_name(gx_device_pclxl *xdev)
+{ stream *s = gdev_vector_stream(vxdev);
+
+ put_string(s, (const byte *)"@", 1, false);
+}
+
+/* Look up a bitmap id, return the index in the character table. */
+/* If the id is missing, return an index for inserting. */
+private int
+pclxl_char_index(gx_device_pclxl *xdev, gs_id id)
+{ int i, i_empty = -1;
+ uint ccode;
+
+ for ( i = (id * char_hash_factor) % countof(xdev->chars.table); ;
+ i = (i == 0 ? countof(xdev->chars.table) : i) - 1
+ ) {
+ ccode = xdev->chars.table[i];
+ if ( ccode == 0 )
+ return (i_empty >= 0 ? i_empty : i);
+ else if ( ccode == 1 ) {
+ if ( i_empty < 0 )
+ i_empty = i;
+ else if ( i == i_empty ) /* full table */
+ return i;
+ }
+ else if ( xdev->chars.data[ccode].id == id )
+ return i;
+ }
+}
+
+/* Remove the character table entry at a given index. */
+private void
+pclxl_remove_char(gx_device_pclxl *xdev, int index)
+{ uint ccode = xdev->chars.table[index];
+ int i;
+
+ if ( ccode < 2 )
+ return;
+ xdev->chars.count--;
+ xdev->chars.used -= xdev->chars.data[ccode].size;
+ xdev->chars.table[index] = 1; /* mark as deleted */
+ i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
+ if ( xdev->chars.table[i] == 0 ) {
+ /* The next slot in probe order is empty. */
+ /* Mark this slot and any deleted predecessors as empty. */
+ for ( i = index; xdev->chars.table[i] == 1;
+ i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
+ )
+ xdev->chars.table[i] = 0;
+ }
+}
+
+/* Write a bitmap as a text character if possible. */
+/* The caller must set the color, cursor, and RasterOp. */
+/* We know id != gs_no_id. */
+private int
+pclxl_copy_text_char(gx_device_pclxl *xdev, const byte *data,
+ int raster, gx_bitmap_id id, int w, int h)
+{ uint width_bytes = (w + 7) >> 3;
+ uint size = width_bytes * h;
+ int index;
+ uint ccode;
+ stream *s = gdev_vector_stream(vxdev);
+
+ if ( size > max_char_size )
+ return -1;
+ index = pclxl_char_index(xdev, id);
+ if ( (ccode = xdev->chars.table[index]) < 2 ) {
+ /* Enter the character in the table. */
+ while ( xdev->chars.used + size > max_char_data ||
+ xdev->chars.count >= max_cached_chars - 2
+ ) {
+ ccode = xdev->chars.next_out;
+ index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
+ pclxl_remove_char(xdev, index);
+ xdev->chars.next_out =
+ (ccode == max_cached_chars - 1 ? 2 : ccode + 1);
+ }
+ index = pclxl_char_index(xdev, id);
+ ccode = xdev->chars.next_in;
+ xdev->chars.data[ccode].id = id;
+ xdev->chars.data[ccode].size = size;
+ xdev->chars.table[index] = ccode;
+ xdev->chars.next_in =
+ (ccode == max_cached_chars - 1 ? 2 : ccode + 1);
+ if ( !xdev->chars.count++ ) {
+ /* This is the very first character. */
+ pclxl_write_font_name(xdev);
+ pclxl_define_bitmap_font(xdev);
+ }
+ xdev->chars.used += size;
+ pclxl_write_font_name(xdev);
+ pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
+ }
+ if ( !xdev->font_set ) {
+ pclxl_write_font_name(xdev);
+ pclxl_set_font(xdev);
+ xdev->font_set = true;
+ }
+ { byte cc_bytes[2];
+ cc_bytes[0] = (byte)ccode;
+ cc_bytes[1] = ccode >> 8;
+ put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
+ }
+ put_ac(s, pxaTextData, pxtText);
+ return 0;
+}
+
+/* ---------------- Vector implementation procedures ---------------- */
+
+#define xvdev ((gx_device_pclxl *)vdev)
+
+private int
+pclxl_beginpage(gx_device_vector *vdev)
+{ /*
+ * We can't use gdev_vector_stream here, because this may be called
+ * from there before in_page is set.
+ */
+ stream *s = vdev->strm;
+
+ { static const byte page_header_1[] = {
+ dub(ePortraitOrientation), da(pxaOrientation),
+ };
+ put_lit(s, page_header_1);
+ }
+ {
+#define msd(ms, res, w, h)\
+ { ms, (w) * 1.0 / (res), (h) * 1.0 / res },
+ static const struct {
+ pxeMediaSize_t ms;
+ float width, height;
+ } media_sizes[] = {
+ px_enumerate_media(msd)
+ { pxeMediaSize_next }
+ };
+ float w = vdev->width / vdev->HWResolution[0],
+ h = vdev->height / vdev->HWResolution[1];
+ int i;
+ pxeMediaSize_t size;
+
+ /* The default is eLetterPaper, media size 0. */
+ for ( i = countof(media_sizes) - 2; i > 0; --i )
+ if ( fabs(media_sizes[i].width - w) < 5.0/72 &&
+ fabs(media_sizes[i].height - h) < 5.0/72
+ )
+ break;
+ size = media_sizes[i].ms;
+ /*
+ * According to the PCL XL documentation, MediaSize must always
+ * be specified, but MediaSource is optional.
+ */
+ put_uba(s, size, pxaMediaSize);
+ if ( size != xvdev->media_size )
+ { static const byte page_header_2[] = {
+ dub(eAutoSelect), da(pxaMediaSource)
+ };
+ put_lit(s, page_header_2);
+ xvdev->media_size = size;
+ }
+ }
+ spputc(s, pxtBeginPage);
+ return 0;
+}
+
+private int
+pclxl_setlinewidth(gx_device_vector *vdev, floatp width)
+{ stream *s = gdev_vector_stream(vdev);
+ put_us(s, (uint)width);
+ return_put_ac(s, pxaPenWidth, pxtSetPenWidth);
+}
+
+private int
+pclxl_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
+{ stream *s = gdev_vector_stream(vdev);
+ /* The PCL XL cap styles just happen to be identical to PostScript. */
+ put_ub(s, (byte)cap);
+ return_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
+}
+
+private int
+pclxl_setlinejoin(gx_device_vector *vdev, gs_line_join join)
+{ stream *s = gdev_vector_stream(vdev);
+ /* The PCL XL join styles just happen to be identical to PostScript. */
+ put_ub(s, (byte)join);
+ return_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
+}
+
+private int
+pclxl_setmiterlimit(gx_device_vector *vdev, floatp limit)
+{ stream *s = gdev_vector_stream(vdev);
+ /*
+ * Amazingly enough, the PCL XL specification doesn't allow real
+ * numbers for the miter limit.
+ */
+ int i_limit = (int)(limit + 0.5);
+
+ put_u(s, max(i_limit, 1));
+ return_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
+}
+
+private int
+pclxl_setdash(gx_device_vector *vdev, const float *pattern, uint count,
+ floatp offset)
+{ stream *s = gdev_vector_stream(vdev);
+ if ( count == 0 )
+ { static const byte nac_[] = { dub(0), da(pxaSolidLine) };
+ put_lit(s, nac_);
+ }
+ else if ( count > 255 )
+ return_error(gs_error_limitcheck);
+ else
+ { uint i;
+ spputc(s, pxt_real32_array);
+ put_ub(s, count);
+ for ( i = 0; i < count; ++i )
+ put_r(s, pattern[i]);
+ put_a(s, pxaLineDashStyle);
+ if ( offset != 0 )
+ { put_rl(s, offset);
+ put_a(s, pxaDashOffset);
+ }
+ }
+ spputc(s, pxtSetLineDash);
+ return 0;
+}
+
+private int
+pclxl_setlogop(gx_device_vector *vdev, gs_logical_operation_t lop,
+ gs_logical_operation_t diff)
+{ stream *s = gdev_vector_stream(vdev);
+ if ( diff & lop_S_transparent )
+ { put_ub(s, (lop & lop_S_transparent ? 1 : 0));
+ put_ac(s, pxaTxMode, pxtSetSourceTxMode);
+ }
+ if ( diff & lop_T_transparent )
+ { put_ub(s, (lop & lop_T_transparent ? 1 : 0));
+ put_ac(s, pxaTxMode, pxtSetPaintTxMode);
+ }
+ if ( lop_rop(diff) )
+ { put_ub(s, lop_rop(lop));
+ put_ac(s, pxaROP3, pxtSetROP);
+ }
+ return 0;
+}
+
+private int
+pclxl_setfillcolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
+{ return pclxl_set_color(xvdev, pdc, pxaNullBrush, pxtSetBrushSource);
+}
+
+private int
+pclxl_setstrokecolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
+{ return pclxl_set_color(xvdev, pdc, pxaNullPen, pxtSetPenSource);
+}
+
+private int
+pclxl_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
+ fixed y1, gx_path_type_t type)
+{ stream *s = gdev_vector_stream(vdev);
+ if ( type & (gx_path_type_fill | gx_path_type_stroke) )
+ { pclxl_set_paints(xvdev, type);
+ put_usq_fixed(s, x0, y0, x1, y1);
+ put_ac(s, pxaBoundingBox, pxtRectangle);
+ }
+ if ( type & gx_path_type_clip )
+ { static const byte cr_[] = {
+ da(pxaBoundingBox),
+ dub(eInterior), da(pxaClipRegion),
+ pxtSetClipRectangle
+ };
+ put_usq_fixed(s, x0, y0, x1, y1);
+ put_lit(s, cr_);
+ }
+ return 0;
+}
+
+private int
+pclxl_beginpath(gx_device_vector *vdev, gx_path_type_t type)
+{ stream *s = gdev_vector_stream(vdev);
+ spputc(s, pxtNewPath);
+ xvdev->points.type = points_none;
+ xvdev->points.count = 0;
+ return 0;
+}
+
+private int
+pclxl_moveto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y,
+ bool first)
+{ int code = pclxl_flush_points(xvdev);
+
+ if ( code < 0 )
+ return code;
+ return pclxl_set_cursor(xvdev,
+ xvdev->points.current.x = (int)x,
+ xvdev->points.current.y = (int)y);
+}
+
+private int
+pclxl_lineto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y)
+{ if ( xvdev->points.type != points_lines ||
+ xvdev->points.count >= num_points
+ )
+ { if ( xvdev->points.type != points_none )
+ { int code = pclxl_flush_points(xvdev);
+ if ( code < 0 )
+ return code;
+ }
+ xvdev->points.current.x = (int)x0;
+ xvdev->points.current.y = (int)y0;
+ xvdev->points.type = points_lines;
+ }
+ { gs_int_point *ppt = &xvdev->points.data[xvdev->points.count++];
+ ppt->x = (int)x, ppt->y = (int)y;
+ }
+ return 0;
+}
+
+private int
+pclxl_curveto(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
+{ if ( xvdev->points.type != points_curves ||
+ xvdev->points.count >= num_points - 2
+ )
+ { if ( xvdev->points.type != points_none )
+ { int code = pclxl_flush_points(xvdev);
+ if ( code < 0 )
+ return code;
+ }
+ xvdev->points.current.x = (int)x0;
+ xvdev->points.current.y = (int)y0;
+ xvdev->points.type = points_curves;
+ }
+ { gs_int_point *ppt = &xvdev->points.data[xvdev->points.count];
+ ppt->x = (int)x1, ppt->y = (int)y1, ++ppt;
+ ppt->x = (int)x2, ppt->y = (int)y2, ++ppt;
+ ppt->x = (int)x3, ppt->y = (int)y3;
+ }
+ xvdev->points.count += 3;
+ return 0;
+}
+
+private int
+pclxl_closepath(gx_device_vector *vdev, floatp x, floatp y,
+ floatp x_start, floatp y_start)
+{ stream *s = gdev_vector_stream(vdev);
+ int code = pclxl_flush_points(xvdev);
+
+ if ( code < 0 )
+ return code;
+ spputc(s, pxtCloseSubPath);
+ xvdev->points.current.x = (int)x_start;
+ xvdev->points.current.y = (int)y_start;
+ return 0;
+}
+
+private int
+pclxl_endpath(gx_device_vector *vdev, gx_path_type_t type)
+{ stream *s = gdev_vector_stream(vdev);
+ int code = pclxl_flush_points(xvdev);
+ gx_path_type_t rule = type & gx_path_type_rule;
+
+ if ( code < 0 )
+ return code;
+ if ( type & (gx_path_type_fill | gx_path_type_stroke) )
+ { pclxl_set_paints(xvdev, type);
+ spputc(s, pxtPaintPath);
+ }
+ if ( type & gx_path_type_clip )
+ { static const byte scr_[] = {
+ dub(eInterior), da(pxaClipRegion), pxtSetClipReplace
+ };
+ if ( rule != xvdev->clip_rule )
+ { put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
+ eNonZeroWinding));
+ put_ac(s, pxaClipMode, pxtSetClipMode);
+ xvdev->clip_rule = rule;
+ }
+ put_lit(s, scr_);
+ }
+ return 0;
+}
+
+/* Vector implementation procedures */
+
+private const gx_device_vector_procs pclxl_vector_procs = {
+ /* Page management */
+ pclxl_beginpage,
+ /* Imager state */
+ pclxl_setlinewidth,
+ pclxl_setlinecap,
+ pclxl_setlinejoin,
+ pclxl_setmiterlimit,
+ pclxl_setdash,
+ gdev_vector_setflat,
+ pclxl_setlogop,
+ /* Other state */
+ pclxl_setfillcolor,
+ pclxl_setstrokecolor,
+ /* Paths */
+ gdev_vector_dopath,
+ pclxl_dorect,
+ pclxl_beginpath,
+ pclxl_moveto,
+ pclxl_lineto,
+ pclxl_curveto,
+ pclxl_closepath,
+ pclxl_endpath
+};
+
+/* ---------------- Driver procedures ---------------- */
+
+#define vdev ((gx_device_vector *)dev)
+#define xdev ((gx_device_pclxl *)dev)
+
+/* ------ Open/close/page ------ */
+
+/* Open the device. */
+private int
+pclxl_open_device(gx_device *dev)
+{ int code;
+ static const char *file_header =
+ "\033%-12345X@PJL ENTER LANGUAGE = PCLXL\n\
+) HP-PCL XL;1;1;Comment Copyright Aladdin Enterprises 1996\000\n";
+ static const byte stream_header[] = {
+ da(pxaUnitsPerMeasure),
+ dub(0), da(pxaMeasure),
+ dub(eBackChAndErrPage), da(pxaErrorReport),
+ pxtBeginSession,
+ dub(0), da(pxaSourceType),
+ dub(eBinaryLowByteFirst), da(pxaDataOrg),
+ pxtOpenDataSource
+ };
+
+ vdev->v_memory = dev->memory; /****** WRONG ******/
+ vdev->vec_procs = &pclxl_vector_procs;
+ code = gdev_vector_open_file(vdev, 512);
+ if ( code < 0 )
+ return code;
+ pclxl_page_init(xdev);
+ { stream *s = vdev->strm;
+ /* We have to add 2 to the strlen because the next-to-last */
+ /* character is a null. */
+ put_bytes(s, (const byte *)file_header,
+ strlen(file_header) + 2);
+ put_usp(s, (uint)(dev->HWResolution[0] + 0.5),
+ (uint)(dev->HWResolution[1] + 0.5));
+ put_lit(s, stream_header);
+ }
+ xdev->media_size = pxeMediaSize_next; /* no size selected */
+ memset(&xdev->chars, 0, sizeof(xdev->chars));
+ xdev->chars.next_in = xdev->chars.next_out = 2;
+ return 0;
+}
+
+/* Wrap up ("output") a page. */
+/* We only support flush = true, and we don't support num_copies != 1. */
+private int
+pclxl_output_page(gx_device *dev, int num_copies, int flush)
+{ if ( xdev->in_page )
+ { stream *s = vdev->strm;
+ spputc(s, pxtEndPage);
+ sflush(s);
+ pclxl_page_init(xdev);
+ }
+ return 0;
+}
+
+/* Close the device. */
+/* Note that if this is being called as a result of finalization, */
+/* the stream may no longer exist. */
+private int
+pclxl_close_device(gx_device *dev)
+{ FILE *file = vdev->file;
+
+ if ( xdev->in_page )
+ fputc(pxtEndPage, file);
+ { static const byte file_trailer[] = {
+ pxtCloseDataSource,
+ pxtEndSession,
+ 033, '%', '-', '1', '2', '3', '4', '5', 'X'
+ };
+
+ /* The stream may no longer exist: see above. */
+ fwrite(file_trailer, 1, sizeof(file_trailer), file);
+ }
+ gdev_vector_close_file(vdev);
+ return 0;
+}
+
+/* ------ One-for-one images ------ */
+
+private const byte eBit_values[] = {
+ 0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
+};
+
+/* Copy a monochrome bitmap. */
+private int
+pclxl_copy_mono(gx_device *dev, const byte *data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ int code;
+ stream *s;
+ gx_color_index color0 = zero, color1 = one;
+ gs_logical_operation_t lop;
+ byte palette[2 * 3];
+ int palette_size;
+ pxeColorSpace_t color_space;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, w, h);
+ code = gdev_vector_update_clip_path(vdev, NULL);
+ if ( code < 0 )
+ return code;
+ pclxl_set_cursor(xdev, x, y);
+ if ( id != gs_no_id && zero == gx_no_color_index &&
+ one != gx_no_color_index && data_x == 0
+ ) {
+ gx_drawing_color dcolor;
+
+ color_set_pure(&dcolor, one);
+ pclxl_setfillcolor(vxdev, &dcolor);
+ if ( pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0 )
+ return 0;
+ }
+ /*
+ * The following doesn't work if we're writing white with a mask.
+ * We'll fix it eventually.
+ */
+ if ( zero == gx_no_color_index )
+ { if ( one == gx_no_color_index )
+ return 0;
+ lop = rop3_S | lop_S_transparent;
+ color0 = (1 << dev->color_info.depth) - 1;
+ }
+ else if ( one == gx_no_color_index )
+ { lop = rop3_S | lop_S_transparent;
+ color1 = (1 << dev->color_info.depth) - 1;
+ }
+ else
+ { lop = rop3_S;
+ }
+ if ( dev->color_info.num_components == 1 ||
+ (rgb_is_gray(color0) && rgb_is_gray(color1))
+ )
+ { palette[0] = (byte)color0;
+ palette[1] = (byte)color1;
+ palette_size = 2;
+ color_space = eGray;
+ }
+ else
+ { palette[0] = (byte)(color0 >> 16);
+ palette[1] = (byte)(color0 >> 8);
+ palette[2] = (byte)color0;
+ palette[3] = (byte)(color1 >> 16);
+ palette[4] = (byte)(color1 >> 8);
+ palette[5] = (byte)color1;
+ palette_size = 6;
+ color_space = eRGB;
+ }
+ code = gdev_vector_update_log_op(vdev, lop);
+ if ( code < 0 )
+ return 0;
+ pclxl_set_color_palette(xdev, color_space, palette, palette_size);
+ s = gdev_vector_stream(vxdev);
+ { static const byte mi_[] = {
+ dub(e1Bit), da(pxaColorDepth),
+ dub(eIndexedPixel), da(pxaColorMapping)
+ };
+ put_lit(s, mi_);
+ }
+ pclxl_write_begin_image(xdev, w, h, w, h);
+ pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
+ pclxl_write_end_image(xdev);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+pclxl_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ stream *s;
+ uint source_bit;
+ int code;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ code = gdev_vector_update_clip_path(vdev, NULL);
+ if ( code < 0 )
+ return code;
+ source_bit = sourcex * dev->color_info.depth;
+ if ( (source_bit & 7) != 0 )
+ return gx_default_copy_color(dev, base, sourcex, raster, id,
+ x, y, w, h);
+ gdev_vector_update_log_op(vdev, rop3_S);
+ pclxl_set_cursor(xdev, x, y);
+ s = gdev_vector_stream(vxdev);
+ { static const byte ci_[] = {
+ da(pxaColorDepth),
+ dub(eDirectPixel), da(pxaColorMapping)
+ };
+ put_ub(s, eBit_values[dev->color_info.depth / dev->color_info.num_components]);
+ put_lit(s, ci_);
+ }
+ pclxl_write_begin_image(xdev, w, h, w, h);
+ pclxl_write_image_data(xdev, base, source_bit, raster,
+ w * dev->color_info.depth, 0, h);
+ pclxl_write_end_image(xdev);
+ return 0;
+}
+
+/* Fill a mask. */
+private int
+pclxl_fill_mask(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ int code;
+ stream *s;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, w, h);
+ if ( (data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 )
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, w, h, pdcolor, depth,
+ lop, pcpath);
+ code = gdev_vector_update_clip_path(vdev, pcpath);
+ if ( code < 0 )
+ return code;
+ code = gdev_vector_update_fill_color(vdev, pdcolor);
+ if ( code < 0 )
+ return 0;
+ pclxl_set_cursor(xdev, x, y);
+ if ( id != gs_no_id && data_x == 0 ) {
+ code = gdev_vector_update_log_op(vdev, lop);
+ if ( code < 0 )
+ return 0;
+ if ( pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0 )
+ return 0;
+ }
+ code = gdev_vector_update_log_op(vdev,
+ lop | rop3_S | lop_S_transparent);
+ if ( code < 0 )
+ return 0;
+ pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
+ s = gdev_vector_stream(vxdev);
+ { static const byte mi_[] = {
+ dub(e1Bit), da(pxaColorDepth),
+ dub(eIndexedPixel), da(pxaColorMapping)
+ };
+ put_lit(s, mi_);
+ }
+ pclxl_write_begin_image(xdev, w, h, w, h);
+ pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
+ pclxl_write_end_image(xdev);
+ return 0;
+}
+
+/* Do a RasterOp. */
+private int
+pclxl_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ /* We can't do general RasterOps yet. */
+ /****** WORK IN PROGRESS ******/
+ return 0;
+}
+
+/* ------ High-level images ------ */
+
+typedef struct pclxl_image_enum_s {
+ gs_memory_t *memory;
+ void *default_info;
+ uint bits_per_row;
+ int bits_per_pixel;
+ int y, h;
+} pclxl_image_enum_t;
+gs_private_st_ptrs1(st_pclxl_image_enum, pclxl_image_enum_t,
+ "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
+ pclxl_image_enum_reloc_ptrs, default_info);
+
+/* Start processing an image. */
+private int
+pclxl_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, void **pinfo)
+{ const gs_color_space *pcs = pim->ColorSpace;
+ pclxl_image_enum_t *pie;
+ gs_matrix mat;
+ int num_components;
+ int bits_per_pixel;
+
+ pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
+ "pclxl_begin_image");
+ if ( pie == 0 )
+ return_error(gs_error_VMerror);
+ pie->memory = mem;
+ *pinfo = pie;
+ if ( pim->ImageMask )
+ bits_per_pixel = num_components = 1;
+ else
+ num_components = gs_color_space_num_components(pcs),
+ bits_per_pixel = pim->BitsPerComponent * num_components;
+ gs_matrix_invert(&pim->ImageMatrix, &mat);
+ gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
+ /* Currently we only handle portrait transformations. */
+ if ( mat.xx <= 0 || mat.xy != 0 || mat.yx != 0 || mat.yy <= 0 ||
+ (pim->ImageMask ?
+ (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
+ (!pclxl_can_handle_color_space(pim->ColorSpace) ||
+ (bits_per_pixel != 1 && bits_per_pixel != 4 &&
+ bits_per_pixel != 8))) ||
+ format != gs_image_format_chunky ||
+ prect
+ )
+ { int code = gx_default_begin_image(dev, pis, pim, format, prect,
+ pdcolor, pcpath, mem,
+ &pie->default_info);
+ if ( code < 0 )
+ gs_free_object(mem, pie, "pclxl_begin_image");
+ return code;
+ }
+ pie->default_info = 0;
+ { stream *s = gdev_vector_stream(vxdev);
+ gs_logical_operation_t lop = pis->log_op;
+ int code = gdev_vector_update_log_op
+ (vdev, (pim->ImageMask || pim->CombineWithColor ? lop :
+ rop3_know_T_0(lop)));
+ int bpc = pim->BitsPerComponent;
+ int sample_max = (1 << bpc) - 1;
+ byte palette[256 * 3];
+ int i;
+
+ if ( code < 0 )
+ return code;
+ pie->bits_per_pixel = bits_per_pixel;
+ pie->bits_per_row = bits_per_pixel * pim->Width;
+ pie->y = 0;
+ pie->h = pim->Height;
+ pclxl_set_cursor(xdev, (int)((mat.tx + 0.5) / xdev->scale.x),
+ (int)((mat.ty + 0.5) / xdev->scale.y));
+ for ( i = 0; i < 1 << bits_per_pixel; ++i )
+ { gs_client_color cc;
+ gx_device_color devc;
+ int cv = i, j;
+
+ for ( j = num_components - 1; j >= 0; cv >>= bpc, --j )
+ cc.paint.values[j] = pim->Decode[j * 2] +
+ (cv & sample_max) *
+ (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
+ sample_max;
+ (*pcs->type->remap_color)
+ (&cc, pcs, &devc, pis, dev, gs_color_select_source);
+ if ( !gx_dc_is_pure(&devc) )
+ return_error(gs_error_Fatal);
+ if ( dev->color_info.num_components == 1 )
+ palette[i] = (byte)gx_dc_pure_color(&devc);
+ else
+ { gx_color_index ci = gx_dc_pure_color(&devc);
+ byte *ppal = &palette[i * 3];
+ ppal[0] = (byte)(ci >> 16);
+ ppal[1] = (byte)(ci >> 8);
+ ppal[2] = (byte)ci;
+ }
+ }
+ if ( dev->color_info.num_components == 1 )
+ pclxl_set_color_palette(xdev, eGray, palette,
+ 1 << bits_per_pixel);
+ else
+ pclxl_set_color_palette(xdev, eRGB, palette,
+ 3 << bits_per_pixel);
+ { static const byte ii_[] = {
+ da(pxaColorDepth),
+ dub(eIndexedPixel), da(pxaColorMapping)
+ };
+ put_ub(s, eBit_values[bits_per_pixel]);
+ put_lit(s, ii_);
+ }
+ pclxl_write_begin_image(xdev, pim->Width, pim->Height,
+ (uint)(pim->Width * mat.xx),
+ (uint)(pim->Height * mat.yy));
+ }
+ return 0;
+}
+
+/* Process the next piece of an image. */
+private int
+pclxl_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ pclxl_image_enum_t *pie = info;
+
+ if ( pie->default_info )
+ return gx_default_image_data(dev, pie->default_info, planes, data_x,
+ raster, height);
+ if ( height > pie->h - pie->y )
+ height = pie->h - pie->y;
+ pclxl_write_image_data(xdev, planes[0], data_x * pie->bits_per_pixel,
+ raster, pie->bits_per_row, pie->y, height);
+ return (pie->y += height) >= pie->h;
+}
+
+/* Clean up by releasing the buffers. */
+private int
+pclxl_end_image(gx_device *dev, void *info, bool draw_last)
+{ pclxl_image_enum_t *pie = info;
+ int code = 0;
+
+ if ( pie->default_info )
+ code = gx_default_end_image(dev, pie->default_info, draw_last);
+ else
+ { /* Fill out to the full image height. */
+ /****** WRONG -- REST OF IMAGE SHOULD BE TRANSPARENT ******/
+ if ( pie->h > pie->y )
+ { uint bytes_per_row = (pie->bits_per_row + 7) >> 3;
+ byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
+ "pclxl_end_image(fill)");
+
+ if ( row == 0 )
+ return_error(gs_error_VMerror);
+ memset(row, 0, bytes_per_row);
+ for ( ; pie->y < pie->h; pie->y++ )
+ pclxl_write_image_data(xdev, row, 0, bytes_per_row,
+ pie->bits_per_row, pie->y, 1);
+ gs_free_object(pie->memory, row, "pclxl_end_image(fill)");
+ }
+ pclxl_write_end_image(xdev);
+ }
+ gs_free_object(pie->memory, pie, "pclxl_end_image");
+ return code;
+}
+
+#undef vdev
diff --git a/gs/src/gdevpxat.h b/gs/src/gdevpxat.h
new file mode 100644
index 000000000..305dfa7da
--- /dev/null
+++ b/gs/src/gdevpxat.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpxat.h */
+/* Attribute ID definitions for PCL XL */
+
+#ifndef gdevpxat_INCLUDED
+# define gdevpxat_INCLUDED
+
+typedef enum {
+
+ pxaPaletteDepth = 2,
+ pxaColorSpace,
+ pxaNullBrush,
+ pxaNullPen,
+ pxaPaletteData,
+
+ pxaPatternSelectID = 8,
+ pxaGrayLevel,
+
+ pxaRGBColor = 11,
+ pxaPatternOrigin,
+ pxaNewDestinationSize,
+
+ pxaDeviceMatrix = 33,
+ pxaDitherMatrixDataType,
+ pxaDitherOrigin,
+ pxaMediaDestination,
+ pxaMediaSize,
+ pxaMediaSource,
+ pxaMediaType,
+ pxaOrientation,
+ pxaPageAngle,
+ pxaPageOrigin,
+ pxaPageScale,
+ pxaROP3,
+ pxaTxMode,
+
+ pxaCustomMediaSize = 47,
+ pxaCustomMediaSizeUnits,
+ pxaPageCopies,
+ pxaDitherMatrixSize,
+ pxaDitherMatrixDepth,
+ pxaSimplexPageMode,
+ pxaDuplexPageMode,
+ pxaDuplexPageSide,
+
+ pxaArcDirection = 65,
+ pxaBoundingBox,
+ pxaDashOffset,
+ pxaEllipseDimension,
+ pxaEndPoint,
+ pxaFillMode,
+ pxaLineCapStyle,
+ pxaLineJoinStyle,
+ pxaMiterLength,
+ pxaLineDashStyle,
+ pxaPenWidth,
+ pxaPoint,
+ pxaNumberOfPoints,
+ pxaSolidLine,
+ pxaStartPoint,
+ pxaPointType,
+ pxaControlPoint1,
+ pxaControlPoint2,
+ pxaClipRegion,
+ pxaClipMode,
+
+ pxaColorDepth = 98,
+ pxaBlockHeight,
+ pxaColorMapping,
+ pxaCompressMode,
+ pxaDestinationBox,
+ pxaDestinationSize,
+ pxaPatternPersistence,
+ pxaPatternDefineID,
+
+ pxaSourceHeight = 107,
+ pxaSourceWidth,
+ pxaStartLine,
+
+ pxaNumberOfScanLines = 115,
+
+ pxaCommentData = 129,
+ pxaDataOrg,
+
+ pxaMeasure = 134,
+
+ pxaSourceType = 136,
+ pxaUnitsPerMeasure,
+
+ pxaStreamName = 139,
+ pxaStreamDataLength,
+
+ pxaErrorReport = 143,
+
+ pxaCharAngle = 161,
+ pxaCharCode,
+ pxaCharDataSize,
+ pxaCharScale,
+ pxaCharShear,
+ pxaCharSize,
+ pxaFontHeaderLength,
+ pxaFontName,
+ pxaFontFormat,
+ pxaSymbolSet,
+ pxaTextData,
+ pxaCharSubModeArray,
+
+ pxaXSpacingData = 175,
+ pxaYSpacingData,
+ pxaCharBoldValue,
+
+ px_attribute_next
+
+} px_attribute_t;
+
+#endif /* gdevpxat_INCLUDED */
diff --git a/gs/src/gdevpxen.h b/gs/src/gdevpxen.h
new file mode 100644
index 000000000..88d547896
--- /dev/null
+++ b/gs/src/gdevpxen.h
@@ -0,0 +1,239 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpxen.h */
+/* Enumerated attribute value definitions for PCL XL */
+
+#ifndef gdevpxen_INCLUDED
+# define gdevpxen_INCLUDED
+
+typedef enum {
+ eClockWise = 0,
+ eCounterClockWise,
+ pxeArcDirection_next
+} pxeArcDirection_t;
+
+typedef enum {
+ eNoSubstitution = 0,
+ eVerticalSubstitution,
+ pxeCharSubModeArray_next
+} pxeCharSubModeArray_t;
+
+typedef enum {
+ eNonZeroWinding = 0,
+ eEvenOdd,
+ pxeClipMode_next,
+ pxeFillMode_next = pxeClipMode_next /* see pxeFillMode_t below */
+} pxeClipMode_t;
+
+typedef enum {
+ eInterior = 0,
+ eExterior,
+ pxeClipRegion_next
+} pxeClipRegion_t;
+
+typedef enum {
+ e1Bit = 0,
+ e4Bit,
+ e8Bit,
+ pxeColorDepth_next
+} pxeColorDepth_t;
+
+typedef enum {
+ eDirectPixel = 0,
+ eIndexedPixel,
+ pxeColorMapping_next
+} pxeColorMapping_t;
+
+typedef enum {
+ eNoColorSpace = 0, /* Note: for this enumeration only, 0 is not a valid value! */
+ eGray,
+ eRGB,
+ pxeColorSpace_next
+} pxeColorSpace_t;
+
+typedef enum {
+ eNoCompression = 0,
+ eRLECompression,
+ pxeCompressMode_next
+} pxeCompressMode_t;
+
+typedef enum {
+ eBinaryHighByteFirst = 0,
+ eBinaryLowByteFirst,
+ pxeDataOrg_next /* is this DataOrg or DataOrganization? */
+} pxeDataOrg_t;
+
+typedef enum {
+ eDefault = 0, /* bad choice of name! */
+ pxeDataSource_next
+} pxeDataSource_t;
+
+typedef enum {
+ eUByte = 0,
+ eSByte,
+ eUInt16,
+ eSInt16,
+ pxeDataType_next
+} pxeDataType_t;
+
+typedef enum {
+ eDownloaded = -1, /* Not a real value, indicates a downloaded matrix */
+ eDeviceBest = 0,
+ pxeDitherMatrix_next
+} pxeDitherMatrix_t;
+
+typedef enum {
+ eDuplexHorizontalBinding = 0,
+ eDuplexVerticalBinding,
+ pxeDuplexPageMode_next
+} pxeDuplexPageMode_t;
+
+typedef enum {
+ eFrontMediaSide = 0,
+ eBackMediaSide,
+ pxeDuplexPageSide_next
+} pxeDuplexPageSide_t;
+
+typedef enum {
+ /* Several pieces of code know that this is a bit mask. */
+ eNoReporting = 0,
+ eBackChannel,
+ eErrorPage,
+ eBackChAndErrPage,
+ pxeErrorReport_next
+} pxeErrorReport_t;
+
+typedef pxeClipMode_t pxeFillMode_t;
+
+typedef enum {
+ eButtCap = 0,
+ eRoundCap,
+ eSquareCap,
+ eTriangleCap,
+ pxeLineCap_next
+} pxeLineCap_t;
+#define pxeLineCap_to_library\
+ { gs_cap_butt, gs_cap_round, gs_cap_square, gs_cap_triangle }
+
+typedef enum {
+ eMiterJoin = 0,
+ eRoundJoin,
+ eBevelJoin,
+ eNoJoin,
+ pxeLineJoin_next
+} pxeLineJoin_t;
+#define pxeLineJoin_to_library\
+ { gs_join_miter, gs_join_round, gs_join_bevel, gs_join_none }
+
+typedef enum {
+ eInch = 0,
+ eMillimeter,
+ eTenthsOfAMillimeter,
+ pxeMeasure_next
+} pxeMeasure_t;
+#define pxeMeasure_to_points { 72.0, 72.0 / 25.4, 72.0 / 254.0 }
+
+/**** MediaDestination is not documented. ****/
+typedef enum {
+ eDefaultDestination = 0,
+ pxeMediaDestination_next
+} pxeMediaDestination_t;
+
+typedef enum {
+ eLetterPaper = 0,
+ eLegalPaper,
+ eA4Paper,
+ eExecPaper,
+ eLedgerPaper,
+ eA3Paper,
+ eCOM10Envelope,
+ eMonarchEnvelope,
+ eC5Envelope,
+ eDLEnvelope,
+ eJB4Paper,
+ eJB5Paper,
+ eB5Envelope,
+ eJPostcard,
+ eJDoublePostcard,
+ eA5Paper,
+ pxeMediaSize_next
+} pxeMediaSize_t;
+
+/*
+ * Apply a macro (or procedure) to all known paper sizes.
+ * The arguments are:
+ * media size code, resolution for width/height, width, height.
+ */
+#define px_enumerate_media(m)\
+ m(eLetterPaper, 300, 2550, 3300)\
+ m(eLegalPaper, 300, 2550, 5300)\
+ m(eA4Paper, 300, 2480, 3507)\
+ m(eExecPaper, 300, 2175, 3150)\
+ m(eLedgerPaper, 300, 3300, 5100)\
+ m(eA3Paper, 300, 3507, 4960)\
+ m(eCOM10Envelope, 300, 1237, 2850)\
+ m(eMonarchEnvelope, 300, 1162, 2250)\
+ m(eC5Envelope, 300, 1913, 2704)\
+ m(eDLEnvelope, 300, 1299, 2598)\
+ m(eB5Envelope, 300, 2078, 2952)
+
+typedef enum {
+ eDefaultSource = 0,
+ eAutoSelect,
+ eManualFeed,
+ eMultiPurposeTray,
+ eUpperCassette,
+ eLowerCassette,
+ eEnvelopeTray,
+ pxeMediaSource_next
+} pxeMediaSource_t;
+
+/**** MediaType is not documented. ****/
+typedef enum {
+ eDefaultType = 0,
+ pxeMediaType_next
+} pxeMediaType_t;
+
+typedef enum {
+ ePortraitOrientation = 0,
+ eLandscapeOrientation,
+ eReversePortrait,
+ eReverseLandscape,
+ pxeOrientation_next
+} pxeOrientation_t;
+
+typedef enum {
+ eTempPattern = 0,
+ ePagePattern,
+ eSessionPattern,
+ pxePatternPersistence_next
+} pxePatternPersistence_t;
+
+typedef enum {
+ eSimplexFrontSide = 0,
+ pxeSimplexPageMode_next
+} pxeSimplexPageMode_t;
+
+typedef enum {
+ eOpaque = 0,
+ eTransparent,
+ pxeTxMode_next
+} pxeTxMode_t;
+
+#endif /* gdevpxen_INCLUDED */
diff --git a/gs/src/gdevpxop.h b/gs/src/gdevpxop.h
new file mode 100644
index 000000000..39832c4c6
--- /dev/null
+++ b/gs/src/gdevpxop.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevpxop.h */
+/* Operator and other tag definitions for PCL XL */
+
+#ifndef gdevpxop_INCLUDED
+# define gdevpxop_INCLUDED
+
+typedef enum {
+/*0x*/
+ pxtNull = 0x00, pxt01, pxt02, pxt03,
+ pxt04, pxt05, pxt06, pxt07,
+ pxt08, pxtHT, pxtLF, pxtVT,
+ pxtFF, pxtCR, pxt0e, pxt0f,
+/*1x*/
+ pxt10, pxt11, pxt12, pxt13,
+ pxt14, pxt15, pxt16, pxt17,
+ pxt18, pxt19, pxt1a, pxt1b,
+ pxt1c, pxt1d, pxt1e, pxt1f,
+/*2x*/
+ pxtSpace, pxt21, pxt22, pxt23,
+ pxt24, pxt25, pxt26, pxt_beginASCII,
+ pxt_beginBinaryMSB, pxt_beginBinaryLSB, pxt2a, pxt2b,
+ pxt2c, pxt2d, pxt2e, pxt2f,
+/*3x*/
+ pxt30, pxt31, pxt32, pxt33,
+ pxt34, pxt35, pxt36, pxt37,
+ pxt38, pxt39, pxt3a, pxt3b,
+ pxt3c, pxt3d, pxt3e, pxt3f,
+/*4x*/
+ pxt40, pxtBeginSession, pxtEndSession, pxtBeginPage,
+ pxtEndPage, pxt45, pxt46, pxtComment,
+ pxtOpenDataSource, pxtCloseDataSource, pxt4a, pxt4b,
+ pxt4c, pxt4d, pxt4e, pxtBeginFontHeader,
+/*5x*/
+ pxtReadFontHeader, pxtEndFontHeader, pxtBeginChar, pxtReadChar,
+ pxtEndChar, pxtRemoveFont, pxt56, pxt57,
+ pxt58, pxt59, pxt5a, pxtBeginStream,
+ pxtReadStream, pxtEndStream, pxtExecStream, pxt5f,
+/*6x*/
+ pxtPopGS, pxtPushGS, pxtSetClipReplace, pxtSetBrushSource,
+ pxtSetCharAngle, pxtSetCharScale, pxtSetCharShear, pxtSetClipIntersect,
+ pxtSetClipRectangle, pxtSetClipToPage, pxtSetColorSpace, pxtSetCursor,
+ pxtSetCursorRel, pxtSetHalftoneMethod, pxtSetFillMode, pxtSetFont,
+/*7x*/
+ pxtSetLineDash, pxtSetLineCap, pxtSetLineJoin, pxtSetMiterLimit,
+ pxtSetPageDefaultCTM, pxtSetPageOrigin, pxtSetPageRotation, pxtSetPageScale,
+ pxtSetPaintTxMode, pxtSetPenSource, pxtSetPenWidth, pxtSetROP,
+ pxtSetSourceTxMode, pxtSetCharBoldValue, pxt7e, pxtSetClipMode,
+/*8x*/
+ pxtSetPathToClip, pxtSetCharSubMode, pxt82, pxt83,
+ pxtCloseSubPath, pxtNewPath, pxtPaintPath, pxt87,
+ pxt88, pxt89, pxt8a, pxt8b,
+ pxt8c, pxt8d, pxt8e, pxt8f,
+/*9x*/
+ pxt90, pxtArcPath, pxt92, pxtBezierPath,
+ pxt94, pxtBezierRelPath, pxtChord, pxtChordPath,
+ pxtEllipse, pxtEllipsePath, pxt9a, pxtLinePath,
+ pxt9c, pxtLineRelPath, pxtPie, pxtPiePath,
+/*ax*/
+ pxtRectangle, pxtRectanglePath, pxtRoundRectangle, pxtRoundRectanglePath,
+ pxta4, pxta5, pxta6, pxta7,
+ pxtText, pxtTextPath, pxtaa, pxtab,
+ pxtac, pxtad, pxtae, pxtaf,
+/*bx*/
+ pxtBeginImage, pxtReadImage, pxtEndImage, pxtBeginRastPattern,
+ pxtReadRastPattern, pxtEndRastPattern, pxtBeginScan, pxtb7,
+ pxtEndScan, pxtScanLineRel, pxtba, pxtbb,
+ pxtbc, pxtbd, pxtbe, pxtbf,
+/*cx*/
+ pxt_ubyte, pxt_uint16, pxt_uint32, pxt_sint16,
+ pxt_sint32, pxt_real32, pxtc6, pxtc7,
+ pxt_ubyte_array, pxt_uint16_array, pxt_uint32_array, pxt_sint16_array,
+ pxt_sint32_array, pxt_real32_array, pxtce, pxtcf,
+/*dx*/
+ pxt_ubyte_xy, pxt_uint16_xy, pxt_uint32_xy, pxt_sint16_xy,
+ pxt_sint32_xy, pxt_real32_xy, pxtd6, pxtd7,
+ pxtd8, pxtd9, pxtda, pxtdb,
+ pxtdc, pxtdd, pxtde, pxtdf,
+/*ex*/
+ pxt_ubyte_box, pxt_uint16_box, pxt_uint32_box, pxt_sint16_box,
+ pxt_sint32_box, pxt_real32_box, pxte6, pxte7,
+ pxte8, pxte9, pxtea, pxteb,
+ pxtec, pxted, pxtee, pxtef,
+/*fx*/
+ pxtf0, pxtf1, pxtf2, pxtf3,
+ pxtf4, pxtf5, pxtf6, pxtf7,
+ pxt_attr_ubyte, pxt_attr_uint16, pxt_dataLength, pxt_dataLengthByte,
+ pxtfc, pxtfd, pxtfe, pxtff
+} px_tag_t;
+
+#endif /* gdevpxop_INCLUDED */
diff --git a/gs/src/gdevrrgb.c b/gs/src/gdevrrgb.c
new file mode 100644
index 000000000..7e7d893ec
--- /dev/null
+++ b/gs/src/gdevrrgb.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevrrgb.c */
+/* RGB device with "render algorithm" */
+#include "gdevprn.h"
+
+/*
+ * This is a 32-bit device in which each pixel holds 24 bits of RGB and 8
+ * (actually 4) bits of "render algorithm". It is not useful in itself, but
+ * it is a good example of (1) how to handle "render algorithm" information
+ * and (2) how to implement a printer device with a non-standard memory
+ * device as its underlying buffer.
+ */
+
+/* Define default device parameters. */
+#ifndef X_DPI
+# define X_DPI 300
+#endif
+#ifndef Y_DPI
+# define Y_DPI 300
+#endif
+
+/* The device descriptor */
+private dev_proc_open_device(rrgb_open);
+private dev_proc_map_rgb_color(rrgb_map_rgb_color);
+private dev_proc_map_color_rgb(rrgb_map_color_rgb);
+private dev_proc_print_page(rrgb_print_page);
+private const gx_device_procs rrgb_procs =
+ prn_color_procs(rrgb_open, gdev_prn_output_page, gdev_prn_close,
+ rrgb_map_rgb_color, rrgb_map_color_rgb);
+
+gx_device_printer far_data gs_rrgb_device =
+{ prn_device_body(gx_device_printer, rrgb_procs, "rrgb",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 3,32,255,255,256,256, rrgb_print_page)
+};
+
+/* Buffer device implementation */
+private dev_proc_make_buffer_device(rrgb_make_buffer_device);
+private dev_proc_strip_copy_rop(rrgb_strip_copy_rop);
+
+#define ppdev ((gx_device_printer *)pdev)
+
+/* Open the device. We redefine this only so we can reset */
+/* make_buffer_device. */
+private int
+rrgb_open(gx_device *pdev)
+{ ppdev->printer_procs.make_buffer_device = rrgb_make_buffer_device;
+ return gdev_prn_open(pdev);
+}
+
+/* Color mapping */
+private gx_color_index
+rrgb_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ return gx_color_value_to_byte(b) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(r) << 16);
+}
+private int
+rrgb_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ prgb[0] = gx_color_value_from_byte((color >> 16) & 0xff);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[2] = gx_color_value_from_byte(color & 0xff);
+ return 0;
+}
+
+/* Print the page. Just copy the bits to the file. */
+private int
+rrgb_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ /* Just dump the bits on the file. */
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ byte *in = (byte *)gs_malloc(line_size, 1, "rrgb_print_page");
+ int lnum;
+
+ if ( in == 0 )
+ return_error(gs_error_VMerror);
+ for ( lnum = 0; lnum < pdev->height; ++lnum )
+ { byte *data;
+ gdev_prn_get_bits(pdev, lnum, in, &data);
+ fwrite(data, 1, line_size, prn_stream);
+ }
+ gs_free((char *)in, line_size, 1, "rrgb_print_page");
+ return 0;
+}
+
+/* Reimplement the buffer device so that it stores the "render algorithm" */
+/* in the top byte of each pixel. */
+private int
+rrgb_make_buffer_device(gx_device_memory *mdev,
+ gx_device *target, gs_memory_t *mem, bool for_band)
+{ int code = gx_default_make_buffer_device(mdev, target, mem, for_band);
+
+ if ( code < 0 )
+ return code;
+ mdev->std_procs.strip_copy_rop = rrgb_strip_copy_rop;
+ return code;
+}
+
+/* Reimplement copy_rop so it saves the "render algorithm". */
+/* This is messy: we have to copy each (partial) scan line from the */
+/* 32-bit representation into a 24-bit buffer, do the operation, */
+/* and then write it back. The code is modeled on the default */
+/* implementation in gdevmrop.c (q.v.). */
+private void
+rrgb_copy_4to3(byte *dest, const byte *src, int width)
+{ const byte *p = src;
+ byte *q = dest;
+ int n;
+
+ for ( n = width; n > 0; p += 4, q += 3, --n )
+ q[0] = p[1], q[1] = p[2], q[2] = p[3];
+}
+private void
+rrgb_copy_3to4(byte *dest, const byte *src, int width, byte upper)
+{ const byte *p = src;
+ byte *q = dest;
+ int n;
+
+ for ( n = width; n > 0; p += 3, q += 4, --n )
+ q[0] = upper, q[1] = p[0], q[2] = p[1], q[3] = p[2];
+}
+int
+rrgb_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gs_rop3_t rop = lop_rop(lop);
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(24);
+ gs_memory_t *mem = &gs_memory_default;
+ gx_device_memory mdev;
+ bool
+ uses_d = rop3_uses_D(rop),
+ copy_s = rop3_uses_S(rop) && scolors == NULL,
+ copy_t = rop3_uses_T(rop) && tcolors == NULL;
+ byte *srow = 0;
+ byte *trow = 0;
+ const byte *srdata;
+ int sx;
+ gx_strip_bitmap tsubst;
+ const gx_strip_bitmap *tptr;
+ int tx;
+ int code;
+ int py;
+
+ gs_make_mem_device(&mdev, mdproto, 0, -1, dev);
+ mdev.width = width;
+ mdev.height = 1;
+ mdev.bitmap_memory = mem;
+ code = (*dev_proc(&mdev, open_device))((gx_device *)&mdev);
+ if ( code < 0 )
+ return code;
+ if ( copy_s )
+ { srow = gs_alloc_bytes(mem, width * 3, "rrgb source buffer");
+ if ( srow == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto x;
+ }
+ }
+ if ( copy_t )
+ { trow = gs_alloc_bytes(mem, textures->rep_width * 3,
+ "rrgb texture buffer");
+ if ( trow == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto x;
+ }
+ }
+ for ( py = y; py < y + height; ++py )
+ { byte *ddata = scan_line_base((gx_device_memory *)dev, y) + x * 4;
+
+ if ( uses_d )
+ { rrgb_copy_4to3(scan_line_base(&mdev, 0), ddata, width);
+ }
+ if ( copy_s )
+ { rrgb_copy_4to3(srow, sdata + sourcex * 4, width);
+ srdata = srow, sx = 0;
+ }
+ else
+ srdata = sdata + y * sraster, sx = sourcex;
+ if ( copy_t )
+ { tsubst = *textures;
+ rrgb_copy_4to3(trow,
+ tsubst.data + ((py + phase_y) %
+ tsubst.rep_height) * tsubst.raster,
+ textures->rep_width);
+ tsubst.data = trow;
+ tsubst.size.x = tsubst.rep_width;
+ tsubst.size.y = 1;
+ tsubst.id = gx_no_bitmap_id;
+ tsubst.rep_height = 1;
+ tx = py / tsubst.rep_height * tsubst.rep_shift;
+ tptr = &tsubst;
+ }
+ else
+ tptr = textures, tx = 0;
+ code = (*dev_proc(&mdev, strip_copy_rop))((gx_device *)&mdev,
+ srdata, sx, 0 /*unused*/, gx_no_bitmap_id, scolors,
+ tptr, tcolors, 0, 0, width, 1,
+ phase_x + tx, phase_y + py, lop);
+ if ( code < 0 )
+ break;
+ rrgb_copy_3to4(ddata, scan_line_base(&mdev, 0), width,
+ (lop >> lop_ral_shift) & lop_ral_mask);
+ }
+x: gs_free_object(mem, trow, "rrgb texture buffer");
+ gs_free_object(mem, srow, "rrgb source buffer");
+ (*dev_proc(&mdev, close_device))((gx_device *)&mdev);
+ return code;
+}
diff --git a/gs/src/gdevrun.c b/gs/src/gdevrun.c
new file mode 100644
index 000000000..eec8737e5
--- /dev/null
+++ b/gs/src/gdevrun.c
@@ -0,0 +1,434 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevrun.c */
+/* Run-length encoded "device" */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/*
+ * The pseudo-device in this file stores 8-bit "pixels" with run-length
+ * encoding. Since it may allocate less space than is required to
+ * store all possible values, it may have to discard some update requests.
+ */
+
+/*
+ * Define the representation of each run. We store runs in a doubly-
+ * linked list using the old trick of storing only a single pointer which
+ * is the xor of the successor and predecessor indices.
+ * Run 0 is a dummy end-of-line run; run 1 is a dummy start-of-line run.
+ * The dummy runs have length 255 to prevent merging.
+ */
+typedef byte run_length;
+typedef byte run_value;
+typedef ushort run_index;
+typedef struct run_s {
+ run_length length;
+ run_value value;
+ run_index nix; /* for allocated runs, xor of successor and */
+ /* predecessor indices; for free runs, */
+ /* index of next free run */
+} run;
+/*
+ * Define a pointer into a run list. The xor trick requires that we
+ * store both the current index and the next (or previous) one.
+ * For speed, we keep both the index of and the pointer to the current run.
+ */
+typedef struct run_ptr_s {
+ run *ptr;
+ run_index index; /* index of current run */
+ run_index next; /* index of next run */
+} run_ptr;
+typedef struct const_run_ptr_s {
+ const run *ptr;
+ run_index index; /* index of current run */
+ run_index next; /* index of next run */
+} const_run_ptr;
+/* Accessors */
+#define rp_length(rp) ((rp).ptr->length)
+#define rp_value(rp) ((rp).ptr->value)
+#define rp_nix(rp) ((rp).ptr->nix)
+/* Traversers */
+#define rp_at_start(rp) ((rp).index == 1)
+#define rp_at_end(rp) ((rp).index == 0)
+#define rp_start(rp, data)\
+ ((rp).index = (data)[1].nix,\
+ (rp).ptr = (data) + (rp).index,\
+ (rp).next = rp_nix(rp) ^ 1)
+/* Note that rp_next and rp_prev allow rpn == rpc. */
+#define rp_next(rpc, data, rpn, itemp)\
+ (itemp = (rpc).index,\
+ (rpn).ptr = (data) + ((rpn).index = (rpc).next),\
+ (rpn).next = itemp ^ rp_nix(rpn))
+#define rp_prev(rpc, data, rpp, itemp)\
+ (itemp = (rpc).next ^ rp_nix(rpc),\
+ (rpp).next = (rpc).index,\
+ (rpp).ptr = (data) + ((rpp).index = itemp))
+/* Insert/delete */
+#define rp_delete_next(rpc, data, line, rpn, rpn2, itemp)\
+ (rp_next(rpc, data, rpn, itemp),\
+ rp_next(rpn, data, rpn2, itemp),\
+ rp_nix(rpc) ^= (rpn).index ^ (rpn2).index,\
+ rp_nix(rpn2) ^= (rpn).index ^ (rpc).index,\
+ rp_nix(rpn) = (line)->free,\
+ (line)->free = (rpn).index)
+#define rp_insert_next(rpc, data, line, rpn, itemp)\
+ (rp_next(rpc, data, rpn, itemp),\
+ itemp = (line)->free,\
+ rp_nix(rpc) ^= (rpn).index ^ itemp,\
+ rp_nix(rpn) ^= (rpc).index ^ itemp,\
+ (rpn).next = (rpn).index,\
+ (rpn).index = itemp,\
+ (rpn).ptr = (data) + itemp,\
+ (line)->free = rp_nix(rpn),\
+ rp_nix(rpn) = (rpc).index ^ (rpn).next)
+#define rp_insert_prev(rpc, data, line, rpp, itemp)\
+ (rp_prev(rpc, data, rpp, itemp),\
+ itemp = (line)->free,\
+ rp_nix(rpc) ^= (rpp).index ^ itemp,\
+ rp_nix(rpp) ^= (rpc).index ^ itemp,\
+ (rpp).ptr = (data) + itemp,\
+ rp_nix(rpp) = (rpp).index ^ (rpc).index,\
+ (rpp).index = itemp,\
+ (line)->free = rp_nix(rpp))
+
+/*
+ * Define the state of a single scan line.
+ *
+ * We maintain the following invariant: if two adjacent runs have the
+ * same value, the sum of their lengths is at least 256. This may miss
+ * optimality by nearly a factor of 2, but it's far easier to maintain
+ * than a true optimal representation.
+ *
+ * For speed in the common case where nothing other than 0 is ever stored,
+ * we initially don't bother to construct the runs (or the free run list)
+ * for a line at all.
+ */
+typedef struct run_line_s {
+ run *data; /* base of runs */
+ int zero; /* 0 if line not initialized, -1 if initialized */
+ uint xcur; /* x value at cursor position */
+ run_ptr rpcur; /* cursor */
+ run_index free; /* head of free list */
+} run_line;
+
+/*
+ * Define the device, built on an 8-bit memory device.
+ */
+typedef struct gx_device_run_s {
+ gx_device_memory md;
+ uint runs_per_line;
+ run_line *lines;
+ int umin, umax1; /* some range of uninitialized lines */
+} gx_device_run;
+
+#define rdev ((gx_device_run *)dev)
+
+/* Open the device. */
+private int
+run_open(gx_device *dev)
+{ run_line *line = rdev->lines;
+ run *data = (run *)rdev->md.base;
+ int i;
+
+ /*
+ * We need ceil(width / 255) runs to represent a line where all
+ * elements have the same value, +2 for the start and end runs,
+ * +2 for the check for 2 free runs when doing a replacement.
+ */
+ if ( rdev->runs_per_line < (dev->width + 254) / 255 + 4 )
+ return_error(gs_error_rangecheck);
+ for ( i = 0; i < dev->height; ++line, data += rdev->runs_per_line, ++i )
+ { line->data = data;
+ line->zero = 0;
+ }
+ rdev->umin = 0;
+ rdev->umax1 = dev->height;
+ return 0;
+}
+
+/* Finish initializing a line. This is a separate procedure only */
+/* for readability. */
+private void
+run_line_initialize(gx_device *dev, int y)
+{ run_line *line = &rdev->lines[y];
+ run *data = line->data;
+ int left = dev->width;
+ run_index index = 2;
+ run *rcur;
+
+ line->zero = -1;
+ data[0].length = 255; /* see above */
+ data[0].value = 0; /* shouldn't matter */
+ data[1].length = 255;
+ data[1].value = 0;
+ data[1].nix = 2;
+ rcur = data + index;
+ for ( ; left > 0; index++, rcur++, left -= 255 )
+ { rcur->length = min(left, 255);
+ rcur->value = 0;
+ rcur->nix = (index - 1) ^ (index + 1);
+ }
+ rcur->nix = index - 2;
+ data[0].nix = index - 1;
+ line->xcur = 0;
+ line->rpcur.ptr = data + 2;
+ line->rpcur.index = 2;
+ line->rpcur.next = data[2].nix ^ 1;
+ line->free = index;
+ for ( ; index < rdev->runs_per_line; ++index )
+ data[index].nix = index + 1;
+ data[index - 1].nix = 0;
+ if ( y >= rdev->umin && y < rdev->umax1 )
+ { if ( y > (rdev->umin + rdev->umax1) >> 1 )
+ rdev->umax1 = y;
+ else
+ rdev->umin = y + 1;
+ }
+}
+
+/* Replace an interval of a line with a new value. This is the procedure */
+/* that does all the interesting work. We assume the line has been */
+/* initialized, and that 0 <= xo < xe <= dev->width. */
+private int
+run_fill_interval(run_line *line, int xo, int xe, run_value new)
+{ run *data = line->data;
+ int xc = line->xcur;
+ run_ptr rpc;
+ run_index itemp;
+ int x0, x1;
+ run_ptr rp0;
+
+ rpc = line->rpcur;
+
+ /* Find the run that contains xo. */
+
+ if ( xo < xc )
+ { while ( xo < xc )
+ rp_prev(rpc, data, rpc, itemp), xc -= rp_length(rpc);
+ }
+ else
+ { while ( xo >= xc + rp_length(rpc) )
+ xc += rp_length(rpc), rp_next(rpc, data, rpc, itemp);
+ }
+
+ /*
+ * Skip runs above xo that already contain the new value.
+ * If the entire interval already has the correct value, exit.
+ * If we skip any such runs, set xo to just above them.
+ */
+
+ for ( ; !rp_at_end(rpc) && rp_value(rpc) == new;
+ rp_next(rpc, data, rpc, itemp)
+ )
+ if ( (xo = xc += rp_length(rpc)) >= xe )
+ return 0;
+ x0 = xc, rp0 = rpc;
+
+ /* Find the run that contains xe-1. */
+
+ while ( xe > xc + rp_length(rpc) )
+ xc += rp_length(rpc), rp_next(rpc, data, rpc, itemp);
+
+ /*
+ * Skip runs below xe that already contain the new value.
+ * (We know that some run between xo and xe doesn't.)
+ * If we skip any such runs, set xe to just below them.
+ */
+
+ while ( rp_prev(rpc, data, rpc, itemp), rp_value(rpc) == new )
+ xe = xc -= rp_length(rpc);
+ rp_next(rpc, data, rpc, itemp);
+
+ /*
+ * At this point, we know the following:
+ * x0 <= xo < x0 + rp_length(rp0).
+ * rp_value(rp0) != new.
+ * xc <= xe-1 < xc + rp_length(rpc).
+ * rp_value(rpc) != new.
+ * Note that rp0 and rpc may point to the same run.
+ */
+
+ /*
+ * Check that we have enough free runs to do the replacement.
+ * In the worst case, where we have to split existing runs
+ * at both ends of the interval, two new runs are required.
+ * We just check for having at least two free runs, since this
+ * is simple and wastes at most 2 runs.
+ */
+
+ if ( line->free == 0 || data[line->free].nix == 0 )
+ return_error(-1);
+
+ /* Split off any unaffected prefix of the run at rp0. */
+
+ if ( x0 < xo )
+ { uint diff = xo - x0;
+ run_value v0 = rp_value(rp0);
+ run_ptr rpp;
+
+ rp_prev(rp0, data, rpp, itemp);
+ if ( rp_value(rpp) == v0 && rp_length(rpp) + diff <= 255 )
+ rp_length(rpp) += diff;
+ else
+ { rp_insert_prev(rp0, data, line, rpp, itemp);
+ rp_length(rpp) = diff;
+ rp_value(rpp) = v0;
+ }
+ }
+
+ /* Split off any unaffected suffix of the run at rpc. */
+
+ x1 = xc + rp_length(rpc);
+ if ( x1 > xe )
+ { uint diff = x1 - xe;
+ run_value vc = rp_value(rpc);
+ run_ptr rpn;
+
+ rp_next(rpc, data, rpn, itemp);
+ if ( rp_value(rpn) == vc && rp_length(rpn) + diff <= 255 )
+ rp_length(rpn) += diff;
+ else
+ { rp_insert_next(rpc, data, line, rpn, itemp);
+ rp_length(rpn) = diff;
+ rp_value(rpn) = vc;
+ }
+ }
+
+ /* Delete all runs from rp0 through rpc. */
+
+ rp_prev(rp0, data, rp0, itemp);
+ { run_ptr rpn, rpn2;
+ while ( rp0.next != rpc.next )
+ rp_delete_next(rp0, data, line, rpn, rpn2, itemp);
+ }
+
+ /*
+ * Finally, insert new runs with the new value.
+ * We need to check for one boundary case, namely,
+ * xo == x0 and the next lower run has the new value.
+ * (There's probably a way to structure the code just slightly
+ * differently to avoid this test.)
+ */
+
+ { uint left = xe - xo;
+ if ( xo == x0 && rp_value(rp0) == new &&
+ rp_length(rp0) + left <= 255
+ )
+ rp_length(rp0) += left;
+ else
+ { /*
+ * If we need more than one run, we probably should
+ * divide up the length to create more runs with length
+ * less than 255 in order to improve the chances of
+ * a later merge, but we won't bother right now.
+ */
+ do
+ { run_ptr rpn;
+ rp_insert_next(rp0, data, line, rpn, itemp);
+ rp_length(rpn) = min(left, 255);
+ rp_value(rpn) = new;
+ }
+ while ( (left -= 255) > 0 );
+ }
+ }
+
+ return 0;
+}
+
+/* Replace a rectangle with a new value. */
+private int
+run_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ int xe;
+ run_line *line;
+ int ny;
+
+ fit_fill(dev, x, y, w, h);
+ /*
+ * If the new value is 0 and the rectangle falls entirely within
+ * the uninitialized region that we're keeping track of,
+ * we can skip the entire operation.
+ */
+ if ( (byte)color == 0 && y >= rdev->umin && y + h <= rdev->umax1 )
+ return 0;
+
+ xe = x + w;
+ for ( line = &rdev->lines[y], ny = h; ny > 0; ++line, --ny )
+ if ( (byte)color != line->zero )
+ { if ( line->zero == 0 )
+ run_line_initialize(dev, y + h - ny);
+ run_fill_interval(line, x, xe, (byte)color);
+ }
+ return 0;
+}
+
+/* Get a fully expanded scan line. */
+private int
+run_get_bits(gx_device *dev, int y, byte *row, byte **actual_row)
+{ const run_line *line = &rdev->lines[y];
+ const run *data = line->data;
+ const_run_ptr rp;
+ byte *q = *actual_row = row;
+ run_index itemp;
+
+ if ( line->zero == 0 )
+ { memset(row, 0, dev->width);
+ return 0;
+ }
+ for ( rp_start(rp, data); !rp_at_end(rp);
+ rp_next(rp, data, rp, itemp)
+ )
+ { memset(q, rp_value(rp), rp_length(rp));
+ q += rp_length(rp);
+ }
+ return 0;
+}
+
+/* Debugging code */
+
+#ifdef DEBUG
+
+void
+debug_print_run(const run *data, run_index index, const char *prefix)
+{ const run *pr = data + index;
+ dprintf5("%s%5d: length = %3d, value = %3d, nix = %5u\n",
+ prefix, index, pr->length, pr->value, pr->nix);
+}
+
+void
+debug_print_run_line(const run_line *line, const char *prefix)
+{ const run *data = line->data;
+ dprintf5("%sruns at 0x%lx: zero = %d, free = %u, xcur = %u,\n",
+ prefix, (ulong)data, line->zero, line->free, line->xcur);
+ dprintf4("%s rpcur = {ptr = 0x%lx, index = %u, next = %u}\n",
+ prefix, (ulong)line->rpcur.ptr, line->rpcur.index, line->rpcur.next);
+ { const_run_ptr rpc;
+ uint itemp;
+ rp_start(rpc, data);
+ while ( !rp_at_end(rpc) )
+ { debug_print_run(data, rpc.index, prefix);
+ rp_next(rpc, data, rpc, itemp);
+ }
+ }
+}
+
+#endif /* DEBUG */
diff --git a/gs/src/gdevs3ga.c b/gs/src/gdevs3ga.c
new file mode 100644
index 000000000..af6ddbbee
--- /dev/null
+++ b/gs/src/gdevs3ga.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevs3ga.c */
+/* S3 86C911 driver */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevpcfb.h"
+#include "gdevsvga.h"
+
+/* Shared routines from gdevsvga.c */
+extern int vesa_get_mode(P0());
+extern void vesa_set_mode(P1(int));
+
+/* Macro for casting gx_device argument */
+#define fb_dev ((gx_device_svga *)dev)
+
+/* ------ The S3 86C911 device ------ */
+
+private dev_proc_open_device(s3_open);
+private dev_proc_fill_rectangle(s3_fill_rectangle);
+private dev_proc_copy_mono(s3_copy_mono);
+private gx_device_procs s3_procs = {
+ s3_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ svga_close,
+ svga_map_rgb_color,
+ svga_map_color_rgb,
+ s3_fill_rectangle,
+ NULL, /* tile_rectangle */
+ s3_copy_mono,
+ svga_copy_color, /****** DOESN'T WORK ******/
+ NULL, /* draw_line */
+ svga_get_bits /****** DOESN'T WORK ******/
+};
+gx_device_svga far_data gs_s3vga_device =
+ svga_device(s3_procs, "s3vga", vesa_get_mode, vesa_set_mode, NULL);
+
+/* Keep track of the character bitmap cache in off-screen memory. */
+#define log2_cell_width 5
+#define cell_width (1 << log2_cell_width)
+#define cache_x_bits (log2_cache_width_bits - log2_cell_width)
+#define log2_cell_height 5
+#define cell_height (1 << log2_cell_height)
+#define cache_y_bits (log2_cache_height - log2_cell_height)
+#define log2_cache_width_bits 10
+#define log2_cache_width_bytes (log2_cache_width_bits - 3)
+#define log2_cache_height 8
+#define log2_cache_capacity (cache_x_bits + cache_y_bits)
+#define cache_capacity (1 << log2_cache_capacity)
+private gx_bitmap_id cache_ids[cache_capacity];
+
+/* Define additional registers and I/O addresses. */
+#define crtc_addr 0x3d4 /* (color) */
+#define crt_lock 0x35
+#define crt_s3_lock1 0x38
+#define crt_s3_lock2 0x39
+#define s3_y_pos 0x82e8
+#define s3_x_pos 0x86e8
+#define s3_y_dest 0x8ae8
+#define s3_x_dest 0x8ee8
+#define s3_width 0x96e8
+#define s3_status 0x9ae8 /* read only */
+#define s3_command 0x9ae8 /* write only */
+#define s3_back_color 0xa2e8
+#define s3_fore_color 0xa6e8
+#define s3_write_mask 0xaae8
+#define s3_read_mask 0xaee8
+#define s3_back_mix 0xb6e8
+#define s3_fore_mix 0xbae8
+#define s3_height 0xbee8
+#define s3_mf_control 0xbee8
+# define mf_data_ones 0xa000
+# define mf_data_cpu 0xa080
+# define mf_data_display 0xa0c0
+#define s3_pixel_data 0xe2e8
+/* Wait for the command FIFO to empty. */
+#define s3_wait_fifo()\
+ while ( inport(s3_status) & 0xff )
+/* Load the parameters for a rectangle operation. */
+#define out_s3_rect(x, y, w, h)\
+ (outport(s3_x_pos, x), outport(s3_y_pos, y),\
+ outport(s3_width, (w) - 1), outport(s3_height, (h) - 1))
+
+private int
+s3_open(gx_device *dev)
+{ static const mode_info mode_table[] = {
+ { 640, 480, 0x201 },
+ { 800, 600, 0x203 },
+ { 1024, 768, 0x205 },
+ { -1, -1, -1 }
+ };
+ int code = svga_find_mode(dev, mode_table);
+ if ( code < 0 ) return_error(gs_error_rangecheck);
+ /* The enhanced modes all use a 1024-pixel raster. */
+ fb_dev->raster = 1024;
+ code = svga_open(dev);
+ if ( code < 0 ) return code;
+ /* Clear the cache */
+ { int i;
+ for ( i = 0; i < cache_capacity; i++ )
+ cache_ids[i] = gx_no_bitmap_id;
+ }
+ return 0;
+}
+
+/* Fill a rectangle. */
+int
+s3_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ fit_fill(dev, x, y, w, h);
+ s3_wait_fifo();
+ outport(s3_fore_mix, 0x27);
+ outport(s3_fore_color, (int)color);
+ outport(s3_mf_control, mf_data_ones);
+ out_s3_rect(x, y, w, h);
+ outport(s3_command, 0x40b3);
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+private int
+s3_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
+{ int sbit;
+ const byte *sptr;
+ int run;
+ byte lmask;
+ byte lmerge = 0;
+ int cache_index, cache_x, cache_y;
+ int i, j;
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ sbit = sourcex & 7;
+ sptr = base + (sourcex >> 3);
+ run = (sbit + w + 7) >> 3;
+ lmask = 0xff >> sbit;
+ /* See whether the cache is applicable. */
+ if ( id != gx_no_bitmap_id && w <= cell_width - 7 &&
+ h <= cell_height
+ )
+ { cache_index = (int)(id & (cache_capacity - 1));
+ cache_x = ((cache_index & ((1 << cache_x_bits) - 1)) <<
+ log2_cell_width) + 7;
+ cache_y = ((cache_index >> cache_x_bits) <<
+ log2_cell_height) + 768;
+ if ( cache_ids[cache_index] != id )
+ { cache_ids[cache_index] = id;
+ /* Copy the bitmap to the cache. */
+ s3_wait_fifo();
+ out_s3_rect(cache_x - sbit, cache_y, w + sbit, h);
+ outport(s3_fore_mix, 0x22); /* 1s */
+ outport(s3_back_mix, 0x01); /* 0s */
+ outport(s3_mf_control, mf_data_cpu);
+ outport(s3_command, 0x41b3);
+ { const int skip = raster - run;
+ for ( i = h; i > 0; i--, sptr += skip )
+ for ( j = run; j > 0; j--, sptr++ )
+ outportb(s3_pixel_data, *sptr);
+ }
+ }
+ s3_wait_fifo();
+ }
+ else
+ { cache_index = -1;
+ if ( lmask != 0xff )
+ { /* The hardware won't do the masking for us. */
+ if ( czero != gx_no_color_index )
+ { if ( cone != gx_no_color_index )
+ { s3_fill_rectangle(dev, x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ else
+ { lmerge = ~lmask;
+ }
+ }
+ }
+ s3_wait_fifo();
+ out_s3_rect(x - sbit, y, w + sbit, h);
+ }
+ /* Load the colors for the real transfer. */
+ if ( cone != gx_no_color_index )
+ { outport(s3_fore_mix, 0x27);
+ outport(s3_fore_color, (int)cone);
+ }
+ else
+ outport(s3_fore_mix, 0x63);
+ if ( czero != gx_no_color_index )
+ { outport(s3_back_mix, 0x07);
+ outport(s3_back_color, (int)czero);
+ }
+ else
+ outport(s3_back_mix, 0x63);
+ s3_wait_fifo();
+ if ( cache_index < 0 ) /* direct transfer */
+ { outport(s3_mf_control, mf_data_cpu);
+ outport(s3_command, 0x41b3);
+ if ( run == 1 && !lmerge ) /* special case for chars */
+ { for ( i = h; i > 0; i--, sptr += raster )
+ outportb(s3_pixel_data, *sptr & lmask);
+ }
+ else
+ { const int skip = raster - run;
+ for ( i = h; i > 0; i--, sptr += skip )
+ { outportb(s3_pixel_data, (*sptr++ & lmask) | lmerge);
+ for ( j = run; j > 1; j--, sptr++ )
+ outportb(s3_pixel_data, *sptr);
+ }
+ }
+ }
+ else
+ { /* Copy the character from the cache to the screen. */
+ out_s3_rect(cache_x, cache_y, w, h);
+ outport(s3_x_dest, x);
+ outport(s3_y_dest, y);
+ outport(s3_mf_control, mf_data_display);
+ outport(s3_command, 0xc0b3);
+ }
+ return 0;
+}
diff --git a/gs/src/gdevsco.c b/gs/src/gdevsco.c
new file mode 100644
index 000000000..c7e869b87
--- /dev/null
+++ b/gs/src/gdevsco.c
@@ -0,0 +1,275 @@
+/* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsco.c - 17Jul91 - wb - based on gdevpcfb.c */
+/* 31Jul91 - Rick Calder rick@rick.att.com - ifdefs for AT&T UNIX 4.0 2.1 */
+/* 13Sep91 - wb - modify for gs24b2 */
+/* 9Mar92 - wb - modify for gs24b4 */
+/* generate SCO Xenix/Unix style memory mapped ioctl output */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevpcfb.h"
+#include <signal.h>
+
+#ifdef M_XENIX
+#include <sys/console.h> /* SCO Xenix and SCO UNIX */
+#ifndef CONSIO
+#include <sys/machdep.h> /* Xenix needs this also */
+#endif
+#else
+#include <sys/kd.h> /* AT&T SVR4 */
+#endif
+
+#if defined(__STDC__)
+#include "stdlib.h"
+#else
+extern char *getenv(P1(const char *));
+#endif
+
+#if defined(M_XENIX)
+#include "prototypes.h"
+#include "fcntl.h"
+#else
+extern int ioctl(P3(int, int, ...));
+extern int open(P3(const char *, int, ...));
+#endif
+
+private int console_fd = -1; /* file descriptor of console */
+fb_ptr fb_addr; /* address of frame buffer for unix */
+private int cur_mode = -1; /* current video mode */
+
+/* open the console */
+/* possible files to open:
+ * /dev/console = current system console
+ * /dev/vga = vga monitor
+ * /dev/tty = current terminal
+ */
+
+private void open_console(P1(void));
+
+private void
+open_console()
+{
+ const char *dev;
+ if (console_fd != -1) return;
+ dev = getenv("GSDEVICE");
+ if (dev == NULL || *dev == '\0')
+ dev = "/dev/tty";
+ console_fd = open(dev, 0);
+ if (console_fd == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf1("unable to map display '%s'\n", dev);
+ perror("open_console");
+ exit(1);
+ }
+}
+
+#if defined(__GNUC__)
+ /* Done with inline assembly in gdevpcfb.h */
+#else
+/* Output to a port */
+void
+outportb(uint port, byte data)
+{
+ int i;
+ struct port_io_arg pio;
+
+ if (console_fd == -1) open_console();
+ pio.args[0].dir = OUT_ON_PORT;
+ pio.args[0].port = port;
+ pio.args[0].data = data;
+ pio.args[1].port = 0;
+ pio.args[2].port = 0;
+ pio.args[3].port = 0;
+ i = ioctl(console_fd, CONSIO, (long)(&pio));
+ if (i == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf("error setting device register\n");
+ perror("outportb");
+ exit(1);
+ }
+}
+
+/* Output to 2 consecutive ports */
+void
+outport2(uint port, byte index, byte data)
+{
+ int i;
+ struct port_io_arg pio;
+
+ if (console_fd == -1) open_console();
+ pio.args[0].dir = OUT_ON_PORT;
+ pio.args[0].port = port;
+ pio.args[0].data = index;
+ pio.args[1].dir = OUT_ON_PORT;
+ pio.args[1].port = port + 1;
+ pio.args[1].data = data;
+ pio.args[2].port = 0;
+ pio.args[3].port = 0;
+ i = ioctl(console_fd, CONSIO, (long)(&pio));
+ if (i == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf("error setting device register\n");
+ perror("outport2");
+ exit(1);
+ }
+}
+#endif
+
+/* interrupt signal handler */
+/* restore the video mode and exit */
+private void
+ega_int_handler(int sig)
+{
+ ega_close((gx_device *)NULL);
+ eprintf("GS exiting...\n");
+ exit(1);
+}
+
+/*
+ * FIXME to make this work, the SIGCONT handler must restore the
+ * the video state, including all the registers.
+ * For now, I made the SIGSTOP handler exit just call the SIGINT handler
+ */
+
+#ifdef SIGTSTP
+/* user tried to stop us. restore video and stop */
+private void
+ega_tstp_handler(int sig)
+{
+#if 1
+ ega_int_handler(sig);
+#else
+ /* Preferable, but sco does not restore the monitor corretly */
+ signal(SIGTSTP, ega_tstp_handler);
+ ega_close((gx_device *)NULL);
+ eprintf("GS stopping...\n");
+ signal(SIGSTOP,SIG_DFL);
+ kill(getpid(), SIGSTOP);
+#endif
+}
+#endif /* SIGTSTP */
+
+#ifdef SIGCONT
+/* we were unstopped. reopen video */
+private void
+ega_cont_handler(int sig)
+{
+#if 1
+ ega_int_handler(sig);
+#else
+ signal(SIGCONT, ega_cont_handler);
+ ega_set_mode(cur_mode);
+#endif
+}
+#endif /* SIGCONT */
+
+/* ------ Internal routines ------ */
+
+/* Catch signals so we can restore the video mode on exit. */
+void
+pcfb_set_signals(gx_device *dev)
+{ signal(SIGINT, ega_int_handler);
+ signal(SIGTERM, ega_int_handler);
+#ifdef SIGTSTP
+ signal(SIGTSTP, ega_tstp_handler);
+#endif
+#ifdef SIGCONT
+ signal(SIGCONT, ega_cont_handler);
+#endif
+}
+
+/* Read the device mode */
+void
+pcfb_get_state(pcfb_bios_state *pbs)
+{ int mode;
+ open_console();
+ mode = ioctl(console_fd, CONS_CURRENT, 0L);
+ if (mode == -1) {
+#ifdef __linux__
+ mode = M_ENH_C80x25;
+#else
+ ega_close((gx_device *)NULL);
+ eprintf("unable to get current console mode\n");
+ perror("pcfb_get_state");
+ exit(1);
+#endif
+ }
+ pbs->display_mode =
+ (mode == M_ENH_CG640 || mode == M_CG640x350 ? 0x10 :
+#ifdef M_VGA12
+ mode == M_VGA12 ? 0x12 :
+#endif
+ 0x03);
+}
+
+/* Set the device mode */
+void
+pcfb_set_mode(int mode)
+{ int i, mode1;
+ open_console();
+ cur_mode = mode;
+ mode1 = -1;
+ if (mode == 0x10) mode = SW_ENH_CG640;
+#ifdef SW_VGA12
+ else if (mode == 0x12) mode = SW_VGA12;
+#endif
+ else if (mode == 0x03) {
+#ifdef SW_VGA80x25
+ mode = SW_VGA80x25; mode1 = SW_ENHC80x25;
+#else
+ mode = SW_ENHC80x25;
+#endif
+ } else {
+ eprintf1("can not set to video mode %d\n", mode);
+ exit(1);
+ }
+ i = ioctl(console_fd, mode, 0L);
+ if (i == -1 && mode1 != -1)
+ i = ioctl(console_fd, mode1, 0L);
+ if (i == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf("unable to set console mode\n");
+ perror("pcfb_set_mode");
+ exit(1);
+ }
+#ifdef VGA_IOPRIVL
+ if (ioctl(console_fd, VGA_IOPRIVL, 1) == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf("unable to get I/O privilege\n");
+ perror("pcfb_set_mode");
+ exit(1);
+ }
+#endif
+ i = ioctl(console_fd, MAPCONS, 0L);
+ if (i == -1) {
+ ega_close((gx_device *)NULL);
+ eprintf("unable to map console adaptor's display memory\n");
+ perror("pcfb_set_mode");
+ exit(1);
+ }
+ fb_addr = (fb_ptr) (i);
+}
+
+/* Restore the device state */
+void
+pcfb_set_state(const pcfb_bios_state *pbs)
+{ pcfb_set_mode(pbs->display_mode);
+}
diff --git a/gs/src/gdevsgi.c b/gs/src/gdevsgi.c
new file mode 100644
index 000000000..a87f9e3ab
--- /dev/null
+++ b/gs/src/gdevsgi.c
@@ -0,0 +1,220 @@
+/*
+ * This file is distributed with Ghostscript, but its author,
+ * Tanmoy Bhattacharya (tanmoy@qcd.lanl.gov) hereby places it in the
+ * public domain.
+ */
+
+/* gdevsgi.c */
+/* SGI raster file driver */
+#include "gdevprn.h"
+#include "gdevsgi.h"
+
+#define X_DPI 72
+#define Y_DPI 72
+
+#define sgi_prn_device(procs, dev_name, num_comp, depth, max_gray, max_color, print_page)\
+{prn_device_body(gx_device_printer, procs, dev_name, \
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, \
+ 0, 0, 0, 0, \
+ num_comp, depth, max_gray, max_color, max_gray+1, max_color+1, \
+ print_page)}
+
+private dev_proc_map_rgb_color(sgi_map_rgb_color);
+private dev_proc_map_color_rgb(sgi_map_color_rgb);
+
+private dev_proc_print_page(sgi_print_page);
+
+private gx_device_procs sgi_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ sgi_map_rgb_color, sgi_map_color_rgb);
+
+gx_device_printer far_data gs_sgirgb_device =
+ sgi_prn_device(sgi_procs, "sgirgb", 3, 24, 255, 255, sgi_print_page);
+
+private gx_color_index
+sgi_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
+{ ushort bitspercolor = dev->color_info.depth / 3;
+ ulong max_value = (1 << bitspercolor) - 1;
+ return ((r*max_value / gx_max_color_value) << (bitspercolor * 2)) +
+ ((g*max_value / gx_max_color_value) << bitspercolor) +
+ (b*max_value / gx_max_color_value);
+}
+
+private int
+sgi_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
+{ ushort bitspercolor = dev->color_info.depth / 3;
+ ushort colormask = (1 << bitspercolor) - 1;
+
+ prgb[0] = ((color >> (bitspercolor * 2)) & colormask) *
+ (ulong)gx_max_color_value / colormask;
+ prgb[1] = ((color >> bitspercolor) & colormask) *
+ (ulong)gx_max_color_value / colormask;
+ prgb[2] = (color & colormask) *
+ (ulong)gx_max_color_value / colormask;
+ return 0;
+}
+
+typedef struct sgi_cursor_s {
+ gx_device_printer *dev;
+ int bpp;
+ uint line_size;
+ byte *data;
+ int lnum;
+} sgi_cursor;
+
+private int
+sgi_begin_page(gx_device_printer *bdev, FILE *pstream, sgi_cursor _ss *pcur)
+{
+ uint line_size = gdev_mem_bytes_per_scan_line((gx_device_printer*)bdev);
+ byte *data = (byte*)gs_malloc(line_size, 1, "sgi_begin_page");
+ IMAGE *header= (IMAGE*)gs_malloc(sizeof(IMAGE),1,"sgi_begin_page");
+ char filler= '\0';
+ int i;
+
+ if ((data == (byte*)0)||(header == (IMAGE*)0)) return -1;
+
+ bzero(header,sizeof(IMAGE));
+ header->imagic = IMAGIC;
+ header->type = RLE(1);
+ header->dim = 3;
+ header->xsize=bdev->width;
+ header->ysize=bdev->height;
+ header->zsize=3;
+ header->min_color = 0;
+ header->max_color = bdev->color_info.max_color;
+ header->wastebytes = 0;
+ strncpy(header->name,"gs picture",80);
+ header->colormap = CM_NORMAL;
+ header->dorev=0;
+ fwrite(header,sizeof(IMAGE),1,pstream);
+ for (i=0; i<512-sizeof(IMAGE); i++) fputc(filler,pstream);
+ pcur->dev = bdev;
+ pcur->bpp = bdev->color_info.depth;
+ pcur->line_size = line_size;
+ pcur->data = data;
+ return 0;
+}
+
+private int
+sgi_next_row(sgi_cursor _ss *pcur)
+{ if (pcur->lnum < 0)
+ return 1;
+ gdev_prn_copy_scan_lines((gx_device_printer*)pcur->dev,
+ pcur->lnum--, pcur->data, pcur->line_size);
+ return 0;
+}
+
+#define bdev ((gx_device_printer *)pdev)
+
+private int
+sgi_print_page(gx_device_printer *pdev, FILE *pstream)
+{ sgi_cursor cur;
+ int code = sgi_begin_page(bdev, pstream, &cur);
+ uint bpe, mask;
+ int separation;
+ long *rowsizes=(long*)gs_malloc(4,3*bdev->height,"sgi_print_page");
+ byte *edata ;
+ long lastval; byte*sptr;
+ int rownumber;
+#define aref2(a,b) a*bdev->height+b
+ edata = (byte*)gs_malloc(cur.line_size, 1, "sgi_begin_page");
+ if((code<0)||(rowsizes==(long*)NULL)||(edata==(byte*)NULL)) return(-1);
+ fwrite(rowsizes,sizeof(long),3*bdev->height,pstream); /* rowstarts */
+ fwrite(rowsizes,sizeof(long),3*bdev->height,pstream); /* rowsizes */
+ lastval = 512+sizeof(long)*6*bdev->height;
+ fseek(pstream,lastval,0);
+ for (separation=0; separation < 3; separation++)
+ {
+ cur.lnum = cur.dev->height-1;
+ rownumber = 0;
+ bpe = cur.bpp/3;
+ mask = (1<<bpe) - 1;
+ while ( !(code=sgi_next_row(&cur)))
+ { byte *bp;
+ uint x;
+ int shift;
+ byte *curcol=cur.data;
+ byte *startcol=edata;
+ int count;
+ byte todo, cc;
+ byte *iptr, *sptr, *optr, *ibufend;
+ for (bp = cur.data, x=0, shift = 8 - cur.bpp;
+ x < bdev->width;
+ )
+ { ulong pixel = 0;
+ uint r, g, b;
+ switch (cur.bpp >> 3)
+ {
+ case 3: pixel = (ulong)*bp << 16; bp++;
+ case 2: pixel += (uint)*bp << 8; bp++;
+ case 1: pixel += *bp; bp++; break;
+ case 0: pixel = *bp >> shift;
+ if ((shift-=cur.bpp) < 0)
+ bp++, shift += 8; break;
+ }
+ ++x;
+ b = pixel & mask; pixel >>= bpe;
+ g = pixel & mask; pixel >>= bpe;
+ r = pixel & mask;
+ switch(separation)
+ {
+ case 0: *curcol++=r; break;
+ case 1: *curcol++=g; break;
+ case 2: *curcol++=b; break;
+ }
+ }
+ iptr=cur.data;
+ optr=startcol;
+ ibufend=curcol-1;
+ while(iptr<ibufend) {
+ sptr = iptr;
+ iptr += 2;
+ while((iptr<ibufend)&&((iptr[-2]!=iptr[-1])||(iptr[-1]!=iptr[0])))
+ iptr++;
+ iptr -= 2;
+ count = iptr-sptr;
+ while(count) {
+ todo = count>126 ? 126:count;
+ count -= todo;
+ *optr++ = 0x80|todo;
+ while(todo--)
+ *optr++ = *sptr++;
+ }
+ sptr = iptr;
+ cc = *iptr++;
+ while( (iptr<ibufend) && (*iptr == cc) )
+ iptr++;
+ count = iptr-sptr;
+ while(count) {
+ todo = count>126 ? 126:count;
+ count -= todo;
+ *optr++ = todo;
+ *optr++ = cc;
+ }
+ }
+ *optr++ = 0;
+ rowsizes[aref2(separation,rownumber++)] = optr-startcol;
+ fwrite(startcol,1,optr-startcol,pstream);
+ }
+ }
+ fseek(pstream,512L,0);
+ for(separation=0; separation<3; separation++)
+ for(rownumber=0; rownumber<bdev->height; rownumber++)
+ {fputc((char)(lastval>>24),pstream);
+ fputc((char)(lastval>>16),pstream);
+ fputc((char)(lastval>>8),pstream);
+ fputc((char)(lastval),pstream);
+ lastval+=rowsizes[aref2(separation,rownumber)];}
+ for(separation=0; separation<3; separation++)
+ for(rownumber=0; rownumber<bdev->height; rownumber++)
+ {lastval=rowsizes[aref2(separation,rownumber)];
+ fputc((char)(lastval>>24),pstream);
+ fputc((char)(lastval>>16),pstream);
+ fputc((char)(lastval>>8),pstream);
+ fputc((char)(lastval),pstream);}
+ gs_free((char*)cur.data, cur.line_size, 1,
+ "sgi_print_page(done)");
+ gs_free((char*)edata, cur.line_size, 1, "sgi_print_page(done)");
+ gs_free((char*)rowsizes,4,3*bdev->height,"sgi_print_page(done)");
+ return (code < 0 ? code : 0);
+}
diff --git a/gs/src/gdevsgi.h b/gs/src/gdevsgi.h
new file mode 100644
index 000000000..1e34081d7
--- /dev/null
+++ b/gs/src/gdevsgi.h
@@ -0,0 +1,66 @@
+/*
+ * This file is distributed with Ghostscript, but its author,
+ * Tanmoy Bhattacharya (tanmoy@qcd.lanl.gov) hereby places it in the
+ * public domain.
+ *
+ * The contents of this file were derived (indeed, largely copied) from
+ * the file image.h on SGI's file server; there is no copyright on that file.
+ */
+
+/* gdevsgi.h */
+/* SGI raster file definitions */
+
+#define IMAGIC 0732
+
+/* colormap of images */
+#define CM_NORMAL 0
+#define CM_DITHERED 1
+#define CM_SCREEN 2
+#define CM_COLORMAP 3
+#define TYPEMASK 0xff00
+#define BPPMASK 0x00ff
+#define ITYPE_VERBATIM 0x0000
+#define ITYPE_RLE 0x0100
+#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
+#define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
+#define BPP(type) ((type) & BPPMASK)
+#define RLE(bpp) (ITYPE_RLE | (bpp))
+#define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
+#define IBUFSIZE(pixels) ((pixels+(pixels>>6))<<2)
+#define RLE_NOP 0x00
+
+#define ierror(p) (((p)->flags&_IOERR)!=0)
+#define ifileno(p) ((p)->file)
+#define getpix(p) (--(p)->cnt>=0 ? *(p)->ptr++ : ifilbuf(p))
+#define putpix(p,x) (--(p)->cnt>=0 \
+ ? ((int)(*(p)->ptr++=(unsigned)(x))) \
+ : iflsbuf(p,(unsigned)(x)))
+
+typedef struct {
+ unsigned short imagic; /* stuff saved on disk . . */
+ unsigned short type;
+ unsigned short dim;
+ unsigned short xsize;
+ unsigned short ysize;
+ unsigned short zsize;
+ unsigned long min_color;
+ unsigned long max_color;
+ unsigned long wastebytes;
+ char name[80];
+ unsigned long colormap;
+
+ long file; /* stuff used in core only */
+ unsigned short flags;
+ short dorev;
+ short x;
+ short y;
+ short z;
+ short cnt;
+ unsigned short *ptr;
+ unsigned short *base;
+ unsigned short *tmpbuf;
+ unsigned long offset;
+ unsigned long rleend; /* for rle images */
+ unsigned long *rowstart; /* for rle images */
+ long *rowsize; /* for rle images */
+} IMAGE;
diff --git a/gs/src/gdevsj48.c b/gs/src/gdevsj48.c
new file mode 100644
index 000000000..44031534a
--- /dev/null
+++ b/gs/src/gdevsj48.c
@@ -0,0 +1,293 @@
+/* Copyright (C) 1990, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+ * gdevsj48.c --- derived from gdevbj10.c 1993-10-07
+ * by Mats kerblom (f86ma@dd.chalmers.se).
+ *
+ *
+ * StarJet SJ48 printer driver.
+ *
+ */
+
+#include "gdevprn.h"
+
+
+/*
+ * The only available resolutions (in the program) are (180,360)x(180,360).
+ *
+ * Used control codes:
+ * <Esc>@ Printer reset
+ * <Esc>J<n> Make a n/180 inch linefeed
+ * <Esc>\<a><b> Move the print position (a+256b)/180 inch to the right
+ * <Esc>*<m><a><b>... Print graphics; m=39: 180*180 dpi
+ * m=40: 360*180 dpi
+ * m=71: 180*360 dpi
+ * m=72: 360*360 dpi
+ * a+256b columns is printed.
+ */
+
+/* The device descriptor */
+private dev_proc_print_page(sj48_print_page);
+gx_device_printer far_data gs_sj48_device =
+ prn_device(prn_std_procs, "sj48",
+ 80, /* width_10ths, 8" */
+ 105, /* height_10ths, 10.5" */
+ 360, /* x_dpi */
+ 360, /* y_dpi */
+ 0,0,0,0, /* margins */
+ 1, sj48_print_page);
+
+
+/* This comes from the bj10/bj200 source. I don't know how it applies
+ * for a StarJet. --- Mats kerblom.
+ *
+ *
+ * The following is taken from the BJ200 Programmer's manual. The top
+ * margin is 3mm (0.12"), and the bottom margin is 6.4mm (0.25"). The
+ * left and right margin depend on the type of paper -- US letter or
+ * A4 -- but ultimately rest on a print width of 203.2mm (8"). For letter
+ * paper, the left margin (and hence the right) is 6.4mm (0.25"), while
+ * for A4 paper, both are 3.4mm (0.13").
+ *
+ * The bottom margin requires a bit of care. The image is printed
+ * as strips, each about 3.4mm wide. We can only attain the bottom
+ * margin if the final strip coincides with it. Note that each strip
+ * is generated using only 48 of the available 64 jets, and the absence
+ * of those bottom 16 jets makes our bottom margin, in effect, about
+ * 1.1mm (0.04") larger.
+ *
+ * The bj200 behaves, in effect, as though the origin were at the first
+ * printable position, rather than the top left corner of the page, so
+ * we add a translation to the initial matrix to compensate for this.
+ *
+ * Except for the details of getting the margins correct, the bj200 is
+ * no different from the bj10e, and uses the same routine to print each
+ * page.
+ *
+ */
+
+
+/* Send the page to the printer. */
+private int
+sj48_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ int line_size = gx_device_raster((gx_device *)pdev, 0);
+ int xres = pdev->x_pixels_per_inch;
+ int yres = pdev->y_pixels_per_inch;
+ int mode = (yres == 180 ?
+ (xres == 180 ? 39 : 40) :
+ (xres == 180 ? 71 : 72));
+ int bytes_per_column = (yres == 180) ? 3 : 6;
+ int bits_per_column = bytes_per_column * 8;
+ int skip_unit = bytes_per_column * (xres == 180 ? 1 : 2); /* Skips in step of 1/180" */
+ byte *in = (byte *)gs_malloc(8, line_size, "sj48_print_page(in)");
+ byte *out = (byte *)gs_malloc(bits_per_column, line_size, "sj48_print_page(out)");
+ int lnum = 0;
+ int skip = 0;
+ int skips;
+ int code = 0;
+ int last_row = dev_print_scan_lines(pdev);
+ int limit = last_row - bits_per_column;
+
+ if ( in == 0 || out == 0 )
+ { code = gs_error_VMerror;
+ gs_note_error(code);
+ goto fin;
+ }
+
+ /* Abort if the requested resolution is unsupported. */
+ if ((xres !=180 && xres != 360) || (yres !=180 && yres != 360))
+ { code = gs_error_rangecheck;
+ gs_note_error(code);
+ goto fin;
+ }
+
+ /* Initialize the printer. */
+ fwrite("\033@\000\000", 1, 4, prn_stream); /* <Printer reset>, <0>, <0>. */
+
+ /* Transfer pixels to printer. The last row we can print is defined
+ by "last_row". Only the bottom of the print head can print at the
+ bottom margin, and so we align the final printing pass. The print
+ head is kept from moving below "limit", which is exactly one pass
+ above the bottom margin. Once it reaches this limit, we make our
+ final printing pass of a full "bits_per_column" rows. */
+ while ( lnum < last_row )
+ {
+ byte *in_data;
+ byte *in_end = in + line_size;
+ byte *out_beg = out;
+ byte *out_end = out + bytes_per_column * pdev->width;
+ byte *outl = out;
+ int count, bnum;
+
+ /* Copy 1 scan line and test for all zero. */
+ code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+ if ( code < 0 ) goto xit;
+ /* The mem... or str... functions should be faster than */
+ /* the following code, but all systems seem to implement */
+ /* them so badly that this code is faster. */
+ { register const long *zip = (const long *)in_data;
+ register int zcnt = line_size;
+ register const byte *zipb;
+ for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
+ { if ( zip[0] | zip[1] | zip[2] | zip[3] )
+ goto notz;
+ }
+ zipb = (const byte *)zip;
+ while ( --zcnt >= 0 )
+ {
+ if ( *zipb++ )
+ goto notz;
+ }
+ /* Line is all zero, skip */
+ lnum++;
+ skip++;
+ continue;
+notz: ;
+ }
+
+ /* Vertical tab to the appropriate position. Note here that
+ we make sure we don't move below limit. */
+ if ( lnum > limit )
+ { skip -= (limit - lnum);
+ lnum = limit;
+ }
+
+ /* The SJ48 can only skip in steps of 1/180" */
+ if (yres == 180) {
+ skips = skip;
+ } else {
+ if (skip & 1) {
+ skip--; /* Makes skip even. */
+ lnum--;
+ }
+ skips = skip/2;
+ }
+
+ while ( skips > 255 )
+ { fputs("\033J\377", prn_stream);
+ skips -= 255;
+ }
+ if ( skips )
+ fprintf(prn_stream, "\033J%c", skips);
+
+ /* If we've printed as far as "limit", then reset "limit"
+ to "last_row" for the final printing pass. */
+ if ( lnum == limit )
+ limit = last_row;
+ skip = 0;
+
+ /* Transpose in blocks of 8 scan lines. */
+ for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
+ { int lcnt = min(8, limit - lnum);
+ byte *inp = in;
+ byte *outp = outl;
+ lcnt = gdev_prn_copy_scan_lines(pdev,
+ lnum, in, lcnt * line_size);
+ if ( lcnt < 0 )
+ { code = lcnt;
+ goto xit;
+ }
+ if ( lcnt < 8 )
+ memset(in + lcnt * line_size, 0,
+ (8 - lcnt) * line_size);
+ for ( ; inp < in_end; inp++, outp += bits_per_column )
+ { gdev_prn_transpose_8x8(inp, line_size,
+ outp, bytes_per_column);
+ }
+ outl++;
+ lnum += lcnt;
+ skip += lcnt;
+ }
+
+ /* Send the bits to the printer. We alternate horizontal
+ skips with the data. The horizontal skips are in units
+ of 1/180 inches, so we look at the data in groups of
+ 1 or 2 columns depending on resolution (controlled
+ by skip_unit). */
+ outl = out;
+ do
+ { int count;
+ int n;
+ byte *out_ptr;
+
+ /* First look for blank groups of columns. */
+ while(outl < out_end)
+ { n = count = min(out_end - outl, skip_unit);
+ out_ptr = outl;
+ while ( --count >= 0 )
+ { if ( *out_ptr++ )
+ break;
+ }
+ if ( count >= 0 )
+ break;
+ else
+ outl = out_ptr;
+ }
+ if (outl >= out_end)
+ break;
+ if (outl > out_beg)
+ { count = (outl - out_beg) / skip_unit;
+ fprintf(prn_stream, "\033\\%c%c",
+ count & 0xff, count >> 8);
+ }
+
+ /* Next look for non-blank groups of columns. */
+ out_beg = outl;
+ outl += n;
+ while(outl < out_end)
+ { n = count = min(out_end - outl, skip_unit);
+ out_ptr = outl;
+ while ( --count >= 0 )
+ { if ( *out_ptr++ )
+ break;
+ }
+ if ( count < 0 )
+ break;
+ else
+ outl += n;
+ }
+ count = outl - out_beg;
+ {
+ /* What to transmit is the number of columns in the row.
+ Compare this with the <Esc>|*-command wich expects the
+ total number of bytes in the graphic row! */
+ int count1 = count/bytes_per_column;
+ fprintf(prn_stream, "\033*%c%c%c",
+ mode, count1 & 0xff, count1 >> 8);
+ }
+ fwrite(out_beg, 1, count, prn_stream);
+ out_beg = outl;
+ outl += n;
+ }
+ while ( out_beg < out_end );
+
+ fputc('\r', prn_stream);
+ skip = bits_per_column; /* <CR> only moves to the beginning of the row. */
+ }
+
+ /* Eject the page */
+xit: fputc(014, prn_stream); /* form feed */
+ fflush(prn_stream);
+fin: if ( out != 0 )
+ gs_free((char *)out, bits_per_column, line_size,
+ "sj48_print_page(out)");
+ if ( in != 0 )
+ gs_free((char *)in, 8, line_size, "sj48_print_page(in)");
+ return code;
+}
diff --git a/gs/src/gdevsnfb.c b/gs/src/gdevsnfb.c
new file mode 100644
index 000000000..6b2dcff6a
--- /dev/null
+++ b/gs/src/gdevsnfb.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 1989, 1990, 1991, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsnfb.c */
+/* Sony News frame buffer driver for GhostScript */
+#include "gdevprn.h"
+/*#include <sys/types.h> problems with ushort! */
+typedef char * caddr_t;
+typedef long off_t;
+#include <sys/uio.h>
+#include <newsiop/framebuf.h>
+
+/* The device descriptor */
+private dev_proc_open_device(sonyfb_open);
+private dev_proc_output_page(sonyfb_output_page);
+private dev_proc_close_device(sonyfb_close);
+private gx_device_procs sonyfb_procs =
+ prn_procs(sonyfb_open, sonyfb_output_page, sonyfb_close);
+gx_device_printer far_data gs_sonyfb_device =
+ prn_device(sonyfb_procs, "sonyfb",
+ 102.4, /* width_10ths */
+ 103.2, /* height_10ths */
+ 100, /* x_dpi */
+ 100, /* y_dpi */
+ 0,0,0,0, /* margins */
+ 1, 0);
+
+private int fb_file = -1;
+sPrimRect prect;
+
+private int
+sonyfb_open(gx_device *dev)
+{
+ sScrType stype;
+
+ if(fb_file < 0)
+ if((fb_file = open("/dev/fb", 2)) < 0)
+ perror("open failed");
+ else
+ if(ioctl(fb_file, FBIOCGETSCRTYPE, &stype) < 0)
+ perror("ioctl failed");
+ else
+ prect.rect = stype.visiblerect;
+
+ return gdev_prn_open(dev);
+}
+
+private int
+sonyfb_close(gx_device *dev)
+{
+ if(fb_file >= 0)
+ {
+ close(fb_file);
+ fb_file = -1;
+ }
+ return gdev_prn_close(dev);
+}
+
+#define FRAME_WIDTH 1024
+
+/* Send the page to the printer. */
+private int
+sonyfb_output_page(gx_device *dev, int num_copies, int flush)
+{
+ int l, i, byte_width, height;
+ unsigned char *bm, *fbs, *fb;
+
+ byte_width = (dev->width + 7) / 8;
+ height = dev->height;
+ bm = (typeof(bm))prn_dev->mem.base;
+
+ prect.refPoint.x = 0;
+ prect.refPoint.y = 0;
+ prect.ptnRect = prect.rect;
+
+ prect.ptnBM.type = BM_MEM;
+ prect.ptnBM.depth = 1;
+ prect.ptnBM.width = (byte_width + 1) / 2;
+ prect.ptnBM.rect.origin.x = 0;
+ prect.ptnBM.rect.origin.y = 0;
+ prect.ptnBM.rect.extent.x = byte_width * 8; /* width in 16bit words */
+ prect.ptnBM.rect.extent.y = height;
+ prect.ptnBM.base = (typeof(prect.ptnBM.base))bm;
+
+ prect.fore_color = 1;
+ prect.aux_color = 0;
+ prect.planemask = FB_PLANEALL;
+ prect.transp = 0;
+ prect.func = BF_S;
+ prect.clip = prect.rect;
+ prect.drawBM.type = BM_FB;
+ prect.drawBM.depth = 1;
+ prect.drawBM.width = (prect.rect.extent.x + 15) / 16;
+ prect.drawBM.rect = prect.rect;
+ prect.drawBM.base = 0;
+
+ if(ioctl(fb_file, FBIOCRECTANGLE, &prect) < 0)
+ perror("rect ioctl failed");
+
+ return 0;
+}
diff --git a/gs/src/gdevsppr.c b/gs/src/gdevsppr.c
new file mode 100644
index 000000000..9977b68a7
--- /dev/null
+++ b/gs/src/gdevsppr.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsppr.c */
+/* SPARCprinter driver for Ghostscript */
+#include "gdevprn.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <unbdev/lpviio.h>
+
+/*
+ Thanks to Martin Schulte (schulte@thp.Uni-Koeln.DE) for contributing
+ this driver to Ghostscript. He supplied the following notes.
+
+The device-driver (normally) returns two differnt types of Error-Conditions,
+FATALS and WARNINGS. In case of a fatal, the print routine returns -1, in
+case of a warning (such as paper out), a string describing the error is
+printed to stdout and the output-operation is repeated after five seconds.
+
+A problem is that not all possible errors seem to return the correct error,
+under some circumstance I get the same response as if an error repeated,
+that's why there is this the strange code about guessing the error.
+
+I didn't implement asynchronous IO (yet), because "`normal"' multipage-
+printings like TEX-Output seem to be printed with the maximum speed whereas
+drawings normally occur as one-page outputs, where asynchronous IO doesn't
+help anyway.
+*/
+
+private dev_proc_open_device(sparc_open);
+private dev_proc_print_page(sparc_print_page);
+
+#define SPARC_MARGINS_A4 0.15, 0.12, 0.12, 0.15
+#define SPARC_MARGINS_LETTER 0.15, 0.12, 0.12, 0.15
+
+gx_device_procs prn_sparc_procs =
+ prn_procs(sparc_open, gdev_prn_output_page, gdev_prn_close);
+
+gx_device_printer far_data gs_sparc_device =
+prn_device(prn_sparc_procs,
+ "sparc",
+ DEFAULT_WIDTH_10THS,DEFAULT_HEIGHT_10THS,
+ 400,400,
+ 0,0,0,0,
+ 1,
+ sparc_print_page);
+
+/* Open the printer, and set the margins. */
+private int
+sparc_open(gx_device *pdev)
+{ /* Change the margins according to the paper size. */
+ const float _ds *m;
+ static const float m_a4[4] = { SPARC_MARGINS_A4 };
+ static const float m_letter[4] = { SPARC_MARGINS_LETTER };
+
+ m = (pdev->height / pdev->y_pixels_per_inch >= 11.1 ? m_a4 : m_letter);
+ gx_device_set_margins(pdev, m, true);
+ return gdev_prn_open(pdev);
+}
+
+char *errmsg[]={
+ "EMOTOR",
+ "EROS",
+ "EFUSER",
+ "XEROFAIL",
+ "ILCKOPEN",
+ "NOTRAY",
+ "NOPAPR",
+ "XITJAM",
+ "MISFEED",
+ "WDRUMX",
+ "WDEVEX",
+ "NODRUM",
+ "NODEVE",
+ "EDRUMX",
+ "EDEVEX",
+ "ENGCOLD",
+ "TIMEOUT",
+ "EDMA",
+ "ESERIAL"
+ };
+
+private char *
+err_code_string(int err_code)
+ {
+ if ((err_code<EMOTOR)||(err_code>ESERIAL))
+ {
+ char buffer[80];
+ sprintf(buffer,"err_code out of range: %d",err_code);
+ return buffer;
+ }
+ return errmsg[err_code];
+ }
+
+int warning=0;
+
+private int
+sparc_print_page(gx_device_printer *pdev, FILE *prn)
+ {
+ struct lpvi_page lpvipage;
+ struct lpvi_err lpvierr;
+ char *out_buf;
+ int out_size;
+ if (ioctl(fileno(prn),LPVIIOC_GETPAGE,&lpvipage)!=0)
+ {
+ fprintf(stderr,"sparc_print_page: LPVIIOC_GETPAGE failed\n");
+ return -1;
+ }
+ lpvipage.bitmap_width=gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ lpvipage.page_width=lpvipage.bitmap_width*8;
+ lpvipage.page_length=pdev->height;
+ lpvipage.resolution= (pdev->x_pixels_per_inch == 300 ? 300 : 400);
+ if (ioctl(fileno(prn),LPVIIOC_SETPAGE,&lpvipage)!=0)
+ {
+ fprintf(stderr,"sparc_print_page: LPVIIOC_SETPAGE failed\n");
+ return -1;
+ }
+ out_size=lpvipage.bitmap_width*lpvipage.page_length;
+ out_buf=gs_malloc(out_size,1,"sparc_print_page: out_buf");
+ gdev_prn_copy_scan_lines(pdev,0,out_buf,out_size);
+ while (write(fileno(prn),out_buf,out_size)!=out_size)
+ {
+ if (ioctl(fileno(prn),LPVIIOC_GETERR,&lpvierr)!=0)
+ {
+ fprintf(stderr,"sparc_print_page: LPVIIOC_GETERR failed\n");
+ return -1;
+ }
+ switch (lpvierr.err_type)
+ {
+ case 0:
+ if (warning==0)
+ {
+ fprintf(stderr,
+ "sparc_print_page: Printer Problem with unknown reason...");
+ fflush(stderr);
+ warning=1;
+ }
+ sleep(5);
+ break;
+ case ENGWARN:
+ fprintf(stderr,
+ "sparc_print_page: Printer-Warning: %s...",
+ err_code_string(lpvierr.err_code));
+ fflush(stderr);
+ warning=1;
+ sleep(5);
+ break;
+ case ENGFATL:
+ fprintf(stderr,
+ "sparc_print_page: Printer-Fatal: %s\n",
+ err_code_string(lpvierr.err_code));
+ return -1;
+ case EDRVR:
+ fprintf(stderr,
+ "sparc_print_page: Interface/driver error: %s\n",
+ err_code_string(lpvierr.err_code));
+ return -1;
+ default:
+ fprintf(stderr,
+ "sparc_print_page: Unknown err_type=%d(err_code=%d)\n",
+ lpvierr.err_type,lpvierr.err_code);
+ return -1;
+ }
+ }
+ if (warning==1)
+ {
+ fprintf(stderr,"OK.\n");
+ warning=0;
+ }
+ gs_free(out_buf,out_size,1,"sparc_print_page: out_buf");
+ return 0;
+ }
diff --git a/gs/src/gdevstc.c b/gs/src/gdevstc.c
new file mode 100644
index 000000000..f1e9a251b
--- /dev/null
+++ b/gs/src/gdevstc.c
@@ -0,0 +1,3552 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ *** This file was "copied" from gdevcdj.c (ghostscript-3.12), which was
+ *** contributed by:
+ *** George Cameron - g.cameron@biomed.abdn.ac.ukis
+ *** Koert Zeilstra - koert@zen.cais.com
+ *** Eckhard Rueggeberg - eckhard@ts.go.dlr.de
+ ***
+ *** Some of the ESC/P2-code was drawn from gdevescp.c, contributed by
+ *** Richard Brown - rab@eos.ncsu.edu
+ ***
+ *** The POSIX-Interrupt-Code is from (Compile-Time-Option -DSTC_SIGNAL)
+ *** Frederic Loyer - loyer@ensta.fr
+ ***
+ *** And several improvements are based on discussions with
+ *** Brian Converse - BCONVERSE@ids.net
+ *** Bill Davidson - bdavidson@ra.isisnet.com
+ *** Gero Guenther - gero@cs.tu-berlin.de
+ *** Jason Patterson - jason@reflections.com.au
+ *** ? Rueschstroer - rue@ibe.med.uni-muenchen.de
+ *** Steven Singer - S.Singer@ph.surrey.ac.uk
+ ***
+ *** And the remaining little rest, mainly the bugs, were written by me:
+ *** Gunther Hess - gunther@elmos.de
+ ***
+ *** P.S.: there is some documentation, see devices.doc
+ ***
+ *** Revision-History:
+ *** 16-DEC-1994 1.1 - initial Version (GS-Dithering & Plain-Write)
+ ...
+ *** 30-JAN-1995 1.11 - FS-Improvements, u/sWeave, 1/4/24-Bits
+ *** 5-MAR-1995 1.12 - L. Peter Deutsch - updated put_params routine
+ (first distributed version with gs3.33)
+ *** 26-APR-1995 1.13 - merged Peters fixes with algorithmic changes:
+ Changed 24Bit-Mode, added 32Bit-Mode (moves colors)
+ [Arrgh: much better than 1.12, but patch was lost]
+ *** 5-JUN-1995 1.14 - Added Color-Correction & Transfer-Curves
+ (Several Beta-Testers, but not distributed)
+ ...
+ *** 24-JUL-1995 1.16 - Made dithering-Algorithms external-functions.
+ (Mailed for Beta-Distribution)
+ *** 10-AUG-1995 1.17 - Several Bug-Fixes and some new features:
+ CMYK10-Coding added
+ Readonly Parameters added
+ "Algorithms", "BitsPerComponent", "Version"
+ Parameters Flag0-4, Model, OutputCode
+ (mailed for distribution)
+ *** 14-SEP-1995 1.18 Fixes Bugs with Borland C (gs3.47)
+ *** 23-SEP-1995 1.19 - reorganized printcode + bug-fixing
+ *** 24-SEP-1995 1.20 - Little Cleanup for the release
+ *** 25-SEP-1995 1.21 - Readonly-Parameters added to put_params.
+ *** 31-Dec-1995 1.22 - Sanitary Engineering on the code
+ *** 16-Jan-1996 1.23 - Added String escp_Release
+ *** 8-May-1996 1.90 - Reintroduced Deltarow & Fixed MEMORY-BUG!
+ ***/
+
+#include "gdevstc.h"
+#ifdef STC_SIGNAL
+# include <signal.h>
+#endif /* STC_SIGNAL */
+/***
+ *** Mode-Table - the various algorithms
+ *** (The intention is, that this source can live alone)
+ ***/
+
+private stc_proc_dither(stc_gscmyk); /* resides in this file */
+private stc_proc_dither(stc_hscmyk); /* resides in this file */
+
+#include <stdlib.h> /* for rand, used in stc_hscmyk */
+
+private const stc_dither_t stc_dither[] = {
+ {"gscmyk", stc_gscmyk, DeviceCMYK|STC_BYTE|STC_DIRECT,0,{0.0,1.0}},
+ {"hscmyk", stc_hscmyk,
+ DeviceCMYK|STC_LONG|STC_CMYK10|STC_DIRECT|1*STC_SCAN,1+2*4,
+ {0.0, 1023.0}},
+ STC_MODI
+ { NULL , NULL , 0, 0,{0.0,0.0}}
+};
+
+/***
+ *** forward-declarations of routines
+ ***/
+
+/* Primary Device functions
+ * (I've the idea to rename the driver to stc)
+ */
+private dev_proc_print_page(stc_print_page);
+private dev_proc_open_device(stc_open);
+private dev_proc_close_device(stc_close);
+private dev_proc_get_params(stc_get_params);
+private dev_proc_put_params(stc_put_params);
+
+/*
+ * Color-Mapping-functions.
+ */
+
+/* routines for monochrome monochrome modi */
+private dev_proc_map_rgb_color(stc_map_gray_color);
+private dev_proc_map_color_rgb(stc_map_color_gray);
+
+/* routines for RGB-Modi */
+private dev_proc_map_rgb_color(stc_map_rgb_color);
+private dev_proc_map_color_rgb(stc_map_color_rgb);
+
+/* routines for general CMYK-Modi */
+private dev_proc_map_cmyk_color(stc_map_cmyk_color);
+private dev_proc_map_color_rgb(stc_map_color_cmyk);
+
+/* routines for 10Bit/Component CMYK */
+private dev_proc_map_cmyk_color(stc_map_cmyk10_color);
+private dev_proc_map_color_rgb(stc_map_color_cmyk10);
+
+/***
+ *** Table of Device-Procedures
+ ***/
+private gx_device_procs stcolor_procs = {
+ stc_open,
+ gx_default_get_initial_matrix,
+ gx_default_sync_output,
+ gdev_prn_output_page,
+ stc_close,
+ NULL,
+ stc_map_color_cmyk,
+ NULL, /* fill_rectangle */
+ NULL, /* tile_rectangle */
+ NULL, /* copy_mono */
+ NULL, /* copy_color */
+ NULL, /* draw_line */
+ gx_default_get_bits,
+ stc_get_params,
+ stc_put_params,
+ stc_map_cmyk_color
+};
+
+/***
+ *** A local dummy-array for extvals
+ ***/
+
+private float defext[] = { 0.0, 1.0 };
+
+/***
+ *** Main device-control structure
+ ***/
+stcolor_device far_data gs_stcolor_device = {
+ prn_device_body(stcolor_device, stcolor_procs, "stcolor",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ STC_L_MARGIN,STC_B_MARGIN,STC_R_MARGIN,STC_T_MARGIN,
+ 4, 4, 1, 1, 2, 2, /* default: cmyk-direct */
+ stc_print_page),
+ {STCNWEAVE, /* stcflags: noWeave/bidirectional */
+ 1, /* stcbits: matches the default */
+ stc_dither, /* stcdither: first algorithm */
+ NULL, /* stcam: NULL -> not used */
+ { NULL, NULL, NULL, NULL}, /* extcode: none defined yet */
+ { 0, 0, 0, 0}, /* sizcode: 0, since no extcode yet */
+ { NULL, NULL, NULL, NULL}, /* stccode: computed by put_params */
+ {defext,defext,defext,defext},/* extvals: default */
+ { 2, 2, 2, 2}, /* sizvals: default countof(defext) */
+ { NULL, NULL, NULL, NULL}, /* stcvals: computed by put_params */
+ { 0, 0, 0}, /* white-run */
+ { 0, 0, 0}, /* white-end */
+ {NULL,0,false}, /* algorithm-table */
+ {NULL,0,false}, /* initialization-String (BOP) */
+ {NULL,0,false}, /* release-String (EOP) */
+ 0,0,0,0, /* New escp-stuff */
+ 1} /* itemsize used by algorithm */
+};
+/***
+ *** Test for white scan-lines
+ ***/
+private bool stc_iswhite(P3(stcolor_device *, int, byte *));
+
+/***
+ *** Functions used for conversion inside the print-loop
+ ***/
+#define stc_proc_iconvert(Name) \
+byte * Name(P4(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line))
+
+private stc_proc_iconvert(stc_any_depth); /* general input-conversion */
+private stc_proc_iconvert(stc_rgb24_long); /* 24Bit RGB -> long's */
+
+private stc_proc_iconvert(stc_cmyk32_long); /* 32Bit CMYK -> long's */
+private stc_proc_iconvert(stc_any_direct); /* use ext_data as input */
+
+private stc_proc_iconvert(stc_cmyk10_byte); /* CMYK10->vals-> any type */
+private stc_proc_iconvert(stc_cmyk10_long); /* CMYK10->vals-> any type */
+private stc_proc_iconvert(stc_cmyk10_float); /* CMYK10->vals-> any type */
+private stc_proc_iconvert(stc_cmyk10_dbyte); /* CMYK10 direct bytes */
+private stc_proc_iconvert(stc_cmyk10_dlong); /* CMYK10 direct longs */
+
+/***
+ *** Print-functions
+ ***/
+private void stc_print_weave(P2(stcolor_device *sd,FILE *prn_stream));
+private void stc_print_bands(P2(stcolor_device *sd,FILE *prn_stream));
+private void stc_print_delta(P2(stcolor_device *sd,FILE *prn_stream));
+private int stc_print_setup(P1(stcolor_device *sd));
+
+/***
+ *** compute the ESC/P2 specific values
+ ***/
+
+private int
+stc_print_setup(stcolor_device *sd)
+{
+
+/*
+ * Compute the resolution-parameters
+ */
+ sd->stc.escp_u = 3600.0 / sd->y_pixels_per_inch; /* y-units */
+ sd->stc.escp_h = 3600.0 / sd->x_pixels_per_inch; /* x-units */
+ sd->stc.escp_v = sd->stc.flags & (STCUWEAVE | STCNWEAVE) ?
+ sd->stc.escp_u : 40;
+/*
+ * Initialize color
+ */
+ sd->stc.escp_c = 0; /* preselect-black */
+
+/*
+ * Band-Width
+ */
+ if((sd->stc.flags & STCBAND) == 0) {
+ if(sd->stc.escp_v != sd->stc.escp_u) sd->stc.escp_m = 15;
+ else if(STCSTCII == (sd->stc.flags & STCMODEL)) sd->stc.escp_m = 1;
+ else if( sd->stc.flags & STCUWEAVE) sd->stc.escp_m = 1;
+ else if((sd->stc.escp_v == sd->stc.escp_u) &&
+ (sd->stc.escp_u == 5)) sd->stc.escp_m = 1;
+ else sd->stc.escp_m = 1;
+ }
+
+/*
+ * Page-Dimensions
+ */
+ if((sd->stc.flags & STCWIDTH ) == 0)
+ sd->stc.escp_width = sd->width -
+ (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch;
+
+ if((sd->stc.flags & STCHEIGHT) == 0)
+ sd->stc.escp_height = sd->height;
+
+ if((sd->stc.flags & STCTOP) == 0)
+ sd->stc.escp_top = dev_t_margin(sd)*sd->y_pixels_per_inch;
+
+ if((sd->stc.flags & STCBOTTOM) == 0)
+ sd->stc.escp_bottom = sd->height - dev_b_margin(sd)*sd->y_pixels_per_inch;
+
+ if((sd->stc.flags & STCINIT) == 0) { /* No Initialization-String defined */
+ int need = 8 /* Reset, Graphics-Mode 1 */
+ + 6 /* MicroWeave */
+ + 6 /* Select Units */
+ + 7 /* Set Page-Length */
+ + 9 /* Set Margins */
+ + 3; /* Select Unidirectionality */
+ byte *bp = (byte *) (sd->stc.escp_init.data);
+
+ if(need != sd->stc.escp_init.size) { /* Reallocate */
+
+ if(NULL != (bp = gs_malloc(need,1,"stcolor/init"))) { /* Replace */
+ if(0 != sd->stc.escp_init.size)
+ gs_free((byte *)sd->stc.escp_init.data,sd->stc.escp_init.size,1,
+ "stcolor/init");
+ sd->stc.escp_init.data = bp;
+ sd->stc.escp_init.size = need;
+ sd->stc.escp_init.persistent = false;
+ } else { /* Replace */
+ return_error(gs_error_VMerror);
+ }
+ }
+
+ if(need != 39) return_error(gs_error_unregistered);
+
+ memcpy(bp,
+/* 1 1 11 1 11 1 1 1 2 22 2 2 22 2 22 3 3 3333 3 33*/
+/* 0 1 2 34 5 6 7 8 90 1 23 4 56 7 8 9 0 12 3 4 56 7 89 0 1 2345 6 78*/
+"\033@\033(G\001\0\1\033(i\1\0w\033(U\001\000u\033(C\2\000hh\033(c\4\000ttbb\033U",
+ need);
+
+
+ if((sd->stc.flags & STCUWEAVE) != 0) bp[13] = '\1';
+ else bp[13] = '\0';
+
+ bp[19] = sd->stc.escp_u;
+
+ bp[25] = sd->stc.escp_height & 0xff;
+ bp[26] = (sd->stc.escp_height>>8) & 0xff;
+
+ bp[32] = sd->stc.escp_top & 0xff;
+ bp[33] = (sd->stc.escp_top>>8) & 0xff;
+ bp[34] = sd->stc.escp_bottom & 0xff;
+ bp[35] = (sd->stc.escp_bottom>>8) & 0xff;
+
+ if(sd->stc.flags & STCUNIDIR) bp[38] = 1;
+ else bp[38] = 0;
+
+ } /* No Initialization-String defined */
+
+ if((sd->stc.flags & STCRELEASE) == 0) { /* No Release-String defined */
+ int need = 3; /* ESC @ \f */
+ byte *bp = (byte *) (sd->stc.escp_release.data);
+
+ if(need != sd->stc.escp_release.size) { /* Reallocate */
+
+ if(NULL != (bp = gs_malloc(need,1,"stcolor/release"))) { /* Replace */
+ if(0 != sd->stc.escp_release.size)
+ gs_free((byte *)sd->stc.escp_release.data,sd->stc.escp_release.size,1,
+ "stcolor/release");
+ sd->stc.escp_release.data = bp;
+ sd->stc.escp_release.size = need;
+ sd->stc.escp_release.persistent = false;
+ } else { /* Replace */
+ return_error(gs_error_VMerror);
+ }
+ }
+
+ if(need != 3) return_error(gs_error_unregistered);
+
+ memcpy(bp,"\033@\f",need);
+
+ } /* No Release-String defined */
+
+ return 0;
+}
+
+/***
+ *** stc_print_page: here we go to do the nasty work
+ ***/
+
+private int
+stc_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ stcolor_device *sd = (stcolor_device *) pdev;
+ long flags = sd == NULL ? 0 : sd->stc.flags;
+
+ int npass; /* # of print-passes (softweave) */
+
+ int ext_size; /* size of a ghostscript-scanline */
+ byte *ext_line; /* dyn: for this scanline */
+
+ int alg_size; /* size of a scanline for the dithering-algorithm */
+ byte *alg_line; /* dyn: 1 scanline for the dithering-algorithm */
+ int buf_size; /* size of the private-buffer for dither-function */
+ byte *buf; /* dyn: the private buffer */
+
+ int prt_pixels; /* Number of pixels printed */
+ byte *col_line; /* A Line with a byte per pixel */
+
+#define OK4GO ((flags & STCOK4GO) != 0)
+#define SORRY ( flags &= ~STCOK4GO)
+
+ if(0 > (npass = stc_print_setup(sd))) return_error(npass);
+
+ npass = sd->stc.escp_v / sd->stc.escp_u;
+
+/***
+ *** Allocate dynamic memory
+ ***/
+
+ ext_size = gdev_prn_raster(sd);
+ ext_line = gs_malloc(ext_size,1,"stc_print_page/ext_line");
+ if(ext_line == NULL) SORRY;
+
+ prt_pixels = sd->stc.escp_width;
+ sd->stc.prt_size = (prt_pixels+7)/8;
+ prt_pixels = sd->stc.prt_size * 8;
+
+ sd->stc.prt_scans = sd->height -
+ (dev_t_margin(sd)+dev_b_margin(sd))*sd->y_pixels_per_inch;
+
+ col_line = gs_malloc(prt_pixels,1,"stc_print_page/col_line");
+ if(col_line == NULL) SORRY;
+
+ alg_size = prt_pixels;
+ alg_size *= sd->color_info.num_components;
+
+ if((sd->stc.dither->flags & STC_DIRECT) ||
+ ((sd->stc.bits == 8) &&
+ (sd->stc.alg_item == 1))) {
+ alg_line = NULL;
+ } else {
+ alg_line = gs_malloc(alg_size,sd->stc.alg_item,"stc_print_page/alg_line");
+ if(alg_line == NULL) SORRY;
+ }
+
+ buf_size = sd->stc.dither->bufadd
+ + alg_size*(sd->stc.dither->flags/STC_SCAN);
+ if(buf_size > 0) {
+ buf = gs_malloc(buf_size,sd->stc.alg_item,"stc_print_page/buf");
+ if(buf == NULL) SORRY;
+ } else {
+ buf = NULL;
+ }
+
+/*
+ * compute the number of printer-buffers
+ */
+
+ for(sd->stc.prt_buf = 16; sd->stc.prt_buf < (sd->stc.escp_m * npass);
+ sd->stc.prt_buf <<= 1);
+ if(sd->color_info.num_components > 1) sd->stc.prt_buf *= 4;
+
+ sd->stc.prt_width = gs_malloc(sd->stc.prt_buf,sizeof(int),
+ "stc_print_page/prt_width");
+ if(sd->stc.prt_width == NULL) SORRY;
+
+ sd->stc.prt_data = gs_malloc(sd->stc.prt_buf,sizeof(byte *),
+ "stc_print_page/prt_data");
+
+ if(sd->stc.prt_data == NULL) {
+ SORRY;
+ } else {
+ int i;
+
+ for(i = 0; i < sd->stc.prt_buf; ++i) {
+ sd->stc.prt_data[i] = gs_malloc(sd->stc.prt_size,1,
+ "stc_print_page/prt");
+ if(sd->stc.prt_data[i] == NULL) SORRY;
+ }
+ }
+
+ sd->stc.seed_size = (sd->stc.prt_size + 2*sizeof(int) - 1)/sizeof(int);
+ {
+ int i;
+ for(i = 0; i < sd->color_info.num_components; ++i) {
+ if((flags & STCCOMP) == STCDELTA) {
+ sd->stc.seed_row[i] = gs_malloc(sd->stc.seed_size,sizeof(int),
+ "stc_print_page/seed_row");
+ if(sd->stc.seed_row[i] == NULL) SORRY;
+ else memset(sd->stc.seed_row[i],0,sd->stc.seed_size*sizeof(int));
+ } else {
+ sd->stc.seed_row[i] = NULL;
+ }
+ }
+ while(i < countof(sd->stc.seed_row)) sd->stc.seed_row[i++] = NULL;
+ }
+
+ switch(flags & STCCOMP) {
+ case STCPLAIN:
+ sd->stc.escp_size = 64 + sd->stc.prt_size;
+ break;
+ case STCDELTA:
+ sd->stc.escp_size = 64 + 2 * sd->stc.prt_size;
+ break;
+ default:
+ sd->stc.escp_size = 64 +
+ sd->stc.prt_size + (sd->stc.prt_size + 127)/128;
+ break;
+ }
+
+ sd->stc.escp_data = gs_malloc(sd->stc.escp_size,1,
+ "stc_print_page/escp_data");
+ if(sd->stc.escp_data == NULL) SORRY;
+
+/*
+ * If we're still ok, we can print something
+ */
+
+ if(OK4GO) {
+
+ int ncolor;
+ int buf_i;
+ stc_proc_iconvert((*iconvert)) = stc_any_depth;
+
+/*
+ * initialize col_line
+ */
+ if(sd->color_info.num_components == 3) {
+ memset(col_line,RED|GREEN|BLUE,prt_pixels);
+ } else {
+ memset(col_line,0, prt_pixels);
+ }
+
+/*
+ * select proper conversion for input to algorithm
+ */
+ if( (sd->stc.dither->flags & STC_DIRECT ) ||
+ ((sd->stc.bits == 8) &&
+ (sd->stc.alg_item == 1)))
+ iconvert = stc_any_direct;
+ else if((sd->color_info.num_components == 3) &&
+ (sd->color_info.depth == 24) &&
+ (sizeof(long) == sd->stc.alg_item))
+ iconvert = stc_rgb24_long;
+ else if(sd->stc.flags & STCCMYK10) {
+ if( ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) &&
+ ( sd->stc.dither->minmax[0] == 0.0 ))
+ iconvert = stc_cmyk10_dbyte;
+ else if ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)
+ iconvert = stc_cmyk10_byte;
+ else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) &&
+ ( sd->stc.dither->minmax[0] == 0.0 ) &&
+ ( sd->stc.dither->minmax[1] <= 1023.0 ))
+ iconvert = stc_cmyk10_dlong;
+ else if( (sd->stc.dither->flags & STC_TYPE) == STC_LONG)
+ iconvert = stc_cmyk10_long;
+ else
+ iconvert = stc_cmyk10_float;
+ }
+ else if((sd->color_info.num_components == 4) &&
+ (sd->color_info.depth == 32) &&
+ (sizeof(long) == sd->stc.alg_item))
+ iconvert = stc_cmyk32_long;
+
+/*
+ * initialize the algorithm
+ */
+
+ if((*sd->stc.dither->fun)(sd,-prt_pixels,alg_line,buf,col_line) < 0)
+ SORRY;
+
+/*
+ * Main-Print-Loop
+ */
+
+ if(OK4GO) {
+#ifdef STC_SIGNAL
+ sigset_t stc_int_mask, stc_int_save, stc_int_pending;
+
+ sigemptyset(&stc_int_mask);
+ sigaddset(&stc_int_mask,SIGINT);
+ sigprocmask(SIG_BLOCK,&stc_int_mask, &stc_int_save);
+#endif /* STC_SIGNAL */
+
+
+ if(sd->color_info.num_components > 1) ncolor = 4;
+ else ncolor = 1;
+
+/*
+ * Decide, wether we Adjust Linefeeds or not. (I hate it here)
+ */
+ if((0 == ((sd->stc.escp_m*sd->stc.escp_u) % 10)) &&
+ (256 > ((sd->stc.escp_m*sd->stc.escp_u) / 10))) sd->stc.escp_lf = sd->stc.escp_m;
+ else sd->stc.escp_lf = 0;
+
+/*
+ * prepare run-values, then loop over scans
+ */
+ sd->stc.stc_y = 0; /* current printer y-Position */
+ sd->stc.buf_y = 0; /* Top-Position within the buffer */
+ sd->stc.prt_y = 0; /* physical position of the printer */
+ buf_i = 0; /* next free line in buffer */
+ sd->stc.flags &= ~STCPRINT; /* no data yet */
+
+ while(sd->stc.stc_y < sd->stc.prt_scans) { /* Until all scans are processed */
+ int need;
+
+ need = sd->stc.stc_y + npass * sd->stc.escp_m;
+
+ if(sd->stc.buf_y < need) { /* Nr. 5 (give me input) */
+
+/* read as much as the buffer can hold */
+ if(ncolor == 1) need = sd->stc.stc_y + sd->stc.prt_buf;
+ else need = sd->stc.stc_y + (sd->stc.prt_buf>>2);
+
+ for(;sd->stc.buf_y < need;
+ buf_i = (sd->stc.prt_buf-1) & (buf_i+ncolor),
+ ++sd->stc.buf_y) {
+
+ int color;
+ byte *ext_data;
+ byte *alg_data;
+
+/* initialize output data 1st -> may take shortcut */
+
+ for(color = 0; color < ncolor; ++color) {
+ memset(sd->stc.prt_data[buf_i+color],0,sd->stc.prt_size);
+ sd->stc.prt_width[buf_i+color] = 0;
+ }
+
+
+/* "read data", immediately continue if all is white */
+
+ if(sd->stc.buf_y < sd->stc.prt_scans) { /* Test for White */
+
+ gdev_prn_get_bits(pdev,sd->stc.buf_y,ext_line,&ext_data);
+
+ color = stc_iswhite(sd,prt_pixels,ext_data) ? ext_size : 0;
+
+ } else {
+
+ color = ext_size;
+
+ } /* Test for White */
+
+ if(color >= ext_size) { /* bypass processing */
+
+ if(sd->stc.dither->flags & STC_WHITE)
+ (*sd->stc.dither->fun)(sd,prt_pixels,NULL,buf,col_line);
+ continue;
+
+ } /* bypass processing */
+
+/* convert data for the various cases */
+
+ alg_data = (*iconvert)(sd,ext_data,prt_pixels,alg_line);
+
+
+/*
+ * invoke the dithering-algorithm
+ */
+
+ (*sd->stc.dither->fun)(sd,prt_pixels,alg_data,buf,col_line);
+/*
+ * convert col_line to printer-format (separate colors)
+ */
+ switch(sd->color_info.num_components) {
+ case 1: /* Black & White: just merge into 8 Bytes */
+ {
+ byte *bytein,*byteout;
+ int width;
+
+ bytein = col_line;
+ byteout = sd->stc.prt_data[buf_i];
+
+ for(width = 1; width <= sd->stc.prt_size; ++width) {
+ byte tmp = 0;
+ byte i;
+
+ for(i = 128; i; i >>= 1) if(*bytein++) tmp |= i;
+
+ if(tmp != 0) sd->stc.prt_width[buf_i] = width;
+
+ *byteout++ = tmp;
+ }
+ }
+ break;
+ case 3: /* convert rgb into cmyk */
+ {
+ byte *bytein;
+ int width;
+
+ bytein = col_line;
+
+ for(width = 0; width < sd->stc.prt_size; ++width) {
+ byte i,tmp,cmyk[4];
+
+ memset(cmyk,0,4);
+
+ for(i = 128; i; i >>= 1) {
+ static const byte rgb2cmyk[] = {
+ BLACK, /* 0->Black */
+ CYAN | MAGENTA, /* 1->BLUE */
+ CYAN | YELLOW, /* 2->GREEN */
+ CYAN, /* 3->CYAN */
+ MAGENTA | YELLOW, /* 4->RED */
+ MAGENTA, /* 5->MAGENTA */
+ YELLOW, /* 6->YELLOW */
+ 0}; /* 7->WHITE */
+
+ tmp = rgb2cmyk[(*bytein++) & 7];
+
+ if(tmp & BLACK) cmyk[3] |= i;
+ if(tmp & YELLOW) cmyk[2] |= i;
+ if(tmp & MAGENTA) cmyk[1] |= i;
+ if(tmp & CYAN) cmyk[0] |= i;
+ }
+
+ for(i = 0; i < 4; ++i) {
+ if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1;
+ sd->stc.prt_data[buf_i+i][width] = cmyk[i];
+ }
+ }
+ }
+ break;
+ case 4: /* split cmyk */
+ {
+ byte *bytein;
+ int width;
+
+ bytein = col_line;
+
+ for(width = 0; width < sd->stc.prt_size; ++width) {
+ byte i,tmp,cmyk[4];
+
+ memset(cmyk,0,4);
+
+ for(i = 128; i; i >>= 1) {
+ tmp = (*bytein++) & 15;
+ if(tmp & BLACK) cmyk[3] |= i;
+ if(tmp & YELLOW) cmyk[2] |= i;
+ if(tmp & MAGENTA) cmyk[1] |= i;
+ if(tmp & CYAN) cmyk[0] |= i;
+ }
+
+ for(i = 0; i < 4; ++i) {
+ if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1;
+ sd->stc.prt_data[buf_i+i][width] = cmyk[i];
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ } /* Nr. 5 (give me input) */
+
+/*
+ * Nr. 5 has got enough input, now we should print it
+ */
+ if((flags & STCCOMP) == STCDELTA) stc_print_delta(sd,prn_stream);
+ else if(npass > 1) stc_print_weave(sd,prn_stream);
+ else stc_print_bands(sd,prn_stream);
+
+#ifdef STC_SIGNAL
+ sigpending(&stc_int_pending);
+ if(sigismember(&stc_int_pending,SIGINT)) {
+ fputs("\033@[Aborted]\f", prn_stream);
+ fflush(prn_stream);
+ sigprocmask(SIG_SETMASK,&stc_int_save,NULL);
+ break;
+ }
+#endif /* STC_SIGNAL */
+
+ } /* Until all scans are processed */
+
+ if(sd->stc.flags & STCPRINT) {
+ if((flags & STCCOMP) == STCDELTA) fputc(0xe3,prn_stream);
+ fwrite(sd->stc.escp_release.data,1,sd->stc.escp_release.size,prn_stream);
+ fflush(prn_stream);
+ }
+#ifdef STC_SIGNAL
+ sigprocmask(SIG_SETMASK,&stc_int_save,NULL);
+#endif /* STC_DIGNAL */
+
+ }
+ }
+
+/***
+ *** Release the dynamic memory
+ ***/
+
+ if(ext_line != NULL)
+ gs_free(ext_line,ext_size,1,"stc_print_page/ext_line");
+
+ if(col_line != NULL)
+ gs_free(col_line,prt_pixels,1,"stc_print_page/col_line");
+
+ if(alg_line != NULL)
+ gs_free(alg_line,alg_size,sd->stc.alg_item,
+ "stc_print_page/alg_line");
+
+ if(buf != NULL)
+ gs_free(buf,buf_size,sd->stc.alg_item,"stc_print_page/buf");
+
+ if(sd->stc.prt_width != NULL)
+ gs_free(sd->stc.prt_width,sd->stc.prt_buf,sizeof(int),
+ "stc_print_page/prt_width");
+
+ if(sd->stc.prt_data != NULL) {
+ int i;
+
+ for(i = 0; i < sd->stc.prt_buf; ++i) {
+ if(sd->stc.prt_data[i] != NULL)
+ gs_free(sd->stc.prt_data[i],sd->stc.prt_size,1,
+ "stc_print_page/prt");
+ }
+
+ gs_free(sd->stc.prt_data,sd->stc.prt_buf,sizeof(byte *),
+ "stc_print_page/prt_data");
+ }
+
+ {
+ int i;
+ for(i = 0; i < sd->color_info.num_components; ++i) {
+ if(sd->stc.seed_row[i] != NULL)
+ gs_free(sd->stc.seed_row[i],sd->stc.seed_size,sizeof(int),
+ "stc_print_page/seed_row");
+ }
+ }
+
+ if(sd->stc.escp_data != NULL)
+ gs_free(sd->stc.escp_data,sd->stc.escp_size,1,
+ "stc_print_page/escp_data");
+
+ return OK4GO ? 0 : gs_error_undefined;
+}
+
+/*
+ * white-check
+ */
+private bool
+stc_iswhite(stcolor_device *sd, int prt_pixels,byte *ext_data)
+{
+ long b2do = (prt_pixels*sd->color_info.depth+7)>>3;
+ int bcmp = 4 * countof(sd->stc.white_run);
+ byte *wht = (byte *) sd->stc.white_run;
+
+ while(b2do >= bcmp) {
+ if(memcmp(ext_data,wht,bcmp)) break;
+ ext_data += bcmp;
+ b2do -= bcmp;
+ }
+
+ if((b2do > 0) && (b2do < bcmp))
+ b2do = memcmp(ext_data,sd->stc.white_end,b2do);
+
+ return b2do ? false : true;
+}
+
+/***
+ *** A bunch of routines that convert gslines into algorithms format.
+ ***/
+private byte *
+stc_any_depth(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
+{ /* general conversion */
+
+ int p,c, niext, nbits;
+ gx_color_index ciext,ci,cimsk,cvmsk;
+ byte *ap = alg_line;
+
+ nbits = sd->stc.bits;
+ cvmsk = ((gx_color_index) 1<<nbits) - 1;
+
+/* it is nonsense to use this algorithm for this cases, but if it claims
+ * generality, it should deliver correct results in this cases too */
+ if(sd->color_info.depth == (sd->color_info.num_components<<3)) nbits = 8;
+
+ cimsk = cvmsk;
+ for(c = 1; c < sd->color_info.num_components; ++c)
+ cimsk = (cimsk<<nbits) | cvmsk;
+
+ ciext = 0;
+ niext = 0;
+
+ for(p = 0; p < prt_pixels; ++p) { /* over pixels */
+
+ ci = ciext;
+ for(c = sd->color_info.depth-niext; c >= 8; c -= 8)
+ ci = (ci<<8) | *ext_data++;
+
+ if(c > 0) { /* partial byte required */
+
+ niext = 8 - c;
+ ciext = *ext_data++;
+ ci = (ci<<c) | (ciext>>niext);
+ ciext &= (1L<<niext)-1;
+
+ } else if(c < 0) { /* some bits left in ciext */
+
+ niext = -c;
+ ciext &= (1L<<niext)-1;
+ ci = ci>>niext;
+
+ } else { /* entire ciext used */
+
+ niext = 0;
+ ciext = 0;
+
+ } /* ciext-adjust */
+
+ ci &= cimsk;
+
+# define stc_storeapc(T) \
+ ((T *)ap)[c] = ((T *)(sd->stc.vals[c]))[ci & cvmsk];
+
+ for(c = sd->color_info.num_components; c--;) { /* comp */
+ STC_TYPESWITCH(sd->stc.dither,stc_storeapc)
+ ci >>= nbits;
+ } /* comp */
+
+# undef stc_storeapc
+
+ ap += sd->color_info.num_components * sd->stc.alg_item;
+
+ } /* over pixels */
+
+ return alg_line;
+} /* general conversion */
+
+/*
+ * rgb-data with depth=24, can use a faster algorithm
+ */
+private byte *
+stc_rgb24_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
+{ /* convert 3 bytes into appropriate long-Values */
+ register int p;
+ register long *out = (long *) alg_line;
+ register long *rvals = (long *) (sd->stc.vals[0]);
+ register long *gvals = (long *) (sd->stc.vals[1]);
+ register long *bvals = (long *) (sd->stc.vals[2]);
+
+ for(p = prt_pixels; p; --p) {
+ *out++ = rvals[*ext_data++];
+ *out++ = gvals[*ext_data++];
+ *out++ = bvals[*ext_data++];
+ }
+
+ return alg_line;
+} /* convert 3 bytes into appropriate long-Values */
+
+/*
+ * cmyk-data with depth=32, can use a faster algorithm
+ */
+private byte *
+stc_cmyk32_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
+{ /* convert 4 bytes into appropriate long-Values */
+ register int p;
+ register long *out = (long *) alg_line;
+ register long *cvals = (long *) (sd->stc.vals[0]);
+ register long *mvals = (long *) (sd->stc.vals[1]);
+ register long *yvals = (long *) (sd->stc.vals[2]);
+ register long *kvals = (long *) (sd->stc.vals[3]);
+
+ for(p = prt_pixels; p; --p) {
+ *out++ = cvals[*ext_data++];
+ *out++ = mvals[*ext_data++];
+ *out++ = yvals[*ext_data++];
+ *out++ = kvals[*ext_data++];
+ }
+
+ return alg_line;
+} /* convert 4 bytes into appropriate long-Values */
+
+/*
+ * handle indirect encoded cmyk-data
+ */
+#define STC_CMYK10_ANY(T)\
+ \
+ register int p = prt_pixels; \
+ register stc_pixel ci,k,n,mode; \
+ register stc_pixel *in = (stc_pixel *) ext_data; \
+ register T *out = (T *) alg_line; \
+ register T *cv = (T *) sd->stc.vals[0]; \
+ register T *mv = (T *) sd->stc.vals[1]; \
+ register T *yv = (T *) sd->stc.vals[2]; \
+ register T *kv = (T *) sd->stc.vals[3]; \
+ \
+ while(p--) { \
+ ci = *in++; \
+ mode = ci & 3; \
+ k = (ci>>2) & 0x3ff; \
+ if(mode == 3) { \
+ *out++ = cv[0]; \
+ *out++ = mv[0]; \
+ *out++ = yv[0]; \
+ *out++ = kv[k]; \
+ } else { \
+ out[3] = kv[k]; \
+ n = (ci>>12) & 0x3ff; \
+ if(mode == 2) { out[2] = yv[k]; } \
+ else { out[2] = yv[n]; n = (ci>>22) & 0x3ff; } \
+ if(mode == 1) { out[1] = mv[k]; } \
+ else { out[1] = mv[n]; n = (ci>>22) & 0x3ff; } \
+ if(mode == 0) out[0] = cv[k]; \
+ else out[0] = cv[n]; \
+ out += 4; \
+ } \
+ } \
+ \
+ return alg_line;
+
+private byte *
+stc_cmyk10_byte(stcolor_device *sd,
+ byte *ext_data,int prt_pixels,byte *alg_line)
+{
+ STC_CMYK10_ANY(byte)
+}
+private byte *
+stc_cmyk10_long(stcolor_device *sd,
+ byte *ext_data,int prt_pixels,byte *alg_line)
+{
+ STC_CMYK10_ANY(long)
+}
+private byte *
+stc_cmyk10_float(stcolor_device *sd,
+ byte *ext_data,int prt_pixels,byte *alg_line)
+{
+ STC_CMYK10_ANY(float)
+}
+
+#undef STC_CMYK10_ANY
+
+#define STC_CMYK10_DANY(T)\
+ \
+ register int p = prt_pixels; \
+ register stc_pixel ci,k,n,mode; \
+ register stc_pixel *in = (stc_pixel *) ext_data; \
+ register T *out = (T *) alg_line; \
+ \
+ while(p--) { \
+ ci = *in++; \
+ mode = ci & 3; \
+ k = (ci>>2) & 0x3ff; \
+ if(mode == 3) { \
+ *out++ = 0; \
+ *out++ = 0; \
+ *out++ = 0; \
+ *out++ = k; \
+ } else { \
+ out[3] = k; \
+ n = (ci>>12) & 0x3ff; \
+ if(mode == 2) { out[2] = k; } \
+ else { out[2] = n; n = (ci>>22) & 0x3ff; } \
+ if(mode == 1) { out[1] = k; } \
+ else { out[1] = n; n = (ci>>22) & 0x3ff; } \
+ if(mode == 0) out[0] = k; \
+ else out[0] = n; \
+ out += 4; \
+ } \
+ } \
+ \
+ return alg_line;
+
+
+private byte *
+stc_cmyk10_dbyte(stcolor_device *sd,
+ byte *ext_data,int prt_pixels,byte *alg_line)
+{
+ STC_CMYK10_DANY(byte)
+}
+private byte *
+stc_cmyk10_dlong(stcolor_device *sd,
+ byte *ext_data,int prt_pixels,byte *alg_line)
+{
+ STC_CMYK10_DANY(long)
+}
+
+#undef STC_CMYK10_DANY
+
+/*
+ * if the algorithm uses bytes & bytes are in ext_data, use them
+ */
+/*ARGSUSED*/
+private byte *
+stc_any_direct(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
+{ /* return ext_data */
+ return ext_data;
+} /* return ext_data */
+
+/* ----------------------------------------------------------------------- */
+/* stc_rle: epson ESC/P2 RLE-Encoding
+ */
+private int
+stc_rle(byte *out,const byte *in,int width)
+{
+
+ int used = 0;
+ int crun,cdata;
+ byte run;
+
+ if(in != NULL) { /* Data present */
+
+ crun = 1;
+
+ while(width > 0) { /* something to compress */
+
+ run = in[0];
+
+ while((width > crun) && (run == in[crun])) if(++crun == 129) break;
+
+ if((crun > 2) || (crun == width)) { /* use this run */
+
+ *out++ = (257 - crun) & 0xff; *out++ = run; used += 2;
+
+ width -= crun; in += crun;
+ crun = 1;
+
+ } else { /* ignore this run */
+
+ for(cdata = crun; (width > cdata) && (crun < 4);) {
+ if(run == in[cdata]) crun += 1;
+ else run = in[cdata], crun = 1;
+ if(++cdata == 128) break;
+ }
+
+ if(crun < 3) crun = 0; /* ignore trailing run */
+ else cdata -= crun;
+
+ *out++ = cdata-1; used++;
+ memcpy(out,in,cdata); used += cdata; out += cdata;
+
+ width -= cdata; in += cdata;
+
+ } /* use/ignore run */
+
+ } /* something to compress */
+
+ } else { /* Empty scans to fill bands */
+
+ while(width > 0) {
+ crun = width > 129 ? 129 : width;
+ width -= crun;
+ *out++ = (257 - crun) & 0xff;
+ *out++ = 0;
+ used += 2;
+ }
+ } /* Data present or empty */
+ return used;
+}
+
+
+/*
+ * Horizontal & vertical positioning, color-selection, "ESC ."
+ */
+private int
+stc_print_escpcmd(stcolor_device *sd, FILE *prn_stream,
+ int escp_used, int color,int m,int wbytes)
+{
+
+ int dy = sd->stc.stc_y - sd->stc.prt_y; /* number of units to skip */
+ int nlf;
+
+/* ESC-R color codes, used only here */
+ static const byte stc_colors[] = { 0x02, 0x01, 0x04, 0x00 }; /* CMYK */
+
+/*
+ * initialize the printer, if necessary
+ */
+ if(0 == (sd->stc.flags & STCPRINT)) {
+
+ fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream);
+
+ if(0 < sd->stc.escp_lf) { /* Adjust Linefeed */
+ fputc('\033', prn_stream);
+ fputc('+', prn_stream);
+ fputc(((sd->stc.escp_m*sd->stc.escp_u) / 10),prn_stream);
+ } /* Adjust Linefeed */
+ sd->stc.flags |= STCPRINT;
+ }
+
+ sd->stc.escp_data[escp_used++] = '\r'; /* leftmost position */
+
+ if(dy) { /* position the printer */
+ if(( sd->stc.escp_lf > 0) && /* Linefeed allowed */
+ ((dy % sd->stc.escp_lf) == 0)) /* and possible */
+ nlf = dy / sd->stc.escp_lf;
+ else nlf = 7;
+
+ if(nlf > 6) {
+ sd->stc.escp_data[escp_used++] = '\033';
+ sd->stc.escp_data[escp_used++] = '(';
+ sd->stc.escp_data[escp_used++] = 'V';
+ sd->stc.escp_data[escp_used++] = '\002';
+ sd->stc.escp_data[escp_used++] = '\000';
+ sd->stc.escp_data[escp_used++] = sd->stc.stc_y & 0xff;
+ sd->stc.escp_data[escp_used++] = (sd->stc.stc_y >> 8) & 0xff;
+ } else {
+ while(nlf--) sd->stc.escp_data[escp_used++] = '\n';
+ }
+ sd->stc.prt_y = sd->stc.stc_y;
+ } /* position the printer */
+
+ if((sd->color_info.num_components > 1) &&
+ (sd->stc.escp_c != stc_colors[color])) { /* select color */
+ sd->stc.escp_data[escp_used++] = '\033';
+ sd->stc.escp_data[escp_used++] = 'r';
+ sd->stc.escp_c = stc_colors[color];
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_c;
+ } /* select color */
+
+/*
+ * Build the command used
+ */
+ sd->stc.escp_data[escp_used++] = '\033';
+ sd->stc.escp_data[escp_used++] = '.';
+ sd->stc.escp_data[escp_used++] =
+ (sd->stc.flags & STCCOMP) == STCPLAIN ? 0 : 1;
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_v;
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_h;
+ sd->stc.escp_data[escp_used++] = m;
+ sd->stc.escp_data[escp_used++] = (wbytes<<3) & 0xff; /* width in Pixels */
+ sd->stc.escp_data[escp_used++] = (wbytes>>5) & 0xff;
+
+ return escp_used;
+}
+
+/*
+ * compute width of a group of scanlines
+ */
+private int
+stc_bandwidth(stcolor_device *sd,int color,int m,int npass)
+{
+ int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
+ int buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
+ int w = 0;
+
+ while(m-- > 0) { /* check width */
+ if(sd->stc.prt_width[buf_a] > w) w = sd->stc.prt_width[buf_a];
+ buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass);
+ } /* check width */
+
+ return w;
+}
+
+/*
+ * Multi-Pass Printing-Routine
+ */
+private void
+stc_print_weave(stcolor_device *sd, FILE *prn_stream)
+{
+
+ int escp_used,nprint,nspace,color,buf_a,iprint,w;
+
+ int npass = sd->stc.escp_v / sd->stc.escp_u;
+ int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
+
+
+ while(sd->stc.stc_y < sd->stc.prt_scans) {
+
+/*
+ * compute spacing & used heads (seems to work with odd escp_m)
+ */
+ if(sd->stc.stc_y >= sd->stc.escp_m) { /* in normal mode */
+ nprint = sd->stc.escp_m;
+ nspace = sd->stc.escp_m;
+ } else if((sd->stc.stc_y) < npass) { /* initialisation */
+ nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass);
+ nspace = 1;
+ } else { /* switch to normal */
+ nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass);
+ nspace = sd->stc.escp_m - sd->stc.stc_y;
+ }
+ iprint = sd->stc.stc_y + npass * nprint;
+ if(sd->stc.buf_y < iprint) break;
+
+ escp_used = 0;
+ for(color = 0; color < ncolor; ++color) { /* print the colors */
+
+ if(0 == (w = stc_bandwidth(sd,color,nprint,npass))) continue;
+
+ escp_used = stc_print_escpcmd(sd,prn_stream,
+ escp_used,color,sd->stc.escp_m,w);
+
+ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
+ for(iprint = 0; iprint < nprint; ++iprint) { /* send data */
+
+ if((sd->stc.flags & STCCOMP) == STCPLAIN) {
+ memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w);
+ escp_used += w;
+ } else {
+ escp_used += stc_rle(sd->stc.escp_data+escp_used,
+ sd->stc.prt_data[buf_a],w);
+ }
+
+ fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
+ escp_used = 0;
+
+ buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass);
+
+ } /* send data */
+
+ while(iprint++ < sd->stc.escp_m) { /* add empty rows */
+
+ if((sd->stc.flags & STCCOMP) == STCPLAIN) {
+ memset(sd->stc.escp_data+escp_used,0,w);
+ escp_used += w;
+ } else {
+ escp_used += stc_rle(sd->stc.escp_data+escp_used,NULL,w);
+ }
+
+ fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
+ escp_used = 0;
+ } /* add empty rows */
+ } /* print the colors */
+
+ sd->stc.stc_y += nspace;
+ }
+}
+
+/*
+ * Single-Pass printing-Routine
+ */
+private void
+stc_print_bands(stcolor_device *sd, FILE *prn_stream)
+{
+
+ int escp_used,color,buf_a,iprint,w,m;
+
+ int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
+
+ while(sd->stc.stc_y < sd->stc.prt_scans) {
+
+/*
+ * find the begin of the band
+ */
+ for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) {
+ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor);
+ for(color = 0; color < ncolor; ++color)
+ if(sd->stc.prt_width[buf_a+color] > w)
+ w = sd->stc.prt_width[buf_a+color];
+ if(w != 0) break;
+ }
+ if(w == 0) break;
+/*
+ * adjust the band-height
+ */
+ w = sd->stc.prt_scans - sd->stc.stc_y;
+ if((w < sd->stc.escp_m) && (sd->stc.escp_v != 40)) {
+ if(w < 8) m = 1;
+ else if(w < 24) m = 8;
+ else m = 24;
+ } else {
+ m = sd->stc.escp_m;
+ }
+
+ if(sd->stc.buf_y < (sd->stc.stc_y+m)) break;
+
+ escp_used = 0;
+ for(color = 0; color < ncolor; ++color) { /* print the colors */
+
+ if(0 == (w = stc_bandwidth(sd,color,m,1))) continue; /* shortcut */
+
+ escp_used = stc_print_escpcmd(sd,prn_stream,escp_used,color,m,w);
+
+ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
+ for(iprint = 0; iprint < m; ++iprint) { /* send data */
+
+ if((sd->stc.flags & STCCOMP) == STCPLAIN) {
+ memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w);
+ escp_used += w;
+ } else {
+ escp_used += stc_rle(sd->stc.escp_data+escp_used,
+ sd->stc.prt_data[buf_a],w);
+ }
+
+ fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
+ escp_used = 0;
+
+ buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor);
+
+ } /* send data */
+
+ } /* print the colors */
+
+ sd->stc.stc_y += m;
+ }
+}
+/* ----------------------------------------------------------------------- */
+
+private int
+stc_deltarow(byte *out,const byte *in,int width,byte *seed)
+{
+
+ int istop,nmove,ndata,i,j;
+ int *wseed = (int *) seed;
+ int used = 0;
+
+ seed += sizeof(int);
+
+ if((in != NULL) && (width > 0)) { /* Data present */
+
+ istop = width < wseed[0] ? wseed[0] : width;
+
+ i = 0;
+ while(i < istop) {
+
+ for(j = i; j < istop; ++j) if(in[j] != seed[j]) break;
+
+ nmove = j - i;
+
+ if(nmove > 0) { /* issue a move */
+ i = j;
+ if(i == istop) break;
+
+ if( nmove < 8) {
+ out[used++] = 0x40 | nmove;
+ } else if(nmove < 128) {
+ out[used++] = 0x51;
+ out[used++] = nmove;
+ } else {
+ out[used++] = 0x52;
+ out[used++] = 0xff & nmove;
+ out[used++] = 0xff & (nmove>>8);
+ }
+ } /* issue a move */
+
+/*
+ * find the end of this run
+ */
+ nmove = 0;
+ for(j = i+1; (j < istop) && ((nmove < 4)); ++j) {
+ if(in[j] == seed[j]) nmove += 1;
+ else nmove = 0;
+ }
+
+ ndata = j-i-nmove;
+
+ nmove = stc_rle(out+used+3,in+i,ndata);
+ if(nmove < 16) {
+ out[used++] = 0x20 | nmove;
+ for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+2];
+ } else if(nmove < 256) {
+ out[used++] = 0x31;
+ out[used++] = nmove;
+ for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+1];
+ } else {
+ out[used++] = 0x32;
+ out[used++] = 0xff & nmove;
+ out[used++] = 0xff & (nmove>>8);
+ }
+ used += nmove;
+ i += ndata;
+ }
+
+ memcpy(seed,in,istop);
+ wseed[0] = width;
+
+ } else if(wseed[0] > 0) { /* blank line, but seed has data */
+
+ out[used++] = 0xe1; /* clear row */
+ memset(seed,0,wseed[0]);
+ wseed[0] = 0;
+
+ }
+
+ return used;
+}
+
+/*
+ * Slightly different single-pass printing
+ */
+private void
+stc_print_delta(stcolor_device *sd, FILE *prn_stream)
+{
+
+ int color,buf_a,w;
+ int escp_used = 0;
+ int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
+
+ while(sd->stc.stc_y < sd->stc.prt_scans) {
+
+/*
+ * find the begin of the band
+ */
+ for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) {
+ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor);
+ for(color = 0; color < ncolor; ++color)
+ if(sd->stc.prt_width[buf_a+color] > w)
+ w = sd->stc.prt_width[buf_a+color];
+ if(w != 0) break;
+ }
+
+ if(sd->stc.buf_y == sd->stc.stc_y) break;
+
+ escp_used = 0;
+
+/*
+ * Send Initialization & ESC . 3 once
+ */
+ if(0 == (sd->stc.flags & STCPRINT)) {
+
+ sd->stc.flags |= STCPRINT;
+
+ fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream);
+
+ sd->stc.escp_data[escp_used++] = '\033';
+ sd->stc.escp_data[escp_used++] = '.';
+ sd->stc.escp_data[escp_used++] = 3;
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_v;
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_h;
+ sd->stc.escp_data[escp_used++] = sd->stc.escp_m;
+ sd->stc.escp_data[escp_used++] = 0;
+ sd->stc.escp_data[escp_used++] = 0;
+ sd->stc.escp_data[escp_used++] = 0xe4; /* MOVXBYTE */
+ }
+
+ if(sd->stc.stc_y != sd->stc.prt_y) { /* really position the printer */
+ w = sd->stc.stc_y - sd->stc.prt_y;
+ if( w < 16) {
+ sd->stc.escp_data[escp_used++] = 0x60 | w;
+ } else if(w < 256) {
+ sd->stc.escp_data[escp_used++] = 0x71;
+ sd->stc.escp_data[escp_used++] = w;
+ } else {
+ sd->stc.escp_data[escp_used++] = 0x72;
+ sd->stc.escp_data[escp_used++] = 0xff & w;
+ sd->stc.escp_data[escp_used++] = 0xff & (w>>8);
+ }
+ sd->stc.prt_y = sd->stc.stc_y;
+ } /* really position the printer */
+
+ for(color = 0; color < ncolor; ++color) { /* print the colors */
+
+/* Color-Selection */
+ if(color == (ncolor-1)) {
+ sd->stc.escp_data[escp_used++] = 0x80; /* Black */
+ } else {
+ switch(color) {
+ case 1: sd->stc.escp_data[escp_used++] = 0x81; break; /* M */
+ case 2: sd->stc.escp_data[escp_used++] = 0x84; break; /* Y */
+ default: sd->stc.escp_data[escp_used++] = 0x82; break; /* C */
+ }
+ }
+
+/* Data-Transfer */
+ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
+
+ w = stc_deltarow(sd->stc.escp_data+escp_used,
+ sd->stc.prt_data[buf_a],sd->stc.prt_width[buf_a],
+ sd->stc.seed_row[color]);
+
+ if(w == 0) escp_used -= 1;
+ else escp_used += w;
+
+ if(escp_used > 0) fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
+ escp_used = 0;
+
+ } /* print the colors */
+
+ sd->stc.stc_y += 1;
+
+ }
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+/***
+ *** Free-Data: release the specific-Arrays
+ ***/
+private void
+stc_freedata(stc_t *stc)
+{
+ int i,j;
+
+ for(i = 0; i < 4; ++i) {
+ if(stc->code[i] != NULL) {
+
+ for(j = 0; j < i; ++j) if(stc->code[i] == stc->code[j]) break;
+
+ if(i == j) gs_free(stc->code[i],1<<stc->bits,sizeof(gx_color_value),
+ "stcolor/code");
+ }
+
+ if(stc->vals[i] != NULL) {
+
+ for(j = 0; j < i; ++j)
+ if(stc->vals[i] == stc->vals[j]) break;
+
+ if(i == j) gs_free(stc->vals[i],1<<stc->bits,sd->stc.alg_item,
+ "stcolor/transfer");
+ }
+ }
+
+ for(i = 0; i < 4; ++i) {
+ stc->code[i] = NULL;
+ stc->vals[i] = NULL;
+ }
+}
+
+/***
+ *** open the device and initialize margins & arrays
+ ***/
+
+private int
+stc_open(gx_device *pdev) /* setup margins & arrays */
+{
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int i,j,code;
+ gx_color_index white;
+ byte *bpw,*bpm;
+
+ code = 0;
+/*
+ * Establish Algorithm-Table, if not present
+ */
+ if(sd->stc.algorithms.size == 0) {
+ gs_param_string *dp;
+ for(i = 0; stc_dither[i].name != NULL; ++i); /* count 'em */
+ sd->stc.algorithms.size = i;
+ dp = gs_malloc(i,sizeof(gs_param_string),
+ "stcolor/algorithms");
+ if(dp == NULL) {
+ code = gs_error_VMerror;
+ sd->stc.algorithms.size = 0;
+ } else {
+ sd->stc.algorithms.data = dp;
+ sd->stc.algorithms.persistent = true;
+ for(i = 0; stc_dither[i].name != NULL; ++i) {
+ param_string_from_string(dp[i],stc_dither[i].name);
+ }
+ }
+ }
+
+# define stc_sizeofitem(T) sd->stc.alg_item = sizeof(T)
+ STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem)
+
+ stc_print_setup(sd);
+
+/*
+ * Establish internal Value & Code-Arrays
+ */
+
+
+ for(i = 0; i < sd->color_info.num_components; ++i) { /* comp */
+
+ if((sd->stc.sizc[i] > 1) && (sd->stc.extc[i] != NULL)) { /* code req. */
+
+ for(j = 0; j < i; ++j) if(sd->stc.extc[i] == sd->stc.extc[j]) break;
+
+ if(i == j) { /* new one */
+ sd->stc.code[i] = gs_malloc(1<<sd->stc.bits,sizeof(gx_color_value),
+ "stcolor/code");
+
+ if(sd->stc.code[i] == NULL) { /* error */
+ code = gs_error_VMerror;
+ } else { /* success */
+/*
+ * Try making things easier:
+ * normalize values to 0.0/1.0-Range
+ * X-Axis: Color-Values (implied)
+ * Y-Values: Indices (given)
+ */
+ unsigned long ly,iy;
+ double ystep,xstep,fx,fy;
+
+/* normalize */
+
+ fx = 1e18;
+ fy = -1e18;
+ for(ly = 0; ly < sd->stc.sizc[i]; ++ly) {
+ if(sd->stc.extc[i][ly] < fx) fx = sd->stc.extc[i][ly];
+ if(sd->stc.extc[i][ly] > fy) fy = sd->stc.extc[i][ly];
+ }
+ if((fx != 0.0) || (fy != 1.0)) {
+ fy = 1.0 / (fy - fx);
+ for(ly = 0; ly < sd->stc.sizc[i]; ++ly)
+ sd->stc.extc[i][ly] = fy * (sd->stc.extc[i][ly]-fx);
+ }
+
+/* interpolate */
+ ystep = 1.0 / (double)((1<<sd->stc.bits)-1);
+ xstep = 1.0 / (double)( sd->stc.sizc[i] -1);
+
+ iy = 0;
+ for(ly = 0; ly < (1<<sd->stc.bits); ++ly) {
+ fy = ystep * ly;
+ while(((iy+1) < sd->stc.sizc[i]) &&
+ ( fy > sd->stc.extc[i][iy+1])) ++iy;
+ fx = iy + (fy - sd->stc.extc[i][iy])
+ / (sd->stc.extc[i][iy+1] - sd->stc.extc[i][iy]);
+ fx *= xstep * gx_max_color_value;
+
+ fx = fx < 0.0 ? 0.0 :
+ (fx > gx_max_color_value ? gx_max_color_value : fx);
+
+ sd->stc.code[i][ly] = fx;
+ if((fx-sd->stc.code[i][ly]) >= 0.5) sd->stc.code[i][ly] += 1;
+ }
+ } /* error || success */
+
+ } else { /* shared one */
+
+ sd->stc.code[i] = sd->stc.code[j];
+
+ } /* new || shared one */
+ } /* code req. */
+
+ if((sd->stc.sizv[i] > 1) && (sd->stc.extv[i] != NULL)) { /* vals req. */
+
+ for(j = 0; j < i; ++j)
+ if((sd->stc.extc[i] == sd->stc.extc[j]) &&
+ (sd->stc.extv[i] == sd->stc.extv[j])) break;
+
+ if(i == j) { /* new one */
+
+ sd->stc.vals[i] =
+ gs_malloc(1<<sd->stc.bits,sd->stc.alg_item,"stcolor/transfer");
+
+ if(sd->stc.vals[i] == NULL) {
+
+ code = gs_error_VMerror;
+
+ } else { /* success */
+
+
+ if(sd->stc.code[i] == NULL) { /* linear */
+
+ byte *Out = sd->stc.vals[i];
+ int Nout = 1<<sd->stc.bits;
+ double Omin = sd->stc.dither->minmax[0];
+ double Omax = sd->stc.dither->minmax[1];
+ float *In = sd->stc.extv[i];
+ int Nin = sd->stc.sizv[i];
+ unsigned long I,io;
+ double Istep,Ostep,Y;
+ byte Ovb; long Ovl;
+
+ Istep = 1.0 / (double) ((Nin)-1);
+ Ostep = 1.0 / (double) ((Nout)-1);
+
+ for(io = 0; io < (Nout); ++io) {
+ I = (long)(io * ((Nin)-1))/((Nout)-1);
+
+ if((I+1) < (Nin))
+ Y = In[I] + (In[I+1]-In[I])
+ * ((double) io * Ostep - (double)I * Istep)
+ / (double) Istep;
+ else
+ Y = In[I] + (In[I]-In[I-1])
+ * ((double) io * Ostep - (double)I * Istep)
+ / (double) Istep;
+
+ Y = Omin + (Omax-Omin) * Y;
+ Y = Y < Omin ? Omin : (Y > Omax ? Omax : Y);
+
+
+ switch(sd->stc.dither->flags & STC_TYPE) {
+ case STC_BYTE:
+ Ovb = Y;
+ if(((Y-Ovb) >= 0.5) && ((Ovb+1) <= Omax)) Ovb += 1;
+ Out[io] = Ovb;
+ break;
+ case STC_LONG:
+ Ovl = Y;
+ if(((Y-Ovl) >= 0.5) && ((Ovl+1) <= Omax)) Ovl += 1;
+ if(((Ovl-Y) >= 0.5) && ((Ovl-1) >= Omax)) Ovl -= 1;
+ ((long *)Out)[io] = Ovl;
+ break;
+ default:
+ ((float *)Out)[io] = Y;
+ break;
+ }
+ }
+
+ } else { /* encoded */
+ unsigned long j,o;
+ double xstep,x,y;
+
+ xstep = 1.0 / (double) (sd->stc.sizv[i]-1);
+
+/*
+ * The following differs in so far from the previous, that the desired
+ * X-Values are stored in another array.
+ */
+ for(o = 0; o < (1<<sd->stc.bits); ++o) { /* code-loop */
+
+ x = sd->stc.code[i][o]; x /= gx_max_color_value;
+
+ j = x / xstep;
+
+ if((j+1) < sd->stc.sizv[i]) {
+ y = sd->stc.extv[i][j];
+ y += (sd->stc.extv[i][j+1]-y)*(x-(double)j*xstep)/xstep;
+ } else {
+ y = sd->stc.extv[i][j];
+ y += (y-sd->stc.extv[i][j-1])*(x-(double)j*xstep)/xstep;
+ }
+
+ y = sd->stc.dither->minmax[0]
+ +(sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0])*y;
+
+# define stc_adjvals(T) \
+ ((T *)(sd->stc.vals[i]))[o] = y; \
+ \
+ if(((y-((T *)(sd->stc.vals[i]))[o]) >= 0.5) && \
+ ((1+((T *)(sd->stc.vals[i]))[o]) <= sd->stc.dither->minmax[1]))\
+ ((T *)(sd->stc.vals[i]))[o] += 1; \
+ \
+ if(((((T *)(sd->stc.vals[i]))[o]-y) >= 0.5) && \
+ ((((T *)(sd->stc.vals[i]))[o]-1) >= sd->stc.dither->minmax[0]))\
+ ((T *)(sd->stc.vals[i]))[o] -= 1;
+
+ STC_TYPESWITCH(sd->stc.dither,stc_adjvals)
+
+# undef stc_adjvals
+ } /* code-loop */
+ } /* lineaer / encoded */
+ } /* error || success */
+
+ } else { /* shared one */
+
+ sd->stc.vals[i] = sd->stc.vals[j];
+
+ } /* new || shared one */
+ } /* vals req. */
+ } /* comp */
+
+ if(code == 0) {
+
+ sd->stc.flags |= STCOK4GO;
+
+/*
+ * Arrgh: open-procedure seems to be the right-place, but it is
+ * necessary to establish the defaults for omitted procedures too.
+ */
+
+ switch(sd->color_info.num_components) { /* Establish color-procs */
+ case 1:
+ set_dev_proc(sd,map_rgb_color, stc_map_gray_color);
+ set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(sd,map_color_rgb, stc_map_color_gray);
+ white = stc_map_gray_color((gx_device *) sd,
+ gx_max_color_value,gx_max_color_value,gx_max_color_value);
+ break;
+ case 3:
+ set_dev_proc(sd,map_rgb_color, stc_map_rgb_color);
+ set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(sd,map_color_rgb, stc_map_color_rgb);
+ white = stc_map_rgb_color((gx_device *) sd,
+ gx_max_color_value,gx_max_color_value,gx_max_color_value);
+ break;
+ default:
+ set_dev_proc(sd,map_rgb_color, gx_default_map_rgb_color);
+ if(sd->stc.flags & STCCMYK10) {
+ set_dev_proc(sd,map_cmyk_color,stc_map_cmyk10_color);
+ set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk10);
+ white = stc_map_cmyk10_color((gx_device *) sd,0,0,0,0);
+ } else {
+ set_dev_proc(sd,map_cmyk_color,stc_map_cmyk_color);
+ set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk);
+ white = stc_map_cmyk_color((gx_device *) sd,0,0,0,0);
+ }
+ break; /* Establish color-procs */
+ }
+
+
+/*
+ * create at least a Byte
+ */
+ if(sd->color_info.depth < 2) white |= (white<<1);
+ if(sd->color_info.depth < 4) white |= (white<<2);
+ if(sd->color_info.depth < 8) white |= (white<<4);
+
+/*
+ * copy the Bytes
+ */
+ bpw = (byte *) sd->stc.white_run;
+
+ if(sd->color_info.depth < 16) {
+ for(i = 0; i < sizeof(sd->stc.white_run); i += 1) {
+ bpw[i] = 0xff & white;
+ }
+ } else if(sd->color_info.depth < 24) {
+ for(i = 0; i < sizeof(sd->stc.white_run); i += 2) {
+ bpw[i] = 0xff & (white>>8);
+ bpw[i+1] = 0xff & white;
+ }
+ } else if(sd->color_info.depth < 32) {
+ for(i = 0; i < sizeof(sd->stc.white_run); i += 3) {
+ bpw[i] = 0xff & (white>>16);
+ bpw[i+1] = 0xff & (white>> 8);
+ bpw[i+2] = 0xff & white;
+ }
+ } else {
+ for(i = 0; i < sizeof(sd->stc.white_run); i += 4) {
+ bpw[i] = 0xff & (white>>24);
+ bpw[i+1] = 0xff & (white>>16);
+ bpw[i+2] = 0xff & (white>> 8);
+ bpw[i+3] = 0xff & white;
+ }
+ }
+/*
+ * compute the trailer
+ */
+ j = sd->width -
+ (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch;
+ j = j * sd->color_info.depth; /* the Bit-count */
+ j = j % (32*countof(sd->stc.white_run)); /* remaining Bits */
+
+ bpm = (byte *) sd->stc.white_end;
+ for(i = 0; i < (4*countof(sd->stc.white_end)); ++i) {
+ if( j <= 0) {
+ bpm[i] = 0;
+ } else if(j >= 8) {
+ bpm[i] = 0xff;
+ j -= 8;
+ } else {
+ bpm[i] = 0xff ^ ((1<<(8-j))-1);
+ j = 0;
+ }
+ bpm[i] &= bpw[i];
+ }
+
+/*
+ * Call super-class open
+ */
+
+ return gdev_prn_open(pdev);
+
+ } else {
+
+ stc_freedata(&sd->stc);
+
+ return_error(code);
+ }
+
+}
+
+/***
+ *** stc_close: release the internal data
+ ***/
+private int
+stc_close(gx_device *pdev)
+{
+ stc_freedata(&((stcolor_device *) pdev)->stc);
+ ((stcolor_device *) pdev)->stc.flags &= ~STCOK4GO;
+ return gdev_prn_close(pdev);
+}
+
+
+/***
+ *** Function for Bit-Truncation, including direct-byte-transfer
+ ***/
+private gx_color_value
+stc_truncate(stcolor_device *sd,int i,gx_color_value v)
+{
+
+ if(sd->stc.bits < gx_color_value_bits) {
+ if(sd->stc.code[i] != NULL) {
+/*
+ * Perform binary search in the code-array
+ */
+ long s;
+ gx_color_value *p;
+
+ s = sd->stc.bits > 1 ? 1L<<(sd->stc.bits-2) : 0L;
+ p = sd->stc.code[i]+(1L<<(sd->stc.bits-1));
+
+ while(s > 0) {
+ if(v > *p) {
+ p += s;
+ } else if(v < p[-1]) {
+ p -= s;
+ } else {
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ break;
+ }
+ s >>= 1;
+ }
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ v = p - sd->stc.code[i];
+
+ } else {
+
+ v >>= gx_color_value_bits-sd->stc.bits;
+
+ }
+
+/*
+ V = (((1L<<D->stc.bits)-1)*V+(gx_max_color_value>>1))\
+ /gx_max_color_value; \
+*/
+ }
+ return v;
+}
+
+private gx_color_value
+stc_truncate1(stcolor_device *sd,int i,gx_color_value v)
+{
+
+ return sd->stc.vals[i][stc_truncate(sd,i,v)];
+}
+
+/***
+ *** Expansion of indices for reverse-mapping
+ ***/
+private gx_color_value
+stc_expand(stcolor_device *sd,int i,gx_color_index col)
+{
+
+ gx_color_index cv;
+ gx_color_index l = (1<<sd->stc.bits)-1;
+
+ if(sd->stc.code[i] != NULL) {
+
+ cv = sd->stc.code[i][col & l];
+
+ } else if(sd->stc.bits < gx_color_value_bits) {
+
+ cv = (col & l)<<(gx_color_value_bits-sd->stc.bits);
+ cv += (col & l)/l * ((1<<(gx_color_value_bits-sd->stc.bits))-1);
+
+ } else if(sd->stc.bits > gx_color_value_bits) {
+
+ cv = (col & l)>>(sd->stc.bits-gx_color_value_bits);
+
+ } else {
+
+ cv = col & l;
+
+ }
+
+ return cv;
+}
+
+/***
+ *** color-mapping of gray-scales
+ ***/
+private gx_color_index
+stc_map_gray_color(gx_device *pdev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ gx_color_index rv;
+
+ if((r == g) && (g == b)) {
+
+ rv = gx_max_color_value - r;
+
+ } else if(sd->stc.am != NULL) {
+ float *m,fv;
+
+ m = sd->stc.am;
+
+ fv = gx_max_color_value;
+ fv -= *m++ * (float) r; fv -= *m++ * (float) g; fv -= *m * (float) b;
+
+ if( fv < 0.0) rv = 0;
+ else if((fv+0.5) > gx_max_color_value) rv = gx_max_color_value;
+ else rv = fv+0.5;
+
+ } else {
+
+ rv = ((gx_color_index)gx_max_color_value)<<3;
+ rv -= (gx_color_index) 3 * r;
+ rv -= (gx_color_index) 3 * g;
+ rv -= ((gx_color_index)b)<<1;
+ rv = (rv+4)>>3;
+ if(rv > gx_max_color_value) rv = gx_max_color_value;
+
+ }
+
+ if(( sd->stc.bits == 8) &&
+ ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE))
+ rv = stc_truncate1(sd,0,(gx_color_value)rv);
+ else
+ rv = stc_truncate(sd,0,(gx_color_value)rv);
+
+ return rv;
+}
+
+private int
+stc_map_color_gray(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
+{
+ stcolor_device *sd = (stcolor_device *) pdev;
+ gx_color_index l = ((gx_color_index)1<<sd->stc.bits)-1;
+
+ prgb[0] = gx_max_color_value - stc_expand(sd,0,color & l);
+ prgb[1] = prgb[0]; prgb[2] = prgb[0];
+
+ return 0;
+}
+
+/***
+ *** color-mapping of rgb-values
+ ***/
+private gx_color_index
+stc_map_rgb_color(gx_device *pdev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits;
+ gx_color_index rv = 0;
+
+ if((sd->stc.am != NULL) && ((r != g) || (g != b))) {
+ float *m,fr,fg,fb,fv;
+
+ m = sd->stc.am;
+ fr = r; fg = g; fb = b;
+
+ fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
+
+ if( fv < 0.0) r = 0;
+ else if((fv+0.5) > gx_max_color_value) r = gx_max_color_value;
+ else r = fv+0.5;
+
+ fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
+
+ if( fv < 0.0) g = 0;
+ else if((fv+0.5) > gx_max_color_value) g = gx_max_color_value;
+ else g = fv+0.5;
+
+ fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
+
+ if( fv < 0.0) b = 0;
+ else if((fv+0.5) > gx_max_color_value) b = gx_max_color_value;
+ else b = fv+0.5;
+
+ }
+
+ if(( sd->stc.bits == 8) &&
+ ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
+ rv = stc_truncate1(sd,0,r);
+ rv = (rv<<shift) | stc_truncate1(sd,1,g);
+ rv = (rv<<shift) | stc_truncate1(sd,2,b);
+ } else {
+ rv = stc_truncate(sd,0,r);
+ rv = (rv<<shift) | stc_truncate(sd,1,g);
+ rv = (rv<<shift) | stc_truncate(sd,2,b);
+ }
+
+ return rv;
+}
+
+private int
+stc_map_color_rgb(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits;
+ gx_color_index l = ((gx_color_index)1<<sd->stc.bits)-1;
+
+ prgb[0] = stc_expand(sd,0,((color>>(shift<<1)) & l));
+ prgb[1] = stc_expand(sd,1,((color>> shift ) & l));
+ prgb[2] = stc_expand(sd,2,( color & l));
+
+ return 0;
+}
+
+/***
+ *** color-mapping of cmyk-values
+ ***/
+private gx_color_index
+stc_map_cmyk_color(gx_device *pdev,
+ gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits;
+ gx_color_index rv = 0;
+
+ if((c == m) && (m == y)) {
+
+ k = c > k ? c : k;
+ c = m = y = 0;
+
+ if(( sd->stc.bits == 8) &&
+ ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
+ k = stc_truncate1(sd,3,k);
+ } else {
+ k = stc_truncate(sd,3,k);
+ }
+
+ } else {
+
+ if(sd->stc.am != NULL) {
+
+ float *a,fc,fm,fy,fk,fv;
+
+ if(k == 0) { /* no separated black yet */
+ k = c < m ? c : m;
+ k = k < y ? k : y;
+ if(k) { /* no black at all */
+ c -= k;
+ m -= k;
+ y -= k;
+ } /* no black at all */
+ } /* no separated black yet */
+
+ a = sd->stc.am;
+ fc = c; fm = m; fy = y; fk = k;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) c = 0;
+ else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value;
+ else c = fv+0.5;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) m = 0;
+ else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value;
+ else m = fv+0.5;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) y = 0;
+ else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value;
+ else y = fv+0.5;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) k = 0;
+ else if((fv+0.5) > gx_max_color_value) k = gx_max_color_value;
+ else k = fv+0.5;
+
+ } else if(k == 0) {
+
+ k = c < m ? c : m;
+ k = k < y ? k : y;
+ }
+
+ if(( sd->stc.bits == 8) &&
+ ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
+ c = stc_truncate1(sd,0,c);
+ m = stc_truncate1(sd,1,m);
+ y = stc_truncate1(sd,2,y);
+ k = stc_truncate1(sd,3,k);
+ } else {
+ c = stc_truncate(sd,0,c);
+ m = stc_truncate(sd,1,m);
+ y = stc_truncate(sd,2,y);
+ k = stc_truncate(sd,3,k);
+ }
+ }
+
+ rv = c;
+ rv = (rv<<shift) | m;
+ rv = (rv<<shift) | y;
+ rv = (rv<<shift) | k;
+
+ if(rv == gx_no_color_index) rv ^= 1;
+
+ return rv;
+}
+
+private int
+stc_map_color_cmyk(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits;
+ gx_color_index l = ((gx_color_index)1<<sd->stc.bits)-1;
+ gx_color_value c,m,y,k;
+
+ k = stc_expand(sd,3, color & l); color >>= shift;
+ y = stc_expand(sd,2, color & l); color >>= shift;
+ m = stc_expand(sd,1, color & l); color >>= shift;
+ c = stc_expand(sd,0, color & l);
+
+ if((c == m) && (m == y)) {
+ prgb[0] = gx_max_color_value-k;
+ prgb[1] = prgb[0];
+ prgb[2] = prgb[0];
+ } else {
+ prgb[0] = gx_max_color_value-c;
+ prgb[1] = gx_max_color_value-m;
+ prgb[2] = gx_max_color_value-y;
+ }
+ return 0;
+}
+
+/***
+ *** color-mapping of cmyk10-values
+ ***/
+private gx_color_index
+stc_map_cmyk10_color(gx_device *pdev,
+ gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ int mode;
+ gx_color_index rv = 0;
+
+ if((c == m) && (m == y)) {
+
+ k = c > k ? c : k;
+ c = m = y = 0;
+ mode = 3;
+
+ } else {
+
+ if(sd->stc.am != NULL) {
+
+ float *a,fc,fm,fy,fk,fv;
+
+ k = c < m ? c : m;
+ k = k < y ? k : y;
+ if(k) { /* no black at all */
+ c -= k;
+ m -= k;
+ y -= k;
+ } /* no black at all */
+
+ a = sd->stc.am;
+ fc = c; fm = m; fy = y; fk = k;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) c = 0;
+ else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value;
+ else c = fv+0.5;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) m = 0;
+ else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value;
+ else m = fv+0.5;
+
+ fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
+ if( fv < 0.0) y = 0;
+ else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value;
+ else y = fv+0.5;
+
+ }
+
+ if(c < m) {
+ if(c < y) { k = c; c = 0; mode = 0; }
+ else { k = y; y = 0; mode = 2; }
+ } else {
+ if(m < y) { k = m; m = 0; mode = 1; }
+ else { k = y; y = 0; mode = 2; }
+ }
+ }
+
+/*
+ * truncate only the values that require it
+ */
+ if(c) c = stc_truncate(sd,0,c);
+ if(m) m = stc_truncate(sd,1,m);
+ if(y) y = stc_truncate(sd,2,y);
+ if(k) k = stc_truncate(sd,3,k);
+
+/*
+ * make sure that truncation-white becomes white.
+ */
+ if((c|m|y) == 0) mode = 3;
+
+/*
+ * check wether value-arrays can be bypassed
+ */
+ if(((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) &&
+ ( sd->stc.dither->minmax[0] == 0.0 )) {
+ c = sd->stc.vals[0][c];
+ m = sd->stc.vals[1][m];
+ y = sd->stc.vals[2][y];
+ k = sd->stc.vals[3][k];
+ } else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) &&
+ ( sd->stc.dither->minmax[0] == 0.0 ) &&
+ ( sd->stc.dither->minmax[1] <= 1023.0 )) {
+ c = ((long *)(sd->stc.vals[0]))[c];
+ m = ((long *)(sd->stc.vals[1]))[m];
+ y = ((long *)(sd->stc.vals[2]))[y];
+ k = ((long *)(sd->stc.vals[3]))[k];
+ } /* direct */
+/*
+ * compute the long-representation of gx_color_index
+ */
+ switch(mode) {
+ case 0:
+ rv = (((gx_color_index) m)<<22)|
+ (((gx_color_index) y)<<12)|
+ (((gx_color_index) k)<< 2)|mode;
+ break;
+ case 1:
+ rv = (((gx_color_index) c)<<22)|
+ (((gx_color_index) y)<<12)|
+ (((gx_color_index) k)<< 2)|mode;
+ break;
+ case 2:
+ rv = (((gx_color_index) c)<<22)|
+ (((gx_color_index) m)<<12)|
+ (((gx_color_index) k)<< 2)|mode;
+ break;
+ default:
+ rv = (((gx_color_index) k)<< 2)|mode;
+ break;
+ }
+
+/*
+ * We may need some swapping
+ */
+#if !arch_is_big_endian
+ {
+ union { stc_pixel cv; byte bv[4]; } ui,uo;
+ ui.cv = rv;
+ uo.bv[0] = ui.bv[3];
+ uo.bv[1] = ui.bv[2];
+ uo.bv[2] = ui.bv[1];
+ uo.bv[3] = ui.bv[0];
+ rv = uo.cv;
+ }
+#endif
+ return rv;
+}
+
+private int
+stc_map_color_cmyk10(gx_device *pdev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+
+ stcolor_device *sd = (stcolor_device *) pdev;
+ gx_color_value c,m,y;
+
+/*
+ * We may need some swapping
+ */
+#if !arch_is_big_endian
+ union { stc_pixel cv; byte bv[4]; } ui,uo;
+ ui.cv = color;
+ uo.bv[0] = ui.bv[3];
+ uo.bv[1] = ui.bv[2];
+ uo.bv[2] = ui.bv[1];
+ uo.bv[3] = ui.bv[0];
+ color = uo.cv;
+#endif
+
+ c = stc_expand(sd,3,(color>>2)&0x3ff);
+
+ switch(color & 3) {
+ case 0:
+ m = stc_expand(sd,1,(color>>22) & 0x3ff);
+ y = stc_expand(sd,2,(color>>12) & 0x3ff);
+ break;
+ case 1:
+ m = c;
+ c = stc_expand(sd,0,(color>>22) & 0x3ff);
+ y = stc_expand(sd,2,(color>>12) & 0x3ff);
+ break;
+ case 2:
+ y = c;
+ c = stc_expand(sd,0,(color>>22) & 0x3ff);
+ m = stc_expand(sd,1,(color>>12) & 0x3ff);
+ break;
+ default:
+ m = c;
+ y = c;
+ break;
+ }
+
+ prgb[0] = gx_max_color_value - c;
+ prgb[1] = gx_max_color_value - m;
+ prgb[2] = gx_max_color_value - y;
+
+ return 0;
+}
+
+/***
+ *** Macros for parameter-handling
+ ***/
+
+#define set_param_array(A, D, S)\
+ {A.data = D; A.size = S; A.persistent = false;}
+
+#define stc_write_null(N) \
+ set_param_array(pfa,defext,countof(defext)) \
+ code = param_write_null(plist,N); \
+ if (code < 0) return code;
+
+#define stc_write_xarray(I,Coding,Transfer) \
+ if(sd->stc.sizc[I] > 0) { \
+ set_param_array(pfa, sd->stc.extc[I],sd->stc.sizc[I]) \
+ code = param_write_float_array(plist,Coding,&pfa); \
+ } else { \
+ code = param_write_null(plist,Coding); \
+ } \
+ if ( code < 0 ) return code; \
+ \
+ if(sd->stc.sizv[I] > 0) \
+ set_param_array(pfa, sd->stc.extv[I],sd->stc.sizv[I]) \
+ else \
+ set_param_array(pfa,defext,countof(defext)) \
+ code = param_write_float_array(plist,Transfer,&pfa); \
+ if ( code < 0 ) return code;
+
+#define stc_read_null(N) \
+ code = param_read_null(plist,N); \
+ if(code == gs_error_typecheck) \
+ code = param_read_float_array(plist,N,&pfa); \
+ if(code < 0) param_signal_error(plist,N,code); \
+ error = error > code ? code : error;
+
+#define stc_read_xarray(I,Coding,Transfer) \
+ code = param_read_float_array(plist,Coding,&pfa); \
+ if((error == 0) && (code == 0)) { \
+ if(pfa.size > 1) { \
+ sd->stc.extc[I] = (float *) pfa.data; \
+ sd->stc.sizc[I] = pfa.size; \
+ } else { \
+ code = gs_error_rangecheck; \
+ } \
+ } else if(code < 0) { \
+ code = param_read_null(plist,Coding); \
+ if(code == 0) { \
+ sd->stc.extc[I] = NULL; \
+ sd->stc.sizc[I] = 0; \
+ } \
+ } \
+ if(code < 0) param_signal_error(plist,Coding,code); \
+ error = error > code ? code : error; \
+ code = param_read_float_array(plist,Transfer,&pfa); \
+ if((error == 0) && (code == 0)) { \
+ sd->stc.extv[I] = (float *) pfa.data; \
+ sd->stc.sizv[I] = pfa.size; \
+ } else if(code < 0) { \
+ code = param_read_null(plist,Transfer); \
+ if(code == 0) { \
+ sd->stc.extv[I] = defext; \
+ sd->stc.sizv[I] = countof(defext); \
+ } \
+ } \
+ if(code < 0) param_signal_error(plist,Transfer,code); \
+ error = error > code ? code : error;
+
+/***
+ *** Get parameters == Make them accessable via PostScript
+ ***/
+
+private int
+stc_get_params(gx_device *pdev, gs_param_list *plist)
+{
+ int code,nc;
+ gs_param_string ps;
+ gs_param_float_array pfa;
+ bool btmp;
+ stcolor_device *sd = (stcolor_device *) pdev;
+
+ code = gdev_prn_get_params(pdev, plist);
+ if ( code < 0 ) return code;
+
+/*
+ * Export some readonly-Parameters, used by stcinfo.ps
+ */
+ param_string_from_string(ps,"1.91");
+ code = param_write_string(plist,"Version",&ps);
+ if ( code < 0 ) return code;
+
+ code = param_write_int(plist,"BitsPerComponent",&sd->stc.bits);
+ if ( code < 0 ) return code;
+
+ if(sd->stc.algorithms.size > 0) {
+ code = param_write_string_array(plist,"Algorithms",&sd->stc.algorithms);
+ } else {
+ code = param_write_null(plist,"Algorithms");
+ }
+ if ( code < 0 ) return code;
+
+/*
+ * Export OutputCode
+ */
+ switch(sd->stc.flags & STCCOMP) {
+ case STCPLAIN: param_string_from_string(ps,"plain"); break;
+ case STCDELTA: param_string_from_string(ps,"deltarow"); break;
+ default: param_string_from_string(ps,"runlength"); break;
+ }
+ code = param_write_string(plist,"OutputCode",&ps);
+ if ( code < 0 ) return code;
+/*
+ * Export Model
+ */
+ switch(sd->stc.flags & STCMODEL) {
+ case STCST800: param_string_from_string(ps,"st800"); break;
+ case STCSTCII: param_string_from_string(ps,"stcii"); break;
+ default: param_string_from_string(ps,"stc"); break;
+ }
+ code = param_write_string(plist,"Model",&ps);
+ if ( code < 0 ) return code;
+
+/*
+ * Export the booleans
+ */
+#define stc_write_flag(Mask,Name) \
+ btmp = sd->stc.flags & (Mask) ? true : false; \
+ code = param_write_bool(plist,Name,&btmp); \
+ if ( code < 0 ) return code;
+
+ stc_write_flag(STCUNIDIR,"Unidirectional")
+ stc_write_flag(STCUWEAVE,"Microweave")
+ btmp = sd->stc.flags & (STCUNIDIR|STCUWEAVE) ? false : true;
+ code = param_write_bool(plist,"Softweave",&btmp);
+ if ( code < 0 ) return code;
+ stc_write_flag(STCNWEAVE,"noWeave")
+ stc_write_flag(STCDFLAG0, "Flag0")
+ stc_write_flag(STCDFLAG1, "Flag1")
+ stc_write_flag(STCDFLAG2, "Flag2")
+ stc_write_flag(STCDFLAG3, "Flag3")
+ stc_write_flag(STCDFLAG4, "Flag4")
+
+#undef stc_write_flag
+
+# define stc_write_int(Mask,Name,Val) \
+ code = param_write_int(plist,Name,&Val); \
+ if ( code < 0 ) return code
+
+ stc_write_int(STCBAND, "escp_Band", sd->stc.escp_m);
+ stc_write_int(STCWIDTH, "escp_Width", sd->stc.escp_width);
+ stc_write_int(STCHEIGHT,"escp_Height",sd->stc.escp_height);
+ stc_write_int(STCTOP, "escp_Top", sd->stc.escp_top);
+ stc_write_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom);
+
+# undef stc_write_int
+
+ code = param_write_string(plist,"escp_Init",&sd->stc.escp_init);
+ code = param_write_string(plist,"escp_Release",&sd->stc.escp_release);
+
+ if(sd->stc.dither != NULL) {
+ param_string_from_string(ps,sd->stc.dither->name);
+ code = param_write_string(plist,"Dithering",&ps);
+ } else {
+ code = param_write_null(plist,"Dithering");
+ }
+ if ( code < 0 ) return code;
+
+ nc = sd->color_info.num_components;
+
+ if(sd->stc.am != NULL) {
+ if( nc == 1) set_param_array(pfa, sd->stc.am, 3)
+ else if(nc == 3) set_param_array(pfa, sd->stc.am, 9)
+ else set_param_array(pfa, sd->stc.am,16)
+ code = param_write_float_array(plist,"ColorAdjustMatrix",&pfa);
+ } else {
+ code = param_write_null(plist,"ColorAdjustMatrix");
+ }
+ if ( code < 0 ) return code;
+
+ if(nc == 1) { /* DeviceGray */
+
+ stc_write_xarray(0,"Kcoding","Ktransfer");
+
+ stc_write_null("Rcoding"); stc_write_null("Rtransfer");
+ stc_write_null("Gcoding"); stc_write_null("Gtransfer");
+ stc_write_null("Bcoding"); stc_write_null("Btransfer");
+
+ stc_write_null("Ccoding"); stc_write_null("Ctransfer");
+ stc_write_null("Mcoding"); stc_write_null("Mtransfer");
+ stc_write_null("Ycoding"); stc_write_null("Ytransfer");
+
+ } else if(nc == 3) { /* DeviceRGB */
+
+ stc_write_xarray(0,"Rcoding","Rtransfer");
+ stc_write_xarray(1,"Gcoding","Gtransfer");
+ stc_write_xarray(2,"Bcoding","Btransfer");
+
+ stc_write_null("Ccoding"); stc_write_null("Ctransfer");
+ stc_write_null("Mcoding"); stc_write_null("Mtransfer");
+ stc_write_null("Ycoding"); stc_write_null("Ytransfer");
+ stc_write_null("Kcoding"); stc_write_null("Ktransfer");
+
+ } else { /* DeviceCMYK */
+
+ stc_write_xarray(0,"Ccoding","Ctransfer");
+ stc_write_xarray(1,"Mcoding","Mtransfer");
+ stc_write_xarray(2,"Ycoding","Ytransfer");
+ stc_write_xarray(3,"Kcoding","Ktransfer");
+
+ stc_write_null("Rcoding"); stc_write_null("Rtransfer");
+ stc_write_null("Gcoding"); stc_write_null("Gtransfer");
+ stc_write_null("Bcoding"); stc_write_null("Btransfer");
+
+ }
+ return code;
+}
+
+/***
+ *** put parameters == Store them in the device-structure
+ ***/
+
+private int
+stc_put_params(gx_device *pdev, gs_param_list *plist)
+{
+ int code,error,i,l;
+ bool b1,b2,b3;
+ float fv,*fp;
+ gs_param_string ps;
+ gs_param_string_array psa;
+ gs_param_float_array pfa;
+ stcolor_device *sd = (stcolor_device *) pdev;
+ gx_device_color_info oldcolor;
+ stc_t oldstc;
+
+/*
+ * save old Values
+ */
+ memcpy(&oldcolor,&sd->color_info,sizeof(oldcolor));
+ memcpy(&oldstc ,&sd->stc ,sizeof(oldstc ));
+
+/*
+ * Arrrgh:
+ * With Version 3.4x and above my simple minded read-only Parameters
+ * do not work any more. So read them here for heavens sake.
+ */
+ code = param_read_string(plist,"Version",&ps);
+ code = param_read_int(plist,"BitsPerComponent",&i);
+ code = param_read_string_array(plist,"Algorithms",&psa);
+
+/*
+ * Fetch Major-Parameters (Model, Dithering, BitsPerPixel/BitsPerComponent)
+ */
+ error = 0;
+
+ code = param_read_string(plist,"Model",&ps);
+ if(code == 0) { /* Analyze the Model-String */
+/*
+ * Arrgh: I should have known, that internal strings are not zero-terminated.
+ */
+ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
+# define stc_putcmp(Name) \
+ ((strlen(Name) != l) || (0 != strncmp(Name, (const char *)ps.data,l)))
+
+ sd->stc.flags &= ~STCMODEL;
+ if( !stc_putcmp("st800")) sd->stc.flags |= STCST800;
+ else if(!stc_putcmp("stcii")) sd->stc.flags |= STCSTCII;
+
+ } /* Analyze the Model-String */
+ if(code < 0) param_signal_error(plist,"Model",code);
+ error = error > code ? code : error;
+
+/* If we're running for st800, #components must be 1 */
+ if(((sd->stc.flags & STCMODEL) == STCST800) &&
+ (( sd->color_info.num_components > 1) ||
+ ( sd->stc.dither == NULL) ||
+ ((sd->stc.dither->flags & 7) > 1))) {
+ sd->color_info.num_components = 1;
+ sd->stc.dither = NULL;
+ }
+
+/* Weaving isn't a feature for the st800 */
+ if((sd->stc.flags & STCMODEL) == STCST800) {
+ sd->stc.flags &= ~STCUWEAVE;
+ sd->stc.flags |= STCNWEAVE;
+ } else if((sd->stc.flags & STCMODEL) == STCSTCII) { /* no SoftWeave */
+ sd->stc.flags |= STCNWEAVE;
+ }
+
+ code = param_read_string(plist,"Dithering",&ps);
+ if(code == 0) { /* lookup new value new value */
+
+ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
+
+ for(i = 0; stc_dither[i].name != NULL; ++i)
+ if(!stc_putcmp(stc_dither[i].name)) break;
+
+ } else if(sd->stc.dither != NULL) { /* compute index of given value */
+
+ i = sd->stc.dither - stc_dither;
+
+ } else { /* find matching value */
+
+ for(i = 0; stc_dither[i].name != NULL; ++i)
+ if((stc_dither[i].flags & 7) == sd->color_info.num_components) break;
+
+ } /* we've got an index */
+
+ if(stc_dither[i].name != NULL) { /* establish data */
+
+/*
+ * Establish new dithering algorithm & color-model
+ */
+ sd->stc.dither = stc_dither+i;
+ sd->color_info.num_components = sd->stc.dither->flags & 7;
+ STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem)
+# undef stc_sizeofitem
+ if(((sd->stc.flags & STCMODEL) == STCST800) &&
+ ( sd->color_info.num_components > 1 ))
+ code = gs_error_rangecheck;
+
+/*
+ * reset Parameters related to the color-model, if it changed
+ */
+
+ if(sd->color_info.num_components != oldcolor.num_components) {
+
+ for(i = 0; i < sd->color_info.num_components; ++i) {
+ sd->stc.extv[i] = (float *) defext;
+ sd->stc.sizv[i] = countof(defext);
+
+ sd->stc.extc[i] = NULL;
+ sd->stc.sizc[i] = 0;
+
+ }
+
+ sd->stc.am = NULL;
+
+ } else { /* guarantee, that extvals is present */
+
+ for(i = 0; i < sd->color_info.num_components; ++i) {
+ if(sd->stc.sizv[i] < 2) {
+ sd->stc.extv[i] = (float *) defext;
+ sd->stc.sizv[i] = countof(defext);
+ }
+ }
+ }
+
+ for(i = sd->color_info.num_components; i < 4; ++ i) { /* clear unused */
+ sd->stc.extv[i] = NULL;
+ sd->stc.sizv[i] = 0;
+ sd->stc.vals[i] = NULL;
+
+ sd->stc.extc[i] = NULL;
+ sd->stc.sizc[i] = 0;
+ sd->stc.code[i] = NULL;
+
+ } /* clear unused */
+
+/*
+ * Guess default depth from range of values
+ */
+ if((sd->stc.dither != oldstc.dither)||(oldstc.vals[0] == NULL)) {
+
+ if((sd->stc.dither->flags & STC_CMYK10) != 0) {
+
+ sd->stc.flags |= STCCMYK10;
+ sd->stc.bits = 10;
+ sd->color_info.depth = 32;
+
+ } else {
+
+ sd->stc.flags &= ~STCCMYK10;
+
+ if((sd->stc.dither->flags & STC_FLOAT) != STC_FLOAT) {
+ fv = 2.0;
+ for(i = 1;(i < gx_color_value_bits) &&
+ (fv <= (sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]));
+ ++i) fv *= 2.0;
+
+ } else {
+ i = 8; /* arbitrary */
+ }
+
+ if((i*sd->color_info.num_components) > (sizeof(stc_pixel)*8)) {
+
+ sd->stc.bits = (sizeof(stc_pixel)*8) /
+ sd->color_info.num_components;
+ sd->color_info.depth = sd->stc.bits * sd->color_info.num_components;
+
+ } else {
+
+ sd->stc.bits = i;
+ sd->color_info.depth = sd->stc.bits * sd->color_info.num_components;
+
+ }
+ }
+ }
+
+ } else {
+
+ code = gs_error_rangecheck;
+
+ } /* verify new value */
+ if(code < 0) param_signal_error(plist,"Dithering",code);
+ error = error > code ? code : error;
+
+/*
+ * now fetch the desired depth, if the algorithm allows it
+ */
+/*
+ * Arrrgh: We get code == 0, even if nobody sets BitsPerPixel.
+ * The value is the old one, but this may cause trouble
+ * with CMYK10.
+ */
+ code = param_read_int(plist, "BitsPerPixel", &i);
+ if((error == 0) && (code == 0) &&
+ (((sd->stc.flags & STCCMYK10) == 0) || (i != sd->color_info.depth))) {
+
+ if((1 > i) || (i > (sizeof(stc_pixel)*8)))
+ code = gs_error_rangecheck;
+ else
+ sd->color_info.depth = i;
+
+ sd->stc.bits = i / sd->color_info.num_components;
+
+ if(1 > sd->stc.bits) code = gs_error_rangecheck;
+
+ if((sd->stc.dither->flags & STC_DIRECT) &&
+ (sd->stc.dither->flags & STC_CMYK10))
+ code = gs_error_rangecheck;
+ else
+ sd->stc.flags &= ~STCCMYK10;
+
+ }
+ if(code < 0) param_signal_error(plist,"BitsPerPixel",code);
+ error = error > code ? code : error;
+
+/*
+ * Fetch OutputCode
+ */
+ code = param_read_string(plist,"OutputCode",&ps);
+ if(code == 0) { /* Analyze the OutputCode-String */
+
+ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
+
+ sd->stc.flags &= ~STCCOMP;
+ if(!stc_putcmp("plain")) sd->stc.flags |= STCPLAIN;
+ else if(!stc_putcmp("deltarow")) sd->stc.flags |= STCDELTA;
+
+ } /* Analyze the OutputCode-String */
+ if((sd->stc.flags & STCCOMP) == STCDELTA) {
+ sd->stc.flags |= STCUWEAVE;
+ sd->stc.flags &= ~STCNWEAVE;
+ }
+ if(code < 0) param_signal_error(plist,"OutputCode",code);
+ error = error > code ? code : error;
+
+/*
+ * fetch the weave-mode (noWeave wins)
+ */
+ b1 = sd->stc.flags & STCUWEAVE ? true : false;
+ b2 = sd->stc.flags & STCNWEAVE ? true : false;
+ b3 = sd->stc.flags & (STCUWEAVE|STCNWEAVE) ? false : true;
+
+ code = param_read_bool(plist,"Microweave",&b1);
+ if(code < 0) {
+ param_signal_error(plist,"Microweave",code);
+ } else if(code == 0) {
+ if(b1) { b2 = false; b3 = false; }
+ }
+ error = error > code ? code : error;
+
+ code = param_read_bool(plist,"noWeave",&b2);
+ if(code < 0) {
+ param_signal_error(plist,"noWeave",code);
+ } else if (code == 0) {
+ if(b2) { b1 = false; b3 = false; }
+ }
+ error = error > code ? code : error;
+
+ code = param_read_bool(plist,"Softweave",&b3);
+ if(code < 0) {
+ param_signal_error(plist,"Softweave",code);
+ } else if (code == 0) {
+ if(b3) { b1 = false; b2 = false; }
+ }
+ error = error > code ? code : error;
+
+ if(b1) sd->stc.flags |= STCUWEAVE;
+ else sd->stc.flags &= ~STCUWEAVE;
+
+ if(b2) sd->stc.flags |= STCNWEAVE;
+ else sd->stc.flags &= ~STCNWEAVE;
+
+/*
+ * Check the simple Flags
+ */
+# define stc_read_flag(Mask,Name) \
+ code = param_read_bool(plist,Name,&b1); \
+ if(code < 0) { \
+ param_signal_error(plist,Name,code); \
+ } else if(code == 0) { \
+ if(b1 == true) sd->stc.flags |= Mask; \
+ else sd->stc.flags &= ~(Mask); \
+ } \
+ error = error > code ? code : error;
+
+ stc_read_flag(STCUNIDIR,"Unidirectional")
+ stc_read_flag(STCDFLAG0, "Flag0")
+ stc_read_flag(STCDFLAG1, "Flag1")
+ stc_read_flag(STCDFLAG2, "Flag2")
+ stc_read_flag(STCDFLAG3, "Flag3")
+ stc_read_flag(STCDFLAG4, "Flag4")
+
+/*
+ * Now deal with the escp-Stuff
+ */
+# define stc_read_int(Mask,Name,Val) \
+ code = param_read_int(plist,Name,&Val); \
+ if(code < 0) \
+ param_signal_error(plist,Name,code); \
+ else if(code == 0) \
+ sd->stc.flags |= Mask; \
+ error = error > code ? code : error
+
+ stc_read_int(STCBAND, "escp_Band", sd->stc.escp_m);
+ stc_read_int(STCWIDTH, "escp_Width", sd->stc.escp_width);
+ stc_read_int(STCHEIGHT,"escp_Height",sd->stc.escp_height);
+ stc_read_int(STCTOP, "escp_Top", sd->stc.escp_top);
+ stc_read_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom);
+
+# undef stc_read_int
+
+ code = param_read_string(plist,"escp_Init",&sd->stc.escp_init);
+ if(code == 0) sd->stc.flags |= STCINIT;
+ error = error > code ? code : error;
+
+ code = param_read_string(plist,"escp_Release",&sd->stc.escp_release);
+ if(code == 0) sd->stc.flags |= STCRELEASE;
+ error = error > code ? code : error;
+
+/*
+ * ColorAdjustMatrix must match the required size,
+ * setting it explicitly to null, erases old matrix
+ */
+ code = param_read_float_array(plist,"ColorAdjustMatrix",&pfa);
+ if((error == 0) && (code == 0)) {
+ if(((sd->color_info.num_components == 1) && (pfa.size == 3)) ||
+ ((sd->color_info.num_components == 3) && (pfa.size == 9)) ||
+ ((sd->color_info.num_components == 4) && (pfa.size == 16)))
+ sd->stc.am = (float *) pfa.data;
+ else
+ code = gs_error_rangecheck;
+ } else if(code < 0) {
+ code = param_read_null(plist,"ColorAdjustMatrix");
+ if(code == 0) sd->stc.am = NULL;
+ }
+ if(code < 0) param_signal_error(plist,"ColorAdjustMatrix",code);
+ error = error > code ? code : error;
+
+/*
+ * Read the external array-Parameters
+ */
+ if(sd->color_info.num_components == 1) { /* DeviceGray */
+
+ stc_read_xarray(0,"Kcoding","Ktransfer");
+
+ stc_read_null("Rcoding"); stc_read_null("Rtransfer");
+ stc_read_null("Gcoding"); stc_read_null("Gtransfer");
+ stc_read_null("Bcoding"); stc_read_null("Btransfer");
+
+ stc_read_null("Ccoding"); stc_read_null("Ctransfer");
+ stc_read_null("Mcoding"); stc_read_null("Mtransfer");
+ stc_read_null("Ycoding"); stc_read_null("Ytransfer");
+
+ } else if(sd->color_info.num_components == 3) { /* DeviceRGB */
+
+ stc_read_xarray(0,"Rcoding","Rtransfer");
+ stc_read_xarray(1,"Gcoding","Gtransfer");
+ stc_read_xarray(2,"Bcoding","Btransfer");
+
+ stc_read_null("Ccoding"); stc_read_null("Ctransfer");
+ stc_read_null("Mcoding"); stc_read_null("Mtransfer");
+ stc_read_null("Ycoding"); stc_read_null("Ytransfer");
+ stc_read_null("Kcoding"); stc_read_null("Ktransfer");
+
+ } else { /* DeviceCMYK */
+
+ stc_read_xarray(0,"Ccoding","Ctransfer");
+ stc_read_xarray(1,"Mcoding","Mtransfer");
+ stc_read_xarray(2,"Ycoding","Ytransfer");
+ stc_read_xarray(3,"Kcoding","Ktransfer");
+
+ stc_read_null("Rcoding"); stc_read_null("Rtransfer");
+ stc_read_null("Gcoding"); stc_read_null("Gtransfer");
+ stc_read_null("Bcoding"); stc_read_null("Btransfer");
+
+ }
+/*
+ * Update remaining color_info values
+ */
+ if(error == 0) {
+
+/* compute #values from the component-bits */
+ sd->color_info.max_gray = sd->stc.bits < gx_color_value_bits ?
+ (1<<sd->stc.bits)-1 : gx_max_color_value;
+
+/* An integer-algorithm might reduce the number of values */
+ if(((sd->stc.dither->flags & STC_TYPE) != STC_FLOAT) &&
+ ((sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]) <
+ sd->color_info.max_gray))
+ sd->color_info.max_gray =
+ sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]+0.5;
+
+ sd->color_info.max_color = sd->color_info.num_components < 3 ? 0 :
+ sd->color_info.max_gray;
+ sd->color_info.dither_grays =
+ sd->color_info.max_gray < gx_max_color_value ?
+ sd->color_info.max_gray+1 : gx_max_color_value;
+ sd->color_info.dither_colors = sd->color_info.num_components < 3 ? 0 :
+ sd->color_info.dither_grays;
+ }
+
+/*
+ * Call superclass-Update
+ */
+
+ code = gdev_prn_put_params(pdev, plist);
+ error = error > code ? code : error;
+
+/*
+ * Arrrgh, writing BitsPerPixel is really *VERY* special:
+ * gdev_prn_put_params verifies, that the external value
+ * is written, if not, it raises a rangecheck-error.
+ * On the other hand ghostscript is quite unhappy with odd
+ * values, so we do the necessary rounding *AFTER* the
+ * "superclass-Update".
+ */
+
+ if(sd->color_info.depth == 3) sd->color_info.depth = 4;
+ else if(sd->color_info.depth > 4)
+ sd->color_info.depth = (sd->color_info.depth+7) & ~7;
+
+/*
+ * Allocate the storage for the arrays in memory
+ */
+ if(error == 0) { /* Allocate new external-arrays */
+
+ for(i = 0; i < sd->color_info.num_components; ++i){ /* Active components */
+ int j;
+
+ if((sd->stc.extv[i] != oldstc.extv[i]) &&
+ (sd->stc.extv[i] != defext )) { /* Value-Arrays */
+
+ for(j = 0; j < i; ++j)
+ if((sd->stc.sizv[j] == sd->stc.sizv[i]) &&
+ (memcmp(sd->stc.extv[j],sd->stc.extv[i],
+ sd->stc.sizv[i]*sizeof(float)) == 0)) break;
+
+ if(j < i) {
+ sd->stc.extv[i] = sd->stc.extv[j];
+ } else {
+ fp = gs_malloc(sd->stc.sizv[i],sizeof(float),"stc_put_params");
+ if(fp != NULL)
+ memcpy(fp,sd->stc.extv[i],sd->stc.sizv[i]*sizeof(float));
+ else
+ code = gs_error_VMerror;
+ sd->stc.extv[i] = fp;
+ }
+ } /* Value-Arrays */
+
+ if((sd->stc.sizc[i] > 1) &&
+ (sd->stc.extc[i] != oldstc.extc[i])) { /* Code-Arrays */
+
+ for(j = 0; j < i; ++j)
+ if((sd->stc.sizc[j] == sd->stc.sizc[i]) &&
+ (memcmp(sd->stc.extc[j],sd->stc.extc[i],
+ sd->stc.sizc[i]*sizeof(float)) == 0)) break;
+
+ if(j < i) {
+ sd->stc.extc[i] = sd->stc.extc[j];
+ } else {
+ fp = gs_malloc(sd->stc.sizc[i],sizeof(float),"stc_put_params");
+ if(fp != NULL)
+ memcpy(fp,sd->stc.extc[i],sd->stc.sizc[i]*sizeof(float));
+ else
+ code = gs_error_VMerror;
+ sd->stc.extc[i] = fp;
+ }
+ } /* Code-Arrays */
+
+ } /* Active components */
+
+ if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) {
+ if( sd->color_info.num_components == 1) i = 3;
+ else if(sd->color_info.num_components == 3) i = 9;
+ else i = 16;
+ fp = gs_malloc(i,sizeof(float),"stc_put_params");
+ if(fp != NULL) memcpy(fp,sd->stc.am,i*sizeof(float));
+ else code = gs_error_VMerror;
+ sd->stc.am = fp;
+ }
+
+ if(sd->stc.escp_init.data != oldstc.escp_init.data) {
+ byte *ip = NULL;
+
+ if(sd->stc.escp_init.size > 0) {
+ ip = gs_malloc(sd->stc.escp_init.size,1,"stcolor/init");
+ if(ip == NULL) {
+ code = gs_error_VMerror;
+ sd->stc.escp_init.size = 0;
+ } else {
+ memcpy(ip,sd->stc.escp_init.data,sd->stc.escp_init.size);
+ }
+ }
+ sd->stc.escp_init.data = ip;
+ sd->stc.escp_init.persistent = false;
+ }
+
+ if(sd->stc.escp_release.data != oldstc.escp_release.data) {
+ byte *ip = NULL;
+
+ if(sd->stc.escp_release.size > 0) {
+ ip = gs_malloc(sd->stc.escp_release.size,1,"stcolor/release");
+ if(ip == NULL) {
+ code = gs_error_VMerror;
+ sd->stc.escp_release.size = 0;
+ } else {
+ memcpy(ip,sd->stc.escp_release.data,sd->stc.escp_release.size);
+ }
+ }
+ sd->stc.escp_release.data = ip;
+ sd->stc.escp_release.persistent = false;
+ }
+
+ if(code < 0) { /* free newly allocated arrays */
+
+ if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) {
+ if( sd->color_info.num_components == 1) i = 3;
+ else if(sd->color_info.num_components == 3) i = 9;
+ else i = 16;
+ gs_free(sd->stc.am,i,sizeof(float),"stc_put_params");
+ }
+
+ if((sd->stc.escp_init.data != NULL) &&
+ (sd->stc.escp_init.data != oldstc.escp_init.data))
+ gs_free((byte *) sd->stc.escp_init.data,sd->stc.escp_init.size,1,
+ "stcolor/init");
+
+ if((sd->stc.escp_release.data != NULL) &&
+ (sd->stc.escp_release.data != oldstc.escp_release.data))
+ gs_free((byte *) sd->stc.escp_release.data,sd->stc.escp_release.
+ size,1,"stcolor/release");
+
+ for(i = 0; i < sd->color_info.num_components; ++i) { /* components */
+ int j;
+
+ if((sd->stc.extc[i] != NULL) &&
+ (sd->stc.extc[i] != defext) &&
+ (sd->stc.extc[i] != oldstc.extc[i])) {
+
+ for(j = 0; j < i; ++j)
+ if(sd->stc.extc[i] == sd->stc.extc[j]) break;
+
+ if(i == j) gs_free(sd->stc.extc[i],sd->stc.sizc[i],sizeof(float),
+ "stc_put_params");
+ }
+
+ if((sd->stc.extv[i] != NULL) &&
+ (sd->stc.extv[i] != oldstc.extv[i]) &&
+ (sd->stc.extv[i] != defext)) {
+
+ for(j = 0; j < i; ++j)
+ if(sd->stc.extv[i] == sd->stc.extv[j]) break;
+
+ if(i == j) gs_free(sd->stc.extv[i],sd->stc.sizv[i],sizeof(float),
+ "stc_put_params");
+ }
+ } /* components */
+ } /* free newly allocated arrays */
+ } /* Allocate new arrays */
+ error = error > code ? code : error;
+
+/*
+ * finally decide upon restore or release of old, unused data
+ */
+ if(error != 0) { /* Undo changes */
+
+ memcpy(&sd->color_info,&oldcolor,sizeof(oldcolor));
+ memcpy(&sd->stc ,&oldstc ,sizeof(oldstc ));
+ } else { /* undo / release */
+
+ if((oldstc.escp_init.data != NULL) &&
+ (oldstc.escp_init.data != sd->stc.escp_init.data)) {
+ gs_free((byte *)oldstc.escp_init.data,
+ oldstc.escp_init.size,1,"stcolor/init");
+ }
+
+ if((oldstc.escp_release.data != NULL) &&
+ (oldstc.escp_release.data != sd->stc.escp_release.data)) {
+ gs_free((byte *)oldstc.escp_release.data,
+ oldstc.escp_release.size,1,"stcolor/release");
+ }
+
+ if((oldstc.am != NULL) && (oldstc.am != sd->stc.am)) {
+ if( oldcolor.num_components == 1) i = 3;
+ else if(oldcolor.num_components == 3) i = 9;
+ else i = 16;
+ gs_free(oldstc.am,i,sizeof(float),"stc_put_params");
+ }
+
+ for(i = 0; i < 4; ++i) {
+ int j;
+
+ if((oldstc.extc[i] != NULL) &&
+ (oldstc.extc[i] != sd->stc.extc[i]) &&
+ (oldstc.dither != NULL) &&
+ (oldstc.extc[i] != defext)) {
+
+ for(j = 0; j < i; ++j) if(oldstc.extc[i] == oldstc.extc[j]) break;
+
+ if(i == j) gs_free(oldstc.extc[i],oldstc.sizc[i],sizeof(float),
+ "stc_put_params");
+ }
+
+ if((oldstc.extv[i] != NULL) &&
+ (oldstc.extv[i] != sd->stc.extv[i]) &&
+ (oldstc.extv[i] != defext)) {
+
+ for(j = 0; j < i; ++j) if(oldstc.extv[i] == oldstc.extv[j]) break;
+
+ if(i == j) gs_free(oldstc.extv[i],oldstc.sizv[i],sizeof(float),
+ "stc_put_params");
+ }
+ }
+
+/*
+ * Close the device if colormodel changed or recomputation
+ * of internal arrays is required
+ */
+ if(sd->is_open) { /* we might need to close it */
+ bool doclose = false;
+ if((sd->color_info.num_components != oldcolor.num_components) ||
+ (sd->color_info.depth != oldcolor.depth ) ||
+ (sd->stc.bits != oldstc.bits ) ||
+ (sd->stc.dither != oldstc.dither ))
+ doclose = true;
+
+ for(i = 0; i < sd->color_info.num_components; ++i) {
+ if(sd->stc.extv[i] != oldstc.extv[i]) doclose = true;
+ if(sd->stc.extc[i] != oldstc.extc[i]) doclose = true;
+ }
+ if(doclose) {
+ stc_freedata(&oldstc);
+ for(i = 0; i < 4; ++i) {
+ sd->stc.vals[i] = NULL;
+ sd->stc.code[i] = NULL;
+ }
+
+ gs_closedevice(pdev);
+ }
+ } /* we might need to close it */
+
+ }
+
+ return error;
+}
+/*
+ * 1Bit CMYK-Algorithm
+ */
+
+private int
+stc_gscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out)
+{
+
+ byte *ip = in;
+ int error = 0;
+
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+ int p;
+
+/*
+ * simply split the two pixels rsiding in a byte
+ */
+ for(p = npixel; p > 0; --p) { /* loop over pixels */
+ byte tmp =*ip++;
+
+ *out++ = (tmp>>4) & 15;
+ if(--p <= 0) break;
+
+ *out++ = tmp & 15;
+
+ } /* loop over pixels */
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+/* we didn't check for the white-calls above, so this may cause errors */
+ if(sdev->stc.dither->flags & STC_WHITE) error = -1;
+
+/* if we're not setup for bytes, this is an error too */
+ if((sdev->stc.dither->flags & STC_TYPE) != STC_BYTE) error = -2;
+
+/* This IS a direct-driver, so STC_DIRECT must be set! */
+ if((sdev->stc.dither->flags & STC_DIRECT) == 0) error = -3;
+
+/* and cmyk-mode is the only supported mode */
+ if(sdev->color_info.num_components != 4) error = -4;
+
+/* and we support only 4Bit-Depth here */
+ if(sdev->color_info.depth != 4) error = -5;
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return error;
+}
+
+/*
+ * The following is an algorithm under test
+ */
+private int
+stc_hscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out)
+{
+
+/* ============================================================= */
+ if(npixel < 0) { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+ int i,i2do;
+ long *lp = (long *) buf;
+
+/* CMYK-only algorithm */
+ if( sdev->color_info.num_components != 4) return -1;
+
+/*
+ * check wether stcdither & TYPE are correct
+ */
+ if(( sdev->stc.dither == NULL) ||
+ ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
+
+/*
+ * check wether the buffer-size is sufficiently large
+ */
+ if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
+ ( sdev->stc.dither->bufadd <
+ (1 + 2*sdev->color_info.num_components))) return -3;
+
+/*
+ * must have STC_CMYK10, STC_DIRECT, but not STC_WHITE
+ */
+ if((sdev->stc.dither->flags & STC_CMYK10) == 0) return -4;
+ if((sdev->stc.dither->flags & STC_DIRECT) == 0) return -5;
+ if((sdev->stc.dither->flags & STC_WHITE ) != 0) return -6;
+
+/*
+ * Must have values between 0-1023.0
+ */
+ if((sdev->stc.dither->minmax[0] != 0.0) ||
+ (sdev->stc.dither->minmax[1] != 1023.0)) return -7;
+/*
+ * initialize buffer
+ */
+
+ i2do = 1 + 8 - 4 * npixel;
+ lp[0] = 0;
+
+ if(sdev->stc.flags & STCDFLAG0) {
+ for(i = 1; i < i2do; ++i) lp[i] = 0;
+ } else {
+ for(i = 1; i < i2do; ++i) lp[i] = (rand() % 381) - 190;
+ }
+
+/* ============================================================= */
+ } else { /* npixel > 0 && in != NULL -> scanline-processing */
+/* ============================================================= */
+
+ long errc[4],*errv;
+ int step = buf[0] ? -1 : 1;
+ stc_pixel *ip = (stc_pixel *) in;
+
+ buf[0] = ~ buf[0];
+ errv = (long *) buf + 5;
+
+ if(step < 0) {
+ ip += npixel-1;
+ out += npixel-1;
+ errv += 4*(npixel-1);
+ }
+
+ errc[0] = 0; errc[1] = 0; errc[2] = 0; errc[3] = 0;
+
+ while(npixel-- > 0) {
+
+ register stc_pixel ci,mode;
+ register long k,v,n;
+ register int pixel; /* internal pixel-value */
+
+ ci = *ip; ip += step;
+
+ mode = ci & 3;
+ k = (ci>>2) & 0x3ff;
+ pixel = 0;
+
+ v = k+errv[3]+((7*errc[3])>>4);
+
+ if(mode == 3) { /* only Black allowed to fire */
+
+ if(v > 511) {
+ v -= 1023;
+ pixel = BLACK;
+ }
+ errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[3] = v;
+
+ errv[0] = errv[0] < -190 ? -190 : errv[0] < 190 ? errv[0] : 190;
+ errv[1] = errv[1] < -190 ? -190 : errv[1] < 190 ? errv[1] : 190;
+ errv[2] = errv[2] < -190 ? -190 : errv[2] < 190 ? errv[2] : 190;
+
+ errc[0] = 0; errc[1] = 0; errc[2] = 0;
+
+ } else if(v > 511) { /* black known to fire */
+
+ v -= 1023;
+ pixel = BLACK;
+
+ errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[3] = v;
+
+ n = (ci>>12) & 0x3ff;
+
+ if(mode == 2) { v = k; }
+ else { v = n; n = (ci>>22) & 0x3ff; }
+
+ v += errv[2]+((7*errc[2])>>4)-1023;
+ if(v < -511) v = -511;
+ errv[2-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[2] = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[2] = v;
+
+ if(mode == 1) { v = k; }
+ else { v = n; n = (ci>>22) & 0x3ff; }
+
+ v += errv[1]+((7*errc[1])>>4)-1023;
+ if(v < -511) v = -511;
+ errv[1-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[1] = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[1] = v;
+
+ if(mode == 0) v = k;
+ else v = n;
+
+ v += errv[0]+((7*errc[0])>>4)-1023;
+ if(v < -511) v = -511;
+ errv[0-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[0] = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[0] = v;
+
+ } else { /* Black does not fire initially */
+
+ long kv = v; /* Black computed after colors */
+
+ n = (ci>>12) & 0x3ff;
+
+ if(mode == 2) { v = k; }
+ else { v = n; n = (ci>>22) & 0x3ff; }
+
+ v += errv[2]+((7*errc[2])>>4);
+ if(v > 511) {
+ pixel |= YELLOW;
+ v -= 1023;
+ }
+ errv[2-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[2] = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[2] = v;
+
+ if(mode == 1) { v = k; }
+ else { v = n; n = (ci>>22) & 0x3ff; }
+
+ v += errv[1]+((7*errc[1])>>4);
+ if(v > 511) {
+ pixel |= MAGENTA;
+ v -= 1023;
+ }
+ errv[1-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[1] = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[1] = v;
+
+ if(mode == 0) v = k;
+ else v = n;
+
+ v += errv[0]+((7*errc[0])>>4);
+ if(v > 511) {
+ pixel |= CYAN;
+ v -= 1023;
+ }
+ errv[0-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[0] = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[0] = v;
+
+ v = kv;
+ if(pixel == (CYAN|MAGENTA|YELLOW)) {
+ pixel = BLACK;
+ v = v > 511 ? v-1023 : -511;
+ }
+ errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */
+ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
+ errc[3] = v;
+
+ }
+
+ errv += step<<2;
+ *out = pixel; out += step;
+
+ } /* loop over pixels */
+
+/* ============================================================= */
+ } /* initialisation, white or scanline-processing */
+/* ============================================================= */
+
+ return 0;
+}
diff --git a/gs/src/gdevstc.h b/gs/src/gdevstc.h
new file mode 100644
index 000000000..db5df9d4f
--- /dev/null
+++ b/gs/src/gdevstc.h
@@ -0,0 +1,252 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc.h */
+/* Epson Stylus-Color Printer-Driver */
+#ifndef gdevstc_INCLUDED
+# define gdevstc_INCLUDED
+
+/***
+ *** This holds most of the declarations used by gdevstc.c/stcolor.
+ *** It should be included by the dithering-routines and should be
+ *** modified to include the separately compilable routines.
+ ***/
+
+/*** Ghostscript-Headers ***/
+
+#include "gdevprn.h"
+#include "gsparam.h"
+#include "gsstate.h"
+
+/*** Private Type for 32Bit-Pixels ***/
+#if arch_log2_sizeof_int < 2 /* int is too small */
+ typedef unsigned long stc_pixel;
+#else /* int is sufficient */
+ typedef unsigned int stc_pixel;
+#endif /* use int or long ? */
+
+/*** Auxillary-Device Structure ***/
+
+typedef struct stc_s {
+ long flags; /* some mode-flags */
+ int bits; /* the number of bits per component */
+ const struct stc_dither_s *dither; /* dithering-mode */
+ float *am; /* 3/9/16-E. vector/matrix */
+
+ float *extc[4]; /* Given arrays for stccode */
+ uint sizc[4]; /* Size of extcode-arrays */
+ gx_color_value *code[4]; /* cv -> internal */
+
+ float *extv[4]; /* Given arrays for stcvals */
+ uint sizv[4]; /* Size of extvals-arrays */
+ byte *vals[4]; /* internal -> dithering */
+
+ stc_pixel white_run[3]; /* the white-pattern */
+ stc_pixel white_end[3]; /* the white-Trailer */
+ gs_param_string_array
+ algorithms; /* Names of the available algorithms */
+
+ gs_param_string escp_init; /* Initialization-Sequence */
+ gs_param_string escp_release; /* Initialization-Sequence */
+ int escp_width; /* Number of Pixels printed */
+ int escp_height;/* Height send to the Printer */
+ int escp_top; /* Top-Margin, send to the printer */
+ int escp_bottom;/* Bottom-Margin, send to the printer */
+
+ int alg_item; /* Size of the items used by the algorithm */
+
+ int prt_buf; /* Number of buffers */
+ int prt_size; /* Size of the Printer-buffer */
+ int escp_size; /* Size of the ESC/P2-buffer */
+ int seed_size; /* Size of the seed-buffers */
+
+ int escp_u; /* print-resolution (3600 / ydpi )*/
+ int escp_c; /* selected color */
+ int escp_v; /* spacing within band */
+ int escp_h; /* 3600 / xdpi */
+ int escp_m; /* number of heads */
+ int escp_lf; /* linefeed in units */
+
+ int prt_y; /* print-coordinate */
+ int stc_y; /* Next line 2b printed */
+ int buf_y; /* Next line 2b loaded into the buffer */
+ int prt_scans; /* number of lines printed */
+
+
+ int *prt_width; /* Width of buffered lines */
+ byte **prt_data; /* Buffered printer-lines */
+ byte *escp_data; /* Buffer for ESC/P2-Data */
+ byte *seed_row[4];/* Buffer for delta-row compression (prt_size) */
+
+} stc_t;
+
+/*** Main-Device Structure ***/
+
+typedef struct stcolor_device_s {
+ gx_device_common;
+ gx_prn_device_common;
+ stc_t stc;
+} stcolor_device;
+
+#define STCDFLAG0 0x000001L /* Algorithm-Bit 0 */
+#define STCDFLAG1 0x000002L /* Algorithm-Bit 1 */
+#define STCDFLAG2 0x000004L /* Algorithm-Bit 2 */
+#define STCDFLAG3 0x000008L /* Algorithm-Bit 3 */
+#define STCDFLAG4 0x000010L /* Algorithm-Bit 4 */
+#define STCCMYK10 0x000020L /* CMYK10-Coding active */
+
+#define STCUNIDIR 0x000040L /* Unidirectional, if set */
+#define STCUWEAVE 0x000080L /* Hardware Microweave */
+#define STCNWEAVE 0x000100L /* Software Microweave disabled */
+
+#define STCOK4GO 0x000200L /* stc_put_params was o.k. */
+
+#define STCCOMP 0x000C00L /* RLE, Plain (>= 1.18) */
+#define STCPLAIN 0x000400L /* No compression */
+#define STCDELTA 0x000800L /* Delta-Row */
+
+#define STCMODEL 0x00f000L /* STC, ST800 */
+#define STCST800 0x001000L /* Monochrome-Variant */
+#define STCSTCII 0x002000L /* Stylus Color II */
+
+#define STCBAND 0x010000L /* Initialization defined */
+#define STCHEIGHT 0x020000L /* Page-Length set */
+#define STCWIDTH 0x040000L /* Page-Length set */
+#define STCTOP 0x080000L /* Top-Margin set */
+#define STCBOTTOM 0x100000L /* Bottom-Margin set */
+#define STCINIT 0x200000L /* Initialization defined */
+#define STCRELEASE 0x400000L /* Release defined */
+
+#define STCPRINT 0x800000L /* Data printed */
+
+/*** Datatype for the array of dithering-Algorithms ***/
+
+#define stc_proc_dither(name) \
+ int name(P5(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out))
+
+typedef struct stc_dither_s {
+ const char *name; /* Mode-Name for Dithering */
+ stc_proc_dither((*fun));
+ uint flags;
+ uint bufadd;
+ double minmax[2];
+} stc_dither_t;
+
+/*
+ * Color-Values for the output
+ */
+#define BLACK 1 /* in monochrome-Mode as well as in CMYK-Mode */
+#define RED 4 /* in RGB-Mode */
+#define GREEN 2
+#define BLUE 1
+#define CYAN 8 /* in CMYK-Mode */
+#define MAGENTA 4
+#define YELLOW 2
+
+/*** A Macro to ease Type-depending things with the stc_p-union ***/
+
+#define STC_TYPESWITCH(Dither,Action) \
+ switch((Dither)->flags & STC_TYPE) { \
+ case STC_BYTE: Action(byte); break; \
+ case STC_LONG: Action(long); break; \
+ default: Action(float); break;}
+
+/***
+ *** MODIFY HERE to include your routine:
+ ***
+ *** 1. Declare it here
+ *** 2. Add it to the definition of STC_MODI
+ *** 3. Add your file to the dependency-list in the Makefile & devices.mak
+ ***/
+
+/* Step 1. */
+stc_proc_dither(stc_gsmono); /* resides in gdevstc1.c */
+stc_proc_dither(stc_fs); /* resides in gdevstc2.c */
+stc_proc_dither(stc_fscmyk); /* resides in gdevstc2.c too */
+stc_proc_dither(stc_gsrgb); /* resides in gdevstc3.c */
+stc_proc_dither(stc_fs2); /* resides in gdevstc4.c */
+
+
+/* Values used to assemble flags */
+#define DeviceGray 1 /* ProcessColorModel = DeviceGray */
+#define DeviceRGB 3 /* ProcessColorModel = DeviceRGB */
+#define DeviceCMYK 4 /* ProcessColorModel = DeviceCMYK */
+
+#define STC_BYTE 8 /* Pass Bytes to the Dithering-Routine */
+#define STC_LONG 16 /* Pass Longs to the Dithering-Routine */
+#define STC_FLOAT 24 /* Pass Floats to the Dithering-Routine */
+#define STC_TYPE 24 /* all the type-bits */
+
+#define STC_CMYK10 32 /* Special 32-Bit CMYK-Coding */
+#define STC_DIRECT 64 /* Suppress conversion of Scanlines */
+#define STC_WHITE 128 /* Call Algorithm for white lines too (out == NULL) */
+#define STC_SCAN 256 /* multiply by number of scanlines in buffer */
+
+/* Step 2. */
+/* Items: 1. Name to activate it
+ 2. Name of the dithering-function
+ 3. Several flags ored together, including # of buffered scanlines
+ 4. Additional buffer-space (bytes/longs/floats)
+ 5. Array of double with minimum and maximum-value
+ Keep the last line as it is.
+ */
+
+#define STC_MODI \
+{"gsmono", stc_gsmono, DeviceGray|STC_BYTE,0,{0.0,1.0}},\
+{"gsrgb" , stc_gsrgb , DeviceRGB |STC_BYTE,0,{0.0,1.0}},\
+{"fsmono", stc_fs, \
+ DeviceGray|STC_LONG|1*STC_SCAN,3+3*1,{0.0,16777215.0}},\
+{"fsrgb", stc_fs, \
+ DeviceRGB |STC_LONG|1*STC_SCAN,3+3*3,{0.0,16777215.0}},\
+{"fsx4", stc_fs, \
+ DeviceCMYK|STC_LONG|1*STC_SCAN,3+3*4,{0.0,16777215.0}},\
+{"fscmyk", stc_fscmyk, \
+ DeviceCMYK|STC_LONG|1*STC_SCAN,3+3*4,{0.0,16777215.0}},\
+{"fs2", stc_fs2, \
+ DeviceRGB |STC_BYTE|STC_WHITE|1*STC_SCAN,0,{0.0,255.0}},
+
+
+#ifndef X_DPI
+#define X_DPI 360
+#endif /* X_DPI */
+#ifndef Y_DPI
+#define Y_DPI 360
+#endif /* Y_DPI */
+
+#ifndef STC_L_MARGIN
+# define STC_L_MARGIN 0.125 /* yields 45 Pixel@360DpI */
+#endif /* STC_L_MARGIN */
+#ifndef STC_B_MARGIN
+# define STC_B_MARGIN 0.555 /* yields 198 Pixel@#60DpI (looses 1mm) */
+#endif /* STC_B_MARGIN */
+/*
+ * Right-Margin: Should match maximum print-width of 8".
+ */
+
+#ifndef STC_R_MARGIN
+# ifdef A4
+# define STC_R_MARGIN 0.175 /* Yields 63 Pixel@360DpI */
+# else
+# define STC_R_MARGIN 0.375 /* 135 Pixel */
+# endif
+#endif /* STC_R_MARGIN */
+#ifndef STC_T_MARGIN
+# define STC_T_MARGIN 0.125
+#endif /* STC_T_MARGIN */
+
+#endif
diff --git a/gs/src/gdevstc1.c b/gs/src/gdevstc1.c
new file mode 100644
index 000000000..856336eef
--- /dev/null
+++ b/gs/src/gdevstc1.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc1.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ This file holds the sample-implementation of a monochrome-algorithm for
+ the stcolor-driver. It is available via
+
+ gs -sDEVICE=stcolor -sDithering=gsmono ...
+
+ Actually this is no dithering-algorithm, it lets ghostscript do the job.
+ This achieved, by requesting BYTE-Values between 0 and 1 to be delivered,
+ which causes a depth of 1-Bit by default.
+
+ ***/
+
+/*
+ * gdevstc.h holds all the includes and the driver-specific definitions, so
+ * it is the only include you need. To add a new algorthim, STC_MODI in
+ * gdevstc.h should be extended. (see the instructions there)
+ */
+
+#include "gdevstc.h"
+
+/*
+ * the routine required.
+ */
+
+/*ARGSUSED*/
+int
+stc_gsmono(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out)
+{
+
+/*
+ * There are basically 3 Types of calls:
+ * npixel < 0 => initialize buf, if this is required
+ * (happens only if requested)
+ * npixel > 0 => process next scanline, if the flag STC_WHITE is set, then
+ * in == NULL signals, that the basic-driver has decided
+ * that this scanline is white. (Useful for really dithering
+ * drivers)
+ */
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+/* -----------------------------------------------*/
+ if(in != NULL) { /* normal processing */
+/* -----------------------------------------------*/
+
+ memcpy(out,in,npixel); /* really simple algorithm */
+
+/* -----------------------------------------------*/
+ } else { /* skip-notification */
+/* -----------------------------------------------*/
+
+ /* An algorithm may use the output-line as a buffer.
+ So it might need to be cleared on white-lines.
+ */
+
+ memset(out,0,npixel);
+
+/* -----------------------------------------------*/
+ } /* normal / skip */
+/* -----------------------------------------------*/
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+/*
+ * the optional buffer is already allocated by the basic-driver, here
+ * you just need to fill it, for instance, set it all to zeros:
+ */
+ int buf_size;
+
+/*
+ * compute the size of the buffer, according to the requested values
+ * the buffer consists of a constant part, e.g. related to the number
+ * of color-components, and a number of arrays, which are multiples of
+ * the size of a scanline times the number of components.
+ * additionally, the size of the scanlines may be expanded by one to the
+ * right and to the left.
+ */
+ buf_size =
+ sdev->stc.dither->bufadd /* scanline-independend size */
+ + (-npixel) /* pixels */
+ * (sdev->stc.dither->flags/STC_SCAN) /* * scanlines */
+ * sdev->color_info.num_components; /* * comp */
+
+ if(buf_size > 0) { /* we obviously have a buffer */
+ memset(buf,0,buf_size * sdev->stc.alg_item);
+ } /* we obviously have a buffer */
+
+/*
+ * Usually one should check parameters upon initializaon
+ */
+ if(sdev->color_info.num_components != 1) return -1;
+
+ if((sdev->stc.dither->flags & STC_TYPE) != STC_BYTE) return -2;
+
+/*
+ * must neither have STC_DIRECT nor STC_WHITE
+ */
+ if((sdev->stc.dither->flags & STC_DIRECT) != 0) return -3;
+
+ } /* scanline-processing or initialisation */
+
+ return 0; /* negative values are error-codes, that abort printing */
+}
diff --git a/gs/src/gdevstc2.c b/gs/src/gdevstc2.c
new file mode 100644
index 000000000..661f7e16a
--- /dev/null
+++ b/gs/src/gdevstc2.c
@@ -0,0 +1,427 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc2.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ This file holds two implementations of the Floyd-Steinberg error
+ diffusion-algorithm. This algorithms are intended for high quality
+ printing in conjunction with the PostScript-Header stcolor.ps:
+
+ gs -sDEVICE=stcolor <other options> stcolor.ps ...
+
+ Most prominent option is -sDithering=xxx, to select the algorithm:
+
+ fsmono - monochrome Floyd-Steinberg
+ fsrgb - 3-Component Floyd-Steinberg
+ fsx4 - 4-Component Floyd-Steinberg (Bad results)
+
+ fscmyk - Modified 4-Component Floyd-Steinberg
+ (Algorithmically identical with hscmyk, but slower)
+
+ ***/
+
+#include "gdevstc.h"
+
+#include <stdlib.h> /* for rand */
+
+/*
+ Both algorithms require an error-buffer of
+
+ 3 + 3*num_components +1*scan long-items.
+
+ and must consequently set up to work with longs.
+ It is just a Floyd-Steinberg-algorithm applied to each component.
+
+ */
+
+/*
+ * Due to the -selfdefined- ugly coding of the output-data, we need
+ * some conversion. But since this includes the black-separation, I
+ * did not change the definition.
+ *
+ * This algorithm stores the 1st component in the LSB, thus it
+ * reverts the order used by the basic driver.
+ */
+
+static const byte grayvals[2] = { 0, BLACK };
+
+static const byte rgbvals[8] = {
+ 0, RED, GREEN, RED|GREEN, BLUE, BLUE|RED, BLUE|GREEN, BLUE|RED|GREEN};
+
+static const byte cmykvals[16] = {
+ 0, CYAN,MAGENTA,CYAN|MAGENTA,YELLOW,YELLOW|CYAN,YELLOW|MAGENTA,BLACK,
+ BLACK,BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,BLACK};
+
+static const byte *const pixelconversion[5] = {
+ NULL, grayvals, NULL, rgbvals, cmykvals};
+
+
+int
+stc_fs(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
+{
+
+ long *in = (long *) bin;
+ long *buf = (long *) bbuf;
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+ int bstep,pstart,pstop,pstep,p;
+ long spotsize,threshold,*errc,*errv;
+ const byte *pixel2stc;
+
+ if(buf[0] >= 0) { /* run forward */
+ buf[0] = -1;
+ bstep = 1;
+ pstep = sdev->color_info.num_components;
+ pstart = 0;
+ pstop = npixel * pstep;
+
+ } else { /* run backward */
+ buf[0] = 1;
+ bstep = -1;
+ pstep = -sdev->color_info.num_components;
+ pstop = pstep;
+ pstart = (1-npixel) * pstep;
+ out += npixel-1;
+ } /* forward / backward */
+
+/* --------------------------------------------------------------------- */
+ if(in == NULL) return 0; /* almost ignore the 'white calls' */
+/* --------------------------------------------------------------------- */
+
+ spotsize = buf[1];
+ threshold = buf[2];
+ errc = buf+3;
+ errv = errc + 2*sdev->color_info.num_components;
+ pixel2stc = pixelconversion[sdev->color_info.num_components];
+
+ for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
+ int c; /* component-number */
+ int pixel; /* internal pxel-value */
+
+ pixel = 0;
+
+ for(c = 0; c < sdev->color_info.num_components; c++) { /* comp */
+ long cv; /* component value */
+
+ cv = in[p+c] + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
+ if(cv > threshold) {
+ pixel |= 1<<c;
+ cv -= spotsize;
+ }
+ errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
+ errv[p+c ] = ((5*cv )>>4) /* 5/16 */
+ + ((errc[c]+4)>>3); /* 1/16 (rest) */
+ errc[c] = cv /* 8/16 (neu) */
+ - ((5*cv )>>4)
+ - ((3*cv+8)>>4);
+ } /* comp */
+
+ *out = pixel2stc[pixel];
+ out += bstep;
+ } /* loop over pixels */
+
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+ int i,i2do;
+ long rand_max;
+ double offset,scale;
+
+/*
+ * check wether the number of components is valid
+ */
+ if((sdev->color_info.num_components < 0) ||
+ (sdev->color_info.num_components >= countof(pixelconversion)) ||
+ (pixelconversion[sdev->color_info.num_components] == NULL)) return -1;
+
+/*
+ * check wether stcdither & TYPE are correct
+ */
+ if(( sdev->stc.dither == NULL) ||
+ ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
+
+/*
+ * check wether the buffer-size is sufficiently large
+ */
+ if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
+ ( sdev->stc.dither->bufadd <
+ (3 + 3*sdev->color_info.num_components))) return -3;
+/*
+ * must neither have STC_DIRECT nor STC_WHITE
+ */
+ if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
+
+/*
+ * compute initial values
+ */
+/* -- direction */
+ buf[0] = 1;
+
+/* -- "spotsize" */
+ scale = sdev->stc.dither->minmax[1];
+ buf[1] = scale + (scale > 0.0 ? 0.5 : -0.5);
+
+/* -- "threshold" */
+ offset = sdev->stc.dither->minmax[0];
+ scale -= offset;
+ if((offset+0.5*scale) > 0.0) buf[2] = offset + 0.5*scale + 0.5;
+ else buf[2] = offset + 0.5*scale - 0.5;
+
+/*
+ * random values, that do not exceed half of normal value
+ */
+ i2do = sdev->color_info.num_components * (3-npixel);
+ rand_max = 0;
+
+ if(sdev->stc.flags & STCDFLAG0) {
+
+ for(i = 0; i < i2do; ++i) buf[i+3] = 0;
+
+ } else {
+
+ for(i = 0; i < i2do; ++i) {
+ buf[i+3] = rand();
+ if(buf[i+3] > rand_max) rand_max = buf[i+3];
+ }
+
+ scale = (double) buf[1] / (double) rand_max;
+
+ for(i = 0; i < sdev->color_info.num_components; ++ i)
+ buf[i+3] = 0.25000*scale*(buf[i+3]-rand_max/2);
+
+ for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
+ buf[i+3] = 0.28125*scale*(buf[i+3]-rand_max/2);
+
+ }
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return 0;
+}
+
+/*
+ * Experimental CMYK-Algorithm
+ */
+
+int
+stc_fscmyk(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
+{
+ long *in = (long *) bin;
+ long *buf = (long *) bbuf;
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+ int bstep,pstart,pstop,pstep,p;
+ long spotsize,threshold,*errc,*errv;
+
+ if(buf[0] >= 0) { /* run forward */
+ buf[0] = -1;
+ bstep = 1;
+ pstep = 4;
+ pstart = 0;
+ pstop = npixel * pstep;
+
+ } else { /* run backward */
+ buf[0] = 1;
+ bstep = -1;
+ pstep = -4;
+ pstop = pstep;
+ pstart = (1-npixel) * pstep;
+ out += npixel-1;
+ } /* forward / backward */
+
+ spotsize = buf[1];
+ threshold = buf[2];
+ errc = buf+3;
+ errv = errc + 2*4;
+
+ for(p = 0; p < 4; ++p) errc[p] = 0;
+
+ for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
+ int c; /* component-number */
+ int pixel; /* internal pxel-value */
+ long cv,k;
+
+/*
+ * Black is treated first, with conventional Floyd-Steinberg
+ */
+ k = in[p+3];
+ cv = k + errv[p+3] + errc[3] - ((errc[3]+4)>>3);
+
+ if(cv > threshold) {
+ pixel = BLACK;
+ cv -= spotsize;
+ } else {
+ pixel = 0;
+ }
+
+ errv[p+3-pstep] += ((3*cv+8)>>4); /* 3/16 */
+ errv[p+3 ] = ((5*cv )>>4) /* 5/16 */
+ + ((errc[3]+4)>>3); /* 1/16 (rest) */
+ errc[3] = cv /* 8/16 (neu) */
+ - ((5*cv )>>4)
+ - ((3*cv+8)>>4);
+
+/*
+ * color-handling changes with black fired or not
+ */
+ if(pixel) {
+
+/* -------- firing of black causes all colors to fire too */
+
+ for(c = 0; c < 3; ++c) {
+ cv = in[p+c] > k ? in[p+c] : k;
+ cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3)-spotsize;
+ if(cv <= (threshold-spotsize)) cv = threshold-spotsize+1;
+
+ errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
+ errv[p+c ] = ((5*cv )>>4) /* 5/16 */
+ + ((errc[c]+4)>>3); /* 1/16 (rest) */
+ errc[c] = cv /* 8/16 (neu) */
+ - ((5*cv )>>4)
+ - ((3*cv+8)>>4);
+ }
+
+ } else {
+
+/* -------- if black did not fire, only colors w. larger values may fire */
+
+ for(c = 0; c < 3; ++c) {
+
+ cv = in[p+c];
+
+ if(cv > k) { /* May Fire */
+ cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3);
+ if(cv > threshold) {
+ cv -= spotsize;
+ pixel |= CYAN>>c;
+ }
+ } else { /* Must not fire */
+ cv = k + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
+ if(cv > threshold ) cv = threshold;
+ }
+
+ errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
+ errv[p+c ] = ((5*cv )>>4) /* 5/16 */
+ + ((errc[c]+4)>>3); /* 1/16 (rest) */
+ errc[c] = cv /* 8/16 (neu) */
+ - ((5*cv )>>4)
+ - ((3*cv+8)>>4);
+ }
+ }
+
+ *out = pixel;
+ out += bstep;
+ } /* loop over pixels */
+
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+ int i,i2do;
+ long rand_max;
+ double offset,scale;
+
+/*
+ * check wether the number of components is valid
+ */
+ if(sdev->color_info.num_components != 4) return -1;
+
+/*
+ * check wether stcdither & TYPE are correct
+ */
+ if(( sdev->stc.dither == NULL) ||
+ ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
+
+/*
+ * check wether the buffer-size is sufficiently large
+ */
+ if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
+ ( sdev->stc.dither->bufadd <
+ (3 + 3*sdev->color_info.num_components))) return -3;
+/*
+ * must neither have STC_DIRECT nor STC_WHITE
+ */
+ if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
+
+/*
+ * compute initial values
+ */
+/* -- direction */
+ buf[0] = 1;
+
+/* -- "spotsize" */
+ scale = sdev->stc.dither->minmax[1];
+ buf[1] = scale + (scale > 0.0 ? 0.5 : -0.5);
+
+/* -- "threshold" */
+ offset = sdev->stc.dither->minmax[0];
+ scale -= offset;
+ if(sdev->stc.flags & STCDFLAG1) {
+ buf[2] = (sdev->stc.extv[0][sdev->stc.sizv[0]-1] - sdev->stc.extv[0][0])
+ * scale / 2.0 + offset;
+ } else {
+ if((offset+0.5*scale) > 0.0) buf[2] = offset + 0.5*scale + 0.5;
+ else buf[2] = offset + 0.5*scale - 0.5;
+ }
+
+/*
+ * random values, that do not exceed half of normal value
+ */
+ i2do = sdev->color_info.num_components * (3-npixel);
+ rand_max = 0;
+
+ if(sdev->stc.flags & STCDFLAG0) {
+
+ for(i = 0; i < i2do; ++i) buf[i+3] = 0;
+
+ } else {
+
+ for(i = 0; i < i2do; ++i) {
+ buf[i+3] = rand();
+ if(buf[i+3] > rand_max) rand_max = buf[i+3];
+ }
+
+ scale = (double) buf[1] / (double) rand_max;
+
+ for(i = 0; i < sdev->color_info.num_components; ++ i)
+ buf[i+3] = 0.25000*scale*(buf[i+3]-rand_max/2);
+
+ for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
+ buf[i+3] = 0.28125*scale*(buf[i+3]-rand_max/2);
+
+ }
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return 0;
+}
diff --git a/gs/src/gdevstc3.c b/gs/src/gdevstc3.c
new file mode 100644
index 000000000..6fd5b0504
--- /dev/null
+++ b/gs/src/gdevstc3.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc3.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ This file holds the sample-implementation of a RGB-algorithm for
+ the stcolor-driver. It is available via
+
+ gs -sDEVICE=stcolor -sDithering=gsrgb ...
+
+ Actually this is no dithering-algorithm, it lets ghostscript do the job.
+ This achieved, by requesting BYTE-Values between 0 and 1 to be delivered,
+ which causes a depth of 1-Bit by default.
+
+ ***/
+
+/*
+ * gdevstc.h holds all the includes and the driver-specific definitions, so
+ * it is the only include you need. To add a new algorthim, STC_MODI in
+ * gdevstc.h should be extended. (see the instructions there)
+ */
+
+#include "gdevstc.h"
+
+/*
+ * the routine required.
+ */
+
+/*ARGSUSED*/
+int
+stc_gsrgb(stcolor_device *sdev,int npixel,byte *ip,byte *buf,byte *out)
+{
+
+ int error = 0;
+
+/*
+ * There are basically 3 Types of calls:
+ * npixel < 0 => initialize buf, if this is required
+ * (happens only if requested)
+ * npixel > 0 => process next scanline, if the flag STC_WHITE is set, then
+ * in == NULL signals, that the basic-driver has decided
+ * that this scanline is white. (Useful for really dithering
+ * drivers)
+ */
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+ int p;
+
+/*
+ * simply merge the color-values into a single byte
+ * (RED, GREEN, BLUE are defined in gdevstc.h)
+ */
+ for(p = 0; p < npixel; ++p,++out) { /* loop over pixels */
+
+ *out = 0;
+ if(*ip++) *out |= RED;
+ if(*ip++) *out |= GREEN;
+ if(*ip++) *out |= BLUE;
+
+ } /* loop over pixels */
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+/*
+ * besides buffer-Initialisation, one may check the parameters in
+ * the algorithm-table of the driver.
+ */
+
+/* we didn't check for the white-calls above, so they would cause errors */
+ if(sdev->stc.dither->flags & STC_WHITE) error = -1;
+
+/* if we're not setup for bytes, this is an error too */
+ if((sdev->stc.dither->flags & STC_TYPE) != STC_BYTE) error = -2;
+
+/* and rgb-mode is the only supported mode */
+ if(sdev->color_info.num_components != 3) error = -3;
+
+/* we can't deal with ghostscript-data directly. */
+ if(sdev->stc.dither->flags & STC_DIRECT) error = -4;
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return error;
+}
diff --git a/gs/src/gdevstc4.c b/gs/src/gdevstc4.c
new file mode 100644
index 000000000..61a9313f2
--- /dev/null
+++ b/gs/src/gdevstc4.c
@@ -0,0 +1,301 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc4.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ This file holds a byte-Implementation of the Floyd-Steinberg error
+ diffusion-algorithm. This algorithm is an alternative for high quality
+ printing in conjunction with the PostScript-Header stcolor.ps:
+
+ gs -sDEVICE=stcolor -sDithering=fs2 <other options> stcolor.ps ...
+
+ THIS ALGORIHM WAS WRITTEN BY STEVEN SINGER (S.Singer@ph.surrey.ac.uk)
+ AS PART OF escp2cfs2.
+ THIS IMPLEMENTATION INCORPORATES ONLY FEW CHANGES TO THE ORIGINAL CODE.
+
+ ***/
+
+#include "gdevstc.h"
+
+/*
+ * escp2c_pick best scans for best matching color
+ */
+private byte *
+escp2c_pick_best(byte *col)
+{
+ static byte colour[8][3] = {
+ { 0, 0, 0},{255, 0, 0},{ 0,255, 0},{255,255, 0},
+ { 0, 0,255},{255, 0,255},{ 0,255,255},{255,255,255}};
+ register int x, y, z, dx, dy, dz, dz2, dx2, dx3, dx4;
+ register byte *p;
+ register long md, d;
+
+ md = 16777216; /* plenty */
+
+/*
+ Note that I don't use a simple distance algorithm. That can lead to a block
+ of (130,127,127) being dithered as red-cyan. This algorithm should make
+ it use black-white-red. This is very important, as a coloured block in
+ the middle of a grey block can, via error diffusion, perturb the
+ surrounding colours sufficiently for this to happen.
+*/
+
+/*
+ The next bit is equivalent to this, but faster.
+
+ x = col[0];
+ y = col[1];
+ z = col[2];
+ for(n=8; n--; )
+ {
+ dx = x - colour[n][0];
+ dy = y - colour[n][1];
+ dz = z - colour[n][2];
+ d = dx*(dx-(dy>>1)) + dy*(dy-(dz>>1)) + dz*(dz-(dx>>1));
+ if (d < md)
+ {
+ md = d;
+ p = n;
+ }
+ }
+*/
+
+/*
+ * Test colours in gray code order to reduce number of recalculations.
+ * I bet you can't find an optimiser that would do this automatically.
+ */
+
+ x = col[0];
+ y = col[1];
+ z = col[2];
+ dx = x*(x-(y>>1));
+ dy = y*(y-(z>>1));
+ dz = z*(z-(x>>1));
+ md = dx + dy + dz;
+ p = colour[0];
+ x -= 255;
+ dx2 = x*(x-(y>>1));
+ dz2 = z*(z-(x>>1));
+ if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[1];}
+ y -= 255;
+ dx3 = x*(x-(y>>1));
+ dy = y*(y-(z>>1));
+ if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[3];}
+ x += 255;
+ dx4 = x*(x-(y>>1));
+ if ((d = dx4 + dy + dz) < md) {md = d; p = colour[2];}
+ z -= 255;
+ dy = y*(y-(z>>1));
+ dz = z*(z-(x>>1));
+ if ((d = dx4 + dy + dz) < md) {md = d; p = colour[6];}
+ x -= 255;
+ dz2 = z*(z-(x>>1));
+ if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[7];}
+ y += 255;
+ dy = y*(y-(z>>1));
+ if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[5];}
+ if ((d = dx + dy + dz) < md) {p = colour[4];}
+ return(p);
+}
+
+/*
+ * escp2c_conv_stc converts into the ouput format used by stcolor
+ */
+private void
+escp2c_conv_stc(byte *p, byte *q, int i)
+{
+ for(; i; p+=3, i-=3)
+ *q++ = (*p & RED) | (p[1] & GREEN) | (p[2] & BLUE);
+}
+
+
+/*
+ * Limit byte-values
+ */
+#define LIMIT(a) if (a > 255) a = 255; if (a < 0) a = 0
+#define LIMIT2(a) if (a > 127) a = 127; if (a < -128) a = -128; \
+ if (a < 0) a += 256
+/*
+ * Main routine of the algorithm
+ */
+int
+stc_fs2(stcolor_device *sd,int npixel,byte *in,byte *buf,byte *out)
+{
+ int fullcolor_line_size = npixel*3;
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+/* -------------------------------------------------------------------- */
+ if(in == NULL) { /* clear the error-buffer upon white-lines */
+/* -------------------------------------------------------------------- */
+
+ memset(buf,0,fullcolor_line_size);
+
+/* ------------------------------------------------------------------- */
+ } else { /* do the actual dithering */
+/* ------------------------------------------------------------------- */
+ int i, j, k, e, l, i2, below[3][3], *fb, *b, *bb, *tb;
+ byte *p, *q, *cp;
+ static int dir = 1;
+
+ p = buf;
+ if (*p != 0 || memcmp((char *) p, (char *) p + 1, fullcolor_line_size - 1))
+ {
+ for(p = in, q=buf, i=fullcolor_line_size;
+ i--; p++, q++ )
+ {
+ j = *p + ((*q & 128) ? *q - 256 : *q);
+ LIMIT(j);
+ *p = j;
+ }
+ }
+
+ p = in;
+
+ fb = below[2];
+ b = below[1];
+ bb = below[0];
+ *b = b[1] = b[2] = *bb = bb[1] = bb[2] = 0;
+
+ if (dir)
+ {
+ for(p = in, q=buf-3,
+ i=fullcolor_line_size; i; i-=3)
+ {
+ cp = escp2c_pick_best(p);
+ for(i2=3; i2--; p++, q++, fb++, b++, bb++)
+ {
+ j = *p;
+ *p = *cp++;
+ j -= *p;
+ if (j != 0)
+ {
+ l = (e = (j>>1)) - (*fb = (j>>4));
+ if (i > 2)
+ {
+ k = p[3] + l;
+ LIMIT(k);
+ p[3] = k;
+ }
+ *b += e - (l = (j>>2) - *fb);
+ if (i < fullcolor_line_size)
+ {
+ l += *bb;
+ LIMIT2(l);
+ *q = l;
+ }
+ }
+ else
+ *fb = 0;
+ }
+ tb = bb-3;
+ bb = b-3;
+ b = fb-3;
+ fb = tb;
+ }
+ *q = *bb;
+ q[1] = bb[1];
+ q[2] = bb[2];
+ dir = 0;
+ }
+ else
+ {
+ for(p = in+fullcolor_line_size-1,
+ q = buf+fullcolor_line_size+2, i=fullcolor_line_size;
+ i; i-=3)
+ {
+ cp = escp2c_pick_best(p-2) + 2;
+ for(i2=3; i2--; p--, q--, fb++, b++, bb++)
+ {
+ j = *p;
+ *p = *cp--;
+ j -= *p;
+ if (j != 0)
+ {
+ l = (e = (j>>1)) - (*fb = (j>>4));
+ if (i > 2)
+ {
+ k = p[-3] + l;
+ LIMIT(k);
+ p[-3] = k;
+ }
+ *b += e - (l = (j>>2) - *fb);
+ if (i < fullcolor_line_size)
+ {
+ l += *bb;
+ LIMIT2(l);
+ *q = l;
+ }
+ }
+ else
+ *fb = 0;
+ }
+ tb = bb-3;
+ bb = b-3;
+ b = fb-3;
+ fb = tb;
+ }
+ *q = *bb;
+ q[1] = bb[1];
+ q[2] = bb[2];
+ dir = 1;
+ }
+
+ escp2c_conv_stc(in, out, fullcolor_line_size);
+
+/* ------------------------------------------------------------------- */
+ } /* buffer-reset | dithering */
+/* ------------------------------------------------------------------- */
+
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+
+/*
+ * check wether the number of components is valid
+ */
+ if(sd->color_info.num_components != 3) return -1;
+
+/*
+ * check wether stcdither & TYPE are correct
+ */
+ if(( sd->stc.dither == NULL) ||
+ ((sd->stc.dither->flags & STC_TYPE) != STC_BYTE)) return -2;
+
+/*
+ * check wether the buffer-size is sufficiently large
+ */
+ if((sd->stc.dither->flags/STC_SCAN) < 1) return -3;
+
+/*
+ * finally clear the buffer
+ */
+ memset(buf,0,-fullcolor_line_size);
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return 0;
+}
diff --git a/gs/src/gdevsun.c b/gs/src/gdevsun.c
new file mode 100644
index 000000000..a0bfc845c
--- /dev/null
+++ b/gs/src/gdevsun.c
@@ -0,0 +1,685 @@
+/* Copyright (C) 1989, 1992, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsun.c */
+/* SunView driver */
+#include "gx.h" /* for gx_bitmap; includes std.h */
+
+#include <suntool/sunview.h>
+#include <suntool/canvas.h>
+#include <sunwindow/cms_mono.h>
+#include <stdio.h>
+
+#include "gscdefs.h"
+#include "gsmatrix.h" /* needed for gxdevice.h */
+#include "gxdevice.h"
+#include "malloc_.h"
+
+#ifndef DEFAULT_DPI
+# define DEFAULT_DPI 75 /* Sun standard monitor */
+#endif
+
+#ifdef A4
+# define PAPER_X 8.27 /* A4 paper */
+# define PAPER_Y 11.69
+#endif
+
+#ifndef PAPER_X
+# define PAPER_X 8.5 /* US letter paper */
+# define PAPER_Y 11
+#endif
+/* Procedures */
+dev_proc_open_device(sun_open);
+dev_proc_sync_output(sun_sync);
+dev_proc_close_device(sun_close);
+dev_proc_map_rgb_color(sun_map_rgb_color);
+dev_proc_map_color_rgb(sun_map_color_rgb);
+dev_proc_fill_rectangle(sun_fill_rectangle);
+dev_proc_copy_mono(sun_copy_mono);
+dev_proc_copy_color(sun_copy_color);
+dev_proc_draw_line(sun_draw_line);
+
+/* The device descriptor */
+private gx_device_procs sun_procs = {
+ sun_open,
+ NULL, /* get_initial_matrix */
+ sun_sync,
+ NULL, /* output_page */
+ sun_close,
+ sun_map_rgb_color,
+ sun_map_color_rgb,
+ sun_fill_rectangle,
+ NULL, /* tile_rectangle */
+ sun_copy_mono,
+ sun_copy_color,
+ sun_draw_line
+};
+
+#define CMSNAME "GHOSTVIEW" /* SunView colormap name */
+
+/* Define the SunView device */
+typedef struct gx_device_sun {
+ gx_device_common;
+ Frame frame;
+ Canvas canvas;
+ Pixwin *pw;
+ struct mpr_data mpr;
+ Pixrect pr;
+ int truecolor; /* use truecolor mapping */
+ int freecols; /* unallocated colors */
+ byte *red, *green, *blue; /* colormap */
+ char cmsname[sizeof(CMSNAME)+9];/* color map name */
+#if !arch_is_big_endian /* need to swap bits & bytes */
+# define BUF_WIDTH_BYTES (((int)(8.5*DEFAULT_DPI)+15)/16*2)
+ byte swap_buf[BUF_WIDTH_BYTES];
+#endif
+} gx_device_sun;
+
+#if !arch_is_big_endian
+/* Define a table for reversing bit order. */
+static byte reverse_bits[256] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
+#endif
+
+/* The instance is public. */
+gx_device_sun far_data gs_sunview_device = {
+ std_device_std_body(gx_device_sun, &sun_procs, "sunview",
+ (int)(PAPER_X*DEFAULT_DPI), (int)(PAPER_Y*DEFAULT_DPI), /* x and y extent */
+ DEFAULT_DPI, DEFAULT_DPI /* x and y density */
+ ), /* fill in color_info later from display depth */
+ { 0 }, /* std_procs */
+ 0, /* connection not initialized */
+};
+
+/* Macro for casting gx_device argument */
+#define xdev ((gx_device_sun *)dev)
+
+/*
+ * The macros below define the colormap configuration used on 8-bit
+ * pseudo-color displays.
+ */
+/*
+ * The following macros define the number of bits used to represent rgb colors.
+ * The total must not exceed the display depth.
+ * Note that the RGB dimensions could have an uneven number of bits assigned
+ * to them, but that will cause dithering to not work very well, since
+ * gs assumes the dither ramp is the same for all 3 color dimensions.
+ *
+ * Setting RED_BITS to n will pre-allocate a color-cube of 2^(3n) entries.
+ * The remaining entries are allocated on demand for colors requested by
+ * sun_map_rgb_color(), until the color map is full. At that point gs will
+ * fall back onto dithering using the pre-allocated colors.
+ * As a special case, if RED_BITS = GREEN_BITS = BLUE_BITS = 0, only
+ * black and white are pre-allocated.
+ */
+#define RED_BITS 2 /* everything depends on this one */
+#define GREEN_BITS RED_BITS
+#define BLUE_BITS RED_BITS
+#define DEPTH 8 /* don't change this */
+#define RGB_BITS (RED_BITS + GREEN_BITS + BLUE_BITS)
+/*
+ * Smallest # bits per dimension
+ */
+#define MAX_BITS RED_BITS
+#if (GREEN_BITS > MAX_BITS)
+#undef MAX_BITS
+#define MAX_BITS GREEN_BITS
+#endif
+#if (BLUE_BITS > MAX_BITS)
+#undef MAX_BITS
+#define MAX_BITS BLUE_BITS
+#endif
+/*
+ * masks to pull out rgb components
+ */
+#define BLUE_MASK ((1 << BLUE_BITS) - 1)
+#define GREEN_MASK ((1 << (BLUE_BITS + GREEN_BITS)) - 1 - BLUE_MASK)
+#define RED_MASK ((1 << (BLUE_BITS + GREEN_BITS + RED_BITS)) - 1 \
+ - BLUE_MASK - GREEN_MASK)
+/*
+ * number of colors on rgb dimensions
+ */
+#define RED_COLS (1 << RED_BITS)
+#define GREEN_COLS (1 << GREEN_BITS)
+#define BLUE_COLS (1 << BLUE_BITS)
+#define RGB_COLS (RED_COLS * GREEN_COLS * BLUE_COLS)
+#define MAX_COLS (1 << MAX_BITS)
+/*
+ * maximum number of colors in map
+ */
+#define ALL_COLS (1 << DEPTH) /* 256 */
+#define CMS_SIZE ALL_COLS /* cut down to 64 or 128 for
+ more cooperative behaviour */
+
+#if (RGB_COLS > CMS_SIZE) /* one is reserved for the scrollbar */
+CMS_SIZE_too_small_for_color_cube
+#endif
+#if (RGB_BITS < 0) || (RGB_BITS > DEPTH)
+Display_does_not_support_this_many_colors
+#endif
+
+/*
+ * The macros below define the color mapping used on 24-bit true-color
+ * displays.
+ * FAKE_TRUE_COLOR is used for debugging only. It simulates a true-color
+ * type mapping on an 8-bit pseudo-color display.
+#define FAKE_TRUE_COLOR
+ */
+#ifdef FAKE_TRUE_COLOR
+# define TRUE_RED_BITS 3 /* everything depends on this one */
+# define TRUE_GREEN_BITS 2
+# define TRUE_BLUE_BITS (DEPTH - TRUE_RED_BITS - TRUE_GREEN_BITS)
+#else
+# define TRUE_RED_BITS 8 /* everything depends on this one */
+# define TRUE_GREEN_BITS TRUE_RED_BITS
+# define TRUE_BLUE_BITS TRUE_RED_BITS
+#endif ./* FAKE_TRUE_COLOR */
+#define TRUE_DEPTH (TRUE_RED_BITS + TRUE_GREEN_BITS + TRUE_BLUE_BITS)
+/*
+ * Masks to pull out rgb components. Note that the bit order is BGR from
+ * high to low order bits.
+ */
+#define TRUE_RED_MASK ((1 << TRUE_RED_BITS) - 1)
+#define TRUE_GREEN_MASK ((1 << (TRUE_RED_BITS + TRUE_GREEN_BITS)) - 1 \
+ - TRUE_RED_MASK)
+#define TRUE_BLUE_MASK ((1 << (TRUE_RED_BITS + TRUE_GREEN_BITS \
+ + TRUE_BLUE_BITS)) - 1 \
+ - TRUE_GREEN_MASK - TRUE_RED_MASK)
+/*
+ * number of colors on rgb dimensions
+ */
+#define TRUE_RED_COLS (1 << TRUE_RED_BITS)
+#define TRUE_GREEN_COLS (1 << TRUE_GREEN_BITS)
+#define TRUE_BLUE_COLS (1 << TRUE_BLUE_BITS)
+
+/* Initialize the device. */
+private Notify_value destroy_func();
+int
+sun_open(register gx_device *dev)
+{
+#ifdef gs_DEBUG
+if ( gs_debug['X'] )
+ { extern int _Xdebug;
+ _Xdebug = 1;
+ }
+#endif
+ if (xdev->frame == (Frame)0)
+ xdev->frame =
+ window_create(NULL, FRAME, FRAME_LABEL, gs_product,
+ WIN_WIDTH, min(xdev->width + 24, 900),
+ WIN_HEIGHT, min(xdev->height + 36, 900),
+ WIN_Y, 0,
+ WIN_X, 200,
+ 0);
+ if (xdev->frame == (Frame)0)
+ return -1;
+ xdev->canvas = window_create(xdev->frame, CANVAS,
+ CANVAS_AUTO_EXPAND, FALSE,
+ CANVAS_AUTO_SHRINK, FALSE,
+ CANVAS_WIDTH, xdev->width,
+ CANVAS_HEIGHT, xdev->height,
+#ifndef PRE_IBIS /* try to use 24-bit visual if OS supports it */
+ CANVAS_COLOR24, TRUE,
+#endif
+ CANVAS_RETAINED, FALSE,
+ 0);
+ xdev->pw = canvas_pixwin(xdev->canvas);
+
+ switch (xdev->pw->pw_pixrect->pr_depth) {
+ static gx_device_color_info mono_ci =
+ dci_black_and_white;
+ /*
+ * If the pre-allocated color cube leaves room for spare entries,
+ * tell gs we can render colors exactly. Otherwise admit our
+ * limitations.
+ */
+ static gx_device_color_info color_ci =
+#if (RGB_COLS < CMS_SIZE)
+ dci_color(DEPTH, 31, MAX_COLS);
+#else
+ dci_color(DEPTH, MAX_COLS - 1, MAX_COLS);
+#endif
+ static gx_device_color_info truecolor_ci =
+ dci_color(TRUE_DEPTH,31,4);
+ case 1:
+ /* mono display */
+ xdev->color_info = mono_ci;
+ break;
+#ifndef FAKE_TRUE_COLOR
+ case DEPTH:
+ /* pseudo-color display */
+ xdev->color_info = color_ci;
+ xdev->truecolor = 0;
+ break;
+#endif /* FAKE_TRUE_COLOR */
+ case TRUE_DEPTH:
+ case TRUE_DEPTH+8: /* I'm not sure whether the XBGR frame buffer
+ returns depth 24 or 32. */
+ /* pseudo-color display */
+ xdev->color_info = truecolor_ci;
+ xdev->truecolor = 1;
+ break;
+ default:
+ eprintf1("gs: Cannot handle display of depth %d.\n",
+ xdev->pw->pw_pixrect->pr_depth);
+ return -1;
+ }
+
+ if ( gx_device_has_color(xdev)
+#ifndef FAKE_TRUE_COLOR
+ && !xdev->truecolor
+#endif
+ )
+ {
+ int j;
+ int color;
+
+ /*
+ * Create the pre-allocated colorcube.
+ */
+ xdev->red = (byte *)malloc(CMS_SIZE);
+ xdev->green = (byte *)malloc(CMS_SIZE);
+ xdev->blue = (byte *)malloc(CMS_SIZE);
+ if (!xdev->red || !xdev->green || !xdev->blue) {
+ eprintf("gs: no memory for colormap\n");
+ return -1;
+ }
+
+#ifdef FAKE_TRUE_COLOR
+ /*
+ * Fit the largest possible color cube into the colormap.
+ */
+ for ( j = 0; j < ALL_COLS; j++ ) {
+ xdev->blue[j] =
+ (double)((j & TRUE_BLUE_MASK)
+ >> (TRUE_GREEN_BITS + TRUE_RED_BITS))
+ / (TRUE_BLUE_COLS - 1)
+ * (ALL_COLS - 1);
+ xdev->green[j] =
+ (double)((j & TRUE_GREEN_MASK) >> TRUE_RED_BITS)
+ / (TRUE_GREEN_COLS - 1)
+ * (ALL_COLS - 1);
+ xdev->red[j] =
+ (double)((j & TRUE_RED_MASK))
+ / (TRUE_RED_COLS - 1)
+ * (ALL_COLS - 1);
+ }
+
+ xdev->freecols = 0;
+#else /* !FAKE_TRUE_COLOR */
+ /*
+ * Black and white are allocated in the last two slots,
+ * so as to be compatible with the monochrome colormap.
+ * This prevents most text etc. to go technicolor as focus
+ * changes into the window.
+ *
+ * The requirement that these two entries be at the end
+ * of the colormap makes it most convenient to allocate
+ * the remmaining entries from back to the front as well.
+ * Therefore xdev->freecols is the minimal allocated
+ * color index, and decreases as new ones are allocated.
+ */
+ j = CMS_SIZE - 2;
+ cms_monochromeload(xdev->red + j,
+ xdev->green + j,
+ xdev->blue + j);
+
+ /*
+ * The remaining slots down to CMS_SIZE - RGB_COLS are filled
+ * with evenly spaced points from the colorcube.
+ */
+ for ( color = 1; color < RGB_COLS - 1; color++ ) {
+ j--;
+ xdev->red[j] =
+ (double)((color & RED_MASK) >> (GREEN_BITS + BLUE_BITS))
+ / (RED_COLS - 1)
+ * (ALL_COLS - 1);
+ xdev->green[j] =
+ (double)((color & GREEN_MASK) >> BLUE_BITS)
+ / (GREEN_COLS - 1)
+ * (ALL_COLS - 1);
+ xdev->blue[j] =
+ (double)((color & BLUE_MASK))
+ / (BLUE_COLS - 1)
+ * (ALL_COLS - 1);
+ }
+
+
+ /*
+ * Set the low-water mark to the beginning of the colorcube.
+ */
+ xdev->freecols = j;
+
+ /*
+ * The unused entries are filled so that the last entry is
+ * always different from the 0th entry. This is a requirement
+ * for SunWindows.
+ */
+ for (j-- ; j >= 0 ; j--) {
+ xdev->red[j] = xdev->green[j] = xdev->blue[j] =
+ ~xdev->red[CMS_SIZE - 1];
+ }
+#endif /* FAKE_TRUE_COLOR */
+
+ /*
+ * Install the colormap.
+ */
+ sprintf(xdev->cmsname, "%s-%d", CMSNAME, getpid());
+ pw_setcmsname(xdev->pw, xdev->cmsname);
+ pw_putcolormap(xdev->pw, 0, CMS_SIZE,
+ xdev->red, xdev->green, xdev->blue);
+ }
+ else {
+ xdev->freecols = 0;
+ xdev->red = (byte *)0;
+ xdev->green = (byte *)0;
+ xdev->blue = (byte *)0;
+ }
+
+ /*
+ * Reset to retained after colormap length is changed
+ */
+ window_set(xdev->canvas,
+ CANVAS_RETAINED, TRUE,
+ WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
+ WIN_HORIZONTAL_SCROLLBAR, scrollbar_create(0),
+ 0);
+ window_set(xdev->frame, WIN_SHOW, TRUE, 0);
+ /* Interpose a destroy function to keep the driver bookkeeping */
+ /* machinery from getting confused if the user closes the window. */
+ notify_interpose_destroy_func(xdev->frame, destroy_func);
+ (void) notify_do_dispatch();
+ (void) notify_dispatch();
+ return 0;
+}
+/* Prevent the user from closing the window. */
+private Notify_value
+destroy_func(Frame frame, Destroy_status status)
+{ if ( status == DESTROY_CHECKING )
+ { notify_veto_destroy(frame);
+ return (NOTIFY_DONE);
+ }
+ return (notify_next_destroy_func(frame, status));
+}
+
+/* Close the device. */
+int
+sun_close(gx_device *dev)
+{ window_destroy(xdev->frame);
+ xdev->frame = (Frame)0;
+ xdev->canvas = (Canvas)0;
+ xdev->pw = (Pixwin *)0;
+ xdev->freecols = 0;
+ if (xdev->red)
+ free(xdev->red);
+ if (xdev->green)
+ free(xdev->green);
+ if (xdev->blue)
+ free(xdev->blue);
+ return 0;
+}
+
+/* Synchronize the display with the commands already given */
+int
+sun_sync(register gx_device *dev)
+{ (void) notify_dispatch();
+ return 0;
+}
+
+/* Map RGB to color number -
+ Look for existing entry in colormap, or create a new one, or
+ give up if no free colormap entries (requesting dithering).
+ */
+gx_color_index
+sun_map_rgb_color(gx_device *dev, unsigned short red,
+ unsigned short green, unsigned short blue)
+{ if ( !xdev->frame || !gx_device_has_color(dev) )
+ /*
+ * Invert default color index to match mono display
+ * pixel values (black = 1, white = 0).
+ */
+ return !gx_default_map_rgb_color(dev, red, green, blue);
+ else if ( !xdev->truecolor ) {
+ byte red_val, green_val, blue_val;
+ int i;
+ static int warn = 1;
+
+ /*
+ * Determine the RGB values at display resolution we
+ * ideally would want this color to be mapped into.
+ */
+ red_val = (double)red/gx_max_color_value * (ALL_COLS - 1);
+ green_val = (double)green/gx_max_color_value * (ALL_COLS - 1);
+ blue_val = (double)blue/gx_max_color_value * (ALL_COLS - 1);
+
+ /*
+ * Look for an exact match among the colors already allocated.
+ * This includes the pre-allocated default color cube.
+ */
+ for (i = CMS_SIZE - 1; i >= xdev->freecols; i--) {
+ if (xdev->red[i] == red_val &&
+ xdev->green[i] == green_val &&
+ xdev->blue[i] == blue_val) {
+ return i;
+ }
+ }
+
+ /*
+ * If we run out of space in the color map, let gs know.
+ * It will call us again to request colors to do the
+ * dithering, and hopefully request only RGB values that
+ * match the colorcube entries. IF NOT, WE WILL LOOP
+ * FOREVER!
+ * NOTE: Leave the zero'th colormap entry alone lest the
+ * scrollbar be colored.
+ */
+ if (xdev->freecols <= 1) {
+ if (warn) {
+ eprintf("gs: last spare color map entry allocated\n");
+ warn = 0;
+ }
+ return gx_no_color_index;
+ }
+
+ /*
+ * Allocate new color in map.
+ */
+ xdev->red[i] = red_val;
+ xdev->green[i] = green_val;
+ xdev->blue[i] = blue_val;
+ pw_setcmsname(xdev->pw, xdev->cmsname);
+ pw_putcolormap(xdev->pw, i, 1,
+ &xdev->red[i], &xdev->green[i], &xdev->blue[i]);
+
+ xdev->freecols = i;
+ return i;
+ }
+ else { /* true color mapping --
+ color index encodes all 3 RGB values */
+ return ((blue >> (gx_color_value_bits - TRUE_BLUE_BITS))
+ << (TRUE_GREEN_BITS + TRUE_RED_BITS)) |
+ ((green >> (gx_color_value_bits - TRUE_GREEN_BITS))
+ << TRUE_RED_BITS) |
+ (red >> (gx_color_value_bits - TRUE_RED_BITS));
+ }
+}
+
+/* Map color number back to RGB values - see sun_map_rgb_color(), above */
+int
+sun_map_color_rgb(gx_device *dev, gx_color_index color,
+ unsigned short rgb[3])
+{ if ( !xdev->frame || !gx_device_has_color(dev) )
+ return gx_default_map_color_rgb(dev, !color, rgb);
+ else if ( !xdev->truecolor ) {
+ /*
+ * We just use the colormap to map back to rgb values.
+ */
+ if (color < xdev->freecols || color >= CMS_SIZE) {
+ eprintf1("gs: attempt to get RGB values for unallocated color index %d\n", (int)color);
+ return -1;
+ }
+ rgb[0] = (double)xdev->red[color] / (ALL_COLS - 1)
+ * gx_max_color_value;
+ rgb[1] = (double)xdev->green[color] / (ALL_COLS - 1)
+ * gx_max_color_value;
+ rgb[2] = (double)xdev->blue[color] / (ALL_COLS - 1)
+ * gx_max_color_value;
+ return 0;
+ }
+ else { /* true color mapping */
+ rgb[0] = (double)((unsigned short)(color & TRUE_RED_MASK))
+ / (TRUE_RED_COLS - 1)
+ * gx_max_color_value;
+ rgb[1] = (double)((unsigned short)(color & TRUE_GREEN_MASK)
+ >> TRUE_RED_BITS)
+ / (TRUE_GREEN_COLS - 1)
+ * gx_max_color_value;
+ rgb[2] = (double)((unsigned short)(color & TRUE_BLUE_MASK)
+ >> (TRUE_GREEN_BITS + TRUE_RED_BITS))
+ / (TRUE_BLUE_COLS - 1)
+ * gx_max_color_value;
+ return 0;
+ }
+}
+
+/* Fill a rectangle with a color. */
+int
+sun_fill_rectangle(register gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{ fit_fill(dev, x, y, w, h);
+
+ pw_write(xdev->pw, x, y, w, h, PIX_SRC | PIX_COLOR((int)(color)),
+ (Pixrect *)0, 0, 0);
+ (void) notify_dispatch();
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+int
+sun_copy_mono(register gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{
+/* We define a non-const pointer to the data so we can invert it or */
+/* byte-swap it in place temporarily (we restore it at the end). */
+/* Yes, this is a bad and wicked thing to do! */
+#define non_const_base ((byte *)base)
+
+ register int i;
+ int nbytes;
+ extern struct pixrectops mem_ops;
+#if !arch_is_big_endian /* need to swap bits & bytes */
+# define BUF_WIDTH_BYTES (((int)(8.5*DEFAULT_DPI)+15)/16*2)
+ byte swap_buf[BUF_WIDTH_BYTES];
+#endif
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ nbytes = h * raster;
+
+ xdev->pr.pr_ops = &mem_ops;
+ xdev->pr.pr_width = w + sourcex + 8;
+ xdev->pr.pr_height = h;
+ xdev->pr.pr_depth = 1;
+ xdev->pr.pr_data = (caddr_t)&(xdev->mpr);
+ xdev->mpr.md_linebytes = raster;
+ xdev->mpr.md_image = (short *)((ulong)base & ~1);
+#if !arch_is_big_endian
+ /* Reverse the bit order in each byte. */
+ for ( i = 0; i < nbytes; i++ )
+ non_const_base[i] = reverse_bits[base[i]];
+#endif
+ pw_batch_on(xdev->pw);
+ if (one != gx_no_color_index)
+ { pw_stencil(xdev->pw, x, y, w, h,
+ PIX_SRC | PIX_COLOR(one), &(xdev->pr),
+ ((int)base & 1) ? sourcex + 8 : sourcex, 0,
+ (Pixrect *)0, 0, 0);
+ }
+ if (zero != gx_no_color_index)
+ { for (i = 0; i < nbytes; i++)
+ non_const_base[i] = ~base[i];
+ pw_stencil(xdev->pw, x, y, w, h,
+ PIX_SRC | PIX_COLOR(zero), &(xdev->pr),
+ ((int)base & 1) ? sourcex + 8 : sourcex, 0,
+ (Pixrect *)0, 0, 0);
+ for (i = 0; i < nbytes; i++)
+ non_const_base[i] = ~base[i];
+ }
+ pw_batch_off(xdev->pw);
+#if !arch_is_big_endian
+ /* Reverse the bits back again. */
+ for ( i = 0; i < nbytes; i++ )
+ non_const_base[i] = reverse_bits[base[i]];
+#endif
+ (void) notify_dispatch();
+ return 0;
+}
+
+/* Copy a color bitmap. */
+int
+sun_copy_color(register gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ extern struct pixrectops mem_ops;
+
+ if ( !gx_device_has_color(dev) )
+ return sun_copy_mono(dev, base, sourcex, raster, id,
+ x, y, w, h,
+ (gx_color_index)0, (gx_color_index)1);
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ xdev->pr.pr_ops = &mem_ops;
+ xdev->pr.pr_width = w + sourcex + 8;
+ xdev->pr.pr_height = h;
+ xdev->pr.pr_depth = 8;
+ xdev->pr.pr_data = (caddr_t)&(xdev->mpr);
+ xdev->mpr.md_linebytes = raster;
+ xdev->mpr.md_image = (short *)((ulong)base & ~1);
+ pw_write(xdev->pw, x, y, w, h,
+ PIX_SRC, &(xdev->pr),
+ (((int)base & 1) ? sourcex + 8 : sourcex), 0);
+ (void) notify_dispatch();
+ return 0;
+}
+
+/* Draw a line */
+int
+sun_draw_line(register gx_device *dev,
+ int x0, int y0, int x1, int y1, gx_color_index color)
+{ pw_vector(xdev->pw, x0, y0, x1, y1, PIX_SRC, color);
+ (void) notify_dispatch();
+ return 0;
+}
diff --git a/gs/src/gdevsvga.c b/gs/src/gdevsvga.c
new file mode 100644
index 000000000..40c337f04
--- /dev/null
+++ b/gs/src/gdevsvga.c
@@ -0,0 +1,952 @@
+/* Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsvga.c */
+/* SuperVGA display drivers */
+#include "memory_.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h" /* for ...log2 */
+#include "gxdevice.h"
+#include "gdevpccm.h"
+#include "gdevpcfb.h"
+#include "gdevsvga.h"
+#include "gsparam.h"
+
+/* The color map for dynamically assignable colors. */
+#define first_dc_index 64
+private int next_dc_index;
+#define dc_hash_size 293 /* prime, >num_dc */
+typedef struct { ushort rgb, index; } dc_entry;
+private dc_entry dynamic_colors[dc_hash_size + 1];
+#define num_colors 255
+
+/* Macro for casting gx_device argument */
+#define fb_dev ((gx_device_svga *)dev)
+
+/* Procedure records */
+#define svga_procs(open) {\
+ open, NULL /*get_initial_matrix*/,\
+ NULL /*sync_output*/, NULL /*output_page*/, svga_close,\
+ svga_map_rgb_color, svga_map_color_rgb,\
+ svga_fill_rectangle, NULL /*tile_rectangle*/,\
+ svga_copy_mono, svga_copy_color, NULL /*draw_line*/,\
+ svga_get_bits, NULL /*get_params*/, svga_put_params,\
+ NULL /*map_cmyk_color*/, NULL /*get_xfont_procs*/,\
+ NULL /*get_xfont_device*/, NULL /*map_rgb_alpha_color*/,\
+ NULL /*get_page_device*/, svga_get_alpha_bits, svga_copy_alpha\
+}
+
+/* Save the controller mode */
+private int svga_save_mode = -1;
+
+/* ------ Internal routines ------ */
+
+#define regen 0xa000
+
+/* Construct a pointer for writing a pixel. */
+/* Assume 64K pages, 64K granularity. */
+/* We know that y is within bounds. */
+#define set_pixel_ptr(ptr, fbdev, x, y, wnum)\
+{ ulong index = (ulong)(y) * fbdev->raster + (uint)(x);\
+ if ( (uint)(index >> 16) != fbdev->current_page )\
+ { (*fbdev->set_page)(fbdev, (fbdev->current_page = index >> 16), wnum);\
+ }\
+ ptr = (fb_ptr)MK_PTR(regen, (ushort)index);\
+}
+#define set_pixel_write_ptr(ptr, fbdev, x, y)\
+ set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_write)
+#define set_pixel_read_ptr(ptr, fbdev, x, y)\
+ set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_read)
+
+/* Find the graphics mode for a desired width and height. */
+/* Set the mode in the device structure and return 0, */
+/* or return an error code. */
+int
+svga_find_mode(gx_device *dev, const mode_info _ds *mip)
+{ for ( ; ; mip++ )
+ { if ( mip->width >= fb_dev->width &&
+ mip->height >= fb_dev->height ||
+ mip[1].mode < 0
+ )
+ { fb_dev->mode = mip;
+ gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
+ fb_dev->raster = fb_dev->width;
+ return 0;
+ }
+ }
+ return_error(gs_error_rangecheck);
+}
+
+/* Set the index for writing into the color DAC. */
+#define svga_dac_set_write_index(i) outportb(0x3c8, i)
+
+/* Write 6-bit R,G,B values into the color DAC. */
+#define svga_dac_write(r, g, b)\
+ (outportb(0x3c9, r), outportb(0x3c9, g), outportb(0x3c9, b))
+
+/* ------ Common procedures ------ */
+
+#define cv_bits(v,n) (v >> (gx_color_value_bits - n))
+
+/* Initialize the dynamic color table, if any. */
+void
+svga_init_colors(gx_device *dev)
+{ if ( fb_dev->fixed_colors )
+ next_dc_index = num_colors;
+ else
+ { memset(dynamic_colors, 0,
+ (dc_hash_size + 1) * sizeof(dc_entry));
+ next_dc_index = first_dc_index;
+ }
+}
+
+/* Load the color DAC with the predefined colors. */
+private void
+svga_load_colors(gx_device *dev)
+{ int ci;
+ svga_dac_set_write_index(0);
+ if ( fb_dev->fixed_colors )
+ for ( ci = 0; ci < num_colors; ci++ )
+ { gx_color_value rgb[3];
+ pc_8bit_map_color_rgb(dev, (gx_color_index)ci, rgb);
+ svga_dac_write(cv_bits(rgb[0], 6), cv_bits(rgb[1], 6),
+ cv_bits(rgb[2], 6));
+ }
+ else
+ for ( ci = 0; ci < 64; ci++ )
+ { static const byte c2[10] =
+ { 0, 42, 0, 0, 0, 0, 0, 0, 21, 63 };
+ svga_dac_write(c2[(ci >> 2) & 9], c2[(ci >> 1) & 9],
+ c2[ci & 9]);
+ }
+}
+
+/* Initialize the device structure and the DACs. */
+int
+svga_open(gx_device *dev)
+{ fb_dev->x_pixels_per_inch =
+ fb_dev->y_pixels_per_inch =
+ fb_dev->height / PAGE_HEIGHT_INCHES;
+ /* Set the display mode. */
+ if ( svga_save_mode < 0 )
+ svga_save_mode = (*fb_dev->get_mode)();
+ (*fb_dev->set_mode)(fb_dev->mode->mode);
+ svga_init_colors(dev);
+ svga_load_colors(dev);
+ fb_dev->current_page = -1;
+ return 0;
+}
+
+/* Close the device; reinitialize the display for text mode. */
+int
+svga_close(gx_device *dev)
+{ if ( svga_save_mode >= 0 )
+ (*fb_dev->set_mode)(svga_save_mode);
+ svga_save_mode = -1;
+ return 0;
+}
+
+/* Map a r-g-b color to a palette index. */
+/* The first 64 entries of the color map are set */
+/* for compatibility with the older display modes: */
+/* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
+gx_color_index
+svga_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ ushort rgb;
+ if ( fb_dev->fixed_colors )
+ { gx_color_index ci = pc_8bit_map_rgb_color(dev, r, g, b);
+ /* Here is where we should permute the index to match */
+ /* the old color map... but we don't yet. */
+ return ci;
+ }
+ { ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5),
+ b5 = cv_bits(b, 5);
+ static const byte cube_bits[32] =
+ { 0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 9
+ };
+ uint cx = ((uint)cube_bits[r5] << 2) +
+ ((uint)cube_bits[g5] << 1) +
+ (uint)cube_bits[b5];
+ /* Check for a color on the cube. */
+ if ( cx < 64 ) return (gx_color_index)cx;
+ /* Not on the cube, check the dynamic color table. */
+ rgb = (r5 << 10) + (g5 << 5) + b5;
+ }
+ { register dc_entry _ds *pdc;
+ for ( pdc = &dynamic_colors[rgb % dc_hash_size];
+ pdc->rgb != 0; pdc++
+ )
+ if ( pdc->rgb == rgb )
+ return (gx_color_index)(pdc->index);
+ if ( pdc == &dynamic_colors[dc_hash_size] )
+ { /* Wraparound */
+ for ( pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++ )
+ if ( pdc->rgb == rgb )
+ return (gx_color_index)(pdc->index);
+ }
+ if ( next_dc_index == num_colors )
+ { /* No space left, report failure. */
+ return gx_no_color_index;
+ }
+ /* Not on the cube, and not in the dynamic table. */
+ /* Put in the dynamic table if space available. */
+ { int i = next_dc_index++;
+ pdc->rgb = rgb;
+ pdc->index = i;
+ svga_dac_set_write_index(i);
+ svga_dac_write(cv_bits(r, 6), cv_bits(g, 6),
+ cv_bits(b, 6));
+ return (gx_color_index)i;
+ }
+ }
+}
+
+/* Map a color code to r-g-b. */
+/* This routine must invert the transformation of the one above. */
+/* Since this is practically never used, we just read the DAC. */
+int
+svga_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ uint cval;
+ outportb(0x3c7, (byte)color);
+#define dacin() (cval = inportb(0x3c9) >> 1,\
+ ((cval << 11) + (cval << 6) + (cval << 1) + (cval >> 4)) >>\
+ (16 - gx_color_value_bits))
+ prgb[0] = dacin();
+ prgb[1] = dacin();
+ prgb[2] = dacin();
+#undef dacin
+ return 0;
+}
+
+/* Fill a rectangle. */
+int
+svga_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ uint raster = fb_dev->raster;
+ ushort limit = (ushort)-raster;
+ int yi;
+ fb_ptr ptr;
+ fit_fill(dev, x, y, w, h);
+ set_pixel_write_ptr(ptr, fb_dev, x, y);
+ /* Most fills are very small and don't cross a page boundary. */
+ yi = h;
+ switch ( w )
+ {
+ case 0: return 0; /* no-op */
+ case 1:
+ while ( --yi >= 0 && PTR_OFF(ptr) < limit )
+ ptr[0] = (byte)color,
+ ptr += raster;
+ if ( !++yi ) return 0;
+ break;
+ case 2:
+ while ( --yi >= 0 && PTR_OFF(ptr) < limit )
+ ptr[0] = ptr[1] = (byte)color,
+ ptr += raster;
+ if ( !++yi ) return 0;
+ break;
+ case 3:
+ while ( --yi >= 0 && PTR_OFF(ptr) < limit )
+ ptr[0] = ptr[1] = ptr[2] = (byte)color,
+ ptr += raster;
+ if ( !++yi ) return 0;
+ break;
+ case 4:
+ while ( --yi >= 0 && PTR_OFF(ptr) < limit )
+ ptr[0] = ptr[1] = ptr[2] = ptr[3] = (byte)color,
+ ptr += raster;
+ if ( !++yi ) return 0;
+ break;
+ default:
+ if ( w < 0 ) return 0;
+ /* Check for erasepage. */
+ if ( w == dev->width && h == dev->height &&
+ color < first_dc_index
+ )
+ svga_init_colors(dev);
+ }
+ while ( --yi >= 0 )
+ { if ( PTR_OFF(ptr) < limit )
+ { memset(ptr, (byte)color, w);
+ ptr += raster;
+ }
+ else if ( PTR_OFF(ptr) <= (ushort)(-w) )
+ { memset(ptr, (byte)color, w);
+ if ( yi > 0 )
+ set_pixel_write_ptr(ptr, fb_dev, x, y + h - yi);
+ }
+ else
+ { uint left = (uint)0x10000 - PTR_OFF(ptr);
+ memset(ptr, (byte)color, left);
+ set_pixel_write_ptr(ptr, fb_dev, x + left, y + h - 1 - yi);
+ memset(ptr, (byte)color, w - left);
+ ptr += raster - left;
+ }
+ }
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+int
+svga_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
+{ uint raster = fb_dev->raster;
+ ushort limit;
+ register int wi;
+ uint skip;
+ int yi;
+ register fb_ptr ptr = (fb_ptr)0;
+ const byte *srow;
+ uint invert;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ limit = (ushort)-w;
+ skip = raster - w + 1;
+ srow = base + (sourcex >> 3);
+#define izero (int)czero
+#define ione (int)cone
+ if ( ione == no_color )
+ { gx_color_index temp;
+ if ( izero == no_color ) return 0; /* no-op */
+ temp = czero;
+ czero = cone;
+ cone = temp;
+ invert = ~0;
+ }
+ else
+ invert = 0;
+ /* Pre-filling saves us a test in the loop, */
+ /* and since tiling is uncommon, we come out ahead. */
+ if ( izero != no_color )
+ svga_fill_rectangle(dev, x, y, w, h, czero);
+ for ( yi = 0; yi < h; yi++ )
+ { const byte *sptr = srow;
+ uint bits;
+ int bitno = sourcex & 7;
+ wi = w;
+ if ( PTR_OFF(ptr) <= skip )
+ { set_pixel_write_ptr(ptr, fb_dev, x, y + yi);
+ }
+ else if ( PTR_OFF(ptr) > limit )
+ { /* We're crossing a page boundary. */
+ /* This is extremely rare, so it doesn't matter */
+ /* how slow it is. */
+ int xi = (ushort)-PTR_OFF(ptr);
+ svga_copy_mono(dev, srow, sourcex & 7, sraster,
+ gx_no_bitmap_id, x, y + yi, xi, 1,
+ gx_no_color_index, cone);
+ set_pixel_write_ptr(ptr, fb_dev, x + xi, y + yi);
+ sptr = srow - (sourcex >> 3) + ((sourcex + xi) >> 3);
+ bitno = (sourcex + xi) & 7;
+ wi -= xi;
+ }
+ bits = *sptr ^ invert;
+ switch ( bitno )
+ {
+#define ifbit(msk)\
+ if ( bits & msk ) *ptr = (byte)ione;\
+ if ( !--wi ) break; ptr++
+ case 0:
+bit0: ifbit(0x80);
+ case 1:
+ ifbit(0x40);
+ case 2:
+ ifbit(0x20);
+ case 3:
+ ifbit(0x10);
+ case 4:
+ ifbit(0x08);
+ case 5:
+ ifbit(0x04);
+ case 6:
+ ifbit(0x02);
+ case 7:
+ ifbit(0x01);
+#undef ifbit
+ bits = *++sptr ^ invert;
+ goto bit0;
+ }
+ ptr += skip;
+ srow += sraster;
+ }
+#undef izero
+#undef ione
+ return 0;
+}
+
+/* Copy a color pixelmap. This is just like a bitmap, */
+/* except that each pixel takes 8 bits instead of 1. */
+int
+svga_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ int xi, yi;
+ int skip;
+ const byte *sptr;
+ fb_ptr ptr;
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ skip = sraster - w;
+ sptr = base + sourcex;
+ for ( yi = y; yi - y < h; yi++ )
+ { ptr = 0;
+ for ( xi = x; xi - x < w; xi++ )
+ { if ( PTR_OFF(ptr) == 0 )
+ set_pixel_write_ptr(ptr, fb_dev, xi, yi);
+ *ptr++ = *sptr++;
+ }
+ sptr += skip;
+ }
+ return 0;
+}
+
+/* Put parameters. */
+int
+svga_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ int atext = fb_dev->alpha_text, agraphics = fb_dev->alpha_graphics;
+ const char _ds *param_name;
+
+ switch ( code = param_read_int(plist, (param_name = "TextAlphaBits"), &fb_dev->alpha_text) )
+ {
+ case 0:
+ if ( atext == 1 || atext == 2 || atext == 4 )
+ break;
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ ;
+ }
+
+ switch ( code = param_read_int(plist, (param_name = "GraphicsAlphaBits"), &fb_dev->alpha_graphics) )
+ {
+ case 0:
+ if ( agraphics == 1 || agraphics == 2 || agraphics == 4 )
+ break;
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ ;
+ }
+
+ if ( (code = ecode) < 0 ||
+ (code = gx_default_put_params(dev, plist)) < 0
+ )
+ { fb_dev->alpha_text = atext;
+ fb_dev->alpha_graphics = agraphics;
+ }
+ return code;
+}
+
+/* Read scan lines back from the frame buffer. */
+int
+svga_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ uint bytes_per_row = dev->width;
+ ushort limit = (ushort)-bytes_per_row;
+ fb_ptr src;
+ if ( y < 0 || y >= dev->height )
+ return gs_error_rangecheck;
+ set_pixel_read_ptr(src, fb_dev, 0, y);
+ /* The logic here is similar to fill_rectangle. */
+ if ( PTR_OFF(src) <= limit )
+ memcpy(data, src, bytes_per_row);
+ else
+ { uint left = (uint)0x10000 - PTR_OFF(src);
+ memcpy(data, src, left);
+ set_pixel_read_ptr(src, fb_dev, left, y);
+ memcpy(data + left, src, bytes_per_row - left);
+ }
+ if ( actual_data != 0 )
+ *actual_data = data;
+ return 0;
+}
+
+/* Get the number of alpha bits. */
+private int
+svga_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return (type == go_text ? fb_dev->alpha_text :
+ fb_dev->alpha_graphics);
+}
+
+/* Copy an alpha-map to the screen. */
+/* Depth is 1, 2, or 4. */
+private int
+svga_copy_alpha(gx_device *dev, const byte *base, int sourcex,
+ int sraster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{ int xi, yi;
+ int skip;
+ const byte *sptr;
+ byte mask;
+ int ishift;
+ /* We fake alpha by interpreting it as saturation, i.e., */
+ /* alpha = 0 is white, alpha = 1 is the full color. */
+ byte shades[16];
+ gx_color_value rgb[3];
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ int n1 = (1 << depth) - 1;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ shades[0] = (byte)svga_map_rgb_color(dev, gx_max_color_value,
+ gx_max_color_value,
+ gx_max_color_value);
+ shades[n1] = (byte)color;
+ if ( n1 > 1 )
+ { memset(shades + 1, 255, n1 - 1);
+ svga_map_color_rgb(dev, color, rgb);
+ }
+ skip = sraster - ((w * depth) >> 3);
+ sptr = base + (sourcex >> (3 - log2_depth));
+ mask = n1;
+ ishift = (~sourcex & (7 >> log2_depth)) << log2_depth;
+ for ( yi = y; yi - y < h; yi++ )
+ { fb_ptr ptr = 0;
+ int shift = ishift;
+ for ( xi = x; xi - x < w; xi++, ptr++ )
+ { uint a = (*sptr >> shift) & mask;
+ if ( PTR_OFF(ptr) == 0 )
+ set_pixel_write_ptr(ptr, fb_dev, xi, yi);
+map: if ( a != 0 )
+ { byte ci = shades[a];
+ if ( ci == 255 )
+ { /* Map the color now. */
+#define make_shade(v, alpha, n1)\
+ (gx_max_color_value -\
+ ((ulong)(gx_max_color_value - (v)) * (alpha) / (n1)))
+ gx_color_value r =
+ make_shade(rgb[0], a, n1);
+ gx_color_value g =
+ make_shade(rgb[1], a, n1);
+ gx_color_value b =
+ make_shade(rgb[2], a, n1);
+ gx_color_index sci =
+ svga_map_rgb_color(dev, r, g, b);
+ if ( sci == gx_no_color_index )
+ { a += (n1 + 1 - a) >> 1;
+ goto map;
+ }
+ shades[a] = ci = (byte)sci;
+ }
+ *ptr = ci;
+ }
+ if ( shift == 0 )
+ shift = 8 - depth, sptr++;
+ else
+ shift -= depth;
+ }
+ sptr += skip;
+ }
+ return 0;
+}
+
+/* ------ The VESA device ------ */
+
+private dev_proc_open_device(vesa_open);
+private gx_device_procs vesa_procs = svga_procs(vesa_open);
+int vesa_get_mode(P0());
+void vesa_set_mode(P1(int));
+private void vesa_set_page(P3(gx_device_svga *, int, int));
+gx_device_svga far_data gs_vesa_device =
+ svga_device(vesa_procs, "vesa", vesa_get_mode, vesa_set_mode, vesa_set_page);
+
+/* Define the structures for information returned by the BIOS. */
+#define bits_include(a, m) !(~(a) & (m))
+/* Information about the BIOS capabilities. */
+typedef struct {
+ byte vesa_signature[4]; /* "VESA" */
+ ushort vesa_version;
+ char *product_info; /* product name string */
+ byte capabilities[4]; /* (undefined) */
+ ushort *mode_list; /* supported video modes, -1 ends */
+} vga_bios_info;
+/* Information about an individual VESA mode. */
+typedef enum {
+ m_supported = 1,
+ m_graphics = 0x10
+} mode_attribute;
+typedef enum {
+ w_supported = 1,
+ w_readable = 2,
+ w_writable = 4
+} win_attribute;
+typedef struct {
+ ushort mode_attributes;
+ byte win_a_attributes;
+ byte win_b_attributes;
+ ushort win_granularity;
+ ushort win_size;
+ ushort win_a_segment;
+ ushort win_b_segment;
+ void (*win_func_ptr)(P2(int, int));
+ ushort bytes_per_line;
+ /* Optional information */
+ ushort x_resolution;
+ ushort y_resolution;
+ byte x_char_size;
+ byte y_char_size;
+ byte number_of_planes;
+ byte bits_per_pixel;
+ byte number_of_banks;
+ byte memory_model;
+ byte bank_size;
+ /* Padding to 256 bytes */
+ byte _padding[256-29];
+} vesa_info;
+
+/* Read the device mode */
+int
+vesa_get_mode(void)
+{ registers regs;
+ regs.h.ah = 0x4f;
+ regs.h.al = 0x03;
+ int86(0x10, &regs, &regs);
+ return regs.rshort.bx;
+}
+
+/* Set the device mode */
+void
+vesa_set_mode(int mode)
+{ registers regs;
+ regs.h.ah = 0x4f;
+ regs.h.al = 0x02;
+ regs.rshort.bx = mode;
+ int86(0x10, &regs, &regs);
+}
+
+/* Read information about a device mode */
+private int
+vesa_get_info(int mode, vesa_info _ss *info)
+{ registers regs;
+ struct SREGS sregs;
+ regs.h.ah = 0x4f;
+ regs.h.al = 0x01;
+ regs.rshort.cx = mode;
+ segread(&sregs);
+ sregs.es = sregs.ss;
+ regs.rshort.di = PTR_OFF(info);
+ int86x(0x10, &regs, &regs, &sregs);
+#ifdef DEBUG
+ if ( regs.h.ah == 0 && regs.h.al == 0x4f )
+ dprintf8("vesa_get_info(%x): ma=%x wa=%x/%x wg=%x ws=%x wseg=%x/%x\n",
+ mode, info->mode_attributes,
+ info->win_a_attributes, info->win_b_attributes,
+ info->win_granularity, info->win_size,
+ info->win_a_segment, info->win_b_segment);
+ else
+ dprintf3("vesa_get_info(%x) failed: ah=%x al=%x\n",
+ mode, regs.h.ah, regs.h.al);
+#endif
+ return (regs.h.ah == 0 && regs.h.al == 0x4f ? 0 : -1);
+}
+
+/* Initialize the graphics mode. */
+/* Shared routine to look up a VESA-compatible BIOS mode. */
+private int
+vesa_find_mode(gx_device *dev, const mode_info _ds *mode_table)
+{ /* Select the proper video mode */
+ vesa_info info;
+ const mode_info _ds *mip;
+ for ( mip = mode_table; mip->mode >= 0; mip++ )
+ { if ( mip->width >= fb_dev->width &&
+ mip->height >= fb_dev->height &&
+ vesa_get_info(mip->mode, &info) >= 0 &&
+ bits_include(info.mode_attributes,
+ m_supported | m_graphics) &&
+ info.win_granularity <= 64 &&
+ (info.win_granularity & (info.win_granularity - 1)) == 0 &&
+ info.win_size == 64 &&
+ bits_include(info.win_a_attributes,
+ w_supported) &&
+ info.win_a_segment == regen
+ )
+ { /* Make sure we can both read & write. */
+ /* Initialize for the default case. */
+ fb_dev->wnum_read = 0;
+ fb_dev->wnum_write = 0;
+ if ( bits_include(info.win_a_attributes,
+ w_readable | w_writable)
+ )
+ break;
+ else if ( info.win_b_segment == regen &&
+ bits_include(info.win_b_attributes,
+ w_supported) &&
+ bits_include(info.win_a_attributes |
+ info.win_b_attributes,
+ w_readable | w_writable)
+ )
+ { /* Two superimposed windows. */
+ if ( !bits_include(info.win_a_attributes,
+ w_writable)
+ )
+ fb_dev->wnum_write = 1;
+ else
+ fb_dev->wnum_read = 1;
+ }
+ break;
+ }
+ }
+ if ( mip->mode < 0 )
+ return_error(gs_error_rangecheck); /* mode not available */
+ fb_dev->mode = mip;
+ gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
+ fb_dev->info.vesa.bios_set_page = info.win_func_ptr;
+ fb_dev->info.vesa.pn_shift = small_exact_log2(64 / info.win_granularity);
+ /* Reset the raster per the VESA info. */
+ fb_dev->raster = info.bytes_per_line;
+ return 0;
+}
+private int
+vesa_open(gx_device *dev)
+{ static const mode_info mode_table[] = {
+ { 640, 400, 0x100 },
+ { 640, 480, 0x101 },
+ { 800, 600, 0x103 },
+ { 1024, 768, 0x105 },
+ { 1280, 1024, 0x107 },
+ { -1, -1, -1 }
+ };
+ int code = vesa_find_mode(dev, mode_table);
+ if ( code < 0 ) return code;
+ return svga_open(dev);
+}
+
+/* Set the current display page. */
+private void
+vesa_set_page(gx_device_svga *dev, int pn, int wnum)
+{
+#if USE_ASM
+extern void vesa_call_set_page(P3(void (*)(P2(int, int)), int, int));
+ if ( dev->info.vesa.bios_set_page != NULL )
+ vesa_call_set_page(dev->info.vesa.bios_set_page, pn << dev->info.vesa.pn_shift, wnum);
+ else
+#endif
+ { registers regs;
+ regs.rshort.dx = pn << dev->info.vesa.pn_shift;
+ regs.h.ah = 0x4f;
+ regs.h.al = 5;
+ regs.rshort.bx = wnum;
+ int86(0x10, &regs, &regs);
+ }
+}
+
+/* ------ The ATI Wonder device ------ */
+
+private dev_proc_open_device(atiw_open);
+private gx_device_procs atiw_procs = svga_procs(atiw_open);
+private int atiw_get_mode(P0());
+private void atiw_set_mode(P1(int));
+private void atiw_set_page(P3(gx_device_svga *, int, int));
+gx_device_svga far_data gs_atiw_device =
+ svga_device(atiw_procs, "atiw", atiw_get_mode, atiw_set_mode, atiw_set_page);
+
+/* Read the device mode */
+private int
+atiw_get_mode(void)
+{ registers regs;
+ regs.h.ah = 0xf;
+ int86(0x10, &regs, &regs);
+ return regs.h.al;
+}
+
+/* Set the device mode */
+private void
+atiw_set_mode(int mode)
+{ registers regs;
+ regs.h.ah = 0;
+ regs.h.al = mode;
+ int86(0x10, &regs, &regs);
+}
+
+/* Initialize the graphics mode. */
+private int
+atiw_open(gx_device *dev)
+{ /* Select the proper video mode */
+ { static const mode_info mode_table[] = {
+ { 640, 400, 0x61 },
+ { 640, 480, 0x62 },
+ { 800, 600, 0x63 },
+ { 1024, 768, 0x64 },
+ { -1, -1, -1 }
+ };
+ int code = svga_find_mode(dev, mode_table);
+ if ( code < 0 ) return code; /* mode not available */
+ fb_dev->info.atiw.select_reg = *(int *)MK_PTR(0xc000, 0x10);
+ return svga_open(dev);
+ }
+}
+
+/* Set the current display page. */
+private void
+atiw_set_page(gx_device_svga *dev, int pn, int wnum)
+{ int select_reg = dev->info.atiw.select_reg;
+ byte reg;
+ disable();
+ outportb(select_reg, 0xb2);
+ reg = inportb(select_reg + 1);
+ outportb(select_reg, 0xb2);
+ outportb(select_reg + 1, (reg & 0xe1) + (pn << 1));
+ enable();
+}
+
+/* ------ The Trident device ------ */
+
+private dev_proc_open_device(tvga_open);
+private gx_device_procs tvga_procs = svga_procs(tvga_open);
+/* We can use the atiw_get/set_mode procedures. */
+private void tvga_set_page(P3(gx_device_svga *, int, int));
+gx_device_svga far_data gs_tvga_device =
+ svga_device(tvga_procs, "tvga", atiw_get_mode, atiw_set_mode, tvga_set_page);
+
+/* Initialize the graphics mode. */
+private int
+tvga_open(gx_device *dev)
+{ fb_dev->wnum_read = 1;
+ fb_dev->wnum_write = 0;
+ /* Select the proper video mode */
+ { static const mode_info mode_table[] = {
+ { 640, 400, 0x5c },
+ { 640, 480, 0x5d },
+ { 800, 600, 0x5e },
+ { 1024, 768, 0x62 },
+ { -1, -1, -1 }
+ };
+ int code = svga_find_mode(dev, mode_table);
+ if ( code < 0 ) return code; /* mode not available */
+ return svga_open(dev);
+ }
+}
+
+/* Set the current display page. */
+private void
+tvga_set_page(gx_device_svga *dev, int pn, int wnum)
+{
+ /* new mode */
+ outportb(0x3c4, 0x0b);
+ inportb(0x3c4);
+
+ outportb(0x3c4, 0x0e);
+ outportb(0x3c5, pn ^ 2);
+}
+
+/* ------ The Tseng Labs ET3000/4000 devices ------ */
+
+private dev_proc_open_device(tseng_open);
+private gx_device_procs tseng_procs =
+ svga_procs(tseng_open);
+/* We can use the atiw_get/set_mode procedures. */
+private void tseng_set_page(P3(gx_device_svga *, int, int));
+
+/* The 256-color Tseng device */
+gx_device_svga far_data gs_tseng_device =
+ svga_device(tseng_procs, "tseng", atiw_get_mode, atiw_set_mode, tseng_set_page);
+
+/* Initialize the graphics mode. */
+private int
+tseng_open(gx_device *dev)
+{ fb_dev->wnum_read = 1;
+ fb_dev->wnum_write = 0;
+ /* Select the proper video mode */
+ { static const mode_info mode_table[] = {
+ { 640, 350, 0x2d },
+ { 640, 480, 0x2e },
+ { 800, 600, 0x30 },
+ { 1024, 768, 0x38 },
+ { -1, -1, -1 }
+ };
+ int code = svga_find_mode(dev, mode_table);
+ volatile_fb_ptr p0 = (volatile_fb_ptr)MK_PTR(regen, 0);
+ if ( code < 0 ) return code; /* mode not available */
+ code = svga_open(dev);
+ if ( code < 0 ) return 0;
+ /* Figure out whether we have an ET3000 or an ET4000 */
+ /* by playing with the segment register. */
+ outportb(0x3cd, 0x44);
+ *p0 = 4; /* byte 0, page 4 */
+ outportb(0x3cd, 0x40);
+ *p0 = 3; /* byte 0, page 0 */
+ fb_dev->info.tseng.et_model = *p0;
+ /* read page 0 if ET3000, */
+ /* page 4 if ET4000 */
+ return 0;
+ }
+}
+
+/* Set the current display page. */
+private void
+tseng_set_page(gx_device_svga *dev, int pn, int wnum)
+{ /* The ET3000 has read page = 5:3, write page = 2:0; */
+ /* the ET4000 has read page = 7:4, write page = 3:0. */
+ int shift = dev->info.tseng.et_model;
+ int mask = (1 << shift) - 1;
+ if ( wnum ) pn <<= shift, mask <<= shift;
+ outportb(0x3cd, (inportb(0x3cd) & ~mask) + pn);
+}
+
+/* ------ The Avance Logic device (mostly experimental) ------ */
+/* For questions about this device, please contact Stefan Freund */
+/* <freund@ikp.uni-koeln.de>. */
+
+private dev_proc_open_device(ali_open);
+private gx_device_procs ali_procs = svga_procs(ali_open);
+/* We can use the atiw_get/set_mode procedures. */
+private void ali_set_page(P3(gx_device_svga *, int, int));
+
+/* The 256-color Avance Logic device */
+gx_device_svga gs_ali_device =
+ svga_device(ali_procs, "ali", atiw_get_mode, atiw_set_mode,
+ali_set_page);
+
+/* Initialize the graphics mode. */
+private int
+ali_open(gx_device *dev)
+{ fb_dev->wnum_read = 1;
+ fb_dev->wnum_write = 0;
+ /* Select the proper video mode */
+ { static const mode_info mode_table[] = {
+ { 640, 400, 0x29 },
+ { 640, 480, 0x2a },
+ { 800, 600, 0x2c },
+ { 1024, 768, 0x31 },
+ { -1, -1, -1 }
+ };
+ int code = svga_find_mode(dev, mode_table);
+ if ( code < 0 ) return code; /* mode not available */
+ return svga_open(dev);
+ }
+
+}
+
+/* Set the current display page. */
+private void
+ali_set_page(gx_device_svga *dev, int pn, int wnum)
+{
+ outportb(0x3d6, pn); /* read */
+ outportb(0x3d7, pn); /* write */
+}
diff --git a/gs/src/gdevsvga.h b/gs/src/gdevsvga.h
new file mode 100644
index 000000000..badaa8533
--- /dev/null
+++ b/gs/src/gdevsvga.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevsvga.h */
+/* SuperVGA display definitions */
+/* Requires gdevpcfb.h */
+
+/* Common procedures */
+
+ /* See gxdevice.h for the definitions of the procedures. */
+
+dev_proc_close_device(svga_close);
+dev_proc_map_rgb_color(svga_map_rgb_color);
+dev_proc_map_color_rgb(svga_map_color_rgb);
+dev_proc_fill_rectangle(svga_fill_rectangle);
+dev_proc_copy_mono(svga_copy_mono);
+dev_proc_copy_color(svga_copy_color);
+dev_proc_get_params(svga_get_params);
+dev_proc_put_params(svga_put_params);
+dev_proc_get_bits(svga_get_bits);
+dev_proc_get_alpha_bits(svga_get_alpha_bits);
+dev_proc_copy_alpha(svga_copy_alpha);
+
+/* Table structure for looking up graphics modes. */
+typedef struct {
+ int width, height; /* "key" */
+ int mode; /* "value" */
+} mode_info;
+
+/* The device descriptor structure */
+typedef struct gx_device_svga_s gx_device_svga;
+struct gx_device_svga_s {
+ gx_device_common;
+ int (*get_mode)(P0());
+ void (*set_mode)(P1(int));
+ void (*set_page)(P3(gx_device_svga *fbdev, int pnum, int wnum));
+ bool fixed_colors; /* if true, used a fixed palette */
+ int alpha_text, alpha_graphics; /* if >1, map alpha to saturation */
+ const mode_info _ds *mode; /* BIOS display mode info */
+ uint raster; /* frame buffer bytes per line */
+ int current_page; /* current page */
+ int wnum_read, wnum_write; /* window #s for read vs. write */
+ /* Following are device-specific. */
+ union {
+ struct {
+ void (*bios_set_page)(P2(int, int)); /* set-page function */
+ int pn_shift; /* log2(64K/granularity) */
+ } vesa;
+ struct {
+ int select_reg; /* page-select register */
+ } atiw;
+ struct {
+ int et_model; /* 4 for ET4000, */
+ /* 3 for ET3000 */
+ } tseng;
+ } info;
+};
+
+/* The initial parameters map an appropriate fraction of */
+/* the screen to a full-page coordinate space. */
+/* This may or may not be what is desired! */
+#define svga_color_device(procs, name, depth, maxv, dither, get_mode, set_mode, set_page) {\
+ std_device_color_body(gx_device_svga, &procs, name,\
+ 640, 480,\
+ 480 / PAGE_HEIGHT_INCHES, 480 / PAGE_HEIGHT_INCHES,\
+ /*dci_color(*/depth, maxv, dither/*)*/),\
+ { 0 }, /* std_procs */\
+ get_mode, set_mode, set_page,\
+ 0 /*fixed_colors*/, 1 /*alpha_text*/, 1 /*alpha_graphics*/\
+ }
+#define svga_device(procs, name, get_mode, set_mode, set_page)\
+ svga_color_device(procs, name, 8, 31, 4, get_mode, set_mode, set_page)
+
+/* Utility procedures */
+void svga_init_colors(P1(gx_device *));
+int svga_find_mode(P2(gx_device *, const mode_info _ds *));
+int svga_open(P1(gx_device *));
diff --git a/gs/src/gdevtfax.c b/gs/src/gdevtfax.c
new file mode 100644
index 000000000..9f8892ee2
--- /dev/null
+++ b/gs/src/gdevtfax.c
@@ -0,0 +1,424 @@
+/* Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevtfax.c */
+/* TIFF and fax devices */
+#include "gdevprn.h"
+#include "gdevtifs.h" /* for TIFF output only */
+#include "strimpl.h"
+#include "scfx.h"
+
+/* Define the device parameters. */
+#define X_DPI 204
+#define Y_DPI 196
+#define LINE_SIZE ((X_DPI * 101 / 10 + 7) / 8) /* max bytes per line */
+
+/* The device descriptors */
+
+dev_proc_open_device(gdev_fax_open);
+private dev_proc_print_page(faxg3_print_page);
+private dev_proc_print_page(faxg32d_print_page);
+private dev_proc_print_page(faxg4_print_page);
+private dev_proc_print_page(tiffcrle_print_page);
+private dev_proc_print_page(tiffg3_print_page);
+private dev_proc_print_page(tiffg32d_print_page);
+private dev_proc_print_page(tiffg4_print_page);
+
+struct gx_device_tfax_s {
+ gx_device_common;
+ gx_prn_device_common;
+ gdev_tiff_state tiff; /* for TIFF output only */
+};
+typedef struct gx_device_tfax_s gx_device_tfax;
+
+#define tfdev ((gx_device_tfax *)dev)
+
+/* Define procedures that adjust the paper size. */
+private gx_device_procs gdev_fax_std_procs =
+ prn_procs(gdev_fax_open, gdev_prn_output_page, gdev_prn_close);
+
+gx_device_tfax far_data gs_faxg3_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "faxg3",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, faxg3_print_page)
+};
+
+gx_device_tfax far_data gs_faxg32d_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "faxg32d",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, faxg32d_print_page)
+};
+
+gx_device_tfax far_data gs_faxg4_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "faxg4",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, faxg4_print_page)
+};
+
+gx_device_tfax far_data gs_tiffcrle_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "tiffcrle",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tiffcrle_print_page)
+};
+
+gx_device_tfax far_data gs_tiffg3_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "tiffg3",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tiffg3_print_page)
+};
+
+gx_device_tfax far_data gs_tiffg32d_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "tiffg32d",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tiffg32d_print_page)
+};
+
+gx_device_tfax far_data gs_tiffg4_device =
+{ prn_device_std_body(gx_device_tfax, gdev_fax_std_procs, "tiffg4",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tiffg4_print_page)
+};
+
+/* Open the device, adjusting the paper size. */
+int
+gdev_fax_open(gx_device *dev)
+{ if ( dev->width >= 1680 && dev->width <= 1736 )
+ { /* Adjust width for A4 paper. */
+ dev->width = 1728;
+ }
+ else if ( dev->width >= 2000 && dev->width <= 2056 )
+ { /* Adjust width for B4 paper. */
+ dev->width = 2048;
+ }
+ return gdev_prn_open(dev);
+}
+
+/* Initialize the stream state with a set of default parameters. */
+/* These select the same defaults as the CCITTFaxEncode filter, */
+/* except we set BlackIs1 = true. */
+void
+gdev_fax_init_state(stream_CFE_state *ss, const gx_device_printer *pdev)
+{ (*s_CFE_template.set_defaults)((stream_state *)ss);
+ ss->Columns = pdev->width;
+ ss->Rows = pdev->height;
+ ss->BlackIs1 = true;
+}
+
+/* Send the page to the printer. */
+int
+gdev_stream_print_page(gx_device_printer *pdev, FILE *prn_stream,
+ const stream_template _ds *temp, stream_state *ss)
+{ gs_memory_t *mem = &gs_memory_default;
+ int code;
+ stream_cursor_read r;
+ stream_cursor_write w;
+ int in_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ int lnum;
+ byte *in;
+ byte *out;
+ /* If the file is 'nul', don't even do the writes. */
+ bool nul = !strcmp(pdev->fname, "nul");
+
+ /* Initialize the common part of the encoder state. */
+ ss->template = temp;
+ ss->memory = mem;
+ /* Now initialize the encoder. */
+ code = (*temp->init)(ss);
+ if ( code < 0 )
+ return_error(gs_error_limitcheck); /* bogus, but as good as any */
+
+ /* Allocate the buffers. */
+ in = gs_alloc_bytes(mem, temp->min_in_size + in_size + 1, "gdev_stream_print_page(in)");
+#define out_size 1000
+ out = gs_alloc_bytes(mem, out_size, "gdev_stream_print_page(out)");
+ if ( in == 0 || out == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+
+ /* Set up the processing loop. */
+ lnum = 0;
+ r.ptr = r.limit = in - 1;
+ w.ptr = out - 1;
+ w.limit = w.ptr + out_size;
+
+ /* Process the image. */
+ for ( ; ; )
+ { int status;
+ if_debug7('w', "[w]lnum=%d r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", lnum,
+ (ulong)in, (ulong)r.ptr, (ulong)r.limit,
+ (ulong)out, (ulong)w.ptr, (ulong)w.limit);
+ status = (*temp->process)(ss, &r, &w, lnum == pdev->height);
+ if_debug7('w', "...%d, r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", status,
+ (ulong)in, (ulong)r.ptr, (ulong)r.limit,
+ (ulong)out, (ulong)w.ptr, (ulong)w.limit);
+ switch ( status )
+ {
+ case 0: /* need more input data */
+ { uint left;
+ if ( lnum == pdev->height )
+ goto ok;
+ left = r.limit - r.ptr;
+ memcpy(in, r.ptr + 1, left);
+ gdev_prn_copy_scan_lines(pdev, lnum++, in + left, in_size);
+ r.limit = in + left + in_size - 1;
+ r.ptr = in - 1;
+ } break;
+ case 1: /* need to write output */
+ if ( !nul )
+ fwrite(out, 1, w.ptr + 1 - out, prn_stream);
+ w.ptr = out - 1;
+ break;
+ }
+ }
+
+ok:
+ /* Write out any remaining output. */
+ if ( !nul )
+ fwrite(out, 1, w.ptr + 1 - out, prn_stream);
+
+done:
+ gs_free_object(mem, out, "gdev_stream_print_page(out)");
+ gs_free_object(mem, in, "gdev_stream_print_page(in)");
+ if ( temp->release != 0 )
+ (*temp->release)(ss);
+ return code;
+}
+/* Print a fax page. Other fax drivers use this. */
+int
+gdev_fax_print_page(gx_device_printer *pdev, FILE *prn_stream,
+ stream_CFE_state *ss)
+{ return gdev_stream_print_page(pdev, prn_stream, &s_CFE_template,
+ (stream_state *)ss);
+}
+
+/* Print a 1-D Group 3 page. */
+private int
+faxg3_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ stream_CFE_state state;
+ gdev_fax_init_state(&state, pdev);
+ state.EndOfLine = true;
+ state.EndOfBlock = false;
+ return gdev_fax_print_page(pdev, prn_stream, &state);
+}
+
+/* Print a 2-D Group 3 page. */
+private int
+faxg32d_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ stream_CFE_state state;
+ gdev_fax_init_state(&state, pdev);
+ state.K = (pdev->y_pixels_per_inch < 100 ? 2 : 4);
+ state.EndOfLine = true;
+ state.EndOfBlock = false;
+ return gdev_fax_print_page(pdev, prn_stream, &state);
+}
+
+/* Print a Group 4 page. */
+private int
+faxg4_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{ stream_CFE_state state;
+ gdev_fax_init_state(&state, pdev);
+ state.K = -1;
+ state.EndOfBlock = false;
+ return gdev_fax_print_page(pdev, prn_stream, &state);
+}
+
+/* ---------------- TIFF output ---------------- */
+
+#include "slzwx.h"
+#include "srlx.h"
+
+/* Device descriptors for TIFF formats other than fax. */
+private dev_proc_print_page(tifflzw_print_page);
+private dev_proc_print_page(tiffpack_print_page);
+
+gx_device_tfax far_data gs_tifflzw_device =
+{ prn_device_std_body(gx_device_tfax, prn_std_procs, "tifflzw",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tifflzw_print_page)
+};
+
+gx_device_tfax far_data gs_tiffpack_device =
+{ prn_device_std_body(gx_device_tfax, prn_std_procs, "tiffpack",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0,0,0,0, /* margins */
+ 1, tiffpack_print_page)
+};
+
+/* Define the TIFF directory we use, beyond the standard entries. */
+/* NB: this array is sorted by tag number (assumed below) */
+typedef struct tiff_mono_directory_s {
+ TIFF_dir_entry BitsPerSample;
+ TIFF_dir_entry Compression;
+ TIFF_dir_entry Photometric;
+ TIFF_dir_entry FillOrder;
+ TIFF_dir_entry SamplesPerPixel;
+ TIFF_dir_entry T4T6Options;
+ TIFF_dir_entry CleanFaxData;
+} tiff_mono_directory;
+private const tiff_mono_directory far_data dir_mono_template = {
+ { TIFFTAG_BitsPerSample, TIFF_SHORT, 1, 1 },
+ { TIFFTAG_Compression, TIFF_SHORT, 1, Compression_CCITT_T4 },
+ { TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_min_is_white },
+ { TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_LSB2MSB },
+ { TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 1 },
+ { TIFFTAG_T4Options, TIFF_LONG, 1, 0 },
+ { TIFFTAG_CleanFaxData, TIFF_SHORT, 1, CleanFaxData_clean },
+};
+
+/* Forward references */
+private int tfax_begin_page(P3(gx_device_tfax *, FILE *, const tiff_mono_directory *));
+
+/* Print a fax-encoded page. */
+private int
+tifff_print_page(gx_device_printer *dev, FILE *prn_stream,
+ stream_CFE_state *pstate, tiff_mono_directory *pdir)
+{ int code;
+
+ tfax_begin_page(tfdev, prn_stream, pdir);
+ pstate->FirstBitLowOrder = true; /* decoders prefer this */
+ code = gdev_fax_print_page(dev, prn_stream, pstate);
+ gdev_tiff_end_page(&tfdev->tiff, prn_stream);
+ return code;
+}
+private int
+tiffcrle_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ stream_CFE_state state;
+ tiff_mono_directory dir;
+
+ gdev_fax_init_state(&state, dev);
+ state.EndOfLine = false;
+ state.EncodedByteAlign = true;
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_CCITT_RLE;
+ dir.T4T6Options.tag = TIFFTAG_T4Options;
+ dir.T4T6Options.value = T4Options_fill_bits;
+ return tifff_print_page(dev, prn_stream, &state, &dir);
+}
+private int
+tiffg3_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ stream_CFE_state state;
+ tiff_mono_directory dir;
+
+ gdev_fax_init_state(&state, dev);
+ state.EndOfLine = true;
+ state.EncodedByteAlign = true;
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_CCITT_T4;
+ dir.T4T6Options.tag = TIFFTAG_T4Options;
+ dir.T4T6Options.value = T4Options_fill_bits;
+ return tifff_print_page(dev, prn_stream, &state, &dir);
+}
+private int
+tiffg32d_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ stream_CFE_state state;
+ tiff_mono_directory dir;
+
+ gdev_fax_init_state(&state, dev);
+ state.K = (dev->y_pixels_per_inch < 100 ? 2 : 4);
+ state.EndOfLine = true;
+ state.EncodedByteAlign = true;
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_CCITT_T4;
+ dir.T4T6Options.tag = TIFFTAG_T4Options;
+ dir.T4T6Options.value = T4Options_2D_encoding | T4Options_fill_bits;
+ return tifff_print_page(dev, prn_stream, &state, &dir);
+}
+private int
+tiffg4_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ stream_CFE_state state;
+ tiff_mono_directory dir;
+
+ gdev_fax_init_state(&state, dev);
+ state.K = -1;
+ /*state.EncodedByteAlign = false;*/ /* no fill_bits option for T6 */
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_CCITT_T6;
+ dir.T4T6Options.tag = TIFFTAG_T6Options;
+ return tifff_print_page(dev, prn_stream, &state, &dir);
+}
+
+/* Print an LZW page. */
+private int
+tifflzw_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ tiff_mono_directory dir;
+ stream_LZW_state state;
+ int code;
+
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_LZW;
+ dir.FillOrder.value = FillOrder_MSB2LSB;
+ tfax_begin_page(tfdev, prn_stream, &dir);
+ state.InitialCodeLength = 8;
+ state.FirstBitLowOrder = false;
+ state.BlockData = false;
+ state.EarlyChange = 0; /****** CHECK THIS ******/
+ code = gdev_stream_print_page(dev, prn_stream, &s_LZWE_template,
+ (stream_state *)&state);
+ gdev_tiff_end_page(&tfdev->tiff, prn_stream);
+ return code;
+}
+
+/* Print a PackBits page. */
+private int
+tiffpack_print_page(gx_device_printer *dev, FILE *prn_stream)
+{ tiff_mono_directory dir;
+ stream_RLE_state state;
+ int code;
+
+ dir = dir_mono_template;
+ dir.Compression.value = Compression_PackBits;
+ dir.FillOrder.value = FillOrder_MSB2LSB;
+ tfax_begin_page(tfdev, prn_stream, &dir);
+ state.EndOfData = false;
+ state.record_size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
+ code = gdev_stream_print_page(dev, prn_stream, &s_RLE_template,
+ (stream_state *)&state);
+ gdev_tiff_end_page(&tfdev->tiff, prn_stream);
+ return code;
+}
+
+#undef tfdev
+
+/* Begin a TIFF fax page. */
+private int
+tfax_begin_page(gx_device_tfax *tfdev, FILE *fp,
+ const tiff_mono_directory *pdir)
+{ return gdev_tiff_begin_page((gx_device_printer *)tfdev,
+ &tfdev->tiff, fp,
+ (const TIFF_dir_entry *)pdir,
+ sizeof(*pdir) / sizeof(TIFF_dir_entry),
+ NULL, 0);
+}
diff --git a/gs/src/gdevtfnx.c b/gs/src/gdevtfnx.c
new file mode 100644
index 000000000..6aad3d816
--- /dev/null
+++ b/gs/src/gdevtfnx.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevtfnx.c */
+/* 12-bit & 24-bit RGB uncompressed TIFF driver */
+#include "gdevprn.h"
+#include "gdevtifs.h"
+
+/*
+ * Thanks to Alan Barclay <alan@escribe.co.uk> for donating the original
+ * version of this code to Ghostscript.
+ */
+
+/* ------ The device descriptors ------ */
+
+/* Default X and Y resolution */
+#define X_DPI 72
+#define Y_DPI 72
+
+typedef struct gx_device_tiff_s {
+ gx_device_common;
+ gx_prn_device_common;
+ gdev_tiff_state tiff;
+} gx_device_tiff;
+
+private dev_proc_print_page(tiff12_print_page);
+private dev_proc_print_page(tiff24_print_page);
+
+private gx_device_procs tiff12_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+private gx_device_procs tiff24_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+
+gx_device_printer far_data gs_tiff12nc_device =
+{ prn_device_std_body(gx_device_tiff, tiff12_procs, "tiff12nc",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0,
+ 24, tiff12_print_page)
+};
+
+gx_device_printer far_data gs_tiff24nc_device =
+{ prn_device_std_body(gx_device_tiff, tiff24_procs, "tiff24nc",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0,
+ 24, tiff24_print_page)
+};
+
+/* ------ Private definitions ------ */
+
+/* Define our TIFF directory - sorted by tag number */
+typedef struct tiff_rgb_directory_s {
+ TIFF_dir_entry BitsPerSample;
+ TIFF_dir_entry Compression;
+ TIFF_dir_entry Photometric;
+ TIFF_dir_entry FillOrder;
+ TIFF_dir_entry SamplesPerPixel;
+} tiff_rgb_directory;
+typedef struct tiff_rgb_values_s {
+ TIFF_ushort bps[3];
+} tiff_rgb_values;
+
+private const tiff_rgb_directory far_data dir_rgb_template = {
+ /* C's ridiculous rules about & and arrays require bps[0] here: */
+ { TIFFTAG_BitsPerSample, TIFF_SHORT | TIFF_INDIRECT, 3, offset_of(tiff_rgb_values, bps[0]) },
+ { TIFFTAG_Compression, TIFF_SHORT, 1, Compression_none },
+ { TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_RGB },
+ { TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_MSB2LSB },
+ { TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 3 },
+};
+
+private const tiff_rgb_values val_12_template = {
+ { 4, 4, 4 }
+};
+
+private const tiff_rgb_values val_24_template = {
+ { 8, 8, 8 }
+};
+
+/* ------ Private functions ------ */
+
+#define tfdev ((gx_device_tiff *)pdev)
+
+private int
+tiff12_print_page( gx_device_printer *pdev, FILE *file )
+{ int code;
+
+ /* Write the page directory. */
+ code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
+ (const TIFF_dir_entry *)&dir_rgb_template,
+ sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry),
+ (const byte *)&val_12_template,
+ sizeof(val_12_template));
+ if ( code < 0 )
+ return code;
+
+ /* Write the page data. */
+ {
+ int y;
+ int raster = gdev_prn_raster( pdev );
+ byte *line = (byte *)gs_malloc( raster, 1, "tiff12_print_page" );
+ byte *row;
+
+ if ( line == 0 )
+ return_error( gs_error_VMerror );
+
+ for ( y = 0; y < pdev->height; ++y )
+ { const byte *src;
+ byte *dest;
+ int x;
+
+ code = gdev_prn_get_bits( pdev, y, line, &row );
+ if ( code < 0 )
+ break;
+
+ for ( src = row, dest = line, x = 0; x < raster;
+ src += 6, dest += 3, x += 6
+ )
+ {
+ dest[0] = (src[0] & 0xf0) | (src[1] >> 4);
+ dest[1] = (src[2] & 0xf0) | (src[3] >> 4);
+ dest[2] = (src[4] & 0xf0) | (src[5] >> 4);
+ }
+ fwrite( line, 1, dest - line, file );
+ }
+
+ gdev_tiff_end_page( &tfdev->tiff, file );
+ gs_free( line, raster, 1, "tiff12_print_page" );
+ }
+
+ return code;
+}
+
+private int
+tiff24_print_page(gx_device_printer *pdev, FILE *file)
+{ int code;
+
+ /* Write the page directory. */
+ code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
+ (const TIFF_dir_entry *)&dir_rgb_template,
+ sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry),
+ (const byte *)&val_24_template,
+ sizeof(val_24_template));
+ if ( code < 0 )
+ return code;
+
+ /* Write the page data. */
+ { int y;
+ int raster = gdev_prn_raster(pdev);
+ byte *line = (byte *)gs_malloc(raster, 1, "tiff24_print_page");
+ byte *row;
+
+ if ( line == 0 )
+ return_error(gs_error_VMerror);
+ for ( y = 0; y < pdev->height; ++y )
+ { code = gdev_prn_get_bits(pdev, y, line, &row);
+ if ( code < 0 )
+ break;
+ fwrite((char *)row, raster, 1, file);
+ }
+ gdev_tiff_end_page(&tfdev->tiff, file);
+ gs_free(line, raster, 1, "tiff24_print_page");
+ }
+
+ return code;
+}
+
+#undef tfdev
diff --git a/gs/src/gdevtifs.c b/gs/src/gdevtifs.c
new file mode 100644
index 000000000..0e2bc8973
--- /dev/null
+++ b/gs/src/gdevtifs.c
@@ -0,0 +1,238 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevtifs.c */
+/* TIFF-writing substructure */
+#include "stdio_.h"
+#include "time_.h"
+#include "gstypes.h"
+#include "gscdefs.h"
+#include "gdevprn.h"
+#include "gdevtifs.h"
+
+/*
+ * Define the standard contents of a TIFF directory.
+ * Clients may add more items, also sorted in increasing tag order.
+ */
+typedef struct TIFF_std_directory_entries_s {
+ TIFF_dir_entry SubFileType;
+ TIFF_dir_entry ImageWidth;
+ TIFF_dir_entry ImageLength;
+ TIFF_dir_entry StripOffsets;
+ TIFF_dir_entry Orientation;
+ TIFF_dir_entry RowsPerStrip;
+ TIFF_dir_entry StripByteCounts;
+ TIFF_dir_entry XResolution;
+ TIFF_dir_entry YResolution;
+ TIFF_dir_entry PlanarConfig;
+ TIFF_dir_entry ResolutionUnit;
+ TIFF_dir_entry PageNumber;
+ TIFF_dir_entry Software;
+ TIFF_dir_entry DateTime;
+} TIFF_std_directory_entries;
+/* Define values that follow the directory entries. */
+typedef struct TIFF_std_directory_values_s {
+ TIFF_ulong diroff; /* offset to next directory */
+ TIFF_ulong xresValue[2]; /* XResolution indirect value */
+ TIFF_ulong yresValue[2]; /* YResolution indirect value */
+#define maxSoftware 40
+ char softwareValue[maxSoftware]; /* Software indirect value */
+ char dateTimeValue[20]; /* DateTime indirect value */
+} TIFF_std_directory_values;
+private const TIFF_std_directory_entries std_entries_initial = {
+ { TIFFTAG_SubFileType, TIFF_LONG, 1, SubFileType_page },
+ { TIFFTAG_ImageWidth, TIFF_LONG, 1 },
+ { TIFFTAG_ImageLength, TIFF_LONG, 1 },
+ { TIFFTAG_StripOffsets, TIFF_LONG, 1 },
+ { TIFFTAG_Orientation, TIFF_SHORT, 1, Orientation_top_left },
+ { TIFFTAG_RowsPerStrip, TIFF_LONG, 1 },
+ { TIFFTAG_StripByteCounts, TIFF_LONG, 1 },
+ { TIFFTAG_XResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
+ offset_of(TIFF_std_directory_values, xresValue[0]) },
+ { TIFFTAG_YResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
+ offset_of(TIFF_std_directory_values, yresValue[0]) },
+ { TIFFTAG_PlanarConfig, TIFF_SHORT, 1, PlanarConfig_contig },
+ { TIFFTAG_ResolutionUnit, TIFF_SHORT, 1, ResolutionUnit_inch },
+ { TIFFTAG_PageNumber, TIFF_SHORT, 2 },
+ { TIFFTAG_Software, TIFF_ASCII | TIFF_INDIRECT, 0,
+ offset_of(TIFF_std_directory_values, softwareValue[0]) },
+ { TIFFTAG_DateTime, TIFF_ASCII | TIFF_INDIRECT, 20,
+ offset_of(TIFF_std_directory_values, dateTimeValue[0]) }
+};
+private const TIFF_std_directory_values std_values_initial = {
+ 0, { 0, 1 }, { 0, 1 }, { 0 }, { 0, 0 }
+};
+
+/* Fix up tag values on big-endian machines if necessary. */
+#if arch_is_big_endian
+private void
+tiff_fixup_tag(TIFF_dir_entry *dp)
+{ switch ( dp->type )
+ {
+ case TIFF_SHORT: case TIFF_SSHORT:
+ /* We may have two shorts packed into a TIFF_ulong. */
+ dp->value = (dp->value << 16) + (dp->value >> 16); break;
+ case TIFF_BYTE: case TIFF_SBYTE:
+ dp->value <<= 24; break;
+ }
+}
+#else
+# define tiff_fixup_tag(dp) DO_NOTHING
+#endif
+
+/* Begin a TIFF page. */
+int
+gdev_tiff_begin_page(gx_device_printer *pdev, gdev_tiff_state *tifs, FILE *fp,
+ const TIFF_dir_entry *entries, int entry_count,
+ const byte *values, int value_size)
+{ TIFF_std_directory_entries std_entries;
+ const TIFF_dir_entry *pse = (TIFF_dir_entry *)&std_entries;
+ const TIFF_dir_entry *pce;
+ TIFF_dir_entry entry;
+#define std_entry_count\
+ (sizeof(TIFF_std_directory_entries) / sizeof(TIFF_dir_entry))
+ int nse, nce, ntags;
+ TIFF_std_directory_values std_values;
+#define std_value_size sizeof(TIFF_std_directory_values)
+
+ if ( gdev_prn_file_is_new(pdev) )
+ { /* This is a new file; write the TIFF header. */
+ static const TIFF_header hdr =
+ {
+#if arch_is_big_endian
+ TIFF_magic_big_endian,
+#else
+ TIFF_magic_little_endian,
+#endif
+ TIFF_version_value,
+ sizeof(TIFF_header)
+ };
+ fwrite((const char *)&hdr, sizeof(hdr), 1, fp);
+ tifs->prev_dir = 0;
+ }
+ else
+ { /* Patch pointer to this directory from previous. */
+ TIFF_ulong offset = (TIFF_ulong)tifs->dir_off;
+ fseek(fp, tifs->prev_dir, SEEK_SET);
+ fwrite((char *)&offset, sizeof(offset), 1, fp);
+ fseek(fp, tifs->dir_off, SEEK_SET);
+ }
+
+ /* We're going to shuffle the two tag lists together. */
+ /* Both lists are sorted; entries in the client list */
+ /* replace entries with the same tag in the standard list. */
+ for ( ntags = 0, pse = (const TIFF_dir_entry *)&std_entries,
+ nse = std_entry_count, pce = entries, nce = entry_count;
+ nse && nce; ++ntags
+ )
+ { if ( pse->tag < pce->tag ) ++pse, --nse;
+ else if ( pce->tag < pse->tag ) ++pce, --nce;
+ else ++pse, --nse, ++pce, --nce;
+ }
+ ntags += nse + nce;
+ tifs->ntags = ntags;
+ tifs->vsize = std_value_size + value_size;
+
+ /* Write count of tags in directory. */
+ { TIFF_short dircount = ntags;
+ fwrite((char *)&dircount, sizeof(dircount), 1, fp);
+ }
+ tifs->dir_off = ftell(fp);
+
+ /* Fill in standard directory tags. */
+ std_entries = std_entries_initial;
+ std_values = std_values_initial;
+ std_entries.ImageWidth.value = pdev->width;
+ std_entries.ImageLength.value = pdev->height;
+ std_entries.StripOffsets.value =
+ tifs->dir_off + sizeof(TIFF_std_directory_entries) +
+ entry_count * sizeof(TIFF_dir_entry) +
+ sizeof(TIFF_std_directory_values) + value_size;
+ std_entries.RowsPerStrip.value = pdev->height;
+ std_entries.PageNumber.value = (TIFF_ulong)pdev->PageCount;
+ std_values.xresValue[0] = pdev->x_pixels_per_inch;
+ std_values.yresValue[0] = pdev->y_pixels_per_inch;
+ { char revs[10];
+ strncpy(std_values.softwareValue, gs_product, maxSoftware);
+ std_values.softwareValue[maxSoftware - 1] = 0;
+ sprintf(revs, " %1.2f", gs_revision / 100.0);
+ strncat(std_values.softwareValue, revs,
+ maxSoftware - strlen(std_values.softwareValue) - 1);
+ std_entries.Software.count =
+ strlen(std_values.softwareValue) + 1;
+ }
+ { struct tm tms;
+ time_t t;
+ time(&t);
+ tms = *localtime(&t);
+ sprintf(std_values.dateTimeValue,
+ "%04d:%02d:%02d %02d:%02d:%02d",
+ tms.tm_year + 1900, tms.tm_mon, tms.tm_mday,
+ tms.tm_hour, tms.tm_min, tms.tm_sec);
+ }
+
+ /* Write the merged directory. */
+ for ( pse = (const TIFF_dir_entry *)&std_entries,
+ nse = std_entry_count, pce = entries, nce = entry_count;
+ nse || nce;
+ )
+ { bool std;
+ if ( nce == 0 || (nse != 0 && pse->tag < pce->tag) )
+ std = true, entry = *pse++, --nse;
+ else if ( nse == 0 || (nce != 0 && pce->tag < pse->tag) )
+ std = false, entry = *pce++, --nce;
+ else
+ std = false, ++pse, --nse, entry = *pce++, --nce;
+ if ( entry.tag == TIFFTAG_StripByteCounts )
+ tifs->offset_StripByteCounts =
+ (int)(ftell(fp) - tifs->dir_off);
+ tiff_fixup_tag(&entry); /* don't fix up indirects */
+ if ( entry.type & TIFF_INDIRECT )
+ { /* Fix up the offset for an indirect value. */
+ entry.type -= TIFF_INDIRECT;
+ entry.value +=
+ tifs->dir_off + ntags * sizeof(TIFF_dir_entry) +
+ (std ? 0 : std_value_size);
+ }
+ fwrite((char *)&entry, sizeof(entry), 1, fp);
+ }
+
+ /* Write the indirect values. */
+ fwrite((const char *)&std_values, sizeof(std_values), 1, fp);
+ fwrite((const char *)values, value_size, 1, fp);
+
+ return 0;
+}
+
+/* End a TIFF page. */
+int
+gdev_tiff_end_page(gdev_tiff_state *tifs, FILE *fp)
+{ long dir_off = tifs->dir_off;
+ int tags_size = tifs->ntags * sizeof(TIFF_dir_entry);
+ TIFF_ulong cc;
+
+ tifs->prev_dir =
+ dir_off + tags_size + offset_of(TIFF_std_directory_values, diroff);
+ tifs->dir_off = ftell(fp);
+ /* Patch strip byte counts value. */
+ cc = tifs->dir_off - (dir_off + tags_size + tifs->vsize);
+ fseek(fp, dir_off + tifs->offset_StripByteCounts +
+ offset_of(TIFF_dir_entry, value), SEEK_SET);
+ fwrite(&cc, sizeof(cc), 1, fp);
+ return 0;
+}
diff --git a/gs/src/gdevtifs.h b/gs/src/gdevtifs.h
new file mode 100644
index 000000000..4923c9df9
--- /dev/null
+++ b/gs/src/gdevtifs.h
@@ -0,0 +1,206 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevtifs.h */
+/* Definitions for writing TIFF file formats. */
+
+#ifndef gdevtifs_INCLUDED
+# define gdevtifs_INCLUDED
+
+/* ================ TIFF specification ================ */
+
+/* Based on TIFF specification version 6.0 obtained from */
+/* sgi.com:graphics/tiff/TIFF6.ps.Z. */
+
+/*
+ * The sizes of TIFF data types are system-independent. Therefore,
+ * we cannot use short, long, etc., but must use types of known sizes.
+ */
+#if arch_sizeof_short == 2
+typedef short TIFF_short; /* no plausible alternative */
+typedef unsigned short TIFF_ushort;
+#endif
+#if arch_sizeof_int == 4
+typedef int TIFF_long;
+typedef unsigned int TIFF_ulong;
+#else
+# if arch_sizeof_long == 4
+typedef long TIFF_long;
+typedef unsigned long TIFF_ulong;
+# endif
+#endif
+
+/*
+ * Define the TIFF file header.
+ */
+typedef struct TIFF_header_s {
+ TIFF_ushort magic; /* magic number (defines byte order) */
+ TIFF_ushort version; /* TIFF version number */
+ TIFF_ulong diroff; /* byte offset to first directory */
+} TIFF_header;
+
+#define TIFF_magic_big_endian 0x4d4d /* 'MM' */
+#define TIFF_magic_little_endian 0x4949 /* 'II' */
+
+#define TIFF_version_value 42
+
+/*
+ * Define an individual entry in a TIFF directory. Within a directory,
+ * the entries must be sorted by increasing tag value.
+ *
+ * The value field contains either the offset of the field data in the file,
+ * or, if the value fits in 32 bits, the value itself, left-justified.
+ * Field data may appear anywhere in the file, so long as each data block is
+ * aligned on a 32-bit boundary and is disjoint from all other data blocks.
+ */
+typedef struct TIFF_dir_entry_s {
+ TIFF_ushort tag; /* TIFF_tag */
+ TIFF_ushort type; /* TIFF_data_type */
+ TIFF_ulong count; /* number of items (spec calls this 'length') */
+ TIFF_ulong value; /* byte offset to field data, */
+ /* or actual value if <=4 bytes */
+} TIFF_dir_entry;
+
+/*
+ * Define the tag data type values.
+ */
+typedef enum {
+ TIFF_BYTE = 1, /* 8-bit unsigned integer */
+ TIFF_ASCII = 2, /* 8-bit bytes with last byte null */
+ TIFF_SHORT = 3, /* 16-bit unsigned integer */
+ TIFF_LONG = 4, /* 32-bit unsigned integer */
+ TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */
+ /* (ratio of two 32-bit unsigned integers) */
+ TIFF_SBYTE = 6, /* 8-bit signed integer */
+ TIFF_UNDEFINED = 7, /* 8-bit untyped data */
+ TIFF_SSHORT = 8, /* 16-bit signed integer */
+ TIFF_SLONG = 9, /* 32-bit signed integer */
+ TIFF_SRATIONAL = 10, /* 64-bit signed fraction */
+ /* (ratio of two 32-bit signed integers) */
+ TIFF_FLOAT = 11, /* 32-bit IEEE floating point */
+ TIFF_DOUBLE = 12, /* 64-bit IEEE floating point */
+ /* A flag to indicate the value is indirect. */
+ /* This is only used internally; it is not part of the */
+ /* TIFF specification (although it should be!). */
+ TIFF_INDIRECT = 128
+} TIFF_data_type;
+
+/*
+ * Define the tag values we need. Note that this is only a very small subset
+ * of all the values defined in the TIFF specification; we will add more
+ * as the need arises.
+ */
+typedef enum {
+ TIFFTAG_SubFileType = 254, /* subfile data descriptor */
+#define SubFileType_reduced_image 0x1 /* reduced resolution version */
+#define SubFileType_page 0x2 /* one page of many */
+#define SubFileType_mask 0x4 /* transparency mask */
+ TIFFTAG_ImageWidth = 256, /* image width in pixels */
+ TIFFTAG_ImageLength = 257, /* image height in pixels */
+ TIFFTAG_BitsPerSample = 258, /* bits per channel (sample) */
+ TIFFTAG_Compression = 259, /* data compression technique */
+#define Compression_none 1 /* dump mode */
+#define Compression_CCITT_RLE 2 /* CCITT modified Huffman RLE */
+#define Compression_CCITT_T4 3 /* CCITT T.4 fax encoding */
+#define Compression_CCITT_T6 4 /* CCITT T.6 fax encoding */
+#define Compression_LZW 5 /* Lempel-Ziv & Welch */
+#define Compression_JPEG 6 /* !JPEG compression */
+#define Compression_NeXT 32766 /* NeXT 2-bit RLE */
+#define Compression_CCITT_RLEW 32771 /* #1 w/ word alignment */
+#define Compression_PackBits 32773 /* Macintosh RLE */
+#define Compression_Thunderscan 32809 /* ThunderScan RLE */
+ TIFFTAG_Photometric = 262, /* photometric interpretation */
+#define Photometric_min_is_white 0 /* min value is white */
+#define Photometric_min_is_black 1 /* min value is black */
+#define Photometric_RGB 2 /* RGB color model */
+#define Photometric_palette 3 /* color map indexed */
+#define Photometric_mask 4 /* $holdout mask */
+#define Photometric_separated 5 /* !color separations */
+#define Photometric_YCbCr 6 /* !CCIR 601 */
+#define Photometric_CIE_Lab 8 /* !1976 CIE L*a*b* */
+ TIFFTAG_FillOrder = 266, /* data order within a byte */
+#define FillOrder_MSB2LSB 1 /* most significant -> least */
+#define FillOrder_LSB2MSB 2 /* least significant -> most */
+ TIFFTAG_StripOffsets = 273, /* offsets to data strips */
+ TIFFTAG_Orientation = 274, /* +image Orientation */
+#define Orientation_top_left 1 /* row 0 top, col 0 lhs */
+#define Orientation_top_right 2 /* row 0 top, col 0 rhs */
+#define Orientation_bot_right 3 /* row 0 bottom, col 0 rhs */
+#define Orientation_bot_left 4 /* row 0 bottom, col 0 lhs */
+#define Orientation_left_top 5 /* row 0 lhs, col 0 top */
+#define Orientation_right_top 6 /* row 0 rhs, col 0 top */
+#define Orientation_right_bot 7 /* row 0 rhs, col 0 bottom */
+#define Orientation_left_bot 8 /* row 0 lhs, col 0 bottom */
+ TIFFTAG_SamplesPerPixel = 277, /* samples per pixel */
+ TIFFTAG_RowsPerStrip = 278, /* rows per strip of data */
+ TIFFTAG_StripByteCounts = 279, /* bytes counts for strips */
+ TIFFTAG_XResolution = 282, /* pixels/resolution in x */
+ TIFFTAG_YResolution = 283, /* pixels/resolution in y */
+ TIFFTAG_PlanarConfig = 284, /* storage organization */
+#define PlanarConfig_contig 1 /* single image plane */
+#define PlanarConfig_separate 2 /* separate planes of data */
+ TIFFTAG_T4Options = 292, /* 32 flag bits */
+#define T4Options_2D_encoding 0x1 /* 2-dimensional coding */
+#define T4Options_uncompressed 0x2 /* data not compressed */
+#define T4Options_fill_bits 0x4 /* fill to byte boundary */
+ TIFFTAG_T6Options = 293, /* 32 flag bits */
+#define T6Options_uncompressed 0x2 /* data not compressed */
+ TIFFTAG_ResolutionUnit = 296, /* units of resolutions */
+#define ResolutionUnit_none 1 /* no meaningful units */
+#define ResolutionUnit_inch 2 /* english */
+#define ResolutionUnit_centimeter 3 /* metric */
+ TIFFTAG_PageNumber = 297, /* page number if multi-page */
+ TIFFTAG_Software = 305, /* software name & release */
+ TIFFTAG_DateTime = 306, /* creation date and time */
+ TIFFTAG_CleanFaxData = 327 /* regenerated line info */
+#define CleanFaxData_clean 0 /* no errors detected */
+#define CleanFaxData_regenerated 1 /* receiver regenerated lines */
+#define CleanFaxData_unclean 2 /* uncorrected errors exist */
+} TIFF_tag;
+
+/* ================ Implementation ================ */
+
+/*
+ * Define the added driver state for TIFF writing.
+ */
+typedef struct gdev_tiff_state_s {
+ long prev_dir; /* file offset of previous directory offset */
+ long dir_off; /* file offset of next write */
+ int ntags; /* # of tags in directory */
+ int vsize; /* size of values following tags */
+ /* Record offsets of values */
+ int offset_StripByteCounts;
+} gdev_tiff_state;
+
+/*
+ * Begin writing a TIFF page. This procedure supplies a standard set of
+ * tags; the client can provide additional tags (pre-sorted) and
+ * indirect values.
+ */
+int gdev_tiff_begin_page(P7(gx_device_printer *pdev, gdev_tiff_state *tifs,
+ FILE *fp,
+ const TIFF_dir_entry *entries, int entry_count,
+ const byte *values, int value_size));
+
+/*
+ * Finish writing a TIFF page. All data written between begin and end
+ * is considered to be a single strip.
+ */
+int gdev_tiff_end_page(P2(gdev_tiff_state *tifs, FILE *fp));
+
+#endif /* gdevtifs_INCLUDED */
diff --git a/gs/src/gdevtknk.c b/gs/src/gdevtknk.c
new file mode 100644
index 000000000..3693983f7
--- /dev/null
+++ b/gs/src/gdevtknk.c
@@ -0,0 +1,253 @@
+/* Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevtknk.c */
+/*
+ Tektronix Ink-jet plotter driver.
+ This code is written for 4696 and 4695 plotters, it may easily be
+ adopted to the 4393 and 4394 models as well, simply by adding new
+ device descriptors with other geometrical characteristics.
+*/
+#include "gdevprn.h"
+#include "malloc_.h"
+
+/* Thanks to Karsten Spang (spang@nbivax.nbi.dk) for contributing */
+/* this code to Aladdin Enterprises. */
+
+
+/* The device descriptor */
+/* We need our own color mapping procedures. */
+private dev_proc_map_rgb_color(tekink_map_rgb_color);
+private dev_proc_map_color_rgb(tekink_map_color_rgb);
+private dev_proc_print_page(tekink_print_page);
+private gx_device_procs tekink_procs =
+ prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ tekink_map_rgb_color, tekink_map_color_rgb);
+
+
+/*
+ Device descriptor for the Tek 4696.
+ The 4696 plotter uses roll media, thus the y size is arbitrary. The
+ value below is chosen to make the image area A*-format like, i.e. the
+ aspect ratio is close to sqrt(2).
+*/
+gx_device_printer far_data gs_tek4696_device =
+ prn_device(tekink_procs,"tek4696",
+ 85,120, /* Page size in 10th of inches */
+ 120,120, /* Resolution in DPI */
+ 0.0,0.0,0.0,0.0, /* Margins */
+ 4, /* Bits per pixel */
+ tekink_print_page);
+
+/* Color mapping.
+ The tek inkjets use subtractive colors B=0 M=1 Y=2 C=3. These are
+ represented as 4 bits B=1 M=2 Y=4 C=8 in a byte. This gives:
+ White = 0
+ Black = 1
+ Magenta = 2
+ Yellow = 4
+ Red = 6
+ Cyan = 8
+ Blue = 10
+ Green = 12
+ The remaining values are unused. (They give ugly results if sent to the
+ plotter.) Of course this could have been compressed into 3 bits, but
+ as the palette color memory device uses 8 bits anyway, this is easier,
+ and perhaps faster.
+*/
+
+static gx_color_index rgb_to_index[8]={1,6,12,4,10,2,8,0};
+static ushort index_to_rgb[16][3]={
+ {65535,65535,65535}, /* White */
+ {0,0,0}, /* Black */
+ {65535,0,65535}, /* Magenta */
+ {2,2,2}, /* Unused */
+ {65535,65535,0}, /* Yellow */
+ {2,2,2}, /* Unused */
+ {65535,0,0}, /* Red */
+ {2,2,2}, /* Unused */
+ {0,65535,65535}, /* Cyan */
+ {2,2,2}, /* Unused */
+ {0,0,65535}, /* Blue */
+ {2,2,2}, /* Unused */
+ {0,65535,0}, /* Green */
+ {2,2,2}, /* Unused */
+ {2,2,2}, /* Unused */
+ {2,2,2} /* Unused */
+};
+
+/* Map an RGB color to a printer color. */
+private gx_color_index
+tekink_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
+{
+ return(rgb_to_index[(((b>32767) << 2) + ((g>32767) << 1) +
+ (r>32767)) & 7]);
+}
+
+/* Map the printer color back to RGB. */
+private int
+tekink_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
+{
+ register ushort c = (ushort)color;
+ register int i;
+ if (c>15) return -1;
+ if (index_to_rgb[c][0]==2) return -1;
+ for (i=0;i<3;i++){
+ prgb[i]=index_to_rgb[c][i];
+ }
+ return 0;
+}
+
+/* Send the page to the printer. */
+private int
+tekink_print_page(gx_device_printer *pdev,FILE *prn_stream)
+{
+ int line_size,color_line_size,scan_line,num_bytes,scan_lines,color_plane;
+ int roll_paper,out_line,micro_line,pending_micro_lines,line_blank,
+ blank_lines;
+ byte *outdata,*indata1,*bdata1,*mdata1,*ydata1,*cdata1;
+ register byte *indata,*bdatap,*mdatap,*ydatap,*cdatap;
+ register byte bdata,mdata,ydata,cdata;
+ register byte mask,inbyte;
+ register byte *indataend,*outdataend;
+
+ /* Allocate a temporary buffer for color separation.
+ The buffer is partitioned into an input buffer and four
+ output buffers for the color planes. The output buffers
+ are allocated with an extra sentinel byte. */
+
+ line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+ color_line_size=(pdev->width+7)/8;
+ indata1=(byte *)malloc(line_size+4*(color_line_size+1));
+ if (indata1==NULL) return -1;
+ /* pointers to the partions */
+ indataend=indata1+line_size;
+ bdata1=indataend;
+ mdata1=bdata1+(color_line_size+1);
+ ydata1=mdata1+(color_line_size+1);
+ cdata1=ydata1+(color_line_size+1);
+
+ /* Does this device use roll paper? */
+ roll_paper=!strcmp(pdev->dname,"tek4696");
+
+ out_line=0;
+ blank_lines=0;
+ scan_lines=pdev->height;
+ for (scan_line=0;scan_line<scan_lines;scan_line++){
+ /* get data */
+ gdev_prn_copy_scan_lines(pdev,scan_line,indata1,line_size);
+ /* Separate data into color planes */
+ bdatap = bdata1+1;
+ mdatap = mdata1+1;
+ ydatap = ydata1+1;
+ cdatap = cdata1+1;
+ bdata=0;
+ mdata=0;
+ cdata=0;
+ ydata=0;
+ mask=0x80;
+ memset(indataend,0,4*(color_line_size+1));
+ for (indata=indata1;indata<indataend;indata++){
+ inbyte = *indata;
+ if (inbyte&0x01) bdata|=mask;
+ if (inbyte&0x02) mdata|=mask;
+ if (inbyte&0x04) ydata|=mask;
+ if (inbyte&0x08) cdata|=mask;
+ mask>>=1;
+ if (!mask){
+ *(bdatap++) = bdata;
+ *(mdatap++) = mdata;
+ *(cdatap++) = cdata;
+ *(ydatap++) = ydata;
+ bdata=0;
+ mdata=0;
+ cdata=0;
+ ydata=0;
+ mask=0x80;
+ }
+ }
+ if (mask!=0x80){
+ *bdatap = bdata;
+ *mdatap = mdata;
+ *cdatap = cdata;
+ *ydatap = ydata;
+ }
+ line_blank=1;
+ /* Output each of the four color planes */
+ for (color_plane=0;color_plane<4;color_plane++){
+ outdata=indataend+(color_plane*(color_line_size+1));
+ outdataend=outdata+color_line_size;
+
+ /* Remove trailing spaces and output the color line if it is
+ not blank */
+ *outdata=0xff;
+ while (!(*outdataend)) outdataend--;
+ if (num_bytes=(outdataend-outdata)){
+ line_blank=0;
+ /* On encountering the first non-blank data, output pending
+ blank lines */
+ if (blank_lines){
+ pending_micro_lines=((out_line+blank_lines+1)/4)-
+ (out_line/4);
+ for (micro_line=0;micro_line<pending_micro_lines;
+ micro_line++){
+ fputs("\033A",prn_stream);
+ }
+ out_line+=blank_lines;
+ blank_lines=0;
+ }
+ fprintf(prn_stream,"\033I%c%03d",'0'+(out_line%4)+
+ 4*color_plane,num_bytes);
+ fwrite(outdata+1,1,num_bytes,prn_stream);
+ }
+ } /* loop over color planes */
+
+ /* If this line is blank, and if it is a roll paper model,
+ count the line. Otherwise output the line */
+ if (line_blank&&roll_paper){
+ /* Only increment the blank line count, if non blank lines
+ have been encountered previously, i.e. skip leading blank
+ lines. */
+ if (out_line) blank_lines++;
+ }
+ else{
+ if (out_line%4==3){
+ /* Write micro line feed code */
+ fputs("\033A",prn_stream);
+ }
+ out_line++;
+ }
+ } /* loop over scan lines */
+
+ /* if the number of scan lines written is not a multiple of four,
+ write the final micro line feed code */
+ if (out_line%4){
+ fputs("\033A",prn_stream);
+ }
+ /* Separate this plot from the next */
+ if (roll_paper){
+ fputs("\n\n\n\n\n",prn_stream);
+ }
+ else{
+ fputs("\f",prn_stream);
+ }
+
+ /* Deallocate temp buffer */
+ free(indata1);
+ return 0;
+}
diff --git a/gs/src/gdevupd.c b/gs/src/gdevupd.c
new file mode 100644
index 000000000..4df126266
--- /dev/null
+++ b/gs/src/gdevupd.c
@@ -0,0 +1,6269 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevupd.c Revision: 1.77 */
+/* "uniprint" -- Ugly Printer Driver by Gunther Hess (gunther@elmos.de) */
+
+/* Revision-History:
+ 23-Mar-1997 - 1.43: First published version
+ 24-Mar-1997 - 1.44: gs4.03 compatible version on the web
+ 31-Mar-1997 - 1.53: First Version inside gs-fileset (limited)
+ 28-Apr-1997 - 1.54: Version intended for public gs-release
+ 4-May-1997 - 1.55: Deactivated an accidentially active Debug-Option
+ 14-Jun-1997 - 1.56: Bug-Workaround for White on White Printing (gs5.0)
+ 17-Jun-1997 - 1.57: More reasonable Fix for the above Bug
+ ...
+ 7-Jul-1997 - 1.68: NULL-Param-BUG, HR's BJC, Pwidth/-height BUG, YFlip
+ 25-Jul-1997 - 1.69: Bug-Fix: incomplete Change of PHEIGHT-Treatment
+ 4-Aug-1997 - 1.70: Arrgh: still incomplete Change of PHEIGHT-Treatment
+ 17-AUG-1997 - 1.71: Fix of BSD-sprintf bug. (returns char * there)
+ ...
+ 28-Sep-1977 - 1.77: Fixed the byte<>char and casted-lvalue Problems
+*/
+
+/* Canon BJC 610 additions from (hr)
+ Helmut Riegler <helmut-riegler@net4you.co.at>
+
+ The BJC-4000 can be supported very easily, only by creating the right .upp
+ parameter file. If you have this printer and you are willing to do this,
+ contact me, I'll give you the technical details (ESC codes).
+*/
+
+/* ------------------------------------------------------------------- */
+/* Compile-Time-Options */
+/* ------------------------------------------------------------------- */
+
+/**
+There are two compile-time options for this driver:
+ 1. UPD_SIGNAL enables interrupt detection, that aborts printing and
+ 2. UPD_MESSAGES controls the amount of messages generated by the driver
+*/
+
+#ifndef UPD_SIGNAL
+#ifdef __unix__
+#define UPD_SIGNAL 1 /** Activated, if undefined, on UNIX-Systems */
+#else /* !__unix__ */
+#define UPD_SIGNAL 0 /** Inactive on others, by default */
+#endif /* ?__unix__ */
+#endif /* UPD_SIGNAL */
+
+#ifndef UPD_MESSAGES
+#define UPD_MESSAGES UPD_M_ERROR /** Error-messages only, if not defined */
+#endif /* UPD_MESSAGES */
+
+/* ------------------------------------------------------------------- */
+/* Required Header-Files */
+/* ------------------------------------------------------------------- */
+
+#ifndef hess_test_INCLUDED /* A private test-Option */
+
+#include "gdevprn.h" /** Printer-superclass header */
+#include "gsparam.h" /** For the Parameter-Handling (optional) */
+
+#include <stdlib.h> /** for rand */
+#include <limits.h> /** for INT_MIN */
+#include <ctype.h> /** for isupper */
+
+#endif /* hess_test_INCLUDED A private test-Option */
+
+#if UPD_SIGNAL
+#include <signal.h> /** Only included, if UPD_SIGNAL is active (true) */
+#endif /* UPD_SIGNAL */
+
+/* ------------------------------------------------------------------- */
+/* Device-Structure (including an additional Structure-Pointer-Type) */
+/* ------------------------------------------------------------------- */
+
+typedef struct upd_s upd_t,*upd_p; /** Type & Pointer of device-specifics */
+typedef const upd_t *upd_pc; /** Pointer to constant device-specfics */
+
+typedef struct upd_device_s { /** The driver must typedef ... */
+ gx_device_common; /** common fields for all devices */
+ gx_prn_device_common; /** common fields for printing-devices */
+ gs_param_string upd_version; /** Source-Code Version */
+ upd_p upd; /** uniprint-specific extension */
+} upd_device; /** some type usually <name>_device> */
+
+/* ------------------------------------------------------------------- */
+/* Major Driver-Functions */
+/* ------------------------------------------------------------------- */
+
+private dev_proc_print_page(upd_print_page); /** print a page (required) */
+
+private dev_proc_open_device(upd_open); /** device-initialization (opt) */
+private dev_proc_close_device(upd_close); /** device-release (opt) */
+
+private dev_proc_get_params(upd_get_params); /** export parameters (opt) */
+private dev_proc_put_params(upd_put_params); /** import parameters (opt) */
+
+/**
+A `normal' Device-Driver wil only implement one of the following pairs
+of functions for the colormapping. But "uniprint" is something special and
+it really provides all four reasonable pairs and in addition to that
+a fifth set of functions, that delivers better FS-Results with KCMY.
+
+The first pair is for the mapping into a single stored component, that
+usually represents a grayscale. But nevertheless GHOSTSCRIPT deals with
+RGB-Values, but promises to deal with R==G==B-Values when asking to map.
+
+The second pair deals with RGB-Values.
+*/
+
+private dev_proc_map_rgb_color( upd_rgb_1color); /** RGB->Gray-Index */
+private dev_proc_map_color_rgb( upd_1color_rgb); /** Gray-Index->RGB */
+
+private dev_proc_map_rgb_color( upd_rgb_3color); /** RGB->RGB-Index */
+private dev_proc_map_color_rgb( upd_3color_rgb); /** RGB-Index->RGB */
+
+/**
+The third pair maps RGB-Values into four components, which one might
+expect to be KCMY-Values, but they are not: "uniprint" considers this four
+Values as White+RGB Values!
+*/
+
+private dev_proc_map_rgb_color( upd_rgb_4color); /** RGB->WRGB-Index */
+private dev_proc_map_color_rgb(upd_4color_rgb); /** WRGB-Index->RGB */
+
+/**
+Finally the fourth pair deals with KCMY-Values. The Mapping-Function
+is of a different type, due to the additional argument, but the
+inverse-Function is of the same type, and expects RGB-Values to be
+deliverd into the receiving 3-Component-Array!
+*/
+
+private dev_proc_map_cmyk_color(upd_cmyk_icolor); /** KCMY->KCMY-Index */
+private dev_proc_map_color_rgb( upd_icolor_rgb); /** KCMY->RGB-Index */
+
+/**
+The difference between the icolor-pair and the kcolor-pair is the enforced
+black-generation in the forward-mapping. that is taken into account by the
+reverse-mapping too.
+*/
+
+private dev_proc_map_cmyk_color(upd_cmyk_kcolor); /** adds black generation */
+private dev_proc_map_color_rgb( upd_kcolor_rgb); /** watches black-gen */
+
+/**
+For the sake of efficiency there is that bunch of functions and they
+perform no validity checks, thus it has to be assured that they are
+only active, if there is a valid device-structure for then.
+upd_procs_map performs this task.
+*/
+
+private int upd_procs_map( P1(upd_device *udev));
+
+/* ------------------------------------------------------------------- */
+/* Prototype of the Device-Structure (the only thing exported!) */
+/* ------------------------------------------------------------------- */
+
+/**
+"uniprint" needs a procedure-table of its own, since it provides several
+optional procedures. Simpler-Drivers (e.g. non-color-drivers) may use
+prn_std_procs instead of defining their own procedure-table.
+*/
+
+#define upd_set_dev_proc(dev, p, proc) \
+ ((dev)->std_procs.p = (dev)->orig_procs.p = (proc))
+
+private gx_device_procs upd_procs = { /** Table of procedures */
+ upd_open, /** open-function, upd-special */
+ gx_default_get_initial_matrix, /** retrieve matrix */
+ gx_default_sync_output, /** sync display */
+ gdev_prn_output_page, /** superclass-print (calls back) */
+ upd_close, /** close-function, upd-special */
+ gx_default_map_rgb_color, /** RGB-mapping */
+ gx_default_map_color_rgb, /** reverse mapping */
+ NULL, /** fill_rectangle */
+ NULL, /** tile_rectangle */
+ NULL, /** copy_mono */
+ NULL, /** copy_color */
+ NULL, /** draw_line */
+ gx_default_get_bits, /** reads scanlines, e.g. for the driver */
+ upd_get_params, /** Export parameters, upd-special */
+ upd_put_params, /** Import parameters, upd-special */
+ gx_default_map_cmyk_color /** KCMY-mapping */
+}; /** */
+
+/**
+The prototype-instance of the device-structure _must_ have the name
+"gs_uniprint_device", where "uniprint" is the external name of the driver.
+This notice is bluntly copied from drivers.txt, which a potential
+driver-author should carefully read.
+
+Just to mention: this prototype is quite similar to the one, that
+"prn_device" produces and it identifies "uniprint" as a monochrome 1Bit
+device to GHOSTSCRIPT. But during the lifetime of a driver-instance
+this might change.
+
+This is the end of the part of declarations, that are common for
+color-drivers. The next sections address "uniprint"-specific data-types
+and the reader might directly skip to the section titled
+
+ upd_print_page: The main workhorse
+*/
+
+upd_device far_data gs_uniprint_device = { /** */
+ prn_device_body(upd_device, upd_procs, /** The Type and Procedures */
+ "uniprint", /** External name of the Device */
+ DEFAULT_WIDTH_10THS, /** X-Size (1/10") */
+ DEFAULT_HEIGHT_10THS, /** Y-Size (1/10") */
+ 72, 72, /** X,Y-DpI */
+ 0.0, 0.0, 0.0, 0.0, /** L,B,R,T-Margin */
+ 1, /** color_info.num_components 1/3/4 */
+ 1, /** color_info.depth 1/2/4/8/16/24/32 */
+ 1, /** color_info.max_gray # of distinct gray levels -1 (255/1) */
+ 0, /** color_info.max_color # of distinct color levels -1 (255/1/0)*/
+ 1, /** color_info.dither_grays size of gray ramp for dithering (5/2) */
+ 0, /** color_info.dither_colors size of color cube ditto (5/2/0) */
+ upd_print_page), /** Print-procedure */
+ { NULL, 0, true }, /** Driver-Version */
+ NULL /** upd-field: Initially none */
+}; /** */
+
+
+/* ------------------------------------------------------------------- */
+/* UPD-Data- and Prototypes */
+/* ------------------------------------------------------------------- */
+
+/*@ gdevupd.h < */
+/* ------------------------------------------------------------------- */
+/* External names of the UPD-Parameters */
+/* ------------------------------------------------------------------- */
+
+/** UPD-Parameters
+
+"uniprint" supports a hole bunch of external parameters. This Parameters
+fall into the following categories:
+
+ 0. special-string the upd_version, readonly upd_version
+ 1. choice name-indices, stored in upd->choice
+ 2. boolean single bits, stored in upd->flags
+ 3. integers single numbers, stored in upd->ints
+ 4. integer-Arrays arrays of numbers, stored in upd->int_a
+ 5. string device-commands, stored in upd->strings
+ 6. string-Arrays arrayed device-commands, stored in upd->string_a
+ 7. float-Arrays arrays of floats, stored in upd->float_a
+
+Currently there is no need for single floats, but they may be introduced in
+future versions. Since "uniprint" somtimes manipulates the contents of the
+array-variables it dynamically allocates storage for all this parameters.
+
+The following sections defines the names for this parameters in the order,
+they are stored within the mentioned dynamic fields of the upd-structure.
+A NULL-name means that the corresponding parameter is not externally visible.
+Besides the name, there is always a symbolic index #defined, that MUST match
+the Index-Number of the name.
+Actually
+*/
+
+static const char *const upd_version = "upVersion"; /** Readonly Version */
+
+/** Names for the multiple-choice-Parameters
+
+Currently there are three Parameters, that are handled as named choices.
+For each of them, there is an array of constant strings that consists of
+
+1. the Parameter-Name
+2. - n-1 the available choices.
+n. A terminating NULL
+*/
+
+static const char *const upd_mapper[] = { "upColorModel",
+#define MAP_GRAY 1 /** Monochrome & Grayscale Devices */
+"DeviceGray", /** Monochrome & Grayscale Devices */
+#define MAP_RGBW 2 /** RGB with White-Generation */
+"DeviceRGBW", /** RGB with White-Generation */
+#define MAP_RGB 3 /** RGB-Mapping */
+"DeviceRGB", /** RGB-Mapping */
+#define MAP_CMYK 4 /** CMYK-Mapping */
+"DeviceCMYK", /** CMYK-Mapping */
+#define MAP_CMYKGEN 5 /** CMYK-Mapping with Black-Generation */
+"DeviceCMYKgenerate", /** CMYK-Mapping with Black-Generation */
+NULL
+};
+
+static const char *const upd_render[] = { "upRendering",
+#define RND_FSCOMP 1 /** Componentwise Floyd-Steinberg */
+"ErrorDiffusion", /** Componentwise Floyd-Steinberg */
+#define RND_FSCMYK 2 /** CMYK-specialized 32Bit Floyd-Steinberg */
+"FSCMYK32", /** CMYK-specialized 32Bit Floyd-Steinberg */
+NULL
+};
+
+static const char *const upd_format[] = { "upOutputFormat",
+#define FMT_RAS 1 /** Generates SUN-Rasterfiles */
+"SunRaster", /** Generates SUN-Rasterfiles */
+#define FMT_EPSON 2 /** Generates X+Y-Weaved ESC/P-Output */
+"Epson", /** Generates X+Y-Weaved ESC/P-Output */
+#define FMT_ESCP2Y 3 /** Generates Y-Weaved ESC/P2-Output */
+"EscP2", /** Generates Y-Weaved ESC/P2-Output */
+#define FMT_ESCP2XY 4 /** Generates X+Y-Weaved ESC/P2-Output */
+"EscP2XY", /** Generates X+Y-Weaved ESC/P2-Output */
+#define FMT_RTL 5 /** Generates HP-PCL/RTL-Output */
+"Pcl", /** Generates HP-PCL/RTL-Output */
+#define FMT_CANON 6 /** Generates Output for Canon extended mode (hr) */
+"Canon", /** Generates Output for Canon extended mode (hr) */
+NULL
+};
+
+static const char *const *const upd_choice[] = {
+#define C_MAPPER 0 /** the selected Mapper */
+ upd_mapper,
+#define C_RENDER 1 /** the selected Rendering */
+ upd_render,
+#define C_FORMAT 2 /** the selected Choice */
+ upd_format
+};
+
+/** Names for the flags (bool)
+*/
+
+static const char *const upd_flags[] = { /** */
+#define B_REVDIR ((uint32) 1<<0) /** FS-Dir-Flag */
+"upFSReverseDirection", /** FS-Dir-Flag */
+#define B_FIXDIR ((uint32) 1<<1) /** Do not alter FS-direction */
+"upFSFixedDirection", /** Do not alter FS-direction */
+#define B_FSWHITE ((uint32) 1<<2) /** Process white in FS */
+"upFSProcessWhiteSpace", /** Process white in FS */
+#define B_FSZERO ((uint32) 1<<3) /** Zero FS-Initialization */
+"upFSZeroInit", /** Zero FS-Initialization */
+
+#define B_PAGEWIDTH ((uint32) 1<<4) /** Adjust Width in BOP */
+"upAdjustPageWidthCommand", /** Adjust Page-Width in BOP */
+#define B_PAGELENGTH ((uint32) 1<<5) /** Adjust Length in BOP */
+"upAdjustPageLengthCommand", /** Adjust Page-Length in BOP */
+#define B_TOPMARGIN ((uint32) 1<<6) /** Adjust Top-Margin in BOP */
+"upAdjustTopMarginCommand", /** Adjust Top-Margin in BOP */
+#define B_BOTTOMMARGIN ((uint32) 1<<7) /** Adjust Bottom-Margin in BOP */
+"upAdjustBottomMarginCommand", /** Adjust Bottom-Margin in BOP */
+#define B_RESOLUTION ((uint32) 1<<8) /** Adjust Resolution in BOP */
+"upAdjustResolutionCommand", /** Adjust Resolution in BOP */
+#define B_MEDIASIZE ((uint32) 1<<9) /** Adjust Mediasize in BOP */
+"upAdjustMediaSize", /** Adjust Mediasize in BOP */
+
+#define B_XABS ((uint32) 1<<10) /** Use Absolute X-Values */
+"upFormatXabsolute", /** Use Absolute X-Values */
+#define B_YABS ((uint32) 1<<11) /** Use Absolute Y-Values */
+"upFormatYabsolute", /** Use Absolute Y-Values */
+
+#define B_MAP ((uint32) 1<<12) /** Mapping Initialized */
+"upColorModelInitialized", /** Mapping Initialized */
+#define B_BUF ((uint32) 1<<13) /** Raster-Buffer Initialized */
+"upRasterBufferInitialized", /** Raster-Buffer Initialized */
+#define B_RENDER ((uint32) 1<<14) /** Rendering Initialized */
+"upRenderingInitialized", /** Rendering Initialized */
+#define B_FORMAT ((uint32) 1<<15) /** Formatter Initialized */
+"upOutputFormatInitialized", /** Formatter Initialized */
+#define B_ABORT ((uint32) 1<<16) /** Abort on Interrupt */
+"upOutputAborted", /** Abort on Interrupt */
+#define B_ERROR ((uint32) 1<<17) /** Severe Error detected */
+"upErrorDetected", /** Severe Error detected */
+
+#define B_OPEN ((uint32) 1<<18) /** Open-Command written */
+"upWroteData", /** Open-Command written */
+
+#define B_YFLIP ((uint32) 1<<19) /** Mirrored printing (hr) */
+"upYFlip" /** Mirrored printing (hr) */
+
+};
+
+/** B_OK4GO: Bits required to execute the print-loop */
+
+#define B_OK4GO (B_MAP | B_BUF | B_RENDER | B_FORMAT)
+
+/** Names for the ints
+*/
+
+static const char *const upd_ints[] = {
+#define I_PWIDTH 0 /** Output-Width */
+"upOutputWidth",
+#define I_PHEIGHT 1 /** Output-Height */
+"upOutputHeight",
+#define I_NCOMP 2 /** Output-Components */
+"upOutputComponents",
+#define I_NSCNBUF 3 /** Output-Buffers */
+"upOutputBuffers",
+#define I_XSTEP 4 /** Unit-Step */
+"upOutputXStep", /* > 0 -> divide Raster-X, < 0 muliply Raster-X */
+#define I_XOFS 5 /** abs. X-Offset */
+"upOutputXOffset",
+#define I_YSTEP 6 /** Unit-Step */
+"upOutputYStep", /* > 0 -> divide Raster-Y, < 0 muliply Raster-Y */
+#define I_YOFS 7 /** abs. Y-Offset */
+"upOutputYOffset",
+#define I_PINS2WRITE 8 /** Number of Pins */
+"upOutputPins",
+
+#define I_NXPASS 9 /** X-Passes */
+"upWeaveXPasses",
+#define I_NYPASS 10 /** Y-Passes */
+"upWeaveYPasses",
+#define I_NPASS 11 /** Total # Passes */
+"upWeavePasses",
+#define I_BEG_Y 12 /** Start of normal Weaving */
+"upWeaveInitialScan",
+#define I_END_Y 13 /** End of normal Weaving */
+"upWeaveFinalScan",
+#define I_BEGSKIP 14 /** A Scan-Offset */
+"upWeaveYOffset"
+};
+
+/** Names for the Integer-Arrays
+*/
+
+static const char *const upd_int_a[] = { /** */
+#define IA_COLOR_INFO 0 /** external color_info */
+"upColorInfo", /** external color_info */
+
+#define IA_COMPBITS 1 /** Bits stored per Component */
+"upComponentBits", /** Bits stored per Component */
+#define IA_COMPSHIFT 2 /** Shift for the stored Bits */
+"upComponentShift", /** Shift for the stored Bits */
+#define IA_COMPORDER 3 /** Order of Output-Components */
+"upOutputComponentOrder", /** Order of Output-Components */
+
+#define IA_STD_DY 4 /** Standard-Weave Feeds */
+"upWeaveYFeeds", /** Standard-Weave Feeds */
+#define IA_STD_IX 5 /** Standard-Weave X-Passes */
+"upWeaveXStarts", /** Standard-Weave X-Start */
+#define IA_BEG_DY 6 /** Initial-Weave Feeds */
+"upWeaveInitialYFeeds", /** Initial-Weave Feeds */
+#define IA_BEG_IX 7 /** Initial-Weave X-Start */
+"upWeaveInitialXStarts", /** Initial-Weave X-Start */
+#define IA_BEGBOT 8 /** Initial-Weave #Pins */
+"upWeaveInitialPins", /** Initial-Weave #Pins */
+#define IA_END_DY 9 /** Final-Weave Feeds */
+"upWeaveFinalYFeeds", /** Final-Weave Feeds */
+#define IA_END_IX 10 /** Final-Weave X-Start */
+"upWeaveFinalXStarts", /** Final-Weave X-Start */
+#define IA_ENDTOP 11 /** Final-Weave #Pins */
+"upWeaveFinalPins" /** Final-Weave #Pins */
+};
+
+/** Names of the String-Parameters
+*/
+
+static const char *const upd_strings[] = { /** */
+#define S_MODEL 0 /** Name of the Printer-Model */
+"upModel", /** Name of the Printer-Model */
+#define S_OPEN 1 /** Printer-Begin-Job */
+"upBeginJobCommand", /** Printer-Begin-Job */
+#define S_CLOSE 2 /** Printer-End-Job */
+"upEndJobCommand", /** Printer-End-Job */
+#define S_BEGIN 3 /** Printer-Begin-Page */
+"upBeginPageCommand", /** Printer-Begin-Page */
+#define S_END 4 /** Printer-End-Page */
+"upEndPageCommand", /** Printer-End-Page */
+#define S_ABORT 5 /** Printer-Abort-Command */
+"upAbortCommand", /** Printer-Abort-Command */
+
+#define S_XMOVE 6 /** X-Positioning-Command */
+"upXMoveCommand", /** X-Positioning-Command */
+#define S_XSTEP 7 /** X-Step Command (1<I_XSTEP) */
+"upXStepCommand", /** X-Step Command (1<I_XSTEP) */
+#define S_SETLF 8 /** Set-Linefeed-Command */
+"upSetLineFeedCommand", /** Set-Linefeed-Command */
+#define S_YMOVE 9 /** Y-Positioning-Command */
+"upYMoveCommand", /** Y-Positioning-Command */
+#define S_YSTEP 10 /** Y-Step Command (1<I_YSTEP) */
+"upYStepCommand" /** Y-Step Command (1<I_YSTEP) */
+}; /** */
+
+/** Names for the String-Arrays
+*/
+
+static const char *const upd_string_a[] = { /** */
+#define SA_SETCOMP 0 /** Select Components */
+"upSelectComponentCommands", /** Select Components */
+#define SA_WRITECOMP 1 /** Write Component Comands */
+"upWriteComponentCommands" /** Write Component Commands */
+}; /** */
+
+/** Names for the float-Arrays
+*/
+static const char *const upd_float_a[] = { /** */
+#define FA_WXFER 0 /** White-Transfer */
+"upWhiteTransfer", /** White-Transfer */
+#define FA_RXFER 1 /** Red-Transfer */
+"upRedTransfer", /** Red-Transfer */
+#define FA_GXFER 2 /** Green-Transfer */
+"upGreenTransfer", /** Green-Transfer */
+#define FA_BXFER 3 /** Blue-Transfer */
+"upBlueTransfer", /** Blue-Transfer */
+#define FA_KXFER 4 /** Black-Transfer */
+"upBlackTransfer", /** Black-Transfer */
+#define FA_CXFER 5 /** Cyan-Transfer */
+"upCyanTransfer", /** Cyan-Transfer */
+#define FA_MXFER 6 /** Magenta-Transfer */
+"upMagentaTransfer", /** Magenta-Transfer */
+#define FA_YXFER 7 /** Yellow-Transfer */
+"upYellowTransfer", /** Yellow-Transfer */
+#define FA_MARGINS 8 /** private Margins */
+"upMargins" /** private Margins */
+}; /** */
+
+/* ------------------------------------------------------------------- */
+/* UPD-specific datatypes */
+/* ------------------------------------------------------------------- */
+
+/**
+int32 and uint32 are 32Bit-Integer-Types used in the
+Floyd-Steinberg Algorithm and instead of gx_color_index. The
+8-Byte long's on some 64Bit-Machines are apparently useless,
+since gdevprn.c does (currently) support only 32-Bit Rasterdata.
+*/
+
+#if arch_log2_sizeof_int < 2 /* int is too small */
+ typedef long int32;
+#define INT32_MIN LONG_MIN
+#define INT32_MAX LONG_MAX
+ typedef unsigned long uint32;
+#define UINT32_MAX ULONG_MAX
+#else /* int is sufficient */
+ typedef int int32;
+#define INT32_MIN INT_MIN
+#define INT32_MAX INT_MAX
+ typedef unsigned int uint32;
+#define UINT32_MAX UINT_MAX
+#endif /* use int or long ? */
+
+/**
+"updcmap" is used by the color-mapping functions of the driver.
+there are four cmaps in the "uniprint"-structure, one for each component.
+To be exact, it's not "4" but rather "UPD_CMAP_MAX", which is a synonym.
+*/
+
+typedef struct updcmap_s { /** */
+ gx_color_value *code; /** Values related to codes */
+ uint32 bitmsk; /** Mask, right justified */
+ int bitshf; /** Shift to right-justify */
+ int xfer; /** Index to the Xfer-Array */
+ int bits; /** # of Bits */
+ int comp; /** Output-Number */
+ bool rise; /* Rising/Falling Curve */
+} updcmap_t, *updcmap_p; /** */
+typedef const updcmap_t *updcmap_pc;
+
+
+/**
+"updcomp" holds similar informations, but is used for the rendering
+*/
+
+typedef struct updcomp_s { /* Parameters for Floyd-Steinberg */
+ int32 offset; /* Offset added to scaled values */
+ int32 scale; /* Scale for the raw values */
+ int32 threshold; /* Val must be larger than this to fire */
+ int32 spotsize; /* subtracted from Val when fired */
+ uint32 bitmsk; /* Mask */
+ int bitshf; /* shift */
+ int bits; /* # of Bits */
+ int cmap; /* Index for the Parameter-name */
+} updcomp_t, *updcomp_p; /* Parameters for Floyd-Steinberg */
+
+/** updscan is the Element of the scan-buffer. */
+
+typedef struct updscan_s { /* Single Scanline (1 Bit/Pixel) */
+ byte *bytes; /* Buffer used w. 32-Bit Words */
+ int *xbegin; /* 1st Pixel set (or nbytes<<3 if none) */
+ int *xend; /* last Pixel set (or -1, if none) */
+} updscan_t, *updscan_p; /* Single Scanline (1 Bit/Pixel) */
+
+
+/** Main upd-Structure ***/
+
+#define UPD_CMAP_MAX 4 /** Number of Colormaps provided */
+#define UPD_VALPTR_MAX 32 /** Number of valbuf-Pointers */
+
+#define upd_proc_pxlget(name) uint32 name(P1(upd_p upd))
+#define upd_proc_render(name) int name(P1(upd_p upd))
+#define upd_proc_writer(name) int name(P2(upd_p upd,FILE *out))
+
+struct upd_s { /* All upd-specific data */
+
+ int *choice; /** Named-Choices */
+ int *ints; /** Integers */
+ gs_param_int_array *int_a; /** Integer-Arrays */
+ gs_param_string *strings; /** Strings */
+ gs_param_string_array *string_a; /** String-Arrays */
+ gs_param_float_array *float_a; /** Float-Arrays */
+
+ updcmap_t cmap[UPD_CMAP_MAX]; /** Mapping-Data */
+
+ byte *gsbuf; /* Storage for GS-Rasterdata */
+ byte *gsscan; /* Begin of GS-Rasterdata */
+
+ byte *pxlptr; /* Source for pxlget */
+ upd_proc_pxlget( (*pxlget)); /* The Pixel-Reader */
+ upd_proc_render( (*render)); /* Actual Rendering */
+ upd_proc_writer( (*writer));
+
+ updscan_p *scnbuf; /* Output-Values */
+ int32 *valbuf; /* Floyd-Steinberg-Buffer */
+ void *valptr[UPD_VALPTR_MAX];
+
+ byte *outbuf; /* Output-Buffer */
+ upd_proc_render( (*start_render)); /* Setup for rendering */
+ upd_proc_writer( (*start_writer)); /* Setup for writilg */
+
+ uint32 flags; /** Some flags */
+ int pdwidth; /** pdev-width upon open */
+ int pdheight; /** pdev-height upon open */
+
+ uint ngsbuf; /* Size of gsbuf */
+ int gswidth; /* Width in GS-Pixels */
+ int gsheight; /* Height in GS-Pixels */
+
+ int rwidth; /* Rendering-Width */
+
+ int pwidth; /* Printing-Width */
+ int pheight; /* # scanlines printed */
+
+ uint nvalbuf; /* Size of valbuf */
+ int nscnbuf; /* Number of entries in scnbuf. */
+ int ncomp; /* # Components in scnbuf */
+ int nbytes; /* Size of scnbuf[][].words */
+ int nlimits; /* Size of scnbuf[][].xbegin/end */
+ int scnmsk; /* Size of scanbuf - 1 */
+ uint noutbuf; /* Size of the Output-Buffer */
+
+ int ixpass; /* Current X-pass (0 ... nxpass-1) */
+ int ipass; /* Current pass (0 ... npass-1) */
+ int icomp; /* Selected Component */
+ int lf; /* Selected Line-Space */
+
+ int xprinter; /* Actual X-Position */
+
+ int yscan; /* Top-Scan (page-vari) */
+ int yprinter; /* Actual Y-Position (page-vari) */
+ int yscnbuf; /* Y not yet buffered */
+}; /* All upd-specific data */
+
+
+/* ------------------------------------------------------------------- */
+/* Various Message-Levels */
+/* ------------------------------------------------------------------- */
+
+/**
+UPD_MESSAGES, Is collection of Bits, that controls Messages
+*/
+
+#define UPD_M_NONE 0x0000 /** No Messages at all */
+#define UPD_M_ERROR 0x0001 /** Errors */
+#define UPD_M_WARNING 0x0002 /** Warnings */
+#define UPD_M_TOPCALLS 0x0004 /** Log Calls to main Functions */
+#define UPD_M_MAPCALLS 0x0008 /** Log Color-Mapping-Calls */
+#define UPD_M_SETUP 0x0010 /** Log Setup-Activity */
+#define UPD_M_FSBUF 0x0020 /** Error-Summary for valbuf */
+
+
+/* ------------------------------------------------------------------- */
+/* The UPD-Routines */
+/* ------------------------------------------------------------------- */
+
+/**
+Besides the main routines required for the color-mapping, that were
+declared near the beginning, there are some auxillary functions.
+Most prominent are "upd_open_map" and "upd_close_map", which
+do the proper actions when opening and closing the device.
+*/
+
+private int upd_open_map( P1(upd_device *udev));
+private int upd_close_map(P1(upd_device *udev));
+
+/**
+But "upd_truncate" and "upd_expand" are also mentionable. They are
+the actual workhorses for the component-oriented mapping. When mapping
+the 16Bit Component-Values to the indices, some truncation takes place
+and this is what "upd_truncate" does, in the most general manner i can
+think of and with O(log(n)) in time. "upd_expand" is required for the
+reverse mapping-functions and is a constant-time `algorithm'.
+*/
+private uint32 upd_truncate(P3(upd_pc,int,gx_color_value));
+private gx_color_value upd_expand( P3(upd_pc,int,uint32));
+
+/**
+The next group of internal functions adresses the rendering. Besides
+the main-functions "upd_open_render" and "upd_close_render", there
+are groups of up to 3 Functions, for each algorithm available with
+UPD. Two routines are invoked during open and close and the third
+is called for each scanline. Actually a fourth function is provided,
+that is invoked at the beginning of each page to be printed, but the
+current algorithms do not need it.
+*/
+private void upd_open_render( P1(upd_device *udev));
+private void upd_close_render( P1(upd_device *udev));
+
+private void upd_open_fscomp( P1(upd_device *udev));
+private int upd_fscomp( P1(upd_p upd));
+private void upd_close_fscomp( P1(upd_device *udev));
+
+private void upd_open_fscmyk( P1(upd_device *udev));
+private int upd_fscmyk( P1(upd_p upd));
+
+/**
+I hope that the formatting stuff can be kept simple and thus most
+of the work is done inside the general open and close-functions.
+During open, there is a call to a format-specific open-function, but
+this is only for checking and determining the amount of of bytes required
+for the output-buffer (and limit-values in the scan-buffer).
+*/
+private int upd_open_writer( P1(upd_device *udev));
+private void upd_close_writer( P1(upd_device *udev));
+#if UPD_SIGNAL
+private void upd_signal_handler(P1(int sig));
+#endif
+
+/**
+The first format are the uncompressed! SUN-Rasterfiles. The primary intention
+of this format is testing, but it might turn out to be useful for other
+purposes, even if the amount of generated data is huge. On the other hand
+it is a violation of UPD's rules: the start-routine computes the Begin-Page
+sequence (the Rasterfile header) since it would be a nuisance to provide
+this code within each (test-)personalization in PostScript.
+*/
+private int upd_open_rascomp( P1(upd_device *udev));
+private int upd_start_rascomp( P2(upd_p upd, FILE *out));
+private int upd_rascomp( P2(upd_p upd, FILE *out));
+
+/**
+The second format is ESC/P, the format introduced with the first Epson
+impact printers. This format is used by a lot of other printers too.
+It is also uncompressed. This formatter supports X- and Y-Weaving,
+which makes it the most sophisticated one inside this driver.
+*/
+
+private void upd_limits( P2(upd_p upd, bool check));
+private int upd_open_wrtescp( P1(upd_device *udev));
+private int upd_wrtescp( P2(upd_p upd, FILE *out));
+
+/**
+The third format is ESC/P2, the format use by the newer Epson-Printers.
+It allows runlength-Compression similar to the RTL/PCL-Family of Printers.
+This formatter does not allow for X-Weaving.
+
+The fourth writer is a ESC/P2-Writer, that supports X-Weaving
+*/
+private int upd_rle(P3(byte *out,const byte *in,int nbytes));
+private int upd_open_wrtescp2( P1(upd_device *udev));
+private int upd_wrtescp2( P2(upd_p upd, FILE *out));
+private int upd_wrtescp2x( P2(upd_p upd, FILE *out));
+
+/**
+The fifth writer is a HP-RTL/PCL-Writer
+*/
+
+private int upd_open_wrtrtl( P1(upd_device *udev));
+private int upd_wrtrtl( P2(upd_p upd, FILE *out));
+
+/**
+The sixth writer is for Canon Extended Mode (currently BJC610) (hr)
+*/
+
+private int upd_open_wrtcanon( P1(upd_device *udev));
+private int upd_wrtcanon( P2(upd_p upd, FILE *out));
+
+/**
+Generalized Pixel Get & Read
+*/
+private uint32 upd_pxlfwd(P1(upd_p upd));
+private uint32 upd_pxlrev(P1(upd_p upd));
+#define upd_pxlget(UPD) (*UPD->pxlget)(UPD)
+
+
+/* ------------------------------------------------------------------- */
+/* Macros to deal with the Parameter-Memory */
+/* ------------------------------------------------------------------- */
+
+/**
+Usually the creation of copies of external parameters is not necessary,
+at least with gs-versions > 4.03. But uniprint writes to the parameters
+in some cases or creates some by itself, thus to get a unified interface
+all parameter-data are copied and thus it is legal to manipulate them.
+
+Here are several Macros, named "UPD_MM_*" to deal with that.
+*/
+
+/** UPD_MM_GET_ARRAY allocates & initializes an array of values */
+#define UPD_MM_GET_ARRAY(Which,Nelts) \
+ Which = NULL; \
+ if(0 < (Nelts)) { \
+ byte *tmp = gs_malloc(Nelts,sizeof(Which[0]),"uniprint/params");\
+ if(tmp) { \
+ memset(tmp,0,(Nelts)*sizeof(Which[0])); \
+ Which = (void *) tmp; \
+ } else { \
+ return_error(gs_error_VMerror); \
+ } \
+ }
+
+/** UPD_MM_DEL_ARRAY frees an array of values */
+#define UPD_MM_DEL_ARRAY(Which,Nelts,Delete) \
+ if(Which && 0 < (Nelts)) { \
+ uint ii; \
+ for(ii = 0; (Nelts) > ii; ++ii) Delete(Which[ii]); \
+ gs_free((byte *)Which,Nelts,sizeof(Which[0]),"uniprint/params");\
+ } \
+ Which = 0
+
+/** UPD_MM_DEL_VALUE deletes a value, does nothing */
+#define UPD_MM_DEL_VALUE(Which) /* */
+
+/** UPD_MM_DEL_PARAM deletes a single gs-array-parameter */
+#define UPD_MM_DEL_PARAM(Which) { \
+ if(Which.data && Which.size) \
+ gs_free((byte *)Which.data,Which.size,sizeof(Which.data[0]),\
+ "uniprint/params"); \
+}
+
+/** UPD_MM_DEL_APARAM deletes a nested gs-array-parameter */
+#define UPD_MM_DEL_APARAM(Which) { \
+ if(Which.data && Which.size) { \
+ uint iii; \
+ for(iii = 0; iii < Which.size; ++iii) \
+ UPD_MM_DEL_PARAM(Which.data[iii]); \
+ gs_free((byte *)Which.data,Which.size,sizeof(Which.data[0]),\
+ "uniprint/params"); \
+ } \
+}
+
+/** UPD_MM_CPY_ARRAY creates a new copy of an array of values */
+#define UPD_MM_CPY_ARRAY(To,From,Nelts,Copy) \
+ UPD_MM_GET_ARRAY(To,Nelts); \
+ if(To && From) { \
+ uint ii; \
+ for(ii = 0; (Nelts) > ii; ++ii) Copy(To[ii],From[ii]);\
+ }
+
+/** UPD_MM_CPY_VALUE Copies a simple Value */
+#define UPD_MM_CPY_VALUE(To,From) To = From
+
+/** UPD_MM_CPY_PARAM Creates a copy of a gs-parameter */
+#define UPD_MM_CPY_PARAM(To,From) \
+ if(From.data && From.size) { \
+ UPD_MM_GET_ARRAY(To.data,From.size); \
+ if(To.data) { \
+ To.size = From.size; \
+ memcpy((byte *)To.data,From.data,To.size*sizeof(To.data[0]));\
+ } \
+ }
+
+/** UPD_MM_CPY_APARAM Creates a copy of a nested gs-parameter */
+#define UPD_MM_CPY_APARAM(To,From) \
+ if(From.data && From.size) { \
+ UPD_MM_GET_ARRAY(To.data,From.size); \
+ if(To.data) { \
+ gs_param_string *tmp2 = (gs_param_string *) To.data; \
+ uint iii; \
+ To.size = From.size; \
+ for(iii = 0; To.size > iii; ++iii) \
+ UPD_MM_CPY_PARAM(tmp2[iii],From.data[iii]); \
+ } \
+ }
+
+/* ------------------------------------------------------------------- */
+/* UPD-Initialized-Data */
+/* ------------------------------------------------------------------- */
+
+/** Version-String */
+
+static const char rcsid[] = "Revision: 1.77 ";
+
+/** Default-Transfer-curve */
+
+static const float upd_data_xfer[2] = { 0.0, 1.0 };
+
+/*@ > */
+
+
+/* ------------------------------------------------------------------- */
+/* upd_signal_handler: Catch interrupts */
+/* ------------------------------------------------------------------- */
+
+#if UPD_SIGNAL
+static upd_p sigupd = NULL;
+private void
+upd_signal_handler(int sig)
+{
+ if(sigupd) sigupd->flags |= B_ABORT;
+}
+#endif
+
+
+/* ------------------------------------------------------------------- */
+/* upd_print_page: The main workhorse */
+/* ------------------------------------------------------------------- */
+
+/**
+Function: upd_print_page
+
+This is the top-level printing routine. It works through this
+steps:
+
+ 1. Once for each generated file, the "device-open-sequence" is written.
+ 2. The "page-begin-sequence" is written.
+
+ 3. The data are generated and written:
+ 3.1: Data are converted into a "printer-family"-specific format.
+ This step includes the halftoning, if selected.
+ 3.2: Data are written with a printer-specific function.
+ There is not much code-compression inside theese functions,
+ since i observed to improvments in print-speed. Other
+ drivers do a better job in this.
+
+ 4. The "page-end-sequence" is written.
+ 5. If a one-page-per-file mode is selected, the "device-close-sequence"
+ is added to the output. For multi-page files, this writing is
+ performed in "upd_close", the drivers close-function.
+
+The routine is quite short, since all the allocation and checking
+occur in upd_open and upd_putparams. The only test, that upd_print_page
+does, is the verification wether the device is in a sane state. This
+must be done here, since during the initialisation, the device is
+usually opened several times, before obtaining a valid state.
+*/
+
+private int
+upd_print_page(gx_device_printer *pdev, FILE *out)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ const int *const ints = upd ? upd->ints : NULL;
+ int error,need,yfill;
+
+#if UPD_SIGNAL /* variables required for signal-handling only */
+ void (*oldint )(P1(int)) = NULL;
+ void (*oldterm)(P1(int)) = NULL;
+ upd_p oldupd = sigupd;
+#endif /* variables required for signal-handling only */
+
+/*
+ * Refuse to work, if not explicitly enabled during open
+ * (some/lot of allocated memory is required)
+ */
+ if(!upd || B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR))) {
+#if UPD_MESSAGES & (UPD_M_ERROR | UPD_M_TOPCALLS)
+ fprintf(stderr,"CALL-REJECTED upd_print_page(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) out);
+#endif
+ return gs_error_undefined;
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"CALL: upd_print_page(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) out);
+#endif
+
+#if UPD_SIGNAL /* Setup of signal-handling */
+ sigupd = upd;
+ oldint = signal(SIGINT, upd_signal_handler);
+ oldterm = signal(SIGTERM,upd_signal_handler);
+#endif /* Setup of signal-handling */
+
+/*
+ * If the OutputFile was just opened, transfer the Open-Sequence to it.
+ */
+ if(!(upd->flags & B_OPEN)) {
+
+ if(0 < upd->strings[S_OPEN].size)
+ fwrite(upd->strings[S_OPEN].data,1,upd->strings[S_OPEN].size,out);
+ upd->flags |= B_OPEN;
+ }
+/*
+ * Always write the the Page-begin-sequence
+ */
+ if(0 < upd->strings[S_BEGIN].size)
+ fwrite(upd->strings[S_BEGIN].data,1,upd->strings[S_BEGIN].size,out);
+/*
+ * Establish page-variables
+ */
+
+/* Positions */
+ upd->xprinter = 0;
+ upd->yscan = 0; /* Position we are processing */
+ upd->yprinter = 0; /* Actual Printer-Positions */
+ upd->yscnbuf = 0; /* Next free scnbuf-Line */
+
+/* Rendering & Writing Setup, if available */
+ if(upd->start_render) (*upd->start_render)(upd);
+ if(upd->start_writer) (*upd->start_writer)(upd,out);
+
+/* How many scanlines do we need ? */
+ need = ints[I_NYPASS] * ints[I_PINS2WRITE];
+ if(0 >= need) need = 1;
+
+/* The Weave-counters */
+ upd->ipass = 0;
+ upd->ixpass = 0;
+ upd->icomp = -1; /* Enforces initial selection */
+ upd->lf = -1; /* Enforces initial selection */
+/*
+ * Main Loop
+ */
+ while(upd->pheight > upd->yscan) { /* Main-Loop */
+
+/*
+ * Load as much data into the scan-buffer as possible
+ * (this is done in scan-sequence, the printing not necessarily.)
+ */
+ if(ints[I_BEGSKIP] > upd->yscan) yfill = 0;
+ else yfill = upd->yscan - ints[I_BEGSKIP];
+
+ for(yfill += upd->nscnbuf; upd->yscnbuf < yfill; upd->yscnbuf++) {
+
+ if(upd->gsheight > upd->yscnbuf) {
+
+ if(0 > (*dev_proc(udev,get_bits))((gx_device *) udev,
+ upd->yscnbuf,upd->gsbuf,&upd->gsscan)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,"get_bits aborted with error, yscnbuf = %4d\n",
+ upd->yscnbuf);
+#endif
+ break;
+ }
+ } else {
+
+ memset(upd->gsscan = upd->gsbuf,0,upd->ngsbuf);
+
+ }
+
+ if(0 > (*upd->render)(upd)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,"Rendering aborted with error, yscnbuf = %4d\n",
+ upd->yscnbuf);
+#endif
+ break;
+ }
+
+ }
+/*
+ * Did the buffering loop take an error exit ?
+ */
+ if((upd->yscnbuf ^ yfill) & upd->scnmsk) break;
+/*
+ * Print as much as possible
+ */
+ while((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) {
+
+/* first write the scan(s) */
+ (*upd->writer)(upd,out);
+
+/* Check for termination */
+ if(upd->yscan >= upd->pheight) break;
+ if(upd->flags & B_ABORT ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,"Printing aborted upon interrupt, yscan = %4d\n",
+ upd->yscan);
+#endif
+ break;
+ }
+ }
+/*
+ * Did the print-Loop take an error exit ?
+ */
+ if((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) break;
+ } /* Main-Loop */
+
+/*
+ * If we aborted for some reason, use the dedicated sequence
+ */
+
+ if((upd->pheight > upd->yscan) &&
+ (0 < upd->strings[S_ABORT].size)) { /* Only This! */
+ fwrite(upd->strings[S_ABORT].data,1,upd->strings[S_ABORT].size,out);
+
+ upd->flags &= ~B_OPEN; /* Inhibit Close-Sequence ! */
+/*
+ * If there is no special sequence, or we came to normal end,
+ * write the normal sequence, if any
+ */
+
+ } else if(0 < upd->strings[S_END].size) {
+ fwrite(upd->strings[S_END].data,1,upd->strings[S_END].size,out);
+ }
+/*
+ * If necessary, write the close-sequence
+ */
+ if((NULL != udev->fname ) && strchr(udev->fname,'%')) {
+
+ if(0 < upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,upd->strings[S_CLOSE].size,out);
+
+ upd->flags &= ~B_OPEN;
+ }
+
+/*
+ * clean up, and return status
+ */
+
+ fflush(out); /* just to prepare for ferror */
+
+ if(upd->pheight > upd->yscan) error = gs_error_interrupt;
+ else if(ferror(out)) error = gs_error_ioerror;
+ else error = 0;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"RETURN: %d = upd_print_page(0x%05lx,0x%05lx)\n",
+ error,(long) udev,(long)out);
+#endif
+
+#if UPD_SIGNAL /* Restore Interrupt-state */
+ sigupd = oldupd;
+ (void) signal(SIGINT ,oldint);
+ (void) signal(SIGTERM,oldterm);
+#endif /* Restore Interrupt-state */
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open: Initialize everything for printing */
+/* ------------------------------------------------------------------- */
+/**
+"upd_open" is -through the specified table of procedures- called instead
+of the normal open-procedures for printer-devices, that performs quite
+a complex job. Thus it is necessary to call this `superclass-open´
+here.
+
+Besides that, this routine does quite a complex job too, in initializes
+everything required to print a page. This might be time-consuming, the
+alternative would be "upd_print_page", but i often print 100 pages or
+more, but i never experienced more than 5-6 open-calls.
+*/
+
+private int
+upd_open(gx_device *pdev)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ int error;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"CALL: upd_open(0x%05lx)\n",(long) pdev);
+#endif
+
+/** enforce the UPD-Margins */
+
+ if((NULL != upd) &&
+ (NULL != upd->float_a[FA_MARGINS].data) &&
+ (4 == upd->float_a[FA_MARGINS].size) ) {
+ static float m[4];
+ m[1] = upd->float_a[FA_MARGINS].data[1] / 72.0;
+ m[3] = upd->float_a[FA_MARGINS].data[3] / 72.0;
+ if(B_YFLIP & upd->flags) {
+ m[0] = upd->float_a[FA_MARGINS].data[2] / 72.0;
+ m[2] = upd->float_a[FA_MARGINS].data[0] / 72.0;
+ } else {
+ m[0] = upd->float_a[FA_MARGINS].data[0] / 72.0;
+ m[2] = upd->float_a[FA_MARGINS].data[2] / 72.0;
+ }
+ gx_device_set_margins((gx_device *) udev, m, true);
+ }
+
+/** call the super-class open **/
+ error = gdev_prn_open(pdev);
+
+/** invoke the subroutines, if an upd is present. */
+
+ if(upd) {
+
+ upd->flags &= ~B_OK4GO;
+
+/**
+The following initializations are run, even in case of an error in
+the super-class open, just to bring our upd into a sane state.
+*/
+ if(0 > error) upd->flags |= B_ERROR;
+
+ if(gs_error_VMerror == upd_open_map(udev)) error = gs_error_VMerror;
+
+/**
+The following piece of code is here for demonstration-purposes:
+It determines the size of the printed image and allocates the
+buffer for the raw raster-data
+*/
+ upd->gswidth = udev->width -
+ (dev_l_margin(udev)+dev_r_margin(udev))*udev->x_pixels_per_inch;
+
+ upd->gsheight = udev->height -
+ (dev_t_margin(udev)+dev_b_margin(udev))*udev->y_pixels_per_inch;
+
+ upd->ngsbuf = 0; /* Ensure sane values */
+ upd->gsbuf = NULL; /* Ensure sane values */
+
+ if(B_MAP & upd->flags) { /* Only if prerequisites were met */
+ uint want = gx_device_raster(pdev,true);
+ upd->gsbuf = gs_malloc(want,1,"upd/gsbuf");
+
+ if(upd->gsbuf) {
+ upd->ngsbuf = want;
+ upd->flags |= B_BUF; /* Signal Success */
+ } else {
+ error = gs_error_VMerror; /* Signal Error */
+ upd->flags |= B_ERROR;
+ }
+
+ } /* Only if prerequisites were met */
+
+ upd_open_render(udev); /* First subloop in printing */
+
+ if(gs_error_VMerror == upd_open_writer(udev)) error = gs_error_VMerror;
+
+#if UPD_MESSAGES & UPD_M_SETUP
+ fprintf(stderr,"\n%sready to print\n\n",
+ B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR)) ?
+ "NOT " : "");
+#endif
+ udev->upd->pdwidth = udev->width;
+ udev->upd->pdheight = udev->height;
+
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"RETURN: %d = upd_open(0x%05lx)\n",
+ error,(long) pdev);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close: Release everything allocated in upd_open */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_close(gx_device *pdev)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ int error = 0;
+ int code;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"CALL: upd_close(0x%05lx)\n",(long)pdev);
+#endif
+
+/** If necessary, write the close-sequence **/
+
+ if( upd && (( B_OPEN | B_OK4GO) ==
+ ((B_OPEN | B_OK4GO | B_ERROR) & upd->flags))) {
+
+ if(udev->file && upd->strings && 0 < upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,
+ upd->strings[S_CLOSE].size,udev->file);
+
+ upd->flags &= ~B_OPEN;
+ }
+
+/** Then release the open-allocated memory */
+ if(upd) {
+
+ upd_close_writer(udev);
+
+ if(upd->gsbuf)
+ gs_free(upd->gsbuf,upd->ngsbuf,1,"uniprint/gsbuf");
+ upd->gsbuf = NULL;
+ upd->ngsbuf = 0;
+ upd->flags &= ~B_BUF;
+
+ upd_close_render(udev);
+ upd_close_map(udev);
+
+ UPD_MM_DEL_ARRAY(upd->choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(upd->ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(upd->int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+
+ gs_free(upd,sizeof(upd[0]),1,"uniprint");
+
+ udev->upd = NULL;
+ }
+
+/** Then call the superclass close **/
+ code = gdev_prn_close(pdev);
+ error = error > code ? code : error;
+
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"RETURN: %d = upd_close(0x%05lx)\n",
+ error,(long) pdev);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_get_params: Export Parameters to the Interpreter */
+/* ------------------------------------------------------------------- */
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+#define UPD_EXIT_GET(Err,Dev,List) \
+ if(0 > Err) { \
+ fprintf(stderr,"RETURN-%d: %d upd_get_params(0x%05lx,0x%05lx)\n", \
+ __LINE__,Err,(long) Dev,(long) List); \
+ return_error(Err); \
+ }
+#else
+#define UPD_EXIT_GET(Err,Dev,List) if(0 > Err) return_error(Err);
+#endif
+
+private int
+upd_get_params(gx_device *pdev, gs_param_list *plist)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ int error,i;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"CALL: upd_get_params(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) plist);
+#endif
+
+/** Call the SuperClass-get_params at the beginning */
+ error = gdev_prn_get_params((gx_device *)udev,plist);
+ UPD_EXIT_GET(error,udev,plist);
+
+/** Export the version */
+ if(upd_version) { /* Version-Export enabled */
+ udev->upd_version.data = (const byte *) rcsid;
+ udev->upd_version.size = strlen(rcsid);
+ udev->upd_version.persistent = true;
+ error = param_write_string(plist,upd_version,&udev->upd_version);
+ UPD_EXIT_GET(error,udev,plist);
+ } /* Version-Export enabled */
+
+/** Export the Named choices */
+ for(i = 0; i < countof(upd_choice); ++i) {
+ if(!upd_choice[i]) continue; /* Choice-Export disabled */
+ if(upd && upd->choice && upd->choice[i]) {
+ gs_param_string name;
+ name.data = (const byte *) upd_choice[i][upd->choice[i]];
+ name.size = strlen((const char *) name.data);
+ name.persistent = true;
+ error = param_write_name(plist,upd_choice[i][0],&name);
+ } else {
+ error = param_write_null(plist,upd_choice[i][0]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the flags (bool) */
+ for(i = 0; i < countof(upd_flags); ++i) {
+ if(!upd_flags[i]) continue; /* Flag-Export disabled */
+ if(upd) {
+ bool value = upd->flags & ((uint32) 1 << i);
+ error = param_write_bool(plist,upd_flags[i],&value);
+ } else {
+ error = param_write_null(plist,upd_flags[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the ints */
+ for(i = 0; i < countof(upd_ints); ++i) {
+ if(!upd_ints[i]) continue; /* int-Export disabled */
+ if(upd && upd->ints && upd->ints[i]) {
+ int value = upd->ints[i];
+ error = param_write_int( plist,upd_ints[i],&value);
+ } else {
+ error = param_write_null(plist,upd_ints[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the int-arrays */
+ for(i = 0; i < countof(upd_int_a); ++i) {
+ if(!upd_int_a[i]) continue; /* int-Array-Export disabled */
+ if(upd && upd->int_a && upd->int_a[i].size) {
+ error = param_write_int_array( plist,upd_int_a[i],(upd->int_a+i));
+ } else {
+ error = param_write_null(plist,upd_int_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the strings */
+ for(i = 0; i < countof(upd_strings); ++i) {
+ if(!upd_strings[i]) continue; /* String-Export disabled */
+ if(upd && upd->strings && upd->strings[i].size) {
+ error = param_write_string( plist,upd_strings[i],(upd->strings+i));
+ } else {
+ error = param_write_null(plist,upd_strings[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the string-Arrays */
+ for(i = 0; i < countof(upd_string_a); ++i) {
+ if(!upd_string_a[i]) continue; /* String-Array-Export disabled */
+ if(upd && upd->string_a && upd->string_a[i].size) {
+ error =
+ param_write_string_array( plist,upd_string_a[i],(upd->string_a+i));
+ } else {
+ error = param_write_null(plist,upd_string_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the float-Arrays */
+ for(i = 0; i < countof(upd_float_a); ++i) {
+ if(!upd_float_a[i]) continue; /* Float-Array-Export disabled */
+ if(upd && upd->float_a && upd->float_a[i].size) {
+ error =
+ param_write_float_array( plist,upd_float_a[i],(upd->float_a+i));
+ } else {
+ error = param_write_null(plist,upd_float_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"RETURN: %d = upd_get_params(0x%05lx,0x%05lx)\n",
+ error,(long) udev,(long) plist);
+#endif
+
+ return error;
+}
+
+#undef UPD_EXIT_GET
+
+/* ------------------------------------------------------------------- */
+/* upd_put_params: Load Parameters into the device-structure */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_put_params(gx_device *pdev, gs_param_list *plist)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ upd_p upd = udev->upd;
+ int error = 0, code,i;
+
+ float MarginsHWResolution[2],Margins[2];
+ gx_device_color_info color_info;
+ uint32 flags = 0;
+ int *choice = NULL;
+ int *ints = NULL;
+ gs_param_int_array *int_a = NULL;
+ gs_param_string *strings = NULL;
+ gs_param_string_array *string_a = NULL;
+ gs_param_float_array *float_a = NULL, mfa;
+
+/**
+Error is used for two purposes: either it holds a negative error
+code or it is used as a bitfield, that tells, which parameters
+were actually loaded. If any of the important parameters changed
+upd_put_params closes the device, since the real parameter-evaluation
+is carried out by upd_open.
+*/
+
+#define UPD_PUT_FLAGS 0x0002
+#define UPD_PUT_CHOICE 0x0004
+#define UPD_PUT_INTS 0x0008
+#define UPD_PUT_INT_A 0x0010
+#define UPD_PUT_STRINGS 0x0020
+#define UPD_PUT_STRING_A 0x0040
+#define UPD_PUT_FLOAT_A 0x0080
+#define UPD_PUT_CHANGEDSIZE 0x0100
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"CALL: upd_put_params(0x%05lx,0x%05lx)\n",
+ (long)udev,(long)plist);
+#endif
+
+
+/**
+I consider the following part of upd_put_params a bad-nasty-hack-hack
+and i am uncertain, wether it really works in the intended way. I provide it
+just for the case someone is performing nasty-parameter-changes on the
+active device, especially switching the OutputFile. If this happens in
+a situation, where data were written to the file, but the termination
+sequence is required, the driver does it now. (If you want to know, why
+i am writing bad-nasty-hack-hack, visit http://www.zark.com )
+*/
+ if(upd && (B_OPEN & udev->upd->flags) && (NULL != udev->file)) {
+
+ gs_param_string fname = { NULL, 0, false };
+
+ code = param_read_string(plist,"OutputFile",&fname);
+ if((1 != code) && (0 != code)) {
+ code = param_read_null(plist,"OutputFile");
+ if(0 == code) {
+ fname.data = (const byte *) "";
+ fname.size = 0;
+ }
+ }
+
+ if((0 == code) &&
+ strncmp((const char *)fname.data,udev->fname,fname.size)) {
+ if(upd->strings && 0 < udev->upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,
+ upd->strings[S_CLOSE].size,udev->file);
+
+ upd->flags &= ~B_OPEN;
+ }
+ }
+/* Done with the bad-nasty-hack-hack */
+
+/**
+The next thing "upd_put_params" does, is a little strange too. It imports
+a readonly-parameter, the version-string. I do not know wether it is still
+required, but some versions of GHOSTSCRIPT disliked it very much, if an
+existing parameter was not touched by the put-operation.
+
+On the other hand it is the right time to show the basic-outline of the
+parameter-importing flow. Basically the proper "param_read"-procedure
+is called. If it indicated, that the parameter was present, but of the
+wrong type, a read for the null-type is attempted, which is by convention
+somehow an reset to default. This sequence is applied to all the parameters
+and in case of the array-parameters, a succesful null-read is marked by
+setting data and size to 0.
+*/
+#if UPD_MESSAGES & UPD_M_SETUP
+#define UPD_PARAM_READ(Param_read,Name,Object) \
+ code = Param_read(plist,Name,&Object); \
+ if(0 > code) { \
+ code = param_read_null(plist,Name); \
+ if(0 == code) memset(&Object,0,sizeof(Object));\
+ } \
+ if(!code) fprintf(stderr, \
+ "upd_put_params: retrieved parameter \"%s\"\n",\
+ Name); \
+ if(0 > code) { \
+ param_signal_error(plist,Name,code); \
+ if(error > code) error = code; \
+ }
+#else
+#define UPD_PARAM_READ(Param_read,Name,Object) \
+ code = Param_read(plist,Name,&Object); \
+ if(0 > code) { \
+ code = param_read_null(plist,Name); \
+ if(0 == code) memset(&Object,0,sizeof(Object));\
+ } \
+ if(0 > code) { \
+ param_signal_error(plist,Name,code); \
+ if(error > code) error = code; \
+ }
+#endif
+
+ UPD_PARAM_READ(param_read_string,upd_version,udev->upd_version)
+
+
+/**
+upd_put_params begins it's normal work by creating a copy, of
+the data, that it might change, except for color_info that might
+be changed in the device-structure, all manipulations are carried
+out on this copies.
+*/
+ MarginsHWResolution[0] = udev->MarginsHWResolution[0];
+ MarginsHWResolution[1] = udev->MarginsHWResolution[1];
+ Margins[0] = udev->Margins[0];
+ Margins[1] = udev->Margins[1];
+
+ color_info = udev->color_info;
+ if(upd) {
+ flags = upd->flags;
+ UPD_MM_CPY_ARRAY(choice, upd->choice, countof(upd_choice),
+ UPD_MM_CPY_VALUE);
+ UPD_MM_CPY_ARRAY(ints, upd->ints, countof(upd_ints),
+ UPD_MM_CPY_VALUE);
+ UPD_MM_CPY_ARRAY(int_a, upd->int_a, countof(upd_int_a),
+ UPD_MM_CPY_PARAM);
+ UPD_MM_CPY_ARRAY(strings, upd->strings, countof(upd_strings),
+ UPD_MM_CPY_PARAM);
+ UPD_MM_CPY_ARRAY(string_a,upd->string_a,countof(upd_string_a),
+ UPD_MM_CPY_APARAM);
+ UPD_MM_CPY_ARRAY(float_a, upd->float_a, countof(upd_float_a),
+ UPD_MM_CPY_PARAM);
+ } else {
+ flags = 0;
+ UPD_MM_GET_ARRAY(choice, countof(upd_choice));
+ UPD_MM_GET_ARRAY(ints, countof(upd_ints));
+ UPD_MM_GET_ARRAY(int_a, countof(upd_int_a));
+ UPD_MM_GET_ARRAY(strings, countof(upd_strings));
+ UPD_MM_GET_ARRAY(string_a,countof(upd_string_a));
+ UPD_MM_GET_ARRAY(float_a, countof(upd_float_a));
+ }
+
+/** Import the Multiple-Choices */
+ for(i = 0; countof(upd_choice) > i; ++i) {
+ gs_param_string value = { NULL, 0, false};
+ if(!upd_choice[i][0]) continue;
+ UPD_PARAM_READ(param_read_name,upd_choice[i][0],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_CHOICE;
+ choice[i] = 0;
+ if(0 < value.size) {
+ int j;
+ for(j = 1; upd_choice[i][j]; ++j) {
+ if((strlen(upd_choice[i][j]) == value.size) &&
+ (0 == strncmp(upd_choice[i][j],
+ (char *) value.data,value.size))) {
+ choice[i] = j;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+/** Import the Boolean Values */
+ for(i = 0; countof(upd_flags) > i; ++i) {
+ uint32 bit = (uint32) 1 << i;
+ bool flag = flags & bit ? true : false;
+ if(!upd_flags[i]) continue;
+ UPD_PARAM_READ(param_read_bool,upd_flags[i],flag);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_FLAGS;
+ if(flag) flags |= bit;
+ else flags &= ~bit;
+ }
+ }
+
+/** Import the Integer Values */
+ for(i = 0; countof(upd_ints) > i; ++i) {
+ int value = ints[i];
+ if(!upd_ints[i]) continue;
+ UPD_PARAM_READ(param_read_int,upd_ints[i],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_INTS;
+ ints[i] = value;
+ }
+ }
+
+/** Import the Integer Arrays */
+ for(i = 0; countof(upd_int_a) > i; ++i) {
+ gs_param_int_array value = int_a[i];
+ if(!upd_int_a[i]) continue;
+ UPD_PARAM_READ(param_read_int_array,upd_int_a[i],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_INT_A;
+ UPD_MM_DEL_PARAM(int_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ int_a[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(int_a[i],value);
+ }
+ }
+ }
+
+/** Import the Strings */
+ for(i = 0; countof(upd_strings) > i; ++i) {
+ gs_param_string value = strings[i];
+ if(!upd_strings[i]) continue;
+ UPD_PARAM_READ(param_read_string,upd_strings[i],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_STRINGS;
+ UPD_MM_DEL_PARAM(strings[i]);
+ if(!value.size) {
+ value.data = NULL;
+ strings[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(strings[i],value);
+ }
+ }
+ }
+
+/** Import the String Arrays */
+ for(i = 0; countof(upd_string_a) > i; ++i) {
+ gs_param_string_array value = string_a[i];
+ if(!upd_string_a[i]) continue;
+ UPD_PARAM_READ(param_read_string_array,upd_string_a[i],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_STRING_A;
+ UPD_MM_DEL_APARAM(string_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ string_a[i] = value;
+ } else {
+ UPD_MM_CPY_APARAM(string_a[i],value);
+ }
+ }
+ }
+
+/** Import the Float Arrays */
+ for(i = 0; countof(upd_float_a) > i; ++i) {
+ gs_param_float_array value = float_a[i];
+ if(!upd_float_a[i]) continue;
+ UPD_PARAM_READ(param_read_float_array,upd_float_a[i],value);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_FLOAT_A;
+ UPD_MM_DEL_PARAM(float_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ float_a[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(float_a[i],value);
+ }
+ }
+ }
+
+/**
+Prior to the call to the superclass-put_params, the memory-layout and
+the color-model needs adjustment. This is performed here, if any parameters
+were set.
+In addition to that, Resolution & Margin-Parameters are tested & adjusted.
+*/
+ if(0 < error) {
+
+ int *ip,*ip2,ncomp,nbits;
+
+ if(6 > int_a[IA_COLOR_INFO].size) {
+ UPD_MM_DEL_PARAM(int_a[IA_COLOR_INFO]);
+ UPD_MM_GET_ARRAY(int_a[IA_COLOR_INFO].data,6);
+ int_a[IA_COLOR_INFO].size = 6;
+ }
+ ip = (int *) int_a[IA_COLOR_INFO].data;
+
+ if(0 == ip[0]) { /* Try to obtain num_components */
+ switch(choice[C_MAPPER]) {
+ case MAP_GRAY: ip[0] = 1; break;
+ case MAP_RGBW: ip[0] = 3; break;
+ case MAP_RGB: ip[0] = 3; break;
+ case MAP_CMYK: ip[0] = 4; break;
+ case MAP_CMYKGEN: ip[0] = 4; break;
+ default: ip[0] = color_info.num_components; break;
+ }
+ } /* Try to obtain num_components */
+
+ switch(choice[C_MAPPER]) {
+ case MAP_GRAY: ncomp = 1; break;
+ case MAP_RGBW: ncomp = 4; break;
+ case MAP_RGB: ncomp = 3; break;
+ case MAP_CMYK: ncomp = 4; break;
+ case MAP_CMYKGEN: ncomp = 4; break;
+ default: ncomp = ip[0]; break;
+ }
+ if(UPD_CMAP_MAX < ncomp) ncomp = UPD_CMAP_MAX;
+
+ if(ncomp > int_a[IA_COMPBITS].size) { /* Default ComponentBits */
+ UPD_MM_GET_ARRAY(ip2,ncomp);
+ nbits = 32 / ncomp;
+ if(8 < nbits) nbits = 8;
+ for(i = 0; i < ncomp; ++i) ip2[i] = nbits;
+ UPD_MM_DEL_PARAM(int_a[IA_COMPBITS]);
+ int_a[IA_COMPBITS].data = ip2;
+ int_a[IA_COMPBITS].size = ncomp;
+ } /* Default ComponentBits */
+
+ if(ncomp > int_a[IA_COMPSHIFT].size) { /* Default ComponentShift */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) nbits += int_a[IA_COMPBITS].data[i];
+ UPD_MM_GET_ARRAY(ip2,ncomp);
+ for(i = 0; i < ncomp; ++i) {
+ ip2[i] = nbits - int_a[IA_COMPBITS].data[i];
+ nbits -= int_a[IA_COMPBITS].data[i];
+ }
+ UPD_MM_DEL_PARAM(int_a[IA_COMPSHIFT]);
+ int_a[IA_COMPSHIFT].data = ip2;
+ int_a[IA_COMPSHIFT].size = ncomp;
+ } /* Default ComponentShift */
+
+ if(0 == ip[1]) { /* Try to compute the depth */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) {
+ if(nbits < (int_a[IA_COMPBITS].data[i] +
+ int_a[IA_COMPSHIFT].data[i]))
+ nbits = int_a[IA_COMPBITS].data[i] +
+ int_a[IA_COMPSHIFT].data[i];
+ }
+ if( 1 >= nbits) nbits = 1;
+ else if( 2 >= nbits) nbits = 2;
+ else if( 4 >= nbits) nbits = 4;
+ else if( 8 >= nbits) nbits = 8;
+ else if(16 >= nbits) nbits = 16;
+ else if(24 >= nbits) nbits = 24;
+ else nbits = 32;
+
+ ip[1] = nbits;
+
+ } /* Try to compute the depth */
+
+ if(0 == ip[2]) { /* Number of Gray-Levels */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(nbits > 8) nbits = 8;
+ ip[2] = (1 << nbits) - 1;
+ } /* Number of Gray-Levels */
+
+ if(0 == ip[3] && 1 < ip[0]) { /* Number of Colors */
+ nbits = 0;
+ for(i = 0; i < ip[0]; ++i) nbits += int_a[IA_COMPBITS].data[i];
+ if(nbits > 8) nbits = 8;
+ ip[3] = (1 << nbits) - 1;
+ } /* Number of Colors */
+
+ if(0 == ip[4]) { /* Gray-Ramp */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(2 < nbits) ip[4] = 5;
+ else ip[4] = 2;
+ } /* Gray-Ramp */
+
+ if(0 == ip[5] && 1 < ip[0]) { /* Color-Ramp */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(2 < nbits) ip[5] = 5;
+ else ip[5] = 2;
+ } /* Color-Ramp */
+
+ udev->color_info.num_components = ip[0];
+ udev->color_info.depth = ip[1];
+ udev->color_info.max_gray = (gx_color_value) ip[2];
+ udev->color_info.max_color = (gx_color_value) ip[3];
+ udev->color_info.dither_grays = (gx_color_value) ip[4];
+ udev->color_info.dither_colors = (gx_color_value) ip[5];
+
+/*
+ * Now we're dealing with the Resolution- & Margin-Stuff
+ * (This is close to be a bad-nasty-hack-hack)
+ */
+ if((0 == param_read_float_array(plist,"HWResolution",&mfa)) &&
+ (2 == mfa.size) && (0 != mfa.data)) {
+ udev->MarginsHWResolution[0] = mfa.data[0];
+ udev->MarginsHWResolution[1] = mfa.data[1];
+ } else {
+ udev->MarginsHWResolution[0] = udev->HWResolution[0];
+ udev->MarginsHWResolution[1] = udev->HWResolution[1];
+ }
+
+ if((0 == param_read_float_array(plist,".HWMargins",&mfa)) &&
+ (4 == mfa.size) && (0 != mfa.data)) {
+ udev->Margins[0] = -mfa.data[0] * udev->MarginsHWResolution[0] / 72.0;
+ udev->Margins[1] = -mfa.data[3] * udev->MarginsHWResolution[1] / 72.0;
+ }
+ } /* Change the color-Info */
+
+/* Call the superclass-put_params now */
+ code = gdev_prn_put_params((gx_device *)udev,plist);
+ if(0 > code) error = code;
+
+/**
+If the superclass-"put_params" went o.k. too, then the new parameters are
+transferred into the device-structure. In the case of "uniprint", this may
+
+ 1. Close the device, which might fail.
+ 2. Allocate new memory for the upd-specific structure, that might fail too.
+
+*/
+/* *HGS* recognize a changed device geometry */
+ if( udev->upd && /* HGS */
+ ((udev->width != udev->upd->pdwidth) || /* HGS */
+ (udev->height != udev->upd->pdheight) )) /* HGS */
+ error |= UPD_PUT_CHANGEDSIZE; /* HGS */
+
+ if(0 < error && udev->is_open) {
+ code = gs_closedevice((gx_device *)udev);
+ if(0 > code) error = code;
+ }
+
+ if(0 < error) { /* Actually something loaded without error */
+
+ if(!(upd = udev->upd)) {
+ UPD_MM_GET_ARRAY(udev->upd,1);
+ upd = udev->upd;
+ } else {
+ UPD_MM_DEL_ARRAY(upd->choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(upd->ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(upd->int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+ }
+
+ upd->choice = choice;
+ upd->flags = flags;
+ upd->ints = ints;
+ upd->int_a = int_a;
+ upd->strings = strings;
+ upd->string_a = string_a;
+ upd->float_a = float_a;
+
+ if(0 < error) error = 0;
+
+ } else {
+
+ udev->Margins[0] = Margins[0];
+ udev->Margins[1] = Margins[1];
+ udev->MarginsHWResolution[0] = MarginsHWResolution[0];
+ udev->MarginsHWResolution[1] = MarginsHWResolution[1];
+
+ udev->color_info = color_info;
+ UPD_MM_DEL_ARRAY(choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+
+ }
+
+/*
+ * upd_put_params keeps the Procedures upd to date
+ */
+
+ upd_procs_map(udev);
+
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ fprintf(stderr,"RETURN: %d = upd_put_params(0x%05lx,0x%05lx)\n",
+ error,(long) udev, (long) plist);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_cmyk_icolor: KCMY->KCMY-Index Mapping */
+/* ------------------------------------------------------------------- */
+/**
+The next Routines, that follow, are the color-mapping routines.
+GHOSTSCRIPT talks about "gx_color_values" and the driver has
+to merge the 1, 3 or four values into up to 32 Bits, that means
+it is necessary to do some truncation and shifting. For the truncation
+"uniprint" uses the internal function "upd_truncate" and "upd_expand"
+reverses this in the reverse-mapping procedures.
+*/
+
+private gx_color_index
+upd_cmyk_icolor(gx_device *pdev,
+ gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+
+/**
+All 4-Component-Modi have to deal with the Problem, that a value
+with all bits set can be produced, which is treated as an error-return
+from the mapping-functions. But with RGBW or KCMY, there is a neat
+trick: Grayscale are transferred as RGB/CMY=0 and holding Data only
+in the W- or K-Component.
+*/
+
+ if((c == m) && (m == y)) {
+
+ rv = upd_truncate(upd,0,c > k ? c : k);
+
+ } else {
+
+ rv = upd_truncate(upd,0,k) | upd_truncate(upd,1,c)
+ | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+"cmyk_icolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_icolor_rgb: Stored KCMY back to a RGB */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_icolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_value c,m,y,k;
+
+/*
+ * Expand to the Component-Values
+ */
+ k = upd_expand(upd,0,color);
+ c = upd_expand(upd,1,color);
+ m = upd_expand(upd,2,color);
+ y = upd_expand(upd,3,color);
+
+/*
+ * Then Invert and subtract K from the colors
+ */
+ prgb[0] = gx_max_color_value - c;
+ if(prgb[0] > k) prgb[0] -= k;
+ else prgb[0] = 0;
+
+ prgb[1] = gx_max_color_value - m;
+ if(prgb[1] > k) prgb[1] -= k;
+ else prgb[1] = 0;
+
+ prgb[2] = gx_max_color_value - y;
+ if(prgb[2] > k) prgb[2] -= k;
+ else prgb[2] = 0;
+
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "icolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_1color: Grayscale-RGB->Grayscale-index-Mapping */
+/* ------------------------------------------------------------------- */
+
+private gx_color_index
+upd_rgb_1color(gx_device *pdev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+
+ rv = upd_truncate(upd,0,r);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "rgb_1color: (%5.1f,%5.1f,%5.1f) : (%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_1color_rgb: reversal of the above */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_1color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+/*
+ * Actual task: expand to full range of gx_color_value
+ */
+ prgb[0] = upd_expand(upd,0,color);
+
+ prgb[2] = prgb[1] = prgb[0];
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,"1color_rgb: 0x%0*lx -> %5.1f -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_3color: component-wise RGB->RGB-Mapping */
+/* ------------------------------------------------------------------- */
+
+private gx_color_index
+upd_rgb_3color(gx_device *pdev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+
+ rv = upd_truncate(upd,0,r) | upd_truncate(upd,1,g) | upd_truncate(upd,2,b);
+ if(rv == gx_no_color_index) rv ^= 1;
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "rgb_3color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_3color_rgb: reversal of the above */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_3color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+
+ prgb[0] = upd_expand(upd,0,color);
+ prgb[1] = upd_expand(upd,1,color);
+ prgb[2] = upd_expand(upd,2,color);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "3color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_4color: Create an WRGB-Index from RGB */
+/* ------------------------------------------------------------------- */
+
+private gx_color_index
+upd_rgb_4color(gx_device *pdev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+
+ if((r == g) && (g == b)) {
+
+ rv = upd_truncate(upd,0,r);
+
+ } else {
+
+ gx_color_value w = g < r ? g : r; w = w < b ? w : b; /* Minimum */
+
+ rv = upd_truncate(upd,0,w) | upd_truncate(upd,1,r) |
+ upd_truncate(upd,2,g) | upd_truncate(upd,3,b);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "rgb_4color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+/* ------------------------------------------------------------------- */
+/* upd_4color_rgb: Stored WRGB-Index back to a RGB */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_4color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+
+/*
+ * Expand to the Component-Values
+ */
+ prgb[0] = upd_expand(upd,1,color);
+ prgb[1] = upd_expand(upd,2,color);
+ prgb[2] = upd_expand(upd,3,color);
+
+/* Revert our Grayscale-Trick: */
+ if(!(prgb[0] || prgb[1] || prgb[2]))
+ prgb[0] = prgb[1] = prgb[2] = upd_expand(upd,0,color);
+
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "4color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_cmyk_kcolor: KCMY->KCMY-Index Mapping with Black Generation */
+/* ------------------------------------------------------------------- */
+
+private gx_color_index
+upd_cmyk_kcolor(gx_device *pdev,
+ gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value black;
+
+ if((c == m) && (m == y)) {
+
+ black = c > k ? c : k;
+ rv = upd_truncate(upd,0,black);
+
+ } else {
+
+ if(k) {
+ black = k;
+ } else {
+ black = c < m ? c : m;
+ black = black < y ? black : y;
+ }
+
+ rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c)
+ | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+"cmyk_kcolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_kcolor_rgb: Stored CMY+generated K back to a RGB */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_kcolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_value c,m,y,k;
+
+/*
+ * Expand to the Component-Values
+ */
+ k = upd_expand(upd,0,color);
+ c = upd_expand(upd,1,color);
+ m = upd_expand(upd,2,color);
+ y = upd_expand(upd,3,color);
+
+/*
+ * Check for plain Gray-Values
+ */
+ if(!(c | m | y )) {
+
+ prgb[2] = prgb[1] = prgb[0] = gx_max_color_value - k;
+
+ } else {
+ prgb[0] = gx_max_color_value - c;
+ prgb[1] = gx_max_color_value - m;
+ prgb[2] = gx_max_color_value - y;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ fprintf(stderr,
+ "kcolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* NOTE: Beyond this point only "uniprint"-special-items. */
+/* ------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------- */
+/* Return the gx_color_value for a given component */
+/* ------------------------------------------------------------------- */
+
+private gx_color_value
+upd_expand(upd_pc upd,int i,uint32 ci)
+{
+ const updcmap_pc cmap = upd->cmap + i; /* Writing-Shortcut */
+
+ ci = (ci >> cmap->bitshf) & cmap->bitmsk; /* Extract the component */
+ if(!cmap->rise) ci = cmap->bitmsk - ci; /* Invert, if necessary */
+/* no Truncation/Expansion on full range */
+ if(gx_color_value_bits > cmap->bits) return cmap->code[ci];
+ else return (gx_color_value) ci;
+}
+/* That's simple, isn't it? */
+
+/* ------------------------------------------------------------------- */
+/* Truncate a gx_color_value to the desired number of bits. */
+/* ------------------------------------------------------------------- */
+
+private uint32
+upd_truncate(upd_pc upd,int i,gx_color_value v) {
+ const updcmap_pc cmap = upd->cmap + i;
+ int32 s; /* step size */
+ gx_color_value *p; /* value-pointer */
+
+ if(0 == cmap->bits) { /* trivial case */
+
+ v = 0;
+
+ } else if(gx_color_value_bits > cmap->bits) { /* really truncate ? */
+
+ p = cmap->code + ((cmap->bitmsk + 1) >> 1);
+ s = ((cmap->bitmsk + 1) >> 2);
+/*
+ * Perform search in monotonic code-array
+ */
+ while(s > 0) {
+ if(v > *p) { /* we're below */
+ p += s;
+ } else if(v < p[-1]) { /* we're ahead for sure */
+ p -= s;
+ } else {
+/* years ago, i knew what this was good for */
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ break;
+ }
+ s >>= 1;
+ }
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ v = p - cmap->code;
+ }
+
+ if(!cmap->rise) v = cmap->bitmsk - v; /* Again reverse, if necessary */
+
+ return ((uint32) v) << cmap->bitshf;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_map: install the color-mapping */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_map(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int imap;
+
+/** _always_ initialize crucial Values! */
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) upd->cmap[imap].code = NULL;
+ upd->ncomp = 0;
+
+/** There should not be an error yet */
+ if(B_ERROR & upd->flags) imap = 0;
+
+/** Establish the xfer-Indices */
+ if(imap) {
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ upd->cmap[imap].xfer = -1;
+ upd->cmap[imap].bits = 0;
+ }
+ switch(upd->choice[C_MAPPER]) {
+ case MAP_GRAY:
+ upd->cmap[0].xfer = FA_WXFER;
+ break;
+ case MAP_RGBW:
+ upd->cmap[0].xfer = FA_WXFER;
+ upd->cmap[1].xfer = FA_RXFER;
+ upd->cmap[2].xfer = FA_GXFER;
+ upd->cmap[3].xfer = FA_BXFER;
+ break;
+ case MAP_RGB:
+ upd->cmap[0].xfer = FA_RXFER;
+ upd->cmap[1].xfer = FA_GXFER;
+ upd->cmap[2].xfer = FA_BXFER;
+ break;
+ case MAP_CMYK:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ case MAP_CMYKGEN:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(upd_choice[C_MAPPER][0])
+ fprintf(stderr,
+ "upd_open_map: unsupported %s=%d\n",
+ upd_choice[C_MAPPER][0],upd->choice[C_MAPPER]);
+ else
+ fprintf(stderr,
+ "upd_open_map: unsupported choce[%d]=%d\n",
+ C_MAPPER,upd->choice[C_MAPPER]);
+#endif
+ imap = 0;
+ break;
+ }
+ }
+
+
+/** The bit number sould be positive & fit into the storage */
+
+ if(imap) { /* Check number of Bits & Shifts */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ uint32 used = 0,bitmsk;
+#endif
+ bool success = true;
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ if(0 > upd->cmap[imap].xfer) continue;
+
+ if((0 > upd->int_a[IA_COMPBITS].data[imap]) ||
+ (gx_color_value_bits < upd->int_a[IA_COMPBITS].data[imap]) ||
+ (0 > upd->int_a[IA_COMPSHIFT].data[imap]) ||
+ (upd->int_a[IA_COMPBITS].data[imap] >
+ (udev->color_info.depth - upd->int_a[IA_COMPSHIFT].data[imap]))) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_map: %d Bits << %d is illegal for %d. Component\n",
+ upd->int_a[IA_COMPBITS].data[imap],
+ upd->int_a[IA_COMPSHIFT].data[imap],imap+1);
+#endif
+
+ success = false;
+
+
+ } else {
+
+ int n;
+ const float *now;
+ float last;
+
+ if((NULL == upd->float_a[upd->cmap[imap].xfer].data) ||
+ (2 > upd->float_a[upd->cmap[imap].xfer].size) ) {
+ float *fp;
+ UPD_MM_DEL_PARAM(upd->float_a[upd->cmap[imap].xfer]);
+ UPD_MM_GET_ARRAY(fp,2);
+ fp[0] = 0.0;
+ fp[1] = 1.0;
+ upd->float_a[upd->cmap[imap].xfer].data = fp;
+ upd->float_a[upd->cmap[imap].xfer].size = 2;
+ }
+ n = upd->float_a[upd->cmap[imap].xfer].size-1;
+ now = upd->float_a[upd->cmap[imap].xfer].data;
+ last = now[n];
+
+ if( *now < last) { /* Rising */
+ last = *now++;
+ while(n--) {
+ if(last >= *now) break;
+ last = *now++;
+ }
+ } else if(*now > last) { /* Falling */
+ last = *now++;
+ while(n--) {
+ if(last <= *now) break;
+ last = *now++;
+ }
+ } /* Monotony-check */
+
+ if(0 <= n) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_map: %d. Component has non monoton Xfer\n",imap+1);
+#endif
+ success = false;
+
+ } else {
+
+#if UPD_MESSAGES & UPD_M_WARNING
+
+ bitmsk = ((uint32) 1 << upd->int_a[IA_COMPBITS].data[imap]) -1;
+ bitmsk <<= upd->int_a[IA_COMPSHIFT].data[imap];
+
+ if(used & bitmsk) fprintf(stderr,
+ "upd_open_map: %d. Component overlaps with others\n",imap+1);
+
+ used |= bitmsk;
+#endif
+ }
+ }
+ }
+
+ if(!success) imap = 0;
+
+ } /* Check number of Bits */
+
+/** Do the allocation */
+
+ if(imap) {
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ if(0 > upd->cmap[imap].xfer) continue;
+
+ upd->cmap[imap].bits = upd->int_a[IA_COMPBITS].data[imap];
+ upd->cmap[imap].bitshf = upd->int_a[IA_COMPSHIFT].data[imap];
+ upd->cmap[imap].bitmsk = 1;
+ upd->cmap[imap].bitmsk <<= upd->cmap[imap].bits;
+ upd->cmap[imap].bitmsk -= 1;
+ upd->cmap[imap].rise =
+ upd->float_a[upd->cmap[imap].xfer].data[0] <
+ upd->float_a[upd->cmap[imap].xfer].data[
+ upd->float_a[upd->cmap[imap].xfer].size-1] ?
+ true : false;
+ upd->cmap[imap].code = gs_malloc(sizeof(upd->cmap[imap].code[0]),
+ upd->cmap[imap].bitmsk+1,"upd/code");
+ if(!upd->cmap[imap].code) break;
+ }
+
+ if(UPD_CMAP_MAX > imap) {
+
+ imap = 0;
+
+#if UPD_MESSAGES & UPD_M_ERROR
+ fprintf(stderr,"upd_open_map: could not allocate code-arrays\n");
+# endif
+
+ }
+ }
+
+/** then fill the code-arrays */
+
+ if(imap) {
+/*
+ * Try making things easier: (than with stcolor)
+ * normalize values to 0.0/1.0-Range
+ * X-Axis: Color-Values (implied)
+ * Y-Values: Indices (given)
+ */
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+
+ const updcmap_p cmap = upd->cmap + imap;
+ uint32 ly,iy;
+ float ystep,xstep,fx,fy;
+
+/* Variables & Macro for Range-Normalization */
+ double offset,scale;
+#define XFVAL(I) ((upd->float_a[cmap->xfer].data[I]-offset)*scale)
+
+ if(0 > cmap->xfer) continue;
+
+ cmap->code[cmap->bitmsk] = gx_max_color_value;
+
+ if(!cmap->bits) continue;
+
+ offset = upd->float_a[cmap->xfer].data[0];
+ if( 0.0 > offset) offset = 0.0;
+ else if(1.0 < offset) offset = 1.0;
+
+ scale = upd->float_a[cmap->xfer].data[upd->float_a[cmap->xfer].size-1];
+ if( 0.0 > scale ) scale = 0.0;
+ else if(1.0 < scale ) scale = 1.0;
+
+ if(scale != offset) scale = 1.0 / (scale - offset);
+ else scale = 0.0;
+
+/* interpolate */
+ ystep = (float) 1.0 / (float) cmap->bitmsk;
+ xstep = (float) 1.0 / (float)(upd->float_a[cmap->xfer].size - 1);
+
+ iy = 0;
+ for(ly = 0; ly <= cmap->bitmsk; ++ly) {
+
+ fy = ystep * ly; /* Target-Value */
+
+ while(((iy+1) < upd->float_a[cmap->xfer].size) &&
+ (fy > XFVAL(iy+1))) ++iy;
+
+ fx = iy + (fy - XFVAL(iy))/(XFVAL(iy+1) - XFVAL(iy));
+
+ fx *= xstep * gx_max_color_value;
+
+ fx = fx < 0.0 ? 0.0 :
+ (fx > gx_max_color_value ? gx_max_color_value : fx);
+
+ cmap->code[ly] = fx;
+ if((fx - cmap->code[ly]) >= 0.5) cmap->code[ly] += 1;
+ }
+
+#undef XFVAL
+
+ }
+ }
+
+/** If we're ok, massage upd->ncomp */
+
+ if(imap) {
+ switch(upd->choice[C_MAPPER]) {
+ case MAP_GRAY:
+ if(1 > imap) imap = 0;
+ upd->ncomp = 1;
+ break;
+ case MAP_RGBW: /* RGB->RGBW */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_RGB: /* Plain RGB */
+ if(3 > imap) imap = 0;
+ upd->ncomp = 3;
+ break;
+ case MAP_CMYK: /* Plain KCMY */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_CMYKGEN: /* KCMY with black-generation */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+
+ default:
+ imap = 0;
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open: Mapping %d unknown\n",upd->choice[C_MAPPER]);
+#endif
+
+ break;
+ }
+ }
+
+
+/** If unsuccesful, install the default routines */
+
+ if(!imap) {
+ upd_close_map(udev);
+ } else {
+ upd->flags |= B_MAP;
+ upd_procs_map(udev);
+ }
+
+ return imap ? 1 : -1;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_procs_map: (de-) install the color-mapping-procedures */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_procs_map(upd_device *udev)
+{
+ int imap;
+
+ if( udev->upd &&
+ (udev->upd->flags & B_MAP)) imap = udev->upd->choice[C_MAPPER];
+ else imap = 0;
+
+ switch(imap) {
+ case 1: /* Grayscale -> Grayscale */
+ set_dev_proc(udev,map_rgb_color, upd_rgb_1color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_1color_rgb);
+ break;
+ case 2: /* RGB->RGBW */
+ set_dev_proc(udev,map_rgb_color, upd_rgb_4color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_4color_rgb);
+ break;
+ case 3: /* Plain RGB */
+ set_dev_proc(udev,map_rgb_color, upd_rgb_3color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_3color_rgb);
+ break;
+ case 4: /* Plain KCMY */
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,upd_cmyk_icolor);
+ set_dev_proc(udev,map_color_rgb, upd_icolor_rgb);
+ break;
+ case 5: /* KCMY with black-generation */
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,upd_cmyk_kcolor);
+ set_dev_proc(udev,map_color_rgb, upd_kcolor_rgb);
+ break;
+ default:
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, gx_default_map_color_rgb);
+ break;
+ }
+ return 0;
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_map: remove color mapping */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_close_map(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int imap;
+
+ if(upd) {
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+
+ if(upd->cmap[imap].code)
+ gs_free(upd->cmap[imap].code,sizeof(upd->cmap[imap].code[0]),
+ upd->cmap[imap].bitmsk+1,"upd/code");
+ upd->cmap[imap].code = NULL;
+
+ upd->cmap[imap].bitmsk = 0;
+ upd->cmap[imap].bitshf = 0;
+ upd->cmap[imap].bits = 0;
+ upd->cmap[imap].rise = false;
+ }
+ upd->flags &= ~B_MAP;
+ }
+
+ upd_procs_map(udev);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* Functions for the rendering of data */
+/* ------------------------------------------------------------------- */
+
+/**
+Inside the main-upd-type are a "valbuf" and some unidentified
+pointers. This stuff is used in conjunction with the rendering,
+which is the process of converting gx_color_indices into something
+suitable for the device.
+
+*/
+
+/* ------------------------------------------------------------------- */
+/* upd_open_render: Initialize rendering */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_open_render(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp;
+
+/** Reset everything related to rendering */
+ upd->flags &= ~B_RENDER;
+ upd->valbuf = NULL;
+ upd->nvalbuf = 0;
+ upd->render = NULL;
+ upd->start_render = NULL;
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
+
+ if( (B_BUF | B_MAP) ==
+ ((B_BUF | B_MAP | B_ERROR) & upd->flags)) {
+
+/** Establish the renderingwidth in upd */
+ upd->rwidth = upd->gswidth;
+ if((0 < upd->ints[I_PWIDTH]) &&
+ (upd->gswidth > upd->ints[I_PWIDTH]) )
+ upd->rwidth = upd->ints[I_PWIDTH];
+
+/** Call the Render-specific Open-Function */
+ switch(upd->choice[C_RENDER]) {
+ case RND_FSCOMP:
+ upd_open_fscomp(udev);
+ break;
+ case RND_FSCMYK:
+ upd_open_fscmyk(udev);
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,"upd_open_render: Unknown rendering type %d\n",
+ upd->choice[C_RENDER]);
+#endif
+ break;
+ }
+ }
+
+ if(B_RENDER != ((B_ERROR | B_RENDER) & upd->flags))
+ upd_close_render(udev);
+
+ return;
+}
+
+
+/* ------------------------------------------------------------------- */
+/* upd_close_render: Deinitialize rendering */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_close_render(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ if(upd) {
+ int icomp;
+
+ if((upd->render == upd_fscomp) ||
+ (upd->render == upd_fscmyk) ) upd_close_fscomp(udev);
+
+ if((0 < upd->nvalbuf) && upd->valbuf)
+ gs_free(upd->valbuf,upd->nvalbuf,sizeof(upd->valbuf[0]),"upd/valbuf");
+ upd->valbuf = NULL;
+ upd->nvalbuf = 0;
+
+ upd->flags &= ~B_RENDER;
+ upd->render = NULL;
+ upd->start_render = NULL;
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
+
+ }
+ return;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_fscomp: Initialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+#if UPD_MESSAGES & UPD_M_FSBUF
+static int32 fs_emin[UPD_VALPTR_MAX],fs_emax[UPD_VALPTR_MAX];
+#endif
+private void
+upd_open_fscomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp,order[UPD_CMAP_MAX];
+
+#if UPD_MESSAGES & UPD_M_FSBUF
+ for(icomp = 0; UPD_VALPTR_MAX < icomp; ++icomp)
+ fs_emin[icomp] = fs_emax[icomp] = 0;
+#endif
+
+ icomp = upd->ncomp;
+ if(0 < upd->ints[I_NCOMP]) icomp = upd->ints[I_NCOMP];
+
+ if((0 >= icomp) ||
+ (UPD_VALPTR_MAX < icomp) ||
+ (UPD_CMAP_MAX < icomp) ) icomp = 0;
+ else upd->ncomp = icomp;
+
+/**
+This Version of the FS-algorithm works on the mapped components, but
+the printing-order might be different from the order dictated by the
+mapping-routines. The optional RNDCOMP-Array is used for that. The
+initial test checks it's integrity.
+*/
+ if(icomp) {
+ if(upd->ncomp <= upd->int_a[IA_COMPORDER].size) { /* Reordering */
+ bool success = true;
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+ order[icomp] = upd->int_a[IA_COMPORDER].data[icomp];
+ if((0 > order[icomp]) ||
+ (UPD_CMAP_MAX <= order[icomp]) ) {
+ success = false;
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_fscomp: %d is illegal component-index\n",
+ order[icomp]);
+#endif
+ }
+ }
+ if(!success) icomp = 0;
+ } else { /* Default-Ordering */
+ for(icomp = 0; UPD_CMAP_MAX > icomp; ++icomp) order[icomp] = icomp;
+ } /* Ordering defined */
+ }
+
+/**
+If anything was ok. up to now, memory get's allocated.
+*/
+ if(icomp) {
+
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+ upd->valptr[icomp] = gs_malloc(1,sizeof(updcomp_t),"upd/fscomp");
+ if(NULL == upd->valptr[icomp]) {
+#if UPD_MESSAGES & UPD_M_ERROR
+ fprintf(stderr,
+ "upd_open_fscomp: could not allocate %d. updcomp\n",
+ icomp);
+#endif
+ icomp = 0;
+ break;
+ }
+ }
+ }
+
+ if(icomp) {
+ uint need;
+
+ need = (2 + upd->rwidth) * upd->ncomp;
+ upd->valbuf = gs_malloc(need,sizeof(upd->valbuf[0]),"upd/valbuf");
+
+ if(upd->valbuf) {
+ upd->nvalbuf = need;
+ memset(upd->valbuf,0,need*sizeof(upd->valbuf[0]));
+ } else {
+#if UPD_MESSAGES & UPD_M_ERROR
+ fprintf(stderr,
+ "upd_open_fscomp: could not allocate %u words for valbuf\n",need);
+#endif
+ icomp = 0;
+ }
+ }
+
+/* Still happy? then compute component-values */
+
+ if(icomp) {
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+
+ const updcomp_p comp = upd->valptr[icomp];
+ const int32 nsteps = upd->cmap[order[icomp]].bitmsk;
+ float ymin,ymax;
+ int32 highmod,highval;
+ int i;
+
+ comp->threshold = nsteps;
+ comp->spotsize = nsteps;
+ comp->offset = 0;
+ comp->scale = 1;
+ comp->cmap = order[icomp];
+ upd->cmap[comp->cmap].comp = icomp;
+ comp->bits = upd->cmap[comp->cmap].bits;
+ comp->bitshf = upd->cmap[comp->cmap].bitshf;
+ comp->bitmsk = upd->cmap[comp->cmap].bitmsk;
+
+ if(!nsteps) continue; /* A 0-Bit component is legal! */
+
+ if(upd->cmap[comp->cmap].rise) {
+ ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
+ ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[
+ upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
+ } else {
+ ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
+ ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[
+ upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
+ }
+
+ if(0.0 > ymin) {
+ ymin = 0.0;
+ if(0.0 > ymax) ymax = 1.0 / (float) (nsteps+1);
+ }
+ if(1.0 < ymax) ymax = 1.0;
+
+ comp->spotsize = ((int32) 1 << 28) - 1;
+
+ for(i = 0; i < 32; ++i) { /* Attempt Ideal */
+
+ highval = (ymax-ymin) * (double) comp->spotsize + 0.5;
+
+ if(!(highmod = highval % nsteps)) break; /* Gotcha */
+
+ highval += nsteps - highmod;
+ comp->spotsize = (double) highval / (ymax-ymin) + 0.5;
+
+ if(!(comp->spotsize % 2)) comp->spotsize++;
+
+ } /* Attempt Ideal */
+
+ comp->offset = ymin * (double) comp->spotsize + (double) 0.5;
+ comp->scale = highval / nsteps;
+ comp->threshold = comp->spotsize / 2;
+
+#if UPD_MESSAGES & UPD_M_SETUP
+ fprintf(stderr,
+ "Values for %d. Component after %d iterations\n",comp->cmap+1,i);
+ fprintf(stderr,
+ "steps: %10ld, Bits: %d\n",(long) comp->bitmsk,comp->bits);
+ fprintf(stderr,
+ "xfer: %10d Points, %s\n",
+ upd->float_a[upd->cmap[comp->cmap].xfer].size,
+ upd->cmap[comp->cmap].rise ? "rising" : "falling");
+ fprintf(stderr,
+ "offset: %10d 0x%08x\n",comp->offset,comp->offset);
+ fprintf(stderr,
+ "scale: %10d 0x%08x\n",comp->scale,comp->scale);
+ fprintf(stderr,
+ "threshold: %10d 0x%08x\n",comp->threshold,comp->threshold);
+ fprintf(stderr,
+ "spotsize: %10d 0x%08x\n",comp->spotsize,comp->spotsize);
+#endif
+ }
+ }
+/**
+Optional Random Initialization of the value-Buffer
+*/
+ if(icomp && !(B_FSZERO & upd->flags)) {
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ const updcomp_p comp = upd->valptr[icomp];
+ int i;
+ int32 lv = INT32_MAX, hv = INT32_MIN, v;
+ float scale;
+ for(i = icomp; i < upd->nvalbuf; i += upd->ncomp) {
+ v = rand();
+ if(lv > v) lv = v;
+ if(hv < v) hv = v;
+ upd->valbuf[i] = v;
+ }
+ scale = (float) comp->threshold / (float) (hv - lv);
+ lv += comp->threshold / (2*scale);
+ for(i = icomp; i < upd->nvalbuf; i += upd->ncomp)
+ upd->valbuf[i] = scale * (upd->valbuf[i] - lv);
+ }
+ }
+
+/**
+The render-Routine acts as an indicator, which render-close is to use!
+*/
+ upd->render = upd_fscomp;
+
+ if(icomp) upd->flags |= B_RENDER;
+ else upd->flags &= ~B_RENDER;
+
+ return;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_fscomp: Deinitialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_close_fscomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp;
+
+#if UPD_MESSAGES & UPD_M_FSBUF
+ if(upd && (upd->flags & B_RENDER)) {
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ updcomp_p comp = upd->valptr[icomp];
+ if(!comp) continue;
+ if(!comp->spotsize) continue;
+ fprintf(stderr,"%d. Component: %6.3f <= error <= %6.3f\n",
+ icomp+1,
+ (double) fs_emin[icomp] / (double) comp->spotsize,
+ (double) fs_emax[icomp] / (double) comp->spotsize);
+ }
+
+ }
+#endif
+
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) {
+ if(!upd->valptr[icomp]) continue;
+ gs_free(upd->valptr[icomp],1,sizeof(updcomp_t),"upd/fscomp");
+ upd->valptr[icomp] = NULL;
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_fscomp: Apply Floyd-Steinberg to each component */
+/* ------------------------------------------------------------------- */
+
+/**
+ With UPD_M_FSBUF Max/Min-Values for the Errors are computed
+*/
+#if UPD_MESSAGES & UPD_M_FSBUF
+#define FS_M_ROWERR(I) \
+ if(fs_emin[I] > rowerr[I]) fs_emin[I] = rowerr[I]; \
+ if(fs_emax[I] < rowerr[I]) fs_emax[I] = rowerr[I];
+#else
+#define FS_M_ROWERR(I) ;
+#endif
+/**
+ FS_GOAL computes the desired Pixel-Value
+*/
+#define FS_GOAL(Raw,I) \
+ pixel[I] = (int32)(Raw) * comp[I]->scale + comp[I]->offset \
+ + rowerr[I] + colerr[I] - ((colerr[I]+4)>>3); \
+ if( pixel[I] < 0) pixel[I] = 0; \
+ else if( pixel[I] > comp[I]->spotsize) pixel[I] = comp[I]->spotsize;
+
+/*
+ * Distribute the error: prev now next
+ * X 7/16 Y
+ * 3/16 5/16 1/16 Y+1
+ */
+#define FS_DIST(I) \
+ if(!first) rowerr[I-dir] += ((3*pixel[I]+8)>>4); /* 3/16 */ \
+ rowerr[I ] = ((5*pixel[I] )>>4) /* 5/16 */ \
+ + (( colerr[I]+4)>>3); /* 1/16 (rest) */ \
+ colerr[I ] = pixel[I] /* 8/16 (neu) */ \
+ - ((5*pixel[I] )>>4) \
+ - ((3*pixel[I]+8)>>4);
+/**
+ S_FSTEP adjusts the Indices (rowerr, bit and iword)
+*/
+#define S_FSTEP \
+ rowerr += dir; \
+ first = false; \
+ if(0 > dir) { /* Reverse */ \
+ if(!(bit <<= 1)) { bit = 0x01; ibyte--; }\
+ } else { /* Forward */ \
+ if(!(bit >>= 1)) { bit = 0x80; ibyte++; }\
+ } /* Inc/Dec Bit */
+
+private int
+upd_fscomp(upd_p upd)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
+ const updcomp_p *comp = (updcomp_p *) upd->valptr;
+ int32 *const pixel = upd->valbuf;
+ int32 *const colerr = pixel + upd->ncomp;
+ int32 *rowerr = colerr + upd->ncomp;
+ int pwidth = upd->rwidth;
+ int dir,ibyte;
+ uint32 ci;
+ byte bit;
+ bool first = true;
+/*
+ * Erase the component-Data
+ */
+ switch(upd->ncomp) {
+ case 4: memset(scan[3].bytes,0,upd->nbytes);
+ case 3: memset(scan[2].bytes,0,upd->nbytes);
+ memset(scan[1].bytes,0,upd->nbytes);
+ default: memset(scan[0].bytes,0,upd->nbytes);
+ }
+/*
+ * determine the direction
+ */
+ if(upd->flags & B_REVDIR) { /* This one reverse */
+
+ if(upd->flags & B_YFLIP) {
+ dir = upd->ncomp;
+ bit = 0x80;
+ ibyte = 0;
+ } else {
+ dir = -upd->ncomp;
+ rowerr += upd->ncomp * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlfwd(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlrev(upd);
+
+ } else { /* This one forward */
+
+ if(upd->flags & B_YFLIP) {
+ dir = -upd->ncomp;
+ rowerr += upd->ncomp * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ } else {
+ dir = upd->ncomp;
+ bit = 0x80;
+ ibyte = 0;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlrev(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlfwd(upd);
+
+ } /* reverse or forward */
+/*
+ * Toggle Direction, if not fixed
+ */
+ if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
+/*
+ * Skip over leading white-space
+ */
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_proc_pxlget((*fun)) = upd->pxlget;
+ byte *ptr = upd->pxlptr;
+ while((0 < pwidth) && !upd_pxlget(upd)) {
+ pwidth--;
+ fun = upd->pxlget;
+ ptr = upd->pxlptr;
+ S_FSTEP
+ }
+ upd->pxlget = fun;
+ upd->pxlptr = ptr;
+ }
+/*
+ * Process all Pixels
+ */
+ first = true;
+ while(0 < pwidth--) {
+/*
+ * Execute FS-Algorithm for each active component
+ */
+ ci = upd_pxlget(upd);
+ switch(upd->ncomp) {
+ case 4: FS_M_ROWERR(3)
+ FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
+ if(pixel[3] > comp[3]->threshold) { /* "Fire" */
+ pixel[3] -= comp[3]->spotsize;
+ scan[3].bytes[ibyte] |= bit;
+ } /* "Fire" */
+ FS_DIST(3)
+
+ case 3: FS_M_ROWERR(2)
+ FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
+ if(pixel[2] > comp[2]->threshold) { /* "Fire" */
+ pixel[2] -= comp[2]->spotsize;
+ scan[2].bytes[ibyte] |= bit;
+ } /* "Fire" */
+ FS_DIST(2)
+
+ FS_M_ROWERR(1)
+ FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
+ if(pixel[1] > comp[1]->threshold) { /* "Fire" */
+ pixel[1] -= comp[1]->spotsize;
+ scan[1].bytes[ibyte] |= bit;
+ } /* "Fire" */
+ FS_DIST(1)
+
+ default: FS_M_ROWERR(0)
+ FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
+ if(pixel[0] > comp[0]->threshold) { /* "Fire" */
+ pixel[0] -= comp[0]->spotsize;
+ scan[0].bytes[ibyte] |= bit;
+ } /* "Fire" */
+ FS_DIST(0)
+ }
+/*
+ * Adjust rowerr, bit & iword, depending on direction
+ */
+ S_FSTEP
+ }
+/*
+ * Finally call the limits-Routine
+ */
+ if(0 < upd->nlimits) upd_limits(upd,true);
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_fscmyk: Initialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_open_fscmyk(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ upd_open_fscomp(udev);
+
+ if((B_RENDER & upd->flags) &&
+ (4 == upd->ncomp) &&
+ (8 <= upd->cmap[0].bits) && (24 == upd->cmap[0].bitshf) &&
+ (8 <= upd->cmap[1].bits) && (16 == upd->cmap[1].bitshf) &&
+ (8 <= upd->cmap[2].bits) && ( 8 == upd->cmap[2].bitshf) &&
+ (8 <= upd->cmap[3].bits) && ( 0 == upd->cmap[3].bitshf) ) {
+ upd->render = upd_fscmyk;
+ } else {
+ upd->flags &= ~B_RENDER;
+ }
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_fscmyk: 32 Bit, K-CMY-Order Dithering */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_fscmyk(upd_p upd)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
+ int32 *const pixel = upd->valbuf;
+ const updcomp_p *comp = (updcomp_p *) upd->valptr;
+ int32 *const colerr = pixel + 4;
+ int32 *rowerr = colerr + 4;
+ int32 pwidth = upd->rwidth;
+ int dir,ibyte;
+ byte bit,*data;
+ bool first = false;
+/*
+ * Erase the component-Data
+ */
+ memset(scan[0].bytes,0,upd->nbytes);
+ memset(scan[1].bytes,0,upd->nbytes);
+ memset(scan[2].bytes,0,upd->nbytes);
+ memset(scan[3].bytes,0,upd->nbytes);
+
+/*
+ * determine the direction
+ */
+ if(upd->flags & B_REVDIR) { /* This one reverse */
+
+ if(!(upd->flags & B_FSWHITE)) {
+ data = upd->gsscan;
+ while(0 < pwidth && !*(uint32 *)data) pwidth--, data += 4;
+ if(0 >= pwidth) {
+ if(0 < upd->nlimits) upd_limits(upd,false);
+ return 0;
+ }
+ }
+
+ data = upd->gsscan + 4 * (upd->rwidth-1);
+
+ } else { /* This one forward */
+
+ if(!(upd->flags & B_FSWHITE)) {
+ data = upd->gsscan + 4 * (upd->rwidth-1);
+ while(0 < pwidth && !*(uint32 *)data) pwidth--, data -= 4;
+ if(0 >= pwidth) {
+ if(0 < upd->nlimits) upd_limits(upd,false);
+ return 0;
+ }
+ }
+
+ data = upd->gsscan;
+
+ } /* reverse or forward */
+/*
+ * Bits depend on FLIP & Direction
+ */
+ if(!(B_REVDIR & upd->flags) == !(B_YFLIP & upd->flags)) {
+ dir = 4;
+ bit = 0x80;
+ ibyte = 0;
+ } else {
+ dir = -4;
+ rowerr += 4 * (upd->rwidth-1);
+ bit = 0x80 >> ((upd->rwidth-1) & 7);
+ ibyte = (upd->rwidth-1) >> 3;
+ }
+
+/*
+ * Toggle Direction, if not fixed
+ */
+ if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
+/*
+ * Skip over leading white-space
+ */
+ if(!(upd->flags & B_FSWHITE)) {
+ while(0 < pwidth && !*((uint32 *)data)) {
+ pwidth--;
+ if(B_YFLIP & upd->flags) data -= dir;
+ else data += dir;
+ S_FSTEP
+ }
+ }
+/*
+ * Process all Pixels
+ */
+ first = true;
+ while(0 < pwidth--) {
+/*
+ * Compute the Black-Value first
+ */
+ FS_M_ROWERR(upd->cmap[0].comp) FS_GOAL(data[0],upd->cmap[0].comp);
+
+/*
+ * Decide wether this is a color value
+ */
+ if(data[1] || data[2] || data[3]) {
+
+ FS_M_ROWERR(upd->cmap[1].comp) FS_GOAL(data[1],upd->cmap[1].comp)
+ FS_M_ROWERR(upd->cmap[2].comp) FS_GOAL(data[2],upd->cmap[2].comp)
+ FS_M_ROWERR(upd->cmap[3].comp) FS_GOAL(data[3],upd->cmap[3].comp)
+/*
+ * if black fires, then all other components fire logically too
+ */
+ if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
+
+ pixel[0] -= comp[0]->spotsize;
+ pixel[1] -= comp[1]->spotsize;
+ pixel[2] -= comp[2]->spotsize;
+ pixel[3] -= comp[3]->spotsize;
+ scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
+
+/*
+ * if black is below threshold, only components with larger data-values
+ * are allowed to fire
+ */
+ } else { /* Restricted firing */
+
+ if(( data[0] < data[1]) &&
+ (pixel[upd->cmap[1].comp] >
+ comp[upd->cmap[1].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[1].comp] -= comp[upd->cmap[1].comp]->spotsize;
+ scan[upd->cmap[1].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ if(( data[0] < data[2]) &&
+ (pixel[upd->cmap[2].comp] >
+ comp[upd->cmap[2].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[2].comp] -= comp[upd->cmap[2].comp]->spotsize;
+ scan[upd->cmap[2].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ if(( data[0] < data[3]) &&
+ (pixel[upd->cmap[3].comp] >
+ comp[upd->cmap[3].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[3].comp] -= comp[upd->cmap[3].comp]->spotsize;
+ scan[upd->cmap[3].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ } /* Fire-Mode */
+
+/*
+ * Handle Color-Errors
+ */
+ FS_DIST(upd->cmap[3].comp)
+ FS_DIST(upd->cmap[2].comp)
+ FS_DIST(upd->cmap[1].comp)
+
+ } else if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
+ scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
+ pixel[upd->cmap[0].comp] -= comp[upd->cmap[0].comp]->spotsize;
+ }
+
+ FS_DIST(upd->cmap[0].comp)
+/*
+ * Adjust bit & iword, depending on direction
+ */
+ S_FSTEP
+ if(upd->flags & B_YFLIP) data -= dir;
+ else data += dir;
+ }
+/*
+ * Finally call the limits-Routine
+ */
+ if(0 < upd->nlimits) upd_limits(upd,true);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------- */
+/* upd_open_writer: Initialize rendering */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_writer(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ bool success = true;
+
+
+/** Reset the crucial values */
+ upd->start_writer = NULL;
+ upd->writer = NULL;
+ upd->scnbuf = NULL;
+ upd->nscnbuf = 0;
+ upd->nbytes = 0;
+ upd->nlimits = 0;
+ upd->outbuf = NULL;
+ upd->noutbuf = 0;
+
+/** Rendering should be succesfully initialized */
+ if(B_RENDER != ((B_RENDER | B_ERROR) & upd->flags))
+ success = false;
+
+/** Massage some Parameters */
+ if(success) {
+
+/* Make sure, that Pass & Pin-Numbers are at least 1 */
+ if(1 > upd->ints[I_NYPASS]) upd->ints[I_NYPASS] = 1;
+ if(1 > upd->ints[I_NXPASS]) upd->ints[I_NXPASS] = 1;
+ if(1 > upd->ints[I_PINS2WRITE]) upd->ints[I_PINS2WRITE] = 1;
+
+ if((upd->ints[I_NXPASS] * upd->ints[I_NYPASS]) > upd->ints[I_NPASS])
+ upd->ints[I_NPASS] = upd->ints[I_NXPASS] * upd->ints[I_NYPASS];
+
+/* Create Default noWeave-Feeds */
+
+ if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
+ int ix,iy,*ip;
+ UPD_MM_DEL_PARAM(upd->int_a[IA_STD_DY]);
+ UPD_MM_GET_ARRAY(ip,upd->ints[I_NPASS]);
+ upd->int_a[IA_STD_DY].data = ip;
+ upd->int_a[IA_STD_DY].size = upd->ints[I_NPASS];
+
+ for(iy = 1; iy < upd->ints[I_NYPASS]; ++iy) {
+ for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
+ *ip++ = 1;
+ }
+ for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
+ *ip = upd->ints[I_NYPASS] * upd->ints[I_PINS2WRITE]
+ - upd->ints[I_NYPASS] + 1;
+
+ upd->ints[I_BEG_Y] = 0;
+ upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
+ upd->ints[I_PHEIGHT] : upd->gsheight;
+ }
+
+/* Adjust BEG_Y */
+ if(0 >= upd->ints[I_BEG_Y]) {
+ if(0 < upd->int_a[IA_BEG_DY].size) {
+ int i,sum = 0;
+ for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
+ sum += upd->int_a[IA_BEG_DY].data[i];
+ upd->ints[I_BEG_Y] = sum;
+ } else {
+ upd->ints[I_BEG_Y] = 0;
+ }
+ }
+
+/* Adjust END_Y */
+/* Arrgh, I knew, why I refused to provide defaults for crucial */
+/* parameters in uniprint. But o.k. it's nice for size-changing */
+/* PostScript-Code. Nevertheless, it's still not perfect. */
+
+ if(0 >= upd->int_a[IA_ENDTOP].size ||
+ 0 >= upd->int_a[IA_END_DY].size ) upd->ints[I_END_Y] =
+ upd->ints[I_PHEIGHT] ? upd->ints[I_PHEIGHT] : upd->gsheight;
+
+ if(0 >= upd->ints[I_END_Y]) upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
+ upd->ints[I_PHEIGHT] : upd->gsheight;
+
+
+/* Create Default X-Passes */
+
+ if(0 >= upd->int_a[IA_STD_IX].size) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(upd->int_a[IA_STD_IX]);
+ UPD_MM_GET_ARRAY(ip,upd->int_a[IA_STD_DY].size);
+ upd->int_a[IA_STD_IX].data = ip;
+ upd->int_a[IA_STD_IX].size = upd->int_a[IA_STD_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_STD_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+
+ if((0 >= upd->int_a[IA_BEG_IX].size) &&
+ (0 < upd->int_a[IA_BEG_DY].size) ) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(upd->int_a[IA_BEG_IX]);
+ UPD_MM_GET_ARRAY(ip,upd->int_a[IA_BEG_DY].size);
+ upd->int_a[IA_BEG_IX].data = ip;
+ upd->int_a[IA_BEG_IX].size = upd->int_a[IA_BEG_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_BEG_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+
+ if((0 >= upd->int_a[IA_END_IX].size) &&
+ (0 < upd->int_a[IA_END_DY].size) ) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(upd->int_a[IA_END_IX]);
+ UPD_MM_GET_ARRAY(ip,upd->int_a[IA_END_DY].size);
+ upd->int_a[IA_END_IX].data = ip;
+ upd->int_a[IA_END_IX].size = upd->int_a[IA_END_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_END_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+ }
+
+ if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d normal Feeds\n",
+ (int) upd->int_a[IA_STD_DY].size,upd->ints[I_NPASS]);
+#endif
+ success = false;
+
+ } else if(upd->int_a[IA_STD_IX].size < upd->int_a[IA_STD_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d normal Xstarts\n",
+ (int) upd->int_a[IA_STD_IX].size,
+ (int) upd->int_a[IA_STD_DY].size);
+#endif
+ success = false;
+ }
+
+/** The sum of Values in STD_DY should equal NYPASS * PINS2WRITE (diagnostic) */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(success) {
+ int i,sum = 0;
+ for(i = 0; upd->ints[I_NPASS] > i; ++i)
+ sum += upd->int_a[IA_STD_DY].data[i];
+ if((upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]) != sum)
+ fprintf(stderr,
+ "upd_open_writer: Sum of normal Feeds is %d rather than %d\n",
+ sum,upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]);
+ }
+#endif
+
+ if(upd->int_a[IA_BEG_IX].size < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d initial Xstarts\n",
+ (int) upd->int_a[IA_BEG_IX].size,
+ (int) upd->int_a[IA_BEG_DY].size);
+#endif
+ success = false;
+ }
+
+ if(upd->int_a[IA_BEGBOT].size < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d initial Pins\n",
+ (int) upd->int_a[IA_BEGBOT].size,
+ (int) upd->int_a[IA_BEG_DY].size);
+#endif
+ success = false;
+
+ } else {
+
+ int i;
+ for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
+ if((upd->int_a[IA_BEGBOT].data[i] > upd->ints[I_PINS2WRITE]) ||
+ (upd->int_a[IA_BEGBOT].data[i] < 0 ) ) break;
+
+ if(i < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d is invalid initial Pins\n",
+ upd->int_a[IA_BEGBOT].data[i]);
+#endif
+ success = false;
+ }
+ }
+
+
+/** The sum of Values in BEG_DY should equal BEG_Y */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(success) {
+ int i,sum = 0;
+ for(i = 0; upd->int_a[IA_BEG_DY].size > i; ++i)
+ sum += upd->int_a[IA_BEG_DY].data[i];
+ if(upd->ints[I_BEG_Y] != sum)
+ fprintf(stderr,
+ "upd_open_writer: Sum of initial Feeds is %d rather than %d\n",
+ sum,upd->ints[I_BEG_Y]);
+ }
+#endif
+
+ if(upd->int_a[IA_END_IX].size < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d final Xstarts\n",
+ (int) upd->int_a[IA_END_IX].size,
+ (int) upd->int_a[IA_END_DY].size);
+#endif
+ success = false;
+ }
+
+ if(upd->int_a[IA_ENDTOP].size < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d instead of %d Final Pins\n",
+ (int) upd->int_a[IA_ENDTOP].size,
+ (int) upd->int_a[IA_END_DY].size);
+#endif
+ success = false;
+
+ } else {
+
+ int i;
+ for(i = 0; i < upd->int_a[IA_END_DY].size; ++i)
+ if((upd->int_a[IA_ENDTOP].data[i] > upd->ints[I_PINS2WRITE]) ||
+ (upd->int_a[IA_ENDTOP].data[i] < 0 ) ) break;
+
+ if(i < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d is invalid initial Pins\n",
+ upd->int_a[IA_ENDTOP].data[i]);
+#endif
+ success = false;
+ }
+ }
+
+/** SA_SETCOMP must be valid, if present */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->ncomp > upd->string_a[SA_SETCOMP].size)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "upd_open_writer: Only %d SETCOMP-Commands (%d required)\n",
+ (int) upd->string_a[SA_SETCOMP].size,upd->ncomp);
+#endif
+ success = false;
+ }
+
+/** Determine required number of scan-Buffers */
+
+ if(success) { /* Compute nscnbuf */
+ int32 want,use;
+
+ want = upd->ints[I_NYPASS];
+ want *= upd->ints[I_PINS2WRITE];
+
+ if(upd->ints[I_NSCNBUF] > want) want = upd->ints[I_NSCNBUF];
+
+ if(1 > want) want = 1;
+
+ for(use = 1; 0 < use; use <<= 1) if(use > want) break;
+
+ if(use <= INT_MAX) upd->nscnbuf = upd->ints[I_NSCNBUF] = use;
+ else success = false;
+
+ } /* Compute nscnbuf */
+
+/** Determine number of words in scan-buffers */
+
+ if(success) { /* Compute pwidth, scnmsk, nbytes, pheight */
+
+ if(0 < upd->ints[I_PWIDTH]) upd->pwidth = upd->ints[I_PWIDTH];
+ else upd->pwidth = upd->gswidth;
+
+ upd->nbytes = (upd->pwidth+CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]) - 1)
+ / (CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]));
+
+ upd->scnmsk = upd->nscnbuf - 1;
+
+ if(0 < upd->ints[I_PHEIGHT]) upd->pheight = upd->ints[I_PHEIGHT];
+ else upd->pheight = upd->gsheight;
+
+ } /* Compute pwidth, scnmsk, nbytes */
+
+/** Call the writer-specific open-function */
+
+ if(success) { /* Determine sizes */
+ switch(upd->choice[C_FORMAT]) {
+ case FMT_RAS:
+ if(0 > upd_open_rascomp(udev)) success = false;
+ break;
+ case FMT_EPSON:
+ if(0 > upd_open_wrtescp(udev)) success = false;
+ break;
+ case FMT_ESCP2Y:
+ case FMT_ESCP2XY:
+ if(0 > upd_open_wrtescp2(udev)) success = false;
+ break;
+ case FMT_RTL:
+ if(0 > upd_open_wrtrtl(udev)) success = false;
+ break;
+ case FMT_CANON: /* (hr) */
+ if(0 > upd_open_wrtcanon(udev)) success = false;
+ break;
+ default:
+ success = false;
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,"upd_open_writer: Unknown writer-type %d\n",
+ upd->choice[C_FORMAT]);
+#endif
+ break;
+ }
+ } /* Determine sizes*/
+
+/** Allocate the Outputbuffer */
+ if(success && (0 < upd->noutbuf)) { /* Allocate outbuf */
+ upd->outbuf = gs_malloc(upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
+ if(!upd->outbuf) success = false;
+ } /* Allocate outbuf */
+
+/** Allocate the desired scan-buffer-pointers */
+ if(success) {
+ upd->scnbuf = gs_malloc(upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
+ if(NULL == upd->scnbuf) {
+ success = false;
+ } else {
+ int ibuf;
+ for(ibuf = 0; ibuf < upd->nscnbuf; ++ibuf) {
+ if(success) upd->scnbuf[ibuf] =
+ gs_malloc(upd->ncomp,sizeof(upd->scnbuf[0][0]),"upd/scnbuf[]");
+ else upd->scnbuf[ibuf] = NULL;
+
+ if(!upd->scnbuf[ibuf]) {
+ success = false;
+ } else {
+ int icomp;
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ if(success) upd->scnbuf[ibuf][icomp].bytes =
+ gs_malloc(upd->nbytes,sizeof(upd->scnbuf[0][0].bytes[0]),
+ "upd/bytes");
+ else upd->scnbuf[ibuf][icomp].bytes = NULL;
+ if(!upd->scnbuf[ibuf][icomp].bytes) success = false;
+
+ if(0 < upd->nlimits) {
+
+ upd->scnbuf[ibuf][icomp].xbegin = gs_malloc(upd->nlimits,
+ sizeof(upd->scnbuf[0][0].xbegin[0]),"upd/xbegin");
+ if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
+
+ upd->scnbuf[ibuf][icomp].xend = gs_malloc(upd->nlimits,
+ sizeof(upd->scnbuf[0][0].xend[0]),"upd/xend");
+ if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
+
+ } else {
+
+ upd->scnbuf[ibuf][icomp].xbegin = NULL;
+ upd->scnbuf[ibuf][icomp].xend = NULL;
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(success) upd->flags |= B_FORMAT;
+ else upd_close_writer(udev);
+
+ return success ? 1 : -1;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_writer: Deinitialize rendering */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_close_writer(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ if(upd) {
+ int ibuf,icomp;
+
+ if((0 < upd->noutbuf) && upd->outbuf)
+ gs_free(upd->outbuf,upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
+ upd->noutbuf = 0;
+ upd->outbuf = NULL;
+
+ if((0 < upd->nscnbuf) && upd->scnbuf) {
+ for(ibuf = 0; upd->nscnbuf > ibuf; ++ibuf) {
+
+ if(!upd->scnbuf[ibuf]) continue;
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+
+ if((0 < upd->nbytes) && upd->scnbuf[ibuf][icomp].bytes)
+ gs_free(upd->scnbuf[ibuf][icomp].bytes,upd->nbytes,
+ sizeof(upd->scnbuf[ibuf][icomp].words[0]),"upd/bytes");
+ upd->scnbuf[ibuf][icomp].bytes = NULL;
+
+ if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xbegin)
+ gs_free(upd->scnbuf[ibuf][icomp].xbegin,upd->nlimits,
+ sizeof(upd->scnbuf[ibuf][icomp].xbegin[0]),"upd/xbegin");
+ upd->scnbuf[ibuf][icomp].xbegin = NULL;
+
+ if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xend)
+ gs_free(upd->scnbuf[ibuf][icomp].xend,upd->nlimits,
+ sizeof(upd->scnbuf[ibuf][icomp].xend[0]),"upd/xend");
+ upd->scnbuf[ibuf][icomp].xend = NULL;
+ }
+
+ if(icomp)
+ gs_free(upd->scnbuf[ibuf],upd->ncomp,sizeof(upd->scnbuf[0][0]),
+ "upd/scnbuf[]");
+ upd->scnbuf[ibuf] = NULL;
+
+ }
+ gs_free(upd->scnbuf,upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
+ }
+
+
+ upd->flags &= ~B_FORMAT;
+ }
+}
+
+
+/* ------------------------------------------------------------------- */
+/* upd_limits: Establish passwise limits, after rendering */
+/* ------------------------------------------------------------------- */
+
+private void
+upd_limits(upd_p upd, bool check)
+{
+ updscan_p scans = upd->scnbuf[upd->yscnbuf & upd->scnmsk], scan;
+ int xs,x,xe,icomp,pass;
+ byte *bytes,bit;
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ scan = scans + icomp;
+ for(pass = 0; pass < upd->nlimits; ++pass) {
+ scan->xbegin[pass] = upd->pwidth;
+ scan->xend[ pass] = -1;
+ }
+ }
+
+ if(check) { /* Really check */
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Check Components */
+ scan = scans + icomp;
+ bytes = scan->bytes;
+
+ for(xs = 0; xs < upd->nbytes && !bytes[xs]; ++xs);
+
+ if(xs < upd->nbytes) { /* Has Data */
+ for(xe = upd->nbytes; xs < xe && !bytes[xe-1]; --xe);
+
+ for(pass = 0; pass < upd->nlimits; ++pass) { /* limit (pass) loop */
+
+ x = ((xs<<3)/upd->nlimits)*upd->nlimits + pass;
+ while((x >> 3) < xs) x += upd->nlimits;
+
+ bit = 0x80 >> (x & 7);
+ while(x < scan->xbegin[pass]) {
+ if(bytes[x>>3] & bit) scan->xbegin[pass] = x;
+ x += upd->nlimits;
+ bit = 0x80 >> (x & 7);
+ }
+
+ x = (((xe<<3)|7)/upd->nlimits)*upd->nlimits + pass;
+
+ while((x >> 3) < xe) x += upd->nlimits;
+ while((x >> 3) > xe) x -= upd->nlimits;
+
+ bit = 0x80 >> (xs & 7);
+ while(x > scan->xend[pass]) {
+ if(bytes[x>>3] & bit) scan->xend[pass] = x;
+ x -= upd->nlimits;
+ bit = 0x80 >> (x & 7);
+ }
+
+ } /* limit (pass) loop */
+
+ } /* Has Data */
+
+ } /* Check Components */
+
+ } /* Really check */
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_rascomp: ncomp * 1Bit Raster-Writer */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_rascomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int32 noutbuf;
+ int error = 0;
+
+ noutbuf = upd->pwidth;
+
+ if(1 < upd->ncomp) noutbuf *= 8;
+
+ noutbuf = ((noutbuf+15)>>4)<<1;
+
+ if(INT_MAX >= noutbuf) {
+ upd->noutbuf = noutbuf;
+ upd->start_writer = upd_start_rascomp;
+ upd->writer = upd_rascomp;
+ } else {
+ error = -1;
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_start_rascomp: write appropiate raster-header */
+/* ------------------------------------------------------------------- */
+#if arch_is_big_endian
+#define put32(I32,Out) \
+ fwrite(&I32,1,4,Out)
+#else
+#define put32(I32,Out) \
+ putc(((I32)>>24)&255,Out),\
+ putc(((I32)>>16)&255,Out),\
+ putc(((I32)>> 8)&255,Out),\
+ putc( (I32) &255,Out)
+#endif
+
+private int
+upd_start_rascomp(upd_p upd, FILE *out) {
+
+/** if no begin-sequence externally set */
+ if(0 == upd->strings[S_BEGIN].size) {
+ int32 val;
+
+/** ras_magic */
+ val = 0x59a66a95;
+ put32(val,out);
+
+/** ras_width */
+ val = upd->pwidth;
+ put32(val,out);
+
+/** ras_height */
+ val = upd->pheight;
+ put32(val,out);
+
+/** ras_depth */
+ if(1 < upd->ncomp) val = 8;
+ else val = 1;
+ put32(val,out);
+
+/** ras_length */
+ val *= upd->pwidth;
+ val = ((val+15)>>4)<<1;
+ val *= upd->pheight;
+ put32(val,out);
+
+/** ras_type */
+ val = 1;
+ put32(val,out);
+
+/** ras_maptype */
+ val = 1;
+ put32(val,out);
+
+/** ras_maplength */
+ val = 3 * (1 << upd->ncomp);
+ put32(val,out);
+
+/** R,G,B-Map */
+ if(1 == upd->ncomp) {
+ const updcomp_p comp = upd->valptr[0];
+
+ if(upd->cmap[comp->cmap].rise) {
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ } else {
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ }
+
+ } else if(3 == upd->ncomp) {
+ int rgb;
+
+ for( rgb = 0; rgb < 3; ++rgb) {
+ int entry;
+ for(entry = 0; entry < 8; ++entry) {
+ byte xval = upd->cmap[rgb].rise ? 0x00 : 0xff;
+ if(entry & (1<<upd->cmap[rgb].comp)) xval ^= 0xff;
+ putc(xval,out);
+ }
+ }
+ } else { /* we have 4 components */
+ int rgb;
+
+ for(rgb = 16; 0 <= rgb; rgb -= 8) {
+ int entry;
+ for(entry = 0; entry < 16; ++entry) {
+ uint32 rgbval = 0;
+
+ if(entry & (1<<upd->cmap[0].comp)) {
+
+ rgbval = 0xffffff;
+
+ } else {
+
+ if(entry & (1<<upd->cmap[1].comp)) rgbval |= 0xff0000;
+ if(entry & (1<<upd->cmap[2].comp)) rgbval |= 0x00ff00;
+ if(entry & (1<<upd->cmap[3].comp)) rgbval |= 0x0000ff;
+ }
+
+ if(!upd->cmap[1].rise) rgbval ^= 0xff0000;
+ if(!upd->cmap[2].rise) rgbval ^= 0x00ff00;
+ if(!upd->cmap[3].rise) rgbval ^= 0x0000ff;
+
+ if(!(upd->choice[C_MAPPER] == MAP_RGBW)) rgbval ^= 0xffffff;
+
+ putc((rgbval>>rgb)&255,out);
+ }
+ }
+ }
+ }
+ memset(upd->outbuf,0,upd->noutbuf);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rascomp: assemble & write a scanline */
+/* ------------------------------------------------------------------- */
+private int
+upd_rascomp(upd_p upd, FILE *out) {
+ updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+ uint bits = upd->pwidth;
+
+ if(1 == upd->ncomp) {
+ uint nbytes;
+
+ nbytes = (bits+7)>>3;
+ memcpy(upd->outbuf,scan->bytes,nbytes);
+ if((bits &= 7)) upd->outbuf[nbytes-1] &= ((byte) 0xff) << (8-bits);
+
+ } else {
+
+ byte *buf = upd->outbuf, bit = 0x80;
+ int ibyte = 0;
+
+ while(0 < bits--) {
+ byte val = 0;
+ switch(upd->ncomp) {
+ case 4: if(scan[3].bytes[ibyte] & bit) val |= 8;
+ case 3: if(scan[2].bytes[ibyte] & bit) val |= 4;
+ if(scan[1].bytes[ibyte] & bit) val |= 2;
+ case 1: if(scan[0].bytes[ibyte] & bit) val |= 1;
+ }
+ *buf++ = val;
+ if(!(bit >>= 1)) {
+ bit = 0x80;
+ ibyte += 1;
+ }
+ }
+ }
+
+ fwrite(upd->outbuf,1,upd->noutbuf,out);
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtescp: ESC/P Writer intended for ESC * m commands */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_wrtescp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+/** Adjust the PageLength, If Requested */
+ if((B_PAGELENGTH & upd->flags) &&
+ (0 < upd->strings[S_BEGIN].size)) { /* BOP-Checker */
+ int i,state = 0,value = 0;
+ byte *bp = (byte *) upd->strings[S_BEGIN].data;
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+ switch(state) {
+ case 0:
+ if(0x1b == bp[i]) state = 1;
+ break;
+ case 1:
+ if('C' == bp[i]) state = 2;
+ else state = 0;
+ break;
+ case 2:
+ if(bp[i]) {
+ value = 0.5 + udev->height * (float) bp[i]
+ / udev->y_pixels_per_inch;
+ if( 0 >= value) bp[i] = 1;
+ else if(128 > value) bp[i] = value;
+ else bp[i] = 127;
+ state = 0;
+ } else {
+ state = 3;
+ }
+ break;
+ case 3:
+ value = 0.5 + udev->height / udev->y_pixels_per_inch;
+ if( 0 >= value) bp[i] = 1;
+ else if( 22 > value) bp[i] = value;
+ else bp[i] = 22;
+ state = 0;
+ break;
+ }
+ }
+ } /* BOP-Checker */
+
+
+/** Either SETLF or YMOVE must be set */
+ if((0 == upd->strings[S_SETLF].size) &&
+ (0 == upd->strings[S_YMOVE].size) ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P-Open: Either SETLF- or YMOVE-Command must be present\n");
+#endif
+ error = -1;
+ }
+
+/** X-Positioning must be set too */
+ if(((1 < upd->ints[I_XSTEP] ) &&
+ (0 == upd->strings[S_XSTEP].size) ) ||
+ ((1 < upd->ints[I_NXPASS] ) &&
+ (0 == upd->strings[S_XMOVE].size) &&
+ (0 == upd->strings[S_XSTEP].size) ) ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P-Open: Missing XSTEP- and/or XMOVE-Command\n");
+#endif
+ error = -1;
+ }
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/**
+If all this is correct, it's time to coumput the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. X-Positioning
+ 3. Component-Selection
+ 4. The Raster-Command
+ 5. The Data
+*/
+ if(0 <= error) {
+ int32 i,noutbuf,need;
+
+ if(0 < upd->strings[S_YMOVE].size) {
+ noutbuf = upd->strings[S_YMOVE].size + 2;
+ } else {
+ int nmax = upd->pheight;
+ if( 1 < upd->ints[I_YSTEP]) nmax /= upd->ints[I_YSTEP];
+ else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
+ noutbuf = 2 * upd->strings[S_SETLF].size + 2;
+ noutbuf += nmax/255 + 1;
+ }
+
+ if(1 < upd->ints[I_YSTEP])
+ noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
+
+ noutbuf += upd->strings[S_XMOVE].size + 2;
+
+ if(1 < upd->ints[I_XSTEP])
+ noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
+
+ if(0 < upd->string_a[SA_SETCOMP].size) {
+ need = 0;
+ for(i = 0; i < upd->ncomp; ++i)
+ if(need < upd->string_a[SA_SETCOMP].data[i].size)
+ need = upd->string_a[SA_SETCOMP].data[i].size;
+ noutbuf += need;
+ }
+
+ need = 0;
+ for(i = 0; i < upd->ncomp; ++i)
+ if(need < upd->string_a[SA_WRITECOMP].data[i].size)
+ need = upd->string_a[SA_WRITECOMP].data[i].size;
+ noutbuf += need + 2;
+
+ noutbuf += ((upd->ints[I_PINS2WRITE] + 7) / 8)
+ * ((upd->pwidth + upd->ints[I_NXPASS] - 1)/upd->ints[I_NXPASS]);
+
+ if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
+ upd->noutbuf = noutbuf;
+ upd->writer = upd_wrtescp;
+ upd->nlimits = upd->ints[I_NXPASS];
+ error = 1;
+ } else {
+ error = -1;
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P-Open: %ld is unreasonable size of Outputbuffer\n",
+ (long) noutbuf);
+#endif
+ }
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp: Write a pass */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_wrtescp(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
+ byte *obytes,bit;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->pwidth;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
+ if(xbegin > scan[icomp].xbegin[ixpass])
+ xbegin = scan[icomp].xbegin[ixpass];
+ if(xend < scan[icomp].xend[ ixpass])
+ xend = scan[icomp].xend[ ixpass];
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ if(0 < upd->strings[S_YMOVE].size) {
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,
+ upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } else {
+
+ while(n) {
+ int n2do = n > 255 ? 255 : n;
+ if(upd->lf != n2do) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_SETLF].data,
+ upd->strings[S_SETLF].size);
+ ioutbuf += upd->strings[S_SETLF].size;
+ upd->outbuf[ioutbuf++] = n2do;
+ upd->lf = n2do;
+ }
+ upd->outbuf[ioutbuf++] = '\n';
+ n -= n2do;
+ }
+ }
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(0 <= scan->xend[ixpass]) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = ixpass;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = (xend - xbegin) / upd->ints[I_NXPASS] + 1;;
+ upd->outbuf[ioutbuf++] = n & 255;
+ upd->outbuf[ioutbuf++] = (n>>8) & 255;
+/*
+ * Clear the data-Part
+ */
+ obytes = upd->outbuf+ioutbuf;
+ n *= (upd->ints[I_PINS2WRITE]+7)>>3;
+ memset(obytes,0,n);
+ ioutbuf += n;
+/*
+ * Set the Pixels
+ */
+ for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
+
+ bit = 0x80 >> (pintop & 7);
+ obytes += pintop>>3;
+
+ for(pin = pintop, y = ybegin; pin < pinbot;
+ pin++, y += upd->ints[I_NYPASS]) {
+ if(0 <= y) {
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(scan->bytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
+ }
+ if(!(bit >>= 1)) { obytes++; bit = 0x80; }
+ }
+
+ obytes += (upd->ints[I_PINS2WRITE]-pinbot+7)>>3;
+ }
+/*
+ * Send this Component to the Printer
+ */
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtescp2: ESC/P2 Writer intended for ESC . 1 commands */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_wrtescp2(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+ float pixels_per_inch = 360.0;
+
+/** Analyze (and optionally adjust) the BOP-Sequence */
+ if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
+ int i,state = 0,value = 0;
+ byte *bp = (byte *) upd->strings[S_BEGIN].data;
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+ switch(state) {
+ case 0:
+ if(0x1b == bp[i]) state = 1;
+ break;
+ case 1:
+ if('(' == bp[i]) state = 2;
+ else state = 0;
+ break;
+ case 2:
+ switch(bp[i]) {
+ case 'U': state = 3; break; /* Printer-Resolution */
+ case 'C': state = 6; break; /* Page-Length */
+ case 'c': state = 10; break; /* Top/Bottom Margin */
+ default: state = 0; break;
+ }
+ break;
+ case 3:
+ if(1 == bp[i]) state = 4;
+ else state = 0;
+ break;
+ case 4:
+ if(0 == bp[i]) state = 5;
+ else state = 0;
+ break;
+ case 5:
+ pixels_per_inch = 3600.0 / (float) bp[i];
+ state = 0;
+ break;
+ case 6:
+ if(2 == bp[i]) state = 7;
+ else state = 0;
+ break;
+ case 7:
+ if(0 == bp[i]) state = 8;
+ else state = 0;
+ break;
+ case 8:
+ if(B_PAGELENGTH & upd->flags) {
+ value = 0.5 + udev->height
+ * pixels_per_inch / udev->y_pixels_per_inch;
+ bp[i] = value & 0xff;
+ }
+ state = 9;
+ break;
+ case 9:
+ if(B_PAGELENGTH & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 0;
+ break;
+ case 10:
+ if(4 == bp[i]) state = 11;
+ else state = 0;
+ break;
+ case 11:
+ if(0 == bp[i]) state = 12;
+ else state = 0;
+ break;
+ case 12:
+ if(B_TOPMARGIN & upd->flags) {
+ value = dev_t_margin(udev) * pixels_per_inch;
+ bp[i] = value & 0xff;
+ }
+ state = 13;
+ break;
+ case 13:
+ if(B_TOPMARGIN & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 14;
+ break;
+ case 14:
+ if(B_BOTTOMMARGIN & upd->flags) {
+ value = 0.5 + udev->height
+ * pixels_per_inch / udev->y_pixels_per_inch
+ - dev_b_margin(udev) * pixels_per_inch;
+ bp[i] = value & 0xff;
+ }
+ state = 15;
+ break;
+ case 15:
+ if(B_BOTTOMMARGIN & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 0;
+ break;
+ }
+ }
+ } /* BOP-Checker */
+
+/** Create Y-Move-Command, if not given */
+ if(0 == upd->strings[S_YMOVE].size) {
+ byte *bp;
+ UPD_MM_DEL_PARAM(upd->strings[S_YMOVE]);
+ UPD_MM_GET_ARRAY(bp,5);
+ upd->strings[S_YMOVE].data = bp;
+ upd->strings[S_YMOVE].size = 5;
+ *bp++ = 0x1b; /* ESC */
+ *bp++ = '(';
+ *bp++ = upd->flags & B_YABS ? 'V' : 'v';
+ *bp++ = 2;
+ *bp++ = 0;
+ }
+
+/** X-Positioning must be set too, sometimes */
+ if((1 < upd->ints[I_XSTEP]) && (0 == upd->strings[S_XSTEP].size)) {
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P2-Open: XSTEP-Command required for XSTEP=%d\n",
+ upd->ints[I_XSTEP]);
+#endif
+ error = -1;
+
+ } else if((1 < upd->ints[I_NXPASS] ) &&
+ (0 == upd->strings[S_XMOVE].size) &&
+ (0 == upd->strings[S_XSTEP].size) ) {
+ byte *bp;
+ int ratio;
+
+ ratio = (udev->y_pixels_per_inch + .5) / udev->x_pixels_per_inch;
+
+ if(0 == upd->ints[I_XSTEP]) { /* Adjust scale-factor too! */
+ if(ratio > 1) upd->ints[I_XSTEP] = -ratio;
+ } else { /* Adjust scale-factor too! */
+ ratio = -upd->ints[I_XSTEP];
+ }
+
+ if(2 == upd->ints[I_NXPASS]) { /* Use a relative Step */
+
+ UPD_MM_DEL_PARAM(upd->strings[S_XSTEP]);
+ UPD_MM_GET_ARRAY(bp,4);
+ upd->strings[S_XSTEP].size = 4;
+ upd->strings[S_XSTEP].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = '\\';
+ *bp++ = ratio & 0xff;
+ *bp++ = (ratio>>8) & 0xff;
+
+ } else { /* Use relative or absolute Move */
+
+ UPD_MM_DEL_PARAM(upd->strings[S_XMOVE]);
+ UPD_MM_GET_ARRAY(bp,2);
+ upd->strings[S_XMOVE].size = 2;
+ upd->strings[S_XMOVE].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = upd->flags & B_XABS ? '$' : '\\';
+
+ }
+ }
+
+/** If there is neither a writecomp nor a setcomp-command, generate both */
+ if((0 == upd->string_a[SA_WRITECOMP].size) &&
+ (0 == upd->string_a[SA_SETCOMP].size ) ) { /* Default-commands */
+ byte *bp;
+ gs_param_string *ap;
+ int i;
+
+ if(4 == upd->ncomp) { /* Establish Component-Selection */
+ UPD_MM_DEL_APARAM(upd->string_a[SA_SETCOMP]);
+ UPD_MM_GET_ARRAY(ap,4);
+ upd->string_a[SA_SETCOMP].data = ap;
+ upd->string_a[SA_SETCOMP].size = 4;
+ for(i = 0; i < 4; ++i) {
+ UPD_MM_GET_ARRAY(bp,3);
+ ap[i].size = 3;
+ ap[i].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = 'r';
+ switch(((updcomp_p)upd->valptr[i])->cmap) { /* use COMPORDER! */
+ case 0: *bp++ = 0; break; /* Black */
+ case 1: *bp++ = 2; break; /* Cyan */
+ case 2: *bp++ = 1; break; /* Magenta */
+ case 3: *bp++ = 4; break; /* Yellow */
+ } /* use COMPORDER! */
+ }
+ } /* Establish Component-Selection */
+
+ UPD_MM_DEL_APARAM(upd->string_a[SA_WRITECOMP]);
+ UPD_MM_GET_ARRAY(ap,upd->ncomp);
+ upd->string_a[SA_WRITECOMP].data = ap;
+ upd->string_a[SA_WRITECOMP].size = upd->ncomp;
+ for(i = 0; i < upd->ncomp; ++i) {
+ UPD_MM_GET_ARRAY(bp,6);
+ ap[i].size = 6;
+ ap[i].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = '.';
+ *bp++ = 1; /* RLE */
+ *bp++ = 3600.0 * upd->ints[I_NYPASS] / udev->y_pixels_per_inch + 0.5;
+ *bp++ = 3600.0 * upd->ints[I_NXPASS] / udev->x_pixels_per_inch + 0.5;
+ *bp++ = upd->ints[I_PINS2WRITE];
+ }
+ } /* Default-commands */
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P2-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/** Check Validity of X-Pass */
+ switch(upd->choice[C_FORMAT]) {
+ case FMT_ESCP2Y:
+ if(1 < upd->ints[I_NXPASS]) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P2-Open: FMT_ESCP2Y cannot handle multiple X-Passes\n");
+#endif
+ error = -1;
+ } else {
+ upd->writer = upd_wrtescp2;
+ }
+ break;
+ case FMT_ESCP2XY:
+ upd->writer = upd_wrtescp2x;
+ upd->nlimits = upd->ints[I_NXPASS];
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(1 == upd->ints[I_NXPASS])
+ fprintf(stderr,
+ "ESC/P2-Open: FMT_ESCP2XY should not be used with 1X-Pass\n");
+#endif
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "ESC/P2-Open: %d is not a ESC/P2-Format\n",
+ upd->choice[C_FORMAT]);
+#endif
+ error = - 1;
+ break;
+ }
+
+
+/**
+If all this is correct, it's time to compute the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. X-Positioning
+ 3. Component-Selection
+ 4. The Raster-Command
+ 5. The Data
+*/
+ if(0 <= error) {
+ int32 i,noutbuf,need;
+
+ if(0 < upd->strings[S_YMOVE].size) {
+ noutbuf = upd->strings[S_YMOVE].size + 2;
+ } else {
+ int nmax = upd->pheight;
+ if( 1 < upd->ints[I_YSTEP]) nmax /= upd->ints[I_YSTEP];
+ else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
+ noutbuf = 2 * upd->strings[S_SETLF].size + 2;
+ noutbuf += nmax/255 + 1;
+ }
+
+ if(1 < upd->ints[I_YSTEP])
+ noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
+
+ if(0 == upd->strings[S_XMOVE].size) {
+ noutbuf += 1; /* The CR */
+ noutbuf += (upd->ints[I_NXPASS]-1) * upd->strings[S_XSTEP].size;
+ } else {
+ noutbuf += upd->strings[S_XMOVE].size + 2;
+
+ if(1 < upd->ints[I_XSTEP])
+ noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
+ }
+
+ if(0 < upd->string_a[SA_SETCOMP].size) {
+ need = 0;
+ for(i = 0; i < upd->ncomp; ++i)
+ if(need < upd->string_a[SA_SETCOMP].data[i].size)
+ need = upd->string_a[SA_SETCOMP].data[i].size;
+ noutbuf += need;
+ }
+
+ need = 0;
+ for(i = 0; i < upd->ncomp; ++i)
+ if(need < upd->string_a[SA_WRITECOMP].data[i].size)
+ need = upd->string_a[SA_WRITECOMP].data[i].size;
+ noutbuf += need + 2;
+
+ noutbuf += 2*upd->nbytes + (upd->nbytes + 127) / 128;
+
+ upd->noutbuf = noutbuf;
+ error = 1;
+
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp2: Write a pass */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_wrtescp2(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
+ byte *obytes;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->nbytes;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
+ obytes = scan[icomp].bytes;
+
+ for(x = 0; x < xbegin && !obytes[x]; x++);
+ if(x < xbegin) xbegin = x;
+
+ if(x < upd->nbytes) {
+ for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
+ if(x > xend) xend = x;
+ }
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ obytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
+ for(x = xbegin; x <= xend && !obytes[x]; ++x);
+ if( x <= xend) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = 0;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = xend + 1 - xbegin;
+ upd->outbuf[ioutbuf++] = (n<<3) & 255;
+ upd->outbuf[ioutbuf++] = (n>>5) & 255;
+/*
+ * Set the Pixels
+ */
+ for(pin = 0; pin < pintop; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(y = ybegin; 0 > y; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(; y < yend; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,
+ upd->scnbuf[y & upd->scnmsk][icomp].bytes+xbegin,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp2x: Write an ESC/P2-pass with X-Weaving */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_wrtescp2x(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
+ byte *obytes,bit;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->pwidth;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
+ if(xbegin > scan[icomp].xbegin[ixpass])
+ xbegin = scan[icomp].xbegin[ixpass];
+ if(xend < scan[icomp].xend[ ixpass])
+ xend = scan[icomp].xend[ ixpass];
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = upd->nbytes;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(0 <= scan->xend[ixpass]) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = ixpass;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = ((xend - xbegin) / upd->ints[I_NXPASS] + 8) & ~7;
+ upd->outbuf[ioutbuf++] = n & 255;
+ upd->outbuf[ioutbuf++] = (n>>8) & 255;
+ n >>= 3;
+/*
+ * Set the Pixels
+ */
+ for(pin = 0; pin < pintop; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(y = ybegin; 0 > y; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(; y < yend; y += upd->ints[I_NYPASS]) {
+ byte * ibytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
+ obytes = upd->outbuf;
+ memset(obytes,0,upd->nbytes);
+ bit = 0x80;
+ for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
+ if(ibytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
+ if(!(bit >>= 1)) { obytes++; bit = 0x80; }
+ }
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,upd->outbuf,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rle: The Runlength-Compressor */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_rle(byte *out,const byte *in,int nbytes)
+{
+
+ int used = 0;
+ int crun,cdata;
+ byte run;
+
+ if(in != NULL) { /* Data present */
+
+ crun = 1;
+
+ while(nbytes > 0) { /* something to compress */
+
+ run = in[0];
+
+ while((nbytes > crun) && (run == in[crun])) if(++crun == 128) break;
+
+ if((crun > 2) || (crun == nbytes)) { /* use this run */
+
+ *out++ = (257 - crun) & 0xff; *out++ = run; used += 2;
+
+ nbytes -= crun; in += crun;
+ crun = 1;
+
+ } else { /* ignore this run */
+
+ for(cdata = crun; (nbytes > cdata) && (crun < 4);) {
+ if(run == in[cdata]) crun += 1;
+ else run = in[cdata], crun = 1;
+ if(++cdata == 128) break;
+ }
+
+ if(crun < 3) crun = 0; /* ignore trailing run */
+ else cdata -= crun;
+
+ *out++ = cdata-1; used++;
+ memcpy(out,in,cdata); used += cdata; out += cdata;
+
+ nbytes -= cdata; in += cdata;
+
+ } /* use/ignore run */
+
+ } /* something to compress */
+
+ } else { /* Empty scans to fill bands */
+
+ while(nbytes > 0) {
+ crun = nbytes > 128 ? 128 : nbytes;
+ nbytes -= crun;
+ *out++ = (257 - crun) & 0xff;
+ *out++ = 0;
+ used += 2;
+ }
+ } /* Data present or empty */
+ return used;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtrtl: Basic HP-RTL Writer */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_wrtrtl(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+/** Adjust the Raster-Width */
+
+ if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
+
+ int i,j,state = 0;
+ char cv[16];
+ byte *bp;
+ uint ncv,nbp;
+
+ j = -1;
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+
+ switch(state) {
+ case 0:
+ if(0x1b == upd->strings[S_BEGIN].data[i]) state = 1;
+ break;
+ case 1:
+ if('*' == upd->strings[S_BEGIN].data[i]) state = 2;
+ else state = 0;
+ break;
+ case 2:
+ if('r' == upd->strings[S_BEGIN].data[i]) state = 3;
+ else if('t' == upd->strings[S_BEGIN].data[i]) state = 4;
+ else state = 0;
+ break;
+
+ case 3:
+
+ if((B_PAGEWIDTH & upd->flags) &&
+ (('s' == upd->strings[S_BEGIN].data[i]) ||
+ ('S' == upd->strings[S_BEGIN].data[i]) )) {
+
+ sprintf(cv,"%d",upd->pwidth);
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ } else if((B_PAGELENGTH & upd->flags) &&
+ (('t' == upd->strings[S_BEGIN].data[i]) ||
+ ('T' == upd->strings[S_BEGIN].data[i]) )) {
+
+ sprintf(cv,"%d",upd->pheight);
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ }
+ if(isupper(upd->strings[S_BEGIN].data[i])) state = 0;
+
+ break;
+
+ case 4:
+
+ if((B_RESOLUTION & upd->flags) &&
+ (('r' == upd->strings[S_BEGIN].data[i]) ||
+ ('R' == upd->strings[S_BEGIN].data[i]) )) {
+
+ sprintf(cv,"%d",(int)
+ ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
+ udev->x_pixels_per_inch : udev->y_pixels_per_inch)
+ +0.5));
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ }
+ if(isupper(upd->strings[S_BEGIN].data[i])) state = 0;
+
+ break;
+ }
+
+ if((0x30 > upd->strings[S_BEGIN].data[i]) ||
+ (0x39 < upd->strings[S_BEGIN].data[i]) ) j = i;
+
+ }
+ } /* BOP-Checker */
+
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "PCL-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/**
+If all this is correct, it's time to compute the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. Component-Data
+*/
+ if(0 <= error) {
+ int32 ny,noutbuf;
+ char tmp[16];
+
+ if(0 < upd->strings[S_YMOVE].size) {
+ sprintf(tmp,"%d",upd->pheight);
+ ny = upd->strings[S_YMOVE].size + strlen(tmp);
+ } else {
+ ny = 1 + upd->string_a[SA_WRITECOMP].data[upd->ncomp-1].size;
+ ny *= upd->pheight;
+ }
+
+ noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
+
+ if(ny > noutbuf) noutbuf = ny;
+ noutbuf += 16;
+
+ if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
+ upd->noutbuf = noutbuf;
+ upd->writer = upd_wrtrtl;
+ error = 1;
+ } else {
+ error = -1;
+#if UPD_MESSAGES & UPD_M_WARNING
+ fprintf(stderr,
+ "PCL-Open: %ld is unreasonable size of Outputbuffer\n",
+ (long) noutbuf);
+#endif
+ }
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtrtl: Write a pass */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_wrtrtl(upd_p upd, FILE *out)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+
+ int x,xend,icomp,ioutbuf;
+ byte *data;
+
+/** Determine Width of this scan */
+
+ xend = -1;
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+
+ data = scan[icomp].bytes;
+
+ for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
+ if(x > xend) xend = x;
+ }
+
+ if(0 <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+ xend += 1;
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(1 < upd->strings[S_YMOVE].size) {
+ sprintf((char *)upd->outbuf+ioutbuf,
+ (char *) upd->strings[S_YMOVE].data,upd->yscan - upd->yprinter);
+ ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
+ } else {
+ while(upd->yscan > upd->yprinter) {
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ sprintf((char *)upd->outbuf+ioutbuf,
+ (char *) upd->string_a[SA_WRITECOMP].data[icomp].data,0);
+ ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
+ }
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ upd->yprinter += 1;
+ }
+ }
+ upd->yprinter = upd->yscan;
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ } /* Adjust Y-Position */
+/*
+ * Now write the all! components
+ */
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
+ data = scan[icomp].bytes;
+ for(x = 0; x <= xend; ++x) if(data[x]) break;
+ if(x <= xend) {
+ ioutbuf = upd_rle(upd->outbuf,scan[icomp].bytes,xend);
+ fprintf(out,
+ (char *)upd->string_a[SA_WRITECOMP].data[icomp].data,ioutbuf);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ } else {
+ fprintf(out,
+ (char *)upd->string_a[SA_WRITECOMP].data[icomp].data,0);
+ }
+ }
+
+ upd->yprinter += 1;
+
+ } /* Some data to write */
+
+/** Advance scan by one */
+
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtcanon: Basic Canon Extended Mode Writer (hr) */
+/* ------------------------------------------------------------------- */
+
+private int
+upd_open_wrtcanon(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+ /* max length of one printer line */
+ upd->noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
+ upd->writer = upd_wrtcanon;
+ error = 1;
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtcanon: Write a pass (hr) */
+/* ------------------------------------------------------------------- */
+
+#define LOW(b) ((b)&0xFF)
+#define HIGH(b) ((b)>>8)
+#define ESC 0x1B
+#define CR 0x0D
+
+private int
+upd_wrtcanon(upd_p upd, FILE *out)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+
+ int x, xend, icomp, ioutbuf, step, ioutbuf1;
+ byte *data;
+
+
+ /* Check length of the printable date */
+ xend = -1;
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ data = scan[icomp].bytes;
+
+ for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
+
+ if(x > xend) xend = x;
+ }
+
+ /* If some date to print */
+ if(0 <= xend) { /* Some data to write */
+ ioutbuf = 0;
+ xend += 1;
+
+ /* Perform vertical tab */
+ if(upd->yscan != upd->yprinter) {
+ step = upd->yscan - upd->yprinter;
+
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('e', out);
+ fputc(2, out);
+ fputc(0, out);
+ fputc(HIGH(step), out);
+ fputc(LOW(step), out);
+
+ upd->yprinter = upd->yscan;
+ }
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+
+ /* Are there date to print for the selected color component */
+ data = scan[icomp].bytes;
+ for(x = 0; x <= xend; ++x) if(data[x]) break;
+
+ /* Compressing of the scan line */
+ if(x <= xend) {
+ ioutbuf = upd_rle(upd->outbuf, scan[icomp].bytes, xend);
+ } else {
+ ioutbuf = 0;
+ }
+
+ ioutbuf1 = ioutbuf + 1;
+
+ /* prints the scan line */
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('A', out);
+ fputc(LOW(ioutbuf1), out);
+ fputc(HIGH(ioutbuf1), out);
+ fputc("YMCK"[icomp], out);
+
+ fwrite(upd->outbuf, 1, ioutbuf, out);
+
+ fputc(CR, out);
+ }
+
+ /* Printer advances one raster line */
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('e', out);
+ fputc(2, out);
+ fputc(0, out);
+ fputc(HIGH(1), out);
+ fputc(LOW(1), out);
+
+ upd->yprinter += 1;
+
+ }
+
+ /* Advance scan by one */
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* All the Pixel-Get Routines */
+/* ------------------------------------------------------------------- */
+
+/* That bunch of Pixel-Get Routines */
+
+private upd_proc_pxlget(upd_pxlgetnix); /* A Dummy */
+
+private upd_proc_pxlget(upd_pxlget1f1); /* 1 Bit Forward */
+private upd_proc_pxlget(upd_pxlget1f2);
+private upd_proc_pxlget(upd_pxlget1f3);
+private upd_proc_pxlget(upd_pxlget1f4);
+private upd_proc_pxlget(upd_pxlget1f5);
+private upd_proc_pxlget(upd_pxlget1f6);
+private upd_proc_pxlget(upd_pxlget1f7);
+private upd_proc_pxlget(upd_pxlget1f8);
+
+private upd_proc_pxlget(upd_pxlget1r1); /* 1 Bit Reverse */
+private upd_proc_pxlget(upd_pxlget1r2);
+private upd_proc_pxlget(upd_pxlget1r3);
+private upd_proc_pxlget(upd_pxlget1r4);
+private upd_proc_pxlget(upd_pxlget1r5);
+private upd_proc_pxlget(upd_pxlget1r6);
+private upd_proc_pxlget(upd_pxlget1r7);
+private upd_proc_pxlget(upd_pxlget1r8);
+
+private upd_proc_pxlget(upd_pxlget2f1); /* 2 Bit Forward */
+private upd_proc_pxlget(upd_pxlget2f2);
+private upd_proc_pxlget(upd_pxlget2f3);
+private upd_proc_pxlget(upd_pxlget2f4);
+
+private upd_proc_pxlget(upd_pxlget2r1); /* 2 Bit Reverse */
+private upd_proc_pxlget(upd_pxlget2r2);
+private upd_proc_pxlget(upd_pxlget2r3);
+private upd_proc_pxlget(upd_pxlget2r4);
+
+private upd_proc_pxlget(upd_pxlget4f1); /* 4 Bit Forward */
+private upd_proc_pxlget(upd_pxlget4f2);
+
+private upd_proc_pxlget(upd_pxlget4r1); /* 4 Bit Reverse */
+private upd_proc_pxlget(upd_pxlget4r2);
+
+private upd_proc_pxlget(upd_pxlget8f); /* 8 Bit Forward */
+private upd_proc_pxlget(upd_pxlget8r); /* 8 Bit Reverse */
+
+private upd_proc_pxlget(upd_pxlget16f); /* 16 Bit Forward */
+private upd_proc_pxlget(upd_pxlget16r); /* 16Bit Reverse */
+
+private upd_proc_pxlget(upd_pxlget24f); /* 24 Bit Forward */
+private upd_proc_pxlget(upd_pxlget24r); /* 24 Bit Reverse */
+
+private upd_proc_pxlget(upd_pxlget32f); /* 32 Bit Forward */
+private upd_proc_pxlget(upd_pxlget32r); /* 32 Bit Reverse */
+
+/* Initialize Forward-Run */
+
+private uint32
+upd_pxlfwd(upd_p upd)
+{
+ if(!(upd->pxlptr = upd->gsscan)) {
+
+ upd->pxlget = upd_pxlgetnix;
+
+ } else {
+ switch(upd->int_a[IA_COLOR_INFO].data[1]) {
+ case 1: upd->pxlget = upd_pxlget1f1; break;
+ case 2: upd->pxlget = upd_pxlget2f1; break;
+ case 4: upd->pxlget = upd_pxlget4f1; break;
+ case 8: upd->pxlget = upd_pxlget8f; break;
+ case 16: upd->pxlget = upd_pxlget16f; break;
+ case 24: upd->pxlget = upd_pxlget24f; break;
+ case 32: upd->pxlget = upd_pxlget32f; break;
+ default:
+#if UPD_MESSAGES & UPD_M_ERROR
+ fprintf(stderr,"upd_pxlfwd: unsupported depth (%d)\n",
+ upd->int_a[IA_COLOR_INFO].data[1]);
+#endif
+ upd->pxlget = upd_pxlgetnix;
+ break;
+ }
+ }
+ return (uint32) 0;
+}
+
+/* 1 Bit Forward */
+
+private uint32
+upd_pxlget1f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f2;
+ return *upd->pxlptr & 0x80 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f3;
+ return *upd->pxlptr & 0x40 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f4;
+ return *upd->pxlptr & 0x20 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f5;
+ return *upd->pxlptr & 0x10 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f5(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f6;
+ return *upd->pxlptr & 0x08 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f6(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f7;
+ return *upd->pxlptr & 0x04 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f7(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f8;
+ return *upd->pxlptr & 0x02 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1f8(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f1;
+ return *upd->pxlptr++ & 0x01 ? (uint32) 1 : (uint32) 0;
+}
+
+/* 2 Bit Forward */
+
+private uint32
+upd_pxlget2f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f2;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0xC0) >> 6;
+}
+
+private uint32
+upd_pxlget2f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f3;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0x30) >> 4;
+}
+
+private uint32
+upd_pxlget2f3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f4;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0x0C) >> 2;
+}
+
+private uint32
+upd_pxlget2f4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f1;
+ return (uint32) (*upd->pxlptr++) & (uint32) 0x03;
+}
+
+
+/* 4 Bit Forward */
+private uint32
+upd_pxlget4f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4f2;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0xF0) >> 4;
+}
+
+private uint32
+upd_pxlget4f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4f1;
+ return (uint32) (*upd->pxlptr++) & (uint32) 0x0F;
+}
+
+
+/* 8 Bit Forward */
+private uint32
+upd_pxlget8f(upd_p upd)
+{
+ return (uint32) (*upd->pxlptr++);
+}
+
+
+/* 16 Bit Forward */
+private uint32
+upd_pxlget16f(upd_p upd)
+{
+ uint32 ci = (uint32) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+/* 24 Bit Forward */
+private uint32
+upd_pxlget24f(upd_p upd)
+{
+ uint32 ci = (uint32) (*upd->pxlptr++) << 16;
+ ci |= (uint32) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+/* 32 Bit Forward */
+private uint32
+upd_pxlget32f(upd_p upd)
+{
+ uint32 ci = (uint32) (*upd->pxlptr++) << 24;
+ ci |= (uint32) (*upd->pxlptr++) << 16;
+ ci |= (uint32) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+
+/* Dummy-Routine */
+
+private uint32
+upd_pxlgetnix(upd_p upd)
+{
+ return (uint32) 0;
+}
+
+/* Initialize Reverse-Run */
+
+private uint32
+upd_pxlrev(upd_p upd)
+{
+ const uint width = upd->pwidth < upd->gswidth ? upd->pwidth : upd->gswidth;
+
+ if(!(upd->pxlptr = upd->gsscan)) {
+
+ upd->pxlget = upd_pxlgetnix;
+
+ } else {
+ uint32 ofs = (uint32) upd->int_a[IA_COLOR_INFO].data[1] * (width-1);
+
+ upd->pxlptr += ofs>>3;
+
+ ofs &= 7;
+
+ switch(upd->int_a[IA_COLOR_INFO].data[1]) {
+ case 1: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget1r1; break;
+ case 1: upd->pxlget = upd_pxlget1r2; break;
+ case 2: upd->pxlget = upd_pxlget1r3; break;
+ case 3: upd->pxlget = upd_pxlget1r4; break;
+ case 4: upd->pxlget = upd_pxlget1r5; break;
+ case 5: upd->pxlget = upd_pxlget1r6; break;
+ case 6: upd->pxlget = upd_pxlget1r7; break;
+ case 7: upd->pxlget = upd_pxlget1r8; break;
+ } break;
+ case 2: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget2r1; break;
+ case 2: upd->pxlget = upd_pxlget2r2; break;
+ case 4: upd->pxlget = upd_pxlget2r3; break;
+ case 6: upd->pxlget = upd_pxlget2r4; break;
+ } break;
+ case 4: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget4r1; break;
+ case 4: upd->pxlget = upd_pxlget4r2; break;
+ } break;
+ case 8: upd->pxlget = upd_pxlget8r; break;
+ case 16:
+ upd->pxlget = upd_pxlget16r;
+ upd->pxlptr += 1;
+ break;
+ case 24:
+ upd->pxlget = upd_pxlget24r;
+ upd->pxlptr += 2;
+ break;
+ case 32:
+ upd->pxlget = upd_pxlget32r;
+ upd->pxlptr += 3;
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_ERROR
+ fprintf(stderr,"upd_pxlrev: unsupported depth (%d)\n",
+ upd->int_a[IA_COLOR_INFO].data[1]);
+#endif
+ upd->pxlget = upd_pxlgetnix;
+ break;
+ }
+ }
+ return (uint32) 0;
+}
+
+/* 1 Bit Reverse */
+
+private uint32
+upd_pxlget1r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r8;
+ return *upd->pxlptr-- & 0x80 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r1;
+ return *upd->pxlptr & 0x40 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r2;
+ return *upd->pxlptr & 0x20 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r3;
+ return *upd->pxlptr & 0x10 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r5(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r4;
+ return *upd->pxlptr & 0x08 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r6(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r5;
+ return *upd->pxlptr & 0x04 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r7(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r6;
+ return *upd->pxlptr & 0x02 ? (uint32) 1 : (uint32) 0;
+}
+
+private uint32
+upd_pxlget1r8(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r7;
+ return *upd->pxlptr & 0x01 ? (uint32) 1 : (uint32) 0;
+}
+
+/* 2 Bit Reverse */
+
+private uint32
+upd_pxlget2r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r4;
+ return ((uint32) (*upd->pxlptr--) & (uint32) 0xC0) >> 6;
+}
+
+private uint32
+upd_pxlget2r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r1;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0x30) >> 4;
+}
+
+private uint32
+upd_pxlget2r3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r2;
+ return ((uint32) (*upd->pxlptr ) & (uint32) 0x0C) >> 2;
+}
+
+private uint32
+upd_pxlget2r4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r3;
+ return (uint32) (*upd->pxlptr ) & (uint32) 0x03;
+}
+
+/* 4 Bit Reverse */
+
+private uint32
+upd_pxlget4r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4r2;
+ return ((uint32) (*upd->pxlptr--) & (uint32) 0xF0) >> 4;
+}
+
+private uint32
+upd_pxlget4r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4r1;
+ return (uint32) (*upd->pxlptr ) & (uint32) 0x0F;
+}
+
+
+/* 8 Bit Reverse */
+private uint32
+upd_pxlget8r(upd_p upd)
+{
+ return (uint32) (*upd->pxlptr--);
+}
+
+
+/* 16 Bit Reverse */
+private uint32
+upd_pxlget16r(upd_p upd)
+{
+ uint32 ci = *upd->pxlptr--;
+ ci |= (uint32) (*upd->pxlptr--) << 8;
+ return ci;
+}
+
+/* 24 Bit Reverse */
+private uint32
+upd_pxlget24r(upd_p upd)
+{
+ uint32 ci = *upd->pxlptr--;
+ ci |= (uint32) (*upd->pxlptr--) << 8;
+ ci |= (uint32) (*upd->pxlptr--) << 16;
+ return ci;
+}
+
+/* 32 Bit Reverse */
+private uint32
+upd_pxlget32r(upd_p upd)
+{
+ uint32 ci = *upd->pxlptr--;
+ ci |= (uint32) (*upd->pxlptr--) << 8;
+ ci |= (uint32) (*upd->pxlptr--) << 16;
+ ci |= (uint32) (*upd->pxlptr--) << 24;
+ return ci;
+}
diff --git a/gs/src/gdevvec.c b/gs/src/gdevvec.c
new file mode 100644
index 000000000..863255f25
--- /dev/null
+++ b/gs/src/gdevvec.c
@@ -0,0 +1,852 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevvec.c */
+/* Utilities for "vector" devices */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gsutil.h"
+#include "gxfixed.h"
+#include "gdevvec.h"
+#include "gscspace.h"
+#include "gxdcolor.h"
+#include "gxpaint.h" /* requires gx_path, ... */
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/******
+ ****** NOTE: EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE.
+ ****** USE AT YOUR OWN RISK.
+ ******/
+
+/* Structure descriptors */
+public_st_device_vector();
+public_st_vector_image_enum();
+
+/* ================ Default implementations of vector procs ================ */
+
+int
+gdev_vector_setflat(gx_device_vector *vdev, floatp flatness)
+{ return 0;
+}
+
+int
+gdev_vector_dopath(gx_device_vector *vdev, const gx_path *ppath,
+ gx_path_type_t type)
+{ bool do_close = (type & gx_path_type_stroke) != 0;
+ gs_fixed_rect rect;
+ gs_point scale;
+ double x_start = 0, y_start = 0, x_prev, y_prev;
+ bool first = true;
+ gs_path_enum cenum;
+ int code;
+
+ if ( gx_path_is_rectangle(ppath, &rect) )
+ return (*vdev_proc(vdev, dorect))(vdev, rect.p.x, rect.p.y, rect.q.x,
+ rect.q.y, type);
+ scale = vdev->scale;
+ code = (*vdev_proc(vdev, beginpath))(vdev, type);
+ gx_path_enum_init(&cenum, ppath);
+ for ( ; ; )
+ { fixed vs[6];
+ int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
+ double x, y;
+
+sw: switch ( pe_op )
+ {
+ case 0: /* done */
+ return (*vdev_proc(vdev, endpath))(vdev, type);
+ case gs_pe_moveto:
+ code = (*vdev_proc(vdev, moveto))
+ (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x),
+ (y = fixed2float(vs[1]) / scale.y), first);
+ if ( first )
+ x_start = x, y_start = y, first = false;
+ break;
+ case gs_pe_lineto:
+ code = (*vdev_proc(vdev, lineto))
+ (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x),
+ (y = fixed2float(vs[1]) / scale.y));
+ break;
+ case gs_pe_curveto:
+ code = (*vdev_proc(vdev, curveto))
+ (vdev, x_prev, y_prev,
+ fixed2float(vs[0]) / scale.x,
+ fixed2float(vs[1]) / scale.y,
+ fixed2float(vs[2]) / scale.x,
+ fixed2float(vs[3]) / scale.y,
+ (x = fixed2float(vs[4]) / scale.x),
+ (y = fixed2float(vs[5]) / scale.y));
+ break;
+ case gs_pe_closepath:
+ x = x_start, y = y_start;
+ if ( do_close )
+ { code = (*vdev_proc(vdev, closepath))
+ (vdev, x_prev, y_prev, x_start, y_start);
+ break;
+ }
+ pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
+ if ( pe_op != 0 )
+ { code = (*vdev_proc(vdev, closepath))
+ (vdev, x_prev, y_prev, x_start, y_start);
+ if ( code < 0 )
+ return code;
+ goto sw;
+ }
+ return (*vdev_proc(vdev, endpath))(vdev, type);
+ default: /* can't happen */
+ return_error(gs_error_unknownerror);
+ }
+ if ( code < 0 )
+ return code;
+ x_prev = x, y_prev = y;
+ }
+}
+
+int
+gdev_vector_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
+ fixed y1, gx_path_type_t type)
+{ int code = (*vdev_proc(vdev, beginpath))(vdev, type);
+ if ( code < 0 )
+ return code;
+ code = gdev_vector_write_rectangle(vdev, x0, y0, x1, y1,
+ (type & gx_path_type_stroke) != 0,
+ gx_rect_x_first);
+ if ( code < 0 )
+ return code;
+ return (*vdev_proc(vdev, endpath))(vdev, type);
+}
+
+/* ================ Utility procedures ================ */
+
+/* Recompute the cached color values. */
+private void
+gdev_vector_load_cache(gx_device_vector *vdev)
+{ vdev->black =
+ (*dev_proc(vdev, map_rgb_color))
+ ((gx_device *)vdev, (gx_color_value)0, (gx_color_value)0, (gx_color_value)0);
+ vdev->white =
+ (*dev_proc(vdev, map_rgb_color))
+ ((gx_device *)vdev, gx_max_color_value, gx_max_color_value, gx_max_color_value);
+}
+
+/* Initialize the state. */
+void
+gdev_vector_init(gx_device_vector *vdev)
+{ gdev_vector_reset(vdev);
+ vdev->scale.x = vdev->scale.y = 1.0;
+ vdev->in_page = false;
+ gdev_vector_load_cache(vdev);
+}
+
+/* Reset the remembered graphics state. */
+void
+gdev_vector_reset(gx_device_vector *vdev)
+{ static const gs_imager_state state_initial =
+ { gs_imager_state_initial(1) };
+
+ vdev->state = state_initial;
+ color_unset(&vdev->fill_color);
+ color_unset(&vdev->stroke_color);
+ vdev->clip_path_id =
+ vdev->no_clip_path_id = gs_next_ids(1);
+}
+
+/* Open the output file and stream. */
+int
+gdev_vector_open_file_bbox(gx_device_vector *vdev, uint strmbuf_size,
+ bool bbox)
+{ /* Open the file as positionable if possible. */
+ int code = gx_device_open_output_file((gx_device *)vdev, vdev->fname,
+ true, true, &vdev->file);
+
+ if ( code < 0 )
+ return code;
+ if ( (vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
+ "vector_open(strmbuf)")) == 0 ||
+ (vdev->strm = s_alloc(vdev->v_memory,
+ "vector_open(strm)")) == 0 ||
+ (bbox &&
+ (vdev->bbox_device =
+ gs_alloc_struct_immovable(vdev->v_memory,
+ gx_device_bbox, &st_device_bbox,
+ "vector_open(bbox_device)")) == 0)
+ )
+ { if ( vdev->bbox_device )
+ gs_free_object(vdev->v_memory, vdev->bbox_device,
+ "vector_open(bbox_device)");
+ vdev->bbox_device = 0;
+ if ( vdev->strm )
+ gs_free_object(vdev->v_memory, vdev->strm,
+ "vector_open(strm)");
+ vdev->strm = 0;
+ if ( vdev->strmbuf )
+ gs_free_object(vdev->v_memory, vdev->strmbuf,
+ "vector_open(strmbuf)");
+ vdev->strmbuf = 0;
+ fclose(vdev->file);
+ vdev->file = 0;
+ return_error(gs_error_VMerror);
+ }
+ vdev->strmbuf_size = strmbuf_size;
+ swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
+ /*
+ * We don't want finalization to close the file, but we do want it
+ * to flush the stream buffer.
+ */
+ vdev->strm->procs.close = vdev->strm->procs.flush;
+ if ( vdev->bbox_device )
+ { gx_device_bbox_init(vdev->bbox_device, NULL);
+ gx_device_set_resolution((gx_device *)vdev->bbox_device,
+ vdev->HWResolution[0],
+ vdev->HWResolution[1]);
+ /* Do the right thing about upright vs. inverted. */
+ /* (This is dangerous in general, since the procedure */
+ /* might reference non-standard elements.) */
+ set_dev_proc(vdev->bbox_device, get_initial_matrix,
+ dev_proc(vdev, get_initial_matrix));
+ (*dev_proc(vdev->bbox_device, open_device))
+ ((gx_device *)vdev->bbox_device);
+ }
+ return 0;
+}
+
+/* Get the current stream, calling beginpage if in_page is false. */
+stream *
+gdev_vector_stream(gx_device_vector *vdev)
+{ if ( !vdev->in_page )
+ { (*vdev_proc(vdev, beginpage))(vdev);
+ vdev->in_page = true;
+ }
+ return vdev->strm;
+}
+
+/* Compare two drawing colors. */
+/* Right now we don't attempt to handle non-pure colors. */
+private bool
+drawing_color_eq(const gx_drawing_color *pdc1, const gx_drawing_color *pdc2)
+{ return (gx_dc_is_pure(pdc1) ?
+ gx_dc_is_pure(pdc2) &&
+ gx_dc_pure_color(pdc1) == gx_dc_pure_color(pdc2) :
+ gx_dc_is_null(pdc1) ?
+ gx_dc_is_null(pdc2) :
+ false);
+}
+
+/* Update the logical operation. */
+int
+gdev_vector_update_log_op(gx_device_vector *vdev, gs_logical_operation_t lop)
+{ gs_logical_operation_t diff = lop ^ vdev->state.log_op;
+ if ( diff != 0 )
+ { int code = (*vdev_proc(vdev, setlogop))(vdev, lop, diff);
+ if ( code < 0 )
+ return code;
+ vdev->state.log_op = lop;
+ }
+ return 0;
+}
+
+/* Update the fill color. */
+int
+gdev_vector_update_fill_color(gx_device_vector *vdev,
+ const gx_drawing_color *pdcolor)
+{ if ( !drawing_color_eq(pdcolor, &vdev->fill_color) )
+ { int code = (*vdev_proc(vdev, setfillcolor))(vdev, pdcolor);
+ if ( code < 0 )
+ return code;
+ vdev->fill_color = *pdcolor;
+ }
+ return 0;
+}
+
+/* Update the state for filling a region. */
+private int
+update_fill(gx_device_vector *vdev, const gx_drawing_color *pdcolor,
+ gs_logical_operation_t lop)
+{ int code = gdev_vector_update_fill_color(vdev, pdcolor);
+ if ( code < 0 )
+ return code;
+ return gdev_vector_update_log_op(vdev, lop);
+}
+
+/* Bring state up to date for filling. */
+int
+gdev_vector_prepare_fill(gx_device_vector *vdev, const gs_imager_state *pis,
+ const gx_fill_params *params, const gx_drawing_color *pdcolor)
+{ if ( params->flatness != vdev->state.flatness )
+ { int code = (*vdev_proc(vdev, setflat))(vdev, params->flatness);
+ if ( code < 0 )
+ return code;
+ vdev->state.flatness = params->flatness;
+ }
+ return update_fill(vdev, pdcolor, pis->log_op);
+}
+
+/* Compare two dash patterns. */
+private bool
+dash_pattern_eq(const float *stored, const gx_dash_params *set, floatp scale)
+{ int i;
+ for ( i = 0; i < set->pattern_size; ++i )
+ if ( stored[i] != (float)(set->pattern[i] * scale) )
+ return false;
+ return true;
+}
+
+/* Bring state up to date for stroking. */
+int
+gdev_vector_prepare_stroke(gx_device_vector *vdev, const gs_imager_state *pis,
+ const gx_stroke_params *params, const gx_drawing_color *pdcolor,
+ floatp scale)
+{ int pattern_size = pis->line_params.dash.pattern_size;
+ float dash_offset = pis->line_params.dash.offset * scale;
+ float half_width = pis->line_params.half_width * scale;
+
+ if ( pattern_size > max_dash )
+ return_error(gs_error_limitcheck);
+ if ( dash_offset != vdev->state.line_params.dash.offset ||
+ pattern_size != vdev->state.line_params.dash.pattern_size ||
+ (pattern_size != 0 &&
+ !dash_pattern_eq(vdev->dash_pattern, &pis->line_params.dash,
+ scale))
+ )
+ { float pattern[max_dash];
+ int i, code;
+
+ for ( i = 0; i < pattern_size; ++i )
+ pattern[i] = pis->line_params.dash.pattern[i] * scale;
+ code = (*vdev_proc(vdev, setdash))
+ (vdev, pattern, pattern_size, dash_offset);
+ if ( code < 0 )
+ return code;
+ memcpy(vdev->dash_pattern, pattern, pattern_size * sizeof(float));
+ vdev->state.line_params.dash.pattern_size = pattern_size;
+ vdev->state.line_params.dash.offset = dash_offset;
+ }
+ if ( params->flatness != vdev->state.flatness )
+ { int code = (*vdev_proc(vdev, setflat))(vdev, params->flatness);
+ if ( code < 0 )
+ return code;
+ vdev->state.flatness = params->flatness;
+ }
+ if ( half_width != vdev->state.line_params.half_width )
+ { int code = (*vdev_proc(vdev, setlinewidth))
+ (vdev, pis->line_params.half_width * 2);
+ if ( code < 0 )
+ return code;
+ vdev->state.line_params.half_width = half_width;
+ }
+ if ( pis->line_params.miter_limit != vdev->state.line_params.miter_limit )
+ { int code = (*vdev_proc(vdev, setmiterlimit))
+ (vdev, pis->line_params.miter_limit);
+ if ( code < 0 )
+ return code;
+ gx_set_miter_limit(&vdev->state.line_params,
+ pis->line_params.miter_limit);
+ }
+ if ( pis->line_params.cap != vdev->state.line_params.cap )
+ { int code = (*vdev_proc(vdev, setlinecap))
+ (vdev, pis->line_params.cap);
+ if ( code < 0 )
+ return code;
+ vdev->state.line_params.cap = pis->line_params.cap;
+ }
+ if ( pis->line_params.join != vdev->state.line_params.join )
+ { int code = (*vdev_proc(vdev, setlinejoin))
+ (vdev, pis->line_params.join);
+ if ( code < 0 )
+ return code;
+ vdev->state.line_params.join = pis->line_params.join;
+ }
+ { int code = gdev_vector_update_log_op(vdev, pis->log_op);
+ if ( code < 0 )
+ return code;
+ }
+ if ( !drawing_color_eq(pdcolor, &vdev->stroke_color) )
+ { int code = (*vdev_proc(vdev, setstrokecolor))(vdev, pdcolor);
+ if ( code < 0 )
+ return code;
+ vdev->stroke_color = *pdcolor;
+ }
+ return 0;
+}
+
+/* Write a polygon as part of a path. */
+/* May call beginpath, moveto, lineto, closepath, endpath. */
+int
+gdev_vector_write_polygon(gx_device_vector *vdev, const gs_fixed_point *points,
+ uint count, bool close, gx_path_type_t type)
+{ int code = 0;
+
+ if ( type != gx_path_type_none &&
+ (code = (*vdev_proc(vdev, beginpath))(vdev, type)) < 0
+ )
+ return code;
+ if ( count > 0 )
+ { double x = fixed2float(points[0].x) / vdev->scale.x,
+ y = fixed2float(points[0].y) / vdev->scale.y;
+ double x_start = x, y_start = y, x_prev, y_prev;
+ uint i;
+
+ code = (*vdev_proc(vdev, moveto))
+ (vdev, 0.0, 0.0, x, y, true);
+ if ( code >= 0 )
+ for ( i = 1; i < count && code >= 0; ++i )
+ { x_prev = x, y_prev = y;
+ code = (*vdev_proc(vdev, lineto))
+ (vdev, x_prev, y_prev,
+ (x = fixed2float(points[i].x) / vdev->scale.x),
+ (y = fixed2float(points[i].y) / vdev->scale.y));
+ }
+ if ( code >= 0 && close )
+ code = (*vdev_proc(vdev, closepath))
+ (vdev, x, y, x_start, y_start);
+ }
+ return (code >= 0 && type != gx_path_type_none ?
+ (*vdev_proc(vdev, endpath))(vdev, type) : code);
+}
+
+/* Write a rectangle as part of a path. */
+/* May call moveto, lineto, closepath. */
+int
+gdev_vector_write_rectangle(gx_device_vector *vdev, fixed x0, fixed y0,
+ fixed x1, fixed y1, bool close, gx_rect_direction_t direction)
+{ gs_fixed_point points[4];
+
+ points[0].x = x0, points[0].y = y0;
+ points[2].x = x1, points[2].y = y1;
+ if ( direction == gx_rect_x_first )
+ points[1].x = x1, points[1].y = y0,
+ points[3].x = x0, points[3].y = y1;
+ else
+ points[1].x = x0, points[1].y = y1,
+ points[3].x = x1, points[3].y = y0;
+ return gdev_vector_write_polygon(vdev, points, 4, close,
+ gx_path_type_none);
+}
+
+/* Write a clipping path by calling the path procedures. */
+int
+gdev_vector_write_clip_path(gx_device_vector *vdev, const gx_clip_path *pcpath)
+{ const gx_clip_rect *prect;
+ gx_clip_rect page_rect;
+ int code;
+
+ if ( pcpath == 0 )
+ { /* There's no special provision for initclip. */
+ /* Write a rectangle that covers the entire page. */
+ page_rect.xmin = page_rect.ymin = 0;
+ page_rect.xmax = vdev->width;
+ page_rect.ymax = vdev->height;
+ page_rect.next = 0;
+ prect = &page_rect;
+ }
+ else if ( pcpath->segments_valid )
+ return (*vdev_proc(vdev, dopath))(vdev, &pcpath->path,
+ gx_path_type_clip);
+ else
+ { prect = pcpath->list.head;
+ if ( prect == 0 )
+ prect = &pcpath->list.single;
+ }
+ /* Write out the rectangles. */
+ code = (*vdev_proc(vdev, beginpath))(vdev, gx_path_type_clip);
+ for ( ; code >= 0 && prect != 0; prect = prect->next )
+ if ( prect->xmax > prect->xmin && prect->ymax > prect->ymin )
+ code = gdev_vector_write_rectangle
+ (vdev, int2fixed(prect->xmin), int2fixed(prect->ymin),
+ int2fixed(prect->xmax), int2fixed(prect->ymax),
+ false, gx_rect_x_first);
+ if ( code >= 0 )
+ code = (*vdev_proc(vdev, endpath))(vdev, gx_path_type_clip);
+ return code;
+}
+
+/* Update the clipping path if needed. */
+int
+gdev_vector_update_clip_path(gx_device_vector *vdev,
+ const gx_clip_path *pcpath)
+{ if ( pcpath )
+ { if ( pcpath->id != vdev->clip_path_id )
+ { int code = gdev_vector_write_clip_path(vdev, pcpath);
+ if ( code < 0 )
+ return code;
+ vdev->clip_path_id = pcpath->id;
+ }
+ }
+ else
+ { if ( vdev->clip_path_id != vdev->no_clip_path_id )
+ { int code = gdev_vector_write_clip_path(vdev, NULL);
+ if ( code < 0 )
+ return code;
+ vdev->clip_path_id = vdev->no_clip_path_id;
+ }
+ }
+ return 0;
+}
+
+/* Close the output file and stream. */
+void
+gdev_vector_close_file(gx_device_vector *vdev)
+{ gs_free_object(vdev->v_memory, vdev->bbox_device,
+ "vector_close(bbox_device)");
+ vdev->bbox_device = 0;
+ sclose(vdev->strm);
+ gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)");
+ vdev->strm = 0;
+ gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)");
+ vdev->strmbuf = 0;
+ fclose(vdev->file); /* we prevented sclose from doing this */
+ vdev->file = 0;
+}
+
+/* ---------------- Image enumeration ---------------- */
+
+/* Initialize for enumerating an image. */
+int
+gdev_vector_begin_image(gx_device_vector *vdev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, gdev_vector_image_enum_t *pie)
+{ const gs_color_space *pcs = pim->ColorSpace;
+ int num_components;
+ int bits_per_pixel;
+ int code;
+
+ if ( pim->ImageMask )
+ bits_per_pixel = num_components = 1;
+ else
+ num_components = gs_color_space_num_components(pcs),
+ bits_per_pixel = pim->BitsPerComponent;
+ switch ( format )
+ {
+ case gs_image_format_chunky:
+ pie->num_planes = 1;
+ pie->bits_per_pixel = bits_per_pixel * num_components;
+ break;
+ case gs_image_format_component_planar:
+ pie->num_planes = num_components;
+ pie->bits_per_pixel = bits_per_pixel;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ pie->default_info = 0;
+ pie->bbox_info = 0;
+ if ( (code = gdev_vector_update_log_op(vdev, pis->log_op)) < 0 ||
+ (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
+ ((pim->ImageMask ||
+ (pim->CombineWithColor && rop3_uses_T(pis->log_op))) &&
+ (code = gdev_vector_update_fill_color(vdev, pdcolor)) < 0) ||
+ (vdev->bbox_device &&
+ (code = (*dev_proc(vdev->bbox_device, begin_image))
+ ((gx_device *)vdev->bbox_device, pis, pim, format, prect,
+ pdcolor, pcpath, mem, &pie->bbox_info)) < 0)
+ )
+ return code;
+ pie->memory = mem;
+ if ( prect )
+ pie->width = prect->q.x - prect->p.x,
+ pie->height = prect->q.y - prect->p.y;
+ else
+ pie->width = pim->Width, pie->height = pim->Height;
+ pie->bits_per_row = pie->width * pie->bits_per_pixel;
+ pie->y = 0;
+ return 0;
+}
+
+/* End an image, optionally supplying any necessary blank padding rows. */
+/* Return 0 if we used the default implementation, 1 if not. */
+int
+gdev_vector_end_image(gx_device_vector *vdev,
+ gdev_vector_image_enum_t *pie, bool draw_last, gx_color_index pad)
+{ int code;
+
+ if ( pie->default_info )
+ { code = gx_default_end_image((gx_device *)vdev, pie->default_info,
+ draw_last);
+ if ( code >= 0 )
+ code = 0;
+ }
+ else
+ { /* Fill out to the full image height. */
+ if ( pie->y < pie->height && pad != gx_no_color_index )
+ { uint bytes_per_row = (pie->bits_per_row + 7) >> 3;
+ byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
+ "gdev_vector_end_image(fill)");
+
+ if ( row == 0 )
+ return_error(gs_error_VMerror);
+ /****** FILL VALUE IS WRONG ******/
+ memset(row, (byte)pad, bytes_per_row);
+ for ( ; pie->y < pie->height; pie->y++ )
+ (*dev_proc(vdev, image_data))((gx_device *)vdev, pie,
+ (const byte **)&row, 0,
+ bytes_per_row, 1);
+ gs_free_object(pie->memory, row,
+ "gdev_vector_end_image(fill)");
+ }
+ code = 1;
+ }
+ if ( vdev->bbox_device )
+ { int bcode = (*dev_proc(vdev->bbox_device, end_image))
+ ((gx_device *)vdev->bbox_device, pie->bbox_info, draw_last);
+ if ( bcode < 0 )
+ code = bcode;
+ }
+ gs_free_object(pie->memory, pie, "pclxl_end_image");
+ return code;
+}
+
+/* ================ Device procedures ================ */
+
+#define vdev ((gx_device_vector *)dev)
+
+/* Get parameters. */
+int
+gdev_vector_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_default_get_params(dev, plist);
+ int ecode;
+ gs_param_string ofns;
+
+ if ( code < 0 )
+ return code;
+ ofns.data = (const byte *)vdev->fname,
+ ofns.size = strlen(vdev->fname),
+ ofns.persistent = false;
+ if ( (ecode = param_write_string(plist, "OutputFile", &ofns)) < 0 )
+ return ecode;
+ return code;
+}
+
+/* Put parameters. */
+int
+gdev_vector_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ gs_param_string ofns;
+
+ switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofns) )
+ {
+ case 0:
+ if ( ofns.size > fname_size )
+ ecode = gs_error_limitcheck;
+ else
+ break;
+ goto ofe;
+ default:
+ ecode = code;
+ofe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ ofns.data = 0;
+ break;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ { bool open = dev->is_open;
+ /* Don't let gx_default_put_params close the device. */
+ dev->is_open = false;
+ code = gx_default_put_params(dev, plist);
+ dev->is_open = open;
+ }
+ if ( code < 0 )
+ return code;
+
+ if ( ofns.data != 0 &&
+ bytes_compare(ofns.data, ofns.size,
+ (const byte *)vdev->fname, strlen(vdev->fname))
+ )
+ { memcpy(vdev->fname, ofns.data, ofns.size);
+ vdev->fname[ofns.size] = 0;
+ if ( vdev->file != 0 )
+ { gdev_vector_close_file(vdev);
+ return gdev_vector_open_file(vdev, vdev->strmbuf_size);
+ }
+ }
+
+ gdev_vector_load_cache(vdev); /* in case color mapping changed */
+ return 0;
+}
+
+/* ---------------- Defaults ---------------- */
+
+int
+gdev_vector_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_drawing_color dcolor;
+
+ /* Ignore the initial fill with white. */
+ if ( !vdev->in_page && color == vdev->white )
+ return 0;
+ color_set_pure(&dcolor, color);
+ { int code = update_fill(vdev, &dcolor, rop3_T);
+ if ( code < 0 )
+ return code;
+ }
+ if ( vdev->bbox_device )
+ { int code = (*dev_proc(vdev->bbox_device, fill_rectangle))
+ ((gx_device *)vdev->bbox_device, x, y, w, h, color);
+ if ( code < 0 )
+ return code;
+ }
+ return (*vdev_proc(vdev, dorect))(vdev, int2fixed(x), int2fixed(y),
+ int2fixed(x + w), int2fixed(y + h),
+ gx_path_type_fill);
+}
+
+int
+gdev_vector_fill_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_fill_params *params,
+ const gx_device_color *pdevc, const gx_clip_path *pcpath)
+{ int code;
+
+ if ( (code = gdev_vector_prepare_fill(vdev, pis, params, pdevc)) < 0 ||
+ (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
+ (vdev->bbox_device &&
+ (code = (*dev_proc(vdev->bbox_device, fill_path))
+ ((gx_device *)vdev->bbox_device, pis, ppath, params,
+ pdevc, pcpath)) < 0) ||
+ (code = (*vdev_proc(vdev, dopath))
+ (vdev, ppath,
+ (params->rule > 0 ? gx_path_type_even_odd :
+ gx_path_type_winding_number) | gx_path_type_fill)) < 0
+ )
+ return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
+ return code;
+}
+
+int
+gdev_vector_stroke_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ int code;
+
+ /****** HANDLE SCALE ******/
+ if ( (code = gdev_vector_prepare_stroke(vdev, pis, params, pdcolor,
+ dev->HWResolution[0])) < 0 ||
+ (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
+ (vdev->bbox_device &&
+ (code = (*dev_proc(vdev->bbox_device, stroke_path))
+ ((gx_device *)vdev->bbox_device, pis, ppath, params,
+ pdcolor, pcpath)) < 0) ||
+ (code = (*vdev_proc(vdev, dopath))
+ (vdev, ppath, gx_path_type_stroke)) < 0
+ )
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor, pcpath);
+ return code;
+}
+
+int
+gdev_vector_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left,
+ const gs_fixed_edge *right, fixed ybot, fixed ytop, bool swap_axes,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ fixed xl = left->start.x;
+ fixed wl = left->end.x - xl;
+ fixed yl = left->start.y;
+ fixed hl = left->end.y - yl;
+ fixed xr = right->start.x;
+ fixed wr = right->end.x - xr;
+ fixed yr = right->start.y;
+ fixed hr = right->end.y - yr;
+ fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl);
+ fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl);
+ fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr);
+ fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr);
+#define y0 ybot
+#define y1 ytop
+ gs_fixed_point points[4];
+
+ if ( swap_axes )
+ points[0].y = x0l, points[1].y = x0r,
+ points[0].x = points[1].x = y0,
+ points[2].y = x1r, points[3].y = x1l,
+ points[2].x = points[3].x = y1;
+ else
+ points[0].x = x0l, points[1].x = x0r,
+ points[0].y = points[1].y = y0,
+ points[2].x = x1r, points[3].x = x1l,
+ points[2].y = points[3].y = y1;
+#undef y0
+#undef y1
+ if ( vdev->bbox_device )
+ { int code = (*dev_proc(vdev->bbox_device, fill_trapezoid))
+ ((gx_device *)vdev->bbox_device, left, right, ybot, ytop,
+ swap_axes, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ return gdev_vector_write_polygon(vdev, points, 4, true,
+ gx_path_type_fill);
+}
+
+int
+gdev_vector_fill_parallelogram(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ fixed pax = px + ax, pay = py + ay;
+ int code = update_fill(vdev, pdevc, lop);
+ gs_fixed_point points[4];
+
+ if ( code < 0 )
+ return code;
+ if ( vdev->bbox_device )
+ { code = (*dev_proc(vdev->bbox_device, fill_parallelogram))
+ ((gx_device *)vdev->bbox_device, px, py, ax, ay, bx, by,
+ pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ points[0].x = px, points[0].y = py;
+ points[1].x = pax, points[0].y = pay;
+ points[2].x = pax + bx, points[2].y = pay + by;
+ points[3].x = px + bx, points[3].y = py + by;
+ return gdev_vector_write_polygon(vdev, points, 4, true,
+ gx_path_type_fill);
+}
+
+int
+gdev_vector_fill_triangle(gx_device *dev,
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ int code = update_fill(vdev, pdevc, lop);
+ gs_fixed_point points[3];
+
+ if ( code < 0 )
+ return code;
+ if ( vdev->bbox_device )
+ { code = (*dev_proc(vdev->bbox_device, fill_triangle))
+ ((gx_device *)vdev->bbox_device, px, py, ax, ay, bx, by,
+ pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ points[0].x = px, points[0].y = py;
+ points[1].x = px + ax, points[1].y = py + ay;
+ points[2].x = px + bx, points[2].y = py + by;
+ return gdev_vector_write_polygon(vdev, points, 3, true,
+ gx_path_type_fill);
+}
+
+#undef vdev
diff --git a/gs/src/gdevvec.h b/gs/src/gdevvec.h
new file mode 100644
index 000000000..9a0cd1127
--- /dev/null
+++ b/gs/src/gdevvec.h
@@ -0,0 +1,328 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevvec.h */
+/* Common definitions for "vector" devices */
+#include "gsropt.h"
+#include "gxdevice.h"
+#include "gdevbbox.h"
+#include "gxistate.h"
+#include "stream.h"
+
+/******
+ ****** NOTE: EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE.
+ ****** USE AT YOUR OWN RISK.
+ ******/
+
+/*
+ * "Vector" devices produce a stream of higher-level drawing commands rather
+ * than a raster image. (We don't like the term "vector", since the command
+ * vocabulary typically includes text and raster images as well as actual
+ * vectors, but it's widely used in the industry, and we weren't able to
+ * find one that read better.) Some examples of "vector" formats are PDF,
+ * PostScript, PCL XL, HP-GL/2 + RTL, CGM, Windows Metafile, and Macintosh
+ * PICT.
+ *
+ * This file extends the basic driver structure with elements likely to be
+ * useful to vector devices. These include:
+ *
+ * - Tracking whether any marks have been made on the page;
+ *
+ * - Keeping track of the page bounding box;
+ *
+ * - A copy of the most recently written current graphics state
+ * parameters;
+ *
+ * - An output stream (for drivers that compress or otherwise filter
+ * their output);
+ *
+ * - A vector of procedures for writing changes to the graphics state.
+ *
+ * - The ability to work with scaled output coordinate systems.
+ *
+ * We expect to add more elements and procedures as we gain more experience
+ * with this kind of driver.
+ */
+
+/* ================ Types and structures ================ */
+
+/* Define the abstract type for a vector device. */
+typedef struct gx_device_vector_s gx_device_vector;
+
+/* Define the maximum size of the output file name. */
+#define fname_size 80
+
+/* Define the longest dash pattern we can remember. */
+#define max_dash 11
+
+/*
+ * Define procedures for writing common output elements. Not all devices
+ * will support all of these elements. Note that these procedures normally
+ * only write out commands, and don't update the driver state itself. All
+ * of them are optional, called only as indicated under the utility
+ * procedures below.
+ */
+typedef enum {
+ gx_path_type_none = 0,
+ /*
+ * All combinations of flags are legal. Multiple commands are
+ * executed in the order fill, stroke, clip.
+ */
+ gx_path_type_fill = 1,
+ gx_path_type_stroke = 2,
+ gx_path_type_clip = 4,
+ gx_path_type_winding_number = 0,
+ gx_path_type_even_odd = 8,
+ gx_path_type_rule = gx_path_type_winding_number | gx_path_type_even_odd
+} gx_path_type_t;
+typedef enum {
+ gx_rect_x_first,
+ gx_rect_y_first
+} gx_rect_direction_t;
+typedef struct gx_device_vector_procs_s {
+ /* Page management */
+ int (*beginpage)(P1(gx_device_vector *vdev));
+ /* Imager state */
+ int (*setlinewidth)(P2(gx_device_vector *vdev, floatp width));
+ int (*setlinecap)(P2(gx_device_vector *vdev, gs_line_cap cap));
+ int (*setlinejoin)(P2(gx_device_vector *vdev, gs_line_join join));
+ int (*setmiterlimit)(P2(gx_device_vector *vdev, floatp limit));
+ int (*setdash)(P4(gx_device_vector *vdev, const float *pattern,
+ uint count, floatp offset));
+ int (*setflat)(P2(gx_device_vector *vdev, floatp flatness));
+ int (*setlogop)(P3(gx_device_vector *vdev, gs_logical_operation_t lop,
+ gs_logical_operation_t diff));
+ /* Other state */
+ int (*setfillcolor)(P2(gx_device_vector *vdev, const gx_drawing_color *pdc));
+ int (*setstrokecolor)(P2(gx_device_vector *vdev, const gx_drawing_color *pdc));
+ /* Paths */
+ /* dopath and dorect are normally defaulted */
+ int (*dopath)(P3(gx_device_vector *vdev, const gx_path *ppath,
+ gx_path_type_t type));
+ int (*dorect)(P6(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
+ fixed y1, gx_path_type_t type));
+ int (*beginpath)(P2(gx_device_vector *vdev, gx_path_type_t type));
+ int (*moveto)(P6(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x, floatp y, bool first));
+ int (*lineto)(P5(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x, floatp y));
+ int (*curveto)(P9(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x1, floatp y1, floatp x2, floatp y2,
+ floatp x3, floatp y3));
+ int (*closepath)(P5(gx_device_vector *vdev, floatp x0, floatp y0,
+ floatp x_start, floatp y_start));
+ int (*endpath)(P2(gx_device_vector *vdev, gx_path_type_t type));
+} gx_device_vector_procs;
+
+/* Default implementations of procedures */
+/* setflat does nothing */
+int gdev_vector_setflat(P2(gx_device_vector *vdev, floatp flatness));
+/* dopath may call dorect, beginpath, moveto/lineto/curveto/closepath, */
+/* endpath */
+int gdev_vector_dopath(P3(gx_device_vector *vdev, const gx_path *ppath,
+ gx_path_type_t type));
+/* dorect may call beginpath, moveto, lineto, closepath */
+int gdev_vector_dorect(P6(gx_device_vector *vdev, fixed x0, fixed y0,
+ fixed x1, fixed y1, gx_path_type_t type));
+
+/* Finally, define the extended device structure. */
+#define gx_device_vector_common\
+ gx_device_common;\
+ gs_memory_t *v_memory;\
+ /* Output element writing procedures */\
+ const gx_device_vector_procs *vec_procs;\
+ /* Output file */\
+ char fname[fname_size + 1];\
+ FILE *file;\
+ stream *strm;\
+ byte *strmbuf;\
+ uint strmbuf_size;\
+ /* Graphics state */\
+ gs_imager_state state;\
+ float dash_pattern[max_dash];\
+ gx_drawing_color fill_color, stroke_color;\
+ gs_id no_clip_path_id; /* indicates no clipping */\
+ gs_id clip_path_id;\
+ /* Other state */\
+ gs_point scale; /* device coords / scale => output coords */\
+ bool in_page; /* true if any marks on this page */\
+ gx_device_bbox *bbox_device; /* for tracking bounding box */\
+ /* Cached values */\
+ gx_color_index black, white
+#define vdev_proc(vdev, p) ((vdev)->vec_procs->p)
+
+#define vector_initial_values\
+ 0, /* v_memory */\
+ 0, /* vec_procs */\
+ { 0 }, /* fname */\
+ 0, /* file */\
+ 0, /* strm */\
+ 0, /* strmbuf */\
+ 0, /* strmbuf_size */\
+ { 0 }, /* state */\
+ { 0 }, /* dash_pattern */\
+ { 0 }, /* fill_color ****** WRONG ****** */\
+ { 0 }, /* stroke_color ****** WRONG ****** */\
+ gs_no_id, /* clip_path_id */\
+ gs_no_id, /* no_clip_path_id */\
+ { X_DPI/72.0, Y_DPI/72.0 }, /* scale */\
+ 0/*false*/, /* in_page */\
+ 0, /* bbox_device */\
+ gx_no_color_index, /* black */\
+ gx_no_color_index /* white */
+
+struct gx_device_vector_s {
+ gx_device_vector_common;
+};
+/* st_device_vector is never instantiated per se, but we still need to */
+/* extern its descriptor for the sake of subclasses. */
+extern_st(st_device_vector);
+#define public_st_device_vector() /* in gdevvec.c */\
+ gs_public_st_suffix_add3_final(st_device_vector, gx_device_vector,\
+ "gx_device_vector", device_vector_enum_ptrs,\
+ device_vector_reloc_ptrs, gx_device_finalize, st_device, strm, strmbuf,\
+ bbox_device)
+#define st_device_vector_max_ptrs (st_device_max_ptrs + 3)
+
+/* ================ Utility procedures ================ */
+
+/* Initialize the state. */
+void gdev_vector_init(P1(gx_device_vector *vdev));
+
+/* Reset the remembered graphics state. */
+void gdev_vector_reset(P1(gx_device_vector *vdev));
+
+/* Open the output file and stream, with optional bbox tracking. */
+int gdev_vector_open_file_bbox(P3(gx_device_vector *vdev, uint strmbuf_size,
+ bool bbox));
+#define gdev_vector_open_file(vdev, strmbuf_size)\
+ gdev_vector_open_file_bbox(vdev, strmbuf_size, false)
+
+/* Get the current stream, calling beginpage if in_page is false. */
+stream *gdev_vector_stream(P1(gx_device_vector *vdev));
+
+/* Bring the logical operation up to date. */
+/* May call setlogop. */
+int gdev_vector_update_log_op(P2(gx_device_vector *vdev,
+ gs_logical_operation_t lop));
+
+/* Bring the fill color up to date. */
+/* May call setfillcolor. */
+int gdev_vector_update_fill_color(P2(gx_device_vector *vdev,
+ const gx_drawing_color *pdcolor));
+
+/* Bring state up to date for filling. */
+/* May call setflat, setfillcolor, setlogop. */
+int gdev_vector_prepare_fill(P4(gx_device_vector *vdev,
+ const gs_imager_state *pis,
+ const gx_fill_params *params,
+ const gx_drawing_color *pdcolor));
+
+/* Bring state up to date for stroking. Note that we pass the scale */
+/* for the line width and dash offset explicitly. */
+/* May call setlinewidth, setlinecap, setlinejoin, setmiterlimit, */
+/* setdash, setflat, setstrokecolor, setlogop. */
+int gdev_vector_prepare_stroke(P5(gx_device_vector *vdev,
+ const gs_imager_state *pis,
+ const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor,
+ floatp scale));
+
+/* Write a polygon as part of a path (type = gx_path_type_none) */
+/* or as a path. */
+/* May call moveto, lineto, closepath (if close); */
+/* may call beginpath & endpath if type != none. */
+int gdev_vector_write_polygon(P5(gx_device_vector *vdev,
+ const gs_fixed_point *points, uint count,
+ bool close, gx_path_type_t type));
+
+/* Write a rectangle as part of a path. */
+/* May call moveto, lineto, closepath (if close). */
+int gdev_vector_write_rectangle(P7(gx_device_vector *vdev,
+ fixed x0, fixed y0, fixed x1, fixed y1,
+ bool close, gx_rect_direction_t dir));
+
+/* Write a clipping path by calling the path procedures. */
+/* May call the same procedures as writepath. */
+int gdev_vector_write_clip_path(P2(gx_device_vector *vdev,
+ const gx_clip_path *pcpath));
+
+/* Bring the clipping state up to date. */
+/* May call write_rectangle (q.v.), write_clip_path (q.v.). */
+int gdev_vector_update_clip_path(P2(gx_device_vector *vdev,
+ const gx_clip_path *pcpath));
+
+/* Close the output file and stream. */
+void gdev_vector_close_file(P1(gx_device_vector *vdev));
+
+/* ---------------- Image enumeration ---------------- */
+
+/* Define a common set of state parameters for enumerating images. */
+#define gdev_vector_image_enum_common\
+ /* Set by begin_image */\
+ gs_memory_t *memory; /* from begin_image */\
+ void *default_info; /* non-0 iff using default implementation */\
+ void *bbox_info; /* non-0 iff passing image data to bbox dev */\
+ int width, height;\
+ int num_planes;\
+ int bits_per_pixel; /* (per plane) */\
+ uint bits_per_row; /* (per plane) */\
+ /* Updated dynamically by image_data */\
+ int y /* 0 <= y < height */
+typedef struct gdev_vector_image_enum_s {
+ gdev_vector_image_enum_common;
+} gdev_vector_image_enum_t;
+extern_st(st_vector_image_enum);
+#define public_st_vector_image_enum() /* in gdevvec.c */\
+ gs_public_st_ptrs2(st_vector_image_enum, gdev_vector_image_enum_t,\
+ "gdev_vector_image_enum_t", vector_image_enum_enum_ptrs,\
+ vector_image_enum_reloc_ptrs, default_info, bbox_info)
+
+/* Initialize for enumerating an image. */
+/* Note that the last argument is an already-allocated enumerator, */
+/* not a pointer to the place to store the enumerator. */
+int gdev_vector_begin_image(P9(gx_device_vector *vdev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, gdev_vector_image_enum_t *pie));
+
+/* End an image, optionally supplying any necessary blank padding rows. */
+/* Return 0 if we used the default implementation, 1 if not. */
+int gdev_vector_end_image(P4(gx_device_vector *vdev,
+ gdev_vector_image_enum_t *pie, bool draw_last, gx_color_index pad));
+
+/* ================ Device procedures ================ */
+
+/* Redefine get/put_params to handle OutputFile. */
+dev_proc_put_params(gdev_vector_put_params);
+dev_proc_get_params(gdev_vector_get_params);
+
+/* ---------------- Defaults ---------------- */
+
+/* fill_rectangle may call setfillcolor, dorect. */
+dev_proc_fill_rectangle(gdev_vector_fill_rectangle);
+/* fill_path may call prepare_fill, writepath, write_clip_path. */
+dev_proc_fill_path(gdev_vector_fill_path);
+/* stroke_path may call prepare_stroke, write_path, write_clip_path. */
+dev_proc_stroke_path(gdev_vector_stroke_path);
+/* fill_trapezoid, fill_parallelogram, and fill_triangle may call */
+/* setfillcolor, setlogop, beginpath, moveto, lineto, endpath. */
+dev_proc_fill_trapezoid(gdev_vector_fill_trapezoid);
+dev_proc_fill_parallelogram(gdev_vector_fill_parallelogram);
+dev_proc_fill_triangle(gdev_vector_fill_triangle);
diff --git a/gs/src/gdevvglb.c b/gs/src/gdevvglb.c
new file mode 100644
index 000000000..f36fb33a7
--- /dev/null
+++ b/gs/src/gdevvglb.c
@@ -0,0 +1,389 @@
+/* Copyright (C) 1992, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/*
+ * gdevvglb.c
+ *
+ * This is a driver for 386 PCs using VGALIB for graphics on the console
+ * display.
+ *
+ * Written by Sigfrid Lundberg, siglun@euler.teorekol.lu.se.
+ * Modified by Erik Talvola, talvola@gnu.ai.mit.edu
+ * Updated 9/28/96 by L. Peter Deutsch, ghost@aladdin.com: allow setting
+ * the display mode as a device parameter.
+ * Updated 2/13/97 by ghost@aladdin.com: make the device identify itself
+ * as a page device.
+ * Updated 5/2/97 by ghost@aladdin.com: copy_mono computed some parameters
+ * before doing fit_copy.
+ * Update 1997-06-28 by ghost@aladdin.com: get_bits wasn't implemented.
+ */
+
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gdevpccm.h"
+
+#include <errno.h>
+#include <vga.h>
+
+typedef struct gx_device_vgalib {
+ gx_device_common;
+ int display_mode;
+} gx_device_vgalib;
+
+#define vga_dev ((gx_device_vgalib *)dev)
+
+#define XDPI 60 /* to get a more-or-less square aspect ratio */
+#define YDPI 60
+
+#ifndef A4 /*Letter size*/
+#define YSIZE (20.0 * YDPI / 2.5)
+#define XSIZE (8.5 / 11)*YSIZE /* 8.5 x 11 inch page, by default */
+#else /* A4 paper */
+#define XSIZE 8.27
+#define YSIZE 11.69
+#endif
+
+private dev_proc_open_device(vgalib_open);
+private dev_proc_close_device(vgalib_close);
+private dev_proc_map_rgb_color(vgalib_map_rgb_color);
+private dev_proc_map_color_rgb(vgalib_map_color_rgb);
+private dev_proc_fill_rectangle(vgalib_fill_rectangle);
+private dev_proc_tile_rectangle(vgalib_tile_rectangle);
+private dev_proc_copy_mono(vgalib_copy_mono);
+private dev_proc_copy_color(vgalib_copy_color);
+private dev_proc_get_bits(vgalib_get_bits);
+private dev_proc_get_params(vgalib_get_params);
+private dev_proc_put_params(vgalib_put_params);
+
+gx_device_vgalib far_data gs_vgalib_device = {
+ std_device_std_body(gx_device_vgalib, 0, "vgalib",
+ 0, 0, 1, 1),
+ { vgalib_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ vgalib_close,
+ vgalib_map_rgb_color,
+ vgalib_map_color_rgb,
+ vgalib_fill_rectangle,
+ vgalib_tile_rectangle,
+ vgalib_copy_mono,
+ vgalib_copy_color,
+ NULL, /* draw_line (obsolete) */
+ vgalib_get_bits,
+ vgalib_get_params,
+ vgalib_put_params,
+ NULL, /* map_cmyk_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device
+ },
+ -1 /* display_mode */
+};
+
+private int
+vgalib_open(gx_device *dev)
+{
+ int VGAMODE = vga_dev->display_mode;
+ int width = dev->width, height = dev->height;
+
+ if ( VGAMODE == -1 )
+ VGAMODE = vga_getdefaultmode();
+ if ( VGAMODE == -1 )
+ vga_setmode(G640x480x16);
+ else
+ vga_setmode(VGAMODE);
+ vga_clear();
+ if ( width == 0 )
+ width = vga_getxdim() + 1;
+ if ( height == 0 )
+ height = vga_getydim() + 1;
+
+ /*vgalib provides no facilities for finding out aspect ratios*/
+ if ( dev->y_pixels_per_inch == 1 )
+ {
+ dev->y_pixels_per_inch = height / 11.0;
+ dev->x_pixels_per_inch = dev->y_pixels_per_inch;
+ }
+ gx_device_set_width_height(dev, width, height);
+
+ /* Find out if the device supports color */
+ /* (default initialization is monochrome). */
+ /* We only recognize 16-color devices right now. */
+ if ( vga_getcolors() > 1 )
+ { int index;
+
+ static const gx_device_color_info vgalib_16color = dci_pc_4bit;
+ dev->color_info = vgalib_16color;
+
+ for ( index = 0; index < 16; ++index )
+ { gx_color_value rgb[3];
+ (*dev_proc(dev, map_color_rgb))(dev, (gx_color_index)index, rgb);
+#define cv2pv(cv) ((cv) >> (gx_color_value_bits - 8))
+ vga_setpalette(index, cv2pv(rgb[0]), cv2pv(rgb[1]), cv2pv(rgb[2]));
+#undef cv2pv
+ }
+ }
+
+ return 0;
+}
+
+private int
+vgalib_close(gx_device *dev)
+{
+ vga_setmode(TEXT);
+ return 0;
+}
+
+private gx_color_index
+vgalib_map_rgb_color(gx_device *dev, gx_color_value red,
+ gx_color_value green, gx_color_value blue)
+{
+ return pc_4bit_map_rgb_color(dev, red, green, blue);
+}
+
+private int
+vgalib_map_color_rgb(gx_device *dev, gx_color_index index,
+ unsigned short rgb[3])
+{
+ return pc_4bit_map_color_rgb(dev, index, rgb);
+}
+
+private int
+vgalib_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index czero,
+ gx_color_index cone, int px, int py)
+{
+ if ( czero != gx_no_color_index && cone != gx_no_color_index )
+ {
+ vgalib_fill_rectangle(dev, x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px,
+py);
+}
+
+private int
+vgalib_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ int i, j;
+
+ fit_fill(dev, x, y, w, h);
+ vga_setcolor((int)color);
+ if ( (w | h) > 3 )
+ { /* Draw larger rectangles as lines. */
+ if ( w > h )
+ for ( i = y; i < y + h; ++i )
+ vga_drawline(x, i, x + w - 1, i);
+ else
+ for ( j = x; j < x + w; ++j )
+ vga_drawline(j, y, j, y + h - 1);
+ }
+ else
+ { /* Draw small rectangles point-by-point. */
+ for(i=y;i<y+h;i++)
+ for(j=x;j<x+w;j++)
+ vga_drawpixel(j,i);
+ }
+ return 0;
+}
+
+private int
+vgalib_copy_mono(gx_device *dev, const byte *base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int width,
+ int height, gx_color_index zero, gx_color_index one)
+{
+ const byte *ptr_line;
+ int left_bit, dest_y, end_x;
+ int invert = 0;
+ int color;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, width, height);
+ ptr_line = base + (sourcex >> 3);
+ left_bit = 0x80 >> (sourcex & 7);
+ dest_y = y, end_x = x + width;
+
+ if ( zero == gx_no_color_index )
+ {
+ if ( one == gx_no_color_index )
+ return 0;
+ color = (int)one;
+ }
+ else
+ {
+ if ( one == gx_no_color_index )
+ {
+ color = (int)zero;
+ invert = -1;
+ }
+ else
+ { /* Pre-clear the rectangle to zero */
+ vgalib_fill_rectangle(dev,x,y,width,height,zero);
+ color = (int)one;
+ }
+ }
+
+ vga_setcolor(color);
+ while( height-- )
+ { /* for each line */
+ const byte *ptr_source = ptr_line;
+ register int dest_x = x;
+ register int bit = left_bit;
+
+ while ( dest_x < end_x )
+ { /* for each bit in the line */
+ if ( (*ptr_source ^ invert) & bit )
+ vga_drawpixel(dest_x,dest_y);
+ dest_x++;
+ if ( (bit >>= 1) == 0 )
+ bit = 0x80, ptr_source++;
+ }
+
+ dest_y++;
+ ptr_line += raster;
+ }
+ return 0;
+}
+
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 4 bits instead of 1 when device driver has color. */
+private int
+vgalib_copy_color(gx_device *dev, const byte *base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y,
+ int width, int height)
+{
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, width, height);
+
+ if ( gx_device_has_color(dev) )
+ { /* color device, four bits per pixel */
+ const byte *line = base + (sourcex >> 1);
+ int dest_y = y, end_x = x + width;
+
+ if ( width <= 0 )
+ return 0;
+ while ( height-- )
+ { /* for each line */
+ const byte *source = line;
+ register int dest_x = x;
+
+ if ( sourcex & 1 )
+ { /* odd nibble first */
+ int color = *source++ & 0xf;
+ vga_setcolor(color);
+ vga_drawpixel(dest_x,dest_y);
+ dest_x++;
+ }
+ /* Now do full bytes */
+ while ( dest_x < end_x )
+ {
+ int color = *source >> 4;
+ vga_setcolor(color);
+ vga_drawpixel(dest_x,dest_y);
+ dest_x++;
+
+ if ( dest_x < end_x )
+ {
+ color = *source++ & 0xf;
+ vga_setcolor(color);
+ vga_drawpixel(dest_x,dest_y);
+ dest_x++;
+ }
+ }
+
+ dest_y++;
+ line += raster;
+ }
+ }
+ else
+ { /* monochrome device: one bit per pixel */
+ /* bitmap is the same as bgi_copy_mono: one bit per pixel */
+ vgalib_copy_mono(dev, base, sourcex, raster, id, x, y, width, height,
+ (gx_color_index)0, (gx_color_index)7);
+ }
+
+ return 0;
+}
+
+/* Read bits back from the device. */
+private int
+vgalib_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ int x;
+ byte *dest = data;
+ int b = 0;
+ int depth = dev->color_info.depth; /* 1 or 4 */
+ int mask = (1 << depth) - 1;
+ int left = 8;
+
+ if ( actual_data )
+ *actual_data = data;
+ for ( x = 0; x < dev->width; ++x )
+ { int color = vga_getpixel(x, y);
+
+ if ( (left -= depth) < 0 )
+ *dest++ = b, b = 0, left += 8;
+ b += (color & mask) << left;
+ }
+ if ( left < 8 )
+ *dest = b;
+ return 0;
+}
+
+/* Get/put the display mode parameter. */
+private int
+vgalib_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gx_default_get_params(dev, plist);
+ if ( code < 0 )
+ return code;
+ return param_write_int(plist, "DisplayMode", &vga_dev->display_mode);
+}
+private int
+vgalib_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ int imode = vga_dev->display_mode;
+ const char _ds *param_name;
+
+ switch ( code = param_read_int(plist, (param_name = "DisplayMode"), &imode) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+ code = gx_default_put_params(dev, plist);
+ if ( code < 0 )
+ return code;
+
+ if ( imode != vga_dev->display_mode )
+ { if ( dev->is_open )
+ gs_closedevice(dev);
+ vga_dev->display_mode = imode;
+ }
+
+ return 0;
+}
diff --git a/gs/src/gdevwddb.c b/gs/src/gdevwddb.c
new file mode 100644
index 000000000..fdd0c69fc
--- /dev/null
+++ b/gs/src/gdevwddb.c
@@ -0,0 +1,604 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevwddb.c */
+/*
+ * Microsoft Windows 3.n driver for Ghostscript,
+ * using device-dependent bitmap.
+ * Original version by Russell Lang and Maurice Castro with help from
+ * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
+ * created from gdevbgi.c and gnuplot/term/win.trm 5th June 1992.
+ * Extensively modified by L. Peter Deutsch, Aladdin Enterprises.
+ */
+#include "gdevmswn.h"
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_win_ddb_s gx_device_win_ddb;
+#undef wdev
+#define wdev ((gx_device_win_ddb *)dev)
+
+/* Forward references */
+private void near win_addtool(P2(gx_device_win_ddb *, int));
+private void near win_maketools(P2(gx_device_win_ddb *, HDC));
+private void near win_destroytools(P1(gx_device_win_ddb *));
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(win_ddb_open);
+private dev_proc_close_device(win_ddb_close);
+private dev_proc_map_rgb_color(win_ddb_map_rgb_color);
+private dev_proc_fill_rectangle(win_ddb_fill_rectangle);
+private dev_proc_tile_rectangle(win_ddb_tile_rectangle);
+private dev_proc_copy_mono(win_ddb_copy_mono);
+private dev_proc_copy_color(win_ddb_copy_color);
+/* Windows-specific procedures */
+private win_proc_copy_to_clipboard(win_ddb_copy_to_clipboard);
+private win_proc_repaint(win_ddb_repaint);
+private win_proc_alloc_bitmap(win_ddb_alloc_bitmap);
+private win_proc_free_bitmap(win_ddb_free_bitmap);
+
+/* The device descriptor */
+struct gx_device_win_ddb_s {
+ gx_device_common;
+ gx_device_win_common;
+
+ /* Handles */
+
+ HBITMAP FAR hbitmap;
+ HDC FAR hdcbit;
+ HPEN hpen, *hpens;
+ uint hpensize;
+ HBRUSH hbrush, *hbrushs;
+ uint hbrushsize;
+#define select_brush(color)\
+ if (wdev->hbrush != wdev->hbrushs[color])\
+ { wdev->hbrush = wdev->hbrushs[color];\
+ SelectObject(wdev->hdcbit,wdev->hbrush);\
+ }
+ HPALETTE hpalette;
+ LPLOGPALETTE lpalette;
+
+ /* A staging bitmap for copy_mono. */
+ /* We want one big enough to handle the standard 16x16 halftone; */
+ /* this is also big enough for ordinary-size characters. */
+
+#define bmWidthBytes 4 /* must be even */
+#define bmWidthBits (bmWidthBytes * 8)
+#define bmHeight 32
+ HBITMAP FAR hbmmono;
+ HDC FAR hdcmono;
+ gx_bitmap_id bm_id;
+};
+private gx_device_procs win_ddb_procs = {
+ win_ddb_open,
+ NULL, /* get_initial_matrix */
+ win_sync_output,
+ win_output_page,
+ win_ddb_close,
+ win_ddb_map_rgb_color,
+ win_map_color_rgb,
+ win_ddb_fill_rectangle,
+ win_ddb_tile_rectangle,
+ win_ddb_copy_mono,
+ win_ddb_copy_color,
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ win_get_params,
+ win_put_params,
+ NULL, /* map_cmyk_color */
+ win_get_xfont_procs
+};
+gx_device_win_ddb far_data gs_mswin_device = {
+ std_device_std_body(gx_device_win_ddb, &win_ddb_procs, "mswin",
+ INITIAL_WIDTH, INITIAL_HEIGHT, /* win_open() fills these in later */
+ INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */
+ ),
+ { 0 }, /* std_procs */
+ 0, /* BitsPerPixel - not used */
+ 5000, /* UpdateInterval (in milliseconds) */
+ "\0", /* GSVIEW_STR */
+ 0, /* not a DLL device */
+ 2, /* nColors */
+ 0, /* mapped_color_flags */
+ win_ddb_copy_to_clipboard,
+ win_ddb_repaint,
+ win_ddb_alloc_bitmap,
+ win_ddb_free_bitmap
+};
+
+/* Open the win_ddb driver */
+private int
+win_ddb_open(gx_device *dev)
+{ int code = win_open(dev);
+ HDC hdc;
+ if ( code < 0 ) return code;
+
+ if (wdev->BitsPerPixel > 8)
+ return gs_error_limitcheck; /* don't support 24 bit/pixel */
+
+ /* Create the backing bitmap. */
+ code = win_ddb_alloc_bitmap((gx_device_win *)dev, dev);
+ if ( code < 0 ) return code;
+
+ /* Create the bitmap and DC for copy_mono. */
+ hdc = GetDC(wdev->hwndimg);
+ wdev->hbmmono = CreateBitmap(bmWidthBits, bmHeight, 1, 1, NULL);
+ wdev->hdcmono = CreateCompatibleDC(hdc);
+ if ( wdev->hbmmono == NULL || wdev->hdcmono == NULL )
+ { win_ddb_free_bitmap((gx_device_win *)dev);
+ ReleaseDC(wdev->hwndimg, hdc);
+ return win_nomemory();
+ }
+ SetMapMode(wdev->hdcmono, GetMapMode(hdc));
+ SelectObject(wdev->hdcmono, wdev->hbmmono);
+ wdev->bm_id = gx_no_bitmap_id;
+ ReleaseDC(wdev->hwndimg, hdc);
+
+ /* create palette and tools for bitmap */
+ if ((wdev->lpalette = win_makepalette((gx_device_win *)dev))
+ == (LPLOGPALETTE)NULL)
+ return win_nomemory();
+ wdev->hpalette = CreatePalette(wdev->lpalette);
+ (void) SelectPalette(wdev->hdcbit,wdev->hpalette,NULL);
+ RealizePalette(wdev->hdcbit);
+ win_maketools(wdev,wdev->hdcbit);
+
+ wdev->hdctext = wdev->hdcbit; /* draw text here */
+
+ return 0;
+}
+
+/* Close the win_ddb driver */
+private int
+win_ddb_close(gx_device *dev)
+{
+ /* Free resources */
+
+ win_destroytools(wdev);
+ DeleteDC(wdev->hdcmono);
+ win_ddb_free_bitmap((gx_device_win *)dev);
+ DeleteObject(wdev->hpalette);
+ DeleteObject(wdev->hbmmono);
+ gs_free((char *)(wdev->lpalette), 1, sizeof(LOGPALETTE) +
+ (1<<(wdev->color_info.depth)) * sizeof(PALETTEENTRY),
+ "win_ddb_close");
+
+ return win_close(dev);
+}
+
+/* Map a r-g-b color to the colors available under Windows */
+private gx_color_index
+win_ddb_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ int i = wdev->nColors;
+ gx_color_index color = win_map_rgb_color(dev, r, g, b);
+ LPLOGPALETTE lipal = wdev->limgpalette;
+ LPLOGPALETTE lpal = wdev->lpalette;
+ if ( color != i ) return color;
+
+ /* We just added a color to the window palette. */
+ /* Add it to the bitmap palette as well. */
+
+ DeleteObject(wdev->hpalette);
+ lpal->palPalEntry[i].peFlags = NULL;
+ lpal->palPalEntry[i].peRed = lipal->palPalEntry[i].peRed;
+ lpal->palPalEntry[i].peGreen = lipal->palPalEntry[i].peGreen;
+ lpal->palPalEntry[i].peBlue = lipal->palPalEntry[i].peBlue;
+ lpal->palNumEntries = i+1;
+ wdev->hpalette = CreatePalette(lpal);
+ (void) SelectPalette(wdev->hdcbit,wdev->hpalette,NULL);
+ RealizePalette(wdev->hdcbit);
+ win_addtool(wdev, i);
+
+ return color;
+}
+
+/* Macro for filling a rectangle with a color. */
+/* Note that it starts with a declaration. */
+#define fill_rect(x, y, w, h, color)\
+RECT rect;\
+rect.left = x, rect.top = y;\
+rect.right = x + w, rect.bottom = y + h;\
+FillRect(wdev->hdcbit, &rect, wdev->hbrushs[(int)color])
+
+
+/* Fill a rectangle. */
+private int
+win_ddb_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ fit_fill(dev, x, y, w, h);
+ /* Use PatBlt for filling. Special-case black. */
+ if ( color == 0 )
+ PatBlt(wdev->hdcbit, x, y, w, h, rop_write_0s);
+ else
+ { select_brush((int)color);
+ PatBlt(wdev->hdcbit, x, y, w, h, rop_write_pattern);
+ }
+ win_update((gx_device_win *)dev);
+
+ return 0;
+}
+
+/* Tile a rectangle. If neither color is transparent, */
+/* pre-clear the rectangle to color0 and just tile with color1. */
+/* This is faster because of how win_copy_mono is implemented. */
+/* Note that this also does the right thing for colored tiles. */
+private int
+win_ddb_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
+ int px, int py)
+{ fit_fill(dev, x, y, w, h);
+ if ( czero != gx_no_color_index && cone != gx_no_color_index )
+ { fill_rect(x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ if ( tile->raster == bmWidthBytes && tile->size.y <= bmHeight &&
+ (px | py) == 0 && cone != gx_no_color_index
+ )
+ { /* We can do this much more efficiently */
+ /* by using the internal algorithms of copy_mono */
+ /* and gx_default_tile_rectangle. */
+ int width = tile->size.x;
+ int height = tile->size.y;
+ int rwidth = tile->rep_width;
+ int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */
+ x & (rwidth - 1) :
+ x % rwidth);
+ int ry = y % tile->rep_height;
+ int icw = width - irx;
+ int ch = height - ry;
+ int ex = x + w, ey = y + h;
+ int fex = ex - width, fey = ey - height;
+ int cx, cy;
+
+ select_brush((int)cone);
+
+ if ( tile->id != wdev->bm_id || tile->id == gx_no_bitmap_id )
+ { wdev->bm_id = tile->id;
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * tile->size.y),
+ (BYTE *)tile->data);
+ }
+
+#define copy_tile(srcx, srcy, tx, ty, tw, th)\
+ BitBlt(wdev->hdcbit, tx, ty, tw, th, wdev->hdcmono, srcx, srcy, rop_write_at_1s)
+
+ if ( ch > h ) ch = h;
+ for ( cy = y; ; )
+ { if ( w <= icw )
+ copy_tile(irx, ry, x, cy, w, ch);
+ else
+ { copy_tile(irx, ry, x, cy, icw, ch);
+ cx = x + icw;
+ while ( cx <= fex )
+ { copy_tile(0, ry, cx, cy, width, ch);
+ cx += width;
+ }
+ if ( cx < ex )
+ { copy_tile(0, ry, cx, cy, ex - cx, ch);
+ }
+ }
+ if ( (cy += ch) >= ey ) break;
+ ch = (cy > fey ? ey - cy : height);
+ ry = 0;
+ }
+
+ win_update((gx_device_win *)dev);
+ return 0;
+ }
+ return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
+}
+
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+private int
+win_ddb_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ int endx;
+ const byte *ptr_line;
+ int width_bytes, height;
+ DWORD rop = rop_write_at_1s;
+ int color;
+ BYTE aBit[bmWidthBytes * bmHeight];
+ BYTE *aptr = aBit;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ if ( sourcex & ~7 )
+ { base += sourcex >> 3;
+ sourcex &= 7;
+ }
+
+ /* Break up large transfers into smaller ones. */
+ while ( (endx = sourcex + w) > bmWidthBits )
+ { int lastx = (endx - 1) & -bmWidthBits;
+ int subw = endx - lastx;
+ int code = win_ddb_copy_mono(dev, base, lastx,
+ raster, gx_no_bitmap_id,
+ x + lastx - sourcex, y,
+ subw, h, zero, one);
+ if ( code < 0 ) return code;
+ w -= subw;
+ }
+ while ( h > bmHeight )
+ { int code;
+ h -= bmHeight;
+ code = win_ddb_copy_mono(dev, base + h * raster, sourcex,
+ raster, gx_no_bitmap_id,
+ x, y + h, w, bmHeight, zero, one);
+ if ( code < 0 ) return code;
+ }
+
+ width_bytes = (sourcex + w + 7) >> 3;
+ ptr_line = base;
+
+ if ( zero == gx_no_color_index )
+ { if ( one == gx_no_color_index ) return 0;
+ color = (int)one;
+ if ( color == 0 )
+ rop = rop_write_0_at_1s;
+ else
+ select_brush(color);
+ }
+ else
+ { if ( one == gx_no_color_index )
+ { color = (int)zero;
+ rop = rop_write_at_0s;
+ }
+ else
+ { /* Pre-clear the rectangle to zero */
+ fill_rect(x, y, w, h, zero);
+ color = (int)one;
+ }
+ select_brush(color);
+ }
+
+ if ( id != wdev->bm_id || id == gx_no_bitmap_id )
+ { wdev->bm_id = id;
+ if ( raster == bmWidthBytes )
+ { /* We can do the whole thing in a single transfer! */
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * h),
+ (BYTE *)base);
+ }
+ else
+ { for ( height = h; height--;
+ ptr_line += raster, aptr += bmWidthBytes
+ )
+ { /* Pack the bits into the bitmap. */
+ switch ( width_bytes )
+ {
+ default: memcpy(aptr, ptr_line, width_bytes); break;
+ case 4: aptr[3] = ptr_line[3];
+ case 3: aptr[2] = ptr_line[2];
+ case 2: aptr[1] = ptr_line[1];
+ case 1: aptr[0] = ptr_line[0];
+ }
+ }
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * h),
+ &aBit[0]);
+ }
+ }
+
+ BitBlt(wdev->hdcbit, x, y, w, h, wdev->hdcmono, sourcex, 0, rop);
+ win_update((gx_device_win *)dev);
+ return 0;
+}
+
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
+private int
+win_ddb_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ if ( gx_device_has_color(dev) )
+ {
+ switch(dev->color_info.depth) {
+ case 8:
+ { int xi, yi;
+ int skip = raster - w;
+ const byte *sptr = base + sourcex;
+ if ( w <= 0 ) return 0;
+ if ( x < 0 || x + w > dev->width )
+ return_error(gs_error_rangecheck);
+ for ( yi = y; yi - y < h; yi++ )
+ {
+ for ( xi = x; xi - x < w; xi++ )
+ { int color = *sptr++;
+ SetPixel(wdev->hdcbit,xi,yi,PALETTEINDEX(color));
+ }
+ sptr += skip;
+ }
+ }
+ break;
+ case 4:
+ { /* color device, four bits per pixel */
+ const byte *line = base + (sourcex >> 1);
+ int dest_y = y, end_x = x + w;
+
+ if ( w <= 0 ) return 0;
+ while ( h-- ) /* for each line */
+ { const byte *source = line;
+ register int dest_x = x;
+ if ( sourcex & 1 ) /* odd nibble first */
+ { int color = *source++ & 0xf;
+ SetPixel(wdev->hdcbit,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ }
+ /* Now do full bytes */
+ while ( dest_x < end_x )
+ { int color = *source >> 4;
+ SetPixel(wdev->hdcbit,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ if ( dest_x < end_x )
+ { color = *source++ & 0xf;
+ SetPixel(wdev->hdcbit,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ }
+ }
+ dest_y++;
+ line += raster;
+ }
+ }
+ break;
+ default:
+ return(-1); /* panic */
+ }
+ }
+ else
+ /* monochrome device: one bit per pixel */
+ { /* bitmap is the same as win_copy_mono: one bit per pixel */
+ win_ddb_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
+ (gx_color_index)0,
+ (gx_color_index)(dev->color_info.depth==8 ? 63 : dev->color_info.max_gray));
+ }
+ win_update((gx_device_win *)dev);
+ return 0;
+}
+
+/* ------ Windows-specific device procedures ------ */
+
+
+/* Copy the bitmap to the clipboard. */
+private void
+win_ddb_copy_to_clipboard(gx_device_win *dev)
+{ /* make somewhere to put it and copy */
+ HDC hdcbit = wdev->hdcbit;
+ HBITMAP bitmap = CreateCompatibleBitmap(hdcbit, dev->width,
+ dev->height);
+ if (bitmap) {
+ /* there is enough memory and the bitmaps OK */
+ HDC mem = CreateCompatibleDC(hdcbit);
+ SelectObject(mem, bitmap);
+ BitBlt(mem, 0, 0, dev->width, dev->height,
+ hdcbit, 0, 0, SRCCOPY);
+ DeleteDC(mem);
+ /* copy it to the clipboard */
+ OpenClipboard(wdev->hwndimg);
+ EmptyClipboard();
+ SetClipboardData(CF_BITMAP, bitmap);
+ SetClipboardData(CF_PALETTE, CreatePalette(wdev->limgpalette));
+ CloseClipboard();
+ }
+}
+
+
+/* Repaint a section of the window. */
+private void
+win_ddb_repaint(gx_device_win *dev, HDC hdc, int dx, int dy, int wx, int wy,
+ int sx, int sy)
+{ BitBlt(hdc, dx, dy, wx, wy, wdev->hdcbit, sx, sy, SRCCOPY);
+}
+
+
+/* Allocate the backing bitmap. */
+private int
+win_ddb_alloc_bitmap(gx_device_win *dev, gx_device *param_dev)
+{
+ HDC hdc;
+ int i;
+
+ hdc = GetDC(wdev->hwndimg);
+ for ( i = 0; ; i++ )
+ { wdev->hbitmap = CreateCompatibleBitmap(hdc,
+ param_dev->width, param_dev->height);
+ if ( wdev->hbitmap != (HBITMAP)NULL )
+ break;
+ if ( i >= 4 )
+ { ReleaseDC(wdev->hwndimg, hdc);
+ return win_nomemory();
+ }
+ fprintf(stderr, "\nNot enough memory for bitmap. Halving resolution... ");
+ param_dev->x_pixels_per_inch /= 2;
+ param_dev->y_pixels_per_inch /= 2;
+ param_dev->width /= 2;
+ param_dev->height /= 2;
+ }
+
+ wdev->hdcbit = CreateCompatibleDC(hdc); /* create Device Context for drawing */
+ SelectObject(wdev->hdcbit, wdev->hbitmap);
+ ReleaseDC(wdev->hwndimg, hdc);
+ return 0;
+}
+
+
+/* Free the backing bitmap. */
+private void
+win_ddb_free_bitmap(gx_device_win *dev)
+{ DeleteDC(wdev->hdcbit); /* must do this first */
+ DeleteObject(wdev->hbitmap);
+}
+
+
+/* ------ Internal routines ------ */
+
+#undef wdev
+
+
+private void near
+win_addtool(gx_device_win_ddb *wdev, int i)
+{
+ wdev->hpens[i] = CreatePen(PS_SOLID, 1, PALETTEINDEX(i));
+ wdev->hbrushs[i] = CreateSolidBrush(PALETTEINDEX(i));
+}
+
+
+private void near
+win_maketools(gx_device_win_ddb *wdev, HDC hdc)
+{ int i;
+ wdev->hpensize = (1<<(wdev->color_info.depth)) * sizeof(HPEN);
+ wdev->hpens = (HPEN *)gs_malloc(1, wdev->hpensize,
+ "win_maketools(pens)");
+ wdev->hbrushsize = (1<<(wdev->color_info.depth)) * sizeof(HBRUSH);
+ wdev->hbrushs = (HBRUSH *)gs_malloc(1, wdev->hbrushsize,
+ "win_maketools(brushes)");
+ if (wdev->hpens && wdev->hbrushs) {
+ for (i=0; i<wdev->nColors; i++)
+ win_addtool(wdev, i);
+
+ wdev->hpen = wdev->hpens[0];
+ SelectObject(hdc,wdev->hpen);
+
+ wdev->hbrush = wdev->hbrushs[0];
+ SelectObject(hdc,wdev->hbrush);
+ }
+}
+
+
+private void near
+win_destroytools(gx_device_win_ddb *wdev)
+{ int i;
+ for (i=0; i<wdev->nColors; i++) {
+ DeleteObject(wdev->hpens[i]);
+ DeleteObject(wdev->hbrushs[i]);
+ }
+ gs_free((char *)wdev->hbrushs, 1, wdev->hbrushsize,
+ "win_destroytools(brushes)");
+ gs_free((char *)wdev->hpens, 1, wdev->hpensize,
+ "win_destroytools(pens)");
+}
diff --git a/gs/src/gdevwdib.c b/gs/src/gdevwdib.c
new file mode 100644
index 000000000..27a4e7454
--- /dev/null
+++ b/gs/src/gdevwdib.c
@@ -0,0 +1,674 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevwdib.c */
+/* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
+#include "gdevmswn.h"
+#include "gxdevmem.h"
+#include "gsdll.h"
+
+#ifdef __WIN32__
+# define USE_SEGMENTS 0
+#else
+# define USE_SEGMENTS 1
+#endif
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_win_dib_s gx_device_win_dib;
+#undef wdev
+#define wdev ((gx_device_win_dib *)dev)
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(win_dib_open);
+private dev_proc_get_initial_matrix(win_dib_get_initial_matrix);
+private dev_proc_close_device(win_dib_close);
+private dev_proc_fill_rectangle(win_dib_fill_rectangle);
+private dev_proc_copy_mono(win_dib_copy_mono);
+private dev_proc_copy_color(win_dib_copy_color);
+private dev_proc_get_bits(win_dib_get_bits);
+private dev_proc_put_params(win_dib_put_params);
+/* Windows-specific procedures */
+private win_proc_repaint(win_dib_repaint);
+private win_proc_alloc_bitmap(win_dib_alloc_bitmap);
+private win_proc_free_bitmap(win_dib_free_bitmap);
+
+/* The device descriptor */
+struct gx_device_win_dib_s {
+ gx_device_common;
+ gx_device_win_common;
+
+#if USE_SEGMENTS
+ /* The following help manage the division of the DIB */
+ /* into 64K segments. Each block of y_block scan lines */
+ /* starting at y_base mod 64K falls in a single segment. */
+ /* Since the raster is a power of 2, y_block is a power of 2. */
+
+ int y_block;
+ int y_base;
+ int y_mask; /* y_block - 1 */
+#endif /* USE_SEGMENTS */
+
+ HGLOBAL hmdata;
+#ifdef __WIN32__
+ HANDLE hmtx;
+#endif
+ int lock_count;
+ gx_device_memory mdev;
+};
+private gx_device_procs win_dib_procs = {
+ win_dib_open,
+ win_dib_get_initial_matrix,
+ win_sync_output,
+ win_output_page,
+ win_dib_close,
+ win_map_rgb_color,
+ win_map_color_rgb,
+ win_dib_fill_rectangle,
+ NULL, /* tile_rectangle */
+ win_dib_copy_mono,
+ win_dib_copy_color,
+ NULL, /* draw_line */
+ win_dib_get_bits /* NULL */, /* get_bits */
+ win_get_params,
+ win_dib_put_params,
+ NULL, /* map_cmyk_color */
+ win_get_xfont_procs,
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device,
+ win_get_alpha_bits
+};
+gx_device_win_dib far_data gs_mswindll_device = {
+ std_device_std_body(gx_device_win_dib, &win_dib_procs, "mswindll",
+ INITIAL_WIDTH, INITIAL_HEIGHT, /* win_open() fills these in later */
+ INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */
+ ),
+ { 0 }, /* std_procs */
+ 0, /* BitsPerPixel */
+ 2, /* nColors */
+ 1, /* Text Alpha bits */
+ 1, /* Graphics Alpha bits */
+ 0, /* mapped_color_flags */
+ win_dib_alloc_bitmap,
+ win_dib_free_bitmap
+};
+
+/* forward declarations */
+private HGLOBAL win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy);
+private int win_dib_lock_device(unsigned char *device, int flag);
+
+
+/* Open the win_dib driver */
+private int
+win_dib_open(gx_device *dev)
+{
+ int code = win_open(dev);
+ if ( code < 0 ) return code;
+
+#ifdef __WIN32__
+ if (!is_win32s)
+ wdev->hmtx = CreateMutex(NULL, FALSE, NULL); /* unnamed mutex, initially unowned */
+#endif
+ if ( gdev_mem_device_for_bits(dev->color_info.depth) == 0 )
+ { win_close(dev);
+ return gs_error_rangecheck;
+ }
+ code = win_dib_alloc_bitmap((gx_device_win *)dev, dev);
+ if ( code < 0 ) {
+ win_close(dev);
+ return code;
+ }
+ /* notify caller about new device */
+ (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 1);
+ (*pgsdll_callback)(GSDLL_SIZE, (unsigned char *)dev,
+ (dev->width & 0xffff) +
+ ((ulong)(dev->height & 0xffff) << 16));
+ return code;
+}
+
+/* Get the initial matrix. DIBs, unlike most displays, */
+/* put (0,0) in the lower left corner. */
+private void
+win_dib_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+{ pmat->xx = dev->x_pixels_per_inch / 72.0;
+ pmat->xy = 0.0;
+ pmat->yx = 0.0;
+ pmat->yy = dev->y_pixels_per_inch / 72.0;
+ pmat->tx = 0.0;
+ pmat->ty = 0.0;
+}
+
+/* Close the win_dib driver */
+private int
+win_dib_close(gx_device *dev)
+{int code;
+ /* wait until bitmap is not being used by caller */
+ win_dib_lock_device((unsigned char *)dev, 1);
+ (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 0);
+ win_dib_lock_device((unsigned char *)dev, 0);
+ win_dib_free_bitmap((gx_device_win *)dev);
+#ifdef __WIN32__
+ if (!is_win32s)
+ CloseHandle(wdev->hmtx);
+#endif
+ code = win_close(dev);
+ return code;
+}
+
+#define wmdev ((gx_device *)&wdev->mdev)
+#define wmproc(proc) (*dev_proc(&wdev->mdev, proc))
+
+#if USE_SEGMENTS
+
+/* The drawing routines must all be careful not to cross */
+/* a segment boundary. */
+
+#define single_block(y, h)\
+ !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
+
+#define BEGIN_BLOCKS\
+{ int by, bh, left = h;\
+ for ( by = y; left > 0; by += bh, left -= bh )\
+ { bh = wdev->y_block - (by & wdev->y_mask);\
+ if ( bh > left ) bh = left;
+#define END_BLOCKS\
+ }\
+}
+
+#endif /* (!)USE_SEGMENTS */
+
+/* Fill a rectangle. */
+private int
+win_dib_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+#if USE_SEGMENTS
+ if ( single_block(y, h) )
+ { wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
+ }
+ else
+ { /* Divide the transfer into blocks. */
+ BEGIN_BLOCKS
+ wmproc(fill_rectangle)(wmdev, x, by, w, bh, color);
+ END_BLOCKS
+ }
+#else
+ wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
+#endif
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+private int
+win_dib_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+#if USE_SEGMENTS
+ if ( single_block(y, h) )
+ { wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
+ x, y, w, h, zero, one);
+ }
+ else
+ { /* Divide the transfer into blocks. */
+ const byte *source = base;
+ BEGIN_BLOCKS
+ wmproc(copy_mono)(wmdev, source, sourcex, raster,
+ gx_no_bitmap_id, x, by, w, bh,
+ zero, one);
+ source += bh * raster;
+ END_BLOCKS
+ }
+#else
+ wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
+ x, y, w, h, zero, one);
+#endif
+ return 0;
+}
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
+private int
+win_dib_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+#if USE_SEGMENTS
+ if ( single_block(y, h) )
+ { wmproc(copy_color)(wmdev, base, sourcex, raster, id,
+ x, y, w, h);
+ }
+ else
+ { /* Divide the transfer into blocks. */
+ const byte *source = base;
+ BEGIN_BLOCKS
+ wmproc(copy_color)(wmdev, source, sourcex, raster,
+ gx_no_bitmap_id, x, by, w, bh);
+ source += by * raster;
+ END_BLOCKS
+ }
+#else
+ wmproc(copy_color)(wmdev, base, sourcex, raster, id,
+ x, y, w, h);
+#endif
+ return 0;
+}
+
+int
+win_dib_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{
+ return wmproc(get_bits)(wmdev, y, str, actual_data);
+}
+
+int
+win_dib_put_params(gx_device *dev, gs_param_list *plist)
+{
+int code;
+ win_dib_lock_device((unsigned char *)dev, 1);
+ code = win_put_params(dev, plist);
+ win_dib_lock_device((unsigned char *)dev, 0);
+ return code;
+}
+
+/* ------ DLL device procedures ------ */
+
+/* make a copy of the device bitmap and return shared memory handle to it */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+HGLOBAL GSDLLAPI
+gsdll_copy_dib(unsigned char *device)
+{
+gx_device_win_dib *dev = (gx_device_win_dib *)device;
+ if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
+ return (HGLOBAL)NULL;
+ return win_dib_make_dib((gx_device_win *)dev, 0, 0, dev->width, dev->height);
+}
+
+/* make a copy of the device palette and return a handle to it */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+HPALETTE GSDLLAPI
+gsdll_copy_palette(unsigned char *device)
+{
+gx_device_win_dib *dev = (gx_device_win_dib *)device;
+ if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
+ return (HPALETTE)NULL;
+ if (wdev->nColors > 0)
+ return CreatePalette(dev->limgpalette);
+ return (HPALETTE)NULL;
+}
+
+/* copy the rectangle src from the device bitmap */
+/* to the rectangle dest on the device given by hdc */
+/* hdc must be a device context for a device (NOT a bitmap) */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+void GSDLLAPI
+gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src)
+{
+gx_device_win_dib *dev = (gx_device_win_dib *)device;
+HPALETTE oldpalette;
+ if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
+ return;
+ if (dev->nColors > 0) {
+ oldpalette = SelectPalette(hdc,dev->himgpalette,FALSE);
+ RealizePalette(hdc);
+ }
+ win_dib_repaint((gx_device_win *)dev, hdc, dest->left, dest->top,
+ dest->right-dest->left, dest->bottom-dest->top,
+ src->left, src->top);
+ if (dev->nColors > 0) {
+ SelectPalette(hdc,oldpalette,FALSE);
+ }
+ return;
+}
+
+/* ------ Windows-specific device procedures ------ */
+
+
+/* Repaint a section of the window. */
+private void
+win_dib_repaint(gx_device_win *dev, HDC hdc, int dx, int dy, int wx, int wy,
+ int sx, int sy)
+{ struct bmi_s {
+ BITMAPINFOHEADER h;
+ ushort pal_index[256];
+ } bmi;
+ int i;
+ UINT which_colors;
+
+ bmi.h.biSize = sizeof(bmi.h);
+ bmi.h.biWidth = wdev->mdev.width;
+ bmi.h.biHeight = wy;
+ bmi.h.biPlanes = 1;
+ bmi.h.biBitCount = dev->color_info.depth;
+ bmi.h.biCompression = 0;
+ bmi.h.biSizeImage = 0; /* default */
+ bmi.h.biXPelsPerMeter = 0; /* default */
+ bmi.h.biYPelsPerMeter = 0; /* default */
+ if ( dev->BitsPerPixel <= 8 )
+ { bmi.h.biClrUsed = wdev->nColors;
+ bmi.h.biClrImportant = wdev->nColors;
+ for ( i = 0; i < wdev->nColors; i++ )
+ bmi.pal_index[i] = i;
+ which_colors = DIB_PAL_COLORS;
+ }
+ else
+ { bmi.h.biClrUsed = 0;
+ bmi.h.biClrImportant = 0;
+ which_colors = DIB_RGB_COLORS;
+ }
+ /*
+ * Windows apparently limits the size of a single transfer
+ * to 2 Mb, which can be exceeded on 24-bit displays.
+ * Deal with this here.
+ */
+#define max_transfer 2000000
+ if ( wdev->mdev.raster > 0 ) /* just in case! */
+ { long ny = max_transfer / wdev->mdev.raster;
+ for ( ; wy > ny; dy += ny, wy -= ny, sy += ny )
+ SetDIBitsToDevice(hdc, dx, dy, wx, ny,
+ sx, 0, 0, ny,
+ wdev->mdev.line_ptrs[wdev->height - (sy + ny)],
+ (BITMAPINFO FAR *)&bmi, which_colors);
+ }
+#undef max_transfer
+ SetDIBitsToDevice(hdc, dx, dy, wx, wy,
+ sx, 0, 0, wy,
+ wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
+ (BITMAPINFO FAR *)&bmi, which_colors);
+}
+
+/* This makes a DIB that contains all or part of the bitmap. */
+/* The bitmap pixel orgx must start on a byte boundary. */
+private HGLOBAL
+win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy)
+{
+#define xwdev ((gx_device_win_dib *)dev)
+ gx_color_value prgb[3];
+ HGLOBAL hglobal;
+ BYTE FAR *pDIB;
+ BITMAPINFOHEADER FAR *pbmih;
+ RGBQUAD FAR *pColors;
+ BYTE huge *pBits;
+ BYTE huge *pLine;
+ ulong bitmapsize;
+ int palcount;
+ int i;
+ UINT lwidth; /* line width in bytes rounded up to multiple of 4 bytes */
+#ifdef USE_SEGMENTS
+ int loffset; /* byte offset to start of line */
+ UINT lseg; /* bytes remaining in this segment */
+#endif
+
+ if (orgx + wx > wdev->width)
+ wx = wdev->width - orgx;
+ if (orgy + wy > wdev->height)
+ wy = wdev->height - orgy;
+
+ loffset = orgx * wdev->color_info.depth / 8;
+ lwidth = ((wx * wdev->color_info.depth + 31) & ~31) >> 3;
+ bitmapsize = (long)lwidth * wy;
+
+ if (wdev->color_info.depth == 24)
+ palcount = 0;
+ else
+ palcount = wdev->nColors;
+
+ hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER)
+ + sizeof(RGBQUAD) * palcount + bitmapsize);
+ if (hglobal == (HGLOBAL)NULL) {
+ MessageBeep(-1);
+ return(HGLOBAL)NULL;
+ }
+ pDIB = (BYTE FAR *)GlobalLock(hglobal);
+ if (pDIB == (BYTE FAR *)NULL) {
+ MessageBeep(-1);
+ return(HGLOBAL)NULL;
+ }
+ pbmih = (BITMAPINFOHEADER FAR *)(pDIB);
+ pColors = (RGBQUAD FAR *)(pDIB + sizeof(BITMAPINFOHEADER));
+ pBits = (BYTE huge *)(pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
+
+ pbmih->biSize = sizeof(BITMAPINFOHEADER);
+ pbmih->biWidth = wx;
+ pbmih->biHeight = wy;
+ pbmih->biPlanes = 1;
+ pbmih->biBitCount = wdev->color_info.depth;
+ pbmih->biCompression = 0;
+ pbmih->biSizeImage = 0; /* default */
+ pbmih->biXPelsPerMeter = (DWORD)(dev->x_pixels_per_inch / 25.4 * 1000);
+ pbmih->biYPelsPerMeter = (DWORD)(dev->y_pixels_per_inch / 25.4 * 1000);
+ pbmih->biClrUsed = palcount;
+ pbmih->biClrImportant = palcount;
+ for ( i = 0; i < palcount; i++ ) {
+ win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
+ pColors[i].rgbRed = win_color_value(prgb[0]);
+ pColors[i].rgbGreen = win_color_value(prgb[1]);
+ pColors[i].rgbBlue = win_color_value(prgb[2]);
+ pColors[i].rgbReserved = 0;
+ }
+
+ pLine = pBits;
+ for ( i = orgy; i < orgy + wy; i++ ) {
+#if USE_SEGMENTS
+ /* Window 3.1 has hmemcpy, but 3.0 doesn't */
+ lseg = (UINT)(-OFFSETOF(pLine)); /* remaining bytes in this segment */
+ if (lseg >= lwidth) {
+ _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth);
+ }
+ else { /* break up transfer to avoid crossing segment boundary */
+ _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg);
+ _fmemcpy(pLine+lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg);
+ }
+#else
+ memcpy(pLine, xwdev->mdev.line_ptrs[i], lwidth);
+#endif
+ pLine += lwidth;
+ }
+
+ GlobalUnlock(hglobal);
+ return hglobal;
+}
+
+
+/* Allocate the backing bitmap. */
+private int
+win_dib_alloc_bitmap(gx_device_win *dev, gx_device *param_dev)
+{
+ int width;
+ gx_device_memory mdev;
+ HGLOBAL hmdata;
+ byte huge *base;
+ byte huge *ptr_base;
+ uint ptr_size;
+ uint raster;
+#ifdef USE_SEGMENTS
+ ulong data_size;
+#endif
+
+#ifdef __WIN32__
+ if (is_win32s) {
+#endif
+ /* Round up the width so that the scan line size is a power of 2. */
+ if (dev->color_info.depth == 24) {
+ width = param_dev->width * 3 - 1;
+ while ( width & (width + 1) ) width |= width >> 1;
+ width = (width + 1) / 3;
+ }
+ else {
+ width = param_dev->width - 1;
+ while ( width & (width + 1) ) width |= width >> 1;
+ width++;
+ }
+#ifdef __WIN32__
+ }
+ else { /* don't have to worry about segments so use less memory */
+ width = param_dev->width;
+ }
+#endif
+
+ /* Finish initializing the DIB. */
+
+ gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0, (gx_device *)dev);
+ mdev.width = width;
+ mdev.height = param_dev->height;
+ raster = gdev_mem_raster(&mdev);
+ data_size = (ulong)raster * mdev.height;
+ ptr_size = sizeof(byte **) * mdev.height;
+ hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
+ if ( hmdata == 0 ) {
+ return win_nomemory();
+ }
+
+ /* Nothing can go wrong now.... */
+
+ wdev->hmdata = hmdata;
+ base = GlobalLock(hmdata);
+#if USE_SEGMENTS
+ /* Adjust base so scan lines, and the pointer table, */
+ /* don't cross a segment boundary. */
+ base += (-PTR_OFF(base) & (raster - 1));
+ ptr_base = base + data_size;
+ if ( PTR_OFF(ptr_base + ptr_size) < ptr_size )
+ base += (uint)-PTR_OFF(ptr_base);
+ wdev->y_block = 0x10000L / raster;
+ wdev->y_mask = wdev->y_block - 1;
+ if ( (wdev->y_base = PTR_OFF(base)) != 0 )
+ wdev->y_base = -(PTR_OFF(base) / raster);
+#endif
+ wdev->mdev = mdev;
+ wdev->mdev.base = (byte *)base;
+ wmproc(open_device)((gx_device *)&wdev->mdev);
+
+ if (wdev->is_open)
+ (*pgsdll_callback)(GSDLL_SIZE, (unsigned char *)dev,
+ (dev->width & 0xffff) +
+ ((ulong)(dev->height & 0xffff) << 16));
+
+ return 0;
+}
+
+
+/* Free the backing bitmap. */
+private void
+win_dib_free_bitmap(gx_device_win *dev)
+{ HGLOBAL hmdata = wdev->hmdata;
+ GlobalUnlock(hmdata);
+ GlobalFree(hmdata);
+}
+
+/* Lock the device (so it's size cannot be changed) if flag = TRUE */
+/* or unlock the device if flag = FALSE */
+/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
+private int
+win_dib_lock_device(unsigned char *device, int flag)
+{
+gx_device *dev = (gx_device *)device;
+#ifdef __WIN32__
+ if (!is_win32s) {
+ if (flag) {
+ if (WaitForSingleObject(wdev->hmtx, 60000) == WAIT_TIMEOUT)
+ return 2;
+ return 1;
+ }
+ ReleaseMutex(wdev->hmtx);
+ return 0;
+ }
+#endif
+ if (flag)
+ wdev->lock_count++;
+ else
+ wdev->lock_count--;
+ if (wdev->lock_count < 0)
+ wdev->lock_count = 0;
+ return wdev->lock_count;
+}
+
+int GSDLLAPI _export
+gsdll_lock_device(unsigned char *device, int flag)
+{
+ return win_dib_lock_device(device, flag);
+}
+
+
+/* Copy bitmap
+ * If pbmih nonzero, copy the BITMAPINFOHEADER.
+ * If prgbquad nonzero, copy the palette.
+ * number of entries copied is given by pbmih->biClrUsed
+ * If ppbyte nonzero, return pointer to row.
+ * pointer is only valid while device is locked
+ * GS can change the palette while the device is locked.
+ * Do not call this function while GS is busy.
+ * If all pbmih and prgbquad and ppbyte are all NULL,
+ * return value is byte count needed for BITMAPINFOHEADER
+ * and palette and one bitmap row.
+ * Otherwise return value is 0;
+ *
+ * This function exists to allow the bitmap to be copied to a file
+ * or structured storage, without the overhead of having two copies
+ * of the bitmap in memory at the same time.
+ */
+int GSDLLAPI _export
+gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE *ppbyte, unsigned int row)
+{
+ int palcount;
+ gx_device_win_dib *dev = (gx_device_win_dib *)device;
+ palcount = (dev->color_info.depth == 24) ? 0 : dev->nColors;
+
+ if (pbmih) {
+ pbmih->biSize = sizeof(BITMAPINFOHEADER);
+ pbmih->biWidth = dev->width;
+ pbmih->biHeight = dev->mdev.height;
+ pbmih->biPlanes = 1;
+ pbmih->biBitCount = dev->color_info.depth;
+ pbmih->biCompression = 0;
+ pbmih->biSizeImage = 0; /* default */
+ pbmih->biXPelsPerMeter = (DWORD)(dev->x_pixels_per_inch / 25.4 * 1000);
+ pbmih->biYPelsPerMeter = (DWORD)(dev->y_pixels_per_inch / 25.4 * 1000);
+ pbmih->biClrUsed = palcount;
+ pbmih->biClrImportant = palcount;
+ }
+
+ if (prgbquad) {
+ int i;
+ gx_color_value prgb[3];
+ for ( i = 0; i < palcount; i++ ) {
+ win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
+ prgbquad[i].rgbRed = win_color_value(prgb[0]);
+ prgbquad[i].rgbGreen = win_color_value(prgb[1]);
+ prgbquad[i].rgbBlue = win_color_value(prgb[2]);
+ prgbquad[i].rgbReserved = 0;
+ }
+ }
+
+ if (ppbyte) {
+ if (row < dev->mdev.height)
+ *ppbyte = dev->mdev.line_ptrs[row];
+ else
+ *ppbyte = NULL;
+ }
+
+ if ((pbmih == NULL) && (prgbquad == NULL) && (ppbyte == NULL))
+ return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)
+ + gdev_mem_raster(&(dev->mdev));
+ return 0;
+}
+
diff --git a/gs/src/gdevwpr2.c b/gs/src/gdevwpr2.c
new file mode 100644
index 000000000..bad6b0885
--- /dev/null
+++ b/gs/src/gdevwpr2.c
@@ -0,0 +1,804 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevwpr2.c */
+/*
+ * Microsoft Windows 3.n printer driver for Ghostscript.
+ * Original version by Russell Lang and
+ * L. Peter Deutsch, Aladdin Enterprises.
+ * Modified by rjl 1995-03-29 to use BMP printer code
+ */
+
+/* This driver uses the printer default size and resolution and
+ * ignores page size and resolution set using -gWIDTHxHEIGHT and
+ * -rXxY. You must still set the correct PageSize to get the
+ * correct clipping path.
+ * The code in win_pr2_getdc() does try to set the printer page
+ * size from the PostScript PageSize, but it isn't working
+ * reliably at the moment.
+ *
+ * This driver doesn't work with some Windows printer drivers.
+ * The reason is unknown. All printers to which I have access
+ * work.
+ *
+ * rjl 1997-11-20
+ */
+
+/* Supported printer parameters are
+ * -dBitsPerPixel=n
+ * Override what the Window printer driver returns.
+ * -dNoCancel
+ * Don't display cancel dialog box. Useful for unattended or
+ * console EXE operation.
+ */
+
+#include "gdevprn.h"
+#include "gdevpccm.h"
+
+#include "windows_.h"
+#include <shellapi.h>
+#include "gp_mswin.h"
+
+#include "gp.h"
+#include "commdlg.h"
+
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_win_pr2_s gx_device_win_pr2;
+#undef wdev
+#define wdev ((gx_device_win_pr2 *)dev)
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(win_pr2_open);
+private dev_proc_close_device(win_pr2_close);
+private dev_proc_print_page(win_pr2_print_page);
+private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
+private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
+private dev_proc_get_params(win_pr2_get_params);
+private dev_proc_put_params(win_pr2_put_params);
+
+private void win_pr2_set_bpp(gx_device *dev, int depth);
+
+private gx_device_procs win_pr2_procs =
+ prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
+ win_pr2_map_rgb_color, win_pr2_map_color_rgb,
+ win_pr2_get_params, win_pr2_put_params);
+
+
+/* The device descriptor */
+typedef struct gx_device_win_pr2_s gx_device_win_pr2;
+struct gx_device_win_pr2_s {
+ gx_device_common;
+ gx_prn_device_common;
+ HDC hdcprn;
+ bool nocancel;
+ DLGPROC lpfnAbortProc;
+ DLGPROC lpfnCancelProc;
+};
+
+gx_device_win_pr2 far_data gs_mswinpr2_device = {
+ prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
+ 0, 0, 0, 0,
+ 0, win_pr2_print_page), /* depth = 0 */
+ 0, /* hdcprn */
+ 0, /* nocancel */
+ NULL, /* lpfnAbortProc */
+ NULL /* lpfnCancelProc */
+};
+
+private int win_pr2_getdc(gx_device_win_pr2 *);
+
+/* Open the win_pr2 driver */
+private int
+win_pr2_open(gx_device *dev)
+{ int code;
+ int depth;
+ PRINTDLG pd;
+ POINT offset;
+ POINT size;
+ float m[4];
+ FILE *pfile;
+
+ if ((!wdev->nocancel) && (hDlgModeless)) {
+ /* device cannot opened twice since only one hDlgModeless */
+ fprintf(stderr, "Can't open mswinpr2 device twice\n");
+ return gs_error_limitcheck;
+ }
+
+ /* get a HDC for the printer */
+ if (!win_pr2_getdc(wdev)) {
+ /* couldn't get a printer from -sOutputFile= */
+ /* Prompt with dialog box */
+ memset(&pd, 0, sizeof(pd));
+ pd.lStructSize = sizeof(pd);
+ pd.hwndOwner = hwndtext;
+ pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
+ if (!PrintDlg(&pd)) {
+ /* device not opened - exit ghostscript */
+ return gs_error_Fatal; /* exit Ghostscript cleanly */
+ }
+ GlobalFree(pd.hDevMode);
+ GlobalFree(pd.hDevNames);
+ pd.hDevMode = pd.hDevNames = NULL;
+ wdev->hdcprn = pd.hDC;
+ }
+ if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
+ fprintf(stderr, "Windows printer does not have RC_DIBTODEV\n");
+ DeleteDC(wdev->hdcprn);
+ return gs_error_limitcheck;
+ }
+
+ /* initialise printer, install abort proc */
+#ifdef __WIN32__
+ wdev->lpfnAbortProc = (DLGPROC)AbortProc;
+#else
+#ifdef __DLL__
+ wdev->lpfnAbortProc = (DLGPROC)GetProcAddress(phInstance, "AbortProc");
+#else
+ wdev->lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)AbortProc,phInstance);
+#endif
+#endif
+ Escape(wdev->hdcprn,SETABORTPROC,0,(LPSTR)wdev->lpfnAbortProc,NULL);
+ if (Escape(wdev->hdcprn, STARTDOC, lstrlen(szAppName), szAppName, NULL) <= 0) {
+ fprintf(stderr, "Printer Escape STARTDOC failed\n");
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ return gs_error_limitcheck;
+ }
+
+ dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
+ dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
+ Escape(wdev->hdcprn, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&size);
+ gx_device_set_width_height(dev, (int)size.x, (int)size.y);
+ Escape(wdev->hdcprn, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offset);
+ /* m[] gives margins in inches */
+ m[0] /*left*/ = offset.x / dev->x_pixels_per_inch;
+ m[3] /*top*/ = offset.y / dev->y_pixels_per_inch;
+ m[2] /*right*/ =
+ (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES))
+ / dev->x_pixels_per_inch;
+ m[1] /*bottom*/ =
+ (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES))
+ / dev->y_pixels_per_inch;
+ gx_device_set_margins(dev, m, true);
+
+ depth = dev->color_info.depth;
+ if (depth == 0) {
+ /* Set parameters that were unknown before opening device */
+ /* Find out if the device supports color */
+ /* We recognize 1, 4 (but uses only 3), 8 and 24 bit color devices */
+ depth = GetDeviceCaps(wdev->hdcprn,PLANES) * GetDeviceCaps(wdev->hdcprn,BITSPIXEL);
+ }
+ win_pr2_set_bpp(dev, depth);
+
+ /* gdev_prn_open opens a temporary file which we don't want */
+ /* so we specify the name now so we can delete it later */
+ pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
+ wdev->fname, "wb");
+ fclose(pfile);
+ code = gdev_prn_open(dev);
+ /* delete unwanted temporary file */
+ unlink(wdev->fname);
+
+ if (!wdev->nocancel) {
+ /* inform user of progress with dialog box and allow cancel */
+#ifdef __WIN32__
+ wdev->lpfnCancelProc = (DLGPROC)CancelDlgProc;
+#else
+#ifdef __DLL__
+ wdev->lpfnCancelProc = (DLGPROC)GetProcAddress(phInstance, "CancelDlgProc");
+#else
+ wdev->lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
+#endif
+#endif
+ hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
+ hwndtext, wdev->lpfnCancelProc);
+ ShowWindow(hDlgModeless, SW_HIDE);
+ }
+
+ return code;
+};
+
+/* Close the win_pr2 driver */
+private int
+win_pr2_close(gx_device *dev)
+{ int code;
+ int aborted = FALSE;
+ /* Free resources */
+
+ if (!wdev->nocancel) {
+ if (!hDlgModeless)
+ aborted = TRUE;
+ else
+ DestroyWindow(hDlgModeless);
+ hDlgModeless = 0;
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnCancelProc);
+#endif
+ }
+
+ if (aborted)
+ Escape(wdev->hdcprn,ABORTDOC,0,NULL,NULL);
+ else
+ Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
+
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ code = gdev_prn_close(dev);
+ return code;
+}
+
+
+/* ------ Internal routines ------ */
+
+#undef wdev
+#define wdev ((gx_device_win_pr2 *)pdev)
+
+/************************************************/
+
+
+/* ------ Private definitions ------ */
+
+
+/* new win_pr2_print_page routine */
+
+/* Write BMP header to memory, then send bitmap to printer */
+/* one scan line at a time */
+private int
+win_pr2_print_page(gx_device_printer *pdev, FILE *file)
+{ int raster = gdev_prn_raster(pdev);
+ /* BMP scan lines are padded to 32 bits. */
+ ulong bmp_raster = raster + (-raster & 3);
+ ulong bmp_raster_multi;
+ int scan_lines, yslice, lines, i;
+ int width;
+ int depth = pdev->color_info.depth;
+ byte *row;
+ int y;
+ int code = 0; /* return code */
+ MSG msg;
+ char dlgtext[32];
+ HGLOBAL hrow;
+
+ struct bmi_s {
+ BITMAPINFOHEADER h;
+ RGBQUAD pal[256];
+ } bmi;
+
+ scan_lines = dev_print_scan_lines(pdev);
+ width = pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
+ dev_x_offset(pdev)) * pdev->x_pixels_per_inch);
+
+ yslice = 65535 / bmp_raster; /* max lines in 64k */
+ bmp_raster_multi = bmp_raster * yslice;
+ hrow = GlobalAlloc(0, bmp_raster_multi);
+ row = GlobalLock(hrow);
+ if ( row == 0 ) /* can't allocate row buffer */
+ return_error(gs_error_VMerror);
+
+ /* Write the info header. */
+
+ bmi.h.biSize = sizeof(bmi.h);
+ bmi.h.biWidth = pdev->width; /* wdev->mdev.width; */
+ bmi.h.biHeight = yslice;
+ bmi.h.biPlanes = 1;
+ bmi.h.biBitCount = pdev->color_info.depth;
+ bmi.h.biCompression = 0;
+ bmi.h.biSizeImage = 0; /* default */
+ bmi.h.biXPelsPerMeter = 0; /* default */
+ bmi.h.biYPelsPerMeter = 0; /* default */
+
+ /* Write the palette. */
+
+ if ( depth <= 8 )
+ { int i;
+ gx_color_value rgb[3];
+ LPRGBQUAD pq;
+ bmi.h.biClrUsed = 1 << depth;
+ bmi.h.biClrImportant = 1 << depth;
+ for ( i = 0; i != 1 << depth; i++ )
+ { (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
+ (gx_color_index)i, rgb);
+ pq = &bmi.pal[i];
+ pq->rgbRed = gx_color_value_to_byte(rgb[0]);
+ pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
+ pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
+ pq->rgbReserved = 0;
+ }
+ }
+ else {
+ bmi.h.biClrUsed = 0;
+ bmi.h.biClrImportant = 0;
+ }
+
+ if (!wdev->nocancel) {
+ sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount)+1);
+ SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PRINTING), dlgtext);
+ ShowWindow(hDlgModeless, SW_SHOW);
+ }
+
+ for ( y = 0; y < scan_lines; ) {
+ /* copy slice to row buffer */
+ if (y > scan_lines - yslice)
+ lines = scan_lines - y;
+ else
+ lines = yslice;
+ for (i=0; i<lines; i++)
+ gdev_prn_copy_scan_lines(pdev, y+i,
+ row + (bmp_raster*(lines-1-i)), raster);
+ SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
+ 0, 0, 0, lines,
+ row,
+ (BITMAPINFO FAR *)&bmi, DIB_RGB_COLORS);
+ y += lines;
+
+ if (!wdev->nocancel) {
+ /* inform user of progress */
+ sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
+ SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), dlgtext);
+ }
+
+ /* process message loop */
+ while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
+ if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ if ((!wdev->nocancel) && (hDlgModeless == 0)) {
+ /* user pressed cancel button */
+ break;
+ }
+ }
+
+ if ((!wdev->nocancel) && (hDlgModeless == 0))
+ code = gs_error_Fatal; /* exit Ghostscript cleanly */
+ else {
+ /* push out the page */
+ if (!wdev->nocancel)
+ SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE),
+ "Ejecting page...");
+ Escape(wdev->hdcprn,NEWFRAME,0,NULL,NULL);
+ if (!wdev->nocancel)
+ ShowWindow(hDlgModeless, SW_HIDE);
+ }
+
+bmp_done:
+ GlobalUnlock(hrow);
+ GlobalFree(hrow);
+
+ return code;
+}
+
+/* combined color mappers */
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that Windows expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+private gx_color_index
+win_pr2_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{
+ switch(dev->color_info.depth) {
+ case 1:
+ return gdev_prn_map_rgb_color(dev, r, g, b);
+ case 4:
+ /* use only 8 colors */
+ return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
+ (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
+ (b > (gx_max_color_value / 2 + 1) ? 1 : 0) ;
+ case 8:
+ return pc_8bit_map_rgb_color(dev, r, g, b);
+ case 24:
+ return gx_color_value_to_byte(r) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(b) << 16);
+ }
+ return 0; /* error */
+}
+
+/* Map a color index to a r-g-b color. */
+private int
+win_pr2_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ switch(dev->color_info.depth) {
+ case 1:
+ gdev_prn_map_color_rgb(dev, color, prgb);
+ break;
+ case 4:
+ /* use only 8 colors */
+ prgb[0] = (color & 4) ? gx_max_color_value : 0;
+ prgb[1] = (color & 2) ? gx_max_color_value : 0;
+ prgb[2] = (color & 1) ? gx_max_color_value : 0;
+ break;
+ case 8:
+ pc_8bit_map_color_rgb(dev, color, prgb);
+ break;
+ case 24:
+ prgb[2] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color & 0xff);
+ break;
+ }
+ return 0;
+}
+
+void
+win_pr2_set_bpp(gx_device *dev, int depth)
+{
+ if (depth > 8) {
+ static const gx_device_color_info win_pr2_24color = dci_std_color(24);
+ dev->color_info = win_pr2_24color;
+ }
+ else if ( depth >= 8 ) {
+ /* 8-bit (SuperVGA-style) color. */
+ /* (Uses a fixed palette of 3,3,2 bits.) */
+ static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
+ dev->color_info = win_pr2_8color;
+ }
+ else if ( depth >= 3) {
+ /* 3 plane printer */
+ /* suitable for impact dot matrix CMYK printers */
+ /* create 4-bit bitmap, but only use 8 colors */
+ static const gx_device_color_info win_pr2_4color = {3, 4, 1, 1, 2, 2};
+ dev->color_info = win_pr2_4color;
+ }
+ else { /* default is black_and_white */
+ static const gx_device_color_info win_pr2_1color = dci_std_color(1);
+ dev->color_info = win_pr2_1color;
+ }
+}
+
+/* Get device parameters */
+int
+win_pr2_get_params(gx_device *dev, gs_param_list *plist)
+{ int code = gdev_prn_get_params(dev, plist);
+ if (code >=0)
+ code = param_write_bool(plist, "NoCancel",
+ &(((gx_device_win_pr2 *)dev)->nocancel));
+ return code;
+}
+
+/* We implement this ourselves so that we can change BitsPerPixel */
+/* before the device is opened */
+int
+win_pr2_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0, code;
+ int old_bpp = dev->color_info.depth;
+ int bpp = old_bpp;
+ bool nocancel = ((gx_device_win_pr2 *)dev)->nocancel;
+
+ switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
+ {
+ case 0:
+ if ( dev->is_open )
+ ecode = gs_error_rangecheck;
+ else
+ { /* change dev->color_info is valid before device is opened */
+ win_pr2_set_bpp(dev, bpp);
+ break;
+ }
+ goto bppe;
+ default:
+ ecode = code;
+bppe: param_signal_error(plist, "BitsPerPixel", ecode);
+ case 1:
+ break;
+ }
+
+ switch ( code = param_read_bool(plist, "NoCancel", &nocancel) )
+ {
+ case 0:
+ if ( dev->is_open )
+ ecode = gs_error_rangecheck;
+ else
+ {
+ ((gx_device_win_pr2 *)dev)->nocancel = nocancel;
+ break;
+ }
+ goto nocancele;
+ default:
+ ecode = code;
+nocancele: param_signal_error(plist, "NoCancel", ecode);
+ case 1:
+ break;
+ }
+
+ if ( ecode >= 0 )
+ ecode = gdev_prn_put_params(dev, plist);
+ return ecode;
+}
+
+#undef wdev
+
+#ifndef __WIN32__
+#include <print.h>
+#endif
+
+
+/* Get Device Context for printer */
+private int
+win_pr2_getdc(gx_device_win_pr2 *wdev)
+{
+char *device;
+char *devices;
+char *p;
+char driverbuf[512];
+char *driver;
+char *output;
+char *devcap;
+int devcapsize;
+int size;
+
+int i, n;
+POINT *pp;
+int paperindex;
+int paperwidth, paperheight;
+int orientation;
+int papersize;
+char papername[64];
+char drvname[32];
+HINSTANCE hlib;
+LPFNDEVMODE pfnExtDeviceMode;
+LPFNDEVCAPS pfnDeviceCapabilities;
+LPDEVMODE podevmode, pidevmode;
+
+#ifdef __WIN32__
+HANDLE hprinter;
+#endif
+
+
+ /* first try to derive the printer name from -sOutputFile= */
+ /* is printer if name prefixed by \\spool\ */
+ if ( is_spool(wdev->fname) )
+ device = wdev->fname + 8; /* skip over \\spool\ */
+ else
+ return FALSE;
+
+ /* now try to match the printer name against the [Devices] section */
+ if ( (devices = gs_malloc(4096, 1, "win_pr2_getdc")) == (char *)NULL )
+ return FALSE;
+ GetProfileString("Devices", NULL, "", devices, 4096);
+ p = devices;
+ while (*p) {
+ if (strcmp(p, device) == 0)
+ break;
+ p += strlen(p) + 1;
+ }
+ if (*p == '\0')
+ p = NULL;
+ gs_free(devices, 4096, 1, "win_pr2_getdc");
+ if (p == NULL)
+ return FALSE; /* doesn't match an available printer */
+
+ /* the printer exists, get the remaining information from win.ini */
+ GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
+ driver = strtok(driverbuf, ",");
+ output = strtok(NULL, ",");
+#ifdef __WIN32__
+ if (is_win32s)
+#endif
+ {
+ strcpy(drvname, driver);
+ strcat(drvname, ".drv");
+ driver = drvname;
+ }
+
+
+#ifdef __WIN32__
+
+ if (!is_win32s) {
+ if (!OpenPrinter(device, &hprinter, NULL))
+ return FALSE;
+ size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
+ if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
+ ClosePrinter(hprinter);
+ return FALSE;
+ }
+ if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
+ gs_free(podevmode, size, 1, "win_pr2_getdc");
+ ClosePrinter(hprinter);
+ return FALSE;
+ }
+ DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
+ pfnDeviceCapabilities = (LPFNDEVCAPS)DeviceCapabilities;
+ } else
+#endif
+ { /* Win16 and Win32s */
+ /* now load the printer driver */
+ hlib = LoadLibrary(driver);
+ if (hlib < (HINSTANCE)HINSTANCE_ERROR)
+ return FALSE;
+
+ /* call ExtDeviceMode() to get default parameters */
+ pfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hlib, "ExtDeviceMode");
+ if (pfnExtDeviceMode == (LPFNDEVMODE)NULL) {
+ FreeLibrary(hlib);
+ return FALSE;
+ }
+ pfnDeviceCapabilities = (LPFNDEVCAPS)GetProcAddress(hlib, "DeviceCapabilities");
+ if (pfnDeviceCapabilities == (LPFNDEVCAPS)NULL) {
+ FreeLibrary(hlib);
+ return FALSE;
+ }
+ size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
+ if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
+ FreeLibrary(hlib);
+ return FALSE;
+ }
+ if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
+ gs_free(podevmode, size, 1, "win_pr2_getdc");
+ FreeLibrary(hlib);
+ return FALSE;
+ }
+ pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
+ NULL, NULL, DM_OUT_BUFFER);
+ }
+
+ /* now find out what paper sizes are available */
+ devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
+ devcapsize *= sizeof(POINT);
+ if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
+ return FALSE;
+ n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
+ paperwidth = wdev->MediaSize[0] * 254 / 72;
+ paperheight = wdev->MediaSize[1] * 254 / 72;
+ papername[0] = '\0';
+ papersize = 0;
+ paperindex = -1;
+ orientation = DMORIENT_PORTRAIT;
+ pp = (POINT *)devcap;
+ for (i=0; i<n; i++, pp++) {
+ if ( (pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
+ (pp->y < paperheight + 20) && (pp->y > paperheight - 20) ) {
+ paperindex = i;
+ paperwidth = pp->x;
+ paperheight = pp->y;
+ break;
+ }
+ }
+ if (paperindex < 0) {
+ /* try again in landscape */
+ pp = (POINT *)devcap;
+ for (i=0; i<n; i++, pp++) {
+ if ( (pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
+ (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20) ) {
+ paperindex = i;
+ paperwidth = pp->x;
+ paperheight = pp->y;
+ orientation = DMORIENT_LANDSCAPE;
+ break;
+ }
+ }
+ }
+ gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
+
+ /* get the dmPaperSize */
+ devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
+ devcapsize *= sizeof(WORD);
+ if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
+ return FALSE;
+ n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
+ if ( (paperindex >= 0) && (paperindex < n) )
+ papersize = ((WORD *)devcap)[paperindex];
+ gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
+
+ /* get the paper name */
+ devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
+ devcapsize *= 64;
+ if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
+ return FALSE;
+ n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
+ if ( (paperindex >= 0) && (paperindex < n) )
+ strcpy(papername, devcap + paperindex*64);
+ gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
+
+ memcpy(pidevmode, podevmode, size);
+
+ pidevmode->dmFields = 0;
+
+ pidevmode->dmFields |= DM_DEFAULTSOURCE;
+ pidevmode->dmDefaultSource = 0;
+
+ pidevmode->dmFields |= DM_ORIENTATION;
+ pidevmode->dmOrientation = orientation;
+
+ if (papersize)
+ pidevmode->dmFields |= DM_PAPERSIZE;
+ else
+ pidevmode->dmFields &= (~DM_PAPERSIZE);
+ pidevmode->dmPaperSize = papersize;
+
+ pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
+ pidevmode->dmPaperLength = paperheight;
+ pidevmode->dmPaperWidth = paperwidth;
+
+
+#ifdef WIN32
+ if (!is_win32s) {
+ /* change the page size by changing the form */
+ /* WinNT only */
+ /* at present, changing the page size isn't working under Win NT */
+ /* Win95 returns FALSE to GetForm */
+ LPBYTE lpbForm;
+ FORM_INFO_1 *fi1;
+ DWORD dwBuf;
+ DWORD dwNeeded;
+ dwNeeded = 0;
+ dwBuf = 1024;
+ if ( (lpbForm = gs_malloc(dwBuf, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
+ {
+ gs_free(podevmode, size, 1, "win_pr2_getdc");
+ gs_free(pidevmode, size, 1, "win_pr2_getdc");
+ ClosePrinter(hprinter);
+ return FALSE;
+ }
+ if (GetForm(hprinter, papername, 1, lpbForm, dwBuf, &dwNeeded)) {
+ fi1 = (FORM_INFO_1 *)lpbForm;
+ pidevmode->dmFields |= DM_FORMNAME;
+ SetForm(hprinter, papername, 1, (LPBYTE)fi1);
+ }
+ gs_free(lpbForm, dwBuf, 1, "win_pr2_getdc");
+
+ strcpy(pidevmode->dmFormName, papername);
+ pidevmode->dmFields |= DM_FORMNAME;
+
+/*
+ pidevmode->dmFields &= DM_FORMNAME;
+ pidevmode->dmDefaultSource = 0;
+*/
+
+ /* merge the entries */
+ DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
+
+ ClosePrinter(hprinter);
+ /* now get a DC */
+ wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
+ }
+ else
+#endif
+ { /* Win16 and Win32s */
+ pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
+ pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
+ /* release the printer driver */
+ FreeLibrary(hlib);
+ /* now get a DC */
+ if (is_win32s)
+ strtok(driver, "."); /* remove .drv */
+ wdev->hdcprn = CreateDC(driver, device, output, podevmode);
+ }
+
+ gs_free(pidevmode, size, 1, "win_pr2_getdc");
+ gs_free(podevmode, size, 1, "win_pr2_getdc");
+
+ if (wdev->hdcprn != (HDC)NULL)
+ return TRUE; /* success */
+
+ /* fall back to prompting user */
+ return FALSE;
+}
diff --git a/gs/src/gdevwprn.c b/gs/src/gdevwprn.c
new file mode 100644
index 000000000..0e6b8cdca
--- /dev/null
+++ b/gs/src/gdevwprn.c
@@ -0,0 +1,665 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevwprn.c */
+/*
+ * Microsoft Windows 3.n printer driver for Ghostscript.
+ * Original version by Russell Lang and
+ * L. Peter Deutsch, Aladdin Enterprises.
+ */
+#include "gdevmswn.h"
+#include "gp.h"
+#include "commdlg.h"
+
+/*
+ ****** NOTE: this module and gdevwddb should be refactored.
+ * The drawing routines are almost identical.
+ * The differences are that the mswinprn doesn't use an extra
+ * palette (gdevwddb.c could probably be made to work with
+ * one palette also), mswinprn doesn't call win_update() because
+ * hwndimg doesn't exist, and the HDC is hdcmf not hdcbit.
+ ******/
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_win_prn_s gx_device_win_prn;
+#undef wdev
+#define wdev ((gx_device_win_prn *)dev)
+
+/* Forward references */
+private void near win_prn_addtool(P2(gx_device_win_prn *, int));
+private void near win_prn_maketools(P2(gx_device_win_prn *, HDC));
+private void near win_prn_destroytools(P1(gx_device_win_prn *));
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+private dev_proc_open_device(win_prn_open);
+private dev_proc_close_device(win_prn_close);
+private dev_proc_sync_output(win_prn_sync_output);
+private dev_proc_output_page(win_prn_output_page);
+private dev_proc_map_rgb_color(win_prn_map_rgb_color);
+private dev_proc_fill_rectangle(win_prn_fill_rectangle);
+private dev_proc_tile_rectangle(win_prn_tile_rectangle);
+private dev_proc_copy_mono(win_prn_copy_mono);
+private dev_proc_copy_color(win_prn_copy_color);
+private dev_proc_draw_line(win_prn_draw_line);
+
+/* The device descriptor */
+struct gx_device_win_prn_s {
+ gx_device_common;
+ gx_device_win_common;
+
+ /* Handles */
+
+ HPEN hpen, *hpens;
+ uint hpensize;
+ HBRUSH hbrush, *hbrushs;
+ uint hbrushsize;
+#define select_brush(color)\
+ if (wdev->hbrush != wdev->hbrushs[color])\
+ { wdev->hbrush = wdev->hbrushs[color];\
+ SelectObject(wdev->hdcmf,wdev->hbrush);\
+ }
+ /* A staging bitmap for copy_mono. */
+ /* We want one big enough to handle the standard 16x16 halftone; */
+ /* this is also big enough for ordinary-size characters. */
+
+#define bmWidthBytes 4 /* must be even */
+#define bmWidthBits (bmWidthBytes * 8)
+#define bmHeight 32
+ HBITMAP FAR hbmmono;
+ HDC FAR hdcmono;
+ gx_bitmap_id bm_id;
+
+ HDC hdcprn;
+ HDC hdcmf;
+ char mfname[128];
+ DLGPROC lpfnAbortProc;
+};
+private gx_device_procs win_prn_procs = {
+ win_prn_open,
+ NULL, /* get_initial_matrix */
+ win_prn_sync_output,
+ win_prn_output_page,
+ win_prn_close,
+ win_prn_map_rgb_color,
+ win_map_color_rgb,
+ win_prn_fill_rectangle,
+ win_prn_tile_rectangle,
+ win_prn_copy_mono,
+ win_prn_copy_color,
+ win_prn_draw_line,
+ NULL, /* get_bits */
+ NULL, /* get_params */
+ NULL, /* put_params */
+ NULL, /* map_cmyk_color */
+ win_get_xfont_procs
+};
+gx_device_win_prn far_data gs_mswinprn_device = {
+ std_device_std_body(gx_device_win_prn, &win_prn_procs, "mswinprn",
+ INITIAL_WIDTH, INITIAL_HEIGHT, /* win_open() fills these in later */
+ INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */
+ ),
+ { 0 }, /* std_procs */
+ 0, /* BitsPerPixel */
+ 2, /* nColors */
+};
+
+/* Open the win_prn driver */
+private int
+win_prn_open(gx_device *dev)
+{ int depth;
+ PRINTDLG pd;
+ FILE *f;
+ POINT offset;
+ POINT size;
+ float m[4];
+
+ memset(&pd, 0, sizeof(PRINTDLG));
+ pd.lStructSize = sizeof(PRINTDLG);
+ pd.hwndOwner = hwndtext;
+ pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
+ if (!PrintDlg(&pd)) {
+ /* device not opened - exit ghostscript */
+ return gs_error_limitcheck;
+ }
+ GlobalFree(pd.hDevMode);
+ GlobalFree(pd.hDevNames);
+ pd.hDevMode = pd.hDevNames = NULL;
+ wdev->hdcprn = pd.hDC;
+ if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_BITBLT)) {
+ DeleteDC(wdev->hdcprn);
+ return gs_error_limitcheck;
+ }
+
+#ifdef __WIN32__
+ wdev->lpfnAbortProc = (DLGPROC)AbortProc;
+#else
+#ifdef __DLL__
+ wdev->lpfnAbortProc = (DLGPROC)GetProcAddress(phInstance, "AbortProc");
+#else
+ wdev->lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)AbortProc,phInstance);
+#endif
+#endif
+ Escape(wdev->hdcprn,SETABORTPROC,0,(LPSTR)wdev->lpfnAbortProc,NULL);
+ if (Escape(wdev->hdcprn, STARTDOC, strlen(szAppName),szAppName, NULL) <= 0) {
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ return gs_error_limitcheck;
+ }
+
+ f = gp_open_scratch_file(gp_scratch_file_name_prefix,
+ wdev->mfname, "wb");
+ if (f == (FILE *)NULL) {
+ Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ return gs_error_limitcheck;
+ }
+ unlink(wdev->mfname);
+ wdev->hdcmf = CreateMetaFile(wdev->mfname);
+
+ dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
+ dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
+ Escape(wdev->hdcprn, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&size);
+ dev->width = size.x;
+ dev->height = size.y;
+ Escape(wdev->hdcprn, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offset);
+ m[0] /*left*/ = offset.x / dev->x_pixels_per_inch;
+ m[3] /*top*/ = offset.y / dev->y_pixels_per_inch;
+ m[2] /*right*/ =
+ (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES))
+ / dev->x_pixels_per_inch;
+ m[1] /*bottom*/ =
+ (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES))
+ / dev->y_pixels_per_inch
+ + 0.15; /* hack to add a bit more margin for deskjet printer */
+ gx_device_set_margins(dev, m, true);
+
+ /* Set parameters that were unknown before opening device */
+ /* Find out if the device supports color */
+ /* We recognize 2, 16 or 256 color devices */
+ depth = GetDeviceCaps(wdev->hdcprn,PLANES) * GetDeviceCaps(wdev->hdcprn,BITSPIXEL);
+ if ( depth >= 8 ) { /* use 64 static colors and 166 dynamic colors from 8 planes */
+ static const gx_device_color_info win_256color = dci_color(8,31,4);
+ dev->color_info = win_256color;
+ wdev->nColors = 64;
+ }
+ else if ( depth >= 4 ) {
+ static const gx_device_color_info win_16ega_color = dci_color(4, 2, 3);
+ dev->color_info = win_16ega_color;
+ wdev->nColors = 16;
+ }
+ else { /* default is black_and_white */
+ wdev->nColors = 2;
+ }
+
+ /* create palette for display */
+ if ((wdev->limgpalette = win_makepalette((gx_device_win *)dev))
+ == (LPLOGPALETTE)NULL) {
+ HMETAFILE hmf = CloseMetaFile(wdev->hdcmf);
+ DeleteMetaFile(hmf);
+ unlink(wdev->mfname);
+ Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ return win_nomemory();
+ }
+ wdev->himgpalette = CreatePalette(wdev->limgpalette);
+
+ /* Create the bitmap and DC for copy_mono. */
+ wdev->hbmmono = CreateBitmap(bmWidthBits, bmHeight, 1, 1, NULL);
+ wdev->hdcmono = CreateCompatibleDC(wdev->hdcprn);
+ if ( wdev->hbmmono == NULL || wdev->hdcmono == NULL ) {
+ HMETAFILE hmf = CloseMetaFile(wdev->hdcmf);
+ DeleteMetaFile(hmf);
+ unlink(wdev->mfname);
+ Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ gs_free((char *)(wdev->limgpalette), 1, sizeof(LOGPALETTE) +
+ (1<<(wdev->color_info.depth)) * sizeof(PALETTEENTRY),
+ "win_prn_open");
+ return win_nomemory();
+ }
+ SetMapMode(wdev->hdcmono, GetMapMode(wdev->hdcprn));
+ SelectObject(wdev->hdcmono, wdev->hbmmono);
+ (void) SelectPalette(wdev->hdcmf,wdev->himgpalette,FALSE);
+ RealizePalette(wdev->hdcmf);
+ win_prn_maketools(wdev,wdev->hdcmf);
+ wdev->bm_id = gx_no_bitmap_id;
+
+ return 0;
+}
+
+
+/* Close the win_prn driver */
+private int
+win_prn_close(gx_device *dev)
+{
+HMETAFILE hmf;
+ /* Free resources */
+ Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
+#endif
+ DeleteDC(wdev->hdcprn);
+ hmf = CloseMetaFile(wdev->hdcmf);
+ DeleteMetaFile(hmf);
+ unlink(wdev->mfname);
+
+ win_prn_destroytools(wdev);
+ DeleteDC(wdev->hdcmono);
+ DeleteObject(wdev->hbmmono);
+ DeleteObject(wdev->himgpalette);
+ gs_free((char *)(wdev->limgpalette), 1, sizeof(LOGPALETTE) +
+ (1<<(wdev->color_info.depth)) * sizeof(PALETTEENTRY),
+ "win_prn_close");
+ return(0);
+}
+
+/* Do nothing */
+int
+win_prn_sync_output(gx_device *dev)
+{
+ return 0;
+}
+
+/* Write page to printer */
+int
+win_prn_output_page(gx_device *dev, int copies, int flush)
+{
+RECT rect;
+HMETAFILE hmf;
+ hmf = CloseMetaFile(wdev->hdcmf);
+
+ Escape(wdev->hdcprn, NEXTBAND, 0, NULL, (LPRECT)&rect);
+ while (!IsRectEmpty(&rect)) {
+ PlayMetaFile(wdev->hdcprn, hmf);
+ if (Escape(wdev->hdcprn, NEXTBAND, 0, NULL, (LPRECT)&rect) <= 0)
+ break;
+ }
+ DeleteMetaFile(hmf);
+ unlink(wdev->mfname);
+ wdev->hdcmf = CreateMetaFile(wdev->mfname);
+ (void) SelectPalette(wdev->hdcmf,wdev->himgpalette,FALSE);
+ RealizePalette(wdev->hdcmf);
+ SelectObject(wdev->hdcmf,wdev->hpen);
+ SelectObject(wdev->hdcmf,wdev->hbrush);
+
+ return 0;
+}
+
+
+/* Map a r-g-b color to the colors available under Windows */
+private gx_color_index
+win_prn_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
+ gx_color_value b)
+{ int i = wdev->nColors;
+ gx_color_index color = win_map_rgb_color(dev, r, g, b);
+ if ( color != i ) return color;
+ (void) SelectPalette(wdev->hdcmf,wdev->himgpalette,FALSE);
+ RealizePalette(wdev->hdcmf);
+ win_prn_addtool(wdev, i);
+
+ return color;
+}
+
+
+/* Macro for filling a rectangle with a color. */
+/* Note that it starts with a declaration. */
+#define fill_rect(x, y, w, h, color)\
+RECT rect;\
+rect.left = x, rect.top = y;\
+rect.right = x + w, rect.bottom = y + h;\
+FillRect(wdev->hdcmf, &rect, wdev->hbrushs[(int)color])
+
+
+/* Fill a rectangle. */
+private int
+win_prn_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ fit_fill(dev, x, y, w, h);
+ /* Use PatBlt for filling. Special-case black. */
+ if ( color == 0 )
+ PatBlt(wdev->hdcmf, x, y, w, h, rop_write_0s);
+ else
+ { select_brush((int)color);
+ PatBlt(wdev->hdcmf, x, y, w, h, rop_write_pattern);
+ }
+
+ return 0;
+}
+
+/* Tile a rectangle. If neither color is transparent, */
+/* pre-clear the rectangle to color0 and just tile with color1. */
+/* This is faster because of how win_copy_mono is implemented. */
+/* Note that this also does the right thing for colored tiles. */
+private int
+win_prn_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
+ int px, int py)
+{ fit_fill(dev, x, y, w, h);
+ if ( czero != gx_no_color_index && cone != gx_no_color_index )
+ { fill_rect(x, y, w, h, czero);
+ czero = gx_no_color_index;
+ }
+ if ( tile->raster == bmWidthBytes && tile->size.y <= bmHeight &&
+ (px | py) == 0 && cone != gx_no_color_index
+ )
+ { /* We can do this much more efficiently */
+ /* by using the internal algorithms of copy_mono */
+ /* and gx_default_tile_rectangle. */
+ int width = tile->size.x;
+ int height = tile->size.y;
+ int rwidth = tile->rep_width;
+ int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */
+ x & (rwidth - 1) :
+ x % rwidth);
+ int ry = y % tile->rep_height;
+ int icw = width - irx;
+ int ch = height - ry;
+ int ex = x + w, ey = y + h;
+ int fex = ex - width, fey = ey - height;
+ int cx, cy;
+
+ select_brush((int)cone);
+
+ if ( tile->id != wdev->bm_id || tile->id == gx_no_bitmap_id )
+ { wdev->bm_id = tile->id;
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * tile->size.y),
+ (BYTE *)tile->data);
+ }
+
+#define copy_tile(srcx, srcy, tx, ty, tw, th)\
+ BitBlt(wdev->hdcmf, tx, ty, tw, th, wdev->hdcmono, srcx, srcy, rop_write_at_1s)
+
+ if ( ch > h ) ch = h;
+ for ( cy = y; ; )
+ { if ( w <= icw )
+ copy_tile(irx, ry, x, cy, w, ch);
+ else
+ { copy_tile(irx, ry, x, cy, icw, ch);
+ cx = x + icw;
+ while ( cx <= fex )
+ { copy_tile(0, ry, cx, cy, width, ch);
+ cx += width;
+ }
+ if ( cx < ex )
+ { copy_tile(0, ry, cx, cy, ex - cx, ch);
+ }
+ }
+ if ( (cy += ch) >= ey ) break;
+ ch = (cy > fey ? ey - cy : height);
+ ry = 0;
+ }
+
+ return 0;
+ }
+ return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
+}
+
+
+/* Draw a line */
+private int
+win_prn_draw_line(gx_device *dev, int x0, int y0, int x1, int y1,
+ gx_color_index color)
+{
+ if (wdev->hpen != wdev->hpens[(int)color]) {
+ wdev->hpen = wdev->hpens[(int)color];
+ SelectObject(wdev->hdcmf,wdev->hpen);
+ }
+#ifdef __WIN32__
+ MoveToEx(wdev->hdcmf, x0, y0, NULL);
+#else
+ MoveTo(wdev->hdcmf, x0, y0);
+#endif
+ LineTo(wdev->hdcmf, x1, y1);
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+private int
+win_prn_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ int endx;
+ const byte *ptr_line;
+ int width_bytes, height;
+ DWORD rop = rop_write_at_1s;
+ int color;
+ BYTE aBit[bmWidthBytes * bmHeight];
+ BYTE *aptr = aBit;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ if ( sourcex & ~7 )
+ { base += sourcex >> 3;
+ sourcex &= 7;
+ }
+
+ /* Break up large transfers into smaller ones. */
+ while ( (endx = sourcex + w) > bmWidthBits )
+ { int lastx = (endx - 1) & -bmWidthBits;
+ int subw = endx - lastx;
+ int code = win_prn_copy_mono(dev, base, lastx,
+ raster, gx_no_bitmap_id,
+ x + lastx - sourcex, y,
+ subw, h, zero, one);
+ if ( code < 0 ) return code;
+ w -= subw;
+ }
+ while ( h > bmHeight )
+ { int code;
+ h -= bmHeight;
+ code = win_prn_copy_mono(dev, base + h * raster, sourcex,
+ raster, gx_no_bitmap_id,
+ x, y + h, w, bmHeight, zero, one);
+ if ( code < 0 ) return code;
+ }
+
+ width_bytes = (sourcex + w + 7) >> 3;
+ ptr_line = base;
+
+ if ( zero == gx_no_color_index )
+ { if ( one == gx_no_color_index ) return 0;
+ color = (int)one;
+ if ( color == 0 )
+ rop = rop_write_0_at_1s;
+ else
+ select_brush(color);
+ }
+ else
+ { if ( one == gx_no_color_index )
+ { color = (int)zero;
+ rop = rop_write_at_0s;
+ }
+ else
+ { /* Pre-clear the rectangle to zero */
+ fill_rect(x, y, w, h, zero);
+ color = (int)one;
+ }
+ select_brush(color);
+ }
+
+ if ( id != wdev->bm_id || id == gx_no_bitmap_id )
+ { wdev->bm_id = id;
+ if ( raster == bmWidthBytes )
+ { /* We can do the whole thing in a single transfer! */
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * h),
+ (BYTE *)base);
+ }
+ else
+ { for ( height = h; height--;
+ ptr_line += raster, aptr += bmWidthBytes
+ )
+ { /* Pack the bits into the bitmap. */
+ switch ( width_bytes )
+ {
+ default: memcpy(aptr, ptr_line, width_bytes); break;
+ case 4: aptr[3] = ptr_line[3];
+ case 3: aptr[2] = ptr_line[2];
+ case 2: aptr[1] = ptr_line[1];
+ case 1: aptr[0] = ptr_line[0];
+ }
+ }
+ SetBitmapBits(wdev->hbmmono,
+ (DWORD)(bmWidthBytes * h),
+ &aBit[0]);
+ }
+ }
+
+ BitBlt(wdev->hdcmf, x, y, w, h, wdev->hdcmono, sourcex, 0, rop);
+ return 0;
+}
+
+
+/* Copy a color pixel map. This is just like a bitmap, except that */
+/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
+private int
+win_prn_copy_color(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ if ( gx_device_has_color(dev) )
+ {
+ switch(dev->color_info.depth) {
+ case 8:
+ { int xi, yi;
+ int skip = raster - w;
+ const byte *sptr = base + sourcex;
+ if ( w <= 0 ) return 0;
+ if ( x < 0 || x + w > dev->width )
+ return_error(gs_error_rangecheck);
+ for ( yi = y; yi - y < h; yi++ )
+ {
+ for ( xi = x; xi - x < w; xi++ )
+ { int color = *sptr++;
+ SetPixel(wdev->hdcmf,xi,yi,PALETTEINDEX(color));
+ }
+ sptr += skip;
+ }
+ }
+ break;
+ case 4:
+ { /* color device, four bits per pixel */
+ const byte *line = base + (sourcex >> 1);
+ int dest_y = y, end_x = x + w;
+
+ if ( w <= 0 ) return 0;
+ while ( h-- ) /* for each line */
+ { const byte *source = line;
+ register int dest_x = x;
+ if ( sourcex & 1 ) /* odd nibble first */
+ { int color = *source++ & 0xf;
+ SetPixel(wdev->hdcmf,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ }
+ /* Now do full bytes */
+ while ( dest_x < end_x )
+ { int color = *source >> 4;
+ SetPixel(wdev->hdcmf,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ if ( dest_x < end_x )
+ { color = *source++ & 0xf;
+ SetPixel(wdev->hdcmf,dest_x,dest_y,PALETTEINDEX(color));
+ dest_x++;
+ }
+ }
+ dest_y++;
+ line += raster;
+ }
+ }
+ break;
+ default:
+ return(-1); /* panic */
+ }
+ }
+ else
+ /* monochrome device: one bit per pixel */
+ { /* bitmap is the same as win_copy_mono: one bit per pixel */
+ win_prn_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
+ (gx_color_index)0,
+ (gx_color_index)(dev->color_info.depth==8 ? 63 : dev->color_info.max_gray));
+ }
+ return 0;
+}
+
+
+/* ------ Internal routines ------ */
+
+#undef wdev
+
+
+private void near
+win_prn_addtool(gx_device_win_prn *wdev, int i)
+{
+ wdev->hpens[i] = CreatePen(PS_SOLID, 1, PALETTEINDEX(i));
+ wdev->hbrushs[i] = CreateSolidBrush(PALETTEINDEX(i));
+}
+
+
+private void near
+win_prn_maketools(gx_device_win_prn *wdev, HDC hdc)
+{ int i;
+ wdev->hpensize = (1<<(wdev->color_info.depth)) * sizeof(HPEN);
+ wdev->hpens = (HPEN *)gs_malloc(1, wdev->hpensize,
+ "win_prn_maketools(pens)");
+ wdev->hbrushsize = (1<<(wdev->color_info.depth)) * sizeof(HBRUSH);
+ wdev->hbrushs = (HBRUSH *)gs_malloc(1, wdev->hbrushsize,
+ "win_prn_maketools(brushes)");
+ if (wdev->hpens && wdev->hbrushs) {
+ for (i=0; i<wdev->nColors; i++)
+ win_prn_addtool(wdev, i);
+
+ wdev->hpen = wdev->hpens[0];
+ SelectObject(hdc,wdev->hpen);
+
+ wdev->hbrush = wdev->hbrushs[0];
+ SelectObject(hdc,wdev->hbrush);
+ }
+}
+
+
+private void near
+win_prn_destroytools(gx_device_win_prn *wdev)
+{ int i;
+ for (i=0; i<wdev->nColors; i++) {
+ DeleteObject(wdev->hpens[i]);
+ DeleteObject(wdev->hbrushs[i]);
+ }
+ gs_free((char *)wdev->hbrushs, 1, wdev->hbrushsize,
+ "win_prn_destroytools(brushes)");
+ gs_free((char *)wdev->hpens, 1, wdev->hpensize,
+ "win_prn_destroytools(pens)");
+}
diff --git a/gs/src/gdevx.c b/gs/src/gdevx.c
new file mode 100644
index 000000000..ba29a2d16
--- /dev/null
+++ b/gs/src/gdevx.c
@@ -0,0 +1,1250 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevx.c */
+/* X Windows driver for Ghostscript library */
+/* The X include files include <sys/types.h>, which, on some machines */
+/* at least, define uint, ushort, and ulong, which std.h also defines. */
+/* std.h has taken care of this. */
+#include "gx.h" /* for gx_bitmap; includes std.h */
+#include "math_.h"
+#include "memory_.h"
+#include "x_.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gdevx.h"
+
+/* Define whether to update after every write, for debugging. */
+bool always_update = false;
+
+/* Define the maximum size of the temporary pixmap for copy_mono */
+/* that we are willing to leave lying around in the server */
+/* between uses. (Assume 32-bit ints here!) */
+private int max_temp_pixmap = 20000;
+
+/* Forward references */
+private int set_tile(P2(gx_device *, const gx_strip_bitmap *));
+private void free_cp(P1(gx_device *));
+/* Screen updating machinery */
+#define update_init(dev)\
+ ((gx_device_X *)(dev))->up_area = 0,\
+ ((gx_device_X *)(dev))->up_count = 0
+#define update_flush(dev)\
+ if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
+private void update_do_flush(P1(gx_device *));
+private void x_send_event(P2(gx_device *, Atom));
+
+/* Procedures */
+
+extern int gdev_x_open(P1(gx_device_X *));
+private dev_proc_open_device(x_open);
+private dev_proc_get_initial_matrix(x_get_initial_matrix);
+private dev_proc_sync_output(x_sync);
+private dev_proc_output_page(x_output_page);
+private dev_proc_close_device(x_close);
+private dev_proc_map_rgb_color(x_map_rgb_color);
+private dev_proc_map_color_rgb(x_map_color_rgb);
+private dev_proc_fill_rectangle(x_fill_rectangle);
+private dev_proc_copy_mono(x_copy_mono);
+private dev_proc_copy_color(x_copy_color);
+private dev_proc_get_bits(x_get_bits);
+private dev_proc_put_params(x_put_params);
+dev_proc_get_xfont_procs(x_get_xfont_procs);
+private dev_proc_get_page_device(x_get_page_device);
+private dev_proc_strip_tile_rectangle(x_strip_tile_rectangle);
+
+/* The device descriptor */
+private gx_device_procs x_procs = {
+ x_open,
+ x_get_initial_matrix,
+ x_sync,
+ x_output_page,
+ x_close,
+ x_map_rgb_color,
+ x_map_color_rgb,
+ x_fill_rectangle,
+ NULL, /* tile_rectangle */
+ x_copy_mono,
+ x_copy_color,
+ NULL, /* draw_line */
+ x_get_bits,
+ NULL, /* get_params */
+ x_put_params,
+ NULL, /* map_cmyk_color */
+ x_get_xfont_procs,
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ x_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 */
+ x_strip_tile_rectangle
+};
+
+/* The instance is public. */
+gx_device_X far_data gs_x11_device = {
+ std_device_color_body(gx_device_X, &x_procs, "x11",
+ FAKE_RES*DEFAULT_WIDTH_10THS/10, FAKE_RES*DEFAULT_HEIGHT_10THS/10, /* x and y extent (nominal) */
+ FAKE_RES, FAKE_RES, /* x and y density (nominal) */
+ /*dci_color(*/24, 255, 256/*)*/),
+ { 0 }, /* std_procs */
+ 1 /*true*/, /* IsPageDevice */
+ { /* image */
+ 0, 0, /* width, height */
+ 0, XYBitmap, NULL, /* xoffset, format, data */
+ LSBFirst, 8, /* byte-order, bitmap-unit */
+ MSBFirst, 8, 1, /* bitmap-bit-order, bitmap-pad, depth */
+ 0, 1, /* bytes_per_line, bits_per_pixel */
+ 0, 0, 0, /* red_mask, green_mask, blue_mask */
+ NULL, /* *obdata */
+ { NULL, /* *(*create_image)() */
+ NULL, /* (*destroy_image)() */
+ NULL, /* (*get_pixel)() */
+ NULL, /* (*put_pixel)() */
+ NULL, /* *(*sub_image)() */
+ NULL /* (*add_pixel)() */
+ },
+ },
+ NULL, NULL, /* dpy, scr */
+ /* (connection not initialized) */
+ NULL, /* vinfo */
+ (Colormap)None, /* cmap */
+ (Window)None, /* win */
+ NULL, /* gc */
+ (Window)None, /* pwin */
+ (Pixmap)0, /* bpixmap */
+ 0, /* ghostview */
+ (Window)None, /* mwin */
+#if HaveStdCMap
+ NULL, /* std_cmap */
+#endif
+ { identity_matrix_body }, /* initial matrix (filled in) */
+ (Atom)0, (Atom)0, (Atom)0, /* Atoms: NEXT, PAGE, DONE */
+ { 0, 0, 0, 0 }, 0, 0, /* update, up_area, up_count */
+ (Pixmap)0, /* dest */
+ 0L, (ulong)~0L, /* colors_or, colors_and */
+ { /* cp */
+ (Pixmap)0, /* pixmap */
+ NULL, /* gc */
+ -1, -1 /* raster, height */
+ },
+ { /* ht */
+ (Pixmap)None, /* pixmap */
+ (Pixmap)None, /* no_pixmap */
+ gx_no_bitmap_id, /* id */
+ 0, 0, 0, /* width, height, raster */
+ 0, 0 /* fore_c, back_c */
+ },
+ GXcopy, /* function */
+ FillSolid, /* fill_style */
+ 0, /* font */
+ 0, 0, /* back_color, fore_color */
+ 0, 0, /* background, foreground */
+ NULL, /* dither_colors */
+ 0, 0, /* color_mask, num_rgb */
+ NULL, 0, /* dynamic_colors, max_dynamic_colors */
+ 0, 0, /* dynamic_size, dynamic_allocs */
+ 0, 0, /* borderColor, borderWidth */
+ NULL, /* geometry */
+ 128, 5, /* maxGrayRamp, maxRGBRamp */
+ NULL, /* palette */
+ NULL, NULL, NULL, /* regularFonts, symbolFonts, dingbatFonts */
+ NULL, NULL, NULL, /* regular_fonts, symbol_fonts, dingbat_fonts */
+ 1, 1, /* useXFonts, useFontExtensions */
+ 1, 0, /* useScalableFonts, logXFonts */
+ 0.0, 0.0, /* xResolution, yResolution */
+ 1, /* useBackingPixmap */
+ 1, 1, /* useXPutImage, useXSetTile */
+};
+
+/* If XPutImage doesn't work, do it ourselves. */
+private int alt_put_image(P11(gx_device *dev, Display *dpy, Drawable win,
+ GC gc, XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h));
+#define put_image(dpy,win,gc,im,sx,sy,x,y,w,h)\
+ do {\
+ if ( xdev->useXPutImage ) {\
+ XPutImage(dpy,win,gc,im,sx,sy,x,y,w,h);\
+ } else {\
+ int code_ = alt_put_image(dev,dpy,win,gc,im,sx,sy,x,y,w,h);\
+ if ( code_ < 0 ) return code_;\
+ }\
+ } while (0)
+
+/* Open the device. Most of the code is in gdevxini.c. */
+private int
+x_open(gx_device *dev)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+ int code = gdev_x_open(xdev);
+
+ if (code < 0) return code;
+ update_init(dev);
+ return 0;
+}
+
+/* Close the device. */
+private int
+x_close(gx_device *dev)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ if (xdev->ghostview) x_send_event(dev, xdev->DONE);
+ if (xdev->vinfo) {
+ XFree((char *)xdev->vinfo);
+ xdev->vinfo = NULL;
+ }
+ if (xdev->dither_colors) {
+ if (gx_device_has_color(xdev))
+#define cube(r) (r*r*r)
+ gs_free((char *)xdev->dither_colors, sizeof(x_pixel),
+ cube(xdev->color_info.dither_colors), "x11_rgb_cube");
+#undef cube
+ else
+ gs_free((char *)xdev->dither_colors, sizeof(x_pixel),
+ xdev->color_info.dither_grays, "x11_gray_ramp");
+ xdev->dither_colors = NULL;
+ }
+ if (xdev->dynamic_colors) {
+ int i;
+ for (i = 0; i < xdev->dynamic_size; i++) {
+ x11color *xcp = (*xdev->dynamic_colors)[i];
+ x11color *next;
+ while (xcp) {
+ next = xcp->next;
+ gs_free((char *)xcp, sizeof(x11color), 1, "x11_dynamic_color");
+ xcp = next;
+ }
+ }
+ gs_free((char *)xdev->dynamic_colors, sizeof(x11color *),
+ xdev->dynamic_size, "x11_dynamic_colors");
+ xdev->dynamic_colors = NULL;
+ }
+ while (xdev->regular_fonts) {
+ x11fontmap *font = xdev->regular_fonts;
+ xdev->regular_fonts = font->next;
+ if (font->std_names) XFreeFontNames(font->std_names);
+ if (font->iso_names) XFreeFontNames(font->iso_names);
+ gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
+ "x11_font_x11name");
+ gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
+ "x11_font_psname");
+ gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
+ }
+ while (xdev->symbol_fonts) {
+ x11fontmap *font = xdev->symbol_fonts;
+ xdev->symbol_fonts = font->next;
+ if (font->std_names) XFreeFontNames(font->std_names);
+ if (font->iso_names) XFreeFontNames(font->iso_names);
+ gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
+ "x11_font_x11name");
+ gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
+ "x11_font_psname");
+ gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
+ }
+ while (xdev->dingbat_fonts) {
+ x11fontmap *font = xdev->dingbat_fonts;
+ xdev->dingbat_fonts = font->next;
+ if (font->std_names) XFreeFontNames(font->std_names);
+ if (font->iso_names) XFreeFontNames(font->iso_names);
+ gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
+ "x11_font_x11name");
+ gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
+ "x11_font_psname");
+ gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
+ }
+ XCloseDisplay(xdev->dpy);
+ return 0;
+}
+
+/* Define a table for computing N * X_max_color_value / D for 0 <= N <= D, */
+/* 1 <= D <= 7. */
+/* This requires a multiply and a divide otherwise; */
+/* integer multiply and divide are slow on all platforms. */
+#define cv_fraction(n, d) ((ushort)(X_max_color_value * (n) / (d)))
+#define nd(n, d) cv_fraction(n, d)
+private const ushort cv_tab1[] = {
+ nd(0,1), nd(1,1)
+};
+private const ushort cv_tab2[] = {
+ nd(0,2), nd(1,2), nd(2,2)
+};
+private const ushort cv_tab3[] = {
+ nd(0,3), nd(1,3), nd(2,3), nd(3,3)
+};
+private const ushort cv_tab4[] = {
+ nd(0,4), nd(1,4), nd(2,4), nd(3,4), nd(4,4)
+};
+private const ushort cv_tab5[] = {
+ nd(0,5), nd(1,5), nd(2,5), nd(3,5), nd(4,5), nd(5,5)
+};
+private const ushort cv_tab6[] = {
+ nd(0,6), nd(1,6), nd(2,6), nd(3,6), nd(4,6), nd(5,6), nd(6,6)
+};
+private const ushort cv_tab7[] = {
+ nd(0,7), nd(1,7), nd(2,7), nd(3,7), nd(4,7), nd(5,7), nd(6,7), nd(7,7)
+};
+private const ushort _ds *cv_tables[] = {
+ 0, cv_tab1, cv_tab2, cv_tab3, cv_tab4, cv_tab5, cv_tab6, cv_tab7
+};
+
+/* Map a color. The "device colors" are just r,g,b packed together. */
+private gx_color_index
+x_map_rgb_color(register gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+ /* X and ghostscript both use shorts for color values */
+ unsigned short dr = r & xdev->color_mask; /* Nearest color that */
+ unsigned short dg = g & xdev->color_mask; /* the X device can */
+ unsigned short db = b & xdev->color_mask; /* represent */
+ unsigned short cv_max = X_max_color_value & xdev->color_mask;
+ int cv_denom = (gx_max_color_value + 1);
+
+ /* Foreground and background get special treatment: */
+ /* They may be mapped to other colors. */
+ if ( (dr | dg | db) == 0 ) { /* i.e., all 0 */
+ return xdev->foreground;
+ }
+ if ( (dr & dg & db) == cv_max ) { /* i.e., all max value */
+ return xdev->background;
+ }
+#if HaveStdCMap
+ /* check the standard colormap first */
+ if (xdev->std_cmap) {
+ XStandardColormap *cmap = xdev->std_cmap;
+
+ if (gx_device_has_color(xdev)) {
+ unsigned short cr, cg, cb; /* rgb cube indices */
+ unsigned short cvr, cvg, cvb; /* color value on cube */
+
+ cr = r * (cmap->red_max + 1) / cv_denom;
+ cg = g * (cmap->green_max + 1) / cv_denom;
+ cb = b * (cmap->blue_max + 1) / cv_denom;
+ cvr = X_max_color_value * cr / cmap->red_max;
+ cvg = X_max_color_value * cg / cmap->green_max;
+ cvb = X_max_color_value * cb / cmap->blue_max;
+ if ((abs((int)r - (int)cvr) & xdev->color_mask) == 0 &&
+ (abs((int)g - (int)cvg) & xdev->color_mask) == 0 &&
+ (abs((int)b - (int)cvb) & xdev->color_mask) == 0)
+ return cr * cmap->red_mult + cg * cmap->green_mult +
+ cb * cmap->blue_mult + cmap->base_pixel;
+ } else {
+ unsigned short cr;
+ unsigned short cvr;
+ int dither_grays = xdev->color_info.dither_grays;
+
+ cr = r * dither_grays / cv_denom;
+ cvr = X_max_color_value * cr / cmap->red_max;
+ if ((abs((int)r - (int)cvr) & xdev->color_mask) == 0)
+ return cr * cmap->red_mult + cmap->base_pixel;
+ }
+ } else
+#endif
+ /* If there is no standard colormap, check the dither cube/ramp */
+ if (xdev->dither_colors) {
+ if (gx_device_has_color(xdev)) {
+ unsigned short cr, cg, cb; /* rgb cube indices */
+ unsigned short cvr, cvg, cvb; /* color value on cube */
+ int dither_rgb = xdev->color_info.dither_colors;
+ unsigned short max_rgb = dither_rgb - 1;
+
+ cr = r * dither_rgb / cv_denom;
+ cg = g * dither_rgb / cv_denom;
+ cb = b * dither_rgb / cv_denom;
+ if ( max_rgb < countof(cv_tables) )
+ { const ushort *cv_tab = cv_tables[max_rgb];
+ cvr = cv_tab[cr];
+ cvg = cv_tab[cg];
+ cvb = cv_tab[cb];
+ }
+ else
+ { cvr = cv_fraction(cr, max_rgb);
+ cvg = cv_fraction(cg, max_rgb);
+ cvb = cv_fraction(cb, max_rgb);
+ }
+ if ((abs((int)r - (int)cvr) & xdev->color_mask) == 0 &&
+ (abs((int)g - (int)cvg) & xdev->color_mask) == 0 &&
+ (abs((int)b - (int)cvb) & xdev->color_mask) == 0) {
+ return xdev->dither_colors[cube_index(cr, cg, cb)];
+ }
+ } else {
+ unsigned short cr;
+ unsigned short cvr;
+ int dither_grays = xdev->color_info.dither_grays;
+ unsigned short max_gray = dither_grays - 1;
+
+ cr = r * dither_grays / cv_denom;
+ cvr = (X_max_color_value * cr / max_gray);
+ if ((abs((int)r - (int)cvr) & xdev->color_mask) == 0)
+ return xdev->dither_colors[cr];
+ }
+ }
+ /* Finally look through the list of dynamic colors */
+ if (xdev->dynamic_colors) {
+ int i = (dr ^ dg ^ db) >> (16 - xdev->vinfo->bits_per_rgb);
+ x11color *xcp = (*xdev->dynamic_colors)[i];
+ x11color *last = NULL;
+ XColor xc;
+
+ while (xcp) {
+ if (xcp->color.red == dr && xcp->color.green == dg &&
+ xcp->color.blue == db) {
+ if (last) {
+ last->next = xcp->next;
+ xcp->next = (*xdev->dynamic_colors)[i];
+ (*xdev->dynamic_colors)[i] = xcp;
+ }
+ if (xcp->color.pad) return xcp->color.pixel;
+ else return gx_no_color_index;
+ }
+ last = xcp;
+ xcp = xcp->next;
+ }
+
+ /* If not in our list of dynamic colors, */
+ /* ask the X server and add an entry. */
+ /* First check if dynamic table is exhausted */
+ if (xdev->dynamic_allocs > xdev->max_dynamic_colors)
+ return gx_no_color_index;
+ xcp = (x11color *) gs_malloc(sizeof(x11color), 1, "x11_dynamic_color");
+ if (!xcp) return gx_no_color_index;
+ xc.red = xcp->color.red = dr;
+ xc.green = xcp->color.green = dg;
+ xc.blue = xcp->color.blue = db;
+ xcp->next = (*xdev->dynamic_colors)[i];
+ (*xdev->dynamic_colors)[i] = xcp;
+ xdev->dynamic_allocs++;
+ if (XAllocColor(xdev->dpy, xdev->cmap, &xc)) {
+ xcp->color.pixel = xc.pixel;
+ xcp->color.pad = True;
+ return xc.pixel;
+ } else {
+ xcp->color.pad = False;
+ return gx_no_color_index;
+ }
+ }
+ return gx_no_color_index;
+}
+
+
+/* Map a "device color" back to r-g-b. */
+/* This doesn't happen often, so we just ask the display */
+/* Foreground and background may be mapped to other colors, so */
+/* they are handled specially. */
+private int
+x_map_color_rgb(register gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ if (color == xdev->foreground)
+ prgb[0] = prgb[1] = prgb[2] = 0;
+ else if (color == xdev->background)
+ prgb[0] = prgb[1] = prgb[2] = gx_max_color_value;
+ else {
+ XColor xc;
+
+ xc.pixel = color;
+ XQueryColor(xdev->dpy, xdev->cmap, &xc);
+ prgb[0] = xc.red;
+ prgb[1] = xc.green;
+ prgb[2] = xc.blue;
+ }
+ return 0;
+}
+
+/* Get initial matrix for X device. */
+/* This conflicts seriously with the code for page devices; */
+/* we only do it if Ghostview is active. */
+private void
+x_get_initial_matrix(register gx_device *dev, register gs_matrix *pmat)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ if ( !xdev->ghostview )
+ { gx_default_get_initial_matrix(dev, pmat);
+ return;
+ }
+ pmat->xx = xdev->initial_matrix.xx;
+ pmat->xy = xdev->initial_matrix.xy;
+ pmat->yx = xdev->initial_matrix.yx;
+ pmat->yy = xdev->initial_matrix.yy;
+ pmat->tx = xdev->initial_matrix.tx;
+ pmat->ty = xdev->initial_matrix.ty;
+}
+
+/* Synchronize the display with the commands already given */
+private int
+x_sync(register gx_device *dev)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ update_flush(dev);
+ XFlush(xdev->dpy);
+ return 0;
+}
+
+/* Send event to ghostview process */
+private void
+x_send_event(gx_device *dev, Atom msg)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+ XEvent event;
+
+ event.xclient.type = ClientMessage;
+ event.xclient.display = xdev->dpy;
+ event.xclient.window = xdev->win;
+ event.xclient.message_type = msg;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = xdev->mwin;
+ event.xclient.data.l[1] = xdev->dest;
+ XSendEvent(xdev->dpy, xdev->win, False, 0, &event);
+}
+
+/* Output "page" */
+private int
+x_output_page(gx_device *dev, int num_copies, int flush)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ x_sync(dev);
+
+ /* Send ghostview a "page" client event */
+ /* Wait for a "next" client event */
+ if (xdev->ghostview) {
+ XEvent event;
+
+ x_send_event(dev, xdev->PAGE);
+ XNextEvent(xdev->dpy, &event);
+ while (event.type != ClientMessage ||
+ event.xclient.message_type != xdev->NEXT) {
+ XNextEvent(xdev->dpy, &event);
+ }
+ }
+ return 0;
+}
+
+/* Fill a rectangle with a color. */
+private int
+x_fill_rectangle(register gx_device *dev,
+ int x, int y, int w, int h, gx_color_index color)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ fit_fill(dev, x, y, w, h);
+ set_fill_style(FillSolid);
+ set_fore_color(color);
+ set_function(GXcopy);
+ XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
+ /* If we are filling the entire screen, reset */
+ /* colors_or and colors_and. It's wasteful to do this */
+ /* on every operation, but there's no separate driver routine */
+ /* for erasepage (yet). */
+ if (x == 0 && y == 0 && w == xdev->width && h == xdev->height) {
+ if (color == xdev->foreground || color == xdev->background) {
+ if (xdev->dynamic_colors) {
+ int i;
+ for (i = 0; i < xdev->dynamic_size; i++) {
+ x11color *xcp = (*xdev->dynamic_colors)[i];
+ x11color *next;
+ while (xcp) {
+ next = xcp->next;
+ if (xcp->color.pad) {
+ XFreeColors(xdev->dpy, xdev->cmap,
+ &xcp->color.pixel, 1, 0);
+ }
+ gs_free((char *)xcp, sizeof(x11color), 1,
+ "x11_dynamic_color");
+ xcp = next;
+ }
+ (*xdev->dynamic_colors)[i] = NULL;
+ }
+ xdev->dynamic_allocs = 0;
+ }
+ }
+ xdev->colors_or = xdev->colors_and = color;
+ }
+ if (xdev->bpixmap != (Pixmap) 0) {
+ x_update_add(dev, x, y, w, h);
+ }
+#ifdef DEBUG
+ if (gs_debug['F'])
+ dprintf5("[F] fill (%d,%d):(%d,%d) %ld\n",
+ x, y, w, h, (long)color);
+#endif
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+private int
+x_copy_mono(register gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+/*
+ * X doesn't directly support the simple operation of writing a color
+ * through a mask specified by an image. The plot is the following:
+ * If neither color is gx_no_color_index ("transparent"),
+ * use XPutImage with the "copy" function as usual.
+ * If the color either bitwise-includes or is bitwise-included-in
+ * every color written to date
+ * (a special optimization for writing black/white on color displays),
+ * use XPutImage with an appropriate Boolean function.
+ * Otherwise, do the following complicated stuff:
+ * Create pixmap of depth 1 if necessary.
+ * If foreground color is "transparent" then
+ * invert the raster data.
+ * Use XPutImage to copy the raster image to the newly
+ * created Pixmap.
+ * Install the Pixmap as the clip_mask in the X GC and
+ * tweak the clip origin.
+ * Do an XFillRectangle, fill style=solid, specifying a
+ * rectangle the same size as the original raster data.
+ * De-install the clip_mask.
+ */
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+ int function = GXcopy;
+
+ x_pixel
+ bc = zero,
+ fc = one;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+
+ xdev->image.width = sourcex + w;
+ xdev->image.height = h;
+ xdev->image.data = (char *)base;
+ xdev->image.bytes_per_line = raster;
+ set_fill_style(FillSolid);
+
+ /* Check for null, easy 1-color, hard 1-color, and 2-color cases. */
+ if (zero != gx_no_color_index) {
+ if (one != gx_no_color_index) {
+ /* 2-color case. */
+ /* Simply replace existing bits with what's in the image. */
+ } else if (!(~xdev->colors_and & bc)) {
+ function = GXand;
+ fc = ~(x_pixel) 0;
+ } else if (!(~bc & xdev->colors_or)) {
+ function = GXor;
+ fc = 0;
+ } else {
+ goto hard;
+ }
+ } else {
+ if (one == gx_no_color_index) { /* no-op */
+ return 0;
+ } else if (!(~xdev->colors_and & fc)) {
+ function = GXand;
+ bc = ~(x_pixel) 0;
+ } else if (!(~fc & xdev->colors_or)) {
+ function = GXor;
+ bc = 0;
+ } else {
+ goto hard;
+ }
+ }
+ xdev->image.format = XYBitmap;
+ set_function(function);
+ if (bc != xdev->back_color) {
+ XSetBackground(xdev->dpy, xdev->gc, (xdev->back_color = bc));
+ }
+ if (fc != xdev->fore_color) {
+ XSetForeground(xdev->dpy, xdev->gc, (xdev->fore_color = fc));
+ }
+ if (zero != gx_no_color_index)
+ note_color(zero);
+ if (one != gx_no_color_index)
+ note_color(one);
+ put_image(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
+ sourcex, 0, x, y, w, h);
+
+ goto out;
+
+hard: /* Handle the hard 1-color case. */
+ if (raster > xdev->cp.raster || h > xdev->cp.height) {
+ /* Must allocate a new pixmap and GC. */
+ /* Release the old ones first. */
+ free_cp(dev);
+
+ /* Create the clipping pixmap, depth must be 1. */
+ xdev->cp.pixmap =
+ XCreatePixmap(xdev->dpy, xdev->win, raster << 3, h, 1);
+ if (xdev->cp.pixmap == (Pixmap) 0) {
+ lprintf("x_copy_mono: can't allocate pixmap\n");
+ return_error(gs_error_VMerror);
+ }
+ xdev->cp.gc = XCreateGC(xdev->dpy, xdev->cp.pixmap, 0, 0);
+ if (xdev->cp.gc == (GC) 0) {
+ lprintf("x_copy_mono: can't allocate GC\n");
+ return_error(gs_error_VMerror);
+ }
+ xdev->cp.raster = raster;
+ xdev->cp.height = h;
+ }
+ /* Initialize static mask image params */
+ xdev->image.format = XYBitmap;
+ set_function(GXcopy);
+
+ /* Select polarity based on fg/bg transparency. */
+ if (one == gx_no_color_index) { /* invert */
+ XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
+ XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
+ set_fore_color(zero);
+ } else {
+ XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
+ XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
+ set_fore_color(one);
+ }
+ put_image(xdev->dpy, xdev->cp.pixmap, xdev->cp.gc,
+ &xdev->image, sourcex, 0, 0, 0, w, h);
+
+ /* Install as clipmask. */
+ XSetClipMask(xdev->dpy, xdev->gc, xdev->cp.pixmap);
+ XSetClipOrigin(xdev->dpy, xdev->gc, x, y);
+
+ /*
+ * Draw a solid rectangle through the raster clip mask.
+ * Note fill style is guaranteed to be solid from above.
+ */
+ XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
+
+ /* Tidy up. Free the pixmap if it's big. */
+ XSetClipMask(xdev->dpy, xdev->gc, None);
+ if (raster * h > max_temp_pixmap)
+ free_cp(dev);
+
+out:if (xdev->bpixmap != (Pixmap) 0) {
+ /* We wrote to the pixmap, so update the display now. */
+ x_update_add(dev, x, y, w, h);
+ }
+ return 0;
+}
+
+/* Internal routine to free the GC and pixmap used for copying. */
+private void
+free_cp(register gx_device *dev)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ if (xdev->cp.gc != NULL) {
+ XFreeGC(xdev->dpy, xdev->cp.gc);
+ xdev->cp.gc = NULL;
+ }
+ if (xdev->cp.pixmap != (Pixmap) 0) {
+ XFreePixmap(xdev->dpy, xdev->cp.pixmap);
+ xdev->cp.pixmap = (Pixmap) 0;
+ }
+ xdev->cp.raster = -1; /* mark as unallocated */
+}
+
+/* Copy a color bitmap. */
+private int
+x_copy_color(register gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ gx_device_X *xdev = (gx_device_X *)dev;
+ int depth = dev->color_info.depth;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ set_fill_style(FillSolid);
+ set_function(GXcopy);
+
+ /* Filling with a colored halftone often gives rise to */
+ /* copy_color calls for a single pixel. Check for this now. */
+
+ if ( h == 1 && w == 1 )
+ { uint sbit = sourcex * depth;
+ const byte *ptr = base + (sbit >> 3);
+ x_pixel pixel;
+ if ( depth < 8 )
+ pixel = (byte)(*ptr << (sbit & 7)) >> (8 - depth);
+ else
+ { pixel = *ptr++;
+ while ( (depth -= 8) > 0 )
+ pixel = (pixel << 8) + *ptr++;
+ }
+ set_fore_color(pixel);
+ XDrawPoint(xdev->dpy, xdev->dest, xdev->gc, x, y);
+ }
+ else
+ { xdev->image.width = sourcex + w;
+ xdev->image.height = h;
+ xdev->image.format = ZPixmap;
+ xdev->image.data = (char *)base;
+ xdev->image.depth = depth;
+ xdev->image.bytes_per_line = raster;
+ xdev->image.bits_per_pixel = depth;
+ XPutImage(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
+ sourcex, 0, x, y, w, h);
+ xdev->image.depth = xdev->image.bits_per_pixel = 1;
+ }
+ if (xdev->bpixmap != (Pixmap) 0)
+ x_update_add(dev, x, y, w, h);
+#ifdef DEBUG
+ if (gs_debug['F'])
+ dprintf4("[F] copy_color (%d,%d):(%d,%d)\n",
+ x, y, w, h);
+#endif
+ return 0;
+}
+
+private int
+x_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ gx_device_X *xdev = (gx_device_X *)dev;
+ int depth = dev->color_info.depth;
+ uint width_bytes = gx_device_raster(dev, false);
+ XImage *image;
+
+ /* Make sure the frame buffer is up to date. */
+ if ( xdev->up_area != 0 &&
+ y >= xdev->update.yo && y < xdev->update.ye
+ )
+ update_do_flush(dev);
+ /*
+ * The X library doesn't provide any way to specify the desired
+ * bit or byte ordering for the result, so we just hope for the best
+ * (big-endian).
+ */
+ image = XGetImage(xdev->dpy, xdev->dest, 0, y, dev->width, 1,
+ (1L << depth) - 1, ZPixmap);
+ memcpy(str, image->data, width_bytes);
+ XDestroyImage(image);
+ *actual_data = str;
+ return 0;
+}
+
+/* Set the device parameters. We reimplement this so we can resize */
+/* the window and avoid closing and reopening the device, and to add */
+/* .IsPageDevice. */
+private int
+x_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device_X *xdev = (gx_device_X *)dev;
+ bool is_open = dev->is_open;
+ int width = dev->width;
+ int height = dev->height;
+ float xres = dev->HWResolution[0];
+ float yres = dev->HWResolution[1];
+ long pwin = (long)xdev->pwin;
+ bool is_page = xdev->IsPageDevice;
+ bool save_is_page = xdev->IsPageDevice;
+ int ecode = 0, code;
+
+ /* Handle extra parameters */
+ switch ( code = param_read_long(plist, "WindowID", &pwin) )
+ {
+ case 0:
+ case 1:
+ break;
+ default:
+ ecode = code;
+ param_signal_error(plist, "GSVIEW", ecode);
+ }
+
+ switch ( code = param_read_bool(plist, ".IsPageDevice", &is_page) )
+ {
+ case 0:
+ case 1:
+ break;
+ default:
+ ecode = code;
+ param_signal_error(plist, "GSVIEW", ecode);
+ }
+
+ if ( ecode < 0 )
+ return ecode;
+
+ /* Unless we specified a new window ID, */
+ /* prevent gx_default_put_params from closing the device. */
+ if ( pwin == (long)xdev->pwin )
+ dev->is_open = false;
+ xdev->IsPageDevice = is_page;
+ code = gx_default_put_params(dev, plist);
+ dev->is_open = is_open;
+ if ( code < 0 )
+ { /* Undo setting of .IsPageDevice */
+ xdev->IsPageDevice = save_is_page;
+ return code;
+ }
+
+ if ( pwin != (long)xdev->pwin )
+ { if ( xdev->is_open )
+ gs_closedevice(dev);
+ xdev->pwin = (Window)pwin;
+ }
+
+ /* If the device is open, resize the window. */
+ /* Don't do this if Ghostview is active. */
+ if ( xdev->is_open && !xdev->ghostview &&
+ (dev->width != width || dev->height != height ||
+ dev->HWResolution[0] != xres || dev->HWResolution[1] != yres)
+ )
+ { int dw = dev->width - width;
+ int dh = dev->height - height;
+ double qx = dev->HWResolution[0] / xres;
+ double qy = dev->HWResolution[1] / xres;
+ if ( dw != 0 || dh != 0 )
+ { XResizeWindow(xdev->dpy, xdev->win,
+ dev->width, dev->height);
+ if (xdev->bpixmap != (Pixmap) 0)
+ { XFreePixmap(xdev->dpy, xdev->bpixmap);
+ xdev->bpixmap = (Pixmap) 0;
+ }
+ xdev->dest = 0;
+ gdev_x_clear_window(xdev);
+ }
+ /* Attempt to update the initial matrix in a sensible way. */
+ /* The whole handling of the initial matrix is a hack! */
+ if ( xdev->initial_matrix.xy == 0 )
+ { if ( xdev->initial_matrix.xx < 0 )
+ { /* 180 degree rotation */
+ xdev->initial_matrix.tx += dw;
+ }
+ else
+ { /* no rotation */
+ xdev->initial_matrix.ty += dh;
+ }
+ }
+ else
+ { if ( xdev->initial_matrix.xy < 0 )
+ { /* 90 degree rotation */
+ xdev->initial_matrix.tx += dh;
+ xdev->initial_matrix.ty += dw;
+ }
+ else
+ { /* 270 degree rotation */
+ }
+ }
+ xdev->initial_matrix.xx *= qx;
+ xdev->initial_matrix.xy *= qx;
+ xdev->initial_matrix.yx *= qy;
+ xdev->initial_matrix.yy *= qy;
+ }
+
+ return 0;
+}
+
+/* Get the page device. We reimplement this so that we can make this */
+/* device be a page device conditionally. */
+private gx_device *
+x_get_page_device(gx_device *dev)
+{ return (((gx_device_X *)dev)->IsPageDevice ? dev : (gx_device *)0);
+}
+
+/* Tile a rectangle. */
+private int
+x_strip_tile_rectangle(register gx_device *dev, const gx_strip_bitmap *tiles,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one,
+ int px, int py)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+ /* Give up if one color is transparent, or if the tile is colored. */
+ /* We should implement the latter someday, since X can handle it. */
+
+ if (one == gx_no_color_index || zero == gx_no_color_index)
+ return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
+ zero, one, px, py);
+
+ /* For the moment, give up if the phase or shift is non-zero. */
+ if (tiles->shift | px | py)
+ return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
+ zero, one, px, py);
+
+ fit_fill(dev, x, y, w, h);
+
+ /* Imaging with a halftone often gives rise to very small */
+ /* tile_rectangle calls. Check for this now. */
+
+ if ( h <= 2 && w <= 2 )
+ { int j;
+ set_fill_style(FillSolid);
+ set_function(GXcopy);
+ for ( j = 0; j < h; j++ )
+ { const byte *ptr =
+ tiles->data + ((y + j) % tiles->rep_height) * tiles->raster;
+ int i;
+ for ( i = 0; i < w; i++ )
+ { uint tx = (x + i) % tiles->rep_width;
+ byte mask = 0x80 >> (tx & 7);
+ x_pixel pixel = (ptr[tx >> 3] & mask ? one : zero);
+ set_fore_color(pixel);
+ XDrawPoint(xdev->dpy, xdev->dest, xdev->gc,
+ x + i, y + j);
+ }
+ }
+ if (xdev->bpixmap != (Pixmap) 0) {
+ x_update_add(dev, x, y, w, h);
+ }
+ return 0;
+ }
+
+ /*
+ * Remember, an X tile is already filled with particular
+ * pixel values (i.e., colors). Therefore if we are changing
+ * fore/background color, we must invalidate the tile (using
+ * the same technique as in set_tile). This problem only
+ * bites when using grayscale -- you may want to change
+ * fg/bg but use the same halftone screen.
+ */
+ if ((zero != xdev->ht.back_c) || (one != xdev->ht.fore_c))
+ xdev->ht.id = ~tiles->id; /* force reload */
+
+ set_back_color(zero);
+ set_fore_color(one);
+ if (!set_tile(dev, tiles))
+ { /* Bad news. Fall back to the default algorithm. */
+ return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
+ zero, one, px, py);
+ }
+ /* Use the tile to fill the rectangle */
+ set_fill_style(FillTiled);
+ set_function(GXcopy);
+ XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
+ if (xdev->bpixmap != (Pixmap) 0) {
+ x_update_add(dev, x, y, w, h);
+ }
+#ifdef DEBUG
+ if (gs_debug['F'])
+ dprintf6("[F] tile (%d,%d):(%d,%d) %ld,%ld\n",
+ x, y, w, h, (long)zero, (long)one);
+#endif
+ return 0;
+}
+
+/* Set up with a specified tile. */
+/* Return false if we can't do it for some reason. */
+private int
+set_tile(register gx_device *dev, register const gx_strip_bitmap *tile)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+
+#ifdef DEBUG
+ if (gs_debug['T'])
+ return 0;
+#endif
+ if (tile->id == xdev->ht.id && tile->id != gx_no_bitmap_id)
+ return xdev->useXSetTile;
+ /* Set up the tile Pixmap */
+ if (tile->size.x != xdev->ht.width ||
+ tile->size.y != xdev->ht.height ||
+ xdev->ht.pixmap == (Pixmap) 0) {
+ if (xdev->ht.pixmap != (Pixmap) 0)
+ XFreePixmap(xdev->dpy, xdev->ht.pixmap);
+ xdev->ht.pixmap = XCreatePixmap(xdev->dpy, xdev->win,
+ tile->size.x, tile->size.y,
+ xdev->vinfo->depth);
+ if (xdev->ht.pixmap == (Pixmap) 0)
+ return 0;
+ xdev->ht.width = tile->size.x, xdev->ht.height = tile->size.y;
+ xdev->ht.raster = tile->raster;
+ }
+ xdev->ht.fore_c = xdev->fore_color;
+ xdev->ht.back_c = xdev->back_color;
+ /* Copy the tile into the Pixmap */
+ xdev->image.data = (char *)tile->data;
+ xdev->image.width = tile->size.x;
+ xdev->image.height = tile->size.y;
+ xdev->image.bytes_per_line = tile->raster;
+ xdev->image.format = XYBitmap;
+ set_fill_style(FillSolid);
+#ifdef DEBUG
+ if (gs_debug['H']) {
+ int i;
+
+ dprintf4("[H] 0x%lx: width=%d height=%d raster=%d\n",
+ (ulong)tile->data, tile->size.x, tile->size.y, tile->raster);
+ for (i = 0; i < tile->raster * tile->size.y; i++)
+ dprintf1(" %02x", tile->data[i]);
+ dputc('\n');
+ }
+#endif
+ XSetTile(xdev->dpy, xdev->gc, xdev->ht.no_pixmap); /* *** X bug *** */
+ set_function(GXcopy);
+ put_image(xdev->dpy, xdev->ht.pixmap, xdev->gc, &xdev->image,
+ 0, 0, 0, 0, tile->size.x, tile->size.y);
+ XSetTile(xdev->dpy, xdev->gc, xdev->ht.pixmap);
+ xdev->ht.id = tile->id;
+ return xdev->useXSetTile;
+}
+
+
+/* ------ Screen update procedures ------ */
+
+/* Flush updates to the screen if needed. */
+private void
+update_do_flush(register gx_device *dev)
+{
+ gx_device_X *xdev = (gx_device_X *)dev;
+ int xo = xdev->update.xo, yo = xdev->update.yo;
+
+ set_function(GXcopy);
+ XCopyArea(xdev->dpy, xdev->bpixmap, xdev->win, xdev->gc,
+ xo, yo, xdev->update.xe - xo, xdev->update.ye - yo,
+ xo, yo);
+ update_init(dev);
+}
+
+/* Add a region to be updated. */
+/* This is only called if xdev->bpixmap != 0. */
+void
+x_update_add(gx_device *dev, int xo, int yo, int w, int h)
+{
+ register gx_device_X *xdev = (gx_device_X *)dev;
+ int xe = xo + w, ye = yo + h;
+ long new_area;
+
+ if ( always_update )
+ { /* Update the screen now. */
+ update_do_flush(dev);
+ new_area = (long)w * h;
+ }
+ else
+ { /* Only update the screen if it's worthwhile. */
+ if ( (++xdev->up_count >= 200 && xdev->up_area > 1000) ||
+ xdev->up_area == 0
+ )
+ { if ( xdev->up_area != 0 )
+ update_do_flush(dev);
+ new_area = (long)w * h;
+ }
+ else
+ { /* See whether adding this rectangle */
+ /* would result in too much being copied unnecessarily. */
+ long old_area = xdev->up_area;
+ long new_up_area;
+ rect u;
+
+ u.xo = min(xo, xdev->update.xo);
+ u.yo = min(yo, xdev->update.yo);
+ u.xe = max(xe, xdev->update.xe);
+ u.ye = max(ye, xdev->update.ye);
+ new_up_area = (long)(u.xe - u.xo) * (u.ye - u.yo);
+ /* The fraction of new_up_area used in the following test */
+ /* is not particularly critical; using a denominator */
+ /* that is a power of 2 eliminates a divide. */
+ if ( u.xe - u.xo >= 10 && u.ye - u.yo >= 10 &&
+ old_area + (new_area = (long)w * h) <
+ new_up_area - (new_up_area >> 2)
+ )
+ update_do_flush(dev);
+ else
+ { xdev->update = u;
+ xdev->up_area = new_up_area;
+ return;
+ }
+ }
+ }
+
+ xdev->update.xo = xo;
+ xdev->update.yo = yo;
+ xdev->update.xe = xe;
+ xdev->update.ye = ye;
+ xdev->up_area = new_area;
+}
+
+/* ------ Internal procedures ------ */
+
+/* Substitute for XPutImage using XFillRectangle. */
+/* This is a total hack to get around an apparent bug */
+/* in some X servers. It only works with the specific */
+/* parameters (bit/byte order, padding) used above. */
+private int
+alt_put_image(gx_device *dev, Display *dpy, Drawable win, GC gc,
+ XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h)
+{
+ int raster = pi->bytes_per_line;
+ byte *data = (byte *) pi->data + sy * raster + (sx >> 3);
+ int init_mask = 0x80 >> (sx & 7);
+ int invert = 0;
+ int yi;
+
+#define nrects 40
+ XRectangle rects[nrects];
+ XRectangle *rp = rects;
+
+ XGCValues gcv;
+
+ XGetGCValues(dpy, gc, (GCFunction | GCForeground | GCBackground), &gcv);
+
+ if (gcv.function == GXcopy) {
+ XSetForeground(dpy, gc, gcv.background);
+ XFillRectangle(dpy, win, gc, dx, dy, w, h);
+ XSetForeground(dpy, gc, gcv.foreground);
+ } else if (gcv.function == GXand) {
+ if (gcv.background != ~(x_pixel) 0) {
+ XSetForeground(dpy, gc, gcv.background);
+ invert = 0xff;
+ }
+ } else if (gcv.function == GXor) {
+ if (gcv.background != 0) {
+ XSetForeground(dpy, gc, gcv.background);
+ invert = 0xff;
+ }
+ } else {
+ lprintf("alt_put_image: unimplemented function.\n");
+ return_error(gs_error_rangecheck);
+ }
+
+ for (yi = 0; yi < h; yi++, data += raster) {
+ register int mask = init_mask;
+ register byte *dp = data;
+ register int xi = 0;
+
+ while (xi < w) {
+ if ((*dp ^ invert) & mask) {
+ int xleft = xi;
+
+ if (rp == &rects[nrects]) {
+ XFillRectangles(dpy, win, gc, rects, nrects);
+ rp = rects;
+ }
+ /* Scan over a run of 1-bits */
+ rp->x = dx + xi, rp->y = dy + yi;
+ do {
+ if (!(mask >>= 1))
+ mask = 0x80, dp++;
+ xi++;
+ } while (xi < w && (*dp & mask));
+ rp->width = xi - xleft, rp->height = 1;
+ rp++;
+ } else {
+ if (!(mask >>= 1))
+ mask = 0x80, dp++;
+ xi++;
+ }
+ }
+ }
+ XFillRectangles(dpy, win, gc, rects, rp - rects);
+ if (invert) XSetForeground(dpy, gc, gcv.foreground);
+ return 0;
+}
diff --git a/gs/src/gdevx.h b/gs/src/gdevx.h
new file mode 100644
index 000000000..11552a1f6
--- /dev/null
+++ b/gs/src/gdevx.h
@@ -0,0 +1,177 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevx.h */
+/* Header file with X device structure */
+/* Requires gxdevice.h and x_.h */
+
+/* Define the type of an X pixel. */
+typedef unsigned long x_pixel;
+
+/* Define a rectangle structure for update bookkeeping */
+typedef struct rect_s {
+ int xo, yo, xe, ye;
+} rect;
+
+/* Define dynamic color hash table structure */
+struct x11color_s;
+typedef struct x11color_s x11color;
+struct x11color_s {
+ XColor color;
+ x11color *next;
+};
+
+/* Define PostScript to X11 font name mapping */
+struct x11fontmap_s;
+typedef struct x11fontmap_s x11fontmap;
+struct x11fontmap_s {
+ char *ps_name;
+ char *x11_name;
+ char **std_names;
+ char **iso_names;
+ int std_count, iso_count;
+ x11fontmap *next;
+};
+
+/* Define the X Windows device */
+typedef struct gx_device_X_s {
+ gx_device_common;
+ bool IsPageDevice;
+
+ /* An XImage object for writing bitmap images to the screen */
+ XImage image;
+
+ /* Global X state */
+ Display *dpy;
+ Screen *scr;
+ XVisualInfo *vinfo;
+ Colormap cmap;
+ Window win;
+ GC gc;
+
+ /* An optional Window ID supplied as a device parameter */
+ Window pwin;
+
+ /* A backing pixmap so X will handle exposure automatically */
+ Pixmap bpixmap; /* 0 if useBackingPixmap is false, */
+ /* or if it can't be allocated */
+ int ghostview; /* flag to tell if ghostview is in control */
+ Window mwin; /* window to receive ghostview messages */
+/* Don't include standard colormap stuff for X11R3 and earlier */
+#if HaveStdCMap
+ XStandardColormap *std_cmap; /* standard color map if available */
+#endif
+ gs_matrix initial_matrix; /* the initial transformation */
+ Atom NEXT, PAGE, DONE; /* Atoms used to talk to ghostview */
+ rect update; /* region needing updating */
+ long up_area; /* total area of update */
+ /* (always 0 if no backing pixmap) */
+ int up_count; /* # of updates since flush */
+ Pixmap dest; /* bpixmap if non-0, else win */
+ x_pixel colors_or; /* 'or' of all device colors used so far */
+ x_pixel colors_and; /* 'and' ditto */
+
+ /* An intermediate pixmap for the stencil case of copy_mono */
+ struct {
+ Pixmap pixmap;
+ GC gc;
+ int raster, height;
+ } cp;
+
+ /* Structure for dealing with the halftone tile. */
+ /* Later this might become a multi-element cache. */
+ struct {
+ Pixmap pixmap;
+ Pixmap no_pixmap; /* kludge to get around X bug */
+ gx_bitmap_id id;
+ int width, height, raster;
+ x_pixel fore_c, back_c;
+ } ht;
+
+ /* Cache the function and fill style from the GC */
+ int function;
+ int fill_style;
+ Font fid;
+
+#define set_fill_style(style)\
+ if ( xdev->fill_style != style )\
+ XSetFillStyle(xdev->dpy, xdev->gc, (xdev->fill_style = style))
+#define set_function(func)\
+ if ( xdev->function != func )\
+ XSetFunction(xdev->dpy, xdev->gc, (xdev->function = func))
+#define set_font(font)\
+ if ( xdev->fid != font )\
+ XSetFont(xdev->dpy, xdev->gc, (xdev->fid = font))
+
+ x_pixel back_color, fore_color;
+
+ Pixel background, foreground;
+#define X_max_color_value 0xffff
+#define cube_index(r,g,b) (((r) * xdev->color_info.dither_colors + (g)) * \
+ xdev->color_info.dither_colors + (b))
+ x_pixel *dither_colors;
+ ushort color_mask;
+ int num_rgb;
+ x11color *(*dynamic_colors)[];
+ int max_dynamic_colors, dynamic_size, dynamic_allocs;
+
+#define note_color(pixel)\
+ xdev->colors_or |= pixel,\
+ xdev->colors_and &= pixel
+#define set_back_color(pixel)\
+ if ( xdev->back_color != pixel )\
+ { xdev->back_color = pixel;\
+ note_color(pixel);\
+ XSetBackground(xdev->dpy, xdev->gc, pixel);\
+ }
+#define set_fore_color(pixel)\
+ if ( xdev->fore_color != pixel )\
+ { xdev->fore_color = pixel;\
+ note_color(pixel);\
+ XSetForeground(xdev->dpy, xdev->gc, pixel);\
+ }
+
+ /* Defautlts set by resources */
+ Pixel borderColor;
+ Dimension borderWidth;
+ String geometry;
+ int maxGrayRamp, maxRGBRamp;
+ String palette;
+ String regularFonts;
+ String symbolFonts;
+ String dingbatFonts;
+ x11fontmap *regular_fonts;
+ x11fontmap *symbol_fonts;
+ x11fontmap *dingbat_fonts;
+ Boolean useXFonts, useFontExtensions, useScalableFonts, logXFonts;
+ float xResolution, yResolution;
+
+ /* Flags work around various X server problems. */
+ Boolean useBackingPixmap;
+ Boolean useXPutImage;
+ Boolean useXSetTile;
+
+} gx_device_X;
+
+/* function to keep track of screen updates */
+void x_update_add(P5(gx_device *, int, int, int, int));
+void gdev_x_clear_window(P1(gx_device_X *));
+int x_catch_free_colors(P2(Display *, XErrorEvent *));
+
+/* Number used to distinguish when resoultion was set from the command line */
+#define FAKE_RES (16*72)
diff --git a/gs/src/gdevxalt.c b/gs/src/gdevxalt.c
new file mode 100644
index 000000000..1cef263cf
--- /dev/null
+++ b/gs/src/gdevxalt.c
@@ -0,0 +1,723 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevxalt.c */
+/* Alternative X Windows drivers for help in driver debugging */
+#include "gx.h" /* for gx_bitmap; includes std.h */
+#include "math_.h"
+#include "memory_.h"
+#include "x_.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gdevx.h"
+
+extern gx_device_X gs_x11_device;
+
+/*
+ * Define a forwarding device with a cache for the first 16 colors,
+ * which avoids all of the time-consuming color mapping calls for
+ * the black-and-white, 2-bit gray, and CMYK devices defined here.
+ */
+typedef struct {
+ gx_device_forward_common;
+ gx_color_index color_cache[16];
+} gx_device_X_wrapper;
+
+/* ---------------- Generic procedures ---------------- */
+
+/* Forward declarations */
+private int get_dev_target(P2(gx_device **, gx_device *));
+#define set_dev_target(tdev, dev)\
+ do {\
+ int code_ = get_dev_target(&tdev, dev);\
+ if ( code_ < 0 )\
+ return code_;\
+ } while (0)
+private int get_target_info(P1(gx_device *));
+private gx_color_index x_alt_map_color(P2(gx_device *, gx_color_index));
+
+/* Clear the color mapping cache. */
+private void
+x_clear_color_cache(gx_device /*gx_device_X_wrapper*/ *dev)
+{ gx_device_X_wrapper *xdev = (gx_device_X_wrapper *)dev;
+ int i;
+
+ for ( i = 0; i < countof(xdev->color_cache); ++i )
+ xdev->color_cache[i] = gx_no_color_index;
+}
+
+/* "Wrappers" for driver procedures */
+
+private int
+x_wrap_open(gx_device *dev)
+{ gx_device *tdev;
+ int rcode, code;
+
+ set_dev_target(tdev, dev);
+ rcode = (*dev_proc(tdev, open_device))(tdev);
+ if ( rcode < 0 )
+ return rcode;
+ tdev->is_open = true;
+ code = get_target_info(dev);
+ return (code < 0 ? code : rcode);
+}
+
+private int
+x_forward_sync_output(gx_device *dev)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, sync_output))(tdev);
+}
+
+private int
+x_forward_output_page(gx_device *dev, int num_copies, int flush)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, output_page))(tdev, num_copies, flush);
+}
+
+private int
+x_wrap_close(gx_device *dev)
+{ gx_device *tdev;
+ /* If Ghostscript is exiting, we might have closed the */
+ /* underlying x11 device already.... */
+ int code;
+
+ set_dev_target(tdev, dev);
+ if ( tdev->is_open )
+ { code = (*dev_proc(tdev, close_device))(tdev);
+ x_clear_color_cache(dev);
+ if ( code < 0 )
+ return code;
+ tdev->is_open = false;
+ }
+ else
+ code = 0;
+ return code;
+}
+
+private int
+x_wrap_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, map_color_rgb))(tdev,
+ x_alt_map_color(dev, color),
+ prgb);
+}
+
+private int
+x_wrap_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, fill_rectangle))(tdev, x, y, w, h,
+ x_alt_map_color(dev, color));
+}
+
+private int
+x_wrap_copy_mono(gx_device *dev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, copy_mono))(tdev, base, sourcex, raster, id,
+ x, y, w, h,
+ x_alt_map_color(dev, zero),
+ x_alt_map_color(dev, one));
+
+}
+
+private int
+x_wrap_copy_color(gx_device *dev, const byte *base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h)
+{ gx_device *tdev;
+#define mapped_bytes 480 /* must be a multiple of 3 & 4 */
+ int depth_bytes, source_bits;
+ int block_w, block_h;
+ int xblock, yblock;
+ byte mapped[mapped_bytes];
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ set_dev_target(tdev, dev);
+ /* Device pixels must be an integral number of bytes. */
+ if ( tdev->color_info.depth & 7 )
+ return gx_default_copy_color(dev, base, sourcex, raster, id,
+ x, y, w, h);
+ depth_bytes = tdev->color_info.depth >> 3;
+ source_bits = dev->color_info.depth;
+ { int mapped_pixels = mapped_bytes / depth_bytes;
+ if ( w > mapped_pixels >> 1 )
+ block_w = min(w, mapped_pixels), block_h = 1;
+ else
+ block_w = w, block_h = mapped_pixels / w;
+ }
+ for ( yblock = y; yblock < y + h; yblock += block_h )
+ for ( xblock = x; xblock < x + w; xblock += block_w ) {
+ byte *p = mapped;
+ int xend = min(xblock + block_w, x + w);
+ int yend = min(yblock + block_h, y + h);
+ int xcur, ycur;
+ int code;
+
+ for ( ycur = yblock; ycur < yend; ++ycur )
+ for ( xcur = xblock; xcur < xend; ++xcur ) {
+ int sbit = (xcur - x + sourcex) * source_bits;
+ uint sbyte =
+ base[(ycur - y) * raster + (sbit >> 3)];
+ uint spixel =
+ ((sbyte << (sbit & 7)) & 0xff) >> (8 - source_bits);
+ gx_color_index cindex =
+ ((gx_device_X_wrapper *)dev)->color_cache[spixel];
+
+ if ( cindex == gx_no_color_index )
+ cindex = x_alt_map_color(dev, spixel);
+ switch ( depth_bytes ) {
+ case 4: *p++ = (byte)(cindex >> 24);
+ case 3: *p++ = (byte)(cindex >> 16);
+ case 2: *p++ = (byte)(cindex >> 8);
+ default /*case 1*/: *p++ = (byte)cindex;
+ }
+ }
+ code = (*dev_proc(tdev, copy_color))
+ (tdev, mapped, 0, (xend - xblock) * depth_bytes, gx_no_bitmap_id,
+ xblock, yblock, xend - xblock, yend - yblock);
+ if ( code < 0 )
+ return code;
+ }
+ return 0;
+}
+
+
+private int
+x_forward_copy_color(gx_device *dev, const byte *base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, copy_color))(tdev, base, sourcex, raster, id,
+ x, y, w, h);
+}
+
+private int
+x_forward_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+ return (*dev_proc(tdev, get_bits))(tdev, y, str, actual_data);
+}
+
+private int
+x_wrap_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{ int depth = dev->color_info.depth;
+ gx_device *tdev;
+ int width;
+ int sdepth;
+ byte smask;
+ uint dsize;
+ gs_memory_t *mem =
+ (dev->memory == 0 ? &gs_memory_default : dev->memory);
+ byte *row;
+ byte *base;
+ int code;
+ gx_color_index pixel_in = gx_no_color_index;
+ gx_color_index pixel_out;
+ int xi;
+ int sbit;
+ declare_line_accum(str, depth, 0);
+
+ set_dev_target(tdev, dev);
+ width = tdev->width;
+ sdepth = tdev->color_info.depth;
+ smask = (sdepth <= 8 ? (1 << sdepth) - 1 : 0xff);
+ dsize = (width * sdepth + 7) / 8;
+ row = gs_alloc_bytes(mem, dsize, "x_wrap_get_bits");
+ if ( row == 0 )
+ return_error(gs_error_VMerror);
+ code = (*dev_proc(tdev, get_bits))(tdev, y, row, &base);
+ if ( code < 0 )
+ goto gx;
+ for ( sbit = 0, xi = 0; xi < width; sbit += sdepth, ++xi )
+ { const byte *sptr = base + (sbit >> 3);
+ gx_color_index pixel;
+ gx_color_value rgb[3];
+ int i;
+
+ if ( sdepth <= 8 )
+ pixel = (*sptr >> (8 - sdepth - (sbit & 7))) & smask;
+ else
+ { pixel = 0;
+ for ( i = 0; i < depth; i += 8, ++sptr )
+ pixel = (pixel << 8) + *sptr;
+ }
+ if ( pixel != pixel_in )
+ { (*dev_proc(tdev, map_color_rgb))(tdev, pixel, rgb);
+ pixel_in = pixel;
+ pixel_out = (*dev_proc(dev, map_rgb_color))(dev, rgb[0], rgb[1], rgb[2]);
+ }
+ line_accum(pixel_out, depth);
+ }
+ line_accum_store(depth);
+gx: gs_free_object(mem, row, "x_wrap_get_bits");
+ *actual_data = str;
+ return code;
+}
+
+private int
+x_wrap_get_params(gx_device *dev, gs_param_list *plist)
+{ gx_device *tdev;
+ /* We assume that a get_params call has no side effects.... */
+ gx_device_X save_dev;
+ int code;
+
+ set_dev_target(tdev, dev);
+ save_dev = *(gx_device_X *)tdev;
+ if ( tdev->is_open )
+ tdev->color_info = dev->color_info;
+ tdev->dname = dev->dname;
+ code = (*dev_proc(tdev, get_params))(tdev, plist);
+ *(gx_device_X *)tdev = save_dev;
+ return code;
+}
+
+private int
+x_wrap_put_params(gx_device *dev, gs_param_list *plist)
+{ gx_device *tdev;
+ gx_device_color_info cinfo;
+ const char *dname;
+ int rcode, code;
+
+ set_dev_target(tdev, dev);
+ /*
+ * put_params will choke if we simply feed it the output of
+ * get_params; we have to substitute color_info the same way.
+ */
+ cinfo = tdev->color_info;
+ dname = tdev->dname;
+ tdev->color_info = dev->color_info;
+ tdev->dname = dev->dname;
+ rcode = (*dev_proc(tdev, put_params))(tdev, plist);
+ tdev->color_info = cinfo;
+ tdev->dname = dname;
+ if ( rcode < 0 )
+ return rcode;
+ code = get_target_info(dev);
+ return (code < 0 ? code : rcode);
+}
+
+/* Internal procedures */
+
+/* Get the target, creating it if necessary. */
+private int
+get_dev_target(gx_device **ptdev, gx_device *dev)
+{ gx_device *tdev = ((gx_device_forward *)dev)->target;
+
+ if ( tdev == 0 )
+ { /* Create or link to an X device instance. */
+ if ( dev->memory == 0 ) /* static instance */
+ tdev = (gx_device *)&gs_x11_device;
+ else
+ { tdev = (gx_device *)gs_alloc_bytes(dev->memory,
+ (gs_x11_device).params_size,
+ "dev_target");
+ if ( tdev == 0 )
+ return_error(gs_error_VMerror);
+ *(gx_device_X *)tdev = gs_x11_device;
+ tdev->memory = dev->memory;
+ tdev->is_open = false;
+ }
+ gx_device_fill_in_procs(tdev);
+ ((gx_device_forward *)dev)->target = tdev;
+ x_clear_color_cache(dev);
+ }
+ *ptdev = tdev;
+ return 0;
+}
+
+/* Copy parameters back from the target. */
+private int
+get_target_info(gx_device *dev)
+{ gx_device *tdev;
+
+ set_dev_target(tdev, dev);
+
+#define copy(m) dev->m = tdev->m;
+#define copy2(m) copy(m[0]); copy(m[1])
+#define copy4(m) copy2(m); copy(m[2]); copy(m[3])
+
+ copy(width); copy(height);
+ copy2(MediaSize);
+ copy4(ImagingBBox);
+ copy(ImagingBBox_set);
+ copy2(HWResolution);
+ copy2(MarginsHWResolution);
+ copy2(Margins);
+ copy4(HWMargins);
+ if ( dev->color_info.num_components == 3 )
+ copy(color_info);
+
+#undef copy4
+#undef copy2
+#undef copy
+
+ x_clear_color_cache(dev);
+ return 0;
+}
+
+/* Map a fake CMYK or black/white color to a real X color if necessary. */
+private gx_color_index
+x_alt_map_color(gx_device *dev, gx_color_index color)
+{ gx_device *tdev;
+ gx_color_value r, g, b;
+ gx_color_index cindex;
+
+ if ( color == gx_no_color_index )
+ return color;
+ if ( color < 16 )
+ { cindex = ((gx_device_X_wrapper *)dev)->color_cache[color];
+ if ( cindex != gx_no_color_index )
+ return cindex;
+ }
+ set_dev_target(tdev, dev);
+ switch ( dev->color_info.num_components )
+ {
+ case 3: /* RGB, this is the real thing (possibly + alpha) */
+ return color & 0xffffff;
+ case 4: /* CMYK */
+ if ( color & 1 )
+ r = g = b = 0;
+ else
+ { r = (color & 8 ? 0 : gx_max_color_value);
+ g = (color & 4 ? 0 : gx_max_color_value);
+ b = (color & 2 ? 0 : gx_max_color_value);
+ }
+ break;
+ default /*case 1*/:
+ if ( dev->color_info.depth == 1 )
+ { /* 0 = white, 1 = black */
+ r = g = b = (color ? 0 : gx_max_color_value);
+ }
+ else
+ { r = g = b =
+ color * gx_max_color_value / dev->color_info.max_gray;
+ }
+ break;
+ }
+ cindex = (*dev_proc(tdev, map_rgb_color))(tdev, r, g, b);
+ if ( color < 16 )
+ ((gx_device_X_wrapper *)dev)->color_cache[color] = cindex;
+ return cindex;
+}
+
+/* ---------------- CMYK procedures ---------------- */
+
+/* Device procedures */
+private dev_proc_map_rgb_color(x_cmyk_map_rgb_color);
+private dev_proc_map_cmyk_color(x_cmyk_map_cmyk_color);
+
+/* The device descriptor */
+private gx_device_procs x_cmyk_procs = {
+ x_wrap_open,
+ gx_forward_get_initial_matrix,
+ x_forward_sync_output,
+ x_forward_output_page,
+ x_wrap_close,
+ x_cmyk_map_rgb_color,
+ x_wrap_map_color_rgb,
+ x_wrap_fill_rectangle,
+ gx_default_tile_rectangle,
+ x_wrap_copy_mono,
+ x_wrap_copy_color,
+ gx_default_draw_line,
+ x_wrap_get_bits,
+ x_wrap_get_params,
+ x_wrap_put_params,
+ x_cmyk_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ NULL, /* map_rgb_alpha_color */
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ NULL /* copy_alpha */
+};
+
+/* The instance is public. */
+gx_device_X_wrapper far_data gs_x11cmyk_device = {
+ std_device_dci_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk",
+ FAKE_RES*85/10, FAKE_RES*11, /* x and y extent (nominal) */
+ FAKE_RES, FAKE_RES, /* x and y density (nominal) */
+ 4, 4, 1, 1, 2, 2),
+ { 0 }, /* std_procs */
+ 0 /* target */
+};
+
+/* Device procedures */
+
+private gx_color_index
+x_cmyk_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /*
+ * Under normal circumstances, this is never called, but it may be
+ * called from x_wrap_get_bits.
+ */
+ gx_color_value c = gx_max_color_value - r;
+ gx_color_value m = gx_max_color_value - g;
+ gx_color_value y = gx_max_color_value - b;
+ gx_color_value k = (c < m ? min(c, y) : min(m, y));
+
+ return (*dev_proc(dev, map_cmyk_color))(dev, c - k, m - k, y - k, k);
+}
+
+private gx_color_index
+x_cmyk_map_cmyk_color(gx_device *dev,
+ gx_color_value c, gx_color_value m, gx_color_value y,
+ gx_color_value k)
+{ return
+ (gx_color_index)
+ (((c >> (gx_color_value_bits - 4)) & 8) |
+ ((m >> (gx_color_value_bits - 3)) & 4) |
+ ((y >> (gx_color_value_bits - 2)) & 2) |
+ ((k >> (gx_color_value_bits - 1)) & 1));
+}
+
+/* ---------------- Black-and-white procedures ---------------- */
+
+/* The device descriptor */
+private gx_device_procs x_mono_procs = {
+ x_wrap_open,
+ gx_forward_get_initial_matrix,
+ x_forward_sync_output,
+ x_forward_output_page,
+ x_wrap_close,
+ gx_default_b_w_map_rgb_color,
+ x_wrap_map_color_rgb,
+ x_wrap_fill_rectangle,
+ gx_default_tile_rectangle,
+ x_wrap_copy_mono,
+ gx_default_copy_color, /* this is fast for the 1-bit case */
+ gx_default_draw_line,
+ x_wrap_get_bits,
+ x_wrap_get_params,
+ x_wrap_put_params,
+ gx_default_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ NULL, /* map_rgb_alpha_color */
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ NULL /* copy_alpha */
+};
+
+/* The instance is public. */
+gx_device_X_wrapper far_data gs_x11mono_device = {
+ std_device_dci_body(gx_device_X_wrapper, &x_mono_procs, "x11mono",
+ FAKE_RES*85/10, FAKE_RES*11, /* x and y extent (nominal) */
+ FAKE_RES, FAKE_RES, /* x and y density (nominal) */
+ 1, 1, 1, 0, 2, 0),
+ { 0 }, /* std_procs */
+ 0 /* target */
+};
+
+/* ---------------- 2-bit gray-scale procedures ---------------- */
+
+/* The device descriptor */
+private gx_device_procs x_gray2_procs = {
+ x_wrap_open,
+ gx_forward_get_initial_matrix,
+ x_forward_sync_output,
+ x_forward_output_page,
+ x_wrap_close,
+ gx_default_gray_map_rgb_color,
+ x_wrap_map_color_rgb,
+ x_wrap_fill_rectangle,
+ gx_default_tile_rectangle,
+ x_wrap_copy_mono,
+ x_wrap_copy_color,
+ gx_default_draw_line,
+ x_wrap_get_bits,
+ x_wrap_get_params,
+ x_wrap_put_params,
+ gx_default_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ NULL, /* map_rgb_alpha_color */
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ NULL /* copy_alpha */
+};
+
+/* The instance is public. */
+gx_device_X_wrapper far_data gs_x11gray2_device = {
+ std_device_dci_body(gx_device_X_wrapper, &x_gray2_procs, "x11gray2",
+ FAKE_RES*85/10, FAKE_RES*11, /* x and y extent (nominal) */
+ FAKE_RES, FAKE_RES, /* x and y density (nominal) */
+ 1, 2, 3, 0, 4, 0),
+ { 0 }, /* std_procs */
+ 0 /* target */
+};
+
+/* ---------------- Alpha procedures ---------------- */
+
+/* Device procedures */
+private dev_proc_map_color_rgb(x_alpha_map_color_rgb);
+private dev_proc_map_rgb_alpha_color(x_alpha_map_rgb_alpha_color);
+private dev_proc_get_alpha_bits(x_alpha_get_alpha_bits);
+private dev_proc_copy_alpha(x_alpha_copy_alpha);
+
+/* The device descriptor */
+private gx_device_procs x_alpha_procs = {
+ x_wrap_open,
+ gx_forward_get_initial_matrix,
+ x_forward_sync_output,
+ x_forward_output_page,
+ x_wrap_close,
+ gx_forward_map_rgb_color,
+ x_alpha_map_color_rgb,
+ x_wrap_fill_rectangle,
+ gx_default_tile_rectangle,
+ x_wrap_copy_mono,
+ x_forward_copy_color,
+ gx_default_draw_line,
+ x_forward_get_bits,
+ x_wrap_get_params,
+ x_wrap_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ x_alpha_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ x_alpha_get_alpha_bits,
+ /*gx_default_copy_alpha*/ x_alpha_copy_alpha
+};
+
+/* The instance is public. */
+gx_device_X_wrapper far_data gs_x11alpha_device = {
+ std_device_dci_body(gx_device_X_wrapper, &x_alpha_procs, "x11alpha",
+ FAKE_RES*85/10, FAKE_RES*11, /* x and y extent (nominal) */
+ FAKE_RES, FAKE_RES, /* x and y density (nominal) */
+ 3, 32, 255, 255, 256, 256),
+ { 0 }, /* std_procs */
+ 0 /* target */
+};
+
+/* Device procedures */
+
+/* We encode a complemented alpha value in the top 8 bits of the */
+/* device color. */
+private int
+x_alpha_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ return gx_forward_map_color_rgb(dev, color & 0xffffff, prgb);
+}
+private gx_color_index
+x_alpha_map_rgb_alpha_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+ byte abyte = alpha >> (gx_color_value_bits - 8);
+
+ return (abyte == 0 ? 0xff000000 :
+ ((gx_color_index)(abyte ^ 0xff) << 24) + color);
+}
+
+private int
+x_alpha_get_alpha_bits(gx_device *dev, graphics_object_type type)
+{ return 4;
+}
+
+private int
+x_alpha_copy_alpha(gx_device *dev, const unsigned char *base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{ gx_device *tdev;
+ int xi, yi;
+ const byte *row = base;
+ gx_color_index base_color = color & 0xffffff;
+ /* We fake alpha by interpreting it as saturation, i.e., */
+ /* alpha = 0 is white, alpha = 15/15 is the full color. */
+ gx_color_value rgb[3];
+ gx_color_index shades[16];
+ int i;
+
+/**************** PATCH for measuring rasterizer speed ****************/
+/*if ( 1 ) return 0;*/
+
+ set_dev_target(tdev, dev);
+ for ( i = 0; i < 15; ++i )
+ shades[i] = gx_no_color_index;
+ shades[15] = base_color;
+ (*dev_proc(tdev, map_color_rgb))(tdev, base_color, rgb);
+ /* Do the copy operation pixel-by-pixel. */
+ /* For the moment, if the base color has alpha in it, we ignore it. */
+ for ( yi = y; yi < y + h; row += raster, ++yi )
+ { int prev_x = x;
+ gx_color_index prev_color = gx_no_color_index;
+ uint prev_alpha = 0x10; /* not a possible value */
+
+ for ( xi = x; xi < x + w; ++xi )
+ { int sx = sourcex + xi - x;
+ uint alpha2 = row[sx >> 1];
+ uint alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
+ gx_color_index a_color;
+
+ if ( alpha == prev_alpha )
+ continue;
+ prev_alpha = alpha;
+ if ( alpha == 0 )
+ a_color = gx_no_color_index;
+ else
+ while ( (a_color = shades[alpha]) == gx_no_color_index )
+ { /* Map the color now. */
+#define make_shade(v, alpha)\
+ (gx_max_color_value -\
+ ((gx_max_color_value - (v)) * (alpha) / 15))
+ gx_color_value r = make_shade(rgb[0], alpha);
+ gx_color_value g = make_shade(rgb[1], alpha);
+ gx_color_value b = make_shade(rgb[2], alpha);
+#undef make_shade
+ a_color = (*dev_proc(tdev, map_rgb_color))(tdev, r, g, b);
+ if ( a_color != gx_no_color_index )
+ { shades[alpha] = a_color;
+ break;
+ }
+ /* Try a higher saturation. (We know */
+ /* the fully saturated color exists.) */
+ alpha += (16 - alpha) >> 1;
+ }
+ if ( a_color != prev_color )
+ { if ( prev_color != gx_no_color_index )
+ (*dev_proc(tdev, fill_rectangle))(tdev,
+ prev_x, yi, xi - prev_x, 1,
+ prev_color);
+ prev_x = xi;
+ prev_color = a_color;
+ }
+ }
+ if ( prev_color != gx_no_color_index )
+ (*dev_proc(tdev, fill_rectangle))(tdev,
+ prev_x, yi, x + w - prev_x, 1,
+ prev_color);
+ }
+ return 0;
+}
diff --git a/gs/src/gdevxini.c b/gs/src/gdevxini.c
new file mode 100644
index 000000000..57fbe7110
--- /dev/null
+++ b/gs/src/gdevxini.c
@@ -0,0 +1,1001 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevxini.c */
+/* X Windows driver initialization for Ghostscript library */
+#include "math_.h"
+#include "memory_.h"
+#include "x_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevx.h"
+
+extern char *getenv(P1(const char *));
+
+private XtResource resources[] = {
+
+/* (String) casts are here to suppress warnings about discarding `const' */
+#define RINIT(a,b,t,s,o,it,n)\
+ {(String)(a), (String)(b), (String)t, sizeof(s),\
+ XtOffsetOf(gx_device_X, o), (String)it, (n)}
+#define rpix(a,b,o,n)\
+ RINIT(a,b,XtRPixel,Pixel,o,XtRString,(XtPointer)(n))
+#define rdim(a,b,o,n)\
+ RINIT(a,b,XtRDimension,Dimension,o,XtRImmediate,(XtPointer)(n))
+#define rstr(a,b,o,n)\
+ RINIT(a,b,XtRString,String,o,XtRString,(char*)(n))
+#define rint(a,b,o,n)\
+ RINIT(a,b,XtRInt,int,o,XtRImmediate,(XtPointer)(n))
+#define rbool(a,b,o,n)\
+ RINIT(a,b,XtRBoolean,Boolean,o,XtRImmediate,(XtPointer)(n))
+#define rfloat(a,b,o,n)\
+ RINIT(a,b,XtRFloat,float,o,XtRString,(XtPointer)(n))
+
+ rpix(XtNbackground, XtCBackground, background, "XtDefaultBackground"),
+ rpix(XtNborderColor, XtCBorderColor, borderColor, "XtDefaultForeground"),
+ rdim(XtNborderWidth, XtCBorderWidth, borderWidth, 1),
+ rstr("dingbatFonts", "DingbatFonts", dingbatFonts,
+ "ZapfDingbats: -Adobe-ITC Zapf Dingbats-Medium-R-Normal--"),
+ rpix(XtNforeground, XtCForeground, foreground, "XtDefaultForeground"),
+ rstr(XtNgeometry, XtCGeometry, geometry, NULL),
+ rbool("logExternalFonts", "LogExternalFonts", logXFonts, False),
+ rint("maxGrayRamp", "MaxGrayRamp", maxGrayRamp, 128),
+ rint("maxRGBRamp", "MaxRGBRamp", maxRGBRamp, 5),
+ rstr("palette", "Palette", palette, "Color"),
+
+ /*
+ * I had to compress the whitespace out of the default string to
+ * satisfy certain balky compilers.
+ */
+ rstr("regularFonts", "RegularFonts", regularFonts, "\
+AvantGarde-Book:-Adobe-ITC Avant Garde Gothic-Book-R-Normal--\n\
+AvantGarde-BookOblique:-Adobe-ITC Avant Garde Gothic-Book-O-Normal--\n\
+AvantGarde-Demi:-Adobe-ITC Avant Garde Gothic-Demi-R-Normal--\n\
+AvantGarde-DemiOblique:-Adobe-ITC Avant Garde Gothic-Demi-O-Normal--\n\
+Bookman-Demi:-Adobe-ITC Bookman-Demi-R-Normal--\n\
+Bookman-DemiItalic:-Adobe-ITC Bookman-Demi-I-Normal--\n\
+Bookman-Light:-Adobe-ITC Bookman-Light-R-Normal--\n\
+Bookman-LightItalic:-Adobe-ITC Bookman-Light-I-Normal--\n\
+Courier:-Adobe-Courier-Medium-R-Normal--\n\
+Courier-Bold:-Adobe-Courier-Bold-R-Normal--\n\
+Courier-BoldOblique:-Adobe-Courier-Bold-O-Normal--\n\
+Courier-Oblique:-Adobe-Courier-Medium-O-Normal--\n\
+Helvetica:-Adobe-Helvetica-Medium-R-Normal--\n\
+Helvetica-Bold:-Adobe-Helvetica-Bold-R-Normal--\n\
+Helvetica-BoldOblique:-Adobe-Helvetica-Bold-O-Normal--\n\
+Helvetica-Narrow:-Adobe-Helvetica-Medium-R-Narrow--\n\
+Helvetica-Narrow-Bold:-Adobe-Helvetica-Bold-R-Narrow--\n\
+Helvetica-Narrow-BoldOblique:-Adobe-Helvetica-Bold-O-Narrow--\n\
+Helvetica-Narrow-Oblique:-Adobe-Helvetica-Medium-O-Narrow--\n\
+Helvetica-Oblique:-Adobe-Helvetica-Medium-O-Normal--\n\
+NewCenturySchlbk-Bold:-Adobe-New Century Schoolbook-Bold-R-Normal--\n\
+NewCenturySchlbk-BoldItalic:-Adobe-New Century Schoolbook-Bold-I-Normal--\n\
+NewCenturySchlbk-Italic:-Adobe-New Century Schoolbook-Medium-I-Normal--\n\
+NewCenturySchlbk-Roman:-Adobe-New Century Schoolbook-Medium-R-Normal--\n\
+Palatino-Bold:-Adobe-Palatino-Bold-R-Normal--\n\
+Palatino-BoldItalic:-Adobe-Palatino-Bold-I-Normal--\n\
+Palatino-Italic:-Adobe-Palatino-Medium-I-Normal--\n\
+Palatino-Roman:-Adobe-Palatino-Medium-R-Normal--\n\
+Times-Bold:-Adobe-Times-Bold-R-Normal--\n\
+Times-BoldItalic:-Adobe-Times-Bold-I-Normal--\n\
+Times-Italic:-Adobe-Times-Medium-I-Normal--\n\
+Times-Roman:-Adobe-Times-Medium-R-Normal--\n\
+Utopia-Bold:-Adobe-Utopia-Bold-R-Normal--\n\
+Utopia-BoldItalic:-Adobe-Utopia-Bold-I-Normal--\n\
+Utopia-Italic:-Adobe-Utopia-Regular-I-Normal--\n\
+Utopia-Regular:-Adobe-Utopia-Regular-R-Normal--\n\
+ZapfChancery-MediumItalic:-Adobe-ITC Zapf Chancery-Medium-I-Normal--"),
+
+ rstr("symbolFonts", "SymbolFonts", symbolFonts,
+ "Symbol: -Adobe-Symbol-Medium-R-Normal--"),
+
+ rbool("useBackingPixmap", "UseBackingPixmap", useBackingPixmap, True),
+ rbool("useExternalFonts", "UseExternalFonts", useXFonts, True),
+ rbool("useFontExtensions", "UseFontExtensions", useFontExtensions, True),
+ rbool("useScalableFonts", "UseScalableFonts", useScalableFonts, True),
+ rbool("useXPutImage", "UseXPutImage", useXPutImage, True),
+ rbool("useXSetTile", "UseXSetTile", useXSetTile, True),
+ rfloat("xResolution", "Resolution", xResolution, "0.0"),
+ rfloat("yResolution", "Resolution", yResolution, "0.0"),
+
+#undef RINIT
+#undef rpix
+#undef rdim
+#undef rstr
+#undef rint
+#undef rbool
+#undef rfloat
+};
+
+private String
+fallback_resources[] = {
+ (String)"Ghostscript*Background: white",
+ (String)"Ghostscript*Foreground: black",
+ NULL
+};
+
+/* Define constants for orientation from ghostview */
+/* Number represents clockwise rotation of the paper in degrees */
+typedef enum {
+ Portrait = 0, /* Normal portrait orientation */
+ Landscape = 90, /* Normal landscape orientation */
+ Upsidedown = 180, /* Don't think this will be used much */
+ Seascape = 270 /* Landscape rotated the wrong way */
+} orientation;
+
+/* Forward references */
+private int gdev_x_setup_colors(P1(gx_device_X *));
+private void gdev_x_setup_fontmap(P1(gx_device_X *));
+
+/* Catch the alloc error when there is not enough resources for the
+ * backing pixmap. Automatically shut off backing pixmap and let the
+ * user know when this happens.
+ */
+private Boolean alloc_error;
+private XErrorHandler orighandler;
+private XErrorHandler oldhandler;
+
+private int
+x_catch_alloc(Display *dpy, XErrorEvent *err)
+{
+ if (err->error_code == BadAlloc)
+ alloc_error = True;
+ if (alloc_error)
+ return 0;
+ return oldhandler(dpy, err);
+}
+
+int
+x_catch_free_colors(Display *dpy, XErrorEvent *err)
+{
+ if (err->request_code == X_FreeColors) return 0;
+ return orighandler(dpy, err);
+}
+
+/* Open the X device */
+int
+gdev_x_open(register gx_device_X *xdev)
+{
+ XSizeHints sizehints;
+ char *window_id;
+ XEvent event;
+ XVisualInfo xvinfo;
+ int nitems;
+ XtAppContext app_con;
+ Widget toplevel;
+ Display *dpy;
+ XColor xc;
+ int zero = 0;
+ int xid_height, xid_width;
+ int code;
+
+#ifdef DEBUG
+# ifdef have_Xdebug
+ if (gs_debug['X']) {
+ extern int _Xdebug;
+
+ _Xdebug = 1;
+ }
+# endif
+#endif
+ if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
+ char *dispname = getenv("DISPLAY");
+
+ eprintf1("Cannot open X display `%s'.\n",
+ (dispname == NULL ? "(null)" : dispname));
+ return_error(gs_error_ioerror);
+ }
+ xdev->dest = 0;
+ if ((window_id = getenv("GHOSTVIEW"))) {
+ if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
+ &(xdev->win), &(xdev->dest)))) {
+ eprintf("Cannot get Window ID from ghostview.\n");
+ return_error(gs_error_ioerror);
+ }
+ }
+ if (xdev->pwin != (Window)None) {/* pick up the destination window parameters if specified */
+ XWindowAttributes attrib;
+
+ xdev->win = xdev->pwin;
+ if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
+ xdev->scr = attrib.screen;
+ xvinfo.visual = attrib.visual;
+ xdev->cmap = attrib.colormap;
+ xid_width = attrib.width;
+ xid_height = attrib.height;
+ } else {
+ /* No idea why we can't get the attributes, but */
+ /* we shouldn't let it lead to a failure below. */
+ xid_width = xid_height = 0;
+ }
+ }
+ else if (xdev->ghostview) {
+ XWindowAttributes attrib;
+ Atom type;
+ int format;
+ unsigned long nitems, bytes_after;
+ char *buf;
+ Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);
+
+ if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
+ xdev->scr = attrib.screen;
+ xvinfo.visual = attrib.visual;
+ xdev->cmap = attrib.colormap;
+ xdev->width = attrib.width;
+ xdev->height = attrib.height;
+ }
+ /* Delete property if explicit dest is given */
+ if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
+ 256, (xdev->dest != 0), XA_STRING,
+ &type, &format, &nitems, &bytes_after,
+ (unsigned char **)&buf) == 0 &&
+ type == XA_STRING) {
+ int llx, lly, urx, ury;
+ int left_margin = 0, bottom_margin = 0;
+ int right_margin = 0, top_margin = 0;
+
+ /* We declare page_orientation as an int so that we can */
+ /* use an int * to reference it for sscanf; compilers */
+ /* might be tempted to use less space to hold it if */
+ /* it were declared as an orientation. */
+ int /*orientation*/ page_orientation;
+ float xppp, yppp; /* pixels per point */
+ nitems = sscanf(buf,
+ "%ld %d %d %d %d %d %f %f %d %d %d %d",
+ &(xdev->bpixmap), &page_orientation,
+ &llx, &lly, &urx, &ury,
+ &(xdev->x_pixels_per_inch),
+ &(xdev->y_pixels_per_inch),
+ &left_margin, &bottom_margin,
+ &right_margin, &top_margin);
+ if (!(nitems == 8 || nitems == 12)) {
+ eprintf("Cannot get ghostview property.\n");
+ return_error(gs_error_ioerror);
+ }
+ if (xdev->dest && xdev->bpixmap) {
+ eprintf("Both destination and backing pixmap specified.\n");
+ return_error(gs_error_rangecheck);
+ }
+ if (xdev->dest) {
+ Window root;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width, depth;
+
+ if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
+ &width, &height, &border_width, &depth)) {
+ xdev->width = width;
+ xdev->height = height;
+ }
+ }
+ xppp = xdev->x_pixels_per_inch / 72.0;
+ yppp = xdev->y_pixels_per_inch / 72.0;
+ switch (page_orientation) {
+ case Portrait:
+ xdev->initial_matrix.xx = xppp;
+ xdev->initial_matrix.xy = 0.0;
+ xdev->initial_matrix.yx = 0.0;
+ xdev->initial_matrix.yy = -yppp;
+ xdev->initial_matrix.tx = -llx * xppp;
+ xdev->initial_matrix.ty = ury * yppp;
+ break;
+ case Landscape:
+ xdev->initial_matrix.xx = 0.0;
+ xdev->initial_matrix.xy = yppp;
+ xdev->initial_matrix.yx = xppp;
+ xdev->initial_matrix.yy = 0.0;
+ xdev->initial_matrix.tx = -lly * xppp;
+ xdev->initial_matrix.ty = -llx * yppp;
+ break;
+ case Upsidedown:
+ xdev->initial_matrix.xx = -xppp;
+ xdev->initial_matrix.xy = 0.0;
+ xdev->initial_matrix.yx = 0.0;
+ xdev->initial_matrix.yy = yppp;
+ xdev->initial_matrix.tx = urx * xppp;
+ xdev->initial_matrix.ty = -lly * yppp;
+ break;
+ case Seascape:
+ xdev->initial_matrix.xx = 0.0;
+ xdev->initial_matrix.xy = -yppp;
+ xdev->initial_matrix.yx = -xppp;
+ xdev->initial_matrix.yy = 0.0;
+ xdev->initial_matrix.tx = ury * xppp;
+ xdev->initial_matrix.ty = urx * yppp;
+ break;
+ }
+
+ /* The following sets the imageable area according to the */
+ /* bounding box and margins sent by ghostview. */
+ /* This code has been patched many times; its current state */
+ /* is per a recommendation by Tim Theisen on 4/28/95. */
+
+ xdev->ImagingBBox[0] = llx - left_margin;
+ xdev->ImagingBBox[1] = lly - bottom_margin;
+ xdev->ImagingBBox[2] = urx + right_margin;
+ xdev->ImagingBBox[3] = ury + top_margin;
+ xdev->ImagingBBox_set = true;
+
+ } else if (xdev->pwin == (Window)None) {
+ eprintf("Cannot get ghostview property.\n");
+ return_error(gs_error_ioerror);
+ }
+ } else {
+ Screen *scr = DefaultScreenOfDisplay(xdev->dpy);
+
+ xdev->scr = scr;
+ xvinfo.visual = DefaultVisualOfScreen(scr);
+ xdev->cmap = DefaultColormapOfScreen(scr);
+ }
+
+ xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
+ xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
+ if (xdev->vinfo == NULL) {
+ eprintf("Cannot get XVisualInfo.\n");
+ return_error(gs_error_ioerror);
+ }
+
+ /* Buggy X servers may cause a Bad Access on XFreeColors. */
+ orighandler = XSetErrorHandler(x_catch_free_colors);
+
+ /* Get X Resources. Use the toolkit for this. */
+ XtToolkitInitialize();
+ app_con = XtCreateApplicationContext();
+ XtAppSetFallbackResources(app_con, fallback_resources);
+ dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
+ NULL, 0, &zero, NULL);
+ toplevel = XtAppCreateShell(NULL, "Ghostscript",
+ applicationShellWidgetClass, dpy, NULL, 0);
+ XtGetApplicationResources(toplevel, (XtPointer) xdev,
+ resources, XtNumber(resources), NULL, 0);
+
+ /* Reserve foreground and background colors under the regular connection. */
+ xc.pixel = xdev->foreground;
+ XQueryColor(xdev->dpy, xdev->cmap, &xc);
+ XAllocColor(xdev->dpy, xdev->cmap, &xc);
+ xc.pixel = xdev->background;
+ XQueryColor(xdev->dpy, xdev->cmap, &xc);
+ XAllocColor(xdev->dpy, xdev->cmap, &xc);
+
+ code = gdev_x_setup_colors(xdev);
+ if ( code < 0 )
+ { XCloseDisplay(xdev->dpy);
+ return code;
+ }
+ gdev_x_setup_fontmap(xdev);
+
+ if (!xdev->ghostview) {
+ XWMHints wm_hints;
+ XSetWindowAttributes xswa;
+ gx_device *dev = (gx_device *)xdev;
+
+ /* Take care of resolution and paper size. */
+ if (xdev->x_pixels_per_inch == FAKE_RES ||
+ xdev->y_pixels_per_inch == FAKE_RES) {
+ float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
+ float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
+
+ if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
+ float dpi, xdpi, ydpi;
+
+ xdpi = 25.4 * WidthOfScreen(xdev->scr) /
+ WidthMMOfScreen(xdev->scr);
+ ydpi = 25.4 * HeightOfScreen(xdev->scr) /
+ HeightMMOfScreen(xdev->scr);
+ dpi = min(xdpi, ydpi);
+ /*
+ * Some X servers provide very large "virtual screens", and
+ * return the virtual screen size for Width/HeightMM but the
+ * physical size for Width/Height. Attempt to detect and
+ * correct for this now. This is a KLUDGE required because
+ * the X server provides no way to read the screen
+ * resolution directly.
+ */
+ if ( dpi < 30 )
+ dpi = 75; /* arbitrary */
+ else
+ { while (xsize*dpi > WidthOfScreen(xdev->scr)-32 ||
+ ysize*dpi > HeightOfScreen(xdev->scr)-32)
+ dpi *= 0.95;
+ }
+ xdev->x_pixels_per_inch = dpi;
+ xdev->y_pixels_per_inch = dpi;
+ } else {
+ xdev->x_pixels_per_inch = xdev->xResolution;
+ xdev->y_pixels_per_inch = xdev->yResolution;
+ }
+ if (xdev->width > WidthOfScreen(xdev->scr)) {
+ xdev->width = xsize*xdev->x_pixels_per_inch;
+ }
+ if (xdev->height > HeightOfScreen(xdev->scr)) {
+ xdev->height = ysize*xdev->y_pixels_per_inch;
+ }
+ xdev->MediaSize[0] =
+ (float)xdev->width / xdev->x_pixels_per_inch * 72;
+ xdev->MediaSize[1] =
+ (float)xdev->height / xdev->y_pixels_per_inch * 72;
+ }
+
+ sizehints.x = 0;
+ sizehints.y = 0;
+ sizehints.width = xdev->width;
+ sizehints.height = xdev->height;
+ sizehints.flags = 0;
+
+ if (xdev->geometry != NULL) {
+ /*
+ * Note that border_width must be set first. We can't use
+ * scr, because that is a Screen*, and XWMGeometry wants
+ * the screen number.
+ */
+ char gstr[40];
+ int bitmask;
+
+ sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
+ sizehints.height, sizehints.x, sizehints.y);
+ bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
+ xdev->geometry, gstr, xdev->borderWidth,
+ &sizehints,
+ &sizehints.x, &sizehints.y,
+ &sizehints.width, &sizehints.height,
+ &sizehints.win_gravity);
+
+ if (bitmask & (XValue | YValue))
+ sizehints.flags |= USPosition;
+ }
+
+ gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));
+
+ if (xdev->pwin != (Window)None && xid_width != 0 && xid_height != 0) {
+#if 0 /****************/
+
+ /*
+ * The user who originally implemented the WindowID feature
+ * provided the following code to scale the displayed output
+ * to fit in the window. We think this is a bad idea,
+ * since it doesn't track window resizing and is generally
+ * completely at odds with the way Ghostscript treats
+ * window or paper size in all other contexts. We are
+ * leaving the code here in case someone decides that
+ * this really is the behavior they want.
+ */
+
+ /* Scale to fit in the window. */
+ xdev->initial_matrix.xx
+ = xdev->initial_matrix.xx *
+ (float)xid_width / (float)xdev->width;
+ xdev->initial_matrix.yy
+ = xdev->initial_matrix.yy *
+ (float)xid_height / (float)xdev->height;
+
+#endif /****************/
+ xdev->width = xid_width;
+ xdev->height = xid_height;
+ xdev->initial_matrix.ty = xdev->height;
+ } else { /* !xdev->pwin */
+ xswa.event_mask = ExposureMask;
+ xswa.background_pixel = xdev->background;
+ xswa.border_pixel = xdev->borderColor;
+ xswa.colormap = xdev->cmap;
+ xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
+ sizehints.x, sizehints.y, /* upper left */
+ xdev->width, xdev->height,
+ xdev->borderWidth,
+ xdev->vinfo->depth,
+ InputOutput, /* class */
+ xdev->vinfo->visual, /* visual */
+ CWEventMask | CWBackPixel |
+ CWBorderPixel | CWColormap,
+ &xswa);
+ XStoreName(xdev->dpy, xdev->win, "ghostscript");
+ XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
+ wm_hints.flags = InputHint;
+ wm_hints.input = False;
+ XSetWMHints(xdev->dpy, xdev->win, &wm_hints); /* avoid input focus */
+ }
+ }
+
+ /***
+ *** According to Ricard Torres (torres@upf.es), we have to wait until here
+ *** to close the toolkit connection, which we formerly did
+ *** just after the calls on XAllocColor above. I suspect that
+ *** this will cause things to be left dangling if an error occurs
+ *** anywhere in the above code, but I'm willing to let users
+ *** fight over fixing it, since I have no idea what's right.
+ ***/
+
+ /* And close the toolkit connection. */
+ XtDestroyWidget(toplevel);
+ XtCloseDisplay(dpy);
+ XtDestroyApplicationContext(app_con);
+
+ xdev->ht.pixmap = (Pixmap) 0;
+ xdev->ht.id = gx_no_bitmap_id;;
+ xdev->fill_style = FillSolid;
+ xdev->function = GXcopy;
+ xdev->fid = (Font) 0;
+
+ /* Set up a graphics context */
+ xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
+ XSetFunction(xdev->dpy, xdev->gc, GXcopy);
+ XSetLineAttributes(xdev->dpy, xdev->gc, 0,
+ LineSolid, CapButt, JoinMiter);
+
+ gdev_x_clear_window(xdev);
+
+ if (!xdev->ghostview) { /* Make the window appear. */
+ XMapWindow(xdev->dpy, xdev->win);
+
+ /* Before anything else, do a flush and wait for */
+ /* an exposure event. */
+ XFlush(xdev->dpy);
+ if (xdev->pwin == (Window)None) { /* there isn't a next event for existing windows */
+ XNextEvent(xdev->dpy, &event);
+ }
+ /* Now turn off graphics exposure events so they don't queue up */
+ /* indefinitely. Also, since we can't do anything about real */
+ /* Expose events, mask them out. */
+ XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
+ XSelectInput(xdev->dpy, xdev->win, NoEventMask);
+ } else {
+ /* Create an unmapped window, that the window manager will ignore.
+ * This invisible window will be used to receive "next page"
+ * events from ghostview */
+ XSetWindowAttributes attributes;
+
+ attributes.override_redirect = True;
+ xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
+ 0, 0, 1, 1, 0, CopyFromParent,
+ CopyFromParent, CopyFromParent,
+ CWOverrideRedirect, &attributes);
+ xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
+ xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
+ xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
+ }
+
+ xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
+ xdev->vinfo->depth);
+
+ return 0;
+}
+
+/* Allocate the backing pixmap, if any, and clear the window. */
+void
+gdev_x_clear_window(gx_device_X *xdev)
+{
+ if (!xdev->ghostview) {
+ if (xdev->useBackingPixmap) {
+ oldhandler = XSetErrorHandler(x_catch_alloc);
+ alloc_error = False;
+ xdev->bpixmap =
+ XCreatePixmap(xdev->dpy, xdev->win,
+ xdev->width, xdev->height,
+ xdev->vinfo->depth);
+ XSync(xdev->dpy, False); /* Force the error */
+ if (alloc_error) {
+ xdev->useBackingPixmap = False;
+#ifdef DEBUG
+ eprintf("Warning: Failed to allocated backing pixmap.\n");
+#endif
+ if (xdev->bpixmap) {
+ XFreePixmap(xdev->dpy, xdev->bpixmap);
+ xdev->bpixmap = None;
+ XSync(xdev->dpy, False); /* Force the error */
+ }
+ }
+ oldhandler = XSetErrorHandler(oldhandler);
+ } else
+ xdev->bpixmap = (Pixmap) 0;
+ }
+ /* Clear the destination pixmap to avoid initializing with garbage. */
+ if (xdev->dest != (Pixmap) 0) {
+ XSetForeground(xdev->dpy, xdev->gc, xdev->background);
+ XFillRectangle(xdev->dpy, xdev->dest, xdev->gc,
+ 0, 0, xdev->width, xdev->height);
+ } else {
+ xdev->dest = (xdev->bpixmap != (Pixmap) 0 ?
+ xdev->bpixmap : (Pixmap) xdev->win);
+ }
+
+ /* Clear the background pixmap to avoid initializing with garbage. */
+ if (xdev->bpixmap != (Pixmap) 0) {
+ if (!xdev->ghostview)
+ XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
+ XSetForeground(xdev->dpy, xdev->gc, xdev->background);
+ XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
+ 0, 0, xdev->width, xdev->height);
+ }
+ /* Initialize foreground and background colors */
+ xdev->back_color = xdev->background;
+ XSetBackground(xdev->dpy, xdev->gc, xdev->background);
+ xdev->fore_color = xdev->background;
+ XSetForeground(xdev->dpy, xdev->gc, xdev->background);
+ xdev->colors_or = xdev->colors_and = xdev->background;
+}
+
+/* ------ Initialize color mapping ------ */
+
+#if HaveStdCMap
+/* Get the Standard colormap if available. */
+private XStandardColormap *
+x_get_std_cmap(gx_device_X *xdev, Atom prop)
+{
+ int i;
+ XStandardColormap *scmap, *sp;
+ int nitems;
+
+ if (XGetRGBColormaps(xdev->dpy, RootWindowOfScreen(xdev->scr),
+ &scmap, &nitems, prop))
+ for (i = 0, sp = scmap; i < nitems; i++, sp++)
+ if (xdev->cmap == sp->colormap)
+ return sp;
+
+ return NULL;
+}
+#endif
+
+/* Allocate the dynamic color table, if needed and possible. */
+private void
+alloc_dynamic_colors(gx_device_X *xdev, int reserved_colors)
+{
+ /* Allocate space for dynamic colors hash table */
+ xdev->dynamic_colors =
+ (x11color*(*)[]) gs_malloc(sizeof(x11color *), xdev->num_rgb,
+ "x11_dynamic_colors");
+
+ if (xdev->dynamic_colors) {
+ int i;
+ xdev->dynamic_size = xdev->num_rgb;
+ for (i = 0; i < xdev->num_rgb; i++) {
+ (*xdev->dynamic_colors)[i] = NULL;
+ }
+ xdev->max_dynamic_colors = min(256, xdev->vinfo->colormap_size -
+ reserved_colors);
+ }
+}
+
+/* Free a partially filled color ramp. */
+private void
+free_ramp(gx_device_X *xdev, int num_used, int size)
+{ if ( num_used - 1 > 0 )
+ { XFreeColors(xdev->dpy, xdev->cmap,
+ xdev->dither_colors + 1,
+ num_used - 1, 0);
+ }
+ gs_free((char *)xdev->dither_colors, sizeof(x_pixel), size,
+ "x11_setup_colors");
+ xdev->dither_colors = NULL;
+}
+
+/* Allocate and fill in a color cube or ramp. */
+/* Return true if the operation succeeded. */
+private bool
+setup_cube(gx_device_X *xdev, int ramp_size, bool colors)
+{ int step, num_entries;
+ int max_rgb = ramp_size - 1;
+ int index;
+
+ if ( colors )
+ { num_entries = ramp_size * ramp_size * ramp_size;
+ step = 1; /* all colors */
+ }
+ else
+ { num_entries = ramp_size;
+ step = (ramp_size + 1) * ramp_size + 1; /* gray only */
+ }
+
+ xdev->dither_colors =
+ (x_pixel *)gs_malloc(sizeof(x_pixel), num_entries,
+ "gdevx setup_cube");
+ if ( xdev->dither_colors == NULL )
+ return false;
+
+ xdev->dither_colors[0] = xdev->foreground;
+ xdev->dither_colors[num_entries - 1] = xdev->background;
+ for ( index = 1; index < num_entries - 1; index++ )
+ { int rgb_index = index * step;
+ int r = rgb_index / (ramp_size * ramp_size);
+ int g = (rgb_index / ramp_size) % ramp_size;
+ int b = rgb_index % ramp_size;
+ XColor xc;
+
+ xc.red = (X_max_color_value * r / max_rgb) & xdev->color_mask;
+ xc.green = (X_max_color_value * g / max_rgb) & xdev->color_mask;
+ xc.blue = (X_max_color_value * b / max_rgb) & xdev->color_mask;
+ if ( XAllocColor(xdev->dpy, xdev->cmap, &xc) )
+ { xdev->dither_colors[index] = xc.pixel;
+ }
+ else
+ { free_ramp(xdev, index, num_entries);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Setup color mapping. */
+private int
+gdev_x_setup_colors(gx_device_X *xdev)
+{
+ char palette;
+
+ palette = ((xdev->vinfo->class != StaticGray) &&
+ (xdev->vinfo->class != GrayScale) ? 'C' : /* Color */
+ (xdev->vinfo->colormap_size > 2) ? 'G' : /* GrayScale */
+ 'M'); /* MonoChrome */
+ if (xdev->ghostview) {
+ Atom gv_colors = XInternAtom(xdev->dpy, "GHOSTVIEW_COLORS", False);
+ Atom type;
+ int format;
+ unsigned long nitems, bytes_after;
+ char *buf;
+
+ /* Delete property if explicit dest is given */
+ if (XGetWindowProperty(xdev->dpy, xdev->win, gv_colors, 0,
+ 256, (xdev->dest != 0), XA_STRING,
+ &type, &format, &nitems, &bytes_after,
+ (unsigned char **)&buf) == 0 &&
+ type == XA_STRING) {
+ nitems = sscanf(buf, "%*s %ld %ld", &(xdev->foreground),
+ &(xdev->background));
+ if (nitems != 2 || (*buf != 'M' && *buf != 'G' && *buf != 'C')) {
+ eprintf("Malformed ghostview color property.\n");
+ return_error(gs_error_rangecheck);
+ }
+ palette = max(palette, *buf);
+ }
+ } else {
+ if (xdev->palette[0] == 'c') xdev->palette[0] = 'C';
+ else if (xdev->palette[0] == 'g') xdev->palette[0] = 'G';
+ else if (xdev->palette[0] == 'm') xdev->palette[0] = 'M';
+ palette = max(palette, xdev->palette[0]);
+ }
+
+ /* set up color mappings here */
+ xdev->color_mask = X_max_color_value -
+ (X_max_color_value >> xdev->vinfo->bits_per_rgb);
+ xdev->num_rgb = 1 << xdev->vinfo->bits_per_rgb;
+
+#if HaveStdCMap
+ xdev->std_cmap = NULL;
+#endif
+ xdev->dither_colors = NULL;
+ xdev->dynamic_colors = NULL;
+ xdev->dynamic_size = 0;
+ xdev->dynamic_allocs = 0;
+ xdev->color_info.depth = xdev->vinfo->depth;
+
+ if (palette == 'C') {
+ xdev->color_info.num_components = 3;
+ xdev->color_info.max_gray =
+ xdev->color_info.max_color = xdev->num_rgb - 1;
+#if HaveStdCMap
+ /* Get a standard color map if available */
+ if (xdev->vinfo->visual == DefaultVisualOfScreen(xdev->scr)) {
+ xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_DEFAULT_MAP);
+ } else {
+ xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_BEST_MAP);
+ }
+ if (xdev->std_cmap) {
+ xdev->color_info.dither_grays =
+ xdev->color_info.dither_colors =
+ min(xdev->std_cmap->red_max,
+ min(xdev->std_cmap->green_max,
+ xdev->std_cmap->blue_max)) + 1;
+ } else
+#endif
+ /* Otherwise set up a rgb cube of our own */
+ /* The color cube is limited to about 1/2 of the available */
+ /* colormap, the user specified maxRGBRamp (usually 5), */
+ /* or the number of representable colors */
+#define cube(r) (r*r*r)
+#define cbrt(r) pow(r, 1.0/3.0)
+ {
+ int ramp_size =
+ min((int)cbrt((double)xdev->vinfo->colormap_size / 2.0),
+ min(xdev->maxRGBRamp, xdev->num_rgb));
+
+ while (!xdev->dither_colors && ramp_size >= 2) {
+ xdev->color_info.dither_grays =
+ xdev->color_info.dither_colors = ramp_size;
+ if ( !setup_cube(xdev, ramp_size, true) ) {
+#ifdef DEBUG
+ eprintf3("Warning: failed to allocate %dx%dx%d RGB cube.\n",
+ ramp_size, ramp_size, ramp_size);
+#endif
+ ramp_size--;
+ continue;
+ }
+ }
+
+ if (!xdev->dither_colors) {
+ goto grayscale;
+ }
+ }
+
+ /* Allocate the dynamic color table. */
+ alloc_dynamic_colors(xdev, cube(xdev->color_info.dither_colors));
+
+#undef cube
+#undef cbrt
+ } else if (palette == 'G') {
+grayscale:
+ xdev->color_info.num_components = 1;
+ xdev->color_info.max_gray = xdev->num_rgb - 1;
+#if HaveStdCMap
+ /* Get a standard color map if available */
+ xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_GRAY_MAP);
+ if (xdev->std_cmap != 0) {
+ xdev->color_info.dither_grays = xdev->std_cmap->red_max +
+ xdev->std_cmap->green_max +
+ xdev->std_cmap->blue_max + 1;
+ } else
+#endif
+ /* Otherwise set up a gray ramp of our own */
+ /* The gray ramp is limited to about 1/2 of the available */
+ /* colormap, the user specified maxGrayRamp (usually 128), */
+ /* or the number of representable grays */
+ {
+ int ramp_size = min(xdev->vinfo->colormap_size / 2,
+ min(xdev->maxGrayRamp, xdev->num_rgb));
+
+ while (!xdev->dither_colors && ramp_size >= 3) {
+ xdev->color_info.dither_grays = ramp_size;
+ if ( !setup_cube(xdev, ramp_size, false) )
+ {
+#ifdef DEBUG
+ eprintf1("Warning: failed to allocate %d level gray ramp.\n",
+ ramp_size);
+#endif
+ ramp_size /= 2;
+ continue;
+ }
+ }
+ if (!xdev->dither_colors) {
+ goto monochrome;
+ }
+ }
+
+ /* Allocate the dynamic color table. */
+ alloc_dynamic_colors(xdev, xdev->color_info.dither_grays);
+
+ } else if (palette == 'M') {
+monochrome:
+ xdev->color_info.num_components = 1;
+ xdev->color_info.max_gray = 1;
+ xdev->color_info.dither_grays = 2;
+ } else {
+ eprintf1("Unknown palette: %s\n", xdev->palette);
+ return_error(gs_error_rangecheck);
+ }
+ return 0;
+}
+
+/* ------ Initialize font mapping ------ */
+
+/* Extract the PostScript font name from the font map resource. */
+private const char *
+get_ps_name(const char **cpp, int *len)
+{
+ const char *ret;
+ *len = 0;
+ /* skip over whitespace and newlines */
+ while (**cpp == ' ' || **cpp == '\t' || **cpp == '\n') {
+ (*cpp)++;
+ }
+ /* return font name up to ":", whitespace, or end of string */
+ if (**cpp == ':' || **cpp == '\0') {
+ return NULL;
+ }
+ ret = *cpp;
+ while (**cpp != ':' &&
+ **cpp != ' ' && **cpp != '\t' && **cpp != '\n' &&
+ **cpp != '\0') {
+ (*cpp)++;
+ (*len)++;
+ }
+ return ret;
+}
+
+/* Extract the X11 font name from the font map resource. */
+private const char *
+get_x11_name(const char **cpp, int *len)
+{
+ const char *ret;
+ int dashes = 0;
+ *len = 0;
+ /* skip over whitespace and the colon */
+ while (**cpp == ' ' || **cpp == '\t' ||
+ **cpp == ':') {
+ (*cpp)++;
+ }
+ /* return font name up to end of line or string */
+ if (**cpp == '\0' || **cpp == '\n') {
+ return NULL;
+ }
+ ret = *cpp;
+ while (dashes != 7 &&
+ **cpp != '\0' && **cpp != '\n') {
+ if (**cpp == '-') dashes++;
+ (*cpp)++;
+ (*len)++;
+ }
+ while (**cpp != '\0' && **cpp != '\n') {
+ (*cpp)++;
+ }
+ if (dashes != 7) return NULL;
+ return ret;
+}
+
+/* Scan one resource and build font map records. */
+private void
+scan_font_resource(const char *resource, x11fontmap **pmaps)
+{
+ const char *ps_name;
+ const char *x11_name;
+ int ps_name_len;
+ int x11_name_len;
+ x11fontmap *font;
+ const char *cp = resource;
+
+ while ((ps_name = get_ps_name(&cp, &ps_name_len)) != 0) {
+ x11_name = get_x11_name(&cp, &x11_name_len);
+ if (x11_name) {
+ font = (x11fontmap *)gs_malloc(sizeof(x11fontmap), 1,
+ "x11_setup_fontmap");
+ if (font == NULL) continue;
+ font->ps_name = (char *)gs_malloc(sizeof(char), ps_name_len+1,
+ "x11_setup_fontmap");
+ if (font->ps_name == NULL) {
+ gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
+ continue;
+ }
+ strncpy(font->ps_name, ps_name, ps_name_len);
+ font->ps_name[ps_name_len] = '\0';
+ font->x11_name = (char *)gs_malloc(sizeof(char), x11_name_len,
+ "x11_setup_fontmap");
+ if (font->x11_name == NULL) {
+ gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
+ "x11_font_psname");
+ gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
+ continue;
+ }
+ strncpy(font->x11_name, x11_name, x11_name_len-1);
+ font->x11_name[x11_name_len-1] = '\0';
+ font->std_names = NULL;
+ font->iso_names = NULL;
+ font->std_count = -1;
+ font->iso_count = -1;
+ font->next = *pmaps;
+ *pmaps = font;
+ }
+ }
+}
+
+/* Scan all the font resources and set up the maps. */
+private void
+gdev_x_setup_fontmap(gx_device_X *xdev)
+{
+ if (!xdev->useXFonts) return; /* If no external fonts, don't bother */
+
+ scan_font_resource(xdev->regularFonts, &xdev->regular_fonts);
+ scan_font_resource(xdev->symbolFonts, &xdev->symbol_fonts);
+ scan_font_resource(xdev->dingbatFonts, &xdev->dingbat_fonts);
+}
diff --git a/gs/src/gdevxxf.c b/gs/src/gdevxxf.c
new file mode 100644
index 000000000..627142b59
--- /dev/null
+++ b/gs/src/gdevxxf.c
@@ -0,0 +1,465 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevxxf.c */
+/* External font (xfont) implementation for X11. */
+#include "math_.h"
+#include "memory_.h"
+#include "x_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gdevx.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gserrors.h"
+#include "gxxfont.h"
+
+/* Define the smallest point size that we trust X to render reasonably well. */
+#define min_X_font_size 6
+/* Define the largest point size where X will do a better job than we can. */
+#define max_X_font_size 35
+
+extern gx_device_X gs_x11_device;
+
+extern const byte gs_map_std_to_iso[256];
+extern const byte gs_map_iso_to_std[256];
+
+/* Declare the xfont procedures */
+private xfont_proc_lookup_font(x_lookup_font);
+private xfont_proc_char_xglyph(x_char_xglyph);
+private xfont_proc_char_metrics(x_char_metrics);
+private xfont_proc_render_char(x_render_char);
+private xfont_proc_release(x_release);
+private gx_xfont_procs x_xfont_procs = {
+ x_lookup_font,
+ x_char_xglyph,
+ x_char_metrics,
+ x_render_char,
+ x_release
+};
+
+/* Return the xfont procedure record. */
+gx_xfont_procs *
+x_get_xfont_procs(gx_device *dev)
+{
+ return &x_xfont_procs;
+}
+
+/* Define a X11 xfont. */
+typedef struct x_xfont_s x_xfont;
+struct x_xfont_s {
+ gx_xfont_common common;
+ gx_device_X *xdev;
+ XFontStruct *font;
+ int encoding_index;
+ int My;
+ int angle;
+};
+gs_private_st_dev_ptrs1(st_x_xfont, x_xfont, "x_xfont",
+ x_xfont_enum_ptrs, x_xfont_reloc_ptrs, xdev);
+
+/* Look up a font. */
+private gx_xfont *
+x_lookup_font(gx_device *dev, const byte *fname, uint len,
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,
+ gs_memory_t *mem)
+{
+ gx_device_X *xdev = (gx_device_X *) dev;
+ x_xfont *xxf;
+ char x11template[256];
+ char *x11fontname = NULL;
+ XFontStruct *x11font;
+ x11fontmap *fmp;
+ int i;
+ double height;
+ int size;
+ int xwidth, xheight, angle;
+ Boolean My;
+ Boolean scalable_font = False;
+
+ if (!xdev->useXFonts) return NULL;
+
+ if (pmat->xy == 0 && pmat->yx == 0) {
+ xwidth = fabs(pmat->xx * 1000) + 0.5;
+ xheight = fabs(pmat->yy * 1000) + 0.5;
+ height = fabs(pmat->yy * 1000);
+ if (pmat->xx > 0) angle = 0;
+ else angle = 180;
+ My = (pmat->xx > 0 && pmat->yy > 0) || (pmat->xx < 0 && pmat->yy < 0);
+ } else if (pmat->xx == 0 && pmat->yy == 0) {
+ xwidth = fabs(pmat->xy * 1000) + 0.5;
+ xheight = fabs(pmat->yx * 1000) + 0.5;
+ height = fabs(pmat->yx * 1000);
+ if (pmat->yx < 0) angle = 90;
+ else angle = 270;
+ My = (pmat->yx > 0 && pmat->xy < 0) || (pmat->yx < 0 && pmat->xy > 0);
+ } else {
+ return NULL;
+ }
+
+ /* Don't do very small fonts, where font metrics are way off */
+ /* due to rounding and the server does a very bad job of scaling, */
+ /* or very large fonts, where we can do just as good a job and */
+ /* the server may lock up the entire window system while rasterizing */
+ /* the whole font. */
+ if ( xwidth < min_X_font_size || xwidth > max_X_font_size ||
+ xheight < min_X_font_size || xheight > max_X_font_size
+ )
+ return NULL;
+
+ if (!xdev->useFontExtensions && (My || angle != 0)) return NULL;
+
+ if (encoding_index == 0 || encoding_index == 1) {
+ int tried_other_encoding = 0;
+
+ fmp = xdev->regular_fonts;
+ while (fmp) {
+ if (len == strlen(fmp->ps_name) &&
+ strncmp(fmp->ps_name, (const char *)fname, len) == 0) break;
+ fmp = fmp->next;
+ }
+ if (fmp == NULL) return NULL;
+ while (True) {
+ if (encoding_index == 0) {
+ if (fmp->std_count == -1) {
+ sprintf(x11template, "%s%s", fmp->x11_name,
+ "-*-*-*-*-*-*-Adobe-fontspecific");
+ fmp->std_names = XListFonts(xdev->dpy, x11template, 32,
+ &fmp->std_count);
+ }
+ if (fmp->std_count) {
+ for (i = 0; i < fmp->std_count; i++) {
+ char *szp = fmp->std_names[i] + strlen(fmp->x11_name)+1;
+
+ size = 0;
+ while (*szp >= '0' && *szp <= '9')
+ size = size * 10 + *szp++ - '0';
+ if (size == 0) {
+ scalable_font = True;
+ continue;
+ }
+ if (size == xheight) {
+ x11fontname = fmp->std_names[i];
+ break;
+ }
+ }
+ if (!x11fontname && scalable_font &&
+ xdev->useScalableFonts) {
+ sprintf(x11template, "%s-%d%s", fmp->x11_name,
+ xheight, "-0-0-0-*-0-Adobe-fontspecific");
+ x11fontname = x11template;
+ }
+ if (x11fontname) break;
+ }
+ if (tried_other_encoding) return NULL;
+ encoding_index = 1;
+ tried_other_encoding = 1;
+ } else if (encoding_index == 1) {
+ if (fmp->iso_count == -1) {
+ sprintf(x11template, "%s%s", fmp->x11_name,
+ "-*-*-*-*-*-*-ISO8859-1");
+ fmp->iso_names = XListFonts(xdev->dpy, x11template, 32,
+ &fmp->iso_count);
+ }
+ if (fmp->iso_count) {
+ for (i = 0; i < fmp->iso_count; i++) {
+ char *szp = fmp->iso_names[i] + strlen(fmp->x11_name)+1;
+
+ size = 0;
+ while (*szp >= '0' && *szp <= '9')
+ size = size * 10 + *szp++ - '0';
+ if (size == 0) {
+ scalable_font = True;
+ continue;
+ }
+ if (size == xheight) {
+ x11fontname = fmp->iso_names[i];
+ break;
+ }
+ }
+ if (!x11fontname && scalable_font &&
+ xdev->useScalableFonts) {
+ sprintf(x11template, "%s-%d%s", fmp->x11_name,
+ xheight, "-0-0-0-*-0-ISO8859-1");
+ x11fontname = x11template;
+ }
+ if (x11fontname) break;
+ }
+ if (tried_other_encoding) return NULL;
+ encoding_index = 0;
+ tried_other_encoding = 1;
+ }
+ }
+ } else if (encoding_index == 2 || encoding_index == 3) {
+ if (encoding_index == 2) fmp = xdev->symbol_fonts;
+ if (encoding_index == 3) fmp = xdev->dingbat_fonts;
+ while (fmp) {
+ if (len == strlen(fmp->ps_name) &&
+ strncmp(fmp->ps_name, (const char *)fname, len) == 0)
+ break;
+ fmp = fmp->next;
+ }
+ if (fmp == NULL) return NULL;
+ if (fmp->std_count == -1) {
+ sprintf(x11template, "%s%s", fmp->x11_name,
+ "-*-*-*-*-*-*-Adobe-fontspecific");
+ fmp->std_names = XListFonts(xdev->dpy, x11template, 32,
+ &fmp->std_count);
+ }
+ if (fmp->std_count) {
+ for (i = 0; i < fmp->std_count; i++) {
+ char *szp = fmp->std_names[i] + strlen(fmp->x11_name)+1;
+
+ size = 0;
+ while (*szp >= '0' && *szp <= '9')
+ size = size * 10 + *szp++ - '0';
+ if (size == 0) {
+ scalable_font = True;
+ continue;
+ }
+ if (size == xheight) {
+ x11fontname = fmp->std_names[i];
+ break;
+ }
+ }
+ if (!x11fontname && scalable_font && xdev->useScalableFonts) {
+ sprintf(x11template, "%s-%d%s", fmp->x11_name, xheight,
+ "-0-0-0-*-0-Adobe-fontspecific");
+ x11fontname = x11template;
+ }
+ if (!x11fontname) return NULL;
+ } else {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+
+ if (xwidth != xheight || angle != 0 || My) {
+ if (!xdev->useScalableFonts || !scalable_font) return NULL;
+ sprintf(x11template, "%s%s+%d-%d+%d%s",
+ fmp->x11_name, My ? "+My" : "",
+ angle*64 , xheight, xwidth,
+ encoding_index == 1 ? "-0-0-0-*-0-ISO8859-1" :
+ "-0-0-0-*-0-Adobe-fontspecific");
+ x11fontname = x11template;
+ }
+
+ x11font = XLoadQueryFont(xdev->dpy, x11fontname);
+ if (x11font == NULL)
+ return NULL;
+ /* Don't bother with 16-bit or 2 byte fonts yet */
+ if (x11font->min_byte1 || x11font->max_byte1) {
+ XFreeFont(xdev->dpy, x11font);
+ return NULL;
+ }
+ xxf = gs_alloc_struct(mem, x_xfont, &st_x_xfont, "x_lookup_font");
+ if (xxf == NULL)
+ return NULL;
+ xxf->common.procs = &x_xfont_procs;
+ xxf->xdev = xdev;
+ xxf->font = x11font;
+ xxf->encoding_index = encoding_index;
+ xxf->My = My ? -1 : 1;
+ xxf->angle = angle;
+ if (xdev->logXFonts) {
+ fprintf(stdout, "Using %s\n", x11fontname);
+ fprintf(stdout, " for %s at %g pixels.\n", fmp->ps_name, height);
+ fflush(stdout);
+ }
+ return (gx_xfont *) xxf;
+}
+
+/* Convert a character name or index to an xglyph code. */
+private gx_xglyph
+x_char_xglyph(gx_xfont *xf, gs_char chr, int encoding_index,
+ gs_glyph glyph, gs_proc_glyph_name_t glyph_name_proc)
+{
+ x_xfont *xxf = (x_xfont *) xf;
+
+ if (chr == gs_no_char)
+ return gx_no_xglyph; /* can't look up names yet */
+ if (encoding_index != xxf->encoding_index) {
+ if (encoding_index == 0 && xxf->encoding_index == 1)
+ chr = gs_map_std_to_iso[chr];
+ else if (encoding_index == 1 && xxf->encoding_index == 0)
+ chr = gs_map_iso_to_std[chr];
+ else
+ return gx_no_xglyph;
+ if (chr == 0) return gx_no_xglyph;
+ }
+ if (chr < xxf->font->min_char_or_byte2 ||
+ chr > xxf->font->max_char_or_byte2)
+ return gx_no_xglyph;
+ if (xxf->font->per_char) {
+ int i = chr - xxf->font->min_char_or_byte2;
+ XCharStruct *xc = &(xxf->font->per_char[i]);
+
+ if ((xc->lbearing == 0) && (xc->rbearing == 0) &&
+ (xc->ascent == 0) && (xc->descent == 0))
+ return gx_no_xglyph;
+ }
+ return (gx_xglyph) chr;
+}
+
+/* Get the metrics for a character. */
+private int
+x_char_metrics(gx_xfont *xf, gx_xglyph xg, int wmode,
+ gs_point *pwidth, gs_int_rect *pbbox)
+{
+ x_xfont *xxf = (x_xfont *) xf;
+
+ if (wmode != 0)
+ return gs_error_undefined;
+ if (xxf->font->per_char == NULL) {
+ if (xxf->angle == 0) {
+ pwidth->x = xxf->font->max_bounds.width;
+ pwidth->y = 0;
+ } else if (xxf->angle == 90) {
+ pwidth->x = 0;
+ pwidth->y = -xxf->My * xxf->font->max_bounds.width;
+ } else if (xxf->angle == 180) {
+ pwidth->x = -xxf->font->max_bounds.width;
+ pwidth->y = 0;
+ } else if (xxf->angle == 270) {
+ pwidth->x = 0;
+ pwidth->y = xxf->My * xxf->font->max_bounds.width;
+ }
+ pbbox->p.x = xxf->font->max_bounds.lbearing;
+ pbbox->q.x = xxf->font->max_bounds.rbearing;
+ pbbox->p.y = -xxf->font->max_bounds.ascent;
+ pbbox->q.y = xxf->font->max_bounds.descent;
+ } else {
+ int i = xg - xxf->font->min_char_or_byte2;
+
+ if (xxf->angle == 0) {
+ pwidth->x = xxf->font->per_char[i].width;
+ pwidth->y = 0;
+ } else if (xxf->angle == 90) {
+ pwidth->x = 0;
+ pwidth->y = -xxf->My * xxf->font->per_char[i].width;
+ } else if (xxf->angle == 180) {
+ pwidth->x = -xxf->font->per_char[i].width;
+ pwidth->y = 0;
+ } else if (xxf->angle == 270) {
+ pwidth->x = 0;
+ pwidth->y = xxf->My * xxf->font->per_char[i].width;
+ }
+ pbbox->p.x = xxf->font->per_char[i].lbearing;
+ pbbox->q.x = xxf->font->per_char[i].rbearing;
+ pbbox->p.y = -xxf->font->per_char[i].ascent;
+ pbbox->q.y = xxf->font->per_char[i].descent;
+ }
+ return 0;
+}
+
+/* Render a character. */
+private int
+x_render_char(gx_xfont *xf, gx_xglyph xg, gx_device *dev,
+ int xo, int yo, gx_color_index color, int required)
+{
+ x_xfont *xxf = (x_xfont *) xf;
+ gx_device_X *xdev = xxf->xdev;
+ char chr = (char)xg;
+ gs_point wxy;
+ gs_int_rect bbox;
+ int x, y, w, h;
+ int code;
+
+ if (dev->dname == gs_x11_device.dname) {
+ code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
+ if (code < 0) return code;
+ set_fill_style(FillSolid);
+ set_fore_color(color);
+ set_function(GXcopy);
+ set_font(xxf->font->fid);
+ XDrawString(xdev->dpy, xdev->dest, xdev->gc, xo, yo, &chr, 1);
+ if (xdev->bpixmap != (Pixmap) 0) {
+ x = xo + bbox.p.x;
+ y = yo + bbox.p.y;
+ w = bbox.q.x - bbox.p.x;
+ h = bbox.q.y - bbox.p.y;
+ fit_fill(dev, x, y, w, h);
+ x_update_add(dev, x, y, w, h);
+ }
+ return 0;
+ } else if (!required)
+ return -1; /* too hard */
+ else {
+ /* Display on an intermediate bitmap, then copy the bits. */
+ int wbm, raster;
+ int i;
+ XImage *xim;
+ Pixmap xpm;
+ GC fgc;
+ byte *bits;
+
+ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
+
+ code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
+ if (code < 0) return code;
+ w = bbox.q.x - bbox.p.x;
+ h = bbox.q.y - bbox.p.y;
+ wbm = round_up(w, align_bitmap_mod * 8);
+ raster = wbm >> 3;
+ bits = (byte *) gs_malloc(h, raster, "x_render_char");
+ if (bits == 0) return gs_error_limitcheck;
+ xpm = XCreatePixmap(xdev->dpy, xdev->win, w, h, 1);
+ fgc = XCreateGC(xdev->dpy, xpm, None, NULL);
+ XSetForeground(xdev->dpy, fgc, 0);
+ XFillRectangle(xdev->dpy, xpm, fgc, 0, 0, w, h);
+ XSetForeground(xdev->dpy, fgc, 1);
+ XSetFont(xdev->dpy, fgc, xxf->font->fid);
+ XDrawString(xdev->dpy, xpm, fgc, -bbox.p.x, -bbox.p.y, &chr, 1);
+ xim = XGetImage(xdev->dpy, xpm, 0, 0, w, h, 1, ZPixmap);
+ i = 0;
+ for (y = 0; y < h; y++) {
+ char b = 0;
+
+ for (x = 0; x < wbm; x++) {
+ b = b << 1;
+ if (x < w)
+ b += XGetPixel(xim, x, y);
+ if ((x & 7) == 7)
+ bits[i++] = b;
+ }
+ }
+ code = (*copy_mono) (dev, bits, 0, raster, gx_no_bitmap_id,
+ xo + bbox.p.x, yo + bbox.p.y, w, h,
+ gx_no_color_index, color);
+ gs_free((char *)bits, h, raster, "x_render_char");
+ XFreePixmap(xdev->dpy, xpm);
+ XFreeGC(xdev->dpy, fgc);
+ XDestroyImage(xim);
+ return (code < 0 ? code : 0);
+ }
+}
+
+/* Release an xfont. */
+private int
+x_release(gx_xfont *xf, gs_memory_t *mem)
+{
+#if 0
+ /* The device may not be open. Cannot reliably free the font. */
+ x_xfont *xxf = (x_xfont *) xf;
+ XFreeFont(xxf->xdev->dpy, xxf->font);
+#endif
+ if (mem != NULL)
+ gs_free_object(mem, xf, "x_release");
+ return 0;
+}
diff --git a/gs/src/genarch.c b/gs/src/genarch.c
new file mode 100644
index 000000000..e3d4344e2
--- /dev/null
+++ b/gs/src/genarch.c
@@ -0,0 +1,122 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* genarch.c */
+/* Generate a header file (arch.h) with parameters */
+/* reflecting the machine architecture and compiler characteristics. */
+
+#include "stdpre.h"
+#include <stdio.h>
+
+/* We should write the result on stdout, but the original Turbo C 'make' */
+/* can't handle output redirection (sigh). */
+
+main(int argc, char *argv[])
+{ char *fname = argv[1];
+ long one = 1;
+#define ffs_strlen 16
+ char *ffs = "ffffffffffffffff";
+ struct { char c; short s; } ss;
+ struct { char c; int i; } si;
+ struct { char c; long l; } sl;
+ struct { char c; char *p; } sp;
+ struct { char c; float f; } sf;
+ struct { char c; double d; } sd;
+ static int log2s[17] = {0,0,1,0,2,0,0,0,3,0,0,0,0,0,0,0,4};
+ long lm1 = -1;
+ long lr1 = lm1 >> 1, lr2 = lm1 >> 2;
+ unsigned long um1 = ~(unsigned long)0;
+ int im1 = -1;
+ int ir1 = im1 >> 1, ir2 = im1 >> 2;
+ union { long l; char *p; } pl0, pl1;
+ int ars;
+ int lwidth = size_of(long) * 8;
+ union { float f; int i; long l; } f0, f1, fm1;
+ FILE *f = fopen(fname, "w");
+ if ( f == NULL )
+ { fprintf(stderr, "genarch.c: can't open %s for writing\n", fname);
+ return exit_FAILED;
+ }
+ fprintf(f, "/* Parameters derived from machine and compiler architecture */\n");
+#define S(str) fprintf(f, "\n\t%s\n\n", str)
+
+S("/* ---------------- Scalar alignments ---------------- */");
+
+#define offset(s, e) (int)((char *)&s.e - (char *)&s)
+ fprintf(f, "#define arch_align_short_mod %d\n", offset(ss, s));
+ fprintf(f, "#define arch_align_int_mod %d\n", offset(si, i));
+ fprintf(f, "#define arch_align_long_mod %d\n", offset(sl, l));
+ fprintf(f, "#define arch_align_ptr_mod %d\n", offset(sp, p));
+ fprintf(f, "#define arch_align_float_mod %d\n", offset(sf, f));
+ fprintf(f, "#define arch_align_double_mod %d\n", offset(sd, d));
+#undef offset
+
+S("/* ---------------- Scalar sizes ---------------- */");
+
+ fprintf(f, "#define arch_log2_sizeof_short %d\n", log2s[size_of(short)]);
+ fprintf(f, "#define arch_log2_sizeof_int %d\n", log2s[size_of(int)]);
+ fprintf(f, "#define arch_log2_sizeof_long %d\n", log2s[size_of(long)]);
+ fprintf(f, "#define arch_sizeof_ds_ptr %d\n", size_of(char _ds *));
+ fprintf(f, "#define arch_sizeof_ptr %d\n", size_of(char *));
+ fprintf(f, "#define arch_sizeof_float %d\n", size_of(float));
+ fprintf(f, "#define arch_sizeof_double %d\n", size_of(double));
+
+S("/* ---------------- Unsigned max values ---------------- */");
+
+#define pmax(str, typ, tstr, l)\
+ fprintf(f, "#define arch_max_%s ((%s)0x%s%s + (%s)0)\n",\
+ str, tstr, ffs + ffs_strlen - size_of(typ) * 2, l, tstr)
+ pmax("uchar", unsigned char, "unsigned char", "");
+ pmax("ushort", unsigned short, "unsigned short", "");
+ pmax("uint", unsigned int, "unsigned int", "");
+ pmax("ulong", unsigned long, "unsigned long", "L");
+#undef pmax
+
+S("/* ---------------- Miscellaneous ---------------- */");
+
+ fprintf(f, "#define arch_is_big_endian %d\n", 1 - *(char *)&one);
+ pl0.l = 0;
+ pl1.l = -1;
+ fprintf(f, "#define arch_ptrs_are_signed %d\n",
+ (pl1.p < pl0.p));
+ f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0;
+ /* We have to test the size dynamically here, */
+ /* because the preprocessor can't evaluate sizeof. */
+ fprintf(f, "#define arch_floats_are_IEEE %d\n",
+ ((size_of(float) == size_of(int) ?
+ f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 :
+ f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L)
+ ? 1 : 0));
+ /* There are three cases for arithmetic right shift: */
+ /* always correct, correct except for right-shifting a long by 1 */
+ /* (a bug in some versions of the Turbo C compiler), and */
+ /* never correct. */
+ ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 :
+ lr1 != -1 ? 1 : /* Turbo C problem */
+ 2);
+ fprintf(f, "#define arch_arith_rshift %d\n", ars);
+ /* Some machines can't handle a variable shift by */
+ /* the full width of a long. */
+ fprintf(f, "#define arch_can_shift_full_long %d\n",
+ um1 >> lwidth == 0);
+
+/* ---------------- Done. ---------------- */
+
+ fclose(f);
+ return exit_OK;
+}
diff --git a/gs/src/genconf.c b/gs/src/genconf.c
new file mode 100644
index 000000000..e446f6f25
--- /dev/null
+++ b/gs/src/genconf.c
@@ -0,0 +1,640 @@
+/* Copyright (C) 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* genconf.c */
+/* Generate configuration files */
+#include "stdpre.h"
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h> /* for calloc */
+#include <string.h>
+
+/* We would like to use the real realloc, but it doesn't work on all systems */
+/* (e.g., some Linux versions). */
+void *
+mrealloc(void *old_ptr, size_t old_size, size_t new_size)
+{ void *new_ptr = malloc(new_size);
+ if ( new_ptr == NULL )
+ return NULL;
+ /* We have to pass in the old size, since we have no way to */
+ /* determine it otherwise. */
+ memcpy(new_ptr, old_ptr, min(old_size, new_size));
+ return new_ptr;
+}
+
+/*
+ * This program generates a set of configuration files.
+ * Almost everything it does could be done by a shell program, except that
+ * (1) Unix shells are not compatible from one system to another,
+ * (2) the DOS shell is not equal to the task,
+ * (3) the VMS shell is radically different from all others.
+ *
+ * Usage:
+ * genconf [-Z] [-n [name_prefix | -]] [@]xxx.dev*
+ * [-f gconfigf.h] [-h gconfig.h]
+ * [-p[l|L][u][e] pattern] [-l|o|lo|ol out.tr]
+ * & in the pattern acts as an escape character as follows:
+ * &p produces a %;
+ * &s produces a space;
+ * && produces a \;
+ * &- produces a -;
+ * &x, for any other character x, is an error.
+ */
+
+/* DEFAULT_PREFIX should be DEFAULT_NAME_PREFIX. */
+#define DEFAULT_PREFIX "gs_"
+
+/* Structures for accumulating information. */
+typedef struct string_item_s {
+ const char *str;
+ int index;
+} string_item;
+/* The values of uniq_mode are bit masks. */
+typedef enum {
+ uniq_all = 1, /* keep all occurrences (default) */
+ uniq_first = 2, /* keep only first occurrence */
+ uniq_last = 4 /* keep only last occurrence */
+} uniq_mode;
+typedef struct string_list_s {
+ /* The following are set at creation time. */
+ int max_count;
+ uniq_mode mode;
+ /* The following are updated dynamically. */
+ int count;
+ string_item *items;
+} string_list;
+#define max_pattern 60
+typedef struct string_pattern_s {
+ bool upper_case;
+ bool drop_extn;
+ char pattern[max_pattern + 1];
+} string_pattern;
+typedef struct config_s {
+ int debug;
+ const char *name_prefix;
+ const char *file_prefix;
+ /* file_names and file_contents are special.... */
+ string_list file_names;
+ string_list file_contents;
+ string_list resources;
+ string_list devs;
+ string_list fonts;
+ string_list headers;
+ string_list libs;
+ string_list libpaths;
+ string_list objs;
+ string_pattern lib_p;
+ string_pattern libpath_p;
+ string_pattern obj_p;
+} config;
+/* These lists grow automatically if needed, so we could start out with */
+/* small allocations. */
+static const config init_config = {
+ 0, /* debug */
+ DEFAULT_PREFIX, /* name_prefix */
+ "", /* file_prefix */
+ { 200 }, /* file_names */
+ { 200 }, /* file_contents */
+ { 100, uniq_first }, /* resources */
+ { 100, uniq_first }, /* devs */
+ { 50, uniq_first }, /* fonts */
+ { 20, uniq_first }, /* headers */
+ { 20, uniq_last }, /* libs */
+ { 10, uniq_first }, /* libpaths */
+ { 400, uniq_first } /* objs */
+};
+
+/* Forward definitions */
+int alloc_list(P1(string_list *));
+void parse_affix(P2(char *, const char *));
+int read_dev(P2(config *, const char *));
+int read_token(P3(char *, int, const char **));
+int add_entry(P3(config *, char *, const char *));
+string_item *add_item(P2(string_list *, const char *));
+void sort_uniq(P1(string_list *));
+void write_list(P3(FILE *, const string_list *, const char *));
+void write_list_pattern(P3(FILE *, const string_list *, const string_pattern *));
+
+main(int argc, char *argv[])
+{ config conf;
+ int i;
+
+ /* Allocate string lists. */
+ conf = init_config;
+ alloc_list(&conf.file_names);
+ alloc_list(&conf.file_contents);
+ alloc_list(&conf.resources);
+ alloc_list(&conf.devs);
+ alloc_list(&conf.fonts);
+ alloc_list(&conf.headers);
+ alloc_list(&conf.libs);
+ alloc_list(&conf.libpaths);
+ alloc_list(&conf.objs);
+
+ /* Initialize patterns. */
+ conf.lib_p.upper_case = false;
+ conf.lib_p.drop_extn = false;
+ strcpy(conf.lib_p.pattern, "%s\n");
+ conf.libpath_p = conf.lib_p;
+ conf.obj_p = conf.lib_p;
+
+ /* Process command line arguments. */
+ for ( i = 1; i < argc; i++ )
+ { const char *arg = argv[i];
+ FILE *out;
+ int lib = 0, obj = 0;
+ if ( *arg != '-' )
+ { read_dev(&conf, arg);
+ continue;
+ }
+ if ( i == argc - 1 )
+ { fprintf(stderr, "Missing argument after %s.\n",
+ arg);
+ exit(1);
+ }
+ switch ( arg[1] )
+ {
+ case 'C': /* change directory, by analogy with make */
+ conf.file_prefix =
+ (argv[i + 1][0] == '-' ? "" : argv[i + 1]);
+ ++i;
+ continue;
+ case 'n':
+ conf.name_prefix =
+ (argv[i + 1][0] == '-' ? "" : argv[i + 1]);
+ ++i;
+ continue;
+ case 'p':
+ { string_pattern *pat;
+ switch ( *(arg += 2) )
+ {
+ case 'l': pat = &conf.lib_p; break;
+ case 'L': pat = &conf.libpath_p; break;
+ default: pat = &conf.obj_p; arg--;
+ }
+ pat->upper_case = false;
+ pat->drop_extn = false;
+ if ( argv[i + 1][0] == '-' )
+ strcpy(pat->pattern, "%s\n");
+ else
+ { char *p, *q;
+ for ( p = pat->pattern, q = argv[++i];
+ (*p++ = *q++) != 0;
+ )
+ if ( p[-1] == '&' )
+ switch ( *q )
+ {
+ case 'p': p[-1] = '%'; q++; break;
+ case 's': p[-1] = ' '; q++; break;
+ case '&': p[-1] = '\\'; q++; break;
+ case '-': p[-1] = '-'; q++; break;
+ default:
+ fprintf(stderr,
+ "& not followed by ps&-: &%c\n",
+ *q);
+ exit(1);
+ }
+ p[-1] = '\n';
+ *p = 0;
+ }
+ for ( ; ; )
+ switch ( *++arg )
+ {
+ case 'u': pat->upper_case = true; break;
+ case 'e': pat->drop_extn = true; break;
+ case 0: goto pbreak;
+ default:
+ fprintf(stderr, "Unknown switch %s.\n", arg);
+ exit(1);
+ }
+pbreak: if ( pat == &conf.obj_p )
+ { conf.lib_p = *pat;
+ conf.libpath_p = *pat;
+ }
+ continue;
+ case 'Z':
+ conf.debug = 1;
+ continue;
+ }
+ }
+ /* Must be an output file. */
+ out = fopen(argv[++i], "w");
+ if ( out == 0 )
+ { fprintf(stderr, "Can't open %s for output.\n",
+ argv[i]);
+ exit(1);
+ }
+ switch ( arg[1] )
+ {
+ case 'f':
+ fputs("/* This file was generated automatically by genconf.c. */\n", out);
+ fputs("/* For documentation, see gsconfig.c. */\n", out);
+ { char template[80];
+ sprintf(template,
+ "font_(\"0.font_%%s\",%sf_%%s,zf_%%s)\n",
+ conf.name_prefix);
+ write_list(out, &conf.fonts, template);
+ }
+ break;
+ case 'h':
+ fputs("/* This file was generated automatically by genconf.c. */\n", out);
+ { char template[80];
+ sprintf(template, "device_(%s%%s_device)\n",
+ conf.name_prefix);
+ write_list(out, &conf.devs, template);
+ }
+ sort_uniq(&conf.resources);
+ write_list(out, &conf.resources, "%s\n");
+ write_list(out, &conf.headers, "#include \"%s\"\n");
+ break;
+ case 'l':
+ lib = 1;
+ obj = arg[2] == 'o';
+ goto lo;
+ case 'o':
+ obj = 1;
+ lib = arg[2] == 'l';
+lo: if ( obj )
+ { sort_uniq(&conf.objs);
+ write_list_pattern(out, &conf.objs, &conf.obj_p);
+ }
+ if ( lib )
+ { sort_uniq(&conf.libs);
+ write_list_pattern(out, &conf.libpaths, &conf.libpath_p);
+ write_list_pattern(out, &conf.libs, &conf.lib_p);
+ }
+ break;
+ default:
+ fclose(out);
+ fprintf(stderr, "Unknown switch %s.\n", argv[i]);
+ exit(1);
+ }
+ fclose(out);
+ }
+
+ exit(0);
+}
+
+/* Allocate and initialize a string list. */
+int
+alloc_list(string_list *list)
+{ list->count = 0;
+ list->items =
+ (string_item *)calloc(list->max_count, sizeof(string_item));
+ assert(list->items != NULL);
+ return 0;
+}
+
+/* Read an entire file into memory. */
+/* We use the 'index' of the file_contents string_item to record the union */
+/* of the uniq_modes of all (direct and indirect) items in the file. */
+string_item *
+read_file(config *pconf, const char *fname)
+{ char *cname = malloc(strlen(fname) + strlen(pconf->file_prefix) + 1);
+ int i;
+ FILE *in;
+ int end, nread;
+ char *cont;
+ string_item *item;
+
+ if ( cname == 0 )
+ { fprintf(stderr, "Can't allocate space for file name %s%s.\n",
+ pconf->file_prefix, fname);
+ exit(1);
+ }
+ strcpy(cname, pconf->file_prefix);
+ strcat(cname, fname);
+ for ( i = 0; i < pconf->file_names.count; ++i )
+ if ( !strcmp(pconf->file_names.items[i].str, cname) )
+ { free(cname);
+ return &pconf->file_contents.items[i];
+ }
+ /* Try to open the file in binary mode, to avoid the overhead */
+ /* of unnecessary EOL conversion in the C library. */
+ in = fopen(cname, "rb");
+ if ( in == 0 )
+ { in = fopen(cname, "r");
+ if ( in == 0 )
+ { fprintf(stderr, "Can't read %s.\n", cname);
+ exit(1);
+ }
+ }
+ fseek(in, 0L, 2 /*SEEK_END*/);
+ end = ftell(in);
+ cont = malloc(end + 1);
+ if ( cont == 0 )
+ { fprintf(stderr, "Can't allocate %d bytes to read %s.\n",
+ end + 1, cname);
+ exit(1);
+ }
+ rewind(in);
+ nread = fread(cont, 1, end, in);
+ fclose(in);
+ cont[nread] = 0;
+ if ( pconf->debug )
+ printf("File %s = %d bytes.\n", cname, nread);
+ add_item(&pconf->file_names, cname);
+ item = add_item(&pconf->file_contents, cont);
+ item->index = 0; /* union of uniq_modes */
+ return item;
+}
+
+/* Read and parse a .dev file. */
+/* Return the union of all its uniq_modes. */
+int
+read_dev(config *pconf, const char *arg)
+{ string_item *item;
+ const char *in;
+#define max_token 256
+ char *token = malloc(max_token + 1);
+ char *category = malloc(max_token + 1);
+ int len;
+
+ if ( pconf->debug )
+ printf("Reading %s;\n", arg);
+ item = read_file(pconf, arg);
+ if ( item->index == uniq_first )
+ { /* Don't need to read the file again. */
+ if ( pconf->debug )
+ printf("Skipping duplicate file.\n");
+ return uniq_first;
+ }
+ in = item->str;
+ strcpy(category, "obj");
+ while ( (len = read_token(token, max_token, &in)) > 0 )
+ item->index |= add_entry(pconf, category, token);
+ free(category);
+#undef max_token
+ if ( len < 0 )
+ { fprintf(stderr, "Token too long: %s.\n", token);
+ exit(1);
+ }
+ if ( pconf->debug )
+ printf("Finished %s.\n", arg);
+ free(token);
+ return item->index;
+}
+
+/* Read a token from a string that contains the contents of a file. */
+int
+read_token(char *token, int max_len, const char **pin)
+{ const char *in = *pin;
+ int len = 0;
+
+ while ( len < max_len )
+ { char ch = *in;
+ if ( ch == 0 )
+ break;
+ ++in;
+ if ( isspace(ch) )
+ { if ( len > 0 )
+ break;
+ continue;
+ }
+ token[len++] = ch;
+ }
+ token[len] = 0;
+ *pin = in;
+ return (len >= max_len ? -1 /* token too long */ : len);
+}
+
+/* Add an entry to a configuration. */
+/* Return its uniq_mode. */
+int
+add_entry(config *pconf, char *category, const char *item)
+{ if ( item[0] == '-' ) /* set category */
+ { strcpy(category, item + 1);
+ return 0;
+ }
+ else /* add to current category */
+ {
+#define max_str 120
+ char str[max_str];
+ char template[80];
+ const char *pat = 0;
+ string_list *list = &pconf->resources;
+
+ if ( pconf->debug )
+ printf("Adding %s %s;\n", category, item);
+ /* Handle a few resources specially; just queue the rest. */
+ switch ( category[0] )
+ {
+#define is_cat(str) !strcmp(category, str)
+ case 'd':
+ if ( is_cat("dev") )
+ { list = &pconf->devs; break; }
+ goto err;
+ case 'e':
+ if ( is_cat("emulator") )
+ { pat = "emulator_(\"%s\")"; break; }
+ goto err;
+ case 'f':
+ if ( is_cat("font") )
+ { list = &pconf->fonts; break; }
+ goto err;
+ case 'h':
+ if ( is_cat("header") )
+ { list = &pconf->headers; break; }
+ goto err;
+ case 'i':
+ if ( is_cat("include") )
+ { int len = strlen(item);
+ strcpy(str, item);
+ if ( len < 5 || strcmp(str + len - 4, ".dev") )
+ strcat(str, ".dev");
+ return read_dev(pconf, str);
+ }
+ if ( is_cat("includef") )
+ { strcpy(str, item);
+ strcat(str, ".dvc");
+ return read_dev(pconf, str);
+ }
+ if ( is_cat("init") )
+ { pat = "init_(%s%%s_init)"; }
+ else if ( is_cat("iodev") )
+ { pat = "io_device_(%siodev_%%s)"; }
+ else
+ goto err;
+ sprintf(template, pat, pconf->name_prefix);
+ pat = template;
+ break;
+ case 'l':
+ if ( is_cat("lib") )
+ { list = &pconf->libs; break; }
+ if ( is_cat("libpath") )
+ { list = &pconf->libpaths; break; }
+ goto err;
+ case 'o':
+ if ( is_cat("obj") )
+ { list = &pconf->objs;
+ strcpy(template, pconf->file_prefix);
+ strcat(template, "%s");
+ pat = template;
+ break;
+ }
+ if ( is_cat("oper") )
+ { pat = "oper_(%s_op_defs)"; break; }
+ goto err;
+ case 'p':
+ if ( is_cat("ps") )
+ { pat = "psfile_(\"%s.ps\")"; break; }
+ goto err;
+#undef is_cat
+ default:
+err: fprintf(stderr, "Unknown category %s.\n", category);
+ exit(1);
+ }
+ if ( pat )
+ { sprintf(str, pat, item);
+ assert(strlen(str) < max_str);
+ add_item(list, str);
+ }
+ else
+ add_item(list, item);
+ return list->mode;
+ }
+}
+
+/* Add an item to a list. */
+string_item *
+add_item(string_list *list, const char *str)
+{ char *rstr = malloc(strlen(str) + 1);
+ int count = list->count;
+ string_item *item;
+
+ strcpy(rstr, str);
+ if ( count >= list->max_count )
+ { list->max_count <<= 1;
+ list->items =
+ (string_item *)mrealloc(list->items,
+ (list->max_count >> 1) *
+ sizeof(string_item),
+ list->max_count *
+ sizeof(string_item));
+ assert(list->items != NULL);
+ }
+ item = &list->items[count];
+ item->index = count;
+ item->str = rstr;
+ list->count++;
+ return item;
+}
+
+/* Remove duplicates from a list of string_items. */
+/* In case of duplicates, remove all but the earliest (if last = false) */
+/* or the latest (if last = true). */
+#define psi1 ((const string_item *)p1)
+#define psi2 ((const string_item *)p2)
+int
+cmp_index(const void *p1, const void *p2)
+{ int cmp = psi1->index - psi2->index;
+ return (cmp < 0 ? -1 : cmp > 0 ? 1 : 0);
+}
+int
+cmp_str(const void *p1, const void *p2)
+{ return strcmp(psi1->str, psi2->str);
+}
+#undef psi1
+#undef psi2
+void
+sort_uniq(string_list *list)
+{ string_item *strlist = list->items;
+ int count = list->count;
+ const string_item *from;
+ string_item *to;
+ int i;
+ bool last = list->mode == uniq_last;
+
+ if ( count == 0 )
+ return;
+ qsort((char *)strlist, count, sizeof(string_item), cmp_str);
+ for ( from = to = strlist + 1, i = 1; i < count; from++, i++ )
+ if ( strcmp(from->str, to[-1].str) )
+ *to++ = *from;
+ else if ( (last ? from->index > to[-1].index :
+ from->index < to[-1].index)
+ )
+ to[-1] = *from;
+ count = to - strlist;
+ list->count = count;
+ qsort((char *)strlist, count, sizeof(string_item), cmp_index);
+}
+
+/* Write a list of strings using a template. */
+void
+write_list(FILE *out, const string_list *list, const char *pstr)
+{ string_pattern pat;
+ pat.upper_case = false;
+ pat.drop_extn = false;
+ strcpy(pat.pattern, pstr);
+ write_list_pattern(out, list, &pat);
+}
+void
+write_list_pattern(FILE *out, const string_list *list, const string_pattern *pat)
+{ int i;
+ char macname[40];
+ int plen = strlen(pat->pattern);
+ *macname = 0;
+ for ( i = 0; i < list->count; i++ )
+ { const char *lstr = list->items[i].str;
+ int len = strlen(lstr);
+ char *str = malloc(len + 1);
+ int xlen = plen + len * 3;
+ char *xstr = malloc(xlen + 1);
+ char *alist;
+ strcpy(str, lstr);
+ if ( pat->drop_extn )
+ { char *dot = str + len;
+ while ( dot > str && *dot != '.' ) dot--;
+ if ( dot > str ) *dot = 0, len = dot - str;
+ }
+ if ( pat->upper_case )
+ { char *ptr = str;
+ for ( ; *ptr; ptr++ )
+ if ( islower(*ptr) ) *ptr = toupper(*ptr);
+ }
+ /* We repeat str for the benefit of patterns that */
+ /* need the argument substituted in more than one place. */
+ sprintf(xstr, pat->pattern, str, str, str);
+ /* Check to make sure the item is within the scope of */
+ /* an appropriate #ifdef, if necessary. */
+ alist = strchr(xstr, '(');
+ if ( alist != 0 && alist != xstr && alist[-1] == '_' )
+ { *alist = 0;
+ if ( strcmp(xstr, macname) )
+ { if (*macname )
+ fputs("#endif\n", out);
+ fprintf(out, "#ifdef %s\n", xstr);
+ strcpy(macname, xstr);
+ }
+ *alist = '(';
+ }
+ else
+ { if ( *macname )
+ { fputs("#endif\n", out);
+ *macname = 0;
+ }
+ }
+ fputs(xstr, out);
+ free(xstr);
+ free(str);
+ }
+ if ( *macname )
+ fputs("#endif\n", out);
+}
diff --git a/gs/src/geninit.c b/gs/src/geninit.c
new file mode 100644
index 000000000..a5bdaa39a
--- /dev/null
+++ b/gs/src/geninit.c
@@ -0,0 +1,231 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* geninit.c */
+/* Utility for merging all the Ghostscript initialization files */
+/* (gs_*.ps) into a single file, optionally converting them to C data. */
+#include "stdio_.h"
+#include "string_.h"
+
+/* Usage:
+ * geninit <init-file.ps> <gconfig.h> <merged-init-file.ps>
+ * geninit <init-file.ps> <gconfig.h> -c <merged-init-file.c>
+ */
+
+/* Forward references */
+private void merge_to_c();
+private void merge_to_ps();
+
+#define line_size 128
+
+int
+main(int argc, char *argv[])
+{ const char *fin;
+ FILE *in;
+ const char *fconfig;
+ FILE *config;
+ const char *fout;
+ FILE *out;
+ bool to_c = false;
+
+ if ( argc == 4 )
+ fin = argv[1], fconfig = argv[2], fout = argv[3];
+ else if ( argc == 5 && !strcmp(argv[3], "-c") )
+ fin = argv[1], fconfig = argv[2], fout = argv[4], to_c = true;
+ else
+ { fprintf(stderr, "\
+Usage: geninit gs_init.ps gconfig.h gs_xinit.ps\n\
+ or geninit gs_init.ps gconfig.h -c gs_init.c\n");
+ exit(1);
+ }
+ in = fopen(fin, "r");
+ if ( in == 0 )
+ { fprintf(stderr, "Cannot open %s for reading.\n", fin);
+ exit(1);
+ }
+ config = fopen(fconfig, "r");
+ if ( config == 0 )
+ { fprintf(stderr, "Cannot open %s for reading.\n", fconfig);
+ fclose(in);
+ exit(1);
+ }
+ out = fopen(fout, "w");
+ if ( out == 0 )
+ { fprintf(stderr, "Cannot open %s for writing.\n", fout);
+ fclose(config);
+ fclose(in);
+ exit(1);
+ }
+ if ( to_c )
+ merge_to_c(fin, in, config, out);
+ else
+ merge_to_ps(fin, in, config, out);
+ fclose(out);
+ return 0;
+}
+
+/* Read a line from the input. */
+private bool
+rl(FILE *in, char *str, int len)
+{ if ( fgets(str, len, in) == NULL )
+ return false;
+ str[strlen(str) - 1] = 0; /* remove newline */
+ return true;
+}
+
+/* Write a line on the output. */
+private void
+wl(FILE *out, const char *str, bool to_c)
+{ if ( to_c )
+ { int n = 0;
+ const char *p = str;
+ for ( ; *p; ++p )
+ { char c = *p;
+ const char *format = "%d,";
+ if ( c >= 32 && c < 127 )
+ format = (c == '\'' || c == '\\' ? "'\\%c'," : "'%c',");
+ fprintf(out, format, c);
+ if ( ++n == 15 )
+ { fputs("\n", out);
+ n = 0;
+ }
+ }
+ fputs("10,\n", out);
+ }
+ else
+ { fprintf(out, "%s\n", str);
+ }
+}
+
+/* Strip whitespace and comments from a string if possible. */
+/* Return a pointer to any string that remains, or NULL if none. */
+/* Note that this may store into the string. */
+private char *
+doit(char *line)
+{ char *str = line;
+ char *p1;
+
+ while ( *str == ' ' || *str == '\t' ) /* strip leading whitespace */
+ ++str;
+ if ( *str == 0 ) /* all whitespace */
+ return NULL;
+ if ( !strncmp(str, "%END", 4) ) /* keep these for .skipeof */
+ return str;
+ if ( str[0] == '%' ) /* comment line */
+ return NULL;
+ if ( (p1 = strchr(str, '%')) == NULL ) /* no internal comment */
+ return str;
+ if ( strchr(p1, ')') != NULL ) /* might be a % inside a string */
+ return str;
+ while ( p1[-1] == ' ' || p1[-1] == '\t' )
+ --p1;
+ *p1 = 0; /* remove comment */
+ return str;
+}
+
+/* Merge a file from input to output. */
+private void
+mergefile(const char *inname, FILE *in, FILE *config, FILE *out, bool to_c)
+{ char line[line_size + 1];
+
+ while ( rl(in, line, line_size) )
+ { char psname[line_size + 1];
+ int nlines;
+
+ if ( !strncmp(line, "%% Replace ", 11) &&
+ sscanf(line + 11, "%d %s", &nlines, psname) == 2
+ )
+ { while ( nlines-- > 0 )
+ rl(in, line, line_size);
+ if ( psname[0] == '(' )
+ { FILE *ps;
+ psname[strlen(psname) - 1] = 0;
+ ps = fopen(psname + 1, "r");
+ if ( ps == 0 )
+ { fprintf(stderr, "Cannot open %s for reading.\n", psname + 1);
+ exit(1);
+ }
+ mergefile(psname + 1, ps, config, out, to_c);
+ }
+ else if ( !strcmp(psname, "INITFILES") )
+ { /*
+ * We don't want to bind config.h into geninit, so
+ * we parse it ourselves at execution time instead.
+ */
+ rewind(config);
+ while ( rl(config, psname, line_size) )
+ if ( !strncmp(psname, "psfile_(\"", 9) )
+ { FILE *ps;
+ psname[strlen(psname) - 2] = 0;
+ ps = fopen(psname + 9, "r");
+ if ( ps == 0 )
+ { fprintf(stderr, "Cannot open %s for reading.\n", psname + 9);
+ exit(1);
+ }
+ mergefile(psname + 9, ps, config, out, to_c);
+ }
+ }
+ else
+ { fprintf(stderr, "Unknown %%%% Replace %d %s\n",
+ nlines, psname);
+ exit(1);
+ }
+ }
+ else if ( !strcmp(line, "currentfile closefile") )
+ { /* The rest of the file is debugging code, stop here. */
+ break;
+ }
+ else
+ { char *str = doit(line);
+ if ( str != 0 )
+ wl(out, str, to_c);
+ }
+ }
+ fprintf(stderr, "%s: %ld bytes, output pos = %ld\n",
+ inname, ftell(in), ftell(out));
+ fclose(in);
+}
+
+/* Merge and produce a C file. */
+private void
+merge_to_c(const char *inname, FILE *in, FILE *config, FILE *out)
+{ char line[line_size + 1];
+
+ fputs("/*\n", out);
+ while ( (rl(in, line, line_size), line[0]) )
+ fprintf(out, "%s\n", line);
+ fputs("*/\n", out);
+ fputs("\n", out);
+ fputs("/* Pre-compiled interpreter initialization string. */\n", out);
+ fputs("#include \"stdpre.h\"\n", out);
+ fputs("\n", out);
+ fputs("const byte gs_init_string[] = {\n", out);
+ mergefile(inname, in, config, out, true);
+ fputs("10};\n", out);
+ fputs("const uint gs_init_string_sizeof = sizeof(gs_init_string);\n", out);
+}
+
+/* Merge and produce a PostScript file. */
+private void
+merge_to_ps(const char *inname, FILE *in, FILE *config, FILE *out)
+{ char line[line_size + 1];
+
+ while ( (rl(in, line, line_size), line[0]) )
+ fprintf(out, "%s\n", line);
+ mergefile(inname, in, config, out, false);
+}
diff --git a/gs/src/ghost.h b/gs/src/ghost.h
new file mode 100644
index 000000000..c10782a83
--- /dev/null
+++ b/gs/src/ghost.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ghost.h */
+/* Common definitions for interpreter */
+#include "gx.h"
+#include "iref.h"
diff --git a/gs/src/gp.h b/gs/src/gp.h
new file mode 100644
index 000000000..b659118d2
--- /dev/null
+++ b/gs/src/gp.h
@@ -0,0 +1,196 @@
+/* Copyright (C) 1991, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp.h */
+/* Interface to platform-specific routines */
+/* Requires gsmemory.h, gstypes.h */
+
+/*
+ * This file defines the interface to ***ALL*** platform-specific routines.
+ * The routines are implemented in a gp_*.c file specific to each platform.
+ * We try very hard to keep this list short!
+ */
+
+/* ------ Initialization/termination ------ */
+
+/*
+ * This routine is called early in the initialization.
+ * It should do as little as possible. In particular, it should not
+ * do things like open display connections: that is the responsibility
+ * of the display device driver.
+ */
+void gp_init(P0());
+
+/*
+ * This routine is called just before the program exits (normally or
+ * abnormally). It too should do as little as possible.
+ */
+void gp_exit(P2(int exit_status, int code));
+
+/*
+ * Exit the program. Normally this just calls the `exit' library procedure,
+ * but it does something different on a few platforms.
+ */
+void gp_do_exit(P1(int exit_status));
+
+/* ------ Miscellaneous ------ */
+
+/*
+ * Get the string corresponding to an OS error number.
+ * If no string is available, return NULL. The caller may assume
+ * the string is allocated statically and permanently.
+ */
+const char *gp_strerror(P1(int));
+
+/* ------ Date and time ------ */
+
+/*
+ * Read the current time (in seconds since an implementation-defined epoch)
+ * into ptm[0], and fraction (in nanoseconds) into ptm[1].
+ */
+void gp_get_realtime(P1(long ptm[2]));
+
+/*
+ * Read the current user CPU time (in seconds) into ptm[0],
+ * and fraction (in nanoseconds) into ptm[1].
+ */
+void gp_get_usertime(P1(long ptm[2]));
+
+/* ------ Screen management ------ */
+
+/*
+ * The following routines are only relevant in a single-window environment
+ * such as a PC; on platforms with window systems, the 'make current'
+ * routines do nothing.
+ */
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+/* Initialize the console. */
+void gp_init_console(P0());
+
+/* Write a string to the console. */
+void gp_console_puts(P2(const char *, uint));
+
+/* Make the console current on the screen. */
+int gp_make_console_current(P1(gx_device *));
+
+/* Make the graphics current on the screen. */
+int gp_make_graphics_current(P1(gx_device *));
+
+/*
+ * The following are only relevant for X Windows.
+ */
+
+/* Get the environment variable that specifies the display to use. */
+const char *gp_getenv_display(P0());
+
+/* ------ Printer accessing ------ */
+
+/*
+ * Open a connection to a printer. A null file name means use the
+ * standard printer connected to the machine, if any.
+ * If possible, support "|command" for opening an output pipe.
+ * Return NULL if the connection could not be opened.
+ */
+FILE *gp_open_printer(P2(char *fname, int binary_mode));
+
+/* Close the connection to the printer. */
+void gp_close_printer(P2(FILE *pfile, const char *fname));
+
+/* ------ File naming and accessing ------ */
+
+/* Define the character used for separating file names in a list. */
+extern const char gp_file_name_list_separator;
+
+/* Define the default scratch file name prefix. */
+extern const char gp_scratch_file_name_prefix[];
+
+/* Define the name of the null output file. */
+extern const char gp_null_file_name[];
+
+/* Define the name that designates the current directory. */
+extern const char gp_current_directory_name[];
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+/* This is always either "" or "b". */
+extern const char gp_fmode_binary_suffix[];
+/* Define the file modes for binary reading or writing. */
+/* (This is just a convenience: they are "r" or "w" + the suffix.) */
+extern const char gp_fmode_rb[];
+extern const char gp_fmode_wb[];
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *gp_open_scratch_file(P3(const char *prefix, char *fname,
+ const char *mode));
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *gp_fopen(P2(const char *fname, const char *mode));
+
+/* Answer whether a file name contains a directory/device specification, */
+/* i.e. is absolute (not directory- or device-relative). */
+bool gp_file_name_is_absolute(P2(const char *fname, uint len));
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *gp_file_name_concat_string(P4(const char *prefix, uint plen,
+ const char *fname, uint len));
+
+/* ------ File enumeration ------ */
+
+#ifndef file_enum_DEFINED /* also defined in iodev.h */
+# define file_enum_DEFINED
+struct file_enum_s; /* opaque to client, defined by implementor */
+typedef struct file_enum_s file_enum;
+#endif
+
+/*
+ * Begin an enumeration. pat is a C string that may contain *s or ?s.
+ * The implementor should copy the string to a safe place.
+ * If the operating system doesn't support correct, arbitrarily placed
+ * *s and ?s, the implementation should modify the string so that it
+ * will return a conservative superset of the request, and then use
+ * the string_match procedure to select the desired subset. E.g., if the
+ * OS doesn't implement ? (single-character wild card), any consecutive
+ * string of ?s should be interpreted as *. Note that \ can appear in
+ * the pattern also, as a quoting character.
+ */
+file_enum *gp_enumerate_files_init(P3(const char *pat, uint patlen,
+ gs_memory_t *memory));
+
+/*
+ * Return the next file name in the enumeration. The client passes in
+ * a scratch string and a max length. If the name of the next file fits,
+ * the procedure returns the length. If it doesn't fit, the procedure
+ * returns max length +1. If there are no more files, the procedure
+ * returns -1.
+ */
+uint gp_enumerate_files_next(P3(file_enum *pfen, char *ptr, uint maxlen));
+
+/*
+ * Clean up a file enumeration. This is only called to abandon
+ * an enumeration partway through: ...next should do it if there are
+ * no more files to enumerate. This should deallocate the file_enum
+ * structure and any subsidiary structures, strings, buffers, etc.
+ */
+void gp_enumerate_files_close(P1(file_enum *pfen));
diff --git a/gs/src/gp_dosfb.c b/gs/src/gp_dosfb.c
new file mode 100644
index 000000000..fbf7ec7c6
--- /dev/null
+++ b/gs/src/gp_dosfb.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_dosfb.c */
+/* MS-DOS frame buffer swapping routines for Ghostscript */
+#include <conio.h>
+#include "malloc_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+
+/* On MS-DOS machines, we maintain a console image in memory, */
+/* and swap screens on request. */
+#define cw_width 80
+#define cw_height 25
+typedef struct text_line_s {
+ int end;
+ char text[cw_width + 1];
+} text_line;
+typedef struct {
+ text_line *line;
+ text_line lines[cw_height];
+} ds_text_screen;
+
+private ds_text_screen *console;
+
+private int console_is_current;
+
+/* Buffer one scan line of graphics. */
+#define row_buf_size 1280
+private char graphics_file_name[] = "_temp_.gfb";
+
+/* Forward references */
+private int save_graphics(P1(gx_device *));
+private int restore_graphics(P1(gx_device *));
+
+/* Initialize the console buffer. */
+void
+gp_init_console(void)
+{ console = (ds_text_screen *)gs_malloc(1, sizeof(ds_text_screen), "gp_init_console(dosfb)");
+ if ( console != 0 )
+ { memset(&console->lines, 0, sizeof(console->lines));
+ console->line = &console->lines[0];
+ console_is_current = 0;
+ }
+ else
+ console_is_current = 1;
+}
+
+/* Write a string to the console. */
+void
+gp_console_puts(const char *str, uint size)
+{ register ds_text_screen *cop = console;
+ register text_line *lip;
+ if ( console == 0 )
+ { fwrite(str, 1, size, stdout);
+ return;
+ }
+ lip = cop->line;
+ for ( ; size ; str++, size-- )
+ switch ( *str )
+ {
+ case '\n':
+ if ( lip == &cop->lines[cw_height - 1] )
+ { /* Scroll up */
+ memcpy(&cop->lines[0], &cop->lines[1],
+ sizeof(text_line) * (cw_height - 1));
+ }
+ else
+ cop->line = ++lip;
+ lip->end = 0;
+ break;
+ case '\t':
+ gp_console_puts(" ", 8 - (lip->end & 7));
+ lip = cop->line;
+ break;
+ default:
+ if ( lip->end == cw_width )
+ { gp_console_puts("\n", 1);
+ lip = cop->line;
+ }
+ lip->text[lip->end++] = *str;
+ }
+}
+
+/* Make the console current on the screen. */
+int
+gp_make_console_current(gx_device *dev)
+{ int code = 0;
+ if ( console == 0 )
+ return 0;
+ if ( !console_is_current )
+ code = save_graphics(dev);
+ /* Transfer the console buffer to the screen. */
+ /* Unfortunately, there is no standard way to clear the screen. */
+ /* Output the ANSI sequence and hope for the best. */
+ cputs("\r\033[2J\r \r");
+ { int i;
+ register text_line *lip;
+ for ( i = 0, lip = &console->lines[0]; i < cw_height; i++, lip++ )
+ { if ( i != 0 ) cputs("\r\n");
+ lip->text[lip->end] = 0;
+ cputs(lip->text);
+ }
+ }
+ console_is_current = 1;
+ return code;
+}
+
+/* Make the graphics current on the screen. */
+int
+gp_make_graphics_current(gx_device *dev)
+{ if ( console == 0 )
+ return 0;
+ if ( console_is_current )
+ { int code = restore_graphics(dev);
+ if ( code < 0 ) return code;
+ console_is_current = 0;
+ }
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* We compress the pixmap just a little, by noting */
+/* replicated bytes at the beginning and end of a line. */
+typedef struct { ushort pre, post; } row_head;
+
+/* Save the graphics screen on a file. */
+private int
+save_graphics(gx_device *dev)
+{ uint row_size = gx_device_raster(dev, 0);
+ char row_buf[row_buf_size];
+ FILE *gfile;
+ int y;
+ if ( row_size > row_buf_size ) return -1;
+ gfile = fopen(graphics_file_name, "wb");
+ if ( gfile == 0 ) return gs_error_ioerror;
+ for ( y = 0; y < dev->height; y++ )
+ { char _ss *row = row_buf;
+ (*dev_proc(dev, get_bits))(dev, y, row, NULL);
+ { row_head head;
+ char _ss *beg = row, *end = row + row_size - 1;
+ while ( end > beg && *end == end[-1] ) end--;
+ if ( beg < end )
+ while ( *beg == beg[1] ) beg++;
+ head.pre = beg - row;
+ head.post = end + 1 - row;
+ fwrite((char *)&head, 1, sizeof(head), gfile);
+ fwrite(beg, head.post - head.pre, 1, gfile);
+ row += row_size;
+ }
+ }
+ fclose(gfile);
+ return 0;
+}
+
+/* Restore the graphics screen from a file. */
+private int
+restore_graphics(gx_device *dev)
+{ FILE *gfile;
+ uint row_size = gx_device_raster(dev, 0);
+ char row_buf[row_buf_size];
+ int y;
+ if ( row_size > row_buf_size ) return -1;
+ gfile = fopen(graphics_file_name, "rb");
+ if ( gfile == 0 ) return gs_error_ioerror;
+ for ( y = 0; y < dev->height; y ++ )
+ { row_head head;
+ char _ss *beg, *end;
+ fread((char *)&head, 1, sizeof(head), gfile);
+ beg = row_buf + head.pre;
+ end = row_buf + head.post;
+ fread(beg, 1, end - beg, gfile);
+ if ( head.pre )
+ memset(row_buf, *beg, head.pre);
+ if ( head.post < row_size )
+ memset(end, end[-1], row_size - head.post);
+ (*dev_proc(dev, copy_color))(dev, row_buf, 0, row_size, gx_no_bitmap_id, 0, y, dev->width, 1);
+ }
+ fclose(gfile);
+ return 0;
+}
diff --git a/gs/src/gp_dosfe.c b/gs/src/gp_dosfe.c
new file mode 100644
index 000000000..669fe1ad5
--- /dev/null
+++ b/gs/src/gp_dosfe.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_dosfe.c */
+/* MS-DOS file enumeration. */
+#include "stdio_.h"
+#include <fcntl.h>
+#include "dos_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gp.h"
+#include "gsutil.h"
+
+struct file_enum_s {
+ ff_struct_t ffblk;
+ char *pattern; /* orig pattern + modified pattern */
+ int patlen; /* orig pattern length */
+ int pat_size; /* allocate space for pattern */
+ int head_size; /* pattern length through last */
+ /* :, / or \ */
+ int first_time;
+ gs_memory_t *memory;
+};
+gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
+ file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
+
+/* Initialize an enumeration. Note that * and ? in a directory */
+/* don't work, and \ is taken literally unless a second \ follows. */
+file_enum *
+gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem)
+{ file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
+ int pat_size = 2 * patlen + 1;
+ char *pattern;
+ char *p;
+ int hsize = 0;
+ int i;
+ int dot = 0;
+ if ( pfen == 0 )
+ return 0;
+
+ /* pattern could be allocated as a string, */
+ /* but it's simpler for GC and freeing to allocate it as bytes. */
+
+ pattern = (char *)gs_alloc_bytes(mem, pat_size,
+ "gp_enumerate_files(pattern)");
+ if ( pattern == 0 )
+ return 0;
+ memcpy(pattern, pat, patlen);
+ p = pattern + patlen;
+ for ( i = 0; i < patlen; i++ )
+ { switch ( pat[i] )
+ {
+ case '*':
+ /* Skip to . or end of string so DOS can do it. */
+ *p++ = '*';
+ while ( i < patlen && pat[i] != '.' ) i++;
+ if ( i == patlen && !dot )
+ { /* DOS doesn't interpret * alone as */
+ /* matching all files; we need *.*. */
+ *p++ = '.';
+ *p++ = '*';
+ }
+ i--;
+ continue;
+ case '.':
+ dot = 1;
+ break;
+ case '\\':
+ if ( i + 1 < patlen && pat[i + 1] == '\\' )
+ i++;
+ /* falls through */
+ case ':':
+ case '/':
+ hsize = p + 1 - (pattern + patlen);
+ dot = 0;
+ }
+ *p++ = pat[i];
+ }
+ *p = 0;
+ pfen->pattern = pattern;
+ pfen->patlen = patlen;
+ pfen->pat_size = pat_size;
+ pfen->head_size = hsize;
+ pfen->memory = mem;
+ pfen->first_time = 1;
+ return pfen;
+}
+
+/* Enumerate the next file. */
+private const string_match_params smp_file = { '*', '?', -1, true };
+uint
+gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
+{ int code;
+ char *p, *q;
+ uint len;
+ const char *fpat = pfen->pattern + pfen->patlen;
+top: if ( pfen->first_time )
+ { code = dos_findfirst(fpat, &pfen->ffblk);
+ pfen->first_time = 0;
+ }
+ else
+ code = dos_findnext(&pfen->ffblk);
+ if ( code != 0 )
+ { /* All done, clean up. */
+ gp_enumerate_files_close(pfen);
+ return ~(uint)0;
+ }
+ if ( maxlen < 13 + pfen->head_size ) return maxlen + 1; /* cop out! */
+ memcpy(ptr, fpat, pfen->head_size);
+ for ( p = &pfen->ffblk.ff_name[0], q = ptr + pfen->head_size; *p; p++ )
+ if ( *p != ' ' ) *q++ = *p;
+ len = q - ptr;
+ /* Make sure this file really matches the pattern. */
+ if ( !string_match(ptr, len, pfen->pattern, pfen->patlen, &smp_file) )
+ goto top;
+ return len;
+}
+
+/* Clean up the file enumeration. */
+void
+gp_enumerate_files_close(file_enum *pfen)
+{ gs_memory_t *mem = pfen->memory;
+ gs_free_object(mem, pfen->pattern,
+ "gp_enumerate_files_close(pattern)");
+ gs_free_object(mem, pfen, "gp_enumerate_files_close");
+}
+
diff --git a/gs/src/gp_dosfs.c b/gs/src/gp_dosfs.c
new file mode 100644
index 000000000..924233ed0
--- /dev/null
+++ b/gs/src/gp_dosfs.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_dosfs.c */
+/* Common routines for MS-DOS (any compiler) and DesqView/X, */
+/* which has a MS-DOS-like file system. */
+#include "dos_.h"
+#include "gx.h"
+#include "gp.h"
+
+/* ------ Printer accessing ------ */
+
+/* Put a printer file (which might be stdout) into binary or text mode. */
+/* This is not a standard gp procedure, */
+/* but all MS-DOS configurations need it. */
+void
+gp_set_printer_binary(int prnfno, int binary)
+{ union REGS regs;
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 0; /* get device info */
+ regs.rshort.bx = prnfno;
+ intdos(&regs, &regs);
+ if ( regs.rshort.cflag != 0 || !(regs.h.dl & 0x80) )
+ return; /* error, or not a device */
+ if ( binary )
+ regs.h.dl |= 0x20; /* binary (no ^Z intervention) */
+ else
+ regs.h.dl &= ~0x20; /* text */
+ regs.h.dh = 0;
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 1; /* set device info */
+ intdos(&regs, &regs);
+}
+
+/* ------ File names ------ */
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ';';
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "b";
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "rb";
+const char gp_fmode_wb[] = "wb";
+
+/* Answer whether a file name contains a directory/device specification, */
+/* i.e. is absolute (not directory- or device-relative). */
+bool
+gp_file_name_is_absolute(const char *fname, unsigned len)
+{ /* A file name is absolute if it contains a drive specification */
+ /* (second character is a :) or if it start with 0 or more .s */
+ /* followed by a / or \. */
+ if ( len >= 2 && fname[1] == ':' )
+ return true;
+ while ( len && *fname == '.' )
+ ++fname, --len;
+ return (len && (*fname == '/' || *fname == '\\'));
+}
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *
+gp_file_name_concat_string(const char *prefix, unsigned plen,
+ const char *fname, unsigned len)
+{ if ( plen > 0 )
+ switch ( prefix[plen - 1] )
+ { case ':': case '/': case '\\': return "";
+ };
+ return "\\";
+}
diff --git a/gs/src/gp_dvx.c b/gs/src/gp_dvx.c
new file mode 100644
index 000000000..0c143ce4a
--- /dev/null
+++ b/gs/src/gp_dvx.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_dvx.c */
+/* Desqview/X-specific routines for Ghostscript */
+#include "string_.h"
+#include "gx.h"
+#include "gsexit.h"
+#include "gp.h"
+#include "time_.h"
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ exit(exit_status);
+}
+
+/* ------ Miscellaneous ------ */
+
+/* Get the string corresponding to an OS error number. */
+/* All reasonable compilers support it. */
+const char *
+gp_strerror(int errnum)
+{ return strerror(errnum);
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1970) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_realtime(long *pdt)
+{ struct timeval tp;
+ struct timezone tzp;
+
+ if ( gettimeofday(&tp, &tzp) == -1 )
+ { lprintf("Ghostscript: gettimeofday failed!\n");
+ gs_exit(1);
+ }
+
+ /* tp.tv_sec is #secs since Jan 1, 1970 */
+ pdt[0] = tp.tv_sec;
+ pdt[1] = tp.tv_usec * 1000;
+
+#ifdef DEBUG_CLOCK
+ printf("tp.tv_sec = %d tp.tv_usec = %d pdt[0] = %ld pdt[1] = %ld\n",
+ tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]);
+#endif
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ gp_get_realtime(pdt); /* Use an approximation for now. */
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+extern void gp_set_printer_binary(P2(int, int));
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ if ( strlen(fname) == 0 || !strcmp(fname, "PRN") )
+ { if ( binary_mode )
+ gp_set_printer_binary(fileno(stdprn), 1);
+ stdprn->_flag = _IOWRT; /* Make stdprn buffered to improve performance */
+ return stdprn;
+ }
+ else
+ return fopen(fname, (binary_mode ? "wb" : "w"));
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ if ( pfile == stdprn )
+ fflush(pfile);
+ else
+ fclose(pfile);
+}
diff --git a/gs/src/gp_itbc.c b/gs/src/gp_itbc.c
new file mode 100644
index 000000000..53de3d007
--- /dev/null
+++ b/gs/src/gp_itbc.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_itbc.c */
+/* Intel processor, Turbo/Borland C-specific routines for Ghostscript */
+#include "dos_.h"
+#include <fcntl.h>
+#include <io.h>
+#include <signal.h>
+#include "ctype_.h" /* for tolower */
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#ifdef __OVERLAY__
+# include "overlay.h"
+#endif
+
+/* Library routines not declared in a standard header */
+extern char *getenv(P1(const char *));
+
+/* Define the size of the C stack. */
+unsigned _stklen = 8000; /* default is 4096, we need more */
+
+/* Define the size of the overlay buffer, if relevant. */
+#ifdef __OVERLAY__
+unsigned _ovrbuffer = (1024L * OVLBUFK) / 16;
+#endif
+
+/* Forward declarations */
+private void handle_FPE(P3(int, int, int *));
+
+/* Do platform-dependent initialization. */
+#if CPU_TYPE > 86
+/* Internal routine to set flags and read them back. */
+/* We use __emit__ so we don't require an assembler. */
+private int
+push_pop_flags(unsigned flags)
+{ __emit__(0x8b, 0x46, 6); /* mov ax,flags */
+ __emit__(0x50, 0x9d); /* push ax; popf */
+ __emit__(0x9c, 0x58); /* pushf; pop ax */
+}
+#endif
+void
+gp_init(void)
+{ /*
+ * Detect the processor type using the following algorithms:
+ * The 8088/8086 truncate shift counts mod 32,
+ * the 80186 and up do not.
+ * The 80186 and below fix FLAGS bits 15-12 to 1,
+ * the 80286 and up do not.
+ * The 80386 allows setting FLAGS bits 14-12,
+ * the 80286 and below do not.
+ * We currently can't tell an 80386 from an 80486.
+ * Note that this algorithm will identify an 80386
+ * running in Virtual 8086 mode as an 80386.
+ * This is acceptable, because Ghostscript doesn't actually
+ * use 80286 or 80386 addressing modes, only the additional
+ * instructions available on these processors.
+ * (This algorithm is derived from the Intel manuals.)
+ */
+#if CPU_TYPE > 86
+ /* We have to be careful not to turn interrupts off! */
+ int result, type;
+ result = push_pop_flags(0x202);
+ if ( (result & 0xf000) == 0xf000 )
+ { /* CPU is an 8088/8086/80186 */
+ { int shc = 33; /* force shift by variable */
+ result = 0xffff << shc;
+ }
+ type = (result == 0 ? 186 : 86);
+ }
+ else
+ { /* CPU is an 80286/80386/... */
+ result = push_pop_flags(0x7202);
+ type = ((result & 0x7000) == 0 ? 286 : 386);
+ }
+ /* A 486 is the same as a 386. */
+#define CPU_EQUIV (CPU_TYPE > 386 ? 386 : CPU_TYPE)
+ if ( type < CPU_EQUIV )
+ { eprintf1("This executable requires an 80%d or higher.\n",
+ CPU_EQUIV);
+ exit(1);
+ }
+#endif
+
+#ifdef __OVERLAY__
+ /* Initialize the overlay machinery. */
+ { int code;
+# ifdef OVEMS
+ code = _OvrInitEms(OVEMS_HANDLE, OVEMS_FIRST, OVEMS_PAGES);
+ if ( code )
+ eprintf("Attempt to use EMS memory for overlays failed.\n");
+# endif
+# ifdef OVEXT
+ code = _OvrInitExt(OVEXT_START, OVEXT_LENGTH);
+ if ( code )
+ eprintf("Attempt to use extended memory for overlays failed.\n");
+# endif
+ }
+#endif
+ /* Set up the handler for numeric exceptions. */
+ signal(SIGFPE, handle_FPE);
+ gp_init_console();
+}
+
+/* Trap numeric exceptions. Someday we will do something */
+/* more appropriate with these. */
+private void
+handle_FPE(int sig, int subcode, int *regs)
+{ unsigned char far *ip = MK_PTR(regs[10], regs[9]);
+ eprintf1("Numeric exception %d:\n", subcode);
+ fprintf(estderr,
+"AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x\n",
+ regs[8], regs[7], regs[6], regs[5], regs[2], regs[1], regs[0]);
+ fprintf(estderr,
+"DS=%04x ES=%04x CS:IP=%04x:%04x",
+ regs[3], regs[4], regs[10], regs[9]);
+ fflush(estderr); /* in case of trap */
+ fprintf(estderr, " --> %02x %02x %02x %02x %02x >> %02x %02x %02x %02x %02x\n",
+ ip[-5], ip[-4], ip[-3], ip[-2], ip[-1],
+ ip[0], ip[1], ip[2], ip[3], ip[4]);
+ exit(1);
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ exit(exit_status);
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+extern void gp_set_printer_binary(P2(int, int));
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ FILE *pfile;
+ if ( strlen(fname) == 0 || !strcmp(fname, "PRN") )
+ pfile = stdprn;
+ else
+ { pfile = fopen(fname, (binary_mode ? "wb" : "w"));
+ if ( pfile == NULL )
+ return NULL;
+ }
+ gp_set_printer_binary(fileno(pfile), binary_mode);
+ return pfile;
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ if ( pfile != stdprn )
+ fclose(pfile);
+}
+
+/* ------ File naming and accessing ------ */
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ char *temp;
+ if ( (temp = getenv("TEMP")) == NULL )
+ *fname = 0;
+ else
+ { char last = '\\';
+ strcpy(fname, temp);
+ /* Prevent X's in path from being converted by mktemp. */
+ for ( temp = fname; *temp; temp++ )
+ *temp = last = tolower(*temp);
+ switch ( last )
+ {
+ default:
+ strcat(fname, "\\");
+ case ':': case '\\':
+ ;
+ }
+ }
+ strcat(fname, prefix);
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{ return fopen(fname, mode);
+}
diff --git a/gs/src/gp_iwatc.c b/gs/src/gp_iwatc.c
new file mode 100644
index 000000000..26f194eca
--- /dev/null
+++ b/gs/src/gp_iwatc.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_iwatc.c */
+/* Intel processor, Watcom C-specific routines for Ghostscript */
+#include "dos_.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include "stat_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+
+/* Library routines not declared in a standard header */
+extern char *getenv(P1(const char *));
+
+/* Define a substitute for stdprn (see below). */
+private FILE *gs_stdprn;
+
+/* Forward declarations */
+private void handle_FPE(P1(int));
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{ gs_stdprn = 0;
+ /* Set up the handler for numeric exceptions. */
+ signal(SIGFPE, handle_FPE);
+ gp_init_console();
+}
+
+/* Trap numeric exceptions. Someday we will do something */
+/* more appropriate with these. */
+private void
+handle_FPE(int sig)
+{ eprintf("Numeric exception:\n");
+ exit(1);
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ exit(exit_status);
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+extern void gp_set_printer_binary(P2(int, int));
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ FILE *pfile;
+ if ( strlen(fname) == 0 || !strcmp(fname, "PRN") )
+ { if ( !binary_mode )
+ return stdprn;
+ if ( gs_stdprn == 0 )
+ { /* We have to effectively reopen the printer, */
+ /* because the Watcom library does \n -> \r\n */
+ /* substitution on the stdprn stream. */
+ int fno = dup(fileno(stdprn));
+ setmode(fno, O_BINARY);
+ gs_stdprn = fdopen(fno, "wb");
+ }
+ pfile = gs_stdprn;
+ }
+ else
+ { pfile = fopen(fname, (binary_mode ? "wb" : "w"));
+ if ( pfile == NULL )
+ return NULL;
+ }
+ gp_set_printer_binary(fileno(pfile), binary_mode);
+ return pfile;
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ if ( pfile != stdprn )
+ fclose(pfile);
+ if ( pfile == gs_stdprn )
+ gs_stdprn = 0;
+}
+
+/* ------ File naming and accessing ------ */
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ /* Unfortunately, Watcom C doesn't provide mktemp, */
+ /* so we have to simulate it ourselves. */
+ char *temp;
+ struct stat fst;
+ char *end;
+ if ( (temp = getenv("TEMP")) == NULL )
+ *fname = 0;
+ else
+ { char last = '\\';
+ strcpy(fname, temp);
+ /* Prevent X's in path from being converted by mktemp. */
+ for ( temp = fname; *temp; temp++ )
+ *temp = last = tolower(*temp);
+ switch ( last )
+ {
+ default:
+ strcat(fname, "\\");
+ case ':': case '\\':
+ ;
+ }
+ }
+ strcat(fname, prefix);
+ strcat(fname, "AA.AAA");
+ end = fname + strlen(fname) - 1;
+ while ( stat(fname, &fst) == 0 )
+ { char *inc = end;
+ while ( *inc == 'Z' || *inc == '.' )
+ { if ( *inc == 'Z' ) *inc = 'A';
+ inc--;
+ if ( end - inc == 6 ) return 0;
+ }
+ ++*inc;
+ }
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{ return fopen(fname, mode);
+}
diff --git a/gs/src/gp_msdos.c b/gs/src/gp_msdos.c
new file mode 100644
index 000000000..b5798104f
--- /dev/null
+++ b/gs/src/gp_msdos.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_msdos.c */
+/* Common platform-specific routines for MS-DOS (any compiler) */
+#include "stdio_.h"
+#include "string_.h" /* for strerror */
+#include "dos_.h"
+#include "gstypes.h"
+#include "gsmemory.h" /* for gp.h */
+#include "gp.h"
+
+/* ------ Miscellaneous ------ */
+
+/* Get the string corresponding to an OS error number. */
+/* This is compiler-, not OS-, specific, but it is ANSI-standard and */
+/* all MS-DOS and MS Windows compilers support it. */
+const char *
+gp_strerror(int errnum)
+{ return strerror(errnum);
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1980) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_realtime(long *pdt)
+{ union REGS osdate, ostime;
+ long idate;
+ static const int mstart[12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ osdate.h.ah = 0x2a; /* get date */
+ intdos(&osdate, &osdate);
+#define da_year rshort.cx
+#define da_mon h.dh
+#define da_day h.dl
+ ostime.h.ah = 0x2c; /* get time */
+ intdos(&ostime, &ostime);
+#define ti_hour h.ch
+#define ti_min h.cl
+#define ti_sec h.dh
+#define ti_hund h.dl
+ idate = (long)osdate.da_year * 365 +
+ ( /* intervening leap days */
+ ((osdate.da_year + 1979)/4 - 1979/4) +
+ (1979/100 - (osdate.da_year + 1979)/100) +
+ ((osdate.da_year + 1979)/400 - 1979/400) +
+ mstart[osdate.da_mon - 1] + /* month is 1-origin */
+ osdate.da_day - 1); /* day of month is 1-origin */
+ idate += (2 < osdate.da_mon
+ && (osdate.da_year % 4 == 0
+ && ((osdate.da_year + 1980) % 100 != 0
+ || (osdate.da_year + 1980) % 400 == 0)));
+ pdt[0] =
+ ((idate * 24 + ostime.ti_hour) * 60 + ostime.ti_min) * 60 +
+ ostime.ti_sec;
+ pdt[1] = ostime.ti_hund * 10000000;
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ gp_get_realtime(pdt); /* Use an approximation for now. */
+}
+
+/* ------ Console management ------ */
+
+/* Answer whether a given file is the console (input or output). */
+/* This is not a standard gp procedure, */
+/* but the MS Windows configuration needs it, */
+/* and other MS-DOS configurations might need it someday. */
+int
+gp_file_is_console(FILE *f)
+{ union REGS regs;
+#ifdef __DLL__
+ if ( f == NULL )
+ return 1;
+#else
+ if ( f == NULL )
+ return 0;
+#endif
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 0; /* get device info */
+ regs.rshort.bx = fileno(f);
+ intdos(&regs, &regs);
+ return ((regs.h.dl & 0x80) != 0 && (regs.h.dl & 3) != 0);
+}
+
+/* ------ Screen management ------ */
+
+/* Get the environment variable that specifies the display to use. */
+const char *
+gp_getenv_display(void)
+{ return NULL;
+}
+
+/* ------ File names ------ */
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "_temp_";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "nul";
+
+/* Define the name that designates the current directory. */
+const char gp_current_directory_name[] = ".";
diff --git a/gs/src/gp_msio.c b/gs/src/gp_msio.c
new file mode 100644
index 000000000..28b36573e
--- /dev/null
+++ b/gs/src/gp_msio.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_msio.c */
+/*
+ * Streams for Windows text window
+ * Original version by Russell Lang and Maurice Castro with help from
+ * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
+ * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
+ */
+
+/* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
+/* by Friedrich Nowak */
+
+/* Factored out from gp_mswin.c by JD 6/25/97 */
+
+#include "stdio_.h"
+#include <stdlib.h>
+#include "gx.h"
+#include "gp.h"
+#include "windows_.h"
+#include <shellapi.h>
+#ifdef __WIN32__
+#include <winspool.h>
+#endif
+#include "gp_mswin.h"
+#include "gsdll.h"
+
+#include "stream.h"
+#include "gxiodev.h" /* must come after stream.h */
+
+/* Imported from gp_msdos.c */
+int gp_file_is_console(P1(FILE *));
+
+
+/* ====== Substitute for stdio ====== */
+
+/* Forward references */
+private void win_std_init(void);
+private stream_proc_process(win_std_read_process);
+private stream_proc_process(win_std_write_process);
+
+/* Use a pseudo IODevice to get win_stdio_init called at the right time. */
+/* This is bad architecture; we'll fix it later. */
+private iodev_proc_init(win_stdio_init);
+gx_io_device gs_iodev_wstdio = {
+ "wstdio", "Special",
+ { win_stdio_init, iodev_no_open_device,
+ iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file,
+ iodev_no_file_status, iodev_no_enumerate_files
+ }
+};
+
+/* Do one-time initialization */
+private int
+win_stdio_init(gx_io_device *iodev, gs_memory_t *mem)
+{
+ win_std_init(); /* redefine stdin/out/err to our window routines */
+ return 0;
+}
+
+/* Define alternate 'open' routines for our stdin/out/err streams. */
+
+extern int iodev_stdin_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+win_stdin_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdin_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.process = win_std_read_process;
+ s->file = NULL;
+ return 0;
+}
+
+extern int iodev_stdout_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+win_stdout_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdout_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.process = win_std_write_process;
+ s->file = NULL;
+ return 0;
+}
+
+extern int iodev_stderr_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+win_stderr_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stderr_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.process = win_std_write_process;
+ s->file = NULL;
+ return 0;
+}
+
+/* Patch stdin/out/err to use our windows. */
+private void
+win_std_init(void)
+{
+ /* If stdxxx is the console, replace the 'open' routines, */
+ /* which haven't gotten called yet. */
+
+ if ( gp_file_is_console(gs_stdin) )
+ gs_findiodevice((const byte *)"%stdin", 6)->procs.open_device =
+ win_stdin_open;
+
+ if ( gp_file_is_console(gs_stdout) )
+ gs_findiodevice((const byte *)"%stdout", 7)->procs.open_device =
+ win_stdout_open;
+
+ if ( gp_file_is_console(gs_stderr) )
+ gs_findiodevice((const byte *)"%stderr", 7)->procs.open_device =
+ win_stderr_open;
+}
+
+private int
+win_std_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{
+ int count = pw->limit - pw->ptr;
+
+ if ( count == 0 ) /* empty buffer */
+ return 1;
+
+/* callback to get more input */
+ count = (*pgsdll_callback)(GSDLL_STDIN, pw->ptr+1, count);
+ if (count == 0) {
+ /* EOF */
+ /* what should we do? */
+ return EOFC;
+ }
+
+ pw->ptr += count;
+ return 1;
+}
+
+
+private int
+win_std_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ uint count = pr->limit - pr->ptr;
+ (*pgsdll_callback)(GSDLL_STDOUT, (char *)(pr->ptr +1), count);
+ pr->ptr = pr->limit;
+ return 0;
+}
+
+/* This is used instead of the stdio version. */
+/* The declaration must be identical to that in <stdio.h>. */
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(_WATCOM_))
+#if defined(_CRTAPI2)
+int _CRTAPI2
+fprintf(FILE *file, const char *fmt, ...)
+#else
+_CRTIMP int __cdecl
+fprintf(FILE *file, const char *fmt, ...)
+#endif
+#else
+int _Cdecl _FARFUNC
+fprintf(FILE _FAR *file, const char *fmt, ...)
+#endif
+{
+int count;
+va_list args;
+ va_start(args,fmt);
+ if ( gp_file_is_console(file) ) {
+ char buf[1024];
+ count = vsprintf(buf,fmt,args);
+ (*pgsdll_callback)(GSDLL_STDOUT, buf, count);
+ }
+ else
+ count = vfprintf(file, fmt, args);
+ va_end(args);
+ return count;
+}
diff --git a/gs/src/gp_mslib.c b/gs/src/gp_mslib.c
new file mode 100644
index 000000000..035ed3831
--- /dev/null
+++ b/gs/src/gp_mslib.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_mslib.c */
+/*
+ * Microsoft Windows 3.n platform support for Graphics Library
+ *
+ * This file just stubs out a few references from gp_mswin.c, where the
+ * real action is. This was done to avoid restructuring Windows support,
+ * though that would be the right thing to do.
+ *
+ * Created 6/25/97 by JD
+ */
+
+#include <setjmp.h>
+
+/// Export dummy longjmp environment
+jmp_buf gsdll_env;
+
+
+/// Export dummy interpreter status
+int gs_exit_status = 0;
+
+
+/// Dummy callback routine & export pointer to it
+int
+gsdll_callback(int a, char * b, unsigned long c)
+ { return 0;}
+
+int (*pgsdll_callback)() = gsdll_callback;
diff --git a/gs/src/gp_mswin.c b/gs/src/gp_mswin.c
new file mode 100644
index 000000000..0806ef6e5
--- /dev/null
+++ b/gs/src/gp_mswin.c
@@ -0,0 +1,852 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_mswin.c */
+/*
+ * Microsoft Windows 3.n platform support for Ghostscript.
+ * Original version by Russell Lang and Maurice Castro with help from
+ * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
+ * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
+ */
+
+/* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
+/* by Friedrich Nowak */
+
+/* Original EXE and GSview specific code removed */
+/* DLL version must now be used under MS-Windows */
+/* Russell Lang 16 March 1996 */
+
+#include "stdio_.h"
+#include "string_.h"
+#include "memory_.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include "ctype_.h"
+#include "dos_.h"
+#include <io.h>
+#include "malloc_.h"
+#include <fcntl.h>
+#include <signal.h>
+#include "gx.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsexit.h"
+
+#include "windows_.h"
+#include <shellapi.h>
+#ifdef __WIN32__
+#include <winspool.h>
+#endif
+#include "gp_mswin.h"
+#include "gsdll.h"
+/* use longjmp instead of exit when using DLL */
+#include <setjmp.h>
+extern jmp_buf gsdll_env;
+
+/* Library routines not declared in a standard header */
+extern char *getenv(P1(const char *));
+
+/* ------ from gnuplot winmain.c plus new stuff ------ */
+
+/* limits */
+#define MAXSTR 255
+
+/* public handles */
+HINSTANCE phInstance;
+HWND hwndtext = HWND_DESKTOP; /* would be better to be a real window */
+
+const LPSTR szAppName = "Ghostscript";
+BOOL is_win32s = FALSE;
+char FAR win_prntmp[MAXSTR]; /* filename of PRN temporary file */
+private int is_printer(const char *name);
+int win_init = 0; /* flag to know if gp_exit has been called */
+int win_exit_status;
+
+BOOL CALLBACK _export AbortProc(HDC, int);
+
+#ifdef __WIN32__
+/* DLL entry point for Borland C++ */
+BOOL WINAPI _export
+DllEntryPoint(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
+{
+ /* Win32s: HIWORD bit 15 is 1 and bit 14 is 0 */
+ /* Win95: HIWORD bit 15 is 1 and bit 14 is 1 */
+ /* WinNT: HIWORD bit 15 is 0 and bit 14 is 0 */
+ /* WinNT Shell Update Release is WinNT && LOBYTE(LOWORD) >= 4 */
+ DWORD version = GetVersion();
+ if ( ((HIWORD(version) & 0x8000) != 0) && ((HIWORD(version) & 0x4000) == 0) )
+ is_win32s = TRUE;
+
+ phInstance = hInst;
+ return TRUE;
+}
+
+/* DLL entry point for Microsoft Visual C++ */
+BOOL WINAPI _export
+DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
+{
+ DllEntryPoint(hInst, fdwReason, lpReserved);
+}
+
+
+#else
+int WINAPI _export
+LibMain(HINSTANCE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
+{
+ phInstance = hInstance;
+ return 1;
+}
+
+int WINAPI _export
+WEP(int nParam)
+{
+ return 1;
+}
+#endif
+
+
+BOOL CALLBACK _export
+AbortProc(HDC hdcPrn, int code)
+{
+ process_interrupts();
+ if (code == SP_OUTOFDISK)
+ return (FALSE); /* cancel job */
+ return(TRUE);
+}
+
+/* ------ Process message loop ------ */
+/*
+ * Check messages and interrupts; return true if interrupted.
+ * This is called frequently - it must be quick!
+ */
+int
+gp_check_interrupts(void)
+{
+ return (*pgsdll_callback)(GSDLL_POLL, NULL, 0);
+}
+
+/* ====== Generic platform procedures ====== */
+
+/* ------ Initialization/termination (from gp_itbc.c) ------ */
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{
+ win_init = 1;
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+ win_init = 0;
+ win_exit_status = exit_status;
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{
+ /* Use longjmp since exit would terminate caller */
+ /* setjmp code will check gs_exit_status */
+ longjmp(gsdll_env, gs_exit_status);
+}
+
+/* ------ Printer accessing ------ */
+
+/* Forward references */
+private int gp_printfile(P2(const char *, const char *));
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{
+ if (is_printer(fname))
+ { FILE *pfile;
+ /* Open a scratch file, which we will send to the */
+ /* actual printer in gp_close_printer. */
+ pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
+ win_prntmp, "wb");
+ return pfile;
+ }
+ else
+ return fopen(fname, (binary_mode ? "wb" : "w"));
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{
+ fclose(pfile);
+ if (!is_printer(fname))
+ return; /* a file, not a printer */
+
+ gp_printfile(win_prntmp, fname);
+ unlink(win_prntmp);
+}
+
+/* Printer abort procedure and progress/cancel dialog box */
+/* Used by Win32 and mswinprn device */
+
+HWND hDlgModeless;
+
+BOOL CALLBACK _export
+PrintAbortProc(HDC hdcPrn, int code)
+{
+ MSG msg;
+ while (hDlgModeless && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if (hDlgModeless || !IsDialogMessage(hDlgModeless,&msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ return(hDlgModeless!=0);
+}
+
+/* Modeless dialog box - Cancel printing */
+BOOL CALLBACK _export
+CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ SetWindowText(hDlg, szAppName);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ DestroyWindow(hDlg);
+ hDlgModeless = 0;
+ EndDialog(hDlg, 0);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#ifndef __WIN32__
+
+/* Windows does not provide API's in the SDK for writing directly to a */
+/* printer. Instead you are supposed to use the Windows printer drivers. */
+/* Ghostscript has its own printer drivers, so we need to use some API's */
+/* that are documented only in the Device Driver Adaptation Guide */
+/* that comes with the DDK. Prototypes taken from DDK <print.h> */
+DECLARE_HANDLE(HPJOB);
+
+HPJOB WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
+int WINAPI StartSpoolPage(HPJOB);
+int WINAPI EndSpoolPage(HPJOB);
+int WINAPI WriteSpool(HPJOB, LPSTR, int);
+int WINAPI CloseJob(HPJOB);
+int WINAPI DeleteJob(HPJOB, int);
+int WINAPI WriteDialog(HPJOB, LPSTR, int);
+int WINAPI DeleteSpoolPage(HPJOB);
+
+#endif /* WIN32 */
+
+/* Dialog box to select printer port */
+BOOL CALLBACK _export
+SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+LPSTR entry;
+ switch(message) {
+ case WM_INITDIALOG:
+ entry = (LPSTR)lParam;
+ while (*entry) {
+ SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM)entry);
+ entry += lstrlen(entry)+1;
+ }
+ SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM)0);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case SPOOL_PORT:
+#ifdef __WIN32__
+ if (HIWORD(wParam)
+#else
+ if (HIWORD(lParam)
+#endif
+ == LBN_DBLCLK)
+ PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
+ return FALSE;
+ case IDOK:
+ EndDialog(hDlg, 1+(int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
+ return TRUE;
+ case IDCANCEL:
+ EndDialog(hDlg, 0);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* return TRUE if queue looks like a valid printer name */
+int
+is_spool(const char *queue)
+{
+char *prefix = "\\\\spool"; /* 7 characters long */
+int i;
+ for (i=0; i<7; i++) {
+ if (prefix[i] == '\\') {
+ if ((*queue != '\\') && (*queue != '/'))
+ return FALSE;
+ }
+ else if (tolower(*queue) != prefix[i])
+ return FALSE;
+ queue++;
+ }
+ if (*queue && (*queue != '\\') && (*queue != '/'))
+ return FALSE;
+ return TRUE;
+}
+
+
+private int
+is_printer(const char *name)
+{
+char buf[128];
+ /* is printer if no name given */
+ if (strlen(name) == 0)
+ return TRUE;
+
+ /* is printer if name appears in win.ini [ports] section */
+ GetProfileString("ports", name, "XYZ", buf, sizeof(buf));
+ if ( strlen(name) == 0 || strcmp(buf,"XYZ"))
+ return TRUE;
+
+ /* is printer if name prefixed by \\spool\ */
+ if ( is_spool(name) )
+ return TRUE;
+
+ return FALSE;
+}
+
+#ifdef __WIN32__ /* ******** WIN32 ******** */
+
+/******************************************************************/
+/* Print File to port or queue */
+/* port==NULL means prompt for port or queue with dialog box */
+
+/* This is messy because Microsoft changed the spooler interface */
+/* between Window 3.1 and Windows 95/NT */
+/* and didn't provide the spooler interface in Win32s */
+
+/* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */
+private int gp_printfile_win32(const char *filename, char *port);
+
+/* Win32s: Pass to Win16 spooler via gs16spl.exe */
+private int gp_printfile_gs16spl(const char *filename, const char *port);
+
+
+/* valid values for pmport are:
+ * ""
+ * action: WinNT and Win95 use default queue, Win32s prompts for port
+ * "LPT1:" (or other port that appears in win.ini [ports]
+ * action: start gs16spl.exe to print to the port
+ * "\\spool\printer name"
+ * action: send to printer using WritePrinter (WinNT and Win95).
+ * action: translate to port name using win.ini [Devices]
+ * then use gs16spl.exe (Win32s).
+ * "\\spool"
+ * action: prompt for queue name then send to printer using
+ * WritePrinter (WinNT and Win95).
+ * action: prompt for port then use gs16spl.exe (Win32s).
+ *
+/* Print File */
+private int
+gp_printfile(const char *filename, const char *pmport)
+{
+ /* treat WinNT and Win95 differently to Win32s */
+ if (!is_win32s) {
+ if (strlen(pmport)==0) { /* get default printer */
+ char buf[256];
+ char *p;
+ /* WinNT stores default printer in registry and win.ini */
+ /* Win95 stores default printer in win.ini */
+ GetProfileString("windows", "device", "", buf, sizeof(buf));
+ if ( (p = strchr(buf, ',')) != NULL )
+ *p = '\0';
+ return gp_printfile_win32(filename, buf);
+ }
+ else if (is_spool(pmport)) {
+ if (strlen(pmport) >= 8)
+ return gp_printfile_win32(filename, (char *)pmport+8);
+ else
+ return gp_printfile_win32(filename, (char *)NULL);
+ }
+ else
+ return gp_printfile_gs16spl(filename, pmport);
+ }
+ else {
+ /* Win32s */
+ if (is_spool(pmport)) {
+ if (strlen(pmport) >= 8) {
+ /* extract port name from win.ini */
+ char driverbuf[256];
+ char *output;
+ GetProfileString("Devices", pmport+8, "", driverbuf, sizeof(driverbuf));
+ strtok(driverbuf, ",");
+ output = strtok(NULL, ",");
+ return gp_printfile_gs16spl(filename, output);
+ }
+ else
+ return gp_printfile_gs16spl(filename, (char *)NULL);
+ }
+ else
+ return gp_printfile_gs16spl(filename, pmport);
+ }
+}
+
+#define PRINT_BUF_SIZE 16384u
+#define PORT_BUF_SIZE 4096
+
+char *
+get_queues(void)
+{
+int i;
+DWORD count, needed;
+PRINTER_INFO_1 *prinfo;
+char *enumbuffer;
+char *buffer;
+char *p;
+ /* enumerate all available printers */
+ EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count);
+ if (needed == 0) {
+ /* no printers */
+ enumbuffer = malloc(4);
+ if (enumbuffer == (char *)NULL)
+ return NULL;
+ memset(enumbuffer, 0, 4);
+ return enumbuffer;
+ }
+ enumbuffer = malloc(needed);
+ if (enumbuffer == (char *)NULL)
+ return NULL;
+ if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE)enumbuffer, needed, &needed, &count)) {
+ char buf[256];
+ free(enumbuffer);
+ sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError());
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ return NULL;
+ }
+ prinfo = (PRINTER_INFO_1 *)enumbuffer;
+ if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) {
+ free(enumbuffer);
+ return NULL;
+ }
+ /* copy printer names to single buffer */
+ p = buffer;
+ for (i=0; i<count; i++) {
+ if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE- (p-buffer))) {
+ strcpy(p, prinfo[i].pName);
+ p += strlen(p) + 1;
+ }
+ }
+ *p = '\0'; /* double null at end */
+ free(enumbuffer);
+ return buffer;
+}
+
+
+char *
+get_ports(void)
+{
+char *buffer;
+#ifdef __WIN32__
+ if (!is_win32s)
+ return get_queues();
+#endif
+
+ if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL)
+ return NULL;
+ GetProfileString("ports", NULL, "", buffer, PORT_BUF_SIZE);
+ return buffer;
+}
+
+/* return TRUE if queuename available */
+/* return FALSE if cancelled or error */
+/* if queue non-NULL, use as suggested queue */
+BOOL
+get_queuename(char *portname, const char *queue)
+{
+char *buffer;
+char *p;
+int i, iport;
+
+ buffer = get_queues();
+ if (buffer == NULL)
+ return FALSE;
+ if ( (queue == (char *)NULL) || (strlen(queue)==0) ) {
+ /* select a queue */
+ iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND)NULL, SpoolDlgProc, (LPARAM)buffer);
+ if (!iport) {
+ free(buffer);
+ return FALSE;
+ }
+ p = buffer;
+ for (i=1; i<iport && strlen(p)!=0; i++)
+ p += lstrlen(p)+1;
+ /* prepend \\spool\ which is used by Ghostscript to distinguish */
+ /* real files from queues */
+ strcpy(portname, "\\\\spool\\");
+ strcat(portname, p);
+ }
+ else {
+ strcpy(portname, "\\\\spool\\");
+ strcat(portname, queue);
+ }
+
+ free(buffer);
+ return TRUE;
+}
+
+/* return TRUE if portname available */
+/* return FALSE if cancelled or error */
+/* if port non-NULL, use as suggested port */
+BOOL
+get_portname(char *portname, const char *port)
+{
+char *buffer;
+char *p;
+int i, iport;
+char filename[MAXSTR];
+ buffer = get_ports();
+ if (buffer == NULL)
+ return FALSE;
+ if ( (port == (char *)NULL) || (strlen(port)==0) ) {
+ if (buffer == (char *)NULL)
+ return FALSE;
+ /* select a port */
+ iport = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND)NULL, SpoolDlgProc, (LPARAM)buffer);
+ if (!iport) {
+ free(buffer);
+ return FALSE;
+ }
+ p = buffer;
+ for (i=1; i<iport && strlen(p)!=0; i++)
+ p += lstrlen(p)+1;
+ strcpy(portname, p);
+ }
+ else
+ strcpy(portname, port);
+
+ if (strlen(portname) == 0)
+ return FALSE;
+ if (strcmp(portname,"FILE:") == 0) {
+ OPENFILENAME ofn;
+ filename[0] = '\0';
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = (HWND)NULL;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename);
+ ofn.Flags = OFN_PATHMUSTEXIST;
+ if (!GetSaveFileName(&ofn)) {
+ free(buffer);
+ return FALSE;
+ }
+ strcpy(portname, filename);
+ }
+ free(buffer);
+ return TRUE;
+}
+
+
+/* True Win32 method, using OpenPrinter, WritePrinter etc. */
+private int
+gp_printfile_win32(const char *filename, char *port)
+{
+DWORD count;
+char *buffer;
+char portname[MAXSTR];
+FILE *f;
+HANDLE printer;
+DOC_INFO_1 di;
+DWORD written;
+
+ if (!get_queuename(portname, port))
+ return FALSE;
+ port = portname + 8; /* skip over \\spool\ */
+
+ if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
+ return FALSE;
+
+ if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
+ free(buffer);
+ return FALSE;
+ }
+
+ /* open a printer */
+ if (!OpenPrinter(port, &printer, NULL)) {
+ char buf[256];
+ sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError());
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ free(buffer);
+ return FALSE;
+ }
+ /* from here until ClosePrinter, should AbortPrinter on error */
+
+ di.pDocName = szAppName;
+ di.pOutputFile = NULL;
+ di.pDatatype = "RAW"; /* for available types see EnumPrintProcessorDatatypes */
+ if (!StartDocPrinter(printer, 1, (LPBYTE)&di)) {
+ char buf[256];
+ sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError());
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ AbortPrinter(printer);
+ free(buffer);
+ return FALSE;
+ }
+
+ /* copy file to printer */
+ while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
+ if (!WritePrinter(printer, (LPVOID)buffer, count, &written)) {
+ free(buffer);
+ fclose(f);
+ AbortPrinter(printer);
+ return FALSE;
+ }
+ }
+ fclose(f);
+ free(buffer);
+
+ if (!EndDocPrinter(printer)) {
+ char buf[256];
+ sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError());
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ AbortPrinter(printer);
+ return FALSE;
+ }
+
+ if (!ClosePrinter(printer)) {
+ char buf[256];
+ sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError());
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/* Start a 16-bit application gs16spl.exe to print a file */
+/* Intended for Win32s where 16-bit spooler functions are not available */
+/* and Win32 spooler functions are not implemented. */
+int
+gp_printfile_gs16spl(const char *filename, const char *port)
+{
+/* Get printer port list from win.ini */
+char portname[MAXSTR];
+HINSTANCE hinst;
+char command[MAXSTR];
+char *p;
+HWND hwndspl;
+
+ if (!get_portname(portname, port))
+ return FALSE;
+
+ /* get path to EXE - same as DLL */
+ GetModuleFileName(phInstance, command, sizeof(command));
+ if ((p = strrchr(command,'\\')) != (char *)NULL)
+ p++;
+ else
+ p = command;
+ *p = '\0';
+ sprintf(command+strlen(command), "gs16spl.exe %s %s",
+ portname, filename);
+
+ hinst = (HINSTANCE)WinExec(command, SW_SHOWNORMAL);
+ if (hinst < (HINSTANCE)HINSTANCE_ERROR)
+ { char buf[MAXSTR];
+ sprintf(buf, "Can't run: %s", command);
+ MessageBox((HWND)NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
+ return FALSE;
+ }
+
+ hwndspl = FindWindow(NULL, "GS Win32s/Win16 spooler");
+
+ while (IsWindow(hwndspl)) {
+ gp_check_interrupts();
+ }
+
+ return 0;
+}
+
+
+
+#else /* ******** !WIN32 ******** */
+
+/* Print File to port */
+private int
+gp_printfile(const char *filename, const char *pmport)
+{
+#define PRINT_BUF_SIZE 16384u
+char *buffer;
+char *portname;
+int i, port;
+FILE *f;
+DLGPROC lpfnSpoolProc;
+WORD count;
+DLGPROC lpfnCancelProc;
+int error = FALSE;
+long lsize;
+long ldone;
+char pcdone[20];
+MSG msg;
+HPJOB hJob;
+
+ if (is_spool(pmport) && (strlen(pmport) >= 8)) {
+ /* translate from printer name to port name */
+ char driverbuf[256];
+ GetProfileString("Devices", pmport+8, "", driverbuf, sizeof(driverbuf));
+ strtok(driverbuf, ",");
+ pmport = strtok(NULL, ",");
+ }
+
+ /* get list of ports */
+ if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
+ return FALSE;
+
+ if ( (strlen(pmport)==0) || (strcmp(pmport, "PRN")==0) ) {
+ GetProfileString("ports", NULL, "", buffer, PRINT_BUF_SIZE);
+ /* select a port */
+#ifdef __WIN32__
+ lpfnSpoolProc = (DLGPROC)SpoolDlgProc;
+#else
+#ifdef __DLL__
+ lpfnSpoolProc = (DLGPROC)GetProcAddress(phInstance, "SpoolDlgProc");
+#else
+ lpfnSpoolProc = (DLGPROC)MakeProcInstance((FARPROC)SpoolDlgProc, phInstance);
+#endif
+#endif
+ port = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND)NULL, lpfnSpoolProc, (LPARAM)buffer);
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)lpfnSpoolProc);
+#endif
+ if (!port) {
+ free(buffer);
+ return FALSE;
+ }
+ portname = buffer;
+ for (i=1; i<port && strlen(portname)!=0; i++)
+ portname += lstrlen(portname)+1;
+ }
+ else
+ portname = (char *)pmport; /* Print Manager port name already supplied */
+
+ if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
+ free(buffer);
+ return FALSE;
+ }
+ fseek(f, 0L, SEEK_END);
+ lsize = ftell(f);
+ if (lsize <= 0)
+ lsize = 1;
+ fseek(f, 0L, SEEK_SET);
+
+ hJob = OpenJob(portname, filename, (HPJOB)NULL);
+ switch ((int)hJob) {
+ case SP_APPABORT:
+ case SP_ERROR:
+ case SP_OUTOFDISK:
+ case SP_OUTOFMEMORY:
+ case SP_USERABORT:
+ fclose(f);
+ free(buffer);
+ return FALSE;
+ }
+ if (StartSpoolPage(hJob) < 0)
+ error = TRUE;
+
+#ifdef __WIN32__
+ lpfnCancelProc = (DLGPROC)CancelDlgProc;
+#else
+#ifdef __DLL__
+ lpfnCancelProc = (DLGPROC)GetProcAddress(phInstance, "CancelDlgProc");
+#else
+ lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
+#endif
+#endif
+ hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", (HWND)NULL, lpfnCancelProc);
+ ldone = 0;
+
+ while (!error && hDlgModeless
+ && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
+ if (WriteSpool(hJob, buffer, count) < 0)
+ error = TRUE;
+ ldone += count;
+ sprintf(pcdone, "%d %%done", (int)(ldone * 100 / lsize));
+ SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), pcdone);
+ while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
+ if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ free(buffer);
+ fclose(f);
+
+ if (!hDlgModeless)
+ error=TRUE;
+ DestroyWindow(hDlgModeless);
+ hDlgModeless = 0;
+#if !defined(__WIN32__) && !defined(__DLL__)
+ FreeProcInstance((FARPROC)lpfnCancelProc);
+#endif
+ EndSpoolPage(hJob);
+ if (error)
+ DeleteJob(hJob, 0);
+ else
+ CloseJob(hJob);
+ return !error;
+}
+
+#endif /* ******** (!)WIN32 ******** */
+
+/* ------ File naming and accessing ------ */
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ char *temp;
+ if ( (temp = getenv("TEMP")) == NULL )
+ *fname = 0;
+ else
+ { strcpy(fname, temp);
+ /* Prevent X's in path from being converted by mktemp. */
+ for ( temp = fname; *temp; temp++ )
+ *temp = tolower(*temp);
+ if ( strlen(fname) && (fname[strlen(fname)-1] != '\\') )
+ strcat(fname, "\\");
+ }
+ strcat(fname, prefix);
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{ return fopen(fname, mode);
+}
+
diff --git a/gs/src/gp_mswin.h b/gs/src/gp_mswin.h
new file mode 100644
index 000000000..384d0fa08
--- /dev/null
+++ b/gs/src/gp_mswin.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_mswin.h */
+/* Definitions common to MS Windows implementation */
+/* (used by both C code and Windows 'resource') */
+
+#define GSTEXT_ICON 50
+#define GSIMAGE_ICON 51
+#define SPOOL_PORT 100
+#define CANCEL_PCDONE 101
+#define CANCEL_PRINTING 102
+
+#ifndef RC_INVOKED /* NOTA BENE */
+
+/* system menu constants for image window */
+#define M_COPY_CLIP 1
+
+/* externals from gp_mswin.c */
+
+/* Patch 26.10.94 :for Microsoft C/C++ 8.0 32-Bit */
+/* "_export" is Microsoft 16-Bit specific. */
+/* With MS-C/C++ 8.00 32 Bit "_export" causes an error. */
+#if defined(_WIN32) && defined(_MSC_VER)
+#define _export
+#endif
+
+extern HWND hwndtext;
+extern HWND hDlgModeless;
+extern HINSTANCE phInstance;
+extern const LPSTR szAppName;
+extern BOOL is_win32s;
+extern BOOL CALLBACK _export AbortProc(HDC, int);
+extern BOOL CALLBACK _export CancelDlgProc(HWND, UINT, WPARAM, LPARAM);
+extern int is_spool(const char *queue);
+
+#endif /* !defined(RC_INVOKED) */
diff --git a/gs/src/gp_nofb.c b/gs/src/gp_nofb.c
new file mode 100644
index 000000000..5c58bea40
--- /dev/null
+++ b/gs/src/gp_nofb.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_nofb.c */
+/* Dummy routines for Ghostscript platforms with no frame buffer management */
+#include "gx.h"
+#include "gp.h"
+#include "gxdevice.h"
+
+/* ------ Screen management ------ */
+
+/* Initialize the console. */
+void
+gp_init_console(void)
+{
+}
+
+/* Write a string to the console. */
+void
+gp_console_puts(const char *str, uint size)
+{ fwrite(str, 1, size, stdout);
+}
+
+/* Make the console current on the screen. */
+int
+gp_make_console_current(gx_device *dev)
+{ return 0;
+}
+
+/* Make the graphics current on the screen. */
+int
+gp_make_graphics_current(gx_device *dev)
+{ return 0;
+}
diff --git a/gs/src/gp_ntfs.c b/gs/src/gp_ntfs.c
new file mode 100644
index 000000000..4e438eb91
--- /dev/null
+++ b/gs/src/gp_ntfs.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 1992, 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_ntfs.c */
+/* file system stuff for MS-Windows WIN32 and MS-Windows NT*/
+/* hacked from gp_dosfs.c by Russell Lang */
+
+#include "stdio_.h"
+#include <fcntl.h>
+#include "dos_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gp.h"
+#include "gsutil.h"
+#include "windows_.h"
+
+/* ------ Printer accessing ------ */
+
+/* Put a printer file (which might be stdout) into binary or text mode. */
+/* This is not a standard gp procedure, */
+/* but all MS-DOS configurations need it. */
+void
+gp_set_printer_binary(int prnfno, int binary)
+{
+ /* UNIMPLEMENTED */
+}
+
+/* ------ File names ------ */
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ';';
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "b";
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "rb";
+const char gp_fmode_wb[] = "wb";
+
+/* Answer whether a file name contains a directory/device specification, */
+/* i.e. is absolute (not directory- or device-relative). */
+bool
+gp_file_name_is_absolute(const char *fname, uint len)
+{ /* A file name is absolute if it contains a drive specification */
+ /* (second character is a :) or if it start with 0 or more .s */
+ /* followed by a / or \. */
+ if ( len >= 2 && fname[1] == ':' )
+ return true;
+ while ( len && *fname == '.' )
+ ++fname, --len;
+ return (len && (*fname == '/' || *fname == '\\'));
+}
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *
+gp_file_name_concat_string(const char *prefix, uint plen,
+ const char *fname, uint len)
+{ if ( plen > 0 )
+ switch ( prefix[plen - 1] )
+ { case ':': case '/': case '\\': return "";
+ };
+ return "\\";
+}
+
+/* ------ File enumeration ------ */
+
+struct file_enum_s {
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+ char *pattern; /* orig pattern + modified pattern */
+ int patlen; /* orig pattern length */
+ int pat_size; /* allocate space for pattern */
+ int head_size; /* pattern length through last */
+ /* :, / or \ */
+ int first_time;
+ gs_memory_t *memory;
+};
+gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
+ file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
+
+/* Initialize an enumeration. Note that * and ? in a directory */
+/* don't work, and \ is taken literally unless a second \ follows. */
+file_enum *
+gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem)
+{ file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
+ int pat_size = 2 * patlen + 1;
+ char *pattern;
+ int hsize = 0;
+ int i;
+ if ( pfen == 0 ) return 0;
+
+ /* pattern could be allocated as a string, */
+ /* but it's simpler for GC and freeing to allocate it as bytes. */
+
+ pattern = (char *)gs_alloc_bytes(mem, pat_size,
+ "gp_enumerate_files(pattern)");
+ if ( pattern == 0 ) return 0;
+ memcpy(pattern, pat, patlen);
+ /* find directory name = header */
+ for ( i = 0; i < patlen; i++ )
+ { switch ( pat[i] )
+ {
+ case '\\':
+ if ( i + 1 < patlen && pat[i + 1] == '\\' )
+ i++;
+ /* falls through */
+ case ':':
+ case '/':
+ hsize = i + 1;
+ }
+ }
+ pattern[patlen] = 0;
+ pfen->pattern = pattern;
+ pfen->patlen = patlen;
+ pfen->pat_size = pat_size;
+ pfen->head_size = hsize;
+ pfen->memory = mem;
+ pfen->first_time = 1;
+ memset(&pfen->find_data, 0, sizeof(pfen->find_data));
+ pfen->find_handle = INVALID_HANDLE_VALUE;
+ return pfen;
+}
+
+/* Enumerate the next file. */
+uint
+gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
+{ int code = 0;
+ uint len;
+top: if ( pfen->first_time )
+ {
+ pfen->find_handle = FindFirstFile(pfen->pattern, &(pfen->find_data));
+ if (pfen->find_handle == INVALID_HANDLE_VALUE)
+ code = -1;
+ pfen->first_time = 0;
+ }
+ else
+ {
+ if (!FindNextFile(pfen->find_handle, &(pfen->find_data)))
+ code = -1;
+ }
+ if ( code != 0 )
+ { /* All done, clean up. */
+ gp_enumerate_files_close(pfen);
+ return ~(uint)0;
+ }
+
+ len = strlen(pfen->find_data.cFileName);
+
+ if (pfen->head_size + len < maxlen) {
+ memcpy(ptr, pfen->pattern, pfen->head_size);
+ strcpy(ptr + pfen->head_size, pfen->find_data.cFileName);
+ return pfen->head_size + len;
+ }
+
+ if (pfen->head_size >= maxlen)
+ return 0; /* no hope at all */
+
+ memcpy(ptr, pfen->pattern, pfen->head_size);
+ strncpy(ptr + pfen->head_size, pfen->find_data.cFileName,
+ maxlen - pfen->head_size - 1);
+ return maxlen;
+}
+
+/* Clean up the file enumeration. */
+void
+gp_enumerate_files_close(file_enum *pfen)
+{ gs_memory_t *mem = pfen->memory;
+ if (pfen->find_handle != INVALID_HANDLE_VALUE)
+ FindClose(pfen->find_handle);
+ gs_free_object(mem, pfen->pattern,
+ "gp_enumerate_files_close(pattern)");
+ gs_free_object(mem, pfen, "gp_enumerate_files_close");
+}
diff --git a/gs/src/gp_os2.c b/gs/src/gp_os2.c
new file mode 100644
index 000000000..09b82dc81
--- /dev/null
+++ b/gs/src/gp_os2.c
@@ -0,0 +1,907 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_os2.c */
+/* Common platform-specific routines for OS/2 and MS-DOS */
+/* compiled with GCC/EMX */
+
+#define INCL_DOS
+#define INCL_SPL
+#define INCL_SPLDOSPRINT
+#define INCL_SPLERRORS
+#define INCL_BASE
+#define INCL_ERRORS
+#define INCL_WIN
+#include <os2.h>
+
+#include "stdio_.h"
+#include "string_.h"
+#include <fcntl.h>
+
+#ifdef __IBMC__
+#define popen fopen /* doesn't support popen */
+#define pclose fclose /* doesn't support pclose */
+#else
+#include <dos.h>
+#endif
+/* Define the regs union tag for short registers. */
+# define rshort x
+#define intdos(a,b) _int86(0x21, a, b)
+
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gsexit.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gp.h"
+#include "gsutil.h"
+#include "stdlib.h" /* need _osmode, exit */
+#include "time_.h"
+#include <time.h> /* should this be in time_.h? */
+#include "gdevpm.h"
+#ifdef __EMX__
+#include <sys/emxload.h>
+#endif
+
+#if defined(__DLL__) && defined( __EMX__)
+/* This isn't provided in any of the libraries */
+/* We set this to the process environment in gp_init */
+char *fake_environ[3] = {"", NULL, NULL};
+char **environ = fake_environ;
+char **_environ = fake_environ;
+HWND hwndtext = (HWND)NULL;
+#endif
+
+#ifdef __DLL__
+/* use longjmp instead of exit when using DLL */
+#include <setjmp.h>
+extern jmp_buf gsdll_env;
+#endif
+
+#ifdef __DLL__
+#define isos2 TRUE
+#else
+#define isos2 (_osmode == OS2_MODE)
+#endif
+char pm_prntmp[256]; /* filename of printer spool temporary file */
+
+
+/* ------ Miscellaneous ------ */
+
+/* Get the string corresponding to an OS error number. */
+/* All reasonable compilers support it. */
+const char *
+gp_strerror(int errnum)
+{ return strerror(errnum);
+}
+
+/* use Unix version for date and time */
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1970) */
+/* and fraction (in nanoseconds since midnight). */
+void
+gp_get_realtime(long *pdt)
+{ struct timeval tp;
+ struct timezone tzp;
+
+ if ( gettimeofday(&tp, &tzp) == -1 )
+ { lprintf("Ghostscript: gettimeofday failed!\n");
+ gs_exit(1);
+ }
+
+ /* tp.tv_sec is #secs since Jan 1, 1970 */
+ pdt[0] = tp.tv_sec;
+ pdt[1] = tp.tv_usec * 1000;
+
+#ifdef DEBUG_CLOCK
+ printf("tp.tv_sec = %d tp.tv_usec = %d pdt[0] = %ld pdt[1] = %ld\n",
+ tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]);
+#endif
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ gp_get_realtime(pdt); /* Use an approximation for now. */
+}
+
+
+/* ------ Console management ------ */
+
+/* Answer whether a given file is the console (input or output). */
+/* This is not a standard gp procedure, */
+/* but the MS Windows configuration needs it, */
+/* and other MS-DOS configurations might need it someday. */
+/* Don't know if it is needed for OS/2. */
+bool
+gp_file_is_console(FILE *f)
+{
+#ifndef __DLL__
+ if (!isos2) {
+ union REGS regs;
+ if ( f == NULL )
+ return false;
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 0; /* get device info */
+ regs.rshort.bx = fileno(f);
+ intdos(&regs, &regs);
+ return ((regs.h.dl & 0x80) != 0 && (regs.h.dl & 3) != 0);
+ }
+#endif
+ if ( (f==stdin) || (f==stdout) || (f==stderr) )
+ return true;
+ return false;
+}
+
+/* ------ File naming and accessing ------ */
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ';';
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "gs";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "nul";
+
+/* Define the name that designates the current directory. */
+const char gp_current_directory_name[] = ".";
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "b";
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "rb";
+const char gp_fmode_wb[] = "wb";
+
+/* Answer whether a file name contains a directory/device specification, */
+/* i.e. is absolute (not directory- or device-relative). */
+bool
+gp_file_name_is_absolute(const char *fname, uint len)
+{ /* A file name is absolute if it contains a drive specification */
+ /* (second character is a :) or if it start with 0 or more .s */
+ /* followed by a / or \. */
+ if ( len >= 2 && fname[1] == ':' )
+ return true;
+ while ( len && *fname == '.' )
+ ++fname, --len;
+ return (len && (*fname == '/' || *fname == '\\'));
+}
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *
+gp_file_name_concat_string(const char *prefix, uint plen,
+ const char *fname, uint len)
+{ if ( plen > 0 )
+ switch ( prefix[plen - 1] )
+ { case ':': case '/': case '\\': return "";
+ };
+ return "\\";
+}
+
+
+/* ------ File enumeration ------ */
+
+
+struct file_enum_s {
+ FILEFINDBUF3 findbuf;
+ HDIR hdir;
+ char *pattern;
+ int patlen; /* orig pattern length */
+ int pat_size; /* allocate space for pattern */
+ int head_size; /* pattern length through last */
+ /* :, / or \ */
+ int first_time;
+ gs_memory_t *memory;
+};
+gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
+ file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
+
+/* Initialize an enumeration. may NEED WORK ON HANDLING * ? \. */
+file_enum *
+gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem)
+{ file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
+ int pat_size = 2 * patlen + 1;
+ char *pattern;
+ int hsize = 0;
+ int i;
+ if ( pfen == 0 ) return 0;
+
+ /* pattern could be allocated as a string, */
+ /* but it's simpler for GC and freeing to allocate it as bytes. */
+
+ pattern = (char *)gs_alloc_bytes(mem, pat_size,
+ "gp_enumerate_files(pattern)");
+ if ( pattern == 0 ) return 0;
+ memcpy(pattern, pat, patlen);
+ /* find directory name = header */
+ for ( i = 0; i < patlen; i++ )
+ { switch ( pat[i] )
+ {
+ case '\\':
+ if ( i + 1 < patlen && pat[i + 1] == '\\' )
+ i++;
+ /* falls through */
+ case ':':
+ case '/':
+ hsize = i + 1;
+ }
+ }
+ pattern[patlen] = 0;
+ pfen->pattern = pattern;
+ pfen->patlen = patlen;
+ pfen->pat_size = pat_size;
+ pfen->head_size = hsize;
+ pfen->memory = mem;
+ pfen->first_time = 1;
+ pfen->hdir = HDIR_CREATE;
+ return pfen;
+}
+
+/* Enumerate the next file. */
+uint
+gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
+{
+ APIRET rc;
+ ULONG cFilenames = 1;
+ if (!isos2) {
+ /* CAN'T DO IT SO JUST RETURN THE PATTERN. */
+ if ( pfen->first_time )
+ { char *pattern = pfen->pattern;
+ uint len = strlen(pattern);
+ pfen->first_time = 0;
+ if ( len > maxlen )
+ return maxlen + 1;
+ strcpy(ptr, pattern);
+ return len;
+ }
+ return -1;
+ }
+
+ /* else OS/2 */
+ if ( pfen->first_time ) {
+ rc = DosFindFirst(pfen->pattern, &pfen->hdir, FILE_NORMAL,
+ &pfen->findbuf, sizeof(pfen->findbuf),
+ &cFilenames, FIL_STANDARD);
+ pfen->first_time = 0;
+ }
+ else {
+ rc = DosFindNext(pfen->hdir, &pfen->findbuf, sizeof(pfen->findbuf),
+ &cFilenames);
+ }
+ if (rc)
+ return -1;
+
+ if (pfen->head_size + pfen->findbuf.cchName < maxlen) {
+ memcpy(ptr, pfen->pattern, pfen->head_size);
+ strcpy(ptr + pfen->head_size, pfen->findbuf.achName);
+ return pfen->head_size + pfen->findbuf.cchName;
+ }
+
+ if (pfen->head_size >= maxlen)
+ return 0; /* no hope at all */
+
+ memcpy(ptr, pfen->pattern, pfen->head_size);
+ strncpy(ptr + pfen->head_size, pfen->findbuf.achName,
+ maxlen - pfen->head_size - 1);
+ return maxlen;
+}
+
+/* Clean up the file enumeration. */
+void
+gp_enumerate_files_close(file_enum *pfen)
+{
+ gs_memory_t *mem = pfen->memory;
+ if (isos2)
+ DosFindClose(pfen->hdir);
+ gs_free_object(mem, pfen->pattern,
+ "gp_enumerate_files_close(pattern)");
+ gs_free_object(mem, pfen, "gp_enumerate_files_close");
+}
+
+/*************************************************************/
+/* from gp_iwatc.c and gp_itbc.c */
+
+/* Intel processor, EMX/GCC specific routines for Ghostscript */
+#include <signal.h>
+#include "stat_.h"
+#include "string_.h"
+
+/* Library routines not declared in a standard header */
+/* extern char *getenv(P1(const char *)); */
+
+/* Forward declarations */
+private void handle_FPE(P1(int));
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{
+#if defined(__DLL__) && defined(__EMX__)
+ PTIB pptib;
+ PPIB pppib;
+ int i;
+ char *p;
+ /* get environment of EXE */
+ DosGetInfoBlocks(&pptib, &pppib);
+ for (i=0, p=pppib->pib_pchenv; *p; p+=strlen(p)+1)
+ i++;
+ _environ = environ = (char **)malloc((i+2) * sizeof(char *));
+ for (i=0, p=pppib->pib_pchenv; *p; p+=strlen(p)+1) {
+ environ[i] = p;
+ i++;
+ }
+ environ[i] = p;
+ i++;
+ environ[i] = NULL;
+#endif
+
+ /* keep gsos2.exe in memory for number of minutes specified in */
+ /* environment variable GS_LOAD */
+#ifdef __EMX__
+ _emxload_env("GS_LOAD");
+#endif
+ /* Set up the handler for numeric exceptions. */
+ signal(SIGFPE, handle_FPE);
+ gp_init_console();
+}
+
+
+/* Trap numeric exceptions. Someday we will do something */
+/* more appropriate with these. */
+private void
+handle_FPE(int sig)
+{ eprintf("Numeric exception:\n");
+ exit(1);
+}
+
+extern int gs_exit_status;
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+#ifndef __DLL__
+ if (exit_status && (_osmode == OS2_MODE))
+ DosSleep(2000);
+#endif
+#if defined(__DLL__) && defined(__EMX__)
+ if (environ != fake_environ) {
+ free(environ);
+ environ = _environ = fake_environ;
+ }
+#endif
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{
+#if defined(__DLL__)
+ /* Use longjmp since exit would terminate caller */
+ /* setjmp code will check gs_exit_status */
+ longjmp(gsdll_env, gs_exit_status);
+#else
+ exit(exit_status);
+#endif
+}
+
+/* ------ Printer accessing ------ */
+private int pm_find_queue(char *queue_name, char *driver_name);
+private int is_os2_spool(const char *queue);
+private int pm_spool(char *filename, const char *queue);
+
+/* Put a printer file (which might be stdout) into binary or text mode. */
+/* This is not a standard gp procedure, */
+/* but all MS-DOS configurations need it. */
+void
+gp_set_printer_binary(int prnfno, int binary)
+{
+#ifndef __IBMC__
+ union REGS regs;
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 0; /* get device info */
+ regs.rshort.bx = prnfno;
+ intdos(&regs, &regs);
+ if ( ((regs.rshort.flags)&1) != 0 || !(regs.h.dl & 0x80) )
+ return; /* error, or not a device */
+ if ( binary )
+ regs.h.dl |= 0x20; /* binary (no ^Z intervention) */
+ else
+ regs.h.dl &= ~0x20; /* text */
+ regs.h.dh = 0;
+ regs.h.ah = 0x44; /* ioctl */
+ regs.h.al = 1; /* set device info */
+ intdos(&regs, &regs);
+#endif
+}
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+/* filename can be one of the following values
+ * "" Spool in default queue
+ * "\\spool\queue" Spool in "queue"
+ * "|command" open an output pipe using popen()
+ * "filename" open filename using fopen()
+ * "port" open port using fopen()
+ */
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ FILE *pfile;
+ if ( (strlen(fname) == 0) || is_os2_spool(fname) ) {
+ if (isos2) {
+ /* default or spool */
+ if (pm_spool(NULL, fname)) /* check if spool queue valid */
+ return NULL;
+ pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
+ pm_prntmp, (binary_mode ? "wb" : "w"));
+ }
+ else
+ pfile = fopen("PRN", (binary_mode ? "wb" : "w"));
+ }
+ else if ( (isos2) && (fname[0] == '|') )
+ /* pipe */
+ pfile = popen(fname+1, (binary_mode ? "wb" : "w"));
+ else
+ /* normal file or port */
+ pfile = fopen(fname, (binary_mode ? "wb" : "w"));
+
+ if ( pfile == (FILE *)NULL )
+ return (FILE *)NULL;
+ if (!isos2)
+ gp_set_printer_binary(fileno(pfile), binary_mode);
+ return pfile;
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{
+ if ( isos2 && (fname[0] == '|') )
+ pclose(pfile);
+ else
+ fclose(pfile);
+
+ if ( (strlen(fname) == 0) || is_os2_spool(fname) ) {
+ /* spool temporary file */
+ pm_spool(pm_prntmp, fname);
+ unlink(pm_prntmp);
+ }
+}
+
+/* ------ Printer Spooling ------ */
+#ifndef NERR_BufTooSmall
+#define NERR_BufTooSmall 2123 /* For SplEnumQueue */
+#endif
+
+/* If queue_name is NULL, list available queues */
+/* If strlen(queue_name)==0, return default queue and driver name */
+/* If queue_name supplied, return driver_name */
+/* returns 0 if OK, non-zero for error */
+private int
+pm_find_queue(char *queue_name, char *driver_name)
+{
+ SPLERR splerr;
+ USHORT jobCount;
+ ULONG cbBuf;
+ ULONG cTotal;
+ ULONG cReturned;
+ ULONG cbNeeded;
+ ULONG ulLevel;
+ ULONG i;
+ PSZ pszComputerName;
+ PBYTE pBuf;
+ PPRQINFO3 prq;
+
+ ulLevel = 3L;
+ pszComputerName = (PSZ)NULL ;
+ splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L, /* cbBuf */
+ &cReturned, &cTotal,
+ &cbNeeded, NULL);
+ if ( splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall ) {
+ if (!DosAllocMem( (PVOID)&pBuf, cbNeeded,
+ PAG_READ|PAG_WRITE|PAG_COMMIT) ) {
+ cbBuf = cbNeeded ;
+ splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
+ &cReturned, &cTotal,
+ &cbNeeded, NULL);
+ if (splerr == NO_ERROR) {
+ /* Set pointer to point to the beginning of the buffer. */
+ prq = (PPRQINFO3)pBuf ;
+
+ /* cReturned has the count of the number of PRQINFO3 structures. */
+ for (i=0;i < cReturned ; i++) {
+ if (queue_name) {
+ /* find queue name and return driver name */
+ if (strlen(queue_name)==0) { /* use default queue */
+ if ( prq->fsType & PRQ3_TYPE_APPDEFAULT )
+ strcpy(queue_name, prq->pszName);
+ }
+ if (strcmp(prq->pszName, queue_name) == 0) {
+ char *p;
+ for (p=prq->pszDriverName; *p && (*p!='.'); p++)
+ /* do nothing */ ;
+ *p = '\0'; /* truncate at '.' */
+ if (driver_name != NULL)
+ strcpy(driver_name, prq->pszDriverName);
+ DosFreeMem((PVOID)pBuf) ;
+ return 0;
+ }
+ }
+ else {
+ /* list queue details */
+ if ( prq->fsType & PRQ3_TYPE_APPDEFAULT )
+ fprintf(stdout, " %s (DEFAULT)\n", prq->pszName) ;
+ else
+ fprintf(stdout, " %s\n", prq->pszName) ;
+ }
+ prq++;
+ }/*endfor cReturned */
+ }
+ DosFreeMem((PVOID)pBuf) ;
+ }
+ } /* end if Q level given */
+ else {
+ /* If we are here we had a bad error code. Print it and some other info.*/
+ fprintf(stdout, "SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
+ splerr, cTotal, cReturned, cbNeeded) ;
+ }
+ if (splerr)
+ return splerr;
+ if (queue_name)
+ return -1;
+ return 0;
+}
+
+
+/* return TRUE if queue looks like a valid OS/2 queue name */
+private int
+is_os2_spool(const char *queue)
+{
+char *prefix = "\\\\spool\\"; /* 8 characters long */
+int i;
+ for (i=0; i<8; i++) {
+ if (prefix[i] == '\\') {
+ if ((*queue != '\\') && (*queue != '/'))
+ return FALSE;
+ }
+ else if (tolower(*queue) != prefix[i])
+ return FALSE;
+ queue++;
+ }
+ return TRUE;
+}
+
+#define PRINT_BUF_SIZE 16384
+
+/* Spool file to queue */
+/* return 0 if successful, non-zero if error */
+/* if filename is NULL, return 0 if spool queue is valid, non-zero if error */
+private int
+pm_spool(char *filename, const char *queue)
+{
+HSPL hspl;
+PDEVOPENSTRUC pdata;
+PSZ pszToken = "*";
+ULONG jobid;
+BOOL rc;
+char queue_name[256];
+char driver_name[256];
+char *buffer;
+FILE *f;
+int count;
+ if (strlen(queue)!= 0) {
+ /* queue specified */
+ strcpy(queue_name, queue+8); /* skip over \\spool\ */
+ }
+ else {
+ /* get default queue */
+ queue_name[0] = '\0';
+ }
+ if (pm_find_queue(queue_name, driver_name)) {
+ /* error, list valid queue names */
+ fprintf(stdout, "Invalid queue name. Use one of:\n");
+ pm_find_queue(NULL,NULL);
+ return 1;
+ }
+ if (!filename)
+ return 0; /* we were only asked to check the queue */
+
+
+ if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL) {
+ fprintf(stdout, "Out of memory in pm_spool\n");
+ return 1;
+ }
+ if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
+ free(buffer);
+ fprintf(stdout, "Can't open temporary file %s\n", filename);
+ return 1;
+ }
+
+ /* Allocate memory for pdata */
+ if ( !DosAllocMem( (PVOID)&pdata,sizeof( DEVOPENSTRUC ),
+ (PAG_READ|PAG_WRITE|PAG_COMMIT ) ) ) {
+ /* Initialize elements of pdata */
+ pdata->pszLogAddress = queue_name;
+ pdata->pszDriverName = driver_name;
+ pdata->pdriv = NULL;
+ pdata->pszDataType = "PM_Q_RAW";
+ pdata->pszComment = "Ghostscript";
+ pdata->pszQueueProcName = NULL;
+ pdata->pszQueueProcParams = NULL;
+ pdata->pszSpoolerParams = NULL;
+ pdata->pszNetworkParams = NULL;
+
+ hspl = SplQmOpen( pszToken,4L,( PQMOPENDATA )pdata );
+ if ( hspl == SPL_ERROR ) {
+ fprintf(stdout, "SplQmOpen failed.\n");
+ DosFreeMem((PVOID)pdata);
+ free(buffer);
+ fclose(f);
+ return 1; /* failed */
+ }
+
+ rc = SplQmStartDoc(hspl, "Ghostscript");
+ if (!rc) {
+ fprintf(stdout, "SplQmStartDoc failed.\n");
+ DosFreeMem((PVOID)pdata);
+ free(buffer);
+ fclose(f);
+ return 1;
+ }
+
+ /* loop, copying file to queue */
+ while (rc && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
+ rc = SplQmWrite(hspl, count, buffer);
+ if (!rc)
+ fprintf(stdout, "SplQmWrite failed.\n");
+ }
+ free(buffer);
+ fclose(f);
+
+ if (!rc) {
+ fprintf(stdout, "Aborting Spooling.\n");
+ SplQmAbort(hspl);
+ }
+ else {
+ SplQmEndDoc(hspl);
+ rc = SplQmClose(hspl);
+ if (!rc)
+ fprintf(stdout, "SplQmClose failed.\n");
+ }
+ }
+ else
+ rc = 0; /* no memory */
+ return !rc;
+}
+
+/* ------ File naming and accessing ------ */
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ char *temp;
+#ifdef __IBMC__
+ char *tname;
+ *fname = 0;
+ temp = getenv("TEMP");
+ tname = _tempnam(temp, (char *)prefix);
+ if (tname) {
+ strcpy(fname, tname);
+ free(tname);
+ }
+#else
+ if ( (temp = getenv("TEMP")) == NULL )
+ *fname = 0;
+ else
+ { char last = '\\';
+ strcpy(fname, temp);
+ /* Prevent X's in path from being converted by mktemp. */
+ for ( temp = fname; *temp; temp++ )
+ *temp = last = tolower(*temp);
+ switch ( last )
+ {
+ default:
+ strcat(fname, "\\");
+ case ':': case '\\':
+ ;
+ }
+ }
+ strcat(fname, prefix);
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+#endif
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{ return fopen(fname, mode);
+}
+
+#ifdef __DLL__
+
+/* The DLL version must not be allowed direct access to stdin and stdout */
+/* Instead these are redirected to the gsdll_callback */
+#include "gsdll.h"
+#include <stdarg.h>
+
+/* for redirecting stdin/out/err */
+#include "stream.h"
+#include "gxiodev.h" /* must come after stream.h */
+
+
+/* ====== Substitute for stdio ====== */
+
+/* this code has been derived from gp_mswin.c */
+
+/* Forward references */
+private stream_proc_process(pm_std_read_process);
+private stream_proc_process(pm_std_write_process);
+
+/* Use a pseudo IODevice to get pm_stdio_init called at the right time. */
+/* This is bad architecture; we'll fix it later. */
+private iodev_proc_init(pm_stdio_init);
+gx_io_device gs_iodev_wstdio = {
+ "wstdio", "Special",
+ { pm_stdio_init, iodev_no_open_device,
+ iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file,
+ iodev_no_file_status, iodev_no_enumerate_files
+ }
+};
+
+/* Discard the contents of the buffer when reading. */
+void
+pm_std_read_reset(stream *s)
+{ s_std_read_reset(s);
+ s->end_status = 0;
+}
+
+/* Define alternate 'open' routines for our stdin/out/err streams. */
+
+extern int iodev_stdin_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+pm_stdin_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdin_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.reset = pm_std_read_reset;
+ s->procs.process = pm_std_read_process;
+ s->file = NULL;
+ return 0;
+}
+
+extern int iodev_stdout_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+pm_stdout_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdout_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.process = pm_std_write_process;
+ s->file = NULL;
+ return 0;
+}
+
+extern int iodev_stderr_open(P4(gx_io_device *, const char *, stream **,
+ gs_memory_t *));
+private int
+pm_stderr_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stderr_open(iodev, access, ps, mem);
+ stream *s = *ps;
+ if ( code != 1 )
+ return code;
+ s->procs.process = pm_std_write_process;
+ s->file = NULL;
+ return 0;
+}
+
+/* Patch stdin/out/err to use our windows. */
+private int
+pm_stdio_init(gx_io_device *iodev, gs_memory_t *mem)
+{
+ /* If stdxxx is the console, replace the 'open' routines, */
+ /* which haven't gotten called yet. */
+
+ if ( gp_file_is_console(gs_stdin) )
+ gs_findiodevice((const byte *)"%stdin", 6)->procs.open_device =
+ pm_stdin_open;
+
+ if ( gp_file_is_console(gs_stdout) )
+ gs_findiodevice((const byte *)"%stdout", 7)->procs.open_device =
+ pm_stdout_open;
+
+ if ( gp_file_is_console(gs_stderr) )
+ gs_findiodevice((const byte *)"%stderr", 7)->procs.open_device =
+ pm_stderr_open;
+
+ return 0;
+}
+
+
+/* We should really use a private buffer for line reading, */
+/* because we can't predict the size of the supplied input area.... */
+private int
+pm_std_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{
+ int count = pw->limit - pw->ptr;
+
+ if ( count == 0 ) /* empty buffer */
+ return 1;
+
+ /* callback to get more input */
+ count = (*pgsdll_callback)(GSDLL_STDIN, pw->ptr+1, count);
+ if (count == 0) {
+ /* EOF */
+ /* what should we do? */
+ return EOFC;
+ }
+
+ pw->ptr += count;
+ return 1;
+}
+
+private int
+pm_std_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ uint count = pr->limit - pr->ptr;
+ (*pgsdll_callback)(GSDLL_STDOUT, (char *)(pr->ptr + 1), count);
+ pr->ptr = pr->limit;
+ return 0;
+}
+
+/* This is used instead of the stdio version. */
+/* The declaration must be identical to that in <stdio.h>. */
+#ifdef __EMX__
+int
+fprintf(FILE *file, __const__ char *fmt, ...)
+#else
+int
+fprintf(FILE *file, const char *fmt, ...)
+#endif
+{
+int count;
+va_list args;
+ va_start(args,fmt);
+ if ( gp_file_is_console(file) ) {
+ char buf[1024];
+ count = vsprintf(buf,fmt,args);
+ (*pgsdll_callback)(GSDLL_STDOUT, buf, count);
+ }
+ else {
+ count = vfprintf(file, fmt, args);
+ }
+ va_end(args);
+ return count;
+}
+#endif /* __DLL__ */
+
diff --git a/gs/src/gp_os9.c b/gs/src/gp_os9.c
new file mode 100644
index 000000000..222f8e084
--- /dev/null
+++ b/gs/src/gp_os9.c
@@ -0,0 +1,138 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_os9.c */
+/* OSK-specific routines for Ghostscript */
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "time_.h"
+#include <signal.h>
+#include <stdlib.h> /* for exit */
+#include <sys/param.h> /* for MAXPATHLEN */
+
+/* popen isn't POSIX-standard, so we declare it here. */
+extern FILE *popen();
+extern int pclose();
+
+int interrupted;
+
+/* Forward declarations */
+private void signalhandler(P1(int));
+private FILE *rbfopen(P2(char*, char*));
+
+/* Do platform-dependent initialization */
+void
+gp_init(void)
+{ intercept(signalhandler);
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ exit(exit_status);
+}
+
+private void
+signalhandler(int sig)
+{ clearerr(stdin);
+ switch(sig) {
+ case SIGINT:
+ case SIGQUIT:
+ interrupted = 1;
+ break;
+ case SIGFPE:
+ interrupted = 2;
+ break;
+ default:
+ break;
+ }
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1980) */
+/* and fraction (in nanoseconds). */
+#define PS_YEAR_0 80
+#define PS_MONTH_0 1
+#define PS_DAY_0 1
+void
+gp_get_realtime(long *pdt)
+{
+ long date, time, pstime, psdate, tick;
+ short day;
+
+ _sysdate(0, &time, &date, &day, &tick);
+ _julian(&time, &date);
+
+ pstime = 0;
+ psdate = (PS_YEAR_0 << 16) + (PS_MONTH_0 << 8) + PS_DAY_0;
+ _julian(&pstime, &psdate);
+
+ pdt[0] = (date - psdate)*86400 + time;
+ pdt[1] = 0;
+
+#ifdef DEBUG_CLOCK
+ printf("pdt[0] = %ld pdt[1] = %ld\n", pdt[0], pdt[1]);
+#endif
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ return gp_get_realtime(pdt); /* not yet implemented */
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* "|command" opens an output pipe. */
+/* Return NULL if the connection could not be opened. */
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ return
+ (strlen(fname) == 0 ?
+ gp_open_scratch_file(gp_scratch_file_name_prefix, fname, "w") :
+ fname[0] == '|' ?
+ popen(fname + 1, "w") :
+ rbfopen(fname, "w"));
+}
+
+FILE *
+rbfopen(char *fname, char *perm)
+{ FILE *file = fopen(fname, perm);
+ file->_flag |= _RBF;
+ return file;
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ if ( fname[0] == '|' )
+ pclose(pfile);
+ else
+ fclose(pfile);
+}
diff --git a/gs/src/gp_sysv.c b/gs/src/gp_sysv.c
new file mode 100644
index 000000000..62e2ce2c1
--- /dev/null
+++ b/gs/src/gp_sysv.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_sysv.c */
+/* System V Unix-specific routines for Ghostscript */
+
+/* This file contains a couple of standard Unix library procedures */
+/* that a few System V platforms don't provide. */
+/* Note that this file is NOT used for SVR4 platforms. */
+#include <errno.h>
+#include "stdio_.h"
+#include "time_.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+/* rename */
+int
+rename(const char *a, const char *b)
+{ if (access(a, 0) == -1 )
+ return(-1);
+ unlink(b);
+ if ( link(a, b) == -1 )
+ return(-1);
+ if ( unlink(a) == -1 )
+ { unlink(b); /* ??? */
+ return(-1);
+ }
+ return(0);
+}
+
+/* gettimeofday */
+#ifndef HZ
+# define HZ 100 /* see sys/param.h */
+#endif
+int
+gettimeofday(struct timeval *tvp, struct timezone *tzp)
+{ struct tms tms;
+ static long offset = 0;
+ long ticks;
+
+ if (!offset)
+ { time(&offset);
+ offset -= (times(&tms) / HZ);
+ }
+ ticks = times(&tms);
+ tvp->tv_sec = ticks/HZ + offset;
+ tvp->tv_usec = (ticks % HZ) * (1000*1000/HZ);
+ return 0;
+}
diff --git a/gs/src/gp_unifn.c b/gs/src/gp_unifn.c
new file mode 100644
index 000000000..54275455c
--- /dev/null
+++ b/gs/src/gp_unifn.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_unifn.c */
+/* Unix-like file name syntax platform routines for Ghostscript */
+#include "gx.h"
+#include "gp.h"
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ':';
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "";
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "r";
+const char gp_fmode_wb[] = "w";
+
+/* Answer whether a file name contains a directory/device specification, */
+/* i.e. is absolute (not directory- or device-relative). */
+bool
+gp_file_name_is_absolute(const char *fname, unsigned len)
+{ /* A file name is absolute if it starts with a 0 or more .s */
+ /* followed by a /. */
+ while ( len && *fname == '.' )
+ ++fname, --len;
+ return (len && *fname == '/');
+}
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *
+gp_file_name_concat_string(const char *prefix, unsigned plen,
+ const char *fname, unsigned len)
+{ if ( plen > 0 && prefix[plen - 1] == '/' )
+ return "";
+ return "/";
+}
diff --git a/gs/src/gp_unifs.c b/gs/src/gp_unifs.c
new file mode 100644
index 000000000..e06ae4c23
--- /dev/null
+++ b/gs/src/gp_unifs.c
@@ -0,0 +1,419 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_unifs.c */
+/* "Unix-like" file system platform routines for Ghostscript */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for string_match */
+#include "stat_.h"
+#include "dirent_.h"
+#include <sys/param.h> /* for MAXPATHLEN */
+
+/* Some systems (Interactive for example) don't define MAXPATHLEN,
+ * so we define it here. (This probably should be done via a Config-Script.)
+ */
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+/* Library routines not declared in a standard header */
+extern char *getenv(P1(const char *));
+extern char *mktemp(P1(char *));
+
+/* ------ File naming and accessing ------ */
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "gs_";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "/dev/null";
+
+/* Define the name that designates the current directory. */
+const char gp_current_directory_name[] = ".";
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ char *temp;
+ if ( (temp = getenv("TEMP")) == NULL )
+ strcpy(fname, "/tmp/");
+ else
+ { strcpy(fname, temp);
+ if ( strlen(fname) != 0 && fname[strlen(fname) - 1] != '/' )
+ strcat(fname, "/");
+ }
+ strcat(fname, prefix);
+ /* Prevent trailing X's in path from being converted by mktemp. */
+ if ( *fname != 0 && fname[strlen(fname) - 1] == 'X' )
+ strcat(fname, "-");
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{ return fopen(fname, mode);
+}
+
+/* ------ File enumeration ------ */
+
+/* Thanks to Fritz Elfert (Fritz_Elfert@wue.maus.de) for */
+/* the original version of the following code, and Richard Mlynarik */
+/* (mly@adoc.xerox.com) for an improved version. */
+
+typedef struct dirstack_s dirstack;
+struct dirstack_s {
+ dirstack *next;
+ DIR *entry;
+};
+gs_private_st_ptrs1(st_dirstack, dirstack, "dirstack",
+ dirstack_enum_ptrs, dirstack_reloc_ptrs, next);
+
+struct file_enum_s {
+ DIR *dirp; /* pointer to current open directory */
+ char *pattern; /* original pattern */
+ char *work; /* current path */
+ int worklen; /* strlen (work) */
+ dirstack *dstack; /* directory stack */
+ int patlen;
+ int pathead; /* how much of pattern to consider
+ * when listing files in current directory */
+ bool first_time;
+ gs_memory_t *memory;
+};
+gs_private_st_ptrs3(st_file_enum, struct file_enum_s, "file_enum",
+ file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern, work, dstack);
+
+/* Private procedures */
+
+/* Do a wild-card match. */
+#ifdef DEBUG
+private bool
+wmatch(const byte *str, uint len, const byte *pstr, uint plen,
+ const string_match_params *psmp)
+{ bool match = string_match(str, len, pstr, plen, psmp);
+ if ( gs_debug_c('e') )
+ { dputs("[e]string_match(\"");
+ fwrite(str, 1, len, dstderr);
+ dputs("\", \"");
+ fwrite(pstr, 1, plen, dstderr);
+ dprintf1("\") = %s\n", (match ? "TRUE" : "false"));
+ }
+ return match;
+}
+#define string_match wmatch
+#endif
+
+/* Search a string backward for a character. */
+/* (This substitutes for strrchr, which some systems don't provide.) */
+private char *
+rchr(char *str, char ch, int len)
+{ register char *p = str + len;
+ while ( p > str )
+ if ( *--p == ch ) return p;
+ return 0;
+}
+
+/* Pop a directory from the enumeration stack. */
+private bool
+popdir(file_enum *pfen)
+{ dirstack *d = pfen->dstack;
+ if ( d == 0 )
+ return false;
+ pfen->dirp = d->entry;
+ pfen->dstack = d->next;
+ gs_free_object(pfen->memory, d, "gp_enumerate_files(popdir)");
+ return true;
+}
+
+/* Initialize an enumeration. */
+file_enum *
+gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem)
+{ file_enum *pfen;
+ char *p;
+ char *work;
+
+ /* Reject attempts to enumerate paths longer than the */
+ /* system-dependent limit. */
+ if ( patlen > MAXPATHLEN )
+ return 0;
+
+ /* Reject attempts to enumerate with a pattern containing zeroes. */
+ { const char *p1;
+ for (p1 = pat; p1 < pat + patlen; p1++)
+ if (*p1 == 0) return 0;
+ }
+ /* >>> Should crunch strings of repeated "/"'s in pat to a single "/"
+ * >>> to match stupid unix filesystem "conventions" */
+
+ pfen = gs_alloc_struct(mem, file_enum, &st_file_enum,
+ "gp_enumerate_files");
+ if (pfen == 0)
+ return 0;
+
+ /* pattern and work could be allocated as strings, */
+ /* but it's simpler for GC and freeing to allocate them as bytes. */
+
+ pfen->pattern =
+ (char *)gs_alloc_bytes(mem, patlen + 1,
+ "gp_enumerate_files(pattern)");
+ if (pfen->pattern == 0)
+ return 0;
+ memcpy(pfen->pattern, pat, patlen);
+ pfen->pattern[patlen] = 0;
+
+ work = (char *)gs_alloc_bytes(mem, MAXPATHLEN+1,
+ "gp_enumerate_files(work)");
+ if (work == 0)
+ return 0;
+ pfen->work = work;
+
+ p = work;
+ memcpy(p, pat, patlen);
+ p += patlen;
+ *p = 0;
+
+ /* Remove directory specifications beyond the first wild card. */
+ /* Some systems don't have strpbrk, so we code it open. */
+ p = pfen->work;
+ while ( !(*p == '*' || *p == '?' || *p == 0) ) p++;
+ while ( !(*p == '/' || *p == 0) ) p++;
+ if ( *p == '/' )
+ *p = 0;
+ /* Substring for first wildcard match */
+ pfen->pathead = p - work;
+
+ /* Select the next higher directory-level. */
+ p = rchr(work, '/', p - work);
+ if (!p)
+ { /* No directory specification */
+ work[0] = 0;
+ pfen->worklen = 0;
+ }
+ else
+ { if (p == work)
+ { /* Root directory -- don't turn "/" into "" */
+ p++;
+ }
+ *p = 0;
+ pfen->worklen = p - work;
+ }
+
+ pfen->memory = mem;
+ pfen->dstack = 0;
+ pfen->first_time = true;
+ pfen->patlen = patlen;
+ return pfen;
+}
+
+/* Enumerate the next file. */
+uint
+gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
+{ const dir_entry *de;
+ char *work = pfen->work;
+ int worklen = pfen->worklen;
+ char *pattern = pfen->pattern;
+ int pathead = pfen->pathead;
+ int len;
+ struct stat stbuf;
+
+ if ( pfen->first_time )
+ { pfen->dirp = ((worklen == 0) ? opendir(".") : opendir(work));
+ if_debug1('e', "[e]file_enum:First-Open '%s'\n", work);
+ pfen->first_time = false;
+ if (pfen->dirp == 0) /* first opendir failed */
+ { gp_enumerate_files_close(pfen);
+ return ~(uint)0;
+ }
+ }
+
+ top: de = readdir(pfen->dirp);
+ if (de == 0)
+ { /* No more entries in this directory */
+ char *p;
+
+ if_debug0('e', "[e]file_enum:Closedir\n");
+ closedir(pfen->dirp);
+ /* Back working directory and matching pattern up one level */
+ p = rchr(work,'/', worklen);
+ if (p != 0)
+ { if (p == work) p++;
+ *p = 0;
+ worklen = p - work;
+ }
+ else
+ worklen = 0;
+ p = rchr(pattern,'/', pathead);
+ if (p != 0)
+ pathead = p - pattern;
+ else
+ pathead = 0;
+
+ if (popdir(pfen))
+ { /* Back up the directory tree. */
+ if_debug1('e', "[e]file_enum:Dir popped '%s'\n", work);
+ goto top;
+ }
+ else
+ { if_debug0('e', "[e]file_enum:Dirstack empty\n");
+ gp_enumerate_files_close(pfen);
+ return ~(uint)0;
+ }
+ }
+
+ /* Skip . and .. */
+ len = strlen(de->d_name);
+ if (len <= 2 && (!strcmp(de->d_name,".") || !strcmp(de->d_name,"..") ))
+ goto top;
+ if (len + worklen + 1 > MAXPATHLEN)
+ /* Should be an error, I suppose */
+ goto top;
+ if (worklen == 0)
+ { /* "Current" directory (evil un*x kludge) */
+ memcpy(work, de->d_name, len + 1);
+ }
+ else if (worklen == 1 && work[0] == '/')
+ { /* Root directory */
+ memcpy(work + 1, de->d_name, len + 1);
+ len = len + 1;
+ }
+ else
+ { work[worklen] = '/';
+ memcpy(work + worklen + 1, de->d_name, len + 1);
+ len = worklen + 1 + len;
+ }
+
+ /* Test for a match at this directory level */
+ if (!string_match((byte *)work, len, (byte *)pattern, pathead, NULL))
+ goto top;
+
+ /* Perhaps descend into subdirectories */
+ if (pathead < pfen->patlen)
+ { DIR *dp;
+
+ if (((stat(work,&stbuf) >= 0)
+ ? !stat_is_dir(stbuf)
+ /* Couldn't stat it.
+ * Well, perhaps it's a directory and
+ * we'll be able to list it anyway.
+ * If it isn't or we can't, no harm done. */
+ : 0))
+ goto top;
+
+ if (pfen->patlen == pathead + 1)
+ { /* Listing "foo/?/" -- return this entry */
+ /* if it's a directory. */
+ if (!stat_is_dir (stbuf))
+ { /* Do directoryp test the hard way */
+ dp = opendir(work);
+ if (!dp) goto top;
+ closedir(dp);
+ }
+ work[len++] = '/';
+ goto winner;
+ }
+
+ /* >>> Should optimise the case in which the next level */
+ /* >>> of directory has no wildcards. */
+ dp = opendir(work);
+#ifdef DEBUG
+ { char save_end = pattern[pathead];
+ pattern[pathead] = 0;
+ if_debug2('e', "[e]file_enum:fname='%s', p='%s'\n",
+ work, pattern);
+ pattern[pathead] = save_end;
+ }
+#endif /* DEBUG */
+ if (!dp)
+ /* Can't list this one */
+ goto top;
+ else
+ { /* Advance to the next directory-delimiter */
+ /* in pattern */
+ char *p;
+ dirstack *d;
+ for (p = pattern + pathead + 1; ; p++)
+ { if (*p == 0)
+ { /* No more subdirectories to match */
+ pathead = pfen->patlen;
+ break;
+ }
+ else if (*p == '/')
+ { pathead = p - pattern;
+ break;
+ }
+ }
+
+ /* Push a directory onto the enumeration stack. */
+ d = gs_alloc_struct(pfen->memory, dirstack,
+ &st_dirstack,
+ "gp_enumerate_files(pushdir)");
+ if ( d != 0 )
+ {
+ d->next = pfen->dstack;
+ d->entry = pfen->dirp;
+ pfen->dstack = d;
+ }
+ else
+ DO_NOTHING; /* >>> e_VMerror!!! */
+
+ if_debug1('e', "[e]file_enum:Dir pushed '%s'\n",
+ work);
+ worklen = len;
+ pfen->dirp = dp;
+ goto top;
+ }
+ }
+
+ winner:
+ /* We have a winner! */
+ pfen->worklen = worklen;
+ pfen->pathead = pathead;
+ memcpy(ptr, work, len);
+ return len;
+}
+
+/* Clean up the file enumeration. */
+void
+gp_enumerate_files_close(file_enum *pfen)
+{ gs_memory_t *mem = pfen->memory;
+
+ if_debug0('e', "[e]file_enum:Cleanup\n");
+ while (popdir(pfen)) /* clear directory stack */
+ DO_NOTHING;
+ gs_free_object(mem, (byte *)pfen->work,
+ "gp_enumerate_close(work)");
+ gs_free_object(mem, (byte *)pfen->pattern,
+ "gp_enumerate_files_close(pattern)");
+ gs_free_object(mem, pfen, "gp_enumerate_files_close");
+}
+
+/* Test-cases:
+ (../?*r*?/?*.ps) {==} 100 string filenameforall
+ (../?*r*?/?*.ps*) {==} 100 string filenameforall
+ (../?*r*?/) {==} 100 string filenameforall
+ (/t*?/?*.ps) {==} 100 string filenameforall
+*/
diff --git a/gs/src/gp_unix.c b/gs/src/gp_unix.c
new file mode 100644
index 000000000..0e760288f
--- /dev/null
+++ b/gs/src/gp_unix.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_unix.c */
+/* Unix-specific routines for Ghostscript */
+#include "string_.h"
+#include "time_.h"
+#include "gx.h"
+#include "gsexit.h"
+#include "gp.h"
+
+/*
+ * Because of inconsistent (and sometimes incorrect) header files,
+ * we must omit the argument list for popen.
+ */
+extern FILE *popen( /* P2(const char *, const char *) */ );
+extern int pclose(P1(FILE *));
+/*
+ * This is the only place in Ghostscript that calls 'exit'. Including
+ * <stdlib.h> is overkill, but that's where it's declared on ANSI systems.
+ * We don't have any way of detecting whether we have a standard library
+ * (some GNU compilers perversely define __STDC__ but don't provide
+ * an ANSI-compliant library), so we check __PROTOTYPES__ and
+ * hope for the best. We pick up getenv at the same time.
+ */
+#ifdef __PROTOTYPES__
+# include <stdlib.h> /* for exit and getenv */
+#else
+extern void exit(P1(int));
+extern char *getenv(P1(const char *));
+#endif
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ exit(exit_status);
+}
+
+/* ------ Miscellaneous ------ */
+
+/* Get the string corresponding to an OS error number. */
+/* Unix systems support this so inconsistently that we don't attempt */
+/* to figure out whether it's available. */
+const char *
+gp_strerror(int errnum)
+{ return NULL;
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1970) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_realtime(long *pdt)
+{ struct timeval tp;
+
+#if gettimeofday_no_timezone /* older versions of SVR4 */
+ { if ( gettimeofday(&tp) == -1 )
+ { lprintf("Ghostscript: gettimeofday failed!\n");
+ gs_exit(1);
+ }
+ }
+#else /* All other systems */
+ { struct timezone tzp;
+ if ( gettimeofday(&tp, &tzp) == -1 )
+ { lprintf("Ghostscript: gettimeofday failed!\n");
+ gs_exit(1);
+ }
+ }
+#endif
+
+ /* tp.tv_sec is #secs since Jan 1, 1970 */
+ pdt[0] = tp.tv_sec;
+
+ /* Some Unix systems (e.g., Interactive 3.2 r3.0) return garbage */
+ /* in tp.tv_usec. Try to filter out the worst of it here. */
+ pdt[1] = tp.tv_usec >= 0 && tp.tv_usec < 1000000 ? tp.tv_usec*1000 : 0;
+
+#ifdef DEBUG_CLOCK
+ printf("tp.tv_sec = %d tp.tv_usec = %d pdt[0] = %ld pdt[1] = %ld\n",
+ tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]);
+#endif
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{
+#if use_times_for_usertime
+ struct tms tms;
+ long ticks;
+
+ static long ticks_per_sec = 0;
+ if ( !ticks_per_sec ) /* not initialized yet */
+ ticks_per_sec = CLK_TCK;
+
+ times(&tms);
+ ticks = tms.tms_utime + tms.tms_stime + tms.tms_cutime + tms.tms_cstime;
+ pdt[0] = ticks / ticks_per_sec;
+ pdt[1] = (ticks % ticks_per_sec) * (1000000000 / ticks_per_sec);
+#else
+ gp_get_realtime(pdt); /* Use an approximation on other hosts. */
+#endif
+}
+
+/* ------ Screen management ------ */
+
+/* Get the environment variable that specifies the display to use. */
+const char *
+gp_getenv_display(void)
+{ return getenv("DISPLAY");
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* "|command" opens an output pipe. */
+/* Return NULL if the connection could not be opened. */
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{ return
+ (strlen(fname) == 0 ?
+ gp_open_scratch_file(gp_scratch_file_name_prefix, fname, "w") :
+ fname[0] == '|' ?
+ popen(fname + 1, "w") :
+ fopen(fname, "w"));
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ if ( fname[0] == '|' )
+ pclose(pfile);
+ else
+ fclose(pfile);
+}
diff --git a/gs/src/gp_vms.c b/gs/src/gp_vms.c
new file mode 100644
index 000000000..c56553625
--- /dev/null
+++ b/gs/src/gp_vms.c
@@ -0,0 +1,422 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_vms.c */
+/* VAX/VMS specific routines for Ghostscript */
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include <stat.h>
+#include <stdlib.h> /* for exit() */
+#include <unixio.h>
+
+extern char *getenv(P1(const char *));
+
+/* Apparently gcc doesn't allow extra arguments for fopen: */
+#ifdef VMS /* DEC C */
+# define fopen_VMS fopen
+#else /* gcc */
+# define fopen_VMS(name, mode, m1, m2) fopen(name, mode)
+#endif
+
+
+/* VMS string descriptor structure */
+#define DSC$K_DTYPE_T 14
+#define DSC$K_CLASS_S 1
+struct dsc$descriptor_s {
+ unsigned short dsc$w_length;
+ unsigned char dsc$b_dtype;
+ unsigned char dsc$b_class;
+ char *dsc$a_pointer;
+};
+typedef struct dsc$descriptor_s descrip;
+
+/* VMS RMS constants */
+#define RMS$_NMF 99018
+#define RMS$_NORMAL 65537
+#define NAM$C_MAXRSS 255
+
+struct file_enum_s {
+ uint context, length;
+ descrip *pattern;
+};
+
+extern uint
+ LIB$FIND_FILE(descrip *, descrip *, uint *, descrip *, descrip *,
+ uint *, uint *),
+ LIB$FIND_FILE_END(uint *),
+ SYS$FILESCAN (descrip *, uint *, uint *),
+ SYS$PUTMSG (uint *, int (*)(), descrip *, uint);
+
+private uint
+strlength(char *str, uint maxlen, char term)
+{ uint i = 0;
+ while ( i < maxlen && str[i] != term ) i++;
+ return i;
+}
+
+/* Do platform-dependent initialization. */
+void
+gp_init(void)
+{
+}
+
+/* Do platform-dependent cleanup. */
+void
+gp_exit(int exit_status, int code)
+{
+}
+
+/* Exit the program. */
+void
+gp_do_exit(int exit_status)
+{ /* The program returns exit_status = 0 for OK, 1 for failure; */
+ /* VMS has different conventions. */
+ switch ( exit_status )
+ {
+ case 0:
+ exit(exit_OK);
+ case 1:
+ exit(exit_FAILED);
+ }
+ exit(exit_status);
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1980) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_realtime(long *pdt)
+{ struct {uint _l0, _l1;} binary_date, now, difference;
+ long lib$ediv(), lib$subx(), sys$bintim(), sys$gettim();
+ long units_per_second = 10000000;
+ char *jan_1_1980 = "1-JAN-1980 00:00:00.00";
+ descrip str_desc;
+
+ /* For those interested, Wednesday, November 17, 1858 is the base
+ of the Modified Julian Day system adopted by the Smithsonian
+ Astrophysical Observatory in 1957 for satellite tracking. (The
+ year 1858 preceded the oldest star catalog in use at the
+ observatory.) VMS uses quadword time stamps which are offsets
+ in 100 nanosecond units from November 17, 1858. With a 63-bit
+ absolute time representation (sign bit must be clear), VMS will
+ have no trouble with time until 31-JUL-31086 02:48:05.47. */
+
+ /* Convert January 1, 1980 into a binary absolute time */
+ str_desc.dsc$w_length = strlen(jan_1_1980);
+ str_desc.dsc$a_pointer = jan_1_1980;
+ (void) sys$bintim (&str_desc, &binary_date);
+
+ /* Compute number of 100 nanosecond units since January 1, 1980. */
+ (void) sys$gettim (&now);
+ (void) lib$subx (&now, &binary_date, &difference);
+
+ /* Convert to seconds and nanoseconds. */
+ (void) lib$ediv (&units_per_second, &difference, &pdt[0], &pdt[1]);
+ pdt[1] *= 100;
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ gp_get_realtime(pdt); /* Use an approximation for now. */
+}
+
+/* ------ Screen management ------ */
+
+/* Get the environment variable that specifies the display to use. */
+const char *
+gp_getenv_display(void)
+{ return getenv("DECW$DISPLAY");
+}
+
+/* ------ Printer accessing ------ */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* Return NULL if the connection could not be opened. */
+FILE *
+gp_open_printer(char *fname, int binary_mode)
+{
+ if (strlen(fname) == 0)
+ { strcpy(fname, gp_scratch_file_name_prefix);
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+ }
+ if ( binary_mode )
+ { /*
+ * Printing must be done exactly byte to byte,
+ * using "passall". However the standard VMS symbiont
+ * does not treat stream-LF files correctly in this respect,
+ * but throws away \n characters. Giving the file
+ * the record type "undefined", but accessing it as a
+ * normal stream-LF file does the trick.
+ */
+ return fopen_VMS(fname, "w", "rfm = udf", "ctx = stm");
+ }
+ else
+ { /* Open as a normal text stream file. */
+ return fopen_VMS(fname, "w", "rfm = var", "rat = cr");
+ }
+}
+
+/* Close the connection to the printer. */
+void
+gp_close_printer(FILE *pfile, const char *fname)
+{ fclose(pfile);
+}
+
+/* ------ File naming and accessing ------ */
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ',';
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "_temp_";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "NLA0:";
+
+/* Define the name that designates the current directory. */
+const char gp_current_directory_name[] = "[]";
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "";
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "r";
+const char gp_fmode_wb[] = "w";
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+FILE *
+gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
+{ strcpy(fname, prefix);
+ strcat(fname, "XXXXXX");
+ mktemp(fname);
+ return fopen(fname, mode);
+}
+
+/* Open a file with the given name, as a stream of uninterpreted bytes. */
+/* We have to do something special if the file was FTP'ed in binary mode. */
+/* Unfortunately, only DEC C supports the extra arguments to fopen. */
+FILE *
+gp_fopen(const char *fname, const char *mode)
+{
+#ifdef __DECC
+#define FAB$C_FIX 1
+ stat_t buffer;
+
+ if ( stat((char *)fname, &buffer) == 0 )
+ if ( buffer.st_fab_rfm == FAB$C_FIX )
+ return fopen(fname, mode, "rfm=stmlf", "ctx=stm");
+#endif
+ return fopen(fname, mode);
+}
+
+/* Answer whether a file name contains a directory/device specification, i.e.,
+ * is absolute (not directory- or device-relative). Since for VMS, the concept
+ * of an "absolute" file reference has no meaning. As Ghostscript is here
+ * merely checking to see if it will make sense to paste a path to the front
+ * of the file name, we use the VMS system service SYS$FILESCAN to check that
+ * the file name has no node, device, root, or directory specification: if all
+ * four of these items are missing from the file name then it is considered to
+ * a relative file name to which a path may be prefixed. (Roots are associated
+ * with rooted logical names.)
+ */
+
+bool
+gp_file_name_is_absolute(const char *fname, uint len)
+{
+ descrip str_desc;
+ /* SYS$FILESCAN takes a uint *, but we want to extract bits. */
+ union {
+ uint i;
+ struct {
+ unsigned fscn$v_node : 1;
+ unsigned fscn$v_device : 1;
+ unsigned fscn$v_root : 1;
+ unsigned fscn$v_directory : 1;
+ unsigned fscn$v_name : 1;
+ unsigned fscn$v_type : 1;
+ unsigned fscn$v_version : 1;
+ unsigned fscn$v_fill_23 : 1;
+ } s;
+ } flags;
+ uint zero = 0;
+
+ str_desc.dsc$w_length = len;
+ str_desc.dsc$a_pointer = (char *)fname;
+ SYS$FILESCAN (&str_desc, &zero, &flags.i);
+ if ( flags.s.fscn$v_directory || flags.s.fscn$v_root ||
+ flags.s.fscn$v_device || flags.s.fscn$v_node) return true;
+ else return false;
+}
+
+/* Answer the string to be used for combining a directory/device prefix */
+/* with a base file name. The file name is known to not be absolute. */
+const char *
+gp_file_name_concat_string(const char *prefix, uint plen,
+ const char *fname, uint len)
+{
+ /* Full VAX/VMS paths are of the form:
+ *
+ * device:[root.][directory.subdirectory]filename.extension;version
+ * logical:filename.extension;version
+ *
+ * Roots are fairly rare and associated typically with rooted logical
+ * names.
+ *
+ * Examples:
+ *
+ * DUA1:[GHOSTSCRIPT]GHOST.PS;1
+ * THOR_DEC:[DOOF.A.B.C.D]FILE.DAT;-3
+ * LOG:GHOST.PS (LOG is a logical defined as DUA1:[GHOSTSCRIPT])
+ * LOG:DOOF.DAT (LOG is defined as DUA1, current directory is
+ * is used as the directory spec.)
+ *
+ */
+ if ( plen > 0 )
+ switch ( prefix[plen - 1] )
+ { case ':': case ']': return "";
+ };
+ return ":";
+}
+
+/* ------ Wild card file search procedures ------ */
+
+private void
+gp_free_enumeration(file_enum *pfen)
+{
+ if (pfen) {
+ LIB$FIND_FILE_END(&pfen->context);
+ gs_free(pfen->pattern->dsc$a_pointer, pfen->length, 1,
+ "GP_ENUM(pattern)");
+ gs_free((char *)pfen->pattern, sizeof(descrip), 1,
+ "GP_ENUM(descriptor)");
+ gs_free((char *)pfen, sizeof(file_enum), 1,
+ "GP_ENUM(file_enum)");
+ }
+}
+
+/* Begin an enumeration. See gp.h for details. */
+
+file_enum *
+gp_enumerate_files_init(const char *pat, uint patlen,
+ gs_memory_t *memory)
+{
+ file_enum *pfen;
+ uint i, len;
+ char *c, *newpat;
+
+ pfen = (file_enum *)gs_malloc(sizeof (file_enum), 1,
+ "GP_ENUM(file_enum)");
+ pfen->pattern = (descrip *)gs_malloc(sizeof (descrip), 1,
+ "GP_ENUM(descriptor)");
+ newpat = (char *)gs_malloc(patlen, 1, "GP_ENUM(pattern)");
+
+ /* Copy the pattern removing backslash quoting characters and
+ * transforming unquoted question marks, '?', to percent signs, '%'.
+ * (VAX/VMS uses the wildcard '%' to represent exactly one character
+ * and '*' to represent zero or more characters. Any combination and
+ * number of interspersed wildcards is permitted.)
+ */
+ c = newpat;
+ for ( i = 0; i < patlen; pat++, i++ )
+ switch (*pat) {
+ case '?' :
+ *c++ = '%'; break;
+ case '\\' :
+ i++;
+ if (i < patlen) *c++ = *++pat;
+ break;
+ default :
+ *c++ = *pat; break;
+ }
+ len = c - newpat;
+
+ /* Pattern may not exceed 255 characters */
+ if (len > 255) {
+ gs_free(newpat, patlen, 1, "GP_ENUM(pattern)");
+ gs_free((char *)pfen->pattern, sizeof (descrip), 1,
+ "GP_ENUM(descriptor)");
+ gs_free((char *)pfen, sizeof (file_enum), 1, "GP_ENUM(file_enum)");
+ return (file_enum *)0;
+ }
+
+ pfen->context = 0;
+ pfen->length = patlen;
+ pfen->pattern->dsc$w_length = len;
+ pfen->pattern->dsc$b_dtype = DSC$K_DTYPE_T;
+ pfen->pattern->dsc$b_class = DSC$K_CLASS_S;
+ pfen->pattern->dsc$a_pointer = newpat;
+
+ return pfen;
+}
+
+/* Return the next file name in the enumeration. The client passes in */
+/* a scratch string and a max length. If the name of the next file fits, */
+/* the procedure returns the length. If it doesn't fit, the procedure */
+/* returns max length +1. If there are no more files, the procedure */
+/* returns -1. */
+
+uint
+gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
+{
+ char *c, filnam[NAM$C_MAXRSS];
+ descrip result = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+ uint i, len;
+
+ result.dsc$a_pointer = filnam;
+
+ /* Find the next file which matches the pattern */
+ i = LIB$FIND_FILE(pfen->pattern, &result, &pfen->context,
+ (descrip *)0, (descrip *)0, (uint *)0, (uint *)0);
+
+ /* Check the return status */
+ if (i == RMS$_NMF) {
+ gp_free_enumeration (pfen);
+ return (uint)-1;
+ }
+ else if (i != RMS$_NORMAL) return 0;
+ else if ((len = strlength (filnam, NAM$C_MAXRSS, ' ')) > maxlen)
+ return maxlen+1;
+
+ /* Copy the returned filename over to the input string ptr */
+ c = ptr;
+ for (i = 0; i < len; i++) *c++ = filnam[i];
+
+ return len;
+}
+
+/* Clean up a file enumeration. This is only called to abandon */
+/* an enumeration partway through: ...next should do it if there are */
+/* no more files to enumerate. This should deallocate the file_enum */
+/* structure and any subsidiary structures, strings, buffers, etc. */
+
+void
+gp_enumerate_files_close(file_enum *pfen)
+{ gp_free_enumeration (pfen);
+}
+
+const char *
+gp_strerror(int errnum)
+{ return NULL;
+}
diff --git a/gs/src/gp_win32.c b/gs/src/gp_win32.c
new file mode 100644
index 000000000..990aa9fc4
--- /dev/null
+++ b/gs/src/gp_win32.c
@@ -0,0 +1,253 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gp_win32.c */
+/* Common platform-specific routines for MS-Windows WIN32 */
+/* hacked from gp_msdos.c by Russell Lang */
+#include "stdio_.h"
+#include "string_.h" /* for strerror */
+#include "dos_.h"
+#include "gstypes.h"
+#include "gsmemory.h" /* for gp.h */
+#include "gserror.h"
+#include "gserrors.h"
+#include "gp.h"
+#include "gpsync.h"
+#include "windows_.h"
+
+/* ------ Miscellaneous ------ */
+
+/* Get the string corresponding to an OS error number. */
+/* This is compiler-, not OS-, specific, but it is ANSI-standard and */
+/* all MS-DOS and MS Windows compilers support it. */
+const char *
+gp_strerror(int errnum)
+{ return strerror(errnum);
+}
+
+/* ------ Date and time ------ */
+
+/* Read the current time (in seconds since Jan. 1, 1980) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_realtime(long *pdt)
+{
+SYSTEMTIME st;
+long idate;
+static const int mstart[12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ /* This gets UTC, not local time */
+ /* We have no way of knowing the time zone correction */
+ GetSystemTime(&st);
+ idate = (st.wYear - 1980) * 365 + /* days per year */
+ ((st.wYear - 1)/4 - 1979/4) + /* intervening leap days */
+ (1979/100 - (st.wYear - 1)/100) +
+ ((st.wYear - 1)/400 - 1979/400) +
+ mstart[st.wMonth - 1] + /* month is 1-origin */
+ st.wDay - 1; /* day of month is 1-origin */
+ idate += (2 < st.wMonth
+ && (st.wYear % 4 == 0
+ && (st.wYear % 100 != 0 || st.wYear % 400 == 0)));
+ pdt[0] = ((idate*24 + st.wHour) * 60 + st.wMinute) * 60 + st.wSecond;
+ pdt[1] = st.wMilliseconds * 1000000;
+}
+
+/* Read the current user CPU time (in seconds) */
+/* and fraction (in nanoseconds). */
+void
+gp_get_usertime(long *pdt)
+{ gp_get_realtime(pdt); /* Use an approximation for now. */
+}
+
+/* ------ Console management ------ */
+
+/* Answer whether a given file is the console (input or output). */
+/* This is not a standard gp procedure, */
+/* but the MS Windows configuration needs it, */
+/* and other MS-DOS configurations might need it someday. */
+int
+gp_file_is_console(FILE *f)
+{
+#ifdef __DLL__
+ if ( f == NULL )
+ return 1;
+#else
+ if ( f == NULL )
+ return 0;
+#endif
+ if (fileno(f) <= 2)
+ return 1;
+ return 0;
+}
+
+/* ------ Screen management ------ */
+
+/* Get the environment variable that specifies the display to use. */
+const char *
+gp_getenv_display(void)
+{ return NULL;
+}
+
+/* ------ File names ------ */
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "_temp_";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "nul";
+
+/* Define the name that designates the current directory. */
+const char gp_current_directory_name[] = ".";
+
+/* ------- Synchronization primitives -------- */
+
+/* Semaphore supports wait/signal semantics */
+
+typedef struct win32_semaphore_s {
+ HANDLE handle; /* returned from CreateSemaphore */
+} win32_semaphore;
+const uint gp_semaphore_sizeof = sizeof (win32_semaphore);
+
+int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
+gp_semaphore_open(
+ gp_semaphore *sema /* create semaphore here */
+) {
+ win32_semaphore *const winSema = (win32_semaphore *)sema;
+ if (winSema)
+ {
+ winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL);
+ return winSema->handle != NULL ? 0 : gs_note_error(gs_error_unknownerror);
+ }
+ else
+ return 0; /* Win32 semaphores handles may be moved */
+ }
+
+void
+gp_semaphore_close(
+ gp_semaphore *sema /* semaphore to affect */
+) {
+ win32_semaphore *const winSema = (win32_semaphore *)sema;
+ if (winSema->handle != NULL)
+ CloseHandle(winSema->handle);
+ winSema->handle = NULL;
+ }
+
+int /* rets 0 ok, -ve error */
+gp_semaphore_wait(
+ gp_semaphore *sema /* semaphore to affect */
+) {
+ win32_semaphore *const winSema = (win32_semaphore *)sema;
+ return WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0
+ ? 0 : gs_error_unknownerror;
+ }
+
+int /* rets 0 ok, -ve error */
+gp_semaphore_signal(
+ gp_semaphore *sema /* semaphore to affect */
+) {
+ win32_semaphore *const winSema = (win32_semaphore *)sema;
+ return
+ ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 : gs_error_unknownerror;
+ }
+
+
+/* Monitor supports enter/leave semantics */
+
+typedef struct win32_monitor_s {
+ CRITICAL_SECTION lock; /* critical section lock */
+} win32_monitor;
+const uint gp_monitor_sizeof = sizeof (win32_monitor);
+
+int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
+gp_monitor_open(
+ gp_monitor *mon /* create monitor here */
+) {
+ win32_monitor *const winMon = (win32_monitor *)mon;
+ if (mon)
+ {
+ InitializeCriticalSection(&winMon->lock); /* returns no status */
+ return 0;
+ }
+ else
+ return 1; /* Win32 critical sections mutsn't be moved */
+ }
+
+void
+gp_monitor_close(
+ gp_monitor *mon /* monitor to affect */
+) {
+ win32_monitor *const winMon = (win32_monitor *)mon;
+ DeleteCriticalSection(&winMon->lock); /* rets no status */
+ }
+
+int /* rets 0 ok, -ve error */
+gp_monitor_enter(
+ gp_monitor *mon /* monitor to affect */
+) {
+ win32_monitor *const winMon = (win32_monitor *)mon;
+ EnterCriticalSection(&winMon->lock); /* rets no status */
+ return 0;
+ }
+
+int /* rets 0 ok, -ve error */
+gp_monitor_leave(
+ gp_monitor *mon /* monitor to affect */
+) {
+ win32_monitor *const winMon = (win32_monitor *)mon;
+ LeaveCriticalSection(&winMon->lock); /* rets no status */
+ return 0;
+ }
+
+/* --------- Thread primitives ---------- */
+
+typedef struct gp_thread_creation_closure_s {
+ gp_thread_creation_callback_t function; /* function to start */
+ void *data; /* magic data to pass to thread */
+} gp_thread_creation_closure;
+
+/* Origin of new threads started by gp_create_thread */
+private DWORD WINAPI
+gp_thread_begin_wrapper(
+ void *thread_data /* gp_thread_creation_closure passed as magic data */
+) {
+ gp_thread_creation_closure closure = *(gp_thread_creation_closure *)thread_data;
+ free(thread_data);
+ (*closure.function)(closure.data);
+ return 0;
+ }
+
+/* Call a function on a brand new thread */
+int /* 0 ok, -ve error */
+gp_create_thread(
+ gp_thread_creation_callback_t function, /* function to start */
+ void *data /* magic data to pass to thread fn */
+) {
+ DWORD threadID;
+
+ /* Create the magic closure that thread_wrapper gets passed */
+ gp_thread_creation_closure *closure
+ = (gp_thread_creation_closure *)malloc( sizeof(*closure) );
+ if (!closure)
+ return gs_error_VMerror;
+ closure->function = function;
+ closure->data = data;
+
+ /* Start thread_wrapper */
+ return CreateThread(NULL, 0, gp_thread_begin_wrapper, closure, 0, &threadID)
+ ? 0 : gs_note_error(gs_error_unknownerror);
+ }
diff --git a/gs/src/gpcheck.h b/gs/src/gpcheck.h
new file mode 100644
index 000000000..6da0c39fd
--- /dev/null
+++ b/gs/src/gpcheck.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gpcheck.h */
+/* Interrupt check interface */
+
+/*
+ * On some platforms, the interpreter must check periodically for user-
+ * initiated actions. (Eventually, this may be extended to all platforms,
+ * to handle multi-tasking through the 'context' facility.) Routines that
+ * run for a long time must periodically call gp_check_interrupts(), and
+ * if it returns true, must clean up whatever they are doing and return an
+ * e_interrupted (or gs_error_interrupted) exceptional condition.
+ * The return_if_interrupt macro provides a convenient way to do this.
+ *
+ * On platforms that require an interrupt check, the makefile defines
+ * a symbol CHECK_INTERRUPTS. Currently this is only the Microsoft
+ * Windows platform.
+ */
+
+#ifdef CHECK_INTERRUPTS
+int gp_check_interrupts(P0());
+int gs_return_check_interrupt(P1(int code));
+# define process_interrupts() discard(gp_check_interrupts())
+# define return_if_interrupt()\
+ { int icode_ = gp_check_interrupts();\
+ if ( icode_ )\
+ return gs_note_error((icode_ > 0 ? gs_error_interrupt : icode_));\
+ }
+# define return_check_interrupt(code)\
+ return gs_return_check_interrupt(code)
+#else
+# define gp_check_interrupts() 0
+# define process_interrupts() DO_NOTHING
+# define return_if_interrupt() DO_NOTHING
+# define return_check_interrupt(code)\
+ return (code)
+#endif
diff --git a/gs/src/gpsync.h b/gs/src/gpsync.h
new file mode 100644
index 000000000..d7d88b4ae
--- /dev/null
+++ b/gs/src/gpsync.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gpsync.h */
+/* Platform-dependent synchronization primitives */
+
+#if !defined(gpsync_INCLUDED)
+ #define gpsync_INCLUDED
+
+/* Initial version 4/1/98 by John Desrosiers (soho@crl.com) */
+
+/* -------- Synchronization primitives ------- */
+
+/* Semaphore supports wait/signal semantics */
+typedef struct {char filler;} gp_semaphore;
+extern const uint gp_semaphore_sizeof;
+
+int gp_semaphore_open(P1(gp_semaphore *sema));
+void gp_semaphore_close(P1(gp_semaphore *sema));
+int gp_semaphore_wait(P1(gp_semaphore *sema));
+int gp_semaphore_signal(P1(gp_semaphore *sema));
+
+/* Monitor supports enter/leave semantics */
+typedef struct {char filler;} gp_monitor;
+extern const uint gp_monitor_sizeof;
+
+int gp_monitor_open(P1(gp_monitor *mon));
+void gp_monitor_close(P1(gp_monitor *mon));
+int gp_monitor_enter(P1(gp_monitor *mon));
+int gp_monitor_leave(P1(gp_monitor *mon));
+
+typedef void(*gp_thread_creation_callback_t)(P1(void*));
+int gp_create_thread(P2(gp_thread_creation_callback_t, void*));
+
+#endif /* !defined(gpsync_INCLUDED) */
diff --git a/gs/src/gs.c b/gs/src/gs.c
new file mode 100644
index 000000000..811604d14
--- /dev/null
+++ b/gs/src/gs.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gs.c */
+/* 'main' program for Ghostscript */
+#include "ghost.h"
+#include "imain.h"
+#include "imainarg.h"
+#include "iminst.h"
+
+/* Define an optional array of strings for testing. */
+/*#define RUN_STRINGS*/
+#ifdef RUN_STRINGS
+private const char *run_strings[] = {
+ "2 vmreclaim /SAVE save def 2 vmreclaim",
+ "(saved\n) print flush",
+ "SAVE restore (restored\n) print flush 2 vmreclaim",
+ "(done\n) print flush quit",
+ 0
+};
+#endif
+
+int
+main(int argc, char *argv[])
+{ gs_main_instance *minst = gs_main_instance_default();
+ gs_main_init_with_args(minst, argc, argv);
+
+#ifdef RUN_STRINGS
+ { /* Run a list of strings (for testing). */
+ const char **pstr = run_strings;
+ for ( ; *pstr; ++pstr )
+ { int exit_code;
+ ref error_object;
+ int code;
+ fprintf(stdout, "{%s} =>\n", *pstr);
+ fflush(stdout);
+ code = gs_main_run_string(minst, *pstr, 0,
+ &exit_code, &error_object);
+ zflush(osp);
+ fprintf(stdout, " => code = %d\n", code);
+ fflush(stdout);
+ if ( code < 0 )
+ gs_exit(1);
+ }
+ }
+#endif
+
+ if ( minst->run_start )
+ gs_main_run_start(minst);
+
+ gs_exit(0); /* exit */
+ /* NOTREACHED */
+}
diff --git a/gs/src/gs.mak b/gs/src/gs.mak
new file mode 100644
index 000000000..48170fd5a
--- /dev/null
+++ b/gs/src/gs.mak
@@ -0,0 +1,339 @@
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Generic makefile, common to all platforms.
+# The platform-specific makefiles `include' this file.
+# They define the following symbols:
+# GS - the name of the executable (without the extension, if any).
+# GS_LIB_DEFAULT - the default directory/ies for searching for the
+# initialization and font files at run time.
+# SEARCH_HERE_FIRST - the default setting of -P (whether or not to
+# look for files in the current directory first).
+# GS_DOCDIR - the directory where documentation will be available
+# at run time.
+# JSRCDIR - the directory where the IJG JPEG library source code
+# is stored (at compilation time).
+# JVERSION - the major version number of the IJG JPEG library.
+# PSRCDIR, PVERSION - the same for libpng.
+# ZSRCDIR - the same for zlib.
+# SHARE_LIBPNG - normally 0; if set to 1, asks the linker to use
+# an existing compiled libpng (-lpng) instead of compiling and
+# linking libpng explicitly.
+# LIBPNG_NAME, the name of the shared libpng, currently always
+# png (libpng, -lpng).
+# SHARE_ZLIB - normally 0; if set to 1, asks the linker to use
+# an existing compiled zlib (-lgz or -lz) instead of compiling
+# and linking libgz/libz explicitly.
+# ZLIB_NAME - the name of the shared zlib, either gz (for libgz, -lgz)
+# or z (for libz, -lz).
+# CONFIG - a configuration ID, added at the request of a customer,
+# that is supposed to help in maintaining multiple variants in
+# a single directory. Normally this is an empty string;
+# it may be any string that is legal as part of a file name.
+# DEVICE_DEVS - the devices to include in the executable.
+# See devs.mak for details.
+# DEVICE_DEVS1...DEVICE_DEVS15 - additional devices, if the definition
+# of DEVICE_DEVS doesn't fit on one line. See devs.mak for details.
+# FEATURE_DEVS - what features to include in the executable.
+# Normally this is one of:
+# level1 - a standard PostScript Level 1 language
+# interpreter.
+# level2 - a standard PostScript Level 2 language
+# interpreter.
+# pdf - a PDF-capable interpreter.
+# You may include both level1 and pdf, or both level2 and pdf.
+# The following feature may be added to either of the standard
+# configurations:
+# ccfonts - precompile fonts into C, and link them
+# with the executable. See fonts.txt for details.
+# The remaining features are of interest primarily to developers
+# who want to "mix and match" features to create custom
+# configurations:
+# dps - (partial) support for Display PostScript extensions:
+# see language.txt for details.
+# btoken - support for binary token encodings.
+# Included automatically in the dps and level2 features.
+# cidfont - (currently partial) support for CID-keyed fonts.
+# color - support for the Level 1 CMYK color extensions.
+# Included automatically in the dps and level2 features.
+# compfont - support for composite (type 0) fonts.
+# Included automatically in the level2 feature.
+# dct - support for DCTEncode/Decode filters.
+# Included automatically in the level2 feature.
+# epsf - support for recognizing and skipping the binary
+# header of MS-DOS EPSF files.
+# filter - support for Level 2 filters (other than eexec,
+# ASCIIHexEncode/Decode, NullEncode, PFBDecode,
+# RunLengthEncode/Decode, and SubFileDecode, which are
+# always included, and DCTEncode/Decode,
+# which are separate).
+# Included automatically in the level2 feature.
+# fzlib - support for zlibEncode/Decode filters.
+# ttfont - support for TrueType fonts.
+# type1 - support for Type 1 fonts and eexec;
+# normally included automatically in all configurations.
+# type42 - support for Type 42 (embedded TrueType) fonts.
+# Included automatically in the level2 feature.
+# There are quite a number of other sub-features that can be
+# selectively included in or excluded from a configuration,
+# but the above are the ones that are most likely to be of
+# interest.
+# COMPILE_INITS - normally 0; if set to 1, compiles the PostScript
+# language initialization files (gs_init.ps et al) into the
+# executable, eliminating the need for these files to be present
+# at run time.
+# BAND_LIST_STORAGE - normally file; if set to memory, stores band
+# lists in memory (with compression if needed).
+# BAND_LIST_COMPRESSOR - normally zlib: selects the compression method
+# to use for band lists in memory.
+# FILE_IMPLEMENTATION - normally stdio; if set to fd, uses file
+# descriptors instead of buffered stdio for file I/O; if set to
+# both, provides both implementations with different procedure
+# names for the fd-based implementation (see sfxfd.c for
+# more information).
+# EXTEND_NAMES - a value N between 0 and 6, indicating that the name
+# table should have a capacity of 2^(16+N) names. This normally
+# should be set to 0 (or left undefined), since non-zero values
+# result in a larger fixed space overhead and slightly slower code.
+# EXTEND_NAMES is ignored in 16-bit environments.
+#
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+# GS_INIT - the name of the initialization file for the interpreter,
+# normally gs_init.ps.
+# PLATFORM - a "device" name for the platform, so that platforms can
+# add various kinds of resources like devices and features.
+# CMD - the suffix for shell command files (e.g., null or .bat).
+# (This is only needed in a few places.)
+# D - the directory separator character (\ for MS-DOS, / for Unix).
+# O - the string for specifying the output file from the C compiler
+# (-o for MS-DOS, -o ./ for Unix).
+# OBJ - the extension for relocatable object files (e.g., o or obj).
+# XE - the extension for executable files (e.g., null or .exe).
+# XEAUX - the extension for the executable files (e.g., null or .exe)
+# for the utility programs (ansi2knr and those compiled with
+# CCAUX).
+# BEGINFILES - the list of files that `make begin' and `make clean'
+# should delete.
+# CCA2K - the C invocation for the ansi2knr program, which is the only
+# one that doesn't use ANSI C syntax. (It is only needed if
+# the main C compiler also isn't an ANSI compiler.)
+# CCAUX - the C invocation for auxiliary programs (echogs, genarch,
+# genconf, geninit).
+# CCBEGIN - the compilation command for `make begin', normally
+# $(CCC) *.c.
+# CCC - the C invocation for normal compilation.
+# CCD - the C invocation for files that store into frame buffers or
+# device registers. Needed because some optimizing compilers
+# will eliminate necessary stores.
+# CCCF - the C invocation for compiled fonts and other large,
+# self-contained data modules. Needed because MS-DOS
+# requires using the 'huge' memory model for these.
+# CCINT - the C invocation for compiling the main interpreter module,
+# normally the same as CCC: this is needed because the
+# Borland compiler generates *worse* code for this module
+# (but only this module) when optimization (-O) is turned on.
+# CCLEAF - the C invocation for compiling modules that contain only
+# leaf procedures, which don't need to build stack frames.
+# This is needed only because many compilers aren't able to
+# recognize leaf procedures on their own.
+# AK - if source files must be converted from ANSI to K&R syntax,
+# this is $(ANSI2KNR_XE); if not, it is null.
+# If a particular platform requires other utility programs
+# to be built, AK must include them too.
+# SHP - the prefix for invoking a shell script in the current directory
+# (null for MS-DOS, $(SH) ./ for Unix).
+# EXPP, EXP - the prefix for invoking an executable program in the
+# current directory (null for MS-DOS, ./ for Unix).
+# SH - the shell for scripts (null on MS-DOS, sh on Unix).
+# CONFILES - the arguments for genconf to generate the appropriate
+# linker control files (various).
+# CP_ - the command for copying one file to another. Because of
+# limitations in the MS-DOS/MS Windows environment, the
+# second argument must either be '.' (in which case the
+# write date may be either preserved or set to the current
+# date) or a file name (in which case the write date is
+# always updated).
+# RM_ - the command for deleting (a) file(s) (including wild cards,
+# but limited to a single file or pattern).
+# RMN_ = the command for deleting multiple files / patterns.
+#
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+# Define the name of this makefile.
+GS_MAK=gs.mak
+
+# Define the names of the executables.
+GS_XE=$(GS)$(XE)
+ANSI2KNR_XE=ansi2knr$(XEAUX)
+ECHOGS_XE=echogs$(XEAUX)
+GENARCH_XE=genarch$(XEAUX)
+GENCONF_XE=genconf$(XEAUX)
+GENINIT_XE=geninit$(XEAUX)
+
+# Define the names of the CONFIG-dependent header files.
+# gconfig*.h and gconfx*.h are generated dynamically.
+gconfig_h=gconfxx$(CONFIG).h
+gconfigf_h=gconfxc$(CONFIG).h
+
+# Watcom make insists that rules have a non-empty body!
+all default: $(GS_XE)
+ $(RM_) _temp_*
+
+distclean maintainer-clean realclean: clean
+ $(RM_) makefile
+
+clean: mostlyclean
+ $(RM_) arch.h
+ $(RM_) $(GS_XE)
+
+mostlyclean:
+ $(RMN_) *.$(OBJ) *.a core gmon.out
+ $(RMN_) *.dev *.d_* devs*.tr gconfig*.h gconfx*.h j*.h o*.tr l*.tr
+ $(RMN_) deflate.h zutil.h
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) _temp_* _temp_*.* *.map *.sym
+ $(RMN_) $(ANSI2KNR_XE) $(ECHOGS_XE) $(GENARCH_XE) $(GENCONF_XE) $(GENINIT_XE)
+ $(RMN_) gs_init.c $(BEGINFILES)
+
+# Remove only configuration-dependent information.
+config-clean:
+ $(RMN_) *.dev devs*.tr gconfig*.h gconfx*.h o*.tr l*.tr
+
+# A rule to do a quick and dirty compilation attempt when first installing
+# the interpreter. Many of the compilations will fail:
+# follow this with 'make'.
+
+begin:
+ $(RMN_) arch.h gconfig*.h gconfx*.h $(GENARCH_XE) $(GS_XE)
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) gs_init.c $(BEGINFILES)
+ make arch.h gconfigv.h
+ - $(CCBEGIN)
+ $(RMN_) gconfig.$(OBJ) gdev*.$(OBJ) gp_*.$(OBJ) gscdefs.$(OBJ) gsmisc.$(OBJ)
+ $(RMN_) icfontab.$(OBJ) iconfig.$(OBJ) iinit.$(OBJ) interp.$(OBJ)
+
+# Auxiliary programs
+
+arch.h: $(GENARCH_XE)
+ $(EXPP) $(EXP)genarch arch.h
+
+# Macros for constructing the *.dev files that describe features and
+# devices.
+SETDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-obj
+SETPDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-include -lpage -l-obj
+SETMOD=$(EXP)echogs -e .dev -w- -l-obj
+ADDMOD=$(EXP)echogs -e .dev -a-
+
+# Define the compilation commands for the third-party libraries.
+CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR) -DPNG_USE_CONST
+CCCJ=$(CCC) -I. -I$(JSRCDIR)
+CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+
+######################## How to define new 'features' #######################
+#
+# One defines new 'features' exactly like devices (see devs.mak for details).
+# For example, one would define a feature abc by adding the following to
+# gs.mak:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_)
+# $(SETMOD) abc $(abc_)
+# $(ADDMOD) abc -obj ... [if needed]
+# $(ADDMOD) abc -oper ... [if appropriate]
+# $(ADDMOD) abc -ps ... [if appropriate]
+#
+# If the abc feature requires the presence of some other features jkl and
+# pqr, then the rules must look like this:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_) jkl.dev pqr.dev
+# $(SETMOD) abc $(abc_)
+# ...
+# $(ADDMOD) abc -include jkl pqr
+
+# --------------------- Configuration-dependent files --------------------- #
+
+# gconfig.h shouldn't have to depend on DEVS_ALL, but that would
+# involve rewriting gsconfig to only save the device name, not the
+# contents of the <device>.dev files.
+# FEATURE_DEVS must precede DEVICE_DEVS so that devices can override
+# features in obscure cases.
+
+DEVS_ALL=$(PLATFORM).dev $(FEATURE_DEVS) \
+ $(DEVICE_DEVS) $(DEVICE_DEVS1) \
+ $(DEVICE_DEVS2) $(DEVICE_DEVS3) $(DEVICE_DEVS4) $(DEVICE_DEVS5) \
+ $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
+ $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
+ $(DEVICE_DEVS14) $(DEVICE_DEVS15)
+
+devs_tr=devs.tr$(CONFIG)
+$(devs_tr): $(GS_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w $(devs_tr) - -include $(PLATFORM).dev
+ $(EXP)echogs -a $(devs_tr) - $(FEATURE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS1)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS2)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS3)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS4)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS5)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS6)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS7)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS8)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS9)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS10)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS11)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS12)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS13)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS14)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS15)
+
+# GCONFIG_EXTRAS can be set on the command line.
+# Note that it consists of arguments for echogs, i.e.,
+# it isn't just literal text.
+GCONFIG_EXTRAS=
+
+ld_tr=ld$(CONFIG).tr
+$(gconfig_h) $(ld_tr) lib.tr: \
+ $(GS_MAK) $(MAKEFILE) version.mak $(GENCONF_XE) $(ECHOGS_XE) $(devs_tr) $(DEVS_ALL) libcore.dev
+ $(EXP)genconf $(devs_tr) libcore.dev -h $(gconfig_h) $(CONFILES)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_LIB_DEFAULT -x 2022 $(GS_LIB_DEFAULT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u SEARCH_HERE_FIRST -s $(SEARCH_HERE_FIRST)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_DOCDIR -x 2022 $(GS_DOCDIR) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_INIT -x 2022 $(GS_INIT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISION -s $(GS_REVISION)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISIONDATE -s $(GS_REVISIONDATE)
+ $(EXP)echogs -a $(gconfig_h) $(GCONFIG_EXTRAS)
+
+################################################################
+# The other platform-independent makefiles are concatenated
+# (or included) after this one:
+# lib.mak
+# int.mak
+# jpeg.mak
+# libpng.mak
+# zlib.mak
+# devs.mak
+################################################################
diff --git a/gs/src/gs16spl.c b/gs/src/gs16spl.c
new file mode 100644
index 000000000..d8f4da5b6
--- /dev/null
+++ b/gs/src/gs16spl.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1995, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gs16spl.c */
+/* 16-bit access to print spooler from Win32s */
+/* by Russell Lang */
+/* 1995-11-23 */
+
+/*
+ * Ghostscript produces printer specific output
+ * which must be given to the print spooler.
+ * Under Win16, the APIs OpenJob, WriteSpool etc. are used
+ * Under Win32 and Windows 95/NT, the APIs OpenPrinter, WritePrinter etc.
+ * are used.
+ * Under Win32s, the 16-bit spooler APIs are not available, and the
+ * 32-bit spooler APIs are not implemented.
+ * This purpose of this application is to provide a means for the Win32s
+ * version of Ghostscript to send output to the 16-bit spooler.
+ */
+
+/*
+ * Usage: gs16spl port filename
+ *
+ * filename will be sent to the spooler port.
+ */
+
+
+#define STRICT
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ID_TEXT 100
+
+/* documented in Device Driver Adaptation Guide */
+/* Prototypes taken from print.h */
+DECLARE_HANDLE(HPJOB);
+
+HPJOB WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
+int WINAPI StartSpoolPage(HPJOB);
+int WINAPI EndSpoolPage(HPJOB);
+int WINAPI WriteSpool(HPJOB, LPSTR, int);
+int WINAPI CloseJob(HPJOB);
+int WINAPI DeleteJob(HPJOB, int);
+int WINAPI WriteDialog(HPJOB, LPSTR, int);
+int WINAPI DeleteSpoolPage(HPJOB);
+
+#define MAXSTR 256
+#define PRINT_BUF_SIZE 16384
+
+HPJOB hJob;
+HWND hwndspl;
+DLGPROC lpfnSpoolProc;
+HINSTANCE phInstance;
+char port[MAXSTR];
+char filename[MAXSTR];
+char error_message[MAXSTR];
+int error;
+
+char szAppName[] = "GS Win32s/Win16 spooler";
+
+/* returns TRUE on success, FALSE on failure */
+int
+spoolfile(char *portname, char *filename)
+{
+FILE *f;
+char *buffer;
+char pcdone[64];
+long ldone;
+long lsize;
+int count;
+MSG msg;
+ if ( (*portname == '\0') || (*filename == '\0') ) {
+ strcpy(error_message, "Usage: gs16spl port filename");
+ return FALSE;
+ }
+
+ if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
+ return FALSE;
+
+ if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
+ sprintf(error_message, "Can't open %s", filename);
+ free(buffer);
+ return FALSE;
+ }
+ fseek(f, 0L, SEEK_END);
+ lsize = ftell(f);
+ if (lsize <= 0)
+ lsize = 1;
+ fseek(f, 0L, SEEK_SET);
+ ldone = 0;
+
+ hJob = OpenJob(portname, filename, (HDC)NULL);
+ switch ((int)hJob) {
+ case SP_APPABORT:
+ case SP_ERROR:
+ case SP_OUTOFDISK:
+ case SP_OUTOFMEMORY:
+ case SP_USERABORT:
+ fclose(f);
+ free(buffer);
+ return FALSE;
+ }
+ if (StartSpoolPage(hJob) < 0)
+ error = TRUE;
+
+ while (!error
+ && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
+ if (WriteSpool(hJob, buffer, count) < 0)
+ error = TRUE;
+ ldone += count;
+ sprintf(pcdone, "%d%% written to %s", (int)(ldone * 100 / lsize), portname);
+ SetWindowText(GetDlgItem(hwndspl, ID_TEXT), pcdone);
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ free(buffer);
+ fclose(f);
+
+ EndSpoolPage(hJob);
+ if (error)
+ DeleteJob(hJob, 0);
+ else
+ CloseJob(hJob);
+ return !error;
+}
+
+
+/* Modeless dialog box - main window */
+BOOL CALLBACK _export
+SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ SetWindowText(hDlg, szAppName);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ error = TRUE;
+ DestroyWindow(hDlg);
+ EndDialog(hDlg, 0);
+ PostQuitMessage(0);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void
+init_window(LPSTR cmdline)
+{
+ LPSTR s;
+ char *d;
+ s = cmdline;
+ /* skip leading spaces */
+ while (*s && *s==' ')
+ s++;
+ /* copy port name */
+ d = port;
+ while (*s && *s!=' ')
+ *d++ = *s++;
+ *d='\0';
+ /* skip spaces */
+ while (*s && *s==' ')
+ s++;
+ /* copy port name */
+ d = filename;
+ while (*s && *s!=' ')
+ *d++ = *s++;
+ *d='\0';
+
+ lpfnSpoolProc = (DLGPROC)MakeProcInstance((FARPROC)SpoolDlgProc, phInstance);
+ hwndspl = CreateDialog(phInstance, "SpoolDlgBox", HWND_DESKTOP, lpfnSpoolProc);
+
+ return;
+}
+
+int PASCAL
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
+{
+ MSG msg;
+ phInstance = hInstance;
+
+ init_window(lpszCmdLine);
+ ShowWindow(hwndspl, cmdShow);
+
+ if (!spoolfile(port, filename)) {
+ /* wait, showing error message */
+ SetWindowText(GetDlgItem(hwndspl, ID_TEXT), error_message);
+ while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ DestroyWindow(hwndspl);
+ FreeProcInstance((FARPROC)lpfnSpoolProc);
+ return 0;
+}
+
diff --git a/gs/src/gs16spl.def b/gs/src/gs16spl.def
new file mode 100644
index 000000000..cd6ca4615
--- /dev/null
+++ b/gs/src/gs16spl.def
@@ -0,0 +1,7 @@
+NAME GS16SPL
+DESCRIPTION 'GS Win32s/Win16 spooler interface'
+EXETYPE WINDOWS
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MULTIPLE MOVEABLE
+HEAPSIZE 256
+STACKSIZE 16384
diff --git a/gs/src/gs16spl.rc b/gs/src/gs16spl.rc
new file mode 100644
index 000000000..36047439d
--- /dev/null
+++ b/gs/src/gs16spl.rc
@@ -0,0 +1,38 @@
+/* Copyright (C) 1995, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gs16spl.rc */
+/* Resources for GS16SPL.EXE, 16-bit access to print spooler */
+/* 1995-11-10 */
+
+#include <windows.h>
+
+#define ID_TEXT 100
+
+1 ICON "gstext.ico"
+
+SpoolDlgBox DIALOG 20, 32, 158, 56
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "GS Win32s/Win16 spooler"
+FONT 8, "Helv"
+BEGIN
+ CONTROL "&Cancel", IDCANCEL, "button", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 8, 36, 32, 14
+ ICON 1, 1, 8, 8, 16, 16
+ LTEXT "", ID_TEXT, 40, 12, 108, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+END
+
diff --git a/gs/src/gsalloc.c b/gs/src/gsalloc.c
new file mode 100644
index 000000000..6e872d623
--- /dev/null
+++ b/gs/src/gsalloc.c
@@ -0,0 +1,1282 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsalloc.c */
+/* Standard memory allocator */
+#include "gx.h"
+#include "memory_.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "gxalloc.h"
+
+/*
+ * This allocator produces tracing messages of the form
+ * [aNMOTS]...
+ * where
+ * N is the VM space number,
+ * M is : for movable objects, | for immovable,
+ * O is {alloc = +, free = -, grow = >, shrink = <},
+ * T is {bytes = b, object = <, ref = $, string = >}, and
+ * S is {freelist = F, LIFO = space, own chunk = L, lost = #,
+ * lost own chunk = ~, other = .}.
+ */
+
+/* The structure descriptor for allocators. Even though allocators */
+/* are allocated outside GC space, they reference objects within it. */
+public_st_ref_memory();
+#define mptr ((gs_ref_memory_t *)vptr)
+private ENUM_PTRS_BEGIN(ref_memory_enum_ptrs) return 0;
+ ENUM_PTR(0, gs_ref_memory_t, changes);
+ ENUM_PTR(1, gs_ref_memory_t, saved);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(ref_memory_reloc_ptrs) {
+ RELOC_PTR(gs_ref_memory_t, changes);
+ /* Don't relocate the pointer now -- see igc.c for details. */
+ mptr->reloc_saved = gs_reloc_struct_ptr(mptr->saved, gcst);
+} RELOC_PTRS_END
+
+/* Forward references */
+private ulong compute_free_objects(P1(gs_ref_memory_t *));
+private obj_header_t *alloc_obj(P5(gs_ref_memory_t *, ulong, gs_memory_type_ptr_t, bool, client_name_t));
+private chunk_t *alloc_add_chunk(P4(gs_ref_memory_t *, ulong, bool, client_name_t));
+void alloc_close_chunk(P1(gs_ref_memory_t *));
+
+#define imem ((gs_ref_memory_t *)mem)
+
+/*
+ * Define the standard implementation (with garbage collection)
+ * of Ghostscript's memory manager interface.
+ */
+private gs_memory_proc_alloc_bytes(i_alloc_bytes);
+private gs_memory_proc_alloc_bytes(i_alloc_bytes_immovable);
+private gs_memory_proc_alloc_struct(i_alloc_struct);
+private gs_memory_proc_alloc_struct(i_alloc_struct_immovable);
+private gs_memory_proc_alloc_byte_array(i_alloc_byte_array);
+private gs_memory_proc_alloc_byte_array(i_alloc_byte_array_immovable);
+private gs_memory_proc_alloc_struct_array(i_alloc_struct_array);
+private gs_memory_proc_alloc_struct_array(i_alloc_struct_array_immovable);
+private gs_memory_proc_resize_object(i_resize_object);
+private gs_memory_proc_object_size(i_object_size);
+private gs_memory_proc_object_type(i_object_type);
+private gs_memory_proc_free_object(i_free_object);
+private gs_memory_proc_alloc_string(i_alloc_string);
+private gs_memory_proc_alloc_string(i_alloc_string_immovable);
+private gs_memory_proc_resize_string(i_resize_string);
+private gs_memory_proc_free_string(i_free_string);
+private gs_memory_proc_register_root(i_register_root);
+private gs_memory_proc_unregister_root(i_unregister_root);
+private gs_memory_proc_status(i_status);
+private gs_memory_proc_enable_free(i_enable_free);
+/* We export the procedures for subclasses. */
+const gs_memory_procs_t gs_ref_memory_procs = {
+ i_alloc_bytes,
+ i_alloc_bytes_immovable,
+ i_alloc_struct,
+ i_alloc_struct_immovable,
+ i_alloc_byte_array,
+ i_alloc_byte_array_immovable,
+ i_alloc_struct_array,
+ i_alloc_struct_array_immovable,
+ i_resize_object,
+ i_object_size,
+ i_object_type,
+ i_free_object,
+ i_alloc_string,
+ i_alloc_string_immovable,
+ i_resize_string,
+ i_free_string,
+ i_register_root,
+ i_unregister_root,
+ i_status,
+ i_enable_free
+};
+/*
+ * Allocate and mostly initialize the state of an allocator (system, global,
+ * or local). Does not initialize global or space.
+ */
+private void *ialloc_solo(P3(gs_memory_t *, gs_memory_type_ptr_t, chunk_t **));
+gs_ref_memory_t *
+ialloc_alloc_state(gs_memory_t *parent, uint chunk_size)
+{ chunk_t *cp;
+ gs_ref_memory_t *iimem = ialloc_solo(parent, &st_ref_memory, &cp);
+
+ if ( iimem == 0 )
+ return 0;
+ iimem->procs = gs_ref_memory_procs;
+ iimem->parent = parent;
+ iimem->chunk_size = chunk_size;
+ iimem->large_size = ((chunk_size / 4) & -obj_align_mod) + 1;
+ iimem->gc_status.vm_threshold = chunk_size * 3L;
+ iimem->gc_status.max_vm = max_long;
+ iimem->gc_status.psignal = NULL;
+ iimem->gc_status.enabled = false;
+ iimem->previous_status.allocated = 0;
+ iimem->previous_status.used = 0;
+ ialloc_reset(iimem);
+ iimem->cfirst = iimem->clast = cp;
+ ialloc_set_limit(iimem);
+ iimem->cc.cbot = iimem->cc.ctop = 0;
+ iimem->pcc = 0;
+ iimem->roots = 0;
+ iimem->num_contexts = 1;
+ iimem->saved = 0;
+ return iimem;
+}
+/* Allocate a 'solo' object with its own chunk. */
+private void *
+ialloc_solo(gs_memory_t *parent, gs_memory_type_ptr_t pstype, chunk_t **pcp)
+{ /*
+ * We can't assume that the parent uses the same object header
+ * that we do, but the GC requires that allocators have
+ * such a header. Therefore, we prepend one explicitly.
+ */
+ chunk_t *cp = gs_alloc_struct_immovable(parent, chunk_t, &st_chunk,
+ "ialloc_solo(chunk)");
+ uint csize =
+ round_up(sizeof(chunk_head_t) + sizeof(obj_header_t) +
+ pstype->ssize,
+ obj_align_mod);
+ byte *cdata = gs_alloc_bytes_immovable(parent, csize, "ialloc_solo");
+ obj_header_t *obj = (obj_header_t *)(cdata + sizeof(chunk_head_t));
+
+ if ( cp == 0 || cdata == 0 )
+ return 0;
+ alloc_init_chunk(cp, cdata, cdata + csize, false, (chunk_t *)NULL);
+ cp->cbot = cp->ctop;
+ cp->cprev = cp->cnext = 0;
+ /* Construct the object header "by hand". */
+ obj->o_large = 0;
+ obj->o_size = pstype->ssize;
+ obj->o_type = pstype;
+ *pcp = cp;
+ return (void *)(obj + 1);
+}
+/* Initialize after a save. */
+void
+ialloc_reset(gs_ref_memory_t *mem)
+{ mem->cfirst = 0;
+ mem->clast = 0;
+ mem->cc.rcur = 0;
+ mem->cc.rtop = 0;
+ mem->cc.has_refs = false;
+ mem->allocated = 0;
+ mem->inherited = 0;
+ mem->changes = 0;
+ ialloc_reset_free(mem);
+}
+/* Initialize after a save or GC. */
+void
+ialloc_reset_free(gs_ref_memory_t *mem)
+{ int i;
+ obj_header_t **p;
+ mem->lost.objects = 0;
+ mem->lost.refs = 0;
+ mem->lost.strings = 0;
+ mem->cfreed.cp = 0;
+ for ( i = 0, p = &mem->freelists[0]; i < num_freelists; i++, p++ )
+ *p = 0;
+}
+/* Set the allocation limit after a change in one or more of */
+/* vm_threshold, max_vm, or enabled, or after a GC. */
+void
+ialloc_set_limit(register gs_ref_memory_t *mem)
+{ /*
+ * The following code is intended to set the limit so that
+ * we stop allocating when allocated + previous_status.allocated
+ * exceeds the lesser of max_vm or (if GC is enabled)
+ * gc_allocated + vm_threshold.
+ */
+ ulong max_allocated =
+ (mem->gc_status.max_vm > mem->previous_status.allocated ?
+ mem->gc_status.max_vm - mem->previous_status.allocated :
+ 0);
+ if ( mem->gc_status.enabled )
+ { ulong limit = mem->gc_allocated + mem->gc_status.vm_threshold;
+ if ( limit < mem->previous_status.allocated )
+ mem->limit = 0;
+ else
+ { limit -= mem->previous_status.allocated;
+ mem->limit = min(limit, max_allocated);
+ }
+ }
+ else
+ mem->limit = max_allocated;
+ if_debug7('0', "[0]space=%d, max_vm=%ld, prev.alloc=%ld, enabled=%d,\n\
+ gc_alloc=%ld, threshold=%ld => limit=%ld\n",
+ mem->space, (long)mem->gc_status.max_vm,
+ (long)mem->previous_status.allocated,
+ mem->gc_status.enabled, (long)mem->gc_allocated,
+ (long)mem->gc_status.vm_threshold, (long)mem->limit);
+}
+
+/* ================ Accessors ================ */
+
+/* Get the size of an object from the header. */
+private uint
+i_object_size(gs_memory_t *mem, const void /*obj_header_t*/ *obj)
+{ return pre_obj_contents_size((const obj_header_t *)obj - 1);
+}
+
+/* Get the type of a structure from the header. */
+private gs_memory_type_ptr_t
+i_object_type(gs_memory_t *mem, const void /*obj_header_t*/ *obj)
+{ return ((const obj_header_t *)obj - 1)->o_type;
+}
+
+/* Get the GC status of a memory. */
+void
+gs_memory_gc_status(const gs_ref_memory_t *mem, gs_memory_gc_status_t *pstat)
+{ *pstat = mem->gc_status;
+}
+
+/* Set the GC status of a memory. */
+void
+gs_memory_set_gc_status(gs_ref_memory_t *mem, const gs_memory_gc_status_t *pstat)
+{ mem->gc_status = *pstat;
+ ialloc_set_limit(mem);
+}
+
+/* ================ Objects ================ */
+
+/* Allocate a small object quickly if possible. */
+/* The size must be substantially less than max_uint. */
+/* ptr must be declared as obj_header_t *. */
+/* pfl must be declared as obj_header_t **. */
+#define IF_FREELIST_ALLOC(ptr, imem, size, pstype, pfl)\
+ if ( size <= max_freelist_size &&\
+ *(pfl = &imem->freelists[(size + obj_align_mask) >> log2_obj_align_mod]) != 0\
+ )\
+ { ptr = *pfl;\
+ *pfl = *(obj_header_t **)ptr;\
+ ptr[-1].o_size = size;\
+ ptr[-1].o_type = pstype;\
+ /* If debugging, clear the block in an attempt to */\
+ /* track down uninitialized data errors. */\
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+#define ELSEIF_LIFO_ALLOC(ptr, imem, size, pstype)\
+ }\
+ else if ( (imem->cc.ctop - (byte *)(ptr = (obj_header_t *)imem->cc.cbot))\
+ >= size + (obj_align_mod + sizeof(obj_header_t) * 2) &&\
+ size < imem->large_size\
+ )\
+ { imem->cc.cbot = (byte *)ptr + obj_size_round(size);\
+ ptr->o_large = 0;\
+ ptr->o_size = size;\
+ ptr->o_type = pstype;\
+ ptr++;\
+ /* If debugging, clear the block in an attempt to */\
+ /* track down uninitialized data errors. */\
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+#define ELSE_ALLOC\
+ }\
+ else
+
+private byte *
+i_alloc_bytes(gs_memory_t *mem, uint size, client_name_t cname)
+{ obj_header_t *obj;
+ obj_header_t **pfl;
+ IF_FREELIST_ALLOC(obj, imem, size, &st_bytes, pfl)
+ if_debug4('A', "[a%d:+bF]%s -bytes-(%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), size, (ulong)obj);
+ ELSEIF_LIFO_ALLOC(obj, imem, size, &st_bytes)
+ if_debug4('A', "[a%d:+b ]%s -bytes-(%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), size, (ulong)obj);
+ ELSE_ALLOC
+ { obj = alloc_obj(imem, size, &st_bytes, false, cname);
+ if ( obj == 0 )
+ return 0;
+ if_debug4('A', "[a%d:+b.]%s -bytes-(%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), size, (ulong)obj);
+ }
+ return (byte *)obj;
+}
+private byte *
+i_alloc_bytes_immovable(gs_memory_t *mem, uint size, client_name_t cname)
+{ obj_header_t *obj = alloc_obj(imem, size, &st_bytes, true, cname);
+ if ( obj == 0 )
+ return 0;
+ if_debug4('A', "[a%d|+b.]%s -bytes-(%u) = 0x%lx\n",
+ imem->space, client_name_string(cname), size, (ulong)obj);
+ return (byte *)obj;
+}
+private void *
+i_alloc_struct(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{ uint size = pstype->ssize;
+ obj_header_t *obj;
+ obj_header_t **pfl;
+ IF_FREELIST_ALLOC(obj, imem, size, pstype, pfl)
+ if_debug5('A', "[a%d:+<F]%s %s(%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ struct_type_name_string(pstype), size, (ulong)obj);
+ ELSEIF_LIFO_ALLOC(obj, imem, size, pstype)
+ if_debug5('A', "[a%d:+< ]%s %s(%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ struct_type_name_string(pstype), size, (ulong)obj);
+ ELSE_ALLOC
+ { obj = alloc_obj(imem, size, pstype, false, cname);
+ if ( obj == 0 )
+ return 0;
+ if_debug5('A', "[a%d:+<.]%s %s(%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ struct_type_name_string(pstype), size, (ulong)obj);
+ }
+ return obj;
+}
+private void *
+i_alloc_struct_immovable(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{ uint size = pstype->ssize;
+ obj_header_t *obj = alloc_obj(imem, size, pstype, true, cname);
+ if ( obj == 0 )
+ return 0;
+ if_debug5('A', "[a%d|+<.]%s %s(%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ struct_type_name_string(pstype), size, (ulong)obj);
+ return obj;
+}
+private byte *
+i_alloc_byte_array(gs_memory_t *mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{ obj_header_t *obj = alloc_obj(imem, (ulong)num_elements * elt_size,
+ &st_bytes, false, cname);
+ if_debug6('A', "[a%d:+b.]%s -bytes-*(%lu=%u*%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ (ulong)num_elements * elt_size,
+ num_elements, elt_size, (ulong)obj);
+ return (byte *)obj;
+}
+private byte *
+i_alloc_byte_array_immovable(gs_memory_t *mem, uint num_elements,
+ uint elt_size, client_name_t cname)
+{ obj_header_t *obj = alloc_obj(imem, (ulong)num_elements * elt_size,
+ &st_bytes, true, cname);
+ if_debug6('A', "[a%d|+b.]%s -bytes-*(%lu=%u*%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ (ulong)num_elements * elt_size,
+ num_elements, elt_size, (ulong)obj);
+ return (byte *)obj;
+}
+private void *
+i_alloc_struct_array(gs_memory_t *mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{ obj_header_t *obj = alloc_obj(imem,
+ (ulong)num_elements * pstype->ssize,
+ pstype, false, cname);
+ if_debug7('A', "[a%d:+<.]%s %s*(%lu=%u*%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), struct_type_name_string(pstype),
+ (ulong)num_elements * pstype->ssize,
+ num_elements, pstype->ssize, (ulong)obj);
+ return (char *)obj;
+}
+private void *
+i_alloc_struct_array_immovable(gs_memory_t *mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{ obj_header_t *obj = alloc_obj(imem,
+ (ulong)num_elements * pstype->ssize,
+ pstype, true, cname);
+ if_debug7('A', "[a%d|+<.]%s %s*(%lu=%u*%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), struct_type_name_string(pstype),
+ (ulong)num_elements * pstype->ssize,
+ num_elements, pstype->ssize, (ulong)obj);
+ return (char *)obj;
+}
+private void *
+i_resize_object(gs_memory_t *mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{ obj_header_t *pp = (obj_header_t *)obj - 1;
+ gs_memory_type_ptr_t pstype = pp->o_type;
+ ulong old_size = pre_obj_contents_size(pp);
+ ulong new_size = (ulong)pstype->ssize * new_num_elements;
+ void *new_obj;
+
+ if ( (byte *)obj + obj_align_round(old_size) == imem->cc.cbot &&
+ imem->cc.ctop - imem->cc.cbot > new_size + obj_align_mod
+ )
+ { imem->cc.cbot = (byte *)obj + obj_align_round(new_size);
+ pp->o_size = new_size;
+ if_debug8('A', "[a%d:%c%c ]%s %s(%lu=>%lu) 0x%lx\n",
+ imem->space,
+ (new_size > old_size ? '>' : '<'),
+ (pstype == &st_bytes ? 'b' : '<'),
+ client_name_string(cname),
+ struct_type_name_string(pstype),
+ old_size, new_size, (ulong)obj);
+ return obj;
+ }
+ /* Punt. */
+ new_obj = gs_alloc_struct_array(mem, new_num_elements, void,
+ pstype, cname);
+ if ( new_obj == 0 )
+ return 0;
+ memcpy(new_obj, obj, min(old_size, new_size));
+ gs_free_object(mem, obj, cname);
+ return new_obj;
+}
+private void
+i_free_object(gs_memory_t *mem, void *ptr, client_name_t cname)
+{ obj_header_t *pp;
+ struct_proc_finalize((*finalize));
+ uint size;
+
+ if ( ptr == 0 )
+ return;
+ pp = (obj_header_t *)ptr - 1;
+#ifdef DEBUG
+ if ( gs_debug_c('?') )
+ { chunk_locator_t cld;
+
+ if ( pp->o_type == &st_free )
+ { lprintf2("%s: object 0x%lx already free!\n",
+ client_name_string(cname), (ulong)ptr);
+ return;/*gs_abort();*/
+ }
+ /* Check that this allocator owns the object being freed. */
+ cld.memory = imem;
+ while ( (cld.cp = cld.memory->clast),
+ !chunk_locate_ptr(ptr, &cld)
+ )
+ { if ( !cld.memory->saved )
+ { lprintf3("%s: freeing 0x%lx, not owned by memory 0x%lx!\n",
+ client_name_string(cname), (ulong)ptr,
+ (ulong)mem);
+ return;/*gs_abort();*/
+ }
+ /****** HACK: we know the saved state is the first ******
+ ****** member of an alloc_save_t. ******/
+ cld.memory = (gs_ref_memory_t *)cld.memory->saved;
+ }
+ /* Check that the object is in the allocated region. */
+ if ( cld.memory == imem && cld.cp == imem->pcc )
+ cld.cp = &imem->cc;
+ if ( !(ptr_between((const byte *)pp, cld.cp->cbase,
+ cld.cp->cbot))
+ )
+ { lprintf5("%s: freeing 0x%lx,\n\toutside chunk 0x%lx cbase=0x%lx, cbot=0x%lx!\n",
+ client_name_string(cname), (ulong)ptr,
+ (ulong)cld.cp, (ulong)cld.cp->cbase,
+ (ulong)cld.cp->cbot);
+ return;/*gs_abort();*/
+ }
+ }
+#endif
+ size = pre_obj_contents_size(pp);
+ finalize = pp->o_type->finalize;
+ if ( finalize != 0 )
+ { if_debug3('u', "[u]finalizing %s 0x%lx (%s)\n",
+ struct_type_name_string(pp->o_type),
+ (ulong)ptr, client_name_string(cname));
+ (*finalize)(ptr);
+ }
+ if ( (byte *)ptr + obj_align_round(size) == imem->cc.cbot )
+ { if_debug4('A', "[a%d:-o ]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), size, (ulong)ptr);
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ imem->cc.cbot = (byte *)pp;
+ return;
+ }
+ if ( pp->o_large )
+ { /*
+ * We gave this object its own chunk. Free the entire chunk,
+ * unless it belongs to an older save level, in which case
+ * we mustn't overwrite it.
+ */
+ chunk_locator_t cl;
+#ifdef DEBUG
+ { chunk_locator_t cld;
+ cld.memory = imem;
+ cld.cp = 0;
+ if_debug5('a', "[a%d:-o%c]%s(%u) 0x%lx\n", imem->space,
+ (chunk_locate_ptr(ptr, &cld) ? 'L' : '~'),
+ client_name_string(cname), size, (ulong)ptr);
+ }
+#endif
+ cl.memory = imem;
+ cl.cp = 0;
+ if ( chunk_locate_ptr(ptr, &cl) )
+ { alloc_free_chunk(cl.cp, imem);
+ return;
+ }
+ /* Don't overwrite even if gs_alloc_debug is set. */
+ }
+ if ( size <= max_freelist_size &&
+ obj_align_round(size) >= sizeof(obj_header_t *)
+ )
+ { /*
+ * Put the object on a freelist, unless it belongs to
+ * an older save level, in which case we mustn't
+ * overwrite it.
+ */
+ imem->cfreed.memory = imem;
+ if ( chunk_locate(ptr, &imem->cfreed) )
+ { obj_header_t **pfl =
+ &imem->freelists[(size + obj_align_mask) >>
+ log2_obj_align_mod];
+ pp->o_type = &st_free; /* don't confuse GC */
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ *(obj_header_t **)ptr = *pfl;
+ *pfl = (obj_header_t *)ptr;
+ if_debug4('A', "[a%d:-oF]%s(%u) 0x%lx\n",
+ imem->space, client_name_string(cname),
+ size, (ulong)ptr);
+ return;
+ }
+ /* Don't overwrite even if gs_alloc_debug is set. */
+ }
+ else
+ { pp->o_type = &st_free; /* don't confuse GC */
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ }
+ if_debug4('A', "[a%d:-o#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), size, (ulong)ptr);
+ imem->lost.objects += obj_size_round(size);
+}
+private byte *
+i_alloc_string(gs_memory_t *mem, uint nbytes, client_name_t cname)
+{ byte *str;
+top: if ( imem->cc.ctop - imem->cc.cbot > nbytes )
+ { if_debug4('A', "[a%d:+> ]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes,
+ (ulong)(imem->cc.ctop - nbytes));
+ str = imem->cc.ctop -= nbytes;
+ gs_alloc_fill(str, gs_alloc_fill_alloc, nbytes);
+ return str;
+ }
+ if ( nbytes > string_space_quanta(max_uint - sizeof(chunk_head_t)) *
+ string_data_quantum
+ )
+ { /* Can't represent the size in a uint! */
+ return 0;
+ }
+ if ( nbytes >= imem->large_size )
+ { /* Give it a chunk all its own. */
+ return i_alloc_string_immovable(mem, nbytes, cname);
+ }
+ else
+ { /* Add another chunk. */
+ chunk_t *cp =
+ alloc_add_chunk(imem, (ulong)imem->chunk_size, true,
+ "chunk");
+ if ( cp == 0 )
+ return 0;
+ alloc_close_chunk(imem);
+ imem->pcc = cp;
+ imem->cc = *imem->pcc;
+ gs_alloc_fill(imem->cc.cbase, gs_alloc_fill_free,
+ imem->cc.climit - imem->cc.cbase);
+ goto top;
+ }
+}
+private byte *
+i_alloc_string_immovable(gs_memory_t *mem, uint nbytes, client_name_t cname)
+{ byte *str;
+ /* Give it a chunk all its own. */
+ uint asize = string_chunk_space(nbytes) + sizeof(chunk_head_t);
+ chunk_t *cp = alloc_add_chunk(imem, (ulong)asize, true,
+ "large string chunk");
+ if ( cp == 0 )
+ return 0;
+ str = cp->ctop = cp->climit - nbytes;
+ if_debug4('a', "[a%d|+>L]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong)str);
+ gs_alloc_fill(str, gs_alloc_fill_alloc, nbytes);
+ return str;
+}
+private byte *
+i_resize_string(gs_memory_t *mem, byte *data, uint old_num, uint new_num,
+ client_name_t cname)
+{ byte *ptr;
+ if ( data == imem->cc.ctop &&
+ (new_num < old_num ||
+ imem->cc.ctop - imem->cc.cbot > new_num - old_num)
+ )
+ { /* Resize in place. */
+ ptr = data + old_num - new_num;
+ if_debug6('A', "[a%d:%c> ]%s(%u->%u) 0x%lx\n",
+ imem->space, (new_num > old_num ? '>' : '<'),
+ client_name_string(cname), old_num, new_num,
+ (ulong)ptr);
+ imem->cc.ctop = ptr;
+ memmove(ptr, data, min(old_num, new_num));
+#ifdef DEBUG
+ if ( new_num > old_num )
+ gs_alloc_fill(ptr + old_num, gs_alloc_fill_alloc,
+ new_num - old_num);
+ else
+ gs_alloc_fill(data, gs_alloc_fill_free, old_num - new_num);
+#endif
+ }
+ else
+ { /* Punt. */
+ ptr = gs_alloc_string(mem, new_num, cname);
+ if ( ptr == 0 )
+ return 0;
+ memcpy(ptr, data, min(old_num, new_num));
+ gs_free_string(mem, data, old_num, cname);
+ }
+ return ptr;
+}
+private void
+i_free_string(gs_memory_t *mem, byte *data, uint nbytes,
+ client_name_t cname)
+{ if ( data == imem->cc.ctop )
+ { if_debug4('A', "[a%d:-> ]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong)data);
+ imem->cc.ctop += nbytes;
+ }
+ else
+ { if_debug4('A', "[a%d:->#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong)data);
+ imem->lost.strings += nbytes;
+ }
+ gs_alloc_fill(data, gs_alloc_fill_free, nbytes);
+}
+private void
+i_status(gs_memory_t *mem, gs_memory_status_t *pstat)
+{ ulong unused = imem->lost.refs + imem->lost.strings;
+ ulong inner = 0;
+
+ alloc_close_chunk(imem);
+ /* Add up unallocated space within each chunk. */
+ /* Also keep track of space allocated to inner chunks, */
+ /* which are included in previous_status.allocated. */
+ { const chunk_t *cp = imem->cfirst;
+ while ( cp != 0 )
+ { unused += cp->ctop - cp->cbot;
+ if ( cp->outer )
+ inner += cp->cend - (byte *)cp->chead;
+ cp = cp->cnext;
+ }
+ }
+ unused += compute_free_objects(imem);
+ pstat->used = imem->allocated + inner - unused +
+ imem->previous_status.used;
+ pstat->allocated = imem->allocated +
+ imem->previous_status.allocated;
+}
+
+private void
+i_enable_free(gs_memory_t *mem, bool enable)
+{ if ( enable )
+ mem->procs.free_object = i_free_object,
+ mem->procs.free_string = i_free_string;
+ else
+ mem->procs.free_object = gs_ignore_free_object,
+ mem->procs.free_string = gs_ignore_free_string;
+}
+
+/* ------ Internal procedures ------ */
+
+/* Compute the amount of free object space by scanning free lists. */
+private ulong
+compute_free_objects(gs_ref_memory_t *mem)
+{ ulong unused = mem->lost.objects;
+ int i;
+
+ /* Add up space on free lists. */
+ for ( i = 0; i < num_freelists; i++ )
+ { uint free_size =
+ (i << log2_obj_align_mod) + sizeof(obj_header_t);
+ const obj_header_t *pfree;
+
+ for ( pfree = mem->freelists[i]; pfree != 0;
+ pfree = *(const obj_header_t * const *)pfree
+ )
+ unused += free_size;
+ }
+ return unused;
+}
+
+/* Allocate an object. This handles all but the fastest, simplest case. */
+private obj_header_t *
+alloc_obj(gs_ref_memory_t *mem, ulong lsize, gs_memory_type_ptr_t pstype,
+ bool immovable, client_name_t cname)
+{ obj_header_t *ptr;
+ if ( lsize >= mem->large_size || immovable )
+ { ulong asize =
+ ((lsize + obj_align_mask) & -obj_align_mod) +
+ sizeof(obj_header_t);
+ /* Give it a chunk all its own. */
+ chunk_t *cp =
+ alloc_add_chunk(mem, asize + sizeof(chunk_head_t), false,
+ "large object chunk");
+ if ( cp == 0 )
+ return 0;
+ ptr = (obj_header_t *)cp->cbot;
+ cp->cbot += asize;
+ ptr->o_large = 1;
+ pre_obj_set_large_size(ptr, lsize);
+ }
+ else
+ { uint asize = obj_size_round((uint)lsize);
+ while ( mem->cc.ctop -
+ (byte *)(ptr = (obj_header_t *)mem->cc.cbot)
+ <= asize + sizeof(obj_header_t) )
+ { /* Add another chunk. */
+ chunk_t *cp =
+ alloc_add_chunk(mem, (ulong)mem->chunk_size,
+ true, "chunk");
+ if ( cp == 0 )
+ return 0;
+ alloc_close_chunk(mem);
+ mem->pcc = cp;
+ mem->cc = *mem->pcc;
+ gs_alloc_fill(mem->cc.cbase, gs_alloc_fill_free,
+ mem->cc.climit - mem->cc.cbase);
+ }
+ mem->cc.cbot = (byte *)ptr + asize;
+ ptr->o_large = 0;
+ ptr->o_size = (uint)lsize;
+ }
+ ptr->o_type = pstype;
+ ptr++;
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, lsize);
+ return ptr;
+}
+
+/* ================ Roots ================ */
+
+/* Register a root. */
+private void
+i_register_root(gs_memory_t *mem, gs_gc_root_t *rp, gs_ptr_type_t ptype,
+ void **up, client_name_t cname)
+{ if_debug3('8', "[8]register root(%s) 0x%lx -> 0x%lx\n",
+ client_name_string(cname), (ulong)rp, (ulong)up);
+ rp->ptype = ptype, rp->p = up;
+ rp->next = imem->roots, imem->roots = rp;
+}
+
+/* Unregister a root. */
+private void
+i_unregister_root(gs_memory_t *mem, gs_gc_root_t *rp, client_name_t cname)
+{ gs_gc_root_t **rpp = &imem->roots;
+ if_debug2('8', "[8]unregister root(%s) 0x%lx\n",
+ client_name_string(cname), (ulong)rp);
+ while ( *rpp != rp ) rpp = &(*rpp)->next;
+ *rpp = (*rpp)->next;
+}
+
+/* ================ Chunks ================ */
+
+public_st_chunk();
+
+/* Insert a chunk in the chain. This is exported for the GC and for */
+/* the forget_save operation. */
+void
+alloc_link_chunk(chunk_t *cp, gs_ref_memory_t *mem)
+{ byte *cdata = cp->cbase;
+ chunk_t *icp;
+ chunk_t *prev;
+ for ( icp = mem->cfirst; icp != 0 && ptr_ge(cdata, icp->ctop);
+ icp = icp->cnext
+ )
+ ;
+ cp->cnext = icp;
+ if ( icp == 0 ) /* add at end of chain */
+ { prev = imem->clast;
+ imem->clast = cp;
+ }
+ else /* insert before icp */
+ { prev = icp->cprev;
+ icp->cprev = cp;
+ }
+ cp->cprev = prev;
+ if ( prev == 0 )
+ imem->cfirst = cp;
+ else
+ prev->cnext = cp;
+ if ( imem->pcc != 0 )
+ { imem->cc.cnext = imem->pcc->cnext;
+ imem->cc.cprev = imem->pcc->cprev;
+ }
+}
+
+/* Allocate a chunk. If we would exceed MaxLocalVM (if relevant), */
+/* or if we would exceed the VMThreshold and psignal is NULL, */
+/* return 0; if we would exceed the VMThreshold but psignal is valid, */
+/* just set the signal and return successfully. */
+private chunk_t *
+alloc_add_chunk(gs_ref_memory_t *mem, ulong csize, bool has_strings,
+ client_name_t cname)
+{ gs_memory_t *parent = mem->parent;
+ chunk_t *cp = gs_alloc_struct_immovable(parent, chunk_t, &st_chunk,
+ cname);
+ byte *cdata;
+ /* If csize is larger than max_uint, */
+ /* we have to fake it using gs_alloc_byte_array. */
+ ulong elt_size = csize;
+ uint num_elts = 1;
+ if ( (ulong)(mem->allocated + mem->inherited) >= mem->limit )
+ { mem->gc_status.requested += csize;
+ if ( mem->limit >= mem->gc_status.max_vm ||
+ mem->gc_status.psignal == 0
+ )
+ return 0;
+ if_debug4('0', "[0]signaling space=%d, allocated=%ld, limit=%ld, requested=%ld\n",
+ mem->space, (long)mem->allocated,
+ (long)mem->limit, (long)mem->gc_status.requested);
+ *mem->gc_status.psignal = mem->gc_status.signal_value;
+ }
+ while ( (uint)elt_size != elt_size )
+ elt_size = (elt_size + 1) >> 1,
+ num_elts <<= 1;
+ cdata = gs_alloc_byte_array_immovable(parent, num_elts, elt_size,
+ cname);
+ if ( cp == 0 || cdata == 0 )
+ { gs_free_object(parent, cdata, cname);
+ gs_free_object(parent, cp, cname);
+ mem->gc_status.requested = csize;
+ return 0;
+ }
+ alloc_init_chunk(cp, cdata, cdata + csize, has_strings, (chunk_t *)0);
+ alloc_link_chunk(cp, mem);
+ mem->allocated +=
+ gs_object_size(parent, cdata) + gs_object_size(parent, cp);
+ return cp;
+}
+
+/* Initialize the pointers in a chunk. This is exported for save/restore. */
+/* The bottom pointer must be aligned, but the top pointer need not */
+/* be aligned. */
+void
+alloc_init_chunk(chunk_t *cp, byte *bot, byte *top, bool has_strings,
+ chunk_t *outer)
+{ byte *cdata = bot;
+ if ( outer != 0 )
+ outer->inner_count++;
+ cp->chead = (chunk_head_t *)cdata;
+ cdata += sizeof(chunk_head_t);
+ cp->cbot = cp->cbase = cdata;
+ cp->cend = top;
+ cp->rcur = 0;
+ cp->rtop = 0;
+ cp->outer = outer;
+ cp->inner_count = 0;
+ cp->has_refs = false;
+ cp->sbase = cdata;
+ if ( has_strings && top - cdata >= string_space_quantum + sizeof(long) - 1)
+ { /*
+ * We allocate a large enough string marking and reloc table
+ * to cover the entire chunk.
+ */
+ uint nquanta = string_space_quanta(top - cdata);
+ cp->climit = cdata + nquanta * string_data_quantum;
+ cp->smark = cp->climit;
+ cp->smark_size = string_quanta_mark_size(nquanta);
+ cp->sreloc =
+ (string_reloc_offset *)(cp->smark + cp->smark_size);
+ cp->sfree1 = (ushort *)cp->sreloc;
+ }
+ else
+ { /* No strings, don't need the string GC tables. */
+ cp->climit = cp->cend;
+ cp->sfree1 = 0;
+ cp->smark = 0;
+ cp->smark_size = 0;
+ cp->sreloc = 0;
+ }
+ cp->ctop = cp->climit;
+ alloc_init_free_strings(cp);
+}
+
+/* Initialize the string freelists in a chunk. */
+void
+alloc_init_free_strings(chunk_t *cp)
+{ if ( cp->sfree1 )
+ memset(cp->sfree1, 0,
+ ((cp->climit - csbase(cp) + 255) >> 8) *
+ sizeof(*cp->sfree1));
+ cp->sfree = 0;
+}
+
+/* Close up the current chunk. */
+/* This is exported for save/restore and the GC. */
+void
+alloc_close_chunk(gs_ref_memory_t *mem)
+{ if ( mem->pcc != 0 )
+ { *mem->pcc = mem->cc;
+#ifdef DEBUG
+ if ( gs_debug_c('a') )
+ { dprintf1("[a%d]", mem->space);
+ dprintf_chunk("closing chunk", mem->pcc);
+ }
+#endif
+ }
+}
+
+/* Reopen the current chunk after a GC or restore. */
+void
+alloc_open_chunk(gs_ref_memory_t *mem)
+{ if ( mem->pcc != 0 )
+ { mem->cc = *mem->pcc;
+#ifdef DEBUG
+ if ( gs_debug_c('a') )
+ { dprintf1("[a%d]", mem->space);
+ dprintf_chunk("opening chunk", mem->pcc);
+ }
+#endif
+ }
+}
+
+/* Remove a chunk from the chain. This is exported for the GC. */
+void
+alloc_unlink_chunk(chunk_t *cp, gs_ref_memory_t *mem)
+{
+#ifdef DEBUG
+ if ( gs_alloc_debug )
+ { /* Check to make sure this chunk belongs to this allocator. */
+ const chunk_t *ap = mem->cfirst;
+ while ( ap != 0 && ap != cp )
+ ap = ap->cnext;
+ if ( ap != cp )
+ { lprintf2("unlink_chunk 0x%lx not owned by memory 0x%lx!\n",
+ (ulong)cp, (ulong)mem);
+ return;/*gs_abort();*/
+ }
+ }
+#endif
+ if ( cp->cprev == 0 )
+ mem->cfirst = cp->cnext;
+ else
+ cp->cprev->cnext = cp->cnext;
+ if ( cp->cnext == 0 )
+ mem->clast = cp->cprev;
+ else
+ cp->cnext->cprev = cp->cprev;
+ if ( mem->pcc != 0 )
+ { mem->cc.cnext = mem->pcc->cnext;
+ mem->cc.cprev = mem->pcc->cprev;
+ if ( mem->pcc == cp )
+ { mem->pcc = 0;
+ mem->cc.cbot = mem->cc.ctop = 0;
+ }
+ }
+}
+
+/* Free a chunk. This is exported for save/restore and for the GC. */
+void
+alloc_free_chunk(chunk_t *cp, gs_ref_memory_t *mem)
+{ gs_memory_t *parent = mem->parent;
+ alloc_unlink_chunk(cp, mem);
+ if ( mem->cfreed.cp == cp )
+ mem->cfreed.cp = 0;
+ if ( cp->outer == 0 )
+ { byte *cdata = (byte *)cp->chead;
+ mem->allocated -= gs_object_size(parent, cdata);
+ gs_free_object(parent, cdata, "alloc_free_chunk(data)");
+ }
+ else
+ cp->outer->inner_count--;
+ mem->allocated -= gs_object_size(parent, cp);
+ gs_free_object(parent, cp, "alloc_free_chunk(chunk struct)");
+}
+
+/* Find the chunk for a pointer. */
+/* Note that this only searches the current save level. */
+/* Since a given save level can't contain both a chunk and an inner chunk */
+/* of that chunk, we can stop when is_within_chunk succeeds, and just test */
+/* is_in_inner_chunk then. */
+bool
+chunk_locate_ptr(const void *vptr, chunk_locator_t *clp)
+{ register chunk_t *cp = clp->cp;
+ if ( cp == 0 )
+ { cp = clp->memory->cfirst;
+ if ( cp == 0 )
+ return false;
+ }
+#define ptr (const byte *)vptr
+ if ( ptr_lt(ptr, cp->cbase) )
+ { do
+ { cp = cp->cprev;
+ if ( cp == 0 )
+ return false;
+ }
+ while ( ptr_lt(ptr, cp->cbase) );
+ if ( ptr_ge(ptr, cp->cend) )
+ return false;
+ }
+ else
+ { while ( ptr_ge(ptr, cp->cend) )
+ { cp = cp->cnext;
+ if ( cp == 0 )
+ return false;
+ }
+ if ( ptr_lt(ptr, cp->cbase) )
+ return false;
+ }
+ clp->cp = cp;
+ return !ptr_is_in_inner_chunk(ptr, cp);
+#undef ptr
+}
+
+/* ------ Debugging printout ------ */
+
+/*
+ * All of this code should be in a separate file, but we added it just
+ * before a release, and it would have been too disruptive to add a new
+ * file at this point.
+ */
+
+#ifdef DEBUG
+
+#include "string_.h"
+
+/*
+ * Define the options for a memory dump. These may be or'ed together.
+ */
+typedef enum {
+ dump_do_default = 0, /* pro forma */
+ dump_do_strings = 1,
+ dump_do_type_addresses = 2,
+ dump_do_no_types = 4,
+ dump_do_pointers = 8,
+ dump_do_pointed_strings = 16, /* only if do_pointers also set */
+ dump_do_contents = 32,
+ dump_do_marks = 64
+} dump_options_t;
+
+/*
+ * Define all the parameters controlling what gets dumped.
+ */
+typedef struct dump_control_s {
+ dump_options_t options;
+ const byte *bottom;
+ const byte *top;
+} dump_control_t;
+#define obj_in_control_region(obot, otop, pdc)\
+ ( ((pdc)->bottom == NULL || (const byte *)(otop) > (pdc)->bottom) &&\
+ ((pdc)->top == NULL || (const byte *)(obot) < (pdc)->top) )
+const dump_control_t dump_control_default = {
+ dump_do_default, NULL, NULL
+};
+const dump_control_t dump_control_all = {
+ dump_do_strings | dump_do_type_addresses | dump_do_pointers |
+ dump_do_pointed_strings | dump_do_contents, NULL, NULL
+};
+
+/*
+ * Internal procedure to dump a block of memory, in hex and optionally
+ * also as characters.
+ */
+private void
+debug_indent(int indent)
+{ int i;
+ for ( i = indent; i > 0; --i )
+ dputc(' ');
+}
+private void
+debug_dump_contents(const byte *bot, const byte *top, int indent,
+ bool as_chars)
+{ const byte *block;
+#define block_size 16
+
+ if ( bot >= top )
+ return;
+ for ( block = bot - ((bot - (byte *)0) & (block_size - 1));
+ block < top; block += block_size
+ ) {
+ int i;
+ char label[12];
+
+ /* Check for repeated blocks. */
+ if ( block >= bot + block_size &&
+ block <= top - (block_size * 2) &&
+ !memcmp(block, block - block_size, block_size) &&
+ !memcmp(block, block + block_size, block_size)
+ ) {
+ if ( block < bot + block_size * 2 ||
+ memcmp(block, block - block_size * 2, block_size)
+ ) {
+ debug_indent(indent);
+ dputs(" ...\n");
+ }
+ continue;
+ }
+ sprintf(label, "0x%lx:", (ulong)block);
+ debug_indent(indent);
+ dputs(label);
+ for ( i = 0; i < block_size; ++i ) {
+ const char *sepr = ((i & 3) == 0 && i != 0 ? " " : " ");
+
+ dputs(sepr);
+ if ( block + i >= bot && block + i < top )
+ dprintf1("%02x", block[i]);
+ else
+ dputs(" ");
+ }
+ dputc('\n');
+ if ( as_chars ) {
+ debug_indent(indent + strlen(label));
+ for ( i = 0; i < block_size; ++i ) {
+ byte ch;
+ if ( (i & 3) == 0 && i != 0 )
+ dputc(' ');
+ if ( block + i >= bot && block + i < top &&
+ (ch = block[i]) >= 32 && ch <= 126
+ )
+ dprintf1(" %c", ch);
+ else
+ dputs(" ");
+ }
+ dputc('\n');
+ }
+ }
+#undef block_size
+}
+
+/* Print one object with the given options. */
+/* Relevant options: type_addresses, no_types, pointers, pointed_strings, */
+/* contents. */
+void
+debug_print_object(const void *obj, const dump_control_t *control)
+{ const obj_header_t *pre = ((const obj_header_t *)obj) - 1;
+ ulong size = pre_obj_contents_size(pre);
+ const gs_memory_struct_type_t *type = pre->o_type;
+ dump_options_t options = control->options;
+
+ dprintf3(" pre=0x%lx(obj=0x%lx) size=%lu", (ulong)pre, (ulong)obj,
+ size);
+ switch ( options & (dump_do_type_addresses | dump_do_no_types) )
+ {
+ case dump_do_type_addresses + dump_do_no_types: /* addresses only */
+ dprintf1(" type=0x%lx", (ulong)type);
+ break;
+ case dump_do_type_addresses: /* addresses & names */
+ dprintf2(" type=%s(0x%lx)", struct_type_name_string(type),
+ (ulong)type);
+ break;
+ case 0: /* names only */
+ dprintf1(" type=%s", struct_type_name_string(type));
+ case dump_do_no_types: /* nothing */
+ ;
+ }
+ if ( options & dump_do_marks ) {
+ if ( pre->o_large )
+ dprintf1(" lmark=%d", pre->o_lmark);
+ else
+ dprintf2(" smark/back=%u (0x%x)", pre->o_smark, pre->o_smark);
+ }
+ dputc('\n');
+ if ( type == &st_free )
+ return;
+ if ( options & dump_do_pointers ) {
+ struct_proc_enum_ptrs((*proc)) = type->enum_ptrs;
+ uint index = 0;
+ const void *ptr;
+ gs_ptr_type_t ptype;
+
+ /*
+ * NOTE: the following cast should be unnecessary, but that
+ * will require adding 'const' to the first prototype argument
+ * of struct_proc_enum_ptrs.
+ */
+ if ( proc != 0 )
+ for ( ; (ptype = (*proc)((obj_header_t *)pre + 1, size, index, &ptr)) != 0;
+ ++index
+ ) {
+ dprintf1(" ptr %u: ", index);
+ if ( ptype == ptr_string_type || ptype == ptr_const_string_type ) {
+ const gs_const_string *str = (const gs_const_string *)ptr;
+
+ dprintf2("0x%lx(%u)", (ulong)str->data, str->size);
+ if ( options & dump_do_pointed_strings ) {
+ dputs(" =>\n");
+ debug_dump_contents(str->data, str->data + str->size, 6,
+ true);
+ } else {
+ dputc('\n');
+ }
+ } else {
+ dprintf1((ptr_between(ptr, obj, (const byte *)obj + size) ?
+ "(0x%lx)\n" : "0x%lx\n"), (ulong)ptr);
+ }
+ }
+ }
+ if ( options & dump_do_contents ) {
+ debug_dump_contents((const byte *)obj, (const byte *)obj + size,
+ 0, false);
+ }
+}
+
+/* Print the contents of a chunk with the given options. */
+/* Relevant options: all. */
+void
+debug_dump_chunk(const chunk_t *cp, const dump_control_t *control)
+{ dprintf1("chunk at 0x%lx:\n", (ulong)cp);
+ dprintf3(" chead=0x%lx cbase=0x%lx sbase=0x%lx\n",
+ (ulong)cp->chead, (ulong)cp->cbase, (ulong)cp->sbase);
+ dprintf3(" rcur=0x%lx rtop=0x%lx cbot=0x%lx\n",
+ (ulong)cp->rcur, (ulong)cp->rtop, (ulong)cp->cbot);
+ dprintf4(" ctop=0x%lx climit=0x%lx smark=0x%lx, size=%u\n",
+ (ulong)cp->ctop, (ulong)cp->climit, (ulong)cp->smark,
+ cp->smark_size);
+ dprintf2(" sreloc=0x%lx cend=0x%lx\n",
+ (ulong)cp->sreloc, (ulong)cp->cend);
+ dprintf5("cprev=0x%lx cnext=0x%lx outer=0x%lx inner_count=%u has_refs=%s\n",
+ (ulong)cp->cprev, (ulong)cp->cnext, (ulong)cp->outer,
+ cp->inner_count, (cp->has_refs? "true" : "false"));
+
+ dprintf2(" sfree1=0x%lx sfree=0x%x\n",
+ (ulong)cp->sfree1, cp->sfree);
+ if ( control->options & dump_do_strings ) {
+ debug_dump_contents((control->bottom == 0 ? cp->ctop :
+ max(control->bottom, cp->ctop)),
+ (control->top == 0 ? cp->climit :
+ min(control->top, cp->climit)),
+ 0, true);
+ }
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if ( obj_in_control_region(pre + 1,
+ (const byte *)(pre + 1) + size,
+ control)
+ )
+ debug_print_object(pre + 1, control);
+/* Temporarily redefine gs_exit so a chunk parsing error */
+/* won't actually exit. */
+#define gs_exit(n) DO_NOTHING
+ END_OBJECTS_SCAN
+#undef gs_exit
+}
+void debug_print_chunk(const chunk_t *cp)
+{ dump_control_t control;
+
+ control = dump_control_default;
+ debug_dump_chunk(cp, &control);
+}
+
+/* Print the contents of all chunks managed by an allocator. */
+/* Relevant options: all. */
+void
+debug_dump_memory(const gs_ref_memory_t *mem, const dump_control_t *control)
+{ const chunk_t *mcp;
+
+ for ( mcp = mem->cfirst; mcp != 0; mcp = mcp->cnext ) {
+ const chunk_t *cp = (mcp == mem->pcc ? &mem->cc : mcp);
+
+ if ( obj_in_control_region(cp->cbase, cp->cend, control) )
+ debug_dump_chunk(cp, control);
+ }
+}
+
+#endif /* DEBUG */
diff --git a/gs/src/gsalloc.h b/gs/src/gsalloc.h
new file mode 100644
index 000000000..e9a8314fd
--- /dev/null
+++ b/gs/src/gsalloc.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsalloc.h */
+/* Memory allocator extensions for standard allocator */
+
+#ifndef gsalloc_INCLUDED
+# define gsalloc_INCLUDED
+
+/*
+ * Define a structure and interface for GC-related allocator state.
+ */
+typedef struct gs_memory_gc_status_s {
+ /* Set by client */
+ long vm_threshold; /* GC interval */
+ long max_vm; /* maximum allowed allocation */
+ int *psignal; /* if not NULL, store signal_value */
+ /* here if we go over the vm_threshold */
+ int signal_value; /* value to store in *psignal */
+ bool enabled; /* auto GC enabled if true */
+ /* Set by allocator */
+ long requested; /* amount of last failing request */
+} gs_memory_gc_status_t;
+void gs_memory_gc_status(P2(const gs_ref_memory_t *, gs_memory_gc_status_t *));
+void gs_memory_set_gc_status(P2(gs_ref_memory_t *, const gs_memory_gc_status_t *));
+
+/* ------ Internal routines ------ */
+
+/* Initialize after a save. */
+void ialloc_reset(P1(gs_ref_memory_t *));
+
+/* Initialize after a save or GC. */
+void ialloc_reset_free(P1(gs_ref_memory_t *));
+
+/* Set the cached allocation limit of an alloctor from its GC parameters. */
+void ialloc_set_limit(P1(gs_ref_memory_t *));
+
+#endif /* gsalloc_INCLUDED */
diff --git a/gs/src/gsargs.c b/gs/src/gsargs.c
new file mode 100644
index 000000000..e1aab2de9
--- /dev/null
+++ b/gs/src/gsargs.c
@@ -0,0 +1,159 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsargs.c */
+/* Command line argument list management */
+#include "ctype_.h"
+#include "stdio_.h"
+#include "string_.h"
+#include "gsexit.h"
+#include "gsmemory.h"
+#include "gsargs.h"
+
+/* Initialize an arg list. */
+void
+arg_init(arg_list *pal, const char **argv, int argc,
+ FILE *(*arg_fopen)(P2(const char *fname, void *fopen_data)),
+ void *fopen_data)
+{ pal->expand_ats = true;
+ pal->arg_fopen = arg_fopen;
+ pal->fopen_data = fopen_data;
+ pal->argp = argv + 1;
+ pal->argn = argc - 1;
+ pal->depth = 0;
+}
+
+/* Push a string onto an arg list. */
+void
+arg_push_string(arg_list *pal, const char *str)
+{ arg_source *pas;
+
+ if ( pal->depth == arg_depth_max )
+ { lprintf("Too much nesting of @-files.\n");
+ gs_exit(1);
+ }
+ pas = &pal->sources[pal->depth];
+ pas->is_file = false;
+ pas->u.str = str;
+ pal->depth++;
+}
+
+/* Clean up an arg list. */
+void
+arg_finit(arg_list *pal)
+{ while ( pal->depth )
+ if ( pal->sources[--(pal->depth)].is_file )
+ fclose(pal->sources[pal->depth].u.file);
+}
+
+/* Get the next arg from a list. */
+/* Note that these are not copied to the heap. */
+const char *
+arg_next(arg_list *pal)
+{ arg_source *pas;
+ FILE *f;
+ const char *astr = 0; /* initialized only to pacify gcc */
+ char *cstr;
+ const char *result;
+ int endc;
+ register int c;
+ register int i;
+ bool in_quote;
+
+top: pas = &pal->sources[pal->depth - 1];
+ if ( pal->depth == 0 )
+ { if ( pal->argn <= 0 ) /* all done */
+ return 0;
+ pal->argn--;
+ result = *(pal->argp++);
+ goto at;
+ }
+ if ( pas->is_file )
+ f = pas->u.file, endc = EOF;
+ else
+ astr = pas->u.str, f = NULL, endc = 0;
+ result = cstr = pal->cstr;
+#define cfsgetc() (f == NULL ? (*astr ? *astr++ : 0) : fgetc(f))
+ while ( isspace(c = cfsgetc()) ) ;
+ if ( c == endc )
+ { if ( f != NULL )
+ fclose(f);
+ pal->depth--;
+ goto top;
+ }
+ in_quote = false;
+ for ( i = 0; ; )
+ { if ( i == arg_str_max - 1 )
+ { cstr[i] = 0;
+ fprintf(stdout, "Command too long: %s\n", cstr);
+ gs_exit(1);
+ }
+ /* If input is coming from an @-file, allow quotes */
+ /* to protect whitespace. */
+ if ( c == '"' && f != NULL )
+ in_quote = !in_quote;
+ else
+ cstr[i++] = c;
+ c = cfsgetc();
+ if ( c == endc )
+ { if ( in_quote )
+ { cstr[i] = 0;
+ fprintf(stdout,
+ "Unterminated quote in @-file: %s\n",
+ cstr);
+ gs_exit(1);
+ }
+ break;
+ }
+ if ( isspace(c) && !in_quote )
+ break;
+ }
+ cstr[i] = 0;
+ if ( f == NULL )
+ pas->u.str = astr;
+at: if ( pal->expand_ats && result[0] == '@' )
+ { if ( pal->depth == arg_depth_max )
+ { lprintf("Too much nesting of @-files.\n");
+ gs_exit(1);
+ }
+ result++; /* skip @ */
+ f = (*pal->arg_fopen)(result, pal->fopen_data);
+ if ( f == NULL )
+ { fprintf(stdout, "Unable to open command line file %s\n", result);
+ gs_exit(1);
+ }
+ pal->depth++;
+ pas++;
+ pas->is_file = true;
+ pas->u.file = f;
+ goto top;
+ }
+ return result;
+}
+
+/* Copy an argument string to the heap. */
+char *
+arg_copy(const char *str, gs_memory_t *mem)
+{ char *sstr = (char *)gs_alloc_bytes(mem, strlen(str) + 1, "arg_copy");
+ if ( sstr == 0 )
+ { lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ strcpy(sstr, str);
+ return sstr;
+}
diff --git a/gs/src/gsargs.h b/gs/src/gsargs.h
new file mode 100644
index 000000000..f07aa614d
--- /dev/null
+++ b/gs/src/gsargs.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsargs.h */
+/* Command line argument list management */
+
+#ifndef gsargs_INCLUDED
+# define gsargs_INCLUDED
+
+/*
+ * We need to handle recursion into @-files.
+ * The following structures keep track of the state.
+ * Defining a maximum argument length and a maximum nesting depth
+ * decreases generality, but eliminates the need for dynamic allocation.
+ */
+#define arg_str_max 512
+#define arg_depth_max 10
+typedef struct arg_source_s {
+ bool is_file;
+ union _u {
+ const char *str;
+ FILE *file;
+ } u;
+} arg_source;
+typedef struct arg_list_s {
+ bool expand_ats; /* if true, expand @-files */
+ FILE *(*arg_fopen)(P2(const char *fname, void *fopen_data));
+ void *fopen_data;
+ const char **argp;
+ int argn;
+ int depth; /* depth of @-files */
+ char cstr[arg_str_max + 1];
+ arg_source sources[arg_depth_max];
+} arg_list;
+
+/* Initialize an arg list. */
+void arg_init(P5(arg_list *pal, const char **argv, int argc,
+ FILE *(*arg_fopen)(P2(const char *fname, void *fopen_data)),
+ void *fopen_data));
+
+/* Push a string onto an arg list. */
+/* This may also be used (once) to "unread" the last argument. */
+void arg_push_string(P2(arg_list *pal, const char *str));
+
+/* Clean up an arg list before exiting. */
+void arg_finit(P1(arg_list *pal));
+
+/* Get the next arg from a list. */
+/* Note that these are not copied to the heap. */
+const char *arg_next(P1(arg_list *pal));
+
+/* Copy an argument string to the heap. */
+char *arg_copy(P2(const char *str, gs_memory_t *mem));
+
+#endif /* gsargs_INCLUDED */
diff --git a/gs/src/gsbitmap.h b/gs/src/gsbitmap.h
new file mode 100644
index 000000000..a24cf693b
--- /dev/null
+++ b/gs/src/gsbitmap.h
@@ -0,0 +1,187 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsbitmap.h */
+/* Library "client" bitmap structures */
+
+#ifndef gsbitmap_INCLUDED
+#define gsbitmap_INCLUDED
+
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * The Ghostscript library stores all bitmaps bit-big-endian (i.e., the 0x80
+ * bit of the first byte corresponds to x=0), as a sequence of bytes (i.e.,
+ * you can't do word-oriented operations on them if you're on a
+ * little-endian platform like the Intel 80x86 or VAX). The first scan line
+ * corresponds to y=0 in whatever coordinate system is relevant.
+ *
+ * The structures defined here are for APIs that don't impose any alignment
+ * restrictions on either the starting address or the raster (distance
+ * between scan lines) of bitmap data. The structures defined in gxbitmap.h
+ * do impose alignment restrictions, so that the library can use more
+ * efficient algorithms; they are declared with identical contents to the
+ * ones defined here, so that one can cast between them under appropriate
+ * circumstances (aligned to unaligned is always safe; unaligned to
+ * aligned is safe if one knows somehow that the data are actually aligned.)
+ *
+ * In this file we also provide structures that include depth information.
+ * It probably was a design mistake not to include this information in the
+ * gx structures as well.
+ */
+
+/*
+ * Drivers such as the X driver and the command list (band list) driver
+ * benefit greatly by being able to cache bitmaps (tiles and characters)
+ * and refer to them later. To help them recognize when a bitmap is the
+ * same as one that they have seen before, the core code passes an optional
+ * ID with the property that if two bitmaps have the same ID, they are
+ * guaranteed to have the same contents. (The converse is *not* true,
+ * however: two bitmaps may have different IDs and still be the same.)
+ */
+typedef gs_id gs_bitmap_id;
+
+/* Define a special value to indicate "no identifier". */
+#define gs_no_bitmap_id gs_no_id
+
+/*
+ * In its simplest form, the client bitmap structure does not specify a
+ * depth, expecting it to be implicit in the context of use. In many cases
+ * it is possible to guess this by comparing size.x and raster, but of
+ * course code should not rely on this. See also gs_depth_bitmap below.
+ * Requirements:
+ * size.x > 0, size.y > 0
+ * If size.y > 1,
+ * raster >= (size.x * depth + 7) / 8
+ */
+#define gs_bitmap_common \
+ byte * data; /* pointer to the data */ \
+ int raster; /* increment between scanlines, bytes */ \
+ gs_int_point size; /* width and height */ \
+ gs_bitmap_id id /* usually unused */
+
+typedef struct gs_bitmap_s {
+ gs_bitmap_common;
+} gs_bitmap;
+
+/*
+ * For bitmaps used as halftone tiles, we may replicate the tile in
+ * X and/or Y, but it is still valuable to know the true tile dimensions
+ * (i.e., the dimensions prior to replication). Requirements:
+ * size.x % rep_width = 0
+ * size.y % rep_height = 0
+ * Unaligned bitmaps are not very likely to be used as tiles (replicated),
+ * since most of the library procedures that replicate tiles expect them
+ * to be aligned.
+ */
+#define gs_tile_bitmap_common \
+ gs_bitmap_common; \
+ ushort rep_width, rep_height /* true size of tile */
+
+typedef struct gs_tile_bitmap_s {
+ gs_tile_bitmap_common;
+} gs_tile_bitmap;
+
+/*
+ * There is no "strip" version for client bitmaps, as the strip structure is
+ * primarily used to efficiently store bitmaps rendered at an angle, and
+ * there is little reason to do so with client bitmaps.
+ *
+ * For client bitmaps it is not always apparent from context what the intended
+ * depth per sample value is. To provide for this, an extended version of the
+ * bitmap structure is provided, that handles both variable depth and
+ * interleaved color components. This structure is provided in both the
+ * normal and tiled version.
+ *
+ * Extending this line of thinking, one could also add color space information
+ * to a client bitmap structure. We have chosen not to do so, because color
+ * space is almost always derived from context, and to provide such a feature
+ * would involve additional memory-management complexity.
+ */
+#define gs_depth_bitmap_common \
+ gs_bitmap_common; \
+ byte pix_depth; /* bits per sample */ \
+ byte num_comps /* number of interleaved components */ \
+
+typedef struct gs_depth_bitmap_s {
+ gs_depth_bitmap_common;
+} gs_depth_bitmap;
+
+#define gs_tile_depth_bitmap_common \
+ gs_tile_bitmap_common; \
+ byte pix_depth; /* bits per sample */ \
+ byte num_comps /* number of interleaved components */ \
+
+typedef struct gs_tile_depth_bitmap_s {
+ gs_tile_depth_bitmap_common;
+} gs_tile_depth_bitmap;
+
+/*
+ * For reasons that are no entirely clear, no memory management routines were
+ * provided for the aligned bitmap structures provided in gxbitmap.h. Since
+ * client bitmaps will, by nature, be created by different clients, so public
+ * memory management procedures are provided. Note that the memory management
+ * structure names retain the "gs_" prefix, to distinguish these structures
+ * from those that may be provided for the gx_*_bitmap structures.
+ *
+ * For historical reasons of no particular validity (this was where the client
+ * bitmap structure was first provided), the memory managment procedures for
+ * client bitmap structures are included in gspcolor.c.
+ */
+extern_st(st_gs_bitmap);
+extern_st(st_gs_tile_bitmap);
+extern_st(st_gs_depth_bitmap);
+extern_st(st_gs_tile_depth_bitmap);
+
+#define public_st_gs_bitmap() /* in gspcolor.c */ \
+ gs_public_st_ptrs1( st_gs_bitmap, \
+ gs_bitmap, \
+ "client bitmap", \
+ bitmap_enum_ptrs, \
+ bitmap_reloc_ptrs, \
+ data \
+ )
+
+#define public_st_gs_tile_bitmap() /* in gspcolor.c */ \
+ gs_public_st_suffix_add0( st_gs_tile_bitmap, \
+ gs_tile_bitmap, \
+ "client tile bitmap", \
+ tile_bitmap_enum_ptrs, \
+ tile_bitmap_reloc_ptrs, \
+ st_gs_bitmap \
+ )
+
+#define public_st_gs_depth_bitmap() /* in gspcolor.c */ \
+ gs_public_st_suffix_add0( st_gs_depth_bitmap, \
+ gs_depth_bitmap, \
+ "client depth bitmap", \
+ depth_bitmap_enum_ptrs, \
+ depth_bitmap_reloc_ptrs, \
+ st_gs_bitmap \
+ )
+
+#define public_st_gs_tile_depth_bitmap()/* in gspcolor.c */ \
+ gs_public_st_suffix_add0( st_gs_tile_depth_bitmap, \
+ gs_tile_depth_bitmap, \
+ "client tile_depth bitmap", \
+ tile_depth_bitmap_enum_ptrs, \
+ tile_depth_bitmap_reloc_ptrs, \
+ st_gs_tile_bitmap \
+ )
+
+#endif /* gsbitmap_INCLUDED */
diff --git a/gs/src/gsbitops.c b/gs/src/gsbitops.c
new file mode 100644
index 000000000..4c604d9b2
--- /dev/null
+++ b/gs/src/gsbitops.c
@@ -0,0 +1,601 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsbitops.c */
+/* Bitmap filling, copying, and transforming operations */
+#include "stdio_.h"
+#include "memory_.h"
+#include "gdebug.h"
+#include "gstypes.h"
+#include "gsbitops.h"
+
+/*
+ * Define a compile-time option to reverse nibble order in alpha maps.
+ * Note that this does not reverse bit order within nibbles.
+ * This option is here for a very specialized purpose and does not
+ * interact well with the rest of the code.
+ */
+#ifndef ALPHA_LSB_FIRST
+# define ALPHA_LSB_FIRST 0
+#endif
+
+/* ---------------- Bit-oriented operations ---------------- */
+
+/* Define masks for little-endian operation. */
+/* masks[i] has the first i bits off and the rest on. */
+#if !arch_is_big_endian
+const bits16 mono_copy_masks[17] = {
+ 0xffff, 0xff7f, 0xff3f, 0xff1f,
+ 0xff0f, 0xff07, 0xff03, 0xff01,
+ 0xff00, 0x7f00, 0x3f00, 0x1f00,
+ 0x0f00, 0x0700, 0x0300, 0x0100,
+ 0x0000
+};
+# if arch_sizeof_int > 2
+const bits32 mono_fill_masks[33] = {
+ 0xffffffff, 0xffffff7f, 0xffffff3f, 0xffffff1f,
+ 0xffffff0f, 0xffffff07, 0xffffff03, 0xffffff01,
+ 0xffffff00, 0xffff7f00, 0xffff3f00, 0xffff1f00,
+ 0xffff0f00, 0xffff0700, 0xffff0300, 0xffff0100,
+ 0xffff0000, 0xff7f0000, 0xff3f0000, 0xff1f0000,
+ 0xff0f0000, 0xff070000, 0xff030000, 0xff010000,
+ 0xff000000, 0x7f000000, 0x3f000000, 0x1f000000,
+ 0x0f000000, 0x07000000, 0x03000000, 0x01000000,
+ 0x00000000
+};
+# endif
+#endif
+
+/* Fill a rectangle of bits with an 8x1 pattern. */
+/* The pattern argument must consist of the pattern in every byte, */
+/* e.g., if the desired pattern is 0xaa, the pattern argument must */
+/* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
+#undef chunk
+#define chunk mono_fill_chunk
+#undef mono_masks
+#define mono_masks mono_fill_masks
+void
+bits_fill_rectangle(byte *dest, int dest_bit, uint draster,
+ mono_fill_chunk pattern, int width_bits, int height)
+{ uint bit;
+ chunk right_mask;
+
+#define write_loop(stat)\
+ { int line_count = height;\
+ chunk *ptr = (chunk *)dest;\
+ do { stat; inc_ptr(ptr, draster); }\
+ while ( --line_count );\
+ }
+
+#define write_partial(msk)\
+ switch ( (byte)pattern )\
+ { case 0: write_loop(*ptr &= ~msk); break;\
+ case 0xff: write_loop(*ptr |= msk); break;\
+ default: write_loop(*ptr = (*ptr & ~msk) | (pattern & msk));\
+ }
+
+ dest += (dest_bit >> 3) & -chunk_align_bytes;
+ bit = dest_bit & chunk_align_bit_mask;
+
+#if 1 /* new code */
+
+#define write_span(lmsk, stat0, statx, stat1, n, rmsk)\
+ switch ( (byte)pattern )\
+ { case 0: write_loop((*ptr &= ~lmsk, stat0, ptr[n] &= ~rmsk)); break;\
+ case 0xff: write_loop((*ptr |= lmsk, stat1, ptr[n] |= rmsk)); break;\
+ default: write_loop((*ptr = (*ptr & ~lmsk) | (pattern & lmsk), statx,\
+ ptr[n] = (ptr[n] & ~rmsk) | (pattern & rmsk)));\
+ }
+
+ { int last_bit = width_bits + bit - (chunk_bits + 1);
+ if ( last_bit < 0 ) /* <=1 chunk */
+ { set_mono_thin_mask(right_mask, width_bits, bit);
+ write_partial(right_mask);
+ }
+ else
+ { chunk mask;
+ int last = last_bit >> chunk_log2_bits;
+ set_mono_left_mask(mask, bit);
+ set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
+ switch ( last )
+ {
+ case 0: /* 2 chunks */
+ { write_span(mask, 0, 0, 0, 1, right_mask);
+ } break;
+ case 1: /* 3 chunks */
+ { write_span(mask, ptr[1] = 0, ptr[1] = pattern,
+ ptr[1] = ~(chunk)0, 2, right_mask);
+ } break;
+ default: /* >3 chunks */
+ { uint byte_count = (last_bit >> 3) & -chunk_bytes;
+ write_span(mask, memset(ptr + 1, 0, byte_count),
+ memset(ptr + 1, (byte)pattern, byte_count),
+ memset(ptr + 1, 0xff, byte_count),
+ last + 1, right_mask);
+ } break;
+ }
+ }
+ }
+
+#else /* old code */
+
+ if ( bit + width_bits <= chunk_bits )
+ { /* Only one word. */
+ set_mono_thin_mask(right_mask, width_bits, bit);
+ }
+ else
+ { int byte_count;
+ if ( bit )
+ { chunk mask;
+ set_mono_left_mask(mask, bit);
+ write_partial(mask);
+ inc_ptr(dest, chunk_bytes);
+ width_bits += bit - chunk_bits;
+ }
+ set_mono_right_mask(right_mask, width_bits & chunk_bit_mask);
+ if ( width_bits >= chunk_bits )
+ switch ( (byte_count = (width_bits >> 3) & -chunk_bytes) )
+ {
+ case chunk_bytes:
+ write_loop(*ptr = pattern);
+ inc_ptr(dest, chunk_bytes);
+ break;
+ case chunk_bytes * 2:
+ write_loop(ptr[1] = *ptr = pattern);
+ inc_ptr(dest, chunk_bytes * 2);
+ break;
+ default:
+ write_loop(memset(ptr, (byte)pattern, byte_count));
+ inc_ptr(dest, byte_count);
+ break;
+ }
+ }
+ if ( right_mask )
+ write_partial(right_mask);
+
+#endif
+
+}
+
+/* Replicate a bitmap horizontally in place. */
+void
+bits_replicate_horizontally(byte *data, uint width, uint height,
+ uint raster, uint replicated_width, uint replicated_raster)
+{ /* The current algorithm is extremely inefficient. */
+ uint y;
+ for ( y = height; y-- > 0; )
+ { const byte *orig_row = data + y * raster;
+ byte *tile_row = data + y * replicated_raster;
+ uint sx;
+ if ( !(width & 7) )
+ { uint wbytes = width >> 3;
+ for ( sx = wbytes; sx-- > 0; )
+ { byte sb = orig_row[sx];
+ uint dx;
+ for ( dx = sx + (replicated_width >> 3); dx >= wbytes; )
+ tile_row[dx -= wbytes] = sb;
+ }
+ }
+ else
+ for ( sx = width; sx-- > 0; )
+ { byte sm = orig_row[sx >> 3] & (0x80 >> (sx & 7));
+ uint dx;
+ for ( dx = sx + replicated_width; dx >= width;
+ )
+ { byte *dp =
+ (dx -= width, tile_row + (dx >> 3));
+ byte dm = 0x80 >> (dx & 7);
+ if ( sm ) *dp |= dm;
+ else *dp &= ~dm;
+ }
+ }
+ }
+}
+
+/* Replicate a bitmap vertically in place. */
+void
+bits_replicate_vertically(byte *data, uint height, uint raster,
+ uint replicated_height)
+{ byte *dest = data;
+ uint h = replicated_height;
+ uint size = raster * height;
+
+ while ( h > height )
+ { memcpy(dest + size, dest, size);
+ dest += size;
+ h -= height;
+ }
+}
+
+/* Find the bounding box of a bitmap. */
+/* Assume bits beyond the width are zero. */
+void
+bits_bounding_box(const byte *data, uint height, uint raster,
+ gs_int_rect *pbox)
+{ register const ulong *lp;
+ static const byte first_1[16] =
+ { 4, 3, 2,2, 1,1,1,1, 0,0,0,0,0,0,0,0 };
+ static const byte last_1[16] =
+ { 0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4 };
+
+ /* Count trailing blank rows. */
+ /* Since the raster is a multiple of sizeof(long), */
+ /* we don't need to scan by bytes, only by longs. */
+
+ lp = (const ulong *)(data + raster * height);
+ while ( (const byte *)lp > data && !lp[-1] )
+ --lp;
+ if ( (const byte *)lp == data )
+ { pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0;
+ return;
+ }
+ pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster;
+
+ /* Count leading blank rows. */
+
+ lp = (const ulong *)data;
+ while ( !*lp )
+ ++lp;
+ { uint n = ((const byte *)lp - data) / raster;
+ pbox->p.y = n;
+ if ( n )
+ height -= n, data += n * raster;
+ }
+
+ /* Find the left and right edges. */
+ /* We know that the first and last rows are non-blank. */
+
+ { uint raster_longs = raster >> arch_log2_sizeof_long;
+ uint left = raster_longs - 1, right = 0;
+ ulong llong = 0, rlong = 0;
+ const byte *q;
+ uint h, n;
+
+ for ( q = data, h = height; h-- > 0; q += raster )
+ { /* Work from the left edge by longs. */
+ for ( lp = (const ulong *)q, n = 0;
+ n < left && !*lp; lp++, n++
+ )
+ ;
+ if ( n < left )
+ left = n, llong = *lp;
+ else
+ llong |= *lp;
+ /* Work from the right edge by longs. */
+ for ( lp = (const ulong *)(q + raster - sizeof(long)),
+ n = raster_longs - 1;
+ n > right && !*lp; lp--, n--
+ )
+ ;
+ if ( n > right )
+ right = n, rlong = *lp;
+ else
+ rlong |= *lp;
+ }
+
+ /* Do binary subdivision on edge longs. We assume that */
+ /* sizeof(long) = 4 or 8. */
+#if arch_sizeof_long > 8
+ Error_longs_are_too_large();
+#endif
+
+#if arch_is_big_endian
+# define last_bits(n) ((1L << (n)) - 1)
+# define shift_out_last(x,n) ((x) >>= (n))
+# define right_justify_last(x,n) DO_NOTHING
+#else
+# define last_bits(n) (-1L << ((arch_sizeof_long * 8) - (n)))
+# define shift_out_last(x,n) ((x) <<= (n))
+# define right_justify_last(x,n) (x) >>= ((arch_sizeof_long * 8) - (n))
+#endif
+
+ left <<= arch_log2_sizeof_long + 3;
+#if arch_sizeof_long == 8
+ if ( llong & ~last_bits(32) ) shift_out_last(llong, 32);
+ else left += 32;
+#endif
+ if ( llong & ~last_bits(16) ) shift_out_last(llong, 16);
+ else left += 16;
+ if ( llong & ~last_bits(8) ) shift_out_last(llong, 8);
+ else left += 8;
+ right_justify_last(llong, 8);
+ if ( llong & 0xf0 )
+ left += first_1[(byte)llong >> 4];
+ else
+ left += first_1[(byte)llong] + 4;
+
+ right <<= arch_log2_sizeof_long + 3;
+#if arch_sizeof_long == 8
+ if ( !(rlong & last_bits(32)) ) shift_out_last(rlong, 32);
+ else right += 32;
+#endif
+ if ( !(rlong & last_bits(16)) ) shift_out_last(rlong, 16);
+ else right += 16;
+ if ( !(rlong & last_bits(8)) ) shift_out_last(rlong, 8);
+ else right += 8;
+ right_justify_last(rlong, 8);
+ if ( !(rlong & 0xf) )
+ right += last_1[(byte)rlong >> 4];
+ else
+ right += last_1[(uint)rlong & 0xf] + 4;
+
+ pbox->p.x = left;
+ pbox->q.x = right;
+ }
+}
+
+/* Count the number of 1-bits in a half-byte. */
+static const byte half_byte_1s[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
+/* Count the number of trailing 1s in an up-to-5-bit value, -1. */
+static const byte bits5_trailing_1s[32] =
+{ 0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,4 };
+/* Count the number of leading 1s in an up-to-5-bit value, -1. */
+static const byte bits5_leading_1s[32] =
+{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,4 };
+
+/*
+ * Compress a value between 0 and 2^M to a value between 0 and 2^N-1.
+ * Possible values of M are 1, 2, 3, or 4; of N are 1, 2, and 4.
+ * The name of the table is compress_count_M_N.
+ * As noted below, we require that N <= M.
+ */
+static const byte compress_1_1[3] =
+ { 0, 1, 1 };
+static const byte compress_2_1[5] =
+ { 0, 0, 1, 1, 1 };
+static const byte compress_2_2[5] =
+ { 0, 1, 2, 2, 3 };
+static const byte compress_3_1[9] =
+ { 0, 0, 0, 0, 1, 1, 1, 1, 1 };
+static const byte compress_3_2[9] =
+ { 0, 0, 1, 1, 2, 2, 2, 3, 3 };
+static const byte compress_4_1[17] =
+ { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static const byte compress_4_2[17] =
+ { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3 };
+static const byte compress_4_4[17] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9,10,11,12,13,14,15 };
+/* The table of tables is indexed by log2(N) and then by M-1. */
+static const byte _ds *compress_tables[4][4] =
+{ { compress_1_1, compress_2_1, compress_3_1, compress_4_1 },
+ { 0, compress_2_2, compress_3_2, compress_4_2 },
+ { 0, 0, 0, compress_4_4 }
+};
+
+/*
+ * Compress an XxY-oversampled bitmap to Nx1 by counting 1-bits. The X and
+ * Y oversampling factors are 1, 2, or 4, but may be different. N, the
+ * resulting number of (alpha) bits per pixel, may be 1, 2, or 4; we allow
+ * compression in place, in which case N must not exceed the X oversampling
+ * factor. Width and height are the source dimensions, and hence reflect
+ * the oversampling; both are multiples of the relevant scale factor. The
+ * same is true for srcx.
+ */
+void
+bits_compress_scaled(const byte *src, int srcx, uint width, uint height,
+ uint sraster, byte *dest, uint draster,
+ const gs_log2_scale_point *plog2_scale, int log2_out_bits)
+{ int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
+ int xscale = 1 << log2_x;
+ int yscale = 1 << log2_y;
+ int out_bits = 1 << log2_out_bits;
+ int input_byte_out_bits;
+ byte input_byte_out_mask;
+ const byte _ds *table =
+ compress_tables[log2_out_bits][log2_x + log2_y - 1];
+ uint sskip = sraster << log2_y;
+ uint dwidth = (width >> log2_x) << log2_out_bits;
+ uint dskip = draster - ((dwidth + 7) >> 3);
+ uint mask = (1 << xscale) - 1;
+ uint count_max = 1 << (log2_x + log2_y);
+ /*
+ * For right now, we don't attempt to take advantage of the fact
+ * that the input is aligned.
+ */
+ const byte *srow = src + (srcx >> 3);
+ int in_shift_initial = 8 - xscale - (srcx & 7);
+ int in_shift_check = (out_bits <= xscale ? 8 - xscale : -1);
+ byte *d = dest;
+ uint h;
+
+ if ( out_bits <= xscale )
+ input_byte_out_bits = out_bits << (3 - log2_x),
+ input_byte_out_mask = (1 << input_byte_out_bits) - 1;
+ for ( h = height; h; srow += sskip, h -= yscale )
+ { const byte *s = srow;
+#if ALPHA_LSB_FIRST
+# define out_shift_initial 0
+# define out_shift_update(out_shift, nbits) ((out_shift += (nbits)) >= 8)
+#else
+# define out_shift_initial (8 - out_bits)
+# define out_shift_update(out_shift, nbits) ((out_shift -= (nbits)) < 0)
+#endif
+ int out_shift = out_shift_initial;
+ byte out = 0;
+ int in_shift = in_shift_initial;
+ int dw = 8 - (srcx & 7);
+ int w;
+
+ /* Loop over source bytes. */
+ for ( w = width; w > 0; w -= dw, dw = 8 )
+ { int index;
+ int in_shift_final =
+ (w >= dw ? 0 : dw - w);
+ /*
+ * Check quickly for all-0s or all-1s, but only if each
+ * input byte generates no more than one output byte,
+ * we're at an input byte boundary, and we're processing
+ * an entire input byte (i.e., this isn't a final
+ * partial byte.)
+ */
+ if ( in_shift == in_shift_check && in_shift_final == 0 )
+ switch ( *s )
+ {
+ case 0:
+ for ( index = sraster; index != sskip; index += sraster )
+ if ( s[index] != 0 )
+ goto p;
+ if ( out_shift_update(out_shift, input_byte_out_bits) )
+ *d++ = out, out_shift &= 7, out = 0;
+ s++;
+ continue;
+#if !ALPHA_LSB_FIRST /* too messy to make it work */
+ case 0xff:
+ for ( index = sraster; index != sskip; index += sraster )
+ if ( s[index] != 0xff )
+ goto p;
+ { int shift =
+ (out_shift -= input_byte_out_bits) + out_bits;
+ if ( shift > 0 )
+ out |= input_byte_out_mask << shift;
+ else
+ { out |= input_byte_out_mask >> -shift;
+ *d++ = out;
+ out_shift += 8;
+ out = input_byte_out_mask << (8 + shift);
+ }
+ }
+ s++;
+ continue;
+#endif
+ default:
+ ;
+ }
+p: /* Loop over source pixels within a byte. */
+ do
+ { uint count;
+ for ( index = 0, count = 0; index != sskip;
+ index += sraster
+ )
+ count += half_byte_1s[(s[index] >> in_shift) & mask];
+ if ( count != 0 && table[count] == 0 )
+ { /* Look at adjacent cells to help prevent */
+ /* dropouts. */
+ uint orig_count = count;
+ uint shifted_mask = mask << in_shift;
+ byte in;
+ if_debug3('B', "[B]count(%d,%d)=%d\n",
+ (width - w) / xscale,
+ (height - h) / yscale, count);
+ if ( yscale > 1 )
+ { /* Look at the next "lower" cell. */
+ if ( h < height && (in = s[0] & shifted_mask) != 0 )
+ { uint lower;
+ for ( index = 0, lower = 0;
+ -(index -= sraster) <= sskip &&
+ (in &= s[index]) != 0;
+ )
+ lower += half_byte_1s[in >> in_shift];
+ if_debug1('B', "[B] lower adds %d\n",
+ lower);
+ if ( lower <= orig_count )
+ count += lower;
+ }
+ /* Look at the next "higher" cell. */
+ if ( h > yscale && (in = s[sskip - sraster] & shifted_mask) != 0 )
+ { uint upper;
+ for ( index = sskip, upper = 0;
+ index < sskip << 1 &&
+ (in &= s[index]) != 0;
+ index += sraster
+ )
+ upper += half_byte_1s[in >> in_shift];
+ if_debug1('B', "[B] upper adds %d\n",
+ upper);
+ if ( upper < orig_count )
+ count += upper;
+ }
+ }
+ if ( xscale > 1 )
+ { uint mask1 = (mask << 1) + 1;
+ /* Look at the next cell to the left. */
+ if ( w < width )
+ { int lshift = in_shift + xscale - 1;
+ uint left;
+ for ( index = 0, left = 0;
+ index < sskip; index += sraster
+ )
+ { uint bits =
+ ((s[index - 1] << 8) +
+ s[index]) >> lshift;
+ left += bits5_trailing_1s[bits & mask1];
+ }
+ if_debug1('B', "[B] left adds %d\n",
+ left);
+ if ( left < orig_count )
+ count += left;
+ }
+ /* Look at the next cell to the right. */
+ if ( w > xscale )
+ { int rshift = in_shift - xscale + 8;
+ uint right;
+ for ( index = 0, right = 0;
+ index < sskip; index += sraster
+ )
+ { uint bits =
+ ((s[index] << 8) +
+ s[index + 1]) >> rshift;
+ right += bits5_leading_1s[(bits & mask1) << (4 - xscale)];
+ }
+ if_debug1('B', "[B] right adds %d\n",
+ right);
+ if ( right <= orig_count )
+ count += right;
+ }
+ }
+ if ( count > count_max )
+ count = count_max;
+ }
+ out += table[count] << out_shift;
+ if ( out_shift_update(out_shift, out_bits) )
+ *d++ = out, out_shift &= 7, out = 0;
+ }
+ while ( (in_shift -= xscale) >= in_shift_final );
+ s++, in_shift += 8;
+ }
+ if ( out_shift != out_shift_initial )
+ *d++ = out;
+ for ( w = dskip; w != 0; w-- )
+ *d++ = 0;
+#undef out_shift_initial
+#undef out_shift_update
+ }
+}
+
+/* ---------------- Byte-oriented operations ---------------- */
+
+/* Fill a rectangle of bytes. */
+void
+bytes_fill_rectangle(byte *dest, uint raster,
+ byte value, int width_bytes, int height)
+{ while ( height-- > 0 )
+ { memset(dest, value, width_bytes);
+ dest += raster;
+ }
+}
+
+/* Copy a rectangle of bytes. */
+void
+bytes_copy_rectangle(byte *dest, uint dest_raster,
+ const byte *src, uint src_raster, int width_bytes, int height)
+{ while ( height-- > 0 )
+ { memcpy(dest, src, width_bytes);
+ src += src_raster;
+ dest += dest_raster;
+ }
+}
diff --git a/gs/src/gsbitops.h b/gs/src/gsbitops.h
new file mode 100644
index 000000000..b79426e09
--- /dev/null
+++ b/gs/src/gsbitops.h
@@ -0,0 +1,173 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsbitops.h */
+/* Definitions for bitmap operations */
+
+/* ---------------- Definitions ---------------- */
+
+/*
+ * Macros for processing bitmaps in the largest possible chunks.
+ * Bits within a byte are always stored big-endian;
+ * bytes are likewise stored in left-to-right order, i.e., big-endian.
+ * Note that this is the format used for the source of copy_mono.
+ * It used to be the case that bytes were stored in the natural
+ * platform order, and the client had force them into big-endian order
+ * by calling gdev_mem_ensure_byte_order, but this no longer necessary.
+ *
+ * Note that we use type uint for register variables holding a chunk:
+ * for this reason, the chunk size cannot be larger than uint.
+ */
+/* Generic macros for chunk accessing. */
+#define cbytes(ct) size_of(ct) /* sizeof may be unsigned */
+# define chunk_bytes cbytes(chunk)
+/* The clog2_bytes macro assumes that ints are 2, 4, or 8 bytes in size. */
+#define clog2_bytes(ct) (size_of(ct) == 8 ? 3 : size_of(ct)>>1)
+# define chunk_log2_bytes clog2_bytes(chunk)
+#define cbits(ct) (size_of(ct)*8) /* sizeof may be unsigned */
+# define chunk_bits cbits(chunk)
+#define clog2_bits(ct) (clog2_bytes(ct)+3)
+# define chunk_log2_bits clog2_bits(chunk)
+#define cbit_mask(ct) (cbits(ct)-1)
+# define chunk_bit_mask cbit_mask(chunk)
+#define calign_bytes(ct)\
+ (sizeof(ct) == 1 ? 1:\
+ sizeof(ct) == sizeof(short) ? arch_align_short_mod :\
+ sizeof(ct) == sizeof(int) ? arch_align_int_mod : arch_align_long_mod)
+# define chunk_align_bytes calign_bytes(chunk)
+#define calign_bit_mask(ct) (calign_bytes(ct)*8-1)
+# define chunk_align_bit_mask calign_bit_mask(chunk)
+/*
+ * The obvious definition for cmask is:
+ * #define cmask(ct) ((ct)~(ct)0)
+ * but this doesn't work on the VAX/VMS compiler, which fails to truncate
+ * the value to 16 bits when ct is ushort.
+ * Instead, we have to generate the mask with no extra 1-bits.
+ * We can't do this in the obvious way:
+ * #define cmask(ct) ((1 << (size_of(ct) * 8)) - 1)
+ * because some compilers won't allow a shift of the full type size.
+ * Instead, we have to do something really awkward:
+ */
+#define cmask(ct) ((ct) (((((ct)1 << (size_of(ct)*8-2)) - 1) << 2) + 3))
+# define chunk_all_bits cmask(chunk)
+/*
+ * The obvious definition for chi_bits is:
+ * #define chi_bits(ct,n) (cmask(ct)-(cmask(ct)>>(n)))
+ * but this doesn't work on the DEC/MIPS compilers.
+ * Instead, we have to restrict chi_bits to only working for values of n
+ * between 0 and cbits(ct)-1, and use
+ */
+#define chi_bits(ct,n) (ct)(~(ct)1 << (cbits(ct)-1 - (n)))
+# define chunk_hi_bits(n) chi_bits(chunk,n)
+
+/* Define whether this is a machine where chunks are long, */
+/* but the machine can't shift a long by its full width. */
+#define arch_cant_shift_full_chunk\
+ (arch_is_big_endian && !arch_ints_are_short && !arch_can_shift_full_long)
+
+/* Pointer arithmetic macros. */
+#define inc_ptr(ptr,delta)\
+ ptr = (void *)((byte *)ptr + (delta))
+
+/* Define macros for setting up left- and right-end masks. */
+/* These are used for monobit operations, and for filling */
+/* with 2- and 4-bit-per-pixel patterns. */
+
+/*
+ * Define the chunk size for monobit copying operations.
+ * (The chunk size for monobit filling is always uint.)
+ */
+#define mono_fill_chunk uint
+#define mono_fill_chunk_bytes arch_sizeof_int
+#if arch_is_big_endian
+# define mono_copy_chunk uint
+# define set_mono_right_mask(var, w)\
+ var = ((w) == chunk_bits ? chunk_all_bits : chunk_hi_bits(w))
+/*
+ * We have to split the following statement because of a bug in the Xenix C
+ * compiler (it produces a signed rather than an unsigned shift if we don't
+ * split).
+ */
+# define set_mono_thin_mask(var, w, bit)\
+ set_mono_right_mask(var, w), var >>= (bit)
+/*
+ * We have to split the following statement in two because of a bug
+ * in the DEC VAX/VMS C compiler.
+ */
+# define set_mono_left_mask(var, bit)\
+ var = chunk_all_bits, var >>= (bit)
+#else
+# define mono_copy_chunk bits16
+extern const bits16 mono_copy_masks[17];
+# if mono_fill_chunk_bytes == 2
+# define mono_fill_masks mono_copy_masks
+# else
+extern const bits32 mono_fill_masks[33];
+# endif
+/*
+ * We define mono_masks as either mono_fill_masks or
+ * mono_copy_masks before using the following macros.
+ */
+# define set_mono_left_mask(var, bit)\
+ var = mono_masks[bit]
+# define set_mono_thin_mask(var, w, bit)\
+ var = ~mono_masks[(w) + (bit)] & mono_masks[bit]
+# define set_mono_right_mask(var, ebit)\
+ var = ~mono_masks[ebit]
+#endif
+
+/* ---------------- Procedures ---------------- */
+
+/* Fill a rectangle of bits with an 8x1 pattern. */
+/* The pattern argument must consist of the pattern in every byte, */
+/* e.g., if the desired pattern is 0xaa, the pattern argument must */
+/* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
+#if mono_fill_chunk_bytes == 2
+# define mono_fill_make_pattern(byt) (uint)((uint)(byt) * 0x0101)
+#else
+# define mono_fill_make_pattern(byt) (uint)((uint)(byt) * 0x01010101)
+#endif
+void bits_fill_rectangle(P6(byte *dest, int dest_bit, uint raster,
+ mono_fill_chunk pattern, int width_bits, int height));
+
+/* Replicate a bitmap horizontally in place. */
+void bits_replicate_horizontally(P6(byte *data, uint width, uint height,
+ uint raster, uint replicated_width, uint replicated_raster));
+
+/* Replicate a bitmap vertically in place. */
+void bits_replicate_vertically(P4(byte *data, uint height, uint raster,
+ uint replicated_height));
+
+/* Find the bounding box of a bitmap. */
+void bits_bounding_box(P4(const byte *data, uint height, uint raster,
+ gs_int_rect *pbox));
+
+/* Compress an oversampled image, possibly in place. */
+/* The width and height must be multiples of the respective scale factors. */
+/* The source must be an aligned bitmap, as usual. */
+void bits_compress_scaled(P9(const byte *src, int srcx, uint width,
+ uint height, uint sraster, byte *dest, uint draster,
+ const gs_log2_scale_point *plog2_scale, int log2_out_bits));
+
+/* Fill a rectangle of bytes. */
+void bytes_fill_rectangle(P5(byte *dest, uint raster,
+ byte value, int width_bytes, int height));
+
+/* Copy a rectangle of bytes. */
+void bytes_copy_rectangle(P6(byte *dest, uint dest_raster,
+ const byte *src, uint src_raster, int width_bytes, int height));
diff --git a/gs/src/gsbittab.c b/gs/src/gsbittab.c
new file mode 100644
index 000000000..574f03857
--- /dev/null
+++ b/gs/src/gsbittab.c
@@ -0,0 +1,126 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsbittab.c */
+/* Tables for bit operations */
+#include "stdpre.h"
+#include "gsbittab.h"
+
+/* ---------------- Byte processing tables ---------------- */
+
+/*
+ * byte_reverse_bits[B] = the byte B with the order of bits reversed.
+ */
+const byte byte_reverse_bits[256] = {
+ bit_table_8(0, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80)
+};
+
+/*
+ * byte_right_mask[N] = a byte with N trailing 1s, 0 <= N <= 8.
+ */
+const byte byte_right_mask[9] = {
+ 0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
+};
+
+/*
+ * byte_count_bits[B] = the number of 1-bits in a byte with value B.
+ */
+const byte byte_count_bits[256] = {
+ bit_table_8(0, 1, 1, 1, 1, 1, 1, 1, 1)
+};
+
+/* ---------------- Scanning tables ---------------- */
+
+/*
+ * byte_bit_run_length_N[B], for 0 <= N <= 7, gives the length of the
+ * run of 1-bits starting at bit N in a byte with value B,
+ * numbering the bits in the byte as 01234567. If the run includes
+ * the low-order bit (i.e., might be continued into a following byte),
+ * the run length is increased by 8.
+ */
+
+#define t8(n) n,n,n,n,n+1,n+1,n+2,n+11
+#define r8(n) n,n,n,n,n,n,n,n
+#define r16(n) r8(n),r8(n)
+#define r32(n) r16(n),r16(n)
+#define r64(n) r32(n),r32(n)
+#define r128(n) r64(n),r64(n)
+const byte byte_bit_run_length_0[256] = {
+ r128(0), r64(1), r32(2), r16(3), r8(4), t8(5)
+};
+const byte far_data byte_bit_run_length_1[256] = {
+ r64(0), r32(1), r16(2), r8(3), t8(4),
+ r64(0), r32(1), r16(2), r8(3), t8(4)
+};
+const byte far_data byte_bit_run_length_2[256] = {
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3)
+};
+const byte far_data byte_bit_run_length_3[256] = {
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2)
+};
+const byte far_data byte_bit_run_length_4[256] = {
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+};
+#define rr8(a,b,c,d,e,f,g,h)\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h
+const byte far_data byte_bit_run_length_5[256] = {
+ rr8(0,0,0,0,1,1,2,11)
+};
+const byte far_data byte_bit_run_length_6[256] = {
+ rr8(0,0,1,10,0,0,1,10)
+};
+const byte far_data byte_bit_run_length_7[256] = {
+ rr8(0,9,0,9,0,9,0,9)
+};
+
+/* Pointer tables indexed by bit number. */
+
+const byte *byte_bit_run_length[8] =
+{ byte_bit_run_length_0, byte_bit_run_length_1,
+ byte_bit_run_length_2, byte_bit_run_length_3,
+ byte_bit_run_length_4, byte_bit_run_length_5,
+ byte_bit_run_length_6, byte_bit_run_length_7
+};
+const byte *byte_bit_run_length_neg[8] =
+{ byte_bit_run_length_0, byte_bit_run_length_7,
+ byte_bit_run_length_6, byte_bit_run_length_5,
+ byte_bit_run_length_4, byte_bit_run_length_3,
+ byte_bit_run_length_2, byte_bit_run_length_1
+};
+
+/* Some C compilers insist on having executable code in every file.... */
+void
+gsbittab_dummy(void)
+{
+}
diff --git a/gs/src/gsbittab.h b/gs/src/gsbittab.h
new file mode 100644
index 000000000..fbc87f98f
--- /dev/null
+++ b/gs/src/gsbittab.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsbittab.h */
+/* Interface to tables for bit operations */
+
+/*
+ * Generate tables for transforming 2, 4, 6, or 8 bits.
+ */
+#define btab2_(v0,v2,v1)\
+ v0,v1+v0,v2+v0,v2+v1+v0
+#define bit_table_2(v0,v2,v1) btab2_(v0,v2,v1)
+#define btab4_(v0,v8,v4,v2,v1)\
+ btab2_(v0,v2,v1), btab2_(v4+v0,v2,v1),\
+ btab2_(v8+v0,v2,v1), btab2_(v8+v4+v0,v2,v1)
+#define bit_table_4(v0,v8,v4,v2,v1) btab4_(v0,v8,v4,v2,v1)
+#define btab6_(v0,v20,v10,v8,v4,v2,v1)\
+ btab4_(v0,v8,v4,v2,v1), btab4_(v10+v0,v8,v4,v2,v1),\
+ btab4_(v20+v0,v8,v4,v2,v1), btab4_(v20+v10+v0,v8,v4,v2,v1)
+#define bit_table_6(v0,v20,v10,v8,v4,v2,v1) btab6_(v0,v20,v10,v8,v4,v2,v1)
+#define bit_table_8(v0,v80,v40,v20,v10,v8,v4,v2,v1)\
+ btab6_(v0,v20,v10,v8,v4,v2,v1), btab6_(v40+v0,v20,v10,v8,v4,v2,v1),\
+ btab6_(v80+v0,v20,v10,v8,v4,v2,v1), btab6_(v80+v40+v0,v20,v10,v8,v4,v2,v1)
+
+/*
+ * byte_reverse_bits[B] = the byte B with the order of bits reversed.
+ */
+extern const byte byte_reverse_bits[256];
+
+/*
+ * byte_right_mask[N] = a byte with N trailing 1s, 0 <= N <= 8.
+ */
+extern const byte byte_right_mask[9];
+
+/*
+ * byte_count_bits[B] = the number of 1-bits in a byte with value B.
+ */
+extern const byte byte_count_bits[256];
+
+/*
+ * byte_bit_run_length_N[B], for 0 <= N <= 7, gives the length of the
+ * run of 1-bits starting at bit N in a byte with value B,
+ * numbering the bits in the byte as 01234567. If the run includes
+ * the low-order bit (i.e., might be continued into a following byte),
+ * the run length is increased by 8.
+ */
+extern const byte
+ byte_bit_run_length_0[256], byte_bit_run_length_1[256],
+ byte_bit_run_length_2[256], byte_bit_run_length_3[256],
+ byte_bit_run_length_4[256], byte_bit_run_length_5[256],
+ byte_bit_run_length_6[256], byte_bit_run_length_7[256];
+
+/*
+ * byte_bit_run_length[N] points to byte_bit_run_length_N.
+ * byte_bit_run_length_neg[N] = byte_bit_run_length[-N & 7].
+ */
+extern const byte *byte_bit_run_length[8];
+extern const byte *byte_bit_run_length_neg[8];
diff --git a/gs/src/gsccode.h b/gs/src/gsccode.h
new file mode 100644
index 000000000..87bcca5c7
--- /dev/null
+++ b/gs/src/gsccode.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsccode.h */
+/* Types for character codes */
+
+#ifndef gsccode_INCLUDED
+# define gsccode_INCLUDED
+
+/*
+ * Define a character code. Normally this is just a single byte from a
+ * string, but because of composite fonts, character codes must be
+ * at least 32 bits.
+ */
+typedef ulong gs_char;
+#define gs_no_char ((gs_char)~0L)
+
+/*
+ * Define a character glyph code, a.k.a. character name.
+ * gs_glyphs from 0 to 2^31-1 are (PostScript) names; gs_glyphs 2^31 and
+ * above are CIDs, biased by 2^31.
+ */
+typedef ulong gs_glyph;
+#define gs_no_glyph ((gs_glyph)0x7fffffff)
+#define gs_min_cid_glyph ((gs_glyph)0x80000000)
+#define gs_max_glyph max_ulong
+
+/* Define a procedure for marking a gs_glyph during garbage collection. */
+typedef bool (*gs_glyph_mark_proc_t)(P2(gs_glyph glyph, void *proc_data));
+
+/* Define a procedure for mapping a gs_glyph to its (string) name. */
+#define gs_proc_glyph_name(proc)\
+ const char *proc(P2(gs_glyph, uint *))
+/* The following typedef is needed because ansi2knr can't handle */
+/* gs_proc_glyph_name((*procname)) in a formal argument list. */
+typedef gs_proc_glyph_name((*gs_proc_glyph_name_t));
+
+/* Define a procedure for accessing the known encodings. */
+#define gs_proc_known_encode(proc)\
+ gs_glyph proc(P2(gs_char, int))
+typedef gs_proc_known_encode((*gs_proc_known_encode_t));
+
+/* Define the callback procedure vector for character to xglyph mapping. */
+typedef struct gx_xfont_callbacks_s {
+ gs_proc_glyph_name((*glyph_name));
+ gs_proc_known_encode((*known_encode));
+} gx_xfont_callbacks;
+
+#endif /* gsccode_INCLUDED */
diff --git a/gs/src/gsccolor.h b/gs/src/gsccolor.h
new file mode 100644
index 000000000..6924e755f
--- /dev/null
+++ b/gs/src/gsccolor.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsccolor.h */
+/* Client color structure definition */
+
+#ifndef gsccolor_INCLUDED
+# define gsccolor_INCLUDED
+
+#include "gsstruct.h" /* for extern_st */
+
+/* Pattern instance, usable in color. */
+typedef struct gs_pattern_instance_s gs_pattern_instance;
+
+/* Paint (non-pattern) colors (Device, CIE, Indexed, Separation) */
+typedef struct gs_paint_color_s {
+ float values[4];
+} gs_paint_color;
+
+/* General colors */
+typedef struct gs_client_color_s {
+ gs_paint_color paint; /* also color for uncolored pattern */
+ gs_pattern_instance *pattern;
+} gs_client_color;
+extern_st(st_client_color);
+#define public_st_client_color() /* in gscolor.c */\
+ gs_public_st_ptrs1(st_client_color, gs_client_color, "gs_client_color",\
+ client_color_enum_ptrs, client_color_reloc_ptrs, pattern)
+#define st_client_color_max_ptrs 1
+
+#endif /* gsccolor_INCLUDED */
diff --git a/gs/src/gscdef.c b/gs/src/gscdef.c
new file mode 100644
index 000000000..f4e49b1b2
--- /dev/null
+++ b/gs/src/gscdef.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscdef.c */
+/* Configuration scalars */
+#include "stdpre.h"
+#include "gscdefs.h" /* interface */
+#include "gconfig.h" /* for #defines */
+
+/* ---------------- Miscellaneous system parameters ---------------- */
+
+/* All of these can be set in the makefile. */
+/* They should all be const; see gscdefs.h for more information. */
+
+#ifndef GS_BUILDTIME
+# define GS_BUILDTIME\
+ 0 /* should be set in the makefile */
+#endif
+long gs_buildtime = GS_BUILDTIME;
+
+#ifndef GS_COPYRIGHT
+# define GS_COPYRIGHT\
+ "Copyright (C) 1997 Aladdin Enterprises, Menlo Park, CA. All rights reserved."
+#endif
+const char *gs_copyright = GS_COPYRIGHT;
+
+#ifndef GS_PRODUCT
+# define GS_PRODUCT\
+ "Aladdin Ghostscript"
+#endif
+const char *gs_product = GS_PRODUCT;
+
+/* GS_REVISION must be defined in the makefile. */
+long gs_revision = GS_REVISION; /* should be const, see gscdefs.h */
+
+/* GS_REVISIONDATE must be defined in the makefile. */
+long gs_revisiondate = GS_REVISIONDATE; /* should be const, see gscdefs.h */
+
+#ifndef GS_SERIALNUMBER
+# define GS_SERIALNUMBER\
+ 42 /* a famous number */
+#endif
+long gs_serialnumber = GS_SERIALNUMBER; /* should be const, see gscdefs.h */
+
+/* ---------------- Installation directories and files ---------------- */
+
+/* Here is where the library search path, the name of the */
+/* initialization file, and the doc directory are defined. */
+/* Define the documentation directory (only used in help messages). */
+const char *gs_doc_directory = GS_DOCDIR;
+
+/* Define the default library search path. */
+const char *gs_lib_default_path = GS_LIB_DEFAULT;
+
+/* Define the interpreter initialization file. */
+const char *gs_init_file = GS_INIT;
diff --git a/gs/src/gscdefs.h b/gs/src/gscdefs.h
new file mode 100644
index 000000000..b8f33ad0e
--- /dev/null
+++ b/gs/src/gscdefs.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscdefs.h */
+/* Prototypes for configuration definitions in gconfig.c. */
+
+/* Miscellaneous system constants (read-only systemparams). */
+/* They should all be const, but one application needs some of them */
+/* to be writable.... */
+extern long gs_buildtime;
+extern const char *gs_copyright;
+extern const char *gs_product;
+extern long gs_revision;
+extern long gs_revisiondate;
+extern long gs_serialnumber;
+
+/* Installation directories and files */
+extern const char *gs_doc_directory;
+extern const char *gs_lib_default_path;
+extern const char *gs_init_file;
+
+/* Resource tables. In order to avoid importing a large number of types, */
+/* we only provide macros for the externs, not the externs themselves. */
+
+#define extern_gx_init_table()\
+ extern void (*gx_init_table[])(P1(gs_memory_t *))
+
+#define extern_gx_io_device_table()\
+ extern gx_io_device *gx_io_device_table[]
+
+/* Return the list of device prototypes, the list of their structure */
+/* descriptors, and (as the value) the length of the lists. */
+#define extern_gs_lib_device_list()\
+ int gs_lib_device_list(P2(const gx_device ***plist,\
+ gs_memory_struct_type_t **pst))
diff --git a/gs/src/gschar.c b/gs/src/gschar.c
new file mode 100644
index 000000000..2e17c014a
--- /dev/null
+++ b/gs/src/gschar.c
@@ -0,0 +1,1432 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gschar.c */
+/* Character writing operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h" /* ditto */
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxcoord.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+#include "gxfcache.h"
+#include "gspath.h"
+#include "gzpath.h"
+
+/* Define whether or not to cache characters rotated by angles other than */
+/* multiples of 90 degrees. */
+#define CACHE_ROTATED_CHARS 1
+
+/* Define whether or not to oversample characters at small sizes. */
+#define OVERSAMPLE 1
+
+/* Define the maximum size of a full temporary bitmap when rasterizing, */
+/* in bits (not bytes). */
+#define MAX_TEMP_BITMAP_BITS 80000
+
+/* Structure descriptors */
+private_st_gs_show_enum();
+#define eptr ((gs_show_enum *)vptr)
+private ENUM_PTRS_BEGIN(show_enum_enum_ptrs) {
+ if ( index > eptr->fstack.depth + 6 )
+ return 0;
+ ENUM_RETURN(eptr->fstack.items[index - 6].font);
+ }
+ ENUM_PTR(0, gs_show_enum, pgs);
+ ENUM_CONST_STRING_PTR(1, gs_show_enum, str);
+ ENUM_PTR(2, gs_show_enum, show_gstate);
+ ENUM_PTR(3, gs_show_enum, dev_cache);
+ ENUM_PTR(4, gs_show_enum, dev_cache2);
+ ENUM_PTR(5, gs_show_enum, dev_null);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(show_enum_reloc_ptrs) {
+ int i;
+ RELOC_PTR(gs_show_enum, pgs);
+ RELOC_CONST_STRING_PTR(gs_show_enum, str);
+ RELOC_PTR(gs_show_enum, show_gstate);
+ RELOC_PTR(gs_show_enum, dev_cache);
+ RELOC_PTR(gs_show_enum, dev_cache2);
+ RELOC_PTR(gs_show_enum, dev_null);
+ for ( i = 0; i <= eptr->fstack.depth; i++ )
+ RELOC_PTR(gs_show_enum, fstack.items[i].font);
+} RELOC_PTRS_END
+#undef eptr
+
+/* Forward declarations */
+private int continue_kshow(P1(gs_show_enum *));
+private int continue_show(P1(gs_show_enum *));
+private int continue_show_update(P1(gs_show_enum *));
+private int show_setup(P4(gs_show_enum *, gs_state *, const char *, bool));
+private void show_set_scale(P1(gs_show_enum *));
+private int show_cache_setup(P1(gs_show_enum *));
+private int show_state_setup(P1(gs_show_enum *));
+private int show_origin_setup(P4(gs_state *, fixed, fixed, gs_char_path_mode));
+private int stringwidth_setup(P3(gs_show_enum *, gs_state *, const char *));
+
+/* Print the ctm if debugging */
+#define print_ctm(s,pgs)\
+ dprintf7("[p]%sctm=[%g %g %g %g %g %g]\n", s,\
+ pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy,\
+ pgs->ctm.tx, pgs->ctm.ty)
+
+/* ------ Font procedures ------ */
+
+/* Dummy (ineffective) BuildChar/BuildGlyph procedure */
+int
+gs_no_build_char(gs_show_enum *penum, gs_state *pgs,
+ gs_font *pfont, gs_char chr, gs_glyph glyph)
+{ return 1; /* failure, but not error */
+}
+
+/* Dummy character encoding procedure */
+gs_glyph
+gs_no_encode_char(gs_show_enum *penum,
+ gs_font *pfont, gs_char *pchr)
+{ return gs_no_glyph;
+}
+
+/* ------ String writing operators ------ */
+
+/* Allocate a show enumerator. */
+gs_show_enum *
+gs_show_enum_alloc(gs_memory_t *mem, gs_state *pgs, client_name_t cname)
+{ gs_show_enum *penum =
+ gs_alloc_struct(mem, gs_show_enum, &st_gs_show_enum, cname);
+ if ( penum == 0 )
+ return 0;
+ /* Initialize pointers for GC */
+ penum->pgs = pgs;
+ penum->str.data = 0;
+ penum->str.size = 0;
+ penum->dev_cache = 0;
+ penum->dev_cache2 = 0;
+ penum->dev_null = 0;
+ penum->fstack.depth = -1;
+ return penum;
+}
+
+/* Free the contents of a show enumerator. */
+void
+gs_show_enum_release(gs_show_enum *penum, gs_memory_t *emem)
+{ gs_state *pgs = penum->pgs;
+ gs_memory_t *mem = pgs->memory;
+
+ penum->cc = 0;
+ if ( penum->dev_cache2 != 0 )
+ { gs_free_object(mem, penum->dev_cache2,
+ "gs_show_enum_release(dev_cache2)");
+ penum->dev_cache2 = 0;
+ }
+ if ( penum->dev_cache != 0 )
+ { gs_free_object(mem, penum->dev_cache,
+ "gs_show_enum_release(dev_cache)");
+ penum->dev_cache = 0;
+ }
+ if ( penum->dev_null != 0 )
+ { gs_free_object(mem, penum->dev_null,
+ "gs_show_enum_release(dev_null)");
+ penum->dev_null = 0;
+ }
+ if ( emem != 0 )
+ gs_free_object(emem, penum, "gs_show_enum_release(enum)");
+}
+
+/* Setup macros for show operators */
+#define setup_show_n()\
+ penum->str.size = size
+#define setup_a()\
+ penum->add = true, penum->ax = ax, penum->ay = ay,\
+ penum->slow_show = true
+#define setup_width()\
+ penum->wchr = chr, penum->wcx = cx, penum->wcy = cy,\
+ penum->slow_show = true
+
+/* show[_n] */
+int
+gs_show_n_init(register gs_show_enum *penum,
+ gs_state *pgs, const char *str, uint size)
+{ setup_show_n();
+ penum->slow_show = false;
+ return show_setup(penum, pgs, str, true);
+}
+int
+gs_show_init(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ return gs_show_n_init(penum, pgs, str, strlen(str));
+}
+
+/* ashow[_n] */
+int
+gs_ashow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, floatp ax, floatp ay, const char *str, uint size)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, true);
+ setup_a();
+ return code;
+}
+int
+gs_ashow_init(gs_show_enum *penum,
+ gs_state *pgs, floatp ax, floatp ay, const char *str)
+{ return gs_ashow_n_init(penum, pgs, ax, ay, str, strlen(str));
+}
+
+/* widthshow[_n] */
+int
+gs_widthshow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, floatp cx, floatp cy, gs_char chr, const char *str, uint size)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, true);
+ setup_width();
+ return code;
+}
+int
+gs_widthshow_init(gs_show_enum *penum,
+ gs_state *pgs, floatp cx, floatp cy, gs_char chr, const char *str)
+{ return gs_widthshow_n_init(penum, pgs, cx, cy, chr, str, strlen(str));
+}
+
+/* awidthshow[_n] */
+int
+gs_awidthshow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
+ const char *str, uint size)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, true);
+ setup_a();
+ setup_width();
+ return code;
+}
+int
+gs_awidthshow_init(gs_show_enum *penum,
+ gs_state *pgs, floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
+ const char *str)
+{ return gs_awidthshow_n_init(penum, pgs, cx, cy, chr, ax, ay,
+ str, strlen(str));
+}
+
+/* kshow[_n] */
+int
+gs_kshow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, const char *str, uint size)
+{ int code;
+ if ( pgs->font->FontType == ft_composite)
+ return_error(gs_error_invalidfont);
+ setup_show_n();
+ code = show_setup(penum, pgs, str, true);
+ penum->do_kern = 1;
+ penum->slow_show = true;
+ return code;
+}
+int
+gs_kshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ return gs_kshow_n_init(penum, pgs, str, strlen(str));
+}
+
+/* xyshow[_n] */
+int
+gs_xyshow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, const char *str, uint size)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, true);
+ penum->do_kern = -1;
+ penum->slow_show = true;
+ return code;
+}
+int
+gs_xyshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ return gs_xyshow_n_init(penum, pgs, str, strlen(str));
+}
+
+/* glyphshow */
+private int
+setup_glyph(P3(gs_show_enum *, gs_state *, gs_glyph));
+private font_proc_encode_char(gs_glyphshow_encode_char);
+int
+gs_glyphshow_init(gs_show_enum *penum, gs_state *pgs, gs_glyph glyph)
+{ return setup_glyph(penum, pgs, glyph);
+}
+int
+gs_glyphpath_init(gs_show_enum *penum, gs_state *pgs, gs_glyph glyph,
+ bool stroke_path)
+{ int code = setup_glyph(penum, pgs, glyph);
+ penum->charpath_flag =
+ (stroke_path ? cpm_true_charpath : cpm_false_charpath);
+ penum->can_cache = -1;
+ if_debug1('k', "[k]glyphpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+private int
+setup_glyph(gs_show_enum *penum, gs_state *pgs, gs_glyph glyph)
+{ int code;
+ if ( pgs->font->FontType == ft_composite)
+ return_error(gs_error_invalidfont);
+ penum->str.size = 1;
+ penum->slow_show = false;
+ code = show_setup(penum, pgs, "\000", true); /* arbitrary char */
+ penum->current_glyph = glyph;
+ penum->encode_char = gs_glyphshow_encode_char;
+ return code;
+}
+private gs_glyph
+gs_glyphshow_encode_char(gs_show_enum *penum, gs_font *pfont, gs_char *pchr)
+{ /* We just nil out the character, and return the pre-loaded glyph. */
+ *pchr = gs_no_char;
+ return penum->current_glyph;
+}
+
+/* ------ Related operators ------ */
+
+/* cshow[_n] */
+int
+gs_cshow_n_init(register gs_show_enum *penum,
+ gs_state *pgs, const char *str, uint size)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, false);
+ penum->do_kern = -1;
+ penum->stringwidth_flag = -1;
+ penum->slow_show = true;
+ return code;
+}
+int
+gs_cshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ return gs_cshow_n_init(penum, pgs, str, strlen(str));
+}
+
+/* stringwidth[_n] */
+int
+gs_stringwidth_n_init(gs_show_enum *penum, gs_state *pgs, const char *str, uint size)
+{ setup_show_n();
+ return stringwidth_setup(penum, pgs, str);
+}
+int
+gs_stringwidth_init(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ return gs_stringwidth_n_init(penum, pgs, str, strlen(str));
+}
+
+/* Common code for stringwidth[_n] */
+private int
+stringwidth_setup(gs_show_enum *penum, gs_state *pgs, const char *str)
+{ int code =
+ (penum->slow_show = false, show_setup(penum, pgs, str, false));
+ gs_memory_t *mem = pgs->memory;
+ gx_device_null *dev_null;
+ if ( code < 0 )
+ return code;
+ dev_null = gs_alloc_struct(mem, gx_device_null, &st_device_null,
+ "stringwidth_setup(dev_null)");
+ if ( dev_null == 0 )
+ return_error(gs_error_VMerror);
+ penum->stringwidth_flag = 1;
+ /* Do an extra gsave and suppress output */
+ if ( (code = gs_gsave(pgs)) < 0 )
+ return code;
+ penum->level = pgs->level; /* for level check in show_update */
+ /* Set up a null device that forwards xfont requests properly. */
+ gs_make_null_device(dev_null, mem);
+ dev_null->target = gs_currentdevice_inline(pgs);
+ pgs->device = (gx_device *)dev_null;
+ pgs->ctm_default_set = false;
+ penum->dev_null = dev_null;
+ /* Establish an arbitrary translation and current point. */
+ gs_newpath(pgs);
+ gx_translate_to_fixed(pgs, fixed_0, fixed_0);
+ return gx_path_add_point(pgs->path, fixed_0, fixed_0);
+}
+
+/* charpath[_n] */
+int
+gs_charpath_n_init(gs_show_enum *penum, gs_state *pgs,
+ const char *str, uint size, bool stroke_path)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, false);
+ penum->charpath_flag =
+ (stroke_path ? cpm_true_charpath : cpm_false_charpath);
+ penum->can_cache = -1;
+ if_debug1('k', "[k]charpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+int
+gs_charpath_init(gs_show_enum *penum, gs_state *pgs,
+ const char *str, bool stroke_path)
+{ return gs_charpath_n_init(penum, pgs, str, strlen(str), stroke_path);
+}
+
+/* charboxpath[_n] */
+int
+gs_charboxpath_n_init(gs_show_enum *penum, gs_state *pgs,
+ const char *str, uint size, bool use_boxes)
+{ int code;
+ setup_show_n();
+ code = show_setup(penum, pgs, str, false);
+ penum->charpath_flag =
+ (use_boxes ? cpm_true_charboxpath : cpm_false_charboxpath);
+ penum->can_cache = 0; /* different from charpath! */
+ if_debug1('k', "[k]charboxpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+int
+gs_charboxpath_init(gs_show_enum *penum, gs_state *pgs,
+ const char *str, bool stroke_path)
+{ return gs_charboxpath_n_init(penum, pgs, str, strlen(str),
+ stroke_path);
+}
+
+/* ------ Width/cache operators ------ */
+
+private int set_cache_device(P6(gs_show_enum *penum, gs_state *pgs,
+ floatp llx, floatp lly, floatp urx, floatp ury));
+
+/* setcachedevice */
+/* The elements of pw are: wx, wy, llx, lly, urx, ury. */
+/* Note that this returns 1 if we just set up the cache device. */
+int
+gs_setcachedevice_double(gs_show_enum *penum, gs_state *pgs, const double *pw)
+{ int code = gs_setcharwidth(penum, pgs, pw[0], pw[1]); /* default is don't cache */
+
+ if ( code < 0 )
+ return code;
+ return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
+}
+/* The _float procedure is strictly for backward compatibility. */
+int
+gs_setcachedevice_float(gs_show_enum *penum, gs_state *pgs, const float *pw)
+{ double w[6];
+ int i;
+
+ for ( i = 0; i < 6; ++i )
+ w[i] = pw[i];
+ return gs_setcachedevice_double(penum, pgs, w);
+}
+
+/* setcachedevice2 */
+/* The elements of pw2 are: w0x, w0y, llx, lly, urx, ury, w1x, w1y, vx, vy. */
+/* Note that this returns 1 if we just set up the cache device. */
+int
+gs_setcachedevice2_double(gs_show_enum *penum, gs_state *pgs,
+ const double *pw2)
+{ int code;
+
+ if ( gs_rootfont(pgs)->WMode )
+ { float vx = pw2[8], vy = pw2[9];
+ gs_fixed_point pvxy, dvxy;
+ cached_char *cc;
+
+ if ( (code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0 ||
+ (code = gs_setcharwidth(penum, pgs, pw2[6], pw2[7])) < 0
+ )
+ return code;
+ /* Adjust the origin by (vx, vy). */
+ gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
+ code = set_cache_device(penum, pgs, pw2[2], pw2[3], pw2[4], pw2[5]);
+ if ( code != 1 )
+ return code;
+ /* Adjust the character origin too. */
+ cc = penum->cc;
+ cc->offset.x += dvxy.x;
+ cc->offset.y += dvxy.y;
+ }
+ else
+ { code = gs_setcharwidth(penum, pgs, pw2[0], pw2[1]);
+ if ( code < 0 )
+ return code;
+ code = set_cache_device(penum, pgs, pw2[2], pw2[3], pw2[4], pw2[5]);
+ }
+ return code;
+}
+/* The _float procedure is strictly for backward compatibility. */
+int
+gs_setcachedevice2_float(gs_show_enum *penum, gs_state *pgs, const float *pw2)
+{ double w2[10];
+ int i;
+
+ for ( i = 0; i < 10; ++i )
+ w2[i] = pw2[i];
+ return gs_setcachedevice2_double(penum, pgs, w2);
+}
+
+/* Set up the cache device if relevant. */
+/* Return 1 if we just set up a cache device. */
+/* Used by setcachedevice and setcachedevice2. */
+private int
+set_cache_device(gs_show_enum *penum, gs_state *pgs, floatp llx, floatp lly,
+ floatp urx, floatp ury)
+{ gs_glyph glyph;
+
+ /* See if we want to cache this character. */
+ if ( pgs->in_cachedevice ) /* no recursion! */
+ return 0;
+ pgs->in_cachedevice = 1; /* disable color/gray/image operators */
+ /* We can only use the cache if we know the glyph. */
+ glyph = gs_show_current_glyph(penum);
+ if ( glyph == gs_no_glyph )
+ return 0;
+ /* We can only use the cache if ctm is unchanged */
+ /* (aside from a possible translation). */
+ if ( penum->can_cache <= 0 || !pgs->char_tm_valid )
+ { if_debug2('k', "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
+ penum->can_cache, (int)pgs->char_tm_valid);
+ return 0;
+ }
+ { const gs_font *pfont = pgs->font;
+ gs_font_dir *dir = pfont->dir;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ int alpha_bits =
+ (*dev_proc(dev, get_alpha_bits))(dev, go_text);
+ gs_log2_scale_point log2_scale;
+ static const fixed max_cdim[3] = {
+#define max_cd(n)\
+ (fixed_1 << (arch_sizeof_short * 8 - n)) - (fixed_1 >> n) * 3
+ max_cd(0), max_cd(1), max_cd(2)
+#undef max_cd
+ };
+ ushort iwidth, iheight;
+ cached_char *cc;
+ gs_fixed_rect clip_box;
+ int code;
+ /* Compute the bounding box of the transformed character. */
+ /* Since we accept arbitrary transformations, the extrema */
+ /* may occur in any order; however, we can save some work */
+ /* by observing that opposite corners before transforming */
+ /* are still opposite afterwards. */
+ gs_fixed_point cll, clr, cul, cur, cdim;
+
+ if ( (code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
+ )
+ return code;
+ { fixed ctemp;
+#define swap(a, b) ctemp = a, a = b, b = ctemp
+#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
+ make_min(cll.x, cur.x);
+ make_min(cll.y, cur.y);
+ make_min(clr.x, cul.x);
+ make_min(clr.y, cul.y);
+#undef make_min
+#undef swap
+ }
+ /* Now take advantage of symmetry. */
+ if ( clr.x < cll.x ) cll.x = clr.x, cur.x = cul.x;
+ if ( clr.y < cll.y ) cll.y = clr.y, cur.y = cul.y;
+ /* Now cll and cur are the extrema of the box. */
+ cdim.x = cur.x - cll.x;
+ cdim.y = cur.y - cll.y;
+ show_set_scale(penum);
+ log2_scale.x = penum->log2_suggested_scale.x;
+ log2_scale.y = penum->log2_suggested_scale.y;
+#ifdef DEBUG
+if ( gs_debug_c('k') )
+ { dprintf6("[k]cbox=[%g %g %g %g] scale=%dx%d\n",
+ fixed2float(cll.x), fixed2float(cll.y),
+ fixed2float(cur.x), fixed2float(cur.y),
+ 1 << log2_scale.x, 1 << log2_scale.y);
+ print_ctm(" ", pgs);
+ }
+#endif
+ /*
+ * If the device wants anti-aliased text,
+ * increase the sampling scale to ensure that
+ * if we want N bits of alpha, we generate
+ * at least 2^N sampled bits per pixel.
+ */
+ if ( alpha_bits > 1 )
+ { int more_bits =
+ alpha_bits - (log2_scale.x + log2_scale.y);
+ if ( more_bits > 0 )
+ { if (log2_scale.x <= log2_scale.y)
+ { log2_scale.x += (more_bits + 1) >> 1;
+ log2_scale.y += more_bits >> 1;
+ }
+ else
+ { log2_scale.x += more_bits >> 1;
+ log2_scale.y += (more_bits + 1) >> 1;
+ }
+ }
+ }
+ else
+#if OVERSAMPLE
+ if ( pfont->PaintType != 0 )
+#endif
+ { /* Don't oversample artificially stroked fonts. */
+ log2_scale.x = log2_scale.y = 0;
+ }
+ if ( cdim.x > max_cdim[log2_scale.x] ||
+ cdim.y > max_cdim[log2_scale.y]
+ )
+ return 0; /* much too big */
+ iwidth = ((ushort)fixed2int_var(cdim.x) + 2) << log2_scale.x;
+ iheight = ((ushort)fixed2int_var(cdim.y) + 2) << log2_scale.y;
+ if_debug3('k', "[k]iwidth=%u iheight=%u dev_cache %s\n",
+ (uint)iwidth, (uint)iheight,
+ (penum->dev_cache == 0 ? "not set" : "set"));
+ if ( penum->dev_cache == 0 )
+ { code = show_cache_setup(penum);
+ if ( code < 0 )
+ return code;
+ }
+ /*
+ * If we're oversampling (i.e., the temporary bitmap is
+ * larger than the final monobit or alpha array) and the
+ * temporary bitmap is large, use incremental conversion
+ * from oversampled bitmap strips to alpha values instead of
+ * full oversampling with compression at the end.
+ */
+ cc = gx_alloc_char_bits(dir, penum->dev_cache,
+ (iwidth > MAX_TEMP_BITMAP_BITS / iheight &&
+ log2_scale.x + log2_scale.y > alpha_bits ?
+ penum->dev_cache2 : NULL),
+ iwidth, iheight, &log2_scale, alpha_bits);
+ if ( cc == 0 )
+ return 0; /* too big for cache */
+ /* The mins handle transposed coordinate systems.... */
+ /* Truncate the offsets to avoid artifacts later. */
+ cc->offset.x = fixed_ceiling(-cll.x);
+ cc->offset.y = fixed_ceiling(-cll.y);
+ if_debug4('k', "[k]width=%u, height=%u, offset=[%g %g]\n",
+ (uint)iwidth, (uint)iheight,
+ fixed2float(cc->offset.x),
+ fixed2float(cc->offset.y));
+ if ( (code = gs_gsave(pgs)) < 0 )
+ { gx_free_cached_char(dir, cc);
+ return code;
+ }
+ /* Nothing can go wrong now.... */
+ penum->cc = cc;
+ cc->code = glyph;
+ cc->wmode = gs_rootfont(pgs)->WMode;
+ cc->wxy = penum->wxy;
+ /* Install the device */
+ pgs->device = (gx_device *)penum->dev_cache;
+ pgs->ctm_default_set = false;
+ /* Adjust the transformation in the graphics context */
+ /* so that the character lines up with the cache. */
+ gx_translate_to_fixed(pgs,
+ cc->offset.x << log2_scale.x,
+ cc->offset.y << log2_scale.y);
+ if ( (log2_scale.x | log2_scale.y) != 0 )
+ gx_scale_char_matrix(pgs, 1 << log2_scale.x,
+ 1 << log2_scale.y);
+ /* Set the initial matrix for the cache device. */
+ penum->dev_cache->initial_matrix = ctm_only(pgs);
+ /* Set the oversampling factor. */
+ penum->log2_current_scale.x = log2_scale.x;
+ penum->log2_current_scale.y = log2_scale.y;
+ /* Reset the clipping path to match the metrics. */
+ clip_box.p.x = clip_box.p.y = 0;
+ clip_box.q.x = int2fixed(iwidth);
+ clip_box.q.y = int2fixed(iheight);
+ if ( (code = gx_clip_to_rectangle(pgs, &clip_box)) < 0 )
+ return code;
+ gx_set_device_color_1(pgs); /* write 1's */
+ pgs->in_cachedevice = 2; /* we are caching */
+ }
+ penum->width_status = sws_cache;
+ return 1;
+}
+
+/* setcharwidth */
+/* Note that this returns 1 if the current show operation is */
+/* non-displaying (stringwidth or cshow). */
+int
+gs_setcharwidth(register gs_show_enum *penum, gs_state *pgs,
+ floatp wx, floatp wy)
+{ int code;
+ if ( penum->width_status != sws_none )
+ return_error(gs_error_undefined);
+ if ( (code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy)) < 0 )
+ return code;
+ /* Check whether we're setting the scalable width */
+ /* for a cached xfont character. */
+ if ( penum->cc != 0 )
+ { penum->cc->wxy = penum->wxy;
+ penum->width_status = sws_cache_width_only;
+ }
+ else
+ { penum->width_status = sws_no_cache;
+ }
+ return (penum->stringwidth_flag != 0 ? 1 : 0);
+}
+
+/* ------ Enumerator ------ */
+
+/* Do the next step of a show (or stringwidth) operation */
+int
+gs_show_next(gs_show_enum *penum)
+{ return (*penum->continue_proc)(penum);
+}
+
+/* Continuation procedures */
+private int show_update(P1(gs_show_enum *penum));
+private int show_move(P1(gs_show_enum *penum));
+private int show_proceed(P1(gs_show_enum *penum));
+private int show_finish(P1(gs_show_enum *penum));
+private int
+continue_show_update(register gs_show_enum *penum)
+{ int code = show_update(penum);
+ if ( code < 0 )
+ return code;
+ code = show_move(penum);
+ if ( code != 0 )
+ return code;
+ return show_proceed(penum);
+}
+private int
+continue_show(register gs_show_enum *penum)
+{ return show_proceed(penum);
+}
+/* For kshow, the CTM or font may have changed, so we have to reestablish */
+/* the cached values in the enumerator. */
+private int
+continue_kshow(register gs_show_enum *penum)
+{ int code = show_state_setup(penum);
+ if ( code < 0 )
+ return code;
+ return show_proceed(penum);
+}
+
+/* Update position */
+private int
+show_update(register gs_show_enum *penum)
+{ register gs_state *pgs = penum->pgs;
+ cached_char *cc = penum->cc;
+ int code;
+ /* Update position for last character */
+ switch ( penum->width_status )
+ {
+ case sws_none:
+ /* Adobe interpreters assume a character width of 0, */
+ /* even though the documentation says this is an error.... */
+ penum->wxy.x = penum->wxy.y = 0;
+ break;
+ case sws_cache:
+ /* Finish installing the cache entry. */
+ /* If the BuildChar/BuildGlyph procedure did a save and a */
+ /* restore, it already undid the gsave in setcachedevice. */
+ /* We have to check for this by comparing levels. */
+ switch ( pgs->level - penum->level )
+ {
+ default:
+ return_error(gs_error_invalidfont); /* WRONG */
+ case 2:
+ code = gs_grestore(pgs);
+ if ( code < 0 )
+ return code;
+ case 1:
+ ;
+ }
+ gx_add_cached_char(pgs->font->dir, penum->dev_cache,
+ cc, gx_lookup_fm_pair(pgs->font, pgs),
+ &penum->log2_current_scale);
+ if ( penum->stringwidth_flag != 0 ||
+ penum->charpath_flag != cpm_show
+ )
+ break;
+ /* falls through */
+ case sws_cache_width_only:
+ /* Copy the bits to the real output device. */
+ code = gs_grestore(pgs);
+ if ( code < 0 )
+ return code;
+ code = gs_state_color_load(pgs);
+ if ( code < 0 )
+ return code;
+ return gx_image_cached_char(penum, cc);
+ case sws_no_cache:
+ ;
+ }
+ if ( penum->charpath_flag != cpm_show )
+ { /* Move back to the character origin, so that */
+ /* show_move will get us to the right place. */
+ code = gx_path_add_point(pgs->show_gstate->path,
+ penum->origin.x, penum->origin.y);
+ if ( code < 0 )
+ return code;
+ }
+ return gs_grestore(pgs);
+}
+
+/* Move to next character */
+private int
+show_fast_move(gs_state *pgs, gs_fixed_point *pwxy)
+{ int code = gx_path_add_rel_point_inline(pgs->path, pwxy->x, pwxy->y);
+ /* If the current position is out of range, don't try to move. */
+ if ( code == gs_error_limitcheck && pgs->clamp_coordinates )
+ code = 0;
+ return code;
+}
+private int
+show_move(register gs_show_enum *penum)
+{ register gs_state *pgs = penum->pgs;
+ if ( penum->do_kern < 0 )
+ { /* xyshow or cshow */
+ penum->continue_proc = continue_show;
+ return gs_show_move;
+ }
+ if ( penum->add )
+ gs_rmoveto(pgs, penum->ax, penum->ay);
+ if ( penum->wchr != gs_no_char )
+ { gs_char chr = penum->current_char;
+ int fdepth = penum->fstack.depth;
+ if ( fdepth > 0 )
+ { /* Add in the shifted font number. */
+ uint fidx = penum->fstack.items[fdepth].index;
+ switch ( ((gs_font_type0 *)(penum->fstack.items[fdepth - 1].font))->data.FMapType )
+ {
+ case fmap_1_7:
+ case fmap_9_7:
+ chr += fidx << 7;
+ break;
+ default:
+ chr += fidx << 8;
+ }
+ }
+ if ( chr == penum->wchr )
+ gs_rmoveto(pgs, penum->wcx, penum->wcy);
+ }
+ /* wxy is in device coordinates */
+ { int code = show_fast_move(pgs, &penum->wxy);
+ if ( code < 0 )
+ return code;
+ }
+ /* Check for kerning, but not on the last character. */
+ if ( penum->do_kern && penum->index < penum->str.size )
+ { penum->continue_proc = continue_kshow;
+ return gs_show_kern;
+ }
+ return 0;
+}
+/* Process next character */
+private int
+show_proceed(register gs_show_enum *penum)
+{ register gs_state *pgs = penum->pgs;
+ gs_font *pfont;
+ cached_fm_pair *pair = 0;
+ gs_font *rfont =
+ (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
+ int wmode = rfont->WMode;
+ font_proc_next_char((*next_char)) = rfont->procs.next_char;
+ font_proc_next_glyph((*next_glyph)) = rfont->procs.next_glyph;
+#define next_char_glyph(penum, pchr, pglyph)\
+ (next_char == 0 ? (*next_glyph)(penum, pchr, pglyph) :\
+ (*(pglyph) = gs_no_glyph, (*next_char)(penum, pchr)))
+ gs_char chr;
+ gs_glyph glyph;
+ int code;
+ cached_char *cc;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ int alpha_bits = (*dev_proc(dev, get_alpha_bits))(dev, go_text);
+
+ if ( penum->charpath_flag == cpm_show && !penum->stringwidth_flag )
+ { code = gs_state_color_load(pgs);
+ if ( code < 0 )
+ return code;
+ }
+more: /* Proceed to next character */
+ pfont = (penum->fstack.depth < 0 ? pgs->font :
+ penum->fstack.items[penum->fstack.depth].font);
+ /* can_cache >= 0 allows us to use cached characters, */
+ /* even if we can't make new cache entries. */
+ if ( penum->can_cache >= 0 )
+ { /* Loop with cache */
+ for ( ; ; )
+ { switch ( (code = next_char_glyph(penum, &chr, &glyph)) )
+ {
+ default: /* error */
+ return code;
+ case 2: /* done */
+ return show_finish(penum);
+ case 1: /* font change */
+ pfont = penum->fstack.items[penum->fstack.depth].font;
+ pgs->char_tm_valid = false;
+ show_state_setup(penum);
+ pair = 0;
+ /* falls through */
+ case 0: /* plain char */
+ /*
+ * We don't need to set penum->current_char in the
+ * normal cases, but it's needed for widthshow,
+ * kshow, and one strange client, so we may as well
+ * do it here.
+ */
+ penum->current_char = chr;
+ if ( glyph == gs_no_glyph )
+ { glyph = (*penum->encode_char)(penum, pfont, &chr);
+ penum->current_char = chr;
+ if ( glyph == gs_no_glyph )
+ { cc = 0;
+ goto no_cache;
+ }
+ }
+ if ( pair == 0 )
+ pair = gx_lookup_fm_pair(pfont, pgs);
+ cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
+ alpha_bits);
+ if ( cc == 0 )
+ { /* Character is not in cache. */
+ /* If possible, try for an xfont before */
+ /* rendering from the outline. */
+ if ( pfont->ExactSize == fbit_use_outlines ||
+ pfont->PaintType == 2
+ )
+ goto no_cache;
+ if ( pfont->BitmapWidths )
+ { cc = gx_lookup_xfont_char(pgs, pair, chr,
+ glyph, &pfont->procs.callbacks, wmode);
+ if ( cc == 0 )
+ goto no_cache;
+ }
+ else
+ { if ( penum->stringwidth_flag != 0 ||
+ penum->charpath_flag != cpm_show
+ )
+ goto no_cache;
+ /* We might have an xfont, but we still */
+ /* want the scalable widths. */
+ cc = gx_lookup_xfont_char(pgs, pair, chr,
+ glyph, &pfont->procs.callbacks, wmode);
+ /* Render up to the point of */
+ /* setcharwidth or setcachedevice, */
+ /* just as for stringwidth. */
+ /* This is the only case in which we can */
+ /* to go no_cache with cc != 0. */
+ goto no_cache;
+ }
+ }
+ /* Character is in cache. */
+ /* We might be doing .charboxpath or stringwidth; */
+ /* check for these now. */
+ if ( penum->charpath_flag != cpm_show )
+ { /* This is .charboxpath. Get the bounding box */
+ /* and append it to a path. */
+ gx_path box_path;
+ gs_fixed_point pt;
+ fixed llx, lly, urx, ury;
+ code = gx_path_current_point(pgs->path, &pt);
+ if ( code < 0 )
+ return code;
+ llx = fixed_rounded(pt.x - cc->offset.x) +
+ int2fixed(penum->ftx);
+ lly = fixed_rounded(pt.y - cc->offset.y) +
+ int2fixed(penum->fty);
+ urx = llx + int2fixed(cc->width),
+ ury = lly + int2fixed(cc->height);
+ gx_path_init(&box_path, pgs->memory);
+ code =
+ gx_path_add_rectangle(&box_path, llx, lly,
+ urx, ury);
+ if ( code >= 0 )
+ code =
+ gx_path_add_char_path(pgs->show_gstate->path,
+ &box_path,
+ penum->charpath_flag);
+ if ( code >= 0 )
+ code = gx_path_add_point(pgs->path, pt.x, pt.y);
+ gx_path_release(&box_path);
+ if ( code < 0 )
+ return code;
+ }
+ else if ( !penum->stringwidth_flag )
+ { code = gx_image_cached_char(penum, cc);
+ if ( code < 0 )
+ return code;
+ else if ( code > 0 )
+ { cc = 0;
+ goto no_cache;
+ }
+ }
+ if ( penum->slow_show )
+ { /* Split up the assignment so that the */
+ /* Watcom compiler won't reserve esi/edi. */
+ penum->wxy.x = cc->wxy.x;
+ penum->wxy.y = cc->wxy.y;
+ code = show_move(penum);
+ }
+ else
+ code = show_fast_move(pgs, &cc->wxy);
+ if ( code )
+ { /* Might be kshow, so store the state. */
+ penum->current_glyph = glyph;
+ return code;
+ }
+ }
+ }
+ }
+ else
+ { /* Can't use cache */
+ switch ( (code = next_char_glyph(penum, &chr, &glyph)) )
+ {
+ default:
+ return code;
+ case 2:
+ return show_finish(penum);
+ case 1:
+ pfont = penum->fstack.items[penum->fstack.depth].font;
+ show_state_setup(penum);
+ case 0:
+ ;
+ }
+ penum->current_char = chr;
+ if ( glyph == gs_no_glyph )
+ { glyph = (*penum->encode_char)(penum, pfont, &chr);
+ penum->current_char = chr;
+ }
+ cc = 0;
+ }
+no_cache:
+ /*
+ * We must call the client's rendering code. Normally,
+ * we only do this if the character is not cached (cc = 0);
+ * however, we also must do this if we have an xfont but
+ * are using scalable widths. In this case, and only this case,
+ * we get here with cc != 0. penum->current_char has already
+ * been set, but not penum->current_glyph.
+ */
+ penum->current_glyph = glyph;
+ if ( (code = gs_gsave(pgs)) < 0 )
+ return code;
+ /* Set the font to the current descendant font. */
+ pgs->font = pfont;
+ /* Reset the in_cachedevice flag, so that a recursive show */
+ /* will use the cache properly. */
+ pgs->in_cachedevice = 0;
+ /* Reset the sampling scale. */
+ penum->log2_current_scale.x = penum->log2_current_scale.y = 0;
+ /* Set the charpath data in the graphics context if necessary, */
+ /* so that fill and stroke will add to the path */
+ /* rather than having their usual effect. */
+ pgs->in_charpath = penum->charpath_flag;
+ pgs->show_gstate =
+ (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
+ pgs->stroke_adjust = false; /* per specification */
+ { gs_fixed_point cpt;
+ gx_path *ppath = pgs->path;
+
+ if ( (code = gx_path_current_point_inline(ppath, &cpt)) < 0 )
+ goto rret;
+ penum->origin.x = cpt.x;
+ penum->origin.y = cpt.y;
+ /* Normally, char_tm is valid because of show_state_setup, */
+ /* but if we're in a cshow, it may not be. */
+ gs_currentcharmatrix(pgs, NULL, true);
+#if 1 /*USE_FPU <= 0*/
+ if ( pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid )
+ { fixed tx = pgs->ctm.tx_fixed;
+ fixed ty = pgs->ctm.ty_fixed;
+
+ gs_settocharmatrix(pgs);
+ cpt.x += pgs->ctm.tx_fixed - tx;
+ cpt.y += pgs->ctm.ty_fixed - ty;
+ }
+ else
+#endif
+ { double tx = pgs->ctm.tx;
+ double ty = pgs->ctm.ty;
+ double fpx, fpy;
+
+ gs_settocharmatrix(pgs);
+ fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
+ fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+ if ( !(f_fits_in_fixed(fpx) && f_fits_in_fixed(fpy)) )
+ { gs_note_error(code = gs_error_limitcheck);
+ goto rret;
+ }
+ cpt.x = float2fixed(fpx);
+ cpt.y = float2fixed(fpy);
+ }
+ gs_newpath(pgs);
+ code = show_origin_setup(pgs, cpt.x, cpt.y,
+ penum->charpath_flag);
+ if ( code < 0 )
+ goto rret;
+ }
+ penum->width_status = sws_none;
+ penum->continue_proc = continue_show_update;
+ /* Try using the build procedure in the font. */
+ /* < 0 means error, 0 means success, 1 means failure. */
+ penum->cc = cc; /* set this now for build procedure */
+ code = (*pfont->procs.build_char)(penum, pgs, pfont, chr, glyph);
+ if ( code < 0 )
+ { discard(gs_note_error(code));
+ goto rret;
+ }
+ if ( code == 0 )
+ { code = show_update(penum);
+ if ( code < 0 )
+ goto rret;
+ /* Note that show_update does a grestore.... */
+ code = show_move(penum);
+ if ( code )
+ return code; /* ... so don't go to rret here. */
+ goto more;
+ }
+ /*
+ * Some BuildChar procedures do a save before the setcachedevice,
+ * and a restore at the end. If we waited to allocate the cache
+ * device until the setcachedevice, we would attempt to free it
+ * after the restore. Therefore, allocate it now.
+ */
+ if ( penum->dev_cache == 0 )
+ { code = show_cache_setup(penum);
+ if ( code < 0 )
+ goto rret;
+ }
+ return gs_show_render;
+ /* If we get an error while setting up for BuildChar, */
+ /* we must undo the partial setup. */
+rret: gs_grestore(pgs);
+ return code;
+#undef next_char_glyph
+}
+
+/* Finish show or stringwidth */
+private int
+show_finish(gs_show_enum *penum)
+{ gs_state *pgs = penum->pgs;
+ int code, rcode;
+
+ gs_show_enum_release(penum, NULL);
+ if ( penum->stringwidth_flag <= 0 ) /* could be cshow */
+ return 0;
+ /* Save the accumulated width before returning, */
+ /* and undo the extra gsave. */
+ code = gs_currentpoint(pgs, &penum->width);
+ rcode = gs_grestore(pgs);
+ return (code < 0 ? code : rcode);
+}
+
+/* Return the current character for rendering. */
+gs_char
+gs_show_current_char(const gs_show_enum *penum)
+{ return penum->current_char;
+}
+
+/* Return the current glyph for rendering. */
+gs_glyph
+gs_show_current_glyph(const gs_show_enum *penum)
+{ return penum->current_glyph;
+}
+
+/* Return the width of the just-enumerated character (for cshow). */
+int
+gs_show_current_width(const gs_show_enum *penum, gs_point *ppt)
+{ return gs_idtransform(penum->pgs,
+ fixed2float(penum->wxy.x),
+ fixed2float(penum->wxy.y), ppt);
+}
+
+/* Return the just-displayed character for kerning. */
+gs_char
+gs_kshow_previous_char(const gs_show_enum *penum)
+{ return penum->current_char;
+}
+
+/* Return the about-to-be-displayed character for kerning. */
+gs_char
+gs_kshow_next_char(const gs_show_enum *penum)
+{ return penum->str.data[penum->index];
+}
+
+/* ------ Miscellaneous accessors ------ */
+
+/* Return the current font for cshow. */
+gs_font *
+gs_show_current_font(const gs_show_enum *penum)
+{ return (penum->fstack.depth < 0 ? penum->pgs->font :
+ penum->fstack.items[penum->fstack.depth].font);
+}
+
+/* Restore the current font after cshow. */
+int
+gs_show_restore_font(const gs_show_enum *penum)
+{ int fdepth = penum->fstack.depth;
+
+ if ( fdepth >= 0 )
+ { gs_state *pgs = penum->pgs;
+
+ gs_setfont(pgs, penum->fstack.items[0].font);
+ pgs->font = penum->fstack.items[fdepth].font;
+ }
+ return 0;
+}
+
+/* Return the charpath mode. */
+gs_char_path_mode
+gs_show_in_charpath(const gs_show_enum *penum)
+{ return penum->charpath_flag;
+}
+
+/* Return the accumulated width for stringwidth. */
+void
+gs_show_width(const gs_show_enum *penum, gs_point *ppt)
+{ *ppt = penum->width;
+}
+
+/* Return true if we only need the width from the rasterizer */
+/* and can short-circuit the full rendering of the character, */
+/* false if we need the actual character bits. */
+/* This is only meaningful just before calling gs_setcharwidth or */
+/* gs_setcachedevice[2]. */
+/* Note that we can't do this if the procedure has done any extra [g]saves. */
+bool
+gs_show_width_only(const gs_show_enum *penum)
+{ /* penum->cc will be non-zero iff we are calculating */
+ /* the scalable width for an xfont character. */
+ return ((penum->stringwidth_flag != 0 || penum->cc != 0) &&
+ penum->pgs->level == penum->level + 1);
+}
+
+/* ------ Internal routines ------ */
+
+/* Initialize a show enumerator. */
+/* Note that this does not set str.size. */
+private int
+show_setup(register gs_show_enum *penum, gs_state *pgs, const char *str,
+ bool propagate_charpath)
+{ int code;
+ gs_font *pfont;
+ gx_set_dev_color(pgs);
+ pfont = pgs->font;
+ penum->pgs = pgs;
+ penum->level = pgs->level;
+ penum->str.data = (const byte *)str; /* avoid signed chars */
+ penum->wchr = gs_no_char;
+ penum->add = false;
+ penum->do_kern = 0;
+ penum->charpath_flag =
+ (propagate_charpath ? pgs->in_charpath : cpm_show);
+ penum->stringwidth_flag = 0;
+ penum->dev_cache = 0;
+ penum->dev_cache2 = 0;
+ penum->dev_null = 0;
+ penum->index = 0;
+ penum->cc = 0;
+ penum->continue_proc = continue_show;
+ code = (*pfont->procs.init_fstack)(penum, pfont);
+ if ( code < 0 )
+ return code;
+ penum->can_cache = /* show_state_setup may reset */
+ (penum->charpath_flag == cpm_show ? 1 : -1);
+ code = show_state_setup(penum);
+ if ( code < 0 )
+ return code;
+ penum->show_gstate =
+ (propagate_charpath && (pgs->in_charpath != 0) ?
+ pgs->show_gstate : pgs);
+ return 0;
+}
+
+/* Initialize the gstate-derived parts of a show enumerator. */
+/* We do this both when starting the show operation, */
+/* and when returning from the kshow callout. */
+private int
+show_state_setup(gs_show_enum *penum)
+{ gs_state *pgs = penum->pgs;
+ const gs_font *pfont;
+ if ( penum->fstack.depth <= 0 )
+ { pfont = pgs->font;
+ gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
+ }
+ else
+ { /* We have to concatenate the parent's FontMatrix as well. */
+ gs_matrix mat;
+ const gx_font_stack_item *pfsi =
+ &penum->fstack.items[penum->fstack.depth];
+ pfont = pfsi->font;
+ gs_matrix_multiply(&pfont->FontMatrix,
+ &pfsi[-1].font->FontMatrix, &mat);
+ gs_setcharmatrix(pgs, &mat);
+ }
+ if ( (penum->can_cache >= 0
+#if !CACHE_ROTATED_CHARS
+ &= /* no skewing or non-rectangular rotation */
+ (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
+ is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy))
+#endif
+ ) )
+ { gs_fixed_rect cbox;
+ gx_cpath_inner_box(pgs->clip_path, &cbox);
+ /* Since characters occupy an integral number of pixels, */
+ /* we can (and should) round the inner clipping box */
+ /* outward rather than inward. */
+ penum->ibox.p.x = fixed2int_var(cbox.p.x);
+ penum->ibox.p.y = fixed2int_var(cbox.p.y);
+ penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
+ penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
+ gx_cpath_outer_box(pgs->clip_path, &cbox);
+ penum->obox.p.x = fixed2int_var(cbox.p.x);
+ penum->obox.p.y = fixed2int_var(cbox.p.y);
+ penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
+ penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
+#if 1 /*USE_FPU <= 0*/
+ if ( pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid )
+ { penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
+ pgs->ctm.tx_fixed);
+ penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
+ pgs->ctm.ty_fixed);
+ }
+ else
+#endif
+ { double fdx = pgs->char_tm.tx - pgs->ctm.tx;
+ double fdy = pgs->char_tm.ty - pgs->ctm.ty;
+#define int_bits (arch_sizeof_int * 8 - 1)
+ if ( !(f_fits_in_bits(fdx, int_bits) &&
+ f_fits_in_bits(fdy, int_bits))
+ )
+ return_error(gs_error_limitcheck);
+#undef int_bits
+ penum->ftx = (int)fdx;
+ penum->fty = (int)fdy;
+ }
+ }
+ penum->encode_char = pfont->procs.encode_char;
+ return 0;
+}
+
+/* Set the suggested oversampling scale for character rendering. */
+private void
+show_set_scale(gs_show_enum *penum)
+{ /* Decide whether to oversample. */
+ /* We have to decide this each time setcachedevice is called. */
+ const gs_state *pgs = penum->pgs;
+ if ( penum->charpath_flag == cpm_show &&
+ !penum->stringwidth_flag &&
+ gx_path_is_void_inline(pgs->path) &&
+ /* Oversampling rotated characters doesn't work well. */
+ (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
+ is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy))
+ )
+ { const gs_font_base *pfont = (gs_font_base *)pgs->font;
+ gs_fixed_point extent;
+ int code = gs_distance_transform2fixed(&pgs->char_tm,
+ pfont->FontBBox.q.x - pfont->FontBBox.p.x,
+ pfont->FontBBox.q.y - pfont->FontBBox.p.y,
+ &extent);
+ if ( code >= 0 )
+ { int sx =
+ (extent.x == 0 ? 0 :
+ any_abs(extent.x) < int2fixed(25) ? 2 :
+ any_abs(extent.x) < int2fixed(60) ? 1 :
+ 0);
+ int sy =
+ (extent.y == 0 ? 0 :
+ any_abs(extent.y) < int2fixed(25) ? 2 :
+ any_abs(extent.y) < int2fixed(60) ? 1 :
+ 0);
+ /* If we oversample at all, make sure we do it */
+ /* in both X and Y. */
+ if ( sx == 0 && sy != 0 ) sx = 1;
+ else if ( sy == 0 && sx != 0 ) sy = 1;
+ penum->log2_suggested_scale.x = sx;
+ penum->log2_suggested_scale.y = sy;
+ return;
+ }
+ }
+ /* By default, don't scale. */
+ penum->log2_suggested_scale.x =
+ penum->log2_suggested_scale.y = 0;
+}
+
+/* Set up the cache device and related information. */
+/* Note that we always allocate both cache devices, */
+/* even if we only use one of them. */
+private int
+show_cache_setup(gs_show_enum *penum)
+{ gs_state *pgs = penum->pgs;
+ gs_memory_t *mem = pgs->memory;
+ gx_device_memory *dev =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "show_cache_setup(dev_cache)");
+ gx_device_memory *dev2 =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "show_cache_setup(dev_cache2)");
+ if ( dev == 0 || dev2 == 0 )
+ { gs_free_object(mem, dev2, "show_cache_setup(dev_cache2)");
+ gs_free_object(mem, dev, "show_cache_setup(dev_cache)");
+ return_error(gs_error_VMerror);
+ }
+ /* We only initialize the device for the sake of the GC, */
+ /* (since we have to re-initialize it as either a mem_mono */
+ /* or a mem_abuf device before actually using it) and also */
+ /* to set its memory pointer. */
+ gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
+ penum->dev_cache = dev;
+ penum->dev_cache2 = dev2;
+ /* Initialize dev2 for the sake of the GC. */
+ *dev2 = *dev;
+ return 0;
+}
+
+/* Set the character origin as the origin of the coordinate system. */
+/* Used before rendering characters, and for moving the origin */
+/* in setcachedevice2 when WMode=1. */
+private int
+show_origin_setup(gs_state *pgs, fixed cpt_x, fixed cpt_y,
+ gs_char_path_mode charpath_flag)
+{ if ( charpath_flag == cpm_show )
+ { /* Round the translation in the graphics state. */
+ /* This helps prevent rounding artifacts later. */
+ cpt_x = fixed_rounded(cpt_x);
+ cpt_y = fixed_rounded(cpt_y);
+ }
+ /*
+ * BuildChar procedures expect the current point to be undefined,
+ * so we omit the gx_path_add_point with ctm.t*_fixed.
+ */
+ return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
+}
+
+/* Default fstack initialization procedure. */
+int
+gs_default_init_fstack(gs_show_enum *penum, gs_font *pfont)
+{ penum->fstack.depth = -1;
+ return 0;
+}
+
+/* Default next-character procedure. */
+int
+gs_default_next_char(gs_show_enum *penum, gs_char *pchr)
+{ gs_glyph ignore_glyph;
+ return gs_default_next_glyph(penum, pchr, &ignore_glyph);
+}
+
+/* Default next-glyph procedure. */
+int
+gs_default_next_glyph(gs_show_enum *penum, gs_char *pchr, gs_glyph *pglyph)
+{ if ( penum->index == penum->str.size )
+ return 2;
+ *pchr = penum->str.data[penum->index++];
+ *pglyph = gs_no_glyph;
+ return 0;
+}
diff --git a/gs/src/gschar.h b/gs/src/gschar.h
new file mode 100644
index 000000000..466457575
--- /dev/null
+++ b/gs/src/gschar.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gschar.h */
+/* Client interface to character operations */
+#include "gsccode.h"
+#include "gscpm.h"
+
+/* String display, like image display, uses an enumeration structure */
+/* to keep track of what's going on (aka 'poor man's coroutine'). */
+#ifndef gs_show_enum_DEFINED
+# define gs_show_enum_DEFINED
+typedef struct gs_show_enum_s gs_show_enum;
+#endif
+
+/* Define an opaque type for fonts if necessary. */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+#endif
+
+/* Allocate an enumerator. */
+gs_show_enum *gs_show_enum_alloc(P3(gs_memory_t *, gs_state *, client_name_t));
+/* Release the contents of an enumerator. */
+/* (This happens automatically if the enumeration finishes normally.) */
+/* If the second argument is not NULL, also free the enumerator. */
+void gs_show_enum_release(P2(gs_show_enum *, gs_memory_t *));
+
+/* The initialization routines all come in two versions, */
+/* one that uses the C convention of null-terminated strings, */
+/* and one that supplies a length. */
+int gs_show_init(P3(gs_show_enum *, gs_state *, const char *)),
+ gs_show_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_ashow_init(P5(gs_show_enum *, gs_state *, floatp, floatp, const char *)),
+ gs_ashow_n_init(P6(gs_show_enum *, gs_state *, floatp, floatp, const char *, uint)),
+ gs_widthshow_init(P6(gs_show_enum *, gs_state *, floatp, floatp, gs_char, const char *)),
+ gs_widthshow_n_init(P7(gs_show_enum *, gs_state *, floatp, floatp, gs_char, const char *, uint)),
+ gs_awidthshow_init(P8(gs_show_enum *, gs_state *, floatp, floatp, gs_char, floatp, floatp, const char *)),
+ gs_awidthshow_n_init(P9(gs_show_enum *, gs_state *, floatp, floatp, gs_char, floatp, floatp, const char *, uint)),
+ gs_kshow_init(P3(gs_show_enum *, gs_state *, const char *)),
+ gs_kshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_xyshow_init(P3(gs_show_enum *, gs_state *, const char *)),
+ gs_xyshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_glyphshow_init(P3(gs_show_enum *, gs_state *, gs_glyph)),
+ gs_cshow_init(P3(gs_show_enum *, gs_state *, const char *)),
+ gs_cshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_stringwidth_init(P3(gs_show_enum *, gs_state *, const char *)),
+ gs_stringwidth_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_charpath_init(P4(gs_show_enum *, gs_state *, const char *, bool)),
+ gs_charpath_n_init(P5(gs_show_enum *, gs_state *, const char *, uint, bool)),
+ gs_glyphpath_init(P4(gs_show_enum *, gs_state *, gs_glyph, bool)),
+ gs_charboxpath_init(P4(gs_show_enum *, gs_state *, const char *, bool)),
+ gs_charboxpath_n_init(P5(gs_show_enum *, gs_state *, const char *, uint, bool));
+
+/* After setting up the enumeration, all the string-related routines */
+/* work the same way. The client calls gs_show_next until it returns */
+/* a zero (successful completion) or negative (error) value. */
+/* Other values indicate the following situations: */
+
+ /* The client must render a character: obtain the code from */
+ /* gs_show_current_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_render 1
+
+ /* The client has asked to intervene between characters (kshow). */
+ /* Obtain the previous and next codes from gs_kshow_previous_char */
+ /* and gs_kshow_next_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_kern 2
+
+ /* The client has asked to handle characters individually */
+ /* (xshow, yshow, xyshow, cshow). Obtain the current code */
+ /* from gs_show_current_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_move 3
+
+int gs_show_next(P1(gs_show_enum *));
+gs_char
+ gs_show_current_char(P1(const gs_show_enum *)),
+ gs_kshow_previous_char(P1(const gs_show_enum *)),
+ gs_kshow_next_char(P1(const gs_show_enum *));
+gs_font *
+ gs_show_current_font(P1(const gs_show_enum *));
+int gs_show_restore_font(P1(const gs_show_enum *));
+gs_glyph
+ gs_show_current_glyph(P1(const gs_show_enum *));
+int gs_show_current_width(P2(const gs_show_enum *, gs_point *));
+void gs_show_width(P2(const gs_show_enum *, gs_point *)); /* cumulative width */
+gs_char_path_mode
+ gs_show_in_charpath(P1(const gs_show_enum *)); /* return charpath flag */
+
+/* Character cache and metrics operators. */
+/* gs_setcachedevice* return 1 iff the cache device was just installed. */
+int gs_setcachedevice_float(P3(gs_show_enum *, gs_state *, const float * /*[6]*/));
+int gs_setcachedevice_double(P3(gs_show_enum *, gs_state *, const double * /*[6]*/));
+#define gs_setcachedevice(penum, pgs, pw)\
+ gs_setcachedevice_float(penum, pgs, pw)
+int gs_setcachedevice2_float(P3(gs_show_enum *, gs_state *, const float * /*[10]*/));
+int gs_setcachedevice2_double(P3(gs_show_enum *, gs_state *, const double * /*[10]*/));
+#define gs_setcachedevice2(penum, pgs, pw2)\
+ gs_setcachedevice2_float(penum, pgs, pw2)
+int gs_setcharwidth(P4(gs_show_enum *, gs_state *, floatp, floatp));
+/* Return true if we only need the width from the rasterizer */
+/* and can short-circuit the full rendering of the character, */
+/* false if we need the actual character bits. */
+/* This is only meaningful just before calling gs_setcharwidth or */
+/* gs_setcachedevice[2]. */
+bool gs_show_width_only(P1(const gs_show_enum *));
diff --git a/gs/src/gschar0.c b/gs/src/gschar0.c
new file mode 100644
index 000000000..c0ff80da7
--- /dev/null
+++ b/gs/src/gschar0.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 1991, 1992, 1993, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gschar0.c */
+/* Composite font decoding for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsfcmap.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxchar.h */
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+
+/* Stack up modal composite fonts, down to a non-modal or base font. */
+private int
+gs_stack_modal_fonts(gs_show_enum *penum)
+{ int fdepth = penum->fstack.depth;
+ gs_font *cfont = penum->fstack.items[fdepth].font;
+#define cmfont ((gs_font_type0 *)cfont)
+ while ( cfont->FontType == ft_composite &&
+ fmap_type_is_modal(cmfont->data.FMapType)
+ )
+ { if ( fdepth == max_font_depth )
+ return_error(gs_error_invalidfont);
+ fdepth++;
+ cfont = cmfont->data.FDepVector[cmfont->data.Encoding[0]];
+ penum->fstack.items[fdepth].font = cfont;
+ penum->fstack.items[fdepth].index = 0;
+ if_debug2('j', "[j]stacking depth=%d font=0x%lx\n",
+ fdepth, (ulong)cfont);
+ }
+ penum->fstack.depth = fdepth;
+ return 0;
+#undef cmfont
+}
+/* Initialize the composite font stack for a show enumerator. */
+int
+gs_type0_init_fstack(gs_show_enum *penum, gs_font *pfont)
+{ if_debug1('j', "[j]stacking depth=0 font=0x%lx\n",
+ (ulong)pfont);
+ penum->fstack.depth = 0;
+ penum->fstack.items[0].font = pfont;
+ penum->fstack.items[0].index = 0;
+ return gs_stack_modal_fonts(penum);
+}
+
+/* Select the appropriate descendant of a font. */
+/* Uses free variables: penum. */
+/* Uses pdata, uses & updates fdepth, sets pfont. */
+#define select_descendant(pfont, pdata, fidx, fdepth)\
+ if ( fidx >= pdata->encoding_size )\
+ return_error(gs_error_rangecheck);\
+ if ( fdepth == max_font_depth )\
+ return_error(gs_error_invalidfont);\
+ pfont = pdata->FDepVector[pdata->Encoding[fidx]];\
+ if ( ++fdepth > orig_depth || pfont != penum->fstack.items[fdepth].font )\
+ penum->fstack.items[fdepth].font = pfont,\
+ changed = 1;\
+ penum->fstack.items[fdepth].index = fidx
+
+/* Get the next character or glyph from a composite string. */
+/* If we run off the end of the string in the middle of a */
+/* multi-byte sequence, return gs_error_rangecheck. */
+/* If the string is empty, return 2. */
+/* If the current (base) font changed, return 1. Otherwise, return 0. */
+int
+gs_type0_next_glyph(register gs_show_enum *penum, gs_char *pchr,
+ gs_glyph *pglyph)
+{ const byte *str = penum->str.data;
+ const byte *p = str + penum->index;
+ const byte *end = str + penum->str.size;
+ int fdepth = penum->fstack.depth;
+ int orig_depth = fdepth;
+ gs_font *pfont;
+#define pfont0 ((gs_font_type0 *)pfont)
+ gs_type0_data *pdata;
+ uint fidx;
+ gs_char chr;
+ gs_glyph glyph = gs_no_glyph;
+ int changed = 0;
+#define need_left(n)\
+ if ( end - p < n ) return_error(gs_error_rangecheck)
+#define root_EscChar\
+ (((gs_font_type0 *)(penum->fstack.items[0].font))->data.EscChar) /* root overrides */
+
+ /*
+ * Although the Adobe documentation doesn't say anything about this,
+ * if the root font is modal and the very first character of the
+ * string being decoded is an escape or shift character, then
+ * font selection via the escape mechanism works down from the root,
+ * rather than up from the lowest modal font. (This was first
+ * reported by Norio Katayama, and confirmed by someone at Adobe.)
+ */
+
+ if ( penum->index == 0 )
+ { int idepth = 0;
+ pfont = penum->fstack.items[0].font;
+ for ( ; pfont->FontType == ft_composite; )
+ { fmap_type fmt = (pdata = &pfont0->data)->FMapType;
+ if ( p == end )
+ return 2;
+ chr = *p;
+ switch ( fmt )
+ {
+ case fmap_escape:
+ if ( chr != root_EscChar )
+ break;
+ need_left(2);
+ fidx = p[1];
+ p += 2;
+ if_debug1('j', "[j]from root: escape %d\n", fidx);
+rdown: select_descendant(pfont, pdata, fidx, idepth);
+ if_debug2('j', "[j]... new depth=%d, new font=0x%lx\n",
+ idepth, (ulong)pfont);
+ continue;
+ case fmap_double_escape:
+ if ( chr != root_EscChar )
+ break;
+ need_left(2);
+ fidx = p[1];
+ p += 2;
+ if ( fidx == chr )
+ { need_left(1);
+ fidx = *p++ + 256;
+ }
+ if_debug1('j', "[j]from root: double escape %d\n", fidx);
+ goto rdown;
+ case fmap_shift:
+ if ( chr == pdata->ShiftIn )
+ fidx = 0;
+ else if ( chr == pdata->ShiftOut )
+ fidx = 1;
+ else break;
+ p++;
+ if_debug1('j', "[j]from root: shift %d\n", fidx);
+ goto rdown;
+ default:
+ break;
+ }
+ break;
+ }
+ /* If we saw any initial escapes or shifts, */
+ /* compute a new initial base font. */
+ if ( idepth != 0 )
+ { int code;
+ penum->fstack.depth = idepth;
+ code = gs_stack_modal_fonts(penum);
+ if ( code < 0 )
+ return code;
+ if ( penum->fstack.depth > idepth )
+ changed = 1;
+ orig_depth = fdepth = penum->fstack.depth;
+ }
+ }
+
+ /* Handle initial escapes or shifts. */
+
+up: if ( p == end )
+ return 2;
+ chr = *p;
+ while ( fdepth > 0 )
+ { pfont = penum->fstack.items[fdepth - 1].font;
+ pdata = &pfont0->data;
+ switch ( pdata->FMapType )
+ {
+ default: /* non-modal */
+ fdepth--;
+ continue;
+
+ case fmap_escape:
+ if ( chr != root_EscChar )
+ break;
+ need_left(2);
+ fidx = *++p;
+ if_debug1('j', "[j]next: escape %d\n", fidx);
+ /* Per Adobe, if we get an escape at the root, */
+ /* treat it as an ordinary character (font index). */
+ if ( fidx == chr && fdepth > 1 )
+ { fdepth--;
+ goto up;
+ }
+down: if ( ++p == end )
+ return 2;
+ chr = *p;
+ fdepth--;
+ do
+ { select_descendant(pfont, pdata, fidx, fdepth);
+ if_debug3('j', "[j]down from modal: new depth=%d, index=%d, new font=0x%lx\n",
+ fdepth, fidx, (ulong)pfont);
+ if ( pfont->FontType != ft_composite )
+ break;
+ pdata = &pfont0->data;
+ fidx = 0;
+ }
+ while ( pdata->FMapType == fmap_escape );
+ continue;
+
+ case fmap_double_escape:
+ if ( chr != root_EscChar )
+ break;
+ need_left(2);
+ fidx = *++p;
+ if ( fidx == chr )
+ { need_left(2);
+ fidx = *++p + 256;
+ }
+ if_debug1('j', "[j]next: double escape %d\n", fidx);
+ goto down;
+
+ case fmap_shift:
+ if ( chr == pdata->ShiftIn )
+ fidx = 0;
+ else if ( chr == pdata->ShiftOut )
+ fidx = 1;
+ else break;
+ if_debug1('j', "[j]next: shift %d\n", fidx);
+ goto down;
+ }
+ break;
+ }
+ /* At this point, chr == *p. */
+ /* (This is important to know for CMap'ed fonts.) */
+ p++;
+
+ /*
+ * Now handle non-modal descendants.
+ * The PostScript language manual has some confusing
+ * wording about the parent supplying the "first part"
+ * of the child's decoding information; what this means
+ * is not (as one might imagine) the font index, but
+ * simply the first byte of the data.
+ */
+
+ while ( (pfont = penum->fstack.items[fdepth].font)->FontType == ft_composite )
+ { pdata = &pfont0->data;
+ switch ( pdata->FMapType )
+ {
+ default: /* can't happen */
+ return_error(gs_error_invalidfont);
+
+ case fmap_8_8:
+ need_left(1);
+ fidx = chr;
+ chr = *p++;
+ if_debug2('J', "[J]8/8 index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+
+ case fmap_1_7:
+ fidx = chr >> 7;
+ chr &= 0x7f;
+ if_debug2('J', "[J]1/7 index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+
+ case fmap_9_7:
+ need_left(1);
+ fidx = ((uint)chr << 1) + (*p >> 7);
+ chr = *p & 0x7f;
+ if_debug2('J', "[J]9/7 index=%d, char=%ld\n",
+ fidx, chr);
+ p++;
+ break;
+
+ case fmap_SubsVector:
+ { int width = pdata->subs_width;
+ uint subs_count = pdata->subs_size;
+ const byte *psv = pdata->SubsVector.data;
+#define subs_loop(subs_elt, width)\
+ while ( subs_count != 0 && tchr >= (schr = subs_elt) )\
+ subs_count--, tchr -= schr, psv += width;\
+ chr = tchr; p += width - 1; break
+
+ switch ( width )
+ {
+ default: /* can't happen */
+ return_error(gs_error_invalidfont);
+ case 1:
+ { byte tchr = (byte)chr, schr;
+ subs_loop(*psv, 1);
+ }
+ case 2:
+ need_left(1);
+#define w2(p) (((ushort)*p << 8) + p[1])
+ { ushort tchr = ((ushort)chr << 8) + *p, schr;
+ subs_loop(w2(psv), 2);
+ }
+ case 3:
+ need_left(2);
+#define w3(p) (((ulong)*p << 16) + ((uint)p[1] << 8) + p[2])
+ { ulong tchr = ((ulong)chr << 16) + w2(p), schr;
+ subs_loop(w3(psv), 3);
+ }
+ case 4:
+ need_left(3);
+#define w4(p) (((ulong)*p << 24) + ((ulong)p[1] << 16) + ((uint)p[2] << 8) + p[3])
+ { ulong tchr = ((ulong)chr << 24) + w3(p), schr;
+ subs_loop(w4(psv), 4);
+ }
+#undef w2
+#undef w3
+#undef w4
+#undef subs_loop
+ }
+ fidx = pdata->subs_size - subs_count;
+ if_debug2('J', "[J]SubsVector index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+ }
+
+ case fmap_CMap:
+ { gs_const_string cstr;
+ uint mindex = p - str - 1; /* p was incremented */
+ int code;
+
+ cstr.data = str;
+ cstr.size = end - str;
+ code = gs_cmap_decode_next(pdata->CMap, &cstr, &mindex,
+ &fidx, &glyph);
+ if ( code < 0 )
+ return code;
+ p = str + mindex;
+ if_debug2('J', "[J]CMap returns %d, glyph=0x%lx\n",
+ code, (ulong)glyph);
+ if ( code == 0 )
+ { chr = gs_no_char;
+ if ( glyph == gs_no_glyph )
+ glyph = gs_min_cid_glyph;
+ }
+ else
+ chr = (gs_char)glyph, glyph = gs_no_glyph;
+ /****** RESCAN chr IF DESCENDANT IS CMAP'ED ******/
+ break;
+ }
+
+ }
+
+ select_descendant(pfont, pdata, fidx, fdepth);
+ if_debug2('J', "... new depth=%d, new font=0x%lx\n",
+ fdepth, (ulong)pfont);
+ }
+ *pchr = chr;
+ *pglyph = glyph;
+ /* Update the pointer into the original string, but only if */
+ /* we didn't switch over to parsing a code from a CMap. */
+ if ( str == penum->str.data )
+ penum->index = p - str;
+ penum->fstack.depth = fdepth;
+ if_debug4('J', "[J]depth=%d font=0x%lx index=%d changed=%d\n",
+ fdepth, (ulong)penum->fstack.items[fdepth].font,
+ penum->fstack.items[fdepth].index, changed);
+ return changed;
+#undef pfont0
+}
diff --git a/gs/src/gscie.c b/gs/src/gscie.c
new file mode 100644
index 000000000..e99dfc3e1
--- /dev/null
+++ b/gs/src/gscie.c
@@ -0,0 +1,1189 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscie.c */
+/* CIE color rendering for Ghostscript */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscie.h"
+#include "gxarith.h"
+#include "gxdevice.h" /* for gxcmap.h */
+#include "gxcmap.h"
+#include "gzstate.h"
+
+/* Forward references */
+private void cie_joint_caches_init(P3(gx_cie_joint_caches *,
+ const gs_cie_common *, const gs_cie_render *));
+private void cie_joint_caches_complete(P3(gx_cie_joint_caches *,
+ const gs_cie_common *, const gs_cie_render *));
+private void near cie_mult3(P3(const gs_vector3 *, const gs_matrix3 *,
+ gs_vector3 *));
+private void near cie_matrix_mult3(P3(const gs_matrix3 *, const gs_matrix3 *,
+ gs_matrix3 *));
+private void near cie_invert3(P2(const gs_matrix3 *, gs_matrix3 *));
+private void near cie_matrix_init(P1(gs_matrix3 *));
+
+#define set_restrict_index(i, v, n)\
+ if ( (uint)(i = (int)(v)) >= (n) )\
+ i = (i < 0 ? 0 : (n) - 1)
+#define restrict_index(v, n, itemp)\
+ ((uint)(itemp = (int)(v)) >= (n) ?\
+ (itemp < 0 ? 0 : (n) - 1) : itemp)
+
+/* Compute a cache index as (vin - base) * factor. */
+/* vin, base, factor, and the result are cie_cached_values. */
+/* We know that the result doesn't exceed (gx_cie_cache_size - 1) << fbits. */
+#define lookup_index(vin, pcache, fbits)\
+ ((vin) <= (pcache)->vecs.params.base ? 0 :\
+ (vin) >= (pcache)->vecs.params.limit ? (gx_cie_cache_size - 1) << (fbits) :\
+ cie_cached_product2int( ((vin) - (pcache)->vecs.params.base),\
+ (pcache)->vecs.params.factor, fbits ))
+#define lookup_value(vin, pcache)\
+ ((pcache)->vecs.values[lookup_index(vin, pcache, 0)])
+
+#define if_restrict(v, range)\
+ if ( (v) < (range).rmin ) v = (range).rmin;\
+ else if ( (v) > (range).rmax ) v = (range).rmax
+
+/* Define the template for loading a cache. */
+/* If we had parameterized types, or a more flexible type system, */
+/* this could be done with a single procedure. */
+#define cie_cache_init3(pcache3, plp3, prange3, cname)\
+ gs_cie_cache_init(&(pcache3)->floats.params, &(plp3)[0], &(prange3)[0], cname);\
+ gs_cie_cache_init(&(pcache3)[1].floats.params, &(plp3)[1], &(prange3)[1], cname);\
+ gs_cie_cache_init(&(pcache3)[2].floats.params, &(plp3)[2], &(prange3)[2], cname)
+#define CIE_LOAD_CACHE3_BODY(pcache, domains, rprocs, pcie, cname)\
+{ int i, j;\
+ gs_for_loop_params lp[3];\
+ cie_cache_init3(pcache, lp, domains, cname);\
+ for ( i = 0; i < gx_cie_cache_size; i++ )\
+ for ( j = 0; j < 3; lp[j].init += lp[j].step, j++ )\
+ pcache[j].floats.values[i] =\
+ (*(rprocs)->procs[j])(lp[j].init, pcie);\
+}
+
+/* ================ Color space definition ================ */
+
+/* Allocator structure types */
+private_st_joint_caches();
+
+/* Define the CIE color space types. */
+/* We use CIExxx rather than CIEBasedxxx in some places because */
+/* gcc under VMS only retains 23 characters of procedure names, */
+/* and DEC C truncates all identifiers at 31 characters. */
+private cs_proc_concrete_space(gx_concrete_space_CIE);
+cs_declare_procs(private, gx_concretize_CIEDEFG, gx_install_CIEDEFG,
+ gx_adjust_cspace_CIEDEFG,
+ gx_enum_ptrs_CIEDEFG, gx_reloc_ptrs_CIEDEFG);
+cs_declare_procs(private, gx_concretize_CIEDEF, gx_install_CIEDEF,
+ gx_adjust_cspace_CIEDEF,
+ gx_enum_ptrs_CIEDEF, gx_reloc_ptrs_CIEDEF);
+private cs_proc_remap_color(gx_remap_CIEABC);
+cs_declare_procs(private, gx_concretize_CIEABC, gx_install_CIEABC,
+ gx_adjust_cspace_CIEABC,
+ gx_enum_ptrs_CIEABC, gx_reloc_ptrs_CIEABC);
+cs_declare_procs(private, gx_concretize_CIEA, gx_install_CIEA,
+ gx_adjust_cspace_CIEA,
+ gx_enum_ptrs_CIEA, gx_reloc_ptrs_CIEA);
+const gs_color_space_type
+ gs_color_space_type_CIEDEFG =
+ { gs_color_space_index_CIEDEFG, 3, true,
+ gx_init_paint_3, gx_concrete_space_CIE,
+ gx_concretize_CIEDEFG, NULL,
+ gx_default_remap_color, gx_install_CIEDEFG,
+ gx_adjust_cspace_CIEDEFG, gx_no_adjust_color_count,
+ gx_enum_ptrs_CIEDEFG, gx_reloc_ptrs_CIEDEFG
+ },
+ gs_color_space_type_CIEDEF =
+ { gs_color_space_index_CIEDEF, 3, true,
+ gx_init_paint_3, gx_concrete_space_CIE,
+ gx_concretize_CIEDEF, NULL,
+ gx_default_remap_color, gx_install_CIEDEF,
+ gx_adjust_cspace_CIEDEF, gx_no_adjust_color_count,
+ gx_enum_ptrs_CIEDEF, gx_reloc_ptrs_CIEDEF
+ },
+ gs_color_space_type_CIEABC =
+ { gs_color_space_index_CIEABC, 3, true,
+ gx_init_paint_3, gx_concrete_space_CIE,
+ gx_concretize_CIEABC, NULL,
+ gx_remap_CIEABC, gx_install_CIEABC,
+ gx_adjust_cspace_CIEABC, gx_no_adjust_color_count,
+ gx_enum_ptrs_CIEABC, gx_reloc_ptrs_CIEABC
+ },
+ gs_color_space_type_CIEA =
+ { gs_color_space_index_CIEA, 1, true,
+ gx_init_paint_1, gx_concrete_space_CIE,
+ gx_concretize_CIEA, NULL,
+ gx_default_remap_color, gx_install_CIEA,
+ gx_adjust_cspace_CIEA, gx_no_adjust_color_count,
+ gx_enum_ptrs_CIEA, gx_reloc_ptrs_CIEA
+ };
+
+/* GC procedures for CIE color spaces. */
+/* These have to come after the cs_declare_procs because of */
+/* a bug in the VAX C compiler. */
+
+#define pcs ((gs_color_space *)vptr)
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_CIEDEFG) return 0;
+ ENUM_PTR(0, gs_color_space, params.defg);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_CIEDEFG) {
+ RELOC_PTR(gs_color_space, params.defg);
+} RELOC_PTRS_END
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_CIEDEF) return 0;
+ ENUM_PTR(0, gs_color_space, params.def);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_CIEDEF) {
+ RELOC_PTR(gs_color_space, params.def);
+} RELOC_PTRS_END
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_CIEABC) return 0;
+ ENUM_PTR(0, gs_color_space, params.abc);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_CIEABC) {
+ RELOC_PTR(gs_color_space, params.abc);
+} RELOC_PTRS_END
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_CIEA) return 0;
+ ENUM_PTR(0, gs_color_space, params.a);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_CIEA) {
+ RELOC_PTR(gs_color_space, params.a);
+} RELOC_PTRS_END
+
+#undef pcs
+
+/* ------ Default values for CIE dictionary elements ------ */
+
+/* Default transformation procedures. */
+
+private float
+a_identity(floatp in, const gs_cie_a *pcie)
+{ return in;
+}
+private float
+abc_identity(floatp in, const gs_cie_abc *pcie)
+{ return in;
+}
+private float
+def_identity(floatp in, const gs_cie_def *pcie)
+{ return in;
+}
+private float
+defg_identity(floatp in, const gs_cie_defg *pcie)
+{ return in;
+}
+private float
+common_identity(floatp in, const gs_cie_common *pcie)
+{ return in;
+}
+private float
+render_identity(floatp in, const gs_cie_render *pcie)
+{ return in;
+}
+private float
+tpqr_identity(floatp in, const gs_cie_wbsd *pwbsd, const gs_cie_render *pcie)
+{ return in;
+}
+private frac
+render_table_identity(byte in, const gs_cie_render *pcie)
+{ return byte2frac(in);
+}
+
+/* Default vectors and matrices. */
+
+const gs_range3 Range3_default = { {{0,1}, {0,1}, {0,1}} };
+const gs_range4 Range4_default = { {{0,1}, {0,1}, {0,1}, {0,1}} };
+const gs_cie_defg_proc4 DecodeDEFG_default =
+ { { defg_identity, defg_identity, defg_identity, defg_identity } };
+const gs_cie_def_proc3 DecodeDEF_default =
+ { { def_identity, def_identity, def_identity } };
+const gs_cie_abc_proc3 DecodeABC_default =
+ { { abc_identity, abc_identity, abc_identity } };
+const gs_cie_common_proc3 DecodeLMN_default =
+ { { common_identity, common_identity, common_identity } };
+const gs_matrix3 Matrix3_default = { {1,0,0}, {0,1,0}, {0,0,1}, 1 /*true*/ };
+const gs_range RangeA_default = {0,1};
+const gs_cie_a_proc DecodeA_default = a_identity;
+const gs_vector3 MatrixA_default = { 1, 1, 1 };
+const gs_vector3 BlackPoint_default = { 0, 0, 0 };
+const gs_cie_render_proc3 Encode_default =
+ { { render_identity, render_identity, render_identity } };
+const gs_cie_transform_proc3 TransformPQR_default =
+ { { tpqr_identity, tpqr_identity, tpqr_identity } };
+const gs_cie_render_table_procs RenderTableT_default =
+ { { render_table_identity, render_table_identity, render_table_identity,
+ render_table_identity
+ } };
+
+/* ------ Adjust reference counts for a CIE color space ------ */
+
+private void
+gx_adjust_cspace_CIEDEFG(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ rc_adjust_const(pcs->params.defg, delta, "gx_adjust_cspace_CIEDEFG");
+}
+
+private void
+gx_adjust_cspace_CIEDEF(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ rc_adjust_const(pcs->params.def, delta, "gx_adjust_cspace_CIEDEF");
+}
+
+private void
+gx_adjust_cspace_CIEABC(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ rc_adjust_const(pcs->params.abc, delta, "gx_adjust_cspace_CIEABC");
+}
+
+private void
+gx_adjust_cspace_CIEA(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ rc_adjust_const(pcs->params.a, delta, "gx_adjust_cspace_CIEA");
+}
+
+/* ================ Table setup ================ */
+
+/* ------ Install a CIE color space ------ */
+
+private int cie_load_common_cache(P3(gs_cie_common *, gs_state *,
+ client_name_t));
+private void near cie_cache_mult(P3(gx_cie_vector_cache *, const gs_vector3 *,
+ const cie_cache_floats *));
+private bool near cie_cache_mult3(P2(gx_cie_vector_cache *,
+ const gs_matrix3 *));
+
+private int
+gx_install_CIEDEFG(gs_color_space *pcs, gs_state *pgs)
+{ /****** NOT IMPLEMENTED YET ******/
+ return_error(gs_error_undefined);
+}
+
+private int
+gx_install_CIEDEF(gs_color_space *pcs, gs_state *pgs)
+{ /****** NOT IMPLEMENTED YET ******/
+ return_error(gs_error_undefined);
+}
+
+private int
+gx_install_CIEABC(gs_color_space *pcs, gs_state *pgs)
+{ gs_cie_abc *pcie = pcs->params.abc;
+ cie_matrix_init(&pcie->MatrixABC);
+ CIE_LOAD_CACHE3_BODY(pcie->caches.DecodeABC, pcie->RangeABC.ranges,
+ &pcie->DecodeABC, pcie, "DecodeABC");
+ gs_cie_abc_complete(pcie);
+ return cie_load_common_cache(&pcie->common, pgs, "gx_install_CIEABC");
+}
+
+private int
+gx_install_CIEA(gs_color_space *pcs, gs_state *pgs)
+{ gs_cie_a *pcie = pcs->params.a;
+ int i;
+ gs_for_loop_params lp;
+ float in;
+ gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp,
+ &pcie->RangeA, "DecodeA");
+ for ( i = 0, in = lp.init; i < gx_cie_cache_size; in += lp.step, i++ )
+ pcie->caches.DecodeA.floats.values[i] =
+ (*pcie->DecodeA)(in, pcie);
+ gs_cie_a_complete(pcie);
+ return cie_load_common_cache(&pcie->common, pgs, "gx_install_CIEA");
+}
+
+/* Load the common caches when installing the color space. */
+private int
+cie_load_common_cache(gs_cie_common *pcie, gs_state *pgs, client_name_t cname)
+{ gx_cie_joint_caches *pjc;
+
+ cie_matrix_init(&pcie->MatrixLMN);
+ CIE_LOAD_CACHE3_BODY(pcie->caches.DecodeLMN, pcie->RangeLMN.ranges,
+ &pcie->DecodeLMN, pcie, "DecodeLMN")
+ if ( pgs->cie_render == 0 )
+ return 0;
+ pjc = gx_currentciecaches(pgs);
+ if ( pjc == 0 )
+ return_error(gs_error_VMerror);
+ cie_joint_caches_init(pjc, pcie, pgs->cie_render);
+ cie_joint_caches_complete(pjc, pcie, pgs->cie_render);
+ return 0;
+}
+
+/* Complete loading a CIEBasedABC color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_abc_complete(gs_cie_abc *pcie)
+{ pcie->caches.skipABC =
+ cie_cache_mult3(pcie->caches.DecodeABC, &pcie->MatrixABC);
+}
+
+/* Complete loading a CIEBasedA color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_a_complete(gs_cie_a *pcie)
+{ cie_cache_mult(&pcie->caches.DecodeA, &pcie->MatrixA,
+ &pcie->caches.DecodeA.floats);
+}
+
+/* Convert a scalar cache to a vector cache by multiplying */
+/* the scalar values by a vector. */
+private void near
+cie_cache_mult(gx_cie_vector_cache *pcache, const gs_vector3 *pvec,
+ const cie_cache_floats *pcf)
+{ int i;
+ cie_vector_cache_params params;
+ params.is_identity = pcf->params.is_identity;
+ params.base = float2cie_cached(pcf->params.base);
+ params.factor = float2cie_cached(pcf->params.factor);
+ params.limit =
+ float2cie_cached((gx_cie_cache_size - 1) / pcf->params.factor +
+ pcf->params.base);
+ /* Loop from top to bottom so that we don't */
+ /* overwrite elements before they're used, */
+ /* in case pcf is an alias for pcache->floats. */
+ for ( i = gx_cie_cache_size; --i >= 0; )
+ { float f = pcf->values[i];
+ pcache->vecs.values[i].u = float2cie_cached(f * pvec->u);
+ pcache->vecs.values[i].v = float2cie_cached(f * pvec->v);
+ pcache->vecs.values[i].w = float2cie_cached(f * pvec->w);
+ }
+ pcache->vecs.params = params;
+}
+/* Convert 3 scalar caches to vector caches by multiplying by a matrix. */
+/* Return true iff the resulting cache is an identity transformation. */
+private bool near
+cie_cache_mult3(gx_cie_vector_cache *pc /*[3]*/, const gs_matrix3 *pmat)
+{ cie_cache_mult(pc, &pmat->cu, &pc->floats);
+ cie_cache_mult(pc + 1, &pmat->cv, &pc[1].floats);
+ cie_cache_mult(pc + 2, &pmat->cw, &pc[2].floats);
+ return pmat->is_identity & pc[0].vecs.params.is_identity &
+ pc[1].vecs.params.is_identity & pc[2].vecs.params.is_identity;
+}
+
+/* ------ Install a rendering dictionary ------ */
+
+/* setcolorrendering */
+int
+gs_setcolorrendering(gs_state *pgs, gs_cie_render *pcie)
+{ int code = gs_cie_render_init(pcie);
+ if ( code < 0 )
+ return code;
+ rc_assign(pgs->cie_render, pcie, "gs_setcolorrendering");
+ /* Load the caches. */
+ CIE_LOAD_CACHE3_BODY(pcie->caches.EncodeLMN, pcie->DomainLMN.ranges,
+ &pcie->EncodeLMN, pcie, "EncodeLMN");
+ CIE_LOAD_CACHE3_BODY(pcie->caches.EncodeABC, pcie->DomainABC.ranges,
+ &pcie->EncodeABC, pcie, "EncodeABC");
+ if ( pcie->RenderTable.lookup.table != 0 )
+ { int i, j, m = pcie->RenderTable.lookup.m;
+ gs_for_loop_params flp;
+ for ( j = 0; j < m; j++ )
+ gs_cie_cache_init(&pcie->caches.RenderTableT[j].fracs.params,
+ &flp, &Range3_default.ranges[0],
+ "RenderTableT");
+ /****** ASSUMES gx_cie_cache_size >= 256 ******/
+ for ( i = 0; i < 256; i++ )
+ for ( j = 0; j < m; j++ )
+ pcie->caches.RenderTableT[j].fracs.values[i] =
+ (*pcie->RenderTable.T.procs[j])((byte)i, pcie);
+ }
+ code = gs_cie_render_complete(pcie);
+ if ( code < 0 )
+ return code;
+ /* Initialize the joint caches if needed. */
+ gs_cie_cs_complete(pgs, true);
+ gx_unset_dev_color(pgs);
+ return code;
+}
+
+/* currentcolorrendering */
+const gs_cie_render *
+gs_currentcolorrendering(const gs_state *pgs)
+{ return pgs->cie_render;
+}
+
+/* Unshare (allocating if necessary) the joint caches. */
+gx_cie_joint_caches *
+gx_currentciecaches(gs_state *pgs)
+{ rc_unshare_struct(pgs->cie_joint_caches, gx_cie_joint_caches,
+ &st_joint_caches, pgs->memory,
+ return 0, "gx_currentciecaches");
+ return pgs->cie_joint_caches;
+}
+
+/* ------ Compute the parameters for loading a cache. ------ */
+/* Sets base and factor. */
+
+void
+gs_cie_cache_init(cie_cache_params *pcache, gs_for_loop_params *pflp,
+ const gs_range *domain, client_name_t cname)
+{ /*
+ * We need to map the values in the range
+ * [domain->rmin..domain->rmax]. However, if neither rmin
+ * nor rmax is zero and the function is non-linear,
+ * this can lead to anomalies at zero, which is the
+ * default value for CIE colors. The "correct" way to
+ * approach this is to run the mapping functions on demand,
+ * but we don't want to deal with the complexities of the
+ * callbacks this would involve (especially in the middle of
+ * rendering images); instead, we adjust the range so that zero
+ * maps precisely to a cache slot. Define:
+ * a = domain->rmin;
+ * b = domain->rmax;
+ * R = b - a;
+ * N = gx_cie_cache_size - 1;
+ * f(v) = N(v-a)/R;
+ * x = f(0).
+ * If x is not an integer, we can either increase b or
+ * decrease a to make it one. In the former case, compute:
+ * Kb = floor(x); R'b = N(0-a)/Kb; b' = a + R'b.
+ * In the latter case, compute:
+ * Ka = ceiling(x-N); R'a = N(0-b)/Ka; a' = b - R'a.
+ * We choose whichever method stretches the range the least,
+ * i.e., the one whose R' value (R'a or R'b) is smaller.
+ */
+ double a = domain->rmin, b = domain->rmax;
+ double R = b - a;
+#define N (gx_cie_cache_size - 1)
+ double delta;
+ /* Adjust the range if necessary. */
+ if ( a < 0 && b >= 0 )
+ { double x = -N * a / R; /* must be > 0 */
+ double Kb = floor(x); /* must be >= 0 */
+ double Ka = ceil(x) - N; /* must be <= 0 */
+ if ( Kb == 0 || (Ka != 0 && -b / Ka < -a / Kb) ) /* use R'a */
+ R = -N * b / Ka, a = b - R;
+ else /* use R'b */
+ R = -N * a / Kb, b = a + R;
+ }
+ delta = R / N;
+#ifdef CIE_CACHE_INTERPOLATE
+ pcache->base = a; /* no rounding */
+#else
+ pcache->base = a - delta / 2; /* so lookup will round */
+#endif
+ pcache->factor = (delta == 0 ? 0 : N / R);
+ if_debug4('c', "[c]cache %s 0x%lx base=%g, factor=%g\n",
+ (const char *)cname, (ulong)pcache,
+ pcache->base, pcache->factor);
+ pflp->init = a;
+ pflp->step = delta;
+ pflp->limit = b + delta / 2;
+}
+
+/* ------ Complete a rendering structure ------ */
+
+/* Compute values derived from the rendering structure parameters */
+/* other than the cached procedure values. This routine is idempotent. */
+private void near cie_transform_range3(P3(const gs_range3 *,
+ const gs_matrix3 *, gs_range3 *));
+int
+gs_cie_render_init(gs_cie_render *pcie)
+{ gs_matrix3 PQR_inverse;
+ cie_matrix_init(&pcie->MatrixLMN);
+ cie_matrix_init(&pcie->MatrixABC);
+ cie_matrix_init(&pcie->MatrixPQR);
+ cie_invert3(&pcie->MatrixPQR, &PQR_inverse);
+ cie_matrix_mult3(&pcie->MatrixLMN, &PQR_inverse,
+ &pcie->MatrixPQR_inverse_LMN);
+ cie_transform_range3(&pcie->RangePQR, &pcie->MatrixPQR_inverse_LMN,
+ &pcie->DomainLMN);
+ cie_transform_range3(&pcie->RangeLMN, &pcie->MatrixABC,
+ &pcie->DomainABC);
+ cie_mult3(&pcie->points.WhitePoint, &pcie->MatrixPQR, &pcie->wdpqr);
+ cie_mult3(&pcie->points.BlackPoint, &pcie->MatrixPQR, &pcie->bdpqr);
+ return 0;
+}
+
+/* Transform a set of ranges. */
+private void near
+cie_transform_range(const gs_range3 *in, floatp mu, floatp mv, floatp mw,
+ gs_range *out)
+{ float umin = mu * in->ranges[0].rmin,
+ umax = mu * in->ranges[0].rmax;
+ float vmin = mv * in->ranges[1].rmin,
+ vmax = mv * in->ranges[1].rmax;
+ float wmin = mw * in->ranges[2].rmin,
+ wmax = mw * in->ranges[2].rmax;
+ float temp;
+#define swap(x, y) temp = x, x = y, y = temp
+
+ if ( umin > umax ) swap(umin, umax);
+ if ( vmin > vmax ) swap(vmin, vmax);
+ if ( wmin > wmax ) swap(wmin, wmax);
+ out->rmin = umin + vmin + wmin;
+ out->rmax = umax + vmax + wmax;
+#undef swap
+}
+private void near
+cie_transform_range3(const gs_range3 *in, const gs_matrix3 *mat,
+ gs_range3 *out)
+{ cie_transform_range(in, mat->cu.u, mat->cv.u, mat->cw.u,
+ &out->ranges[0]);
+ cie_transform_range(in, mat->cu.v, mat->cv.v, mat->cw.v,
+ &out->ranges[1]);
+ cie_transform_range(in, mat->cu.w, mat->cv.w, mat->cw.w,
+ &out->ranges[2]);
+}
+
+/* Complete the loading of the rendering caches. */
+/* Note that this routine may make non-idempotent changes to */
+/* the values in the caches. */
+private void near cie_cache_restrict(P2(cie_cache_floats *, const gs_range *));
+#define cie_cache_restrict3(pcache3, pr3)\
+ cie_cache_restrict(&(pcache3)[0].floats, &(pr3)->ranges[0]);\
+ cie_cache_restrict(&(pcache3)[1].floats, &(pr3)->ranges[1]);\
+ cie_cache_restrict(&(pcache3)[2].floats, &(pr3)->ranges[2])
+int
+gs_cie_render_complete(gs_cie_render *pcie)
+{ /* Since range restriction happens immediately after */
+ /* the cache lookup, we can save a step by restricting */
+ /* the values in the cache entries. */
+ cie_cache_restrict3(pcie->caches.EncodeLMN, &pcie->RangeLMN);
+ cie_cache_restrict3(pcie->caches.EncodeABC, &pcie->RangeABC);
+ /* If there is no lookup table, we want the final ABC values */
+ /* to be fracs; if there is a table, we want them to be */
+ /* appropriately scaled ints. */
+ pcie->MatrixABCEncode = pcie->MatrixABC;
+ { int c;
+ double f;
+ for ( c = 0; c < 3; c++ )
+ { gx_cie_scalar_cache *pcache =
+ &pcie->caches.EncodeABC[c];
+ if ( pcie->RenderTable.lookup.table == 0 )
+ { cie_cache_restrict(&pcache->floats,
+ &Range3_default.ranges[0]);
+ gs_cie_cache_to_fracs(pcache);
+ pcache->fracs.params.is_identity = false;
+ }
+ else
+ { int i;
+ int n = pcie->RenderTable.lookup.dims[c];
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+# define scale_index(f, n, itemp)\
+ restrict_index(f * (1 << _cie_interpolate_bits),\
+ (n) << _cie_interpolate_bits, itemp)
+#else
+ int m = pcie->RenderTable.lookup.m;
+ int k =
+ (c == 0 ? 1 : c == 1 ?
+ m * pcie->RenderTable.lookup.dims[2] : m);
+# define scale_index(f, n, itemp)\
+ (restrict_index(f, n, itemp) * k)
+#endif
+ const gs_range *prange =
+ pcie->RangeABC.ranges + c;
+ /* Loop from top to bottom so that we don't */
+ /* overwrite elements before they're used. */
+ for ( i = gx_cie_cache_size; --i >= 0; )
+ { float v =
+ (pcache->floats.values[i] -
+ prange->rmin) * (n - 1) /
+ (prange->rmax - prange->rmin)
+#ifndef CIE_RENDER_TABLE_INTERPOLATE
+ + 0.5
+#endif
+ ;
+ int itemp;
+
+ if_debug5('c',
+ "[c]cache[%d][%d] = %g => %g => %d\n",
+ c, i, pcache->floats.values[i], v,
+ scale_index(v, n, itemp));
+ pcache->ints.values[i] =
+ scale_index(v, n, itemp);
+ }
+ pcache->ints.params = pcache->floats.params; /* (not necessary) */
+ pcache->ints.params.is_identity = false;
+#undef scale_index
+ }
+ }
+ /* Fold the scaling of the EncodeABC cache index */
+ /* into MatrixABC. */
+#define mabc(i, t)\
+ f = pcie->caches.EncodeABC[i].floats.params.factor;\
+ pcie->MatrixABCEncode.cu.t *= f;\
+ pcie->MatrixABCEncode.cv.t *= f;\
+ pcie->MatrixABCEncode.cw.t *= f;\
+ pcie->EncodeABC_base[i] =\
+ float2cie_cached(pcie->caches.EncodeABC[i].floats.params.base * f)
+ mabc(0, u);
+ mabc(1, v);
+ mabc(2, w);
+ pcie->MatrixABCEncode.is_identity = 0;
+ }
+#undef mabc
+ cie_cache_mult3(pcie->caches.EncodeLMN, &pcie->MatrixABCEncode);
+ return 0;
+}
+
+/* Apply a range restriction to one cache or 3 caches. */
+private void near
+cie_cache_restrict(cie_cache_floats *pcache, const gs_range *prange)
+{ int i;
+ for ( i = 0; i < gx_cie_cache_size; i++ )
+ if_restrict(pcache->values[i], *prange);
+}
+
+/* Convert a cache from floats to fracs. */
+void
+gs_cie_cache_to_fracs(gx_cie_scalar_cache *pcache)
+{ int i;
+ /* Loop from bottom to top so that we don't */
+ /* overwrite elements before they're used. */
+ for ( i = 0; i < gx_cie_cache_size; ++i )
+ pcache->fracs.values[i] = float2frac(pcache->floats.values[i]);
+ pcache->fracs.params = pcache->floats.params; /* (not necessary) */
+}
+
+/* ------ Fill in the joint cache ------ */
+
+/* If the current color space is a CIE space, or has a CIE base space, */
+/* return a pointer to the common part of the space; otherwise return 0. */
+const gs_cie_common *
+gs_cie_cs_common(gs_state *pgs)
+{ const gs_color_space *pcs = pgs->color_space;
+
+sw: switch ( pcs->type->index )
+ {
+ case gs_color_space_index_CIEABC:
+ return &pcs->params.abc->common;
+ case gs_color_space_index_CIEA:
+ return &pcs->params.a->common;
+ case gs_color_space_index_Separation:
+ pcs = (const gs_color_space *)&pcs->params.separation.alt_space;
+ goto sw;
+ case gs_color_space_index_Indexed:
+ pcs = gs_color_space_indexed_base_space(pcs);
+ goto sw;
+ case gs_color_space_index_Pattern:
+ /****** WHAT? ******/
+ default:
+ return 0;
+ }
+}
+
+/* Finish loading the joint caches for the current color space. */
+void
+gs_cie_cs_complete(gs_state *pgs, bool init)
+{ const gs_cie_common *common = gs_cie_cs_common(pgs);
+
+ if ( common )
+ { if ( init )
+ cie_joint_caches_init(pgs->cie_joint_caches, common,
+ pgs->cie_render);
+ cie_joint_caches_complete(pgs->cie_joint_caches, common,
+ pgs->cie_render);
+ }
+}
+
+/* Compute values derived from the color space and rendering parameters */
+/* other than the cached procedure values. This routine is idempotent. */
+private void
+cie_joint_caches_init(gx_cie_joint_caches *pjc,
+ const gs_cie_common *pcie, const gs_cie_render *pcier)
+{ pjc->points_sd.ws.xyz = pcie->points.WhitePoint;
+ cie_mult3(&pjc->points_sd.ws.xyz, &pcier->MatrixPQR,
+ &pjc->points_sd.ws.pqr);
+ pjc->points_sd.bs.xyz = pcie->points.BlackPoint;
+ cie_mult3(&pjc->points_sd.bs.xyz, &pcier->MatrixPQR,
+ &pjc->points_sd.bs.pqr);
+ pjc->points_sd.wd.xyz = pcier->points.WhitePoint;
+ pjc->points_sd.wd.pqr = pcier->wdpqr;
+ pjc->points_sd.bd.xyz = pcier->points.BlackPoint;
+ pjc->points_sd.bd.pqr = pcier->bdpqr;
+ cie_matrix_mult3(&pcier->MatrixPQR, &pcie->MatrixLMN,
+ &pjc->MatrixLMN_PQR);
+ /* Load the TransformPQR caches. */
+ { int i, j;
+ gs_for_loop_params lp[3];
+ cie_cache_init3(pjc->TransformPQR, lp, pcier->RangePQR.ranges,
+ "TransformPQR");
+ for ( i = 0; i < gx_cie_cache_size; i++ )
+ for ( j = 0; j < 3; lp[j].init += lp[j].step, j++ )
+ pjc->TransformPQR[j].floats.values[i] =
+ (*pcier->TransformPQR.procs[j])(lp[j].init, &pjc->points_sd, pcier);
+ }
+}
+
+/* Complete the loading of the joint caches. Note that this routine */
+/* may make non-idempotent changes to the values in the caches. */
+private void
+cie_joint_caches_complete(gx_cie_joint_caches *pjc,
+ const gs_cie_common *pcie, const gs_cie_render *pcier)
+{ int j;
+ cie_cache_restrict3(pjc->TransformPQR, &pcier->RangePQR);
+ for ( j = 0; j < 3; j++ )
+ cie_cache_mult(&pjc->DecodeLMN[j],
+ &pjc->MatrixLMN_PQR.cu + j,
+ &pcie->caches.DecodeLMN[j].floats);
+ pjc->skipLMN = pjc->MatrixLMN_PQR.is_identity &
+ pjc->DecodeLMN[0].vecs.params.is_identity &
+ pjc->DecodeLMN[1].vecs.params.is_identity &
+ pjc->DecodeLMN[2].vecs.params.is_identity;
+ pjc->skipPQR =
+ cie_cache_mult3(pjc->TransformPQR, &pcier->MatrixPQR_inverse_LMN);
+}
+
+/* ================ Color rendering (using the caches) ================ */
+
+private int near cie_remap_finish(P3(const cie_cached_vector3 *,
+ frac *, const gs_imager_state *));
+private void near cie_lookup_mult3(P2(cie_cached_vector3 *,
+ const gx_cie_vector_cache *));
+#ifdef DEBUG
+private void near
+cie_lookup_map3(cie_cached_vector3 *pvec,
+ const gx_cie_vector_cache *pc /*[3]*/, const char _ds *cname)
+{ if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n",
+ (const char *)cname, (ulong)pc,
+ cie_cached2float(pvec->u), cie_cached2float(pvec->v),
+ cie_cached2float(pvec->w));
+ cie_lookup_mult3(pvec, pc);
+ if_debug3('c', " =[%g %g %g]\n",
+ cie_cached2float(pvec->u), cie_cached2float(pvec->v),
+ cie_cached2float(pvec->w));
+}
+#else
+# define cie_lookup_map3(pvec, pc, cname) cie_lookup_mult3(pvec, pc)
+#endif
+
+/* Determine the concrete space underlying a CIEBased space. */
+private const gs_color_space *
+gx_concrete_space_CIE(const gs_color_space *pcs, const gs_imager_state *pis)
+{ const gs_cie_render *pcie = pis->cie_render;
+ if ( pcie == 0 || pcie->RenderTable.lookup.table == 0 ||
+ pcie->RenderTable.lookup.m == 3
+ )
+ return gs_color_space_DeviceRGB();
+ else /* pcie->RenderTable.lookup.m == 4 */
+ return gs_color_space_DeviceCMYK();
+}
+
+/* Render a CIEBasedDEFG color. */
+private int
+gx_concretize_CIEDEFG(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ /****** NOT IMPLEMENTED YET ******/
+ return_error(gs_error_undefined);
+}
+
+/* Render a CIEBasedDEF color. */
+private int
+gx_concretize_CIEDEF(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ /****** NOT IMPLEMENTED YET ******/
+ return_error(gs_error_undefined);
+}
+
+/* Render a CIEBasedABC color. */
+/* We provide both remap and concretize, but only the former */
+/* needs to be efficient. */
+private int
+gx_remap_CIEABC(const gs_client_color *pc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac conc[4];
+ const gs_cie_abc *pcie = pcs->params.abc;
+ cie_cached_vector3 vec3;
+
+ if_debug3('c', "[c]remap CIEABC [%g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2]);
+ vec3.u = float2cie_cached(pc->paint.values[0]);
+ vec3.v = float2cie_cached(pc->paint.values[1]);
+ vec3.w = float2cie_cached(pc->paint.values[2]);
+
+ /* Apply DecodeABC and MatrixABC. */
+#define vabc vec3
+#define vlmn vec3
+ if ( !pcie->caches.skipABC )
+ cie_lookup_map3(&vabc /*&vlmn*/, &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+#undef vabc
+ switch ( cie_remap_finish(&vlmn, conc, pis) )
+ {
+ case 3:
+ if_debug3('c', "[c]=RGB [%g %g %g]\n",
+ frac2float(conc[0]), frac2float(conc[1]),
+ frac2float(conc[2]));
+ gx_remap_concrete_rgb(conc[0], conc[1], conc[2], pdc, pis,
+ dev, select);
+ return 0;
+ case 4:
+ if_debug4('c', "[c]=CMYK [%g %g %g %g]\n",
+ frac2float(conc[0]), frac2float(conc[1]),
+ frac2float(conc[2]), frac2float(conc[3]));
+ gx_remap_concrete_cmyk(conc[0], conc[1], conc[2], conc[3],
+ pdc, pis, dev, select);
+ return 0;
+ }
+ /* Can't happen. */
+ return_error(gs_error_unknownerror);
+#undef vlmn
+}
+private int
+gx_concretize_CIEABC(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ const gs_cie_abc *pcie = pcs->params.abc;
+ cie_cached_vector3 vec3;
+
+ if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2]);
+ vec3.u = float2cie_cached(pc->paint.values[0]);
+ vec3.v = float2cie_cached(pc->paint.values[1]);
+ vec3.w = float2cie_cached(pc->paint.values[2]);
+#define vabc vec3
+#define vlmn vec3
+ if ( !pcie->caches.skipABC )
+ cie_lookup_map3(&vabc /*&vlmn*/, &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+#undef vabc
+ cie_remap_finish(&vlmn, pconc, pis);
+#undef vlmn
+ return 0;
+}
+
+/* Render a CIEBasedA color. */
+private int
+gx_concretize_CIEA(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ const gs_cie_a *pcie = pcs->params.a;
+ cie_cached_value a = float2cie_cached(pc->paint.values[0]);
+ cie_cached_vector3 vlmn;
+
+ if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
+
+ /* Apply DecodeA and MatrixA. */
+ vlmn = lookup_value(a, &pcie->caches.DecodeA);
+ return cie_remap_finish(&vlmn, pconc, pis);
+}
+
+/* Common rendering code. */
+/* Return 3 if RGB, 4 if CMYK. */
+private int near
+cie_remap_finish(const cie_cached_vector3 *plmn, frac *pconc,
+ const gs_imager_state *pis)
+{ const gs_cie_render *pcie = pis->cie_render;
+ const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
+ const gs_const_string *table;
+ cie_cached_vector3 vec3;
+ int tabc[3]; /* indices for final EncodeABC lookup */
+
+ if ( pcie == 0 )
+ { /* No rendering has been defined yet. */
+ /* Just return black. */
+ pconc[0] = pconc[1] = pconc[2] = frac_0;
+ return 3;
+ }
+
+ /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */
+#define vlmn vec3
+ vlmn = *plmn;
+#define vpqr vec3
+ if ( !pjc->skipLMN )
+ cie_lookup_map3(&vlmn /*&vpqr*/, &pjc->DecodeLMN[0],
+ "Decode/MatrixLMN+MatrixPQR");
+#undef vlmn
+
+ /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */
+#define vlmn vec3
+ if ( !pjc->skipPQR )
+ cie_lookup_map3(&vpqr /*&vlmn*/, &pjc->TransformPQR[0],
+ "Transform/Matrix'PQR+MatrixLMN");
+#undef vpqr
+
+ /* Apply EncodeLMN and MatrixABC(encode). */
+#define vabc vec3
+ cie_lookup_map3(&vlmn /*&vabc*/, &pcie->caches.EncodeLMN[0],
+ "EncodeLMN+MatrixABC");
+#undef vlmn
+ /* MatrixABCEncode includes the scaling of the EncodeABC */
+ /* cache index. */
+#define set_tabc(i, t)\
+ set_restrict_index(tabc[i],\
+ cie_cached2int(vabc.t - pcie->EncodeABC_base[i],\
+ _cie_interpolate_bits),\
+ gx_cie_cache_size << _cie_interpolate_bits)
+ set_tabc(0, u);
+ set_tabc(1, v);
+ set_tabc(2, w);
+ table = pcie->RenderTable.lookup.table;
+ if ( table == 0 )
+ { /* No further transformation. */
+ /* The final mapping step includes both restriction to */
+ /* the range [0..1] and conversion to fracs. */
+#define eabc(i)\
+ cie_interpolate_fracs(pcie->caches.EncodeABC[i].fracs.values, tabc[i])
+ pconc[0] = eabc(0);
+ pconc[1] = eabc(1);
+ pconc[2] = eabc(2);
+#undef eabc
+ return 3;
+ }
+ else
+ { /* Use the RenderTable. */
+ int m = pcie->RenderTable.lookup.m;
+#define rt_lookup(j, i) pcie->caches.RenderTableT[j].fracs.values[i]
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+
+ /* The final mapping step includes restriction to the */
+ /* ranges [0..dims[c]] as ints with interpolation bits. */
+ fixed rfix[3];
+
+#define eabc(i)\
+ cie_interpolate_fracs(pcie->caches.EncodeABC[i].ints.values, tabc[i])
+#define fabc(i)\
+ (eabc(i) << (_fixed_shift - _cie_interpolate_bits))
+ rfix[0] = fabc(0);
+ rfix[1] = fabc(1);
+ rfix[2] = fabc(2);
+ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n",
+ cie_cached2float(vabc.u), cie_cached2float(vabc.v),
+ cie_cached2float(vabc.w), fixed2float(rfix[0]),
+ fixed2float(rfix[1]), fixed2float(rfix[2]));
+ gx_color_interpolate_linear(rfix, &pcie->RenderTable.lookup,
+ pconc);
+ if_debug3('c', "[c] interpolated => %g,%g,%g\n",
+ frac2float(pconc[0]), frac2float(pconc[1]),
+ frac2float(pconc[2]));
+ if ( !pcie->caches.RenderTableT_is_identity )
+ { /* Map the interpolated values. */
+#define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size)
+ pconc[0] = rt_lookup(0, frac2cache_index(pconc[0]));
+ pconc[1] = rt_lookup(1, frac2cache_index(pconc[1]));
+ pconc[2] = rt_lookup(2, frac2cache_index(pconc[2]));
+ if ( m > 3 )
+ pconc[3] = rt_lookup(3, frac2cache_index(pconc[3]));
+#undef frac2cache_index
+ }
+
+#else /* !CIE_RENDER_TABLE_INTERPOLATE */
+
+ /* The final mapping step includes restriction to the */
+ /* ranges [0..dims[c]], plus scaling of the indices */
+ /* in the strings. */
+#define ri(i)\
+ pcie->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits]
+ int ia = ri(0);
+ int ib = ri(1); /* pre-multiplied by m * NC */
+ int ic = ri(2); /* pre-multiplied by m */
+ const byte *prtc = table[ia].data + ib + ic;
+ /* (*pcie->RenderTable.T)(prtc, m, pcie, pconc); */
+
+ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n",
+ cie_cached2float(vabc.u), cie_cached2float(vabc.v),
+ cie_cached2float(vabc.w), ia, ib, ic);
+ if ( pcie->caches.RenderTableT_is_identity )
+ { pconc[0] = byte2frac(prtc[0]);
+ pconc[1] = byte2frac(prtc[1]);
+ pconc[2] = byte2frac(prtc[2]);
+ if ( m > 3 )
+ pconc[3] = byte2frac(prtc[3]);
+ }
+ else
+ {
+#if gx_cie_log2_cache_size == 8
+# define byte2cache_index(b) (b)
+#else
+# if gx_cie_log2_cache_size > 8
+# define byte2cache_index(b)\
+ ( ((b) << (gx_cie_log2_cache_size - 8)) +\
+ ((b) >> (16 - gx_cie_log2_cache_size)) )
+# else /* < 8 */
+# define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size))
+# endif
+#endif
+ pconc[0] = rt_lookup(0, byte2cache_index(prtc[0]));
+ pconc[1] = rt_lookup(1, byte2cache_index(prtc[1]));
+ pconc[2] = rt_lookup(2, byte2cache_index(prtc[2]));
+ if ( m > 3 )
+ pconc[3] = rt_lookup(3, byte2cache_index(prtc[3]));
+#undef byte2cache_index
+ }
+
+#endif /* !CIE_RENDER_TABLE_INTERPOLATE */
+#undef ri
+#undef rt_lookup
+ return m;
+ }
+}
+
+/* ================ Utilities ================ */
+
+#define if_debug_vector3(str, vec)\
+ if_debug4('c', "%s[%g %g %g]\n", str, vec->u, vec->v, vec->w)
+#define if_debug_matrix3(str, mat)\
+ if_debug10('c', "%s[%g %g %g / %g %g %g / %g %g %g]\n", str,\
+ mat->cu.u, mat->cu.v, mat->cu.w, mat->cv.u, mat->cv.v, mat->cv.w,\
+ mat->cw.u, mat->cw.v, mat->cw.w)
+
+/* Multiply a vector by a matrix. */
+/* Note that we are computing M * V where v is a column vector. */
+private void near
+cie_mult3(const gs_vector3 *in, register const gs_matrix3 *mat,
+ gs_vector3 *out)
+{ if_debug_vector3("[c]mult", in);
+ if_debug_matrix3(" *", mat);
+ { float u = in->u, v = in->v, w = in->w;
+ out->u = (u * mat->cu.u) + (v * mat->cv.u) + (w * mat->cw.u);
+ out->v = (u * mat->cu.v) + (v * mat->cv.v) + (w * mat->cw.v);
+ out->w = (u * mat->cu.w) + (v * mat->cv.w) + (w * mat->cw.w);
+ }
+ if_debug_vector3(" =", out);
+}
+
+/* Multiply two matrices. We assume the result is not an alias for */
+/* either of the operands. Note that the composition of the transformations */
+/* M1 followed by M2 is M2 * M1, not M1 * M2. (See gscie.h for details.) */
+private void near
+cie_matrix_mult3(const gs_matrix3 *ma, const gs_matrix3 *mb, gs_matrix3 *mc)
+{ if_debug_matrix3("[c]matrix_mult", ma);
+ if_debug_matrix3(" *", mb);
+ cie_mult3(&mb->cu, ma, &mc->cu);
+ cie_mult3(&mb->cv, ma, &mc->cv);
+ cie_mult3(&mb->cw, ma, &mc->cw);
+ cie_matrix_init(mc);
+ if_debug_matrix3(" =", mc);
+}
+
+/* Invert a matrix. */
+/* The output must not be an alias for the input. */
+private void near
+cie_invert3(register const gs_matrix3 *in, register gs_matrix3 *out)
+{ /* This is a brute force algorithm; maybe there are better. */
+ /* We label the array elements */
+ /* [ A B C ] */
+ /* [ D E F ] */
+ /* [ G H I ] */
+#define A cu.u
+#define B cv.u
+#define C cw.u
+#define D cu.v
+#define E cv.v
+#define F cw.v
+#define G cu.w
+#define H cv.w
+#define I cw.w
+ double coA = in->E * in->I - in->F * in->H;
+ double coB = in->F * in->G - in->D * in->I;
+ double coC = in->D * in->H - in->E * in->G;
+ double det = in->A * coA + in->B * coB + in->C * coC;
+ if_debug_matrix3("[c]invert", in);
+ out->A = coA / det;
+ out->D = coB / det;
+ out->G = coC / det;
+ out->B = (in->C * in->H - in->B * in->I) / det;
+ out->E = (in->A * in->I - in->C * in->G) / det;
+ out->H = (in->B * in->G - in->A * in->H) / det;
+ out->C = (in->B * in->F - in->C * in->E) / det;
+ out->F = (in->C * in->D - in->A * in->F) / det;
+ out->I = (in->A * in->E - in->B * in->D) / det;
+ if_debug_matrix3(" =", out);
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+#undef I
+ out->is_identity = in->is_identity;
+}
+
+/* Look up 3 values in a cache, with cached post-multiplication. */
+private void near
+cie_lookup_mult3(cie_cached_vector3 *pvec, const gx_cie_vector_cache *pc /*[3]*/)
+{
+ /****** Interpolating at intermediate stages doesn't seem to ******/
+ /****** make things better, and slows things down, so.... ******/
+#ifdef CIE_INTERPOLATE_INTERMEDIATE
+ /* Interpolate between adjacent cache entries. */
+ /* This is expensive! */
+#ifdef CIE_CACHE_USE_FIXED
+# define lookup_interpolate_between(v0, v1, i, ftemp)\
+ cie_interpolate_between(v0, v1, i)
+#else
+ float ftu, ftv, ftw;
+# define lookup_interpolate_between(v0, v1, i, ftemp)\
+ ((v0) + ((v1) - (v0)) *\
+ ((ftemp = float_rshift(i, _cie_interpolate_bits)), ftemp - (int)ftemp))
+#endif
+
+ cie_cached_value iu =
+ lookup_index(pvec->u, pc, _cie_interpolate_bits);
+ const cie_cached_vector3 *pu =
+ &pc[0].vecs.values[(int)cie_cached_rshift(iu,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pu1 =
+ (iu >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pu : pu + 1);
+
+ cie_cached_value iv =
+ lookup_index(pvec->v, pc + 1, _cie_interpolate_bits);
+ const cie_cached_vector3 *pv =
+ &pc[1].vecs.values[(int)cie_cached_rshift(iv,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pv1 =
+ (iv >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pv : pv + 1);
+
+ cie_cached_value iw =
+ lookup_index(pvec->w, pc + 2, _cie_interpolate_bits);
+ const cie_cached_vector3 *pw =
+ &pc[2].vecs.values[(int)cie_cached_rshift(iw,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pw1 =
+ (iw >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pw : pw + 1);
+
+ pvec->u = lookup_interpolate_between(pu->u, pu1->u, iu, ftu) +
+ lookup_interpolate_between(pv->u, pv1->u, iv, ftv) +
+ lookup_interpolate_between(pw->u, pw1->u, iw, ftw);
+ pvec->v = lookup_interpolate_between(pu->v, pu1->v, iu, ftu) +
+ lookup_interpolate_between(pv->v, pv1->v, iv, ftv) +
+ lookup_interpolate_between(pw->v, pw1->v, iw, ftw);
+ pvec->w = lookup_interpolate_between(pu->w, pu1->w, iu, ftu) +
+ lookup_interpolate_between(pv->w, pv1->w, iv, ftv) +
+ lookup_interpolate_between(pw->w, pw1->w, iw, ftw);
+#else
+ const cie_cached_vector3 *pu = &lookup_value(pvec->u, pc);
+ const cie_cached_vector3 *pv = &lookup_value(pvec->v, pc + 1);
+ const cie_cached_vector3 *pw = &lookup_value(pvec->w, pc + 2);
+ pvec->u = pu->u + pv->u + pw->u;
+ pvec->v = pu->v + pv->v + pw->v;
+ pvec->w = pu->w + pv->w + pw->w;
+#endif
+}
+
+/* Set the is_identity flag that accelerates multiplication. */
+private void near
+cie_matrix_init(register gs_matrix3 *mat)
+{ mat->is_identity =
+ mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
+ mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
+ mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
+}
diff --git a/gs/src/gscie.h b/gs/src/gscie.h
new file mode 100644
index 000000000..a429a87c8
--- /dev/null
+++ b/gs/src/gscie.h
@@ -0,0 +1,472 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscie.h */
+/* Structures for CIE color algorithms */
+/* (requires gscspace.h, gscolor2.h) */
+#include "gsrefct.h"
+#include "gxctable.h"
+
+/* Define the size of the Encode/Decode/Transform procedure value caches. */
+/* With the current design, these caches must all have the same size. */
+#ifndef CIE_LOG2_CACHE_SIZE
+# define CIE_LOG2_CACHE_SIZE 9
+#endif
+#define gx_cie_log2_cache_size CIE_LOG2_CACHE_SIZE
+#define gx_cie_cache_size (1 << gx_cie_log2_cache_size)
+
+/* Define whether to use fixed- or floating-point values in the caches. */
+/*#define CIE_CACHE_USE_FIXED*/
+
+/* If we are using fixed-point values, define the number of fraction bits. */
+#define CIE_FIXED_FRACTION_BITS 12
+#ifndef CIE_FIXED_FRACTION_BITS
+/* Take as many bits as we can without having to multiply in two pieces. */
+# define CIE_FIXED_FRACTION_BITS\
+ ((arch_sizeof_long * 8 - gx_cie_log2_cache_size) / 2 - 1)
+#endif
+
+/* Define whether to interpolate between cached values. */
+#define CIE_CACHE_INTERPOLATE
+
+/* Define whether to interpolate at all intermediate lookup steps. */
+/* This is computationally expensive and doesn't seem to improve */
+/* the accuracy of the result. */
+/*#define CIE_INTERPOLATE_INTERMEDIATE*/
+
+/* Define whether to interpolate in the RenderTable. */
+/* This is computationally very expensive, so it is normally disabled. */
+#define CIE_RENDER_TABLE_INTERPOLATE
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+# define CIE_CACHE_INTERPOLATE
+#endif
+
+/* Mark code intended for later use. */
+/****** NOTE: this is also used in zcie.c. ******/
+/*#define NEW_CIE*/
+
+#define float_lshift(v, nb) ((v) * (1L << (nb)))
+#define float_rshift(v, nb) ((v) * (1.0 / (1L << (nb))))
+
+#ifdef CIE_CACHE_INTERPOLATE
+/* We have to have room for both a cache index and the interpolation bits */
+/* in a positive int (i.e., leaving 1 bit for the sign), plus a little slop. */
+/* The values for interpolation are cie_cached_values by default. */
+# define _cie_interpolate_bits\
+ min(arch_sizeof_int * 8 - gx_cie_log2_cache_size - 2, 10)
+# define _cix(i) ((i) >> _cie_interpolate_bits)
+# define _cif(i) ((int)(i) & ((1 << _cie_interpolate_bits) - 1))
+# define cie_interpolate_between(v0, v1, i)\
+ ((v0) + cie_cached_rshift(((v1) - (v0)) * _cif(i) +\
+ (1 << (_cie_interpolate_bits - 1)),\
+ _cie_interpolate_bits))
+# define cie_interpolate(p, i)\
+ cie_interpolate_between((p)[_cix(i)], (p)[_cix(i) + 1], i)
+# define cie_interpolate_fracs(p, i)\
+ ((p)[_cix(i)] + (frac)arith_rshift((long)((p)[_cix(i) + 1] - (p)[_cix(i)]) * _cif(i), _cie_interpolate_bits))
+#else
+# define _cie_interpolate_bits 0
+# define cie_interpolate_between(v0, v1, i) (v0)
+# define cie_interpolate(p, i) ((p)[i])
+# define cie_interpolate_fracs(p, i) ((p)[i])
+#endif
+
+#ifdef CIE_CACHE_USE_FIXED
+typedef long cie_cached_value;
+# define _cie_fixed_shift CIE_FIXED_FRACTION_BITS
+# define float2cie_cached(v)\
+ ((cie_cached_value)float_lshift(v, _cie_fixed_shift))
+# define cie_cached2float(v)\
+ float_rshift(v, _cie_fixed_shift)
+# define cie_cached2int(v, fbits)\
+ arith_rshift(v, _cie_fixed_shift - (fbits))
+/* We are multiplying two cie_cached_values to produce a result that */
+/* lies between 0 and gx_cie_cache_size - 1. If the intermediate result */
+/* might overflow, compute it in pieces (being a little sloppy). */
+# define _cie_product_excess_bits\
+ (_cie_fixed_shift * 2 + gx_cie_log2_cache_size - (arch_sizeof_long * 8 - 1))
+# define cie_cached_product2int(v, factor, fbits)\
+ (_cie_product_excess_bits > 0 ?\
+ arith_rshift( (v) * arith_rshift(factor, _cie_product_excess_bits) +\
+ arith_rshift(v, _cie_product_excess_bits) *\
+ ((factor) & ((1 << _cie_product_excess_bits) - 1)),\
+ _cie_fixed_shift * 2 - _cie_product_excess_bits - (fbits)) :\
+ arith_rshift((v) * (factor), _cie_fixed_shift * 2 - (fbits)))
+# define cie_cached_rshift(v, n) arith_rshift(v, n)
+#else
+typedef float cie_cached_value;
+# define float2cie_cached(v) (v)
+# define cie_cached2float(v) (v)
+# define cie_cached2int(v, fbits)\
+ ((int)float_lshift(v, fbits))
+# define cie_cached_product2int(v, factor, fbits)\
+ ((int)float_lshift((v) * (factor), fbits))
+# define cie_cached_rshift(v, n) float_rshift(v, n)
+#endif
+
+/* ------ Common definitions ------ */
+
+/*
+ * For the purposes of the CIE routines, we consider that all the vectors
+ * are column vectors, that the matrices are specified in column order
+ * (e.g., the matrix
+ * [ A B C ]
+ * [ D E F ]
+ * [ G H I ]
+ * is represented as [A D G B E H C F I]), and that to transform a vector
+ * V by a matrix M, we compute M * V to produce another column vector.
+ * Note in particular that in order to produce a matrix M that is
+ * equivalent to transforming by M1 and then by M2, we must compute
+ * M = M2 * M1. This probably isn't the most intuitive way to specify
+ * these things, but that's how the code turned out, and it isn't worth
+ * changing at this point.
+ */
+
+/* A 3-element vector. */
+typedef struct gs_vector3_s {
+ float u, v, w;
+} gs_vector3;
+
+/* A 3x3 matrix, stored in column order. */
+typedef struct gs_matrix3_s {
+ gs_vector3 cu, cv, cw;
+ bool is_identity;
+} gs_matrix3;
+
+/* 3- and 4-element vectors of ranges. */
+typedef struct gs_range_s {
+ float rmin, rmax;
+} gs_range;
+typedef struct gs_range3_s {
+ gs_range ranges[3];
+} gs_range3;
+typedef struct gs_range4_s {
+ gs_range ranges[4];
+} gs_range4;
+
+/* Client-supplied transformation procedures. */
+typedef struct gs_cie_common_s gs_cie_common;
+#ifdef NEW_CIE
+typedef struct gs_cie_abc_common_s gs_cie_abc_common;
+#else
+typedef struct gs_cie_abc_s gs_cie_abc_common;
+#endif
+typedef struct gs_cie_wbsd_s gs_cie_wbsd;
+
+typedef float (*gs_cie_a_proc)(P2(floatp, const gs_cie_a *));
+
+typedef float (*gs_cie_abc_proc)(P2(floatp, const gs_cie_abc *));
+typedef struct gs_cie_abc_proc3_s {
+ gs_cie_abc_proc procs[3];
+} gs_cie_abc_proc3;
+
+typedef float (*gs_cie_def_proc)(P2(floatp, const gs_cie_def *));
+typedef struct gs_cie_def_proc3_s {
+ gs_cie_def_proc procs[3];
+} gs_cie_def_proc3;
+
+typedef float (*gs_cie_defg_proc)(P2(floatp, const gs_cie_defg *));
+typedef struct gs_cie_defg_proc4_s {
+ gs_cie_defg_proc procs[4];
+} gs_cie_defg_proc4;
+
+typedef float (*gs_cie_common_proc)(P2(floatp, const gs_cie_common *));
+typedef struct gs_cie_common_proc3_s {
+ gs_cie_common_proc procs[3];
+} gs_cie_common_proc3;
+
+typedef float (*gs_cie_render_proc)(P2(floatp, const gs_cie_render *));
+typedef struct gs_cie_render_proc3_s {
+ gs_cie_render_proc procs[3];
+} gs_cie_render_proc3;
+
+typedef float (*gs_cie_transform_proc)(P3(floatp, const gs_cie_wbsd *,
+ const gs_cie_render *));
+typedef struct gs_cie_transform_proc3_s {
+ gs_cie_transform_proc procs[3];
+} gs_cie_transform_proc3;
+
+typedef frac (*gs_cie_render_table_proc)(P2(byte, const gs_cie_render *));
+typedef struct gs_cie_render_table_procs_s {
+ gs_cie_render_table_proc procs[4];
+} gs_cie_render_table_procs;
+
+/* CIE white and black points. */
+typedef struct gs_cie_wb_s {
+ gs_vector3 WhitePoint;
+ gs_vector3 BlackPoint;
+} gs_cie_wb;
+
+/* ------ Caches ------ */
+
+/*
+ * Given that all the client-supplied procedures involved in CIE color
+ * mapping and rendering are monotonic, and given that we can determine
+ * the minimum and maximum input values for them, we can cache their values.
+ * This takes quite a lot of space, but eliminates the need for callbacks
+ * deep in the graphics code (particularly the image operator).
+ *
+ * The procedures, and how we determine their domains, are as follows:
+
+Stage Name Domain determination
+----- ---- --------------------
+pre-decode DecodeDEF RangeDEF
+pre-decode DecodeDEFG RangeDEFG
+color space DecodeA RangeA
+color space DecodeABC RangeABC
+color space DecodeLMN RangeLMN
+rendering TransformPQR RangePQR
+ (but depends on color space White/BlackPoints)
+rendering EncodeLMN RangePQR transformed by the inverse of
+ MatrixPQR and then by MatrixLMN
+rendering EncodeABC RangeLMN transformed by MatrixABC
+rendering RenderTable.T [0..1]*m
+
+ * Note that we can mostly cache the results of the color space procedures
+ * without knowing the color rendering parameters, and vice versa,
+ * because of the range parameters supplied in the dictionaries.
+ * Unfortunately, TransformPQR is an exception.
+ */
+/*
+ * The index into a cache is (value - base) * factor, where
+ * factor is computed as (cie_cache_size - 1) / (rmax - rmin).
+ */
+/*
+ * We have two kinds of caches: ordinary caches, where each value is
+ * a scalar, and vector caches, where each value is a gs_cached_vector3.
+ * The latter allow us to pre-multiply the values by one column of
+ * a gs_matrix3, avoiding multiplications at lookup time.
+ * Since we sometimes alias the two types of caches for access to
+ * the floats, values must come last.
+ */
+typedef struct cie_cache_params_s {
+ bool is_identity; /* must come first */
+ float base, factor;
+} cie_cache_params;
+#define cie_cache_struct(sname, vtype)\
+ struct sname {\
+ cie_cache_params params;\
+ vtype values[gx_cie_cache_size];\
+ }
+typedef cie_cache_struct(gx_cie_cache_s, float) cie_cache_floats;
+typedef union gx_cie_scalar_cache_s {
+ cie_cache_floats floats;
+ cie_cache_struct(_scf, frac) fracs;
+ cie_cache_struct(_sci, int) ints;
+} gx_cie_scalar_cache;
+typedef struct cie_cached_vector3_s {
+ cie_cached_value u, v, w;
+} cie_cached_vector3;
+typedef struct cie_vector_cache_params_s {
+ bool is_identity; /* must come first */
+ cie_cached_value base, factor, limit;
+} cie_vector_cache_params;
+typedef struct cie_cache_vectors_s {
+ cie_vector_cache_params params; /* must come first for is_identity */
+ cie_cached_vector3 values[gx_cie_cache_size];
+} cie_cache_vectors;
+typedef union gx_cie_vector_cache_s {
+ cie_cache_floats floats;
+ cie_cache_vectors vecs;
+} gx_cie_vector_cache;
+
+/* ------ Color space dictionaries ------ */
+
+/* Elements common to all CIE dictionaries. */
+struct gs_cie_common_s {
+ gs_range3 RangeLMN;
+ gs_cie_common_proc3 DecodeLMN;
+ gs_matrix3 MatrixLMN;
+ gs_cie_wb points;
+ /* Following are computed when structure is initialized. */
+ struct {
+ gx_cie_scalar_cache DecodeLMN[3];
+ } caches;
+};
+
+/* A CIEBasedA dictionary. */
+struct gs_cie_a_s {
+ gs_cie_common common; /* must be first */
+ rc_header rc;
+ gs_range RangeA;
+ gs_cie_a_proc DecodeA;
+ gs_vector3 MatrixA;
+ /* Following are computed when structure is initialized. */
+ struct {
+ gx_cie_vector_cache DecodeA; /* mult. by MatrixA */
+ } caches;
+};
+#define private_st_cie_a() /* in zcie.c */\
+ gs_private_st_simple(st_cie_a, gs_cie_a, "gs_cie_a")
+
+/* A CIEBasedABC dictionary. */
+#ifdef NEW_CIE
+struct gs_cie_abc_common_s {
+ gs_cie_common common; /* must be first */
+#else
+struct gs_cie_abc_s {
+ gs_cie_common common; /* must be first */
+ rc_header rc;
+#endif
+ gs_range3 RangeABC;
+ gs_cie_abc_proc3 DecodeABC;
+ gs_matrix3 MatrixABC;
+ /* Following are computed when structure is initialized. */
+ struct {
+ bool skipABC;
+ gx_cie_vector_cache DecodeABC[3]; /* mult. by MatrixABC */
+ } caches;
+};
+#ifdef NEW_CIE
+/* A CIEBasedABC dictionary. */
+struct gs_cie_abc_s {
+ gs_cie_abc_common abc; /* must be first */
+ rc_header rc;
+};
+#endif
+#define private_st_cie_abc() /* in zcie.c */\
+ gs_private_st_simple(st_cie_abc, gs_cie_abc, "gs_cie_abc")
+
+/* A CIEBasedDEF dictionary. */
+/****** NOT IMPLEMENTED YET ******/
+struct gs_cie_def_s {
+ gs_cie_abc_common abc; /* must be first */
+#ifndef NEW_CIE
+ rc_header rc;
+#endif
+ gs_range3 RangeDEF;
+ gs_cie_def_proc3 DecodeDEF;
+ gs_range3 RangeHIJ;
+ gx_color_lookup_table Table; /* [NH][NI * NJ * 3] */
+ struct {
+ gx_cie_scalar_cache DecodeDEF[3];
+ } caches;
+};
+#define private_st_cie_def() /* in zcie.c */\
+ gs_private_st_ptrs1(st_cie_def, gs_cie_def, "gs_cie_def",\
+ cie_def_enum_ptrs, cie_def_reloc_ptrs, Table.table)
+
+/* A CIEBasedDEFG dictionary. */
+/****** NOT IMPLEMENTED YET ******/
+struct gs_cie_defg_s {
+ gs_cie_abc_common abc; /* must be first */
+#ifndef NEW_CIE
+ rc_header rc;
+#endif
+ gs_range4 RangeDEFG;
+ gs_cie_defg_proc4 DecodeDEFG;
+ gs_range4 RangeHIJK;
+ gx_color_lookup_table Table; /* [NH * NI][NJ * NK * 3] */
+ struct {
+ gx_cie_scalar_cache DecodeDEFG[4];
+ } caches;
+};
+#define private_st_cie_defg() /* in zcie.c */\
+ gs_private_st_ptrs1(st_cie_defg, gs_cie_defg, "gs_cie_defg",\
+ cie_defg_enum_ptrs, cie_defg_reloc_ptrs, Table.table)
+
+/* Default values for components */
+extern const gs_range3 Range3_default;
+extern const gs_range4 Range4_default;
+extern const gs_cie_defg_proc4 DecodeDEFG_default;
+extern const gs_cie_def_proc3 DecodeDEF_default;
+extern const gs_cie_abc_proc3 DecodeABC_default;
+extern const gs_cie_common_proc3 DecodeLMN_default;
+extern const gs_matrix3 Matrix3_default;
+extern const gs_range RangeA_default;
+extern const gs_cie_a_proc DecodeA_default;
+extern const gs_vector3 MatrixA_default;
+extern const gs_vector3 BlackPoint_default;
+extern const gs_cie_render_proc3 Encode_default;
+extern const gs_cie_transform_proc3 TransformPQR_default;
+extern const gs_cie_render_table_procs RenderTableT_default;
+
+/* ------ Rendering dictionaries ------ */
+
+struct gs_cie_wbsd_s {
+ struct { gs_vector3 xyz, pqr; } ws, bs, wd, bd;
+};
+/* The main dictionary */
+struct gs_cie_render_s {
+ rc_header rc;
+ gs_cie_wb points;
+ gs_matrix3 MatrixPQR;
+ gs_range3 RangePQR;
+ gs_cie_transform_proc3 TransformPQR;
+ gs_matrix3 MatrixLMN;
+ gs_cie_render_proc3 EncodeLMN;
+ gs_range3 RangeLMN;
+ gs_matrix3 MatrixABC;
+ gs_cie_render_proc3 EncodeABC;
+ gs_range3 RangeABC;
+ struct {
+ gx_color_lookup_table lookup; /* if table is 0, other */
+ /* members are not set */
+ gs_cie_render_table_procs T;
+ } RenderTable;
+ /* Following are computed when structure is initialized. */
+ gs_range3 DomainLMN;
+ gs_range3 DomainABC;
+ gs_matrix3 MatrixABCEncode;
+ cie_cached_value EncodeABC_base[3];
+ gs_matrix3 MatrixPQR_inverse_LMN;
+ gs_vector3 wdpqr, bdpqr;
+ struct {
+ gx_cie_vector_cache EncodeLMN[3]; /* mult. by M'ABCEncode */
+ gx_cie_scalar_cache EncodeABC[3];
+ gx_cie_scalar_cache RenderTableT[4];
+ bool RenderTableT_is_identity;
+ } caches;
+};
+#define private_st_cie_render() /* in zcrd.c */\
+ gs_private_st_ptrs1(st_cie_render, gs_cie_render, "gs_cie_render",\
+ cie_render_enum_ptrs, cie_render_reloc_ptrs, RenderTable.lookup.table)
+/* RenderTable.lookup.table points to an array of st_const_string_elements. */
+
+/* ------ Joint caches ------ */
+
+/* This cache depends on both the color space and the rendering */
+/* dictionary -- see above. */
+
+typedef struct gx_cie_joint_caches_s {
+ rc_header rc;
+ bool skipLMN;
+ gx_cie_vector_cache DecodeLMN[3]; /* mult. by dLMN_PQR */
+ gs_cie_wbsd points_sd;
+ gs_matrix3 MatrixLMN_PQR;
+ bool skipPQR;
+ gx_cie_vector_cache TransformPQR[3]; /* mult. by PQR_inverse_eLMN */
+} gx_cie_joint_caches;
+#define private_st_joint_caches() /* in gscie.c */\
+ gs_private_st_simple(st_joint_caches, gx_cie_joint_caches,\
+ "gx_cie_joint_caches")
+
+/* Internal routines */
+typedef struct gs_for_loop_params_s {
+ float init, step, limit;
+} gs_for_loop_params;
+void gs_cie_cache_init(P4(cie_cache_params *, gs_for_loop_params *,
+ const gs_range *, client_name_t));
+void gs_cie_cache_to_fracs(P1(gx_cie_scalar_cache *));
+void gs_cie_abc_complete(P1(gs_cie_abc *));
+void gs_cie_a_complete(P1(gs_cie_a *));
+int gs_cie_render_init(P1(gs_cie_render *));
+int gs_cie_render_complete(P1(gs_cie_render *));
+gx_cie_joint_caches *gx_currentciecaches(P1(gs_state *));
+const gs_cie_common *gs_cie_cs_common(P1(gs_state *));
+void gs_cie_cs_complete(P2(gs_state *, bool));
diff --git a/gs/src/gscolor.c b/gs/src/gscolor.c
new file mode 100644
index 000000000..c26897b1f
--- /dev/null
+++ b/gs/src/gscolor.c
@@ -0,0 +1,366 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor.c */
+/* Color and halftone operators for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxdcconv.h"
+#include "gxdevice.h" /* for gx_color_index */
+#include "gxcmap.h"
+#include "gzstate.h"
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Define the standard color space types. */
+extern cs_proc_remap_color(gx_remap_DeviceGray);
+extern cs_proc_concretize_color(gx_concretize_DeviceGray);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DGray);
+extern cs_proc_remap_color(gx_remap_DeviceRGB);
+extern cs_proc_concretize_color(gx_concretize_DeviceRGB);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DRGB);
+const gs_color_space_type
+ gs_color_space_type_DeviceGray =
+ { gs_color_space_index_DeviceGray, 1, true,
+ gx_init_paint_1, gx_same_concrete_space,
+ gx_concretize_DeviceGray, gx_remap_concrete_DGray,
+ gx_remap_DeviceGray, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count,
+ gx_no_cspace_enum_ptrs, gx_no_cspace_reloc_ptrs
+ },
+ gs_color_space_type_DeviceRGB =
+ { gs_color_space_index_DeviceRGB, 3, true,
+ gx_init_paint_3, gx_same_concrete_space,
+ gx_concretize_DeviceRGB, gx_remap_concrete_DRGB,
+ gx_remap_DeviceRGB, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count,
+ gx_no_cspace_enum_ptrs, gx_no_cspace_reloc_ptrs
+ };
+
+/* Structure descriptors */
+public_st_color_space();
+public_st_client_color();
+
+/*
+ * Define permanent instances of the 3 device color spaces.
+ * The one for CMYK is initialized by gscolor1.c and may be NULL.
+ */
+const gs_color_space *gs_cs_static_DeviceGray;
+private gs_gc_root_t cs_gray_root;
+const gs_color_space *gs_cs_static_DeviceRGB;
+private gs_gc_root_t cs_rgb_root;
+const gs_color_space *gs_cs_static_DeviceCMYK = 0;
+private gs_gc_root_t cs_cmyk_root;
+void
+gs_gscolor_init(gs_memory_t *mem)
+{
+#define cs_init(cs_var, cs_type, cname)\
+ { gs_color_space *pcs =\
+ gs_alloc_struct(mem, gs_color_space, &st_color_space, cname);\
+ pcs->type = &cs_type;\
+ cs_var = pcs;\
+ }
+ cs_init(gs_cs_static_DeviceGray, gs_color_space_type_DeviceGray,
+ "gs_cs_static_DeviceGray");
+ gs_register_struct_root(mem, &cs_gray_root,
+ (void **)&gs_cs_static_DeviceGray,
+ "gs_cs_static_DeviceGray");
+ cs_init(gs_cs_static_DeviceRGB, gs_color_space_type_DeviceRGB,
+ "gs_cs_static_DeviceRGB");
+ gs_register_struct_root(mem, &cs_rgb_root,
+ (void **)&gs_cs_static_DeviceRGB,
+ "gs_cs_static_DeviceRGB");
+ gs_register_struct_root(mem, &cs_cmyk_root,
+ (void **)&gs_cs_static_DeviceCMYK,
+ "gs_cs_static_DeviceCMYK");
+#undef cs_init
+}
+const gs_color_space *
+gs_color_space_DeviceGray(void)
+{ return gs_cs_static_DeviceGray;
+}
+const gs_color_space *
+gs_color_space_DeviceRGB(void)
+{ return gs_cs_static_DeviceRGB;
+}
+const gs_color_space *
+gs_color_space_DeviceCMYK(void)
+{ return gs_cs_static_DeviceCMYK;
+}
+
+/* Get the index of a color space. */
+gs_color_space_index
+gs_color_space_get_index(const gs_color_space *pcs)
+{ return pcs->type->index;
+}
+
+/* Get the number of components in a color space. */
+int
+gs_color_space_num_components(const gs_color_space *pcs)
+{ return pcs->type->num_components;
+}
+
+/* Get the base space of an Indexed color space. */
+const gs_color_space *
+gs_color_space_indexed_base_space(const gs_color_space *pcs)
+{ return (const gs_color_space *)&pcs->params.indexed.base_space;
+}
+
+/* Initialize colors with 1, or 3, or 4 paint components. */
+/* (These are only used by setcolorspace.) */
+void
+gx_init_paint_1(gs_client_color *pcc, const gs_color_space *pcs)
+{ pcc->paint.values[0] = 0.0;
+}
+void
+gx_init_paint_3(gs_client_color *pcc, const gs_color_space *pcs)
+{ pcc->paint.values[2] = 0.0;
+ pcc->paint.values[1] = 0.0;
+ pcc->paint.values[0] = 0.0;
+}
+void
+gx_init_paint_4(gs_client_color *pcc, const gs_color_space *pcs)
+{ /* DeviceCMYK and CIEBasedDEFG spaces initialize to 0,0,0,1. */
+ pcc->paint.values[3] = 1.0;
+ gx_init_paint_3(pcc, pcs);
+}
+
+/* Null color space installation procedure. */
+int
+gx_no_install_cspace(gs_color_space *pcs, gs_state *pgs)
+{ return 0;
+}
+
+/* Null reference count adjustment procedures. */
+void
+gx_no_adjust_cspace_count(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{
+}
+void
+gx_no_adjust_color_count(const gs_client_color *pcc, const gs_color_space *pcs, gs_memory_t *mem, int delta)
+{
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private ENUM_PTRS_BEGIN_PROC(color_space_enum_ptrs) {
+ return (*pcs->type->enum_ptrs)(pcs, size, index, pep);
+ENUM_PTRS_END_PROC }
+private RELOC_PTRS_BEGIN(color_space_reloc_ptrs) {
+ (*pcs->type->reloc_ptrs)(pcs, size, gcst);
+} RELOC_PTRS_END
+
+#undef pcs
+
+/* Force a parameter into the range [0.0..1.0]. */
+#define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
+
+/* Forward declarations */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* setgray */
+int
+gs_setgray(gs_state *pgs, floatp gray)
+{ if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pgs->ccolor->paint.values[0] = force_unit(gray);
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentgray */
+float
+gs_currentgray(const gs_state *pgs)
+{ const gs_client_color *pcc = pgs->ccolor;
+ switch ( pgs->color_space->type->index )
+ {
+ case gs_color_space_index_DeviceGray:
+ return pcc->paint.values[0];
+ case gs_color_space_index_DeviceRGB:
+ return frac2float(color_rgb_to_gray(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ (const gs_imager_state *)pgs));
+ case gs_color_space_index_DeviceCMYK:
+ return frac2float(color_cmyk_to_gray(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ float2frac(pcc->paint.values[3]),
+ (const gs_imager_state *)pgs));
+ default:
+ return 0.0;
+ }
+}
+
+/* setrgbcolor */
+int
+gs_setrgbcolor(gs_state *pgs, floatp r, floatp g, floatp b)
+{ gs_client_color *pcc = pgs->ccolor;
+ if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = force_unit(r);
+ pcc->paint.values[1] = force_unit(g);
+ pcc->paint.values[2] = force_unit(b);
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceRGB;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentrgbcolor */
+int
+gs_currentrgbcolor(const gs_state *pgs, float pr3[3])
+{ const gs_client_color *pcc = pgs->ccolor;
+ switch ( pgs->color_space->type->index )
+ {
+ case gs_color_space_index_DeviceGray:
+ pr3[0] = pr3[1] = pr3[2] = pcc->paint.values[0];
+ break;
+ case gs_color_space_index_DeviceRGB:
+ pr3[0] = pcc->paint.values[0];
+ pr3[1] = pcc->paint.values[1];
+ pr3[2] = pcc->paint.values[2];
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ { frac frgb[3];
+ color_cmyk_to_rgb(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ float2frac(pcc->paint.values[3]),
+ (const gs_imager_state *)pgs, frgb);
+ pr3[0] = frac2float(frgb[0]);
+ pr3[1] = frac2float(frgb[1]);
+ pr3[2] = frac2float(frgb[2]);
+ } break;
+ default:
+ pr3[0] = pr3[1] = pr3[2] = 0.0;
+ }
+ return 0;
+}
+
+/* setalpha */
+int
+gs_setalpha(gs_state *pgs, floatp alpha)
+{ pgs->alpha = (gx_color_value)(force_unit(alpha) * gx_max_color_value);
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentalpha */
+float
+gs_currentalpha(const gs_state *pgs)
+{ return (float)pgs->alpha / gx_max_color_value;
+}
+
+/* setnullcolor */
+int
+gs_setnullcolor(gs_state *pgs)
+{ if ( pgs->in_cachedevice )
+ return_error(gs_error_undefined);
+ gs_setgray(pgs, 0.0); /* set color space to something harmless */
+ color_set_null(pgs->dev_color);
+ return 0;
+}
+
+/* settransfer */
+/* Remap=0 is used by the interpreter. */
+int
+gs_settransfer(gs_state *pgs, gs_mapping_proc tproc)
+{ return gs_settransfer_remap(pgs, tproc, true);
+}
+int
+gs_settransfer_remap(gs_state *pgs, gs_mapping_proc tproc, bool remap)
+{ gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+ /* We can safely decrement the reference counts */
+ /* of the non-gray transfer maps, because */
+ /* if any of them get freed, the rc_unshare can't fail. */
+ rc_decrement(ptran->red, "gs_settransfer");
+ rc_decrement(ptran->green, "gs_settransfer");
+ rc_decrement(ptran->blue, "gs_settransfer");
+ rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fail, "gs_settransfer");
+ ptran->gray->proc = tproc;
+ ptran->gray->id = gs_next_ids(1);
+ ptran->red = ptran->gray;
+ ptran->green = ptran->gray;
+ ptran->blue = ptran->gray;
+ ptran->gray->rc.ref_count += 3;
+ if ( remap )
+ { load_transfer_map(pgs, ptran->gray, 0.0);
+ gx_set_effective_transfer(pgs);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+fail: rc_increment(ptran->red);
+ rc_increment(ptran->green);
+ rc_increment(ptran->blue);
+ return_error(gs_error_VMerror);
+}
+
+/* currenttransfer */
+gs_mapping_proc
+gs_currenttransfer(const gs_state *pgs)
+{ return pgs->set_transfer.colored.gray->proc;
+}
+
+/* ------ Non-operator routines ------ */
+
+/* Set device color = 1 for writing into the character cache. */
+void
+gx_set_device_color_1(gs_state *pgs)
+{ gx_device_color *pdc = pgs->dev_color;
+ gs_client_color *pcc = pgs->ccolor;
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = 0.0;
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ color_set_pure(pdc, 1);
+ pgs->log_op = lop_default;
+}
+
+/* ------ Internal routines ------ */
+
+/* Load one cached transfer map. */
+/* This is exported for gscolor1.c. */
+void
+load_transfer_map(gs_state *pgs, gx_transfer_map *pmap, floatp min_value)
+{ gs_mapping_proc proc = pmap->proc;
+ frac *values = pmap->values;
+ frac fmin = float2frac(min_value);
+ int i;
+ for ( i = 0; i < transfer_map_size; i++ )
+ { float fval =
+ (*proc)((float)i / (transfer_map_size - 1), pmap);
+ values[i] =
+ (fval < min_value ? fmin :
+ fval >= 1.0 ? frac_1 :
+ float2frac(fval));
+ }
+}
diff --git a/gs/src/gscolor.h b/gs/src/gscolor.h
new file mode 100644
index 000000000..b9e3489b2
--- /dev/null
+++ b/gs/src/gscolor.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 1991, 1992, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor.h */
+/* Client interface to color routines */
+
+#ifndef gscolor_INCLUDED
+# define gscolor_INCLUDED
+
+#include "gxtmap.h"
+
+/* Color and gray interface */
+int gs_setgray(P2(gs_state *, floatp));
+float gs_currentgray(P1(const gs_state *));
+int gs_setrgbcolor(P4(gs_state *, floatp, floatp, floatp)),
+ gs_currentrgbcolor(P2(const gs_state *, float [3])),
+ gs_setalpha(P2(gs_state *, floatp));
+float gs_currentalpha(P1(const gs_state *));
+int gs_setnullcolor(P1(gs_state *));
+/* Transfer function */
+int gs_settransfer(P2(gs_state *, gs_mapping_proc)),
+ gs_settransfer_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currenttransfer(P1(const gs_state *));
+
+#endif /* gscolor_INCLUDED */
diff --git a/gs/src/gscolor1.c b/gs/src/gscolor1.c
new file mode 100644
index 000000000..6de54875c
--- /dev/null
+++ b/gs/src/gscolor1.c
@@ -0,0 +1,229 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor.c */
+/* Level 1 extended color operators for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxdcconv.h"
+#include "gxdevice.h" /* for gx_color_index */
+#include "gxcmap.h"
+#include "gzstate.h"
+#include "gscolor1.h"
+
+/* Imports from gscolor.c */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Force a parameter into the range [0.0..1.0]. */
+#define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
+
+/* Define the CMYK color space type. */
+extern cs_proc_remap_color(gx_remap_DeviceCMYK);
+extern cs_proc_concretize_color(gx_concretize_DeviceCMYK);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DCMYK);
+const gs_color_space_type
+ gs_color_space_type_DeviceCMYK =
+ { gs_color_space_index_DeviceCMYK, 4, true,
+ gx_init_paint_4, gx_same_concrete_space,
+ gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK,
+ gx_remap_DeviceCMYK, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count,
+ gx_no_cspace_enum_ptrs, gx_no_cspace_reloc_ptrs
+ };
+
+/* Initialize the permanent color space instance (declared in gscolor.c). */
+extern const gs_color_space *gs_cs_static_DeviceCMYK;
+void
+gs_gscolor1_init(gs_memory_t *mem)
+{ gs_color_space *pcs =
+ gs_alloc_struct(mem, gs_color_space, &st_color_space,
+ "gs_cs_static_DeviceCMYK");
+ pcs->type = &gs_color_space_type_DeviceCMYK;
+ gs_cs_static_DeviceCMYK = pcs;
+}
+
+/* setcmykcolor */
+int
+gs_setcmykcolor(gs_state *pgs, floatp c, floatp m, floatp y, floatp k)
+{ gs_client_color *pcc = pgs->ccolor;
+ if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = force_unit(c);
+ pcc->paint.values[1] = force_unit(m);
+ pcc->paint.values[2] = force_unit(y);
+ pcc->paint.values[3] = force_unit(k);
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceCMYK;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentcmykcolor */
+int
+gs_currentcmykcolor(const gs_state *pgs, float pr4[4])
+{ const gs_client_color *pcc = pgs->ccolor;
+ switch ( pgs->color_space->type->index )
+ {
+ case gs_color_space_index_DeviceGray:
+ pr4[0] = pr4[1] = pr4[2] = 0.0;
+ pr4[3] = 1.0 - pcc->paint.values[0];
+ break;
+ case gs_color_space_index_DeviceRGB:
+ { frac fcmyk[4];
+ color_rgb_to_cmyk(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ (const gs_imager_state *)pgs, fcmyk);
+ pr4[0] = frac2float(fcmyk[0]);
+ pr4[1] = frac2float(fcmyk[1]);
+ pr4[2] = frac2float(fcmyk[2]);
+ pr4[3] = frac2float(fcmyk[3]);
+ } break;
+ case gs_color_space_index_DeviceCMYK:
+ pr4[0] = pcc->paint.values[0];
+ pr4[1] = pcc->paint.values[1];
+ pr4[2] = pcc->paint.values[2];
+ pr4[3] = pcc->paint.values[3];
+ break;
+ default:
+ pr4[0] = pr4[1] = pr4[2] = 0.0;
+ pr4[3] = 1.0;
+ }
+ return 0;
+}
+
+/* setblackgeneration */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setblackgeneration(gs_state *pgs, gs_mapping_proc proc)
+{ return gs_setblackgeneration_remap(pgs, proc, true);
+}
+int
+gs_setblackgeneration_remap(gs_state *pgs, gs_mapping_proc proc, bool remap)
+{ rc_unshare_struct(pgs->black_generation, gx_transfer_map,
+ &st_transfer_map, pgs->memory,
+ return_error(gs_error_VMerror),
+ "gs_setblackgeneration");
+ pgs->black_generation->proc = proc;
+ pgs->black_generation->id = gs_next_ids(1);
+ if ( remap )
+ { load_transfer_map(pgs, pgs->black_generation, 0.0);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+}
+
+/* currentblackgeneration */
+gs_mapping_proc
+gs_currentblackgeneration(const gs_state *pgs)
+{ return pgs->black_generation->proc;
+}
+
+/* setundercolorremoval */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setundercolorremoval(gs_state *pgs, gs_mapping_proc proc)
+{ return gs_setundercolorremoval_remap(pgs, proc, true);
+}
+int
+gs_setundercolorremoval_remap(gs_state *pgs, gs_mapping_proc proc, bool remap)
+{ rc_unshare_struct(pgs->undercolor_removal, gx_transfer_map,
+ &st_transfer_map, pgs->memory,
+ return_error(gs_error_VMerror),
+ "gs_setundercolorremoval");
+ pgs->undercolor_removal->proc = proc;
+ pgs->undercolor_removal->id = gs_next_ids(1);
+ if ( remap )
+ { load_transfer_map(pgs, pgs->undercolor_removal, -1.0);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+}
+
+/* currentundercolorremoval */
+gs_mapping_proc
+gs_currentundercolorremoval(const gs_state *pgs)
+{ return pgs->undercolor_removal->proc;
+}
+
+/* setcolortransfer */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setcolortransfer_remap(gs_state *pgs, gs_mapping_proc red_proc,
+ gs_mapping_proc green_proc, gs_mapping_proc blue_proc,
+ gs_mapping_proc gray_proc, bool remap)
+{ gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+ gx_transfer_colored old;
+ gs_id new_ids = gs_next_ids(4);
+
+ old = *ptran;
+ rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fgray, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->red, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fred, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->green, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fgreen, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->blue, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fblue, "gs_setcolortransfer");
+ ptran->gray->proc = gray_proc;
+ ptran->gray->id = new_ids;
+ ptran->red->proc = red_proc;
+ ptran->red->id = new_ids + 1;
+ ptran->green->proc = green_proc;
+ ptran->green->id = new_ids + 2;
+ ptran->blue->proc = blue_proc;
+ ptran->blue->id = new_ids + 3;
+ if ( remap )
+ { load_transfer_map(pgs, ptran->red, 0.0);
+ load_transfer_map(pgs, ptran->green, 0.0);
+ load_transfer_map(pgs, ptran->blue, 0.0);
+ load_transfer_map(pgs, ptran->gray, 0.0);
+ gx_set_effective_transfer(pgs);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+fblue: rc_assign(ptran->green, old.green, "setcolortransfer");
+fgreen: rc_assign(ptran->red, old.red, "setcolortransfer");
+fred: rc_assign(ptran->gray, old.gray, "setcolortransfer");
+fgray: return_error(gs_error_VMerror);
+}
+int
+gs_setcolortransfer(gs_state *pgs, gs_mapping_proc red_proc,
+ gs_mapping_proc green_proc, gs_mapping_proc blue_proc,
+ gs_mapping_proc gray_proc)
+{ return gs_setcolortransfer_remap(pgs, red_proc, green_proc,
+ blue_proc, gray_proc, true);
+}
+
+/* currentcolortransfer */
+void
+gs_currentcolortransfer(const gs_state *pgs, gs_mapping_proc procs[4])
+{ const gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+ procs[0] = ptran->red->proc;
+ procs[1] = ptran->green->proc;
+ procs[2] = ptran->blue->proc;
+ procs[3] = ptran->gray->proc;
+}
diff --git a/gs/src/gscolor1.h b/gs/src/gscolor1.h
new file mode 100644
index 000000000..a26ec64c6
--- /dev/null
+++ b/gs/src/gscolor1.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor1.h */
+/* Client interface to Level 1 extended color facilities */
+/* Requires gscolor.h */
+
+#ifndef gscolor1_INCLUDED
+# define gscolor1_INCLUDED
+
+/* Color and gray interface */
+int gs_setcmykcolor(P5(gs_state *, floatp, floatp, floatp, floatp)),
+ gs_currentcmykcolor(P2(const gs_state *, float [4])),
+ gs_setblackgeneration(P2(gs_state *, gs_mapping_proc)),
+ gs_setblackgeneration_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currentblackgeneration(P1(const gs_state *));
+int gs_setundercolorremoval(P2(gs_state *, gs_mapping_proc)),
+ gs_setundercolorremoval_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currentundercolorremoval(P1(const gs_state *));
+/* Transfer function */
+int gs_setcolortransfer(P5(gs_state *, gs_mapping_proc /*red*/,
+ gs_mapping_proc /*green*/, gs_mapping_proc /*blue*/,
+ gs_mapping_proc /*gray*/)),
+ gs_setcolortransfer_remap(P6(gs_state *, gs_mapping_proc /*red*/,
+ gs_mapping_proc /*green*/, gs_mapping_proc /*blue*/,
+ gs_mapping_proc /*gray*/, bool));
+void gs_currentcolortransfer(P2(const gs_state *, gs_mapping_proc [4]));
+
+#endif /* gscolor1_INCLUDED */
diff --git a/gs/src/gscolor2.c b/gs/src/gscolor2.c
new file mode 100644
index 000000000..273fc0790
--- /dev/null
+++ b/gs/src/gscolor2.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 1992, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor2.c */
+/* Level 2 color operators for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h" /* ditto */
+#include "gxmatrix.h" /* for gzstate.h */
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gzstate.h"
+
+/* GC descriptors */
+public_st_indexed_map();
+
+/* Define the Indexed color space type. */
+cs_declare_procs(private, gx_concretize_Indexed, gx_install_Indexed,
+ gx_adjust_cspace_Indexed,
+ gx_enum_ptrs_Indexed, gx_reloc_ptrs_Indexed);
+private cs_proc_concrete_space(gx_concrete_space_Indexed);
+const gs_color_space_type
+ gs_color_space_type_Indexed =
+ { gs_color_space_index_Indexed, 1, false,
+ gx_init_paint_1, gx_concrete_space_Indexed,
+ gx_concretize_Indexed, NULL,
+ gx_default_remap_color, gx_install_Indexed,
+ gx_adjust_cspace_Indexed, gx_no_adjust_color_count,
+ gx_enum_ptrs_Indexed, gx_reloc_ptrs_Indexed
+ };
+
+/* setcolorspace */
+int
+gs_setcolorspace(gs_state *pgs, gs_color_space *pcs)
+{ gs_memory_t *mem = pgs->memory;
+ int code;
+ gs_color_space cs_old;
+ gs_client_color cc_old;
+
+ if ( pgs->in_cachedevice )
+ return_error(gs_error_undefined);
+ cs_old = *pgs->color_space;
+ cc_old = *pgs->ccolor;
+ (*pcs->type->adjust_cspace_count)(pcs, mem, 1);
+ *pgs->color_space = *pcs;
+ if ( (code = (*pcs->type->install_cspace)(pcs, pgs)) < 0 )
+ goto rcs;
+ cs_full_init_color(pgs->ccolor, pcs);
+ (*cs_old.type->adjust_color_count)(&cc_old, &cs_old, mem, -1);
+ (*cs_old.type->adjust_cspace_count)(&cs_old, mem, -1);
+ gx_unset_dev_color(pgs);
+ return code;
+ /* Restore the color space if installation failed. */
+rcs: *pgs->color_space = cs_old;
+ (*pcs->type->adjust_cspace_count)(pcs, mem, -1);
+ return code;
+}
+
+/* currentcolorspace */
+const gs_color_space *
+gs_currentcolorspace(const gs_state *pgs)
+{ return pgs->color_space;
+}
+
+/* setcolor */
+int
+gs_setcolor(gs_state *pgs, const gs_client_color *pcc)
+{ gs_memory_t *mem = pgs->memory;
+ gs_color_space *pcs = pgs->color_space;
+
+ if ( pgs->in_cachedevice )
+ return_error(gs_error_undefined);
+ (*pcs->type->adjust_color_count)(pcc, pcs, mem, 1);
+ (*pcs->type->adjust_color_count)(pgs->ccolor, pcs, mem, -1);
+ *pgs->ccolor = *pcc;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentcolor */
+const gs_client_color *
+gs_currentcolor(const gs_state *pgs)
+{ return pgs->ccolor;
+}
+
+/* ------ Internal routines ------ */
+
+/* Color remapping for Indexed color spaces. */
+
+private const gs_color_space *
+gx_concrete_space_Indexed(const gs_color_space *pcs,
+ const gs_imager_state *pis)
+{ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.indexed.base_space;
+ return cs_concrete_space(pbcs, pis);
+}
+
+private int
+gx_concretize_Indexed(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ float value = pc->paint.values[0];
+ int index =
+ (is_fneg(value) ? 0 :
+ value >= pcs->params.indexed.hival ? pcs->params.indexed.hival :
+ (int)value);
+ gs_client_color cc;
+ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.indexed.base_space;
+
+ if ( pcs->params.indexed.use_proc )
+ { int code =
+ (*pcs->params.indexed.lookup.map->proc.lookup_index)
+ (&pcs->params.indexed, index, &cc.paint.values[0]);
+ if ( code < 0 ) return code;
+ }
+ else
+ { int m = pcs->params.indexed.base_space.type->num_components;
+ const byte *pcomp =
+ pcs->params.indexed.lookup.table.data + m * index;
+ switch ( m )
+ {
+ default: return_error(gs_error_rangecheck);
+ case 4: cc.paint.values[3] = pcomp[3] * (1.0 / 255.0);
+ case 3: cc.paint.values[2] = pcomp[2] * (1.0 / 255.0);
+ cc.paint.values[1] = pcomp[1] * (1.0 / 255.0);
+ case 1: cc.paint.values[0] = pcomp[0] * (1.0 / 255.0);
+ }
+ }
+ return (*pbcs->type->concretize_color)(&cc, pbcs, pconc, pis);
+}
+
+/* Color space installation ditto. */
+
+private int
+gx_install_Indexed(gs_color_space *pcs, gs_state *pgs)
+{ return (*pcs->params.indexed.base_space.type->install_cspace)
+ ((gs_color_space *)&pcs->params.indexed.base_space, pgs);
+}
+
+/* Color space reference count adjustment ditto. */
+
+private void
+gx_adjust_cspace_Indexed(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ if ( pcs->params.indexed.use_proc )
+ { rc_adjust_const(pcs->params.indexed.lookup.map, delta,
+ "gx_adjust_Indexed");
+ }
+ (*pcs->params.indexed.base_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.indexed.base_space, mem, delta);
+}
+
+/* GC procedures ditto. */
+
+#define pcs ((gs_color_space *)vptr)
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_Indexed) {
+ return (*pcs->params.indexed.base_space.type->enum_ptrs)
+ (&pcs->params.indexed.base_space,
+ sizeof(pcs->params.indexed.base_space), index-1, pep);
+ }
+ case 0:
+ if ( pcs->params.indexed.use_proc )
+ ENUM_RETURN((void *)pcs->params.indexed.lookup.map);
+ else
+ { pcs->params.indexed.lookup.table.size =
+ (pcs->params.indexed.hival + 1) *
+ pcs->params.indexed.base_space.type->num_components;
+ *pep = &pcs->params.indexed.lookup.table;
+ return ptr_const_string_type;
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_Indexed) {
+ (*pcs->params.indexed.base_space.type->reloc_ptrs)
+ (&pcs->params.indexed.base_space, sizeof(gs_base_color_space), gcst);
+ if ( pcs->params.indexed.use_proc )
+ RELOC_PTR(gs_color_space, params.indexed.lookup.map);
+ else
+ RELOC_CONST_STRING_PTR(gs_color_space, params.indexed.lookup.table);
+} RELOC_PTRS_END
+
+#undef pcs
diff --git a/gs/src/gscolor2.h b/gs/src/gscolor2.h
new file mode 100644
index 000000000..8b8a1759f
--- /dev/null
+++ b/gs/src/gscolor2.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 1992, 1993, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscolor2.h */
+/* Client interface to Level 2 color facilities */
+/* (requires gscspace.h, gsmatrix.h) */
+#include "gsccolor.h"
+#include "gsuid.h" /* for pattern template */
+#include "gxbitmap.h" /* for makebitmappattern */
+
+/* Note: clients should use rc_alloc_struct_0 (in gsrefct.h) to allocate */
+/* CIE color spaces or rendering structures; makepattern uses */
+/* rc_alloc_struct_1 to allocate pattern instances. */
+
+/* General color routines */
+const gs_color_space *gs_currentcolorspace(P1(const gs_state *));
+int gs_setcolorspace(P2(gs_state *, gs_color_space *));
+const gs_client_color *gs_currentcolor(P1(const gs_state *));
+int gs_setcolor(P2(gs_state *, const gs_client_color *));
+
+/* CIE-specific routines */
+#ifndef gs_cie_render_DEFINED
+# define gs_cie_render_DEFINED
+typedef struct gs_cie_render_s gs_cie_render;
+#endif
+const gs_cie_render *gs_currentcolorrendering(P1(const gs_state *));
+int gs_setcolorrendering(P2(gs_state *, gs_cie_render *));
+
+/* Pattern template */
+typedef struct gs_client_pattern_s {
+ gs_uid uid;
+ int PaintType;
+ int TilingType;
+ gs_rect BBox;
+ float XStep;
+ float YStep;
+ int (*PaintProc)(P2(const gs_client_color *, gs_state *));
+ void *client_data; /* additional client data */
+} gs_client_pattern;
+#define private_st_client_pattern() /* in gspcolor.c */\
+ gs_private_st_ptrs1(st_client_pattern, gs_client_pattern,\
+ "client pattern", client_pattern_enum_ptrs, client_pattern_reloc_ptrs,\
+ client_data)
+#define st_client_pattern_max_ptrs 1
+
+/* Pattern-specific routines */
+/* The gs_memory_t argument for makepattern may be null, meaning use the */
+/* same allocator as for the gs_state argument. */
+int gs_makepattern(P5(gs_client_color *, const gs_client_pattern *,
+ const gs_matrix *, gs_state *, gs_memory_t *));
+int gs_setpattern(P2(gs_state *, const gs_client_color *));
+int gs_setpatternspace(P1(gs_state *));
+const gs_client_pattern *gs_getpattern(P1(const gs_client_color *));
+
+/*
+ * Make a pattern from a bitmap or pixmap. The pattern may be colored or
+ * uncolored, as determined by the mask operand. This code is intended
+ * primarily for use by PCL.
+ *
+ * By convention, if pmat is null the identity matrix will be used, and if
+ * id is no_UniqueID the code will assign a unique id. Thes conventions allow
+ * gs_makebitmappattern to be implemented as a macro. Also, if mem is a
+ * null pointer, the memory allocator for the graphic state is used.
+ *
+ * For mask patterns, pix_depth must be 1, while pcspace and white_index are
+ * ignored; the polarity of the mask considers ones part of the mask, while
+ * zeros are not. For colored patterns pspace must point to an indexed color
+ * space and the image must used the canoncial Decode array for this color
+ * space. For both cases no interpolation or adjustment is provided.
+ *
+ * For backwards compatibility, if mask is false, pcspace is null, and
+ * pix_depth is 1, the pattern will be rendered with a color space that maps
+ * 0 to white and 1 to black.
+ *
+ * The image must be described by a gx_tile_bitmap structure (this is actually
+ * somewhat awkward, but the only option available at the moment), and the
+ * pattern step will exactly match the image size. The client need not maintain
+ * the gx_tile_bitmap structure after the completion of this call, but the
+ * raw image data itself must be kept until the pattern is no longer needed.
+ *
+ * NB: For proper handling of transparency in PCL, there must be only a single
+ * white value accessed by the pattern image. If the palette contains
+ * multiple white values, the PCL component must remap the image data to
+ * ensure that all white indices are mapped to the single, given white
+ * index.
+ */
+extern int gs_makepixmappattern( gs_client_color * pcc,
+ const gs_depth_bitmap * pbitmap,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ const gs_color_space * pcspace,
+ uint white_index,
+ gs_state * pgs,
+ gs_memory_t * mem
+ );
+
+/*
+ * Backwards compatibility feature, to allow the existing
+ * gs_makebitmappattern operation to still function.
+ */
+extern int gs_makebitmappattern_xform( gs_client_color * pcc,
+ const gx_tile_bitmap * ptile,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ gs_state * pgs,
+ gs_memory_t * mem
+ );
+
+#define gs_makebitmappattern(pcc, tile, mask, pgs, mem) \
+ gs_makebitmappattern_xform(pcc, tile, mask, 0, (uint)-1, pgs, mem)
diff --git a/gs/src/gscoord.c b/gs/src/gscoord.c
new file mode 100644
index 000000000..1274889c3
--- /dev/null
+++ b/gs/src/gscoord.c
@@ -0,0 +1,471 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscoord.c */
+/* Coordinate system operators for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxfont.h" /* for char_tm */
+#include "gxpath.h" /* for gx_path_translate */
+#include "gzstate.h"
+#include "gxcoord.h" /* requires gsmatrix, gsstate */
+#include "gxdevice.h"
+
+/* Choose whether to enable the rounding code in update_ctm. */
+#define ROUND_CTM_FIXED 1
+
+/* Forward declarations */
+#ifdef DEBUG
+#define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
+private void near trace_matrix_fixed(P1(const gs_matrix_fixed *));
+private void near trace_matrix(P1(const gs_matrix *));
+#endif
+
+/* Macro for ensuring ctm_inverse is valid */
+#ifdef DEBUG
+#define print_inverse(pgs)\
+if ( gs_debug_c('x') )\
+ dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
+#else
+#define print_inverse(pgs) DO_NOTHING
+#endif
+#define ensure_inverse_valid(pgs)\
+ if ( !pgs->ctm_inverse_valid )\
+ { int code = ctm_set_inverse(pgs);\
+ if ( code < 0 ) return code;\
+ }
+
+private int
+ctm_set_inverse(gs_state *pgs)
+{ int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
+ print_inverse(pgs);
+ if ( code < 0 ) return code;
+ pgs->ctm_inverse_valid = true;
+ return 0;
+}
+
+/* Machinery for updating fixed version of ctm. */
+/*
+ * We (conditionally) adjust the floating point translation
+ * so that it exactly matches the (rounded) fixed translation.
+ * This avoids certain unpleasant rounding anomalies, such as
+ * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
+ * not returning 0 0.
+ */
+#if ROUND_CTM_FIXED
+# define update_t_fixed(mat, t, t_fixed, v)\
+ (set_float2fixed_vars((mat).t_fixed, v),\
+ set_fixed2float_var((mat).t, (mat).t_fixed))
+#else /* !ROUND_CTM_FIXED */
+# define update_t_fixed(mat, t, t_fixed, v)\
+ ((mat).t = (v),\
+ set_float2fixed_vars((mat).t_fixed, (mat).t))
+#endif /* (!)ROUND_CTM_FIXED */
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+#define update_matrix_fixed(mat, xt, yt)\
+ ((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
+ (update_t_fixed(mat, tx, tx_fixed, xt),\
+ update_t_fixed(mat, ty, ty_fixed, yt), true) :\
+ ((mat).tx = (xt), (mat).ty = (yt), false)))
+#define update_ctm(pgs, xt, yt)\
+ (pgs->ctm_inverse_valid = false,\
+ pgs->char_tm_valid = false,\
+ update_matrix_fixed(pgs->ctm, xt, yt))
+
+/* ------ Coordinate system definition ------ */
+
+int
+gs_initmatrix(gs_state *pgs)
+{ gs_matrix imat;
+ gs_defaultmatrix(pgs, &imat);
+ update_ctm(pgs, imat.tx, imat.ty);
+ set_ctm_only(pgs, imat);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
+{ gx_device *dev;
+ if ( pgs->ctm_default_set ) /* set after Install */
+ { *pmat = pgs->ctm_default;
+ return 1;
+ }
+ dev = gs_currentdevice_inline(pgs);
+ gs_deviceinitialmatrix(dev, pmat);
+ /* Add in the translation for the Margins. */
+ pmat->tx += dev->Margins[0] *
+ dev->HWResolution[0] / dev->MarginsHWResolution[0];
+ pmat->ty += dev->Margins[1] *
+ dev->HWResolution[1] / dev->MarginsHWResolution[1];
+ return 0;
+}
+
+int
+gs_setdefaultmatrix(gs_state *pgs, const gs_matrix *pmat)
+{ if ( pmat == NULL )
+ pgs->ctm_default_set = false;
+ else
+ { pgs->ctm_default = *pmat;
+ pgs->ctm_default_set = true;
+ }
+ return 0;
+}
+
+int
+gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
+{ *pmat = ctm_only(pgs);
+ return 0;
+}
+
+/* Set the current transformation matrix for rendering text. */
+/* Note that this may be based on a font other than the current font. */
+int
+gs_setcharmatrix(gs_state *pgs, const gs_matrix *pmat)
+{ gs_matrix cmat;
+ int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
+ if ( code < 0 )
+ return code;
+ update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
+ char_tm_only(pgs) = cmat;
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
+#endif
+ pgs->char_tm_valid = true;
+ return 0;
+}
+
+/* Read (after possibly computing) the current transformation matrix */
+/* for rendering text. If force=true, update char_tm if it is invalid; */
+/* if force=false, don't update char_tm, and return an error code. */
+int
+gs_currentcharmatrix(gs_state *pgs, gs_matrix *ptm, bool force)
+{ if ( !pgs->char_tm_valid )
+ { int code;
+ if ( !force )
+ return_error(gs_error_undefinedresult);
+ code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
+ if ( code < 0 )
+ return code;
+ }
+ if ( ptm != NULL )
+ *ptm = char_tm_only(pgs);
+ return 0;
+}
+
+int
+gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
+{ update_ctm(pgs, pmat->tx, pmat->ty);
+ set_ctm_only(pgs, *pmat);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_imager_setmatrix(gs_imager_state *pis, const gs_matrix *pmat)
+{ update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
+ set_ctm_only(pis, *pmat);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
+#endif
+ return 0;
+}
+
+int
+gs_settocharmatrix(gs_state *pgs)
+{ if ( pgs->char_tm_valid )
+ { pgs->ctm = pgs->char_tm;
+ pgs->ctm_inverse_valid = false;
+ return 0;
+ }
+ else
+ return_error(gs_error_undefinedresult);
+}
+
+int
+gs_translate(gs_state *pgs, floatp dx, floatp dy)
+{ gs_point pt;
+ int code;
+ if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
+ return code;
+ pt.x += pgs->ctm.tx;
+ pt.y += pgs->ctm.ty;
+ update_ctm(pgs, pt.x, pt.y);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf4("[x]translate: %f %f -> %f %f\n",
+ dx, dy, pt.x, pt.y),
+ trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_scale(gs_state *pgs, floatp sx, floatp sy)
+{ pgs->ctm.xx *= sx;
+ pgs->ctm.xy *= sx;
+ pgs->ctm.yx *= sy;
+ pgs->ctm.yy *= sy;
+ pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_rotate(gs_state *pgs, floatp ang)
+{ int code = gs_matrix_rotate(&ctm_only(pgs), ang,
+ &ctm_only_writable(pgs));
+ pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
+#endif
+ return code;
+}
+
+int
+gs_concat(gs_state *pgs, const gs_matrix *pmat)
+{ gs_matrix cmat;
+ int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
+ if ( code < 0 )
+ return code;
+ update_ctm(pgs, cmat.tx, cmat.ty);
+ set_ctm_only(pgs, cmat);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
+#endif
+ return code;
+}
+
+/* ------ Coordinate transformation ------ */
+
+#define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
+
+int
+gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
+{ return gs_point_transform(x, y, &ctm_only(pgs), pt);
+}
+
+int
+gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
+{ return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
+}
+
+int
+gs_itransform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
+{ /* If the matrix isn't skewed, we get more accurate results */
+ /* by using transform_inverse than by using the inverse matrix. */
+ if ( !is_skewed(&pgs->ctm) )
+ { return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
+ }
+ else
+ { ensure_inverse_valid(pgs);
+ return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
+ }
+}
+
+int
+gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
+{ /* If the matrix isn't skewed, we get more accurate results */
+ /* by using transform_inverse than by using the inverse matrix. */
+ if ( !is_skewed(&pgs->ctm) )
+ { return gs_distance_transform_inverse(dx, dy,
+ &ctm_only(pgs), pt);
+ }
+ else
+ { ensure_inverse_valid(pgs);
+ return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
+ }
+}
+
+int
+gs_imager_idtransform(const gs_imager_state *pis, floatp dx, floatp dy,
+ gs_point *pt)
+{ return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
+}
+
+/* ------ For internal use only ------ */
+
+/* Set the translation to a fixed value, and translate any existing path. */
+/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
+int
+gx_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
+{ double fpx = fixed2float(px);
+ double fdx = fpx - pgs->ctm.tx;
+ double fpy = fixed2float(py);
+ double fdy = fpy - pgs->ctm.ty;
+ fixed dx, dy;
+ int code;
+
+ if ( pgs->ctm.txy_fixed_valid )
+ { dx = float2fixed(fdx);
+ dy = float2fixed(fdy);
+ code = gx_path_translate(pgs->path, dx, dy);
+ if ( code < 0 )
+ return code;
+ if ( pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid )
+ pgs->char_tm.tx_fixed += dx,
+ pgs->char_tm.ty_fixed += dy;
+ }
+ else
+ { if ( !gx_path_is_null(pgs->path) )
+ return_error(gs_error_limitcheck);
+ }
+ pgs->ctm.tx = fpx;
+ pgs->ctm.tx_fixed = px;
+ pgs->ctm.ty = fpy;
+ pgs->ctm.ty_fixed = py;
+ pgs->ctm.txy_fixed_valid = true;
+ pgs->ctm_inverse_valid = false;
+ if ( pgs->char_tm_valid )
+ { /* Update char_tm now, leaving it valid. */
+ pgs->char_tm.tx += fdx;
+ pgs->char_tm.ty += fdy;
+ }
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ dprintf2("[x]translate_to_fixed %g, %g:\n",
+ fixed2float(px), fixed2float(py)),
+ trace_ctm(pgs),
+ dprintf("[x] char_tm:\n"),
+ trace_matrix_fixed(&pgs->char_tm);
+#endif
+ return 0;
+}
+
+/* Scale the CTM and character matrix for oversampling. */
+int
+gx_scale_char_matrix(register gs_state *pgs, int sx, int sy)
+{
+#define scale_cxy(s, vx, vy)\
+ if ( s != 1 )\
+ { pgs->ctm.vx *= s;\
+ pgs->ctm.vy *= s;\
+ pgs->ctm_inverse_valid = false;\
+ if ( pgs->char_tm_valid )\
+ { pgs->char_tm.vx *= s;\
+ pgs->char_tm.vy *= s;\
+ }\
+ }
+ scale_cxy(sx, xx, yx);
+ scale_cxy(sy, xy, yy);
+#undef scale_cxy
+ if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
+ return 0;
+}
+
+/* Compute the coefficients for fast fixed-point distance transformations */
+/* from a transformation matrix. */
+/* We should cache the coefficients with the ctm.... */
+int
+gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
+ int max_bits)
+{ gs_matrix ctm;
+ int scale = -10000;
+ int expt, shift;
+ ctm = *pmat;
+ pfc->skewed = 0;
+ if ( !is_fzero(ctm.xx) )
+ { discard(frexp(ctm.xx, &scale));
+ }
+ if ( !is_fzero(ctm.xy) )
+ { discard(frexp(ctm.xy, &expt));
+ if ( expt > scale ) scale = expt;
+ pfc->skewed = 1;
+ }
+ if ( !is_fzero(ctm.yx) )
+ { discard(frexp(ctm.yx, &expt));
+ if ( expt > scale ) scale = expt;
+ pfc->skewed = 1;
+ }
+ if ( !is_fzero(ctm.yy) )
+ { discard(frexp(ctm.yy, &expt));
+ if ( expt > scale ) scale = expt;
+ }
+ scale = sizeof(long) * 8 - 1 - max_bits - scale;
+ shift = scale - _fixed_shift;
+ if ( shift > 0 )
+ { pfc->shift = shift;
+ pfc->round = (fixed)1 << (shift - 1);
+ }
+ else
+ { pfc->shift = 0;
+ pfc->round = 0;
+ scale -= shift;
+ }
+#define set_c(c)\
+ if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
+ else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
+ set_c(xx);
+ set_c(xy);
+ set_c(yx);
+ set_c(yy);
+#ifdef DEBUG
+if ( gs_debug_c('x') )
+ { dprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
+ ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
+ dprintf6(" scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
+ scale, pfc->xx.l, pfc->xy.l, pfc->yx.l, pfc->yy.l,
+ pfc->shift);
+ }
+#endif
+ pfc->max_bits = max_bits;
+ return 0;
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print a matrix */
+private void near
+trace_matrix_fixed(const gs_matrix_fixed *pmat)
+{ trace_matrix((const gs_matrix *)pmat);
+ if ( pmat->txy_fixed_valid )
+ { dprintf2("\t\tt_fixed: [%6g %6g]\n",
+ fixed2float(pmat->tx_fixed),
+ fixed2float(pmat->ty_fixed));
+ }
+ else
+ { dputs("\t\tt_fixed not valid\n");
+ }
+}
+private void near
+trace_matrix(register const gs_matrix *pmat)
+{ dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+}
+
+#endif
diff --git a/gs/src/gscoord.h b/gs/src/gscoord.h
new file mode 100644
index 000000000..6cb7f9dd7
--- /dev/null
+++ b/gs/src/gscoord.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscoord.h */
+/* Client interface to coordinate system operations */
+/* Requires gsmatrix.h and gsstate.h */
+
+/* Coordinate system modification */
+int gs_initmatrix(P1(gs_state *)),
+ gs_defaultmatrix(P2(const gs_state *, gs_matrix *)),
+ gs_currentmatrix(P2(const gs_state *, gs_matrix *)),
+ gs_setmatrix(P2(gs_state *, const gs_matrix *)),
+ gs_translate(P3(gs_state *, floatp, floatp)),
+ gs_scale(P3(gs_state *, floatp, floatp)),
+ gs_rotate(P2(gs_state *, floatp)),
+ gs_concat(P2(gs_state *, const gs_matrix *));
+/* Extensions */
+int gs_setdefaultmatrix(P2(gs_state *, const gs_matrix *)),
+ gs_currentcharmatrix(P3(gs_state *, gs_matrix *, bool)),
+ gs_setcharmatrix(P2(gs_state *, const gs_matrix *)),
+ gs_settocharmatrix(P1(gs_state *));
+
+/* Coordinate transformation */
+int gs_transform(P4(gs_state *, floatp, floatp, gs_point *)),
+ gs_dtransform(P4(gs_state *, floatp, floatp, gs_point *)),
+ gs_itransform(P4(gs_state *, floatp, floatp, gs_point *)),
+ gs_idtransform(P4(gs_state *, floatp, floatp, gs_point *));
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+
+int gs_imager_setmatrix(P2(gs_imager_state *, const gs_matrix *));
+int gs_imager_idtransform(P4(const gs_imager_state *, floatp, floatp,
+ gs_point *));
diff --git a/gs/src/gscpm.h b/gs/src/gscpm.h
new file mode 100644
index 000000000..e35cb4eaf
--- /dev/null
+++ b/gs/src/gscpm.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscpm.h */
+/* Charpath mode definitions */
+
+#ifndef gscpm_INCLUDED
+# define gscpm_INCLUDED
+
+typedef enum {
+ cpm_show, /* *show (default, must be 0) */
+ cpm_false_charpath, /* false charpath */
+ cpm_true_charpath, /* true charpath */
+ cpm_false_charboxpath, /* false charboxpath (not standard PS) */
+ cpm_true_charboxpath /* true charboxpath (ditto) */
+} gs_char_path_mode;
+
+#endif /* gscpm_INCLUDED */
diff --git a/gs/src/gscrypt1.h b/gs/src/gscrypt1.h
new file mode 100644
index 000000000..8c73905e1
--- /dev/null
+++ b/gs/src/gscrypt1.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1990, 1992, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscrypt1.h */
+/* Interface to Adobe Type 1 encryption/decryption. */
+
+/* Normal public interface */
+typedef ushort crypt_state;
+int gs_type1_encrypt(P4(byte *dest, const byte *src, uint len,
+ crypt_state *pstate));
+int gs_type1_decrypt(P4(byte *dest, const byte *src, uint len,
+ crypt_state *pstate));
+
+/* Define the encryption parameters and procedures. */
+#define crypt_c1 ((ushort)52845)
+#define crypt_c2 ((ushort)22719)
+/* c1 * c1' == 1 mod 2^16. */
+#define crypt_c1_inverse ((ushort)27493)
+#define encrypt_next(ch, state, chvar)\
+ (chvar = ((ch) ^ (state >> 8)),\
+ state = (chvar + state) * crypt_c1 + crypt_c2)
+#define decrypt_this(ch, state)\
+ ((ch) ^ (state >> 8))
+#define decrypt_next(ch, state, chvar)\
+ (chvar = decrypt_this(ch, state),\
+ decrypt_skip_next(ch, state))
+#define decrypt_skip_next(ch, state)\
+ (state = ((ch) + state) * crypt_c1 + crypt_c2)
+#define decrypt_skip_previous(ch, state)\
+ (state = (state - crypt_c2) * crypt_c1_inverse - (ch))
diff --git a/gs/src/gscsel.h b/gs/src/gscsel.h
new file mode 100644
index 000000000..512aa7b61
--- /dev/null
+++ b/gs/src/gscsel.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscsel.h */
+/* Definitions for color operand selection */
+
+#ifndef gscsel_INCLUDED
+# define gscsel_INCLUDED
+
+/*
+ * Define whether we are mapping a "source" or a "texture" color for
+ * RasterOp. Right the source and texture only have separate halftone
+ * phases in the graphics state, but someday they might have more.
+ */
+typedef enum {
+ gs_color_select_all = -1, /* for setting only, not for reading */
+ gs_color_select_texture = 0, /* 0 is the one is used for currenthtphase */
+ gs_color_select_source = 1
+} gs_color_select_t;
+#define gs_color_select_count 2
+
+#endif /* gscsel_INCLUDED */
diff --git a/gs/src/gscsepr.c b/gs/src/gscsepr.c
new file mode 100644
index 000000000..3ada6f9e5
--- /dev/null
+++ b/gs/src/gscsepr.c
@@ -0,0 +1,176 @@
+/* Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscsepr.c */
+/* Separation color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscsepr.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h" /* for gs_indexed_map */
+#include "gzstate.h" /* for pgs->overprint */
+
+extern gs_memory_t *gs_state_memory(P1(const gs_state *));
+
+/* Define the Separation color space type. */
+cs_declare_procs(private, gx_concretize_Separation, gx_install_Separation,
+ gx_adjust_cspace_Separation,
+ gx_enum_ptrs_Separation, gx_reloc_ptrs_Separation);
+private cs_proc_concrete_space(gx_concrete_space_Separation);
+private cs_proc_remap_concrete_color(gx_remap_concrete_Separation);
+private cs_proc_init_color(gx_init_Separation);
+const gs_color_space_type
+ gs_color_space_type_Separation =
+ { gs_color_space_index_Separation, 1, false,
+ gx_init_Separation, gx_concrete_space_Separation,
+ gx_concretize_Separation, gx_remap_concrete_Separation,
+ gx_default_remap_color, gx_install_Separation,
+ gx_adjust_cspace_Separation, gx_no_adjust_color_count,
+ gx_enum_ptrs_Separation, gx_reloc_ptrs_Separation
+ };
+
+/* setoverprint */
+void
+gs_setoverprint(gs_state *pgs, bool ovp)
+{ pgs->overprint = ovp;
+}
+
+/* currentoverprint */
+bool
+gs_currentoverprint(const gs_state *pgs)
+{ return pgs->overprint;
+}
+
+/* ------ Internal routines ------ */
+
+/* Initialize a Separation color. */
+
+private void
+gx_init_Separation(gs_client_color *pcc, const gs_color_space *pcs)
+{ pcc->paint.values[0] = 1.0;
+}
+
+/* Remap a Separation color. */
+
+private const gs_color_space *
+gx_concrete_space_Separation(const gs_color_space *pcs,
+ const gs_imager_state *pis)
+{ /* We don't support concrete Separation spaces yet. */
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.separation.alt_space;
+ return cs_concrete_space(pacs, pis);
+}
+
+private int
+gx_concretize_Separation(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ float tint = pc->paint.values[0];
+ int code;
+ gs_client_color cc;
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.separation.alt_space;
+
+ if ( tint < 0 ) tint = 0;
+ else if ( tint > 1 ) tint = 1;
+ /* We always map into the alternate color space. */
+ code = (*pcs->params.separation.map->proc.tint_transform)(&pcs->params.separation, tint, &cc.paint.values[0]);
+ if ( code < 0 ) return code;
+ return (*pacs->type->concretize_color)(&cc, pacs, pconc, pis);
+}
+
+private int
+gx_remap_concrete_Separation(const frac *pconc,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ /* We don't support concrete Separation colors yet. */
+ return_error(gs_error_rangecheck);
+}
+
+/* Install a Separation color space. */
+
+private int
+gx_install_Separation(gs_color_space *pcs, gs_state *pgs)
+{ return (*pcs->params.separation.alt_space.type->install_cspace)
+ ((gs_color_space *)&pcs->params.separation.alt_space, pgs);
+}
+
+/* Adjust the reference count of a Separation color space. */
+
+private void
+gx_adjust_cspace_Separation(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ rc_adjust_const(pcs->params.separation.map, delta,
+ "gx_adjust_Separation");
+ (*pcs->params.separation.alt_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.separation.alt_space, mem, delta);
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private ENUM_PTRS_BEGIN(gx_enum_ptrs_Separation) {
+ return (*pcs->params.separation.alt_space.type->enum_ptrs)
+ (&pcs->params.separation.alt_space,
+ sizeof(pcs->params.separation.alt_space), index-1, pep);
+ }
+ ENUM_PTR(0, gs_color_space, params.separation.map);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_Separation) {
+ RELOC_PTR(gs_color_space, params.separation.map);
+ (*pcs->params.separation.alt_space.type->reloc_ptrs)
+ (&pcs->params.separation.alt_space, sizeof(gs_base_color_space), gcst);
+} RELOC_PTRS_END
+
+#undef pcs
+
+/* ---------------- Notes on real Separation colors ---------------- */
+
+typedef ulong gs_separation; /* BOGUS */
+#define gs_no_separation ((gs_separation)(-1L))
+
+#define dev_proc_lookup_separation(proc)\
+ gs_separation proc(P4(gx_device *dev, const byte *sname, uint len,\
+ gx_color_value *num_levels))
+
+#define dev_proc_map_tint_color(proc)\
+ gx_color_index proc(P4(gx_device *dev, gs_separation sepr, bool overprint,\
+ gx_color_value tint))
+
+/*
+ * In principle, setting a Separation color space, or setting the device
+ * when the current color space is a Separation space, calls the
+ * lookup_separation device procedure to obtain the separation ID and
+ * the number of achievable levels. Currently, the only hooks for doing
+ * this are unsuitable: gx_set_cmap_procs isn't called when the color
+ * space changes, and doing it in gx_remap_Separation is inefficient.
+ * Probably the best approach is to call gx_set_cmap_procs whenever the
+ * color space changes. In fact, if we do this, we can probably short-cut
+ * two levels of procedure call in color remapping (gx_remap_color, by
+ * turning it into a macro, and gx_remap_DeviceXXX, by calling the
+ * cmap_proc procedure directly). Some care will be required for the
+ * implicit temporary resetting of the color space in [color]image.
+ *
+ * For actual remapping of Separation colors, we need cmap_separation_direct
+ * and cmap_separation_halftoned, just as for the other device color spaces.
+ * So we need to break apart gx_render_gray in gxdither.c so it can also
+ * do the job for separations.
+ */
diff --git a/gs/src/gscsepr.h b/gs/src/gscsepr.h
new file mode 100644
index 000000000..190ac70df
--- /dev/null
+++ b/gs/src/gscsepr.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* Client interface to Separation color */
+
+bool gs_currentoverprint(P1(const gs_state *));
+void gs_setoverprint(P2(gs_state *, bool));
diff --git a/gs/src/gscspace.h b/gs/src/gscspace.h
new file mode 100644
index 000000000..32c30196b
--- /dev/null
+++ b/gs/src/gscspace.h
@@ -0,0 +1,189 @@
+/* Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gscspace.h */
+/* Client interface to color spaces */
+
+#ifndef gscspace_INCLUDED
+# define gscspace_INCLUDED
+
+/* Color space type indices */
+typedef enum {
+ /* Supported in all configurations */
+ gs_color_space_index_DeviceGray = 0,
+ gs_color_space_index_DeviceRGB,
+ /* Supported in extended Level 1, and in Level 2 */
+ gs_color_space_index_DeviceCMYK,
+ /* Supported in Level 2 only */
+ /* DEC C truncates identifiers at 32 characters, so.... */
+ gs_color_space_index_CIEDEFG,
+ gs_color_space_index_CIEDEF,
+ gs_color_space_index_CIEABC,
+ gs_color_space_index_CIEA,
+ gs_color_space_index_Separation,
+ gs_color_space_index_Indexed,
+ gs_color_space_index_Pattern
+} gs_color_space_index;
+
+/* Define the abstract type for color space objects. */
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+#endif
+
+/*
+ * We preallocate instances of the 3 device color spaces, and provide
+ * procedures that return them (to avoid upsetting compilers that don't
+ * allow extern pointers to abstract types). Note that
+ * gs_color_space_DeviceCMYK() may return NULL if CMYK color support is not
+ * included in this configuration.
+ */
+extern const gs_color_space *gs_color_space_DeviceGray(P0());
+extern const gs_color_space *gs_color_space_DeviceRGB(P0());
+extern const gs_color_space *gs_color_space_DeviceCMYK(P0());
+
+/*
+ * Color spaces are complicated because different spaces involve
+ * different kinds of parameters, as follows:
+
+Space Space parameters Color parameters
+----- ---------------- ----------------
+DeviceGray (none) 1 real [0-1]
+DeviceRGB (none) 3 reals [0-1]
+DeviceCMYK (none) 4 reals [0-1]
+CIEBasedDEFG dictionary 4 reals
+CIEBasedDEF dictionary 3 reals
+CIEBasedABC dictionary 3 reals
+CIEBasedA dictionary 1 real
+Separation name, alt_space, tint_xform 1 real [0-1]
+Indexed base_space, hival, lookup 1 int [0-hival]
+Pattern colored: (none) dictionary
+ uncolored: base_space dictionary + base space params
+
+Space Underlying or alternate space
+----- -----------------------------
+Separation Device, CIE
+Indexed Device, CIE
+Pattern Device, CIE, Separation, Indexed
+
+ * Logically speaking, each color space type should be a different
+ * structure type at the allocator level. This would potentially require
+ * either reference counting or garbage collector for color spaces, but that
+ * is probably better than the current design, which uses fixed-size color
+ * space objects and a second level of type discrimination.
+ */
+
+/* Define abstract structure types for color space parameters. */
+typedef struct gs_cie_defg_s gs_cie_defg;
+typedef struct gs_cie_def_s gs_cie_def;
+typedef struct gs_cie_abc_s gs_cie_abc;
+typedef struct gs_cie_a_s gs_cie_a;
+typedef struct gs_separation_params_s gs_separation_params;
+typedef struct gs_indexed_params_s gs_indexed_params;
+
+/* Define an abstract type for color space types. */
+typedef struct gs_color_space_type_s gs_color_space_type;
+
+/* ---------------- Color spaces per se ---------------- */
+
+ /* Base color spaces (Device and CIE) */
+
+/*typedef struct gs_cie_defg_s gs_cie_defg;*/
+/*typedef struct gs_cie_def_s gs_cie_def;*/
+/*typedef struct gs_cie_abc_s gs_cie_abc;*/
+/*typedef struct gs_cie_a_s gs_cie_a;*/
+#define gs_base_cspace_params\
+ gs_cie_defg *defg;\
+ gs_cie_def *def;\
+ gs_cie_abc *abc;\
+ gs_cie_a *a
+typedef struct gs_base_color_space_s {
+ const gs_color_space_type _ds *type;
+ union {
+ gs_base_cspace_params;
+ } params;
+} gs_base_color_space;
+
+ /* Paint (non-pattern) color spaces (base + Separation + Indexed) */
+
+typedef ulong gs_separation_name; /* BOGUS */
+
+typedef struct gs_indexed_map_s gs_indexed_map;
+/*typedef struct gs_separation_params_s gs_separation_params;*/
+struct gs_separation_params_s {
+ gs_separation_name sname;
+ gs_base_color_space alt_space;
+ gs_indexed_map *map;
+};
+/*typedef struct gs_indexed_params_s gs_indexed_params;*/
+struct gs_indexed_params_s {
+ gs_base_color_space base_space;
+ int hival;
+ union {
+ gs_const_string table; /* size is implicit */
+ gs_indexed_map *map;
+ } lookup;
+ bool use_proc; /* 0 = use table, 1 = use proc & map */
+};
+#define gs_paint_cspace_params\
+ gs_base_cspace_params;\
+ gs_separation_params separation;\
+ gs_indexed_params indexed
+typedef struct gs_paint_color_space_s {
+ const gs_color_space_type _ds *type;
+ union {
+ gs_paint_cspace_params;
+ } params;
+} gs_paint_color_space;
+
+ /* General color spaces (including patterns) */
+
+typedef struct gs_pattern_params_s {
+ bool has_base_space;
+ gs_paint_color_space base_space;
+} gs_pattern_params;
+struct gs_color_space_s {
+ const gs_color_space_type _ds *type;
+ union {
+ gs_paint_cspace_params;
+ gs_pattern_params pattern;
+ } params;
+};
+/*extern_st(st_color_space);*/ /* in gxcspace.h */
+#define public_st_color_space() /* in gscolor.c */\
+ gs_public_st_composite(st_color_space, gs_color_space,\
+ "gs_color_space", color_space_enum_ptrs, color_space_reloc_ptrs)
+#define st_color_space_max_ptrs 2 /* 1 base + 1 indexed */
+
+/* ---------------- Procedures ---------------- */
+
+/* Get the index of a color space. */
+gs_color_space_index gs_color_space_get_index(P1(const gs_color_space *));
+
+/* Get the number of components in a color space. */
+int gs_color_space_num_components(P1(const gs_color_space *));
+
+/* Get the base space of an Indexed color space. */
+/* We have to redefine this because the VAX VMS C compiler (but not */
+/* the preprocessor!) limits identifiers to 31 characters. */
+#define gs_color_space_indexed_base_space(pcs)\
+ gs_color_space_indexed_base(pcs)
+const gs_color_space *
+ gs_color_space_indexed_base_space(P1(const gs_color_space *));
+
+#endif /* gscspace_INCLUDED */
diff --git a/gs/src/gsdcolor.h b/gs/src/gsdcolor.h
new file mode 100644
index 000000000..5fa5345fc
--- /dev/null
+++ b/gs/src/gsdcolor.h
@@ -0,0 +1,310 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdcolor.h */
+/* Device color representation for drivers */
+
+#ifndef gsdcolor_INCLUDED
+# define gsdcolor_INCLUDED
+
+#include "gsccolor.h"
+#include "gxarith.h" /* for imod */
+#include "gxbitmap.h"
+#include "gxhttile.h"
+#include "gxcindex.h"
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The definitions in the following section of the file are the only
+ * ones that should be used by read-only clients such as implementors
+ * of high-level driver functions.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * A device color consists of a base color and an optional (tiled) mask.
+ * The base color may be a pure color, a binary halftone, or a colored
+ * bitmap (color halftone or colored Pattern). The mask is used for
+ * both colored and uncolored Patterns.
+ */
+
+/* Accessing a pure color. */
+#define gx_dc_is_pure(pdc)\
+ ((pdc)->type == gx_dc_type_pure)
+#define gx_dc_writes_pure(pdc, lop)\
+ (gx_dc_is_pure(pdc) && lop_no_S_is_T(lop))
+#define gx_dc_pure_color(pdc)\
+ ((pdc)->colors.pure)
+
+/* Accessing the phase of a halftone. */
+#define gx_dc_phase(pdc)\
+ ((pdc)->phase)
+
+/* Accessing a binary halftone. */
+#define gx_dc_is_binary_halftone(pdc)\
+ ((pdc)->type == gx_dc_type_ht_binary)
+#define gx_dc_binary_tile(pdc)\
+ (&(pdc)->colors.binary.b_tile->tiles)
+#define gx_dc_binary_color0(pdc)\
+ ((pdc)->colors.binary.color[0])
+#define gx_dc_binary_color1(pdc)\
+ ((pdc)->colors.binary.color[1])
+
+/* Accessing a colored halftone. */
+#define gx_dc_is_colored_halftone(pdc)\
+ ((pdc)->type == gx_dc_type_ht_colored)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The definitions in the following section of the file, plus the ones
+ * just above, are the only ones that should be used by clients that
+ * set as well as read device colors.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define color_is_set(pdc)\
+ ((pdc)->type != gx_dc_type_none)
+#define color_unset(pdc)\
+ ((pdc)->type = gx_dc_type_none)
+
+#define gx_dc_is_null(pdc)\
+ ((pdc)->type == gx_dc_type_null)
+#define color_is_null(pdc) gx_dc_is_null(pdc)
+#define color_set_null(pdc)\
+ ((pdc)->type = gx_dc_type_null)
+
+#define color_is_pure(pdc) gx_dc_is_pure(pdc)
+#define color_writes_pure(pdc, lop) gx_dc_writes_pure(pdc, lop)
+#define color_set_pure(pdc, color)\
+ ((pdc)->colors.pure = (color),\
+ (pdc)->type = gx_dc_type_pure)
+
+/* Set the phase to an offset from the tile origin. */
+#define color_set_phase(pdc, px, py)\
+ ((pdc)->phase.x = (px),\
+ (pdc)->phase.y = (py))
+/* Set the phase from the halftone phase in a graphics state. */
+#define color_set_phase_mod(pdc, px, py, tw, th)\
+ color_set_phase(pdc, imod(-(px), tw), imod(-(py), th))
+
+#define color_is_binary_halftone(pdc) gx_dc_is_binary_halftone(pdc)
+#define color_set_binary_halftone(pdc, ht, color0, color1, level)\
+ ((pdc)->colors.binary.b_ht = (ht),\
+ (pdc)->colors.binary.color[0] = (color0),\
+ (pdc)->colors.binary.color[1] = (color1),\
+ (pdc)->colors.binary.b_level = (level),\
+ (pdc)->type = gx_dc_type_ht_binary)
+#define color_set_binary_tile(pdc, color0, color1, tile)\
+ ((pdc)->colors.binary.b_ht = 0,\
+ (pdc)->colors.binary.color[0] = (color0),\
+ (pdc)->colors.binary.color[1] = (color1),\
+ (pdc)->colors.binary.b_tile = (tile),\
+ (pdc)->type = gx_dc_type_ht_binary)
+
+#define color_is_colored_halftone(pdc) gx_dc_is_colored_halftone(pdc)
+#define _color_set_c(pdc, i, b, l)\
+ ((pdc)->colors.colored.c_base[i] = (b),\
+ (pdc)->colors.colored.c_level[i] = (l))
+#define color_set_rgb_halftone(pdc, ht, br, lr, bg, lg, bb, lb, a)\
+ ((pdc)->colors.colored.c_ht = (ht),\
+ _color_set_c(pdc, 0, br, lr),\
+ _color_set_c(pdc, 1, bg, lg),\
+ _color_set_c(pdc, 2, bb, lb),\
+ (pdc)->colors.colored.alpha = (a),\
+ (pdc)->type = gx_dc_type_ht_colored)
+/* Some special clients set the individual components separately. */
+#define color_finish_set_cmyk_halftone(pdc, ht)\
+ ((pdc)->colors.colored.c_ht = (ht),\
+ (pdc)->colors.colored.alpha = max_ushort,\
+ (pdc)->type = gx_dc_type_ht_colored)
+#define color_set_cmyk_halftone(pdc, ht, bc, lc, bm, lm, by, ly, bk, lk)\
+ (_color_set_c(pdc, 0, bc, lc),\
+ _color_set_c(pdc, 1, bm, lm),\
+ _color_set_c(pdc, 2, by, ly),\
+ _color_set_c(pdc, 3, bk, lk),\
+ color_finish_set_cmyk_halftone(pdc, ht))
+
+/* Note that color_set_null_pattern doesn't set mask.ccolor. */
+#define color_set_null_pattern(pdc)\
+ ((pdc)->mask.id = gx_no_bitmap_id,\
+ (pdc)->mask.m_tile = 0,\
+ (pdc)->colors.pattern.p_tile = 0,\
+ (pdc)->type = gx_dc_type_pattern)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The remaining definitions are internal ones that are included in this
+ * file only because C's abstraction mechanisms aren't strong enough to
+ * allow us to keep them separate and still have in-line access to the
+ * commonly used members.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Define opaque types for objects referenced by device colors. */
+
+#ifndef gx_ht_tile_DEFINED
+# define gx_ht_tile_DEFINED
+typedef struct gx_ht_tile_s gx_ht_tile;
+#endif
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+#endif
+
+#ifndef gx_color_tile_DEFINED
+# define gx_color_tile_DEFINED
+typedef struct gx_color_tile_s gx_color_tile;
+#endif
+
+/*
+ * The device color in the graphics state is computed from client color
+ * specifications, and kept current through changes in transfer function,
+ * device, and (if relevant) halftone phase.
+ * (gx_set_dev_color sets the device color if needed.)
+ * For binary halftones (and eventually colored halftones as well),
+ * the bitmaps are only cached, so internal clients (the painting operators)
+ * must call gx_color_load to ensure that the bitmap is available.
+ * Device color elements set by gx_color_load are marked with @ below.
+ *
+ * Base colors are represented as follows:
+ *
+ * Pure color (gx_dc_pure):
+ * colors.pure = the color;
+ * Binary halftone (gx_dc_ht_binary):
+ * colors.binary.b_ht = the device halftone;
+ * colors.binary.color[0] = the color for 0s (darker);
+ * colors.binary.color[1] = the color for 1s (lighter);
+ * colors.binary.b_level = the number of pixels to lighten,
+ * 0 < halftone_level < P, the number of pixels in the tile;
+ * @ colors.binary.b_tile points to an entry in the binary
+ * tile cache.
+ * Colored halftone (gx_dc_ht_colored):
+ * colors.colored.c_ht = the device halftone;
+ * colors.colored.c_level[0..N-1] = the halftone levels,
+ * like b_level;
+ * colors.colored.c_base[0..N-1] = the base colors;
+ * N=3 for RGB devices, 4 for CMYK devices;
+ * 0 <= c_level[i] < P;
+ * 0 <= c_base[i] <= dither_rgb;
+ * colors.colored.alpha = the opacity.
+ * Colored pattern (gx_dc_pattern):
+ * (id and mask are also set, see below)
+ * @ colors.pattern.p_tile points to a gx_color_tile in
+ * the pattern cache, or is NULL for a null pattern.
+ *
+ * The phase element is used for all colors except pure ones. It holds
+ * the negative of the graphics state halftone phase, modulo the halftone
+ * tile or colored pattern size.
+ *
+ * The mask elements of a device color are only used for patterns:
+ * Non-pattern:
+ * mask is unused.
+ * Pattern:
+ * mask.ccolor gives the original Pattern color (needed for
+ * reloading the pattern cache);
+ * mask.id gives the ID of the pattern (and its mask);
+ * @ mask.m_tile points to a gx_color_tile in the pattern cache,
+ * or is NULL for a pattern that doesn't require a mask.
+ * (The 'bits' of the tile are not accessed.)
+ * For colored patterns requiring a mask, p_tile and
+ * mask.m_tile point to the same cache entry.
+ * For masked colors, gx_set_dev_color replaces the type with a different
+ * type that applies the mask when painting. These types are not defined
+ * here, because they are only used in Level 2.
+ */
+
+/* A device color type is just a pointer to the procedures. */
+typedef struct gx_device_color_procs_s gx_device_color_procs;
+typedef const gx_device_color_procs _ds *gx_device_color_type;
+
+struct gx_device_color_s {
+ /*
+ * Since some compilers don't allow static initialization of a
+ * union, we put the type first.
+ */
+ gx_device_color_type type;
+ /*
+ * See the comment above for descriptions of the members. We use
+ * b_, c_, and p_ member names because some old compilers don't
+ * allow the same name to be used for two different structure
+ * members even when it's unambiguous.
+ */
+ union _c {
+ gx_color_index pure;
+ struct _bin {
+ const gx_device_halftone *b_ht;
+ gx_color_index color[2];
+ uint b_level;
+ gx_ht_tile *b_tile;
+ } binary;
+ struct _col {
+ const gx_device_halftone *c_ht;
+ byte c_base[4];
+ uint c_level[4];
+ ushort /*gx_color_value*/ alpha;
+ } colored;
+ struct _pat {
+ gx_color_tile *p_tile;
+ } /*(colored)*/ pattern;
+ } colors;
+ gs_int_point phase;
+ struct _mask {
+ gs_client_color ccolor; /* needed for remapping pattern */
+ gx_bitmap_id id;
+ gx_color_tile *m_tile;
+ } mask;
+};
+/*extern_st(st_device_color);*/ /* in gxdcolor.h */
+#define public_st_device_color() /* in gxcmap.c */\
+ gs_public_st_composite(st_device_color, gx_device_color, "gx_device_color",\
+ device_color_enum_ptrs, device_color_reloc_ptrs)
+#define st_device_color_max_ptrs 2
+
+/*
+ * Define the standard device color types.
+ * We define them here as pointers to the real types only because a few
+ * C compilers don't allow declaring externs with abstract struct types;
+ * we redefine them as macros in gxdcolor.h where the concrete type for
+ * gx_device_color_procs is available.
+ * We spell out the definition of gx_device_color type because some
+ * C compilers can't handle the typedef correctly.
+ */
+#ifndef gx_dc_type_none
+extern const gx_device_color_procs _ds *gx_dc_type_none; /* gxdcolor.c */
+#endif
+#ifndef gx_dc_type_null
+extern const gx_device_color_procs _ds *gx_dc_type_null; /* gxdcolor.c */
+#endif
+#ifndef gx_dc_type_pure
+extern const gx_device_color_procs _ds *gx_dc_type_pure; /* gxdcolor.c */
+#endif
+ /*
+ * We don't declare gx_dc_pattern here, so as not to create
+ * a spurious external reference in Level 1 systems.
+ */
+#ifndef gx_dc_type_pattern
+/*extern const gx_device_color_procs _ds *gx_dc_type_pattern;*/ /* gspcolor.c */
+#endif
+#ifndef gx_dc_type_ht_binary
+extern const gx_device_color_procs _ds *gx_dc_type_ht_binary; /* gxht.c */
+#endif
+#ifndef gx_dc_type_ht_colored
+extern const gx_device_color_procs _ds *gx_dc_type_ht_colored; /* gxcht.c */
+#endif
+
+#endif /* gsdcolor_INCLUDED */
diff --git a/gs/src/gsdevice.c b/gs/src/gsdevice.c
new file mode 100644
index 000000000..3d2b40595
--- /dev/null
+++ b/gs/src/gsdevice.c
@@ -0,0 +1,448 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdevice.c */
+/* Device operators for Ghostscript library */
+#include "ctype_.h"
+#include "memory_.h" /* for memcpy */
+#include "string_.h"
+#include "gx.h"
+#include "gscdefs.h" /* for gs_lib_device_list */
+#include "gserrors.h"
+#include "gp.h"
+#include "gsstruct.h"
+#include "gspath.h" /* gs_initclip prototype */
+#include "gspaint.h" /* gs_erasepage prototype */
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h" /* for gs_initmatrix */
+#include "gzstate.h"
+#include "gxcmap.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Include the extern for the device list. */
+extern_gs_lib_device_list();
+
+/* Finalization for devices: close the device if it is open. */
+void
+gx_device_finalize(void *vptr)
+{ discard(gs_closedevice((gx_device *)vptr));
+}
+
+/* GC procedures */
+#define fdev ((gx_device_forward *)vptr)
+private ENUM_PTRS_BEGIN(device_forward_enum_ptrs) return 0;
+ case 0: ENUM_RETURN(gx_device_enum_ptr(fdev->target));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_forward_reloc_ptrs) {
+ fdev->target = gx_device_reloc_ptr(fdev->target, gcst);
+} RELOC_PTRS_END
+#undef fdev
+
+/* Structure descriptors. These must follow the procedures, because */
+/* we can't conveniently forward-declare the procedures. */
+/* (See gxdevice.h for details.) */
+public_st_device();
+public_st_device_forward();
+public_st_device_null();
+/* A fake descriptor for devices whose descriptor we can't find. */
+gs_private_st_complex_only(st_device_unknown, byte, "gx_device(unknown)",
+ 0, 0, 0, gx_device_finalize);
+
+/* GC utilities */
+/* Enumerate or relocate a device pointer for a client. */
+gx_device *
+gx_device_enum_ptr(gx_device *dev)
+{ if ( dev == 0 || dev->memory == 0 )
+ return 0;
+ return dev;
+}
+gx_device *
+gx_device_reloc_ptr(gx_device *dev, gc_state_t *gcst)
+{ if ( dev == 0 || dev->memory == 0 )
+ return dev;
+ return gs_reloc_struct_ptr(dev, gcst);
+}
+
+/* Set up the device procedures in the device structure. */
+/* Also copy old fields to new ones. */
+void
+gx_device_set_procs(gx_device *dev)
+{ if ( dev->static_procs != 0 ) /* 0 if already populated */
+ { dev->std_procs = *dev->static_procs;
+ dev->static_procs = 0;
+ }
+}
+
+/* Initialize a device just after allocation. */
+int
+gdev_initialize(gx_device *dev)
+{ *dev = *(gx_device *)&gs_null_device;
+ return 0;
+}
+
+/* Flush buffered output to the device */
+int
+gs_flushpage(gs_state *pgs)
+{ gx_device *dev = gs_currentdevice(pgs);
+ return (*dev_proc(dev, sync_output))(dev);
+}
+
+/* Make the device output the accumulated page description */
+int
+gs_copypage(gs_state *pgs)
+{ return gs_output_page(pgs, 1, 0);
+}
+int
+gs_output_page(gs_state *pgs, int num_copies, int flush)
+{ gx_device *dev = gs_currentdevice(pgs);
+ int code;
+
+ if ( dev->IgnoreNumCopies )
+ num_copies = 1;
+ code = (*dev_proc(dev, output_page))(dev, num_copies, flush);
+ if ( code >= 0 )
+ dev->PageCount += num_copies;
+ return code;
+}
+
+/* Copy scan lines from an image device */
+int
+gs_copyscanlines(gx_device *dev, int start_y, byte *data, uint size,
+ int *plines_copied, uint *pbytes_copied)
+{ uint line_size = gx_device_raster(dev, 0);
+ uint count = size / line_size;
+ uint i;
+ byte *dest = data;
+ for ( i = 0; i < count; i++, dest += line_size )
+ { int code = (*dev_proc(dev, get_bits))(dev, start_y + i, dest, NULL);
+ if ( code < 0 )
+ { /* Might just be an overrun. */
+ if ( start_y + i == dev->height ) break;
+ return_error(code);
+ }
+ }
+ if ( plines_copied != NULL )
+ *plines_copied = i;
+ if ( pbytes_copied != NULL )
+ *pbytes_copied = i * line_size;
+ return 0;
+}
+
+/* Get the current device from the graphics state. */
+gx_device *
+gs_currentdevice(const gs_state *pgs)
+{ return pgs->device;
+}
+
+/* Get the name of a device. */
+const char *
+gs_devicename(const gx_device *dev)
+{ return dev->dname;
+}
+
+/* Get the initial matrix of a device. */
+void
+gs_deviceinitialmatrix(gx_device *dev, gs_matrix *pmat)
+{ fill_dev_proc(dev, get_initial_matrix, gx_default_get_initial_matrix);
+ (*dev_proc(dev, get_initial_matrix))(dev, pmat);
+}
+
+/* Get the N'th device from the known device list */
+const gx_device *
+gs_getdevice(int index)
+{ const gx_device **list;
+ int count = gs_lib_device_list(&list, NULL);
+
+ if ( index < 0 || index >= count )
+ return 0; /* index out of range */
+ return list[index];
+}
+
+/* Clone an existing device. */
+int
+gs_copydevice(gx_device **pnew_dev, const gx_device *dev, gs_memory_t *mem)
+{ gx_device *new_dev;
+ const gs_memory_struct_type_t *std = dev->stype;
+
+ /*
+ * Because command list devices have complicated internal pointer
+ * structures, we allocate all device instances as immovable.
+ */
+ if ( std == 0 )
+ { /*
+ * This is the statically allocated prototype. Find its
+ * structure descriptor, and fill it in if this is the first
+ * time we've needed it. (Right now we always fill it in,
+ * for simplicity.)
+ */
+ const gx_device **list;
+ gs_memory_struct_type_t *st;
+ int count = gs_lib_device_list(&list, &st);
+ int i;
+ bool forward = false;
+ const gx_device_procs *procs = dev->static_procs;
+
+ for ( i = 0; list[i] != dev; ++i )
+ if ( i == count )
+ { /* We can't find a structure descriptor for */
+ /* this device. Allocate it as bytes and */
+ /* hope for the best. */
+ std = &st_device_unknown;
+ new_dev = gs_alloc_struct_array_immovable(mem,
+ dev->params_size, gx_device, st,
+ "gs_copydevice(unknown)");
+ goto out;
+ }
+ st += i;
+ /*
+ * Try to figure out if this is a forwarding device.
+ * All printer devices, and no other devices, have
+ * a null fill_rectangle procedure; for other devices,
+ * we look for a likely forwarding procedure in the vector.
+ * The algorithm isn't foolproof, but it's all we've got.
+ */
+ if ( procs == 0 )
+ procs = &dev->std_procs;
+ if ( procs->fill_rectangle == 0 ||
+ procs->get_xfont_procs == gx_forward_get_xfont_procs
+ )
+ forward = true;
+ if ( forward )
+ *st = st_device_forward;
+ else
+ *st = st_device;
+ st->ssize = dev->params_size;
+ std = st;
+ }
+ new_dev = gs_alloc_struct_immovable(mem, gx_device, std,
+ "gs_copydevice");
+out: if ( new_dev == 0 )
+ return_error(gs_error_VMerror);
+ memcpy(new_dev, dev, dev->params_size);
+ new_dev->memory = mem;
+ new_dev->stype = std;
+ new_dev->is_open = false;
+ *pnew_dev = new_dev;
+ return 0;
+}
+
+/* Set the device in the graphics state */
+int
+gs_setdevice(gs_state *pgs, gx_device *dev)
+{ int code = gs_setdevice_no_erase(pgs, dev);
+ if ( code == 1 )
+ code = gs_erasepage(pgs);
+ return code;
+}
+int
+gs_setdevice_no_erase(gs_state *pgs, gx_device *dev)
+{ bool was_open = dev->is_open;
+ int code;
+ /* Initialize the device */
+ if ( !was_open )
+ { gx_device_fill_in_procs(dev);
+ if ( gs_device_is_memory(dev) )
+ { /* Set the target to the current device. */
+ gx_device *odev = gs_currentdevice_inline(pgs);
+ while ( odev != 0 && gs_device_is_memory(odev) )
+ odev = ((gx_device_memory *)odev)->target;
+ ((gx_device_memory *)dev)->target = odev;
+ }
+ code = (*dev_proc(dev, open_device))(dev);
+ if ( code < 0 ) return_error(code);
+ dev->is_open = true;
+ }
+ pgs->device = dev;
+ gx_set_cmap_procs((gs_imager_state *)pgs, dev);
+ pgs->ctm_default_set = false;
+ if ( (code = gs_initmatrix(pgs)) < 0 ||
+ (code = gs_initclip(pgs)) < 0
+ )
+ return code;
+ gx_unset_dev_color(pgs);
+ /* If we were in a charpath or a setcachedevice, */
+ /* we aren't any longer. */
+ pgs->in_cachedevice = 0;
+ pgs->in_charpath = (gs_char_path_mode)0;
+ return (was_open ? 0 : 1);
+}
+
+/* Make a null device. */
+void
+gs_make_null_device(gx_device_null *dev, gs_memory_t *mem)
+{ *dev = gs_null_device;
+ dev->memory = mem;
+}
+
+/* Select the null device. This is just a convenience. */
+void
+gs_nulldevice(gs_state *pgs)
+{ gs_setdevice(pgs, (gx_device *)&gs_null_device);
+}
+
+/* Close a device. The client is responsible for ensuring that */
+/* this device is not current in any graphics state. */
+int
+gs_closedevice(gx_device *dev)
+{ int code = 0;
+ if ( dev->is_open )
+ { code = (*dev_proc(dev, close_device))(dev);
+ if ( code < 0 ) return_error(code);
+ dev->is_open = false;
+ }
+ return code;
+}
+
+/* Install enough of a null device to suppress the page device check */
+/* during the execution of a restore/grestore/setgstate. */
+void
+gx_device_no_output(gs_state *pgs)
+{ pgs->device = (gx_device *)&gs_null_device;
+}
+
+/* Just set the device without reinitializing. */
+/* (For internal use only.) */
+void
+gx_set_device_only(gs_state *pgs, gx_device *dev)
+{ pgs->device = dev;
+}
+
+/* Compute the size of one scan line for a device, */
+/* with or without padding to a word boundary. */
+uint
+gx_device_raster(const gx_device *dev, bool pad)
+{ ulong bits = (ulong)dev->width * dev->color_info.depth;
+ return (pad ? bitmap_raster(bits) : (uint)((bits + 7) >> 3));
+}
+
+/* Adjust the resolution for devices that only have a fixed set of */
+/* geometries, so that the apparent size in inches remains constant. */
+/* If fit=1, the resolution is adjusted so that the entire image fits; */
+/* if fit=0, one dimension fits, but the other one is clipped. */
+int
+gx_device_adjust_resolution(gx_device *dev,
+ int actual_width, int actual_height, int fit)
+{ double width_ratio = (double)actual_width / dev->width ;
+ double height_ratio = (double)actual_height / dev->height ;
+ double ratio =
+ (fit ? min(width_ratio, height_ratio) :
+ max(width_ratio, height_ratio));
+ dev->x_pixels_per_inch *= ratio;
+ dev->y_pixels_per_inch *= ratio;
+ gx_device_set_width_height(dev, actual_width, actual_height);
+ return 0;
+}
+
+/* Set the HWMargins to values defined in inches. */
+/* If move_origin is true, also reset the Margins. */
+/* Note that this assumes a printer-type device (Y axis inverted). */
+void
+gx_device_set_margins(gx_device *dev, const float *margins /*[4]*/,
+ bool move_origin)
+{ int i;
+ for ( i = 0; i < 4; ++i )
+ dev->HWMargins[i] = margins[i] * 72.0;
+ if ( move_origin )
+ { dev->Margins[0] = -margins[0] * dev->MarginsHWResolution[0];
+ dev->Margins[1] = -margins[3] * dev->MarginsHWResolution[1];
+ }
+}
+
+/* Set the width and height, updating MediaSize to remain consistent. */
+void
+gx_device_set_width_height(gx_device *dev, int width, int height)
+{ dev->width = width;
+ dev->height = height;
+ dev->MediaSize[0] = width * 72.0 / dev->x_pixels_per_inch;
+ dev->MediaSize[1] = height * 72.0 / dev->y_pixels_per_inch;
+}
+
+/* Set the resolution, updating width and height to remain consistent. */
+void
+gx_device_set_resolution(gx_device *dev, floatp x_dpi, floatp y_dpi)
+{ dev->x_pixels_per_inch = x_dpi;
+ dev->y_pixels_per_inch = y_dpi;
+ dev->width = dev->MediaSize[0] * x_dpi / 72.0 + 0.5;
+ dev->height = dev->MediaSize[1] * y_dpi / 72.0 + 0.5;
+}
+
+/* Set the MediaSize, updating width and height to remain consistent. */
+void
+gx_device_set_media_size(gx_device *dev, floatp media_width, floatp media_height)
+{ dev->MediaSize[0] = media_width;
+ dev->MediaSize[1] = media_height;
+ dev->width = media_width * dev->x_pixels_per_inch / 72.0 + 0.499;
+ dev->height = media_height * dev->y_pixels_per_inch / 72.0 + 0.499;
+}
+
+/* Open the output file for a device. */
+int
+gx_device_open_output_file(const gx_device *dev, const char *fname,
+ bool binary, bool positionable, FILE **pfile)
+{ char pfname[128];
+ char pfmt[10];
+ const char *fsrc = fname;
+ char *fdest = pfname;
+ long count1 = dev->PageCount + 1;
+
+ if ( !strcmp(fname, "-") )
+ { *pfile = stdout;
+ return 0;
+ }
+ /****** SHOULD RETURN rangecheck IF FILE NAME TOO LONG ******/
+ for ( ; *fsrc; ++fsrc )
+ { if ( *fsrc != '%' )
+ { *fdest++ = *fsrc;
+ continue;
+ }
+ if ( fsrc[1] == '%' )
+ { *fdest++ = '%';
+ ++fsrc;
+ continue;
+ }
+ { char *ffmt = pfmt;
+ bool use_long;
+
+ /****** SHOULD CHECK FOR FORMAT TOO LONG ******/
+ while ( !isalpha(*fsrc) )
+ *ffmt++ = *fsrc++;
+ if ( (use_long = (*fsrc == 'l')) )
+ *ffmt++ = *fsrc++;
+ *ffmt = *fsrc;
+ ffmt[1] = 0;
+ /****** SHOULD CHECK FOR LEGAL FORMATS ******/
+ sprintf(fdest, pfmt, (use_long ? count1 : (int)count1));
+ fdest += strlen(fdest);
+ }
+ }
+ *fdest = 0;
+ if ( positionable && pfname[0] != '|' )
+ { char fmode[4];
+
+ strcpy(fmode, gp_fmode_wb);
+ strcat(fmode, "+");
+ *pfile = gp_fopen(pfname, fmode);
+ if ( *pfile )
+ return 0;
+ }
+ *pfile = gp_open_printer(pfname, binary);
+ if ( *pfile )
+ return 0;
+ return_error(gs_error_invalidfileaccess);
+}
diff --git a/gs/src/gsdevice.h b/gs/src/gsdevice.h
new file mode 100644
index 000000000..4b520a177
--- /dev/null
+++ b/gs/src/gsdevice.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdevice.h */
+/* Device and page control API */
+
+#ifndef gsdevice_INCLUDED
+# define gsdevice_INCLUDED
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+#endif
+
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+#endif
+
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+int gs_flushpage(P1(gs_state *));
+int gs_copypage(P1(gs_state *));
+int gs_output_page(P3(gs_state *, int, int));
+int gs_copyscanlines(P6(gx_device *, int, byte *, uint, int *, uint *));
+const gx_device *gs_getdevice(P1(int));
+int gs_copydevice(P3(gx_device **, const gx_device *, gs_memory_t *));
+#define gs_makeimagedevice(pdev, pmat, w, h, colors, colors_size, mem)\
+ gs_makewordimagedevice(pdev, pmat, w, h, colors, colors_size, false, true, mem)
+int gs_makewordimagedevice(P9(gx_device **pnew_dev, const gs_matrix *pmat,
+ uint width, uint height,
+ const byte *colors, int num_colors,
+ bool word_oriented, bool page_device,
+ gs_memory_t *mem));
+#define gs_initialize_imagedevice(mdev, pmat, w, h, colors, colors_size, mem)\
+ gs_initialize_wordimagedevice(mdev, pmat, w, h, colors, color_size, false, true, mem)
+int gs_initialize_wordimagedevice(P9(gx_device_memory *new_dev,
+ const gs_matrix *pmat,
+ uint width, uint height,
+ const byte *colors, int colors_size,
+ bool word_oriented, bool page_device,
+ gs_memory_t *mem));
+void gs_nulldevice(P1(gs_state *));
+int gs_setdevice(P2(gs_state *, gx_device *));
+int gs_setdevice_no_erase(P2(gs_state *, gx_device *)); /* returns 1 */
+ /* if erasepage required */
+gx_device *gs_currentdevice(P1(const gs_state *));
+/* gzstate.h redefines the following: */
+#ifndef gs_currentdevice_inline
+# define gs_currentdevice_inline(pgs) gs_currentdevice(pgs)
+#endif
+const char *gs_devicename(P1(const gx_device *));
+void gs_deviceinitialmatrix(P2(gx_device *, gs_matrix *));
+int gs_getdeviceparams(P2(gx_device *, gs_param_list *));
+int gs_gethardwareparams(P2(gx_device *, gs_param_list *));
+int gs_get_device_or_hardware_params(P3(gx_device *, gs_param_list *, bool));
+int gs_putdeviceparams(P2(gx_device *, gs_param_list *));
+int gs_closedevice(P1(gx_device *));
+
+#endif /* gsdevice_INCLUDED */
diff --git a/gs/src/gsdevmem.c b/gs/src/gsdevmem.c
new file mode 100644
index 000000000..5479a9c66
--- /dev/null
+++ b/gs/src/gsdevmem.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdevmem.c */
+/* Memory device creation for Ghostscript library */
+#include "math_.h" /* for fabs */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Make a memory (image) device. */
+/* If colors_size = -16, -24, or -32, this is a true-color device; */
+/* otherwise, colors_size is the size of the palette in bytes */
+/* (2^N for gray scale, 3*2^N for RGB color). */
+/* We separate device allocation and initialization at customer request. */
+int
+gs_initialize_wordimagedevice(gx_device_memory *new_dev, const gs_matrix *pmat,
+ uint width, uint height, const byte *colors, int colors_size,
+ bool word_oriented, bool page_device, gs_memory_t *mem)
+{ const gx_device_memory *proto_dev;
+ int palette_count = colors_size;
+ int num_components = 1;
+ int pcount;
+ int bits_per_pixel;
+ float x_pixels_per_unit, y_pixels_per_unit;
+ byte palette[256 * 3];
+ byte *dev_palette;
+ bool has_color;
+ switch ( colors_size )
+ {
+ case 3*2:
+ palette_count = 2; num_components = 3;
+ case 2:
+ bits_per_pixel = 1; break;
+ case 3*4:
+ palette_count = 4; num_components = 3;
+ case 4:
+ bits_per_pixel = 2; break;
+ case 3*16:
+ palette_count = 16; num_components = 3;
+ case 16:
+ bits_per_pixel = 4; break;
+ case 3*256:
+ palette_count = 256; num_components = 3;
+ case 256:
+ bits_per_pixel = 8; break;
+ case -16:
+ bits_per_pixel = 16; palette_count = 0; break;
+ case -24:
+ bits_per_pixel = 24; palette_count = 0; break;
+ case -32:
+ bits_per_pixel = 32; palette_count = 0; break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ proto_dev = (word_oriented ?
+ gdev_mem_word_device_for_bits(bits_per_pixel) :
+ gdev_mem_device_for_bits(bits_per_pixel));
+ if ( proto_dev == 0 ) /* no suitable device */
+ return_error(gs_error_rangecheck);
+ pcount = palette_count * 3;
+ /* Check to make sure the palette contains white and black, */
+ /* and, if it has any colors, the six primaries. */
+ if ( bits_per_pixel <= 8 )
+ { const byte *p;
+ byte *q;
+ int primary_mask = 0;
+ int i;
+
+ has_color = false;
+ for ( i = 0, p = colors, q = palette;
+ i < palette_count; i++, q += 3
+ )
+ { int mask = 1;
+ switch ( num_components )
+ {
+ case 1: /* gray */
+ q[0] = q[1] = q[2] = *p++;
+ break;
+ default /* case 3 */: /* RGB */
+ q[0] = p[0], q[1] = p[1], q[2] = p[2];
+ p += 3;
+ }
+#define shift_mask(b,n)\
+ switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; }
+ shift_mask(q[0], 4);
+ shift_mask(q[1], 2);
+ shift_mask(q[2], 1);
+#undef shift_mask
+ primary_mask |= mask;
+ if ( q[0] != q[1] || q[0] != q[2] )
+ has_color = true;
+ }
+ switch ( primary_mask )
+ {
+ case 129: /* just black and white */
+ if ( has_color ) /* color but no primaries */
+ return_error(gs_error_rangecheck);
+ case 255: /* full color */
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ }
+ else
+ has_color = true;
+ /*
+ * The initial transformation matrix must map 1 user unit to
+ * 1/72". Let W and H be the width and height in pixels, and
+ * assume the initial matrix is of the form [A 0 0 B X Y].
+ * Then the size of the image in user units is (W/|A|,H/|B|),
+ * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so
+ * the number of pixels per inch is
+ * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72).
+ * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90
+ * or 270 degree rotation, the size of the image in user
+ * units is (W/|B|,H/|A|), so the pixels per inch are
+ * (|B|*72,|A|*72). We forbid non-orthogonal transformation
+ * matrices.
+ */
+ if ( is_fzero2(pmat->xy, pmat->yx) )
+ x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy;
+ else if ( is_fzero2(pmat->xx, pmat->yy) )
+ x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy;
+ else
+ return_error(gs_error_undefinedresult);
+ /* All checks done, allocate the device. */
+ if ( bits_per_pixel != 1 )
+ { dev_palette = gs_alloc_string(mem, pcount,
+ "gs_makeimagedevice(palette)");
+ if ( dev_palette == 0 )
+ return_error(gs_error_VMerror);
+ }
+ gs_make_mem_device(new_dev, proto_dev, mem,
+ (page_device ? 1 : -1), 0);
+ if ( !has_color )
+ { new_dev->color_info.num_components = 1;
+ new_dev->color_info.max_color = 0;
+ new_dev->color_info.dither_colors = 0;
+ }
+ if ( bits_per_pixel == 1 )
+ { /* Determine the polarity from the palette. */
+ /* This is somewhat bogus, but does the right thing */
+ /* in the only cases we care about. */
+ gdev_mem_mono_set_inverted(new_dev,
+ (palette[0] | palette[1] | palette[2]) != 0);
+ }
+ else
+ { new_dev->palette.size = pcount;
+ new_dev->palette.data = dev_palette;
+ memcpy(dev_palette, palette, pcount);
+ }
+ new_dev->initial_matrix = *pmat;
+ new_dev->MarginsHWResolution[0] = new_dev->HWResolution[0] =
+ fabs(x_pixels_per_unit) * 72;
+ new_dev->MarginsHWResolution[1] = new_dev->HWResolution[1] =
+ fabs(y_pixels_per_unit) * 72;
+ gx_device_set_width_height((gx_device *)new_dev, width, height);
+ /* Set the ImagingBBox so we get a correct clipping region. */
+ { gs_rect bbox;
+ bbox.p.x = 0;
+ bbox.p.y = 0;
+ bbox.q.x = width;
+ bbox.q.y = height;
+ gs_bbox_transform_inverse(&bbox, pmat, &bbox);
+ new_dev->ImagingBBox[0] = bbox.p.x;
+ new_dev->ImagingBBox[1] = bbox.p.y;
+ new_dev->ImagingBBox[2] = bbox.q.x;
+ new_dev->ImagingBBox[3] = bbox.q.y;
+ new_dev->ImagingBBox_set = true;
+ }
+ /* The bitmap will be allocated when the device is opened. */
+ new_dev->is_open = false;
+ new_dev->bitmap_memory = mem;
+ return 0;
+}
+
+int
+gs_makewordimagedevice(gx_device **pnew_dev, const gs_matrix *pmat,
+ uint width, uint height, const byte *colors, int num_colors,
+ bool word_oriented, bool page_device, gs_memory_t *mem)
+{ int code;
+ gx_device_memory *pnew =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "gs_makeimagedevice(device)");
+
+ if (pnew == 0)
+ return_error (gs_error_VMerror);
+ code = gs_initialize_wordimagedevice(pnew, pmat, width, height,
+ colors, num_colors, word_oriented,
+ page_device, mem);
+ if (code < 0)
+ { gs_free_object(mem, pnew, "gs_makeimagedevice(device)");
+ return code;
+ }
+ *pnew_dev = (gx_device *)pnew;
+ return 0;
+}
diff --git a/gs/src/gsdll.c b/gs/src/gsdll.c
new file mode 100644
index 000000000..ea1964850
--- /dev/null
+++ b/gs/src/gsdll.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+/* Portions Copyright (C) 1994, 1995, 1996, Russell Lang. All rights reserved. */
+
+
+/* gsdll.c */
+/* Dynamic Link Library interface for OS/2 and MS-Windows Ghostscript */
+/* front end to gs.c */
+
+/* HOW MANY OF THESE INCLUDES ARE REALLY NEEDED? */
+
+/* Define PROGRAM_NAME before we include std.h */
+#define PROGRAM_NAME gs_product
+#include "ctype_.h"
+#include "memory_.h"
+#include <stdarg.h>
+#include "string_.h"
+
+#include "ghost.h"
+#include "gscdefs.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "stream.h"
+#include "errors.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "ivmspace.h"
+#include "sfilter.h" /* for iscan.h */
+#include "ostack.h" /* must precede iscan.h */
+#include "iscan.h"
+#include "main.h"
+#include "imainarg.h"
+#include "store.h"
+#include "files.h" /* requires stream.h */
+#include "interp.h"
+#ifdef _Windows
+#include "windows_.h"
+#ifndef __WIN32__
+#define GSDLLEXPORT _export
+#endif
+#else
+#define INCL_DOS
+#define INCL_WIN
+#include <os2.h>
+#endif
+#include "gsdll.h" /* header for DLLs */
+#include <setjmp.h>
+
+jmp_buf gsdll_env; /* used by gp_do_exit in DLL configurations */
+
+private int gsdll_usage; /* should be needed only for 16-bit SHARED DATA */
+
+/****** SINGLE-INSTANCE HACK ******/
+private gs_main_instance *gsdll_minst; /* instance data */
+extern HWND hwndtext; /* in gp_mswin.h */
+
+GSDLL_CALLBACK pgsdll_callback; /* callback for messages and stdio to caller */
+
+
+/* ---------- DLL exported functions ---------- */
+
+/* arguments are:
+ * 1. callback function for stdio and for notification of
+ * sync_output, output_page and resize events
+ * 2. window handle, used as parent. Use NULL if you have no window.
+ * 3. argc
+ * 4. argv
+ */
+int GSDLLAPI
+gsdll_init(GSDLL_CALLBACK callback, HWND hwnd, int argc, char GSFAR *argv[])
+{
+ if (gsdll_usage) {
+ return GSDLL_INIT_IN_USE; /* DLL can't be used by multiple programs under Win16 */
+ }
+ gsdll_usage++;
+
+ if (setjmp(gsdll_env)) {
+ gsdll_usage--;
+ if (gs_exit_status)
+ return gs_exit_status; /* error */
+ return GSDLL_INIT_QUIT; /* not an error */
+ }
+
+ /****** SINGLE-INSTANCE HACK ******/
+ pgsdll_callback = callback;
+ hwndtext = hwnd;
+
+ /****** SINGLE-INSTANCE HACK ******/
+ gsdll_minst = gs_main_instance_default();
+
+ /* in gs.c */
+ gs_main_init_with_args(gsdll_minst, argc, argv);
+
+ return 0;
+}
+
+/* if return value < 0, then error occured and caller should call */
+/* gsdll_exit, then unload library */
+int GSDLLAPI
+gsdll_execute_begin(void)
+{ int exit_code;
+ ref error_object;
+ int code;
+ if (!gsdll_usage)
+ return -1;
+ if (setjmp(gsdll_env))
+ return gs_exit_status; /* error */
+ code = gs_main_run_string_begin(gsdll_minst, 0, &exit_code, &error_object);
+ return code;
+}
+
+/* if return value < 0, then error occured and caller should call */
+/* gsdll_execute_end, then gsdll_exit, then unload library */
+int GSDLLAPI
+gsdll_execute_cont(const char GSFAR *str, int len)
+{ int exit_code;
+ ref error_object;
+ int code;
+ if (!gsdll_usage)
+ return -1;
+ if (setjmp(gsdll_env))
+ return gs_exit_status; /* error */
+ code = gs_main_run_string_continue(gsdll_minst, str, len, 0, &exit_code, &error_object);
+ if (code == e_NeedInput)
+ code = 0; /* this is not an error */
+ return code;
+}
+
+/* if return value < 0, then error occured and caller should call */
+/* gsdll_exit, then unload library */
+int GSDLLAPI
+gsdll_execute_end(void)
+{ int exit_code;
+ ref error_object;
+ int code;
+ if (!gsdll_usage)
+ return -1;
+ if (setjmp(gsdll_env))
+ return gs_exit_status; /* error */
+ code = gs_main_run_string_end(gsdll_minst, 0, &exit_code, &error_object);
+ return code;
+}
+
+int GSDLLAPI
+gsdll_exit(void)
+{
+ if (!gsdll_usage)
+ return -1;
+ gsdll_usage--;
+
+ if (setjmp(gsdll_env))
+ return gs_exit_status; /* error */
+ /* don't call gs_exit() since this would cause caller to exit */
+ gs_finit(0, 0);
+ pgsdll_callback = (GSDLL_CALLBACK)NULL;
+ return 0;
+}
+
+/* return revision numbers and strings of Ghostscript */
+/* Used for determining if wrong GSDLL loaded */
+/* this may be called before gsdll_init */
+int GSDLLAPI
+gsdll_revision(char GSFAR **product, char GSFAR **copyright,
+ long GSFAR *revision, long GSFAR *revisiondate)
+{
+ if (product)
+ *product = (char *)gs_product;
+ if (copyright)
+ *copyright = (char *)gs_copyright;
+ if (revision)
+ *revision = gs_revision;
+ if (revisiondate)
+ *revisiondate = gs_revisiondate;
+ return 0;
+}
+
+/* end gsdll.c */
diff --git a/gs/src/gsdll.h b/gs/src/gsdll.h
new file mode 100644
index 000000000..803fb35c3
--- /dev/null
+++ b/gs/src/gsdll.h
@@ -0,0 +1,128 @@
+/* Copyright (C) 1994-1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+/* gsdll.h */
+
+#ifndef _GSDLL_H
+#define _GSDLL_H
+
+#ifndef GSDLLEXPORT
+#define GSDLLEXPORT
+#endif
+
+#ifdef __WINDOWS__
+#define _Windows
+#endif
+
+/* type of exported functions */
+#ifdef _Windows
+#ifdef _WATCOM_
+#define GSDLLAPI GSDLLEXPORT
+#else
+#define GSDLLAPI CALLBACK GSDLLEXPORT
+#endif
+#else
+#ifdef __IBMC__
+#define GSDLLAPI _System
+#else
+#define GSDLLAPI
+#endif
+#endif
+
+#ifdef _Windows
+#define GSDLLCALLLINK
+#define GSFAR FAR
+#else
+#ifdef __IBMC__
+#define GSDLLCALLLINK _System
+#else
+#define GSDLLCALLLINK
+#endif
+#define GSFAR
+#endif
+
+/* global pointer to callback */
+typedef int (GSFAR *GSDLLCALLLINK GSDLL_CALLBACK)(int, char GSFAR *, unsigned long);
+extern GSDLL_CALLBACK pgsdll_callback;
+
+/* message values for callback */
+#define GSDLL_STDIN 1 /* get count characters to str from stdin */
+ /* return number of characters read */
+#define GSDLL_STDOUT 2 /* put count characters from str to stdout*/
+ /* return number of characters written */
+#define GSDLL_DEVICE 3 /* device = str has been opened if count=1 */
+ /* or closed if count=0 */
+#define GSDLL_SYNC 4 /* sync_output for device str */
+#define GSDLL_PAGE 5 /* output_page for device str */
+#define GSDLL_SIZE 6 /* resize for device str */
+ /* LOWORD(count) is new xsize */
+ /* HIWORD(count) is new ysize */
+#define GSDLL_POLL 7 /* Called from gp_check_interrupt */
+ /* Can be used by caller to poll the message queue */
+ /* Normally returns 0 */
+ /* To abort gsdll_execute_cont(), return a */
+ /* non zero error code until gsdll_execute_cont() */
+ /* returns */
+
+/* return values from gsdll_init() */
+#define GSDLL_INIT_IN_USE 100 /* DLL is in use */
+#define GSDLL_INIT_QUIT 101 /* quit or EOF during init */
+ /* This is not an error. */
+ /* gsdll_exit() must not be called */
+
+
+/* DLL exported functions */
+/* for load time dynamic linking */
+int GSDLLAPI gsdll_revision(char GSFAR * GSFAR *product, char GSFAR * GSFAR *copyright, long GSFAR *gs_revision, long GSFAR *gs_revisiondate);
+int GSDLLAPI gsdll_init(GSDLL_CALLBACK callback, HWND hwnd, int argc, char GSFAR * GSFAR *argv);
+int GSDLLAPI gsdll_execute_begin(void);
+int GSDLLAPI gsdll_execute_cont(const char GSFAR *str, int len);
+int GSDLLAPI gsdll_execute_end(void);
+int GSDLLAPI gsdll_exit(void);
+int GSDLLAPI gsdll_lock_device(unsigned char *device, int flag);
+#ifdef _Windows
+HGLOBAL GSDLLAPI gsdll_copy_dib(unsigned char GSFAR *device);
+HPALETTE GSDLLAPI gsdll_copy_palette(unsigned char GSFAR *device);
+void GSDLLAPI gsdll_draw(unsigned char GSFAR *device, HDC hdc, LPRECT dest, LPRECT src);
+int GSDLLAPI gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE *ppbyte, unsigned int row);
+#else
+unsigned long gsdll_get_bitmap(unsigned char *device, unsigned char **pbitmap);
+#endif
+
+/* Function pointer typedefs */
+/* for run time dynamic linking */
+typedef int (GSDLLAPI *PFN_gsdll_revision)(char GSFAR * GSFAR *, char GSFAR * GSFAR *, long GSFAR *, long GSFAR *);
+typedef int (GSDLLAPI *PFN_gsdll_init)(GSDLL_CALLBACK, HWND, int argc, char GSFAR * GSFAR *argv);
+typedef int (GSDLLAPI *PFN_gsdll_execute_begin)(void);
+typedef int (GSDLLAPI *PFN_gsdll_execute_cont)(const char GSFAR *str, int len);
+typedef int (GSDLLAPI *PFN_gsdll_execute_end)(void);
+typedef int (GSDLLAPI *PFN_gsdll_exit)(void);
+typedef int (GSDLLAPI *PFN_gsdll_lock_device)(unsigned char GSFAR *, int);
+#ifdef _Windows
+typedef HGLOBAL (GSDLLAPI *PFN_gsdll_copy_dib)(unsigned char GSFAR *);
+typedef HPALETTE (GSDLLAPI *PFN_gsdll_copy_palette)(unsigned char GSFAR *);
+typedef void (GSDLLAPI *PFN_gsdll_draw)(unsigned char GSFAR *, HDC, LPRECT, LPRECT);
+typedef int (GSDLLAPI *PFN_gsdll_get_bitmap_row)(unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE *ppbyte, unsigned int row);
+#else
+typedef long (*GSDLLAPI PFN_gsdll_get_bitmap)(unsigned char *, unsigned char **);
+#endif
+
+#endif
diff --git a/gs/src/gsdll16.def b/gs/src/gsdll16.def
new file mode 100644
index 000000000..218b44775
--- /dev/null
+++ b/gs/src/gsdll16.def
@@ -0,0 +1,20 @@
+LIBRARY GSDLL16
+DESCRIPTION 'Ghostscript Interpreter DLL'
+CODE PRELOAD DISCARDABLE
+DATA SINGLE SHARED PRELOAD
+SEGMENTS GSDLL_TEXT PRELOAD NONDISCARDABLE
+ GDEVMSWN_TEXT PRELOAD NONDISCARDABLE
+ GDEVWDIB_TEXT PRELOAD NONDISCARDABLE
+ GP_MSWIN_TEXT PRELOAD NONDISCARDABLE
+EXPORTS
+ gsdll_revision @1
+ gsdll_init @2
+ gsdll_execute_begin @3
+ gsdll_execute_cont @4
+ gsdll_execute_end @5
+ gsdll_exit @6
+ gsdll_lock_device @7
+ gsdll_copy_dib @8
+ gsdll_copy_palette @9
+ gsdll_draw @10
+ gsdll_get_bitmap_row @11
diff --git a/gs/src/gsdll16.rc b/gs/src/gsdll16.rc
new file mode 100644
index 000000000..252a350ff
--- /dev/null
+++ b/gs/src/gsdll16.rc
@@ -0,0 +1,26 @@
+#include <windows.h>
+#include "gp_mswin.h"
+
+GSTEXT_ICON ICON gstext.ico
+GSIMAGE_ICON ICON gsgraph.ico
+
+#ifndef DS_3DLOOK
+#define DS_3DLOOK 0x0004L /* for Windows 95 look */
+#endif
+
+SpoolDlgBox DIALOG 32, 40, 110, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK
+CAPTION "Select Printer Port"
+BEGIN
+ CONTROL "&Ok", IDOK, "button", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 14, 32, 14
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 36, 32, 14
+ CONTROL "", SPOOL_PORT, "LISTBOX", LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 8, 8, 56, 50
+END
+
+CancelDlgBox DIALOG 32, 40, 120, 48
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | DS_3DLOOK
+BEGIN
+ CTEXT "Printing", -1, 8, 4, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CTEXT "", CANCEL_PCDONE, 8, 16, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 44, 30, 32, 14
+END
diff --git a/gs/src/gsdll2.def b/gs/src/gsdll2.def
new file mode 100644
index 000000000..1aa491c0a
--- /dev/null
+++ b/gs/src/gsdll2.def
@@ -0,0 +1,12 @@
+LIBRARY GSDLL2 INITINSTANCE TERMINSTANCE
+DESCRIPTION 'Ghostscript DLL'
+DATA MULTIPLE NONSHARED
+EXPORTS
+ gsdll_revision @1
+ gsdll_init @2
+ gsdll_execute_begin @3
+ gsdll_execute_cont @4
+ gsdll_execute_end @5
+ gsdll_exit @6
+ gsdll_lock_device @7
+ gsdll_get_bitmap @8
diff --git a/gs/src/gsdll2.rc b/gs/src/gsdll2.rc
new file mode 100644
index 000000000..8bf70ccea
--- /dev/null
+++ b/gs/src/gsdll2.rc
@@ -0,0 +1,22 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdll2.rc */
+/* Resources for gsdll2.dll, Ghostscript DLL for OS/2 */
+
+ICON 1 gsos2.ico
diff --git a/gs/src/gsdll32.def b/gs/src/gsdll32.def
new file mode 100644
index 000000000..83bc4af8e
--- /dev/null
+++ b/gs/src/gsdll32.def
@@ -0,0 +1,17 @@
+LIBRARY GSDLL32 INITINSTANCE
+DESCRIPTION 'Ghostscript Interpreter DLL'
+DATA MULTIPLE NONSHARED
+EXPORTS
+ DllEntryPoint
+ DllMain
+ gsdll_revision @1
+ gsdll_init @2
+ gsdll_execute_begin @3
+ gsdll_execute_cont @4
+ gsdll_execute_end @5
+ gsdll_exit @6
+ gsdll_lock_device @7
+ gsdll_copy_dib @8
+ gsdll_copy_palette @9
+ gsdll_draw @10
+ gsdll_get_bitmap_row @11
diff --git a/gs/src/gsdll32.rc b/gs/src/gsdll32.rc
new file mode 100644
index 000000000..252a350ff
--- /dev/null
+++ b/gs/src/gsdll32.rc
@@ -0,0 +1,26 @@
+#include <windows.h>
+#include "gp_mswin.h"
+
+GSTEXT_ICON ICON gstext.ico
+GSIMAGE_ICON ICON gsgraph.ico
+
+#ifndef DS_3DLOOK
+#define DS_3DLOOK 0x0004L /* for Windows 95 look */
+#endif
+
+SpoolDlgBox DIALOG 32, 40, 110, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK
+CAPTION "Select Printer Port"
+BEGIN
+ CONTROL "&Ok", IDOK, "button", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 14, 32, 14
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 36, 32, 14
+ CONTROL "", SPOOL_PORT, "LISTBOX", LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 8, 8, 56, 50
+END
+
+CancelDlgBox DIALOG 32, 40, 120, 48
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | DS_3DLOOK
+BEGIN
+ CTEXT "Printing", -1, 8, 4, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CTEXT "", CANCEL_PCDONE, 8, 16, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 44, 30, 32, 14
+END
diff --git a/gs/src/gsdparam.c b/gs/src/gsdparam.c
new file mode 100644
index 000000000..ae6a86f0e
--- /dev/null
+++ b/gs/src/gsdparam.c
@@ -0,0 +1,615 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdparam.c */
+/* Default device parameters for Ghostscript library */
+#include "memory_.h" /* for memcpy */
+#include "string_.h" /* for strlen */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+
+/* Define whether we accept PageSize as a synonym for MediaSize. */
+/* This is for backward compatibility only. */
+#define PAGESIZE_IS_MEDIASIZE
+
+/* ================ Getting parameters ================ */
+
+/* Forward references */
+private bool param_HWColorMap(P2(gx_device *, byte *));
+
+int
+gs_get_device_or_hardware_params(gx_device *dev, gs_param_list *plist,
+ bool is_hardware)
+{ gx_device_set_procs(dev);
+ fill_dev_proc(dev, get_params, gx_default_get_params);
+ fill_dev_proc(dev, get_page_device, gx_default_get_page_device);
+ fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
+ return is_hardware
+ ? (*dev_proc(dev, get_hardware_params))(dev, plist)
+ : (*dev_proc(dev, get_params))(dev, plist);
+}
+
+/* Get the device parameters. */
+int
+gs_getdeviceparams(gx_device *dev, gs_param_list *plist)
+{ return gs_get_device_or_hardware_params(dev, plist, false);
+}
+
+/* Get the hardware parameters. */
+int
+gs_gethardwareparams(gx_device *dev, gs_param_list *plist)
+{ return gs_get_device_or_hardware_params(dev, plist, true);
+}
+
+/* Standard ProcessColorModel values. */
+static const char *pcmsa[] = {
+ "", "DeviceGray", "", "DeviceRGB", "DeviceCMYK"
+};
+
+/* Get standard parameters. */
+int
+gx_default_get_params(gx_device *dev, gs_param_list *plist)
+{
+ int code;
+
+ /* Standard page device parameters: */
+
+ gs_param_string dns, pcms;
+ gs_param_float_array msa, ibba, hwra, ma;
+#define set_param_array(a, d, s)\
+ (a.data = d, a.size = s, a.persistent = false);
+
+ /* Non-standard parameters: */
+
+ int colors = dev->color_info.num_components;
+ int depth = dev->color_info.depth;
+ int GrayValues = dev->color_info.max_gray + 1;
+ int HWSize[2];
+ gs_param_int_array hwsa;
+ gs_param_float_array hwma, mhwra;
+
+ /* Fill in page device parameters. */
+
+ param_string_from_string(dns, dev->dname);
+ { const char *cms = pcmsa[colors];
+ /* We might have an uninitialized device with */
+ /* color_info.num_components = 0.... */
+ if ( *cms != 0 )
+ param_string_from_string(pcms, cms);
+ else
+ pcms.data = 0;
+ }
+ set_param_array(hwra, dev->HWResolution, 2);
+ set_param_array(msa, dev->MediaSize, 2);
+ set_param_array(ibba, dev->ImagingBBox, 4);
+ set_param_array(ma, dev->Margins, 2);
+
+ /* Fill in non-standard parameters. */
+
+ HWSize[0] = dev->width;
+ HWSize[1] = dev->height;
+ set_param_array(hwsa, HWSize, 2);
+ set_param_array(hwma, dev->HWMargins, 4);
+ set_param_array(mhwra, dev->MarginsHWResolution, 2);
+
+ /* Transmit the values. */
+
+ if (
+ /* Standard parameters */
+
+ (code = param_write_name(plist, "OutputDevice", &dns)) < 0 ||
+#ifdef PAGESIZE_IS_MEDIASIZE
+ (code = param_write_float_array(plist, "PageSize", &msa)) < 0 ||
+#endif
+ (code = (pcms.data == 0 ? 0 :
+ param_write_name(plist, "ProcessColorModel", &pcms))) < 0 ||
+ (code = param_write_float_array(plist, "HWResolution", &hwra)) < 0 ||
+ (code = (dev->ImagingBBox_set ?
+ param_write_float_array(plist, "ImagingBBox", &ibba) :
+ param_write_null(plist, "ImagingBBox"))) < 0 ||
+ (code = param_write_float_array(plist, "Margins", &ma)) < 0 ||
+
+ /* Non-standard parameters */
+
+ (code = param_write_int_array(plist, "HWSize", &hwsa)) < 0 ||
+ (code = param_write_float_array(plist, ".HWMargins", &hwma)) < 0 ||
+ (code = param_write_float_array(plist, ".MarginsHWResolution", &mhwra)) < 0 ||
+ (code = param_write_float_array(plist, ".MediaSize", &msa)) < 0 ||
+ (code = param_write_string(plist, "Name", &dns)) < 0 ||
+ (code = param_write_int(plist, "Colors", &colors)) < 0 ||
+ (code = param_write_int(plist, "BitsPerPixel", &depth)) < 0 ||
+ (code = param_write_int(plist, "GrayValues", &GrayValues)) < 0 ||
+ (code = param_write_long(plist, "PageCount", &dev->PageCount)) < 0 ||
+ (code = param_write_bool(plist, ".IgnoreNumCopies", &dev->IgnoreNumCopies)) < 0
+ )
+ return code;
+
+ /* Fill in color information. */
+
+ if ( colors > 1 )
+ { int RGBValues = dev->color_info.max_color + 1;
+ long ColorValues = 1L << depth;
+ if ( (code = param_write_int(plist, "RedValues", &RGBValues)) < 0 ||
+ (code = param_write_int(plist, "GreenValues", &RGBValues)) < 0 ||
+ (code = param_write_int(plist, "BlueValues", &RGBValues)) < 0 ||
+ (code = param_write_long(plist, "ColorValues", &ColorValues)) < 0
+ )
+ return code;
+ }
+
+ if ( param_requested(plist, "HWColorMap") )
+ { byte palette[3 << 8];
+ if ( param_HWColorMap(dev, palette) )
+ { gs_param_string hwcms;
+ hwcms.data = palette, hwcms.size = colors << depth,
+ hwcms.persistent = false;
+ if ( (code = param_write_string(plist, "HWColorMap", &hwcms)) < 0 )
+ return code;
+ }
+ }
+
+ { int tab = (*dev_proc(dev, get_alpha_bits))(dev, go_text);
+ int gab = (*dev_proc(dev, get_alpha_bits))(dev, go_graphics);
+
+ if ( (code = param_write_int(plist, "TextAlphaBits", &tab)) < 0 ||
+ (code = param_write_int(plist, "GraphicsAlphaBits", &gab)) < 0
+ )
+ return code;
+ }
+
+ return 0;
+}
+
+/* Get hardware-detected parameters. Default action is no hardware params. */
+int
+gx_default_get_hardware_params(gx_device *dev, gs_param_list *plist)
+{ return 0;
+}
+
+/* Get the color map for a device. Return true if there is one. */
+private bool
+param_HWColorMap(gx_device *dev, byte *palette /* 3 << 8 */)
+{ int depth = dev->color_info.depth;
+ int colors = dev->color_info.num_components;
+
+ if ( depth <= 8 && colors <= 3 )
+ { byte *p = palette;
+ gx_color_value rgb[3];
+ gx_color_index i;
+ fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
+ for ( i = 0; (i >> depth) == 0; i++ )
+ { int j;
+ if ( (*dev_proc(dev, map_color_rgb))(dev, i, rgb) < 0 )
+ return false;
+ for ( j = 0; j < colors; j++ )
+ *p++ = gx_color_value_to_byte(rgb[j]);
+ }
+ return true;
+ }
+ return false;
+}
+
+/* ================ Putting parameters ================ */
+
+/* Forward references */
+private int param_MediaSize(P4(gs_param_list *, gs_param_name,
+ const float *, gs_param_float_array *));
+#if 0 /****** not used ******/
+private int param_check_bool(P4(gs_param_list *, gs_param_name, bool, bool));
+#endif /****** not used ******/
+private int param_check_long(P4(gs_param_list *, gs_param_name, long, bool));
+#define param_check_int(plist, pname, ival, defined)\
+ param_check_long(plist, pname, (long)(ival), defined)
+private int param_check_bytes(P5(gs_param_list *, gs_param_name, const byte *, uint, bool));
+#define param_check_string(plist, pname, str, defined)\
+ param_check_bytes(plist, pname, (const byte *)str, strlen(str), defined)
+
+/* Set the device parameters. */
+/* If the device was open and the put_params procedure closed it, */
+/* return 1; otherwise, return 0 or an error code as usual. */
+int
+gs_putdeviceparams(gx_device *dev, gs_param_list *plist)
+{ bool was_open = dev->is_open;
+ int code;
+
+ gx_device_set_procs(dev);
+ fill_dev_proc(dev, put_params, gx_default_put_params);
+ fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
+ code = (*dev_proc(dev, put_params))(dev, plist);
+ return (code < 0 ? code : was_open && !dev->is_open ? 1 : code);
+}
+
+/* Set standard parameters. */
+/* Note that setting the size or resolution closes the device. */
+/* Window devices that don't want this to happen must temporarily */
+/* set is_open to false before calling gx_default_put_params, */
+/* and then taking appropriate action afterwards. */
+int
+gx_default_put_params(gx_device *dev, gs_param_list *plist)
+{ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ gs_param_float_array hwra;
+ gs_param_int_array hwsa;
+ gs_param_float_array msa;
+ gs_param_float_array ma;
+ gs_param_float_array hwma;
+ gs_param_float_array mhwra;
+
+ bool ignc = dev->IgnoreNumCopies;
+ gs_param_float_array ibba;
+ bool ibbnull = false;
+ int colors = dev->color_info.num_components;
+ int depth = dev->color_info.depth;
+ int GrayValues = dev->color_info.max_gray + 1;
+ int RGBValues = dev->color_info.max_color + 1;
+ long ColorValues = 1L << depth;
+ gs_param_string cms;
+
+#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
+ switch ( code = pread(plist, (param_name = pname), &(pa)) )\
+ {\
+ case 0:\
+ if ( (pa).size != psize )\
+ ecode = gs_note_error(gs_error_rangecheck);\
+ else {
+/* The body of the processing code goes here. */
+/* If it succeeds, it should do a 'break'; */
+/* if it fails, it should set ecode and fall through. */
+#define END_ARRAY_PARAM(pa, e)\
+ }\
+ goto e;\
+ default:\
+ ecode = code;\
+e: param_signal_error(plist, param_name, ecode);\
+ case 1:\
+ (pa).data = 0; /* mark as not filled */\
+ }
+
+ /*
+ * The HWResolution, HWSize, and MediaSize parameters interact in
+ * the following way:
+ * 1. Setting HWResolution recomputes HWSize from MediaSize.
+ * 2. Setting HWSize recomputes MediaSize from HWResolution.
+ * 3. Setting MediaSize recomputes HWSize from HWResolution.
+ * If more than one parameter is being set, we apply these rules
+ * in the order 1, 2, 3. This does the right thing in the most
+ * common case of setting more than one parameter, namely,
+ * setting both HWResolution and HWSize.
+ */
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
+ if ( hwra.data[0] <= 0 || hwra.data[1] <= 0 )
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ END_ARRAY_PARAM(hwra, hwre)
+
+ BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa)
+ /* We need a special check to handle the nullpage device, */
+ /* whose size is legitimately [0 0]. */
+ if ( (hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
+ (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+#define max_coord (max_fixed / fixed_1)
+#if max_coord < max_int
+ else if ( hwsa.data[0] > max_coord || hwsa.data[1] > max_coord )
+ ecode = gs_note_error(gs_error_limitcheck);
+#endif
+#undef max_coord
+ else
+ break;
+ END_ARRAY_PARAM(hwsa, hwse)
+
+ { const float *res = (hwra.data == 0 ? dev->HWResolution : hwra.data);
+#ifdef PAGESIZE_IS_MEDIASIZE
+ const float *data;
+
+ /* .MediaSize takes precedence over PageSize, so */
+ /* we read PageSize first. */
+ code = param_MediaSize(plist, "PageSize", res, &msa);
+ if ( code < 0 )
+ ecode = code;
+ /* Prevent data from being set to 0 if PageSize is specified */
+ /* but .MediaSize is not. */
+ data = msa.data;
+ code = param_MediaSize(plist, ".MediaSize", res, &msa);
+ if ( code < 0 )
+ ecode = code;
+ else if ( msa.data == 0 )
+ msa.data = data;
+#else
+ code = param_MediaSize(plist, ".MediaSize", res, &msa);
+ if ( code < 0 )
+ ecode = code;
+#endif
+ }
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, "Margins", ma, 2, me)
+ break;
+ END_ARRAY_PARAM(ma, me)
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, ".HWMargins", hwma, 4, hwme)
+ break;
+ END_ARRAY_PARAM(hwma, hwme)
+
+ /* MarginsHWResolution cannot be changed, only checked. */
+ BEGIN_ARRAY_PARAM(param_read_float_array, ".MarginsHWResolution", mhwra, 2, mhwre)
+ if ( mhwra.data[0] != dev->MarginsHWResolution[0] ||
+ mhwra.data[1] != dev->MarginsHWResolution[1]
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ END_ARRAY_PARAM(mhwra, mhwre)
+
+ switch ( code = param_read_bool(plist, (param_name = ".IgnoreNumCopies"), &ignc) )
+ {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+
+ /* Ignore parameters that only have meaning for printers. */
+#define IGNORE_INT_PARAM(pname)\
+ { int igni;\
+ switch ( code = param_read_int(plist, (param_name = pname), &igni) )\
+ { default:\
+ ecode = code;\
+ param_signal_error(plist, param_name, ecode);\
+ case 0:\
+ case 1:\
+ break;\
+ }\
+ }
+ IGNORE_INT_PARAM("%MediaSource")
+ IGNORE_INT_PARAM("%MediaDestination")
+
+ switch ( code = param_read_float_array(plist, (param_name = "ImagingBBox"), &ibba) )
+ {
+ case 0:
+ if ( ibba.size != 4 ||
+ ibba.data[2] < ibba.data[0] || ibba.data[3] < ibba.data[1]
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ goto ibbe;
+ default:
+ if ( (code = param_read_null(plist, param_name)) == 0 )
+ { ibbnull = true;
+ ibba.data = 0;
+ break;
+ }
+ ecode = code; /* can't be 1 */
+ibbe: param_signal_error(plist, param_name, ecode);
+ case 1:
+ ibba.data = 0;
+ break;
+ }
+
+ /* Now check nominally read-only parameters. */
+ if ( (code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_string(plist, "ProcessColorModel", pcmsa[colors], colors != 0)) < 0 )
+ ecode = code;
+ if ( (code = param_check_string(plist, "Name", dev->dname, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "Colors", colors, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "BitsPerPixel", depth, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "GrayValues", GrayValues, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_long(plist, "PageCount", dev->PageCount, true)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "RedValues", RGBValues, colors > 1)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "GreenValues", RGBValues, colors > 1)) < 0 )
+ ecode = code;
+ if ( (code = param_check_int(plist, "BlueValues", RGBValues, colors > 1)) < 0 )
+ ecode = code;
+ if ( (code = param_check_long(plist, "ColorValues", ColorValues, colors > 1)) < 0 )
+ ecode = code;
+ if ( param_read_string(plist, "HWColorMap", &cms) != 1 )
+ { byte palette[3 << 8];
+ if ( param_HWColorMap(dev, palette) )
+ code = param_check_bytes(plist, "HWColorMap", palette,
+ colors << depth, true);
+ else
+ code = param_check_bytes(plist, "HWColorMap", 0, 0, false);
+ if ( code < 0 )
+ ecode = code;
+ }
+ if ( (code =
+ param_check_int(plist, "TextAlphaBits",
+ (*dev_proc(dev, get_alpha_bits))(dev, go_text),
+ true)) < 0
+ )
+ ecode = code;
+ if ( (code =
+ param_check_int(plist, "GraphicsAlphaBits",
+ (*dev_proc(dev, get_alpha_bits))(dev, go_graphics),
+ true)) < 0
+ )
+ ecode = code;
+
+ /* We must 'commit', in order to detect unknown parameters, */
+ /* even if there were errors. */
+ code = param_commit(plist);
+ if ( ecode < 0 )
+ return ecode;
+ if ( code < 0 )
+ return code;
+
+ /* Now actually make the changes. */
+ /* Changing resolution or page size requires closing the device, */
+ /* but changing margins or ImagingBBox does not. */
+ /* In order not to close and reopen the device unnecessarily, */
+ /* we check for replacing the values with the same ones. */
+
+ if ( hwra.data != 0 &&
+ (dev->HWResolution[0] != hwra.data[0] ||
+ dev->HWResolution[1] != hwra.data[1])
+ )
+ { if ( dev->is_open )
+ gs_closedevice(dev);
+ gx_device_set_resolution(dev, hwra.data[0], hwra.data[1]);
+ }
+ if ( hwsa.data != 0 &&
+ (dev->width != hwsa.data[0] ||
+ dev->height != hwsa.data[1])
+ )
+ { if ( dev->is_open )
+ gs_closedevice(dev);
+ gx_device_set_width_height(dev, hwsa.data[0], hwsa.data[1]);
+ }
+ if ( msa.data != 0 &&
+ (dev->MediaSize[0] != msa.data[0] ||
+ dev->MediaSize[1] != msa.data[1])
+ )
+ { if ( dev->is_open )
+ gs_closedevice(dev);
+ gx_device_set_page_size(dev, msa.data[0], msa.data[1]);
+ }
+ if ( ma.data != 0 )
+ { dev->Margins[0] = ma.data[0];
+ dev->Margins[1] = ma.data[1];
+ }
+ if ( hwma.data != 0 )
+ { dev->HWMargins[0] = hwma.data[0];
+ dev->HWMargins[1] = hwma.data[1];
+ dev->HWMargins[2] = hwma.data[2];
+ dev->HWMargins[3] = hwma.data[3];
+ }
+ dev->IgnoreNumCopies = ignc;
+ if ( ibba.data != 0 )
+ { dev->ImagingBBox[0] = ibba.data[0];
+ dev->ImagingBBox[1] = ibba.data[1];
+ dev->ImagingBBox[2] = ibba.data[2];
+ dev->ImagingBBox[3] = ibba.data[3];
+ dev->ImagingBBox_set = true;
+ }
+ else if ( ibbnull )
+ { dev->ImagingBBox_set = false;
+ }
+ return 0;
+}
+
+/* Read .MediaSize or, if supported as a synonym, PageSize. */
+private int
+param_MediaSize(gs_param_list *plist, gs_param_name pname,
+ const float *res, gs_param_float_array *pa)
+{ gs_param_name param_name;
+ int ecode = 0;
+ int code;
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, pname, *pa, 2, mse)
+ float width_new = pa->data[0] * res[0] / 72;
+ float height_new = pa->data[1] * res[1] / 72;
+ if ( width_new < 0 || height_new < 0 )
+ ecode = gs_note_error(gs_error_rangecheck);
+#define max_coord (max_fixed / fixed_1)
+#if max_coord < max_int
+ else if ( width_new > max_coord || height_new > max_coord )
+ ecode = gs_note_error(gs_error_limitcheck);
+#endif
+#undef max_coord
+ else
+ break;
+ END_ARRAY_PARAM(*pa, mse)
+ return ecode;
+}
+
+#if 0 /****** not used ******/
+/* Check that a nominally read-only parameter is being set to */
+/* its existing value. */
+private int
+param_check_bool(gs_param_list *plist, gs_param_name pname, bool value,
+ bool defined)
+{ int code;
+ bool new_value;
+ switch ( code = param_read_bool(plist, pname, &new_value) )
+ {
+ case 0:
+ if ( defined && new_value == value )
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if ( param_read_null(plist, pname) == 0 )
+ return 1;
+e: param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+#endif /****** not used ******/
+private int
+param_check_long(gs_param_list *plist, gs_param_name pname, long value,
+ bool defined)
+{ int code;
+ long new_value;
+ switch ( code = param_read_long(plist, pname, &new_value) )
+ {
+ case 0:
+ if ( defined && new_value == value )
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if ( param_read_null(plist, pname) == 0 )
+ return 1;
+e: param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+private int
+param_check_bytes(gs_param_list *plist, gs_param_name pname, const byte *str,
+ uint size, bool defined)
+{ int code;
+ gs_param_string new_value;
+ switch ( code = param_read_string(plist, pname, &new_value) )
+ {
+ case 0:
+ if ( defined && new_value.size == size &&
+ !memcmp((const char *)str, (const char *)new_value.data,
+ size)
+ )
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if ( param_read_null(plist, pname) == 0 )
+ return 1;
+e: param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
diff --git a/gs/src/gsdps.c b/gs/src/gsdps.c
new file mode 100644
index 000000000..2210d4700
--- /dev/null
+++ b/gs/src/gsdps.c
@@ -0,0 +1,129 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdps.c */
+/* Display PostScript extensions */
+#include "gx.h"
+#include "gsdps.h"
+#include "gspath.h" /* for newpath */
+#include "gxdevice.h" /* for gxcpath.h */
+#include "gzpath.h" /* for gzcpath.h */
+#include "gzstate.h"
+#include "gzcpath.h"
+
+#ifdef DPNEXT
+
+/* Forward references */
+private int common_viewclip(P2(gs_state *, int));
+
+int
+gs_initviewclip(gs_state *pgs)
+{ const gx_clip_path *pcpath = pgs->view_clip->path;
+
+ if ( pcpath->rule != 0 ) {
+ gx_cpath_release(pcpath);
+ gx_cpath_init(pcpath, pcpath->path.memory);
+ pcpath->rule = 0;
+ }
+ return 0;
+}
+
+int
+gs_viewclip(gs_state *pgs)
+{ return common_viewclip(pgs, gx_rule_winding_number);
+}
+
+int
+gs_eoviewclip(gs_state *pgs)
+{ return common_viewclip(pgs, gx_rule_even_odd);
+}
+
+private int
+common_viewclip(gs_state *pgs, int rule)
+{ /*
+ * Temporarily substitute the view clip path for the clip path
+ * so we can use gx_clip_to_path.
+ */
+ gx_clip_path *save_cpath = pgs->clip_path;
+ int code;
+
+ pgs->clip_path = pgs->view_clip->path;
+ code = gx_clip_to_path(pgs);
+ pgs->clip_path = save_cpath;
+ if ( code >= 0 )
+ gs_newpath(pgs);
+ return code;
+}
+
+int
+gs_viewclippath(gs_state *pgs)
+{ gx_path cpath;
+ const gx_clip_path *pcpath = pgs->view_clip->path;
+ int code;
+
+ if ( pcpath->rule == 0 ) {
+ /*
+ * No view clip path is active: fabricate one.
+ ****** SHOULD USE IMAGEABLE AREA, NOT ENTIRE PAGE ******
+ */
+ const gx_device *dev = pgs->device;
+
+ gx_path_init(&cpath, pgs->memory);
+ code = gx_path_add_rectangle(&cpath, fixed_0, fixed_0,
+ int2fixed(dev->width),
+ int2fixed(dev->height));
+ } else {
+ gx_path path;
+
+ code = gx_cpath_path(pcpath, &path);
+ if ( code < 0 )
+ return code;
+ code = gx_path_copy(&path, &cpath, 1);
+ }
+ if ( code < 0 )
+ return code;
+ gx_path_release(pgs->path);
+ *pgs->path = cpath;
+ return 0;
+}
+
+#else /* !DPNEXT */
+
+/* Provide dummy definitions, since gs_state.view_clip doesn't exist. */
+
+int
+gs_initviewclip(gs_state *pgs)
+{ return 0;
+}
+
+int
+gs_viewclip(gs_state *pgs)
+{ return gs_newpath(pgs);
+}
+
+int
+gs_eoviewclip(gs_state *pgs)
+{ return gs_newpath(pgs);
+}
+
+int
+gs_viewclippath(gs_state *pgs)
+{ return gs_initclip(pgs);
+}
+
+#endif
diff --git a/gs/src/gsdps.h b/gs/src/gsdps.h
new file mode 100644
index 000000000..94f72eaab
--- /dev/null
+++ b/gs/src/gsdps.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdps.h */
+/* Client interface to Display PostScript facilities. */
+
+/* View clipping */
+int gs_initviewclip(P1(gs_state *));
+int gs_eoviewclip(P1(gs_state *));
+int gs_viewclip(P1(gs_state *));
+int gs_viewclippath(P1(gs_state *));
diff --git a/gs/src/gsdps1.c b/gs/src/gsdps1.c
new file mode 100644
index 000000000..af0cd9e0c
--- /dev/null
+++ b/gs/src/gsdps1.c
@@ -0,0 +1,231 @@
+/* Copyright (C) 1991, 1992, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdps1.c */
+/* Display PostScript graphics additions for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gspath.h"
+#include "gspath2.h" /* defines interface */
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gzstate.h"
+
+/*
+ * Define how much rounding slop setbbox should leave,
+ * in device coordinates. Because of rounding in transforming
+ * path coordinates to fixed point, the minimum realistic value is:
+ *
+ * #define box_rounding_slop_fixed (fixed_epsilon)
+ *
+ * But even this isn't enough to compensate for cumulative rounding error
+ * in rmoveto or rcurveto. Instead, we somewhat arbitrarily use:
+ */
+#define box_rounding_slop_fixed (fixed_epsilon * 3)
+
+/* ------ Graphics state ------ */
+
+/* Set the bounding box for the current path. */
+int
+gs_setbbox(gs_state *pgs, floatp llx, floatp lly, floatp urx, floatp ury)
+{ gs_rect ubox, dbox;
+ gs_fixed_rect obox, bbox;
+ gx_path *ppath = pgs->path;
+ int code;
+
+ if ( llx > urx || lly > ury )
+ return_error(gs_error_rangecheck);
+ /* Transform box to device coordinates. */
+ ubox.p.x = llx;
+ ubox.p.y = lly;
+ ubox.q.x = urx;
+ ubox.q.y = ury;
+ if ( (code = gs_bbox_transform(&ubox, &ctm_only(pgs), &dbox)) < 0 )
+ return code;
+ /* Round the corners in opposite directions. */
+ /* Because we can't predict the magnitude of the dbox values, */
+ /* we add/subtract the slop after fixing. */
+ if ( dbox.p.x < fixed2float(min_fixed + box_rounding_slop_fixed) ||
+ dbox.p.y < fixed2float(min_fixed + box_rounding_slop_fixed) ||
+ dbox.q.x >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) ||
+ dbox.q.y >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon)
+ )
+ return_error(gs_error_limitcheck);
+ bbox.p.x =
+ (fixed)floor(dbox.p.x * fixed_scale) - box_rounding_slop_fixed;
+ bbox.p.y =
+ (fixed)floor(dbox.p.y * fixed_scale) - box_rounding_slop_fixed;
+ bbox.q.x =
+ (fixed)ceil(dbox.q.x * fixed_scale) + box_rounding_slop_fixed;
+ bbox.q.y =
+ (fixed)ceil(dbox.q.y * fixed_scale) + box_rounding_slop_fixed;
+ if ( gx_path_bbox(ppath, &obox) >= 0 )
+ { /* Take the union of the bboxes. */
+ ppath->bbox.p.x = min(obox.p.x, bbox.p.x);
+ ppath->bbox.p.y = min(obox.p.y, bbox.p.y);
+ ppath->bbox.q.x = max(obox.q.x, bbox.q.x);
+ ppath->bbox.q.y = max(obox.q.y, bbox.q.y);
+ }
+ else /* empty path */
+ { /* Just set the bbox. */
+ ppath->bbox = bbox;
+ }
+ ppath->bbox_set = 1;
+ return 0;
+}
+
+/* ------ Rectangles ------ */
+
+/* Append a list of rectangles to a path. */
+int
+gs_rectappend(gs_state *pgs, const gs_rect *pr, uint count)
+{ for ( ; count != 0; count--, pr++ )
+ { floatp px = pr->p.x, py = pr->p.y, qx = pr->q.x, qy = pr->q.y;
+ int code;
+ /* Ensure counter-clockwise drawing. */
+ if ( (qx >= px) != (qy >= py) )
+ qx = px, px = pr->q.x; /* swap x values */
+ if ( (code = gs_moveto(pgs, px, py)) < 0 ||
+ (code = gs_lineto(pgs, qx, py)) < 0 ||
+ (code = gs_lineto(pgs, qx, qy)) < 0 ||
+ (code = gs_lineto(pgs, px, qy)) < 0 ||
+ (code = gs_closepath(pgs)) < 0
+ )
+ return code;
+ }
+ return 0;
+}
+
+/* Clip to a list of rectangles. */
+int
+gs_rectclip(gs_state *pgs, const gs_rect *pr, uint count)
+{ int code;
+ gx_path old_path;
+ old_path = *pgs->path;
+ gx_path_reset(pgs->path);
+ if ( (code = gs_rectappend(pgs, pr, count)) < 0 ||
+ (code = gs_clip(pgs)) < 0
+ )
+ { gx_path_release(pgs->path);
+ *pgs->path = old_path;
+ return code;
+ }
+ gs_newpath(pgs);
+ gx_path_release(&old_path);
+ return 0;
+}
+
+/* Fill a list of rectangles. */
+/* We take the trouble to do this efficiently in the simple cases. */
+int
+gs_rectfill(gs_state *pgs, const gs_rect *pr, uint count)
+{ const gs_rect *rlist = pr;
+ uint rcount = count;
+ int code;
+
+ gx_set_dev_color(pgs);
+ if ( (is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
+ is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) &&
+ clip_list_is_rectangle(&pgs->clip_path->list) &&
+ gs_state_color_load(pgs) >= 0 &&
+ (*dev_proc(pgs->device, get_alpha_bits))(pgs->device, go_graphics)
+ <= 1
+ )
+ { uint i;
+ gs_fixed_rect clip_rect;
+
+ gx_cpath_inner_box(pgs->clip_path, &clip_rect);
+ for ( i = 0; i < count; ++i )
+ { gs_fixed_point p, q;
+ gs_fixed_rect draw_rect;
+ int x, y, w, h;
+
+ if ( gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 ||
+ gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0
+ )
+ { /* Switch to the slow algorithm. */
+ goto slow;
+ }
+ draw_rect.p.x = min(p.x, q.x) - pgs->fill_adjust.x;
+ draw_rect.p.y = min(p.y, q.y) - pgs->fill_adjust.y;
+ draw_rect.q.x = max(p.x, q.x) + pgs->fill_adjust.x;
+ draw_rect.q.y = max(p.y, q.y) + pgs->fill_adjust.y;
+ rect_intersect(draw_rect, clip_rect);
+ x = fixed2int_pixround(draw_rect.p.x);
+ y = fixed2int_pixround(draw_rect.p.y);
+ w = fixed2int_pixround(draw_rect.q.x) - x;
+ h = fixed2int_pixround(draw_rect.q.y) - y;
+ if ( w > 0 && h > 0 )
+ { if ( gx_fill_rectangle(x, y, w, h, pgs->dev_color, pgs) < 0 )
+ goto slow;
+ }
+ }
+ return 0;
+slow: rlist = pr + i;
+ rcount = count - i;
+ }
+ { bool do_save = !gx_path_is_null(pgs->path);
+
+ if ( do_save )
+ { if ( (code = gs_gsave(pgs)) < 0 )
+ return code;
+ gs_newpath(pgs);
+ }
+ if ( (code = gs_rectappend(pgs, rlist, rcount)) < 0 ||
+ (code = gs_fill(pgs)) < 0
+ )
+ DO_NOTHING;
+ if ( do_save )
+ gs_grestore(pgs);
+ else if ( code < 0 )
+ gs_newpath(pgs);
+ }
+ return code;
+}
+
+/* Stroke a list of rectangles. */
+/* (We could do this a lot more efficiently.) */
+int
+gs_rectstroke(gs_state *pgs, const gs_rect *pr, uint count,
+ const gs_matrix *pmat)
+{ bool do_save = pmat != NULL || !gx_path_is_null(pgs->path);
+ int code;
+
+ if ( do_save )
+ { if ( (code = gs_gsave(pgs)) < 0 )
+ return code;
+ gs_newpath(pgs);
+ }
+ if ( (code = gs_rectappend(pgs, pr, count)) < 0 ||
+ (pmat != NULL && (code = gs_concat(pgs, pmat)) < 0) ||
+ (code = gs_stroke(pgs)) < 0
+ )
+ DO_NOTHING;
+ if ( do_save )
+ gs_grestore(pgs);
+ else if ( code < 0 )
+ gs_newpath(pgs);
+ return code;
+}
diff --git a/gs/src/gsdsc.c b/gs/src/gsdsc.c
new file mode 100644
index 000000000..056d07346
--- /dev/null
+++ b/gs/src/gsdsc.c
@@ -0,0 +1,315 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved. */
+
+/* dsc.c */
+/* Parse DSC comments from a PostScript file. */
+#include "stdpre.h"
+#include <stdio.h>
+#include <malloc.h>
+#include <math.h>
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Define the maximum length of a line in a DSC-conforming file. */
+/* This is 255 characters + 2 for newline + 1 for null. */
+#define line_size 258
+
+/* Test whether a line begins with %%. */
+#define is_dsc_comment(line) ((line)[0] == '%' && (line)[1] == '%')
+
+/* Test whether a string begins with a given prefix. */
+#define has_prefix(str, pre) !strncmp(str, pre, strlen(pre))
+/* Faster test if prefix is a literal string. */
+#define has_lit_prefix(str, litpre) !strncmp(str, litpre, sizeof(litpre) - 1)
+/* Test whether a line is a specific DSC comment. */
+#define has_dsc_prefix(line, litpre)\
+ (is_dsc_comment(line) && has_lit_prefix(line, litpre))
+
+/* Define a bounding box structure. */
+#define LLX 0
+#define LLY 1
+#define URX 2
+#define URY 3
+
+/* ------ Internal routines ------ */
+
+/* Allocate a block with malloc, exiting on failure. */
+private void *
+dsc_malloc(size_t size)
+{ void *blk = malloc(size);
+ if ( blk == 0 )
+ { fprintf(stderr, "Unable to allocate object; giving up.\n");
+ exit(255);
+ }
+ return blk;
+}
+
+/* Copy a given amount of data from one file to another (to != NULL) or */
+/* skip a given amount of data in a file without using fseek (to == NULL). */
+#define fcpy_size 5000
+private void
+fcpy(FILE *to, FILE *from, long len)
+{ char buf[fcpy_size];
+ size_t count;
+ for ( ; len > 0; len -= count )
+ { count = (len > fcpy_size ? fcpy_size : len);
+ fread(buf, sizeof(char), count, from);
+ if ( to != NULL )
+ fwrite(buf, sizeof(char), count, to);
+ }
+}
+#undef fcpy_size
+
+/*
+ * Copy (or skip) a %%BeginBinary/%%EndBinary section.
+ * Return the number of bytes copied or skipped.
+ */
+private long
+copy_binary(FILE *to, FILE *from, const char *line)
+{ long count;
+ if ( sscanf(line + 14, "%ld", &count) == 1 )
+ fcpy(to, from, count);
+ else
+ count = 0;
+ return count;
+}
+
+/*
+ * Copy (or skip) a %%BeginData/%%EndData section.
+ * Return the number of bytes copied or skipped.
+ */
+private long
+copy_data(FILE *to, FILE *from, const char *line)
+{ long count, amount = 0;
+ char str[line_size];
+ str[0] = '\0';
+ if ( sscanf(line + 12, "%ld %*s %s", &count, str) >= 1 )
+ { if ( !strcmp(str, "Lines") )
+ for ( ; count > 0; --count )
+ { if ( !fgets(str, line_size, from) )
+ break;
+ amount += strlen(str);
+ if ( to != NULL )
+ fputs(str, to);
+ }
+ else
+ { amount = count;
+ fcpy(to, from, count);
+ }
+ }
+ return amount;
+}
+
+/*
+ * Read the next line from the input. Skip over embedded data, and also
+ * skip sections (such as procsets, fonts, and included documents) that
+ * are not part of the main document flow.
+ * Return a pointer to the input line, or NULL if we reached EOF.
+ */
+private void skip_region(P4(char *, FILE *, long *, const char *));
+private char *
+next_line(char *line, FILE *in, long *pstart, long *plen)
+{ if ( pstart )
+ *pstart = ftell(in);
+ *plen = 0;
+ for ( ; ; )
+ { if ( !fgets(line, line_size, in) ) /* EOF */
+ { line[0] = 0;
+ return 0;
+ }
+ *plen += strlen(line);
+ if ( !has_dsc_comment(line, "Begin") )
+ break;
+ else if ( has_lit_prefix(line+7, "Binary:") )
+ { *plen += copy_binary(NULL, in, line);
+ skip_region(line, in, plen, "EndBinary");
+ }
+ else if ( has_lit_prefix(line+7, "Data:") )
+ { *plen += copy_data(NULL, in, line);
+ skip_region(line, in, plen, "EndData");
+ }
+ else if ( has_lit_prefix(line+7, "Feature:") )
+ skip_region(line, in, plen, "EndFeature");
+ else if ( has_lit_prefix(line+7, "File:") )
+ skip_region(line, in, plen, "EndFile");
+ else if ( has_lit_prefix(line+7, "Font:") )
+ skip_region(line, in, plen, "EndFont");
+ else if ( has_lit_prefix(line+7, "ProcSet:") )
+ skip_region(line, in, plen, "EndProcSet");
+ else if ( has_lit_prefix(line+7, "Resource:") )
+ skip_region(line, in, plen, "EndResource");
+ }
+ return line;
+}
+/*
+ * Skip a region of the PostScript file up to a given %%End comment.
+ */
+private void
+skip_region(char *line, FILE *in, long *plen, const char *end_comment)
+{ do
+ { long len;
+ if ( next_line(line, in, NULL, &len) == NULL )
+ break;
+ *plen += len;
+ }
+ while ( !has_dsc_prefix(line, end_comment) );
+}
+
+/*
+ * Scan a bounding box argument. Return 1 iff we found one.
+ */
+private int
+scan_bbox(const char *line, int bbox[4])
+{ float fx0, fy0, fx1, fy1;
+ if ( sscanf(line, "%d %d %d %d", &bbox[LLX], &bbox[LLY],
+ &bbox[URX], &bbox[URY]) == 4
+ )
+ return 1;
+ if ( sscanf(line, "%f %f %f %f", &fx0, &fy0, &fx1, &fy1) != 4 )
+ return 0;
+ bbox[LLX] = (int)floor(fx0);
+ bbox[LLY] = (int)floor(fy0);
+ bbox[URX] = (int)ceil(fx1);
+ bbox[URY] = (int)ceil(fy1);
+ return 1;
+}
+
+/*
+ * Scan a text argument, recognizing escapes if it is a parenthesized string.
+ * If the string is not parenthesized then if rest = 1, take the rest of
+ * the line as the argument; if rest = 0, only take up to the next whitespace.
+ */
+#define scan_text_arg(line, endp) scan_text(line, endp, 0)
+#define scan_line_arg(line, endp) scan_text(line, endp, 1)
+private const char *
+scan_text(const char *line, const char **endp, int rest)
+{ char buf[line_size];
+ const char *lp = line;
+ char *bp = buf;
+ char *arg;
+
+ while ( *lp == ' ' || *lp == '\t' )
+ lp++;
+ if ( *lp == '(' )
+ { int level = 1;
+ lp++;
+ for ( ; ; )
+ switch ( *bp++ = *lp++ )
+ {
+ case '\\':
+ switch ( *lp++ )
+ {
+ case 'n':
+ bp[-1] = '\n'; break;
+ case 'r':
+ bp[-1] = '\r'; break;
+ case 't':
+ bp[-1] = '\t'; break;
+ case 'b':
+ bp[-1] = '\b'; break;
+ case 'f':
+ bp[-1] = '\f'; break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ { int c = lp[-1] - '0';
+ int d = *lp;
+ if ( d >= '0' && d <= '7' )
+ { c = (c << 3) + d - '0';
+ d = *++lp;
+ if ( d >= '0' && d <= '7' )
+ { c = (c << 3) + d - '0';
+ lp++;
+ }
+ }
+ bp[-1] = c;
+ break;
+ }
+ case 0: /* unexpected EOF */
+ lp--;
+ goto out;
+ default:
+ bp[-1] = lp[-1];
+ }
+ break;
+ case '(':
+ ++level;
+ break;
+ case ')':
+ if ( --level )
+ break;
+ case 0:
+ goto out;
+ default:
+ ;
+ }
+ out: --bp;
+ }
+ else
+ { /* Not quoted. */
+ while ( !(*lp == 0 || *lp == '\n' ||
+ (!rest && (*lp == ' ' || *lp == '\t')))
+ )
+ *bp++ = *lp++;
+ if ( bp == buf ) /* empty */
+ return NULL;
+ }
+ *bp = 0;
+ if ( endp )
+ *endp = lp;
+ arg = dsc_malloc(bp - buf + 1);
+ strcpy(arg, buf);
+ return arg;
+}
+
+/* ------ Public routines ------ */
+
+/*
+ * Copy a section of a DSC-conforming PostScript file.
+ * Detect %%(Begin|End)(Binary|Data) comments and copy the intervening
+ * data as binary if necessary. If a sentinel is specified,
+ * stop copying when we reach a line that begins with the sentinel.
+ * If start < 0, don't seek before copying.
+ */
+private int dsc_copy_section(P6(FILE *from, FILE *to, long start, long end,
+ char *line, const char *sentinel));
+void
+dsc_copy(FILE *from, FILE *to, long start, long end)
+{ char line[line_size];
+ dsc_copy_section(from, to, start, end, line, NULL);
+}
+char *
+dsc_copy_until(FILE *from, FILE *to, long start, long end,
+ const char *sentinel)
+{ char line[line_size];
+ int found = dsc_copy_section(from, to, start, end, line, sentinel);
+ if ( found )
+ { char *ret = dsc_malloc(strlen(line) + 1);
+ strcpy(ret, line);
+ return ret;
+ }
+ return NULL;
+}
+private int
+dsc_copy_section(FILE *from, FILE *to, long start, long end,
+ char *line, const char *sentinel)
+{ int sent_len = (sentinel == 0 ? 0 : strlen(sentinel));
+
+ if ( start >= 0 )
+ fseek(from, start, SEEK_SET);
+ while ( ftell(from) < end )
+ { long count;
+ fgets(line, line_size, from);
+ if ( sent_len )
+ { if ( !strncmp(line, sentinel, sent_len) )
+ return 1;
+ }
+ fputs(line, to);
+ if ( !has_dsc_prefix(line, "Begin") )
+ ;
+ else if ( has_lit_prefix(line + 7, "Binary:") )
+ copy_binary(to, from, line);
+ else if ( has_lit_prefix(line + 7, "Data:") )
+ copy_data(to, from, line);
+ }
+ return 0;
+}
diff --git a/gs/src/gsdsrc.c b/gs/src/gsdsrc.c
new file mode 100644
index 000000000..3639edbc8
--- /dev/null
+++ b/gs/src/gsdsrc.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdsrc.c */
+/* DataSource procedures */
+
+#include "memory_.h"
+#include "gx.h"
+#include "gsdsrc.h"
+#include "gserrors.h"
+#include "stream.h"
+
+/* GC descriptor */
+public_st_data_source();
+#define psrc ((gs_data_source_t *)vptr)
+private ENUM_PTRS_BEGIN(data_source_enum_ptrs) {
+ if ( psrc->access == data_source_access_string )
+ ENUM_RETURN_CONST_STRING_PTR(gs_data_source_t, data.str);
+ else if ( psrc->access == data_source_access_bytes )
+ ENUM_RETURN_PTR(gs_data_source_t, data.str.data);
+ else /*if ( psrc->access == data_source_access_stream )*/
+ ENUM_RETURN_PTR(gs_data_source_t, data.strm);
+} ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(data_source_reloc_ptrs) {
+ if ( psrc->access == data_source_access_string )
+ RELOC_CONST_STRING_PTR(gs_data_source_t, data.str);
+ else if ( psrc->access == data_source_access_bytes )
+ RELOC_PTR(gs_data_source_t, data.str.data);
+ else /*if ( psrc->access == data_source_access_stream )*/
+ RELOC_PTR(gs_data_source_t, data.strm);
+} RELOC_PTRS_END
+#undef psrc
+
+/* Access data from a string or a byte object. */
+/* Does *not* check bounds. */
+int
+data_source_access_string(const gs_data_source_t *psrc, ulong start,
+ uint length, byte *buf, const byte **ptr)
+{ const byte *p = psrc->data.str.data + start;
+
+ if ( ptr )
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ return 0;
+}
+/* access_bytes is identical to access_string, but has a different */
+/* GC procedure. */
+int
+data_source_access_bytes(const gs_data_source_t *psrc, ulong start,
+ uint length, byte *buf, const byte **ptr)
+{ const byte *p = psrc->data.str.data + start;
+
+ if ( ptr )
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ return 0;
+}
+
+/* Access data from a stream. */
+/* Returns gs_error_rangecheck if out of bounds. */
+int
+data_source_access_stream(const gs_data_source_t *psrc, ulong start,
+ uint length, byte *buf, const byte **ptr)
+{ stream *s = psrc->data.strm;
+ const byte *p;
+
+ if ( start >= s->position &&
+ (p = start - s->position + s->cbuf) + length <=
+ s->cursor.r.limit + 1
+ ) {
+ if ( ptr )
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ } else {
+ uint nread;
+ int code = sseek(s, start);
+
+ if ( code < 0 )
+ return_error(gs_error_rangecheck);
+ code = sgets(s, buf, length, &nread);
+ if ( code < 0 )
+ return_error(gs_error_rangecheck);
+ if ( nread != length )
+ return_error(gs_error_rangecheck);
+ if ( ptr )
+ *ptr = buf;
+ }
+ return 0;
+}
diff --git a/gs/src/gsdsrc.h b/gs/src/gsdsrc.h
new file mode 100644
index 000000000..a0a423183
--- /dev/null
+++ b/gs/src/gsdsrc.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsdsrc.h */
+/* DataSource definitions */
+
+#ifndef gsdsrc_INCLUDED
+# define gsdsrc_INCLUDED
+
+#include "gsstruct.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * A gs_data_source_t represents the data source for various constructs.
+ * Shading. It can be either a string (either a gs_string or a byte-type
+ * object) or a positionable, non-procedure-based stream. An ordinary
+ * positionable file stream will do, as long as the client doesn't attempt
+ * to read past the EOF.
+ */
+
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+#endif
+
+/*
+ * Prepare to access a block of data from a source. buf must be a client-
+ * supplied buffer of at least length bytes. If ptr == 0, always copy the
+ * data into buf. If ptr != 0, either copy the data into buf and set *ptr =
+ * buf, or set *ptr to point to the data (which might be invalidated by the
+ * next call). Note that this procedure may or may not do bounds checking.
+ */
+#define data_source_proc_access(proc)\
+ int proc(P5(const gs_data_source_t *psrc, ulong start, uint length,\
+ byte *buf, const byte **ptr))
+
+typedef struct gs_data_source_s gs_data_source_t;
+struct gs_data_source_s {
+ data_source_proc_access((*access));
+ union d_ {
+ gs_const_string str; /* also used for byte objects */
+ stream *strm;
+ } data;
+};
+
+#define data_source_access_only(psrc, start, length, buf, ptr)\
+ (*(psrc)->access)(psrc, (ulong)(start), length, buf, ptr)
+#define data_source_access(psrc, start, length, buf, ptr)\
+ do {\
+ int code_ = data_source_access_only(psrc, start, length, buf, ptr);\
+ if ( code_ < 0 ) return code_;\
+ } while ( 0 )
+#define data_source_copy_only(psrc, start, length, buf)\
+ data_source_access_only(psrc, start, length, buf, (const byte **)0)
+#define data_source_copy(psrc, start, length, buf)\
+ data_source_access(psrc, start, length, buf, (const byte **)0)
+
+/*
+ * Data sources are always embedded in other structures, but they do have
+ * pointers that need to be traced and relocated, so they do have a GC
+ * structure type.
+ */
+extern_st(st_data_source);
+#define public_st_data_source() /* in gsdsrc.c */\
+ gs_public_st_composite(st_data_source, gs_data_source_t, "gs_data_source_t",\
+ data_source_enum_ptrs, data_source_reloc_ptrs)
+#define st_data_source_max_ptrs 1
+
+/* ---------------- Procedures ---------------- */
+
+/* Initialize a data source of the various known types. */
+data_source_proc_access(data_source_access_string);
+#define data_source_init_string(psrc, strg)\
+ ((psrc)->data.str = strg, (psrc)->access = data_source_access_string)
+#define data_source_init_string2(psrc, bytes, len)\
+ ((psrc)->data.str.data = bytes, (psrc)->data.str.size = len,\
+ (psrc)->access = data_source_access_string)
+data_source_proc_access(data_source_access_bytes);
+#define data_source_init_bytes(psrc, bytes)\
+ ((psrc)->data.str.data = bytes, (psrc)->access = data_source_access_bytes)
+data_source_proc_access(data_source_access_stream);
+#define data_source_init_stream(psrc, s)\
+ ((psrc)->data.strm = s, (psrc)->access = data_source_access_stream)
+
+#endif /* gsdsrc_INCLUDED */
diff --git a/gs/src/gserror.h b/gs/src/gserror.h
new file mode 100644
index 000000000..eab942593
--- /dev/null
+++ b/gs/src/gserror.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gserror.h */
+/* Error return macros */
+
+#ifndef gserror_INCLUDED
+# define gserror_INCLUDED
+
+#ifdef DEBUG
+int gs_log_error(P3(int, const char _ds *, int));
+#else
+# define gs_log_error(err, file, line) (err)
+#endif
+#define gs_note_error(err) gs_log_error(err, __FILE__, __LINE__)
+#define return_error(err) return gs_note_error(err)
+#define return_if_error(expr)\
+ do { int code_ = (expr); if ( code_ < 0 ) return code; } while ( 0 )
+
+#endif /* gserror_INCLUDED */
diff --git a/gs/src/gserrors.h b/gs/src/gserrors.h
new file mode 100644
index 000000000..9f25a8d6f
--- /dev/null
+++ b/gs/src/gserrors.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1989, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gserrors.h */
+/* Error code definitions */
+
+/* A procedure that may return an error always returns */
+/* a non-negative value (zero, unless otherwise noted) for success, */
+/* or negative for failure. */
+/* We use ints rather than an enum to avoid a lot of casting. */
+
+#define gs_error_unknownerror (-1) /* unknown error */
+#define gs_error_interrupt (-6)
+#define gs_error_invalidaccess (-7)
+#define gs_error_invalidfileaccess (-9)
+#define gs_error_invalidfont (-10)
+#define gs_error_ioerror (-12)
+#define gs_error_limitcheck (-13)
+#define gs_error_nocurrentpoint (-14)
+#define gs_error_rangecheck (-15)
+#define gs_error_typecheck (-20)
+#define gs_error_undefined (-21)
+#define gs_error_undefinedfilename (-22)
+#define gs_error_undefinedresult (-23)
+#define gs_error_VMerror (-25)
+#define gs_error_unregistered (-29)
+
+#define gs_error_Fatal (-100)
diff --git a/gs/src/gserver.c b/gs/src/gserver.c
new file mode 100644
index 000000000..eaf85aa2b
--- /dev/null
+++ b/gs/src/gserver.c
@@ -0,0 +1,290 @@
+/* Copyright (C) 1992, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gserver.c */
+/* Server front end for Ghostscript, replacing gs.c. */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "imemory.h" /* for iutil.h */
+#include "interp.h" /* for gs_interp_reset */
+#include "iutil.h" /* for obj_cvs */
+#include "main.h"
+#include "ostack.h"
+#include "store.h"
+#include "gspaint.h" /* for gs_erasepage */
+
+/*
+ * This file provides a very simple procedural interface to the Ghostscript
+ * PostScript/PDF language interpreter, with a rudimentary provision for
+ * saving and restoring state around "jobs".
+ * See below for the descriptions of individual procedures.
+ *
+ * All routines in this file return an integer value which is 0 if the
+ * routine completed successfully, non-0 if an error occurred.
+ */
+
+/* ------ Public interface ------ */
+
+/*
+ * Initialize Ghostscript. fno_stdin, fno_stdout, and fno_stderr are
+ * file handles that Ghostscript will use in place of stdin, stdout,
+ * and stderr respectively. This routine should be called once at the
+ * beginning of execution, and not after that.
+ *
+ * This routine establishes a "baseline" initial state for Ghostscript,
+ * which includes reading in the standard Ghostscript initialization files
+ * such as gs_init.ps and gs_fonts.ps. This baseline is always used as the
+ * starting state for gs_server_run_string and gs_server_run_files, unless
+ * modified as described below.
+ *
+ * This routine 'opens' the default driver.
+ */
+
+int gs_server_initialize(P4(int fno_stdin, int fno_stdout, int fno_stderr,
+ const char *init_str));
+
+/*
+ * Execute a string containing PostScript code. The effects of this code
+ * do modify the baseline state for future calls of ...run_string and
+ * ...run_files. There are four cases of return values:
+ * value = 0: normal return.
+ * value = e_Quit: the PostScript code executed a `quit'.
+ * value = e_Fatal: the PostScript code encountered a fatal error.
+ * *exit_code_ptr holds the C exit code.
+ * other value: the PostScript code encountered a PostScript error
+ * while processing another error, or some other fatal
+ * PostScript error.
+ *
+ * errstr points to a string area of length errstr_max_len for reporting
+ * the PostScript object causing the error. In the case of an error return,
+ * the characters from errstr[0] through errstr[*errstr_len_ptr-1] will
+ * contain a representation of the error object. *errstr_len_ptr will not
+ * exceed errstr_max_len.
+ */
+
+int gs_server_run_string(P5(const char *str, int *exit_code_ptr,
+ char *errstr, int errstr_max_len,
+ int *errstr_len_ptr));
+
+/*
+ * Run a sequence of files containing PostScript code. If permanent is 0,
+ * the files do not affect the baseline state; if permanent is 1, they do
+ * affect the baseline state, just like ...run_string. The returned value,
+ * exit code, and error string are the same as for gs_server_run_string.
+ *
+ * If permanent is 0, the output page buffer is cleared before running the
+ * first file (equivalent to `erasepage').
+ */
+
+int gs_server_run_files(P6(const char **file_names, int permanent,
+ int *exit_code_ptr, char *errstr,
+ int errstr_max_len, int *errstr_len_ptr));
+
+/*
+ * Terminate Ghostscript. Ghostscript will release all memory and close
+ * all files it has opened, including the ones referenced by fno_stdin,
+ * fno_stdout, and fno_stderr.
+ *
+ * This routine 'closes' the default driver.
+ */
+
+int gs_server_terminate(P0());
+
+/* ------ Example of use ------ */
+
+/* To run this example, change the 0 to 1 in the following line. */
+#if 0
+
+/*
+ * This example predefines the name fubar, prints out its value,
+ * and then renders the golfer art file supplied with Ghostscript.
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+int
+main(int argc, char *argv[])
+{ int code, exit_code;
+#define emax 50
+ char errstr[emax+1];
+ int errlen;
+ static const char *fnames[] = { "golfer.ps", 0 };
+ FILE *cin = fopen("stdin.tmp", "w+");
+ int sout = open("stdout.tmp", O_WRONLY|O_CREAT|O_TRUNC,
+ S_IREAD|S_IWRITE);
+ int serr = open("stderr.tmp", O_WRONLY|O_CREAT|O_TRUNC,
+ S_IREAD|S_IWRITE);
+ code = gs_server_initialize(fileno(cin), sout, serr,
+ "/fubar 42 def");
+ fprintf(stdout, "init: code %d\n", code);
+ if ( code < 0 ) goto x;
+ code = gs_server_run_string("fubar == flush", &exit_code,
+ errstr, emax, &errlen);
+ fprintf(stdout, "print: code %d\n", code);
+ if ( code < 0 ) goto x;
+ code = gs_server_run_files(fnames, 0, &exit_code,
+ errstr, emax, &errlen);
+ fprintf(stdout, "golfer: code %d\n", code);
+ if ( code < 0 ) goto x;
+ errlen = 0;
+ code = gs_server_run_string("fubar 0 div", &exit_code,
+ errstr, emax, &errlen);
+ errstr[errlen] = 0;
+ fprintf(stdout, "0 div: code %d object %s\n", code, errstr);
+ errlen = 0;
+ code = gs_server_run_string("xxx", &exit_code,
+ errstr, emax, &errlen);
+ errstr[errlen] = 0;
+ fprintf(stdout, "undef: code %d object %s\n", code, errstr);
+x: code = gs_server_terminate();
+ fprintf(stdout, "end: code %d\n", code);
+ fflush(stdout);
+ close(serr);
+ close(sout);
+ fclose(cin);
+ return code;
+}
+
+#endif
+
+/* ------ Private definitions ------ */
+
+/* Forward references */
+private int job_begin(P0());
+private int job_end(P0());
+private void errstr_report(P4(ref *, char *, int, int *));
+
+/* ------ Public routines ------ */
+
+/* Initialize Ghostscript. */
+
+int
+gs_server_initialize(int fno_stdin, int fno_stdout, int fno_stderr,
+ const char *init_str)
+{ int code, exit_code; /* discard exit_code for now */
+ int errstr_len; /* discard */
+ FILE *c_stdin, *c_stdout, *c_stderr;
+ /* Establish C-compatible files for stdout and stderr. */
+ c_stdin = fdopen(fno_stdin, "r");
+ if ( c_stdin == NULL ) return -1;
+ c_stdout = fdopen(fno_stdout, "w");
+ if ( c_stdout == NULL ) return -1;
+ c_stderr = fdopen(fno_stderr, "w");
+ if ( c_stderr == NULL ) return -1;
+ /* Initialize the Ghostscript interpreter. */
+ gs_init0(c_stdin, c_stdout, c_stderr, 0);
+ gs_init1();
+ gs_init2();
+ code = gs_server_run_string("/QUIET true def /NOPAUSE true def",
+ &exit_code,
+ (char *)0, 0, &errstr_len);
+ if ( code < 0 ) return code;
+ return (init_str == NULL ? 0 :
+ gs_server_run_string(init_str, &exit_code,
+ (char *)0, 0, &errstr_len));
+}
+
+/* Run a string. */
+
+int
+gs_server_run_string(const char *str, int *exit_code_ptr,
+ char *errstr, int errstr_max_len, int *errstr_len_ptr)
+{ ref error_object;
+ int code;
+ make_tasv(&error_object, t_string, 0, 0, bytes, 0);
+ code = gs_run_string(str, 0, exit_code_ptr, &error_object);
+ if ( code < 0 )
+ errstr_report(&error_object, errstr, errstr_max_len,
+ errstr_len_ptr);
+ return code;
+}
+
+/* Run files. */
+
+int
+gs_server_run_files(const char **file_names, int permanent,
+ int *exit_code_ptr, char *errstr, int errstr_max_len, int *errstr_len_ptr)
+{ int code = 0;
+ ref error_object;
+ const char **pfn;
+ if ( !permanent ) job_begin();
+ make_tasv(&error_object, t_string, 0, 0, bytes, 0);
+ for ( pfn = file_names; *pfn != NULL && code == 0; pfn++ )
+ code = gs_run_file(*pfn, 0, exit_code_ptr, &error_object);
+ if ( !permanent ) job_end();
+ if ( code < 0 )
+ errstr_report(&error_object, errstr, errstr_max_len,
+ errstr_len_ptr);
+ return code;
+}
+
+/* Terminate Ghostscript. */
+
+int
+gs_server_terminate()
+{ gs_finit(0, 0);
+ return 0;
+}
+
+/* ------ Private routines ------ */
+
+private ref job_save; /* 'save' object for baseline state */
+
+extern int zsave(P1(os_ptr)), zrestore(P1(os_ptr));
+
+/* Start a 'job' by restoring the baseline state. */
+
+private int
+job_begin()
+{ int code;
+ /* Aladdin Ghostscript doesn't provide erasepage as an operator. */
+ /* However, we can get the same effect by calling gs_erasepage. */
+ extern gs_state *igs;
+ if ( (code = gs_erasepage(igs)) < 0 )
+ return code;
+ code = zsave(osp);
+ if ( code == 0 )
+ job_save = *osp--;
+ return code;
+}
+
+/* End a 'job'. */
+
+private int
+job_end()
+{ gs_interp_reset();
+ *++osp = job_save;
+ return zrestore(osp);
+}
+
+/* Produce a printable representation of an error object. */
+
+private void
+errstr_report(ref *perror_object, char *errstr, int errstr_max_len,
+ int *errstr_len_ptr)
+{ int code = obj_cvs(perror_object, (byte *)errstr,
+ (uint)errstr_max_len, (uint *)errstr_len_ptr,
+ false);
+ if ( code < 0 )
+ { const char *ustr = "[unprintable]";
+ int len = min(strlen(ustr), errstr_max_len);
+ memcpy(errstr, ustr, len);
+ *errstr_len_ptr = len;
+ }
+}
diff --git a/gs/src/gsexit.h b/gs/src/gsexit.h
new file mode 100644
index 000000000..f09f9b68a
--- /dev/null
+++ b/gs/src/gsexit.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsexit.h */
+/* Declarations for exits */
+
+#ifndef gsexit_INCLUDED
+# define gsexit_INCLUDED
+
+void gs_exit_with_code(P2(int exit_status, int code));
+void gs_exit(P1(int exit_status));
+#define gs_abort() gs_exit(1)
+
+/* The only reason we export gs_exit_status is so that window systems */
+/* with alert boxes can know whether to pause before exiting if */
+/* the program terminates with an error. There must be a better way .... */
+extern int gs_exit_status;
+
+#endif /* gsexit_INCLUDED */
diff --git a/gs/src/gsfcmap.c b/gs/src/gsfcmap.c
new file mode 100644
index 000000000..874647ddd
--- /dev/null
+++ b/gs/src/gsfcmap.c
@@ -0,0 +1,153 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfcmap.c */
+/* CMap character decoding */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfcmap.h"
+
+/* CMap structure descriptors */
+public_st_cmap();
+public_st_code_map();
+public_st_code_map_element();
+#define pcmap ((gx_code_map *)vptr)
+/* Because code maps can be elements of arrays, */
+/* their enum_ptrs procedure must never return 0 prematurely. */
+private ENUM_PTRS_BEGIN(code_map_enum_ptrs) return 0;
+ ENUM_PTR(0, gx_code_map, cmap);
+ case 1:
+ switch ( pcmap->type )
+ {
+ case cmap_glyph:
+ (*pcmap->cmap->mark_glyph)(pcmap->data.glyph,
+ pcmap->cmap->mark_glyph_data);
+ default:
+ ENUM_RETURN(0);
+ case cmap_subtree:
+ ENUM_RETURN_PTR(gx_code_map, data.subtree);
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(code_map_reloc_ptrs) ;
+ switch ( pcmap->type )
+ {
+ case cmap_subtree:
+ RELOC_PTR(gx_code_map, data.subtree);
+ break;
+ default:
+ ;
+ }
+ RELOC_PTR(gx_code_map, cmap);
+RELOC_PTRS_END
+#undef pcmap
+/* CIDSystemInfo structure */
+gs_public_st_composite(st_cid_system_info, gs_cid_system_info,
+ "gs_cid_system_info", cid_si_enum_ptrs, cid_si_reloc_ptrs);
+#define pcidsi ((gs_cid_system_info *)vptr)
+private ENUM_PTRS_BEGIN(cid_si_enum_ptrs) return 0;
+ ENUM_CONST_STRING_PTR(0, gs_cid_system_info, Registry);
+ ENUM_CONST_STRING_PTR(1, gs_cid_system_info, Ordering);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cid_si_reloc_ptrs) ;
+ RELOC_CONST_STRING_PTR(gs_cid_system_info, Registry);
+ RELOC_CONST_STRING_PTR(gs_cid_system_info, Ordering);
+RELOC_PTRS_END
+#undef pcidsi
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Decode a character from a string using a code map, updating the index.
+ * Return 0 for a CID or name, N > 0 for a character code where N is the
+ * number of bytes in the code, or an error. For undefined characters,
+ * we set *pglyph = gs_no_glyph and return 0.
+ */
+private int
+code_map_decode_next(const gx_code_map *pcmap, const gs_const_string *str,
+ uint *pindex, uint *pfidx, gs_glyph *pglyph)
+{ const gx_code_map *map = pcmap;
+ uint chr = 0;
+
+ for ( ; ; )
+ { int result;
+
+ switch ( (gx_code_map_type)map->type )
+ {
+ case cmap_char_code:
+ *pglyph = (gs_glyph)map->data.ccode;
+ result = map->num_bytes1 + 1;
+leaf: if ( chr > map->last )
+ goto undef;
+ if ( map->add_offset )
+ *pglyph += chr - map->first;
+ *pfidx = map->byte_data.font_index;
+ return result;
+ case cmap_glyph:
+ *pglyph = map->data.glyph;
+ result = 0;
+ goto leaf;
+ case cmap_subtree:
+ if ( *pindex >= str->size )
+ return_error(gs_error_rangecheck);
+ chr = str->data[(*pindex)++];
+ if ( chr >= map->data.subtree[0].first )
+ { /* Invariant: map[lo].first <= chr < map[hi].first. */
+ uint lo = 0, hi = map->byte_data.count1 + 1;
+
+ map = map->data.subtree;
+ while ( lo + 1 < hi )
+ { uint mid = (lo + hi) >> 1;
+ if ( chr >= map[mid].first )
+ lo = mid;
+ else
+ hi = mid;
+ }
+ map = &map[lo];
+ continue;
+ }
+undef: *pglyph = gs_no_glyph;
+ return 0;
+ default: /* (can't happen) */
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/*
+ * Decode a character from a string using a CMap.
+ * Return like code_map_decode_next.
+ */
+int
+gs_cmap_decode_next(const gs_cmap *pcmap, const gs_const_string *str,
+ uint *pindex, uint *pfidx, gs_glyph *pglyph)
+{ uint save_index = *pindex;
+ int code =
+ code_map_decode_next(&pcmap->def, str, pindex, pfidx, pglyph);
+
+ if ( code != 0 || *pglyph != gs_no_glyph )
+ return code;
+ /* This is an undefined character. Use the notdef map. */
+ { uint next_index = *pindex;
+ *pindex = save_index;
+ code =
+ code_map_decode_next(&pcmap->notdef, str, pindex, pfidx, pglyph);
+ *pindex = next_index;
+ }
+ return code;
+}
diff --git a/gs/src/gsfcmap.h b/gs/src/gsfcmap.h
new file mode 100644
index 000000000..53ab4058b
--- /dev/null
+++ b/gs/src/gsfcmap.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfcmap.h */
+/* CMap data definition */
+/* Requires gsstruct.h */
+
+#ifndef gsfcmap_INCLUDED
+# define gsfcmap_INCLUDED
+
+#include "gsccode.h"
+
+/* Define the abstract type for a CMap. */
+#ifndef gs_cmap_DEFINED
+# define gs_cmap_DEFINED
+typedef struct gs_cmap_s gs_cmap;
+#endif
+
+/* We only need the structure descriptor for testing. */
+extern_st(st_cmap);
+
+/* Define the structure for CIDSystemInfo. */
+typedef struct gs_cid_system_info_s {
+ gs_const_string Registry;
+ gs_const_string Ordering;
+ int Supplement;
+} gs_cid_system_info;
+#define gs_cid_system_info_max_ptrs 2
+/* We only need the structure descriptor for embedding. */
+extern_st(st_cid_system_info);
+
+/* ---------------- Procedural interface ---------------- */
+
+/*
+ * Decode a character from a string using a CMap, updating the index.
+ * Return 0 for a CID or name, N > 0 for a character code where N is the
+ * number of bytes in the code, or an error. For undefined characters,
+ * we return CID 0.
+ */
+int gs_cmap_decode_next(P5(const gs_cmap *pcmap, const gs_const_string *str,
+ uint *pindex, uint *pfidx, gs_glyph *pglyph));
+
+#endif /* gsfcmap_INCLUDED */
diff --git a/gs/src/gsfemu.c b/gs/src/gsfemu.c
new file mode 100644
index 000000000..2e5f6a198
--- /dev/null
+++ b/gs/src/gsfemu.c
@@ -0,0 +1,722 @@
+/* Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfemu.c */
+/* Floating point emulator for gcc */
+
+/* We actually only need arch.h + uint and ulong, but because signal.h */
+/* may include <sys/types.h>, we have to include std.h to handle (avoid) */
+/* redefinition of type names. */
+#include "std.h"
+#include <signal.h>
+
+/*#define TEST*/
+
+/*
+ * This package is not a fully general IEEE floating point implementation.
+ * It implements only one rounding mode (round to nearest) and does not
+ * generate or properly handle NaNs.
+ *
+ * The names and interfaces of the routines in this package were designed to
+ * work with gcc. This explains some peculiarities such as the presence of
+ * single-precision arithmetic (forbidden by the ANSI standard) and the
+ * omission of unsigned-to-float conversions (which gcc implements with
+ * truly grotesque inline code).
+ *
+ * The following routines do not yet handle denormalized numbers:
+ * addd3 (operands or result)
+ * __muldf3 (operands or result)
+ * __divdf3 (operands or result)
+ * __truncdfsf2 (result)
+ * __extendsfdf2 (operand)
+ */
+
+/*
+ * IEEE single-precision floats have the format:
+ * sign(1) exponent(8) mantissa(23)
+ * The exponent is biased by +127.
+ * The mantissa is a fraction with an implicit integer part of 1,
+ * unless the exponent is zero.
+ */
+#define fx(ia) (((ia) >> 23) & 0xff)
+#define fx_bias 127
+/*
+ * IEEE double-precision floats have the format:
+ * sign(1) exponent(11) mantissa(52)
+ * The exponent is biased by +1023.
+ */
+#define dx(ld) ((ld[msw] >> 20) & 0x7ff)
+#define dx_bias 1023
+
+#if arch_is_big_endian
+# define msw 0
+# define lsw 1
+#else
+# define msw 1
+# define lsw 0
+#endif
+/* Double arguments/results */
+#define la ((const long *)&a)
+#define ula ((const ulong *)&a)
+#define lb ((const long *)&b)
+#define ulb ((const ulong *)&b)
+#define dc (*(const double *)lc)
+/* Float arguments/results */
+#define ia (*(const long *)&a)
+#define ua (*(const ulong *)&a)
+#define ib (*(const long *)&b)
+#define ub (*(const ulong *)&b)
+#define fc (*(const float *)&lc)
+
+/* Round a double-length fraction by adding 1 in the lowest bit and */
+/* then shifting right by 1. */
+#define roundr1(ms, uls)\
+ if ( uls == 0xffffffff ) ms++, uls = 0;\
+ else uls++;\
+ uls = (uls >> 1) + (ms << 31);\
+ ms >>= 1
+
+/* Extend a non-zero float to a double. */
+#define extend(lc, ia)\
+ ((lc)[msw] = ((ia) & 0x80000000) + (((ia) & 0x7fffffff) >> 3) + 0x38000000,\
+ (lc)[lsw] = (ia) << 29)
+
+/* ---------------- Arithmetic ---------------- */
+
+/* -------- Add/subtract/negate -------- */
+
+double
+__negdf2(double a)
+{ long lc[2];
+ lc[msw] = la[msw] ^ 0x80000000;
+ lc[lsw] = la[lsw];
+ return dc;
+}
+float
+__negsf2(float a)
+{ long lc = ia ^ 0x80000000;
+ return fc;
+}
+
+double
+__adddf3(double a, double b)
+{ long lc[2];
+ int expt = dx(la);
+ int shift = expt - dx(lb);
+ long sign;
+ ulong msa, lsa;
+ ulong msb, lsb;
+
+ if ( shift < 0 )
+ { /* Swap a and b so that expt(a) >= expt(b). */
+ double temp = a;
+ a = b, b = temp;
+ expt += (shift = -shift);
+ }
+ if ( shift >= 54 ) /* also picks up most cases where b == 0 */
+ return a;
+ if ( !(lb[msw] & 0x7fffffff) )
+ return a;
+ sign = la[msw] & 0x80000000;
+ msa = (la[msw] & 0xfffff) + 0x100000, lsa = la[lsw];
+ msb = (lb[msw] & 0xfffff) + 0x100000, lsb = lb[lsw];
+ if ( (la[msw] ^ lb[msw]) >= 0 )
+ { /* Adding numbers of the same sign. */
+ if ( shift >= 32 )
+ lsb = msb, msb = 0, shift -= 32;
+ if ( shift )
+ { --shift;
+ lsb = (lsb >> shift) + (msb << (32 - shift));
+ msb >>= shift;
+ roundr1(msb, lsb);
+ }
+ if ( lsb > (ulong)0xffffffff - lsa )
+ msa++;
+ lsa += lsb;
+ msa += msb;
+ if ( msa > 0x1fffff )
+ { roundr1(msa, lsa);
+ /* In principle, we have to worry about exponent */
+ /* overflow here, but we don't. */
+ ++expt;
+ }
+ }
+ else
+ { /* Adding numbers of different signs. */
+ if ( shift > 53 )
+ return a; /* b can't affect the result, even rounded */
+ if ( shift == 0 && (msb > msa || (msb == msa && lsb >= lsa)) )
+ { /* This is the only case where the sign of the result */
+ /* differs from the sign of the first operand. */
+ sign ^= 0x80000000;
+ msa = msb - msa;
+ if ( lsb < lsa ) msa--;
+ lsa = lsb - lsa;
+ }
+ else
+ { if ( shift >= 33 )
+ { lsb = ((msb >> (shift - 32)) + 1) >> 1; /* round */
+ msb = 0;
+ }
+ else if ( shift )
+ { lsb = (lsb >> (shift - 1)) + (msb << (33 - shift));
+ msb >>= shift - 1;
+ roundr1(msb, lsb);
+ }
+ msa -= msb;
+ if ( lsb > lsa ) msa--;
+ lsa -= lsb;
+ }
+ /* Now renormalize the result. */
+ /* For the moment, we do this the slow way. */
+ if ( !(msa | lsa) )
+ return 0;
+ while ( msa < 0x100000 )
+ { msa = (msa << 1) + (lsa >> 31);
+ lsa <<= 1;
+ expt -= 1;
+ }
+ if ( expt <= 0 )
+ { /* Underflow. Return 0 rather than a denorm. */
+ lc[msw] = sign;
+ lc[lsw] = 0;
+ return dc;
+ }
+ }
+ lc[msw] = sign + ((ulong)expt << 20) + (msa & 0xfffff);
+ lc[lsw] = lsa;
+ return dc;
+}
+float
+__addsf3(float a, float b)
+{ return (float)((double)a + (double)b);
+}
+
+double
+__subdf3(double a, double b)
+{ long nb[2];
+ nb[msw] = lb[msw] ^ 0x80000000;
+ nb[lsw] = lb[lsw];
+ return a + *(const double *)nb;
+}
+float
+__subsf3(float a, float b)
+{ return (float)((double)a - (double)b);
+}
+
+/* -------- Multiplication -------- */
+
+double
+__muldf3(double a, double b)
+{ long lc[2];
+ ulong sign;
+ uint H, I, h, i;
+ ulong p0, p1, p2;
+ ulong expt;
+
+ if ( !(la[msw] & 0x7fffffff) || !(lb[msw] & 0x7fffffff) )
+ return 0;
+ /*
+ * We now have to multiply two 53-bit fractions to produce a 53-bit
+ * result. Since the idiots who specified the standard C libraries
+ * don't allow us to use the 32 x 32 => 64 multiply that every
+ * 32-bit CPU provides, we have to chop these 53-bit numbers up into
+ * 14-bit chunks so we can use 32 x 32 => 32 multiplies.
+ */
+#define chop_ms(ulx, h, i)\
+ h = ((ulx[msw] >> 7) & 0x1fff) | 0x2000,\
+ i = ((ulx[msw] & 0x7f) << 7) | (ulx[lsw] >> 25)
+#define chop_ls(ulx, j, k)\
+ j = (ulx[lsw] >> 11) & 0x3fff,\
+ k = (ulx[lsw] & 0x7ff) << 3
+ chop_ms(ula, H, I);
+ chop_ms(ulb, h, i);
+#undef chop
+#define prod(m, n) ((ulong)(m) * (n)) /* force long multiply */
+ p0 = prod(H, h);
+ p1 = prod(H, i) + prod(I, h);
+ /* If these doubles were produced from floats or ints, */
+ /* all the other products will be zero. It's worth a check. */
+ if ( (ula[lsw] | ulb[lsw]) & 0x1ffffff )
+ { /* No luck. */
+ /* We can almost always avoid computing p5 and p6, */
+ /* but right now it's not worth the trouble to check. */
+ uint J, K, j, k;
+
+ chop_ls(ula, J, K);
+ chop_ls(ulb, j, k);
+ { ulong p6 = prod(K, k);
+ ulong p5 = prod(J, k) + prod(K, j) + (p6 >> 14);
+ ulong p4 = prod(I, k) + prod(J, j) + prod(K, i) + (p5 >> 14);
+ ulong p3 = prod(H, k) + prod(I, j) + prod(J, i) + prod(K, h) +
+ (p4 >> 14);
+
+ p2 = prod(H, j) + prod(I, i) + prod(J, h) + (p3 >> 14);
+ }
+ }
+ else
+ { p2 = prod(I, i);
+ }
+ /* Now p0 through p2 hold the result. */
+ /****** ASSUME expt IS 32 BITS WIDE. ******/
+ expt = (la[msw] & 0x7ff00000) + (lb[msw] & 0x7ff00000) -
+ (dx_bias << 20);
+ /* Now expt is in the range [-1023..3071] << 20. */
+ /* Values outside the range [1..2046] are invalid. */
+ p1 += p2 >> 14;
+ p0 += p1 >> 14;
+ /* Now the 56-bit result consists of p0, the low 14 bits of p1, */
+ /* and the low 14 bits of p2. */
+ /* p0 can be anywhere between 2^26 and almost 2^28, so we might */
+ /* need to adjust the exponent by 1. */
+ if ( p0 < 0x8000000 )
+ { p0 = (p0 << 1) + ((p1 >> 13) & 1);
+ p1 = (p1 << 1) + ((p2 >> 13) & 1);
+ p2 <<= 1;
+ }
+ else
+ expt += 0x100000;
+ /* The range of expt is now [-1023..3072] << 20. */
+ /* Round the mantissa to 53 bits. */
+ if ( !((p2 += 4) & 0x3ffc) && !(++p1 & 0x3fff) && ++p0 >= 0x10000000 )
+ { p0 >>= 1, p1 = 0x2000;
+ /* Check for exponent overflow, just in case. */
+ if ( (ulong)expt < 0xc0000000 )
+ expt += 0x100000;
+ }
+ sign = (la[msw] ^ lb[msw]) & 0x80000000;
+ if ( expt == 0 )
+ { /* Underflow. Return 0 rather than a denorm. */
+ lc[msw] = sign;
+ lc[lsw] = 0;
+ }
+ else if ( (ulong)expt >= 0x7ff00000 )
+ { /* Overflow or underflow. */
+ if ( (ulong)expt <= 0xc0000000 )
+ { /* Overflow. */
+ raise(SIGFPE);
+ lc[msw] = sign + 0x7ff00000;
+ lc[lsw] = 0;
+ }
+ else
+ { /* Underflow. See above. */
+ lc[msw] = sign;
+ lc[lsw] = 0;
+ }
+ }
+ else
+ { lc[msw] = sign + expt + ((p0 >> 7) & 0xfffff);
+ lc[lsw] = (p0 << 25) | ((p1 & 0x3fff) << 11) | ((p2 >> 3) & 0x7ff);
+ }
+ return dc;
+#undef prod
+}
+float
+__mulsf3(float a, float b)
+{ long da[2], db[2];
+
+ if ( !(ia & 0x7fffffff) || !(ib & 0x7fffffff) )
+ return 0;
+ extend(da, ia);
+ extend(db, ib);
+ return (float)(*(const double *)da * *(const double *)db);
+}
+
+/* -------- Division -------- */
+
+double
+__divdf3(double a, double b)
+{ long lc[2];
+ /*
+ * Multi-precision division is really, really awful.
+ * We generate the result more or less brute force,
+ * 11 bits at a time.
+ */
+ ulong sign = (la[msw] ^ lb[msw]) & 0x80000000;
+ ulong msa = (la[msw] & 0xfffff) | 0x100000, lsa = la[lsw];
+ ulong msb = (lb[msw] & 0xfffff) | 0x100000, lsb = lb[lsw];
+ uint qn[5];
+ int i;
+ ulong msq, lsq;
+ int expt = dx(la) - dx(lb) + dx_bias;
+
+ if ( !(lb[msw] & 0x7fffffff) )
+ { /* Division by zero. */
+ raise(SIGFPE);
+ lc[lsw] = 0;
+ lc[msw] =
+ (la[msw] & 0x7fffffff ?
+ sign + 0x7ff00000 /* infinity */ :
+ 0x7ff80000 /* NaN */);
+ return dc;
+ }
+ if ( !(la[msw] & 0x7fffffff) )
+ return 0;
+ for ( i = 0; i < 5; ++i )
+ { uint q;
+ ulong msp, lsp;
+
+ msa = (msa << 11) + (lsa >> 21);
+ lsa <<= 11;
+ q = msa / msb;
+ /* We know that 2^20 <= msb < 2^21; q could be too high by 1, */
+ /* but it can't be too low. */
+ /* Set p = d * q. */
+ msp = q * msb;
+ lsp = q * (lsb & 0x1fffff);
+ { ulong midp = q * (lsb >> 21);
+ msp += (midp + (lsp >> 21)) >> 11;
+ lsp += midp << 21;
+ }
+ /* Set a = a - p, i.e., the tentative remainder. */
+ if ( msp > msa || (lsp > lsa && msp == msa) )
+ { /* q was too large. */
+ --q;
+ if ( lsb > lsp )
+ msp--;
+ lsp -= lsb;
+ msp -= msb;
+ }
+ if ( lsp > lsa )
+ msp--;
+ lsa -= lsp;
+ msa -= msp;
+ qn[i] = q;
+ }
+ /* Pack everything together again. */
+ msq = (qn[0] << 9) + (qn[1] >> 2);
+ lsq = (qn[1] << 30) + (qn[2] << 19) + (qn[3] << 8) + (qn[4] >> 3);
+ if ( msq < 0x100000 )
+ { msq = (msq << 1) + (lsq >> 31);
+ lsq <<= 1;
+ expt--;
+ }
+ /* We should round the quotient, but we don't. */
+ if ( expt <= 0 )
+ { /* Underflow. Return 0 rather than a denorm. */
+ lc[msw] = sign;
+ lc[lsw] = 0;
+ }
+ else if ( expt >= 0x7ff )
+ { /* Overflow. */
+ raise(SIGFPE);
+ lc[msw] = sign + 0x7ff00000;
+ lc[lsw] = 0;
+ }
+ else
+ { lc[msw] = sign + (expt << 20) + (msq & 0xfffff);
+ lc[lsw] = lsq;
+ }
+ return dc;
+}
+float
+__divsf3(float a, float b)
+{ return (float)((double)a / (double)b);
+}
+
+/* ---------------- Comparisons ---------------- */
+
+static int
+compared2(const long *pa, const long *pb)
+{
+#define upa ((const ulong *)pa)
+#define upb ((const ulong *)pb)
+ if ( pa[msw] == pb[msw] )
+ { int result = (upa[lsw] < upb[lsw] ? -1 :
+ upa[lsw] > upb[lsw] ? 1 : 0);
+ return (pa[msw] < 0 ? -result : result);
+ }
+ if ( (pa[msw] & pb[msw]) < 0 )
+ return (pa[msw] < pb[msw] ? 1 : -1);
+ /* We have to treat -0 and +0 specially. */
+ else if ( !((pa[msw] | pb[msw]) & 0x7fffffff) && !(pa[lsw] | pb[lsw]) )
+ return 0;
+ else
+ return (pa[msw] > pb[msw] ? 1 : -1);
+#undef upa
+#undef upb
+}
+
+/* 0 means true */
+int
+__eqdf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+/* !=0 means true */
+int
+__nedf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+/* >0 means true */
+int
+__gtdf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+/* >=0 means true */
+int
+__gedf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+/* <0 means true */
+int
+__ltdf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+/* <=0 means true */
+int
+__ledf2(double a, double b)
+{ return compared2(la, lb);
+}
+
+static int
+comparef2(long va, long vb)
+{ /* We have to treat -0 and +0 specially. */
+ if ( va == vb )
+ return 0;
+ if ( (va & vb) < 0 )
+ return (va < vb ? 1 : -1);
+ else if ( !((va | vb) & 0x7fffffff) )
+ return 0;
+ else
+ return (va > vb ? 1 : -1);
+}
+
+/* See the __xxdf2 functions above for the return values. */
+int
+__eqsf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+int
+__nesf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+int
+__gtsf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+int
+__gesf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+int
+__ltsf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+int
+__lesf2(float a, float b)
+{ return comparef2(ia, ib);
+}
+
+/* ---------------- Conversion ---------------- */
+
+long
+__fixdfsi(double a)
+{ /* This routine does check for overflow. */
+ long i = (la[msw] & 0xfffff) + 0x100000;
+ int expt = dx(la) - dx_bias;
+
+ if ( expt < 0 )
+ return 0;
+ if ( expt <= 20 )
+ i >>= 20 - expt;
+ else if ( expt >= 31 &&
+ (expt > 31 || i != 0x100000 || la[msw] >= 0 ||
+ ula[lsw] >= 1L << 21)
+ )
+ { raise(SIGFPE);
+ i = (la[msw] < 0 ? 0x80000000 : 0x7fffffff);
+ }
+ else
+ i = (i << (expt - 20)) + (ula[lsw] >> (52 - expt));
+ return (la[msw] < 0 ? -i : i);
+}
+
+long
+__fixsfsi(float a)
+{ /* This routine does check for overflow. */
+ long i = (ia & 0x7fffff) + 0x800000;
+ int expt = fx(ia) - fx_bias;
+
+ if ( expt < 0 )
+ return 0;
+ if ( expt <= 23 )
+ i >>= 23 - expt;
+ else if ( expt >= 31 && (expt > 31 || i != 0x800000 || ia >= 0) )
+ { raise(SIGFPE);
+ i = (ia < 0 ? 0x80000000 : 0x7fffffff);
+ }
+ else
+ i <<= expt - 23;
+ return (ia < 0 ? -i : i);
+}
+
+double
+__floatsidf(long i)
+{ long msc;
+ ulong v;
+ long lc[2];
+
+ if ( i > 0 )
+ msc = 0x41e00000 - 0x100000, v = i;
+ else if ( i < 0 )
+ msc = 0xc1e00000 - 0x100000, v = -i;
+ else /* i == 0 */
+ return 0;
+ while ( v < 0x01000000 )
+ v <<= 8, msc -= 0x00800000;
+ if ( v < 0x10000000 )
+ v <<= 4, msc -= 0x00400000;
+ while ( v < 0x80000000 )
+ v <<= 1, msc -= 0x00100000;
+ lc[msw] = msc + (v >> 11);
+ lc[lsw] = v << 21;
+ return dc;
+}
+
+float
+__floatsisf(long i)
+{ long lc;
+
+ if ( i == 0 )
+ lc = 0;
+ else
+ { ulong v;
+ if ( i < 0 )
+ lc = 0xcf000000, v = -i;
+ else
+ lc = 0x4f000000, v = i;
+ while ( v < 0x01000000 )
+ v <<= 8, lc -= 0x04000000;
+ while ( v < 0x80000000 )
+ v <<= 1, lc -= 0x00800000;
+ v = ((v >> 7) + 1) >> 1;
+ if ( v > 0xffffff )
+ v >>= 1, lc += 0x00800000;
+ lc += v & 0x7fffff;
+ }
+ return fc;
+}
+
+float
+__truncdfsf2(double a)
+{ /* This routine does check for overflow, but it converts */
+ /* underflows to zero rather than to a denormalized number. */
+ long lc;
+
+ if ( (la[msw] & 0x7ff00000) < 0x38100000 )
+ lc = la[msw] & 0x80000000;
+ else if ( (la[msw] & 0x7ff00000) >= 0x47f00000 )
+ { raise(SIGFPE);
+ lc = (la[msw] & 0x80000000) + 0x7f800000; /* infinity */
+ }
+ else
+ { lc = (la[msw] & 0xc0000000) +
+ ((la[msw] & 0x07ffffff) << 3) +
+ (ula[lsw] >> 29);
+ /* Round the mantissa. Simply adding 1 works even if the */
+ /* mantissa overflows, because it increments the exponent and */
+ /* sets the mantissa to zero! */
+ if ( ula[lsw] & 0x10000000 )
+ ++lc;
+ }
+ return fc;
+}
+
+double
+__extendsfdf2(float a)
+{ long lc[2];
+
+ if ( !(ia & 0x7fffffff) )
+ lc[msw] = ia, lc[lsw] = 0;
+ else
+ extend(lc, ia);
+ return dc;
+}
+
+/* ---------------- Test program ---------------- */
+
+#ifdef TEST
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+test(double v1)
+{ double v3 = v1 * 3;
+ double vh = v1 / 2;
+ double vd = v3 - vh;
+ double vdn = v1 - v3;
+
+ printf("%g=1 %g=3 %g=0.5 %g=2.5 %g=-2\n", v1, v3, vh, vd, vdn);
+ return 0;
+}
+
+float
+randf(void)
+{ int v = rand();
+ v = (v << 16) ^ rand();
+ if ( !(v & 0x7f800000) )
+ return 0;
+ if ( (v & 0x7f800000) == 0x7f800000 )
+ return randf();
+ return *(float *)&v;
+}
+
+int
+main(int argc, char *argv[])
+{ int i;
+ test(1.0);
+ for ( i = 0; i < 10; ++i )
+ { float a = randf(), b = randf(), r;
+ int c;
+ switch ( (rand() >> 12) & 3 )
+ {
+ case 0: r = a + b; c = '+'; break;
+ case 1: r = a - b; c = '-'; break;
+ case 2: r = a * b; c = '*'; break;
+ case 3: if ( b == 0 ) continue; r = a / b; c = '/'; break;
+ }
+ printf("0x%08x %c 0x%08x = 0x%08x\n",
+ *(int *)&a, c, *(int *)&b, *(int *)&r);
+ }
+}
+
+/*
+ Results from compiling with hardware floating point:
+
+1=1 3=3 0.5=0.5 2.5=2.5 -2=-2
+0x6f409924 - 0x01faa67a = 0x6f409924
+0x00000000 + 0x75418107 = 0x75418107
+0xe32fab71 - 0xc88f7816 = 0xe32fab71
+0x94809067 * 0x84ddaeee = 0x00000000
+0x2b0a5b7d + 0x38f70f50 = 0x38f70f50
+0xa5efcef3 - 0xc5dc1a2c = 0x45dc1a2c
+0xe7124521 * 0x3f4206d2 = 0xe6ddb891
+0x8d175f17 * 0x2ed2c1c0 = 0x80007c9f
+0x419e7a6d / 0xf2f95a35 = 0x8e22b404
+0xe0b2f48f * 0xc72793fc = 0x686a49f8
+
+ */
+
+
+#endif
diff --git a/gs/src/gsflip.c b/gs/src/gsflip.c
new file mode 100644
index 000000000..dc1a61270
--- /dev/null
+++ b/gs/src/gsflip.c
@@ -0,0 +1,293 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsflip.c */
+/* Routines for "flipping" image data */
+#include "gx.h"
+#include "gsbittab.h"
+#include "gsflip.h"
+
+#define arch_has_byte_regs 1
+
+/* Transpose a block of bits between registers. */
+#define transpose(r,s,mask,shift)\
+ r ^= (temp = ((s << shift) ^ r) & mask);\
+ s ^= temp >> shift
+
+/* Define the size of byte temporaries. On Intel CPUs, this should be */
+/* byte, but on all other CPUs, it should be uint. */
+#if arch_has_byte_regs
+typedef byte byte_var;
+#else
+typedef uint byte_var;
+#endif
+
+#define vtab(v80,v40,v20,v10,v8,v4,v2,v1)\
+ bit_table_8(0,v80,v40,v20,v10,v8,v4,v2,v1)
+
+/* Convert 3Mx1 to 3x1. */
+private void
+flip3x1(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ uint n = nbytes;
+ static const far_data bits32 tab3x1[256] = {
+ vtab(0x800000,0x100000,0x20000,0x4000,0x800,0x100,0x20,4)
+ };
+
+ for ( ; n > 0; out += 3, ++in1, ++in2, ++in3, --n )
+ { bits32 b24 =
+ tab3x1[*in1] | (tab3x1[*in2] >> 1) | (tab3x1[*in3] >> 2);
+ out[0] = (byte)(b24 >> 16);
+ out[1] = (byte)(b24 >> 8);
+ out[2] = (byte)b24;
+ }
+}
+
+/* Convert 3Mx2 to 3x2. */
+private void
+flip3x2(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ uint n = nbytes;
+ static const far_data bits32 tab3x2[256] = {
+ vtab(0x800000,0x400000,0x20000,0x10000,0x800,0x400,0x20,0x10)
+ };
+
+ for ( ; n > 0; out += 3, ++in1, ++in2, ++in3, --n )
+ { bits32 b24 =
+ tab3x2[*in1] | (tab3x2[*in2] >> 2) | (tab3x2[*in3] >> 4);
+ out[0] = (byte)(b24 >> 16);
+ out[1] = (byte)(b24 >> 8);
+ out[2] = (byte)b24;
+ }
+}
+
+/* Convert 3Mx4 to 3x4. */
+private void
+flip3x4(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 3, ++in1, ++in2, ++in3, --n )
+ { byte_var b1 = *in1, b2 = *in2, b3 = *in3;
+ out[0] = (b1 & 0xf0) | (b2 >> 4);
+ out[1] = (b3 & 0xf0) | (b1 & 0xf);
+ out[2] = (byte)(b2 << 4) | (b3 & 0xf);
+ }
+}
+
+/* Convert 3Mx8 to 3x8. */
+private void
+flip3x8(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 3, ++in1, ++in2, ++in3, --n )
+ { out[0] = *in1;
+ out[1] = *in2;
+ out[2] = *in3;
+ }
+}
+
+/* Convert 3Mx12 to 3x12. */
+private void
+flip3x12(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *pa = planes[0] + offset;
+ const byte *pb = planes[1] + offset;
+ const byte *pc = planes[2] + offset;
+ uint n = nbytes;
+
+ /* We are guaranteed that the input is an integral number of pixels. */
+ /* This implies that n = 0 mod 3. */
+
+ for ( ; n > 0; out += 9, pa += 3, pb += 3, pc += 3, n -= 3 )
+ { byte_var a1 = pa[1], b0 = pb[0], b1 = pb[1],
+ b2 = pb[2], c1 = pc[1];
+ out[0] = pa[0];
+ out[1] = (a1 & 0xf0) | (b0 >> 4);
+ out[2] = (byte)((b0 << 4) | (b1 >> 4));
+ out[3] = pc[0];
+ out[4] = (c1 & 0xf0) | (a1 & 0xf);
+ out[5] = pa[2];
+ out[6] = (byte)((b1 << 4) | (b2 >> 4));
+ out[7] = (byte)((b2 << 4) | (c1 & 0xf));
+ out[8] = pc[2];
+ }
+}
+
+/* Convert 4Mx1 to 4x1. */
+private void
+flip4x1(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ const byte *in4 = planes[3] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n )
+ { byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
+ byte_var temp;
+
+ /* Transpose blocks of 1 */
+ transpose(b1, b2, 0x55, 1);
+ transpose(b3, b4, 0x55, 1);
+ /* Transpose blocks of 2 */
+ transpose(b1, b3, 0x33, 2);
+ transpose(b2, b4, 0x33, 2);
+ /* There's probably a faster way to do this.... */
+ out[0] = (b1 & 0xf0) | (b2 >> 4);
+ out[1] = (b3 & 0xf0) | (b4 >> 4);
+ out[2] = (byte)((b1 << 4) | (b2 & 0xf));
+ out[3] = (byte)((b3 << 4) | (b4 & 0xf));
+ }
+}
+
+/* Convert 4Mx2 to 4x2. */
+private void
+flip4x2(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ const byte *in4 = planes[3] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n )
+ { byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
+ byte_var temp;
+
+ /* Transpose blocks of 4x2 */
+ transpose(b1, b3, 0x0f, 4);
+ transpose(b2, b4, 0x0f, 4);
+ /* Transpose blocks of 2x1 */
+ transpose(b1, b2, 0x33, 2);
+ transpose(b3, b4, 0x33, 2);
+ out[0] = b1;
+ out[1] = b2;
+ out[2] = b3;
+ out[3] = b4;
+ }
+}
+
+/* Convert 4Mx4 to 4x4. */
+private void
+flip4x4(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ const byte *in4 = planes[3] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n )
+ { byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
+ out[0] = (b1 & 0xf0) | (b2 >> 4);
+ out[1] = (b3 & 0xf0) | (b4 >> 4);
+ out[2] = (byte)((b1 << 4) | (b2 & 0xf));
+ out[3] = (byte)((b3 << 4) | (b4 & 0xf));
+ }
+}
+
+/* Convert 4Mx8 to 4x8. */
+private void
+flip4x8(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *in1 = planes[0] + offset;
+ const byte *in2 = planes[1] + offset;
+ const byte *in3 = planes[2] + offset;
+ const byte *in4 = planes[3] + offset;
+ uint n = nbytes;
+
+ for ( ; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n )
+ { out[0] = *in1;
+ out[1] = *in2;
+ out[2] = *in3;
+ out[3] = *in4;
+ }
+}
+
+/* Convert 4Mx12 to 4x12. */
+private void
+flip4x12(byte *buffer, const byte **planes, uint offset, uint nbytes)
+{ byte *out = buffer;
+ const byte *pa = planes[0] + offset;
+ const byte *pb = planes[1] + offset;
+ const byte *pc = planes[2] + offset;
+ const byte *pd = planes[3] + offset;
+ uint n = nbytes;
+
+ /* We are guaranteed that the input is an integral number of pixels. */
+ /* This implies that n = 0 mod 3. */
+
+ for ( ; n > 0; out += 12, pa += 3, pb += 3, pc += 3, pd += 3, n -= 3 )
+ { byte_var a1 = pa[1], b1 = pb[1], c1 = pc[1], d1 = pd[1];
+ { byte_var v0;
+ out[0] = pa[0];
+ v0 = pb[0];
+ out[1] = (a1 & 0xf0) | (v0 >> 4);
+ out[2] = (byte)((v0 << 4) | (b1 >> 4));
+ out[3] = pc[0];
+ v0 = pd[0];
+ out[4] = (c1 & 0xf0) | (v0 >> 4);
+ out[5] = (byte)((v0 << 4) | (d1 >> 4));
+ }
+ { byte_var v2;
+ v2 = pa[2];
+ out[6] = (byte)((a1 << 4) | (v2 >> 4));
+ out[7] = (byte)((v2 << 4) | (b1 & 0xf));
+ out[8] = pb[2];
+ v2 = pc[2];
+ out[9] = (byte)((c1 << 4) | (v2 >> 4));
+ out[10] = (byte)((v2 << 4) | (d1 & 0xf));
+ out[11] = pd[2];
+ }
+ }
+}
+
+/* Flip data given number of planes and bits per pixel. */
+private void (*image_flip_procs[2][13])(P4(byte *, const byte **, uint, uint)) = {
+ { 0, flip3x1, flip3x2, 0, flip3x4, 0, 0, 0, flip3x8, 0, 0, 0, flip3x12 },
+ { 0, flip4x1, flip4x2, 0, flip4x4, 0, 0, 0, flip4x8, 0, 0, 0, flip4x12 }
+};
+/* Here is the public interface to all of the above. */
+int
+image_flip_planes(byte *buffer, const byte **planes, uint offset, uint nbytes,
+ int num_planes, int bits_per_sample)
+{ void (*proc)(P4(byte *buffer, const byte **planes, uint offset, uint nbytes));
+
+ if ( num_planes < 3 || num_planes > 4 ||
+ bits_per_sample < 1 || bits_per_sample > 12 ||
+ (proc = image_flip_procs[num_planes - 3][bits_per_sample]) == 0
+ )
+ return -1;
+ (*proc)(buffer, planes, offset, nbytes);
+ return 0;
+}
diff --git a/gs/src/gsflip.h b/gs/src/gsflip.h
new file mode 100644
index 000000000..50b655476
--- /dev/null
+++ b/gs/src/gsflip.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsflip.h */
+/* Interface to routines for "flipping" image data */
+
+/*
+ * Convert line-based (MultipleDataSource) input to the chunky format
+ * used everywhere else.
+ *
+ * We store the output at buffer.
+ * Each row of input must consist of an integral number of pixels.
+ * In particular, for 12-bit input, nbytes must be 0 mod 3.
+ * offset is the amount to be added to each plane pointer.
+ * num_planes must be 3 or 4; bits_per_sample must be 1, 2, 4, 8, or 12.
+ * Returns -1 if num_planes or bits_per_sample is invalid, otherwise 0.
+ */
+extern int image_flip_planes(P6(byte *buffer, const byte **planes,
+ uint offset, uint nbytes,
+ int num_planes, int bits_per_sample));
diff --git a/gs/src/gsfont.c b/gs/src/gsfont.c
new file mode 100644
index 000000000..c3d315443
--- /dev/null
+++ b/gs/src/gsfont.c
@@ -0,0 +1,527 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfont.c */
+/* Font operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+
+/* Imported procedures */
+void gs_purge_font_from_char_caches(P2(gs_font_dir *, const gs_font *));
+
+/* Define the sizes of the various aspects of the font/character cache. */
+/*** Big memory machines ***/
+#define smax_LARGE 50 /* smax - # of scaled fonts */
+#define bmax_LARGE 500000 /* bmax - space for cached chars */
+#define mmax_LARGE 200 /* mmax - # of cached font/matrix pairs */
+#define cmax_LARGE 5000 /* cmax - # of cached chars */
+#define blimit_LARGE 2500 /* blimit/upper - max size of a single cached char */
+/*** Small memory machines ***/
+#define smax_SMALL 20 /* smax - # of scaled fonts */
+#define bmax_SMALL 25000 /* bmax - space for cached chars */
+#define mmax_SMALL 40 /* mmax - # of cached font/matrix pairs */
+#define cmax_SMALL 500 /* cmax - # of cached chars */
+#define blimit_SMALL 100 /* blimit/upper - max size of a single cached char */
+
+private_st_font_dir();
+private struct_proc_enum_ptrs(font_enum_ptrs);
+private struct_proc_reloc_ptrs(font_reloc_ptrs);
+public_st_gs_font();
+public_st_gs_font_base();
+private_st_gs_font_ptr();
+public_st_gs_font_ptr_element();
+
+/*
+ * Garbage collection of fonts poses some special problems. On the one
+ * hand, we need to keep track of all existing base (not scaled) fonts,
+ * using the next/prev list whose head is the orig_fonts member of the font
+ * directory; on the other hand, we want these to be "weak" pointers that
+ * don't keep fonts in existence if the fonts aren't referenced from
+ * anywhere else. We accomplish this as follows:
+ *
+ * We don't trace through gs_font_dir.orig_fonts or gs_font.{next,prev}
+ * during the mark phase of the GC.
+ *
+ * When we finalize a base gs_font, we unlink it from the list. (A
+ * gs_font is a base font iff its base member points to itself.)
+ *
+ * We *do* relocate the orig_fonts and next/prev pointers during the
+ * relocation phase of the GC. */
+
+/* Font directory GC procedures */
+#define dir ((gs_font_dir *)vptr)
+private ENUM_PTRS_BEGIN(font_dir_enum_ptrs)
+ { /* Enumerate pointers from cached characters to f/m pairs, */
+ /* and mark the cached character glyphs. */
+ /* See gxfcache.h for why we do this here. */
+ uint cci = index - st_font_dir_max_ptrs;
+ uint offset, count;
+ uint tmask = dir->ccache.table_mask;
+
+ if ( cci == 0 )
+ offset = 0, count = 1;
+ else if ( cci == dir->enum_index + 1 )
+ offset = dir->enum_offset + 1, count = 1;
+ else
+ offset = 0, count = cci;
+ for ( ; offset <= tmask; ++offset )
+ { cached_char *cc = dir->ccache.table[offset];
+ if ( cc != 0 && !--count )
+ { (*dir->ccache.mark_glyph)
+ (cc->code, dir->ccache.mark_glyph_data);
+ dir->enum_index = cci;
+ dir->enum_offset = offset;
+ ENUM_RETURN(cc_pair(cc) - cc->pair_index);
+ }
+ }
+ }
+ return 0;
+#define e1(i,elt) ENUM_PTR(i,gs_font_dir,elt);
+ font_dir_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_dir_reloc_ptrs) ;
+ /* Relocate the pointers from cached characters to f/m pairs. */
+ /* See gxfcache.h for why we do this here. */
+ { int chi;
+ for ( chi = dir->ccache.table_mask; chi >= 0; --chi )
+ { cached_char *cc = dir->ccache.table[chi];
+ if ( cc != 0 )
+ cc_set_pair_only(cc,
+ (cached_fm_pair *)
+ gs_reloc_struct_ptr(cc_pair(cc) -
+ cc->pair_index, gcst) +
+ cc->pair_index);
+ }
+ }
+ /* We have to relocate the cached characters before we */
+ /* relocate dir->ccache.table! */
+ RELOC_PTR(gs_font_dir, orig_fonts);
+#define r1(i,elt) RELOC_PTR(gs_font_dir, elt);
+ font_dir_do_ptrs(r1)
+#undef r1
+RELOC_PTRS_END
+#undef dir
+
+/* GC procedures for fonts */
+#define pfont ((gs_font *)vptr)
+/*
+ * When we finalize a base font, we unlink it from the orig_fonts list;
+ * when we finalize a scaled font, we unlink it from scaled_fonts.
+ * See above for more information.
+ */
+void
+gs_font_finalize(void *vptr)
+{ gs_font **ppfirst;
+ gs_font *next = pfont->next;
+ gs_font *prev = pfont->prev;
+
+ if_debug4('u', "[u]unlinking font 0x%lx, base=0x%lx, prev=0x%lx, next=0x%lx\n",
+ (ulong)pfont, (ulong)pfont->base, (ulong)prev, (ulong)next);
+ if ( pfont->dir == 0 )
+ ppfirst = 0;
+ else if ( pfont->base == pfont )
+ ppfirst = &pfont->dir->orig_fonts;
+ else
+ { /*
+ * Track the number of cached scaled fonts. Only decrement the
+ * count if we didn't do this already in gs_makefont.
+ */
+ if ( next || prev || pfont->dir->scaled_fonts == pfont )
+ pfont->dir->ssize--;
+ ppfirst = &pfont->dir->scaled_fonts;
+ }
+ /*
+ * gs_purge_font may have unlinked this font already:
+ * don't unlink it twice.
+ */
+ if ( next != 0 && next->prev == pfont )
+ next->prev = prev;
+ if ( prev != 0 )
+ { if ( prev->next == pfont )
+ prev->next = next;
+ }
+ else if ( ppfirst != 0 && *ppfirst == pfont )
+ *ppfirst = next;
+}
+private ENUM_PTRS_BEGIN(font_enum_ptrs) return 0;
+ /* We don't enumerate next or prev of base fonts. */
+ /* See above for details. */
+ case 0:
+ ENUM_RETURN((pfont->base == pfont ? 0 : pfont->next));
+ case 1:
+ ENUM_RETURN((pfont->base == pfont ? 0 : pfont->prev));
+ ENUM_PTR(2, gs_font, dir);
+ ENUM_PTR(3, gs_font, base);
+ ENUM_PTR(4, gs_font, client_data);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_reloc_ptrs) ;
+ /* We *do* always relocate next and prev. */
+ /* Again, see above for details. */
+ RELOC_PTR(gs_font, next);
+ RELOC_PTR(gs_font, prev);
+ RELOC_PTR(gs_font, dir);
+ RELOC_PTR(gs_font, base);
+ RELOC_PTR(gs_font, client_data);
+RELOC_PTRS_END
+#undef pfont
+
+/* Allocate a font directory */
+private bool
+cc_no_mark_glyph(gs_glyph glyph, void *ignore_data)
+{ return false;
+}
+gs_font_dir *
+gs_font_dir_alloc(gs_memory_t *mem)
+{ gs_font_dir *pdir = 0;
+#if !arch_small_memory
+# ifdef DEBUG
+ if ( !gs_debug_c('.') )
+# endif
+ { /* Try allocating a very large cache. */
+ /* If this fails, allocate a small one. */
+ pdir = gs_font_dir_alloc_limits(mem,
+ smax_LARGE, bmax_LARGE, mmax_LARGE,
+ cmax_LARGE, blimit_LARGE);
+ }
+ if ( pdir == 0 )
+#endif
+ pdir = gs_font_dir_alloc_limits(mem,
+ smax_SMALL, bmax_SMALL, mmax_SMALL,
+ cmax_SMALL, blimit_SMALL);
+ if ( pdir == 0 )
+ return 0;
+ pdir->ccache.mark_glyph = cc_no_mark_glyph;
+ pdir->ccache.mark_glyph_data = 0;
+ return pdir;
+}
+gs_font_dir *
+gs_font_dir_alloc_limits(gs_memory_t *mem,
+ uint smax, uint bmax, uint mmax, uint cmax, uint upper)
+{ register gs_font_dir *pdir =
+ gs_alloc_struct(mem, gs_font_dir, &st_font_dir,
+ "font_dir_alloc(dir)");
+ int code;
+ if ( pdir == 0 )
+ return 0;
+ code = gx_char_cache_alloc(mem, pdir, bmax, mmax, cmax, upper);
+ if ( code < 0 )
+ { gs_free_object(mem, pdir, "font_dir_alloc(dir)");
+ return 0;
+ }
+ pdir->orig_fonts = 0;
+ pdir->scaled_fonts = 0;
+ pdir->ssize = 0;
+ pdir->smax = smax;
+ return pdir;
+}
+
+/* Macro for linking an element at the head of a chain */
+#define link_first(first, elt)\
+ if ( (elt->next = first) != NULL ) first->prev = elt;\
+ elt->prev = 0;\
+ first = elt
+
+/* definefont */
+/* Use this only for original (unscaled) fonts! */
+/* Note that it expects pfont->procs.define_font to be set already. */
+int
+gs_definefont(gs_font_dir *pdir, gs_font *pfont)
+{ int code;
+ pfont->dir = pdir;
+ pfont->base = pfont;
+ code = (*pfont->procs.define_font)(pdir, pfont);
+ if ( code < 0 )
+ { /* Make sure we don't try to finalize this font. */
+ pfont->base = 0;
+ return code;
+ }
+ link_first(pdir->orig_fonts, pfont);
+ if_debug2('m', "[m]defining font 0x%lx, next=0x%lx\n",
+ (ulong)pfont, (ulong)pfont->next);
+ return 0;
+}
+/* Default (vacuous) definefont handler. */
+int
+gs_no_define_font(gs_font_dir *pdir, gs_font *pfont)
+{ return 0;
+}
+
+/* scalefont */
+int
+gs_scalefont(gs_font_dir *pdir, const gs_font *pfont, floatp scale,
+ gs_font **ppfont)
+{ gs_matrix mat;
+ gs_make_scaling(scale, scale, &mat);
+ return gs_makefont(pdir, pfont, &mat, ppfont);
+}
+
+/* makefont */
+int
+gs_makefont(gs_font_dir *pdir, const gs_font *pfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{
+#define pbfont ((const gs_font_base *)pfont)
+ int code;
+ gs_font *prev = 0;
+ gs_font *pf_out = pdir->scaled_fonts;
+ gs_memory_t *mem = pfont->memory;
+ gs_matrix newmat;
+ bool can_cache;
+
+ if ( (code = gs_matrix_multiply(&pfont->FontMatrix, pmat, &newmat)) < 0 )
+ return code;
+ /* Check for the font already being in the scaled font cache. */
+ /* Only attempt to share fonts if the current font has */
+ /* a valid UniqueID or XUID. */
+#ifdef DEBUG
+if ( gs_debug_c('m') )
+ { if ( pfont->FontType == ft_composite )
+ dprintf("[m]composite");
+ else if ( uid_is_UniqueID(&pbfont->UID) )
+ dprintf1("[m]UniqueID=%ld", pbfont->UID.id);
+ else if ( uid_is_XUID(&pbfont->UID) )
+ dprintf1("[m]XUID(%u)", (uint)(-pbfont->UID.id));
+ else
+ dprintf("[m]no UID");
+ dprintf7(", FontType=%d,\n[m] new FontMatrix=[%g %g %g %g %g %g]\n",
+ pfont->FontType,
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ pmat->tx, pmat->ty);
+ }
+#endif
+ /* The UID of a composite font is of no value in caching.... */
+ if ( pfont->FontType != ft_composite &&
+ uid_is_valid(&pbfont->UID)
+ )
+ { for ( ; pf_out != 0; prev = pf_out, pf_out = pf_out->next )
+ if ( pf_out->FontType == pfont->FontType &&
+ pf_out->base == pfont->base &&
+ uid_equal(&((gs_font_base *)pf_out)->UID, &pbfont->UID) &&
+ pf_out->FontMatrix.xx == newmat.xx &&
+ pf_out->FontMatrix.xy == newmat.xy &&
+ pf_out->FontMatrix.yx == newmat.yx &&
+ pf_out->FontMatrix.yy == newmat.yy &&
+ pf_out->FontMatrix.tx == newmat.tx &&
+ pf_out->FontMatrix.ty == newmat.ty
+ )
+ { *ppfont = pf_out;
+ if_debug1('m', "[m]found font=0x%lx\n", (ulong)pf_out);
+ return 0;
+ }
+ can_cache = true;
+ }
+ else
+ can_cache = false;
+ pf_out = gs_alloc_struct(mem, gs_font, gs_object_type(mem, pfont),
+ "gs_makefont");
+ if ( !pf_out )
+ return_error(gs_error_VMerror);
+ memcpy(pf_out, pfont, gs_object_size(mem, pfont));
+ pf_out->FontMatrix = newmat;
+ pf_out->client_data = 0;
+ pf_out->dir = pdir;
+ pf_out->base = pfont->base;
+ *ppfont = pf_out;
+ code = (*pf_out->procs.make_font)(pdir, pfont, pmat, ppfont);
+ if ( code < 0 )
+ return code;
+ if ( can_cache )
+ { if ( pdir->ssize >= pdir->smax && prev != 0 )
+ { /*
+ * We must discard a cached scaled font.
+ * prev points to the last (oldest) font.
+ * (We can't free it, because there might be
+ * other references to it.)
+ */
+ if_debug1('m', "[m]discarding font 0x%lx\n",
+ (ulong)prev);
+ if ( prev->prev != 0 )
+ prev->prev->next = 0;
+ else
+ pdir->scaled_fonts = 0;
+ pdir->ssize--;
+ prev->prev = 0;
+ if ( prev->FontType != ft_composite )
+ { if_debug1('m', "[m]discarding UID 0x%lx\n",
+ (ulong)((gs_font_base *)prev)->
+ UID.xvalues);
+ uid_free(&((gs_font_base *)prev)->UID,
+ prev->memory,
+ "gs_makefont(discarding)");
+ uid_set_invalid(&((gs_font_base *)prev)->UID);
+ }
+ }
+ pdir->ssize++;
+ link_first(pdir->scaled_fonts, pf_out);
+ }
+ else
+ { /* Prevent garbage pointers. */
+ pf_out->next = pf_out->prev = 0;
+ }
+ if_debug2('m', "[m]new font=0x%lx can_cache=%s\n",
+ (ulong)*ppfont, (can_cache ? "true" : "false"));
+ return 1;
+#undef pbfont
+}
+/* Default (vacuous) makefont handler. */
+int
+gs_no_make_font(gs_font_dir *pdir, const gs_font *pfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{ return 0;
+}
+/* Makefont handler for base fonts, which must copy the XUID. */
+int
+gs_base_make_font(gs_font_dir *pdir, const gs_font *pfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{
+#define pbfont ((gs_font_base *)*ppfont)
+ if ( uid_is_XUID(&pbfont->UID) )
+ { uint xsize = uid_XUID_size(&pbfont->UID);
+ long *xvalues = (long *)
+ gs_alloc_byte_array(pbfont->memory, xsize, sizeof(long),
+ "gs_base_make_font(XUID)");
+ if ( xvalues == 0 )
+ return_error(gs_error_VMerror);
+ memcpy(xvalues, uid_XUID_values(&pbfont->UID),
+ xsize * sizeof(long));
+ pbfont->UID.xvalues = xvalues;
+ }
+#undef pbfont
+ return 0;
+}
+
+/* Set the current font. This is provided only for the benefit of cshow, */
+/* which must reset the current font without disturbing the root font. */
+void
+gs_set_currentfont(gs_state *pgs, gs_font *pfont)
+{ pgs->font = pfont;
+ pgs->char_tm_valid = false;
+}
+
+/* setfont */
+int
+gs_setfont(gs_state *pgs, gs_font *pfont)
+{ pgs->font = pgs->root_font = pfont;
+ pgs->char_tm_valid = false;
+ return 0;
+}
+
+/* currentfont */
+gs_font *
+gs_currentfont(const gs_state *pgs)
+{ return pgs->font;
+}
+
+/* rootfont */
+gs_font *
+gs_rootfont(const gs_state *pgs)
+{ return pgs->root_font;
+}
+
+/* cachestatus */
+void
+gs_cachestatus(register const gs_font_dir *pdir, register uint pstat[7])
+{ pstat[0] = pdir->ccache.bsize;
+ pstat[1] = pdir->ccache.bmax;
+ pstat[2] = pdir->fmcache.msize;
+ pstat[3] = pdir->fmcache.mmax;
+ pstat[4] = pdir->ccache.csize;
+ pstat[5] = pdir->ccache.cmax;
+ pstat[6] = pdir->ccache.upper;
+}
+
+/* setcacheparams */
+int
+gs_setcachesize(gs_font_dir *pdir, uint size)
+{ /* This doesn't delete anything from the cache yet. */
+ pdir->ccache.bmax = size;
+ return 0;
+}
+int
+gs_setcachelower(gs_font_dir *pdir, uint size)
+{ pdir->ccache.lower = size;
+ return 0;
+}
+int
+gs_setcacheupper(gs_font_dir *pdir, uint size)
+{ pdir->ccache.upper = size;
+ return 0;
+}
+
+/* currentcacheparams */
+uint
+gs_currentcachesize(const gs_font_dir *pdir)
+{ return pdir->ccache.bmax;
+}
+uint
+gs_currentcachelower(const gs_font_dir *pdir)
+{ return pdir->ccache.lower;
+}
+uint
+gs_currentcacheupper(const gs_font_dir *pdir)
+{ return pdir->ccache.upper;
+}
+
+/* Purge a font from all font- and character-related tables. */
+/* This is only used by restore (and, someday, the GC). */
+void
+gs_purge_font(gs_font *pfont)
+{ gs_font_dir *pdir = pfont->dir;
+ gs_font *pf;
+
+ /* Remove the font from its list (orig_fonts or scaled_fonts). */
+ gs_font *prev = pfont->prev;
+ gs_font *next = pfont->next;
+ if ( next != 0 )
+ next->prev = prev, pfont->next = 0;
+ if ( prev != 0 )
+ prev->next = next, pfont->prev = 0;
+ else if ( pdir->orig_fonts == pfont )
+ pdir->orig_fonts = next;
+ else if ( pdir->scaled_fonts == pfont )
+ pdir->scaled_fonts = next;
+ else
+ { /* Shouldn't happen! */
+ lprintf1("purged font 0x%lx not found\n", (ulong)pfont);
+ }
+
+ /* Purge the font from the scaled font cache. */
+ for ( pf = pdir->scaled_fonts; pf != 0; )
+ { if ( pf->base == pfont )
+ { gs_purge_font(pf);
+ pf = pdir->scaled_fonts; /* start over */
+ }
+ else
+ pf = pf->next;
+ }
+
+ /* Purge the font from the font/matrix pair cache, */
+ /* including all cached characters rendered with that font. */
+ gs_purge_font_from_char_caches(pdir, pfont);
+
+}
diff --git a/gs/src/gsfont.h b/gs/src/gsfont.h
new file mode 100644
index 000000000..bd4dcf6f6
--- /dev/null
+++ b/gs/src/gsfont.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1989, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfont.h */
+/* Client interface to font operations */
+/* Requires gsmatrix.h */
+
+/* A 'font directory' object (to avoid making fonts global). */
+/* 'directory' is something of a misnomer: this structure */
+/* just keeps track of the defined fonts, and the scaled font and */
+/* rendered character caches. */
+#ifndef gs_font_dir_DEFINED
+# define gs_font_dir_DEFINED
+typedef struct gs_font_dir_s gs_font_dir;
+#endif
+
+/* Font objects */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+#endif
+
+/* Initialization */
+/* These procedures return 0 if they fail. */
+gs_font_dir *gs_font_dir_alloc(P1(gs_memory_t *));
+gs_font_dir *gs_font_dir_alloc_limits(P6(gs_memory_t *,
+ uint /*smax*/, uint /*bmax*/, uint /*mmax*/,
+ uint /*cmax*/, uint /*upper*/));
+
+/* Font manipulations */
+/* Use gs_definefont only with original (unscaled) fonts! */
+int gs_definefont(P2(gs_font_dir *, gs_font *));
+/* gs_scalefont and gs_makefont return 0 if the scaled font */
+/* was already in the cache, 1 if a new font was created. */
+int gs_scalefont(P4(gs_font_dir *, const gs_font *, floatp, gs_font **));
+int gs_makefont(P4(gs_font_dir *, const gs_font *, const gs_matrix *, gs_font **));
+int gs_setfont(P2(gs_state *, gs_font *));
+gs_font *gs_currentfont(P1(const gs_state *));
+gs_font *gs_rootfont(P1(const gs_state *));
+void gs_set_currentfont(P2(gs_state *, gs_font *));
+void gs_purge_font(P1(gs_font *));
+
+/* Font cache parameter operations */
+void gs_cachestatus(P2(const gs_font_dir *, uint [7]));
+#define gs_setcachelimit(pdir,limit) gs_setcacheupper(pdir,limit)
+uint gs_currentcachesize(P1(const gs_font_dir *));
+int gs_setcachesize(P2(gs_font_dir *, uint));
+uint gs_currentcachelower(P1(const gs_font_dir *));
+int gs_setcachelower(P2(gs_font_dir *, uint));
+uint gs_currentcacheupper(P1(const gs_font_dir *));
+int gs_setcacheupper(P2(gs_font_dir *, uint));
diff --git a/gs/src/gsfont0.c b/gs/src/gsfont0.c
new file mode 100644
index 000000000..91d2181f1
--- /dev/null
+++ b/gs/src/gsfont0.c
@@ -0,0 +1,121 @@
+/* Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfont0.c */
+/* Composite font operations for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfcache.h" /* gs_font_dir */
+#include "gxfont.h"
+#include "gxfont0.h"
+
+/* Structure descriptor */
+private struct_proc_enum_ptrs(font_type0_enum_ptrs);
+private struct_proc_reloc_ptrs(font_type0_reloc_ptrs);
+public_st_gs_font_type0();
+#define pfont ((gs_font_type0 *)vptr)
+private ENUM_PTRS_BEGIN(font_type0_enum_ptrs) ENUM_PREFIX(st_gs_font, gs_type0_data_max_ptrs);
+ ENUM_PTR(0, gs_font_type0, data.Encoding);
+ ENUM_PTR(1, gs_font_type0, data.FDepVector);
+ case 2:
+ switch ( pfont->data.FMapType )
+ {
+ case fmap_SubsVector:
+ ENUM_RETURN_CONST_STRING_PTR(gs_font_type0,
+ data.SubsVector);
+ case fmap_CMap:
+ ENUM_RETURN_PTR(gs_font_type0, data.CMap);
+ default:
+ ENUM_RETURN(0);
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_type0_reloc_ptrs) RELOC_PREFIX(st_gs_font);
+ RELOC_PTR(gs_font_type0, data.Encoding);
+ RELOC_PTR(gs_font_type0, data.FDepVector);
+ switch ( pfont->data.FMapType )
+ {
+ case fmap_SubsVector:
+ RELOC_CONST_STRING_PTR(gs_font_type0, data.SubsVector);
+ break;
+ case fmap_CMap:
+ RELOC_PTR(gs_font_type0, data.CMap);
+ break;
+ default:
+ ;
+ }
+RELOC_PTRS_END
+#undef pfont
+
+/* Adjust a composite font by concatenating a given matrix */
+/* to the FontMatrix of all descendant composite fonts. */
+private int
+gs_type0_adjust_matrix(gs_font_dir *pdir, gs_font_type0 *pfont,
+ const gs_matrix *pmat)
+{ gs_font **pdep = pfont->data.FDepVector;
+ uint fdep_size = pfont->data.fdep_size;
+ gs_font **ptdep;
+ uint i;
+ /* Check for any descendant composite fonts. */
+ for ( i = 0; i < fdep_size; i++ )
+ if ( pdep[i]->FontType == ft_composite )
+ break;
+ if ( i == fdep_size )
+ return 0;
+ ptdep = gs_alloc_struct_array(pfont->memory, fdep_size, gs_font *,
+ &st_gs_font_ptr_element,
+ "gs_type0_adjust_font(FDepVector)");
+ if ( ptdep == 0 )
+ return_error(gs_error_VMerror);
+ memcpy(ptdep, pdep, sizeof(gs_font *) * fdep_size);
+ for ( ; i < fdep_size; i++ )
+ if ( pdep[i]->FontType == ft_composite )
+ { int code = gs_makefont(pdir, pdep[i], pmat, &ptdep[i]);
+ if ( code < 0 )
+ return code;
+ }
+ pfont->data.FDepVector = ptdep;
+ return 0;
+}
+
+/* Finish defining a composite font, */
+/* by adjusting its descendants' FontMatrices. */
+int
+gs_type0_define_font(gs_font_dir *pdir, gs_font *pfont)
+{ const gs_matrix *pmat = &pfont->FontMatrix;
+ /* Check for the identity matrix, which is common in root fonts. */
+ if ( pmat->xx == 1.0 && pmat->yy == 1.0 &&
+ pmat->xy == 0.0 && pmat->yx == 0.0 &&
+ pmat->tx == 0.0 && pmat->ty == 0.0
+ )
+ return 0;
+ return gs_type0_adjust_matrix(pdir, (gs_font_type0 *)pfont, pmat);
+}
+
+/* Finish scaling a composite font similarly. */
+int
+gs_type0_make_font(gs_font_dir *pdir, const gs_font *pfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{ return gs_type0_adjust_matrix(pdir, (gs_font_type0 *)*ppfont, pmat);
+}
diff --git a/gs/src/gsfunc.c b/gs/src/gsfunc.c
new file mode 100644
index 000000000..98d987343
--- /dev/null
+++ b/gs/src/gsfunc.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfunc.c */
+/* Generic Function support */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfunc.h"
+
+/* GC descriptor */
+public_st_function();
+
+/* Generic free_params implementation. */
+void
+fn_common_free_params(gs_function_params_t *params, gs_memory_t *mem)
+{ gs_free_object(mem, (void *)params->Range, "Range"); /* break const */
+ gs_free_object(mem, (void *)params->Domain, "Domain"); /* break const */
+}
+
+/* Generic free implementation. */
+void
+fn_common_free(gs_function_t *pfn, bool free_params, gs_memory_t *mem)
+{ if ( free_params )
+ gs_function_free_params(pfn, mem);
+ gs_free_object(mem, pfn, "fn_xxx_free");
+}
+
+/* Free an array of subsidiary Functions. */
+void
+fn_free_functions(gs_function_t **Functions, int count, gs_memory_t *mem)
+{ int i;
+
+ for ( i = count; --i >= 0; )
+ gs_function_free(Functions[i], true, mem);
+ gs_free_object(mem, Functions, "Functions");
+}
+
+/* Check the values of m, n, Domain, and (if supplied) Range. */
+int
+fn_check_mnDR_proc(const gs_function_params_t *params, int m, int n)
+{ int i;
+
+ if ( m <= 0 || n <= 0 )
+ return_error(gs_error_rangecheck);
+ for ( i = 0; i < m; ++i )
+ if ( params->Domain[2 * i] > params->Domain[2 * i + 1] )
+ return_error(gs_error_rangecheck);
+ if ( params->Range != 0 )
+ for ( i = 0; i < n; ++i )
+ if ( params->Range[2 * i] > params->Range[2 * i + 1] )
+ return_error(gs_error_rangecheck);
+ return 0;
+}
diff --git a/gs/src/gsfunc.h b/gs/src/gsfunc.h
new file mode 100644
index 000000000..8e97b23f7
--- /dev/null
+++ b/gs/src/gsfunc.h
@@ -0,0 +1,114 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfunc.h */
+/* Generic definitions for Functions */
+
+#ifndef gsfunc_INCLUDED
+# define gsfunc_INCLUDED
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * gs_function_type_t is defined as equivalent to int, rather than as an
+ * enum type, because we can't enumerate all its possible values here in the
+ * generic definitions.
+ */
+typedef int gs_function_type_t;
+
+/*
+ * Define information common to all Function types.
+ * We separate the private part from the parameters so that
+ * clients can create statically initialized parameter structures.
+ */
+#define gs_function_params_common\
+ int m; /* # of inputs */\
+ const float *Domain; /* 2 x m */\
+ int n; /* # of outputs */\
+ const float *Range /* 2 x n, optional */
+
+/* Define a generic function, for use as the target type of pointers. */
+typedef struct gs_function_params_s {
+ gs_function_params_common;
+} gs_function_params_t;
+typedef struct gs_function_s gs_function_t;
+typedef int (*fn_evaluate_proc_t)(P3(const gs_function_t *pfn,
+ const float *in, float *out));
+typedef void (*fn_free_params_proc_t)(P2(gs_function_params_t *params,
+ gs_memory_t *mem));
+typedef void (*fn_free_proc_t)(P3(gs_function_t *pfn,
+ bool free_params, gs_memory_t *mem));
+typedef struct gs_function_head_s {
+ gs_function_type_t type;
+ fn_evaluate_proc_t evaluate;
+ fn_free_params_proc_t free_params;
+ fn_free_proc_t free;
+} gs_function_head_t;
+struct gs_function_s {
+ gs_function_head_t head;
+ gs_function_params_t params;
+};
+#define FunctionType(pfn) ((pfn)->head.type)
+
+/*
+ * Each specific function type has a definition in its own header file
+ * for its parameter record. In order to keep names from overflowing
+ * various compilers' limits, we take the name of the function type and
+ * reduce it to the first and last letter of each word, e.g., for
+ * Sampled functions, XxYy is Sd.
+
+typedef struct gs_function_XxYy_params_s {
+ gs_function_params_common;
+ << P additional members >>
+} gs_function_XxYy_params_t;
+#define private_st_function_XxYy()\
+ gs_private_st_suffix_addP(st_function_XxYy, gs_function_XxYy_t,\
+ "gs_function_XxYy_t", function_XxYy_enum_ptrs, function_XxYy_reloc_ptrs,\
+ st_function, <<params.additional_members>>)
+
+ */
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Each specific function type has a pair of procedures in its own
+ * header file, one to allocate and initialize an instance of that type,
+ * and one to free the parameters of that type.
+
+int gs_function_XxYy_init(P3(gs_function_t **ppfn,
+ const gs_function_XxYy_params_t *params,
+ gs_memory_t *mem));
+
+void gs_function_XxYy_free_params(P2(gs_function_XxYy_params_t *params,
+ gs_memory_t *mem));
+
+*/
+
+/* Evaluate a function. */
+#define gs_function_evaluate(pfn, in, out)\
+ (*(pfn)->head.evaluate)(pfn, in, out)
+
+/* Free function parameters. */
+#define gs_function_free_params(pfn, mem)\
+ (*(pfn)->head.free_params)(&(pfn)->params, mem)
+
+/* Free a function's implementation, optionally including its parameters. */
+#define gs_function_free(pfn, free_params, mem)\
+ (*(pfn)->head.free)(pfn, free_params, mem)
+
+#endif /* gsfunc_INCLUDED */
diff --git a/gs/src/gsfunc0.c b/gs/src/gsfunc0.c
new file mode 100644
index 000000000..270d9002b
--- /dev/null
+++ b/gs/src/gsfunc0.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfunc0.c */
+/* Implementation of FunctionType 0 (Sampled) Functions */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsfunc0.h"
+#include "gxfunc.h"
+
+typedef struct gs_function_Sd_s {
+ gs_function_head_t head;
+ gs_function_Sd_params_t params;
+} gs_function_Sd_t;
+private_st_function_Sd();
+
+/* Define the maximum plausible number of inputs and outputs */
+/* for a Sampled function. */
+#define max_Sd_m 16
+#define max_Sd_n 16
+
+/* Get one set of sample values. */
+private int
+fn_get_samples(const gs_function_Sd_t *pfn, ulong offset, uint *samples)
+{ int bps = pfn->params.BitsPerSample;
+ int n = pfn->params.n;
+ byte buf[max_Sd_n * 4];
+ const byte *p;
+ int i;
+
+ data_source_access(&pfn->params.DataSource, offset >> 3,
+ (bps * n + 7) >> 3, buf, &p);
+ switch ( bps ) {
+ case 1:
+ for ( i = 0; i < n; ++i ) {
+ samples[i] = (*p >> (~offset & 7)) & 1;
+ if ( !(++offset & 7) )
+ p++;
+ }
+ break;
+ case 2:
+ for ( i = 0; i < n; ++i ) {
+ samples[i] = (*p >> (6 - (offset & 7))) & 3;
+ if ( !((offset += 2) & 7) )
+ p++;
+ }
+ break;
+ case 4:
+ for ( i = 0; i < n; offset ^= 4, ++i )
+ samples[i] = (offset & 4 ? *p++ & 0xf : *p >> 4);
+ break;
+ case 8:
+ for ( i = 0; i < n; ++i )
+ samples[i] = *p++;
+ break;
+ case 12:
+ for ( i = 0; i < n; offset ^= 4, ++i )
+ if ( offset & 4 )
+ samples[i] = ((*p & 0xf) << 8) + p[1], p += 2;
+ else
+ samples[i] = (*p << 4) + (p[1] >> 4), p++;
+ break;
+ case 16:
+ for ( i = 0; i < n; p += 2, ++i )
+ samples[i] = (*p << 8) + p[1];
+ break;
+ case 24:
+ for ( i = 0; i < n; p += 3, ++i )
+ samples[i] = (*p << 16) + (p[1] << 8) + p[2];
+ break;
+ case 32:
+ for ( i = 0; i < n; p += 4, ++i )
+ samples[i] = (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
+ break;
+ }
+ return 0;
+}
+
+/* Calculate a result by multilinear interpolation. */
+private void
+fn_interpolate_linear(const gs_function_Sd_t *pfn, const float *values,
+ const ulong *factors, uint *samples, ulong offset, int i)
+{ if ( i == pfn->params.m )
+ fn_get_samples(pfn, offset, samples);
+ else {
+ float fpart = values[i] - floor(values[i]);
+
+ fn_interpolate_linear(pfn, values, factors, samples, offset, i + 1);
+ if ( fpart != 0 ) {
+ int j;
+ uint samples1[max_Sd_n];
+
+ fn_interpolate_linear(pfn, values, factors, samples1,
+ offset + factors[i], i + 1);
+ for ( j = 0; j < pfn->params.n; ++j )
+ samples[j] += (samples1[j] - samples[j]) * fpart;
+ }
+ }
+}
+
+/* Evaluate a Sampled function. */
+private int
+fn_Sd_evaluate(const gs_function_t *pfn_common, const float *in, float *out)
+{ const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
+ int bps = pfn->params.BitsPerSample;
+ ulong offset = 0;
+ int i;
+ float encoded[max_Sd_m];
+ ulong factors[max_Sd_m];
+ uint samples[max_Sd_n];
+
+ /* Encode the input values. */
+
+ for ( i = 0; i < pfn->params.m; ++i ) {
+ float d0 = pfn->params.Domain[2 * i],
+ d1 = pfn->params.Domain[2 * i + 1];
+ float arg = in[i], enc;
+
+ if ( arg < d0 )
+ arg = d0;
+ else if ( arg > d1 )
+ arg = d1;
+ if ( pfn->params.Encode ) {
+ float e0 = pfn->params.Encode[2 * i];
+ float e1 = pfn->params.Encode[2 * i + 1];
+
+ enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0;
+ if ( enc < 0 )
+ encoded[i] = 0;
+ else if ( enc >= pfn->params.Size[i] - 1 )
+ encoded[i] = pfn->params.Size[i] - 1;
+ else
+ encoded[i] = enc;
+ } else {
+ /* arg is guaranteed to be in bounds, ergo so is enc */
+ encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
+ }
+ }
+
+ /* Look up and interpolate the output values. */
+
+ { ulong factor = bps * pfn->params.n;
+
+ for ( i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++] )
+ offset += (factors[i] = factor) * (int)encoded[i];
+ }
+ /****** LINEAR INTERPOLATION ONLY ******/
+ fn_interpolate_linear(pfn, encoded, factors, samples, offset, 0);
+
+ /* Encode the output values. */
+
+ for ( i = 0; i < pfn->params.n; offset += bps, ++i ) {
+ float d0, d1, r0, r1, value;
+
+ if ( pfn->params.Range )
+ r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1];
+ else
+ r0 = 0, r1 = (1 << bps) - 1;
+ if ( pfn->params.Decode )
+ d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1];
+ else
+ d0 = r0, d1 = r1;
+
+ value = samples[i] * (d1 - d0) / ((1 << bps) - 1) + d0;
+ if ( value < r0 )
+ out[i] = r0;
+ else if ( value > r1 )
+ out[i] = r1;
+ else
+ out[i] = value;
+ }
+
+ return 0;
+}
+
+/* Free the parameters of a Sampled function. */
+void
+gs_function_Sd_free_params(gs_function_Sd_params_t *params, gs_memory_t *mem)
+{ gs_free_object(mem, (void *)params->Size, "Size"); /* break const */
+ gs_free_object(mem, (void *)params->Decode, "Decode"); /* break const */
+ gs_free_object(mem, (void *)params->Encode, "Encode"); /* break const */
+ fn_common_free_params((gs_function_params_t *)params, mem);
+}
+
+/* Allocate and initialize a Sampled function. */
+int
+gs_function_Sd_init(gs_function_t **ppfn,
+ const gs_function_Sd_params_t *params, gs_memory_t *mem)
+{ static const gs_function_head_t function_Sd_head = {
+ function_type_Sampled,
+ (fn_evaluate_proc_t)fn_Sd_evaluate,
+ (fn_free_params_proc_t)gs_function_Sd_free_params,
+ fn_common_free
+ };
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ fn_check_mnDR(params, params->m, params->n);
+ if ( params->m > max_Sd_m )
+ return_error(gs_error_limitcheck);
+ switch ( params->Order ) {
+ case 0: /* use default */
+ case 1: case 3:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch ( params->BitsPerSample ) {
+ case 1: case 2: case 4: case 8: case 12: case 16: case 24: case 32:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ for ( i = 0; i < params->m; ++i )
+ if ( params->Size[i] <= 0 )
+ return_error(gs_error_rangecheck);
+ { gs_function_Sd_t *pfn =
+ gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
+ "gs_function_Sd_init");
+
+ if ( pfn == 0 )
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ if ( params->Order == 0 )
+ pfn->params.Order = 1; /* default */
+ pfn->head = function_Sd_head;
+ *ppfn = (gs_function_t *)pfn;
+ }
+ return 0;
+}
diff --git a/gs/src/gsfunc0.h b/gs/src/gsfunc0.h
new file mode 100644
index 000000000..6e811c406
--- /dev/null
+++ b/gs/src/gsfunc0.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfunc0.h */
+/* Definitions for FunctionType 0 (Sampled) Functions */
+
+#ifndef gsfunc0_INCLUDED
+# define gsfunc0_INCLUDED
+
+#include "gsfunc.h"
+#include "gsdsrc.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the Function type. */
+#define function_type_Sampled 0
+
+/* Define Sampled functions. */
+typedef struct gs_function_Sd_params_s {
+ gs_function_params_common;
+ int Order; /* 1 or 3, optional */
+ gs_data_source_t DataSource;
+ int BitsPerSample; /* 1, 2, 4, 8, 12, 16, 24, 32 */
+ const float *Encode; /* 2 x m, optional */
+ const float *Decode; /* 2 x n, optional */
+ const int *Size; /* m */
+} gs_function_Sd_params_t;
+#define private_st_function_Sd() /* in gsfunc.c */\
+ gs_private_st_suffix_add3(st_function_Sd, gs_function_Sd_t,\
+ "gs_function_Sd_t", function_Sd_enum_ptrs, function_Sd_reloc_ptrs,\
+ st_function, params.Encode, params.Decode, params.Size)
+
+/* ---------------- Procedures ---------------- */
+
+/* Allocate and initialize a Sampled function. */
+int gs_function_Sd_init(P3(gs_function_t **ppfn,
+ const gs_function_Sd_params_t *params,
+ gs_memory_t *mem));
+
+/* Free the parameters of a Sampled function. */
+void gs_function_Sd_free_params(P2(gs_function_Sd_params_t *params,
+ gs_memory_t *mem));
+
+#endif /* gsfunc0_INCLUDED */
diff --git a/gs/src/gsgc.h b/gs/src/gsgc.h
new file mode 100644
index 000000000..ab8629627
--- /dev/null
+++ b/gs/src/gsgc.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsgc.h */
+/* Library-level interface to garbage collector */
+
+/*
+ * This API is not strictly at the library level, since it references
+ * gs_ref_memory_t and the 4 PostScript memory spaces; however, the former
+ * concept already leaks into the library's standard allocator, and the
+ * latter is relatively small and harmless.
+ */
+
+#ifndef gsgc_INCLUDED
+# define gsgc_INCLUDED
+
+/*
+ * Define the VM space numbers, in increasing order of dynamism. Pointers
+ * from a higher-numbered space to the same or a lower-numbered space are
+ * always allowed, but not vice versa. Foreign space (the most static) is
+ * internal, the rest are visible to the programmer; the index of foreign
+ * space must be 0, so that we don't have to set any space bits in scalar
+ * refs (PostScript objects).
+ */
+typedef enum {
+ i_vm_foreign = 0, /* must be 0 */
+ i_vm_system,
+ i_vm_global,
+ i_vm_local,
+ i_vm_max = i_vm_local
+} i_vm_space;
+
+/* Define an array of allocators indexed by space. */
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+/*
+ * r_space_bits is only defined in PostScript interpreters, but if it is
+ * defined, we want to make sure it's 2.
+ */
+#ifdef r_space_bits
+# if r_space_bits != 2
+Error_r_space_bits_is_not_2;
+# endif
+#endif
+typedef union vm_spaces_s {
+ gs_ref_memory_t *indexed[4 /*1 << r_space_bits*/];
+ struct _ssn {
+ gs_ref_memory_t *foreign;
+ gs_ref_memory_t *system;
+ gs_ref_memory_t *global;
+ gs_ref_memory_t *local;
+ } named;
+} vm_spaces;
+/* By convention, the vm_spaces member of structures, and local variables */
+/* of type vm_spaces, are named spaces. */
+#define space_foreign spaces.named.foreign
+#define space_system spaces.named.system
+#define space_global spaces.named.global
+#define space_local spaces.named.local
+
+/*
+ * Define the top-level entry to the garbage collector.
+ */
+void gs_reclaim(P2(vm_spaces *pspaces, bool global));
+
+#endif /* gsgc_INCLUDED */
diff --git a/gs/src/gsgraph.icx b/gs/src/gsgraph.icx
new file mode 100644
index 000000000..0005dbf45
--- /dev/null
+++ b/gs/src/gsgraph.icx
@@ -0,0 +1,48 @@
+0000010001002020100000000000e802
+00001600000028000000200000004000
+00000100040000000000800200000000
+00000000000000000000000000000000
+00000000800000800000008080008000
+00008000800080800000808080004040
+40000000ff0000ff000000ffff00ff00
+0000ff00ff00ffff0000ffffff00cccc
+cccccccccccccccccccccccccccccccc
+ccccccccccccccbbbbccccccccccccbc
+bccbccbccbbbbcccccbccbbbccccccbc
+bccbccbcbcccbccbbbbcbcccccccccbc
+bccbccbccbbbbcbcccbcbbbbbcccccbc
+bccbccbcccccbcbcccbcbcccbcccccbc
+bbbcbbcccbbbcccbbbbccbbbcccccccc
+ccccccccccccccccccccccccccccccbc
+cccccccccccccccccccccccccccccccc
+cccccccccccccccccccccccccccc0000
+00fffffffffffffffff0000000000000
+000ffffffffffff0f000000000000000
+0000ffffffffffff0000000000000000
+00000ffffffffffff000000f000000ff
+000ff0fffffffffff00ffffff000000f
+ffff0fffffffffff0ffffffff0000fff
+fffff0fffffffffffffffffffff00000
+fffffffffffffffffffff000ff0000ff
+f000fffffffffffffffff0000ff000f0
+0000ffffffffffffffff000000000000
+00000ffffffffffff0f0000000000000
+0000000fff0ff00fff00000000000000
+0000000ff0fff00fff00000000000000
+0000000000ffffffff00000000000000
+0000000000ffffffff00000000000000
+0000000000ff0f0ff000000000000000
+00000000000fffff0000000000000000
+00000000000ffff00000000000000000
+0000000000ffff000000000000000000
+000000000ffff0000000000000000000
+0000000000ff00000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+000000000000f80000fffc0001fffe00
+07efcc00020780000003800000010000
+0000800000018000003086000079df00
+00ffff8001ffffc001ffffe001fffff8
+01fffff803fffff807fffffc0ffffff8
+1ffffff03ffffff87ffffffcffff
diff --git a/gs/src/gshsb.c b/gs/src/gshsb.c
new file mode 100644
index 000000000..28fbeeb77
--- /dev/null
+++ b/gs/src/gshsb.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gshsb.c */
+/* HSB color operators for Ghostscript library */
+#include "gx.h"
+#include "gscolor.h"
+#include "gshsb.h" /* interface definition */
+#include "gxfrac.h"
+
+/* Forward references */
+private void color_hsb_to_rgb(P4(floatp h, floatp s, floatp b, float rgb[3]));
+private void color_rgb_to_hsb(P4(floatp r, floatp g, floatp b, float hsb[3]));
+
+/* Force a parameter into the range [0.0..1.0]. */
+#define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
+
+/* sethsbcolor */
+int
+gs_sethsbcolor(gs_state *pgs, floatp h, floatp s, floatp b)
+{ float rgb[3];
+ color_hsb_to_rgb(force_unit(h), force_unit(s), force_unit(b), rgb);
+ return gs_setrgbcolor(pgs, rgb[0], rgb[1], rgb[2]);
+}
+
+/* currenthsbcolor */
+int
+gs_currenthsbcolor(const gs_state *pgs, float pr3[3])
+{ float rgb[3];
+ gs_currentrgbcolor(pgs, rgb);
+ color_rgb_to_hsb(rgb[0], rgb[1], rgb[2], pr3);
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Note: the color model conversion algorithms are taken from */
+/* Rogers, Procedural Elements for Computer Graphics, pp. 401-403. */
+
+/* Convert RGB to HSB. */
+private void
+color_rgb_to_hsb(floatp r, floatp g, floatp b, float hsb[3])
+{ frac red = float2frac(r), green = float2frac(g), blue = float2frac(b);
+#define rhue hsb[0]
+#define rsat hsb[1]
+#define rbri hsb[2]
+ if ( red == green && green == blue )
+ { rhue = 0; /* arbitrary */
+ rsat = 0;
+ rbri = r; /* pick any one */
+ }
+ else
+ { /* Convert rgb to hsb */
+ frac V, Temp, diff;
+ long H;
+ V = (red > green ? red : green);
+ if ( blue > V )
+ V = blue;
+ Temp = (red > green ? green : red);
+ if ( blue < Temp )
+ Temp = blue;
+ diff = V - Temp;
+ if ( V == red )
+ H = (green - blue) * frac_1_long / diff;
+ else if ( V == green )
+ H = (blue - red) * frac_1_long / diff + 2 * frac_1_long;
+ else /* V == blue */
+ H = (red - green) * frac_1_long / diff + 4 * frac_1_long;
+ if ( H < 0 )
+ H += 6 * frac_1_long;
+ rhue = H / (frac_1 * 6.0);
+ rsat = diff / (float)V;
+ rbri = frac2float(V);
+ }
+#undef rhue
+#undef rsat
+#undef rbri
+}
+
+/* Convert HSB to RGB. */
+private void
+color_hsb_to_rgb(floatp hue, floatp saturation, floatp brightness, float rgb[3])
+{ if ( saturation == 0 )
+ { rgb[0] = rgb[1] = rgb[2] = brightness;
+ }
+ else
+ { /* Convert hsb to rgb. */
+ /* We rely on the fact that the product of two */
+ /* fracs fits into an unsigned long. */
+ floatp h6 = hue * 6;
+ ulong V = float2frac(brightness); /* force arithmetic to long */
+ frac S = float2frac(saturation);
+ int I = (int)h6;
+ ulong F = float2frac(h6 - I); /* ditto */
+ /* M = V*(1-S), N = V*(1-S*F), K = V*(1-S*(1-F)) = M-N+V */
+ frac M = V * (frac_1_long - S) / frac_1_long;
+ frac N = V * (frac_1_long - S * F / frac_1_long) / frac_1_long;
+ frac K = M - N + V;
+ frac R, G, B;
+ switch ( I )
+ {
+ default: R = V; G = K; B = M; break;
+ case 1: R = N; G = V; B = M; break;
+ case 2: R = M; G = V; B = K; break;
+ case 3: R = M; G = N; B = V; break;
+ case 4: R = K; G = M; B = V; break;
+ case 5: R = V; G = M; B = N; break;
+ }
+ rgb[0] = frac2float(R);
+ rgb[1] = frac2float(G);
+ rgb[2] = frac2float(B);
+#ifdef DEBUG
+if ( gs_debug_c('c') )
+{ dprintf7("[c]hsb(%g,%g,%g)->VSFI(%ld,%d,%ld,%d)->\n",
+ hue, saturation, brightness, V, S, F, I);
+ dprintf6(" RGB(%d,%d,%d)->rgb(%g,%g,%g)\n",
+ R, G, B, rgb[0], rgb[1], rgb[2]);
+}
+#endif
+ }
+}
diff --git a/gs/src/gshsb.h b/gs/src/gshsb.h
new file mode 100644
index 000000000..69b2035e8
--- /dev/null
+++ b/gs/src/gshsb.h
@@ -0,0 +1,23 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gshsb.h */
+/* Client interface to HSB color routines */
+
+int gs_sethsbcolor(P4(gs_state *, floatp, floatp, floatp)),
+ gs_currenthsbcolor(P2(const gs_state *, float [3]));
diff --git a/gs/src/gsht.c b/gs/src/gsht.c
new file mode 100644
index 000000000..141c2d41e
--- /dev/null
+++ b/gs/src/gsht.c
@@ -0,0 +1,552 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsht.c */
+/* setscreen operator for Ghostscript library */
+#include "memory_.h"
+#include <stdlib.h> /* for qsort */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxarith.h" /* for igcd */
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Forward declarations */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Structure types */
+public_st_ht_order();
+private_st_ht_order_component();
+public_st_ht_order_comp_element();
+public_st_halftone();
+public_st_device_halftone();
+
+/* GC procedures */
+
+#define hptr ((gs_halftone *)vptr)
+
+private ENUM_PTRS_BEGIN(halftone_enum_ptrs) return 0;
+ case 0:
+ switch ( hptr->type )
+ {
+ case ht_type_threshold:
+ ENUM_RETURN_CONST_STRING_PTR(gs_halftone, params.threshold.thresholds);
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ ENUM_RETURN(hptr->params.multiple.components);
+ default:
+ return 0;
+ }
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(halftone_reloc_ptrs) {
+ switch ( hptr->type )
+ {
+ case ht_type_threshold:
+ RELOC_CONST_STRING_PTR(gs_halftone, params.threshold.thresholds);
+ break;
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ RELOC_PTR(gs_halftone, params.multiple.components);
+ break;
+ case ht_type_none:
+ case ht_type_screen:
+ case ht_type_colorscreen:
+ case ht_type_spot:
+ break;
+ }
+} RELOC_PTRS_END
+
+#undef hptr
+
+/* setscreen */
+int
+gs_setscreen(gs_state *pgs, gs_screen_halftone *phsp)
+{ gs_screen_enum senum;
+ int code = gx_ht_process_screen(&senum, pgs, phsp,
+ gs_currentaccuratescreens());
+ if ( code < 0 )
+ return code;
+ return gs_screen_install(&senum);
+}
+
+/* currentscreen */
+int
+gs_currentscreen(const gs_state *pgs, gs_screen_halftone *phsp)
+{ switch ( pgs->halftone->type )
+ {
+ case ht_type_screen:
+ *phsp = pgs->halftone->params.screen;
+ return 0;
+ case ht_type_colorscreen:
+ *phsp = pgs->halftone->params.colorscreen.screens.colored.gray;
+ return 0;
+ default:
+ return_error(gs_error_undefined);
+ }
+}
+
+/* .currentscreenlevels */
+int
+gs_currentscreenlevels(const gs_state *pgs)
+{ return pgs->dev_ht->order.num_levels;
+}
+
+/* .setscreenphase */
+int
+gx_imager_setscreenphase(gs_imager_state *pis, int x, int y,
+ gs_color_select_t select)
+{ if ( select == gs_color_select_all )
+ { int i;
+ for ( i = 0; i < gs_color_select_count; ++i )
+ gx_imager_setscreenphase(pis, x, y, (gs_color_select_t)i);
+ return 0;
+ }
+ else if ( select < 0 || select >= gs_color_select_count )
+ return_error(gs_error_rangecheck);
+ pis->screen_phase[select].x = x;
+ pis->screen_phase[select].y = y;
+ return 0;
+}
+int
+gs_setscreenphase(gs_state *pgs, int x, int y, gs_color_select_t select)
+{ int code = gx_imager_setscreenphase((gs_imager_state *)pgs, x, y,
+ select);
+
+ /*
+ * If we're only setting the source phase, we don't need to do
+ * unset_dev_color, because the source phase doesn't affect painting
+ * with the current color.
+ */
+ if ( code >= 0 && (select == gs_color_select_texture ||
+ select == gs_color_select_all)
+ )
+ gx_unset_dev_color(pgs);
+ return code;
+}
+
+/* .currentscreenphase */
+int
+gs_currentscreenphase(const gs_state *pgs, gs_int_point *pphase,
+ gs_color_select_t select)
+{ if ( select < 0 || select >= gs_color_select_count )
+ return_error(gs_error_rangecheck);
+ *pphase = pgs->screen_phase[select];
+ return 0;
+}
+
+/* currenthalftone */
+int
+gs_currenthalftone(gs_state *pgs, gs_halftone *pht)
+{ *pht = *pgs->halftone;
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Process one screen plane. */
+int
+gx_ht_process_screen_memory(gs_screen_enum *penum, gs_state *pgs,
+ gs_screen_halftone *phsp, bool accurate, gs_memory_t *mem)
+{ gs_point pt;
+ int code = gs_screen_init_memory(penum, pgs, phsp, accurate, mem);
+
+ if ( code < 0 ) return code;
+ while ( (code = gs_screen_currentpoint(penum, &pt)) == 0 )
+ if ( (code = gs_screen_next(penum, (*phsp->spot_function)(pt.x, pt.y))) < 0 )
+ return code;
+ return 0;
+}
+
+/* Allocate and initialize the contents of a halftone order. */
+/* The client must have set the defining values in porder->params. */
+int
+gx_ht_alloc_order(gx_ht_order *porder, uint width, uint height,
+ uint strip_shift, uint num_levels, gs_memory_t *mem)
+{ uint size = width * height;
+ gx_ht_order order;
+
+ order = *porder;
+ gx_compute_cell_values(&order.params);
+ order.width = width;
+ order.height = height;
+ order.raster = bitmap_raster(width);
+ order.shift = strip_shift;
+ order.orig_height = order.height;
+ order.orig_shift = order.shift;
+ order.full_height = ht_order_full_height(&order);
+ order.num_levels = num_levels;
+ order.num_bits = size;
+ order.levels =
+ (uint *)gs_alloc_byte_array(mem, num_levels, sizeof(uint),
+ "ht order(levels)");
+ order.bits =
+ (gx_ht_bit *)gs_alloc_byte_array(mem, size, sizeof(gx_ht_bit),
+ "ht order(bits)");
+ if ( order.levels == 0 || order.bits == 0 )
+ { gs_free_object(mem, order.bits, "ht order(bits)");
+ gs_free_object(mem, order.levels, "ht order(levels)");
+ return_error(gs_error_VMerror);
+ }
+ order.cache = 0;
+ order.transfer = 0;
+ *porder = order;
+ return 0;
+}
+
+/* Compare keys ("masks", actually sample values) for qsort. */
+private int
+compare_samples(const void *p1, const void *p2)
+{ ht_sample_t m1 = ((const gx_ht_bit *)p1)->mask;
+ ht_sample_t m2 = ((const gx_ht_bit *)p2)->mask;
+ return (m1 < m2 ? -1 : m1 > m2 ? 1 : 0);
+}
+/* Sort the halftone order by sample value. */
+void
+gx_sort_ht_order(gx_ht_bit *recs, uint N)
+{ int i;
+ /* Tag each sample with its index, for sorting. */
+ for ( i = 0; i < N; i++ )
+ recs[i].offset = i;
+ qsort((void *)recs, N, sizeof(*recs), compare_samples);
+#ifdef DEBUG
+if ( gs_debug_c('H') )
+ { uint i;
+ dprintf("[H]Sorted samples:\n");
+ for ( i = 0; i < N; i++ )
+ dprintf3("%5u: %5u: %u\n",
+ i, recs[i].offset, recs[i].mask);
+ }
+#endif
+}
+
+/*
+ * Construct the halftone order from a sampled spot function. Only width x
+ * strip samples have been filled in; we must replicate the resulting sorted
+ * order vertically, shifting it by shift each time. See gxdht.h regarding
+ * the invariants that must be restored.
+ */
+void
+gx_ht_construct_spot_order(gx_ht_order *porder)
+{ uint width = porder->width;
+ uint height = porder->orig_height;
+ uint num_levels = porder->num_levels; /* = width x strip */
+ uint strip = num_levels / width;
+ gx_ht_bit *bits = porder->bits;
+ uint *levels = porder->levels;
+ uint shift = porder->orig_shift;
+ uint full_height = porder->full_height;
+ uint num_bits = porder->num_bits;
+ uint copies = num_bits / (width * strip);
+ gx_ht_bit *bp = bits + num_bits - 1;
+ uint i;
+
+ gx_sort_ht_order(bits, num_levels);
+ if_debug5('h',
+ "[h]spot order: num_levels=%u w=%u h=%u strip=%u shift=%u\n",
+ num_levels, width, height, strip, shift);
+ /* Fill in the levels array, replicating the bits vertically */
+ /* if needed. */
+ for ( i = num_levels; i > 0; )
+ { uint offset = bits[--i].offset;
+ uint x = offset % width;
+ uint hy = offset - x;
+ uint k;
+
+ levels[i] = i * copies;
+ for ( k = 0; k < copies;
+ k++, bp--, hy += num_levels, x = (x + width - shift) % width
+ )
+ bp->offset = hy + x;
+ }
+ /* If we have a complete halftone, restore the invariant. */
+ if ( num_bits == width * full_height )
+ { porder->height = full_height;
+ porder->shift = 0;
+ }
+ gx_ht_construct_bits(porder);
+}
+
+/* Construct offset/masks from the whitening order. */
+/* porder->bits[i].offset contains the index of the bit position */
+/* that is i'th in the whitening order. */
+void
+gx_ht_construct_bits(gx_ht_order *porder)
+{ uint width = porder->width;
+ uint size = porder->num_bits;
+ gx_ht_bit *bits = porder->bits;
+ uint i;
+ gx_ht_bit *phb;
+ byte *pb;
+ uint padding = porder->raster * 8 - width;
+
+ for ( i = 0, phb = bits; i < size; i++, phb++ )
+ { int pix = phb->offset;
+ ht_mask_t mask;
+ pix += pix / width * padding;
+ phb->offset = (pix >> 3) & -size_of(mask);
+ mask = (ht_mask_t)1 << (~pix & (ht_mask_bits - 1));
+ /* Replicate the mask bits. */
+ pix = ht_mask_bits - width;
+ while ( (pix -= width) >= 0 )
+ mask |= mask >> width;
+ /* Store the mask, reversing bytes if necessary. */
+ phb->mask = 0;
+ for ( pb = (byte *)&phb->mask + (sizeof(mask) - 1);
+ mask != 0;
+ mask >>= 8, pb--
+ )
+ *pb = (byte)mask;
+ }
+#ifdef DEBUG
+if ( gs_debug_c('H') )
+ { dprintf1("[H]Halftone order bits 0x%lx:\n", (ulong)bits);
+ for ( i = 0, phb = bits; i < size; i++, phb++ )
+ dprintf3("%4d: %u:0x%lx\n", i, phb->offset,
+ (ulong)phb->mask);
+ }
+#endif
+}
+
+/* Release a gx_device_halftone by freeing its components. */
+/* (Don't free the gx_device_halftone itself.) */
+void
+gx_ht_order_release(gx_ht_order *porder, gs_memory_t *mem, bool free_cache)
+{ if ( free_cache && porder->cache )
+ gx_ht_free_cache(mem, porder->cache);
+ gs_free_object(mem, porder->transfer, "gx_ht_order_release(transfer)");
+ gs_free_object(mem, porder->bits, "gx_ht_order_release(bits)");
+ gs_free_object(mem, porder->levels, "gx_ht_order_release(levels)");
+}
+void
+gx_device_halftone_release(gx_device_halftone *pdht, gs_memory_t *mem)
+{ if ( pdht->components )
+ { int i;
+ /* One of the components might be the same as the default */
+ /* order, so check that we don't free it twice. */
+ for ( i = 0; i < pdht->num_comp; ++i )
+ if ( pdht->components[i].corder.bits !=
+ pdht->order.bits
+ )
+ { /* Currently, all orders except the default one */
+ /* own their caches. */
+ gx_ht_order_release(&pdht->components[i].corder, mem, true);
+ }
+ gs_free_object(mem, pdht->components,
+ "gx_dev_ht_release(components)");
+ pdht->components = 0;
+ pdht->num_comp = 0;
+ }
+ gx_ht_order_release(&pdht->order, mem, false);
+}
+
+/* Install a device halftone in an imager state. */
+/* Note that this does not read or update the client halftone. */
+int
+gx_imager_dev_ht_install(gs_imager_state *pis,
+ const gx_device_halftone *pdht, gs_halftone_type type, const gx_device *dev)
+{ gx_device_halftone *pgdht = pis->dev_ht;
+
+ if ( (ulong)pdht->order.raster * (pdht->order.num_bits /
+ pdht->order.width) > pis->ht_cache->bits_size
+ )
+ return_error(gs_error_limitcheck);
+ if ( pgdht != 0 && pgdht->rc.ref_count == 1 &&
+ pgdht->rc.memory == pdht->rc.memory
+ )
+ { /* The current device halftone isn't shared. */
+ /* Just release its components. */
+ gx_device_halftone_release(pgdht, pgdht->rc.memory);
+ }
+ else
+ { /* The device halftone is shared or not yet allocated. */
+ rc_unshare_struct(pis->dev_ht, gx_device_halftone,
+ &st_device_halftone, pdht->rc.memory,
+ return_error(gs_error_VMerror),
+ "gx_imager_dev_ht_install");
+ pgdht = pis->dev_ht;
+ }
+ { rc_header rc;
+ rc = pgdht->rc;
+ *pgdht = *pdht;
+ pgdht->rc = rc;
+ }
+ pgdht->id = gs_next_ids(1);
+#ifdef FUTURE
+ pgdht->type = type;
+#endif
+ /* Clear the cache, to avoid confusion in case the address of */
+ /* a new order vector matches that of a (deallocated) old one. */
+ gx_ht_clear_cache(pis->ht_cache);
+ /* Set the color_indices according to the device color_info. */
+ /* Also compute the LCM of the primary color cell sizes. */
+ /* Note that for strip halftones, the "cell size" is the */
+ /* theoretical fully expanded size with shift = 0. */
+ if ( pdht->components != 0 )
+ { static const gs_ht_separation_name dcnames[5][4] =
+ { { gs_ht_separation_Default }, /* not used */
+ { gs_ht_separation_Default, gs_ht_separation_Default,
+ gs_ht_separation_Default, gs_ht_separation_Gray
+ },
+ { gs_ht_separation_Default }, /* not used */
+ { gs_ht_separation_Red, gs_ht_separation_Green,
+ gs_ht_separation_Blue, gs_ht_separation_Default
+ },
+ { gs_ht_separation_Cyan, gs_ht_separation_Magenta,
+ gs_ht_separation_Yellow, gs_ht_separation_Black
+ }
+ };
+ static const gs_ht_separation_name cscnames[4] =
+ { gs_ht_separation_Red, gs_ht_separation_Green,
+ gs_ht_separation_Blue, gs_ht_separation_Default
+ };
+ int num_comps = dev->color_info.num_components;
+ const gs_ht_separation_name _ds *cnames = dcnames[num_comps];
+ int lcm_width = 1, lcm_height = 1;
+ uint i;
+
+ /* Halftones set by setcolorscreen, and (we think) */
+ /* Type 2 and Type 4 halftones, are supposed to work */
+ /* for both RGB and CMYK, so we need a special check here. */
+ if ( num_comps == 4 &&
+ (type == ht_type_colorscreen ||
+ type == ht_type_multiple_colorscreen)
+ )
+ cnames = cscnames;
+ if_debug4('h', "[h]dcnames=%lu,%lu,%lu,%lu\n",
+ (ulong)cnames[0], (ulong)cnames[1],
+ (ulong)cnames[2], (ulong)cnames[3]);
+ memset(pgdht->color_indices, 0, sizeof(pdht->color_indices));
+ for ( i = 0; i < pdht->num_comp; i++ )
+ { const gx_ht_order_component *pcomp =
+ &pdht->components[i];
+ int j;
+ if_debug2('h', "[h]cname[%d]=%lu\n",
+ i, (ulong)pcomp->cname);
+ for ( j = 0; j < 4; j++ )
+ { if ( pcomp->cname == cnames[j] )
+ { if_debug2('h', "[h]color_indices[%d]=%d\n",
+ j, i);
+ pgdht->color_indices[j] = i;
+ }
+ }
+ }
+ /* Now do a second pass to compute the LCM. */
+ /* We have to do it this way in case some entry in */
+ /* color_indices is still 0. */
+ for ( i = 0; i < 4; ++i )
+ { const gx_ht_order_component *pcomp =
+ &pdht->components[pgdht->color_indices[i]];
+ uint cw = pcomp->corder.width;
+ uint ch = pcomp->corder.full_height;
+ int dw = lcm_width / igcd(lcm_width, cw);
+ int dh = lcm_height / igcd(lcm_height, ch);
+ lcm_width = (cw > max_int / dw ? max_int : cw * dw);
+ lcm_height = (ch > max_int / dh ? max_int : ch * dh);
+ }
+ pgdht->lcm_width = lcm_width;
+ pgdht->lcm_height = lcm_height;
+ }
+ else
+ { /* Only one component. */
+ pgdht->lcm_width = pgdht->order.width;
+ pgdht->lcm_height = pgdht->order.full_height;
+ }
+ if_debug2('h', "[h]LCM=(%d,%d)\n",
+ pgdht->lcm_width, pgdht->lcm_height);
+ gx_imager_set_effective_xfer(pis);
+ return 0;
+}
+
+/*
+ * Install a new halftone in the graphics state. Note that we copy the top
+ * level of the gs_halftone and the gx_device_halftone, and take ownership
+ * of any substructures.
+ */
+int
+gx_ht_install(gs_state *pgs, const gs_halftone *pht,
+ const gx_device_halftone *pdht)
+{ gs_memory_t *mem = pht->rc.memory;
+ gs_halftone *old_ht = pgs->halftone;
+ gs_halftone *new_ht;
+ int code;
+
+ if ( old_ht != 0 && old_ht->rc.memory == mem &&
+ old_ht->rc.ref_count == 1
+ )
+ new_ht = old_ht;
+ else
+ rc_alloc_struct_1(new_ht, gs_halftone, &st_halftone,
+ mem, return_error(gs_error_VMerror),
+ "gx_ht_install(new halftone)");
+ code = gx_imager_dev_ht_install((gs_imager_state *)pgs,
+ pdht, pht->type, gs_currentdevice_inline(pgs));
+ if ( code < 0 )
+ { if ( new_ht != old_ht )
+ gs_free_object(mem, new_ht, "gx_ht_install(new halftone)");
+ return code;
+ }
+ if ( new_ht != old_ht )
+ rc_decrement(old_ht, "gx_ht_install(old halftone)");
+ { rc_header rc;
+ rc = new_ht->rc;
+ *new_ht = *pht;
+ new_ht->rc = rc;
+ }
+ pgs->halftone = new_ht;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* Reestablish the effective transfer functions, taking into account */
+/* any overrides from halftone dictionaries. */
+void
+gx_imager_set_effective_xfer(gs_imager_state *pis)
+{ const gx_device_halftone *pdht = pis->dev_ht;
+
+ pis->effective_transfer = pis->set_transfer; /* default */
+ if ( pdht == 0 )
+ return; /* not initialized yet */
+ if ( pdht->components == 0 )
+ { /* Check for transfer function override in single halftone */
+ gx_transfer_map *pmap = pdht->order.transfer;
+ if ( pmap != 0 )
+ pis->effective_transfer.indexed[0] =
+ pis->effective_transfer.indexed[1] =
+ pis->effective_transfer.indexed[2] =
+ pis->effective_transfer.indexed[3] = pmap;
+ }
+ else
+ { /* Check in all 4 standard separations */
+ int i;
+ for ( i = 0; i < 4; ++i )
+ { gx_transfer_map *pmap =
+ pdht->components[pdht->color_indices[i]].corder.
+ transfer;
+ if ( pmap != 0 )
+ pis->effective_transfer.indexed[i] = pmap;
+ }
+ }
+}
+void
+gx_set_effective_transfer(gs_state *pgs)
+{ gx_imager_set_effective_xfer((gs_imager_state *)pgs);
+}
diff --git a/gs/src/gsht.h b/gs/src/gsht.h
new file mode 100644
index 000000000..49b6a3e8b
--- /dev/null
+++ b/gs/src/gsht.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsht.h */
+/* Public interface to halftone functionality */
+
+#ifndef gsht_INCLUDED
+# define gsht_INCLUDED
+
+/* Client definition of (Type 1) halftones */
+typedef struct gs_screen_halftone_s {
+ float frequency;
+ float angle;
+ float (*spot_function)(P2(floatp, floatp));
+ /* setscreen or sethalftone sets these: */
+ /* (a Level 2 feature, but we include them in Level 1) */
+ float actual_frequency;
+ float actual_angle;
+} gs_screen_halftone;
+#define st_screen_halftone_max_ptrs 0
+
+/* Client definition of color (Type 2) halftones */
+typedef struct gs_colorscreen_halftone_s {
+ union _css {
+ gs_screen_halftone indexed[4];
+ struct _csc {
+ gs_screen_halftone red, green, blue, gray;
+ } colored;
+ } screens;
+} gs_colorscreen_halftone;
+#define st_colorscreen_halftone_max_ptrs 0
+
+/* Procedural interface */
+int gs_setscreen(P2(gs_state *, gs_screen_halftone *));
+int gs_currentscreen(P2(const gs_state *, gs_screen_halftone *));
+int gs_currentscreenlevels(P1(const gs_state *));
+
+/*
+ * Enumeration-style definition of a single screen. The client must:
+ * - probably, call gs_screen_enum_alloc;
+ * - call gs_screen_init;
+ * - in a loop,
+ * - call gs_screen_currentpoint; if it returns 1, exit;
+ * - call gs_screen_next;
+ * - if desired, call gs_screen_install to install the screen.
+ */
+typedef struct gs_screen_enum_s gs_screen_enum;
+gs_screen_enum *gs_screen_enum_alloc(P2(gs_memory_t *, client_name_t));
+int gs_screen_init(P3(gs_screen_enum *, gs_state *,
+ gs_screen_halftone *));
+int gs_screen_currentpoint(P2(gs_screen_enum *, gs_point *));
+int gs_screen_next(P2(gs_screen_enum *, floatp));
+int gs_screen_install(P1(gs_screen_enum *));
+
+#endif /* gsht_INCLUDED */
diff --git a/gs/src/gsht1.c b/gs/src/gsht1.c
new file mode 100644
index 000000000..b2b98480f
--- /dev/null
+++ b/gs/src/gsht1.c
@@ -0,0 +1,356 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsht1.c */
+/* Extended halftone operators for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Define the size of the halftone tile cache. */
+#define max_tile_bytes_LARGE 4096
+#define max_tile_bytes_SMALL 512
+#if arch_small_memory
+# define max_tile_cache_bytes max_tile_bytes_SMALL
+#else
+# define max_tile_cache_bytes\
+ (gs_if_debug_c('.') ? max_tile_bytes_SMALL : max_tile_bytes_LARGE)
+#endif
+
+/* Imports from gscolor.c */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* Forward declarations */
+private int process_spot(P4(gx_ht_order *, gs_state *,
+ gs_spot_halftone *, gs_memory_t *));
+private int process_threshold(P4(gx_ht_order *, gs_state *,
+ gs_threshold_halftone *, gs_memory_t *));
+
+/* Structure types */
+public_st_halftone_component();
+public_st_ht_component_element();
+
+/* GC procedures */
+
+#define hptr ((gs_halftone_component *)vptr)
+
+private ENUM_PTRS_BEGIN(halftone_component_enum_ptrs) return 0;
+ case 0:
+ if ( hptr->type != ht_type_threshold )
+ return 0;
+ ENUM_RETURN_CONST_STRING_PTR(gs_halftone_component, params.threshold.thresholds);
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(halftone_component_reloc_ptrs) {
+ if ( hptr->type == ht_type_threshold )
+ RELOC_CONST_STRING_PTR(gs_halftone_component, params.threshold.thresholds);
+} RELOC_PTRS_END
+
+#undef hptr
+
+/* setcolorscreen */
+int
+gs_setcolorscreen(gs_state *pgs, gs_colorscreen_halftone *pht)
+{ gs_halftone ht;
+
+ ht.type = ht_type_colorscreen;
+ ht.params.colorscreen = *pht;
+ return gs_sethalftone(pgs, &ht);
+}
+
+/* currentcolorscreen */
+int
+gs_currentcolorscreen(gs_state *pgs, gs_colorscreen_halftone *pht)
+{ int code;
+ switch ( pgs->halftone->type )
+ {
+ case ht_type_colorscreen:
+ *pht = pgs->halftone->params.colorscreen;
+ return 0;
+ default:
+ code = gs_currentscreen(pgs, &pht->screens.colored.gray);
+ if ( code < 0 )
+ return code;
+ pht->screens.colored.red = pht->screens.colored.gray;
+ pht->screens.colored.green = pht->screens.colored.gray;
+ pht->screens.colored.blue = pht->screens.colored.gray;
+ return 0;
+ }
+}
+
+/* Set the halftone in the graphics state. */
+int
+gs_sethalftone(gs_state *pgs, gs_halftone *pht)
+{ gs_halftone ht;
+
+ ht = *pht;
+ ht.rc.memory = pgs->memory;
+ return gs_sethalftone_allocated(pgs, &ht);
+}
+int
+gs_sethalftone_allocated(gs_state *pgs, gs_halftone *pht)
+{ gx_device_halftone dev_ht;
+ int code = gs_sethalftone_prepare(pgs, pht, &dev_ht);
+
+ if ( code < 0 )
+ return code;
+ dev_ht.rc.memory = pht->rc.memory;
+ return gx_ht_install(pgs, pht, &dev_ht);
+}
+/* Prepare the halftone, but don't install it. */
+int
+gs_sethalftone_prepare(gs_state *pgs, gs_halftone *pht,
+ gx_device_halftone *pdht)
+{ gs_memory_t *mem = pht->rc.memory;
+ gx_ht_order_component *pocs = 0;
+ int code = 0;
+
+ switch ( pht->type )
+ {
+ case ht_type_colorscreen:
+ { gs_screen_halftone *phc =
+ pht->params.colorscreen.screens.indexed;
+ static const gs_ht_separation_name cnames[4] =
+ { gs_ht_separation_Default, gs_ht_separation_Red,
+ gs_ht_separation_Green, gs_ht_separation_Blue
+ };
+ static const int cindex[4] = { 3, 0, 1, 2 };
+ int i;
+ pocs = gs_alloc_struct_array(mem, 4,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if ( pocs == 0 )
+ return_error(gs_error_VMerror);
+ for ( i = 0; i < 4; i++ )
+ { gs_screen_enum senum;
+ int ci = cindex[i];
+ gx_ht_order_component *poc = &pocs[i];
+
+ code = gx_ht_process_screen_memory(&senum, pgs,
+ &phc[ci], gs_currentaccuratescreens(), mem);
+ if ( code < 0 )
+ break;
+#define sorder senum.order
+ poc->corder = sorder;
+ poc->cname = cnames[i];
+ if ( i == 0 ) /* Gray = Default */
+ pdht->order = sorder;
+ else
+ { uint tile_bytes =
+ sorder.raster *
+ (sorder.num_bits / sorder.width);
+ uint num_tiles =
+ max_tile_cache_bytes / tile_bytes + 1;
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, num_tiles,
+ tile_bytes * num_tiles);
+ if ( pcache == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ poc->corder.cache = pcache;
+ gx_ht_init_cache(pcache, &poc->corder);
+ }
+#undef sorder
+ }
+ if ( code < 0 )
+ break;
+ pdht->components = pocs;
+ pdht->num_comp = 4;
+ } break;
+ case ht_type_spot:
+ code = process_spot(&pdht->order, pgs, &pht->params.spot, mem);
+ if ( code < 0 )
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&pdht->order, pgs,
+ &pht->params.threshold, mem);
+ if ( code < 0 )
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ { uint count = pht->params.multiple.num_comp;
+ bool have_Default = false;
+ uint i;
+ gs_halftone_component *phc = pht->params.multiple.components;
+ gx_ht_order_component *poc_next;
+ pocs = gs_alloc_struct_array(mem, count,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if ( pocs == 0 )
+ return_error(gs_error_VMerror);
+ poc_next = pocs + 1;
+ for ( i = 0; i < count; i++, phc++ )
+ { gx_ht_order_component *poc;
+ if ( phc->cname == gs_ht_separation_Default )
+ { if ( have_Default )
+ { /* Duplicate Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ poc = pocs;
+ have_Default = true;
+ }
+ else if ( i == count - 1 && !have_Default )
+ { /* No Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ else
+ poc = poc_next++;
+ poc->cname = phc->cname;
+ switch ( phc->type )
+ {
+ case ht_type_spot:
+ code = process_spot(&poc->corder, pgs,
+ &phc->params.spot, mem);
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&poc->corder, pgs,
+ &phc->params.threshold, mem);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if ( code < 0 )
+ break;
+ if ( poc != pocs )
+ { gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, 1,
+ poc->corder.raster *
+ (poc->corder.num_bits /
+ poc->corder.width));
+ if ( pcache == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ poc->corder.cache = pcache;
+ gx_ht_init_cache(pcache, &poc->corder);
+ }
+ }
+ if ( code < 0 )
+ break;
+ pdht->order = pocs[0].corder; /* Default */
+ if ( count == 1 )
+ { /* We have only a Default; */
+ /* we don't need components. */
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ pdht->components = 0;
+ }
+ else
+ { pdht->components = pocs;
+ pdht->num_comp = count;
+ }
+ } break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if ( code < 0 )
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/* Process a transfer function override, if any. */
+private int
+process_transfer(gx_ht_order *porder, gs_state *pgs,
+ gs_mapping_proc tproc, gs_memory_t *mem)
+{ gx_transfer_map *pmap;
+
+ if ( tproc == 0 )
+ return 0;
+ pmap = gs_alloc_struct(mem, gx_transfer_map, &st_transfer_map,
+ "process_transfer");
+ if ( pmap == 0 )
+ return_error(gs_error_VMerror);
+ pmap->proc = tproc;
+ pmap->id = gs_next_ids(1);
+ load_transfer_map(pgs, pmap, 0.0);
+ porder->transfer = pmap;
+ return 0;
+}
+
+/* Process a spot plane. */
+private int
+process_spot(gx_ht_order *porder, gs_state *pgs,
+ gs_spot_halftone *phsp, gs_memory_t *mem)
+{ gs_screen_enum senum;
+
+ int code = gx_ht_process_screen_memory(&senum, pgs, &phsp->screen,
+ phsp->accurate_screens, mem);
+ if ( code < 0 )
+ return code;
+ *porder = senum.order;
+ return process_transfer(porder, pgs, phsp->transfer, mem);
+}
+
+/* Process a threshold plane. */
+private int
+process_threshold(gx_ht_order *porder, gs_state *pgs,
+ gs_threshold_halftone *phtp, gs_memory_t *mem)
+{ int code;
+
+ porder->params.M = phtp->width, porder->params.N = 0;
+ porder->params.R = 1;
+ porder->params.M1 = phtp->height, porder->params.N1 = 0;
+ porder->params.R1 = 1;
+ code = gx_ht_alloc_order(porder, phtp->width, phtp->height,
+ 0, 256, mem);
+ if ( code < 0 )
+ return code;
+ gx_ht_construct_threshold_order(porder, phtp->thresholds.data);
+ return process_transfer(porder, pgs, phtp->transfer, mem);
+}
+
+/* Construct the halftone order from a threshold array. */
+void
+gx_ht_construct_threshold_order(gx_ht_order *porder, const byte *thresholds)
+{ uint size = porder->num_bits;
+ uint *levels = porder->levels;
+ gx_ht_bit *bits = porder->bits;
+ uint i, j;
+ for ( i = 0; i < size; i++ )
+ bits[i].mask = max(1, thresholds[i]);
+ gx_sort_ht_order(bits, size);
+ /* We want to set levels[j] to the lowest value of i */
+ /* such that bits[i].mask > j. */
+ for ( i = 0, j = 0; i < size; i++ )
+ { if ( bits[i].mask != j )
+ { if_debug3('h', "[h]levels[%u..%u] = %u\n",
+ j, (uint)bits[i].mask, i);
+ while ( j < bits[i].mask )
+ levels[j++] = i;
+ }
+ }
+ while ( j < 256 )
+ levels[j++] = size;
+ gx_ht_construct_bits(porder);
+}
diff --git a/gs/src/gsht1.h b/gs/src/gsht1.h
new file mode 100644
index 000000000..ae89d510f
--- /dev/null
+++ b/gs/src/gsht1.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsht1.h */
+/* Extended public interface to halftones */
+
+#ifndef gsht1_INCLUDED
+# define gsht1_INCLUDED
+
+#include "gsht.h"
+
+/* Procedural interface */
+int gs_setcolorscreen(P2(gs_state *, gs_colorscreen_halftone *));
+int gs_currentcolorscreen(P2(gs_state *, gs_colorscreen_halftone *));
+
+/*
+ * We include sethalftone here, even though it is a Level 2 feature,
+ * because it turns out to be convenient to define setcolorscreen
+ * using sethalftone.
+ */
+#ifndef gs_halftone_DEFINED
+# define gs_halftone_DEFINED
+typedef struct gs_halftone_s gs_halftone;
+#endif
+/*
+ * gs_halftone structures may have complex substructures. We provide two
+ * procedures for setting them. gs_halftone assumes that the gs_halftone
+ * structure and all its substructures was allocated with the same allocator
+ * as the gs_state; gs_halftone_allocated looks in the structure itself (the
+ * rc.memory member) to find the allocator that was used Both procedures
+ * copy the top-level structure (using the appropriate allocator), but take
+ * ownership of the substructures.
+ */
+int gs_sethalftone(P2(gs_state *, gs_halftone *));
+int gs_sethalftone_allocated(P2(gs_state *, gs_halftone *));
+int gs_currenthalftone(P2(gs_state *, gs_halftone *));
+
+#endif /* gsht1_INCLUDED */
diff --git a/gs/src/gshtscr.c b/gs/src/gshtscr.c
new file mode 100644
index 000000000..a4fbae6c3
--- /dev/null
+++ b/gs/src/gshtscr.c
@@ -0,0 +1,529 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gshtscr.c */
+/* Screen (Type 1) halftone processing for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Define whether to force all halftones to be strip halftones, */
+/* for debugging. */
+#define FORCE_STRIP_HALFTONES 1
+
+/* Structure descriptors */
+private_st_gs_screen_enum();
+
+/* GC procedures */
+#define eptr ((gs_screen_enum *)vptr)
+
+private ENUM_PTRS_BEGIN(screen_enum_enum_ptrs) {
+ if ( index < 2 + st_ht_order_max_ptrs )
+ { gs_ptr_type_t ret = (*st_ht_order.enum_ptrs)(&eptr->order, sizeof(eptr->order), index-2, pep);
+ if ( ret == 0 ) /* don't stop early */
+ ret = ptr_struct_type, *pep = 0;
+ return ret;
+ }
+ return (*st_halftone.enum_ptrs)(&eptr->halftone, sizeof(eptr->halftone), index-(2+st_ht_order_max_ptrs), pep);
+ }
+ ENUM_PTR(0, gs_screen_enum, pgs);
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(screen_enum_reloc_ptrs) {
+ RELOC_PTR(gs_screen_enum, pgs);
+ (*st_halftone.reloc_ptrs)(&eptr->halftone, sizeof(gs_halftone), gcst);
+ (*st_ht_order.reloc_ptrs)(&eptr->order, sizeof(gx_ht_order), gcst);
+} RELOC_PTRS_END
+
+#undef eptr
+
+/* Define the default value of AccurateScreens that affects */
+/* setscreen and setcolorscreen. */
+private bool screen_accurate_screens = false;
+
+/* Default AccurateScreens control */
+void
+gs_setaccuratescreens(bool accurate)
+{ screen_accurate_screens = accurate;
+}
+bool
+gs_currentaccuratescreens(void)
+{ return screen_accurate_screens;
+}
+
+/* Define the MinScreenLevels user parameter similarly. */
+private uint screen_min_screen_levels = 1;
+
+void
+gs_setminscreenlevels(uint levels)
+{ screen_min_screen_levels = levels;
+}
+uint
+gs_currentminscreenlevels(void)
+{ return screen_min_screen_levels;
+}
+
+/*
+ * The following implementation notes complement the general discussion of
+ * halftone tiles found in gxdht.h.
+ *
+ * Currently we allow R(') > 1 (i.e., multiple basic cells per multi-cell)
+ * only if AccurateScreens is true or if B (the number of pixels in a basic
+ * cell) < MinScreenLevels; if AccurateScreens is false and B >=
+ * MinScreenLevels, multi-cells and basic cells are the same.
+ *
+ * To find the smallest super-cell for a given multi-cell size, i.e., the
+ * smallest (absolute value) coordinates where the corners of multi-cells
+ * lie on the coordinate axes, we compute the values of i and j that give
+ * the minimum value of W by:
+ * D = gcd(abs(M'), abs(N)), i = M'/D, j = N/D, W = C / D,
+ * and similarly
+ * D' = gcd(abs(M), abs(N')), i' = N'/D', j' = M/D', W' = C / D'.
+ */
+
+/* Compute the derived values of a halftone tile. */
+void
+gx_compute_cell_values(gx_ht_cell_params_t *phcp)
+{ const int M = phcp->M, N = phcp->N, M1 = phcp->M1, N1 = phcp->N1;
+ const uint m = any_abs(M), n = any_abs(N);
+ const uint m1 = any_abs(M1), n1 = any_abs(N1);
+ const ulong C = phcp->C = (ulong)m * m1 + (ulong)n * n1;
+ const int D = igcd(m1, n);
+ const int D1 = igcd(m, n1);
+ const uint W = phcp->W = C / D;
+ const uint W1 = phcp->W1 = C / D1;
+
+ phcp->D = D, phcp->D1 = D1;
+ /* Compute the shift value. */
+ /* If M1 or N is zero, the shift is zero. */
+ if ( M1 && N )
+ { int h = 0, k = 0, dy = 0;
+ int shift;
+
+ /*
+ * There may be a faster way to do this: see Knuth vol. 2,
+ * section 4.5.2, Algorithm X (p. 302) and exercise 15
+ * (p. 315, solution p. 523).
+ */
+ while ( dy != D )
+ if ( dy > D )
+ { if ( M1 > 0 ) ++k;
+ else --k;
+ dy -= m1;
+ }
+ else
+ { if ( N > 0 ) ++h;
+ else --h;
+ dy += n;
+ }
+ shift = h * M + k * N1;
+ /* We just computed what amounts to a right shift; */
+ /* what we want is a left shift. */
+ phcp->S = imod(-shift, W);
+ }
+ else
+ phcp->S = 0;
+ if_debug12('h', "[h]MNR=(%d,%d)/%d, M'N'R'=(%d,%d)/%d => C=%lu, D=%d, D'=%d, W=%u, W'=%u, S=%d\n",
+ M, N, phcp->R, M1, N1, phcp->R1,
+ C, D, D1, W, W1, phcp->S);
+}
+
+/* Forward references */
+private int pick_cell_size(P6(gs_screen_halftone *ph,
+ const gs_matrix *pmat, ulong max_size, uint min_levels, bool accurate,
+ gx_ht_cell_params_t *phcp));
+
+/* Allocate a screen enumerator. */
+gs_screen_enum *
+gs_screen_enum_alloc(gs_memory_t *mem, client_name_t cname)
+{ return gs_alloc_struct(mem, gs_screen_enum, &st_gs_screen_enum, cname);
+}
+
+/* Set up for halftone sampling. */
+int
+gs_screen_init(gs_screen_enum *penum, gs_state *pgs,
+ gs_screen_halftone *phsp)
+{ return gs_screen_init_accurate(penum, pgs, phsp,
+ screen_accurate_screens);
+}
+int
+gs_screen_init_memory(gs_screen_enum *penum, gs_state *pgs,
+ gs_screen_halftone *phsp, bool accurate, gs_memory_t *mem)
+{ int code =
+ gs_screen_order_init_memory(&penum->order, pgs, phsp, accurate, mem);
+
+ if ( code < 0 )
+ return code;
+ return
+ gs_screen_enum_init_memory(penum, &penum->order, pgs, phsp, mem);
+}
+
+/* Allocate and initialize a spot screen. */
+/* This is the first half of gs_screen_init_accurate. */
+int
+gs_screen_order_init_memory(gx_ht_order *porder, const gs_state *pgs,
+ gs_screen_halftone *phsp, bool accurate, gs_memory_t *mem)
+{ gs_matrix imat;
+ ulong max_size = pgs->ht_cache->bits_size;
+ int code;
+
+ if ( phsp->frequency < 0.1 )
+ return_error(gs_error_rangecheck);
+ gs_deviceinitialmatrix(gs_currentdevice(pgs), &imat);
+ code = pick_cell_size(phsp, &imat, max_size,
+ screen_min_screen_levels, accurate,
+ &porder->params);
+ if ( code < 0 )
+ return code;
+ gx_compute_cell_values(&porder->params);
+#if !FORCE_STRIP_HALFTONES
+ if ( porder->params.W1 <= max_size / bitmap_raster(porder->params.W) )
+ { /*
+ * Allocate an order for the entire tile, but only sample one
+ * strip. Note that this causes the order parameters to be
+ * self-inconsistent until gx_ht_construct_spot_order fixes them
+ * up: see gxdht.h for more information.
+ */
+ code = gx_ht_alloc_order(porder, porder->params.W,
+ porder->params.W1, 0,
+ porder->params.W * porder->params.D,
+ mem);
+ porder->height = porder->orig_height = porder->params.D;
+ porder->shift = porder->orig_shift = porder->params.S;
+ }
+ else
+#endif
+ { /* Just allocate the order for a single strip. */
+ code = gx_ht_alloc_order(porder, porder->params.W,
+ porder->params.D, porder->params.S,
+ porder->params.W * porder->params.D,
+ mem);
+ }
+ if ( code < 0 )
+ return code;
+ return 0;
+}
+
+/*
+ * Given a desired frequency, angle, and minimum number of levels, a maximum
+ * cell size, and an AccurateScreens flag, pick values for M('), N('), and
+ * R('). We want to get a good fit to the requested frequency and angle,
+ * provide at least the requested minimum number of levels, and keep
+ * rendering as fast as possible; trading these criteria off against each
+ * other is what makes the code complicated.
+ *
+ * We compute trial values u and v from the original values of F and A.
+ * Normally these will not be integers. We then examine the 4 pairs of
+ * integers obtained by rounding each of u and v independently up or down,
+ * and pick the pair U, V that yields the closest match to the requested
+ * F and A values and doesn't require more than max_size storage for a
+ * single tile. If no pair
+ * yields an acceptably small W, we divide both u and v by 2 and try again.
+ * Then we run the equations backward to obtain the actual F and A.
+ * This is fairly easy given that we require either xx = yy = 0 or
+ * xy = yx = 0. In the former case, we have
+ * U = (72 / F * xx) * cos(A);
+ * V = (72 / F * yy) * sin(A);
+ * from which immediately
+ * A = arctan((V / yy) / (U / xx)),
+ * or equivalently
+ * A = arctan((V * xx) / (U * yy)).
+ * We can then obtain F as
+ * F = (72 * xx / U) * cos(A),
+ * or equivalently
+ * F = (72 * yy / V) * sin(A).
+ * For landscape devices, we replace xx by yx, yy by xy, and interchange
+ * sin and cos, resulting in
+ * A = arctan((U * xy) / (V * yx))
+ * and
+ * F = (72 * yx / U) * sin(A)
+ * or
+ * F = (72 * xy / V) * cos(A).
+ */
+/* ph->frequency and ph->angle are input parameters; */
+/* the routine sets ph->actual_frequency and ph->actual_angle. */
+private int
+pick_cell_size(gs_screen_halftone *ph, const gs_matrix *pmat, ulong max_size,
+ uint min_levels, bool accurate, gx_ht_cell_params_t *phcp)
+{ const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0);
+ /* Account for a possibly reflected coordinate system. */
+ /* See gxstroke.c for the algorithm. */
+ const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy;
+ const int reflection = (reflected ? -1 : 1);
+ const int rotation =
+ (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0);
+ const double f0 = ph->frequency, a0 = ph->angle;
+ const double T =
+ fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy));
+ gs_point uv0;
+#define u0 uv0.x
+#define v0 uv0.y
+ int rt = 1;
+ double f = 0, a = 0;
+ double e_best = 1000;
+ bool better;
+
+ /*
+ * We need to find a vector in device space whose length is
+ * 1 inch / ph->frequency and whose angle is ph->angle.
+ * Because device pixels may not be square, we can't simply
+ * map the length to device space and then rotate it;
+ * instead, since we know that user space is uniform in X and Y,
+ * we calculate the correct angle in user space before rotation.
+ */
+
+ /* Compute trial values of u and v. */
+
+ { gs_matrix rmat;
+ gs_make_rotation(a0 * reflection + rotation, &rmat);
+ gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0);
+ gs_distance_transform(u0, v0, pmat, &uv0);
+ if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n u=%g v=%g\n",
+ ph->frequency, ph->angle,
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ max_size, min_levels, u0, v0);
+ }
+
+ /* Adjust u and v to reasonable values. */
+
+ if ( u0 == 0 && v0 == 0 )
+ return_error(gs_error_rangecheck);
+ while ( (fabs(u0) + fabs(v0)) * rt < 4 )
+ ++rt;
+try_size:
+ better = false;
+ { int m0 = (int)floor(u0 * rt + 0.0001);
+ int n0 = (int)floor(v0 * rt + 0.0001);
+ gx_ht_cell_params_t p;
+
+ p.R = p.R1 = rt;
+ for ( p.M = m0 + 1; p.M >= m0; p.M-- )
+ for ( p.N = n0 + 1; p.N >= n0; p.N-- )
+ { long raster, wt, wt_size;
+ double fr, ar, ft, at, f_diff, a_diff, f_err, a_err;
+
+ p.M1 = (int)(p.M / T + 0.5);
+ p.N1 = (int)(p.N * T + 0.5);
+ gx_compute_cell_values(&p);
+ if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt);
+ wt = p.W;
+ if ( wt >= max_short )
+ continue;
+ /* Check the strip size, not the full tile size, */
+ /* against max_size. */
+ raster = bitmap_raster(wt);
+ if ( raster > max_size / p.D || raster > max_long / wt )
+ continue;
+ wt_size = raster * wt;
+
+ /* Compute the corresponding values of F and A. */
+
+ if ( landscape )
+ ar = atan2(p.M * pmat->xy, p.N * pmat->yx),
+ fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) :
+ pmat->yx / p.M * sin(ar));
+ else
+ ar = atan2(p.N * pmat->xx, p.M * pmat->yy),
+ fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) :
+ pmat->xx / p.M * cos(ar));
+ ft = fabs(fr) * rt;
+ /* Normalize the angle to the requested quadrant. */
+ at = (ar * radians_to_degrees - rotation) * reflection;
+ at -= floor(at / 180.0) * 180.0;
+ at += floor(a0 / 180.0) * 180.0;
+ f_diff = fabs(ft - f0);
+ a_diff = fabs(at - a0);
+ f_err = f_diff / fabs(f0);
+ /*
+ * We used to compute the percentage difference here:
+ * a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0));
+ * but using the angle difference makes more sense:
+ */
+ a_err = a_diff;
+
+ if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n",
+ p.D, wt, bitmap_raster(wt) * wt, ft, at);
+
+ /*
+ * Minimize angle and frequency error within the
+ * permitted maximum super-cell size.
+ */
+
+ { double err = f_err * a_err;
+ if ( err > e_best )
+ continue;
+ e_best = err;
+ }
+ *phcp = p;
+ f = ft, a = at;
+ better = true;
+ if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n",
+ wt_size, f_diff, a_diff);
+ if ( f_err <= 0.01 && a_err <= 0.01 )
+ goto done;
+ }
+ }
+ if ( phcp->C < min_levels )
+ { /* We don't have enough levels yet. Keep going. */
+ ++rt;
+ goto try_size;
+ }
+ if ( better )
+ { /* If we want accurate screens, continue till we fail. */
+ if ( accurate )
+ { ++rt;
+ goto try_size;
+ }
+ }
+ else
+ { /*
+ * We couldn't find an acceptable M and N. If R > 1,
+ * take what we've got; if R = 1, give up.
+ */
+ if ( rt == 1 )
+ return_error(gs_error_rangecheck);
+ }
+
+ /* Deliver the results. */
+done:
+ if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n",
+ f, a, phcp->M, phcp->N, phcp->R);
+ ph->actual_frequency = f;
+ ph->actual_angle = a;
+ return 0;
+#undef u0
+#undef v0
+}
+
+/* Prepare to sample a spot screen. */
+/* This is the second half of gs_screen_init_accurate. */
+int
+gs_screen_enum_init_memory(gs_screen_enum *penum, const gx_ht_order *porder,
+ gs_state *pgs, gs_screen_halftone *phsp, gs_memory_t *mem)
+{ penum->pgs = pgs; /* ensure clean for GC */
+ penum->order = *porder;
+ penum->halftone.rc.memory = mem;
+ penum->halftone.type = ht_type_screen;
+ penum->halftone.params.screen = *phsp;
+ penum->x = penum->y = 0;
+ penum->strip = porder->num_levels / porder->width;
+ penum->shift = porder->shift;
+ /*
+ * We want a transformation matrix that maps the parallelogram
+ * (0,0), (U,V), (U-V',V+U'), (-V',U') to the square (+/-1, +/-1).
+ * If the coefficients are [a b c d e f] and we let
+ * u = U = M/R, v = V = N/R,
+ * r = -V' = -N'/R', s = U' = M'/R',
+ * then we just need to solve the equations:
+ * a*0 + c*0 + e = -1 b*0 + d*0 + f = -1
+ * a*u + c*v + e = 1 b*u + d*v + f = 1
+ * a*r + c*s + e = -1 b*r + d*s + f = 1
+ * This has the following solution:
+ * Q = 2 / (M*M' + N*N')
+ * a = Q * R * M'
+ * b = -Q * R' * N
+ * c = Q * R * N'
+ * d = Q * R' * M
+ * e = -1
+ * f = -1
+ */
+ { const int M = porder->params.M, N = porder->params.N,
+ R = porder->params.R;
+ const int M1 = porder->params.M1, N1 = porder->params.N1,
+ R1 = porder->params.R1;
+ double Q = 2.0 / ((long)M * M1 + (long)N * N1);
+ penum->mat.xx = Q * (R * M1);
+ penum->mat.xy = Q * (-R1 * N);
+ penum->mat.yx = Q * (R * N1);
+ penum->mat.yy = Q * (R1 * M);
+ penum->mat.tx = -1.0;
+ penum->mat.ty = -1.0;
+ }
+ if_debug7('h', "[h]Screen: (%dx%d)/%d [%f %f %f %f]\n",
+ porder->width, porder->height, porder->params.R,
+ penum->mat.xx, penum->mat.xy,
+ penum->mat.yx, penum->mat.yy);
+ return 0;
+}
+
+/* Report current point for sampling */
+int
+gs_screen_currentpoint(gs_screen_enum *penum, gs_point *ppt)
+{ gs_point pt;
+ int code;
+ if ( penum->y >= penum->strip ) /* all done */
+ { gx_ht_construct_spot_order(&penum->order);
+ return 1;
+ }
+ /* We displace the sampled coordinates very slightly */
+ /* in order to reduce the likely number of points */
+ /* for which the spot function returns the same value. */
+ if ( (code = gs_point_transform(penum->x + 0.501, penum->y + 0.498, &penum->mat, &pt)) < 0 )
+ return code;
+ if ( pt.x < -1.0 )
+ pt.x += ((int)(-ceil(pt.x)) + 1) & ~1;
+ else if ( pt.x >= 1.0 )
+ pt.x -= ((int)pt.x + 1) & ~1;
+ if ( pt.y < -1.0 )
+ pt.y += ((int)(-ceil(pt.y)) + 1) & ~1;
+ else if ( pt.y >= 1.0 )
+ pt.y -= ((int)pt.y + 1) & ~1;
+ *ppt = pt;
+ return 0;
+}
+
+/* Record next halftone sample */
+int
+gs_screen_next(gs_screen_enum *penum, floatp value)
+{ ht_sample_t sample;
+ int width = penum->order.width;
+ if ( value < -1.0 || value > 1.0 )
+ return_error(gs_error_rangecheck);
+ /* The following statement was split into two */
+ /* to work around a bug in the Siemens C compiler. */
+ sample = (ht_sample_t)(value * max_ht_sample);
+ sample += max_ht_sample; /* convert from signed to biased */
+#ifdef DEBUG
+if ( gs_debug_c('H') )
+ { gs_point pt;
+ gs_screen_currentpoint(penum, &pt);
+ dprintf6("[H]sample x=%d y=%d (%f,%f): %f -> %u\n",
+ penum->x, penum->y, pt.x, pt.y, value, sample);
+ }
+#endif
+ penum->order.bits[penum->y * width + penum->x].mask = sample;
+ if ( ++(penum->x) >= width )
+ penum->x = 0, ++(penum->y);
+ return 0;
+}
+
+/* Install a fully constructed screen in the gstate. */
+int
+gs_screen_install(gs_screen_enum *penum)
+{ gx_device_halftone dev_ht;
+
+ dev_ht.rc.memory = penum->halftone.rc.memory;
+ dev_ht.order = penum->order;
+ dev_ht.components = 0;
+ return gx_ht_install(penum->pgs, &penum->halftone, &dev_ht);
+}
diff --git a/gs/src/gsimage.c b/gs/src/gsimage.c
new file mode 100644
index 000000000..acbeea046
--- /dev/null
+++ b/gs/src/gsimage.c
@@ -0,0 +1,311 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsimage.c */
+/* Image setup procedures for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gscspace.h"
+#include "gsmatrix.h" /* for gsiparam.h */
+#include "gsimage.h"
+#include "gxarith.h" /* for igcd */
+#include "gxdevice.h"
+#include "gzstate.h"
+
+/* Define the maximum number of image components. */
+#ifdef DPNEXT
+# define max_components 5
+#else
+# define max_components 4
+#endif
+
+/* Define the enumeration state for this interface layer. */
+/*typedef struct gs_image_enum_s gs_image_enum;*/ /* in gsimage.h */
+struct gs_image_enum_s {
+ /* The following are set at initialization time. */
+ gs_memory_t *memory;
+ gx_device *dev;
+ bool skip; /* if true, just skip over the data */
+ void *info; /* driver bookkeeping structure */
+ int num_components;
+ bool multi;
+ int num_planes;
+ int width, height;
+ int bpp; /* bits per pixel (per plane, if multi) */
+ uint raster; /* bytes per row (per plane), no padding */
+ /* The following are updated dynamically. */
+ int plane_index; /* index of next plane of data */
+ int y;
+ uint pos; /* byte position within the scan line */
+ gs_const_string sources[max_components]; /* source data */
+ gs_string rows[max_components]; /* row buffers */
+ bool error;
+};
+gs_private_st_composite(st_gs_image_enum, gs_image_enum, "gs_image_enum",
+ gs_image_enum_enum_ptrs, gs_image_enum_reloc_ptrs);
+#define gs_image_enum_num_ptrs 2
+
+/* GC procedures */
+#define eptr ((gs_image_enum *)vptr)
+private ENUM_PTRS_BEGIN(gs_image_enum_enum_ptrs) {
+ /* Enumerate the data planes. */
+ index -= gs_image_enum_num_ptrs;
+ if ( index < eptr->plane_index )
+ { *pep = (void *)&eptr->sources[index];
+ return ptr_string_type;
+ }
+ index -= eptr->plane_index;
+ if ( index < eptr->num_planes )
+ { *pep = (void *)&eptr->rows[index];
+ return ptr_string_type;
+ }
+ return 0;
+ }
+ ENUM_PTR(0, gs_image_enum, dev);
+ ENUM_PTR(1, gs_image_enum, info);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_image_enum_reloc_ptrs) {
+ int i;
+ RELOC_PTR(gs_image_enum, dev);
+ RELOC_PTR(gs_image_enum, info);
+ for ( i = 0; i < eptr->plane_index; i++ )
+ RELOC_CONST_STRING_PTR(gs_image_enum, sources[i]);
+ for ( i = 0; i < eptr->num_planes; i++ )
+ RELOC_STRING_PTR(gs_image_enum, rows[i]);
+} RELOC_PTRS_END
+#undef eptr
+
+/* Allocate an image enumerator. */
+private void
+image_enum_init(gs_image_enum *pie)
+{ /* Clean pointers for GC. */
+ int i;
+ pie->info = 0;
+ pie->dev = 0;
+ for ( i = 0; i < countof(pie->sources); ++i )
+ { pie->sources[i].data = 0, pie->sources[i].size = 0;
+ pie->rows[i].data = 0, pie->rows[i].size = 0;
+ }
+}
+gs_image_enum *
+gs_image_enum_alloc(gs_memory_t *mem, client_name_t cname)
+{ gs_image_enum *pie =
+ gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
+
+ if ( pie != 0 )
+ { pie->memory = mem;
+ image_enum_init(pie);
+ }
+ return pie;
+}
+
+/* Start processing an image. */
+int
+gs_image_init(gs_image_enum *pie, const gs_image_t *pim, bool multi,
+ gs_state *pgs)
+{ gx_device *dev = gs_currentdevice_inline(pgs);
+ gs_image_t image;
+ ulong samples_per_row = pim->Width;
+ int code;
+
+ if ( pim->Width == 0 || pim->Height == 0 )
+ return 1;
+ image = *pim;
+ image_enum_init(pie);
+ pie->skip = pgs->in_charpath;
+ if ( image.ImageMask )
+ { image.ColorSpace = NULL;
+ if ( pgs->in_cachedevice <= 1 )
+ image.adjust = false;
+ pie->num_components = pie->num_planes = 1;
+ }
+ else
+ { if ( pgs->in_cachedevice )
+ return_error(gs_error_undefined);
+ if ( image.ColorSpace == NULL )
+ image.ColorSpace = gs_color_space_DeviceGray();
+ pie->num_components =
+ gs_color_space_num_components(image.ColorSpace);
+#ifdef DPNEXT
+ if ( pim->HasAlpha )
+ pie->num_components++;
+#endif
+ if ( multi )
+ pie->num_planes = pie->num_components;
+ else
+ { pie->num_planes = 1;
+ samples_per_row *= pie->num_components;
+ }
+ }
+ if ( image.ImageMask | image.CombineWithColor )
+ gx_set_dev_color(pgs);
+ if ( !pie->skip )
+ { code = (*dev_proc(dev, begin_image))
+ (dev, (const gs_imager_state *)pgs, &image,
+ (multi ? gs_image_format_component_planar : gs_image_format_chunky),
+ NULL, pgs->dev_color, pgs->clip_path, pie->memory, &pie->info);
+ if ( code < 0 )
+ return code;
+ }
+ pie->dev = dev;
+ pie->multi = multi;
+ pie->bpp =
+ image.BitsPerComponent * pie->num_components / pie->num_planes;
+ pie->width = image.Width;
+ pie->height = image.Height;
+ pie->raster = (samples_per_row * image.BitsPerComponent + 7) >> 3;
+ /* Initialize the dynamic part of the state. */
+ pie->plane_index = 0;
+ pie->y = 0;
+ pie->pos = 0;
+ pie->error = false;
+ return 0;
+}
+
+/*
+ * Return the number of bytes of data per row
+ * (per plane, if MultipleDataSources is true).
+ */
+uint
+gs_image_bytes_per_row(const gs_image_enum *pie)
+{ return pie->raster;
+}
+
+/* Process the next piece of an image. */
+private int
+copy_planes(gx_device *dev, gs_image_enum *pie, const byte **planes, int h)
+{ int code =
+ (pie->skip ? (pie->y + h < pie->height ? 0 : 1) :
+ (*dev_proc(dev, image_data))(dev, pie->info, planes, 0,
+ pie->raster, h));
+
+ if ( code < 0 )
+ pie->error = true;
+ return code;
+}
+int
+gs_image_next(gs_image_enum *pie, const byte *dbytes, uint dsize,
+ uint *pused)
+{ gx_device *dev;
+ uint left;
+ int num_planes;
+ uint raster;
+ uint pos;
+ int code;
+
+ /*
+ * Handle the following differences between gs_image_next and
+ * the device image_data procedure:
+ *
+ * - image_data requires an array of planes; gs_image_next
+ * expects planes in successive calls.
+ *
+ * - image_data requires that each call pass entire rows;
+ * gs_image_next allows arbitrary amounts of data.
+ */
+ if ( pie->plane_index != 0 )
+ if ( dsize != pie->sources[0].size )
+ return_error(gs_error_rangecheck);
+ pie->sources[pie->plane_index].data = dbytes;
+ pie->sources[pie->plane_index].size = dsize;
+ if ( ++(pie->plane_index) != pie->num_planes )
+ return 0;
+ /* We have a full set of planes. */
+ dev = pie->dev;
+ left = dsize;
+ num_planes = pie->num_planes;
+ raster = pie->raster;
+ pos = pie->pos;
+ code = 0;
+ while ( left && pie->y < pie->height )
+ { const byte *planes[max_components];
+ int i;
+
+ for ( i = 0; i < num_planes; ++i )
+ planes[i] = pie->sources[i].data + dsize - left;
+ if ( pos == 0 && left >= raster )
+ { /* Pass (a) row(s) directly from the source. */
+ int h = left / raster;
+ if ( h > pie->height - pie->y )
+ h = pie->height - pie->y;
+ code = copy_planes(dev, pie, planes, h);
+ if ( code < 0 )
+ break;
+ left -= raster * h;
+ pie->y += h;
+ }
+ else
+ { /* Buffer a partial row. */
+ uint count = min(left, raster - pos);
+ if ( pie->rows[0].data == 0 )
+ { /* Allocate the row buffers. */
+ for ( i = 0; i < num_planes; ++i )
+ { byte *row = gs_alloc_string(pie->memory, raster,
+ "gs_image_next(row)");
+ if ( row == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ while ( --i >= 0 )
+ { gs_free_string(pie->memory, pie->rows[i].data,
+ raster, "gs_image_next(row)");
+ pie->rows[i].data = 0;
+ pie->rows[i].size = 0;
+ }
+ break;
+ }
+ pie->rows[i].data = row;
+ pie->rows[i].size = raster;
+ }
+ if ( code < 0 )
+ break;
+ }
+ for ( i = 0; i < num_planes; ++i )
+ memcpy(pie->rows[i].data + pos, planes[i], count);
+ pos += count;
+ left -= count;
+ if ( pos == raster )
+ { for ( i = 0; i < num_planes; ++i )
+ planes[i] = pie->rows[i].data;
+ code = copy_planes(dev, pie, planes, 1);
+ if ( code < 0 )
+ break;
+ pos = 0;
+ pie->y++;
+ }
+ }
+ }
+ pie->pos = pos;
+ pie->plane_index = 0;
+ *pused = dsize - left;
+ return code;
+}
+
+/* Clean up after processing an image. */
+void
+gs_image_cleanup(gs_image_enum *pie)
+{ gx_device *dev = pie->dev;
+ int i;
+
+ for ( i = 0; i < pie->num_planes; ++i )
+ gs_free_string(pie->memory, pie->rows[i].data,
+ pie->rows[i].size, "gs_image_cleanup(row)");
+ if ( !pie->skip )
+ (*dev_proc(dev, end_image))(dev, pie->info, !pie->error);
+ /* Don't free the local enumerator -- the client does that. */
+}
diff --git a/gs/src/gsimage.h b/gs/src/gsimage.h
new file mode 100644
index 000000000..8783167f2
--- /dev/null
+++ b/gs/src/gsimage.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsimage.h */
+/* Client interface to image painting */
+/* Requires gsstate.h */
+#include "gsiparam.h"
+
+/*
+ * The image painting interface uses an enumeration style:
+ * the client initializes an enumerator, then supplies data incrementally.
+ */
+typedef struct gs_image_enum_s gs_image_enum;
+gs_image_enum *gs_image_enum_alloc(P2(gs_memory_t *, client_name_t));
+/*
+ * image_init returns 1 for an empty image, 0 normally, <0 on error.
+ * Note that image_init serves for both image and imagemask,
+ * depending on the value of ImageMask in the image structure.
+ */
+int gs_image_init(P4(gs_image_enum *penum, const gs_image_t *pim,
+ bool MultipleDataSources, gs_state *pgs));
+int gs_image_next(P4(gs_image_enum *penum, const byte *dbytes,
+ uint dsize, uint *pused));
+/*
+ * Return the number of bytes of data per row
+ * (per plane, if MultipleDataSources is true).
+ */
+uint gs_image_bytes_per_row(P1(const gs_image_enum *penum));
+/* Clean up after processing an image. */
+void gs_image_cleanup(P1(gs_image_enum *penum));
diff --git a/gs/src/gsimpath.c b/gs/src/gsimpath.c
new file mode 100644
index 000000000..e415c30fc
--- /dev/null
+++ b/gs/src/gsimpath.c
@@ -0,0 +1,183 @@
+/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsimpath.c */
+/* Image to outline conversion for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gspath.h"
+
+/* Define the state of the conversion process. */
+typedef struct {
+ /* The following are set at the beginning of the conversion. */
+ gs_state *pgs;
+ const byte *data; /* image data */
+ int width, height, raster;
+ /* The following are updated dynamically. */
+ int dx, dy; /* X/Y increment of current run */
+ int count; /* # of steps in current run */
+} status;
+
+/* Define the scaling for the path tracer. */
+/* It must be even. */
+#define outline_scale 4
+/* Define the length of the short strokes for turning corners. */
+#define step 1
+
+/* Forward declarations */
+private int near get_pixel(P3(const status *, int, int));
+private int near trace_from(P4(status *, int, int, int));
+private int near add_dxdy(P4(status *, int, int, int));
+#define add_deltas(s, dx, dy, n)\
+ if ( (code = add_dxdy(s, dx, dy, n)) < 0 ) return code
+/* Append an outline derived from an image to the current path. */
+int
+gs_imagepath(gs_state *pgs, int width, int height, const byte *data)
+{ status stat;
+ status *out = &stat;
+ int code, x, y;
+ /* Initialize the state. */
+ stat.pgs = pgs;
+ stat.data = data;
+ stat.width = width;
+ stat.height = height;
+ stat.raster = (width + 7) / 8;
+ /* Trace the cells to form an outline. The trace goes in clockwise */
+ /* order, always starting by going west along a bottom edge. */
+ for ( y = height - 1; y >= 0; y-- )
+ for ( x = width - 1; x >= 0; x-- )
+ { if ( get_pixel(out, x, y) && !get_pixel(out, x, y - 1) &&
+ (!get_pixel(out, x + 1, y) || get_pixel(out, x + 1, y - 1)) &&
+ !trace_from(out, x, y, 1)
+ )
+ { /* Found a starting point */
+ stat.count = 0;
+ stat.dx = stat.dy = 0;
+ if ( (code = trace_from(out, x, y, 0)) < 0 )
+ return code;
+ add_deltas(out, 0, 0, 1); /* force out last segment */
+ if ( (code = gs_closepath(pgs)) < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Get a pixel from the data. Return 0 if outside the image. */
+private int near
+get_pixel(register const status *out, int x, int y)
+{ if ( x < 0 || x >= out->width || y < 0 || y >= out->height )
+ return 0;
+ return (out->data[y * out->raster + (x >> 3)] >> (~x & 7)) & 1;
+}
+
+/* Trace a path. If detect is true, don't draw, just return 1 if we ever */
+/* encounter a starting point whose x,y follows that of the initial point */
+/* in x-then-y scan order; if detect is false, actually draw the outline. */
+private int near
+trace_from(register status *out, int x0, int y0, int detect)
+{ int x = x0, y = y0;
+ int dx = -1, dy = 0; /* initially going west */
+ int part = 0; /* how far along edge we are; */
+ /* initialized only to pacify gcc */
+ int code;
+ if ( !detect )
+ { part = (get_pixel(out, x + 1, y - 1) ?
+ outline_scale - step : step);
+ code = gs_moveto(out->pgs,
+ x + 1 - part / (float)outline_scale,
+ (float)y);
+ if ( code < 0 ) return code;
+ }
+ while ( 1 )
+ { /* Relative to the current direction, */
+ /* -dy,dx is at +90 degrees (counter-clockwise); */
+ /* tx,ty is at +45 degrees; */
+ /* ty,-tx is at -45 degrees (clockwise); */
+ /* dy,-dx is at -90 degrees. */
+ int tx = dx - dy, ty = dy + dx;
+ if ( get_pixel(out, x + tx, y + ty) )
+ { /* Cell at 45 degrees is full, */
+ /* go counter-clockwise. */
+ if ( !detect )
+ { /* If this is a 90 degree corner set at a */
+ /* 45 degree angle, avoid backtracking. */
+ if ( out->dx == ty && out->dy == -tx )
+ {
+#define half_scale (outline_scale / 2 - step)
+ out->count -= half_scale;
+ add_deltas(out, tx, ty, outline_scale / 2);
+#undef half_scale
+ }
+ else
+ { add_deltas(out, dx, dy, step - part);
+ add_deltas(out, tx, ty, outline_scale - step);
+ }
+ part = outline_scale - step;
+ }
+ x += tx, y += ty;
+ dx = -dy, dy += tx;
+ }
+ else if ( !get_pixel(out, x + dx, y + dy) )
+ { /* Cell straight ahead is empty, go clockwise. */
+ if ( !detect )
+ { add_deltas(out, dx, dy, outline_scale - step - part);
+ add_deltas(out, ty, -tx, step);
+ part = step;
+ }
+ dx = dy, dy -= ty;
+ }
+ else
+ { /* Neither of the above, go in same direction. */
+ if ( !detect )
+ { add_deltas(out, dx, dy, outline_scale);
+ }
+ x += dx, y += dy;
+ }
+ if ( dx == -step && dy == 0 && !(tx == -step && ty == -step) )
+ { /* We just turned a corner and are going west, */
+ /* so the previous pixel is a starting point pixel. */
+ if ( x == x0 && y == y0 ) return 0;
+ if ( detect && (y > y0 || (y == y0 && x > x0)) )
+ return 1;
+ }
+ }
+}
+
+/* Add a (dx, dy) pair to the path being formed. */
+/* Accumulate successive segments in the same direction. */
+private int near
+add_dxdy(register status *out, int dx, int dy, int count)
+{ if ( count != 0 )
+ { if ( dx == out->dx && dy == out->dy )
+ out->count += count;
+ else
+ { if ( out->count != 0 )
+ { int code = gs_rlineto(out->pgs,
+ out->dx * out->count / (float)outline_scale,
+ out->dy * out->count / (float)outline_scale);
+ if ( code < 0 ) return code;
+ }
+ out->dx = dx, out->dy = dy;
+ out->count = count;
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gsinit.c b/gs/src/gsinit.c
new file mode 100644
index 000000000..b245a2fe4
--- /dev/null
+++ b/gs/src/gsinit.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsinit.c */
+/* Initialization for the imager */
+#include "stdio_.h"
+#include "memory_.h"
+#include "gdebug.h"
+#include "gscdefs.h"
+#include "gsmemory.h"
+#include "gp.h"
+#include "gslib.h" /* interface definition */
+
+/* Imported from gsmisc.c */
+extern FILE *gs_debug_out;
+
+/* Imported from gsmemory.c */
+void gs_malloc_init(P0());
+void gs_malloc_release(P0());
+
+/* Configuration information from gconfig.c. */
+extern_gx_init_table();
+
+/* Initialization to be done before anything else. */
+void
+gs_lib_init(FILE *debug_out)
+{ gs_lib_init0(debug_out);
+ gs_lib_init1(&gs_memory_default);
+}
+void
+gs_lib_init0(FILE *debug_out)
+{ gs_debug_out = debug_out;
+ gs_malloc_init();
+ /* Reset debugging flags */
+ memset(gs_debug, 0, 128);
+ gs_log_errors = 0;
+}
+void
+gs_lib_init1(gs_memory_t *mem)
+{ /* Run configuration-specific initialization procedures. */
+ { void (**ipp)(P1(gs_memory_t *));
+ for ( ipp = gx_init_table; *ipp != 0; ++ipp )
+ (**ipp)(mem);
+ }
+}
+
+/* Clean up after execution. */
+void
+gs_lib_finit(int exit_status, int code)
+{ fflush(stderr); /* in case of error exit */
+ /* Do platform-specific cleanup. */
+ gp_exit(exit_status, code);
+ gs_malloc_release();
+}
diff --git a/gs/src/gsio.h b/gs/src/gsio.h
new file mode 100644
index 000000000..fc3ad77d2
--- /dev/null
+++ b/gs/src/gsio.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 1989, 1990, 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsio.h */
+/* stdio redirection */
+
+#ifndef gsio_INCLUDED
+# define gsio_INCLUDED
+
+/* The library and interpreter never use stdin/out/err directly. */
+extern FILE *gs_stdin, *gs_stdout, *gs_stderr;
+
+/* Redefine all the relevant stdio functions to use the above. */
+/* Some functions we make illegal, rather than redefining them. */
+#undef stdin
+#define stdin gs_stdin
+#undef stdout
+#define stdout gs_stdout
+#undef stderr
+#define stderr gs_stderr
+#undef fgetchar
+#define fgetchar() fgetc(stdin)
+#undef fputchar
+#define fputchar(c) fputc(c, stdout)
+#undef getchar
+#define getchar() getc(stdin)
+#undef gets
+#define gets Function._gets_.unavailable
+/* We should do something about perror, but since many Unix systems */
+/* don't provide the strerror function, we can't. (No Aladdin-maintained */
+/* code uses perror.) */
+#undef printf
+#define printf Function._printf_.unavailable
+#undef putchar
+#define putchar(c) fputc(c, stdout)
+#undef puts
+#define puts(s) (fputs(s, stdout), putchar('\n'))
+#undef scanf
+#define scanf Function._scanf_.unavailable
+#undef vprintf
+#define vprintf Function._vprintf_.unavailable
+#undef vscanf
+#define vscanf Function._vscanf_.unavailable
+
+#endif /* gsio_INCLUDED */
diff --git a/gs/src/gsiodev.c b/gs/src/gsiodev.c
new file mode 100644
index 000000000..c82a4412c
--- /dev/null
+++ b/gs/src/gsiodev.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsiodev.c */
+/* IODevice implementation for Ghostscript */
+#include "errno_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gp.h"
+#include "gsparam.h"
+#include "gxiodev.h"
+
+/* Import the IODevice table from gconfig.c. */
+extern gx_io_device *gx_io_device_table[];
+extern uint gx_io_device_table_count;
+
+/* Define the OS (%os%) device. */
+iodev_proc_fopen(iodev_os_fopen);
+iodev_proc_fclose(iodev_os_fclose);
+private iodev_proc_delete_file(os_delete);
+private iodev_proc_rename_file(os_rename);
+private iodev_proc_file_status(os_status);
+private iodev_proc_enumerate_files(os_enumerate);
+private iodev_proc_get_params(os_get_params);
+gx_io_device gs_iodev_os = {
+ "%os%", "FileSystem",
+ { iodev_no_init, iodev_no_open_device,
+ NULL /*iodev_os_open_file*/, iodev_os_fopen, iodev_os_fclose,
+ os_delete, os_rename, os_status,
+ os_enumerate, gp_enumerate_files_next, gp_enumerate_files_close,
+ os_get_params, iodev_no_put_params
+ }
+};
+
+/* ------ Initialization ------ */
+
+void
+gs_iodev_init(gs_memory_t *mem)
+{ /* Run the one-time initialization of each IODevice. */
+ gx_io_device **piodev = &gx_io_device_table[0];
+ for ( ; *piodev; piodev++ )
+ ((*piodev)->procs.init)(*piodev, mem);
+}
+
+/* ------ Default (unimplemented) IODevice procedures ------ */
+
+int
+iodev_no_init(gx_io_device *iodev, gs_memory_t *mem)
+{ return 0;
+}
+
+int
+iodev_no_open_device(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_open_file(gx_io_device *iodev, const char *fname, uint namelen,
+ const char *access, stream **ps, gs_memory_t *mem)
+{ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_fopen(gx_io_device *iodev, const char *fname, const char *access,
+ FILE **pfile, char *rfname, uint rnamelen)
+{ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_fclose(gx_io_device *iodev, FILE *file)
+{ return_error(gs_error_ioerror);
+}
+
+int
+iodev_no_delete_file(gx_io_device *iodev, const char *fname)
+{ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_rename_file(gx_io_device *iodev, const char *from, const char *to)
+{ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_file_status(gx_io_device *iodev, const char *fname, struct stat *pstat)
+{ return_error(gs_error_undefinedfilename);
+}
+
+file_enum *
+iodev_no_enumerate_files(gx_io_device *iodev, const char *pat, uint patlen,
+ gs_memory_t *memory)
+{ return NULL;
+}
+
+int
+iodev_no_get_params(gx_io_device *iodev, gs_param_list *plist)
+{ return 0;
+}
+
+int
+iodev_no_put_params(gx_io_device *iodev, gs_param_list *plist)
+{ return param_commit(plist);
+}
+
+/* ------ %os% ------ */
+
+/* The fopen routine is exported for %null. */
+int
+iodev_os_fopen(gx_io_device *iodev, const char *fname, const char *access,
+ FILE **pfile, char *rfname, uint rnamelen)
+{ errno = 0;
+ *pfile = gp_fopen(fname, access);
+ if ( *pfile == NULL )
+ return_error(gs_fopen_errno_to_code(errno));
+ if ( rfname != NULL )
+ strcpy(rfname, fname);
+ return 0;
+}
+
+/* The fclose routine is exported for %null. */
+int
+iodev_os_fclose(gx_io_device *iodev, FILE *file)
+{ fclose(file);
+ return 0;
+}
+
+private int
+os_delete(gx_io_device *iodev, const char *fname)
+{ return (unlink(fname) == 0 ? 0 : gs_error_ioerror);
+}
+
+private int
+os_rename(gx_io_device *iodev, const char *from, const char *to)
+{ return (rename(from, to) == 0 ? 0 : gs_error_ioerror);
+}
+
+private int
+os_status(gx_io_device *iodev, const char *fname, struct stat *pstat)
+{ /* The RS/6000 prototype for stat doesn't include const, */
+ /* so we have to explicitly remove the const modifier. */
+ return (stat((char *)fname, pstat) < 0 ? gs_error_undefinedfilename : 0);
+}
+
+private file_enum *
+os_enumerate(gx_io_device *iodev, const char *pat, uint patlen,
+ gs_memory_t *mem)
+{ return gp_enumerate_files_init(pat, patlen, mem);
+}
+
+private int
+os_get_params(gx_io_device *iodev, gs_param_list *plist)
+{ /* We aren't going to implement *all* of the Adobe parameters.... */
+ int code;
+ bool btrue = true;
+
+ if ( (code = param_write_bool(plist, "HasNames", &btrue)) < 0 )
+ return code;
+ return 0;
+}
+
+/* ------ Utilities ------ */
+
+/* Get the N'th IODevice from the known device table. */
+gx_io_device *
+gs_getiodevice(int index)
+{ if ( index < 0 || index >= gx_io_device_table_count )
+ return 0; /* index out of range */
+ return gx_io_device_table[index];
+}
+
+/* Look up an IODevice name. */
+/* The name may be either %device or %device%. */
+gx_io_device *
+gs_findiodevice(const byte *str, uint len)
+{ gx_io_device **pftab;
+ if ( len > 1 && str[len - 1] == '%' )
+ len--;
+ for ( pftab = gx_io_device_table; *pftab != NULL; pftab++ )
+ { const char *dname = (*pftab)->dname;
+ if ( strlen(dname) == len + 1 && !memcmp(str, dname, len) )
+ return *pftab;
+ }
+ return 0;
+}
+
+/* ------ Accessors ------ */
+
+/* Get IODevice parameters. */
+int
+gs_getdevparams(gx_io_device *iodev, gs_param_list *plist)
+{ /* All IODevices have the Type parameter. */
+ gs_param_string ts;
+ int code;
+
+ param_string_from_string(ts, iodev->dtype);
+ code = param_write_name(plist, "Type", &ts);
+ if ( code < 0 )
+ return code;
+ return (*iodev->procs.get_params)(iodev, plist);
+}
+
+/* Put IODevice parameters. */
+int
+gs_putdevparams(gx_io_device *iodev, gs_param_list *plist)
+{ return (*iodev->procs.put_params)(iodev, plist);
+}
+
+/* Convert an OS error number to a PostScript error */
+/* if opening a file fails. */
+int
+gs_fopen_errno_to_code(int eno)
+{ /* Different OSs vary widely in their error codes. */
+ /* We try to cover as many variations as we know about. */
+ switch ( eno )
+ {
+#ifdef ENOENT
+ case ENOENT:
+ return_error(gs_error_undefinedfilename);
+#endif
+#ifdef ENOFILE
+# ifndef ENOENT
+# define ENOENT ENOFILE
+# endif
+# if ENOFILE != ENOENT
+ case ENOFILE:
+ return_error(gs_error_undefinedfilename);
+# endif
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG:
+ return_error(gs_error_undefinedfilename);
+#endif
+#ifdef EACCES
+ case EACCES:
+ return_error(gs_error_invalidfileaccess);
+#endif
+#ifdef EMFILE
+ case EMFILE:
+ return_error(gs_error_limitcheck);
+#endif
+#ifdef ENFILE
+ case ENFILE:
+ return_error(gs_error_limitcheck);
+#endif
+ default:
+ return_error(gs_error_ioerror);
+ }
+}
diff --git a/gs/src/gsiparam.h b/gs/src/gsiparam.h
new file mode 100644
index 000000000..7a0adfdfb
--- /dev/null
+++ b/gs/src/gsiparam.h
@@ -0,0 +1,167 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsiparam.h */
+/* Image parameter definition */
+/* Requires gsmatrix.h */
+
+#ifndef gsiparam_INCLUDED
+# define gsiparam_INCLUDED
+
+/* ---------------- Image parameters ---------------- */
+
+/* Define an opaque type for a color space. */
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+#endif
+
+/*
+ * Define the structure for specifying image data. It follows closely
+ * the discussion on pp. 219-223 of the PostScript Language Reference Manual,
+ * Second Edition, with the following exceptions:
+ *
+ * ColorSpace and ImageMask are added members from PDF.
+ *
+ * DataSource and MultipleDataSources are not members of this
+ * structure, but are arguments of gs_image_init.
+ *
+ * adjust, CombineWithColor, and HasAlpha are not PostScript or
+ * PDF standard (see the RasterOp section of language.doc for a
+ * discussion of CombineWithColor).
+ */
+typedef enum {
+ /* Single plane, chunky pixels. */
+ gs_image_format_chunky = 0,
+ /* num_components planes, chunky components. */
+ gs_image_format_component_planar = 1,
+ /* BitsPerComponent * num_components planes, 1 bit per plane */
+ /****** NOT SUPPORTED YET, DO NOT USE ******/
+ gs_image_format_bit_planar = 2
+} gs_image_format_t;
+
+typedef struct gs_image_s {
+ /*
+ * Define the width of source image in pixels.
+ */
+ int Width;
+ /*
+ * Define the height of source image in pixels.
+ */
+ int Height;
+ /*
+ * Define the transformation from user space to image space.
+ */
+ gs_matrix ImageMatrix;
+ /*
+ * Define B, the number of bits per pixel component.
+ * Currently this must be 1 for masks.
+ */
+ int BitsPerComponent;
+ /*
+ * Define the source color space (must be NULL for masks).
+ */
+ const gs_color_space *ColorSpace;
+ /*
+ * Define the linear remapping of the input values.
+ * For the I'th pixel component, we start by treating
+ * the B bits of component data as a fraction F between
+ * 0 and 1; the actual component value is then
+ * Decode[I*2] + F * (Decode[I*2+1] - Decode[I*2]).
+ * For masks, only the first two entries are used;
+ * they must be 1,0 for write-0s masks, 0,1 for write-1s.
+ */
+#ifdef DPNEXT
+ float Decode[10]; /* 4 colors + alpha */
+#else
+ float Decode[8];
+#endif
+ /*
+ * Define whether to smooth the image.
+ */
+ bool Interpolate;
+ /*
+ * Define whether this is a mask or a solid image.
+ */
+ bool ImageMask;
+ /***
+ *** The following are not PostScript standard.
+ ***/
+ /*
+ * Define whether to expand each destination pixel, to make
+ * masked characters look better (only used for masks).
+ */
+ bool adjust;
+ /*
+ * Define whether to use the drawing color as the
+ * "texture" for RasterOp. For more information,
+ * see the discussion of RasterOp in language.doc.
+ */
+ bool CombineWithColor;
+#ifdef DPNEXT
+ /*
+ * Define whether there is an additional component providing
+ * alpha information for each pixel, in addition to (and
+ * following) the components implied by the color space.
+ * For masks, HasAlpha must be false.
+ */
+ bool HasAlpha;
+#endif
+} gs_image_t;
+
+/*
+ * Define procedures for initializing a gs_image_t to default values.
+ * For masks, write_1s = false paints 0s, write_1s = true paints 1s.
+ * This is consistent with the "polarity" operand of the PostScript
+ * imagemask operator.
+ *
+ * Note that because gs_image_t may add more members in the future, all
+ * clients constructing gs_image_t values *must* start by initializing
+ * the value by calling one of the following procedures.
+ */
+void
+ gs_image_t_init_gray(P1(gs_image_t *pim)),
+ gs_image_t_init_color(P1(gs_image_t *pim)),/* general color, initially RGB */
+ gs_image_t_init_mask(P2(gs_image_t *pim, bool write_1s));
+
+/****** REMAINDER OF FILE UNDER CONSTRUCTION. PROCEED AT YOUR OWN RISK. ******/
+
+#if 0
+
+/* ---------------- Services ---------------- */
+
+/*
+In order to make the driver's life easier, we provide the following callback
+procedure:
+*/
+
+int gx_map_image_color(P5(gx_device *dev,
+ const gs_image_t *pim,
+ const gx_color_rendering_info *pcri,
+ const uint components[4],
+ gx_drawing_color *pdcolor));
+
+/*
+Map a source color to a drawing color. The components are simply the pixel
+component values from the input data, i.e., 1 to 4 B-bit numbers from the
+source data. Return 0 if the operation succeeded, or a negative error code.
+*/
+
+#endif /****************************************************************/
+
+#endif /* gsiparam_INCLUDED */
diff --git a/gs/src/gsjconf.h b/gs/src/gsjconf.h
new file mode 100644
index 000000000..49cb99c9c
--- /dev/null
+++ b/gs/src/gsjconf.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsjconf.h */
+/* jconfig.h file for Independent JPEG Group code */
+#include "std.h"
+
+/* See IJG's jconfig.doc for the contents of this file. */
+
+#ifdef __PROTOTYPES__
+# define HAVE_PROTOTYPES
+#endif
+
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+#undef CHAR_IS_UNSIGNED
+
+#ifdef __STDC__ /* is this right? */
+# define HAVE_STDDEF_H
+# define HAVE_STDLIB_H
+#endif
+
+#undef NEED_BSD_STRINGS /* WRONG */
+#undef NEED_SYS_TYPES_H /* WRONG */
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* The following is documented in jmemsys.h, not jconfig.doc. */
+#if arch_ints_are_short
+# undef MAX_ALLOC_CHUNK
+# define MAX_ALLOC_CHUNK 0xfff0
+#endif
+
+#ifdef JPEG_INTERNALS
+
+#if arch_arith_rshift == 0
+# define RIGHT_SHIFT_IS_UNSIGNED
+#else
+# undef RIGHT_SHIFT_IS_UNSIGNED
+#endif
+
+#endif /* JPEG_INTERNALS */
diff --git a/gs/src/gsjerror.c b/gs/src/gsjerror.c
new file mode 100644
index 000000000..228e4f76d
--- /dev/null
+++ b/gs/src/gsjerror.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* "wrapper" for IJG jerror.c */
+#include "stdpre.h"
+#include "jversion.h"
+#define JMAKE_MSG_STRINGS
+#include "jerror.h"
+#undef JMAKE_MSG_STRINGS
+#undef JCOPYRIGHT
+#undef JVERSION
+#include "jerrorig.c"
diff --git a/gs/src/gsjerror.h b/gs/src/gsjerror.h
new file mode 100644
index 000000000..9605b0b4f
--- /dev/null
+++ b/gs/src/gsjerror.h
@@ -0,0 +1,383 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too. Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+
+/* To define the enum list of message codes, include this file without
+ * defining JMAKE_MSG_TABLE. To create the message string table, include it
+ * again with JMAKE_MSG_STRINGS defined, and then yet again with
+ * JMAKE_MSG_TABLE defined (this should be done in just one module).
+ */
+
+#ifdef JMAKE_MSG_TABLE
+
+/*
+ * The following doesn't work, because jpeg_message_table is also
+ * the name a member of the jpeg_error_mgr structure.
+ */
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_message_table jMsgTable
+#endif
+
+const char far_data * const far_data jpeg_message_table[] = {
+
+#define JMESSAGE(code,strvar,string) strvar ,
+
+#else /* not JMAKE_MSG_TABLE */
+
+#ifdef JMAKE_MSG_STRINGS
+
+#define JMESSAGE(code,strvar,string) const char far_data strvar[] = string;
+
+#else /* not JMAKE_MSG_STRINGS, not JMAKE_MSG_TABLE */
+
+typedef enum {
+
+#define JMESSAGE(code,strvar,string) code ,
+
+#endif /* JMAKE_MSG_STRINGS */
+
+#endif /* JMAKE_MSG_TABLE */
+
+JMESSAGE(JMSG_NOMESSAGE, str_JMSG_NOMESSAGE,
+ "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_ARITH_NOTIMPL, str_JERR_ARITH_NOTIMPL,
+ "Sorry, there are legal restrictions on arithmetic coding")
+JMESSAGE(JERR_BAD_ALIGN_TYPE, str_JERR_BAD_ALIGN_TYPE,
+ "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, str_JERR_BAD_ALLOC_CHUNK,
+ "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, str_JERR_BAD_BUFFER_MODE,
+ "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, str_JERR_BAD_COMPONENT_ID,
+ "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_DCTSIZE, str_JERR_BAD_DCTSIZE,
+ "IDCT output block size %d not supported")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, str_JERR_BAD_IN_COLORSPACE,
+ "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, str_JERR_BAD_J_COLORSPACE,
+ "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, str_JERR_BAD_LENGTH,
+ "Bogus marker length")
+JMESSAGE(JERR_BAD_MCU_SIZE, str_JERR_BAD_MCU_SIZE,
+ "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, str_JERR_BAD_POOL_ID,
+ "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, str_JERR_BAD_PRECISION,
+ "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_SAMPLING, str_JERR_BAD_SAMPLING,
+ "Bogus sampling factors")
+JMESSAGE(JERR_BAD_STATE, str_JERR_BAD_STATE,
+ "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, str_JERR_BAD_VIRTUAL_ACCESS,
+ "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, str_JERR_BUFFER_SIZE,
+ "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, str_JERR_CANT_SUSPEND,
+ "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, str_JERR_CCIR601_NOTIMPL,
+ "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, str_JERR_COMPONENT_COUNT,
+ "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, str_JERR_CONVERSION_NOTIMPL,
+ "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, str_JERR_DAC_INDEX,
+ "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, str_JERR_DAC_VALUE,
+ "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_COUNTS, str_JERR_DHT_COUNTS,
+ "Bogus DHT counts")
+JMESSAGE(JERR_DHT_INDEX, str_JERR_DHT_INDEX,
+ "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, str_JERR_DQT_INDEX,
+ "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, str_JERR_EMPTY_IMAGE,
+ "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, str_JERR_EMS_READ,
+ "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, str_JERR_EMS_WRITE,
+ "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, str_JERR_EOI_EXPECTED,
+ "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, str_JERR_FILE_READ,
+ "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, str_JERR_FILE_WRITE,
+ "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, str_JERR_FRACT_SAMPLE_NOTIMPL,
+ "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, str_JERR_HUFF_CLEN_OVERFLOW,
+ "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, str_JERR_HUFF_MISSING_CODE,
+ "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, str_JERR_IMAGE_TOO_BIG,
+ "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, str_JERR_INPUT_EMPTY,
+ "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, str_JERR_INPUT_EOF,
+ "Premature end of input file")
+JMESSAGE(JERR_JFIF_MAJOR, str_JERR_JFIF_MAJOR,
+ "Unsupported JFIF revision number %d.%02d")
+JMESSAGE(JERR_NOTIMPL, str_JERR_NOTIMPL,
+ "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, str_JERR_NOT_COMPILED,
+ "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_BACKING_STORE, str_JERR_NO_BACKING_STORE,
+ "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, str_JERR_NO_HUFF_TABLE,
+ "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, str_JERR_NO_IMAGE,
+ "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, str_JERR_NO_QUANT_TABLE,
+ "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, str_JERR_NO_SOI,
+ "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, str_JERR_OUT_OF_MEMORY,
+ "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS, str_JERR_QUANT_COMPONENTS,
+ "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, str_JERR_QUANT_FEW_COLORS,
+ "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, str_JERR_QUANT_MANY_COLORS,
+ "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_DUPLICATE, str_JERR_SOF_DUPLICATE,
+ "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, str_JERR_SOF_NO_SOS,
+ "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, str_JERR_SOF_UNSUPPORTED,
+ "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, str_JERR_SOI_DUPLICATE,
+ "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_SOS_NO_SOF, str_JERR_SOS_NO_SOF,
+ "Invalid JPEG file structure: SOS before SOF")
+JMESSAGE(JERR_TFILE_CREATE, str_JERR_TFILE_CREATE,
+ "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, str_JERR_TFILE_READ,
+ "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, str_JERR_TFILE_SEEK,
+ "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE, str_JERR_TFILE_WRITE,
+ "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, str_JERR_TOO_LITTLE_DATA,
+ "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, str_JERR_UNKNOWN_MARKER,
+ "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, str_JERR_VIRTUAL_BUG,
+ "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, str_JERR_WIDTH_OVERFLOW,
+ "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, str_JERR_XMS_READ,
+ "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, str_JERR_XMS_WRITE,
+ "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, str_JMSG_COPYRIGHT,
+ JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, str_JMSG_VERSION,
+ JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES, str_JTRC_16BIT_TABLES,
+ "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE, str_JTRC_ADOBE,
+ "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, str_JTRC_APP0,
+ "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, str_JTRC_APP14,
+ "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, str_JTRC_DAC,
+ "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, str_JTRC_DHT,
+ "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, str_JTRC_DQT,
+ "Define Quantization Table %d precision %d")
+JMESSAGE(JTRC_DRI, str_JTRC_DRI,
+ "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, str_JTRC_EMS_CLOSE,
+ "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, str_JTRC_EMS_OPEN,
+ "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, str_JTRC_EOI,
+ "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, str_JTRC_HUFFBITS,
+ " %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, str_JTRC_JFIF,
+ "JFIF APP0 marker, density %dx%d %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, str_JTRC_JFIF_BADTHUMBNAILSIZE,
+ "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_MINOR, str_JTRC_JFIF_MINOR,
+ "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, str_JTRC_JFIF_THUMBNAIL,
+ " with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, str_JTRC_MISC_MARKER,
+ "Skipping marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, str_JTRC_PARMLESS_MARKER,
+ "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, str_JTRC_QUANTVALS,
+ " %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, str_JTRC_QUANT_3_NCOLORS,
+ "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, str_JTRC_QUANT_NCOLORS,
+ "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, str_JTRC_QUANT_SELECTED,
+ "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, str_JTRC_RECOVERY_ACTION,
+ "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, str_JTRC_RST,
+ "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL, str_JTRC_SMOOTH_NOTIMPL,
+ "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, str_JTRC_SOF,
+ "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, str_JTRC_SOF_COMPONENT,
+ " Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, str_JTRC_SOI,
+ "Start of Image")
+JMESSAGE(JTRC_SOS, str_JTRC_SOS,
+ "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, str_JTRC_SOS_COMPONENT,
+ " Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, str_JTRC_TFILE_CLOSE,
+ "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, str_JTRC_TFILE_OPEN,
+ "Opened temporary file %s")
+JMESSAGE(JTRC_UNKNOWN_IDS, str_JTRC_UNKNOWN_IDS,
+ "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, str_JTRC_XMS_CLOSE,
+ "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, str_JTRC_XMS_OPEN,
+ "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, str_JWRN_ADOBE_XFORM,
+ "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA, str_JWRN_EXTRANEOUS_DATA,
+ "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, str_JWRN_HIT_MARKER,
+ "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, str_JWRN_HUFF_BAD_CODE,
+ "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JPEG_EOF, str_JWRN_JPEG_EOF,
+ "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC, str_JWRN_MUST_RESYNC,
+ "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, str_JWRN_NOT_SEQUENTIAL,
+ "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, str_JWRN_TOO_MUCH_DATA,
+ "Application transferred too many scanlines")
+
+#ifdef JMAKE_MSG_TABLE
+
+ NULL
+};
+
+#else /* not JMAKE_MSG_TABLE */
+
+#ifndef JMAKE_MSG_STRINGS
+
+ JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#endif /* JMAKE_MSG_STRINGS */
+
+#endif /* JMAKE_MSG_TABLE */
+
+#undef JMESSAGE
+
+
+#ifndef JMAKE_MSG_TABLE
+#ifndef JMAKE_MSG_STRINGS
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JMAKE_MSG_STRINGS */
+#endif /* JMAKE_MSG_TABLE */
diff --git a/gs/src/gsjmorec.h b/gs/src/gsjmorec.h
new file mode 100644
index 000000000..c7b336698
--- /dev/null
+++ b/gs/src/gsjmorec.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsjmorec.h */
+/* "Wrapper" for Independent JPEG Group code jmorecfg.h */
+
+#include "jmcorig.h"
+
+/* Remove unwanted / unneeded features. */
+#undef DCT_IFAST_SUPPORTED
+#undef DCT_FLOAT_SUPPORTED
+/*
+ * Note: on machines with fast floating point, it might make more sense
+ * to use the float DCT?
+ */
+#undef C_MULTISCAN_FILES_SUPPORTED
+#undef C_PROGRESSIVE_SUPPORTED
+#undef ENTROPY_OPT_SUPPORTED
+#undef INPUT_SMOOTHING_SUPPORTED
+
+/****** Comment out the next two lines to add progressive decoding. ******/
+#undef D_MULTISCAN_FILES_SUPPORTED
+#undef D_PROGRESSIVE_SUPPORTED
+
+#undef BLOCK_SMOOTHING_SUPPORTED
+#undef IDCT_SCALING_SUPPORTED
+#undef UPSAMPLE_SCALING_SUPPORTED
+#undef UPSAMPLE_MERGING_SUPPORTED
+#undef QUANT_1PASS_SUPPORTED
+#undef QUANT_2PASS_SUPPORTED
+/*
+ * Read "JPEG" files with up to 64 blocks/MCU for Adobe compatibility.
+ * Note that this #define will have no effect in pre-v6 IJG versions.
+ */
+#define D_MAX_BLOCKS_IN_MCU 64
diff --git a/gs/src/gsjpglib.h b/gs/src/gsjpglib.h
new file mode 100644
index 000000000..a1875e99d
--- /dev/null
+++ b/gs/src/gsjpglib.h
@@ -0,0 +1,938 @@
+/*
+ * jpeglib.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ * Modified by L. Peter Deutsch 4-4-1995 for use with Ghostscript.
+ * (Edits marked with 'lpd' below.)
+ *
+ * This file defines the application interface for the JPEG library.
+ * Most applications using the library need only include this file,
+ * and perhaps jerror.h if they want to know the exact error codes.
+ */
+
+#ifndef JPEGLIB_H
+#define JPEGLIB_H
+
+/*
+ * First we include the configuration files that record how this
+ * installation of the JPEG library is set up. jconfig.h can be
+ * generated automatically for many systems. jmorecfg.h contains
+ * manual configuration options that most people need not worry about.
+ */
+
+#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
+#include "jconfig.h" /* widely used configuration options */
+#endif
+#include "jmorecfg.h" /* seldom changed options */
+
+
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+
+#define JPEG_LIB_VERSION 51 /* Version 5a */
+
+
+/* Various constants determining the sizes of things.
+ * All of these are specified by the JPEG standard, so don't change them
+ * if you want to be compatible.
+ */
+
+#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
+#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
+#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
+#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */
+#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */
+#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */
+#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */
+/* Following values changed by lpd for Adobe compatibility. */
+#define MAX_BLOCKS_IN_MCU 64 /* JPEG limit on # of blocks in an MCU */
+
+
+/* This macro is used to declare a "method", that is, a function pointer.
+ * We want to supply prototype parameters if the compiler can cope.
+ * Note that the arglist parameter must be parenthesized!
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JMETHOD(type,methodname,arglist) type (*methodname) arglist
+#else
+#define JMETHOD(type,methodname,arglist) type (*methodname) ()
+#endif
+
+
+/* Data structures for images (arrays of samples and of DCT coefficients).
+ * On 80x86 machines, the image arrays are too big for near pointers,
+ * but the pointer arrays can fit in near memory.
+ */
+
+typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */
+typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
+typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+
+typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
+typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */
+typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
+typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
+
+typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
+
+
+/* Types for JPEG compression parameters and working tables. */
+
+
+/* DCT coefficient quantization tables. */
+
+typedef struct {
+ /* This field directly represents the contents of a JPEG DQT marker.
+ * Note: the values are always given in zigzag order.
+ */
+ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JQUANT_TBL;
+
+
+/* Huffman coding tables. */
+
+typedef struct {
+ /* These two fields directly represent the contents of a JPEG DHT marker */
+ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */
+ /* length k bits; bits[0] is unused */
+ UINT8 huffval[256]; /* The symbols, in order of incr code length */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JHUFF_TBL;
+
+
+/* Basic info about one component (color channel). */
+
+typedef struct {
+ /* These values are fixed over the whole image. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOF marker. */
+ int component_id; /* identifier for this component (0..255) */
+ int component_index; /* its index in SOF or cinfo->comp_info[] */
+ int h_samp_factor; /* horizontal sampling factor (1..4) */
+ int v_samp_factor; /* vertical sampling factor (1..4) */
+ int quant_tbl_no; /* quantization table selector (0..3) */
+ /* These values may vary between scans. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOS marker. */
+ int dc_tbl_no; /* DC entropy table selector (0..3) */
+ int ac_tbl_no; /* AC entropy table selector (0..3) */
+
+ /* Remaining fields should be treated as private by applications. */
+
+ /* These values are computed during compression or decompression startup: */
+ /* Component's size in DCT blocks.
+ * Any dummy blocks added to complete an MCU are not counted; therefore
+ * these values do not depend on whether a scan is interleaved or not.
+ */
+ JDIMENSION width_in_blocks;
+ JDIMENSION height_in_blocks;
+ /* Size of a DCT block in samples. Always DCTSIZE for compression.
+ * For decompression this is the size of the output from one DCT block,
+ * reflecting any scaling we choose to apply during the IDCT step.
+ * Values of 1,2,4,8 are likely to be supported. Note that different
+ * components may receive different IDCT scalings.
+ */
+ int DCT_scaled_size;
+ /* The downsampled dimensions are the component's actual, unpadded number
+ * of samples at the main buffer (preprocessing/compression interface), thus
+ * downsampled_width = ceil(image_width * Hi/Hmax)
+ * and similarly for height. For decompression, IDCT scaling is included, so
+ * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
+ */
+ JDIMENSION downsampled_width; /* actual width in samples */
+ JDIMENSION downsampled_height; /* actual height in samples */
+ /* This flag is used only for decompression. In cases where some of the
+ * components will be ignored (eg grayscale output from YCbCr image),
+ * we can skip most computations for the unused components.
+ */
+ boolean component_needed; /* do we need the value of this component? */
+
+ /* These values are computed before starting a scan of the component: */
+ int MCU_width; /* number of blocks per MCU, horizontally */
+ int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_blocks; /* MCU_width * MCU_height */
+ int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */
+ int last_col_width; /* # of non-dummy blocks across in last MCU */
+ int last_row_height; /* # of non-dummy blocks down in last MCU */
+
+ /* Private per-component storage for DCT or IDCT subsystem. */
+ void * dct_table;
+} jpeg_component_info;
+
+
+/* Known color spaces. */
+
+typedef enum {
+ JCS_UNKNOWN, /* error/unspecified */
+ JCS_GRAYSCALE, /* monochrome */
+ JCS_RGB, /* red/green/blue */
+ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
+ JCS_CMYK, /* C/M/Y/K */
+ JCS_YCCK /* Y/Cb/Cr/K */
+} J_COLOR_SPACE;
+
+/* DCT/IDCT algorithm options. */
+
+typedef enum {
+ JDCT_ISLOW, /* slow but accurate integer algorithm */
+ JDCT_IFAST, /* faster, less accurate integer method */
+ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */
+} J_DCT_METHOD;
+
+#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */
+#define JDCT_DEFAULT JDCT_ISLOW
+#endif
+#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */
+#define JDCT_FASTEST JDCT_IFAST
+#endif
+
+/* Dithering options for decompression. */
+
+typedef enum {
+ JDITHER_NONE, /* no dithering */
+ JDITHER_ORDERED, /* simple ordered dither */
+ JDITHER_FS /* Floyd-Steinberg error diffusion dither */
+} J_DITHER_MODE;
+
+
+/* Common fields between JPEG compression and decompression master structs. */
+
+#define jpeg_common_fields \
+ struct jpeg_error_mgr * err; /* Error handler module */\
+ struct jpeg_memory_mgr * mem; /* Memory manager module */\
+ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\
+ boolean is_decompressor; /* so common code can tell which is which */\
+ int global_state /* for checking call sequence validity */
+
+/* Routines that are to be used by both halves of the library are declared
+ * to receive a pointer to this structure. There are no actual instances of
+ * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.
+ */
+struct jpeg_common_struct {
+ jpeg_common_fields; /* Fields common to both master struct types */
+ /* Additional fields follow in an actual jpeg_compress_struct or
+ * jpeg_decompress_struct. All three structs must agree on these
+ * initial fields! (This would be a lot cleaner in C++.)
+ */
+};
+
+typedef struct jpeg_common_struct * j_common_ptr;
+typedef struct jpeg_compress_struct * j_compress_ptr;
+typedef struct jpeg_decompress_struct * j_decompress_ptr;
+
+
+/* Master record for a compression instance */
+
+struct jpeg_compress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */
+
+ /* Destination for compressed data */
+ struct jpeg_destination_mgr * dest;
+
+ /* Description of source image --- these fields must be filled in by
+ * outer application before starting compression. in_color_space must
+ * be correct before you can even call jpeg_set_defaults().
+ */
+
+ JDIMENSION image_width; /* input image width */
+ JDIMENSION image_height; /* input image height */
+ int input_components; /* # of color components in input image */
+ J_COLOR_SPACE in_color_space; /* colorspace of input image */
+
+ double input_gamma; /* image gamma of input image */
+
+ /* Compression parameters --- these fields must be set before calling
+ * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to
+ * initialize everything to reasonable defaults, then changing anything
+ * the application specifically wants to change. That way you won't get
+ * burnt when new parameters are added. Also note that there are several
+ * helper routines to simplify changing parameters.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ boolean raw_data_in; /* TRUE=caller supplies downsampled data */
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+ boolean interleave; /* TRUE=interleaved output, FALSE=not */
+ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+ int smoothing_factor; /* 1..100, or 0 for no input smoothing */
+ J_DCT_METHOD dct_method; /* DCT algorithm selector */
+
+ /* The restart interval can be specified in absolute MCUs by setting
+ * restart_interval, or in MCU rows by setting restart_in_rows
+ * (in which case the correct restart_interval will be figured
+ * for each scan).
+ */
+ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */
+ int restart_in_rows; /* if > 0, MCU rows per restart interval */
+
+ /* Parameters controlling emission of special markers. */
+
+ boolean write_JFIF_header; /* should a JFIF marker be written? */
+ /* These three values are not used by the JPEG code, merely copied */
+ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */
+ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */
+ /* ratio is defined by X_density/Y_density even when density_unit=0. */
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean write_Adobe_marker; /* should an Adobe marker be written? */
+
+ /* State variable: index of next scanline to be written to
+ * jpeg_write_scanlines(). Application may use this to control its
+ * processing loop, e.g., "while (next_scanline < image_height)".
+ */
+
+ JDIMENSION next_scanline; /* 0 .. image_height-1 */
+
+ /* Remaining fields are known throughout compressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during compression startup
+ */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
+ /* The coefficient controller receives data in units of MCU rows as defined
+ * for fully interleaved scans (whether the JPEG file is interleaved or not).
+ * There are v_samp_factor * DCTSIZE sample rows of each component in an
+ * "iMCU" (interleaved MCU) row.
+ */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ /*
+ * Links to compression subobjects (methods and private variables of modules)
+ */
+ struct jpeg_comp_master * master;
+ struct jpeg_c_main_controller * main;
+ struct jpeg_c_prep_controller * prep;
+ struct jpeg_c_coef_controller * coef;
+ struct jpeg_marker_writer * marker;
+ struct jpeg_color_converter * cconvert;
+ struct jpeg_downsampler * downsample;
+ struct jpeg_forward_dct * fdct;
+ struct jpeg_entropy_encoder * entropy;
+};
+
+
+/* Master record for a decompression instance */
+
+struct jpeg_decompress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_compress_struct */
+
+ /* Source of compressed data */
+ struct jpeg_source_mgr * src;
+
+ /* Basic description of image --- filled in by jpeg_read_header(). */
+ /* Application may inspect these values to decide how to process image. */
+
+ JDIMENSION image_width; /* nominal image width (from SOF marker) */
+ JDIMENSION image_height; /* nominal image height */
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ /* Decompression processing parameters --- these fields must be set before
+ * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes
+ * them to default values.
+ */
+
+ J_COLOR_SPACE out_color_space; /* colorspace for output */
+
+ unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+ double output_gamma; /* image gamma wanted in output */
+
+ boolean raw_data_out; /* TRUE=downsampled data wanted */
+
+ boolean quantize_colors; /* TRUE=colormapped output wanted */
+ /* the following are ignored if not quantize_colors: */
+ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */
+ J_DITHER_MODE dither_mode; /* type of color dithering to use */
+ int desired_number_of_colors; /* max number of colors to use */
+
+ J_DCT_METHOD dct_method; /* DCT algorithm selector */
+ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */
+
+ /* Description of actual output image that will be returned to application.
+ * These fields are computed by jpeg_start_decompress().
+ * You can also use jpeg_calc_output_dimensions() to determine these values
+ * in advance of calling jpeg_start_decompress().
+ */
+
+ JDIMENSION output_width; /* scaled image width */
+ JDIMENSION output_height; /* scaled image height */
+ int out_color_components; /* # of color components in out_color_space */
+ int output_components; /* # of color components returned */
+ /* output_components is 1 (a colormap index) when quantizing colors;
+ * otherwise it equals out_color_components.
+ */
+ int rec_outbuf_height; /* min recommended height of scanline buffer */
+ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
+ * high, space and time will be wasted due to unnecessary data copying.
+ * Usually rec_outbuf_height will be 1 or 2, at most 4.
+ */
+
+ /* When quantizing colors, the output colormap is described by these fields.
+ * The application can supply a colormap by setting colormap non-NULL before
+ * calling jpeg_start_decompress; otherwise a colormap is created during
+ * jpeg_start_decompress.
+ * The map has out_color_components rows and actual_number_of_colors columns.
+ */
+ int actual_number_of_colors; /* number of entries in use */
+ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
+
+ /* State variable: index of next scaled scanline to be read from
+ * jpeg_read_scanlines(). Application may use this to control its
+ * processing loop, e.g., "while (output_scanline < output_height)".
+ */
+
+ JDIMENSION output_scanline; /* 0 .. output_height-1 */
+
+ /* Internal JPEG parameters --- the application usually need not look at
+ * these fields.
+ */
+
+ /* Quantization and Huffman tables are carried forward across input
+ * datastreams when processing abbreviated JPEG datastreams.
+ */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ /* These parameters are never carried across datastreams, since they
+ * are given in SOF/SOS markers or defined to be reset by SOI.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+
+ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */
+
+ /* These fields record data obtained from optional markers recognized by
+ * the JPEG library.
+ */
+ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */
+ /* Data copied from JFIF marker: */
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */
+ UINT8 Adobe_transform; /* Color transform code from Adobe marker */
+
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+
+ /* Remaining fields are known throughout decompressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during decompression startup
+ */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be output by coef ctlr */
+ /* The coefficient controller outputs data in units of MCU rows as defined
+ * for fully interleaved scans (whether the JPEG file is interleaved or not).
+ * There are v_samp_factor * DCT_scaled_size sample rows of each component
+ * in an "iMCU" (interleaved MCU) row.
+ */
+
+ JSAMPLE * sample_range_limit; /* table for fast range-limiting */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ /* This field is shared between entropy decoder and marker parser.
+ * It is either zero or the code of a JPEG marker that has been
+ * read from the data source, but has not yet been processed.
+ */
+ int unread_marker;
+
+ /*
+ * Links to decompression subobjects (methods, private variables of modules)
+ */
+ struct jpeg_decomp_master * master;
+ struct jpeg_d_main_controller * main;
+ struct jpeg_d_coef_controller * coef;
+ struct jpeg_d_post_controller * post;
+ struct jpeg_marker_reader * marker;
+ struct jpeg_entropy_decoder * entropy;
+ struct jpeg_inverse_dct * idct;
+ struct jpeg_upsampler * upsample;
+ struct jpeg_color_deconverter * cconvert;
+ struct jpeg_color_quantizer * cquantize;
+};
+
+
+/* "Object" declarations for JPEG modules that may be supplied or called
+ * directly by the surrounding application.
+ * As with all objects in the JPEG library, these structs only define the
+ * publicly visible methods and state variables of a module. Additional
+ * private fields may exist after the public ones.
+ */
+
+
+/* Error handler object */
+
+struct jpeg_error_mgr {
+ /* Error exit handler: does not return to caller */
+ JMETHOD(void, error_exit, (j_common_ptr cinfo));
+ /* Conditionally emit a trace or warning message */
+ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
+ /* Routine that actually outputs a trace or error message */
+ JMETHOD(void, output_message, (j_common_ptr cinfo));
+ /* Format a message string for the most recent JPEG error or message */
+ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));
+#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */
+ /* Reset error state variables at start of a new image */
+ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
+
+ /* The message ID code and any parameters are saved here.
+ * A message can have one string parameter or up to 8 int parameters.
+ */
+ int msg_code;
+#define JMSG_STR_PARM_MAX 80
+ union {
+ int i[8];
+ char s[JMSG_STR_PARM_MAX];
+ } msg_parm;
+
+ /* Standard state variables for error facility */
+
+ int trace_level; /* max msg_level that will be displayed */
+
+ /* For recoverable corrupt-data errors, we emit a warning message,
+ * but keep going unless emit_message chooses to abort. emit_message
+ * should count warnings in num_warnings. The surrounding application
+ * can check for bad data by seeing if num_warnings is nonzero at the
+ * end of processing.
+ */
+ long num_warnings; /* number of corrupt-data warnings */
+
+ /* These fields point to the table(s) of error message strings.
+ * An application can change the table pointer to switch to a different
+ * message list (typically, to change the language in which errors are
+ * reported). Some applications may wish to add additional error codes
+ * that will be handled by the JPEG library error mechanism; the second
+ * table pointer is used for this purpose.
+ *
+ * First table includes all errors generated by JPEG library itself.
+ * Error code 0 is reserved for a "no such error string" message.
+ */
+ const char * const * jpeg_message_table; /* Library errors */
+ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */
+ /* Second table can be added by application (see cjpeg/djpeg for example).
+ * It contains strings numbered first_addon_message..last_addon_message.
+ */
+ const char * const * addon_message_table; /* Non-library errors */
+ int first_addon_message; /* code for first string in addon table */
+ int last_addon_message; /* code for last string in addon table */
+};
+
+
+/* Progress monitor object */
+
+struct jpeg_progress_mgr {
+ JMETHOD(void, progress_monitor, (j_common_ptr cinfo));
+
+ long pass_counter; /* work units completed in this pass */
+ long pass_limit; /* total number of work units in this pass */
+ int completed_passes; /* passes completed so far */
+ int total_passes; /* total number of passes expected */
+};
+
+
+/* Data destination object for compression */
+
+struct jpeg_destination_mgr {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+
+ JMETHOD(void, init_destination, (j_compress_ptr cinfo));
+ JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
+ JMETHOD(void, term_destination, (j_compress_ptr cinfo));
+};
+
+
+/* Data source object for decompression */
+
+struct jpeg_source_mgr {
+ const JOCTET * next_input_byte; /* => next byte to read from buffer */
+ size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+
+ JMETHOD(void, init_source, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
+ JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
+ JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo));
+ JMETHOD(void, term_source, (j_decompress_ptr cinfo));
+};
+
+
+/* Memory manager object.
+ * Allocates "small" objects (a few K total), "large" objects (tens of K),
+ * and "really big" objects (virtual arrays with backing store if needed).
+ * The memory manager does not allow individual objects to be freed; rather,
+ * each created object is assigned to a pool, and whole pools can be freed
+ * at once. This is faster and more convenient than remembering exactly what
+ * to free, especially where malloc()/free() are not too speedy.
+ * NB: alloc routines never return NULL. They exit to error_exit if not
+ * successful.
+ */
+
+#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */
+#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */
+#define JPOOL_NUMPOOLS 2
+
+typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
+typedef struct jvirt_barray_control * jvirt_barray_ptr;
+
+
+struct jpeg_memory_mgr {
+ /* Method pointers */
+ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows));
+ JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows));
+ JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
+ int pool_id,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows,
+ JDIMENSION unitheight));
+ JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,
+ int pool_id,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows,
+ JDIMENSION unitheight));
+ JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));
+ JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,
+ jvirt_sarray_ptr ptr,
+ JDIMENSION start_row,
+ boolean writable));
+ JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,
+ jvirt_barray_ptr ptr,
+ JDIMENSION start_row,
+ boolean writable));
+ JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));
+ JMETHOD(void, self_destruct, (j_common_ptr cinfo));
+
+ /* Limit on memory allocation for this JPEG object. (Note that this is
+ * merely advisory, not a guaranteed maximum; it only affects the space
+ * used for virtual-array buffers.) May be changed by outer application
+ * after creating the JPEG object.
+ */
+ long max_memory_to_use;
+};
+
+
+/* Routine signature for application-supplied marker processing methods.
+ * Need not pass marker code since it is stored in cinfo->unread_marker.
+ */
+typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
+
+
+/* Declarations for routines called by application.
+ * The JPP macro hides prototype parameters from compilers that can't cope.
+ * Note JPP requires double parentheses.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JPP(arglist) arglist
+#else
+#define JPP(arglist) ()
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers.
+ * We shorten external names to be unique in the first six letters, which
+ * is good enough for all known systems.
+ * (If your compiler itself needs names to be unique in less than 15
+ * characters, you are out of luck. Get a better compiler.)
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_error jStdError
+#define jpeg_create_compress jCreaCompress
+#define jpeg_create_decompress jCreaDecompress
+#define jpeg_destroy_compress jDestCompress
+#define jpeg_destroy_decompress jDestDecompress
+#define jpeg_stdio_dest jStdDest
+#define jpeg_stdio_src jStdSrc
+#define jpeg_set_defaults jSetDefaults
+#define jpeg_set_colorspace jSetColorspace
+#define jpeg_default_colorspace jDefColorspace
+#define jpeg_set_quality jSetQuality
+#define jpeg_set_linear_quality jSetLQuality
+#define jpeg_add_quant_table jAddQuantTable
+#define jpeg_quality_scaling jQualityScaling
+#define jpeg_suppress_tables jSuppressTables
+#define jpeg_alloc_quant_table jAlcQTable
+#define jpeg_alloc_huff_table jAlcHTable
+#define jpeg_start_compress jStrtCompress
+#define jpeg_write_scanlines jWrtScanlines
+#define jpeg_finish_compress jFinCompress
+#define jpeg_write_raw_data jWrtRawData
+#define jpeg_write_marker jWrtMarker
+#define jpeg_write_tables jWrtTables
+#define jpeg_read_header jReadHeader
+#define jpeg_start_decompress jStrtDecompress
+#define jpeg_read_scanlines jReadScanlines
+#define jpeg_finish_decompress jFinDecompress
+#define jpeg_read_raw_data jReadRawData
+#define jpeg_calc_output_dimensions jCalcDimensions
+#define jpeg_set_marker_processor jSetMarker
+#define jpeg_abort_compress jAbrtCompress
+#define jpeg_abort_decompress jAbrtDecompress
+#define jpeg_abort jAbort
+#define jpeg_destroy jDestroy
+#define jpeg_resync_to_restart jResyncRestart
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Default error-management setup */
+EXTERN struct jpeg_error_mgr *jpeg_std_error JPP((struct jpeg_error_mgr *err));
+
+/* Initialization and destruction of JPEG compression objects */
+/* NB: you must set up the error-manager BEFORE calling jpeg_create_xxx */
+EXTERN void jpeg_create_compress JPP((j_compress_ptr cinfo));
+EXTERN void jpeg_create_decompress JPP((j_decompress_ptr cinfo));
+EXTERN void jpeg_destroy_compress JPP((j_compress_ptr cinfo));
+EXTERN void jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));
+
+/* Standard data source and destination managers: stdio streams. */
+/* Caller is responsible for opening the file before and closing after. */
+EXTERN void jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
+EXTERN void jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* Default parameter setup for compression */
+EXTERN void jpeg_set_defaults JPP((j_compress_ptr cinfo));
+/* Compression parameter setup aids */
+EXTERN void jpeg_set_colorspace JPP((j_compress_ptr cinfo,
+ J_COLOR_SPACE colorspace));
+EXTERN void jpeg_default_colorspace JPP((j_compress_ptr cinfo));
+EXTERN void jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,
+ boolean force_baseline));
+EXTERN void jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN void jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN int jpeg_quality_scaling JPP((int quality));
+EXTERN void jpeg_suppress_tables JPP((j_compress_ptr cinfo,
+ boolean suppress));
+EXTERN JQUANT_TBL * jpeg_alloc_quant_table JPP((j_common_ptr cinfo));
+EXTERN JHUFF_TBL * jpeg_alloc_huff_table JPP((j_common_ptr cinfo));
+
+/* Main entry points for compression */
+EXTERN void jpeg_start_compress JPP((j_compress_ptr cinfo,
+ boolean write_all_tables));
+EXTERN JDIMENSION jpeg_write_scanlines JPP((j_compress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION num_lines));
+EXTERN void jpeg_finish_compress JPP((j_compress_ptr cinfo));
+
+/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
+EXTERN JDIMENSION jpeg_write_raw_data JPP((j_compress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION num_lines));
+
+/* Write a special marker. See libjpeg.doc concerning safe usage. */
+EXTERN void jpeg_write_marker JPP((j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen));
+
+/* Alternate compression function: just write an abbreviated table file */
+EXTERN void jpeg_write_tables JPP((j_compress_ptr cinfo));
+
+/* Decompression startup: read start of JPEG datastream to see what's there */
+EXTERN int jpeg_read_header JPP((j_decompress_ptr cinfo,
+ boolean require_image));
+/* Return value is one of: */
+#define JPEG_HEADER_OK 0 /* Found valid image datastream */
+#define JPEG_HEADER_TABLES_ONLY 1 /* Found valid table-specs-only datastream */
+#define JPEG_SUSPENDED 2 /* Had to suspend before end of headers */
+/* If you pass require_image = TRUE (normal case), you need not check for
+ * a TABLES_ONLY return code; an abbreviated file will cause an error exit.
+ * JPEG_SUSPENDED is only possible if you use a data source module that can
+ * give a suspension return (the stdio source module doesn't).
+ */
+
+/* Main entry points for decompression */
+EXTERN void jpeg_start_decompress JPP((j_decompress_ptr cinfo));
+EXTERN JDIMENSION jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION max_lines));
+EXTERN boolean jpeg_finish_decompress JPP((j_decompress_ptr cinfo));
+
+/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
+EXTERN JDIMENSION jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION max_lines));
+
+/* Precalculate output dimensions for current decompression parameters. */
+EXTERN void jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
+
+/* Install a special processing method for COM or APPn markers. */
+EXTERN void jpeg_set_marker_processor JPP((j_decompress_ptr cinfo,
+ int marker_code,
+ jpeg_marker_parser_method routine));
+
+/* If you choose to abort compression or decompression before completing
+ * jpeg_finish_(de)compress, then you need to clean up to release memory,
+ * temporary files, etc. You can just call jpeg_destroy_(de)compress
+ * if you're done with the JPEG object, but if you want to clean it up and
+ * reuse it, call this:
+ */
+EXTERN void jpeg_abort_compress JPP((j_compress_ptr cinfo));
+EXTERN void jpeg_abort_decompress JPP((j_decompress_ptr cinfo));
+
+/* Generic versions of jpeg_abort and jpeg_destroy that work on either
+ * flavor of JPEG object. These may be more convenient in some places.
+ */
+EXTERN void jpeg_abort JPP((j_common_ptr cinfo));
+EXTERN void jpeg_destroy JPP((j_common_ptr cinfo));
+
+/* Default restart-marker-resync procedure for use by data source modules */
+EXTERN boolean jpeg_resync_to_restart JPP((j_decompress_ptr cinfo));
+
+
+/* These marker codes are exported since applications and data source modules
+ * are likely to want to use them.
+ */
+
+#define JPEG_RST0 0xD0 /* RST0 marker code */
+#define JPEG_EOI 0xD9 /* EOI marker code */
+#define JPEG_APP0 0xE0 /* APP0 marker code */
+#define JPEG_COM 0xFE /* COM marker code */
+
+
+/* If we have a brain-damaged compiler that emits warnings (or worse, errors)
+ * for structure definitions that are never filled in, keep it quiet by
+ * supplying dummy definitions for the various substructures.
+ */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+struct jpeg_comp_master { long dummy; };
+struct jpeg_c_main_controller { long dummy; };
+struct jpeg_c_prep_controller { long dummy; };
+struct jpeg_c_coef_controller { long dummy; };
+struct jpeg_marker_writer { long dummy; };
+struct jpeg_color_converter { long dummy; };
+struct jpeg_downsampler { long dummy; };
+struct jpeg_forward_dct { long dummy; };
+struct jpeg_entropy_encoder { long dummy; };
+struct jpeg_decomp_master { long dummy; };
+struct jpeg_d_main_controller { long dummy; };
+struct jpeg_d_coef_controller { long dummy; };
+struct jpeg_d_post_controller { long dummy; };
+struct jpeg_marker_reader { long dummy; };
+struct jpeg_entropy_decoder { long dummy; };
+struct jpeg_inverse_dct { long dummy; };
+struct jpeg_upsampler { long dummy; };
+struct jpeg_color_deconverter { long dummy; };
+struct jpeg_color_quantizer { long dummy; };
+#endif /* JPEG_INTERNALS */
+#endif /* INCOMPLETE_TYPES_BROKEN */
+
+
+/*
+ * The JPEG library modules define JPEG_INTERNALS before including this file.
+ * The internal structure declarations are read only when that is true.
+ * Applications using the library should not include jpegint.h, but may wish
+ * to include jerror.h.
+ */
+
+#ifdef JPEG_INTERNALS
+#include "jpegint.h" /* fetch private declarations */
+#include "jerror.h" /* fetch error codes too */
+#endif
+
+#endif /* JPEGLIB_H */
diff --git a/gs/src/gslib.c b/gs/src/gslib.c
new file mode 100644
index 000000000..6dd54bfc7
--- /dev/null
+++ b/gs/src/gslib.c
@@ -0,0 +1,549 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gslib.c */
+/* Test program for Ghostscript library */
+/* Capture stdin/out/err before gs.h redefines them. */
+#include <stdio.h>
+static FILE *real_stdin, *real_stdout, *real_stderr;
+static void
+get_real(void)
+{ real_stdin = stdin, real_stdout = stdout, real_stderr = stderr;
+}
+#include "math_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gscdefs.h"
+#include "gserrors.h"
+#include "gslib.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gscoord.h"
+#include "gsparam.h"
+#include "gspaint.h"
+#include "gspath.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxalloc.h"
+#include "gxdevice.h"
+
+/* Define whether we are processing captured data. */
+/*#define CAPTURE*/
+
+/* Test programs */
+private void test1(P2(gs_state *, gs_memory_t *)); /* kaleidoscope */
+private void test2(P2(gs_state *, gs_memory_t *)); /* pattern fill */
+private void test3(P2(gs_state *, gs_memory_t *)); /* RasterOp */
+private void test4(P2(gs_state *, gs_memory_t *)); /* set resolution */
+#ifdef CAPTURE
+#include "k/capture.c"
+private void test5(P2(gs_state *, gs_memory_t *)); /* captured data */
+#endif
+private void (*tests[])(P2(gs_state *, gs_memory_t *)) =
+ { test1, test2, test3, test4
+#ifdef CAPTURE
+ , test5
+#endif
+ };
+
+/* Include the extern for the device list. */
+extern_gs_lib_device_list();
+
+/* Other imported procedures */
+ /* from gsalloc.c */
+extern gs_ref_memory_t *ialloc_alloc_state(P2(gs_memory_t *, uint));
+
+/* Forward references */
+private float odsf(P2(floatp, floatp));
+
+int
+main(int argc, const char *argv[])
+{ char achar;
+ gs_ref_memory_t *imem;
+#define mem ((gs_memory_t *)imem)
+ gs_state *pgs;
+ const gx_device **list;
+ gx_device *dev;
+
+ gp_init();
+ get_real();
+ gs_stdin = real_stdin;
+ gs_stdout = real_stdout;
+ gs_stderr = real_stderr;
+ gs_lib_init(stdout);
+ if ( argc < 2 || (achar = argv[1][0]) < '1' ||
+ achar > '0' + countof(tests)
+
+ )
+ { lprintf1("Usage: gslib 1..%c\n", '0' + countof(tests));
+ exit(1);
+ }
+ gs_debug['@'] = 1;
+ gs_debug['?'] = 1;
+ /*gs_debug['L'] = 1;*/ /****** PATCH ******/
+ imem = ialloc_alloc_state(&gs_memory_default, 20000);
+ imem->space = 0; /****** WRONG ******/
+ gs_lib_device_list(&list, NULL);
+ gs_copydevice(&dev, list[0], mem);
+ /* Print out the device name just to test the gsparam.c API. */
+ { gs_c_param_list list;
+ gs_param_string nstr;
+ int code;
+ gs_c_param_list_write(&list, mem);
+ code = gs_getdeviceparams(dev, (gs_param_list *)&list);
+ if ( code < 0 )
+ { lprintf1("getdeviceparams failed! code = %d\n", code);
+ exit(1);
+ }
+ gs_c_param_list_read(&list);
+ code = param_read_string((gs_param_list *)&list, "Name", &nstr);
+ if ( code < 0 )
+ { lprintf1("reading Name failed! code = %d\n", code);
+ exit(1);
+ }
+ dputs("Device name = ");
+ debug_print_string(nstr.data, nstr.size);
+ dputs("\n");
+ gs_c_param_list_release(&list);
+ }
+ pgs = gs_state_alloc(mem);
+ gs_setdevice_no_erase(pgs, dev); /* can't erase yet */
+ { gs_point dpi;
+ gs_screen_halftone ht;
+ gs_dtransform(pgs, 72.0, 72.0, &dpi);
+ ht.frequency = min(fabs(dpi.x), fabs(dpi.y)) / 16.001;
+ ht.angle = 0;
+ ht.spot_function = odsf;
+ gs_setscreen(pgs, &ht);
+ }
+ /* gsave and grestore (among other places) assume that */
+ /* there are at least 2 gstates on the graphics stack. */
+ /* Ensure that now. */
+ gs_gsave(pgs);
+ gs_erasepage(pgs);
+ (*tests[achar - '1'])(pgs, mem);
+ gs_output_page(pgs, 1, 1);
+ dputs("Done. Press <enter> to exit.");
+ getchar();
+ gs_lib_finit(0, 0);
+ return 0;
+#undef mem
+}
+/* Ordered dither spot function */
+private float
+odsf(floatp x, floatp y)
+{ static const byte dither[256] = {
+0x0E,0x8E,0x2E,0xAE,0x06,0x86,0x26,0xA6,0x0C,0x8C,0x2C,0xAC,0x04,0x84,0x24,0xA4,
+0xCE,0x4E,0xEE,0x6E,0xC6,0x46,0xE6,0x66,0xCC,0x4C,0xEC,0x6C,0xC4,0x44,0xE4,0x64,
+0x3E,0xBE,0x1E,0x9E,0x36,0xB6,0x16,0x96,0x3C,0xBC,0x1C,0x9C,0x34,0xB4,0x14,0x94,
+0xFE,0x7E,0xDE,0x5E,0xF6,0x76,0xD6,0x56,0xFC,0x7C,0xDC,0x5C,0xF4,0x74,0xD4,0x54,
+0x01,0x81,0x21,0xA1,0x09,0x89,0x29,0xA9,0x03,0x83,0x23,0xA3,0x0B,0x8B,0x2B,0xAB,
+0xC1,0x41,0xE1,0x61,0xC9,0x49,0xE9,0x69,0xC3,0x43,0xE3,0x63,0xCB,0x4B,0xEB,0x6B,
+0x31,0xB1,0x11,0x91,0x39,0xB9,0x19,0x99,0x33,0xB3,0x13,0x93,0x3B,0xBB,0x1B,0x9B,
+0xF1,0x71,0xD1,0x51,0xF9,0x79,0xD9,0x59,0xF3,0x73,0xD3,0x53,0xFB,0x7B,0xDB,0x5B,
+0x0D,0x8D,0x2D,0xAD,0x05,0x85,0x25,0xA5,0x0F,0x8F,0x2F,0xAF,0x07,0x87,0x27,0xA7,
+0xCD,0x4D,0xED,0x6D,0xC5,0x45,0xE5,0x65,0xCF,0x4F,0xEF,0x6F,0xC7,0x47,0xE7,0x67,
+0x3D,0xBD,0x1D,0x9D,0x35,0xB5,0x15,0x95,0x3F,0xBF,0x1F,0x9F,0x37,0xB7,0x17,0x97,
+0xFD,0x7D,0xDD,0x5D,0xF5,0x75,0xD5,0x55,0xFF,0x7F,0xDF,0x5F,0xF7,0x77,0xD7,0x57,
+0x02,0x82,0x22,0xA2,0x0A,0x8A,0x2A,0xAA,0x00,0x80,0x20,0xA0,0x08,0x88,0x28,0xA8,
+0xC2,0x42,0xE2,0x62,0xCA,0x4A,0xEA,0x6A,0xC0,0x40,0xE0,0x60,0xC8,0x48,0xE8,0x68,
+0x32,0xB2,0x12,0x92,0x3A,0xBA,0x1A,0x9A,0x30,0xB0,0x10,0x90,0x38,0xB8,0x18,0x98,
+0xF2,0x72,0xD2,0x52,0xFA,0x7A,0xDA,0x5A,0xF0,0x70,0xD0,0x50,0xF8,0x78,0xD8,0x58
+ };
+ int i = (int)((x + 1) * 7.9999);
+ int j = (int)((y + 1) * 7.9999);
+ return dither[16 * i + j] / 256.0;
+}
+
+/* Stubs for GC */
+const gs_ptr_procs_t ptr_struct_procs = { NULL, NULL, NULL };
+const gs_ptr_procs_t ptr_string_procs = { NULL, NULL, NULL };
+const gs_ptr_procs_t ptr_const_string_procs = { NULL, NULL, NULL };
+void * /* obj_header_t * */
+gs_reloc_struct_ptr(const void * /* obj_header_t * */ obj, gc_state_t *gcst)
+{ return (void *)obj;
+}
+void
+gs_reloc_string(gs_string *sptr, gc_state_t *gcst)
+{
+}
+void
+gs_reloc_const_string(gs_const_string *sptr, gc_state_t *gcst)
+{
+}
+
+/* Other stubs */
+void
+gs_exit(int exit_status)
+{ gs_lib_finit(exit_status, 0);
+ exit(exit_status);
+}
+
+
+/* ---------------- Test program 1 ---------------- */
+/* Draw a colored kaleidoscope. */
+
+/* Random number generator */
+private long rand_state = 1;
+private long
+rand(void)
+{
+#define A 16807
+#define M 0x7fffffff
+#define Q 127773 /* M / A */
+#define R 2836 /* M % A */
+ rand_state = A * (rand_state % Q) - R * (rand_state / Q);
+ /* Note that rand_state cannot be 0 here. */
+ if ( rand_state <= 0 ) rand_state += M;
+#undef A
+#undef M
+#undef Q
+#undef R
+ return rand_state;
+}
+private void
+test1(gs_state *pgs, gs_memory_t *mem)
+{ int n;
+ gs_scale(pgs, 72.0, 72.0);
+ gs_translate(pgs, 4.25, 5.5);
+ gs_scale(pgs, 4.0, 4.0);
+ gs_newpath(pgs);
+ for ( n = 200; --n >= 0; )
+ { int j;
+#define rf() (rand() / (1.0 * 0x10000 * 0x8000))
+ double r = rf(), g = rf(), b = rf();
+ double x0=rf(), y0=rf(), x1=rf(), y1=rf(), x2=rf(), y2=rf();
+ gs_setrgbcolor(pgs, r, g, b);
+ for ( j = 0; j < 6; j++ )
+ { gs_gsave(pgs);
+ gs_rotate(pgs, 60.0 * j);
+ gs_moveto(pgs, x0, y0);
+ gs_lineto(pgs, x1, y1);
+ gs_lineto(pgs, x2, y2);
+ gs_fill(pgs);
+ gs_grestore(pgs);
+ }
+ }
+#undef mem
+}
+
+/* ---------------- Test program 2 ---------------- */
+/* Fill an area with a pattern. */
+
+private void
+test2(gs_state *pgs, gs_memory_t *mem)
+{ gs_client_color cc;
+ gx_tile_bitmap tile;
+ /*const*/ byte tpdata[] = {
+ /* Define a pattern that looks like this:
+ ..xxxx
+ .....x
+ .....x
+ ..xxxx
+ .x....
+ x.....
+ */
+ 0x3c,0,0,0, 0x04,0,0,0, 0x04,0,0,0, 0x3c,0,0,0,
+ 0x40,0,0,0, 0x80,0,0,0
+ };
+
+ gs_newpath(pgs);
+ gs_moveto(pgs, 100.0, 300.0);
+ gs_lineto(pgs, 500.0, 500.0);
+ gs_lineto(pgs, 200.0, 100.0);
+ gs_lineto(pgs, 300.0, 500.0);
+ gs_lineto(pgs, 500.0, 200.0);
+ gs_closepath(pgs);
+ gs_setrgbcolor(pgs, 0.0, 0.0, 0.0);
+ gs_gsave(pgs);
+ gs_fill(pgs);
+ gs_grestore(pgs);
+ tile.data = tpdata;
+ tile.raster = 4;
+ tile.size.x = tile.rep_width = 6;
+ tile.size.y = tile.rep_height = 6;
+ tile.id = gx_no_bitmap_id;
+ gs_makebitmappattern(&cc, &tile, true, pgs, NULL);
+ /* Note: color space is DeviceRGB */
+ cc.paint.values[0] = 0.0;
+ cc.paint.values[1] = 1.0;
+ cc.paint.values[2] = 1.0;
+ gs_setpattern(pgs, &cc);
+ gs_eofill(pgs);
+ gs_makebitmappattern(&cc, &tile, false, pgs, NULL);
+ gs_setcolor(pgs, &cc);
+ gs_moveto(pgs, 50.0, 50.0);
+ gs_lineto(pgs, 300.0, 50.0);
+ gs_lineto(pgs, 50.0, 300.0);
+ gs_closepath(pgs);
+ gs_setrgbcolor(pgs, 1.0, 0.0, 0.0);
+ gs_gsave(pgs);
+ gs_fill(pgs);
+ gs_grestore(pgs);
+ gs_setpattern(pgs, &cc);
+ gs_eofill(pgs);
+}
+
+/* ---------------- Test program 3 ---------------- */
+/* Exercise RasterOp a little. */
+/* Currently, this only works with monobit devices. */
+
+private void
+test3(gs_state *pgs, gs_memory_t *mem)
+{ gx_device *dev = gs_currentdevice(pgs);
+ gx_color_index black =
+ (*dev_proc(dev, map_rgb_color))(dev, 0, 0, 0);
+ gx_color_index white =
+ (*dev_proc(dev, map_rgb_color))(dev, gx_max_color_value,
+ gx_max_color_value,
+ gx_max_color_value);
+ gx_color_index black2[2];
+ gx_color_index black_white[2];
+ gx_color_index white_black[2];
+ long pattern[max(align_bitmap_mod / sizeof(long), 1) * 4];
+#define pbytes ((byte *)pattern)
+ gx_tile_bitmap tile;
+
+ black2[0] = black2[1] = black;
+ black_white[0] = white_black[1] = black;
+ black_white[1] = white_black[0] = white;
+ pbytes[0] = 0xf0;
+ pbytes[align_bitmap_mod] = 0x90;
+ pbytes[align_bitmap_mod*2] = 0x90;
+ pbytes[align_bitmap_mod*3] = 0xf0;
+ tile.data = pbytes;
+ tile.raster = align_bitmap_mod;
+ tile.size.x = tile.size.y = 4;
+ tile.id = gs_next_ids(1);
+ tile.rep_width = tile.rep_height = 4;
+ (*dev_proc(dev, copy_rop))
+ (dev, NULL, 0, 0, gx_no_bitmap_id, black2,
+ &tile, white_black, 100, 100, 150, 150, 0, 0, rop3_T);
+ (*dev_proc(dev, copy_rop))
+ (dev, NULL, 0, 0, gx_no_bitmap_id, black2,
+ NULL, NULL, 120, 120, 110, 110, 0, 0, ~rop3_S & rop3_1);
+ (*dev_proc(dev, copy_rop))
+ (dev, NULL, 0, 0, gx_no_bitmap_id, black2,
+ &tile, white_black, 110, 110, 130, 130, 0, 0, rop3_T ^ rop3_D);
+#undef pbytes
+}
+
+/* ---------------- Test program 4 ---------------- */
+/* Set the resolution dynamically. */
+
+private void
+test4(gs_state *pgs, gs_memory_t *mem)
+{ gs_c_param_list list;
+ float resv[2];
+ gs_param_float_array ares;
+ int code;
+ gx_device *dev = gs_currentdevice(pgs);
+
+ gs_c_param_list_write(&list, mem);
+ resv[0] = resv[1] = 100;
+ ares.data = resv;
+ ares.size = 2;
+ ares.persistent = true;
+ code = param_write_float_array((gs_param_list *)&list,
+ "HWResolution", &ares);
+ if ( code < 0 )
+ { lprintf1("Writing HWResolution failed: %d\n", code);
+ exit(1);
+ }
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(dev, (gs_param_list *)&list);
+ gs_c_param_list_release(&list);
+ if ( code < 0 )
+ { lprintf1("Setting HWResolution failed: %d\n", code);
+ exit(1);
+ }
+ gs_initmatrix(pgs);
+ gs_initclip(pgs);
+ if ( code == 1 )
+ { code = (*dev_proc(dev, open_device))(dev);
+ if ( code < 0 )
+ { lprintf1("Reopening device failed: %d\n", code);
+ exit(1);
+ }
+ }
+ gs_moveto(pgs, 0.0, 72.0);
+ gs_rlineto(pgs, 72.0, 0.0);
+ gs_rlineto(pgs, 0.0, 72.0);
+ gs_closepath(pgs);
+ gs_stroke(pgs);
+}
+
+#ifdef CAPTURE
+
+/* ---------------- Test program 5 ---------------- */
+/* Replay captured data for printer output. */
+
+private const char outfile[] = "t.pbm";
+private const float ypage_wid = 11.0;
+private const float xpage_len = 17.0;
+private const int rotate_value = 0;
+private const float scale_x = 0.45;
+private const float scale_y = 0.45;
+private const float xmove_origin = 0.0;
+private const float ymove_origin = 0.0;
+
+private void
+test5(gs_state *pgs, gs_memory_t *mem)
+{ gs_c_param_list list;
+ gs_param_string nstr, OFstr;
+ gs_param_float_array PSa;
+ gs_param_float_array HWRa;
+ gs_param_int_array HWSa;
+ int HWSize[2];
+ float HWResolution[2], PageSize[2];
+ long MaxBitmap;
+ int code;
+ gx_device *dev = gs_currentdevice(pgs);
+ float xlate_x, xlate_y;
+ gs_rect cliprect;
+
+ gs_c_param_list_write(&list, mem);
+ code = gs_getdeviceparams(dev, (gs_param_list *)&list);
+ if ( code < 0 )
+ { lprintf1("getdeviceparams failed! code = %d\n", code);
+ exit(1);
+ }
+ gs_c_param_list_read(&list);
+ code = param_read_string((gs_param_list *)&list, "Name", &nstr);
+ if ( code < 0 )
+ { lprintf1("reading Name failed! code = %d\n", code);
+ exit(1);
+ }
+ code = param_read_int_array((gs_param_list *)&list,
+ "HWSize", &HWSa);
+ if ( code < 0 )
+ { lprintf1("reading HWSize failed! code = %d\n", code);
+ exit(1);
+ }
+ eprintf3("HWSize[%d] = [ %d, %d ]\n", HWSa.size,
+ HWSa.data[0], HWSa.data[1]);
+ code = param_read_float_array((gs_param_list *)&list,
+ "HWResolution", &HWRa);
+ if ( code < 0 )
+ { lprintf1("reading Resolution failed! code = %d\n", code);
+ exit(1);
+ }
+ eprintf3("HWResolution[%d] = [ %f, %f ]\n", HWRa.size,
+ HWRa.data[0], HWRa.data[1]);
+ code = param_read_float_array((gs_param_list *)&list,
+ "PageSize", &PSa);
+ if ( code < 0 )
+ { lprintf1("reading PageSize failed! code = %d\n", code);
+ exit(1);
+ }
+ eprintf3("PageSize[%d] = [ %f, %f ]\n", PSa.size,
+ PSa.data[0], PSa.data[1]);
+ code = param_read_long((gs_param_list *)&list,
+ "MaxBitmap", &MaxBitmap);
+ if ( code < 0 )
+ { lprintf1("reading MaxBitmap failed! code = %d\n", code);
+ exit(1);
+ }
+ eprintf1("MaxBitmap = %ld\n", MaxBitmap );
+ /* Switch to param list functions to "write" */
+ gs_c_param_list_write(&list, mem);
+ /* Always set the PageSize. */
+ PageSize[0] = 72.0 * ypage_wid;
+ PageSize[1] = 72.0 * xpage_len;
+ PSa.data = PageSize;
+ code = param_write_float_array((gs_param_list *)&list,
+ "PageSize", &PSa);
+ if( nstr.data[0] != 'v' ) {
+ /* Set the OutputFile string file name */
+ OFstr.persistent = false;
+ OFstr.data = outfile;
+ OFstr.size = strlen(outfile);
+ code = param_write_string((gs_param_list *)&list,
+ "OutputFile", &OFstr);
+ if ( code < 0 )
+ { lprintf1("setting OutputFile name failed, code=%d\n",
+ code);
+ exit(1);
+ }
+ if( nstr.data[0] == 'x' ) {
+ HWResolution[0] = HWResolution[1] = 72.0;
+ }
+ else {
+ HWResolution[0] = HWResolution[1] = 360.0;
+ }
+ HWRa.data = HWResolution;
+ HWSize[0] = (int) (HWResolution[0] * ypage_wid);
+ HWSize[1] = (int) (HWResolution[1] * xpage_len);
+ eprintf3(" HWSize = [%d,%d], HWResolution = %f dpi\n",
+ HWSize[0], HWSize[1], HWResolution[0] );
+ HWSa.data = HWSize;
+ code = param_write_float_array((gs_param_list *)&list,
+ "HWResolution", &HWRa);
+ code = param_write_int_array((gs_param_list *)&list,
+ "HWSize", &HWSa);
+ MaxBitmap = 1000000L;
+ code = param_write_long((gs_param_list *)&list,
+ "MaxBitmap", &MaxBitmap);
+ }
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(dev, (gs_param_list *)&list);
+ eprintf1("putdeviceparams: code=%d\n", code);
+ gs_c_param_list_release(&list);
+
+ gs_erasepage(pgs);
+ gs_initgraphics(pgs);
+ gs_clippath( pgs );
+ gs_pathbbox( pgs, &cliprect );
+ eprintf4(" cliprect = [[%g,%g],[%g,%g]]\n",
+ cliprect.p.x, cliprect.p.y, cliprect.q.x, cliprect.q.y);
+ gs_newpath( pgs );
+
+ switch( ((rotate_value+270)/90) & 3 ) {
+ default:
+ case 0: /* 0 = 360 degrees in PS == 90 degrees in printer */
+ xlate_x = cliprect.p.x; xlate_y = cliprect.p.y;
+ break;
+ case 1: /* 90 degrees in PS = 180 degrees printer */
+ xlate_x = cliprect.q.x; xlate_y = cliprect.p.y;
+ break;
+ case 2: /* 180 degrees in PS == 270 degrees in printer */
+ xlate_x = cliprect.q.x; xlate_y = cliprect.q.y;
+ break;
+ case 3: /* 270 degrees in PS == 0 degrees in printer */
+ xlate_x = cliprect.p.x; xlate_y = cliprect.q.y;
+ break;
+ }
+ eprintf2("translate origin to [ %f, %f ]\n", xlate_x, xlate_y);
+ gs_translate( pgs, xlate_x, xlate_y );
+
+ /* further move (before rotate) by user requested amount */
+ gs_translate( pgs, 72.0*(float)xmove_origin, 72.0*(float)ymove_origin );
+
+ gs_rotate( pgs, (float)rotate_value + 270.0 );
+ gs_scale( pgs, scale_x*72.0/2032.0,
+ scale_y*72.0/2032.0);
+ gs_setlinecap( pgs, gs_cap_butt );
+ gs_setlinejoin( pgs, gs_join_bevel );
+ gs_setfilladjust(pgs, 0.0, 0.0);
+
+ capture_exec(pgs);
+}
+
+#endif /* CAPTURE */
diff --git a/gs/src/gslib.h b/gs/src/gslib.h
new file mode 100644
index 000000000..588dc5dd2
--- /dev/null
+++ b/gs/src/gslib.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gslib.h */
+/* Top-level API functions for imaging library */
+/* Requires stdio.h, gsmemory.h */
+
+/*
+ * Initialize the library. gs_lib_init does all of the initialization,
+ * using the C heap for initial allocation; if a client wants the library to
+ * use a different default allocator during initialization, it should call
+ * gs_lib_init0 and then gs_lib_init1.
+ */
+void gs_lib_init(P1(FILE *debug_out));
+void gs_lib_init0(P1(FILE *debug_out));
+void gs_lib_init1(P1(gs_memory_t *));
+
+/* Clean up after execution. */
+void gs_lib_finit(P2(int exit_status, int code));
diff --git a/gs/src/gsline.c b/gs/src/gsline.c
new file mode 100644
index 000000000..761a22e00
--- /dev/null
+++ b/gs/src/gsline.c
@@ -0,0 +1,302 @@
+/* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsline.c */
+/* Line parameter operators for Ghostscript library */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h" /* ditto */
+#include "gxmatrix.h" /* for gzstate */
+#include "gzstate.h"
+#include "gsline.h" /* for prototypes */
+#include "gzline.h"
+
+/* ------ Device-independent parameters ------ */
+
+#define pgs_lp gs_currentlineparams_inline(pgs)
+
+/* setlinewidth */
+int
+gs_setlinewidth(gs_state *pgs, floatp width)
+{ gx_set_line_width(pgs_lp, width);
+ return 0;
+}
+
+/* currentlinewidth */
+float
+gs_currentlinewidth(const gs_state *pgs)
+{ return gx_current_line_width(pgs_lp);
+}
+
+/* setlinecap */
+int
+gs_setlinecap(gs_state *pgs, gs_line_cap cap)
+{ if ( (uint)cap > gs_line_cap_max )
+ return_error(gs_error_rangecheck);
+ pgs_lp->cap = cap;
+ return 0;
+}
+
+/* currentlinecap */
+gs_line_cap
+gs_currentlinecap(const gs_state *pgs)
+{ return pgs_lp->cap;
+}
+
+/* setlinejoin */
+int
+gs_setlinejoin(gs_state *pgs, gs_line_join join)
+{ if ( (uint)join > gs_line_join_max )
+ return_error(gs_error_rangecheck);
+ pgs_lp->join = join;
+ return 0;
+}
+
+/* currentlinejoin */
+gs_line_join
+gs_currentlinejoin(const gs_state *pgs)
+{ return pgs_lp->join;
+}
+
+/* setmiterlimit */
+int
+gx_set_miter_limit(gx_line_params *plp, floatp limit)
+{ if ( limit < 1.0 )
+ return_error(gs_error_rangecheck);
+ plp->miter_limit = limit;
+ /*
+ * Compute the miter check value. The supplied miter limit is an
+ * upper bound on 1/sin(phi/2); we convert this to a lower bound on
+ * tan(phi). Note that if phi > pi/2, this is negative. We use the
+ * half-angle and angle-sum formulas here to avoid the trig functions.
+ * We also need a special check for phi/2 close to pi/4.
+ * Some C compilers can't handle this as a conditional expression....
+ */
+ { double limit_squared = limit * limit;
+ if ( limit_squared < 2.0001 && limit_squared > 1.9999 )
+ plp->miter_check = 1.0e6;
+ else
+ plp->miter_check =
+ sqrt(limit_squared - 1) * 2 / (limit_squared - 2);
+ }
+ return 0;
+}
+int
+gs_setmiterlimit(gs_state *pgs, floatp limit)
+{ return gx_set_miter_limit(pgs_lp, limit);
+}
+
+/* currentmiterlimit */
+float
+gs_currentmiterlimit(const gs_state *pgs)
+{ return pgs_lp->miter_limit;
+}
+
+/* setdash */
+int
+gx_set_dash(gx_dash_params *dash, const float *pattern, uint length,
+ floatp offset, gs_memory_t *mem)
+{ uint n = length;
+ const float *dfrom = pattern;
+ bool ink = true;
+ int index = 0;
+ float pattern_length = 0.0;
+ float dist_left;
+ float *ppat = dash->pattern;
+
+ /* Check the dash pattern. */
+ while ( n-- )
+ { float elt = *dfrom++;
+ if ( elt < 0 )
+ return_error(gs_error_rangecheck);
+ pattern_length += elt;
+ }
+ if ( length == 0 ) /* empty pattern */
+ { dist_left = 0.0;
+ if ( mem && ppat ) {
+ gs_free_object(mem, ppat, "gx_set_dash(old pattern)");
+ ppat = 0;
+ }
+ }
+ else
+ { uint size = length * sizeof(float);
+ if ( pattern_length == 0 )
+ return_error(gs_error_rangecheck);
+ /* Compute the initial index, ink_on, and distance left */
+ /* in the pattern, according to the offset. */
+#define f_mod(a, b) ((a) - floor((a) / (b)) * (b))
+ if ( length & 1 )
+ { /* Odd and even repetitions of the pattern */
+ /* have opposite ink values! */
+ float length2 = pattern_length * 2;
+ dist_left = f_mod(offset, length2);
+ if ( dist_left >= pattern_length )
+ dist_left -= pattern_length, ink = !ink;
+ }
+ else
+ dist_left = f_mod(offset, pattern_length);
+ while ( (dist_left -= pattern[index]) >= 0 &&
+ (dist_left > 0 || pattern[index] != 0)
+ )
+ ink = !ink, index++;
+ if ( mem )
+ { if ( ppat == 0 )
+ ppat = (float *)gs_alloc_bytes(mem, size,
+ "gx_set_dash(pattern)");
+ else if ( length != dash->pattern_size )
+ ppat = gs_resize_object(mem, ppat, size,
+ "gx_set_dash(pattern)");
+ if ( ppat == 0 )
+ return_error(gs_error_VMerror);
+ }
+ memcpy(ppat, pattern, length * sizeof(float));
+ }
+ dash->pattern = ppat;
+ dash->pattern_size = length;
+ dash->offset = offset;
+ dash->pattern_length = pattern_length;
+ dash->init_ink_on = ink;
+ dash->init_index = index;
+ dash->init_dist_left = -dist_left;
+ return 0;
+}
+int
+gs_setdash(gs_state *pgs, const float *pattern, uint length, floatp offset)
+{ return gx_set_dash(&pgs_lp->dash, pattern, length, offset,
+ pgs->memory);
+}
+
+/* currentdash */
+uint
+gs_currentdash_length(const gs_state *pgs)
+{ return pgs_lp->dash.pattern_size;
+}
+const float *
+gs_currentdash_pattern(const gs_state *pgs)
+{ return pgs_lp->dash.pattern;
+}
+float
+gs_currentdash_offset(const gs_state *pgs)
+{ return pgs_lp->dash.offset;
+}
+
+/* Internal accessor for line parameters */
+const gx_line_params *
+gs_currentlineparams(const gs_imager_state *pis)
+{ return gs_currentlineparams_inline(pis);
+}
+
+/* ------ Device-dependent parameters ------ */
+
+/* setflat */
+int
+gs_imager_setflat(gs_imager_state *pis, floatp flat)
+{ if ( flat <= 0.2 )
+ flat = 0.2;
+ else if ( flat > 100 )
+ flat = 100;
+ pis->flatness = flat;
+ return 0;
+}
+int
+gs_setflat(gs_state *pgs, floatp flat)
+{ return gs_imager_setflat((gs_imager_state *)pgs, flat);
+}
+
+/* currentflat */
+float
+gs_currentflat(const gs_state *pgs)
+{ return pgs->flatness;
+}
+
+/* setstrokeadjust */
+int
+gs_setstrokeadjust(gs_state *pgs, bool stroke_adjust)
+{ pgs->stroke_adjust = stroke_adjust;
+ return 0;
+}
+
+/* currentstrokeadjust */
+bool
+gs_currentstrokeadjust(const gs_state *pgs)
+{ return pgs->stroke_adjust;
+}
+
+/* ------ Extensions ------ */
+
+/* Device-independent */
+
+/* setdashadapt */
+void
+gs_setdashadapt(gs_state *pgs, bool adapt)
+{ pgs_lp->dash.adapt = adapt;
+}
+
+/* currentdashadapt */
+bool
+gs_imager_currentdashadapt(const gs_imager_state *pis)
+{ return gs_currentlineparams_inline(pis)->dash.adapt;
+}
+bool
+gs_currentdashadapt(const gs_state *pgs)
+{ return gs_imager_currentdashadapt((const gs_imager_state *)pgs);
+}
+
+/* Device-dependent */
+
+/* setaccuratecurves */
+void
+gs_setaccuratecurves(gs_state *pgs, bool accurate)
+{ pgs->accurate_curves = accurate;
+}
+
+/* currentaccuratecurves */
+bool
+gs_imager_currentaccuratecurves(const gs_imager_state *pis)
+{ return pis->accurate_curves;
+}
+bool
+gs_currentaccuratecurves(const gs_state *pgs)
+{ return gs_imager_currentaccuratecurves((const gs_imager_state *)pgs);
+}
+
+/* setdotlength */
+int
+gx_set_dot_length(gx_line_params *plp, floatp length, bool absolute)
+{ if ( length < 0 )
+ return_error(gs_error_rangecheck);
+ plp->dot_length = length;
+ plp->dot_length_absolute = absolute;
+ return 0;
+}
+int
+gs_setdotlength(gs_state *pgs, floatp length, bool absolute)
+{ return gx_set_dot_length(pgs_lp, length, absolute);
+}
+
+/* currentdotlength */
+float
+gs_currentdotlength(const gs_state *pgs)
+{ return pgs_lp->dot_length;
+}
+bool
+gs_currentdotlength_absolute(const gs_state *pgs)
+{ return pgs_lp->dot_length_absolute;
+}
diff --git a/gs/src/gsline.h b/gs/src/gsline.h
new file mode 100644
index 000000000..f98204760
--- /dev/null
+++ b/gs/src/gsline.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsline.h */
+/* Line parameter and quality definitions */
+
+#ifndef gsline_INCLUDED
+# define gsline_INCLUDED
+
+#include "gslparam.h"
+
+/* Procedures */
+int gs_setlinewidth(P2(gs_state *, floatp));
+float gs_currentlinewidth(P1(const gs_state *));
+int gs_setlinecap(P2(gs_state *, gs_line_cap));
+gs_line_cap
+ gs_currentlinecap(P1(const gs_state *));
+int gs_setlinejoin(P2(gs_state *, gs_line_join));
+gs_line_join
+ gs_currentlinejoin(P1(const gs_state *));
+int gs_setmiterlimit(P2(gs_state *, floatp));
+float gs_currentmiterlimit(P1(const gs_state *));
+int gs_setdash(P4(gs_state *, const float *, uint, floatp));
+uint gs_currentdash_length(P1(const gs_state *));
+const float *
+ gs_currentdash_pattern(P1(const gs_state *));
+float gs_currentdash_offset(P1(const gs_state *));
+int gs_setflat(P2(gs_state *, floatp));
+float gs_currentflat(P1(const gs_state *));
+int gs_setstrokeadjust(P2(gs_state *, bool));
+bool gs_currentstrokeadjust(P1(const gs_state *));
+
+/* Extensions */
+void gs_setaccuratecurves(P2(gs_state *, bool));
+bool gs_currentaccuratecurves(P1(const gs_state *));
+void gs_setdashadapt(P2(gs_state *, bool));
+bool gs_currentdashadapt(P1(const gs_state *));
+int gs_setdotlength(P3(gs_state *, floatp, bool));
+float gs_currentdotlength(P1(const gs_state *));
+bool gs_currentdotlength_absolute(P1(const gs_state *));
+
+/* Imager-level procedures */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+int gs_imager_setflat(P2(gs_imager_state *, floatp));
+bool gs_imager_currentdashadapt(P1(const gs_imager_state *));
+bool gs_imager_currentaccuratecurves(P1(const gs_imager_state *));
+
+#endif /* gsline_INCLUDED */
diff --git a/gs/src/gslparam.h b/gs/src/gslparam.h
new file mode 100644
index 000000000..de1c82494
--- /dev/null
+++ b/gs/src/gslparam.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gslparam.h */
+/* Line parameter definitions */
+
+#ifndef gslparam_INCLUDED
+# define gslparam_INCLUDED
+
+/* Line cap values */
+typedef enum {
+ gs_cap_butt = 0,
+ gs_cap_round = 1,
+ gs_cap_square = 2,
+ gs_cap_triangle = 3 /* not supported by PostScript */
+} gs_line_cap;
+#define gs_line_cap_max 3
+
+/* Line join values */
+typedef enum {
+ gs_join_miter = 0,
+ gs_join_round = 1,
+ gs_join_bevel = 2,
+ gs_join_none = 3, /* not supported by PostScript */
+ gs_join_triangle = 4 /* not supported by PostScript */
+} gs_line_join;
+#define gs_line_join_max 4
+
+#endif /* gslparam_INCLUDED */
diff --git a/gs/src/gsmatrix.c b/gs/src/gsmatrix.c
new file mode 100644
index 000000000..c1f0c3d21
--- /dev/null
+++ b/gs/src/gsmatrix.c
@@ -0,0 +1,426 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmatrix.c */
+/* Matrix operators for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+
+/* The identity matrix */
+private gs_matrix gs_identity_matrix =
+ { identity_matrix_body };
+
+/* ------ Matrix creation ------ */
+
+/* Create an identity matrix */
+void
+gs_make_identity(gs_matrix *pmat)
+{ *pmat = gs_identity_matrix;
+}
+
+/* Create a translation matrix */
+int
+gs_make_translation(floatp dx, floatp dy, gs_matrix *pmat)
+{ *pmat = gs_identity_matrix;
+ pmat->tx = dx;
+ pmat->ty = dy;
+ return 0;
+}
+
+/* Create a scaling matrix */
+int
+gs_make_scaling(floatp sx, floatp sy, gs_matrix *pmat)
+{ *pmat = gs_identity_matrix;
+ pmat->xx = sx;
+ pmat->yy = sy;
+ return 0;
+}
+
+/* Create a rotation matrix. */
+/* The angle is in degrees. */
+int
+gs_make_rotation(floatp ang, gs_matrix *pmat)
+{ gs_sincos_t sincos;
+ gs_sincos_degrees(ang, &sincos);
+ pmat->yy = pmat->xx = sincos.cos;
+ pmat->xy = sincos.sin;
+ pmat->yx = -sincos.sin;
+ pmat->tx = pmat->ty = 0.0;
+ return 0;
+}
+
+/* ------ Matrix arithmetic ------ */
+
+/* Multiply two matrices. We should check for floating exceptions, */
+/* but for the moment it's just too awkward. */
+/* Since this is used heavily, we check for shortcuts. */
+int
+gs_matrix_multiply(const gs_matrix *pm1, const gs_matrix *pm2, gs_matrix *pmr)
+{ double xx1 = pm1->xx, yy1 = pm1->yy;
+ double tx1 = pm1->tx, ty1 = pm1->ty;
+ double xx2 = pm2->xx, yy2 = pm2->yy;
+ double xy2 = pm2->xy, yx2 = pm2->yx;
+ if ( is_xxyy(pm1) )
+ { pmr->tx = tx1 * xx2 + pm2->tx;
+ pmr->ty = ty1 * yy2 + pm2->ty;
+ if ( is_fzero(xy2) )
+ pmr->xy = 0;
+ else
+ pmr->xy = xx1 * xy2,
+ pmr->ty += tx1 * xy2;
+ pmr->xx = xx1 * xx2;
+ if ( is_fzero(yx2) )
+ pmr->yx = 0;
+ else
+ pmr->yx = yy1 * yx2,
+ pmr->tx += ty1 * yx2;
+ pmr->yy = yy1 * yy2;
+ }
+ else
+ { double xy1 = pm1->xy, yx1 = pm1->yx;
+ pmr->xx = xx1 * xx2 + xy1 * yx2;
+ pmr->xy = xx1 * xy2 + xy1 * yy2;
+ pmr->yy = yx1 * xy2 + yy1 * yy2;
+ pmr->yx = yx1 * xx2 + yy1 * yx2;
+ pmr->tx = tx1 * xx2 + ty1 * yx2 + pm2->tx;
+ pmr->ty = tx1 * xy2 + ty1 * yy2 + pm2->ty;
+ }
+ return 0;
+}
+
+/* Invert a matrix. Return gs_error_undefinedresult if not invertible. */
+int
+gs_matrix_invert(const gs_matrix *pm, gs_matrix *pmr)
+{ /* We have to be careful about fetch/store order, */
+ /* because pm might be the same as pmr. */
+ if ( is_xxyy(pm) )
+ { if ( is_fzero(pm->xx) || is_fzero(pm->yy) )
+ return_error(gs_error_undefinedresult);
+ pmr->tx = - (pmr->xx = 1.0 / pm->xx) * pm->tx;
+ pmr->xy = 0.0;
+ pmr->yx = 0.0;
+ pmr->ty = - (pmr->yy = 1.0 / pm->yy) * pm->ty;
+ }
+ else
+ { double det = pm->xx * pm->yy - pm->xy * pm->yx;
+ double mxx = pm->xx, mtx = pm->tx;
+ if ( det == 0 )
+ return_error(gs_error_undefinedresult);
+ pmr->xx = pm->yy / det;
+ pmr->xy = - pm->xy / det;
+ pmr->yx = - pm->yx / det;
+ pmr->yy = mxx / det; /* xx is already changed */
+ pmr->tx = - (mtx * pmr->xx + pm->ty * pmr->yx);
+ pmr->ty = - (mtx * pmr->xy + pm->ty * pmr->yy); /* tx ditto */
+ }
+ return 0;
+}
+
+/* Translate a matrix, possibly in place. */
+int
+gs_matrix_translate(const gs_matrix *pm, floatp dx, floatp dy, gs_matrix *pmr)
+{ gs_point trans;
+ int code = gs_distance_transform(dx, dy, pm, &trans);
+ if ( code < 0 )
+ return code;
+ if ( pmr != pm )
+ *pmr = *pm;
+ pmr->tx += trans.x;
+ pmr->ty += trans.y;
+ return 0;
+}
+
+/* Scale a matrix, possibly in place. */
+int
+gs_matrix_scale(const gs_matrix *pm, floatp sx, floatp sy, gs_matrix *pmr)
+{ pmr->xx = pm->xx * sx;
+ pmr->xy = pm->xy * sx;
+ pmr->yx = pm->yx * sy;
+ pmr->yy = pm->yy * sy;
+ if ( pmr != pm )
+ { pmr->tx = pm->tx;
+ pmr->ty = pm->ty;
+ }
+ return 0;
+}
+
+/* Rotate a matrix, possibly in place. The angle is in degrees. */
+int
+gs_matrix_rotate(const gs_matrix *pm, floatp ang, gs_matrix *pmr)
+{ double mxx, mxy;
+ gs_sincos_t sincos;
+ gs_sincos_degrees(ang, &sincos);
+ mxx = pm->xx, mxy = pm->xy;
+ pmr->xx = sincos.cos * mxx + sincos.sin * pm->yx;
+ pmr->xy = sincos.cos * mxy + sincos.sin * pm->yy;
+ pmr->yx = sincos.cos * pm->yx - sincos.sin * mxx;
+ pmr->yy = sincos.cos * pm->yy - sincos.sin * mxy;
+ if ( pmr != pm )
+ { pmr->tx = pm->tx;
+ pmr->ty = pm->ty;
+ }
+ return 0;
+}
+
+/* ------ Coordinate transformations (floating point) ------ */
+
+/* Note that all the transformation routines take separate */
+/* x and y arguments, but return their result in a point. */
+
+/* Transform a point. */
+int
+gs_point_transform(floatp x, floatp y, const gs_matrix *pmat,
+ gs_point *ppt)
+{ ppt->x = x * pmat->xx + pmat->tx;
+ ppt->y = y * pmat->yy + pmat->ty;
+ if ( !is_fzero(pmat->yx) )
+ ppt->x += y * pmat->yx;
+ if ( !is_fzero(pmat->xy) )
+ ppt->y += x * pmat->xy;
+ return 0;
+}
+
+/* Inverse-transform a point. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+int
+gs_point_transform_inverse(floatp x, floatp y, const gs_matrix *pmat,
+ gs_point *ppt)
+{ if ( is_xxyy(pmat) )
+ { if ( is_fzero(pmat->xx) || is_fzero(pmat->yy) )
+ return_error(gs_error_undefinedresult);
+ ppt->x = (x - pmat->tx) / pmat->xx;
+ ppt->y = (y - pmat->ty) / pmat->yy;
+ return 0;
+ }
+ else if ( is_xyyx(pmat) )
+ { if ( is_fzero(pmat->xy) || is_fzero(pmat->yx) )
+ return_error(gs_error_undefinedresult);
+ ppt->x = (y - pmat->ty) / pmat->xy;
+ ppt->y = (x - pmat->tx) / pmat->yx;
+ return 0;
+ }
+ else
+ { /* There are faster ways to do this, */
+ /* but we won't implement one unless we have to. */
+ gs_matrix imat;
+ int code = gs_matrix_invert(pmat, &imat);
+ if ( code < 0 )
+ return code;
+ return gs_point_transform(x, y, &imat, ppt);
+ }
+}
+
+/* Transform a distance. */
+int
+gs_distance_transform(floatp dx, floatp dy, const gs_matrix *pmat,
+ gs_point *pdpt)
+{ pdpt->x = dx * pmat->xx;
+ pdpt->y = dy * pmat->yy;
+ if ( !is_fzero(pmat->yx) )
+ pdpt->x += dy * pmat->yx;
+ if ( !is_fzero(pmat->xy) )
+ pdpt->y += dx * pmat->xy;
+ return 0;
+}
+
+/* Inverse-transform a distance. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+int
+gs_distance_transform_inverse(floatp dx, floatp dy,
+ const gs_matrix *pmat, gs_point *pdpt)
+{ if ( is_xxyy(pmat) )
+ { if ( is_fzero(pmat->xx) || is_fzero(pmat->yy) )
+ return_error(gs_error_undefinedresult);
+ pdpt->x = dx / pmat->xx;
+ pdpt->y = dy / pmat->yy;
+ }
+ else if ( is_xyyx(pmat) )
+ { if ( is_fzero(pmat->xy) || is_fzero(pmat->yx) )
+ return_error(gs_error_undefinedresult);
+ pdpt->x = dy / pmat->xy;
+ pdpt->y = dx / pmat->yx;
+ }
+ else
+ { double det = pmat->xx * pmat->yy - pmat->xy * pmat->yx;
+ if ( det == 0 )
+ return_error(gs_error_undefinedresult);
+ pdpt->x = (dx * pmat->yy - dy * pmat->yx) / det;
+ pdpt->y = (dy * pmat->xx - dx * pmat->xy) / det;
+ }
+ return 0;
+}
+
+/* Compute the bounding box of 4 points. */
+int
+gs_points_bbox(const gs_point pts[4], gs_rect *pbox)
+{
+#define assign_min_max(vmin, vmax, v0, v1)\
+ if ( v0 < v1 ) vmin = v0, vmax = v1; else vmin = v1, vmax = v0
+#define assign_min_max_4(vmin, vmax, v0, v1, v2, v3)\
+ { double min01, max01, min23, max23;\
+ assign_min_max(min01, max01, v0, v1);\
+ assign_min_max(min23, max23, v2, v3);\
+ vmin = min(min01, min23);\
+ vmax = max(max01, max23);\
+ }
+ assign_min_max_4(pbox->p.x, pbox->q.x,
+ pts[0].x, pts[1].x, pts[2].x, pts[3].x);
+ assign_min_max_4(pbox->p.y, pbox->q.y,
+ pts[0].y, pts[1].y, pts[2].y, pts[3].y);
+#undef assign_min_max
+#undef assign_min_max_4
+ return 0;
+}
+
+/* Transform or inverse-transform a bounding box. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+private int
+bbox_transform_either_only(const gs_rect *pbox_in, const gs_matrix *pmat,
+ gs_point pts[4],
+ int (*point_xform)(P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{ int code;
+ if ( (code = (*point_xform)(pbox_in->p.x, pbox_in->p.y, pmat, &pts[0])) < 0 ||
+ (code = (*point_xform)(pbox_in->p.x, pbox_in->q.y, pmat, &pts[1])) < 0 ||
+ (code = (*point_xform)(pbox_in->q.x, pbox_in->p.y, pmat, &pts[2])) < 0 ||
+ (code = (*point_xform)(pbox_in->q.x, pbox_in->q.y, pmat, &pts[3])) < 0
+ )
+ DO_NOTHING;
+ return code;
+}
+
+private int
+bbox_transform_either(const gs_rect *pbox_in, const gs_matrix *pmat,
+ gs_rect *pbox_out,
+ int (*point_xform)(P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{ int code;
+ /*
+ * In principle, we could transform only one point and two
+ * distance vectors; however, because of rounding, we will only
+ * get fully consistent results if we transform all 4 points.
+ * We must compute the max and min after transforming,
+ * since a rotation may be involved.
+ */
+ gs_point pts[4];
+ if ( (code = bbox_transform_either_only(pbox_in, pmat, pts, point_xform)) < 0 )
+ return code;
+ return gs_points_bbox(pts, pbox_out);
+}
+int
+gs_bbox_transform(const gs_rect *pbox_in, const gs_matrix *pmat,
+ gs_rect *pbox_out)
+{ return bbox_transform_either(pbox_in, pmat, pbox_out,
+ gs_point_transform);
+}
+int
+gs_bbox_transform_only(const gs_rect *pbox_in, const gs_matrix *pmat,
+ gs_point points[4])
+{ return bbox_transform_either_only(pbox_in, pmat, points,
+ gs_point_transform);
+}
+int
+gs_bbox_transform_inverse(const gs_rect *pbox_in, const gs_matrix *pmat,
+ gs_rect *pbox_out)
+{ return bbox_transform_either(pbox_in, pmat, pbox_out,
+ gs_point_transform_inverse);
+}
+
+/* ------ Coordinate transformations (to fixed point) ------ */
+
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+
+/* Transform a point with a fixed-point result. */
+int
+gs_point_transform2fixed(const gs_matrix_fixed *pmat,
+ floatp x, floatp y, gs_fixed_point *ppt)
+{ fixed px, py, t;
+ double dtemp;
+ int code;
+ if ( !pmat->txy_fixed_valid )
+ { /* The translation is out of range. Do the */
+ /* computation in floating point, and convert to */
+ /* fixed at the end. */
+ gs_point fpt;
+ gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt);
+ if ( !(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y)) )
+ return_error(gs_error_limitcheck);
+ ppt->x = float2fixed(fpt.x);
+ ppt->y = float2fixed(fpt.y);
+ return 0;
+ }
+ if ( !is_fzero(pmat->xy) )
+ { /* Hope for 90 degree rotation */
+ if ( (code = set_dfmul2fixed_vars(px, y, pmat->yx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, x, pmat->xy, dtemp)) < 0
+ )
+ return code;
+ if ( !is_fzero(pmat->xx) )
+ { if ( (code = set_dfmul2fixed_vars(t, x, pmat->xx, dtemp)) < 0 )
+ return code;
+ px += t; /* should check for overflow */
+ }
+ if ( !is_fzero(pmat->yy) )
+ { if ( (code = set_dfmul2fixed_vars(t, y, pmat->yy, dtemp)) < 0 )
+ return code;
+ py += t; /* should check for overflow */
+ }
+ }
+ else
+ { if ( (code = set_dfmul2fixed_vars(px, x, pmat->xx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, y, pmat->yy, dtemp)) < 0
+ )
+ return code;
+ if ( !is_fzero(pmat->yx) )
+ { if ( (code = set_dfmul2fixed_vars(t, y, pmat->yx, dtemp)) < 0 )
+ return code;
+ px += t; /* should check for overflow */
+ }
+ }
+ ppt->x = px + pmat->tx_fixed; /* should check for overflow */
+ ppt->y = py + pmat->ty_fixed; /* should check for overflow */
+ return 0;
+}
+
+/* Transform a distance with a fixed-point result. */
+int
+gs_distance_transform2fixed(const gs_matrix_fixed *pmat,
+ floatp dx, floatp dy, gs_fixed_point *ppt)
+{ fixed px, py, t;
+ double dtemp;
+ int code;
+ if ( (code = set_dfmul2fixed_vars(px, dx, pmat->xx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, dy, pmat->yy, dtemp)) < 0
+ )
+ return code;
+ if ( !is_fzero(pmat->yx) )
+ { if ( (code = set_dfmul2fixed_vars(t, dy, pmat->yx, dtemp)) < 0 )
+ return code;
+ px += t; /* should check for overflow */
+ }
+ if ( !is_fzero(pmat->xy) )
+ { if ( (code = set_dfmul2fixed_vars(t, dx, pmat->xy, dtemp)) < 0 )
+ return code;
+ py += t; /* should check for overflow */
+ }
+ ppt->x = px;
+ ppt->y = py;
+ return 0;
+}
diff --git a/gs/src/gsmatrix.h b/gs/src/gsmatrix.h
new file mode 100644
index 000000000..664373f93
--- /dev/null
+++ b/gs/src/gsmatrix.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmatrix.h */
+/* Definition of matrices and client interface to matrix routines */
+
+#ifndef gsmatrix_INCLUDED
+# define gsmatrix_INCLUDED
+
+/* See p. 65 of the PostScript manual for the semantics of */
+/* transformation matrices. */
+
+/* Structure for a transformation matrix. */
+#define _matrix_body\
+ float xx, xy, yx, yy, tx, ty
+struct gs_matrix_s {
+ _matrix_body;
+};
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+/* Macro for initializing constant matrices */
+#define constant_matrix_body(xx, xy, yx, yy, tx, ty)\
+ (float)(xx), (float)(xy), (float)(yx),\
+ (float)(yy), (float)(tx), (float)(ty)
+
+/* Macros for testing whether matrix coefficients are zero, */
+/* for shortcuts when the matrix is simple. */
+#define is_xxyy(pmat) is_fzero2((pmat)->xy, (pmat)->yx)
+#define is_xyyx(pmat) is_fzero2((pmat)->xx, (pmat)->yy)
+
+/* The identity matrix (for structure initialization) */
+#define identity_matrix_body\
+ constant_matrix_body(1, 0, 0, 1, 0, 0)
+
+/* Matrix creation */
+void gs_make_identity(P1(gs_matrix *));
+int gs_make_translation(P3(floatp, floatp, gs_matrix *)),
+ gs_make_scaling(P3(floatp, floatp, gs_matrix *)),
+ gs_make_rotation(P2(floatp, gs_matrix *));
+
+/* Matrix arithmetic */
+int gs_matrix_multiply(P3(const gs_matrix *, const gs_matrix *, gs_matrix *)),
+ gs_matrix_invert(P2(const gs_matrix *, gs_matrix *)),
+ gs_matrix_translate(P4(const gs_matrix *, floatp, floatp, gs_matrix *)),
+ gs_matrix_scale(P4(const gs_matrix *, floatp, floatp, gs_matrix *)),
+ gs_matrix_rotate(P3(const gs_matrix *, floatp, gs_matrix *));
+
+/* Coordinate transformation */
+int gs_point_transform(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_point_transform_inverse(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_distance_transform(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_distance_transform_inverse(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_points_bbox(P2(const gs_point [4], gs_rect *)),
+ gs_bbox_transform_only(P3(const gs_rect *, const gs_matrix *, gs_point [4])),
+ gs_bbox_transform(P3(const gs_rect *, const gs_matrix *, gs_rect *)),
+ gs_bbox_transform_inverse(P3(const gs_rect *, const gs_matrix *, gs_rect *));
+
+#endif /* gsmatrix_INCLUDED */
diff --git a/gs/src/gsmdebug.h b/gs/src/gsmdebug.h
new file mode 100644
index 000000000..8b3896cf3
--- /dev/null
+++ b/gs/src/gsmdebug.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmdebug.h */
+/* Debugging definitions for memory manager */
+/* Requires gdebug.h (for gs_debug) */
+
+/* Define the fill patterns used for debugging the allocator. */
+extern byte
+ gs_alloc_fill_alloc, /* allocated but not initialized */
+ gs_alloc_fill_block, /* locally allocated block */
+ gs_alloc_fill_collected, /* garbage collected */
+ gs_alloc_fill_deleted, /* locally deleted block */
+ gs_alloc_fill_free; /* freed */
+
+/* Define an alias for a specialized debugging flag */
+/* that used to be a separate variable. */
+#define gs_alloc_debug gs_debug['@']
+
+/* Conditionally fill unoccupied blocks with a pattern. */
+extern void gs_alloc_memset(P3(void *, int/*byte*/, ulong));
+#ifdef DEBUG
+/* The following peculiar syntax avoids incorrect capture of an 'else'. */
+# define gs_alloc_fill(ptr, fill, len)\
+ do { if ( gs_alloc_debug ) gs_alloc_memset(ptr, fill, (ulong)(len));\
+ } while ( 0 )
+#else
+# define gs_alloc_fill(ptr, fill, len)\
+ DO_NOTHING
+#endif
diff --git a/gs/src/gsmemfix.c b/gs/src/gsmemfix.c
new file mode 100644
index 000000000..9d86b08f8
--- /dev/null
+++ b/gs/src/gsmemfix.c
@@ -0,0 +1,414 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemfix.c Very simple fixed-block raw memory allocator */
+
+/* Initial version 02/03/1998 by John Desrosiers (soho@crl.com) */
+
+#include "memory_.h"
+#include "gsmemraw.h"
+#include "gsmemfix.h"
+
+/* --------------- Constants ---------------------- */
+
+#define gs_memfix_align 8 /* align memory to double */
+#define ChunkSignature 'CS'
+
+/* ------------- Structures ----------- */
+
+/* Allocated/free chunk */
+#define memfix_chunk_data\
+ long total_size; /* sizeof chunk including this overhead */\
+ short unsigned is_allocated
+struct memfix_chunk_data_s { memfix_chunk_data; };
+typedef struct memfix_chunk_s {
+ memfix_chunk_data;
+ /* ANSI C does not allow zero-size arrays, so we need the following */
+ /* unnecessary and wasteful workaround: */
+#define _npad (-size_of(struct memfix_chunk_data_s) & (gs_memfix_align - 1))
+ byte _pad[(_npad == 0 ? gs_memfix_align : _npad)];
+#undef _npad
+} gs_memfix_chunk;
+
+
+/* Fixed memory allocation block */
+typedef struct gs_memfix_alloc_block_s gs_memfix_alloc_block;
+#define memfix_alloc_block_data\
+ gs_memfix_alloc_block *next; /* next block, 0 if last one */\
+ long total_size; /* total # bytes in this block */\
+ byte *original_memory; /* memory as provided to add_raw */\
+ long original_memory_sizeof /* memory size as provided to add_raw */
+struct memfix_block_data_s { memfix_alloc_block_data; };
+struct gs_memfix_alloc_block_s {
+ memfix_alloc_block_data;
+#define _npad (-size_of(struct memfix_chunk_data_s) & (gs_memfix_align - 1))
+ byte _pad[(_npad == 0 ? gs_memfix_align : _npad)];
+#undef _npad
+ gs_memfix_chunk first_chunk; /* first chunk, not a pointer */
+};
+
+/* --------------- Forward Decl's ---------------------- */
+
+private void
+trim_and_allocate_chunk(P3(
+ gs_memfix *memfix, /* memfix to update */
+ gs_memfix_chunk *chunk, /* free chunk to allocate */
+ unsigned int bytes_to_alloc /* bytes to allocate */
+));
+
+private mem_proc_destructor(gs_memfix_destructor);
+private mem_proc_query_freespace(gs_memfix_query_freespace);
+private mem_proc_malloc(gs_memfix_malloc);
+private mem_proc_realloc(gs_memfix_realloc);
+private mem_proc_free(gs_memfix_free);
+
+
+/* -------------- Public Procedures ------------------------------------*/
+
+/* Construct an empty */
+void
+gs_memfix_constructor(
+ gs_memfix *memfix /* memfix to construct */
+) {
+ static gs_memraw_procs static_procs =
+ {
+ gs_memfix_destructor, gs_memfix_query_freespace,
+ gs_memfix_malloc, gs_memfix_realloc, gs_memfix_free
+ };
+ memfix->procs = static_procs;
+ memfix->total_universe = memfix->total_free = 0;
+ memfix->first = 0;
+ }
+
+/* Destruct a raw memory allocator */
+private void
+gs_memfix_destructor(
+ gs_memraw *memraw /* memory to destruct */
+) {
+ /* It'd be nice to dealloc mem, but there's nobody to hand it back to */
+ /* Should cascade down to superclasses, but there are none */
+ }
+
+/* Add raw memory block to a */
+int /* ret 0 if ok, -1 if error raw memory allocator */
+gs_memfix_add_raw(
+ gs_memfix *memfix, /* memory to add to */
+ byte *raw_memory, /* raw memory to add to */
+ long raw_sizeof /* sizeof raw memory */
+) {
+ byte *original_raw_memory = raw_memory;
+ long original_raw_sizeof = raw_sizeof;
+ gs_memfix_alloc_block *block;
+
+ /* Align address & length of block */
+ unsigned head_align = ( -(long)raw_memory ) & (gs_memfix_align - 1);
+ raw_memory += head_align;
+ raw_sizeof -= head_align;
+ raw_sizeof -= raw_sizeof & (gs_memfix_align - 1);
+ if ( raw_sizeof < sizeof(gs_memfix_alloc_block) )
+ return -1; /* if it's too small, spit it back */
+
+ block = (gs_memfix_alloc_block *)raw_memory;
+ block->original_memory = original_raw_memory;
+ block->original_memory_sizeof = original_raw_sizeof;
+ block->total_size = raw_sizeof;
+ block->next = memfix->first;
+ block->first_chunk.is_allocated = 0;
+ block->first_chunk.total_size
+ = raw_sizeof - sizeof(*block) + sizeof(block->first_chunk);
+
+ memfix->first = block;
+ memfix->total_universe += raw_sizeof - sizeof(*block);
+ memfix->total_free += raw_sizeof - sizeof(*block);
+
+ return 0;
+ }
+
+/* Remove the most recently added raw memory block from raw memory allocator */
+/* NB that, unless all blocks in block are unallocated, will be unusable */
+int /* returns size of returned memory, 0 if none */
+gs_memfix_remove_raw(
+ gs_memfix *memfix, /* memory to remove from */
+ byte **removed /* RETURNS pointer to removed memory */
+) {
+ gs_memfix_alloc_block *block = memfix->first;
+ if (block)
+ {
+ long original_sizeof = block->original_memory_sizeof;
+ *removed = block->original_memory;
+ memfix->total_universe
+ -= block->total_size - sizeof(gs_memfix_alloc_block);
+ memfix->total_free
+ -= block->total_size - sizeof(gs_memfix_alloc_block);
+ memfix->first = block->next;
+ return original_sizeof;
+ }
+ else
+ return 0;
+ }
+
+/* Return amount of free memory in raw memory allocator */
+private long /* # bytes free */
+gs_memfix_query_freespace(
+ gs_memraw *memraw /* mem device to operate on */
+) {
+ gs_memfix * const memfix = (gs_memfix *)memraw;
+ return memfix->total_free;
+ }
+
+/* Allocate requested # bytes from given raw memory allocator */
+private void* /* rets allocated bytes, 0 if none */
+gs_memfix_malloc(
+ gs_memraw *memraw, /* mem device to operate on */
+ unsigned int malloc_sizeof /* # bytes to malloc */
+) {
+ gs_memfix * const memfix = (gs_memfix *)memraw;
+ gs_memfix_alloc_block *block;
+ void *found_memory = 0;
+
+ /* All mallocs must allocate an aligned # of bytes & include overhead */
+ malloc_sizeof
+ += ( -(int)malloc_sizeof & (gs_memfix_align - 1) ) + sizeof(gs_memfix_chunk);
+
+ /* Search each allocation block for a free block of sufficient size */
+ for (block = memfix->first; !found_memory && block; block = block->next)
+ {
+ gs_memfix_chunk *limit_chunk
+ = (gs_memfix_chunk *)( (byte *)block + block->total_size );
+ gs_memfix_chunk *last_free = 0;
+ gs_memfix_chunk *chunk;
+
+ /* Search for first free chunk w/a sufficent free block */
+ for ( chunk = &block->first_chunk; chunk < limit_chunk;
+ chunk = (gs_memfix_chunk *)( (byte *)chunk + chunk->total_size ) )
+ {
+ if (chunk->is_allocated)
+ last_free = 0;
+ else
+ {
+ /* consolidate free chunks as we go */
+ if (last_free)
+ last_free->total_size += chunk->total_size;
+ else
+ last_free = chunk;
+ if (last_free->total_size >= malloc_sizeof)
+ {
+ /* found enough memory */
+ trim_and_allocate_chunk(memfix, last_free, malloc_sizeof);
+ found_memory = (void*)(last_free + 1);
+ break;
+ }
+ }
+ }
+ }
+ return found_memory;
+ }
+
+/* Deallocate memory taken from this raw memory allocator */
+private void
+gs_memfix_free(
+ gs_memraw *memraw, /* mem device to operate on */
+ void *raw /* memory to deallocate */
+) {
+ gs_memfix * const memfix = (gs_memfix *)memraw;
+ gs_memfix_chunk * const chunk = (gs_memfix_chunk *)raw - 1;
+
+ /* This prevents multiple & incorrect de-allocations */
+ if (raw && chunk->is_allocated == ChunkSignature)
+ {
+ memfix->total_free += chunk->total_size;
+ chunk->is_allocated = 0;
+ }
+ }
+
+/* Resize memory taken from this raw memory allocator */
+private void * /* address of reallocated block, 0 if error */
+gs_memfix_realloc(
+ gs_memraw *memraw, /* mem device to operate on */
+ void *old_raw, /* memory to reallocate */
+ unsigned int malloc_sizeof /* # bytes to malloc */
+) {
+ gs_memfix * const memfix = (gs_memfix *)memraw;
+ if (!old_raw || !malloc_sizeof)
+ /* Handle degenerate cases */
+ return !old_raw ? gs_memfix_malloc(memraw, malloc_sizeof)
+ : ( gs_memfix_free(memraw, old_raw), 0 );
+ else
+ {
+ /* Credible realloc, size can be GT, LT or approx EQ to original */
+ gs_memfix_chunk * const old_chunk = (gs_memfix_chunk *)old_raw - 1;
+ gs_memfix_chunk *new_chunk = 0;
+ long old_malloc_sizeof
+ = old_chunk->total_size - sizeof(gs_memfix_chunk);
+
+ /* All mallocs must allocate an aligned # of bytes & include overhead */
+ malloc_sizeof
+ += ( -(int)malloc_sizeof & (gs_memfix_align - 1) ) + sizeof(gs_memfix_chunk);
+
+ /* This prevents multiple & incorrect de-allocations */
+ if (old_chunk->is_allocated != ChunkSignature)
+ return 0; /* garbage input */
+
+ if (malloc_sizeof <= old_chunk->total_size)
+ {
+ /* Easy case: just shrink or maintain allocation */
+ memfix->total_free += old_chunk->total_size; /* pretend to deallocate */
+ trim_and_allocate_chunk(memfix, old_chunk, malloc_sizeof);
+ new_chunk = old_chunk;
+ }
+ else
+ {
+ /*
+ * Increase alloc'n. Try to:
+ * i ) Expand into any free space after curr block
+ * ii ) Expand into any free space before curr block & move memory
+ * iii) Find new mem space, copy old to new, delete old
+ */
+ /* First, have to find current allocation's block & position within */
+
+ /* Search allocation blocks for this block. Search for free space too */
+ long extra_bytes_needed = malloc_sizeof - old_chunk->total_size;
+ gs_memfix_alloc_block *found_block = 0;
+ gs_memfix_alloc_block *block;
+ for (block = memfix->first; !found_block && block;
+ block = block->next)
+ {
+ gs_memfix_chunk *limit_chunk
+ = (gs_memfix_chunk *)( (byte *)block + block->total_size );
+ gs_memfix_chunk *last_free;
+ gs_memfix_chunk *chunk;
+ gs_memfix_chunk *chunk_after;
+ long chunk_after_length;
+
+ /* Quickly eliminate this block if it doesn't encompass old_chunk */
+ if (old_chunk < &block->first_chunk || old_chunk >= limit_chunk)
+ continue;
+ found_block = block;
+
+ /* Consolidate free space after this chunk, grow old chunk into it */
+ chunk_after = (gs_memfix_chunk *)
+ ( (byte *)old_chunk + old_chunk->total_size );
+ chunk_after_length = 0;
+ for ( chunk = chunk_after; chunk < limit_chunk;
+ chunk = (gs_memfix_chunk *)( (byte *)chunk + chunk->total_size ) )
+ if (!chunk->is_allocated)
+ chunk_after_length += chunk->total_size;
+ else
+ break; /* no more freespace in block */
+ if (chunk_after_length)
+ {
+ chunk_after->total_size = chunk_after_length; /* consolidate tail pieces */
+
+ /* Grow chunk into freespace after it */
+ trim_and_allocate_chunk( memfix, chunk_after,
+ min(chunk_after_length, extra_bytes_needed) );
+ old_chunk->total_size += chunk_after->total_size;
+ if ( (extra_bytes_needed -= chunk_after->total_size) <= 0 )
+ {
+ new_chunk = old_chunk;
+ break; /* done */
+ }
+ }
+
+ /* Try to consolidate with free chunk before old one */
+
+ /* Search for last free chunk before old chunk */
+ last_free = 0;
+ for ( chunk = &block->first_chunk; chunk <= old_chunk;
+ chunk = (gs_memfix_chunk *)( (byte *)chunk + chunk->total_size ) )
+ {
+ if (!chunk->is_allocated)
+ {
+ /* consolidate free chunks as we go */
+ if (last_free)
+ last_free->total_size += chunk->total_size;
+ else
+ last_free = chunk;
+ }
+ else
+ if (chunk != old_chunk)
+ last_free = 0;
+ else
+ {
+ /* worked back up to old chunk */
+ if (last_free && last_free->total_size >= extra_bytes_needed)
+ {
+ /* There's an adequate free block before old chunk */
+ new_chunk = last_free;
+ memfix->total_free += old_chunk->total_size;
+ new_chunk->total_size += old_chunk->total_size;
+ /* use memmove instead of memcpy since it handles overlap */
+ memmove( new_chunk + 1, old_chunk + 1,
+ old_chunk->total_size - sizeof(*old_chunk) );
+ trim_and_allocate_chunk(memfix, new_chunk, malloc_sizeof);
+ }
+ break; /* fail or success, no in-place reallocation possible */
+ }
+ }
+ }
+ }
+ /* Last-ditch maneuver: if no luck, try to alloc new & copy to it */
+ if (!new_chunk)
+ {
+ char *new_raw = gs_memfix_malloc(memraw, malloc_sizeof);
+ if (new_raw)
+ {
+ new_chunk = (gs_memfix_chunk *)new_raw - 1;
+ memcpy( new_raw, old_raw, old_chunk->total_size - sizeof(*old_chunk) );
+ gs_memfix_free(memraw, old_raw);
+ }
+ }
+
+ /* If ultimate failure, go back to original size; else return new chunk */
+ if (new_chunk)
+ return (new_chunk + 1); /* xvert chunk to its raw mem */
+ else
+ {
+ /* realloc fails, scale block back to original size, ret NULL */
+ gs_memfix_realloc(memraw, old_raw, old_malloc_sizeof);
+ return 0;
+ }
+ }
+ }
+
+/* -------------- Private Procedures ------------------------------------*/
+
+/* Trim & allocate a given free chunk */
+private void
+trim_and_allocate_chunk(
+ gs_memfix *memfix, /* memory to alloc from */
+ gs_memfix_chunk *chunk, /* free chunk to allocate */
+ unsigned int bytes_to_alloc /* bytes to allocate */
+) {
+ chunk->is_allocated = ChunkSignature;
+
+ /* if there's only a few bytes extra, lump them in with allocation*/
+ if (chunk->total_size
+ >= bytes_to_alloc + sizeof(gs_memfix_chunk) )
+ {
+ /* Make remaining part of block into new block */
+ gs_memfix_chunk *created = (gs_memfix_chunk *)
+ ( (byte *)chunk + bytes_to_alloc );
+ created->total_size = chunk->total_size - bytes_to_alloc;
+ created->is_allocated = 0;
+ chunk->total_size = bytes_to_alloc;
+ }
+
+ /* update book keeping */
+ memfix->total_free -= chunk->total_size;
+ }
diff --git a/gs/src/gsmemfix.h b/gs/src/gsmemfix.h
new file mode 100644
index 000000000..c4b7a4a4e
--- /dev/null
+++ b/gs/src/gsmemfix.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemfix.h Interface files for fixed-block raw memory allocator */
+
+/* Initial version 02/03/1998 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gsmemfix__INCLUDED)
+ #define gsmemfix__INCLUDED
+
+ #include "gsmemraw.h"
+
+
+struct gs_memfix_alloc_block_s; /* opaque */
+
+/*
+ * A raw-memory allocator. Subclasses may have state as well.
+ */
+#define gs_memfix_common\
+ gs_memraw_common;\
+ struct gs_memfix_alloc_block_s *first; /* first allocation block in chain */\
+ long total_universe; /* total # bytes in universe */\
+ long total_free /* total # bytes free */
+typedef struct gs_memfix_s {
+ gs_memfix_common;
+} gs_memfix;
+
+/* Constructor for gs_memfix's */
+void gs_memfix_constructor(gs_memfix *);
+
+/* Remove the most recently added raw memory block from pool */
+/* NB that, unless all blocks in block are unallocated, pool will be unusable */
+int /* returns size of returned memory, 0 if none */
+gs_memfix_remove_raw(P2(
+ gs_memfix *memfix, /* memory pool to remove from */
+ byte **removed /* RETURNS pointer to removed memory */
+));
+
+/* Add raw memory block to a pool */
+int /* ret 0 if ok, -1 if error */
+gs_memfix_add_raw(P3(
+ gs_memfix *memfix, /* memory pool to add to */
+ byte *raw_memory, /* raw memory to add to pool */
+ long raw_sizeof /* sizeof raw memory */
+));
+
+
+#endif /*!defined(gsmemfix__INCLUDED)*/
+
diff --git a/gs/src/gsmemlok.c b/gs/src/gsmemlok.c
new file mode 100644
index 000000000..d310dc786
--- /dev/null
+++ b/gs/src/gsmemlok.c
@@ -0,0 +1,320 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemlok.c */
+/* Monitor-locked heap memory allocator */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "gx.h"
+#include "gsmemlok.h"
+#include "gserrors.h"
+
+private gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes);
+private gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes_immovable);
+private gs_memory_proc_alloc_struct(gs_locked_alloc_struct);
+private gs_memory_proc_alloc_struct(gs_locked_alloc_struct_immovable);
+private gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array);
+private gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array_immovable);
+private gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array);
+private gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array_immovable);
+private gs_memory_proc_resize_object(gs_locked_resize_object);
+private gs_memory_proc_object_size(gs_locked_object_size);
+private gs_memory_proc_object_type(gs_locked_object_type);
+private gs_memory_proc_free_object(gs_locked_free_object);
+private gs_memory_proc_alloc_string(gs_locked_alloc_string);
+private gs_memory_proc_alloc_string(gs_locked_alloc_string_immovable);
+private gs_memory_proc_resize_string(gs_locked_resize_string);
+private gs_memory_proc_free_string(gs_locked_free_string);
+private gs_memory_proc_register_root(gs_locked_register_root);
+private gs_memory_proc_unregister_root(gs_locked_unregister_root);
+private gs_memory_proc_status(gs_locked_status);
+private gs_memory_proc_enable_free(gs_locked_enable_free);
+private gs_memory_procs_t locked_procs = {
+ gs_locked_alloc_bytes,
+ gs_locked_alloc_bytes_immovable,
+ gs_locked_alloc_struct,
+ gs_locked_alloc_struct_immovable,
+ gs_locked_alloc_byte_array,
+ gs_locked_alloc_byte_array_immovable,
+ gs_locked_alloc_struct_array,
+ gs_locked_alloc_struct_array_immovable,
+ gs_locked_resize_object,
+ gs_locked_object_size,
+ gs_locked_object_type,
+ gs_locked_free_object,
+ gs_locked_alloc_string,
+ gs_locked_alloc_string_immovable,
+ gs_locked_resize_string,
+ gs_locked_free_string,
+ gs_locked_register_root,
+ gs_locked_unregister_root,
+ gs_locked_status,
+ gs_locked_enable_free
+};
+
+/* ---------- Public constructors/destructors ---------- */
+
+/* Init some raw memory into a gs_memory_locked_t */
+int /* -ve error code or 0 */
+gs_memory_locked_construct(
+ gs_memory_locked_t *lmem, /* allocator to init */
+ gs_memory_t *target /* allocator to monitor lock */
+) {
+ /* Init the procedure vector from template */
+ lmem->procs = locked_procs;
+
+ lmem->target = target;
+
+ /* Allocate a monitor to serialize access to structures within */
+ lmem->monitor = gx_monitor_alloc(target);
+ return (lmem->monitor) ? 0 : gs_error_VMerror;
+ }
+
+/* Release resources held by a gs_memory_locked_t */
+void
+gs_memory_locked_destruct(
+ gs_memory_locked_t *lmem /* allocator to dnit */
+) {
+ gx_monitor_free(lmem->monitor);
+ lmem->monitor = 0;
+ lmem->target = 0;
+ }
+
+/* ---------- Accessors ------------- */
+
+/* Retrieve this allocator's target */
+gs_memory_t * /* returns target of this allocator */
+gs_memory_locked_query_target(
+ gs_memory_locked_t *lmem /* allocator to query */
+) {
+ return lmem->target;
+ }
+
+/* -------- Private members just wrap a monitor around a gs_memory_heap --- */
+
+/* Allocate various kinds of blocks. */
+private byte *
+gs_locked_alloc_bytes(gs_memory_t *mem, uint size, client_name_t cname)
+{ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_bytes)(lmem->target, size, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private byte *
+gs_locked_alloc_bytes_immovable(gs_memory_t *mem, uint size,
+ client_name_t cname)
+{ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_bytes_immovable)
+ (lmem->target, size, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void *
+gs_locked_alloc_struct(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ void *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_struct)(lmem->target, pstype, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void *
+gs_locked_alloc_struct_immovable(gs_memory_t *mem,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ void *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_struct_immovable)
+ (lmem->target, pstype, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private byte *
+gs_locked_alloc_byte_array(gs_memory_t *mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_byte_array)
+ (lmem->target, num_elements, elt_size, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private byte *
+gs_locked_alloc_byte_array_immovable(gs_memory_t *mem, uint num_elements,
+ uint elt_size, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_byte_array_immovable)
+ (lmem->target, num_elements, elt_size, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void *
+gs_locked_alloc_struct_array(gs_memory_t *mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ void *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_struct_array)
+ (lmem->target, num_elements, pstype, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void *
+gs_locked_alloc_struct_array_immovable(gs_memory_t *mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ void *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_struct_array_immovable)
+ (lmem->target, num_elements, pstype, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void *
+gs_locked_resize_object(gs_memory_t *mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ void *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.resize_object)(lmem->target, obj,
+ new_num_elements, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private uint
+gs_locked_object_size(gs_memory_t *mem, const void *ptr)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ uint temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.object_size)(lmem->target, ptr);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private gs_memory_type_ptr_t
+gs_locked_object_type(gs_memory_t *mem, const void *ptr)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gs_memory_type_ptr_t temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.object_type)(lmem->target, ptr);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void
+gs_locked_free_object(gs_memory_t *mem, void *ptr, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.free_object)(lmem->target, ptr, cname);
+ gx_monitor_leave(lmem->monitor);
+}
+private byte *
+gs_locked_alloc_string(gs_memory_t *mem, uint nbytes, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_string)(lmem->target, nbytes, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private byte *
+gs_locked_alloc_string_immovable(gs_memory_t *mem, uint nbytes,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.alloc_string_immovable)
+ (lmem->target, nbytes, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private byte *
+gs_locked_resize_string(gs_memory_t *mem, byte *data, uint old_num,
+ uint new_num,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ byte *temp;
+ gx_monitor_enter(lmem->monitor);
+ temp = (*lmem->target->procs.resize_string)(lmem->target, data,
+ old_num, new_num, cname);
+ gx_monitor_leave(lmem->monitor);
+ return temp;
+}
+private void
+gs_locked_free_string(gs_memory_t *mem, byte *data, uint nbytes,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.free_string)(lmem->target, data, nbytes, cname);
+ gx_monitor_leave(lmem->monitor);
+}
+private void
+gs_locked_register_root(gs_memory_t *mem, gs_gc_root_t *rp, gs_ptr_type_t ptype,
+ void **up, client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.register_root)(lmem->target, rp, ptype, up, cname);
+ gx_monitor_leave(lmem->monitor);
+}
+private void
+gs_locked_unregister_root(gs_memory_t *mem, gs_gc_root_t *rp,
+ client_name_t cname)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.unregister_root)(lmem->target, rp, cname);
+ gx_monitor_leave(lmem->monitor);
+}
+private void
+gs_locked_status(gs_memory_t *mem, gs_memory_status_t *pstat)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.status)(lmem->target, pstat);
+ gx_monitor_leave(lmem->monitor);
+}
+private void
+gs_locked_enable_free(gs_memory_t *mem, bool enable)
+{
+ gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
+ gx_monitor_enter(lmem->monitor);
+ (*lmem->target->procs.enable_free)(lmem->target, enable);
+ gx_monitor_leave(lmem->monitor);
+}
diff --git a/gs/src/gsmemlok.h b/gs/src/gsmemlok.h
new file mode 100644
index 000000000..6b5c392f4
--- /dev/null
+++ b/gs/src/gsmemlok.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemlok.h */
+/* Monitor-locked heap memory allocator */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gsmemlok__INCLUDED)
+ #define gsmemlok__INCLUDED
+
+ #include "gsmemory.h"
+ #include "gxsync.h"
+
+typedef struct gs_memory_locked_s {
+ gs_memory_common; /* interface outside world sees */
+ gs_memory_t *target; /* allocator to front */
+ gx_monitor_t *monitor; /* monitor to serialize access to functions */
+} gs_memory_locked_t;
+
+/* ---------- Public constructors/destructors ---------- */
+int /* -ve error code or 0 */
+gs_memory_locked_construct(P2(
+ gs_memory_locked_t *lmem, /* allocator to init */
+ gs_memory_t *target /* allocator to monitor lock */
+));
+void
+gs_memory_locked_destruct(P1(
+ gs_memory_locked_t *lmem /* allocator to dnit */
+));
+
+gs_memory_t * /* returns target of this allocator */
+gs_memory_locked_query_target(P1(
+ gs_memory_locked_t *lmem /* allocator to query */
+));
+#endif /*!defined(gsmemlok__INCLUDED)*/
+
diff --git a/gs/src/gsmemory.c b/gs/src/gsmemory.c
new file mode 100644
index 000000000..d8cf99ed2
--- /dev/null
+++ b/gs/src/gsmemory.c
@@ -0,0 +1,472 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemory.c */
+/* Generic allocator support for Ghostscript library */
+#include "gx.h"
+#include "malloc_.h"
+#include "memory_.h"
+#include "gsmdebug.h"
+#include "gsmemraw.h"
+#include "gsrefct.h" /* to check prototype */
+#include "gsstruct.h" /* ditto */
+
+/* Define the fill patterns for unallocated memory. */
+byte gs_alloc_fill_alloc = 0xa1;
+byte gs_alloc_fill_block = 0xb1;
+byte gs_alloc_fill_collected = 0xc1;
+byte gs_alloc_fill_deleted = 0xd1;
+byte gs_alloc_fill_free = 0xf1;
+
+/* A 'structure' type descriptor for free blocks. */
+gs_public_st_simple(st_free, byte, "(free)");
+
+/* The 'structure' type descriptor for bytes. */
+gs_public_st_simple(st_bytes, byte, "bytes");
+
+/* The descriptors for elements and arrays of const strings. */
+private_st_const_string();
+public_st_const_string_element();
+#define sptr ((gs_const_string *)vptr)
+private ENUM_PTRS_BEGIN(const_string_enum_ptrs) return 0;
+ case 0: *pep = (void *)sptr; return ptr_const_string_type;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(const_string_reloc_ptrs) {
+ gs_reloc_const_string(sptr, gcst);
+} RELOC_PTRS_END
+#undef sptr
+
+/* Fill an unoccupied block with a pattern. */
+/* Note that the block size may be too large for a single memset. */
+void
+gs_alloc_memset(void *ptr, int/*byte*/ fill, ulong lsize)
+{ ulong msize = lsize;
+ char *p = ptr;
+ int isize;
+
+ for ( ; msize; msize -= isize, p += isize )
+ { isize = min(msize, max_int);
+ memset(p, fill, isize);
+ }
+}
+
+/* ------ Heap allocator ------ */
+
+/*
+ * An implementation of Ghostscript's memory manager interface
+ * that works directly with the C heap. We keep track of all allocated
+ * blocks so we can free them at cleanup time.
+ */
+/* We must make sure that malloc_blocks leave the block aligned. */
+#define malloc_block_data\
+ malloc_block *next;\
+ malloc_block *prev;\
+ uint size;\
+ gs_memory_type_ptr_t type;\
+ client_name_t cname
+struct malloc_block_data_s { malloc_block_data; };
+struct malloc_block_s {
+ malloc_block_data;
+/* ANSI C does not allow zero-size arrays, so we need the following */
+/* unnecessary and wasteful workaround: */
+#define _npad (-size_of(struct malloc_block_data_s) & 7)
+ byte _pad[(_npad == 0 ? 8 : _npad)]; /* pad to double */
+#undef _npad
+};
+private gs_memory_proc_alloc_bytes(gs_heap_alloc_bytes);
+private gs_memory_proc_alloc_struct(gs_heap_alloc_struct);
+private gs_memory_proc_alloc_byte_array(gs_heap_alloc_byte_array);
+private gs_memory_proc_alloc_struct_array(gs_heap_alloc_struct_array);
+private gs_memory_proc_resize_object(gs_heap_resize_object);
+private gs_memory_proc_object_size(gs_heap_object_size);
+private gs_memory_proc_object_type(gs_heap_object_type);
+private gs_memory_proc_free_object(gs_heap_free_object);
+private gs_memory_proc_alloc_string(gs_heap_alloc_string);
+private gs_memory_proc_resize_string(gs_heap_resize_string);
+private gs_memory_proc_free_string(gs_heap_free_string);
+private gs_memory_proc_register_root(gs_heap_register_root);
+private gs_memory_proc_unregister_root(gs_heap_unregister_root);
+private gs_memory_proc_status(gs_heap_status);
+private gs_memory_proc_enable_free(gs_heap_enable_free);
+gs_memory_heap_t gs_memory_heap_default = {
+ { gs_heap_alloc_bytes,
+ gs_heap_alloc_bytes,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_resize_object,
+ gs_heap_object_size,
+ gs_heap_object_type,
+ gs_heap_free_object,
+ gs_heap_alloc_string,
+ gs_heap_alloc_string,
+ gs_heap_resize_string,
+ gs_heap_free_string,
+ gs_heap_register_root,
+ gs_heap_unregister_root,
+ gs_heap_status,
+ gs_heap_enable_free
+ },
+ gs_memory_heap_initial_values
+};
+
+
+/* The limit on allocable space is public. */
+long gs_malloc_limit = max_long;
+
+/* The record of maximum allocation is public. */
+long gs_malloc_max = 0; /* ref'd by XL */
+
+/* Initialize the malloc heap. */
+private long heap_available(P0());
+void
+gs_malloc_init(void)
+{ gs_memory_heap_construct(&gs_memory_heap_default, 0);
+}
+/* Estimate the amount of available memory by probing with mallocs. */
+/* We may under-estimate by a lot, but that's better than winding up with */
+/* a seriously inflated address space. */
+/* This is quite a hack! */
+#define max_malloc_probes 20
+#define malloc_probe_size 64000
+private long
+heap_available(void)
+{ long avail = 0;
+ void *probes[max_malloc_probes];
+ uint n;
+ for ( n = 0; n < max_malloc_probes; n++ )
+ { if ( (probes[n] = malloc(malloc_probe_size)) == 0 )
+ break;
+ if_debug2('a', "[a]heap_available probe[%d]=0x%lx\n",
+ n, (ulong)probes[n]);
+ avail += malloc_probe_size;
+ }
+ while ( n )
+ free(probes[--n]);
+ return avail;
+}
+
+/* Allocate various kinds of blocks. */
+private byte *
+gs_heap_alloc_bytes(gs_memory_t *mem, uint size, client_name_t cname)
+{ byte *ptr = 0;
+ gs_memory_heap_t * const hmem = (gs_memory_heap_t *)mem;
+#ifdef DEBUG
+ const char *msg;
+ static const char *ok_msg = "OK";
+# define set_msg(str) (msg = (str))
+#else
+# define set_msg(str) DO_NOTHING
+#endif
+ if ( size > gs_malloc_limit - sizeof(malloc_block)
+ )
+ { /* Definitely too large to allocate; also avoids overflow. */
+ set_msg("exceeded limit");
+ }
+ else
+ { uint added = size + sizeof(malloc_block);
+
+ if ( gs_malloc_limit - added < hmem->malloc_used )
+ set_msg("exceeded limit");
+ else if ( ( ptr = (byte *)( hmem->raw_memory
+ ? (*hmem->raw_memory->procs.malloc)(hmem->raw_memory, added)
+ : malloc(added) ) ) == 0 )
+ set_msg("failed");
+ else
+ { malloc_block *bp = (malloc_block *)ptr;
+
+ if ( hmem->malloc_list )
+ hmem->malloc_list->prev = bp;
+ bp->next = hmem->malloc_list;
+ bp->prev = 0;
+ bp->size = size;
+ bp->type = &st_bytes;
+ bp->cname = cname;
+ hmem->malloc_list = bp;
+ set_msg(ok_msg);
+ ptr = (byte *)(bp + 1);
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+ hmem->malloc_used += size + sizeof(malloc_block);
+ if ( hmem->malloc_used > hmem->malloc_max )
+ hmem->malloc_max = hmem->malloc_used;
+ }
+ }
+#ifdef DEBUG
+ { malloc_block *bp = hmem->malloc_list;
+ for ( ; bp; bp = bp->next)
+ ;
+ }
+#endif
+ return ptr;
+#undef set_msg
+}
+private void *
+gs_heap_alloc_struct(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{ void *ptr = gs_heap_alloc_bytes(mem, gs_struct_type_size(pstype), cname);
+ if ( ptr == 0 )
+ return 0;
+ ((malloc_block *)ptr)[-1].type = pstype;
+ return ptr;
+}
+private byte *
+gs_heap_alloc_byte_array(gs_memory_t *mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{ ulong lsize = (ulong)num_elements * elt_size;
+ if ( lsize != (uint)lsize )
+ return 0;
+ return gs_heap_alloc_bytes(mem, (uint)lsize, cname);
+}
+private void *
+gs_heap_alloc_struct_array(gs_memory_t *mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{ void *ptr = gs_heap_alloc_byte_array(mem, num_elements, gs_struct_type_size(pstype), cname);
+ if ( ptr == 0 )
+ return 0;
+ ((malloc_block *)ptr)[-1].type = pstype;
+ return ptr;
+}
+private void *
+gs_heap_resize_object(gs_memory_t *mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{ gs_memory_heap_t * const hmem = (gs_memory_heap_t *)mem;
+
+ malloc_block *ptr = (malloc_block *)obj - 1;
+ gs_memory_type_ptr_t pstype = ptr->type;
+ uint old_size = gs_object_size(mem, obj) + sizeof(malloc_block);
+ uint new_size =
+ gs_struct_type_size(pstype) * new_num_elements +
+ sizeof(malloc_block);
+ malloc_block *new_ptr = (malloc_block *)( hmem->raw_memory
+ ? (*hmem->raw_memory->procs.realloc)(hmem->raw_memory, ptr, new_size)
+ : gs_realloc(ptr, old_size, new_size) );
+
+ if ( new_ptr == 0 )
+ return 0;
+ if ( new_ptr->prev )
+ new_ptr->prev->next = new_ptr;
+ else
+ hmem->malloc_list = new_ptr;
+ if ( new_ptr->next )
+ new_ptr->next->prev = new_ptr;
+ new_ptr->size = new_size - sizeof(malloc_block);
+ hmem->malloc_used -= old_size;
+ hmem->malloc_used += new_size;
+ if ( new_size > old_size )
+ gs_alloc_fill((byte *)new_ptr + old_size,
+ gs_alloc_fill_alloc, new_size - old_size);
+ return new_ptr + 1;
+}
+private uint
+gs_heap_object_size(gs_memory_t *mem, const void *ptr)
+{ return ((const malloc_block *)ptr)[-1].size;
+}
+private gs_memory_type_ptr_t
+gs_heap_object_type(gs_memory_t *mem, const void *ptr)
+{ return ((const malloc_block *)ptr)[-1].type;
+}
+private void
+gs_heap_free_object(gs_memory_t *mem, void *ptr, client_name_t cname)
+{ gs_memory_heap_t * const hmem = (gs_memory_heap_t *)mem;
+ malloc_block *bp;
+
+ if (hmem->disable_free_object)
+ return;
+ bp = hmem->malloc_list;
+ if ( gs_debug_c('a') )
+ dprintf3("[a-]gs_free(%s) 0x%lx(%u)\n",
+ client_name_string(cname), (ulong)ptr,
+ (ptr == 0 ? 0 : ((malloc_block *)ptr)[-1].size));
+ if ( ptr == 0 )
+ return;
+ if ( ptr == bp + 1 )
+ { hmem->malloc_list = bp->next;
+ hmem->malloc_used -= bp->size + sizeof(malloc_block);
+ if ( hmem->malloc_list )
+ hmem->malloc_list->prev = 0;
+ gs_alloc_fill(bp, gs_alloc_fill_free,
+ bp->size + sizeof(malloc_block));
+ if (hmem->raw_memory)
+ (*hmem->raw_memory->procs.free)(hmem->raw_memory, bp);
+ else
+ free(bp);
+ }
+ else
+ { malloc_block *np;
+ char* free_this;
+ for ( ; (np = bp->next) != 0; bp = np )
+ { if ( ptr == np + 1 )
+ { bp->next = np->next;
+ if ( np->next )
+ np->next->prev = bp;
+ hmem->malloc_used -= np->size + sizeof(malloc_block);
+ gs_alloc_fill(np, gs_alloc_fill_free,
+ np->size + sizeof(malloc_block));
+ if (hmem->raw_memory)
+ (*hmem->raw_memory->procs.free)(hmem->raw_memory, np);
+ else
+ free(np);
+ return;
+ }
+ }
+ lprintf2("%s: free 0x%lx not found!\n",
+ client_name_string(cname), (ulong)ptr);
+ free_this = (char *)( (malloc_block *)ptr - 1 );
+ if (hmem->raw_memory)
+ (*hmem->raw_memory->procs.free)(hmem->raw_memory, free_this);
+ else
+ free(free_this);
+ }
+}
+private byte *
+gs_heap_alloc_string(gs_memory_t *mem, uint nbytes, client_name_t cname)
+{ return gs_heap_alloc_bytes(mem, nbytes, cname);
+}
+private byte *
+gs_heap_resize_string(gs_memory_t *mem, byte *data, uint old_num, uint new_num,
+ client_name_t cname)
+{ if ( gs_heap_object_type(mem, data) != &st_bytes )
+ { lprintf2("%s: resizing non-string 0x%lx!\n",
+ client_name_string(cname), (ulong)data);
+ }
+ return gs_heap_resize_object(mem, data, new_num, cname);
+}
+private void
+gs_heap_free_string(gs_memory_t *mem, byte *data, uint nbytes,
+ client_name_t cname)
+{ /****** SHOULD CHECK SIZE IF DEBUGGING ******/
+ gs_heap_free_object(mem, data, cname);
+}
+private void
+gs_heap_register_root(gs_memory_t *mem, gs_gc_root_t *rp, gs_ptr_type_t ptype,
+ void **up, client_name_t cname)
+{
+}
+private void
+gs_heap_unregister_root(gs_memory_t *mem, gs_gc_root_t *rp,
+ client_name_t cname)
+{
+}
+private void
+gs_heap_status(gs_memory_t *mem, gs_memory_status_t *pstat)
+{ gs_memory_heap_t * const hmem = (gs_memory_heap_t *)mem;
+
+ pstat->allocated = hmem->malloc_used + ( hmem->raw_memory
+ ? (*hmem->raw_memory->procs.query_freespace)(hmem->raw_memory)
+ : heap_available() );
+ pstat->used = hmem->malloc_used;
+}
+private void
+gs_heap_enable_free(gs_memory_t *mem, bool enable)
+{ gs_memory_heap_t * const hmem = (gs_memory_heap_t *)mem;
+ hmem->disable_free_object = !enable;
+}
+
+/* Release all malloc'ed blocks. */
+void
+gs_malloc_release(void)
+{ gs_memory_heap_t * const hmem = &gs_memory_heap_default;
+
+ malloc_block *bp = hmem->malloc_list;
+ malloc_block *np;
+ for ( ; bp != 0; bp = np )
+ { np = bp->next;
+ if ( gs_debug_c('a') )
+ dprintf3("[a]gs_malloc_release(%s) 0x%lx(%u)\n",
+ client_name_string(bp->cname), (ulong)(bp + 1),
+ bp->size);
+ gs_alloc_fill(bp + 1, gs_alloc_fill_free, bp->size);
+ if (hmem->raw_memory)
+ (*hmem->raw_memory->procs.free)(hmem->raw_memory, bp);
+ else
+ free(bp);
+ }
+ hmem->malloc_list = 0;
+ hmem->malloc_used = 0;
+}
+
+/* ------ Other memory management ------ */
+
+/* No-op pointer enumeration procedure */
+ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs) {
+ return 0;
+ENUM_PTRS_END_PROC }
+
+/* No-op pointer relocation procedure */
+RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs) {
+} RELOC_PTRS_END
+
+/* No-op freeing procedures */
+void
+gs_ignore_free_object(gs_memory_t *mem, void *data, client_name_t cname)
+{
+}
+void
+gs_ignore_free_string(gs_memory_t *mem, byte *data, uint nbytes,
+ client_name_t cname)
+{
+}
+
+/* Get the size of a structure from the descriptor. */
+uint
+gs_struct_type_size(gs_memory_type_ptr_t pstype)
+{ return pstype->ssize;
+}
+
+/* Get the name of a structure from the descriptor. */
+struct_name_t
+gs_struct_type_name(gs_memory_type_ptr_t pstype)
+{ return pstype->sname;
+}
+
+/* Normal freeing routine for reference-counted structures. */
+void
+rc_free_struct_only(gs_memory_t *mem, void *data, client_name_t cname)
+{ gs_free_object(mem, data, cname);
+}
+
+/* Public constructors/destructors for gs_memory_heap_t */
+int /* -ve error code or 0 */
+gs_memory_heap_construct(
+ gs_memory_heap_t *hmem, /* allocator to init */
+ gs_memraw *raw_memory /* underling raw memory allocator to use */
+)
+{
+ hmem->procs = gs_memory_heap_default.procs;
+ hmem->raw_memory = raw_memory;
+ hmem->malloc_list = 0;
+ hmem->malloc_used = 0;
+ hmem->malloc_max = 0;
+ hmem->disable_free_object = false;
+ return 0;
+}
+void
+gs_memory_heap_destruct(
+ gs_memory_heap_t *hmem /* allocator to dnit */
+)
+{}
+
+gs_memraw * /* rets raw memory allocator in this object */
+gs_memory_heap_get_raw(
+ gs_memory_heap_t *hmem /* allocator to operate on */
+)
+{ return hmem->raw_memory;
+}
diff --git a/gs/src/gsmemory.h b/gs/src/gsmemory.h
new file mode 100644
index 000000000..84e2ef18b
--- /dev/null
+++ b/gs/src/gsmemory.h
@@ -0,0 +1,390 @@
+/* Copyright (C) 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemory.h */
+/* Client interface for memory allocation */
+
+/*
+ * The allocator knows about two basic kinds of memory: objects, which are
+ * aligned and cannot have pointers to their interior, and strings, which are
+ * not aligned and which can have interior references.
+ *
+ * The standard allocator includes a garbage collector. The garbage
+ * collector normally may move objects, relocating pointers to them;
+ * however, objects may be declared immovable at the time of allocation.
+ * Clients must not attempt to resize immovable objects, and must not create
+ * references to substrings of immovable strings.
+ */
+
+#ifndef gsmemory_INCLUDED
+# define gsmemory_INCLUDED
+
+# include "gsmemraw.h"
+
+/*
+ * Define the (opaque) type for a structure descriptor. */
+typedef struct gs_memory_struct_type_s gs_memory_struct_type_t;
+typedef const gs_memory_struct_type_t *gs_memory_type_ptr_t;
+
+ /* Accessors for structure types. */
+
+typedef client_name_t struct_name_t;
+
+/* Get the size of a structure from the descriptor. */
+uint gs_struct_type_size(P1(gs_memory_type_ptr_t));
+
+/* Get the name of a structure from the descriptor. */
+struct_name_t gs_struct_type_name(P1(gs_memory_type_ptr_t));
+#define gs_struct_type_name_string(styp)\
+ ((const char *)gs_struct_type_name(styp))
+
+/* An opaque type for the garbage collector state. */
+/* We need this because it is passed to pointer implementation procedures. */
+typedef struct gc_state_s gc_state_t;
+
+/*
+ * A pointer type defines how to mark the referent of the pointer.
+ * We define it here so that we can define ptr_struct_type,
+ * which is needed so we can define gs_register_struct_root.
+ */
+typedef struct gs_ptr_procs_s {
+
+ /* Unmark the referent of a pointer. */
+
+#define ptr_proc_unmark(proc)\
+ void proc(P2(void *, gc_state_t *))
+ ptr_proc_unmark((*unmark));
+
+ /* Mark the referent of a pointer. */
+ /* Return true iff it was unmarked before. */
+
+#define ptr_proc_mark(proc)\
+ bool proc(P2(void *, gc_state_t *))
+ ptr_proc_mark((*mark));
+
+ /* Relocate a pointer. */
+ /* Note that the argument is const, but the */
+ /* return value is not: this shifts the compiler */
+ /* 'discarding const' warning from the call sites */
+ /* (the reloc_ptr routines) to the implementations. */
+
+#define ptr_proc_reloc(proc, typ)\
+ typ *proc(P2(const typ *, gc_state_t *))
+ ptr_proc_reloc((*reloc), void);
+
+} gs_ptr_procs_t;
+typedef const gs_ptr_procs_t _ds *gs_ptr_type_t;
+
+/* Define the pointer type for ordinary structure pointers. */
+extern const gs_ptr_procs_t ptr_struct_procs;
+#define ptr_struct_type (&ptr_struct_procs)
+
+/* Define the pointer types for a pointer to a gs_[const_]string. */
+extern const gs_ptr_procs_t ptr_string_procs;
+#define ptr_string_type (&ptr_string_procs)
+extern const gs_ptr_procs_t ptr_const_string_procs;
+#define ptr_const_string_type (&ptr_const_string_procs)
+
+/* Register a structure root. */
+#define gs_register_struct_root(mem, root, pp, cname)\
+ gs_register_root(mem, root, ptr_struct_type, pp, cname)
+
+/*
+ * Define the type for a GC root.
+ */
+typedef struct gs_gc_root_s gs_gc_root_t;
+struct gs_gc_root_s {
+ gs_gc_root_t *next;
+ gs_ptr_type_t ptype;
+ void **p;
+};
+
+/* Print a root debugging message. */
+#define if_debug_root(c, msg, rp)\
+ if_debug4(c, "%s 0x%lx: 0x%lx -> 0x%lx\n",\
+ msg, (ulong)(rp), (ulong)(rp)->p, (ulong)*(rp)->p)
+
+/* Define the type for memory manager statistics. */
+typedef struct gs_memory_status_s {
+ /*
+ * "Allocated" space is the total amount of space acquired from
+ * the parent of the memory manager. It includes space used for
+ * allocated data, space available for allocation, and overhead.
+ */
+ ulong allocated;
+ /*
+ * "Used" space is the amount of space used by allocated data
+ * plus overhead.
+ */
+ ulong used;
+} gs_memory_status_t;
+
+/*
+ * Define the memory manager procedural interface.
+ */
+struct gs_memory_s;
+typedef struct gs_memory_s gs_memory_t;
+typedef struct gs_memory_procs_s {
+
+ /*
+ * Allocate bytes. The bytes are always aligned maximally
+ * if the processor requires alignment.
+ */
+
+#define gs_memory_proc_alloc_bytes(proc)\
+ byte *proc(P3(gs_memory_t *mem, uint nbytes, client_name_t cname))
+#define gs_alloc_bytes(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_bytes)(mem, nbytes, cname)
+ gs_memory_proc_alloc_bytes((*alloc_bytes));
+#define gs_alloc_bytes_immovable(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_bytes_immovable)(mem, nbytes, cname)
+ gs_memory_proc_alloc_bytes((*alloc_bytes_immovable));
+
+ /*
+ * Allocate a structure.
+ */
+
+#define gs_memory_proc_alloc_struct(proc)\
+ void *proc(P3(gs_memory_t *mem, gs_memory_type_ptr_t pstype,\
+ client_name_t cname))
+#define gs_alloc_struct(mem, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct)(mem, pstype, cname)
+ gs_memory_proc_alloc_struct((*alloc_struct));
+#define gs_alloc_struct_immovable(mem, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_immovable)(mem, pstype, cname)
+ gs_memory_proc_alloc_struct((*alloc_struct_immovable));
+
+ /*
+ * Allocate an array of bytes.
+ */
+
+#define gs_memory_proc_alloc_byte_array(proc)\
+ byte *proc(P4(gs_memory_t *mem, uint num_elements, uint elt_size,\
+ client_name_t cname))
+#define gs_alloc_byte_array(mem, nelts, esize, cname)\
+ (*(mem)->procs.alloc_byte_array)(mem, nelts, esize, cname)
+ gs_memory_proc_alloc_byte_array((*alloc_byte_array));
+#define gs_alloc_byte_array_immovable(mem, nelts, esize, cname)\
+ (*(mem)->procs.alloc_byte_array_immovable)(mem, nelts, esize, cname)
+ gs_memory_proc_alloc_byte_array((*alloc_byte_array_immovable));
+
+ /*
+ * Allocate an array of structures.
+ */
+
+#define gs_memory_proc_alloc_struct_array(proc)\
+ void *proc(P4(gs_memory_t *mem, uint num_elements,\
+ gs_memory_type_ptr_t pstype, client_name_t cname))
+#define gs_alloc_struct_array(mem, nelts, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_array)(mem, nelts, pstype, cname)
+ gs_memory_proc_alloc_struct_array((*alloc_struct_array));
+#define gs_alloc_struct_array_immovable(mem, nelts, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_array_immovable)(mem, nelts, pstype, cname)
+ gs_memory_proc_alloc_struct_array((*alloc_struct_array_immovable));
+
+ /*
+ * Resize an object to a new number of elements, considering
+ * it as an array of bytes or structures. The new size may
+ * be either larger or smaller than the old.
+ */
+
+#define gs_memory_proc_resize_object(proc)\
+ void *proc(P4(gs_memory_t *mem, void *obj, uint new_num_elements,\
+ client_name_t cname))
+#define gs_resize_object(mem, obj, newn, cname)\
+ (*(mem)->procs.resize_object)(mem, obj, newn, cname)
+ gs_memory_proc_resize_object((*resize_object));
+
+ /*
+ * Get the size of an object (anything except a string).
+ */
+
+#define gs_memory_proc_object_size(proc)\
+ uint proc(P2(gs_memory_t *mem, const void *obj))
+#define gs_object_size(mem, obj)\
+ (*(mem)->procs.object_size)(mem, obj)
+ gs_memory_proc_object_size((*object_size));
+
+ /*
+ * Get the type of an object (anything except a string).
+ * The value returned for byte objects is useful only for
+ * printing.
+ */
+
+#define gs_memory_proc_object_type(proc)\
+ gs_memory_type_ptr_t proc(P2(gs_memory_t *mem, const void *obj))
+#define gs_object_type(mem, obj)\
+ (*(mem)->procs.object_type)(mem, obj)
+ gs_memory_proc_object_type((*object_type));
+
+ /*
+ * Free an object (anything except a string).
+ * Note: data == 0 must be allowed, and must be a no-op.
+ */
+
+#define gs_memory_proc_free_object(proc)\
+ void proc(P3(gs_memory_t *mem, void *data, client_name_t cname))
+#define gs_free_object(mem, data, cname)\
+ (*(mem)->procs.free_object)(mem, data, cname)
+ gs_memory_proc_free_object((*free_object));
+
+ /*
+ * Allocate a string (unaligned bytes).
+ */
+
+#define gs_memory_proc_alloc_string(proc)\
+ byte *proc(P3(gs_memory_t *mem, uint nbytes, client_name_t cname))
+#define gs_alloc_string(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_string)(mem, nbytes, cname)
+ gs_memory_proc_alloc_string((*alloc_string));
+#define gs_alloc_string_immovable(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_string_immovable)(mem, nbytes, cname)
+ gs_memory_proc_alloc_string((*alloc_string_immovable));
+
+ /*
+ * Resize a string.
+ */
+
+#define gs_memory_proc_resize_string(proc)\
+ byte *proc(P5(gs_memory_t *mem, byte *data, uint old_num, uint new_num,\
+ client_name_t cname))
+#define gs_resize_string(mem, data, oldn, newn, cname)\
+ (*(mem)->procs.resize_string)(mem, data, oldn, newn, cname)
+ gs_memory_proc_resize_string((*resize_string));
+
+ /*
+ * Free a string.
+ */
+
+#define gs_memory_proc_free_string(proc)\
+ void proc(P4(gs_memory_t *mem, byte *data, uint nbytes,\
+ client_name_t cname))
+#define gs_free_string(mem, data, nbytes, cname)\
+ (*(mem)->procs.free_string)(mem, data, nbytes, cname)
+ gs_memory_proc_free_string((*free_string));
+
+ /*
+ * Register a root for the garbage collector.
+ */
+
+#define gs_memory_proc_register_root(proc)\
+ void proc(P5(gs_memory_t *mem, gs_gc_root_t *root, gs_ptr_type_t ptype,\
+ void **pp, client_name_t cname))
+#define gs_register_root(mem, root, ptype, pp, cname)\
+ (*(mem)->procs.register_root)(mem, root, ptype, pp, cname)
+ gs_memory_proc_register_root((*register_root));
+
+ /*
+ * Unregister a root.
+ */
+
+#define gs_memory_proc_unregister_root(proc)\
+ void proc(P3(gs_memory_t *mem, gs_gc_root_t *root, client_name_t cname))
+#define gs_unregister_root(mem, root, cname)\
+ (*(mem)->procs.unregister_root)(mem, root, cname)
+ gs_memory_proc_unregister_root((*unregister_root));
+
+ /*
+ * Report status (assigned, used).
+ */
+
+#define gs_memory_proc_status(proc)\
+ void proc(P2(gs_memory_t *mem, gs_memory_status_t *status))
+#define gs_memory_status(mem, pst)\
+ (*(mem)->procs.status)(mem, pst)
+ gs_memory_proc_status((*status));
+
+ /*
+ * Enable or disable the freeing operations: when disabled,
+ * these operations return normally but do nothing. The
+ * garbage collector and the PostScript interpreter
+ * 'restore' operator need to temporarily disable the
+ * freeing functions of (an) allocator(s) while running
+ * finalization procedures.
+ */
+
+#define gs_memory_proc_enable_free(proc)\
+ void proc(P2(gs_memory_t *mem, bool enable))
+#define gs_enable_free(mem, enable)\
+ (*(mem)->procs.enable_free)(mem, enable)
+ gs_memory_proc_enable_free((*enable_free));
+
+} gs_memory_procs_t;
+
+/* Define no-op freeing procedures for use by enable_free. */
+gs_memory_proc_free_object(gs_ignore_free_object);
+gs_memory_proc_free_string(gs_ignore_free_string);
+
+/*
+ * An allocator instance. Subclasses may have state as well.
+ */
+#define gs_memory_common\
+ gs_memory_procs_t procs
+struct gs_memory_s {
+ gs_memory_common;
+};
+
+/* ----- A heap-based memory allocator -------- */
+
+/*
+ * A heap-based allocator instance, subclassed from gs_memory_common.
+ * This may be subclassed further; subclasses may have their own state.
+ */
+typedef struct malloc_block_s malloc_block; /* opaque */
+#define gs_memory_heap_common\
+ gs_memory_common;\
+ malloc_block *malloc_list; /* head of list of allocated blocks */\
+ long malloc_used; /* # bytes allocated herein */\
+ long malloc_max; /* record of max mem allocation */\
+ bool disable_free_object; /* true if disable free_object fn */\
+ gs_memraw *raw_memory /* device used to alloc raw memory */
+typedef struct gs_memory_heap_s {
+ gs_memory_heap_common;
+} gs_memory_heap_t;
+#define gs_memory_heap_initial_values 0, 0, 0, 0, 0
+
+/* Public constructors/destructors */
+int /* -ve error code or 0 */
+gs_memory_heap_construct(P2(
+ gs_memory_heap_t *hmem, /* allocator to init */
+ gs_memraw *raw_memory /* underlying raw memory allocator, 0 if C heap */
+));
+void
+gs_memory_heap_destruct(P1(
+ gs_memory_heap_t *hmem /* allocator to dnit */
+));
+
+/* accessors */
+gs_memraw * /* rets raw memory allocator in this object */
+gs_memory_heap_get_raw(P1(
+ gs_memory_heap_t *hmem /* allocator to operate on */
+));
+
+
+/*
+ * gs_malloc and gs_free are historical artifacts, but we still need
+ * a memory manager instance that allocates directly from the C heap.
+ */
+extern gs_memory_heap_t gs_memory_heap_default;
+#define gs_memory_default ( *(gs_memory_t *)(&gs_memory_heap_default) )
+#define gs_malloc(nelts, esize, cname)\
+ (void *)gs_alloc_byte_array(&gs_memory_default, nelts, esize, cname)
+#define gs_free(data, nelts, esize, cname)\
+ gs_free_object(&gs_memory_default, data, cname)
+
+#endif /* gsmemory_INCLUDED */
diff --git a/gs/src/gsmemraw.h b/gs/src/gsmemraw.h
new file mode 100644
index 000000000..241907054
--- /dev/null
+++ b/gs/src/gsmemraw.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmemraw.h Abstract raw-memory allocator */
+
+/* Initial version 02/03/1998 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gsmemraw__INCLUDED)
+ #define gsmemraw__INCLUDED
+
+typedef struct gs_memraw_s gs_memraw;
+
+/* Procedure vector for accessing raw memory allocator */
+typedef struct gs_memraw_procs_s {
+ /* There is no constructor here. Constructors for subclasses must */
+ /* be called statically: each constructor must *first* call its */
+ /* superclass' constructor, then do its own init. */
+
+ /* Destuctor: subclasses destruct their own stuff first, then call */
+ /* superclass' destructor. */
+#define mem_proc_destructor(proc)\
+ void proc(P1(gs_memraw *))
+ mem_proc_destructor((*destructor));
+
+ /* Query freespace */
+#define mem_proc_query_freespace(proc)\
+ long proc (P1(gs_memraw *))
+ mem_proc_query_freespace((*query_freespace));
+
+ /* malloc */
+#define mem_proc_malloc(proc)\
+ void *proc (P2(gs_memraw *, unsigned int))
+ mem_proc_malloc((*malloc));
+
+ /* realloc */
+#define mem_proc_realloc(proc)\
+ void *proc (P3(gs_memraw *, void *, unsigned int))
+ mem_proc_realloc((*realloc));
+
+ /* free */
+#define mem_proc_free(proc)\
+ void proc(P2(gs_memraw *, void*))
+ mem_proc_free((*free));
+} gs_memraw_procs;
+
+
+/*
+ * An abstract raw-memory allocator instance. Subclasses may have state as well.
+ */
+#define gs_memraw_common\
+ gs_memraw_procs procs
+
+struct gs_memraw_s {
+ gs_memraw_common;
+};
+
+#endif /*!defined(gsmemraw__INCLUDED)*/
+
diff --git a/gs/src/gsmisc.c b/gs/src/gsmisc.c
new file mode 100644
index 000000000..a4090d4ef
--- /dev/null
+++ b/gs/src/gsmisc.c
@@ -0,0 +1,815 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsmisc.c */
+/* Miscellaneous utilities for Ghostscript library */
+#include "malloc_.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gpcheck.h" /* for gs_return_check_interrupt */
+#include "gserrors.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gxfarith.h"
+#include "gxfixed.h"
+
+/* Define private replacements for stdin, stdout, and stderr. */
+FILE *gs_stdin, *gs_stdout, *gs_stderr;
+/* Ghostscript writes debugging output to gs_debug_out. */
+/* We define gs_debug and gs_debug_out even if DEBUG isn't defined, */
+/* so that we can compile individual modules with DEBUG set. */
+char gs_debug[128];
+FILE *gs_debug_out;
+
+/* Define eprintf_program_name and lprintf_file_and_line as procedures */
+/* so one can set breakpoints on them. */
+void
+eprintf_program_name(FILE *f, const char *program_name)
+{ fprintf(f, "%s: ", program_name);
+}
+void
+lprintf_file_and_line(FILE *f, const char *file, int line)
+{ fprintf(f, "%s(%d): ", file, line);
+}
+
+/* Log an error return. We always include this, in case other */
+/* modules were compiled with DEBUG set. */
+#undef gs_log_error /* in case DEBUG isn't set */
+int
+gs_log_error(int err, const char _ds *file, int line)
+{ if ( gs_log_errors )
+ { if ( file == NULL )
+ dprintf1("Returning error %d.\n", err);
+ else
+ dprintf3("%s(%d): Returning error %d.\n",
+ (const char *)file, line, err);
+ }
+ return err;
+}
+
+/* Check for interrupts before a return. */
+int
+gs_return_check_interrupt(int code)
+{ if ( code < 0 )
+ return code;
+ { int icode = gp_check_interrupts();
+ return (icode == 0 ? code :
+ gs_note_error((icode > 0 ? gs_error_interrupt : icode)));
+ }
+}
+
+/* ------ Substitutes for missing C library functions ------ */
+
+#ifdef memory__need_memmove /* see memory_.h */
+/* Copy bytes like memcpy, guaranteed to handle overlap correctly. */
+/* ANSI C defines the returned value as being the src argument, */
+/* but with the const restriction removed! */
+void *
+gs_memmove(void *dest, const void *src, size_t len)
+{ if ( !len )
+ return (void *)src;
+#define bdest ((byte *)dest)
+#define bsrc ((const byte *)src)
+ /* We use len-1 for comparisons because adding len */
+ /* might produce an offset overflow on segmented systems. */
+ if ( ptr_le(bdest, bsrc) )
+ { register byte *end = bdest + (len - 1);
+ if ( ptr_le(bsrc, end) )
+ { /* Source overlaps destination from above. */
+ register const byte *from = bsrc;
+ register byte *to = bdest;
+ for ( ; ; )
+ { *to = *from;
+ if ( to >= end ) /* faster than = */
+ return (void *)src;
+ to++; from++;
+ }
+ }
+ }
+ else
+ { register const byte *from = bsrc + (len - 1);
+ if ( ptr_le(bdest, from) )
+ { /* Source overlaps destination from below. */
+ register const byte *end = bsrc;
+ register byte *to = bdest + (len - 1);
+ for ( ; ; )
+ { *to = *from;
+ if ( from <= end ) /* faster than = */
+ return (void *)src;
+ to--; from--;
+ }
+ }
+ }
+#undef bdest
+#undef bsrc
+ /* No overlap, it's safe to use memcpy. */
+ memcpy(dest, src, len);
+ return (void *)src;
+}
+#endif
+
+#ifdef memory__need_memchr /* see memory_.h */
+/* ch should obviously be char rather than int, */
+/* but the ANSI standard declaration uses int. */
+const char *
+gs_memchr(const char *ptr, int ch, size_t len)
+{ if ( len > 0 )
+ { register const char *p = ptr;
+ register uint count = len;
+ do { if ( *p == (char)ch ) return p; p++; } while ( --count );
+ }
+ return 0;
+}
+#endif
+
+#ifdef memory__need_memset /* see memory_.h */
+/* ch should obviously be char rather than int, */
+/* but the ANSI standard declaration uses int. */
+void *
+gs_memset(void *dest, register int ch, size_t len)
+{ if ( ch == 0 )
+ bzero(dest, len);
+ else if ( len > 0 )
+ { register char *p = dest;
+ register uint count = len;
+ do { *p++ = (char)ch; } while ( --count );
+ }
+ return dest;
+}
+#endif
+
+#ifdef malloc__need_realloc /* see malloc_.h */
+/* Some systems have non-working implementations of realloc. */
+void *
+gs_realloc(void *old_ptr, size_t old_size, size_t new_size)
+{ void *new_ptr;
+ if ( new_size )
+ { new_ptr = malloc(new_size);
+ if ( new_ptr == NULL )
+ return NULL;
+ }
+ else
+ new_ptr = NULL;
+ /* We have to pass in the old size, since we have no way to */
+ /* determine it otherwise. */
+ if ( old_ptr != NULL )
+ { if ( new_ptr != NULL )
+ memcpy(new_ptr, old_ptr, min(old_size, new_size));
+ free(old_ptr);
+ }
+ return new_ptr;
+}
+#endif
+
+/* ------ Debugging support ------ */
+
+/* Dump a region of memory. */
+void
+debug_dump_bytes(const byte *from, const byte *to, const char *msg)
+{ const byte *p = from;
+ if ( from < to && msg )
+ dprintf1("%s:\n", msg);
+ while ( p != to )
+ { const byte *q = min(p + 16, to);
+ dprintf1("0x%lx:", (ulong)p);
+ while ( p != q ) dprintf1(" %02x", *p++);
+ dputc('\n');
+ }
+}
+
+/* Dump a bitmap. */
+void
+debug_dump_bitmap(const byte *bits, uint raster, uint height, const char *msg)
+{ uint y;
+ const byte *data = bits;
+ for ( y = 0; y < height; ++y, data += raster )
+ debug_dump_bytes(data, data + raster, (y == 0 ? msg : NULL));
+}
+
+/* Print a string. */
+void
+debug_print_string(const byte *chrs, uint len)
+{ uint i;
+ for ( i = 0; i < len; i++ )
+ dputc(chrs[i]);
+ fflush(dstderr);
+}
+
+/* ------ Arithmetic ------ */
+
+/* Compute M modulo N. Requires N > 0; guarantees 0 <= imod(M,N) < N, */
+/* regardless of the whims of the % operator for negative operands. */
+int
+imod(int m, int n)
+{ if ( n <= 0 )
+ return 0; /* sanity check */
+ if ( m >= 0 )
+ return m % n;
+ { int r = -m % n;
+ return (r == 0 ? 0 : n - r);
+ }
+}
+
+/* Compute the GCD of two integers. */
+int
+igcd(int x, int y)
+{ int c = x, d = y;
+ if ( c < 0 ) c = -c;
+ if ( d < 0 ) d = -d;
+ while ( c != 0 && d != 0 )
+ if ( c > d ) c %= d;
+ else d %= c;
+ return d + c; /* at most one is non-zero */
+}
+
+#if defined(set_fmul2fixed_vars) && !USE_ASM
+
+/*
+ * Floating multiply with fixed result, for avoiding floating point in
+ * common coordinate transformations. Assumes IEEE representation,
+ * 16-bit short, 32-bit long. Optimized for the case where the first
+ * operand has no more than 16 mantissa bits, e.g., where it is a user space
+ * coordinate (which are often integers).
+ *
+ * The assembly language version of this code is actually faster than
+ * the FPU, if the code is compiled with FPU_TYPE=0 (which requires taking
+ * a trap on every FPU operation). If there is no FPU, the assembly
+ * language version of this code is over 10 times as fast as the emulated FPU.
+ */
+/* Some of the following code has been tweaked for the Borland 16-bit */
+/* compiler. The tweaks do not change the algorithms. */
+#if arch_ints_are_short && !defined(FOR80386)
+# define SHORT_ARITH
+#endif
+int
+set_fmul2fixed_(fixed *pr, long /*float*/ a, long /*float*/ b)
+{
+#ifdef SHORT_ARITH
+# define long_rsh8_ushort(x)\
+ (((ushort)(x) >> 8) | ((ushort)((ulong)(x) >> 16) << 8))
+# define utemp ushort
+#else
+# define long_rsh8_ushort(x) ((ushort)((x) >> 8))
+# define utemp ulong
+#endif
+ /* utemp may be either ushort or ulong. This is OK because */
+ /* we only use ma and mb in multiplications involving */
+ /* a long or ulong operand. */
+ utemp ma = long_rsh8_ushort(a) | 0x8000;
+ utemp mb = long_rsh8_ushort(b) | 0x8000;
+ int e = 260 + _fixed_shift - ((
+ (((uint)((ulong)a >> 16)) & 0x7f80) +
+ (((uint)((ulong)b >> 16)) & 0x7f80)
+ ) >> 7);
+ ulong p1 = ma * (b & 0xff);
+ ulong p = (ulong)ma * mb;
+#define p_bits (size_of(p) * 8)
+
+ if ( (byte)a ) /* >16 mantissa bits */
+ { ulong p2 = (a & 0xff) * mb;
+ p += ((((uint)(byte)a * (uint)(byte)b) >> 8) + p1 + p2) >> 8;
+ }
+ else
+ p += p1 >> 8;
+ if ( (uint)e < p_bits ) /* e = -1 is possible */
+ p >>= e;
+ else if ( e >= p_bits ) /* also detects a=0 or b=0 */
+ { *pr = fixed_0;
+ return 0;
+ }
+ else if ( e >= -(p_bits - 1) || p >= 1L << (p_bits - 1 + e) )
+ return_error(gs_error_limitcheck);
+ else
+ p <<= -e;
+ *pr = ((a ^ b) < 0 ? -p : p);
+ return 0;
+}
+int
+set_dfmul2fixed_(fixed *pr, ulong /*double lo*/ xalo, long /*float*/ b, long /*double hi*/ xahi)
+{
+#ifdef SHORT_ARITH
+# define long_lsh3(x) ((((x) << 1) << 1) << 1)
+# define long_rsh(x,ng16) ((uint)((x) >> 16) >> (ng16 - 16))
+#else
+# define long_lsh3(x) ((x) << 3)
+# define long_rsh(x,ng16) ((x) >> ng16)
+#endif
+ return set_fmul2fixed_(pr,
+ (xahi & 0xc0000000) +
+ (long_lsh3(xahi) & 0x3ffffff8) +
+ long_rsh(xalo, 29),
+ b);
+}
+
+#endif
+
+#if USE_FPU_FIXED
+
+/*
+ * Convert from floating point to fixed point with scaling.
+ * These are efficient algorithms for FPU-less machines.
+ */
+#define mbits_float 23
+#define mbits_double 20
+int
+set_float2fixed_(fixed *pr, long /*float*/ vf, int frac_bits)
+{ fixed mantissa;
+ int shift;
+
+ if ( !(vf & 0x7f800000) )
+ { *pr = fixed_0;
+ return 0;
+ }
+ mantissa = (fixed)((vf & 0x7fffff) | 0x800000);
+ shift = ((vf >> 23) & 255) - (127 + 23) + frac_bits;
+ if ( shift >= 0 )
+ { if ( shift >= sizeof(fixed) * 8 - 24 )
+ return_error(gs_error_limitcheck);
+ if ( vf < 0 )
+ mantissa = -mantissa;
+ *pr = (fixed)(mantissa << shift);
+ }
+ else
+ *pr = (shift < -24 ? fixed_0 :
+ vf < 0 ? -(fixed)(mantissa >> -shift) : /* truncate */
+ (fixed)(mantissa >> -shift));
+ return 0;
+}
+int
+set_double2fixed_(fixed *pr, ulong /*double lo*/ lo,
+ long /*double hi*/ hi, int frac_bits)
+{ fixed mantissa;
+ int shift;
+
+ if ( !(hi & 0x7ff00000) )
+ { *pr = fixed_0;
+ return 0;
+ }
+ /* We only use 31 bits of mantissa even if sizeof(long) > 4. */
+ mantissa = (fixed)(((hi & 0xfffff) << 10) | (lo >> 22) | 0x40000000);
+ shift = ((hi >> 20) & 2047) - (1023 + 30) + frac_bits;
+ if ( shift > 0 )
+ return_error(gs_error_limitcheck);
+ *pr = (shift < -30 ? fixed_0 :
+ hi < 0 ? -(fixed)(mantissa >> -shift) : /* truncate */
+ (fixed)(mantissa >> -shift));
+ return 0;
+}
+/*
+ * Given a fixed value x with fbits bits of fraction, set v to the mantissa
+ * (left-justified in 32 bits) and f to the exponent word of the
+ * corresponding floating-point value with mbits bits of mantissa in the
+ * first word. (The exponent part of f is biased by -1, because we add the
+ * top 1-bit of the mantissa to it.)
+ */
+static const byte f2f_shifts[] =
+ { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
+#define f2f_declare(v, f)\
+ ulong v;\
+ long f
+#define f2f(x, v, f, mbits, fbits)\
+ if ( x < 0 )\
+ f = 0xc0000000 + (29 << mbits) - ((long)fbits << mbits), v = -x;\
+ else\
+ f = 0x40000000 + (29 << mbits) - ((long)fbits << mbits), v = x;\
+ if ( v < 0x8000 )\
+ v <<= 15, f -= 15 << mbits;\
+ if ( v < 0x800000 )\
+ v <<= 8, f -= 8 << mbits;\
+ if ( v < 0x8000000 )\
+ v <<= 4, f -= 4 << mbits;\
+ { int shift = f2f_shifts[v >> 28];\
+ v <<= shift, f -= shift << mbits;\
+ }
+long
+fixed2float_(fixed x, int frac_bits)
+{ f2f_declare(v, f);
+
+ if ( x == 0 )
+ return 0;
+ f2f(x, v, f, mbits_float, frac_bits);
+ return f + (((v >> 7) + 1) >> 1);
+}
+void
+set_fixed2double_(double *pd, fixed x, int frac_bits)
+{ f2f_declare(v, f);
+
+ if ( x == 0 )
+ { ((long *)pd)[1 - arch_is_big_endian] = 0;
+ ((ulong *)pd)[arch_is_big_endian] = 0;
+ }
+ else
+ { f2f(x, v, f, mbits_double, frac_bits);
+ ((long *)pd)[1 - arch_is_big_endian] = f + (v >> 11);
+ ((ulong *)pd)[arch_is_big_endian] = v << 21;
+ }
+}
+
+/*
+ * Compute A * B / C when 0 <= B < C and A * B exceeds (or might exceed)
+ * the capacity of a long.
+ */
+#ifdef DEBUG
+struct { long mnanb, mnab, manb, mab, mnc, mdq, mde, mds, mqh, mql; } fmq_stat;
+# define mincr(x) ++fmq_stat.x
+#else
+# define mincr(x) DO_NOTHING
+#endif
+fixed
+fixed_mult_quo(fixed signed_A, fixed B, fixed C)
+{ /* First compute A * B in double-fixed precision. */
+ ulong A = (signed_A < 0 ? -signed_A : signed_A);
+ long msw;
+ ulong lsw;
+ ulong p1;
+
+#define num_bits (sizeof(fixed) * 8)
+#define half_bits (num_bits / 2)
+#define half_mask ((1L << half_bits) - 1)
+ if ( B <= half_mask )
+ { if ( A <= half_mask )
+ { fixed Q = (ulong)(A * B) / (ulong)C;
+
+ mincr(mnanb);
+ return (signed_A < 0 ? -Q : Q);
+ }
+ /*
+ * We might still have C <= half_mask, which we can
+ * handle with a simpler algorithm.
+ */
+ lsw = (A & half_mask) * B;
+ p1 = (A >> half_bits) * B;
+ if ( C <= half_mask )
+ { ulong q0 = (p1 += lsw >> half_bits) / C;
+ ulong rem = ((p1 - C * q0) << half_bits) + (lsw & half_mask);
+ ulong Q = (q0 << half_bits) + rem / C;
+
+ mincr(mnc);
+ return (signed_A < 0 ? -Q : Q);
+ }
+ msw = p1 >> half_bits;
+ mincr(manb);
+ }
+ else if ( A <= half_mask )
+ { p1 = A * (B >> half_bits);
+ msw = p1 >> half_bits;
+ lsw = A * (B & half_mask);
+ mincr(mnab);
+ }
+ else
+ { /* We have to compute all 4 products. :-( */
+ ulong lo_A = A & half_mask;
+ ulong hi_A = A >> half_bits;
+ ulong lo_B = B & half_mask;
+ ulong hi_B = B >> half_bits;
+ ulong p1x = hi_A * lo_B;
+
+ msw = hi_A * hi_B;
+ lsw = lo_A * lo_B;
+ p1 = lo_A * hi_B;
+ if ( p1 > max_ulong - p1x )
+ msw += 1L << half_bits;
+ p1 += p1x;
+ msw += p1 >> half_bits;
+ mincr(mab);
+ }
+ /* Finish up by adding the low half of p1 to the high half of lsw. */
+#if max_fixed < max_long
+ p1 &= half_mask;
+#endif
+ p1 <<= half_bits;
+ if ( p1 > max_ulong - lsw )
+ msw++;
+ lsw += p1;
+ /*
+ * Now divide the double-length product by C. Note that we know msw
+ * < C (otherwise the quotient would overflow). Start by shifting
+ * (msw,lsw) and C left until C >= 1 << (num_bits - 1).
+ */
+ { ulong denom = C;
+ int shift = 0;
+
+#define bits_4th (num_bits / 4)
+ if ( denom < 1L << (num_bits - bits_4th) )
+ { mincr(mdq);
+ denom <<= bits_4th, shift += bits_4th;
+ }
+#undef bits_4th
+#define bits_8th (num_bits / 8)
+ if ( denom < 1L << (num_bits - bits_8th) )
+ { mincr(mde);
+ denom <<= bits_8th, shift += bits_8th;
+ }
+#undef bits_8th
+ while ( !(denom & (1L << (num_bits - 1))) )
+ { mincr(mds);
+ denom <<= 1, ++shift;
+ }
+ msw = (msw << shift) + (lsw >> (num_bits - shift));
+ lsw <<= shift;
+#if max_fixed < max_long
+ lsw &= (1L << (sizeof(fixed) * 8)) - 1;
+#endif
+ /* Compute a trial upper-half quotient. */
+ { ulong hi_D = denom >> half_bits;
+ ulong lo_D = denom & half_mask;
+ ulong hi_Q = (ulong)msw / hi_D;
+ /* hi_Q might be too high by 1 or 2, but it isn't too low. */
+ ulong p0 = hi_Q * hi_D;
+ ulong p1 = hi_Q * lo_D;
+ ulong hi_P;
+
+ while ( (hi_P = p0 + (p1 >> half_bits)) > msw ||
+ (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
+ )
+ { /* hi_Q was too high by 1. */
+ --hi_Q;
+ p0 -= hi_D;
+ p1 -= lo_D;
+ mincr(mqh);
+ }
+ p1 = (p1 & half_mask) << half_bits;
+ if ( p1 > lsw )
+ msw--;
+ lsw -= p1;
+ msw -= hi_P;
+ /* Now repeat to get the lower-half quotient. */
+ msw = (msw << half_bits) + (lsw >> half_bits);
+#if max_fixed < max_long
+ lsw &= half_mask;
+#endif
+ lsw <<= half_bits;
+ { ulong lo_Q = (ulong)msw / hi_D;
+ long Q;
+
+ p1 = lo_Q * lo_D;
+ p0 = lo_Q * hi_D;
+ while ( (hi_P = p0 + (p1 >> half_bits)) > msw ||
+ (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
+ )
+ { /* lo_Q was too high by 1. */
+ --lo_Q;
+ p0 -= hi_D;
+ p1 -= lo_D;
+ mincr(mql);
+ }
+ Q = (hi_Q << half_bits) + lo_Q;
+ return (signed_A < 0 ? -Q : Q);
+ }
+ }
+ }
+#undef half_bits
+#undef half_mask
+}
+
+#endif
+
+/* Trace calls on sqrt when debugging. */
+#undef sqrt
+extern double sqrt(P1(double));
+double
+gs_sqrt(double x, const char *file, int line)
+{ if ( gs_debug_c('~') )
+ { fprintf(stdout, "[~]sqrt(%g) at %s:%d\n",
+ x, (const char *)file, line);
+ fflush(stdout);
+ }
+ return sqrt(x);
+}
+
+/*
+ * Define sine and cosine functions that take angles in degrees rather than
+ * radians, and that are implemented efficiently on machines with slow
+ * (or no) floating point.
+ */
+#if USE_FPU < 0 /****** maybe should be <= 0 ? ******/
+
+#define sin0 0.00000000000000000
+#define sin1 0.01745240643728351
+#define sin2 0.03489949670250097
+#define sin3 0.05233595624294383
+#define sin4 0.06975647374412530
+#define sin5 0.08715574274765817
+#define sin6 0.10452846326765346
+#define sin7 0.12186934340514748
+#define sin8 0.13917310096006544
+#define sin9 0.15643446504023087
+#define sin10 0.17364817766693033
+#define sin11 0.19080899537654480
+#define sin12 0.20791169081775931
+#define sin13 0.22495105434386498
+#define sin14 0.24192189559966773
+#define sin15 0.25881904510252074
+#define sin16 0.27563735581699916
+#define sin17 0.29237170472273671
+#define sin18 0.30901699437494740
+#define sin19 0.32556815445715670
+#define sin20 0.34202014332566871
+#define sin21 0.35836794954530027
+#define sin22 0.37460659341591201
+#define sin23 0.39073112848927377
+#define sin24 0.40673664307580015
+#define sin25 0.42261826174069944
+#define sin26 0.43837114678907740
+#define sin27 0.45399049973954675
+#define sin28 0.46947156278589081
+#define sin29 0.48480962024633706
+#define sin30 0.50000000000000000
+#define sin31 0.51503807491005416
+#define sin32 0.52991926423320490
+#define sin33 0.54463903501502708
+#define sin34 0.55919290347074679
+#define sin35 0.57357643635104605
+#define sin36 0.58778525229247314
+#define sin37 0.60181502315204827
+#define sin38 0.61566147532565829
+#define sin39 0.62932039104983739
+#define sin40 0.64278760968653925
+#define sin41 0.65605902899050728
+#define sin42 0.66913060635885824
+#define sin43 0.68199836006249848
+#define sin44 0.69465837045899725
+#define sin45 0.70710678118654746
+#define sin46 0.71933980033865108
+#define sin47 0.73135370161917046
+#define sin48 0.74314482547739413
+#define sin49 0.75470958022277201
+#define sin50 0.76604444311897801
+#define sin51 0.77714596145697090
+#define sin52 0.78801075360672190
+#define sin53 0.79863551004729283
+#define sin54 0.80901699437494745
+#define sin55 0.81915204428899180
+#define sin56 0.82903757255504174
+#define sin57 0.83867056794542394
+#define sin58 0.84804809615642596
+#define sin59 0.85716730070211222
+#define sin60 0.86602540378443860
+#define sin61 0.87461970713939574
+#define sin62 0.88294759285892688
+#define sin63 0.89100652418836779
+#define sin64 0.89879404629916704
+#define sin65 0.90630778703664994
+#define sin66 0.91354545764260087
+#define sin67 0.92050485345244037
+#define sin68 0.92718385456678731
+#define sin69 0.93358042649720174
+#define sin70 0.93969262078590832
+#define sin71 0.94551857559931674
+#define sin72 0.95105651629515353
+#define sin73 0.95630475596303544
+#define sin74 0.96126169593831889
+#define sin75 0.96592582628906831
+#define sin76 0.97029572627599647
+#define sin77 0.97437006478523525
+#define sin78 0.97814760073380558
+#define sin79 0.98162718344766398
+#define sin80 0.98480775301220802
+#define sin81 0.98768834059513777
+#define sin82 0.99026806874157036
+#define sin83 0.99254615164132198
+#define sin84 0.99452189536827329
+#define sin85 0.99619469809174555
+#define sin86 0.99756405025982420
+#define sin87 0.99862953475457383
+#define sin88 0.99939082701909576
+#define sin89 0.99984769515639127
+#define sin90 1.00000000000000000
+
+private const double sin_table[361] = {
+ sin0,
+ sin1, sin2, sin3, sin4, sin5, sin6, sin7, sin8, sin9, sin10,
+ sin11, sin12, sin13, sin14, sin15, sin16, sin17, sin18, sin19, sin20,
+ sin21, sin22, sin23, sin24, sin25, sin26, sin27, sin28, sin29, sin30,
+ sin31, sin32, sin33, sin34, sin35, sin36, sin37, sin38, sin39, sin40,
+ sin41, sin42, sin43, sin44, sin45, sin46, sin47, sin48, sin49, sin50,
+ sin51, sin52, sin53, sin54, sin55, sin56, sin57, sin58, sin59, sin60,
+ sin61, sin62, sin63, sin64, sin65, sin66, sin67, sin68, sin69, sin70,
+ sin71, sin72, sin73, sin74, sin75, sin76, sin77, sin78, sin79, sin80,
+ sin81, sin82, sin83, sin84, sin85, sin86, sin87, sin88, sin89, sin90,
+ sin89, sin88, sin87, sin86, sin85, sin84, sin83, sin82, sin81, sin80,
+ sin79, sin78, sin77, sin76, sin75, sin74, sin73, sin72, sin71, sin70,
+ sin69, sin68, sin67, sin66, sin65, sin64, sin63, sin62, sin61, sin60,
+ sin59, sin58, sin57, sin56, sin55, sin54, sin53, sin52, sin51, sin50,
+ sin49, sin48, sin47, sin46, sin45, sin44, sin43, sin42, sin41, sin40,
+ sin39, sin38, sin37, sin36, sin35, sin34, sin33, sin32, sin31, sin30,
+ sin29, sin28, sin27, sin26, sin25, sin24, sin23, sin22, sin21, sin20,
+ sin19, sin18, sin17, sin16, sin15, sin14, sin13, sin12, sin11, sin10,
+ sin9, sin8, sin7, sin6, sin5, sin4, sin3, sin2, sin1, sin0,
+ -sin1, -sin2, -sin3, -sin4, -sin5, -sin6, -sin7, -sin8, -sin9, -sin10,
+-sin11, -sin12, -sin13, -sin14, -sin15, -sin16, -sin17, -sin18, -sin19, -sin20,
+-sin21, -sin22, -sin23, -sin24, -sin25, -sin26, -sin27, -sin28, -sin29, -sin30,
+-sin31, -sin32, -sin33, -sin34, -sin35, -sin36, -sin37, -sin38, -sin39, -sin40,
+-sin41, -sin42, -sin43, -sin44, -sin45, -sin46, -sin47, -sin48, -sin49, -sin50,
+-sin51, -sin52, -sin53, -sin54, -sin55, -sin56, -sin57, -sin58, -sin59, -sin60,
+-sin61, -sin62, -sin63, -sin64, -sin65, -sin66, -sin67, -sin68, -sin69, -sin70,
+-sin71, -sin72, -sin73, -sin74, -sin75, -sin76, -sin77, -sin78, -sin79, -sin80,
+-sin81, -sin82, -sin83, -sin84, -sin85, -sin86, -sin87, -sin88, -sin89, -sin90,
+-sin89, -sin88, -sin87, -sin86, -sin85, -sin84, -sin83, -sin82, -sin81, -sin80,
+-sin79, -sin78, -sin77, -sin76, -sin75, -sin74, -sin73, -sin72, -sin71, -sin70,
+-sin69, -sin68, -sin67, -sin66, -sin65, -sin64, -sin63, -sin62, -sin61, -sin60,
+-sin59, -sin58, -sin57, -sin56, -sin55, -sin54, -sin53, -sin52, -sin51, -sin50,
+-sin49, -sin48, -sin47, -sin46, -sin45, -sin44, -sin43, -sin42, -sin41, -sin40,
+-sin39, -sin38, -sin37, -sin36, -sin35, -sin34, -sin33, -sin32, -sin31, -sin30,
+-sin29, -sin28, -sin27, -sin26, -sin25, -sin24, -sin23, -sin22, -sin21, -sin20,
+-sin19, -sin18, -sin17, -sin16, -sin15, -sin14, -sin13, -sin12, -sin11, -sin10,
+ -sin9, -sin8, -sin7, -sin6, -sin5, -sin4, -sin3, -sin2, -sin1, -sin0
+};
+
+double
+gs_sin_degrees(double ang)
+{ int ipart;
+ if ( is_fneg(ang) )
+ ang = 180 - ang;
+ ipart = (int)ang;
+ if ( ipart >= 360 )
+ { int arem = ipart % 360;
+ ang -= (ipart - arem);
+ ipart = arem;
+ }
+ return
+ (ang == ipart ? sin_table[ipart] :
+ sin_table[ipart] + (sin_table[ipart+1] - sin_table[ipart]) *
+ (ang - ipart));
+}
+
+double
+gs_cos_degrees(double ang)
+{ int ipart;
+ if ( is_fneg(ang) )
+ ang = 90 - ang;
+ else
+ ang += 90;
+ ipart = (int)ang;
+ if ( ipart >= 360 )
+ { int arem = ipart % 360;
+ ang -= (ipart - arem);
+ ipart = arem;
+ }
+ return
+ (ang == ipart ? sin_table[ipart] :
+ sin_table[ipart] + (sin_table[ipart+1] - sin_table[ipart]) *
+ (ang - ipart));
+}
+
+void
+gs_sincos_degrees(double ang, gs_sincos_t *psincos)
+{ psincos->sin = gs_sin_degrees(ang);
+ psincos->cos = gs_cos_degrees(ang);
+}
+
+#else /* we have floating point */
+
+static const int isincos[5] = { 0, 1, 0, -1, 0 };
+
+double
+gs_sin_degrees(double ang)
+{ double quot = ang / 90;
+ if ( floor(quot) == quot )
+ { int quads = (int)fmod(quot, 4) & 3; /* & 3 because might be < 0 */
+ return isincos[quads];
+ }
+ return sin(ang * (M_PI / 180));
+}
+
+double
+gs_cos_degrees(double ang)
+{ double quot = ang / 90;
+ if ( floor(quot) == quot )
+ { int quads = (int)fmod(quot, 4) & 3; /* & 3 because might be < 0 */
+ return isincos[quads + 1];
+ }
+ return cos(ang * (M_PI / 180));
+}
+
+void
+gs_sincos_degrees(double ang, gs_sincos_t *psincos)
+{ double quot = ang / 90;
+ if ( floor(quot) == quot )
+ { int quads = (int)fmod(quot, 4) & 3; /* & 3 because might be < 0 */
+ psincos->sin = isincos[quads];
+ psincos->cos = isincos[quads + 1];
+ }
+ else
+ { double arad = ang * (M_PI / 180);
+ psincos->sin = sin(arad);
+ psincos->cos = cos(arad);
+ }
+}
+
+#endif /* USE_FPU */
diff --git a/gs/src/gsnogc.c b/gs/src/gsnogc.c
new file mode 100644
index 000000000..54721ec37
--- /dev/null
+++ b/gs/src/gsnogc.c
@@ -0,0 +1,329 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsnogc.c */
+/* String freelist implementation and ersatz garbage collector */
+#include "gx.h"
+#include "gsgc.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "gxalloc.h"
+
+/*
+ * We implement string freelists here, because they are only useful
+ * in non-garbage-collected environments.
+ */
+
+#define get2(ptr) (((ptr)[0] << 8) + (ptr)[1])
+#define put2(ptr, val) ((ptr)[0] = (val) >> 8, (ptr)[1] = (byte)(val))
+
+#define imem ((gs_ref_memory_t *)mem)
+
+/* Allocate a string. */
+/* Scan the current chunk's free list if the request is large enough. */
+/* Currently we require an exact match of the block size. */
+private byte *
+sf_alloc_string(gs_memory_t *mem, uint nbytes, client_name_t cname)
+{ if ( nbytes >= 40 && nbytes < imem->large_size )
+ { byte *base = csbase(&imem->cc);
+ byte *prev = 0;
+ uint offset = imem->cc.sfree;
+ uint next;
+ byte *ptr;
+
+ for ( ; offset != 0; prev = ptr, offset = next )
+ { ptr = base + offset;
+ next = get2(ptr + 2);
+ if ( get2(ptr) != nbytes )
+ continue;
+ /* Take this block. */
+ if ( prev == 0 )
+ imem->cc.sfree = next;
+ else
+ put2(prev + 2, next);
+ if_debug4('A', "[a%d:+>F]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong)ptr);
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, nbytes);
+ imem->lost.strings -= nbytes;
+ return ptr;
+ }
+ }
+ return (*gs_ref_memory_procs.alloc_string)(mem, nbytes, cname);
+}
+
+/* Free a string. */
+private void
+sf_free_string(gs_memory_t *mem, byte *str, uint size, client_name_t cname)
+{ chunk_t *cp;
+ uint str_offset;
+
+ if ( str == imem->cc.ctop )
+ { if_debug4('A', "[a%d:-> ]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), size, (ulong)str);
+ imem->cc.ctop += size;
+ gs_alloc_fill(str, gs_alloc_fill_free, size);
+ return;
+ }
+ if_debug4('A', "[a%d:->#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), size, (ulong)str);
+ imem->lost.strings += size;
+ if ( ptr_is_in_chunk(str, &imem->cc) )
+ cp = &imem->cc;
+ else
+ { chunk_locator_t loc;
+ loc.memory = imem;
+ loc.cp = imem->clast;
+ if ( !chunk_locate_ptr(str, &loc) )
+ return; /* something is probably wrong.... */
+ cp = loc.cp;
+ }
+ if ( str == cp->ctop )
+ { cp->ctop += size;
+ return;
+ }
+ str_offset = str - csbase(cp);
+ if ( size >= 4 )
+ { byte *prev;
+ uint next;
+
+ put2(str, size);
+ if ( cp->sfree == 0 || str_offset < cp->sfree )
+ { /* Put the string at the head of the free list. */
+ put2(str + 2, cp->sfree);
+ cp->sfree = str_offset;
+ return;
+ }
+ /* Insert the new string in address order. */
+ prev = csbase(cp) + cp->sfree;
+#ifdef DEBUG
+ if ( gs_debug_c('?') )
+ { if ( prev < str + size && prev + get2(prev) > str )
+ { lprintf4("freeing string 0x%lx(%u), overlaps 0x%lx(%u)!\n",
+ (ulong)str, size, (ulong)prev, get2(prev));
+ return;
+ }
+ }
+#endif
+ for ( ; ; )
+ { next = get2(prev + 2);
+#ifdef DEBUG
+ if ( gs_debug_c('?') && next != 0 )
+ { byte *pnext = csbase(cp) + next;
+ if ( pnext < str + size && pnext + get2(pnext) > str )
+ { lprintf4("freeing string 0x%lx(%u), overlaps 0x%lx(%u)!\n",
+ (ulong)str, size, (ulong)pnext, get2(pnext));
+ return;
+ }
+ }
+#endif
+ if ( next >= str_offset || next == 0 )
+ break;
+ prev = csbase(cp) + next;
+ }
+ put2(str + 2, next);
+ put2(prev + 2, str_offset);
+ gs_alloc_fill(str + 4, gs_alloc_fill_free, size - 4);
+ }
+ else
+ { /* Insert the string in the 1-byte free list(s). Note that */
+ /* if it straddles a 256-byte block, we need to do this twice. */
+ ushort *pfree1 = &cp->sfree1[str_offset >> 8];
+ uint count = size;
+ byte *prev;
+ byte *ptr = str;
+
+ if ( *pfree1 == 0 )
+ { *str = 0;
+ *pfree1 = str_offset;
+ prev = str;
+ }
+ else if ( str_offset < *pfree1 )
+ { *str = *pfree1 - str_offset;
+ *pfree1 = str_offset;
+ prev = str;
+ }
+ else
+ { uint next;
+ prev = csbase(cp) + *pfree1;
+ while ( prev + (next = *prev) < str )
+ prev += next;
+ }
+ for ( ; ; )
+ { /*
+ * Invariants:
+ * prev < sfbase + str_offset
+ * *prev == 0 || prev + *prev > sfbase + str_offset
+ */
+ *ptr = (*prev == 0 ? 0 : prev + *prev - ptr);
+ *prev = ptr - prev;
+ if ( !--count )
+ break;
+ prev = ptr++;
+ if ( !(++str_offset & 255) )
+ { /* Move to the next block of 256 bytes. */
+ ++pfree1;
+ *ptr = (byte)*pfree1;
+ *pfree1 = str_offset;
+ if ( !--count )
+ break;
+ prev = ptr++;
+ ++str_offset;
+ }
+ }
+ }
+}
+
+/* Enable or disable freeing. */
+private void
+sf_enable_free(gs_memory_t *mem, bool enable)
+{ (*gs_ref_memory_procs.enable_free)(mem, enable);
+ if ( enable )
+ mem->procs.free_string = sf_free_string;
+}
+
+#undef imem
+
+/* Merge free strings at the bottom of a chunk's string storage. */
+private void
+sf_merge_strings(chunk_t *cp)
+{ for ( ; ; )
+ { byte *ctop = cp->ctop;
+ uint top_offset = ctop - csbase(cp);
+ ushort *pfree1;
+
+ if ( cp->sfree == top_offset )
+ { /* Merge a large free block. */
+ cp->sfree = get2(ctop + 2);
+ cp->ctop += get2(ctop);
+ continue;
+ }
+ if ( !cp->sfree1 )
+ break;
+ pfree1 = &cp->sfree1[top_offset >> 8];
+ if ( *pfree1 != top_offset )
+ break;
+ /* Merge a small (1-byte) free block. */
+ *pfree1 = (*ctop ? *pfree1 + *ctop : 0);
+ cp->ctop++;
+ }
+}
+
+/*
+ * This procedure has the same API as the garbage collector used by the
+ * PostScript interpreter, but it is designed to be used in environments
+ * that don't need garbage collection and don't use save/restore. All it
+ * does is coalesce free blocks at the high end of the object area of each
+ * chunk, and free strings at the low end of the string area, and then free
+ * completely empty chunks.
+ */
+
+void
+gs_reclaim(vm_spaces *pspaces, bool global)
+{ int space;
+ gs_ref_memory_t *mem_prev = 0;
+
+ for ( space = 0; space < countof(pspaces->indexed); ++space )
+ { gs_ref_memory_t *mem = pspaces->indexed[space];
+ chunk_t *cp;
+ chunk_t *cprev;
+ /*
+ * We're going to recompute lost.objects, by subtracting the
+ * amount of space reclaimed minus the amount of that space that
+ * was on free lists.
+ */
+ ulong found = 0;
+
+ if ( mem == 0 || mem == mem_prev )
+ continue;
+ mem_prev = mem;
+ alloc_close_chunk(mem);
+
+ /*
+ * Change the allocator to use string freelists in the future.
+ */
+ mem->procs.alloc_string = sf_alloc_string;
+ if ( mem->procs.free_string != gs_ignore_free_string )
+ mem->procs.free_string = sf_free_string;
+ mem->procs.enable_free = sf_enable_free;
+
+ /* Visit chunks in reverse order to encourage LIFO behavior. */
+ for ( cp = mem->clast; cp != 0; cp = cprev )
+ { obj_header_t *begin_free = (obj_header_t *)cp->cbase;
+
+ cprev = cp->cprev;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if ( pre->o_type == &st_free )
+ { if ( begin_free == 0 )
+ begin_free = pre;
+ }
+ else
+ begin_free = 0;
+ END_OBJECTS_SCAN
+ if ( !begin_free )
+ continue;
+ /* We found free objects at the top of the object area. */
+ found += (byte *)cp->cbot - (byte *)begin_free;
+ /* Remove the free objects from the freelists. */
+ { int i;
+ for ( i = 0; i < num_freelists; i++ )
+ { obj_header_t *pfree;
+ obj_header_t **ppfprev = &mem->freelists[i];
+ uint free_size =
+ (i << log2_obj_align_mod) + sizeof(obj_header_t);
+
+ while ( (pfree = *ppfprev) != 0 )
+ if ( ptr_ge(pfree, begin_free) &&
+ ptr_lt(pfree, cp->cbot)
+ )
+ { /* We're removing an object. */
+ *ppfprev = *(obj_header_t **)pfree;
+ found -= free_size;
+ }
+ else
+ ppfprev = (obj_header_t **)pfree;
+ }
+ }
+ { byte *top = cp->ctop;
+ sf_merge_strings(cp);
+ mem->lost.strings -= cp->ctop - top;
+ }
+ if ( begin_free == (obj_header_t *)cp->cbase &&
+ cp->ctop == cp->climit
+ )
+ { /* The entire chunk is free. */
+ chunk_t *cnext = cp->cnext;
+
+ alloc_free_chunk(cp, mem);
+ if ( mem->pcc == cp )
+ mem->pcc =
+ (cnext == 0 ? cprev : cprev == 0 ? cnext :
+ cprev->cbot - cprev->ctop > cnext->cbot - cnext->ctop ?
+ cprev : cnext);
+ }
+ else
+ { if_debug4('a', "[a]resetting chunk 0x%lx cbot from 0x%lx to 0x%lx (%lu free)\n",
+ (ulong)cp, (ulong)cp->cbot, (ulong)begin_free,
+ (ulong)((byte *)cp->cbot - (byte *)begin_free));
+ cp->cbot = (byte *)begin_free;
+ }
+ }
+ mem->lost.objects -= found;
+ alloc_open_chunk(mem);
+ }
+}
diff --git a/gs/src/gsos2.def b/gs/src/gsos2.def
new file mode 100644
index 000000000..6840e729e
--- /dev/null
+++ b/gs/src/gsos2.def
@@ -0,0 +1,3 @@
+NAME GSOS2 WINDOWCOMPAT
+DESCRIPTION 'Ghostscript OS/2 EXE'
+STACKSIZE 32768
diff --git a/gs/src/gsos2.icx b/gs/src/gsos2.icx
new file mode 100644
index 000000000..2e466efd8
--- /dev/null
+++ b/gs/src/gsos2.icx
@@ -0,0 +1,209 @@
+42412800000078000000000000004349
+1a00000010001000e00100000c000000
+2000400001000100000000ffffff4349
+1a00000010001000e00200000c000000
+20002000010004000000008000000080
+00808000000080800080008080808080
+ccccccff000000ff00ffff000000ffff
+00ff00ffffffffff424128000000f000
+00000000000043491a00000008000800
+e00400000c0000001000200001000100
+000000ffffff43491a00000008000800
+600500000c0000001000100001000400
+00000080000000800080800000008080
+0080008080808080ccccccff000000ff
+00ffff000000ffff00ff00ffffffffff
+42412800000068010000000000004349
+1a0000000a000a00e00500000c000000
+1400280001000100000000ffffff4349
+1a0000000a000a00800600000c000000
+14001400010004000000008000000080
+00808000000080800080008080808080
+ccccccff000000ff00ffff000000ffff
+00ff00ffffffffff4241280000000000
+00000004000343491a00000014001400
+700700000c0000002800500001000100
+000000ffffff43491a00000014001400
+f00900000c0000002800280001000400
+00000080000000800080800000008080
+0080008080808080ccccccff000000ff
+00ffff000000ffff00ff00ffffffffff
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+0000000000000000f80000fffc0001ff
+fe0007efcc0002078000000380000001
+00000000800000018000003086000079
+df0000ffff8001ffffc001ffffe001ff
+fff801fffff803fffff807fffffc0fff
+fff81ffffff03ffffff87ffffffcffff
+44444444444444444444444444444444
+44444444444444444444444444444444
+44444eeee444eee444eee44444e44444
+44444e444e4e444e4e444e4444444444
+44444e444e4e444e4e444e4444e44444
+44444e444e4e444e4e444e4444e44444
+44444eeee444eee444eee44444e44444
+44444e44444444444444444444e44444
+44444e44444444444444444444e44444
+44444444444444444444444444444444
+000000fffffffffffffffff000000000
+0000000ffffffffffff0f00000000000
+00000000ffffffffffff000000000000
+000000000ffffffffffff000000f0000
+00ff000ff0fffffffffff00ffffff000
+000fffff0fffffffffff0ffffffff000
+0ffffffff0fffffffffffffffffffff0
+0000fffffffffffffffffffff000ff00
+00fff000fffffffffffffffff0000ff0
+00f00000ffffffffffffffff00000000
+000000000ffffffffffff0f000000000
+00000000000fff0ff00fff0000000000
+00000000000ff0fff00fff0000000000
+00000000000000ffffffff0000000000
+00000000000000ffffffff0000000000
+00000000000000ff0f0ff00000000000
+000000000000000fffff000000000000
+000000000000000ffff0000000000000
+00000000000000ffff00000000000000
+0000000000000ffff000000000000000
+00000000000000ff0000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+ffff0000ffff0000dfdf0000dfdf0000
+afc300007ffd00007ffe00008ff00000
+f66f0000f7ef0000faaf0000fddf0000
+fb3f0000fcff0000ffff0000ffff0000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000a5a00000a5a00000a5a00000300
+fffff000fffffc00dffbf400dffbf400
+cffbf000b7f830007fffd0007fffe000
+7fffe00087fe0000fb9df000fbfdf000
+fbfdf000fdadf000fefbf000fde7f000
+fd9ff000fe7ff000fffff000fffff000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+0000000000000000000000000000b004
+00000000000000000000b00400000000
+000000000000fe030000000000000000
+0000ff0f00000000000000000000005a
+00000000000000000000005a00000000
+00000000000000000000000000000000
+000000ff000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+fc000003ff000000fc000003ff000000
+fe000007ff000000ff80003fdf000000
+c60000080f0000008000000003000000
+80000000030000008000000001000c00
+00000000000000008000000001000000
+c0000000010000008000000060000000
+83800001f1000000cfc00003ff000000
+ffe00007ff000000ffe00007ff000000
+fff00007ff000000fffc0007ff000000
+ffff0007ff000000ffff000fff000000
+ffff000fff000000ffff001fff000000
+ffff803fff000000ffff007fff000000
+fffe00ffff999999fffe01ffff999999
+ffff07ffff999999ffff8fffff999999
+44444444444444444444444444444444
+4444444444444eeeeee4444eeeee4444
+eeeee444ee44444444444eeeeee4444e
+eeee4444eeeee444ee44444444444ee4
+44ee44ee444ee44ee444ee4444444444
+44444ee444ee44ee444ee44ee444ee44
+ee44444444444ee444ee44ee444ee44e
+e444ee44ee44444444444eeeeee4444e
+eeee4444eeeee444ee44444444444eee
+eee4444eeeee4444eeeee444ee444444
+44444ee4444444444444444444444444
+ee44444444444ee44444444444444444
+44444444ee44444444444ee444444444
+44444444444444444e44444444444444
+44444444444444444444444444444444
+0000000ffffffffffffffffffffff000
+000000000000000fffffffffffffffff
+fffff00000000000000000000fffffff
+ffffffff0f0000000000000000000000
+00fffffffffffffff000000000000000
+00000000000fffffffffffffff000000
+00f0000000fff000fff0ffffffffffff
+fff00fffffff000000fffffffff0ffff
+ffffffffff0ffffffffff0000000ffff
+ff0ffffffffffffff0ffffffffffff00
+0ffffffffff0ffffffffffffffffffff
+fffffff000000fffffffffffffffffff
+ffffffffffffff00000fffffffffffff
+fffffffffffffffff00fff0000ffff00
+00fffffffffffffffffffff00000fff0
+00ff000000ffffffffffffffffffff00
+0000000000000000000fffffffffffff
+ff00f00000000000000000000000ffff
+f0fff000ffff00000000000000000000
+0000fffff0fff000ffff000000000000
+00000000000000ff0ffff000ffff0000
+0000000000000000000000000fffffff
+ffff0000000000000000000000000000
+0fffffffffff00000000000000000000
+000000000ff00ff00ff0000000000000
+00000000000000000ff00ff00ff00000
+00000000000000000000000000ffffff
+ff000000000000000000000000000000
+00fffffff00000000000000000000000
+000000000fffffff0000000000000000
+0000000000000000fffffff000000000
+000000000000000000000000fffff000
+00000000000000000000000000000000
+0fff0000000000000000000000000000
+00000000000000000000000000000000
diff --git a/gs/src/gsos2.rc b/gs/src/gsos2.rc
new file mode 100644
index 000000000..c4a2967df
--- /dev/null
+++ b/gs/src/gsos2.rc
@@ -0,0 +1,22 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsos2.rc */
+/* Resources for gsos2.exe, Ghostscript for OS/2 */
+
+ICON 1 gsos2.ico
diff --git a/gs/src/gspaint.c b/gs/src/gspaint.c
new file mode 100644
index 000000000..e0a407f88
--- /dev/null
+++ b/gs/src/gspaint.c
@@ -0,0 +1,308 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspaint.c */
+/* Painting procedures for Ghostscript library */
+#include "math_.h" /* for fabs */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsropt.h" /* for gxpaint.h */
+#include "gxfixed.h"
+#include "gxmatrix.h" /* for gs_state */
+#include "gspaint.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gxpaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+
+/* Define the nominal size for alpha buffers. */
+#define abuf_nominal_SMALL 500
+#define abuf_nominal_LARGE 2000
+#if arch_small_memory
+# define abuf_nominal abuf_nominal_SMALL
+#else
+# define abuf_nominal\
+ (gs_if_debug_c('.') ? abuf_nominal_SMALL : abuf_nominal_LARGE)
+#endif
+
+/* Erase the page */
+int
+gs_erasepage(gs_state *pgs)
+{ /* We can't just fill with device white; we must take the */
+ /* transfer function into account. */
+ int code;
+ if ( (code = gs_gsave(pgs)) < 0 )
+ return code;
+ if ( (code = gs_setgray(pgs, 1.0)) >= 0 )
+ { /* Fill the page directly, ignoring clipping. */
+ code = gs_fillpage(pgs);
+ }
+ gs_grestore(pgs);
+ return code;
+}
+
+/* Fill the page with the current color. */
+int
+gs_fillpage(gs_state *pgs)
+{ gx_device *dev;
+ int code;
+ gs_logical_operation_t save_lop;
+
+ gx_set_dev_color(pgs);
+ dev = gs_currentdevice(pgs);
+ /* Fill the page directly, ignoring clipping. */
+ /* Use the default RasterOp. */
+ save_lop = pgs->log_op;
+ gs_init_rop(pgs);
+ code = gx_fill_rectangle(0, 0, dev->width, dev->height,
+ pgs->dev_color, pgs);
+ pgs->log_op = save_lop;
+ if ( code < 0 )
+ return code;
+ return (*dev_proc(dev, sync_output))(dev);
+}
+
+/*
+ * Determine the number of bits of alpha buffer for a stroke or fill.
+ * We should do alpha buffering iff this value is >1.
+ */
+private int near
+alpha_buffer_bits(gs_state *pgs)
+{ gx_device *dev;
+
+ if ( !color_is_pure(pgs->dev_color) )
+ return 0;
+ dev = gs_currentdevice_inline(pgs);
+ if ( gs_device_is_abuf(dev) )
+ { /* We're already writing into an alpha buffer. */
+ return 0;
+ }
+ return (*dev_proc(dev, get_alpha_bits))(dev, go_graphics);
+}
+/*
+ * Set up an alpha buffer for a stroke or fill operation. Return 0
+ * if no buffer could be allocated, 1 if a buffer was installed,
+ * or the usual negative error code.
+ *
+ * The fill/stroke code sets up a clipping device if needed; however,
+ * since we scale up all the path coordinates, we either need to scale up
+ * the clipping region, or do clipping after, rather than before,
+ * alpha buffering. Either of these is a little inconvenient, but
+ * the former is less inconvenient.
+ */
+private int near
+alpha_buffer_init(gs_state *pgs, fixed extra_x, fixed extra_y, int alpha_bits)
+{ gx_device *dev = gs_currentdevice_inline(pgs);
+ int log2_alpha_bits;
+ gs_fixed_rect bbox;
+ gs_int_rect ibox;
+ uint width, raster, band_space;
+ uint height;
+ gs_log2_scale_point log2_scale;
+ gs_memory_t *mem;
+ gx_device_memory *mdev;
+
+ log2_alpha_bits = alpha_bits >> 1; /* works for 1,2,4 */
+ log2_scale.x = log2_scale.y = log2_alpha_bits;
+ gx_path_bbox(pgs->path, &bbox);
+ ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1;
+ ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1;
+ ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1;
+ ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1;
+ width = (ibox.q.x - ibox.p.x) << log2_scale.x;
+ raster = bitmap_raster(width);
+ band_space = raster << log2_scale.y;
+ height = (abuf_nominal / band_space) << log2_scale.y;
+ if ( height == 0 )
+ height = 1 << log2_scale.y;
+ mem = pgs->memory;
+ mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "alpha_buffer_init");
+ if ( mdev == 0 )
+ return 0; /* if no room, don't buffer */
+ gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale,
+ alpha_bits, ibox.p.x << log2_scale.x);
+ mdev->width = width;
+ mdev->height = height;
+ mdev->bitmap_memory = mem;
+ if ( (*dev_proc(mdev, open_device))((gx_device *)mdev) < 0 )
+ { /* No room for bits, punt. */
+ gs_free_object(mem, mdev, "alpha_buffer_init");
+ return 0;
+ }
+ gx_set_device_only(pgs, (gx_device *)mdev);
+ gx_path_scale_exp2(pgs->path, log2_scale.x, log2_scale.y);
+ gx_cpath_scale_exp2(pgs->clip_path, log2_scale.x, log2_scale.y);
+ return 1;
+}
+
+/* Release an alpha buffer. */
+private void near
+alpha_buffer_release(gs_state *pgs, bool newpath)
+{ gx_device_memory *mdev =
+ (gx_device_memory *)gs_currentdevice_inline(pgs);
+ gx_device *target = mdev->target;
+
+ (*dev_proc(mdev, close_device))((gx_device *)mdev);
+ gs_free_object(mdev->memory, mdev, "alpha_buffer_release");
+ gx_set_device_only(pgs, target);
+ gx_cpath_scale_exp2(pgs->clip_path,
+ -mdev->log2_scale.x, -mdev->log2_scale.y);
+ if ( !(newpath && !pgs->path->shares_segments) )
+ gx_path_scale_exp2(pgs->path,
+ -mdev->log2_scale.x, -mdev->log2_scale.y);
+}
+
+/* Fill the current path using a specified rule. */
+private int near
+fill_with_rule(gs_state *pgs, int rule)
+{ int code;
+ /* If we're inside a charpath, just merge the current path */
+ /* into the parent's path. */
+ if ( pgs->in_charpath )
+ code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
+ pgs->in_charpath);
+ else
+ { int abits, acode;
+
+ gx_set_dev_color(pgs);
+ code = gs_state_color_load(pgs);
+ if ( code < 0 )
+ return code;
+ abits = alpha_buffer_bits(pgs);
+ if ( abits > 1 )
+ { acode = alpha_buffer_init(pgs, pgs->fill_adjust.x,
+ pgs->fill_adjust.y, abits);
+ if ( acode < 0 )
+ return acode;
+ }
+ else
+ acode = 0;
+ code = gx_fill_path(pgs->path, pgs->dev_color, pgs, rule,
+ pgs->fill_adjust.x, pgs->fill_adjust.y);
+ if ( acode > 0 )
+ alpha_buffer_release(pgs, code >= 0);
+ if ( code >= 0 )
+ gs_newpath(pgs);
+
+ }
+ return code;
+}
+/* Fill using the winding number rule */
+int
+gs_fill(gs_state *pgs)
+{ return fill_with_rule(pgs, gx_rule_winding_number);
+}
+/* Fill using the even/odd rule */
+int
+gs_eofill(gs_state *pgs)
+{ return fill_with_rule(pgs, gx_rule_even_odd);
+}
+
+/* Stroke the current path */
+int
+gs_stroke(gs_state *pgs)
+{ int code;
+ /* If we're inside a charpath, just merge the current path */
+ /* into the parent's path. */
+ if ( pgs->in_charpath )
+ { if ( pgs->in_charpath == cpm_true_charpath )
+ { /* A stroke inside a true charpath should do the */
+ /* equivalent of strokepath. */
+ code = gs_strokepath(pgs);
+ if ( code < 0 )
+ return code;
+ }
+ code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
+ pgs->in_charpath);
+ }
+ else
+ { int abits, acode;
+ float orig_width;
+
+ gx_set_dev_color(pgs);
+ code = gs_state_color_load(pgs);
+ if ( code < 0 )
+ return code;
+ abits = alpha_buffer_bits(pgs);
+ if ( abits > 1 )
+ { /* Expand the bounding box by the line width. */
+ /* This is expensive to compute, so we only do it */
+ /* if we know we're going to buffer. */
+ float xxyy = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yy);
+ float xyyx = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yx);
+ float new_width =
+ (orig_width = gs_currentlinewidth(pgs)) *
+ (1 << (abits / 2));
+ fixed extra_adjust =
+ float2fixed(max(xxyy, xyyx) * new_width / 2);
+ gx_path spath;
+
+ /* Scale up the line width. */
+ if ( extra_adjust < fixed_1 )
+ extra_adjust = fixed_1;
+ acode = alpha_buffer_init(pgs,
+ pgs->fill_adjust.x + extra_adjust,
+ pgs->fill_adjust.y + extra_adjust,
+ abits);
+ if ( acode < 0 )
+ return acode;
+ gs_setlinewidth(pgs, new_width);
+ /*
+ * The alpha-buffer device requires that we fill the
+ * entire path as a single unit.
+ */
+ gx_path_init(&spath, pgs->memory);
+ code = gx_stroke_add(pgs->path, &spath, pgs);
+ gs_setlinewidth(pgs, orig_width);
+ if ( code >= 0 )
+ code = gx_fill_path(&spath, pgs->dev_color, pgs,
+ gx_rule_winding_number,
+ pgs->fill_adjust.x,
+ pgs->fill_adjust.y);
+ gx_path_release(&spath);
+ if ( acode > 0 )
+ alpha_buffer_release(pgs, code >= 0);
+ }
+ else
+ { code = gx_stroke_fill(pgs->path, pgs);
+ }
+ if ( code >= 0 )
+ gs_newpath(pgs);
+ }
+ return code;
+}
+
+/* Compute the stroked outline of the current path */
+int
+gs_strokepath(gs_state *pgs)
+{ gx_path spath;
+ int code;
+
+ gx_path_init(&spath, pgs->memory);
+ code = gx_stroke_add(pgs->path, &spath, pgs);
+ if ( code < 0 )
+ return code;
+ gx_path_release(pgs->path);
+ *pgs->path = spath;
+ return 0;
+}
diff --git a/gs/src/gspaint.h b/gs/src/gspaint.h
new file mode 100644
index 000000000..027107dee
--- /dev/null
+++ b/gs/src/gspaint.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspaint.h */
+/* Client interface to painting functions */
+/* Requires gsstate.h */
+
+/* Painting */
+int gs_erasepage(P1(gs_state *)),
+ gs_fillpage(P1(gs_state *)),
+ gs_fill(P1(gs_state *)),
+ gs_eofill(P1(gs_state *)),
+ gs_stroke(P1(gs_state *));
+
+/* Image tracing */
+int gs_imagepath(P4(gs_state *, int, int, const byte *));
diff --git a/gs/src/gsparam.c b/gs/src/gsparam.c
new file mode 100644
index 000000000..2e6cf6ffc
--- /dev/null
+++ b/gs/src/gsparam.c
@@ -0,0 +1,558 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsparam.c */
+/* Default implementation of parameter lists */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+
+/* Forward references */
+typedef union c_param_value_s c_param_value;
+/*typedef struct gs_c_param_s gs_c_param;*/ /* in gsparam.h */
+
+/* Define the GC type for a parameter list. */
+private_st_c_param_list();
+
+/* Define a union type for parameter values. */
+union gs_c_param_value_s {
+ bool b;
+ int i;
+ long l;
+ float f;
+ gs_param_string s;
+ gs_param_int_array ia;
+ gs_param_float_array fa;
+ gs_param_string_array sa;
+ gs_c_param_list d;
+};
+
+
+/* Lengths corresponding to various cpt_xxx types */
+const byte gs_param_type_sizes[] = {GS_PARAM_TYPE_SIZES_ELEMENTS};
+#define cpt_size(cpt) (gs_param_type_sizes[(int)cpt])
+
+/* Lengths of *actual* data-containing type pointed to or contained by cpt_xxx's */
+const int cpt_base_sizeof[] = {CPT_BASE_SIZEOF_ELEMENTS};
+
+/* Define a parameter list element. */
+struct gs_c_param_s {
+ gs_c_param *next;
+ gs_param_name key;
+ union gs_c_param_value_s value;
+ gs_param_type type;
+ void *alternate_typed_data;
+};
+/* Parameter values aren't really simple, */
+/* but since parameter lists are transient, it doesn't matter. */
+gs_private_st_ptrs2(st_c_param, gs_c_param, "gs_c_param",
+ c_param_enum_ptrs, c_param_reloc_ptrs, next, alternate_typed_data);
+
+/* ================ Utilities ================ */
+
+#define cplist ((gs_c_param_list *)plist)
+
+/* ================ Generic gs_param_list procs =============== */
+
+/* Reset a gs_param_key_t enumerator to its initial state */
+void
+param_init_enumerator(gs_param_enumerator_t *enumerator)
+{ memset( enumerator, 0, sizeof(*enumerator) );
+}
+
+/* ================ Writing parameters to a list ================ */
+
+private param_proc_xmit_null(c_param_write_null);
+private param_proc_xmit_typed(c_param_write_typed);
+private param_proc_xmit_bool(c_param_write_bool);
+private param_proc_xmit_int(c_param_write_int);
+private param_proc_xmit_long(c_param_write_long);
+private param_proc_xmit_float(c_param_write_float);
+private param_proc_xmit_string(c_param_write_string);
+private param_proc_xmit_int_array(c_param_write_int_array);
+private param_proc_xmit_float_array(c_param_write_float_array);
+private param_proc_xmit_string_array(c_param_write_string_array);
+private param_proc_begin_xmit_dict(c_param_begin_write_dict);
+private param_proc_end_xmit_dict(c_param_end_write_dict);
+private param_proc_requested(c_param_requested);
+private const gs_param_list_procs c_write_procs = {
+ c_param_write_null,
+ c_param_write_typed,
+ c_param_write_bool,
+ c_param_write_int,
+ c_param_write_long,
+ c_param_write_float,
+ c_param_write_string,
+ c_param_write_string, /* name = string */
+ c_param_write_int_array,
+ c_param_write_float_array,
+ c_param_write_string_array,
+ c_param_write_string_array, /* name = string */
+ c_param_begin_write_dict,
+ c_param_end_write_dict,
+ NULL, /* get_next_key */
+ c_param_requested
+};
+
+/* Initialize a list for writing. */
+void
+gs_c_param_list_write(gs_c_param_list *plist, gs_memory_t *mem)
+{ plist->procs = &c_write_procs;
+ plist->memory = mem;
+ plist->head = 0;
+ plist->count = 0;
+ plist->has_int_keys = 0;
+}
+
+/* Release a list. */
+void
+gs_c_param_list_release(gs_c_param_list *plist)
+{ gs_c_param *pparam;
+ while ( (pparam = plist->head) != 0 )
+ { gs_c_param *next = pparam->next;
+ switch (pparam->type)
+ {
+ case cpt_dict:
+ case cpt_dict_int_keys:
+ gs_c_param_list_release(&pparam->value.d);
+ break;
+ case cpt_string:
+ case cpt_name:
+ case cpt_int_array:
+ case cpt_float_array:
+ case cpt_string_array:
+ case cpt_name_array:
+ if (!pparam->value.s.persistent)
+ gs_free_object( plist->memory, (void *)pparam->value.s.data,
+ "gs_c_param_list_release data" );
+ break;
+ default:
+ break;
+ }
+ gs_free_object(plist->memory, pparam->alternate_typed_data,
+ "gs_c_param_list_release alternate data");
+ gs_free_object(plist->memory, pparam, "gs_c_param_list_release entry");
+ plist->head = next;
+ plist->count--;
+ }
+}
+
+/* Generic routine for writing a parameter to a list. */
+private int
+c_param_write(gs_c_param_list *plist, gs_param_name pkey, void *pvalue,
+ gs_param_type type)
+{ unsigned top_level_sizeof = 0;
+ unsigned second_level_sizeof = 0;
+ gs_c_param *pparam =
+ gs_alloc_struct(plist->memory, gs_c_param, &st_c_param,
+ "c_param_write entry");
+ if ( pparam == 0 )
+ return_error(gs_error_VMerror);
+ pparam->next = plist->head;
+ pparam->key = pkey;
+ memcpy(&pparam->value, pvalue, cpt_size(type));
+ pparam->type = type;
+ pparam->alternate_typed_data = 0;
+
+ /* Need deeper copies of data if it's not persistent */
+ switch (type)
+ {
+ gs_param_string const *curr_string;
+ gs_param_string const *end_string;
+ case cpt_string_array:
+ case cpt_name_array:
+ /* Determine how much mem needed to hold actual string data */
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for ( ; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent)
+ second_level_sizeof += curr_string->size;
+ /* fall thru */
+
+ case cpt_string:
+ case cpt_name:
+ case cpt_int_array:
+ case cpt_float_array:
+ if (!pparam->value.s.persistent)
+ { /* Allocate & copy object pointed to by array or string */
+ byte *top_level_memory;
+ top_level_sizeof = pparam->value.s.size * cpt_base_sizeof[type];
+ top_level_memory = gs_alloc_bytes_immovable(plist->memory,
+ top_level_sizeof + second_level_sizeof, "c_param_write data");
+ if (top_level_memory == 0)
+ { gs_free_object(plist->memory, pparam, "c_param_write entry");
+ return_error(gs_error_VMerror);
+ }
+ memcpy(top_level_memory, pparam->value.s.data, top_level_sizeof);
+ pparam->value.s.data = top_level_memory;
+
+ /* String/name arrays need to copy actual str data */
+ if (second_level_sizeof > 0)
+ { byte *second_level_memory
+ = top_level_memory + top_level_sizeof;
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for ( ; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent)
+ { memcpy(second_level_memory,
+ curr_string->data, curr_string->size);
+ ( (gs_param_string *)curr_string )->data
+ = second_level_memory;
+ second_level_memory += curr_string->size;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ plist->head = pparam;
+ plist->count++;
+ return 0;
+}
+
+/* Individual writing routines. */
+#define cpw(pvalue, type)\
+ c_param_write(cplist, pkey, pvalue, type)
+private int
+c_param_write_null(gs_param_list *plist, gs_param_name pkey)
+{ return cpw(NULL, cpt_null);
+}
+private int
+c_param_write_typed(gs_param_list *plist, gs_param_name pkey,
+ gs_param_typed_value *pvalue)
+{ switch (pvalue->type)
+ {
+ case cpt_dict:
+ return c_param_begin_write_dict
+ ( plist, pkey, &pvalue->value.d, false );
+ case cpt_dict_int_keys:
+ return c_param_begin_write_dict
+ ( plist, pkey, &pvalue->value.d, true );
+ default:
+ ;
+ }
+ return cpw(&pvalue->value, pvalue->type);
+}
+private int
+c_param_write_bool(gs_param_list *plist, gs_param_name pkey, bool *pvalue)
+{ return cpw(pvalue, cpt_bool);
+}
+private int
+c_param_write_int(gs_param_list *plist, gs_param_name pkey, int *pvalue)
+{
+ return cpw(pvalue, cpt_int);
+}
+private int
+c_param_write_long(gs_param_list *plist, gs_param_name pkey, long *pvalue)
+{ return cpw(pvalue, cpt_long);
+}
+private int
+c_param_write_float(gs_param_list *plist, gs_param_name pkey, float *pvalue)
+{ return cpw(pvalue, cpt_float);
+}
+private int
+c_param_write_string(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string *pvalue)
+{ return cpw(pvalue, cpt_string);
+}
+private int
+c_param_write_int_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_int_array *pvalue)
+{ return cpw(pvalue, cpt_int_array);
+}
+private int
+c_param_write_float_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_float_array *pvalue)
+{ return cpw(pvalue, cpt_float_array);
+}
+private int
+c_param_write_string_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string_array *pvalue)
+{ return cpw(pvalue, cpt_string_array);
+}
+private int
+c_param_begin_write_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue, bool int_keys)
+{ gs_c_param_list *dlist =
+ gs_alloc_struct(cplist->memory, gs_c_param_list, &st_c_param_list,
+ "c_param_begin_write_dict");
+ if ( dlist == 0 )
+ return_error(gs_error_VMerror);
+ gs_c_param_list_write(dlist, cplist->memory);
+ dlist->has_int_keys = int_keys;
+ pvalue->list = (gs_param_list *)dlist;
+ return 0;
+}
+private int
+c_param_end_write_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue)
+{ return cpw( pvalue->list,
+ ( (gs_c_param_list *)(pvalue->list) )->has_int_keys
+ ? cpt_dict_int_keys : cpt_dict );
+}
+
+/* Other procedures */
+private bool
+c_param_requested(const gs_param_list *plist, gs_param_name pkey)
+{ return true;
+}
+
+/* ================ Reading from a list to parameters ================ */
+
+private param_proc_xmit_null(c_param_read_null);
+private param_proc_xmit_typed(c_param_read_typed);
+private param_proc_xmit_bool(c_param_read_bool);
+private param_proc_xmit_int(c_param_read_int);
+private param_proc_xmit_long(c_param_read_long);
+private param_proc_xmit_float(c_param_read_float);
+private param_proc_xmit_string(c_param_read_string);
+private param_proc_xmit_int_array(c_param_read_int_array);
+private param_proc_xmit_float_array(c_param_read_float_array);
+private param_proc_xmit_string_array(c_param_read_string_array);
+private param_proc_begin_xmit_dict(c_param_begin_read_dict);
+private param_proc_next_key(c_param_get_next_key);
+private param_proc_end_xmit_dict(c_param_end_read_dict);
+private param_proc_get_policy(c_param_read_get_policy);
+private param_proc_signal_error(c_param_read_signal_error);
+private param_proc_commit(c_param_read_commit);
+private const gs_param_list_procs c_read_procs = {
+ c_param_read_null,
+ c_param_read_typed,
+ c_param_read_bool,
+ c_param_read_int,
+ c_param_read_long,
+ c_param_read_float,
+ c_param_read_string,
+ c_param_read_string, /* name = string */
+ c_param_read_int_array,
+ c_param_read_float_array,
+ c_param_read_string_array,
+ c_param_read_string_array, /* name = string */
+ c_param_begin_read_dict,
+ c_param_end_read_dict,
+ c_param_get_next_key,
+ NULL, /* requested */
+ c_param_read_get_policy,
+ c_param_read_signal_error,
+ c_param_read_commit
+};
+
+/* Switch a list from writing to reading. */
+void
+gs_c_param_list_read(gs_c_param_list *plist)
+{ plist->procs = &c_read_procs;
+}
+
+/* Generic routine for reading a parameter from a list. */
+private gs_c_param *
+c_param_find(gs_c_param_list *plist, gs_param_name pkey)
+{ gs_c_param *pparam = plist->head;
+ for ( ; pparam != 0; pparam = pparam->next )
+ if ( !strcmp(pparam->key, pkey) )
+ return pparam;
+ return 0;
+}
+private int
+c_param_read(gs_c_param_list *plist, gs_param_name pkey, void *pvalue,
+ gs_param_type type)
+{ gs_c_param *pparam = c_param_find(plist, pkey);
+ bool match;
+ if ( pparam == 0 )
+ return 1;
+ /* This module's implementation aliases some types, so force those comparisons true */
+ if ( !(match = pparam->type == type) )
+ switch (pparam->type)
+ {
+ case cpt_int:
+ if (type == cpt_long)
+ { *(long *)pvalue = pparam->value.i;
+ return 0;
+ }
+ if (type == cpt_float)
+ { *(float *)pvalue = (float)pparam->value.i;
+ return 0;
+ }
+ break;
+ case cpt_long:
+ if (type == cpt_int)
+ {
+ *(int *)pvalue = (int)pparam->value.l;
+#if arch_sizeof_int < arch_sizeof_long
+ if ( pparam->value.l != *(int *)pvalue )
+ return_error(e_rangecheck);
+#endif
+ return 0;
+ }
+ if (type == cpt_float)
+ { *(float *)pvalue = (float)pparam->value.l;
+ return 0;
+ }
+ break;
+ case cpt_string:
+ match = (type == cpt_name);
+ break;
+ case cpt_name:
+ match = (type == cpt_string);
+ break;
+ case cpt_int_array:
+ if (type == cpt_float_array)
+ {
+ /* Convert int array to float dest */
+ gs_param_float_array fa;
+ int element;
+ fa.size = pparam->value.ia.size;
+ fa.persistent = false;
+ if (pparam->alternate_typed_data == 0)
+ { if ( ( pparam->alternate_typed_data
+ = (void *)gs_alloc_bytes_immovable( plist->memory,
+ fa.size * sizeof(float),
+ "gs_c_param_read alternate float array" ) ) == 0 )
+ return_error(gs_error_VMerror);
+ for (element = 0; element < fa.size; ++element)
+ ( (float*)(pparam->alternate_typed_data) )[element]
+ = (float)pparam->value.ia.data[element];
+ }
+ fa.data = (float *)pparam->alternate_typed_data;
+
+ memcpy( pvalue, &fa, sizeof(gs_param_float_array) );
+ return 0;
+ }
+ break;
+ case cpt_string_array:
+ match = (type == cpt_name_array);
+ break;
+ case cpt_name_array:
+ match = (type == cpt_string_array);
+ break;
+ default:
+ break;
+ }
+ if (!match)
+ return_error(gs_error_typecheck);
+ memcpy(pvalue, &pparam->value, cpt_size(type));
+ return 0;
+}
+
+/* Individual reading routines. */
+#define cpr(pvalue, type)\
+ c_param_read(cplist, pkey, pvalue, type)
+private int
+c_param_read_null(gs_param_list *plist, gs_param_name pkey)
+{ return cpr(NULL, cpt_null);
+}
+private int
+c_param_read_typed(gs_param_list *plist, gs_param_name pkey,
+ gs_param_typed_value *pvalue)
+{ gs_c_param *pparam = c_param_find(cplist, pkey);
+ if ( pparam == 0 )
+ return 1;
+ pvalue->type = pparam->type;
+ if (pvalue->type == cpt_dict || pvalue->type == cpt_dict_int_keys)
+ { gs_c_param_list_read(&pparam->value.d);
+ pvalue->value.d.list = (gs_param_list *)&pparam->value.d;
+ pvalue->value.d.size = pparam->value.d.count;
+ }
+ else
+ memcpy(&pvalue->value, &pparam->value, cpt_size(pvalue->type));
+ return 0;
+}
+private int
+c_param_read_bool(gs_param_list *plist, gs_param_name pkey, bool *pvalue)
+{ return cpr(pvalue, cpt_bool);
+}
+private int
+c_param_read_int(gs_param_list *plist, gs_param_name pkey, int *pvalue)
+{ return cpr(pvalue, cpt_int);
+}
+private int
+c_param_read_long(gs_param_list *plist, gs_param_name pkey, long *pvalue)
+{ return cpr(pvalue, cpt_long);
+}
+private int
+c_param_read_float(gs_param_list *plist, gs_param_name pkey, float *pvalue)
+{ return cpr(pvalue, cpt_float);
+}
+private int
+c_param_read_string(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string *pvalue)
+{ return cpr(pvalue, cpt_string);
+}
+private int
+c_param_read_int_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_int_array *pvalue)
+{ return cpr(pvalue, cpt_int_array);
+}
+private int
+c_param_read_float_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_float_array *pvalue)
+{ return cpr(pvalue, cpt_float_array);
+}
+private int
+c_param_read_string_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string_array *pvalue)
+{ return cpr(pvalue, cpt_string_array);
+}
+private int
+c_param_begin_read_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue, bool int_keys)
+{ gs_c_param *pparam = c_param_find(cplist, pkey);
+ if ( pparam == 0 )
+ return 1;
+ if ( pparam->type != (int_keys ? cpt_dict_int_keys : cpt_dict) )
+ return_error(gs_error_typecheck);
+ gs_c_param_list_read(&pparam->value.d);
+ pvalue->list = (gs_param_list *)&pparam->value.d;
+ pvalue->size = pparam->value.d.count;
+ return 0;
+}
+private int
+c_param_end_read_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue)
+{ return 0;
+}
+
+/* Other procedures */
+private int
+c_param_read_get_policy(gs_param_list *plist, gs_param_name pkey)
+{ return gs_param_policy_ignore;
+}
+private int
+c_param_read_signal_error(gs_param_list *plist, gs_param_name pkey, int code)
+{ return code;
+}
+private int
+c_param_read_commit(gs_param_list *plist)
+{ return 0;
+}
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+c_param_get_next_key(gs_param_list *plist, gs_param_key_t *key)
+{ gs_c_param *pparam = key->enumerator.pvoid
+ ? ( (gs_c_param *)(key->enumerator.pvoid) )->next : cplist->head;
+ if (pparam == 0)
+ return 1;
+ key->enumerator.pvoid = pparam;
+ key->key = pparam->key;
+ key->key_sizeof= strlen(key->key);
+ return 0;
+}
+
diff --git a/gs/src/gsparam.h b/gs/src/gsparam.h
new file mode 100644
index 000000000..1e73de24b
--- /dev/null
+++ b/gs/src/gsparam.h
@@ -0,0 +1,445 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsparam.h */
+/* Client interface to parameter dictionaries */
+
+#ifndef gsparam_INCLUDED
+# define gsparam_INCLUDED
+
+/*
+ * Several interfaces use parameter dictionaries to communicate sets of
+ * (key, value) pairs from a client to an object with complex state.
+ * (Several of these correspond directly to similar interfaces in the
+ * PostScript language.) This file defines the API for parameter dictionaries.
+ */
+
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+#endif
+
+typedef const char *gs_param_name;
+
+/* Define the type for dictionary and mixed-type-array values. */
+typedef struct gs_param_collection_s {
+ gs_param_list *list;
+ uint size;
+} gs_param_collection;
+typedef gs_param_collection gs_param_dict;
+typedef gs_param_collection gs_param_array;
+
+/*
+ * Define a structure for representing a variable-size value
+ * (string/name, integer array, or floating point array).
+ * The size is the number of elements, not the size in bytes.
+ * A value is persistent if it is defined as static const,
+ * or if it is allocated in garbage-collectable space and never freed.
+ */
+
+#define _param_array_struct(sname,etype)\
+ struct sname { const etype *data; uint size; bool persistent; }
+typedef _param_array_struct(gs_param_string_s, byte) gs_param_string;
+typedef _param_array_struct(gs_param_int_array_s, int) gs_param_int_array;
+typedef _param_array_struct(gs_param_float_array_s, float) gs_param_float_array;
+typedef _param_array_struct(gs_param_string_array_s, gs_param_string) gs_param_string_array;
+
+#define param_string_from_string(ps, str)\
+ (ps).data = (const byte *)(str), (ps).size = strlen((const char *)(ps).data),\
+ (ps).persistent = true
+
+/*
+ * Define the parameter list element types.
+ * We would like to define:
+ * #define cpt(n, t) ((sizeof(t) << 4) + n)
+ * #define cpt_size(cpt) ((cpt) >> 4)
+ * but a bug in the Borland C++ 3.1 compiler causes the enumerated type
+ * never to get defined if we do this. Instead, we use an ordinary
+ * enumeration, and get the sizes from a table.
+ */
+typedef enum {
+ cpt_null = 0, cpt_bool, cpt_int, cpt_long, cpt_float,
+ cpt_string, cpt_name, cpt_int_array,
+ cpt_float_array, cpt_string_array, cpt_name_array,
+ cpt_dict, cpt_dict_int_keys
+} gs_param_type;
+
+/* Define list of lengths of types implied by cpt_xxx types */
+#define GS_PARAM_TYPE_SIZES_ELEMENTS \
+ 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
+ sizeof(gs_param_string), sizeof(gs_param_string), sizeof(gs_param_int_array),\
+ sizeof(gs_param_float_array), sizeof(gs_param_string_array), sizeof(gs_param_string_array),\
+ sizeof(gs_c_param_list), sizeof(gs_c_param_list)
+extern const byte gs_param_type_sizes[];
+
+/* Declare array used to size *actual* underlying data types contained by */
+/* or pointed to by given cpt_xxx types. */
+#define CPT_BASE_SIZEOF_ELEMENTS \
+ 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
+ sizeof(byte), sizeof(byte), sizeof(int), sizeof(float),\
+ sizeof(gs_param_string), sizeof(gs_param_string), 0, 0
+extern const int cpt_base_sizeof[];
+
+/* Define a union type for parameter values. */
+typedef union gs_param_value_s {
+ bool b;
+ int i;
+ long l;
+ float f;
+ gs_param_string s;
+ gs_param_string n;
+ gs_param_int_array ia;
+ gs_param_float_array fa;
+ gs_param_string_array sa;
+ gs_param_string_array na;
+ gs_param_dict d;
+} gs_param_value_t;
+
+/* Define a struct containing a value along with its type */
+typedef struct {
+ gs_param_value_t value;
+ gs_param_type type;
+} gs_param_typed_value;
+/* No GC: Parameter values aren't really simple, */
+/* but since parameter lists are transient, it doesn't matter. */
+
+
+/* Define the 'policies' for handling out-of-range parameter values. */
+/* This is not an enum, because some parameters may recognize other values. */
+#define gs_param_policy_signal_error 0
+#define gs_param_policy_ignore 1
+#define gs_param_policy_consult_user 2
+
+/* Define an enumerator used to get the next key in a list */
+typedef union gs_param_enumerator_s {
+/* Must all be used such that memset(0) entire union means 'begin of struct' */
+ int intval;
+ long longval;
+ void *pvoid;
+ char *pchar;
+} gs_param_enumerator_t;
+typedef struct gs_param_key_s {
+ gs_param_enumerator_t enumerator;
+ gs_param_name key;
+ int key_sizeof;
+} gs_param_key_t;
+
+/*
+ * Define the object procedures. Note that the same interface is used
+ * both for getting and for setting parameter values. (This is a bit
+ * of a hack, and we might change it someday.) The procedures return
+ * as follows:
+ * - 'reading' procedures ('put' operations from the client's viewpoint)
+ * return 1 for a missing parameter, 0 for a valid parameter, <0 on error.
+ * - 'writing' procedures ('get' operations from the client's viewpoint)
+ * return 0 or 1 if successful, <0 on error.
+ */
+
+/*
+ * Transmitting variable-size objects requires some extra care.
+ * - When writing an array, string, name, or dictionary, the
+ * implementation (not the client) sets all the fields of the value.
+ * - When reading an array, string, or name, the client must set
+ * all the fields of the value.
+ * - When reading a dictionary, the client must set the size field
+ * before calling begin_write_dict; the implementation of begin_write_dict
+ * allocates the list.
+ */
+
+/*
+ * Setting parameters must use a "two-phase commit" policy. Specifically,
+ * any put_params procedure must observe the following discipline:
+
+ 1. For each parameter known to the device, ask the parameter list if
+there is a new value, and if so, make all necessary validity checks. If any
+check fails, call param_signal_error for that parameter, but continue to
+check further parameters. Normally, this step should not alter the state of
+the device; however, if the device allows changing any parameters that are
+read-only by default (for example, BitsPerPixel or ProcessColorModel), or if
+it replaces the default put_params behavior for any parameter (for example,
+if it handles MediaSize or Resolution itself to forestall the normal closing
+of the device when these are set), step 1 of put_params must change the
+parameters in the device state, and step 2 must undo the changes if
+returning an error.
+
+ 2. Call the "superclass" put_params routine. For printer devices,
+this is gdev_prn_put_params; for other devices, it is gx_default_put_params.
+Note that this must be done even if errors were detected in step 1. If this
+routine returns an error code, or if step 1 detected an error, undo any
+changes that step 1 made in the device state, and return the error code.
+
+ 3. Install the new parameter values in the device. If necessary,
+close the device first; a higher-level routine (gs_putdeviceparams) will
+reopen the device if necessary.
+
+ */
+
+typedef struct gs_param_list_procs_s {
+
+ /* Transmit a null value. */
+ /* Note that this is the only 'transmit' operation */
+ /* that does not actually pass any data. */
+
+#define param_proc_xmit_null(proc)\
+ int proc(P2(gs_param_list *, gs_param_name))
+ param_proc_xmit_null((*xmit_null));
+#define param_read_null(plist, pkey)\
+ (*(plist)->procs->xmit_null)(plist, pkey)
+#define param_write_null(plist, pkey)\
+ (*(plist)->procs->xmit_null)(plist, pkey)
+
+ /* Transmit a typed value. */
+ /* Note that read/write_typed do a begin_read/write_dict if the */
+ /* type is one of the dict types. */
+
+#define param_proc_xmit_typed(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_typed_value *))
+ param_proc_xmit_typed((*xmit_typed));
+#define param_read_typed(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_typed)(plist, pkey, pvalue)
+#define param_write_typed(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_typed)(plist, pkey, pvalue)
+
+ /* Transmit a Boolean value. */
+
+#define param_proc_xmit_bool(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, bool *))
+ param_proc_xmit_bool((*xmit_bool));
+#define param_read_bool(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_bool)(plist, pkey, pvalue)
+#define param_write_bool(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_bool)(plist, pkey, pvalue)
+
+ /* Transmit an integer value. */
+
+#define param_proc_xmit_int(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, int *))
+ param_proc_xmit_int((*xmit_int));
+#define param_read_int(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_int)(plist, pkey, pvalue)
+#define param_write_int(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_int)(plist, pkey, pvalue)
+
+ /* Transmit a long value. */
+
+#define param_proc_xmit_long(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, long *))
+ param_proc_xmit_long((*xmit_long));
+#define param_read_long(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_long)(plist, pkey, pvalue)
+#define param_write_long(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_long)(plist, pkey, pvalue)
+
+ /* Transmit a float value. */
+
+#define param_proc_xmit_float(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, float *))
+ param_proc_xmit_float((*xmit_float));
+#define param_read_float(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_float)(plist, pkey, pvalue)
+#define param_write_float(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_float)(plist, pkey, pvalue)
+
+ /* Transmit a string value. */
+
+#define param_proc_xmit_string(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_string *))
+ param_proc_xmit_string((*xmit_string));
+#define param_read_string(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_string)(plist, pkey, pvalue)
+#define param_write_string(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_string)(plist, pkey, pvalue)
+
+ /* Transmit a name value. */
+
+#define param_proc_xmit_name(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_string *))
+ param_proc_xmit_name((*xmit_name));
+#define param_read_name(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_name)(plist, pkey, pvalue)
+#define param_write_name(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_name)(plist, pkey, pvalue)
+
+ /* Transmit an integer array value. */
+
+#define param_proc_xmit_int_array(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_int_array *))
+ param_proc_xmit_int_array((*xmit_int_array));
+#define param_read_int_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_int_array)(plist, pkey, pvalue)
+#define param_write_int_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_int_array)(plist, pkey, pvalue)
+
+ /* Transmit a float array value. */
+
+#define param_proc_xmit_float_array(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_float_array *))
+ param_proc_xmit_float_array((*xmit_float_array));
+#define param_read_float_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_float_array)(plist, pkey, pvalue)
+#define param_write_float_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_float_array)(plist, pkey, pvalue)
+
+ /* Transmit a string array value. */
+
+#define param_proc_xmit_string_array(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_string_array *))
+ param_proc_xmit_string_array((*xmit_string_array));
+#define param_read_string_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_string_array)(plist, pkey, pvalue)
+#define param_write_string_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_string_array)(plist, pkey, pvalue)
+
+ /* Transmit a name array value. */
+
+#define param_proc_xmit_name_array(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_string_array *))
+ param_proc_xmit_name_array((*xmit_name_array));
+#define param_read_name_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_name_array)(plist, pkey, pvalue)
+#define param_write_name_array(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_name_array)(plist, pkey, pvalue)
+
+ /* Start transmitting a dictionary value. */
+ /* If int_keys is true, the keys are actually integers */
+ /* (although still presented as strings). */
+
+#define param_proc_begin_xmit_dict(proc)\
+ int proc(P4(gs_param_list *, gs_param_name, gs_param_dict *, bool))
+ param_proc_begin_xmit_dict((*begin_xmit_dict));
+#define param_begin_read_dict(plist, pkey, pvalue, int_keys)\
+ (*(plist)->procs->begin_xmit_dict)(plist, pkey, pvalue, int_keys)
+#define param_begin_write_dict(plist, pkey, pvalue, int_keys)\
+ (*(plist)->procs->begin_xmit_dict)(plist, pkey, pvalue, int_keys)
+
+ /* Finish transmitting a dictionary value. */
+
+#define param_proc_end_xmit_dict(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_dict *))
+ param_proc_end_xmit_dict((*end_xmit_dict));
+#define param_end_read_dict(plist, pkey, pvalue)\
+ (*(plist)->procs->end_xmit_dict)(plist, pkey, pvalue)
+#define param_end_write_dict(plist, pkey, pvalue)\
+ (*(plist)->procs->end_xmit_dict)(plist, pkey, pvalue)
+
+ /*
+ * Get the next key in sequence.
+ * Use param_init_enumerator(...) to reset to first key.
+ */
+
+#define param_proc_next_key(proc)\
+ int proc(P2(gs_param_list *, gs_param_key_t *))
+ param_proc_next_key((*next_key));
+#define param_get_next_key(plist, pkey)\
+ (*(plist)->procs->next_key)(plist, pkey)
+
+ /* Determine whether a given key has been requested. */
+ /* (Only used when writing.) */
+
+#define param_proc_requested(proc)\
+ bool proc(P2(const gs_param_list *, gs_param_name))
+ param_proc_requested((*requested));
+#define param_requested(plist, pkey)\
+ (*(plist)->procs->requested)(plist, pkey)
+
+ /* Get the 'policy' associated with an out-of-range parameter value. */
+ /* (Only used when reading.) */
+
+#define param_proc_get_policy(proc)\
+ int proc(P2(gs_param_list *, gs_param_name))
+ param_proc_get_policy((*get_policy));
+#define param_get_policy(plist, pkey)\
+ (*(plist)->procs->get_policy)(plist, pkey)
+
+ /*
+ * Signal an error. (Only used when reading.)
+ * The procedure may return a different error code,
+ * or may return 0 indicating that the error is to be ignored.
+ */
+
+#define param_proc_signal_error(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, int))
+ param_proc_signal_error((*signal_error));
+#define param_signal_error(plist, pkey, code)\
+ (*(plist)->procs->signal_error)(plist, pkey, code)
+#define param_return_error(plist, pkey, code)\
+ return_error(param_signal_error(plist, pkey, code))
+
+ /*
+ * "Commit" a set of changes. (Only used when reading.)
+ * This is called at the end of the first phase.
+ */
+
+#define param_proc_commit(proc)\
+ int proc(P1(gs_param_list *))
+ param_proc_commit((*commit));
+#define param_commit(plist)\
+ (*(plist)->procs->commit)(plist)
+
+} gs_param_list_procs;
+
+/* Define an abstract parameter dictionary. Implementations are */
+/* concrete subclasses. */
+#define gs_param_list_common\
+ const gs_param_list_procs _ds *procs
+struct gs_param_list_s {
+ gs_param_list_common;
+};
+
+/* Functionality common to all subclasses of gs_param_list */
+void param_init_enumerator(P1(gs_param_enumerator_t *));
+
+
+/*
+ * Define a default implementation, intended to be usable easily
+ * from C code. The intended usage pattern is:
+ gs_c_param_list list;
+ [... other code here ...]
+ gs_c_param_list_write(&list, mem);
+ [As many as needed:]
+ code = param_write_XXX(&list, "ParamName", &param_value);
+ [Check code for <0]
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(dev, &list);
+ gs_c_param_list_release(&list);
+ [Check code for <0]
+ if ( code == 1 )
+ { code = (*dev_proc(dev, open_device))(dev);
+ [Check code for <0]
+ }
+ */
+
+typedef struct gs_c_param_s gs_c_param; /* opaque here */
+typedef struct gs_c_param_list_s {
+ gs_param_list_common;
+ gs_memory_t *memory;
+ gs_c_param *head;
+ uint count;
+ bool has_int_keys;
+} gs_c_param_list;
+#define private_st_c_param_list() /* in gsparam.c */\
+ gs_private_st_ptrs1(st_c_param_list, gs_c_param_list, "c_param_list",\
+ c_param_list_enum_ptrs, c_param_list_reloc_ptrs, head)
+
+/* Clients normally allocate the gs_c_param_list on the stack. */
+void gs_c_param_list_write(P2(gs_c_param_list *, gs_memory_t *));
+void gs_c_param_list_read(P1(gs_c_param_list *)); /* switch to reading */
+void gs_c_param_list_release(P1(gs_c_param_list *));
+
+
+#endif /* gsparam_INCLUDED */
diff --git a/gs/src/gsparams.c b/gs/src/gsparams.c
new file mode 100644
index 000000000..f940c0fc4
--- /dev/null
+++ b/gs/src/gsparams.c
@@ -0,0 +1,400 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsparams.c */
+/* Generic parameter list serializer & expander */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsparams.h"
+
+
+/* ----------- Local Type Decl's ------------ */
+typedef struct {
+ byte* buf; /* current buffer ptr */
+ byte* buf_end; /* end of buffer */
+ unsigned total_sizeof; /* current # bytes in buf */
+} WriteBuffer;
+
+/* ---------- Forward refs ----------- */
+private void
+align_to(P2(
+ const byte **src, /* pointer to align */
+ unsigned alignment /* alignment, must be power of 2 */
+));
+private void
+put_word(P2(
+ unsigned source, /* number to put to buffer */
+ WriteBuffer *dest /* destination descriptor */
+));
+private void
+put_bytes(P3(
+ const byte *source, /* bytes to put to buffer */
+ unsigned source_sizeof, /* # bytes to put */
+ WriteBuffer *dest /* destination descriptor */
+));
+private void
+put_alignment(P2(
+ unsigned alignment, /* alignment to match, must be power 2 */
+ WriteBuffer *dest /* destination descriptor */
+));
+/* Get word compressed with put_word */
+private unsigned /* decompressed word */
+get_word(P1(
+ const byte **src /* UPDATES: ptr to src buf ptr */
+));
+
+
+/* ------------ Serializer ------------ */
+/* Serialize the contents of a gs_param_list (including sub-dicts) */
+int /* ret -ve err, else # bytes needed to represent param list, whether */
+ /* or not it actually fit into buffer. List was successully */
+ /* serialized only if if this # is <= supplied buf size. */
+gs_param_list_serialize(
+ gs_param_list *list, /* root of list to serialize */
+ /* list MUST BE IN READ MODE */
+ byte *buf, /* destination buffer (can be 0) */
+ int buf_sizeof /* # bytes available in buf (can be 0) */
+) {
+ int code = 0;
+ int temp_code;
+ gs_param_key_t key_enum;
+ WriteBuffer write_buf;
+ write_buf.buf = buf;
+ write_buf.buf_end = buf + (buf ? buf_sizeof : 0);
+ write_buf.total_sizeof = 0;
+ param_init_enumerator(&key_enum.enumerator);
+
+ /* Each item is serialized as ("word" means compressed word):
+ * word: key sizeof + 1, or 0 if end of list/dict
+ * word: data type(cpt_xxx)
+ * byte[]: key, including trailing \0
+ * (if simple type)
+ * byte[]: unpacked representation of data
+ * (if simple array or string)
+ * byte[]: unpacked mem image of gs_param_xxx_array structure
+ * pad: to array alignment
+ * byte[]: data associated with array contents
+ * (if string/name array)
+ * byte[]: unpacked mem image of gs_param_string_array structure
+ * pad: to void *
+ * { gs_param_string structure mem image;
+ * data associated with string;
+ * } for each string in array
+ * (if dict/dict_int_keys)
+ * word: # of entries in dict,
+ * pad: to void *
+ * dict entries follow immediately until end-of-dict
+ *
+ * NB that this format is designed to allow using an input buffer
+ * as the direct source of data when expanding a gs_c_param_list
+ */
+ /* Enumerate all the keys; use keys to get their typed values */
+ while ( ( code = param_get_next_key(list, &key_enum) ) == 0 )
+ {
+ int value_top_sizeof;
+ int value_base_sizeof;
+ int array_index;
+
+ /* Get next datum & put its type & key to buffer */
+ gs_param_typed_value value;
+ char string_key[256];
+ if ( sizeof(string_key) < key_enum.key_sizeof + 1 )
+ {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ memcpy(string_key, key_enum.key, key_enum.key_sizeof);
+ string_key[key_enum.key_sizeof] = 0;
+ if ( ( code = param_read_typed(list, string_key, &value) ) != 0 )
+ {
+ code = code > 0 ? gs_note_error(gs_error_unknownerror) : code;
+ break;
+ }
+ put_word( (unsigned)key_enum.key_sizeof + 1, &write_buf);
+ put_word( (unsigned)value.type, &write_buf );
+ put_bytes( (byte *)string_key, key_enum.key_sizeof + 1, &write_buf );
+
+ /* Put value & its size to buffer */
+ value_top_sizeof = gs_param_type_sizes[value.type];
+ value_base_sizeof = cpt_base_sizeof[value.type];
+ switch (value.type)
+ {
+ case cpt_null:
+ case cpt_bool:
+ case cpt_int:
+ case cpt_long:
+ case cpt_float:
+ put_bytes( (byte*)&value.value, value_top_sizeof, &write_buf);
+ break;
+
+ case cpt_string:
+ case cpt_name:
+ case cpt_int_array:
+ case cpt_float_array:
+ put_bytes( (byte*)&value.value, value_top_sizeof, &write_buf );
+ put_alignment(value_base_sizeof, &write_buf);
+ put_bytes(value.value.s.data,
+ value_base_sizeof * value.value.s.size, &write_buf);
+ break;
+
+ case cpt_string_array:
+ case cpt_name_array:
+ put_bytes( (byte*)&value.value, value_top_sizeof, &write_buf);
+ put_alignment( sizeof(void *), &write_buf );
+ put_bytes( (byte*)value.value.sa.data,
+ value_base_sizeof * value.value.sa.size, &write_buf );
+ {
+ int str_count;
+ const gs_param_string *sa;
+ for (str_count = value.value.sa.size,
+ sa = value.value.sa.data; str_count-- > 0; ++sa)
+ put_bytes(sa->data, sa->size, &write_buf);
+ }
+ break;
+
+ case cpt_dict:
+ case cpt_dict_int_keys:
+ put_word(value.value.d.size, &write_buf);
+ put_alignment( sizeof(void *), &write_buf );
+ {
+ int bytes_written = gs_param_list_serialize(value.value.d.list,
+ write_buf.buf,
+ write_buf.buf ? write_buf.buf_end - write_buf.buf : 0);
+ temp_code
+ = param_end_read_dict(list, key_enum.key, &value.value.d);
+ if (bytes_written < 0)
+ code = bytes_written;
+ else
+ {
+ code = temp_code;
+ if (bytes_written)
+ put_bytes(buf, bytes_written, &write_buf);
+ }
+ }
+ break;
+
+ default:
+ code = gs_note_error(gs_error_unknownerror);
+ break;
+ }
+ if (code < 0)
+ break;
+ }
+
+ /* Write end marker, which is an (illegal) 0 key length */
+ if (code >= 0)
+ {
+ put_word(0, &write_buf);
+ code = write_buf.total_sizeof;
+ }
+
+ return code;
+ }
+
+
+/* ------------ Expander --------------- */
+/* Expand a buffer into a gs_param_list (including sub-dicts) */
+int /* ret -ve err, +ve # of chars read from buffer */
+gs_param_list_unserialize(
+ gs_param_list *list, /* root of list to expand to */
+ /* list MUST BE IN WRITE MODE */
+ const byte *buf /* source buffer */
+) {
+ int code = 0;
+ const byte *orig_buf = buf;
+ do
+ {
+ gs_param_typed_value typed;
+ gs_param_name key;
+ unsigned key_sizeof;
+ int value_top_sizeof;
+ int value_base_sizeof;
+ int temp_code;
+ gs_param_type type;
+
+ /* key length, 0 indicates end of data */
+ key_sizeof = get_word(&buf);
+ if (key_sizeof == 0) /* end of data */
+ break;
+
+ /* data type */
+ type = (gs_param_type)get_word(&buf);
+
+ /* key */
+ key = (gs_param_name)buf;
+ buf += key_sizeof;
+
+ /* Data values */
+ value_top_sizeof = gs_param_type_sizes[type];
+ value_base_sizeof = cpt_base_sizeof[type];
+ typed.type = type;
+ if (type != cpt_dict && type != cpt_dict_int_keys)
+ { memcpy(&typed.value, buf, value_top_sizeof);
+ buf += value_top_sizeof;
+ }
+ switch (type)
+ {
+ case cpt_null:
+ case cpt_bool:
+ case cpt_int:
+ case cpt_long:
+ case cpt_float:
+ break;
+
+ case cpt_string:
+ case cpt_name:
+ case cpt_int_array:
+ case cpt_float_array:
+ align_to(&buf, value_base_sizeof);
+ typed.value.s.data = buf;
+ typed.value.s.persistent = false;
+ buf += typed.value.s.size * value_base_sizeof;
+ break;
+
+ case cpt_string_array:
+ case cpt_name_array:
+ align_to( &buf, sizeof(void *) );
+ typed.value.sa.data = (gs_param_string *)buf;
+ typed.value.sa.persistent = false;
+ buf += typed.value.s.size * value_base_sizeof;
+ {
+ int str_count;
+ gs_param_string *sa;
+ for ( str_count = typed.value.sa.size,
+ sa = (gs_param_string *)typed.value.sa.data;
+ str_count-- > 0; ++sa )
+ {
+ sa->data = buf;
+ sa->persistent = false;
+ buf += sa->size;
+ }
+ }
+ break;
+
+ case cpt_dict:
+ case cpt_dict_int_keys:
+ typed.value.d.size = get_word(&buf);
+ code = param_begin_write_dict
+ (list, key, &typed.value.d, type == cpt_dict_int_keys);
+ if (code < 0)
+ break;
+ align_to( &buf, sizeof(void *) );
+ code = gs_param_list_unserialize(typed.value.d.list, buf);
+ temp_code = param_end_write_dict(list, key, &typed.value.d);
+ if (code >= 0)
+ {
+ buf += code;
+ code = temp_code;
+ }
+ break;
+
+ default:
+ code = gs_note_error(gs_error_unknownerror);
+ break;
+ }
+ if (code < 0)
+ break;
+ if (typed.type != cpt_dict && typed.type != cpt_dict_int_keys)
+ code = param_write_typed(list, key, &typed);
+ }
+ while (code >= 0);
+
+ return code >= 0 ? buf - orig_buf : code;
+ }
+
+
+/* ---------- Utility functions -------- */
+
+/* Align a byte pointer on the next Nth byte */
+private void
+align_to(
+ const byte **src, /* pointer to align */
+ unsigned alignment /* alignment, must be power of 2 */
+) {
+ *src += -(int)alignment_mod(*src, alignment) & (alignment - 1);
+ }
+
+/* Put compressed word repr to a buffer */
+private void
+put_word(
+ unsigned source, /* number to put to buffer */
+ WriteBuffer *dest /* destination descriptor */
+) {
+ do
+ {
+ byte chunk = source & 0x7f;
+ if (source >= 0x80)
+ chunk |= 0x80;
+ source >>= 7;
+ ++dest->total_sizeof;
+ if (dest->buf && dest->buf < dest->buf_end)
+ *dest->buf++ = chunk;
+ }
+ while (source != 0);
+ }
+
+/* Put array of bytes to buffer */
+private void
+put_bytes(
+ const byte *source, /* bytes to put to buffer */
+ unsigned source_sizeof, /* # bytes to put */
+ WriteBuffer *dest /* destination descriptor */
+) {
+ dest->total_sizeof += source_sizeof;
+ if (dest->buf && dest->buf + source_sizeof <= dest->buf_end)
+ {
+ if (dest->buf != source)
+ memcpy(dest->buf, source, source_sizeof);
+ dest->buf += source_sizeof;
+ }
+ }
+
+/* Pad destination out to req'd alignment w/zeros */
+private void
+put_alignment(
+ unsigned alignment, /* alignment to match, must be power 2 */
+ WriteBuffer *dest /* destination descriptor */
+) {
+ static const byte zero = {0};
+ while ( ( dest->total_sizeof & (alignment - 1) ) != 0 )
+ put_bytes(&zero, 1, dest);
+ }
+
+/* Get word compressed with put_word */
+private unsigned /* decompressed word */
+get_word(
+ const byte **src /* UPDATES: ptr to src buf ptr */
+) {
+ unsigned dest = 0;
+ byte chunk;
+ unsigned shift = 0;
+ do
+ {
+ chunk = *(*src)++;
+ dest |= (chunk & 0x7f) << shift;
+ shift += 7;
+ }
+ while (chunk & 0x80);
+
+ return dest;
+ }
+
diff --git a/gs/src/gsparams.h b/gs/src/gsparams.h
new file mode 100644
index 000000000..1a3ea0e26
--- /dev/null
+++ b/gs/src/gsparams.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsparams.h */
+/* Serializer/expander for gs_parm_list's */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "gsparam.h"
+
+/* -------------------------------------------------------------------------- */
+int /* ret -ve err, else # bytes needed to represent param list, whether */
+ /* or not it actually fit into buffer. List was successully */
+ /* serialized only if if this # is <= supplied buf size. */
+gs_param_list_serialize(P3(
+ gs_param_list *list, /* root of list to serialize */
+ /* list MUST BE IN READ MODE */
+ byte *buf, /* destination buffer (can be 0) */
+ int buf_sizeof /* # bytes available in buf (can be 0) */
+));
+
+/* Expand a buffer into a gs_param_list (including sub-dicts) */
+int /* ret -ve err, +ve # of chars read from buffer */
+gs_param_list_unserialize(P2(
+ gs_param_list *list, /* root of list to expand to */
+ /* list MUST BE IN WRITE MODE */
+ const byte *buf /* source buffer, MUST BE void* aligned */
+));
+
diff --git a/gs/src/gspath.c b/gs/src/gspath.c
new file mode 100644
index 000000000..0bd71b5c7
--- /dev/null
+++ b/gs/src/gspath.c
@@ -0,0 +1,416 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspath.c */
+/* Basic path routines for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h" /* for gxcpath.h */
+#include "gzcpath.h"
+
+/* ------ Miscellaneous ------ */
+
+int
+gs_newpath(gs_state *pgs)
+{ gx_path_release(pgs->path);
+ gx_path_init(pgs->path, pgs->memory);
+ return 0;
+}
+
+int
+gs_closepath(gs_state *pgs)
+{ gx_path *ppath = pgs->path;
+ int code = gx_path_close_subpath(ppath);
+
+ if ( code < 0 )
+ return code;
+ if ( path_start_outside_range(ppath) )
+ path_set_outside_position(ppath, ppath->outside_start.x,
+ ppath->outside_start.y);
+ return code;
+}
+
+int
+gs_upmergepath(gs_state *pgs)
+{ return gx_path_add_path(pgs->saved->path, pgs->path);
+}
+
+/* Get the current path (for internal use only). */
+gx_path *
+gx_current_path(const gs_state *pgs)
+{ return pgs->path;
+}
+
+/* ------ Points and lines ------ */
+
+/*
+ * Define clamped values for out-of-range coordinates.
+ * Currently the path drawing routines can't handle values
+ * close to the edge of the representable space.
+ */
+#define max_coord_fixed (max_fixed - int2fixed(1000)) /* arbitrary */
+#define min_coord_fixed (-max_coord_fixed)
+private void
+clamp_point(gs_fixed_point *ppt, floatp x, floatp y)
+{
+#define clamp_coord(xy)\
+ ppt->xy = (xy > fixed2float(max_coord_fixed) ? max_coord_fixed :\
+ xy < fixed2float(min_coord_fixed) ? min_coord_fixed :\
+ float2fixed(xy))
+ clamp_coord(x);
+ clamp_coord(y);
+#undef clamp_coord
+}
+
+int
+gs_currentpoint(const gs_state *pgs, gs_point *ppt)
+{ gx_path *ppath = pgs->path;
+ int code;
+ gs_fixed_point pt;
+
+ if ( path_outside_range(ppath) )
+ return gs_itransform((gs_state *)pgs,
+ ppath->outside_position.x,
+ ppath->outside_position.y, ppt);
+ code = gx_path_current_point(pgs->path, &pt);
+ if ( code < 0 )
+ return code;
+ return gs_itransform((gs_state *)pgs,
+ fixed2float(pt.x), fixed2float(pt.y), ppt);
+}
+
+int
+gs_moveto(gs_state *pgs, floatp x, floatp y)
+{ gx_path *ppath = pgs->path;
+ gs_fixed_point pt;
+ int code;
+
+ if ( (code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0 )
+ { if ( pgs->clamp_coordinates )
+ { /* Handle out-of-range coordinates. */
+ gs_point opt;
+
+ if ( code != gs_error_limitcheck ||
+ (code = gs_transform(pgs, x, y, &opt)) < 0
+ )
+ return code;
+ clamp_point(&pt, opt.x, opt.y);
+ code = gx_path_add_point(ppath, pt.x, pt.y);
+ if ( code < 0 )
+ return code;
+ path_set_outside_position(ppath, opt.x, opt.y);
+ ppath->outside_start = ppath->outside_position;
+ ppath->start_flags = ppath->state_flags;
+ }
+ return code;
+ }
+ return gx_path_add_point(ppath, pt.x, pt.y);
+}
+
+int
+gs_rmoveto(gs_state *pgs, floatp x, floatp y)
+{ gs_fixed_point dpt;
+ int code;
+
+ if ( (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 ||
+ (code = gx_path_add_relative_point(pgs->path, dpt.x, dpt.y)) < 0
+ )
+ { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ( (code = gs_currentpoint(pgs, &upt)) < 0 )
+ return code;
+ return gs_moveto(pgs, upt.x + x, upt.y + y);
+ }
+ return code;
+}
+
+int
+gs_lineto(gs_state *pgs, floatp x, floatp y)
+{ gx_path *ppath = pgs->path;
+ int code;
+ gs_fixed_point pt;
+
+ if ( (code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0 )
+ { if ( pgs->clamp_coordinates )
+ { /* Handle out-of-range coordinates. */
+ gs_point opt;
+
+ if ( code != gs_error_limitcheck ||
+ (code = gs_transform(pgs, x, y, &opt)) < 0
+ )
+ return code;
+ clamp_point(&pt, opt.x, opt.y);
+ code = gx_path_add_line(ppath, pt.x, pt.y);
+ if ( code < 0 )
+ return code;
+ path_set_outside_position(ppath, opt.x, opt.y);
+ }
+ return code;
+ }
+ return gx_path_add_line(pgs->path, pt.x, pt.y);
+}
+
+int
+gs_rlineto(gs_state *pgs, floatp x, floatp y)
+{ gx_path *ppath = pgs->path;
+ gs_fixed_point dpt;
+ fixed nx, ny;
+ int code;
+
+ if ( !path_position_in_range(ppath) ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 ||
+ /* Check for overflow in addition. */
+ (((nx = ppath->position.x + dpt.x) ^ dpt.x) < 0 &&
+ (ppath->position.x ^ dpt.x) >= 0) ||
+ (((ny = ppath->position.y + dpt.y) ^ dpt.y) < 0 &&
+ (ppath->position.y ^ dpt.y) >= 0) ||
+ (code = gx_path_add_line(ppath, nx, ny)) < 0
+ )
+ { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ( (code = gs_currentpoint(pgs, &upt)) < 0 )
+ return code;
+ return gs_lineto(pgs, upt.x + x, upt.y + y);
+ }
+ return code;
+}
+
+/* ------ Curves ------ */
+
+int
+gs_curveto(gs_state *pgs,
+ floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
+{ gs_fixed_point p1, p2, p3;
+ int code1 = gs_point_transform2fixed(&pgs->ctm, x1, y1, &p1);
+ int code2 = gs_point_transform2fixed(&pgs->ctm, x2, y2, &p2);
+ int code3 = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3);
+ gx_path *ppath = pgs->path;
+
+ if ( (code1 | code2 | code3) < 0 )
+ { if ( pgs->clamp_coordinates )
+ { /* Handle out-of-range coordinates. */
+ gs_point opt1, opt2, opt3;
+ int code;
+
+ if ( (code1 < 0 && code1 != gs_error_limitcheck) ||
+ (code1 = gs_transform(pgs, x1, y1, &opt1)) < 0
+ )
+ return code1;
+ if ( (code2 < 0 && code2 != gs_error_limitcheck) ||
+ (code2 = gs_transform(pgs, x2, y2, &opt2)) < 0
+ )
+ return code2;
+ if ( (code3 < 0 && code3 != gs_error_limitcheck) ||
+ (code3 = gs_transform(pgs, x3, y3, &opt3)) < 0
+ )
+ return code3;
+ clamp_point(&p1, opt1.x, opt1.y);
+ clamp_point(&p2, opt2.x, opt2.y);
+ clamp_point(&p3, opt3.x, opt3.y);
+ code = gx_path_add_curve(ppath,
+ p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+ if ( code < 0 )
+ return code;
+ path_set_outside_position(ppath, opt3.x, opt3.y);
+ return code;
+ }
+ else
+ return (code1 < 0 ? code1 : code2 < 0 ? code2 : code3);
+ }
+ return gx_path_add_curve(ppath,
+ p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+}
+
+int
+gs_rcurveto(gs_state *pgs,
+ floatp dx1, floatp dy1, floatp dx2, floatp dy2, floatp dx3, floatp dy3)
+{ gx_path *ppath = pgs->path;
+ gs_fixed_point p1, p2, p3;
+ fixed ptx, pty;
+ int code;
+
+ /****** SHOULD CHECK FOR OVERFLOW IN ADDITION ******/
+ if ( !path_position_in_range(ppath) ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx1, dy1, &p1)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx2, dy2, &p2)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx3, dy3, &p3)) < 0 ||
+ (ptx = ppath->position.x, pty = ppath->position.y,
+ code = gx_path_add_curve(ppath, ptx + p1.x, pty + p1.y,
+ ptx + p2.x, pty + p2.y,
+ ptx + p3.x, pty + p3.y)) < 0
+ )
+ { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ( (code = gs_currentpoint(pgs, &upt)) < 0 )
+ return code;
+ return gs_curveto(pgs, upt.x + dx1, upt.y + dy1,
+ upt.x + dx2, upt.y + dy2,
+ upt.x + dx3, upt.y + dy3);
+ }
+ return code;
+}
+
+/* ------ Clipping ------ */
+
+/* Forward references */
+private int common_clip(P2(gs_state *, int));
+private int set_clip_path(P2(gs_state *, gx_clip_path *));
+
+int
+gs_clippath(gs_state *pgs)
+{ gx_path path, cpath;
+ int code = gx_cpath_path(pgs->clip_path, &path);
+
+ if ( code < 0 )
+ return code;
+ code = gx_path_copy(&path, &cpath, 1);
+ if ( code < 0 )
+ return code;
+ gx_path_release(pgs->path);
+ *pgs->path = cpath;
+ return 0;
+}
+
+int
+gs_initclip(gs_state *pgs)
+{ register gx_device *dev = gs_currentdevice(pgs);
+ gs_rect bbox;
+ gs_fixed_rect box;
+ gs_matrix imat;
+
+ if ( dev->ImagingBBox_set )
+ { /* Use the ImagingBBox, relative to default user space. */
+ gs_defaultmatrix(pgs, &imat);
+ bbox.p.x = dev->ImagingBBox[0];
+ bbox.p.y = dev->ImagingBBox[1];
+ bbox.q.x = dev->ImagingBBox[2];
+ bbox.q.y = dev->ImagingBBox[3];
+ }
+ else
+ { /* Use the MediaSize indented by the HWMargins, */
+ /* relative to unrotated user space adjusted by */
+ /* the Margins. (We suspect this isn't quite right, */
+ /* but the whole issue of "margins" is such a mess that */
+ /* we don't think we can do any better.) */
+ (*dev_proc(dev, get_initial_matrix))(dev, &imat);
+ /* Adjust for the Margins. */
+ imat.tx += dev->Margins[0] * dev->HWResolution[0] /
+ dev->MarginsHWResolution[0];
+ imat.ty += dev->Margins[1] * dev->HWResolution[1] /
+ dev->MarginsHWResolution[1];
+ bbox.p.x = dev->HWMargins[0];
+ bbox.p.y = dev->HWMargins[1];
+ bbox.q.x = dev->MediaSize[0] - dev->HWMargins[2];
+ bbox.q.y = dev->MediaSize[1] - dev->HWMargins[3];
+ }
+ gs_bbox_transform(&bbox, &imat, &bbox);
+ /* Round the clipping box so that it doesn't get ceilinged. */
+ box.p.x = fixed_rounded(float2fixed(bbox.p.x));
+ box.p.y = fixed_rounded(float2fixed(bbox.p.y));
+ box.q.x = fixed_rounded(float2fixed(bbox.q.x));
+ box.q.y = fixed_rounded(float2fixed(bbox.q.y));
+ return gx_clip_to_rectangle(pgs, &box);
+}
+
+int
+gs_clip(gs_state *pgs)
+{ return common_clip(pgs, gx_rule_winding_number);
+}
+
+int
+gs_eoclip(gs_state *pgs)
+{ return common_clip(pgs, gx_rule_even_odd);
+}
+
+private int
+common_clip(gs_state *pgs, int rule)
+{ gx_path fpath;
+ int code = gx_path_flatten_accurate(pgs->path, &fpath, pgs->flatness,
+ pgs->accurate_curves);
+
+ if ( code < 0 )
+ return code;
+ code = gx_cpath_intersect(pgs, pgs->clip_path, &fpath, rule);
+ if ( code != 1 )
+ gx_path_release(&fpath);
+ if ( code < 0 )
+ return code;
+ pgs->clip_path->rule = rule;
+ return set_clip_path(pgs, pgs->clip_path);
+}
+
+int
+gs_setclipoutside(gs_state *pgs, bool outside)
+{ return gx_cpath_set_outside(pgs->clip_path, outside);
+}
+
+bool
+gs_currentclipoutside(const gs_state *pgs)
+{ return gx_cpath_is_outside(pgs->clip_path);
+}
+
+/* Establish a rectangle as the clipping path. */
+/* Used by initclip and by the character and Pattern cache logic. */
+int
+gx_clip_to_rectangle(gs_state *pgs, gs_fixed_rect *pbox)
+{ gx_clip_path cpath;
+ int code = gx_cpath_from_rectangle(&cpath, pbox, pgs->memory);
+
+ if ( code < 0 )
+ return code;
+ gx_cpath_release(pgs->clip_path);
+ cpath.rule = gx_rule_winding_number;
+ return set_clip_path(pgs, &cpath);
+}
+
+/* Set the clipping path to the current path, without intersecting. */
+/* Currently only used by the insideness testing operators, */
+/* but might be used by viewclip eventually. */
+/* The algorithm is very inefficient; we'll improve it later if needed. */
+int
+gx_clip_to_path(gs_state *pgs)
+{ gs_fixed_rect bbox;
+ int code;
+ if ( (code = gx_path_bbox(pgs->path, &bbox)) < 0 ||
+ (code = gx_clip_to_rectangle(pgs, &bbox)) < 0
+ )
+ return code;
+ return gs_clip(pgs);
+}
+
+/* Set the clipping path (internal). */
+private int
+set_clip_path(gs_state *pgs, gx_clip_path *pcpath)
+{ *pgs->clip_path = *pcpath;
+#ifdef DEBUG
+if ( gs_debug_c('P') )
+ { extern void gx_cpath_print(P1(const gx_clip_path *));
+ dprintf("[P]Clipping path:\n"),
+ gx_cpath_print(pcpath);
+ }
+#endif
+ return 0;
+}
diff --git a/gs/src/gspath.h b/gs/src/gspath.h
new file mode 100644
index 000000000..b2f04d7bc
--- /dev/null
+++ b/gs/src/gspath.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspath.h */
+/* Client interface to path manipulation facilities */
+/* Requires gsstate.h */
+#include "gspenum.h"
+
+/* Path constructors */
+int gs_newpath(P1(gs_state *)),
+ gs_moveto(P3(gs_state *, floatp, floatp)),
+ gs_rmoveto(P3(gs_state *, floatp, floatp)),
+ gs_lineto(P3(gs_state *, floatp, floatp)),
+ gs_rlineto(P3(gs_state *, floatp, floatp)),
+ gs_arc(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)),
+ gs_arcn(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)),
+/*
+ * Because of an obscure bug in the IBM RS/6000 compiler, one (but not both)
+ * bool argument(s) for gs_arc_add must come before the floatp arguments.
+ */
+ gs_arc_add(P8(gs_state *, bool, floatp, floatp, floatp, floatp, floatp, bool)),
+ gs_arcto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, float [4])),
+ gs_curveto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)),
+ gs_rcurveto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)),
+ gs_closepath(P1(gs_state *));
+
+/* Add the current path to the path in the previous graphics state. */
+int gs_upmergepath(P1(gs_state *));
+
+/* Path accessors and transformers */
+int gs_currentpoint(P2(const gs_state *, gs_point *)),
+ gs_upathbbox(P3(gs_state *, gs_rect *, bool)),
+ gs_dashpath(P1(gs_state *)),
+ gs_flattenpath(P1(gs_state *)),
+ gs_reversepath(P1(gs_state *)),
+ gs_strokepath(P1(gs_state *));
+/* The extra argument for gs_upathbbox controls whether to include */
+/* a trailing moveto in the bounding box. */
+#define gs_pathbbox(pgs, prect)\
+ gs_upathbbox(pgs, prect, false)
+
+/* Path enumeration */
+
+/* This interface makes a copy of the path. */
+gs_path_enum *
+ gs_path_enum_alloc(P2(gs_memory_t *, client_name_t));
+int gs_path_enum_init(P2(gs_path_enum *, const gs_state *));
+int gs_path_enum_next(P2(gs_path_enum *, gs_point [3])); /* 0 when done */
+void gs_path_enum_cleanup(P1(gs_path_enum *));
+
+/* Clipping */
+int gs_clippath(P1(gs_state *)),
+ gs_initclip(P1(gs_state *)),
+ gs_clip(P1(gs_state *)),
+ gs_eoclip(P1(gs_state *));
+int gs_setclipoutside(P2(gs_state *, bool));
+bool gs_currentclipoutside(P1(const gs_state *));
diff --git a/gs/src/gspath1.c b/gs/src/gspath1.c
new file mode 100644
index 000000000..0a6fbea8d
--- /dev/null
+++ b/gs/src/gspath1.c
@@ -0,0 +1,376 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspath1.c */
+/* Additional PostScript Level 1 path routines for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gscoord.h" /* gs_itransform prototype */
+
+/* ------ Arcs ------ */
+
+/* Conversion parameters */
+#define degrees_to_radians (M_PI / 180.0)
+
+/* Forward declarations */
+/*
+ * Because of an obscure bug in the IBM RS/6000 compiler, the int argument
+ * for arc_add must come before the floatp arguments.
+ */
+typedef enum {
+ arc_nothing,
+ arc_moveto,
+ arc_lineto
+} arc_action;
+private int arc_add(P10(gs_state *, arc_action, segment_notes,
+ floatp, floatp, floatp, floatp, floatp, floatp, floatp));
+
+int
+gs_arc(gs_state *pgs,
+ floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{ return gs_arc_add(pgs, false, xc, yc, r, ang1, ang2, true);
+}
+
+int
+gs_arcn(gs_state *pgs,
+ floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{ return gs_arc_add(pgs, true, xc, yc, r, ang1, ang2, true);
+}
+
+int
+gs_arc_add(gs_state *pgs, bool clockwise, floatp axc, floatp ayc, floatp arad,
+ floatp aang1, floatp aang2, bool add_line)
+{ double ar = arad;
+ fixed ang1 = float2fixed(aang1), ang2 = float2fixed(aang2), adiff;
+ double ang1r; /* reduced angle */
+ gs_sincos_t sincos;
+ double x0, y0, sin0, cos0;
+ double x3r, y3r;
+ arc_action action = (add_line ? arc_lineto : arc_moveto);
+ segment_notes notes = sn_none;
+ int code;
+
+#define fixed_90 int2fixed(90)
+#define fixed_180 int2fixed(180)
+#define fixed_360 int2fixed(360)
+ if ( ar < 0 )
+ { ang1 += fixed_180;
+ ang2 += fixed_180;
+ ar = - ar;
+ }
+ ang1r = fixed2float(ang1 % fixed_360);
+ gs_sincos_degrees(ang1r, &sincos);
+ sin0 = ar * sincos.sin, cos0 = ar * sincos.cos;
+ x0 = axc + cos0, y0 = ayc + sin0;
+ if ( clockwise )
+ { /* Quadrant reduction */
+ while ( ang1 < ang2 ) ang2 -= fixed_360;
+ while ( (adiff = ang2 - ang1) < -fixed_90 )
+ { double w = sin0; sin0 = -cos0; cos0 = w;
+ x3r = axc + cos0, y3r = ayc + sin0;
+ code = arc_add(pgs, action, notes,
+ ar, x0, y0, x3r, y3r,
+ x0 + cos0, y0 + sin0);
+ if ( code < 0 ) return code;
+ x0 = x3r, y0 = y3r;
+ ang1 -= fixed_90;
+ action = arc_nothing;
+ notes = sn_not_first;
+ }
+ }
+ else
+ { /* Quadrant reduction */
+ while ( ang2 < ang1 ) ang2 += fixed_360;
+ while ( (adiff = ang2 - ang1) > fixed_90 )
+ { double w = cos0; cos0 = -sin0; sin0 = w;
+ x3r = axc + cos0, y3r = ayc + sin0;
+ code = arc_add(pgs, action, notes,
+ ar, x0, y0, x3r, y3r,
+ x0 + cos0, y0 + sin0);
+ if ( code < 0 ) return code;
+ x0 = x3r, y0 = y3r;
+ ang1 += fixed_90;
+ action = arc_nothing;
+ notes = sn_not_first;
+ }
+ }
+ /* Compute the intersection of the tangents. */
+ /* We define xt and yt as separate variables to work around */
+ /* a floating point bug in one of the SPARC compilers. */
+ /* We know that -fixed_90 <= adiff <= fixed_90. */
+ { double trad =
+ tan(fixed2float(adiff) * (degrees_to_radians / 2));
+ double xt = x0 - trad * sin0, yt = y0 + trad * cos0;
+ gs_sincos_degrees(fixed2float(ang2), &sincos);
+ code = arc_add(pgs, action, notes,
+ ar, x0, y0,
+ (axc + ar * sincos.cos),
+ (ayc + ar * sincos.sin),
+ xt, yt);
+ }
+ return code;
+}
+
+int
+gs_arcto(gs_state *pgs,
+ floatp ax1, floatp ay1, floatp ax2, floatp ay2, floatp arad, float retxy[4])
+{ double xt0, yt0, xt2, yt2;
+ gs_point up0;
+#define ax0 up0.x
+#define ay0 up0.y
+ /* Transform the current point back into user coordinates. */
+ int code = gs_currentpoint(pgs, &up0);
+
+ if ( code < 0 )
+ return code;
+ { /* Now we have to compute the tangent points. */
+ /* Basically, the idea is to compute the tangent */
+ /* of the bisector by using tan(x+y) and tan(z/2) */
+ /* formulas, without ever using any trig. */
+ double dx0 = ax0 - ax1, dy0 = ay0 - ay1;
+ double dx2 = ax2 - ax1, dy2 = ay2 - ay1;
+ /* Compute the squared lengths from p1 to p0 and p2. */
+ double sql0 = dx0 * dx0 + dy0 * dy0;
+ double sql2 = dx2 * dx2 + dy2 * dy2;
+ /* Compute the distance from p1 to the tangent points. */
+ /* This is the only messy part. */
+ double num = dy0 * dx2 - dy2 * dx0;
+ double denom = sqrt(sql0 * sql2) - (dx0 * dx2 + dy0 * dy2);
+
+ /* Check for collinear points. */
+ if ( denom == 0 )
+ { code = gs_lineto(pgs, ax1, ay1);
+ xt0 = xt2 = ax1;
+ yt0 = yt2 = ay1;
+ }
+ else /* not collinear */
+ { double dist = fabs(arad * num / denom);
+ double l0 = dist / sqrt(sql0), l2 = dist / sqrt(sql2);
+
+ if ( arad < 0 )
+ l0 = -l0, l2 = -l2;
+ xt0 = ax1 + dx0 * l0;
+ yt0 = ay1 + dy0 * l0;
+ xt2 = ax1 + dx2 * l2;
+ yt2 = ay1 + dy2 * l2;
+ code = arc_add(pgs, arc_lineto, sn_none,
+ arad, xt0, yt0, xt2, yt2, ax1, ay1);
+ }
+ }
+ if ( retxy != 0 )
+ { retxy[0] = xt0;
+ retxy[1] = yt0;
+ retxy[2] = xt2;
+ retxy[3] = yt2;
+ }
+ return code;
+}
+
+/* Internal routine for adding an arc to the path. */
+private int
+arc_add(gs_state *pgs, arc_action action, segment_notes notes,
+ floatp r, floatp x0, floatp y0, floatp x3, floatp y3, floatp xt, floatp yt)
+{ gx_path *path = pgs->path;
+ floatp dx = xt - x0, dy = yt - y0;
+ double dist = dx * dx + dy * dy;
+ double r2 = r * r;
+ floatp fraction;
+ gs_fixed_point p0, p3, pt, cpt;
+ int code;
+
+ /* Compute the fraction coefficient for the curve. */
+ /* See gx_path_add_partial_arc for details. */
+ if ( dist >= r2 * 1.0e8 ) /* almost zero radius; */
+ /* the >= catches dist == r == 0 */
+ fraction = 0.0;
+ else
+ fraction = (4.0/3.0) / (1 + sqrt(1 + dist / r2));
+ if_debug8('r',
+ "[r]Arc f=%f p0=(%f,%f) pt=(%f,%f) p3=(%f,%f) action=%d\n",
+ fraction, x0, y0, xt, yt, x3, y3, (int)action);
+ if ( (code = gs_point_transform2fixed(&pgs->ctm, x0, y0, &p0)) < 0 ||
+ (code = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3)) < 0 ||
+ (code = gs_point_transform2fixed(&pgs->ctm, xt, yt, &pt)) < 0 ||
+ (code =
+ (action == arc_nothing ? 0 :
+ action == arc_lineto &&
+ gx_path_current_point(path, &cpt) >= 0 ?
+ gx_path_add_line(path, p0.x, p0.y) :
+ /* action == arc_moveto */
+ gx_path_add_point(path, p0.x, p0.y))) < 0
+ )
+ return code;
+ return gx_path_add_partial_arc_notes(path, p3.x, p3.y, pt.x, pt.y,
+ fraction, notes);
+}
+
+/* ------ Path transformers ------ */
+
+int
+gs_dashpath(gs_state *pgs)
+{ gx_path fpath;
+ int code;
+
+ if ( gs_currentdash_length == 0 )
+ return 0; /* no dash pattern */
+ code = gs_flattenpath(pgs);
+ if ( code < 0 )
+ return code;
+ code = gx_path_expand_dashes(pgs->path, &fpath,
+ (const gs_imager_state *)pgs);
+ if ( code < 0 )
+ return code;
+ gx_path_release(pgs->path);
+ *pgs->path = fpath;
+ return 0;
+}
+
+int
+gs_flattenpath(gs_state *pgs)
+{ gx_path fpath;
+ int code;
+ if ( !pgs->path->curve_count ) return 0; /* no curves */
+ code = gx_path_flatten_accurate(pgs->path, &fpath, pgs->flatness,
+ pgs->accurate_curves);
+ if ( code < 0 ) return code;
+ gx_path_release(pgs->path);
+ *pgs->path = fpath;
+ return 0;
+}
+
+int
+gs_reversepath(gs_state *pgs)
+{ gx_path rpath;
+ int code = gx_path_copy_reversed(pgs->path, &rpath, 1);
+ if ( code < 0 ) return code;
+ gx_path_release(pgs->path);
+ *pgs->path = rpath;
+ return 0;
+}
+
+/* ------ Accessors ------ */
+
+int
+gs_upathbbox(gs_state *pgs, gs_rect *pbox, bool include_moveto)
+{ gs_fixed_rect fbox; /* box in device coordinates */
+ gs_rect dbox;
+ int code = gx_path_bbox(pgs->path, &fbox);
+
+ if ( code < 0 )
+ return code;
+ /* If the path ends with a moveto and include_moveto is true, */
+ /* include the moveto in the bounding box. */
+ if ( path_last_is_moveto(pgs->path) && include_moveto )
+ { gs_fixed_point pt;
+ gx_path_current_point_inline(pgs->path, &pt);
+ if ( pt.x < fbox.p.x )
+ fbox.p.x = pt.x;
+ if ( pt.y < fbox.p.y )
+ fbox.p.y = pt.y;
+ if ( pt.x > fbox.q.x )
+ fbox.q.x = pt.x;
+ if ( pt.y > fbox.q.y )
+ fbox.q.y = pt.y;
+ }
+ /* Transform the result back to user coordinates. */
+ dbox.p.x = fixed2float(fbox.p.x);
+ dbox.p.y = fixed2float(fbox.p.y);
+ dbox.q.x = fixed2float(fbox.q.x);
+ dbox.q.y = fixed2float(fbox.q.y);
+ return gs_bbox_transform_inverse(&dbox, &ctm_only(pgs), pbox);
+}
+
+/* ------ Enumerators ------ */
+
+/* Start enumerating a path */
+int
+gs_path_enum_init(gs_path_enum *penum, const gs_state *pgs)
+{ gx_path *copied_path = gx_path_alloc(pgs->memory, "gs_path_enum_init");
+ int code;
+
+ if ( copied_path == 0 )
+ return_error(gs_error_VMerror);
+ code = gx_path_copy(pgs->path, copied_path, 1);
+ if ( code < 0 )
+ { gs_free_object(pgs->memory, copied_path, "gs_path_enum_init");
+ return code;
+ }
+ gx_path_enum_init(penum, copied_path);
+ penum->pgs = pgs;
+ penum->copied_path = copied_path;
+ return 0;
+}
+
+/* Enumerate the next element of a path. */
+/* If the path is finished, return 0; */
+/* otherwise, return the element type. */
+int
+gs_path_enum_next(gs_path_enum *penum, gs_point ppts[3])
+{ gs_fixed_point fpts[3];
+ gs_state *pgs = (gs_state *)penum->pgs; /* discard const */
+ int pe_op = gx_path_enum_next(penum, fpts);
+ int code;
+
+ switch ( pe_op )
+ {
+ case 0: /* all done */
+ case gs_pe_closepath:
+ break;
+ case gs_pe_curveto:
+ if ( (code = gs_itransform(pgs,
+ fixed2float(fpts[1].x),
+ fixed2float(fpts[1].y),
+ &ppts[1])) < 0 ||
+ (code = gs_itransform(pgs,
+ fixed2float(fpts[2].x),
+ fixed2float(fpts[2].y),
+ &ppts[2])) < 0 )
+ return code;
+ case gs_pe_moveto:
+ case gs_pe_lineto:
+ if ( (code = gs_itransform(pgs,
+ fixed2float(fpts[0].x),
+ fixed2float(fpts[0].y),
+ &ppts[0])) < 0 )
+ return code;
+ default: /* error */
+ break;
+ }
+ return pe_op;
+}
+
+/* Clean up after a pathforall. */
+void
+gs_path_enum_cleanup(gs_path_enum *penum)
+{ if ( penum->copied_path != 0 ) /* don't do it twice ... */
+ /* shouldn't be needed! */
+ { gx_path_release(penum->copied_path);
+ gs_free_object(penum->pgs->memory, penum->copied_path,
+ "gs_path_enum_cleanup");
+ penum->path = 0;
+ penum->copied_path = 0;
+ }
+}
diff --git a/gs/src/gspath2.h b/gs/src/gspath2.h
new file mode 100644
index 000000000..04ab66883
--- /dev/null
+++ b/gs/src/gspath2.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspath2.h */
+/* Client interface to Level 2 path facilities */
+/* Requires gsmatrix.h */
+
+/* Miscellaneous */
+int gs_setbbox(P5(gs_state *, floatp, floatp, floatp, floatp));
+
+/* Rectangles */
+int gs_rectappend(P3(gs_state *, const gs_rect *, uint));
+int gs_rectclip(P3(gs_state *, const gs_rect *, uint));
+int gs_rectfill(P3(gs_state *, const gs_rect *, uint));
+int gs_rectstroke(P4(gs_state *, const gs_rect *, uint, const gs_matrix *));
diff --git a/gs/src/gspcolor.c b/gs/src/gspcolor.c
new file mode 100644
index 000000000..7480f4ac4
--- /dev/null
+++ b/gs/src/gspcolor.c
@@ -0,0 +1,991 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspcolor.c */
+/* Pattern color operators and procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h" /* for gs_concat, gx_tr'_to_fixed */
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclip2.h"
+#include "gspath.h"
+#include "gxpath.h"
+#include "gxpcolor.h"
+#include "gzstate.h"
+#include "gsimage.h"
+
+private_st_client_pattern();
+public_st_pattern_instance();
+
+/* Import the Pattern reloading procedure from gxpcmap.c. */
+int gx_pattern_load(P4(gx_device_color *, const gs_imager_state *,
+ gx_device *, gs_color_select_t));
+
+/* Define the Pattern color space. */
+extern cs_proc_remap_color(gx_remap_Pattern);
+private cs_proc_install_cspace(gx_install_Pattern);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_Pattern);
+private cs_proc_init_color(gx_init_Pattern);
+private cs_proc_adjust_color_count(gx_adjust_color_Pattern);
+private struct_proc_enum_ptrs(gx_enum_ptrs_Pattern);
+private struct_proc_reloc_ptrs(gx_reloc_ptrs_Pattern);
+const gs_color_space_type
+ gs_color_space_type_Pattern =
+ { gs_color_space_index_Pattern, -1, false,
+ gx_init_Pattern, gx_no_concrete_space,
+ gx_no_concretize_color, NULL,
+ gx_remap_Pattern, gx_install_Pattern,
+ gx_adjust_cspace_Pattern, gx_adjust_color_Pattern,
+ gx_enum_ptrs_Pattern, gx_reloc_ptrs_Pattern
+ };
+
+/* makepattern */
+private int compute_inst_matrix(P3(gs_pattern_instance *pinst,
+ const gs_state *saved,
+ gs_rect *pbbox));
+private rc_free_proc(rc_free_pattern_instance);
+int
+gs_makepattern(gs_client_color *pcc, const gs_client_pattern *pcp,
+ const gs_matrix *pmat, gs_state *pgs, gs_memory_t *mem)
+{ gs_pattern_instance inst;
+ gs_pattern_instance *pinst;
+ gs_state *saved;
+ gs_rect bbox;
+ gs_fixed_rect cbox;
+ int code;
+
+ if ( mem == 0 )
+ mem = gs_state_memory(pgs);
+ rc_alloc_struct_1(pinst, gs_pattern_instance, &st_pattern_instance,
+ mem, return_error(gs_error_VMerror),
+ "gs_makepattern");
+ pinst->rc.free = rc_free_pattern_instance;
+ inst.rc = pinst->rc;
+ saved = gs_state_copy(pgs, mem);
+ if ( saved == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto finst;
+ }
+ gs_concat(saved, pmat);
+ gs_newpath(saved);
+ switch ( pcp->PaintType )
+ {
+ case 1: /* colored */
+ gs_set_logical_op(saved, lop_default);
+ break;
+ case 2: /* uncolored */
+ gx_set_device_color_1(saved);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ goto fsaved;
+ }
+ inst.template = *pcp;
+ inst.saved = saved;
+ code = compute_inst_matrix(&inst, saved, &bbox);
+ if ( code < 0 )
+ goto fsaved;
+#define mat inst.step_matrix
+ if_debug6('t', "[t]step_matrix=[%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
+ /* Check for singular stepping matrix. */
+ if ( fabs(mat.xx * mat.yy - mat.xy * mat.yx) < 1.0e-6 )
+ { code = gs_note_error(gs_error_rangecheck);
+ goto fsaved;
+ }
+ if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ { float bbw = bbox.q.x - bbox.p.x;
+ float bbh = bbox.q.y - bbox.p.y;
+ /* If the step and the size agree to within 1/2 pixel, */
+ /* make them the same. */
+ inst.size.x = (int)(bbw + 0.8); /* 0.8 is arbitrary */
+ inst.size.y = (int)(bbh + 0.8);
+ if ( mat.xy == 0 && mat.yx == 0 &&
+ fabs(fabs(mat.xx) - bbw) < 0.5 &&
+ fabs(fabs(mat.yy) - bbh) < 0.5
+ )
+ { gs_scale(saved, fabs(inst.size.x / mat.xx),
+ fabs(inst.size.y / mat.yy));
+ code = compute_inst_matrix(&inst, saved, &bbox);
+ if ( code < 0 )
+ goto fsaved;
+ if_debug2('t',
+ "[t]adjusted XStep & YStep to size=(%d,%d)\n",
+ inst.size.x, inst.size.y);
+ if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ }
+ }
+ if ( (code = gs_bbox_transform_inverse(&bbox, &mat, &inst.bbox)) < 0 )
+ goto fsaved;
+ if_debug4('t', "[t]ibbox=(%g,%g),(%g,%g)\n",
+ inst.bbox.p.x, inst.bbox.p.y, inst.bbox.q.x, inst.bbox.q.y);
+ inst.is_simple = (fabs(mat.xx) == inst.size.x && mat.xy == 0 &&
+ mat.yx == 0 && fabs(mat.yy) == inst.size.y);
+ if_debug6('t',
+ "[t]is_simple? xstep=(%g,%g) ystep=(%g,%g) size=(%d,%d)\n",
+ inst.step_matrix.xx, inst.step_matrix.xy,
+ inst.step_matrix.yx, inst.step_matrix.yy,
+ inst.size.x, inst.size.y);
+ gx_translate_to_fixed(saved, float2fixed(mat.tx - bbox.p.x),
+ float2fixed(mat.ty - bbox.p.y));
+ mat.tx = bbox.p.x;
+ mat.ty = bbox.p.y;
+#undef mat
+ cbox.p.x = fixed_0;
+ cbox.p.y = fixed_0;
+ cbox.q.x = int2fixed(inst.size.x);
+ cbox.q.y = int2fixed(inst.size.y);
+ code = gx_clip_to_rectangle(saved, &cbox);
+ if ( code < 0 )
+ goto fsaved;
+ inst.id = gs_next_ids(1);
+ *pinst = inst;
+ pcc->pattern = pinst;
+ return 0;
+#undef mat
+fsaved: gs_state_free(saved);
+finst: gs_free_object(mem, pinst, "gs_makepattern");
+ return code;
+}
+/* Compute the stepping matrix and device space instance bounding box */
+/* from the step values and the saved matrix. */
+private int
+compute_inst_matrix(gs_pattern_instance *pinst, const gs_state *saved,
+ gs_rect *pbbox)
+{ double xx = pinst->template.XStep * saved->ctm.xx;
+ double xy = pinst->template.XStep * saved->ctm.xy;
+ double yx = pinst->template.YStep * saved->ctm.yx;
+ double yy = pinst->template.YStep * saved->ctm.yy;
+
+ /* Adjust the stepping matrix so all coefficients are >= 0. */
+ if ( xx == 0 || yy == 0 )
+ { /* We know that both xy and yx are non-zero. */
+ double temp;
+ temp = xx, xx = yx, yx = temp;
+ temp = xy, xy = yy, yy = temp;
+ }
+ if ( xx < 0 )
+ xx = -xx, xy = -xy;
+ if ( yy < 0 )
+ yx = -yx, yy = -yy;
+ /* Now xx > 0, yy > 0. */
+ pinst->step_matrix.xx = xx;
+ pinst->step_matrix.xy = xy;
+ pinst->step_matrix.yx = yx;
+ pinst->step_matrix.yy = yy;
+ pinst->step_matrix.tx = saved->ctm.tx;
+ pinst->step_matrix.ty = saved->ctm.ty;
+ return gs_bbox_transform(&pinst->template.BBox, &ctm_only(saved),
+ pbbox);
+}
+/* Free the saved gstate when freeing a Pattern instance. */
+private void
+rc_free_pattern_instance(gs_memory_t *mem, void *pinst_void,
+ client_name_t cname)
+{ gs_pattern_instance *pinst = pinst_void;
+
+ gs_state_free(pinst->saved);
+ rc_free_struct_only(mem, pinst_void, cname);
+}
+
+/* setpattern */
+int
+gs_setpattern(gs_state *pgs, const gs_client_color *pcc)
+{ int code = gs_setpatternspace(pgs);
+ if ( code < 0 )
+ return code;
+ return gs_setcolor(pgs, pcc);
+}
+
+/* setpatternspace */
+/* This does all the work of setpattern except for the final setcolor. */
+int
+gs_setpatternspace(gs_state *pgs)
+{ int code = 0;
+ if ( pgs->color_space->type->index != gs_color_space_index_Pattern )
+ { gs_color_space cs;
+ cs.params.pattern.base_space =
+ *(gs_paint_color_space *)pgs->color_space;
+ cs.params.pattern.has_base_space = true;
+ cs.type = &gs_color_space_type_Pattern;
+ code = gs_setcolorspace(pgs, &cs);
+ }
+ return code;
+}
+
+/* getpattern */
+/* This is only intended for the benefit of pattern PaintProcs. */
+const gs_client_pattern *
+gs_getpattern(const gs_client_color *pcc)
+{ return &pcc->pattern->template;
+}
+
+/*
+ * Code for generating patterns from bitmaps and pixmaps.
+ */
+
+/*
+ * The following structures are realized here only because this is the
+ * first location in which they were needed. Otherwise, there is nothing
+ * about them that is specific to patterns.
+ */
+public_st_gs_bitmap();
+public_st_gs_tile_bitmap();
+public_st_gs_depth_bitmap();
+public_st_gs_tile_depth_bitmap();
+
+/*
+ * Structure for holding a gs_depth_bitmap and the corresponding depth and
+ * colorspace information. The white index is currently unused, but will be
+ * needed when ImageType 4 images are supported.
+ */
+typedef struct pixmap_info_s {
+ gs_depth_bitmap bitmap; /* must be first */
+ const gs_color_space * pcspace;
+ uint white_index;
+} pixmap_info;
+
+gs_private_st_suffix_add1( st_pixmap_info,
+ pixmap_info,
+ "pixmap info. struct",
+ pixmap_enum_ptr,
+ pixmap_reloc_ptr,
+ st_gs_depth_bitmap,
+ pcspace
+ );
+
+#define st_pixmap_info_max_ptrs (1 + st_tile_bitmap_max_ptrs)
+
+/*
+ * The following code is to handle the transition from a single image type
+ * to multiple image types. Once the latter become available, the "NOTYET"
+ * code may be removed.
+ *
+ * This modification only affects the pixmap_PaintProc and gx_makepixmappattern
+ * functions.
+ */
+#ifndef NOTYET
+
+typedef gs_image_t gs_image4_t;
+typedef gs_image_t gs_image_data_t;
+typedef gs_image_t gs_pixel_image_t;
+
+#define gs_pixel_image_t_init(pimage, pcspace) \
+ { \
+ gs_image_t_init_color(pimage); \
+ (pimage)->ColorSpace = (pcspace); \
+ }
+
+#define gs_image4_t_init(pimage, pcspace) \
+ gs_pixel_image_t_init((pimage), (pcspace))
+
+#define set_white_index(pimage, white_index)
+
+#else
+
+#define set_white_index(pimage, white_index) \
+ { \
+ (pimage)->MaskColor_is_range = false; \
+ (pimage)->MaskColor[0] = (white_index); \
+ }
+
+#endif /* NOTYET */
+
+
+/*
+ * PaintProc for bitmap and pixmap patterns.
+ */
+private int
+pixmap_PaintProc(
+ const gs_client_color * pcolor,
+ gs_state * pgs
+)
+{
+ gs_image_enum * pen = gs_image_enum_alloc( gs_state_memory(pgs),
+ "bitmap_PaintProc"
+ );
+ const gs_client_pattern * ppat = gs_getpattern(pcolor);
+ const pixmap_info * ppmap = ppat->client_data;
+ const gs_depth_bitmap * pbitmap = &(ppmap->bitmap);
+ const byte * dp = pbitmap->data;
+ gs_image4_t image;
+ int n;
+ uint nbytes, raster, used;
+
+ /*
+ * Initialize the image structure.
+ *
+ * When ImageType 4 becomes available, the image type to be used will
+ * be selected based on whether or the pattern image can contain the
+ * white_index value. Patterns images that cannot have this value are
+ * effectively opaque, irrespective of the current transparency setting.
+ *
+ * The implementation of ImageType 4 should internally verify if the
+ * produce transparency mask is blank, and remove it if this is the case.
+ */
+ if (ppat->PaintType == 2)
+ gs_image_t_init_mask(&image, true);
+ else {
+ const gs_color_space * pcspace = ( ppmap->pcspace == 0
+ ? gs_color_space_DeviceGray()
+ : ppmap->pcspace );
+
+ if (ppmap->white_index >= (1 << pbitmap->pix_depth)) {
+ gs_pixel_image_t_init((gs_pixel_image_t *)&image, pcspace);
+ } else {
+ gs_image4_t_init(&image, pcspace);
+ set_white_index(&image, pcspace);
+ }
+ image.Decode[0] = 0;
+ image.Decode[1] = (1 << pbitmap->pix_depth) - 1;
+ image.BitsPerComponent = pbitmap->pix_depth;
+
+ /* backwards compatibility */
+ if (ppmap->pcspace == 0) {
+ image.Decode[0] = 1.0;
+ image.Decode[1] = 0.0;
+ }
+ }
+ image.Width = pbitmap->size.x;
+ image.Height = pbitmap->size.y;
+
+ raster = pbitmap->raster;
+ nbytes = (image.Width * pbitmap->pix_depth + 7) >> 3;
+ gs_image_init(pen, (gs_image_data_t *)&image, false, pgs);
+ if (nbytes == raster)
+ (void)gs_image_next(pen, dp, nbytes * image.Height, &used);
+ else for (n = image.Height; n > 0; dp += raster, --n)
+ (void)gs_image_next(pen, dp, nbytes, &used);
+ gs_image_cleanup(pen);
+
+ gs_free_object(gs_state_memory(pgs), pen, "bitmap_PaintProc");
+ return 0;
+}
+
+/*
+ * Make a pattern from a bitmap or pixmap. The pattern may be colored or
+ * uncolored, as determined by the mask operand. This code is intended
+ * primarily for use by PCL.
+ *
+ * See the comment prior to the declaration of this function in gscolor2.h
+ * for further information.
+ */
+int
+gs_makepixmappattern(
+ gs_client_color * pcc,
+ const gs_depth_bitmap * pbitmap,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ const gs_color_space * pcspace,
+ uint white_index,
+ gs_state * pgs,
+ gs_memory_t * mem
+)
+{
+
+ gs_client_pattern pat;
+ pixmap_info * ppmap;
+ gs_matrix mat, smat;
+ int code;
+
+ /* check that the data is legitimate */
+ if ((mask) || (pcspace == 0)) {
+ if (pbitmap->pix_depth != 1)
+ return_error(gs_error_rangecheck);
+ pcspace = 0;
+ } else if (gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed)
+ return_error(gs_error_rangecheck);
+ if (pbitmap->num_comps != 1)
+ return_error(gs_error_rangecheck);
+
+ /* allocate and initialize a pixmap_info structure for the paint proc */
+ if (mem == 0)
+ mem = gs_state_memory(pgs);
+ ppmap = gs_alloc_struct( mem,
+ pixmap_info,
+ &st_pixmap_info,
+ "makepximappattern"
+ );
+ if (ppmap == 0)
+ return_error(gs_error_VMerror);
+ ppmap->bitmap = *pbitmap;
+ ppmap->pcspace = pcspace;
+ ppmap->white_index = white_index;
+
+ /* set up the client pattern structure */
+ uid_set_UniqueID(&pat.uid, (id == no_UniqueID) ? gs_next_ids(1) : id );
+ pat.PaintType = (mask ? 2 : 1);
+ pat.TilingType = 1;
+ pat.BBox.p.x = 0;
+ pat.BBox.p.y = 0;
+ pat.BBox.q.x = pbitmap->size.x;
+ pat.BBox.q.y = pbitmap->size.y;
+ pat.XStep = pbitmap->size.x;
+ pat.YStep = pbitmap->size.y;
+ pat.PaintProc = pixmap_PaintProc;
+ pat.client_data = ppmap;
+
+ /* set the ctm to be the identity */
+ gs_currentmatrix(pgs, &smat);
+ gs_make_identity(&mat);
+ gs_setmatrix(pgs, &mat);
+
+ /* build the pattern, restore the previous matrix */
+ if (pmat == NULL)
+ pmat = &mat;
+ if ((code = gs_makepattern(pcc, &pat, pmat, pgs, mem)) != 0)
+ gs_free_object(mem, ppmap, "makebitmappattern_xform");
+ gs_setmatrix(pgs, &smat);
+ return code;
+}
+
+/*
+ * Backwards compatibility.
+ */
+int
+gs_makebitmappattern_xform(
+ gs_client_color * pcc,
+ const gx_tile_bitmap * ptile,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ gs_state * pgs,
+ gs_memory_t * mem
+)
+{
+ gs_depth_bitmap bitmap;
+
+ /* build the bitmap the size of one repetition */
+ bitmap.data = ptile->data;
+ bitmap.raster = ptile->raster;
+ bitmap.size.x = ptile->rep_width;
+ bitmap.size.y = ptile->rep_height;
+ bitmap.id = ptile->id; /* shouldn't matter */
+ bitmap.pix_depth = 1;
+ bitmap.num_comps = 1;
+
+ return gs_makepixmappattern(pcc, &bitmap, mask, pmat, id, 0, 0, pgs, mem);
+}
+
+
+/* ------ Color space implementation ------ */
+
+/* Pattern device color types. */
+/* We need a masked analogue of each of the non-pattern types, */
+/* to handle uncolored patterns. */
+/* We use 'masked_fill_rect' instead of 'masked_fill_rectangle' */
+/* in order to limit identifier lengths to 32 characters. */
+private dev_color_proc_load(gx_dc_pattern_load);
+private dev_color_proc_fill_rectangle(gx_dc_pattern_fill_rectangle);
+private struct_proc_enum_ptrs(dc_pattern_enum_ptrs);
+private struct_proc_reloc_ptrs(dc_pattern_reloc_ptrs);
+private dev_color_proc_load(gx_dc_pure_masked_load);
+private dev_color_proc_fill_rectangle(gx_dc_pure_masked_fill_rect);
+private struct_proc_enum_ptrs(dc_masked_enum_ptrs);
+private struct_proc_reloc_ptrs(dc_masked_reloc_ptrs);
+private dev_color_proc_load(gx_dc_binary_masked_load);
+private dev_color_proc_fill_rectangle(gx_dc_binary_masked_fill_rect);
+private struct_proc_enum_ptrs(dc_binary_masked_enum_ptrs);
+private struct_proc_reloc_ptrs(dc_binary_masked_reloc_ptrs);
+private dev_color_proc_load(gx_dc_colored_masked_load);
+private dev_color_proc_fill_rectangle(gx_dc_colored_masked_fill_rect);
+/* The device color types are exported for gxpcmap.c. */
+const gx_device_color_procs
+ gx_dc_pattern =
+ { gx_dc_pattern_load, gx_dc_pattern_fill_rectangle,
+ gx_dc_default_fill_masked,
+ dc_pattern_enum_ptrs, dc_pattern_reloc_ptrs
+ },
+ gx_dc_pure_masked =
+ { gx_dc_pure_masked_load, gx_dc_pure_masked_fill_rect,
+ gx_dc_default_fill_masked,
+ dc_masked_enum_ptrs, dc_masked_reloc_ptrs
+ },
+ gx_dc_binary_masked =
+ { gx_dc_binary_masked_load, gx_dc_binary_masked_fill_rect,
+ gx_dc_default_fill_masked,
+ dc_binary_masked_enum_ptrs, dc_binary_masked_reloc_ptrs
+ },
+ gx_dc_colored_masked =
+ { gx_dc_colored_masked_load, gx_dc_colored_masked_fill_rect,
+ gx_dc_default_fill_masked,
+ dc_masked_enum_ptrs, dc_masked_reloc_ptrs
+ };
+#undef gx_dc_type_pattern
+const gx_device_color_procs _ds *gx_dc_type_pattern = &gx_dc_pattern;
+#define gx_dc_type_pattern (&gx_dc_pattern)
+/* GC procedures */
+#define cptr ((gx_device_color *)vptr)
+private ENUM_PTRS_BEGIN(dc_pattern_enum_ptrs) {
+ return dc_masked_enum_ptrs(vptr, size, index - 1, pep);
+ }
+ case 0:
+ { gx_color_tile *tile = cptr->colors.pattern.p_tile;
+ ENUM_RETURN((tile == 0 ? tile : tile - tile->index));
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_pattern_reloc_ptrs) {
+ gx_color_tile *tile = cptr->colors.pattern.p_tile;
+ if ( tile != 0 )
+ { uint index = tile->index;
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.pattern.p_tile, index);
+ }
+ dc_masked_reloc_ptrs(vptr, size, gcst);
+} RELOC_PTRS_END
+private ENUM_PTRS_BEGIN(dc_masked_enum_ptrs) ENUM_SUPER(gx_device_color, st_client_color, mask.ccolor, 1);
+ case 0:
+ { gx_color_tile *mask = cptr->mask.m_tile;
+ ENUM_RETURN((mask == 0 ? mask : mask - mask->index));
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_masked_reloc_ptrs) {
+ gx_color_tile *mask = cptr->mask.m_tile;
+ RELOC_SUPER(gx_device_color, st_client_color, mask.ccolor);
+ if ( mask != 0 )
+ { uint index = mask->index;
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, mask.m_tile, index);
+ }
+} RELOC_PTRS_END
+private ENUM_PTRS_BEGIN(dc_binary_masked_enum_ptrs) {
+ return (*gx_dc_procs_ht_binary.enum_ptrs)(vptr, size, index - 2, pep);
+ }
+ case 0:
+ case 1:
+ return dc_masked_enum_ptrs(vptr, size, index, pep);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_binary_masked_reloc_ptrs) {
+ dc_masked_reloc_ptrs(vptr, size, gcst);
+ (*gx_dc_procs_ht_binary.reloc_ptrs)(vptr, size, gcst);
+} RELOC_PTRS_END
+#undef cptr
+
+/* Macros for pattern loading */
+#define FINISH_PATTERN_LOAD\
+ while ( !gx_pattern_cache_lookup(pdevc, pis, dev, select) )\
+ { code = gx_pattern_load(pdevc, pis, dev, select);\
+ if ( code < 0 ) break;\
+ }\
+ return code;
+
+/* Ensure that a colored Pattern is loaded in the cache. */
+private int
+gx_dc_pattern_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ int code = 0;
+ FINISH_PATTERN_LOAD
+}
+/* Ensure that an uncolored Pattern is loaded in the cache. */
+private int
+gx_dc_pure_masked_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ int code = (*gx_dc_procs_pure.load)(pdevc, pis, dev, select);
+ if ( code < 0 )
+ return code;
+ FINISH_PATTERN_LOAD
+}
+private int
+gx_dc_binary_masked_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ int code = (*gx_dc_procs_ht_binary.load)(pdevc, pis, dev, select);
+ if ( code < 0 )
+ return code;
+ FINISH_PATTERN_LOAD
+}
+private int
+gx_dc_colored_masked_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ int code = (*gx_dc_procs_ht_colored.load)(pdevc, pis, dev, select);
+ if ( code < 0 )
+ return code;
+ FINISH_PATTERN_LOAD
+}
+
+/* Look up a pattern color in the cache. */
+bool
+gx_pattern_cache_lookup(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ gx_pattern_cache *pcache = pis->pattern_cache;
+ gx_bitmap_id id = pdevc->mask.id;
+
+ if ( id == gx_no_bitmap_id )
+ { color_set_null_pattern(pdevc);
+ return true;
+ }
+ if ( pcache != 0 )
+ { gx_color_tile *ctile = &pcache->tiles[id % pcache->num_tiles];
+ if ( ctile->id == id &&
+ (pdevc->type != &gx_dc_pattern ||
+ ctile->depth == dev->color_info.depth)
+ )
+ { if ( pdevc->type == &gx_dc_pattern ) /* colored */
+ { pdevc->colors.pattern.p_tile = ctile;
+ color_set_phase_mod(pdevc, pis->screen_phase[select].x,
+ pis->screen_phase[select].y,
+ ctile->tbits.rep_width,
+ ctile->tbits.rep_height);
+ }
+ pdevc->mask.m_tile =
+ (ctile->tmask.data == 0 ? (gx_color_tile *)0 :
+ ctile);
+ return true;
+ }
+ }
+ return false;
+}
+
+#undef FINISH_PATTERN_LOAD
+
+/*
+ * The filling procedures below disregard the phase in the color.
+ * We don't see how this can possibly work, but it does; and if we
+ * do take the phase into account, we get incorrect output.
+ */
+
+/* Macros for filling with a possibly masked pattern. */
+#define BEGIN_PATTERN_FILL\
+ { gx_device_tile_clip cdev;\
+ gx_device *pcdev;\
+ const gx_strip_bitmap *tmask;\
+ int code;\
+\
+ if ( pdevc->mask.m_tile == 0 ) { /* no clipping */\
+ code = 0;\
+ pcdev = dev;\
+ } else {\
+ tmask = &pdevc->mask.m_tile->tmask;\
+ code = tile_clip_initialize(&cdev, tmask, dev, 0, 0);\
+ if ( code < 0 )\
+ return code;\
+ pcdev = (gx_device *)&cdev;\
+ }
+#define CLIPPING_FILL (pcdev == (gx_device *)&cdev)
+#define END_PATTERN_FILL\
+ return code;\
+ }
+
+/* Macros for filling with non-standard X and Y stepping. */
+/* Free variables: x, y, w, h, ptile. */
+/* tbits_or_tmask is whichever of tbits and tmask is supplying */
+/* the tile size. */
+/* This implementation could be sped up considerably! */
+#define BEGIN_STEPS(tbits_or_tmask)\
+ { gs_rect bbox, ibbox;\
+ gs_point offset;\
+ int x0 = x, x1 = x + w, y0 = y, y1 = y + h;\
+ int w0 = w, h0 = h;\
+ int i0, i1, j0, j1, i, j;\
+\
+ bbox.p.x = x0, bbox.p.y = y0;\
+ bbox.q.x = x1, bbox.q.y = y1;\
+ gs_bbox_transform_inverse(&bbox, &ptile->step_matrix, &ibbox);\
+ if_debug10('T',\
+ "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",\
+ x, y, w, h,\
+ ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,\
+ ptile->step_matrix.tx, ptile->step_matrix.ty);\
+ offset.x = ptile->step_matrix.tx;\
+ offset.y = ptile->step_matrix.ty;\
+ i0 = (int)floor(ibbox.p.x - ptile->bbox.q.x + 0.000001);\
+ i1 = (int)ceil(ibbox.q.x - ptile->bbox.p.x - 0.000001);\
+ j0 = (int)floor(ibbox.p.y - ptile->bbox.q.y + 0.000001);\
+ j1 = (int)ceil(ibbox.q.y - ptile->bbox.p.y - 0.000001);\
+ if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);\
+ for ( i = i0; i < i1; i++ )\
+ for ( j = j0; j < j1; j++ )\
+ { int xoff, yoff;\
+ x = (int)(ptile->step_matrix.xx * i +\
+ ptile->step_matrix.yx * j + offset.x);\
+ y = (int)(ptile->step_matrix.xy * i +\
+ ptile->step_matrix.yy * j + offset.y);\
+ if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);\
+ w = ptile->tbits_or_tmask.size.x;\
+ h = ptile->tbits_or_tmask.size.y;\
+ if ( x < x0 ) xoff = x0 - x, x = x0, w -= xoff;\
+ else xoff = 0;\
+ if ( y < y0 ) yoff = y0 - y, y = y0, h -= yoff;\
+ else yoff = 0;\
+ if ( x + w > x1 ) w = x1 - x;\
+ if ( y + h > y1 ) h = y1 - y;\
+ if_debug4('T', "=>(%d,%d) w,h=(%d,%d)\n",\
+ x, y, w, h);\
+ if ( w > 0 && h > 0 )\
+ { if ( CLIPPING_FILL )\
+ tile_clip_set_phase(&cdev,\
+ imod(xoff - x, tmask->rep_width),\
+ imod(yoff - y, tmask->rep_height))
+#define SOURCE_STEP(src)\
+ (src).sdata = source->sdata + (y - y0) * source->sraster;\
+ (src).sourcex = source->sourcex + (x - x0);\
+ (src).sraster = source->sraster;\
+ (src).id = (w == w0 && h == h0 ?\
+ source->id : gx_no_bitmap_id);\
+ (src).scolors[0] = source->scolors[0];\
+ (src).scolors[1] = source->scolors[1];\
+ (src).use_scolors = source->use_scolors
+#define END_STEPS\
+ }\
+ }\
+ }
+
+/* Fill a rectangle with a colored Pattern. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_pattern_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
+ const gx_rop_source_t *rop_source = source;
+ gx_rop_source_t no_source;
+ gx_strip_bitmap *bits;
+
+ if ( ptile == 0 ) /* null pattern */
+ return 0;
+ if ( rop_source == NULL )
+ set_rop_no_source(rop_source, no_source, dev);
+ bits = &ptile->tbits;
+ BEGIN_PATTERN_FILL
+ if ( ptile->is_simple )
+ { int px = imod(-(int)(ptile->step_matrix.tx + 0.5),
+ bits->rep_width);
+ int py = imod(-(int)(ptile->step_matrix.ty + 0.5),
+ bits->rep_height);
+
+ if ( pcdev != dev )
+ tile_clip_set_phase(&cdev, px, py);
+ if ( source == NULL && lop_no_S_is_T(lop) )
+ code = (*dev_proc(pcdev, strip_tile_rectangle))(pcdev, bits,
+ x, y, w, h,
+ gx_no_color_index, gx_no_color_index, px, py);
+ else
+ code = (*dev_proc(dev, strip_copy_rop))(dev,
+ rop_source->sdata, rop_source->sourcex,
+ rop_source->sraster, rop_source->id,
+ (rop_source->use_scolors ? rop_source->scolors : NULL),
+ bits, NULL, x, y, w, h, px, py, lop);
+ }
+ else
+ { BEGIN_STEPS(tbits);
+ { const byte *data = bits->data;
+ bool full_transfer = (w == w0 && h == h0);
+ gx_bitmap_id source_id =
+ (full_transfer ? rop_source->id : gx_no_bitmap_id);
+
+ if ( source == NULL && lop_no_S_is_T(lop) )
+ code = (*dev_proc(pcdev, copy_color))(pcdev,
+ data + bits->raster * yoff, xoff,
+ bits->raster,
+ (full_transfer ? bits->id : gx_no_bitmap_id),
+ x, y, w, h);
+ else
+ { gx_strip_bitmap data_tile;
+
+ data_tile.data = (byte *)data; /* actually const */
+ data_tile.raster = bits->raster;
+ data_tile.size.x = data_tile.rep_width =
+ ptile->tbits.size.x;
+ data_tile.size.y = data_tile.rep_height =
+ ptile->tbits.size.y;
+ data_tile.id = bits->id;
+ data_tile.shift = data_tile.rep_shift = 0;
+ code = (*dev_proc(dev, strip_copy_rop))(dev,
+ rop_source->sdata + (y - y0) * rop_source->sraster,
+ rop_source->sourcex + (x - x0),
+ rop_source->sraster, source_id,
+ (rop_source->use_scolors ?
+ rop_source->scolors : NULL),
+ &data_tile, NULL,
+ x, y, w, h,
+ imod(xoff - x, data_tile.rep_width),
+ imod(yoff - y, data_tile.rep_height),
+ lop);
+ }
+ if ( code < 0 )
+ return code;
+ }
+ END_STEPS
+ }
+ END_PATTERN_FILL
+}
+/* Fill a rectangle with an uncolored Pattern. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_pure_masked_fill_rect(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ gx_color_tile *ptile = pdevc->mask.m_tile;
+
+ BEGIN_PATTERN_FILL
+ if ( ptile == 0 || ptile->is_simple )
+ code = (*gx_dc_procs_pure.fill_rectangle)(pdevc, x, y, w, h,
+ pcdev, lop, source);
+ else
+ { BEGIN_STEPS(tmask);
+ if ( source == NULL )
+ code = (*gx_dc_procs_pure.fill_rectangle)(pdevc, x, y, w, h,
+ pcdev, lop, source);
+ else
+ { gx_rop_source_t step_source;
+ SOURCE_STEP(step_source);
+ code = (*gx_dc_procs_pure.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, &step_source);
+ }
+ if ( code < 0 )
+ return code;
+ END_STEPS
+ }
+ END_PATTERN_FILL
+}
+private int
+gx_dc_binary_masked_fill_rect(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ gx_color_tile *ptile = pdevc->mask.m_tile;
+
+ BEGIN_PATTERN_FILL
+ if ( ptile == 0 || ptile->is_simple )
+ code = (*gx_dc_procs_ht_binary.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, source);
+ else
+ { BEGIN_STEPS(tmask);
+ if ( source == NULL )
+ code = (*gx_dc_procs_ht_binary.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, source);
+ else
+ { gx_rop_source_t step_source;
+ SOURCE_STEP(step_source);
+ code = (*gx_dc_procs_ht_binary.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, &step_source);
+ }
+ if ( code < 0 )
+ return code;
+ END_STEPS
+ }
+ END_PATTERN_FILL
+}
+private int
+gx_dc_colored_masked_fill_rect(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ gx_color_tile *ptile = pdevc->mask.m_tile;
+
+ BEGIN_PATTERN_FILL
+ if ( ptile == 0 || ptile->is_simple )
+ code = (*gx_dc_procs_ht_colored.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, source);
+ else
+ { BEGIN_STEPS(tmask);
+ if ( source == NULL )
+ code = (*gx_dc_procs_ht_colored.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, source);
+ else
+ { gx_rop_source_t step_source;
+ SOURCE_STEP(step_source);
+ code = (*gx_dc_procs_ht_colored.fill_rectangle)(pdevc,
+ x, y, w, h,
+ pcdev, lop, &step_source);
+ }
+ if ( code < 0 )
+ return code;
+ END_STEPS
+ }
+ END_PATTERN_FILL
+}
+
+#undef BEGIN_PATTERN_FILL
+#undef END_PATTERN_FILL
+
+/* Initialize a Pattern color. */
+private void
+gx_init_Pattern(gs_client_color *pcc, const gs_color_space *pcs)
+{ if ( pcs->params.pattern.has_base_space )
+ { const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.pattern.base_space;
+ cs_init_color(pcc, pbcs);
+ }
+ /*pcc->pattern = 0;*/ /* cs_full_init_color handles this */
+}
+
+/* Install a Pattern color space. */
+private int
+gx_install_Pattern(gs_color_space *pcs, gs_state *pgs)
+{ if ( !pcs->params.pattern.has_base_space )
+ return 0;
+ return (*pcs->params.pattern.base_space.type->install_cspace)
+ ((gs_color_space *)&pcs->params.pattern.base_space, pgs);
+}
+
+/* Adjust the reference counts for Pattern color spaces or colors. */
+private void
+gx_adjust_cspace_Pattern(const gs_color_space *pcs, gs_memory_t *mem,
+ int delta)
+{ if ( pcs->params.pattern.has_base_space )
+ (*pcs->params.pattern.base_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.pattern.base_space, mem, delta);
+}
+
+private void
+gx_adjust_color_Pattern(const gs_client_color *pcc, const gs_color_space *pcs,
+ gs_memory_t *mem, int delta)
+{ gs_pattern_instance *pinst = pcc->pattern;
+
+ rc_adjust_only(pinst, delta, "gx_adjust_color_Pattern");
+ if ( pcs->params.pattern.has_base_space )
+ (*pcs->params.pattern.base_space.type->adjust_color_count)
+ (pcc, (const gs_color_space *)&pcs->params.pattern.base_space,
+ mem, delta);
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private ENUM_PTRS_BEGIN_PROC(gx_enum_ptrs_Pattern) {
+ if ( !pcs->params.pattern.has_base_space )
+ return 0;
+ return (*pcs->params.pattern.base_space.type->enum_ptrs)
+ (&pcs->params.pattern.base_space,
+ sizeof(pcs->params.pattern.base_space), index, pep);
+} ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(gx_reloc_ptrs_Pattern) {
+ if ( !pcs->params.pattern.has_base_space )
+ return;
+ (*pcs->params.pattern.base_space.type->reloc_ptrs)
+ (&pcs->params.pattern.base_space, sizeof(gs_paint_color_space), gcst);
+} RELOC_PTRS_END
+
+#undef pcs
diff --git a/gs/src/gspenum.h b/gs/src/gspenum.h
new file mode 100644
index 000000000..e0211b758
--- /dev/null
+++ b/gs/src/gspenum.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspenum.h */
+/* Common definitions for client interface to path enumeration */
+
+#ifndef gspenum_INCLUDED
+# define gspenum_INCLUDED
+
+/* Define the path element types. */
+#define gs_pe_moveto 1
+#define gs_pe_lineto 2
+#define gs_pe_curveto 3
+#define gs_pe_closepath 4
+
+/* Define an abstract type for the path enumerator. */
+typedef struct gs_path_enum_s gs_path_enum;
+
+#endif /* gspenum_INCLUDED */
diff --git a/gs/src/gspmdrv.c b/gs/src/gspmdrv.c
new file mode 100644
index 000000000..c37626059
--- /dev/null
+++ b/gs/src/gspmdrv.c
@@ -0,0 +1,1252 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspmdrv.c */
+/* Presentation Manager driver for Ghostscript */
+/* Written by Russell Lang */
+
+/* To display output from os2pm driver: */
+/* gspmdrv -d id_string */
+/* To display BMP file (used for testing display code) */
+/* gspmdrv -b filename.bmp */
+
+#define INCL_DOS
+#define INCL_WIN
+#define INCL_GPI
+#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/emxload.h>
+#include "gspmdrv.h"
+#include "gdevpm.h"
+
+#ifndef min
+#define min(x,y) ( (x) < (y) ? (x) : (y) )
+#endif
+#ifndef max
+#define max(x,y) ( (x) > (y) ? (x) : (y) )
+#endif
+
+HEV update_event_sem;
+HMTX bmp_mutex_sem;
+
+/* bitmap details */
+typedef struct tagBM {
+ BOOL valid;
+ BOOL old_bmp; /* bitmap type */
+ PBITMAPINFO2 pbmi; /* pointer to bitmap info */
+ PBYTE bits; /* pointer to bitmap bits */
+ int width;
+ int height;
+ int planes;
+ int depth;
+ int palsize;
+ int palimportant;
+ int old_width;
+ int old_height;
+ int old_planes;
+ int old_depth;
+ int old_palsize;
+ int old_palimportant;
+} BMAP;
+
+typedef struct tagDISPLAY {
+ LONG planes;
+ LONG bitcount;
+ LONG hasPalMan; /* Palette Manager */
+ BOOL hpal_exists;
+ HPAL hpal;
+} DISPLAY;
+
+/* options that are saved in INI file */
+typedef struct tagOPTIONS {
+ POINTL img_origin;
+ POINTL img_size;
+ BOOL img_max;
+} OPTIONS;
+#define CW_USEDEFAULT 32768
+
+
+BMAP bitmap;
+DISPLAY display;
+OPTIONS option;
+PBYTE bbuffer; /* for BMP file display */
+POINTL scroll_pos; /* not used */ /* not used */
+ULONG os_version;
+char *section = "Ghostscript Image";
+
+HAB hab; /* Anchor Block */
+HWND hwnd_frame;
+HWND hwnd_bmp;
+HWND hwnd_gs; /* window handle for CMD.EXE that started gs */
+TID update_tid;
+#define WM_GSUPDATE WM_USER+1
+#define SB_TOP 20
+#define SB_BOTTOM 21
+
+
+MRESULT EXPENTRY ClientWndProc(HWND, ULONG, MPARAM, MPARAM);
+MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM);
+APIRET init_window(void);
+void fix_sysmenu(HWND);
+APIRET restore_window_position(SWP *pswp);
+BOOL scan_bitmap(BMAP *pbm);
+void read_profile(void);
+void write_profile(void);
+APIRET init_display(int argc, char *argv[]);
+APIRET init_bitmap(int argc, char *argv[]);
+void copy_clipboard(void);
+HBITMAP make_bitmap(BMAP *pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth);
+
+void
+debugbeep(int type)
+{
+#ifdef DEBUG
+int i;
+/* current debug beeps are: */
+/* 1. Null handle PS */
+/* 2. make_bitmap() failed */
+/* 3. GpiDrawBits() or WinDrawBitmap() failed */
+/* 4. Null handle PS from WinBeginPaint() */
+ for (i=0; i<type; i++) {
+ DosBeep(400+100*type,50);
+ DosSleep(50);
+ }
+#endif
+}
+
+
+/* display message */
+int
+message_box(char *str, int icon)
+{
+ return WinMessageBox(HWND_DESKTOP, hwnd_frame ? hwnd_frame : HWND_DESKTOP,
+ str, "gspmdrv.exe", 0, icon | MB_MOVEABLE | MB_OK);
+}
+
+void error_message(char *str)
+{
+ WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "gspmdrv.exe", 0, MB_MOVEABLE | MB_ICONHAND | MB_OK);
+ WinPostMsg(hwnd_frame, WM_QUIT, MPFROMLONG(0), MPFROMLONG(0));
+}
+
+/* Update thread */
+/* This thread waits for the update event semaphore from gs.exe */
+/* then generates a WM_PAINT message for the bitmap */
+/* This thread must NOT call C library functions */
+VOID APIENTRY update_func(ULONG unused)
+{
+ APIRET rc;
+ BOOL flag;
+ ULONG count;
+ unused = unused; /* to shut up warning */
+ while (!DosQueryEventSem(update_event_sem, &count)) {
+ /* loop while semaphore exists */
+ DosWaitEventSem(update_event_sem, SEM_INDEFINITE_WAIT);
+ DosResetEventSem(update_event_sem, &count);
+ WinPostMsg(hwnd_bmp, WM_GSUPDATE, MPFROMLONG(0), MPFROMLONG(0));
+ }
+}
+
+VOID APIENTRY exit_func(ULONG code)
+{
+ write_profile();
+ DosCloseEventSem(update_event_sem);
+ DosCloseMutexSem(bmp_mutex_sem);
+ DosFreeMem((PVOID)bitmap.pbmi);
+ DosExitList(EXLST_EXIT, 0);
+ code = code; /* to shut up warning */
+}
+
+void
+find_hwnd_gs(char *gsid)
+{
+ULONG ulCount;
+ULONG ulLength;
+ULONG pBase;
+ULONG cbBuf;
+PSWBLOCK pswblk;
+PSWENTRY pswentry;
+SWCNTRL *pswc;
+int i;
+ULONG pid;
+char buf[256];
+char *p, *s;
+ PTIB pptib;
+ PPIB pppib;
+
+ /* extract gs pid from command line id */
+ strcpy(buf, gsid);
+ for (p=buf; *p && *p!='_';p++)
+ ;
+ *p++='\0';
+ s = p;
+ for (p=buf; *p && *p!='_';p++)
+ ;
+ *p='\0';
+ pid = atoi(s); /* pid is Process ID of CMD.EXE that started gsos2.exe */
+
+ ulCount = WinQuerySwitchList(hab, NULL, 0); /* get num of items */
+ cbBuf = (ulCount * sizeof(SWENTRY)) + sizeof(HSWITCH);
+ pswblk = (PSWBLOCK) malloc(cbBuf+32768);
+ ulCount = WinQuerySwitchList(hab, pswblk, cbBuf); /* get num of items */
+ for (i=0; i<ulCount; i++) {
+ pswentry = &pswblk->aswentry[i];
+ pswc = &pswentry->swctl;
+ if (pid == pswc->idProcess)
+ hwnd_gs = pswc->hwnd; /* save window handle */
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ HMQ hand_mq; /* message queue */
+ QMSG q_mess; /* message queue */
+ APIRET rc = 0;
+
+
+ hab = WinInitialize(0); /* Get the Anchor Block */
+
+ hand_mq = WinCreateMsgQueue(hab, 0); /* start a queue */
+
+ if (argc < 2) {
+ rc = 1;
+ error_message("Usage: gspmdrv -d id_string");
+ }
+
+ if (!rc) {
+ if (strcmp(argv[1],"-d")==0) {
+ rc = init_display(argc, argv);
+ }
+ else if (strcmp(argv[1],"-b")==0) {
+ rc = init_bitmap(argc, argv);
+ }
+ else {
+ rc = 1;
+ error_message("Usage: gspmdrv -d id_string");
+ }
+ }
+
+ if (!rc) {
+ rc = DosCreateThread(&update_tid, update_func, 0, 0, 8192);
+ if (rc)
+ error_message("Failed to create update thread");
+ }
+
+ if (!rc)
+ rc = init_window();
+
+ if (!rc)
+ WinShowWindow(hwnd_frame, TRUE);
+
+ if (!rc) {
+ /* keep gspmdrv.exe in memory for number of minutes specified in */
+ /* environment variable GS_LOAD */
+ _emxload_env("GS_LOAD");
+ }
+
+ DosExitList(EXLST_ADD, exit_func);
+
+ /* message loop */
+ while (!rc && WinGetMsg(hab, &q_mess, 0L, 0, 0))
+ WinDispatchMsg(hab, &q_mess);
+
+ /* Shut down the application window and queue */
+ DosKillThread(update_tid);
+ WinDestroyWindow(hwnd_frame);
+ WinDestroyMsgQueue(hand_mq);
+ WinTerminate(hab);
+ return rc;
+}
+
+APIRET
+init_window()
+{
+ ULONG version[3];
+ SWP swp;
+ APIRET rc = 0;
+ ULONG flFlags; /* Window frame definition */
+ unsigned char class[] = "gspmdrvClass"; /* class name */
+
+ if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, &version, sizeof(version)))
+ os_version = 201000; /* a guess */
+ else {
+ os_version = version[0]*10000 + version[1]*100 + version[2];
+ }
+
+ /* define the frame constants */
+ flFlags = FCF_TITLEBAR | /* have a title bar */
+ FCF_SIZEBORDER | /* have a sizeable window */
+ FCF_MINMAX | /* have a min and max button */
+ FCF_SYSMENU | /* include a system menu */
+ FCF_VERTSCROLL | /* vertical scroll bar */
+ FCF_HORZSCROLL | /* horizontal scroll bar */
+ FCF_TASKLIST | /* show it in window list */
+ FCF_ICON; /* Load icon from resources */
+
+ /* save SHELL default size and location */
+ rc = WinQueryTaskSizePos(hab, 0, &swp);
+ if (rc)
+ return rc;
+
+ read_profile();
+ if ((option.img_size.x==0) || (option.img_size.y==0))
+ option.img_size.x = option.img_size.y = CW_USEDEFAULT;
+
+ if (!rc) {
+ HPS ps = WinGetPS(HWND_DESKTOP);
+ HDC hdc = GpiQueryDevice(ps);
+ DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display.planes);
+ DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display.bitcount);
+ DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display.hasPalMan);
+ display.hasPalMan &= CAPS_PALETTE_MANAGER;
+ WinReleasePS(ps);
+ }
+
+ if (!rc) {
+ if (!WinRegisterClass( /* register this window class */
+ hab, /* anchor block */
+ (PSZ)class, /* class name */
+ (PFNWP) ClientWndProc, /* window function */
+ CS_SIZEREDRAW | /* window style */
+ CS_MOVENOTIFY,
+ 0)) /* no storage */
+ exit(1);
+
+ hwnd_frame = WinCreateStdWindow(
+ HWND_DESKTOP, /* window type */
+ 0, /* frame style is not WS_VISIBLE */
+ &flFlags, /* definitions */
+ (PSZ)class, /* client class */
+ (PSZ)"Ghostscript Image", /* title */
+ WS_VISIBLE, /* client style */
+ 0, /* resource module */
+ ID_GSPMDRV, /* resource identifier */
+ &hwnd_bmp); /* pointer to client */
+
+ fix_sysmenu(hwnd_frame);
+ }
+ rc = restore_window_position(&swp);
+
+ return rc;
+}
+
+
+void
+write_profile(void)
+{
+char profile[64];
+ sprintf(profile, "%d %d", option.img_origin.x, option.img_origin.y);
+ PrfWriteProfileString(HINI_USERPROFILE, section, "Origin", profile);
+ sprintf(profile, "%d %d", option.img_size.x, option.img_size.y);
+ PrfWriteProfileString(HINI_USERPROFILE, section, "Size", profile);
+ sprintf(profile, "%d", option.img_max);
+ PrfWriteProfileString(HINI_USERPROFILE, section, "Maximized", profile);
+}
+
+void
+read_profile(void)
+{
+char profile[64];
+ PrfQueryProfileString(HINI_USERPROFILE, section, "Origin", "", profile, sizeof(profile));
+ if (sscanf(profile,"%d %d", &option.img_origin.x, &option.img_origin.y) != 2) {
+ option.img_origin.x = CW_USEDEFAULT;
+ option.img_origin.y = CW_USEDEFAULT;
+ }
+ PrfQueryProfileString(HINI_USERPROFILE, section, "Size", "", profile, sizeof(profile));
+ if (sscanf(profile,"%d %d", &option.img_size.x, &option.img_size.y) != 2) {
+ option.img_size.x = CW_USEDEFAULT;
+ option.img_size.y = CW_USEDEFAULT;
+ }
+ PrfQueryProfileString(HINI_USERPROFILE, section, "Maximized", "", profile, sizeof(profile));
+ if (sscanf(profile,"%d", &option.img_max) != 1)
+ option.img_max = 0;
+}
+
+void
+fix_sysmenu(HWND hwnd)
+{
+MENUITEM mi;
+HWND hwndSysMenu;
+ if (!WinSendMsg(WinWindowFromID(hwnd, FID_SYSMENU), MM_QUERYITEM,
+ MPFROM2SHORT(SC_SYSMENU, TRUE), MPFROMP(&mi))) {
+ message_box("failed getting system menu handle",0);
+ return;
+ }
+ hwndSysMenu = mi.hwndSubMenu;
+ mi.iPosition = MIT_END;
+ mi.afStyle = MIS_SEPARATOR;
+ mi.afAttribute = 0;
+ mi.id = 0;
+ mi.hwndSubMenu = 0;
+ mi.hItem = 0;
+ WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), NULL);
+ mi.afStyle = MIS_TEXT;
+ mi.id = IDM_ABOUT;
+ WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "About...");
+ mi.id = IDM_COPY;
+ WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "Copy");
+}
+
+APIRET
+restore_window_position(SWP *pswp)
+{
+ SWP swp;
+ swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
+
+ if (option.img_max) {
+ /* Get maximized frame window position and size. */
+ if (!WinGetMaxPosition(hwnd_frame, &swp))
+ return 1;
+ swp.fl |= SWP_MAXIMIZE ;
+ }
+ else if ((option.img_size.x != CW_USEDEFAULT) &&
+ (option.img_size.y != CW_USEDEFAULT) &&
+ (option.img_origin.y != CW_USEDEFAULT) &&
+ (option.img_origin.y != CW_USEDEFAULT)) {
+ LONG cxClientMax ;
+ LONG cyClientMax ;
+ LONG cyTitleBar ;
+ LONG cxSizeBorder ;
+ LONG cySizeBorder ;
+
+ /* get maximum client window size */
+ cxClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CXFULLSCREEN) ;
+ cyClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CYFULLSCREEN) ;
+ cyTitleBar = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR) ;
+ cxSizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER) ;
+ cySizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER) ;
+ cyClientMax += cyTitleBar ;
+
+ /* Make sure x origin is within display boundaries */
+ swp.x = option.img_origin.x ;
+ if (swp.x < -cxSizeBorder)
+ swp.x = 0 ;
+
+ /* Make sure window isn't too wide, or negative value */
+ swp.cx = option.img_size.x ;
+ if (swp.cx >= cxClientMax || swp.cx < 0) {
+ swp.cx = cxClientMax ;
+ swp.x = 0 ;
+ }
+
+ if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder))
+ swp.x = cxClientMax + cxSizeBorder - swp.cx ;
+
+ /* Make sure y origin is within display boundaries */
+ swp.y = option.img_origin.y ;
+ if (swp.y < -cySizeBorder)
+ swp.y = 0 ;
+
+ /* Make sure window isn't too high, or negative value */
+ swp.cy = option.img_size.y ;
+ if (swp.cy > cyClientMax || swp.cy < 0) {
+ swp.cy = cyClientMax ;
+ swp.y = 0 ;
+ }
+
+ if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder))
+ swp.y = cyClientMax + cySizeBorder - swp.cy ;
+ }
+ else { /* No saved position -- use supplied position */
+ swp = *pswp;
+ option.img_origin.x = swp.x;
+ option.img_origin.y = swp.y;
+ option.img_size.x = swp.cx;
+ option.img_size.y = swp.cy;
+ option.img_max = FALSE;
+ swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
+ }
+
+ if (hwnd_gs)
+ swp.fl |= SWP_ZORDER;
+ /* Position and size this frame window */
+ if (!WinSetWindowPos(hwnd_frame, hwnd_gs,
+ swp.x, swp.y, swp.cx, swp.cy, swp.fl))
+ return 1;
+ return 0;
+}
+
+APIRET init_display(int argc, char *argv[])
+{
+ char buf[256];
+ char name[256];
+ APIRET rc = 0;
+
+ if (argc != 3) {
+ rc = 1;
+ error_message("Usage: gspmdrv -d id_string");
+ }
+
+ find_hwnd_gs(argv[2]);
+
+ if (!rc) {
+ sprintf(name, SHARED_NAME, argv[2]);
+ rc = DosGetNamedSharedMem((PVOID *)&bitmap.pbmi, name, PAG_READ | PAG_WRITE);
+ if (rc) {
+ sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", argv[0], rc);
+ error_message(buf);
+ }
+ }
+ if (!rc) {
+ sprintf(name, SYNC_NAME, argv[2]);
+ rc = DosOpenEventSem(name, &update_event_sem);
+ if (rc) {
+ sprintf(buf, "Failed to open: update event semaphore \"%s\" rc = %d", argv[1], rc);
+ error_message(buf);
+ }
+ }
+ if (!rc) {
+ sprintf(name, MUTEX_NAME, argv[2]);
+ rc = DosOpenMutexSem(name, &bmp_mutex_sem);
+ if (rc) {
+ sprintf(buf, "Failed to open: bmp mutex semaphore \"%s\" rc = %d", argv[1], rc);
+ error_message(buf);
+ }
+ }
+
+ if (!rc) {
+ scan_bitmap(&bitmap);
+ bitmap.valid = TRUE;
+ }
+
+ return rc;
+}
+
+
+APIRET init_bitmap(int argc, char *argv[])
+{
+ char buf[256];
+ APIRET rc = 0;
+ HFILE hf;
+ ULONG action, count, length;
+ PBITMAPFILEHEADER2 pbmfh;
+
+ if (argc != 3)
+ return 1; /* error - no filename */
+
+ /* open bitmap */
+ if ( (rc = DosOpen(argv[2], &hf, &action, 0, FILE_NORMAL, FILE_OPEN,
+ OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, 0))
+ != (APIRET)0) {
+ sprintf(buf,"Error opening: %s",argv[2]);
+ error_message(buf);
+ return rc;
+ }
+
+ rc = DosSetFilePtr(hf, 0, FILE_END, &length);
+ if (rc) {
+ sprintf(buf, "failed seeking to EOF: error = %d", rc);
+ error_message(buf);
+ return rc;
+ }
+
+ rc = DosSetFilePtr(hf, 0, FILE_BEGIN, &count);
+ if (rc) {
+ sprintf(buf, "failed seeking to BOF: error = %d", rc);
+ error_message(buf);
+ return rc;
+ };
+
+ /* allocate memory for bitmap */
+ if ( (rc = DosAllocMem((PPVOID)&bbuffer, length, PAG_READ | PAG_WRITE | PAG_COMMIT))
+ != (APIRET)0 ){
+ sprintf(buf, "failed allocating memory");
+ error_message(buf);
+ return rc;
+ }
+
+ rc = DosRead(hf, bbuffer, length, &count);
+ DosClose(hf);
+ if (rc) {
+ sprintf(buf, "failed reading bitmap, error = %u, count = %u", rc, count);
+ error_message(buf);
+ return rc;
+ }
+
+ /* extract some info about bitmap */
+ pbmfh = (PBITMAPFILEHEADER2)bbuffer;
+ bitmap.pbmi = (PBITMAPINFO2)(&pbmfh->bmp2);
+
+ scan_bitmap(&bitmap);
+ bitmap.valid = TRUE;
+
+ sprintf(buf, "bitmap width = %d, height = %d", bitmap.width, bitmap.height);
+ message_box(buf,0);
+ return rc;
+}
+
+#define MAX_PAL_SIZE 256
+void
+make_palette(BMAP *pbm)
+{
+ULONG tbl[MAX_PAL_SIZE];
+PRGB2 palptr = (PRGB2) ((PBYTE)(pbm->pbmi) + pbm->pbmi->cbFix);
+RGB *old_palptr = (RGB *)palptr;
+int palcount = pbm->palimportant;
+int i;
+BOOL old_bmp = (pbm->pbmi->cbFix == sizeof(BITMAPINFOHEADER));
+ if (old_bmp) {
+ for (i=0; i<palcount; i++) {
+ tbl[i] = (old_palptr->bRed<<16) + (old_palptr->bGreen<<8) + (old_palptr->bBlue);
+ palptr++;
+ }
+ }
+ else {
+ for (i=0; i<palcount; i++) {
+ tbl[i] = (palptr->bRed<<16) + (palptr->bGreen<<8) + (palptr->bBlue);
+ palptr++;
+ }
+ }
+ if (display.hpal_exists)
+ GpiDeletePalette(display.hpal);
+ display.hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB, palcount, tbl);
+ display.hpal_exists = TRUE;
+}
+
+
+
+/* scan bitmap */
+/* update bitmap structure */
+/* return value is TRUE if bitmap dimension has changed */
+BOOL
+scan_bitmap(BMAP *pbm)
+{
+PBITMAPINFO2 pbmi = pbm->pbmi;
+PBITMAPINFO old_pbmi = (PBITMAPINFO)pbmi;
+BOOL old_bmp = (pbmi->cbFix == sizeof(BITMAPINFOHEADER));
+
+ if (old_bmp) {
+ /* it is a BITMAPINFO */
+ switch(old_pbmi->cBitCount) {
+ case 24:
+ pbm->palsize = 0;
+ break;
+ case 8:
+ pbm->palsize = 256;
+ break;
+ case 4:
+ pbm->palsize = 16;
+ break;
+ case 1:
+ pbm->palsize = 2;
+ break;
+ default:
+ pbm->valid = FALSE;
+ error_message("scan_bitmap: wrong number of bits"); /* panic */
+ return FALSE;
+ }
+ pbm->palimportant = pbm->palsize;
+ pbm->palsize = pbm->palsize * sizeof(RGB);
+ pbm->bits = (PBYTE)old_pbmi + old_pbmi->cbFix + pbm->palsize;
+ pbm->width = old_pbmi->cx;
+ pbm->height = old_pbmi->cy;
+ pbm->planes = old_pbmi->cPlanes;
+ pbm->depth = old_pbmi->cBitCount;
+ }
+ else {
+ /* it is a BITMAPINFO2 */
+ switch(pbmi->cBitCount) {
+ case 24:
+ pbm->palsize = 0;
+ break;
+ case 8:
+ pbm->palsize = 256;
+ break;
+ case 4:
+ pbm->palsize = 16;
+ break;
+ case 1:
+ pbm->palsize = 2;
+ break;
+ default:
+ pbm->valid = FALSE;
+ error_message("scan_bitmap: wrong number of bits"); /* panic */
+ return FALSE;
+ }
+ if ( (pbmi->cbFix > (&(pbmi->cclrUsed) - &(pbmi->cbFix)))
+ && (pbmi->cclrUsed != 0) && (pbmi->cBitCount != 24) )
+ pbm->palsize = pbmi->cclrUsed;
+ pbm->palimportant = pbm->palsize;
+ if ( (pbmi->cbFix > (&(pbmi->cclrImportant) - &(pbmi->cbFix)))
+ && (pbmi->cclrImportant != 0) && (pbmi->cBitCount != 24) )
+ pbm->palimportant = pbmi->cclrImportant;
+ pbm->palsize = pbm->palsize * sizeof(RGB2);
+ pbm->bits = (PBYTE)pbmi + pbmi->cbFix + pbm->palsize;
+ pbm->width = pbmi->cx;
+ pbm->height = pbmi->cy;
+ pbm->planes = pbmi->cPlanes;
+ pbm->depth = pbmi->cBitCount;
+ }
+
+ if ((pbm->palsize != pbm->old_palsize) || (pbm->palimportant != pbm->old_palimportant)) {
+ if ( (pbm->depth == 8) && display.hasPalMan )
+ make_palette(pbm);
+ pbm->old_palimportant = pbm->palimportant;
+ }
+
+ if ( (pbm->width == pbm->old_width) &&
+ (pbm->height == pbm->old_height) &&
+ (pbm->planes == pbm->old_planes) &&
+ (pbm->depth == pbm->old_depth) &&
+ (pbm->palsize == pbm->old_palsize) &&
+ (pbm->old_bmp == old_bmp) )
+ return FALSE;
+
+ /* bitmap has changed */
+ pbm->old_width = pbm->width;
+ pbm->old_height = pbm->height;
+ pbm->old_planes = pbm->planes;
+ pbm->old_depth = pbm->depth;
+ pbm->old_palsize = pbm->palsize;
+ pbm->old_bmp = old_bmp;
+ return TRUE;
+}
+
+
+void
+update_scroll_bars(void)
+{
+ /* Cause update of scroll bars etc. */
+ SWP swp;
+ WinQueryWindowPos(hwnd_bmp, &swp);
+ WinSendMsg(hwnd_bmp, WM_SIZE, MPFROM2SHORT(swp.cx, swp.cy), MPFROM2SHORT(swp.cx, swp.cy));
+}
+
+
+/* copy bitmap to the clipboard */
+void
+copy_clipboard(void)
+{
+HBITMAP hbmp;
+ if (!bitmap.valid) {
+ message_box("Cannot copy to clipboard:\nNo Bitmap displayed",0);
+ return;
+ }
+ if (WinOpenClipbrd(hab)) {
+ /* get bmp mutex to stop gs.exe changing bitmap while we copy it */
+ DosRequestMutexSem(bmp_mutex_sem, 10000);
+ if (scan_bitmap(&bitmap)) {
+ /* bitmap has changed */
+ update_scroll_bars();
+ }
+ hbmp = make_bitmap(&bitmap, 0, 0, bitmap.width, bitmap.height, bitmap.depth);
+ if (hbmp) {
+ WinEmptyClipbrd(hab);
+ WinSetClipbrdData(hab, (ULONG)hbmp, CF_BITMAP, CFI_HANDLE);
+ }
+
+ DosReleaseMutexSem(bmp_mutex_sem);
+ WinCloseClipbrd(hab);
+ }
+}
+
+
+HBITMAP
+make_bitmap(BMAP *pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth)
+{
+HDC hdc = DEV_ERROR, hdcMem = DEV_ERROR;
+HPS hps = GPI_ERROR;
+HBITMAP hbmp = GPI_ERROR, hbmr = HBM_ERROR;
+SIZEL sizePS;
+BITMAPINFOHEADER2 bmih;
+
+ if ( (left == right) || (bottom == top) )
+ return (HBITMAP)NULL;
+
+ if (right > pbm->width)
+ right = pbm->width;
+ if (left > pbm->width)
+ left = 0;
+ if (top > pbm->height)
+ top = pbm->height;
+ if (bottom > pbm->height)
+ bottom = 0;
+
+ memset(&bmih, 0, sizeof(bmih));
+ bmih.cbFix = sizeof(BITMAPINFOHEADER2);
+ bmih.cx = right - left;
+ bmih.cy = top - bottom;
+ bmih.cPlanes = 1;
+ bmih.cBitCount = depth;
+
+ /* create memory DC compatible with screen */
+ hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, NULLHANDLE);
+
+ sizePS.cx = right - left;
+ sizePS.cy = top - bottom;
+ if (hdcMem != DEV_ERROR)
+ hps = GpiCreatePS(hab, hdcMem, &sizePS,
+ PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
+
+ if (hps != GPI_ERROR)
+ hbmp = GpiCreateBitmap(hps, &bmih, 0L, NULL, NULL);
+
+ if (hbmp != GPI_ERROR)
+ hbmr = GpiSetBitmap(hps, hbmp);
+
+
+ if (hbmr != HBM_ERROR) {
+ LONG rc;
+ ERRORID eid;
+ POINTL apts[4];
+ /* target is inclusive */
+ apts[0].x = 0;
+ apts[0].y = 0;
+ apts[1].x = right - left - 1;
+ apts[1].y = top - bottom - 1;
+ /* source is not inclusive of top & right borders */
+ apts[2].x = left;
+ apts[2].y = bottom;
+ apts[3].x = right;
+ apts[3].y = top;
+
+ rc = 0;
+ eid = WinGetLastError(hab);
+ rc = GpiDrawBits(hps, pbm->bits, pbm->pbmi, 4, apts,
+ (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
+ if (rc==0) {
+ char buf[256];
+ eid = WinGetLastError(hab);
+ sprintf(buf,"make_bitmap: GpiDrawBits rc = %08x, eid = %08x",rc, eid);
+ message_box(buf, 0);
+ }
+ }
+
+ if (hbmr != HBM_ERROR)
+ GpiSetBitmap(hps, (ULONG)0);
+ if (hps != GPI_ERROR)
+ GpiDestroyPS(hps);
+ if (hdcMem != DEV_ERROR)
+ DevCloseDC(hdcMem);
+
+ if ( (hbmr == HBM_ERROR) || (hdcMem == DEV_ERROR) ||
+ (hbmp == GPI_ERROR) || (hps == GPI_ERROR) ) {
+ if (hbmp != GPI_ERROR)
+ GpiDeleteBitmap(hbmp);
+ debugbeep(2);
+ return 0;
+ }
+ return hbmp;
+}
+
+MRESULT
+paint_bitmap(HPS ps, PRECTL prect, int scrollx, int scrolly)
+{
+ POINTL apts[4];
+ int wx, wy;
+ if (WinIsRectEmpty(hab, prect))
+ return 0;
+ if (ps == NULLHANDLE) {
+ debugbeep(1);
+ }
+ /* source is not inclusive of top & right borders */
+ wx = prect->xRight - prect->xLeft; /* update width */
+ wy = prect->yTop - prect->yBottom; /* update height */
+ apts[2].x = prect->xLeft + scrollx;
+ apts[2].y = prect->yBottom + scrolly;
+ if (apts[2].x > bitmap.width)
+ apts[2].x = bitmap.width;
+ if (apts[2].x + wx > bitmap.width)
+ wx = bitmap.width - apts[2].x;
+ apts[3].x = apts[2].x + wx;
+ if (apts[2].y > bitmap.height)
+ apts[2].y = bitmap.height;
+ if (apts[2].y + wy > bitmap.height)
+ wy = bitmap.height - apts[2].y;
+ apts[3].y = apts[2].y + wy;
+ /* target is inclusive */
+ apts[0].x = prect->xLeft;
+ apts[0].y = prect->yBottom;
+ apts[1].x = prect->xLeft + wx - 1;
+ apts[1].y = prect->yBottom + wy - 1;
+
+ if ( (display.bitcount == 4) /* standard VGA is buggy */
+ || ( (os_version==201100) && (display.bitcount==8) && (bitmap.depth==1)) /* S3 and ATI GU are buggy */
+ ) {
+ /* slow code to dodge OS/2 bugs */
+ /* this code double buffers the bitmap and works on a standard VGA
+ * but didn't work on an ATI Ultra Graphics Pro in 8514 emulation
+ */
+ /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 8bit/pixel bitmap */
+ HBITMAP hbmp;
+ /* create a bitmap */
+ hbmp = make_bitmap(&bitmap, apts[2].x, apts[2].y, apts[3].x, apts[3].y, bitmap.depth);
+ /* Draw it to the display */
+ if (hbmp) {
+ WinDrawBitmap(ps, hbmp, NULL, &apts[0], CLR_BLACK, CLR_WHITE, DBM_NORMAL);
+ GpiDeleteBitmap(hbmp);
+ }
+ }
+ else {
+ /* fast code which doesn't always work */
+ /* This code works on the Trident SVGA and 8514 in 256 color mode,
+ * but GpiDrawBits fails with a SYS3175 on the standard VGA.
+ */
+ /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 1bit/pixel bitmap */
+ GpiDrawBits(ps, bitmap.bits, bitmap.pbmi, 4, apts,
+ (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
+ }
+
+ return 0;
+}
+
+
+/* This is the window function */
+MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG mess,
+ MPARAM mp1, MPARAM mp2)
+{
+ char buf[256];
+ static int cxClient, cyClient;
+ static int cxAdjust, cyAdjust;
+ static int nHscrollMax, nHscrollPos;
+ static int nVscrollMax, nVscrollPos;
+ int nHscrollInc;
+ int nVscrollInc;
+ HWND hwndScroll;
+ HPS hps;
+ RECTL rect;
+ ULONG ulclr;
+
+ switch(mess) {
+ case WM_CREATE:
+ break;
+ case WM_ERASEBACKGROUND:
+ /* by returning TRUE, the Presentation Manager automatically clears
+ * the window each time the window is resized or moved.
+ */
+ return (MRESULT)TRUE;
+ case WM_GSUPDATE:
+ if (!WinInvalidateRect(hwnd_bmp, (PRECTL)NULL, TRUE))
+ error_message("error invalidating rect");
+ if (!WinUpdateWindow(hwnd_bmp))
+ error_message("error updating window");
+ return 0;
+ case WM_COMMAND:
+ switch(LONGFROMMP(mp1)) {
+ case IDM_ABOUT:
+ WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDD_ABOUT, 0);
+ break;
+ case IDM_COPY:
+ copy_clipboard();
+ break;
+ }
+ break;
+ case WM_REALIZEPALETTE:
+ if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
+ hps = WinGetPS(hwnd);
+ if (hps == NULLHANDLE)
+ debugbeep(1);
+ GpiSelectPalette(hps, display.hpal);
+ if (WinRealizePalette(hwnd, hps, &ulclr) > 0)
+ WinInvalidateRect(hwnd, NULL, FALSE);
+ GpiSelectPalette(hps, (HPAL)NULL);
+ WinReleasePS(hps);
+ return 0;
+ }
+ break; /* use default processing */
+ case WM_PAINT:
+ /* Refresh the window each time the WM_PAINT message is received */
+
+ /* get bmp mutex to stop gs.exe changing bitmap while we paint */
+ DosRequestMutexSem(bmp_mutex_sem, 10000);
+ if (scan_bitmap(&bitmap))
+ update_scroll_bars(); /* bitmap has changed */
+
+ if (!bitmap.valid) {
+ DosReleaseMutexSem(bmp_mutex_sem);
+ hps = WinBeginPaint(hwnd, (ULONG)0, &rect);
+ if (hps == NULLHANDLE)
+ debugbeep(4);
+ WinFillRect(hps, &rect, CLR_BACKGROUND);
+ WinEndPaint(hwnd);
+ return 0;
+ }
+
+ hps = WinBeginPaint(hwnd, (HPS)NULL, &rect);
+ if (hps == NULLHANDLE)
+ debugbeep(4);
+ if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
+ GpiSelectPalette(hps, display.hpal);
+ WinRealizePalette(hwnd, hps, &ulclr);
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ GpiSelectPalette(hps, (HPAL)NULL);
+ }
+ else
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ WinEndPaint(hwnd);
+
+ DosReleaseMutexSem(bmp_mutex_sem);
+ return 0;
+ case WM_MOVE:
+ /* don't interrogate the window location immediately since */
+ /* it causes the Diamond Stealth VL24 with IBM S3 drivers */
+ /* to corrupt the display */
+ DosSleep(50);
+ if (hwnd_frame) { /* save window position for INI file */
+ SWP swp;
+ WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
+ if (!(swp.fl & SWP_MINIMIZE)) {
+ option.img_origin.x = swp.x;
+ option.img_origin.y = swp.y;
+ option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
+ }
+ }
+ return 0;
+ case WM_SIZE:
+ cyClient = SHORT2FROMMP(mp2);
+ cxClient = SHORT1FROMMP(mp2);
+
+ cyAdjust = min(bitmap.height, cyClient) - cyClient;
+ cyClient += cyAdjust;
+
+ nVscrollMax = max(0, bitmap.height - cyClient);
+ nVscrollPos = min(nVscrollPos, nVscrollMax);
+ scroll_pos.y = nVscrollMax - nVscrollPos;
+
+ if (!bitmap.valid)
+ cyClient = cyAdjust = nVscrollMax = nVscrollPos;
+
+ hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
+ WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nVscrollPos),
+ MPFROM2SHORT(0, nVscrollMax));
+ if (bitmap.valid)
+ WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cyClient, bitmap.height),
+ MPFROMLONG(0));
+ else
+ WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
+ MPFROMLONG(0));
+
+ cxAdjust = min(bitmap.width, cxClient) - cxClient;
+ cxClient += cxAdjust;
+
+ nHscrollMax = max(0, bitmap.width - cxClient);
+ nHscrollPos = min(nHscrollPos, nHscrollMax);
+ scroll_pos.x = nHscrollPos;
+
+ if (!bitmap.valid)
+ cxClient = cxAdjust = nHscrollMax = nHscrollPos;
+
+ hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
+ WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nHscrollPos),
+ MPFROM2SHORT(0, nHscrollMax));
+ if (bitmap.valid)
+ WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cxClient, bitmap.width),
+ MPFROMLONG(0));
+ else
+ WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
+ MPFROMLONG(0));
+
+ if ((cxAdjust!=0 || cyAdjust!=0)) {
+ SWP swp;
+ WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
+ WinSetWindowPos(WinQueryWindow(hwnd, QW_PARENT), 0,
+ swp.x, swp.y - cyAdjust,
+ swp.cx + cxAdjust, swp.cy + cyAdjust, SWP_SIZE | SWP_MOVE);
+ cxAdjust = cyAdjust = 0;
+ }
+ if (hwnd_frame) { /* save window size for INI file */
+ SWP swp;
+ WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
+ if (!(swp.fl & SWP_MINIMIZE)) {
+ option.img_size.x = swp.cx;
+ option.img_size.y = swp.cy;
+ option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
+ }
+ }
+ break;
+ case WM_VSCROLL:
+ switch(SHORT2FROMMP(mp2)) {
+ case SB_LINEUP:
+ nVscrollInc = -cyClient/16;
+ break;
+ case SB_LINEDOWN:
+ nVscrollInc = cyClient/16;
+ break;
+ case SB_PAGEUP:
+ nVscrollInc = min(-1,-cyClient);
+ break;
+ case SB_PAGEDOWN:
+ nVscrollInc = max(1,cyClient);
+ break;
+ case SB_SLIDERPOSITION:
+ nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos;
+ break;
+ case SB_TOP:
+ nVscrollInc = -nVscrollPos;
+ break;
+ case SB_BOTTOM:
+ nVscrollInc = nVscrollMax - nVscrollPos;
+ break;
+ default:
+ nVscrollInc = 0;
+ }
+ if ((nVscrollInc = max(-nVscrollPos,
+ min(nVscrollInc, nVscrollMax - nVscrollPos)))!=0) {
+ LONG lComplexity;
+ hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
+ nVscrollPos += nVscrollInc;
+ scroll_pos.y = nVscrollMax - nVscrollPos;
+ lComplexity = WinScrollWindow(hwnd, 0, nVscrollInc, (PRECTL)NULL, (PRECTL)NULL,
+ (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
+ WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nVscrollPos), 0);
+ if (lComplexity != RGN_RECT) {
+ WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
+ WinUpdateWindow(hwnd);
+ }
+ else {
+ /* redraw exposed area */
+ hps = WinGetPS(hwnd);
+ if (hps == NULLHANDLE)
+ debugbeep(1);
+ if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
+ GpiSelectPalette(hps, display.hpal);
+ WinRealizePalette(hwnd, hps, &ulclr);
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ GpiSelectPalette(hps, (HPAL)NULL);
+ }
+ else
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ WinReleasePS(hps);
+ }
+ }
+ break;
+ case WM_HSCROLL:
+ switch(SHORT2FROMMP(mp2)) {
+ case SB_LINELEFT:
+ nHscrollInc = -cxClient/16;
+ break;
+ case SB_LINERIGHT:
+ nHscrollInc = cyClient/16;
+ break;
+ case SB_PAGELEFT:
+ nHscrollInc = min(-1,-cxClient);
+ break;
+ case SB_PAGERIGHT:
+ nHscrollInc = max(1,cxClient);
+ break;
+ case SB_SLIDERPOSITION:
+ nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos;
+ break;
+ default:
+ nHscrollInc = 0;
+ }
+ if ((nHscrollInc = max(-nHscrollPos,
+ min(nHscrollInc, nHscrollMax - nHscrollPos)))!=0) {
+ LONG lComplexity;
+ hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
+ nHscrollPos += nHscrollInc;
+ scroll_pos.x = nHscrollPos;
+ lComplexity = WinScrollWindow(hwnd, -nHscrollInc, 0, (PRECTL)NULL, (PRECTL)NULL,
+ (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
+ /* need to send next message BEFORE redrawing, otherwise S3 driver screws up */
+ WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nHscrollPos), 0);
+ if (lComplexity != RGN_RECT) {
+ WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
+ WinUpdateWindow(hwnd);
+ }
+ else {
+ /* redraw exposed area */
+ hps = WinGetPS(hwnd);
+ if (hps == NULLHANDLE)
+ debugbeep(1);
+ if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
+ GpiSelectPalette(hps, display.hpal);
+ WinRealizePalette(hwnd, hps, &ulclr);
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ GpiSelectPalette(hps, (HPAL)NULL);
+ }
+ else
+ paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
+ WinReleasePS(hps);
+ }
+ }
+ break;
+ case WM_CHAR: /* process keystrokes here */
+ if (SHORT1FROMMP(mp1) & KC_CHAR) {
+ /* pass control to gs if ENTER pressed */
+ if (hwnd_gs && (SHORT1FROMMP(mp2) == '\r'))
+ WinSetActiveWindow(HWND_DESKTOP, hwnd_gs);
+ }
+ /* Process only key presses, not key releases */
+ if (SHORT1FROMMP(mp1) & KC_KEYUP)
+ break;
+ if (SHORT1FROMMP(mp1) & KC_VIRTUALKEY) {
+ USHORT vkey = SHORT2FROMMP(mp2);
+ switch(vkey) {
+ case VK_HOME:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_TOP));
+ break;
+ case VK_END:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_BOTTOM));
+ break;
+ case VK_UP:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEUP));
+ break;
+ case VK_DOWN:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEDOWN));
+ break;
+ case VK_PAGEUP:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEUP));
+ break;
+ case VK_PAGEDOWN:
+ WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEDOWN));
+ break;
+ case VK_LEFT:
+ if (SHORT1FROMMP(mp1) & KC_CTRL)
+ WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT));
+ else
+ WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINELEFT));
+ break;
+ case VK_RIGHT:
+ if (SHORT1FROMMP(mp1) & KC_CTRL)
+ WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT));
+ else
+ WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINERIGHT));
+ break;
+ }
+ }
+ break;
+ default:
+ /* All messages not handled by the ClientWndProc must be passed
+ * along to the Presentation Manager for default processing
+ */
+ return WinDefWindowProc(hwnd, mess, mp1, mp2);
+ }
+ return (MRESULT)FALSE;
+}
+
+
+
+/* About Dialog Box */
+MRESULT EXPENTRY AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+ switch(msg) {
+ case WM_COMMAND:
+ switch(COMMANDMSG(&msg)->cmd) {
+ case DID_OK:
+ WinDismissDlg(hwnd, TRUE);
+ return (MRESULT)TRUE;
+ }
+ break;
+ }
+ return WinDefDlgProc(hwnd, msg, mp1, mp2);
+}
diff --git a/gs/src/gspmdrv.def b/gs/src/gspmdrv.def
new file mode 100644
index 000000000..e85944624
--- /dev/null
+++ b/gs/src/gspmdrv.def
@@ -0,0 +1,3 @@
+NAME GSPMDRV WINDOWAPI
+DESCRIPTION 'Ghostscript PM driver'
+STACKSIZE 32768
diff --git a/gs/src/gspmdrv.h b/gs/src/gspmdrv.h
new file mode 100644
index 000000000..259a80a51
--- /dev/null
+++ b/gs/src/gspmdrv.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspmdrv.h */
+/* Definitions common to gspmdrv.c and gspmdrv.rc */
+#define GSPMDRV_VERSION "1994-02-09"
+
+#define IDM_ABOUT 5
+#define IDM_COPY 6
+
+#define IDD_ABOUT IDM_ABOUT
+
+#define ID_GSPMDRV 1000
diff --git a/gs/src/gspmdrv.icx b/gs/src/gspmdrv.icx
new file mode 100644
index 000000000..604e4593f
--- /dev/null
+++ b/gs/src/gspmdrv.icx
@@ -0,0 +1,209 @@
+42412800000078000000000000004349
+1a00000008000800e00100000c000000
+1000200001000100000000ffffff4349
+1a00000008000800600200000c000000
+10001000010004000000008000000080
+00808000000080800080008080808080
+ccccccff000000ff00ffff000000ffff
+00ff00ffffffffff424128000000f000
+00000000000043491a00000010001000
+e00200000c0000002000400001000100
+000000ffffff43491a00000010001000
+e00300000c0000002000200001000400
+00000080000000800080800000008080
+0080008080808080ccccccff000000ff
+00ffff000000ffff00ff00ffffffffff
+42412800000068010000000000004349
+1a0000000a000a00e00500000c000000
+1400280001000100000000ffffff4349
+1a0000000a000a00800600000c000000
+14001400010004000000008000000080
+00808000000080800080008080808080
+ccccccff000000ff00ffff000000ffff
+00ff00ffffffffff4241280000000000
+00000004000343491a00000014001400
+700700000c0000002800500001000100
+000000ffffff43491a00000014001400
+f00900000c0000002800280001000400
+00000080000000800080800000008080
+0080008080808080ccccccff000000ff
+00ffff000000ffff00ff00ffffffffff
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+ffff0000ffff0000dfdf0000dfdf0000
+afc300007ffd00007ffe00008ff00000
+f66f0000f7ef0000faaf0000fddf0000
+fb3f0000fcff0000ffff0000ffff0000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+0000000000000000f80000fffc0001ff
+fe0007efcc0002078000000380000001
+00000000800000018000003086000079
+df0000ffff8001ffffc001ffffe001ff
+fff801fffff803fffff807fffffc0fff
+fff81ffffff03ffffff87ffffffcffff
+99999999999999999999999999999999
+999999999999999999eeee9999999999
+99e9e99e99e99eeee99999e99eee9999
+99e9e99e99e9e999e99eeee9e9999999
+99e9e99e99e99eeee9e999e9eeeee999
+99e9e99e99e99999e9e999e9e999e999
+99e9eee9ee999eee999eeee99eee9999
+99999999999999999999999999999999
+99e99999999999999999999999999999
+99999999999999999999999999999999
+000000fffffffffffffffff000000000
+0000000ffffffffffff0f00000000000
+00000000ffffffffffff000000000000
+000000000ffffffffffff000000f0000
+00ff000ff0fffffffffff00ffffff000
+000fffff0fffffffffff0ffffffff000
+0ffffffff0fffffffffffffffffffff0
+0000fffffffffffffffffffff000ff00
+00fff000fffffffffffffffff0000ff0
+00f00000ffffffffffffffff00000000
+000000000ffffffffffff0f000000000
+00000000000fff0ff00fff0000000000
+00000000000ff0fff00fff0000000000
+00000000000000ffffffff0000000000
+00000000000000ffffffff0000000000
+00000000000000ff0f0ff00000000000
+000000000000000fffff000000000000
+000000000000000ffff0000000000000
+00000000000000ffff00000000000000
+0000000000000ffff000000000000000
+00000000000000ff0000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+fffff000fffff000dffbf000dffbf000
+cffbf000b7f830007fffd0007fffe000
+7fffe00087fe1000fb8df000fbfdf000
+fbfdf000fdadf000fefbf000fef7f000
+fdcff000fe3ff000fffff000fffff000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+ffffffffff000000ffffffffff000000
+ffffffffff000000ffffffffff000000
+f00000000f000000f00000000f000000
+f00000000f000000f00000000f000000
+f00000000f000000f00000000f000000
+f00000000f000000f00000000f000000
+f00000000f000000f00000000f000000
+ff80000fff000000ffc0001fff000000
+ffe0007eff000000fcc000207f000000
+f80000003f000000f80000001f000000
+f00000000f000000f80000001f000000
+f80000030f000000f86000079f000000
+fdf0000fff000000fff8001fff000000
+fffc001fff000000fffe001fff000000
+ffff801fff000000ffff803fff000000
+ffff807fff000000ffffc0ffff000000
+ffff81ffff000000ffff03ffff000000
+ffff87ffff000000ffffcfffff000000
+ffffffffff000000ffffffffff000000
+ffffffffff000000ffffffffff000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00009999999999999999999999999999
+999900000000999999999999999999ee
+ee99999999990000000099e9e99e99e9
+9eeee99999e99eee99990000000099e9
+e99e99e9e999e99eeee9e99999990000
+000099e9e99e99e99eeee9e999e9eeee
+e9990000000099e9e99e99e99999e9e9
+99e9e999e9990000000099e9eee9ee99
+9eee999eeee99eee9999000000009999
+99999999999999999999999999990000
+000099e9999999999999999999999999
+99990000000099999999999999999999
+99999999999900000000000000ffffff
+fffffffffff000000000000000000000
+000ffffffffffff0f000000000000000
+000000000000ffffffffffff00000000
+000000000000000000000fffffffffff
+f000000f00000000000000ff000ff0ff
+fffffffff00ffffff00000000000000f
+ffff0fffffffffff0ffffffff0000000
+00000ffffffff0ffffffffffffffffff
+fff0000000000000ffffffffffffffff
+fffff000ff000000000000fff000ffff
+fffffffffffff0000ff00000000000f0
+0000ffffffffffffffff000000000000
+0000000000000ffffffffffff0f00000
+00000000000000000000000fff0ff00f
+ff00000000000000000000000000000f
+f0fff00fff0000000000000000000000
+0000000000ffffffff00000000000000
+000000000000000000ffffffff000000
+00000000000000000000000000ff0f0f
+f0000000000000000000000000000000
+000fffff000000000000000000000000
+00000000000ffff00000000000000000
+000000000000000000ffff0000000000
+0000000000000000000000000ffff000
+00000000000000000000000000000000
+00ff0000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
diff --git a/gs/src/gspmdrv.rc b/gs/src/gspmdrv.rc
new file mode 100644
index 000000000..503d64d53
--- /dev/null
+++ b/gs/src/gspmdrv.rc
@@ -0,0 +1,40 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gspmdrv.rc */
+/* Resources for gspmdrv.exe, the PM display driver for Ghostscript */
+
+#include <os2.h>
+#include "gspmdrv.h"
+
+ICON ID_GSPMDRV gspmdrv.ico
+
+DLGTEMPLATE IDD_ABOUT LOADONCALL MOVEABLE DISCARDABLE
+BEGIN
+ DIALOG "About Ghostscript PM driver", IDD_ABOUT, 10, 10, 250, 76, WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR
+ BEGIN
+ ICON ID_GSPMDRV, ID_GSPMDRV, 8, 56, 20, 16, WS_GROUP
+ LTEXT "Ghostscript Presentation Manager Driver", -1, 34, 64, 210, 8
+ LTEXT GSPMDRV_VERSION, -1, 34, 56, 210, 8
+ LTEXT "Copyright (C) 1992, 1993 Aladdin Enterprises.", -1, 34, 48, 210, 8
+ LTEXT "All rights reserved", -1, 34, 40, 210, 8
+ PUSHBUTTON "OK", DID_OK, 105, 8, 40, 14
+ END
+END
+
+
diff --git a/gs/src/gsrefct.h b/gs/src/gsrefct.h
new file mode 100644
index 000000000..b99d9a45d
--- /dev/null
+++ b/gs/src/gsrefct.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsrefct.h */
+/* Reference counting definitions */
+
+#ifndef gsrefct_INCLUDED
+# define gsrefct_INCLUDED
+
+/*
+ * In many places below, a do {...} while (0) avoids problems with a possible
+ * enclosing 'if'.
+ */
+
+/*
+ * A reference-counted object must include the following header:
+ * rc_header rc;
+ * The header need not be the first element of the object.
+ */
+typedef struct rc_header_s rc_header;
+struct rc_header_s {
+ long ref_count;
+ gs_memory_t *memory;
+#define rc_free_proc(proc)\
+ void proc(P3(gs_memory_t *, void *, client_name_t))
+ rc_free_proc((*free));
+};
+
+/* ------ Allocate/free ------ */
+
+rc_free_proc(rc_free_struct_only);
+#define rc_alloc_struct_n(vp, typ, pstyp, mem, errstat, cname, rcinit)\
+ do\
+ { if ( ((vp) = gs_alloc_struct(mem, typ, pstyp, cname)) == 0 ) {\
+ errstat;\
+ } else {\
+ (vp)->rc.ref_count = rcinit;\
+ (vp)->rc.memory = mem;\
+ (vp)->rc.free = rc_free_struct_only;\
+ }\
+ }\
+ while (0)
+#define rc_alloc_struct_0(vp, typ, pstype, mem, errstat, cname)\
+ rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 0)
+#define rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname)\
+ rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 1)
+
+#define rc_free_struct(vp, cname)\
+ (*(vp)->rc.free)((vp)->rc.memory, (void *)(vp), cname)
+
+/* ------ Reference counting ------ */
+
+/* Increment a reference count. */
+#define rc_increment(vp)\
+ do { if ( (vp) != 0 ) (vp)->rc.ref_count++; } while (0)
+
+/* Increment a reference count, allocating the structure if necessary. */
+#define rc_allocate_struct(vp, typ, pstype, mem, errstat, cname)\
+ do\
+ { if ( (vp) != 0 )\
+ (vp)->rc.ref_count++;\
+ else\
+ rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname);\
+ }\
+ while (0)
+
+/* Guarantee that a structure is allocated and is not shared. */
+#define rc_unshare_struct(vp, typ, pstype, mem, errstat, cname)\
+ do\
+ { if ( (vp) == 0 || (vp)->rc.ref_count > 1 || (vp)->rc.memory != (mem) )\
+ { typ *new;\
+ rc_alloc_struct_1(new, typ, pstype, mem, errstat, cname);\
+ if ( vp ) (vp)->rc.ref_count--;\
+ (vp) = new;\
+ }\
+ }\
+ while (0)
+
+/* Adjust a reference count either up or down. */
+#define rc_adjust_(vp, delta, cname, body)\
+ do\
+ { if ( (vp) != 0 && !((vp)->rc.ref_count += delta) )\
+ { rc_free_struct(vp, cname);\
+ body;\
+ }\
+ }\
+ while (0)
+#define rc_adjust(vp, delta, cname)\
+ rc_adjust_(vp, delta, cname, (vp) = 0)
+#define rc_adjust_only(vp, delta, cname)\
+ rc_adjust_(vp, delta, cname, DO_NOTHING)
+#define rc_adjust_const(vp, delta, cname)\
+ rc_adjust_only(vp, delta, cname)
+#define rc_decrement(vp, cname)\
+ rc_adjust(vp, -1, cname)
+#define rc_decrement_only(vp, cname)\
+ rc_adjust_only(vp, -1, cname)
+
+/* Assign a pointer, adjusting reference counts. */
+#define rc_assign(vpto, vpfrom, cname)\
+ do\
+ { if ( (vpto) != (vpfrom) )\
+ { rc_decrement_only(vpto, cname);\
+ (vpto) = (vpfrom);\
+ rc_increment(vpto);\
+ }\
+ }\
+ while (0)
+/* Adjust reference counts for assigning a pointer, */
+/* but don't do the assignment. We use this before assigning */
+/* an entire structure containing reference-counted pointers. */
+#define rc_pre_assign(vpto, vpfrom, cname)\
+ do\
+ { if ( (vpto) != (vpfrom) )\
+ { rc_decrement_only(vpto, cname);\
+ rc_increment(vpfrom);\
+ }\
+ }\
+ while (0)
+
+#endif /* gsrefct_INCLUDED */
diff --git a/gs/src/gsrop.c b/gs/src/gsrop.c
new file mode 100644
index 000000000..5e8fe6dca
--- /dev/null
+++ b/gs/src/gsrop.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsrop.c */
+/* RasterOp / transparency / render algorithm accessing for library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gzstate.h"
+#include "gsrop.h"
+
+#define set_log_op(pgs, lopv)\
+ (pgs)->log_op = (lopv)
+
+/* setrasterop */
+void
+gs_setrasterop(gs_state *pgs, gs_rop3_t rop)
+{ set_log_op(pgs, (rop & rop3_1) | (pgs->log_op & ~rop3_1));
+}
+
+/* currentrasterop */
+gs_rop3_t
+gs_currentrasterop(const gs_state *pgs)
+{ return lop_rop(pgs->log_op);
+}
+
+/* setsourcetransparent */
+void
+gs_setsourcetransparent(gs_state *pgs, bool transparent)
+{ set_log_op(pgs,
+ (transparent ? pgs->log_op | lop_S_transparent:
+ pgs->log_op & ~lop_S_transparent));
+}
+
+/* currentsourcetransparent */
+bool
+gs_currentsourcetransparent(const gs_state *pgs)
+{ return (pgs->log_op & lop_S_transparent) != 0;
+}
+
+/* settexturetransparent */
+void
+gs_settexturetransparent(gs_state *pgs, bool transparent)
+{ set_log_op(pgs,
+ (transparent ? pgs->log_op | lop_T_transparent:
+ pgs->log_op & ~lop_T_transparent));
+}
+
+/* currenttexturetransparent */
+bool
+gs_currenttexturetransparent(const gs_state *pgs)
+{ return (pgs->log_op & lop_T_transparent) != 0;
+}
+
+/* setrenderalgorithm */
+int
+gs_setrenderalgorithm(gs_state *pgs, int render_algorithm)
+{ if ( render_algorithm < render_algorithm_min ||
+ render_algorithm > render_algorithm_max
+ )
+ return_error(gs_error_rangecheck);
+ set_log_op(pgs,
+ (render_algorithm << lop_ral_shift) |
+ (pgs->log_op & ~(lop_ral_mask << lop_ral_shift)));
+ return 0;
+}
+
+/* currentrenderalgorithm */
+int
+gs_currentrenderalgorithm(const gs_state *pgs)
+{ return (pgs->log_op >> lop_ral_shift) & lop_ral_mask;
+}
+
+/* Save/restore logical operation. */
+void
+gs_set_logical_op(gs_state *pgs, gs_logical_operation_t lop)
+{ pgs->log_op = lop;
+}
+gs_logical_operation_t
+gs_current_logical_op(const gs_state *pgs)
+{ return pgs->log_op;
+}
diff --git a/gs/src/gsrop.h b/gs/src/gsrop.h
new file mode 100644
index 000000000..207274dff
--- /dev/null
+++ b/gs/src/gsrop.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsrop.h */
+/* RasterOp / transparency / render algorithm procedure interface */
+
+#ifndef gsrop_INCLUDED
+# define gsrop_INCLUDED
+
+#include "gsropt.h"
+
+/* Procedural interface */
+
+void gs_setrasterop(P2(gs_state *, gs_rop3_t));
+gs_rop3_t
+ gs_currentrasterop(P1(const gs_state *));
+void gs_setsourcetransparent(P2(gs_state *, bool));
+bool gs_currentsourcetransparent(P1(const gs_state *));
+void gs_settexturetransparent(P2(gs_state *, bool));
+bool gs_currenttexturetransparent(P1(const gs_state *));
+int gs_setrenderalgorithm(P2(gs_state *, int));
+int gs_currentrenderalgorithm(P1(const gs_state *));
+/* Save/restore the combined logical operation. */
+gs_logical_operation_t
+ gs_current_logical_op(P1(const gs_state *));
+void gs_set_logical_op(P2(gs_state *, gs_logical_operation_t));
+
+#endif /* gsrop_INCLUDED */
diff --git a/gs/src/gsropt.h b/gs/src/gsropt.h
new file mode 100644
index 000000000..b930e5ef2
--- /dev/null
+++ b/gs/src/gsropt.h
@@ -0,0 +1,189 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsropt.h */
+/* RasterOp / transparency / render algorithm type definitions */
+
+#ifndef gsropt_INCLUDED
+# define gsropt_INCLUDED
+
+/*
+ * This file defines the types for some library extensions that are
+ * motivated by PCL5 and also made available for PostScript:
+ * RasterOp, source and pattern white-pixel transparency, and
+ * per-pixel "render algorithm" information.
+ */
+
+/*
+ * By the magic of Boolean algebra, we can operate on the rop codes using
+ * Boolean operators and get the right result. E.g., the value of
+ * (rop3_S & rop3_D) is the rop3 code for S & D. We just have to remember
+ * to mask results with rop2_1 or rop3_1 if necessary.
+ */
+
+/* 2-input RasterOp */
+typedef enum {
+ rop2_0 = 0,
+ rop2_S = 0xc, /* source */
+#define rop2_S_shift 2
+ rop2_D = 0xa, /* destination */
+#define rop2_D_shift 1
+ rop2_1 = 0xf,
+#define rop2_operand(shift, d, s)\
+ ((shift) == 2 ? (s) : (d))
+ rop2_default = rop2_S
+} gs_rop2_t;
+
+/*
+ * For the 3-input case, we follow H-P's inconsistent terminology:
+ * the transparency mode is called pattern transparency, but the third
+ * RasterOp operand is called texture, not pattern.
+ */
+
+/* 3-input RasterOp */
+typedef enum {
+ rop3_0 = 0,
+ rop3_T = 0xf0, /* texture */
+#define rop3_T_shift 4
+ rop3_S = 0xcc, /* source */
+#define rop3_S_shift 2
+ rop3_D = 0xaa, /* destination */
+#define rop3_D_shift 1
+ rop3_1 = 0xff,
+ rop3_default = rop3_T | rop3_S
+} gs_rop3_t;
+
+/* All the transformations on rop3s are designed so that */
+/* they can also be used on lops. The only place this costs anything */
+/* is in rop3_invert. */
+
+/*
+ * Invert an operand.
+ */
+#define rop3_invert_(op, mask, shift)\
+ ( (((op) & mask) >> shift) | (((op) & (rop3_1 - mask)) << shift) |\
+ ((op) & ~rop3_1) )
+#define rop3_invert_D(op) rop3_invert_(op, rop3_D, rop3_D_shift)
+#define rop3_invert_S(op) rop3_invert_(op, rop3_S, rop3_S_shift)
+#define rop3_invert_T(op) rop3_invert_(op, rop3_T, rop3_T_shift)
+/*
+ * Pin an operand to 0.
+ */
+#define rop3_know_0_(op, mask, shift)\
+ ( (((op) & (rop3_1 - mask)) << shift) | ((op) & ~mask) )
+#define rop3_know_D_0(op) rop3_know_0_(op, rop3_D, rop3_D_shift)
+#define rop3_know_S_0(op) rop3_know_0_(op, rop3_S, rop3_S_shift)
+#define rop3_know_T_0(op) rop3_know_0_(op, rop3_T, rop3_T_shift)
+/*
+ * Pin an operand to 1.
+ */
+#define rop3_know_1_(op, mask, shift)\
+ ( (((op) & mask) >> shift) | ((op) & ~(rop3_1 - mask)) )
+#define rop3_know_D_1(op) rop3_know_1_(op, rop3_D, rop3_D_shift)
+#define rop3_know_S_1(op) rop3_know_1_(op, rop3_S, rop3_S_shift)
+#define rop3_know_T_1(op) rop3_know_1_(op, rop3_T, rop3_T_shift)
+/*
+ * Swap S and T.
+ */
+#define rop3_swap_S_T(op)\
+ ( (((op) & rop3_S & ~rop3_T) << (rop3_T_shift - rop3_S_shift)) |\
+ (((op) & ~rop3_S & rop3_T) >> (rop3_T_shift - rop3_S_shift)) |\
+ ((op) & (~rop3_1 | (rop3_S ^ rop3_T))) )
+/*
+ * Account for transparency.
+ */
+#define rop3_use_D_when_0_(op, mask)\
+ (((op) & ~(rop3_1 - mask)) | (rop3_D & ~mask))
+#define rop3_use_D_when_1_(op, mask)\
+ (((op) & ~mask) | (rop3_D & mask))
+#define rop3_use_D_when_S_0(op) rop3_use_D_when_0_(op, rop3_S)
+#define rop3_use_D_when_S_1(op) rop3_use_D_when_1_(op, rop3_S)
+#define rop3_use_D_when_T_0(op) rop3_use_D_when_0_(op, rop3_T)
+#define rop3_use_D_when_T_1(op) rop3_use_D_when_1_(op, rop3_T)
+/*
+ * Invert the result.
+ */
+#define rop3_not(op) ((op) ^ rop3_1)
+/*
+ * Test whether an operand is used.
+ */
+#define rop3_uses_(op, mask, shift)\
+ ( ((((op) << shift) ^ (op)) & mask) != 0 )
+#define rop3_uses_D(op) rop3_uses_(op, rop3_D, rop3_D_shift)
+#define rop3_uses_S(op) rop3_uses_(op, rop3_S, rop3_S_shift)
+#define rop3_uses_T(op) rop3_uses_(op, rop3_T, rop3_T_shift)
+/*
+ * Test whether an operation is idempotent, i.e., whether
+ * f(D, S, T) = f(f(D, S, T), S, T). This is equivalent to the condition that
+ * for all values s and t, !( f(0,s,t) == 1 && f(1,s,t) == 0 ).
+ */
+#define rop3_is_idempotent(op)\
+ !( (op) & ~((op) << rop3_D_shift) & rop3_D )
+
+/* Transparency */
+#define source_transparent_default false
+#define pattern_transparent_default false
+
+/* Render algorithm */
+#define render_algorithm_default 0
+#define render_algorithm_min 0
+#define render_algorithm_max 14
+
+/*
+ * We define a logical operation as a RasterOp, transparency flags,
+ * and render algorithm all packed into a single integer.
+ * In principle, we should use a structure, but most C implementations
+ * implement structure values very inefficiently.
+ */
+#define lop_rop(lop) ((gs_rop3_t)((lop) & 0xff)) /* must be low-order bits */
+#define lop_S_transparent 0x100
+#define lop_T_transparent 0x200
+#define lop_ral_shift 10
+#define lop_ral_mask 0xf
+typedef uint gs_logical_operation_t;
+#define lop_default\
+ (rop3_default |\
+ (source_transparent_default ? lop_S_transparent : 0) |\
+ (pattern_transparent_default ? lop_T_transparent : 0) |\
+ (render_algorithm_default << lop_ral_shift))
+
+/* Test whether a logical operation just sets D = x if y = 0. */
+#define lop_no_T_is_S(lop)\
+ (((lop) & (lop_S_transparent | (rop3_1 - rop3_T))) == (rop3_S & ~rop3_T))
+#define lop_no_S_is_T(lop)\
+ (((lop) & (lop_T_transparent | (rop3_1 - rop3_S))) == (rop3_T & ~rop3_S))
+/* Test whether a logical operation is idempotent. */
+#define lop_is_idempotent(lop) rop3_is_idempotent(lop)
+
+/* Define the interface to the table of 256 RasterOp procedures. */
+typedef unsigned rop_operand;
+typedef rop_operand (*rop_proc)(P3(rop_operand D, rop_operand S, rop_operand T));
+
+/* Define the table of operand usage by the 256 RasterOp operations. */
+typedef enum {
+ rop_usage_none = 0,
+ rop_usage_D = 1,
+ rop_usage_S = 2,
+ rop_usage_DS = 3,
+ rop_usage_T = 4,
+ rop_usage_DT = 5,
+ rop_usage_ST = 6,
+ rop_usage_DST = 7
+} rop_usage_t;
+
+#endif /* gsropt_INCLUDED */
diff --git a/gs/src/gsroptab.c b/gs/src/gsroptab.c
new file mode 100644
index 000000000..59245dd5b
--- /dev/null
+++ b/gs/src/gsroptab.c
@@ -0,0 +1,372 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsroptab.c */
+/* Table of RasterOp procedures */
+#include "stdpre.h"
+#include "gsropt.h"
+
+/*
+ * The H-P documentation (probably copied from Microsoft documentation)
+ * specifies RasterOp algorithms using reverse Polish notation, with
+ * a = AND, o = OR, n = NOT, x = XOR
+ * We can use preprocessor macros to transcribe these algorithms almost
+ * literally into C code.
+ */
+
+#ifdef __PROTOTYPES__
+# define rop_proc(pname)\
+private rop_operand pname(rop_operand D, rop_operand S, rop_operand T)
+#else
+# define rop_proc(pname)\
+private rop_operand pname(D,S,T) rop_operand D; rop_operand S; rop_operand T;
+#endif
+#define r return
+
+#define a(u,v) (u&v)
+#define o(u,v) (u|v)
+#define x(u,v) (u^v)
+
+rop_proc(rop0) { r 0; } /* 0 */
+rop_proc(rop1) { r ~(D | (S | T)); } /* DTSoon */
+rop_proc(rop2) { r D & (~(S | T)); } /* DTSona */
+rop_proc(rop3) { r ~(S | T); } /* TSon */
+rop_proc(rop4) { r S & (~(D | T)); } /* SDTona */
+rop_proc(rop5) { r ~(D | T); } /* DTon */
+rop_proc(rop6) { r ~(T | (~(D ^ S))); } /* TDSxnon */
+rop_proc(rop7) { r ~(T | (D & S)); } /* TDSaon */
+rop_proc(rop8) { r S & (D & ~T); } /* SDTnaa */
+rop_proc(rop9) { r ~(T | (D ^ S)); } /* TDSxon */
+rop_proc(rop10) { r D & ~T; } /* DTna */
+rop_proc(rop11) { r ~(T | (S & ~D)); } /* TSDnaon */
+rop_proc(rop12) { r S & ~T; } /* STna */
+rop_proc(rop13) { r ~(T | (D & ~S)); } /* TDSnaon */
+rop_proc(rop14) { r ~(T | (~(D | S))); } /* TDSonon */
+rop_proc(rop15) { r ~T; } /* Tn */
+rop_proc(rop16) { r T & (~(D | S)); } /* TDSona */
+rop_proc(rop17) { r ~(D | S); } /* DSon */
+rop_proc(rop18) { r ~(S | (~(D ^ T))); } /* SDTxnon */
+rop_proc(rop19) { r ~(S | (D & T)); } /* SDTaon */
+rop_proc(rop20) { r ~(D | ~(T ^ S)); } /* DTSxnon */
+rop_proc(rop21) { r ~(D | (T & S)); } /* DTSaon */
+rop_proc(rop22) { r (T ^ (S ^ (D & ~(T & S)))); } /* TSDTSanaxx */
+rop_proc(rop23) { r ~(S ^ ((S ^ T) & (D ^ S))); } /* SSTxDSxaxn */
+rop_proc(rop24) { r (S ^ T) & (T ^ D); } /* STxTDxa */
+rop_proc(rop25) { r ~(S ^ (D & ~(T & S))); } /* SDTSanaxn */
+rop_proc(rop26) { r T ^ (D | (S & T)); } /* TDSTaox */
+rop_proc(rop27) { r ~(S ^ (D & (T ^ S))); } /* SDTSxaxn */
+rop_proc(rop28) { r T ^ (S | (D & T)); } /* TSDTaox */
+rop_proc(rop29) { r ~(D ^ (S & (T ^ D))); } /* DSTDxaxn */
+rop_proc(rop30) { r T ^ (D | S); } /* TDSox */
+rop_proc(rop31) { r ~(T & (D | S)); } /* TDSoan */
+rop_proc(rop32) { r D & (T & ~S); } /* DTSnaa */
+rop_proc(rop33) { r ~(S | (D ^ T)); } /* SDTxon */
+rop_proc(rop34) { r D & ~S; } /* DSna */
+rop_proc(rop35) { r ~(S | (T & ~D)); } /* STDnaon */
+rop_proc(rop36) { r (S ^ T) & (D ^ S); } /* STxDSxa */
+rop_proc(rop37) { r ~(T ^ (D & ~(S & T))); } /* TDSTanaxn */
+rop_proc(rop38) { r S ^ (D | (T & S)); } /* SDTSaox */
+rop_proc(rop39) { r S ^ (D | ~(T ^ S)); } /* SDTSxnox */
+rop_proc(rop40) { r D & (T ^ S); } /* DTSxa */
+rop_proc(rop41) { r ~(T ^ (S ^ (D | (T & S)))); } /* TSDTSaoxxn */
+rop_proc(rop42) { r D & ~(T & S); } /* DTSana */
+rop_proc(rop43) { r ~x(a(x(D,T),x(T,S)),S) ; } /* SSTxTDxaxn */
+rop_proc(rop44) { r (S ^ (T & (D | S))); } /* STDSoax */
+rop_proc(rop45) { r T ^ (S | ~D); } /* TSDnox */
+rop_proc(rop46) { r (T ^ (S | (D ^ T))); } /* TSDTxox */
+rop_proc(rop47) { r ~(T & (S | ~D)); } /* TSDnoan */
+rop_proc(rop48) { r T & ~S; } /* TSna */
+rop_proc(rop49) { r ~(S | (D & ~T)); } /* SDTnaon */
+rop_proc(rop50) { r S ^ (D | (T | S)); } /* SDTSoox */
+rop_proc(rop51) { r ~S; } /* Sn */
+rop_proc(rop52) { r S ^ (T |(D & S)); } /* STDSaox */
+rop_proc(rop53) { r S ^ (T | ~(D ^ S)); } /* STDSxnox */
+rop_proc(rop54) { r S ^ (D | T); } /* SDTox */
+rop_proc(rop55) { r ~(S & (D | T)); } /* SDToan */
+rop_proc(rop56) { r T ^ (S & (D | T)); } /* TSDToax */
+rop_proc(rop57) { r S ^ (T | ~D); } /* STDnox */
+rop_proc(rop58) { r S ^ (T | (D ^ S)); } /* STDSxox */
+rop_proc(rop59) { r ~(S & (T | ~D)); } /* STDnoan */
+rop_proc(rop60) { r T ^ S; } /* TSx */
+rop_proc(rop61) { r S ^ (T | ~(D | S)); } /* STDSonox */
+rop_proc(rop62) { r S ^ (T | (D & ~S)); } /* STDSnaox */
+rop_proc(rop63) { r ~(T & S); } /* TSan */
+rop_proc(rop64) { r T & (S & ~D); } /* TSDnaa */
+rop_proc(rop65) { r ~(D | (T ^ S)); } /* DTSxon */
+rop_proc(rop66) { r (S ^ D) & (T ^ D); } /* SDxTDxa */
+rop_proc(rop67) { r ~(S ^ (T & ~(D & S))); } /* STDSanaxn */
+rop_proc(rop68) { r S & ~D; } /* SDna */
+rop_proc(rop69) { r ~(D | (T & ~S)); } /* DTSnaon */
+rop_proc(rop70) { r D ^ (S | (T & D)); } /* DSTDaox */
+rop_proc(rop71) { r ~(T ^ (S & (D ^ T))); } /* TSDTxaxn */
+rop_proc(rop72) { r S & (D ^ T); } /* SDTxa */
+rop_proc(rop73) { r ~(T ^ (D ^ (S | (T & D)))); } /* TDSTDaoxxn */
+rop_proc(rop74) { r D ^ (T & (S | D)); } /* DTSDoax */
+rop_proc(rop75) { r T ^ (D | ~S); } /* TDSnox */
+rop_proc(rop76) { r S & ~(D & T); } /* SDTana */
+rop_proc(rop77) { r ~(S ^ ((S ^ T) | (D ^ S))); } /* SSTxDSxoxn */
+rop_proc(rop78) { r T ^ (D | (S ^ T)); } /* TDSTxox */
+rop_proc(rop79) { r ~(T & (D | ~S)); } /* TDSnoan */
+rop_proc(rop80) { r T & ~D; } /* TDna */
+rop_proc(rop81) { r ~(D | (S & ~T)); } /* DSTnaon */
+rop_proc(rop82) { r D ^ (T | (S & D)); } /* DTSDaox */
+rop_proc(rop83) { r ~(S ^ (T & (D ^ S))); } /* STDSxaxn */
+rop_proc(rop84) { r ~(D | ~(T | S)); } /* DTSonon */
+rop_proc(rop85) { r ~D; } /* Dn */
+rop_proc(rop86) { r D ^ (T | S); } /* DTSox */
+rop_proc(rop87) { r ~(D & (T | S)); } /* DTSoan */
+rop_proc(rop88) { r T ^ (D & (S | T)); } /* TDSToax */
+rop_proc(rop89) { r D ^ (T | ~S); } /* DTSnox */
+rop_proc(rop90) { r D ^ T; } /* DTx */
+rop_proc(rop91) { r D ^ (T | ~(S | D)); } /* DTSDonox */
+rop_proc(rop92) { r D ^ (T | (S ^ D)); } /* DTSDxox */
+rop_proc(rop93) { r ~(D & (T | ~S)); } /* DTSnoan */
+rop_proc(rop94) { r D ^ (T | (S & ~D)); } /* DTSDnaox */
+rop_proc(rop95) { r ~(D & T); } /* DTan */
+rop_proc(rop96) { r T & (D ^ S); } /* TDSxa */
+rop_proc(rop97) { r ~(D ^ (S ^ (T | (D & S)))); } /* DSTDSaoxxn */
+rop_proc(rop98) { r D ^ (S & (T | D)); } /* DSTDoax */
+rop_proc(rop99) { r S ^ (D | ~T); } /* SDTnox */
+rop_proc(rop100) { r S ^ (D & (T | S)); } /* SDTSoax */
+rop_proc(rop101) { r D ^ (S | ~T); } /* DSTnox */
+rop_proc(rop102) { r D ^ S; } /* DSx */
+rop_proc(rop103) { r S ^ (D | ~(T | S)); } /* SDTSonox */
+rop_proc(rop104) { r ~(D ^ (S ^ (T | ~(D | S)))); } /* DSTDSonoxxn */
+rop_proc(rop105) { r ~(T ^ (D ^ S)); } /* TDSxxn */
+rop_proc(rop106) { r D ^ (T & S); } /* DTSax */
+rop_proc(rop107) { r ~(T ^ (S ^ (D & (T | S)))); } /* TSDTSoaxxn */
+rop_proc(rop108) { r (D & T) ^ S; } /* SDTax */
+rop_proc(rop109) { r ~((((T | D) & S) ^ D) ^ T); } /* TDSTDoaxxn */
+rop_proc(rop110) { r ((~S | T) & D) ^ S; } /* SDTSnoax */
+rop_proc(rop111) { r ~(~(D ^ S) & T); } /* TDSxnan */
+rop_proc(rop112) { r ~(D & S) & T; } /* TDSana */
+rop_proc(rop113) { r ~(((S ^ D) & (T ^ D)) ^ S); } /* SSDxTDxaxn */
+rop_proc(rop114) { r ((T ^ S) | D) ^ S; } /* SDTSxox */
+rop_proc(rop115) { r ~((~T | D) & S); } /* SDTnoan */
+rop_proc(rop116) { r ((T ^ D) | S) ^ D; } /* DSTDxox */
+rop_proc(rop117) { r ~((~T | S) & D); } /* DSTnoan */
+rop_proc(rop118) { r ((~S & T) | D) ^ S; } /* SDTSnaox */
+rop_proc(rop119) { r ~(D & S); } /* DSan */
+rop_proc(rop120) { r (D & S) ^ T; } /* TDSax */
+rop_proc(rop121) { r ~((((D | S) & T) ^ S) ^ D); } /* DSTDSoaxxn */
+rop_proc(rop122) { r ((~D | S) & T) ^ D; } /* DTSDnoax */
+rop_proc(rop123) { r ~(~(D ^ T) & S); } /* SDTxnan */
+rop_proc(rop124) { r ((~S | D) & T) ^ S; } /* STDSnoax */
+rop_proc(rop125) { r ~(~(T ^ S) & D); } /* DTSxnan */
+rop_proc(rop126) { r (S ^ T) | (D ^ S); } /* STxDSxo */
+rop_proc(rop127) { r ~((T & S) & D); } /* DTSaan */
+rop_proc(rop128) { r (T & S) & D; } /* DTSaa */
+rop_proc(rop129) { r ~((S ^ T) | (D ^ S)); } /* STxDSxon */
+rop_proc(rop130) { r ~(T ^ S) & D; } /* DTSxna */
+rop_proc(rop131) { r ~(((~S | D) & T) ^ S); } /* STDSnoaxn */
+rop_proc(rop132) { r ~(D ^ T) & S; } /* SDTxna */
+rop_proc(rop133) { r ~(((~T | S) & D) ^ T); } /* TDSTnoaxn */
+rop_proc(rop134) { r (((D | S) & T) ^ S) ^ D; } /* DSTDSoaxx */
+rop_proc(rop135) { r ~((D & S) ^ T); } /* TDSaxn */
+rop_proc(rop136) { r D & S; } /* DSa */
+rop_proc(rop137) { r ~(((~S & T) | D) ^ S); } /* SDTSnaoxn */
+rop_proc(rop138) { r (~T | S) & D; } /* DSTnoa */
+rop_proc(rop139) { r ~(((T ^ D) | S) ^ D); } /* DSTDxoxn */
+rop_proc(rop140) { r (~T | D) & S; } /* SDTnoa */
+rop_proc(rop141) { r ~(((T ^ S) | D) ^ S); } /* SDTSxoxn */
+rop_proc(rop142) { r ((S ^ D) & (T ^ D)) ^ S; } /* SSDxTDxax */
+rop_proc(rop143) { r ~(~(D & S) & T); } /* TDSanan */
+rop_proc(rop144) { r ~(D ^ S) & T; } /* TDSxna */
+rop_proc(rop145) { r ~(((~S | T) & D) ^ S); } /* SDTSnoaxn */
+rop_proc(rop146) { r (((D | T) & S) ^ T) ^ D; } /* DTSDToaxx */
+rop_proc(rop147) { r ~((T & D) ^ S); } /* STDaxn */
+rop_proc(rop148) { r (((T | S) & D) ^ S) ^ T; } /* TSDTSoaxx */
+rop_proc(rop149) { r ~((T & S) ^ D); } /* DTSaxn */
+rop_proc(rop150) { r (T ^ S) ^ D; } /* DTSxx */
+rop_proc(rop151) { r ((~(T | S) | D) ^ S) ^ T; } /* TSDTSonoxx */
+rop_proc(rop152) { r ~((~(T | S) | D) ^ S); } /* SDTSonoxn */
+rop_proc(rop153) { r ~(D ^ S); } /* DSxn */
+rop_proc(rop154) { r (~S & T) ^ D; } /* DTSnax */
+rop_proc(rop155) { r ~(((T | S) & D) ^ S); } /* SDTSoaxn */
+rop_proc(rop156) { r (~D & T) ^ S; } /* STDnax */
+rop_proc(rop157) { r ~(((T | D) & S) ^ D); } /* DSTDoaxn */
+rop_proc(rop158) { r (((D & S) | T) ^ S) ^ D; } /* DSTDSaoxx */
+rop_proc(rop159) { r ~((D ^ S) & T); } /* TDSxan */
+rop_proc(rop160) { r D & T; } /* DTa */
+rop_proc(rop161) { r ~(((~T & S) | D) ^ T); } /* TDSTnaoxn */
+rop_proc(rop162) { r (~S | T) & D; } /* DTSnoa */
+rop_proc(rop163) { r ~(((D ^ S) | T) ^ D); } /* DTSDxoxn */
+rop_proc(rop164) { r ~((~(T | S) | D) ^ T) ; } /* TDSTonoxn */
+rop_proc(rop165) { r ~(D ^ T); } /* TDxn */
+rop_proc(rop166) { r (~T & S) ^ D; } /* DSTnax */
+rop_proc(rop167) { r ~(((T | S) & D) ^ T); } /* TDSToaxn */
+rop_proc(rop168) { r ((S | T) & D); } /* DTSoa */
+rop_proc(rop169) { r ~((S | T) ^ D); } /* DTSoxn */
+rop_proc(rop170) { r D; } /* D */
+rop_proc(rop171) { r ~(S | T) | D; } /* DTSono */
+rop_proc(rop172) { r (((S ^ D) & T) ^ S); } /* STDSxax */
+rop_proc(rop173) { r ~(((D & S) | T) ^ D); } /* DTSDaoxn */
+rop_proc(rop174) { r (~T & S) | D; } /* DSTnao */
+rop_proc(rop175) { r ~T | D; } /* DTno */
+rop_proc(rop176) { r (~S | D) & T; } /* TDSnoa */
+rop_proc(rop177) { r ~(((T ^ S) | D) ^ T) ; } /* TDSTxoxn */
+rop_proc(rop178) { r ((S ^ D) | (S ^ T)) ^ S; } /* SSTxDSxox */
+rop_proc(rop179) { r ~(~(T & D) & S); } /* SDTanan */
+rop_proc(rop180) { r (~D & S) ^ T; } /* TSDnax */
+rop_proc(rop181) { r ~(((D | S) & T) ^ D); } /* DTSDoaxn */
+rop_proc(rop182) { r (((T & D) | S) ^ T) ^ D; } /* DTSDTaoxx */
+rop_proc(rop183) { r ~((T ^ D) & S); } /* SDTxan */
+rop_proc(rop184) { r ((T ^ D) & S) ^ T; } /* TSDTxax */
+rop_proc(rop185) { r (~((D & T) | S) ^ D); } /* DSTDaoxn */
+rop_proc(rop186) { r (~S & T) | D; } /* DTSnao */
+rop_proc(rop187) { r ~S | D; } /* DSno */
+rop_proc(rop188) { r (~(S & D) & T) ^ S; } /* STDSanax */
+rop_proc(rop189) { r ~((D ^ T) & (D ^ S)); } /* SDxTDxan */
+rop_proc(rop190) { r (S ^ T) | D; } /* DTSxo */
+rop_proc(rop191) { r ~(S & T) | D; } /* DTSano */
+rop_proc(rop192) { r T & S; } /* TSa */
+rop_proc(rop193) { r ~(((~S & D) | T)^ S); } /* STDSnaoxn */
+rop_proc(rop194) { r ~x(o(~o(S,D),T),S) ; } /* STDSonoxn */
+rop_proc(rop195) { r ~(S ^ T); } /* TSxn */
+rop_proc(rop196) { r ((~D | T) & S); } /* STDnoa */
+rop_proc(rop197) { r ~(((S ^ D) | T) ^ S); } /* STDSxoxn */
+rop_proc(rop198) { r ((~T & D) ^ S); } /* SDTnax */
+rop_proc(rop199) { r ~(((T | D) & S) ^ T); } /* TSDToaxn */
+rop_proc(rop200) { r ((T | D) & S); } /* SDToa */
+rop_proc(rop201) { r ~((D | T) ^ S); } /* STDoxn */
+rop_proc(rop202) { r ((D ^ S) & T) ^ D; } /* DTSDxax */
+rop_proc(rop203) { r ~(((S & D) | T) ^ S); } /* STDSaoxn */
+rop_proc(rop204) { r S; } /* S */
+rop_proc(rop205) { r ~(T | D) | S; } /* SDTono */
+rop_proc(rop206) { r (~T & D) | S; } /* SDTnao */
+rop_proc(rop207) { r ~T | S; } /* STno */
+rop_proc(rop208) { r (~D | S) & T; } /* TSDnoa */
+rop_proc(rop209) { r ~(((T ^ D) | S) ^ T); } /* TSDTxoxn */
+rop_proc(rop210) { r (~S & D) ^ T; } /* TDSnax */
+rop_proc(rop211) { r ~(((S | D) & T) ^ S); } /* STDSoaxn */
+rop_proc(rop212) { r x(a(x(D,T),x(T,S)),S) ; } /* SSTxTDxax */
+rop_proc(rop213) { r ~(~(S & T) & D); } /* DTSanan */
+rop_proc(rop214) { r ((((S & T) | D) ^ S) ^ T); } /* TSDTS aoxx */
+rop_proc(rop215) { r ~((S ^ T) & D); } /* DTS xan */
+rop_proc(rop216) { r ((T ^ S) & D) ^ T; } /* TDST xax */
+rop_proc(rop217) { r ~(((S & T) | D) ^ S); } /* SDTS aoxn */
+rop_proc(rop218) { r x(a(~a(D,S),T),D) ; } /* DTSD anax */
+rop_proc(rop219) { r ~a(x(S,D),x(T,S)) ; } /* STxDSxan */
+rop_proc(rop220) { r (~D & T) | S; } /* STD nao */
+rop_proc(rop221) { r ~D | S; } /* SDno */
+rop_proc(rop222) { r (T ^ D) | S; } /* SDT xo */
+rop_proc(rop223) { r (~(T & D)) | S; } /* SDT ano */
+rop_proc(rop224) { r ((S | D) & T); } /* TDS oa */
+rop_proc(rop225) { r ~((S | D) ^ T); } /* TDS oxn */
+rop_proc(rop226) { r (((D ^ T) & S) ^ D); } /* DSTD xax */
+rop_proc(rop227) { r ~(((T & D) | S) ^ T); } /* TSDT aoxn */
+rop_proc(rop228) { r ((S ^ T) & D) ^ S; } /* SDTSxax */
+rop_proc(rop229) { r ~(((T & S) | D) ^ T); } /* TDST aoxn */
+rop_proc(rop230) { r (~(S & T) & D) ^ S; } /* SDTSanax */
+rop_proc(rop231) { r ~a(x(D,T),x(T,S)) ; } /* STxTDxan */
+rop_proc(rop232) { r x(a(x(S,D),x(T,S)),S) ; } /* SS TxD Sxax */
+rop_proc(rop233) { r ~x(x(a(~a(S,D),T),S),D) ; } /* DST DSan axxn */
+rop_proc(rop234) { r (S & T) | D; } /* DTSao */
+rop_proc(rop235) { r ~(S ^ T) | D; } /* DTSxno */
+rop_proc(rop236) { r (T & D) | S; } /* SDTao */
+rop_proc(rop237) { r ~(T ^ D) | S; } /* SDTxno */
+rop_proc(rop238) { r S | D; } /* DSo */
+rop_proc(rop239) { r (~T | D) | S; } /* SDTnoo */
+rop_proc(rop240) { r T; } /* T */
+rop_proc(rop241) { r ~(S | D) | T; } /* TDSono */
+rop_proc(rop242) { r (~S & D) | T; } /* TDSnao */
+rop_proc(rop243) { r ~S | T; } /* TSno */
+rop_proc(rop244) { r (~D & S) | T; } /* TSDnao */
+rop_proc(rop245) { r ~D | T; } /* TDno */
+rop_proc(rop246) { r (S ^ D) | T; } /* TDSxo */
+rop_proc(rop247) { r ~ (S & D) | T; } /* TDSano */
+rop_proc(rop248) { r (S & D) | T; } /* TDSao */
+rop_proc(rop249) { r ~ (S ^ D) | T; } /* TDSxno */
+rop_proc(rop250) { r D | T; } /* DTo */
+rop_proc(rop251) { r (~S | T) | D; } /* DTSnoo */
+rop_proc(rop252) { r S | T; } /* TSo */
+rop_proc(rop253) { r (~D | S) | T; } /* TSDnoo */
+rop_proc(rop254) { r S | T | D; } /* DTSoo */
+rop_proc(rop255) { r ~(rop_operand)0; } /* 1 */
+
+#undef rop_proc
+const far_data rop_proc rop_proc_table[256] =
+{
+ rop0, rop1, rop2, rop3, rop4, rop5, rop6, rop7,
+ rop8, rop9, rop10, rop11, rop12, rop13, rop14, rop15,
+ rop16, rop17, rop18, rop19, rop20, rop21, rop22, rop23,
+ rop24, rop25, rop26, rop27, rop28, rop29, rop30, rop31,
+ rop32, rop33, rop34, rop35, rop36, rop37, rop38, rop39,
+ rop40, rop41, rop42, rop43, rop44, rop45, rop46, rop47,
+ rop48, rop49, rop50, rop51, rop52, rop53, rop54, rop55,
+ rop56, rop57, rop58, rop59, rop60, rop61, rop62, rop63,
+ rop64, rop65, rop66, rop67, rop68, rop69, rop70, rop71,
+ rop72, rop73, rop74, rop75, rop76, rop77, rop78, rop79,
+ rop80, rop81, rop82, rop83, rop84, rop85, rop86, rop87,
+ rop88, rop89, rop90, rop91, rop92, rop93, rop94, rop95,
+ rop96, rop97, rop98, rop99, rop100, rop101, rop102, rop103,
+ rop104, rop105, rop106, rop107, rop108, rop109, rop110, rop111,
+ rop112, rop113, rop114, rop115, rop116, rop117, rop118, rop119,
+ rop120, rop121, rop122, rop123, rop124, rop125, rop126, rop127,
+ rop128, rop129, rop130, rop131, rop132, rop133, rop134, rop135,
+ rop136, rop137, rop138, rop139, rop140, rop141, rop142, rop143,
+ rop144, rop145, rop146, rop147, rop148, rop149, rop150, rop151,
+ rop152, rop153, rop154, rop155, rop156, rop157, rop158, rop159,
+ rop160, rop161, rop162, rop163, rop164, rop165, rop166, rop167,
+ rop168, rop169, rop170, rop171, rop172, rop173, rop174, rop175,
+ rop176, rop177, rop178, rop179, rop180, rop181, rop182, rop183,
+ rop184, rop185, rop186, rop187, rop188, rop189, rop190, rop191,
+ rop192, rop193, rop194, rop195, rop196, rop197, rop198, rop199,
+ rop200, rop201, rop202, rop203, rop204, rop205, rop206, rop207,
+ rop208, rop209, rop210, rop211, rop212, rop213, rop214, rop215,
+ rop216, rop217, rop218, rop219, rop220, rop221, rop222, rop223,
+ rop224, rop225, rop226, rop227, rop228, rop229, rop230, rop231,
+ rop232, rop233, rop234, rop235, rop236, rop237, rop238, rop239,
+ rop240, rop241, rop242, rop243, rop244, rop245, rop246, rop247,
+ rop248, rop249, rop250, rop251, rop252, rop253, rop254, rop255
+};
+
+/*
+ * Here is the program that generated the table below.
+ *
+int
+main(int argc, char *argv[])
+{ uint i;
+ for ( i = 0; i < 256; ++i )
+ printf("%d,",
+ (rop3_uses_D(i) ? rop_usage_D : 0) |
+ (rop3_uses_S(i) ? rop_usage_S : 0) |
+ (rop3_uses_T(i) ? rop_usage_T : 0));
+ fflush(stdout);
+ return 0;
+}
+ */
+
+const far_data byte /*rop_usage_t*/ rop_usage_table[256] = {
+ 0,7,7,6,7,5,7,7,7,7,5,7,6,7,7,4,
+ 7,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,3,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 6,7,7,2,7,7,7,7,7,7,7,7,6,7,7,6,
+ 7,7,7,7,3,7,7,7,7,7,7,7,7,7,7,7,
+ 5,7,7,7,7,1,7,7,7,7,5,7,7,7,7,5,
+ 7,7,7,7,7,7,3,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,3,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,3,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,3,7,7,7,7,7,7,
+ 5,7,7,7,7,5,7,7,7,7,1,7,7,7,7,5,
+ 7,7,7,7,7,7,7,7,7,7,7,3,7,7,7,7,
+ 6,7,7,6,7,7,7,7,7,7,7,7,2,7,7,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,3,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,7,
+ 4,7,7,6,7,5,7,7,7,7,5,7,6,7,7,0
+};
diff --git a/gs/src/gsstate.c b/gs/src/gsstate.c
new file mode 100644
index 000000000..510628831
--- /dev/null
+++ b/gs/src/gsstate.c
@@ -0,0 +1,1046 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsstate.c */
+/* Miscellaneous graphics state operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gzstate.h"
+#include "gxcspace.h" /* here for gscolor2.h */
+#include "gscolor2.h"
+#include "gscoord.h" /* for gs_initmatrix */
+#include "gscie.h"
+#include "gxcmap.h"
+#include "gxdevice.h"
+#include "gxpcache.h"
+#include "gzht.h"
+#include "gzline.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Imported values */
+/* The following should include a 'const', but for some reason */
+/* the Watcom compiler won't accept it, even though it happily accepts */
+/* the same construct everywhere else. */
+extern /*const*/ gx_color_map_procs *cmap_procs_default;
+
+/* Forward references */
+private gs_state *gstate_alloc(P2(gs_memory_t *, client_name_t));
+private void gstate_set_contents(P2(gs_state *, gs_state_contents *));
+private gs_state *gstate_clone(P4(gs_state *, gs_memory_t *, client_name_t,
+ gs_state_copy_reason_t));
+private void gstate_free_contents(P1(gs_state *));
+private void gstate_share_paths(P1(const gs_state *));
+private int gstate_copy(P4(gs_state *, const gs_state *,
+ gs_state_copy_reason_t, client_name_t));
+
+/*
+ * Graphics state storage management is complicated. There are many
+ * different classes of storage associated with a graphics state:
+ *
+ * (1) The gstate object itself. This includes some objects physically
+ * embedded within the gstate object, but because of garbage collection
+ * requirements, there are no embedded objects that can be
+ * referenced by non-transient pointers. We assume that the gstate
+ * stack "owns" its gstates and that we can free the top gstate when
+ * doing a restore.
+ *
+ * (2) Objects that are referenced directly by the gstate and whose lifetime
+ * is independent of the gstate. These are garbage collected, not
+ * reference counted, so we don't need to do anything special with them
+ * when manipulating gstates. Currently this includes:
+ * font, device
+ *
+ * (3) Objects that are referenced directly by the gstate, may be shared
+ * among gstates, and should disappear when no gstates reference them.
+ * These fall into two groups:
+ *
+ * (3a) Objects that are logically connected to individual gstates.
+ * We use reference counting to manage these. Currently these are:
+ * halftone, dev_ht, cie_render, black_generation,
+ * undercolor_removal, set_transfer.*, cie_joint_caches
+ * effective_transfer.* may point to some of the same objects as
+ * set_transfer.*, but don't contribute to the reference count.
+ * Similarly, dev_color may point to the dev_ht object. For
+ * simplicity, we initialize all of these pointers to 0 and then
+ * allocate the object itself when needed.
+ *
+ * (3b) Objects whose lifetimes are associated with something else.
+ * Currently these are:
+ * ht_cache, which is associated with the entire gstate
+ * stack, is allocated with the very first graphics state,
+ * and currently is never freed;
+ * pattern_cache, which is associated with the entire
+ * stack, is allocated when first needed, and currently
+ * is never freed;
+ */
+#ifdef DPNEXT
+/*
+ * view_clip, which is associated with the current
+ * save level (effectively, with the gstate sub-stack
+ * back to the save) and is managed specially;
+ * saved_view_clip, which is only used in the gstate on the
+ * top of a stack saved by 'save'.
+ */
+#endif
+/* (4) Objects that are referenced directly by exactly one gstate and that
+ * are not referenced (except transiently) from any other object.
+ * These fall into three groups:
+ *
+ * (4a) Objects lumped into a single gs_state_contents object in order
+ * to reduce the load on the allocator for gsave and grestore. Each
+ * gs_gstate_contents is referenced by exactly one gstate, and nowhere
+ * else. We reference the individual members through pointers, just as
+ * though they were allocated individually, so that we wouldn't have to
+ * keep remembering to put & in front of references to its components,
+ * which would otherwise have to be embedded in the gstate object.
+ * Again, we do not allow non-transient references to the objects
+ * embedded in this object, aside from a single pointer from the gstate
+ * object to each embedded component. Currently these are:
+ * path, clip_path, ccolor, dev_color
+ *
+ * (4b) Objects allocated individually:
+ * line_params.dash.pattern, color_space
+ * color_space is a special case because it is referenced both
+ * directly and also indirectly from image enumerators.
+ * line_params.dash.pattern is also a special case, because it is
+ * variable-length. Otherwise, we could include these elements in
+ * the contents object (4a).
+ *
+ * (4c) The "client data" for a gstate. For the interpreter, this is
+ * the refs associated with the gstate, such as the screen procedures.
+ * Client-supplied procedures manage client data.
+ *
+ * (5) Objects referenced indirectly from gstate objects of category (4),
+ * including objects that may also be referenced directly by the gstate.
+ * The individual routines that manipulate these are responsible
+ * for doing the right kind of reference counting or whatever.
+ * Currently:
+ * path and clip_path require gx_path_share/release,
+ * which use a 1-bit reference count;
+ * color_space and ccolor require cs_adjust_color/cspace_count
+ * or cs_adjust_counts, which use a full reference count;
+ * dev_color has no references to storage that it owns.
+ * We count on garbage collection or restore to deallocate
+ * sub-objects of halftone.
+ *
+ * This situation is unnecessarily complicated. We should get rid of
+ * the contents object and use reference counting to manage individually
+ * the objects it currently contains. We should use full reference
+ * counting for paths, and use the freeing procedure to release the
+ * individual path elements. However, making these changes runs a large
+ * risk of introducing hard-to-find bugs, so we don't plan to make them
+ * in the foreseeable future.
+ *
+ * Note that when we do a gsave, the newly allocated gstate doesn't
+ * necessarily reference the related objects that we allocate at the same
+ * time; in particular, the old contents go with the new gstate object and
+ * vice versa. The same is true of grestore. However, when we allocate
+ * gstates off-stack, the newly allocated gstate does reference the newly
+ * allocated component objects. Note also that setgstate / currentgstate
+ * may produce gstates in which different allocators own different
+ * sub-objects; this is OK, because restore guarantees that there won't
+ * be any dangling pointers (as long as we don't allow pointers from
+ * global gstates to local objects).
+ */
+
+/* The structure for allocating (most of) the contents of a gstate */
+/* all at once. The typedef is in gzstate.c. */
+struct gs_state_contents_s {
+ gx_path path;
+ gx_clip_path clip_path;
+ gs_client_color ccolor;
+ gx_device_color dev_color;
+};
+
+/* Enumerate the pointers in a graphics state, other than the ones */
+/* that point to the gs_state_contents and the ones in the imager state. */
+#ifdef DPNEXT
+#define gs_state_do_ptrs(m)\
+ m(0,saved) m(1,contents)\
+ /*m(---,path)*/ /*m(---,clip_path)*/\
+ m(2,color_space)\
+ /*m(---,client_color)*/ /*m(---,dev_color)*/\
+ m(3,font) m(4,root_font) m(5,show_gstate) /*m(---,device)*/\
+ m(6,client_data) m(7,view_clip) m(8,saved_view_clip)
+#define gs_state_num_ptrs 9
+#else
+#define gs_state_do_ptrs(m)\
+ m(0,saved) m(1,contents)\
+ /*m(---,path)*/ /*m(---,clip_path)*/\
+ m(2,color_space)\
+ /*m(---,client_color)*/ /*m(---,dev_color)*/\
+ m(3,font) m(4,root_font) m(5,show_gstate) /*m(---,device)*/\
+ m(6,client_data)
+#define gs_state_num_ptrs 7
+#endif
+/* Enumerate the pointers to the gs_state_contents. */
+#define gs_state_do_contents_ptrs(m)\
+ m(0,path) m(1,clip_path) m(2,ccolor) m(3,dev_color)
+
+/* GC descriptors */
+private_st_line_params();
+private_st_imager_state();
+private_st_gs_state();
+#ifdef DPNEXT
+private_st_gx_clip_state();
+#endif
+
+/* GC procedures for gs_imager_state */
+#define pis ((gs_imager_state *)vptr)
+private ENUM_PTRS_BEGIN(imager_state_enum_ptrs) ENUM_SUPER(gs_imager_state, st_line_params, line_params, st_imager_state_num_ptrs - st_line_params_num_ptrs);
+#define e1(i,elt) ENUM_PTR(i,gs_imager_state,elt);
+ gs_cr_state_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(imager_state_reloc_ptrs) {
+ RELOC_SUPER(gs_imager_state, st_line_params, line_params);
+#define r1(i,elt) RELOC_PTR(gs_imager_state,elt);
+ gs_cr_state_do_ptrs(r1)
+#undef r1
+} RELOC_PTRS_END
+#undef pis
+
+/* Components of the graphics state */
+gs_private_st_composite(st_gs_state_contents, gs_state_contents,
+ "gs_state_contents", state_contents_enum_ptrs, state_contents_reloc_ptrs);
+public_st_transfer_map();
+
+/* GC procedures for gs_state */
+#define gsvptr ((gs_state *)vptr)
+private ENUM_PTRS_BEGIN(gs_state_enum_ptrs) ENUM_PREFIX(st_imager_state, gs_state_num_ptrs + 1);
+#define e1(i,elt) ENUM_PTR(i,gs_state,elt);
+ gs_state_do_ptrs(e1)
+ case gs_state_num_ptrs: /* handle device specially */
+ ENUM_RETURN(gx_device_enum_ptr(gsvptr->device));
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_state_reloc_ptrs) {
+ RELOC_PREFIX(st_imager_state);
+ { /* Save the contents pointer before relocation. */
+ byte *cont = (byte *)gsvptr->contents;
+ long reloc;
+#define r1(i,elt) RELOC_PTR(gs_state,elt);
+ gs_state_do_ptrs(r1)
+#undef r1
+ gsvptr->device = gx_device_reloc_ptr(gsvptr->device, gcst);
+ /* Now relocate the pointers into the contents. */
+ reloc = cont - (byte *)gsvptr->contents;
+#define r1(i,elt)\
+ gsvptr->elt = (void *)((byte *)gsvptr->elt - reloc);
+ gs_state_do_contents_ptrs(r1)
+#undef r1
+ }
+} RELOC_PTRS_END
+#undef gsvptr
+
+/* GC procedures for gs_state_contents */
+#define cptr ((gs_state_contents *)vptr)
+private ENUM_PTRS_BEGIN_PROC(state_contents_enum_ptrs) {
+ gs_ptr_type_t ret;
+#define next_comp(np, st, e)\
+ if ( index < np ) { ret = (*st.enum_ptrs)(&cptr->e, sizeof(cptr->e), index, pep); goto rx; }\
+ index -= np
+#define last_comp(np, st, e)\
+ return (*st.enum_ptrs)(&cptr->e, sizeof(cptr->e), index, pep)
+ next_comp(st_path_max_ptrs, st_path, path);
+ next_comp(st_clip_path_max_ptrs, st_clip_path, clip_path);
+ next_comp(st_client_color_max_ptrs, st_client_color, ccolor);
+ last_comp(st_device_color_max_ptrs, st_device_color, dev_color);
+#undef next_comp
+#undef last_comp
+rx: if ( ret == 0 )
+ { /* A component ran out of pointers early. */
+ /* Just return a null so we can keep going. */
+ *pep = 0;
+ return ptr_struct_type;
+ }
+ return ret;
+ENUM_PTRS_END_PROC }
+private RELOC_PTRS_BEGIN(state_contents_reloc_ptrs) {
+ (*st_path.reloc_ptrs)(&cptr->path, sizeof(gx_path), gcst);
+ (*st_clip_path.reloc_ptrs)(&cptr->clip_path, sizeof(gx_clip_path), gcst);
+ (*st_client_color.reloc_ptrs)(&cptr->ccolor, sizeof(gs_client_color), gcst);
+ (*st_device_color.reloc_ptrs)(&cptr->dev_color, sizeof(gx_device_color), gcst);
+} RELOC_PTRS_END
+#undef cptr
+
+/* Copy client data, using the copy_for procedure if available, */
+/* the copy procedure otherwise. */
+private int near
+gstate_copy_client_data(gs_state *pgs, void *dto, void *dfrom,
+ gs_state_copy_reason_t reason)
+{ return (pgs->client_procs.copy_for != 0 ?
+ (*pgs->client_procs.copy_for)(dto, dfrom, reason) :
+ (*pgs->client_procs.copy)(dto, dfrom));
+}
+
+/* ------ Operations on the entire graphics state ------ */
+
+/* Initialize an imager state, other than the parts covered by */
+/* gs_imager_state_initial. */
+/* The halftone, dev_ht, and ht_cache elements are not set or used. */
+private float
+null_transfer(floatp gray, const gx_transfer_map *pmap)
+{ return gray;
+}
+int
+gs_imager_state_initialize(gs_imager_state *pis, gs_memory_t *mem)
+{ pis->memory = mem;
+ /* Skip halftone */
+ { int i;
+ for ( i = 0; i < gs_color_select_count; ++i )
+ pis->screen_phase[i].x = pis->screen_phase[i].y = 0;
+ }
+ /* Skip dev_ht */
+ /* Skip ht_cache */
+ pis->cie_render = 0;
+ pis->black_generation = 0;
+ pis->undercolor_removal = 0;
+ /* Allocate an initial transfer map. */
+ rc_alloc_struct_n(pis->set_transfer.colored.gray,
+ gx_transfer_map, &st_transfer_map,
+ mem, return_error(gs_error_VMerror),
+ "gs_imager_state_init(transfer)", 4);
+ pis->set_transfer.colored.gray->proc = null_transfer;
+ pis->set_transfer.colored.gray->id = gs_next_ids(1);
+ pis->set_transfer.colored.gray->values[0] = frac_0;
+ pis->set_transfer.colored.red =
+ pis->set_transfer.colored.green =
+ pis->set_transfer.colored.blue =
+ pis->set_transfer.colored.gray;
+ pis->effective_transfer = pis->set_transfer;
+ pis->cie_joint_caches = 0;
+ pis->cmap_procs = cmap_procs_default;
+ pis->pattern_cache = 0;
+ return 0;
+}
+
+/* Release an imager state. */
+void
+gs_imager_state_release(gs_imager_state *pis)
+{ static const char cname[] = "gs_imager_state_release";
+#define rcdecr(element)\
+ rc_decrement(pis->element, cname)
+
+ rcdecr(cie_joint_caches);
+ rcdecr(set_transfer.colored.gray);
+ rcdecr(set_transfer.colored.blue);
+ rcdecr(set_transfer.colored.green);
+ rcdecr(set_transfer.colored.red);
+ rcdecr(undercolor_removal);
+ rcdecr(black_generation);
+ rcdecr(cie_render);
+#undef rcdecr
+}
+
+/* Allocate and initialize a graphics state. */
+gs_state *
+gs_state_alloc(gs_memory_t *mem)
+{ gs_state *pgs = gstate_alloc(mem, "gs_state_alloc");
+
+ if ( pgs == 0 )
+ return 0;
+ { static const gs_imager_state gstate_initial =
+ { gs_imager_state_initial(1.0) };
+ *(gs_imager_state *)pgs = gstate_initial;
+ }
+ /* Just enough of the state is initialized at this point */
+ /* that it's OK to call gs_state_free if an allocation fails. */
+ rc_alloc_struct_1(pgs->halftone, gs_halftone, &st_halftone, mem,
+ goto fail, "gs_state_alloc(halftone)");
+ pgs->saved = 0;
+ gstate_set_contents(pgs, pgs->contents);
+
+ /* Initialize the color rendering state, except for elements */
+ /* which are in the gs_state contents (halftone). */
+
+ pgs->halftone->type = ht_type_none;
+ pgs->dev_ht = 0;
+ pgs->ht_cache = gx_ht_alloc_cache(mem,
+ gx_ht_cache_default_tiles(),
+ gx_ht_cache_default_bits());
+ gs_imager_state_initialize((gs_imager_state *)pgs, mem);
+ pgs->client_data = 0;
+
+ /* Initialize other things not covered by initgraphics */
+
+ gx_path_init(pgs->path, mem);
+ gx_cpath_init(pgs->clip_path, mem);
+#ifdef DPNEXT
+ rc_alloc_struct_1(pgs->view_clip, gx_clip_state, &st_gx_clip_state,
+ mem, goto fail, "gs_state_alloc(view_clip)");
+ pgs->view_clip->path =
+ gs_alloc_struct(mem, gx_clip_path, &st_clip_path,
+ "gs_state_alloc(view_clip path)");
+ if ( pgs->view_clip->path == 0 )
+ goto fail;
+ gx_cpath_init(pgs->view_clip->path, mem);
+ pgs->saved_view_clip = 0;
+#endif
+ /* Initialize things so that gx_remap_color won't crash. */
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ gx_set_device_color_1(pgs);
+ pgs->overprint = false;
+ gs_nulldevice(pgs);
+ gs_setalpha(pgs, 1.0);
+ gs_settransfer(pgs, null_transfer);
+ gs_setflat(pgs, 1.0);
+ gs_setfilladjust(pgs, 0.25, 0.25);
+ gs_setlimitclamp(pgs, false);
+ gs_setstrokeadjust(pgs, true);
+ pgs->font = 0; /* Not right, but acceptable until the */
+ /* PostScript code does the first setfont. */
+ pgs->root_font = 0; /* ditto */
+ pgs->in_cachedevice = 0;
+ pgs->in_charpath = (gs_char_path_mode)0;
+ pgs->show_gstate = 0;
+ pgs->level = 0;
+ pgs->client_data = 0;
+ if ( gs_initgraphics(pgs) < 0 )
+ { /* Something went very wrong */
+ return 0;
+ }
+ return pgs;
+fail: gs_state_free(pgs);
+ return 0;
+}
+
+/* Set the client data in a graphics state. */
+/* This should only be done to a newly created state. */
+void
+gs_state_set_client(gs_state *pgs, void *pdata,
+ const gs_state_client_procs *pprocs)
+{ pgs->client_data = pdata;
+ pgs->client_procs = *pprocs;
+}
+
+/* Get the client data from a graphics state. */
+#undef gs_state_client_data /* gzstate.h makes this a macro */
+void *
+gs_state_client_data(const gs_state *pgs)
+{ return pgs->client_data;
+}
+
+/* Free a graphics state */
+#ifdef DPNEXT
+/* Note that we do not free the view clip path. */
+#endif
+int
+gs_state_free(gs_state *pgs)
+{ gstate_free_contents(pgs);
+ gs_free_object(pgs->memory, pgs, "gs_state_free");
+ return 0;
+}
+
+/* Save the graphics state. */
+int
+gs_gsave(gs_state *pgs)
+{ gs_state *pnew = gstate_clone(pgs, pgs->memory, "gs_gsave",
+ copy_for_gsave);
+
+ if ( pnew == 0 )
+ return_error(gs_error_VMerror);
+ gx_path_share(pgs->path);
+ gx_cpath_share(pgs->clip_path);
+ pgs->saved = pnew;
+ if ( pgs->show_gstate == pgs )
+ pgs->show_gstate = pnew->show_gstate = pnew;
+ pgs->level++;
+ if_debug2('g', "[g]gsave -> 0x%lx, level = %d\n",
+ (ulong)pnew, pgs->level);
+ return 0;
+}
+
+/* Save the graphics state for a 'save'. */
+/* We cut the stack below the new gstate, and return the old one. */
+#ifdef DPNEXT
+/* In addition to an ordinary gsave, we un-share the view clip path. */
+#endif
+int
+gs_gsave_for_save(gs_state *pgs, gs_state **psaved)
+{ int code;
+#ifdef DPNEXT
+ gx_clip_path *new_cpath =
+ gs_alloc_struct(pgs->memory, gx_clip_path, &st_clip_path,
+ "gs_gsave_for_save(view_clip path)");
+ gx_clip_path *old_cpath = pgs->view_clip->path;
+
+ if ( new_cpath == 0 )
+ return_error(gs_error_VMerror);
+ code = gs_gsave(pgs);
+ if ( code < 0 ) {
+ gs_free_object(pgs->memory, new_cpath,
+ "gs_gsave_for_save(view_clip path)");
+ return code;
+ }
+ *new_cpath = *old_cpath;
+ gx_cpath_share(new_cpath);
+ pgs->saved->saved_view_clip = old_cpath;
+ pgs->view_clip->path = new_cpath;
+#else
+ code = gs_gsave(pgs);
+ if ( code < 0 )
+ return code;
+#endif
+ /* Cut the stack so we can't grestore past here. */
+ *psaved = pgs->saved;
+ pgs->saved = 0;
+ return code;
+}
+
+/* Restore the graphics state. */
+int
+gs_grestore(gs_state *pgs)
+{ gs_state *saved = pgs->saved;
+ void *pdata = pgs->client_data;
+ void *sdata;
+
+ if_debug2('g', "[g]grestore 0x%lx, level was %d\n",
+ (ulong)saved, pgs->level);
+ if ( !saved ) /* shouldn't happen */
+ return gs_gsave(pgs);
+ sdata = saved->client_data;
+ if ( saved->pattern_cache == 0 )
+ saved->pattern_cache = pgs->pattern_cache;
+ /* Swap back the client data pointers. */
+ pgs->client_data = sdata;
+ saved->client_data = pdata;
+ if ( pdata != 0 && sdata != 0 )
+ gstate_copy_client_data(pgs, pdata, sdata, copy_for_grestore);
+ gstate_free_contents(pgs);
+ *pgs = *saved;
+ if ( pgs->show_gstate == saved )
+ pgs->show_gstate = pgs;
+ gs_free_object(pgs->memory, saved, "gs_grestore");
+ if ( pgs->saved )
+ return 0;
+ return gs_gsave(pgs);
+}
+
+/* Restore the graphics state for a 'restore', splicing the old stack */
+/* back on. Note that we actually do 2 grestores. */
+#ifdef DPNEXT
+/* In addition to an ordinary grestore, we restore the view clip path. */
+#endif
+int
+gs_grestore2_for_restore(gs_state *pgs, gs_state *saved)
+{ int code;
+
+ /* Check that the caller has done a grestoreall. */
+ if ( pgs->saved == 0 || pgs->saved->saved != 0 )
+ return_error(gs_error_Fatal);
+#ifdef DPNEXT
+ { gx_clip_path *cpath = pgs->view_clip->path;
+ gx_clip_path *saved_cpath = saved->saved_view_clip;
+
+ gx_cpath_release(cpath);
+ if ( saved )
+ { pgs->view_clip->path = saved_cpath;
+ gs_free_object(pgs->memory, cpath,
+ "grestore2_for_restore(view clip path)");
+ saved->saved_view_clip = 0;
+ }
+ else
+ { gx_cpath_init(cpath, pgs->memory);
+ cpath->rule = 0;
+ }
+ }
+#endif
+ pgs->saved->saved = saved;
+ code = gs_grestore(pgs);
+ if ( code < 0 )
+ return code;
+ return gs_grestore(pgs);
+}
+
+
+/* Restore to the bottommost graphics state. Also clear */
+/* the halftone caches, so stale pointers don't survive a restore. */
+int
+gs_grestoreall(gs_state *pgs)
+{ int code;
+ if ( !pgs->saved ) /* shouldn't happen */
+ return gs_gsave(pgs);
+ while ( pgs->saved->saved )
+ { int code = gs_grestore(pgs);
+ if ( code < 0 )
+ return code;
+ }
+ code = gs_grestore(pgs);
+ if ( code < 0 )
+ return code;
+ gx_ht_clear_cache(pgs->ht_cache);
+ if ( pgs->pattern_cache )
+ (*pgs->pattern_cache->free_all)(pgs->pattern_cache);
+ return code;
+}
+
+/* Allocate and return a new graphics state. */
+gs_state *
+gs_gstate(gs_state *pgs)
+{ return gs_state_copy(pgs, pgs->memory);
+}
+gs_state *
+gs_state_copy(gs_state *pgs, gs_memory_t *mem)
+{ gs_state *pnew;
+
+#if 0 /****************/
+ if ( mem == pgs->memory )
+#endif /****************/
+ gstate_share_paths(pgs);
+ pnew = gstate_clone(pgs, mem, "gs_gstate", copy_for_gstate);
+ if ( pnew == 0 )
+ return 0;
+ pnew->saved = 0;
+ /*
+ * Prevent dangling references from the show_gstate pointer. If
+ * this context is its own show_gstate, set the pointer in the clone
+ * to point to the clone; otherwise, set the pointer in the clone to
+ * 0, and let gs_setgstate fix it up.
+ */
+ pnew->show_gstate =
+ (pgs->show_gstate == pgs ? pnew : 0);
+ return pnew;
+}
+
+/* Copy one previously allocated graphics state to another. */
+int
+gs_copygstate(gs_state *pto, const gs_state *pfrom)
+{ return gstate_copy(pto, pfrom, copy_for_copygstate, "gs_copygstate");
+}
+
+/* Copy the current graphics state to a previously allocated one. */
+int
+gs_currentgstate(gs_state *pto, const gs_state *pgs)
+{ gstate_share_paths(pgs);
+ return gstate_copy(pto, pgs, copy_for_currentgstate, "gs_currentgstate");
+}
+
+/* Restore the current graphics state from a previously allocated one. */
+int
+gs_setgstate(gs_state *pgs, const gs_state *pfrom)
+{ /*
+ * The implementation is the same as currentgstate,
+ * except we must preserve the saved pointer, the level,
+ * and possibly the show_gstate.
+ */
+ gs_state *saved_show = pgs->show_gstate;
+ int level = pgs->level;
+ int code = gstate_copy(pgs, pfrom, copy_for_setgstate, "gs_setgstate");
+
+ if ( code < 0 )
+ return code;
+ pgs->level = level;
+ pgs->show_gstate =
+ (pgs->show_gstate == pfrom ? pgs : saved_show);
+ return 0;
+}
+
+/* Get the allocator pointer of a graphics state. */
+/* This is provided only for the interpreter */
+/* and for color space implementation. */
+gs_memory_t *
+gs_state_memory(const gs_state *pgs)
+{ return pgs->memory;
+}
+
+/* Get the saved pointer of the graphics state. */
+/* This is provided only for Level 2 grestore. */
+gs_state *
+gs_state_saved(const gs_state *pgs)
+{ return pgs->saved;
+}
+
+/* Swap the saved pointer of the graphics state. */
+/* This is provided only for save/restore. */
+gs_state *
+gs_state_swap_saved(gs_state *pgs, gs_state *new_saved)
+{ gs_state *saved = pgs->saved;
+ pgs->saved = new_saved;
+ return saved;
+}
+
+/* Swap the memory pointer of the graphics state. */
+/* This is provided only for the interpreter. */
+gs_memory_t *
+gs_state_swap_memory(gs_state *pgs, gs_memory_t *mem)
+{ gs_memory_t *memory = pgs->memory;
+ pgs->memory = mem;
+ return memory;
+}
+
+/* ------ Operations on components ------ */
+
+/* Reset most of the graphics state */
+int
+gs_initgraphics(gs_state *pgs)
+{ int code;
+ gs_initmatrix(pgs);
+ if ( (code = gs_newpath(pgs)) < 0 ||
+ (code = gs_initclip(pgs)) < 0 ||
+ (code = gs_setlinewidth(pgs, 1.0)) < 0 ||
+ (code = gs_setlinecap(pgs, gs_cap_butt)) < 0 ||
+ (code = gs_setlinejoin(pgs, gs_join_miter)) < 0 ||
+ (code = gs_setdash(pgs, (float *)0, 0, 0.0)) < 0 ||
+ (gs_setdashadapt(pgs, false),
+ (code = gs_setdotlength(pgs, 0.0, false))) < 0 ||
+ (code = gs_setgray(pgs, 0.0)) < 0 ||
+ (code = gs_setmiterlimit(pgs, 10.0)) < 0
+ )
+ return code;
+ gs_init_rop(pgs);
+ return 0;
+}
+
+/* setfilladjust */
+int
+gs_setfilladjust(gs_state *pgs, floatp adjust_x, floatp adjust_y)
+{
+#define adjust_fill_adjust(v)\
+ if ( v < 0 ) v = 0; else if ( v > 0.5 ) v = 0.5
+ adjust_fill_adjust(adjust_x);
+ pgs->fill_adjust.x = float2fixed(adjust_x);
+ adjust_fill_adjust(adjust_y);
+ pgs->fill_adjust.y = float2fixed(adjust_y);
+ return 0;
+}
+
+/* currentfilladjust */
+int
+gs_currentfilladjust(const gs_state *pgs, gs_point *adjust)
+{ adjust->x = fixed2float(pgs->fill_adjust.x);
+ adjust->y = fixed2float(pgs->fill_adjust.y);
+ return 0;
+}
+
+/* setlimitclamp */
+void
+gs_setlimitclamp(gs_state *pgs, bool clamp)
+{ pgs->clamp_coordinates = clamp;
+}
+
+/* currentlimitclamp */
+bool
+gs_currentlimitclamp(const gs_state *pgs)
+{ return pgs->clamp_coordinates;
+}
+
+/* ------ Internal routines ------ */
+
+/* Allocate a gstate and its contents. */
+private gs_state *
+gstate_alloc(gs_memory_t *mem, client_name_t cname)
+{ gs_state *pgs =
+ gs_alloc_struct(mem, gs_state, &st_gs_state, cname);
+ gs_state_contents *cont =
+ gs_alloc_struct(mem, gs_state_contents, &st_gs_state_contents, cname);
+ gs_color_space *pcs =
+ gs_alloc_struct(mem, gs_color_space, &st_color_space, cname);
+
+ if ( pgs == 0 || cont == 0 || pcs == 0 )
+ { gs_free_object(mem, pcs, cname);
+ gs_free_object(mem, cont, cname);
+ gs_free_object(mem, pgs, cname);
+ return 0;
+ }
+ pgs->memory = mem;
+ pgs->contents = cont;
+ pgs->color_space = pcs;
+ return pgs;
+}
+
+/* Set the contents pointers of a gstate. */
+private void
+gstate_set_contents(gs_state *pgs, gs_state_contents *cont)
+{ pgs->contents = cont;
+#define gset(element)\
+ pgs->element = &cont->element;
+ gset(path);
+ gset(clip_path);
+ gset(ccolor);
+ gset(dev_color);
+#undef gset
+}
+
+/* Copy the dash pattern from one gstate to another. */
+private int
+gstate_copy_dash(gs_state *pto, const gs_state *pfrom)
+{ return gs_setdash(pto, pfrom->line_params.dash.pattern,
+ pfrom->line_params.dash.pattern_size,
+ pfrom->line_params.dash.offset);
+}
+
+/* Clone an existing graphics state. */
+/* Return 0 if the allocation fails. */
+/* The client is responsible for calling gx_[c]path_share on */
+/* whichever of the old and new paths is appropriate. */
+/* If reason is for_gsave, the clone refers to the old contents, */
+/* and we switch the old state to refer to the new contents. */
+private gs_state *
+gstate_clone(gs_state *pfrom, gs_memory_t *mem, client_name_t cname,
+ gs_state_copy_reason_t reason)
+{ gs_state_contents *cfrom = pfrom->contents;
+ gs_color_space *csfrom = pfrom->color_space;
+ gs_state *pgs = gstate_alloc(mem, cname);
+ gs_state_contents *cont;
+ gs_color_space *pcs;
+
+ if ( pgs == 0 )
+ return 0;
+ cont = pgs->contents;
+ pcs = pgs->color_space;
+ /* Increment references from gstate object. */
+ *pgs = *pfrom;
+ /* Copy the dash pattern if necessary. */
+ if ( pgs->line_params.dash.pattern )
+ { int code;
+ pgs->line_params.dash.pattern = 0; /* force allocation */
+ code = gstate_copy_dash(pgs, pfrom);
+ if ( code < 0 )
+ goto fail;
+ }
+ if ( pgs->client_data != 0 )
+ { void *pdata = pgs->client_data =
+ (*pgs->client_procs.alloc)(mem);
+ if ( pdata == 0 ||
+ gstate_copy_client_data(pgs, pdata, pfrom->client_data, reason) < 0
+ )
+ goto fail;
+ }
+ rc_increment(pgs->set_transfer.colored.gray);
+ rc_increment(pgs->set_transfer.colored.red);
+ rc_increment(pgs->set_transfer.colored.green);
+ rc_increment(pgs->set_transfer.colored.blue);
+ rc_increment(pgs->halftone);
+ rc_increment(pgs->dev_ht);
+ rc_increment(pgs->cie_render);
+ rc_increment(pgs->black_generation);
+ rc_increment(pgs->undercolor_removal);
+ rc_increment(pgs->cie_joint_caches);
+ if ( reason == copy_for_gsave )
+ { float *dfrom = pfrom->line_params.dash.pattern;
+ float *dto = pgs->line_params.dash.pattern;
+
+ gstate_set_contents(pgs, cfrom);
+ pgs->color_space = csfrom;
+ pgs->line_params.dash.pattern = dfrom;
+ gstate_set_contents(pfrom, cont);
+ pfrom->color_space = pcs;
+ pfrom->line_params.dash.pattern = dto;
+ }
+ else
+ { gstate_set_contents(pgs, cont);
+ pgs->color_space = pcs;
+ }
+ *cont = *cfrom;
+ *pcs = *csfrom;
+ cs_adjust_counts(pgs, 1);
+#ifdef DPNEXT
+ rc_increment(pgs->view_clip);
+#endif
+ return pgs;
+fail: gs_free_object(mem, pgs->line_params.dash.pattern, cname);
+ gs_free_object(mem, pcs, cname);
+ gs_free_object(mem, cont, cname);
+ gs_free_object(mem, pgs, cname);
+ return 0;
+}
+
+/* Release the composite parts of a graphics state, */
+/* but not the state itself. */
+private void
+gstate_free_contents(gs_state *pgs)
+{ gs_memory_t *mem = pgs->memory;
+ static const char cname[] = "gstate_free_contents";
+ gx_device_halftone *pdht = pgs->dev_ht;
+#define rcdecr(element)\
+ rc_decrement(pgs->element, cname)
+
+ gx_path_release(pgs->path);
+ gx_cpath_release(pgs->clip_path);
+ rcdecr(cie_joint_caches);
+ rcdecr(set_transfer.colored.gray);
+ rcdecr(set_transfer.colored.blue);
+ rcdecr(set_transfer.colored.green);
+ rcdecr(set_transfer.colored.red);
+ rcdecr(undercolor_removal);
+ rcdecr(black_generation);
+ rcdecr(cie_render);
+ if ( pdht != 0 && pdht->rc.ref_count == 1 )
+ { /* Make sure we don't leave dangling pointers in the cache. */
+ gx_ht_cache *pcache = pgs->ht_cache;
+
+ if ( pcache->order.bits == pdht->order.bits ||
+ pcache->order.levels == pdht->order.levels
+ )
+ gx_ht_clear_cache(pcache);
+ gx_device_halftone_release(pdht, pdht->rc.memory);
+ }
+ rcdecr(dev_ht);
+ rcdecr(halftone);
+#ifdef DPNEXT
+ rcdecr(view_clip);
+#endif
+ cs_adjust_counts(pgs, -1);
+ if ( pgs->client_data != 0 )
+ (*pgs->client_procs.free)(pgs->client_data, mem);
+ gs_free_object(mem, pgs->line_params.dash.pattern, cname);
+ gs_free_object(mem, pgs->color_space, cname);
+ gs_free_object(mem, pgs->contents, cname);
+#undef rcdecr
+}
+
+/*
+ * Mark both the old and new paths as shared when copying a gstate off-stack.
+ * If the old path was previously shared, we must search up
+ * the graphics state stack so we can mark its original ancestor
+ * as shared, because the off-stack copy defeats the one-bit
+ * reference count.
+ */
+private void
+gstate_share_paths(const gs_state *pgs)
+{ gx_path *ppath = pgs->path;
+ gx_clip_path *pcpath = pgs->clip_path;
+
+ if ( ppath->shares_segments )
+ { const gs_state *pcur;
+ const gs_state *prev;
+ const subpath *first;
+ for ( pcur = pgs, first = ppath->first_subpath;
+ (prev = pcur->saved) != 0 &&
+ prev->path->first_subpath == first;
+ pcur = prev
+ )
+ if ( !prev->path->shares_segments )
+ { gx_path_share(prev->path);
+ break;
+ }
+ }
+ else
+ gx_path_share(ppath);
+ /*
+ * If the clip path is a rectangle, free its path representation
+ * rather than copying it.
+ */
+ if ( pcpath->list.count <= 1 && pcpath->segments_valid )
+ { gx_path_release(&pcpath->path);
+ pcpath->segments_valid = false;
+ }
+ if ( pcpath->path.shares_segments )
+ { const gs_state *pcur;
+ const gs_state *prev;
+ const subpath *first;
+ for ( pcur = pgs, first = pcpath->path.first_subpath;
+ (prev = pcur->saved) != 0 &&
+ prev->clip_path->path.first_subpath == first;
+ pcur = prev
+ )
+ if ( !prev->clip_path->path.shares_segments )
+ { gx_cpath_share(prev->clip_path);
+ break;
+ }
+ }
+ if ( pcpath->shares_list )
+ { const gs_state *pcur;
+ const gs_state *prev;
+ const gx_clip_rect *head;
+ for ( pcur = pgs, head = pcpath->list.head;
+ (prev = pcur->saved) != 0 &&
+ prev->clip_path->list.head == head;
+ pcur = prev
+ )
+ if ( !prev->clip_path->shares_list )
+ { gx_cpath_share(prev->clip_path);
+ break;
+ }
+ }
+ gx_cpath_share(pcpath);
+}
+
+/* Copy one gstate to another. */
+private int
+gstate_copy(gs_state *pto, const gs_state *pfrom,
+ gs_state_copy_reason_t reason, client_name_t cname)
+{ gs_state_contents *cto = pto->contents;
+ gs_color_space *csto = pto->color_space;
+
+ /* Copy the dash pattern if necessary. */
+ if ( pfrom->line_params.dash.pattern || pto->line_params.dash.pattern )
+ { int code = gstate_copy_dash(pto, pfrom);
+ if ( code < 0 )
+ return 0;
+ }
+ /* It's OK to decrement the counts before incrementing them, */
+ /* because anything that is going to survive has a count of */
+ /* at least 2 (pto and somewhere else) initially. */
+ /* Handle references from contents. */
+ cs_adjust_counts(pto, -1);
+ gx_path_release(pto->path);
+ gx_cpath_release(pto->clip_path);
+ *cto = *pfrom->contents;
+ *csto = *pfrom->color_space;
+ cs_adjust_counts(pto, 1);
+ gx_path_share(pto->path);
+ gx_cpath_share(pto->clip_path);
+ /* Handle references from gstate object. */
+#define rccopy(element)\
+ rc_pre_assign(pto->element, pfrom->element, cname)
+ rccopy(cie_joint_caches);
+ rccopy(set_transfer.colored.gray);
+ rccopy(set_transfer.colored.blue);
+ rccopy(set_transfer.colored.green);
+ rccopy(set_transfer.colored.red);
+ rccopy(undercolor_removal);
+ rccopy(black_generation);
+ rccopy(cie_render);
+ rccopy(dev_ht);
+ rccopy(halftone);
+ { struct gx_pattern_cache_s *pcache = pto->pattern_cache;
+ void *pdata = pto->client_data;
+ gs_memory_t *mem = pto->memory;
+ gs_state *saved = pto->saved;
+ float *pattern = pto->line_params.dash.pattern;
+
+ *pto = *pfrom;
+ pto->client_data = pdata;
+ pto->memory = mem;
+ pto->saved = saved;
+ pto->line_params.dash.pattern = pattern;
+ if ( pto->pattern_cache == 0 )
+ pto->pattern_cache = pcache;
+ if ( pfrom->client_data != 0 )
+ { /* We need to break 'const' here. */
+ gstate_copy_client_data((gs_state *)pfrom, pdata,
+ pfrom->client_data, reason);
+ }
+ }
+ gstate_set_contents(pto, cto);
+ pto->color_space = csto;
+#ifdef DPNEXT
+ rccopy(view_clip);
+#endif
+#undef rccopy
+ pto->show_gstate =
+ (pfrom->show_gstate == pfrom ? pto : 0);
+ return 0;
+}
diff --git a/gs/src/gsstate.h b/gs/src/gsstate.h
new file mode 100644
index 000000000..ce119fbdc
--- /dev/null
+++ b/gs/src/gsstate.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsstate.h */
+/* Public graphics state API */
+
+#ifndef gsstate_INCLUDED
+# define gsstate_INCLUDED
+
+/* Opaque type for a graphics state */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+/* Initial allocation and freeing */
+gs_state *gs_state_alloc(P1(gs_memory_t *)); /* 0 if fails */
+int gs_state_free(P1(gs_state *));
+
+/* Initialization, saving, restoring, and copying */
+int gs_gsave(P1(gs_state *)),
+ gs_grestore(P1(gs_state *)),
+ gs_grestoreall(P1(gs_state *));
+int gs_gsave_for_save(P2(gs_state *, gs_state **)),
+ gs_grestore2_for_restore(P2(gs_state *, gs_state *));
+gs_state *gs_gstate(P1(gs_state *));
+gs_state *gs_state_copy(P2(gs_state *, gs_memory_t *));
+int gs_copygstate(P2(gs_state * /*to*/, const gs_state * /*from*/)),
+ gs_currentgstate(P2(gs_state * /*to*/, const gs_state * /*from*/)),
+ gs_setgstate(P2(gs_state * /*to*/, const gs_state * /*from*/));
+int gs_initgraphics(P1(gs_state *));
+
+/* Device control */
+#include "gsdevice.h"
+
+/* Line parameters and quality */
+#include "gsline.h"
+
+/* Color and gray */
+#include "gscolor.h"
+
+/* Halftone screen */
+#include "gsht.h"
+#include "gscsel.h"
+int gs_setscreenphase(P4(gs_state *, int, int, gs_color_select_t));
+int gs_currentscreenphase(P3(const gs_state *, gs_int_point *,
+ gs_color_select_t));
+#define gs_sethalftonephase(pgs, px, py)\
+ gs_setscreenphase(pgs, px, py, gs_color_select_all)
+#define gs_currenthalftonephase(pgs, ppt)\
+ gs_currentscreenphase(pgs, ppt, 0)
+int gx_imager_setscreenphase(P4(gs_imager_state *, int, int,
+ gs_color_select_t));
+
+/* Miscellaneous */
+int gs_setfilladjust(P3(gs_state *, floatp, floatp));
+int gs_currentfilladjust(P2(const gs_state *, gs_point *));
+void gs_setlimitclamp(P2(gs_state *, bool));
+bool gs_currentlimitclamp(P1(const gs_state *));
+
+#endif /* gsstate_INCLUDED */
diff --git a/gs/src/gsstruct.h b/gs/src/gsstruct.h
new file mode 100644
index 000000000..7c69eb71e
--- /dev/null
+++ b/gs/src/gsstruct.h
@@ -0,0 +1,672 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsstruct.h */
+/* Definitions for Ghostscript modules that define allocatable structures */
+/* Requires gstypes.h */
+
+#ifndef gsstruct_INCLUDED
+# define gsstruct_INCLUDED
+
+/*
+ * Ghostscript structures are defined with names of the form (gs_)xxx_s,
+ * with a corresponding typedef of the form (gs_)xxx or (gs_)xxx_t.
+ * By extension, the structure descriptor is named st_[gs_]xxx.
+ * (Note that the descriptor name may omit the gs_ even if the type has it.)
+ * Structure descriptors are always allocated statically and are
+ * always const; they may be either public or private.
+ *
+ * In order to ensure that there is a descriptor for each structure type,
+ * we require, by convention, that the following always appear together
+ * if the structure is defined in a .h file:
+ * - The definition of the structure xxx_s;
+ * - If the descriptor is public, an extern_st(st_xxx);
+ * - The definition of a macro public_st_xxx() or private_st_xxx()
+ * that creates the actual descriptor.
+ * This convention makes the descriptor visible (if public) to any module
+ * that can see the structure definition. This is more liberal than
+ * we would like, but it is a reasonable compromise between restricting
+ * visibility and keeping all the definitional elements of a structure
+ * together. We require that there be no other externs for (public)
+ * structure descriptors; if the definer of a structure wants to make
+ * available the ability to create an instance but does not want to
+ * expose the structure definition, it must export a creator procedure.
+ *
+ * Because of bugs in some compilers' bookkeeping for undefined structure
+ * types, any file that uses extern_st must include gsstruct.h.
+ * (If it weren't for these bugs, the definition of extern_st could
+ * go in gsmemory.h.)
+ */
+#define extern_st(st) extern const gs_memory_struct_type_t st
+/*
+ * If the structure is defined in a .c file, we require that the following
+ * appear together:
+ * - The definition of the structure xxx_s;
+ * - The gs_private_st_xxx macro that creates the descriptor.
+ * Note that we only allow this if the structure is completely private
+ * to a single file. Again, the file must export a creator procedure
+ * if it wants external clients to be able to create instances.
+ *
+ * Some structures are embedded inside others. In order to be able to
+ * construct the composite pointer enumeration procedures, for such
+ * structures we must define not only the st_xxx descriptor, but also
+ * a st_xxx_max_ptrs constant that gives the maximum number of pointers
+ * the enumeration procedure will return. This is an unfortunate consequence
+ * of the method we have chosen for implementing pointer enumeration.
+ *
+ * Some structures may exist as elements of homogenous arrays.
+ * In order to be able to enumerate and relocate such arrays, we adopt
+ * the convention that the structure representing an element must be
+ * distinguished from the structure per se, and the name of the element
+ * structure always ends with "_element". Element structures cannot be
+ * embedded in other structures.
+ *
+ * Note that the definition of the xxx_s structure may be separate from
+ * the typedef for the type xxx(_t). This still allows us to have full
+ * structure type abstraction.
+ *
+ * Descriptor definitions are not required for structures to which
+ * no traceable pointers from garbage-collectable space will ever exist.
+ * For example, the struct that defines structure types themselves does not
+ * require a descriptor.
+ */
+
+/* An opaque type for an object header. */
+#ifndef obj_header_DEFINED
+# define obj_header_DEFINED
+typedef struct obj_header_s obj_header_t;
+#endif
+
+/*
+ * A descriptor for an object (structure) type.
+ */
+typedef struct struct_shared_procs_s struct_shared_procs_t;
+struct gs_memory_struct_type_s {
+ uint ssize;
+ struct_name_t sname;
+
+ /* ------ Procedures shared among many structure types. ------ */
+ /* Note that this pointer is usually 0. */
+
+ const struct_shared_procs_t _ds *shared;
+
+ /* ------ Procedures specific to this structure type. ------ */
+ /* Note that these procedures may be 0. */
+
+ /* Clear the marks of a structure. */
+
+#define struct_proc_clear_marks(proc)\
+ void proc(P2(void /*obj_header_t*/ *pre, uint size))
+ struct_proc_clear_marks((*clear_marks));
+
+ /* Enumerate the pointers in a structure. */
+
+#define struct_proc_enum_ptrs(proc)\
+ gs_ptr_type_t proc(P4(void /*obj_header_t*/ *ptr, uint size, uint index,\
+ const void **pep))
+ struct_proc_enum_ptrs((*enum_ptrs));
+
+ /* Relocate all the pointers in this structure. */
+
+#define struct_proc_reloc_ptrs(proc)\
+ void proc(P3(void /*obj_header_t*/ *ptr, uint size, gc_state_t *gcst))
+ struct_proc_reloc_ptrs((*reloc_ptrs));
+
+ /*
+ * Finalize this structure just before freeing it.
+ * Finalization procedures must not allocate or resize
+ * any objects in any space managed by the allocator,
+ * and must not assume that any objects in such spaces
+ * referenced by this structure still exist. However,
+ * finalization procedures may free such objects, and
+ * may allocate, free, and reference objects allocated
+ * in other ways, such as objects allocated with malloc
+ * by libraries.
+ */
+
+#define struct_proc_finalize(proc)\
+ void proc(P1(void /*obj_header_t*/ *ptr))
+ struct_proc_finalize((*finalize));
+
+};
+#define struct_type_name_string(pstype) ((const char *)((pstype)->sname))
+/* Default pointer processing */
+struct_proc_enum_ptrs(gs_no_struct_enum_ptrs);
+struct_proc_reloc_ptrs(gs_no_struct_reloc_ptrs);
+/* Standard relocation procedures */
+ptr_proc_reloc(gs_reloc_struct_ptr, void /*obj_header_t*/);
+void gs_reloc_string(P2(gs_string *, gc_state_t *));
+void gs_reloc_const_string(P2(gs_const_string *, gc_state_t *));
+
+/* Define a 'type' descriptor for free blocks. */
+extern_st(st_free);
+
+/* Define a type descriptor for byte objects. */
+extern_st(st_bytes);
+
+/* Define type descriptors for elements and arrays of const strings. */
+#define private_st_const_string()\
+ gs_private_st_composite(st_const_string, gs_const_string, "gs_const_string",\
+ const_string_enum_ptrs, const_string_reloc_ptrs)
+extern_st(st_const_string_element);
+#define public_st_const_string_element()\
+ gs_public_st_element(st_const_string_element, gs_const_string,\
+ "gs_const_string[]", const_string_elt_enum_ptrs,\
+ const_string_elt_reloc_ptrs, st_const_string)
+
+/* ================ Macros for defining structure types ================ */
+
+#define public_st public const gs_memory_struct_type_t
+#define private_st private const gs_memory_struct_type_t
+
+/* -------------- Simple structures (no internal pointers). -------------- */
+
+#define gs__st_simple(scope_st, stname, stype, sname)\
+ scope_st stname = { sizeof(stype), sname, 0, 0, 0, 0, 0 }
+#define gs_public_st_simple(stname, stype, sname)\
+ gs__st_simple(public_st, stname, stype, sname)
+#define gs_private_st_simple(stname, stype, sname)\
+ gs__st_simple(private_st, stname, stype, sname)
+
+/* ---------------- Structures with explicit procedures. ---------------- */
+
+ /* Complex structures with their own clear_marks, */
+ /* enum, reloc, and finalize procedures. */
+
+#define gs__st_complex_only(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)\
+ scope_st stname = { sizeof(stype), sname, 0, pclear, penum, preloc, pfinal }
+#define gs_public_st_complex_only(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex_only(public_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_private_st_complex_only(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex_only(private_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+
+#define gs__st_complex(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)\
+ private struct_proc_clear_marks(pclear);\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ private struct_proc_finalize(pfinal);\
+ gs__st_complex_only(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_public_st_complex(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex(public_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_private_st_complex(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex(private_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+
+ /* Composite structures with their own enum and reloc procedures. */
+
+#define gs__st_composite(scope_st, stname, stype, sname, penum, preloc)\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, 0)
+#define gs_public_st_composite(stname, stype, sname, penum, preloc)\
+ gs__st_composite(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_composite(stname, stype, sname, penum, preloc)\
+ gs__st_composite(private_st, stname, stype, sname, penum, preloc)
+
+ /* Composite structures with finalization. */
+
+#define gs__st_composite_final(scope_st, stname, stype, sname, penum, preloc, pfinal)\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ private struct_proc_finalize(pfinal);\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_composite_final(stname, stype, sname, penum, preloc, pfinal)\
+ gs__st_composite_final(public_st, stname, stype, sname, penum, preloc, pfinal)
+#define gs_private_st_composite_final(stname, stype, sname, penum, preloc, pfinal)\
+ gs__st_composite_final(private_st, stname, stype, sname, penum, preloc, pfinal)
+
+ /* Composite structures with enum and reloc procedures */
+ /* already declared. */
+
+#define gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, 0)
+#define gs_public_st_composite_only(stname, stype, sname, penum, preloc)\
+ gs__st_composite_only(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_composite_only(stname, stype, sname, penum, preloc)\
+ gs__st_composite_only(private_st, stname, stype, sname, penum, preloc)
+
+/* ---------------- Special kinds of structures ---------------- */
+
+ /* Element structures, for use in arrays of structures. */
+ /* Note that these require that the underlying structure's */
+ /* enum_ptrs procedure always return the same number of pointers. */
+
+#define gs__st_element(scope_st, stname, stype, sname, penum, preloc, basest)\
+ private ENUM_PTRS_BEGIN_PROC(penum) {\
+ uint count = size / (uint)sizeof(stype);\
+ if ( count == 0 ) return 0;\
+ return (*basest.enum_ptrs)((char *)vptr + (index % count) * sizeof(stype),\
+ sizeof(stype), index / count, pep);\
+ } ENUM_PTRS_END_PROC\
+ private RELOC_PTRS_BEGIN(preloc) {\
+ uint count = size / (uint)sizeof(stype);\
+ for ( ; count; count--, vptr = (char *)vptr + sizeof(stype) )\
+ (*basest.reloc_ptrs)(vptr, sizeof(stype), gcst);\
+ } RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_element(stname, stype, sname, penum, preloc, basest)\
+ gs__st_element(public_st, stname, stype, sname, penum, preloc, basest)
+#define gs_private_st_element(stname, stype, sname, penum, preloc, basest)\
+ gs__st_element(private_st, stname, stype, sname, penum, preloc, basest)
+
+ /* A "structure" just consisting of a pointer. */
+ /* Note that in this case only, stype is a pointer type. */
+
+#define gs__st_ptr(scope_st, stname, stype, sname, penum, preloc)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ case 0: *pep = (const void *)*(stype *)vptr; return ptr_struct_type;\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ *(stype *)vptr = gs_reloc_struct_ptr((const void *)*(stype *)vptr, gcst);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptr(stname, stype, sname, penum, preloc)\
+ gs__st_ptr(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_ptr(stname, stype, sname, penum, preloc)\
+ gs__st_ptr(private_st, stname, stype, sname, penum, preloc)
+
+/* ---------------- Ordinary structures ---------------- */
+
+/*
+ * The simplest kind of composite structure is one with a fixed set of
+ * pointers, each of which points to a struct. We provide macros for
+ * defining this kind of structure conveniently, either all at once in
+ * the structure definition macro, or using the following template:
+
+ENUM_PTRS_BEGIN(xxx_enum_ptrs) return 0;
+ ... ENUM_PTR(i, xxx, elt); ...
+ENUM_PTRS_END
+RELOC_PTRS_BEGIN(xxx_reloc_ptrs) ;
+ ... RELOC_PTR(xxx, elt) ...
+RELOC_PTRS_END
+
+ */
+/*
+ * We have to pull the 'private' outside the ENUM_PTRS_BEGIN and
+ * RELOC_PTRS_BEGIN macros because of a bug in the Borland C++ preprocessor.
+ * We also have to make sure there is more on the line after these
+ * macros, so as not to confuse ansi2knr.
+ */
+#ifdef __PROTOTYPES__
+# define ENUM_PTRS_BEGIN_PROC(proc)\
+ gs_ptr_type_t proc(void *vptr, uint size, uint index, const void **pep)
+#else
+# define ENUM_PTRS_BEGIN_PROC(proc)\
+ gs_ptr_type_t proc(vptr, size, index, pep) void *vptr; uint size; uint index; const void **pep;
+#endif
+#define ENUM_PTRS_BEGIN(proc)\
+ ENUM_PTRS_BEGIN_PROC(proc) { switch ( index ) { default:
+#define ENUM_PTR(i, typ, elt)\
+ case i: ENUM_RETURN_PTR(typ, elt)
+#define ENUM_RETURN_PTR(typ, elt)\
+ ENUM_RETURN(((typ *)vptr)->elt)
+#define ENUM_RETURN(ptr)\
+ do { *pep = (const void *)(ptr); return ptr_struct_type; } while (0)
+#define ENUM_STRING_PTR(i, typ, elt)\
+ case i: ENUM_RETURN_STRING_PTR(typ, elt)
+#define ENUM_RETURN_STRING_PTR(typ, elt)\
+ do { *pep = (const void *)&((typ *)vptr)->elt; return ptr_string_type; } while (0)
+#define ENUM_CONST_STRING_PTR(i, typ, elt)\
+ case i: ENUM_RETURN_CONST_STRING_PTR(typ, elt)
+#define ENUM_RETURN_CONST_STRING_PTR(typ, elt)\
+ do { *pep = (const void *)&((typ *)vptr)->elt; return ptr_const_string_type; } while (0)
+#define ENUM_PTRS_END\
+ } /* mustn't fall through! */ ENUM_PTRS_END_PROC }
+#define ENUM_PTRS_END_PROC /* */
+#ifdef __PROTOTYPES__
+# define RELOC_PTRS_BEGIN(proc)\
+ void proc(void *vptr, uint size, gc_state_t *gcst) {
+#else
+# define RELOC_PTRS_BEGIN(proc)\
+ void proc(vptr, size, gcst) void *vptr; uint size; gc_state_t *gcst; {
+#endif
+#define RELOC_PTR(typ, elt)\
+ ((typ *)vptr)->elt =\
+ gs_reloc_struct_ptr((const void *)((const typ *)vptr)->elt, gcst)
+/* Relocate a pointer that points to a known offset within an object. */
+/* OFFSET is for byte offsets, TYPED_OFFSET is for element offsets. */
+#define RELOC_OFFSET_PTR(typ, elt, offset)\
+ ((typ *)vptr)->elt = (void *)\
+ ((char *)gs_reloc_struct_ptr((char *)((typ *)vptr)->elt - (offset), gcst) +\
+ (offset))
+#define RELOC_TYPED_OFFSET_PTR(typ, elt, offset)\
+ (((typ *)vptr)->elt = (void *)\
+ gs_reloc_struct_ptr(((typ *)vptr)->elt - (offset), gcst),\
+ ((typ *)vptr)->elt += (offset))
+#define RELOC_STRING_PTR(typ, elt)\
+ gs_reloc_string(&((typ *)vptr)->elt, gcst)
+#define RELOC_CONST_STRING_PTR(typ, elt)\
+ gs_reloc_const_string(&((typ *)vptr)->elt, gcst)
+#define RELOC_PTRS_END\
+ }
+
+/*
+ * Boilerplate for clear_marks procedures.
+ */
+#ifdef __PROTOTYPES__
+# define CLEAR_MARKS_PROC(proc)\
+ void proc(void *vptr, uint size)
+#else
+# define CLEAR_MARKS_PROC(proc)\
+ void proc(vptr, size) void *vptr; uint size;
+#endif
+
+/* ---------------- Structures with a fixed set of pointers ---------------- */
+
+ /* Structures with 1 pointer. */
+
+#define gs__st_ptrs1(scope_st, stname, stype, sname, penum, preloc, e1)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_ptrs1(public_st, stname, stype, sname, penum, preloc, e1)
+#define gs_private_st_ptrs1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_ptrs1(private_st, stname, stype, sname, penum, preloc, e1)
+
+ /* Structures with 1 pointer and 1 string. */
+
+#define gs__st_ptrs1_strings1(scope_st, stname, stype, sname, penum, preloc, e1, e2)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1); ENUM_STRING_PTR(1,stype,e2);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1); RELOC_STRING_PTR(stype,e2);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs1_strings1(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs1_strings1(public_st, stname, stype, sname, penum, preloc, e1, e2)
+#define gs_private_st_ptrs1_strings1(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs1_strings1(private_st, stname, stype, sname, penum, preloc, e1, e2)
+
+ /* Structures with 2 pointers. */
+
+#define gs__st_ptrs2(scope_st, stname, stype, sname, penum, preloc, e1, e2)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs2(public_st, stname, stype, sname, penum, preloc, e1, e2)
+#define gs_private_st_ptrs2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs2(private_st, stname, stype, sname, penum, preloc, e1, e2)
+
+ /* Structures with 3 pointers. */
+
+#define gs__st_ptrs3(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs3(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs3(public_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+#define gs_private_st_ptrs3(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs3(private_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+
+ /* Structures with 4 pointers. */
+
+#define gs__st_ptrs4(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTR(3,stype,e4);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTR(stype,e4);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs4(stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ gs__st_ptrs4(public_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)
+#define gs_private_st_ptrs4(stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ gs__st_ptrs4(private_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)
+
+ /* Structures with 5 pointers. */
+
+#define gs__st_ptrs5(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTR(3,stype,e4); ENUM_PTR(4,stype,e5);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTR(stype,e4); RELOC_PTR(stype,e5);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs5(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ gs__st_ptrs5(public_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)
+#define gs_private_st_ptrs5(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ gs__st_ptrs5(private_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)
+
+/* ---------------- Suffix subclasses ---------------- */
+
+/*
+ * Boilerplate for suffix subclasses. Special subclasses constructed
+ * 'by hand' may use this also.
+ */
+#define ENUM_PREFIX(supst, n)\
+ return (*supst.enum_ptrs)(vptr,size,index-(n),pep)
+#define RELOC_PREFIX(supst)\
+ (*supst.reloc_ptrs)(vptr,size,gcst)
+
+ /* Suffix subclasses with no additional pointers. */
+
+#define gs__st_suffix_add0(scope_st, stname, stype, sname, penum, preloc, supstname)\
+ private ENUM_PTRS_BEGIN_PROC(penum) {\
+ return (*supstname.enum_ptrs)(vptr, size, index, pep);\
+ } ENUM_PTRS_END_PROC\
+ private RELOC_PTRS_BEGIN(preloc) {\
+ (*supstname.reloc_ptrs)(vptr, size, gcst);\
+ } RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_suffix_add0(stname, stype, sname, penum, preloc, supstname)\
+ gs__st_suffix_add0(public_st, stname, stype, sname, penum, preloc, supstname)
+#define gs_private_st_suffix_add0(stname, stype, sname, penum, preloc, supstname)\
+ gs__st_suffix_add0(private_st, stname, stype, sname, penum, preloc, supstname)
+
+ /* Suffix subclasses with no additional pointers and finalization. */
+ /* This is a hack -- subclasses should inherit finalization, */
+ /* but that would require a superclass pointer in the descriptor, */
+ /* which would perturb things too much right now. */
+
+#define gs__st_suffix_add0_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname)\
+ private ENUM_PTRS_BEGIN_PROC(penum) {\
+ return (*supstname.enum_ptrs)(vptr, size, index, pep);\
+ } ENUM_PTRS_END_PROC\
+ private RELOC_PTRS_BEGIN(preloc) {\
+ (*supstname.reloc_ptrs)(vptr, size, gcst);\
+ } RELOC_PTRS_END\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_suffix_add0_final(stname, stype, sname, penum, preloc, pfinal, supstname)\
+ gs__st_suffix_add0_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname)
+#define gs_private_st_suffix_add0_final(stname, stype, sname, penum, preloc, pfinal, supstname)\
+ gs__st_suffix_add0_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname)
+
+ /* Suffix subclasses with 1 additional pointer. */
+
+#define gs__st_suffix_add1(scope_st, stname, stype, sname, penum, preloc, supstname, e1)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,1);\
+ ENUM_PTR(0,stype,e1);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_suffix_add1(stname, stype, sname, penum, preloc, supstname, e1)\
+ gs__st_suffix_add1(public_st, stname, stype, sname, penum, preloc, supstname, e1)
+#define gs_private_st_suffix_add1(stname, stype, sname, penum, preloc, supstname, e1)\
+ gs__st_suffix_add1(private_st, stname, stype, sname, penum, preloc, supstname, e1)
+
+ /* Suffix subclasses with 1 additional pointer and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add1_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,1);\
+ ENUM_PTR(0,stype,e1);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1);\
+ RELOC_PTRS_END\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_suffix_add1_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ gs__st_suffix_add1_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)
+#define gs_private_st_suffix_add1_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ gs__st_suffix_add1_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)
+
+ /* Suffix subclasses with 2 additional pointers. */
+
+#define gs__st_suffix_add2(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,2);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_suffix_add2(stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ gs__st_suffix_add2(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2)
+#define gs_private_st_suffix_add2(stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ gs__st_suffix_add2(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2)
+
+ /* Suffix subclasses with 2 additional pointers and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add2_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,2);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2);\
+ RELOC_PTRS_END\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_suffix_add2_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ gs__st_suffix_add2_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)
+#define gs_private_st_suffix_add2_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ gs__st_suffix_add2_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)
+
+ /* Suffix subclasses with 3 additional pointers. */
+
+#define gs__st_suffix_add3(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,3);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_suffix_add3(stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ gs__st_suffix_add3(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)
+#define gs_private_st_suffix_add3(stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ gs__st_suffix_add3(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)
+
+ /* Suffix subclasses with 3 additional pointers and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add3_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,3);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTRS_END\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_suffix_add3_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ gs__st_suffix_add3_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)
+#define gs_private_st_suffix_add3_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ gs__st_suffix_add3_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)
+
+ /* Suffix subclasses with 4 additional pointers. */
+
+#define gs__st_suffix_add4(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_PREFIX(supstname,4);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2); ENUM_PTR(2,stype,e3);\
+ ENUM_PTR(3,stype,e4);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_PREFIX(supstname);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2); RELOC_PTR(stype,e3);\
+ RELOC_PTR(stype,e4);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_suffix_add4(stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ gs__st_suffix_add4(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)
+#define gs_private_st_suffix_add4(stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ gs__st_suffix_add4(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)
+
+/* ---------------- General subclasses ---------------- */
+
+/*
+ * Boilerplate for general subclasses.
+ */
+#define ENUM_SUPER(stype, supst, member, n)\
+ return (*supst.enum_ptrs)(&((stype *)vptr)->member, sizeof(((stype *)vptr)->member),\
+ index-(n), pep)
+#define RELOC_SUPER(stype, supst, member)\
+ (*supst.reloc_ptrs)(&((stype *)vptr)->member, sizeof(((stype *)vptr)->member), gcst)
+
+ /* General subclasses with no additional pointers. */
+
+#define gs__st_ptrs_add0(scope_st, stname, stype, sname, penum, preloc, supstname, member)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_SUPER(stype,supstname,member,0);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_SUPER(stype,supstname,member);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs_add0(stname, stype, sname, penum, preloc, supstname, member)\
+ gs__st_ptrs_add0(public_st, stname, stype, sname, penum, preloc, supstname, member)
+#define gs_private_st_ptrs_add0(stname, stype, sname, penum, preloc, supstname, member)\
+ gs__st_ptrs_add0(private_st, stname, stype, sname, penum, preloc, supstname, member)
+
+ /* General subclasses with 1 additional pointer. */
+
+#define gs__st_ptrs_add1(scope_st, stname, stype, sname, penum, preloc, supstname, member, e1)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_SUPER(stype,supstname,member,1);\
+ ENUM_PTR(0,stype,e1);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_SUPER(stype,supstname,member);\
+ RELOC_PTR(stype,e1);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs_add1(stname, stype, sname, penum, preloc, supstname, member, e1)\
+ gs__st_ptrs_add1(public_st, stname, stype, sname, penum, preloc, supstname, member, e1)
+#define gs_private_st_ptrs_add1(stname, stype, sname, penum, preloc, supstname, member, e1)\
+ gs__st_ptrs_add1(private_st, stname, stype, sname, penum, preloc, supstname, member, e1)
+
+ /* General subclasses with 2 additional pointers. */
+
+#define gs__st_ptrs_add2(scope_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ private ENUM_PTRS_BEGIN(penum) ENUM_SUPER(stype,supstname,member,2);\
+ ENUM_PTR(0,stype,e1); ENUM_PTR(1,stype,e2);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) RELOC_SUPER(stype,supstname,member);\
+ RELOC_PTR(stype,e1); RELOC_PTR(stype,e2);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptrs_add2(stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ gs__st_ptrs_add2(public_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)
+#define gs_private_st_ptrs_add2(stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ gs__st_ptrs_add2(private_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)
+
+#endif /* gsstruct_INCLUDED */
diff --git a/gs/src/gstext.icx b/gs/src/gstext.icx
new file mode 100644
index 000000000..79f62da5f
--- /dev/null
+++ b/gs/src/gstext.icx
@@ -0,0 +1,48 @@
+0000010001002020100000000000e802
+00001600000028000000200000004000
+00000100040000000000800200000000
+00000000000000000000000000000000
+00000000800000800000008080008000
+00008000800080800000808080004040
+40000000ff0000ff000000ffff00ff00
+0000ff00ff00ffff0000ffffff001111
+11111111111111111111111111111111
+11111111111111111111111111111111
+1bbbb111bbb111bbb11111b111111111
+1b111b1b111b1b111b11111111111111
+1b111b1b111b1b111b1111b111111111
+1b111b1b111b1b111b1111b111111111
+1bbbb111bbb111bbb11111b111111111
+1b11111111111111111111b111111111
+1b11111111111111111111b111111111
+11111111111111111111111111110000
+00fffffffffffffffff0000000000000
+000ffffffffffff0f000000000000000
+0000ffffffffffff0000000000000000
+00000ffffffffffff000000f000000ff
+000ff0fffffffffff00ffffff000000f
+ffff0fffffffffff0ffffffff0000fff
+fffff0fffffffffffffffffffff00000
+fffffffffffffffffffff000ff0000ff
+f000fffffffffffffffff0000ff000f0
+0000ffffffffffffffff000000000000
+00000ffffffffffff0f0000000000000
+0000000fff0ff00fff00000000000000
+0000000ff0fff00fff00000000000000
+0000000000ffffffff00000000000000
+0000000000ffffffff00000000000000
+0000000000ff0f0ff000000000000000
+00000000000fffff0000000000000000
+00000000000ffff00000000000000000
+0000000000ffff000000000000000000
+000000000ffff0000000000000000000
+0000000000ff00000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+000000000000f80000fffc0001fffe00
+07efcc00020780000003800000010000
+0000800000018000003086000079df00
+00ffff8001ffffc001ffffe001fffff8
+01fffff803fffff807fffffc0ffffff8
+1ffffff03ffffff87ffffffcffff
diff --git a/gs/src/gstype1.c b/gs/src/gstype1.c
new file mode 100644
index 000000000..efae286e5
--- /dev/null
+++ b/gs/src/gstype1.c
@@ -0,0 +1,588 @@
+/* Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gstype1.c */
+/* Adobe Type 1 charstring interpreter */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/*
+ * Define whether to always do Flex segments as curves.
+ * This is only an issue because some old Adobe DPS fonts
+ * seem to violate the Flex specification in a way that requires this.
+ * We changed this from 1 to 0 in release 5.02: if it causes any
+ * problems, we'll implement a more sophisticated test.
+ */
+#define ALWAYS_DO_FLEX_AS_CURVE 0
+
+/* ------ Main interpreter ------ */
+
+/* Define a pointer to the charstring interpreter stack. */
+typedef fixed _ss *cs_ptr;
+
+/*
+ * Continue interpreting a Type 1 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+private int
+gs_type1_charstring_interpret(gs_type1_state *pcis,
+ const gs_const_string *str, int *pindex)
+{ gs_font_type1 *pfont = pcis->pfont;
+ gs_type1_data *pdata = &pfont->data;
+ bool encrypted = pdata->lenIV >= 0;
+ gs_op1_state s;
+ fixed cstack[ostack_size];
+#define cs0 cstack[0]
+#define ics0 fixed2int_var(cs0)
+#define cs1 cstack[1]
+#define ics1 fixed2int_var(cs1)
+#define cs2 cstack[2]
+#define ics2 fixed2int_var(cs2)
+#define cs3 cstack[3]
+#define ics3 fixed2int_var(cs3)
+#define cs4 cstack[4]
+#define ics4 fixed2int_var(cs4)
+#define cs5 cstack[5]
+#define ics5 fixed2int_var(cs5)
+ cs_ptr csp;
+#define clear csp = cstack - 1
+ ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ register const byte *cip;
+ register crypt_state state;
+ register int c;
+ int code = 0;
+ fixed ftx = pcis->origin.x, fty = pcis->origin.y;
+
+ switch ( pcis->init_done )
+ {
+ case -1:
+ break;
+ case 0:
+ gs_type1_finish_init(pcis, &s); /* sets sfc, ptx, pty, origin */
+ ftx = pcis->origin.x, fty = pcis->origin.y;
+ break;
+ default /*case 1*/:
+ ptx = pcis->position.x;
+ pty = pcis->position.y;
+ sfc = pcis->fc;
+ }
+ sppath = pcis->path;
+ s.pcis = pcis;
+ init_cstack(cstack, csp, pcis);
+
+ if ( str == 0 )
+ goto cont;
+ ipsp->char_string = *str;
+ cip = str->data;
+call: state = crypt_charstring_seed;
+ if ( encrypted )
+ { int skip = pdata->lenIV;
+ /* Skip initial random bytes */
+ for ( ; skip > 0; ++cip, --skip )
+ decrypt_skip_next(*cip, state);
+ }
+ goto top;
+cont: cip = ipsp->ip;
+ state = ipsp->dstate;
+top: for ( ; ; )
+ { uint c0 = *cip++;
+
+ charstring_next(c0, state, c, encrypted);
+ if ( c >= c_num1 )
+ {
+ /* This is a number, decode it and push it on the stack. */
+
+ if ( c < c_pos2_0 )
+ { /* 1-byte number */
+ decode_push_num1(csp, c);
+ }
+ else if ( c < cx_num4 )
+ { /* 2-byte number */
+ decode_push_num2(csp, c, cip, state, encrypted);
+ }
+ else if ( c == cx_num4 )
+ { /* 4-byte number */
+ long lw;
+
+ decode_num4(lw, cip, state, encrypted);
+ *++csp = int2fixed(lw);
+ if ( lw != fixed2long(*csp) )
+ return_error(gs_error_rangecheck);
+ }
+ else /* not possible */
+ return_error(gs_error_invalidfont);
+pushed: if_debug3('1', "[1]%d: (%d) %f\n",
+ (int)(csp - cstack), c, fixed2float(*csp));
+ continue;
+ }
+
+#ifdef DEBUG
+ if ( gs_debug['1'] )
+ { static const char *c1names[] =
+ { char1_command_names };
+ if ( c1names[c] == 0 )
+ dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
+ else
+ dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
+ c1names[c]);
+ }
+#endif
+ switch ( (char_command)c )
+ {
+#define cnext clear; goto top
+#define inext goto top
+
+ /* Commands with identical functions in Type 1 and Type 2, */
+ /* except for 'escape'. */
+
+ case c_undef0:
+ case c_undef2:
+ case c_undef17:
+ return_error(gs_error_invalidfont);
+ case c_callsubr:
+ c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
+ code = (*pdata->subr_proc)
+ (pfont, c, false, &ipsp[1].char_string);
+ if ( code < 0 )
+ return_error(code);
+ --csp;
+ ipsp->ip = cip, ipsp->dstate = state;
+ ++ipsp;
+ cip = ipsp->char_string.data;
+ goto call;
+ case c_return:
+ --ipsp;
+ goto cont;
+ case c_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ case cx_hstem:
+ apply_path_hints(pcis, false);
+ type1_hstem(pcis, cs0, cs1);
+ cnext;
+ case cx_vstem:
+ apply_path_hints(pcis, false);
+ type1_vstem(pcis, cs0, cs1);
+ cnext;
+ case cx_vmoveto:
+ cs1 = cs0;
+ cs0 = 0;
+ accum_y(cs1);
+move: /* cs0 = dx, cs1 = dy for hint checking. */
+ if ( (pcis->hint_next != 0 || path_is_drawing(sppath)) &&
+ pcis->flex_count == flex_max
+ )
+ apply_path_hints(pcis, true);
+ code = gx_path_add_point(sppath, ptx, pty);
+ goto cc;
+ case cx_rlineto:
+ accum_xy(cs0, cs1);
+line: /* cs0 = dx, cs1 = dy for hint checking. */
+ code = gx_path_add_line(sppath, ptx, pty);
+cc: if ( code < 0 )
+ return code;
+pp: if_debug2('1', "[1]pt=(%g,%g)\n",
+ fixed2float(ptx), fixed2float(pty));
+ cnext;
+ case cx_hlineto:
+ accum_x(cs0);
+ cs1 = 0;
+ goto line;
+ case cx_vlineto:
+ cs1 = cs0;
+ cs0 = 0;
+ accum_y(cs1);
+ goto line;
+ case cx_rrcurveto:
+ code = gs_op1_rrcurveto(&s, cs0, cs1, cs2, cs3, cs4, cs5);
+ goto cc;
+ case cx_endchar:
+ if ( pcis->seac_base >= 0 )
+ { /* We just finished the accent of a seac. */
+ /* Do the base character. */
+ gs_const_string bstr;
+ int bchar = pcis->seac_base;
+ pcis->seac_base = -1;
+ /* Restore the coordinate system origin */
+ pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0;
+ sppath->position.x = pcis->position.x = ftx;
+ sppath->position.y = pcis->position.y = fty;
+ pcis->os_count = 0; /* clear */
+ /* Clear the ipstack, in case the accent ended */
+ /* inside a subroutine. */
+ pcis->ips_count = 1;
+ /* Remove any accent hints. */
+ reset_stem_hints(pcis);
+ /* Ask the caller to provide a new string. */
+ code = (*pdata->seac_proc)(pfont, bchar, &bstr);
+ if ( code != 0 )
+ { *pindex = bchar;
+ return code;
+ }
+ /* Continue with the supplied string. */
+ clear;
+ ptx = ftx, pty = fty;
+ ipsp = &pcis->ipstack[0];
+ ipsp->char_string = bstr;
+ cip = bstr.data;
+ goto call;
+ }
+ /* This is a real endchar. Handle it below. */
+ return gs_type1_endchar(pcis);
+ case cx_rmoveto:
+ accum_xy(cs0, cs1);
+ goto move;
+ case cx_hmoveto:
+ accum_x(cs0);
+ cs1 = 0;
+ goto move;
+ case cx_vhcurveto:
+ { gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+ accum_y(cs0);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(cs1, cs2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_x(cs3);
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+ } goto cc;
+ case cx_hvcurveto:
+ { gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+ accum_x(cs0);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(cs1, cs2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_y(cs3);
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+ } goto cc;
+
+ /* Commands only recognized in Type 1 charstrings, */
+ /* plus 'escape'. */
+
+ case c1_closepath:
+ code = gs_op1_closepath(&s);
+ apply_path_hints(pcis, true);
+ goto cc;
+ case c1_hsbw:
+ gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0);
+rsbw: /* Give the caller the opportunity to intervene. */
+ pcis->os_count = 0; /* clear */
+ ipsp->ip = cip, ipsp->dstate = state;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ /* If we aren't in a seac, do nothing else now; */
+ /* finish_init will take care of the rest. */
+ if ( pcis->init_done < 0 )
+ { /* Finish init when we return. */
+ pcis->init_done = 0;
+ }
+ else
+ { /* Do accumulate the side bearing now. */
+ accum_xy(pcis->lsb.x, pcis->lsb.y);
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+ }
+ return type1_result_sbw;
+ case cx_escape:
+ charstring_next(*cip, state, c, encrypted); ++cip;
+#ifdef DEBUG
+ if ( gs_debug['1'] && c < char1_extended_command_count )
+ { static const char *ce1names[] =
+ { char1_extended_command_names };
+ if ( ce1names[c] == 0 )
+ dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
+ else
+ dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
+ ce1names[c]);
+ }
+#endif
+ switch ( (char1_extended_command)c )
+ {
+ case ce1_dotsection:
+ pcis->dotsection_flag ^=
+ (dotsection_in ^ dotsection_out);
+ cnext;
+ case ce1_vstem3:
+ apply_path_hints(pcis, false);
+ if ( !pcis->vstem3_set && pcis->fh.use_x_hints )
+ { center_vstem(pcis, pcis->lsb.x + cs2, cs3);
+ /* Adjust the current point */
+ /* (center_vstem handles everything else). */
+ ptx += pcis->vs_offset.x;
+ pty += pcis->vs_offset.y;
+ pcis->vstem3_set = true;
+ }
+ type1_vstem(pcis, cs0, cs1);
+ type1_vstem(pcis, cs2, cs3);
+ type1_vstem(pcis, cs4, cs5);
+ cnext;
+ case ce1_hstem3:
+ apply_path_hints(pcis, false);
+ type1_hstem(pcis, cs0, cs1);
+ type1_hstem(pcis, cs2, cs3);
+ type1_hstem(pcis, cs4, cs5);
+ cnext;
+ case ce1_seac:
+ { gs_const_string acstr;
+ /* Do the accent now. When it finishes */
+ /* (detected in endchar), do the base character. */
+ pcis->seac_base = ics3;
+ /* Adjust the origin of the coordinate system */
+ /* for the accent (endchar puts it back). */
+ ptx = ftx, pty = fty;
+ pcis->asb_diff = cs0 - pcis->lsb.x;
+ pcis->adxy.x = cs1;
+ pcis->adxy.y = cs2;
+ accum_xy(cs1, cs2);
+ sppath->position.x = pcis->position.x = ptx;
+ sppath->position.y = pcis->position.y = pty;
+ pcis->os_count = 0; /* clear */
+ /* Ask the caller to provide a new string. */
+ code = (*pdata->seac_proc)(pfont, ics4, &acstr);
+ if ( code != 0 )
+ { *pindex = ics4;
+ return code;
+ }
+ /* Continue with the supplied string. */
+ clear;
+ ipsp->char_string = acstr;
+ cip = acstr.data;
+ goto call;
+ }
+ case ce1_sbw:
+ gs_type1_sbw(pcis, cs0, cs1, cs2, cs3);
+ goto rsbw;
+ case ce1_div:
+ csp[-1] = float2fixed((float)csp[-1] / (float)*csp);
+ --csp; goto pushed;
+ case ce1_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+ case ce1_callothersubr:
+ { int num_results;
+#define fpts pcis->flex_points
+ /* We must remember to pop both the othersubr # */
+ /* and the argument count off the stack. */
+ switch ( *pindex = fixed2int_var(*csp) )
+ {
+ case 0:
+ { /* We have to do something really sleazy */
+ /* here, namely, make it look as though */
+ /* the rmovetos never really happened, */
+ /* because we don't want to interrupt */
+ /* the current subpath. */
+ gs_fixed_point ept;
+#if defined(DEBUG) || !ALWAYS_DO_FLEX_AS_CURVE
+ fixed fheight = csp[-4];
+ gs_fixed_point hpt;
+#endif
+
+ if ( pcis->flex_count != 8 )
+ return_error(gs_error_invalidfont);
+ /* Assume the next two opcodes */
+ /* are `pop' `pop'. Unfortunately, some */
+ /* Monotype fonts put these in a Subr, */
+ /* so we can't just look ahead in the */
+ /* opcode stream. */
+ pcis->ignore_pops = 2;
+ csp[-4] = csp[-3] - pcis->asb_diff;
+ csp[-3] = csp[-2];
+ csp -= 3;
+ gx_path_current_point(sppath, &ept);
+ gx_path_add_point(sppath, fpts[0].x, fpts[0].y);
+ sppath->state_flags = /* <--- sleaze */
+ pcis->flex_path_state_flags;
+#if defined(DEBUG) || !ALWAYS_DO_FLEX_AS_CURVE
+ /* Decide whether to do the flex as a curve. */
+ hpt.x = fpts[1].x - fpts[4].x;
+ hpt.y = fpts[1].y - fpts[4].y;
+ if_debug3('1',
+ "[1]flex: d=(%g,%g), height=%g\n",
+ fixed2float(hpt.x), fixed2float(hpt.y),
+ fixed2float(fheight) / 100);
+#endif
+#if !ALWAYS_DO_FLEX_AS_CURVE /* See beginning of file. */
+ if ( any_abs(hpt.x) + any_abs(hpt.y) <
+ fheight / 100
+ )
+ { /* Do the flex as a line. */
+ code = gx_path_add_line(sppath,
+ ept.x, ept.y);
+ }
+ else
+#endif
+ { /* Do the flex as a curve. */
+ code = gx_path_add_curve(sppath,
+ fpts[2].x, fpts[2].y,
+ fpts[3].x, fpts[3].y,
+ fpts[4].x, fpts[4].y);
+ if ( code < 0 )
+ return code;
+ code = gx_path_add_curve(sppath,
+ fpts[5].x, fpts[5].y,
+ fpts[6].x, fpts[6].y,
+ fpts[7].x, fpts[7].y);
+ }
+ }
+ if ( code < 0 )
+ return code;
+ pcis->flex_count = flex_max; /* not inside flex */
+ inext;
+ case 1:
+ gx_path_current_point(sppath, &fpts[0]);
+ pcis->flex_path_state_flags = /* <--- more sleaze */
+ sppath->state_flags;
+ pcis->flex_count = 1;
+ csp -= 2;
+ inext;
+ case 2:
+ if ( pcis->flex_count >= flex_max )
+ return_error(gs_error_invalidfont);
+ gx_path_current_point(sppath,
+ &fpts[pcis->flex_count++]);
+ csp -= 2;
+ inext;
+ case 3:
+ /* Assume the next opcode is a `pop'. */
+ /* See above as to why we don't just */
+ /* look ahead in the opcode stream. */
+ pcis->ignore_pops = 1;
+ replace_stem_hints(pcis);
+ csp -= 2;
+ inext;
+ case 14:
+ num_results = 1;
+blend: { int num_values = fixed2int_var(csp[-1]);
+ int k1 = num_values / num_results - 1;
+ int i, j;
+ cs_ptr base, deltas;
+
+ if ( num_values < num_results ||
+ num_values % num_results != 0
+ )
+ return_error(gs_error_invalidfont);
+ base = csp - 1 - num_values;
+ deltas = base + num_results - 1;
+ for ( j = 0; j < num_results;
+ j++, base++, deltas += k1
+ )
+ for ( i = 1; i <= k1; i++ )
+ *base += deltas[i] *
+ pdata->WeightVector.values[i];
+ csp = base - 1;
+ }
+ pcis->ignore_pops = num_results;
+ inext;
+ case 15:
+ num_results = 2;
+ goto blend;
+ case 16:
+ num_results = 3;
+ goto blend;
+ case 17:
+ num_results = 4;
+ goto blend;
+ case 18:
+ num_results = 6;
+ goto blend;
+ }
+ }
+#undef fpts
+ /* Not a recognized othersubr, */
+ /* let the client handle it. */
+ { int scount = csp - cstack;
+ int n;
+ /* Copy the arguments to the caller's stack. */
+ if ( scount < 1 || csp[-1] < 0 ||
+ csp[-1] > int2fixed(scount - 1)
+ )
+ return_error(gs_error_invalidfont);
+ n = fixed2int_var(csp[-1]);
+ code = (*pdata->push_proc)(pfont, csp - (n + 1), n);
+ if ( code < 0 )
+ return_error(code);
+ scount -= n + 1;
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+ apply_path_hints(pcis, false);
+ /* Exit to caller */
+ ipsp->ip = cip, ipsp->dstate = state;
+ pcis->os_count = scount;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ if ( scount )
+ memcpy(pcis->ostack, cstack, scount * sizeof(fixed));
+ return type1_result_callothersubr;
+ }
+ case ce1_pop:
+ /* Check whether we're ignoring the pops after */
+ /* a known othersubr. */
+ if ( pcis->ignore_pops != 0 )
+ { pcis->ignore_pops--;
+ inext;
+ }
+ ++csp;
+ code = (*pdata->pop_proc)(pfont, csp);
+ if ( code < 0 )
+ return_error(code);
+ goto pushed;
+ case ce1_setcurrentpoint:
+ ptx = ftx, pty = fty;
+ cs0 += pcis->adxy.x;
+ cs1 += pcis->adxy.y;
+ accum_xy(cs0, cs1);
+ goto pp;
+ default:
+ return_error(gs_error_invalidfont);
+ }
+ /*NOTREACHED*/
+
+ /* Fill up the dispatch up to 32. */
+
+ case_c1_undefs:
+ default: /* pacify compiler */
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/* Register the interpreter. */
+void
+gs_gstype1_init(gs_memory_t *mem)
+{ gs_charstring_interpreter[1] = gs_type1_charstring_interpret;
+}
diff --git a/gs/src/gstype1.h b/gs/src/gstype1.h
new file mode 100644
index 000000000..0c23a3894
--- /dev/null
+++ b/gs/src/gstype1.h
@@ -0,0 +1,250 @@
+/* Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gstype1.h */
+/* Client interface to Adobe Type 1 font routines */
+
+#ifndef gstype1_INCLUDED
+# define gstype1_INCLUDED
+
+/* ------ Normal client interface ------ */
+
+#define crypt_charstring_seed 4330
+typedef struct gs_type1_state_s gs_type1_state;
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+#ifndef gs_show_enum_s_DEFINED
+struct gs_show_enum_s;
+#endif
+#ifndef gs_font_type1_DEFINED
+# define gs_font_type1_DEFINED
+typedef struct gs_font_type1_s gs_font_type1;
+#endif
+#ifndef gs_type1_data_s_DEFINED
+struct gs_type1_data_s;
+#endif
+int gs_type1_interp_init(P7(gs_type1_state *pcis, gs_imager_state *pis,
+ gx_path *ppath, const gs_log2_scale_point *pscale,
+ bool charpath_flag, int paint_type,
+ gs_font_type1 *pfont));
+void gs_type1_set_lsb(P2(gs_type1_state *pcis, const gs_point *psbpt));
+void gs_type1_set_width(P2(gs_type1_state *pcis, const gs_point *pwpt));
+/* Backward compatibility */
+#define gs_type1_init(pcis, penum, psbpt, charpath_flag, paint_type, pfont)\
+ (gs_type1_interp_init(pcis, (gs_imager_state *)((penum)->pgs),\
+ (penum)->pgs->path, &(penum)->log2_current_scale,\
+ charpath_flag, paint_type, pfont) |\
+ ((psbpt) == 0 ? 0 : (gs_type1_set_lsb(pcis, psbpt), 0)))
+/*
+ * Continue interpreting a Type 1 CharString. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+#define type1_result_sbw 1 /* allow intervention after [h]sbw */
+#define type1_result_callothersubr 2
+
+int gs_type1_interpret(P3(gs_type1_state *, const gs_const_string *, int *));
+
+/* ------ CharString number representation ------ */
+
+/* Define the representation of integers used by both Type 1 and Type 2. */
+typedef enum {
+
+ /* Values from 32 to 246 represent small integers. */
+ c_num1 = 32,
+#define c_value_num1(ch) ((int)(byte)(ch) - 139)
+
+ /* The next 4 values represent 2-byte positive integers. */
+ c_pos2_0 = 247,
+ c_pos2_1 = 248,
+ c_pos2_2 = 249,
+ c_pos2_3 = 250,
+#define c_value_pos2(c1,c2)\
+ (((int)(byte)((c1) - (int)c_pos2_0) << 8) + (int)(byte)(c2) + 108)
+
+ /* The next 4 values represent 2-byte negative integers. */
+ c_neg2_0 = 251,
+ c_neg2_1 = 252,
+ c_neg2_2 = 253,
+ c_neg2_3 = 254
+#define c_value_neg2(c1,c2)\
+ -(((int)(byte)((c1) - (int)c_neg2_0) << 8) + (int)(byte)(c2) + 108)
+
+} char_num_command;
+
+/* ------ Type 1 & Type 2 CharString representation ------ */
+
+/*
+ * We define both the Type 1 and Type 2 operators here, because they
+ * overlap so much.
+ */
+typedef enum {
+
+ /* Commands with identical functions in Type 1 and Type 2 */
+ /* charstrings. */
+
+ c_undef0 = 0,
+ c_undef2 = 2,
+ c_callsubr = 10,
+ c_return = 11,
+ c_undoc15 = 15, /* An obsolete and undocumented */
+ /* command used in some very old */
+ /* Adobe fonts. */
+ c_undef17 = 17,
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ cx_hstem = 1,
+ cx_vstem = 3,
+ cx_vmoveto = 4,
+ cx_rlineto = 5,
+ cx_hlineto = 6,
+ cx_vlineto = 7,
+ cx_rrcurveto = 8,
+ cx_escape = 12, /* extends the command set */
+ cx_endchar = 14,
+ cx_rmoveto = 21,
+ cx_hmoveto = 22,
+ cx_vhcurveto = 30,
+ cx_hvcurveto = 31,
+
+ cx_num4 = 255, /* 4-byte numbers */
+
+ /* Commands recognized only in Type 1 charstrings. */
+
+ c1_closepath = 9,
+ c1_hsbw = 13,
+
+ /* Commands not recognized in Type 1 charstrings. */
+
+#define case_c1_undefs\
+ case 16: case 18: case 19:\
+ case 20: case 23: case 24:\
+ case 25: case 26: case 27: case 28: case 29
+
+ /* Commands only recognized in Type 2 charstrings. */
+
+ c2_blend = 16,
+ c2_hstemhm = 18,
+ c2_hintmask = 19,
+ c2_cntrmask = 20,
+ c2_vstemhm = 23,
+ c2_rcurveline = 24,
+ c2_rlinecurve = 25,
+ c2_vvcurveto = 26,
+ c2_hhcurveto = 27,
+ c2_shortint = 28,
+ c2_callgsubr = 29
+
+ /* Commands not recognized in Type 2 charstrings. */
+
+#define case_c2_undefs\
+ case 9: case 13
+
+} char_command;
+#define char1_command_names\
+ 0, "hstem", 0, "vstem", "vmoveto",\
+ "rlineto", "hlineto", "vlineto", "rrcurveto", "closepath",\
+ "callsubr", "return", "(escape)", "hsbw", "endchar",\
+ "undoc15", 0, 0, 0, 0,\
+ 0, "rmoveto", "hmoveto", 0, 0,\
+ 0, 0, 0, 0, 0,\
+ "vhcurveto", "hvcurveto"
+#define char2_command_names\
+ 0, "hstem", 0, "vstem", "vmoveto",\
+ "rlineto", "hlineto", "vlineto", "rrcurveto", 0,\
+ "callsubr", "return", "(escape)", 0, "endchar",\
+ "undoc15", "blend", 0, "hstemhm", "hintmask",\
+ "cntrmask", "rmoveto", "hmoveto", "vstemhm", "rcurveline",\
+ "rlinecurve", "vvcurveto", "hhcurveto", "shortint", "callgsubr",\
+ "vhcurveto", "hvcurveto"
+
+/*
+ * Extended (escape) commands in Type 1 charstrings.
+ */
+typedef enum {
+ ce1_dotsection = 0,
+ ce1_vstem3 = 1,
+ ce1_hstem3 = 2,
+ ce1_seac = 6,
+ ce1_sbw = 7,
+ ce1_div = 12,
+ ce1_undoc15 = 15, /* An obsolete and undocumented */
+ /* command used in some very old */
+ /* Adobe fonts. */
+ ce1_callothersubr = 16,
+ ce1_pop = 17,
+ ce1_setcurrentpoint = 33
+} char1_extended_command;
+#define char1_extended_command_count 34
+#define char1_extended_command_names\
+ "dotsection", "vstem3", "hstem3", 0, 0,\
+ 0, "seac", "sbw", 0, 0,\
+ 0, 0, "div", 0, 0,\
+ "undoc15", "callothersubr", "pop", 0, 0,\
+ 0, 0, 0, 0, 0,\
+ 0, 0, 0, 0, 0,\
+ 0, 0, 0, "setcurrentpoint"
+
+/*
+ * Extended (escape) commands in Type 2 charstrings.
+ */
+typedef enum {
+ ce2_and = 3,
+ ce2_or = 4,
+ ce2_not = 5,
+ ce2_store = 8,
+ ce2_abs = 9,
+ ce2_add = 10,
+ ce2_sub = 11,
+ ce2_div = 12, /* same as ce1_div */
+ ce2_load = 13,
+ ce2_neg = 14,
+ ce2_eq = 15,
+ ce2_drop = 18,
+ ce2_put = 20,
+ ce2_get = 21,
+ ce2_ifelse = 22,
+ ce2_random = 23,
+ ce2_mul = 24,
+ ce2_sqrt = 26,
+ ce2_dup = 27,
+ ce2_exch = 28,
+ ce2_index = 29,
+ ce2_roll = 30,
+ ce2_hflex = 34,
+ ce2_flex = 35,
+ ce2_hflex1 = 36,
+ ce2_flex1 = 37
+} char2_extended_command;
+#define char2_extended_command_count 38
+#define char2_extended_command_names\
+ 0, 0, 0, "and", "or",\
+ "not", 0, 0, "store", "abs",\
+ "add", "sub", "div", "load", "neg",\
+ "eq", 0, 0, "drop", 0,\
+ "put", "get", "ifelse", "random", "mul",\
+ 0, "sqrt", "dup", "exch", "index",\
+ "roll", 0, 0, 0, "hflex",\
+ "flex", "hflex1", "flex1"
+
+#endif /* gstype1_INCLUDED */
diff --git a/gs/src/gstype2.c b/gs/src/gstype2.c
new file mode 100644
index 000000000..c7bdc9f04
--- /dev/null
+++ b/gs/src/gstype2.c
@@ -0,0 +1,658 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gstype2.c */
+/* Adobe Type 2 charstring interpreter */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* NOTE: The following are not yet implemented:
+ * Registry items other than 0
+ * Hint and counter masks (but they are parsed correctly)
+ * 'random' operator
+ */
+
+/* Define a pointer to the charstring interpreter stack. */
+typedef fixed _ss *cs_ptr;
+
+/* ------ Internal routines ------ */
+
+/*
+ * Set the character width. This is provided as an optional extra operand
+ * on the stack for the first operator. After setting the width, we remove
+ * the extra operand, and back up the interpreter pointer so we will
+ * re-execute the operator when control re-enters the interpreter.
+ */
+#define check_first_operator(explicit_width)\
+ do {\
+ if ( pcis->init_done < 0 )\
+ { ipsp->ip = cip, ipsp->dstate = state;\
+ return type2_sbw(pcis, csp, cstack, ipsp, explicit_width);\
+ }\
+ } while (0)
+private int near
+type2_sbw(gs_type1_state *pcis, cs_ptr csp, cs_ptr cstack, ip_state *ipsp,
+ bool explicit_width)
+{ fixed wx;
+
+ if ( explicit_width )
+ { wx = cstack[0] + pcis->pfont->data.nominalWidthX;
+ memmove(cstack, cstack + 1, (csp - cstack) * sizeof(*cstack));
+ --csp;
+ }
+ else
+ wx = pcis->pfont->data.defaultWidthX;
+ gs_type1_sbw(pcis, fixed_0, fixed_0, wx, fixed_0);
+ /* Back up the interpretation pointer. */
+ { ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ ipsp->ip--;
+ decrypt_skip_previous(*ipsp->ip, ipsp->dstate);
+ }
+ /* Save the interpreter state. */
+ pcis->os_count = csp + 1 - cstack;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ memcpy(pcis->ostack, cstack, pcis->os_count * sizeof(cstack[0]));
+ if ( pcis->init_done < 0 )
+ { /* Finish init when we return. */
+ pcis->init_done = 0;
+ }
+ return type1_result_sbw;
+}
+private int near
+type2_vstem(gs_type1_state *pcis, cs_ptr csp, cs_ptr cstack)
+{ fixed x = 0;
+ cs_ptr ap;
+
+ apply_path_hints(pcis, false);
+ for ( ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2 )
+ type1_vstem(pcis, x += ap[0], ap[1]);
+ return 0;
+}
+
+/* ------ Main interpreter ------ */
+
+/*
+ * Continue interpreting a Type 2 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is only for compatibility with the Type 1 charstring interpreter.
+ */
+private int
+gs_type2_charstring_interpret(gs_type1_state *pcis,
+ const gs_const_string *str, int *ignore_pindex)
+{ gs_font_type1 *pfont = pcis->pfont;
+ gs_type1_data *pdata = &pfont->data;
+ bool encrypted = pdata->lenIV >= 0;
+ gs_op1_state s;
+ fixed cstack[ostack_size];
+ cs_ptr csp;
+#define clear csp = cstack - 1
+ ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ register const byte *cip;
+ register crypt_state state;
+ register int c;
+ cs_ptr ap;
+ bool vertical;
+ int code = 0;
+ /****** FAKE THE REGISTRY ******/
+ struct { float *values; uint size; } Registry[1];
+ Registry[0].values = pcis->pfont->data.WeightVector.values;
+
+ switch ( pcis->init_done )
+ {
+ case -1:
+ break;
+ case 0:
+ gs_type1_finish_init(pcis, &s); /* sets sfc, ptx, pty, origin */
+ break;
+ default /*case 1*/:
+ ptx = pcis->position.x;
+ pty = pcis->position.y;
+ sfc = pcis->fc;
+ }
+ sppath = pcis->path;
+ s.pcis = pcis;
+ init_cstack(cstack, csp, pcis);
+
+ if ( str == 0 )
+ goto cont;
+ ipsp->char_string = *str;
+ cip = str->data;
+call: state = crypt_charstring_seed;
+ if ( encrypted )
+ { int skip = pdata->lenIV;
+ /* Skip initial random bytes */
+ for ( ; skip > 0; ++cip, --skip )
+ decrypt_skip_next(*cip, state);
+ }
+ goto top;
+cont: cip = ipsp->ip;
+ state = ipsp->dstate;
+top: for ( ; ; )
+ { uint c0 = *cip++;
+
+ charstring_next(c0, state, c, encrypted);
+ if ( c >= c_num1 )
+ {
+ /* This is a number, decode it and push it on the stack. */
+
+ if ( c < c_pos2_0 )
+ { /* 1-byte number */
+ decode_push_num1(csp, c);
+ }
+ else if ( c < cx_num4 )
+ { /* 2-byte number */
+ decode_push_num2(csp, c, cip, state, encrypted);
+ }
+ else if ( c == cx_num4 )
+ { /* 4-byte number */
+ long lw;
+
+ decode_num4(lw, cip, state, encrypted);
+ /* 32-bit numbers are 16:16. */
+ *++csp = arith_rshift(lw, 16 - _fixed_shift);
+ }
+ else /* not possible */
+ return_error(gs_error_invalidfont);
+pushed: if_debug3('1', "[1]%d: (%d) %f\n",
+ (int)(csp - cstack), c, fixed2float(*csp));
+ continue;
+ }
+
+#ifdef DEBUG
+ if ( gs_debug['1'] )
+ { static const char *c2names[] =
+ { char2_command_names };
+ if ( c2names[c] == 0 )
+ dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
+ else
+ dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
+ c2names[c]);
+ }
+#endif
+ switch ( (char_command)c )
+ {
+#define cnext clear; goto top
+
+ /* Commands with identical functions in Type 1 and Type 2, */
+ /* except for 'escape'. */
+
+ case c_undef0:
+ case c_undef2:
+ case c_undef17:
+ return_error(gs_error_invalidfont);
+ case c_callsubr:
+ c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
+ code = (*pdata->subr_proc)
+ (pfont, c, false, &ipsp[1].char_string);
+subr: if ( code < 0 )
+ return_error(code);
+ --csp;
+ ipsp->ip = cip, ipsp->dstate = state;
+ ++ipsp;
+ cip = ipsp->char_string.data;
+ goto call;
+ case c_return:
+ --ipsp;
+ goto cont;
+ case c_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ case cx_hstem:
+ goto hstem;
+ case cx_vstem:
+ goto vstem;
+ case cx_vmoveto:
+ check_first_operator(csp > cstack);
+ accum_y(*csp);
+move: if ( (pcis->hint_next != 0 || path_is_drawing(sppath)) )
+ apply_path_hints(pcis, true);
+ code = gx_path_add_point(sppath, ptx, pty);
+cc: if ( code < 0 )
+ return code;
+ goto pp;
+ case cx_rlineto:
+ for ( ap = cstack; ap + 1 <= csp; ap += 2 )
+ { accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ if ( code < 0 )
+ return code;
+ }
+pp: if_debug2('1', "[1]pt=(%g,%g)\n",
+ fixed2float(ptx), fixed2float(pty));
+ cnext;
+ case cx_hlineto:
+ vertical = false;
+ goto hvl;
+ case cx_vlineto:
+ vertical = true;
+hvl: for ( ap = cstack; ap <= csp; vertical = !vertical, ++ap )
+ { if ( vertical )
+ accum_y(*ap);
+ else
+ accum_x(*ap);
+ code = gx_path_add_line(sppath, ptx, pty);
+ if ( code < 0 )
+ return code;
+ }
+ goto pp;
+ case cx_rrcurveto:
+rrc: for ( ap = cstack; ap + 5 <= csp; ap += 6 )
+ { code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2],
+ ap[3], ap[4], ap[5]);
+ if ( code < 0 )
+ return code;
+ }
+ goto pp;
+ case cx_endchar:
+ /*
+ * This might be the only operator in the charstring.
+ * In this case, there might be a width on the stack.
+ */
+ check_first_operator(csp >= cstack);
+ return gs_type1_endchar(pcis);
+ case cx_rmoveto:
+ check_first_operator(csp > cstack + 1);
+ accum_xy(csp[-1], *csp);
+ goto move;
+ case cx_hmoveto:
+ check_first_operator(csp > cstack);
+ accum_x(*csp);
+ goto move;
+ case cx_vhcurveto:
+ vertical = true;
+ goto hvc;
+ case cx_hvcurveto:
+ vertical = false;
+hvc: for ( ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4 )
+ { gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+
+ if ( vertical )
+ accum_y(ap[0]);
+ else
+ accum_x(ap[0]);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(ap[1], ap[2]);
+ pt2.x = ptx, pt2.y = pty;
+ if ( vertical )
+ { if ( ap + 4 == csp )
+ accum_xy(ap[3], ap[4]);
+ else
+ accum_x(ap[3]);
+ }
+ else
+ { if ( ap + 4 == csp )
+ accum_xy(ap[4], ap[3]);
+ else
+ accum_y(ap[3]);
+ }
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y,
+ pt2.x, pt2.y, ptx, pty);
+ if ( code < 0 )
+ return code;
+ }
+ goto pp;
+
+ /***********************
+ * New Type 2 commands *
+ ***********************/
+
+ case c2_blend:
+ { int n = fixed2int_var(*csp);
+ int num_values = csp - cstack;
+ gs_font_type1 *pfont = pcis->pfont;
+ int k = pfont->data.WeightVector.count;
+ int i, j;
+ cs_ptr base, deltas;
+
+ base = csp - 1 - num_values;
+ deltas = base + n - 1;
+ for ( j = 0; j < n; j++, base++, deltas += k - 1 )
+ for ( i = 1; i < k; i++ )
+ *base += deltas[i] * pfont->data.WeightVector.values[i];
+ }
+ cnext;
+ case c2_hstemhm:
+ pcis->have_hintmask = true;
+hstem: check_first_operator(!((csp - cstack) & 1));
+ apply_path_hints(pcis, false);
+ { fixed x = 0;
+
+ for ( ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2 )
+ type1_hstem(pcis, x += ap[0], ap[1]);
+ }
+ cnext;
+ case c2_hintmask:
+ /*
+ * A hintmask at the beginning of the CharString is
+ * equivalent to vstemhm + hintmask. For simplicity, we use
+ * this interpretation everywhere.
+ */
+ pcis->have_hintmask = true;
+ check_first_operator(!((csp - cstack) & 1));
+ type2_vstem(pcis, csp, cstack);
+ clear;
+ /* (falls through) */
+ case c2_cntrmask:
+ { byte mask[max_total_stem_hints / 8];
+ int i;
+
+ if_debug1('1', "[1]mask(%d)",
+ pcis->vstem_hints.count + pcis->hstem_hints.count);
+ for ( i = 0;
+ i < pcis->vstem_hints.count + pcis->hstem_hints.count;
+ ++cip, i += 8
+ )
+ { charstring_next(*cip, state, mask[i >> 3], encrypted);
+ if_debug1('1', " 0x%02x", mask[i >> 3]);
+ }
+ if_debug0('1', "\n");
+ ipsp->ip = cip;
+ ipsp->dstate = state;
+ }
+ /****** NYI ******/
+ break;
+ case c2_vstemhm:
+ pcis->have_hintmask = true;
+vstem: check_first_operator(!((csp - cstack) & 1));
+ type2_vstem(pcis, csp, cstack);
+ cnext;
+ case c2_rcurveline:
+ for ( ap = cstack; ap + 5 <= csp; ap += 6 )
+ { code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
+ ap[4], ap[5]);
+ if ( code < 0 )
+ return code;
+ }
+ accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ goto cc;
+ case c2_rlinecurve:
+ for ( ap = cstack; ap + 7 <= csp; ap += 2 )
+ { accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ if ( code < 0 )
+ return code;
+ }
+ code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
+ ap[4], ap[5]);
+ goto cc;
+ case c2_vvcurveto:
+ ap = cstack;
+ { int n = csp + 1 - cstack;
+ fixed dxa = (n & 1 ? *ap++ : 0);
+
+ for ( ; ap + 3 <= csp; ap += 4 )
+ { code = gs_op1_rrcurveto(&s, dxa, ap[0], ap[1], ap[2],
+ fixed_0, ap[3]);
+ if ( code < 0 )
+ return code;
+ dxa = 0;
+ }
+ }
+ goto pp;
+ case c2_hhcurveto:
+ ap = cstack;
+ { int n = csp + 1 - cstack;
+ fixed dya = (n & 1 ? *ap++ : 0);
+
+ for ( ; ap + 3 <= csp; ap += 4 )
+ { code = gs_op1_rrcurveto(&s, ap[0], dya, ap[1], ap[2],
+ ap[3], fixed_0);
+ if ( code < 0 )
+ return code;
+ dya = 0;
+ }
+ }
+ goto pp;
+ case c2_shortint:
+ { int c1, c2;
+
+ charstring_next(*cip, state, c1, encrypted); ++cip;
+ charstring_next(*cip, state, c2, encrypted); ++cip;
+ *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2);
+ }
+ goto pushed;
+ case c2_callgsubr:
+ c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
+ code = (*pdata->subr_proc)
+ (pfont, c, true, &ipsp[1].char_string);
+ goto subr;
+ case cx_escape:
+ charstring_next(*cip, state, c, encrypted); ++cip;
+#ifdef DEBUG
+ if ( gs_debug['1'] && c < char2_extended_command_count )
+ { static const char *ce2names[] =
+ { char2_extended_command_names };
+ if ( ce2names[c] == 0 )
+ dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
+ else
+ dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
+ ce2names[c]);
+ }
+#endif
+ switch ( (char2_extended_command)c )
+ {
+ case ce2_and:
+ csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0);
+ --csp; break;
+ case ce2_or:
+ csp[-1] = (csp[-1] | *csp ? fixed_1 : 0);
+ --csp; break;
+ case ce2_not:
+ *csp = (*csp ? 0 : fixed_1);
+ break;
+ case ce2_store:
+ { int i, n = fixed2int_var(*csp);
+ float *to = Registry[fixed2int_var(csp[-3])].values +
+ fixed2int_var(csp[-2]);
+ const fixed *from =
+ pcis->transient_array + fixed2int_var(csp[-1]);
+
+ for ( i = 0; i < n; ++i )
+ to[i] = fixed2float(from[i]);
+ }
+ csp -= 4; break;
+ case ce2_abs:
+ if ( *csp < 0 )
+ *csp = -*csp;
+ break;
+ case ce2_add:
+ csp[-1] += *csp;
+ --csp; break;
+ case ce2_sub:
+ csp[-1] -= *csp;
+ --csp; break;
+ case ce2_div:
+ csp[-1] = float2fixed((double)csp[-1] / *csp);
+ --csp; break;
+ case ce2_load:
+ /* The specification says there is no j (starting index */
+ /* in registry array) argument.... */
+ { int i, n = fixed2int_var(*csp);
+ const float *from = Registry[fixed2int_var(csp[-2])].values;
+ fixed *to =
+ pcis->transient_array + fixed2int_var(csp[-1]);
+
+ for ( i = 0; i < n; ++i )
+ to[i] = float2fixed(from[i]);
+ }
+ csp -= 3; break;
+ case ce2_neg:
+ *csp = -*csp;
+ break;
+ case ce2_eq:
+ csp[-1] = (csp[-1] == *csp ? fixed_1 : 0);
+ --csp; break;
+ case ce2_drop:
+ --csp; break;
+ case ce2_put:
+ pcis->transient_array[fixed2int_var(*csp)] = csp[-1];
+ csp -= 2; break;
+ case ce2_get:
+ *csp = pcis->transient_array[fixed2int_var(*csp)];
+ break;
+ case ce2_ifelse:
+ if ( csp[-1] > *csp )
+ csp[-3] = csp[-2];
+ csp -= 3; break;
+ case ce2_random:
+ ++csp;
+ /****** NYI ******/
+ break;
+ case ce2_mul:
+ { double prod = fixed2float(csp[-1]) * *csp;
+ csp[-1] =
+ (prod > max_fixed ? max_fixed :
+ prod < min_fixed ? min_fixed : prod);
+ }
+ --csp; break;
+ case ce2_sqrt:
+ if ( *csp >= 0 )
+ *csp = float2fixed(sqrt(fixed2float(*csp)));
+ break;
+ case ce2_dup:
+ csp[1] = *csp;
+ ++csp; break;
+ case ce2_exch:
+ { fixed top = *csp;
+ *csp = csp[-1], csp[-1] = top;
+ }
+ break;
+ case ce2_index:
+ *csp =
+ (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]);
+ break;
+ case ce2_roll:
+ { int j = fixed2int_var(*csp);
+ int n = fixed2int_var(csp[-1]);
+ cs_ptr bot;
+
+ csp -= 2;
+ if ( n < 0 || n > csp + 1 - cstack )
+ return_error(gs_error_invalidfont);
+ if ( n == 0 )
+ break;
+ if ( j < 0 )
+ j = n - (-j % n);
+ bot = csp + 1 - n;
+ while ( --j >= 0 )
+ { fixed top = *bot;
+ memmove(bot, bot + 1, (n - 1) * sizeof(fixed));
+ *csp = top;
+ }
+ }
+ break;
+ case ce2_hflex:
+ csp[6] = fixed_half; /* fd/100 */
+ csp[4] = 0, csp[5] = *csp; /* dx6, dy6 */
+ csp[2] = 0, csp[3] = csp[-1]; /* dx5, dy5 */
+ *csp = 0, csp[1] = csp[-2]; /* dx4, dy4 */
+ csp[-2] = csp[-3], csp[-1] = 0; /* dx3, dy3 */
+ csp[-3] = csp[-4], csp[-4] = csp[-5]; /* dx2, dy2 */
+ csp[-5] = 0; /* dy1 */
+ csp += 6; goto flex;
+ case ce2_flex:
+ *csp /= 100; /* fd/100 */
+flex: { fixed x_join = csp[-12] + csp[-10] + csp[-8];
+ fixed y_join = csp[-11] + csp[-9] + csp[-7];
+ fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2];
+ fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1];
+ gs_point join, end;
+
+ if ( (code = gs_distance_transform(fixed2float(x_join),
+ fixed2float(y_join),
+ &ctm_only(pcis->pis),
+ &join)) < 0 ||
+ (code = gs_distance_transform(fixed2float(x_end),
+ fixed2float(y_end),
+ &ctm_only(pcis->pis),
+ &end)) < 0
+ )
+ return code;
+ /*
+ * The distance from the point (U,V) from a line from
+ * (0,0) to (C,D) is
+ * abs(C*V - D*U) / sqrt(C^2 + D^2)
+ * In this case (U,V) is join, and (C,D) is end.
+ */
+ if ( fabs(end.x * join.y - end.y * join.x) >=
+ hypot(end.x, end.y) * fixed2float(*csp) )
+ { /* Do flex as curve. */
+ --csp;
+ goto rrc;
+ }
+ /* Do flex as line. */
+ accum_xy(x_end, y_end);
+ code = gx_path_add_line(sppath, ptx, pty);
+ }
+ cnext;
+ case ce2_hflex1:
+ csp[4] = fixed_half; /* fd/100 */
+ csp[2] = *csp, csp[3] = 0; /* dx6, dy6 */
+ *csp = csp[-2], csp[1] = csp[-1]; /* dx5, dy5 */
+ csp[-2] = csp[-3], csp[-1] = 0; /* dx4, dy4 */
+ csp[-3] = 0; /* dy3 */
+ csp += 4; goto flex;
+ case ce2_flex1:
+ { fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2];
+ fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1];
+
+ if ( any_abs(dx) > any_abs(dy) )
+ csp[1] = -dy; /* d6 is dx6 */
+ else
+ csp[1] = *csp, *csp = -dx; /* d6 is dy6 */
+ }
+ csp[2] = fixed_half; /* fd/100 */
+ csp += 2; goto flex;
+ }
+ break;
+
+ /* Fill up the dispatch up to 32. */
+
+ case_c2_undefs:
+ default: /* pacify compiler */
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/* Register the interpreter. */
+void
+gs_gstype2_init(gs_memory_t *mem)
+{ gs_charstring_interpreter[2] = gs_type2_charstring_interpret;
+}
diff --git a/gs/src/gstype42.c b/gs/src/gstype42.c
new file mode 100644
index 000000000..312bd60e9
--- /dev/null
+++ b/gs/src/gstype42.c
@@ -0,0 +1,444 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gstype42.c */
+/* Type 42 (TrueType) font library routines */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gxfixed.h" /* for gxpath.h */
+#include "gxpath.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "gxistate.h"
+
+/*
+ * This Type 42 / TrueType rasterizer is about as primitive as it can be
+ * and still produce useful output. Here are some things it doesn't handle:
+ * - left side bearings;
+ * and, of course, instructions (hints).
+ */
+
+/* Structure descriptor */
+public_st_gs_font_type42();
+
+/* Set up a pointer to a substring of the font data. */
+/* Free variables: pfont, string_proc. */
+#define access(base, length, vptr)\
+ do {\
+ code = (*string_proc)(pfont, (ulong)(base), length, &vptr);\
+ if ( code < 0 ) return code;\
+ } while (0)
+
+/* Get 2- or 4-byte quantities from a table. */
+#define u8(p) ((uint)((p)[0]))
+#define s8(p) (int)((u8(p) ^ 0x80) - 0x80)
+#define u16(p) (((uint)((p)[0]) << 8) + (p)[1])
+#define s16(p) (int)((u16(p) ^ 0x8000) - 0x8000)
+#define u32(p) (((ulong)u16(p) << 16) + u16((p) + 2))
+#define s32(p) (long)((u32(p) ^ 0x80000000) - 0x80000000)
+
+/* Define the default implementation for getting the outline data for */
+/* a glyph, using indexToLocFormat and the loca and glyf tables. */
+/* Set pglyph->data = 0 if the glyph is empty. */
+private int
+default_get_outline(gs_font_type42 *pfont, uint glyph_index,
+ gs_const_string *pglyph)
+{ int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ const byte *ploca;
+ ulong glyph_start;
+ uint glyph_length;
+ int code;
+
+ if ( pfont->data.indexToLocFormat )
+ { access(pfont->data.loca + glyph_index * 4, 8, ploca);
+ glyph_start = u32(ploca);
+ glyph_length = u32(ploca + 4) - glyph_start;
+ }
+ else
+ { access(pfont->data.loca + glyph_index * 2, 4, ploca);
+ glyph_start = (ulong)u16(ploca) << 1;
+ glyph_length = ((ulong)u16(ploca + 2) << 1) - glyph_start;
+ }
+ pglyph->size = glyph_length;
+ if ( glyph_length == 0 )
+ pglyph->data = 0;
+ else
+ access(pfont->data.glyf + glyph_start, glyph_length, pglyph->data);
+ return 0;
+}
+
+/* Initialize the cached values in a Type 42 font. */
+/* Note that this initializes get_outline as well. */
+int
+gs_type42_font_init(gs_font_type42 *pfont)
+{ int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ const byte *OffsetTable;
+ uint numTables;
+ const byte *TableDirectory;
+ uint i;
+ int code;
+ byte head_box[8];
+
+ access(0, 12, OffsetTable);
+ { static const byte version1_0[4] = {0,1,0,0};
+ if ( memcmp(OffsetTable, version1_0, 4) )
+ return_error(gs_error_invalidfont);
+ }
+ numTables = u16(OffsetTable + 4);
+ access(12, numTables * 16, TableDirectory);
+ for ( i = 0; i < numTables; ++i )
+ { const byte *tab = TableDirectory + i * 16;
+ ulong offset = u32(tab + 8);
+ if ( !memcmp(tab, "glyf", 4) )
+ pfont->data.glyf = offset;
+ else if ( !memcmp(tab, "head", 4) )
+ { const byte *head;
+ access(offset, 54, head);
+ pfont->data.unitsPerEm = u16(head + 18);
+ memcpy(head_box, head + 36, 8);
+ pfont->data.indexToLocFormat = u16(head + 50);
+ }
+ else if ( !memcmp(tab, "hhea", 4) )
+ { const byte *hhea;
+ access(offset, 36, hhea);
+ pfont->data.numLongMetrics = u16(hhea + 34);
+ }
+ else if ( !memcmp(tab, "hmtx", 4) )
+ pfont->data.hmtx = offset,
+ pfont->data.hmtx_length = (uint)u32(tab + 12);
+ else if ( !memcmp(tab, "loca", 4) )
+ pfont->data.loca = offset;
+ }
+ /* If the font doesn't have a valid FontBBox, */
+ /* compute one from the 'head' information. */
+ if ( pfont->FontBBox.p.x >= pfont->FontBBox.q.x ||
+ pfont->FontBBox.p.y >= pfont->FontBBox.q.y
+ )
+ { float upem = pfont->data.unitsPerEm;
+ pfont->FontBBox.p.x = s16(head_box) / upem;
+ pfont->FontBBox.p.y = s16(head_box + 2) / upem;
+ pfont->FontBBox.q.x = s16(head_box + 4) / upem;
+ pfont->FontBBox.q.y = s16(head_box + 6) / upem;
+ }
+ pfont->data.get_outline = default_get_outline;
+ return 0;
+}
+
+/* Get the metrics of a glyph. */
+int
+gs_type42_get_metrics(gs_font_type42 *pfont, uint glyph_index,
+ float psbw[4])
+{ int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ float scale = pfont->data.unitsPerEm;
+ uint widthx;
+ int lsbx;
+ int code;
+
+ { uint num_metrics = pfont->data.numLongMetrics;
+ const byte *hmetrics;
+ if ( glyph_index < num_metrics )
+ { access(pfont->data.hmtx + glyph_index * 4, 4, hmetrics);
+ widthx = u16(hmetrics);
+ lsbx = s16(hmetrics + 2);
+ }
+ else
+ { uint offset = pfont->data.hmtx + (num_metrics - 1) * 4;
+ const byte *lsb;
+ access(offset, 4, hmetrics);
+ widthx = u16(hmetrics);
+ offset += 4 + (glyph_index - num_metrics) * 2;
+ if ( offset >= pfont->data.hmtx_length )
+ offset = pfont->data.hmtx_length - 2;
+ access(offset, 2, lsb);
+ lsbx = s16(lsb);
+ }
+ }
+ psbw[0] = lsbx / scale;
+ psbw[1] = 0;
+ psbw[2] = widthx / scale;
+ psbw[3] = 0;
+ return 0;
+}
+
+/* Define the bits in the glyph flags. */
+#define gf_OnCurve 1
+#define gf_xShort 2
+#define gf_yShort 4
+#define gf_Repeat 8
+#define gf_xPos 16 /* xShort */
+#define gf_xSame 16 /* !xShort */
+#define gf_yPos 32 /* yShort */
+#define gf_ySame 32 /* !yShort */
+
+/* Define the bits in the component glyph flags. */
+#define cg_argsAreWords 1
+#define cg_argsAreXYValues 2
+#define cg_haveScale 8
+#define cg_moreComponents 32
+#define cg_haveXYScale 64
+#define cg_have2x2 128
+
+/* Forward references */
+private int append_outline(P4(uint glyph_index, const gs_matrix_fixed *pmat,
+ gx_path *ppath, gs_font_type42 *pfont));
+
+/* Append a TrueType outline to a path. */
+/* Note that this does not append the final moveto for the width. */
+int
+gs_type42_append(uint glyph_index, gs_imager_state *pis,
+ gx_path *ppath, const gs_log2_scale_point *pscale, bool charpath_flag,
+ int paint_type, gs_font_type42 *pfont)
+{ /*
+ * This is where we should do something about the l.s.b., but I
+ * can't figure out from the TrueType documentation what it should
+ * be.
+ */
+ return append_outline(glyph_index, &pis->ctm, ppath, pfont);
+}
+
+/* Append a simple glyph outline. */
+private int
+append_simple(const byte *glyph, const gs_matrix_fixed *pmat, gx_path *ppath,
+ gs_font_type42 *pfont)
+{ int numContours = s16(glyph);
+ const byte *pends = glyph + 10;
+ const byte *pinstr = pends + numContours * 2;
+ const byte *pflags;
+ uint npoints;
+ const byte *pxc, *pyc;
+ int code;
+
+ if ( numContours == 0 )
+ return 0;
+ /*
+ * It appears that the only way to find the X and Y coordinate
+ * tables is to parse the flags. If this is true, it is an
+ * incredible piece of bad design.
+ */
+ { const byte *pf = pflags = pinstr + 2 + u16(pinstr);
+ uint xbytes = npoints = u16(pinstr - 2) + 1;
+ uint np = npoints;
+
+ while ( np > 0 )
+ { byte flags = *pf++;
+ uint reps = (flags & gf_Repeat ? *pf++ + 1 : 1);
+ if ( !(flags & gf_xShort) )
+ { if ( flags & gf_xSame )
+ xbytes -= reps;
+ else
+ xbytes += reps;
+ }
+ np -= reps;
+ }
+ pxc = pf;
+ pyc = pxc + xbytes;
+ }
+
+ /* Interpret the contours. */
+
+ { uint i, np;
+ gs_fixed_point pt;
+ float scale = pfont->data.unitsPerEm;
+ uint reps = 0;
+ byte flags;
+
+ gs_point_transform2fixed(pmat, 0.0, 0.0, &pt);
+ for ( i = 0, np = 0; i < numContours; ++i )
+ { bool move = true;
+ uint last_point = u16(pends + i * 2);
+ float dx, dy;
+ int off_curve = 0;
+ gs_fixed_point start;
+ gs_fixed_point cpoints[3];
+
+ for ( ; np <= last_point; --reps, ++np )
+ { gs_fixed_point dpt;
+ if ( reps == 0 )
+ { flags = *pflags++;
+ reps = (flags & gf_Repeat ? *pflags++ + 1 : 1);
+ }
+ if ( flags & gf_xShort )
+ dx = (flags & gf_xPos ? *pxc++ : -(int)*pxc++) / scale;
+ else if ( !(flags & gf_xSame) )
+ dx = s16(pxc) / scale, pxc += 2;
+ else
+ dx = 0;
+ if ( flags & gf_yShort )
+ dy = (flags & gf_yPos ? *pyc++ : -(int)*pyc++) / scale;
+ else if ( !(flags & gf_ySame) )
+ dy = s16(pyc) / scale, pyc += 2;
+ else
+ dy = 0;
+ code = gs_distance_transform2fixed(pmat, dx, dy, &dpt);
+ if ( code < 0 )
+ return code;
+ pt.x += dpt.x, pt.y += dpt.y;
+#define control1(xy) cpoints[1].xy
+#define control2(xy) cpoints[2].xy
+#define control3off(xy) ((cpoints[1].xy + pt.xy) / 2)
+#define control4off(xy) ((cpoints[0].xy + 2 * cpoints[1].xy) / 3)
+#define control5off(xy) ((2 * cpoints[1].xy + cpoints[2].xy) / 3)
+#define control6off(xy) ((2 * cpoints[1].xy + pt.xy) / 3)
+#define control7off(xy) ((2 * cpoints[1].xy + start.xy) / 3)
+ if ( move )
+ { if_debug2('1', "[1t]start (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ start = pt;
+ code = gx_path_add_point(ppath, pt.x, pt.y);
+ cpoints[0] = pt;
+ move = false;
+ }
+ else if ( flags & gf_OnCurve )
+ { if_debug2('1', "[1t]ON (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ if ( off_curve )
+ code = gx_path_add_curve(ppath, control4off(x),
+ control4off(y), control6off(x),
+ control6off(y), pt.x, pt.y);
+ else
+ code = gx_path_add_line(ppath, pt.x, pt.y);
+ cpoints[0] = pt;
+ off_curve = 0;
+ }
+ else
+ { if_debug2('1', "[1t]...off (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ switch ( off_curve++ )
+ {
+ default: /* >= 1 */
+ control2(x) = control3off(x);
+ control2(y) = control3off(y);
+ code = gx_path_add_curve(ppath,
+ control4off(x), control4off(y),
+ control5off(x), control5off(y),
+ control2(x), control2(y));
+ cpoints[0] = cpoints[2];
+ off_curve = 1;
+ /* falls through */
+ case 0:
+ cpoints[1] = pt;
+ }
+ }
+ if ( code < 0 )
+ return code;
+ }
+ if ( off_curve )
+ code = gx_path_add_curve(ppath, control4off(x), control4off(y),
+ control7off(x), control7off(y),
+ start.x, start.y);
+ code = gx_path_close_subpath(ppath);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Append a glyph outline. */
+private int
+append_outline(uint glyph_index, const gs_matrix_fixed *pmat, gx_path *ppath,
+ gs_font_type42 *pfont)
+{ gs_const_string glyph_string;
+#define glyph glyph_string.data
+ int numContours;
+ int code;
+
+ code = (*pfont->data.get_outline)(pfont, glyph_index, &glyph_string);
+ if ( code < 0 )
+ return code;
+ if ( glyph == 0 ) /* empty glyph */
+ return 0;
+ numContours = s16(glyph);
+ if ( numContours >= 0 )
+ return append_simple(glyph, pmat, ppath, pfont);
+ if ( numContours != -1 )
+ return_error(gs_error_rangecheck);
+ /* This is a component glyph. Things get messy. */
+ { uint flags;
+ float scale = pfont->data.unitsPerEm;
+
+ glyph += 10;
+ do
+ { uint comp_index = u16(glyph + 2);
+ gs_matrix_fixed mat;
+ gs_matrix scale_mat;
+
+ flags = u16(glyph);
+ glyph += 4;
+ mat = *pmat;
+ if ( flags & cg_argsAreXYValues )
+ { int arg1, arg2;
+ gs_fixed_point pt;
+ if ( flags & cg_argsAreWords )
+ arg1 = s16(glyph), arg2 = s16(glyph + 2), glyph += 4;
+ else
+ arg1 = s8(glyph), arg2 = s8(glyph + 1), glyph += 2;
+ gs_point_transform2fixed(pmat, arg1 / scale,
+ arg2 / scale, &pt);
+ /****** HACK: WE KNOW ABOUT FIXED MATRICES ******/
+ mat.tx = fixed2float(mat.tx_fixed = pt.x);
+ mat.ty = fixed2float(mat.ty_fixed = pt.y);
+ }
+ else
+ { /****** WE DON'T HANDLE POINT MATCHING YET ******/
+ glyph += (flags & cg_argsAreWords ? 4 : 2);
+ }
+#define s2_14(p) (s16(p) / 16384.0)
+ if ( flags & cg_haveScale )
+ { scale_mat.xx = scale_mat.yy = s2_14(glyph);
+ scale_mat.xy = scale_mat.yx = 0;
+ glyph += 2;
+ }
+ else if ( flags & cg_haveXYScale )
+ { scale_mat.xx = s2_14(glyph);
+ scale_mat.yy = s2_14(glyph + 2);
+ scale_mat.xy = scale_mat.yx = 0;
+ glyph += 4;
+ }
+ else if ( flags & cg_have2x2 )
+ { scale_mat.xx = s2_14(glyph);
+ scale_mat.xy = s2_14(glyph + 2);
+ scale_mat.yx = s2_14(glyph + 4);
+ scale_mat.yy = s2_14(glyph + 6);
+ glyph += 8;
+ }
+ else
+ goto no_scale;
+#undef s2_14
+ scale_mat.tx = 0;
+ scale_mat.ty = 0;
+ /* The scale doesn't affect mat.t{x,y}, so we don't */
+ /* need to update the fixed components. */
+ gs_matrix_multiply(&scale_mat, (const gs_matrix *)&mat,
+ (gs_matrix *)&mat);
+no_scale: code = append_outline(comp_index, &mat, ppath, pfont);
+ if ( code < 0 )
+ return code;
+ }
+ while ( flags & cg_moreComponents );
+ }
+ return 0;
+#undef glyph
+}
diff --git a/gs/src/gstypes.h b/gs/src/gstypes.h
new file mode 100644
index 000000000..e8049988d
--- /dev/null
+++ b/gs/src/gstypes.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gstypes.h */
+/* Miscellaneous common types for Ghostscript library */
+
+#ifndef gstypes_INCLUDED
+# define gstypes_INCLUDED
+
+/*
+ * Define a type used internally for unique IDs of various kinds
+ * (primarily, but not exclusively, character and halftone bitmaps).
+ * These IDs bear no relation to any other ID space; we generate them all
+ * ourselves.
+ */
+typedef ulong gs_id;
+#define gs_no_id 0L
+
+/*
+ * Define a sensible representation of a string, as opposed to
+ * the C char * type (which can't store arbitrary data, represent
+ * substrings, or perform concatenation without destroying aliases).
+ */
+typedef struct gs_string_s {
+ byte *data;
+ uint size;
+} gs_string;
+typedef struct gs_const_string_s {
+ const byte *data;
+ uint size;
+} gs_const_string;
+
+/*
+ * Define types for Cartesian points.
+ */
+typedef struct gs_point_s {
+ double x, y;
+} gs_point;
+typedef struct gs_int_point_s {
+ int x, y;
+} gs_int_point;
+
+/*
+ * Define a scale for oversampling. Clients don't actually use this,
+ * but this seemed like the handiest place for it.
+ */
+typedef struct gs_log2_scale_point_s {
+ int x, y;
+} gs_log2_scale_point;
+
+/*
+ * Define types for rectangles in the Cartesian plane.
+ * Note that rectangles are half-open, i.e.: their width is
+ * q.x-p.x and their height is q.y-p.y; they include the points
+ * (x,y) such that p.x<=x<q.x and p.y<=y<q.y.
+ */
+typedef struct gs_rect_s {
+ gs_point p, q; /* origin point, corner point */
+} gs_rect;
+typedef struct gs_int_rect_s {
+ gs_int_point p, q;
+} gs_int_rect;
+
+#endif /* gstypes_INCLUDED */
diff --git a/gs/src/gsuid.h b/gs/src/gsuid.h
new file mode 100644
index 000000000..9baafd114
--- /dev/null
+++ b/gs/src/gsuid.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsuid.h */
+/* Unique id definitions for Ghostscript */
+
+#ifndef gsuid_INCLUDED
+# define gsuid_INCLUDED
+
+/* A unique id (uid) may be either a UniqueID or an XUID. */
+/* (XUIDs are a Level 2 feature.) */
+#ifndef gs_uid_DEFINED
+# define gs_uid_DEFINED
+typedef struct gs_uid_s gs_uid;
+#endif
+struct gs_uid_s {
+ /* id >= 0 is a UniqueID, xvalues is 0. */
+ /* id < 0 is an XUID, size of xvalues is -id. */
+ long id;
+ long *xvalues;
+};
+
+/* A UniqueID of no_UniqueID is an indication that there is no uid. */
+#define no_UniqueID 0x1000000
+#define uid_is_valid(puid)\
+ ((puid)->id != no_UniqueID)
+#define uid_set_invalid(puid)\
+ ((puid)->id = no_UniqueID, (puid)->xvalues = 0)
+#define uid_is_UniqueID(puid)\
+ (((puid)->id & ~0xffffff) == 0)
+#define uid_is_XUID(puid)\
+ ((puid)->id < 0)
+
+/* Initialize a uid. */
+#define uid_set_UniqueID(puid, idv)\
+ ((puid)->id = idv, (puid)->xvalues = 0)
+#define uid_set_XUID(puid, pvalues, siz)\
+ ((puid)->id = -(long)(siz), (puid)->xvalues = pvalues)
+
+/* Get the size and the data of an XUID. */
+#define uid_XUID_size(puid) ((uint)(-(puid)->id))
+#define uid_XUID_values(puid) ((puid)->xvalues)
+
+/* Compare two uids for equality. */
+/* This could be a macro, but the Zortech compiler compiles it wrong. */
+bool uid_equal(P2(const gs_uid *, const gs_uid *)); /* in gsutil.c */
+
+/* Free the XUID array of a uid if necessary. */
+#define uid_free(puid, mem, cname)\
+ gs_free_object(mem, (puid)->xvalues, cname)
+
+#endif /* gsuid_INCLUDED */
diff --git a/gs/src/gsutil.c b/gs/src/gsutil.c
new file mode 100644
index 000000000..1f4fc7075
--- /dev/null
+++ b/gs/src/gsutil.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsutil.c */
+/* Utilities for Ghostscript library */
+#include "string_.h"
+#include "memory_.h"
+#include "gstypes.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gsuid.h"
+#include "gsutil.h" /* for prototype checking */
+
+/* ------ Unique IDs ------ */
+
+/* Generate a block of unique IDs. */
+static ulong gs_next_id = 0;
+ulong
+gs_next_ids(uint count)
+{ ulong id;
+ if ( gs_next_id == 0 ) gs_next_id++;
+ id = gs_next_id;
+ gs_next_id += count;
+ return id;
+}
+
+/* ------ Memory utilities ------ */
+
+/* Transpose an 8 x 8 block of bits. line_size is the raster of */
+/* the input data. dist is the distance between output bytes. */
+/* This routine may be supplanted by assembly code. */
+#if !USE_ASM
+
+void
+memflip8x8(const byte *inp, int line_size, byte *outp, int dist)
+{ register uint ae, bf, cg, dh;
+ { const byte *ptr4 = inp + (line_size << 2);
+ ae = ((uint)*inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ bf = ((uint)*inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ cg = ((uint)*inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ dh = ((uint)*inp << 8) + *ptr4;
+ }
+
+ /* Check for all 8 bytes being the same. */
+ /* This is especially worth doing for the case where all are zero. */
+ if ( ae == bf && ae == cg && ae == dh && (ae >> 8) == (ae & 0xff) )
+ { if ( ae == 0 ) goto store;
+ *outp = -((ae >> 7) & 1);
+ outp += dist;
+ *outp = -((ae >> 6) & 1);
+ outp += dist;
+ *outp = -((ae >> 5) & 1);
+ outp += dist;
+ *outp = -((ae >> 4) & 1);
+ outp += dist;
+ *outp = -((ae >> 3) & 1);
+ outp += dist;
+ *outp = -((ae >> 2) & 1);
+ outp += dist;
+ *outp = -((ae >> 1) & 1);
+ outp += dist;
+ *outp = -(ae & 1);
+ return;
+ }
+
+ { register uint temp;
+
+/* Transpose a block of bits between registers. */
+#define transpose(r,s,mask,shift)\
+ r ^= (temp = ((s >> shift) ^ r) & mask);\
+ s ^= temp << shift
+
+/* Transpose blocks of 4 x 4 */
+#define transpose4(r) transpose(r,r,0x00f0,4)
+ transpose4(ae);
+ transpose4(bf);
+ transpose4(cg);
+ transpose4(dh);
+
+/* Transpose blocks of 2 x 2 */
+ transpose(ae, cg, 0x3333, 2);
+ transpose(bf, dh, 0x3333, 2);
+
+/* Transpose blocks of 1 x 1 */
+ transpose(ae, bf, 0x5555, 1);
+ transpose(cg, dh, 0x5555, 1);
+
+ }
+
+store: *outp = ae >> 8;
+ outp += dist;
+ *outp = bf >> 8;
+ outp += dist;
+ *outp = cg >> 8;
+ outp += dist;
+ *outp = dh >> 8;
+ outp += dist;
+ *outp = (byte)ae;
+ outp += dist;
+ *outp = (byte)bf;
+ outp += dist;
+ *outp = (byte)cg;
+ outp += dist;
+ *outp = (byte)dh;
+}
+
+#endif /* !USE_ASM */
+
+/* ------ String utilities ------ */
+
+/* Compare two strings, returning -1 if the first is less, */
+/* 0 if they are equal, and 1 if first is greater. */
+/* We can't use memcmp, because we always use unsigned characters. */
+int
+bytes_compare(const byte *s1, uint len1, const byte *s2, uint len2)
+{ register uint len = len1;
+ if ( len2 < len ) len = len2;
+ { register const byte *p1 = s1;
+ register const byte *p2 = s2;
+ while ( len-- )
+ if ( *p1++ != *p2++ )
+ return (p1[-1] < p2[-1] ? -1 : 1);
+ }
+ /* Now check for differing lengths */
+ return (len1 == len2 ? 0 : len1 < len2 ? -1 : 1);
+}
+
+/* Test whether a string matches a pattern with wildcards. */
+/* '*' = any substring, '?' = any character, '\' quotes next character. */
+private const string_match_params smp_default = { '*', '?', '\\', false };
+bool
+string_match(const byte *str, uint len, const byte *pstr, uint plen,
+ register const string_match_params *psmp)
+{ const byte *pback = 0;
+ const byte *spback = 0; /* initialized only to pacify gcc */
+ const byte *p = pstr, *pend = pstr + plen;
+ const byte *sp = str, *spend = str + len;
+ if ( psmp == 0 )
+ psmp = &smp_default;
+again: while ( p < pend )
+ { register byte ch = *p;
+ if ( ch == psmp->any_substring )
+ { pback = ++p, spback = sp;
+ continue;
+ }
+ else if ( ch == psmp->any_char )
+ { if ( sp == spend )
+ return false; /* str too short */
+ p++, sp++;
+ continue;
+ }
+ else if ( ch == psmp->quote_next )
+ { if ( ++p == pend )
+ return true; /* bad pattern */
+ ch = *p;
+ }
+ if ( sp == spend )
+ return false; /* str too short */
+ if ( *sp == ch ||
+ (psmp->ignore_case && (*sp ^ ch) == 0x20 &&
+ (ch &= ~0x20) >= 0x41 && ch <= 0x5a)
+ )
+ p++, sp++;
+ else if ( pback == 0 )
+ return false; /* no * to back up to */
+ else
+ { sp = ++spback;
+ p = pback;
+ }
+ }
+ if ( sp < spend )
+ { /* We got a match, but there are chars left over. */
+ /* If we can back up, back up to the only place that */
+ /* could produce a complete match, otherwise fail. */
+ if ( pback == 0 )
+ return false;
+ p = pback;
+ pback = 0;
+ sp = spend - (pend - p);
+ goto again;
+ }
+ return true;
+}
+
+/* ------ UID utilities ------ */
+
+/* Compare two UIDs for equality. */
+/* We know that at least one of them is valid. */
+bool
+uid_equal(register const gs_uid *puid1, register const gs_uid *puid2)
+{ if ( puid1->id != puid2->id )
+ return false;
+ if ( puid1->id >= 0 )
+ return true; /* UniqueID */
+ return
+ !memcmp((const char *)puid1->xvalues,
+ (const char *)puid2->xvalues,
+ (uint)-(puid1->id) * sizeof(long));
+}
diff --git a/gs/src/gsutil.h b/gs/src/gsutil.h
new file mode 100644
index 000000000..eb3c8aa89
--- /dev/null
+++ b/gs/src/gsutil.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsutil.h */
+/* Prototypes for procedures in gsutil.c */
+
+#ifndef gsutil_INCLUDED
+# define gsutil_INCLUDED
+
+/* ------ Unique IDs ------ */
+
+/* Generate a block of unique IDs. */
+gs_id gs_next_ids(P1(uint count));
+
+/* ------ Memory utilities ------ */
+
+/* Transpose an 8 x 8 block of bits. */
+/* line_size is the raster of the input data; */
+/* dist is the distance between output bytes. */
+/* Dot matrix printers need this. */
+/* Note that with a negative dist value, */
+/* this will rotate an 8 x 8 block 90 degrees counter-clockwise. */
+void memflip8x8(P4(const byte *inp, int line_size, byte *outp, int dist));
+
+/* ------ String utilities ------ */
+
+/* Compare two strings, returning -1 if the first is less, */
+/* 0 if they are equal, and 1 if first is greater. */
+/* We can't use memcmp, because we always use unsigned characters. */
+int bytes_compare(P4(const byte *str1, uint len1,
+ const byte *str2, uint len2));
+
+/* Test whether a string matches a pattern with wildcards. */
+/* If psmp == NULL, use standard parameters: '*' = any substring, */
+/* '?' = any character, '\\' quotes next character, don't ignore case. */
+typedef struct string_match_params_s {
+ int any_substring; /* '*' */
+ int any_char; /* '?' */
+ int quote_next; /* '\\' */
+ bool ignore_case;
+} string_match_params;
+bool string_match(P5(const byte *str, uint len,
+ const byte *pstr, uint plen,
+ const string_match_params *psmp));
+
+#endif /* gsutil_INCLUDED */
diff --git a/gs/src/gswin.rc b/gs/src/gswin.rc
new file mode 100644
index 000000000..18787bc3b
--- /dev/null
+++ b/gs/src/gswin.rc
@@ -0,0 +1,29 @@
+/* Copyright (C) 1996, Russell Lang. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+
+/* gswin.rc */
+#include <windows.h>
+#include "dwmain.h"
+
+GSTEXT_ICON ICON gstext.ico
+GSIMAGE_ICON ICON gsgraph.ico
+
+#ifndef DS_3DLOOK
+#define DS_3DLOOK 0x0004L /* for Windows 95 look */
+#endif
diff --git a/gs/src/gswin32.rc b/gs/src/gswin32.rc
new file mode 100644
index 000000000..6d63709c0
--- /dev/null
+++ b/gs/src/gswin32.rc
@@ -0,0 +1,36 @@
+#include <windows.h>
+#include "gp_mswin.h"
+
+GSTEXT_ICON ICON gstext.ico
+GSIMAGE_ICON ICON gsgraph.ico
+
+#ifndef DS_3DLOOK
+#define DS_3DLOOK 0x0004L /* for Windows 95 look */
+#endif
+
+QueueDlgBox DIALOG 32, 40, 176, 60
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK
+CAPTION "Select Queue"
+Font 8, "Helv"
+{
+ DEFPUSHBUTTON "&Ok", IDOK, 134, 12, 32, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD
+ PUSHBUTTON "&Cancel", IDCANCEL, 134, 36, 32, 14, BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD
+ LISTBOX SPOOL_PORT, 6, 6, 116, 50, LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+}
+
+SpoolDlgBox DIALOG 32, 40, 110, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Select Printer Port"
+BEGIN
+ CONTROL "&Ok", IDOK, "button", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 14, 32, 14
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 72, 36, 32, 14
+ CONTROL "", SPOOL_PORT, "LISTBOX", LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 8, 8, 56, 50
+END
+
+CancelDlgBox DIALOG 32, 40, 120, 48
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+BEGIN
+ CTEXT "Printing", CANCEL_PRINTING, 8, 4, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CTEXT "", CANCEL_PCDONE, 8, 16, 104, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+ CONTROL "&Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 44, 30, 32, 14
+END
diff --git a/gs/src/gswin386.rc b/gs/src/gswin386.rc
new file mode 100644
index 000000000..ec81842b5
--- /dev/null
+++ b/gs/src/gswin386.rc
@@ -0,0 +1,4 @@
+#include "windows.h"
+
+texticon ICON gstext.ico
+grpicon ICON gsgraph.ico
diff --git a/gs/src/gsxfont.h b/gs/src/gsxfont.h
new file mode 100644
index 000000000..9bb4aa397
--- /dev/null
+++ b/gs/src/gsxfont.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsxfont.h */
+/* External font client definitions for Ghostscript library */
+
+#ifndef gsxfont_INCLUDED
+# define gsxfont_INCLUDED
+
+/* Define a character glyph identifier. This is opaque, probably an index */
+/* into the font. Glyph identifiers are font-specific. */
+typedef ulong gx_xglyph;
+#define gx_no_xglyph ((gx_xglyph)~0L)
+
+/* Structure for xfont procedures. */
+struct gx_xfont_procs_s;
+typedef struct gx_xfont_procs_s gx_xfont_procs;
+
+/* A generic xfont. */
+struct gx_xfont_s;
+typedef struct gx_xfont_s gx_xfont;
+
+#endif /* gsxfont_INCLUDED */
diff --git a/gs/src/gx.h b/gs/src/gx.h
new file mode 100644
index 000000000..635b83c52
--- /dev/null
+++ b/gs/src/gx.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1989, 1991, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gx.h */
+/* Common internal definitions for Ghostscript library */
+#include "stdio_.h" /* includes std.h */
+#include "gserror.h"
+#include "gsio.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gdebug.h"
+
+/* Define opaque types for the graphics state. */
+/* This is used so pervasively that we define it here, */
+/* rather than at a higher level as perhaps would be more appropriate. */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
diff --git a/gs/src/gxacpath.c b/gs/src/gxacpath.c
new file mode 100644
index 000000000..7a1e808b7
--- /dev/null
+++ b/gs/src/gxacpath.c
@@ -0,0 +1,447 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxacpath.c */
+/* Accumulator for clipping paths */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gsdcolor.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+#include "gxpaint.h"
+#include "gzcpath.h"
+#include "gzacpath.h"
+
+/* Imported procedures */
+extern gx_device *gs_currentdevice(P1(const gs_state *));
+extern float gs_currentflat(P1(const gs_state *));
+extern bool clip_list_validate(P1(const gx_clip_list *));
+
+/* Device procedures */
+private dev_proc_open_device(accum_open);
+private dev_proc_close_device(accum_close);
+private dev_proc_fill_rectangle(accum_fill_rectangle);
+
+/* The device descriptor */
+/* Many of these procedures won't be called; they are set to NULL. */
+private const gx_device_cpath_accum gs_cpath_accum_device =
+{ std_device_std_body(gx_device_cpath_accum, 0, "clip list accumulator",
+ 0, 0, 1, 1),
+ { accum_open,
+ NULL,
+ NULL,
+ NULL,
+ accum_close,
+ NULL,
+ NULL,
+ accum_fill_rectangle,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ NULL,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ NULL,
+ NULL,
+ gx_get_largest_clipping_box,
+ NULL
+ }
+};
+
+/* Start accumulating a clipping path. */
+void
+gx_cpath_accum_begin(gx_device_cpath_accum *padev, gs_memory_t *mem)
+{ *padev = gs_cpath_accum_device;
+ padev->list_memory = mem;
+ (*dev_proc(padev, open_device))((gx_device *)padev);
+}
+
+void
+gx_cpath_accum_set_cbox(gx_device_cpath_accum *padev,
+ const gs_fixed_rect *pbox)
+{ padev->clip_box.p.x = fixed2int_var(pbox->p.x);
+ padev->clip_box.p.y = fixed2int_var(pbox->p.y);
+ padev->clip_box.q.x = fixed2int_var_ceiling(pbox->q.x);
+ padev->clip_box.q.y = fixed2int_var_ceiling(pbox->q.y);
+}
+
+/* Finish accumulating a clipping path. */
+int
+gx_cpath_accum_end(const gx_device_cpath_accum *padev, gx_clip_path *pcpath)
+{ int code = (*dev_proc(padev, close_device))((gx_device *)padev);
+ if ( code < 0 )
+ return code;
+ gx_cpath_release(pcpath);
+ pcpath->list = padev->list;
+ pcpath->path.bbox.p.x = int2fixed(padev->bbox.p.x);
+ pcpath->path.bbox.p.y = int2fixed(padev->bbox.p.y);
+ pcpath->path.bbox.q.x = int2fixed(padev->bbox.q.x);
+ pcpath->path.bbox.q.y = int2fixed(padev->bbox.q.y);
+ /* Using the setbbox flag here is slightly bogus, */
+ /* but it's as good a way as any to indicate that */
+ /* the bbox is accurate. */
+ pcpath->path.bbox_set = 1;
+ /* Note that the result of the intersection might be */
+ /* a single rectangle. This will cause clip_path_is_rect.. */
+ /* to return true. This, in turn, requires that */
+ /* we set pcpath->inner_box correctly. */
+ if ( clip_list_is_rectangle(&padev->list) )
+ pcpath->inner_box = pcpath->path.bbox;
+ else
+ { /* The quick check must fail. */
+ pcpath->inner_box.p.x = pcpath->inner_box.p.y = 0;
+ pcpath->inner_box.q.x = pcpath->inner_box.q.y = 0;
+ }
+ gx_cpath_set_outer_box(pcpath);
+ pcpath->segments_valid = 0;
+ pcpath->shares_list = 0;
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ return 0;
+}
+
+/* Discard an accumulator in case of error. */
+void
+gx_cpath_accum_discard(gx_device_cpath_accum *padev)
+{ gx_clip_list_free(&padev->list, padev->list_memory);
+}
+
+/* Intersect two clipping paths using an accumulator. */
+int
+gx_cpath_intersect_slow(gs_state *pgs, gx_clip_path *pcpath, gx_path *ppath,
+ int rule)
+{ bool outside = pcpath->list.outside;
+ gs_logical_operation_t save_lop = gs_current_logical_op(pgs);
+ gx_device_cpath_accum adev;
+ gx_device_color devc;
+ gx_fill_params params;
+ int code;
+
+ gx_cpath_accum_begin(&adev, pcpath->path.memory);
+ color_set_pure(&devc, 0); /* arbitrary, but not transparent */
+ gs_set_logical_op(pgs, lop_default);
+ params.rule = rule;
+ params.adjust.x = params.adjust.y = fixed_half;
+ params.flatness = gs_currentflat(pgs);
+ params.fill_zero_width = true;
+ code = gx_fill_path_only(ppath, (gx_device *)&adev,
+ (const gs_imager_state *)pgs,
+ &params, &devc, pcpath);
+ if ( code < 0 || (code = gx_cpath_accum_end(&adev, pcpath)) < 0 )
+ gx_cpath_accum_discard(&adev);
+ pcpath->list.outside = outside;
+ gs_set_logical_op(pgs, save_lop);
+ return code;
+}
+
+/* ------ Device implementation ------ */
+
+#define adev ((gx_device_cpath_accum *)dev)
+
+/* Initialize the accumulation device. */
+private int
+accum_open(register gx_device *dev)
+{ gx_clip_list_init(&adev->list);
+ adev->bbox.p.x = adev->bbox.p.y = max_int;
+ adev->bbox.q.x = adev->bbox.q.y = min_int;
+ adev->clip_box.p.x = adev->clip_box.p.y = min_int;
+ adev->clip_box.q.x = adev->clip_box.q.y = max_int;
+ return 0;
+}
+
+/* Close the accumulation device. */
+private int
+accum_close(gx_device *dev)
+{
+#ifdef DEBUG
+if ( gs_debug_c('q') )
+ { gx_clip_rect *rp =
+ (adev->list.count <= 1 ? &adev->list.single : adev->list.head);
+ dprintf4("[q]list at 0x%lx, count=%d, head=0x%lx, tail=0x%lx:\n",
+ (ulong)&adev->list, adev->list.count,
+ (ulong)adev->list.head, (ulong)adev->list.tail);
+ while ( rp != 0 )
+ { clip_rect_print('q', " ", rp);
+ rp = rp->next;
+ }
+ }
+ if ( !clip_list_validate(&adev->list) )
+ { lprintf1("[q]Bad clip list 0x%lx!\n", (ulong)&adev->list);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ return 0;
+}
+
+/* Accumulate one rectangle. */
+#undef adev
+/* Allocate a rectangle to be added to the list. */
+static const gx_clip_rect clip_head_rect =
+ { 0, 0, min_int, min_int, min_int, min_int };
+static const gx_clip_rect clip_tail_rect =
+ { 0, 0, max_int, max_int, max_int, max_int };
+private gx_clip_rect *
+accum_alloc_rect(gx_device_cpath_accum *adev)
+{ gs_memory_t *mem = adev->list_memory;
+ gx_clip_rect *ar = gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect");
+ if ( ar == 0 )
+ return 0;
+ if ( adev->list.count == 2 )
+ { /* We're switching from a single rectangle to a list. */
+ /* Allocate the head and tail entries. */
+ gx_clip_rect *head = ar;
+ gx_clip_rect *tail =
+ gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(tail)");
+ gx_clip_rect *single =
+ gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(single)");
+ ar = gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(head)");
+ if ( tail == 0 || single == 0 || ar == 0 )
+ { gs_free_object(mem, ar, "accum_alloc_rect");
+ gs_free_object(mem, single, "accum_alloc_rect(single)");
+ gs_free_object(mem, tail, "accum_alloc_rect(tail)");
+ gs_free_object(mem, head, "accum_alloc_rect(head)");
+ return 0;
+ }
+ *head = clip_head_rect;
+ head->next = single;
+ *single = adev->list.single;
+ single->prev = head;
+ single->next = tail;
+ *tail = clip_tail_rect;
+ tail->prev = single;
+ adev->list.head = head;
+ adev->list.tail = tail;
+ }
+ return ar;
+}
+#define accum_alloc(s, ar, px, py, qx, qy)\
+ if ( ++(adev->list.count) == 1 )\
+ ar = &adev->list.single;\
+ else if ( (ar = accum_alloc_rect(adev)) == 0 )\
+ return_error(gs_error_VMerror);\
+ accum_set(s, ar, px, py, qx, qy)
+#define accum_set(s, ar, px, py, qx, qy)\
+ (ar)->xmin = px, (ar)->ymin = py, (ar)->xmax = qx, (ar)->ymax = qy;\
+ clip_rect_print('Q', s, ar)
+/* Link or unlink a rectangle in the list. */
+#define accum_add_last(ar)\
+ accum_add_before(ar, adev->list.tail)
+#define accum_add_after(ar, rprev)\
+ ar->prev = (rprev), (ar->next = (rprev)->next)->prev = ar,\
+ (rprev)->next = ar
+#define accum_add_before(ar, rnext)\
+ (ar->prev = (rnext)->prev)->next = ar, ar->next = (rnext),\
+ (rnext)->prev = ar
+#define accum_remove(ar)\
+ ar->next->prev = ar->prev, ar->prev->next = ar->next
+/* Free a rectangle that was removed from the list. */
+#define accum_free(s, ar)\
+ if ( --(adev->list.count) )\
+ { clip_rect_print('Q', s, ar);\
+ gs_free_object(adev->list_memory, ar, "accum_rect");\
+ }
+/*
+ * Add a rectangle to the list. It would be wonderful if rectangles
+ * were always disjoint and always presented in the correct order,
+ * but they aren't: the fill loop works by trapezoids, not by scan lines,
+ * and may produce slightly overlapping rectangles because of "fattening".
+ * All we can count on is that they are approximately disjoint and
+ * approximately in order.
+ *
+ * Because of the way the fill loop handles a path that is just a single
+ * rectangle, we take special care to merge Y-adjacent rectangles when
+ * this is possible.
+ */
+private int
+accum_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ int xe = x + w, ye = y + h;
+ gx_clip_rect *nr;
+ gx_clip_rect *ar;
+ register gx_clip_rect *rptr;
+ int ymin, ymax;
+#define adev ((gx_device_cpath_accum *)dev)
+
+ /* Clip the rectangle being added. */
+ if ( y < adev->clip_box.p.y )
+ y = adev->clip_box.p.y;
+ if ( ye > adev->clip_box.q.y )
+ ye = adev->clip_box.q.y;
+ if ( y >= ye )
+ return 0;
+ if ( x < adev->clip_box.p.x )
+ x = adev->clip_box.p.x;
+ if ( xe > adev->clip_box.q.x )
+ xe = adev->clip_box.q.x;
+ if ( x >= xe )
+ return 0;
+
+ /* Update the bounding box. */
+ if ( x < adev->bbox.p.x )
+ adev->bbox.p.x = x;
+ if ( y < adev->bbox.p.y )
+ adev->bbox.p.y = y;
+ if ( xe > adev->bbox.q.x )
+ adev->bbox.q.x = xe;
+ if ( ye > adev->bbox.q.y )
+ adev->bbox.q.y = ye;
+
+top: if ( adev->list.count == 0 ) /* very first rectangle */
+ { adev->list.count = 1;
+ accum_set("single", &adev->list.single, x, y, xe, ye);
+ return 0;
+ }
+ if ( adev->list.count == 1 ) /* check for Y merging */
+#define rptr (&adev->list.single)
+ { if ( x == rptr->xmin && xe == rptr->xmax &&
+ y <= rptr->ymax && y >= rptr->ymin
+ )
+ { if ( ye > rptr->ymax )
+ rptr->ymax = ye;
+ return 0;
+ }
+ }
+#undef rptr
+ accum_alloc("accum", nr, x, y, xe, ye);
+ rptr = adev->list.tail->prev;
+ if ( y >= rptr->ymax ||
+ (y == rptr->ymin && ye == rptr->ymax && x >= rptr->xmax)
+ )
+ { accum_add_last(nr);
+ return 0;
+ }
+ /* Work backwards till we find the insertion point. */
+ while ( ye <= rptr->ymin ) rptr = rptr->prev;
+ ymin = rptr->ymin;
+ ymax = rptr->ymax;
+ if ( ye > ymax )
+ { if ( y >= ymax )
+ { /* Insert between two bands. */
+ accum_add_after(nr, rptr);
+ return 0;
+ }
+ /* Split off the top part of the new rectangle. */
+ accum_alloc("a.top", ar, x, ymax, xe, ye);
+ accum_add_after(ar, rptr);
+ ye = nr->ymax = ymax;
+ clip_rect_print('Q', " ymax", nr);
+ }
+ /* Here we know ymin < ye <= ymax; */
+ /* rptr points to the last node with this value of ymin/ymax. */
+ /* If necessary, split off the part of the existing band */
+ /* that is above the new band. */
+ if ( ye < ymax )
+ { gx_clip_rect *rsplit = rptr;
+ while ( rsplit->ymax == ymax )
+ { accum_alloc("s.top", ar, rsplit->xmin, ye, rsplit->xmax, ymax);
+ accum_add_after(ar, rptr);
+ rsplit->ymax = ye;
+ rsplit = rsplit->prev;
+ }
+ ymax = ye;
+ }
+ /* Now ye = ymax. If necessary, split off the part of the */
+ /* existing band that is below the new band. */
+ if ( y > ymin )
+ { gx_clip_rect *rbot = rptr, *rsplit;
+ while ( rbot->prev->ymin == ymin )
+ rbot = rbot->prev;
+ for ( rsplit = rbot; ; )
+ { accum_alloc("s.bot", ar, rsplit->xmin, ymin, rsplit->xmax, y);
+ accum_add_before(ar, rbot);
+ rsplit->ymin = y;
+ if ( rsplit == rptr ) break;
+ rsplit = rsplit->next;
+ }
+ ymin = y;
+ }
+ /* Now y <= ymin as well. (y < ymin is possible.) */
+ nr->ymin = ymin;
+ /* Search for the X insertion point. */
+ for ( ; rptr->ymin == ymin; rptr = rptr->prev )
+ { if ( xe < rptr->xmin ) continue; /* still too far to right */
+ if ( x > rptr->xmax ) break; /* disjoint */
+ /* The new rectangle overlaps an existing one. Merge them. */
+ if ( xe > rptr->xmax )
+ { rptr->xmax = nr->xmax; /* might be > xe if */
+ /* we already did a merge */
+ clip_rect_print('Q', "widen", rptr);
+ }
+ accum_free("free", nr);
+ if ( x >= rptr->xmin )
+ goto out;
+ /* Might overlap other rectangles to the left. */
+ rptr->xmin = x;
+ nr = rptr;
+ accum_remove(rptr);
+ clip_rect_print('Q', "merge", nr);
+ }
+ accum_add_after(nr, rptr);
+out: /* Check whether there are only 0 or 1 rectangles left. */
+ if ( adev->list.count <= 1 )
+ { /* We're switching from a list to at most 1 rectangle. */
+ /* Free the head and tail entries. */
+ gs_memory_t *mem = adev->list_memory;
+ gx_clip_rect *single = adev->list.head->next;
+ if ( single != adev->list.tail )
+ { adev->list.single = *single;
+ gs_free_object(mem, single, "accum_free_rect(single)");
+ adev->list.single.next = adev->list.single.prev = 0;
+ }
+ gs_free_object(mem, adev->list.tail, "accum_free_rect(tail)");
+ gs_free_object(mem, adev->list.head, "accum_free_rect(head)");
+ adev->list.head = 0;
+ adev->list.tail = 0;
+ }
+ /* Check whether there is still more of the new band to process. */
+ if ( y < ymin )
+ { /* Continue with the bottom part of the new rectangle. */
+ clip_rect_print('Q', " ymin", nr);
+ ye = ymin;
+ goto top;
+ }
+ return 0;
+#undef adev
+}
diff --git a/gs/src/gxalloc.h b/gs/src/gxalloc.h
new file mode 100644
index 000000000..35419b4fa
--- /dev/null
+++ b/gs/src/gxalloc.h
@@ -0,0 +1,373 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxalloc.h */
+/* Memory manager internal definitions for Ghostscript */
+/* Requires gsmemory.h, gsstruct.h */
+
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+#include "gsalloc.h"
+#include "gxobj.h"
+
+/* ================ Chunks ================ */
+
+/*
+ * We obtain memory from the operating system in `chunks'. A chunk
+ * may hold only a single large object (or string), or it may hold
+ * many objects (allocated from the bottom up, always aligned)
+ * and strings (allocated from the top down, not aligned).
+ */
+
+/*
+ * Refs are allocated in the bottom-up section, along with struct objects.
+ * In order to keep the overhead for refs small, we make consecutive
+ * blocks of refs into a single allocator object of type st_refs.
+ * To do this, we remember the start of the current ref object (if any),
+ * and the end of the last block of allocated refs. As long as
+ * the latter is equal to the top of the allocated area, we can add
+ * more refs to the current object; otherwise, we have to start a new one.
+ * We assume that sizeof(ref) % obj_align_mod == 0; this means that if we
+ * ever have to pad a block of refs, we never add as much as one entire ref.
+ */
+
+/*
+ * When we do a save, we create a new 'inner' chunk out of the remaining
+ * space in the currently active chunk. Inner chunks must not be freed
+ * by a restore.
+ *
+ * The garbage collector implements relocation for refs by scanning
+ * forward to a free object. Because of this, every ref object must end
+ * with a dummy ref that can hold the relocation for the last block.
+ * In order to put a reasonable upper bound on the scanning time, we
+ * limit the length of the objects that contain runs of refs.
+ */
+#define max_size_st_refs (50 * sizeof(ref))
+
+/*
+ * Strings carry some additional overhead for use by the GC.
+ * At the top of the chunk is a table of relocation values for
+ * 16N-character blocks of strings, where N is sizeof(uint).
+ * This table is aligned, by adding padding above it if necessary.
+ * Just below it is a mark table for the strings. This table is also aligned,
+ * to improve GC performance. The actual string data start below
+ * the mark table. These tables are not needed for a chunk that holds
+ * a single large (non-string) object, but they are needed for all other
+ * chunks, including chunks created to hold a single large string.
+ */
+
+/*
+ * Define the unit of data manipulation for marking strings.
+ */
+typedef uint string_mark_unit;
+#define log2_sizeof_string_mark_unit arch_log2_sizeof_int
+/*
+ * Define the quantum of relocation for strings, which determines
+ * the quantum for reserving space. This value must be a power of 2,
+ * must be at least sizeof(string_mark_unit) * 8, and (because of the
+ * unrolled loops in igcstr.c) currently must be equal to either 32 or 64.
+ */
+typedef uint string_reloc_offset;
+#define log2_string_data_quantum (arch_log2_sizeof_int + 4)
+#define string_data_quantum (1 << log2_string_data_quantum)
+/*
+ * Define the quantum for reserving string space, including data,
+ * marks, and relocation.
+ */
+#define string_space_quantum\
+ (string_data_quantum + (string_data_quantum / 8) +\
+ sizeof(string_reloc_offset))
+/*
+ * Compute the amount of space needed for a chunk that holds only
+ * a string of a given size.
+ */
+#define string_chunk_space(nbytes)\
+ (((nbytes) + (string_data_quantum - 1)) / string_data_quantum *\
+ string_space_quantum)
+/*
+ * Compute the number of string space quanta in a given amount of storage.
+ */
+#define string_space_quanta(spacebytes)\
+ ((spacebytes) / string_space_quantum)
+/*
+ * Compute the size of string marks for a given number of quanta.
+ */
+#define string_quanta_mark_size(nquanta)\
+ ((nquanta) * (string_data_quantum / 8))
+
+/*
+ * To allow the garbage collector to combine chunks, we store in the
+ * head of each chunk the address to which its contents will be moved.
+ */
+/*typedef struct chunk_head_s chunk_head_t;*/ /* in gxobj.h */
+
+/* Structure for a chunk. */
+typedef struct chunk_s chunk_t;
+struct chunk_s {
+ chunk_head_t *chead; /* chunk head, bottom of chunk; */
+ /* csbase is an alias for chead */
+#define csbase(cp) ((byte *)(cp)->chead)
+ /* Note that allocation takes place both from the bottom up */
+ /* (aligned objects) and from the top down (strings). */
+ byte *cbase; /* bottom of chunk data area */
+ byte *cbot; /* bottom of free area */
+ /* (top of aligned objects) */
+ obj_header_t *rcur; /* current refs object, 0 if none */
+ byte *rtop; /* top of rcur */
+ byte *ctop; /* top of free area */
+ /* (bottom of strings) */
+ byte *climit; /* top of strings */
+ byte *cend; /* top of chunk */
+ chunk_t *cprev; /* chain chunks together, */
+ chunk_t *cnext; /* sorted by address */
+ chunk_t *outer; /* the chunk of which this is */
+ /* an inner chunk, if any */
+ uint inner_count; /* number of chunks of which this is */
+ /* the outer chunk, if any */
+ bool has_refs; /* true if any refs in chunk */
+ /*
+ * Free lists for single bytes in blocks of 1-3 bytes,
+ * one per 256 bytes in [csbase..climit). The chain
+ * pointer is a (1-byte) self-relative offset,
+ * terminated by a 0; obviously, the chain is sorted by
+ * increasing address. The free list pointers themselves
+ * are offsets relative to csbase.
+ *
+ * Note that these lists overlay the GC relocation table.
+ */
+ ushort *sfree1;
+ /*
+ * Free list for blocks of >= 4 bytes. Each block begins
+ * with a 2-byte size and a 2-byte next block pointer,
+ * both big-endian.
+ */
+ ushort sfree;
+ /* The remaining members are for the GC. */
+ byte *odest; /* destination for objects */
+ byte *smark; /* mark bits for strings */
+ uint smark_size;
+ byte *sbase; /* base for computing smark offsets */
+ string_reloc_offset *sreloc; /* relocation for string blocks */
+ byte *sdest; /* destination for (top of) strings */
+ byte *rescan_bot; /* bottom of rescanning range if */
+ /* the GC mark stack overflows */
+ byte *rescan_top; /* top of range ditto */
+};
+/* The chunk descriptor is exported only for isave.c. */
+extern_st(st_chunk);
+#define public_st_chunk() /* in ialloc.c */\
+ gs_public_st_ptrs2(st_chunk, chunk_t, "chunk_t",\
+ chunk_enum_ptrs, chunk_reloc_ptrs, cprev, cnext)
+
+/*
+ * Macros for scanning a chunk linearly, with the following schema:
+ * SCAN_CHUNK_OBJECTS(cp) << declares pre, size >>
+ * << code for all objects -- size not set yet >>
+ * DO_LARGE
+ * << code for large objects >>
+ * DO_SMALL
+ * << code for small objects >>
+ * END_OBJECTS_SCAN
+ * If large and small objects are treated alike, one can use DO_ALL instead
+ * of DO_LARGE and DO_SMALL.
+ */
+#define SCAN_CHUNK_OBJECTS(cp)\
+ { obj_header_t *pre = (obj_header_t *)((cp)->cbase);\
+ obj_header_t *end = (obj_header_t *)((cp)->cbot);\
+ ulong size; /* long because of large objects */\
+ for ( ; pre < end;\
+ pre = (obj_header_t *)((char *)pre + obj_size_round(size))\
+ )\
+ {
+#define DO_LARGE\
+ if ( pre->o_large )\
+ { size = pre_obj_large_size(pre);\
+ {
+#define DO_SMALL\
+ }\
+ } else\
+ { size = pre_obj_small_size(pre);\
+ {
+#define DO_ALL\
+ { size = pre_obj_contents_size(pre);\
+ {
+#ifdef DEBUG
+# define END_OBJECTS_SCAN\
+ }\
+ }\
+ }\
+ if ( pre != end )\
+ { lprintf2("Chunk parsing error, 0x%lx != 0x%lx\n",\
+ (ulong)pre, (ulong)end);\
+ gs_exit(1);\
+ }\
+ }
+#else
+# define END_OBJECTS_SCAN\
+ }\
+ }\
+ }\
+ }
+#endif
+
+/* Initialize a chunk. */
+/* This is exported for save/restore. */
+void alloc_init_chunk(P5(chunk_t *, byte *, byte *, bool, chunk_t *));
+
+/* Initialize the string freelists in a chunk. */
+void alloc_init_free_strings(P1(chunk_t *));
+
+/* Find the chunk for a pointer. */
+/* Note that ptr_is_within_chunk returns true even if the pointer */
+/* is in an inner chunk of the chunk being tested. */
+#define ptr_is_within_chunk(ptr, cp)\
+ ptr_between((const byte *)(ptr), (cp)->cbase, (cp)->cend)
+#define ptr_is_in_inner_chunk(ptr, cp)\
+ ((cp)->inner_count != 0 &&\
+ ptr_between((const byte *)(ptr), (cp)->cbot, (cp)->ctop))
+#define ptr_is_in_chunk(ptr, cp)\
+ (ptr_is_within_chunk(ptr, cp) && !ptr_is_in_inner_chunk(ptr, cp))
+typedef struct chunk_locator_s {
+ const gs_ref_memory_t *memory; /* for head & tail of chain */
+ chunk_t *cp; /* one-element cache */
+} chunk_locator_t;
+bool chunk_locate_ptr(P2(const void *, chunk_locator_t *));
+#define chunk_locate(ptr, clp)\
+ (((clp)->cp != 0 && ptr_is_in_chunk(ptr, (clp)->cp)) ||\
+ chunk_locate_ptr(ptr, clp))
+
+/* Close up the current chunk. */
+/* This is exported for save/restore and for the GC. */
+void alloc_close_chunk(P1(gs_ref_memory_t *mem));
+
+/* Reopen the current chunk after a GC. */
+void alloc_open_chunk(P1(gs_ref_memory_t *mem));
+
+/* Insert or remove a chunk in the address-ordered chain. */
+/* These are exported for the GC. */
+void alloc_link_chunk(P2(chunk_t *, gs_ref_memory_t *));
+void alloc_unlink_chunk(P2(chunk_t *, gs_ref_memory_t *));
+
+/* Free a chunk. This is exported for save/restore and for the GC. */
+void alloc_free_chunk(P2(chunk_t *, gs_ref_memory_t *));
+
+/* Print a chunk debugging message. */
+/* Unfortunately, the ANSI C preprocessor doesn't allow us to */
+/* define the list of variables being printed as a macro. */
+#define dprintf_chunk_format\
+ "%s 0x%lx (0x%lx..0x%lx, 0x%lx..0x%lx..0x%lx)\n"
+#define dprintf_chunk(msg, cp)\
+ dprintf7(dprintf_chunk_format,\
+ msg, (ulong)(cp), (ulong)(cp)->cbase, (ulong)(cp)->cbot,\
+ (ulong)(cp)->ctop, (ulong)(cp)->climit, (ulong)(cp)->cend)
+#define if_debug_chunk(c, msg, cp)\
+ if_debug7(c, dprintf_chunk_format,\
+ msg, (ulong)(cp), (ulong)(cp)->cbase, (ulong)(cp)->cbot,\
+ (ulong)(cp)->ctop, (ulong)(cp)->climit, (ulong)(cp)->cend)
+
+/* ================ Allocator state ================ */
+
+/* Structures for save/restore (not defined here). */
+struct alloc_save_s;
+struct alloc_change_s;
+
+/* Define the number of freelists. The index in the freelist array */
+/* is the ceiling of the size of the object contents (i.e., not including */
+/* the header) divided by obj_align_mod. */
+#define max_freelist_size 800 /* big enough for gstate & contents */
+#define num_freelists\
+ ((max_freelist_size + obj_align_mod - 1) / obj_align_mod + 1)
+
+/* Define the memory manager subclass for this allocator. */
+struct gs_ref_memory_s {
+ /* The following are set at initialization time. */
+ gs_memory_common;
+ gs_memory_t *parent; /* for allocating chunks */
+ uint chunk_size;
+ uint large_size; /* min size to give large object */
+ /* its own chunk: must be */
+ /* 1 mod obj_align_mod */
+ gs_ref_memory_t *global; /* global VM for this allocator */
+ /* (may point to itself) */
+ uint space; /* a_local, a_global, a_system */
+ /* Callers can change the following dynamically */
+ /* (through a procedural interface). */
+ gs_memory_gc_status_t gc_status;
+ /* The following are updated dynamically. */
+ ulong limit; /* signal a VMerror when total */
+ /* allocated exceeds this */
+ chunk_t *cfirst; /* head of chunk list */
+ chunk_t *clast; /* tail of chunk list */
+ chunk_t cc; /* current chunk */
+ chunk_t *pcc; /* where to store cc */
+ chunk_locator_t cfreed; /* chunk where last object freed */
+ ulong allocated; /* total size of all chunks */
+ /* allocated at this save level */
+ long inherited; /* chunks allocated at outer save */
+ /* levels that should be counted */
+ /* towards the GC threshold */
+ /* (may be negative, but allocated + */
+ /* inherited >= 0 always) */
+ ulong gc_allocated; /* value of (allocated + */
+ /* previous_status.allocated) after last GC */
+ struct lost_ { /* space freed and 'lost' */
+ ulong objects;
+ ulong refs;
+ ulong strings;
+ } lost;
+ /* Garbage collector information */
+ gs_gc_root_t *roots; /* roots for GC */
+ /* Sharing / saved state information */
+ int num_contexts; /* # of contexts sharing this VM */
+ struct alloc_change_s *changes;
+ struct alloc_save_s *saved;
+ struct alloc_save_s *reloc_saved; /* for GC */
+ gs_memory_status_t previous_status; /* total allocated & used */
+ /* in outer save levels */
+ /* We put the freelists last to keep the scalar */
+ /* offsets small. */
+ obj_header_t *freelists[num_freelists];
+};
+/* The descriptor for gs_ref_memory_t is exported only for */
+/* the alloc_save_t subclass; otherwise, it should be private. */
+extern_st(st_ref_memory);
+#define public_st_ref_memory() /* in ialloc.c */\
+ gs_public_st_composite(st_ref_memory, gs_ref_memory_t,\
+ "gs_ref_memory", ref_memory_enum_ptrs, ref_memory_reloc_ptrs)
+#define st_ref_memory_max_ptrs 2 /* changes, saved */
+
+/* Define the procedures for the standard allocator. */
+/* We export this for subclasses. */
+extern const gs_memory_procs_t gs_ref_memory_procs;
+
+/*
+ * Scan the chunks of an allocator:
+ * SCAN_MEM_CHUNKS(mem, cp)
+ * << code to process chunk cp >>
+ * END_CHUNKS_SCAN
+ */
+#define SCAN_MEM_CHUNKS(mem, cp)\
+ { chunk_t *cp = (mem)->cfirst;\
+ for ( ; cp != 0; cp = cp->cnext )\
+ {
+#define END_CHUNKS_SCAN\
+ }\
+ }
diff --git a/gs/src/gxarith.h b/gs/src/gxarith.h
new file mode 100644
index 000000000..2ee9bfca0
--- /dev/null
+++ b/gs/src/gxarith.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 1990, 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+#ifndef gxarith_INCLUDED
+# define gxarith_INCLUDED
+
+/* gxarith.h */
+/* Arithmetic macros for Ghostscript library */
+
+/* Define an in-line abs function, good for any signed numeric type. */
+#define any_abs(x) ((x) < 0 ? -(x) : (x))
+
+/* Compute M modulo N. Requires N > 0; guarantees 0 <= imod(M,N) < N, */
+/* regardless of the whims of the % operator for negative operands. */
+int imod(P2(int m, int n));
+
+/* Compute the GCD of two integers. */
+int igcd(P2(int x, int y));
+
+/* Test whether an integral value fits in a given number of bits. */
+/* This works for all integral types. */
+#define fits_in_bits(i, n)\
+ (sizeof(i) <= sizeof(int) ? fits_in_ubits((i) + (1 << ((n) - 1)), (n) + 1) :\
+ fits_in_ubits((i) + (1L << ((n) - 1)), (n) + 1))
+#define fits_in_ubits(i, n) (((i) >> (n)) == 0)
+
+/*
+ * There are some floating point operations that can be implemented
+ * very efficiently on machines that have no floating point hardware,
+ * assuming IEEE representation and no range overflows.
+ * We define straightforward versions of them here, and alternate versions
+ * for no-floating-point machines in gxfarith.h.
+ */
+/* Test floating point values against constants. */
+#define is_fzero(f) ((f) == 0.0)
+#define is_fzero2(f1,f2) ((f1) == 0.0 && (f2) == 0.0)
+#define is_fneg(f) ((f) < 0.0)
+#define is_fge1(f) ((f) >= 1.0)
+/* Test whether a floating point value fits in a given number of bits. */
+#define f_fits_in_bits(f, n)\
+ ((f) >= -2.0 * (1L << ((n) - 2)) && (f) < 2.0 * (1L << ((n) - 2)))
+#define f_fits_in_ubits(f, n)\
+ ((f) >= 0 && (f) < 4.0 * (1L << ((n) - 2)))
+
+/*
+ * Define a macro for computing log2(n), where n=1,2,4,...,128.
+ * Because some compilers limit the total size of a statement,
+ * this macro must only mention n once. The macro should really
+ * only be used with compile-time constant arguments, but it will work
+ * even if n is an expression computed at run-time.
+ */
+#define small_exact_log2(n)\
+ ((uint)(05637042010L >> ((((n) % 11) - 1) * 3)) & 7)
+
+/*
+ * The following doesn't give rise to a macro, but is used in several
+ * places in Ghostscript. We observe that if M = 2^n-1 and V < M^2,
+ * then the quotient Q and remainder R can be computed as:
+ * Q = V / M = (V + (V >> n) + 1) >> n;
+ * R = V % M = (V + (V / M)) & M = V - (Q << n) + Q.
+ */
+
+#endif /* gxarith_INCLUDED */
diff --git a/gs/src/gxband.h b/gs/src/gxband.h
new file mode 100644
index 000000000..7c49c489c
--- /dev/null
+++ b/gs/src/gxband.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxband.h */
+/* Band-processing parameters for Ghostscript */
+
+#ifndef gxband_INCLUDED
+# define gxband_INCLUDED
+
+#include "gxclio.h"
+
+
+/*
+ * Define the parameters controlling banding.
+ */
+typedef struct gx_band_params_s {
+ int BandWidth; /* (optional) band width in pixels */
+ int BandHeight; /* (optional) */
+ long BandBufferSpace; /* (optional) */
+} gx_band_params;
+#define band_params_initial_values 0, 0, 0
+
+/*
+ * Define the information for a saved page.
+ */
+typedef struct gx_band_page_info_s {
+ char cfname[60]; /* command file name */
+ clist_file_ptr cfile; /* command file, normally 0 */
+ char bfname[60]; /* block file name */
+ clist_file_ptr bfile; /* block file, normally 0 */
+ uint tile_cache_size; /* size of tile cache */
+ long bfile_end_pos; /* ftell at end of bfile */
+ gx_band_params band_params; /* parameters used when writing band list */
+ /* (actual values, no 0s) */
+} gx_band_page_info;
+/*
+ * By convention, the structure member containing the above is called
+ * page_info. Define shorthand accessors for its members.
+ */
+#define page_cfile page_info.cfile
+#define page_cfname page_info.cfname
+#define page_bfile page_info.bfile
+#define page_bfname page_info.bfname
+#define page_tile_cache_size page_info.tile_cache_size
+#define page_bfile_end_pos page_info.bfile_end_pos
+#define page_band_height page_info.band_params.BandHeight
+
+#endif /* ndef gxband_INCLUDED */
diff --git a/gs/src/gxbcache.c b/gs/src/gxbcache.c
new file mode 100644
index 000000000..19f8df886
--- /dev/null
+++ b/gs/src/gxbcache.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxbcache.c */
+/* Bitmap cache implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gsmdebug.h"
+#include "gxbcache.h"
+
+/* ------ Entire cache ------ */
+
+/* Initialize a cache. The caller must allocate and initialize */
+/* the first chunk. */
+void
+gx_bits_cache_init(gx_bits_cache *bc, gx_bits_cache_chunk *bck)
+{ bck->next = bck;
+ bc->chunks = bck;
+ bc->cnext = 0;
+ bc->bsize = 0;
+ bc->csize = 0;
+}
+
+/* ------ Chunks ------ */
+
+/* Initialize a chunk. The caller must allocate it and its data. */
+void
+gx_bits_cache_chunk_init(gx_bits_cache_chunk *bck, byte *data, uint size)
+{ bck->next = 0;
+ bck->data = data;
+ bck->size = size;
+ bck->allocated = 0;
+ if ( data != 0 )
+ { gx_cached_bits_head *cbh = (gx_cached_bits_head *)data;
+ cbh->size = size;
+ cb_head_set_free(cbh);
+ }
+}
+
+/* ------ Individual entries ------ */
+
+/* Attempt to allocate an entry. If successful, set *pcbh and return 0. */
+/* If there isn't enough room, set *pcbh to an entry requiring freeing, */
+/* or to 0 if we are at the end of the chunk, and return -1. */
+int
+gx_bits_cache_alloc(gx_bits_cache *bc, ulong lsize, gx_cached_bits_head **pcbh)
+{
+#define ssize ((uint)lsize)
+ ulong lsize1 = lsize + sizeof(gx_cached_bits_head);
+#define ssize1 ((uint)lsize1)
+ uint cnext = bc->cnext;
+ gx_bits_cache_chunk *bck = bc->chunks;
+ uint left = bck->size - cnext;
+ gx_cached_bits_head *cbh;
+ gx_cached_bits_head *cbh_next;
+ uint fsize = 0;
+
+ if ( lsize1 > bck->size - cnext && lsize != left )
+ { /* Not enough room to allocate in this chunk. */
+ *pcbh = 0;
+ return -1;
+ }
+ /* Look for and/or free enough space. */
+ cbh = cbh_next = (gx_cached_bits_head *)(bck->data + cnext);
+ while ( fsize < ssize1 && fsize != ssize )
+ { if ( !cb_head_is_free(cbh_next) )
+ { /* Ask the caller to free the entry. */
+ if ( fsize )
+ cbh->size = fsize;
+ *pcbh = cbh_next;
+ return -1;
+ }
+ fsize += cbh_next->size;
+ if_debug2('K', "[K]merging free bits 0x%lx(%u)\n",
+ (ulong)cbh_next, cbh_next->size);
+ cbh_next = (gx_cached_bits_head *)((byte *)cbh + fsize);
+ }
+ if ( fsize > ssize ) /* fsize >= ssize1 */
+ { cbh_next = (gx_cached_bits_head *)((byte *)cbh + ssize);
+ cbh_next->size = fsize - ssize;
+ cb_head_set_free(cbh_next);
+ if_debug2('K', "[K]shortening bits 0x%lx by %u (initial)\n",
+ (ulong)cbh, fsize - ssize);
+ }
+ gs_alloc_fill(cbh, gs_alloc_fill_block, ssize);
+ cbh->size = ssize;
+ bc->bsize += ssize;
+ bc->csize++;
+ bc->cnext += ssize;
+ bck->allocated += ssize;
+ *pcbh = cbh;
+ return 0;
+#undef ssize
+#undef ssize1
+}
+
+/* Shorten an entry by a given amount. */
+void
+gx_bits_cache_shorten(gx_bits_cache *bc, gx_cached_bits_head *cbh,
+ uint diff, gx_bits_cache_chunk *bck)
+{ gx_cached_bits_head *next;
+
+ if ( (byte *)cbh + cbh->size == bck->data + bc->cnext &&
+ bck == bc->chunks
+ )
+ bc->cnext -= diff;
+ bc->bsize -= diff;
+ bck->allocated -= diff;
+ cbh->size -= diff;
+ next = (gx_cached_bits_head *)((byte *)cbh + cbh->size);
+ cb_head_set_free(next);
+ next->size = diff;
+}
+
+/* Free an entry. The caller is responsible for removing the entry */
+/* from any other structures (like a hash table). */
+void
+gx_bits_cache_free(gx_bits_cache *bc, gx_cached_bits_head *cbh,
+ gx_bits_cache_chunk *bck)
+{ uint size = cbh->size;
+ bc->csize--;
+ bc->bsize -= size;
+ bck->allocated -= size;
+ gs_alloc_fill(cbh, gs_alloc_fill_deleted, size);
+ cbh->size = size; /* gs_alloc_fill may have overwritten */
+ cb_head_set_free(cbh);
+}
diff --git a/gs/src/gxbcache.h b/gs/src/gxbcache.h
new file mode 100644
index 000000000..ad16e9e30
--- /dev/null
+++ b/gs/src/gxbcache.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxbcache.h */
+/* Bitmap cache structures */
+#include "gxbitmap.h"
+
+/*
+ * These structures are superclasses for a cache in which the 'value' is
+ * a bitmap. The structures defined here don't take any position about
+ * the nature of the 'key'.
+ */
+
+/* ---------------- Bitmap cache entry ---------------- */
+
+/*
+ * The cache may contain both used and free blocks.
+ * All blocks have a common header; free blocks have ONLY the header.
+ */
+typedef struct gx_cached_bits_head_s {
+ uint size; /* total block size in bytes */
+ uint depth; /* bits per pixel, free block if 0 */
+} gx_cached_bits_head;
+#define cb_head_is_free(cbh) ((cbh)->depth == 0)
+#define cb_head_set_free(cbh) ((cbh)->depth = 0)
+#define gx_cached_bits_common\
+ gx_cached_bits_head head; /* must be first */\
+ /* The rest of the entry is an abbreviation of */\
+ /* gx_strip_bitmap, sans data. */\
+ ushort width, height, shift;\
+ ushort raster;\
+ gx_bitmap_id id
+/* Define aliases for head members. */
+#define cb_depth head.depth
+/* Define aliases for common members formerly in the head. */
+#define cb_raster raster
+typedef struct gx_cached_bits_s {
+ gx_cached_bits_common;
+} gx_cached_bits;
+#define cb_is_free(cb) cb_head_is_free(&(cb)->head)
+/*
+ * Define the alignment of the gx_cached_bits structure. We must ensure
+ * that an immediately following bitmap will be properly aligned.
+ */
+#define align_cached_bits_mod\
+ (max(align_bitmap_mod, max(arch_align_ptr_mod, arch_align_long_mod)))
+
+/*
+ * We may allocate a bitmap cache in chunks, so as not to tie up memory
+ * prematurely if it isn't needed (or something else needs it more).
+ * Thus there is a structure for managing an entire cache, and another
+ * structure for managing each chunk.
+ */
+typedef struct gx_bits_cache_chunk_s gx_bits_cache_chunk;
+struct gx_bits_cache_chunk_s {
+ gx_bits_cache_chunk *next;
+ byte *data; /* gx_cached_bits_head * */
+ uint size;
+ uint allocated; /* amount of allocated data */
+};
+
+/* ---------------- Bitmap cache ---------------- */
+
+#define gx_bits_cache_common\
+ gx_bits_cache_chunk *chunks; /* current chunk in circular list */\
+ uint cnext; /* rover for allocating entries */\
+ /* in current chunk */\
+ uint bsize; /* total # of bytes for all entries */\
+ uint csize /* # of entries */
+typedef struct gx_bits_cache_s {
+ gx_bits_cache_common;
+} gx_bits_cache;
+
+/* ---------------- Procedural interface ---------------- */
+
+/* ------ Entire cache ------ */
+
+/* Initialize a cache. The caller must allocate and initialize */
+/* the first chunk. */
+void gx_bits_cache_init(P2(gx_bits_cache *, gx_bits_cache_chunk *));
+
+/* ------ Chunks ------ */
+
+/* Initialize a chunk. The caller must allocate it and its data. */
+void gx_bits_cache_chunk_init(P3(gx_bits_cache_chunk *, byte *, uint));
+
+/* ------ Individual entries ------ */
+
+/* Attempt to allocate an entry. If successful, set *pcbh and return 0. */
+/* If there isn't enough room, set *pcbh to an entry requiring freeing, */
+/* or to 0 if we are at the end of the chunk, and return -1. */
+int gx_bits_cache_alloc(P3(gx_bits_cache *, ulong, gx_cached_bits_head **));
+
+/* Shorten an entry by a given amount. */
+void gx_bits_cache_shorten(P4(gx_bits_cache *, gx_cached_bits_head *,
+ uint, gx_bits_cache_chunk *));
+
+/* Free an entry. The caller is responsible for removing the entry */
+/* from any other structures (like a hash table). */
+void gx_bits_cache_free(P3(gx_bits_cache *, gx_cached_bits_head *,
+ gx_bits_cache_chunk *));
diff --git a/gs/src/gxbitmap.h b/gs/src/gxbitmap.h
new file mode 100644
index 000000000..2330ef13e
--- /dev/null
+++ b/gs/src/gxbitmap.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 1989, 1993, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxbitmap.h */
+/* Definitions for stored bitmaps for Ghostscript */
+
+#ifndef gxbitmap_INCLUDED
+# define gxbitmap_INCLUDED
+
+#include "gstypes.h" /* for gs_id */
+#include "gsbitmap.h"
+
+/* Define the gx version of a bitmap identifier. */
+typedef gs_bitmap_id gx_bitmap_id;
+
+/* Define the gx version of the "no identifier" value. */
+#define gx_no_bitmap_id gs_no_bitmap_id
+
+/*
+ * For gx_bitmap data, each scan line must start on a `word' (long)
+ * boundary, and hence is padded to a word boundary, although this should
+ * rarely be of concern, since the raster and width are specified
+ * individually.
+ */
+/* We assume arch_align_long_mod is 1-4 or 8. */
+#if arch_align_long_mod <= 4
+# define log2_align_bitmap_mod 2
+#else
+#if arch_align_long_mod == 8
+# define log2_align_bitmap_mod 3
+#endif
+#endif
+#define align_bitmap_mod (1 << log2_align_bitmap_mod)
+#define bitmap_raster(width_bits)\
+ ((uint)(((width_bits + (align_bitmap_mod * 8 - 1))\
+ >> (log2_align_bitmap_mod + 3)) << log2_align_bitmap_mod))
+
+/*
+ * Define the gx analogue of the basic bitmap structure. Note that since
+ * all scan lines must be aligned, the requirement on raster is:
+ * If size.y > 1,
+ * raster >= bitmap_raster(size.x * depth)
+ * raster % align_bitmap_mod = 0
+ */
+#define gx_bitmap_common gs_bitmap_common
+typedef struct gx_bitmap_s {
+ gx_bitmap_common;
+} gx_bitmap;
+
+/*
+ * Define the gx analogue of the tile bitmap structure. Note that if
+ * shift != 0 (for strip bitmaps, see below), size.y and rep_height
+ * mean something slightly different: see below for details.
+ */
+#define gx_tile_bitmap_common gs_tile_bitmap_common
+typedef struct gx_tile_bitmap_s {
+ gx_tile_bitmap_common;
+} gx_tile_bitmap;
+
+/*
+ * For halftones at arbitrary angles, we provide for storing the halftone
+ * data as a strip that must be shifted in X for different values of Y. For
+ * an ordinary (non-shifted) halftone that has a repetition width of W and a
+ * repetition height of H, the pixel at coordinate (X,Y) corresponds to
+ * halftone pixel (X mod W, Y mod H), ignoring phase; for a strip halftone
+ * with strip shift S and strip height H, the pixel at (X,Y) corresponds to
+ * halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). In other words,
+ * each Y increment of H shifts the strip left by S pixels.
+ *
+ * As for non-shifted tiles, a strip bitmap may include multiple copies
+ * in X or Y to reduce loop overhead. In this case, we must distinguish:
+ * - The height of an individual strip, which is the same as
+ * the height of the bitmap being replicated (rep_height, H);
+ * - The height of the entire bitmap (size.y).
+ * Similarly, we must distinguish:
+ * - The shift per strip (rep_shift, S);
+ * - The shift for the entire bitmap (shift).
+ * Note that shift = (rep_shift * size.y / rep_height) mod rep_width,
+ * so the shift member of the structure is only an accelerator. It is,
+ * however, an important one, since it indicates whether the overall
+ * bitmap requires shifting or not.
+ *
+ * Note that for shifted tiles, size.y is the size of the stored bitmap
+ * (1 or more strips), and NOT the height of the actual tile. The latter
+ * is not stored in the structure at all: it can be computed as H * W /
+ * gcd(S, W).
+ *
+ * If the bitmap consists of a multiple of W / gcd(S, W) copies in Y, the
+ * effective shift is zero, reducing it to a tile. For simplicity, we
+ * require that if shift is non-zero, the bitmap height be less than H * W /
+ * gcd(S, W). I.e., we don't allow strip bitmaps that are large enough to
+ * include a complete tile but that don't include an integral number of
+ * tiles. Requirements:
+ * rep_shift < rep_width
+ * shift = (rep_shift * (size.y / rep_height)) % rep_width
+ */
+#define gx_strip_bitmap_common\
+ gx_tile_bitmap_common;\
+ ushort rep_shift;\
+ ushort shift
+typedef struct gx_strip_bitmap_s {
+ gx_strip_bitmap_common;
+} gx_strip_bitmap;
+
+#endif /* gxbitmap_INCLUDED */
diff --git a/gs/src/gxccache.c b/gs/src/gxccache.c
new file mode 100644
index 000000000..cb22e3d4f
--- /dev/null
+++ b/gs/src/gxccache.c
@@ -0,0 +1,440 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxccache.c */
+/* Fast case character cache routines for Ghostscript library */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gzcpath.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "gxxfont.h"
+#include "gscspace.h" /* for gsimage.h */
+#include "gsimage.h"
+#include "gxhttile.h"
+
+/* Forward references */
+private byte *compress_alpha_bits(P2(const cached_char *, gs_memory_t *));
+
+/* Define a scale factor of 1. */
+static const gs_log2_scale_point scale_log2_1 = { 0, 0 };
+
+/* Look up, and if necessary add, a font/matrix pair in the cache */
+cached_fm_pair *
+gx_lookup_fm_pair(gs_font *pfont, register const gs_state *pgs)
+{ float mxx = pgs->char_tm.xx, mxy = pgs->char_tm.xy,
+ myx = pgs->char_tm.yx, myy = pgs->char_tm.yy;
+ gs_font *font = pfont;
+ register gs_font_dir *dir = font->dir;
+ register cached_fm_pair *pair =
+ dir->fmcache.mdata + dir->fmcache.mnext;
+ int count = dir->fmcache.mmax;
+ gs_uid uid;
+
+ if ( font->FontType == ft_composite || font->PaintType != 0 )
+ { /* We can't cache by UID alone. */
+ uid_set_invalid(&uid);
+ }
+ else
+ { uid = ((gs_font_base *)font)->UID;
+ if ( uid_is_valid(&uid) )
+ font = 0;
+ }
+ while ( count-- )
+ { if ( pair == dir->fmcache.mdata )
+ pair += dir->fmcache.mmax;
+ pair--;
+ /* We have either a non-zero font and an invalid UID, */
+ /* or a zero font and a valid UID. */
+ /* We have to break up the test */
+ /* because of a bug in the Zortech compiler. */
+ if ( font != 0 )
+ { if ( pair->font != font )
+ continue;
+ }
+ else
+ { if ( !uid_equal(&pair->UID, &uid) ||
+ pair->FontType != pfont->FontType
+ )
+ continue;
+ }
+ if ( pair->mxx == mxx && pair->mxy == mxy &&
+ pair->myx == myx && pair->myy == myy
+ )
+ { if ( pair->font == 0 )
+ { pair->font = pfont;
+ if_debug2('k', "[k]updating pair 0x%lx with font 0x%lx\n",
+ (ulong)pair, (ulong)pfont);
+ }
+ else
+ { if_debug2('k', "[k]found pair 0x%lx: font=0x%lx\n",
+ (ulong)pair, (ulong)pair->font);
+ }
+ return pair;
+ }
+ }
+ return gx_add_fm_pair(dir, pfont, &uid, pgs);
+}
+
+/* Look up a glyph in the cache. */
+/* The character depth must be either 1 or alt_depth. */
+/* Return the cached_char or 0. */
+cached_char *
+gx_lookup_cached_char(const gs_font *pfont, const cached_fm_pair *pair,
+ gs_glyph glyph, int wmode, int alt_depth)
+{ gs_font_dir *dir = pfont->dir;
+ uint chi = chars_head_index(glyph, pair);
+ register cached_char *cc;
+ while ( (cc = dir->ccache.table[chi & dir->ccache.table_mask]) != 0 )
+ { if ( cc->code == glyph && cc_pair(cc) == pair &&
+ cc->wmode == wmode && (cc_depth(cc) == 1 || cc_depth(cc) == alt_depth)
+ )
+ { if_debug4('K', "[K]found 0x%lx (depth=%d) for glyph=0x%lx, wmode=%d\n",
+ (ulong)cc, cc_depth(cc), (ulong)glyph, wmode);
+ return cc;
+ }
+ chi++;
+ }
+ if_debug3('K', "[K]not found: glyph=0x%lx, wmode=%d, alt_depth=%d\n",
+ (ulong)glyph, wmode, alt_depth);
+ return 0;
+}
+
+/* Look up a character in an external font. */
+/* Return the cached_char or 0. */
+cached_char *
+gx_lookup_xfont_char(const gs_state *pgs, cached_fm_pair *pair,
+ gs_char chr, gs_glyph glyph, const gx_xfont_callbacks *callbacks, int wmode)
+{ gs_font *font = pair->font;
+ int enc_index;
+ gx_xfont *xf;
+ gx_xglyph xg;
+ gs_log2_scale_point log2_scale;
+ gs_point wxy;
+ gs_int_rect bbox;
+ cached_char *cc;
+
+ if ( font == 0 )
+ return NULL;
+ enc_index =
+ (font->FontType == ft_composite ? -1 :
+ ((gs_font_base *)font)->nearest_encoding_index);
+ if ( !pair->xfont_tried )
+ { /* Look for an xfont now. */
+ gx_lookup_xfont(pgs, pair, enc_index);
+ pair->xfont_tried = true;
+ }
+ xf = pair->xfont;
+ if ( xf == 0 )
+ return NULL;
+ { const gx_xfont_procs *procs = xf->common.procs;
+ if ( procs->char_xglyph2 == 0 )
+ { /* The xfont can't recognize reencoded fonts. */
+ /* Use the registered encoding only if this glyph */
+ /* is the same as the one in the registered encoding. */
+ if ( enc_index >= 0 &&
+ (*callbacks->known_encode)(chr, enc_index) != glyph
+ )
+ enc_index = -1;
+ xg = (*procs->char_xglyph)(xf, chr, enc_index, glyph,
+ callbacks->glyph_name);
+ }
+ else
+ { /* The xfont can recognize reencoded fonts. */
+ xg = (*procs->char_xglyph2)(xf, chr, enc_index, glyph,
+ callbacks);
+ }
+ if ( xg == gx_no_xglyph )
+ return NULL;
+ if ( (*procs->char_metrics)(xf, xg, wmode, &wxy, &bbox) < 0 )
+ return NULL;
+ }
+ log2_scale.x = log2_scale.y = 1;
+ cc = gx_alloc_char_bits(font->dir, NULL, NULL, bbox.q.x - bbox.p.x,
+ bbox.q.y - bbox.p.y, &log2_scale, 1);
+ if ( cc == 0 )
+ return NULL;
+ /* Success. Make the cache entry. */
+ cc->code = glyph;
+ cc->wmode = wmode;
+ cc->xglyph = xg;
+ cc->wxy.x = float2fixed(wxy.x);
+ cc->wxy.y = float2fixed(wxy.y);
+ cc->offset.x = int2fixed(-bbox.p.x);
+ cc->offset.y = int2fixed(-bbox.p.y);
+ if_debug5('k', "[k]xfont %s char %d/0x%x#0x%lx=>0x%lx\n",
+ font->font_name.chars, enc_index, (int)chr,
+ (ulong)glyph, (ulong)xg);
+ if_debug6('k', " wxy=(%g,%g) bbox=(%d,%d),(%d,%d)\n",
+ wxy.x, wxy.y, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ gx_add_cached_char(font->dir, NULL, cc, pair, &scale_log2_1);
+ return cc;
+}
+
+/* Copy a cached character to the screen. */
+/* Assume the caller has already done gx_color_load. */
+/* Return 0 if OK, 1 if we couldn't do the operation but no error */
+/* should be signalled, or a negative error code. */
+int
+gx_image_cached_char(register gs_show_enum *penum, register cached_char *cc)
+{ register gs_state *pgs = penum->pgs;
+ gx_device_color *pdevc = pgs->dev_color;
+ int x, y, w, h, depth;
+ int code;
+ gs_fixed_point pt;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_device *orig_dev = dev;
+ gx_device_clip cdev;
+ gx_xglyph xg = cc->xglyph;
+ gx_xfont *xf;
+ byte *bits;
+
+top: code = gx_path_current_point_inline(pgs->path, &pt);
+ if ( code < 0 ) return code;
+ /*
+ * If the character doesn't lie entirely within the inner
+ * clipping rectangle, we set up an intermediate clipping device.
+ * Note that if the original device implements fill_mask, we may
+ * never actually use the clipping device.
+ */
+ pt.x -= cc->offset.x;
+ x = fixed2int_var_rounded(pt.x) + penum->ftx;
+ pt.y -= cc->offset.y;
+ y = fixed2int_var_rounded(pt.y) + penum->fty;
+ w = cc->width;
+ h = cc->height;
+#ifdef DEBUG
+ if ( gs_debug_c('K') )
+ { if ( cc_has_bits(cc) )
+ debug_dump_bitmap(cc_bits(cc), cc_raster(cc), h,
+ "[K]bits");
+ else
+ dputs("[K]no bits\n");
+ dprintf3("[K]copying 0x%lx, offset=(%g,%g)\n", (ulong)cc,
+ fixed2float(-cc->offset.x),
+ fixed2float(-cc->offset.y));
+ dprintf6(" at (%g,%g)+(%d,%d)->(%d,%d)\n",
+ fixed2float(pt.x), fixed2float(pt.y),
+ penum->ftx, penum->fty, x, y);
+ }
+#endif
+ if ( (x < penum->ibox.p.x || x + w > penum->ibox.q.x ||
+ y < penum->ibox.p.y || y + h > penum->ibox.q.y) &&
+ dev != (gx_device *)&cdev /* might be 2nd time around */
+ )
+ { /* Check for the character falling entirely outside */
+ /* the clipping region. */
+ if ( x >= penum->obox.q.x || x + w <= penum->obox.p.x ||
+ y >= penum->obox.q.y || y + h <= penum->obox.p.y
+ )
+ return 0; /* nothing to do */
+ gx_make_clip_device(&cdev, &cdev, &pgs->clip_path->list);
+ cdev.target = dev;
+ dev = (gx_device *)&cdev;
+ (*dev_proc(dev, open_device))(dev);
+ if_debug0('K', "[K](clipping)\n");
+ }
+ /* If an xfont can render this character, use it. */
+ if ( xg != gx_no_xglyph && (xf = cc_pair(cc)->xfont) != 0 )
+ { int cx = x + fixed2int(cc->offset.x);
+ int cy = y + fixed2int(cc->offset.y);
+ /*
+ * Note that we prefer a 1-bit xfont implementation over
+ * a multi-bit cached bitmap. Eventually we should change
+ * the xfont interface so it can deliver multi-bit bitmaps,
+ * or else implement oversampling for xfonts.
+ */
+ if ( gs_color_writes_pure(pgs) )
+ { code = (*xf->common.procs->render_char)(xf, xg,
+ dev, cx, cy, pdevc->colors.pure, 0);
+ if_debug8('K', "[K]render_char display: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d, color=0x%lx => %d\n",
+ (ulong)xf, (ulong)xg, (ulong)dev,
+ dev->dname, cx, cy,
+ (ulong)pdevc->colors.pure, code);
+ if ( code == 0 )
+ return_check_interrupt(0);
+ }
+ /* Can't render directly. If we don't have a bitmap yet, */
+ /* get it from the xfont now. */
+ if ( !cc_has_bits(cc) )
+ { gx_device_memory mdev;
+ gs_make_mem_mono_device(&mdev, 0, dev);
+ gx_open_cache_device(&mdev, cc);
+ code = (*xf->common.procs->render_char)(xf, xg,
+ (gx_device *)&mdev, cx - x, cy - y,
+ (gx_color_index)1, 1);
+ if_debug7('K', "[K]render_char to bits: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d => %d\n",
+ (ulong)xf, (ulong)xg, (ulong)&mdev,
+ mdev.dname, cx - x, cy - y, code);
+ if ( code != 0 )
+ return_check_interrupt(1);
+ gx_add_char_bits(cc_pair(cc)->font->dir,
+ cc, &scale_log2_1);
+ /* gx_add_char_bits may change width, height, */
+ /* raster, and/or offset. It's easiest to */
+ /* start over from the top. Clear xg so that */
+ /* we don't waste time trying render_char again. */
+ xg = gx_no_xglyph;
+ goto top;
+ }
+ }
+ /*
+ * No xfont. Render from the cached bits. If the cached bits
+ * have more than 1 bit of alpha, and the color isn't pure or
+ * the copy_alpha operation fails, construct a single-bit mask
+ * by taking the high-order alpha bit.
+ */
+ bits = cc_bits(cc);
+ depth = cc_depth(cc);
+ if ( orig_dev->std_procs.fill_mask != gx_default_fill_mask ||
+ !lop_no_S_is_T(pgs->log_op)
+ )
+ { code = (*dev_proc(orig_dev, fill_mask))
+ (orig_dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, pdevc, depth, pgs->log_op, pgs->clip_path);
+ if ( code >= 0 )
+ goto done;
+ }
+ else if ( gs_color_writes_pure(pgs) )
+ { gx_color_index color = pdevc->colors.pure;
+ if ( depth > 1 )
+ { code = (*dev_proc(dev, copy_alpha))
+ (dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, color, depth);
+ if ( code >= 0 )
+ return_check_interrupt(0);
+ /* copy_alpha failed, construct a monobit mask. */
+ bits = compress_alpha_bits(cc, &gs_memory_default);
+ if ( bits == 0 )
+ return 1; /* VMerror, but recoverable */
+ }
+ code = (*dev_proc(dev, copy_mono))
+ (dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, gx_no_color_index, pdevc->colors.pure);
+ goto done;
+ }
+ if ( depth > 1 )
+ { /* Complex color or fill_mask / copy_alpha failed, */
+ /* construct a monobit mask. */
+ bits = compress_alpha_bits(cc, &gs_memory_default);
+ if ( bits == 0 )
+ return 1; /* VMerror, but recoverable */
+
+ }
+ { /* Use imagemask to render the character. */
+ gs_image_enum *pie = gs_image_enum_alloc(&gs_memory_default,
+ "image_char(image_enum)");
+ gs_image_t image;
+ int iy;
+ uint used;
+
+ if ( pie == 0 )
+ { if ( bits != cc_bits(cc) )
+ gs_free_object(&gs_memory_default, bits,
+ "compress_alpha_bits");
+ return 1; /* VMerror, but recoverable */
+ }
+ /* Make a matrix that will place the image */
+ /* at (x,y) with no transformation. */
+ gs_image_t_init_mask(&image, true);
+#define mat image.ImageMatrix
+ gs_make_translation((floatp)-x, (floatp)-y, &mat);
+ gs_matrix_multiply(&ctm_only(pgs), &mat, &mat);
+#undef mat
+ image.Width = w;
+ image.Height = h;
+ image.adjust = false;
+ code = gs_image_init(pie, &image, false, pgs);
+ switch ( code )
+ {
+ case 1: /* empty image */
+ code = 0;
+ default:
+ break;
+ case 0:
+ for ( iy = 0; iy < h && code >= 0; iy++ )
+ code = gs_image_next(pie, bits + iy * cc_raster(cc),
+ (w + 7) >> 3, &used);
+ gs_image_cleanup(pie);
+ }
+ gs_free_object(&gs_memory_default, pie,
+ "image_char(image_enum)");
+ }
+done: if ( bits != cc_bits(cc) )
+ gs_free_object(&gs_memory_default, bits, "compress_alpha_bits");
+ if ( code > 0 )
+ code = 0;
+ return_check_interrupt(code);
+}
+
+/* ------ Image manipulation ------ */
+
+/*
+ * Compress a mask with 2 or 4 bits of alpha to a monobit mask.
+ * Allocate and return the address of the monobit mask.
+ */
+private byte *
+compress_alpha_bits(const cached_char *cc, gs_memory_t *mem)
+{ const byte *data = cc_const_bits(cc);
+ uint width = cc->width;
+ uint height = cc->height;
+ int log2_scale = cc_depth(cc);
+ int scale = 1 << log2_scale;
+ uint sraster = cc_raster(cc);
+ uint sskip = sraster - ((width * scale + 7) >> 3);
+ uint draster = bitmap_raster(width);
+ uint dskip = draster - ((width + 7) >> 3);
+ byte *mask = gs_alloc_bytes(mem, draster * height,
+ "compress_alpha_bits");
+ const byte *sptr = data;
+ byte *dptr = mask;
+ uint h;
+
+ if ( mask == 0 )
+ return 0;
+ for ( h = height; h; --h )
+ { byte sbit = 0x80;
+ byte d = 0;
+ byte dbit = 0x80;
+ uint w;
+
+ for ( w = width; w; --w )
+ { if ( *sptr & sbit )
+ d += dbit;
+ if ( !(sbit >>= log2_scale) )
+ sbit = 0x80, sptr++;
+ if ( !(dbit >>= 1) )
+ dbit = 0x80, dptr++, d = 0;
+ }
+ if ( dbit != 0x80 )
+ *dptr++ = d;
+ for ( w = dskip; w != 0; --w )
+ *dptr++ = 0;
+ sptr += sskip;
+ }
+ return mask;
+}
diff --git a/gs/src/gxccman.c b/gs/src/gxccman.c
new file mode 100644
index 000000000..681328a7d
--- /dev/null
+++ b/gs/src/gxccman.c
@@ -0,0 +1,763 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxccman.c */
+/* Character cache management routines for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsbitops.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "gxxfont.h"
+
+/* Define the descriptors for the cache structures. */
+private_st_cached_fm_pair();
+private_st_cached_fm_pair_elt();
+/*private_st_cached_char();*/ /* unused */
+private_st_cached_char_ptr(); /* unused */
+private_st_cached_char_ptr_elt();
+/* GC procedures */
+/* We do all the work in font_dir_enum/reloc_ptrs in gsfont.c. */
+/* See gxfcache.h for details. */
+private ENUM_PTRS_BEGIN(cc_ptr_enum_ptrs) return 0;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cc_ptr_reloc_ptrs) {
+} RELOC_PTRS_END
+
+/* Forward references */
+private gx_xfont *lookup_xfont_by_name(P6(gx_device *, gx_xfont_procs *, gs_font_name *, int, const cached_fm_pair *, const gs_matrix *));
+private cached_char *alloc_char(P2(gs_font_dir *, ulong));
+private cached_char *alloc_char_in_chunk(P2(gs_font_dir *, ulong));
+private void hash_remove_cached_char(P2(gs_font_dir *, uint));
+private void shorten_cached_char(P3(gs_font_dir *, cached_char *, uint));
+
+/* ====== Initialization ====== */
+
+/* Allocate and initialize the character cache elements of a font directory. */
+int
+gx_char_cache_alloc(gs_memory_t *mem, register gs_font_dir *pdir,
+ uint bmax, uint mmax, uint cmax, uint upper)
+{ /* Since we use open hashing, we must increase cmax somewhat. */
+ uint chsize = (cmax + (cmax >> 1)) | 31;
+ cached_fm_pair *mdata;
+ cached_char **chars;
+
+ /* Round up chsize to a power of 2. */
+ while ( chsize & (chsize + 1) )
+ chsize |= chsize >> 1;
+ chsize++;
+ mdata = gs_alloc_struct_array(mem, mmax, cached_fm_pair,
+ &st_cached_fm_pair_element,
+ "font_dir_alloc(mdata)");
+ chars = gs_alloc_struct_array(mem, chsize, cached_char *,
+ &st_cached_char_ptr_element,
+ "font_dir_alloc(chars)");
+ if ( mdata == 0 || chars == 0 )
+ { gs_free_object(mem, chars, "font_dir_alloc(chars)");
+ gs_free_object(mem, mdata, "font_dir_alloc(mdata)");
+ return_error(gs_error_VMerror);
+ }
+ pdir->fmcache.mmax = mmax;
+ pdir->fmcache.mdata = mdata;
+ pdir->ccache.memory = mem;
+ pdir->ccache.bmax = bmax;
+ pdir->ccache.cmax = cmax;
+ pdir->ccache.lower = upper / 10;
+ pdir->ccache.upper = upper;
+ pdir->ccache.table = chars;
+ pdir->ccache.table_mask = chsize - 1;
+ gx_char_cache_init(pdir);
+ return 0;
+}
+
+/* Initialize the character cache. */
+void
+gx_char_cache_init(register gs_font_dir *dir)
+{ int i;
+ cached_fm_pair *pair;
+ char_cache_chunk *cck =
+ (char_cache_chunk *)gs_malloc(1, sizeof(char_cache_chunk),
+ "initial_chunk");
+
+ dir->fmcache.msize = 0;
+ dir->fmcache.mnext = 0;
+ gx_bits_cache_chunk_init(cck, NULL, 0);
+ gx_bits_cache_init((gx_bits_cache *)&dir->ccache, cck);
+ dir->ccache.bspace = 0;
+ memset((char *)dir->ccache.table, 0,
+ (dir->ccache.table_mask + 1) * sizeof(cached_char *));
+ for ( i = 0, pair = dir->fmcache.mdata;
+ i < dir->fmcache.mmax; i++, pair++
+ )
+ { pair->index = i;
+ fm_pair_init(pair);
+ }
+}
+
+/* ====== Purging ====== */
+
+/* Purge from the character cache all entries selected by */
+/* a client-supplied procedure. */
+void
+gx_purge_selected_cached_chars(gs_font_dir *dir,
+ bool (*proc)(P2(cached_char *, void *)), void *proc_data)
+{ int chi;
+ int cmax = dir->ccache.table_mask;
+
+ for ( chi = 0; chi <= cmax; )
+ { cached_char *cc = dir->ccache.table[chi];
+ if ( cc != 0 && (*proc)(cc, proc_data) )
+ { hash_remove_cached_char(dir, chi);
+ gx_free_cached_char(dir, cc);
+ }
+ else
+ chi++;
+ }
+}
+
+/* ====== Font-level routines ====== */
+
+/* Add a font/matrix pair to the cache. */
+/* (This is only exported for gxccache.c.) */
+cached_fm_pair *
+gx_add_fm_pair(register gs_font_dir *dir, gs_font *font, const gs_uid *puid,
+ const gs_state *pgs)
+{ register cached_fm_pair *pair =
+ dir->fmcache.mdata + dir->fmcache.mnext;
+ cached_fm_pair *mend =
+ dir->fmcache.mdata + dir->fmcache.mmax;
+
+ if ( dir->fmcache.msize == dir->fmcache.mmax ) /* cache is full */
+ { /* Prefer an entry with num_chars == 0, if any. */
+ int count;
+ for ( count = dir->fmcache.mmax;
+ --count >= 0 && pair->num_chars != 0;
+ )
+ if ( ++pair == mend )
+ pair = dir->fmcache.mdata;
+ gs_purge_fm_pair(dir, pair, 0);
+ }
+ else
+ { /* Look for an empty entry. (We know there is one.) */
+ while ( !fm_pair_is_free(pair) )
+ if ( ++pair == mend )
+ pair = dir->fmcache.mdata;
+ }
+ dir->fmcache.msize++;
+ dir->fmcache.mnext = pair + 1 - dir->fmcache.mdata;
+ if ( dir->fmcache.mnext == dir->fmcache.mmax )
+ dir->fmcache.mnext = 0;
+ pair->font = font;
+ pair->UID = *puid;
+ pair->FontType = font->FontType;
+ /* The OSF/1 compiler doesn't like casting a pointer to */
+ /* a shorter int.... */
+ pair->hash = (uint)(ulong)pair % 549; /* scramble bits */
+ pair->mxx = pgs->char_tm.xx, pair->mxy = pgs->char_tm.xy;
+ pair->myx = pgs->char_tm.yx, pair->myy = pgs->char_tm.yy;
+ pair->num_chars = 0;
+ pair->xfont_tried = false;
+ pair->xfont = 0;
+ if_debug8('k', "[k]adding pair 0x%lx: font=0x%lx [%g %g %g %g] UID %ld, 0x%lx\n",
+ (ulong)pair, (ulong)font,
+ pair->mxx, pair->mxy, pair->myx, pair->myy,
+ (long)pair->UID.id, (ulong)pair->UID.xvalues);
+ return pair;
+}
+
+/* Look up the xfont for a font/matrix pair. */
+/* (This is only exported for gxccache.c.) */
+void
+gx_lookup_xfont(const gs_state *pgs, cached_fm_pair *pair, int encoding_index)
+{ gx_device *dev = gs_currentdevice(pgs);
+ gx_device *fdev = (*dev_proc(dev, get_xfont_device))(dev);
+ gs_font *font = pair->font;
+ gx_xfont_procs *procs = (*dev_proc(fdev, get_xfont_procs))(fdev);
+ gx_xfont *xf = 0;
+
+ /* We mustn't attempt to use xfonts for stroked characters, */
+ /* because such characters go outside their bounding box. */
+ if ( procs != 0 && font->PaintType == 0 )
+ { gs_matrix mat;
+
+ mat.xx = pair->mxx, mat.xy = pair->mxy;
+ mat.yx = pair->myx, mat.yy = pair->myy;
+ mat.tx = 0, mat.ty = 0;
+ /* xfonts can outlive their invocations, */
+ /* but restore purges them properly. */
+ pair->memory = pgs->memory;
+ if ( font->key_name.size != 0 )
+ xf = lookup_xfont_by_name(fdev, procs,
+ &font->key_name, encoding_index,
+ pair, &mat);
+#define font_name_eq(pfn1,pfn2)\
+ ((pfn1)->size == (pfn2)->size && (pfn1)->size != 0 &&\
+ !memcmp((char *)(pfn1)->chars, (char *)(pfn2)->chars, (pfn1)->size))
+ if ( xf == 0 && font->font_name.size != 0 &&
+ /* Avoid redundant lookup */
+ !font_name_eq(&font->font_name, &font->key_name)
+ )
+ xf = lookup_xfont_by_name(fdev, procs,
+ &font->font_name, encoding_index,
+ pair, &mat);
+ if ( xf == 0 && font->FontType != ft_composite &&
+ uid_is_valid(&((gs_font_base *)font)->UID)
+ )
+ { /* Look for an original font with the same UID. */
+ gs_font_dir *pdir = font->dir;
+ gs_font *pfont;
+
+ for ( pfont = pdir->orig_fonts; pfont != 0;
+ pfont = pfont->next
+ )
+ { if ( pfont->FontType != ft_composite &&
+ uid_equal(&((gs_font_base *)pfont)->UID,
+ &((gs_font_base *)font)->UID) &&
+ pfont->key_name.size != 0 &&
+ !font_name_eq(&font->key_name,
+ &pfont->key_name)
+ )
+ { xf = lookup_xfont_by_name(fdev, procs,
+ &pfont->key_name,
+ encoding_index, pair, &mat);
+ if ( xf != 0 )
+ break;
+ }
+ }
+ }
+ }
+ pair->xfont = xf;
+}
+
+/* ------ Internal routines ------ */
+
+/* Purge from the caches all references to a given font/matrix pair, */
+/* or just characters that depend on its xfont. */
+#define cpair ((cached_fm_pair *)vpair)
+private bool
+purge_fm_pair_char(cached_char *cc, void *vpair)
+{ return cc_pair(cc) == cpair;
+}
+private bool
+purge_fm_pair_char_xfont(cached_char *cc, void *vpair)
+{ return cc_pair(cc) == cpair && cpair->xfont == 0 && !cc_has_bits(cc);
+}
+#undef cpair
+void
+gs_purge_fm_pair(gs_font_dir *dir, cached_fm_pair *pair, int xfont_only)
+{ if_debug2('k', "[k]purging pair 0x%lx%s\n",
+ (ulong)pair, (xfont_only ? " (xfont only)" : ""));
+ if ( pair->xfont != 0 )
+ { (*pair->xfont->common.procs->release)(pair->xfont,
+ pair->memory);
+ pair->xfont_tried = false;
+ pair->xfont = 0;
+ }
+ gx_purge_selected_cached_chars(dir,
+ (xfont_only ? purge_fm_pair_char_xfont :
+ purge_fm_pair_char),
+ pair);
+ if ( !xfont_only )
+ {
+#ifdef DEBUG
+ if ( pair->num_chars != 0 )
+ { lprintf1("Error in gs_purge_fm_pair: num_chars =%d\n",
+ pair->num_chars);
+ }
+#endif
+ fm_pair_set_free(pair);
+ dir->fmcache.msize--;
+ }
+}
+
+/* Look up an xfont by name. */
+/* The caller must already have done get_xfont_device to get the proper */
+/* device to pass as the first argument to lookup_font. */
+private gx_xfont *
+lookup_xfont_by_name(gx_device *fdev, gx_xfont_procs *procs,
+ gs_font_name *pfstr, int encoding_index, const cached_fm_pair *pair,
+ const gs_matrix *pmat)
+{ gx_xfont *xf;
+ if_debug5('k', "[k]lookup xfont %s [%g %g %g %g]\n",
+ pfstr->chars, pmat->xx, pmat->xy, pmat->yx, pmat->yy);
+ xf = (*procs->lookup_font)(fdev,
+ &pfstr->chars[0], pfstr->size,
+ encoding_index, &pair->UID,
+ pmat, pair->memory);
+ if_debug1('k', "[k]... xfont=0x%lx\n", (ulong)xf);
+ return xf;
+}
+
+/* ====== Character-level routines ====== */
+
+/*
+ * Allocate storage for caching a rendered character with possible
+ * oversampling and/or alpha. Return the cached_char if OK, 0 if too big.
+ * If the character is being oversampled, make the size decision
+ * on the basis of the final (scaled-down) size.
+ *
+ * The iwidth and iheight parameters include scaling up for oversampling
+ * (multiplication by 1 << pscale->{x,y}.)
+ * The depth parameter is the final number of alpha bits;
+ * depth <= x scale * y scale.
+ * If dev == NULL, this is an xfont-only entry.
+ * If dev != NULL, set up the memory device(s); in this case, if dev2 is
+ * not NULL, dev should be an alpha-buffer device with dev2 (an alpha
+ * device) as target.
+ */
+cached_char *
+gx_alloc_char_bits(gs_font_dir *dir, gx_device_memory *dev,
+ gx_device_memory *dev2, ushort iwidth, ushort iheight,
+ const gs_log2_scale_point *pscale, int depth)
+{ int log2_xscale = pscale->x;
+ int log2_yscale = pscale->y;
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ uint nwidth_bits = (iwidth >> log2_xscale) << log2_depth;
+ ulong isize, icdsize;
+ uint iraster;
+ cached_char *cc;
+ gx_device_memory mdev;
+ gx_device_memory *pdev = dev;
+ gx_device_memory *pdev2;
+
+ if ( dev == NULL )
+ { mdev.memory = 0;
+ mdev.target = 0;
+ pdev = &mdev;
+ }
+ pdev2 = (dev2 == 0 ? pdev : dev2);
+
+ /* Compute the scaled-down bitmap size, and test against */
+ /* the maximum cachable character size. */
+
+ iraster = bitmap_raster(nwidth_bits);
+ if ( iraster != 0 && iheight >> log2_yscale > dir->ccache.upper / iraster )
+ { if_debug5('k', "[k]no cache bits: scale=%dx%d, raster/scale=%u, height/scale=%u, upper=%u\n",
+ 1 << log2_xscale, 1 << log2_yscale,
+ iraster, iheight, dir->ccache.upper);
+ return 0; /* too big */
+ }
+
+ /* Compute the actual bitmap size(s) and allocate the bits. */
+
+ if ( dev2 == 0 )
+ { /* Render to a full (possibly oversampled) bitmap; */
+ /* compress (if needed) when done. */
+ gs_make_mem_mono_device(pdev, pdev->memory, pdev->target);
+ pdev->width = iwidth;
+ pdev->height = iheight;
+ isize = gdev_mem_bitmap_size(pdev);
+ }
+ else
+ { /* Use an alpha-buffer device to compress as we go. */
+ gs_make_mem_alpha_device(dev2, dev2->memory, NULL, depth);
+ dev2->width = iwidth >> log2_xscale;
+ dev2->height = iheight >> log2_yscale;
+ gs_make_mem_abuf_device(dev, dev->memory, (gx_device *)dev2,
+ pscale, depth, 0);
+ dev->width = iwidth;
+ dev->height = 2 << log2_yscale;
+ isize = gdev_mem_bitmap_size(dev) +
+ gdev_mem_bitmap_size(dev2);
+ }
+ icdsize = isize + sizeof_cached_char;
+ cc = alloc_char(dir, icdsize);
+ if ( cc == 0 )
+ return 0;
+ if_debug4('k', "[k]adding char 0x%lx:%u(%u,%u)\n",
+ (ulong)cc, (uint)icdsize, iwidth, iheight);
+
+ /* Fill in the entry. */
+
+ cc_set_depth(cc, depth);
+ cc->xglyph = gx_no_xglyph;
+ /* Set the width and height to those of the device. */
+ /* Note that if we are oversampling without an alpha buffer. */
+ /* these are not the final unscaled dimensions. */
+ cc->width = pdev2->width;
+ cc->height = pdev2->height;
+ cc->shift = 0;
+ cc_set_raster(cc, gdev_mem_raster(pdev2));
+ cc_set_pair_only(cc, 0); /* not linked in yet */
+ cc->id = gx_no_bitmap_id;
+
+ /* Open the cache device(s). */
+
+ if ( dev2 )
+ { /* The second device is an alpha device that targets */
+ /* the real storage for the character. */
+ byte *bits = cc_bits(cc);
+ uint bsize = (uint)gdev_mem_bitmap_size(dev2);
+
+ memset(bits, 0, bsize);
+ dev2->base = bits;
+ (*dev_proc(dev2, open_device))((gx_device *)dev2);
+ dev->base = bits + bsize;
+ (*dev_proc(dev, open_device))((gx_device *)dev);
+ }
+ else if ( dev )
+ gx_open_cache_device(dev, cc);
+
+ return cc;
+}
+
+/* Open the cache device. */
+void
+gx_open_cache_device(gx_device_memory *dev, cached_char *cc)
+{ byte *bits = cc_bits(cc);
+
+ dev->width = cc->width;
+ dev->height = cc->height;
+ memset((char *)bits, 0, (uint)gdev_mem_bitmap_size(dev));
+ dev->base = bits;
+ (*dev_proc(dev, open_device))((gx_device *)dev); /* initialize */
+}
+
+/* Remove a character from the cache. */
+void
+gx_free_cached_char(gs_font_dir *dir, cached_char *cc)
+{ char_cache_chunk *cck = cc->chunk;
+
+ dir->ccache.chunks = cck;
+ dir->ccache.cnext = (byte *)cc - cck->data;
+ if ( cc_pair(cc) != 0 )
+ { /* might be allocated but not added to table yet */
+ cc_pair(cc)->num_chars--;
+ }
+ if_debug2('k', "[k]freeing char 0x%lx, pair=0x%lx\n",
+ (ulong)cc, (ulong)cc_pair(cc));
+ gx_bits_cache_free((gx_bits_cache *)&dir->ccache, &cc->head, cck);
+}
+
+/* Add a character to the cache */
+void
+gx_add_cached_char(gs_font_dir *dir, gx_device_memory *dev,
+ cached_char *cc, cached_fm_pair *pair, const gs_log2_scale_point *pscale)
+{ if_debug5('k', "[k]chaining char 0x%lx: pair=0x%lx, glyph=0x%lx, wmode=%d, depth=%d\n",
+ (ulong)cc, (ulong)pair, (ulong)cc->code,
+ cc->wmode, cc_depth(cc));
+ if ( dev != NULL )
+ { static const gs_log2_scale_point no_scale = { 0, 0 };
+ /* Close the device, to flush the alpha buffer if any. */
+ (*dev_proc(dev, close_device))((gx_device *)dev);
+ gx_add_char_bits(dir, cc,
+ (gs_device_is_abuf((gx_device *)dev) ?
+ &no_scale : pscale));
+ }
+ /* Add the new character to the hash table. */
+ { uint chi = chars_head_index(cc->code, pair);
+ while ( dir->ccache.table[chi &= dir->ccache.table_mask] != 0 )
+ chi++;
+ dir->ccache.table[chi] = cc;
+ cc_set_pair(cc, pair);
+ pair->num_chars++;
+ }
+}
+
+/* Adjust the bits of a newly-rendered character, by unscaling */
+/* and compressing or converting to alpha values if necessary. */
+void
+gx_add_char_bits(gs_font_dir *dir, cached_char *cc,
+ const gs_log2_scale_point *plog2_scale)
+{ int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
+ uint raster = cc_raster(cc);
+ byte *bits = cc_bits(cc);
+ int depth = cc_depth(cc);
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ uint nwidth_bits, nraster;
+ gs_int_rect bbox;
+
+#ifdef DEBUG
+ if ( cc->width % (1 << log2_x) != 0 ||
+ cc->height % (1 << log2_y) != 0
+ )
+ { lprintf4("size %d,%d not multiple of scale %d,%d!\n",
+ cc->width, cc->height,
+ 1 << log2_x, 1 << log2_y);
+ cc->width &= -1 << log2_x;
+ cc->height &= -1 << log2_y;
+ }
+#endif
+
+ /*
+ * Compute the bounding box before compressing.
+ * We may have to scan more bits, but this is a lot faster than
+ * compressing the white space. Note that all bbox values are
+ * in bits, not pixels.
+ */
+
+ bits_bounding_box(bits, cc->height, raster, &bbox);
+
+ /*
+ * If the character was oversampled, compress it now.
+ * In this case we know that log2_depth <= log2_x.
+ * If the character was not oversampled, or if we converted
+ * oversampling to alpha dynamically (using an alpha buffer
+ * intermediate device), log2_x and log2_y are both zero,
+ * but in the latter case we may still have depth > 1.
+ */
+
+ if ( (log2_x | log2_y) != 0 )
+ { if_debug5('k', "[k]compressing %dx%d by %dx%d to depth=%d\n",
+ cc->width, cc->height, 1 << log2_x, 1 << log2_y,
+ depth);
+ if ( gs_debug_c('K') )
+ debug_dump_bitmap(bits, raster, cc->height,
+ "[K]uncompressed bits");
+ /* Truncate/round the bbox to a multiple of the scale. */
+ { int scale_x = 1 << log2_x;
+ bbox.p.x &= -scale_x;
+ bbox.q.x = (bbox.q.x + scale_x - 1) & -scale_x;
+ }
+ { int scale_y = 1 << log2_y;
+ bbox.p.y &= -scale_y;
+ bbox.q.y = (bbox.q.y + scale_y - 1) & -scale_y;
+ }
+ cc->width = (bbox.q.x - bbox.p.x) >> log2_x;
+ cc->height = (bbox.q.y - bbox.p.y) >> log2_y;
+ nwidth_bits = cc->width << log2_depth;
+ nraster = bitmap_raster(nwidth_bits);
+ bits_compress_scaled(bits + raster * bbox.p.y, bbox.p.x,
+ cc->width << log2_x,
+ cc->height << log2_y,
+ raster,
+ bits, nraster, plog2_scale, log2_depth);
+ bbox.p.x >>= log2_x;
+ bbox.p.y >>= log2_y;
+ }
+ else
+ { /* No oversampling, just remove white space. */
+ const byte *from = bits + raster * bbox.p.y + (bbox.p.x >> 3);
+
+ cc->height = bbox.q.y - bbox.p.y;
+ /*
+ * We'd like to trim off left and right blank space,
+ * but currently we're only willing to move bytes, not bits.
+ * (If we ever want to do better, we must remember that
+ * we can only trim whole pixels, and a pixel may occupy
+ * more than one bit.)
+ */
+ bbox.p.x &= ~7; /* adjust to byte boundary */
+ bbox.p.x >>= log2_depth; /* bits => pixels */
+ bbox.q.x = (bbox.q.x + depth - 1) >> log2_depth; /* ditto */
+ cc->width = bbox.q.x - bbox.p.x;
+ nwidth_bits = cc->width << log2_depth;
+ nraster = bitmap_raster(nwidth_bits);
+ if ( bbox.p.x != 0 || nraster != raster )
+ { /* Move the bits down and over. */
+ byte *to = bits;
+ uint n = cc->height;
+ /* We'd like to move only
+ uint nbytes = (nwidth_bits + 7) >> 3;
+ * bytes per scan line, but unfortunately this drops
+ * the guaranteed zero padding at the end.
+ */
+
+ for ( ; n--; from += raster, to += nraster )
+ memmove(to, from, /*nbytes*/nraster);
+ }
+ else if ( bbox.p.y != 0 )
+ { /* Just move the bits down. */
+ memmove(bits, from, raster * cc->height);
+ }
+ }
+
+ /* Adjust the offsets to account for removed white space. */
+
+ cc->offset.x -= int2fixed(bbox.p.x);
+ cc->offset.y -= int2fixed(bbox.p.y);
+
+ /* Discard the memory device overhead that follows the bits, */
+ /* and any space reclaimed from unscaling or compression. */
+
+ cc_set_raster(cc, nraster);
+ { uint diff = round_down(cc->head.size - sizeof_cached_char -
+ nraster * cc->height,
+ align_cached_char_mod);
+
+ if ( diff >= sizeof(cached_char_head) )
+ { shorten_cached_char(dir, cc, diff);
+ if_debug2('K', "[K]shortening char 0x%lx by %u (adding)\n",
+ (ulong)cc, diff);
+ }
+ }
+
+ /* Assign a bitmap id. */
+
+ cc->id = gs_next_ids(1);
+}
+
+/* Purge from the caches all references to a given font. */
+void
+gs_purge_font_from_char_caches(gs_font_dir *dir, const gs_font *font)
+{ cached_fm_pair *pair = dir->fmcache.mdata;
+ int count = dir->fmcache.mmax;
+
+ if_debug1('k', "[k]purging font 0x%lx\n",
+ (ulong)font);
+ while ( count-- )
+ { if ( pair->font == font )
+ { if ( uid_is_valid(&pair->UID) )
+ { /* Keep the entry. */
+ pair->font = 0;
+ }
+ else
+ gs_purge_fm_pair(dir, pair, 0);
+ }
+ pair++;
+ }
+}
+
+/* ------ Internal routines ------ */
+
+/* Allocate data space for a cached character, adding a new chunk if needed. */
+private cached_char *
+alloc_char(gs_font_dir *dir, ulong icdsize)
+{ /* Try allocating at the current position first. */
+ cached_char *cc = alloc_char_in_chunk(dir, icdsize);
+
+ if ( cc == 0 )
+ { if ( dir->ccache.bspace < dir->ccache.bmax )
+ { /* Allocate another chunk. */
+ char_cache_chunk *cck_prev = dir->ccache.chunks;
+ char_cache_chunk *cck;
+ uint cksize = dir->ccache.bmax / 5 + 1;
+ uint tsize = dir->ccache.bmax - dir->ccache.bspace;
+ byte *cdata;
+
+ if ( cksize > tsize )
+ cksize = tsize;
+ if ( icdsize + sizeof(cached_char_head) > cksize )
+ { if_debug2('k', "[k]no cache bits: cdsize+head=%lu, cksize=%u\n",
+ icdsize + sizeof(cached_char_head),
+ cksize);
+ return 0; /* wouldn't fit */
+ }
+ cck = (char_cache_chunk *)gs_malloc(1, sizeof(*cck),
+ "char cache chunk");
+ if ( cck == 0 )
+ return 0;
+ cdata = (byte *)gs_malloc(cksize, 1,
+ "char cache chunk");
+ if ( cdata == 0 )
+ { gs_free((char *)cck, 1, sizeof(*cck),
+ "char cache chunk");
+ return 0;
+ }
+ gx_bits_cache_chunk_init(cck, cdata, cksize);
+ cck->next = cck_prev->next;
+ cck_prev->next = cck;
+ dir->ccache.bspace += cksize;
+ dir->ccache.chunks = cck;
+ }
+ else
+ { /* Cycle through existing chunks. */
+ char_cache_chunk *cck_init = dir->ccache.chunks;
+ char_cache_chunk *cck = cck_init;
+ while ( (dir->ccache.chunks = cck = cck->next) != cck_init )
+ { dir->ccache.cnext = 0;
+ cc = alloc_char_in_chunk(dir, icdsize);
+ if ( cc != 0 )
+ return cc;
+ }
+ }
+ dir->ccache.cnext = 0;
+ cc = alloc_char_in_chunk(dir, icdsize);
+ }
+ return cc;
+}
+
+/* Allocate a character in the current chunk. */
+private cached_char *
+alloc_char_in_chunk(gs_font_dir *dir, ulong icdsize)
+{ char_cache_chunk *cck = dir->ccache.chunks;
+ cached_char_head *cch;
+#define cc ((cached_char *)cch)
+
+ while ( gx_bits_cache_alloc((gx_bits_cache *)&dir->ccache,
+ icdsize, &cch) < 0
+ )
+ { if ( cch == 0 )
+ { /* Not enough room to allocate in this chunk. */
+ return 0;
+ }
+ { /* Free the character */
+ cached_fm_pair *pair = cc_pair(cc);
+
+ if ( pair != 0 )
+ { uint chi = chars_head_index(cc->code, pair);
+ while ( dir->ccache.table[chi & dir->ccache.table_mask] != cc )
+ chi++;
+ hash_remove_cached_char(dir, chi);
+ }
+ gx_free_cached_char(dir, cc);
+ }
+ }
+ cc->chunk = cck;
+ cc->loc = (byte *)cc - cck->data;
+ return cc;
+#undef cc
+}
+
+/* Remove the cached_char at a given index in the hash table. */
+/* In order not to slow down lookup, we relocate following entries. */
+private void
+hash_remove_cached_char(gs_font_dir *dir, uint chi)
+{ uint mask = dir->ccache.table_mask;
+ uint from = ((chi &= mask) + 1) & mask;
+ cached_char *cc;
+
+ dir->ccache.table[chi] = 0;
+ while ( (cc = dir->ccache.table[from]) != 0 )
+ { /* Loop invariants: chars[chi] == 0; */
+ /* chars[chi+1..from] != 0. */
+ uint fchi = chars_head_index(cc->code, cc_pair(cc));
+
+ /* If chi <= fchi < from, we relocate the character. */
+ /* Note that '<=' must take wraparound into account. */
+ if ( (chi < from ? chi <= fchi && fchi < from :
+ chi <= fchi || fchi < from)
+ )
+ { dir->ccache.table[chi] = cc;
+ dir->ccache.table[from] = 0;
+ chi = from;
+ }
+ from = (from + 1) & mask;
+ }
+}
+
+/* Shorten a cached character. */
+/* diff >= sizeof(cached_char_head). */
+private void
+shorten_cached_char(gs_font_dir *dir, cached_char *cc, uint diff)
+{ gx_bits_cache_shorten((gx_bits_cache *)&dir->ccache, &cc->head,
+ diff, cc->chunk);
+ if_debug2('K', "[K]shortening creates free block 0x%lx(%u)\n",
+ (ulong)((byte *)cc + cc->head.size), diff);
+}
diff --git a/gs/src/gxchar.h b/gs/src/gxchar.h
new file mode 100644
index 000000000..cc9a3afc5
--- /dev/null
+++ b/gs/src/gxchar.h
@@ -0,0 +1,155 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxchar.h */
+/* Internal character definition for Ghostscript library */
+/* Requires gsmatrix.h, gxfixed.h */
+#include "gschar.h"
+
+/* The type of cached characters is opaque. */
+#ifndef cached_char_DEFINED
+# define cached_char_DEFINED
+typedef struct cached_char_s cached_char;
+#endif
+
+/* The type of cached font/matrix pairs is opaque. */
+#ifndef cached_fm_pair_DEFINED
+# define cached_fm_pair_DEFINED
+typedef struct cached_fm_pair_s cached_fm_pair;
+#endif
+
+/* The type of font objects is opaque. */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+#endif
+
+/* The types of memory and null devices may be opaque. */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+#endif
+#ifndef gx_device_null_DEFINED
+# define gx_device_null_DEFINED
+typedef struct gx_device_null_s gx_device_null;
+#endif
+
+/*
+ * Define the stack for composite fonts.
+ * If the current font is not composite, depth = -1.
+ * If the current font is composite, 0 <= depth <= max_font_depth.
+ * items[0] through items[depth] are occupied.
+ * items[0].font is the root font; items[0].index = 0.
+ * The root font must be composite, but may be of any map type.
+ * items[0..N-1] are modal composite fonts, for some N <= depth.
+ * items[N..depth-1] are non-modal composite fonts.
+ * items[depth] is a base (non-composite) font.
+ * Note that if depth >= 0, the font member of the graphics state
+ * for a base font BuildChar/Glyph is the same as items[depth].font.
+ */
+#define max_font_depth 5
+typedef struct gx_font_stack_item_s {
+ gs_font *font; /* font at this level */
+ uint index; /* index of this font in parent's */
+ /* Encoding */
+} gx_font_stack_item;
+typedef struct gx_font_stack_s {
+ int depth;
+ gx_font_stack_item items[1 + max_font_depth];
+} gx_font_stack;
+
+/* An enumeration object for string display. */
+typedef enum {
+ sws_none,
+ sws_cache, /* setcachedevice[2] */
+ sws_no_cache, /* setcharwidth */
+ sws_cache_width_only /* setcharwidth for xfont char */
+} show_width_status;
+struct gs_show_enum_s {
+ /* Following are set at creation time */
+ gs_state *pgs;
+ int level; /* save the level of pgs */
+ gs_const_string str;
+ float wcx, wcy; /* for widthshow */
+ gs_char wchr; /* ditto */
+ float ax, ay; /* for ashow */
+ bool add; /* true if a[width]show */
+ int do_kern; /* 1 if kshow, -1 if [x][y]show */
+ /* or cshow, 0 otherwise */
+ bool slow_show; /* [a][width]show or kshow or */
+ /* [x][y]show or cshow */
+ gs_char_path_mode charpath_flag;
+ gs_state *show_gstate; /* for setting pgs->show_gstate */
+ /* at returns/callouts */
+ int stringwidth_flag; /* 0 for show/charpath, */
+ /* 1 for stringwidth, */
+ /* -1 for cshow */
+ int can_cache; /* -1 if can't use cache at all, */
+ /* 0 if can read but not load, */
+ /* 1 if can read and load */
+ gs_int_rect ibox; /* int version of quick-check */
+ /* (inner) clipping box */
+ gs_int_rect obox; /* int version of (outer) clip box */
+ int ftx, fty; /* transformed font translation */
+ /* Following are updated dynamically */
+ gs_glyph (*encode_char)(P3(gs_show_enum *, gs_font *, gs_char *));
+ /* copied from font, */
+ /* except for glyphshow */
+ gs_log2_scale_point log2_suggested_scale; /* suggested scaling */
+ /* factors for oversampling, */
+ /* based on FontBBox and CTM */
+ gx_device_memory *dev_cache; /* cache device */
+ gx_device_memory *dev_cache2; /* underlying alpha memory device, */
+ /* if dev_cache is an alpha buffer */
+ gx_device_null *dev_null; /* null device for stringwidth */
+ uint index; /* index within string */
+ gs_char current_char; /* current char for render or move */
+ gs_glyph current_glyph; /* current glyph ditto */
+ gs_fixed_point wxy; /* width of current char */
+ /* in device coords */
+ gs_fixed_point origin; /* unrounded origin of current char */
+ /* in device coords, needed for */
+ /* charpath and WMode=1 */
+ cached_char *cc; /* being accumulated */
+ gs_point width; /* total width of string, set at end */
+ show_width_status width_status;
+ gs_log2_scale_point log2_current_scale;
+ gx_font_stack fstack;
+ int (*continue_proc)(P1(gs_show_enum *)); /* continuation procedure */
+};
+#define gs_show_enum_s_DEFINED
+#define private_st_gs_show_enum() /* in gschar.c */\
+ gs_private_st_composite(st_gs_show_enum, gs_show_enum, "gs_show_enum",\
+ show_enum_enum_ptrs, show_enum_reloc_ptrs)
+
+/* Cached character procedures (in gxccache.c and gxccman.c) */
+#ifndef gs_font_dir_DEFINED
+# define gs_font_dir_DEFINED
+typedef struct gs_font_dir_s gs_font_dir;
+#endif
+cached_char *
+ gx_alloc_char_bits(P7(gs_font_dir *, gx_device_memory *, gx_device_memory *, ushort, ushort, const gs_log2_scale_point *, int));
+void gx_open_cache_device(P2(gx_device_memory *, cached_char *));
+void gx_free_cached_char(P2(gs_font_dir *, cached_char *));
+void gx_add_cached_char(P5(gs_font_dir *, gx_device_memory *, cached_char *, cached_fm_pair *, const gs_log2_scale_point *));
+void gx_add_char_bits(P3(gs_font_dir *, cached_char *, const gs_log2_scale_point *));
+cached_char *
+ gx_lookup_cached_char(P5(const gs_font *, const cached_fm_pair *, gs_glyph, int, int));
+cached_char *
+ gx_lookup_xfont_char(P6(const gs_state *, cached_fm_pair *, gs_char, gs_glyph, const gx_xfont_callbacks *, int));
+int gx_image_cached_char(P2(gs_show_enum *, cached_char *));
diff --git a/gs/src/gxcht.c b/gs/src/gxcht.c
new file mode 100644
index 000000000..15077b097
--- /dev/null
+++ b/gs/src/gxcht.c
@@ -0,0 +1,585 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcht.c */
+/* Color halftone rendering for Ghostscript imaging library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for id generation */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzht.h"
+
+/* Define the size of the tile buffer allocated on the stack. */
+#define tile_longs_LARGE 256
+#define tile_longs_SMALL 64
+#if arch_small_memory
+# define tile_longs_allocated tile_longs_SMALL
+# define tile_longs tile_longs_SMALL
+#else
+# define tile_longs_allocated tile_longs_LARGE
+# define tile_longs\
+ (gs_if_debug_c('.') ? tile_longs_SMALL : tile_longs_LARGE)
+#endif
+
+/* Define the colored halftone device color type. */
+private dev_color_proc_load(gx_dc_ht_colored_load);
+private dev_color_proc_fill_rectangle(gx_dc_ht_colored_fill_rectangle);
+private struct_proc_enum_ptrs(dc_ht_colored_enum_ptrs);
+private struct_proc_reloc_ptrs(dc_ht_colored_reloc_ptrs);
+const gx_device_color_procs
+ gx_dc_procs_ht_colored =
+ { gx_dc_ht_colored_load, gx_dc_ht_colored_fill_rectangle,
+ gx_dc_default_fill_masked,
+ dc_ht_colored_enum_ptrs, dc_ht_colored_reloc_ptrs
+ };
+#undef gx_dc_type_ht_colored
+const gx_device_color_procs _ds *gx_dc_type_ht_colored = &gx_dc_procs_ht_colored;
+#define gx_dc_type_ht_colored (&gx_dc_procs_ht_colored)
+/* GC procedures */
+#define cptr ((gx_device_color *)vptr)
+private ENUM_PTRS_BEGIN(dc_ht_colored_enum_ptrs) return 0;
+ ENUM_PTR(0, gx_device_color, colors.colored.c_ht);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_ht_colored_reloc_ptrs) {
+ RELOC_PTR(gx_device_color, colors.colored.c_ht);
+} RELOC_PTRS_END
+#undef cptr
+
+/* Forward references. */
+private void set_ht_colors(P6(gx_color_index [16], gx_strip_bitmap *[4],
+ const gx_device_color *, gx_device *, gx_ht_cache *[4], int));
+private void set_color_ht(P9(gx_strip_bitmap *, int, int, int, int, int, int,
+ const gx_color_index [16], const gx_strip_bitmap *[4]));
+
+/* Define a table for expanding 8x1 bits to 8x4. */
+private const bits32 far_data expand_8x1_to_8x4[256] = {
+#define x16(c)\
+ c+0, c+1, c+0x10, c+0x11, c+0x100, c+0x101, c+0x110, c+0x111,\
+ c+0x1000, c+0x1001, c+0x1010, c+0x1011, c+0x1100, c+0x1101, c+0x1110, c+0x1111
+ x16(0x00000000), x16(0x00010000), x16(0x00100000), x16(0x00110000),
+ x16(0x01000000), x16(0x01010000), x16(0x01100000), x16(0x01110000),
+ x16(0x10000000), x16(0x10010000), x16(0x10100000), x16(0x10110000),
+ x16(0x11000000), x16(0x11010000), x16(0x11100000), x16(0x11110000)
+#undef x16
+};
+
+/* Prepare to use a colored halftone, by loading the default cache. */
+private int
+gx_dc_ht_colored_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *ignore_dev, gs_color_select_t select)
+{ gx_device_halftone *pdht = pis->dev_ht;
+ gx_ht_order *porder = &pdht->components[0].corder;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if ( pcache->order.bits != porder->bits )
+ gx_ht_init_cache(pcache, porder);
+ /* Set the cache pointers in the default order. */
+ pdht->order.cache = porder->cache = pcache;
+ return 0;
+}
+
+/* Fill a rectangle with a colored halftone. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_ht_colored_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ ulong tbits[tile_longs_allocated];
+ const uint tile_bytes = tile_longs * size_of(long);
+ gx_strip_bitmap tiles;
+ gx_rop_source_t no_source;
+ const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
+ int depth = dev->color_info.depth;
+ int nplanes = dev->color_info.num_components;
+ gx_color_index colors[16];
+ gx_strip_bitmap *sbits[4];
+ gx_ht_cache *caches[4];
+ int code = 0;
+ int raster;
+ uint size_x;
+ int dw, dh;
+ int lw = pdht->lcm_width, lh = pdht->lcm_height;
+
+ if ( w <= 0 || h <= 0 )
+ return 0;
+ /* Colored halftone patterns are unconditionally opaque. */
+ lop &= ~lop_T_transparent;
+ tiles.data = (byte *)tbits;
+ if ( pdht->components == 0 )
+ caches[0] = caches[1] = caches[2] = caches[3] = pdht->order.cache;
+ else
+ { gx_ht_order_component *pocs = pdht->components;
+ caches[0] = pocs[pdht->color_indices[0]].corder.cache;
+ caches[1] = pocs[pdht->color_indices[1]].corder.cache;
+ caches[2] = pocs[pdht->color_indices[2]].corder.cache;
+ caches[3] = pocs[pdht->color_indices[3]].corder.cache;
+ }
+ set_ht_colors(colors, sbits, pdevc, dev, caches, nplanes);
+ /* If the LCM of the plane cell sizes is smaller than */
+ /* the rectangle being filled, compute a single tile and */
+ /* let tile_rectangle do the replication. */
+ if ( (w > lw || h > lh) &&
+ (raster = bitmap_raster(lw * depth)) <= tile_bytes / lh
+ )
+ { /*
+ * The only reason we need to do fit_fill here is that if the
+ * device is a clipper, the caller might be counting on it to do
+ * all necessary clipping. Actually, we should clip against the
+ * device's clipping box, not the default....
+ */
+ fit_fill(dev, x, y, w, h);
+ /* Check to make sure we still have a big rectangle. */
+ if ( w > lw || h > lh )
+ { tiles.raster = raster;
+ tiles.rep_width = tiles.size.x = lw;
+ tiles.rep_height = tiles.size.y = lh;
+ tiles.id = gs_next_ids(1);
+ tiles.rep_shift = tiles.shift = 0;
+ /* See below for why we need to cast bits. */
+ set_color_ht(&tiles, 0, 0, lw, lh,
+ depth, nplanes, colors,
+ (const gx_strip_bitmap **)sbits);
+ if ( source == NULL && lop_no_S_is_T(lop) )
+ return (*dev_proc(dev, strip_tile_rectangle))(dev, &tiles,
+ x, y, w, h,
+ gx_no_color_index, gx_no_color_index,
+ pdevc->phase.x, pdevc->phase.y);
+ if ( source == NULL )
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop))(dev, source->sdata,
+ source->sourcex, source->sraster, source->id,
+ (source->use_scolors ? source->scolors : NULL),
+ &tiles, NULL,
+ x, y, w, h,
+ pdevc->phase.x, pdevc->phase.y,
+ rop3_know_S_0(lop));
+ }
+ }
+ tiles.id = gx_no_bitmap_id;
+ size_x = w * depth;
+ raster = bitmap_raster(size_x);
+ if ( raster > tile_bytes )
+ { /*
+ * We can't even do an entire line at once. See above for
+ * why we do the X equivalent of fit_fill here.
+ */
+ if ( x < 0 )
+ w += x, x = 0;
+ if ( x > dev->width - w )
+ w = dev->width - x;
+ if ( w <= 0 )
+ return 0;
+ size_x = w * depth;
+ raster = bitmap_raster(size_x);
+ if ( raster > tile_bytes )
+ { dw = tile_bytes * 8 / depth;
+ size_x = dw * depth;
+ raster = bitmap_raster(size_x);
+ dh = 1;
+ goto fit;
+ }
+ }
+ /* Do as many lines as will fit. */
+ dw = w;
+ dh = tile_bytes / raster;
+ if ( dh > h )
+ dh = h;
+fit: /* Now the tile will definitely fit. */
+ tiles.raster = raster;
+ tiles.rep_width = tiles.size.x = size_x / depth;
+ tiles.rep_shift = tiles.shift = 0;
+ while ( w )
+ { int cy = y, ch = dh, left = h;
+ tiles.rep_height = tiles.size.y = ch;
+ for ( ; ; )
+ { /* The cast in the following statement is bogus, */
+ /* but some compilers won't accept an array type, */
+ /* and won't accept the ** type without a cast. */
+ set_color_ht(&tiles, x, cy, dw, ch,
+ depth, nplanes, colors,
+ (const gx_strip_bitmap **)sbits);
+ if ( lop_no_S_is_T(lop) )
+ { code = (*dev_proc(dev, copy_color))(dev,
+ tiles.data, 0, raster,
+ gx_no_bitmap_id, x, cy, dw, ch);
+ }
+ else
+ { gs_logical_operation_t lop_st = rop3_swap_S_T(lop);
+ code = (*dev_proc(dev, strip_copy_rop))(dev,
+ tiles.data, 0, raster,
+ gx_no_bitmap_id,
+ NULL,
+ NULL,
+ pdevc->colors.binary.color /*arb*/,
+ x, cy, dw, ch, 0, 0,
+ rop3_know_T_0(lop_st));
+ }
+ if ( code < 0 )
+ return code;
+ if ( !(left -= ch) )
+ break;
+ cy += ch;
+ if ( ch > left )
+ tiles.rep_height = tiles.size.y = ch = left;
+ }
+ if ( !(w -= dw) )
+ break;
+ x += dw;
+ if ( dw > w)
+ dw = w, tiles.rep_width = tiles.size.x = size_x / depth;
+ }
+ return code;
+}
+
+/*
+ * We construct color halftone tiles out of 3 or 4 "planes".
+ * Each plane specifies halftoning for one component (R/G/B or C/M/Y/K).
+ */
+
+/* Set up the colors and the individual plane halftone bitmaps. */
+private void
+set_ht_colors(gx_color_index colors[16], gx_strip_bitmap *sbits[4],
+ const gx_device_color *pdc, gx_device *dev, gx_ht_cache *caches[4],
+ int nplanes)
+{ gx_color_value v[2][4];
+ static const ulong no_bitmap_data[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0 };
+ static gx_strip_bitmap no_bitmap =
+ { 0, sizeof(ulong), { sizeof(ulong) * 8, countof(no_bitmap_data) },
+ gx_no_bitmap_id, 1, 1, 0, 0
+ };
+ gx_color_value max_color = dev->color_info.dither_colors - 1;
+ int plane_mask = 0;
+
+ no_bitmap.data = (byte *)no_bitmap_data; /* actually const */
+#define cb(i) pdc->colors.colored.c_base[i]
+#define cl(i) pdc->colors.colored.c_level[i]
+#define set_plane_color(i)\
+{ uint q = cb(i);\
+ uint r = cl(i);\
+ v[0][i] = fractional_color(q, max_color);\
+ if ( r == 0 )\
+ v[1][i] = v[0][i], sbits[i] = &no_bitmap;\
+ else\
+ v[1][i] = fractional_color(q+1, max_color),\
+ sbits[i] = &gx_render_ht(caches[i], r)->tiles,\
+ plane_mask |= 1 << (i);\
+}
+#define map8(m) m(0), m(1), m(2), m(3), m(4), m(5), m(6), m(7)
+ set_plane_color(0);
+ set_plane_color(1);
+ set_plane_color(2);
+ if ( nplanes == 3 )
+ {
+#define map_rgb(i)\
+ colors[i] = map1rgb(v[(i) & 1][0], v[((i) & 2) >> 1][1], v[(i) >> 2][2])
+ gx_color_value alpha = pdc->colors.colored.alpha;
+ if ( alpha == gx_max_color_value )
+ {
+#ifdef DEBUG
+# define map1rgb(r, g, b) gx_map_rgb_color(dev, r, g, b)
+#else
+ dev_proc_map_rgb_color((*map)) =
+ dev_proc(dev, map_rgb_color);
+# define map1rgb(r, g, b) (*map)(dev, r, g, b)
+#endif
+ map8(map_rgb);
+#undef map1rgb
+ }
+ else
+ {
+#ifdef DEBUG
+# define map1rgb(r, g, b) gx_map_rgb_alpha_color(dev, r, g, b, alpha)
+#else
+ dev_proc_map_rgb_alpha_color((*map)) =
+ dev_proc(dev, map_rgb_alpha_color);
+# define map1rgb(r, g, b) (*map)(dev, r, g, b, alpha)
+#endif
+ map8(map_rgb);
+#undef map1rgb
+ }
+ }
+ else
+ {
+#define map_cmyk(i)\
+ colors[i] = map1cmyk(v[(i) & 1][0], v[((i) & 2) >> 1][1],\
+ v[((i) & 4) >> 2][2], v[(i) >> 3][3])
+#ifdef DEBUG
+# define map1cmyk(r, g, b, w) gx_map_cmyk_color(dev, r, g, b, w)
+#else
+ dev_proc_map_cmyk_color((*map)) =
+ dev_proc(dev, map_cmyk_color);
+# define map1cmyk(r, g, b, w) (*map)(dev, r, g, b, w)
+#endif
+ set_plane_color(3);
+ /*
+ * For CMYK output, especially if the input was RGB, it's
+ * common for one or more of the components to be zero.
+ * Each zero component can cut the cost of color mapping in
+ * half, so it's worth doing a little checking here.
+ */
+#define m1(i) map_cmyk(i)
+#define m2(i,d) m1(i), m1(i+d)
+#define m4(i,d1,d2) m2(i, d1), m2(i + d2, d1)
+ switch ( plane_mask )
+ {
+ case 15: m4(8, 1, 2); m4(12, 1, 2);
+ case 7: m4(4, 1, 2);
+c3: case 3: m2(2, 1);
+c1: case 1: m1(1); break;
+ case 14: m4(8, 2, 4);
+ case 6: m2(4, 2);
+c2: case 2: m1(2); break;
+ case 13: m4(8, 1, 4);
+ case 5: m2(4, 1); goto c1;
+ case 12: m2(8, 4);
+ case 4: m1(4); break;
+ case 11: m4(8, 1, 2); goto c3;
+ case 10: m2(8, 2); goto c2;
+ case 9: m2(8, 1); goto c1;
+ case 8: m1(8); break;
+ case 0: ;
+ }
+ m1(0);
+#undef m1
+#undef m2
+#undef m4
+#undef map1cmyk
+ }
+#undef map8
+#undef set_plane_color
+#undef cb
+#undef cl
+}
+
+/* Render the combined halftone. */
+private void
+set_color_ht(
+ gx_strip_bitmap *ctiles, /* the output tile; data, raster, size are set */
+ int px, /* the initial phase of the output tile */
+ int py,
+ int w, /* how much of the tile to set */
+ int h,
+ int depth, /* depth of tile (4, 8, 16, 24, 32) */
+ int nplanes, /* # of source planes, 3 or 4 */
+ const gx_color_index colors[16], /* the actual colors for the tile, */
+ /* actually [1 << nplanes] */
+ const gx_strip_bitmap *sbits[4] /* the bitmaps for the planes, */
+ /* actually [nplanes] */
+)
+{ /* Note that the planes are specified in the order RGB or CMYK, but */
+ /* the indices used for the internal colors array are BGR or KYMC. */
+
+ int x, y;
+ struct tile_cursor_s {
+ int tile_shift; /* X shift per copy of tile */
+ int xoffset;
+ int xshift;
+ uint xbytes;
+ int xbits;
+ const byte *row;
+ const byte *tdata;
+ uint raster;
+ const byte *data;
+ int bit_shift;
+ } cursor[4];
+ int dbytes = depth >> 3;
+ uint dest_raster = ctiles->raster;
+ byte *dest_row =
+ ctiles->data + dest_raster * (h - 1) + (w * depth) / 8;
+ int endx = w + px;
+
+ if_debug6('h',
+ "[h]color_ht: x=%d y=%d w=%d h=%d nplanes=%d depth=%d\n",
+ px, py, w, h, nplanes, depth);
+
+ /* Do one-time cursor initialization. */
+ { int lasty = h - 1 + py;
+#define set_start(i, c, btile)\
+{ int tw = btile->size.x;\
+ int bx = ((c.tile_shift = btile->shift) == 0 ? endx :\
+ endx + lasty / btile->size.y * c.tile_shift) % tw;\
+ int by = lasty % btile->size.y;\
+ c.xoffset = bx >> 3;\
+ c.xshift = 8 - (bx & 7);\
+ c.xbytes = (tw - 1) >> 3;\
+ c.xbits = ((tw - 1) & 7) + 1;\
+ c.tdata = btile->data;\
+ c.raster = btile->raster;\
+ c.row = c.tdata + by * c.raster;\
+ if_debug5('h', "[h]plane %d: size=%d,%d bx=%d by=%d\n",\
+ i, tw, btile->size.y, bx, by);\
+}
+ set_start(0, cursor[0], sbits[0]);
+ set_start(1, cursor[1], sbits[1]);
+ set_start(2, cursor[2], sbits[2]);
+ if ( nplanes == 4 )
+ set_start(3, cursor[3], sbits[3]);
+#undef set_start
+ }
+
+ /* Now compute the actual tile. */
+ for ( y = h; ; dest_row -= dest_raster )
+ { byte *dest = dest_row;
+#define set_row(c)\
+ { c.data = c.row + c.xoffset;\
+ c.bit_shift = c.xshift;\
+ }
+ set_row(cursor[0]);
+ set_row(cursor[1]);
+ set_row(cursor[2]);
+ if ( nplanes == 4 )
+ { set_row(cursor[3]);
+ }
+#undef set_row
+ --y;
+ for ( x = w; x > 0; )
+ { bits32 indices;
+ int nx, i;
+ register uint bits;
+/* Get the next byte's worth of bits. Note that there may be */
+/* excess bits set beyond the 8th. */
+#define next_bits(c)\
+{ if ( c.data > c.row )\
+ { bits = ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
+ c.data--;\
+ }\
+ else\
+ { bits = *c.data >> c.bit_shift;\
+ c.data += c.xbytes;\
+ if ( (c.bit_shift -= c.xbits) < 0 )\
+ { bits |= *c.data << -c.bit_shift;\
+ c.bit_shift += 8;\
+ }\
+ else\
+ { bits |= ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
+ c.data--;\
+ }\
+ }\
+}
+ if ( nplanes == 4 )
+ { next_bits(cursor[3]);
+ indices = expand_8x1_to_8x4[bits & 0xff] << 1;
+ }
+ else
+ indices = 0;
+ next_bits(cursor[2]);
+ indices = (indices | expand_8x1_to_8x4[bits & 0xff]) << 1;
+ next_bits(cursor[1]);
+ indices = (indices | expand_8x1_to_8x4[bits & 0xff]) << 1;
+ next_bits(cursor[0]);
+ indices |= expand_8x1_to_8x4[bits & 0xff];
+#undef next_bits
+ nx = min(x, 8); /* 1 <= nx <= 8 */
+ x -= nx;
+ switch ( dbytes )
+ {
+ case 0: /* 4 */
+ i = nx;
+ if ( (x + nx) & 1 )
+ { /* First pixel is even nibble. */
+ *dest = (*dest & 0xf) +
+ ((byte)colors[(uint)indices & 0xf] << 4);
+ indices >>= 4;
+ --i;
+ }
+ /* Now 0 <= i <= 8. */
+ for ( ; (i -= 2) >= 0; indices >>= 8 )
+ *--dest =
+ (byte)colors[(uint)indices & 0xf] +
+ ((byte)colors[((uint)indices >> 4) & 0xf]
+ << 4);
+ /* Check for final odd nibble. */
+ if ( i & 1 )
+ *--dest = (byte)colors[(uint)indices & 0xf];
+ break;
+ case 4: /* 32 */
+ for ( i = nx; --i >= 0; indices >>= 4 )
+ { gx_color_index tcolor =
+ colors[(uint)indices & 0xf];
+ dest -= 4;
+ dest[3] = (byte)tcolor;
+ dest[2] = (byte)(tcolor >> 8);
+ tcolor >>= 16;
+ dest[1] = (byte)tcolor;
+ dest[0] = (byte)((uint)tcolor >> 8);
+ }
+ break;
+ case 3: /* 24 */
+ for ( i = nx; --i >= 0; indices >>= 4 )
+ { gx_color_index tcolor =
+ colors[(uint)indices & 0xf];
+ dest -= 3;
+ dest[2] = (byte)tcolor;
+ dest[1] = (byte)((uint)tcolor >> 8);
+ tcolor >>= 16;
+ dest[0] = (byte)((uint)tcolor >> 8);
+ }
+ break;
+ case 2: /* 16 */
+ for ( i = nx; --i >= 0; indices >>= 4 )
+ { uint tcolor =
+ (uint)colors[(uint)indices & 0xf];
+ dest -= 2;
+ dest[1] = (byte)tcolor;
+ dest[0] = (byte)(tcolor >> 8);
+ }
+ break;
+ case 1: /* 8 */
+ for ( i = nx; --i >= 0; indices >>= 4 )
+ *--dest = (byte)colors[(uint)indices & 0xf];
+ break;
+ }
+ }
+ if ( y == 0 )
+ break;
+
+#define step_row(c, i)\
+ if ( c.row > c.tdata )\
+ c.row -= c.raster;\
+ else /* wrap around to end of tile, taking shift into account */\
+ { c.row += c.raster * (sbits[i]->size.y - 1);\
+ if ( c.tile_shift )\
+ { if ( (c.xshift += c.tile_shift) >= 8 )\
+ { if ( (c.xoffset -= c.xshift >> 3) < 0 )\
+ { /* wrap around in X */\
+ int bx = (c.xoffset << 3) + 8 - (c.xshift & 7) +\
+ sbits[i]->size.x;\
+ c.xoffset = bx >> 3;\
+ c.xshift = 8 - (bx & 7);\
+ }\
+ else\
+ c.xshift &= 7;\
+ }\
+ }\
+ }
+
+ step_row(cursor[0], 0);
+ step_row(cursor[1], 1);
+ step_row(cursor[2], 2);
+ if ( nplanes == 4)
+ step_row(cursor[3], 3);
+#undef step_row
+ }
+}
diff --git a/gs/src/gxcindex.h b/gs/src/gxcindex.h
new file mode 100644
index 000000000..3abb52ac6
--- /dev/null
+++ b/gs/src/gxcindex.h
@@ -0,0 +1,96 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcindex.h */
+/* Define the device color index type and macros */
+/* Requires gxbitmap.h. */
+
+#ifndef gxcindex_INCLUDED
+# define gxcindex_INCLUDED
+
+/*
+ * Internally, a (pure) device color is represented by opaque values of
+ * type gx_color_index, which are tied to the specific device. The driver
+ * maps between these values and RGB[alpha] or CMYK values. In this way,
+ * the driver can convert RGB values to its most natural color representation,
+ * and have the graphics library cache the result.
+ */
+
+/* Define the type for device color indices. */
+typedef unsigned long gx_color_index;
+#define arch_log2_sizeof_color_index arch_log2_sizeof_long
+#define arch_sizeof_color_index arch_sizeof_long
+
+/* Define the 'transparent' color index. */
+#define gx_no_color_index_value (-1) /* no cast -> can be used in #if */
+
+/* The SGI C compiler provided with Irix 5.2 gives error messages */
+/* if we use the proper definition of gx_no_color_index: */
+/*#define gx_no_color_index ((gx_color_index)gx_no_color_index_value)*/
+/* Instead, we must spell out the typedef: */
+#define gx_no_color_index ((unsigned long)gx_no_color_index_value)
+
+/*
+ * Define macros for accumulating a scan line of a colored image.
+ * The usage is as follows:
+ * declare_line_accum(line, bpp, xo);
+ * for ( x = xo; x < xe; ++x )
+ * { << compute color at x >>
+ * line_accum(color, bpp);
+ * }
+ * line_accum_copy(dev, line, bpp, xo, xe, raster, y);
+ * This code must be enclosed in { }, since declare_line_accum declares
+ * variables.
+ *
+ * Note that declare_line_accum declares the variables l_dst, l_bits, l_shift,
+ * and l_xprev. Other code in the loop may use these variables.
+ */
+#define declare_line_accum(line, bpp, xo)\
+ byte *l_dst = (line);\
+ uint l_bits = 0;\
+ int l_shift = 8 - (bpp);\
+ int l_xprev = (xo)
+#define line_accum(color, bpp)\
+ switch ( (bpp) >> 3 )\
+ {\
+ case 0:\
+ l_bits += (uint)((color) << l_shift);\
+ if ( (l_shift -= (bpp)) < 0 )\
+ *l_dst++ = (byte)l_bits, l_bits = 0,\
+ l_shift += 8;\
+ break;\
+ case 4: *l_dst++ = (byte)((color) >> 24);\
+ case 3: *l_dst++ = (byte)((color) >> 16);\
+ case 2: *l_dst++ = (byte)((color) >> 8);\
+ case 1: *l_dst++ = (byte)(color);\
+ }
+#define line_accum_store(bpp)\
+ if ( l_shift != 8 - (bpp) )\
+ *l_dst = (byte)l_bits
+#define line_accum_copy(dev, line, bpp, xo, xe, raster, y)\
+ if ( (xe) > l_xprev )\
+ { int code;\
+ line_accum_store(bpp);\
+ code = (*dev_proc(dev, copy_color))\
+ (dev, line, l_xprev - (xo), raster,\
+ gx_no_bitmap_id, l_xprev, y, (xe) - l_xprev, 1);\
+ if ( code < 0 )\
+ return code;\
+ }
+
+#endif /* gxcindex_INCLUDED */
diff --git a/gs/src/gxclbits.c b/gs/src/gxclbits.c
new file mode 100644
index 000000000..c240b0591
--- /dev/null
+++ b/gs/src/gxclbits.c
@@ -0,0 +1,742 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclbits.c */
+/* Halftone and bitmap writing for command lists */
+#include "memory_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxfmap.h"
+
+/*
+ * Define when, if ever, to write character bitmaps in all bands.
+ * Set this to:
+ * 0 to always write in all bands;
+ * N to write in all bands when the character has been seen in N+1
+ * bands on a page;
+ * max_ushort to never write in all bands.
+ */
+#define CHAR_ALL_BANDS_COUNT max_ushort
+
+/* ------ Writing ------ */
+
+/*
+ * Determine the (possibly unpadded) width in bytes for writing a bitmap,
+ * per the algorithm in gxcldev.h. If compression_mask has any of the
+ * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
+ * Return the total size of the bitmap.
+ */
+uint
+clist_bitmap_bytes(uint width_bits, uint height, int compression_mask,
+ uint *width_bytes, uint *raster)
+{ uint full_raster = *raster = bitmap_raster(width_bits);
+ uint short_raster = (width_bits + 7) >> 3;
+ uint width_bytes_last;
+
+ if ( compression_mask & cmd_mask_compress_any )
+ *width_bytes = width_bytes_last = full_raster;
+ else if ( short_raster <= cmd_max_short_width_bytes ||
+ height <= 1 ||
+ (compression_mask & decompress_spread) != 0
+ )
+ *width_bytes = width_bytes_last = short_raster;
+ else
+ *width_bytes = full_raster, width_bytes_last = short_raster;
+ return
+ (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last);
+}
+
+/*
+ * Compress a bitmap, skipping extra padding bytes at the end of each row if
+ * necessary. We require height >= 1, raster >= bitmap_raster(width_bits).
+ */
+private int
+cmd_compress_bitmap(stream_state *st, const byte *data, uint width_bits,
+ uint raster, uint height, stream_cursor_write *pw)
+{ uint width_bytes = bitmap_raster(width_bits);
+ int status = 0;
+ stream_cursor_read r;
+
+ r.ptr = data - 1;
+ if ( raster == width_bytes )
+ { r.limit = r.ptr + raster * height;
+ status = (*st->template->process)(st, &r, pw, true);
+ }
+ else
+ { /* Compress row-by-row. */
+ uint y;
+ for ( y = 1; (r.limit = r.ptr + width_bytes), y < height; ++y )
+ { status = (*st->template->process)(st, &r, pw, false);
+ if ( status )
+ break;
+ if ( r.ptr != r.limit )
+ { /* We don't attempt to handle compressors that */
+ /* require >1 input byte to make progress. */
+ status = -1;
+ break;
+ }
+ r.ptr += raster - width_bytes;
+ }
+ if ( status == 0 )
+ status = (*st->template->process)(st, &r, pw, true);
+ }
+ if ( st->template->release )
+ (*st->template->release)(st);
+ return status;
+}
+
+/*
+ * Put a bitmap in the buffer, compressing if appropriate.
+ * pcls == 0 means put the bitmap in all bands.
+ * Return <0 if error, otherwise the compression method.
+ * A return value of gs_error_limitcheck means that the bitmap was too big
+ * to fit in the command reading buffer.
+ * Note that this leaves room for the command and initial arguments,
+ * but doesn't fill them in.
+ */
+int
+cmd_put_bits(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const byte *data, uint width_bits, uint height, uint raster, int op_size,
+ int compression_mask, byte **pdp, uint *psize)
+{ uint short_raster, full_raster;
+ uint short_size =
+ clist_bitmap_bytes(width_bits, height,
+ compression_mask & ~cmd_mask_compress_any,
+ &short_raster, &full_raster);
+ uint uncompressed_raster;
+ uint uncompressed_size =
+ clist_bitmap_bytes(width_bits, height, compression_mask,
+ &uncompressed_raster, &full_raster);
+ uint max_size = cbuf_size - op_size;
+ gs_memory_t *memory_allocator
+ = cldev->memory ? cldev->memory : &gs_memory_default;
+ byte *dp;
+ int compress = 0;
+
+ /*
+ * See if compressing the bits is possible and worthwhile.
+ * Currently we can't compress if the compressed data won't fit in
+ * the command reading buffer, or if the decompressed data won't fit
+ * in the buffer and decompress_elsewhere isn't set.
+ */
+ if ( short_size >= 50 &&
+ (compression_mask & cmd_mask_compress_any) != 0 &&
+ (uncompressed_size <= max_size ||
+ (compression_mask & decompress_elsewhere) != 0)
+ )
+ { union ss_ {
+ stream_state ss;
+ stream_CFE_state cf;
+ stream_RLE_state rl;
+ } sstate;
+
+ *psize = op_size + uncompressed_size;
+ if ( pcls != 0 )
+ { int code = set_cmd_put_op(dp, cldev, pcls, 0, *psize);
+ if (code < 0)
+ return code;
+ }
+ else
+ { int code = set_cmd_put_all_op(dp, cldev, 0, *psize);
+ if (code < 0)
+ return code;
+ }
+ cmd_uncount_op(0, *psize);
+ /*
+ * Note that we currently keep all the padding if we are
+ * compressing. This is ridiculous, but it's too hard to
+ * change right now.
+ */
+ if ( compression_mask & (1 << cmd_compress_cfe) )
+ { /* Try CCITTFax compression. */
+ clist_cfe_init(&sstate.cf,
+ uncompressed_raster << 3 /*width_bits*/, memory_allocator);
+ sstate.ss.template = &s_CFE_template;
+ compress = cmd_compress_cfe;
+ }
+ else if ( compression_mask & (1 << cmd_compress_rle) )
+ { /* Try RLE compression. */
+ clist_rle_init(&sstate.rl);
+ sstate.ss.template = &s_RLE_template;
+ compress = cmd_compress_rle;
+ }
+ if ( compress )
+ { byte *wbase = dp + (op_size - 1);
+ stream_cursor_write w;
+ /*
+ * We can give up on compressing if we generate too much
+ * output to fit in the command reading buffer, or too
+ * much to make compression worthwhile.
+ */
+ uint wmax = min(uncompressed_size, max_size);
+ int status;
+
+ w.ptr = wbase;
+ w.limit = w.ptr + min(wmax, short_size >> 1);
+ status = cmd_compress_bitmap((stream_state *)&sstate, data,
+ uncompressed_raster << 3 /*width_bits*/,
+ raster, height, &w);
+ if ( status == 0 )
+ { /* Use compressed representation. */
+ uint wcount = w.ptr - wbase;
+ cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ uncompressed_size - wcount);
+ *psize = op_size + wcount;
+ goto out;
+ }
+ }
+ if ( uncompressed_size > max_size )
+ { cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ *psize);
+ return_error(gs_error_limitcheck);
+ }
+ if ( uncompressed_size != short_size )
+ { cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ uncompressed_size - short_size);
+ *psize = op_size + short_size;
+ }
+ compress = 0;
+ }
+ else if ( uncompressed_size > max_size )
+ return_error(gs_error_limitcheck);
+ else
+ { *psize = op_size + short_size;
+ if ( pcls != 0 )
+ { int code = set_cmd_put_op(dp, cldev, pcls, 0, *psize);
+ if (code < 0)
+ return code;
+ }
+ else
+ { int code = set_cmd_put_all_op(dp, cldev, 0, *psize);
+ if (code < 0)
+ return code;
+ }
+ cmd_uncount_op(0, *psize);
+ }
+ bytes_copy_rectangle(dp + op_size, short_raster, data, raster,
+ short_raster, height);
+out: *pdp = dp;
+ return compress;
+}
+
+/* Add a command to set the tile size and depth. */
+private uint
+cmd_size_tile_params(const gx_strip_bitmap *tile)
+{ return 2 + cmd_size_w(tile->rep_width) + cmd_size_w(tile->rep_height) +
+ (tile->rep_width == tile->size.x ? 0 :
+ cmd_size_w(tile->size.x / tile->rep_width)) +
+ (tile->rep_height == tile->size.y ? 0 :
+ cmd_size_w(tile->size.y / tile->rep_height)) +
+ (tile->rep_shift == 0 ? 0 : cmd_size_w(tile->rep_shift));
+}
+private void
+cmd_store_tile_params(byte *dp, const gx_strip_bitmap *tile, int depth,
+ uint csize)
+{ byte *p = dp + 2;
+ byte bd = depth - 1;
+
+ *dp = cmd_count_op(cmd_opv_set_tile_size, csize);
+ p = cmd_put_w(tile->rep_width, p);
+ p = cmd_put_w(tile->rep_height, p);
+ if ( tile->rep_width != tile->size.x ) {
+ p = cmd_put_w(tile->size.x / tile->rep_width, p);
+ bd |= 0x20;
+ }
+ if ( tile->rep_height != tile->size.y ) {
+ p = cmd_put_w(tile->size.y / tile->rep_height, p);
+ bd |= 0x40;
+ }
+ if ( tile->rep_shift != 0 ) {
+ cmd_put_w(tile->rep_shift, p);
+ bd |= 0x80;
+ }
+ dp[1] = bd;
+}
+
+/* Add a command to set the tile index. */
+/* This is a relatively high-frequency operation, so we make it a macro. */
+/* Note that it may do a 'return' with an error code. */
+/* Some compilers try to substitute macro args in string literals! */
+/* NB that we cannot emit 'delta' style tile indices if VM error recovery */
+/* is in effect, since reader & writer's tile indices may get out of phase */
+/* as a consequence of error recoverly occurring. */
+#define cmd_put_tile_index_inline(cldev, pcls, indx)\
+ { int idelta = (indx) - (pcls)->tile_index + 8; byte *dp;\
+ if ( !(idelta & ~15) && clist_test_VMerror_recoverable(cldev) )\
+ { int code = set_cmd_put_op(dp, cldev, pcls, cmd_op_delta_tile_index + idelta, 1);\
+ if (code < 0)\
+ return code;\
+ }\
+ else\
+ { int code = set_cmd_put_op(dp, cldev, pcls, cmd_op_set_tile_index + ((indx) >> 8), 2);\
+ if (code < 0)\
+ return code;\
+ dp[1] = (indx) & 0xff;\
+ if_debug2('L', "[L]writing index=%u, offset=%lu\n",\
+ indx, cldev->tile_table[indx].offset);\
+ }\
+ }
+
+/* If necessary, write out data for a single color map. */
+int
+cmd_put_color_map(gx_device_clist_writer *cldev, cmd_map_index map_index,
+ const gx_transfer_map *map, gs_id *pid)
+{ byte *dp;
+ int code;
+
+ if ( map == 0 )
+ { if ( pid && *pid == gs_no_id )
+ return 0; /* no need to write */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_map + map_index;
+ if ( pid )
+ *pid = gs_no_id;
+ }
+ else
+ { if ( pid && map->id == *pid )
+ return 0; /* no need to write */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
+ 2 + sizeof(map->values));
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_map + 0x20 + map_index;
+ memcpy(dp + 2, map->values, sizeof(map->values));
+ if ( pid )
+ *pid = map->id;
+ }
+ return 0;
+}
+
+/* ------ Tile cache management ------ */
+
+/* We want consecutive ids to map to consecutive hash slots if possible, */
+/* so we can use a delta representation when setting the index. */
+#define tile_id_hash(id) (id)
+#define tile_hash_next(index) ((index) + 413) /* arbitrary large odd # */
+typedef struct tile_loc_s {
+ uint index;
+ tile_slot *tile;
+} tile_loc;
+
+/* Look up a tile or character in the cache. If found, set the index and */
+/* pointer; if not, set the index to the insertion point. */
+private bool
+clist_find_bits(gx_device_clist_writer *cldev, gx_bitmap_id id, tile_loc *ploc)
+{ uint index = tile_id_hash(id);
+ const tile_hash *table = cldev->tile_table;
+ uint mask = cldev->tile_hash_mask;
+ ulong offset;
+
+ for ( ; (offset = table[index &= mask].offset) != 0;
+ index = tile_hash_next(index)
+ )
+ { tile_slot *tile = (tile_slot *)(cldev->data + offset);
+ if ( tile->id == id )
+ { ploc->index = index;
+ ploc->tile = tile;
+ return true;
+ }
+ }
+ ploc->index = index;
+ return false;
+}
+
+/* Delete a tile from the cache. */
+private void
+clist_delete_tile(gx_device_clist_writer *cldev, tile_slot *slot)
+{ tile_hash *table = cldev->tile_table;
+ uint mask = cldev->tile_hash_mask;
+ uint index = slot->index;
+ ulong offset;
+
+ if_debug2('L', "[L]deleting index=%u, offset=%lu\n",
+ index, (ulong)((byte *)slot - cldev->data));
+ gx_bits_cache_free(&cldev->bits, (gx_cached_bits_head *)slot,
+ &cldev->chunk);
+ table[index].offset = 0;
+ /* Delete the entry from the hash table. */
+ /* We'd like to move up any later entries, so that we don't need */
+ /* a deleted mark, but it's too difficult to note this in the */
+ /* band list, so instead, we just delete any entries that */
+ /* would need to be moved. */
+ while ( (offset = table[index = tile_hash_next(index) & mask].offset) != 0 )
+ { tile_slot *tile = (tile_slot *)(cldev->data + offset);
+ tile_loc loc;
+ if ( !clist_find_bits(cldev, tile->id, &loc) )
+ { /* We didn't find it, so it should be moved into a slot */
+ /* that we just vacated; instead, delete it. */
+ if_debug2('L', "[L]move-deleting index=%u, offset=%lu\n",
+ index, offset);
+ gx_bits_cache_free(&cldev->bits,
+ (gx_cached_bits_head *)(cldev->data + offset),
+ &cldev->chunk);
+ table[index].offset = 0;
+ }
+ }
+}
+
+/* Add a tile to the cache. */
+/* tile->raster holds the raster for the replicated tile; */
+/* we pass the raster of the actual data separately. */
+private int
+clist_add_tile(gx_device_clist_writer *cldev, const gx_strip_bitmap *tiles,
+ uint sraster, int depth)
+{ uint raster = tiles->raster;
+ uint size_bytes = raster * tiles->size.y;
+ uint tsize =
+ sizeof(tile_slot) + cldev->tile_band_mask_size + size_bytes;
+ gx_cached_bits_head *slot_head;
+#define slot ((tile_slot *)slot_head)
+
+ if ( cldev->bits.csize == cldev->tile_max_count )
+ { /* Don't let the hash table get too full: delete an entry. */
+ /* Since gx_bits_cache_alloc returns an entry to delete when */
+ /* it fails, just force it to fail. */
+ gx_bits_cache_alloc(&cldev->bits, (ulong)cldev->chunk.size,
+ &slot_head);
+ if ( slot_head == 0 )
+ { /* Wrap around and retry. */
+ cldev->bits.cnext = 0;
+ gx_bits_cache_alloc(&cldev->bits, (ulong)cldev->chunk.size,
+ &slot_head);
+#ifdef DEBUG
+ if ( slot_head == 0 )
+ { lprintf("No entry to delete!\n");
+ return_error(gs_error_Fatal);
+ }
+#endif
+ }
+ clist_delete_tile(cldev, slot);
+ }
+ /* Allocate the space for the new entry, deleting entries as needed. */
+ while ( gx_bits_cache_alloc(&cldev->bits, (ulong)tsize, &slot_head) < 0 )
+ { if ( slot_head == 0 )
+ { /* Wrap around. */
+ if ( cldev->bits.cnext == 0 )
+ { /* Too big to fit. We should probably detect this */
+ /* sooner, since if we get here, we've cleared the */
+ /* cache. */
+ return_error(gs_error_limitcheck);
+ }
+ cldev->bits.cnext = 0;
+ }
+ else
+ clist_delete_tile(cldev, slot);
+ }
+ /* Fill in the entry. */
+ slot->cb_depth = depth;
+ slot->cb_raster = raster;
+ slot->width = tiles->rep_width;
+ slot->height = tiles->rep_height;
+ slot->shift = slot->rep_shift = tiles->rep_shift;
+ slot->x_reps = slot->y_reps = 1;
+ slot->id = tiles->id;
+ memset(ts_mask(slot), 0, cldev->tile_band_mask_size);
+ bytes_copy_rectangle(ts_bits(cldev, slot), raster,
+ tiles->data, sraster,
+ (tiles->rep_width * depth + 7) >> 3,
+ tiles->rep_height);
+ /* Make the hash table entry. */
+ { tile_loc loc;
+#ifdef DEBUG
+ if ( clist_find_bits(cldev, tiles->id, &loc) )
+ lprintf1("clist_find_bits(0x%lx) should have failed!\n",
+ (ulong)tiles->id);
+#else
+ clist_find_bits(cldev, tiles->id, &loc); /* always fails */
+#endif
+ slot->index = loc.index;
+ cldev->tile_table[loc.index].offset =
+ (byte *)slot_head - cldev->data;
+ if_debug2('L', "[L]adding index=%u, offset=%lu\n",
+ loc.index, cldev->tile_table[loc.index].offset);
+ }
+ slot->num_bands = 0;
+ return 0;
+}
+
+/* ------ Driver procedure support ------ */
+
+/* Change the tile parameters (size and depth). */
+/* Currently we do this for all bands at once. */
+private void
+clist_new_tile_params(gx_strip_bitmap *new_tile, const gx_strip_bitmap *tiles,
+ int depth, const gx_device_clist_writer *cldev)
+{ /*
+ * Adjust the replication factors. If we can, we replicate
+ * the tile in X up to 32 bytes, and then in Y up to 4 copies,
+ * as long as we don't exceed a total tile size of 256 bytes,
+ * or more than 255 repetitions in X or Y, or make the tile so
+ * large that not all possible tiles will fit in the cache.
+ * Also, don't attempt Y replication if shifting is required.
+ */
+#define max_tile_reps_x 255
+#define max_tile_bytes_x 32
+#define max_tile_reps_y 4
+#define max_tile_bytes 256
+ uint rep_width = tiles->rep_width;
+ uint rep_height = tiles->rep_height;
+ uint rep_width_bits = rep_width * depth;
+ uint tile_overhead =
+ sizeof(tile_slot) + cldev->tile_band_mask_size;
+ uint max_bytes = cldev->chunk.size / (rep_width_bits * rep_height);
+
+ max_bytes -= min(max_bytes, tile_overhead);
+ if ( max_bytes > max_tile_bytes )
+ max_bytes = max_tile_bytes;
+ *new_tile = *tiles;
+ { uint max_bits_x = max_bytes * 8 / rep_height;
+ uint reps_x =
+ min(max_bits_x, max_tile_bytes_x * 8) / rep_width_bits;
+ uint reps_y;
+
+ while ( reps_x > max_tile_reps_x )
+ reps_x >>= 1;
+ new_tile->size.x = max(reps_x, 1) * rep_width;
+ new_tile->raster = bitmap_raster(new_tile->size.x * depth);
+ if ( tiles->shift != 0 )
+ reps_y = 1;
+ else
+ { reps_y = max_bytes / (new_tile->raster * rep_height);
+ if ( reps_y > max_tile_reps_y )
+ reps_y = max_tile_reps_y;
+ else if ( reps_y < 1 )
+ reps_y = 1;
+ }
+ new_tile->size.y = reps_y * rep_height;
+ }
+#undef max_tile_reps_x
+#undef max_tile_bytes_x
+#undef max_tile_reps_y
+#undef max_tile_bytes
+}
+
+/* Change tile for clist_tile_rectangle. */
+int
+clist_change_tile(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_strip_bitmap *tiles, int depth)
+{ tile_loc loc;
+ int code;
+
+#define tile_params_differ(cldev, tiles, depth)\
+ ((tiles)->rep_width != (cldev)->tile_params.rep_width ||\
+ (tiles)->rep_height != (cldev)->tile_params.rep_height ||\
+ (tiles)->rep_shift != (cldev)->tile_params.rep_shift ||\
+ (depth) != (cldev)->tile_depth)
+
+top: if ( clist_find_bits(cldev, tiles->id, &loc) )
+ { /* The bitmap is in the cache. Check whether this band */
+ /* knows about it. */
+ int band_index = pcls - cldev->states;
+ byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
+ byte bmask = 1 << (band_index & 7);
+
+ if ( *bptr & bmask )
+ { /* Already known. Just set the index. */
+ if ( pcls->tile_index == loc.index )
+ return 0;
+ cmd_put_tile_index_inline(cldev, pcls, loc.index);
+ }
+ else
+ { uint extra = 0;
+ if tile_params_differ(cldev, tiles, depth)
+ { /*
+ * We have a cached tile whose parameters differ from
+ * the current ones. Because of the way tile IDs are
+ * managed, this is currently only possible when mixing
+ * Patterns and halftones, but if we didn't generate new
+ * IDs each time the main halftone cache needed to be
+ * refreshed, this could also happen simply from
+ * switching screens.
+ */
+ int band;
+
+ clist_new_tile_params(&cldev->tile_params, tiles, depth,
+ cldev);
+ cldev->tile_depth = depth;
+ /* No band knows about the new parameters. */
+ for ( band = cldev->tile_known_min;
+ band <= cldev->tile_known_max;
+ ++band
+ )
+ cldev->states[band].known &= ~tile_params_known;
+ cldev->tile_known_min = cldev->nbands;
+ cldev->tile_known_max = -1;
+ }
+ if ( !(pcls->known & tile_params_known) )
+ { /* We're going to have to write the tile parameters. */
+ extra = cmd_size_tile_params(&cldev->tile_params);
+ }
+ { /*
+ * This band doesn't know this tile yet, so output the
+ * bits. Note that the offset we write is the one used by
+ * the reading phase, not the writing phase. Note also
+ * that the size of the cached and written tile may differ
+ * from that of the client's tile. Finally, note that
+ * this tile's size parameters are guaranteed to be
+ * compatible with those stored in the device
+ * (cldev->tile_params).
+ */
+ ulong offset = (byte *)loc.tile - cldev->chunk.data;
+ uint rsize =
+ extra + 1 + cmd_size_w(loc.index) + cmd_size_w(offset);
+ byte *dp;
+ uint csize;
+ uint compress;
+ int code =
+ cmd_put_bits(cldev, pcls, ts_bits(cldev, loc.tile),
+ tiles->rep_width * depth, tiles->rep_height,
+ loc.tile->cb_raster, rsize,
+ (cldev->tile_params.size.x > tiles->rep_width ?
+ decompress_elsewhere | decompress_spread :
+ decompress_elsewhere),
+ &dp, &csize);
+
+ if ( code < 0 )
+ return code;
+ compress = (uint)code;
+ if ( extra )
+ { /* Write the tile parameters before writing the bits. */
+ cmd_store_tile_params(dp, &cldev->tile_params, depth,
+ extra);
+ dp += extra;
+ /* This band now knows the parameters. */
+ pcls->known |= tile_params_known;
+ if ( band_index < cldev->tile_known_min )
+ cldev->tile_known_min = band_index;
+ if ( band_index > cldev->tile_known_max )
+ cldev->tile_known_max = band_index;
+ }
+ *dp = cmd_count_op(cmd_opv_set_tile_bits, csize - extra);
+ dp++;
+ dp = cmd_put_w(loc.index, dp);
+ cmd_put_w(offset, dp);
+ *bptr |= bmask;
+ loc.tile->num_bands++;
+ }
+ }
+ pcls->tile_index = loc.index;
+ pcls->tile_id = loc.tile->id;
+ return 0;
+ }
+ /* The tile is not in the cache, add it. */
+ { gx_strip_bitmap new_tile;
+ gx_strip_bitmap *ptile;
+
+ /* Ensure that the tile size is compatible. */
+ if ( tile_params_differ(cldev, tiles, depth) )
+ { /* We'll reset cldev->tile_params when we write the bits. */
+ clist_new_tile_params(&new_tile, tiles, depth, cldev);
+ ptile = &new_tile;
+ }
+ else
+ { cldev->tile_params.id = tiles->id;
+ cldev->tile_params.data = tiles->data;
+ ptile = &cldev->tile_params;
+ }
+ code = clist_add_tile(cldev, ptile, tiles->raster, depth);
+ if ( code < 0 )
+ return code;
+ }
+ goto top;
+#undef tile_params_differ
+}
+
+/* Change "tile" for clist_copy_*. tiles->[rep_]shift must be zero. */
+int
+clist_change_bits(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_strip_bitmap *tiles, int depth)
+{ tile_loc loc;
+ int code;
+
+top: if ( clist_find_bits(cldev, tiles->id, &loc) )
+ { /* The bitmap is in the cache. Check whether this band */
+ /* knows about it. */
+ uint band_index = pcls - cldev->states;
+ byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
+ byte bmask = 1 << (band_index & 7);
+
+ if ( *bptr & bmask )
+ { /* Already known. Just set the index. */
+ if ( pcls->tile_index == loc.index )
+ return 0;
+ cmd_put_tile_index_inline(cldev, pcls, loc.index);
+ }
+ else
+ { /* Not known yet. Output the bits. */
+ /* Note that the offset we write is the one used by */
+ /* the reading phase, not the writing phase. */
+ ulong offset = (byte *)loc.tile - cldev->chunk.data;
+ uint rsize = 2 + cmd_size_w(loc.tile->width) +
+ cmd_size_w(loc.tile->height) + cmd_size_w(loc.index) +
+ cmd_size_w(offset);
+ byte *dp;
+ uint csize;
+ uint compress;
+ gx_clist_state *bit_pcls = pcls;
+ int code;
+
+ if ( loc.tile->num_bands == CHAR_ALL_BANDS_COUNT )
+ bit_pcls = NULL;
+ code = cmd_put_bits(cldev, bit_pcls, ts_bits(cldev, loc.tile),
+ loc.tile->width * depth,
+ loc.tile->height, loc.tile->cb_raster,
+ rsize,
+ (1 << cmd_compress_cfe) | decompress_elsewhere,
+ &dp, &csize);
+
+ if ( code < 0 )
+ return code;
+ compress = (uint)code;
+ *dp = cmd_count_op(cmd_opv_set_bits, csize);
+ dp[1] = (depth << 2) + compress;
+ dp += 2;
+ dp = cmd_put_w(loc.tile->width, dp);
+ dp = cmd_put_w(loc.tile->height, dp);
+ dp = cmd_put_w(loc.index, dp);
+ cmd_put_w(offset, dp);
+ if ( bit_pcls == NULL )
+ { memset(ts_mask(loc.tile), 0xff,
+ cldev->tile_band_mask_size);
+ loc.tile->num_bands = cldev->nbands;
+ }
+ else
+ { *bptr |= bmask;
+ loc.tile->num_bands++;
+ }
+ }
+ pcls->tile_index = loc.index;
+ pcls->tile_id = loc.tile->id;
+ return 0;
+ }
+ /* The tile is not in the cache. */
+ code = clist_add_tile(cldev, tiles, tiles->raster, depth);
+ if ( code < 0 )
+ return code;
+ goto top;
+}
diff --git a/gs/src/gxcldev.h b/gs/src/gxcldev.h
new file mode 100644
index 000000000..b760fdab6
--- /dev/null
+++ b/gs/src/gxcldev.h
@@ -0,0 +1,636 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcldev.h */
+/* Internal definitions for Ghostscript command lists. */
+#include "gxclist.h"
+#include "gsropt.h"
+#include "gxht.h" /* for gxdht.h */
+#include "gxtmap.h" /* ditto */
+#include "gxdht.h" /* for halftones */
+#include "strimpl.h" /* for compressed bitmaps */
+#include "scfx.h" /* ditto */
+#include "srlx.h" /* ditto */
+
+/* The implementation files define cdev as either crdev or cwdev. */
+#define ccdev (&((gx_device_clist *)dev)->common)
+#define cwdev (&((gx_device_clist *)dev)->writer)
+#define crdev (&((gx_device_clist *)dev)->reader)
+
+/* ---------------- Commands ---------------- */
+
+/* Define the compression modes for bitmaps. */
+/*#define cmd_compress_none 0*/ /* (implicit) */
+#define cmd_compress_rle 1
+#define clist_rle_init(ss)\
+ { s_RLE_set_defaults_inline(ss);\
+ s_RLE_init_inline(ss);\
+ }
+#define clist_rld_init(ss)\
+ { s_RLD_set_defaults_inline(ss);\
+ s_RLD_init_inline(ss);\
+ }
+#define cmd_compress_cfe 2
+#define clist_cf_init(ss, width, mem)\
+ { (ss)->memory = (mem);\
+ (ss)->K = -1;\
+ (ss)->Columns = (width);\
+ (ss)->EndOfBlock = false;\
+ (ss)->BlackIs1 = true;\
+ (ss)->DecodedByteAlign = align_bitmap_mod;\
+ }
+#define clist_cfe_init(ss, width, mem)\
+ { s_CFE_set_defaults_inline(ss);\
+ clist_cf_init(ss, width, mem);\
+ (*s_CFE_template.init)((stream_state *)(ss));\
+ }
+#define clist_cfd_init(ss, width, height, mem)\
+ { (*s_CFD_template.set_defaults)((stream_state *)ss);\
+ clist_cf_init(ss, width, mem);\
+ (ss)->Rows = (height);\
+ (*s_CFD_template.init)((stream_state *)(ss));\
+ }
+#define cmd_mask_compress_any\
+ ((1 << cmd_compress_rle) | (1 << cmd_compress_cfe))
+
+/*
+ * A command always consists of an operation followed by operands;
+ * the syntax of the operands depends on the operation.
+ * In the operation definitions below:
+ * + (prefixed) means the operand is in the low 4 bits of the opcode.
+ * # means a variable-size operand encoded with the variable-size
+ * integer encoding.
+ * % means a variable-size operand encoded with the variable-size
+ * fixed coordinate encoding.
+ * $ means a color sized according to the device depth.
+ * <> means the operand size depends on other state information
+ * and/or previous operands.
+ */
+typedef enum {
+ cmd_op_misc = 0x00, /* (see below) */
+ cmd_opv_end_run = 0x00, /* (nothing) */
+ cmd_opv_set_tile_size = 0x01, /* rs?(1)nry?(1)nrx?(1)depth-1(5), */
+ /* rep_width#, rep_height#, */
+ /* [, nreps_x#][, nreps_y #] */
+ /* [, rep_shift#] */
+ cmd_opv_set_tile_phase = 0x02, /* x#, y# */
+ cmd_opv_set_tile_bits = 0x03, /* index#, offset#, <bits> */
+ cmd_opv_set_bits = 0x04, /* depth*4+compress, width#, height#, */
+ /* index#, offset#, <bits> */
+ cmd_opv_set_tile_color = 0x05, /* (nothing; next set/delta_color */
+ /* refers to tile) */
+ cmd_opv_set_misc = 0x06,
+#define cmd_set_misc_lop (0 << 6) /* 00: lop_lsb(6), lop_msb# */
+#define cmd_set_misc_data_x (1 << 6) /* 01: more(1)dx_lsb(5)[, dx_msb#] */
+#define cmd_set_misc_map (2 << 6) /* 10: non-0(1)map_index(5) */
+ /* [, n x frac] */
+#define cmd_set_misc_halftone (3 << 6) /* 11: type(6), num_comp# */
+ cmd_opv_enable_lop = 0x07, /* (nothing) */
+ cmd_opv_disable_lop = 0x08, /* (nothing) */
+ cmd_opv_set_ht_order = 0x09, /* component+1#[, cname#], */
+ /* width#, height#, raster#, */
+ /* shift#, num_levels#, num_bits# */
+ cmd_opv_set_ht_data = 0x0a, /* n, n x (uint|gx_ht_bit) */
+ cmd_opv_end_page = 0x0b, /* (nothing) */
+ cmd_opv_delta2_color0 = 0x0c, /* dr5dg6db5 or dc4dm4dy4dk4 */
+#define cmd_delta2_24_bias 0x00102010
+#define cmd_delta2_24_mask 0x001f3f1f
+#define cmd_delta2_32_bias 0x08080808
+#define cmd_delta2_32_mask 0x0f0f0f0f
+ cmd_opv_delta2_color1 = 0x0d, /* <<same as color0>> */
+ cmd_opv_set_copy_color = 0x0e, /* (nothing) */
+ cmd_opv_set_copy_alpha = 0x0f, /* (nothing) */
+ cmd_op_set_color0 = 0x10, /* +15 = transparent | */
+ /* +0, color$ | +dcolor+8 | */
+ /* +dr4, dg4db4 | */
+ /* +dc3dm1, dm2dy3dk3 */
+ cmd_op_set_color1 = 0x20, /* <<same as color0>> */
+#define cmd_delta1_24_bias 0x00080808
+#define cmd_delta1_24_mask 0x000f0f0f
+#define cmd_delta1_32_bias 0x04040404
+#define cmd_delta1_32_mask 0x07070707
+ cmd_op_fill_rect = 0x30, /* +dy2dh2, x#, w# | +0, rect# */
+ cmd_op_fill_rect_short = 0x40, /* +dh, dx, dw | +0, rect_short */
+ cmd_op_fill_rect_tiny = 0x50, /* +dw+0, rect_tiny | +dw+8 */
+ cmd_op_tile_rect = 0x60, /* +dy2dh2, x#, w# | +0, rect# */
+ cmd_op_tile_rect_short = 0x70, /* +dh, dx, dw | +0, rect_short */
+ cmd_op_tile_rect_tiny = 0x80, /* +dw+0, rect_tiny | +dw+8 */
+ cmd_op_copy_mono = 0x90, /* +compress, x#, y#, (w+data_x)#, */
+ /* h#, <bits> | */
+#define cmd_copy_ht_color 4
+ /* +4+compress, x#, y#, (w+data_x)#, */
+ /* h#, <bits> | */
+#define cmd_copy_use_tile 8
+ /* +8 (use tile), x#, y# | */
+ /* +12 (use tile), x#, y# */
+ cmd_op_copy_color_alpha = 0xa0, /* (same as copy_mono, except: */
+ /* if color, ignore ht_color; */
+ /* if alpha & !use_tile, depth is */
+ /* first operand) */
+ cmd_op_delta_tile_index = 0xb0, /* +delta+8 */
+ cmd_op_set_tile_index = 0xc0 /* +index[11:8], index[7:0] */
+} gx_cmd_op;
+
+#define cmd_op_name_strings\
+ "(misc)", "set_color[0]", "set_color[1]", "fill_rect",\
+ "fill_rect_short", "fill_rect_tiny", "tile_rect", "tile_rect_short",\
+ "tile_rect_tiny", "copy_mono", "copy_color_alpha", "delta_tile_index",\
+ "set_tile_index", "?dx?", "?ex?", "?fx?"
+
+#define cmd_misc_op_name_strings\
+ "end_run", "set_tile_size", "set_tile_phase", "set_tile_bits",\
+ "set_bits", "set_tile_color", "set_misc", "enable_lop",\
+ "disable_lop", "set_ht_order", "set_ht_data", "end_page",\
+ "delta2_color0", "delta2_color1", "set_copy_color", "set_copy_alpha",
+
+#ifdef DEBUG
+extern const char *cmd_op_names[16];
+extern const char **cmd_sub_op_names[16];
+#endif
+
+/*
+ * Define the size of the largest command, not counting any bitmap or
+ * similar variable-length operands.
+ * The variable-size integer encoding is little-endian. The low 7 bits
+ * of each byte contain data; the top bit is 1 for all but the last byte.
+ */
+#define cmd_max_intsize(siz)\
+ (((siz) * 8 + 6) / 7)
+#define cmd_largest_size\
+ (2 + (1 + cmd_max_dash) * sizeof(float))
+
+/* ---------------- Command parameters ---------------- */
+
+/* Rectangle */
+typedef struct {
+ int x, y, width, height;
+} gx_cmd_rect;
+/* Short rectangle */
+typedef struct {
+ byte dx, dwidth, dy, dheight; /* dy and dheight are optional */
+} gx_cmd_rect_short;
+#define cmd_min_short (-128)
+#define cmd_max_short 127
+/* Tiny rectangle */
+#define cmd_min_dw_tiny (-4)
+#define cmd_max_dw_tiny 3
+typedef struct {
+ unsigned dx : 4;
+ unsigned dy : 4;
+} gx_cmd_rect_tiny;
+#define cmd_min_dxy_tiny (-8)
+#define cmd_max_dxy_tiny 7
+
+/*
+ * When we write bitmaps, we remove raster padding selectively:
+ * - If the bitmap is compressed, we don't remove any padding;
+ * - If the width is <= 6 bytes, we remove all the padding;
+ * - If the bitmap is only 1 scan line high, we remove the padding;
+ * - If the bitmap is going to be replicated horizontally (see the
+ * definition of decompress_spread below), we remove the padding;
+ * - Otherwise, we remove the padding only from the last scan line.
+ */
+#define cmd_max_short_width_bytes 6
+#define cmd_max_short_width_bits (cmd_max_short_width_bytes * 8)
+/*
+ * Determine the (possibly unpadded) width in bytes for writing a bitmap,
+ * per the algorithm just outlined. If compression_mask has any of the
+ * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
+ * Return the total size of the bitmap.
+ */
+uint clist_bitmap_bytes(P5(uint width_bits, uint height,
+ int compression_mask,
+ uint *width_bytes, uint *raster));
+/*
+ * For halftone cells, we always write an unreplicated bitmap, but we
+ * reserve cache space for the reading pass based on the replicated size.
+ * See the clist_change_tile procedure for the algorithm that chooses the
+ * replication factors.
+ */
+
+/* ---------------- Block file entries ---------------- */
+
+typedef struct cmd_block_s {
+ int band_min, band_max;
+#define cmd_band_end (-1) /* end of band file */
+ long pos; /* starting position in cfile */
+} cmd_block;
+
+/* ---------------- Band state ---------------- */
+
+/* Remember the current state of one band when writing or reading. */
+struct gx_clist_state_s {
+ gx_color_index colors[2]; /* most recent colors */
+ uint tile_index; /* most recent tile index */
+ gx_bitmap_id tile_id; /* most recent tile id */
+/* Since tile table entries may be deleted and/or moved at any time, */
+/* the following is the only reliable way to check whether tile_index */
+/* references a particular tile id: */
+#define cls_has_tile_id(cldev, pcls, tid, offset_temp)\
+ ((pcls)->tile_id == (tid) &&\
+ (offset_temp = cldev->tile_table[(pcls)->tile_index].offset) != 0 &&\
+ ((tile_slot *)(cldev->data + offset_temp))->id == (tid))
+ gs_int_point tile_phase; /* most recent tile phase */
+ gx_color_index tile_colors[2]; /* most recent tile colors */
+ gx_cmd_rect rect; /* most recent rectangle */
+ gs_logical_operation_t lop; /* most recent logical op */
+ short lop_enabled; /* 0 = don't use lop, 1 = use lop, */
+ /* -1 is used internally */
+ short clip_enabled; /* 0 = don't clip, 1 = do clip, */
+ /* -1 is used internally */
+ ushort color_is_alpha; /* (Boolean) for copy_color_alpha */
+ ushort known; /* flags for whether this band */
+ /* knows various misc. parameters */
+ /* We assign 'known' flags here from the high end; */
+ /* gxclpath.h assigns them from the low end. */
+#define tile_params_known (1<<15)
+#define begin_image_known (1<<14)
+#define initial_known 0x3fff /* exclude tile params */
+ /* Following are only used when writing */
+ cmd_list list; /* list of commands for band */
+ /* Following is set when writing, read when reading */
+ ulong cost; /* cost of rendering the band */
+};
+
+/* The initial values for a band state */
+/*static const gx_clist_state cls_initial*/
+#define cls_initial_values\
+ { gx_no_color_index, gx_no_color_index },\
+ 0, gx_no_bitmap_id,\
+ { 0, 0 }, { gx_no_color_index, gx_no_color_index },\
+ { 0, 0, 0, 0 }, lop_default, 0, 0, 0, initial_known,\
+ { 0, 0 }, 0
+
+/* Define the size of the command buffer used for reading. */
+/* This is needed to split up operations with a large amount of data, */
+/* primarily large copy_ operations. */
+#define cbuf_size 800
+
+/* ---------------- Driver procedure support ---------------- */
+
+/* The procedures and macros defined here are used when writing */
+/* (gxclist.c, gxclbits.c, gxclpath.c). */
+/* NB cmd_put_xxx's do NO VM error recovery, and upgrade lo-mem warnings to errors */
+
+/* ------ Exported by gxclist.c ------ */
+
+/*
+ * Error recovery procedures for writer-side VM errors, for async rendering support.
+ * This logic assumes that the command list file and/or the renderer allocate
+ * memory from the same pool as the writer. Hence, when the writer runs out
+ * of memory, it tries to pause and let the renderer run for a while in hope
+ * that enough memory will be freed by it to allow the writer to allocate enough
+ * memory to proceed. Once a VM error is detected, error recovery proceeds in two
+ * escalating stages:
+ * 1) The recovery logic repeatedly calls clist_try_recover_VMerror(), which
+ * waits until the next page has finished rendering. The recovery logic
+ * keeps calling clist_try_recover_VMerror() until enough memory is freed,
+ * or until clist_try_recover_VMerror() signals that no more pages
+ * remain to be rendered.
+ * 2) If enough memory is not free, the recovery logic calls
+ * clist_try_recover_VMerror_flush() once. This routine terminates and
+ * flushes out the partially-completed page that the writer is currently
+ * writing to the command file, then waits for the partial page to finish
+ * rendering. It then opens up a new command list "file" and resets the
+ * state of the command list machinery to an initial state as if a new
+ * page were beginning.
+ *
+ * If insufficient memory is available after the 2nd step, the situation
+ * is the same as if it ocurred in a non-async setup: the writer program
+ * simply used up too much memory and cannot continue.
+ *
+ * The first stage of error recovery (no flush) is performed without flushing
+ * out the current page, so failing commands can simply be restarted after
+ * such recovery. This is not true of 2nd stage recovery (flush). It is important
+ * to realize that the failing command is most likely relying on the graphics
+ * state of the renderer matching that of the writer; this will always be
+ * true as long as the writer & renderer are generating/processing the same
+ * command stream. If 2nd stage recovery flushes, the assumption will no
+ * longer be valid since the flush magically resets the state of both writer
+ * and renderer to initial values. In this event, the recovery logic which
+ * called clist_try_recover_VMerror_flush() must force any pertinent state
+ * information to be re-emitted before re-issuing the failing command.
+ *
+ * Error recovery is mainly performed by the high-level driver calls to
+ * gxclist. Its implementation is packaged up in the BEGIN_RECT, et al macros
+ * in gxcldev.h, but--as noted above--recovery is not fully transparent.
+ * Other routines which perform error recovery are those which open the
+ * device, begin a new page, or reopen the device (put_params).
+ */
+int clist_try_recover_VMerror(P2(gx_device_clist_writer *, int));
+int clist_try_recover_VMerror_flush(P2(gx_device_clist_writer *, int));
+
+
+int cmd_put_params(P2(gx_device_clist_writer *, gs_param_list *));
+
+/* Conditionally keep command statistics. */
+#ifdef DEBUG
+int cmd_count_op(P2(int op, uint size));
+void cmd_uncount_op(P2(int op, uint size));
+# define cmd_count_add1(v) (v++)
+#else
+# define cmd_count_op(op, size) (op)
+# define cmd_uncount_op(op, size) DO_NOTHING
+# define cmd_count_add1(v) DO_NOTHING
+#endif
+
+/* Add a command to the appropriate band list, */
+/* and allocate space for its data. */
+/* NB do NO VM error recovery, and upgrade lo-mem warnings to errors */
+byte *cmd_put_list_op(P3(gx_device_clist_writer *cldev, cmd_list *pcl, uint size));
+#ifdef DEBUG
+byte *cmd_put_op(P3(gx_device_clist_writer *cldev, gx_clist_state *pcls, uint size));
+#else
+# define cmd_put_op(cldev, pcls, size)\
+ cmd_put_list_op(cldev, &(pcls)->list, size)
+#endif
+/* Call cmd_put_op and update stats if no error occurs. */
+#define set_cmd_put_op(dp, cldev, pcls, op, csize)\
+ ( ( ( dp = cmd_put_op(cldev, pcls, csize) ) == 0 )\
+ ? (cldev)->error_code : ( ( *dp = cmd_count_op(op, csize) ), 0 ) )
+
+/* Add a command for all bands or a range of bands. */
+/* NB do NO VM error recovery, and upgrade lo-mem warnings to errors */
+byte *cmd_put_range_op(P4(gx_device_clist_writer *cldev, int band_min,
+ int band_max, uint size));
+#define cmd_put_all_op(cldev, size)\
+ cmd_put_range_op(cldev, 0, (cldev)->nbands - 1, size)
+/* Call cmd_put_all/range_op and update stats if no error occurs. */
+#define set_cmd_put_range_op(dp, cldev, op, bmin, bmax, csize)\
+ ( ( ( dp = cmd_put_range_op(cldev, bmin, bmax, csize) ) == 0 )\
+ ? (cldev)->error_code : ( ( *dp = cmd_count_op(op, csize) ), 0 ) )
+#define set_cmd_put_all_op(dp, cldev, op, csize)\
+ set_cmd_put_range_op(dp, cldev, op, 0, (cldev)->nbands - 1, csize)
+
+/* Shorten the last allocated command. */
+/* Note that this does not adjust the statistics. */
+#define cmd_shorten_list_op(cldev, pcls, delta)\
+ ((pcls)->tail->size -= (delta), (cldev)->cnext -= (delta))
+#define cmd_shorten_op(cldev, pcls, delta)\
+ cmd_shorten_list_op(cldev, &(pcls)->list, delta)
+
+/* End a page by flushing the buffer and terminating the command list. */
+int clist_end_page(P1(gx_device_clist_writer *));
+
+/* Compute the # of bytes required to represent a variable-size integer. */
+/* (This works for negative integers also; they are written as though */
+/* they were unsigned.) */
+int cmd_size_w(P1(uint));
+#define w1byte(w) (!((w) & ~0x7f))
+#define w2byte(w) (!((w) & ~0x3fff))
+#define cmd_sizew(w)\
+ (w1byte(w) ? 1 : w2byte(w) ? 2 : cmd_size_w((uint)(w)))
+#define cmd_size2w(wx,wy)\
+ (w1byte((wx) | (wy)) ? 2 :\
+ cmd_size_w((uint)(wx)) + cmd_size_w((uint)(wy)))
+#define cmd_sizexy(xy) cmd_size2w((xy).x, (xy).y)
+#define cmd_sizew_max ((sizeof(uint) * 8 + 6) / 7)
+
+/* Put a variable-size integer in the buffer. */
+byte *cmd_put_w(P2(uint, byte *));
+#define cmd_putw(w,dp)\
+ (w1byte(w) ? (*dp = w, ++dp) :\
+ w2byte(w) ? (*dp = (w) | 0x80, dp[1] = (w) >> 7, dp += 2) :\
+ (dp = cmd_put_w((uint)(w), dp)))
+#define cmd_put2w(wx,wy,dp)\
+ (w1byte((wx) | (wy)) ? (dp[0] = (wx), dp[1] = (wy), dp += 2) :\
+ (dp = cmd_put_w((uint)(wy), cmd_put_w((uint)(wx), dp))))
+#define cmd_putxy(xy,dp) cmd_put2w((xy).x, (xy).y, dp)
+
+/* Put out a command to set a color. */
+typedef struct {
+ byte set_op;
+ byte delta2_op;
+ bool tile_color;
+} clist_select_color_t;
+extern const clist_select_color_t
+ clist_select_color0, clist_select_color1,
+ clist_select_tile_color0, clist_select_tile_color1;
+int cmd_put_color(P5(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const clist_select_color_t *select,
+ gx_color_index color, gx_color_index *pcolor));
+#define cmd_set_color0(dev, pcls, color0)\
+ cmd_put_color(dev, pcls, &clist_select_color0, color0, &(pcls)->colors[0])
+#define cmd_set_color1(dev, pcls, color1)\
+ cmd_put_color(dev, pcls, &clist_select_color1, color1, &(pcls)->colors[1])
+
+/* Put out a command to set the tile colors. */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_set_tile_colors(P4(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ gx_color_index color0, gx_color_index color1));
+
+/* Put out a command to set the tile phase. */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_set_tile_phase(P4(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int px, int py));
+
+/* Enable or disable the logical operation. */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_put_enable_lop(P3(gx_device_clist_writer *, gx_clist_state *, int));
+#define cmd_do_enable_lop(cldev, pcls, enable)\
+ ( ( (pcls)->lop_enabled == ( (enable) ^ 1 ) &&\
+ cmd_put_enable_lop(cldev, pcls, enable) < 0 ) ? (cldev)->error_code : 0 )
+#define cmd_enable_lop(cldev, pcls)\
+ cmd_do_enable_lop(cldev, pcls, 1)
+#define cmd_disable_lop(cldev, pcls)\
+ cmd_do_enable_lop(cldev, pcls, 0)
+
+/* Enable or disable clipping. */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+extern byte cmd_opvar_enable_clip, cmd_opvar_disable_clip;
+int cmd_put_enable_clip(P3(gx_device_clist_writer *, gx_clist_state *, int));
+#define cmd_do_enable_clip(cldev, pcls, enable)\
+ ( ( (pcls)->clip_enabled == ( (enable) ^ 1 ) &&\
+ cmd_put_enable_clip(cldev, pcls, enable) < 0 ) ? (cldev)->error_code : 0 )
+#define cmd_enable_clip(cldev, pcls)\
+ cmd_do_enable_clip(cldev, pcls, 1)
+#define cmd_disable_clip(cldev, pcls)\
+ cmd_do_enable_clip(cldev, pcls, 0)
+
+/* Write a command to set the logical operation. */
+/* NB do NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_set_lop(P3(gx_device_clist_writer *, gx_clist_state *,
+ gs_logical_operation_t));
+
+/*
+ * Define macros for dividing up an operation into bands.
+ * Note that BEGIN_RECT resets y and height. It is OK for the code that
+ * processes each band to reset height to a smaller (positive) value;
+ * the vertical subdivision code in copy_mono, copy_color, and copy_alpha
+ * makes use of this. The band processing code may `continue' (to reduce
+ * nesting of conditionals).
+ *
+ * Recoverable band writing errors should use ERROR_RECT(), which will attempt
+ * to fix the VM error by flushing and closing the band and resetting the
+ * imager state, and then restart emitting the entire band. Before flushing
+ * the file, the 'on_error' clause of END_RECT_ON_ERROR (defaults to the
+ * constant 1 if END_RECT is used) is evaluated and tested.
+ * The 'on_error' clause enables mop-up actions to be executed before flushing,
+ * and/or selectively inhibits the flush, close, reset and restart process.
+ * Similarly, the 'after_recovering' clause of END_RECT_ON_ERROR allows an
+ * action to get performed after successfully recovering.
+ *
+ * When emitting data to the band file, you can wrap each operation with
+ * TRY_RECT and HANDLE_RECT_UNLESS() (or HANDLE_RECT). This will perform a
+ * less agressive type of local VMerror recovery -- waiting for some memory to become
+ * free and then retrying the failed operation within TRY/HANDLE_RECT. In
+ * the event that such local recovery is unsuccessful, ERROR_RECT recovery is
+ * invoked.
+ *
+ * Within BEGIN/END_RECT, wrap with NEST/UNNEST_RECT any calls to routines
+ * which might TRY/HANDLE_RECTs or ERROR_RECTs. This will prevent nested routines
+ * from attempting to flush and close the band, and will cause ERROR_RECT to
+ * simply return an error. N.B. that TRY/HANDLE_RECT will still attempt
+ * local recovery (see above). By convention, calls to cmd_put_xxx
+ * or cmd_set_xxx never attempt recovery and so never require NEXT_RECTs.
+ *
+ * Note that, to avoid attempts to write to unallocated memory, no attempt
+ * is made to write to the command list if permanent_error is set.
+ */
+#define BEGIN_RECT\
+ { int yend = y + height;\
+ int band_height = cdev->page_band_height;\
+ int band_code;\
+ if (cdev->permanent_error < 0)\
+ return (cdev->permanent_error);\
+ do { int band = y / band_height;\
+ gx_clist_state *pcls = cdev->states + band;\
+ int band_end = (band + 1) * band_height;\
+ height = min(band_end, yend) - y;\
+ retry_rect: ;\
+ {
+#define NEST_RECT (++cdev->driver_call_nesting)
+#define UNNEST_RECT (--cdev->driver_call_nesting)
+#define ERROR_RECT(expr)\
+ { band_code = (expr);\
+ goto error_in_rect;\
+ }
+#define TRY_RECT\
+ { do\
+ {
+#define HANDLE_RECT_UNLESS(errvar, unl_clause)\
+ }\
+ while ( errvar < 0\
+ && !( errvar = clist_try_recover_VMerror( cdev, (errvar) ) ) );\
+ if ( errvar < 0 && !(unl_clause) )\
+ ERROR_RECT(errvar)\
+ }
+#define HANDLE_RECT(errvar)\
+ HANDLE_RECT_UNLESS(errvar, 0)
+#define END_RECT_ON_ERROR(on_error, after_recovering)\
+ }\
+ continue;\
+ error_in_rect: if ( cdev->error_is_retryable\
+ && (on_error)\
+ && cdev->driver_call_nesting == 0\
+ && ( band_code = clist_try_recover_VMerror_flush\
+ (cdev, band_code) ) >= 0\
+ && (after_recovering) )\
+ goto retry_rect;\
+ else\
+ return band_code;\
+ }\
+ while ( (y += height) < yend );\
+ }
+#define END_RECT END_RECT_ON_ERROR(1, 1)
+#define DEFAULT_ON_ERROR_RECT 1
+#define ON_ERROR_RECT DEFAULT_ON_ERROR_RECT
+#define DEFAULT_AFTER_RECOVERING_ERROR_RECT 1
+#define AFTER_RECOVERING_ERROR_RECT DEFAULT_AFTER_RECOVERING_ERROR_RECT
+
+/* ------ Exported by gxclrect.c ------ */
+
+/* Put out a fill or tile rectangle command. */
+int cmd_write_rect_cmd(P7(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int op, int x, int y, int width, int height));
+
+/* ------ Exported by gxclbits.c ------ */
+
+/*
+ * Put a bitmap in the buffer, compressing if appropriate.
+ * pcls == 0 means put the bitmap in all bands.
+ * Return <0 if error
+ * A return value of gs_error_limitcheck means that the bitmap was too big
+ * to fit in the command reading buffer.
+ * Note that this leaves room for the command and initial arguments,
+ * but doesn't fill them in.
+ *
+ * If decompress_elsewhere is set in the compression_mask, it is OK
+ * to write out a compressed bitmap whose decompressed size is too large
+ * to fit in the command reading buffer. (This is OK when reading a
+ * cached bitmap, but not a bitmap for a one-time copy operation.)
+ */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+#define decompress_elsewhere 0x100
+/*
+ * If decompress_spread is set, the decompressed data will be spread out
+ * for replication, so we drop all the padding even if the width is
+ * greater than cmd_max_short_width_bytes (see above).
+ */
+#define decompress_spread 0x200
+
+int cmd_put_bits(P10(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const byte *data, uint width_bits, uint height,
+ uint raster, int op_size, int compression_mask,
+ byte **pdp, uint *psize));
+
+/*
+ * Put out commands for a color map (transfer function, black generation, or
+ * undercolor removal). If pid != 0, write the map only if its ID differs
+ * from the current one, and update the saved ID in the case.
+ */
+typedef enum {
+ cmd_map_transfer = 0, /* all transfer functions */
+ cmd_map_transfer_0, /* transfer[0] */
+ cmd_map_transfer_1, /* transfer[1] */
+ cmd_map_transfer_2, /* transfer[2] */
+ cmd_map_transfer_3, /* transfer[3] */
+ cmd_map_ht_transfer, /* transfer fn of most recent halftone order */
+ cmd_map_black_generation,
+ cmd_map_undercolor_removal
+} cmd_map_index;
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_put_color_map(P4(gx_device_clist_writer *cldev,
+ cmd_map_index map_index,
+ const gx_transfer_map *map, gs_id *pid));
+
+/*
+ * Change tiles for clist_tile_rectangle. (We make this a separate
+ * procedure primarily for readability.)
+ */
+int clist_change_tile(P4(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_strip_bitmap *tiles, int depth));
+
+/*
+ * Change "tile" for clist_copy_*. Only uses tiles->{data, id, raster,
+ * rep_width, rep_height}. tiles->[rep_]shift must be zero.
+ */
+int clist_change_bits(P4(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_strip_bitmap *tiles, int depth));
+
+/* ------ Exported by gxclimag.c ------ */
+
+/*
+ * Add commands to represent a full (device) halftone.
+ * (This routine should probably be in some other module.)
+ * Note: in the FUTURE, the type parameter is unnecessary, because device
+ * halftones record the type.
+ */
+/* NB does NO VM error recovery, and upgrade lo-mem warnings to errors */
+int cmd_put_halftone(P3(gx_device_clist_writer *cldev,
+ const gx_device_halftone *pdht, gs_halftone_type type));
diff --git a/gs/src/gxclfile.c b/gs/src/gxclfile.c
new file mode 100644
index 000000000..47ca91d87
--- /dev/null
+++ b/gs/src/gxclfile.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclfile.c */
+/* File-based command list implementation */
+#include "stdio_.h"
+#include "string_.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "gp.h"
+#include "gxclio.h"
+
+/* This is an implementation of the command list I/O interface */
+/* that uses the file system for storage. */
+
+/* ------ Open/close/unlink ------ */
+
+int
+clist_fopen(char *fname, const char *fmode, clist_file_ptr *pcf,
+ gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
+{ if ( *fname == 0 )
+ { if ( fmode[0] == 'r' )
+ return_error(gs_error_invalidfileaccess);
+ *pcf =
+ (clist_file_ptr)gp_open_scratch_file(gp_scratch_file_name_prefix,
+ fname, fmode);
+ }
+ else
+ *pcf = gp_fopen(fname, fmode);
+ if ( *pcf == NULL )
+ { eprintf1("Could not open the scratch file %s.\n", fname);
+ return_error(gs_error_invalidfileaccess);
+ }
+ return 0;
+}
+
+int
+clist_fclose(clist_file_ptr cf, const char *fname, bool delete)
+{ return (fclose((FILE *)cf) != 0 ? gs_note_error(gs_error_ioerror) :
+ delete ? clist_unlink(fname) :
+ 0);
+}
+
+int
+clist_unlink(const char *fname)
+{ return (unlink(fname) != 0 ? gs_note_error(gs_error_ioerror) : 0);
+}
+
+/* ------ Writing ------ */
+
+long
+clist_space_available(long requested)
+{ return requested;
+}
+
+int
+clist_fwrite_chars(const void *data, uint len, clist_file_ptr cf)
+{ return fwrite(data, 1, len, (FILE *)cf);
+}
+
+/* ------ Reading ------ */
+
+int
+clist_fread_chars(void *data, uint len, clist_file_ptr cf)
+{ FILE *f = (FILE *)cf;
+ byte *str = data;
+
+ /* The typical implementation of fread */
+ /* is extremely inefficient for small counts, */
+ /* so we just use straight-line code instead. */
+ switch ( len )
+ {
+ default: return fread(str, 1, len, f);
+ case 8: *str++ = (byte)getc(f);
+ case 7: *str++ = (byte)getc(f);
+ case 6: *str++ = (byte)getc(f);
+ case 5: *str++ = (byte)getc(f);
+ case 4: *str++ = (byte)getc(f);
+ case 3: *str++ = (byte)getc(f);
+ case 2: *str++ = (byte)getc(f);
+ case 1: *str = (byte)getc(f);
+ }
+ return len;
+}
+
+/* ------ Position/status ------ */
+
+int
+clist_set_block_size(clist_file_ptr cf, int sizeofBlock)
+{ return 0; /* always successful */
+}
+
+int
+clist_ferror_code(clist_file_ptr cf)
+{ return (ferror((FILE *)cf) ? gs_error_ioerror : 0);
+}
+
+long
+clist_ftell(clist_file_ptr cf)
+{ return ftell((FILE *)cf);
+}
+
+void
+clist_rewind(clist_file_ptr cf, bool discard_data, const char *fname)
+{ FILE *f = (FILE *)cf;
+
+ if ( discard_data ) {
+ /*
+ * The ANSI C stdio specification provides no operation for
+ * truncating a file at a given position, or even just for
+ * deleting its contents; we have to use a bizarre workaround to
+ * get the same effect.
+ */
+ char fmode[4];
+
+ /* Opening with "w" mode deletes the contents when closing. */
+ freopen(fname, gp_fmode_wb, f);
+ strcpy(fmode, "w+");
+ strcat(fmode, gp_fmode_binary_suffix);
+ freopen(fname, fmode, f);
+ } else {
+ rewind(f);
+ }
+}
+
+int
+clist_fseek(clist_file_ptr cf, long offset, int mode, const char *ignore_fname)
+{ return fseek((FILE *)cf, offset, mode);
+}
diff --git a/gs/src/gxclimag.c b/gs/src/gxclimag.c
new file mode 100644
index 000000000..21a17f4fc
--- /dev/null
+++ b/gs/src/gxclimag.c
@@ -0,0 +1,1234 @@
+/* Copyright (C) 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclimag.c */
+/* Higher-level image operations for band lists */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h"
+#include "gxarith.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxpath.h"
+#include "gxclpath.h"
+#include "gxfmap.h"
+#ifdef FUTURE
+#include "strimpl.h" /* for siscale.h */
+#include "siscale.h"
+#endif
+
+/* Define whether we should use high-level images. */
+/* (See below for additional restrictions.) */
+static bool USE_HL_IMAGES = true;
+
+#define cdev cwdev
+
+/* Forward references */
+private int cmd_put_color_mapping(P3(gx_device_clist_writer *cldev,
+ const gs_imager_state *pis,
+ bool write_rgb_to_cmyk));
+private bool
+check_rect_for_trivial_clip(P5(
+ const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
+ int px, int py, int qx, int qy /* corners of box to test */
+));
+
+/* Driver procedures */
+private dev_proc_fill_mask(clist_fill_mask);
+private dev_proc_begin_image(clist_begin_image);
+private dev_proc_image_data(clist_image_data);
+private dev_proc_end_image(clist_end_image);
+
+/* Initialize the extensions to the command set. */
+void
+gs_climag_init(gs_memory_t *mem)
+{
+ gs_clist_device_procs.fill_mask = clist_fill_mask;
+ gs_clist_device_procs.begin_image = clist_begin_image;
+ gs_clist_device_procs.image_data = clist_image_data;
+ gs_clist_device_procs.end_image = clist_end_image;
+}
+
+/* ------ Driver procedures ------ */
+
+private int
+clist_fill_mask(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ const byte *orig_data = data; /* for writing tile*/
+ int orig_data_x = data_x; /* ditto */
+ int orig_x = x; /* ditto */
+ int orig_width = width; /* ditto */
+ int orig_height = height; /* ditto */
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ int y0;
+ int data_x_bit;
+ byte copy_op =
+ (depth > 1 ? cmd_op_copy_color_alpha :
+ gx_dc_is_pure(pdcolor) ? cmd_op_copy_mono :
+ cmd_op_copy_mono + cmd_copy_ht_color);
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y; /* must do after fit_copy */
+
+ /* If non-trivial clipping & complex clipping disabled, default */
+ if ( (cdev->disable_mask & clist_disable_complex_clip)
+ && !check_rect_for_trivial_clip(pcpath, x, y, x + width, y + height) )
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, width, height, pdcolor, depth, lop, pcpath);
+
+ if ( cmd_check_clip_path(cdev, pcpath) )
+ cmd_clear_known(cdev, clip_path_known);
+ data_x_bit = data_x << log2_depth;
+ BEGIN_RECT
+ int dx = (data_x_bit & 7) >> log2_depth;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT
+ code = 0;
+ if ( lop == lop_default )
+ code = code < 0 ? code : cmd_disable_lop(cdev, pcls);
+ else
+ { if ( lop != pcls->lop )
+ code = code < 0 ? code : cmd_set_lop(cdev, pcls, lop);
+ code = code < 0 ? code : cmd_enable_lop(cdev, pcls);
+ }
+ HANDLE_RECT(code);
+ if ( depth > 1 && !pcls->color_is_alpha )
+ { byte *dp;
+ TRY_RECT
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
+ HANDLE_RECT(code);
+ pcls->color_is_alpha = 1;
+ }
+ TRY_RECT
+ code = cmd_do_write_unknown(cdev, pcls, clip_path_known);
+ code = code < 0 ? code : cmd_do_enable_clip(cdev, pcls, pcpath != NULL);
+ HANDLE_RECT(code);
+ TRY_RECT
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ HANDLE_RECT(code);
+ /*
+ * Unfortunately, painting a character with a halftone requires the
+ * use of two bitmaps, a situation that we can neither represent in
+ * the band list nor guarantee will both be present in the tile
+ * cache; in this case, we always write the bits of the character.
+ *
+ * We could handle more RasterOp cases here directly, but it
+ * doesn't seem worth the trouble right now.
+ */
+ if ( id != gx_no_bitmap_id && gx_dc_is_pure(pdcolor) &&
+ lop == lop_default
+ )
+ { /* This is a character. ****** WRONG IF HALFTONE CELL. ******/
+ /* Put it in the cache if possible. */
+ ulong offset_temp;
+ if ( !cls_has_tile_id(cdev, pcls, id, offset_temp) )
+ { gx_strip_bitmap tile;
+ tile.data = (byte *)orig_data; /* actually const */
+ tile.raster = raster;
+ tile.size.x = tile.rep_width = orig_width;
+ tile.size.y = tile.rep_height = orig_height;
+ tile.rep_shift = tile.shift = 0;
+ tile.id = id;
+ TRY_RECT
+ code = clist_change_bits(cdev, pcls, &tile, depth);
+ HANDLE_RECT_UNLESS(code,
+ (code != gs_error_VMerror || !cdev->error_is_retryable) );
+ if (code < 0)
+ { /* Something went wrong; just copy the bits. */
+ goto copy;
+ }
+ }
+ { gx_cmd_rect rect;
+ int rsize;
+ byte op = copy_op + cmd_copy_use_tile;
+ byte *dp;
+
+ /* Output a command to copy the entire character. */
+ /* It will be truncated properly per band. */
+ rect.x = orig_x, rect.y = y0;
+ rect.width = orig_width, rect.height = yend - y0;
+ rsize = 1 + cmd_sizexy(rect);
+ TRY_RECT
+ code = 0;
+ if ( orig_data_x )
+ { int dx_msb = orig_data_x >> 5;
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_misc,
+ 2 + cmd_size_w(dx_msb));
+ if ( code >= 0 && dx_msb )
+ { dp[1] = cmd_set_misc_data_x + 0x20 +
+ (orig_data_x & 0x1f);
+ cmd_put_w(dx_msb, dp + 2);
+ }
+ else
+ dp[1] = cmd_set_misc_data_x + orig_data_x;
+ }
+ code = code < 0 ? code :
+ set_cmd_put_op(dp, cdev, pcls, op, rsize);
+ HANDLE_RECT(code)
+ dp++;
+ cmd_putxy(rect, dp);
+ pcls->rect = rect;
+ goto end;
+ }
+ }
+copy: /*
+ * The default fill_mask implementation uses strip_copy_rop;
+ * this is exactly what we want.
+ */
+ TRY_RECT
+ NEST_RECT;
+ code = gx_default_fill_mask(dev, row, dx, raster,
+ (y == y0 && height == orig_height &&
+ dx == orig_data_x ? id :
+ gx_no_bitmap_id),
+ x, y, width, height, pdcolor, depth,
+ lop, pcpath);
+ UNNEST_RECT;
+ HANDLE_RECT(code);
+end: ;
+ END_RECT
+ return 0;
+}
+
+/* ------ Bitmap image driver procedures ------ */
+
+/* Define the structure for keeping track of progress through an image. */
+typedef struct clist_image_enum_s {
+ /* Arguments of begin_image */
+ gs_memory_t *memory;
+ gs_image_t image;
+ gx_drawing_color dcolor;
+ gs_int_rect rect;
+ const gs_imager_state *pis;
+ const gx_clip_path *pcpath;
+ /* begin_image command prepared & ready to output */
+ int begin_image_command_length;
+ byte begin_image_command[3 + 2 * cmd_sizew_max + 14 * sizeof(float)
+ + 4 * cmd_sizew_max];
+ byte begin_image_b;
+#ifdef FUTURE
+ byte begin_image_b2;
+#endif
+ /* Set at creation time */
+ int map_rgb_to_cmyk;
+ void *default_info;
+#ifndef FUTURE
+ /* NOTE: currently format is always gs_image_format_chunky. */
+#endif
+ gs_image_format_t format;
+#ifndef FUTURE
+ /* NOTE: currently support is always (0,0). */
+#endif
+ gs_int_point support; /* extra source pixels for interpolation */
+#ifndef FUTURE
+ /* NOTE: currently num_planes is always 1. */
+#endif
+ int num_planes;
+ int bits_per_plane; /* bits per pixel per plane */
+ gs_matrix matrix; /* image space -> device space */
+ bool uses_color;
+ byte color_space;
+ int ymin, ymax;
+ /* Updated dynamically */
+ int y;
+ bool color_map_is_known;
+} clist_image_enum;
+/* We can disregard the pointers in the writer by allocating */
+/* the image enumerator as immovable. This is a hack, of course. */
+gs_private_st_ptrs1(st_clist_image_enum, clist_image_enum, "clist_image_enum",
+ clist_image_enum_enum_ptrs, clist_image_enum_reloc_ptrs, default_info);
+
+/* Forward declarations */
+private bool image_band_box(P5(gx_device *dev, const clist_image_enum *pie,
+ int y, int h, gs_int_rect *pbox));
+private int cmd_image_data(P9(gx_device_clist_writer *cldev,
+ gx_clist_state *pcls,
+ const byte **planes, int num_planes,
+ uint offset, int data_x, uint raster,
+ uint bytes_per_plane, int h));
+private uint /* mask of unknown properties(see pcls->known) */
+clist_image_unknowns(P2(gx_device *dev, const clist_image_enum *pie));
+
+private int /* ret 0 ok, else -ve error status */
+write_image_end_all(P2(gx_device *dev, const clist_image_enum *pie));
+
+/*
+ * Since currently we are limited to writing a single subrectangle of the
+ * image for each band, images that are rotated by angles other than
+ * multiples of 90 degrees may wind up writing many copies of the data.
+ * Eventually we will fix this by breaking up the image into multiple
+ * subrectangles, but for now, don't use the high-level approach if it would
+ * cause the data to explode because of this.
+ */
+private bool
+image_matrix_ok_to_band(const gs_matrix *pmat)
+{ double t;
+
+ /* Don't band if the matrix is (nearly) singular. */
+ if ( fabs(pmat->xx * pmat->yy - pmat->xy * pmat->yx) < 1.0e-6 )
+ return false;
+ if ( is_xxyy(pmat) || is_xyyx(pmat) )
+ return true;
+ t = (fabs(pmat->xx) + fabs(pmat->yy)) /
+ (fabs(pmat->xy) + fabs(pmat->yx));
+ return (t < 0.2 || t > 5);
+}
+
+/* Start processing an image. */
+private int
+clist_begin_image(gx_device *dev,
+ const gs_imager_state *pis, const gs_image_t *pim,
+ gs_image_format_t format, const gs_int_rect *prect,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
+ gs_memory_t *mem, void **pinfo)
+{ clist_image_enum *pie;
+ int base_index;
+ bool indexed;
+ int num_components;
+ int bits_per_pixel;
+ bool uses_color;
+ gs_matrix mat;
+ int code;
+ gs_rect sbox, dbox;
+ int use_default_image;
+
+ /* See above for why we allocate the enumerator as immovable. */
+ pie = gs_alloc_struct_immovable(mem, clist_image_enum,
+ &st_clist_image_enum,
+ "clist_begin_image");
+ if ( pie == 0 )
+ return_error(gs_error_VMerror);
+ pie->memory = mem;
+ *pinfo = pie;
+ if ( pim->ImageMask )
+ { base_index = gs_color_space_index_DeviceGray; /* arbitrary */
+ indexed = false;
+ num_components = 1;
+ uses_color = true;
+ }
+ else
+ { const gs_color_space *pcs = pim->ColorSpace;
+ base_index = gs_color_space_get_index(pcs);
+ if ( base_index == gs_color_space_index_Indexed )
+ { const gs_color_space *pbcs =
+ gs_color_space_indexed_base_space(pcs);
+ indexed = true;
+ base_index = gs_color_space_get_index(pbcs);
+ num_components = 1;
+ }
+ else
+ { indexed = false;
+ num_components = gs_color_space_num_components(pcs);
+ }
+ uses_color = pim->CombineWithColor && rop3_uses_T(pis->log_op);
+ }
+
+ use_default_image =
+ (
+ !USE_HL_IMAGES || /* Always use the default. */
+ (cdev->disable_mask & clist_disable_hl_image) ||
+ cdev->in_image || /* Can't handle nested images */
+ /****** CAN'T HANDLE CIE COLOR YET ******/
+ base_index > gs_color_space_index_DeviceCMYK ||
+ /****** CAN'T HANDLE INDEXED COLOR (READING MAP) ******/
+ indexed ||
+ /****** CAN'T HANDLE NON-PURE COLORS YET ******/
+ ( uses_color && !gx_dc_is_pure(pdcolor) ) ||
+#ifdef DPNEXT
+ /****** CAN'T HANDLE IMAGES WITH ALPHA YET ******/
+ pim->HasAlpha ||
+#endif
+ ( code = gs_matrix_invert(&pim->ImageMatrix, &mat) ) < 0 ||
+ ( code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat) ) < 0 ||
+ !image_matrix_ok_to_band(&mat) ||
+#ifndef FUTURE
+ /****** CAN'T HANDLE MULTI-PLANE IMAGES YET ******/
+ /****** (requires flipping in cmd_image_data) ******/
+ ( format != gs_image_format_chunky &&
+ ( num_components > 1 ||
+ ( format == gs_image_format_bit_planar &&
+ pim->BitsPerComponent > 1) ) ) ||
+ /****** CAN'T HANDLE INTERPOLATION YET ******/
+ pim->Interpolate || /* NB: interpolate won't work w/async rendering */
+#endif
+ 0
+ );
+ if ( !use_default_image
+ && (cdev->disable_mask & clist_disable_nonrect_hl_image) )
+ use_default_image = !( is_xxyy(&mat) || is_xyyx(&mat) );
+ if (!use_default_image)
+ { int bytes_per_plane, bytes_per_row;
+ /* Do cheap enum init, since some of it's needed for the test */
+ if ( prect )
+ pie->rect = *prect;
+ else
+ { pie->rect.p.x = 0, pie->rect.p.y = 0;
+ pie->rect.q.x = pim->Width, pie->rect.q.y = pim->Height;
+ }
+ bits_per_pixel = pim->BitsPerComponent * num_components;
+ pie->default_info = 0;
+ pie->image = *pim;
+ pie->dcolor = *pdcolor;
+ pie->pis = pis;
+ pie->pcpath = pcpath;
+ pie->format = format;
+ switch ( format )
+ {
+ case gs_image_format_chunky:
+ pie->num_planes = 1; break;
+ case gs_image_format_component_planar:
+ pie->num_planes = num_components; break;
+ case gs_image_format_bit_planar:
+ pie->num_planes = bits_per_pixel; break;
+ }
+ pie->bits_per_plane = bits_per_pixel / pie->num_planes;
+ pie->matrix = mat;
+ pie->uses_color = uses_color;
+ pie->color_space = (base_index << 4) |
+ (indexed ? (pim->ColorSpace->params.indexed.use_proc ? 12 : 8) : 0);
+ pie->y = pie->rect.p.y;
+
+ /* Image row has to fit in cmd writer's buffer */
+ bytes_per_plane
+ = (pim->Width * pie->bits_per_plane + 7) >> 3;
+ bytes_per_row = bytes_per_plane * pie->num_planes;
+ bytes_per_row = max(bytes_per_row, 1);
+ use_default_image = cmd_largest_size + bytes_per_row
+ > cdev->cend - cdev->cbuf;
+ }
+ if (!use_default_image)
+ { sbox.p.x = pie->rect.p.x;
+ sbox.p.y = pie->rect.p.y;
+ sbox.q.x = pie->rect.q.x;
+ sbox.q.y = pie->rect.q.y;
+ gs_bbox_transform(&sbox, &mat, &dbox);
+
+ if (cdev->disable_mask & clist_disable_complex_clip)
+ use_default_image
+ = !check_rect_for_trivial_clip( pcpath,
+ (int)(dbox.p.x), (int)(dbox.p.y),
+ (int)ceil(dbox.q.x), (int)ceil(dbox.q.y) );
+ }
+ pie->map_rgb_to_cmyk = dev->color_info.num_components == 4 &&
+ base_index == gs_color_space_index_DeviceRGB;
+ pie->color_map_is_known = false;
+ if (use_default_image)
+ { int code = gx_default_begin_image(dev, pis, pim, format, prect,
+ pdcolor, pcpath, mem,
+ &pie->default_info);
+ if ( code < 0 )
+ gs_free_object(mem, pie, "clist_begin_image");
+ return code;
+ }
+
+ /* Create ready-4-use copy of the begin_image command(s) in enum */
+ {
+ byte *cp = pie->begin_image_command;
+ byte b;
+#ifdef FUTURE
+ b2 = 0;
+#endif
+
+ cmd_put2w(pim->Width, pim->Height, cp);
+ if ( pim->ImageMask )
+ b = 0;
+ else switch ( pim->BitsPerComponent )
+ {
+ case 1: b = 1 << 5; break;
+ case 2: b = 2 << 5; break;
+ case 4: b = 3 << 5; break;
+ case 8: b = 4 << 5; break;
+ case 12: b = 5 << 5; break;
+ default: return_error(gs_error_rangecheck);
+ }
+#ifdef FUTURE
+ if ( format != gs_image_format_chunky )
+ b |= 1 << 4,
+ b2 |= format << 6;
+ if ( pim->Interpolate )
+ { b |= 1 << 4;
+ b2 |= 1 << 5;
+ pie->support.x = pie->support.y = max_support + 1;
+ }
+ else
+ pie->support.x = pie->support.y = 0;
+#else
+ if ( pim->Interpolate )
+ b |= 1 << 4;
+ pie->support.x = pie->support.y = 0;
+#endif
+ if ( !(pim->ImageMatrix.xx == pim->Width &&
+ pim->ImageMatrix.xy == 0 &&
+ pim->ImageMatrix.yx == 0 &&
+ pim->ImageMatrix.yy == -pim->Height &&
+ pim->ImageMatrix.tx == 0 &&
+ pim->ImageMatrix.ty == pim->Height
+ )
+ )
+ { b |= 1 << 3;
+ cp = cmd_for_matrix(cp, &pim->ImageMatrix);
+ }
+ { static const float base_decode[8] = {0, 1, 0, 1, 0, 1, 0, 1};
+ float indexed_decode[2];
+ const float *default_decode = base_decode;
+ int num_decode = num_components * 2;
+ int i;
+
+ if ( indexed )
+ { indexed_decode[0] = 0;
+ indexed_decode[1] = (1 << pim->BitsPerComponent) - 1;
+ default_decode = indexed_decode;
+ }
+ for ( i = 0; i < num_decode; ++i )
+ if ( pim->Decode[i] != default_decode[i] )
+ break;
+ if ( i != num_decode )
+ { byte *pdb = cp++;
+ byte dflags = 0;
+
+ b |= 1 << 2;
+ for ( i = 0; i < num_decode; i += 2 )
+ { float u = pim->Decode[i], v = pim->Decode[i+1];
+ dflags <<= 2;
+ if ( u == 0 && v == default_decode[i+1] )
+ ;
+ else if ( u == default_decode[i+1] && v == 0 )
+ dflags += 1;
+ else
+ { if ( u != 0 )
+ { dflags++;
+ memcpy(cp, &u, sizeof(float));
+ cp += sizeof(float);
+ }
+ dflags += 2;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ *pdb = dflags << (8 - num_decode);
+ }
+ }
+ if ( (pim->ImageMask ? pim->adjust : pim->CombineWithColor) )
+ b |= 1 << 1;
+ { int y0 = (int)floor(dbox.p.y - 0.51); /* adjust + rounding slop */
+ int y1 = (int)ceil(dbox.q.y + 0.51); /* ditto */
+
+ pie->ymin = max(y0, 0);
+ pie->ymax = min(y1, dev->height);
+ }
+ pie->begin_image_b = b;
+#ifdef FUTURE
+ pie->begin_image_b2 = b2;
+#endif
+ pie->begin_image_command_length = cp - pie->begin_image_command;
+ }
+
+ /*
+ * Make sure the CTM, color space, and clipping region (and, for
+ * masked images or images with CombineWithColor, the current color)
+ * are known at the time of the begin_image command.
+ */
+ cmd_clear_known( cdev,
+ clist_image_unknowns(dev, pie) | begin_image_known );
+
+ cdev->in_image = true;
+ return 0;
+}
+
+/* Determine which image-related properties are unknown */
+private uint /* mask of unknown properties(see pcls->known) */
+clist_image_unknowns(gx_device *dev, const clist_image_enum *pie)
+{
+ uint unknown = 0;
+ /*
+ * Determine if the CTM, color space, and clipping region (and, for
+ * masked images or images with CombineWithColor, the current color)
+ * are unknown. Set the device state in anticipation of the values
+ * becoming known.
+ */
+ if (cdev->imager_state.ctm.xx != pie->pis->ctm.xx ||
+ cdev->imager_state.ctm.xy != pie->pis->ctm.xy ||
+ cdev->imager_state.ctm.yx != pie->pis->ctm.yx ||
+ cdev->imager_state.ctm.yy != pie->pis->ctm.yy ||
+ cdev->imager_state.ctm.tx != pie->pis->ctm.tx ||
+ cdev->imager_state.ctm.ty != pie->pis->ctm.ty
+ ) { unknown |= ctm_known;
+ cdev->imager_state.ctm = pie->pis->ctm;
+ }
+ /****** hival CHECK IS NOT SUFFICIENT ******/
+ if ( cdev->color_space != pie->color_space ||
+ ((cdev->color_space & 8) != 0 &&
+ cdev->indexed_params.hival !=
+ pie->image.ColorSpace->params.indexed.hival)
+ )
+ { unknown |= color_space_known;
+ cdev->color_space = pie->color_space;
+ if ( cdev->color_space & 8 )
+ cdev->indexed_params = pie->image.ColorSpace->params.indexed;
+ }
+ if ( cmd_check_clip_path(cdev, pie->pcpath) )
+ unknown |= clip_path_known;
+
+ return unknown;
+}
+
+/* Process the next piece of an image. */
+private int
+clist_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int yh)
+{ clist_image_enum *pie = info;
+ gs_rect sbox, dbox;
+ int code;
+ int y0, y1;
+ int y, height; /* for BEGIN/END_RECT */
+ int full_y, full_height;
+
+ if ( pie->default_info )
+ return gx_default_image_data(dev, pie->default_info, planes, data_x,
+ raster, yh);
+ sbox.p.x = pie->rect.p.x;
+ sbox.p.y = y0 = pie->y;
+ sbox.q.x = pie->rect.q.x;
+ sbox.q.y = y1 = pie->y += yh;
+ gs_bbox_transform(&sbox, &pie->matrix, &dbox);
+ /*
+ * In order to keep the band list consistent, we must write out
+ * the image data in precisely those bands whose begin_image
+ * Y range includes the respective image scan lines. Because of
+ * rounding, we must expand the dbox by a little extra, and then
+ * use image_band_box to calculate the precise range for each band.
+ * This is slow, but we don't see any faster way to do it in the
+ * general case.
+ */
+ { int ry0 = (int)floor(dbox.p.y) - 2;
+ int ry1 = (int)ceil(dbox.q.y) + 2;
+ int band_height = cdev->page_band_height;
+
+ y = max(ry0, 0) / band_height * band_height;
+ height = min(round_up(ry1, band_height), dev->height) - y;
+ }
+
+ BEGIN_RECT
+ gs_int_rect ibox;
+
+ /* If this band doesn't intersect data, skip it for now */
+ if ( !image_band_box(dev, pie, y, height, &ibox) )
+ continue;
+
+ /* Write out begin_image & its preamble for this band */
+ if ( !(pcls->known & begin_image_known) )
+ {
+ gs_logical_operation_t lop = pie->pis->log_op;
+ byte *dp;
+ gs_int_rect entirebox;
+ byte *bp = pie->begin_image_command + pie->begin_image_command_length;
+ byte cb = pie->begin_image_b;
+#ifdef FUTURE
+ uint clen = (pie->begin_image_b & (1 << 4) ? 3 : 2);
+#else
+ uint clen = 2;
+#endif
+ uint len, total_len;
+ uint band_ymax, band_ymin;
+
+ /* Compute intersection of entire band & entire image src rect */
+ band_ymax = min(band_end, pie->ymax);
+ band_ymin = max(band_end - band_height, pie->ymin);
+ image_band_box(dev, pie, band_ymin,
+ band_ymax - band_ymin, &entirebox);
+
+ /* Make sure the imager state is up to date. */
+ TRY_RECT
+ code = pie->color_map_is_known ? 0
+ : cmd_put_color_mapping(cdev, pie->pis, pie->map_rgb_to_cmyk);
+ pie->color_map_is_known = true;
+ code = code < 0 ? code : cmd_do_write_unknown(cdev, pcls,
+ ctm_known | clip_path_known | color_space_known);
+ code = code < 0 ? code :
+ cmd_do_enable_clip(cdev, pcls, pie->pcpath != NULL);
+ if ( lop == lop_default )
+ code = code < 0 ? code : cmd_disable_lop(cdev, pcls);
+ else
+ { if ( lop != pcls->lop )
+ {
+ code = code < 0 ? code : cmd_set_lop(cdev, pcls, lop);
+ code = code < 0 ? code : cmd_enable_lop(cdev, pcls);
+ }
+ }
+ HANDLE_RECT(code);
+ if ( pie->uses_color )
+ TRY_RECT
+ code = cmd_put_drawing_color(cdev, pcls, &pie->dcolor);
+ HANDLE_RECT(code);
+ if ( entirebox.p.x != 0 || entirebox.p.y != 0 ||
+ entirebox.q.x != pie->image.Width ||
+ entirebox.q.y != pie->image.Height
+ )
+ { cb |= 1 << 0;
+ cmd_put2w(entirebox.p.x, entirebox.p.y, bp);
+ cmd_put2w(pie->image.Width - entirebox.q.x,
+ pie->image.Height - entirebox.q.y, bp);
+ }
+ len = bp - pie->begin_image_command;
+ total_len = clen + len;
+ TRY_RECT
+ code
+ = set_cmd_put_op(dp, cdev, pcls, cmd_opv_begin_image, total_len);
+ HANDLE_RECT(code);
+ dp[1] = cb;
+#ifdef FUTURE
+ dp[2] = pie->begin_image_b2;
+#endif
+ dp += clen;
+ memcpy(dp, pie->begin_image_command, len);
+
+ /* Mark band's begin_image as known */
+ pcls->known |= begin_image_known;
+ }
+ { /*
+ * Just transmit the subset of the data that intersects this band.
+ * Note that y and height always define a complete band.
+ */
+ int bpp = pie->bits_per_plane;
+ uint offset;
+ int iy, ih, xskip, nrows;
+ uint bytes_per_plane, bytes_per_row, rows_per_cmd;
+#define bx0 ibox.p.x
+#define by0 ibox.p.y
+#define bx1 ibox.q.x
+#define by1 ibox.q.y
+
+ if ( by0 < y0 )
+ by0 = y0;
+ if ( by1 > y1 )
+ by1 = y1;
+ offset = (by0 - y0) * raster;
+ /*
+ * Make sure we're skipping an integral number of pixels, by
+ * truncating the initial X coordinate to the next lower
+ * value that is an exact multiple of a byte.
+ */
+ xskip = bx0 & -(int)"\001\010\004\010\002\010\004\010"[bpp & 7];
+ offset += (xskip * bpp) >> 3;
+ xskip = bx0 - xskip;
+ bytes_per_plane = ((xskip + bx1 - bx0) * bpp + 7) >> 3;
+ bytes_per_row = bytes_per_plane * pie->num_planes;
+ rows_per_cmd =
+ (cbuf_size - cmd_largest_size) / max(bytes_per_row, 1);
+ if ( rows_per_cmd == 0 )
+ { /* The reader will have to buffer a row separately. */
+ rows_per_cmd = 1;
+ }
+ for ( iy = by0, ih = by1 - by0; ih > 0;
+ iy += nrows, ih -= nrows, offset += raster * nrows
+ )
+ { nrows = min(ih, rows_per_cmd);
+ TRY_RECT
+ code = cmd_image_data(cdev, pcls, planes, pie->num_planes,
+ offset, data_x + xskip, raster,
+ bytes_per_plane, nrows);
+ HANDLE_RECT(code);
+ }
+#undef bx0
+#undef by0
+#undef bx1
+#undef by1
+ }
+ END_RECT_ON_ERROR(\
+ ( ++cdev->ignore_lo_mem_warnings,\
+ NEST_RECT,\
+ code = write_image_end_all(dev, pie),\
+ UNNEST_RECT,\
+ --cdev->ignore_lo_mem_warnings,\
+ ( code < 0 ? (band_code = code) : code ) >= 0 ),\
+ ( cmd_clear_known( cdev,\
+ clist_image_unknowns(dev, pie) | begin_image_known ),\
+ pie->color_map_is_known = false, true )\
+ )
+
+ /* Update sub-rect in case memory exhaustion forced end_image */
+ if (!pie->image.Interpolate)
+ pie->rect.p.y += yh; /* interpolate & mem recovery currently incompat */
+ return pie->y >= pie->rect.q.y;
+}
+
+/* Clean up by releasing the buffers. */
+private int
+clist_end_image(gx_device *dev, void *info, bool draw_last)
+{ clist_image_enum *pie = info;
+ int code;
+
+ if ( pie->default_info )
+ code = gx_default_end_image(dev, pie->default_info, draw_last);
+ else
+ {
+ NEST_RECT;
+ do
+ { code = write_image_end_all(dev, pie);
+ }
+ while ( code < 0 && cdev->error_is_retryable
+ && ( code = clist_try_recover_VMerror(cdev, code) ) >= 0 );
+
+ /* if couldn't write successsfully, do a hard flush */
+ if (code < 0 && cdev->error_is_retryable)
+ {
+ int retry_code;
+ ++cdev->ignore_lo_mem_warnings;
+ retry_code = write_image_end_all(dev, pie); /* force it out */
+ --cdev->ignore_lo_mem_warnings;
+ if (retry_code >= 0 && cdev->driver_call_nesting == 0)
+ code = clist_try_recover_VMerror_flush(cdev, code);
+ }
+ UNNEST_RECT;
+ cdev->in_image = false;
+ }
+ gs_free_object(pie->memory, pie, "clist_end_image");
+ return code;
+}
+
+/* ------ Utilities ------ */
+
+/* Add commands to represent a halftone order. */
+private int
+cmd_put_ht_order(gx_device_clist_writer *cldev, const gx_ht_order *porder,
+ gs_ht_separation_name cname,
+ int component /* -1 = default/gray/black screen */)
+{ byte command[cmd_max_intsize(sizeof(long)) * 8];
+ byte *cp;
+ uint len;
+ byte *dp;
+ uint i, n;
+ int code;
+
+ /* Put out the order parameters. */
+ cp = cmd_put_w(component + 1, command);
+ if ( component >= 0 )
+ cp = cmd_put_w(cname, cp);
+ cp = cmd_put_w(porder->width, cp);
+ cp = cmd_put_w(porder->height, cp);
+ cp = cmd_put_w(porder->raster, cp);
+ cp = cmd_put_w(porder->shift, cp);
+ cp = cmd_put_w(porder->num_levels, cp);
+ cp = cmd_put_w(porder->num_bits, cp);
+ len = cp - command;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_order, len + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, command, len);
+
+ /* Put out the transfer function, if any. */
+ cmd_put_color_map(cldev, cmd_map_ht_transfer, porder->transfer,
+ NULL);
+
+ /* Put out the levels array. */
+#define nlevels min((cbuf_size - 2) / sizeof(*porder->levels), 255)
+ for ( i = 0; i < porder->num_levels; i += n )
+ { n = porder->num_levels - i;
+ if ( n > nlevels )
+ n = nlevels;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_data,
+ 2 + n * sizeof(*porder->levels));
+ if (code < 0)
+ return code;
+ dp[1] = n;
+ memcpy(dp + 2, porder->levels + i, n * sizeof(*porder->levels));
+ }
+#undef nlevels
+
+ /* Put out the bits array. */
+#define nbits min((cbuf_size - 2) / sizeof(*porder->bits), 255)
+ for ( i = 0; i < porder->num_bits; i += n )
+ { n = porder->num_bits - i;
+ if ( n > nbits )
+ n = nbits;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_data,
+ 2 + n * sizeof(*porder->bits));
+ if (code < 0)
+ return code;
+ dp[1] = n;
+ memcpy(dp + 2, porder->bits + i, n * sizeof(*porder->bits));
+ }
+#undef nbits
+
+ return 0;
+}
+
+/* Add commands to represent a full (device) halftone. */
+/* We put out the default/gray/black screen last so that the reading */
+/* pass can recognize the end of the halftone. */
+int
+cmd_put_halftone(gx_device_clist_writer *cldev, const gx_device_halftone *pdht,
+ gs_halftone_type type)
+{ uint num_comp = (pdht->components == 0 ? 0 : pdht->num_comp);
+
+ { byte *dp;
+
+ int code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
+ 2 + cmd_size_w(num_comp));
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_halftone + type;
+ cmd_put_w(num_comp, dp + 2);
+ }
+ if ( num_comp == 0 )
+ return cmd_put_ht_order(cldev, &pdht->order,
+ gs_ht_separation_Default, -1);
+ { int i;
+
+ for ( i = num_comp; --i >= 0; )
+ { int code = cmd_put_ht_order(cldev, &pdht->components[i].corder,
+ pdht->components[i].cname, i);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Write out any necessary color mapping data. */
+private int
+cmd_put_color_mapping(gx_device_clist_writer *cldev,
+ const gs_imager_state *pis, bool write_rgb_to_cmyk)
+{ int code;
+ const gx_device_halftone *pdht = pis->dev_ht;
+
+ /* Put out the halftone. */
+ if ( pdht->id != cldev->device_halftone_id )
+ { code = cmd_put_halftone(cldev, pdht, pis->halftone->type);
+ if ( code < 0 )
+ return code;
+ cldev->device_halftone_id = pdht->id;
+ }
+
+ /* If we need to map RGB to CMYK, put out b.g. and u.c.r. */
+ if ( write_rgb_to_cmyk )
+ { code = cmd_put_color_map(cldev, cmd_map_black_generation,
+ pis->black_generation,
+ &cldev->black_generation_id);
+ if ( code < 0 )
+ return code;
+ code = cmd_put_color_map(cldev, cmd_map_undercolor_removal,
+ pis->undercolor_removal,
+ &cldev->undercolor_removal_id);
+ if ( code < 0 )
+ return code;
+ }
+
+ /* Now put out the transfer functions. */
+ { uint which = 0;
+ bool all_same = true;
+ int i;
+
+ for ( i = 0; i < countof(cldev->transfer_ids); ++i )
+ { if ( pis->effective_transfer.indexed[i]->id !=
+ cldev->transfer_ids[i]
+ )
+ which |= 1 << i;
+ if ( pis->effective_transfer.indexed[i]->id !=
+ pis->effective_transfer.indexed[0]->id
+ )
+ all_same = false;
+ }
+ /* There are 3 cases for transfer functions: nothing to write, */
+ /* a single function, and multiple functions. */
+ if ( which == 0 )
+ return 0;
+ if ( which == (1 << countof(cldev->transfer_ids)) - 1 && all_same )
+ { code = cmd_put_color_map(cldev, cmd_map_transfer,
+ pis->effective_transfer.indexed[0],
+ &cldev->transfer_ids[0]);
+ if ( code < 0 )
+ return code;
+ for ( i = 1; i < countof(cldev->transfer_ids); ++i )
+ cldev->transfer_ids[i] = cldev->transfer_ids[0];
+ }
+ else
+ for ( i = 0; i < countof(cldev->transfer_ids); ++i )
+ { code = cmd_put_color_map(cldev,
+ (cmd_map_index)(cmd_map_transfer_0 + i),
+ pis->effective_transfer.indexed[i],
+ &cldev->transfer_ids[i]);
+ if ( code < 0 )
+ return code;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Compute the subrectangle of an image that intersects a band;
+ * return false if it is empty.
+ * It is OK for this to be too large; in fact, with the present
+ * algorithm, it will be quite a bit too large if the transformation isn't
+ * well-behaved ("well-behaved" meaning either xy = yx = 0 or xx = yy = 0).
+ */
+private void
+box_merge_point(gs_int_rect *pbox, floatp x, floatp y)
+{ int t;
+
+ if ( (t = (int)floor(x)) < pbox->p.x )
+ pbox->p.x = t;
+ if ( (t = (int)ceil(x)) > pbox->q.x )
+ pbox->q.x = t;
+ if ( (t = (int)floor(y)) < pbox->p.y )
+ pbox->p.y = t;
+ if ( (t = (int)ceil(y)) > pbox->q.y )
+ pbox->q.y = t;
+}
+private bool
+image_band_box(gx_device *dev, const clist_image_enum *pie, int y, int h,
+ gs_int_rect *pbox)
+{ fixed by0 = int2fixed(y);
+ fixed by1 = int2fixed(y + h);
+ int px = pie->rect.p.x, py = pie->rect.p.y,
+ qx = pie->rect.q.x, qy = pie->rect.q.y;
+ gs_fixed_rect cbox; /* device clipping box */
+ gs_rect bbox; /* cbox intersected with band */
+
+ /* Intersect the device clipping box and the band. */
+ (*dev_proc(dev, get_clipping_box))(dev, &cbox);
+ /* The fixed_half here is to allow for adjustment. */
+ bbox.p.x = fixed2float(cbox.p.x - fixed_half);
+ bbox.q.x = fixed2float(cbox.q.x + fixed_half);
+ bbox.p.y = fixed2float(max(cbox.p.y, by0) - fixed_half);
+ bbox.q.y = fixed2float(min(cbox.q.y, by1) + fixed_half);
+#ifdef DEBUG
+ if ( gs_debug_c('b') )
+ { dprintf6("[b]band box for (%d,%d),(%d,%d), band (%d,%d) =>\n",
+ px, py, qx, qy, y, y + h);
+ dprintf10(" (%g,%g),(%g,%g), matrix=[%g %g %g %g %g %g]\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y,
+ pie->matrix.xx, pie->matrix.xy, pie->matrix.yx,
+ pie->matrix.yy, pie->matrix.tx, pie->matrix.ty);
+ }
+#endif
+ if ( is_xxyy(&pie->matrix) || is_xyyx(&pie->matrix) )
+ { /*
+ * The inverse transform of the band is a rectangle aligned with
+ * the coordinate axes, so we can just intersect it with the
+ * image subrectangle.
+ */
+ gs_rect ibox; /* bbox transformed back to image space */
+
+ if ( gs_bbox_transform_inverse(&bbox, &pie->matrix, &ibox) < 0 )
+ return false;
+ pbox->p.x = max(px, (int)floor(ibox.p.x));
+ pbox->q.x = min(qx, (int)ceil(ibox.q.x));
+ pbox->p.y = max(py, (int)floor(ibox.p.y));
+ pbox->q.y = min(qy, (int)ceil(ibox.q.y));
+ }
+ else
+ { /*
+ * The inverse transform of the band is not aligned with the
+ * axes, i.e., is a general parallelogram. To compute an exact
+ * bounding box, we need to find the intersections of this
+ * parallelogram with the image subrectangle.
+ *
+ * There is probably a much more efficient way to do this
+ * computation, but we don't know what it is.
+ */
+ gs_point rect[4];
+ gs_point corners[5];
+ int i;
+
+ /* Store the corners of the image rectangle. */
+ rect[0].x = rect[3].x = px;
+ rect[1].x = rect[2].x = qx;
+ rect[0].y = rect[1].y = py;
+ rect[2].y = rect[3].y = qy;
+ /*
+ * Compute the corners of the clipped band in image space. If
+ * the matrix is singular or an overflow occurs, the result will
+ * be nonsense: in this case, there isn't anything useful we
+ * can do, so return an empty intersection.
+ */
+ if ( gs_point_transform_inverse(bbox.p.x, bbox.p.y, &pie->matrix,
+ &corners[0]) < 0 ||
+ gs_point_transform_inverse(bbox.q.x, bbox.p.y, &pie->matrix,
+ &corners[1]) < 0 ||
+ gs_point_transform_inverse(bbox.q.x, bbox.q.y, &pie->matrix,
+ &corners[2]) < 0 ||
+ gs_point_transform_inverse(bbox.p.x, bbox.q.y, &pie->matrix,
+ &corners[3]) < 0
+ ) {
+ if_debug0('b', "[b]can't inverse-transform a band corner!\n");
+ return false;
+ }
+ corners[4] = corners[0];
+ pbox->p.x = qx, pbox->p.y = qy;
+ pbox->q.x = px, pbox->q.y = py;
+ /*
+ * We iterate over both the image rectangle and the band
+ * parallelogram in a single loop for convenience, even though
+ * there is no coupling between the two.
+ */
+ for ( i = 0; i < 4; ++i )
+ { gs_point pa, pt;
+ double dx, dy;
+
+ /* Check the image corner for being inside the band. */
+ pa = rect[i];
+ gs_point_transform(pa.x, pa.y, &pie->matrix, &pt);
+ if ( pt.x >= bbox.p.x && pt.x <= bbox.q.x &&
+ pt.y >= bbox.p.y && pt.y <= bbox.q.y
+ )
+ box_merge_point(pbox, pa.x, pa.y);
+ /* Check the band corner for being inside the image. */
+ pa = corners[i];
+ if ( pa.x >= px && pa.x <= qx && pa.y >= py && pa.y <= qy )
+ box_merge_point(pbox, pa.x, pa.y);
+ /* Check for intersections of band edges with image edges. */
+ dx = corners[i+1].x - pa.x;
+ dy = corners[i+1].y - pa.y;
+#define in_range(t, tc, p, q)\
+ (0 <= t && t <= 1 && (t = tc) >= p && t <= q)
+ if ( dx != 0 )
+ { double t = (px - pa.x) / dx;
+
+ if_debug3('b', " (px) t=%g => (%d,%g)\n",
+ t, px, pa.y + t * dy);
+ if ( in_range(t, pa.y + t * dy, py, qy) )
+ box_merge_point(pbox, (floatp)px, t);
+ t = (qx - pa.x) / dx;
+ if_debug3('b', " (qx) t=%g => (%d,%g)\n",
+ t, qx, pa.y + t * dy);
+ if ( in_range(t, pa.y + t * dy, py, qy) )
+ box_merge_point(pbox, (floatp)qx, t);
+ }
+ if ( dy != 0 )
+ { double t = (py - pa.y) / dy;
+
+ if_debug3('b', " (py) t=%g => (%g,%d)\n",
+ t, pa.x + t * dx, py);
+ if ( in_range(t, pa.x + t * dx, px, qx) )
+ box_merge_point(pbox, t, (floatp)py);
+ t = (qy - pa.y) / dy;
+ if_debug3('b', " (qy) t=%g => (%g,%d)\n",
+ t, pa.x + t * dx, qy);
+ if ( in_range(t, pa.x + t * dx, px, qx) )
+ box_merge_point(pbox, t, (floatp)qy);
+ }
+#undef in_range
+ }
+ }
+ if_debug4('b', " => (%d,%d),(%d,%d)\n", pbox->p.x, pbox->p.y,
+ pbox->q.x, pbox->q.y);
+#ifdef FUTURE
+ /*
+ * If necessary, add pixels around the edges so we will have
+ * enough information to do interpolation.
+ */
+ if ( (pbox->p.x -= pie->support.x) < pie->rect.p.x )
+ pbox->p.x = pie->rect.p.x;
+ if ( (pbox->p.y -= pie->support.y) < pie->rect.p.y )
+ pbox->p.y = pie->rect.p.y;
+ if ( (pbox->q.x += pie->support.x) > pie->rect.q.x )
+ pbox->q.x = pie->rect.q.x;
+ if ( (pbox->q.y += pie->support.y) > pie->rect.q.y )
+ pbox->q.y = pie->rect.q.y;
+#endif
+ return (pbox->p.x < pbox->q.x && pbox->p.y < pbox->q.y);
+}
+
+/* Write data for a partial image. */
+private int
+cmd_image_data(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const byte **planes, int num_planes, uint offset, int data_x, uint raster,
+ uint bytes_per_plane, int h)
+{ uint nbytes = bytes_per_plane * num_planes * h;
+ uint len = 1 + cmd_size2w(h, bytes_per_plane) + nbytes;
+ byte *dp;
+ int plane, i;
+ int code;
+
+ if ( data_x )
+ { code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_data_x + (data_x & 7);
+ offset += ((data_x & ~7) * cldev->color_info.depth) >> 3;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_image_data, len);
+ if (code < 0)
+ return code;
+ dp++;
+ cmd_put2w(h, bytes_per_plane, dp);
+ for ( plane = 0; plane < num_planes; ++plane )
+ for ( i = 0; i < h; ++i )
+ { memcpy(dp, planes[plane] + i * raster + offset, bytes_per_plane);
+ dp += bytes_per_plane;
+ }
+ return 0;
+}
+
+/* Write image_end commands into all bands */
+private int /* ret 0 ok, else -ve error status */
+write_image_end_all(gx_device *dev, const clist_image_enum *pie)
+{ int code;
+ int y = pie->ymin;
+ int height = pie->ymax - y;
+ BEGIN_RECT
+ byte *dp;
+
+ if ( !(pcls->known & begin_image_known) )
+ continue;
+ TRY_RECT
+ if_debug1('L', "[L]image_end for band %d\n", band);
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_image_data, 2);
+ HANDLE_RECT(code);
+ dp[1] = 0; /* EOD */
+ pcls->known ^= begin_image_known;
+ END_RECT
+ return 0;
+}
+
+/* Compare a rectangle vs. clip path. See if rect is trivially accepted, */
+/* or is only clipped by a single rectangle. */
+private bool /* ret true if no clip, rect trivially accepted, or only clipped *
+ /* by one rectangle. */
+check_rect_for_trivial_clip(
+ const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
+ int px, int py, int qx, int qy /* corners of box to test */
+)
+{ gs_fixed_rect obox;
+ gs_fixed_rect imgbox;
+
+ if (!pcpath)
+ return true;
+
+ imgbox.p.x = int2fixed(px);
+ imgbox.p.y = int2fixed(py);
+ imgbox.q.x = int2fixed(qx);
+ imgbox.q.y = int2fixed(qy);
+ if ( gx_cpath_includes_rectangle(pcpath,
+ imgbox.p.x, imgbox.p.y, imgbox.q.x, imgbox.q.y) );
+ return true;
+
+ return ( gx_cpath_outer_box(pcpath, &obox) &&
+ obox.p.x <= imgbox.q.x && obox.q.x >= imgbox.p.x &&
+ obox.p.y <= imgbox.q.y && obox.q.y >= imgbox.p.y );
+}
diff --git a/gs/src/gxclio.h b/gs/src/gxclio.h
new file mode 100644
index 000000000..e5216df43
--- /dev/null
+++ b/gs/src/gxclio.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclio.h */
+/* I/O interface for command lists */
+
+#ifndef gxclio_INCLUDED
+# define gxclio_INCLUDED
+
+/*
+ * There are two implementations of the I/O interface for command lists --
+ * one suitable for embedded systems, which stores the "files" in RAM, and
+ * one suitable for other systems, which uses an external file system --
+ * with the choice made at compile/link time. This header file defines the
+ * API between the command list code proper and its I/O interface.
+ */
+
+typedef void *clist_file_ptr; /* We can't do any better than this. */
+
+/* ---------------- Open/close/unlink ---------------- */
+
+/*
+ * If *fname = 0, generate and store a new scratch file name; otherwise,
+ * open an existing file. Only modes "r" and "w+" are supported,
+ * and only binary data (but the caller must append the "b" if needed).
+ * Mode "r" with *fname = 0 is an error.
+ */
+int clist_fopen(P6(char *fname, const char *fmode, clist_file_ptr *pcf,
+ gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress));
+
+/*
+ * Close a file, optionally deleting it.
+ */
+int clist_fclose(P3(clist_file_ptr cf, const char *fname, bool delete));
+
+/*
+ * Delete a file.
+ */
+int clist_unlink(P1(const char *fname));
+
+/* ---------------- Writing ---------------- */
+
+/* clist_space_available returns min(requested, available). */
+long clist_space_available(P1(long requested));
+
+int clist_fwrite_chars(P3(const void *data, uint len, clist_file_ptr cf));
+
+/* ---------------- Reading ---------------- */
+
+int clist_fread_chars(P3(void *data, uint len, clist_file_ptr cf));
+
+/* ---------------- Position/status ---------------- */
+
+/* clist_set_block_size guarantees that writing a file will generate a */
+/* warning N bytes before actually running out of memory to write into. */
+int clist_set_block_size(P2(clist_file_ptr cf, int sizeofBlock));
+
+/* clist_ferror_code rets -ve err code per gserrors.h, 0 ok, or +1 lo-mem warning */
+int clist_ferror_code(P1(clist_file_ptr cf));
+
+long clist_ftell(P1(clist_file_ptr cf));
+
+/*
+ * We pass the file name to clist_rewind and clist_fseek in case the
+ * implementation has to close and reopen the file. (clist_fseek with
+ * offset = 0 and mode = SEEK_END indicates we are about to append.)
+ */
+void clist_rewind(P3(clist_file_ptr cf, bool discard_data,
+ const char *fname));
+
+int clist_fseek(P4(clist_file_ptr cf, long offset, int mode,
+ const char *fname));
+
+#endif /* gxclio_INCLUDED */
diff --git a/gs/src/gxclip2.c b/gs/src/gxclip2.c
new file mode 100644
index 000000000..03ab09601
--- /dev/null
+++ b/gs/src/gxclip2.c
@@ -0,0 +1,375 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclip2.c */
+/* Mask clipping for patterns */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclip2.h"
+
+private_st_device_tile_clip();
+
+/* Device procedures */
+private dev_proc_fill_rectangle(tile_clip_fill_rectangle);
+private dev_proc_copy_mono(tile_clip_copy_mono);
+private dev_proc_copy_color(tile_clip_copy_color);
+private dev_proc_copy_alpha(tile_clip_copy_alpha);
+private dev_proc_strip_copy_rop(tile_clip_strip_copy_rop);
+
+/* The device descriptor. */
+private const gx_device_tile_clip gs_tile_clip_device =
+{ std_device_std_body_open(gx_device_tile_clip, 0, "tile clipper",
+ 0, 0, 1, 1),
+ { gx_default_open_device,
+ gx_forward_get_initial_matrix,
+ gx_default_sync_output,
+ gx_default_output_page,
+ gx_default_close_device,
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ tile_clip_fill_rectangle,
+ gx_default_tile_rectangle,
+ tile_clip_copy_mono,
+ tile_clip_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ tile_clip_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ gx_default_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ gx_default_strip_tile_rectangle,
+ tile_clip_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_forward_get_hardware_params
+ }
+};
+
+/* Initialize a tile clipping device from a mask. */
+int
+tile_clip_initialize(gx_device_tile_clip *cdev, const gx_strip_bitmap *tiles,
+ gx_device *idev, int px, int py)
+{ int buffer_width = tiles->size.x;
+ int buffer_height =
+ tile_clip_buffer_size / (tiles->raster + sizeof(byte *));
+
+ *cdev = gs_tile_clip_device;
+ cdev->width = idev->width;
+ cdev->height = idev->height;
+ cdev->color_info = idev->color_info;
+ cdev->target = idev;
+ cdev->tiles = *tiles;
+ tile_clip_set_phase(cdev, px, py);
+ if ( buffer_height > tiles->size.y )
+ buffer_height = tiles->size.y;
+ gs_make_mem_mono_device(&cdev->mdev, 0, 0);
+ for ( ; ; )
+ { if ( buffer_height <= 0 )
+ { /*
+ * The tile is too wide to buffer even one scan line.
+ * We could do copy_mono in chunks, but for now, we punt.
+ */
+ cdev->mdev.base = 0;
+ return 0;
+ }
+ cdev->mdev.width = buffer_width;
+ cdev->mdev.height = buffer_height;
+ if ( gdev_mem_bitmap_size(&cdev->mdev) <= tile_clip_buffer_size )
+ break;
+ buffer_height--;
+ }
+ cdev->mdev.base = cdev->buffer.bytes;
+ return (*dev_proc(&cdev->mdev, open_device))((gx_device *)&cdev->mdev);
+}
+
+/* Set the phase of the tile. */
+void
+tile_clip_set_phase(gx_device_tile_clip *cdev, int px, int py)
+{ cdev->phase.x = px;
+ cdev->phase.y = py;
+}
+
+#define cdev ((gx_device_tile_clip *)dev)
+
+/* Fill a rectangle by tiling with the mask. */
+private int
+tile_clip_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ gx_device *tdev = cdev->target;
+ return (*dev_proc(tdev, strip_tile_rectangle))(tdev, &cdev->tiles,
+ x, y, w, h,
+ gx_no_color_index, color, cdev->phase.x, cdev->phase.y);
+}
+
+/* Calculate the X offset corresponding to a given Y, taking the phase */
+/* and shift into account. */
+#define x_offset(ty, cdev)\
+ ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\
+ (cdev)->tiles.rep_shift)
+
+/* Copy a monochrome bitmap. We divide it up into maximal chunks */
+/* that line up with a single tile, and then do the obvious Boolean */
+/* combination of the tile mask and the source. */
+private int
+tile_clip_copy_mono(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{ gx_color_index color, mcolor0, mcolor1;
+ int ty, ny;
+ int code;
+
+ if ( cdev->mdev.base == 0 )
+ { /*
+ * The tile was too large for us to buffer even one scan line.
+ * Punt to the very, very slow default implementation of
+ * copy_mono.
+ */
+ return gx_default_copy_mono(dev, data, sourcex, raster, id,
+ x, y, w, h, color0, color1);
+ }
+ if ( color1 != gx_no_color_index )
+ { if ( color0 != gx_no_color_index )
+ { /* Pre-fill with color0. */
+ code = tile_clip_fill_rectangle(dev, x, y, w, h, color0);
+ if ( code < 0 )
+ return code;
+ }
+ color = color1;
+ mcolor0 = 0, mcolor1 = gx_no_color_index;
+ }
+ else if ( color0 != gx_no_color_index )
+ { color = color0;
+ mcolor0 = gx_no_color_index, mcolor1 = 0;
+ }
+ else
+ return 0;
+ for ( ty = y; ty < y + h; ty += ny )
+ { int tx, nx;
+ int cy = (ty + cdev->phase.y) % cdev->tiles.rep_height;
+ int xoff = x_offset(ty, cdev);
+
+ ny = min(y + h - ty, cdev->tiles.size.y - cy);
+ if ( ny > cdev->mdev.height )
+ ny = cdev->mdev.height;
+ for ( tx = x; tx < x + w; tx += nx )
+ { int cx = (tx + xoff) % cdev->tiles.rep_width;
+ nx = min(x + w - tx, cdev->tiles.size.x - cx);
+ /* Copy a tile slice to the memory device buffer. */
+ memcpy(cdev->buffer.bytes,
+ cdev->tiles.data + cy * cdev->tiles.raster,
+ cdev->tiles.raster * ny);
+ /* Intersect the tile with the source data. */
+ /* mcolor0 and mcolor1 invert the data if needed. */
+ /* This call can't fail. */
+ (*dev_proc(&cdev->mdev, copy_mono))((gx_device *)&cdev->mdev,
+ data + (ty - y) * raster, sourcex + tx - x,
+ raster, gx_no_bitmap_id,
+ cx, 0, nx, ny, mcolor0, mcolor1);
+ /* Now copy the color through the double mask. */
+ code = (*dev_proc(cdev->target, copy_mono))(cdev->target,
+ cdev->buffer.bytes, cx, cdev->tiles.raster,
+ gx_no_bitmap_id,
+ tx, ty, nx, ny, gx_no_color_index, color);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Copy a color rectangle. We can't use the BitBlt tricks; we have to */
+/* scan for runs of 1s. There are many obvious ways to speed this up; */
+/* we'll implement some if we need to. */
+private int
+tile_clip_copy_color(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ const byte *data_row = data;
+ int cy = (y + cdev->phase.y) % cdev->tiles.rep_height;
+ const byte *tile_row = cdev->tiles.data + cy * cdev->tiles.raster;
+ int ty;
+
+ for ( ty = y; ty < y + h; ty++, data_row += raster )
+ { int cx = (x + x_offset(ty, cdev)) % cdev->tiles.rep_width;
+ const byte *tp = tile_row + (cx >> 3);
+ byte tbit = 0x80 >> (cx & 7);
+ int tx;
+ int code;
+
+ for ( tx = x; tx < x + w; )
+ { int tx1;
+#define t_next()\
+ if ( ++cx == cdev->tiles.size.x )\
+ cx = 0, tp = tile_row, tbit = 0x80;\
+ else if ( (tbit >>= 1) == 0 )\
+ tp++, tbit = 0x80;\
+ tx++
+ /* Skip a run of 0s. */
+ while ( tx < x + w && (*tp & tbit) == 0 )
+ { t_next();
+ }
+ if ( tx == x + w )
+ break;
+ /* Scan a run of 1s. */
+ tx1 = tx;
+ do
+ { t_next();
+ }
+ while ( tx < x + w && (*tp & tbit) != 0 );
+ /* Copy the run. */
+ code = (*dev_proc(cdev->target, copy_color))(cdev->target,
+ data_row, sourcex + tx1 - x, raster,
+ gx_no_bitmap_id, tx1, ty, tx - tx1, 1);
+ if ( code < 0 )
+ return code;
+ }
+ if ( ++cy == cdev->tiles.size.y )
+ cy = 0, tile_row = cdev->tiles.data;
+ else
+ tile_row += cdev->tiles.raster;
+ }
+
+ return 0;
+}
+
+/* Copy an alpha rectangle similarly. */
+private int
+tile_clip_copy_alpha(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index color, int depth)
+{ const byte *data_row = data;
+ int ty;
+
+ for ( ty = y; ty < y + h; ty++, data_row += raster )
+ { const byte *tile_row = cdev->tiles.data +
+ ((ty + cdev->phase.y) % cdev->tiles.rep_height) *
+ cdev->tiles.raster;
+ int cx = (x + x_offset(ty, cdev)) % cdev->tiles.rep_width;
+ const byte *tp = tile_row + (cx >> 3);
+ byte tbit = 0x80 >> (cx & 7);
+ int tx;
+ int code;
+
+ for ( tx = x; tx < x + w; )
+ { int tx1;
+#define t_next()\
+ if ( ++cx == cdev->tiles.size.x )\
+ cx = 0, tp = tile_row, tbit = 0x80;\
+ else if ( (tbit >>= 1) == 0 )\
+ tp++, tbit = 0x80;\
+ tx++
+ /* Skip a run of 0s. */
+ while ( tx < x + w && (*tp & tbit) == 0 )
+ { t_next();
+ }
+ if ( tx == x + w )
+ break;
+ /* Scan a run of 1s. */
+ tx1 = tx;
+ do
+ { t_next();
+ }
+ while ( tx < x + w && (*tp & tbit) != 0 );
+ /* Copy the run. */
+ code = (*dev_proc(cdev->target, copy_alpha))(cdev->target,
+ data_row, sourcex + tx1 - x, raster,
+ gx_no_bitmap_id, tx1, ty, tx - tx1, 1,
+ color, depth);
+ if ( code < 0 )
+ return code;
+ }
+ }
+
+ return 0;
+}
+
+/* Copy a RasterOp rectangle similarly. */
+private int
+tile_clip_strip_copy_rop(gx_device *dev,
+ const byte *data, int sourcex, uint raster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int w, int h,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ const byte *data_row = data;
+ int ty;
+
+ for ( ty = y; ty < y + h; ty++, data_row += raster )
+ { const byte *tile_row = cdev->tiles.data +
+ ((ty + cdev->phase.y) % cdev->tiles.rep_height) *
+ cdev->tiles.raster;
+ int cx = (x + x_offset(ty, cdev)) % cdev->tiles.rep_width;
+ const byte *tp = tile_row + (cx >> 3);
+ byte tbit = 0x80 >> (cx & 7);
+ int tx;
+ int code;
+
+ for ( tx = x; tx < x + w; )
+ { int tx1;
+#define t_next()\
+ if ( ++cx == cdev->tiles.size.x )\
+ cx = 0, tp = tile_row, tbit = 0x80;\
+ else if ( (tbit >>= 1) == 0 )\
+ tp++, tbit = 0x80;\
+ tx++
+ /* Skip a run of 0s. */
+ while ( tx < x + w && (*tp & tbit) == 0 )
+ { t_next();
+ }
+ if ( tx == x + w )
+ break;
+ /* Scan a run of 1s. */
+ tx1 = tx;
+ do
+ { t_next();
+ }
+ while ( tx < x + w && (*tp & tbit) != 0 );
+ /* Copy the run. */
+ code = (*dev_proc(cdev->target, strip_copy_rop))
+ (cdev->target,
+ data_row, sourcex + tx1 - x, raster,
+ gx_no_bitmap_id, scolors, textures, tcolors,
+ tx1, ty, tx - tx1, 1, phase_x, phase_y, lop);
+ if ( code < 0 )
+ return code;
+ }
+ }
+
+ return 0;
+}
diff --git a/gs/src/gxclip2.h b/gs/src/gxclip2.h
new file mode 100644
index 000000000..69f346014
--- /dev/null
+++ b/gs/src/gxclip2.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclip2.h */
+/* Mask clipping device and interface */
+/* Requires gxdevice.h, gxdevmem.h */
+
+/*
+ * Patterns that don't completely fill their bounding boxes require
+ * the ability to clip against a tiled mask. For now, we only support
+ * tiling parallel to the axes.
+ */
+
+#define tile_clip_buffer_request 300
+#define tile_clip_buffer_size\
+ ((tile_clip_buffer_request / arch_sizeof_long) * arch_sizeof_long)
+typedef struct gx_device_tile_clip_s {
+ gx_device_forward_common; /* target is set by client */
+ gx_strip_bitmap tiles;
+ gx_device_memory mdev; /* for tile buffer for copy_mono */
+ gs_int_point phase; /* device space origin relative */
+ /* to tile (backwards from gstate phase) */
+ /* Ensure that the buffer is long-aligned. */
+ union _b {
+ byte bytes[tile_clip_buffer_size];
+ ulong longs[tile_clip_buffer_size / arch_sizeof_long];
+ } buffer;
+} gx_device_tile_clip;
+#define private_st_device_tile_clip() /* in gxclip2.c */\
+ gs_private_st_simple(st_device_tile_clip, gx_device_tile_clip,\
+ "gx_device_tile_clip")
+
+/* Initialize a tile clipping device from a mask. */
+/* We supply an explicit phase. */
+int tile_clip_initialize(P5(gx_device_tile_clip *, const gx_strip_bitmap *,
+ gx_device *, int, int));
+
+/* Set the phase of the tile -- used in the tiling loop when */
+/* the tile doesn't simply fill the plane. */
+void tile_clip_set_phase(P3(gx_device_tile_clip *, int, int));
+
diff --git a/gs/src/gxclist.c b/gs/src/gxclist.c
new file mode 100644
index 000000000..1d7baa2ce
--- /dev/null
+++ b/gs/src/gxclist.c
@@ -0,0 +1,1187 @@
+/* Copyright (C) 1991, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclist.c */
+/* Command list writing for Ghostscript. */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gsparams.h"
+
+#define cdev cwdev
+
+/* Forward declarations of procedures */
+private dev_proc_open_device(clist_open);
+private dev_proc_output_page(clist_output_page);
+private dev_proc_close_device(clist_close);
+private dev_proc_get_band(clist_get_band);
+private int clist_put_current_params(gx_device_clist_writer *cldev);
+/* In gxclrect.c */
+extern dev_proc_fill_rectangle(clist_fill_rectangle);
+extern dev_proc_copy_mono(clist_copy_mono);
+extern dev_proc_copy_color(clist_copy_color);
+extern dev_proc_copy_alpha(clist_copy_alpha);
+extern dev_proc_strip_tile_rectangle(clist_strip_tile_rectangle);
+extern dev_proc_strip_copy_rop(clist_strip_copy_rop);
+/* In gxclread.c */
+extern dev_proc_get_bits(clist_get_bits);
+
+/* The device procedures */
+gx_device_procs gs_clist_device_procs =
+{ clist_open,
+ gx_forward_get_initial_matrix,
+ gx_default_sync_output,
+ clist_output_page,
+ clist_close,
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ clist_fill_rectangle,
+ gx_default_tile_rectangle,
+ clist_copy_mono,
+ clist_copy_color,
+ gx_default_draw_line,
+ clist_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ clist_copy_alpha,
+ clist_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ gx_default_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ clist_strip_tile_rectangle,
+ clist_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_forward_get_hardware_params
+};
+
+/* ------ Define the command set and syntax ------ */
+
+/* Define the clipping enable/disable opcodes. */
+/* The path extensions initialize these to their proper values. */
+byte cmd_opvar_disable_clip = 0xff;
+byte cmd_opvar_enable_clip = 0xff;
+
+#ifdef DEBUG
+const char *cmd_op_names[16] = { cmd_op_name_strings };
+private const char *cmd_misc_op_names[16] = { cmd_misc_op_name_strings };
+const char **cmd_sub_op_names[16] =
+{ cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+private ulong far_data cmd_op_counts[256];
+private ulong far_data cmd_op_sizes[256];
+private ulong cmd_tile_reset, cmd_tile_found, cmd_tile_added;
+extern ulong cmd_diffs[5]; /* in gxclpath.c */
+private ulong cmd_same_band, cmd_other_band;
+int
+cmd_count_op(int op, uint size)
+{ cmd_op_counts[op]++;
+ cmd_op_sizes[op] += size;
+ if ( gs_debug_c('L') )
+ { const char **sub = cmd_sub_op_names[op >> 4];
+ if ( sub )
+ dprintf2(", %s(%u)\n", sub[op & 0xf], size);
+ else
+ dprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf, size);
+ fflush(dstderr);
+ }
+ return op;
+}
+void
+cmd_uncount_op(int op, uint size)
+{ cmd_op_counts[op]--;
+ cmd_op_sizes[op] -= size;
+}
+#endif
+
+/* Initialization for imager state. */
+/* The initial scale is arbitrary. */
+const gs_imager_state clist_imager_state_initial =
+ { gs_imager_state_initial(300.0 / 72.0) };
+
+/*
+ * The buffer area (data, data_size) holds a bitmap cache when both writing
+ * and reading. The rest of the space is used for the command buffer and
+ * band state bookkeeping when writing, and for the rendering buffer (image
+ * device) when reading. For the moment, we divide the space up
+ * arbitrarily, except that we allocate less space for the bitmap cache if
+ * the device doesn't need halftoning.
+ *
+ * All the routines for allocating tables in the buffer are idempotent, so
+ * they can be used to check whether a given-size buffer is large enough.
+ */
+
+/*
+ * Calculate the desired size for the tile cache.
+ */
+private uint
+clist_tile_cache_size(const gx_device *target, uint data_size)
+{ uint bits_size =
+ (data_size / 5) & -align_cached_bits_mod; /* arbitrary */
+
+ if ( (gx_device_has_color(target) ? target->color_info.max_color :
+ target->color_info.max_gray) >= 31
+ )
+ { /* No halftones -- cache holds only Patterns & characters. */
+ bits_size -= bits_size >> 2;
+ }
+#define min_bits_size 1024
+ if ( bits_size < min_bits_size )
+ bits_size = min_bits_size;
+#undef min_bits_size
+ return bits_size;
+}
+
+/*
+ * Initialize the allocation for the tile cache. Sets: tile_hash_mask,
+ * tile_max_count, tile_table, chunk (structure), bits (structure).
+ */
+private int
+clist_init_tile_cache(gx_device *dev, byte *init_data, ulong data_size)
+{ byte *data = init_data;
+ uint bits_size = data_size;
+ /*
+ * Partition the bits area between the hash table and the actual
+ * bitmaps. The per-bitmap overhead is about 24 bytes; if the
+ * average character size is 10 points, its bitmap takes about 24 +
+ * 0.5 * 10/72 * xdpi * 10/72 * ydpi / 8 bytes (the 0.5 being a
+ * fudge factor to account for characters being narrower than they
+ * are tall), which gives us a guideline for the size of the hash
+ * table.
+ */
+ uint avg_char_size =
+ (uint)(dev->x_pixels_per_inch * dev->y_pixels_per_inch *
+ (0.5 * 10/72 * 10/72 / 8)) + 24;
+ uint hc = bits_size / avg_char_size;
+ uint hsize;
+
+ while ( (hc + 1) & hc )
+ hc |= hc >> 1; /* make mask (power of 2 - 1) */
+ if ( hc < 0xff )
+ hc = 0xff; /* make allowance for halftone tiles */
+ else if ( hc > 0xfff )
+ hc = 0xfff; /* cmd_op_set_tile_index has 12-bit operand */
+ /* Make sure the tables will fit. */
+ while ( hc >= 3 && (hsize = (hc + 1) * sizeof(tile_hash)) >= bits_size )
+ hc >>= 1;
+ if ( hc < 3 )
+ return_error(gs_error_rangecheck);
+ cdev->tile_hash_mask = hc;
+ cdev->tile_max_count = hc - (hc >> 2);
+ cdev->tile_table = (tile_hash *)data;
+ data += hsize;
+ bits_size -= hsize;
+ gx_bits_cache_chunk_init(&cdev->chunk, data, bits_size);
+ gx_bits_cache_init(&cdev->bits, &cdev->chunk);
+ return 0;
+}
+
+/*
+ * Initialize the allocation for the bands. Requires: target. Sets:
+ * page_band_height (=page_info.band_params.BandHeight), nbands.
+ */
+private int
+clist_init_bands(gx_device *dev, uint data_size, int band_width,
+ int band_height)
+{ gx_device *target = cdev->target;
+ int nbands;
+
+ if ( gdev_mem_data_size((gx_device_memory *)target, band_width,
+ band_height) > data_size
+ )
+ return_error(gs_error_rangecheck);
+ cdev->page_band_height = band_height;
+ nbands = (target->height + band_height - 1) / band_height;
+ cdev->nbands = nbands;
+#ifdef DEBUG
+ if ( gs_debug_c('l') | gs_debug_c(':') )
+ dprintf4("[l]width=%d, band_width=%d, band_height=%d, nbands=%d\n",
+ target->width, band_width, band_height, nbands);
+#endif
+ return 0;
+}
+
+/*
+ * Initialize the allocation for the band states, which are used only
+ * when writing. Requires: nbands. Sets: states, cbuf, cend.
+ */
+private int
+clist_init_states(gx_device *dev, byte *init_data, uint data_size)
+{ ulong state_size = cdev->nbands * (ulong)sizeof(gx_clist_state);
+
+ /*
+ * The +100 in the next line is bogus, but we don't know what the
+ * real check should be. We're effectively assuring that at least 100
+ * bytes will be available to buffer command operands.
+ */
+ if ( state_size + sizeof(cmd_prefix) + cmd_largest_size + 100 > data_size )
+ return_error(gs_error_rangecheck);
+ cdev->states = (gx_clist_state *)init_data;
+ cdev->cbuf = init_data + state_size;
+ cdev->cend = init_data + data_size;
+ return 0;
+}
+
+/*
+ * Initialize all the data allocations. Requires: target. Sets:
+ * page_tile_cache_size, page_info.band_params.BandWidth,
+ * page_info.band_params.BandBufferSpace, + see above.
+ */
+private int
+clist_init_data(gx_device *dev, byte *init_data, uint data_size)
+{ gx_device *target = cdev->target;
+ const int band_width =
+ cdev->page_info.band_params.BandWidth =
+ (cdev->band_params.BandWidth ? cdev->band_params.BandWidth :
+ target->width);
+ int band_height = cdev->band_params.BandHeight;
+ const uint band_space =
+ cdev->page_info.band_params.BandBufferSpace =
+ (cdev->band_params.BandBufferSpace ?
+ cdev->band_params.BandBufferSpace : data_size);
+ byte *data = init_data;
+ uint size = band_space;
+ uint bits_size;
+ int code;
+
+ if ( band_height )
+ { /*
+ * The band height is fixed, so the band buffer requirement
+ * is completely determined.
+ */
+ uint band_data_size =
+ gdev_mem_data_size((gx_device_memory *)target,
+ band_width, band_height);
+
+ if ( band_data_size >= band_space )
+ return_error(gs_error_rangecheck);
+ bits_size = min(band_space - band_data_size, data_size >> 1);
+ }
+ else
+ { /*
+ * Choose the largest band height that will fit in the
+ * rendering-time buffer.
+ */
+ bits_size = clist_tile_cache_size(target, band_space);
+ bits_size = min(bits_size, data_size >> 1);
+ band_height = gdev_mem_max_height((gx_device_memory *)target,
+ band_width,
+ band_space - bits_size);
+ if ( band_height == 0 )
+ return_error(gs_error_rangecheck);
+ }
+ code = clist_init_tile_cache(dev, data, bits_size);
+ if ( code < 0 )
+ return code;
+ cdev->page_tile_cache_size = bits_size;
+ data += bits_size;
+ size -= bits_size;
+ code = clist_init_bands(dev, size, band_width, band_height);
+ if ( code < 0 )
+ return code;
+ return clist_init_states(dev, data, data_size - bits_size);
+}
+/*
+ * Reset the device state (for writing). This routine requires only
+ * data, data_size, and target to be set, and is idempotent.
+ */
+private int
+clist_reset(gx_device *dev)
+{ int code;
+ int nbands;
+
+ code = clist_init_data(dev, cdev->data, cdev->data_size);
+ if ( code < 0 )
+ return (cdev->permanent_error = code);
+
+ /* Now initialize the rest of the state. */
+ cdev->permanent_error = 0;
+ nbands = cdev->nbands;
+ cdev->ymin = cdev->ymax = -1; /* render_init not done yet */
+ memset(cdev->tile_table, 0, (cdev->tile_hash_mask + 1) *
+ sizeof(*cdev->tile_table));
+ cdev->cnext = cdev->cbuf;
+ cdev->ccl = 0;
+ cdev->band_range_list.head = cdev->band_range_list.tail = 0;
+ cdev->band_range_min = 0;
+ cdev->band_range_max = nbands - 1;
+ { int band;
+ gx_clist_state *states = cdev->states;
+
+ for ( band = 0; band < nbands; band++, states++ )
+ { static const gx_clist_state cls_initial =
+ { cls_initial_values };
+ *states = cls_initial;
+ }
+ }
+ /*
+ * Round up the size of the per-tile band mask so that the bits,
+ * which follow it, stay aligned.
+ */
+ cdev->tile_band_mask_size =
+ ((nbands + (align_bitmap_mod * 8 - 1)) >> 3) &
+ ~(align_bitmap_mod - 1);
+ /*
+ * Initialize the all-band parameters to impossible values,
+ * to force them to be written the first time they are used.
+ */
+ memset(&cdev->tile_params, 0, sizeof(cdev->tile_params));
+ cdev->tile_depth = 0;
+ cdev->tile_known_min = nbands;
+ cdev->tile_known_max = -1;
+ cdev->imager_state = clist_imager_state_initial;
+ cdev->clip_path = NULL;
+ cdev->clip_path_id = gs_no_id;
+ cdev->color_space = 0;
+ { int i;
+ for ( i = 0; i < countof(cdev->transfer_ids); ++i )
+ cdev->transfer_ids[i] = gs_no_id;
+ }
+ cdev->black_generation_id = gs_no_id;
+ cdev->undercolor_removal_id = gs_no_id;
+ cdev->device_halftone_id = gs_no_id;
+ return 0;
+}
+/*
+ * Initialize the device state (for writing). This routine requires only
+ * data, data_size, and target to be set, and is idempotent.
+ */
+private int
+clist_init(gx_device *dev)
+{
+ int code = clist_reset(dev);
+ if (code >= 0) {
+ cdev->in_image = false;
+ cdev->error_is_retryable = 0;
+ cdev->driver_call_nesting = 0;
+ cdev->ignore_lo_mem_warnings = 0;
+ }
+ return code;
+}
+
+/* (Re)init open band files for output (set block size, etc). */
+private int /* ret 0 ok, -ve error code */
+clist_reinit_output_file(gx_device *dev)
+{ int code = 0;
+
+ /* bfile needs to guarantee cmd_blocks for: 1 band range, nbands */
+ /* & terminating entry */
+ int b_block = sizeof(cmd_block) * (cdev->nbands + 2);
+
+ /* cfile needs to guarantee one writer buffer */
+ /* + one end_clip cmd (if during image's clip path setup) */
+ /* + an end_image cmd for each band (if during image) */
+ /* + end_cmds for each band and one band range */
+ int c_block
+ = cdev->cend - cdev->cbuf + 2 + cdev->nbands * 2 + (cdev->nbands + 1);
+
+ /* All this is for partial page rendering's benefit, do do only */
+ /* if partial page rendering is available */
+ if ( clist_test_VMerror_recoverable(cdev) )
+ { if (cdev->page_bfile != 0)
+ code = clist_set_block_size(cdev->page_bfile, b_block);
+ if (code >= 0 && cdev->page_cfile != 0)
+ code = clist_set_block_size(cdev->page_cfile, c_block);
+ }
+ return code;
+}
+
+/* Write out the current parameters that must be at the head of each page */
+/* if async rendering is in effect */
+private int
+clist_emit_page_header(gx_device *dev)
+{ int code = 0;
+ if ( (cdev->disable_mask & clist_disable_pass_thru_params) )
+ { do
+ if ( ( code = clist_put_current_params(cdev) ) >= 0 )
+ break;
+ while ( ( code = clist_try_recover_VMerror(cdev, code) ) < 0 );
+ cdev->permanent_error = (code < 0) ? code : 0;
+ if (cdev->permanent_error < 0)
+ cdev->error_is_retryable = 0;
+ }
+ return code;
+}
+
+/* Open the device's bandfiles */
+private int
+clist_open_output_file(gx_device *dev)
+{ char fmode[4];
+ int code;
+
+ if (cdev->do_not_open_or_close_bandfiles)
+ return 0; /* external bandfile open/close managed externally */
+
+ cdev->page_cfile = 0; /* in case of failure */
+ cdev->page_bfile = 0; /* ditto */
+ strcpy(fmode, "w+");
+ strcat(fmode, gp_fmode_binary_suffix);
+ cdev->page_cfname[0] = 0; /* create a new file */
+ cdev->page_bfname[0] = 0; /* ditto */
+ cdev->page_bfile_end_pos = 0;
+ if ( (code = clist_fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
+ cdev->bandlist_memory, cdev->bandlist_memory, true)) < 0 ||
+ (code = clist_fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
+ cdev->bandlist_memory, cdev->bandlist_memory, true)) < 0 ||
+ (code = clist_reinit_output_file(dev)) < 0
+ )
+ { clist_close_output_file(dev);
+ cdev->permanent_error = code;
+ cdev->error_is_retryable = 0;
+ }
+
+ return code;
+}
+
+/* Close the device by freeing the temporary files. */
+/* Note that this does not deallocate the buffer. */
+int
+clist_close_output_file(gx_device *dev)
+{ if ( cdev->page_cfile != NULL )
+ { clist_fclose(cdev->page_cfile, cdev->page_cfname, true);
+ cdev->page_cfile = NULL;
+ }
+ if ( cdev->page_bfile != NULL )
+ { clist_fclose(cdev->page_bfile, cdev->page_bfname, true);
+ cdev->page_bfile = NULL;
+ }
+ return 0;
+}
+
+/* Open the device by initializing the device state and opening the */
+/* scratch files. */
+private int
+clist_open(gx_device *dev)
+{ int code;
+ int pages_remain;
+
+ cdev->permanent_error = 0;
+ code = clist_init(dev);
+ if (code < 0)
+ return code;
+ code = clist_open_output_file(dev);
+ if ( code >= 0)
+ code = clist_emit_page_header(dev);
+ return code;
+}
+
+private int
+clist_close(gx_device *dev)
+{ if (cdev->do_not_open_or_close_bandfiles)
+ return 0;
+ return clist_close_output_file(dev);
+}
+
+/* The output_page procedure should never be called! */
+private int
+clist_output_page(gx_device *dev, int num_copies, int flush)
+{ return_error(gs_error_Fatal);
+}
+
+/* Reset (or prepare to append to) the command list after printing a page. */
+int
+clist_finish_page(gx_device *dev, bool flush)
+{ int code;
+ if ( flush )
+ {
+ if (cdev->page_cfile != 0)
+ clist_rewind(cdev->page_cfile, true, cdev->page_cfname);
+ if (cdev->page_bfile != 0)
+ clist_rewind(cdev->page_bfile, true, cdev->page_bfname);
+ cdev->page_bfile_end_pos = 0;
+ }
+ else
+ { if (cdev->page_cfile != 0)
+ clist_fseek(cdev->page_cfile, 0L, SEEK_END, cdev->page_cfname);
+ if (cdev->page_bfile != 0)
+ clist_fseek(cdev->page_bfile, 0L, SEEK_END, cdev->page_bfname);
+ }
+ code = clist_init(dev); /* reinitialize */
+ if (code >= 0)
+ code = clist_reinit_output_file(dev);
+ if (code >= 0)
+ code = clist_emit_page_header(dev);
+
+ return code;
+}
+
+/* Print statistics. */
+#ifdef DEBUG
+void
+cmd_print_stats(void)
+{ int ci, cj;
+ dprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
+ cmd_tile_reset, cmd_tile_found, cmd_tile_added);
+ dprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
+ cmd_diffs[0], cmd_diffs[1], cmd_diffs[2], cmd_diffs[3],
+ cmd_diffs[4]);
+ dprintf2(" same_band = %lu, other_band = %lu\n",
+ cmd_same_band, cmd_other_band);
+ for ( ci = 0; ci < 0x100; ci += 0x10 )
+ { const char **sub = cmd_sub_op_names[ci >> 4];
+ if ( sub != 0 )
+ { dprintf1("[l] %s =", cmd_op_names[ci >> 4]);
+ for ( cj = ci; cj < ci + 0x10; cj += 2 )
+ dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
+ sub[cj-ci],
+ cmd_op_counts[cj], cmd_op_sizes[cj],
+ sub[cj-ci+1],
+ cmd_op_counts[cj+1], cmd_op_sizes[cj+1]);
+ }
+ else
+ { ulong tcounts = 0, tsizes = 0;
+ for ( cj = ci; cj < ci + 0x10; cj++ )
+ tcounts += cmd_op_counts[cj],
+ tsizes += cmd_op_sizes[cj];
+ dprintf3("[l] %s (%lu,%lu) =\n\t",
+ cmd_op_names[ci >> 4], tcounts, tsizes);
+ for ( cj = ci; cj < ci + 0x10; cj++ )
+ if ( cmd_op_counts[cj] == 0 )
+ dputs(" -");
+ else
+ dprintf2(" %lu(%lu)", cmd_op_counts[cj],
+ cmd_op_sizes[cj]);
+ }
+ dputs("\n");
+ }
+}
+#endif /* DEBUG */
+
+/* ------ Writing ------ */
+
+/* Utilities */
+
+/* Write the commands for one band or band range. */
+private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_band(gx_device_clist_writer *cldev, int band_min, int band_max,
+ cmd_list *pcl, byte cmd_end)
+{ const cmd_prefix *cp = pcl->head;
+ int code_b = 0;
+ int code_c = 0;
+
+ if ( cp != 0 || cmd_end != cmd_opv_end_run ) {
+ clist_file_ptr cfile = cldev->page_cfile;
+ clist_file_ptr bfile = cldev->page_bfile;
+ cmd_block cb;
+ byte end = cmd_count_op(cmd_end, 1);
+
+ if (cfile == 0 || bfile == 0)
+ return_error(gs_error_ioerror);
+ cb.band_min = band_min;
+ cb.band_max = band_max;
+ cb.pos = clist_ftell(cfile);
+ if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
+ band_min, band_max, cb.pos);
+ clist_fwrite_chars(&cb, sizeof(cb), bfile);
+ if ( cp != 0 ) {
+ pcl->tail->next = 0; /* terminate the list */
+ for ( ; cp != 0; cp = cp->next ) {
+#ifdef DEBUG
+ if ( (const byte *)cp < cldev->cbuf ||
+ (const byte *)cp >= cldev->cend ||
+ cp->size > cldev->cend - (const byte *)cp
+ ) {
+ lprintf1("cmd_write_band error at 0x%lx\n", (ulong)cp);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ clist_fwrite_chars(cp + 1, cp->size, cfile);
+ }
+ pcl->head = pcl->tail = 0;
+ }
+
+ clist_fwrite_chars(&end, 1, cfile);
+ process_interrupts();
+ code_b = clist_ferror_code(bfile);
+ code_c = clist_ferror_code(cfile);
+ if (code_b < 0)
+ return_error(code_b);
+ if (code_c < 0)
+ return_error(code_c);
+ }
+ return code_b | code_c;
+}
+
+/* Write out the buffered commands, and reset the buffer. */
+private int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_buffer(gx_device_clist_writer *cldev, byte cmd_end)
+{ int nbands = cldev->nbands;
+ gx_clist_state *pcls;
+ int band;
+ int warning;
+ int code = cmd_write_band(cldev, cldev->band_range_min,
+ cldev->band_range_max,
+ &cldev->band_range_list, cmd_opv_end_run);
+
+
+ warning = code;
+ for ( band = 0, pcls = cldev->states;
+ code >= 0 && band < nbands; band++, pcls++
+ ) {
+ code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
+ warning |= code;
+ }
+ cldev->cnext = cldev->cbuf;
+ cldev->ccl = 0;
+ cldev->band_range_list.head = cldev->band_range_list.tail = 0;
+#ifdef DEBUG
+ if ( gs_debug_c('l') )
+ cmd_print_stats();
+#endif
+ return_check_interrupt(code != 0 ? code : warning);
+}
+/* End a page by flushing the buffer and terminating the command list. */
+int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
+clist_end_page(gx_device_clist_writer *cldev)
+{ int code = cmd_write_buffer(cldev, cmd_opv_end_page);
+ cmd_block cb;
+ int ecode = 0;
+
+ if (code >= 0)
+ { /* Write the terminating entry in the block file. */
+ /* Note that because of copypage, there may be many such entries. */
+ cb.band_min = cb.band_max = cmd_band_end;
+ cb.pos
+ = cldev->page_cfile == 0 ? 0 : clist_ftell(cldev->page_cfile);
+ clist_fwrite_chars(&cb, sizeof(cb), cldev->page_bfile);
+ code = clist_ferror_code(cldev->page_bfile);
+ }
+ if (code >= 0)
+ { ecode |= code;
+ cldev->page_bfile_end_pos = clist_ftell(cldev->page_bfile);
+ }
+ if (code < 0)
+ ecode = code;
+
+ /* reset block size to 0 to release reserve memory if mem files */
+ if (cldev->page_bfile != 0)
+ clist_set_block_size(cldev->page_bfile, 0);
+ if (cldev->page_cfile != 0)
+ clist_set_block_size(cldev->page_cfile, 0);
+
+#ifdef DEBUG
+ if ( gs_debug_c('l') | gs_debug_c(':') )
+ dprintf2("[l]clist_end_page at cfile=%ld, bfile=%ld\n",
+ cb.pos, cldev->page_bfile_end_pos);
+#endif
+ return ecode;
+}
+
+/* Recover recoverable VM error if possible without flushing */
+int /* ret -ve err, >= 0 if recovered w/# = cnt pages left in page queue */
+clist_try_recover_VMerror(gx_device_clist_writer *cldev,
+ int old_error_code)
+{ int code = old_error_code;
+ int pages_remain;
+
+ if ( !clist_test_VMerror_recoverable(cldev)
+ || !cldev->error_is_retryable
+ || old_error_code != gs_error_VMerror )
+ return old_error_code;
+
+ /* Do some rendering, return if enough memory is now free */
+ do {
+ pages_remain = (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, false );
+ if (pages_remain < 0)
+ { code = pages_remain; /* abort, error or interrupt req */
+ break;
+ }
+ if ( clist_reinit_output_file( (gx_device *)cldev ) == 0 )
+ { code = pages_remain; /* got enough memory to continue */
+ break;
+ }
+ } while (pages_remain);
+
+ if_debug1('L', "[L]soft flush of command list, status: %d\n", code);
+ return code;
+}
+
+/* If recoverable VM error, flush & try to recover it */
+int /* ret 0 ok, else -ve error */
+clist_try_recover_VMerror_flush(gx_device_clist_writer *cldev,
+ int old_error_code)
+{ int free_code = 0;
+ int reset_code = 0;
+ int code;
+
+ /* If the device has the ability to render partial pages, flush
+ * out the bandlist, and reset the writing state. Then, get the
+ * device to render this band. When done, see if there's now enough
+ * memory to satisfy the minimum low-memory guarantees. If not,
+ * get the device to render some more. If there's nothing left to
+ * render & still insufficient memory, declare an error condition.
+ */
+ if ( !clist_test_VMerror_recoverable(cldev)
+ || old_error_code != gs_error_VMerror )
+ return old_error_code; /* sorry, don't have any means to recover this error */
+ free_code = (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, true );
+
+ /* Reset the state of bands to "don't know anything" */
+ reset_code = clist_reset( (gx_device *)cldev );
+ if (reset_code >= 0)
+ reset_code = clist_open_output_file( (gx_device *)cldev );
+ if ( reset_code >= 0
+ && (cldev->disable_mask & clist_disable_pass_thru_params) )
+ reset_code = clist_put_current_params(cldev);
+ if (reset_code < 0)
+ {
+ cldev->permanent_error = reset_code;
+ cldev->error_is_retryable = 0;
+ }
+
+ code = reset_code < 0 ? reset_code : (free_code < 0 ? old_error_code : 0);
+ if_debug1('L', "[L]hard flush of command list, status: %d\n", code);
+ return code;
+}
+
+/* Add a command to the appropriate band list, */
+/* and allocate space for its data. */
+/* Return the pointer to the data area. */
+/* If an error or warning occurs, set cldev->error_code and return 0. */
+#define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
+byte *
+cmd_put_list_op(gx_device_clist_writer *cldev, cmd_list *pcl, uint size)
+{ byte *dp = cldev->cnext;
+ if ( size + cmd_headroom > cldev->cend - dp )
+ { if ( ( cldev->error_code =
+ cmd_write_buffer(cldev, cmd_opv_end_run) ) != 0 )
+ { if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else
+ {
+ /* upgrade lo-mem warning into an error */
+ if (!cldev->ignore_lo_mem_warnings)
+ cldev->error_code = gs_error_VMerror;
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ else
+ return cmd_put_list_op(cldev, pcl, size);
+ }
+ if ( cldev->ccl == pcl )
+ { /* We're adding another command for the same band. */
+ /* Tack it onto the end of the previous one. */
+ cmd_count_add1(cmd_same_band);
+#ifdef DEBUG
+ if ( pcl->tail->size > dp - (byte *)(pcl->tail + 1) )
+ { lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong)pcl->tail);
+ }
+#endif
+ pcl->tail->size += size;
+ }
+ else
+ { /* Skip to an appropriate alignment boundary. */
+ /* (We assume the command buffer itself is aligned.) */
+ cmd_prefix *cp =
+ (cmd_prefix *)(dp +
+ ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
+ cmd_count_add1(cmd_other_band);
+ dp = (byte *)(cp + 1);
+ if ( pcl->tail != 0 )
+ {
+#ifdef DEBUG
+ if ( pcl->tail < pcl->head ||
+ pcl->tail->size > dp - (byte *)(pcl->tail + 1)
+ )
+ { lprintf1("cmd_put_list_op error at 0x%lx\n",
+ (ulong)pcl->tail);
+ }
+#endif
+ pcl->tail->next = cp;
+ }
+ else
+ pcl->head = cp;
+ pcl->tail = cp;
+ cldev->ccl = pcl;
+ cp->size = size;
+ }
+ cldev->cnext = dp + size;
+ return dp;
+}
+#ifdef DEBUG
+byte *
+cmd_put_op(gx_device_clist_writer *cldev, gx_clist_state *pcls, uint size)
+{ if_debug3('L', "[L]band %d: size=%u, left=%u",
+ (int)(pcls - cldev->states),
+ size, (uint)(cldev->cend - cldev->cnext));
+ return cmd_put_list_op(cldev, &pcls->list, size);
+}
+#endif
+
+/* Add a command for a range of bands. */
+byte *
+cmd_put_range_op(gx_device_clist_writer *cldev, int band_min, int band_max,
+ uint size)
+{ if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
+ band_min, band_max, size,
+ (uint)(cldev->cend - cldev->cnext));
+ if ( cldev->ccl != 0 &&
+ (cldev->ccl != &cldev->band_range_list ||
+ band_min != cldev->band_range_min ||
+ band_max != cldev->band_range_max)
+ )
+ { if ( (cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0 )
+ { if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else
+ {
+ /* upgrade lo-mem warning into an error */
+ cldev->error_code = gs_error_VMerror;
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ cldev->band_range_min = band_min;
+ cldev->band_range_max = band_max;
+ }
+ return cmd_put_list_op(cldev, &cldev->band_range_list, size);
+}
+
+/* Write a variable-size positive integer. */
+int
+cmd_size_w(register uint w)
+{ register int size = 1;
+ while ( w > 0x7f ) w >>= 7, size++;
+ return size;
+}
+byte *
+cmd_put_w(register uint w, register byte *dp)
+{ while ( w > 0x7f ) *dp++ = w | 0x80, w >>= 7;
+ *dp = w;
+ return dp + 1;
+}
+
+/* Define the encodings of the different settable colors. */
+const clist_select_color_t
+ clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
+ clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
+ clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
+ clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
+int /* ret 0 all ok, -ve error */
+cmd_put_color(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const clist_select_color_t *select,
+ gx_color_index color, gx_color_index *pcolor)
+{ byte *dp;
+ long diff = (long)color - (long)(*pcolor);
+ byte op, op_delta2;
+ int code;
+
+ if ( diff == 0 )
+ return 0;
+ if ( select->tile_color )
+ {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
+ if (code < 0)
+ return code;
+ }
+ op = select->set_op;
+ op_delta2 = select->delta2_op;
+ if ( color == gx_no_color_index )
+ { /*
+ * We must handle this specially, because it may take more
+ * bytes than the color depth.
+ */
+ code = set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
+ if (code < 0)
+ return code;
+ }
+ else
+ { long delta;
+ byte operand;
+
+ switch ( (cldev->color_info.depth + 15) >> 3 )
+ {
+ case 5:
+ if ( !((delta = diff + cmd_delta1_32_bias) &
+ ~cmd_delta1_32_mask) &&
+ (operand =
+ (byte)((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
+ operand != 15
+ )
+ { code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte)(((delta >> 10) & 0300) +
+ (delta >> 5) + delta);
+ break;
+ }
+ if ( !((delta = diff + cmd_delta2_32_bias) &
+ ~cmd_delta2_32_mask)
+ )
+ { code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = (byte)((delta >> 20) + (delta >> 16));
+ dp[2] = (byte)((delta >> 4) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 5);
+ if (code < 0)
+ return code;
+ *++dp = (byte)(color >> 24);
+ goto b3;
+ case 4:
+ if ( !((delta = diff + cmd_delta1_24_bias) &
+ ~cmd_delta1_24_mask) &&
+ (operand = (byte)(delta >> 16)) != 0 &&
+ operand != 15
+ )
+ { code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte)((delta >> 4) + delta);
+ break;
+ }
+ if ( !((delta = diff + cmd_delta2_24_bias) &
+ ~cmd_delta2_24_mask)
+ )
+ { code
+ = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = ((byte)(delta >> 13) & 0xf8) +
+ ((byte)(delta >> 11) & 7);
+ dp[2] = (byte)(((delta >> 3) & 0xe0) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 4);
+ if (code < 0)
+ return code;
+b3: *++dp = (byte)(color >> 16);
+ goto b2;
+ case 3:
+ code = set_cmd_put_op(dp, cldev, pcls, op, 3);
+ if (code < 0)
+ return code;
+b2: *++dp = (byte)(color >> 8);
+ goto b1;
+ case 2:
+ if ( diff >= -7 && diff < 7 )
+ { code = set_cmd_put_op(dp, cldev, pcls,
+ op + (int)diff + 8, 1);
+ if (code < 0)
+ return code;
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 2);
+ if (code < 0)
+ return code;
+b1: dp[1] = (byte)color;
+ }
+ }
+ *pcolor = color;
+ return 0;
+}
+
+/* Put out a command to set the tile colors. */
+int /* ret 0 all ok, -ve error */
+cmd_set_tile_colors(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ gx_color_index color0, gx_color_index color1)
+{ if ( color0 != pcls->tile_colors[0] )
+ { int code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color0,
+ color0, &pcls->tile_colors[0]);
+ if ( code != 0 )
+ return code;
+ }
+ if ( color1 != pcls->tile_colors[1] )
+ { int code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color1,
+ color1, &pcls->tile_colors[1]);
+ if ( code != 0 )
+ return code;
+ }
+ return 0;
+}
+
+/* Put out a command to set the tile phase. */
+int /* ret 0 all ok, -ve error */
+cmd_set_tile_phase(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int px, int py)
+{ int pcsize;
+ byte *dp;
+ int code;
+
+ pcls->tile_phase.x = px;
+ pcls->tile_phase.y = py;
+ pcsize = 1 + cmd_sizexy(pcls->tile_phase);
+ code =
+ set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
+ if (code < 0)
+ return code;
+ ++dp;
+ cmd_putxy(pcls->tile_phase, dp);
+ return 0;
+}
+
+/* Write a command to enable or disable the logical operation. */
+int /* ret 0 all ok, -ve error */
+cmd_put_enable_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int enable)
+{ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opv_enable_lop :
+ cmd_opv_disable_lop),
+ 1);
+ if (code < 0)
+ return code;
+ pcls->lop_enabled = enable;
+ return 0;
+}
+
+/* Write a command to enable or disable clipping. */
+/* This routine is only called if the path extensions are included. */
+int /* ret 0 all ok, -ve error */
+cmd_put_enable_clip(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int enable)
+{ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opvar_enable_clip :
+ cmd_opvar_disable_clip),
+ 1);
+ if (code < 0)
+ return code;
+ pcls->clip_enabled = enable;
+ return 0;
+}
+
+/* Write a command to set the logical operation. */
+int /* ret 0 all ok, -ve error */
+cmd_set_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ gs_logical_operation_t lop)
+{ byte *dp;
+ uint lop_msb = lop >> 6;
+
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_lop + (lop & 0x3f);
+ cmd_put_w(lop_msb, dp + 2);
+ pcls->lop = lop;
+ return 0;
+}
+
+/* Write a parameter list */
+int /* ret 0 all ok, -ve error */
+cmd_put_params(gx_device_clist_writer *cldev,
+ gs_param_list *param_list) /* NB open for READ */
+{ byte *dp;
+ int code;
+ byte local_buf[512]; /* arbitrary */
+ int param_length = 0;
+
+ /* Get serialized list's length + try to get it into local var if it fits. */
+ param_length = code =
+ gs_param_list_serialize( param_list, local_buf, sizeof(local_buf) );
+
+ if (param_length > 0)
+ { /* Get cmd buffer space for serialized */
+ code = set_cmd_put_all_op( dp, cldev, cmd_opv_put_params,
+ 1 + sizeof(unsigned) + param_length );
+ if (code < 0)
+ return code;
+
+ /* write param list to cmd list: needs to all fit in cmd buffer */
+ if_debug1('l', "[l]put_params, length=%d\n", param_length);
+ ++dp;
+ memcpy( dp, &param_length, sizeof(unsigned) );
+ dp += sizeof(unsigned);
+ if ( param_length > sizeof(local_buf) )
+ { int old_param_length = param_length;
+ param_length = code
+ = gs_param_list_serialize(param_list, dp, old_param_length);
+ if (param_length >= 0)
+ code = old_param_length != param_length
+ ? code = gs_error_unknownerror : 0;
+ if (code < 0)
+ { /* error serializing: back out by writing a 0-length parm list */
+ memset( dp - sizeof(unsigned), 0, sizeof(unsigned) );
+ cmd_shorten_list_op(cldev, &cldev->band_range_list, old_param_length);
+ }
+ }
+ else
+ memcpy(dp, local_buf, param_length); /* did this when computing length */
+ }
+
+ return code;
+}
+
+/* Write the target device's current parameter list */
+private int /* ret 0 all ok, -ve error */
+clist_put_current_params(gx_device_clist_writer *cldev)
+{ gx_device *target = cldev->target;
+ gs_c_param_list param_list;
+ int code;
+
+ /* To avoid attempts to write to unallocated memory, no attempt */
+ /* is made to write to the command list if permanent_error is set. */
+ /* This typically happens if a previous put_params failed. */
+ if (cldev->permanent_error)
+ return cldev->permanent_error;
+ gs_c_param_list_write(&param_list, cldev->memory);
+ code = (*dev_proc(target, get_params))
+ ( target, (gs_param_list *)&param_list );
+ if (code >= 0)
+ { gs_c_param_list_read(&param_list);
+ code = cmd_put_params( cldev, (gs_param_list *)&param_list );
+ }
+ gs_c_param_list_release(&param_list);
+
+ return code;
+}
+
+
+/* ---------------- Driver interface ---------------- */
+
+private int
+clist_get_band(gx_device *dev, int y, int *band_start)
+{ int band_height = cdev->page_band_height;
+ int start;
+
+ if ( y < 0 )
+ y = 0;
+ else if ( y >= dev->height )
+ y = dev->height;
+ *band_start = start = y - y % band_height;
+ return min(dev->height - start, band_height);
+}
diff --git a/gs/src/gxclist.h b/gs/src/gxclist.h
new file mode 100644
index 000000000..4dcc7abb0
--- /dev/null
+++ b/gs/src/gxclist.h
@@ -0,0 +1,301 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclist.h */
+/* Command list definitions for Ghostscript. */
+/* Requires gxdevice.h and gxdevmem.h */
+
+#ifndef gxclist_INCLUDED
+# define gxclist_INCLUDED
+
+#include "gscspace.h"
+#include "gxbcache.h"
+#include "gxclio.h"
+#include "gxistate.h"
+#include "gxband.h"
+
+/*
+ * A command list is essentially a compressed list of driver calls.
+ * Command lists are used to record an image that must be rendered in bands
+ * for high-resolution and/or limited-memory printers.
+ *
+ * Command lists work in two phases. The first phase records driver calls,
+ * sorting them according to the band(s) they affect. The second phase
+ * reads back the commands band-by-band to create the bitmap images.
+ * When opened, a command list is in the recording state; it switches
+ * automatically from recording to reading when its get_bits procedure
+ * is called. Currently, there is a hack to reopen the device after
+ * each page is processed, in order to switch back to recording.
+ */
+
+/*
+ * The command list contains both commands for particular bands (the vast
+ * majority) and commands that apply to a range of bands. In order to
+ * synchronize the two, we maintain the following invariant for buffered
+ * commands:
+ *
+ * If there are any band-range commands in the buffer, they are the
+ * first commands in the buffer, before any specific-band commands.
+ *
+ * To maintain this invariant, whenever we are about to put an band-range
+ * command in the buffer, we check to see if the buffer already has any
+ * band-range commands in it, and if so, whether they are the last commands
+ * in the buffer and are for the same range; if the answer to any of these
+ * questions is negative, we flush the buffer.
+ */
+
+/* ---------------- Public structures ---------------- */
+
+/*
+ * Define a saved page object. This consists of a snapshot of the device
+ * structure, information about the page per se, and the num_copies
+ * parameter of output_page.
+ */
+typedef struct gx_saved_page_s {
+ gx_device device;
+ char dname[8+1]; /* device name for checking */
+ gx_band_page_info info;
+ int num_copies;
+} gx_saved_page;
+
+/*
+ * Define a saved page placed at a particular (X,Y) offset for rendering.
+ */
+typedef struct gx_placed_page_s {
+ gx_saved_page *page;
+ gs_int_point offset;
+} gx_placed_page;
+
+/*
+ * Define a procedure to cause some bandlist memory memory to be freed up,
+ * probably by rendering current bandlist contents.
+ */
+#define proc_free_up_bandlist_memory(proc)\
+ int proc(P2(gx_device *, bool))
+
+/* ---------------- Internal structures ---------------- */
+
+/*
+ * Currently, halftoning occurs during the first phase, producing calls
+ * to tile_rectangle. Both phases keep a cache of recently seen bitmaps
+ * (halftone cells and characters), which allows writing only a short cache
+ * index in the command list rather than the entire bitmap.
+ *
+ * We keep only a single cache for all bands, but since the second phase
+ * reads the command lists for each band separately, we have to keep track
+ * for each cache entry E and band B whether the definition of E has been
+ * written into B's list. We do this with a bit mask in each entry.
+ *
+ * Eventually, we will replace this entire arrangement with one in which
+ * we pass the actual halftone screen (whitening order) to all bands
+ * through the command list, and halftoning occurs on the second phase.
+ * This not only will shrink the command list, but will allow us to apply
+ * other rendering algorithms such as error diffusion in the second phase.
+ */
+typedef struct {
+ ulong offset; /* writing: offset from cdev->data, */
+ /* 0 means unused */
+ /* reading: offset from cdev->chunk.data */
+} tile_hash;
+typedef struct {
+ gx_cached_bits_common;
+ /* To save space, instead of storing rep_width and rep_height, */
+ /* we store width / rep_width and height / rep_height. */
+ byte x_reps, y_reps;
+ ushort rep_shift;
+ ushort index; /* index in table (hash table when writing) */
+ ushort num_bands; /* # of 1-bits in the band mask */
+ /* byte band_mask[]; */
+#define ts_mask(pts) (byte *)((pts) + 1)
+ /* byte bits[]; */
+#define ts_bits(cldev,pts) (ts_mask(pts) + (cldev)->tile_band_mask_size)
+} tile_slot;
+
+/* Define the prefix on each command run in the writing buffer. */
+typedef struct cmd_prefix_s cmd_prefix;
+struct cmd_prefix_s {
+ cmd_prefix *next;
+ uint size;
+};
+
+/* Define the pointers for managing a list of command runs in the buffer. */
+/* There is one of these for each band, plus one for band-range commands. */
+typedef struct cmd_list_s {
+ cmd_prefix *head, *tail; /* list of commands for band */
+} cmd_list;
+
+/*
+ * In order to keep the per-band state down to a reasonable size,
+ * we store only a single set of the imager state parameters;
+ * for each parameter, each band has a flag that says whether that band
+ * 'knows' the current value of the parameters.
+ */
+extern const gs_imager_state clist_imager_state_initial;
+
+/*
+ * Define the main structure for holding command list state.
+ * Unless otherwise noted, all elements are used in both the writing (first)
+ * and reading (second) phase.
+ */
+typedef struct gx_clist_state_s gx_clist_state;
+#define gx_device_clist_common\
+ gx_device_forward_common; /* (see gxdevice.h) */\
+ /* Following must be set before writing or reading. */\
+ /* See gx_device_clist_writer, below, for more that must be init'd */\
+ /* gx_device *target; */ /* device for which commands */\
+ /* are being buffered */\
+ dev_proc_make_buffer_device((*make_buffer_device));\
+ gs_memory_t *bandlist_memory; /* allocator for in-memory bandlist files */\
+ byte *data; /* buffer area */\
+ uint data_size; /* size of buffer */\
+ gx_band_params band_params; /* band buffering parameters */\
+ int do_not_open_or_close_bandfiles; /* if true, do not open/close bandfiles */\
+ /* Following are used for both writing and reading. */\
+ gx_bits_cache_chunk chunk; /* the only chunk of bits */\
+ gx_bits_cache bits;\
+ uint tile_hash_mask; /* size of tile hash table -1 */\
+ uint tile_band_mask_size; /* size of band mask preceding */\
+ /* each tile in the cache */\
+ tile_hash *tile_table; /* table for tile cache: */\
+ /* see tile_hash above */\
+ /* (a hash table when writing) */\
+ int ymin, ymax; /* current band, <0 when writing */\
+ /* Following are set when writing, read when reading. */\
+ gx_band_page_info page_info; /* page information */\
+ int nbands /* # of bands */
+
+#define clist_band_height(cldev) ((cldev)->page_info.band_height)
+#define clist_cfname(cldev) ((cldev)->page_info.cfname)
+#define clist_cfile(cldev) ((cldev)->page_info.cfile)
+#define clist_bfname(cldev) ((cldev)->page_info.bfname)
+#define clist_bfile(cldev) ((cldev)->page_info.bfile)
+
+/* Define the length of the longest dash pattern we are willing to store. */
+/* (Strokes with longer patterns are converted to fills.) */
+#define cmd_max_dash 11
+
+/* Define the state of a band list when writing. */
+typedef struct gx_device_clist_writer_s {
+ gx_device_clist_common; /* (must be first) */
+ int error_code; /* error returned by cmd_put_op */
+ gx_clist_state *states; /* current state of each band */
+ byte *cbuf; /* start of command buffer */
+ byte *cnext; /* next slot in command buffer */
+ byte *cend; /* end of command buffer */
+ cmd_list *ccl; /* &clist_state.list of last command */
+ cmd_list band_range_list; /* list of band-range commands */
+ int band_range_min, band_range_max; /* range for list */
+ uint tile_max_size; /* max size of a single tile (bytes) */
+ uint tile_max_count; /* max # of hash table entries */
+ gx_strip_bitmap tile_params; /* current tile parameters */
+ int tile_depth; /* current tile depth */
+ int tile_known_min, tile_known_max;
+ /* range of bands that knows the */
+ /* current tile parameters */
+ gs_imager_state imager_state; /* current values of imager params */
+ float dash_pattern[cmd_max_dash]; /* current dash pattern */
+ const gx_clip_path *clip_path; /* current clip path */
+ gs_id clip_path_id; /* id of current clip path */
+ byte color_space; /* current color space identifier */
+ /* (only used for images) */
+ gs_indexed_params indexed_params; /* current indexed space parameters */
+ /* (ditto) */
+ gs_id transfer_ids[4]; /* ids of transfer maps */
+ gs_id black_generation_id; /* id of black generation map */
+ gs_id undercolor_removal_id; /* id of u.c.r. map */
+ gs_id device_halftone_id; /* id of device halftone */
+ bool in_image; /* true if we are inside an image */
+ /* that we are passing through */
+ int error_is_retryable; /* Extra status used to distinguish hard VMerrors */
+ /* from warnings upgraded to VMerrors. */
+ /* T if err ret'd by cmd_put_op et al can be retried */
+ int permanent_error; /* if < 0, error only cleared by clist_reset() */
+ int driver_call_nesting; /* nesting level of non-retryable driver calls */
+ int ignore_lo_mem_warnings; /* ignore warnings from clist file/mem */
+ /* Following must be set before writing */
+ proc_free_up_bandlist_memory((*free_up_bandlist_memory)); /* if nz, proc to free some bandlist memory */
+ int disable_mask; /* mask of routines to disable clist_disable_xxx */
+} gx_device_clist_writer;
+
+/* Bits for gx_device_clist_writer.disable_mask. Bit set disables behavior */
+#define clist_disable_fill_path (1 << 0)
+#define clist_disable_stroke_path (1 << 1)
+#define clist_disable_hl_image (1 << 2)
+#define clist_disable_complex_clip (1 << 3)
+#define clist_disable_nonrect_hl_image (1 << 4)
+#define clist_disable_pass_thru_params (1 << 5) /* disable EXCEPT at top of page */
+
+/* Define the state of a band list when reading. */
+/* For normal rasterizing, pages and num_pages are both 0. */
+typedef struct gx_device_clist_reader_s {
+ gx_device_clist_common; /* (must be first) */
+ const gx_placed_page *pages;
+ int num_pages;
+} gx_device_clist_reader;
+
+typedef union gx_device_clist_s {
+ struct _clc {
+ gx_device_clist_common;
+ } common;
+ gx_device_clist_reader reader;
+ gx_device_clist_writer writer;
+} gx_device_clist;
+
+/* setup before opening clist device */
+#define clist_init_params(xclist, xdata, xdata_size, xtarget, xmake_buffer, xband_params, xexternal, xmemory, xfree_bandlist, xdisable)\
+ (xclist)->common.data = (xdata);\
+ (xclist)->common.data_size = (xdata_size);\
+ (xclist)->common.target = (xtarget);\
+ (xclist)->common.make_buffer_device = (xmake_buffer);\
+ (xclist)->common.band_params = (xband_params);\
+ (xclist)->common.do_not_open_or_close_bandfiles = (xexternal);\
+ (xclist)->common.bandlist_memory = (xmemory);\
+ (xclist)->writer.free_up_bandlist_memory = (xfree_bandlist);\
+ (xclist)->writer.disable_mask = (xdisable)
+
+/* Determine if this clist device is able to recover VMerrors */
+#define clist_test_VMerror_recoverable(cldev) \
+ ( (cldev)->free_up_bandlist_memory != 0 )
+
+/* The device template itself is never used, only the procedures. */
+extern gx_device_procs gs_clist_device_procs;
+
+/* Reset (or prepare to append to) the command list after printing a page. */
+int clist_finish_page(P2(gx_device *, bool));
+
+/* Force bandfiles closed */
+int clist_close_output_file(P1(gx_device *));
+
+#if !defined(gx_device_printer_defined)
+ #define gx_device_printer_defined
+/* Define the abstract type for a printer device. */
+typedef struct gx_device_printer_s gx_device_printer;
+#endif /* !defined(gx_device_printer_defined) */
+
+
+/* Set up the device's geometry to that in cmd list: for async rendering only */
+int clist_setup_params(P1(gx_device *dev));
+
+/* Do more rendering to a client-supplied memory image, return results */
+int clist_get_overlay_bits(P4(gx_device_printer *, int, int, byte *));
+
+/* Find out where the band buffer for a given line is going to fall on the */
+/* next call to get_bits. */
+int clist_locate_overlay_buffer(P3(gx_device_printer *, int, byte **));
+
+#endif /* gxclist_INCLUDED */
diff --git a/gs/src/gxcllzw.c b/gs/src/gxcllzw.c
new file mode 100644
index 000000000..83370f40b
--- /dev/null
+++ b/gs/src/gxcllzw.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcllzw.c */
+/* LZW filter initialization for RAM-based band lists */
+#include "std.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gxclmem.h"
+#include "slzwx.h"
+
+private stream_LZW_state cl_LZWE_state;
+private stream_LZW_state cl_LZWD_state;
+
+/* Initialize the states to be copied. */
+void
+gs_cl_lzw_init(gs_memory_t *mem)
+{ s_LZW_set_defaults((stream_state *)&cl_LZWE_state);
+ cl_LZWE_state.template = &s_LZWE_template;
+ s_LZW_set_defaults((stream_state *)&cl_LZWD_state);
+ cl_LZWD_state.template = &s_LZWD_template;
+}
+
+/* Return the prototypes for compressing/decompressing the band list. */
+const stream_state *
+clist_compressor_state(void *client_data)
+{ return (const stream_state *)&cl_LZWE_state;
+}
+const stream_state *
+clist_decompressor_state(void *client_data)
+{ return (const stream_state *)&cl_LZWD_state;
+}
diff --git a/gs/src/gxclmem.c b/gs/src/gxclmem.c
new file mode 100644
index 000000000..280aabf5b
--- /dev/null
+++ b/gs/src/gxclmem.c
@@ -0,0 +1,1129 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclmem.c */
+/* RAM-based command list implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxclmem.h"
+
+/*
+ * Based on: memfile.c Version: 1.4 3/21/95 14:59:33 by Ray Johnston.
+ * Copyright assigned to Aladdin Enterprises.
+ */
+
+/*****************************************************************************
+
+ This package is more or less optimal for use by the clist routines, with
+ a couple of the more likely to change "tuning" parameters given in the
+ two macros below -- NEED_TO_COMPRESS and GET_NUM_RAW_BUFFERS. Usually
+ the NEED_TO_COMPRESS decision will be deferred as long as possible based
+ on some total system free RAM space remaining.
+
+ The data structures are in "memfile.h", and the primary 'tuning' parameter
+ is MEMFILE_DATA_SIZE. This should not be too small to keep the overhead
+ ratio of the block structures to the clist data small. A value of 16384
+ is probably in the ballpark.
+
+ The concept is that a memory based "file" is created initially without
+ compression, with index blocks every MEMFILE_DATA_SIZE of the file. The
+ primary blocks (used by the memfile_fseek logic) for indexing into the
+ file are called 'logical' (LOG_MEMFILE_BLK) and the data in stored in a
+ different block called a 'physical' block (PHYS_MEMFILE_BLK). When the
+ file is not yet compressed, indicated by (f->phys_curr==NULL), then there
+ is one physical block for each logical block. The physical block also has
+ the 'data_limit' set to NULL if the data is not compressed. Thus when a
+ file is not compressed there is one physical block for each logical block.
+
+COMPRESSION.
+
+ When compression is triggered for a file then all of the blocks except
+ the last are compressed. Compression will result in a physical block
+ that holds data for more than one logical block. Each logical block now
+ points to the start of compressed data in a physical block with the
+ 'phys_pdata' pointer. The 'data_limit' pointer in the physical block is
+ where the compression logic stopped storing data (as stream data
+ compressors are allowed to do). The data for the logical block may span
+ to the next physical block. Once physical blocks are compressed, they are
+ chained together using the 'link' field.
+
+ The 'f->phys_curr' points to the block being filled by compression, with
+ the 'f->wt.ptr' pointing to the last byte filled in the block. These are
+ used during subsequent compression when the last logical block of the
+ file fills the physical block.
+
+DECOMPRESSION.
+
+ During reading the clist, if the logical block points to an uncompressed
+ physical block, then 'memfile_get_pdata' simply sets the 'pdata' and the
+ 'pdata_end' pointers. If the logical block was compressed, then it may
+ still be resident in a cache of decompression buffers. The number of these
+ decompression buffers is not critical -- even one is enough, but having
+ more may prevent decompressing blocks more than once (a cache_miss). The
+ number of decompression buffers, called "raw" buffers, that are attempted
+ to allocate can be changed with the GET_NUM_RAW_BUFFERS macro, but no
+ error occurs if less than that number can be allocated.
+
+ If the logical block still resides in a decompression cache buffer, then
+ the 'raw_block' will identify the block. If the data for a logical block
+ only exists in compressed form, then the "tail" of the list of decompression
+ buffers is re-used, marking the 'raw_block' of the logical block that was
+ previously associated with this data to NULL.
+
+ Whichever raw decompression buffer is accessed is moved to the head of the
+ decompression buffer list in order to keep the tail of the list as the
+ "least recently used".
+
+ There are some DEBUG global static variables used to count the number of
+ cache hits "tot_cache_hits" and the number of times a logical block is
+ decompressed "tot_cache_miss". Note that the actual number of cache miss
+ events is 'f->log_length/MEMFILE_DATA_SIZE - tot_cache_miss' since we
+ assume that every logical block must be decmpressed at least once.
+
+ Empirical results so far indicate that if one cache raw buffer for every
+ 32 logical blocks, then the hit/miss ratio exceeds 99%. Of course, the
+ number of raw buffers should be more than 1 if possible, and in many
+ implementations (single threaded), the memory usage does not increase
+ during the page output step so almost all of memory can be used for
+ these raw buffers to prevent the likelihood of a cache miss.
+
+ Of course, this is dependent on reasonably efficient clist blocking
+ during writing which is dependent on the data and on the BufferSpace
+ value which determines the number of clist band data buffers available.
+ Empirical testing shows that the overall efficiency is best if the
+ BufferSpace value is 1,000,000 (as in the original Ghostscript source).
+ [Note: I expected to be able to use smaller buffer sizes for some cases,
+ but this resulted in a high level of thrashing...RJJ]
+
+LIMITATIONS.
+
+ The most serious limitation is caused by the way 'memfile_fwrite' decides
+ to free up and re-initialize a file. If memfile_fwrite is called after
+ a seek to any location except the start of the file, then an error is
+ issued since logic is not present to properly free up on a partial file.
+ This is not a problem as used by the 'clist' logic since rewind is used
+ to position to the start of a file when re-using it after an 'erasepage'.
+
+ Since the 'clist' logic always traverses the clist using fseek's to ever
+ increasing locations, no optimizations of backward seeks was implemented.
+ This would be relatively easy with back chain links or bi-directional
+ "X-OR" pointer information to link the logical block chain. The rewind
+ function is optimal and moves directly to the start of the file.
+
+********************************************************************************/
+
+/*
+ The need to compress should be conditional on the amount of available
+ memory, but we don't have a way to communicate this to these routines.
+ Instead, we simply start compressing when we've allocated more than
+ COMPRESSION_THRESHOLD amount of data. The threshold should be at
+ least as large as the fixed overhead of the compressor plus the
+ decompressor, plus the expected compressed size of a block that size.
+*/
+private const long COMPRESSION_THRESHOLD = 300000;
+#define NEED_TO_COMPRESS(f)\
+ ((f)->ok_to_compress && (f)->total_space > COMPRESSION_THRESHOLD)
+
+ /* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8) */
+#define GET_NUM_RAW_BUFFERS( f ) \
+ max(f->log_length/MEMFILE_DATA_SIZE/32, 8)
+
+#define MALLOC(f, siz, cname)\
+ (void *)gs_alloc_bytes((f)->data_memory, siz, cname)
+#define FREE(f, obj, cname)\
+ (gs_free_object((f)->data_memory, obj, cname),\
+ (f)->total_space -= sizeof(*(obj)))
+
+/* Structure descriptor for GC */
+private_st_MEMFILE();
+
+ /* forward references */
+private void memfile_free_mem(P1(MEMFILE *f));
+private int memfile_init_empty(P1(MEMFILE *f));
+
+/************************************************/
+/* #define DEBUG /- force statistics -/ */
+/************************************************/
+
+#ifdef DEBUG
+long tot_compressed;
+long tot_raw;
+long tot_cache_miss;
+long tot_cache_hits;
+long tot_swap_out;
+/*
+ The following pointers are here only for helping with a dumb debugger
+ that can't inspect local variables!
+*/
+byte *decomp_wt_ptr0, *decomp_wt_limit0;
+const byte *decomp_rd_ptr0, *decomp_rd_limit0;
+byte *decomp_wt_ptr1, *decomp_wt_limit1;
+const byte *decomp_rd_ptr1, *decomp_rd_limit1;
+#endif
+
+/* ----------------------------- Memory Allocation --------------------- */
+void * /* allocated memory's address, 0 if failure */
+allocateWithReserve(
+ MEMFILE *f, /* file to allocate mem to */
+ int sizeofBlock, /* size of block to allocate */
+ int *return_code, /* RET 0 ok, -ve GS-style error, or +1 if OK but low memory */
+ const char *allocName, /* name to allocate by */
+ const char *errorMessage /* error message to print */
+) {
+ int code = 0; /* assume success */
+ void *block = MALLOC(f, sizeofBlock, allocName);
+ if (block == NULL)
+ {
+ /* Try to recover block from reserve */
+ if ( sizeofBlock == sizeof(LOG_MEMFILE_BLK) )
+ {
+ if (f->reserveLogBlockCount > 0)
+ {
+ block = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = f->reserveLogBlockChain->link;
+ --f->reserveLogBlockCount;
+ }
+ }
+ else if ( sizeofBlock == sizeof(PHYS_MEMFILE_BLK)
+ || sizeofBlock == sizeof(RAW_BUFFER) )
+ {
+ if (f->reservePhysBlockCount > 0)
+ {
+ block = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = f->reservePhysBlockChain->link;
+ --f->reservePhysBlockCount;
+ }
+ }
+ if (block != NULL)
+ code = 1; /* successful, but allocated from reserve */
+ }
+ if (block != NULL)
+ f->total_space += sizeofBlock;
+ else
+ code = gs_note_error(gs_error_VMerror);
+ *return_code = code;
+ return block;
+}
+
+
+/* ---------------- Open/close/unlink ---------------- */
+
+int
+memfile_fopen(char *fname, const char *fmode, clist_file_ptr /*MEMFILE **/ *pf,
+ gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
+{
+ MEMFILE *f = 0;
+ int code = 0;
+
+ /* We don't implement reopening an existing file. */
+ if ( fname[0] != 0 || fmode[0] != 'w' )
+ {
+ code = gs_note_error(gs_error_invalidfileaccess);
+ goto finish;
+ }
+ /* There is no need to set fname in this implementation, */
+ /* but we do it anyway. */
+ fname[0] = (ok_to_compress ? 'a' : 'b');
+ fname[1] = 0;
+
+ f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
+ "memfile_open_scratch(MEMFILE)");
+ if ( f == NULL ) {
+ eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ f->memory = mem;
+ f->data_memory = data_mem;
+
+ /* init an empty file, BEFORE allocating de/compress state */
+ f->compress_state = 0; /* make clean for GC, or alloc'n failure */
+ f->decompress_state = 0;
+ f->total_space = 0;
+ f->reservePhysBlockChain = NULL;
+ f->reservePhysBlockCount = 0;
+ f->reserveLogBlockChain = NULL;
+ f->reserveLogBlockCount = 0;
+
+ if( ( code = memfile_init_empty(f) ) < 0 )
+ goto finish;
+ if( ( code = memfile_set_block_size(f, 0) ) < 0 )
+ goto finish;
+
+ /*
+ * Disregard the ok_to_compress flag, since the size threshold gives us
+ * a much better criterion for deciding when compression is appropriate.
+ */
+ f->ok_to_compress = /*ok_to_compress*/ true;
+ if ( f->ok_to_compress ) {
+ const stream_state *compress_proto = clist_compressor_state(NULL);
+ const stream_state *decompress_proto = clist_decompressor_state(NULL);
+ const stream_template *compress_template = compress_proto->template;
+ const stream_template *decompress_template = decompress_proto->template;
+ f->compress_state =
+ gs_alloc_struct(mem, stream_state, compress_template->stype,
+ "memfile_open_scratch(compress_state)");
+ f->decompress_state =
+ gs_alloc_struct(mem, stream_state, decompress_template->stype,
+ "memfile_open_scratch(decompress_state)");
+ if ( f->compress_state == 0 || f->decompress_state == 0 ) {
+ eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ memcpy(f->compress_state, compress_proto,
+ gs_struct_type_size(compress_template->stype));
+ f->compress_state->memory = mem;
+ memcpy(f->decompress_state, decompress_proto,
+ gs_struct_type_size(decompress_template->stype));
+ f->decompress_state->memory = mem;
+ if ( compress_template->set_defaults )
+ (*compress_template->set_defaults)(f->compress_state);
+ if ( decompress_template->set_defaults )
+ (*decompress_template->set_defaults)(f->decompress_state);
+ }
+
+#ifdef DEBUG
+ /* If this is the start, init some statistics. */
+ /* Hack: we know the 'a' file is opened first. */
+ if( *fname == 'a' ) {
+ tot_compressed = 0;
+ tot_raw = 0;
+ tot_cache_miss = 0;
+ tot_cache_hits = 0;
+ tot_swap_out = 0;
+ }
+#endif
+finish:
+ if (code != 0)
+ {
+ /* return failure, clean up memory before leaving */
+ if (f != NULL)
+ memfile_fclose( (clist_file_ptr)f, NULL, 1 );
+ return_error(code);
+ }
+ else
+ {
+ /* return success */
+ *pf = f;
+ return 0;
+ }
+}
+
+int
+memfile_fclose(clist_file_ptr cf, const char *fname, bool delete)
+{
+ MEMFILE *f = (MEMFILE *)cf;
+
+ /* We don't implement closing without deletion. */
+ if ( !delete )
+ return_error(gs_error_invalidfileaccess);
+
+ memfile_free_mem(f);
+
+ /* Free reserve blocks; don't do it in memfile_free_mem because */
+ /* that routine gets called to reinit file */
+ while (f->reserveLogBlockChain != NULL)
+ {
+ LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ }
+ while (f->reservePhysBlockChain != NULL)
+ {
+ PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ }
+
+ /* deallocate de/compress state */
+ gs_free_object(f->memory, f->decompress_state,
+ "memfile_close_and_unlink(decompress_state)");
+ gs_free_object(f->memory, f->compress_state,
+ "memfile_close_and_unlink(compress_state)");
+
+ /* deallocate the memfile object proper */
+ gs_free_object(f->memory, f, "memfile_close_and_unlink(MEMFILE)");
+ return 0;
+}
+
+int
+memfile_unlink(const char *fname)
+{
+ /*
+ * Since we have no way to represent a memfile other than by the
+ * pointer, we don't (can't) implement unlinking.
+ */
+ return_error(gs_error_invalidfileaccess);
+}
+
+/* ---------------- Writing ---------------- */
+
+/* Pre-alloc enough reserve mem blox to guarantee a write of N bytes will succeed */
+int /* returns 0 ok, gs_error_VMerror if insufficient */
+memfile_set_block_size( clist_file_ptr cf, int sizeofMaxBlock )
+{
+ MEMFILE *f = (MEMFILE *)cf;
+ int code = 0;
+
+ /* Determine req'd memory block count from sizeofMaxBlock */
+ /* Allocate enough phys & log blocks to hold sizeofMaxBlock */
+ /* + 1 phys blk for compress_log_blk + 1 phys blk for decompress. */
+ int logNeeded = (sizeofMaxBlock + MEMFILE_DATA_SIZE - 1) / MEMFILE_DATA_SIZE;
+ int physNeeded = logNeeded;
+ if (sizeofMaxBlock > 0)
+ ++physNeeded;
+ if (f->raw_head == NULL)
+ ++physNeeded; /* have yet to allocate read buffers */
+
+ /* Allocate or free memory depending on need */
+ while (logNeeded > f->reserveLogBlockCount)
+ {
+ LOG_MEMFILE_BLK *block
+ = MALLOC( f, sizeof(LOG_MEMFILE_BLK), "memfile_set_block_size" );
+ if (block == NULL)
+ { code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ block->link = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = block;
+ ++f->reserveLogBlockCount;
+ }
+ while (logNeeded < f->reserveLogBlockCount)
+ {
+ LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ --f->reserveLogBlockCount;
+ }
+ while (physNeeded > f->reservePhysBlockCount)
+ {
+ PHYS_MEMFILE_BLK *block = MALLOC( f,
+ max( sizeof(PHYS_MEMFILE_BLK), sizeof(RAW_BUFFER) ),
+ "memfile_set_block_size" );
+ if (block == NULL)
+ { code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ block->link = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = block;
+ ++f->reservePhysBlockCount;
+ }
+ while (physNeeded < f->reservePhysBlockCount)
+ {
+ PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ --f->reservePhysBlockCount;
+ }
+ f->error_code = 0; /* memfile_set_block_size is how user resets this */
+finish:
+ return code;
+}
+
+private int /* ret 0 ok, -ve error, or +ve low-memory warning */
+compress_log_blk( MEMFILE *f, LOG_MEMFILE_BLK *bp )
+{
+ int status;
+ int ecode = 0;
+ int code;
+ long compressed_size;
+ byte *start_ptr;
+ PHYS_MEMFILE_BLK *newphys;
+
+ /* compress this block */
+ f->rd.ptr = (const byte *)(bp->phys_blk->data) - 1;
+ f->rd.limit = f->rd.ptr + MEMFILE_DATA_SIZE;
+
+ bp->phys_blk = f->phys_curr;
+ bp->phys_pdata = (char *)(f->wt.ptr) + 1;
+ if ( f->compress_state->template->reinit != 0 )
+ (*f->compress_state->template->reinit)(f->compress_state);
+ compressed_size = 0;
+
+ start_ptr = f->wt.ptr;
+ status = (*f->compress_state->template->process)(f->compress_state,
+ &(f->rd), &(f->wt), true );
+ bp->phys_blk->data_limit = (char *)(f->wt.ptr);
+
+ if( status == 1 ) { /* More output space needed (see strimpl.h) */
+ /* allocate another physical block, then compress remainder */
+ compressed_size = f->wt.limit - start_ptr;
+ newphys
+ = (PHYS_MEMFILE_BLK *)allocateWithReserve(f, sizeof(*newphys), &code,
+ "memfile newphys", "compress_log_blk : MALLOC for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate any low-memory warnings */
+ newphys->link = NULL;
+ bp->phys_blk->link = newphys;
+ f->phys_curr = newphys;
+ f->wt.ptr = (byte *)(newphys->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+
+ start_ptr = f->wt.ptr;
+ status = (*f->compress_state->template->process)(f->compress_state,
+ &(f->rd), &(f->wt), true );
+ if( status != 0 ) {
+ /* You'd think the above line is a bug, but in real life 1 src block */
+ /* never ends up getting split across 3 dest blocks */
+ /* CHANGE memfile_set_block_size if this assumption changes. */
+ eprintf("Compression required more than one full block!\n");
+ return_error(gs_error_Fatal);
+ }
+ newphys->data_limit = (char *)(f->wt.ptr);
+ }
+
+ compressed_size += f->wt.ptr - start_ptr;
+ if( compressed_size > MEMFILE_DATA_SIZE ) {
+ eprintf2("\nCompression didn't - raw=%d, compressed=%ld\n",
+ MEMFILE_DATA_SIZE, compressed_size);
+ }
+#ifdef DEBUG
+ tot_compressed += compressed_size;
+#endif
+ return(status < 0 ? status : ecode);
+} /* end "compress_log_blk()" */
+
+/* Internal (private) routine to handle end of logical block */
+private int /* ret 0 ok, -ve error, or +ve low-memory warning */
+memfile_next_blk( MEMFILE *f )
+{
+ LOG_MEMFILE_BLK *bp = f->log_curr_blk;
+ LOG_MEMFILE_BLK *newbp;
+ PHYS_MEMFILE_BLK *newphys, *oldphys;
+ int ecode = 0;
+ int code;
+
+ if( f->phys_curr == NULL ) { /* means NOT compressing */
+ /* allocate a new block */
+ newphys
+ = (PHYS_MEMFILE_BLK *)allocateWithReserve(f, sizeof(*newphys), &code,
+ "memfile newphys", "memfile_next_blk: MALLOC 1 for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate low-mem warnings */
+ newphys->link = NULL;
+ newphys->data_limit = NULL; /* raw */
+
+ newbp
+ = (LOG_MEMFILE_BLK *)allocateWithReserve(f, sizeof(*newbp), &code, "memfile newbp",
+ "memfile_next_blk: MALLOC 1 for 'newbp' failed\n");
+ if (code < 0)
+ {
+ FREE(f, newphys, "memfile newphys");
+ return code;
+ }
+ ecode |= code; /* accumulate low-mem warnings */
+ bp->link = newbp;
+ newbp->link = NULL;
+ newbp->raw_block = NULL;
+ f->log_curr_blk = newbp;
+
+ /* check if need to start compressing */
+ if ( NEED_TO_COMPRESS(f) ) {
+
+#ifdef DEBUG
+ eprintf("Beginning compression\n");
+#endif
+ /* compress the entire file up to this point */
+ if ( !f->compressor_initialized ) {
+ int code = 0;
+ if ( f->compress_state->template->init != 0 )
+ code = (*f->compress_state->template->init)(f->compress_state);
+ if ( code < 0 )
+ return_error(gs_error_VMerror); /****** BOGUS ******/
+ if ( f->decompress_state->template->init != 0 )
+ code = (*f->decompress_state->template->init)
+ (f->decompress_state);
+ if ( code < 0 )
+ return_error(gs_error_VMerror); /****** BOGUS ******/
+ f->compressor_initialized = true;
+ }
+
+ /* Write into the new physical block we just allocated, */
+ /* replace it after the loop (after some blocks are freed) */
+ f->phys_curr = newphys;
+ f->wt.ptr = (byte *)(newphys->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+ bp = f->log_head;
+ while( bp != newbp ) { /* don't compress last block */
+ int code;
+ oldphys = bp->phys_blk;
+ if( (code = compress_log_blk(f,bp)) < 0 )
+ return_error( code );
+ ecode |= code;
+ FREE(f, oldphys, "memfile_next_blk(oldphys)");
+ bp = bp->link;
+ } /* end while( ) compress loop */
+ /* Allocate a physical block for this (last) logical block */
+ newphys
+ = (PHYS_MEMFILE_BLK *)allocateWithReserve(f, sizeof(*newphys), &code,
+ "memfile newphys",
+ "memfile_next_blk: MALLOC 2 for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate low-mem warnings */
+ newphys->link = NULL;
+ newphys->data_limit = NULL; /* raw */
+
+ } /* end convert file to compressed */
+
+ newbp->phys_blk = newphys;
+ f->pdata = newphys->data;
+ f->pdata_end = newphys->data + MEMFILE_DATA_SIZE;
+ } /* end if NOT compressing */
+
+ /* File IS being compressed */
+ else {
+ int code;
+ oldphys = bp->phys_blk; /* save raw phys block ID */
+ /* compresses bp on phys list */
+ if( (code = compress_log_blk(f,bp)) < 0 )
+ return_error( code );
+ ecode |= code;
+ newbp = (LOG_MEMFILE_BLK *)allocateWithReserve(f, sizeof(*newbp), &code,
+ "memfile newbp",
+ "memfile_next_blk: MALLOC 2 for 'newbp' failed\n");
+ if (code < 0)
+ return code;
+ bp->link = newbp;
+ newbp->link = NULL;
+ newbp->raw_block = NULL;
+ /* Re-use the raw phys block for this new logical blk */
+ newbp->phys_blk = oldphys;
+ f->pdata = oldphys->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ f->log_curr_blk = newbp;
+ } /* end else (when we are compressing) */
+
+ return(ecode);
+}
+
+int /* returns # of chars actually written */
+memfile_fwrite_chars(const void *data, uint len, clist_file_ptr cf)
+{
+ const char *str = (const char *)data;
+ MEMFILE *f = (MEMFILE *)cf;
+ uint count = len;
+ int ecode;
+
+ /* check if we are writing to the start of the file. If so, then */
+ /* free the file memory and re-initialize it (frees memory) */
+ if( f->log_curr_pos == 0 ) {
+ int code;
+ memfile_free_mem( f );
+ if ( ( code = memfile_init_empty(f) ) < 0 ) {
+ f->error_code = gs_note_error(code);
+ return 0;
+ }
+ }
+
+ if( f->log_curr_blk->link != 0 ) {
+ eprintf(" Write file truncate -- need to free physical blocks.\n");
+ }
+
+ while( count ) {
+ uint move_count = f->pdata_end - f->pdata;
+ if ( move_count == 0 ) {
+ if( ( ecode = memfile_next_blk(f) ) != 0 ) {
+ f->error_code = gs_note_error(ecode);
+ if (ecode < 0)
+ return 0;
+ }
+ } else {
+ if ( move_count > count )
+ move_count = count;
+ memmove(f->pdata, str, move_count);
+ f->pdata += move_count;
+ str += move_count;
+ count -= move_count;
+ }
+ }
+ f->log_curr_pos += len;
+ f->log_length = f->log_curr_pos; /* truncate length to here */
+#ifdef DEBUG
+ tot_raw += len;
+#endif
+ return(len);
+}
+
+/* */
+/* Internal routine to set the f->pdata and f->pdata_end pointers */
+/* for the current logical block f->log_curr_blk */
+/* */
+/* If data only exists in compressed form, allocate a raw buffer */
+/* and decompress it. */
+/* */
+
+private int
+memfile_get_pdata( MEMFILE *f )
+{
+ int i, num_raw_buffers, status;
+ LOG_MEMFILE_BLK *bp = f->log_curr_blk;
+
+ if( bp->phys_blk->data_limit == NULL ) {
+ /* Not compressed, return this data pointer */
+ f->pdata = (bp->phys_blk)->data;
+ i = f->log_curr_pos % MEMFILE_DATA_SIZE; /* pos within block */
+ i = f->log_curr_pos - i; /* base of block */
+ if( i+MEMFILE_DATA_SIZE > f->log_length )
+ f->pdata_end = f->pdata + f->log_length - i;
+ else
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ }
+ else {
+ /* data was compressed */
+ if( f->raw_head == NULL ) {
+ /* need to allocate the raw buffer pool */
+ num_raw_buffers = GET_NUM_RAW_BUFFERS( f );
+ if (f->reservePhysBlockCount) {
+ /* hack: allocate reserve block that's been reserved for decompress */
+ /* This buffer's was pre-allocated to make sure we won't come up */
+ /* short here. Take from chain instead of allocateWithReserve() */
+ /* since this buf would just be wasted if allowed to remain preallocated */
+ f->raw_head = (RAW_BUFFER *)f->reservePhysBlockChain;
+ f->reservePhysBlockChain = f->reservePhysBlockChain->link;
+ --f->reservePhysBlockCount;
+ }
+ else {
+ int code;
+ f->raw_head = (RAW_BUFFER *)allocateWithReserve
+ (f, sizeof(*f->raw_head), &code, "memfile raw buffer",
+ "memfile_get_pdata: MALLOC for 'raw_head' failed\n");
+ if (code < 0)
+ return code;
+ }
+ f->raw_head->back = NULL;
+ f->raw_tail = f->raw_head;
+ f->raw_tail->log_blk = NULL;
+ for( i=0; i<num_raw_buffers; i++ ) {
+ f->raw_tail->fwd = (RAW_BUFFER *) MALLOC(f, sizeof(RAW_BUFFER),
+ "memfile raw buffer");
+ /* if MALLOC fails, then just stop allocating */
+ if( ! f->raw_tail->fwd ) break;
+ f->total_space += sizeof(RAW_BUFFER);
+ f->raw_tail->fwd->back = f->raw_tail;
+ f->raw_tail = f->raw_tail->fwd;
+ f->raw_tail->log_blk = NULL;
+ }
+ f->raw_tail->fwd = NULL;
+ num_raw_buffers = i+1; /* if MALLOC failed, then OK */
+#ifdef DEBUG
+ eprintf1("\nNumber of raw buffers allocated=%d\n", num_raw_buffers );
+#endif
+ } /* end allocating the raw buffer pool (first time only) */
+
+ if( bp->raw_block == NULL ) {
+#ifdef DEBUG
+ tot_cache_miss++; /* count every decompress */
+#endif
+ /* find a raw buffer and decompress */
+ if( f->raw_tail->log_blk != NULL ) {
+ /* This block was in use, grab it */
+#ifdef DEBUG
+ tot_swap_out++;
+#endif
+ f->raw_tail->log_blk->raw_block = NULL; /* data no longer here */
+ f->raw_tail->log_blk = NULL;
+ }
+ /* Use the last raw block in the chain (the oldest) */
+ f->raw_tail->back->fwd = NULL; /* disconnect from tail */
+ f->raw_tail->fwd = f->raw_head; /* new head */
+ f->raw_head->back = f->raw_tail;
+ f->raw_tail = f->raw_tail->back;
+ f->raw_head = f->raw_head->back;
+ f->raw_head->back = NULL;
+ f->raw_head->log_blk = bp;
+
+ /* Decompress the data into this raw block */
+ /* Initialize the decompressor */
+ if ( f->decompress_state->template->reinit != 0 )
+ (*f->decompress_state->template->reinit)(f->decompress_state);
+ /* Set pointers and call the decompress routine */
+ f->wt.ptr = (byte *)(f->raw_head->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+ f->rd.ptr = (const byte *)(bp->phys_pdata) - 1;
+ f->rd.limit = (const byte *)bp->phys_blk->data_limit;
+#ifdef DEBUG
+ decomp_wt_ptr0 = f->wt.ptr;
+ decomp_wt_limit0 = f->wt.limit;
+ decomp_rd_ptr0 = f->rd.ptr;
+ decomp_rd_limit0 = f->rd.limit;
+#endif
+ status = (*f->decompress_state->template->process)
+ (f->decompress_state, &(f->rd), &(f->wt), true );
+ if( status == 0 ) { /* More input data needed */
+ /* switch to next block and continue decompress */
+ int back_up = 0; /* adjust pointer backwards */
+ if( f->rd.ptr != f->rd.limit ) {
+ /* transfer remainder bytes from the previous block */
+ back_up = f->rd.limit - f->rd.ptr;
+ for( i=0; i<back_up; i++ )
+ *(bp->phys_blk->link->data - back_up + i) = *++f->rd.ptr;
+ }
+ f->rd.ptr = (const byte *)bp->phys_blk->link->data - back_up - 1;
+ f->rd.limit = (const byte *)bp->phys_blk->link->data_limit;
+#ifdef DEBUG
+ decomp_wt_ptr1 = f->wt.ptr;
+ decomp_wt_limit1 = f->wt.limit;
+ decomp_rd_ptr1 = f->rd.ptr;
+ decomp_rd_limit1 = f->rd.limit;
+#endif
+ status = (*f->decompress_state->template->process)
+ (f->decompress_state, &(f->rd), &(f->wt), true );
+ if( status == 0 ) {
+ eprintf("Decompression required more than one full block!\n");
+ return_error(gs_error_Fatal);
+ }
+ }
+ bp->raw_block = f->raw_head; /* point to raw block */
+ } /* end if( raw_block == NULL ) meaning need to decompress data */
+ else {
+ /* data exists in the raw data cache, if not raw_head, move it */
+ if( bp->raw_block != f->raw_head ) {
+ /* move to raw_head */
+ /* prev.fwd = this.fwd */
+ bp->raw_block->back->fwd = bp->raw_block->fwd;
+ if( bp->raw_block->fwd != NULL )
+ /* next.back = this.back */
+ bp->raw_block->fwd->back = bp->raw_block->back;
+ else
+ f->raw_tail = bp->raw_block->back; /* tail = prev */
+ f->raw_head->back = bp->raw_block; /* head.back = this */
+ bp->raw_block->fwd = f->raw_head; /* this.fwd = orig head */
+ f->raw_head = bp->raw_block; /* head = this */
+ f->raw_head->back = NULL; /* this.back = NULL */
+#ifdef DEBUG
+ tot_cache_hits++; /* counting here prevents repeats since */
+ /* won't count if already at head */
+#endif
+ }
+ }
+ f->pdata = bp->raw_block->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ /* NOTE: last block is never compressed, so a compressed block */
+ /* is always full size. */
+ } /* end else (when data was compressed) */
+
+ return(0);
+}
+
+/* ---------------- Reading ---------------- */
+
+int
+memfile_fread_chars(void *data, uint len, clist_file_ptr cf)
+{
+ char *str = (char *)data;
+ MEMFILE *f = (MEMFILE *)cf;
+ uint count = len, num_read, move_count;
+
+ num_read = f->log_length - f->log_curr_pos;
+ if( count > num_read )
+ count = num_read;
+ num_read = count;
+
+ while( count ) {
+ f->log_curr_pos++; /* move into next byte */
+ if( f->pdata == f->pdata_end ) {
+ f->log_curr_blk = (f->log_curr_blk)->link;
+ memfile_get_pdata( f );
+ }
+ move_count = f->pdata_end - f->pdata;
+ if ( move_count > count )
+ move_count = count;
+ f->log_curr_pos += move_count - 1; /* new position */
+ memmove(str, f->pdata, move_count);
+ str += move_count;
+ f->pdata += move_count;
+ count -= move_count;
+ }
+
+ return( num_read );
+}
+
+/* ---------------- Position/status ---------------- */
+
+int
+memfile_ferror_code(clist_file_ptr cf)
+{
+ return( ((MEMFILE *)cf)->error_code ); /* errors stored here */
+}
+
+long
+memfile_ftell(clist_file_ptr cf)
+{
+ return( ((MEMFILE *)cf)->log_curr_pos );
+}
+
+void
+memfile_rewind(clist_file_ptr cf, bool discard_data, const char *ignore_fname)
+{
+ MEMFILE *f = (MEMFILE *)cf;
+
+ if ( discard_data ) {
+ memfile_free_mem(f);
+ /* We have to call memfile_init_empty to preserve invariants. */
+ memfile_init_empty(f);
+ } else {
+ f->log_curr_blk = f->log_head;
+ f->log_curr_pos = 0;
+ memfile_get_pdata( f );
+ }
+}
+
+int
+memfile_fseek(clist_file_ptr cf, long offset, int mode, const char *ignore_fname)
+{
+ MEMFILE *f = (MEMFILE *)cf;
+ long i, block_num, new_pos;
+
+ switch( mode ) {
+ case SEEK_SET: /* offset from the beginning of the file */
+ new_pos = offset;
+ break;
+
+ case SEEK_CUR: /* offset from the current position in the file */
+ new_pos = offset + f->log_curr_pos;
+ break;
+
+ case SEEK_END: /* offset back from the end of the file */
+ new_pos = f->log_length - offset;
+ break;
+
+ default:
+ return (-1);
+ }
+ if ( new_pos < 0 || new_pos > f->log_length )
+ return -1;
+ if( (f->pdata == f->pdata_end) && (f->log_curr_blk->link != NULL) ) {
+ /* log_curr_blk is actually one block behind log_curr_pos */
+ f->log_curr_blk = f->log_curr_blk->link;
+ }
+ block_num = new_pos / MEMFILE_DATA_SIZE;
+ i = f->log_curr_pos / MEMFILE_DATA_SIZE;
+ if ( block_num < i ) /* if moving backwards, start at beginning */
+ { f->log_curr_blk = f->log_head;
+ i = 0;
+ }
+ for ( ; i < block_num; i++ )
+ { f->log_curr_blk = f->log_curr_blk->link;
+ }
+ f->log_curr_pos = new_pos;
+ memfile_get_pdata( f ); /* pointers to start of block */
+ f->pdata += new_pos - (block_num * MEMFILE_DATA_SIZE);
+
+ return 0; /* return "normal" status */
+}
+
+/* ---------------- Internal routines ---------------- */
+
+private void
+memfile_free_mem( MEMFILE *f )
+{
+ LOG_MEMFILE_BLK *bp, *tmpbp;
+
+#ifdef DEBUG
+ /* output some diagnostics about the effectiveness */
+ if( tot_raw > 100 ) {
+ eprintf2("\n\ttot_raw=%ld, tot_compressed=%ld\n",
+ tot_raw, tot_compressed );
+ }
+
+ if( tot_cache_hits != 0 ) {
+ eprintf3("\n\tCache hits=%ld, cache misses=%ld, swapouts=%ld\n",
+ tot_cache_hits,
+ tot_cache_miss - (f->log_length/MEMFILE_DATA_SIZE), tot_swap_out);
+ }
+ tot_raw = 0;
+ tot_compressed = 0;
+ tot_cache_hits = 0;
+ tot_cache_miss = 0;
+ tot_swap_out = 0;
+#endif
+
+ /* Free up memory that was allocated for the memfile */
+ bp = f->log_head;
+
+/******************************************************************
+ * The following was the original algorithm here. This algorithm has a bug:
+ * the second loop references the physical blocks again after they have been
+ * freed.
+ ******************************************************************/
+
+#if 0 /**************** ****************/
+
+ if ( bp != NULL ) {
+ /* Free the physical blocks that make up the compressed data */
+ PHYS_MEMFILE_BLK *pphys = (f->log_head)->phys_blk;
+ if( pphys->data_limit != NULL ) {
+ /* the data was compressed, free the chain of blocks */
+ while( pphys != NULL ) {
+ PHYS_MEMFILE_BLK *tmpphys = pphys->link;
+
+ FREE(f, pphys, "memfile_free_mem(pphys)");
+ pphys = tmpphys;
+ }
+ }
+ }
+
+ /* free the logical blocks */
+ while( bp != NULL ) {
+ /* if this logical block was not compressed, free the phys_blk */
+ if( bp->phys_blk->data_limit == NULL ) {
+ FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+
+#else /**************** ****************/
+# if 1 /**************** ****************/
+
+/****************************************************************
+ * This algorithm is correct (we think).
+ ****************************************************************/
+
+ if ( bp != NULL ) {
+ /* Null out phys_blk pointers to compressed data. */
+ PHYS_MEMFILE_BLK *pphys = bp->phys_blk;
+ { for ( tmpbp = bp; tmpbp != NULL; tmpbp = tmpbp->link )
+ if ( tmpbp->phys_blk->data_limit != NULL )
+ tmpbp->phys_blk = 0;
+ }
+ /* Free the physical blocks that make up the compressed data */
+ if( pphys->data_limit != NULL ) {
+ /* the data was compressed, free the chain of blocks */
+ while( pphys != NULL ) {
+ PHYS_MEMFILE_BLK *tmpphys = pphys->link;
+
+ FREE(f, pphys, "memfile_free_mem(pphys)");
+ pphys = tmpphys;
+ }
+ }
+ }
+
+ /* Now free the logical blocks, and any uncompressed physical blocks. */
+ while( bp != NULL ) {
+ if( bp->phys_blk != NULL ) {
+ FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+
+/***********************************************************************
+ * This algorithm appears to be both simpler and free of the bug that
+ * occasionally causes the older one to reference freed blocks; but in
+ * fact it can miss blocks, because the very last compressed logical block
+ * can have spill into a second physical block, which is not referenced by
+ * any logical block.
+ ***********************************************************************/
+
+# else /**************** ****************/
+
+ { PHYS_MEMFILE_BLK *prev_phys = 0;
+
+ while ( bp != NULL ) {
+ PHYS_MEMFILE_BLK *phys = bp->phys_blk;
+ if ( phys != prev_phys ) {
+ FREE(f, phys, "memfile_free_mem(phys_blk)");
+ prev_phys = phys;
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+ }
+
+# endif /**************** ****************/
+#endif /**************** ****************/
+
+ f->log_head = NULL;
+
+ /* Free any internal compressor state. */
+ if ( f->compressor_initialized ) {
+ if ( f->decompress_state->template->release != 0 )
+ (*f->decompress_state->template->release)(f->decompress_state);
+ if ( f->compress_state->template->release != 0 )
+ (*f->compress_state->template->release)(f->compress_state);
+ f->compressor_initialized = false;
+ }
+
+ /* free the raw buffers */
+ while( f->raw_head != NULL ) {
+ RAW_BUFFER *tmpraw = f->raw_head->fwd;
+
+ FREE(f, f->raw_head, "memfile_free_mem(raw)");
+ f->raw_head = tmpraw;
+ }
+}
+
+private int
+memfile_init_empty( MEMFILE *f )
+{
+ PHYS_MEMFILE_BLK *pphys;
+ LOG_MEMFILE_BLK *plog;
+
+ /* Zero out key fields so that allocation failure will be unwindable */
+ f->phys_curr = NULL; /* flag as file not compressed */
+ f->log_head = NULL;
+ f->log_curr_blk = NULL;
+ f->log_curr_pos = 0;
+ f->log_length = 0;
+ f->raw_head = NULL;
+ f->compressor_initialized = false;
+ f->total_space = 0;
+
+ /* File empty - get a physical mem block (includes the buffer area) */
+ pphys = (PHYS_MEMFILE_BLK *)MALLOC( f, sizeof(*pphys), "memfile_init_empty" );
+ if (pphys == NULL)
+ {
+ eprintf("memfile_init_empty: MALLOC for 'pphys' failed\n");
+ return_error(gs_error_VMerror);
+ }
+ f->total_space += sizeof(*pphys);
+ pphys->data_limit = NULL; /* raw data for now */
+
+ /* Get logical mem block to go with physical one */
+ plog = (LOG_MEMFILE_BLK *)MALLOC( f, sizeof(*plog), "memfile_init_empty" );
+ if (plog == NULL)
+ {
+ FREE(f, pphys, "memfile_init_empty");
+ f->total_space = 0;
+ eprintf("memfile_init_empty: MALLOC for log_curr_blk failed\n");
+ return_error (gs_error_VMerror);
+ }
+ f->total_space += sizeof(*plog);
+ f->log_curr_blk = plog;
+ f->log_head = f->log_curr_blk;
+ f->log_curr_blk->link = NULL;
+ f->log_curr_blk->phys_blk = pphys;
+ f->log_curr_blk->phys_pdata = NULL;
+ f->log_curr_blk->raw_block = NULL;
+
+ f->pdata = pphys->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+
+ f->error_code = 0;
+
+ return 0;
+}
diff --git a/gs/src/gxclmem.h b/gs/src/gxclmem.h
new file mode 100644
index 000000000..3171f644a
--- /dev/null
+++ b/gs/src/gxclmem.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclmem.h */
+/* Definitions and declarations for clist implementation in memory. */
+#include "gxclio.h" /* defines interface */
+#include "strimpl.h" /* stream structures */
+
+/*
+ * The best values of MEMFILE_DATA_SIZE are slightly less than a power of 2,
+ * to allow typical malloc implementations to allocate in units of a power
+ * of 2 rather than having to go slightly over.
+ */
+#define MEMFILE_DATA_SIZE (16384 - 160)
+
+ /* ============================================================ */
+ /* */
+ /* Memfile structure definitions. */
+ /* */
+ /* The PHYS structures are the elements actually allocated in */
+ /* RAM, containing the compressed data (or optionally raw data) */
+ /* */
+ /* There can be several LOG (logical) elements per physical */
+ /* element, depending on the compression. The MEMFILE pdata */
+ /* item always points into a raw block of data. */
+ /* */
+ /* ============================================================ */
+
+ typedef struct RAW_BUFFER {
+ struct RAW_BUFFER *fwd, *back;
+ struct LOG_MEMFILE_BLK *log_blk;
+ char data[MEMFILE_DATA_SIZE];
+ } RAW_BUFFER ;
+
+ typedef struct PHYS_MEMFILE_BLK {
+ struct PHYS_MEMFILE_BLK *link;
+ char *data_limit; /* end of data when compressed */
+ /* NULL if not compressed */
+ char data_spare[4]; /* used during de-compress */
+ char data[MEMFILE_DATA_SIZE];
+ } PHYS_MEMFILE_BLK ;
+
+ typedef struct LOG_MEMFILE_BLK {
+ struct LOG_MEMFILE_BLK *link;
+ PHYS_MEMFILE_BLK *phys_blk;
+ char *phys_pdata;
+ RAW_BUFFER *raw_block; /* or NULL */
+ } LOG_MEMFILE_BLK ;
+
+ typedef struct MEMFILE {
+ gs_memory_t *memory; /* storage allocator */
+ gs_memory_t *data_memory; /* storage allocator for data */
+ bool ok_to_compress; /* if true, OK to compress this file */
+ /* Reserve memory blocks: these are used to guarantee that a */
+ /* given-sized write (or sequence of writes) will always succeed. */
+ /* More specifically, the guarantee is that N bytes can successfully */
+ /* be written after a low-memory warning is first returned by fwrite. */
+ /* The reserve of N bytes for a given file is (re)allocated by a */
+ /* successful call to memfile_set_block_size(N).
+ /* Fwrite allocates memory only from the reserve when its normal */
+ /* allocation attempts fail; in such cases, it allocates blocks from */
+ /* the reserve pool as needed and completes normally, but returns */
+ /* a low-memory warning status. Once a low-memory warning has been */
+ /* returned, fwrite will continue to attempt to allocate memory from */
+ /* the usual allocator on subsequent fwrites, but does *not* try to */
+ /* "top up" the reserve if becomes available -- only an explicit */
+ /* memfile_set_block_size does so. */
+ PHYS_MEMFILE_BLK *reservePhysBlockChain; /* chain of reserve phys blks */
+ int reservePhysBlockCount; /* count of entries on reservePhysBlockChain */
+ LOG_MEMFILE_BLK *reserveLogBlockChain; /* chain of reserve log blks */
+ int reserveLogBlockCount; /* count of entries on reserveLogBlockChain */
+ /* logical file properties */
+ LOG_MEMFILE_BLK *log_head;
+ LOG_MEMFILE_BLK *log_curr_blk;
+ long log_length; /* updated during write */
+ long log_curr_pos; /* updated during seek, close, read */
+ char *pdata; /* raw data */
+ char *pdata_end;
+ /* physical file properties */
+ long total_space; /* so we know when to start compress */
+ PHYS_MEMFILE_BLK *phys_curr; /* NULL if not compressing */
+ RAW_BUFFER *raw_head, *raw_tail;
+ int error_code; /* used by CLIST_ferror */
+ stream_cursor_read rd; /* use .ptr, .limit */
+ stream_cursor_write wt; /* use .ptr, .limit */
+ bool compressor_initialized;
+ stream_state *compress_state;
+ stream_state *decompress_state;
+ } MEMFILE ;
+
+/*
+ Only MEMFILE & stream_state structures are GC-compatible, so allocate all
+ other structures on the C heap.
+*/
+#define private_st_MEMFILE() /* in gxclmem.c */\
+ gs_private_st_ptrs2(st_MEMFILE, MEMFILE, "MEMFILE",\
+ MEMFILE_enum_ptrs, MEMFILE_reloc_ptrs, compress_state, decompress_state)
+
+/* Make the memfile_... operations aliases for the clist_... operations. */
+
+#define memfile_fopen(fname, fmode, pcf, mem, data_mem, compress)\
+ clist_fopen(fname, fmode, pcf, mem, data_mem, compress)
+#define memfile_fclose(cf, fname, delete)\
+ clist_fclose(cf, fname, delete)
+#define memfile_unlink(fname)\
+ clist_unlink(fname)
+#define memfile_set_block_size(cf, size)\
+ clist_set_block_size(cf, size)
+
+#define memfile_space_available(req)\
+ clist_space_available(req)
+#define memfile_fwrite_chars(data, len, cf)\
+ clist_fwrite_chars(data, len, cf)
+
+#define memfile_fread_chars(data, len, cf)\
+ clist_fread_chars(data, len, cf)
+
+#define memfile_ferror_code(cf) clist_ferror_code(cf)
+#define memfile_ftell(cf) clist_ftell(cf)
+#define memfile_rewind(cf, discard, fname) clist_rewind(cf, discard, fname)
+#define memfile_fseek(cf, offset, mode, fname) clist_fseek(cf, offset, mode, fname)
+
+/* Declare the procedures for returning the prototype filter states */
+/* for compressing and decompressing the band list. */
+const stream_state *clist_compressor_state(P1(void *));
+const stream_state *clist_decompressor_state(P1(void *));
diff --git a/gs/src/gxclpage.c b/gs/src/gxclpage.c
new file mode 100644
index 000000000..b01d30e61
--- /dev/null
+++ b/gs/src/gxclpage.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclpage.c */
+/* Page object management */
+#include "gdevprn.h"
+#include "gxcldev.h"
+#include "gxclpage.h"
+
+/* Save a page. */
+int
+gdev_prn_save_page(gx_device_printer *pdev, gx_saved_page *page,
+ int num_copies)
+{ int code;
+
+ /* Make sure we are banding. */
+ if ( !pdev->buffer_space )
+ return_error(gs_error_rangecheck);
+ if ( strlen(pdev->dname) >= sizeof(page->dname) )
+ return_error(gs_error_limitcheck);
+#define pcldev ((gx_device_clist_writer *)pdev)
+ if ( (code = clist_end_page(pcldev)) < 0 ||
+ (code = clist_fclose(pcldev->page_cfile, pcldev->page_cfname, false)) < 0 ||
+ (code = clist_fclose(pcldev->page_bfile, pcldev->page_bfname, false)) < 0
+ )
+ return code;
+ /* Save the device information. */
+ memcpy(&page->device, pdev, sizeof(gx_device));
+ strcpy(page->dname, pdev->dname);
+ /* Save the page information. */
+ page->info = pcldev->page_info;
+ page->info.cfile = 0;
+ page->info.bfile = 0;
+#undef pcldev
+ /* Save other information. */
+ page->num_copies = num_copies;
+ return (*gs_clist_device_procs.open_device)((gx_device *)pdev);
+}
+
+/* Render an array of saved pages. */
+int
+gdev_prn_render_pages(gx_device_printer *pdev,
+ const gx_placed_page *ppages, int count)
+{
+#define pcldev ((gx_device_clist_reader *)pdev)
+
+ /* Check to make sure the pages are compatible with the device. */
+ { int i;
+ gx_band_params params;
+
+ for ( i = 0; i < count; ++i )
+ { const gx_saved_page *page = ppages[i].page;
+ /* We would like to fully check the color representation, */
+ /* but we don't have enough information to do that. */
+ if ( strcmp(page->dname, pdev->dname) != 0 ||
+ memcmp(&page->device.color_info, &pdev->color_info,
+ sizeof(pdev->color_info)) != 0
+ )
+ return_error(gs_error_rangecheck);
+ /* Currently we don't allow translation in Y. */
+ if ( ppages[i].offset.y != 0 )
+ return_error(gs_error_rangecheck);
+ /* Make sure the band parameters are compatible. */
+ if ( page->info.band_params.BandBufferSpace !=
+ pdev->buffer_space ||
+ page->info.band_params.BandWidth !=
+ pdev->width
+ )
+ return_error(gs_error_rangecheck);
+ /* Currently we require all band heights to be the same. */
+ if ( i == 0 )
+ params = page->info.band_params;
+ else if ( page->info.band_params.BandHeight !=
+ params.BandHeight
+ )
+ return_error(gs_error_rangecheck);
+ }
+ }
+ /* Set up the page list in the device. */
+ /****** SHOULD FACTOR THIS OUT OF clist_render_init ******/
+ pcldev->ymin = pcldev->ymax = 0;
+ pcldev->pages = ppages;
+ pcldev->num_pages = count;
+#undef pcldev
+ /* Render the pages. */
+ { int code = (*dev_proc(pdev, output_page))
+ ((gx_device *)pdev, ppages[0].page->num_copies, true);
+ /* Delete the temporary files. */
+ int i;
+
+ for ( i = 0; i < count; ++i )
+ { const gx_saved_page *page = ppages[i].page;
+ clist_unlink(page->info.cfname);
+ clist_unlink(page->info.bfname);
+ }
+ return code;
+ }
+}
diff --git a/gs/src/gxclpage.h b/gs/src/gxclpage.h
new file mode 100644
index 000000000..82ad064c1
--- /dev/null
+++ b/gs/src/gxclpage.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclpage.h */
+/* Command list page object definitions */
+/* Requires gdevprn.h, gxclist.h */
+
+#include "gxclio.h"
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Package up the current page in a banding device as a page object.
+ * The client must provide storage for the page object.
+ * The client may retain the object in memory, or may write it on a file
+ * for later retrieval; in the latter case, the client should free the
+ * in-memory structure.
+ */
+int gdev_prn_save_page(P3(gx_device_printer *pdev, gx_saved_page *page,
+ int num_copies));
+
+/*
+ * Render an array of saved pages by setting up a modified get_bits
+ * procedure and then calling the device's normal output_page procedure.
+ * Any current page in the device's buffers is lost.
+ * The (0,0) point of each saved page is translated to the corresponding
+ * specified offset on the combined page. (Currently the Y offset must be 0.)
+ * The client is responsible for freeing the saved and placed pages.
+ *
+ * Note that the device instance for rendering need not be, and normally is
+ * not, the same as the device from which the pages were saved, but it must
+ * be an instance of the same device. The client is responsible for
+ * ensuring that the rendering device's buffer size (BufferSpace value) is
+ * the same as the BandBufferSpace value of all the saved pages, and that
+ * the device width is the same as the BandWidth value of the saved pages.
+ */
+int gdev_prn_render_pages(P3(gx_device_printer *pdev,
+ const gx_placed_page *ppages, int count));
diff --git a/gs/src/gxclpath.c b/gs/src/gxclpath.c
new file mode 100644
index 000000000..3bb581efe
--- /dev/null
+++ b/gs/src/gxclpath.c
@@ -0,0 +1,1230 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclpath.c */
+/* Higher-level path operations for band lists */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gxcolor2.h"
+#include "gxpaint.h" /* for gx_fill/stroke_params */
+#include "gzpath.h"
+#include "gzcpath.h"
+
+#define cdev cwdev
+
+/* Statistics */
+#ifdef DEBUG
+ulong cmd_diffs[5];
+#endif
+
+/* Forward declarations */
+private int cmd_put_path(P8(gx_device_clist_writer *cldev,
+ gx_clist_state *pcls, const gx_path *ppath, fixed ymin, fixed ymax, byte op,
+ bool implicit_close, segment_notes keep_notes));
+/* Driver procedures */
+private dev_proc_fill_path(clist_fill_path);
+private dev_proc_stroke_path(clist_stroke_path);
+
+/* ------ Define the extensions to the command set ------ */
+
+#ifdef DEBUG
+private const char *cmd_misc2_op_names[16] = { cmd_misc2_op_name_strings };
+private const char *cmd_segment_op_names[16] = { cmd_segment_op_name_strings };
+private const char *cmd_path_op_names[16] = { cmd_path_op_name_strings };
+#endif
+
+/* Initialize the extensions to the command name table. */
+void
+gs_clpath_init(gs_memory_t *mem)
+{
+#ifdef DEBUG
+ cmd_op_names[cmd_op_misc2 >> 4] = "(misc2)";
+ cmd_sub_op_names[cmd_op_misc2 >> 4] = cmd_misc2_op_names;
+ cmd_op_names[cmd_op_segment >> 4] = "(segment)";
+ cmd_sub_op_names[cmd_op_segment >> 4] = cmd_segment_op_names;
+ cmd_op_names[cmd_op_path >> 4] = "(path)";
+ cmd_sub_op_names[cmd_op_path >> 4] = cmd_path_op_names;
+#endif
+ gs_clist_device_procs.fill_path = clist_fill_path;
+ gs_clist_device_procs.stroke_path = clist_stroke_path;
+ cmd_opvar_disable_clip = cmd_opv_disable_clip;
+ cmd_opvar_enable_clip = cmd_opv_enable_clip;
+}
+
+/* ------ Utilities ------ */
+
+/* Write out the color for filling, stroking, or masking. */
+/* We should be able to share this with clist_tile_rectangle, */
+/* but I don't see how to do it without adding a level of procedure. */
+int
+cmd_put_drawing_color(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_drawing_color *pdcolor)
+{ const gx_strip_bitmap *tile;
+ gx_color_index color0, color1;
+ ulong offset_temp;
+
+ if ( gx_dc_is_pure(pdcolor) )
+ { gx_color_index color1 = gx_dc_pure_color(pdcolor);
+ if ( color1 != pcls->colors[1] )
+ { int code = cmd_set_color1(cldev, pcls, color1);
+ if ( code < 0 )
+ return code;
+ }
+#ifdef FUTURE
+ return cmd_dc_type_pure;
+#else
+ return 0;
+#endif
+ }
+#ifdef FUTURE
+ /* Any non-pure color will require the phase. */
+ { int px = pdcolor->phase.x, py = pdcolor->phase.y;
+ if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
+ { int code = cmd_set_tile_phase(cldev, pcls, px, py);
+ if ( code < 0 )
+ return code;
+ }
+ }
+#endif
+ if ( gx_dc_is_binary_halftone(pdcolor) )
+ { tile = gx_dc_binary_tile(pdcolor);
+ color0 = gx_dc_binary_color0(pdcolor);
+ color1 = gx_dc_binary_color1(pdcolor);
+ /* Set up tile and colors as for clist_tile_rectangle. */
+ if ( !cls_has_tile_id(cldev, pcls, tile->id, offset_temp) )
+ { int depth =
+ (color1 == gx_no_color_index &&
+ color0 == gx_no_color_index ?
+ cldev->color_info.depth : 1);
+ if ( tile->id == gx_no_bitmap_id ||
+ clist_change_tile(cldev, pcls, tile, depth) < 0
+ )
+ return_error(-1); /* can't cache tile */
+ }
+ if ( color1 != pcls->tile_colors[1] ||
+ color0 != pcls->tile_colors[0]
+ )
+ { int code = cmd_set_tile_colors(cldev, pcls, color0, color1);
+ if ( code < 0 )
+ return code;
+ }
+#ifdef FUTURE
+ return cmd_dc_type_ht;
+#endif
+ }
+#ifdef FUTURE
+ else if ( gx_dc_is_colored_halftone(pdcolor) )
+ { const gx_device_halftone *pdht = pdcolor->colors.colored.c_ht;
+ int num_comp = pdht->num_comp;
+ byte buf[4 + 4 * cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))];
+ byte *bp = buf;
+ int i;
+ uint short_bases = 0;
+ ulong bases = 0;
+ byte *dp;
+ int code;
+
+ /****** HOW TO TELL IF COLOR IS ALREADY SET? ******/
+ if ( pdht->id != cldev->device_halftone_id )
+ { int code = cmd_put_halftone(cldev, pdht, pdht->type);
+ if ( code < 0 )
+ return code;
+ cldev->device_halftone_id = pdht->id;
+ }
+ for ( i = 0; i < num_comp; ++i )
+ { uint base = pdcolor->colors.colored.c_base[i];
+ if ( base > 31 )
+ return_error(gs_error_rangecheck);
+ bases |= base << ((3 - i) * 5);
+ short_bases |= base << (3 - i);
+ }
+ if ( bases & 0xf7bde )
+ { /* Some base value requires more than 1 bit. */
+ *bp++ = 0x10 + (byte)(bases >> 16);
+ *bp++ = (byte)(bases >> 8);
+ *bp++ = (byte)bases;
+ }
+ else
+ { /* The bases all fit in 1 bit each. */
+ *bp++ = 0x00 + (byte)short_bases;
+ }
+ for ( i = 0; i < num_comp; ++i )
+ bp = cmd_put_w((uint)pdcolor->colors.colored.c_level[i], bp);
+ /****** IGNORE alpha ******/
+ code =
+ set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color, bp - buf + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, buf, bp - buf);
+ return cmd_dc_type_color;
+ }
+#endif
+ else
+ return_error(-1);
+#ifndef FUTURE
+ { int px = pdcolor->phase.x, py = pdcolor->phase.y;
+ if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
+ { int code = cmd_set_tile_phase(cldev, pcls, px, py);
+ if ( code < 0 )
+ return code;
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Clear (a) specific 'known' flag(s) for all bands. */
+/* We must do this whenever the value of a 'known' parameter changes. */
+void
+cmd_clear_known(gx_device_clist_writer *cldev, uint known)
+{ ushort unknown = ~known;
+ gx_clist_state *pcls = cldev->states;
+ int i;
+
+ for ( i = cldev->nbands; --i >= 0; ++pcls )
+ pcls->known &= unknown;
+}
+
+/* Check whether we need to change the clipping path in the device. */
+bool
+cmd_check_clip_path(gx_device_clist_writer *cldev, const gx_clip_path *pcpath)
+{ if ( pcpath == NULL )
+ return false;
+ /* The clip path might have moved in memory, so even if the */
+ /* ids match, update the pointer. */
+ cldev->clip_path = pcpath;
+ if ( pcpath->id == cldev->clip_path_id )
+ return false;
+ cldev->clip_path_id = pcpath->id;
+ return true;
+}
+
+/* Construct the parameters for writing out a matrix. */
+/* We need a buffer of at least 1 + 6 * sizeof(float) bytes. */
+byte *
+cmd_for_matrix(byte *cbuf, const gs_matrix *pmat)
+{ byte *cp = cbuf + 1;
+ byte b = 0;
+ float coeffs[6];
+ int i;
+
+ coeffs[0] = pmat->xx;
+ coeffs[1] = pmat->xy;
+ coeffs[2] = pmat->yx;
+ coeffs[3] = pmat->yy;
+ coeffs[4] = pmat->tx;
+ coeffs[5] = pmat->ty;
+ for ( i = 0; i < 4; i += 2 )
+ { float u = coeffs[i], v = coeffs[i^3];
+ b <<= 2;
+ if ( u != 0 || v != 0 )
+ { memcpy(cp, &u, sizeof(float));
+ cp += sizeof(float);
+ if ( v == u )
+ b += 1;
+ else if ( v == -u )
+ b += 2;
+ else
+ { b += 3;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ }
+ for ( ; i < 6; ++i )
+ { float v = coeffs[i];
+ b <<= 1;
+ if ( v != 0 )
+ { ++b;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ cbuf[0] = b << 2;
+ return cp;
+}
+
+/* Write out values of any unknown parameters. */
+int
+cmd_write_unknown(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ uint must_know)
+{ int code;
+ ushort unknown = ~pcls->known & must_know;
+
+ if ( unknown & flatness_known )
+ { byte *dp;
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_flatness,
+ 1 + sizeof(float));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.flatness, sizeof(float));
+ pcls->known |= flatness_known;
+ }
+ if ( unknown & fill_adjust_known )
+ { byte *dp;
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_fill_adjust,
+ 1 + sizeof(fixed) * 2);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.fill_adjust.x, sizeof(fixed));
+ memcpy(dp + 1 + sizeof(fixed), &cldev->imager_state.fill_adjust.y, sizeof(fixed));
+ pcls->known |= fill_adjust_known;
+ }
+ if ( unknown & ctm_known )
+ { byte cbuf[1 + 6 * sizeof(float)];
+ uint len =
+ cmd_for_matrix(cbuf,
+ (const gs_matrix *)&cldev->imager_state.ctm) -
+ cbuf;
+ byte *dp;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_ctm, len + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, cbuf, len);
+ pcls->known |= ctm_known;
+ }
+ if ( unknown & line_width_known )
+ { byte *dp;
+ float width =
+ gx_current_line_width(&cldev->imager_state.line_params);
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_line_width,
+ 1 + sizeof(width));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &width, sizeof(width));
+ pcls->known |= line_width_known;
+ }
+ if ( unknown & miter_limit_known )
+ { byte *dp;
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_miter_limit,
+ 1 + sizeof(float));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.line_params.miter_limit, sizeof(float));
+ pcls->known |= miter_limit_known;
+ }
+ if ( unknown & misc0_known )
+ { byte *dp;
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_cap_join +
+ (cldev->imager_state.line_params.cap << 3) +
+ cldev->imager_state.line_params.join;
+ pcls->known |= misc0_known;
+ }
+ if ( unknown & misc1_known )
+ { byte *dp;
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_ac_op_sa +
+ (cldev->imager_state.accurate_curves ? 4 : 0) +
+ (cldev->imager_state.overprint ? 2 : 0) +
+ (cldev->imager_state.stroke_adjust ? 1 : 0);
+ pcls->known |= misc1_known;
+ }
+ if ( unknown & dash_known )
+ { byte *dp;
+ int n = cldev->imager_state.line_params.dash.pattern_size;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_dash,
+ 2 + (n + 2) * sizeof(float));
+ if (code < 0)
+ return code;
+ dp[1] = n + (cldev->imager_state.line_params.dash.adapt ? 0x80 : 0) +
+ (cldev->imager_state.line_params.dot_length_absolute ? 0x40 : 0);
+ memcpy(dp + 2, &cldev->imager_state.line_params.dot_length,
+ sizeof(float));
+ memcpy(dp + 2 + sizeof(float),
+ &cldev->imager_state.line_params.dash.offset,
+ sizeof(float));
+ if ( n != 0 )
+ memcpy(dp + 2 + sizeof(float) * 2,
+ cldev->imager_state.line_params.dash.pattern,
+ n * sizeof(float));
+ pcls->known |= dash_known;
+ }
+ if ( unknown & clip_path_known )
+ { /* We can write out the clipping path either as rectangles */
+ /* or as a real (filled) path. */
+ const gx_clip_path *pcpath = cldev->clip_path;
+ int band_height = cldev->page_band_height;
+ int ymin = (pcls - cldev->states) * band_height;
+ int ymax = min(ymin + band_height, cldev->height);
+ gs_fixed_rect box;
+ int punt_to_outer_box = 0;
+ byte *dp;
+ int code;
+ int end_code;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_begin_clip, 1);
+ if (code < 0)
+ return code;
+ if (pcpath->segments_valid)
+ {
+ if ( gx_path_is_rectangle(&pcpath->path, &box) &&
+ fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)
+ )
+ { /* Write the path as a rectangle. */
+ code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ fixed2int_var(box.p.x),
+ fixed2int_var(box.p.y),
+ fixed2int(box.q.x - box.p.x),
+ fixed2int(box.q.y - box.p.y));
+ }
+ else if ( !(cldev->disable_mask & clist_disable_complex_clip) )
+ { /* Write the path. */
+ code = cmd_put_path(cldev, pcls, &pcpath->path,
+ int2fixed(ymin - 1),
+ int2fixed(ymax + 1),
+ (pcpath->rule == gx_rule_even_odd ?
+ cmd_opv_eofill : cmd_opv_fill),
+ true, sn_not_first);
+ }
+ else
+ /* Complex paths disabled: write outer box as clip */
+ punt_to_outer_box = 1;
+ }
+ else
+ { /* Write out the rectangles. */
+ const gx_clip_rect *prect = pcpath->list.head;
+
+ if ( prect == 0 )
+ prect = &pcpath->list.single;
+ else if (cldev->disable_mask & clist_disable_complex_clip)
+ punt_to_outer_box = 1;
+ if (!punt_to_outer_box)
+ for ( ; prect != 0 && code >= 0; prect = prect->next )
+ if ( prect->xmax > prect->xmin &&
+ prect->ymin < ymax && prect->ymax > ymin
+ )
+ { code =
+ cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ prect->xmin, prect->ymin,
+ prect->xmax - prect->xmin,
+ prect->ymax - prect->ymin);
+ }
+ }
+ if (punt_to_outer_box)
+ { /* Clip is complex, but disabled. Write out the outer box */
+ gs_fixed_rect box;
+ gx_cpath_outer_box(pcpath, &box);
+ box.p.x = fixed_floor(box.p.x);
+ box.p.y = fixed_floor(box.p.y);
+ code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ fixed2int_var(box.p.x),
+ fixed2int_var(box.p.y),
+ fixed2int_ceiling(box.q.x - box.p.x),
+ fixed2int_ceiling(box.q.y - box.p.y));
+ }
+ end_code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 2);
+ if (code >= 0)
+ code = end_code; /* take the first failure seen */
+ if (end_code < 0 && cldev->error_is_retryable)
+ { /* end_clip has to work despite lo-mem to maintain consistency. */
+ /* This isn't error recovery, but just to prevent dangling */
+ /* cmd_opv_begin_clip's */
+ ++cldev->ignore_lo_mem_warnings;
+ end_code
+ = set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 2);
+ --cldev->ignore_lo_mem_warnings;
+ }
+ if (end_code >= 0)
+ dp[1] = (gx_cpath_is_outside(pcpath) ? 1 : 0);
+ if (code < 0)
+ return code;
+ pcls->clip_enabled = 1;
+ pcls->known |= clip_path_known;
+ }
+ if ( unknown & color_space_known )
+ { byte *dp;
+
+ if ( cldev->color_space & 8 ) /* indexed */
+ { uint num_values = (cldev->indexed_params.hival + 1) *
+ gs_color_space_num_components(
+ (const gs_color_space *)&cldev->indexed_params.base_space);
+ bool use_proc = cldev->color_space & 4;
+ const void *map_data;
+ uint map_size;
+
+ if ( use_proc )
+ { map_data = cldev->indexed_params.lookup.map->values;
+ map_size = num_values *
+ sizeof(cldev->indexed_params.lookup.map->values[0]);
+ }
+ else
+ { map_data = cldev->indexed_params.lookup.table.data;
+ map_size = num_values;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space,
+ 2 + cmd_sizew(cldev->indexed_params.hival) + map_size);
+ if (code < 0)
+ return code;
+ memcpy(cmd_put_w(cldev->indexed_params.hival, dp + 2),
+ map_data, map_size);
+ }
+ else
+ { code =
+ set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space, 2);
+ if (code < 0)
+ return code;
+ }
+ dp[1] = cldev->color_space;
+ pcls->known |= color_space_known;
+ }
+ return 0;
+}
+
+/* ------ Driver procedures ------ */
+
+private int
+clist_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
+ const gx_fill_params *params, const gx_drawing_color *pdcolor,
+ const gx_clip_path *pcpath)
+{ uint unknown = 0;
+ int y, height, y0, y1;
+ gs_logical_operation_t lop = pis->log_op;
+ byte op = (byte)
+ (params->rule == gx_rule_even_odd ?
+#ifdef FUTURE
+ cmd_opv_eofill : cmd_opv_fill
+#else
+ (gx_dc_is_pure(pdcolor) ? cmd_opv_eofill : cmd_opv_hteofill) :
+ (gx_dc_is_pure(pdcolor) ? cmd_opv_fill : cmd_opv_htfill)
+#endif
+ );
+ gs_fixed_point adjust;
+
+ if ( (cdev->disable_mask & clist_disable_fill_path)
+ || gs_debug_c(',') /* disable path-based banding */
+ )
+ return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ adjust = params->adjust;
+ { gs_fixed_rect bbox;
+ gx_path_bbox(ppath, &bbox);
+ y = fixed2int(bbox.p.y) - 1;
+ height = fixed2int_ceiling(bbox.q.y) - y + 1;
+ fit_fill_yh(dev, y, height);
+ if ( height <= 0 )
+ return 0;
+ }
+ y0 = y;
+ y1 = y + height;
+ if ( cdev->imager_state.flatness != params->flatness )
+ { unknown |= flatness_known;
+ cdev->imager_state.flatness = params->flatness;
+ }
+ if ( cdev->imager_state.fill_adjust.x != adjust.x ||
+ cdev->imager_state.fill_adjust.y != adjust.y
+ )
+ { unknown |= fill_adjust_known;
+ cdev->imager_state.fill_adjust = adjust;
+ }
+ if ( cmd_check_clip_path(cdev, pcpath) )
+ unknown |= clip_path_known;
+ if ( unknown )
+ cmd_clear_known(cdev, unknown);
+ BEGIN_RECT
+
+ int code = cmd_do_write_unknown(cdev, pcls,
+ flatness_known | fill_adjust_known |
+ clip_path_known);
+ if (code < 0)
+ return code;
+ if ( ( code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL) ) < 0 )
+ return code;
+ if ( lop == lop_default )
+ { if ( ( code = cmd_disable_lop(cdev, pcls) ) < 0 )
+ return code;
+ }
+ else
+ { if ( lop != pcls->lop )
+ { code = cmd_set_lop(cdev, pcls, lop);
+ if ( code < 0 )
+ return code;
+ }
+ if ( ( code = cmd_enable_lop(cdev, pcls) ) < 0 )
+ return code;
+ }
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ if ( code < 0 )
+ { /* Something went wrong, use the default implementation. */
+ return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ code = cmd_put_path(cdev, pcls, ppath,
+ int2fixed(max(y - 1, y0)),
+ int2fixed(min(y + height + 1, y1)),
+#ifdef FUTURE
+ op + code, /* cmd_dc_type */
+#else
+ op,
+#endif
+ true, sn_none /* fill doesn't need the notes */);
+ if ( code < 0 )
+ return code;
+ END_RECT
+ return 0;
+}
+
+private int
+clist_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
+ const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ int pattern_size = pis->line_params.dash.pattern_size;
+ uint unknown = 0;
+ gs_fixed_rect bbox;
+ gs_fixed_point expansion;
+ int adjust_y;
+ int y, height, y0, y1;
+ gs_logical_operation_t lop = pis->log_op;
+#ifndef FUTURE
+ byte op = (byte)
+ (gx_dc_is_pure(pdcolor) ? cmd_opv_stroke : cmd_opv_htstroke);
+#endif
+
+ if ( (cdev->disable_mask & clist_disable_stroke_path)
+ || gs_debug_c(',') /* disable path-based banding */
+ )
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ gx_path_bbox(ppath, &bbox);
+ /* We must use the supplied imager state, not our saved one, */
+ /* for computing the stroke expansion. */
+ if ( gx_stroke_path_expansion(pis, ppath, &expansion) < 0 )
+ { /* Expansion is too large: use the entire page. */
+ adjust_y = 0;
+ y = 0;
+ height = dev->height;
+ }
+ else
+ { adjust_y = fixed2int_ceiling(expansion.y) + 1;
+ y = fixed2int(bbox.p.y) - adjust_y;
+ height = fixed2int_ceiling(bbox.q.y) - y + adjust_y;
+ fit_fill_yh(dev, y, height);
+ if ( height <= 0 )
+ return 0;
+ }
+ y0 = y;
+ y1 = y + height;
+ /* Check the dash pattern, since we bail out if */
+ /* the pattern is too large. */
+ cdev->imager_state.line_params.dash.pattern = cdev->dash_pattern;
+ if ( cdev->imager_state.line_params.dash.pattern_size != pattern_size ||
+ (pattern_size != 0 &&
+ memcmp(cdev->imager_state.line_params.dash.pattern,
+ pis->line_params.dash.pattern,
+ pattern_size * sizeof(float))) ||
+ cdev->imager_state.line_params.dash.offset !=
+ pis->line_params.dash.offset ||
+ cdev->imager_state.line_params.dash.adapt !=
+ pis->line_params.dash.adapt ||
+ cdev->imager_state.line_params.dot_length !=
+ pis->line_params.dot_length ||
+ cdev->imager_state.line_params.dot_length_absolute !=
+ pis->line_params.dot_length_absolute
+ )
+ { /* Bail out if the dash pattern is too long. */
+ if ( pattern_size > cmd_max_dash )
+ return gx_default_stroke_path(dev, pis, ppath, params,
+ pdcolor, pcpath);
+ unknown |= dash_known;
+ gx_set_dash(&cdev->imager_state.line_params.dash,
+ pis->line_params.dash.pattern,
+ pis->line_params.dash.pattern_size,
+ pis->line_params.dash.offset, NULL);
+ gx_set_dash_adapt(&cdev->imager_state.line_params.dash,
+ pis->line_params.dash.adapt);
+ gx_set_dot_length(&cdev->imager_state.line_params,
+ pis->line_params.dot_length,
+ pis->line_params.dot_length_absolute);
+ }
+ if ( state_neq(flatness) )
+ { unknown |= flatness_known;
+ state_update(flatness);
+ }
+ if ( state_neq(fill_adjust.x) || state_neq(fill_adjust.y) )
+ { unknown |= fill_adjust_known;
+ state_update(fill_adjust);
+ }
+ if ( state_neq(ctm.xx) || state_neq(ctm.xy) ||
+ state_neq(ctm.yx) || state_neq(ctm.yy) ||
+ /* We don't actually need tx or ty, but we don't want to bother */
+ /* tracking them separately from the other coefficients. */
+ state_neq(ctm.tx) || state_neq(ctm.ty)
+ )
+ { unknown |= ctm_known;
+ state_update(ctm);
+ }
+ if ( state_neq(line_params.half_width) )
+ { unknown |= line_width_known;
+ state_update(line_params.half_width);
+ }
+ if ( state_neq(line_params.miter_limit) )
+ { unknown |= miter_limit_known;
+ gx_set_miter_limit(&cdev->imager_state.line_params,
+ pis->line_params.miter_limit);
+ }
+ if ( state_neq(line_params.cap) || state_neq(line_params.join) )
+ { unknown |= misc0_known;
+ state_update(line_params.cap);
+ state_update(line_params.join);
+ }
+ if ( state_neq(accurate_curves) || state_neq(overprint) ||
+ state_neq(stroke_adjust)
+ )
+ { unknown |= misc1_known;
+ state_update(accurate_curves);
+ state_update(overprint);
+ state_update(stroke_adjust);
+ }
+ if ( cmd_check_clip_path(cdev, pcpath) )
+ unknown |= clip_path_known;
+ if ( unknown )
+ cmd_clear_known(cdev, unknown);
+ BEGIN_RECT
+
+ int code = cmd_do_write_unknown(cdev, pcls, stroke_all_known);
+ if (code < 0)
+ return code;
+ if ( ( code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL) ) < 0 )
+ return code;
+ if ( lop == lop_default )
+ { if ( ( code = cmd_disable_lop(cdev, pcls) ) < 0 )
+ return code;
+ }
+ else
+ { if ( lop != pcls->lop )
+ { code = cmd_set_lop(cdev, pcls, lop);
+ if ( code < 0 )
+ return code;
+ }
+ if ( ( code = cmd_enable_lop(cdev, pcls) ) < 0 )
+ return code;
+ }
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ if ( code < 0 )
+ { /* Something went wrong, use the default implementation. */
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ { fixed ymin, ymax;
+ /* If a dash pattern is active, we can't skip segments */
+ /* outside the clipping region, because that would throw off */
+ /* the pattern. */
+ if ( pattern_size == 0 )
+ ymin = int2fixed(max(y - adjust_y, y0)),
+ ymax = int2fixed(min(y + height + adjust_y, y1));
+ else
+ ymin = min_fixed,
+ ymax = max_fixed;
+ code = cmd_put_path(cdev, pcls, ppath, ymin, ymax,
+#ifdef FUTURE
+ cmd_opv_stroke + code, /* cmd_dc_type */
+#else
+ op,
+#endif
+ false, (segment_notes)~0);
+ if ( code < 0 )
+ return code;
+ }
+ END_RECT
+ return 0;
+}
+
+/* ------ Path utilities ------ */
+
+/* Define the state bookkeeping for writing path segments. */
+typedef struct cmd_segment_writer_s {
+ /* Set at initialization */
+ gx_device_clist_writer *cldev;
+ gx_clist_state *pcls;
+ /* Updated dynamically */
+ segment_notes notes;
+ byte *dp;
+ int len;
+ gs_fixed_point delta_first;
+ byte cmd[6 * (1 + sizeof(fixed))];
+} cmd_segment_writer;
+
+/* Put out a path segment command. */
+private int near
+cmd_put_segment(cmd_segment_writer _ss *psw, byte op,
+ const fixed _ss *operands, segment_notes notes)
+{ const fixed _ss *optr = operands;
+ /* Fetch num_operands before possible command merging. */
+ int i = clist_segment_op_num_operands[op & 0xf];
+ byte *q = psw->cmd - 1;
+
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { int j;
+ dprintf2("[L] %s:%d:", cmd_segment_op_names[op & 0xf],
+ (int)notes);
+ for ( j = 0; j < i; ++j )
+ dprintf1(" %g", fixed2float(operands[j]));
+ dputs("\n");
+ }
+#endif
+
+ /* Merge or shorten commands if possible. */
+ if ( op == cmd_opv_rlineto )
+ { if ( operands[0] == 0 )
+ op = cmd_opv_vlineto, optr = ++operands, i = 1;
+ else if ( operands[1] == 0 )
+ op = cmd_opv_hlineto, i = 1;
+ else
+ switch ( *psw->dp )
+ {
+ case cmd_opv_rmoveto:
+ psw->delta_first.x = operands[0];
+ psw->delta_first.y = operands[1];
+ op = cmd_opv_rmlineto;
+merge: cmd_uncount_op(*psw->dp, psw->len);
+ cmd_shorten_op(psw->cldev, psw->pcls, psw->len); /* delete it */
+ q += psw->len - 1;
+ break;
+ case cmd_opv_rmlineto:
+ if ( notes != psw->notes )
+ break;
+ op = cmd_opv_rm2lineto;
+ goto merge;
+ case cmd_opv_rm2lineto:
+ if ( notes != psw->notes )
+ break;
+ if ( operands[0] == -psw->delta_first.x &&
+ operands[1] == -psw->delta_first.y
+ )
+ { cmd_uncount_op(cmd_opv_rm2lineto, psw->len);
+ *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len);
+ return 0;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ for ( ; --i >= 0; ++optr )
+ { fixed d = *optr, d2;
+ if ( is_bits(d, _fixed_shift + 11) &&
+ !(d & (float2fixed(0.25) - 1))
+ )
+ { cmd_count_add1(cmd_diffs[3]);
+ d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000;
+ q += 2;
+ }
+ else if ( is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19) )
+ { cmd_count_add1(cmd_diffs[0]);
+ q[1] = (byte)((d >> 13) & 0x3f);
+ q[2] = (byte)(d >> 5);
+ q[3] = (byte)((d << 3) + ((d2 >> 16) & 7));
+ q[4] = (byte)(d2 >> 8);
+ q[5] = (byte)d2;
+ q += 5;
+ --i, ++optr;
+ continue;
+ }
+ else if ( is_bits(d, 22) )
+ { cmd_count_add1(cmd_diffs[1]);
+ q[1] = (byte)(((d >> 16) & 0x3f) + 0x40);
+ q += 3;
+ }
+ else if ( is_bits(d, 30) )
+ { cmd_count_add1(cmd_diffs[2]);
+ q[1] = (byte)(((d >> 24) & 0x3f) + 0x80);
+ q[2] = (byte)(d >> 16);
+ q += 4;
+ }
+ else
+ { int b;
+ cmd_count_add1(cmd_diffs[4]);
+ *++q = 0xe0;
+ for ( b = sizeof(fixed) - 1; b > 1; --b )
+ *++q = (byte)(d >> (b * 8));
+ q += 2;
+ }
+ q[-1] = (byte)(d >> 8);
+ *q = (byte)d;
+ }
+ if ( notes != psw->notes )
+ { byte *dp;
+
+ int code =
+ set_cmd_put_op(dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_notes + notes;
+ psw->notes = notes;
+ }
+ { int len = q + 2 - psw->cmd;
+ byte *dp;
+
+ int code =
+ set_cmd_put_op(dp, psw->cldev, psw->pcls, op, len);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, psw->cmd, len - 1);
+ psw->len = len;
+ psw->dp = dp;
+ }
+ return 0;
+}
+/* Put out a line segment command. */
+#define cmd_put_rmoveto(psw, operands)\
+ cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none)
+#define cmd_put_rlineto(psw, operands, notes)\
+ cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
+
+/*
+ * Write a path. We go to a lot of trouble to omit segments that are
+ * entirely outside the band.
+ */
+private int
+cmd_put_path(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ const gx_path *ppath, fixed ymin, fixed ymax, byte path_op,
+ bool implicit_close, segment_notes keep_notes)
+{ gs_path_enum cenum;
+ cmd_segment_writer writer;
+ static byte initial_op = { cmd_opv_end_run };
+ /*
+ * We define the 'side' of a point according to its Y value as
+ * follows:
+ */
+#define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0)
+
+ /*
+ * While writing a subpath, we need to keep track of any segments
+ * skipped at the beginning of the subpath and any segments skipped
+ * just before the current segment. We do this with two sets of
+ * state variables, one that tracks the actual path segments and one
+ * that tracks the emitted segments.
+ *
+ * The following track the actual segments:
+ */
+
+ /*
+ * The point and side of the last moveto (skipped if
+ * start_side != 0):
+ */
+ gs_fixed_point start;
+ int start_side;
+ /*
+ * Whether any lines or curves were skipped immediately
+ * following the moveto:
+ */
+ bool start_skip;
+ /* The side of the last point: */
+ int side;
+ /* The last point with side != 0: */
+ gs_fixed_point out;
+ /* If the last out-going segment was a lineto, */
+ /* its notes: */
+ segment_notes out_notes;
+
+ /*
+ * The following track the emitted segments:
+ */
+
+ /* The last point emitted: */
+ fixed px = int2fixed(pcls->rect.x);
+ fixed py = int2fixed(pcls->rect.y);
+ /* The point of the last emitted moveto: */
+ gs_fixed_point first;
+ /* Information about the last emitted operation: */
+ int open = 0; /* -1 if last was moveto, 1 if line/curveto, */
+ /* 0 if newpath/closepath */
+
+
+ if_debug4('p', "[p]initial (%g,%g), clip [%g..%g)\n",
+ fixed2float(px), fixed2float(py),
+ fixed2float(ymin), fixed2float(ymax));
+ gx_path_enum_init(&cenum, ppath);
+ writer.cldev = cldev;
+ writer.pcls = pcls;
+ writer.notes = sn_none;
+#define set_first_point() (writer.dp = &initial_op)
+#define first_point() (writer.dp == &initial_op)
+ set_first_point();
+ for ( ; ; )
+ { fixed vs[6];
+#define A vs[0]
+#define B vs[1]
+#define C vs[2]
+#define D vs[3]
+#define E vs[4]
+#define F vs[5]
+ int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
+ byte *dp;
+ int code;
+
+ switch ( pe_op )
+ {
+ case 0:
+ /* If the path is open and needs an implicit close, */
+ /* do the close and then come here again. */
+ if ( open > 0 && implicit_close )
+ goto close;
+ /* All done. */
+ pcls->rect.x = fixed2int_var(px);
+ pcls->rect.y = fixed2int_var(py);
+ if_debug2('p', "[p]final (%d,%d)\n",
+ pcls->rect.x, pcls->rect.y);
+ return set_cmd_put_op(dp, cldev, pcls, path_op, 1);
+ case gs_pe_moveto:
+ /* If the path is open and needs an implicit close, */
+ /* do a closepath and then redo the moveto. */
+ if ( open > 0 && implicit_close )
+ { gx_path_enum_backup(&cenum);
+ goto close;
+ }
+ open = -1;
+ start.x = A, start.y = B;
+ start_skip = false;
+ if ( (start_side = side = which_side(B)) != 0 )
+ { out.x = A, out.y = B;
+ if_debug3('p', "[p]skip moveto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ C = A - px, D = B - py;
+ first.x = px = A, first.y = py = B;
+ code = cmd_put_rmoveto(&writer, &C);
+ if_debug2('p', "[p]moveto (%g,%g)\n",
+ fixed2float(px), fixed2float(py));
+ break;
+ case gs_pe_lineto:
+ { int next_side = which_side(B);
+ segment_notes notes =
+ gx_path_enum_notes(&cenum) & keep_notes;
+
+ if ( next_side == side && side != 0 )
+ { /* Skip a line completely outside the clip region. */
+ if ( open < 0 )
+ start_skip = true;
+ out.x = A, out.y = B;
+ out_notes = notes;
+ if_debug3('p', "[p]skip lineto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ /* If we skipped any segments, put out a moveto/lineto. */
+ if ( side && (px != out.x || py != out.y || first_point()) )
+ { C = out.x - px, D = out.y - py;
+ if ( open < 0 )
+ { first = out;
+ code = cmd_put_rmoveto(&writer, &C);
+ }
+ else
+ code = cmd_put_rlineto(&writer, &C, out_notes);
+ if ( code < 0 )
+ return code;
+ px = out.x, py = out.y;
+ if_debug3('p', "[p]catchup %s (%g,%g) for line\n",
+ (open < 0 ? "moveto" : "lineto"),
+ fixed2float(px), fixed2float(py));
+ }
+ if ( (side = next_side) != 0 )
+ { /* Note a vertex going outside the clip region. */
+ out.x = A, out.y = B;
+ }
+ C = A - px, D = B - py;
+ px = A, py = B;
+ open = 1;
+ code = cmd_put_rlineto(&writer, &C, notes);
+ }
+ if_debug3('p', "[p]lineto (%g,%g) side %d\n",
+ fixed2float(px), fixed2float(py), side);
+ break;
+ case gs_pe_closepath:
+#ifdef DEBUG
+ { gs_path_enum cpenum;
+ gs_fixed_point cvs[3];
+ int op;
+ cpenum = cenum;
+ switch ( op = gx_path_enum_next(&cpenum, cvs) )
+ {
+ case 0: case gs_pe_moveto:
+ break;
+ default:
+ lprintf1("closepath followed by %d, not end/moveto!\n",
+ op);
+ }
+ }
+#endif
+ /* A closepath may require drawing an explicit line if */
+ /* we skipped any segments at the beginning of the path. */
+close: if ( side != start_side )
+ { /* If we skipped any segments, put out a moveto/lineto. */
+ if ( side && (px != out.x || py != out.y || first_point()) )
+ { C = out.x - px, D = out.y - py;
+ code = cmd_put_rlineto(&writer, &C, out_notes);
+ if ( code < 0 )
+ return code;
+ px = out.x, py = out.y;
+ if_debug2('p', "[p]catchup line (%g,%g) for close\n",
+ fixed2float(px), fixed2float(py));
+ }
+ if ( open > 0 && start_skip )
+ { /* Draw the closing line back to the start. */
+ C = start.x - px, D = start.y - py;
+ code = cmd_put_rlineto(&writer, &C, sn_none);
+ if ( code < 0 )
+ return code;
+ px = start.x, py = start.y;
+ if_debug2('p', "[p]draw close to (%g,%g)\n",
+ fixed2float(px), fixed2float(py));
+ }
+ }
+ /*
+ * We don't bother to update side because we know that the
+ * next element after a closepath, if any, must be a moveto.
+ * We must handle explicitly the possibility that the entire
+ * subpath was skipped.
+ */
+ if ( implicit_close || open <= 0 )
+ { open = 0;
+ /*
+ * Force writing an explicit moveto if the next subpath
+ * starts with a moveto to the same point where this one
+ * ends.
+ */
+ set_first_point();
+ continue;
+ }
+ open = 0;
+ px = first.x, py = first.y;
+ code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none);
+ if_debug0('p', "[p]close\n");
+ break;
+ case gs_pe_curveto:
+ { segment_notes notes =
+ gx_path_enum_notes(&cenum) & keep_notes;
+ { fixed bpy, bqy;
+ int all_side, out_side;
+
+ /* Compute the Y bounds for the clipping check. */
+ if ( B < D ) bpy = B, bqy = D;
+ else bpy = D, bqy = B;
+ if ( F < bpy ) bpy = F;
+ else if ( F > bqy ) bqy = F;
+ all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0);
+ if ( all_side != 0 )
+ { if ( all_side == side )
+ { /* Skip a curve entirely outside the clip region. */
+ if ( open < 0 )
+ start_skip = true;
+ out.x = E, out.y = F;
+ out_notes = notes;
+ if_debug3('p', "[p]skip curveto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ out_side = all_side;
+ }
+ else
+ out_side = which_side(F);
+ /* If we skipped any segments, put out a moveto/lineto. */
+ if ( side && (px != out.x || py != out.y || first_point()) )
+ { fixed diff[2];
+ diff[0] = out.x - px, diff[1] = out.y - py;
+ if ( open < 0 )
+ { first = out;
+ code = cmd_put_rmoveto(&writer, diff);
+ }
+ else
+ code = cmd_put_rlineto(&writer, diff, out_notes);
+ if ( code < 0 )
+ return code;
+ px = out.x, py = out.y;
+ if_debug3('p', "[p]catchup %s (%g,%g) for curve\n",
+ (open < 0 ? "moveto" : "lineto"),
+ fixed2float(px), fixed2float(py));
+ }
+ if ( (side = out_side) != 0 )
+ { /* Note a vertex going outside the clip region. */
+ out.x = E, out.y = F;
+ }
+ }
+ { fixed nx = E, ny = F;
+ const fixed _ss *optr = vs;
+ byte op;
+
+ if_debug7('p', "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n",
+ fixed2float(A), fixed2float(B),
+ fixed2float(C), fixed2float(D),
+ fixed2float(E), fixed2float(F), side);
+ E -= C, F -= D;
+ C -= A, D -= B;
+ A -= px, B -= py;
+ if ( B == 0 && E == 0 )
+ { B = A, E = F, optr++, op = cmd_opv_hvcurveto;
+ if ( (B ^ D) >= 0 )
+ { if ( C == D && E == B )
+ op = cmd_opv_hqcurveto;
+ }
+ else if ( C == -D && E == -B )
+ C = D, op = cmd_opv_hqcurveto;
+ }
+ else if ( A == 0 && F == 0 )
+ { optr++, op = cmd_opv_vhcurveto;
+ if ( (B ^ C) >= 0 )
+ { if ( D == C && E == B )
+ op = cmd_opv_vqcurveto;
+ }
+ else if ( D == -C && E == -B )
+ op = cmd_opv_vqcurveto;
+ }
+ else if ( A == 0 && B == 0 )
+ optr += 2, op = cmd_opv_nrcurveto;
+ else if ( E == 0 && F == 0 )
+ op = cmd_opv_rncurveto;
+ else
+ op = cmd_opv_rrcurveto;
+ px = nx, py = ny;
+ open = 1;
+ code = cmd_put_segment(&writer, op, optr, notes);
+ }
+ } break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if ( code < 0 )
+ return code;
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+ }
+}
diff --git a/gs/src/gxclpath.h b/gs/src/gxclpath.h
new file mode 100644
index 000000000..e84a1baea
--- /dev/null
+++ b/gs/src/gxclpath.h
@@ -0,0 +1,201 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclpath.h */
+/* Internal definitions for higher-level command list facilities. */
+/* Extends (requires) gxcldev.h */
+#include "gxfixed.h" /* for gzpath.h */
+
+/* Define the flags indicating whether a band knows the current values of */
+/* various miscellaneous parameters (pcls->known). */
+#define flatness_known (1<<0)
+#define fill_adjust_known (1<<1)
+#define ctm_known (1<<2)
+#define line_width_known (1<<3)
+#define miter_limit_known (1<<4)
+#define misc0_known (1<<5)
+#define misc1_known (1<<6)
+#define dash_known (1<<7)
+#define clip_path_known (1<<8)
+#define stroke_all_known ((1<<9)-1)
+#define color_space_known (1<<9)
+/*#define all_known ((1<<10)-1)*/
+
+/* Define the drawing color types for distinguishing different */
+/* fill/stroke command variations. */
+typedef enum {
+ cmd_dc_type_pure = 0,
+ cmd_dc_type_ht = 1,
+ cmd_dc_type_color = 2
+} cmd_dc_type;
+
+/* Extend the command set. See gxcldev.h for more information. */
+typedef enum {
+ cmd_op_misc2 = 0xd0, /* (see below) */
+ cmd_opv_set_flatness = 0xd0, /* flatness(float) */
+ cmd_opv_set_fill_adjust = 0xd1, /* adjust_x/y(fixed) */
+ cmd_opv_set_ctm = 0xd2, /* (0=0,0, 1=V,V, 2=V,-V, 3=U,V)x */
+ /* (xx+yy,yx+xy)(0=0, 1=V)x(tx,ty), */
+ /* 0..5 x coeff(float) */
+ cmd_opv_set_line_width = 0xd3, /* width(float) */
+ cmd_opv_set_misc2 = 0xd4,
+#define cmd_set_misc2_cap_join (0 << 6) /* 00: cap(3)join(3) */
+#define cmd_set_misc2_ac_op_sa (1 << 6) /* 01: 0(3)acc.curves(1)overprint(1) */
+ /* stroke_adj(1) */
+#define cmd_set_misc2_notes (2 << 6) /* 10: seg.notes(6) */
+#define cmd_set_misc2_unused (3 << 6) /* 11: -unused- */
+ cmd_opv_set_miter_limit = 0xd5, /* miter limit(float) */
+ cmd_opv_set_dash = 0xd6, /* adapt(1)abs.dot(1)n(6), dot */
+ /* length(float), offset(float), */
+ /* n x (float) */
+ cmd_opv_enable_clip = 0xd7, /* (nothing) */
+ cmd_opv_disable_clip = 0xd8, /* (nothing) */
+ cmd_opv_begin_clip = 0xd9, /* (nothing) */
+ cmd_opv_end_clip = 0xda, /* outside? */
+ cmd_opv_set_color_space = 0xdb, /* base(4)Indexed?(2)0(3) */
+ /* [, hival#, table|map] */
+ cmd_opv_begin_image = 0xdc, /* BPCi(3)(0=mask) */
+#ifdef FUTURE
+ /* more params(1) */
+#else
+ /* Interpolate(1) */
+#endif
+ /* Matrix?(1)Decode?(1) */
+ /* adjust/CombineWithColor(1) */
+ /* rect?(1), */
+#ifdef FUTURE
+ /* [format(2)Interpolate(1)0(5),] */
+#endif
+ /* width#, height#, */
+ /* [, aabbcd00, 0..6 x coeff(float)] */
+ /* [, (0=default, 1=swapped default, */
+ /* 2=0,V, 3=U,V)x4, */
+ /* 0..8 x decode(float)], */
+ /* [, x0#, w-x1#, y0#, h-y1#] */
+ cmd_opv_image_data = 0xdd, /* height# (premature EOD if 0), */
+ /* raster#, <data> */
+ cmd_opv_set_color = 0xde, /* (0000abcd | */
+ /* 0001aaaa abbbbbcc cccddddd), */
+ /* (3|4) x level#: colored halftone */
+ /* with base colors a,b,c,d */
+ cmd_opv_put_params = 0xdf, /* (nothing) */
+ cmd_op_segment = 0xe0, /* (see below) */
+ cmd_opv_rmoveto = 0xe0, /* dx%, dy% */
+ cmd_opv_rlineto = 0xe1, /* dx%, dy% */
+ cmd_opv_hlineto = 0xe2, /* dx% */
+ cmd_opv_vlineto = 0xe3, /* dy% */
+ cmd_opv_rrcurveto = 0xe4, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_hvcurveto = 0xe5, /* dx1%, dx2%,dy2%, dy3% */
+ cmd_opv_vhcurveto = 0xe6, /* dy1%, dx2%,dy2%, dx3% */
+ cmd_opv_nrcurveto = 0xe7, /* dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_rncurveto = 0xe8, /* dx1%,dy1%, dx2%,dy2% */
+ cmd_opv_rmlineto = 0xe9, /* dx1%,dy1%, dx2%,dy2% */
+ cmd_opv_rm2lineto = 0xea, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_rm3lineto = 0xeb, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3%, */
+ /* [-dx2,-dy2 implicit] */
+ cmd_opv_vqcurveto = 0xec, /* dy1%, dx2%[,dy2=dx2 with sign */
+ /* of dy1, dx3=dy1 with sign of dx2] */
+ cmd_opv_hqcurveto = 0xed, /* dx1%, [dx2=dy2 with sign */
+ /* of dx1,]%dy2, [dy3=dx1 with sign */
+ /* of dy2] */
+ cmd_opv_closepath = 0xee, /* (nothing) */
+ cmd_op_path = 0xf0, /* (see below) */
+ /* The path drawing commands come in groups: */
+ /* each group consists of a base command plus an offset */
+ /* which is a cmd_dc_type. */
+ cmd_opv_fill = 0xf0,
+ cmd_opv_htfill = 0xf1,
+ cmd_opv_colorfill = 0xf2,
+ cmd_opv_eofill = 0xf3,
+ cmd_opv_hteofill = 0xf4,
+ cmd_opv_coloreofill = 0xf5,
+ cmd_opv_stroke = 0xf6,
+ cmd_opv_htstroke = 0xf7,
+ cmd_opv_colorstroke = 0xf8
+} gx_cmd_xop;
+
+static const byte clist_segment_op_num_operands[] =
+ { 2, 2, 1, 1, 6, 4, 4, 4, 4, 4, 6, 6, 2, 2, 0
+ };
+
+#define cmd_misc2_op_name_strings\
+ "set_flatness", "set_fill_adjust", "set_ctm", "set_line_width",\
+ "set_misc2", "set_miter_limit", "set_dash", "enable_clip",\
+ "disable_clip", "begin_clip", "end_clip", "set_color_space",\
+ "begin_image", "image_data", "set_color", "set_params"
+
+#define cmd_segment_op_name_strings\
+ "rmoveto", "rlineto", "hlineto", "vlineto",\
+ "rrcurveto", "hvcurveto", "vhcurveto", "nrcurveto",\
+ "rncurveto", "rmlineto", "rm2lineto", "rm3lineto",\
+ "vqcurveto", "hqcurveto", "closepath", "?ef?"
+
+#define cmd_path_op_name_strings\
+ "fill", "htfill", "colorfill", "eofill",\
+ "hteofill", "coloreofill", "stroke", "htstroke",\
+ "colorstroke", "?f9?", "?fa?", "?fb?",\
+ "?fc?", "?fd?", "?fe?", "?ff?"
+
+/*
+ * We represent path coordinates as 'fixed' values in a variable-length,
+ * relative form (s/t = sign, x/y = integer, f/g = fraction):
+ * 00sxxxxx xfffffff ffffftyy yyyygggg gggggggg
+ * 01sxxxxx xxxxffff ffffffff
+ * 10sxxxxx xxxxxxxx xxxxffff ffffffff
+ * 110sxxxx xxxxxxff
+ * 111----- (a full-size `fixed' value)
+ */
+#define is_bits(d, n) !(((d) + ((fixed)1 << ((n) - 1))) & (-(fixed)1 << (n)))
+
+/* ---------------- Driver procedure support ---------------- */
+
+/* The procedures and macros defined here are used when writing */
+/* (gxclimag.c, gxclpath.c). */
+
+/* Compare and update members of the imager state. */
+#define state_neq(member)\
+ cdev->imager_state.member != pis->member
+#define state_update(member)\
+ cdev->imager_state.member = pis->member
+
+/* ------ Exported by gxclpath.c ------ */
+
+/* Write out the color for filling, stroking, or masking. */
+/* Return a cmd_dc_type. */
+int cmd_put_drawing_color(P3(gx_device_clist_writer *cldev,
+ gx_clist_state *pcls,
+ const gx_drawing_color *pdcolor));
+
+/* Clear (a) specific 'known' flag(s) for all bands. */
+/* We must do this whenever the value of a 'known' parameter changes. */
+void cmd_clear_known(P2(gx_device_clist_writer *cldev, uint known));
+
+/* Write out values of any unknown parameters. */
+#define cmd_do_write_unknown(cldev, pcls, must_know)\
+ ( ( ~(pcls)->known & (must_know) )\
+ ? cmd_write_unknown(cldev, pcls, must_know) : 0 )
+int cmd_write_unknown(P3(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ uint must_know));
+
+/* Check whether we need to change the clipping path in the device. */
+bool cmd_check_clip_path(P2(gx_device_clist_writer *cldev,
+ const gx_clip_path *pcpath));
+
+/* Construct the parameters for writing out a matrix. */
+/* We need a buffer of at least 1 + 6 * sizeof(float) bytes. */
+byte *cmd_for_matrix(P2(byte *cbuf, const gs_matrix *pmat));
diff --git a/gs/src/gxclread.c b/gs/src/gxclread.c
new file mode 100644
index 000000000..18da2a60a
--- /dev/null
+++ b/gs/src/gxclread.c
@@ -0,0 +1,2491 @@
+/* Copyright (C) 1991, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclread.c */
+/* Command list reading for Ghostscript. */
+#include "memory_.h"
+#include "gx.h"
+#include "gp.h" /* for gp_fmode_rb */
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gsstate.h" /* (should only be imager state) */
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gsdevice.h" /* for gs_deviceinitialmatrix */
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gsparams.h"
+#include "gxclpath.h"
+#include "gxcmap.h"
+#include "gxcspace.h" /* for gs_color_space_type */
+#include "gxpaint.h" /* for gx_fill/stroke_params */
+#include "gxhttile.h"
+#include "gdevht.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gzacpath.h"
+#include "stream.h"
+#include "strimpl.h"
+/* We need color space types for constructing temporary color spaces. */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+#define cdev crdev
+
+/* Print a bitmap for tracing */
+#ifdef DEBUG
+private void
+cmd_print_bits(const byte *data, int width, int height, int raster)
+{ int i, j;
+ dprintf3("[L]width=%d, height=%d, raster=%d\n",
+ width, height, raster);
+ for ( i = 0; i < height; i++ )
+ { const byte *row = data + i * raster;
+ dprintf("[L]");
+ for ( j = 0; j < raster; j++ )
+ dprintf1(" %02x", row[j]);
+ dputc('\n');
+ }
+}
+#else
+# define cmd_print_bits(data, width, height, raster) DO_NOTHING
+#endif
+
+/* ------ Band file reading stream ------ */
+
+/*
+ * To separate banding per se from command list interpretation,
+ * we make the command list interpreter simply read from a stream.
+ * When we are actually doing banding, the stream filters the band file
+ * and only passes through the commands for the current band (or band
+ * ranges that include the current band).
+ */
+typedef struct stream_band_read_state_s {
+ stream_state_common;
+ gx_band_page_info page_info;
+ int band;
+ uint left; /* amount of data left in this run */
+ cmd_block b_this;
+} stream_band_read_state;
+
+#define ss ((stream_band_read_state *)st)
+
+private int
+s_band_read_init(stream_state *st)
+{ ss->left = 0;
+ ss->b_this.band_min = 0;
+ ss->b_this.band_max = 0;
+ ss->b_this.pos = 0;
+ clist_rewind(ss->page_bfile, false, ss->page_bfname);
+ return 0;
+}
+
+private int
+s_band_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ clist_file_ptr cfile = ss->page_cfile;
+ clist_file_ptr bfile = ss->page_bfile;
+ uint left = ss->left;
+ int status = 1;
+ uint count;
+
+ while ( (count = wlimit - q) != 0 )
+ { if ( left )
+ { /* Read more data for the current run. */
+ if ( count > left )
+ count = left;
+ clist_fread_chars(q + 1, count, cfile);
+ if ( clist_ferror_code(cfile) < 0 )
+ { status = ERRC;
+ break;
+ }
+ q += count;
+ left -= count;
+ process_interrupts();
+ continue;
+ }
+rb: /* Scan for the next run for this band (or a band range */
+ /* that includes the current band). */
+ if ( ss->b_this.band_min == cmd_band_end &&
+ clist_ftell(bfile) == ss->page_bfile_end_pos
+ )
+ { status = EOFC;
+ break;
+ }
+ { int bmin = ss->b_this.band_min;
+ int bmax = ss->b_this.band_max;
+ long pos = ss->b_this.pos;
+
+ clist_fread_chars(&ss->b_this, sizeof(ss->b_this), bfile);
+ if ( !(ss->band >= bmin && ss->band <= bmax) )
+ goto rb;
+ clist_fseek(cfile, pos, SEEK_SET, ss->page_cfname);
+ left = (uint)(ss->b_this.pos - pos);
+ if_debug5('l', "[l]reading for bands (%d,%d) at bfile %ld, cfile %ld, length %u\n",
+ bmin, bmax,
+ clist_ftell(bfile) - 2 * sizeof(ss->b_this),
+ pos, left);
+ }
+ }
+ pw->ptr = q;
+ ss->left = left;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_band_read_template =
+{ &st_stream_state, s_band_read_init, s_band_read_process, 1, cbuf_size
+};
+
+
+/* ------ Reading/rendering ------ */
+typedef enum {playback_action_render, playback_action_setup} clist_playback_action;
+
+private int clist_render_init(P1(gx_device_clist *));
+private int clist_playback_file_band(P7(clist_playback_action, gx_device_clist_reader *, gx_band_page_info *, gx_device *, int, int, int));
+private int clist_playback_band(P7(clist_playback_action, gx_device_clist_reader *, stream *, gx_device *, int, int, gs_memory_t *));
+private int clist_rasterize_lines(P5(gx_device *dev, int y, int lineCount, byte *data_in, byte **data_out));
+
+/* Do device setup from params stored in command list. This is only for */
+/* async rendering & assumes that the first command in every command list */
+/* is a put_params command which sets all space-related parameters to the */
+/* value they will have for the duration of that command list. */
+int /* rets 0 ok, else -ve err code */
+clist_setup_params(gx_device *dev)
+{ int code = clist_render_init((gx_device_clist *)dev);
+ if ( code < 0 )
+ return code;
+
+ code = clist_playback_file_band(playback_action_setup,
+ cdev, &cdev->page_info, 0, 0, 0, 0);
+
+ /* put_params may have reinitialized device into a writer */
+ clist_render_init((gx_device_clist *)dev);
+
+ return code;
+}
+
+/* Find out where the band buffer for a given line is going to fall on the */
+/* next call to get_bits. */
+int /* rets # lines from y till end of buffer, or -ve error code */
+clist_locate_overlay_buffer(gx_device_printer *pdev, int y, byte **data)
+{ gx_device * const dev = (gx_device *)pdev;
+ gx_device *target = cdev->target;
+
+ uint raster = gdev_mem_raster(target);
+ byte *mdata = cdev->data + cdev->page_tile_cache_size;
+ int band_height = cdev->page_band_height;
+ int band = y / band_height;
+ int band_begin_line = band * band_height;
+ int bytes_from_band_begin_to_line = (y - band_begin_line) * raster;
+ int band_end_line = band_begin_line + band_height;
+ if (band_end_line > dev->height)
+ band_end_line = dev->height;
+
+ /* Make sure device will rasterize on next get_bits or get_overlay_bits */
+ if ( cdev->ymin >= 0 )
+ cdev->ymin = cdev->ymax = 0;
+
+ *data = mdata + bytes_from_band_begin_to_line;
+ return band_end_line - y; /* # lines remaining in this band */
+}
+
+/* Do more rendering to a client-supplied memory image, return results */
+int /* 0 ok, -ve error code */
+clist_get_overlay_bits(gx_device_printer *pdev, int y, int line_count,
+ byte *data)
+{ byte *data_orig = data;
+ byte *data_transformed;
+ gx_device * const dev = (gx_device *)pdev;
+ gx_device *target = cdev->target;
+ int raster = gdev_mem_raster(target);
+ int current_line = line_count;
+
+ /* May have to render more than once to cover requested line range */
+ while (current_line > 0)
+ { int line_count_rasterized = clist_rasterize_lines(dev, y,
+ current_line, data_orig, &data_transformed);
+ int byte_count_rasterized = raster * line_count_rasterized;
+ if (line_count_rasterized < 0)
+ return line_count_rasterized;
+ if (data_orig != data_transformed)
+ memcpy(data_orig, data_transformed, byte_count_rasterized);
+ data_orig += byte_count_rasterized;
+ current_line -= line_count_rasterized;
+ }
+ return 0;
+}
+
+/* Copy a scan line to the client. This is where rendering gets done. */
+int
+clist_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
+{
+ byte *data_out;
+ int lines_rendered = clist_rasterize_lines(dev, y, 1, 0, &data_out);
+ if (lines_rendered < 0)
+ return lines_rendered; /* -ve error code */
+
+ if (actual_data == 0)
+ memcpy( str, data_out, gx_device_raster(dev, 0) );
+ else
+ *actual_data = data_out;
+ return 0;
+}
+
+/* Copy scan lines to the client. This is where rendering gets done. */
+/* Processes min(requested # lines, # lines available thru end of band) */
+private int /* returns -ve error code, or # scan lines copied */
+clist_rasterize_lines(gx_device *dev, int y, int lineCount, byte *data_in,
+ byte **data_out)
+{ gx_device *target = cdev->target;
+ uint raster = gdev_mem_raster(target);
+ byte *mdata = cdev->data + cdev->page_tile_cache_size;
+ gx_device_memory mdev;
+ gx_device *tdev = (gx_device *)&mdev;
+
+ /* Initialize for rendering if we haven't done so yet. */
+ if ( cdev->ymin < 0 )
+ { int code = clist_end_page( &( (gx_device_clist *)cdev )->writer );
+ if ( code < 0 )
+ return code;
+ code = clist_render_init((gx_device_clist *)dev);
+ if ( code < 0 )
+ return code;
+ }
+ /* Render a band if necessary, and copy it incrementally. */
+ if ( data_in || !(y >= cdev->ymin && y < cdev->ymax) )
+ { const gx_placed_page *ppages = cdev->pages;
+ int num_pages = cdev->num_pages;
+ gx_saved_page current_page;
+ gx_placed_page placed_page;
+ int i;
+ int code;
+ int band_height = cdev->page_band_height;
+ int band = y / band_height;
+ int band_begin_line = band * band_height;
+ int band_end_line = band_begin_line + band_height;
+ if (band_end_line > dev->height)
+ band_end_line = dev->height;
+
+ /* Clip lineCount to current band */
+ if (lineCount > band_end_line - y)
+ lineCount = band_end_line - y;
+
+ if ( y < 0 || y > dev->height )
+ return_error(gs_error_rangecheck);
+ code = (*cdev->make_buffer_device)(&mdev, target, 0, true);
+ if ( code < 0 )
+ return code;
+ /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
+ mdev.color_info = dev->color_info;
+ mdev.base = mdata;
+ /*
+ * The matrix in the memory device is irrelevant,
+ * because all we do with the device is call the device-level
+ * output procedures, but we may as well set it to
+ * something halfway reasonable.
+ */
+ gs_deviceinitialmatrix(target, &mdev.initial_matrix);
+ mdev.width = target->width;
+ mdev.height = band_height;
+ mdev.raster = raster;
+ (*dev_proc(&mdev, open_device))((gx_device *)&mdev);
+ if_debug1('l', "[l]rendering band %d\n", band);
+ /* Unfortunately, there is currently no way to get a mem
+ * device to rasterize into a given memory space, since
+ * a mem device's memory space must also contain internal
+ * structures.
+ */
+ if (data_in)
+ memcpy( mdev.base + (y - band_begin_line) * raster,
+ data_in, lineCount * raster );
+ /*
+ * If we aren't rendering saved pages, do the current one.
+ * Note that this is the only case in which we may encounter
+ * a gx_saved_page with non-zero cfile or bfile.
+ */
+ if ( ppages == 0 )
+ { current_page.info = cdev->page_info;
+ placed_page.page = &current_page;
+ placed_page.offset.x = placed_page.offset.y = 0;
+ ppages = &placed_page;
+ num_pages = 1;
+ }
+ for ( i = 0; i < num_pages; ++i )
+ { const gx_placed_page *ppage = &ppages[i];
+
+ code = clist_playback_file_band(playback_action_render,
+ cdev, &ppage->page->info, tdev, band, -ppage->offset.x,
+ band * mdev.height);
+ if ( code < 0 )
+ break;
+ }
+ /* Reset the band boundaries now, so that we don't get */
+ /* an infinite loop. */
+ cdev->ymin = band_begin_line;
+ cdev->ymax = band_end_line;
+ if ( code < 0 )
+ return code;
+ }
+ *data_out = mdata + (y - cdev->ymin) * raster;
+ return lineCount > cdev->ymax - y ? cdev->ymax - y : lineCount;
+}
+
+/* Initialize for reading. */
+private int
+clist_render_init(gx_device_clist *dev)
+{ cdev->ymin = cdev->ymax = 0;
+ /* For normal rasterizing, pages and num_pages are zero. */
+ cdev->pages = 0;
+ cdev->num_pages = 0;
+ return 0;
+}
+
+#undef cdev
+
+/* Playback the band file, take indicated action w/ its contents */
+private int
+clist_playback_file_band(clist_playback_action action,
+ gx_device_clist_reader *cdev, gx_band_page_info *page_info,
+ gx_device *target, int band, int x0, int y0)
+{ int code = 0;
+ int opened_bfile = 0;
+ int opened_cfile = 0;
+
+ /* We have to pick some allocator for rendering.... */
+ gs_memory_t *mem =
+ (cdev->memory != 0 ? cdev->memory : &gs_memory_default);
+
+ /* setup stream */
+ stream_band_read_state rs;
+ rs.template = &s_band_read_template;
+ rs.memory = 0;
+ rs.band = band;
+ rs.page_info = *page_info;
+
+ /* If this is a saved page, open the files. */
+ if (rs.page_cfile == 0)
+ { code = clist_fopen(rs.page_cfname,
+ gp_fmode_rb, &rs.page_cfile, cdev->bandlist_memory,
+ cdev->bandlist_memory, true);
+ opened_cfile = (code >= 0);
+ }
+ if (rs.page_bfile == 0 && code >= 0)
+ { code = clist_fopen(rs.page_bfname,
+ gp_fmode_rb, &rs.page_bfile, cdev->bandlist_memory,
+ cdev->bandlist_memory, false);
+ opened_bfile = (code >= 0);
+ }
+ if (rs.page_cfile != 0 && rs.page_bfile != 0)
+ { stream s;
+ byte sbuf[cbuf_size];
+ static const stream_procs no_procs =
+ { s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_std_close, s_band_read_process
+ };
+
+ s_band_read_init((stream_state *)&rs);
+ s_std_init(&s, sbuf, cbuf_size, &no_procs, s_mode_read);
+ s.foreign = 1;
+ s.state = (stream_state *)&rs;
+ code = clist_playback_band(action, cdev, &s, target, -x0, y0, mem);
+ }
+
+ /* Close the files if we just opened them. */
+ if (opened_bfile && rs.page_bfile != 0)
+ clist_fclose(rs.page_bfile, rs.page_bfname, false);
+ if (opened_cfile && rs.page_cfile != 0)
+ clist_fclose(rs.page_cfile, rs.page_cfname, false);
+
+ return code;
+}
+
+/* Get a variable-length integer operand. */
+#define cmd_getw(var, p)\
+ do\
+ { if ( *p < 0x80 ) var = *p++;\
+ else { const byte *_cbp; var = cmd_get_w(p, &_cbp); p = _cbp; }\
+ }\
+ while (0)
+private long near
+cmd_get_w(const byte *p, const byte **rp)
+{ long val = *p++ & 0x7f;
+ int shift = 7;
+ for ( ; val += (long)(*p & 0x7f) << shift, *p++ > 0x7f; shift += 7 )
+ ;
+ *rp = p;
+ return val;
+}
+
+/* Render one band to a specified target device. */
+private const byte *cmd_read_rect(P3(int, gx_cmd_rect *, const byte *));
+private const byte *cmd_read_matrix(P2(gs_matrix *, const byte *));
+private void clist_unpack_short_bits(P5(byte *, const byte *, int, int, uint));
+private int cmd_select_map(P7(cmd_map_index, bool, gs_imager_state *,
+ gx_ht_order *, frac **, uint *, gs_memory_t *));
+private int cmd_resize_halftone(P3(gx_device_halftone *, uint, gs_memory_t *));
+private int cmd_install_ht_order(P3(gx_ht_order *, const gx_ht_order *,
+ gs_memory_t *));
+private int clist_decode_segment(P7(gx_path *, int, fixed [6],
+ gs_fixed_point *, int, int,
+ segment_notes));
+private int
+clist_playback_band(clist_playback_action playback_action,
+ gx_device_clist_reader *cdev, stream *s, gx_device *target,
+ int x0, int y0, gs_memory_t *mem)
+{ byte cbuf_on_heap[cbuf_size + sizeof(void *)]; /* but, need this aligned */
+ byte *cbuf
+ = cbuf_on_heap + sizeof(void *) - alignment_mod( cbuf, sizeof(void *) );
+ /* data_bits is for short copy_* bits and copy_* compressed, */
+ /* must be aligned */
+#define data_bits_size cbuf_size
+ byte *data_bits;
+ register const byte *cbp;
+ const byte *cb_limit;
+ const byte *cb_end;
+ int end_status = 0;
+ int dev_depth = cdev->color_info.depth;
+ int dev_depth_bytes = (dev_depth + 7) >> 3;
+ gx_device *tdev;
+ gx_clist_state state;
+ gx_color_index _ss *set_colors;
+ tile_slot *state_slot;
+ gx_strip_bitmap state_tile; /* parameters for reading tiles */
+ tile_slot tile_bits; /* parameters of current tile */
+ gs_int_point tile_phase;
+ gx_path path;
+ bool in_path;
+ gs_fixed_point ppos;
+ gx_clip_path clip_path;
+ bool use_clip;
+ gx_clip_path *pcpath;
+ gx_device_cpath_accum clip_accum;
+ gs_fixed_rect target_box;
+ struct _cas {
+ bool lop_enabled;
+ gs_fixed_point fill_adjust;
+ } clip_save;
+ gs_imager_state imager_state;
+ gx_device_color dev_color;
+ float dash_pattern[cmd_max_dash];
+ gx_fill_params fill_params;
+ gx_stroke_params stroke_params;
+ gx_device_halftone dev_ht;
+ gs_halftone_type halftone_type;
+ gx_ht_order *porder;
+ uint ht_data_index;
+ gs_image_t image;
+ int image_num_planes;
+ gs_int_rect image_rect;
+ gs_color_space color_space; /* only used for indexed spaces */
+ const gs_color_space *pcs;
+ void *image_info;
+ segment_notes notes;
+ int data_x;
+ int code = 0;
+
+#define cmd_get_value(var, cbp)\
+ memcpy(&var, cbp, sizeof(var));\
+ cbp += sizeof(var)
+#define cmd_read(ptr, rsize, cbp)\
+ if ( cb_end - cbp >= (rsize) )\
+ memcpy(ptr, cbp, rsize), cbp += rsize;\
+ else\
+ { uint cleft = cb_end - cbp, rleft = (rsize) - cleft;\
+ memcpy(ptr, cbp, cleft);\
+ sgets(s, ptr + cleft, rleft, &rleft);\
+ cbp = cb_end;\
+ }
+#define cmd_read_short_bits(ptr, bw, ht, ras, cbp)\
+ cmd_read(ptr, (bw) * (ht), cbp);\
+ clist_unpack_short_bits(ptr, ptr, bw, ht, ras)
+
+ cb_limit = cbuf + (cbuf_size - cmd_largest_size + 1);
+ cb_end = cbuf + cbuf_size;
+ cbp = cb_end;
+in: /* Initialize for a new page. */
+ tdev = target;
+ set_colors = state.colors;
+ use_clip = false;
+ pcpath = NULL;
+ notes = sn_none;
+ data_x = 0;
+ { static const gx_clist_state cls_initial = { cls_initial_values };
+ state = cls_initial;
+ }
+ state_tile.id = gx_no_bitmap_id;
+ state_tile.shift = state_tile.rep_shift = 0;
+ tile_phase.x = tile_phase.y = 0;
+ gx_path_init(&path, mem);
+ in_path = false;
+ /*
+ * Initialize the clipping region to the full page.
+ * (Since we also initialize use_clip to false, this is arbitrary.)
+ */
+ { gs_fixed_rect cbox;
+ cbox.p.x = 0;
+ cbox.p.y = 0;
+ cbox.q.x = cdev->width;
+ cbox.q.y = cdev->height;
+ gx_cpath_from_rectangle(&clip_path, &cbox, mem);
+ }
+ if (target != 0)
+ (*dev_proc(target, get_clipping_box))(target, &target_box);
+ imager_state = clist_imager_state_initial;
+ imager_state.line_params.dash.pattern = dash_pattern;
+ code = gs_imager_state_initialize(&imager_state, mem);
+ if ( code < 0 )
+ goto out;
+ imager_state.halftone = 0; /* never referenced */
+ memset(&dev_ht, 0, sizeof(dev_ht));
+ dev_ht.order.levels = 0; /* clear pointers explicitly, just in case */
+ dev_ht.order.bits = 0;
+ dev_ht.order.transfer = 0;
+ dev_ht.components = 0;
+ imager_state.dev_ht = &dev_ht;
+ imager_state.ht_cache = 0;
+ if (tdev != 0)
+ gx_set_cmap_procs(&imager_state, tdev);
+ gx_imager_setscreenphase(&imager_state, -x0, -y0, gs_color_select_all);
+ halftone_type = ht_type_none;
+ fill_params.fill_zero_width = false;
+ pcs = gs_color_space_DeviceGray();
+ data_bits = gs_alloc_bytes(mem, data_bits_size,
+ "clist_playback_band(data_bits)");
+ if ( data_bits == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ while ( code >= 0 )
+ { int op;
+ int compress, depth, raster;
+ byte *source;
+ gx_color_index colors[2];
+ gx_color_index _ss *pcolor;
+ gs_logical_operation_t log_op;
+ tile_slot bits; /* parameters for reading bits */
+
+ /* Make sure the buffer contains a full command. */
+#define set_cb_end(p)\
+ cb_end = p;\
+ cb_limit = cbuf + (cbuf_size - cmd_largest_size + 1);\
+ if ( cb_limit > cb_end ) cb_limit = cb_end
+ if ( cbp >= cb_limit )
+ { if ( end_status < 0 )
+ { /* End of file or error. */
+ if ( cbp == cb_end )
+ { code = (end_status == EOFC ? 0 :
+ gs_note_error(gs_error_ioerror));
+ break;
+ }
+ }
+ else
+#define top_up_cbuf \
+ do\
+ { uint nread;\
+ byte *cb_top = cbuf + (cb_end - cbp);\
+ memmove(cbuf, cbp, cb_end - cbp);\
+ nread = cb_end - cb_top;\
+ end_status = sgets(s, cb_top, nread, &nread);\
+ if ( nread == 0 )\
+ { /* No data for this band at all. */\
+ *cb_top = cmd_opv_end_run;\
+ nread = 1;\
+ }\
+ set_cb_end(cb_top + nread);\
+ cbp = cbuf;\
+ process_interrupts();\
+ } while (false);
+ top_up_cbuf;
+ }
+ op = *cbp++;
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { const char **sub = cmd_sub_op_names[op >> 4];
+ if ( sub )
+ dprintf1("[L]%s:", sub[op & 0xf]);
+ else
+ dprintf2("[L]%s %d:", cmd_op_names[op >> 4], op & 0xf);
+ }
+#endif
+ switch ( op >> 4 )
+ {
+ case cmd_op_misc >> 4:
+ switch ( op )
+ {
+ case cmd_opv_end_run:
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_tile_size:
+ { uint rep_width, rep_height;
+ byte bd = *cbp++;
+
+ tile_bits.cb_depth = (bd & 31) + 1;
+ cmd_getw(rep_width, cbp);
+ cmd_getw(rep_height, cbp);
+ if ( bd & 0x20 ) {
+ cmd_getw(tile_bits.x_reps, cbp);
+ tile_bits.width =
+ rep_width * tile_bits.x_reps;
+ } else {
+ tile_bits.x_reps = 1,
+ tile_bits.width = rep_width;
+ }
+ if ( bd & 0x40 ) {
+ cmd_getw(tile_bits.y_reps, cbp);
+ tile_bits.height =
+ rep_height * tile_bits.y_reps;
+ } else {
+ tile_bits.y_reps = 1,
+ tile_bits.height = rep_height;
+ }
+ if ( bd & 0x80 )
+ cmd_getw(tile_bits.rep_shift, cbp);
+ else
+ tile_bits.rep_shift = 0;
+ if_debug6('L', " depth=%d size=(%d,%d), rep_size=(%d,%d), rep_shift=%d\n",
+ tile_bits.cb_depth, tile_bits.width,
+ tile_bits.height, rep_width,
+ rep_height, tile_bits.rep_shift);
+ tile_bits.shift =
+ (tile_bits.rep_shift == 0 ? 0 :
+ (tile_bits.rep_shift *
+ (tile_bits.height / rep_height))
+ % rep_width);
+ tile_bits.cb_raster =
+ bitmap_raster(tile_bits.width *
+ tile_bits.cb_depth);
+ } continue;
+ case cmd_opv_set_tile_phase:
+ cmd_getw(state.tile_phase.x, cbp);
+ cmd_getw(state.tile_phase.y, cbp);
+ if_debug2('L', " (%d,%d)\n",
+ state.tile_phase.x,
+ state.tile_phase.y);
+ goto set_phase;
+ case cmd_opv_set_tile_bits:
+ bits = tile_bits;
+ compress = 0;
+stb: { uint rep_width = bits.width / bits.x_reps;
+ uint rep_height = bits.height / bits.y_reps;
+ uint index;
+ ulong offset;
+ uint width_bits = rep_width * bits.cb_depth;
+ uint width_bytes;
+ uint bytes =
+ clist_bitmap_bytes(width_bits, rep_height,
+ compress |
+ (rep_width < bits.width ?
+ decompress_spread : 0) |
+ decompress_elsewhere,
+ &width_bytes,
+ (uint *)&raster);
+ byte *data;
+
+ cmd_getw(index, cbp);
+ cmd_getw(offset, cbp);
+ if_debug2('L', " index=%d offset=%lu\n",
+ state.tile_index, offset);
+ state.tile_index = index;
+ cdev->tile_table[state.tile_index].offset =
+ offset;
+ state_slot =
+ (tile_slot *)(cdev->chunk.data + offset);
+ *state_slot = bits;
+ state_tile.data = data =
+ (byte *)(state_slot + 1);
+#ifdef DEBUG
+ state_slot->index = state.tile_index;
+#endif
+ if ( compress )
+ { /* Decompress the image data. */
+ /* We'd like to share this code */
+ /* with the similar code in copy_*, */
+ /* but right now we don't see how. */
+ stream_cursor_read r;
+ stream_cursor_write w;
+ /* We don't know the data length a */
+ /* priori, so to be conservative, */
+ /* we read the uncompressed size. */
+ uint cleft = cb_end - cbp;
+
+ if ( cleft < bytes )
+ { uint nread = cbuf_size - cleft;
+ memmove(cbuf, cbp, cleft);
+ end_status = sgets(s, cbuf + cleft, nread, &nread);
+ set_cb_end(cbuf + cleft + nread);
+ cbp = cbuf;
+ }
+ r.ptr = cbp - 1;
+ r.limit = cb_end - 1;
+ w.ptr = data - 1;
+ w.limit = w.ptr + bytes;
+ switch ( compress )
+ {
+ case cmd_compress_rle:
+ { stream_RLD_state sstate;
+ clist_rld_init(&sstate);
+ (*s_RLD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ } break;
+ case cmd_compress_cfe:
+ { stream_CFD_state sstate;
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*width_bits*/,
+ rep_height, mem);
+ (*s_CFD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *)&sstate);
+ } break;
+ default:
+ goto bad_op;
+ }
+ cbp = r.ptr + 1;
+ }
+ else if ( rep_height > 1 &&
+ width_bytes != bits.cb_raster
+ )
+ { cmd_read_short_bits(data, width_bytes,
+ rep_height, bits.cb_raster, cbp);
+ }
+ else
+ { cmd_read(data, bytes, cbp);
+ }
+ if ( bits.width > rep_width )
+ bits_replicate_horizontally(data,
+ rep_width * bits.cb_depth, rep_height,
+ bits.cb_raster,
+ bits.width * bits.cb_depth,
+ bits.cb_raster);
+ if ( bits.height > rep_height )
+ bits_replicate_vertically(data,
+ rep_height, bits.cb_raster,
+ bits.height);
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ cmd_print_bits(data, bits.width,
+ bits.height,
+ bits.cb_raster);
+#endif
+ }
+ goto stp;
+ case cmd_opv_set_bits:
+ compress = *cbp & 3;
+ bits.cb_depth = *cbp++ >> 2;
+ cmd_getw(bits.width, cbp);
+ cmd_getw(bits.height, cbp);
+ if_debug4('L', " compress=%d depth=%d size=(%d,%d)",
+ compress, bits.cb_depth,
+ bits.width, bits.height);
+ bits.cb_raster =
+ bitmap_raster(bits.width * bits.cb_depth);
+ bits.x_reps = bits.y_reps = 1;
+ bits.shift = bits.rep_shift = 0;
+ goto stb;
+ case cmd_opv_set_tile_color:
+ set_colors = state.tile_colors;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_misc:
+ { uint cb = *cbp++;
+ switch ( cb >> 6 )
+ {
+ case cmd_set_misc_lop >> 6:
+ cmd_getw(state.lop, cbp);
+ state.lop = (state.lop << 6) + (cb & 0x3f);
+ if_debug1('L', " lop=0x%x\n", state.lop);
+ if ( state.lop_enabled )
+ imager_state.log_op = state.lop;
+ break;
+ case cmd_set_misc_data_x >> 6:
+ if ( cb & 0x20 )
+ cmd_getw(data_x, cbp);
+ else
+ data_x = 0;
+ data_x = (data_x << 5) + (cb & 0x1f);
+ if_debug1('L', " data_x=%d\n", data_x);
+ break;
+ case cmd_set_misc_map >> 6:
+ { frac *mdata;
+ uint count;
+ code = cmd_select_map(cb & 0x1f,
+ cb & 0x20,
+ &imager_state,
+ porder, &mdata,
+ &count, mem);
+
+ if ( code < 0 )
+ goto out;
+ if ( mdata )
+ { cmd_read((byte *)mdata, count, cbp);
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { uint i;
+ for ( i = 0; i < count / sizeof(*mdata); ++i )
+ dprintf1(" 0x%04x", mdata[i]);
+ dputc('\n');
+ }
+ }
+ else
+ { if_debug0('L', " none\n");
+#endif
+ }
+ }
+ /* Recompute the effective transfer, */
+ /* in case this was a transfer map. */
+ gx_imager_set_effective_xfer(
+ &imager_state);
+ break;
+ case cmd_set_misc_halftone >> 6:
+ halftone_type = cb & 0x3f;
+ { uint num_comp;
+ cmd_getw(num_comp, cbp);
+ if_debug2('L', " halftone type=%d num_comp=%u\n",
+ halftone_type, num_comp);
+ code = cmd_resize_halftone(&dev_ht,
+ num_comp, mem);
+ if ( code < 0 )
+ goto out;
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ continue;
+ case cmd_opv_enable_lop:
+ state.lop_enabled = true;
+ imager_state.log_op = state.lop;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_disable_lop:
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_ht_order:
+ { int index;
+ gx_ht_order order;
+
+ cmd_getw(index, cbp);
+ if ( index == 0 )
+ porder = &dev_ht.order;
+ else
+ { gx_ht_order_component *pcomp =
+ &dev_ht.components[index - 1];
+ cmd_getw(pcomp->cname, cbp);
+ if_debug1('L', " cname=%lu",
+ (ulong)pcomp->cname);
+ porder = &pcomp->corder;
+ }
+ order = *porder;
+ cmd_getw(order.width, cbp);
+ cmd_getw(order.height, cbp);
+ cmd_getw(order.raster, cbp);
+ cmd_getw(order.shift, cbp);
+ cmd_getw(order.num_levels, cbp);
+ cmd_getw(order.num_bits, cbp);
+ if_debug7('L', " index=%d size=(%d,%d) raster=%d shift=%d num_levels=%d num_bits=%d\n",
+ index, order.width, order.height,
+ order.raster, order.shift,
+ order.num_levels, order.num_bits);
+ code =
+ cmd_install_ht_order(porder, &order, mem);
+ if ( code < 0 )
+ goto out;
+ }
+ ht_data_index = 0;
+ continue;
+ case cmd_opv_set_ht_data:
+ { int n = *cbp++;
+ if ( ht_data_index < porder->num_levels )
+ { /* Setting levels */
+ byte *lptr = (byte *)
+ (porder->levels + ht_data_index);
+ cmd_read(lptr, n * sizeof(*porder->levels),
+ cbp);
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { int i;
+ dprintf1(" levels[%u]", ht_data_index);
+ for ( i = 0; i < n; ++i )
+ dprintf1(" %u",
+ porder->levels[ht_data_index + i]);
+ dputc('\n');
+ }
+#endif
+ }
+ else
+ { /* Setting bits */
+ byte *bptr = (byte *)
+ (porder->bits +
+ (ht_data_index - porder->num_levels));
+ cmd_read(bptr, n * sizeof(*porder->bits),
+ cbp);
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { int i;
+ dprintf1(" bits[%u]", ht_data_index - porder->num_levels);
+ for ( i = 0; i < n; ++i )
+ { const gx_ht_bit *pb =
+ &porder->bits[ht_data_index - porder->num_levels + i];
+ dprintf2(" (%u,0x%lx)",
+ pb->offset,
+ (ulong)pb->mask);
+ }
+ dputc('\n');
+ }
+#endif
+ }
+ ht_data_index += n;
+ }
+ /* If this is the end of the data, */
+ /* install the (device) halftone. */
+ if ( porder ==
+ (dev_ht.components != 0 ?
+ &dev_ht.components[0].corder :
+ &dev_ht.order) &&
+ ht_data_index == porder->num_levels +
+ porder->num_bits
+ )
+ { /* Make sure we have a halftone cache. */
+ uint i;
+ if ( imager_state.ht_cache == 0 )
+ { gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem,
+ porder->num_levels + 2,
+ gx_ht_cache_default_bits());
+ if ( pcache == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ imager_state.ht_cache = pcache;
+ }
+ for ( i = 1; i < dev_ht.num_comp; ++i )
+ { gx_ht_order *pco =
+ &dev_ht.components[i].corder;
+ if ( !pco->cache )
+ { gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, 1,
+ pco->raster * (pco->num_bits /
+ pco->width));
+ if ( pcache == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ pco->cache = pcache;
+ gx_ht_init_cache(pcache, pco);
+ }
+ }
+ if ( dev_ht.num_comp )
+ { dev_ht.components[0].corder.cache =
+ imager_state.ht_cache;
+ dev_ht.order =
+ dev_ht.components[0].corder;
+ }
+ gx_imager_dev_ht_install(&imager_state,
+ &dev_ht, halftone_type,
+ (const gx_device *)cdev);
+ }
+ continue;
+ case cmd_opv_end_page:
+ if_debug0('L', "\n");
+ /*
+ * Do end-of-page cleanup, then reinitialize if
+ * there are more pages to come.
+ */
+ goto out;
+ case cmd_opv_delta2_color0:
+ pcolor = &set_colors[0];
+ goto delta2_c;
+ case cmd_opv_delta2_color1:
+ pcolor = &set_colors[1];
+delta2_c: set_colors = state.colors;
+ { gx_color_index b = ((uint)*cbp << 8) + cbp[1];
+ cbp += 2;
+ if ( dev_depth > 24 )
+ *pcolor +=
+ ((b & 0xf000) << 12) + ((b & 0x0f00) << 8) +
+ ((b & 0x00f0) << 4) + (b & 0x000f) -
+ cmd_delta2_32_bias;
+ else
+ *pcolor +=
+ ((b & 0xf800) << 5) + ((b & 0x07e0) << 3) +
+ (b & 0x001f) - cmd_delta2_24_bias;
+ }
+ if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_opv_set_copy_color:
+ state.color_is_alpha = 0;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_copy_alpha:
+ state.color_is_alpha = 1;
+ if_debug0('L', "\n");
+ continue;
+ default:
+ goto bad_op;
+ }
+ /*NOTREACHED*/
+ case cmd_op_set_color0 >> 4:
+ pcolor = &set_colors[0];
+ goto set_color;
+ case cmd_op_set_color1 >> 4:
+ pcolor = &set_colors[1];
+set_color: set_colors = state.colors;
+ switch ( op & 0xf )
+ {
+ case 0:
+ break;
+ case 15: /* special handling because this may */
+ /* require more bits than depth */
+ *pcolor = gx_no_color_index;
+ goto setc;
+ default:
+ switch ( dev_depth_bytes )
+ {
+ case 4:
+ { gx_color_index b =
+ ((gx_color_index)(op & 0xf) << 8) + *cbp++;
+ *pcolor +=
+ ((b & 07000) << 15) + ((b & 0700) << 10) +
+ ((b & 070) << 5) + (b & 7) -
+ cmd_delta1_32_bias;
+ goto setc;
+ }
+ case 3:
+ { gx_color_index b = *cbp++;
+ *pcolor +=
+ ((gx_color_index)(op & 0xf) << 16) +
+ ((b & 0xf0) << 4) + (b & 0x0f) -
+ cmd_delta1_24_bias;
+ goto setc;
+ }
+ case 2:
+ break;
+ case 1:
+ *pcolor += (gx_color_index)(op & 0xf) - 8;
+ goto setc;
+ }
+ }
+ { gx_color_index color = 0;
+ switch ( dev_depth_bytes )
+ {
+ case 4: color |= (gx_color_index)*cbp++ << 24;
+ case 3: color |= (gx_color_index)*cbp++ << 16;
+ case 2: color |= (gx_color_index)*cbp++ << 8;
+ case 1: color |= (gx_color_index)*cbp++;
+ }
+ *pcolor = color;
+ }
+setc: if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_tile_rect >> 4:
+ cbp = cmd_read_rect(op, &state.rect, cbp);
+ break;
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ state.rect.x += *cbp + cmd_min_short;
+ state.rect.width += cbp[1] + cmd_min_short;
+ if ( op & 0xf )
+ { state.rect.height += (op & 0xf) + cmd_min_dxy_tiny;
+ cbp += 2;
+ }
+ else
+ { state.rect.y += cbp[2] + cmd_min_short;
+ state.rect.height += cbp[3] + cmd_min_short;
+ cbp += 4;
+ }
+ break;
+ case cmd_op_fill_rect_tiny >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ if ( op & 8 )
+ state.rect.x += state.rect.width;
+ else
+ { int txy = *cbp++;
+ state.rect.x += (txy >> 4) + cmd_min_dxy_tiny;
+ state.rect.y += (txy & 0xf) + cmd_min_dxy_tiny;
+ }
+ state.rect.width += (op & 7) + cmd_min_dw_tiny;
+ break;
+ case cmd_op_copy_mono >> 4:
+ depth = 1;
+ goto copy;
+ case cmd_op_copy_color_alpha >> 4:
+ if ( state.color_is_alpha )
+ { if ( !(op & 8) )
+ depth = *cbp++;
+ }
+ else
+ depth = dev_depth;
+copy: cmd_getw(state.rect.x, cbp);
+ cmd_getw(state.rect.y, cbp);
+ if ( op & 8 )
+ { /* Use the current "tile". */
+#ifdef DEBUG
+ if ( state_slot->index != state.tile_index )
+ { lprintf2("state_slot->index = %d, state.tile_index = %d!\n",
+ state_slot->index,
+ state.tile_index);
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ depth = state_slot->cb_depth;
+ state.rect.width = state_slot->width;
+ state.rect.height = state_slot->height;
+ raster = state_slot->cb_raster;
+ source = (byte *)(state_slot + 1);
+ }
+ else
+ { /* Read width, height, bits. */
+ /* depth was set already. */
+ uint width_bits, width_bytes;
+ uint bytes;
+
+ cmd_getw(state.rect.width, cbp);
+ cmd_getw(state.rect.height, cbp);
+ width_bits = state.rect.width * depth;
+ bytes =
+ clist_bitmap_bytes(width_bits,
+ state.rect.height,
+ op & 3, &width_bytes,
+ (uint *)&raster);
+ /* copy_mono and copy_color/alpha */
+ /* ensure that the bits will fit in a single buffer, */
+ /* even after decompression if compressed. */
+#ifdef DEBUG
+ if ( bytes > cbuf_size )
+ { lprintf6("bitmap size exceeds buffer! width=%d raster=%d height=%d\n file pos %ld buf pos %d/%d\n",
+ state.rect.width, raster,
+ state.rect.height,
+ stell(s), (int)(cbp - cbuf),
+ (int)(cb_end - cbuf));
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ if ( op & 3 )
+ { /* Decompress the image data. */
+ stream_cursor_read r;
+ stream_cursor_write w;
+ /* We don't know the data length a priori, */
+ /* so to be conservative, we read */
+ /* the uncompressed size. */
+ uint cleft = cb_end - cbp;
+ if ( cleft < bytes )
+ { uint nread = cbuf_size - cleft;
+ memmove(cbuf, cbp, cleft);
+ end_status = sgets(s, cbuf + cleft, nread, &nread);
+ set_cb_end(cbuf + cleft + nread);
+ cbp = cbuf;
+ }
+ r.ptr = cbp - 1;
+ r.limit = cb_end - 1;
+ w.ptr = data_bits - 1;
+ w.limit = w.ptr + data_bits_size;
+ switch ( op & 3 )
+ {
+ case cmd_compress_rle:
+ { stream_RLD_state sstate;
+ clist_rld_init(&sstate);
+ /* The process procedure can't fail. */
+ (*s_RLD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ } break;
+ case cmd_compress_cfe:
+ { stream_CFD_state sstate;
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*state.rect.width*/,
+ state.rect.height, mem);
+ /* The process procedure can't fail. */
+ (*s_CFD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *)&sstate);
+ } break;
+ default:
+ goto bad_op;
+ }
+ cbp = r.ptr + 1;
+ source = data_bits;
+ }
+ else if ( state.rect.height > 1 &&
+ width_bytes != raster
+ )
+ { source = data_bits;
+ cmd_read_short_bits(source, width_bytes,
+ state.rect.height,
+ raster, cbp);
+ }
+ else
+ { cmd_read(cbuf, bytes, cbp);
+ source = cbuf;
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { dprintf2(" depth=%d, data_x=%d\n",
+ depth, data_x);
+ cmd_print_bits(source, state.rect.width,
+ state.rect.height, raster);
+ }
+#endif
+ }
+ break;
+ case cmd_op_delta_tile_index >> 4:
+ state.tile_index += (int)(op & 0xf) - 8;
+ goto sti;
+ case cmd_op_set_tile_index >> 4:
+ state.tile_index =
+ ((op & 0xf) << 8) + *cbp++;
+sti: state_slot =
+ (tile_slot *)(cdev->chunk.data +
+ cdev->tile_table[state.tile_index].offset);
+ if_debug2('L', " index=%u offset=%lu\n",
+ state.tile_index,
+ cdev->tile_table[state.tile_index].offset);
+ state_tile.data = (byte *)(state_slot + 1);
+stp: state_tile.size.x = state_slot->width;
+ state_tile.size.y = state_slot->height;
+ state_tile.raster = state_slot->cb_raster;
+ state_tile.rep_width = state_tile.size.x /
+ state_slot->x_reps;
+ state_tile.rep_height = state_tile.size.y /
+ state_slot->y_reps;
+ state_tile.rep_shift = state_slot->rep_shift;
+ state_tile.shift = state_slot->shift;
+set_phase: tile_phase.x =
+ (state.tile_phase.x + x0) % state_tile.size.x;
+ /*
+ * The true tile height for shifted tiles is not
+ * size.y: see gxbitmap.h for the computation.
+ */
+ { int full_height;
+
+ if ( state_tile.shift == 0 )
+ full_height = state_tile.size.y;
+ else
+ full_height = state_tile.rep_height *
+ (state_tile.rep_width /
+ igcd(state_tile.rep_shift,
+ state_tile.rep_width));
+ tile_phase.y =
+ (state.tile_phase.y + y0) % full_height;
+ }
+ gx_imager_setscreenphase(&imager_state,
+ -(state.tile_phase.x + x0),
+ -(state.tile_phase.y + y0),
+ gs_color_select_all);
+ continue;
+ case cmd_op_misc2 >> 4:
+ switch ( op )
+ {
+ case cmd_opv_set_flatness:
+ cmd_get_value(imager_state.flatness, cbp);
+ if_debug1('L', " %g\n", imager_state.flatness);
+ continue;
+ case cmd_opv_set_fill_adjust:
+ cmd_get_value(imager_state.fill_adjust.x, cbp);
+ cmd_get_value(imager_state.fill_adjust.y, cbp);
+ if_debug2('L', " (%g,%g)\n",
+ fixed2float(imager_state.fill_adjust.x),
+ fixed2float(imager_state.fill_adjust.y));
+ continue;
+ case cmd_opv_set_ctm:
+ { gs_matrix mat;
+ cbp = cmd_read_matrix(&mat, cbp);
+ mat.tx -= x0;
+ mat.ty -= y0;
+ gs_imager_setmatrix(&imager_state, &mat);
+ if_debug6('L', " [%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy,
+ mat.tx, mat.ty);
+ }
+ continue;
+ case cmd_opv_set_line_width:
+ { float width;
+ cmd_get_value(width, cbp);
+ if_debug1('L', " %g\n", width);
+ gx_set_line_width(&imager_state.line_params, width);
+ }
+ continue;
+ case cmd_opv_set_misc2:
+ { uint cb = *cbp;
+ switch ( cb >> 6 )
+ {
+ case cmd_set_misc2_cap_join >> 6:
+ imager_state.line_params.cap =
+ (gs_line_cap)((cb >> 3) & 7);
+ imager_state.line_params.join =
+ (gs_line_join)(cb & 7);
+ if_debug2('L', " cap=%d join=%d\n",
+ imager_state.line_params.cap,
+ imager_state.line_params.join);
+ break;
+ case cmd_set_misc2_ac_op_sa >> 6:
+ imager_state.accurate_curves =
+ (cb & 4) != 0;
+ imager_state.overprint = (cb & 2) != 0;
+ imager_state.stroke_adjust = cb & 1;
+ if_debug3('L', " AC=%d OP=%d SA=%d\n",
+ imager_state.accurate_curves,
+ imager_state.overprint,
+ imager_state.stroke_adjust);
+ break;
+ case cmd_set_misc2_notes >> 6:
+ notes = (segment_notes)(cb & 0x3f);
+ if_debug1('L', " notes=%d\n", notes);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ cbp++;
+ continue;
+ case cmd_opv_set_miter_limit:
+ { float limit;
+ cmd_get_value(limit, cbp);
+ if_debug1('L', " %g\n", limit);
+ gx_set_miter_limit(&imager_state.line_params, limit);
+ }
+ continue;
+ case cmd_opv_set_dash:
+ { int nb = *cbp++;
+ int n = nb & 0x3f;
+ float dot_length, offset;
+
+ cmd_get_value(dot_length, cbp);
+ cmd_get_value(offset, cbp);
+ memcpy(dash_pattern, cbp, n * sizeof(float));
+ gx_set_dash(&imager_state.line_params.dash,
+ dash_pattern, n, offset,
+ NULL);
+ gx_set_dash_adapt(&imager_state.line_params.dash,
+ (nb & 0x80) != 0);
+ gx_set_dot_length(&imager_state.line_params,
+ dot_length,
+ (nb & 0x40) != 0);
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { int i;
+ dprintf4(" dot=%g(mode %d) adapt=%d offset=%g [",
+ dot_length,
+ (nb & 0x40) != 0,
+ (nb & 0x80) != 0, offset);
+ for ( i = 0; i < n; ++i )
+ dprintf1("%g ", dash_pattern[i]);
+ dputs("]\n");
+ }
+#endif
+ cbp += n * sizeof(float);
+ }
+ break;
+ case cmd_opv_enable_clip:
+ pcpath = (use_clip ? &clip_path : NULL);
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_disable_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_begin_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ gx_cpath_release(&clip_path);
+ gx_cpath_accum_begin(&clip_accum, mem);
+ gx_cpath_accum_set_cbox(&clip_accum,
+ &target_box);
+ tdev = (gx_device *)&clip_accum;
+ clip_save.lop_enabled = state.lop_enabled;
+ clip_save.fill_adjust =
+ imager_state.fill_adjust;
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ imager_state.fill_adjust.x =
+ imager_state.fill_adjust.y = fixed_half;
+ break;
+ case cmd_opv_end_clip:
+ if_debug0('L', "\n");
+ gx_cpath_accum_end(&clip_accum, &clip_path);
+ gx_cpath_set_outside(&clip_path, *cbp++);
+ tdev = target;
+ /*
+ * If the entire band falls within the clip
+ * path, no clipping is needed.
+ */
+ { gs_fixed_rect cbox;
+
+ gx_cpath_inner_box(&clip_path, &cbox);
+ use_clip =
+ !(cbox.p.x <= target_box.p.x &&
+ cbox.q.x >= target_box.q.x &&
+ cbox.p.y <= target_box.p.y &&
+ cbox.q.y >= target_box.q.y);
+ }
+ pcpath = (use_clip ? &clip_path : NULL);
+ state.lop_enabled = clip_save.lop_enabled;
+ imager_state.log_op =
+ (state.lop_enabled ? state.lop :
+ lop_default);
+ imager_state.fill_adjust =
+ clip_save.fill_adjust;
+ break;
+ case cmd_opv_set_color_space:
+ { byte b = *cbp++;
+ int index = b >> 4;
+
+ if_debug2('L', " %d%s\n", index,
+ (b & 8? " (indexed)" : ""));
+ switch ( index )
+ {
+ case gs_color_space_index_DeviceGray:
+ pcs = gs_color_space_DeviceGray();
+ break;
+ case gs_color_space_index_DeviceRGB:
+ pcs = gs_color_space_DeviceRGB();
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ pcs = gs_color_space_DeviceCMYK();
+ break;
+ default:
+ goto bad_op; /* others are NYI */
+ }
+ if ( b & 8 )
+ { int num_comp =
+ gs_color_space_num_components(pcs);
+
+ color_space.type = &gs_color_space_type_Indexed;
+ color_space.params.indexed.base_space.type = pcs->type;
+ cmd_getw(color_space.params.indexed.hival,
+ cbp);
+ color_space.params.indexed.use_proc =
+ (b & 4) != 0;
+ /****** SET map ******/
+ pcs = &color_space;
+ }
+ }
+ break;
+ case cmd_opv_begin_image:
+ { byte b = *cbp++;
+ int bpci = b >> 5;
+ static const byte bpc[6] =
+ {1, 1, 2, 4, 8, 12};
+ gx_drawing_color devc;
+ int num_components;
+ gs_image_format_t format;
+
+#ifdef FUTURE
+ if ( b & (1 << 4) )
+ { byte b2 = *cbp++;
+ format = b2 >> 6;
+ image.Interpolate = (b2 & (1 << 5)) != 0;
+ }
+ else
+ { format = gs_image_format_chunky;
+ image.Interpolate = false;
+ }
+#else
+ format = gs_image_format_chunky;
+ image.Interpolate = (b & (1 << 4)) != 0;
+#endif
+ cmd_getw(image.Width, cbp);
+ cmd_getw(image.Height, cbp);
+ if_debug4('L', " BPCi=%d I=%d size=(%d,%d)",
+ bpci, (b & 0x10) != 0,
+ image.Width, image.Height);
+ if ( b & (1 << 3) )
+ { /* Non-standard ImageMatrix */
+ cbp = cmd_read_matrix(
+ &image.ImageMatrix, cbp);
+ if_debug6('L', " matrix=[%g %g %g %g %g %g]",
+ image.ImageMatrix.xx,
+ image.ImageMatrix.xy,
+ image.ImageMatrix.yx,
+ image.ImageMatrix.yy,
+ image.ImageMatrix.tx,
+ image.ImageMatrix.ty);
+ }
+ else
+ { image.ImageMatrix.xx = image.Width;
+ image.ImageMatrix.xy = 0;
+ image.ImageMatrix.yx = 0;
+ image.ImageMatrix.yy = -image.Height;
+ image.ImageMatrix.tx = 0;
+ image.ImageMatrix.ty = image.Height;
+ }
+ image.BitsPerComponent = bpc[bpci];
+ if ( bpci == 0 )
+ { image.ColorSpace = 0;
+ image.ImageMask = true;
+ image.Decode[0] = 0;
+ image.Decode[1] = 1;
+ num_components = 1;
+ }
+ else
+ { image.ColorSpace = pcs;
+ image.ImageMask = false;
+ if ( gs_color_space_get_index(pcs) == gs_color_space_index_Indexed )
+ { image.Decode[0] = 0;
+ image.Decode[1] =
+ (1 << image.BitsPerComponent) - 1;
+ }
+ else
+ { static const float decode01[] =
+ { 0, 1, 0, 1, 0, 1, 0, 1
+#ifdef DPNEXT
+ , 0, 1
+#endif
+ };
+ memcpy(image.Decode, decode01,
+ sizeof(image.Decode));
+ }
+ num_components =
+ gs_color_space_num_components(pcs);
+ }
+#ifdef FUTURE
+ switch ( format )
+ {
+ case gs_image_format_chunky:
+ image_num_planes = 1; break;
+ case gs_image_format_component_planar:
+ image_num_planes = num_components; break;
+ case gs_image_format_bit_planar:
+ image_num_planes = num_components *
+ image.BitsPerComponent; break;
+ default:
+ goto bad_op;
+ }
+#else
+ image_num_planes = 1;
+#endif
+ if ( b & (1 << 2) )
+ { /* Non-standard Decode */
+ byte dflags = *cbp++;
+ int i;
+
+ for ( i = 0; i < num_components * 2;
+ dflags <<= 2, i += 2
+ )
+ switch ( (dflags >> 6) & 3 )
+ {
+ case 0: /* default */
+ break;
+ case 1: /* swapped default */
+ image.Decode[i] =
+ image.Decode[i+1];
+ image.Decode[i+1] = 0;
+ break;
+ case 3:
+ cmd_get_value(image.Decode[i],
+ cbp);
+ /* falls through */
+ case 2:
+ cmd_get_value(image.Decode[i+1],
+ cbp);
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ { dputs(" decode=[");
+ for ( i = 0; i < num_components * 2;
+ ++i
+ )
+ dprintf1("%g ", image.Decode[i]);
+ dputc(']');
+ }
+#endif
+ }
+ image.adjust = false;
+ image.CombineWithColor = false;
+#ifdef DPNEXT
+ image.HasAlpha = false;
+#endif
+ if ( b & (1 << 1) )
+ { if ( image.ImageMask )
+ image.adjust = true;
+ else
+ image.CombineWithColor = true;
+ if_debug1('L', " %s",
+ (image.ImageMask ? " adjust" :
+ " CWC"));
+ }
+ if ( b & (1 << 0) )
+ { /* Non-standard rectangle */
+ uint diff;
+ cmd_getw(image_rect.p.x, cbp);
+ cmd_getw(image_rect.p.y, cbp);
+ cmd_getw(diff, cbp);
+ image_rect.q.x = image.Width - diff;
+ cmd_getw(diff, cbp);
+ image_rect.q.y = image.Height - diff;
+ if_debug4('L', " rect=(%d,%d),(%d,%d)",
+ image_rect.p.x, image_rect.p.y,
+ image_rect.q.x, image_rect.q.y);
+ }
+ else
+ { image_rect.p.x = 0;
+ image_rect.p.y = 0;
+ image_rect.q.x = image.Width;
+ image_rect.q.y = image.Height;
+ }
+ if_debug0('L', "\n");
+ color_set_pure(&devc, state.colors[1]);
+ code = (*dev_proc(tdev, begin_image))
+ (tdev, &imager_state, &image, format,
+ &image_rect, &devc, pcpath, mem,
+ &image_info);
+ if ( code < 0 )
+ goto out;
+ }
+ break;
+ case cmd_opv_image_data:
+ { uint height;
+
+ cmd_getw(height, cbp);
+ if ( height == 0 )
+ { if_debug0('L', " done image\n");
+ code = (*dev_proc(tdev, end_image))
+ (tdev, image_info, true);
+ }
+ else
+ { uint bytes_per_plane, nbytes;
+ const byte *data;
+ byte *data_on_heap = 0;
+ const byte *planes[64];
+ /****** DOESN'T HANDLE #PLANES YET *****/
+
+ cmd_getw(bytes_per_plane, cbp);
+ if_debug2('L', " height=%u raster=%u\n",
+ height, bytes_per_plane);
+ nbytes = bytes_per_plane *
+ image_num_planes * height;
+ if ( cb_end - cbp < nbytes)
+ top_up_cbuf;
+ if ( cb_end - cbp >= nbytes )
+ { data = cbp;
+ cbp += nbytes;
+ }
+ else
+ { uint cleft = cb_end - cbp;
+ uint rleft = nbytes - cleft;
+ byte *rdata;
+
+ if ( nbytes > cb_end - cbuf )
+ { /* Allocate a separate buffer. */
+ rdata = data_on_heap =
+ gs_alloc_bytes(mem, nbytes,
+ "clist image_data");
+ if ( rdata == 0 )
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ }
+ else
+ rdata = cbuf;
+ memmove(rdata, cbp, cleft);
+ sgets(s, rdata + cleft, rleft,
+ &rleft);
+ data = rdata;
+ cbp = cb_end; /* force refill */
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('L') )
+ cmd_print_bits(data, image_rect.q.x -
+ image_rect.p.x,
+ image_num_planes * height,
+ bytes_per_plane);
+#endif
+#ifdef FUTURE
+ { int plane;
+ for ( plane = 0;
+ plane < image_num_planes;
+ ++plane
+ )
+ planes[plane] = data +
+ bytes_per_plane * height * plane;
+ }
+#else
+ planes[0] = data;
+#endif
+ code = (*dev_proc(tdev, image_data))
+ (tdev, image_info, planes, data_x,
+ bytes_per_plane, height);
+ if ( data_on_heap )
+ gs_free_object(mem, data_on_heap,
+ "clist image_data");
+ data_x = 0;
+ }
+ }
+ if ( code < 0 )
+ goto out;
+ continue;
+ case cmd_opv_set_color:
+ {
+#define dcb dev_color.colors.colored.c_base
+#define dcl dev_color.colors.colored.c_level
+ byte b = *cbp++;
+ int i;
+
+ switch ( b >> 4 )
+ {
+ case 0:
+ dcb[0] = (b >> 3) & 1;
+ dcb[1] = (b >> 2) & 1;
+ dcb[2] = (b >> 1) & 1;
+ dcb[3] = b & 1;
+ break;
+ case 1:
+ dcb[0] = ((b & 0xf) << 1) + (*cbp >> 7);
+ dcb[1] = (*cbp >> 2) & 0x1f;
+ dcb[2] = ((*cbp & 3) << 3) + (cbp[1] >> 5);
+ dcb[3] = cbp[1] & 0x1f;
+ cbp += 2;
+ break;
+ default:
+ goto bad_op;
+ }
+ for ( i = 0; i < imager_state.dev_ht->num_comp; ++i )
+ cmd_getw(dcl[i], cbp);
+ if_debug10('L', " format %d num_comp=%d base=(%u,%u,%u,%u) level=(%u,%u,%u,%u)\n",
+ b >> 4,
+ imager_state.dev_ht->num_comp,
+ dcb[0], dcb[1], dcb[2], dcb[3],
+ dcl[0], dcl[1], dcl[2], dcl[3]);
+ color_finish_set_cmyk_halftone(&dev_color,
+ imager_state.dev_ht);
+#undef dcb
+#undef dcl
+ }
+ continue;
+ case cmd_opv_put_params:
+ { gs_c_param_list param_list;
+ uint cleft;
+ uint rleft;
+ bool alloc_data_on_heap = 0;
+ byte *param_buf;
+ unsigned param_length;
+ cmd_get_value(param_length, cbp);
+ if_debug1('L', "Put parameters, length=%d\n", param_length);
+ code = 0;
+ if (param_length == 0)
+ break;
+
+ /* Make sure entire serialized param list is in cbuf */
+ /* + force void* alignment */
+ top_up_cbuf;
+ if (cb_end - cbp >= param_length)
+ { param_buf = (byte *)cbp;
+ cbp += param_length;
+ }
+ else
+ { param_buf = gs_alloc_bytes(mem, param_length,
+ "clist put_params");
+ /* NB allocated maximally aligned */
+ if (param_buf == 0)
+ { code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ alloc_data_on_heap = true;
+ cleft = cb_end - cbp;
+ rleft = param_length - cleft;
+ memmove(param_buf, cbp, cleft);
+ sgets(s, param_buf + cleft, rleft, &rleft);
+ cbp = cb_end; /* force refill */
+ }
+
+ /* Create a gs_c_param_list & expand into it. */
+ /* NB that gs_c_param_list doesn't copy objects into */
+ /* it, but rather keeps *pointers* to what's passed. */
+ /* That's OK because the serialized format keeps enough */
+ /* space to hold expanded versions of the structures, */
+ /* but this means we cannot deallocate source buffer */
+ /* until the gs_c_param_list is deleted. */
+ gs_c_param_list_write(&param_list, mem);
+ code = gs_param_list_unserialize
+ ( (gs_param_list *)&param_list, param_buf );
+ if (code >= 0 && code != param_length)
+ code = gs_error_unknownerror; /* must match */
+ if (code >= 0)
+ { gs_c_param_list_read(&param_list);
+ code = ( *dev_proc( (gx_device *)cdev, put_params ))
+ ( (gx_device *)cdev, (gs_param_list *)&param_list );
+ }
+ gs_c_param_list_release(&param_list);
+ if (alloc_data_on_heap)
+ gs_free_object(mem, param_buf, "clist put_params");
+ if (code < 0)
+ { gs_note_error(code);
+ goto out;
+ }
+ if (playback_action == playback_action_setup)
+ goto out;
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ continue;
+ case cmd_op_segment >> 4:
+ { fixed vs[6];
+ int i, code;
+
+ if ( !in_path )
+ { ppos.x = int2fixed(state.rect.x);
+ ppos.y = int2fixed(state.rect.y);
+ if_debug2('L', " (%d,%d)", state.rect.x,
+ state.rect.y);
+ notes = sn_none;
+ in_path = true;
+ }
+ for ( i = 0;
+ i < clist_segment_op_num_operands[op & 0xf];
+ ++i
+ )
+ { fixed v;
+ int b = *cbp;
+ switch ( b >> 5 )
+ {
+ case 0: case 1:
+ vs[i++] =
+ ((fixed)((b ^ 0x20) - 0x20) << 13) +
+ ((int)cbp[1] << 5) + (cbp[2] >> 3);
+ if_debug1('L', " %g", fixed2float(vs[i - 1]));
+ cbp += 2;
+ v = (int)((*cbp & 7) ^ 4) - 4;
+ break;
+ case 2: case 3:
+ v = (b ^ 0x60) - 0x20;
+ break;
+ case 4: case 5:
+ /*
+ * Without the following cast, C's
+ * brain-damaged coercion rules cause the
+ * result to be considered unsigned, and not
+ * sign-extended on machines where
+ * sizeof(long) > sizeof(int).
+ */
+ v = (((b ^ 0xa0) - 0x20) << 8) + (int)*++cbp;
+ break;
+ case 6:
+ v = (b ^ 0xd0) - 0x10;
+ vs[i] =
+ ((v << 8) + cbp[1]) << (_fixed_shift - 2);
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ cbp += 2;
+ continue;
+ default /*case 7*/:
+ v = (int)(*++cbp ^ 0x80) - 0x80;
+ for ( b = 0; b < sizeof(fixed) - 3; ++b )
+ v = (v << 8) + *++cbp;
+ break;
+ }
+ cbp += 3;
+ /* Absent the cast in the next statement, */
+ /* the Borland C++ 4.5 compiler incorrectly */
+ /* sign-extends the result of the shift. */
+ vs[i] = (v << 16) + (uint)(cbp[-2] << 8) + cbp[-1];
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ }
+ if_debug0('L', "\n");
+ code = clist_decode_segment(&path, op, vs, &ppos,
+ x0, y0, notes);
+ if ( code < 0 )
+ goto out;
+ } continue;
+ case cmd_op_path >> 4:
+ { gx_device_color devc;
+ gx_device_color *pdevc;
+ gx_ht_tile ht_tile;
+
+ if_debug0('L', "\n");
+ switch ( op )
+ {
+ case cmd_opv_fill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_pure;
+ case cmd_opv_eofill:
+ fill_params.rule = gx_rule_even_odd;
+fill_pure: color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto fill;
+ case cmd_opv_htfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_ht;
+ case cmd_opv_hteofill:
+ fill_params.rule = gx_rule_even_odd;
+fill_ht: ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto fill;
+ case cmd_opv_colorfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_color;
+ case cmd_opv_coloreofill:
+ fill_params.rule = gx_rule_even_odd;
+fill_color: pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if ( code < 0 )
+ break;
+fill: fill_params.adjust = imager_state.fill_adjust;
+ fill_params.flatness = imager_state.flatness;
+ code = gx_fill_path_only(&path, tdev,
+ &imager_state,
+ &fill_params,
+ pdevc, pcpath);
+ break;
+ case cmd_opv_stroke:
+ color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto stroke;
+ case cmd_opv_htstroke:
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto stroke;
+ case cmd_opv_colorstroke:
+ pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if ( code < 0 )
+ break;
+stroke: stroke_params.flatness = imager_state.flatness;
+ code = gx_stroke_path_only(&path,
+ (gx_path *)0, tdev,
+ &imager_state, &stroke_params,
+ pdevc, pcpath);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ if ( in_path ) /* path might be empty! */
+ { state.rect.x = fixed2int_var(ppos.x);
+ state.rect.y = fixed2int_var(ppos.y);
+ in_path = false;
+ }
+ gx_path_release(&path);
+ gx_path_init(&path, mem);
+ if ( code < 0 )
+ goto out;
+ continue;
+ default:
+bad_op: lprintf5("Bad op %02x band y0 = %d file pos %ld buf pos %d/%d\n",
+ op, y0, stell(s), (int)(cbp - cbuf), (int)(cb_end - cbuf));
+ { const byte *pp;
+ for ( pp = cbuf; pp < cb_end; pp += 10 )
+ { dprintf1("%4d:", (int)(pp - cbuf));
+ dprintf10(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ pp[0], pp[1], pp[2], pp[3], pp[4],
+ pp[5], pp[6], pp[7], pp[8], pp[9]);
+ }
+ }
+ code = gs_note_error(gs_error_Fatal);
+ goto out;
+ }
+ if_debug4('L', " x=%d y=%d w=%d h=%d\n",
+ state.rect.x, state.rect.y, state.rect.width,
+ state.rect.height);
+ switch ( op >> 4 )
+ {
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_fill_rect_tiny >> 4:
+ if ( !state.lop_enabled )
+ { code = (*dev_proc(tdev, fill_rectangle))
+ (tdev, state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.colors[1]);
+ break;
+ }
+ source = NULL;
+ data_x = 0;
+ raster = 0;
+ colors[0] = colors[1] = state.colors[1];
+ log_op = state.lop;
+ pcolor = colors;
+do_rop: code = (*dev_proc(tdev, strip_copy_rop))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ pcolor, &state_tile,
+ (state.tile_colors[0] == gx_no_color_index &&
+ state.tile_colors[1] == gx_no_color_index ?
+ NULL : state.tile_colors),
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ tile_phase.x, tile_phase.y, log_op);
+ data_x = 0;
+ break;
+ case cmd_op_tile_rect >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ /* Currently we don't use lop with tile_rectangle. */
+ code = (*dev_proc(tdev, strip_tile_rectangle))
+ (tdev, &state_tile,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.tile_colors[0], state.tile_colors[1],
+ tile_phase.x, tile_phase.y);
+ break;
+ case cmd_op_copy_mono >> 4:
+ if ( state.lop_enabled )
+ { pcolor = state.colors;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ if ( (op & cmd_copy_ht_color) || pcpath != NULL )
+ { /*
+ * This call of copy_mono originated as a call
+ * of fill_mask.
+ */
+ gx_drawing_color dcolor;
+ gx_ht_tile ht_tile;
+ if ( op & cmd_copy_ht_color )
+ { /* Screwy C assignment rules don't allow: */
+ /* dcolor.colors = state.tile_colors; */
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&dcolor,
+ state.tile_colors[0],
+ state.tile_colors[1], &ht_tile);
+ dcolor.phase = tile_phase;
+ }
+ else
+ { color_set_pure(&dcolor, state.colors[1]);
+ }
+ code = (*dev_proc(tdev, fill_mask))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ &dcolor, 1, imager_state.log_op, pcpath);
+ }
+ else
+ code = (*dev_proc(tdev, copy_mono))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[0], state.colors[1]);
+ data_x = 0;
+ break;
+ case cmd_op_copy_color_alpha >> 4:
+ if ( state.color_is_alpha )
+ { /****** CAN'T DO ROP WITH ALPHA ******/
+ code = (*dev_proc(tdev, copy_alpha))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[1], depth);
+ }
+ else
+ { if ( state.lop_enabled )
+ { pcolor = NULL;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ code = (*dev_proc(tdev, copy_color))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height);
+ }
+ data_x = 0;
+ break;
+ default: /* can't happen */
+ goto bad_op;
+ }
+ }
+ /* Clean up before we exit. */
+out: gx_cpath_release(&clip_path);
+ gx_path_release(&path);
+ if ( imager_state.ht_cache )
+ gx_ht_free_cache(mem, imager_state.ht_cache);
+ gx_device_halftone_release(&dev_ht, mem);
+ gs_imager_state_release(&imager_state);
+ gs_free_object(mem, data_bits, "clist_playback_band(data_bits)");
+ if ( code < 0 )
+ return_error(code);
+ /* Check whether we have more pages to process. */
+ if ( playback_action != playback_action_setup &&
+ ( cbp < cb_end || !seofp(s) ) )
+ goto in;
+ return code;
+}
+
+/* Unpack a short bitmap */
+private void
+clist_unpack_short_bits(byte *dest, const byte *src, register int width_bytes,
+ int height, uint raster)
+{ uint bytes = width_bytes * height;
+ const byte *pdata = src + bytes;
+ byte *udata = dest + height * raster;
+ while ( --height >= 0 )
+ { udata -= raster, pdata -= width_bytes;
+ switch ( width_bytes )
+ {
+ default: memmove(udata, pdata, width_bytes); break;
+ case 6: udata[5] = pdata[5];
+ case 5: udata[4] = pdata[4];
+ case 4: udata[3] = pdata[3];
+ case 3: udata[2] = pdata[2];
+ case 2: udata[1] = pdata[1];
+ case 1: udata[0] = pdata[0];
+ case 0: ; /* shouldn't happen */
+ }
+ }
+}
+
+/* Read a rectangle. */
+private const byte *
+cmd_read_rect(int op, register gx_cmd_rect *prect, register const byte *cbp)
+{ cmd_getw(prect->x, cbp);
+ if ( op & 0xf )
+ prect->y += ((op >> 2) & 3) - 2;
+ else
+ { cmd_getw(prect->y, cbp);
+ }
+ cmd_getw(prect->width, cbp);
+ if ( op & 0xf )
+ prect->height += (op & 3) - 2;
+ else
+ { cmd_getw(prect->height, cbp);
+ }
+ return cbp;
+}
+
+/* Read a transformation matrix. */
+private const byte *
+cmd_read_matrix(gs_matrix *pmat, const byte *cbp)
+{ byte b = *cbp++;
+ float coeff[6];
+ int i;
+
+ for ( i = 0; i < 4; i += 2, b <<= 2 )
+ if ( !(b & 0xc0) )
+ coeff[i] = coeff[i^3] = 0.0;
+ else
+ { float value;
+ cmd_get_value(value, cbp);
+ coeff[i] = value;
+ switch ( (b >> 6) & 3 )
+ {
+ case 1:
+ coeff[i^3] = value; break;
+ case 2:
+ coeff[i^3] = -value; break;
+ case 3:
+ cmd_get_value(coeff[i^3], cbp);
+ }
+ }
+ for ( ; i < 6; ++i, b <<= 1 )
+ if ( b & 0x80 )
+ { cmd_get_value(coeff[i], cbp);
+ }
+ else
+ coeff[i] = 0.0;
+ pmat->xx = coeff[0];
+ pmat->xy = coeff[1];
+ pmat->yx = coeff[2];
+ pmat->yy = coeff[3];
+ pmat->tx = coeff[4];
+ pmat->ty = coeff[5];
+ return cbp;
+}
+
+/* Select a map for loading with data. */
+/* load = false is not possible for cmd_map_transfer*. */
+private int
+cmd_select_map(cmd_map_index map_index, bool load, gs_imager_state *pis,
+ gx_ht_order *porder, frac **pmdata, uint *pcount, gs_memory_t *mem)
+{ gx_transfer_map *map;
+ gx_transfer_map **pmap;
+ const char _ds *cname;
+
+ switch ( map_index )
+ {
+ case cmd_map_transfer:
+ if_debug0('L', " transfer");
+ map = pis->set_transfer.colored.gray;
+ pis->effective_transfer.indexed[0] =
+ pis->effective_transfer.indexed[1] =
+ pis->effective_transfer.indexed[2] =
+ pis->effective_transfer.indexed[3] =
+ map;
+ break;
+ case cmd_map_transfer_0:
+ case cmd_map_transfer_1:
+ case cmd_map_transfer_2:
+ case cmd_map_transfer_3:
+ { int i = map_index - cmd_map_transfer_0;
+
+ if_debug1('L', " transfer[%d]", i);
+ rc_unshare_struct(pis->set_transfer.indexed[i], gx_transfer_map,
+ &st_transfer_map, mem,
+ return_error(gs_error_VMerror),
+ "cmd_select_map(transfer)");
+ map = pis->set_transfer.indexed[i];
+ pis->effective_transfer.indexed[i] = map;
+ }
+ break;
+ case cmd_map_ht_transfer:
+ if_debug0('L', " ht transfer");
+ /* Halftone transfer maps are never shared, but */
+ /* rc_unshare_struct is a good way to get one allocated */
+ /* if it hasn't been yet. */
+ pmap = &porder->transfer;
+ cname = "cmd_select_map(ht transfer)";
+ goto alloc;
+ case cmd_map_black_generation:
+ if_debug0('L', " black generation");
+ pmap = &pis->black_generation;
+ cname = "cmd_select_map(black generation)";
+ goto alloc;
+ case cmd_map_undercolor_removal:
+ if_debug0('L', " undercolor removal");
+ pmap = &pis->undercolor_removal;
+ cname = "cmd_select_map(undercolor removal)";
+alloc: if ( !load )
+ { rc_decrement(*pmap, cname);
+ *pmap = 0;
+ *pmdata = 0;
+ *pcount = 0;
+ return 0;
+ }
+ rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map,
+ mem, return_error(gs_error_VMerror), cname);
+ map = *pmap;
+ break;
+ default:
+ *pmdata = 0;
+ return 0;
+ }
+ map->proc = gs_mapped_transfer;
+ *pmdata = map->values;
+ *pcount = sizeof(map->values);
+ return 0;
+}
+
+/* Install a halftone order, resizing the bits and levels if necessary. */
+private int
+cmd_install_ht_order(gx_ht_order *porder, const gx_ht_order *pnew,
+ gs_memory_t *mem)
+{ uint *levels = porder->levels;
+ gx_ht_bit *bits = porder->bits;
+
+ /*
+ * Note that for resizing a byte array, the element size is 1 byte,
+ * not the element size given to alloc_byte_array!
+ */
+ if ( pnew->num_levels > porder->num_levels )
+ { if ( levels == 0 )
+ levels = (uint *)gs_alloc_byte_array(mem, pnew->num_levels,
+ sizeof(*levels),
+ "ht order(levels)");
+ else
+ levels = gs_resize_object(mem, levels,
+ pnew->num_levels * sizeof(*levels),
+ "ht order(levels)");
+ if ( levels == 0 )
+ return_error(gs_error_VMerror);
+ /* Update porder in case we bail out. */
+ porder->levels = levels;
+ porder->num_levels = pnew->num_levels;
+ }
+ if ( pnew->num_bits > porder->num_bits )
+ { if ( bits == 0 )
+ bits = (gx_ht_bit *)gs_alloc_byte_array(mem, pnew->num_bits,
+ sizeof(*bits),
+ "ht order(bits)");
+ else
+ bits = gs_resize_object(mem, bits,
+ pnew->num_bits * sizeof(*bits),
+ "ht order(bits)");
+ if ( bits == 0 )
+ return_error(gs_error_VMerror);
+ }
+ *porder = *pnew;
+ porder->levels = levels;
+ porder->bits = bits;
+ porder->full_height = ht_order_full_height(porder);
+ return 0;
+}
+
+/* Resize the halftone components array if necessary. */
+private int
+cmd_resize_halftone(gx_device_halftone *pdht, uint num_comp,
+ gs_memory_t *mem)
+{ if ( num_comp != pdht->num_comp ) {
+ gx_ht_order_component *pcomp;
+
+ /*
+ * We must be careful not to shrink or free the components array
+ * before releasing any relevant elements.
+ */
+ if ( num_comp < pdht->num_comp ) {
+ uint i;
+ /* Don't release the default order. */
+ for ( i = pdht->num_comp; i-- > num_comp; )
+ if ( pdht->components[i].corder.bits != pdht->order.bits )
+ gx_ht_order_release(&pdht->components[i].corder, mem, true);
+ if ( num_comp == 0 ) {
+ gs_free_object(mem, pdht->components, "cmd_resize_halftone");
+ pcomp = 0;
+ } else {
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if ( pcomp == 0 ) {
+ pdht->num_comp = num_comp; /* attempt consistency */
+ return_error(gs_error_VMerror);
+ }
+ }
+ } else {
+ /* num_comp > pdht->num_comp */
+ if ( pdht->num_comp == 0 )
+ pcomp = gs_alloc_struct_array(mem, num_comp,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "cmd_resize_halftone");
+ else
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if ( pcomp == 0 )
+ return_error(gs_error_VMerror);
+ memset(&pcomp[pdht->num_comp], 0,
+ sizeof(*pcomp) * (num_comp - pdht->num_comp));
+ }
+ pdht->num_comp = num_comp;
+ pdht->components = pcomp;
+ }
+ return 0;
+}
+
+/* ------ Path operations ------ */
+
+/* Decode a path segment. */
+private int
+clist_decode_segment(gx_path *ppath, int op, fixed vs[6],
+ gs_fixed_point *ppos, int x0, int y0, segment_notes notes)
+{ fixed px = ppos->x - int2fixed(x0);
+ fixed py = ppos->y - int2fixed(y0);
+ int code;
+#define A vs[0]
+#define B vs[1]
+#define C vs[2]
+#define D vs[3]
+#define E vs[4]
+#define F vs[5]
+
+ switch ( op )
+ {
+ case cmd_opv_rmoveto:
+ code = gx_path_add_point(ppath, px += A, py += B);
+ break;
+ case cmd_opv_rlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py += B, notes);
+ break;
+ case cmd_opv_hlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py, notes);
+ break;
+ case cmd_opv_vlineto:
+ code = gx_path_add_line_notes(ppath, px, py += A, notes);
+ break;
+ case cmd_opv_rrcurveto: /* a b c d e f => a b a+c b+d a+c+e b+d+f */
+ E += (C += A);
+ F += (D += B);
+curve: code = gx_path_add_curve_notes(ppath, px + A, py + B,
+ px + C, py + D,
+ px + E, py + F, notes);
+ px += E, py += F;
+ break;
+ case cmd_opv_hvcurveto: /* a b c d => a 0 a+b c a+b c+d */
+hvc: F = C + D, D = C, E = C = A + B, B = 0;
+ goto curve;
+ case cmd_opv_vhcurveto: /* a b c d => 0 a b a+c b+d a+c */
+vhc: E = B + D, F = D = A + C, C = B, B = A, A = 0;
+ goto curve;
+ case cmd_opv_nrcurveto: /* a b c d => 0 0 a b a+c b+d */
+ F = B + D, E = A + C, D = B, C = A, B = A = 0;
+ goto curve;
+ case cmd_opv_rncurveto: /* a b c d => a b a+c b+d a+c b+d */
+ F = D += B, E = C += A;
+ goto curve;
+ case cmd_opv_rmlineto:
+ if ( (code = gx_path_add_point(ppath, px += A, py += B)) < 0 )
+ break;
+ code = gx_path_add_line_notes(ppath, px += C, py += D, notes);
+ break;
+ case cmd_opv_rm2lineto:
+ if ( (code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px += E, py += F, notes);
+ break;
+ case cmd_opv_vqcurveto: /* a b => VH a b TS(a,b) TS(b,a) */
+ if ( (A ^ B) < 0 )
+ C = -B, D = -A;
+ else
+ C = B, D = A;
+ goto vhc;
+ case cmd_opv_hqcurveto: /* a b => HV a TS(a,b) b TS(b,a) */
+ if ( (A ^ B) < 0 )
+ D = -A, C = B, B = -B;
+ else
+ D = A, C = B;
+ goto hvc;
+ case cmd_opv_rm3lineto:
+ if ( (code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += E, py += F,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px -= C, py -= D, notes);
+ break;
+ case cmd_opv_closepath:
+ code = gx_path_close_subpath(ppath);
+ gx_path_current_point(ppath, (gs_fixed_point *)vs);
+ px = A, py = B;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+ ppos->x = px + int2fixed(x0);
+ ppos->y = py + int2fixed(y0);
+ return code;
+}
diff --git a/gs/src/gxclrect.c b/gs/src/gxclrect.c
new file mode 100644
index 000000000..ee4c172a4
--- /dev/null
+++ b/gs/src/gxclrect.c
@@ -0,0 +1,616 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclrect.c */
+/* Rectangle-oriented command writing for command list */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+
+#define cdev cwdev
+
+/* ---------------- Writing utilities ---------------- */
+
+#define cmd_set_rect(rect)\
+ ((rect).x = x, (rect).y = y,\
+ (rect).width = width, (rect).height = height)
+
+/* Write a rectangle. */
+private int
+cmd_size_rect(register const gx_cmd_rect *prect)
+{ return
+ cmd_sizew(prect->x) + cmd_sizew(prect->y) +
+ cmd_sizew(prect->width) + cmd_sizew(prect->height);
+}
+private byte *
+cmd_put_rect(register const gx_cmd_rect *prect, register byte *dp)
+{ cmd_putw(prect->x, dp);
+ cmd_putw(prect->y, dp);
+ cmd_putw(prect->width, dp);
+ cmd_putw(prect->height, dp);
+ return dp;
+}
+
+int
+cmd_write_rect_cmd(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ int op, int x, int y, int width, int height)
+{ int code;
+ int dx = x - pcls->rect.x;
+ int dy = y - pcls->rect.y;
+ int dwidth = width - pcls->rect.width;
+ int dheight = height - pcls->rect.height;
+#define check_range_xy(rmin, rmax)\
+ ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
+ (unsigned)(dy - rmin) <= (rmax - rmin))
+#define check_range_w(rmin, rmax)\
+ ((unsigned)(dwidth - rmin) <= (rmax - rmin))
+#define check_ranges(rmin, rmax)\
+ (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
+ (unsigned)(dheight - rmin) <= (rmax - rmin))
+ cmd_set_rect(pcls->rect);
+ if ( dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
+ check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
+ )
+ { byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
+ byte *dp;
+
+ if ( dx == width - dwidth && dy == 0 )
+ { code = set_cmd_put_op(dp, cldev, pcls, op_tiny + 8, 1);
+ if (code < 0)
+ return code;
+ }
+ else
+ { code = set_cmd_put_op(dp, cldev, pcls, op_tiny, 2);
+ if (code < 0)
+ return code;
+ dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
+ }
+ }
+#define rmin cmd_min_short
+#define rmax cmd_max_short
+ else if ( check_ranges(rmin, rmax) )
+ { int dh = dheight - cmd_min_dxy_tiny;
+ byte *dp;
+
+ if ( (unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
+ dh != 0 && dy == 0
+ )
+ { op += dh;
+ code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 3);
+ if (code < 0)
+ return code;
+ if_debug3('L', " rs2:%d,%d,0,%d\n",
+ dx, dwidth, dheight);
+ }
+ else
+ { code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 5);
+ if (code < 0)
+ return code;
+ if_debug4('L', " rs4:%d,%d,%d,%d\n",
+ dx, dwidth, dy, dheight);
+ dp[3] = dy - rmin;
+ dp[4] = dheight - rmin;
+ }
+ dp[1] = dx - rmin;
+ dp[2] = dwidth - rmin;
+ }
+#undef rmin
+#undef rmax
+ else if ( dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
+ (dy + dheight) != -4
+ )
+ { byte *dp;
+ int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
+ code = set_cmd_put_op(dp, cldev, pcls,
+ op + ((dy + 2) << 2) + dheight + 2, rcsize);
+ if (code < 0)
+ return code;
+ ++dp;
+ cmd_put2w(x, width, dp);
+ }
+ else
+ { byte *dp;
+ int rcsize = 1 + cmd_size_rect(&pcls->rect);
+ code = set_cmd_put_op(dp, cldev, pcls, op, rcsize);
+ if (code < 0)
+ return code;
+ if_debug5('L', " r%d:%d,%d,%d,%d\n",
+ rcsize - 1, dx, dwidth, dy, dheight);
+ cmd_put_rect(&pcls->rect, dp + 1);
+ }
+ return 0;
+}
+
+/* ---------------- Driver procedures ---------------- */
+
+int
+clist_fill_rectangle(gx_device *dev, int x, int y, int width, int height,
+ gx_color_index color)
+{ int code;
+ fit_fill(dev, x, y, width, height);
+ BEGIN_RECT
+ TRY_RECT
+ code = cmd_disable_lop(cdev, pcls);
+ if ( color != pcls->colors[1] )
+ code = code < 0 ? code :
+ cmd_put_color(cdev, pcls, &clist_select_color1,
+ color, &pcls->colors[1]);
+ code = code < 0 ? code :
+ cmd_write_rect_cmd(cdev, pcls, cmd_op_fill_rect, x, y,
+ width, height);
+ HANDLE_RECT(code);
+ END_RECT
+ return 0;
+}
+
+int
+clist_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tile,
+ int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1, int px, int py)
+{ int code;
+ int depth =
+ (color1 == gx_no_color_index && color0 == gx_no_color_index ?
+ dev->color_info.depth : 1);
+
+ fit_fill(dev, x, y, width, height);
+ BEGIN_RECT
+ ulong offset_temp;
+
+ TRY_RECT
+ code = cmd_disable_lop(cdev, pcls);
+ HANDLE_RECT(code);
+ if ( !cls_has_tile_id(cdev, pcls, tile->id, offset_temp) )
+ { code = 0;
+ if (tile->id != gx_no_bitmap_id)
+ TRY_RECT
+ code = clist_change_tile(cdev, pcls, tile, depth);
+ HANDLE_RECT_UNLESS( code,
+ (code != gs_error_VMerror || !cdev->error_is_retryable) );
+ if (code < 0)
+ {
+ /* ok if gx_default... does retries internally: it's self-sufficient */
+ code =
+ gx_default_strip_tile_rectangle(dev, tile,
+ x, y, width, height,
+ color0, color1, px, py);
+ if ( code < 0 )
+ ERROR_RECT(code);
+ goto endr;
+ }
+ }
+ TRY_RECT
+ code = 0;
+ if ( color0 != pcls->tile_colors[0] || color1 != pcls->tile_colors[1] )
+ code = cmd_set_tile_colors(cdev, pcls, color0, color1);
+ if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
+ code = code < 0 ? code : cmd_set_tile_phase(cdev, pcls, px, py);
+ code = code < 0 ? code :
+ cmd_write_rect_cmd(cdev, pcls, cmd_op_tile_rect, x, y,
+ width, height);
+ HANDLE_RECT(code);
+endr: ;
+ END_RECT
+ return 0;
+}
+
+int
+clist_copy_mono(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1)
+{ int y0;
+ gx_bitmap_id orig_id = id;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ BEGIN_RECT
+ int dx = data_x & 7;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x >> 3);
+ int code;
+
+ TRY_RECT
+ code = cmd_disable_lop(cdev, pcls);
+ code = code < 0 ? code : cmd_disable_clip(cdev, pcls);
+ if ( color0 != pcls->colors[0] )
+ code = code < 0 ? code : cmd_set_color0(cdev, pcls, color0);
+ if ( color1 != pcls->colors[1] )
+ code = code < 0 ? code : cmd_set_color1(cdev, pcls, color1);
+ HANDLE_RECT(code);
+ /* Don't bother to check for a possible cache hit: */
+ /* tile_rectangle and fill_mask handle those cases. */
+copy: { gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte)cmd_op_copy_mono;
+ byte *dp;
+ uint csize;
+ uint compress;
+ int code;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
+ TRY_RECT
+ code = cmd_put_bits(cdev, pcls, row, w1, height, raster,
+ rsize, (orig_id == gx_no_bitmap_id ?
+ 1 << cmd_compress_rle :
+ cmd_mask_compress_any),
+ &dp, &csize);
+ HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+
+ compress = (uint)code;
+ if ( code < 0 )
+ { /* The bitmap was too large; split up the transfer. */
+ if ( height > 1 )
+ { /* Split the transfer by reducing the height.
+ * See the comment above BEGIN_RECT in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ }
+ { /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+ NEST_RECT;
+ code = clist_copy_mono(dev, row, dx,
+ raster, gx_no_bitmap_id, x, y,
+ w2, 1, color0, color1);
+ if (code >= 0)
+ code = clist_copy_mono(dev, row, dx + w2,
+ raster, gx_no_bitmap_id, x + w2, y,
+ w1 - w2, 1, color0, color1);
+ UNNEST_RECT;
+ if ( code < 0 )
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if ( dx )
+ { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+ }
+ END_RECT
+ return 0;
+}
+
+int
+clist_copy_color(gx_device *dev,
+ const byte *data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height)
+{ int depth = dev->color_info.depth;
+ int y0;
+ int data_x_bit;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ data_x_bit = data_x * depth;
+ BEGIN_RECT
+ int dx = (data_x_bit & 7) / depth;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT
+ code = cmd_disable_lop(cdev, pcls);
+ code = code < 0 ? code : cmd_disable_clip(cdev, pcls);
+ HANDLE_RECT(code);
+ if ( pcls->color_is_alpha )
+ { byte *dp;
+ TRY_RECT
+ code= set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_color, 1);
+ HANDLE_RECT(code);
+ pcls->color_is_alpha = 0;
+ }
+copy: { gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte)cmd_op_copy_color_alpha;
+ byte *dp;
+ uint csize;
+ uint compress;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
+ TRY_RECT
+ code = cmd_put_bits(cdev, pcls, row, w1 * depth,
+ height, raster, rsize,
+ 1 << cmd_compress_rle, &dp, &csize);
+ HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+
+ compress = (uint)code;
+ if ( code < 0 )
+ { /* The bitmap was too large; split up the transfer. */
+ if ( height > 1 )
+ { /* Split the transfer by reducing the height.
+ * See the comment above BEGIN_RECT in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ }
+ { /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+ NEST_RECT;
+ code = clist_copy_color(dev, row, dx,
+ raster, gx_no_bitmap_id, x, y,
+ w2, 1);
+ if (code >= 0)
+ code = clist_copy_color(dev, row, dx + w2,
+ raster, gx_no_bitmap_id, x + w2, y,
+ w1 - w2, 1);
+ UNNEST_RECT;
+ if ( code < 0 )
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if ( dx )
+ { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+
+ }
+ END_RECT
+ return 0;
+}
+
+int
+clist_copy_alpha(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ /* I don't like copying the entire body of clist_copy_color */
+ /* just to change 2 arguments and 1 opcode, */
+ /* but I don't see any alternative that doesn't require */
+ /* another level of procedure call even in the common case. */
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ int y0;
+ int data_x_bit;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ data_x_bit = data_x << log2_depth;
+ BEGIN_RECT
+ int dx = (data_x_bit & 7) >> log2_depth;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT
+ code = cmd_disable_lop(cdev, pcls);
+ code = code < 0 ? code : cmd_disable_clip(cdev, pcls);
+ HANDLE_RECT(code);
+ if ( !pcls->color_is_alpha )
+ { byte *dp;
+ TRY_RECT
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
+ HANDLE_RECT(code);
+ pcls->color_is_alpha = 1;
+ }
+ if ( color != pcls->colors[1] )
+ { TRY_RECT
+ code = cmd_set_color1(cdev, pcls, color);
+ HANDLE_RECT(code);
+ }
+copy: { gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte)cmd_op_copy_color_alpha;
+ byte *dp;
+ uint csize;
+ uint compress;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
+ TRY_RECT
+ code = cmd_put_bits(cdev, pcls, row, w1 << log2_depth,
+ height, raster, rsize,
+ 1 << cmd_compress_rle, &dp, &csize);
+ HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ compress = (uint)code;
+ if ( code < 0 )
+ { /* The bitmap was too large; split up the transfer. */
+ if ( height > 1 )
+ { /* Split the transfer by reducing the height.
+ * See the comment above BEGIN_RECT in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ }
+ { /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+ NEST_RECT;
+ code = clist_copy_alpha(dev, row, dx,
+ raster, gx_no_bitmap_id, x, y,
+ w2, 1, color, depth);
+ if (code >= 0)
+ code = clist_copy_alpha(dev, row, dx + w2,
+ raster, gx_no_bitmap_id, x + w2, y,
+ w1 - w2, 1, color, depth);
+ UNNEST_RECT;
+ if ( code < 0 )
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if ( dx )
+ { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ *dp++ = depth;
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+ }
+ END_RECT
+ return 0;
+}
+
+int
+clist_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ gs_rop3_t rop = lop_rop(lop);
+ gx_strip_bitmap tile_with_id;
+ const gx_strip_bitmap *tiles = textures;
+ int y0;
+
+ if ( scolors != 0 && scolors[0] != scolors[1] )
+ { fit_fill(dev, x, y, width, height);
+ }
+ else
+ { fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
+ }
+ y0 = y;
+ /*
+ * We shouldn't need to put the logic below inside BEGIN/END_RECT,
+ * but the lop_enabled flags are per-band.
+ */
+ BEGIN_RECT
+ const byte *row = sdata + (y - y0) * sraster;
+ int code;
+
+ if ( rop3_uses_T(rop) )
+ { if ( tcolors == 0 || tcolors[0] != tcolors[1] )
+ { ulong offset_temp;
+ if ( !cls_has_tile_id(cdev, pcls, tiles->id, offset_temp) )
+ { /* Change tile. If there is no id, generate one. */
+ if ( tiles->id == gx_no_bitmap_id )
+ { tile_with_id = *tiles;
+ tile_with_id.id = gs_next_ids(1);
+ tiles = &tile_with_id;
+ }
+ TRY_RECT
+ code = clist_change_tile(cdev, pcls, tiles,
+ (tcolors != 0 ? 1 :
+ dev->color_info.depth));
+ HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ if ( code < 0 )
+ { /*
+ * The error is a limitcheck, so we have a tile that
+ * is too big to fit in the command reading buffer.
+ * For now, just divide up the transfer into scan
+ * lines. (If a single scan line won't fit, punt.)
+ * Eventually, we'll need a way to transfer the tile
+ * in pieces.
+ */
+ uint rep_height = tiles->rep_height;
+ gs_id ids;
+ gx_strip_bitmap line_tile;
+ int iy;
+
+ if ( rep_height == 1 ||
+ /****** CAN'T HANDLE SHIFT YET ******/
+ tiles->rep_shift != 0
+ )
+ return code;
+ /*
+ * Allocate enough fake IDs, since the inner call on
+ * clist_strip_copy_rop will need them anyway.
+ */
+ ids = gs_next_ids(min(height, rep_height));
+ line_tile = *tiles;
+ line_tile.size.y = 1;
+ line_tile.rep_height = 1;
+ for ( iy = 0; iy < height; ++iy )
+ { line_tile.data = tiles->data + line_tile.raster *
+ ((y + iy + phase_y) % rep_height);
+ line_tile.id = ids + (iy % rep_height);
+ /*
+ * Note that since we're only transferring
+ * a single scan line, phase_y is irrelevant;
+ * we may as well use the current tile phase
+ * so we don't have to write extra commands.
+ */
+ /* All strips must go out in same band list */
+ NEST_RECT;
+ code = clist_strip_copy_rop(dev,
+ (sdata == 0 ? 0 : row + iy * sraster),
+ sourcex, sraster,
+ gx_no_bitmap_id, scolors, &line_tile, tcolors,
+ x, y + iy, width, 1,
+ phase_x, pcls->tile_phase.y, lop);
+ UNNEST_RECT;
+ if ( code < 0 )
+ ERROR_RECT(code);
+ }
+ continue;
+ }
+ if ( phase_x != pcls->tile_phase.x ||
+ phase_y != pcls->tile_phase.y
+ )
+ TRY_RECT
+ code = cmd_set_tile_phase(cdev, pcls, phase_x,
+ phase_y);
+ HANDLE_RECT(code);
+ }
+ }
+ /* Set the tile colors. */
+ TRY_RECT
+ code = (tcolors != 0 ?
+ cmd_set_tile_colors(cdev, pcls, tcolors[0], tcolors[1]) :
+ cmd_set_tile_colors(cdev, pcls, gx_no_color_index,
+ gx_no_color_index));
+ HANDLE_RECT(code);
+ }
+ TRY_RECT
+ code = 0;
+ if ( lop != pcls->lop )
+ code = cmd_set_lop(cdev, pcls, lop);
+ code = code < 0 ? code :cmd_enable_lop(cdev, pcls);
+ HANDLE_RECT(code);
+
+ /* Set lop_enabled to -1 so that fill_rectangle / copy_* */
+ /* won't attempt to set it to 0. */
+ pcls->lop_enabled = -1;
+ NEST_RECT;
+ if ( scolors != 0 )
+ { if ( scolors[0] == scolors[1] )
+ code = clist_fill_rectangle(dev, x, y, width, height,
+ scolors[1]);
+ else
+ code = clist_copy_mono(dev, row, sourcex, sraster, id,
+ x, y, width, height,
+ scolors[0], scolors[1]);
+ }
+ else
+ code = clist_copy_color(dev, row, sourcex, sraster, id,
+ x, y, width, height);
+ UNNEST_RECT;
+ pcls->lop_enabled = 1;
+ if ( code < 0 )
+ ERROR_RECT(code);
+ END_RECT
+ return 0;
+}
diff --git a/gs/src/gxclzlib.c b/gs/src/gxclzlib.c
new file mode 100644
index 000000000..24db9d03f
--- /dev/null
+++ b/gs/src/gxclzlib.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxclzlib.c */
+/* zlib filter initialization for RAM-based band lists */
+/* Must be compiled with -I$(ZSRCDIR) */
+#include "std.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gxclmem.h"
+#include "szlibx.h"
+
+private stream_zlib_state cl_zlibE_state;
+private stream_zlib_state cl_zlibD_state;
+
+/* Initialize the states to be copied. */
+void
+gs_cl_zlib_init(gs_memory_t *mem)
+{ s_zlib_set_defaults((stream_state *)&cl_zlibE_state);
+ cl_zlibE_state.no_wrapper = true;
+ cl_zlibE_state.template = &s_zlibE_template;
+ s_zlib_set_defaults((stream_state *)&cl_zlibD_state);
+ cl_zlibD_state.no_wrapper = true;
+ cl_zlibD_state.template = &s_zlibD_template;
+}
+
+/* Return the prototypes for compressing/decompressing the band list. */
+const stream_state *
+clist_compressor_state(void *client_data)
+{ return (const stream_state *)&cl_zlibE_state;
+}
+const stream_state *
+clist_decompressor_state(void *client_data)
+{ return (const stream_state *)&cl_zlibD_state;
+}
diff --git a/gs/src/gxcmap.c b/gs/src/gxcmap.c
new file mode 100644
index 000000000..09fba9b98
--- /dev/null
+++ b/gs/src/gxcmap.c
@@ -0,0 +1,776 @@
+/* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcmap.c */
+/* Color mapping for Ghostscript */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxfarith.h"
+#include "gxfrac.h"
+#include "gxdcconv.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxlum.h"
+#include "gzstate.h"
+#include "gxdither.h"
+
+/* Structure descriptor */
+public_st_device_color();
+#define cptr ((gx_device_color *)vptr)
+private ENUM_PTRS_BEGIN(device_color_enum_ptrs) {
+ struct_proc_enum_ptrs((*proc)) = cptr->type->enum_ptrs;
+ if ( proc == 0 )
+ return 0;
+ return (*proc)(vptr, size, index, pep);
+} ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_color_reloc_ptrs) {
+ struct_proc_reloc_ptrs((*proc)) = cptr->type->reloc_ptrs;
+ if ( proc != 0 )
+ (*proc)(vptr, size, gcst);
+} RELOC_PTRS_END
+#undef cptr
+
+/* ------ Trace device mapping procedures ------ */
+
+/* If DEBUG is defined, these procedures substitute for direct calls */
+/* on the device map_{rgb,cmyk}_color procedures. */
+
+gx_color_index
+gx_proc_map_rgb_color(gx_device *dev,
+ gx_color_value vr, gx_color_value vg, gx_color_value vb)
+{ gx_color_index cindex =
+ (*dev_proc(dev, map_rgb_color))(dev, vr, vg, vb);
+ if_debug5('C', "%s [C]RGB %u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint)vr, (uint)vg, (uint)vb, (ulong)cindex);
+ return cindex;
+}
+
+gx_color_index
+gx_proc_map_rgb_alpha_color(gx_device *dev,
+ gx_color_value vr, gx_color_value vg, gx_color_value vb, gx_color_value va)
+{ gx_color_index cindex =
+ (*dev_proc(dev, map_rgb_alpha_color))(dev, vr, vg, vb, va);
+ if_debug6('C', "[C]%s RGBA %u,%u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint)vr, (uint)vg, (uint)vb, (uint)va,
+ (ulong)cindex);
+ return cindex;
+}
+
+gx_color_index
+gx_proc_map_cmyk_color(gx_device *dev,
+ gx_color_value vc, gx_color_value vm, gx_color_value vy, gx_color_value vk)
+{ gx_color_index cindex =
+ (*dev_proc(dev, map_cmyk_color))(dev, vc, vm, vy, vk);
+ if_debug6('C', "[C]%s CMYK %u,%u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint)vc, (uint)vm, (uint)vy, (uint)vk,
+ (ulong)cindex);
+ return cindex;
+}
+
+/* ---------------- Device color rendering ---------------- */
+
+private cmap_proc_gray(cmap_gray_halftoned);
+private cmap_proc_gray(cmap_gray_direct);
+private cmap_proc_gray(cmap_gray_to_rgb_halftoned);
+private cmap_proc_gray(cmap_gray_to_rgb_direct);
+private cmap_proc_gray(cmap_gray_to_cmyk_halftoned);
+private cmap_proc_gray(cmap_gray_to_cmyk_direct);
+private cmap_proc_rgb(cmap_rgb_halftoned);
+private cmap_proc_rgb(cmap_rgb_direct);
+private cmap_proc_rgb(cmap_rgb_to_gray_halftoned);
+private cmap_proc_rgb(cmap_rgb_to_gray_direct);
+private cmap_proc_rgb(cmap_rgb_to_cmyk);
+#define cmap_cmyk_halftoned cmap_cmyk_direct
+private cmap_proc_cmyk(cmap_cmyk_direct);
+private cmap_proc_cmyk(cmap_cmyk_to_gray);
+private cmap_proc_cmyk(cmap_cmyk_to_rgb);
+#ifdef DPNEXT
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_halftoned);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_direct);
+/* Procedure names are only guaranteed unique to 23 characters.... */
+private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_halftoned);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_direct);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_to_cmyk);
+#endif
+
+private const gx_color_map_procs
+ cmap_gray_few =
+ { cmap_gray_halftoned, cmap_rgb_to_gray_halftoned, cmap_cmyk_to_gray
+#ifdef DPNEXT
+ , cmap_rgb_alpha2gray_halftoned
+#endif
+ },
+ cmap_gray_many =
+ { cmap_gray_direct, cmap_rgb_to_gray_direct, cmap_cmyk_to_gray
+#ifdef DPNEXT
+ , cmap_rgb_alpha2gray_direct
+#endif
+ },
+ cmap_rgb_few =
+ { cmap_gray_to_rgb_halftoned, cmap_rgb_halftoned, cmap_cmyk_to_rgb
+#ifdef DPNEXT
+ , cmap_rgb_alpha_halftoned
+#endif
+ },
+ cmap_rgb_many =
+ { cmap_gray_to_rgb_direct, cmap_rgb_direct, cmap_cmyk_to_rgb
+#ifdef DPNEXT
+ , cmap_rgb_alpha_direct
+#endif
+ },
+ cmap_cmyk_few =
+ { cmap_gray_to_cmyk_halftoned, cmap_rgb_to_cmyk, cmap_cmyk_halftoned
+#ifdef DPNEXT
+ , cmap_rgb_alpha_to_cmyk
+#endif
+ },
+ cmap_cmyk_many =
+ { cmap_gray_to_cmyk_direct, cmap_rgb_to_cmyk, cmap_cmyk_direct
+#ifdef DPNEXT
+ , cmap_rgb_alpha_to_cmyk
+#endif
+ };
+
+const gx_color_map_procs *cmap_procs_default = &cmap_gray_many;
+
+private const gx_color_map_procs _ds *cmap_few[] = {
+ 0, &cmap_gray_few, 0, &cmap_rgb_few, &cmap_cmyk_few
+};
+
+private const gx_color_map_procs _ds *cmap_many[] = {
+ 0, &cmap_gray_many, 0, &cmap_rgb_many, &cmap_cmyk_many
+};
+
+/* Determine the color mapping procedures for a device. */
+const gx_color_map_procs *
+gx_device_cmap_procs(const gx_device *dev)
+{ return ((gx_device_has_color(dev) ? dev->color_info.max_color :
+ dev->color_info.max_gray) >= 31 ? cmap_many : cmap_few)
+ [dev->color_info.num_components];
+}
+
+/* Set the color mapping procedures in the graphics state. */
+void
+gx_set_cmap_procs(gs_imager_state *pis, const gx_device *dev)
+{ pis->cmap_procs = gx_device_cmap_procs(dev);
+}
+
+/* Remap the color in the graphics state. */
+int
+gx_remap_color(gs_state *pgs)
+{ const gs_color_space *pcs = pgs->color_space;
+ /* The current color in the graphics state is always used for */
+ /* the texture, never for the source. */
+ return (*pcs->type->remap_color)(pgs->ccolor, pcs, pgs->dev_color,
+ (gs_imager_state *)pgs, pgs->device,
+ gs_color_select_texture);
+}
+
+/* Indicate that a color space has no underlying concrete space. */
+const gs_color_space *
+gx_no_concrete_space(const gs_color_space *pcs, const gs_imager_state *pis)
+{ return NULL;
+}
+
+/* Indicate that a color space is concrete. */
+const gs_color_space *
+gx_same_concrete_space(const gs_color_space *pcs, const gs_imager_state *pis)
+{ return pcs;
+}
+
+/* Indicate that a color cannot be concretized. */
+int
+gx_no_concretize_color(const gs_client_color *pcc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ return_error(gs_error_rangecheck);
+}
+
+/* By default, remap a color by concretizing it and then */
+/* remapping the concrete color. */
+int
+gx_default_remap_color(const gs_client_color *pcc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac conc[4];
+ const gs_color_space *pconcs;
+ int code = (*pcs->type->concretize_color)(pcc, pcs, conc, pis);
+
+ if ( code < 0 )
+ return code;
+ pconcs = cs_concrete_space(pcs, pis);
+ return (*pconcs->type->remap_concrete_color)(conc, pdc, pis, dev,
+ select);
+}
+
+/* Color remappers for the standard color spaces. */
+/* Note that we use D... instead of Device... in some places because */
+/* gcc under VMS only retains 23 characters of procedure names. */
+
+#define unit_frac(v, ftemp)\
+ (ftemp = (v),\
+ (is_fneg(ftemp) ? frac_0 : is_fge1(ftemp) ? frac_1 : float2frac(ftemp)))
+
+/* DeviceGray */
+int
+gx_concretize_DeviceGray(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ float ftemp;
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DGray(const frac *pconc,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ (*pis->cmap_procs->map_gray)
+ (pconc[0], pdc, pis, dev, select);
+ return 0;
+}
+int
+gx_remap_DeviceGray(const gs_client_color *pc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ float ftemp;
+ (*pis->cmap_procs->map_gray)
+ (unit_frac(pc->paint.values[0], ftemp),
+ pdc, pis, dev, select);
+ return 0;
+}
+
+/* DeviceRGB */
+int
+gx_concretize_DeviceRGB(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ float ftemp;
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ pconc[1] = unit_frac(pc->paint.values[1], ftemp);
+ pconc[2] = unit_frac(pc->paint.values[2], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DRGB(const frac *pconc,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2], pdc, pis, dev,
+ select);
+ return 0;
+}
+int
+gx_remap_DeviceRGB(const gs_client_color *pc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ float ft0, ft1, ft2;
+ gx_remap_concrete_rgb(unit_frac(pc->paint.values[0], ft0),
+ unit_frac(pc->paint.values[1], ft1),
+ unit_frac(pc->paint.values[2], ft2),
+ pdc, pis, dev, select);
+ return 0;
+}
+
+/* DeviceCMYK */
+int
+gx_concretize_DeviceCMYK(const gs_client_color *pc, const gs_color_space *pcs,
+ frac *pconc, const gs_imager_state *pis)
+{ float ftemp;
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ pconc[1] = unit_frac(pc->paint.values[1], ftemp);
+ pconc[2] = unit_frac(pc->paint.values[2], ftemp);
+ pconc[3] = unit_frac(pc->paint.values[3], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DCMYK(const frac *pconc,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3], pdc,
+ pis, dev, select);
+ return 0;
+}
+int
+gx_remap_DeviceCMYK(const gs_client_color *pc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ float ft0, ft1, ft2, ft3;
+ gx_remap_concrete_cmyk(unit_frac(pc->paint.values[0], ft0),
+ unit_frac(pc->paint.values[1], ft1),
+ unit_frac(pc->paint.values[2], ft2),
+ unit_frac(pc->paint.values[3], ft3),
+ pdc, pis, dev, select);
+ return 0;
+}
+
+/* ------ Render Gray color. ------ */
+
+private void
+cmap_gray_halftoned(frac gray, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ if ( gx_render_gray(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_direct(frac gray, gx_device_color *pdc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ gx_color_value cv_gray = frac2cv(mgray);
+ gx_color_index color =
+ (pis->alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
+ gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, pis->alpha));
+ if ( color == gx_no_color_index )
+ { if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+ return;
+ }
+ color_set_pure(pdc, color);
+}
+
+private void
+cmap_gray_to_rgb_halftoned(frac gray, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ cmap_rgb_halftoned(gray, gray, gray, pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_rgb_direct(frac gray, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ cmap_rgb_direct(gray, gray, gray, pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_cmyk_halftoned(frac gray, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ /*
+ * Per the last paragraph of section 6.3 (p. 309) of the
+ * PostScript Language Reference Manual, 2nd Edition,
+ * we must bypass the C, M, and Y transfer functions in this case.
+ */
+ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_cmyk_direct(frac gray, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ /*
+ * Per the last paragraph of section 6.3 (p. 309) of the
+ * PostScript Language Reference Manual, 2nd Edition,
+ * we must bypass the C, M, and Y transfer functions in this case.
+ */
+ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ frac mblack = frac_1 - mgray;
+ gx_color_index color =
+ gx_map_cmyk_color(dev,
+ frac2cv(frac_0), frac2cv(frac_0),
+ frac2cv(frac_0), frac2cv(mblack));
+ if ( color != gx_no_color_index )
+ { color_set_pure(pdc, color);
+ return;
+ }
+ if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+/* ------ Render RGB color. ------ */
+
+/*
+ * This code should test r == g and g == b and then use the gray
+ * rendering procedures. The Adobe documentation allows this:
+ * conversion between color spaces occurs before the transfer function
+ * and halftoning. However, output from FrameMaker (mis)uses the
+ * transfer function to provide the equivalent of indexed color;
+ * it requires the color components to be passed through unchanged.
+ * For this reason, we have to make the check after the transfer
+ * function rather than before.
+ *
+ * Since this procedure is used so heavily, we duplicate most of its code
+ * rather than making a text for color_info.max_color >= 31.
+ */
+
+private void
+cmap_rgb_halftoned(frac r, frac g, frac b, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+ if ( (mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray(mred, pdc, pis, dev, select) :
+ gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_direct(frac r, frac g, frac b, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+ gx_color_index color =
+ (pis->alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue)) :
+ gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue), pis->alpha));
+ if ( color != gx_no_color_index )
+ { color_set_pure(pdc, color);
+ return;
+ }
+ if ( (mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray(mred, pdc, pis, dev, select) :
+ gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_gray_halftoned(frac r, frac g, frac b, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ cmap_gray_halftoned(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_gray_direct(frac r, frac g, frac b, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ cmap_gray_direct(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_cmyk(frac r, frac g, frac b, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac cmyk[4];
+ color_rgb_to_cmyk(r, g, b, pis, cmyk);
+ (*pis->cmap_procs->map_cmyk)(cmyk[0], cmyk[1], cmyk[2], cmyk[3], pdc, pis, dev, select);
+}
+
+/* ------ Render CMYK color. ------ */
+
+private void
+cmap_cmyk_to_gray(frac c, frac m, frac y, frac k, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ (*pis->cmap_procs->map_gray)(color_cmyk_to_gray(c, m, y, k, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac mcyan = frac_1 - gx_map_color_frac(pis, frac_1 - c, effective_transfer.colored.red);
+ frac mmagenta = frac_1 - gx_map_color_frac(pis, frac_1 - m, effective_transfer.colored.green);
+ frac myellow = frac_1 - gx_map_color_frac(pis, frac_1 - y, effective_transfer.colored.blue);
+ frac mblack = frac_1 - gx_map_color_frac(pis, frac_1 - k, effective_transfer.colored.gray);
+ /* We make a test for direct vs. halftoned, rather than */
+ /* duplicating most of the code of this procedure. */
+ if ( dev->color_info.max_color >= 31 )
+ { gx_color_index color =
+ gx_map_cmyk_color(dev,
+ frac2cv(mcyan), frac2cv(mmagenta),
+ frac2cv(myellow), frac2cv(mblack));
+ if ( color != gx_no_color_index )
+ { color_set_pure(pdc, color);
+ return;
+ }
+ }
+ /* Don't convert colors with C = M = Y to gray shades: */
+ /* on a CMYK device, this may produce quite different output. */
+ if ( gx_render_cmyk(mcyan, mmagenta, myellow, mblack, pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_cmyk_to_rgb(frac c, frac m, frac y, frac k, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac rgb[3];
+ color_cmyk_to_rgb(c, m, y, k, pis, rgb);
+ (*pis->cmap_procs->map_rgb)(rgb[0], rgb[1], rgb[2], pdc, pis, dev, select);
+}
+
+#ifdef DPNEXT
+
+/* ------ Render RGB+alpha color. ------ */
+
+private void
+cmap_rgb_alpha2gray_halftoned(frac r, frac g, frac b, frac alpha,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac gray = color_rgb_to_gray(r, g, b, pis);
+
+ if ( gx_render_gray_alpha(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), frac2cv(alpha), pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_alpha2gray_direct(frac r, frac g, frac b, frac alpha,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac gray = color_rgb_to_gray(r, g, b, pis);
+ frac mgray =
+ gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ gx_color_value cv_gray = frac2cv(mgray);
+ gx_color_value cv_alpha = frac2cv(alpha);
+ gx_color_index color =
+ (cv_alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
+ gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, cv_alpha));
+
+ if ( color == gx_no_color_index )
+ { if ( gx_render_gray_alpha(mgray, cv_alpha, pdc, pis, dev, select) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+ return;
+ }
+ color_set_pure(pdc, color);
+}
+
+private void
+cmap_rgb_alpha_halftoned(frac r, frac g, frac b, frac alpha,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+ gx_color_value cv_alpha = frac2cv(alpha);
+
+ if ( (mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
+ gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color *pdc,
+ const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
+{ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+ gx_color_value cv_alpha = frac2cv(alpha);
+ gx_color_index color =
+ (cv_alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue)) :
+ gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue), cv_alpha));
+
+ if ( color != gx_no_color_index )
+ { color_set_pure(pdc, color);
+ return;
+ }
+ if ( (mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
+ gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1 )
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+/* Currently CMYK devices can't handle alpha. */
+/* Just multiply the values towards white. */
+private void
+cmap_rgb_alpha_to_cmyk(frac r, frac g, frac b, frac alpha,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ frac white = frac_1 - alpha;
+
+ cmap_rgb_to_cmyk((frac)((long)r * alpha / frac_1) + white,
+ (frac)((long)g * alpha / frac_1) + white,
+ (frac)((long)b * alpha / frac_1) + white,
+ pdc, pis, dev, select);
+}
+
+#endif
+
+/* ------ Transfer function mapping ------ */
+
+/* Define the generic transfer function for the library layer. */
+/* This just returns what's already in the map. */
+float
+gs_mapped_transfer(floatp value, const gx_transfer_map *pmap)
+{ return gx_map_color_float(pmap, value);
+}
+
+#if FRAC_MAP_INTERPOLATE /* NOTA BENE */
+
+/* Map a color fraction through a transfer map. */
+/* We only use this if we are interpolating. */
+frac
+gx_color_frac_map(frac cv, const frac *values)
+{
+#define cp_frac_bits (frac_bits - log2_transfer_map_size)
+ int cmi = frac2bits_floor(cv, log2_transfer_map_size);
+ frac mv = values[cmi];
+ int rem, mdv;
+ /* Interpolate between two adjacent values if needed. */
+ rem = cv - bits2frac(cmi, log2_transfer_map_size);
+ if ( rem == 0 ) return mv;
+ mdv = values[cmi + 1] - mv;
+#if arch_ints_are_short
+ /* Only use long multiplication if necessary. */
+ if ( mdv < -1 << (16 - cp_frac_bits) ||
+ mdv > 1 << (16 - cp_frac_bits)
+ )
+ return mv + (uint)(((ulong)rem * mdv) >> cp_frac_bits);
+#endif
+ return mv + ((rem * mdv) >> cp_frac_bits);
+#undef cp_frac_bits
+}
+
+#endif /* FRAC_MAP_INTERPOLATE */
+
+/* ------ Default device color mapping ------ */
+
+/* RGB mapping for black-and-white devices */
+
+/* White-on-black */
+gx_color_index
+gx_default_w_b_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* Map values >= 1/2 to 1, < 1/2 to 0. */
+ return ((r | g | b) > gx_max_color_value / 2 ?
+ (gx_color_index)1 : (gx_color_index)0);
+}
+int
+gx_default_w_b_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ /* Map 1 to max_value, 0 to 0. */
+ prgb[0] = prgb[1] = prgb[2] = -(gx_color_value)color;
+ return 0;
+}
+/* Black-on-white */
+gx_color_index
+gx_default_b_w_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* Map values >= 1/2 to 0, < 1/2 to 1. */
+ return ((r | g | b) > gx_max_color_value / 2 ?
+ (gx_color_index)0 : (gx_color_index)1);
+}
+int
+gx_default_b_w_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ /* Map 0 to max_value, 1 to 0. */
+ prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
+ return 0;
+}
+
+/* RGB mapping for gray-scale devices */
+
+gx_color_index
+gx_default_gray_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* We round the value rather than truncating it. */
+ gx_color_value gray =
+ (((r * (ulong)lum_red_weight) +
+ (g * (ulong)lum_green_weight) +
+ (b * (ulong)lum_blue_weight) +
+ (lum_all_weights / 2)) / lum_all_weights
+ * dev->color_info.max_gray +
+ (gx_max_color_value / 2)) / gx_max_color_value;
+ return gray;
+}
+
+int
+gx_default_gray_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ gx_color_value gray =
+ color * gx_max_color_value / dev->color_info.max_gray;
+ prgb[0] = gray;
+ prgb[1] = gray;
+ prgb[2] = gray;
+ return 0;
+}
+
+/* RGB mapping for 24-bit true (RGB) color devices */
+
+gx_color_index
+gx_default_rgb_map_rgb_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ if ( dev->color_info.depth == 24 )
+ return gx_color_value_to_byte(b) +
+ ((uint)gx_color_value_to_byte(g) << 8) +
+ ((ulong)gx_color_value_to_byte(r) << 16);
+ else
+ { uint bits_per_color = dev->color_info.depth / 3;
+ ulong max_value = (1 << bits_per_color) - 1;
+
+ return ((r * max_value / gx_max_color_value) << (bits_per_color * 2)) +
+ ((g * max_value / gx_max_color_value) << (bits_per_color)) +
+ (b * max_value / gx_max_color_value);
+ }
+}
+
+/* Map a color index to a r-g-b color. */
+int
+gx_default_rgb_map_color_rgb(gx_device *dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ if ( dev->color_info.depth == 24 )
+ { prgb[0] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[2] = gx_color_value_from_byte(color & 0xff);
+ }
+ else
+ { uint bits_per_color = dev->color_info.depth / 3;
+ uint color_mask = (1 << bits_per_color) - 1;
+
+ prgb[0] = ((color >> (bits_per_color * 2)) & color_mask) *
+ (ulong)gx_max_color_value / color_mask;
+ prgb[1] = ((color >> (bits_per_color)) & color_mask) *
+ (ulong)gx_max_color_value / color_mask;
+ prgb[2] = (color & color_mask) *
+ (ulong)gx_max_color_value / color_mask;
+ }
+ return 0;
+}
+
+/* CMYK mapping for RGB devices (should never be called!) */
+
+gx_color_index
+gx_default_map_cmyk_color(gx_device *dev,
+ gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
+{ /* Convert to RGB */
+ frac rgb[3];
+ color_cmyk_to_rgb(cv2frac(c), cv2frac(m), cv2frac(y), cv2frac(k),
+ NULL, rgb);
+ return gx_map_rgb_color(dev, frac2cv(rgb[0]),
+ frac2cv(rgb[1]), frac2cv(rgb[2]));
+}
+
+/* CMYK mapping for CMYK devices */
+
+gx_color_index
+gx_default_cmyk_map_cmyk_color(gx_device *dev,
+ gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
+{ gx_color_index color =
+ (gx_color_value_to_byte(k) +
+ ((uint)gx_color_value_to_byte(y) << 8)) +
+ ((ulong)(gx_color_value_to_byte(m) +
+ ((uint)gx_color_value_to_byte(c) << 8)) << 16);
+
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/* Default mapping from RGB+alpha to RGB. */
+
+gx_color_index
+gx_default_map_rgb_alpha_color(gx_device *dev,
+ gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ /* Premultiply the values towards white. */
+ gx_color_value white = gx_max_color_value - alpha;
+
+ if ( white == 0 )
+ return gx_map_rgb_color(dev, r, g, b);
+ return gx_map_rgb_color(dev,
+ (gx_color_value)((ulong)r * alpha / gx_max_color_value) + white,
+ (gx_color_value)((ulong)g * alpha / gx_max_color_value) + white,
+ (gx_color_value)((ulong)b * alpha / gx_max_color_value) + white);
+}
diff --git a/gs/src/gxcmap.h b/gs/src/gxcmap.h
new file mode 100644
index 000000000..50cbeff56
--- /dev/null
+++ b/gs/src/gxcmap.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcmap.h */
+/* Private definition of color mapping for Ghostscript */
+/* Requires gxdcolor.h, gxdevice.h. */
+#include "gscsel.h"
+#include "gxfmap.h"
+
+/* Procedures for rendering colors specified by fractions. */
+
+#define cmap_proc_gray(proc)\
+ void proc(P5(frac, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+#define cmap_proc_rgb(proc)\
+ void proc(P7(frac, frac, frac, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+#define cmap_proc_cmyk(proc)\
+ void proc(P8(frac, frac, frac, frac, gx_device_color *,\
+ const gs_imager_state *, gx_device *, gs_color_select_t))
+#ifdef DPNEXT
+#define cmap_proc_rgb_alpha(proc)\
+ void proc(P8(frac, frac, frac, frac, gx_device_color *,\
+ const gs_imager_state *, gx_device *, gs_color_select_t))
+#endif
+
+/* Because of a bug in the Watcom C compiler, */
+/* we have to split the struct from the typedef. */
+struct gx_color_map_procs_s {
+ cmap_proc_gray((*map_gray));
+ cmap_proc_rgb((*map_rgb));
+ cmap_proc_cmyk((*map_cmyk));
+#ifdef DPNEXT
+ cmap_proc_rgb_alpha((*map_rgb_alpha));
+#endif
+};
+typedef struct gx_color_map_procs_s gx_color_map_procs;
+
+/* Determine the color mapping procedures for a device. */
+const gx_color_map_procs *gx_device_cmap_procs(P1(const gx_device *));
+
+/* Set the color mapping procedures in the graphics state. */
+/* This is only needed when switching devices. */
+void gx_set_cmap_procs(P2(gs_imager_state *, const gx_device *));
+
+/* Remap a concrete (frac) RGB or CMYK color. */
+/* These cannot fail, and do not return a value. */
+#define gx_remap_concrete_rgb(cr, cg, cb, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_rgb)(cr, cg, cb, pdc, pgs, dev, select)
+#define gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_cmyk)(cc, cm, cy, ck, pdc, pgs, dev, select)
+#ifdef DPNEXT
+#define gx_remap_concrete_rgb_alpha(cr, cg, cb, ca, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_rgb_alpha)(cr, cg, cb, ca, pdc, pgs, dev, select)
+#endif
+
+/* Map a color, with optional tracing if we are debugging. */
+#ifdef DEBUG
+/* Use procedures in gxcmap.c */
+#include "gxcvalue.h"
+gx_color_index gx_proc_map_rgb_color(P4(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value));
+gx_color_index gx_proc_map_rgb_alpha_color(P5(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value, gx_color_value));
+gx_color_index gx_proc_map_cmyk_color(P5(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value, gx_color_value));
+# define gx_map_rgb_color(dev, vr, vg, vb)\
+ gx_proc_map_rgb_color(dev, vr, vg, vb)
+# define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
+ gx_proc_map_rgb_alpha_color(dev, vr, vg, vb, va)
+# define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
+ gx_proc_map_cmyk_color(dev, vc, vm, vy, vk)
+#else
+# define gx_map_rgb_color(dev, vr, vg, vb)\
+ (*dev_proc(dev, map_rgb_color))(dev, vr, vg, vb)
+# define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
+ (*dev_proc(dev, map_rgb_alpha_color))(dev, vr, vg, vb, va)
+# define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
+ (*dev_proc(dev, map_cmyk_color))(dev, vc, vm, vy, vk)
+#endif
diff --git a/gs/src/gxcolor2.h b/gs/src/gxcolor2.h
new file mode 100644
index 000000000..7c49b71e3
--- /dev/null
+++ b/gs/src/gxcolor2.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcolor2.h */
+/* Internal definitions for Level 2 color routines */
+/* Requires gsstruct.h, gxfixed.h */
+#include "gscolor2.h"
+#include "gsrefct.h"
+#include "gxbitmap.h"
+
+/* Cache for Indexed color with procedure, or Separation color. */
+struct gs_indexed_map_s {
+ rc_header rc;
+ union {
+ int (*lookup_index)(P3(const gs_indexed_params *, int, float *));
+ int (*tint_transform)(P3(const gs_separation_params *, floatp, float *));
+ } proc;
+ uint num_values; /* base_space->type->num_components * (hival + 1) */
+ float *values; /* actually [num_values] */
+};
+extern_st(st_indexed_map);
+#define public_st_indexed_map() /* in gscolor2.c */\
+ gs_public_st_ptrs1(st_indexed_map, gs_indexed_map, "gs_indexed_map",\
+ indexed_map_enum_ptrs, indexed_map_reloc_ptrs, values)
+
+/*
+ * We define 'tiling space' as the space in which (0,0) is the origin of
+ * the key pattern cell and in which coordinate (i,j) is displaced by
+ * i * XStep + j * YStep from the origin. In this space, it is easy to
+ * compute a (rectangular) set of tile copies that cover a (rectangular)
+ * region to be tiled. Note that since all we care about is that the
+ * stepping matrix (the transformation from tiling space to device space)
+ * yield the right set of coordinates for integral X and Y values, we can
+ * adjust it to make the tiling computation easier; in particular, we can
+ * arrange it so that all 4 transformation factors are non-negative.
+ */
+
+/* Implementation of Pattern instances. */
+struct gs_pattern_instance_s {
+ rc_header rc;
+ gs_client_pattern template;
+ /* Following are created by makepattern */
+ gs_state *saved;
+ gs_matrix step_matrix; /* tiling space -> device space */
+ gs_rect bbox; /* bbox of tile in tiling space */
+ bool is_simple; /* true if xstep/ystep = tile size */
+ gs_int_point size; /* in device coordinates */
+ gx_bitmap_id id; /* key for cached bitmap */
+ /* (= id of mask) */
+};
+/* The following is only public for a type test in the interpreter */
+/* (.buildpattern operator). */
+extern_st(st_pattern_instance);
+#define public_st_pattern_instance() /* in gspcolor.c */\
+ gs_public_st_ptrs_add1(st_pattern_instance, gs_pattern_instance,\
+ "pattern instance", pattern_instance_enum_ptrs,\
+ pattern_instance_reloc_ptrs, st_client_pattern, template, saved)
diff --git a/gs/src/gxcoord.h b/gs/src/gxcoord.h
new file mode 100644
index 000000000..9ea96b3d1
--- /dev/null
+++ b/gs/src/gxcoord.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcoord.h */
+/* Internal coordinate system procedures */
+/* Requires gxmatrix.h and gzstate.h */
+#include "gscoord.h"
+
+/* Set the translation to a fixed value, and translate any existing path. */
+/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
+int gx_translate_to_fixed(P3(gs_state *, fixed, fixed));
+
+/* Scale the CTM and character matrix for oversampling. */
+int gx_scale_char_matrix(P3(gs_state *, int, int));
+
+/* Compute the coefficients for fast fixed-point distance transformations */
+/* from a transformation matrix. */
+int gx_matrix_to_fixed_coeff(P3(const gs_matrix *, fixed_coeff *, int));
diff --git a/gs/src/gxcpath.c b/gs/src/gxcpath.c
new file mode 100644
index 000000000..c5e4d43ee
--- /dev/null
+++ b/gs/src/gxcpath.c
@@ -0,0 +1,1020 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcpath.c */
+/* Implementation of clipping paths */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gscoord.h" /* needs gsmatrix.h */
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Define whether to look for vertical clipping regions. */
+#define CHECK_VERTICAL_CLIPPING
+
+/* Imported from gxacpath.c */
+extern int gx_cpath_intersect_slow(P4(gs_state *, gx_clip_path *,
+ gx_path *, int));
+
+/* Forward references */
+private void gx_clip_list_from_rectangle(P2(gx_clip_list *, gs_fixed_rect *));
+private int gx_clip_list_add_to_path(P2(gx_clip_list *, gx_path *));
+
+/* Structure types */
+public_st_clip_rect();
+private_st_clip_list();
+public_st_clip_path();
+public_st_device_clip();
+
+/* GC procedures for gx_clip_path */
+#define cptr ((gx_clip_path *)vptr)
+private ENUM_PTRS_BEGIN(clip_path_enum_ptrs) ;
+ if ( index < st_clip_list_max_ptrs )
+ { gs_ptr_type_t ret = clip_list_enum_ptrs(&cptr->list, sizeof(cptr->list), index, pep);
+ if ( ret == 0 ) /* don't stop early */
+ ret = ptr_struct_type, *pep = 0;
+ return ret;
+ }
+ return (*st_path.enum_ptrs)(&cptr->path, sizeof(cptr->path), index - st_clip_list_max_ptrs, pep);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(clip_path_reloc_ptrs) {
+ clip_list_reloc_ptrs(&cptr->list, sizeof(gx_clip_list), gcst);
+ (*st_path.reloc_ptrs)(&cptr->path, sizeof(gx_path), gcst);
+} RELOC_PTRS_END
+#undef cptr
+
+/* GC procedures for gx_device_clip */
+#define cptr ((gx_device_clip *)vptr)
+private ENUM_PTRS_BEGIN(device_clip_enum_ptrs) {
+ if ( index < st_clip_list_max_ptrs + 1 )
+ return clip_list_enum_ptrs(&cptr->list, sizeof(gx_clip_list),
+ index - 1, pep);
+ return (*st_device_forward.enum_ptrs)(vptr, sizeof(gx_device_forward),
+ index - (st_clip_list_max_ptrs + 1), pep);
+ }
+ case 0:
+ ENUM_RETURN((cptr->current == &cptr->list.single ? NULL :
+ (void *)cptr->current));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_clip_reloc_ptrs) {
+ if ( cptr->current == &cptr->list.single )
+ cptr->current =
+ &((gx_device_clip *)gs_reloc_struct_ptr(vptr, gcst))->list.single;
+ else
+ RELOC_PTR(gx_device_clip, current);
+ clip_list_reloc_ptrs(&cptr->list, sizeof(gx_clip_list), gcst);
+ (*st_device_forward.reloc_ptrs)(vptr, sizeof(gx_device_forward), gcst);
+} RELOC_PTRS_END
+#undef cptr
+
+/* Define an empty clip list. */
+private const gx_clip_list clip_list_empty =
+{ { 0, 0, min_int, max_int, 0, 0 },
+ 0, 0, 0, 0 /*false*/
+};
+
+/* Debugging */
+
+#ifdef DEBUG
+/* Validate a clipping path. */
+bool /* only exported for gxacpath.c */
+clip_list_validate(const gx_clip_list *clp)
+{ if ( clp->count <= 1 )
+ return (clp->head == 0 && clp->tail == 0 &&
+ clp->single.next == 0 && clp->single.prev == 0);
+ else
+ { const gx_clip_rect *prev = clp->head;
+ const gx_clip_rect *ptr;
+ bool ok = true;
+ while ( (ptr = prev->next) != 0 )
+ { if ( ptr->ymin > ptr->ymax || ptr->xmin > ptr->xmax ||
+ !(ptr->ymin >= prev->ymax ||
+ (ptr->ymin == prev->ymin &&
+ ptr->ymax == prev->ymax &&
+ ptr->xmin >= prev->xmax)) ||
+ ptr->prev != prev
+ )
+ { clip_rect_print('q', "WRONG:", ptr);
+ ok = false;
+ }
+ prev = ptr;
+ }
+ return ok && prev == clp->tail;
+ }
+}
+#endif
+
+/* ------ Clipping path accessing ------ */
+
+/* Return the path of a clipping path. */
+int
+gx_cpath_path(gx_clip_path *pcpath, gx_path *ppath)
+{ if ( !pcpath->segments_valid )
+ { int code;
+
+ gx_path_reset(&pcpath->path);
+ code = gx_clip_list_add_to_path(&pcpath->list, &pcpath->path);
+ if ( code < 0 )
+ return code;
+ pcpath->segments_valid = 1;
+ }
+ *ppath = pcpath->path;
+ return 0;
+}
+
+/* Return the inner and outer check rectangles for a clipping path. */
+/* Return true iff the path is a rectangle. */
+/* Note that these must return something strange if we are using */
+/* outside clipping. */
+bool
+gx_cpath_inner_box(const gx_clip_path *pcpath, gs_fixed_rect *pbox)
+{ if ( pcpath->list.outside )
+ { pbox->p.x = pbox->p.y = pbox->q.x = pbox->q.y = 0;
+ return false;
+ }
+ else
+ { *pbox = pcpath->inner_box;
+ return clip_list_is_rectangle(&pcpath->list);
+ }
+}
+bool
+gx_cpath_outer_box(const gx_clip_path *pcpath, gs_fixed_rect *pbox)
+{ if ( pcpath->list.outside )
+ { pbox->p.x = pbox->p.y = min_fixed;
+ pbox->q.x = pbox->q.y = max_fixed;
+ return false;
+ }
+ else
+ { *pbox = pcpath->outer_box;
+ return clip_list_is_rectangle(&pcpath->list);
+ }
+}
+
+/* Test if a clipping path includes a rectangle. */
+/* The rectangle need not be oriented correctly, i.e. x0 > x1 is OK. */
+bool
+gx_cpath_includes_rectangle(register const gx_clip_path *pcpath,
+ fixed x0, fixed y0, fixed x1, fixed y1)
+{ return
+ (x0 <= x1 ?
+ (pcpath->inner_box.p.x <= x0 && x1 <= pcpath->inner_box.q.x) :
+ (pcpath->inner_box.p.x <= x1 && x0 <= pcpath->inner_box.q.x)) &&
+ (y0 <= y1 ?
+ (pcpath->inner_box.p.y <= y0 && y1 <= pcpath->inner_box.q.y) :
+ (pcpath->inner_box.p.y <= y1 && y0 <= pcpath->inner_box.q.y));
+}
+
+/* Set the current outsideness of a clipping path. */
+int
+gx_cpath_set_outside(gx_clip_path *pcpath, bool outside)
+{ if ( outside != pcpath->list.outside )
+ { pcpath->id = gs_next_ids(1); /* path changed => change id */
+ pcpath->list.outside = outside;
+ }
+ return 0;
+}
+
+/* Return the current outsideness of a clipping path. */
+bool
+gx_cpath_is_outside(const gx_clip_path *pcpath)
+{ return pcpath->list.outside;
+}
+
+/* Release a clipping path. */
+void
+gx_cpath_release(gx_clip_path *pcpath)
+{ if ( !pcpath->shares_list )
+ gx_clip_list_free(&pcpath->list, pcpath->path.memory);
+ gx_path_release(&pcpath->path);
+}
+
+/* Share a clipping path. */
+void
+gx_cpath_share(gx_clip_path *pcpath)
+{ gx_path_share(&pcpath->path);
+ pcpath->shares_list = 1;
+}
+
+/* Set the outer clipping box to the path bounding box, */
+/* expanded to pixel boundaries. */
+void
+gx_cpath_set_outer_box(gx_clip_path *pcpath)
+{ pcpath->outer_box.p.x = fixed_floor(pcpath->path.bbox.p.x);
+ pcpath->outer_box.p.y = fixed_floor(pcpath->path.bbox.p.y);
+ pcpath->outer_box.q.x = fixed_ceiling(pcpath->path.bbox.q.x);
+ pcpath->outer_box.q.y = fixed_ceiling(pcpath->path.bbox.q.y);
+}
+
+/* ------ Clipping path setting ------ */
+
+/* Initialize a clipping path. */
+int
+gx_cpath_init(gx_clip_path *pcpath, gs_memory_t *mem)
+{ static /*const*/ gs_fixed_rect null_rect = { { 0, 0 }, { 0, 0 } };
+ return gx_cpath_from_rectangle(pcpath, &null_rect, mem); /* does a gx_path_init */
+}
+
+/* Create a rectangular clipping path. */
+/* The supplied rectangle may not be oriented correctly, */
+/* but it will be oriented correctly upon return. */
+int
+gx_cpath_from_rectangle(gx_clip_path *pcpath, gs_fixed_rect *pbox,
+ gs_memory_t *mem)
+{ gx_clip_list_from_rectangle(&pcpath->list, pbox);
+ pcpath->inner_box = *pbox;
+ pcpath->segments_valid = 0;
+ pcpath->shares_list = 0;
+ gx_path_init(&pcpath->path, mem);
+ pcpath->path.bbox = *pbox;
+ gx_cpath_set_outer_box(pcpath);
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ return 0;
+}
+
+/* Intersect a new clipping path with an old one. */
+/* Note that it may overwrite its path argument; return 1 in this case, */
+/* otherwise 0 for success, <0 for failure as usual. */
+int
+gx_cpath_intersect(gs_state *pgs, gx_clip_path *pcpath, gx_path *ppath,
+ int rule)
+{ gs_fixed_rect old_box, new_box;
+ int code;
+
+ if ( gx_cpath_inner_box(pcpath, &old_box) &&
+ ((code = gx_path_is_rectangle(ppath, &new_box)) ||
+ gx_path_is_void(ppath))
+ )
+ { bool changed = false;
+ bool outside = pcpath->list.outside;
+
+ if ( !code )
+ { /* The new path is void. */
+ if ( gx_path_current_point(ppath, &new_box.p) < 0 )
+ { /* Use the user space origin (arbitrarily). */
+ gs_point origin;
+
+ gs_transform(pgs, 0.0, 0.0, &origin);
+ new_box.p.x = float2fixed(origin.x);
+ new_box.p.y = float2fixed(origin.y);
+ gx_path_add_point(ppath, new_box.p.x, new_box.p.y);
+ }
+ new_box.q = new_box.p;
+ }
+ else
+ { /* Intersect the two rectangles if necessary. */
+ if ( old_box.p.x > new_box.p.x )
+ new_box.p.x = old_box.p.x, changed = true;
+ if ( old_box.p.y > new_box.p.y )
+ new_box.p.y = old_box.p.y, changed = true;
+ if ( old_box.q.x < new_box.q.x )
+ new_box.q.x = old_box.q.x, changed = true;
+ if ( old_box.q.y < new_box.q.y )
+ new_box.q.y = old_box.q.y, changed = true;
+ /* Check for a degenerate rectangle. */
+ if ( new_box.q.x < new_box.p.x )
+ new_box.q.x = new_box.p.x;
+ if ( new_box.q.y < new_box.p.y )
+ new_box.q.y = new_box.p.y;
+ if ( changed )
+ { /* Store the new rectangle back into the new path. */
+ register segment *pseg =
+ (segment *)ppath->first_subpath;
+#define set_pt(pqx,pqy)\
+ pseg->pt.x = new_box.pqx.x, pseg->pt.y = new_box.pqy.y
+ set_pt(p, p); pseg = pseg->next;
+ set_pt(q, p); pseg = pseg->next;
+ set_pt(q, q); pseg = pseg->next;
+ set_pt(p, q); pseg = pseg->next;
+ if ( pseg != 0 ) /* might be an open rectangle */
+ set_pt(p, p);
+#undef set_pt
+ }
+ }
+ ppath->bbox = new_box;
+ gx_cpath_release(pcpath);
+ gx_clip_list_from_rectangle(&pcpath->list, &new_box);
+ pcpath->list.outside = outside;
+ pcpath->inner_box = new_box;
+ pcpath->path = *ppath;
+ gx_cpath_set_outer_box(pcpath);
+ pcpath->segments_valid = 1;
+ pcpath->shares_list = 0;
+ code = 1;
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ }
+ else
+ { /* Not a rectangle. Intersect the slow way. */
+ code = gx_cpath_intersect_slow(pgs, pcpath, ppath, rule);
+ }
+ return code;
+}
+
+/* Scale a clipping path by a power of 2. */
+int
+gx_cpath_scale_exp2(gx_clip_path *pcpath, int log2_scale_x, int log2_scale_y)
+{ int code =
+ gx_path_scale_exp2(&pcpath->path, log2_scale_x, log2_scale_y);
+ gx_clip_rect *pr;
+ if ( code < 0 )
+ return code;
+ /* Scale the fixed entries. */
+ gx_rect_scale_exp2(&pcpath->inner_box, log2_scale_x, log2_scale_y);
+ gx_rect_scale_exp2(&pcpath->outer_box, log2_scale_x, log2_scale_y);
+ /* Scale the clipping list. */
+ pr = pcpath->list.head;
+ if ( pr == 0 )
+ pr = &pcpath->list.single;
+ for ( ; pr != 0; pr = pr->next )
+ if ( pr != pcpath->list.head && pr != pcpath->list.tail )
+ {
+#define scale_v(v, s)\
+ if ( pr->v != min_int && pr->v != max_int )\
+ pr->v = (s >= 0 ? pr->v << s : pr->v >> -s)
+ scale_v(xmin, log2_scale_x);
+ scale_v(xmax, log2_scale_x);
+ scale_v(ymin, log2_scale_y);
+ scale_v(ymax, log2_scale_y);
+#undef scale_v
+ }
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ return 0;
+}
+
+/* ------ Clipping list routines ------ */
+
+/* Initialize a clip list. */
+void
+gx_clip_list_init(gx_clip_list *clp)
+{ *clp = clip_list_empty;
+}
+
+/* Initialize a clip list to a rectangle. */
+/* The supplied rectangle may not be oriented correctly, */
+/* but it will be oriented correctly upon return. */
+private void
+gx_clip_list_from_rectangle(register gx_clip_list *clp,
+ register gs_fixed_rect *rp)
+{ gx_clip_list_init(clp);
+ if ( rp->p.x > rp->q.x )
+ { fixed t = rp->p.x; rp->p.x = rp->q.x; rp->q.x = t; }
+ if ( rp->p.y > rp->q.y )
+ { fixed t = rp->p.y; rp->p.y = rp->q.y; rp->q.y = t; }
+ clp->single.xmin = fixed2int_var(rp->p.x);
+ clp->single.ymin = fixed2int_var(rp->p.y);
+ clp->single.xmax = fixed2int_var_ceiling(rp->q.x);
+ clp->single.ymax = fixed2int_var_ceiling(rp->q.y);
+ clp->count = 1;
+ clp->outside = false;
+}
+
+/* Add a clip list to a path. */
+/* In general, this produces a path made up of zillions of tiny lines. */
+private int
+gx_clip_list_add_to_path(gx_clip_list *clp, gx_path *ppath)
+{ gx_clip_rect *rp;
+ int code = -1;
+ gx_clip_rect *head = (clp->count <= 1 ? &clp->single : clp->head);
+ gx_clip_rect *visit;
+ gx_clip_rect *look;
+ enum { visit_left = 1, visit_right = 2 } first_visit;
+
+ for ( rp = head; rp != 0; rp = rp->next )
+ if ( rp->xmin < rp->xmax && rp->ymin < rp->ymax )
+ rp->to_visit = visit_left | visit_right;
+ for ( visit = head; visit != 0; visit = visit->next )
+ { if ( !visit->to_visit )
+ continue;
+ rp = visit;
+ if ( visit->to_visit & visit_left )
+ { code = gx_path_add_point(ppath, int2fixed(visit->xmin),
+ int2fixed(visit->ymax));
+ if ( code < 0 )
+ return code;
+ first_visit = visit_left;
+ goto left;
+ }
+ else
+ { code = gx_path_add_point(ppath, int2fixed(visit->xmax),
+ int2fixed(visit->ymin));
+ if ( code < 0 )
+ return code;
+ first_visit = visit_right;
+ goto right;
+ }
+#define trace_line(px, py)\
+ code = gx_path_add_line(ppath, int2fixed(px), int2fixed(py));\
+ if ( code < 0 ) return code
+left: /* Trace upward along a left edge. */
+ /* We're at the upper left corner of rp. */
+ rp->to_visit &= ~visit_left;
+ /* Look for an adjacent rectangle above rp. */
+ for ( look = rp;
+ (look = look->next) != 0 &&
+ (look->ymin == rp->ymin ||
+ (look->ymin == rp->ymax && look->xmax <= rp->xmin));
+ )
+ ;
+ /* Now we know look->ymin >= rp->ymax. */
+ if ( look == 0 || look->ymin > rp->ymax || look->xmin >= rp->xmax )
+ { /* No adjacent rectangle, switch directions. */
+ trace_line(rp->xmax, rp->ymax);
+ if ( rp == visit && first_visit == visit_right )
+ goto close;
+ goto right1;
+ }
+ /* We found an adjacent rectangle. */
+ /* See if it also adjoins a rectangle to the left of rp. */
+ { gx_clip_rect *prev = rp->prev;
+ if ( prev->ymax == rp->ymax && look->xmin < prev->xmax )
+ { /* There's an adjoining rectangle as well. */
+ /* Switch directions. */
+ trace_line(prev->xmax, rp->ymax);
+ rp = prev;
+ if ( rp == visit && first_visit == visit_right )
+ goto close;
+ goto right1;
+ }
+ }
+ trace_line(look->xmin, look->ymin);
+ rp = look;
+ if ( rp == visit && first_visit == visit_left )
+ goto close;
+left1: trace_line(rp->xmin, rp->ymax);
+ goto left;
+right: /* Trace downward along a right edge. */
+ /* We're at the lower right corner of rp. */
+ rp->to_visit &= ~visit_right;
+ /* Look for an adjacent rectangle below rp. */
+ for ( look = rp;
+ (look = look->prev) != 0 &&
+ (look->ymax == rp->ymax ||
+ (look->ymax == rp->ymin && look->xmin >= rp->xmax));
+ )
+ ;
+ /* Now we know look->ymax <= rp->ymin. */
+ if ( look == 0 || look->ymax < rp->ymin || look->xmax <= rp->xmin )
+ { /* No adjacent rectangle, switch directions. */
+ trace_line(rp->xmin, rp->ymin);
+ if ( rp == visit && first_visit == visit_left )
+ goto close;
+ goto left1;
+ }
+ /* We found an adjacent rectangle. */
+ /* See if it also adjoins a rectangle to the right of rp. */
+ { gx_clip_rect *next = rp->next;
+ if ( next->ymin == rp->ymin && look->xmax > next->xmin )
+ { /* There's an adjoining rectangle as well. */
+ /* Switch directions. */
+ trace_line(next->xmin, rp->ymin);
+ rp = next;
+ if ( rp == visit && first_visit == visit_left )
+ goto close;
+ goto left1;
+ }
+ }
+ trace_line(look->xmax, look->ymax);
+ rp = look;
+ if ( rp == visit && first_visit == visit_right )
+ goto close;
+right1: trace_line(rp->xmax, rp->ymin);
+ goto right;
+close: /* We've gone all the way around an edge. */
+ code = gx_path_close_subpath(ppath);
+ if ( code < 0 )
+ return code;
+ }
+#undef trace_line
+ if ( code < 0 )
+ { /* We didn't have any rectangles. */
+ code = gx_path_add_point(ppath, fixed_0, fixed_0);
+ }
+ return code;
+}
+
+/* Free a clip list. */
+void
+gx_clip_list_free(gx_clip_list *clp, gs_memory_t *mem)
+{ gx_clip_rect *rp = clp->tail;
+ while ( rp != 0 )
+ { gx_clip_rect *prev = rp->prev;
+ gs_free_object(mem, rp, "gx_clip_list_free");
+ rp = prev;
+ }
+ gx_clip_list_init(clp);
+}
+
+/* ------ Rectangle list clipper ------ */
+
+/* Device for clipping with a region. */
+/* We forward non-drawing operations, but we must be sure to intercept */
+/* all drawing operations. */
+private dev_proc_open_device(clip_open);
+private dev_proc_fill_rectangle(clip_fill_rectangle);
+private dev_proc_copy_mono(clip_copy_mono);
+private dev_proc_copy_color(clip_copy_color);
+private dev_proc_get_bits(clip_get_bits);
+private dev_proc_copy_alpha(clip_copy_alpha);
+private dev_proc_fill_mask(clip_fill_mask);
+private dev_proc_strip_tile_rectangle(clip_strip_tile_rectangle);
+private dev_proc_strip_copy_rop(clip_strip_copy_rop);
+private dev_proc_get_clipping_box(clip_get_clipping_box);
+
+/* The device descriptor. */
+private const gx_device_clip gs_clip_device =
+{ std_device_std_body(gx_device_clip, 0, "clipper",
+ 0, 0, 1, 1),
+ { clip_open,
+ gx_forward_get_initial_matrix,
+ gx_default_sync_output,
+ gx_default_output_page,
+ gx_default_close_device,
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ clip_fill_rectangle,
+ gx_default_tile_rectangle,
+ clip_copy_mono,
+ clip_copy_color,
+ gx_default_draw_line,
+ clip_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ clip_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ clip_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ clip_strip_tile_rectangle,
+ clip_strip_copy_rop,
+ clip_get_clipping_box,
+ gx_forward_get_hardware_params
+ }
+};
+#define rdev ((gx_device_clip *)dev)
+
+/* Make a clipping device. */
+void
+gx_make_clip_translate_device(gx_device_clip *dev, void *container,
+ const gx_clip_list *list, int tx, int ty)
+{ *dev = gs_clip_device;
+ dev->list = *list;
+ dev->translation.x = tx;
+ dev->translation.y = ty;
+}
+void
+gx_make_clip_path_device(gx_device_clip *dev, const gx_clip_path *pcpath)
+{ gx_make_clip_device(dev, NULL, &pcpath->list);
+}
+
+/* Declare and initialize the cursor variables. */
+#ifdef DEBUG
+private ulong clip_loops, clip_in, clip_down, clip_up, clip_x, clip_no_x;
+private uint clip_interval = 10000;
+# define inc(v) v++
+# define print_clip()\
+ if ( clip_loops % clip_interval == 0 )\
+ if_debug10('q', "[q]rect=(%d,%d),(%d,%d)\n loops=%ld in=%ld down=%ld up=%ld x=%ld no_x=%ld\n",\
+ x, y, x + w, y + h,\
+ clip_loops, clip_in, clip_down, clip_up, clip_x, clip_no_x)
+#else
+# define inc(v) discard(0)
+# define print_clip() DO_NOTHING
+#endif
+#define DECLARE_CLIP\
+ register gx_clip_rect *rptr = rdev->current;\
+ gx_device *tdev = rdev->target;\
+ bool outside = rdev->list.outside;
+/* Translate the supplied coordinates. */
+#define TRANSLATE_CLIP\
+ x += rdev->translation.x;\
+ y += rdev->translation.y;
+/* Check whether the rectangle x,y,w,h falls within the current entry. */
+#define xywh_is_in_ryptr()\
+ (!outside &&\
+ y >= rptr->ymin && y + h <= rptr->ymax &&\
+ x >= rptr->xmin && x + w <= rptr->xmax)
+#ifdef DEBUG
+# define xywh_in_ryptr() (xywh_is_in_ryptr() ? (inc(clip_in), 1) : 0)
+#else
+# define xywh_in_ryptr() xywh_is_in_ryptr()
+#endif
+/*
+ * Warp the cursor forward or backward to the first rectangle row that
+ * could include a given y value. Assumes rptr is set, and updates it.
+ * Specifically, after warp_cursor, either rptr == 0 (if the y value is
+ * greater than all y values in the list), or y < rptr->ymax and either
+ * rptr->prev == 0 or y >= rptr->prev->ymax. Note that y <= rptr->ymin
+ * is possible.
+ *
+ * In the first case below, the while loop is safe because if there is
+ * more than one rectangle, there is a 'stopper' at the end of the list.
+ */
+#define warp_cursor(y)\
+ if ( (y) >= rptr->ymax )\
+ { if ( (rptr = rptr->next) != 0 )\
+ while ( inc(clip_up), (y) >= rptr->ymax ) rptr = rptr->next;\
+ }\
+ else while ( rptr->prev != 0 && (y) < rptr->prev->ymax )\
+ { inc(clip_down); rptr = rptr->prev; }
+/*
+ * Enumerate the rectangles of the x,w,y,h argument that fall within
+ * the clipping region. Usage:
+ * DO_CLIP(adjust for yc > yp if necessary,
+ * process(xc, yc, xec, yec) [must be an expression])
+ *
+ * Note that we look ahead to detect unclipped vertical strips.
+ * This is really only valuable for 90 degree rotated images or
+ * (nearly-)vertical lines with convex clipping regions; if we ever
+ * change images to use source buffering and destination-oriented
+ * enumeration, we could probably take out the code here with no
+ * adverse effects.
+ */
+#ifdef CHECK_VERTICAL_CLIPPING
+# define LOOK_AHEAD\
+ if ( xec - xc == w ) /* full width */\
+ { /* Look ahead for a vertical swath. */\
+ while ( (nptr = rptr->next) != 0 &&\
+ nptr->ymin == yec &&\
+ nptr->ymax <= ye &&\
+ nptr->xmin <= x &&\
+ nptr->xmax >= xe\
+ )\
+ yec = nptr->ymax, rptr = nptr;\
+ }\
+ else\
+ nptr = rptr->next
+#else
+# define LOOK_AHEAD\
+ nptr = rptr->next
+#endif
+#define DO_CLIP(adjust_for_y, process_rectangle)\
+ if ( w <= 0 || h <= 0 ) return 0;\
+ inc(clip_loops);\
+ print_clip();\
+ { const int xe = x + w, ye = y + h;\
+ int xc, xec, yc, yec, yp, yep;\
+ int code;\
+\
+ warp_cursor(y);\
+ if ( rptr == 0 || (yc = rptr->ymin) >= ye )\
+ { if ( rdev->list.count > 1 )\
+ rdev->current =\
+ (rptr != 0 ? rptr :\
+ y >= rdev->current->ymax ? rdev->list.tail :\
+ rdev->list.head);\
+ return (outside ? (xc = x, xec = xe, yc = y, yec = ye,\
+ process_rectangle) : 0);\
+ }\
+ rdev->current = rptr;\
+ if ( yc < y ) yc = y;\
+ yp = y;\
+ if ( outside )\
+ { for ( yep = y; ; )\
+ { const int ymax = rptr->ymax;\
+\
+ xc = x;\
+ if ( yc > yep )\
+ { yec = yc, yc = yep;\
+ adjust_for_y;\
+ xec = xe;\
+ code = process_rectangle;\
+ if ( code < 0 ) return code;\
+ yp = yep;\
+ yc = yec;\
+ adjust_for_y;\
+ }\
+ yec = min(ymax, ye);\
+ do \
+ { xec = rptr->xmin;\
+ if ( xec > xc )\
+ { if ( xec > xe ) xec = xe;\
+ code = process_rectangle;\
+ if ( code < 0 ) return code;\
+ xc = rptr->xmax;\
+ if ( xc >= xe ) xc = max_int;\
+ }\
+ else\
+ { xec = rptr->xmax;\
+ if ( xec > xc ) xc = xec;\
+ }\
+ }\
+ while ( (rptr = rptr->next) != 0 && rptr->ymax == ymax );\
+ if ( xc < xe )\
+ { xec = xe;\
+ code = process_rectangle;\
+ if ( code < 0 ) return code;\
+ }\
+ yp = yc;\
+ yep = yec;\
+ if ( rptr == 0 || (yc = rptr->ymin) >= ye ) break;\
+ }\
+ if ( yep < ye )\
+ { xc = x, xec = xe, yc = yep, yec = ye;\
+ code = process_rectangle;\
+ if ( code < 0 ) return code;\
+ }\
+ }\
+ else \
+ for ( ; ; )\
+ { const int ymax = rptr->ymax;\
+ gx_clip_rect *nptr;\
+\
+ yec = min(ymax, ye);\
+ if ( yc > yp ) adjust_for_y;\
+ if_debug2('Q', "[Q]yc=%d yec=%d\n", yc, yec);\
+ do \
+ { xc = rptr->xmin;\
+ xec = rptr->xmax;\
+ if ( xc < x ) xc = x;\
+ if ( xec > xe ) xec = xe;\
+ if ( xec > xc )\
+ { clip_rect_print('Q', "match", rptr);\
+ if_debug2('Q', "[Q]xc=%d xec=%d\n", xc, xec);\
+ inc(clip_x);\
+ LOOK_AHEAD;\
+ code = process_rectangle;\
+ if ( code < 0 ) return code;\
+ }\
+ else\
+ { inc(clip_no_x);\
+ nptr = rptr->next;\
+ }\
+ }\
+ while ( (rptr = nptr) != 0 && rptr->ymax == ymax );\
+ if ( rptr == 0 || (yec = rptr->ymin) >= ye ) break;\
+ yp = yc;\
+ yc = yec;\
+ }\
+ }
+
+/* Open a clipping device */
+private int
+clip_open(register gx_device *dev)
+{ gx_device *tdev = rdev->target;
+ /* Initialize the cursor. */
+ rdev->current =
+ (rdev->list.head == 0 ? &rdev->list.single : rdev->list.head);
+ rdev->color_info = tdev->color_info;
+ rdev->width = tdev->width;
+ rdev->height = tdev->height;
+ return 0;
+}
+
+/* Fill a rectangle */
+private int
+clip_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ DECLARE_CLIP
+ dev_proc_fill_rectangle((*fill)) = dev_proc(tdev, fill_rectangle);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*fill)(tdev, x, y, w, h, color);
+ DO_CLIP(DO_NOTHING,
+ (*fill)(tdev, xc, yc, xec - xc, yec - yc, color))
+ return 0;
+}
+
+/* Copy a monochrome rectangle */
+private int
+clip_copy_mono(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{ DECLARE_CLIP
+ dev_proc_copy_mono((*copy)) = dev_proc(tdev, copy_mono);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*copy)(tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
+ DO_CLIP(data += (yc - yp) * raster,
+ (*copy)(tdev, data, sourcex + xc - x, raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, color0, color1))
+ return 0;
+}
+
+/* Copy a color rectangle */
+private int
+clip_copy_color(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{ DECLARE_CLIP
+ dev_proc_copy_color((*copy)) = dev_proc(tdev, copy_color);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*copy)(tdev, data, sourcex, raster, id, x, y, w, h);
+ DO_CLIP(data += (yc - yp) * raster,
+ (*copy)(tdev, data, sourcex + xc - x, raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc))
+ return 0;
+}
+
+/* Copy a rectangle with alpha */
+private int
+clip_copy_alpha(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{ DECLARE_CLIP
+ dev_proc_copy_alpha((*copy)) = dev_proc(tdev, copy_alpha);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*copy)(tdev, data, sourcex, raster, id, x, y, w, h, color, depth);
+ DO_CLIP(data += (yc - yp) * raster,
+ (*copy)(tdev, data, sourcex + xc - x, raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, color, depth))
+ return 0;
+}
+
+/* Fill a region defined by a mask. */
+private int
+clip_fill_mask(gx_device *dev,
+ const byte *data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path *pcpath)
+{ DECLARE_CLIP
+ dev_proc_fill_mask((*fill)) = dev_proc(tdev, fill_mask);
+
+ if ( pcpath != 0 )
+ return gx_default_fill_mask(dev, data, sourcex, raster, id,
+ x, y, w, h, pdcolor, depth, lop,
+ pcpath);
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*fill)(tdev, data, sourcex, raster, id, x, y, w, h,
+ pdcolor, depth, lop, NULL);
+ DO_CLIP(data += (yc - yp) * raster,
+ (*fill)(tdev, data, sourcex + xc - x, raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, pdcolor, depth, lop,
+ NULL))
+ return 0;
+}
+
+/* Get bits back from the device. */
+private int
+clip_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
+{ gx_device *tdev = rdev->target;
+ return (*dev_proc(tdev, get_bits))(tdev, y - rdev->translation.y,
+ data, actual_data);
+}
+
+/* Strip-tile a rectangle. */
+private int
+clip_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1, int phase_x, int phase_y)
+{ DECLARE_CLIP
+ dev_proc_strip_tile_rectangle((*fill)) =
+ dev_proc(tdev, strip_tile_rectangle);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*fill)(tdev, tiles, x, y, w, h, color0, color1, phase_x, phase_y);
+ DO_CLIP(DO_NOTHING,
+ (*fill)(tdev, tiles, xc, yc, xec - xc, yec - yc,
+ color0, color1, phase_x, phase_y))
+ return 0;
+}
+
+/* Copy a rectangle with RasterOp and strip texture. */
+private int
+clip_strip_copy_rop(gx_device *dev,
+ const byte *sdata, int sourcex, uint raster, gx_bitmap_id id,
+ const gx_color_index *scolors,
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,
+ int x, int y, int w, int h,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{ DECLARE_CLIP
+ dev_proc_strip_copy_rop((*copy)) = dev_proc(tdev, strip_copy_rop);
+
+ TRANSLATE_CLIP
+ if ( xywh_in_ryptr() )
+ return (*copy)(tdev, sdata, sourcex, raster, id, scolors,
+ textures, tcolors, x, y, w, h,
+ phase_x, phase_y, lop);
+ DO_CLIP(sdata += (yc - yp) * raster,
+ (*copy)(tdev, sdata, sourcex + xc - x, raster,
+ gx_no_bitmap_id, scolors, textures, tcolors,
+ xc, yc, xec - xc, yec - yc,
+ phase_x, phase_y, lop))
+ return 0;
+}
+
+/* Get the (outer) clipping box, in client coordinates. */
+private void
+clip_get_clipping_box(gx_device *dev, gs_fixed_rect *pbox)
+{ gx_device *tdev = rdev->target;
+ gs_fixed_rect tbox, cbox;
+ fixed tx = int2fixed(rdev->translation.x),
+ ty = int2fixed(rdev->translation.y);
+
+ (*dev_proc(tdev, get_clipping_box))(tdev, &tbox);
+ /*
+ * To get an accurate clipping box quickly in all cases, we should
+ * save the outer box from the clipping path. However,
+ * this is not currently (or even always guaranteed to be)
+ * available. Instead, we compromise: if there is more than one
+ * rectangle in the list, we return accurate Y values (which are
+ * easy to obtain, because the list is Y-sorted) but copy the
+ * X values from the target.
+ */
+ if ( rdev->list.outside || rdev->list.count == 0 )
+ { cbox = tbox;
+ }
+ else if ( rdev->list.count == 1 )
+ { cbox.p.x = int2fixed(rdev->list.single.xmin);
+ cbox.p.y = int2fixed(rdev->list.single.ymin);
+ cbox.q.x = int2fixed(rdev->list.single.xmax);
+ cbox.q.y = int2fixed(rdev->list.single.ymax);
+ }
+ else
+ { /* The head and tail elements are dummies.... */
+ cbox.p.x = tbox.p.x;
+ cbox.p.y = int2fixed(rdev->list.head->next->ymin);
+ cbox.q.x = tbox.q.x;
+ cbox.q.y = int2fixed(rdev->list.tail->prev->ymax);
+ }
+ rect_intersect(tbox, cbox);
+ if ( tbox.p.x != min_fixed )
+ tbox.p.x -= tx;
+ if ( tbox.p.y != min_fixed )
+ tbox.p.y -= ty;
+ if ( tbox.q.x != max_fixed )
+ tbox.q.x -= tx;
+ if ( tbox.q.y != max_fixed )
+ tbox.q.y -= ty;
+ *pbox = tbox;
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print a clipping path */
+void
+gx_cpath_print(const gx_clip_path *pcpath)
+{ const gx_clip_rect *pr;
+ if ( pcpath->segments_valid )
+ gx_path_print(&pcpath->path);
+ else
+ dputs(" (segments not valid)\n");
+ dprintf4(" inner_box=(%g,%g),(%g,%g)\n",
+ fixed2float(pcpath->inner_box.p.x),
+ fixed2float(pcpath->inner_box.p.y),
+ fixed2float(pcpath->inner_box.q.x),
+ fixed2float(pcpath->inner_box.q.y));
+ dprintf5(" outer_box=(%g,%g),(%g,%g) count=%d\n",
+ fixed2float(pcpath->outer_box.p.x),
+ fixed2float(pcpath->outer_box.p.y),
+ fixed2float(pcpath->outer_box.q.x),
+ fixed2float(pcpath->outer_box.q.y),
+ pcpath->list.count);
+ dprintf2(" rule=%d outside=%d\n",
+ pcpath->rule, pcpath->list.outside);
+ switch ( pcpath->list.count )
+ {
+ case 0: pr = 0; break;
+ case 1: pr = &pcpath->list.single; break;
+ default: pr = pcpath->list.head;
+ }
+ for ( ; pr != 0; pr = pr->next )
+ dprintf4(" rect: (%d,%d),(%d,%d)\n",
+ pr->xmin, pr->ymin, pr->xmax, pr->ymax);
+}
+
+#endif /* DEBUG */
diff --git a/gs/src/gxcpath.h b/gs/src/gxcpath.h
new file mode 100644
index 000000000..f5b88f624
--- /dev/null
+++ b/gs/src/gxcpath.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcpath.h */
+/* Interface to clipping devices */
+/* Requires gxdevice.h */
+
+/* We expose the implementation of clipping lists so that clients */
+/* can allocate clipping lists or devices on the stack. */
+
+/*
+ * For clipping, a path is represented as a list of rectangles.
+ * Normally, a path is created as a list of segments;
+ * installing it as a clipping path creates the rectangle list.
+ * However, when the clipping path originates in some other way
+ * (e.g., from initclip, or for clipping a cached character),
+ * or if it is a non-trivial intersection of two paths,
+ * the resulting clipping path exists only as a rectangle list;
+ * clippath constructs the segment representation if needed.
+ * Note that even if the path only exists as a rectangle list,
+ * its bounding box (path.bbox) is still correct.
+ */
+
+/*
+ * Rectangle list structure.
+ * Consecutive gx_clip_rect entries either have the same Y values,
+ * or ymin of this entry >= ymax of the previous entry.
+ */
+typedef struct gx_clip_rect_s gx_clip_rect;
+struct gx_clip_rect_s {
+ gx_clip_rect *next, *prev;
+ int ymin, ymax; /* ymax > ymin */
+ int xmin, xmax; /* xmax > xmin */
+ byte to_visit; /* bookkeeping for gs_clippath */
+};
+/* The descriptor is public only for gxacpath.c. */
+extern_st(st_clip_rect);
+#define public_st_clip_rect() /* in gxcpath.c */\
+ gs_public_st_ptrs2(st_clip_rect, gx_clip_rect, "clip_rect",\
+ clip_rect_enum_ptrs, clip_rect_reloc_ptrs, next, prev)
+#define st_clip_rect_max_ptrs 2
+
+/*
+ * A clip list may consist either of a single rectangle,
+ * with null head and tail, or a list of rectangles. In the latter case,
+ * there is a dummy head entry with p.x = q.x to cover Y values
+ * starting at min_int, and a dummy tail entry to cover Y values
+ * ending at max_int. This eliminates the need for end tests.
+ */
+#ifndef gx_clip_list_DEFINED
+# define gx_clip_list_DEFINED
+typedef struct gx_clip_list_s gx_clip_list;
+#endif
+struct gx_clip_list_s {
+ gx_clip_rect single; /* (has next = prev = 0) */
+ gx_clip_rect *head;
+ gx_clip_rect *tail;
+ int count; /* # of rectangles not counting */
+ /* head or tail */
+ bool outside; /* if true, clip to outside of list */
+ /* rather than inside */
+};
+#define private_st_clip_list() /* in gxcpath.c */\
+ gs_private_st_ptrs2(st_clip_list, gx_clip_list, "clip_list",\
+ clip_list_enum_ptrs, clip_list_reloc_ptrs, head, tail)
+#define st_clip_list_max_ptrs 2 /* head, tail */
+#define clip_list_is_rectangle(clp) ((clp)->count <= 1)
+
+/*
+ * Clipping devices provide for translation before clipping.
+ * This ability, a late addition, currently is used only in a few
+ * situations that require breaking up a transfer into pieces,
+ * but we suspect it could be used more widely.
+ */
+typedef struct gx_device_clip_s {
+ gx_device_forward_common; /* target is set by client */
+ gx_clip_list list; /* set by client */
+ gx_clip_rect *current; /* cursor in list */
+ gs_int_point translation;
+} gx_device_clip;
+extern_st(st_device_clip);
+#define public_st_device_clip() /* in gxcpath.c */\
+ gs_public_st_composite(st_device_clip, gx_device_clip,\
+ "gx_device_clip", device_clip_enum_ptrs, device_clip_reloc_ptrs)
+void gx_make_clip_translate_device(P5(gx_device_clip *dev, void *container,
+ const gx_clip_list *list, int tx, int ty));
+#define gx_make_clip_device(dev, container, list)\
+ gx_make_clip_translate_device(dev, container, list, 0, 0)
+void gx_make_clip_path_device(P2(gx_device_clip *, const gx_clip_path *));
+
+#define clip_rect_print(ch, str, ar)\
+ if_debug7(ch, "[%c]%s 0x%lx: (%d,%d),(%d,%d)\n", ch, str, (ulong)ar,\
+ (ar)->xmin, (ar)->ymin, (ar)->xmax, (ar)->ymax)
+
+/* Routines exported from gxcpath.c for gxacpath.c */
+
+/* Initialize a clip list. */
+void gx_clip_list_init(P1(gx_clip_list *));
+
+/* Free a clip list. */
+void gx_clip_list_free(P2(gx_clip_list *, gs_memory_t *));
+
+/* Set the outer box for a clipping path from its bounding box. */
+void gx_cpath_set_outer_box(P1(gx_clip_path *));
diff --git a/gs/src/gxcspace.h b/gs/src/gxcspace.h
new file mode 100644
index 000000000..6740e574c
--- /dev/null
+++ b/gs/src/gxcspace.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcspace.h */
+/* Implementation of color spaces */
+
+#ifndef gxcspace_INCLUDED
+# define gxcspace_INCLUDED
+
+#include "gscspace.h" /* client interface */
+#include "gsccolor.h"
+#include "gscsel.h"
+#include "gsstruct.h" /* needed for enum_ptrs & reloc_ptrs */
+#include "gxfrac.h" /* for concrete colors */
+
+/* Define opaque types. */
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+/* Color space types (classes): */
+/*typedef struct gs_color_space_type_s gs_color_space_type;*/
+struct gs_color_space_type_s {
+
+ gs_color_space_index index;
+
+ /* Define the number of components in a color of this space. */
+ /* For Pattern spaces, where the number of components depends on */
+ /* the underlying space, this value is -1. */
+
+ int num_components;
+
+ /* Define whether the space can be the base space for */
+ /* an Indexed color space or the alternate space for */
+ /* a Separation color space. */
+
+ bool can_be_base_space;
+
+ /* ------ Procedures ------ */
+
+ /* Construct the initial color value for this space. */
+
+#define cs_proc_init_color(proc)\
+ void proc(P2(gs_client_color *, const gs_color_space *))
+#define cs_init_color(pcc, pcs)\
+ (*(pcs)->type->init_color)(pcc, pcs)
+#define cs_full_init_color(pcc, pcs)\
+ ((pcc)->pattern = 0, cs_init_color(pcc, pcs))
+ cs_proc_init_color((*init_color));
+
+ /* Return the concrete color space underlying this one. */
+ /* (Not defined for Pattern spaces.) */
+
+#define cs_proc_concrete_space(proc)\
+ const gs_color_space *proc(P2(const gs_color_space *,\
+ const gs_imager_state *))
+#define cs_concrete_space(pcs, pis)\
+ (*(pcs)->type->concrete_space)(pcs, pis)
+ cs_proc_concrete_space((*concrete_space));
+
+ /* Reduce a color to a concrete color. */
+ /* (Not defined for Pattern spaces.) */
+
+#define cs_proc_concretize_color(proc)\
+ int proc(P4(const gs_client_color *, const gs_color_space *,\
+ frac *, const gs_imager_state *))
+ cs_proc_concretize_color((*concretize_color));
+
+ /* Map a concrete color to a device color. */
+ /* (Only defined for concrete color spaces.) */
+
+#define cs_proc_remap_concrete_color(proc)\
+ int proc(P5(const frac *, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+ cs_proc_remap_concrete_color((*remap_concrete_color));
+
+ /* Map a color directly to a device color. */
+
+#define cs_proc_remap_color(proc)\
+ int proc(P6(const gs_client_color *, const gs_color_space *,\
+ gx_device_color *, const gs_imager_state *, gx_device *,\
+ gs_color_select_t))
+ cs_proc_remap_color((*remap_color));
+
+ /* Install the color space in a graphics state. */
+
+#define cs_proc_install_cspace(proc)\
+ int proc(P2(gs_color_space *, gs_state *))
+ cs_proc_install_cspace((*install_cspace));
+
+ /* Adjust reference counts of indirect color space components. */
+#define cs_proc_adjust_cspace_count(proc)\
+ void proc(P3(const gs_color_space *, gs_memory_t *, int))
+#define cs_adjust_cspace_count(pgs, delta)\
+ (*(pgs)->color_space->type->adjust_cspace_count)((pgs)->color_space, (pgs)->memory, delta)
+ cs_proc_adjust_cspace_count((*adjust_cspace_count));
+
+ /* Adjust reference counts of indirect color components. */
+
+#define cs_proc_adjust_color_count(proc)\
+ void proc(P4(const gs_client_color *, const gs_color_space *, gs_memory_t *, int))
+#define cs_adjust_color_count(pgs, delta)\
+ (*(pgs)->color_space->type->adjust_color_count)((pgs)->ccolor, (pgs)->color_space, (pgs)->memory, delta)
+ cs_proc_adjust_color_count((*adjust_color_count));
+
+/* Adjust both reference counts. */
+#define cs_adjust_counts(pgs, delta)\
+ cs_adjust_color_count(pgs, delta), cs_adjust_cspace_count(pgs, delta)
+
+ /* Enumerate the pointers in a color space. */
+
+ struct_proc_enum_ptrs((*enum_ptrs));
+
+ /* Relocate the pointers in a color space. */
+
+ struct_proc_reloc_ptrs((*reloc_ptrs));
+
+};
+/* Standard color space procedures */
+cs_proc_init_color(gx_init_paint_1);
+cs_proc_init_color(gx_init_paint_3);
+cs_proc_init_color(gx_init_paint_4);
+cs_proc_concrete_space(gx_no_concrete_space);
+cs_proc_concrete_space(gx_same_concrete_space);
+cs_proc_concretize_color(gx_no_concretize_color);
+cs_proc_remap_color(gx_default_remap_color);
+cs_proc_install_cspace(gx_no_install_cspace);
+cs_proc_adjust_cspace_count(gx_no_adjust_cspace_count);
+cs_proc_adjust_color_count(gx_no_adjust_color_count);
+#define gx_no_cspace_enum_ptrs gs_no_struct_enum_ptrs
+#define gx_no_cspace_reloc_ptrs gs_no_struct_reloc_ptrs
+
+/* Macro for defining color space procedures. */
+#define cs_declare_procs(scope, concretize, install, adjust, enum_p, reloc_p)\
+ scope cs_proc_concretize_color(concretize);\
+ scope cs_proc_install_cspace(install);\
+ scope cs_proc_adjust_cspace_count(adjust);\
+ scope struct_proc_enum_ptrs(enum_p);\
+ scope struct_proc_reloc_ptrs(reloc_p)
+
+/* Standard color space types */
+extern const gs_color_space_type
+ gs_color_space_type_DeviceGray,
+ gs_color_space_type_DeviceRGB,
+ gs_color_space_type_DeviceCMYK;
+
+/* Define the allocator type for color spaces. */
+extern_st(st_color_space);
+
+#endif /* gxcspace_INCLUDED */
diff --git a/gs/src/gxctable.c b/gs/src/gxctable.c
new file mode 100644
index 000000000..596eaf743
--- /dev/null
+++ b/gs/src/gxctable.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxctable.c */
+/* Color table lookup and interpolation */
+#include "gx.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxctable.h"
+
+/* See gxctable.h for the API and structure definitions. */
+
+/*
+ * Define an implementation that simply picks the nearest value without
+ * any interpolation.
+ */
+void
+gx_color_interpolate_nearest(const fixed *pi,
+ const gx_color_lookup_table *pclt, frac *pv)
+{ const int *pdim = pclt->dims;
+ int m = pclt->m;
+ const gs_const_string *table = pclt->table;
+
+ if ( pclt->n > 3 )
+ { table += fixed2int_var_rounded(pi[0]) * pdim[1];
+ ++pi, ++pdim;
+ }
+ { int ic = fixed2int_var_rounded(pi[2]);
+ int ib = fixed2int_var_rounded(pi[1]);
+ int ia = fixed2int_var_rounded(pi[0]);
+ const byte *p = pclt->table[ia].data + (ib * pdim[2] + ic) * m;
+ int j;
+
+ for ( j = 0; j < m; ++j, ++p )
+ pv[j] = byte2frac(*p);
+ }
+}
+
+/*
+ * Define an implementation that uses trilinear interpolation.
+ */
+void
+gx_color_interpolate_linear(const fixed *pi,
+ const gx_color_lookup_table *pclt, frac *pv)
+{ const int *pdim = pclt->dims;
+ int m = pclt->m;
+
+ if ( pclt->n > 3 )
+ { /* Do two 3-D interpolations, */
+ /* and then interpolate between them. */
+ gx_color_lookup_table clt3;
+ frac vx[4];
+ int ix = fixed2int_var(pi[0]);
+ fixed fx = fixed_fraction(pi[0]);
+ int j;
+
+ clt3.n = 3;
+ /*clt3.dims[0] = pdim[1];*/ /* not used */
+ clt3.dims[1] = pdim[2];
+ clt3.dims[2] = pdim[3];
+ clt3.m = m;
+ clt3.table = pclt->table + ix * pdim[1];
+ gx_color_interpolate_linear(pi + 1, &clt3, pv);
+ if ( ix == pdim[0] - 1 )
+ return;
+ clt3.table += pdim[1];
+ gx_color_interpolate_linear(pi + 1, &clt3, vx);
+ for ( j = 0; j < m; ++j )
+ pv[j] += (frac)arith_rshift((long)fx * (vx[j] - pv[j]),
+ _fixed_shift);
+ }
+ else
+ { int ic = fixed2int_var(pi[2]);
+ fixed fc = fixed_fraction(pi[2]);
+ uint dc1 = (ic == pdim[2] - 1 ? 0 : m);
+ int ib = fixed2int_var(pi[1]);
+ fixed fb = fixed_fraction(pi[1]);
+ uint db1 = (ib == pdim[1] - 1 ? 0 : pdim[2] * m);
+ uint dbc = (ib * pdim[2] + ic) * m;
+ uint dbc1 = db1 + dc1;
+ int ia = fixed2int_var(pi[0]);
+ fixed fa = fixed_fraction(pi[0]);
+ const byte *pa0 = pclt->table[ia].data + dbc;
+ const byte *pa1 =
+ (ia == pdim[0] - 1 ? pa0 : pclt->table[ia+1].data + dbc);
+ int j;
+
+ /* The values to be interpolated are */
+ /* pa{0,1}[{0,db1,dc1,dbc1}]. */
+ for ( j = 0; j < m; ++j, ++pa0, ++pa1 )
+ { frac v000 = byte2frac(pa0[0]);
+ frac v001 = byte2frac(pa0[dc1]);
+ frac v010 = byte2frac(pa0[db1]);
+ frac v011 = byte2frac(pa0[dbc1]);
+ frac v100 = byte2frac(pa1[0]);
+ frac v101 = byte2frac(pa1[dc1]);
+ frac v110 = byte2frac(pa1[db1]);
+ frac v111 = byte2frac(pa1[dbc1]);
+
+ frac v00 = v000 +
+ (frac)arith_rshift((long)fc * (v001 - v000),
+ _fixed_shift);
+ frac v01 = v010 +
+ (frac)arith_rshift((long)fc * (v011 - v010),
+ _fixed_shift);
+ frac v10 = v100 +
+ (frac)arith_rshift((long)fc * (v101 - v100),
+ _fixed_shift);
+ frac v11 = v110 +
+ (frac)arith_rshift((long)fc * (v111 - v110),
+ _fixed_shift);
+
+ frac v0 = v00 +
+ (frac)arith_rshift((long)fb * (v01 - v00),
+ _fixed_shift);
+ frac v1 = v10 +
+ (frac)arith_rshift((long)fb * (v11 - v10),
+ _fixed_shift);
+
+ pv[j] = v0 +
+ (frac)arith_rshift((long)fa * (v1 - v0),
+ _fixed_shift);
+ }
+ }
+}
diff --git a/gs/src/gxctable.h b/gs/src/gxctable.h
new file mode 100644
index 000000000..bd0877008
--- /dev/null
+++ b/gs/src/gxctable.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxctable.h */
+/* Interface to color table lookup and interpolation */
+#include "gxfixed.h"
+#include "gxfrac.h"
+
+/*
+ * Define a 3- or 4-D color lookup table.
+ * n is the number of dimensions (input indices), 3 or 4.
+ * dims[0..n-1] are the table dimensions.
+ * m is the number of output values, 3 or 4.
+ * For n = 3:
+ * table[i], 0 <= i < dims[0], point to strings of length
+ * dims[1] x dims[2] x m.
+ * For n = 4:
+ * table[i], 0 <= i < dims[0] x dims[1], points to strings of length
+ * dims[2] x dims[3] x m.
+ * It isn't really necessary to store the size of each string, since
+ * they're all the same size, but it makes things a lot easier for the GC.
+ */
+typedef struct gx_color_lookup_table_s {
+ int n;
+ int dims[4]; /* [ndims] */
+ int m;
+ const gs_const_string *table;
+} gx_color_lookup_table;
+
+/*
+ * Interpolate in a 3- or 4-D color lookup table.
+ * pi[0..n-1] are the table indices, guaranteed to be in the ranges
+ * [0..dims[n]-1] respectively.
+ * Return interpolated values in pv[0..m-1].
+ */
+
+/* Return the nearest value without interpolation. */
+void gx_color_interpolate_nearest(P3(const fixed *pi,
+ const gx_color_lookup_table *pclt, frac *pv));
+
+/* Use trilinear interpolation. */
+void gx_color_interpolate_linear(P3(const fixed *pi,
+ const gx_color_lookup_table *pclt, frac *pv));
diff --git a/gs/src/gxcvalue.h b/gs/src/gxcvalue.h
new file mode 100644
index 000000000..eea14b5a1
--- /dev/null
+++ b/gs/src/gxcvalue.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxcvalue.h */
+/* Definition of device color values */
+
+#ifndef gxcvalue_INCLUDED
+# define gxcvalue_INCLUDED
+
+/* Define the type for gray or RGB values at the driver interface. */
+typedef unsigned short gx_color_value;
+#define arch_sizeof_gx_color_value arch_sizeof_short
+/* We might use less than the full range someday. */
+/* ...bits must lie between 8 and 16. */
+#define gx_color_value_bits (sizeof(gx_color_value) * 8)
+#define gx_max_color_value ((gx_color_value)((1L << gx_color_value_bits) - 1))
+#define gx_color_value_to_byte(cv)\
+ ((cv) >> (gx_color_value_bits - 8))
+#define gx_color_value_from_byte(cb)\
+ (((cb) << (gx_color_value_bits - 8)) + ((cb) >> (16 - gx_color_value_bits)))
+
+/* Convert between gx_color_values and fracs. */
+#define frac2cv(fr) frac2ushort(fr)
+#define cv2frac(cv) ushort2frac(cv)
+
+#endif /* gxcvalue_INCLUDED */
diff --git a/gs/src/gxdcconv.c b/gs/src/gxdcconv.c
new file mode 100644
index 000000000..bd526527e
--- /dev/null
+++ b/gs/src/gxdcconv.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdcconv.c */
+/* Conversion between device color spaces for Ghostscript */
+#include "gx.h"
+#include "gsdcolor.h" /* for gxcmap.h */
+#include "gxdcconv.h" /* interface */
+#include "gxdevice.h" /* for gxcmap.h */
+#include "gxcmap.h"
+#include "gxfarith.h"
+#include "gxlum.h"
+#include "gxistate.h"
+
+/*
+ * The CMYK to RGB algorithms specified by Adobe are, e.g.,
+ * R = 1.0 - min(1.0, C + K)
+ * C = max(0.0, min(1.0, 1 - R - UCR))
+ * but we get much better results with
+ * R = (1.0 - C) * (1.0 - K)
+ * C = max(0.0, min(1.0, 1 - R / (1 - UCR)))
+ * For utmost compatibility, we offer the Adobe algorithms as an option:
+ */
+#define USE_ADOBE_CMYK_RGB
+
+/* ------ Color space conversion ------ */
+
+/* Only 4 of the 6 conversions are implemented here; */
+/* the other 2 (Gray to RGB/CMYK) are trivial. */
+
+/* Convert RGB to Gray. */
+frac
+color_rgb_to_gray(frac r, frac g, frac b, const gs_imager_state *pis)
+{ return (r * (unsigned long)lum_red_weight +
+ g * (unsigned long)lum_green_weight +
+ b * (unsigned long)lum_blue_weight +
+ (lum_all_weights / 2))
+ / lum_all_weights;
+}
+
+/* Convert RGB to CMYK. */
+/* Note that this involves black generation and undercolor removal. */
+void
+color_rgb_to_cmyk(frac r, frac g, frac b, const gs_imager_state *pis,
+ frac cmyk[4])
+{ frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b;
+ frac k = (c < m ? min(c, y) : min(m, y));
+ /* The default UCR and BG functions are pretty arbitrary.... */
+ frac bg =
+ (pis->black_generation == NULL ? frac_0 :
+ gx_map_color_frac(pis, k, black_generation));
+ signed_frac ucr =
+ (pis->undercolor_removal == NULL ? frac_0 :
+ gx_map_color_frac(pis, k, undercolor_removal));
+ if ( ucr == frac_1 )
+ cmyk[0] = cmyk[1] = cmyk[2] = 0;
+ else
+ {
+#ifdef USE_ADOBE_CMYK_RGB
+ /* C = max(0.0, min(1.0, 1 - R - UCR)), etc. */
+ signed_frac not_ucr = (ucr < 0 ? frac_1 + ucr : frac_1);
+ cmyk[0] = (c < ucr ? frac_0 : c > not_ucr ? frac_1 : c - ucr);
+ cmyk[1] = (m < ucr ? frac_0 : m > not_ucr ? frac_1 : m - ucr);
+ cmyk[2] = (y < ucr ? frac_0 : y > not_ucr ? frac_1 : y - ucr);
+#else
+ /* C = max(0.0, min(1.0, 1 - R / (1 - UCR))), etc. */
+ float denom = frac2float(frac_1 - ucr); /* unscaled */
+ float v;
+ v = (float)frac_1 - r / denom; /* unscaled */
+ cmyk[0] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac)v);
+ v = (float)frac_1 - g / denom; /* unscaled */
+ cmyk[1] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac)v);
+ v = (float)frac_1 - b / denom; /* unscaled */
+ cmyk[2] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac)v);
+#endif
+ }
+ cmyk[3] = bg;
+ if_debug7('c', "[c]RGB 0x%x,0x%x,0x%x -> CMYK 0x%x,0x%x,0x%x,0x%x\n",
+ r, g, b, cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
+}
+
+/* Convert CMYK to Gray. */
+frac
+color_cmyk_to_gray(frac c, frac m, frac y, frac k, const gs_imager_state *pis)
+{ frac not_gray = color_rgb_to_gray(c, m, y, pis);
+ return (not_gray > frac_1 - k ? /* gray + k > 1.0 */
+ frac_0 : frac_1 - (not_gray + k));
+}
+
+/* Convert CMYK to RGB. */
+void
+color_cmyk_to_rgb(frac c, frac m, frac y, frac k, const gs_imager_state *pis,
+ frac rgb[3])
+{ switch ( k )
+ {
+ case frac_0:
+ rgb[0] = frac_1 - c;
+ rgb[1] = frac_1 - m;
+ rgb[2] = frac_1 - y;
+ break;
+ case frac_1:
+ rgb[0] = rgb[1] = rgb[2] = frac_0;
+ break;
+ default:
+ {
+#ifdef USE_ADOBE_CMYK_RGB
+ /* R = 1.0 - min(1.0, C + K), etc. */
+ frac not_k = frac_1 - k;
+ rgb[0] = (c > not_k ? frac_0 : not_k - c);
+ rgb[1] = (m > not_k ? frac_0 : not_k - m);
+ rgb[2] = (y > not_k ? frac_0 : not_k - y);
+#else
+ /* R = (1.0 - C) * (1.0 - K), etc. */
+ ulong not_k = frac_1 - k;
+ /* Compute not_k * (frac_1 - v) / frac_1 efficiently. */
+ ulong prod;
+#define deduct_black(v)\
+ (prod = (frac_1 - (v)) * not_k, frac_1_quo(prod))
+ rgb[0] = deduct_black(c);
+ rgb[1] = deduct_black(m);
+ rgb[2] = deduct_black(y);
+#undef deduct_black
+#endif
+ }
+ }
+ if_debug7('c', "[c]CMYK 0x%x,0x%x,0x%x,0x%x -> RGB 0x%x,0x%x,0x%x\n",
+ c, m, y, k, rgb[0], rgb[1], rgb[2]);
+}
diff --git a/gs/src/gxdcconv.h b/gs/src/gxdcconv.h
new file mode 100644
index 000000000..2ae3a323a
--- /dev/null
+++ b/gs/src/gxdcconv.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 1992, 1993, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdcconv.h */
+/* Internal device color conversion interfaces */
+#include "gxfrac.h"
+
+/* Color space conversion routines */
+frac color_rgb_to_gray(P4(frac r, frac g, frac b,
+ const gs_imager_state *pis));
+void color_rgb_to_cmyk(P5(frac r, frac g, frac b,
+ const gs_imager_state *pis, frac cmyk[4]));
+frac color_cmyk_to_gray(P5(frac c, frac m, frac y, frac k,
+ const gs_imager_state *pis));
+void color_cmyk_to_rgb(P6(frac c, frac m, frac y, frac k,
+ const gs_imager_state *pis, frac rgb[3]));
diff --git a/gs/src/gxdcolor.c b/gs/src/gxdcolor.c
new file mode 100644
index 000000000..040fa3bf3
--- /dev/null
+++ b/gs/src/gxdcolor.c
@@ -0,0 +1,210 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdcolor.c */
+/* Pure and null device color implementation */
+#include "gx.h"
+#include "gsbittab.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+
+/* Define the standard device color types. */
+private dev_color_proc_load(gx_dc_no_load);
+private dev_color_proc_fill_rectangle(gx_dc_no_fill_rectangle);
+private dev_color_proc_fill_masked(gx_dc_no_fill_masked);
+private dev_color_proc_load(gx_dc_pure_load);
+private dev_color_proc_fill_rectangle(gx_dc_pure_fill_rectangle);
+private dev_color_proc_fill_masked(gx_dc_pure_fill_masked);
+const gx_device_color_procs
+ gx_dc_procs_none =
+ { gx_dc_no_load, gx_dc_no_fill_rectangle, gx_dc_no_fill_masked, 0, 0 },
+ /* null is different from none, but it has the same procedures. */
+ gx_dc_procs_null =
+ { gx_dc_no_load, gx_dc_no_fill_rectangle, gx_dc_no_fill_masked, 0, 0 },
+ gx_dc_procs_pure =
+ { gx_dc_pure_load, gx_dc_pure_fill_rectangle, gx_dc_pure_fill_masked, 0, 0 };
+#undef gx_dc_type_none
+const gx_device_color_procs _ds *gx_dc_type_none = &gx_dc_procs_none;
+#define gx_dc_type_none (&gx_dc_procs_none)
+#undef gx_dc_type_null
+const gx_device_color_procs _ds *gx_dc_type_null = &gx_dc_procs_null;
+#define gx_dc_type_null (&gx_dc_procs_null)
+#undef gx_dc_type_pure
+const gx_device_color_procs _ds *gx_dc_type_pure = &gx_dc_procs_pure;
+#define gx_dc_type_pure (&gx_dc_procs_pure)
+
+/* Define a null RasterOp source (for black = 0). */
+const gx_rop_source_t gx_rop_no_source_0 = { gx_rop_no_source_body(0) };
+
+/* ------ Null color ------ */
+
+private int
+gx_dc_no_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
+ gx_device *ignore_dev, gs_color_select_t ignore_select)
+{ return 0;
+}
+
+private int
+gx_dc_no_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ return 0;
+}
+
+private int
+gx_dc_no_fill_masked(const gx_device_color *pdevc, const byte *data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_device *dev, gs_logical_operation_t lop, bool invert)
+{ return 0;
+}
+
+/* ------ Pure color ------ */
+
+private int
+gx_dc_pure_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
+ gx_device *ignore_dev, gs_color_select_t ignore_select)
+{ return 0;
+}
+
+/* Fill a rectangle with a pure color. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_pure_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ if ( source == NULL && lop_no_S_is_T(lop) )
+ return (*dev_proc(dev, fill_rectangle))(dev, x, y, w, h,
+ pdevc->colors.pure);
+ { gx_color_index colors[2];
+ gx_rop_source_t no_source;
+
+ colors[0] = colors[1] = pdevc->colors.pure;
+ if ( source == NULL )
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, source->sdata, source->sourcex, source->sraster,
+ source->id, (source->use_scolors ? source->scolors : NULL),
+ NULL /*arbitrary*/, colors, x, y, w, h, 0, 0, lop);
+ }
+}
+
+/* Fill a mask with a pure color. */
+/* Note that there is no source in this case: the mask is the source. */
+private int
+gx_dc_pure_fill_masked(const gx_device_color *pdevc, const byte *data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_device *dev, gs_logical_operation_t lop, bool invert)
+{ if ( lop_no_S_is_T(lop) )
+ { gx_color_index color0, color1;
+ if ( invert )
+ color0 = pdevc->colors.pure, color1 = gx_no_color_index;
+ else
+ color1 = pdevc->colors.pure, color0 = gx_no_color_index;
+ return (*dev_proc(dev, copy_mono))
+ (dev, data, data_x, raster, id, x, y, w, h, color0, color1);
+ }
+ { gx_color_index scolors[2];
+ gx_color_index tcolors[2];
+
+ scolors[0] = (*dev_proc(dev, map_rgb_color))
+ (dev, (gx_color_value)0, (gx_color_value)0, (gx_color_value)0);
+ scolors[1] = (*dev_proc(dev, map_rgb_color))
+ (dev, gx_max_color_value, gx_max_color_value, gx_max_color_value);
+ tcolors[0] = tcolors[1] = pdevc->colors.pure;
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, data, data_x, raster, id, scolors,
+ NULL, tcolors, x, y, w, h, 0, 0,
+ (invert ? rop3_invert_S(lop) : lop) | lop_S_transparent);
+ }
+}
+
+/* ------ Default implementations ------ */
+
+/* Fill a mask with a color by parsing the mask into rectangles. */
+int
+gx_dc_default_fill_masked(const gx_device_color *pdevc, const byte *data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_device *dev, gs_logical_operation_t lop, bool invert)
+{ int lbit = data_x & 7;
+ const byte *row = data + (data_x >> 3);
+ uint one = (invert ? 0 : 0xff);
+ uint zero = one ^ 0xff;
+ int iy;
+
+ for ( iy = 0; iy < h; ++iy, row += raster )
+ { const byte *p = row;
+ int bit = lbit;
+ int left = w;
+ int l0;
+
+ while ( left )
+ { int run, code;
+
+ /* Skip a run of zeros. */
+ run = byte_bit_run_length[bit][*p ^ one];
+ if ( run )
+ { if ( run < 8 )
+ { if ( run >= left )
+ break; /* end of row while skipping */
+ bit += run, left -= run;
+ }
+ else if ( (run -= 8) >= left )
+ break; /* end of row while skipping */
+ else
+ { left -= run;
+ ++p;
+ while ( left > 8 && *p == zero )
+ left -= 8, ++p;
+ run = byte_bit_run_length_0[*p ^ one];
+ if ( run >= left ) /* run < 8 unless very last byte */
+ break; /* end of row while skipping */
+ else
+ bit = run & 7, left -= run;
+ }
+ }
+
+ l0 = left;
+ /* Scan a run of ones, and then paint it. */
+ run = byte_bit_run_length[bit][*p ^ zero];
+ if ( run < 8 )
+ { if ( run >= left )
+ left = 0;
+ else
+ bit += run, left -= run;
+ }
+ else if ( (run -= 8) >= left )
+ left = 0;
+ else
+ { left -= run;
+ ++p;
+ while ( left > 8 && *p == one )
+ left -= 8, ++p;
+ run = byte_bit_run_length_0[*p ^ zero];
+ if ( run >= left ) /* run < 8 unless very last byte */
+ left = 0;
+ else
+ bit = run & 7, left -= run;
+ }
+ code = gx_device_color_fill_rectangle(pdevc,
+ x + w - l0, y + iy, l0 - left, 1, dev, lop, NULL);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gxdcolor.h b/gs/src/gxdcolor.h
new file mode 100644
index 000000000..314636530
--- /dev/null
+++ b/gs/src/gxdcolor.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdcolor.h */
+/* Device color representation for Ghostscript */
+
+#ifndef gxdcolor_INCLUDED
+# define gxdcolor_INCLUDED
+
+#include "gscsel.h"
+#include "gsdcolor.h"
+#include "gsropt.h"
+#include "gsstruct.h" /* for extern_st, GC procs */
+
+/* Define opaque types. */
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+/*
+ * Define a source structure for RasterOp.
+ */
+typedef struct gx_rop_source_s {
+ const byte *sdata;
+ int sourcex;
+ uint sraster;
+ gx_bitmap_id id;
+ gx_color_index scolors[2];
+ bool use_scolors;
+} gx_rop_source_t;
+/*
+ * Note that the following definition depends on the gx_color_index for
+ * black, which may not be 0. Clients must check this and construct
+ * a different null source if necessary.
+ */
+#define gx_rop_no_source_body(black_pixel)\
+ NULL, 0, 0, gx_no_bitmap_id, {black_pixel, black_pixel}, true
+#define gx_rop_source_set_color(prs, pixel)\
+ ((prs)->scolors[0] = (prs)->scolors[1] = (pixel))
+extern const gx_rop_source_t gx_rop_no_source_0; /* with black_pixel = 0 */
+#define set_rop_no_source(source, no_source, dev)\
+ do {\
+ gx_color_index black_ =\
+ (*dev_proc(dev, map_rgb_color))(dev, (gx_color_index)0,\
+ (gx_color_index)0, (gx_color_index)0);\
+ if ( black_ == 0 )\
+ source = &gx_rop_no_source_0;\
+ else\
+ { no_source = gx_rop_no_source_0;\
+ gx_rop_source_set_color(&no_source, black_);\
+ source = &no_source;\
+ }\
+ } while (0)
+
+/*
+ * Device colors are 'objects' (with very few procedures). In order to
+ * simplify memory management, we use a union, but since different variants
+ * may have different pointer tracing procedures, we have to include those
+ * procedures in the type.
+ */
+
+struct gx_device_color_procs_s {
+
+ /*
+ * If necessary and possible, load the halftone or Pattern cache
+ * with the rendering of this color.
+ */
+
+#define dev_color_proc_load(proc)\
+ int proc(P4(gx_device_color *pdevc, const gs_imager_state *pis,\
+ gx_device *dev, gs_color_select_t select))
+ dev_color_proc_load((*load));
+
+ /*
+ * Fill a rectangle with the color.
+ * We pass the device separately so that pattern fills can
+ * substitute a tiled mask clipping device.
+ */
+
+#define dev_color_proc_fill_rectangle(proc)\
+ int proc(P8(const gx_device_color *pdevc, int x, int y, int w, int h,\
+ gx_device *dev, gs_logical_operation_t lop, const gx_rop_source_t *source))
+ dev_color_proc_fill_rectangle((*fill_rectangle));
+
+ /*
+ * Fill a masked region with a color. Nearly all device colors
+ * use the default implementation, which simply parses the mask
+ * into rectangles and calls fill_rectangle. Note that in this
+ * case there is no RasterOp source: the mask is the source.
+ */
+
+#define dev_color_proc_fill_masked(proc)\
+ int proc(P12(const gx_device_color *pdevc, const byte *data, int data_x,\
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,\
+ gx_device *dev, gs_logical_operation_t lop, bool invert))
+ dev_color_proc_fill_masked((*fill_masked));
+
+ /*
+ * Trace the pointers for the garbage collector.
+ */
+
+ struct_proc_enum_ptrs((*enum_ptrs));
+ struct_proc_reloc_ptrs((*reloc_ptrs));
+
+};
+
+/* Define the default implementation of fill_masked. */
+dev_color_proc_fill_masked(gx_dc_default_fill_masked);
+
+extern_st(st_device_color);
+/* public_st_device_color() is defined in gsdcolor.h */
+
+/* Define the standard device color types. */
+/* See gsdcolor.h for details. */
+extern const gx_device_color_procs
+#define gx_dc_type_none (&gx_dc_procs_none)
+ gx_dc_procs_none, /* gxdcolor.c */
+#define gx_dc_type_null (&gx_dc_procs_null)
+ gx_dc_procs_null, /* gxdcolor.c */
+#define gx_dc_type_pure (&gx_dc_procs_pure)
+ gx_dc_procs_pure, /* gxdcolor.c */
+/*#define gx_dc_type_pattern (&gx_dc_procs_pattern)*/
+ /*gx_dc_procs_pattern,*/ /* gspcolor.c */
+#define gx_dc_type_ht_binary (&gx_dc_procs_ht_binary)
+ gx_dc_procs_ht_binary, /* gxht.c */
+#define gx_dc_type_ht_colored (&gx_dc_procs_ht_colored)
+ gx_dc_procs_ht_colored; /* gxcht.c */
+
+#define gs_color_writes_pure(pgs)\
+ color_writes_pure((pgs)->dev_color, (pgs)->log_op)
+
+/* Set up device color 1 for writing into a mask cache */
+/* (e.g., the character cache). */
+void gx_set_device_color_1(P1(gs_state *pgs));
+
+/* Remap the color if necessary. */
+int gx_remap_color(P1(gs_state *));
+#define gx_set_dev_color(pgs)\
+ if ( !color_is_set((pgs)->dev_color) )\
+ { int code_dc = gx_remap_color(pgs);\
+ if ( code_dc != 0 ) return code_dc;\
+ }
+
+/* Indicate that the device color needs remapping. */
+#define gx_unset_dev_color(pgs)\
+ color_unset((pgs)->dev_color)
+
+/* Load the halftone cache in preparation for drawing. */
+#define gx_color_load_select(pdevc, pis, dev, select)\
+ (*(pdevc)->type->load)(pdevc, pis, dev, select)
+#define gx_color_load(pdevc, pis, dev)\
+ gx_color_load_select(pdevc, pis, dev, gs_color_select_texture)
+#define gs_state_color_load(pgs)\
+ gx_color_load((pgs)->dev_color, (const gs_imager_state *)(pgs),\
+ (pgs)->device)
+
+/* Fill a rectangle with a color. */
+#define gx_device_color_fill_rectangle(pdevc, x, y, w, h, dev, lop, source)\
+ (*(pdevc)->type->fill_rectangle)(pdevc, x, y, w, h, dev, lop, source)
+#define gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop)\
+ gx_device_color_fill_rectangle(pdevc, x, y, w, h, dev, lop, NULL)
+#define gx_fill_rectangle_rop(x, y, w, h, pdevc, lop, pgs)\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, (pgs)->device, lop)
+#define gx_fill_rectangle(x, y, w, h, pdevc, pgs)\
+ gx_fill_rectangle_rop(x, y, w, h, pdevc, (pgs)->log_op, pgs)
+
+#endif /* gxdcolor_INCLUDED */
diff --git a/gs/src/gxdda.h b/gs/src/gxdda.h
new file mode 100644
index 000000000..8c68b475d
--- /dev/null
+++ b/gs/src/gxdda.h
@@ -0,0 +1,145 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdda.h */
+/* DDA definitions for Ghostscript line drawing */
+/* Requires gxfixed.h */
+
+/*
+ * We use the familiar Bresenham DDA algorithm for several purposes:
+ * - tracking the edges when filling trapezoids;
+ * - tracking the current pixel corner coordinates when rasterizing
+ * skewed or rotated images;
+ * - converting curves to sequences of lines (this is a 3rd-order
+ * DDA, the others are 1st-order);
+ * - perhaps someday for drawing single-pixel lines.
+ * In the case of trapezoids, lines, and curves, we need to use
+ * the DDA to find the integer X values at integer+0.5 values of Y;
+ * in the case of images, we use DDAs to compute the (fixed)
+ * X and Y values at (integer) source pixel corners.
+ *
+ * The purpose of the DDA is to compute the exact values Q(i) = floor(i*D/N)
+ * for increasing integers i, 0 <= i <= N. D is considered to be an
+ * integer, although it may actually be a fixed. For the algorithm,
+ * we maintain i*D/N as Q + R/N where Q and R are integers, 0 <= R < N,
+ * with the following auxiliary values:
+ * dQ = floor(D/N)
+ * dR = D mod N (0 <= dR < N)
+ * NdR = N - dR
+ * Then at each iteration we do:
+ * Q += dQ;
+ * if ( R < dR ) ++Q, R += NdR; else R -= dR;
+ * These formulas work regardless of the sign of D, and never let R go
+ * out of range.
+ */
+/* In the following structure definitions, ntype must be an unsigned type. */
+#define dda_state_struct(sname, dtype, ntype)\
+ struct sname { dtype Q; ntype R; }
+#define dda_step_struct(sname, dtype, ntype)\
+ struct sname { dtype dQ; ntype dR, NdR; }
+/* DDA with fixed Q and (unsigned) integer N */
+typedef dda_state_struct(_a, fixed, uint) gx_dda_state_fixed;
+typedef dda_step_struct(_e, fixed, uint) gx_dda_step_fixed;
+typedef struct gx_dda_fixed_s {
+ gx_dda_state_fixed state;
+ gx_dda_step_fixed step;
+} gx_dda_fixed;
+/*
+ * Define a pair of DDAs for iterating along an arbitrary line.
+ */
+typedef struct gx_dda_fixed_point_s {
+ gx_dda_fixed x, y;
+} gx_dda_fixed_point;
+/*
+ * Initialize a DDA. The sign test is needed only because C doesn't
+ * provide reliable definitions of / and % for integers (!!!).
+ */
+#define dda_init_state(dstate, init, N)\
+ (dstate).Q = (init), (dstate).R = (N)
+#define dda_init_step(dstep, D, N)\
+ if ( (N) == 0 )\
+ (dstep).dQ = 0, (dstep).dR = 0;\
+ else if ( (D) < 0 )\
+ { (dstep).dQ = -(-(D) / (N));\
+ if ( ((dstep).dR = -(D) % (N)) != 0 )\
+ --(dstep).dQ, (dstep).dR = (N) - (dstep).dR;\
+ }\
+ else\
+ { (dstep).dQ = (D) / (N); (dstep).dR = (D) % (N); }\
+ (dstep).NdR = (N) - (dstep).dR
+#define dda_init(dda, init, D, N)\
+ dda_init_state((dda).state, init, N);\
+ dda_init_step((dda).step, D, N)
+/*
+ * Compute the sum of two DDA steps with the same D and N.
+ */
+#define dda_step_add(tostep, fromstep)\
+ (tostep).dQ +=\
+ ((tostep).dR < (fromstep).NdR ?\
+ ((tostep).dR += (fromstep).dR, (fromstep).dQ) :\
+ ((tostep).dR -= (fromstep).NdR, (fromstep).dQ + 1))
+/*
+ * Return the current value in a DDA.
+ */
+#define dda_state_current(dstate) (dstate).Q
+#define dda_current(dda) dda_state_current((dda).state)
+#define dda_current_fixed2int(dda)\
+ fixed2int_var(dda_state_current((dda).state))
+/*
+ * Increment a DDA to the next point.
+ * Returns the updated current value.
+ */
+#define dda_state_next(dstate, dstep)\
+ (dstate).Q +=\
+ ((dstate).R >= (dstep).dR ?\
+ ((dstate).R -= (dstep).dR, (dstep).dQ) :\
+ ((dstate).R += (dstep).NdR, (dstep).dQ + 1))
+#define dda_next(dda) dda_state_next((dda).state, (dda).step)
+/*
+ * Back up a DDA to the previous point.
+ * Returns the updated current value.
+ */
+#define dda_state_previous(dstate, dstep)\
+ (dstate).Q -=\
+ ((dstate).R < (dstep).NdR ?\
+ ((dstate).R += (dstep).dR, (dstep).dQ) :\
+ ((dstate).R -= (dstep).NdR, (dstep).dQ + 1))
+#define dda_previous(dda) dda_state_previous((dda).state, (dda).step)
+/*
+ * Advance a DDA by an arbitrary number of steps.
+ * The do { ... } while ( 0 ) construct creates the appropriate syntax.
+ * This implementation is very inefficient; we'll improve it if needed.
+ */
+#define dda_state_advance(dstate, dstep, nsteps)\
+ do\
+ { uint n_ = (nsteps);\
+ (dstate).Q += (dstep).dQ * (nsteps);\
+ while ( n_-- )\
+ if ( (dstate).R >= (dstep).dR ) (dstate).R -= (dstep).dR;\
+ else (dstate).R += (dstep).NdR, (dstate).Q++;\
+ }\
+ while ( 0 )
+#define dda_advance(dda, nsteps)\
+ dda_state_advance((dda).state, (dda).step, nsteps)
+/*
+ * Translate the position of a DDA by a given amount.
+ */
+#define dda_state_translate(dstate, delta)\
+ ((dstate).Q += (delta))
+#define dda_translate(dda, delta)\
+ dda_state_translate((dda).state, delta)
diff --git a/gs/src/gxdevice.h b/gs/src/gxdevice.h
new file mode 100644
index 000000000..460bce410
--- /dev/null
+++ b/gs/src/gxdevice.h
@@ -0,0 +1,1004 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdevice.h */
+/* Device description structure */
+
+#ifndef gxdevice_INCLUDED
+# define gxdevice_INCLUDED
+
+#include "stdio_.h" /* for FILE */
+#include "gsdcolor.h"
+#include "gsmatrix.h"
+#include "gsiparam.h" /* requires gsmatrix.h */
+#include "gsropt.h"
+#include "gsstruct.h"
+#include "gsxfont.h"
+#include "gxbitmap.h"
+#include "gxcindex.h"
+#include "gxcvalue.h"
+#include "gxfixed.h"
+
+/* See drivers.doc for documentation of the driver interface. */
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+/* We need at least an abstract type for a graphics state, */
+/* which is passed to the page device procedures. */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+/* We need abstract types for paths and fill/stroke parameters, */
+/* for the path-oriented device procedures. */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+#endif
+#ifndef gx_fill_params_DEFINED
+# define gx_fill_params_DEFINED
+typedef struct gx_fill_params_s gx_fill_params;
+#endif
+#ifndef gx_stroke_params_DEFINED
+# define gx_stroke_params_DEFINED
+typedef struct gx_stroke_params_s gx_stroke_params;
+#endif
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+
+/* Define the type for colors passed to the higher-level procedures. */
+typedef gx_device_color gx_drawing_color;
+
+/* Define a type for telling get_alpha_bits what kind of object */
+/* is being rendered. */
+typedef enum {
+ go_text,
+ go_graphics
+} graphics_object_type;
+
+/* Define an edge of a trapezoid. Requirement: end.y >= start.y. */
+typedef struct gs_fixed_edge_s {
+ gs_fixed_point start;
+ gs_fixed_point end;
+} gs_fixed_edge;
+
+/* Define the structure for device color capabilities. */
+typedef struct gx_device_color_info_s {
+ int num_components; /* 1 = gray only, 3 = RGB, */
+ /* 4 = CMYK */
+ int depth; /* # of bits per pixel */
+ gx_color_value max_gray; /* # of distinct gray levels -1 */
+ gx_color_value max_color; /* # of distinct color levels -1 */
+ /* (only relevant if num_comp. > 1) */
+ gx_color_value dither_grays; /* size of gray ramp for dithering */
+ gx_color_value dither_colors; /* size of color cube ditto */
+ /* (only relevant if num_comp. > 1) */
+} gx_device_color_info;
+#define dci_values(nc,depth,mg,mc,dg,dc) { nc, depth, mg, mc, dg, dc }
+#define dci_std_color(color_bits)\
+ dci_values(\
+ (color_bits == 32 ? 4 : color_bits > 1 ? 3 : 1),\
+ ((color_bits > 1) & (color_bits < 8) ? 8 : color_bits),\
+ (color_bits >= 8 ? 255 : 1),\
+ (color_bits >= 8 ? 255 : color_bits > 1 ? 1 : 0),\
+ (color_bits >= 8 ? 5 : 2),\
+ (color_bits >= 8 ? 5 : color_bits > 1 ? 2 : 0)\
+ )
+#define dci_black_and_white dci_std_color(1)
+#define dci_black_and_white_() dci_black_and_white
+#define dci_color(depth,maxv,dither)\
+ dci_values(3, depth, maxv, maxv, dither, dither)
+#define gx_device_has_color(dev) ((dev)->color_info.num_components > 1)
+
+/* Structure for device procedures. */
+typedef struct gx_device_procs_s gx_device_procs;
+
+/* Structure for page device procedures. */
+/* Note that these take the graphics state as a parameter. */
+typedef struct gx_page_device_procs_s {
+
+#define dev_page_proc_install(proc)\
+ int proc(P2(gx_device *dev, gs_state *pgs))
+ dev_page_proc_install((*install));
+
+#define dev_page_proc_begin_page(proc)\
+ int proc(P2(gx_device *dev, gs_state *pgs))
+ dev_page_proc_begin_page((*begin_page));
+
+#define dev_page_proc_end_page(proc)\
+ int proc(P3(gx_device *dev, int reason, gs_state *pgs))
+ dev_page_proc_end_page((*end_page));
+
+} gx_page_device_procs;
+/* Default procedures */
+dev_page_proc_install(gx_default_install);
+dev_page_proc_begin_page(gx_default_begin_page);
+dev_page_proc_end_page(gx_default_end_page);
+
+/* Define default pages sizes. */
+/* U.S. letter paper (8.5" x 11"). */
+#define DEFAULT_WIDTH_10THS_US_LETTER 85
+#define DEFAULT_HEIGHT_10THS_US_LETTER 110
+/* A4 paper (210mm x 297mm). The dimensions are off by a few mm.... */
+#define DEFAULT_WIDTH_10THS_A4 83
+#define DEFAULT_HEIGHT_10THS_A4 117
+/* Choose a default. A4 may be set in the makefile. */
+#ifdef A4
+# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_A4
+# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_A4
+#else
+# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_US_LETTER
+# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_US_LETTER
+#endif
+
+/* ---------------- Device structure ---------------- */
+
+/*
+ * Define the generic device structure. The device procedures can
+ * have two different configurations:
+ *
+ * - Statically initialized devices predating release 2.8.1
+ * set the static_procs pointer to point to a separate procedure record,
+ * and do not initialize std_procs.
+ *
+ * - Statically initialized devices starting with release 2.8.1,
+ * and all dynamically created device instances,
+ * set the static_procs pointer to 0, and initialize std_procs.
+ *
+ * The gx_device_set_procs procedure converts the first of these to
+ * the second, which is what all client code starting in 2.8.1 expects
+ * (using the std_procs record, not the static_procs pointer, to call the
+ * driver procedures).
+ *
+ * The choice of the name Margins (rather than, say, HWOffset), and the
+ * specification in terms of a default device resolution rather than
+ * 1/72" units, are due to Adobe.
+ *
+ * ****** NOTE: If you define any subclasses of gx_device, you *must* define
+ * ****** the finalization procedure as gx_device_finalize. Finalization
+ * ****** procedures are not automatically inherited.
+ */
+#define gx_device_common\
+ int params_size; /* OBSOLETE if stype != 0: */\
+ /* size of this structure */\
+ const gx_device_procs *static_procs; /* OBSOLETE */\
+ /* pointer to std_procs */\
+ const char *dname; /* the device name */\
+ gs_memory_t *memory; /* (0 iff static prototype) */\
+ gs_memory_type_ptr_t stype; /* memory manager structure type, */\
+ /* 0 iff static prototype */\
+ bool is_open; /* true if device has been opened */\
+ int max_fill_band; /* limit on band size for fill, */\
+ /* must be 0 or a power of 2 */\
+ /* (see gdevabuf.c for more info) */\
+ gx_device_color_info color_info; /* color information */\
+ int width; /* width in pixels */\
+ int height; /* height in pixels */\
+ float MediaSize[2]; /* media dimensions in points */\
+ float ImagingBBox[4]; /* imageable region in points */\
+ bool ImagingBBox_set;\
+ float HWResolution[2]; /* resolution, dots per inch */\
+ float MarginsHWResolution[2]; /* resolution for Margins */\
+ float Margins[2]; /* offset of physical page corner */\
+ /* from device coordinate (0,0), */\
+ /* in units given by MarginsHWResolution */\
+ float HWMargins[4]; /* margins around imageable area, */\
+ /* in default user units ("points") */\
+ long PageCount; /* number of pages written */\
+ long ShowpageCount; /* number of calls on showpage */\
+ bool IgnoreNumCopies; /* if true, force num_copies = 1 */\
+ gx_page_device_procs page_procs; /* must be last */\
+ /* end of std_device_body */\
+ gx_device_procs std_procs /* standard procedures */
+#define x_pixels_per_inch HWResolution[0]
+#define y_pixels_per_inch HWResolution[1]
+#define offset_margin_values(x, y, left, bot, right, top)\
+ {x, y}, {left, bot, right, top}
+#define margin_values(left, bot, right, top)\
+ offset_margin_values(0, 0, left, bot, right, top)
+#define no_margins margin_values(0, 0, 0, 0)
+#define no_margins_() no_margins
+/* Define macros that give the page offset ("Margins") in inches. */
+#define dev_x_offset(dev) ((dev)->Margins[0] / (dev)->MarginsHWResolution[0])
+#define dev_y_offset(dev) ((dev)->Margins[1] / (dev)->MarginsHWResolution[1])
+#define dev_y_offset_points(dev) (dev_y_offset(dev) * 72.0)
+/* Note that left/right/top/bottom are defined relative to */
+/* the physical paper, not the coordinate system. */
+/* For backward compatibility, we define macros that give */
+/* the margins in inches. */
+#define dev_l_margin(dev) ((dev)->HWMargins[0] / 72.0)
+#define dev_b_margin(dev) ((dev)->HWMargins[1] / 72.0)
+#define dev_b_margin_points(dev) ((dev)->HWMargins[1])
+#define dev_r_margin(dev) ((dev)->HWMargins[2] / 72.0)
+#define dev_t_margin(dev) ((dev)->HWMargins[3] / 72.0)
+#define dev_t_margin_points(dev) ((dev)->HWMargins[3])
+/* The extra () are to prevent premature expansion. */
+#define open_init_closed() 0 /*false*/, 0 /* max_fill_band */
+#define open_init_open() 1 /*true*/, 0 /* max_fill_band */
+/* Accessors for device procedures */
+#define dev_proc(dev, p) ((dev)->std_procs.p)
+#define set_dev_proc(dev, p, proc) ((dev)->std_procs.p = (proc))
+#define fill_dev_proc(dev, p, dproc)\
+ if ( dev_proc(dev, p) == 0 ) set_dev_proc(dev, p, dproc)
+
+/*
+ * To insulate statically defined device templates from the
+ * consequences of changes in the device structure, the following macros
+ * must be used for generating initialized device structures.
+ *
+ * The computations of page width and height in pixels should really be
+ * ((int)(page_width_inches*x_dpi))
+ * but some compilers (the Ultrix 3.X pcc compiler and the HPUX compiler)
+ * can't cast a computed float to an int. That's why we specify
+ * the page width and height in inches/10 instead of inches.
+ *
+ * Note that the macro is broken up so as to be usable for devices that
+ * add further initialized state to the generic device.
+ * Note also that the macro does not initialize std_procs, which is
+ * the next element of the structure.
+ */
+#define std_device_part1_(devtype, ptr_procs, dev_name, stype, open_init)\
+ sizeof(devtype), ptr_procs, dev_name,\
+ 0 /*memory*/, stype, open_init() /*stype, is_open, cached*/
+/* color_info goes here */
+/*
+ * The MetroWerks compiler has some bizarre bug that produces a spurious
+ * error message if the width and/or height are defined as 0 below,
+ * unless we use the +/- workaround in the next macro.
+ */
+#define std_device_part2_(width, height, x_dpi, y_dpi)\
+ width, height,\
+ { (((width) * 72.0 + 0.5) - 0.5) / (x_dpi),\
+ (((height) * 72.0 + 0.5) - 0.5) / (y_dpi) },\
+ { 0, 0, 0, 0 }, 0/*false*/, { x_dpi, y_dpi }, { x_dpi, y_dpi }
+/* offsets and margins go here */
+#define std_device_part3_()\
+ 0, 0, 0/*false*/,\
+ { gx_default_install, gx_default_begin_page, gx_default_end_page }
+/*
+ * We need a number of different variants of the std_device_ macro simply
+ * because we can't pass the color_info or offsets/margins
+ * as macro arguments, which in turn is because of the early macro
+ * expansion issue noted in stdpre.h. The basic variants are:
+ * ...body_with_macros_, which uses 0-argument macros to supply
+ * open_init, color_info, and offsets/margins;
+ * ...full_body, which takes 12 values (6 for dci_values,
+ * 6 for offsets/margins);
+ * ...color_full_body, which takes 9 values (3 for dci_color,
+ * 6 for margins/offset).
+ * ...std_color_full_body, which takes 7 values (1 for dci_std_color,
+ * 6 for margins/offset).
+ *
+ */
+#define std_device_body_with_macros_(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, open_init, dci_macro, margins_macro)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init),\
+ dci_macro(),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ margins_macro(),\
+ std_device_part3_()
+
+#define std_device_std_body(dtype, pprocs, dname, w, h, xdpi, ydpi)\
+ std_device_body_with_macros_(dtype, pprocs, dname, 0,\
+ w, h, xdpi, ydpi,\
+ open_init_closed, dci_black_and_white_, no_margins_)
+
+#define std_device_std_body_open(dtype, pprocs, dname, w, h, xdpi, ydpi)\
+ std_device_body_with_macros_(dtype, pprocs, dname, 0,\
+ w, h, xdpi, ydpi,\
+ open_init_open, dci_black_and_white_, no_margins_)
+
+#define std_device_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_values(ncomp, depth, mg, mc, dg, dc),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+#define std_device_dci_type_body(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\
+ dci_values(ncomp, depth, mg, mc, dg, dc),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(0, 0, 0, 0, 0, 0),\
+ std_device_part3_()
+
+#define std_device_dci_body(dtype, pprocs, dname, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)\
+ std_device_dci_type_body(dtype, pprocs, dname, 0,\
+ w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)
+
+#define std_device_color_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, max_value, dither, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_color(depth, max_value, dither),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+#define std_device_color_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, max_value, dither)\
+ std_device_color_full_body(dtype, pprocs, dname,\
+ w, h, xdpi, ydpi,\
+ depth, max_value, dither,\
+ 0, 0, 0, 0, 0, 0)
+
+#define std_device_color_stype_body(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, depth, max_value, dither)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\
+ dci_color(depth, max_value, dither),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(0, 0, 0, 0, 0, 0),\
+ std_device_part3_()
+
+#define std_device_std_color_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_std_color(depth),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+/* ---------------- Device procedures ---------------- */
+
+/* Define an opaque type for parameter lists. */
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+#endif
+
+/*
+ * Definition of device procedures.
+ * Note that the gx_device * argument is not declared const,
+ * because many drivers maintain dynamic state in the device structure.
+ * Note also that the structure is defined as a template, so that
+ * we can instantiate it with device subclasses.
+ * Because C doesn't have real templates, we must do this with macros.
+ */
+
+/* Define macros for declaring device procedures. */
+
+#define dev_t_proc_open_device(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_open_device(proc)\
+ dev_t_proc_open_device(proc, gx_device)
+
+#define dev_t_proc_get_initial_matrix(proc, dev_t)\
+ void proc(P2(dev_t *dev, gs_matrix *pmat))
+#define dev_proc_get_initial_matrix(proc)\
+ dev_t_proc_get_initial_matrix(proc, gx_device)
+
+#define dev_t_proc_sync_output(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_sync_output(proc)\
+ dev_t_proc_sync_output(proc, gx_device)
+
+#define dev_t_proc_output_page(proc, dev_t)\
+ int proc(P3(dev_t *dev, int num_copies, int flush))
+#define dev_proc_output_page(proc)\
+ dev_t_proc_output_page(proc, gx_device)
+
+#define dev_t_proc_close_device(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_close_device(proc)\
+ dev_t_proc_close_device(proc, gx_device)
+
+#define dev_t_proc_map_rgb_color(proc, dev_t)\
+ gx_color_index proc(P4(dev_t *dev,\
+ gx_color_value red, gx_color_value green, gx_color_value blue))
+#define dev_proc_map_rgb_color(proc)\
+ dev_t_proc_map_rgb_color(proc, gx_device)
+
+#define dev_t_proc_map_color_rgb(proc, dev_t)\
+ int proc(P3(dev_t *dev,\
+ gx_color_index color, gx_color_value rgb[3]))
+#define dev_proc_map_color_rgb(proc)\
+ dev_t_proc_map_color_rgb(proc, gx_device)
+
+#define dev_t_proc_fill_rectangle(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ int x, int y, int width, int height, gx_color_index color))
+#define dev_proc_fill_rectangle(proc)\
+ dev_t_proc_fill_rectangle(proc, gx_device)
+
+#define dev_t_proc_tile_rectangle(proc, dev_t)\
+ int proc(P10(dev_t *dev,\
+ const gx_tile_bitmap *tile, int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1,\
+ int phase_x, int phase_y))
+#define dev_proc_tile_rectangle(proc)\
+ dev_t_proc_tile_rectangle(proc, gx_device)
+
+#define dev_t_proc_copy_mono(proc, dev_t)\
+ int proc(P11(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1))
+#define dev_proc_copy_mono(proc)\
+ dev_t_proc_copy_mono(proc, gx_device)
+
+#define dev_t_proc_copy_color(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height))
+#define dev_proc_copy_color(proc)\
+ dev_t_proc_copy_color(proc, gx_device)
+
+ /* OBSOLETED in release 3.66 */
+
+#define dev_t_proc_draw_line(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ int x0, int y0, int x1, int y1, gx_color_index color))
+#define dev_proc_draw_line(proc)\
+ dev_t_proc_draw_line(proc, gx_device)
+
+ /* Added in release 2.4 */
+
+#define dev_t_proc_get_bits(proc, dev_t)\
+ int proc(P4(dev_t *dev,\
+ int y, byte *data, byte **actual_data))
+#define dev_proc_get_bits(proc)\
+ dev_t_proc_get_bits(proc, gx_device)
+
+ /* Added in release 2.4, changed in 2.8, */
+ /* renamed in 2.9.6 */
+
+#define dev_t_proc_get_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_get_params(proc)\
+ dev_t_proc_get_params(proc, gx_device)
+
+#define dev_t_proc_put_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_put_params(proc)\
+ dev_t_proc_put_params(proc, gx_device)
+
+ /* Added in release 2.6 */
+
+#define dev_t_proc_map_cmyk_color(proc, dev_t)\
+ gx_color_index proc(P5(dev_t *dev,\
+ gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,\
+ gx_color_value black))
+#define dev_proc_map_cmyk_color(proc)\
+ dev_t_proc_map_cmyk_color(proc, gx_device)
+
+#define dev_t_proc_get_xfont_procs(proc, dev_t)\
+ gx_xfont_procs *proc(P1(dev_t *dev))
+#define dev_proc_get_xfont_procs(proc)\
+ dev_t_proc_get_xfont_procs(proc, gx_device)
+
+ /* Added in release 2.6.1 */
+
+#define dev_t_proc_get_xfont_device(proc, dev_t)\
+ gx_device *proc(P1(dev_t *dev))
+#define dev_proc_get_xfont_device(proc)\
+ dev_t_proc_get_xfont_device(proc, gx_device)
+
+ /* Added in release 2.7.1 */
+
+#define dev_t_proc_map_rgb_alpha_color(proc, dev_t)\
+ gx_color_index proc(P5(dev_t *dev,\
+ gx_color_value red, gx_color_value green, gx_color_value blue,\
+ gx_color_value alpha))
+#define dev_proc_map_rgb_alpha_color(proc)\
+ dev_t_proc_map_rgb_alpha_color(proc, gx_device)
+
+ /* Added in release 2.8.1 */
+
+#define dev_t_proc_get_page_device(proc, dev_t)\
+ gx_device *proc(P1(dev_t *dev))
+#define dev_proc_get_page_device(proc)\
+ dev_t_proc_get_page_device(proc, gx_device)
+
+ /* Added in release 3.20 */
+
+#define dev_t_proc_get_alpha_bits(proc, dev_t)\
+ int proc(P2(dev_t *dev, graphics_object_type type))
+#define dev_proc_get_alpha_bits(proc)\
+ dev_t_proc_get_alpha_bits(proc, gx_device)
+
+#define dev_t_proc_copy_alpha(proc, dev_t)\
+ int proc(P11(dev_t *dev, const byte *data, int data_x,\
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,\
+ gx_color_index color, int depth))
+#define dev_proc_copy_alpha(proc)\
+ dev_t_proc_copy_alpha(proc, gx_device)
+
+ /* Added in release 3.38 */
+
+#define dev_t_proc_get_band(proc, dev_t)\
+ int proc(P3(dev_t *dev, int y, int *band_start))
+#define dev_proc_get_band(proc)\
+ dev_t_proc_get_band(proc, gx_device)
+
+ /* Added in release 3.44 */
+
+#define dev_t_proc_copy_rop(proc, dev_t)\
+ int proc(P15(dev_t *dev,\
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,\
+ const gx_color_index *scolors,\
+ const gx_tile_bitmap *texture, const gx_color_index *tcolors,\
+ int x, int y, int width, int height,\
+ int phase_x, int phase_y, gs_logical_operation_t lop))
+#define dev_proc_copy_rop(proc)\
+ dev_t_proc_copy_rop(proc, gx_device)
+
+ /* Added in release 3.60, changed in release 3.68. */
+
+#define dev_t_proc_fill_path(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ const gs_imager_state *pis, gx_path *ppath,\
+ const gx_fill_params *params,\
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath))
+#define dev_proc_fill_path(proc)\
+ dev_t_proc_fill_path(proc, gx_device)
+
+#define dev_t_proc_stroke_path(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ const gs_imager_state *pis, gx_path *ppath,\
+ const gx_stroke_params *params,\
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath))
+#define dev_proc_stroke_path(proc)\
+ dev_t_proc_stroke_path(proc, gx_device)
+
+ /* Added in release 3.60 */
+
+#define dev_t_proc_fill_mask(proc, dev_t)\
+ int proc(P13(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height,\
+ const gx_drawing_color *pdcolor, int depth,\
+ gs_logical_operation_t lop, const gx_clip_path *pcpath))
+#define dev_proc_fill_mask(proc)\
+ dev_t_proc_fill_mask(proc, gx_device)
+
+ /* Added in release 3.66, changed in 3.69 */
+
+#define dev_t_proc_fill_trapezoid(proc, dev_t)\
+ int proc(P8(dev_t *dev,\
+ const gs_fixed_edge *left, const gs_fixed_edge *right,\
+ fixed ybot, fixed ytop, bool swap_axes,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_fill_trapezoid(proc)\
+ dev_t_proc_fill_trapezoid(proc, gx_device)
+
+#define dev_t_proc_fill_parallelogram(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_fill_parallelogram(proc)\
+ dev_t_proc_fill_parallelogram(proc, gx_device)
+
+#define dev_t_proc_fill_triangle(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_fill_triangle(proc)\
+ dev_t_proc_fill_triangle(proc, gx_device)
+
+#define dev_t_proc_draw_thin_line(proc, dev_t)\
+ int proc(P7(dev_t *dev,\
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_draw_thin_line(proc)\
+ dev_t_proc_draw_thin_line(proc, gx_device)
+
+ /* Added in release 3.66 (as stubs); */
+ /* changed in 3.68; */
+ /* begin_image and image_data changed in 4.30 */
+
+#define dev_t_proc_begin_image(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ const gs_imager_state *pis, const gs_image_t *pim,\
+ gs_image_format_t format, const gs_int_rect *prect,\
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,\
+ gs_memory_t *memory, void **pinfo))
+#define dev_proc_begin_image(proc)\
+ dev_t_proc_begin_image(proc, gx_device)
+
+#define dev_t_proc_image_data(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ void *info, const byte **planes, int data_x, uint raster, int height))
+#define dev_proc_image_data(proc)\
+ dev_t_proc_image_data(proc, gx_device)
+
+#define dev_t_proc_end_image(proc, dev_t)\
+ int proc(P3(dev_t *dev,\
+ void *info, bool draw_last))
+#define dev_proc_end_image(proc)\
+ dev_t_proc_end_image(proc, gx_device)
+
+ /* Added in release 3.68 */
+
+#define dev_t_proc_strip_tile_rectangle(proc, dev_t)\
+ int proc(P10(dev_t *dev,\
+ const gx_strip_bitmap *tiles, int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1,\
+ int phase_x, int phase_y))
+#define dev_proc_strip_tile_rectangle(proc)\
+ dev_t_proc_strip_tile_rectangle(proc, gx_device)
+
+#define dev_t_proc_strip_copy_rop(proc, dev_t)\
+ int proc(P15(dev_t *dev,\
+ const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,\
+ const gx_color_index *scolors,\
+ const gx_strip_bitmap *textures, const gx_color_index *tcolors,\
+ int x, int y, int width, int height,\
+ int phase_x, int phase_y, gs_logical_operation_t lop))
+#define dev_proc_strip_copy_rop(proc)\
+ dev_t_proc_strip_copy_rop(proc, gx_device)
+
+ /* Added in release 4.20 */
+
+#define dev_t_proc_get_clipping_box(proc, dev_t)\
+ void proc(P2(dev_t *dev, gs_fixed_rect *pbox))
+#define dev_proc_get_clipping_box(proc)\
+ dev_t_proc_get_clipping_box(proc, gx_device)
+
+ /* Added in release 5.2x */
+#define dev_t_proc_get_hardware_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_get_hardware_params(proc)\
+ dev_t_proc_get_hardware_params(proc, gx_device)
+
+/* Define the device procedure vector template proper. */
+
+#define gx_device_proc_struct(dev_t)\
+{ dev_t_proc_open_device((*open_device), dev_t);\
+ dev_t_proc_get_initial_matrix((*get_initial_matrix), dev_t);\
+ dev_t_proc_sync_output((*sync_output), dev_t);\
+ dev_t_proc_output_page((*output_page), dev_t);\
+ dev_t_proc_close_device((*close_device), dev_t);\
+ dev_t_proc_map_rgb_color((*map_rgb_color), dev_t);\
+ dev_t_proc_map_color_rgb((*map_color_rgb), dev_t);\
+ dev_t_proc_fill_rectangle((*fill_rectangle), dev_t);\
+ dev_t_proc_tile_rectangle((*tile_rectangle), dev_t);\
+ dev_t_proc_copy_mono((*copy_mono), dev_t);\
+ dev_t_proc_copy_color((*copy_color), dev_t);\
+ dev_t_proc_draw_line((*draw_line), dev_t);\
+ dev_t_proc_get_bits((*get_bits), dev_t);\
+ dev_t_proc_get_params((*get_params), dev_t);\
+ dev_t_proc_put_params((*put_params), dev_t);\
+ dev_t_proc_map_cmyk_color((*map_cmyk_color), dev_t);\
+ dev_t_proc_get_xfont_procs((*get_xfont_procs), dev_t);\
+ dev_t_proc_get_xfont_device((*get_xfont_device), dev_t);\
+ dev_t_proc_map_rgb_alpha_color((*map_rgb_alpha_color), dev_t);\
+ dev_t_proc_get_page_device((*get_page_device), dev_t);\
+ dev_t_proc_get_alpha_bits((*get_alpha_bits), dev_t);\
+ dev_t_proc_copy_alpha((*copy_alpha), dev_t);\
+ dev_t_proc_get_band((*get_band), dev_t);\
+ dev_t_proc_copy_rop((*copy_rop), dev_t);\
+ dev_t_proc_fill_path((*fill_path), dev_t);\
+ dev_t_proc_stroke_path((*stroke_path), dev_t);\
+ dev_t_proc_fill_mask((*fill_mask), dev_t);\
+ dev_t_proc_fill_trapezoid((*fill_trapezoid), dev_t);\
+ dev_t_proc_fill_parallelogram((*fill_parallelogram), dev_t);\
+ dev_t_proc_fill_triangle((*fill_triangle), dev_t);\
+ dev_t_proc_draw_thin_line((*draw_thin_line), dev_t);\
+ dev_t_proc_begin_image((*begin_image), dev_t);\
+ dev_t_proc_image_data((*image_data), dev_t);\
+ dev_t_proc_end_image((*end_image), dev_t);\
+ dev_t_proc_strip_tile_rectangle((*strip_tile_rectangle), dev_t);\
+ dev_t_proc_strip_copy_rop((*strip_copy_rop), dev_t);\
+ dev_t_proc_get_clipping_box((*get_clipping_box), dev_t);\
+ dev_t_proc_get_hardware_params((*get_hardware_params), dev_t);\
+}
+
+/* A generic device procedure record. */
+struct gx_device_procs_s gx_device_proc_struct(gx_device);
+
+/*
+ * Define a procedure for setting up a memory device for buffering output
+ * for a given device. This is only used by band devices, but we define it
+ * here for convenience. The default implementation just calls
+ * gs_make_mem_device. Possibly this should be a generic device
+ * procedure....
+ */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+#endif
+#define dev_proc_make_buffer_device(proc)\
+ int proc(P4(gx_device_memory *, gx_device *, gs_memory_t *, bool))
+dev_proc_make_buffer_device(gx_default_make_buffer_device);
+
+/*
+ * Define unaligned analogues of the copy_xxx procedures.
+ * These are slower than the standard procedures, which require
+ * aligned bitmaps, and also are not portable to non-byte-addressed machines.
+ *
+ * We allow both unaligned data and unaligned scan line widths;
+ * however, we do require that both of these be aligned modulo the largest
+ * power of 2 bytes that divides the data depth, i.e.:
+ * depth alignment
+ * <= 8 1
+ * 16 2
+ * 24 1
+ * 32 4
+ */
+dev_proc_copy_mono(gx_copy_mono_unaligned);
+dev_proc_copy_color(gx_copy_color_unaligned);
+dev_proc_copy_alpha(gx_copy_alpha_unaligned);
+
+/* A generic device */
+struct gx_device_s {
+ gx_device_common;
+};
+extern_st(st_device);
+struct_proc_finalize(gx_device_finalize); /* public for subclasses */
+/* We use vacuous enum/reloc procedures, rather than 0, so that */
+/* gx_device can have subclasses. */
+#define public_st_device() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device, gx_device, "gx_device",\
+ 0, gs_no_struct_enum_ptrs, gs_no_struct_reloc_ptrs, gx_device_finalize)
+#define st_device_max_ptrs 0
+
+/* Enumerate or relocate a pointer to a device. */
+/* These take the containing space into account properly. */
+gx_device *gx_device_enum_ptr(P1(gx_device *));
+gx_device *gx_device_reloc_ptr(P2(gx_device *, gc_state_t *));
+
+/* Define typedefs for some of the device procedures, because */
+/* ansi2knr can't handle dev_proc_xxx((*xxx)) in a formal argument list. */
+typedef dev_proc_map_rgb_color((*dev_proc_map_rgb_color_t));
+typedef dev_proc_map_color_rgb((*dev_proc_map_color_rgb_t));
+
+/* A device that forwards non-display operations to another device */
+/* called the "target". This is used for clipping, banding, image, */
+/* and null devices. */
+#define gx_device_forward_common\
+ gx_device_common;\
+ gx_device *target
+/* A generic forwarding device. */
+typedef struct gx_device_forward_s {
+ gx_device_forward_common;
+} gx_device_forward;
+extern_st(st_device_forward);
+#define public_st_device_forward() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device_forward, gx_device_forward,\
+ "gx_device_forward", 0, device_forward_enum_ptrs,\
+ device_forward_reloc_ptrs, gx_device_finalize)
+#define st_device_forward_max_ptrs (st_device_max_ptrs + 1)
+
+/* A null device. This is used to temporarily disable output. */
+#ifndef gx_device_null_DEFINED
+# define gx_device_null_DEFINED
+typedef struct gx_device_null_s gx_device_null;
+#endif
+struct gx_device_null_s {
+ gx_device_forward_common;
+};
+extern gx_device_null far_data gs_null_device; /* (should be const) */
+extern_st(st_device_null);
+#define public_st_device_null() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device_null, gx_device_null,\
+ "gx_device_null", 0, device_forward_enum_ptrs,\
+ device_forward_reloc_ptrs, gx_device_finalize)
+#define st_device_null_max_ptrs st_device_forward_max_ptrs
+/* Make a null device. */
+/* The gs_memory_t argument is 0 if the device is temporary and local, */
+/* or the allocator that was used to allocate it if it is a real object. */
+void gs_make_null_device(P2(gx_device_null *, gs_memory_t *));
+
+/* Calculate the raster (number of bytes in a scan line), */
+/* with byte or word padding. */
+uint gx_device_raster(P2(const gx_device *dev, bool pad_to_word));
+
+/* Adjust the resolution for devices that only have a fixed set of */
+/* geometries, so that the apparent size in inches remains constant. */
+/* If fit=1, the resolution is adjusted so that the entire image fits; */
+/* if fit=0, one dimension fits, but the other one is clipped. */
+int gx_device_adjust_resolution(P4(gx_device *dev, int actual_width, int actual_height, int fit));
+
+/* Set the HWMargins to values defined in inches. */
+/* If move_origin is true, also reset the Margins. */
+void gx_device_set_margins(P3(gx_device *dev, const float *margins /*[4]*/,
+ bool move_origin));
+
+/* Set the width and height (in pixels), updating MediaSize. */
+void gx_device_set_width_height(P3(gx_device *dev, int width, int height));
+/* Set the resolution (in pixels per inch), updating width and height. */
+void gx_device_set_resolution(P3(gx_device *dev, floatp x_dpi, floatp y_dpi));
+/* Set the MediaSize (in 1/72" units), updating width and height. */
+void gx_device_set_media_size(P3(gx_device *dev, floatp media_width, floatp media_height));
+/****** BACKWARD COMPATIBILITY ******/
+#define gx_device_set_page_size(dev, w, h)\
+ gx_device_set_media_size(dev, w, h)
+
+/*
+ * Macros to help the drawing procedures clip coordinates to
+ * fit into the drawing region. Note that these may modify
+ * x, y, w, h, data, data_x, and id.
+ */
+
+/* Macros for fill_rectangle and [strip_]tile_rectangle. */
+#define fit_fill_xy(dev, x, y, w, h)\
+ if ( (x | y) < 0 )\
+ { if ( x < 0 ) w += x, x = 0;\
+ if ( y < 0 ) h += y, y = 0;\
+ }
+#define fit_fill_xyw(dev, x, y, w, h)\
+ fit_fill_xy(dev, x, y, w, h);\
+ if ( x > dev->width - w ) w = dev->width - x
+#define fit_fill_y(dev, y, h)\
+ if ( y < 0 ) h += y, y = 0
+#define fit_fill_h(dev, y, h)\
+ if ( y > dev->height - h ) h = dev->height - y
+#define fit_fill_yh(dev, y, h)\
+ fit_fill_y(dev, y, h);\
+ fit_fill_h(dev, y, h)
+#define fit_fill_xywh(dev, x, y, w, h)\
+ fit_fill_xyw(dev, x, y, w, h);\
+ fit_fill_h(dev, y, h)
+#define if_fit_fill_empty(dev, x, y, w, h)\
+ fit_fill_xywh(dev, x, y, w, h);\
+ if ( w <= 0 || h <= 0 )
+#define fit_fill(dev, x, y, w, h)\
+ if_fit_fill_empty(dev, x, y, w, h) return 0
+
+/* Macro for copy_mono and copy_color. */
+#define fit_copy_xw(dev, data, data_x, raster, id, x, y, w, h)\
+ if ( (x | y) < 0 )\
+ { if ( x < 0 ) w += x, data_x -= x, x = 0;\
+ if ( y < 0 ) h += y, data -= y * raster, id = gx_no_bitmap_id, y = 0;\
+ }\
+ if ( x > dev->width - w ) w = dev->width - x
+#define fit_copy_xwh(dev, data, data_x, raster, id, x, y, w, h)\
+ fit_copy_xw(dev, data, data_x, raster, id, x, y, w, h);\
+ if ( w <= 0 || h <= 0 ) return 0
+#define fit_copy(dev, data, data_x, raster, id, x, y, w, h)\
+ fit_copy_xw(dev, data, data_x, raster, id, x, y, w, h);\
+ if ( y > dev->height - h ) h = dev->height - y;\
+ if ( w <= 0 || h <= 0 ) return 0
+
+/* Default implementations of optional procedures. */
+/* Note that the default map_xxx_color routines assume white_on_black. */
+dev_proc_open_device(gx_default_open_device);
+dev_proc_get_initial_matrix(gx_default_get_initial_matrix);
+dev_proc_get_initial_matrix(gx_upright_get_initial_matrix);
+dev_proc_sync_output(gx_default_sync_output);
+dev_proc_output_page(gx_default_output_page);
+dev_proc_close_device(gx_default_close_device);
+dev_proc_map_rgb_color(gx_default_w_b_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_w_b_map_color_rgb);
+#define gx_default_map_rgb_color gx_default_w_b_map_rgb_color
+#define gx_default_map_color_rgb gx_default_w_b_map_color_rgb
+dev_proc_tile_rectangle(gx_default_tile_rectangle);
+dev_proc_copy_mono(gx_default_copy_mono);
+dev_proc_copy_color(gx_default_copy_color);
+dev_proc_draw_line(gx_default_draw_line);
+dev_proc_get_bits(gx_default_get_bits);
+dev_proc_get_params(gx_default_get_params);
+dev_proc_put_params(gx_default_put_params);
+dev_proc_map_cmyk_color(gx_default_map_cmyk_color);
+dev_proc_get_xfont_procs(gx_default_get_xfont_procs);
+dev_proc_get_xfont_device(gx_default_get_xfont_device);
+dev_proc_map_rgb_alpha_color(gx_default_map_rgb_alpha_color);
+dev_proc_get_page_device(gx_default_get_page_device); /* returns NULL */
+dev_proc_get_page_device(gx_page_device_get_page_device); /* returns dev */
+dev_proc_get_alpha_bits(gx_default_get_alpha_bits);
+dev_proc_copy_alpha(gx_no_copy_alpha); /* gives error */
+dev_proc_copy_alpha(gx_default_copy_alpha);
+dev_proc_get_band(gx_default_get_band);
+dev_proc_copy_rop(gx_no_copy_rop); /* gives error */
+extern dev_proc_copy_rop((*gx_default_copy_rop_proc));
+dev_proc_copy_rop(gx_default_copy_rop); /* calls ...proc */
+dev_proc_fill_path(gx_default_fill_path);
+dev_proc_stroke_path(gx_default_stroke_path);
+dev_proc_fill_mask(gx_default_fill_mask);
+dev_proc_fill_trapezoid(gx_default_fill_trapezoid);
+dev_proc_fill_parallelogram(gx_default_fill_parallelogram);
+dev_proc_fill_triangle(gx_default_fill_triangle);
+dev_proc_draw_thin_line(gx_default_draw_thin_line);
+dev_proc_begin_image(gx_default_begin_image);
+dev_proc_image_data(gx_default_image_data);
+dev_proc_end_image(gx_default_end_image);
+dev_proc_strip_tile_rectangle(gx_default_strip_tile_rectangle);
+dev_proc_strip_copy_rop(gx_no_strip_copy_rop); /* gives error */
+extern dev_proc_strip_copy_rop((*gx_default_strip_copy_rop_proc));
+dev_proc_strip_copy_rop(gx_default_strip_copy_rop); /* calls ...proc */
+dev_proc_get_clipping_box(gx_default_get_clipping_box);
+dev_proc_get_clipping_box(gx_get_largest_clipping_box);
+dev_proc_get_hardware_params(gx_default_get_hardware_params);
+
+/* Color mapping routines for black-on-white, gray scale, true RGB, */
+/* and true CMYK color. */
+dev_proc_map_rgb_color(gx_default_b_w_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_b_w_map_color_rgb);
+dev_proc_map_rgb_color(gx_default_gray_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_gray_map_color_rgb);
+dev_proc_map_rgb_color(gx_default_rgb_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_rgb_map_color_rgb);
+dev_proc_map_cmyk_color(gx_default_cmyk_map_cmyk_color);
+
+/* Default implementations for forwarding devices */
+dev_proc_get_initial_matrix(gx_forward_get_initial_matrix);
+dev_proc_sync_output(gx_forward_sync_output);
+dev_proc_output_page(gx_forward_output_page);
+dev_proc_map_rgb_color(gx_forward_map_rgb_color);
+dev_proc_map_color_rgb(gx_forward_map_color_rgb);
+dev_proc_tile_rectangle(gx_forward_tile_rectangle);
+dev_proc_get_bits(gx_forward_get_bits);
+dev_proc_get_params(gx_forward_get_params);
+dev_proc_put_params(gx_forward_put_params);
+dev_proc_map_cmyk_color(gx_forward_map_cmyk_color);
+dev_proc_get_xfont_procs(gx_forward_get_xfont_procs);
+dev_proc_get_xfont_device(gx_forward_get_xfont_device);
+dev_proc_map_rgb_alpha_color(gx_forward_map_rgb_alpha_color);
+dev_proc_get_page_device(gx_forward_get_page_device);
+dev_proc_get_alpha_bits(gx_forward_get_alpha_bits);
+dev_proc_get_band(gx_forward_get_band);
+extern dev_proc_copy_rop((*gx_forward_copy_rop_proc));
+dev_proc_fill_path(gx_forward_fill_path);
+dev_proc_stroke_path(gx_forward_stroke_path);
+dev_proc_fill_mask(gx_forward_fill_mask);
+dev_proc_fill_trapezoid(gx_forward_fill_trapezoid);
+dev_proc_fill_parallelogram(gx_forward_fill_parallelogram);
+dev_proc_fill_triangle(gx_forward_fill_triangle);
+dev_proc_draw_thin_line(gx_forward_draw_thin_line);
+dev_proc_begin_image(gx_forward_begin_image);
+dev_proc_image_data(gx_forward_image_data);
+dev_proc_end_image(gx_forward_end_image);
+dev_proc_strip_tile_rectangle(gx_forward_strip_tile_rectangle);
+extern dev_proc_strip_copy_rop((*gx_forward_strip_copy_rop_proc));
+dev_proc_get_clipping_box(gx_forward_get_clipping_box);
+dev_proc_get_hardware_params(gx_forward_get_hardware_params);
+
+/* Convert the device procedures to the proper form (see above). */
+void gx_device_set_procs(P1(gx_device *));
+
+/* Fill in defaulted procedures in a device procedure record. */
+void gx_device_fill_in_procs(P1(gx_device *));
+void gx_device_forward_fill_in_procs(P1(gx_device_forward *));
+
+/* Forward the color mapping procedures from a device to its target. */
+void gx_device_forward_color_procs(P1(gx_device_forward *));
+
+/* Temporarily install a null device, or a special device such as */
+/* a clipping device. */
+void gx_device_no_output(P1(gs_state *));
+void gx_set_device_only(P2(gs_state *, gx_device *));
+
+/* Open the output file for a device. */
+int gx_device_open_output_file(P5(const gx_device *dev, const char *fname,
+ bool binary, bool positionable,
+ FILE **pfile));
+
+/* Close a device. */
+int gs_closedevice(P1(gx_device *));
+
+/* ------ Device types ------ */
+
+#define dev_type_proc_initialize(proc)\
+ int proc(P1(gx_device *))
+
+typedef struct gx_device_type_s {
+ gs_memory_type_ptr_t stype;
+ dev_type_proc_initialize((*initialize));
+} gx_device_type;
+
+#define device_type(dtname, stype, initproc)\
+private dev_type_proc_initialize(initproc);\
+const gx_device_type dtname = { &stype, initproc }
+
+dev_type_proc_initialize(gdev_initialize);
+
+#endif /* gxdevice_INCLUDED */
diff --git a/gs/src/gxdevmem.h b/gs/src/gxdevmem.h
new file mode 100644
index 000000000..c8dfb5f03
--- /dev/null
+++ b/gs/src/gxdevmem.h
@@ -0,0 +1,150 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdevmem.h */
+/* "Memory" device structure for Ghostscript library */
+/* Requires gxdevice.h */
+
+/*
+ * A 'memory' device is essentially a stored bitmap.
+ * There are several different kinds: 1-bit black and white,
+ * 2-, 4-, and 8-bit mapped color, 16- and 24-bit RGB color,
+ * and 32-bit CMYK color. (16-bit uses 5/6/5 bits per color.)
+ * All use the same structure, since it's so awkward to get the effect of
+ * subclasses in C.
+ *
+ * Memory devices come in two flavors: standard, which always stores bytes
+ * big-endian, and word-oriented, which stores bytes in the machine order
+ * within 32-bit "words". The source data for copy_mono and
+ * copy_color must be in big-endian order, and since memory devices
+ * also are guaranteed to allocate the bitmap consecutively,
+ * the bitmap of a standard memory device can serve directly as input
+ * to copy_mono or copy_color operations. This is not true of word-oriented
+ * memory devices, which are provided only in response to a request by
+ * a customer with their own image processing library that uses this format.
+ */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+#endif
+
+struct gx_device_memory_s {
+ gx_device_forward_common; /* (see gxdevice.h) */
+ gs_matrix initial_matrix; /* the initial transformation */
+ uint raster; /* bytes per scan line, */
+ /* filled in by 'open' */
+ bool foreign_bits; /* if true, bits are not in */
+ /* GC-able space */
+ byte *base;
+ byte **line_ptrs; /* scan line pointers */
+#define scan_line_base(dev,y) ((dev)->line_ptrs[y])
+ /* If the bitmap_memory pointer is non-zero, it is used for */
+ /* allocating the bitmap when the device is opened, */
+ /* and freeing it when the device is closed. */
+ gs_memory_t *bitmap_memory;
+ /* Following is used for mapped color, */
+ /* including 1-bit devices (to specify polarity). */
+ gs_const_string palette; /* RGB triples */
+ /* Following is only used for 24-bit color. */
+ struct _c24 {
+ gx_color_index rgb; /* cache key */
+ bits32 rgbr, gbrg, brgb; /* cache value */
+ } color24;
+ /* Following are only used for alpha buffers. */
+ /* The client initializes those marked with $; */
+ /* they don't change after initialization. */
+ gs_log2_scale_point log2_scale; /* $ oversampling scale factors */
+ int log2_alpha_bits; /* $ log2 of # of alpha bits being produced */
+ int mapped_x; /* $ X value mapped to buffer X=0 */
+ int mapped_y; /* lowest Y value mapped to buffer */
+ int mapped_height; /* # of Y values mapped to buffer */
+ int mapped_start; /* local Y value corresponding to mapped_y */
+ gx_color_index save_color; /* last (only) color displayed */
+};
+extern_st(st_device_memory);
+#define public_st_device_memory() /* in gdevmem.c */\
+ gs_public_st_composite(st_device_memory, gx_device_memory,\
+ "gx_device_memory", device_memory_enum_ptrs, device_memory_reloc_ptrs)
+#define st_device_memory_max_ptrs (st_device_forward_max_ptrs + 2)
+#define mem_device_init_private\
+ { identity_matrix_body }, /* initial matrix (filled in) */\
+ 0, /* raster (filled in) */\
+ true, /* foreign_bits (default) */\
+ (byte *)0, /* base (filled in) */\
+ (byte **)0, /* line_ptrs (filled in by mem_open) */\
+ 0, /* bitmap_memory */\
+ { (byte *)0, 0 }, /* palette (filled in for color) */\
+ { gx_no_color_index }, /* color24 */\
+ { 0, 0 }, 0, /* scale, log2_alpha_bits */\
+ 0, 0, 0, 0, /* mapped_* */\
+ gx_no_color_index /* save_color */
+
+/*
+ * Memory devices may have special setup requirements.
+ * In particular, it may not be obvious how much space to allocate
+ * for the bitmap. Here is the routine that computes this
+ * from the width and height.
+ */
+ulong gdev_mem_data_size(P3(const gx_device_memory *, int, int));
+#define gdev_mem_bitmap_size(mdev)\
+ gdev_mem_data_size(mdev, (mdev)->width, (mdev)->height)
+/*
+ * Do the inverse computation: given the device width and a buffer size,
+ * compute the maximum height.
+ */
+int gdev_mem_max_height(P3(const gx_device_memory *, int, ulong));
+/*
+ * Compute the raster (data bytes per line) similarly.
+ */
+#define gdev_mem_raster(mdev)\
+ gx_device_raster((const gx_device *)(mdev), true)
+
+/* Determine the appropriate memory device for a given */
+/* number of bits per pixel (0 if none suitable). */
+const gx_device_memory *gdev_mem_device_for_bits(P1(int));
+
+/* Determine the word-oriented memory device for a given depth. */
+const gx_device_memory *gdev_mem_word_device_for_bits(P1(int));
+
+/* Make a memory device. */
+/* mem is 0 if the device is temporary and local, */
+/* or the allocator that was used to allocate it if it is a real object. */
+/* page_device is 1 if the device should be a page device, */
+/* 0 if it should propagate this property from its target, or */
+/* -1 if it should not be a page device. */
+void gs_make_mem_mono_device(P3(gx_device_memory *mdev, gs_memory_t *mem,
+ gx_device *target));
+void gs_make_mem_device(P5(gx_device_memory *mdev,
+ const gx_device_memory *mdproto,
+ gs_memory_t *mem, int page_device,
+ gx_device *target));
+void gs_make_mem_abuf_device(P6(gx_device_memory *adev, gs_memory_t *mem,
+ gx_device *target,
+ const gs_log2_scale_point *pscale,
+ int alpha_bits, int mapped_x));
+void gs_make_mem_alpha_device(P4(gx_device_memory *adev, gs_memory_t *mem,
+ gx_device *target, int alpha_bits));
+
+/* Define whether a monobit memory device is inverted (black=1). */
+void gdev_mem_mono_set_inverted(P2(gx_device_memory *mdev, bool black_is_1));
+
+/* Test whether a device is a memory device. */
+bool gs_device_is_memory(P1(const gx_device *));
+
+/* Test whether a device is an alpha-buffering device. */
+bool gs_device_is_abuf(P1(const gx_device *));
diff --git a/gs/src/gxdevrop.h b/gs/src/gxdevrop.h
new file mode 100644
index 000000000..ee1d4a71d
--- /dev/null
+++ b/gs/src/gxdevrop.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdevrop.h */
+/* Extension of gxdevice.h for RasterOp */
+
+/* Define an unaligned implementation of copy_rop. */
+dev_proc_copy_rop(gx_copy_rop_unaligned);
+dev_proc_strip_copy_rop(gx_strip_copy_rop_unaligned);
+
+/* Define the default and forwarding implementations of [strip_]copy_rop. */
+/* (Normally these are never referenced directly.) */
+dev_proc_copy_rop(gx_real_default_copy_rop);
+dev_proc_copy_rop(gx_forward_copy_rop);
+dev_proc_strip_copy_rop(gx_real_default_strip_copy_rop);
+dev_proc_strip_copy_rop(gx_forward_strip_copy_rop);
diff --git a/gs/src/gxdht.h b/gs/src/gxdht.h
new file mode 100644
index 000000000..56b89c274
--- /dev/null
+++ b/gs/src/gxdht.h
@@ -0,0 +1,251 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdht.h */
+/* Definition of device halftones */
+
+#ifndef gxdht_INCLUDED
+# define gxdht_INCLUDED
+
+#include "gsrefct.h"
+#include "gxarith.h" /* for igcd */
+#include "gxhttype.h"
+
+/*
+ * We represent a halftone tile as a rectangular super-cell consisting of
+ * multiple copies of a multi-cell whose corners lie on integral
+ * coordinates, which in turn is a parallelogram (normally square) array of
+ * basic parallelogram (normally square) cells whose corners lie on rational
+ * coordinates.
+ *
+ * Let T be the aspect ratio (ratio of physical pixel height to physical
+ * pixel width), which is abs(xx/yy) for portrait devices and abs(yx/xy) for
+ * landscape devices. We characterize the basic cell by four rational
+ * numbers U(') = M(')/R(') and V(') = N(')/R(') where R(') is positive, at
+ * least one of U and V (and the corresponding one of U' and V') is
+ * non-zero, and U' is approximately U/T and V' is approximately V*T; these
+ * numbers define the vertices of the basic cell at device space coordinates
+ * (0,0), (U,V), (U-V',U'+V), and (-V',U'); then the multi-cell is defined
+ * similarly by M(') and N('). From these definitions, the basic cell has
+ * an area of B = U*U' + V*V' = (M*M' + N*N') / R*R' pixels, and the
+ * multi-cell has an area of C = B * R*R' = M*M' + N*N' pixels.
+ *
+ * If the coefficients of the default device transformation matrix are xx,
+ * xy, yx, and yy, then U and V are related to the frequency F and the angle
+ * A by:
+ * P = 72 / F;
+ * U = P * (xx * cos(A) + yx * sin(A));
+ * V = P * (xy * cos(A) + yy * sin(A)).
+ *
+ * We can tile the plane with any rectangular super-cell that consists of
+ * repetitions of the multi-cell and whose corners coincide with multi-cell
+ * coordinates (0,0). We observe that for any integers i, j such that i*N -
+ * j*M' = 0, a multi-cell corner lies on the X axis at W = i*M + j*N';
+ * similarly, if i'*M - j'*N' = 0, a corner lies on the Y axis at W' = i'*N
+ * + j'*M'. Then the super-cell occupies Z = W * W' pixels, consisting of Z
+ * / C multi-cells or Z / B basic cells. The trick in all this is to find
+ * values of F and A that aren't too far from the requested ones, and that
+ * yield a manageably small value for Z.
+ *
+ * Note that the super-cell only has to be so large because we want to use
+ * it directly to tile the plane. In fact, we can decompose it into W' / D
+ * horizontal strips of width W and height D, shifted horizontally with
+ * respect to each other by S pixels, where we compute S by finding h and k
+ * such that h*N - k*M' = D and then S = h*M + k*N'. The halftone setup
+ * routines only generate a single strip of samples, and let
+ * gx_ht_construct_spot_order construct the rest. If W' is large, we
+ * actually keep only one strip, and let the strip_tile_rectangle routines
+ * do the shifting at rendering time.
+ */
+typedef struct gx_ht_cell_params_s {
+ /* Defining values. M * M1 != 0 or N * N1 != 0; R > 0, R1 > 0. */
+ /* R and D are short rather than ushort so that we don't get */
+ /* unsigned results from arithmetic. */
+ short M, N, R;
+ short M1, N1, R1;
+ /* Derived values. */
+ ulong C;
+ short D, D1;
+ uint W, W1;
+ int S;
+} gx_ht_cell_params_t;
+/* Compute the derived values from the defining values. */
+void gx_compute_cell_values(P1(gx_ht_cell_params_t *));
+
+/*
+ * The whitening order is represented by a pair of arrays.
+ * The levels array contains an integer (an index into the bits array)
+ * for each distinct halftone level, indicating how many pixels should be
+ * whitened for that level; levels[0] = 0, levels[i] <= levels[i+1], and
+ * levels[num_levels-1] <= num_bits.
+ * The bits array contains an (offset,mask) pair for each pixel in the tile.
+ * bits[i].offset is the (properly aligned) byte index of a pixel
+ * in the tile; bits[i].mask is the mask to be or'ed into this byte and
+ * following ones. This is arranged so it will work properly on
+ * either big- or little-endian machines, and with different mask widths.
+ */
+/* The mask width must be at least as wide as uint, */
+/* and must not be wider than the width implied by align_bitmap_mod. */
+typedef uint ht_mask_t;
+#define ht_mask_bits (sizeof(ht_mask_t) * 8)
+typedef struct gx_ht_bit_s {
+ uint offset;
+ ht_mask_t mask;
+} gx_ht_bit;
+/* During sampling, bits[i].mask is used to hold a normalized sample value. */
+typedef ht_mask_t ht_sample_t;
+/* The following awkward expression avoids integer overflow. */
+#define max_ht_sample (ht_sample_t)(((1 << (ht_mask_bits - 2)) - 1) * 2 + 1)
+
+/*
+ * Define the internal representation of a halftone order.
+ * Note that it may include a cached transfer function.
+ *
+ * Halftone orders exist in two slightly different configurations, strip and
+ * complete. In a complete order, shift = 0 and full_height = height; in a
+ * strip order, shift != 0 and full_height is the height of a fully expanded
+ * halftone made up of enough shifted strip copies to get back to a zero
+ * shift. In other words, full_height is a cached value, but it is an
+ * important one, since it is the modulus used for computing the
+ * tile-relative phase. Requirements:
+ * width > 0, height > 0, multiple > 0
+ * raster >= bitmap_raster(width)
+ * 0 <= shift < width
+ * num_bits = width * height
+ * For complete orders:
+ * full_height = height
+ * For strip orders:
+ * full_height = height * width / gcd(width, shift)
+ * Note that during the sampling of a complete spot halftone, these
+ * invariants may be violated; in particular, it is possible that shift != 0
+ * and height < full_height, even though num_bits and num_levels reflect the
+ * full height. In this case, the invariant is restored (by resetting
+ * shift and height) when sampling is finished. However, we must save the
+ * original height and shift values used for sampling, since sometimes we
+ * run the "finishing" routines more than once. (This is ugly, but it's
+ * too hard to fix.)
+ *
+ * See gxbitmap.h for more details about strip halftones.
+ */
+typedef struct gx_ht_cache_s gx_ht_cache;
+typedef struct gx_ht_order_s {
+ gx_ht_cell_params_t params; /* parameters defining the cells */
+ ushort width;
+ ushort height;
+ ushort raster;
+ ushort shift;
+ ushort orig_height;
+ ushort orig_shift;
+ uint full_height;
+ uint num_levels; /* = levels size */
+ uint num_bits; /* = bits size = width * height */
+ uint *levels;
+ gx_ht_bit *bits;
+ gx_ht_cache *cache; /* cache to use */
+ gx_transfer_map *transfer; /* TransferFunction or 0 */
+} gx_ht_order;
+#define ht_order_is_complete(porder)\
+ ((porder)->shift == 0)
+#define ht_order_full_height(porder)\
+ ((porder)->shift == 0 ? (porder)->height :\
+ (porder)->width / igcd((porder)->width, (porder)->shift) *\
+ (porder)->height)
+
+/* We only export st_ht_order for use in st_screen_enum. */
+extern_st(st_ht_order);
+#define public_st_ht_order() /* in gsht.c */\
+ gs_public_st_ptrs4(st_ht_order, gx_ht_order, "gx_ht_order",\
+ ht_order_enum_ptrs, ht_order_reloc_ptrs, levels, bits, cache, transfer)
+#define st_ht_order_max_ptrs 4
+
+/*
+ * Define a device halftone. This consists of one or more orders.
+ * If components = 0, then order is the only current halftone screen
+ * (set by setscreen, Type 1 sethalftone, Type 3 sethalftone, or
+ * Type 5 sethalftone with only a Default). Otherwise, order is the
+ * gray or black screen (for gray/RGB or CMYK devices respectively),
+ * and components is an array of gx_ht_order_components parallel to
+ * the components of the client halftone (set by setcolorscreen or
+ * Type 5 sethalftone).
+ *
+ * Multi-component halftone orders may be required even in Level 1 systems,
+ * because they are needed for setcolorscreen.
+ *
+ * NOTE: it is assumed that all subsidiary structures of device halftones
+ * (the components array, and the bits, levels, cache, and transfer members
+ * of any gx_ht_orders, both the default order and any component orders) are
+ * allocated with the same allocator as the device halftone itself.
+ */
+typedef struct gx_ht_order_component_s {
+ gx_ht_order corder;
+ gs_ht_separation_name cname;
+} gx_ht_order_component;
+#define private_st_ht_order_component() /* in gsht.c */\
+ gs_private_st_ptrs_add0(st_ht_order_component, gx_ht_order_component,\
+ "gx_ht_order_component", ht_order_component_enum_ptrs,\
+ ht_order_component_reloc_ptrs, st_ht_order, corder)
+#define st_ht_order_component_max_ptrs st_ht_order_max_ptrs
+/* We only export st_ht_order_component_element for use in banding. */
+extern_st(st_ht_order_component_element);
+#define public_st_ht_order_comp_element() /* in gsht.c */\
+ gs_public_st_element(st_ht_order_component_element, gx_ht_order_component,\
+ "gx_ht_order_component[]", ht_order_element_enum_ptrs,\
+ ht_order_element_reloc_ptrs, st_ht_order_component)
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+#endif
+
+/*
+ * color_indices is a cache that gives the indices in components of
+ * the screens for the 1, 3, or 4 primary color(s). These indices are
+ * always in the same order, namely:
+ * -,-,-,W(gray)
+ * R,G,B,-
+ * C,M,Y,K
+ */
+struct gx_device_halftone_s {
+ gx_ht_order order; /* must be first, for subclassing */
+ rc_header rc;
+ gs_id id; /* the id changes whenever the data change */
+#ifdef FUTURE
+ /* We have to keep the halftone type so that we can pass it */
+ /* through the band list for gx_imager_dev_ht_install. */
+ gs_halftone_type type;
+#endif
+ gx_ht_order_component *components;
+ uint num_comp;
+ /* The following are computed from the above. */
+ uint color_indices[4];
+ int lcm_width, lcm_height; /* LCM of primary color tile sizes, */
+ /* max_int if overflowed */
+};
+extern_st(st_device_halftone);
+#define public_st_device_halftone() /* in gsht.c */\
+ gs_public_st_ptrs_add1(st_device_halftone, gx_device_halftone,\
+ "gx_device_halftone", device_halftone_enum_ptrs,\
+ device_halftone_reloc_ptrs, st_ht_order, order, components)
+#define st_device_halftone_max_ptrs (st_ht_order_max_ptrs + 1)
+
+/* Release a gx_device_halftone by freeing its components. */
+/* (Don't free the gx_device_halftone itself.) */
+void gx_device_halftone_release(P2(gx_device_halftone *pdht,
+ gs_memory_t *mem));
+
+#endif /* gxdht_INCLUDED */
diff --git a/gs/src/gxdither.c b/gs/src/gxdither.c
new file mode 100644
index 000000000..a8ab996eb
--- /dev/null
+++ b/gs/src/gxdither.c
@@ -0,0 +1,478 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdither.c */
+#include "gx.h"
+#include "gsstruct.h"
+#include "gsdcolor.h"
+#include "gxdevice.h"
+#include "gxlum.h"
+#include "gxcmap.h"
+#include "gxdither.h"
+#include "gzht.h"
+
+/*
+ * The procedures in this file use halftoning (if necessary)
+ * to implement a given device color that has already gone through
+ * the transfer function. There are two major cases: gray and color.
+ * Gray halftoning always uses a binary screen. Color halftoning
+ * uses either a fast algorithm with a binary screen that produces
+ * relatively poor approximations, or a very slow algorithm with a
+ * general colored screen (or screens) that faithfully implements
+ * the Adobe specifications.
+ */
+
+/* Tables for fast computation of fractional color levels. */
+/* We have to put the table before any uses of it because of a bug */
+/* in the VAX C compiler. */
+/* We have to split up the definition of the table itself because of a bug */
+/* in the IBM AIX 3.2 C compiler. */
+private const gx_color_value
+ q0[] = { 0 };
+private const gx_color_value
+ q1[] = { 0, frac_color_(1,1) };
+private const gx_color_value
+ q2[] = { 0, frac_color_(1,2), frac_color_(2,2) };
+private const gx_color_value
+ q3[] = { 0, frac_color_(1,3), frac_color_(2,3), frac_color_(3,3) };
+private const gx_color_value
+ q4[] = { 0, frac_color_(1,4), frac_color_(2,4), frac_color_(3,4), frac_color_(4,4) };
+private const gx_color_value
+ q5[] = { 0, frac_color_(1,5), frac_color_(2,5), frac_color_(3,5), frac_color_(4,5), frac_color_(5,5) };
+private const gx_color_value
+ q6[] = { 0, frac_color_(1,6), frac_color_(2,6), frac_color_(3,6), frac_color_(4,6), frac_color_(5,6), frac_color_(6,6) };
+private const gx_color_value
+ q7[] = { 0, frac_color_(1,7), frac_color_(2,7), frac_color_(3,7), frac_color_(4,7), frac_color_(5,7), frac_color_(6,7), frac_color_(7,7) };
+/* We export fc_color_quo for the fractional_color macro in gzht.h. */
+const gx_color_value _ds *fc_color_quo[8] =
+ { q0, q1, q2, q3, q4, q5, q6, q7 };
+
+/* Render a gray, possibly by halftoning. */
+int
+gx_render_device_gray(frac gray, gx_color_value alpha, gx_device_color *pdevc,
+ gx_device *dev, const gx_device_halftone *pdht,
+ const gs_int_point *ht_phase)
+{ bool cmyk = dev->color_info.num_components == 4;
+
+/* Make a special check for black and white. */
+ if ( alpha == gx_max_color_value )
+ { gx_color_value lum;
+ switch ( gray )
+ {
+ case frac_0:
+ lum = 0;
+ goto bw;
+ case frac_1:
+ lum = gx_max_color_value;
+bw: color_set_pure(pdevc,
+ (cmyk ?
+ gx_map_cmyk_color(dev, 0, 0, 0,
+ gx_max_color_value - lum) :
+ gx_map_rgb_color(dev, lum, lum, lum)));
+ return 0;
+ default:
+ ;
+ }
+ }
+
+/* get a few handy values */
+ { uint max_value = dev->color_info.dither_grays - 1;
+ unsigned long hsize = (unsigned)pdht->order.num_levels;
+ unsigned long nshades = hsize * max_value + 1;
+ unsigned long lx = (nshades * gray) / (frac_1_long + 1);
+ uint v = lx / hsize;
+ gx_color_value lum = fractional_color(v, max_value);
+ gx_color_index color1;
+ int level = lx % hsize;
+ /* The following should be a conditional expression, */
+ /* but the DECStation 3100 Ultrix 4.3 compiler */
+ /* generates bad code for it. */
+#define set_color_lum(col, lum)\
+ if ( cmyk )\
+ col = gx_map_cmyk_color(dev, 0, 0, 0,\
+ gx_max_color_value - lum);\
+ else if ( alpha == gx_max_color_value )\
+ col = gx_map_rgb_color(dev, lum, lum, lum);\
+ else\
+ col = gx_map_rgb_alpha_color(dev, lum, lum, lum, alpha)
+ set_color_lum(color1, lum);
+ if_debug5('c', "[c]gray=0x%x --> (%d+%d/%lu)/%d\n",
+ (unsigned)gray, v, level, hsize, max_value + 1);
+ if ( level == 0 )
+ { /* Close enough to a pure color, */
+ /* no dithering needed. */
+ color_set_pure(pdevc, color1);
+ return 0;
+ }
+ else
+ { gx_color_index color2;
+ v++;
+ lum = fractional_color(v, max_value);
+ set_color_lum(color2, lum);
+ color_set_binary_halftone(pdevc, pdht,
+ color1, color2, level);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->order.width,
+ pdht->order.full_height);
+ return 1;
+ }
+ }
+}
+
+/*
+ * Color dithering for Ghostscript. The underlying device imaging model
+ * supports dithering between two colors to generate intermediate shades.
+ *
+ * If the device has high quality colors (at least 32 values
+ * per axis), we ask it to map the color directly.
+ *
+ * Otherwise, things are a bit more complicated. If the device
+ * supports N shades of each R, G and B independently, there are a total
+ * of N*N*N colors. These colors form a 3-D grid in a cubical color
+ * space. The following dithering technique works by locating the
+ * color we want in this 3-D color grid and finding the eight colors
+ * that surround it. In the case of dithering into 8 colors with 1
+ * bit for each red, green and blue, these eight colors will always
+ * be the same.
+ *
+ * Now we consider all possible diagonal paths between the eight colors
+ * and chose the path that runs closest to our desired color in 3-D
+ * color space. There are 28 such paths. Then we find the position
+ * on the path that is closest to our color.
+ *
+ * The search is made faster by always reflecting our color into
+ * the bottom octant of the cube and comparing it to 7 paths.
+ * After the best path and the best position on that path are found,
+ * the results are reflected back into the original color space.
+ *
+ * NOTE: This code has been tested for B/W and Color imaging with
+ * 1, 2, 3 and 8 bits per component.
+ *
+ * --- original code by Paul Haeberli @ Silicon Graphics - 1990
+ * --- extensively revised by L. Peter Deutsch, Aladdin Enterprises
+ *
+ * lpd 3/14/94: added support for CMYK.
+ */
+
+/*
+ * The weights are arbitrary, as long as their ratios are correct
+ * and they will fit into the difference between a ulong and a frac
+ * with room to spare. By making WEIGHT1 and WEIGHT4 powers of 2,
+ * we can turn some multiplies into shifts.
+ */
+#define WNUM 128000
+#define WEIGHT1 (ulong)(WNUM/1000) /* 1.0 */
+#define WEIGHT2 (ulong)(WNUM/1414) /* 1/sqrt(2.0) */
+#define WEIGHT3 (ulong)(WNUM/1732) /* 1/sqrt(3.0) */
+#define WEIGHT4 (ulong)(WNUM/2000) /* 1/sqrt(4.0) */
+
+#define DIAG_R (0x1)
+#define DIAG_G (0x2)
+#define DIAG_B (0x4)
+#define DIAG_W (0x8)
+#define DIAG_RG (0x3)
+#define DIAG_GB (0x6)
+#define DIAG_BR (0x5)
+#define DIAG_RGB (0x7)
+#define DIAG_RGBW (0xf)
+
+/* What should we do about the W/K component? For the moment, */
+/* we ignore it in the luminance computation. */
+#define lum_white_weight 0
+private const unsigned short lum_w[16] = {
+ (0*lum_blue_weight+0*lum_green_weight+0*lum_red_weight+0*lum_white_weight),
+ (0*lum_blue_weight+0*lum_green_weight+1*lum_red_weight+0*lum_white_weight),
+ (0*lum_blue_weight+1*lum_green_weight+0*lum_red_weight+0*lum_white_weight),
+ (0*lum_blue_weight+1*lum_green_weight+1*lum_red_weight+0*lum_white_weight),
+ (1*lum_blue_weight+0*lum_green_weight+0*lum_red_weight+0*lum_white_weight),
+ (1*lum_blue_weight+0*lum_green_weight+1*lum_red_weight+0*lum_white_weight),
+ (1*lum_blue_weight+1*lum_green_weight+0*lum_red_weight+0*lum_white_weight),
+ (1*lum_blue_weight+1*lum_green_weight+1*lum_red_weight+0*lum_white_weight),
+ (0*lum_blue_weight+0*lum_green_weight+0*lum_red_weight+1*lum_white_weight),
+ (0*lum_blue_weight+0*lum_green_weight+1*lum_red_weight+1*lum_white_weight),
+ (0*lum_blue_weight+1*lum_green_weight+0*lum_red_weight+1*lum_white_weight),
+ (0*lum_blue_weight+1*lum_green_weight+1*lum_red_weight+1*lum_white_weight),
+ (1*lum_blue_weight+0*lum_green_weight+0*lum_red_weight+1*lum_white_weight),
+ (1*lum_blue_weight+0*lum_green_weight+1*lum_red_weight+1*lum_white_weight),
+ (1*lum_blue_weight+1*lum_green_weight+0*lum_red_weight+1*lum_white_weight),
+ (1*lum_blue_weight+1*lum_green_weight+1*lum_red_weight+1*lum_white_weight)
+};
+
+/* Render RGB or CMYK, possibly by halftoning. */
+/* If we are rendering RGB, white is ignored. */
+/* If we are rendering CMYK, red/green/blue/white are actually */
+/* cyan/magenta/yellow/black. */
+int
+gx_render_device_color(frac red, frac green, frac blue, frac white, bool cmyk,
+ gx_color_value alpha, gx_device_color *pdevc, gx_device *dev,
+ const gx_device_halftone *pdht, const gs_int_point *ht_phase)
+{ uint max_value = dev->color_info.dither_colors - 1;
+ uint num_levels = pdht->order.num_levels;
+ frac rem_r, rem_g, rem_b, rem_w;
+ uint r, g, b, w;
+ gx_color_value vr, vg, vb, vw;
+#define map_color_rgb()\
+ (alpha == gx_max_color_value ?\
+ gx_map_rgb_color(dev, vr, vg, vb) :\
+ gx_map_rgb_alpha_color(dev, vr, vg, vb, alpha))
+#define map_color_cmyk()\
+ gx_map_cmyk_color(dev, vr, vg, vb, vw)
+#define map_color()\
+ (cmyk ? map_color_cmyk() : map_color_rgb())
+
+ /* Compute the quotient and remainder of each color component */
+ /* with the actual number of available colors. */
+ switch ( max_value )
+ {
+ case 1: /* 8 or 16 colors */
+ if ( red == frac_1 ) rem_r = 0, r = 1;
+ else rem_r = red, r = 0;
+ if ( green == frac_1 ) rem_g = 0, g = 1;
+ else rem_g = green, g = 0;
+ if ( blue == frac_1 ) rem_b = 0, b = 1;
+ else rem_b = blue, b = 0;
+ if ( white == frac_1 ) rem_w = 0, w = 1;
+ else rem_w = white, w = 0;
+ break;
+ default:
+ { ulong want_r, want_g, want_b, want_w;
+ want_r = (ulong)max_value * red;
+ r = frac_1_quo(want_r);
+ rem_r = frac_1_rem(want_r, r);
+ want_g = (ulong)max_value * green;
+ g = frac_1_quo(want_g);
+ rem_g = frac_1_rem(want_g, g);
+ want_b = (ulong)max_value * blue;
+ b = frac_1_quo(want_b);
+ rem_b = frac_1_rem(want_b, b);
+ want_w = (ulong)max_value * white;
+ w = frac_1_quo(want_w);
+ rem_w = frac_1_rem(want_w, w);
+ }
+ }
+
+ /* Check for no dithering required */
+ if ( !(rem_r | rem_g | rem_b | rem_w) )
+ { vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ vw = fractional_color(w, max_value);
+ color_set_pure(pdevc, map_color());
+ return 0;
+ }
+
+ if_debug12('c', "[c]rgbw=0x%x,0x%x,0x%x,0x%x -->\n %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x -->\n",
+ (unsigned)red, (unsigned)green, (unsigned)blue, (unsigned)white,
+ (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
+ (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w);
+
+ /* Dithering is required. Choose between two algorithms. */
+
+ if ( pdht->components != 0 && dev->color_info.depth >= 4 )
+ { /* Someone went to the trouble of setting different */
+ /* screens for the different components. */
+ /* Use the slow, general colored halftone algorithm. */
+#define rgb_rem(rem_v, i)\
+ (rem_v * (ulong)(pdht->components[pdht->color_indices[i]].corder.num_levels) / frac_1)
+ uint lr = rgb_rem(rem_r, 0), lg = rgb_rem(rem_g, 1),
+ lb = rgb_rem(rem_b, 2);
+ if ( cmyk )
+ color_set_cmyk_halftone(pdevc, pdht, r, lr, g, lg, b, lb,
+ w, rgb_rem(rem_w, 3));
+ else
+ color_set_rgb_halftone(pdevc, pdht, r, lr, g, lg, b, lb, alpha);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->lcm_width, pdht->lcm_height);
+#undef rgb_rem
+ return 1;
+ }
+
+ /* Fast, approximate binary halftone algorithm. */
+
+ { ulong hsize = num_levels;
+ int adjust_r, adjust_b, adjust_g, adjust_w;
+ gx_color_index color1;
+ frac amax, amin;
+ ulong fmax, cmax;
+ int axisc, facec, cubec, diagc;
+ unsigned short lum_invert;
+ ulong dot1, dot2, dot3, dot4;
+ int level;
+ int code;
+
+/* Flip the remainder color into the 0, 0, 0 octant. */
+ lum_invert = 0;
+#define half (frac_1/2)
+ if ( rem_r > half )
+ rem_r = frac_1 - rem_r,
+ adjust_r = -1, r++, lum_invert += lum_red_weight * 2;
+ else
+ adjust_r = 1;
+ if ( rem_g > half )
+ rem_g = frac_1 - rem_g,
+ adjust_g = -1, g++, lum_invert += lum_green_weight * 2;
+ else
+ adjust_g = 1;
+ if ( rem_b > half )
+ rem_b = frac_1 - rem_b,
+ adjust_b = -1, b++, lum_invert += lum_blue_weight * 2;
+ else
+ adjust_b = 1;
+ vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ if ( cmyk )
+ { if ( rem_w > half )
+ rem_w = frac_1 - rem_w,
+ adjust_w = -1, b++, lum_invert += lum_white_weight * 2;
+ else
+ adjust_w = 1;
+ vw = fractional_color(w, max_value);
+ color1 = map_color_cmyk();
+ }
+ else
+ color1 = map_color_rgb();
+
+/*
+ * Dot the color with each axis to find the best one of 15;
+ * find the color at the end of the axis chosen.
+ */
+ cmax = (ulong)rem_r+rem_g+rem_b;
+ dot4 = cmax + rem_w;
+ if ( rem_g > rem_r )
+ { if ( rem_b > rem_g )
+ amax = rem_b, axisc = DIAG_B;
+ else
+ amax = rem_g, axisc = DIAG_G;
+ if ( rem_b > rem_r )
+ amin = rem_r, fmax = (ulong)rem_g+rem_b, facec = DIAG_GB;
+ else
+ amin = rem_b, fmax = (ulong)rem_r+rem_g, facec = DIAG_RG;
+ }
+ else
+ { if ( rem_b > rem_r )
+ amax = rem_b, axisc = DIAG_B;
+ else
+ amax = rem_r, axisc = DIAG_R;
+ if ( rem_b > rem_g )
+ amin = rem_g, fmax = (ulong)rem_b+rem_r, facec = DIAG_BR;
+ else
+ amin = rem_b, fmax = (ulong)rem_r+rem_g, facec = DIAG_RG;
+ }
+ if ( rem_w > amin )
+ { cmax = fmax + rem_w, cubec = facec + DIAG_W;
+ if ( rem_w > amax )
+ fmax = (ulong)amax + rem_w, facec = axisc + DIAG_W,
+ amax = rem_w, axisc = DIAG_W;
+ else if ( rem_w > fmax - amax )
+ fmax = (ulong)amax + rem_w, facec = axisc + DIAG_W;
+ }
+ else
+ cubec = DIAG_RGB;
+
+ dot1 = amax*WEIGHT1;
+ dot2 = fmax*WEIGHT2;
+ dot3 = cmax*WEIGHT3;
+ /*dot4 see above*/
+#define use_axis()\
+ diagc = axisc, level = (hsize * amax + (frac_1_long / 2)) / frac_1_long
+#define use_face()\
+ diagc = facec, level = (hsize * fmax + frac_1_long) / (2 * frac_1_long)
+#define use_cube()\
+ diagc = cubec, level = (hsize * cmax + (3 * frac_1_long / 2)) / (3 * frac_1_long)
+#define use_tesseract()\
+ diagc = DIAG_RGBW, level = (hsize * dot4 + (2 * frac_1_long)) / (4 * frac_1_long)
+ if ( dot1 > dot2 )
+ { if ( dot3 > dot1 )
+ { if ( dot4*WEIGHT4 > dot3 )
+ use_tesseract();
+ else
+ use_cube();
+ }
+ else
+ { if ( dot4*WEIGHT4 > dot1 )
+ use_tesseract();
+ else
+ use_axis();
+ }
+ }
+ else
+ { if ( dot3 > dot2 )
+ { if ( dot4*WEIGHT4 > dot3 )
+ use_tesseract();
+ else
+ use_cube();
+ }
+ else
+ { if ( dot4*WEIGHT4 > dot2 )
+ use_tesseract();
+ else
+ use_face();
+ }
+ };
+
+ if_debug12('c', " %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x; adjust=%d,%d,%d,%d\n",
+ (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
+ (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w,
+ adjust_r, adjust_g, adjust_b, adjust_w);
+
+ if ( level == 0 )
+ { color_set_pure(pdevc, color1);
+ code = 0;
+ }
+ else
+ { gx_color_index color2;
+/* construct the second color, inverting back to original space if needed */
+ if (diagc & DIAG_R) r += adjust_r;
+ if (diagc & DIAG_G) g += adjust_g;
+ if (diagc & DIAG_B) b += adjust_b;
+/* get the second device color, sorting by luminance */
+ vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ if ( cmyk )
+ { if (diagc & DIAG_W) w += adjust_w;
+ vw = fractional_color(w, max_value);
+ color2 = map_color_cmyk();
+ }
+ else
+ color2 = map_color_rgb();
+ if ( level == num_levels )
+ { /* This can only happen through rounding.... */
+ color_set_pure(pdevc, color2);
+ code = 0;
+ }
+ else
+ { if ( lum_w[diagc] < lum_invert )
+ color_set_binary_halftone(pdevc, pdht, color2, color1, hsize - level);
+ else
+ color_set_binary_halftone(pdevc, pdht, color1, color2, level);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->order.width,
+ pdht->order.full_height);
+ code = 1;
+ }
+ }
+
+ if_debug7('c', "[c]diagc=%d; colors=0x%lx,0x%lx; level=%d/%d; lum=%d,diag=%d\n",
+ diagc, (ulong)pdevc->colors.binary.color[0],
+ (ulong)pdevc->colors.binary.color[1],
+ level, (unsigned)hsize, lum_invert, lum_w[diagc]);
+ return code;
+ }
+}
diff --git a/gs/src/gxdither.h b/gs/src/gxdither.h
new file mode 100644
index 000000000..3fa12d167
--- /dev/null
+++ b/gs/src/gxdither.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxdither.h */
+/* Interface to gxdither.c */
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+#endif
+
+#ifdef DPNEXT
+/*
+ * Note that in the procedures below, the colors are specified by fracs,
+ * but the alpha value is a gx_color_value. This is a design flaw that
+ * we might be able to fix eventually.
+ */
+#endif
+
+/* Render a gray, possibly by halftoning. */
+/* Return 0 if complete, 1 if caller must do gx_color_load, <0 on error. */
+int gx_render_device_gray(P6(frac gray, gx_color_value alpha,
+ gx_device_color *pdevc, gx_device *dev,
+ const gx_device_halftone *dev_ht,
+ const gs_int_point *ht_phase));
+#ifdef DPNEXT
+#define gx_render_gray_alpha(gray, alpha, pdevc, pis, dev, select)\
+ gx_render_device_gray(gray, alpha, pdevc, dev, pis->dev_ht,\
+ &pis->screen_phase[select])
+#define gx_render_gray(gray, pdevc, pis, dev, select)\
+ gx_render_gray_alpha(gray, pis->alpha, pdevc, pis, dev, select)
+#else
+#define gx_render_gray(gray, pdevc, pis, dev, select)\
+ gx_render_device_gray(gray, pis->alpha, pdevc, dev, pis->dev_ht,\
+ &pis->screen_phase[select])
+#endif
+
+/* Render a color, possibly by halftoning. */
+/* Return as for gx_render_[device_]gray. */
+int gx_render_device_color(P10(frac red, frac green, frac blue, frac white,
+ bool cmyk, gx_color_value alpha,
+ gx_device_color *pdevc, gx_device *dev,
+ const gx_device_halftone *pdht,
+ const gs_int_point *ht_phase));
+#ifdef DPNEXT
+#define gx_render_color_alpha(r, g, b, w, a, cmyk, pdevc, pis, dev, select)\
+ gx_render_device_color(r, g, b, w, cmyk, a, pdevc, dev,\
+ pis->dev_ht, &pis->screen_phase[select])
+#define gx_render_color(r, g, b, w, cmyk, pdevc, pis, dev, select)\
+ gx_render_color_alpha(r, g, b, w, pis->alpha, cmyk, pdevc, pis, dev, select)
+#else
+#define gx_render_color(r, g, b, w, cmyk, pdevc, pis, dev, select)\
+ gx_render_device_color(r, g, b, w, cmyk, pis->alpha, pdevc, dev,\
+ pis->dev_ht, &pis->screen_phase[select])
+#endif
+#define gx_render_rgb(r, g, b, pdevc, pis, dev, select)\
+ gx_render_color(r, g, b, frac_0, false, pdevc, pis, dev, select)
+#define gx_render_cmyk(c, m, y, k, pdevc, pis, dev, select)\
+ gx_render_color(c, m, y, k, true, pdevc, pis, dev, select)
+#ifdef DPNEXT
+#define gx_render_rgb_alpha(r, g, b, a, pdevc, pis, dev, select)\
+ gx_render_color_alpha(r, g, b, frac_0, a, false, pdevc, pis, dev, select)
+#endif
diff --git a/gs/src/gxfarith.h b/gs/src/gxfarith.h
new file mode 100644
index 000000000..8b1ff8b6a
--- /dev/null
+++ b/gs/src/gxfarith.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfarith.h */
+/* Floating point arithmetic macros for Ghostscript library */
+#include "gconfigv.h" /* for USE_FPU */
+#include "gxarith.h"
+
+/*
+ * The following macros replace the ones in gxarith.h on machines
+ * that are likely to have very slow floating point.
+ *
+ * None of these macros would be necessary if compilers had a clue
+ * about generating good floating point comparisons on machines with
+ * slow (or no) floating point hardware.
+ */
+
+# if USE_FPU <= 0 && arch_floats_are_IEEE && (arch_sizeof_float == arch_sizeof_int || arch_sizeof_float == arch_sizeof_long)
+
+# if arch_sizeof_float == arch_sizeof_int
+typedef int _f_int_t;
+typedef uint _f_uint_t;
+# else /* arch_sizeof_float == arch_sizeof_long */
+typedef long _f_int_t;
+typedef ulong _f_uint_t;
+# endif
+# define _f_as_int(f) *(_f_int_t *)(&(f))
+# define _f_as_uint(f) *(_f_uint_t *)(&(f))
+
+# if arch_sizeof_double == arch_sizeof_int
+# define _d_int_t int
+# else
+# if arch_sizeof_double == arch_sizeof_long
+# define _d_int_t long
+# endif
+# endif
+# define _d_uint_t unsigned _d_int_t
+# define _d_as_int(f) *(_d_int_t *)(&(d))
+# define _d_as_uint(f) *(_d_uint_t *)(&(d))
+
+# define _ftest(v,f,n)\
+ (sizeof(v)==sizeof(float)?(f):(n))
+# ifdef _d_int_t
+# define _fdtest(v,f,d,n)\
+ (sizeof(v)==sizeof(float)?(f):sizeof(v)==sizeof(double)?(d):(n))
+# else
+# define _fdtest(v,f,d,n)\
+ _ftest(v,f,n)
+# endif
+
+# undef is_fzero
+# define is_fzero(f) /* must handle both +0 and -0 */\
+ _fdtest(f, (_f_as_int(f) << 1) == 0, (_d_as_int(f) << 1) == 0,\
+ (f) == 0.0)
+
+# undef is_fzero2
+# define is_fzero2(f1,f2)\
+ (sizeof(f1) == sizeof(float) && sizeof(f2) == sizeof(float) ?\
+ ((_f_as_int(f1) | _f_as_int(f2)) << 1) == 0 :\
+ (f1) == 0.0 && (f2) == 0.0)
+
+# undef is_fneg
+# if arch_is_big_endian
+# define _is_fnegb(f) (*(byte *)&(f) >= 0x80)
+# else
+# define _is_fnegb(f) (((byte *)&(f))[sizeof(f) - 1] >= 0x80)
+# endif
+# if arch_sizeof_float == arch_sizeof_int
+# define is_fneg(f)\
+ (sizeof(f) == sizeof(float) ? _f_as_int(f) < 0 :\
+ _is_fnegb(f))
+# else
+# define is_fneg(f) _is_fnegb(f)
+# endif
+
+# define IEEE_expt 0x7f800000 /* IEEE exponent mask */
+# define IEEE_f1 0x3f800000 /* IEEE 1.0 */
+
+# undef is_fge1
+# if arch_sizeof_float == arch_sizeof_int
+# define is_fge1(f)\
+ (sizeof(f) == sizeof(float) ?\
+ (_f_as_int(f)) >= IEEE_f1 :\
+ (f) >= 1.0)
+# else /* arch_sizeof_float == arch_sizeof_long */
+# define is_fge1(f)\
+ (sizeof(f) == sizeof(float) ?\
+ (int)(_f_as_int(f) >> 16) >= (IEEE_f1 >> 16) :\
+ (f) >= 1.0)
+# endif
+
+# undef f_fits_in_ubits
+# undef f_fits_in_bits
+# define _f_bits(n) (4.0 * (1L << ((n) - 2)))
+# define f_fits_in_ubits(f, n)\
+ _ftest(f, _f_as_uint(f) < (_f_uint_t)IEEE_f1 + ((_f_uint_t)(n) << 23),\
+ (f) >= 0 && (f) < _f_bits(n))
+# define f_fits_in_bits(f, n)\
+ _ftest(f, (_f_as_uint(f) & IEEE_expt) < IEEE_f1 + ((_f_uint_t)((n)-1) << 23),\
+ (f) >= -_f_bits((n)-1) && (f) < _f_bits((n)-1))
+
+# endif /* USE_FPU <= 0 & ... */
+
+/*
+ * Define sine and cosine functions that take angles in degrees rather than
+ * radians, hit exact values at multiples of 90 degrees, and are implemented
+ * efficiently on machines with slow (or no) floating point.
+ */
+double gs_sin_degrees(P1(double angle));
+double gs_cos_degrees(P1(double angle));
+typedef struct gs_sincos_s {
+ double sin, cos;
+} gs_sincos_t;
+void gs_sincos_degrees(P2(double angle, gs_sincos_t *psincos));
diff --git a/gs/src/gxfcache.h b/gs/src/gxfcache.h
new file mode 100644
index 000000000..a94460323
--- /dev/null
+++ b/gs/src/gxfcache.h
@@ -0,0 +1,250 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfcache.h */
+/* Definitions for Ghostscript font and character caches */
+/* Requires gsfont.h */
+#include "gsuid.h"
+#include "gsxfont.h"
+#include "gxbcache.h"
+#include "gxftype.h"
+
+/* ------ Font/matrix pair cache entry ------ */
+
+#ifndef cached_fm_pair_DEFINED
+# define cached_fm_pair_DEFINED
+typedef struct cached_fm_pair_s cached_fm_pair;
+#endif
+
+/*
+ * Define the entry for a cached (font,matrix) pair. If the UID
+ * is valid, the font pointer may be 0, since we keep entries even for
+ * fonts unloaded by a restore if they have valid UIDs; in this case,
+ * we also need the FontType as part of the key.
+ * Note that because of the dependency on StrokeWidth, we can't cache
+ * fonts with non-zero PaintType.
+ * We can't use the address of the pair for the hash value,
+ * since the GC may move pairs in storage, so we create a hash
+ * when we allocate the pair initially.
+ */
+struct cached_fm_pair_s {
+ gs_font *font; /* base font */
+ gs_uid UID; /* font UniqueID or XUID */
+ font_type FontType; /* (part of key if UID is valid) */
+ uint hash; /* hash for this pair */
+ float mxx, mxy, myx, myy; /* transformation */
+ int num_chars; /* # of cached chars with this */
+ /* f/m pair */
+ bool xfont_tried; /* true if we looked up an xfont */
+ gx_xfont *xfont; /* the xfont (if any) */
+ gs_memory_t *memory; /* the allocator for the xfont */
+ uint index; /* index of this pair in mdata */
+};
+#define private_st_cached_fm_pair() /* in gxccman.c */\
+ gs_private_st_ptrs3(st_cached_fm_pair, cached_fm_pair,\
+ "cached_fm_pair", fm_pair_enum_ptrs, fm_pair_reloc_ptrs,\
+ font, UID.xvalues, xfont)
+#define private_st_cached_fm_pair_elt() /* in gxccman.c */\
+ gs_private_st_element(st_cached_fm_pair_element, cached_fm_pair,\
+ "cached_fm_pair[]", fm_pair_element_enum_ptrs, fm_pair_element_reloc_ptrs,\
+ st_cached_fm_pair)
+/* If font == 0 and UID is invalid, this is a free entry. */
+#define fm_pair_is_free(pair)\
+ ((pair)->font == 0 && !uid_is_valid(&(pair)->UID))
+#define fm_pair_set_free(pair)\
+ ((pair)->font = 0, uid_set_invalid(&(pair)->UID))
+#define fm_pair_init(pair)\
+ (fm_pair_set_free(pair), (pair)->xfont_tried = false, (pair)->xfont = 0)
+
+/* The font/matrix pair cache itself. */
+typedef struct fm_pair_cache_s {
+ uint msize, mmax; /* # of cached font/matrix pairs */
+ cached_fm_pair *mdata;
+ uint mnext; /* rover for allocating font/matrix pairs */
+} fm_pair_cache;
+
+/* ------ Character cache entry ------- */
+
+/* Define the allocation chunk type. */
+typedef gx_bits_cache_chunk char_cache_chunk;
+
+/*
+ * This is a subclass of the entry in a general bitmap cache.
+ * The character cache contains both used and free blocks.
+ * All blocks have a common header; free blocks have ONLY the header.
+ */
+typedef gx_cached_bits_head cached_char_head;
+#define cc_head_is_free(cch) cb_head_is_free(cch)
+#define cc_head_set_free(cch) cb_head_set_free(cch)
+/*
+ * Define the cache entry for an individual character.
+ * The bits, if any, immediately follow the structure;
+ * characters with only xfont definitions may not have bits.
+ * An entry is 'real' if it is not free and if pair != 0.
+ * We maintain the invariant that at least one of the following must be true
+ * for all real entries:
+ * - cc_has_bits(cc);
+ * - cc->xglyph != gx_no_xglyph && cc_pair(cc)->xfont != 0.
+ */
+#ifndef cached_char_DEFINED
+# define cached_char_DEFINED
+typedef struct cached_char_s cached_char;
+#endif
+struct cached_char_s {
+
+ /* The code, font/matrix pair, wmode, and depth */
+ /* are the 'key' in the cache. */
+ /* gx_cached_bits_common includes depth. */
+
+ gx_cached_bits_common; /* (must be first) */
+#define cc_depth(cc) ((cc)->cb_depth)
+#define cc_set_depth(cc, d) ((cc)->cb_depth = (d))
+ cached_fm_pair *pair;
+#define cc_pair(cc) ((cc)->pair)
+#define cc_set_pair_only(cc, p) ((cc)->pair = (p))
+ gs_glyph code; /* glyph code */
+ byte wmode; /* writing mode (0 or 1) */
+
+ /* The following are neither 'key' nor 'value'. */
+
+ char_cache_chunk *chunk; /* chunk where this char */
+ /* is allocated */
+ uint loc; /* relative location in chunk */
+ uint pair_index; /* index of pair in mdata */
+
+ /* The rest of the structure is the 'value'. */
+ /* gx_cached_bits_common has width, height, raster, */
+ /* shift (not used here), id. */
+
+#define cc_raster(cc) ((cc)->raster)
+#define cc_set_raster(cc, r) ((cc)->raster = (r))
+ gx_xglyph xglyph; /* the xglyph for the xfont, if any */
+ gs_fixed_point wxy; /* width in device coords */
+ gs_fixed_point offset; /* (-llx, -lly) in device coords */
+};
+#define cc_is_free(cc) cc_head_is_free(&(cc)->head)
+#define cc_set_free(cc) cc_head_set_free(&(cc)->head)
+#define cc_set_pair(cc, p)\
+ ((cc)->pair_index = ((cc)->pair = (p))->index)
+#define cc_has_bits(cc) ((cc)->id != gx_no_bitmap_id)
+/*
+ * Memory management for cached_chars is a little unusual.
+ * cached_chars are never instantiated on their own; a pointer to
+ * a cached_char points into the middle of a cache chunk.
+ * Consequently, such pointers can't be traced or relocated
+ * in the usual way. What we do instead is allocate the cache
+ * outside garbage-collectable space; we do all the tracing and relocating
+ * of pointers *from* the cache (currently only the head.pair pointer)
+ * when we trace or relocate the font "directory" that owns the cache.
+ *
+ * Since cached_chars are (currently) never instantiated on their own,
+ * they only have a descriptor so that cached_char_ptr can trace them.
+ */
+#define private_st_cached_char() /* in gxccman.c */\
+ gs_private_st_composite(st_cached_char, cached_char, "cached_char",\
+ cached_char_enum_ptrs, cached_char_reloc_ptrs)
+#define private_st_cached_char_ptr() /* in gxccman.c */\
+ gs_private_st_composite(st_cached_char_ptr, cached_char *,\
+ "cached_char *", cc_ptr_enum_ptrs, cc_ptr_reloc_ptrs)
+#define private_st_cached_char_ptr_elt() /* in gxccman.c */\
+ gs_private_st_element(st_cached_char_ptr_element, cached_char *,\
+ "cached_char *[]", cc_ptr_element_enum_ptrs, cc_ptr_element_reloc_ptrs,\
+ st_cached_char_ptr)
+
+/*
+ * Define the alignment and size of the cache structures.
+ */
+#define align_cached_char_mod align_cached_bits_mod
+#define sizeof_cached_char\
+ round_up(sizeof(cached_char), align_cached_char_mod)
+#define cc_bits(cc) ((byte *)(cc) + sizeof_cached_char)
+#define cc_const_bits(cc) ((const byte *)(cc) + sizeof_cached_char)
+
+/* Define the hash index for a (glyph, fm_pair) key. */
+#define chars_head_index(glyph, pair)\
+ ((uint)(glyph) * 59 + (pair)->hash * 73) /* scramble it a bit */
+
+/* ------ Character cache ------ */
+
+/*
+ * So that we can find all the entries in the cache without
+ * following chains of pointers, we use open hashing rather than
+ * chained hashing for the lookup table.
+ */
+typedef struct char_cache_s {
+ /* gx_bits_cache_common provides chunks, cnext, */
+ /* bsize, csize. */
+ gx_bits_cache_common;
+ gs_memory_t *memory;
+ cached_char **table; /* hash table */
+ uint table_mask; /* (a power of 2 -1) */
+ uint bmax; /* max bsize */
+ uint cmax; /* max csize */
+ uint bspace; /* space allocated for chunks */
+ uint lower; /* min size at which cached chars */
+ /* should be stored compressed */
+ uint upper; /* max size of a single cached char */
+ gs_glyph_mark_proc_t mark_glyph;
+ void *mark_glyph_data; /* closure data */
+} char_cache;
+
+/* ------ Font/character cache ------ */
+
+/* A font "directory" (font/character cache manager). */
+struct gs_font_dir_s {
+
+ /* Original (unscaled) fonts */
+
+ gs_font *orig_fonts;
+
+ /* Scaled font cache */
+
+ gs_font *scaled_fonts; /* list of recently scaled fonts */
+ uint ssize, smax;
+
+ /* Font/matrix pair cache */
+
+ fm_pair_cache fmcache;
+
+ /* Character cache */
+
+ char_cache ccache;
+ /* Scanning cache for GC */
+ uint enum_index; /* index (N) */
+ uint enum_offset; /* ccache.table[offset] is N'th non-zero entry */
+};
+#define private_st_font_dir() /* in gsfont.c */\
+ gs_private_st_composite(st_font_dir, gs_font_dir, "gs_font_dir",\
+ font_dir_enum_ptrs, font_dir_reloc_ptrs)
+
+/* Enumerate the pointers in a font directory, except for orig_fonts. */
+#define font_dir_do_ptrs(m)\
+ /*m(-,orig_fonts)*/ m(0,scaled_fonts) m(1,fmcache.mdata)\
+ m(2,ccache.table) m(3,ccache.mark_glyph_data)
+#define st_font_dir_max_ptrs 4
+
+/* Character cache procedures (in gxccache.c and gxccman.c) */
+int gx_char_cache_alloc(P6(gs_memory_t *, gs_font_dir *, uint, uint, uint, uint));
+void gx_char_cache_init(P1(gs_font_dir *));
+void gx_purge_selected_cached_chars(P3(gs_font_dir *, bool (*)(P2(cached_char *, void *)), void *));
+cached_fm_pair *
+ gx_lookup_fm_pair(P2(gs_font *, const gs_state *));
+cached_fm_pair *
+ gx_add_fm_pair(P4(gs_font_dir *, gs_font *, const gs_uid *, const gs_state *));
+void gx_lookup_xfont(P3(const gs_state *, cached_fm_pair *, int));
+void gs_purge_fm_pair(P3(gs_font_dir *, cached_fm_pair *, int));
diff --git a/gs/src/gxfcmap.h b/gs/src/gxfcmap.h
new file mode 100644
index 000000000..471834a1c
--- /dev/null
+++ b/gs/src/gxfcmap.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfcmap.h */
+/* Internal CMap data definition */
+
+/* This file should be called gxcmap.h, except that name is already used. */
+
+#ifndef gxfcmap_INCLUDED
+# define gxfcmap_INCLUDED
+
+#include "gsfcmap.h"
+#include "gsuid.h"
+
+/*
+ * The main body of data in a CMap is two code maps, one for defined
+ * characters, one for notdefs. Each code map is a multi-level tree,
+ * one level per byte decoded from the input string. Each node of
+ * the tree may be:
+ * a character code (1-4 bytes)
+ * a character name (gs_glyph)
+ * a CID (gs_glyph)
+ * a subtree
+ */
+typedef enum {
+ cmap_char_code,
+ cmap_glyph, /* character name or CID */
+ cmap_subtree
+} gx_code_map_type;
+typedef struct gx_code_map_s gx_code_map;
+struct gx_code_map_s {
+ byte first; /* first char code covered by this node */
+ byte last; /* last char code ditto */
+ uint /*gx_code_map_type*/ type : 2;
+ uint num_bytes1 : 2; /* # of bytes -1 for char_code */
+ uint /*bool*/ add_offset : 1; /* if set, add char - first to ccode / glyph */
+ /* We would like to combine the two unions into a union of structs, */
+ /* but no compiler seems to do the right thing about packing. */
+ union bd_ {
+ byte font_index; /* for leaf, font index */
+ /* (only non-zero if rearranged font) */
+ byte count1; /* for subtree, # of entries -1 */
+ } byte_data;
+ union d_ {
+ gs_char ccode; /* num_bytes bytes */
+ gs_glyph glyph;
+ gx_code_map *subtree; /* [count] */
+ } data;
+ gs_cmap *cmap; /* point back to CMap for GC mark proc */
+};
+/* The GC information for a gx_code_map is complex, because names must be */
+/* traced. */
+extern_st(st_code_map);
+extern_st(st_code_map_element);
+#define public_st_code_map() /* in gsfcmap.c */\
+ gs_public_st_composite(st_code_map, gx_code_map, "gx_code_map",\
+ code_map_enum_ptrs, code_map_reloc_ptrs)
+#define public_st_code_map_element() /* in gsfcmap.c */\
+ gs_public_st_element(st_code_map_element, gx_code_map, "gx_code_map[]",\
+ code_map_elt_enum_ptrs, code_map_elt_reloc_ptrs, st_code_map)
+
+/* A CMap proper is relatively simple. */
+struct gs_cmap_s {
+ gs_cid_system_info CIDSystemInfo; /* must be first */
+ gs_uid uid;
+ int WMode;
+ gx_code_map def; /* defined characters (cmap_subtree) */
+ gx_code_map notdef; /* notdef characters (cmap_subtree) */
+ gs_glyph_mark_proc_t mark_glyph; /* glyph marking procedure for GC */
+ void *mark_glyph_data; /* closure data */
+};
+/*extern_st(st_cmap);*/
+#define public_st_cmap() /* in gsfcmap.c */\
+ gs_public_st_suffix_add4(st_cmap, gs_cmap, "gs_cmap",\
+ cmap_enum_ptrs, cmap_reloc_ptrs, st_cid_system_info,\
+ uid.xvalues, def.data.subtree, notdef.data.subtree, mark_glyph_data)
+
+#endif /* gxfcmap_INCLUDED */
diff --git a/gs/src/gxfill.c b/gs/src/gxfill.c
new file mode 100644
index 000000000..643a3cf5f
--- /dev/null
+++ b/gs/src/gxfill.c
@@ -0,0 +1,1507 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfill.c */
+/* Lower-level path filling procedures */
+#include "math_.h" /* for floor in fixed_mult_quo */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxdcolor.h"
+#include "gxhttile.h"
+#include "gxistate.h"
+#include "gxpaint.h" /* for prototypes */
+
+/* Define which fill algorithm(s) to use. */
+#define FILL_SCAN_LINES
+#define FILL_CURVES
+#define FILL_TRAPEZOIDS
+
+/* Define the structure for keeping track of active lines. */
+typedef struct active_line_s active_line;
+struct active_line_s {
+ gs_fixed_point start; /* x,y where line starts */
+ gs_fixed_point end; /* x,y where line ends */
+ gs_fixed_point diff; /* end - start */
+#define al_dx(alp) ((alp)->diff.x)
+#define al_dy(alp) ((alp)->diff.y)
+ fixed y_fast_max; /* can do x_at_y in fixed point */
+ /* if y <= y_fast_max */
+#define set_al_points(alp, startp, endp)\
+ (alp)->diff.x = (endp).x - (startp).x,\
+ (alp)->y_fast_max = max_fixed /\
+ (((alp)->diff.x >= 0 ? (alp)->diff.x : -(alp)->diff.x) | 1) + (startp).y,\
+ (alp)->diff.y = (endp).y - (startp).y,\
+ (alp)->start = startp, (alp)->end = endp
+#define al_x_at_y(alp, yv)\
+ ((yv) == (alp)->end.y ? (alp)->end.x :\
+ ((yv) <= (alp)->y_fast_max ?\
+ ((yv) - (alp)->start.y) * al_dx(alp) / al_dy(alp) :\
+ (n_add1_expr(n_slow_x),\
+ fixed_mult_quo(al_dx(alp), (yv) - (alp)->start.y, al_dy(alp)))) +\
+ (alp)->start.x)
+ fixed x_current; /* current x position */
+ fixed x_next; /* x position at end of band */
+ const segment *pseg; /* endpoint of this line */
+ int direction; /* direction of line segment */
+#define dir_up 1
+#define dir_horizontal 0 /* (these are handled specially) */
+#define dir_down (-1)
+ int curve_k; /* # of subdivisions for curves, */
+ /* -1 for lines */
+ curve_cursor cursor; /* cursor for curves, */
+ /* unused for lines */
+/* "Pending" lines (not reached in the Y ordering yet) use next and prev */
+/* to order lines by increasing starting Y. "Active" lines (being scanned) */
+/* use next and prev to order lines by increasing current X, or if the */
+/* current Xs are equal, by increasing final X. */
+ active_line *prev, *next;
+/* Link together active_lines allocated individually */
+ active_line *alloc_next;
+};
+/*
+ * The active_line structure isn't really simple, but since its instances
+ * only exist temporarily during a fill operation, we don't have to
+ * worry about a garbage collection occurring.
+ */
+gs_private_st_simple(st_active_line, active_line, "active_line");
+
+/* Define the ordering criterion for active lines. */
+/* The xc argument is a copy of lp2->x_current. */
+#define x_precedes(lp1, lp2, xc)\
+ (lp1->x_current < xc || (lp1->x_current == xc &&\
+ (lp1->start.x > lp2->start.x || lp1->end.x < lp2->end.x)))
+
+#ifdef DEBUG
+/* Internal procedures for printing and checking active lines. */
+private void
+print_active_line(const char *label, const active_line *alp)
+{ dprintf5("[f]%s 0x%lx(%d): x_current=%f x_next=%f\n",
+ label, (ulong)alp, alp->direction,
+ fixed2float(alp->x_current), fixed2float(alp->x_next));
+ dprintf5(" start=(%f,%f) pt_end=0x%lx(%f,%f)\n",
+ fixed2float(alp->start.x), fixed2float(alp->start.y),
+ (ulong)alp->pseg,
+ fixed2float(alp->end.x), fixed2float(alp->end.y));
+ dprintf2(" prev=0x%lx next=0x%lx\n",
+ (ulong)alp->prev, (ulong)alp->next);
+}
+private void
+print_line_list(const active_line *flp)
+{ const active_line *lp;
+ for ( lp = flp; lp != 0; lp = lp->next )
+ { fixed xc = lp->x_current, xn = lp->x_next;
+ dprintf3("[f]0x%lx(%d): x_current/next=%g",
+ (ulong)lp, lp->direction,
+ fixed2float(xc));
+ if ( xn != xc ) dprintf1("/%g", fixed2float(xn));
+ dputc('\n');
+ }
+}
+#define print_al(label,alp)\
+ if ( gs_debug_c('F') ) print_active_line(label, alp)
+private int
+check_line_list(const active_line *flp)
+{ const active_line *alp;
+
+ if ( flp != 0 )
+ for ( alp = flp->prev->next; alp != 0; alp = alp->next )
+ if ( alp->next != 0 && alp->next->x_current < alp->x_current )
+ { lprintf("[f]Lines out of order!\n");
+ print_active_line(" 1:", alp);
+ print_active_line(" 2:", alp->next);
+ return_error(gs_error_Fatal);
+ }
+ return 0;
+}
+#else
+#define print_al(label,alp) DO_NOTHING
+#endif
+
+/* Line list structure */
+struct line_list_s {
+ gs_memory_t *memory;
+ active_line *active_area; /* allocated active_line list */
+ active_line *next_active; /* next allocation slot */
+ active_line *limit; /* limit of local allocation */
+ int close_count; /* # of added closing lines */
+ active_line *y_list; /* Y-sorted list of pending lines */
+ active_line *y_line; /* most recently inserted line */
+ active_line x_head; /* X-sorted list of active lines */
+#define x_list x_head.next
+ /* Put the arrays last so the scalars will have */
+ /* small displacements. */
+ /* Allocate a few active_lines locally */
+ /* to avoid round trips through the allocator. */
+#if arch_small_memory
+# define max_local_active 5 /* don't overburden the stack */
+#else
+# define max_local_active 20
+#endif
+ active_line local_active[max_local_active];
+};
+typedef struct line_list_s line_list;
+typedef line_list _ss *ll_ptr;
+
+/* Forward declarations */
+private void init_line_list(P2(ll_ptr, gs_memory_t *));
+private void unclose_path(P2(gx_path *, int));
+private void free_line_list(P1(ll_ptr));
+private int add_y_list(P5(gx_path *, ll_ptr, fixed, fixed,
+ const gs_fixed_rect *));
+private int add_y_line(P4(const segment *, const segment *, int, ll_ptr));
+private void near insert_x_new(P2(active_line *, ll_ptr));
+private bool near end_x_line(P1(active_line *));
+#define fill_loop_proc(proc)\
+int proc(P11(ll_ptr, gx_device *,\
+ const gx_fill_params *, const gx_device_color *, gs_logical_operation_t,\
+ const gs_fixed_rect *, fixed, fixed, fixed, fixed, fixed))
+private fill_loop_proc(fill_loop_by_scan_lines);
+private fill_loop_proc(fill_loop_by_trapezoids);
+
+/* Statistics */
+#ifdef DEBUG
+# define n_add1(x) (x++)
+# define n_add1_expr(x) n_add1(x)
+# define n_add(x,n) (x += (n))
+private long n_fill;
+private long n_fill_alloc;
+private long n_y_up;
+private long n_y_down;
+private long n_horiz;
+private long n_x_step;
+private long n_slow_x;
+private long n_iter;
+private long n_find_y;
+private long n_band;
+private long n_band_step;
+private long n_band_fill;
+private long n_afill;
+private long n_slant;
+private long n_slant_shallow;
+private long n_sfill;
+#else
+# define n_add1(x) DO_NOTHING
+# define n_add1_expr(x) discard(0)
+# define n_add(x,n) DO_NOTHING
+#endif
+
+/*
+ * This is the general path filling algorithm.
+ * It uses the center-of-pixel rule for filling.
+ * We can implement Microsoft's upper-left-corner-of-pixel rule
+ * by subtracting (0.5, 0.5) from all the coordinates in the path.
+ *
+ * The adjust parameters are a hack for keeping regions
+ * from coming out too faint: they specify an amount by which to expand
+ * the sides of every filled region.
+ * Setting adjust = fixed_half is supposed to produce the effect of Adobe's
+ * any-part-of-pixel rule, but it doesn't quite, because of the
+ * closed/open interval rule for regions. We detect this as a special case
+ * and do the slightly ugly things necessary to make it work.
+ */
+
+/*
+ * Tweak the fill adjustment if necessary so that (nearly) empty
+ * rectangles are guaranteed to produce some output. This is a hack
+ * to work around a bug in the Microsoft Windows PostScript driver,
+ * which draws thin lines by filling zero-width rectangles, and in
+ * some other drivers that try to fill epsilon-width rectangles.
+ */
+void
+gx_adjust_if_empty(const gs_fixed_rect *pbox, gs_fixed_point *adjust)
+{ const fixed
+ dx = pbox->q.x - pbox->p.x,
+ dy = pbox->q.y - pbox->p.y;
+ if ( dx < fixed_half && dy >= int2fixed(2) )
+ { adjust->x = arith_rshift_1(fixed_1 + fixed_epsilon - dx);
+ if_debug1('f', "[f]thin adjust_x=%g\n",
+ fixed2float(adjust->x));
+ }
+ else
+ if ( dy < fixed_half && dx >= int2fixed(2) )
+ { adjust->y = arith_rshift_1(fixed_1 + fixed_epsilon - dy);
+ if_debug1('f', "[f]thin adjust_y=%g\n",
+ fixed2float(adjust->y));
+ }
+}
+
+/*
+ * Fill a path. This is the default implementation of the driver
+ * fill_path procedure.
+ */
+int
+gx_default_fill_path(gx_device *pdev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_fill_params *params,
+ const gx_device_color *pdevc, const gx_clip_path *pcpath)
+{ gs_fixed_point adjust;
+#define adjust_x adjust.x
+#define adjust_y adjust.y
+ gs_logical_operation_t lop = pis->log_op;
+ gs_fixed_rect ibox, bbox;
+ gx_device_clip cdev;
+ gx_device *dev = pdev;
+ gx_device *save_dev = dev;
+ gx_path ffpath;
+ gx_path *pfpath;
+ int code;
+ fixed adjust_left, adjust_right, adjust_below, adjust_above;
+ int max_fill_band = dev->max_fill_band;
+#define no_band_mask ((fixed)(-1) << (sizeof(fixed) * 8 - 1))
+ bool fill_by_trapezoids;
+ line_list lst;
+
+ adjust = params->adjust;
+ /*
+ * Compute the bounding box before we flatten the path.
+ * This can save a lot of time if the path has curves.
+ * If the path is neither fully within nor fully outside
+ * the quick-check boxes, we could recompute the bounding box
+ * and make the checks again after flattening the path,
+ * but right now we don't bother.
+ */
+ gx_path_bbox(ppath, &ibox);
+ if ( params->fill_zero_width )
+ gx_adjust_if_empty(&ibox, &adjust);
+ /* Check the bounding boxes. */
+ if_debug6('f', "[f]adjust=%g,%g bbox=(%g,%g),(%g,%g)\n",
+ fixed2float(adjust_x), fixed2float(adjust_y),
+ fixed2float(ibox.p.x), fixed2float(ibox.p.y),
+ fixed2float(ibox.q.x), fixed2float(ibox.q.y));
+ if ( pcpath )
+ gx_cpath_inner_box(pcpath, &bbox);
+ else
+ (*dev_proc(dev, get_clipping_box))(dev, &bbox);
+ if ( !rect_within(ibox, bbox) )
+ { /*
+ * Intersect the path box and the clip bounding box.
+ * If the intersection is empty, this fill is a no-op.
+ */
+ if ( pcpath )
+ gx_cpath_outer_box(pcpath, &bbox);
+ if_debug4('f', " outer_box=(%g,%g),(%g,%g)\n",
+ fixed2float(bbox.p.x), fixed2float(bbox.p.y),
+ fixed2float(bbox.q.x), fixed2float(bbox.q.y));
+ rect_intersect(ibox, bbox);
+ if ( ibox.p.x - adjust_x >= ibox.q.x + adjust_x ||
+ ibox.p.y - adjust_y >= ibox.q.y + adjust_y
+ )
+ { /* Intersection of boxes is empty! */
+ return 0;
+ }
+#undef adjust_x
+#undef adjust_y
+ /*
+ * The path is neither entirely inside the inner clip box
+ * nor entirely outside the outer clip box.
+ * If we had to flatten the path, this is where we would
+ * recompute its bbox and make the tests again,
+ * but we don't bother right now.
+ *
+ * If there is a clipping path, set up a clipping device.
+ */
+ if ( pcpath )
+ { dev = (gx_device *)&cdev;
+ gx_make_clip_device(&cdev, &cdev, &pcpath->list);
+ cdev.target = save_dev;
+ cdev.max_fill_band = save_dev->max_fill_band;
+ (*dev_proc(dev, open_device))(dev);
+ }
+ }
+ /*
+ * Compute the proper adjustment values.
+ * To get the effect of the any-part-of-pixel rule,
+ * we may have to tweak them slightly.
+ * NOTE: We changed the adjust_right/above value from 0.5+epsilon
+ * to 0.5 in release 5.01; even though this does the right thing
+ * in every case we could imagine, we aren't confident that it's
+ * correct. (The old values were definitely incorrect, since they
+ * caused 1-pixel-wide/high objects to color 2 pixels even if
+ * they fell exactly on pixel boundaries.)
+ */
+ if ( adjust.x == fixed_half )
+ adjust_left = fixed_half - fixed_epsilon,
+ adjust_right = fixed_half /* + fixed_epsilon */; /* see above */
+ else
+ adjust_left = adjust_right = adjust.x;
+ if ( adjust.y == fixed_half )
+ adjust_below = fixed_half - fixed_epsilon,
+ adjust_above = fixed_half /* + fixed_epsilon */; /* see above */
+ else
+ adjust_below = adjust_above = adjust.y;
+ /* Initialize the active line list. */
+ init_line_list(&lst, ppath->memory);
+ /*
+ * We have a choice of two different filling algorithms:
+ * scan-line-based and trapezoid-based. They compare as follows:
+ *
+ * Scan Trap
+ * ---- ----
+ * no +yes perfectly accurate Y adjustment
+ * skip +draw 0-height horizontal lines
+ * slow +fast rectangles
+ * +fast slow curves
+ * +yes no write pixels at most once
+ *
+ * Normally we use the scan line algorithm for characters, where
+ * curve speed is important and no Y adjustment is involved, and for
+ * non-idempotent RasterOps, where double pixel writing must be
+ * avoided, and the trapezoid algorithm otherwise.
+ */
+#define double_write_ok lop_is_idempotent(lop)
+#ifdef FILL_SCAN_LINES
+# ifdef FILL_TRAPEZOIDS
+ fill_by_trapezoids =
+ ((adjust_below | adjust_above) != 0 || ppath->curve_count == 0 ||
+ params->flatness >= 1.0) && double_write_ok;
+# else
+ fill_by_trapezoids = false;
+# endif
+#else
+ fill_by_trapezoids = double_write_ok;
+#endif
+#undef double_write_ok
+ /*
+ * Pre-process curves. When filling by trapezoids, we need to
+ * flatten the path completely; when filling by scan lines, we only
+ * need to monotonize it, unless FILL_CURVES is undefined.
+ */
+ if ( !ppath->curve_count ) /* don't need to flatten */
+ pfpath = ppath;
+ else
+#ifdef FILL_CURVES
+ if ( fill_by_trapezoids )
+ { code = gx_path_flatten_accurate(ppath, &ffpath,
+ params->flatness,
+ pis->accurate_curves);
+ if ( code < 0 )
+ return code;
+ pfpath = &ffpath;
+ }
+ else if ( gx_path_is_monotonic(ppath) )
+ pfpath = ppath;
+ else
+ { code = gx_path_monotonize(ppath, &ffpath);
+ if ( code < 0 )
+ return code;
+ pfpath = &ffpath;
+ }
+#else
+ { code = gx_path_flatten_accurate(ppath, &ffpath,
+ params->flatness,
+ pis->accurate_curves);
+ if ( code < 0 )
+ return code;
+ pfpath = &ffpath;
+ }
+#endif
+ if ( (code = add_y_list(pfpath, &lst, adjust_below, adjust_above, &ibox)) < 0 )
+ goto nope;
+ { fill_loop_proc((*fill_loop));
+
+ /* Some short-sighted compilers won't allow a conditional here.... */
+ if ( fill_by_trapezoids )
+ fill_loop = fill_loop_by_trapezoids;
+ else
+ fill_loop = fill_loop_by_scan_lines;
+ code = (*fill_loop)
+ (&lst, dev, params, pdevc, lop, &ibox,
+ adjust_left, adjust_right, adjust_below, adjust_above,
+ (max_fill_band == 0 ? no_band_mask : int2fixed(-max_fill_band)));
+ }
+nope: if ( lst.close_count != 0 )
+ unclose_path(pfpath, lst.close_count);
+ free_line_list(&lst);
+ if ( pfpath != ppath ) /* had to flatten */
+ gx_path_release(pfpath);
+#ifdef DEBUG
+ if ( gs_debug_c('f') )
+ { dputs("[f] # alloc up down horiz step slowx iter find band bstep bfill\n");
+ dprintf5(" %5ld %5ld %5ld %5ld %5ld",
+ n_fill, n_fill_alloc, n_y_up, n_y_down, n_horiz);
+ dprintf4(" %5ld %5ld %5ld %5ld",
+ n_x_step, n_slow_x, n_iter, n_find_y);
+ dprintf3(" %5ld %5ld %5ld\n",
+ n_band, n_band_step, n_band_fill);
+ dputs("[f] afill slant shall sfill\n");
+ dprintf4(" %5ld %5ld %5ld %5ld\n",
+ n_afill, n_slant, n_slant_shallow, n_sfill);
+ }
+#endif
+ return code;
+}
+
+/* Initialize the line list for a path. */
+private void
+init_line_list(ll_ptr ll, gs_memory_t *mem)
+{ ll->memory = mem;
+ ll->active_area = 0;
+ ll->next_active = ll->local_active;
+ ll->limit = ll->next_active + max_local_active;
+ ll->close_count = 0;
+ ll->y_list = 0;
+ ll->y_line = 0;
+ n_add1(n_fill);
+}
+
+/* Unlink any line_close segments added temporarily. */
+private void
+unclose_path(gx_path *ppath, int count)
+{ subpath *psub;
+ for ( psub = ppath->first_subpath; count != 0;
+ psub = (subpath *)psub->last->next
+ )
+ if ( psub->last == (segment *)&psub->closer )
+ { segment *prev = psub->closer.prev, *next = psub->closer.next;
+ prev->next = next;
+ if ( next ) next->prev = prev;
+ psub->last = prev;
+ count--;
+ }
+}
+
+/* Free the line list. */
+private void
+free_line_list(ll_ptr ll)
+{ gs_memory_t *mem = ll->memory;
+ active_line *alp;
+
+ /* Free any individually allocated active_lines. */
+ while ( (alp = ll->active_area) != 0 )
+ { active_line *next = alp->alloc_next;
+ gs_free_object(mem, alp, "active line");
+ ll->active_area = next;
+ }
+}
+
+/*
+ * Construct a Y-sorted list of segments for rasterizing a path. We assume
+ * the path is non-empty. Only include non-horizontal lines or (monotonic)
+ * curve segments where one endpoint is locally Y-minimal, and horizontal
+ * lines that might color some additional pixels.
+ */
+private int
+add_y_list(gx_path *ppath, ll_ptr ll, fixed adjust_below, fixed adjust_above,
+ const gs_fixed_rect *pbox)
+{ register segment *pseg = (segment *)ppath->first_subpath;
+ int close_count = 0;
+ /* fixed xmin = pbox->p.x; */ /* not currently used */
+ fixed ymin = pbox->p.y;
+ /* fixed xmax = pbox->q.x; */ /* not currently used */
+ fixed ymax = pbox->q.y;
+ int code;
+
+ while ( pseg )
+ { /* We know that pseg points to a subpath head (s_start). */
+ subpath *psub = (subpath *)pseg;
+ segment *plast = psub->last;
+ int dir = 2; /* hack to skip first segment */
+ int first_dir, prev_dir;
+ segment *prev;
+
+ if ( plast->type != s_line_close )
+ { /* Create a fake s_line_close */
+ line_close_segment *lp = &psub->closer;
+ segment *next = plast->next;
+ lp->next = next;
+ lp->prev = plast;
+ plast->next = (segment *)lp;
+ if ( next ) next->prev = (segment *)lp;
+ lp->type = s_line_close;
+ lp->pt = psub->pt;
+ lp->sub = psub;
+ psub->last = plast = (segment *)lp;
+ ll->close_count++;
+ }
+ while ( (prev_dir = dir, prev = pseg,
+ (pseg = pseg->next) != 0 && pseg->type != s_start)
+ )
+ { /*
+ * This element is either a line or a monotonic
+ * curve segment.
+ */
+ fixed iy = pseg->pt.y;
+ fixed py = prev->pt.y;
+ /*
+ * Segments falling entirely outside the ibox in Y
+ * are treated as though they were horizontal, *
+ * i.e., they are never put on the list.
+ */
+#define compute_dir(xo, xe, yo, ye)\
+ (ye > yo ? (ye <= ymin || yo >= ymax ? 0 : dir_up) :\
+ ye < yo ? (yo <= ymin || ye >= ymax ? 0 : dir_down) :\
+ 2)
+#define add_dir_lines(prev2, prev, this, pdir, dir)\
+ if ( pdir )\
+ { if ( (code = add_y_line(prev2, prev, pdir, ll)) < 0 ) return code; }\
+ if ( dir )\
+ { if ( (code = add_y_line(prev, this, dir, ll)) < 0 ) return code; }
+ dir = compute_dir(prev->pt.x, pseg->pt.x, py, iy);
+ if ( dir == 2 )
+ { /* Put horizontal lines on the list */
+ /* if they would color any pixels. */
+ if ( fixed2int_pixround(iy - adjust_below) <
+ fixed2int_pixround(iy + adjust_above)
+ )
+ { n_add1(n_horiz);
+ if ( (code = add_y_line(prev, pseg,
+ dir_horizontal, ll)) < 0
+ )
+ return code;
+ }
+ dir = 0;
+ }
+ if ( dir > prev_dir )
+ { add_dir_lines(prev->prev, prev, pseg, prev_dir, dir);
+ }
+ else if ( prev_dir == 2 ) /* first segment */
+ first_dir = dir;
+ if ( pseg == plast )
+ { /*
+ * We skipped the first segment of the
+ * subpath, so the last segment must receive
+ * special consideration. Note that we have
+ * `closed' all subpaths.
+ */
+ if ( first_dir > dir )
+ { add_dir_lines(prev, pseg, psub->next,
+ dir, first_dir);
+ }
+ }
+ }
+#undef compute_dir
+#undef add_dir_lines
+ }
+ return close_count;
+}
+/*
+ * Internal routine to test a segment and add it to the pending list if
+ * appropriate.
+ */
+private int
+add_y_line(const segment *prev_lp, const segment *lp, int dir, ll_ptr ll)
+{ gs_fixed_point this, prev;
+ register active_line *alp = ll->next_active;
+ fixed y_start;
+ if ( alp == ll->limit )
+ { /* Allocate separately */
+ alp = gs_alloc_struct(ll->memory, active_line,
+ &st_active_line, "active line");
+ if ( alp == 0 ) return_error(gs_error_VMerror);
+ alp->alloc_next = ll->active_area;
+ ll->active_area = alp;
+ n_add1(n_fill_alloc);
+ }
+ else
+ ll->next_active++;
+ this.x = lp->pt.x;
+ this.y = lp->pt.y;
+ prev.x = prev_lp->pt.x;
+ prev.y = prev_lp->pt.y;
+ switch ( (alp->direction = dir) )
+ {
+ case dir_up:
+ y_start = prev.y;
+ set_al_points(alp, prev, this);
+ alp->pseg = lp;
+ break;
+ case dir_down:
+ y_start = this.y;
+ set_al_points(alp, this, prev);
+ alp->pseg = prev_lp;
+ break;
+ case dir_horizontal:
+ y_start = this.y; /* = prev.y */
+ alp->start = prev;
+ alp->end = this;
+ /* Don't need to set dx or y_fast_max */
+ alp->pseg = prev_lp; /* may not need this either */
+ break;
+ }
+ /* Insert the new line in the Y ordering */
+ { register active_line *yp = ll->y_line;
+ register active_line *nyp;
+ if ( yp == 0 )
+ { alp->next = alp->prev = 0;
+ ll->y_list = alp;
+ }
+ else if ( y_start >= yp->start.y )
+ { /* Insert the new line after y_line */
+ while ( n_add1_expr(n_y_up),
+ ((nyp = yp->next) != NULL &&
+ y_start > nyp->start.y)
+ )
+ yp = nyp;
+ alp->next = nyp;
+ alp->prev = yp;
+ yp->next = alp;
+ if ( nyp ) nyp->prev = alp;
+ }
+ else
+ { /* Insert the new line before y_line */
+ while ( n_add1_expr(n_y_down),
+ ((nyp = yp->prev) != NULL &&
+ y_start < nyp->start.y)
+ )
+ yp = nyp;
+ alp->prev = nyp;
+ alp->next = yp;
+ yp->prev = alp;
+ if ( nyp ) nyp->next = alp;
+ else ll->y_list = alp;
+ }
+ }
+ ll->y_line = alp;
+ print_al("add ", alp);
+ return 0;
+}
+
+/* ---------------- Filling loop utilities ---------------- */
+
+/* Insert a newly active line in the X ordering. */
+private void near
+insert_x_new(active_line *alp, ll_ptr ll)
+{ register active_line *next;
+ register active_line *prev = &ll->x_head;
+ register fixed x = alp->start.x;
+ alp->x_current = x;
+ while ( n_add1_expr(n_x_step),
+ (next = prev->next) != 0 && x_precedes(next, alp, x)
+ )
+ prev = next;
+ alp->next = next;
+ alp->prev = prev;
+ if ( next != 0 )
+ next->prev = alp;
+ prev->next = alp;
+}
+
+/* Handle a line segment that just ended. Return true iff this was */
+/* the end of a line sequence. */
+private bool near
+end_x_line(active_line *alp)
+{ const segment *pseg = alp->pseg;
+ /*
+ * The computation of next relies on the fact that
+ * all subpaths have been closed. When we cycle
+ * around to the other end of a subpath, we must be
+ * sure not to process the start/end point twice.
+ */
+ const segment *next =
+ (alp->direction == dir_up ?
+ (/* Upward line, go forward along path. */
+ pseg->type == s_line_close ? /* end of subpath */
+ ((const line_close_segment *)pseg)->sub->next :
+ pseg->next) :
+ (/* Downward line, go backward along path. */
+ pseg->type == s_start ? /* start of subpath */
+ ((const subpath *)pseg)->last->prev :
+ pseg->prev)
+ );
+ gs_fixed_point npt;
+
+ npt.y = next->pt.y;
+ if_debug5('F', "[F]ended 0x%lx: pseg=0x%lx y=%f next=0x%lx npt.y=%f\n",
+ (ulong)alp, (ulong)pseg, fixed2float(pseg->pt.y),
+ (ulong)next, fixed2float(npt.y));
+ if ( npt.y <= pseg->pt.y )
+ { /* End of a line sequence */
+ active_line *nlp = alp->next;
+ alp->prev->next = nlp;
+ if ( nlp )
+ nlp->prev = alp->prev;
+ if_debug1('F', "[F]drop 0x%lx\n", (ulong)alp);
+ return true;
+ }
+ alp->pseg = next;
+ npt.x = next->pt.x;
+ set_al_points(alp, alp->end, npt);
+ print_al("repl", alp);
+ return false;
+}
+
+#define loop_fill_rectangle(x, y, w, h)\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop)
+#define loop_fill_rectangle_direct(x, y, w, h)\
+ (fill_direct ?\
+ (*fill_rect)(dev, x, y, w, h, cindex) :\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop))
+
+/* ---------------- Scan line filling loop ---------------- */
+
+/* Forward references */
+private void set_scan_line_points(P2(active_line *, fixed));
+
+/* Main filling loop. */
+private int
+fill_loop_by_scan_lines(ll_ptr ll, gx_device *dev,
+ const gx_fill_params *params, const gx_device_color *pdevc,
+ gs_logical_operation_t lop, const gs_fixed_rect *pbox,
+ fixed adjust_left, fixed adjust_right,
+ fixed adjust_below, fixed adjust_above, fixed band_mask)
+{ int rule = params->rule;
+ fixed fixed_flat = float2fixed(params->flatness);
+ bool fill_direct = color_writes_pure(pdevc, lop);
+ gx_color_index cindex;
+ dev_proc_fill_rectangle((*fill_rect));
+ active_line *yll = ll->y_list;
+ fixed y_limit = pbox->q.y;
+ fixed y;
+ /*
+ * The meaning of adjust_below (B) and adjust_above (A) is that
+ * the pixels that would normally be painted at coordinate Y get
+ * "smeared" to coordinates Y-B through Y+A-epsilon, inclusive.
+ * This is equivalent to saying that the pixels actually painted
+ * at coordinate Y are those contributed by scan lines Y-A+epsilon
+ * through Y+B, inclusive, or up to Y+B+epsilon, half-open.
+ * (A = B = 0 is a special case, equivalent to B = 0, A = epsilon.)
+ */
+ fixed look_below =
+ (adjust_above == fixed_0 ? fixed_0 : adjust_above - fixed_epsilon);
+ fixed look_above =
+ adjust_below + fixed_epsilon;
+ fixed look_height = look_above + look_below;
+ bool do_adjust = look_height > fixed_epsilon;
+
+ if ( yll == 0 ) /* empty list */
+ return 0;
+ if ( fill_direct )
+ cindex = pdevc->colors.pure,
+ fill_rect = dev_proc(dev, fill_rectangle);
+#define next_pixel_center(y)\
+ (fixed_pixround(y) + fixed_half)
+ y = next_pixel_center(yll->start.y) - look_below; /* first Y sample point */
+ ll->x_list = 0;
+ ll->x_head.x_current = min_fixed; /* stop backward scan */
+ while ( 1 )
+ { active_line *alp, *nlp;
+ fixed x;
+ fixed ya = y + look_height;
+
+ n_add1(n_iter);
+ /* Move newly active lines from y to x list. */
+ while ( yll != 0 && yll->start.y < ya )
+ { active_line *ynext = yll->next; /* insert smashes next/prev links */
+ if ( yll->direction == dir_horizontal )
+ { /* Ignore for now. */
+ }
+ else
+ { insert_x_new(yll, ll);
+ set_scan_line_points(yll, fixed_flat);
+ }
+ yll = ynext;
+ }
+ /* Check whether we've reached the maximum y. */
+ if ( y >= y_limit )
+ break;
+ if ( ll->x_list == 0 )
+ { /* No active lines, skip to next start */
+ if ( yll == 0 ) break; /* no lines left */
+ y = next_pixel_center(yll->start.y) - look_below;
+ continue;
+ }
+
+ /* Update active lines to y. */
+ x = min_fixed;
+ for ( alp = ll->x_list; alp != 0; alp = nlp )
+ { fixed nx;
+
+ nlp = alp->next;
+e: if ( alp->end.y <= y )
+ { if ( end_x_line(alp) )
+ continue;
+ set_scan_line_points(alp, fixed_flat);
+ goto e;
+ }
+ /* Note that if Y adjustment is in effect, */
+ /* alp->start.y might be greater than y. */
+ nx = alp->x_current =
+ (alp->start.y >= y ? alp->start.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, y) :
+ gx_curve_x_at_y(&alp->cursor, y));
+ if ( nx < x )
+ { /* Move this line backward in the list. */
+ active_line *ilp = alp;
+ while ( nx < (ilp = ilp->prev)->x_current )
+ ;
+ /* Now ilp->x_current <= nx < ilp->next->x_cur. */
+ alp->prev->next = alp->next;
+ if ( alp->next )
+ alp->next->prev = alp->prev;
+ if ( ilp->next )
+ ilp->next->prev = alp;
+ alp->next = ilp->next;
+ ilp->next = alp;
+ alp->prev = ilp;
+ continue;
+ }
+ x = nx;
+ }
+
+ /* Fill inside regions at y. */
+ { int inside = 0;
+ int x1_prev = min_int;
+
+ /* rule = -1 for winding number rule, i.e. */
+ /* we are inside if the winding number is non-zero; */
+ /* rule = 1 for even-odd rule, i.e. */
+ /* we are inside if the winding number is odd. */
+#define inside_path_p() ((inside & rule) != 0)
+ n_add1(n_band);
+ for ( alp = ll->x_list; alp != 0; alp = alp->next )
+ { /* We're outside a filled region. */
+ int x0 = fixed2int_pixround(alp->x_current -
+ adjust_left);
+
+ /*
+ * This doesn't handle lines that cross
+ * within the adjustment region, but it's a
+ * good start.
+ */
+ if ( do_adjust && alp->end.x < alp->start.x )
+ { fixed xa = (alp->end.y < ya ? alp->end.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, ya) :
+ gx_curve_x_at_y(&alp->cursor,
+ ya));
+ int x0a = fixed2int_pixround(xa -
+ adjust_left);
+
+ if ( x0a < x0 )
+ x0 = x0a;
+ }
+ for ( ; ; )
+ { /* We're inside a filled region. */
+ print_al("step", alp);
+ n_add1(n_band_step);
+ inside += alp->direction;
+ if ( !inside_path_p() )
+ break;
+ /*
+ * Since we're dealing with closed
+ * paths, the test for alp == 0
+ * shouldn't be needed, but we may have
+ * omitted lines that are to the right
+ * of the clipping region. */
+ if ( (alp = alp->next) == 0 )
+ goto out;
+ }
+#undef inside_path_p
+ /*
+ * We just went from inside to outside, so
+ * fill the region. Avoid writing pixels
+ * twice.
+ */
+
+ if ( x0 < x1_prev )
+ x0 = x1_prev;
+ { int x1 = fixed2int_rounded(alp->x_current +
+ adjust_right);
+
+ if ( do_adjust && alp->end.x > alp->start.x )
+ { fixed xa = (alp->end.y < ya ?
+ alp->end.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, ya) :
+ gx_curve_x_at_y(&alp->cursor,
+ ya));
+ int x1a = fixed2int_rounded(xa +
+ adjust_right);
+ if ( x1a > x1 )
+ x1 = x1a;
+ }
+ if ( x1 > x0 )
+ { int code =
+ loop_fill_rectangle_direct(x0,
+ fixed2int_var(y),
+ x1 - x0, 1);
+ if_debug3('F', "[F]drawing [%d:%d),%d\n",
+ x0, x1, fixed2int_var(y));
+ if ( code < 0 )
+ return code;
+ x1_prev = x1;
+ }
+ }
+ }
+out: ;
+ }
+ y += fixed_1;
+ }
+ return 0;
+}
+
+private void
+set_scan_line_points(active_line *alp, fixed fixed_flat)
+{ const segment *pseg = alp->pseg;
+ const gs_fixed_point *pp0;
+
+ if ( alp->direction < 0 )
+ { pseg =
+ (pseg->type == s_line_close ?
+ ((const line_close_segment *)pseg)->sub->next :
+ pseg->next);
+ if ( pseg->type != s_curve )
+ { alp->curve_k = -1;
+ return;
+ }
+ pp0 = &alp->end;
+ }
+ else
+ { if ( pseg->type != s_curve )
+ { alp->curve_k = -1;
+ return;
+ }
+ pp0 = &alp->start;
+ }
+#define pcseg ((const curve_segment *)pseg)
+ alp->curve_k =
+ gx_curve_log2_samples(pp0->x, pp0->y, pcseg, fixed_flat);
+ gx_curve_cursor_init(&alp->cursor, pp0->x, pp0->y, pcseg,
+ alp->curve_k);
+#undef pcseg
+}
+
+/* ---------------- Trapezoid filling loop ---------------- */
+
+/* Forward references */
+private int near fill_slant_adjust(P12(fixed, fixed, fixed, fixed, fixed,
+ fixed, fixed, fixed, const gs_fixed_rect *,
+ const gx_device_color *, gx_device *, gs_logical_operation_t));
+private void near resort_x_line(P1(active_line *));
+
+/****** PATCH ******/
+#define loop_fill_trapezoid_fixed(fx0, fw0, fy0, fx1, fw1, fh)\
+ loop_fill_trap(dev, fx0, fw0, fy0, fx1, fw1, fh, pbox, pdevc, lop)
+private int
+loop_fill_trap(gx_device *dev, fixed fx0, fixed fw0, fixed fy0,
+ fixed fx1, fixed fw1, fixed fh, const gs_fixed_rect *pbox,
+ const gx_device_color *pdevc, gs_logical_operation_t lop)
+{ fixed fy1 = fy0 + fh;
+ fixed ybot = max(fy0, pbox->p.y);
+ fixed ytop = min(fy1, pbox->q.y);
+ gs_fixed_edge left, right;
+
+ if ( ybot >= ytop )
+ return 0;
+ left.start.y = right.start.y = fy0;
+ left.end.y = right.end.y = fy1;
+ right.start.x = (left.start.x = fx0) + fw0;
+ right.end.x = (left.end.x = fx1) + fw1;
+ return (*dev_proc(dev, fill_trapezoid))
+ (dev, &left, &right, ybot, ytop, false, pdevc, lop);
+}
+/****** END PATCH ******/
+
+/* Main filling loop. Takes lines off of y_list and adds them to */
+/* x_list as needed. band_mask limits the size of each band, */
+/* by requiring that ((y1 - 1) & band_mask) == (y0 & band_mask). */
+private int
+fill_loop_by_trapezoids(ll_ptr ll, gx_device *dev,
+ const gx_fill_params *params, const gx_device_color *pdevc,
+ gs_logical_operation_t lop, const gs_fixed_rect *pbox,
+ fixed adjust_left, fixed adjust_right,
+ fixed adjust_below, fixed adjust_above, fixed band_mask)
+{ int rule = params->rule;
+ const fixed y_limit = pbox->q.y;
+ active_line *yll = ll->y_list;
+ fixed y;
+ int code;
+ bool fill_direct = color_writes_pure(pdevc, lop);
+ gx_color_index cindex;
+ dev_proc_fill_rectangle((*fill_rect));
+/*
+ * Define a faster test for
+ * fixed2int_pixround(y - below) != fixed2int_pixround(y + above)
+ * where we know
+ * 0 <= below <= _fixed_pixround_v,
+ * 0 <= above <= min(fixed_half, fixed_1 - below).
+ * Subtracting out the integer parts, this is equivalent to
+ * fixed2int_pixround(fixed_fraction(y) - below) !=
+ * fixed2int_pixround(fixed_fraction(y) + above)
+ * or to
+ * fixed2int(fixed_fraction(y) + _fixed_pixround_v - below) !=
+ * fixed2int(fixed_fraction(y) + _fixed_pixround_v + above)
+ * Letting A = _fixed_pixround_v - below and B = _fixed_pixround_v + above,
+ * we can rewrite this as
+ * fixed2int(fixed_fraction(y) + A) != fixed2int(fixed_fraction(y) + B)
+ * Because of the range constraints given above, this is true precisely when
+ * fixed_fraction(y) + A < fixed_1 && fixed_fraction(y) + B >= fixed_1
+ * or equivalently
+ * fixed_fraction(y + B) < B - A.
+ * i.e.
+ * fixed_fraction(y + _fixed_pixround_v + above) < below + above
+ */
+ fixed y_span_delta = _fixed_pixround_v + adjust_above;
+ fixed y_span_limit = adjust_below + adjust_above;
+#define adjusted_y_spans_pixel(y)\
+ fixed_fraction((y) + y_span_delta) < y_span_limit
+
+ if ( yll == 0 ) return 0; /* empty list */
+ if ( fill_direct )
+ cindex = pdevc->colors.pure,
+ fill_rect = dev_proc(dev, fill_rectangle);
+ y = yll->start.y; /* first Y value */
+ ll->x_list = 0;
+ ll->x_head.x_current = min_fixed; /* stop backward scan */
+ while ( 1 )
+ { fixed y1;
+ active_line *endp, *alp, *stopx;
+ fixed x;
+ int draw;
+
+ n_add1(n_iter);
+ /* Move newly active lines from y to x list. */
+ while ( yll != 0 && yll->start.y == y )
+ { active_line *ynext = yll->next; /* insert smashes next/prev links */
+ if ( yll->direction == dir_horizontal )
+ { /* This is a hack to make sure that */
+ /* isolated horizontal lines get stroked. */
+ int yi = fixed2int_pixround(y - adjust_below);
+ int xi, wi;
+ if ( yll->start.x <= yll->end.x )
+ xi = fixed2int_pixround(yll->start.x -
+ adjust_left),
+ wi = fixed2int_pixround(yll->end.x +
+ adjust_right) - xi;
+ else
+ xi = fixed2int_pixround(yll->end.x -
+ adjust_left),
+ wi = fixed2int_pixround(yll->start.x +
+ adjust_right) - xi;
+ code = loop_fill_rectangle_direct(xi, yi, wi, 1);
+ if ( code < 0 )
+ return code;
+ }
+ else
+ insert_x_new(yll, ll);
+ yll = ynext;
+ }
+ /* Check whether we've reached the maximum y. */
+ if ( y >= y_limit ) break;
+ if ( ll->x_list == 0 )
+ { /* No active lines, skip to next start */
+ if ( yll == 0 ) break; /* no lines left */
+ y = yll->start.y;
+ continue;
+ }
+
+ /* Find the next evaluation point. */
+ /* Start by finding the smallest y value */
+ /* at which any currently active line ends */
+ /* (or the next to-be-active line begins). */
+ y1 = (yll != 0 ? yll->start.y : y_limit);
+ /* Make sure we don't exceed the maximum band height. */
+ { fixed y_band = y | ~band_mask;
+ if ( y1 > y_band ) y1 = y_band + 1;
+ }
+ for ( alp = ll->x_list; alp != 0; alp = alp->next )
+ if ( alp->end.y < y1 ) y1 = alp->end.y;
+#ifdef DEBUG
+ if ( gs_debug_c('F') )
+ { dprintf2("[F]before loop: y=%f y1=%f:\n",
+ fixed2float(y), fixed2float(y1));
+ print_line_list(ll->x_list);
+ }
+#endif
+ /* Now look for line intersections before y1. */
+ x = min_fixed;
+#define have_pixels()\
+ (fixed_pixround(y - adjust_below) < fixed_pixround(y1 + adjust_above))
+ draw = (have_pixels() ? 1 : -1);
+ /*
+ * Loop invariants:
+ * alp = endp->next;
+ * for all lines lp from stopx up to alp,
+ * lp->x_next = al_x_at_y(lp, y1).
+ */
+ for ( alp = stopx = ll->x_list;
+ n_add1_expr(n_find_y), alp != 0;
+ endp = alp, alp = alp->next
+ )
+ { fixed nx = al_x_at_y(alp, y1);
+ fixed dx_old, dx_den;
+ /* Check for intersecting lines. */
+ if ( nx >= x )
+ x = nx;
+ else if
+ ( draw >= 0 && /* don't bother if no pixels */
+ (dx_old = alp->x_current - endp->x_current) >= 0 &&
+ (dx_den = dx_old + endp->x_next - nx) > dx_old
+ )
+ { /* Make a good guess at the intersection */
+ /* Y value using only local information. */
+ fixed dy = y1 - y, y_new;
+ if_debug3('f', "[f]cross: dy=%g, dx_old=%g, dx_new=%g\n",
+ fixed2float(dy), fixed2float(dx_old),
+ fixed2float(dx_den - dx_old));
+ /* Do the computation in single precision */
+ /* if the values are small enough. */
+ y_new =
+ ((dy | dx_old) < 1L << (size_of(fixed)*4-1) ?
+ dy * dx_old / dx_den :
+ fixed_mult_quo(dy, dx_old, dx_den))
+ + y;
+ /* The crossing value doesn't have to be */
+ /* very accurate, but it does have to be */
+ /* greater than y and less than y1. */
+ if_debug3('f', "[f]cross y=%g, y_new=%g, y1=%g\n",
+ fixed2float(y), fixed2float(y_new),
+ fixed2float(y1));
+ stopx = alp;
+ if ( y_new <= y ) y_new = y + 1;
+ if ( y_new < y1 )
+ { y1 = y_new;
+ nx = al_x_at_y(alp, y1);
+ draw = 0;
+ }
+ if ( nx > x ) x = nx;
+ }
+ alp->x_next = nx;
+ }
+ /* Recompute next_x for lines before the intersection. */
+ for ( alp = ll->x_list; alp != stopx; alp = alp->next )
+ alp->x_next = al_x_at_y(alp, y1);
+#ifdef DEBUG
+ if ( gs_debug_c('F') )
+ { dprintf1("[F]after loop: y1=%f\n", fixed2float(y1));
+ print_line_list(ll->x_list);
+ }
+#endif
+ /* Fill a multi-trapezoid band for the active lines. */
+ /* Don't bother if no pixel centers lie within the band. */
+ if ( draw > 0 || (draw == 0 && have_pixels()) )
+ {
+
+/*******************************************************************/
+/* For readability, we start indenting from the left margin again. */
+/*******************************************************************/
+
+ fixed height = y1 - y;
+ fixed xlbot, xltop; /* as of last "outside" line */
+ int inside = 0;
+ active_line *nlp;
+
+ n_add1(n_band);
+ for ( x = min_fixed, alp = ll->x_list; alp != 0; alp = nlp )
+ { fixed xbot = alp->x_current;
+ fixed xtop = alp->x_current = alp->x_next;
+#define nx xtop
+ fixed wtop;
+ int xi, xli;
+ int code;
+
+ print_al("step", alp);
+ n_add1(n_band_step);
+ nlp = alp->next;
+ /* Handle ended or out-of-order lines. After this, */
+ /* the only member of alp we use is alp->direction. */
+ if ( alp->end.y != y1 || !end_x_line(alp) )
+ { if ( nx <= x )
+ resort_x_line(alp);
+ else
+ x = nx;
+ }
+#undef nx
+ /* rule = -1 for winding number rule, i.e. */
+ /* we are inside if the winding number is non-zero; */
+ /* rule = 1 for even-odd rule, i.e. */
+ /* we are inside if the winding number is odd. */
+#define inside_path_p() ((inside & rule) != 0)
+ if ( !inside_path_p() ) /* i.e., outside */
+ { inside += alp->direction;
+ if ( inside_path_p() ) /* about to go in */
+ xlbot = xbot, xltop = xtop;
+ continue;
+ }
+ /* We're inside a region being filled. */
+ inside += alp->direction;
+ if ( inside_path_p() ) /* not about to go out */
+ continue;
+#undef inside_path_p
+ /* We just went from inside to outside, so fill the region. */
+ wtop = xtop - xltop;
+ n_add1(n_band_fill);
+ /* If lines are temporarily out of */
+ /* order, wtop might be negative. */
+ /* Patch this up now. */
+ if ( wtop < 0 )
+ { if_debug2('f', "[f]patch %g,%g\n",
+ fixed2float(xltop), fixed2float(xtop));
+ xtop = xltop += arith_rshift(wtop, 1);
+ wtop = 0;
+ }
+ if ( (adjust_left | adjust_right) != 0 )
+ { xlbot -= adjust_left; xbot += adjust_right;
+ xltop -= adjust_left; xtop += adjust_right;
+ wtop = xtop - xltop;
+ }
+ if ( (xli = fixed2int_var_pixround(xltop)) ==
+ fixed2int_var_pixround(xlbot) &&
+ (xi = fixed2int_var_pixround(xtop)) ==
+ fixed2int_var_pixround(xbot)
+ )
+ { /* Rectangle. */
+ int yi = fixed2int_pixround(y - adjust_below);
+ int wi = fixed2int_pixround(y1 + adjust_above) - yi;
+ code = loop_fill_rectangle_direct(xli, yi,
+ xi - xli, wi);
+ }
+ else if ( (adjust_below | adjust_above) != 0 )
+ { /*
+ * We want to get the effect of filling an area whose
+ * outline is formed by dragging a square of side adj2
+ * along the border of the trapezoid. This is *not*
+ * equivalent to simply expanding the corners by
+ * adjust: There are 3 cases needing different
+ * algorithms, plus rectangles as a fast special case.
+ */
+ fixed wbot = xbot - xlbot;
+ if ( xltop <= xlbot )
+ { if ( xtop >= xbot )
+ { /* Top wider than bottom. */
+ code = loop_fill_trapezoid_fixed(
+ xlbot, wbot, y - adjust_below,
+ xltop, wtop, height);
+ if ( adjusted_y_spans_pixel(y1) )
+ { if ( code < 0 ) return code;
+ n_add1(n_afill);
+ code = loop_fill_rectangle_direct(
+ xli, fixed2int_pixround(y1 - adjust_below),
+ fixed2int_var_pixround(xtop) - xli, 1);
+ }
+ }
+ else
+ { /* Slanted trapezoid. */
+ code = fill_slant_adjust(xlbot, xbot, y,
+ xltop, xtop, height, adjust_below,
+ adjust_above, pbox,
+ pdevc, dev, lop);
+ }
+ }
+ else
+ { if ( xtop <= xbot )
+ { /* Bottom wider than top. */
+ if ( adjusted_y_spans_pixel(y) )
+ { n_add1(n_afill);
+ xli = fixed2int_var_pixround(xlbot);
+ code = loop_fill_rectangle_direct(
+ xli, fixed2int_pixround(y - adjust_below),
+ fixed2int_var_pixround(xbot) - xli, 1);
+ if ( code < 0 ) return code;
+ }
+ code = loop_fill_trapezoid_fixed(
+ xlbot, wbot, y + adjust_above,
+ xltop, wtop, height);
+ }
+ else
+ { /* Slanted trapezoid. */
+ code = fill_slant_adjust(xlbot, xbot, y,
+ xltop, xtop, height, adjust_below,
+ adjust_above, pbox,
+ pdevc, dev, lop);
+ }
+ }
+ }
+ else /* No Y adjustment. */
+ code = loop_fill_trapezoid_fixed(xlbot, xbot - xlbot,
+ y, xltop, wtop, height);
+ if ( code < 0 ) return code;
+ }
+
+/**************************************************************/
+/* End of section requiring less indentation for readability. */
+/**************************************************************/
+
+ }
+ else
+ { /* Just scan for ended or out-of-order lines. */
+ active_line *nlp;
+ for ( x = min_fixed, alp = ll->x_list; alp != 0;
+ alp = nlp
+ )
+ { fixed nx = alp->x_current = alp->x_next;
+ nlp = alp->next;
+ if_debug4('F',
+ "[F]check 0x%lx,x=%g 0x%lx,x=%g\n",
+ (ulong)alp->prev, fixed2float(x),
+ (ulong)alp, fixed2float(nx));
+ if ( alp->end.y == y1 )
+ { if ( end_x_line(alp) )
+ continue;
+ }
+ if ( nx <= x )
+ resort_x_line(alp);
+ else
+ x = nx;
+ }
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('f') )
+ { int code = check_line_list(ll->x_list);
+ if ( code < 0 )
+ return code;
+ }
+#endif
+ y = y1;
+ }
+ return 0;
+}
+
+/*
+ * Handle the case of a slanted trapezoid with adjustment.
+ * To do this exactly right requires filling a central trapezoid
+ * (or rectangle) plus two horizontal almost-rectangles.
+ */
+private int near
+fill_slant_adjust(fixed xlbot, fixed xbot, fixed y,
+ fixed xltop, fixed xtop, fixed height, fixed adjust_below,
+ fixed adjust_above, const gs_fixed_rect *pbox,
+ const gx_device_color *pdevc, gx_device *dev,
+ gs_logical_operation_t lop)
+{ fixed y1 = y + height;
+ dev_proc_fill_trapezoid((*fill_trap)) =
+ dev_proc(dev, fill_trapezoid);
+ const fixed yb = y - adjust_below;
+ const fixed ya = y + adjust_above;
+ const fixed y1b = y1 - adjust_below;
+ const fixed y1a = y1 + adjust_above;
+ const gs_fixed_edge *plbot;
+ const gs_fixed_edge *prbot;
+ const gs_fixed_edge *pltop;
+ const gs_fixed_edge *prtop;
+ gs_fixed_edge vert_left, slant_left, vert_right, slant_right;
+ int code;
+
+ n_add1(n_slant);
+
+ /* Set up all the edges, even though we may not need them all. */
+
+ if ( xlbot < xltop ) /* && xbot < xtop */
+ { vert_left.start.x = vert_left.end.x = xlbot;
+ vert_left.start.y = yb, vert_left.end.y = ya;
+ vert_right.start.x = vert_right.end.x = xtop;
+ vert_right.start.y = y1b, vert_right.end.y = y1a;
+ slant_left.start.y = ya, slant_left.end.y = y1a;
+ slant_right.start.y = yb, slant_right.end.y = y1b;
+ plbot = &vert_left, prbot = &slant_right,
+ pltop = &slant_left, prtop = &vert_right;
+ }
+ else
+ { vert_left.start.x = vert_left.end.x = xltop;
+ vert_left.start.y = y1b, vert_left.end.y = y1a;
+ vert_right.start.x = vert_right.end.x = xbot;
+ vert_right.start.y = yb, vert_right.end.y = ya;
+ slant_left.start.y = yb, slant_left.end.y = y1b;
+ slant_right.start.y = ya, slant_right.end.y = y1a;
+ plbot = &slant_left, prbot = &vert_right,
+ pltop = &vert_left, prtop = &slant_right;
+ }
+ slant_left.start.x = xlbot, slant_left.end.x = xltop;
+ slant_right.start.x = xbot, slant_right.end.x = xtop;
+
+ if ( ya >= y1b )
+ { /*
+ * The upper and lower adjustment bands overlap.
+ * Since the entire entity is less than 2 pixels high
+ * in this case, we could handle it very efficiently
+ * with no more than 2 rectangle fills, but for right now
+ * we don't attempt to do this.
+ */
+ int iyb = fixed2int_var_pixround(yb);
+ int iya = fixed2int_var_pixround(ya);
+ int iy1b = fixed2int_var_pixround(y1b);
+ int iy1a = fixed2int_var_pixround(y1a);
+
+ n_add1(n_slant_shallow);
+ if ( iy1b > iyb )
+ { code = (*fill_trap)(dev, plbot, prbot,
+ yb, y1b, false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ }
+ if ( iya > iy1b )
+ { int ix = fixed2int_var_pixround(vert_left.start.x);
+ int iw = fixed2int_var_pixround(vert_right.start.x) - ix;
+ code = loop_fill_rectangle(ix, iy1b, iw, iya - iy1b);
+ if ( code < 0 )
+ return code;
+ }
+ if ( iy1a > iya )
+ code = (*fill_trap)(dev, pltop, prtop,
+ ya, y1a, false, pdevc, lop);
+ else
+ code = 0;
+ }
+ else
+ { /*
+ * Clip the trapezoid if possible. This can save a lot
+ * of work when filling paths that cross band boundaries.
+ */
+ fixed yac;
+ if ( pbox->p.y < ya )
+ { code = (*fill_trap)(dev, plbot, prbot,
+ yb, ya, false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ yac = ya;
+ }
+ else
+ yac = pbox->p.y;
+ if ( pbox->q.y > y1b )
+ { code = (*fill_trap)(dev, &slant_left, &slant_right,
+ yac, y1b, false, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ code = (*fill_trap)(dev, pltop, prtop,
+ y1b, y1a, false, pdevc, lop);
+ }
+ else
+ code = (*fill_trap)(dev, &slant_left, &slant_right,
+ yac, pbox->q.y, false, pdevc, lop);
+ }
+ return code;
+}
+
+/* Re-sort the x list by moving alp backward to its proper spot. */
+private void near
+resort_x_line(active_line *alp)
+{ active_line *prev = alp->prev;
+ active_line *next = alp->next;
+ fixed nx = alp->x_current;
+
+ prev->next = next;
+ if ( next )
+ next->prev = prev;
+ while ( !x_precedes(prev, alp, nx) )
+ { if_debug2('f', "[f]swap 0x%lx,0x%lx\n",
+ (ulong)alp, (ulong)prev);
+ next = prev, prev = prev->prev;
+ }
+ alp->next = next;
+ alp->prev = prev;
+ /* next might be null, if alp was in */
+ /* the correct spot already. */
+ if ( next )
+ next->prev = alp;
+ prev->next = alp;
+}
diff --git a/gs/src/gxfixed.h b/gs/src/gxfixed.h
new file mode 100644
index 000000000..595cda63b
--- /dev/null
+++ b/gs/src/gxfixed.h
@@ -0,0 +1,227 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfixed.h */
+/* Fixed-point arithmetic for Ghostscript */
+
+#ifndef gxfixed_INCLUDED
+# define gxfixed_INCLUDED
+
+/*
+ * Coordinates are generally represented internally by fixed-point
+ * quantities: integers lose accuracy in crucial places,
+ * and floating point arithmetic is slow.
+ */
+typedef long fixed;
+typedef ulong ufixed; /* only used in a very few places */
+#define max_fixed max_long
+#define min_fixed min_long
+#define fixed_0 0L
+#define fixed_epsilon 1L
+/*
+ * 12 bits of fraction provides both the necessary accuracy and
+ * a sufficiently large range of coordinates.
+ */
+#define _fixed_shift 12
+#define fixed_fraction_bits _fixed_shift
+#define fixed_int_bits (sizeof(fixed) * 8 - _fixed_shift)
+#define fixed_scale (1<<_fixed_shift)
+#define _fixed_rshift(x) arith_rshift(x,_fixed_shift)
+#define _fixed_round_v (fixed_scale>>1)
+#define _fixed_fraction_v (fixed_scale-1)
+/*
+ * We use a center-of-pixel filling rule; Adobe specifies that coordinates
+ * designate half-open regions. Because of this, we need special rounding
+ * to go from a coordinate to the pixel it falls in. We use the term
+ * "pixel rounding" for this kind of rounding.
+ */
+#define _fixed_pixround_v (_fixed_round_v - fixed_epsilon)
+
+/*
+ * Most operations can be done directly on fixed-point quantities:
+ * addition, subtraction, shifting, multiplication or division by
+ * (integer) constants; assignment, assignment with zero;
+ * comparison, comparison against zero.
+ * Multiplication and division by floats is OK if the result is
+ * explicitly cast back to fixed.
+ * Conversion to and from int and float types must be done explicitly.
+ * Note that if we are casting a fixed to a float in a context where
+ * only ratios and not actual values are involved, we don't need to take
+ * the scale factor into account: we can simply cast to float directly.
+ */
+#define int2fixed(i) ((fixed)(i)<<_fixed_shift)
+/* Define some useful constants. */
+/* Avoid casts, so strict ANSI compilers will accept them in #ifs. */
+#define fixed_1 (fixed_epsilon << _fixed_shift)
+#define fixed_half (fixed_1 >> 1)
+/*
+ * On 16-bit systems, we can convert fixed variables to ints more efficiently
+ * than general fixed quantities. For this reason, we define two separate
+ * sets of conversion macros.
+ */
+#define fixed2int(x) ((int)_fixed_rshift(x))
+#define fixed2int_rounded(x) ((int)_fixed_rshift((x)+_fixed_round_v))
+#define fixed2int_ceiling(x) ((int)_fixed_rshift((x)+_fixed_fraction_v))
+#define fixed_pre_pixround(x) ((x)+_fixed_pixround_v)
+#define fixed2int_pixround(x) fixed2int(fixed_pre_pixround(x))
+#define fixed_is_int(x) !((x)&_fixed_fraction_v)
+#if arch_ints_are_short & !arch_is_big_endian
+/* Do some of the shifting and extraction ourselves. */
+# define _fixed_hi(x) *((uint *)&(x)+1)
+# define _fixed_lo(x) *((uint *)&(x))
+# define fixed2int_var(x)\
+ ((int)((_fixed_hi(x) << (16-_fixed_shift)) +\
+ (_fixed_lo(x) >> _fixed_shift)))
+# define fixed2int_var_rounded(x)\
+ ((int)((_fixed_hi(x) << (16-_fixed_shift)) +\
+ (((_fixed_lo(x) >> (_fixed_shift-1))+1)>>1)))
+# define fixed2int_var_ceiling(x)\
+ (fixed2int_var(x) -\
+ arith_rshift((int)-(_fixed_lo(x) & _fixed_fraction_v), _fixed_shift))
+#else
+/* Use reasonable definitions. */
+# define fixed2int_var(x) fixed2int(x)
+# define fixed2int_var_rounded(x) fixed2int_rounded(x)
+# define fixed2int_var_ceiling(x) fixed2int_ceiling(x)
+#endif
+#define fixed2int_var_pixround(x) fixed2int_pixround(x)
+#define fixed2long(x) ((long)_fixed_rshift(x))
+#define fixed2long_rounded(x) ((long)_fixed_rshift((x)+_fixed_round_v))
+#define fixed2long_ceiling(x) ((long)_fixed_rshift((x)+_fixed_fraction_v))
+#define fixed2long_pixround(x) ((long)_fixed_rshift((x)+_fixed_pixround_v))
+#define float2fixed(f) ((fixed)((f)*(float)fixed_scale))
+/* Note that fixed2float actually produces a double result. */
+#define fixed2float(x) ((x)*(1.0/fixed_scale))
+
+/* Rounding and truncation on fixeds */
+#define fixed_floor(x) ((x)&(-1L<<_fixed_shift))
+#define fixed_rounded(x) (((x)+_fixed_round_v)&(-1L<<_fixed_shift))
+#define fixed_ceiling(x) (((x)+_fixed_fraction_v)&(-1L<<_fixed_shift))
+#define fixed_pixround(x) (((x)+_fixed_pixround_v)&(-1L<<_fixed_shift))
+#define fixed_fraction(x) ((int)(x)&_fixed_fraction_v)
+/* I don't see how to do truncation towards 0 so easily.... */
+#define fixed_truncated(x) ((x) < 0 ? fixed_ceiling(x) : fixed_floor(x))
+
+#ifdef USE_FPU
+# define USE_FPU_FIXED (USE_FPU < 0 && arch_floats_are_IEEE && arch_sizeof_long == 4)
+#else
+# define USE_FPU_FIXED 0
+#endif
+
+/*
+ * Define a procedure for computing a * b / c when b and c are non-negative,
+ * b < c, and a * b exceeds (or might exceed) the capacity of a long.
+ * It's really annoying that C doesn't provide any way to get at
+ * the double-length multiply/divide instructions that almost all hardware
+ * provides....
+ */
+
+#if USE_FPU_FIXED
+fixed fixed_mult_quo(P3(fixed A, fixed B, fixed C));
+#else
+# define fixed_mult_quo(fixed_a, fixed_b, fixed_c)\
+ ((fixed)floor((double)(fixed_a) * (fixed_b) / (fixed_c)))
+#endif
+
+/*
+ * Transforming coordinates involves multiplying two floats, or a float
+ * and a double, and then converting the result to a fixed. Since this
+ * operation is so common, we provide an alternative implementation of it
+ * on machines that use IEEE floating point representation but don't have
+ * floating point hardware. The implementation may be in either C or
+ * assembler.
+ */
+
+/*
+ * set_fmul2fixed_vars(R, FA, FB, dtemp) computes R = FA * FB:
+ * R is a fixed, FA and FB are floats (not doubles), and
+ * dtemp is a temporary double.
+ * set_dfmul2fixed_vars(R, DA, FB, dtemp) computes R = DA * FB:
+ * R is a fixed, DA is a double, FB is a float, and
+ * dtemp is a temporary double.
+ * R, FA, FB, and DA must be variables, not expressions.
+ */
+#if USE_FPU_FIXED && arch_sizeof_short == 2
+int set_fmul2fixed_(P3(fixed *, long, long));
+#define set_fmul2fixed_vars(vr,vfa,vfb,dtemp)\
+ set_fmul2fixed_(&vr, *(long *)&vfa, *(long *)&vfb)
+int set_dfmul2fixed_(P4(fixed *, ulong, long, long));
+# if arch_is_big_endian
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ set_dfmul2fixed_(&vr, ((ulong *)&vda)[1], *(long *)&vfb, *(long *)&vda)
+# else
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ set_dfmul2fixed_(&vr, *(ulong *)&vda, *(long *)&vfb, ((long *)&vda)[1])
+# endif
+#else /* don't bother */
+# define set_fmul2fixed_vars(vr,vfa,vfb,dtemp)\
+ (dtemp = (vfa) * (vfb),\
+ (f_fits_in_bits(dtemp, fixed_int_bits) ? (vr = float2fixed(dtemp), 0) :\
+ gs_note_error(gs_error_limitcheck)))
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ (dtemp = (vda) * (vfb),\
+ (f_fits_in_bits(dtemp, fixed_int_bits) ? (vr = float2fixed(dtemp), 0) :\
+ gs_note_error(gs_error_limitcheck)))
+#endif
+/*
+ * set_float2fixed_vars(R, F) does the equivalent of R = float2fixed(F):
+ * R is a fixed, F is a float or a double.
+ * set_fixed2float_var(R, V) does the equivalent of R = fixed2float(V):
+ * R is a float or a double, V is a fixed.
+ * set_ldexp_fixed2double(R, V, E) does the equivalent of R=ldexp((double)V,E):
+ * R is a double, V is a fixed, E is an int.
+ * R and F must be variables, not expressions; V and E may be expressions.
+ */
+#if USE_FPU_FIXED
+int set_float2fixed_(P3(fixed *, long, int));
+int set_double2fixed_(P4(fixed *, ulong, long, int));
+# define set_float2fixed_vars(vr,vf)\
+ (sizeof(vf) == sizeof(float) ?\
+ set_float2fixed_(&vr, *(long *)&vf, fixed_fraction_bits) :\
+ set_double2fixed_(&vr, ((ulong *)&vf)[arch_is_big_endian],\
+ ((long *)&vf)[1 - arch_is_big_endian],\
+ fixed_fraction_bits))
+long fixed2float_(P2(fixed, int));
+void set_fixed2double_(P3(double *, fixed, int));
+# define set_fixed2float_var(vf,x)\
+ (sizeof(vf) == sizeof(float) ?\
+ (*(long *)&vf = fixed2float_(x, fixed_fraction_bits), 0) :\
+ (set_fixed2double_(&vf, x, fixed_fraction_bits), 0))
+#define set_ldexp_fixed2double(vd, x, exp)\
+ set_fixed2double_(&vd, x, -(exp))
+#else
+# define set_float2fixed_vars(vr,vf)\
+ (f_fits_in_bits(vf, fixed_int_bits) ? (vr = float2fixed(vf), 0) :\
+ gs_note_error(gs_error_limitcheck))
+# define set_fixed2float_var(vf,x)\
+ (vf = fixed2float(x), 0)
+# define set_ldexp_fixed2double(vd, x, exp)\
+ discard(vd = ldexp((double)(x), exp))
+#endif
+
+/* A point with fixed coordinates */
+typedef struct gs_fixed_point_s {
+ fixed x, y;
+} gs_fixed_point;
+
+/* A rectangle with fixed coordinates */
+typedef struct gs_fixed_rect_s {
+ gs_fixed_point p, q;
+} gs_fixed_rect;
+
+#endif /* gxfixed_INCLUDED */
diff --git a/gs/src/gxfmap.h b/gs/src/gxfmap.h
new file mode 100644
index 000000000..ce7acb8c0
--- /dev/null
+++ b/gs/src/gxfmap.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfmap.h */
+/* Fraction map representation for Ghostscript */
+
+#ifndef gxfmap_INCLUDED
+# define gxfmap_INCLUDED
+
+#include "gsrefct.h"
+#include "gxfrac.h"
+#include "gxtmap.h"
+
+/*
+ * Define a cached map from fracs to fracs. Level 1 uses this only
+ * for the transfer function; level 2 also uses it for black generation
+ * and undercolor removal. Note that reference counting macros must
+ * be used to allocate, free, and assign references to gx_transfer_maps.
+ */
+/* log2... must not be greater than frac_bits, and must be least 8. */
+#define log2_transfer_map_size 8
+#define transfer_map_size (1 << log2_transfer_map_size)
+/*typedef struct gx_transfer_map_s gx_transfer_map;*/ /* in gxtmap.h */
+struct gx_transfer_map_s {
+ rc_header rc;
+ gs_mapping_proc proc; /* typedef is in gxtmap.h */
+ /* The id changes whenever the map or function changes. */
+ gs_id id;
+ frac values[transfer_map_size];
+};
+/* We export st_transfer_map for gscolor.c. */
+extern_st(st_transfer_map);
+#define public_st_transfer_map() /* in gsstate.c */\
+ gs_public_st_simple(st_transfer_map, gx_transfer_map, "gx_transfer_map")
+
+/*
+ * Map a color fraction through a transfer map. If the map is small,
+ * we interpolate; if it is large, we don't, and save a lot of time.
+ */
+#define FRAC_MAP_INTERPOLATE (log2_transfer_map_size <= 8)
+#if FRAC_MAP_INTERPOLATE
+
+frac gx_color_frac_map(P2(frac, const frac *)); /* in gxcmap.c */
+# define gx_map_color_frac(pgs,cf,m)\
+ gx_color_frac_map(cf, &pgs->m->values[0])
+
+#else /* !FRAC_MAP_INTERPOLATE */
+
+/* Do the lookup in-line. */
+# define gx_map_color_frac(pgs,cf,m)\
+ (pgs->m->values[frac2bits(cf, log2_transfer_map_size)])
+
+#endif /* (!)FRAC_MAP_INTERPOLATE */
+
+/* Map a color fraction expressed as a byte through a transfer map. */
+/* (We don't use this anywhere right now.) */
+/****************
+#if log2_transfer_map_size <= 8
+# define byte_to_tmx(b) ((b) >> (8 - log2_transfer_map_size))
+#else
+# define byte_to_tmx(b)\
+ (((b) << (log2_transfer_map_size - 8)) +\
+ ((b) >> (16 - log2_transfer_map_size)))
+#endif
+#define gx_map_color_frac_byte(pgs,b,m)\
+ (pgs->m->values[byte_to_tmx(b)])
+ ****************/
+
+/* Map a floating point value through a transfer map. */
+#define gx_map_color_float(pmap,v)\
+ ((pmap)->values[(int)((v) * transfer_map_size + 0.5)] / frac_1_float)
+
+/* Define a mapping procedure that just looks up the value in the cache. */
+/* (It is equivalent to gx_map_color_float with the arguments swapped.) */
+float gs_mapped_transfer(P2(floatp, const gx_transfer_map *));
+
+#endif /* gxfmap_INCLUDED */
diff --git a/gs/src/gxfont.h b/gs/src/gxfont.h
new file mode 100644
index 000000000..a8db6cc82
--- /dev/null
+++ b/gs/src/gxfont.h
@@ -0,0 +1,207 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfont.h */
+/* Internal font definition for Ghostscript library */
+/* Requires gsccode.h, gsmatrix.h, gxdevice.h */
+#include "gsfont.h"
+#include "gsuid.h"
+#include "gsstruct.h" /* for extern_st */
+#include "gxftype.h"
+
+/* A font object as seen by clients. */
+/* See the PostScript Language Reference Manual for details. */
+
+#ifndef gs_show_enum_DEFINED
+# define gs_show_enum_DEFINED
+typedef struct gs_show_enum_s gs_show_enum;
+#endif
+
+/*
+ * Fonts are "objects" to a limited extent, in that some of their
+ * behavior is provided by a record of procedures in the font.
+ * However, adding new types of fonts (subclasses) is not supported well.
+ */
+
+typedef struct gs_font_procs_s {
+
+ /*
+ * Define any needed procedure for initializing the composite
+ * font stack in a show enumerator. This is a no-op for
+ * all but composite fonts.
+ */
+
+#define font_proc_init_fstack(proc)\
+ int proc(P2(gs_show_enum *, gs_font *))
+ font_proc_init_fstack((*init_fstack));
+
+ /*
+ * Define the font's algorithm for getting the next character from
+ * a string being shown. This is trivial, except for composite fonts.
+ * Returns 0 if the current (base) font didn't change,
+ * 1 if it did change, 2 if there are no more characters,
+ * or an error code.
+ *
+ * This procedure is OBSOLETE as of release 4.61, superseded by
+ * next_glyph; however, we have to continue supporting it for
+ * backward compatibility.
+ */
+
+#define font_proc_next_char(proc)\
+ int proc(P2(gs_show_enum *, gs_char *))
+ font_proc_next_char((*next_char));
+
+ /* A client-supplied character encoding procedure. */
+
+#define font_proc_encode_char(proc)\
+ gs_glyph proc(P3(gs_show_enum *, gs_font *, gs_char *))
+ font_proc_encode_char((*encode_char));
+
+ /*
+ * A client-supplied BuildChar/BuildGlyph procedure.
+ * The gs_char may be gs_no_char (for BuildGlyph), or the gs_glyph
+ * may be gs_no_glyph (for BuildChar), but not both.
+ */
+
+#define font_proc_build_char(proc)\
+ int proc(P5(gs_show_enum *, gs_state *, gs_font *, gs_char, gs_glyph))
+ font_proc_build_char((*build_char));
+
+ /* Callback procedures for external font rasterizers */
+ /* (see gsccode.h for details.) */
+
+ gx_xfont_callbacks callbacks;
+ /*gs_proc_glyph_name((*glyph_name));*/
+
+ /*
+ * Define any special handling of gs_definefont.
+ * We break this out so it can be different for composite fonts.
+ */
+
+#define font_proc_define_font(proc)\
+ int proc(P2(gs_font_dir *, gs_font *))
+ font_proc_define_font((*define_font));
+
+ /*
+ * Define any special handling of gs_makefont.
+ * We break this out so it can be different for composite fonts.
+ */
+
+#define font_proc_make_font(proc)\
+ int proc(P4(gs_font_dir *, const gs_font *, const gs_matrix *,\
+ gs_font **))
+ font_proc_make_font((*make_font));
+
+ /*
+ * Define the font's algorithm for getting the next character or
+ * glyph from a string being shown. We only use this if the
+ * next_char procedure is 0 (for backward compatibility).
+ */
+
+#define font_proc_next_glyph(proc)\
+ int proc(P3(gs_show_enum *, gs_char *, gs_glyph *))
+ font_proc_next_glyph((*next_glyph));
+
+} gs_font_procs;
+/* Default font procedures */
+font_proc_init_fstack(gs_default_init_fstack);
+font_proc_next_char(gs_default_next_char);
+font_proc_encode_char(gs_no_encode_char);
+font_proc_build_char(gs_no_build_char);
+font_proc_define_font(gs_no_define_font);
+font_proc_make_font(gs_no_make_font);
+font_proc_make_font(gs_base_make_font);
+font_proc_next_glyph(gs_default_next_glyph);
+
+/* The font names are only needed for xfont lookup. */
+typedef struct gs_font_name_s {
+#define gs_font_name_max 47 /* must be >= 40 */
+ /* The +1 is so we can null-terminate for debugging printout. */
+ byte chars[gs_font_name_max+1];
+ uint size;
+} gs_font_name;
+
+/*
+ * Define a generic font. We include PaintType and StrokeWidth here because
+ * they affect rendering algorithms outside the Type 1 font machinery.
+ *
+ * ****** NOTE: If you define any subclasses of gs_font, you *must* define
+ * ****** the finalization procedure as gs_font_finalize. Finalization
+ * ****** procedures are not automatically inherited.
+ */
+#define gs_font_common\
+ gs_font *next, *prev; /* chain for original font list or */\
+ /* scaled font cache */\
+ gs_memory_t *memory; /* allocator for this font */\
+ gs_font_dir *dir; /* directory where registered */\
+ gs_font *base; /* original (unscaled) base font */\
+ void *client_data; /* additional client data */\
+ gs_matrix FontMatrix;\
+ font_type FontType;\
+ bool BitmapWidths;\
+ fbit_type ExactSize, InBetweenSize, TransformedChar;\
+ int WMode; /* 0 or 1 */\
+ int PaintType; /* PaintType for Type 1/4/42 fonts, */\
+ /* 0 for others */\
+ float StrokeWidth; /* StrokeWidth for Type 1/4/42 */\
+ /* fonts (if present), 0 for others */\
+ gs_font_procs procs;\
+ /* We store both the FontDirectory key (key_name) and, */\
+ /* if present, the FontName (font_name). */\
+ gs_font_name key_name, font_name
+/*typedef struct gs_font_s gs_font;*/ /* in gsfont.h and other places */
+struct gs_font_s {
+ gs_font_common;
+};
+extern_st(st_gs_font); /* (abstract) */
+struct_proc_finalize(gs_font_finalize); /* public for concrete subclasses */
+#define public_st_gs_font() /* in gsfont.c */\
+ gs_public_st_complex_only(st_gs_font, gs_font, "gs_font",\
+ 0, font_enum_ptrs, font_reloc_ptrs, gs_font_finalize)
+#define st_gs_font_max_ptrs 5
+#define private_st_gs_font_ptr() /* in gsfont.c */\
+ gs_private_st_ptr(st_gs_font_ptr, gs_font *, "gs_font *",\
+ font_ptr_enum_ptrs, font_ptr_reloc_ptrs)
+#define st_gs_font_ptr_max_ptrs 1
+extern_st(st_gs_font_ptr_element);
+#define public_st_gs_font_ptr_element() /* in gsfont.c */\
+ gs_public_st_element(st_gs_font_ptr_element, gs_font *, "gs_font *[]",\
+ font_ptr_element_enum_ptrs, font_ptr_element_reloc_ptrs, st_gs_font_ptr)
+
+/* Define a base (not composite) font. */
+#define gs_font_base_common\
+ gs_font_common;\
+ gs_rect FontBBox;\
+ gs_uid UID;\
+ int encoding_index; /* 0=Std, 1=ISOLatin1, 2=Symbol, */\
+ /* 3=Dingbats, -1=other */\
+ int nearest_encoding_index /* (may be >= 0 even if */\
+ /* encoding_index = -1) */
+#ifndef gs_font_base_DEFINED
+# define gs_font_base_DEFINED
+typedef struct gs_font_base_s gs_font_base;
+#endif
+struct gs_font_base_s {
+ gs_font_base_common;
+};
+extern_st(st_gs_font_base);
+#define public_st_gs_font_base() /* in gsfont.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_base, gs_font_base,\
+ "gs_font_base", font_base_enum_ptrs, font_base_reloc_ptrs,\
+ gs_font_finalize, st_gs_font, UID.xvalues)
+#define st_gs_font_base_max_ptrs (st_gs_font_max_ptrs + 1)
diff --git a/gs/src/gxfont0.h b/gs/src/gxfont0.h
new file mode 100644
index 000000000..b58f25d91
--- /dev/null
+++ b/gs/src/gxfont0.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfont0.h */
+/* Type 0 (composite) font data definition */
+
+/* Define the composite font mapping types. */
+/* These numbers must be the same as the values of FMapType */
+/* in type 0 font dictionaries. */
+typedef enum {
+ fmap_8_8 = 2,
+ fmap_escape = 3,
+ fmap_1_7 = 4,
+ fmap_9_7 = 5,
+ fmap_SubsVector = 6,
+ fmap_double_escape = 7,
+ fmap_shift = 8,
+ fmap_CMap = 9
+} fmap_type;
+#define fmap_type_min 2
+#define fmap_type_max 9
+#define fmap_type_is_modal(fmt)\
+ ((fmt) == fmap_escape || (fmt) == fmap_double_escape || (fmt) == fmap_shift)
+
+/* This is the type-specific information for a type 0 (composite) gs_font. */
+#ifndef gs_cmap_DEFINED
+# define gs_cmap_DEFINED
+typedef struct gs_cmap_s gs_cmap;
+#endif
+typedef struct gs_type0_data_s {
+ fmap_type FMapType;
+ byte EscChar, ShiftIn, ShiftOut;
+ gs_const_string SubsVector; /* fmap_SubsVector only */
+ uint subs_size; /* bytes per entry */
+ uint subs_width; /* # of entries */
+ uint *Encoding;
+ uint encoding_size;
+ gs_font **FDepVector;
+ uint fdep_size;
+ const gs_cmap *CMap; /* fmap_CMap only */
+} gs_type0_data;
+#define gs_type0_data_max_ptrs 3
+
+typedef struct gs_font_type0_s {
+ gs_font_common;
+ gs_type0_data data;
+} gs_font_type0;
+extern_st(st_gs_font_type0);
+#define public_st_gs_font_type0() /* in gsfont0.c */\
+ gs_public_st_complex_only(st_gs_font_type0, gs_font_type0, "gs_font_type0",\
+ 0, font_type0_enum_ptrs, font_type0_reloc_ptrs, gs_font_finalize)
diff --git a/gs/src/gxfont1.h b/gs/src/gxfont1.h
new file mode 100644
index 000000000..299cad3aa
--- /dev/null
+++ b/gs/src/gxfont1.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfont1.h */
+/* Type 1 font data definition (including Type 2 charstrings) */
+
+/*
+ * This is the type-specific information for an Adobe Type 1 font.
+ * It also includes the information for Type 2 charstrings, because
+ * there isn't very much of it and it's less trouble to include here.
+ */
+/*
+ * The zone_table values should be ints, according to the Adobe
+ * specification, but some fonts have arbitrary floats here.
+ */
+#define zone_table(size)\
+ struct {\
+ int count;\
+ float values[(size)*2];\
+ }
+#define float_array(size)\
+ struct {\
+ int count;\
+ float values[size];\
+ }
+#define stem_table(size)\
+ float_array(size)
+typedef struct gs_type1_data_s gs_type1_data;
+/* The garbage collector really doesn't want the client data pointer */
+/* from a gs_type1_state to point to the gs_type1_data in the middle of */
+/* a gs_font_type1, so we make the client data pointer (which is passed */
+/* to the callback procedures) point to the gs_font_type1 itself. */
+#ifndef gs_font_type1_DEFINED
+# define gs_font_type1_DEFINED
+typedef struct gs_font_type1_s gs_font_type1;
+#endif
+struct gs_type1_data_s {
+ /*int PaintType;*/ /* in gs_font_common */
+ int CharstringType; /* 1 or 2 */
+ int (*subr_proc)(P4(gs_font_type1 *, int, bool, gs_const_string *));
+ int (*seac_proc)(P3(gs_font_type1 *, int, gs_const_string *));
+ int (*push_proc)(P3(gs_font_type1 *, const fixed *, int));
+ int (*pop_proc)(P2(gs_font_type1 *, fixed *));
+ void *proc_data; /* data for subr_proc & seac_proc */
+ int lenIV; /* -1 means no encryption */
+ /* (undocumented feature!) */
+ uint subroutineNumberBias; /* added to operand of callsubr */
+ /* (undocumented feature!) */
+ /* Type 2 charstring additions */
+ uint gsubrNumberBias; /* added to operand of callgsubr */
+ long initialRandomSeed;
+ fixed defaultWidthX;
+ fixed nominalWidthX;
+ /* For a description of the following hint information, */
+ /* see chapter 5 of the "Adobe Type 1 Font Format" book. */
+ int BlueFuzz;
+ float BlueScale;
+ float BlueShift;
+#define max_BlueValues 7
+ zone_table(max_BlueValues) BlueValues;
+ float ExpansionFactor;
+ bool ForceBold;
+#define max_FamilyBlues 7
+ zone_table(max_FamilyBlues) FamilyBlues;
+#define max_FamilyOtherBlues 5
+ zone_table(max_FamilyOtherBlues) FamilyOtherBlues;
+ int LanguageGroup;
+#define max_OtherBlues 5
+ zone_table(max_OtherBlues) OtherBlues;
+ bool RndStemUp;
+ stem_table(1) StdHW;
+ stem_table(1) StdVW;
+#define max_StemSnap 12
+ stem_table(max_StemSnap) StemSnapH;
+ stem_table(max_StemSnap) StemSnapV;
+ /* Additional information for Multiple Master fonts */
+#define max_WeightVector 16
+ float_array(max_WeightVector) WeightVector;
+};
+#define gs_type1_data_s_DEFINED
+
+struct gs_font_type1_s {
+ gs_font_base_common;
+ gs_type1_data data;
+};
+extern_st(st_gs_font_type1);
+#define public_st_gs_font_type1() /* in gstype1.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_type1, gs_font_type1,\
+ "gs_font_type1", font_type1_enum_ptrs, font_type1_reloc_ptrs,\
+ gs_font_finalize, st_gs_font_base, data.proc_data)
diff --git a/gs/src/gxfont42.h b/gs/src/gxfont42.h
new file mode 100644
index 000000000..8c986ed66
--- /dev/null
+++ b/gs/src/gxfont42.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfont42.h */
+/* Type 42 font data definition */
+
+/* This is the type-specific information for a Type 42 (TrueType) font. */
+
+typedef struct gs_type42_data_s gs_type42_data;
+#ifndef gs_font_type42_DEFINED
+# define gs_font_type42_DEFINED
+typedef struct gs_font_type42_s gs_font_type42;
+#endif
+struct gs_type42_data_s {
+ /* The following are set by the client. */
+ int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **));
+ void *proc_data; /* data for procedures */
+ /* The following are initialized by ...font_init, */
+ /* but may be reset by the client. */
+ int (*get_outline)(P3(gs_font_type42 *, uint, gs_const_string *));
+ /* The following are cached values. */
+ ulong glyf; /* offset to glyf table */
+ uint unitsPerEm; /* from head */
+ uint indexToLocFormat; /* from head */
+ uint numLongMetrics; /* from hhea */
+ ulong hmtx; /* offset to hmtx table */
+ uint hmtx_length; /* length of hmtx table */
+ ulong loca; /* offset to loca table */
+};
+struct gs_font_type42_s {
+ gs_font_base_common;
+ gs_type42_data data;
+};
+extern_st(st_gs_font_type42);
+#define public_st_gs_font_type42() /* in gstype42.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_type42, gs_font_type42,\
+ "gs_font_type42", font_type42_enum_ptrs, font_type42_reloc_ptrs,\
+ gs_font_finalize, st_gs_font_base, data.proc_data)
+
+/* Because a Type 42 font contains so many cached values, */
+/* we provide a procedure to initialize them from the font data. */
+/* Note that this initializes get_outline as well. */
+int gs_type42_font_init(P1(gs_font_type42 *));
diff --git a/gs/src/gxfrac.h b/gs/src/gxfrac.h
new file mode 100644
index 000000000..de3050586
--- /dev/null
+++ b/gs/src/gxfrac.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfrac.h */
+/* Fraction representation for Ghostscript */
+
+#ifndef gxfrac_INCLUDED
+# define gxfrac_INCLUDED
+
+/*
+ * Represent a fraction in [0.0..1.0].
+ * Note that the 1.0 endpoint is included.
+ * Since undercolor removal requires a signed frac,
+ * we limit fracs to 15 bits rather than 16.
+ */
+typedef short frac;
+typedef short signed_frac;
+#define arch_log2_sizeof_frac arch_log2_sizeof_short
+#define arch_sizeof_frac arch_sizeof_short
+#define frac_bits 15
+#define frac_0 ((frac)0)
+/* The following definition of frac_1 allows exact representation of */
+/* almost all common fractions (e.g., N/360 for 0<=N<=360). */
+#define frac_1_0bits 3
+#define frac_1 ((frac)0x7ff8)
+#define frac_1_long ((long)frac_1)
+#define frac_1_float ((float)frac_1)
+/* Conversion between fracs and floats. */
+#define frac2float(fr) ((fr) / frac_1_float)
+#define float2frac(fl) ((frac)(((fl) + 0.5 / frac_1_float) * frac_1_float))
+
+/*
+ * Conversion between unsigned fracs and bytes (or, in general,
+ * shorter integers) representing fractions. This is highly dependent
+ * on the definition of frac_1 above.
+ */
+#define _frac2s(fr)\
+ (((fr) >> (frac_bits - frac_1_0bits)) + (fr))
+#define frac2bits(fr, nb)\
+ ((uint)(_frac2s(fr) >> (frac_bits - (nb))))
+#define frac2byte(fr) ((byte)frac2bits(fr, 8))
+/* bits2frac requires frac_bits / 2 <= nb <= frac_bits. */
+#define bits2frac(v, nb) ((frac)(\
+ ((frac)(v) << (frac_bits - (nb))) +\
+ ((v) >> ((nb) * 2 - frac_bits)) -\
+ ((v) >> ((nb) - frac_1_0bits)) ))
+#define byte2frac(b) bits2frac(b, 8)
+/* Produce a result that is guaranteed to convert back to a frac */
+/* not exceeding the original value fr. */
+#define frac2bits_floor(fr, nb)\
+ ((uint)((_frac2s(fr) - (_frac2s(fr) >> (nb))) >> (frac_bits - (nb))))
+/*
+ * Conversion between fracs and unsigned shorts.
+ */
+#define ushort_bits (arch_sizeof_short * 8)
+#define frac2ushort(fr) ((ushort)(\
+ ((fr) << (ushort_bits - frac_bits)) +\
+ ((fr) >> (frac_bits * 2 - ushort_bits - frac_1_0bits)) ))
+#define ushort2frac(us) ((frac)(\
+ ((us) >> (ushort_bits - frac_bits)) -\
+ ((us) >> (ushort_bits - frac_1_0bits)) ))
+/*
+ * Compute the quotient Q = floor(P / frac_1),
+ * where P is the (ulong) product of a uint or ushort V and a frac F.
+ * See gxarith.h for the underlying algorithm.
+ */
+#define frac_1_quo(p)\
+ ( (((p) >> frac_1_0bits) + ((p) >> frac_bits) + 1) >> (frac_bits - frac_1_0bits) )
+/*
+ * Compute the remainder similarly, having already computed the quotient.
+ * This is, of course, P - Q * frac_1.
+ */
+#define frac_1_rem(p, q)\
+ ((frac)( (uint)(p) - ((q) << frac_bits) + ((q) << frac_1_0bits) ))
+
+#endif /* gxfrac_INCLUDED */
diff --git a/gs/src/gxftype.h b/gs/src/gxftype.h
new file mode 100644
index 000000000..3bc3d6860
--- /dev/null
+++ b/gs/src/gxftype.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxftype.h */
+/* Definition of font type and bitmap font behavior */
+
+#ifndef gxftype_INCLUDED
+# define gxftype_INCLUDED
+
+/* Define the known font types. */
+/* These numbers must be the same as the values of FontType */
+/* in font dictionaries. */
+typedef enum {
+ ft_composite = 0,
+ ft_encrypted = 1,
+ ft_CFF = 2,
+ ft_user_defined = 3,
+ ft_disk_based = 4,
+ ft_CID_encrypted = 9,
+ ft_CID_user_defined = 10,
+ ft_CID_TrueType = 11,
+ ft_Chameleon = 14,
+ ft_bitmap = 32,
+ ft_TrueType = 42
+} font_type;
+
+/* Define the bitmap font behaviors. */
+/* These numbers must be the same as the values of the ExactSize, */
+/* InBetweenSize, and TransformedChar entries in font dictionaries. */
+typedef enum {
+ fbit_use_outlines = 0,
+ fbit_use_bitmaps = 1,
+ fbit_transform_bitmaps = 2
+} fbit_type;
+
+#endif /* gxftype_INCLUDED */
diff --git a/gs/src/gxfunc.h b/gs/src/gxfunc.h
new file mode 100644
index 000000000..cabe61a55
--- /dev/null
+++ b/gs/src/gxfunc.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxfunc.h */
+/* Internal definitions for Functions */
+
+#ifndef gxfunc_INCLUDED
+# define gxfunc_INCLUDED
+
+#include "gsfunc.h"
+#include "gsstruct.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the generic Function structure type. This is never instantiated. */
+extern_st(st_function);
+#define public_st_function() /* in gsfunc.c */\
+ gs_public_st_ptrs2(st_function, gs_function_t, "gs_function_t",\
+ function_enum_ptrs, function_reloc_ptrs, params.Domain, params.Range)
+
+/* ---------------- Internal procedures ---------------- */
+
+/* Generic free_params implementation. */
+void fn_common_free_params(P2(gs_function_params_t *params, gs_memory_t *mem));
+
+/* Generic free implementation. */
+void fn_common_free(P3(gs_function_t *pfn, bool free_params, gs_memory_t *mem));
+
+/* Free an array of subsidiary Functions. */
+void fn_free_functions(P3(gs_function_t **Functions, int count, gs_memory_t *mem));
+
+/* Check the values of m, n, Domain, and (if supplied) Range. */
+int fn_check_mnDR_proc(P3(const gs_function_params_t *params, int m, int n));
+#define fn_check_mnDR(params, m, n)\
+ do {\
+ int code = fn_check_mnDR_proc((const gs_function_params_t *)(params), m, n);\
+ if ( code < 0 ) return code;\
+ } while ( 0 )
+
+#endif /* gxfunc_INCLUDED */
diff --git a/gs/src/gxhint1.c b/gs/src/gxhint1.c
new file mode 100644
index 000000000..3a66bd168
--- /dev/null
+++ b/gs/src/gxhint1.c
@@ -0,0 +1,254 @@
+/* Copyright (C) 1990, 1992, 1993, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxhint1.c */
+/* Font level hints for Type 1 fonts */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* Define whether to use font hints. */
+/* Only set this to false for debugging the hint machinery. */
+#define USE_HINTS true
+
+/* ------ Initialization ------ */
+
+typedef zone_table(1) a_zone_table;
+typedef stem_table(1) a_stem_table;
+private void near
+ compute_snaps(P6(const gs_matrix_fixed *, const a_stem_table *,
+ stem_snap_table *, int, int, const char *));
+private alignment_zone *near
+ compute_zones(P6(const gs_matrix_fixed *, const font_hints *,
+ const a_zone_table *, const a_zone_table *, alignment_zone *, int));
+private int near
+ transform_zone(P4(const gs_matrix_fixed *, const font_hints *,
+ const float *, alignment_zone *));
+
+/* Reset the font-level hints. */
+void
+reset_font_hints(font_hints *pfh, const gs_log2_scale_point *plog2_scale)
+{ set_pixel_scale(&pfh->scale.x, plog2_scale->x);
+ set_pixel_scale(&pfh->scale.y, plog2_scale->y);
+ pfh->axes_swapped = pfh->x_inverted = pfh->y_inverted = false;
+ pfh->use_x_hints = pfh->use_y_hints = false;
+ pfh->snap_h.count = pfh->snap_v.count = 0;
+ pfh->a_zone_count = 0;
+}
+
+/* Compute the font-level hints from the font and the matrix. */
+/* We should cache this with the font/matrix pair.... */
+void
+compute_font_hints(font_hints *pfh, const gs_matrix_fixed *pmat,
+ const gs_log2_scale_point *plog2_scale, const gs_type1_data *pdata)
+{ alignment_zone *zp = &pfh->a_zones[0];
+ reset_font_hints(pfh, plog2_scale);
+ /* Figure out which hints, if any, to use, */
+ /* and the orientation of the axes. */
+ if ( is_fzero(pmat->xy) )
+ pfh->y_inverted = is_fneg(pmat->yy),
+ pfh->use_y_hints = USE_HINTS;
+ else if ( is_fzero(pmat->xx) )
+ pfh->y_inverted = is_fneg(pmat->xy),
+ pfh->axes_swapped = true,
+ pfh->use_y_hints = USE_HINTS;
+ if ( is_fzero(pmat->yx) )
+ pfh->x_inverted = is_fneg(pmat->xx),
+ pfh->use_x_hints = USE_HINTS;
+ else if ( is_fzero(pmat->yy) )
+ pfh->x_inverted = is_fneg(pmat->yx),
+ pfh->axes_swapped = true,
+ pfh->use_x_hints = USE_HINTS;
+ if_debug6('y', "[y]ctm=[%g %g %g %g %g %g]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ pmat->tx, pmat->ty);
+ if_debug7('y', "[y]scale=%d/%d, swapped=%d, x/y_hints=%d,%d, x/y_inverted=%d,%d\n",
+ 1 << plog2_scale->x, 1 << plog2_scale->y,
+ pfh->axes_swapped, pfh->use_x_hints, pfh->use_y_hints,
+ pfh->x_inverted, pfh->y_inverted);
+ /* Transform the actual hints. */
+ if ( pfh->use_x_hints )
+ { compute_snaps(pmat, (const a_stem_table *)&pdata->StdHW,
+ &pfh->snap_h, 0, pfh->axes_swapped, "h");
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StemSnapH,
+ &pfh->snap_h, 0, pfh->axes_swapped, "h");
+ }
+ if ( pfh->use_y_hints )
+ { gs_fixed_point vw;
+ fixed *vp = (pfh->axes_swapped ? &vw.x : &vw.y);
+ pixel_scale *psp =
+ (pfh->axes_swapped ? &pfh->scale.x : &pfh->scale.y);
+ /* Convert BlueFuzz to device pixels. */
+ if ( gs_distance_transform2fixed(pmat, 0.0,
+ (float)pdata->BlueFuzz,
+ &vw) < 0
+ )
+ vw.x = vw.y = fixed_0;
+ pfh->blue_fuzz = any_abs(*vp);
+ /*
+ * Decide whether to suppress overshoots. The formula in
+ * section 5.6 of the "Adobe Type 1 Font Format" says that
+ * at 300 dpi, if BlueScale = (P - 0.49) / 240, overshoot
+ * suppression turns off at point sizes at least P, i.e.:
+ * P >= BlueScale * 240 + 0.49.
+ * At 300 dpi, P = |CTM.yy| / (300/72), so the condition is
+ * equivalent to
+ * |CTM.yy| >= BlueScale * 1000 + 2.0417,
+ * or
+ * BlueScale >= (|CTM.yy| - 2.0417) / 1000.
+ * Since *pmat is the concatenation of the FontMatrix and
+ * CTM, if we assume a 1000-unit scale, this is equivalent to
+ * BlueScale >= |pmat->yy| - 0.00020417.
+ * Since the constant term is slightly smaller than
+ * fixed_epsilon, we just disregard it.
+ *
+ * According to the same section of the Adobe documentation,
+ * there is a requirement that BlueScale times the maximum
+ * alignment zone height must be less than 1. We enforced
+ * this when the font was constructed (in zfont1.c).
+ */
+ if ( gs_distance_transform2fixed(pmat, 0.0, 1.0, &vw) < 0 )
+ vw.x = vw.y = fixed_0;
+ pfh->suppress_overshoot =
+ fixed2float(any_abs(*vp) >> psp->log2_unit) <
+ pdata->BlueScale;
+ if ( gs_distance_transform2fixed(pmat, 0.0, pdata->BlueShift,
+ &vw) < 0
+ )
+ vw.x = vw.y = fixed_0;
+ pfh->blue_shift = any_abs(*vp);
+ /*
+ * Don't let the blue shift exceed half a pixel.
+ * See the discussion of BlueShift in section 5.7 of the
+ * "Adobe Type 1 Font Format" book.
+ */
+ if ( pfh->blue_shift > psp->half )
+ pfh->blue_shift = psp->half;
+ if_debug6('y', "[y]blue_fuzz=%d->%g, blue_scale=%g, blue_shift=%g->%g, sup_ov=%d\n",
+ pdata->BlueFuzz, fixed2float(pfh->blue_fuzz),
+ pdata->BlueScale,
+ pdata->BlueShift, fixed2float(pfh->blue_shift),
+ pfh->suppress_overshoot);
+ zp = compute_zones(pmat, pfh,
+ (const a_zone_table *)&pdata->BlueValues,
+ (const a_zone_table *)&pdata->FamilyBlues,
+ zp, 1);
+ zp = compute_zones(pmat, pfh,
+ (const a_zone_table *)&pdata->OtherBlues,
+ (const a_zone_table *)&pdata->FamilyOtherBlues,
+ zp, max_OtherBlues);
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StdVW,
+ &pfh->snap_v, 1, !pfh->axes_swapped, "v");
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StemSnapV,
+ &pfh->snap_v, 1, !pfh->axes_swapped, "v");
+ }
+ pfh->a_zone_count = zp - &pfh->a_zones[0];
+}
+
+/* Transform one set of stem snap widths. */
+private void near
+compute_snaps(const gs_matrix_fixed *pmat, const a_stem_table *pst,
+ stem_snap_table *psst, int from_y, int to_y, const char *tname)
+{ gs_fixed_point wxy;
+ fixed *wp = (to_y ? &wxy.y : &wxy.x);
+ int i;
+ int j = psst->count;
+ for ( i = 0; i < pst->count; i++ )
+ { float w = pst->values[i];
+ int code =
+ (from_y ?
+ gs_distance_transform2fixed(pmat, 0.0, w, &wxy) :
+ gs_distance_transform2fixed(pmat, w, 0.0, &wxy)
+ );
+ if ( code < 0 )
+ continue;
+ psst->data[j] = any_abs(*wp);
+ if_debug3('y', "[y]snap_%s[%d]=%g\n", tname, j,
+ fixed2float(psst->data[j]));
+ j++;
+ }
+ psst->count = j;
+}
+
+/* Compute the alignment zones for one set of 'blue' values. */
+private alignment_zone *near
+compute_zones(const gs_matrix_fixed *pmat, const font_hints *pfh,
+ const a_zone_table *blues, const a_zone_table *family_blues,
+ alignment_zone *zp, int bottom_count)
+{ int i;
+ fixed fuzz = pfh->blue_fuzz;
+ int inverted =
+ (pfh->axes_swapped ? pfh->x_inverted : pfh->y_inverted);
+ for ( i = 0; i < blues->count; i += 2 )
+ { const float *vp = &blues->values[i];
+ zp->is_top_zone = i >> 1 >= bottom_count;
+ if ( transform_zone(pmat, pfh, vp, zp) < 0 )
+ continue;
+ if_debug5('y', "[y]blues[%d]=%g,%g -> %g,%g\n",
+ i >> 1, vp[0], vp[1],
+ fixed2float(zp->v0), fixed2float(zp->v1));
+ if ( i < family_blues->count )
+ { /* Check whether family blues should supersede. */
+ alignment_zone fz;
+ const float *fvp = &family_blues->values[i];
+ fixed unit = (pfh->axes_swapped ?
+ pfh->scale.x.unit : pfh->scale.y.unit);
+ fixed diff;
+ if ( transform_zone(pmat, pfh, fvp, &fz) < 0 )
+ continue;
+ if_debug5('y', "[y]f_blues[%d]=%g,%g -> %g,%g\n",
+ i >> 1, fvp[0], fvp[1],
+ fixed2float(fz.v0), fixed2float(fz.v1));
+ diff = (zp->v1 - zp->v0) - (fz.v1 - fz.v0);
+ if ( diff > -unit && diff < unit )
+ zp->v0 = fz.v0, zp->v1 = fz.v1;
+ }
+ /* Compute the flat position, and add the fuzz. */
+ if ( (inverted ? zp->is_top_zone : !zp->is_top_zone) )
+ zp->flat = zp->v1, zp->v0 -= fuzz;
+ else
+ zp->flat = zp->v0, zp->v1 += fuzz;
+ zp++;
+ }
+ return zp;
+}
+
+/* Transform a single alignment zone to device coordinates, */
+/* taking axis swapping into account. */
+private int near
+transform_zone(const gs_matrix_fixed *pmat, const font_hints *pfh,
+ const float *vp, alignment_zone *zp)
+{ gs_fixed_point p0, p1;
+ fixed v0, v1;
+ int code;
+ if ( (code = gs_point_transform2fixed(pmat, 0.0, vp[0], &p0)) < 0 ||
+ (code = gs_point_transform2fixed(pmat, 0.0, vp[1], &p1)) < 0
+ )
+ return code;
+ if ( pfh->axes_swapped ) v0 = p0.x, v1 = p1.x;
+ else v0 = p0.y, v1 = p1.y;
+ if ( v0 <= v1 ) zp->v0 = v0, zp->v1 = v1;
+ else zp->v0 = v1, zp->v1 = v0;
+ return 0;
+}
diff --git a/gs/src/gxhint2.c b/gs/src/gxhint2.c
new file mode 100644
index 000000000..c3c379f5d
--- /dev/null
+++ b/gs/src/gxhint2.c
@@ -0,0 +1,402 @@
+/* Copyright (C) 1990, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxhint2.c */
+/* Character level hints for Type 1 fonts. */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* Define the tolerance for testing whether a point is in a zone, */
+/* in device pixels. (Maybe this should be variable?) */
+#define stem_tolerance float2fixed(0.05)
+
+/* Forward references */
+
+private stem_hint *near type1_stem(P3(stem_hint_table *, fixed, fixed));
+private fixed near find_snap(P3(fixed, const stem_snap_table *, const pixel_scale *));
+private alignment_zone *near find_zone(P3(gs_type1_state *, fixed, fixed));
+
+/* Reset the stem hints. */
+void
+reset_stem_hints(gs_type1_state *pcis)
+{ pcis->hstem_hints.count = pcis->hstem_hints.replaced_count = 0;
+ pcis->vstem_hints.count = pcis->vstem_hints.replaced_count = 0;
+ update_stem_hints(pcis);
+}
+
+/* Prepare to replace the stem hints. */
+private void
+save_replaced_hints(stem_hint_table *psht)
+{ int rep_count = min(psht->replaced_count + psht->count, max_stems);
+
+ memmove(&psht->data[max_stems - rep_count], &psht->data[0],
+ psht->count * sizeof(psht->data[0]));
+ psht->replaced_count = rep_count;
+ psht->count = psht->current = 0;
+}
+void
+type1_replace_stem_hints(gs_type1_state *pcis)
+{ if_debug2('y', "[y]saving hints: %d hstem, %d vstem\n",
+ pcis->hstem_hints.count, pcis->vstem_hints.count);
+ save_replaced_hints(&pcis->hstem_hints);
+ save_replaced_hints(&pcis->vstem_hints);
+ if_debug2('y', "[y]total saved hints: %d hstem, %d vstem\n",
+ pcis->hstem_hints.replaced_count,
+ pcis->vstem_hints.replaced_count);
+}
+
+/* Update the internal stem hint pointers after moving or copying the state. */
+void
+update_stem_hints(gs_type1_state *pcis)
+{ pcis->hstem_hints.current = 0;
+ pcis->vstem_hints.current = 0;
+}
+
+/* ------ Add hints ------ */
+
+#undef c_fixed
+#define c_fixed(d, c) m_fixed(d, c, pcis->fc, max_coeff_bits)
+
+#ifdef DEBUG
+private void
+print_add_stem(const char *msg, const stem_hint_table *psht,
+ const stem_hint *psh, fixed c, fixed dc, fixed v, fixed dv)
+{ if_debug10('y', "[y]%s %d/%d: %g,%g -> %g(%g)%g ; d = %g,%g\n",
+ msg, (int)(psh - &psht->data[0]), psht->count,
+ fixed2float(c), fixed2float(dc),
+ fixed2float(v), fixed2float(dv), fixed2float(v + dv),
+ fixed2float(psh->dv0), fixed2float(psh->dv1));
+}
+#else
+# define print_add_stem(msg, psht, psh, c, dc, v, dv) DO_NOTHING
+#endif
+
+/* Compute and store the adjusted stem coordinates. */
+private void
+store_stem_deltas(const stem_hint_table *psht, stem_hint *psh,
+ const pixel_scale *psp, fixed v, fixed dv, fixed adj_dv)
+{ /*
+ * We want to align the stem so its edges fall on pixel boundaries
+ * (possibly "big pixel" boundaries if we are oversampling),
+ * but if hint replacement has occurred, we must shift edges in a
+ * consistent way. This is a real nuisance, but I don't see how
+ * to avoid it; if we don't do it, we get bizarre anomalies like
+ * disappearing stems.
+ */
+ const stem_hint *psh0 = 0;
+ const stem_hint *psh1 = 0;
+ int i;
+
+ /*
+ * If we ever had a hint with the same edge(s), align this one
+ * the same way.
+ */
+ for ( i = max_stems - psht->replaced_count; i < max_stems; ++i )
+ { const stem_hint *ph = &psht->data[i];
+ if ( ph == psh )
+ continue;
+ if ( ph->v0 == psh->v0 )
+ psh0 = ph;
+ if ( ph->v1 == psh->v1 )
+ psh1 = ph;
+ }
+ for ( i = 0; i < psht->count; ++i )
+ { const stem_hint *ph = &psht->data[i];
+ if ( ph == psh )
+ continue;
+ if ( ph->v0 == psh->v0 )
+ psh0 = ph;
+ if ( ph->v1 == psh->v1 )
+ psh1 = ph;
+ }
+ if ( psh0 != 0 )
+ { psh->dv0 = psh0->dv0;
+ if ( psh1 != 0 )
+ { /* Both edges are determined. */
+ psh->dv1 = psh1->dv1;
+ }
+ else
+ { /* Only the lower edge is determined. */
+ psh->dv1 = psh->dv0 + adj_dv - dv;
+ }
+ }
+ else if ( psh1 != 0 )
+ { /* Only the upper edge is determined. */
+ psh->dv1 = psh1->dv1;
+ psh->dv0 = psh->dv1 + adj_dv - dv;
+ }
+ else
+ { /* Neither edge is determined. */
+ fixed diff2_dv = arith_rshift_1(adj_dv - dv);
+ fixed edge = v - diff2_dv;
+ fixed diff_v = scaled_rounded(edge, psp) - edge;
+
+ psh->dv0 = diff_v - diff2_dv;
+ psh->dv1 = diff_v + diff2_dv;
+ }
+}
+
+/* Add a horizontal stem hint. */
+void
+type1_do_hstem(gs_type1_state *pcis, fixed y, fixed dy,
+ const gs_matrix_fixed *pmat)
+{ stem_hint *psh;
+ alignment_zone *pz;
+ const pixel_scale *psp;
+ fixed v, dv, adj_dv;
+ fixed vtop, vbot;
+
+ if ( !pcis->fh.use_y_hints || !pmat->txy_fixed_valid )
+ return;
+ y += pcis->lsb.y + pcis->adxy.y;
+ if ( pcis->fh.axes_swapped )
+ { psp = &pcis->scale.x;
+ v = pcis->vs_offset.x + c_fixed(y, yx) + pmat->tx_fixed;
+ dv = c_fixed(dy, yx);
+ }
+ else
+ { psp = &pcis->scale.y;
+ v = pcis->vs_offset.y + c_fixed(y, yy) + pmat->ty_fixed;
+ dv = c_fixed(dy, yy);
+ }
+ if ( dy < 0 )
+ vbot = v + dv, vtop = v;
+ else
+ vbot = v, vtop = v + dv;
+ if ( dv < 0 )
+ v += dv, dv = -dv;
+ psh = type1_stem(&pcis->hstem_hints, v, dv);
+ if ( psh == 0 )
+ return;
+ adj_dv = find_snap(dv, &pcis->fh.snap_h, psp);
+ pz = find_zone(pcis, vbot, vtop);
+ if ( pz != 0 )
+ { /* Use the alignment zone to align the outer stem edge. */
+ int inverted =
+ (pcis->fh.axes_swapped ? pcis->fh.x_inverted : pcis->fh.y_inverted);
+ int adjust_v1 =
+ (inverted ? !pz->is_top_zone : pz->is_top_zone);
+ fixed flat_v = pz->flat;
+ fixed overshoot =
+ (pz->is_top_zone ? vtop - flat_v : flat_v - vbot);
+ fixed pos_over =
+ (inverted ? -overshoot : overshoot);
+ fixed ddv = adj_dv - dv;
+ fixed shift = scaled_rounded(flat_v, psp) - flat_v;
+
+ if ( pos_over > 0 )
+ {
+ if ( pos_over < pcis->fh.blue_shift || pcis->fh.suppress_overshoot )
+ { /* Character is small, suppress overshoot. */
+ if_debug0('y', "[y]suppress overshoot\n");
+ if ( pz->is_top_zone )
+ shift -= overshoot;
+ else
+ shift += overshoot;
+ }
+ else if ( pos_over < psp->unit )
+ { /* Enforce overshoot. */
+ if_debug0('y', "[y]enforce overshoot\n");
+ if ( overshoot < 0 )
+ overshoot = -psp->unit - overshoot;
+ else
+ overshoot = psp->unit - overshoot;
+ if ( pz->is_top_zone )
+ shift += overshoot;
+ else
+ shift -= overshoot;
+ }
+ }
+ if ( adjust_v1 )
+ psh->dv1 = shift, psh->dv0 = shift - ddv;
+ else
+ psh->dv0 = shift, psh->dv1 = shift + ddv;
+ if_debug2('y', "[y]flat_v = %g, overshoot = %g for:\n",
+ fixed2float(flat_v), fixed2float(overshoot));
+ }
+ else
+ { /* Align the stem so its edges fall on pixel boundaries. */
+ store_stem_deltas(&pcis->hstem_hints, psh, psp, v, dv, adj_dv);
+ }
+ print_add_stem("hstem", &pcis->hstem_hints, psh, y, dy, v, dv);
+}
+
+/* Add a vertical stem hint. */
+void
+type1_do_vstem(gs_type1_state *pcis, fixed x, fixed dx,
+ const gs_matrix_fixed *pmat)
+{ stem_hint *psh;
+ const pixel_scale *psp;
+ fixed v, dv, adj_dv;
+
+ if ( !pcis->fh.use_x_hints )
+ return;
+ x += pcis->lsb.x + pcis->adxy.x;
+ if ( pcis->fh.axes_swapped )
+ { psp = &pcis->scale.y;
+ v = pcis->vs_offset.y + c_fixed(x, xy) + pmat->ty_fixed;
+ dv = c_fixed(dx, xy);
+ }
+ else
+ { psp = &pcis->scale.x;
+ v = pcis->vs_offset.x + c_fixed(x, xx) + pmat->tx_fixed;
+ dv = c_fixed(dx, xx);
+ }
+ if ( dv < 0 )
+ v += dv, dv = -dv;
+ psh = type1_stem(&pcis->vstem_hints, v, dv);
+ if ( psh == 0 )
+ return;
+ adj_dv = find_snap(dv, &pcis->fh.snap_v, psp);
+ if ( pcis->pfont->data.ForceBold && adj_dv < psp->unit )
+ adj_dv = psp->unit;
+ /* Align the stem so its edges fall on pixel boundaries. */
+ store_stem_deltas(&pcis->vstem_hints, psh, psp, v, dv, adj_dv);
+ print_add_stem("vstem", &pcis->vstem_hints, psh, x, dx, v, dv);
+}
+
+/* Adjust the character center for a vstem3. */
+/****** NEEDS UPDATING FOR SCALE ******/
+void
+type1_do_center_vstem(gs_type1_state *pcis, fixed x0, fixed dx,
+ const gs_matrix_fixed *pmat)
+{ fixed x1 = x0 + dx;
+ gs_fixed_point pt0, pt1, width;
+ fixed center, int_width;
+ fixed *psxy;
+ if ( gs_point_transform2fixed(pmat, fixed2float(x0), 0.0, &pt0) < 0 ||
+ gs_point_transform2fixed(pmat, fixed2float(x1), 0.0, &pt1) < 0
+ )
+ { /* Punt. */
+ return;
+ }
+ width.x = pt0.x - pt1.x;
+ if ( width.x < 0 )
+ width.x = - width.x;
+ width.y = pt0.y - pt1.y;
+ if ( width.y < 0 )
+ width.y = - width.y;
+ if ( width.y < float2fixed(0.05) )
+ { /* Vertical on device */
+ center = arith_rshift_1(pt0.x + pt1.x);
+ int_width = fixed_rounded(width.x);
+ psxy = &pcis->vs_offset.x;
+ }
+ else
+ { /* Horizontal on device */
+ center = arith_rshift_1(pt0.y + pt1.y);
+ int_width = fixed_rounded(width.y);
+ psxy = &pcis->vs_offset.y;
+ }
+ if ( int_width == fixed_0 || (int_width & fixed_1) == 0 )
+ { /* Odd width, center stem over pixel. */
+ *psxy = fixed_floor(center) + fixed_half - center;
+ }
+ else
+ { /* Even width, center stem between pixels. */
+ *psxy = fixed_rounded(center) - center;
+ }
+ /* We can't fix up the current point here, */
+ /* but we can fix up everything else. */
+ /****** TO BE COMPLETED ******/
+}
+
+/* Add a stem hint, keeping the table sorted. */
+/* We know that d >= 0. */
+/* Return the stem hint pointer, or 0 if the table is full. */
+private stem_hint *near
+type1_stem(stem_hint_table *psht, fixed v0, fixed d)
+{ stem_hint *bot = &psht->data[0];
+ stem_hint *top = bot + psht->count;
+ if ( psht->count >= max_stems )
+ return 0;
+ while ( top > bot && v0 < top[-1].v0 )
+ { *top = top[-1];
+ top--;
+ }
+ /* Add a little fuzz for insideness testing. */
+ top->v0 = v0 - stem_tolerance;
+ top->v1 = v0 + d + stem_tolerance;
+ psht->count++;
+ return top;
+}
+
+/* Compute the adjusted width of a stem. */
+/* The value returned is always a multiple of scale.unit. */
+private fixed near
+find_snap(fixed dv, const stem_snap_table *psst, const pixel_scale *pps)
+{ /* We aren't sure why a maximum difference of pps->half */
+ /* works better than pps->unit, but it does. */
+#define max_snap_distance (pps->half)
+ fixed best = max_snap_distance;
+ fixed adj_dv;
+ int i;
+
+ for ( i = 0; i < psst->count; i++ )
+ { fixed diff = psst->data[i] - dv;
+
+ if ( any_abs(diff) < any_abs(best) )
+ { if_debug3('Y', "[Y]possibly snap %g to [%d]%g\n",
+ fixed2float(dv), i,
+ fixed2float(psst->data[i]));
+ best = diff;
+ }
+ }
+ adj_dv = scaled_rounded((any_abs(best) < max_snap_distance ?
+ dv + best : dv),
+ pps);
+ if ( adj_dv == 0 )
+ adj_dv = pps->unit;
+#ifdef DEBUG
+ if ( adj_dv == dv )
+ if_debug1('Y', "[Y]no snap %g\n", fixed2float(dv));
+ else
+ if_debug2('Y', "[Y]snap %g to %g\n",
+ fixed2float(dv), fixed2float(adj_dv));
+#endif
+ return adj_dv;
+#undef max_snap_distance
+}
+
+/* Find the applicable alignment zone for a stem, if any. */
+/* vbot and vtop are the bottom and top of the stem, */
+/* but without interchanging if the y axis is inverted. */
+private alignment_zone *near
+find_zone(gs_type1_state *pcis, fixed vbot, fixed vtop)
+{ alignment_zone *pz;
+ for ( pz = &pcis->fh.a_zones[pcis->fh.a_zone_count];
+ --pz >= &pcis->fh.a_zones[0];
+ )
+ { fixed v = (pz->is_top_zone ? vtop : vbot);
+ if ( v >= pz->v0 && v <= pz->v1 )
+ { if_debug2('Y', "[Y]stem crosses %s-zone %d\n",
+ (pz->is_top_zone ? "top" : "bottom"),
+ (int)(pz - &pcis->fh.a_zones[0]));
+ return pz;
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/gxhint3.c b/gs/src/gxhint3.c
new file mode 100644
index 000000000..5f486405b
--- /dev/null
+++ b/gs/src/gxhint3.c
@@ -0,0 +1,518 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxhint3.c */
+/* Apply hints for Type 1 fonts. */
+#include "math_.h" /* for floor in fixed_mult_quo */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzpath.h"
+
+/* ------ Path hints ------ */
+
+/* Forward references */
+private void
+ apply_hstem_hints(P3(gs_type1_state *, int, gs_fixed_point *)),
+ apply_vstem_hints(P3(gs_type1_state *, int, gs_fixed_point *));
+
+
+/*
+ * Apply hints along a newly added tail of a subpath.
+ * Path segments require hints as follows:
+ * Nearly vertical line: vstem hints at both ends.
+ * Nearly horizontal line: hstem hints at both ends.
+ * Curve with nearly vertical/horizontal start/end:
+ * vstem/hstem hints at start/end.
+ * We also must take care to handle the implicit closing line for
+ * subpaths that aren't explicitly closed.
+ *
+ * Note that "upper" and "lower" refer to device coordinates, which are
+ * what we use throughout the Type 1 code; however, "horizontal" and
+ * "vertical" refer to the character space coordinate system.
+ */
+#define hint_vert_lower 1
+#define hint_vert_upper 2 /* must be > lower */
+#define hint_vert (hint_vert_lower | hint_vert_upper)
+#define hint_horz_lower 4
+#define hint_horz_upper 8 /* must be > lower */
+#define hint_horz (hint_horz_lower | hint_horz_upper)
+#define nearly_axial(dmajor, dminor)\
+ ((dminor) <= (dmajor) >> 4)
+
+/* Determine which types of hints, if any, are applicable to a given */
+/* line segment. */
+private int near
+line_hints(const gs_type1_state *pcis, const gs_fixed_point *p0,
+ const gs_fixed_point *p1)
+{ fixed dx = p1->x - p0->x;
+ fixed dy = p1->y - p0->y;
+ fixed adx, ady;
+ bool xi = pcis->fh.x_inverted, yi = pcis->fh.y_inverted;
+ int hints;
+
+ /*
+ * To figure out which side of the stem we are on, we assume that
+ * the inside of the filled area is always to the left of the edge,
+ * i.e., edges moving in -X or +Y in character space are on the
+ * "upper" side of the stem, while edges moving by +X or -Y are on
+ * the "lower" side. (See section 3.5 of the Adobe Type 1 Font
+ * Format book.)
+ */
+
+ /*
+ * Map the deltas back into character space. This is essentially
+ * an inverse-distance-transform with the combined matrix,
+ * but we don't bother to undo the scaling, since it only matters
+ * for the axiality test and we don't care about situations where
+ * X and Y scaling are radically different.
+ */
+ if ( xi )
+ dx = -dx;
+ if ( yi )
+ dy = -dy;
+ if ( pcis->fh.axes_swapped )
+ { fixed t = dx; int ti = xi; dx = dy, xi = yi; dy = t, yi = ti;
+ }
+ adx = any_abs(dx);
+ ady = any_abs(dy);
+ /*
+ * Note that since upper/lower refer to device space, we must
+ * interchange them if the corresponding axis is inverted.
+ */
+ if ( dy != 0 && nearly_axial(ady, adx) )
+ { hints = (dy > 0 ? hint_vert_upper : hint_vert_lower);
+ if ( xi )
+ hints ^= (hint_vert_lower | hint_vert_upper);
+ }
+ else if ( dx != 0 && nearly_axial(adx, ady) )
+ { hints = (dx < 0 ? hint_horz_upper : hint_horz_lower);
+ if ( yi )
+ hints ^= (hint_horz_lower | hint_horz_upper);
+ }
+ else
+ hints = 0;
+ if_debug7('y', "[y]hint from 0x%lx(%g,%g) to 0x%lx(%g,%g) = %d\n",
+ (ulong)p0, fixed2float(p0->x), fixed2float(p0->y),
+ (ulong)p1, fixed2float(p1->x), fixed2float(p1->y),
+ hints);
+ return hints;
+}
+
+/* Apply hints at a point. Optionally return the amount of adjustment. */
+private void near
+apply_hints_at(gs_type1_state *pcis, int hints, gs_fixed_point *ppt,
+ gs_fixed_point *pdiff)
+{ fixed px = ppt->x, py = ppt->y;
+
+ if_debug4('y', "[y]applying hints %d to 0x%lx(%g,%g) ...\n",
+ hints, (ulong)ppt, fixed2float(px), fixed2float(py));
+ if ( (hints & hint_vert) != 0 &&
+ (pcis->vstem_hints.count & pcis->dotsection_flag) != 0
+ )
+ apply_vstem_hints(pcis, (hints & hint_vert_upper) -
+ (hints & hint_vert_lower), ppt);
+ if ( (hints & hint_horz) != 0 &&
+ (pcis->hstem_hints.count & pcis->dotsection_flag) != 0
+ )
+ apply_hstem_hints(pcis, (hints & hint_horz_upper) -
+ (hints & hint_horz_lower), ppt);
+ if ( pdiff != NULL )
+ pdiff->x = ppt->x - px,
+ pdiff->y = ppt->y - py;
+ /* Here is where we would round *ppt to the nearest quarter-pixel */
+ /* if we wanted to. */
+ if_debug2('y', "[y] ... => (%g,%g)\n",
+ fixed2float(ppt->x), fixed2float(ppt->y));
+}
+
+#ifdef DEBUG
+private void near
+add_hint_diff_proc(gs_fixed_point *ppt, fixed dx, fixed dy)
+{ if_debug7('y', "[y]adding diff (%g,%g) to 0x%lx(%g,%g) => (%g,%g)\n",
+ fixed2float(dx), fixed2float(dy), (ulong)ppt,
+ fixed2float(ppt->x), fixed2float(ppt->y),
+ fixed2float(ppt->x + dx),
+ fixed2float(ppt->y + dy));
+ ppt->x += dx;
+ ppt->y += dy;
+}
+#define add_hint_dxdy(pt, dx,dy)\
+ add_hint_diff_proc(&(pt), dx, dy)
+#else
+#define add_hint_dxdy(pt, dx, dy)\
+ (pt).x += (dx), (pt).y += (dy)
+#endif
+#define add_hint_diff(pt, diff)\
+ add_hint_dxdy(pt, (diff).x, (diff).y)
+
+/* Test whether a line is null. */
+#define line_is_null(p0, p1)\
+ (any_abs((p1).x - (p0).x) + any_abs((p1).y - (p0).y) < fixed_epsilon * 4)
+
+/*
+ * Adjust the other control points of a curve proportionately when moving
+ * one end. The Boolean argument indicates whether the point being
+ * adjusted is the one nearer the point that was moved.
+ */
+private fixed
+scale_delta(fixed diff, fixed dv, fixed lv, bool nearer)
+{ if ( dv == 0 )
+ return 0;
+ /*
+ * fixed_mult_quo requires non-negative 2nd and 3rd arguments,
+ * and also 2nd argument < 3rd argument.
+ * If it weren't for that, we would just use it directly.
+ *
+ * lv = 0 is implausible, but we have to allow for it.
+ */
+ if ( lv == 0 )
+ return (nearer ? diff : (fixed)0);
+ if ( lv < 0 )
+ lv = -lv, dv = -dv;
+ if ( dv < 0 )
+ dv = -dv, diff = -diff;
+ /*
+ * If dv > lv, there has been some kind of anomaly similar to
+ * the lv = 0 case.
+ */
+ if ( dv >= lv )
+ return (nearer ? diff : (fixed)0);
+ else
+ return fixed_mult_quo(diff, dv, lv);
+}
+private void
+adjust_curve_start(curve_segment *pcseg, const gs_fixed_point *pdiff)
+{ fixed dx = pdiff->x, dy = pdiff->y;
+ fixed end_x = pcseg->pt.x, end_y = pcseg->pt.y;
+ const segment *prev = pcseg->prev;
+ fixed lx = end_x - (prev->pt.x - dx), ly = end_y - (prev->pt.y - dy);
+
+ add_hint_dxdy(pcseg->p1,
+ scale_delta(end_x - pcseg->p1.x, dx, lx, true),
+ scale_delta(end_y - pcseg->p1.y, dy, ly, true));
+ add_hint_dxdy(pcseg->p2,
+ scale_delta(end_x - pcseg->p2.x, dx, lx, false),
+ scale_delta(end_y - pcseg->p2.y, dy, ly, false));
+}
+private void
+adjust_curve_end(curve_segment *pcseg, const gs_fixed_point *pdiff)
+{ fixed dx = pdiff->x, dy = pdiff->y;
+ const segment *prev = pcseg->prev;
+ fixed start_x = prev->pt.x, start_y = prev->pt.y;
+ fixed lx = pcseg->pt.x - dx - start_x, ly = pcseg->pt.y - dy - start_y;
+
+ add_hint_dxdy(pcseg->p1,
+ scale_delta(pcseg->p1.x - start_x, dx, lx, false),
+ scale_delta(pcseg->p1.y - start_y, dy, ly, false));
+ add_hint_dxdy(pcseg->p2,
+ scale_delta(pcseg->p2.x - start_x, dx, lx, true),
+ scale_delta(pcseg->p2.y - start_y, dy, ly, true));
+}
+
+/*
+ * Propagate a final wraparound hint back through any null line segments
+ * to a possible curve. pseg_last.pt has already been adjusted.
+ */
+private void
+apply_final_hint(segment *pseg_last, const gs_fixed_point *pdiff)
+{ segment *pseg;
+ for ( pseg = pseg_last; ; pseg = pseg->prev )
+ { segment *prev = pseg->prev;
+ switch ( pseg->type )
+ {
+ case s_curve:
+ adjust_curve_end(((curve_segment *)pseg), pdiff);
+ return;
+ case s_line:
+ case s_line_close:
+ if ( !line_is_null(prev->pt, pseg->pt) )
+ return;
+ add_hint_diff(prev->pt, *pdiff);
+ break;
+ default: /* s_start */
+ return;
+ }
+ }
+}
+
+/*
+ * Apply hints along a subpath. If closing is true, consider the subpath
+ * closed; if not, we may add more to the subpath later. In the latter case,
+ * don't do anything if the subpath is closed, because we already applied
+ * the hints.
+ */
+void
+type1_apply_path_hints(gs_type1_state *pcis, bool closing, gx_path *ppath)
+{ segment *pseg = pcis->hint_next;
+#define pseg_curve ((curve_segment *)pseg)
+ segment *pnext;
+#define pnext_curve ((curve_segment *)pnext)
+ subpath *psub = ppath->current_subpath;
+ /*
+ * hints holds the set of hints that have already been applied (if
+ * applicable) to pseg->pt, and hence should not be applied again.
+ */
+ int hints = pcis->hints_pending;
+ gs_fixed_point diff;
+
+ /*
+ * Since unknown OtherSubrs call apply_path_hints before returning
+ * to the client, and since OtherSubrs may be invoked before the
+ * [h]sbw is seen, it's possible that init_done < 0, i.e., the path
+ * and hint members of the state haven't been set up yet. In this
+ * case, we know there are no relevant hints.
+ */
+ if ( pcis->init_done < 0 )
+ return;
+ if ( pseg == 0 )
+ { /* Start at the beginning of the subpath. */
+ if ( psub == 0 )
+ return;
+ if ( psub->is_closed && !closing )
+ return;
+ pseg = (segment *)psub;
+ if ( pseg->next == 0 )
+ return;
+ hints = 0;
+ pcis->unmoved_start = psub->pt;
+ pcis->unmoved_end = psub->pt;
+ }
+ else
+ hints = pcis->hints_pending;
+ diff.x = diff.y = 0;
+ for ( ; (pnext = pseg->next) != 0; pseg = pnext )
+ { int hints_next;
+ /* Apply hints to the end of the previous segment (pseg) */
+ /* and the beginning of this one (pnext). */
+ gs_fixed_point dseg;
+
+ switch ( pnext->type )
+ {
+ case s_curve:
+ { int hints_first =
+ line_hints(pcis, &pcis->unmoved_end,
+ &pnext_curve->p1) & ~hints;
+ gs_fixed_point diff2;
+
+ if ( pseg == (segment *)psub )
+ pcis->hints_initial = hints_first;
+ if ( hints_first )
+ apply_hints_at(pcis, hints_first, &pseg->pt, &dseg);
+ else
+ dseg.x = dseg.y = 0;
+ diff2.x = pseg->pt.x - pcis->unmoved_end.x;
+ diff2.y = pseg->pt.y - pcis->unmoved_end.y;
+ hints_next = line_hints(pcis, &pnext_curve->p2,
+ &pnext->pt);
+ adjust_curve_start(pnext_curve, &diff2);
+ if ( hints_next )
+ { apply_hints_at(pcis, hints_next, &pnext_curve->p2,
+ &diff);
+ pcis->unmoved_end = pnext->pt;
+ add_hint_diff(pnext->pt, diff);
+ }
+ else
+ pcis->unmoved_end = pnext->pt;
+ } break;
+ case s_line_close:
+ /* Undo any initial hints propagated to the end. */
+ pnext->pt = pcis->unmoved_start;
+ default: /* s_line, s_line_close */
+ if ( line_is_null(pnext->pt, pcis->unmoved_end) )
+ { /* This is a null line, just move it. */
+ hints_next = hints;
+ dseg.x = dseg.y = 0; /* don't move p2 again */
+ }
+ else
+ { hints_next =
+ line_hints(pcis, &pcis->unmoved_end, &pnext->pt);
+ if ( hints_next & ~hints )
+ apply_hints_at(pcis, hints_next & ~hints,
+ &pseg->pt, &dseg);
+ else
+ dseg.x = dseg.y = 0;
+ }
+ if ( pseg == (segment *)psub )
+ pcis->hints_initial = hints_next;
+ pcis->unmoved_end = pnext->pt;
+ if ( hints_next )
+ apply_hints_at(pcis, hints_next, &pnext->pt, NULL);
+ }
+ if ( pseg->type == s_curve )
+ adjust_curve_end(pseg_curve, &dseg);
+ hints = hints_next;
+ }
+ if ( closing )
+ { /* Handle the end of the subpath wrapping around to the start. */
+ /* This is ugly, messy code that we can surely improve. */
+ fixed ctemp;
+ /* Some fonts don't use closepath when they should.... */
+ bool closed =
+ (pseg->type == s_line_close ||
+ (ctemp = pseg->pt.x - psub->pt.x,
+ any_abs(ctemp) < float2fixed(0.1)) ||
+ (ctemp = pseg->pt.y - psub->pt.y,
+ any_abs(ctemp) < float2fixed(0.1)));
+ segment *pfirst = psub->next;
+#define pfirst_curve ((curve_segment *)pfirst)
+ int hints_first = pcis->hints_initial;
+ if ( closed )
+ { /*
+ * Apply the union of the hints at both the end
+ * (pseg) and the start (psub) of the subpath. Note
+ * that we have already applied hints at the end,
+ * and hints_first at the start.
+ */
+ int do_x, do_y;
+ gs_fixed_point diff2;
+
+ if ( pcis->fh.axes_swapped )
+ do_x = hint_horz, do_y = hint_vert;
+ else
+ do_x = hint_vert, do_y = hint_horz;
+
+ { /* Apply hints_first - hints to the end. */
+ int hints_end = hints_first & ~hints;
+ diff2.x =
+ (hints_end & do_x ?
+ psub->pt.x - pcis->unmoved_start.x : 0);
+ diff2.y =
+ (hints_end & do_y ?
+ psub->pt.y - pcis->unmoved_start.y : 0);
+ }
+
+ { /* Apply hints - hints_first to the start. */
+ int hints_start = hints & ~hints_first;
+ diff.x =
+ (hints_start & do_x ?
+ pseg->pt.x - pcis->unmoved_end.x : 0);
+ diff.y =
+ (hints_start & do_y ?
+ pseg->pt.y - pcis->unmoved_end.y : 0);
+ }
+
+ add_hint_diff(pseg->pt, diff2);
+ apply_final_hint(pseg, &diff2);
+ add_hint_diff(psub->pt, diff);
+ }
+ else
+ { int hints_close =
+ line_hints(pcis, &pcis->unmoved_end,
+ &pcis->unmoved_start);
+ hints_close &= ~(hints | hints_first);
+ if ( hints_close )
+ { apply_hints_at(pcis, hints_close, &pseg->pt, &diff);
+ apply_final_hint(pseg, &diff);
+ apply_hints_at(pcis, hints_close, &psub->pt, &diff);
+ }
+ else
+ diff.x = diff.y = 0;
+ }
+ if ( pfirst->type == s_curve )
+ adjust_curve_start(pfirst_curve, &diff);
+ pcis->hint_next = 0;
+ pcis->hints_pending = 0;
+#undef pfirst_curve
+ }
+ else
+ { pcis->hint_next = pseg;
+ pcis->hints_pending = hints;
+ }
+#undef pseg_curve
+#undef pnext_curve
+}
+
+/* ------ Individual hints ------ */
+
+private const stem_hint *search_hints(P2(stem_hint_table *, fixed));
+
+/*
+ * Adjust a point according to the relevant hints.
+ * dx or dy is > 0 for the upper edge, < 0 for the lower.
+ * The caller is responsible for checking use_hstem_hints or use_vstem_hints
+ * and not calling the find_xxx_hints routine if this is false.
+ * Note that if use_x/y_hints is false, no entries ever get made
+ * in the stem hint tables, so these routines will not get called.
+ */
+
+private void
+apply_vstem_hints(gs_type1_state *pcis, int dy, gs_fixed_point *ppt)
+{ fixed *pv = (pcis->fh.axes_swapped ? &ppt->y : &ppt->x);
+ const stem_hint *ph = search_hints(&pcis->vstem_hints, *pv);
+
+ if ( ph != 0 )
+ { if_debug3('Y', "[Y]use vstem %d: %g (%s)",
+ (int)(ph - &pcis->vstem_hints.data[0]),
+ fixed2float(*pv),
+ (dy == 0 ? "?!" : dy > 0 ? "upper" : "lower"));
+#ifdef DEBUG
+ if ( dy == 0 )
+ { lprintf("dy == 0 in apply_vstem_hints!\n");
+ return;
+ }
+#endif
+ *pv += (dy > 0 ? ph->dv1 : ph->dv0);
+ if_debug1('Y', " -> %g\n", fixed2float(*pv));
+ }
+}
+
+private void
+apply_hstem_hints(gs_type1_state *pcis, int dx, gs_fixed_point *ppt)
+{ fixed *pv = (pcis->fh.axes_swapped ? &ppt->x : &ppt->y);
+ const stem_hint *ph = search_hints(&pcis->hstem_hints, *pv);
+
+ if ( ph != 0 )
+ { if_debug3('Y', "[Y]use hstem %d: %g (%s)",
+ (int)(ph - &pcis->hstem_hints.data[0]),
+ fixed2float(*pv),
+ (dx == 0 ? "?!" : dx > 0 ? "upper" : "lower"));
+#ifdef DEBUG
+ if ( dx == 0 )
+ { lprintf("dx == 0 in apply_vstem_hints!\n");
+ return;
+ }
+#endif
+ *pv += (dx > 0 ? ph->dv1 : ph->dv0);
+ if_debug1('Y', " -> %g\n", fixed2float(*pv));
+ }
+}
+
+/* Search one hint table for an adjustment. */
+private const stem_hint *
+search_hints(stem_hint_table *psht, fixed v)
+{ const stem_hint *table = &psht->data[0];
+ const stem_hint *ph = table + psht->current;
+
+ if ( v >= ph->v0 && v <= ph->v1 )
+ return ph;
+ /* We don't bother with binary or even up/down search, */
+ /* because there won't be very many hints. */
+ for ( ph = &table[psht->count]; --ph >= table; )
+ if ( v >= ph->v0 && v <= ph->v1 )
+ { psht->current = ph - table;
+ return ph;
+ }
+ return 0;
+}
diff --git a/gs/src/gxht.c b/gs/src/gxht.c
new file mode 100644
index 000000000..e843ec07d
--- /dev/null
+++ b/gs/src/gxht.c
@@ -0,0 +1,458 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxht.c */
+/* Halftone rendering routines for Ghostscript imaging library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsbitops.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxdcolor.h"
+#include "gxfixed.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gxistate.h"
+#include "gzht.h"
+
+/* Define the sizes of the halftone cache. */
+#define max_cached_tiles_HUGE 5000 /* not used */
+#define max_ht_bits_HUGE 1000000 /* not used */
+#define max_cached_tiles_LARGE 577
+#define max_ht_bits_LARGE 100000
+#define max_cached_tiles_SMALL 25
+#define max_ht_bits_SMALL 1000
+
+/* Define the binary halftone device color type. */
+private dev_color_proc_load(gx_dc_ht_binary_load);
+private dev_color_proc_fill_rectangle(gx_dc_ht_binary_fill_rectangle);
+private struct_proc_enum_ptrs(dc_ht_binary_enum_ptrs);
+private struct_proc_reloc_ptrs(dc_ht_binary_reloc_ptrs);
+const gx_device_color_procs
+ gx_dc_procs_ht_binary =
+ { gx_dc_ht_binary_load, gx_dc_ht_binary_fill_rectangle,
+ gx_dc_default_fill_masked,
+ dc_ht_binary_enum_ptrs, dc_ht_binary_reloc_ptrs
+ };
+#undef gx_dc_type_ht_binary
+const gx_device_color_procs _ds *gx_dc_type_ht_binary = &gx_dc_procs_ht_binary;
+#define gx_dc_type_ht_binary (&gx_dc_procs_ht_binary)
+/* GC procedures */
+#define cptr ((gx_device_color *)vptr)
+private ENUM_PTRS_BEGIN(dc_ht_binary_enum_ptrs) return 0;
+ ENUM_PTR(0, gx_device_color, colors.binary.b_ht);
+ case 1:
+ { gx_ht_tile *tile = cptr->colors.binary.b_tile;
+ ENUM_RETURN(tile - tile->index);
+ }
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_ht_binary_reloc_ptrs) {
+ uint index = cptr->colors.binary.b_tile->index;
+ RELOC_PTR(gx_device_color, colors.binary.b_ht);
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.binary.b_tile, index);
+} RELOC_PTRS_END
+#undef cptr
+
+/* Other GC procedures */
+private_st_ht_tiles();
+private ENUM_PTRS_BEGIN_PROC(ht_tiles_enum_ptrs) {
+ return 0;
+} ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(ht_tiles_reloc_ptrs) {
+ /* Reset the bitmap pointers in the tiles. */
+ /* We know the first tile points to the base of the bits. */
+ gx_ht_tile *ht_tiles = vptr;
+ byte *bits = ht_tiles->tiles.data;
+ uint diff;
+
+ if ( bits == 0 )
+ return;
+ bits = gs_reloc_struct_ptr(bits, gcst);
+ if ( size == size_of(gx_ht_tile) ) /* only 1 tile */
+ { ht_tiles->tiles.data = bits;
+ return;
+ }
+ diff = ht_tiles[1].tiles.data - ht_tiles[0].tiles.data;
+ for ( ; size; ht_tiles++, size -= size_of(gx_ht_tile), bits += diff )
+ { ht_tiles->tiles.data = bits;
+ }
+} RELOC_PTRS_END
+private_st_ht_cache();
+
+/* Return the default sizes of the halftone cache. */
+uint
+gx_ht_cache_default_tiles(void)
+{
+#if arch_small_memory
+ return max_cached_tiles_SMALL;
+#else
+ return (gs_if_debug_c('.') ? max_cached_tiles_SMALL :
+ max_cached_tiles_LARGE);
+#endif
+}
+uint
+gx_ht_cache_default_bits(void)
+{
+#if arch_small_memory
+ return max_ht_bits_SMALL;
+#else
+ return (gs_if_debug_c('.') ? max_ht_bits_SMALL :
+ max_ht_bits_LARGE);
+#endif
+}
+
+/* Allocate a halftone cache. */
+gx_ht_cache *
+gx_ht_alloc_cache(gs_memory_t *mem, uint max_tiles, uint max_bits)
+{ gx_ht_cache *pcache =
+ gs_alloc_struct(mem, gx_ht_cache, &st_ht_cache,
+ "alloc_ht_cache(struct)");
+ byte *tbits =
+ gs_alloc_bytes(mem, max_bits, "alloc_ht_cache(bits)");
+ gx_ht_tile *ht_tiles =
+ gs_alloc_struct_array(mem, max_tiles, gx_ht_tile, &st_ht_tiles,
+ "alloc_ht_cache(ht_tiles)");
+
+ if ( pcache == 0 || tbits == 0 || ht_tiles == 0 )
+ { gs_free_object(mem, ht_tiles, "alloc_ht_cache(ht_tiles)");
+ gs_free_object(mem, tbits, "alloc_ht_cache(bits)");
+ gs_free_object(mem, pcache, "alloc_ht_cache(struct)");
+ return 0;
+ }
+ pcache->bits = tbits;
+ pcache->bits_size = max_bits;
+ pcache->ht_tiles = ht_tiles;
+ pcache->num_tiles = max_tiles;
+ pcache->order.cache = pcache;
+ pcache->order.transfer = 0;
+ gx_ht_clear_cache(pcache);
+ return pcache;
+}
+
+/* Free a halftone cache. */
+void
+gx_ht_free_cache(gs_memory_t *mem, gx_ht_cache *pcache)
+{ gs_free_object(mem, pcache->ht_tiles, "free_ht_cache(ht_tiles)");
+ gs_free_object(mem, pcache->bits, "free_ht_cache(bits)");
+ gs_free_object(mem, pcache, "free_ht_cache(struct)");
+}
+
+/* Make the cache order current, and return whether */
+/* there is room for all possible tiles in the cache. */
+bool
+gx_check_tile_cache(const gs_imager_state *pis)
+{ const gx_ht_order *porder = &pis->dev_ht->order;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if ( pcache == 0 || pis->dev_ht == 0 )
+ return false; /* no halftone or cache */
+ if ( pcache->order.bits != porder->bits )
+ gx_ht_init_cache(pcache, porder);
+ return pcache->levels_per_tile == 1;
+}
+
+/*
+ * Determine whether a given (width, y, height) might fit into a single
+ * (non-strip) tile. If so, return the byte offset of the appropriate row
+ * from the beginning of the tile, and set *ppx to the x phase offset
+ * within the tile; if not, return -1.
+ */
+int
+gx_check_tile_size(const gs_imager_state *pis, int w, int y, int h,
+ gs_color_select_t select, int *ppx)
+{ int tsy;
+ const gx_strip_bitmap *ptile0;
+
+ if ( pis->ht_cache == 0 )
+ return -1; /* no halftone cache */
+ ptile0 = &pis->ht_cache->ht_tiles[0].tiles; /* a typical tile */
+ if ( h > ptile0->rep_height || w > ptile0->rep_width ||
+ ptile0->shift != 0
+ )
+ return -1;
+ tsy = (y + imod(-pis->screen_phase[select].y, ptile0->rep_height)) %
+ ptile0->rep_height;
+ if ( tsy + h > ptile0->size.y )
+ return -1;
+ /* Tile fits in Y, might fit in X. */
+ *ppx = imod(-pis->screen_phase[select].x, ptile0->rep_width);
+ return tsy * ptile0->raster;
+}
+
+/* Render a given level into a halftone cache. */
+private int render_ht(P4(gx_ht_tile *, int, const gx_ht_order *,
+ gx_bitmap_id));
+gx_ht_tile *
+gx_render_ht(gx_ht_cache *pcache, int b_level)
+{ const gx_ht_order *porder = &pcache->order;
+ int level = porder->levels[b_level];
+ gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
+
+ if ( bt->level != level )
+ { int code = render_ht(bt, level, porder, pcache->base_id + b_level);
+ if ( code < 0 )
+ return 0;
+ }
+ return bt;
+}
+
+/* Load the device color into the halftone cache if needed. */
+private int
+gx_dc_ht_binary_load(gx_device_color *pdevc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ const gx_ht_order *porder = &pis->dev_ht->order;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if ( pcache->order.bits != porder->bits )
+ gx_ht_init_cache(pcache, porder);
+ /* Expand gx_render_ht inline for speed. */
+ { int b_level = pdevc->colors.binary.b_level;
+ int level = porder->levels[b_level];
+ gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
+
+ if ( bt->level != level )
+ { int code = render_ht(bt, level, porder,
+ pcache->base_id + b_level);
+ if ( code < 0 )
+ return_error(gs_error_Fatal);
+ }
+ pdevc->colors.binary.b_tile = bt;
+ }
+ return 0;
+}
+
+/* Fill a rectangle with a binary halftone. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_ht_binary_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev, gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{ gx_rop_source_t no_source;
+
+ /*
+ * Observation of H-P devices and documentation yields confusing
+ * evidence about whether white pixels in halftones are always
+ * opaque. It appears that for black-and-white devices, these
+ * pixels are *not* opaque.
+ */
+ if ( dev->color_info.depth > 1 )
+ lop &= ~lop_T_transparent;
+ if ( source == NULL && lop_no_S_is_T(lop) )
+ return (*dev_proc(dev, strip_tile_rectangle))(dev,
+ &pdevc->colors.binary.b_tile->tiles,
+ x, y, w, h, pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->phase.x, pdevc->phase.y);
+ /* Adjust the logical operation per transparent colors. */
+ if ( pdevc->colors.binary.color[0] == gx_no_color_index )
+ lop = rop3_use_D_when_T_0(lop);
+ if ( pdevc->colors.binary.color[1] == gx_no_color_index )
+ lop = rop3_use_D_when_T_1(lop);
+ if ( source == NULL )
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop))(dev, source->sdata,
+ source->sourcex, source->sraster, source->id,
+ (source->use_scolors ? source->scolors : NULL),
+ &pdevc->colors.binary.b_tile->tiles,
+ pdevc->colors.binary.color,
+ x, y, w, h, pdevc->phase.x, pdevc->phase.y,
+ lop);
+}
+
+/* Initialize the tile cache for a given screen. */
+/* Cache as many different levels as will fit. */
+void
+gx_ht_init_cache(gx_ht_cache *pcache, const gx_ht_order *porder)
+{ uint width = porder->width;
+ uint height = porder->height;
+ uint size = width * height + 1;
+ int width_unit =
+ (width <= ht_mask_bits / 2 ? ht_mask_bits / width * width :
+ width);
+ int height_unit = height;
+ uint raster = porder->raster;
+ uint tile_bytes = raster * height;
+ uint shift = porder->shift;
+ int num_cached;
+ int i;
+ byte *tbits = pcache->bits;
+
+ /* Make sure num_cached is within bounds */
+ num_cached = pcache->bits_size / tile_bytes;
+ if ( num_cached > size )
+ num_cached = size;
+ if ( num_cached > pcache->num_tiles )
+ num_cached = pcache->num_tiles;
+ if ( num_cached == size &&
+ tile_bytes * num_cached <= pcache->bits_size / 2
+ )
+ { /*
+ * We can afford to replicate every tile in the cache,
+ * which will reduce breakage when tiling. Since
+ * horizontal breakage is more expensive than vertical,
+ * and since wide shallow fills are more common than
+ * narrow deep fills, we replicate the tile horizontally.
+ * We do have to be careful not to replicate the tile
+ * to an absurdly large size, however.
+ */
+ uint rep_raster =
+ ((pcache->bits_size / num_cached) / height) &
+ ~(align_bitmap_mod - 1);
+ uint rep_count = rep_raster * 8 / width;
+ /*
+ * There's no real value in replicating the tile
+ * beyond the point where the byte width of the replicated
+ * tile is a multiple of a long.
+ */
+ if ( rep_count > sizeof(ulong) * 8 )
+ rep_count = sizeof(ulong) * 8;
+ width_unit = width * rep_count;
+ raster = bitmap_raster(width_unit);
+ tile_bytes = raster * height;
+ }
+ pcache->base_id = gs_next_ids(porder->num_levels + 1);
+ pcache->order = *porder;
+ pcache->num_cached = num_cached;
+ pcache->levels_per_tile = (size + num_cached - 1) / num_cached;
+ memset(tbits, 0, pcache->bits_size);
+ for ( i = 0; i < num_cached; i++, tbits += tile_bytes )
+ { register gx_ht_tile *bt = &pcache->ht_tiles[i];
+ bt->level = 0;
+ bt->index = i;
+ bt->tiles.data = tbits;
+ bt->tiles.raster = raster;
+ bt->tiles.size.x = width_unit;
+ bt->tiles.size.y = height_unit;
+ bt->tiles.rep_width = width;
+ bt->tiles.rep_height = height;
+ bt->tiles.shift = bt->tiles.rep_shift = shift;
+ }
+}
+
+/*
+ * Compute and save the rendering of a given gray level
+ * with the current halftone. The cache holds multiple tiles,
+ * where each tile covers a range of possible levels.
+ * We adjust the tile whose range includes the desired level incrementally;
+ * this saves a lot of time for the average image, where gray levels
+ * don't change abruptly. Note that the "level" is the number of bits,
+ * not the index in the levels vector.
+ */
+private int
+render_ht(gx_ht_tile *pbt, int level /* [1..num_bits-1] */,
+ const gx_ht_order *porder, gx_bitmap_id new_id)
+{ int old_level = pbt->level;
+ register gx_ht_bit *p = &porder->bits[old_level];
+ register byte *data = pbt->tiles.data;
+
+ if_debug7('H', "[H]Halftone cache slot 0x%lx: old=%d, new=%d, w=%d(%d), h=%d(%d):\n",
+ (ulong)data, old_level, level,
+ pbt->tiles.size.x, porder->width,
+ pbt->tiles.size.y, porder->num_bits / porder->width);
+#ifdef DEBUG
+ if ( level < 0 || level > porder->num_bits )
+ { lprintf3("Error in render_ht: level=%d, old_level=%d, num_bits=%d\n", level, old_level, porder->num_bits);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ /* Invert bits between the two pointers. */
+ /* Note that we can use the same loop to turn bits either */
+ /* on or off, using xor. */
+ /* The Borland compiler generates truly dreadful code */
+ /* if we don't assign the offset to a temporary. */
+#if arch_ints_are_short
+# define invert_data(i)\
+ { uint off = p[i].offset; *(ht_mask_t *)&data[off] ^= p[i].mask; }
+#else
+# define invert_data(i) *(ht_mask_t *)&data[p[i].offset] ^= p[i].mask
+#endif
+#ifdef DEBUG
+# define invert(i)\
+ { if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
+ (int)(p + i - porder->bits), p[i].offset, p[i].mask);\
+ invert_data(i);\
+ }
+#else
+# define invert(i) invert_data(i)
+#endif
+sw: switch ( level - old_level )
+ {
+ default:
+ if ( level > old_level )
+ { invert(0); invert(1); invert(2); invert(3);
+ p += 4; old_level += 4;
+ }
+ else
+ { invert(-1); invert(-2); invert(-3); invert(-4);
+ p -= 4; old_level -= 4;
+ }
+ goto sw;
+ case 7: invert(6);
+ case 6: invert(5);
+ case 5: invert(4);
+ case 4: invert(3);
+ case 3: invert(2);
+ case 2: invert(1);
+ case 1: invert(0);
+ case 0: break; /* Shouldn't happen! */
+ case -7: invert(-7);
+ case -6: invert(-6);
+ case -5: invert(-5);
+ case -4: invert(-4);
+ case -3: invert(-3);
+ case -2: invert(-2);
+ case -1: invert(-1);
+ }
+#undef invert
+ pbt->level = level;
+ pbt->tiles.id = new_id;
+ /*
+ * Check whether we want to replicate the tile in the cache.
+ * Since we only do this when all the renderings will fit
+ * in the cache, we only do it once per level, and it doesn't
+ * have to be very efficient.
+ */
+ /****** TEST IS WRONG if width > rep_width but tile.raster ==
+ ****** order raster.
+ ******/
+ if ( pbt->tiles.raster > porder->raster )
+ bits_replicate_horizontally(data, pbt->tiles.rep_width,
+ pbt->tiles.rep_height, porder->raster,
+ pbt->tiles.size.x, pbt->tiles.raster);
+ if ( pbt->tiles.size.y > pbt->tiles.rep_height &&
+ pbt->tiles.shift == 0
+ )
+ bits_replicate_vertically(data, pbt->tiles.rep_height,
+ pbt->tiles.raster, pbt->tiles.size.y);
+#ifdef DEBUG
+if ( gs_debug_c('H') )
+ { const byte *p = pbt->tiles.data;
+ int wb = pbt->tiles.raster;
+ const byte *ptr = p + wb * pbt->tiles.size.y;
+
+ while ( p < ptr )
+ { dprintf8(" %d%d%d%d%d%d%d%d",
+ *p >> 7, (*p >> 6) & 1, (*p >> 5) & 1,
+ (*p >> 4) & 1, (*p >> 3) & 1, (*p >> 2) & 1,
+ (*p >> 1) & 1, *p & 1);
+ if ( (++p - data) % wb == 0 ) dputc('\n');
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/gs/src/gxht.h b/gs/src/gxht.h
new file mode 100644
index 000000000..46a6e230d
--- /dev/null
+++ b/gs/src/gxht.h
@@ -0,0 +1,142 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxht.h */
+/* Rest of (client) halftone definitions */
+
+#ifndef gxht_INCLUDED
+# define gxht_INCLUDED
+
+#include "gsht1.h"
+#include "gsrefct.h"
+#include "gxhttype.h"
+#include "gxtmap.h"
+
+/* Type 1 halftone. This is just a Level 1 halftone with */
+/* a few extra members. */
+typedef struct gs_spot_halftone_s {
+ gs_screen_halftone screen;
+ bool accurate_screens;
+ gs_mapping_proc transfer;
+} gs_spot_halftone;
+#define st_spot_halftone_max_ptrs st_screen_halftone_max_ptrs
+
+/* Type 3 halftone. */
+typedef struct gs_threshold_halftone_s {
+ int width;
+ int height;
+ gs_const_string thresholds;
+ gs_mapping_proc transfer;
+} gs_threshold_halftone;
+#define st_threshold_halftone_max_ptrs 1
+
+/* Define the separation "names" for a Type 5 halftone. */
+typedef enum {
+ gs_ht_separation_Default, /* must be first */
+ gs_ht_separation_Gray,
+ gs_ht_separation_Red,
+ gs_ht_separation_Green,
+ gs_ht_separation_Blue,
+ gs_ht_separation_Cyan,
+ gs_ht_separation_Magenta,
+ gs_ht_separation_Yellow,
+ gs_ht_separation_Black
+} gs_ht_separation_name;
+#define gs_ht_separation_name_strings\
+ "Default", "Gray", "Red", "Green", "Blue",\
+ "Cyan", "Magenta", "Yellow", "Black"
+
+/* Define the elements of a Type 5 halftone. */
+typedef struct gs_halftone_component_s {
+ gs_ht_separation_name cname;
+ gs_halftone_type type;
+ union {
+ gs_spot_halftone spot; /* Type 1 */
+ gs_threshold_halftone threshold; /* Type 3 */
+ } params;
+} gs_halftone_component;
+extern_st(st_halftone_component);
+#define public_st_halftone_component() /* in gsht1.c */\
+ gs_public_st_composite(st_halftone_component, gs_halftone_component,\
+ "gs_halftone_component", halftone_component_enum_ptrs,\
+ halftone_component_reloc_ptrs)
+extern_st(st_ht_component_element);
+#define public_st_ht_component_element() /* in gsht1.c */\
+ gs_public_st_element(st_ht_component_element, gs_halftone_component,\
+ "gs_halftone_component[]", ht_comp_elt_enum_ptrs, ht_comp_elt_reloc_ptrs,\
+ st_halftone_component)
+#define st_halftone_component_max_ptrs\
+ max(st_spot_halftone_max_ptrs, st_threshold_halftone_max_ptrs)
+
+/* Define the Type 5 halftone itself. */
+typedef struct gs_multiple_halftone_s {
+ gs_halftone_component *components;
+ uint num_comp;
+} gs_multiple_halftone;
+#define st_multiple_halftone_max_ptrs 1
+
+/*
+ * The halftone stored in the graphics state is the union of
+ * setscreen, setcolorscreen, Type 1, Type 3, and Type 5.
+ *
+ * NOTE: it is assumed that all subsidiary structures of halftones (the
+ * threshold array(s) for Type 3 halftones or halftone components, and the
+ * components array for Type 5 halftones) are allocated with the same
+ * allocator as the halftone structure itself.
+ */
+struct gs_halftone_s {
+ gs_halftone_type type;
+ rc_header rc;
+ union {
+ gs_screen_halftone screen; /* setscreen */
+ gs_colorscreen_halftone colorscreen; /* setcolorscreen */
+ gs_spot_halftone spot; /* Type 1 */
+ gs_threshold_halftone threshold; /* Type 3 */
+ gs_multiple_halftone multiple; /* Type 5 */
+ } params;
+};
+extern_st(st_halftone);
+#define public_st_halftone() /* in gsht.c */\
+ gs_public_st_composite(st_halftone, gs_halftone, "gs_halftone",\
+ halftone_enum_ptrs, halftone_reloc_ptrs)
+#define st_halftone_max_ptrs\
+ max(max(st_screen_halftone_max_ptrs, st_colorscreen_halftone_max_ptrs),\
+ max(max(st_spot_halftone_max_ptrs, st_threshold_halftone_max_ptrs),\
+ st_multiple_halftone_max_ptrs))
+
+/* Procedural interface for AccurateScreens */
+
+/* Set/get the default AccurateScreens value (for set[color]screen). */
+/* Note that this value is stored in a static variable. */
+void gs_setaccuratescreens(P1(bool));
+bool gs_currentaccuratescreens(P0());
+
+/* Initiate screen sampling with optional AccurateScreens. */
+int gs_screen_init_memory(P5(gs_screen_enum *, gs_state *,
+ gs_screen_halftone *, bool, gs_memory_t *));
+#define gs_screen_init_accurate(penum, pgs, phsp, accurate)\
+ gs_screen_init_memory(penum, pgs, phsp, accurate, pgs->memory)
+
+/* Procedural interface for MinScreenLevels (a Ghostscript extension) */
+
+/* Set/get the MinScreenLevels value. */
+/* Note that this value is stored in a static variable. */
+void gs_setminscreenlevels(P1(uint));
+uint gs_currentminscreenlevels(P0());
+
+#endif /* gxht_INCLUDED */
diff --git a/gs/src/gxhttile.h b/gs/src/gxhttile.h
new file mode 100644
index 000000000..8baa287aa
--- /dev/null
+++ b/gs/src/gxhttile.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxhttile.h */
+/* Halftone tile definition */
+/* Requires gxbitmap.h */
+
+#ifndef gxhttile_INCLUDED
+# define gxhttile_INCLUDED
+
+/*
+ * A halftone tile is just an ordinary bitmap tile, plus a couple of other
+ * items associated with managing its existence in a tile cache.
+ * (See gzht.h for details.) We define this in its own file so that
+ * clients of gx_device_color can access it.
+ */
+
+#ifndef gx_ht_tile_DEFINED
+# define gx_ht_tile_DEFINED
+typedef struct gx_ht_tile_s gx_ht_tile;
+#endif
+
+struct gx_ht_tile_s {
+ gx_strip_bitmap tiles; /* the currently rendered tile */
+ int level; /* the cached gray level, i.e. */
+ /* the number of spots whitened, */
+ /* or -1 if the cache is empty */
+ uint index; /* the index of the tile within */
+ /* the cache (for GC) */
+};
+
+#endif /* gxhttile_INCLUDED */
diff --git a/gs/src/gxhttype.h b/gs/src/gxhttype.h
new file mode 100644
index 000000000..54953bbfd
--- /dev/null
+++ b/gs/src/gxhttype.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxhttype.h */
+/* Client halftone type enumeration */
+
+#ifndef gxhttype_INCLUDED
+# define gxhttype_INCLUDED
+
+/* Halftone types */
+typedef enum {
+ ht_type_none, /* is this needed? */
+ ht_type_screen, /* set by setscreen */
+ ht_type_colorscreen, /* set by setcolorscreen */
+ ht_type_spot, /* Type 1 halftone dictionary */
+ ht_type_threshold, /* Type 3 halftone dictionary */
+ ht_type_multiple, /* Type 5 halftone dictionary */
+ ht_type_multiple_colorscreen /* Type 5 halftone dictionary */
+ /* created from Type 2 or Type 4 */
+ /* halftone dictionary */
+} gs_halftone_type;
+
+#endif /* gxhttype_INCLUDED */
diff --git a/gs/src/gximage.h b/gs/src/gximage.h
new file mode 100644
index 000000000..f5ad6885e
--- /dev/null
+++ b/gs/src/gximage.h
@@ -0,0 +1,275 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage.h */
+/* Internal definitions for image rendering */
+/* Requires gxcpath.h, gxdevmem.h, gxdcolor.h, gzpath.h */
+#include "gsiparam.h"
+#include "gxcspace.h"
+#include "strimpl.h" /* for siscale.h */
+#include "siscale.h"
+#include "gxdda.h"
+#include "gxsample.h"
+
+/* Define the abstract type for the image enumerator state. */
+typedef struct gx_image_enum_s gx_image_enum;
+
+/*
+ * Incoming samples may go through two different transformations:
+ *
+ * - For N-bit input samples with N <= 8, N-to-8-bit expansion
+ * may involve a lookup map. Currently this map is either an
+ * identity function or a subtraction from 1 (inversion).
+ *
+ * - The 8-bit or frac expanded sample may undergo decoding (a linear
+ * transformation) before being handed off to the color mapping
+ * machinery.
+ *
+ * If the decoding function's range is [0..1], we fold it into the
+ * expansion lookup; otherwise we must compute it separately.
+ * For speed, we distinguish 3 different cases of the decoding step:
+ */
+typedef enum {
+ sd_none, /* decoded during expansion */
+ sd_lookup, /* use lookup_decode table */
+ sd_compute /* compute using base and factor */
+} sample_decoding;
+typedef struct sample_map_s {
+
+ sample_lookup_t table;
+
+ /* If an 8-bit fraction doesn't represent the decoded value */
+ /* accurately enough, but the samples have 4 bits or fewer, */
+ /* we precompute the decoded values into a table. */
+ /* Different entries are used depending on bits/sample: */
+ /* 1,8,12 bits/sample: 0,15 */
+ /* 2 bits/sample: 0,5,10,15 */
+ /* 4 bits/sample: all */
+
+ float decode_lookup[16];
+#define decode_base decode_lookup[0]
+#define decode_max decode_lookup[15]
+
+ /* In the worst case, we have to do the decoding on the fly. */
+ /* The value is base + sample * factor, where the sample is */
+ /* an 8-bit (unsigned) integer or a frac. */
+
+ double decode_factor;
+
+ sample_decoding decoding;
+
+} sample_map;
+
+/* Decode an 8-bit sample into a floating point color component. */
+/* penum points to the gx_image_enum structure. */
+#define decode_sample(sample_value, cc, i)\
+ switch ( penum->map[i].decoding )\
+ {\
+ case sd_none:\
+ cc.paint.values[i] = (sample_value) * (1.0 / 255.0); /* faster than / */\
+ break;\
+ case sd_lookup: /* <= 4 significant bits */\
+ cc.paint.values[i] =\
+ penum->map[i].decode_lookup[(sample_value) >> 4];\
+ break;\
+ case sd_compute:\
+ cc.paint.values[i] =\
+ penum->map[i].decode_base + (sample_value) * penum->map[i].decode_factor;\
+ }
+
+/* Decode a frac value similarly. */
+#define decode_frac(frac_value, cc, i)\
+ cc.paint.values[i] =\
+ penum->map[i].decode_base + (frac_value) * penum->map[i].decode_factor
+
+/*
+ * Declare the variable that holds the 12-bit unpacking procedure
+ * if 12-bit samples are supported.
+ */
+extern sample_unpack_proc((*sample_unpack_12_proc));
+
+/*
+ * Define the interface for routines used to render a (source) scan line.
+ * If the buffer is the original client's input data, it may be unaligned;
+ * otherwise, it will always be aligned.
+ */
+#define irender_proc(proc)\
+ int proc(P6(gx_image_enum *penum, const byte *buffer, int data_x,\
+ uint w, int h, gx_device *dev))
+typedef irender_proc((*irender_proc_t));
+
+/*
+ * Define 'strategy' procedures for selecting imaging methods. Strategies
+ * are called in the order in which they are declared below, so each one may
+ * assume that all the previous ones failed. If a strategy succeeds, it may
+ * update the enumerator structure as well as returning the rendering
+ * procedure.
+ *
+ * Note that strategies are defined by procedure members of a structure, so
+ * that they may be omitted from configurations where they are not desired.
+ */
+#define image_strategy_proc(proc)\
+ irender_proc_t proc(P1(gx_image_enum *penum))
+typedef image_strategy_proc((*image_strategy_proc_t));
+typedef struct gx_image_strategies_s {
+ image_strategy_proc_t interpolate;
+ image_strategy_proc_t simple;
+ image_strategy_proc_t fracs;
+ image_strategy_proc_t mono;
+ image_strategy_proc_t color;
+} gx_image_strategies_t;
+extern gx_image_strategies_t image_strategies;
+
+/* Define the distinct postures of an image. */
+/* Each posture includes its reflected variant. */
+typedef enum {
+ image_portrait = 0, /* 0 or 180 degrees */
+ image_landscape, /* 90 or 270 degrees */
+ image_skewed /* any other transformation */
+} image_posture;
+
+/* Define an entry in the image color table. For single-source-plane */
+/* images, the table index is the sample value, and the key is not used; */
+/* for multiple-plane (color) images, the table index is a hash of the key, */
+/* which is the concatenation of the source pixel components. */
+/* "Clue" = Color LookUp Entry (by analogy with CLUT). */
+typedef struct gx_image_clue_s {
+ gx_device_color dev_color;
+ bits32 key;
+} gx_image_clue;
+
+/* Main state structure */
+
+#ifndef gx_device_rop_texture_DEFINED
+# define gx_device_rop_texture_DEFINED
+typedef struct gx_device_rop_texture_s gx_device_rop_texture;
+#endif
+
+struct gx_image_enum_s {
+ /* We really want the map structure to be long-aligned, */
+ /* so we choose shorter types for some flags. */
+ /* Following are set at structure initialization */
+ byte bps; /* bits per sample: 1, 2, 4, 8, 12 */
+ byte unpack_bps; /* bps for computing unpack proc, */
+ /* set to 8 if no unpacking */
+ byte log2_xbytes; /* log2(bytes per expanded sample): */
+ /* 0 if bps <= 8, log2(sizeof(frac)) */
+ /* if bps > 8 */
+ byte spp; /* samples per pixel: 1, 3, or 4 */
+#ifdef DPNEXT
+ /* (1, 2, 3, 4, or 5 if alpha is allowed) */
+ bool has_alpha; /* true if HasAlpha */
+#endif
+ byte num_planes; /* spp if colors are separated, */
+ /* 1 otherwise */
+ byte spread; /* num_planes << log2_xbytes */
+ byte masked; /* 0 = [color]image, 1 = imagemask */
+ byte interpolate; /* true if Interpolate requested */
+ gs_matrix matrix; /* image space -> device space */
+ struct r_ {
+ int x, y, w, h; /* subrectangle being rendered */
+ } rect;
+ gs_fixed_point x_extent, y_extent; /* extent of one row of rect */
+ sample_unpack_proc((*unpack));
+ irender_proc((*render));
+ const gs_imager_state *pis;
+ const gs_color_space *pcs; /* color space of image */
+ gs_memory_t *memory;
+ gx_device *dev;
+ byte *buffer; /* for expanding samples to a */
+ /* byte or frac */
+ uint buffer_size;
+ byte *line; /* buffer for an output scan line */
+ uint line_size;
+ uint line_width; /* width of line in device pixels */
+ image_posture posture;
+ byte use_rop; /* true if CombineWithColor requested */
+ byte clip_image; /* mask, see below */
+ /* Either we are clipping to a rectangle, in which case */
+ /* the individual x/y flags may be set, or we are clipping */
+ /* to a general region, in which case only clip_region */
+ /* is set. */
+#define image_clip_xmin 1
+#define image_clip_xmax 2
+#define image_clip_ymin 4
+#define image_clip_ymax 8
+#define image_clip_region 0x10
+ byte slow_loop; /* true if must use slower loop */
+ /* (if needed) */
+ byte device_color; /* true if device color space and */
+ /* standard decoding */
+ gs_fixed_rect clip_outer; /* outer box of clip path */
+ gs_fixed_rect clip_inner; /* inner box of clip path */
+ gs_logical_operation_t log_op; /* logical operation */
+ fixed adjust; /* adjustment when rendering */
+ /* characters */
+ fixed dxx, dxy; /* fixed versions of matrix */
+ /* components (as needed) */
+ gx_device_clip *clip_dev; /* clipping device (if needed) */
+ gx_device_rop_texture *rop_dev; /* RasterOp device (if needed) */
+ stream_IScale_state *scaler; /* scale state for */
+ /* Interpolate (if needed) */
+ /* Following are updated dynamically */
+ int y; /* next source y */
+ gs_fixed_point cur, prev; /* device x, y of current & */
+ /* previous row */
+ struct dd_ {
+ gx_dda_fixed_point row; /* DDA for row origin, has been */
+ /* advanced when render proc called */
+ gx_dda_fixed_point pixel0; /* DDA for first pixel of row */
+ } dda;
+ int line_xy; /* x or y value at start of buffered line */
+ int xi_next; /* expected xci of next row */
+ /* (landscape only) */
+ gs_int_point xyi; /* integer origin of row */
+ /* (Interpolate only) */
+ int yci, hci; /* integer y & h of row (portrait) */
+ int xci, wci; /* integer x & w of row (landscape) */
+ /* The maps are set at initialization. We put them here */
+ /* so that the scalars will have smaller offsets. */
+#ifdef DPNEXT
+ sample_map map[5]; /* 4 colors + alpha */
+#else
+ sample_map map[4];
+#endif
+ /* Entries 0 and 255 of the following are set at initialization */
+ /* for monochrome images; other entries are updated dynamically. */
+ gx_image_clue clues[256];
+#define icolor0 clues[0].dev_color
+#define icolor1 clues[255].dev_color
+};
+/* Enumerate the pointers in an image enumerator. */
+#define gx_image_enum_do_ptrs(m)\
+ m(0,pis) m(1,pcs) m(2,dev) m(3,buffer) m(4,line)\
+ m(5,clip_dev) m(6,rop_dev) m(7,scaler)
+#define gx_image_enum_num_ptrs 8
+#define private_st_gx_image_enum() /* in gsimage.c */\
+ gs_private_st_composite(st_gx_image_enum, gx_image_enum, "gx_image_enum",\
+ image_enum_enum_ptrs, image_enum_reloc_ptrs)
+
+/* Compare two device colors for equality. */
+#define dev_color_eq(devc1, devc2)\
+ (gx_dc_is_pure(&(devc1)) ?\
+ gx_dc_is_pure(&(devc2)) &&\
+ gx_dc_pure_color(&(devc1)) == gx_dc_pure_color(&(devc2)) :\
+ gx_dc_is_binary_halftone(&(devc1)) ?\
+ gx_dc_is_binary_halftone(&(devc2)) &&\
+ gx_dc_binary_color0(&(devc1)) == gx_dc_binary_color0(&(devc2)) &&\
+ gx_dc_binary_color1(&(devc1)) == gx_dc_binary_color1(&(devc2)) &&\
+ (devc1).colors.binary.b_level == (devc2).colors.binary.b_level :\
+ false)
diff --git a/gs/src/gximage0.c b/gs/src/gximage0.c
new file mode 100644
index 000000000..3e575b0f5
--- /dev/null
+++ b/gs/src/gximage0.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage0.c */
+/* Generic image enumeration and cleanup */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* Process the next piece of an image */
+int
+gx_default_image_data(gx_device *dev,
+ void *info, const byte **planes, int data_x, uint raster, int height)
+{ gx_image_enum *penum = info;
+ int y = penum->y;
+ int y_end = min(y + height, penum->rect.h);
+ int width_spp = penum->rect.w * penum->spp;
+ int nplanes = penum->num_planes;
+ uint bcount = /* bytes per data row */
+ ((penum->rect.w + data_x) * penum->spp / nplanes * penum->bps
+ + 7) >> 3;
+ fixed adjust = penum->adjust;
+ ulong offset = 0;
+ int ignore_data_x;
+ int code;
+
+ if ( height == 0 )
+ return 0;
+
+ /* Set up the clipping and/or RasterOp device if needed. */
+
+ if ( penum->clip_dev )
+ { gx_device_clip *cdev = penum->clip_dev;
+ cdev->target = dev;
+ dev = (gx_device *)cdev;
+ }
+ if ( penum->rop_dev )
+ { gx_device_rop_texture *rtdev = penum->rop_dev;
+ ((gx_device_forward *)rtdev)->target = dev;
+ dev = (gx_device *)rtdev;
+ }
+
+ /* Now render complete rows. */
+
+ for ( ; penum->y < y_end; offset += raster, penum->y++ )
+ { int px;
+ /*
+ * Normally, we unpack the data into the buffer, but if
+ * there is only one plane and we don't need to expand the
+ * input samples, we may use the data directly.
+ */
+ int sourcex = data_x;
+ const byte *buffer =
+ (*penum->unpack)(penum->buffer, &sourcex,
+ planes[0] + offset, data_x, bcount,
+ &penum->map[0].table, penum->spread);
+
+ for ( px = 1; px < nplanes; ++px )
+ (*penum->unpack)(penum->buffer + (px << penum->log2_xbytes),
+ &ignore_data_x, planes[px] + offset,
+ data_x, bcount,
+ &penum->map[px].table, penum->spread);
+#ifdef DEBUG
+ if ( gs_debug_c('B') )
+ { int i, n = width_spp;
+ dputs("[B]row:");
+ for ( i = 0; i < n; i++ )
+ dprintf1(" %02x", buffer[i]);
+ dputs("\n");
+ }
+#endif
+ penum->cur.x = dda_current(penum->dda.row.x);
+ dda_next(penum->dda.row.x);
+ penum->cur.y = dda_current(penum->dda.row.y);
+ dda_next(penum->dda.row.y);
+ if ( !penum->interpolate )
+ switch ( penum->posture )
+ {
+ case image_portrait:
+ { /* Precompute integer y and height, */
+ /* and check for clipping. */
+ fixed yc = penum->cur.y,
+ yn = dda_current(penum->dda.row.y);
+
+ if ( yn < yc )
+ { fixed temp = yn; yn = yc; yc = temp; }
+ yc -= adjust;
+ if ( yc >= penum->clip_outer.q.y ) goto mt;
+ yn += adjust;
+ if ( yn <= penum->clip_outer.p.y ) goto mt;
+ penum->yci = fixed2int_pixround(yc);
+ penum->hci = fixed2int_pixround(yn) - penum->yci;
+ if ( penum->hci == 0 ) goto mt;
+ } break;
+ case image_landscape:
+ { /* Check for no pixel centers in x. */
+ fixed xc = penum->cur.x,
+ xn = dda_current(penum->dda.row.x);
+
+ if ( xn < xc )
+ { fixed temp = xn; xn = xc; xc = temp; }
+ xc -= adjust;
+ if ( xc >= penum->clip_outer.q.x ) goto mt;
+ xn += adjust;
+ if ( xn <= penum->clip_outer.p.x ) goto mt;
+ penum->xci = fixed2int_pixround(xc);
+ penum->wci = fixed2int_pixround(xn) - penum->xci;
+ if ( penum->wci == 0 ) goto mt;
+ } break;
+ case image_skewed:
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x,
+ penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y,
+ penum->cur.y - penum->prev.y);
+ penum->prev = penum->cur;
+ code = (*penum->render)(penum, buffer, sourcex, width_spp, 1,
+ dev);
+ if ( code < 0 )
+ goto err;
+mt: ;
+ }
+ if ( penum->y < penum->rect.h )
+ { code = 0;
+ goto out;
+ }
+ /* End of data. Render any left-over buffered data. */
+ switch ( penum->posture )
+ {
+ case image_portrait:
+ { fixed yc = dda_current(penum->dda.row.y);
+ penum->yci = fixed2int_rounded(yc - adjust);
+ penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
+ } break;
+ case image_landscape:
+ { fixed xc = dda_current(penum->dda.row.x);
+ penum->xci = fixed2int_rounded(xc - adjust);
+ penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
+ } break;
+ case image_skewed: /* pacify compilers */
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x, penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y, penum->cur.y - penum->prev.y);
+ code = (*penum->render)(penum, NULL, 0, width_spp, 0, dev);
+ if ( code < 0 )
+ { penum->y--;
+ goto err;
+ }
+ code = 1;
+ goto out;
+err: /* Error or interrupt, restore original state. */
+ while ( penum->y > y )
+ { dda_previous(penum->dda.row.x);
+ dda_previous(penum->dda.row.y);
+ --(penum->y);
+ }
+ /* Note that caller must call end_image */
+ /* for both error and normal termination. */
+out: return code;
+}
+
+/* Clean up by releasing the buffers. */
+/* Currently we ignore draw_last. */
+int
+gx_default_end_image(gx_device *dev, void *info, bool draw_last)
+{ gx_image_enum *penum = info;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state *scaler = penum->scaler;
+
+ gs_free_object(mem, penum->rop_dev, "image RasterOp");
+ gs_free_object(mem, penum->clip_dev, "image clipper");
+ if ( scaler != 0 )
+ { (*s_IScale_template.release)((stream_state *)scaler);
+ gs_free_object(mem, scaler, "image scaler state");
+ }
+ gs_free_object(mem, penum->line, "image line");
+ gs_free_object(mem, penum->buffer, "image buffer");
+ gs_free_object(mem, penum, "gx_default_end_image");
+ return 0;
+}
diff --git a/gs/src/gximage2.c b/gs/src/gximage2.c
new file mode 100644
index 000000000..d84af47e8
--- /dev/null
+++ b/gs/src/gximage2.c
@@ -0,0 +1,470 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage2.c */
+/* General monochrome image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gdevmem.h" /* for mem_mono_device */
+#include "gxcpath.h"
+#include "gximage.h"
+#include "gzht.h"
+
+/* ------ Strategy procedure ------ */
+
+/* We can bypass X clipping for portrait monochrome images. */
+private irender_proc(image_render_mono);
+private irender_proc_t
+image_strategy_mono(gx_image_enum *penum)
+{ /* Use slow loop for imagemask with a halftone, */
+ /* or for a non-default logical operation. */
+ penum->slow_loop =
+ (penum->masked && !color_is_pure(&penum->icolor1)) ||
+ penum->use_rop;
+ if ( penum->spp == 1 )
+ { if ( !(penum->slow_loop || penum->posture != image_portrait) )
+ penum->clip_image &= ~(image_clip_xmin | image_clip_xmax);
+ if_debug0('b', "[b]render=mono\n");
+ /* Precompute values needed for rasterizing. */
+ penum->dxx =
+ float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
+ return image_render_mono;
+ }
+ return 0;
+}
+
+void
+gs_gximage2_init(gs_memory_t *mem)
+{ image_strategies.mono = image_strategy_mono;
+}
+
+/* ------ Rendering procedure ------ */
+
+/* Rendering procedure for the general case of displaying a */
+/* monochrome image, dealing with multiple bit-per-sample images, */
+/* general transformations, and arbitrary single-component */
+/* color spaces (DeviceGray, CIEBasedA, Separation, Indexed). */
+/* This procedure handles a single scan line. */
+private int
+image_render_mono(gx_image_enum *penum, const byte *buffer, int data_x,
+ uint w, int h, gx_device *dev)
+{ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ const int masked = penum->masked;
+ const gs_color_space *pcs; /* only set for non-masks */
+ cs_proc_remap_color((*remap_color)); /* ditto */
+ gs_client_color cc;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_gray((*map_gray)) = cmap_procs->map_gray;
+ gx_device_color *pdevc = &penum->icolor1; /* color for masking */
+ /* Make sure the cache setup matches the graphics state. */
+ /* Also determine whether all tiles fit in the cache. */
+ int tiles_fit = gx_check_tile_cache(pis);
+#define image_set_gray(sample_value)\
+ { pdevc = &penum->clues[sample_value].dev_color;\
+ if ( !color_is_set(pdevc) )\
+ { if ( penum->device_color )\
+ (*map_gray)(byte2frac(sample_value), pdevc, pis, dev, gs_color_select_source);\
+ else\
+ { decode_sample(sample_value, cc, 0);\
+ (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);\
+ }\
+ }\
+ else if ( !color_is_pure(pdevc) )\
+ { if ( !tiles_fit )\
+ { code = gx_color_load_select(pdevc, pis, dev, gs_color_select_source);\
+ if ( code < 0 ) return code;\
+ }\
+ }\
+ }
+ gx_dda_fixed_point next; /* (y not used in fast loop) */
+ gx_dda_step_fixed dxx2, dxx3, dxx4; /* (not used in all loops) */
+ register const byte *psrc = buffer + data_x;
+ const byte *endp = psrc + w;
+ const byte *stop = endp;
+ fixed xrun; /* x at start of run */
+ register byte run; /* run value */
+ int htrun = /* halftone run value */
+ (masked ? 255 : -2);
+ int code = 0;
+
+ if ( h == 0 )
+ return 0;
+ next = penum->dda.pixel0;
+ xrun = dda_current(next.x);
+ if ( !masked )
+ { pcs = penum->pcs; /* (may not be set for masks) */
+ remap_color = pcs->type->remap_color;
+ }
+ run = *psrc;
+ /* Find the last transition in the input. */
+ { byte last = stop[-1];
+ while ( stop > psrc && stop[-1] == last )
+ --stop;
+ }
+ if ( penum->slow_loop || penum->posture != image_portrait )
+ { /* Skewed, rotated, or imagemask with a halftone. */
+ fixed yrun;
+ const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ dev_proc_fill_parallelogram((*fill_pgram)) =
+ dev_proc(dev, fill_parallelogram);
+
+#define xl dda_current(next.x)
+#define ytf dda_current(next.y)
+ yrun = ytf;
+ if ( masked )
+ { pdevc = &penum->icolor1;
+ code = gx_color_load(pdevc, pis, dev);
+ if ( code < 0 )
+ return code;
+ if ( stop <= psrc )
+ goto last;
+ if ( penum->posture == image_portrait )
+ { /* We don't have to worry about the Y DDA, */
+ /* and the fill regions are rectangles. */
+ /* Calculate multiples of the DDA step. */
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ for ( ; ; )
+ { /* Skip a run of zeros. */
+ while ( !psrc[0] )
+ if ( !psrc[1] )
+ { if ( !psrc[2] )
+ { if ( !psrc[3] )
+ { psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ continue;
+ }
+ psrc += 3;
+ dda_state_next(next.x.state, dxx3);
+ break;
+ }
+ psrc += 2;
+ dda_state_next(next.x.state, dxx2);
+ break;
+ }
+ else
+ { ++psrc;
+ dda_next(next.x);
+ break;
+ }
+ xrun = xl;
+ if ( psrc >= stop )
+ break;
+ for ( ; *psrc; ++psrc )
+ dda_next(next.x);
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ fixed_0, fixed_0, pdyy,
+ pdevc, lop);
+ if ( code < 0 )
+ return code;
+ if ( psrc >= stop )
+ break;
+ }
+ }
+ else
+ for ( ; ; )
+ { for ( ; !*psrc; ++psrc )
+ { dda_next(next.x);
+ dda_next(next.y);
+ }
+ yrun = ytf;
+ xrun = xl;
+ if ( psrc >= stop )
+ break;
+ for ( ; *psrc; ++psrc )
+ { dda_next(next.x);
+ dda_next(next.y);
+ }
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ if ( psrc >= stop )
+ break;
+ }
+ }
+ else if ( penum->posture == image_portrait ||
+ penum->posture == image_landscape
+ )
+ { /* Not masked, and we can fill runs quickly. */
+ if ( stop <= psrc )
+ goto last;
+ for ( ; ; )
+ { if ( *psrc != run )
+ { if ( run != htrun )
+ { htrun = run;
+ image_set_gray(run);
+ }
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ if ( code < 0 )
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if ( psrc >= stop )
+ break;
+ run = *psrc;
+ }
+ psrc++;
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ }
+ else /* not masked */
+ { /* Since we have to check for the end after every pixel */
+ /* anyway, we may as well avoid the last-run code. */
+ stop = endp;
+ for ( ; ; )
+ { /* We can't skip large constant regions quickly, */
+ /* because this leads to rounding errors. */
+ /* Just fill the region between xrun and xl. */
+ psrc++;
+ if ( run != htrun )
+ { htrun = run;
+ image_set_gray(run);
+ }
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if ( code < 0 )
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if ( psrc > stop )
+ { --psrc;
+ break;
+ }
+ run = psrc[-1];
+ dda_next(next.x);
+ dda_next(next.y); /* harmless if no skew */
+ }
+ }
+ /* Fill the last run. */
+last: if ( stop < endp && (*stop || !masked) )
+ { if ( !masked )
+ { image_set_gray(*stop);
+ }
+ dda_advance(next.x, endp - stop);
+ dda_advance(next.y, endp - stop);
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ }
+#undef xl
+#undef ytf
+ }
+ else /* fast loop */
+ { /* No skew, and not imagemask with a halftone. */
+ const fixed adjust = penum->adjust;
+ const fixed dxx = penum->dxx;
+ fixed xa = (dxx >= 0 ? adjust : -adjust);
+ const int yt = penum->yci, iht = penum->hci;
+ dev_proc_fill_rectangle((*fill_proc)) =
+ dev_proc(dev, fill_rectangle);
+ dev_proc_strip_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, strip_tile_rectangle);
+ dev_proc_copy_mono((*copy_mono_proc)) =
+ dev_proc(dev, copy_mono);
+ /*
+ * If each pixel is likely to fit in a single halftone tile,
+ * determine that now (tile_offset = offset of row within tile).
+ * Don't do this for band devices; they handle halftone fills
+ * more efficiently than copy_mono.
+ */
+ int bstart;
+ int phase_x;
+ int tile_offset =
+ ((*dev_proc(dev, get_band))(dev, yt, &bstart) == 0 ?
+ gx_check_tile_size(pis,
+ fixed2int_ceiling(any_abs(dxx) + (xa << 1)),
+ yt, iht, gs_color_select_source, &phase_x) :
+ -1);
+ int xmin = fixed2int_pixround(penum->clip_outer.p.x);
+ int xmax = fixed2int_pixround(penum->clip_outer.q.x);
+
+#define xl dda_current(next.x)
+ /* Fold the adjustment into xrun and xl, */
+ /* including the +0.5-epsilon for rounding. */
+ xrun = xrun - xa + (fixed_half - fixed_epsilon);
+ dda_translate(next.x, xa + (fixed_half - fixed_epsilon));
+ xa <<= 1;
+ /* Calculate multiples of the DDA step. */
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ if ( stop > psrc )
+ for ( ; ; )
+ { /* Skip large constant regions quickly, */
+ /* but don't slow down transitions too much. */
+skf: if ( psrc[0] == run )
+ { if ( psrc[1] == run )
+ { if ( psrc[2] == run )
+ { if ( psrc[3] == run )
+ { psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ goto skf;
+ }
+ else
+ { psrc += 4;
+ dda_state_next(next.x.state, dxx3);
+ }
+ }
+ else
+ { psrc += 3;
+ dda_state_next(next.x.state, dxx2);
+ }
+ }
+ else
+ { psrc += 2;
+ dda_next(next.x);
+ }
+ }
+ else
+ psrc++;
+ { /* Now fill the region between xrun and xl. */
+ int xi = fixed2int_var(xrun);
+ int wi = fixed2int_var(xl) - xi;
+ int xei, tsx;
+ const gx_strip_bitmap *tile;
+
+ if ( wi <= 0 )
+ { if ( wi == 0 ) goto mt;
+ xi += wi, wi = -wi;
+ }
+ if ( (xei = xi + wi) > xmax || xi < xmin )
+ { /* Do X clipping */
+ if ( xi < xmin )
+ wi -= xmin - xi, xi = xmin;
+ if ( xei > xmax )
+ wi -= xei - xmax;
+ if ( wi <= 0 )
+ goto mt;
+ }
+ switch ( run )
+ {
+ case 0:
+ if ( masked ) goto mt;
+ if ( !color_is_pure(&penum->icolor0) ) goto ht;
+ code = (*fill_proc)(dev, xi, yt, wi, iht,
+ penum->icolor0.colors.pure);
+ break;
+ case 255: /* just for speed */
+ if ( !color_is_pure(&penum->icolor1) ) goto ht;
+ code = (*fill_proc)(dev, xi, yt, wi, iht,
+ penum->icolor1.colors.pure);
+ break;
+ default:
+ht: /* Use halftone if needed */
+ if ( run != htrun )
+ { image_set_gray(run);
+ htrun = run;
+ }
+ /* We open-code gx_fill_rectangle, */
+ /* because we've done some of the work for */
+ /* halftone tiles in advance. */
+ if ( color_is_pure(pdevc) )
+ { code = (*fill_proc)(dev, xi, yt, wi, iht,
+ pdevc->colors.pure);
+ }
+ else if ( !color_is_binary_halftone(pdevc) )
+ { code =
+ gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+ }
+ else if ( tile_offset >= 0 &&
+ (tile = &pdevc->colors.binary.b_tile->tiles,
+ (tsx = (xi + phase_x) % tile->rep_width) + wi <= tile->size.x)
+ )
+ { /* The pixel(s) fit(s) in a single (binary) tile. */
+ byte *row = tile->data + tile_offset;
+ code = (*copy_mono_proc)
+ (dev, row, tsx, tile->raster, gx_no_bitmap_id,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1]);
+ }
+ else
+ { code = (*tile_proc)(dev,
+ &pdevc->colors.binary.b_tile->tiles,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->phase.x, pdevc->phase.y);
+ }
+ }
+ if ( code < 0 ) return code;
+mt: xrun = xl - xa; /* original xa << 1 */
+ if ( psrc > stop )
+ { --psrc;
+ break;
+ }
+ run = psrc[-1];
+ }
+ dda_next(next.x);
+ }
+ /* Fill the last run. */
+ if ( *stop != 0 || !masked )
+ { int xi = fixed2int_var(xrun);
+ int wi, xei;
+
+ dda_advance(next.x, endp - stop);
+ wi = fixed2int_var(xl) - xi;
+ if ( wi <= 0 )
+ { if ( wi == 0 ) goto lmt;
+ xi += wi, wi = -wi;
+ }
+ if ( (xei = xi + wi) > xmax || xi < xmin )
+ { /* Do X clipping */
+ if ( xi < xmin )
+ wi -= xmin - xi, xi = xmin;
+ if ( xei > xmax )
+ wi -= xei - xmax;
+ if ( wi <= 0 )
+ goto lmt;
+ }
+ image_set_gray(*stop);
+ code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+lmt: ;
+ }
+ }
+#undef xl
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gximage3.c b/gs/src/gximage3.c
new file mode 100644
index 000000000..2f0772d63
--- /dev/null
+++ b/gs/src/gximage3.c
@@ -0,0 +1,332 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage3.c */
+/* Color image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcconv.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+private irender_proc(image_render_color);
+private irender_proc_t
+image_strategy_color(gx_image_enum *penum)
+{ return image_render_color;
+}
+
+void
+gs_gximage3_init(gs_memory_t *mem)
+{ image_strategies.color = image_strategy_color;
+}
+
+/* ------ Rendering procedures ------ */
+
+/* Render a color image with 8 or fewer bits per sample. */
+typedef union {
+ byte v[4];
+ bits32 all; /* for fast comparison & clearing */
+} color_samples;
+private int
+image_render_color(gx_image_enum *penum, const byte *buffer, int data_x,
+ uint w, int h, gx_device *dev)
+{ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xl, ytf;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int vci, vdi;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ bool device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_cmyk)) =
+#ifdef DPNEXT
+ /*
+ * map_cmyk is a misnomer in this case: the procedures should
+ * really be called map_3 and map_4.
+ */
+ (penum->has_alpha ? cmap_procs->map_rgb_alpha :
+ cmap_procs->map_cmyk)
+#else
+ cmap_procs->map_cmyk
+#endif
+ ;
+ gx_image_clue *pic = &penum->clues[0];
+#define pdevc (&pic->dev_color)
+ gx_image_clue *pic_next = &penum->clues[1];
+#define pdevc_next (&pic_next->dev_color)
+ gx_image_clue empty_clue;
+ gx_image_clue clue_temp;
+ int spp = penum->spp;
+ const byte *psrc = buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ fixed yrun; /* y ditto */
+ int irun; /* int x/rrun */
+ color_samples run; /* run value */
+ color_samples next; /* next sample value */
+ bool small =
+ fixed2int(any_abs(penum->x_extent.x)) < penum->rect.w &&
+ fixed2int(any_abs(penum->x_extent.y)) < penum->rect.w;
+ const byte *bufend = psrc + w;
+ bool use_cache = spp * penum->bps <= 12;
+ int code;
+
+ if ( h == 0 )
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xl = dda_current(pnext.x);
+ yrun = ytf = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ switch ( posture )
+ {
+ case image_portrait:
+ vci = penum->yci, vdi = penum->hci;
+ irun = fixed2int_var_rounded(xrun);
+ break;
+ case image_landscape:
+ vci = penum->xci, vdi = penum->wci;
+ irun = fixed2int_var_rounded(yrun);
+ break;
+ }
+
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xl), fixed2float(ytf));
+ run.all = 0;
+ next.all = 0;
+ /* Ensure that we don't get any false dev_color_eq hits. */
+ if ( use_cache )
+ { color_set_pure(&empty_clue.dev_color, gx_no_color_index);
+ pic = &empty_clue;
+ }
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ run.v[0] = ~psrc[0]; /* force remap */
+ while ( psrc < bufend )
+ { dda_next(pnext.x);
+#define xn dda_current(pnext.x)
+ dda_next(pnext.y);
+#define yn dda_current(pnext.y)
+#define includes_pixel_center(a, b)\
+ (fixed_floor(a < b ? (a - (fixed_half + fixed_epsilon)) ^ (b - fixed_half) :\
+ (b - (fixed_half + fixed_epsilon)) ^ (a - fixed_half)) != 0)
+#define paint_no_pixels()\
+ (small && !includes_pixel_center(xl, xn) &&\
+ !includes_pixel_center(ytf, yn) && psrc <= bufend)
+#define clue_hash3(next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4)) & 255];
+#define clue_hash4(next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4) +\
+ (next.v[3] << 6)) & 255]
+
+ if ( spp == 4 ) /* cmyk or rgba */
+ { next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+#ifdef DPNEXT
+map4:
+#endif
+ if ( next.all == run.all || paint_no_pixels() )
+ goto inc;
+ if ( use_cache )
+ { pic_next = clue_hash4(next);
+ if ( pic_next->key == next.all )
+ goto f;
+ /*
+ * If we are really unlucky, pic_next == pic,
+ * so mapping this color would clobber the one
+ * we're about to use for filling the run.
+ */
+ if ( pic_next == pic )
+ { clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if ( device_color )
+ { (*map_cmyk)(byte2frac(next.v[0]),
+ byte2frac(next.v[1]),
+ byte2frac(next.v[2]),
+ byte2frac(next.v[3]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ decode_sample(next.v[3], cc, 3);
+ if_debug1('B', "[B]cc[3]=%g\n", cc.paint.values[3]);
+ }
+ else /* rgb */
+#ifdef DPNEXT
+ if ( spp == 3 )
+#endif
+ { next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if ( next.all == run.all || paint_no_pixels() )
+ goto inc;
+ if ( use_cache )
+ { pic_next = clue_hash3(next);
+ if ( pic_next->key == next.all )
+ goto f;
+ /* See above re the following check. */
+ if ( pic_next == pic )
+ { clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if ( device_color )
+ { (*map_rgb)(byte2frac(next.v[0]),
+ byte2frac(next.v[1]),
+ byte2frac(next.v[2]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ }
+#ifdef DPNEXT
+ else if ( spp == 2 ) /* gray+alpha */
+ { next.v[2] = next.v[1] = next.v[0] = psrc[0];
+ next.v[3] = psrc[1];
+ psrc += 2;
+ goto map4;
+ }
+ else /* spp == 5, cmyk+alpha */
+ { /* Convert CMYK to RGB. */
+ frac rgb[3];
+
+ color_cmyk_to_rgb(byte2frac(psrc[0]),
+ byte2frac(psrc[1]),
+ byte2frac(psrc[2]),
+ byte2frac(psrc[3]),
+ pis, rgb);
+ /*
+ * It seems silly to do all this converting between
+ * fracs and bytes, but that's what the current
+ * APIs require.
+ */
+ next.v[0] = frac2byte(rgb[0]);
+ next.v[1] = frac2byte(rgb[1]);
+ next.v[2] = frac2byte(rgb[2]);
+ next.v[3] = psrc[4];
+ psrc += 5;
+ goto map4;
+ }
+#endif
+ decode_sample(next.v[0], cc, 0);
+ decode_sample(next.v[1], cc, 1);
+ decode_sample(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ (*remap_color)(&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+mapped: if ( pic == pic_next )
+ goto fill;
+f: if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong)pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if ( dev_color_eq(*pdevc, *pdevc_next) )
+ goto set;
+fill: { /* Fill the region between */
+ /* xrun/irun and xl */
+ switch ( posture )
+ {
+ case image_portrait:
+ { /* Rectangle */
+ int xi = irun;
+ int wi =
+ (irun = fixed2int_var_rounded(xl)) - xi;
+ if ( wi < 0 )
+ xi += wi, wi = -wi;
+ code =
+ gx_fill_rectangle_device_rop(xi, vci,
+ wi, vdi, pdevc, dev, lop);
+ xrun = xl; /* for sake of final run */
+ } break;
+ case image_landscape:
+ { /* 90 degree rotated rectangle */
+ int yi = irun;
+ int hi =
+ (irun = fixed2int_var_rounded(ytf)) - yi;
+ if ( hi < 0 )
+ yi += hi, hi = -hi;
+ code = gx_fill_rectangle_device_rop(vci, yi,
+ vdi, hi, pdevc, dev, lop);
+ yrun = ytf; /* for sake of final run */
+ } break;
+ default:
+ { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xl - xrun, ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ xrun = xl;
+ yrun = ytf;
+ }
+ }
+ if ( code < 0 )
+ return code;
+ if ( use_cache )
+ pic = pic_next;
+ else
+ { gx_image_clue *ptemp = pic;
+ pic = pic_next;
+ pic_next = ptemp;
+ }
+ }
+set: run.all = next.all;
+inc: xl = xn;
+ ytf = yn; /* harmless if no skew */
+#undef xn
+#undef yn
+ }
+ /* Fill the last run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gximage4.c b/gs/src/gximage4.c
new file mode 100644
index 000000000..5ce559dad
--- /dev/null
+++ b/gs/src/gximage4.c
@@ -0,0 +1,299 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage4.c */
+/* 12-bit image procedures */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ---------------- Unpacking procedures ---------------- */
+
+private const byte *
+sample_unpack_12(byte *bptr, int *pdata_x, const byte *data,
+ int data_x, uint dsize, const sample_lookup_t *ignore_ptab,
+ int spread)
+{ register frac *bufp = (frac *)bptr;
+ uint dskip = (data_x >> 1) * 3;
+ const byte *psrc = data + dskip;
+#define inc_bufp(bp, n) bp = (frac *)((byte *)(bp) + (n))
+ uint sample;
+ int left = dsize - dskip;
+ static const frac bits2frac_4[16] = {
+#define frac15(n) ((frac_1 / 15) * (n))
+ frac15(0), frac15(1), frac15(2), frac15(3),
+ frac15(4), frac15(5), frac15(6), frac15(7),
+ frac15(8), frac15(9), frac15(10), frac15(11),
+ frac15(12), frac15(13), frac15(14), frac15(15)
+#undef frac15
+ };
+
+ if ( (data_x & 1) && left > 0 )
+ switch ( left )
+ {
+ default:
+ sample = ((uint)(psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ break;
+ case 2: /* xxxxxxxx xxxxdddd */
+ *bufp = bits2frac_4[psrc[1] & 0xf];
+ case 1: /* xxxxxxxx */
+ left = 0;
+ }
+ while ( left >= 3 )
+ { sample = ((uint)*psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ sample = ((uint)(psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ }
+ /* Handle trailing bytes. */
+ switch ( left )
+ {
+ case 2: /* dddddddd ddddxxxx */
+ sample = ((uint)*psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ *bufp = bits2frac_4[psrc[1] & 0xf];
+ break;
+ case 1: /* dddddddd */
+ sample = (uint)*psrc << 4;
+ *bufp = bits2frac(sample, 12);
+ break;
+ case 0: /* Nothing more to do. */
+ ;
+ }
+ *pdata_x = 0;
+ return bptr;
+}
+
+/* ------ Strategy procedure ------ */
+
+/* Use special (slow) logic for 12-bit source values. */
+private irender_proc(image_render_frac);
+private irender_proc_t
+image_strategy_frac(gx_image_enum *penum)
+{ if ( penum->bps > 8 )
+ { if_debug0('b', "[b]render=frac\n");
+ return image_render_frac;
+ }
+ return 0;
+}
+
+void
+gs_gximage4_init(gs_memory_t *mem)
+{ image_strategies.fracs = image_strategy_frac;
+ sample_unpack_12_proc = sample_unpack_12;
+}
+
+/* ---------------- Rendering procedures ---------------- */
+
+/* ------ Rendering for 12-bit samples ------ */
+
+/* Render an image with more than 8 bits per sample. */
+/* The samples have been expanded into fracs. */
+#define longs_per_4_fracs (arch_sizeof_frac * 4 / arch_sizeof_long)
+typedef union {
+ frac v[4];
+ long all[longs_per_4_fracs]; /* for fast comparison */
+} color_fracs;
+#if longs_per_4_fracs == 1
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0])
+#else
+#if longs_per_4_fracs == 2
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0] && (f1).all[1] == (f2).all[1])
+#endif
+#endif
+private int
+image_render_frac(gx_image_enum *penum, const byte *buffer, int data_x,
+ uint w, int h, gx_device *dev)
+{ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xl, ytf;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int yt = penum->yci, iht = penum->hci;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ int device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_cmyk)) = cmap_procs->map_cmyk;
+ gx_device_color devc1, devc2;
+ gx_device_color _ss *spdevc = &devc1;
+ gx_device_color _ss *spdevc_next = &devc2;
+#define pdevc ((gx_device_color *)spdevc)
+#define pdevc_next ((gx_device_color *)spdevc_next)
+ int spp = penum->spp;
+ const frac *psrc = (const frac *)buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ int irun; /* int xrun */
+ fixed yrun; /* y ditto */
+ color_fracs run; /* run value */
+ color_fracs next; /* next sample value */
+ const frac *bufend = psrc + w;
+ int code;
+
+ if ( h == 0 )
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xl = dda_current(pnext.x);
+ irun = fixed2int_var_rounded(xrun);
+ yrun = ytf = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xl), fixed2float(ytf));
+ run.v[0] = run.v[1] = run.v[2] = run.v[3] = 0;
+ next.v[0] = next.v[1] = next.v[2] = next.v[3] = 0;
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);
+ run.v[0] = ~psrc[0]; /* force remap */
+
+ while ( psrc < bufend )
+ { next.v[0] = psrc[0];
+ switch ( spp )
+ {
+ case 4: /* cmyk */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+ if ( color_frac_eq(next, run) ) goto inc;
+ if ( device_color )
+ { (*map_cmyk)(next.v[0], next.v[1],
+ next.v[2], next.v[3],
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ decode_frac(next.v[3], cc, 3);
+ if_debug4('B', "[B]cc[0..3]=%g,%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2], cc.paint.values[3]);
+ if_debug1('B', "[B]cc[3]=%g\n",
+ cc.paint.values[3]);
+ break;
+ case 3: /* rgb */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if ( color_frac_eq(next, run) ) goto inc;
+ if ( device_color )
+ { (*map_rgb)(next.v[0], next.v[1],
+ next.v[2], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ break;
+ case 1: /* gray */
+ psrc++;
+ if ( next.v[0] == run.v[0] ) goto inc;
+ if ( device_color )
+ { (*map_rgb)(next.v[0], next.v[0],
+ next.v[0], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ if_debug1('B', "[B]cc[0]=%g\n",
+ cc.paint.values[0]);
+ break;
+ }
+ (*remap_color)(&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+f: if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong)pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if ( !dev_color_eq(devc1, devc2) )
+ { /* Fill the region between */
+ /* xrun/irun and xl */
+ gx_device_color _ss *sptemp;
+
+ if ( posture != image_portrait )
+ { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xl - xrun, ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ }
+ else
+ { /* Rectangle */
+ int xi = irun;
+ int wi = (irun = fixed2int_var_rounded(xl)) - xi;
+ if ( wi < 0 ) xi += wi, wi = -wi;
+ code = gx_fill_rectangle_device_rop(xi, yt,
+ wi, iht, pdevc, dev, lop);
+ }
+ if ( code < 0 )
+ return code;
+ sptemp = spdevc;
+ spdevc = spdevc_next;
+ spdevc_next = sptemp;
+ xrun = xl;
+ yrun = ytf;
+ }
+ run = next;
+inc: xl = dda_next(pnext.x);
+ ytf = dda_next(pnext.y);
+ }
+ /* Fill the final run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gximage5.c b/gs/src/gximage5.c
new file mode 100644
index 000000000..32c4d3bc5
--- /dev/null
+++ b/gs/src/gximage5.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gximage5.c */
+/* Interpolated image procedures */
+#include "gx.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+/* If we're interpolating, use special logic. */
+private irender_proc(image_render_interpolate);
+private irender_proc_t
+image_strategy_interpolate(gx_image_enum *penum)
+{ const gs_imager_state *pis = penum->pis;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state iss;
+ stream_IScale_state *pss;
+ byte *line;
+ const gs_color_space *pcs = penum->pcs;
+ gs_point dst_xy;
+
+ if ( !penum->interpolate )
+ return 0;
+ if ( penum->posture != image_portrait || penum->masked
+#ifdef DPNEXT
+ || penum->has_alpha
+#endif
+ )
+ { /* We can't handle these cases yet. Punt. */
+ penum->interpolate = false;
+ return 0;
+ }
+ iss.memory = mem;
+ /* Non-ANSI compilers require the following casts: */
+ gs_distance_transform((float)penum->rect.w, (float)penum->rect.h,
+ &penum->matrix, &dst_xy);
+ if ( penum->bps <= 8 && penum->device_color )
+ iss.BitsPerComponentIn = 8,
+ iss.MaxValueIn = 0xff;
+ else
+ iss.BitsPerComponentIn = sizeof(frac) * 8,
+ iss.MaxValueIn = frac_1;
+ iss.BitsPerComponentOut = sizeof(frac) * 8;
+ iss.MaxValueOut = frac_1;
+ iss.WidthOut = (int)ceil(fabs(dst_xy.x));
+ iss.HeightOut = (int)ceil(fabs(dst_xy.y));
+ iss.WidthIn = penum->rect.w;
+ iss.HeightIn = penum->rect.h;
+ iss.Colors = cs_concrete_space(pcs, pis)->type->num_components;
+ /* Allocate a buffer for one source/destination line. */
+ { uint in_size =
+ iss.WidthIn * iss.Colors * (iss.BitsPerComponentIn / 8);
+ uint out_size =
+ iss.WidthOut * iss.Colors *
+ max(iss.BitsPerComponentOut / 8, sizeof(gx_color_index));
+ line = gs_alloc_bytes(mem, max(in_size, out_size),
+ "image scale src line");
+ }
+ pss = gs_alloc_struct(mem, stream_IScale_state,
+ &st_IScale_state, "image scale state");
+ if ( line == 0 || pss == 0 ||
+ (*pss = iss,
+ (*s_IScale_template.init)((stream_state *)pss) < 0)
+ )
+ { gs_free_object(mem, pss, "image scale state");
+ gs_free_object(mem, line, "image scale src line");
+ /* Try again without interpolation. */
+ penum->interpolate = false;
+ return 0;
+ }
+ penum->line = line;
+ penum->scaler = pss;
+ penum->line_xy = 0;
+ penum->xyi.x = fixed2int_pixround(dda_current(penum->dda.pixel0.x));
+ penum->xyi.y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
+ if_debug0('b', "[b]render=interpolate\n");
+ return image_render_interpolate;
+}
+
+void
+gs_gximage5_init(gs_memory_t *mem)
+{ image_strategies.interpolate = image_strategy_interpolate;
+}
+
+/* ------ Rendering for interpolated images ------ */
+
+private int
+image_render_interpolate(gx_image_enum *penum, const byte *buffer,
+ int data_x, uint iw, int h, gx_device *dev)
+{ stream_IScale_state *pss = penum->scaler;
+ const gs_imager_state *pis = penum->pis;
+ const gs_color_space *pcs = penum->pcs;
+ gs_logical_operation_t lop = penum->log_op;
+ int c = pss->Colors;
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ if ( h != 0 )
+ { /* Convert the unpacked data to concrete values in */
+ /* the source buffer. */
+ uint row_size = pss->WidthIn * c * pss->sizeofPixelIn;
+ const byte *bdata = buffer + data_x * c * pss->sizeofPixelIn;
+
+ if ( pss->sizeofPixelIn == 1 )
+ { /* Easy case: 8-bit device color values. */
+ r.ptr = bdata - 1;
+ }
+ else
+ { /* Messy case: concretize each sample. */
+ int bps = penum->bps;
+ int dc = penum->spp;
+ const byte *pdata = bdata;
+ frac *psrc = (frac *)penum->line;
+ gs_client_color cc;
+ int i;
+
+ r.ptr = (byte *)psrc - 1;
+ for ( i = 0; i < pss->WidthIn; i++, psrc += c )
+ { int j;
+ if ( bps <= 8 )
+ for ( j = 0; j < dc; ++pdata, ++j )
+ { decode_sample(*pdata, cc, j);
+ }
+ else /* bps == 12 */
+ for ( j = 0; j < dc; pdata += sizeof(frac), ++j )
+ { decode_frac(*(const frac *)pdata, cc, j);
+ }
+ (*pcs->type->concretize_color)(&cc, pcs, psrc,
+ pis);
+ }
+ }
+ r.limit = r.ptr + row_size;
+ }
+ else /* h == 0 */
+ r.ptr = 0, r.limit = 0;
+
+ /*
+ * Process input and/or collect output.
+ * By construction, the pixels are 1-for-1 with the device,
+ * but the Y coordinate might be inverted.
+ */
+
+ { int xo = penum->xyi.x;
+ int yo = penum->xyi.y;
+ int width = pss->WidthOut;
+ int dy;
+ const gs_color_space *pconcs = cs_concrete_space(pcs, pis);
+ int bpp = dev->color_info.depth;
+ uint raster = bitmap_raster(width * bpp);
+
+ if ( penum->matrix.yy > 0 )
+ dy = 1;
+ else
+ dy = -1, yo--;
+ for ( ; ; )
+ { int ry = yo + penum->line_xy * dy;
+ int x;
+ const frac *psrc;
+ gx_device_color devc;
+ int code;
+ declare_line_accum(penum->line, bpp, xo);
+
+ w.limit = penum->line + width * c *
+ sizeof(gx_color_index) - 1;
+ w.ptr = w.limit - width * c *
+ (sizeof(gx_color_index) - pss->sizeofPixelOut);
+ psrc = (const frac *)(w.ptr + 1);
+ code = (*s_IScale_template.process)
+ ((stream_state *)pss, &r, &w, false);
+ if ( code < 0 && code != EOFC )
+ return_error(gs_error_ioerror);
+ if ( w.ptr == w.limit )
+ { for ( x = xo; x < xo + width; x++, psrc += c )
+ { (*pconcs->type->remap_concrete_color)
+ (psrc, &devc, pis, dev,
+ gs_color_select_source);
+ if ( color_is_pure(&devc) )
+ { /* Just pack colors into a scan line. */
+ gx_color_index color = devc.colors.pure;
+ line_accum(color, bpp);
+ }
+ else
+ { line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ code = gx_fill_rectangle_device_rop(x, ry,
+ 1, 1, &devc, dev, lop);
+ if ( code < 0 )
+ return code;
+ if ( bpp < 8 )
+ { if ( (l_shift -= bpp) < 0 )
+ *l_dst++ = (byte)l_bits, l_bits = 0,
+ l_shift += 8;
+ }
+ else
+ l_dst += bpp >> 3;
+ l_xprev = x + 1;
+ }
+ }
+ line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ penum->line_xy++;
+ continue;
+ }
+ if ( r.ptr == r.limit || code == EOFC )
+ break;
+ }
+ }
+
+ return (h == 0 ? 0 : 1);
+}
diff --git a/gs/src/gxiodev.h b/gs/src/gxiodev.h
new file mode 100644
index 000000000..78a021520
--- /dev/null
+++ b/gs/src/gxiodev.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxiodev.h */
+/* Definition of an IODevice object */
+/* Requires gsmemory.h */
+#include "stat_.h"
+
+/*
+ * Note that IODevices are not the same as Ghostscript output devices.
+ * See section 3.8.2 of the PostScript Language Reference Manual,
+ * Second Edition, for more information.
+ */
+
+typedef struct gx_io_device_s gx_io_device; /* defined here */
+typedef struct gx_io_device_procs_s gx_io_device_procs; /* defined here */
+
+/* The IODevice table is defined in gconfig.c; its extern is in gscdefs.h. */
+
+#ifndef file_enum_DEFINED /* also defined in gp.h */
+# define file_enum_DEFINED
+struct file_enum_s; /* opaque to client, defined by implementors */
+typedef struct file_enum_s file_enum;
+#endif
+
+/* Define an opaque type for parameter lists. */
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+#endif
+
+/* Define an opaque type for streams. */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+#endif
+
+/* Definition of IODevice procedures */
+/* Note that file names for fopen, delete, rename, and status */
+/* are C strings, not pointer + length. */
+/* Note also that "streams" are a higher-level concept; */
+/* the open_device and open_file procedures are normally NULL. */
+
+struct gx_io_device_procs_s {
+
+#define iodev_proc_init(proc)\
+ int proc(P2(gx_io_device *iodev, gs_memory_t *mem))
+ iodev_proc_init((*init)); /* one-time initialization */
+
+#define iodev_proc_open_device(proc)\
+ int proc(P4(gx_io_device *iodev, const char *access, stream **ps,\
+ gs_memory_t *mem))
+ iodev_proc_open_device((*open_device));
+
+#define iodev_proc_open_file(proc)\
+ int proc(P6(gx_io_device *iodev, const char *fname, uint namelen,\
+ const char *access, stream **ps, gs_memory_t *mem))
+ iodev_proc_open_file((*open_file));
+
+ /* fopen was changed in release 2.9.6, */
+ /* and again in 3.20 to return the real fname separately */
+
+#define iodev_proc_fopen(proc)\
+ int proc(P6(gx_io_device *iodev, const char *fname, const char *access,\
+ FILE **pfile, char *rfname, uint rnamelen))
+ iodev_proc_fopen((*fopen));
+
+#define iodev_proc_fclose(proc)\
+ int proc(P2(gx_io_device *iodev, FILE *file))
+ iodev_proc_fclose((*fclose));
+
+#define iodev_proc_delete_file(proc)\
+ int proc(P2(gx_io_device *iodev, const char *fname))
+ iodev_proc_delete_file((*delete_file));
+
+#define iodev_proc_rename_file(proc)\
+ int proc(P3(gx_io_device *iodev, const char *from, const char *to))
+ iodev_proc_rename_file((*rename_file));
+
+#define iodev_proc_file_status(proc)\
+ int proc(P3(gx_io_device *iodev, const char *fname, struct stat *pstat))
+ iodev_proc_file_status((*file_status));
+
+#define iodev_proc_enumerate_files(proc)\
+ file_enum *proc(P4(gx_io_device *iodev, const char *pat, uint patlen,\
+ gs_memory_t *mem))
+ iodev_proc_enumerate_files((*enumerate_files));
+
+#define iodev_proc_enumerate_next(proc)\
+ uint proc(P3(file_enum *pfen, char *ptr, uint maxlen))
+ iodev_proc_enumerate_next((*enumerate_next));
+
+#define iodev_proc_enumerate_close(proc)\
+ void proc(P1(file_enum *pfen))
+ iodev_proc_enumerate_close((*enumerate_close));
+
+ /* Added in release 2.9 */
+
+#define iodev_proc_get_params(proc)\
+ int proc(P2(gx_io_device *iodev, gs_param_list *plist))
+ iodev_proc_get_params((*get_params));
+
+#define iodev_proc_put_params(proc)\
+ int proc(P2(gx_io_device *iodev, gs_param_list *plist))
+ iodev_proc_put_params((*put_params));
+
+};
+
+/* The following typedef is needed because ansi2knr can't handle */
+/* iodev_proc_fopen((*procname)) in a formal argument list. */
+typedef iodev_proc_fopen((*iodev_proc_fopen_t));
+
+/* Default implementations of procedures */
+iodev_proc_init(iodev_no_init);
+iodev_proc_open_device(iodev_no_open_device);
+iodev_proc_open_file(iodev_no_open_file);
+iodev_proc_fopen(iodev_no_fopen);
+iodev_proc_fclose(iodev_no_fclose);
+iodev_proc_delete_file(iodev_no_delete_file);
+iodev_proc_rename_file(iodev_no_rename_file);
+iodev_proc_file_status(iodev_no_file_status);
+iodev_proc_enumerate_files(iodev_no_enumerate_files);
+iodev_proc_get_params(iodev_no_get_params);
+iodev_proc_put_params(iodev_no_put_params);
+/* The %os% implemention of fopen and fclose. */
+/* These are exported for pipes and for %null. */
+iodev_proc_fopen(iodev_os_fopen);
+iodev_proc_fclose(iodev_os_fclose);
+
+/* Get the N'th IODevice. */
+gx_io_device *gs_getiodevice(P1(int));
+#define iodev_default (gs_getiodevice(0))
+
+/* Look up an IODevice name. */
+gx_io_device *gs_findiodevice(P2(const byte *, uint));
+
+/* Get and put IODevice parameters. */
+int gs_getdevparams(P2(gx_io_device *, gs_param_list *));
+int gs_putdevparams(P2(gx_io_device *, gs_param_list *));
+
+/* Convert an OS error number to a PostScript error */
+/* if opening a file fails. */
+int gs_fopen_errno_to_code(P1(int));
+
+/* Test whether a string is equal to a character. */
+/* (This is used for access testing in file_open procedures.) */
+#define streq1(str, chr)\
+ ((str)[0] == (chr) && (str)[1] == 0)
+
+/* Finally, the IODevice structure itself. */
+#define gx_io_device_common\
+ const char *dname; /* the IODevice name */\
+ const char *dtype; /* the type returned by c'devparams */\
+ gx_io_device_procs procs
+struct gx_io_device_s {
+ gx_io_device_common;
+};
diff --git a/gs/src/gxistate.h b/gs/src/gxistate.h
new file mode 100644
index 000000000..4a76c141a
--- /dev/null
+++ b/gs/src/gxistate.h
@@ -0,0 +1,216 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxistate.h */
+/* Imager state definition */
+
+#ifndef gxistate_INCLUDED
+# define gxistate_INCLUDED
+
+#include "gscsel.h"
+#include "gsropt.h"
+#include "gxcvalue.h"
+#include "gxfixed.h"
+#include "gxline.h"
+#include "gxmatrix.h"
+#include "gxtmap.h"
+
+/*
+ * Define the subset of the PostScript graphics state that the imager
+ * library API needs. The definition of this subset is subject to change
+ * as we come to understand better the boundary between the imager and
+ * the interpreter. In particular, the imager state currently INCLUDES
+ * the following:
+ * line parameters: cap, join, miter limit, dash pattern
+ * transformation matrix (CTM)
+ * logical operation: RasterOp, transparency
+ * color modification: alpha, rendering algorithm
+ * overprint flag
+ * rendering tweaks: flatness, fill adjustment, stroke adjust flag,
+ * accurate curves flag
+ * color rendering information:
+ * halftone, halftone phases
+ * transfer functions
+ * black generation, undercolor removal
+ * CIE rendering tables
+ * halftone and pattern caches
+ * The imager state currently EXCLUDES the following:
+ * graphics state stack
+ * default CTM
+ * path
+ * clipping path
+ * color specification: color, color space
+ * font
+ * device
+ * caches for many of the above
+ */
+
+/*
+ * Define the color rendering state information.
+ * This should be a separate object (or at least a substructure),
+ * but doing this would require editing too much code.
+ */
+
+/* Opaque types referenced by the color rendering state. */
+#ifndef gs_halftone_DEFINED
+# define gs_halftone_DEFINED
+typedef struct gs_halftone_s gs_halftone;
+#endif
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+#endif
+
+/*
+ * We need some special memory management for the components of a
+ * c.r. state, as indicated by the following notations on the elements:
+ * (RC) means the element is reference-counted.
+ * (Shared) means the element is shared among an arbitrary number of
+ * c.r. states and is never freed.
+ * (Owned) means exactly one c.r. state references the element,
+ * and it is guaranteed that no references to it will outlive
+ * the c.r. state itself.
+ */
+
+/* Define the interior structure of a transfer function. */
+typedef struct gx_transfer_colored_s {
+ /* The components must be in this order: */
+ gx_transfer_map *red; /* (RC) */
+ gx_transfer_map *green; /* (RC) */
+ gx_transfer_map *blue; /* (RC) */
+ gx_transfer_map *gray; /* (RC) */
+} gx_transfer_colored;
+typedef union gx_transfer_s {
+ gx_transfer_map *indexed[4]; /* (RC) */
+ gx_transfer_colored colored;
+} gx_transfer;
+
+#define gs_color_rendering_state_common\
+\
+ /* Halftone screen: */\
+\
+ gs_halftone *halftone; /* (RC) */\
+ gs_int_point screen_phase[gs_color_select_count];\
+ /* dev_ht depends on halftone and device resolution. */\
+ gx_device_halftone *dev_ht; /* (Owned) */\
+ /* The contents of ht_cache depend on dev_ht. */\
+ struct gx_ht_cache_s *ht_cache; /* (Shared) by all gstates */\
+\
+ /* Color (device-dependent): */\
+\
+ struct gs_cie_render_s *cie_render; /* (RC) may be 0 */\
+ gx_transfer_map *black_generation; /* (RC) may be 0 */\
+ gx_transfer_map *undercolor_removal; /* (RC) may be 0 */\
+ /* set_transfer holds the transfer functions specified by */\
+ /* set[color]transfer; effective_transfer includes the */\
+ /* effects of overrides by TransferFunctions in halftone */\
+ /* dictionaries. (In Level 1 systems, set_transfer and */\
+ /* effective_transfer are always the same.) */\
+ gx_transfer set_transfer; /* members are (RC) */\
+ gx_transfer effective_transfer; /* see below */\
+\
+ /* Color caches: */\
+\
+ /* cie_joint_caches depend on cie_render and */\
+ /* the color space. */\
+ struct gx_cie_joint_caches_s *cie_joint_caches; /* (RC) */\
+ /* cmap_procs depend on the device's color_info. */\
+ const struct gx_color_map_procs_s *cmap_procs; /* static */\
+ /* The contents of pattern_cache depend on the */\
+ /* the color space and the device's color_info and */\
+ /* resolution. */\
+ struct gx_pattern_cache_s *pattern_cache /* (Shared) by all gstates */
+
+/*
+ * Enumerate the reference-counted pointers in a c.r. state. Note that
+ * effective_transfer doesn't contribute to the reference count: it points
+ * either to the same objects as set_transfer, or to objects in a halftone
+ * structure that someone else worries about.
+ */
+#define gs_cr_state_do_rc_ptrs(m)\
+ m(halftone) m(cie_render) m(black_generation) m(undercolor_removal)\
+ m(set_transfer.colored.red) m(set_transfer.colored.green)\
+ m(set_transfer.colored.blue) m(set_transfer.colored.gray)\
+ m(cie_joint_caches)
+
+/* Enumerate the pointers in a c.r. state. */
+#define gs_cr_state_do_ptrs(m)\
+ m(0,halftone) m(1,dev_ht) m(2,ht_cache)\
+ m(3,cie_render) m(4,black_generation) m(5,undercolor_removal)\
+ m(6,set_transfer.colored.red) m(7,set_transfer.colored.green)\
+ m(8,set_transfer.colored.blue) m(9,set_transfer.colored.gray)\
+ m(10,effective_transfer.colored.red) m(11,effective_transfer.colored.green)\
+ m(12,effective_transfer.colored.blue) m(13,effective_transfer.colored.gray)\
+ m(14,cie_joint_caches) m(15,pattern_cache)
+#define st_cr_state_num_ptrs 16
+
+/* Define the imager state structure itself. */
+#define gs_imager_state_common\
+ gs_memory_t *memory;\
+ gx_line_params line_params;\
+ gs_matrix_fixed ctm;\
+ gs_logical_operation_t log_op;\
+ gx_color_value alpha;\
+ bool overprint;\
+ float flatness;\
+ gs_fixed_point fill_adjust; /* fattening for fill */\
+ bool stroke_adjust;\
+ bool accurate_curves;\
+ gs_color_rendering_state_common
+#define st_imager_state_num_ptrs\
+ (st_line_params_num_ptrs + st_cr_state_num_ptrs)
+/* Access macros */
+#define ctm_only(pis) (*(const gs_matrix *)&(pis)->ctm)
+#define ctm_only_writable(pis) (*(gs_matrix *)&(pis)->ctm)
+#define set_ctm_only(pis, mat) (*(gs_matrix *)&(pis)->ctm = (mat))
+#define gs_init_rop(pis) ((pis)->log_op = lop_default)
+#define gs_currentlineparams_inline(pis) (&(pis)->line_params)
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+
+struct gs_imager_state_s {
+ gs_imager_state_common;
+};
+
+/* Initialization for gs_imager_state */
+#define gs_imager_state_initial(scale)\
+ 0, { gx_line_params_initial },\
+ { scale, 0.0, 0.0, -(scale), 0.0, 0.0 },\
+ lop_default, gx_max_color_value, 0/*false*/, 1.0,\
+ { fixed_half, fixed_half }, 0/*false*/, 0/*false*/
+
+#define private_st_imager_state() /* in gsstate.c */\
+ gs_private_st_composite(st_imager_state, gs_imager_state, "gs_imager_state",\
+ imager_state_enum_ptrs, imager_state_reloc_ptrs)
+
+/* Initialize an imager state, other than the parts covered by */
+/* gs_imager_state_initial. */
+/* The halftone, dev_ht, and ht_cache elements are not set or used. */
+int gs_imager_state_initialize(P2(gs_imager_state *pis, gs_memory_t *mem));
+
+/* Release an imager state. */
+void gs_imager_state_release(P1(gs_imager_state *pis));
+
+#endif /* gxistate_INCLUDED */
diff --git a/gs/src/gxline.h b/gs/src/gxline.h
new file mode 100644
index 000000000..3e7abfe38
--- /dev/null
+++ b/gs/src/gxline.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxline.h */
+/* Private line parameter definitions */
+
+#ifndef gxline_INCLUDED
+# define gxline_INCLUDED
+
+#include "gslparam.h"
+
+/* Line parameter structures */
+/* gx_dash_params are never instantiated by themselves. */
+typedef struct gx_dash_params_s {
+ float *pattern;
+ uint pattern_size;
+ float offset;
+ bool adapt;
+ /* The rest of the parameters are computed from the above */
+ float pattern_length; /* total of all pattern elements */
+ bool init_ink_on; /* true if ink is initially on */
+ int init_index; /* initial index in pattern */
+ float init_dist_left;
+} gx_dash_params;
+#define gx_dash_params_initial\
+ NULL, 0, 0.0, 0/*false*/, 0.0, 1/*true*/, 0, 0.0
+typedef struct gx_line_params_s {
+ float half_width; /* one-half line width */
+ gs_line_cap cap;
+ gs_line_join join;
+ float miter_limit;
+ float miter_check; /* computed from miter limit, */
+ /* see gx_set_miter_limit and */
+ /* gs_stroke */
+ float dot_length;
+ float dot_length_absolute; /* if true, dot_length is 1/72" units */
+ gx_dash_params dash;
+} gx_line_params;
+#define gx_set_line_width(plp, wid)\
+ ((plp)->half_width = (wid) / 2)
+#define gx_current_line_width(plp)\
+ ((plp)->half_width * 2)
+int gx_set_miter_limit(P2(gx_line_params *, floatp));
+#define gx_current_miter_limit(plp)\
+ ((plp)->miter_limit)
+int gx_set_dash(P5(gx_dash_params *, const float *, uint, floatp,
+ gs_memory_t *));
+#define gx_set_dash_adapt(pdp, adpt) ((pdp)->adapt = (adpt))
+int gx_set_dot_length(P3(gx_line_params *, floatp, bool));
+/* See gsline.c for the computation of miter_check. */
+#define gx_line_params_initial\
+ 0.0, gs_cap_butt, gs_join_miter, 10.0, 0.20305866, 0.0, 0/*false*/,\
+ { gx_dash_params_initial }
+
+#endif /* gxline_INCLUDED */
diff --git a/gs/src/gxlum.h b/gs/src/gxlum.h
new file mode 100644
index 000000000..191aad308
--- /dev/null
+++ b/gs/src/gxlum.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxlum.h */
+/* Luminance computation parameters for Ghostscript */
+
+/* Color weights used for computing luminance. */
+#define lum_red_weight 30
+#define lum_green_weight 59
+#define lum_blue_weight 11
+#define lum_all_weights (lum_red_weight + lum_green_weight + lum_blue_weight)
diff --git a/gs/src/gxmatrix.h b/gs/src/gxmatrix.h
new file mode 100644
index 000000000..5927b3bbe
--- /dev/null
+++ b/gs/src/gxmatrix.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxmatrix.h */
+/* Internal matrix routines for Ghostscript library */
+
+#ifndef gxmatrix_INCLUDED
+# define gxmatrix_INCLUDED
+
+#include "gsmatrix.h"
+
+/*
+ * Define a matrix with a cached fixed-point copy of the translation.
+ * This is only used by a few routines in gscoord.c; they are responsible
+ * for ensuring the validity of the cache. Note that the floating point
+ * tx/ty values may be too large to fit in a fixed values; txy_fixed_valid
+ * is false if this is the case, and true otherwise.
+ */
+typedef struct gs_matrix_fixed_s {
+ _matrix_body;
+ fixed tx_fixed, ty_fixed;
+ bool txy_fixed_valid;
+} gs_matrix_fixed;
+
+/* Coordinate transformations to fixed point. */
+int gs_point_transform2fixed(P4(const gs_matrix_fixed *, floatp, floatp,
+ gs_fixed_point *));
+int gs_distance_transform2fixed(P4(const gs_matrix_fixed *, floatp, floatp,
+ gs_fixed_point *));
+
+/*
+ * Define the fixed-point coefficient structure for avoiding
+ * floating point in coordinate transformations.
+ * Currently this is used only by the Type 1 font interpreter.
+ * The setup is in gscoord.c.
+ */
+typedef struct {
+ long l;
+ fixed f;
+} coeff1;
+typedef struct {
+ coeff1 xx, xy, yx, yy;
+ int skewed;
+ int shift; /* see m_fixed */
+ int max_bits; /* max bits of coefficient */
+ fixed round; /* ditto */
+} fixed_coeff;
+/*
+ * Multiply a fixed whose integer part usually does not exceed max_bits
+ * in magnitude by a coefficient from a fixed_coeff.
+ * We can use a faster algorithm if the fixed is an integer within
+ * a range that doesn't cause the multiplication to overflow an int.
+ */
+#define m_fixed(v, c, fc, maxb)\
+ (((v) + (fixed_1 << (maxb - 1))) &\
+ ((-fixed_1 << maxb) | _fixed_fraction_v) ? /* out of range, or has fraction */\
+ (fixed2int_var(v) * (fc).c.f +\
+ arith_rshift(fixed_fraction(v) * (fc).c.f + fixed_half, _fixed_shift)) :\
+ arith_rshift(fixed2int_var(v) * (fc).c.l + (fc).round, (fc).shift))
+
+#endif /* gxmatrix_INCLUDED */
diff --git a/gs/src/gxobj.h b/gs/src/gxobj.h
new file mode 100644
index 000000000..6f4cb0bec
--- /dev/null
+++ b/gs/src/gxobj.h
@@ -0,0 +1,209 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxobj.h */
+/* Memory manager implementation structures for Ghostscript */
+#include "gxbitmap.h"
+
+/* ================ Objects ================ */
+
+/*
+ * Object headers come in a number of different varieties.
+ * All arise from the same basic form, which is
+ -l- -lmsize/mark/back-
+ -size-
+ -type/reloc-
+ * l (large) is a single bit. The size of lmsize/mark/back, size, and type
+ * varies according to the environment. On machines with N:16 segmented
+ * addressing, 16-bit ints, and no alignment requirement more severe than
+ * 2 bytes, we can fit an object header into 8 bytes by making the first
+ * two fields only 16 bits wide. On all other machines, we let the
+ * lmsize/mark/back field be 1 bit shorter than a uint, and round the header
+ * size up to the next multiple of the most severe alignment restriction
+ * (4 or 8 bytes). Miraculously, we can do all this without any case testing.
+ *
+ * The mark/back field is used for the mark during the marking phase of
+ * garbage collection, and for a back pointer value during the compaction
+ * phase. Since we want to be able to collect local VM independently of
+ * global VM, we need two different distinguished mark values:
+ * - For local objects that have not been traced and should be freed
+ * (compacted out), we use 1...11 in the mark field (o_unmarked).
+ * - For global objects that have not been traced but should be kept,
+ * we use 1...10 in the mark field (o_untraced).
+ * Note that neither of these values is a possible real relocation value.
+ *
+ * The lmsize field of large objects overlaps mark and back, so we must
+ * handle these functions for large objects in some other way.
+ * Since large objects cannot be moved or relocated, we don't need the
+ * back field for them; we allocate 2 bits for the 3 mark values.
+ */
+/*
+ * The back pointer's meaning depends on whether the object is
+ * free (unmarked) or in use (marked):
+ * - In free objects, the back pointer is an offset from the object
+ * header back to a chunk_head_t structure that contains the location
+ * to which all the data in this chunk will get moved; the reloc field
+ * contains the amount by which the following run of useful objects
+ * will be relocated downwards.
+ * - In useful objects, the back pointer is an offset from the object
+ * back to the previous free object; the reloc field is not used (it
+ * overlays the type field).
+ * These two cases can be distinguished when scanning a chunk linearly,
+ * but when simply examining an object via a pointer, the chunk pointer
+ * is also needed.
+ */
+#define obj_flag_bits 1
+#define obj_mb_bits (arch_sizeof_int * 8 - obj_flag_bits)
+#define obj_ls_bits (obj_mb_bits - 2)
+#define o_unmarked (((uint)1 << obj_mb_bits) - 1)
+#define o_l_unmarked (o_unmarked & 3)
+#define o_set_unmarked_large(pp) (pp)->o_lmark = o_l_unmarked
+#define o_set_unmarked(pp)\
+ if ( (pp)->o_large ) o_set_unmarked_large(pp);\
+ else (pp)->o_smark = o_unmarked
+#define o_is_unmarked_large(pp) ((pp)->o_lmark == o_l_unmarked)
+#define o_is_unmarked(pp)\
+ ((pp)->o_large ? o_is_unmarked_large(pp) :\
+ ((pp)->o_smark == o_unmarked))
+#define o_untraced (((uint)1 << obj_mb_bits) - 2)
+#define o_l_untraced (o_untraced & 3)
+#define o_set_untraced(pp)\
+ if ( (pp)->o_large ) (pp)->o_lmark = o_l_untraced;\
+ else (pp)->o_smark = o_untraced
+#define o_is_untraced(pp)\
+ ((pp)->o_large ? (pp)->o_lmark == o_l_untraced :\
+ ((pp)->o_smark == o_untraced))
+#define o_marked 0
+#define o_mark_large(pp) (pp)->o_lmark = o_marked
+#define o_mark(pp)\
+ if ( (pp)->o_large ) o_mark_large(pp);\
+ else (pp)->o_smark = o_marked
+#define obj_back_shift obj_flag_bits
+#define obj_back_scale (1 << obj_back_shift)
+typedef struct obj_header_data_s {
+ union _f {
+ struct _h { unsigned large : 1; } h;
+ struct _l { unsigned _ : 1, lmark : 2, lsize : obj_ls_bits; } l;
+ struct _m { unsigned _ : 1, smark : obj_mb_bits; } m;
+ struct _b { unsigned _ : 1, back : obj_mb_bits; } b;
+ } f;
+ uint size;
+ union _t {
+ gs_memory_type_ptr_t type;
+ uint reloc;
+ } t;
+} obj_header_data_t;
+
+/*
+ * Define the alignment modulus for aligned objects. We assume all
+ * alignment values are powers of 2; we can avoid nested 'max'es that way.
+ * The final | is because back pointer values are divided by obj_back_scale,
+ * so objects must be aligned at least 0 mod obj_back_scale.
+ */
+#define obj_align_mod\
+ (((arch_align_long_mod - 1) | (arch_align_ptr_mod - 1) |\
+ (arch_align_double_mod - 1) | (align_bitmap_mod - 1) |\
+ (obj_back_scale - 1)) + 1)
+/* The only possible values for obj_align_mod are 4, 8, or 16.... */
+#if obj_align_mod == 4
+# define log2_obj_align_mod 2
+#else
+#if obj_align_mod == 8
+# define log2_obj_align_mod 3
+#else
+#if obj_align_mod == 16
+# define log2_obj_align_mod 4
+#endif
+#endif
+#endif
+#define obj_align_mask (obj_align_mod-1)
+#define obj_align_round(siz)\
+ (uint)(((siz) + obj_align_mask) & -obj_align_mod)
+#define obj_size_round(siz)\
+ obj_align_round((siz) + sizeof(obj_header_t))
+
+/* Define the real object header type, taking alignment into account. */
+struct obj_header_s { /* must be a struct because of forward reference */
+ union _d {
+ obj_header_data_t o;
+ byte _pad[round_up(sizeof(obj_header_data_t), obj_align_mod)];
+ } d;
+};
+
+/* Define some reasonable abbreviations for the fields. */
+#define o_large d.o.f.h.large
+#define o_lsize d.o.f.l.lsize
+#define o_lmark d.o.f.l.lmark
+#define o_back d.o.f.b.back
+#define o_smark d.o.f.m.smark
+#define o_size d.o.size
+#define o_type d.o.t.type
+#define o_nreloc d.o.t.reloc
+
+/*
+ * The macros for getting the sizes of objects all take pointers to
+ * the object header, for use when scanning storage linearly.
+ */
+#define pre_obj_small_size(pp)\
+ ((pp)->o_size)
+
+#if arch_sizeof_long > arch_sizeof_int
+
+ /* Large objects need to use o_lsize. */
+
+#define pre_obj_large_size(pp)\
+ (((ulong)(pp)->o_lsize << (arch_sizeof_int * 8)) + (pp)->o_size)
+#define pre_obj_set_large_size(pp, lsize)\
+ ((pp)->o_lsize = (lsize) >> (arch_sizeof_int * 8),\
+ (pp)->o_size = (uint)(lsize))
+#define pre_obj_contents_size(pp)\
+ ((pp)->o_large ? pre_obj_large_size(pp) : pre_obj_small_size(pp))
+
+#else
+
+ /* Large objects don't need to use o_lsize. */
+
+#define pre_obj_large_size(pp)\
+ pre_obj_small_size(pp)
+#define pre_obj_set_large_size(pp, lsize)\
+ ((pp)->o_lsize = 0,\
+ (pp)->o_size = (lsize))
+#define pre_obj_contents_size(pp)\
+ pre_obj_small_size(pp)
+
+#endif
+
+#define pre_obj_rounded_size(pp)\
+ obj_size_round(pre_obj_contents_size(pp))
+#define pre_obj_next(pp)\
+ ((obj_header_t *)((byte *)(pp) + obj_align_round(\
+ pre_obj_contents_size(pp) + sizeof(obj_header_t) )))
+
+/*
+ * Define the header that free objects point back to when relocating.
+ * Every chunk, including inner chunks, has one of these.
+ */
+typedef struct chunk_head_s {
+ byte *dest; /* destination for objects */
+#if obj_align_mod > arch_sizeof_ptr
+ byte *_pad[obj_align_mod / arch_sizeof_ptr - 1];
+#endif
+ obj_header_t free; /* header for a free object, */
+ /* in case the first real object */
+ /* is in use */
+} chunk_head_t;
diff --git a/gs/src/gxop1.h b/gs/src/gxop1.h
new file mode 100644
index 000000000..276b83e8b
--- /dev/null
+++ b/gs/src/gxop1.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 1991, 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxop1.h */
+/* Type 1 state shared between interpreter and compiled fonts. */
+
+/*
+ * The current point (px,py) in the Type 1 interpreter state is not
+ * necessarily the same as the current position in the path being built up.
+ * Specifically, (px,py) may not reflect adjustments for hinting,
+ * whereas the current path position does reflect those adjustments.
+ */
+
+/* Define the shared Type 1 interpreter state. */
+#define max_coeff_bits 11 /* max coefficient in char space */
+typedef struct gs_op1_state_s {
+ struct gx_path_s *ppath;
+ struct gs_type1_state_s *pcis;
+ fixed_coeff fc;
+ gs_fixed_point co; /* character origin (device space) */
+ gs_fixed_point p; /* current point (device space) */
+} gs_op1_state;
+typedef gs_op1_state _ss *is_ptr;
+
+/* Define the state used by operator procedures. */
+/* These macros refer to a current instance (s) of gs_op1_state. */
+#define sppath s.ppath
+#define sfc s.fc
+#define spt s.p
+#define ptx s.p.x
+#define pty s.p.y
+
+/* Accumulate relative coordinates */
+/****** THESE ARE NOT ACCURATE FOR NON-INTEGER DELTAS. ******/
+/* This probably doesn't make any difference in practice. */
+#define c_fixed(d, c) m_fixed(d, c, sfc, max_coeff_bits)
+#define accum_x(dx)\
+ do {\
+ ptx += c_fixed(dx, xx);\
+ if ( sfc.skewed ) pty += c_fixed(dx, xy);\
+ } while ( 0 )
+#define accum_y(dy)\
+ do {\
+ pty += c_fixed(dy, yy);\
+ if ( sfc.skewed ) ptx += c_fixed(dy, yx);\
+ } while ( 0 )
+void accum_xy_proc(P3(is_ptr ps, fixed dx, fixed dy));
+#define accum_xy(dx,dy)\
+ accum_xy_proc(&s, dx, dy)
+
+/* Define operator procedures. */
+int gs_op1_closepath(P1(is_ptr ps));
+int gs_op1_rrcurveto(P7(is_ptr ps, fixed dx1, fixed dy1,
+ fixed dx2, fixed dy2, fixed dx3, fixed dy3));
diff --git a/gs/src/gxpageq.c b/gs/src/gxpageq.c
new file mode 100644
index 000000000..c2d67a2ba
--- /dev/null
+++ b/gs/src/gxpageq.c
@@ -0,0 +1,305 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpageq.c */
+/* Page queue implementation */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxclist.h"
+#include "gxpageq.h"
+#include "gserrors.h"
+
+/* ------------------- Global Data -----------------------*/
+/* Structure descriptor for GC */
+private_st_gx_page_queue_entry();
+private_st_gx_page_queue();
+
+/* ------------ Forward Decl's --------------------------- */
+private gx_page_queue_entry * /* removed entry, 0 if none avail */
+gx_page_queue_remove_first(P1(
+ gx_page_queue *queue /* page queue to retrieve from */
+));
+
+
+/* --------------------Procedures-------------------------*/
+
+/* ------- page_queue_entry alloc/free --------- */
+/* Allocate & init a gx_page_queue_entry */
+gx_page_queue_entry* /* rets ptr to allocated object, 0 if VM error */
+gx_page_queue_entry_alloc(
+ gx_page_queue *queue /* queue that entry is being alloc'd for */
+) {
+ gx_page_queue_entry *entry
+ = gs_alloc_struct(queue->memory, gx_page_queue_entry,
+ &st_gx_page_queue_entry, "gx_page_queue_entry_alloc");
+ if (entry != 0)
+ { entry->next = 0;
+ entry->queue = queue;
+ }
+ return entry;
+ }
+
+/* Free a gx_page_queue_entry allocated w/gx_page_queue_entry_alloc */
+void
+gx_page_queue_entry_free(
+ gx_page_queue_entry *entry /* entry to free up */
+) {
+ gs_free_object(entry->queue->memory, entry, "gx_page_queue_entry_free");
+ }
+
+/* -------- page_queue init/dnit ---------- */
+/* Initialize a gx_page_queue object */
+int /* -ve error code, or 0 */
+gx_page_queue_init(
+ gx_page_queue *queue, /* page queue to init */
+ gs_memory_t *memory /* allocator for dynamic memory */
+) {
+ queue->memory = memory;
+ queue->monitor = gx_monitor_alloc(memory); /* alloc monitor to serialize */
+ queue->entry_count = 0;
+ queue->dequeue_in_progress = false;
+ queue->render_req_sema = gx_semaphore_alloc(memory);
+ queue->enable_render_done_signal = false;
+ queue->render_done_sema = gx_semaphore_alloc(memory);
+ queue->first_in = queue->last_in = 0;
+ queue->reserve_entry = gx_page_queue_entry_alloc(queue);
+
+ if (queue->monitor && queue->render_req_sema && queue->render_done_sema
+ && queue->reserve_entry)
+ return 0;
+ else
+ {
+ gx_page_queue_dnit(queue);
+ return gs_error_VMerror;
+ }
+ }
+
+/* Dnitialize a gx_page_queue object */
+void
+gx_page_queue_dnit(
+ gx_page_queue *queue /* page queue to dnit */
+) {
+ /* Deallocate any left-over queue entries */
+ gx_page_queue_entry *entry;
+ while ( ( entry = gx_page_queue_remove_first(queue) ) != 0 )
+ gx_page_queue_entry_free(entry);
+
+ /* Free dynamic objects */
+ if (queue->monitor)
+ {
+ gx_monitor_free(queue->monitor);
+ queue->monitor = 0;
+ }
+ if (queue->render_req_sema)
+ {
+ gx_semaphore_free(queue->render_req_sema);
+ queue->render_req_sema = 0;
+ }
+ if (queue->render_done_sema)
+ {
+ gx_semaphore_free(queue->render_done_sema);
+ queue->render_done_sema = 0;
+ }
+ if (queue->reserve_entry)
+ {
+ gx_page_queue_entry_free(queue->reserve_entry);
+ queue->reserve_entry = 0;
+ }
+ }
+
+/* -------- low-level queue add/remove ---------- */
+/* Retrieve & remove firstin queue entry */
+private gx_page_queue_entry * /* removed entry, 0 if none avail */
+gx_page_queue_remove_first(
+ gx_page_queue *queue /* page queue to retrieve from */
+) {
+ gx_page_queue_entry *entry = 0; /* assume failure */
+
+ /* Enter monitor */
+ gx_monitor_enter(queue->monitor);
+
+ /* Get the goods */
+ if (queue->entry_count)
+ {
+ entry = queue->first_in;
+ queue->first_in = entry->next;
+ if (queue->last_in == entry)
+ queue->last_in = 0;
+ --queue->entry_count;
+ }
+
+ /* exit monitor */
+ gx_monitor_leave(queue->monitor);
+
+ return entry;
+ }
+
+/* Add entry to queue at end */
+private void
+gx_page_queue_add_last(
+ gx_page_queue_entry *entry /* entry to add */
+) {
+ gx_page_queue *queue = entry->queue;
+
+ /* Enter monitor */
+ gx_monitor_enter(queue->monitor);
+
+ /* Add the goods */
+ entry->next = 0;
+ if (queue->last_in != 0)
+ queue->last_in->next = entry;
+ queue->last_in = entry;
+ if (queue->first_in == 0)
+ queue->first_in = entry;
+ ++queue->entry_count;
+
+ /* exit monitor */
+ gx_monitor_leave(queue->monitor);
+ }
+
+/* --------- low-level synchronization ---------- */
+/* Wait for a single page to finish rendering (if any pending) */
+int /* rets 0 if no pages were waiting for rendering, 1 if actually waited */
+gx_page_queue_wait_one_page(
+ gx_page_queue *queue /* queue to wait on */
+) {
+ int code;
+ gx_monitor_enter(queue->monitor);
+ if (!queue->entry_count && !queue->dequeue_in_progress)
+ {
+ code = 0;
+ gx_monitor_leave(queue->monitor);
+ }
+ else
+ {
+ /* request acknowledgement on render done */
+ queue->enable_render_done_signal = true;
+
+ /* exit monitor & wait for acknowlegement*/
+ gx_monitor_leave(queue->monitor);
+ gx_semaphore_wait(queue->render_done_sema);
+ code = 1;
+ }
+ return code;
+ }
+
+/* Wait for page queue to become empty */
+void
+gx_page_queue_wait_until_empty(
+ gx_page_queue *queue /* page queue to wait on */
+) {
+ while ( gx_page_queue_wait_one_page(queue) )
+ ;
+ }
+
+/* ----------- Synchronized page_queue get/put routines ------ */
+/* Add an entry to page queue for rendering w/sync to renderer */
+void
+gx_page_queue_enqueue(
+ gx_page_queue_entry *entry /* entry to add */
+) {
+ gx_page_queue *queue = entry->queue;
+
+ /* Add the goods to queue, & signal it */
+ gx_page_queue_add_last(entry);
+ gx_semaphore_signal(queue->render_req_sema);
+ }
+
+/* Add page to a page queue */
+/* Even if an error is returned, entry will have been added to queue! */
+int /* rets 0 ok, gs_error_VMerror if error */
+gx_page_queue_add_page(
+ gx_page_queue *queue, /* page queue to add to */
+ gx_page_queue_action_t action, /* action code to queue */
+ const gx_band_page_info *page_info, /* bandinfo incl. bandlist (or 0) */
+ int page_count /* see comments in gdevprna.c */
+) {
+ int code = 0;
+
+ /* Allocate a new page queue entry */
+ gx_page_queue_entry *entry
+ = gx_page_queue_entry_alloc(queue);
+ if (!entry)
+ {
+ /* Use reserve page queue entry */
+ gx_monitor_enter(queue->monitor); /* not strictly necessary */
+ entry = queue->reserve_entry;
+ queue->reserve_entry = 0;
+ gx_monitor_leave(queue->monitor);
+ }
+
+ /* Fill in page queue entry with info from device */
+ entry->action = action;
+ if (page_info != 0)
+ entry->page_info = *page_info;
+ entry->num_copies = page_count;
+
+ /* Stick onto page queue & signal */
+ gx_page_queue_enqueue(entry);
+
+ /* If a new reserve entry is needed, wait till enough mem is avail */
+ while (!queue->reserve_entry)
+ {
+ queue->reserve_entry = gx_page_queue_entry_alloc(queue);
+ if ( !queue->reserve_entry && !gx_page_queue_wait_one_page(queue) )
+ {
+ /* Should never happen: all pages rendered & still can't get memory: give up! */
+ code = gs_note_error(gs_error_Fatal);
+ break;
+ }
+ }
+ return code;
+ }
+
+/* Wait for & get next page queue entry */
+gx_page_queue_entry * /* removed entry */
+gx_page_queue_start_dequeue(
+ gx_page_queue *queue /* page queue to retrieve from */
+) {
+ gx_semaphore_wait(queue->render_req_sema);
+ queue->dequeue_in_progress = true;
+ return gx_page_queue_remove_first(queue);
+ }
+
+/* After rendering page gotten w/gx_page_queue_dequeue, call this to ack */
+void
+gx_page_queue_finish_dequeue(
+ gx_page_queue_entry *entry /* entry that was retrieved to delete */
+) {
+ gx_page_queue *queue = entry->queue;
+
+ gx_monitor_enter(queue->monitor);
+ if (queue->enable_render_done_signal)
+ {
+ queue->enable_render_done_signal = false;
+ gx_semaphore_signal(queue->render_done_sema);
+ }
+ queue->dequeue_in_progress = false;
+
+ /* Delete the previously-allocated entry, do inside monitor in case */
+ /* this is the reserve entry & is the only memory in the universe; */
+ /* in that case gx_page_queue_add_page won't be looking for this */
+ /* until the monitor is exited. */
+ gx_page_queue_entry_free(entry);
+
+ gx_monitor_leave(queue->monitor);
+ }
+
diff --git a/gs/src/gxpageq.h b/gs/src/gxpageq.h
new file mode 100644
index 000000000..fb9f48d9c
--- /dev/null
+++ b/gs/src/gxpageq.h
@@ -0,0 +1,186 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpageq.h */
+/* Page queue implementation */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gxpageq_h_INCLUDED)
+
+# define gxpageq_h_INCLUDED
+
+# include "gsmemory.h"
+# include "gxband.h"
+# include "gxsync.h"
+
+
+/* --------------- Data type definitions --------------------- */
+typedef enum {
+ gx_page_queue_action_partial_page,
+ gx_page_queue_action_full_page,
+ gx_page_queue_action_copy_page,
+ gx_page_queue_action_terminate
+} gx_page_queue_action_t;
+
+
+#if !defined(gx_page_queue_defined)
+# define gx_page_queue_defined
+typedef struct gx_page_queue_s gx_page_queue;
+#endif /* defined(gx_page_queue_defined) */
+
+/*
+ * Define a page queue entry object.
+ */
+typedef struct gx_page_queue_entry_s {
+ gx_band_page_info page_info;
+ gx_page_queue_action_t action; /* action code */
+ int num_copies; /* number of copies to render */
+ struct gx_page_queue_entry_s *next; /* link to next in queue */
+ gx_page_queue *queue; /* link to queue the entry is in */
+} gx_page_queue_entry;
+
+#define private_st_gx_page_queue_entry()
+ gs_private_st_ptrs2(st_gx_page_queue_entry, gx_page_queue_entry, "gx_page_queue_entry",\
+ gx_page_queue_entry_enum_ptrs, gx_page_queue_entry_reloc_ptrs, next, queue);
+
+
+/*
+ * Define the structure used to manage a page queue
+ * A page queue is a monitor-locked FIFO which holds completed command
+ * list files ready for rendering.
+ */
+struct gx_page_queue_s {
+ gs_memory_t *memory; /* allocator used to allocate entries */
+ gx_monitor_t *monitor; /* used to serialize access to this structure */
+ int entry_count; /* # elements in page_queue */
+ bool dequeue_in_progress; /* true between start/ & end_dequeue */
+ gx_semaphore_t *render_req_sema; /* sema signalled when page queued */
+ bool enable_render_done_signal; /* enable signals to render_done_sema */
+ gx_semaphore_t *render_done_sema; /* semaphore signaled when (partial) page rendered */
+ gx_page_queue_entry *last_in; /* if <> 0, Last-in queue entry */
+ gx_page_queue_entry *first_in; /* if <> 0, First-in queue entry */
+ gx_page_queue_entry *reserve_entry; /* spare allocation */
+};
+
+#define private_st_gx_page_queue()
+ gs_private_st_ptrs4(st_gx_page_queue, gx_page_queue, "gx_page_queue",\
+ gx_page_queue_enum_ptrs, gx_page_queue_reloc_ptrs, monitor, first_in,\
+ last_in, reserve_entry);
+
+
+/* -------------- Public Procedure Declaraions --------------------- */
+/* All page queue entries must be allocated by this routine. Allocated */
+/* entries are initialized & ready to go */
+gx_page_queue_entry* /* rets ptr to allocated object, 0 if VM error */
+gx_page_queue_entry_alloc(P1(
+ gx_page_queue *queue /* queue that entry is being alloc'd for */
+));
+
+/* All page queues entries must be destroyed by this routine */
+void
+gx_page_queue_entry_free(P1(
+ gx_page_queue_entry *entry /* entry to free up */
+));
+
+/* Init a page queue; this must be done before it can be used. This routine */
+/* allocates & inits various necessary structures and will fail if insufficient */
+/* memory is available. */
+int /* -ve error code, or 0 */
+gx_page_queue_init(P2(
+ gx_page_queue *queue, /* page queue to init */
+ gs_memory_t *memory /* allocator for dynamic memory */
+));
+
+/* Destroy a page queue which was initialized by gx_page_queue_init. Any */
+/* page queue entries in the queue are released and destroyed; dynamic */
+/* allocations are released. */
+void
+gx_page_queue_dnit(P1(
+ gx_page_queue *queue /* page queue to dnit */
+));
+
+/* If there are any pages in queue, wait until one of them finishes rendering. */
+/* Typically called by writer's out-of-memory error handlers that want to wait */
+/* until some memory has been freed. */
+int /* rets 0 if no pages were waiting for rendering, 1 if actually waited */
+gx_page_queue_wait_one_page(P1(
+ gx_page_queue *queue /* queue to wait on */
+));
+
+/* Wait until all (if any) pages in queue have finished rendering. Typically */
+/* called by writer operations which need to drain the page queue before */
+/* continuing. */
+void
+gx_page_queue_wait_until_empty(P1(
+ gx_page_queue *queue /* page queue to wait on */
+));
+
+/* Add a pageq queue entry to the end of the page queue. If an unsatisfied */
+/* reader thread has an outstanding gx_page_queue_start_deque(), wake it up. */
+void
+gx_page_queue_enqueue(P1(
+ gx_page_queue_entry *entry /* entry to add */
+));
+
+/* Allocate & construct a pageq entry, then to the end of the pageq as */
+/* in gx_page_queue_enqueue. If unable to allocate a new pageq entry, uses */
+/* the pre-allocated reserve entry held in the pageq. When using the reserve */
+/* pageq entry, wait until enough pages have been rendered to allocate a new */
+/* reserve for next time -- this should always succeed & returns eFatal if not. */
+/* Unless the reserve was used, does not wait for any rendering to complete. */
+/* Typically called by writer when it has a (partial) page ready for rendering. */
+int /* rets 0 ok, gs_error_Fatal if error */
+gx_page_queue_add_page(P4(
+ gx_page_queue *queue, /* page queue to add to */
+ gx_page_queue_action_t action, /* action code to queue */
+ const gx_band_page_info *page_info, /* bandinfo incl. bandlist */
+ int page_count /* # of copies to print if final "print,"
+ /* 0 if partial page, -1 if cancel */
+));
+
+/* Retrieve the least-recently added queue entry from the pageq. If no */
+/* entry is available, waits on a signal from gx_page_queue_enqueue. Must */
+/* eventually be followed by a call to gx_page_queue_finish_dequeue for the */
+/* same pageq entry. */
+/* Even though the pageq is actually removed from the pageq, a mark is made in */
+/* the pageq to indicate that the pageq is not "empty" until the */
+/* gx_page_queue_finish_dequeue; this is for the benefit of */
+/* gx_page_queue_wait_???, since the completing the current page's rendering */
+/* may free more memory. */
+/* Typically called by renderer thread loop, which looks like: */
+/* do */
+/* { gx_page_queue_start_deqeueue(...); */
+/* render_retrieved_entry(...); */
+/* gx_page_queue_finish_dequeue(...); */
+/* } */
+/* while (some condition); */
+gx_page_queue_entry * /* removed entry */
+gx_page_queue_start_dequeue(P1(
+ gx_page_queue *queue /* page queue to retrieve from */
+));
+
+/* Free the pageq entry, then signal any waiting threads. /*
+/* Typically used to indicate completion of rendering the pageq entry. */
+void
+gx_page_queue_finish_dequeue(P1(
+ gx_page_queue_entry *entry /* entry that was retrieved to delete */
+));
+
+#endif /*!defined(gxpageq_h_INCLUDED)*/
+
diff --git a/gs/src/gxpaint.c b/gs/src/gxpaint.c
new file mode 100644
index 000000000..615f46c35
--- /dev/null
+++ b/gs/src/gxpaint.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpaint.c */
+/* Graphics-state-aware fill and stroke procedures */
+#include "gx.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxhttile.h"
+#include "gxpaint.h"
+#include "gxpath.h"
+
+/* Fill a path. */
+int
+gx_fill_path(gx_path *ppath, gx_device_color *pdevc, gs_state *pgs,
+ int rule, fixed adjust_x, fixed adjust_y)
+{ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_fill_params params;
+
+ params.rule = rule;
+ params.adjust.x = adjust_x;
+ params.adjust.y = adjust_y;
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ params.fill_zero_width = (adjust_x | adjust_y) != 0;
+ return (*dev_proc(dev, fill_path))
+ (dev, (const gs_imager_state *)pgs, ppath, &params, pdevc,
+ pgs->clip_path);
+}
+
+/* Stroke a path for drawing or saving. */
+int
+gx_stroke_fill(gx_path *ppath, gs_state *pgs)
+{ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_stroke_params params;
+
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ return (*dev_proc(dev, stroke_path))
+ (dev, (const gs_imager_state *)pgs, ppath, &params,
+ pgs->dev_color, pgs->clip_path);
+}
+
+int
+gx_stroke_add(gx_path *ppath, gx_path *to_path, gs_state *pgs)
+{ gx_stroke_params params;
+
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ return gx_stroke_path_only(ppath, to_path, pgs->device,
+ (const gs_imager_state *)pgs,
+ &params, NULL, NULL);
+}
diff --git a/gs/src/gxpaint.h b/gs/src/gxpaint.h
new file mode 100644
index 000000000..f5f6a54a7
--- /dev/null
+++ b/gs/src/gxpaint.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpaint.h */
+/* Device coordinate painting interface for Ghostscript library */
+/* Requires gsropt.h, gxfixed.h, gxpath.h */
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+
+/* ------ Graphics-state-aware procedures ------ */
+
+/*
+ * The following procedures use information from the graphics state.
+ * They are implemented in gxpaint.c.
+ */
+
+int gx_fill_path(P6(gx_path *ppath, gx_device_color *pdevc, gs_state *pgs,
+ int rule, fixed adjust_x, fixed adjust_y));
+int gx_stroke_fill(P2(gx_path *ppath, gs_state *pgs));
+int gx_stroke_add(P3(gx_path *ppath, gx_path *to_path, gs_state *pgs));
+
+/* ------ Imager procedures ------ */
+
+/*
+ * Tweak the fill adjustment if necessary so that (nearly) empty
+ * rectangles are guaranteed to produce some output.
+ */
+void gx_adjust_if_empty(P2(const gs_fixed_rect *, gs_fixed_point *));
+
+/*
+ * Compute the amount by which to expand a stroked bounding box to account
+ * for line width, caps and joins. If the amount is too large to fit in
+ * a gs_fixed_point, return gs_error_limitcheck.
+ */
+int gx_stroke_path_expansion(P3(const gs_imager_state *,
+ const gx_path *, gs_fixed_point *));
+/* Backward compatibility */
+#define gx_stroke_expansion(pis, ppt)\
+ gx_stroke_path_expansion(pis, (const gx_path *)0, ppt)
+
+/*
+ * The following procedures do not need a graphics state.
+ * These procedures are implemented in gxfill.c and gxstroke.c.
+ */
+
+/* Define the parameters passed to the imager's filling routine. */
+#ifndef gx_fill_params_DEFINED
+# define gx_fill_params_DEFINED
+typedef struct gx_fill_params_s gx_fill_params;
+#endif
+struct gx_fill_params_s {
+ int rule; /* -1 = winding #, 1 = even/odd */
+ gs_fixed_point adjust;
+ float flatness;
+ bool fill_zero_width; /* if true, make zero-width/height */
+ /* rectangles one pixel wide/high */
+};
+
+#define gx_fill_path_only(ppath, dev, pis, params, pdevc, pcpath)\
+ (*dev_proc(dev, fill_path))(dev, pis, ppath, params, pdevc, pcpath)
+
+/* Define the parameters passed to the imager's stroke routine. */
+#ifndef gx_stroke_params_DEFINED
+# define gx_stroke_params_DEFINED
+typedef struct gx_stroke_params_s gx_stroke_params;
+#endif
+struct gx_stroke_params_s {
+ float flatness;
+};
+
+int gx_stroke_path_only(P7(gx_path *ppath, gx_path *to_path, gx_device *dev,
+ const gs_imager_state *pis,
+ const gx_stroke_params *params,
+ const gx_device_color *pdevc,
+ const gx_clip_path *pcpath));
diff --git a/gs/src/gxpath.c b/gs/src/gxpath.c
new file mode 100644
index 000000000..2014f4d95
--- /dev/null
+++ b/gs/src/gxpath.c
@@ -0,0 +1,552 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpath.c */
+/* Internal path construction routines for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+
+/* These routines all assume that all points are */
+/* already in device coordinates, and in fixed representation. */
+/* As usual, they return either 0 or a (negative) error code. */
+
+/* Forward references */
+private subpath *path_alloc_copy(P1(gx_path *));
+private int gx_path_new_subpath(P1(gx_path *));
+#ifdef DEBUG
+private void gx_print_segment(P1(const segment *));
+# define trace_segment(msg, pseg)\
+ if ( gs_debug_c('P') ) dprintf(msg), gx_print_segment(pseg);
+#else
+# define trace_segment(msg, pseg) DO_NOTHING
+#endif
+
+/* Macro for checking a point against a preset bounding box. */
+#define outside_bbox(ppath, px, py)\
+ (px < ppath->bbox.p.x || px > ppath->bbox.q.x ||\
+ py < ppath->bbox.p.y || py > ppath->bbox.q.y)
+#define check_in_bbox(ppath, px, py)\
+ if ( outside_bbox(ppath, px, py) )\
+ return_error(gs_error_rangecheck)
+
+/* Structure descriptors for paths and path segment types. */
+public_st_path();
+private_st_segment();
+private_st_line();
+private_st_line_close();
+private_st_curve();
+private_st_subpath();
+
+/* ------ Initialize/free paths ------ */
+
+/* Allocate and initialize a path. */
+gx_path *
+gx_path_alloc(gs_memory_t *mem, client_name_t cname)
+{ gx_path *ppath = gs_alloc_struct(mem, gx_path, &st_path, cname);
+ if ( ppath == 0 )
+ return 0;
+ gx_path_init(ppath, mem);
+ return ppath;
+}
+
+/* Initialize a path */
+void
+gx_path_init(gx_path *ppath, gs_memory_t *mem)
+{ ppath->memory = mem;
+ gx_path_reset(ppath);
+}
+void
+gx_path_reset(gx_path *ppath)
+{ ppath->box_last = 0;
+ ppath->first_subpath = ppath->current_subpath = 0;
+ ppath->subpath_count = 0;
+ ppath->curve_count = 0;
+ path_update_newpath(ppath);
+ ppath->shares_segments = 0;
+ ppath->bbox_set = 0;
+}
+
+/* Release the contents of a path. We do this in reverse order */
+/* so as to maximize LIFO allocator behavior. */
+void
+gx_path_release(gx_path *ppath)
+{ segment *pseg;
+ if ( ppath->first_subpath == 0 ) return; /* empty path */
+ if ( ppath->shares_segments ) return; /* segments are shared */
+ pseg = (segment *)ppath->current_subpath->last;
+ while ( pseg )
+ { segment *prev = pseg->prev;
+ trace_segment("[P]release", pseg);
+ gs_free_object(ppath->memory, pseg, "gx_path_release");
+ pseg = prev;
+ }
+ /* Clear pointers to make things clean for garbage collection. */
+ ppath->box_last = 0;
+ ppath->first_subpath = ppath->current_subpath = 0;
+}
+
+/* Mark a path as shared */
+void
+gx_path_share(gx_path *ppath)
+{ if ( ppath->first_subpath ) ppath->shares_segments = 1;
+}
+
+/* ------ Incremental path building ------ */
+
+/* Macro for opening the current subpath. */
+/* ppath points to the path; psub has been set to ppath->current_subpath. */
+#define path_open()\
+ if ( !path_is_drawing(ppath) )\
+ { int code;\
+ if ( !path_position_valid(ppath) )\
+ return_error(gs_error_nocurrentpoint);\
+ code = gx_path_new_subpath(ppath);\
+ if ( code < 0 ) return code;\
+ psub = ppath->current_subpath;\
+ }
+
+/* Macros for allocating path segments. */
+/* Note that they assume that ppath points to the path, */
+/* and that psub points to the current subpath. */
+/* We have to split the macro into two because of limitations */
+/* on the size of a single statement (sigh). */
+#define path_unshare(ppath)\
+ if(ppath->shares_segments)\
+ if(!(psub = path_alloc_copy(ppath)))return_error(gs_error_VMerror)
+#define path_alloc_segment(pseg,ctype,pstype,stype,snotes,cname)\
+ path_unshare(ppath);\
+ if( !(pseg = gs_alloc_struct(ppath->memory, ctype, pstype, cname)) )\
+ return_error(gs_error_VMerror);\
+ pseg->type = stype, pseg->notes = snotes, pseg->next = 0
+#define path_alloc_link(pseg)\
+ { segment *prev = psub->last;\
+ prev->next = (segment *)pseg;\
+ pseg->prev = prev;\
+ psub->last = (segment *)pseg;\
+ }
+
+/* Open a new subpath. */
+/* The client must invoke path_update_xxx. */
+private int
+gx_path_new_subpath(gx_path *ppath)
+{ subpath *psub = ppath->current_subpath;
+ subpath *spp;
+
+ path_alloc_segment(spp, subpath, &st_subpath, s_start, sn_none,
+ "gx_path_new_subpath");
+ spp->last = (segment *)spp;
+ spp->curve_count = 0;
+ spp->is_closed = 0;
+ spp->pt = ppath->position;
+ if ( !psub ) /* first subpath */
+ { ppath->first_subpath = spp;
+ spp->prev = 0;
+ }
+ else
+ { segment *prev = psub->last;
+
+ prev->next = (segment *)spp;
+ spp->prev = prev;
+ }
+ ppath->current_subpath = spp;
+ ppath->subpath_count++;
+ trace_segment("[P]", (const segment *)spp);
+ return 0;
+}
+
+/* Add a point to the current path (moveto). */
+int
+gx_path_add_point(gx_path *ppath, fixed x, fixed y)
+{ if ( ppath->bbox_set )
+ check_in_bbox(ppath, x, y);
+ ppath->position.x = x;
+ ppath->position.y = y;
+ path_update_moveto(ppath);
+ return 0;
+}
+
+/* Add a relative point to the current path (rmoveto). */
+int
+gx_path_add_relative_point(gx_path *ppath, fixed dx, fixed dy)
+{ if ( !path_position_in_range(ppath) )
+ return_error((path_position_valid(ppath) ? gs_error_limitcheck :
+ gs_error_nocurrentpoint));
+ { fixed nx = ppath->position.x + dx, ny = ppath->position.y + dy;
+ /* Check for overflow in addition. */
+ if ( ((nx ^ dx) < 0 && (ppath->position.x ^ dx) >= 0) ||
+ ((ny ^ dy) < 0 && (ppath->position.y ^ dy) >= 0)
+ )
+ return_error(gs_error_limitcheck);
+ if ( ppath->bbox_set )
+ check_in_bbox(ppath, nx, ny);
+ ppath->position.x = nx;
+ ppath->position.y = ny;
+ }
+ path_update_moveto(ppath);
+ return 0;
+}
+
+/* Set the segment point and the current point in the path. */
+/* Assumes ppath points to the path. */
+#define path_set_point(pseg, fx, fy)\
+ (pseg)->pt.x = ppath->position.x = (fx),\
+ (pseg)->pt.y = ppath->position.y = (fy)
+
+/* Add a line to the current path (lineto). */
+int
+gx_path_add_line_notes(gx_path *ppath, fixed x, fixed y, segment_notes notes)
+{ subpath *psub = ppath->current_subpath;
+ line_segment *lp;
+
+ if ( ppath->bbox_set )
+ check_in_bbox(ppath, x, y);
+ path_open();
+ path_alloc_segment(lp, line_segment, &st_line, s_line, notes,
+ "gx_path_add_line");
+ path_alloc_link(lp);
+ path_set_point(lp, x, y);
+ path_update_draw(ppath);
+ trace_segment("[P]", (segment *)lp);
+ return 0;
+}
+
+/* Add multiple lines to the current path. */
+/* Note that all lines have the same notes. */
+int
+gx_path_add_lines_notes(gx_path *ppath, const gs_fixed_point *ppts, int count,
+ segment_notes notes)
+{ subpath *psub = ppath->current_subpath;
+ segment *prev;
+ line_segment *lp = 0;
+ int i;
+ int code = 0;
+
+ if ( count <= 0 )
+ return 0;
+ path_unshare(ppath);
+ path_open();
+ prev = psub->last;
+ /* We could do better than the following, but this is a start. */
+ /* Note that we don't make any attempt to undo partial additions */
+ /* if we fail partway through; this is equivalent to what would */
+ /* happen with multiple calls on gx_path_add_line. */
+ for ( i = 0; i < count; i++ )
+ { fixed x = ppts[i].x;
+ fixed y = ppts[i].y;
+ line_segment *next;
+ if ( ppath->bbox_set && outside_bbox(ppath, x, y) )
+ { code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if ( !(next = gs_alloc_struct(ppath->memory, line_segment,
+ &st_line, "gx_path_add_lines"))
+ )
+ { code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ lp = next;
+ lp->type = s_line;
+ lp->notes = notes;
+ prev->next = (segment *)lp;
+ lp->prev = prev;
+ lp->pt.x = x;
+ lp->pt.y = y;
+ prev = (segment *)lp;
+ trace_segment("[P]", (segment *)lp);
+ }
+ if ( lp != 0 )
+ ppath->position.x = lp->pt.x,
+ ppath->position.y = lp->pt.y,
+ psub->last = (segment *)lp,
+ lp->next = 0,
+ path_update_draw(ppath);
+ return code;
+}
+
+/* Add a rectangle to the current path. */
+/* This is a special case of adding a closed polygon. */
+int
+gx_path_add_rectangle(gx_path *ppath, fixed x0, fixed y0, fixed x1, fixed y1)
+{ gs_fixed_point pts[3];
+ int code;
+
+ pts[0].x = x0;
+ pts[1].x = pts[2].x = x1;
+ pts[2].y = y0;
+ pts[0].y = pts[1].y = y1;
+ if ( (code = gx_path_add_point(ppath, x0, y0)) < 0 ||
+ (code = gx_path_add_lines(ppath, pts, 3)) < 0 ||
+ (code = gx_path_close_subpath(ppath)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* Add a curve to the current path (curveto). */
+int
+gx_path_add_curve_notes(gx_path *ppath,
+ fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3,
+ segment_notes notes)
+{ subpath *psub = ppath->current_subpath;
+ curve_segment *lp;
+
+ if ( ppath->bbox_set )
+ { check_in_bbox(ppath, x1, y1);
+ check_in_bbox(ppath, x2, y2);
+ check_in_bbox(ppath, x3, y3);
+ }
+ path_open();
+ path_alloc_segment(lp, curve_segment, &st_curve, s_curve, notes,
+ "gx_path_add_curve");
+ path_alloc_link(lp);
+ lp->p1.x = x1;
+ lp->p1.y = y1;
+ lp->p2.x = x2;
+ lp->p2.y = y2;
+ path_set_point(lp, x3, y3);
+ psub->curve_count++;
+ ppath->curve_count++;
+ path_update_draw(ppath);
+ trace_segment("[P]", (segment *)lp);
+ return 0;
+}
+
+/*
+ * Add an approximation of an arc to the current path.
+ * The current point of the path is the initial point of the arc;
+ * parameters are the final point of the arc
+ * and the point at which the extended tangents meet.
+ * We require that the arc be less than a semicircle.
+ * The arc may go either clockwise or counterclockwise.
+ * The approximation is a very simple one: a single curve
+ * whose other two control points are a fraction F of the way
+ * to the intersection of the tangents, where
+ * F = (4/3)(1 / (1 + sqrt(1+(d/r)^2)))
+ * where r is the radius and d is the distance from either tangent
+ * point to the intersection of the tangents. This produces
+ * a curve whose center point, as well as its ends, lies on
+ * the desired arc.
+ *
+ * Because F has to be computed in user space, we let the client
+ * compute it and pass it in as an argument.
+ */
+int
+gx_path_add_partial_arc_notes(gx_path *ppath,
+ fixed x3, fixed y3, fixed xt, fixed yt, floatp fraction, segment_notes notes)
+{ fixed x0 = ppath->position.x, y0 = ppath->position.y;
+ return gx_path_add_curve_notes(ppath,
+ x0 + (fixed)((xt - x0) * fraction),
+ y0 + (fixed)((yt - y0) * fraction),
+ x3 + (fixed)((xt - x3) * fraction),
+ y3 + (fixed)((yt - y3) * fraction),
+ x3, y3, notes | sn_from_arc);
+}
+
+/* Append a path to another path, and reset the first path. */
+/* Currently this is only used to append a path to its parent */
+/* (the path in the previous graphics context). */
+int
+gx_path_add_path(gx_path *ppath, gx_path *ppfrom)
+{ subpath *psub;
+ path_unshare(ppfrom);
+ path_unshare(ppath);
+ if ( ppfrom->first_subpath ) /* i.e. ppfrom not empty */
+ { if ( ppath->first_subpath ) /* i.e. ppath not empty */
+ { subpath *psub = ppath->current_subpath;
+ segment *pseg = psub->last;
+ subpath *pfsub = ppfrom->first_subpath;
+ pseg->next = (segment *)pfsub;
+ pfsub->prev = pseg;
+ }
+ else
+ ppath->first_subpath = ppfrom->first_subpath;
+ ppath->current_subpath = ppfrom->current_subpath;
+ ppath->subpath_count += ppfrom->subpath_count;
+ ppath->curve_count += ppfrom->curve_count;
+ }
+ /* Transfer the remaining state. */
+ ppath->position = ppfrom->position;
+ ppath->outside_position = ppfrom->outside_position;
+ ppath->state_flags = ppfrom->state_flags;
+ gx_path_reset(ppfrom); /* reset the source path */
+ return 0;
+}
+
+/* Add a path or its bounding box to the enclosing path, */
+/* and reset the first path. Only used for implementing charpath and its */
+/* relatives. */
+int
+gx_path_add_char_path(gx_path *to_path, gx_path *from_path,
+ gs_char_path_mode mode)
+{ switch ( mode )
+ {
+ default: /* shouldn't happen! */
+ gx_path_reset(from_path);
+ return 0;
+ case cpm_true_charpath:
+ case cpm_false_charpath:
+ return gx_path_add_path(to_path, from_path);
+ case cpm_true_charboxpath:
+ { gs_fixed_rect bbox;
+ gx_path_bbox(from_path, &bbox);
+ return gx_path_add_rectangle(to_path, bbox.p.x, bbox.p.y,
+ bbox.q.x, bbox.q.y);
+ }
+ case cpm_false_charboxpath:
+ { gs_fixed_rect bbox;
+ int code;
+ gx_path_bbox(from_path, &bbox);
+ return
+ ((code = gx_path_add_point(to_path, bbox.p.x, bbox.p.y)) < 0 ?
+ code : gx_path_add_line(to_path, bbox.q.x, bbox.q.y));
+ }
+ }
+}
+
+/* Close the current subpath. */
+int
+gx_path_close_subpath_notes(gx_path *ppath, segment_notes notes)
+{ subpath *psub = ppath->current_subpath;
+ line_close_segment *lp;
+ int code;
+
+ if ( !path_subpath_open(ppath) )
+ return 0;
+ if ( path_last_is_moveto(ppath) )
+ { /* The last operation was a moveto: create a subpath. */
+ code = gx_path_new_subpath(ppath);
+ if ( code < 0 )
+ return code;
+ psub = ppath->current_subpath;
+ }
+ path_alloc_segment(lp, line_close_segment, &st_line_close,
+ s_line_close, notes, "gx_path_close_subpath");
+ path_alloc_link(lp);
+ path_set_point(lp, psub->pt.x, psub->pt.y);
+ lp->sub = psub;
+ psub->is_closed = 1;
+ path_update_closepath(ppath);
+ trace_segment("[P]", (segment *)lp);
+ return 0;
+}
+
+/* Remove the last line from the current subpath, and then close it. */
+/* The Type 1 font hinting routines use this if a path ends with */
+/* a line to the start followed by a closepath. */
+int
+gx_path_pop_close_notes(gx_path *ppath, segment_notes notes)
+{ subpath *psub = ppath->current_subpath;
+ segment *pseg;
+ segment *prev;
+
+ if ( psub == 0 || (pseg = psub->last) == 0 ||
+ pseg->type != s_line
+ )
+ return_error(gs_error_unknownerror);
+ prev = pseg->prev;
+ prev->next = 0;
+ psub->last = prev;
+ gs_free_object(ppath->memory, pseg, "gx_path_pop_close_subpath");
+ return gx_path_close_subpath_notes(ppath, notes);
+}
+
+/* ------ Internal routines ------ */
+
+/* Copy the current path, because it was shared. */
+/* Return a pointer to the current subpath, or 0. */
+private subpath *
+path_alloc_copy(gx_path *ppath)
+{ gx_path path_new;
+ int code;
+ code = gx_path_copy(ppath, &path_new, 1);
+ if ( code < 0 ) return 0;
+ *ppath = path_new;
+ ppath->shares_segments = 0;
+ return ppath->current_subpath;
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print out a path with a label */
+void
+gx_dump_path(const gx_path *ppath, const char *tag)
+{ dprintf2("[P]Path 0x%lx %s:\n", (ulong)ppath, tag);
+ gx_path_print(ppath);
+}
+
+/* Print a path */
+void
+gx_path_print(const gx_path *ppath)
+{ const segment *pseg = (const segment *)ppath->first_subpath;
+ dprintf5(" state_flags=%d subpaths=%d, curves=%d, point=(%f,%f)\n",
+ ppath->state_flags, ppath->subpath_count, ppath->curve_count,
+ fixed2float(ppath->position.x),
+ fixed2float(ppath->position.y));
+ dprintf5(" box=(%f,%f),(%f,%f) last=0x%lx\n",
+ fixed2float(ppath->bbox.p.x), fixed2float(ppath->bbox.p.y),
+ fixed2float(ppath->bbox.q.x), fixed2float(ppath->bbox.q.y),
+ (ulong)ppath->box_last);
+ while ( pseg )
+ { gx_print_segment(pseg);
+ pseg = pseg->next;
+ }
+}
+private void
+gx_print_segment(const segment *pseg)
+{ double px = fixed2float(pseg->pt.x);
+ double py = fixed2float(pseg->pt.y);
+ char out[80];
+
+ sprintf(out, " 0x%lx<0x%lx,0x%lx>:%u",
+ (ulong)pseg, (ulong)pseg->prev, (ulong)pseg->next,
+ pseg->notes);
+ switch ( pseg->type )
+ {
+ case s_start:
+#define psub ((const subpath *)pseg)
+ dprintf5("%s: %6g %6g moveto\t%% #curves=%d last=0x%lx\n",
+ out, px, py, psub->curve_count, (ulong)psub->last);
+#undef psub
+ break;
+ case s_curve:
+#define pcur ((const curve_segment *)pseg)
+ dprintf7("%s: %g %g %g %g %g %g curveto\n",
+ out, fixed2float(pcur->p1.x), fixed2float(pcur->p1.y),
+ fixed2float(pcur->p2.x), fixed2float(pcur->p2.y), px, py);
+#undef pcur
+ break;
+ case s_line:
+ dprintf3("%s: %6g %6g lineto\n", out, px, py);
+ break;
+ case s_line_close:
+#define plc ((const line_close_segment *)pseg)
+ dprintf4("%s: closepath\t%% %g %g 0x%lx\n",
+ out, px, py, (ulong)(plc->sub));
+#undef plc
+ break;
+ default:
+ dprintf4("%s: %g %g <type 0x%x>\n", out, px, py, pseg->type);
+ }
+}
+
+#endif /* DEBUG */
diff --git a/gs/src/gxpath.h b/gs/src/gxpath.h
new file mode 100644
index 000000000..d3d2a3888
--- /dev/null
+++ b/gs/src/gxpath.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpath.h */
+/* Lower-level path routines for Ghostscript library */
+/* Requires gxfixed.h */
+#include "gscpm.h"
+#include "gslparam.h"
+#include "gspenum.h"
+
+/* The routines and types in this interface use */
+/* device, rather than user, coordinates, and fixed-point, */
+/* rather than floating, representation. */
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+
+/* Define the two insideness rules */
+#define gx_rule_winding_number (-1)
+#define gx_rule_even_odd 1
+
+/* Define 'notes' that describe the role of a path segment. */
+/* These are only for internal use; a normal segment's notes are 0. */
+typedef enum {
+ sn_none = 0,
+ sn_not_first = 1, /* segment is in curve/arc and not first */
+ sn_from_arc = 2 /* segment is part of an arc */
+} segment_notes;
+
+/* Debugging routines */
+#ifdef DEBUG
+void gx_dump_path(P2(const gx_path *, const char *));
+void gx_path_print(P1(const gx_path *));
+#endif
+
+/* Path constructors */
+
+gx_path *gx_path_alloc(P2(gs_memory_t *, client_name_t));
+void gx_path_init(P2(gx_path *, gs_memory_t *)),
+ gx_path_reset(P1(gx_path *)),
+ gx_path_release(P1(gx_path *)),
+ gx_path_share(P1(gx_path *));
+int gx_path_add_point(P3(gx_path *, fixed, fixed)),
+ gx_path_add_relative_point(P3(gx_path *, fixed, fixed)),
+ gx_path_add_line_notes(P4(gx_path *, fixed, fixed, segment_notes)),
+ gx_path_add_lines_notes(P4(gx_path *, const gs_fixed_point *, int, segment_notes)),
+ gx_path_add_rectangle(P5(gx_path *, fixed, fixed, fixed, fixed)),
+ gx_path_add_char_path(P3(gx_path *, gx_path *, gs_char_path_mode)),
+ gx_path_add_curve_notes(P8(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes)),
+ gx_path_add_partial_arc_notes(P7(gx_path *, fixed, fixed, fixed, fixed, floatp, segment_notes)),
+ gx_path_add_path(P2(gx_path *, gx_path *)),
+ gx_path_close_subpath_notes(P2(gx_path *, segment_notes)),
+ /* We have to remove the 'subpath' from the following name */
+ /* to keep it unique in the first 23 characters. */
+ gx_path_pop_close_notes(P2(gx_path *, segment_notes));
+/* The last argument to gx_path_add_partial_arc is a fraction for computing */
+/* the curve parameters. Here is the correct value for quarter-circles. */
+/* (stroke uses this to draw round caps and joins.) */
+#define quarter_arc_fraction 0.552285
+/*
+ * Backward-compatible constructors that don't take a notes argument.
+ */
+#define gx_path_add_line(ppath, x, y)\
+ gx_path_add_line_notes(ppath, x, y, sn_none)
+#define gx_path_add_lines(ppath, pts, count)\
+ gx_path_add_lines_notes(ppath, pts, count, sn_none)
+#define gx_path_add_curve(ppath, x1, y1, x2, y2, x3, y3)\
+ gx_path_add_curve_notes(ppath, x1, y1, x2, y2, x3, y3, sn_none)
+#define gx_path_add_partial_arc(ppath, x3, y3, xt, yt, fraction)\
+ gx_path_add_partial_arc_notes(ppath, x3, y3, xt, yt, fraction, sn_none)
+#define gx_path_close_subpath(ppath)\
+ gx_path_close_subpath_notes(ppath, sn_none)
+#define gx_path_pop_close_subpath(ppath)\
+ gx_path_pop_close_notes(ppath, sn_none)
+
+/* Path accessors */
+
+gx_path *gx_current_path(P1(const gs_state *));
+void gx_path_assign(P2(gx_path *, const gx_path *));
+int gx_path_current_point(P2(const gx_path *, gs_fixed_point *)),
+ gx_path_bbox(P2(gx_path *, gs_fixed_rect *));
+bool gx_path_has_curves(P1(const gx_path *)),
+ gx_path_is_void(P1(const gx_path *)), /* no segments */
+ gx_path_is_null(P1(const gx_path *)), /* nothing at all */
+ gx_path_is_rectangle(P2(const gx_path *, gs_fixed_rect *)),
+ gx_path_is_monotonic(P1(const gx_path *));
+/* Inline versions of the above */
+#define gx_path_has_curves_inline(ppath)\
+ ((ppath)->curve_count != 0)
+#define gx_path_is_void_inline(ppath)\
+ ((ppath)->first_subpath == 0)
+#define gx_path_is_null_inline(ppath)\
+ (gx_path_is_void_inline(ppath) && !path_position_valid(ppath))
+
+/* Path transformers */
+
+/* gx_path_copy_reducing is internal. */
+typedef enum {
+ pco_none = 0,
+ pco_init = 1, /* initialize the destination path */
+ pco_monotonize = 2, /* make curves monotonic */
+ pco_accurate = 4 /* flatten with accurate tangents at ends */
+} gx_path_copy_options;
+int gx_path_copy_reducing(P4(const gx_path *ppath_old, gx_path *ppath_new,
+ fixed fixed_flatness,
+ gx_path_copy_options options));
+#define gx_path_copy(old, new, init)\
+ gx_path_copy_reducing(old, new, max_fixed, (init ? pco_init : pco_none))
+#define gx_path_flatten(old, new, flatness)\
+ gx_path_copy_reducing(old, new, float2fixed(flatness), pco_init)
+#define gx_path_flatten_accurate(old, new, flatness, accurate)\
+ gx_path_copy_reducing(old, new, float2fixed(flatness),\
+ (accurate ? pco_init | pco_accurate : pco_init))
+#define gx_path_monotonize(old, new)\
+ gx_path_copy_reducing(old, new, max_fixed, pco_init | pco_monotonize)
+int gx_path_expand_dashes(P3(const gx_path * /*old*/, gx_path * /*new*/, const gs_imager_state *)),
+ gx_path_copy_reversed(P3(const gx_path * /*old*/, gx_path * /*new*/, bool /*init*/)),
+ gx_path_translate(P3(gx_path *, fixed, fixed)),
+ gx_path_scale_exp2(P3(gx_path *, int, int));
+void gx_point_scale_exp2(P3(gs_fixed_point *, int, int)),
+ gx_rect_scale_exp2(P3(gs_fixed_rect *, int, int));
+
+/* Path enumerator */
+
+/* This interface does not make a copy of the path. */
+/* Do not use gs_path_enum_cleanup with this interface! */
+int gx_path_enum_init(P2(gs_path_enum *, const gx_path *));
+int gx_path_enum_next(P2(gs_path_enum *, gs_fixed_point [3])); /* 0 when done */
+segment_notes
+ gx_path_enum_notes(P1(const gs_path_enum *));
+bool gx_path_enum_backup(P1(gs_path_enum *));
+
+/* ------ Clipping paths ------ */
+
+/* Opaque type for a clipping path */
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+#endif
+
+/* Opaque type for a clip list. */
+#ifndef gx_clip_list_DEFINED
+# define gx_clip_list_DEFINED
+typedef struct gx_clip_list_s gx_clip_list;
+#endif
+
+int gx_clip_to_rectangle(P2(gs_state *, gs_fixed_rect *)),
+ gx_clip_to_path(P1(gs_state *)),
+ gx_cpath_init(P2(gx_clip_path *, gs_memory_t *)),
+ gx_cpath_from_rectangle(P3(gx_clip_path *, gs_fixed_rect *, gs_memory_t *)),
+ gx_cpath_intersect(P4(gs_state *, gx_clip_path *, gx_path *, int)),
+ gx_cpath_scale_exp2(P3(gx_clip_path *, int, int));
+void gx_cpath_release(P1(gx_clip_path *)),
+ gx_cpath_share(P1(gx_clip_path *));
+int gx_cpath_path(P2(gx_clip_path *, gx_path *));
+bool gx_cpath_inner_box(P2(const gx_clip_path *, gs_fixed_rect *)),
+ gx_cpath_outer_box(P2(const gx_clip_path *, gs_fixed_rect *)),
+ gx_cpath_includes_rectangle(P5(const gx_clip_path *, fixed, fixed, fixed, fixed));
+int gx_cpath_set_outside(P2(gx_clip_path *, bool));
+bool gx_cpath_is_outside(P1(const gx_clip_path *));
+
+/* ------ Rectangle utilities ------ */
+
+/* Check whether a path bounding box is within a clipping box. */
+#define rect_within(ibox, cbox)\
+ (ibox.q.y <= cbox.q.y && ibox.q.x <= cbox.q.x &&\
+ ibox.p.y >= cbox.p.y && ibox.p.x >= cbox.p.x)
+
+/* Intersect a bounding box with a clipping box. */
+#define rect_intersect(ibox, cbox)\
+ { if ( cbox.p.x > ibox.p.x ) ibox.p.x = cbox.p.x;\
+ if ( cbox.q.x < ibox.q.x ) ibox.q.x = cbox.q.x;\
+ if ( cbox.p.y > ibox.p.y ) ibox.p.y = cbox.p.y;\
+ if ( cbox.q.y < ibox.q.y ) ibox.q.y = cbox.q.y;\
+ }
diff --git a/gs/src/gxpath2.c b/gs/src/gxpath2.c
new file mode 100644
index 000000000..8645536cc
--- /dev/null
+++ b/gs/src/gxpath2.c
@@ -0,0 +1,452 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpath2.c */
+/* Path tracing procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gzpath.h"
+
+/* Define the enumeration structure. */
+private_st_path_enum();
+
+/* Assign a path. */
+void
+gx_path_assign(gx_path *pto, const gx_path *pfrom)
+{ *pto = *pfrom;
+}
+
+/* Read the current point of a path. */
+int
+gx_path_current_point(const gx_path *ppath, gs_fixed_point *ppt)
+{ if ( !path_position_valid(ppath) )
+ return_error(gs_error_nocurrentpoint);
+ /* Copying the coordinates individually */
+ /* is much faster on a PC, and almost as fast on other machines.... */
+ ppt->x = ppath->position.x, ppt->y = ppath->position.y;
+ return 0;
+}
+
+/* Read the bounding box of a path. */
+/* Note that if the last element of the path is a moveto, */
+/* the bounding box does not include this point, */
+/* unless this is the only element of the path. */
+int
+gx_path_bbox(gx_path *ppath, gs_fixed_rect *pbox)
+{ if ( ppath->bbox_set )
+ { /* The bounding box was set by setbbox. */
+ *pbox = ppath->bbox;
+ return 0;
+ }
+ if ( ppath->first_subpath == 0 )
+ { /* The path is empty, use the current point if any. */
+ int code = gx_path_current_point(ppath, &pbox->p);
+
+ if ( code < 0 )
+ { /*
+ * Don't return garbage, in case the caller doesn't
+ * check the return code.
+ */
+ pbox->p.x = pbox->p.y = 0;
+ }
+ pbox->q = pbox->p;
+ return code;
+ }
+ /* The stored bounding box may not be up to date. */
+ /* Correct it now if necessary. */
+ if ( ppath->box_last == ppath->current_subpath->last )
+ { /* Box is up to date */
+ *pbox = ppath->bbox;
+ }
+ else
+ { gs_fixed_rect box;
+ register segment *pseg = ppath->box_last;
+ if ( pseg == 0 ) /* box is uninitialized */
+ { pseg = (segment *)ppath->first_subpath;
+ box.p.x = box.q.x = pseg->pt.x;
+ box.p.y = box.q.y = pseg->pt.y;
+ }
+ else
+ { box = ppath->bbox;
+ pseg = pseg->next;
+ }
+/* Macro for adjusting the bounding box when adding a point */
+#define adjust_bbox(pt)\
+ if ( (pt).x < box.p.x ) box.p.x = (pt).x;\
+ else if ( (pt).x > box.q.x ) box.q.x = (pt).x;\
+ if ( (pt).y < box.p.y ) box.p.y = (pt).y;\
+ else if ( (pt).y > box.q.y ) box.q.y = (pt).y
+ while ( pseg )
+ { switch ( pseg->type )
+ {
+ case s_curve:
+#define pcurve ((curve_segment *)pseg)
+ adjust_bbox(pcurve->p1);
+ adjust_bbox(pcurve->p2);
+#undef pcurve
+ /* falls through */
+ default:
+ adjust_bbox(pseg->pt);
+ }
+ pseg = pseg->next;
+ }
+#undef adjust_bbox
+ ppath->bbox = box;
+ ppath->box_last = ppath->current_subpath->last;
+ *pbox = box;
+ }
+ return 0;
+}
+
+/* Test if a path has any curves. */
+bool
+gx_path_has_curves(const gx_path *ppath)
+{ return ppath->curve_count != 0;
+}
+
+/* Test if a path has no segments. */
+bool
+gx_path_is_void(const gx_path *ppath)
+{ return ppath->first_subpath == 0;
+}
+
+/* Test if a path has no elements at all. */
+bool
+gx_path_is_null(const gx_path *ppath)
+{ return ppath->first_subpath == 0 && !path_position_valid(ppath);
+}
+
+/*
+ * Test if a subpath to be filled is a rectangle; if so, return its
+ * bounding box and the start of the next subpath.
+ * Note that this must recognize:
+ * ordinary closed rectangles (M, L, L, L, C);
+ * open rectangles (M, L, L, L);
+ * rectangles closed with lineto (Mo, L, L, L, Lo);
+ * rectangles closed with *both* lineto and closepath (bad PostScript,
+ * but unfortunately not rare) (Mo, L, L, L, Lo, C).
+ */
+bool
+gx_subpath_is_rectangle(const subpath *pseg0, gs_fixed_rect *pbox,
+ const subpath **ppnext)
+{ const segment *pseg1, *pseg2, *pseg3, *pseg4;
+ if ( pseg0->curve_count == 0 &&
+ (pseg1 = pseg0->next) != 0 &&
+ (pseg2 = pseg1->next) != 0 &&
+ (pseg3 = pseg2->next) != 0 &&
+ ((pseg4 = pseg3->next) == 0 || pseg4->type != s_line ||
+ (pseg4->pt.x == pseg0->pt.x &&
+ pseg4->pt.y == pseg0->pt.y &&
+ (pseg4->next == 0 || pseg4->next->type != s_line)))
+ )
+ { fixed x0 = pseg0->pt.x, y0 = pseg0->pt.y;
+ fixed x2 = pseg2->pt.x, y2 = pseg2->pt.y;
+ if ( (x0 == pseg1->pt.x && pseg1->pt.y == y2 &&
+ x2 == pseg3->pt.x && pseg3->pt.y == y0) ||
+ (x0 == pseg3->pt.x && pseg3->pt.y == y2 &&
+ x2 == pseg1->pt.x && pseg1->pt.y == y0)
+ )
+ { /* Path is a rectangle. Return the bounding box. */
+ if ( x0 < x2 )
+ pbox->p.x = x0, pbox->q.x = x2;
+ else
+ pbox->p.x = x2, pbox->q.x = x0;
+ if ( y0 < y2 )
+ pbox->p.y = y0, pbox->q.y = y2;
+ else
+ pbox->p.y = y2, pbox->q.y = y0;
+ while ( pseg4 != 0 && pseg4->type != s_start )
+ pseg4 = pseg4->next;
+ *ppnext = (const subpath *)pseg4;
+ return true;
+ }
+ }
+ return false;
+}
+/* Test if an entire path to be filled is a rectangle. */
+bool
+gx_path_is_rectangle(const gx_path *ppath, gs_fixed_rect *pbox)
+{ const subpath *pnext;
+ return (ppath->subpath_count == 1 &&
+ gx_subpath_is_rectangle(ppath->first_subpath, pbox, &pnext));
+}
+
+/* Translate an already-constructed path (in device space). */
+/* Don't bother to update the cbox. */
+int
+gx_path_translate(gx_path *ppath, fixed dx, fixed dy)
+{ segment *pseg;
+#define update_xy(pt)\
+ pt.x += dx, pt.y += dy
+ if ( ppath->box_last != 0 )
+ { update_xy(ppath->bbox.p);
+ update_xy(ppath->bbox.q);
+ }
+ if ( path_position_valid(ppath) )
+ update_xy(ppath->position);
+ for ( pseg = (segment *)(ppath->first_subpath); pseg != 0;
+ pseg = pseg->next
+ )
+ switch ( pseg->type )
+ {
+ case s_curve:
+#define pcseg ((curve_segment *)pseg)
+ update_xy(pcseg->p1);
+ update_xy(pcseg->p2);
+#undef pcseg
+ default:
+ update_xy(pseg->pt);
+ }
+#undef update_xy
+ return 0;
+}
+
+/* Scale an existing path by a power of 2 (positive or negative). */
+void
+gx_point_scale_exp2(gs_fixed_point *pt, int sx, int sy)
+{ if ( sx >= 0 ) pt->x <<= sx; else pt->x >>= -sx;
+ if ( sy >= 0 ) pt->y <<= sy; else pt->y >>= -sy;
+}
+void
+gx_rect_scale_exp2(gs_fixed_rect *pr, int sx, int sy)
+{ gx_point_scale_exp2(&pr->p, sx, sy);
+ gx_point_scale_exp2(&pr->q, sx, sy);
+}
+int
+gx_path_scale_exp2(gx_path *ppath, int log2_scale_x, int log2_scale_y)
+{ segment *pseg;
+ gx_rect_scale_exp2(&ppath->bbox, log2_scale_x, log2_scale_y);
+#define update_xy(pt) gx_point_scale_exp2(&pt, log2_scale_x, log2_scale_y)
+ update_xy(ppath->position);
+ for ( pseg = (segment *)(ppath->first_subpath); pseg != 0;
+ pseg = pseg->next
+ )
+ switch ( pseg->type )
+ {
+ case s_curve:
+#define pcseg ((curve_segment *)pseg)
+ update_xy(pcseg->p1);
+ update_xy(pcseg->p2);
+#undef pcseg
+ default:
+ update_xy(pseg->pt);
+ }
+#undef update_xy
+ return 0;
+}
+
+/*
+ * Reverse a path. We know ppath != ppath_old.
+ * NOTE: in releases 5.01 and earlier, the implicit line added by closepath
+ * became the first segment of the reversed path. Starting in release
+ * 5.02, the code follows the Adobe implementation, in which this line
+ * becomes the *last* segment of the reversed path. This can produce some
+ * quite counter-intuitive results.
+ */
+int
+gx_path_copy_reversed(const gx_path *ppath_old, gx_path *ppath, bool init)
+{ const subpath *psub = ppath_old->first_subpath;
+ int code;
+
+#ifdef DEBUG
+ if ( gs_debug_c('P') )
+ gx_dump_path(ppath_old, "before reversepath");
+#endif
+ if ( init )
+ gx_path_init(ppath, ppath_old->memory);
+nsp: while ( psub )
+ { const segment *pseg = psub->last;
+ const segment *prev;
+ segment_notes prev_notes =
+ (pseg == (const segment *)psub ? sn_none :
+ psub->next->notes);
+ segment_notes notes;
+
+ if ( !psub->is_closed )
+ { code = gx_path_add_point(ppath, pseg->pt.x, pseg->pt.y);
+ if ( code < 0 )
+ goto fx;
+ }
+ for ( ; ; pseg = prev, prev_notes = notes )
+ { prev = pseg->prev;
+ notes = pseg->notes;
+ prev_notes = (prev_notes & sn_not_first) |
+ (notes & ~sn_not_first);
+ switch ( pseg->type )
+ {
+ case s_start:
+ /* Finished subpath */
+ if ( psub->is_closed )
+ { code =
+ gx_path_close_subpath_notes(ppath,
+ prev_notes);
+ if ( code < 0 )
+ goto fx;
+ }
+ psub = (const subpath *)psub->last->next;
+ goto nsp;
+ case s_curve:
+ { const curve_segment *pc =
+ (const curve_segment *)pseg;
+
+ code = gx_path_add_curve_notes(ppath,
+ pc->p2.x, pc->p2.y,
+ pc->p1.x, pc->p1.y,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
+ }
+ case s_line:
+ code = gx_path_add_line_notes(ppath,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
+ case s_line_close:
+ /* Skip the closing line. */
+ code = gx_path_add_point(ppath, prev->pt.x,
+ prev->pt.y);
+ break;
+ }
+ if ( code < 0 )
+ goto fx;
+ }
+ /* not reached */
+ }
+#undef sn_not_end
+ if ( ppath_old->first_subpath == 0 &&
+ path_last_is_moveto(ppath_old)
+ )
+ { /* The path consists only of a single moveto. */
+ code = gx_path_add_point(ppath, ppath_old->position.x,
+ ppath_old->position.y);
+ if ( code < 0 )
+ goto fx;
+ }
+#ifdef DEBUG
+if ( gs_debug_c('P') )
+ gx_dump_path(ppath, "after reversepath");
+#endif
+ return 0;
+fx: gx_path_release(ppath);
+ return code;
+}
+
+/* ------ Path enumeration ------ */
+
+/* Allocate a path enumerator. */
+gs_path_enum *
+gs_path_enum_alloc(gs_memory_t *mem, client_name_t cname)
+{ return gs_alloc_struct(mem, gs_path_enum, &st_gs_path_enum, cname);
+}
+
+/* Start enumerating a path. */
+int
+gx_path_enum_init(gs_path_enum *penum, const gx_path *ppath)
+{ penum->path = ppath;
+ penum->copied_path = 0; /* not copied */
+ penum->pgs = 0;
+ penum->pseg = (const segment *)ppath->first_subpath;
+ penum->moveto_done = false;
+ penum->notes = sn_none;
+ return 0;
+}
+
+/* Enumerate the next element of a path. */
+/* If the path is finished, return 0; */
+/* otherwise, return the element type. */
+int
+gx_path_enum_next(gs_path_enum *penum, gs_fixed_point ppts[3])
+{ const segment *pseg = penum->pseg;
+
+ if ( pseg == 0 )
+ { /* We've enumerated all the segments, but there might be */
+ /* a trailing moveto. */
+ const gx_path *ppath = penum->path;
+ if ( path_last_is_moveto(ppath) && !penum->moveto_done )
+ { /* Handle a trailing moveto */
+ penum->moveto_done = true;
+ penum->notes = sn_none;
+ ppts[0] = ppath->position;
+ return gs_pe_moveto;
+ }
+ return 0;
+ }
+ penum->pseg = pseg->next;
+ penum->notes = pseg->notes;
+ switch ( pseg->type )
+ {
+ case s_start:
+ ppts[0] = pseg->pt;
+ return gs_pe_moveto;
+ case s_line:
+ ppts[0] = pseg->pt;
+ return gs_pe_lineto;
+ case s_line_close:
+ ppts[0] = pseg->pt;
+ return gs_pe_closepath;
+ case s_curve:
+#define pcseg ((const curve_segment *)pseg)
+ ppts[0] = pcseg->p1;
+ ppts[1] = pcseg->p2;
+ ppts[2] = pseg->pt;
+ return gs_pe_curveto;
+#undef pcseg
+ default:
+ lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type);
+ return_error(gs_error_Fatal);
+ }
+}
+
+/* Return the notes from the last-enumerated segment. */
+segment_notes
+gx_path_enum_notes(const gs_path_enum *penum)
+{ return penum->notes;
+}
+
+/* Back up 1 element in the path being enumerated. */
+/* Return true if successful, false if we are at the beginning of the path. */
+/* This implementation allows backing up multiple times, */
+/* but no client currently relies on this. */
+bool
+gx_path_enum_backup(gs_path_enum *penum)
+{ const segment *pseg = penum->pseg;
+
+ if ( pseg != 0 )
+ { if ( (pseg = pseg->prev) == 0 )
+ return false;
+ penum->pseg = pseg;
+ return true;
+ }
+ /* We're at the end of the path. Check to see whether */
+ /* we need to back up over a trailing moveto. */
+ { const gx_path *ppath = penum->path;
+ if ( path_last_is_moveto(ppath) && penum->moveto_done )
+ { /* Back up over the trailing moveto. */
+ penum->moveto_done = false;
+ return true;
+ }
+ { const subpath *psub = ppath->current_subpath;
+ if ( psub == 0 ) /* empty path */
+ return false;
+ /* Back up to the last segment of the last subpath. */
+ penum->pseg = psub->last;
+ return true;
+ }
+ }
+}
diff --git a/gs/src/gxpcache.h b/gs/src/gxpcache.h
new file mode 100644
index 000000000..d1dcd4a39
--- /dev/null
+++ b/gs/src/gxpcache.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpcache.h */
+/* Definition of Pattern cache */
+
+#ifndef gxpcache_INCLUDED
+# define gxpcache_INCLUDED
+
+/*
+ * Define a cache for rendered Patterns. This is currently an open
+ * hash table with single probing (no reprobing) and round-robin
+ * replacement. Obviously, we can do better in both areas.
+ */
+#ifndef gx_pattern_cache_DEFINED
+# define gx_pattern_cache_DEFINED
+typedef struct gx_pattern_cache_s gx_pattern_cache;
+#endif
+#ifndef gx_color_tile_DEFINED
+# define gx_color_tile_DEFINED
+typedef struct gx_color_tile_s gx_color_tile;
+#endif
+struct gx_pattern_cache_s {
+ gs_memory_t *memory;
+ gx_color_tile *tiles;
+ uint num_tiles;
+ uint tiles_used;
+ uint next; /* round-robin index */
+ ulong bits_used;
+ ulong max_bits;
+ void (*free_all)(P1(gx_pattern_cache *));
+};
+#define private_st_pattern_cache() /* in gxpcmap.c */\
+ gs_private_st_ptrs1(st_pattern_cache, gx_pattern_cache,\
+ "gx_pattern_cache", pattern_cache_enum, pattern_cache_reloc, tiles)
+
+#endif /* gxpcache_INCLUDED */
diff --git a/gs/src/gxpcmap.c b/gs/src/gxpcmap.c
new file mode 100644
index 000000000..529641405
--- /dev/null
+++ b/gs/src/gxpcmap.c
@@ -0,0 +1,583 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpcmap.c */
+/* Pattern color mapping for Ghostscript library */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxpcolor.h"
+#include "gzstate.h"
+#include "gzpath.h" /* for tweaking sharing flags */
+#include "gzcpath.h" /* ditto */
+
+/* Define the default size of the Pattern cache. */
+#define max_cached_patterns_LARGE 50
+#define max_pattern_bits_LARGE 100000
+#define max_cached_patterns_SMALL 5
+#define max_pattern_bits_SMALL 1000
+uint
+gx_pat_cache_default_tiles(void)
+{
+#if arch_small_memory
+ return max_cached_patterns_SMALL;
+#else
+ return (gs_if_debug_c('.') ? max_cached_patterns_SMALL :
+ max_cached_patterns_LARGE);
+#endif
+}
+ulong
+gx_pat_cache_default_bits(void)
+{
+#if arch_small_memory
+ return max_pattern_bits_SMALL;
+#else
+ return (gs_if_debug_c('.') ? max_pattern_bits_SMALL :
+ max_pattern_bits_LARGE);
+#endif
+}
+
+/* Define the structures for Pattern rendering and caching. */
+private_st_color_tile();
+private_st_color_tile_element();
+private_st_pattern_cache();
+private_st_device_pattern_accum();
+
+/* ------ Pattern rendering ------ */
+
+/* Device procedures */
+private dev_proc_open_device(pattern_accum_open);
+private dev_proc_close_device(pattern_accum_close);
+private dev_proc_fill_rectangle(pattern_accum_fill_rectangle);
+private dev_proc_copy_mono(pattern_accum_copy_mono);
+private dev_proc_copy_color(pattern_accum_copy_color);
+
+/* The device descriptor */
+private const gx_device_pattern_accum gs_pattern_accum_device =
+{ std_device_std_body_open(gx_device_pattern_accum, 0,
+ "pattern accumulator",
+ 0, 0, 72, 72),
+ { pattern_accum_open,
+ NULL,
+ NULL,
+ NULL,
+ pattern_accum_close,
+ NULL,
+ NULL,
+ pattern_accum_fill_rectangle,
+ NULL,
+ pattern_accum_copy_mono,
+ pattern_accum_copy_color,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ NULL,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ NULL,
+ NULL,
+ gx_get_largest_clipping_box,
+ NULL
+ },
+ 0, /* target */
+ 0, 0, 0, 0 /* bitmap_memory, bits, mask, instance */
+};
+#define padev ((gx_device_pattern_accum *)dev)
+
+/* Allocate a pattern accumulator. */
+gx_device_pattern_accum *
+gx_pattern_accum_alloc(gs_memory_t *mem, client_name_t cname)
+{ gx_device_pattern_accum *adev =
+ gs_alloc_struct(mem, gx_device_pattern_accum,
+ &st_device_pattern_accum, cname);
+ if ( adev == 0 )
+ return 0;
+ *adev = gs_pattern_accum_device;
+ adev->memory = mem;
+ gx_device_forward_fill_in_procs((gx_device_forward *)adev); /* (should only do once) */
+ return adev;
+}
+
+/* Initialize a pattern accumulator. */
+/* Client must already have set instance and bitmap_memory. */
+private int
+pattern_accum_open(gx_device *dev)
+{ const gs_pattern_instance *pinst = padev->instance;
+ gs_memory_t *mem = padev->bitmap_memory;
+ gx_device_memory *mask =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "pattern_accum_open(mask)");
+ gx_device_memory *bits = 0;
+ gx_device *target = gs_currentdevice(pinst->saved);
+ int width = pinst->size.x;
+ int height = pinst->size.y;
+ int code;
+ if ( mask == 0 )
+ return_error(gs_error_VMerror);
+#define pdset(dev)\
+ (dev)->width = width, (dev)->height = height,\
+ (dev)->x_pixels_per_inch = target->x_pixels_per_inch,\
+ (dev)->y_pixels_per_inch = target->y_pixels_per_inch
+ pdset(padev);
+ padev->color_info = target->color_info;
+ gs_make_mem_mono_device(mask, mem, 0);
+ pdset(mask);
+ mask->bitmap_memory = mem;
+ mask->base = 0;
+ code = (*dev_proc(mask, open_device))((gx_device *)mask);
+ if ( code >= 0 )
+ { memset(mask->base, 0, mask->raster * mask->height);
+ switch ( pinst->template.PaintType )
+ {
+ case 2: /* uncolored */
+ padev->target = target;
+ break;
+ case 1: /* colored */
+ bits = gs_alloc_struct(mem, gx_device_memory,
+ &st_device_memory,
+ "pattern_accum_open(bits)");
+ if ( bits == 0 )
+ return_error(gs_error_VMerror);
+ padev->target = (gx_device *)bits;
+ gs_make_mem_device(bits, gdev_mem_device_for_bits(target->color_info.depth), mem, -1, target);
+ pdset(bits);
+#undef pdset
+ bits->color_info = target->color_info;
+ bits->bitmap_memory = mem;
+ code = (*dev_proc(bits, open_device))((gx_device *)bits);
+ }
+ }
+ if ( code < 0 )
+ { if ( bits != 0 )
+ gs_free_object(mem, bits, "pattern_accum_open(bits)");
+ (*dev_proc(mask, close_device))((gx_device *)mask);
+ gs_free_object(mem, mask, "pattern_accum_open(mask)");
+ return code;
+ }
+ padev->mask = mask;
+ padev->bits = bits;
+ return code;
+}
+
+/* Close an accumulator and free the bits. */
+private int
+pattern_accum_close(gx_device *dev)
+{ gs_memory_t *mem = padev->bitmap_memory;
+ if ( padev->bits != 0 )
+ { (*dev_proc(padev->bits, close_device))((gx_device *)padev->bits);
+ gs_free_object(mem, padev->bits, "pattern_accum_close(bits)");
+ padev->bits = 0;
+ }
+ (*dev_proc(padev->mask, close_device))((gx_device *)padev->mask);
+ gs_free_object(mem, padev->mask, "pattern_accum_close(mask)");
+ padev->mask = 0;
+ return 0;
+}
+
+/* Fill a rectangle */
+private int
+pattern_accum_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ if ( padev->bits )
+ (*dev_proc(padev->target, fill_rectangle))(padev->target,
+ x, y, w, h, color);
+ return (*dev_proc(padev->mask, fill_rectangle))((gx_device *)padev->mask,
+ x, y, w, h, (gx_color_index)1);
+}
+
+/* Copy a monochrome bitmap. */
+private int
+pattern_accum_copy_mono(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{ if ( padev->bits )
+ (*dev_proc(padev->target, copy_mono))(padev->target,
+ data, data_x, raster, id, x, y, w, h, color0, color1);
+ if ( color0 != gx_no_color_index )
+ color0 = 1;
+ if ( color1 != gx_no_color_index )
+ color1 = 1;
+ if ( color0 == 1 && color1 == 1 )
+ return (*dev_proc(padev->mask, fill_rectangle))((gx_device *)padev->mask,
+ x, y, w, h, (gx_color_index)1);
+ else
+ return (*dev_proc(padev->mask, copy_mono))((gx_device *)padev->mask,
+ data, data_x, raster, id, x, y, w, h, color0, color1);
+}
+
+/* Copy a color bitmap. */
+private int
+pattern_accum_copy_color(gx_device *dev, const byte *data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h)
+{ if ( padev->bits )
+ (*dev_proc(padev->target, copy_color))(padev->target,
+ data, data_x, raster, id, x, y, w, h);
+ return (*dev_proc(padev->mask, fill_rectangle))((gx_device *)padev->mask,
+ x, y, w, h, (gx_color_index)1);
+}
+
+#undef padev
+
+/* ------ Color space implementation ------ */
+
+/* Free all entries in a pattern cache. */
+private bool
+pattern_cache_choose_all(gx_color_tile *ctile, void *proc_data)
+{ return true;
+}
+private void
+pattern_cache_free_all(gx_pattern_cache *pcache)
+{ gx_pattern_cache_winnow(pcache, pattern_cache_choose_all, NULL);
+}
+
+/* Allocate a Pattern cache. */
+gx_pattern_cache *
+gx_pattern_alloc_cache(gs_memory_t *mem, uint num_tiles, ulong max_bits)
+{ gx_pattern_cache *pcache =
+ gs_alloc_struct(mem, gx_pattern_cache, &st_pattern_cache,
+ "pattern_cache_alloc(struct)");
+ gx_color_tile *tiles =
+ gs_alloc_struct_array(mem, num_tiles, gx_color_tile,
+ &st_color_tile_element,
+ "pattern_cache_alloc(tiles)");
+ uint i;
+
+ if ( pcache == 0 || tiles == 0 )
+ { gs_free_object(mem, tiles, "pattern_cache_alloc(tiles)");
+ gs_free_object(mem, pcache, "pattern_cache_alloc(struct)");
+ return 0;
+ }
+ pcache->memory = mem;
+ pcache->tiles = tiles;
+ pcache->num_tiles = num_tiles;
+ pcache->tiles_used = 0;
+ pcache->next = 0;
+ pcache->bits_used = 0;
+ pcache->max_bits = max_bits;
+ pcache->free_all = pattern_cache_free_all;
+ for ( i = 0; i < num_tiles; tiles++, i++ )
+ { tiles->id = gx_no_bitmap_id;
+ /* Clear the pointers to pacify the GC. */
+ uid_set_invalid(&tiles->uid);
+ tiles->tbits.data = 0;
+ tiles->tmask.data = 0;
+ tiles->index = i;
+ }
+ return pcache;
+}
+/* Ensure that an imager has a Pattern cache. */
+private int
+ensure_pattern_cache(gs_imager_state *pis)
+{ if ( pis->pattern_cache == 0 )
+ { gx_pattern_cache *pcache =
+ gx_pattern_alloc_cache(pis->memory,
+ gx_pat_cache_default_tiles(),
+ gx_pat_cache_default_bits());
+ if ( pcache == 0 )
+ return_error(gs_error_VMerror);
+ pis->pattern_cache = pcache;
+ }
+ return 0;
+}
+
+/* Get and set the Pattern cache in a gstate. */
+gx_pattern_cache *
+gstate_pattern_cache(gs_state *pgs)
+{ return pgs->pattern_cache;
+}
+void
+gstate_set_pattern_cache(gs_state *pgs, gx_pattern_cache *pcache)
+{ pgs->pattern_cache = pcache;
+}
+
+/* Free a Pattern cache entry. */
+private void
+gx_pattern_cache_free_entry(gx_pattern_cache *pcache, gx_color_tile *ctile)
+{ gx_device_memory mdev;
+ if ( ctile->id != gx_no_bitmap_id )
+ { if ( ctile->tmask.data != 0 )
+ { mdev.width = ctile->tmask.size.x;
+ mdev.height = ctile->tmask.size.y;
+ mdev.color_info.depth = 1;
+ pcache->bits_used -= gdev_mem_bitmap_size(&mdev);
+ gs_free_object(pcache->memory, ctile->tmask.data,
+ "free_pattern_cache_entry(mask data)");
+ ctile->tmask.data = 0; /* for GC */
+ }
+ if ( ctile->tbits.data != 0 )
+ { mdev.width = ctile->tbits.size.x;
+ mdev.height = ctile->tbits.size.y;
+ mdev.color_info.depth = ctile->depth;
+ pcache->bits_used -= gdev_mem_bitmap_size(&mdev);
+ gs_free_object(pcache->memory, ctile->tbits.data,
+ "free_pattern_cache_entry(bits data)");
+ ctile->tbits.data = 0; /* for GC */
+ }
+ ctile->id = gx_no_bitmap_id;
+ pcache->tiles_used--;
+ }
+}
+
+/* Add a Pattern cache entry. This is exported for the interpreter. */
+/* Note that this does not free any of the data in the accumulator */
+/* device, but it may zero out the bitmap_memory pointers to prevent */
+/* the accumulated bitmaps from being freed when the device is closed. */
+private void make_bitmap(P3(gx_strip_bitmap *, const gx_device_memory *, gx_bitmap_id));
+int
+gx_pattern_cache_add_entry(gs_imager_state *pis,
+ gx_device_pattern_accum *padev, gx_color_tile **pctile)
+{ gx_device_memory *mbits = padev->bits;
+ gx_device_memory *mmask = padev->mask;
+ const gs_pattern_instance *pinst = padev->instance;
+ gx_pattern_cache *pcache;
+ ulong used = 0;
+ gx_bitmap_id id = pinst->id;
+ gx_color_tile *ctile;
+ int code = ensure_pattern_cache(pis);
+ if ( code < 0 )
+ return code;
+ pcache = pis->pattern_cache;
+ /*
+ * Check whether the pattern completely fills its box.
+ * If so, we can avoid the expensive masking operations
+ * when using the pattern.
+ */
+ { int y;
+ for ( y = 0; y < mmask->height; y++ )
+ { const byte *row = scan_line_base(mmask, y);
+ int w;
+ for ( w = mmask->width; w > 8; w -= 8 )
+ if ( *row++ != 0xff )
+ goto keep;
+ if ( (*row | (0xff >> w)) != 0xff )
+ goto keep;
+ }
+ /* We don't need a mask. */
+ mmask = 0;
+keep: ;
+ }
+ if ( mbits != 0 )
+ used += gdev_mem_bitmap_size(mbits);
+ if ( mmask != 0 )
+ used += gdev_mem_bitmap_size(mmask);
+ ctile = &pcache->tiles[id % pcache->num_tiles];
+ gx_pattern_cache_free_entry(pcache, ctile);
+ while ( pcache->bits_used + used > pcache->max_bits &&
+ pcache->bits_used != 0 /* allow 1 oversized entry (?) */
+ )
+ { pcache->next = (pcache->next + 1) % pcache->num_tiles;
+ gx_pattern_cache_free_entry(pcache, &pcache->tiles[pcache->next]);
+ }
+ ctile->id = id;
+ ctile->depth = padev->color_info.depth;
+ ctile->uid = pinst->template.uid;
+ ctile->tiling_type = pinst->template.TilingType;
+ ctile->step_matrix = pinst->step_matrix;
+ ctile->bbox = pinst->bbox;
+ ctile->is_simple = pinst->is_simple;
+ if ( mbits != 0 )
+ { make_bitmap(&ctile->tbits, mbits, gs_next_ids(1));
+ mbits->bitmap_memory = 0; /* don't free the bits */
+ }
+ else
+ ctile->tbits.data = 0;
+ if ( mmask != 0 )
+ { make_bitmap(&ctile->tmask, mmask, id);
+ mmask->bitmap_memory = 0; /* don't free the bits */
+ }
+ else
+ ctile->tmask.data = 0;
+ pcache->bits_used += used;
+ pcache->tiles_used++;
+ *pctile = ctile;
+ return 0;
+}
+private void
+make_bitmap(register gx_strip_bitmap *pbm, const gx_device_memory *mdev,
+ gx_bitmap_id id)
+{ pbm->data = mdev->base;
+ pbm->raster = mdev->raster;
+ pbm->rep_width = pbm->size.x = mdev->width;
+ pbm->rep_height = pbm->size.y = mdev->height;
+ pbm->id = id;
+ pbm->rep_shift = pbm->shift = 0;
+}
+
+/* Purge selected entries from the pattern cache. */
+void
+gx_pattern_cache_winnow(gx_pattern_cache *pcache,
+ bool (*proc)(P2(gx_color_tile *ctile, void *proc_data)), void *proc_data)
+{ uint i;
+
+ if ( pcache == 0 ) /* no cache created yet */
+ return;
+ for ( i = 0; i < pcache->num_tiles; ++i )
+ { gx_color_tile *ctile = &pcache->tiles[i];
+ if ( ctile->id != gx_no_bitmap_id && (*proc)(ctile, proc_data) )
+ gx_pattern_cache_free_entry(pcache, ctile);
+ }
+}
+
+/* Reload a (non-null) Pattern color into the cache. */
+/* *pdc is already set, except for colors.pattern.p_tile and mask.m_tile. */
+int
+gx_pattern_load(gx_device_color *pdc, const gs_imager_state *pis,
+ gx_device *dev, gs_color_select_t select)
+{ gx_device_pattern_accum adev;
+ gs_pattern_instance *pinst = pdc->mask.ccolor.pattern;
+ gs_state *saved;
+ gx_color_tile *ctile;
+ gs_memory_t *mem = pis->memory;
+ int code;
+
+ if ( gx_pattern_cache_lookup(pdc, pis, dev, select) )
+ return 0;
+ /* We REALLY don't like the following cast.... */
+ code = ensure_pattern_cache((gs_imager_state *)pis);
+ if ( code < 0 )
+ return code;
+ adev = gs_pattern_accum_device;
+ gx_device_forward_fill_in_procs((gx_device_forward *)&adev); /* (should only do once) */
+ adev.instance = pinst;
+ adev.bitmap_memory = mem;
+ code = (*dev_proc(&adev, open_device))((gx_device *)&adev);
+ if ( code < 0 )
+ return code;
+ /*
+ * We want the copying operation to mark paths in the copy as shared,
+ * but we don't want the share marks to persist in the original
+ * after we free the copy, because this prevents the paths from
+ * being freed (except by restore or GC). This requires a bit of
+ * care....
+ */
+ { gs_state *orig = pinst->saved;
+ gx_path *ppath = orig->path;
+ gx_clip_path *pcpath = orig->clip_path;
+ bool path_shared = ppath->shares_segments;
+ bool cpath_shared = pcpath->path.shares_segments;
+ bool list_shared = pcpath->shares_list;
+
+ /*
+ * The call of gs_gstate will set all the sharing flags, but that
+ * is OK, because orig points to an orphan gstate (no stack).
+ */
+ saved = gs_gstate(pinst->saved);
+ if ( saved == 0 )
+ return_error(gs_error_VMerror);
+ if ( saved->pattern_cache == 0 )
+ saved->pattern_cache = pis->pattern_cache;
+ gx_set_device_only(saved, (gx_device *)&adev);
+ code = (*pinst->template.PaintProc)(&pdc->mask.ccolor, saved);
+ gs_state_free(saved);
+ ppath->shares_segments = path_shared;
+ pcpath->path.shares_segments = cpath_shared;
+ pcpath->shares_list = list_shared;
+ }
+ if ( code < 0 )
+ { (*dev_proc(&adev, close_device))((gx_device *)&adev);
+ return code;
+ }
+ /* We REALLY don't like the following cast.... */
+ code = gx_pattern_cache_add_entry((gs_imager_state *)pis, &adev,
+ &ctile);
+ if ( code >= 0 )
+ { if ( !gx_pattern_cache_lookup(pdc, pis, dev, select) )
+ { lprintf("Pattern cache lookup failed after insertion!\n");
+ code = gs_note_error(gs_error_Fatal);
+ }
+ }
+ /* Free the bookkeeping structures, except for the bits and mask */
+ /* iff they are still needed. */
+ (*dev_proc(&adev, close_device))((gx_device *)&adev);
+#ifdef DEBUG
+ if ( gs_debug_c('B') )
+ { debug_dump_bitmap(adev.mask->base, adev.mask->raster,
+ adev.mask->height, "[B]Pattern mask");
+ if ( adev.bits )
+ debug_dump_bitmap(((gx_device_memory *)adev.target)->base,
+ ((gx_device_memory *)adev.target)->raster,
+ adev.target->height, "[B]Pattern bits");
+ }
+#endif
+ return code;
+}
+
+/* Remap a Pattern color. */
+cs_proc_remap_color(gx_remap_Pattern); /* check the prototype */
+int
+gx_remap_Pattern(const gs_client_color *pc, const gs_color_space *pcs,
+ gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
+ gs_color_select_t select)
+{ gs_pattern_instance *pinst = pc->pattern;
+ int code;
+
+ pdc->mask.ccolor = *pc;
+ if ( pinst == 0 )
+ { /* Null pattern */
+ color_set_null_pattern(pdc);
+ return 0;
+ }
+ if ( pinst->template.PaintType == 2 ) /* uncolored */
+ { code = (*pcs->params.pattern.base_space.type->remap_color)
+ (pc, (const gs_color_space *)&pcs->params.pattern.base_space, pdc, pis, dev, select);
+ if ( code < 0 )
+ return code;
+#define replace_dc_type(t, pt)\
+ if ( pdc->type == t ) pdc->type = &pt
+ replace_dc_type(gx_dc_type_pure, gx_dc_pure_masked);
+ else
+ replace_dc_type(gx_dc_type_ht_binary, gx_dc_binary_masked);
+ else
+ replace_dc_type(gx_dc_type_ht_colored, gx_dc_colored_masked);
+ else
+ return_error(gs_error_unregistered);
+#undef replace_dc_type
+ }
+ else
+ color_set_null_pattern(pdc);
+ pdc->mask.id = pinst->id;
+ pdc->mask.m_tile = 0;
+ return gx_pattern_load(pdc, pis, dev, select);
+}
diff --git a/gs/src/gxpcolor.h b/gs/src/gxpcolor.h
new file mode 100644
index 000000000..fd4fb1070
--- /dev/null
+++ b/gs/src/gxpcolor.h
@@ -0,0 +1,125 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpcolor.h */
+/* Internal definitions for Pattern colors */
+/* Requires gsmatrix.h, gxdevice.h, gxdevmem.h, gxcolor2.h, gxdcolor.h */
+#include "gxpcache.h"
+
+/*
+ * Define the Pattern device color types. There is one type for
+ * colored patterns, and one uncolored pattern type for each non-Pattern
+ * device color type.
+ */
+extern const gx_device_color_procs
+ gx_dc_pattern, gx_dc_pure_masked,
+ gx_dc_binary_masked, gx_dc_colored_masked;
+#define gx_dc_type_pattern (&gx_dc_pattern)
+
+/*
+ * Define a color tile, an entry in the rendered Pattern cache (and
+ * eventually in the colored halftone cache). Note that the depth is
+ * not sufficient to ensure that the rendering matches a given device;
+ * however, we don't currently have an object that represents the
+ * abstraction of a 'color representation'.
+ */
+struct gx_color_tile_s {
+ /* ------ The following are the 'key' in the cache. ------ */
+ /* Note that the id is a generated instance ID, */
+ /* and has no relation to the template's gs_uid. */
+ gx_bitmap_id id;
+ int depth;
+ /* We do, however, copy the template's gs_uid, */
+ /* for use in selective cache purging. */
+ gs_uid uid;
+ /* ------ The following are the cache 'value'. ------ */
+ /* Note that if tbits and tmask both have data != 0, */
+ /* both must have the same rep_shift. */
+ /****** NON-ZERO shift VALUES ARE NOT SUPPORTED YET. ******/
+ int tiling_type; /* TilingType */
+ gs_matrix step_matrix; /* tiling space -> device space, */
+ /* see gxcolor2.h for details */
+ gs_rect bbox; /* bbox of tile in tiling space */
+ gx_strip_bitmap tbits; /* data = 0 if uncolored */
+ gx_strip_bitmap tmask; /* data = 0 if no mask */
+ /* (i.e., the mask is all 1's) */
+ bool is_simple; /* true if xstep/ystep = tile size */
+ /* The following is neither key nor value. */
+ uint index; /* the index of the tile within */
+ /* the cache (for GC) */
+};
+#define private_st_color_tile() /* in gxpcmap.c */\
+ gs_private_st_ptrs2(st_color_tile, gx_color_tile, "gx_color_tile",\
+ color_tile_enum_ptrs, color_tile_reloc_ptrs, tbits.data, tmask.data)
+#define private_st_color_tile_element() /* in gxpcmap.c */\
+ gs_private_st_element(st_color_tile_element, gx_color_tile,\
+ "gx_color_tile[]", color_tile_elt_enum_ptrs, color_tile_elt_reloc_ptrs,\
+ st_color_tile)
+
+/* Define the Pattern cache. */
+/*#include "gxpcache.h"*/ /* (above) */
+
+/* Allocate a Pattern cache. */
+/* We shorten the procedure names because some VMS compilers */
+/* truncate names to 23 characters. */
+uint gx_pat_cache_default_tiles(P0());
+ulong gx_pat_cache_default_bits(P0());
+gx_pattern_cache *gx_pattern_alloc_cache(P3(gs_memory_t *, uint, ulong));
+
+/* Get or set the Pattern cache in a gstate. */
+gx_pattern_cache *gstate_pattern_cache(P1(gs_state *));
+void gstate_set_pattern_cache(P2(gs_state *, gx_pattern_cache *));
+
+/*
+ * Define a device for accumulating the rendering of a Pattern.
+ * This is actually a wrapper for two other devices: one that accumulates
+ * the actual pattern image (if this is a colored pattern), and one that
+ * accumulates a mask defining which pixels in the image are set.
+ */
+typedef struct gx_device_pattern_accum_s {
+ gx_device_forward_common;
+ /* Client sets these before opening */
+ gs_memory_t *bitmap_memory;
+ const gs_pattern_instance *instance;
+ /* open sets these */
+ gx_device_memory *bits; /* target also points to bits */
+ gx_device_memory *mask;
+} gx_device_pattern_accum;
+#define private_st_device_pattern_accum() /* in gxpcmap.c */\
+ gs_private_st_suffix_add3(st_device_pattern_accum, gx_device_pattern_accum,\
+ "pattern accumulator", pattern_accum_enum, pattern_accum_reloc,\
+ st_device_forward, instance, bits, mask)
+
+/* Allocate a pattern accumulator. */
+gx_device_pattern_accum *gx_pattern_accum_alloc(P2(gs_memory_t *memory, client_name_t));
+
+/* Add an accumulated pattern to the cache. */
+/* Note that this does not free any of the data in the accumulator */
+/* device, but it may zero out the bitmap_memory pointers to prevent */
+/* the accumulated bitmaps from being freed when the device is closed. */
+int gx_pattern_cache_add_entry(P3(gs_imager_state *, gx_device_pattern_accum *,
+ gx_color_tile **));
+
+/* Look up a pattern color in the cache. */
+bool gx_pattern_cache_lookup(P4(gx_device_color *, const gs_imager_state *,
+ gx_device *, gs_color_select_t));
+
+/* Purge selected entries from the pattern cache. */
+void gx_pattern_cache_winnow(P3(gx_pattern_cache *,
+ bool (*)(P2(gx_color_tile *, void *)),
+ void *));
diff --git a/gs/src/gxpcopy.c b/gs/src/gxpcopy.c
new file mode 100644
index 000000000..7381f60fb
--- /dev/null
+++ b/gs/src/gxpcopy.c
@@ -0,0 +1,806 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpcopy.c */
+/* Path copying and flattening */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gconfigv.h" /* for USE_FPU */
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gzpath.h"
+
+/* Forward declarations */
+private void adjust_point_to_tangent(P3(segment *, const segment *,
+ const gs_fixed_point *));
+private int monotonize_internal(P2(gx_path *, const curve_segment *));
+
+/* Copy a path, optionally flattening or monotonizing it. */
+/* If the copy fails, free the new path. */
+int
+gx_path_copy_reducing(const gx_path *ppath_old, gx_path *ppath,
+ fixed fixed_flatness, gx_path_copy_options options)
+{ gx_path old;
+ const segment *pseg;
+ int code;
+
+#ifdef DEBUG
+ if ( gs_debug_c('P') )
+ gx_dump_path(ppath_old, "before reducing");
+#endif
+ old = *ppath_old;
+ if ( options & pco_init )
+ gx_path_init(ppath, ppath_old->memory);
+ pseg = (const segment *)(old.first_subpath);
+ while ( pseg )
+ { switch ( pseg->type )
+ {
+ case s_start:
+ code = gx_path_add_point(ppath,
+ pseg->pt.x, pseg->pt.y);
+ break;
+ case s_curve:
+ { const curve_segment *pc = (const curve_segment *)pseg;
+ if ( fixed_flatness == max_fixed ) /* don't flatten */
+ { if ( options & pco_monotonize )
+ code = monotonize_internal(ppath, pc);
+ else
+ code = gx_path_add_curve_notes(ppath,
+ pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
+ pc->pt.x, pc->pt.y, pseg->notes);
+ }
+ else
+ { fixed x0 = ppath->position.x;
+ fixed y0 = ppath->position.y;
+ int k = gx_curve_log2_samples(x0, y0, pc,
+ fixed_flatness);
+ segment_notes notes = pseg->notes;
+ segment *start;
+ curve_segment cseg;
+
+ if ( options & pco_accurate )
+ { /* Add an extra line, which will become */
+ /* the tangent segment. */
+ code = gx_path_add_line_notes(ppath, x0, y0,
+ notes);
+ if ( code < 0 )
+ break;
+ start = ppath->current_subpath->last;
+ notes |= sn_not_first;
+ }
+ cseg = *pc;
+ code = gx_flatten_sample(ppath, k, &cseg, notes);
+ if ( options & pco_accurate )
+ { /*
+ * Adjust the first and last segments so that
+ * they line up with the tangents.
+ */
+ segment *end = ppath->current_subpath->last;
+
+ if ( code < 0 ||
+ (code = gx_path_add_line_notes(ppath,
+ ppath->position.x,
+ ppath->position.y,
+ pseg->notes | sn_not_first)) < 0
+ )
+ break;
+ adjust_point_to_tangent(start, start->next,
+ &pc->p1);
+ adjust_point_to_tangent(end, end->prev,
+ &pc->p2);
+ }
+ }
+ break;
+ }
+ case s_line:
+ code = gx_path_add_line_notes(ppath,
+ pseg->pt.x, pseg->pt.y, pseg->notes);
+ break;
+ case s_line_close:
+ code = gx_path_close_subpath(ppath);
+ break;
+ default: /* can't happen */
+ code = gs_note_error(gs_error_unregistered);
+ }
+ if ( code < 0 )
+ { gx_path_release(ppath);
+ if ( ppath == ppath_old )
+ *ppath = old;
+ return code;
+ }
+ pseg = pseg->next;
+ }
+ if ( path_last_is_moveto(&old) )
+ gx_path_add_point(ppath, old.position.x, old.position.y);
+#ifdef DEBUG
+ if ( gs_debug_c('P') )
+ gx_dump_path(ppath, "after reducing");
+#endif
+ return 0;
+}
+
+/*
+ * Adjust one end of a line (the first or last line of a flattened curve)
+ * so it falls on the curve tangent. The closest point on the line from
+ * (0,0) to (C,D) to a point (U,V) -- i.e., the point on the line at which
+ * a perpendicular line from the point intersects it -- is given by
+ * T = (C*U + D*V) / (C^2 + D^2)
+ * (X,Y) = (C*T,D*T)
+ * However, any smaller value of T will also work: the one we actually
+ * use is 0.25 * the value we just derived. We must check that
+ * numerical instabilities don't lead to a negative value of T.
+ */
+private void
+adjust_point_to_tangent(segment *pseg, const segment *next,
+ const gs_fixed_point *p1)
+{ const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
+ const fixed fC = p1->x - x0, fD = p1->y - y0;
+
+ /*
+ * By far the commonest case is that the end of the curve is
+ * horizontal or vertical. Check for this specially, because
+ * we can handle it with far less work (and no floating point).
+ */
+ if ( fC == 0 ) {
+ /* Vertical tangent. */
+ const fixed DT = arith_rshift(next->pt.y - y0, 2);
+
+ if ( fD == 0 )
+ return; /* anomalous case */
+ if_debug1('2', "[2]adjusting vertical: DT = %g\n",
+ fixed2float(DT));
+ if ( DT > 0 )
+ pseg->pt.y = DT + y0;
+ } else if ( fD == 0 ) {
+ /* Horizontal tangent. */
+ const fixed CT = arith_rshift(next->pt.x - x0, 2);
+
+ if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
+ fixed2float(CT));
+ if ( CT > 0 )
+ pseg->pt.x = CT + x0;
+ } else {
+ /* General case. */
+ const double C = fC, D = fD;
+ const double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
+ (C * C + D * D);
+
+ if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
+ C, D, T);
+ if ( T > 0 ) {
+ pseg->pt.x = arith_rshift((fixed)(C * T), 2) + x0;
+ pseg->pt.y = arith_rshift((fixed)(D * T), 2) + y0;
+ }
+ }
+}
+
+/* ---------------- Curve flattening ---------------- */
+
+#define x1 pc->p1.x
+#define y1 pc->p1.y
+#define x2 pc->p2.x
+#define y2 pc->p2.y
+#define x3 pc->pt.x
+#define y3 pc->pt.y
+
+#ifdef DEBUG
+private void
+dprint_curve(const char *str, fixed x0, fixed y0, const curve_segment *pc)
+{ dprintf9("%s p0=(%g,%g) p1=(%g,%g) p2=(%g,%g) p3=(%g,%g)\n",
+ str, fixed2float(x0), fixed2float(y0),
+ fixed2float(pc->p1.x), fixed2float(pc->p1.y),
+ fixed2float(pc->p2.x), fixed2float(pc->p2.y),
+ fixed2float(pc->pt.x), fixed2float(pc->pt.y));
+}
+#endif
+
+/* Initialize a cursor for rasterizing a monotonic curve. */
+void
+gx_curve_cursor_init(curve_cursor *prc, fixed x0, fixed y0,
+ const curve_segment *pc, int k)
+{ fixed v01, v12;
+ int k2 = k + k, k3 = k2 + k;
+
+#define bits_fit(v, n)\
+ (any_abs(v) <= max_fixed >> (n))
+/* The +2s are because of t3d and t2d, see below. */
+#define coeffs_fit(a, b, c)\
+ (k3 <= sizeof(fixed) * 8 - 3 &&\
+ bits_fit(a, k3 + 2) && bits_fit(b, k2 + 2) && bits_fit(c, k + 1))
+
+ prc->k = k;
+ prc->p0.x = x0, prc->p0.y = y0;
+ prc->pc = pc;
+ /* Compute prc->a..c taking into account reversal of xy0/3 */
+ /* in curve_x_at_y. */
+ { fixed w0, w1, w2, w3;
+ if ( y0 < y3 )
+ w0 = x0, w1 = x1, w2 = x2, w3 = x3;
+ else
+ w0 = x3, w1 = x2, w2 = x1, w3 = x0;
+ curve_points_to_coefficients(w0, w1, w2, w3,
+ prc->a, prc->b, prc->c, v01, v12);
+ }
+ prc->double_set = false;
+ prc->fixed_limit =
+ (coeffs_fit(prc->a, prc->b, prc->c) ? (1 << k) - 1 : -1);
+ /* Initialize the cache. */
+ prc->cache.ky0 = prc->cache.ky3 = y0;
+ prc->cache.xl = x0;
+ prc->cache.xd = 0;
+}
+
+/*
+ * Determine the X value on a monotonic curve at a given Y value. It turns
+ * out that we use so few points on the curve that it's actually faster to
+ * locate the desired point by recursive subdivision each time than to try
+ * to keep a cursor that we move incrementally. What's even more surprising
+ * is that if floating point arithmetic is reasonably fast, it's faster to
+ * compute the X value at the desired point explicitly than to do the
+ * recursive subdivision on X as well as Y.
+ */
+#define SUBDIVIDE_X USE_FPU_FIXED
+fixed
+gx_curve_x_at_y(curve_cursor *prc, fixed y)
+{ fixed xl, xd;
+ fixed yd, yrel;
+
+ /* Check the cache before doing anything else. */
+ if ( y >= prc->cache.ky0 && y <= prc->cache.ky3 )
+ { yd = prc->cache.ky3 - prc->cache.ky0;
+ yrel = y - prc->cache.ky0;
+ xl = prc->cache.xl;
+ xd = prc->cache.xd;
+ goto done;
+ }
+
+ {
+#define x0 prc->p0.x
+#define y0 prc->p0.y
+ const curve_segment *pc = prc->pc;
+ /* Reduce case testing by ensuring y3 >= y0. */
+ fixed cy0 = y0, cy1, cy2, cy3 = y3;
+ fixed cx0;
+#if SUBDIVIDE_X
+ fixed cx1, cx2, cx3;
+#else
+ int t = 0;
+#endif
+ int k, i;
+
+ if ( cy0 > cy3 )
+ cx0 = x3,
+#if SUBDIVIDE_X
+ cx1 = x2, cx2 = x1, cx3 = x0,
+#endif
+ cy0 = y3, cy1 = y2, cy2 = y1, cy3 = y0;
+ else
+ cx0 = x0,
+#if SUBDIVIDE_X
+ cx1 = x1, cx2 = x2, cx3 = x3,
+#endif
+ cy1 = y1, cy2 = y2;
+#define midpoint_fast(a,b)\
+ arith_rshift_1((a) + (b) + 1)
+ for ( i = k = prc->k; i > 0; --i )
+ {
+ fixed ym = midpoint_fast(cy1, cy2);
+ fixed yn = ym + arith_rshift(cy0 - cy1 - cy2 + cy3 + 4, 3);
+#if SUBDIVIDE_X
+ fixed xm = midpoint_fast(cx1, cx2);
+ fixed xn = xm + arith_rshift(cx0 - cx1 - cx2 + cx3 + 4, 3);
+#else
+ t <<= 1;
+#endif
+
+ if ( y < yn )
+#if SUBDIVIDE_X
+ cx1 = midpoint_fast(cx0, cx1),
+ cx2 = midpoint_fast(cx1, xm),
+ cx3 = xn,
+#endif
+ cy1 = midpoint_fast(cy0, cy1),
+ cy2 = midpoint_fast(cy1, ym),
+ cy3 = yn;
+ else
+#if SUBDIVIDE_X
+ cx2 = midpoint_fast(cx2, cx3),
+ cx1 = midpoint_fast(xm, cx2),
+ cx0 = xn,
+#else
+ t++,
+#endif
+ cy2 = midpoint_fast(cy2, cy3),
+ cy1 = midpoint_fast(ym, cy2),
+ cy0 = yn;
+ }
+#if SUBDIVIDE_X
+ xl = cx0;
+ xd = cx3 - cx0;
+#else
+ { fixed a = prc->a, b = prc->b, c = prc->c;
+
+/* We must use (1 << k) >> 1 instead of 1 << (k - 1) in case k == 0. */
+#define compute_fixed(a, b, c)\
+ arith_rshift(arith_rshift(arith_rshift(a * t3, k) + b * t2, k)\
+ + c * t + ((1 << k) >> 1), k)
+#define compute_diff_fixed(a, b, c)\
+ arith_rshift(arith_rshift(arith_rshift(a * t3d, k) + b * t2d, k)\
+ + c, k)
+
+ /* use multiply if possible */
+#define np2(n) (1.0 / (1L << (n)))
+ static const double k_denom[11] =
+ { np2(0), np2(1), np2(2), np2(3), np2(4),
+ np2(5), np2(6), np2(7), np2(8), np2(9), np2(10)
+ };
+ static const double k2_denom[11] =
+ { np2(0), np2(2), np2(4), np2(6), np2(8),
+ np2(10), np2(12), np2(14), np2(16), np2(18), np2(20)
+ };
+ static const double k3_denom[11] =
+ { np2(0), np2(3), np2(6), np2(9), np2(12),
+ np2(15), np2(18), np2(21), np2(24), np2(27), np2(30)
+ };
+ double den1, den2;
+#undef np2
+
+#define setup_floating(da, db, dc, a, b, c)\
+ (k >= countof(k_denom) ?\
+ (den1 = ldexp(1.0, -k),\
+ den2 = den1 * den1,\
+ da = (den2 * den1) * a,\
+ db = den2 * b,\
+ dc = den1 * c) :\
+ (da = k3_denom[k] * a,\
+ db = k2_denom[k] * b,\
+ dc = k_denom[k] * c))
+#define compute_floating(da, db, dc)\
+ ((fixed)(da * t3 + db * t2 + dc * t + 0.5))
+#define compute_diff_floating(da, db, dc)\
+ ((fixed)(da * t3d + db * t2d + dc))
+
+ if ( t <= prc->fixed_limit )
+ { /* We can do everything in integer/fixed point. */
+ int t2 = t * t, t3 = t2 * t;
+ int t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+ xl = compute_fixed(a, b, c) + cx0;
+ xd = compute_diff_fixed(a, b, c);
+#ifdef DEBUG
+ { double fa, fb, fc;
+ fixed xlf, xdf;
+ setup_floating(fa, fb, fc, a, b, c);
+ xlf = compute_floating(fa, fb, fc) + cx0;
+ xdf = compute_diff_floating(fa, fb, fc);
+ if ( any_abs(xlf - xl) > fixed_epsilon ||
+ any_abs(xdf - xd) > fixed_epsilon
+ )
+ dprintf9("Curve points differ: k=%d t=%d a,b,c=%g,%g,%g\n xl,xd fixed=%g,%g floating=%g,%g\n",
+ k, t,
+ fixed2float(a), fixed2float(b), fixed2float(c),
+ fixed2float(xl), fixed2float(xd),
+ fixed2float(xlf), fixed2float(xdf));
+/*xl = xlf, xd = xdf;*/
+ }
+#endif
+ }
+ else
+ { /*
+ * Either t3 (and maybe t2) won't fit in an int, or more
+ * likely the result of the multiplies won't fit.
+ */
+#define fa prc->da
+#define fb prc->db
+#define fc prc->dc
+ if ( !prc->double_set )
+ { setup_floating(fa, fb, fc, a, b, c);
+ prc->double_set = true;
+ }
+ if ( t < 1L << ((sizeof(long) * 8 - 1) / 3) )
+ { /*
+ * t3 (and maybe t2) might not fit in an int, but they
+ * will fit in a long. If we have slow floating point,
+ * do the computation in double-precision fixed point,
+ * otherwise do it in fixed point.
+ */
+ long t2 = (long)t * t, t3 = t2 * t;
+ long t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+
+ xl = compute_floating(fa, fb, fc) + cx0;
+ xd = compute_diff_floating(fa, fb, fc);
+ }
+ else
+ { /*
+ * t3 (and maybe t2) don't even fit in a long.
+ * Do the entire computation in floating point.
+ */
+ double t2 = (double)t * t, t3 = t2 * t;
+ double t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+
+ xl = compute_floating(fa, fb, fc) + cx0;
+ xd = compute_diff_floating(fa, fb, fc);
+ }
+#undef fa
+#undef fb
+#undef fc
+ }
+ }
+#endif /* (!)SUBDIVIDE_X */
+
+ /* Update the cache. */
+ prc->cache.ky0 = cy0;
+ prc->cache.ky3 = cy3;
+ prc->cache.xl = xl;
+ prc->cache.xd = xd;
+ yd = cy3 - cy0;
+ yrel = y - cy0;
+#undef x0
+#undef y0
+ }
+done:
+ /*
+ * Now interpolate linearly between current and next.
+ * We know that 0 <= yrel < yd.
+ * It's unlikely but possible that cy0 = y = cy3:
+ * handle this case specially.
+ */
+ if ( yrel == 0 )
+ return xl;
+ /*
+ * Compute in fixed point if possible.
+ */
+#define half_fixed_bits ((fixed)1 << (sizeof(fixed) * 4))
+ if ( yrel < half_fixed_bits )
+ { if ( xd >= 0 )
+ { if ( xd < half_fixed_bits )
+ return (ufixed)xd * (ufixed)yrel / (ufixed)yd + xl;
+ }
+ else
+ { if ( xd > -half_fixed_bits )
+ return -(fixed)((ufixed)(-xd) * (ufixed)yrel / (ufixed)yd) + xl;
+ }
+ }
+#undef half_fixed_bits
+ return fixed_mult_quo(xd, yrel, yd) + xl;
+}
+
+#undef x1
+#undef y1
+#undef x2
+#undef y2
+#undef x3
+#undef y3
+
+/* ---------------- Monotonic curves ---------------- */
+
+/* Test whether a path is free of non-monotonic curves. */
+bool
+gx_path_is_monotonic(const gx_path *ppath)
+{ const segment *pseg = (const segment *)(ppath->first_subpath);
+ gs_fixed_point pt0;
+
+ while ( pseg )
+ { switch ( pseg->type )
+ {
+ case s_start:
+ { const subpath *psub = (const subpath *)pseg;
+ /* Skip subpaths without curves. */
+ if ( !psub->curve_count )
+ pseg = psub->last;
+ }
+ break;
+ case s_curve:
+ { const curve_segment *pc = (const curve_segment *)pseg;
+ double t[2];
+ int nz = gx_curve_monotonic_points(pt0.y,
+ pc->p1.y, pc->p2.y, pc->pt.y, t);
+ if ( nz != 0 )
+ return false;
+ nz = gx_curve_monotonic_points(pt0.x,
+ pc->p1.x, pc->p2.x, pc->pt.x, t);
+ if ( nz != 0 )
+ return false;
+ }
+ break;
+ default:
+ ;
+ }
+ pt0 = pseg->pt;
+ pseg = pseg->next;
+ }
+ return true;
+}
+
+/* Monotonize a curve, by splitting it if necessary. */
+/* In the worst case, this could split the curve into 9 pieces. */
+private int
+monotonize_internal(gx_path *ppath, const curve_segment *pc)
+{ fixed x0 = ppath->position.x, y0 = ppath->position.y;
+ segment_notes notes = pc->notes;
+ double t[2];
+#define max_segs 9
+ curve_segment cs[max_segs];
+ const curve_segment *pcs;
+ curve_segment *pcd;
+ int i, j, nseg;
+ int nz;
+
+ /* Monotonize in Y. */
+ nz = gx_curve_monotonic_points(y0, pc->p1.y, pc->p2.y, pc->pt.y, t);
+ nseg = max_segs - 1 - nz;
+ pcd = cs + nseg;
+ if ( nz == 0 )
+ *pcd = *pc;
+ else
+ { gx_curve_split(x0, y0, pc, t[0], pcd, pcd + 1);
+ if ( nz == 2 )
+ gx_curve_split(pcd->pt.x, pcd->pt.y, pcd + 1,
+ (t[1] - t[0]) / (1 - t[0]),
+ pcd + 1, pcd + 2);
+ }
+
+ /* Monotonize in X. */
+ for ( pcs = pcd, pcd = cs, j = nseg; j < max_segs; ++pcs, ++j )
+ { nz = gx_curve_monotonic_points(x0, pcs->p1.x, pcs->p2.x,
+ pcs->pt.x, t);
+
+ if ( nz == 0 )
+ *pcd = *pcs;
+ else
+ { gx_curve_split(x0, y0, pcs, t[0], pcd, pcd + 1);
+ if ( nz == 2 )
+ gx_curve_split(pcd->pt.x, pcd->pt.y, pcd + 1,
+ (t[1] - t[0]) / (1 - t[0]),
+ pcd + 1, pcd + 2);
+ }
+ pcd += nz + 1;
+ x0 = pcd[-1].pt.x;
+ y0 = pcd[-1].pt.y;
+ }
+ nseg = pcd - cs;
+
+ /* Add the segment(s) to the output. */
+#ifdef DEBUG
+ if ( gs_debug_c('2') )
+ { int pi;
+ gs_fixed_point pp0;
+
+ pp0 = ppath->position;
+ if ( nseg == 1 )
+ dprint_curve("[2]No split", pp0.x, pp0.y, pc);
+ else
+ { dprintf1("[2]Split into %d segments:\n", nseg);
+ dprint_curve("[2]Original", pp0.x, pp0.y, pc);
+ for ( pi = 0; pi < nseg; ++pi )
+ { dprint_curve("[2] =>", pp0.x, pp0.y, cs + pi);
+ pp0 = cs[pi].pt;
+ }
+ }
+ }
+#endif
+ for ( pcs = cs, i = 0; i < nseg; ++pcs, ++i )
+ { int code = gx_path_add_curve_notes(ppath, pcs->p1.x, pcs->p1.y,
+ pcs->p2.x, pcs->p2.y,
+ pcs->pt.x, pcs->pt.y,
+ notes |
+ (i > 0 ? sn_not_first :
+ sn_none));
+ if ( code < 0 )
+ return code;
+ }
+
+ return 0;
+}
+
+/*
+ * Split a curve if necessary into pieces that are monotonic in X or Y as a
+ * function of the curve parameter t. This allows us to rasterize curves
+ * directly without pre-flattening. This takes a fair amount of analysis....
+ * Store the values of t of the split points in pst[0] and pst[1]. Return
+ * the number of split points (0, 1, or 2).
+ */
+int
+gx_curve_monotonic_points(fixed v0, fixed v1, fixed v2, fixed v3,
+ double pst[2])
+{
+ /*
+ Let
+ v(t) = a*t^3 + b*t^2 + c*t + d, 0 <= t <= 1.
+ Then
+ dv(t) = 3*a*t^2 + 2*b*t + c.
+ v(t) has a local minimum or maximum (or inflection point)
+ precisely where dv(t) = 0. Now the roots of dv(t) = 0 (i.e.,
+ the zeros of dv(t)) are at
+ t = ( -2*b +/- sqrt(4*b^2 - 12*a*c) ) / 6*a
+ = ( -b +/- sqrt(b^2 - 3*a*c) ) / 3*a
+ (Note that real roots exist iff b^2 >= 3*a*c.)
+ We want to know if these lie in the range (0..1).
+ (The endpoints don't count.) Call such a root a "valid zero."
+ Since computing the roots is expensive, we would like to have
+ some cheap tests to filter out cases where they don't exist
+ (i.e., where the curve is already monotonic).
+ */
+ fixed v01, v12, a, b, c, b2, a3;
+ fixed dv_end, b2abs, a3abs;
+
+ curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
+ b2 = b << 1;
+ a3 = (a << 1) + a;
+ /*
+ If a = 0, the only possible zero is t = -c / 2*b.
+ This zero is valid iff sign(c) != sign(b) and 0 < |c| < 2*|b|.
+ */
+ if ( a == 0 )
+ { if ( (b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0 )
+ { *pst = (double)(-c) / b2;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ /*
+ Iff a curve is horizontal at t = 0, c = 0. In this case,
+ there can be at most one other zero, at -2*b / 3*a.
+ This zero is valid iff sign(a) != sign(b) and 0 < 2*|b| < 3*|a|.
+ */
+ if ( c == 0 )
+ { if ( (a ^ b) < 0 && any_abs(b2) < any_abs(a3) && b != 0 )
+ { *pst = (double)(-b2) / a3;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ /*
+ Similarly, iff a curve is horizontal at t = 1, 3*a + 2*b + c = 0.
+ In this case, there can be at most one other zero,
+ at -1 - 2*b / 3*a, iff sign(a) != sign(b) and 1 < -2*b / 3*a < 2,
+ i.e., 3*|a| < 2*|b| < 6*|a|.
+ */
+ else if ( (dv_end = a3 + b2 + c) == 0 )
+ { if ( (a ^ b) < 0 &&
+ (b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
+ b2abs < a3abs << 1
+ )
+ { *pst = (double)(-b2 - a3) / a3;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ /*
+ If sign(dv_end) != sign(c), at least one valid zero exists,
+ since dv(0) and dv(1) have opposite signs and hence
+ dv(t) must be zero somewhere in the interval [0..1].
+ */
+ else if ( (dv_end ^ c) < 0 )
+ ;
+ /*
+ If sign(a) = sign(b), no valid zero exists,
+ since dv is monotonic on [0..1] and has the same sign
+ at both endpoints.
+ */
+ else if ( (a ^ b) >= 0 )
+ return 0;
+ /*
+ Otherwise, dv(t) may be non-monotonic on [0..1]; it has valid zeros
+ iff its sign anywhere in this interval is different from its sign
+ at the endpoints, which occurs iff it has an extremum in this
+ interval and the extremum is of the opposite sign from c.
+ To find this out, we look for the local extremum of dv(t)
+ by observing
+ d2v(t) = 6*a*t + 2*b
+ which has a zero only at
+ t1 = -b / 3*a
+ Now if t1 <= 0 or t1 >= 1, no valid zero exists.
+ Note that we just determined that sign(a) != sign(b), so we know t1 > 0.
+ */
+ else if ( any_abs(b) >= any_abs(a3) )
+ return 0;
+ /*
+ Otherwise, we just go ahead with the computation of the roots,
+ and test them for being in the correct range. Note that a valid
+ zero is an inflection point of v(t) iff d2v(t) = 0; we don't
+ bother to check for this case, since it's rare.
+ */
+ { double nbf = (double)(-b);
+ double a3f = (double)a3;
+ double radicand = nbf * nbf - a3f * c;
+
+ if ( radicand < 0 )
+ { if_debug1('2', "[2]negative radicand = %g\n", radicand);
+ return 0;
+ }
+ { double root = sqrt(radicand);
+ int nzeros = 0;
+ double z = (nbf - root) / a3f;
+
+ /*
+ * We need to return the zeros in the correct order.
+ * We know that root is non-negative, but a3f may be either
+ * positive or negative, so we need to check the ordering
+ * explicitly.
+ */
+ if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
+ if ( z > 0 && z < 1 )
+ *pst = z, nzeros = 1;
+ if ( root != 0 )
+ { z = (nbf + root) / a3f;
+ if ( z > 0 && z < 1 )
+ { if ( nzeros && a3f < 0 ) /* order is reversed */
+ pst[1] = *pst, *pst = z;
+ else
+ pst[nzeros] = z;
+ nzeros++;
+ }
+ }
+ return nzeros;
+ }
+ }
+}
+
+/*
+ * Split a curve at an arbitrary point t. The above midpoint split is a
+ * special case of this with t = 0.5.
+ */
+void
+gx_curve_split(fixed x0, fixed y0, const curve_segment *pc, double t,
+ curve_segment *pc1, curve_segment *pc2)
+{ /*
+ * If the original function was v(t), we want to compute the points
+ * for the functions v1(T) = v(t * T) and v2(T) = v(t + (1 - t) * T).
+ * Straightforwardly,
+ * v1(T) = a*t^3*T^3 + b*t^2*T^2 + c*t*T + d
+ * i.e.
+ * a1 = a*t^3, b1 = b*t^2, c1 = c*t, d1 = d.
+ * Similarly,
+ * v2(T) = a*[t + (1-t)*T]^3 + b*[t + (1-t)*T]^2 +
+ * c*[t + (1-t)*T] + d
+ * = a*[(1-t)^3*T^3 + 3*t*(1-t)^2*T^2 + 3*t^2*(1-t)*T +
+ * t^3] + b*[(1-t)^2*T^2 + 2*t*(1-t)*T + t^2] +
+ * c*[(1-t)*T + t] + d
+ * = a*(1-t)^3*T^3 + [a*3*t + b]*(1-t)^2*T^2 +
+ * [a*3*t^2 + b*2*t + c]*(1-t)*T +
+ * a*t^3 + b*t^2 + c*t + d
+ * We do this in the simplest way, namely, we convert the points to
+ * coefficients, do the arithmetic, and convert back. It would
+ * obviously be faster to do the arithmetic directly on the points,
+ * as the midpoint code does; this is just an implementation issue
+ * that we can revisit if necessary.
+ */
+ double t2 = t * t, t3 = t2 * t;
+ double omt = 1 - t, omt2 = omt * omt, omt3 = omt2 * omt;
+ fixed v01, v12, a, b, c, na, nb, nc;
+
+ if_debug1('2', "[2]splitting at t = %g\n", t);
+#define compute_seg(v0, v)\
+ curve_points_to_coefficients(v0, pc->p1.v, pc->p2.v, pc->pt.v,\
+ a, b, c, v01, v12);\
+ na = (fixed)(a * t3), nb = (fixed)(b * t2), nc = (fixed)(c * t);\
+ curve_coefficients_to_points(na, nb, nc, v0,\
+ pc1->p1.v, pc1->p2.v, pc1->pt.v);\
+ na = (fixed)(a * omt3);\
+ nb = (fixed)((a * t * 3 + b) * omt2);\
+ nc = (fixed)((a * t2 * 3 + b * 2 * t + c) * omt);\
+ curve_coefficients_to_points(na, nb, nc, pc1->pt.v,\
+ pc2->p1.v, pc2->p2.v, pc2->pt.v)
+ compute_seg(x0, x);
+ compute_seg(y0, y);
+#undef compute_seg
+}
diff --git a/gs/src/gxpdash.c b/gs/src/gxpdash.c
new file mode 100644
index 000000000..496594acd
--- /dev/null
+++ b/gs/src/gxpdash.c
@@ -0,0 +1,187 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpdash.c */
+/* Dash expansion for paths */
+#include "math_.h"
+#include "gx.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxfixed.h"
+#include "gsline.h"
+#include "gzline.h"
+#include "gzpath.h"
+
+/* Expand a dashed path into explicit segments. */
+/* The path contains no curves. */
+private int subpath_expand_dashes(P4(const subpath *, gx_path *,
+ const gs_imager_state *,
+ const gx_dash_params *));
+int
+gx_path_expand_dashes(const gx_path *ppath_old, gx_path *ppath,
+ const gs_imager_state *pis)
+{ const subpath *psub;
+ const gx_dash_params *dash = &gs_currentlineparams(pis)->dash;
+ int code = 0;
+
+ if ( dash->pattern_size == 0 )
+ return gx_path_copy(ppath_old, ppath, true);
+ gx_path_init(ppath, ppath_old->memory);
+ for ( psub = ppath_old->first_subpath; psub != 0 && code >= 0;
+ psub = (const subpath *)psub->last->next
+ )
+ code = subpath_expand_dashes(psub, ppath, pis, dash);
+ if ( code < 0 )
+ gx_path_release(ppath);
+ return code;
+}
+
+private int
+subpath_expand_dashes(const subpath *psub, gx_path *ppath,
+ const gs_imager_state *pis, const gx_dash_params *dash)
+{ const float *pattern = dash->pattern;
+ int count, index;
+ bool ink_on;
+ float elt_length;
+ fixed x0 = psub->pt.x, y0 = psub->pt.y;
+ fixed x, y;
+ const segment *pseg;
+ int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0);
+ int drawing = wrap;
+ segment_notes notes = ~sn_not_first;
+ int code;
+
+ if ( (code = gx_path_add_point(ppath, x0, y0)) < 0 )
+ return code;
+ /*
+ * To do the right thing at the beginning of a closed path, we have
+ * to skip any initial line, and then redo it at the end of the
+ * path. Drawing = -1 while skipping, 0 while drawing normally, and
+ * 1 on the second round. Note that drawing != 0 implies ink_on.
+ */
+top: count = dash->pattern_size;
+ ink_on = dash->init_ink_on;
+ index = dash->init_index;
+ elt_length = dash->init_dist_left;
+ x = x0, y = y0;
+ pseg = (const segment *)psub;
+ while ( (pseg = pseg->next) != 0 && pseg->type != s_start )
+ { fixed sx = pseg->pt.x, sy = pseg->pt.y;
+ fixed udx = sx - x, udy = sy - y;
+ double length, dx, dy;
+ double scale = 1;
+ double left;
+
+ if ( !(udx | udy) ) /* degenerate */
+ dx = 0, dy = 0, length = 0;
+ else
+ { gs_point d;
+ dx = udx, dy = udy; /* scaled as fixed */
+ gs_imager_idtransform(pis, dx, dy, &d);
+ length = hypot(d.x, d.y) * (1.0 / fixed_1);
+ if ( gs_imager_currentdashadapt(pis) )
+ { double reps = length / dash->pattern_length;
+ scale = reps / ceil(reps);
+ /* Ensure we're starting at the start of a */
+ /* repetition. (This shouldn't be necessary, */
+ /* but it is.) */
+ count = dash->pattern_size;
+ ink_on = dash->init_ink_on;
+ index = dash->init_index;
+ elt_length = dash->init_dist_left * scale;
+ }
+ }
+ left = length;
+ while ( left > elt_length )
+ { /* We are using up the line segment. */
+ double fraction = elt_length / length;
+ fixed nx = x + (fixed)(dx * fraction);
+ fixed ny = y + (fixed)(dy * fraction);
+
+ if ( ink_on )
+ { if ( drawing >= 0 )
+ code = gx_path_add_line_notes(ppath, nx, ny,
+ notes & pseg->notes);
+ notes |= sn_not_first;
+ }
+ else
+ { if ( drawing > 0 ) /* done */
+ return 0;
+ code = gx_path_add_point(ppath, nx, ny);
+ notes &= ~sn_not_first;
+ drawing = 0;
+ }
+ if ( code < 0 )
+ return code;
+ left -= elt_length;
+ ink_on = !ink_on;
+ if ( ++index == count )
+ index = 0;
+ elt_length = pattern[index] * scale;
+ x = nx, y = ny;
+ }
+ elt_length -= left;
+ /* Handle the last dash of a segment. */
+on: if ( ink_on )
+ { if ( drawing >= 0 )
+ { code =
+ (pseg->type == s_line_close && drawing > 0 ?
+ gx_path_close_subpath_notes(ppath,
+ notes & pseg->notes) :
+ gx_path_add_line_notes(ppath, sx, sy,
+ notes & pseg->notes));
+ notes |= sn_not_first;
+ }
+ }
+ else
+ { code = gx_path_add_point(ppath, sx, sy);
+ notes &= ~sn_not_first;
+ if ( elt_length < fixed2float(fixed_epsilon) &&
+ (pseg->next == 0 || pseg->next->type == s_start)
+ )
+ { /*
+ * Ink is off, but we're within epsilon of the end
+ * of the dash element, and at the end of the
+ * subpath. "Stretch" a little so we get a dot.
+ */
+ if ( code < 0 )
+ return code;
+ elt_length = 0;
+ ink_on = true;
+ if ( ++index == count )
+ index = 0;
+ elt_length = pattern[index] * scale;
+ goto on;
+ }
+ if ( drawing > 0 ) /* done */
+ return code;
+ drawing = 0;
+ }
+ if ( code < 0 )
+ return code;
+ x = sx, y = sy;
+ }
+ /* Check for wraparound. */
+ if ( wrap && drawing <= 0 )
+ { /* We skipped some initial lines. */
+ /* Go back and do them now. */
+ drawing = 1;
+ goto top;
+ }
+ return 0;
+}
diff --git a/gs/src/gxpflat.c b/gs/src/gxpflat.c
new file mode 100644
index 000000000..a4df12c3b
--- /dev/null
+++ b/gs/src/gxpflat.c
@@ -0,0 +1,452 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxpflat.c */
+/* Path flattening algorithms */
+#include "gx.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+
+/* Define whether to merge nearly collinear line segments when flattening */
+/* curves. This is very good for performance, but we feel a little */
+/* uneasy about its effects on character appearance. */
+#define MERGE_COLLINEAR_SEGMENTS 1
+
+/* ---------------- Curve flattening ---------------- */
+
+#define x1 pc->p1.x
+#define y1 pc->p1.y
+#define x2 pc->p2.x
+#define y2 pc->p2.y
+#define x3 pc->pt.x
+#define y3 pc->pt.y
+
+/*
+ * To calculate how many points to sample along a path in order to
+ * approximate it to the desired degree of flatness, we define
+ * dist((x,y)) = abs(x) + abs(y);
+ * then the number of points we need is
+ * N = 1 + sqrt(3/4 * D / flatness),
+ * where
+ * D = max(dist(p0 - 2*p1 + p2), dist(p1 - 2*p2 + p3)).
+ * Since we are going to use a power of 2 for the number of intervals,
+ * we can avoid the square root by letting
+ * N = 1 + 2^(ceiling(log2(3/4 * D / flatness) / 2)).
+ * (Reference: DEC Paris Research Laboratory report #1, May 1989.)
+ *
+ * We treat two cases specially. First, if the curve is very
+ * short, we halve the flatness, to avoid turning short shallow curves
+ * into short straight lines. Second, if the curve forms part of a
+ * character (indicated by flatness = 0), we let
+ * N = 1 + 2 * max(abs(x3-x0), abs(y3-y0)).
+ * This is probably too conservative, but it produces good results.
+ */
+int
+gx_curve_log2_samples(fixed x0, fixed y0, const curve_segment *pc,
+ fixed fixed_flat)
+{ fixed
+ x03 = x3 - x0,
+ y03 = y3 - y0;
+ int k;
+
+ if ( x03 < 0 )
+ x03 = -x03;
+ if ( y03 < 0 )
+ y03 = -y03;
+ if ( (x03 | y03) < int2fixed(16) )
+ fixed_flat >>= 1;
+ if ( fixed_flat == 0 )
+ { /* Use the conservative method. */
+ fixed m = max(x03, y03);
+ for ( k = 1; m > fixed_1; )
+ k++, m >>= 1;
+ }
+ else
+ { const fixed
+ x12 = x1 - x2,
+ y12 = y1 - y2,
+ dx0 = x0 - x1 - x12,
+ dy0 = y0 - y1 - y12,
+ dx1 = x12 - x2 + x3,
+ dy1 = y12 - y2 + y3,
+ adx0 = any_abs(dx0),
+ ady0 = any_abs(dy0),
+ adx1 = any_abs(dx1),
+ ady1 = any_abs(dy1);
+ fixed
+ d = max(adx0, adx1) + max(ady0, ady1);
+ /*
+ * The following statement is split up to work around a
+ * bug in the gcc 2.7.2 optimizer on H-P RISC systems.
+ */
+ uint qtmp = d - (d >> 2) /* 3/4 * D */ + fixed_flat - 1;
+ uint q = qtmp / fixed_flat;
+
+ if_debug6('2', "[2]d01=%g,%g d12=%g,%g d23=%g,%g\n",
+ fixed2float(x1 - x0), fixed2float(y1 - y0),
+ fixed2float(-x12), fixed2float(-y12),
+ fixed2float(x3 - x2), fixed2float(y3 - y2));
+ if_debug2('2', " D=%f, flat=%f,",
+ fixed2float(d), fixed2float(fixed_flat));
+ /* Now we want to set k = ceiling(log2(q) / 2). */
+ for ( k = 0; q > 1; )
+ k++, q = (q + 3) >> 2;
+ if_debug1('2', " k=%d\n", k);
+ }
+ return k;
+}
+
+/*
+ * Define the maximum number of points for sampling if we want accurate
+ * rasterizing. 2^(k_sample_max*3)-1 must fit into a uint with a bit
+ * to spare; also, we must be able to compute 1/2^(3*k) by table lookup.
+ */
+#define k_sample_max min((size_of(int) * 8 - 1) / 3, 10)
+
+/*
+ * Split a curve segment into two pieces at the (parametric) midpoint.
+ * Algorithm is from "The Beta2-split: A special case of the Beta-spline
+ * Curve and Surface Representation," B. A. Barsky and A. D. DeRose, IEEE,
+ * 1985, courtesy of Crispin Goswell.
+ */
+private void
+split_curve_midpoint(fixed x0, fixed y0, const curve_segment *pc,
+ curve_segment *pc1, curve_segment *pc2)
+{ /*
+ * We have to define midpoint carefully to avoid overflow.
+ * (If it overflows, something really pathological is going
+ * on, but we could get infinite recursion that way....)
+ */
+#define midpoint(a,b)\
+ (arith_rshift_1(a) + arith_rshift_1(b) + ((a) & (b) & 1) + 1)
+ fixed x12 = midpoint(x1, x2);
+ fixed y12 = midpoint(y1, y2);
+
+ /*
+ * pc1 or pc2 may be the same as pc, so we must be a little careful
+ * about the order in which we store the results.
+ */
+ pc1->p1.x = midpoint(x0, x1);
+ pc1->p1.y = midpoint(y0, y1);
+ pc2->p2.x = midpoint(x2, x3);
+ pc2->p2.y = midpoint(y2, y3);
+ pc1->p2.x = midpoint(pc1->p1.x, x12);
+ pc1->p2.y = midpoint(pc1->p1.y, y12);
+ pc2->p1.x = midpoint(x12, pc2->p2.x);
+ pc2->p1.y = midpoint(y12, pc2->p2.y);
+ if ( pc2 != pc )
+ pc2->pt.x = pc->pt.x,
+ pc2->pt.y = pc->pt.y;
+ pc1->pt.x = midpoint(pc1->p2.x, pc2->p1.x);
+ pc1->pt.y = midpoint(pc1->p2.y, pc2->p1.y);
+#undef midpoint
+}
+
+/*
+ * Flatten a segment of the path by repeated sampling.
+ * 2^k is the number of lines to produce (i.e., the number of points - 1,
+ * including the endpoints); we require k >= 1.
+ * If k or any of the coefficient values are too large,
+ * use recursive subdivision to whittle them down.
+ */
+int
+gx_flatten_sample(gx_path *ppath, int k, curve_segment *pc,
+ segment_notes notes)
+{ fixed x0, y0;
+ /* x1 ... y3 were defined above */
+ fixed cx, bx, ax, cy, by, ay;
+ fixed ptx, pty;
+ fixed x, y;
+ /*
+ * We can compute successive values by finite differences,
+ * using the formulas:
+ x(t) =
+ a*t^3 + b*t^2 + c*t + d =>
+ dx(t) = x(t+e)-x(t) =
+ a*(3*t^2*e + 3*t*e^2 + e^3) + b*(2*t*e + e^2) + c*e =
+ (3*a*e)*t^2 + (3*a*e^2 + 2*b*e)*t + (a*e^3 + b*e^2 + c*e) =>
+ d2x(t) = dx(t+e)-dx(t) =
+ (3*a*e)*(2*t*e + e^2) + (3*a*e^2 + 2*b*e)*e =
+ (6*a*e^2)*t + (6*a*e^3 + 2*b*e^2) =>
+ d3x(t) = d2x(t+e)-d2x(t) =
+ 6*a*e^3;
+ x(0) = d, dx(0) = (a*e^3 + b*e^2 + c*e),
+ d2x(0) = 6*a*e^3 + 2*b*e^2;
+ * In these formulas, e = 1/2^k; of course, there are separate
+ * computations for the x and y values.
+ *
+ * There is a tradeoff in doing the above computation in fixed
+ * point. If we separate out the constant term (d) and require that
+ * all the other values fit in a long, then on a 32-bit machine with
+ * 12 bits of fraction in a fixed, k = 4 implies a maximum curve
+ * size of 128 pixels; anything larger requires subdividing the
+ * curve. On the other hand, doing the computations in explicit
+ * double precision slows down the loop by a factor of 3 or so. We
+ * found to our surprise that the latter is actually faster, because
+ * the additional subdivisions cost more than the slower loop.
+ *
+ * We represent each quantity as I+R/M, where I is an "integer" and
+ * the "remainder" R lies in the range 0 <= R < M=2^(3*k). Note
+ * that R may temporarily exceed M; for this reason, we require that
+ * M have at least one free high-order bit. To reduce the number of
+ * variables, we don't actually compute M, only M-1 (rmask). */
+ uint i;
+ uint rmask; /* M-1 */
+ fixed idx, idy, id2x, id2y, id3x, id3y; /* I */
+ uint rx, ry, rdx, rdy, rd2x, rd2y, rd3x, rd3y; /* R */
+ gs_fixed_point _ss *ppt;
+#define max_points 50 /* arbitrary */
+ gs_fixed_point points[max_points + 1];
+
+top: x0 = ppath->position.x;
+ y0 = ppath->position.y;
+#ifdef DEBUG
+ if ( gs_debug_c('3') )
+ dprintf4("[3]x0=%f y0=%f x1=%f y1=%f\n",
+ fixed2float(x0), fixed2float(y0),
+ fixed2float(x1), fixed2float(y1)),
+ dprintf5(" x2=%f y2=%f x3=%f y3=%f k=%d\n",
+ fixed2float(x2), fixed2float(y2),
+ fixed2float(x3), fixed2float(y3), k);
+#endif
+ { fixed x01, x12, y01, y12;
+ curve_points_to_coefficients(x0, x1, x2, x3, ax, bx, cx,
+ x01, x12);
+ curve_points_to_coefficients(y0, y1, y2, y3, ay, by, cy,
+ y01, y12);
+ }
+
+ if_debug6('3', "[3]ax=%f bx=%f cx=%f\n ay=%f by=%f cy=%f\n",
+ fixed2float(ax), fixed2float(bx), fixed2float(cx),
+ fixed2float(ay), fixed2float(by), fixed2float(cy));
+#define max_fast (max_fixed / 6)
+#define min_fast (-max_fast)
+#define in_range(v) (v < max_fast && v > min_fast)
+ if ( k == 0 )
+ { /* The curve is very short, or anomalous in some way. */
+ /* Just add a line and exit. */
+ return gx_path_add_line_notes(ppath, x3, y3, notes);
+ }
+ if ( k <= k_sample_max &&
+ in_range(ax) && in_range(ay) &&
+ in_range(bx) && in_range(by) &&
+ in_range(cx) && in_range(cy)
+ )
+ { x = x0, y = y0;
+ rx = ry = 0;
+ ppt = points;
+ /* Fast check for n == 3, a common special case */
+ /* for small characters. */
+ if ( k == 1 )
+ {
+#define poly2(a,b,c)\
+ arith_rshift_1(arith_rshift_1(arith_rshift_1(a) + b) + c)
+ x += poly2(ax, bx, cx);
+ y += poly2(ay, by, cy);
+#undef poly2
+ if_debug2('3', "[3]dx=%f, dy=%f\n",
+ fixed2float(x - x0), fixed2float(y - y0));
+ if_debug3('3', "[3]%s x=%g, y=%g\n",
+ (((x ^ x0) | (y ^ y0)) & float2fixed(-0.5) ?
+ "add" : "skip"),
+ fixed2float(x), fixed2float(y));
+ if ( ((x ^ x0) | (y ^ y0)) & float2fixed(-0.5) )
+ ppt->x = ptx = x,
+ ppt->y = pty = y,
+ ppt++;
+ goto last;
+ }
+ else
+ { fixed bx2 = bx << 1, by2 = by << 1;
+ fixed ax6 = ((ax << 1) + ax) << 1,
+ ay6 = ((ay << 1) + ay) << 1;
+#define adjust_rem(r, q)\
+ if ( r > rmask ) q ++, r &= rmask
+ const int k2 = k << 1;
+ const int k3 = k2 + k;
+ rmask = (1 << k3) - 1;
+ /* We can compute all the remainders as ints, */
+ /* because we know they don't exceed M. */
+ /* cx/y terms */
+ idx = arith_rshift(cx, k),
+ idy = arith_rshift(cy, k);
+ rdx = ((uint)cx << k2) & rmask,
+ rdy = ((uint)cy << k2) & rmask;
+ /* bx/y terms */
+ id2x = arith_rshift(bx2, k2),
+ id2y = arith_rshift(by2, k2);
+ rd2x = ((uint)bx2 << k) & rmask,
+ rd2y = ((uint)by2 << k) & rmask;
+ idx += arith_rshift_1(id2x),
+ idy += arith_rshift_1(id2y);
+ rdx += ((uint)bx << k) & rmask,
+ rdy += ((uint)by << k) & rmask;
+ adjust_rem(rdx, idx);
+ adjust_rem(rdy, idy);
+ /* ax/y terms */
+ idx += arith_rshift(ax, k3),
+ idy += arith_rshift(ay, k3);
+ rdx += (uint)ax & rmask,
+ rdy += (uint)ay & rmask;
+ adjust_rem(rdx, idx);
+ adjust_rem(rdy, idy);
+ id2x += id3x = arith_rshift(ax6, k3),
+ id2y += id3y = arith_rshift(ay6, k3);
+ rd2x += rd3x = (uint)ax6 & rmask,
+ rd2y += rd3y = (uint)ay6 & rmask;
+ adjust_rem(rd2x, id2x);
+ adjust_rem(rd2y, id2y);
+#undef adjust_rem
+ }
+ }
+ else
+ { /*
+ * Curve is too long. Break into two pieces and recur.
+ */
+ curve_segment cseg;
+ int code;
+
+ k--;
+ split_curve_midpoint(x0, y0, pc, &cseg, pc);
+ code = gx_flatten_sample(ppath, k, &cseg, notes);
+ if ( code < 0 )
+ return code;
+ notes |= sn_not_first;
+ goto top;
+ }
+ if_debug1('2', "[2]sampling k=%d\n", k);
+ ptx = x0, pty = y0;
+ for ( i = (1 << k) - 1; ; )
+ { int code;
+#ifdef DEBUG
+ if ( gs_debug_c('3') )
+ dprintf4("[3]dx=%f+%d, dy=%f+%d\n",
+ fixed2float(idx), rdx,
+ fixed2float(idy), rdy),
+ dprintf4(" d2x=%f+%d, d2y=%f+%d\n",
+ fixed2float(id2x), rd2x,
+ fixed2float(id2y), rd2y),
+ dprintf4(" d3x=%f+%d, d3y=%f+%d\n",
+ fixed2float(id3x), rd3x,
+ fixed2float(id3y), rd3y);
+#endif
+#define accum(i, r, di, dr)\
+ if ( (r += dr) > rmask ) r &= rmask, i += di + 1;\
+ else i += di
+ accum(x, rx, idx, rdx);
+ accum(y, ry, idy, rdy);
+ if_debug3('3', "[3]%s x=%g, y=%g\n",
+ (((x ^ ptx) | (y ^ pty)) & float2fixed(-0.5) ?
+ "add" : "skip"),
+ fixed2float(x), fixed2float(y));
+ /*
+ * Skip very short segments -- those that lie entirely within
+ * a square half-pixel. Also merge nearly collinear
+ * segments -- those where one coordinate of all three points
+ * (the two endpoints and the midpoint) lie within the same
+ * half-pixel and both coordinates are monotonic.
+ * Note that ptx/y, the midpoint, is the same as ppt[-1].x/y;
+ * the previous point is ppt[-2].x/y.
+ */
+#define coord_near(v, ptv)\
+ (!( ((v) ^ (ptv)) & float2fixed(-0.5) ))
+#define coords_in_order(v0, v1, v2)\
+ ( (((v1) - (v0)) ^ ((v2) - (v1))) >= 0 )
+ if ( coord_near(x, ptx) )
+ { /* X coordinates are within a half-pixel. */
+ if ( coord_near(y, pty) )
+ goto skip; /* short segment */
+#if MERGE_COLLINEAR_SEGMENTS
+ /* Check for collinear segments. */
+ if ( ppt > points + 1 && coord_near(x, ppt[-2].x) &&
+ coords_in_order(ppt[-2].x, ptx, x) &&
+ coords_in_order(ppt[-2].y, pty, y)
+ )
+ --ppt; /* remove middle point */
+#endif
+ }
+ else if ( coord_near(y, pty) )
+ { /* Y coordinates are within a half-pixel. */
+#if MERGE_COLLINEAR_SEGMENTS
+ /* Check for collinear segments. */
+ if ( ppt > points + 1 && coord_near(y, ppt[-2].y) &&
+ coords_in_order(ppt[-2].x, ptx, x) &&
+ coords_in_order(ppt[-2].y, pty, y)
+ )
+ --ppt; /* remove middle point */
+#endif
+ }
+#undef coord_near
+#undef coords_in_order
+ /* Add a line. */
+ if ( ppt == &points[max_points] )
+ { if ( notes & sn_not_first )
+ code = gx_path_add_lines_notes(ppath, points, max_points,
+ notes);
+ else
+ { code = gx_path_add_line_notes(ppath, points[0].x,
+ points[0].y, notes);
+ if ( code < 0 )
+ return code;
+ code = gx_path_add_lines_notes(ppath, points,
+ max_points - 1, notes | sn_not_first);
+ }
+ if ( code < 0 )
+ return code;
+ ppt = points;
+ notes |= sn_not_first;
+ }
+ ppt->x = ptx = x;
+ ppt->y = pty = y;
+ ppt++;
+skip: if ( --i == 0 )
+ break; /* don't bother with last accum */
+ accum(idx, rdx, id2x, rd2x);
+ accum(id2x, rd2x, id3x, rd3x);
+ accum(idy, rdy, id2y, rd2y);
+ accum(id2y, rd2y, id3y, rd3y);
+#undef accum
+ }
+last: if_debug2('3', "[3]last x=%g, y=%g\n",
+ fixed2float(x3), fixed2float(y3));
+ if ( ppt > points )
+ { int count = ppt + 1 - points;
+ gs_fixed_point _ss *pts = points;
+
+ if ( !(notes & sn_not_first) )
+ { int code = gx_path_add_line_notes(ppath,
+ points[0].x, points[0].y,
+ notes);
+ if ( code < 0 )
+ return code;
+ ++pts, --count;
+ notes |= sn_not_first;
+ }
+ ppt->x = x3, ppt->y = y3;
+ return gx_path_add_lines_notes(ppath, pts, count, notes);
+ }
+ return gx_path_add_line_notes(ppath, x3, y3, notes);
+}
+
+#undef x1
+#undef y1
+#undef x2
+#undef y2
+#undef x3
+#undef y3
diff --git a/gs/src/gxsample.c b/gs/src/gxsample.c
new file mode 100644
index 000000000..222769e98
--- /dev/null
+++ b/gs/src/gxsample.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxsample.c */
+/* Sample unpacking procedures */
+#include "gx.h"
+#include "gxsample.h"
+
+/* ---------------- Lookup tables ---------------- */
+
+/*
+ * Define standard tables for spreading 1-bit input data.
+ * Note that these depend on the end-orientation of the CPU.
+ * We can't simply define them as byte arrays, because
+ * they might not wind up properly long- or short-aligned.
+ */
+#define map4tox(z,a,b,c,d)\
+ z, z^a, z^b, z^(a+b),\
+ z^c, z^(a+c), z^(b+c), z^(a+b+c),\
+ z^d, z^(a+d), z^(b+d), z^(a+b+d),\
+ z^(c+d), z^(a+c+d), z^(b+c+d), z^(a+b+c+d)
+#if arch_is_big_endian
+const bits32 lookup4x1to32_identity[16] =
+ { map4tox(0L, 0xffL, 0xff00L, 0xff0000L, 0xff000000L) };
+const bits32 lookup4x1to32_inverted[16] =
+ { map4tox(0xffffffffL, 0xffL, 0xff00L, 0xff0000L, 0xff000000L) };
+#else /* !arch_is_big_endian */
+const bits32 lookup4x1to32_identity[16] =
+ { map4tox(0L, 0xff000000L, 0xff0000L, 0xff00L, 0xffL) };
+const bits32 lookup4x1to32_inverted[16] =
+ { map4tox(0xffffffffL, 0xff000000L, 0xff0000L, 0xff00L, 0xffL) };
+#endif
+
+/* ---------------- Unpacking procedures ---------------- */
+
+const byte *
+sample_unpack_copy(byte *bptr, int *pdata_x, const byte *data, int data_x,
+ uint dsize, const sample_lookup_t *ignore_ptab, int spread)
+{ /* We're going to use the data right away, so no copying is needed. */
+ *pdata_x = data_x;
+ return data;
+}
+
+const byte *
+sample_unpack_1(byte *bptr, int *pdata_x, const byte *data, int data_x,
+ uint dsize, const sample_lookup_t *ptab, int spread)
+{ const byte *psrc = data + (data_x >> 3);
+ int left = dsize - (data_x >> 3);
+
+ if ( spread == 1 )
+ { bits32 *bufp = (bits32 *)bptr;
+ const bits32 *map = &ptab->lookup4x1to32[0];
+ uint b;
+
+ if ( left & 1 )
+ { b = psrc[0];
+ bufp[0] = map[b >> 4];
+ bufp[1] = map[b & 0xf];
+ psrc++, bufp += 2;
+ }
+ left >>= 1;
+ while ( left-- )
+ { b = psrc[0];
+ bufp[0] = map[b >> 4];
+ bufp[1] = map[b & 0xf];
+ b = psrc[1];
+ bufp[2] = map[b >> 4];
+ bufp[3] = map[b & 0xf];
+ psrc += 2, bufp += 4;
+ }
+ }
+ else
+ { byte *bufp = bptr;
+ const byte *map = &ptab->lookup8[0];
+
+ while ( left-- )
+ { uint b = *psrc++;
+ *bufp = map[b >> 7]; bufp += spread;
+ *bufp = map[(b >> 6) & 1]; bufp += spread;
+ *bufp = map[(b >> 5) & 1]; bufp += spread;
+ *bufp = map[(b >> 4) & 1]; bufp += spread;
+ *bufp = map[(b >> 3) & 1]; bufp += spread;
+ *bufp = map[(b >> 2) & 1]; bufp += spread;
+ *bufp = map[(b >> 1) & 1]; bufp += spread;
+ *bufp = map[b & 1]; bufp += spread;
+ }
+ }
+ *pdata_x = data_x & 7;
+ return bptr;
+}
+
+const byte *
+sample_unpack_2(byte *bptr, int *pdata_x, const byte *data, int data_x,
+ uint dsize, const sample_lookup_t *ptab, int spread)
+{ const byte *psrc = data + (data_x >> 2);
+ int left = dsize - (data_x >> 2);
+
+ if ( spread == 1 )
+ { bits16 *bufp = (bits16 *)bptr;
+ const bits16 *map = &ptab->lookup2x2to16[0];
+
+ while ( left-- )
+ { uint b = *psrc++;
+ *bufp++ = map[b >> 4];
+ *bufp++ = map[b & 0xf];
+ }
+ }
+ else
+ { byte *bufp = bptr;
+ const byte *map = &ptab->lookup8[0];
+
+ while ( left-- )
+ { unsigned b = *psrc++;
+ *bufp = map[b >> 6]; bufp += spread;
+ *bufp = map[(b >> 4) & 3]; bufp += spread;
+ *bufp = map[(b >> 2) & 3]; bufp += spread;
+ *bufp = map[b & 3]; bufp += spread;
+ }
+ }
+ *pdata_x = data_x & 3;
+ return bptr;
+}
+
+const byte *
+sample_unpack_4(byte *bptr, int *pdata_x, const byte *data, int data_x,
+ uint dsize, const sample_lookup_t *ptab, int spread)
+{ byte *bufp = bptr;
+ const byte *psrc = data + (data_x >> 1);
+ int left = dsize - (data_x >> 1);
+ const byte *map = &ptab->lookup8[0];
+
+ while ( left-- )
+ { uint b = *psrc++;
+ *bufp = map[b >> 4]; bufp += spread;
+ *bufp = map[b & 0xf]; bufp += spread;
+ }
+ *pdata_x = data_x & 1;
+ return bptr;
+}
+
+const byte *
+sample_unpack_8(byte *bptr, int *pdata_x, const byte *data, int data_x,
+ uint dsize, const sample_lookup_t *ptab, int spread)
+{ byte *bufp = bptr;
+ const byte *psrc = data + data_x;
+
+ *pdata_x = 0;
+ if ( spread == 1 )
+ { if ( ptab->lookup8[0] != 0 ||
+ ptab->lookup8[255] != 255
+ )
+ { uint left = dsize - data_x;
+ const byte *map = &ptab->lookup8[0];
+
+ while ( left-- )
+ *bufp++ = map[*psrc++];
+ }
+ else
+ { /* No copying needed, and we'll use the data right away. */
+ return psrc;
+ }
+ }
+ else
+ { int left = dsize - data_x;
+ const byte *map = &ptab->lookup8[0];
+
+ for ( ; left--; psrc++, bufp += spread )
+ *bufp = map[*psrc];
+ }
+ return bptr;
+}
diff --git a/gs/src/gxsample.h b/gs/src/gxsample.h
new file mode 100644
index 000000000..6ca058028
--- /dev/null
+++ b/gs/src/gxsample.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxsample.h */
+/* Sample lookup and expansion */
+
+/*
+ * The following union implements the expansion of sample
+ * values from N bits to 8, and a possible linear transformation.
+ */
+typedef union sample_lookup_s {
+ bits32 lookup4x1to32[16]; /* 1 bit/sample, not spreading */
+ bits16 lookup2x2to16[16]; /* 2 bits/sample, not spreading */
+ byte lookup8[256]; /* 1 bit/sample, spreading [2] */
+ /* 2 bits/sample, spreading [4] */
+ /* 4 bits/sample [16] */
+ /* 8 bits/sample [256] */
+} sample_lookup_t;
+/*
+ * Define identity and inverted expansion lookups for 1-bit input values.
+ * These can be cast to a const sample_lookup_t.
+ */
+extern const bits32 lookup4x1to32_identity[16];
+#define sample_lookup_1_identity\
+ ((const sample_lookup_t *)lookup4x1to32_identity)
+extern const bits32 lookup4x1to32_inverted[16];
+#define sample_lookup_1_inverted\
+ ((const sample_lookup_t *)lookup4x1to32_inverted)
+
+/*
+ * Define procedures to unpack and shuffle image data samples. The Unix C
+ * compiler can't handle typedefs for procedure (as opposed to
+ * pointer-to-procedure) types, so we have to do it with macros instead.
+ *
+ * The original data start at sample data_x relative to data.
+ * bptr points to the buffer normally used to deliver the unpacked data.
+ * The unpacked data are at sample *pdata_x relative to the return value.
+ *
+ * Note that this procedure may return either a pointer to the buffer, or
+ * a pointer to the original data.
+ */
+#define sample_unpack_proc(proc)\
+ const byte *proc(P7(byte *bptr, int *pdata_x, const byte *data, int data_x,\
+ uint dsize, const sample_lookup_t *ptab, int spread))
+/*
+ * Declare the 1-for-1 unpacking procedure.
+ */
+sample_unpack_proc(sample_unpack_copy);
+/*
+ * Declare unpacking procedures for 1, 2, 4, and 8 bits per pixel,
+ * with optional spreading of the result.
+ */
+sample_unpack_proc(sample_unpack_1);
+sample_unpack_proc(sample_unpack_2);
+sample_unpack_proc(sample_unpack_4);
+sample_unpack_proc(sample_unpack_8);
diff --git a/gs/src/gxstate.h b/gs/src/gxstate.h
new file mode 100644
index 000000000..51787209e
--- /dev/null
+++ b/gs/src/gxstate.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxstate.h */
+/* Internal graphics state API */
+
+#ifndef gxstate_INCLUDED
+# define gxstate_INCLUDED
+
+/* Opaque type for a graphics state */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+/*
+ * The interfaces in this file are for internal use only, primarily by the
+ * interpreter. They are not guaranteed to remain stable from one release
+ * to another.
+ */
+
+/* Memory and save/restore management */
+gs_memory_t *gs_state_memory(P1(const gs_state *));
+gs_state *gs_state_saved(P1(const gs_state *));
+gs_state *gs_state_swap_saved(P2(gs_state *, gs_state *));
+gs_memory_t *gs_state_swap_memory(P2(gs_state *, gs_memory_t *));
+
+/*
+ * "Client data" interface for graphics states.
+ *
+ * As of release 4.36, the copy procedure is superseded by copy_for
+ * (although it will still be called if there is no copy_for procedure).
+ */
+typedef void *(*gs_state_alloc_proc_t)(P1(gs_memory_t *mem));
+typedef int (*gs_state_copy_proc_t)(P2(void *to, const void *from));
+typedef void (*gs_state_free_proc_t)(P2(void *old, gs_memory_t *mem));
+typedef enum {
+ copy_for_gsave, /* from = current, to = new(saved) */
+ copy_for_grestore, /* from = saved, to = current */
+ copy_for_gstate, /* from = current, to = new(copy) */
+ copy_for_setgstate, /* from = stored, to = current */
+ copy_for_copygstate, /* from & to are specified explicitly */
+ copy_for_currentgstate /* from = current, to = stored */
+} gs_state_copy_reason_t;
+/* Note that the 'from' argument of copy_for is not const. */
+/* This is deliberate -- some clients need this. */
+typedef int (*gs_state_copy_for_proc_t)(P3(void *to, void *from,
+ gs_state_copy_reason_t reason));
+typedef struct gs_state_client_procs_s {
+ gs_state_alloc_proc_t alloc;
+ gs_state_copy_proc_t copy;
+ gs_state_free_proc_t free;
+ gs_state_copy_for_proc_t copy_for;
+} gs_state_client_procs;
+void gs_state_set_client(P3(gs_state *, void *, const gs_state_client_procs *));
+/* gzstate.h redefines the following: */
+#ifndef gs_state_client_data
+void *gs_state_client_data(P1(const gs_state *));
+#endif
+
+#endif /* gxstate_INCLUDED */
diff --git a/gs/src/gxstroke.c b/gs/src/gxstroke.c
new file mode 100644
index 000000000..4a6646b6b
--- /dev/null
+++ b/gs/src/gxstroke.c
@@ -0,0 +1,1282 @@
+/* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxstroke.c */
+/* Path stroking procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsdcolor.h"
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gxmatrix.h"
+#include "gscoord.h"
+#include "gsdevice.h"
+#include "gxdevice.h"
+#include "gxhttile.h"
+#include "gxistate.h"
+#include "gzline.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxpaint.h"
+
+/*
+ * We don't really know whether it's a good idea to take fill adjustment
+ * into account for stroking. Disregarding it means that strokes
+ * come out thinner than fills; observing it produces heavy-looking
+ * strokes at low resolutions. But in any case, we must disregard it
+ * when stroking zero-width lines.
+ */
+#define USE_FILL_ADJUSTMENT
+
+#ifdef USE_FILL_ADJUSTMENT
+# define stroke_adjustment(thin, pis, xy)\
+ (thin ? fixed_0 : (pis)->fill_adjust.xy)
+#else
+# define stroke_adjustment(thin, pis, xy) fixed_0
+#endif
+
+/*
+ * For some reason, we commented out the optimization for portrait,
+ * landscape, and uniform (non-scaled) transformations. We have no record
+ * of why we did this, and we don't know what bugs re-enabling it may
+ * introduce.
+ */
+#define OPTIMIZE_ORIENTATION
+
+/*
+ * Compute the amount by which to expand a stroked bounding box to account
+ * for line width, caps and joins. Because of square caps and miter and
+ * triangular joins, the maximum expansion on each side (in user space) is
+ * K * line_width/2
+ * where K is determined as follows:
+ * If the path is only a single line segment, K = 1;
+ * if triangular joins, K = 2;
+ * if miter joins, K = miter_limit;
+ * otherwise, K = 1.
+ * If the amount is too large to fit in a gs_fixed_point, return
+ * gs_error_limitcheck.
+ *
+ * If the miter limit is very large, the foregoing computation will produce
+ * a result that is much too large; we would like to tighten this up at
+ * some point in the future.
+ */
+int
+gx_stroke_path_expansion(const gs_imager_state *pis, const gx_path *ppath,
+ gs_fixed_point *ppt)
+{ const subpath *psub = ppath->first_subpath;
+ const segment *pseg;
+ double expand =
+ (ppath->curve_count == 0 && ppath->subpath_count <= 1 &&
+ (psub == 0 || (pseg = psub->next) == 0 ||
+ (pseg = pseg->next) == 0 || pseg->type == s_line_close) ? 1.0 :
+ pis->line_params.join == gs_join_miter ?
+ pis->line_params.miter_limit :
+ pis->line_params.join == gs_join_triangle ? 2.0 : 1.0) *
+ pis->line_params.half_width;
+ /* Short-cut gs_bbox_transform. */
+ float cx1 = pis->ctm.xx + pis->ctm.yx;
+ float cy1 = pis->ctm.xy + pis->ctm.yy;
+ float cx2 = pis->ctm.xx - pis->ctm.yx;
+ float cy2 = pis->ctm.xy - pis->ctm.yy;
+
+ if ( cx1 < 0 ) cx1 = -cx1;
+ if ( cy1 < 0 ) cy1 = -cy1;
+ if ( cx2 < 0 ) cx2 = -cx2;
+ if ( cy2 < 0 ) cy2 = -cy2;
+ { float exx = expand * max(cx1, cx2);
+ float exy = expand * max(cy1, cy2);
+ int code = set_float2fixed_vars(ppt->x, exx);
+
+ if ( code < 0 )
+ return code;
+ return set_float2fixed_vars(ppt->y, exy);
+ }
+}
+
+/*
+ * Structure for a partial line (passed to the drawing routine).
+ * Two of these are required to do joins right.
+ * Each endpoint includes the two ends of the cap as well,
+ * and the deltas for square, round, and triangular cap computation.
+ *
+ * The two base values for computing the caps of a partial line are the
+ * width and the end cap delta. The width value is one-half the line
+ * width (suitably transformed) at 90 degrees counter-clockwise
+ * (in device space, but with "90 degrees" interpreted in *user*
+ * coordinates) at the end (as opposed to the origin) of the line.
+ * The cdelta value is one-half the transformed line width in the same
+ * direction as the line. From these, we compute two other values at each
+ * end of the line: co and ce, which are the ends of the cap.
+ * Note that the cdelta values at o are the negatives of the values at e,
+ * as are the offsets from p to co and ce.
+ *
+ * Initially, only o.p, e.p, e.cdelta, width, and thin are set.
+ * compute_caps fills in the rest.
+ */
+typedef gs_fixed_point _ss *p_ptr;
+typedef struct endpoint_s {
+ gs_fixed_point p; /* the end of the line */
+ gs_fixed_point co, ce; /* ends of the cap, p +/- width */
+ gs_fixed_point cdelta; /* +/- cap length */
+} endpoint;
+typedef endpoint _ss *ep_ptr;
+typedef const endpoint _ss *const_ep_ptr;
+typedef struct partial_line_s {
+ endpoint o; /* starting coordinate */
+ endpoint e; /* ending coordinate */
+ gs_fixed_point width; /* one-half line width, see above */
+ bool thin; /* true if minimum-width line */
+} partial_line;
+typedef partial_line _ss *pl_ptr;
+
+/* Assign a point. Some compilers would do this with very slow code */
+/* if we simply implemented it as an assignment. */
+#define assign_point(pp, p)\
+ ((pp)->x = (p).x, (pp)->y = (p).y)
+
+/* Other forward declarations */
+private bool width_is_thin(P1(pl_ptr));
+private void near adjust_stroke(P3(pl_ptr, const gs_imager_state *, bool));
+private int near line_join_points(P5(const gx_line_params *pgs_lp,
+ pl_ptr plp, pl_ptr nplp,
+ gs_fixed_point _ss *join_points,
+ const gs_matrix *pmat));
+private void near compute_caps(P1(pl_ptr));
+private int near add_points(P4(gx_path *, const gs_fixed_point _ss *,
+ int, bool));
+private int near add_round_cap(P2(gx_path *, const_ep_ptr));
+private int near cap_points(P3(gs_line_cap, const_ep_ptr,
+ gs_fixed_point _ss * /*[3]*/));
+
+/* Define the default implementation of the device stroke_path procedure. */
+int
+gx_default_stroke_path(gx_device *dev, const gs_imager_state *pis,
+ gx_path *ppath, const gx_stroke_params *params,
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
+{ return gx_stroke_path_only(ppath, (gx_path *)0, dev, pis, params,
+ pdcolor, pcpath);
+}
+
+/* Fill a partial stroked path. Free variables: */
+/* to_path, stroke_path_body, fill_params, always_thin, pis, dev, pdevc, */
+/* code, ppath, exit(label). */
+#define fill_stroke_path(thin)\
+if(to_path==&stroke_path_body && !gx_path_is_void_inline(&stroke_path_body))\
+{ fill_params.adjust.x = stroke_adjustment(thin, pis, x);\
+ fill_params.adjust.y = stroke_adjustment(thin, pis, y);\
+ code = gx_fill_path_only(to_path, dev, pis, &fill_params, pdevc, NULL);\
+ gx_path_release(to_path);\
+ if ( code < 0 ) goto exit;\
+ gx_path_init(to_path, ppath->memory);\
+}
+
+/*
+ * Define the internal procedures that stroke a partial_line
+ * (the first pl_ptr argument). If both partial_lines are non-null,
+ * the procedure creates an appropriate join; otherwise, the procedure
+ * creates an end cap. If the first int is 0, the procedure also starts
+ * with an appropriate cap.
+ */
+#define stroke_line_proc(proc)\
+ int near proc(P10(gx_path *, int, pl_ptr, pl_ptr, const gx_device_color *,\
+ gx_device *, const gs_imager_state *,\
+ const gx_stroke_params *, const gs_fixed_rect *, int))
+typedef stroke_line_proc((*stroke_line_proc_t));
+
+private stroke_line_proc(stroke_add);
+private stroke_line_proc(stroke_fill);
+
+/* Define the orientations we handle specially. */
+typedef enum {
+ orient_other = 0,
+ orient_portrait, /* [xx 0 0 yy tx ty] */
+ orient_landscape /* [0 xy yx 0 tx ty] */
+} orientation;
+
+/*
+ * Stroke a path. If to_path != 0, append the stroke outline to it;
+ * if to_path == 0, draw the strokes on dev.
+ *
+ * Note that gx_stroke_path_only with to_path != NULL may clip the path to
+ * the clipping path, as for to_path == NULL. This is almost never
+ * what is wanted.
+ */
+int
+gx_stroke_path_only(gx_path *ppath, gx_path *to_path, gx_device *pdev,
+ const gs_imager_state *pis, const gx_stroke_params *params,
+ const gx_device_color *pdevc, const gx_clip_path *pcpath)
+{ stroke_line_proc_t line_proc =
+ (to_path == 0 ? stroke_fill : stroke_add);
+ gs_fixed_rect ibox, cbox;
+ gx_device_clip cdev;
+ gx_device *dev = pdev;
+ int code = 0;
+ gx_fill_params fill_params;
+ const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ int dash_count = pgs_lp->dash.pattern_size;
+ gx_path fpath, dpath;
+ gx_path stroke_path_body;
+ const gx_path *spath;
+ float xx = pis->ctm.xx, xy = pis->ctm.xy;
+ float yx = pis->ctm.yx, yy = pis->ctm.yy;
+ /*
+ * We are dealing with a reflected coordinate system
+ * if transform(1,0) is counter-clockwise from transform(0,1).
+ * See the note in stroke_add for the algorithm.
+ */
+ int uniform;
+ bool reflected;
+ orientation orient =
+ (
+#ifdef OPTIMIZE_ORIENTATION
+ is_fzero2(xy, yx) ?
+ (uniform = (xx == yy ? 1 : xx == -yy ? -1 : 0),
+ reflected = (uniform ? uniform < 0 : (xx < 0) != (yy < 0)),
+ orient_portrait) :
+ is_fzero2(xx, yy) ?
+ (uniform = (xy == yx ? -1 : xy == -yx ? 1 : 0),
+ reflected = (uniform ? uniform < 0 : (xy < 0) == (yx < 0)),
+ orient_landscape) :
+ /* We should optimize uniform rotated coordinate systems */
+ /* here as well, but we don't. */
+#endif
+ (uniform = 0,
+ reflected = xy * yx > xx * yy,
+ orient_other));
+ segment_notes not_first =
+ (!is_fzero(pis->line_params.dot_length) ? sn_not_first : sn_none);
+ float line_width = pgs_lp->half_width; /* (*half* the line width) */
+ bool always_thin;
+ double line_width_and_scale, device_line_width_scale;
+ double device_dot_length = pgs_lp->dot_length * fixed_1;
+ const subpath *psub;
+
+#ifdef DEBUG
+if ( gs_debug_c('o') )
+ { int count = pgs_lp->dash.pattern_size;
+ int i;
+ dprintf3("[o]half_width=%f, cap=%d, join=%d,\n",
+ pgs_lp->half_width, (int)pgs_lp->cap, (int)pgs_lp->join);
+ dprintf2(" miter_limit=%f, miter_check=%f,\n",
+ pgs_lp->miter_limit, pgs_lp->miter_check);
+ dprintf1(" dash pattern=%d", count);
+ for ( i = 0; i < count; i++ )
+ dprintf1(",%f", pgs_lp->dash.pattern[i]);
+ dprintf4(",\n offset=%f, init(ink_on=%d, index=%d, dist_left=%f)\n",
+ pgs_lp->dash.offset, pgs_lp->dash.init_ink_on,
+ pgs_lp->dash.init_index, pgs_lp->dash.init_dist_left);
+ }
+#endif
+
+ gx_path_bbox(ppath, &ibox);
+ /* Expand the path bounding box by the scaled line width. */
+ { gs_fixed_point expansion;
+
+ if ( gx_stroke_path_expansion(pis, ppath, &expansion) < 0 )
+ { /* The expansion is so large it caused a limitcheck. */
+ ibox.p.x = ibox.p.y = min_fixed;
+ ibox.q.x = ibox.q.y = max_fixed;
+ }
+ else
+ { expansion.x += pis->fill_adjust.x;
+ expansion.y += pis->fill_adjust.y;
+ /*
+ * It's theoretically possible for the following computations to
+ * overflow, so we need to check for this.
+ */
+ ibox.p.x = (ibox.p.x < min_fixed + expansion.x ? min_fixed :
+ ibox.p.x - expansion.x);
+ ibox.p.y = (ibox.p.y < min_fixed + expansion.y ? min_fixed :
+ ibox.p.y - expansion.y);
+ ibox.q.x = (ibox.q.x > max_fixed - expansion.x ? max_fixed :
+ ibox.q.x + expansion.x);
+ ibox.q.y = (ibox.q.y > max_fixed - expansion.y ? max_fixed :
+ ibox.q.y + expansion.y);
+ }
+ }
+ /* Check the expanded bounding box against the clipping regions. */
+ if ( pcpath )
+ gx_cpath_inner_box(pcpath, &cbox);
+ else if ( pdevc )
+ (*dev_proc(dev, get_clipping_box))(dev, &cbox);
+ else
+ { /* This is strokepath, not stroke. Don't clip. */
+ cbox = ibox;
+ }
+ if ( !rect_within(ibox, cbox) )
+ { /* Intersect the path box and the clip bounding box. */
+ /* If the intersection is empty, this call is a no-op. */
+ gs_fixed_rect bbox;
+
+ if ( pcpath )
+ { gx_cpath_outer_box(pcpath, &bbox);
+ if_debug4('f', " outer_box=(%g,%g),(%g,%g)\n",
+ fixed2float(bbox.p.x), fixed2float(bbox.p.y),
+ fixed2float(bbox.q.x), fixed2float(bbox.q.y));
+ rect_intersect(ibox, bbox);
+ }
+ else
+ rect_intersect(ibox, cbox);
+ if ( ibox.p.x >= ibox.q.x || ibox.p.y >= ibox.q.y )
+ { /* Intersection of boxes is empty! */
+ return 0;
+ }
+ /*
+ * The path is neither entirely inside the inner clip box
+ * nor entirely outside the outer clip box.
+ * If we had to flatten the path, this is where we would
+ * recompute its bbox and make the tests again,
+ * but we don't bother right now.
+ *
+ * If there is a clipping path, set up a clipping device.
+ */
+ if ( pcpath )
+ { gx_make_clip_device(&cdev, &cdev, &pcpath->list);
+ cdev.target = dev;
+ cdev.max_fill_band = dev->max_fill_band;
+ dev = (gx_device *)&cdev;
+ (*dev_proc(dev, open_device))(dev);
+ }
+ }
+ fill_params.rule = gx_rule_winding_number;
+ fill_params.flatness = pis->flatness;
+#ifdef USE_FILL_ADJUSTMENT
+ fill_params.fill_zero_width =
+ (pis->fill_adjust.x | pis->fill_adjust.y) != 0;
+#else
+ fill_params.fill_zero_width = false;
+#endif
+ if ( line_width < 0 )
+ line_width = -line_width;
+ line_width_and_scale = line_width * (double)int2fixed(1);
+ if ( is_fzero(line_width) )
+ always_thin = true;
+ else
+ { float xa, ya;
+ switch ( orient )
+ {
+ case orient_portrait:
+ xa = xx, ya = yy;
+ goto sat;
+ case orient_landscape:
+ xa = xy, ya = yx;
+sat: if ( xa < 0 ) xa = -xa;
+ if ( ya < 0 ) ya = -ya;
+ always_thin = (max(xa, ya) * line_width < 0.5);
+ if ( !always_thin && uniform )
+ { /* Precompute a value we'll need later. */
+ device_line_width_scale = line_width_and_scale * xa;
+ }
+ break;
+ default:
+ { /* The check is more complicated, but it's worth it. */
+ double xsq = xx * xx + xy * xy;
+ double ysq = yx * yx + yy * yy;
+ double cross = xx * yx + xy * yy;
+
+ if ( cross < 0 )
+ cross = 0;
+ always_thin =
+ ((max(xsq, ysq) + cross) * line_width * line_width
+ < 0.25);
+ }
+ }
+ }
+ if_debug5('o', "[o]ctm=(%g,%g,%g,%g) thin=%d\n",
+ xx, xy, yx, yy, always_thin);
+ if ( device_dot_length != 0 )
+ { /*
+ * Compute the dot length in device space. We can't do this
+ * quite right for non-uniform coordinate systems; too bad.
+ */
+ gs_matrix mat;
+ const gs_matrix *pmat;
+
+ if ( pgs_lp->dot_length_absolute )
+ { gs_deviceinitialmatrix(pdev, &mat);
+ pmat = &mat;
+ }
+ else
+ pmat = (const gs_matrix *)&pis->ctm;
+ device_dot_length *= fabs(pmat->xy) + fabs(pmat->yy);
+ }
+ /* Start by flattening the path. We should do this on-the-fly.... */
+ if ( !ppath->curve_count ) /* don't need to flatten */
+ { if ( !ppath->first_subpath )
+ return 0;
+ spath = ppath;
+ }
+ else
+ { if ( (code = gx_path_flatten_accurate(ppath, &fpath,
+ params->flatness, pis->accurate_curves)) < 0
+ )
+ return code;
+ spath = &fpath;
+ }
+ if ( dash_count )
+ { code = gx_path_expand_dashes(spath, &dpath, pis);
+ if ( code < 0 )
+ goto exf;
+ spath = &dpath;
+ }
+ if ( to_path == 0 )
+ { /* We might try to defer this if it's expensive.... */
+ to_path = &stroke_path_body;
+ gx_path_init(to_path, ppath->memory);
+ }
+ for ( psub = spath->first_subpath; psub != 0; )
+ { int index = 0;
+ const segment *pseg = (const segment *)psub;
+ fixed x = pseg->pt.x;
+ fixed y = pseg->pt.y;
+ bool is_closed = ((const subpath *)pseg)->is_closed;
+ partial_line pl, pl_prev, pl_first;
+
+ while ( (pseg = pseg->next) != 0 &&
+ pseg->type != s_start
+ )
+ { /* Compute the width parameters in device space. */
+ /* We work with unscaled values, for speed. */
+ fixed sx = pseg->pt.x, udx = sx - x;
+ fixed sy = pseg->pt.y, udy = sy - y;
+
+ pl.o.p.x = x, pl.o.p.y = y;
+d: pl.e.p.x = sx, pl.e.p.y = sy;
+ if ( !(udx | udy) ) /* degenerate */
+ { /*
+ * If this is the first segment of the subpath,
+ * check the entire subpath for degeneracy.
+ * Otherwise, ignore the degenerate segment.
+ */
+ if ( index != 0 )
+ continue;
+ /* Check for a degenerate subpath. */
+ while ( (pseg = pseg->next) != 0 &&
+ pseg->type != s_start
+ )
+ { sx = pseg->pt.x, udx = sx - x;
+ sy = pseg->pt.y, udy = sy - y;
+ if ( udx | udy )
+ goto d;
+ }
+ /*
+ * The entire subpath is degenerate, but it includes
+ * more than one point. If we are using round caps or
+ * the dot length is non-zero, draw the caps, otherwise
+ * do nothing.
+ */
+ if ( !(pgs_lp->cap == gs_cap_round ||
+ pgs_lp->dot_length != 0)
+ )
+ break;
+ /*
+ * Orient the dot according to the previous segment if
+ * any, or else the next segment if any, or else a
+ * vertical line.
+ */
+ { const segment *end = psub->prev;
+ if ( end != 0 && (end->pt.x != x || end->pt.y != y) )
+ sx = end->pt.x, sy = end->pt.y;
+ else if ( pseg != 0 &&
+ (pseg->pt.x != x || pseg->pt.y != y)
+ )
+ sx = pseg->pt.x, sy = pseg->pt.y;
+ }
+ /*
+ * Compute the properly oriented dot length, and then
+ * draw the dot like a very short line.
+ */
+ udx = sx - x, udy = sy - y;
+ if ( (udx | udy) == 0 )
+ udy = fixed_1;
+ { double scale = device_dot_length /
+ hypot((double)udx, (double)udy);
+
+ /*
+ * If we're using butt caps, make sure the "line" is
+ * long enough to show up.
+ */
+ if ( pgs_lp->cap == gs_cap_butt )
+ { fixed dmax = max(any_abs(udx), any_abs(udy));
+ if ( dmax * scale < fixed_1 )
+ scale = (float)fixed_1 / dmax;
+ }
+ udx = (fixed)(udx * scale);
+ udy = (fixed)(udy * scale);
+ if ( (udx | udy) == 0 )
+ udy = fixed_epsilon;
+ sx = x + udx;
+ sy = y + udy;
+ }
+ /*
+ * Back up 1 segment to keep the bookkeeping straight.
+ */
+ pseg = (pseg != 0 ? pseg->prev : psub->last);
+ goto d;
+ }
+ if ( always_thin )
+ { pl.e.cdelta.x = pl.e.cdelta.y = 0;
+ pl.width.x = pl.width.y = 0;
+ pl.thin = true;
+ }
+ else
+ { if ( uniform != 0 )
+ { /* We can save a lot of work in this case. */
+ /* We know orient != orient_other. */
+ float dpx = udx, dpy = udy;
+ float wl = device_line_width_scale /
+ hypot(dpx, dpy);
+ pl.e.cdelta.x = (fixed)(dpx * wl);
+ pl.e.cdelta.y = (fixed)(dpy * wl);
+ /* The width is the cap delta rotated by */
+ /* 90 degrees. */
+ pl.width.x = -pl.e.cdelta.y,
+ pl.width.y = pl.e.cdelta.x;
+ pl.thin = false; /* if not always_thin, */
+ /* then never thin. */
+ }
+ else
+ { gs_point dpt; /* unscaled */
+ float wl;
+ gs_imager_idtransform(pis,
+ (float)udx, (float)udy, &dpt);
+ wl = line_width_and_scale /
+ hypot(dpt.x, dpt.y);
+ /* Construct the width vector in */
+ /* user space, still unscaled. */
+ dpt.x *= wl;
+ dpt.y *= wl;
+ /*
+ * We now compute both perpendicular
+ * and (optionally) parallel half-widths,
+ * as deltas in device space. We use
+ * a fixed-point, unscaled version of
+ * gs_dtransform. The second computation
+ * folds in a 90-degree rotation (in user
+ * space, before transforming) in the
+ * direction that corresponds to counter-
+ * clockwise in device space.
+ */
+ pl.e.cdelta.x = (fixed)(dpt.x * xx);
+ pl.e.cdelta.y = (fixed)(dpt.y * yy);
+ if ( orient != orient_portrait )
+ pl.e.cdelta.x += (fixed)(dpt.y * yx),
+ pl.e.cdelta.y += (fixed)(dpt.x * xy);
+ if ( !reflected )
+ dpt.x = -dpt.x, dpt.y = -dpt.y;
+ pl.width.x = (fixed)(dpt.y * xx),
+ pl.width.y = -(fixed)(dpt.x * yy);
+ if ( orient != orient_portrait )
+ pl.width.x -= (fixed)(dpt.x * yx),
+ pl.width.y += (fixed)(dpt.y * xy);
+ pl.thin = width_is_thin(&pl);
+ }
+ if ( !pl.thin )
+ { adjust_stroke(&pl, pis, false);
+ compute_caps(&pl);
+ }
+ }
+ if ( index++ )
+ { int first;
+ pl_ptr lptr;
+
+ if ( pgs_lp->join == gs_join_none &&
+ !(pseg->notes & not_first)
+ )
+ { /* Fake the end of a subpath so we get */
+ /* caps instead of joins. */
+ first = 0;
+ lptr = 0;
+ index = 1;
+ }
+ else
+ { first = (is_closed ? 1 : index - 2);
+ lptr = &pl;
+ }
+ code = (*line_proc)(to_path, first, &pl_prev, lptr,
+ pdevc, dev, pis, params, &cbox,
+ uniform);
+ if ( code < 0 )
+ goto exit;
+ fill_stroke_path(always_thin);
+ }
+ else
+ pl_first = pl;
+ pl_prev = pl;
+ x = sx, y = sy;
+ }
+ if ( index )
+ { /* If closed, join back to start, else cap. */
+ /* For some reason, the Borland compiler requires the cast */
+ /* in the following statement. */
+ pl_ptr lptr =
+ (!is_closed ||
+ (pgs_lp->join == gs_join_none &&
+ !( (pseg == 0 ? (const segment *)spath->first_subpath :
+ pseg)->notes & not_first )) ?
+ (pl_ptr)0 : (pl_ptr)&pl_first);
+
+ code = (*line_proc)(to_path, index - 1, &pl_prev, lptr,
+ pdevc, dev, pis, params, &cbox, uniform);
+ if ( code < 0 )
+ goto exit;
+ fill_stroke_path(always_thin);
+ }
+ psub = (const subpath *)pseg;
+ }
+exit: if ( to_path == &stroke_path_body )
+ gx_path_release(to_path); /* (only needed if error) */
+ if ( dash_count )
+ gx_path_release(&dpath);
+exf: if ( ppath->curve_count )
+ gx_path_release(&fpath);
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/*
+ * Test whether a line is thin, i.e., whether the half-width, measured
+ * perpendicular to the line in device space, is less than 0.5 pixel.
+ * Unfortunately, the width values we computed are perpendicular to the
+ * line in *user* space, so we may have to do some extra work.
+ */
+private bool
+width_is_thin(pl_ptr plp)
+{ fixed dx, dy, wx = plp->width.x, wy = plp->width.y;
+
+ /* If the line is horizontal or vertical, things are easy. */
+ if ( (dy = plp->e.p.y - plp->o.p.y) == 0 )
+ return any_abs(wy) < fixed_half;
+ if ( (dx = plp->e.p.x - plp->o.p.x) == 0 )
+ return any_abs(wx) < fixed_half;
+
+ /*
+ * If both horizontal and vertical widths are less than
+ * 0.5, the line is thin.
+ */
+ if ( any_abs(wx) < fixed_half && any_abs(wy) < fixed_half )
+ return true;
+
+ /*
+ * We have to do this the hard way, by actually computing the
+ * perpendicular distance. The distance from the point (U,V)
+ * from a line from (0,0) to (C,D) is
+ * abs(C*V - D*U) / sqrt(C^2 + D^2)
+ * In this case, (U,V) is plp->width, and (C,D) is (dx,dy).
+ */
+ { double C = dx, D = dy;
+ double num = C * wy - D * wx;
+ double denom = hypot(C, D);
+
+ /* both num and denom are scaled by fixed_scale^2, */
+ /* so we don't need to do any de-scaling for the test. */
+ return fabs(num) < denom * 0.5;
+ }
+}
+
+/* Adjust the endpoints and width of a stroke segment */
+/* to achieve more uniform rendering. */
+/* Only o.p, e.p, e.cdelta, and width have been set. */
+private void near
+adjust_stroke(pl_ptr plp, const gs_imager_state *pis, bool thin)
+{ fixed _ss *pw;
+ fixed _ss *pov;
+ fixed _ss *pev;
+ fixed w, w2;
+ fixed adj2;
+ if ( !pis->stroke_adjust && plp->width.x != 0 && plp->width.y != 0 )
+ return; /* don't adjust */
+ if ( any_abs(plp->width.x) < any_abs(plp->width.y) )
+ { /* More horizontal stroke */
+ pw = &plp->width.y, pov = &plp->o.p.y, pev = &plp->e.p.y;
+ adj2 = stroke_adjustment(thin, pis, y) << 1;
+ }
+ else
+ { /* More vertical stroke */
+ pw = &plp->width.x, pov = &plp->o.p.x, pev = &plp->e.p.x;
+ adj2 = stroke_adjustment(thin, pis, x) << 1;
+ }
+ /* Round the larger component of the width up or down, */
+ /* whichever way produces a result closer to the correct width. */
+ /* Note that just rounding the larger component */
+ /* may not produce the correct result. */
+ w = *pw;
+ w2 = fixed_rounded(w << 1); /* full line width */
+ if ( w2 == 0 && *pw != 0 )
+ { /* Make sure thin lines don't disappear. */
+ w2 = (*pw < 0 ? -fixed_1 + adj2 : fixed_1 - adj2);
+ *pw = arith_rshift_1(w2);
+ }
+ /* Only adjust the endpoints if the line is horizontal or vertical. */
+ if ( *pov == *pev )
+ { /* We're going to round the endpoint coordinates, so */
+ /* take the fill adjustment into account now. */
+ if ( w >= 0 ) w2 += adj2;
+ else w2 = adj2 - w2;
+ if ( w2 & fixed_1 ) /* odd width, move to half-pixel */
+ { *pov = *pev = fixed_floor(*pov) + fixed_half;
+ }
+ else /* even width, move to pixel */
+ { *pov = *pev = fixed_rounded(*pov);
+ }
+ }
+}
+
+/* Compute the intersection of two lines. This is a messy algorithm */
+/* that somehow ought to be useful in more places than just here.... */
+/* If the lines are (nearly) parallel, return -1 without setting *pi; */
+/* otherwise, return 0 if the intersection is beyond *pp1 and *pp2 in */
+/* the direction determined by *pd1 and *pd2, and 1 otherwise. */
+private int
+line_intersect(
+ p_ptr pp1, /* point on 1st line */
+ p_ptr pd1, /* slope of 1st line (dx,dy) */
+ p_ptr pp2, /* point on 2nd line */
+ p_ptr pd2, /* slope of 2nd line */
+ p_ptr pi) /* return intersection here */
+{ /* We don't have to do any scaling, the factors all work out right. */
+ float u1 = pd1->x, v1 = pd1->y;
+ float u2 = pd2->x, v2 = pd2->y;
+ double denom = u1 * v2 - u2 * v1;
+ float xdiff = pp2->x - pp1->x;
+ float ydiff = pp2->y - pp1->y;
+ double f1;
+ double max_result = any_abs(denom) * (double)max_fixed;
+#ifdef DEBUG
+if ( gs_debug_c('O') )
+ { dprintf4("[o]Intersect %f,%f(%f/%f)",
+ fixed2float(pp1->x), fixed2float(pp1->y),
+ fixed2float(pd1->x), fixed2float(pd1->y));
+ dprintf4(" & %f,%f(%f/%f),\n",
+ fixed2float(pp2->x), fixed2float(pp2->y),
+ fixed2float(pd2->x), fixed2float(pd2->y));
+ dprintf3("\txdiff=%f ydiff=%f denom=%f ->\n",
+ xdiff, ydiff, denom);
+ }
+#endif
+ /* Check for degenerate result. */
+ if ( any_abs(xdiff) >= max_result || any_abs(ydiff) >= max_result )
+ { /* The lines are nearly parallel, */
+ /* or one of them has zero length. Punt. */
+ if_debug0('O', "\tdegenerate!\n");
+ return -1;
+ }
+ f1 = (v2 * xdiff - u2 * ydiff) / denom;
+ pi->x = pp1->x + (fixed)(f1 * u1);
+ pi->y = pp1->y + (fixed)(f1 * v1);
+ if_debug2('O', "\t%f,%f\n",
+ fixed2float(pi->x), fixed2float(pi->y));
+ return (f1 >= 0 && (v1 * xdiff >= u1 * ydiff ? denom >= 0 : denom < 0) ? 0 : 1);
+}
+
+#define lix plp->o.p.x
+#define liy plp->o.p.y
+#define litox plp->e.p.x
+#define litoy plp->e.p.y
+
+/* Set up the width and delta parameters for a thin line. */
+/* We only approximate the width and height. */
+private void near
+set_thin_widths(register pl_ptr plp)
+{ fixed dx = litox - lix, dy = litoy - liy;
+
+#define trsign(pos, c) ((pos) ? (c) : -(c))
+ if ( any_abs(dx) > any_abs(dy) )
+ { plp->width.x = plp->e.cdelta.y = 0;
+ plp->width.y = plp->e.cdelta.x = trsign(dx >= 0, fixed_half);
+ }
+ else
+ { plp->width.y = plp->e.cdelta.x = 0;
+ plp->width.x = -(plp->e.cdelta.y = trsign(dy >= 0, fixed_half));
+ }
+#undef trsign
+}
+
+/* Draw a line on the device. */
+/* Treat no join the same as a bevel join. */
+private int near
+stroke_fill(gx_path *ppath, int first, register pl_ptr plp, pl_ptr nplp,
+ const gx_device_color *pdevc, gx_device *dev, const gs_imager_state *pis,
+ const gx_stroke_params *params, const gs_fixed_rect *pbbox,
+ int uniform)
+{ if ( plp->thin )
+ { /* Minimum-width line, don't have to be careful. */
+ /* We do have to check for the entire line being */
+ /* within the clipping rectangle, allowing for some */
+ /* slop at the ends. */
+ fixed x0 = lix, y0 = liy;
+ fixed x1 = litox, y1 = litoy;
+ fixed t;
+
+#define slop int2fixed(2)
+ if ( x0 > x1 )
+ t = x0, x0 = x1 - slop, x1 = t + slop;
+ else
+ x0 -= slop, x1 += slop;
+ if ( y0 > y1 )
+ t = y0, y0 = y1 - slop, y1 = t + slop;
+ else
+ y0 -= slop, y1 += slop;
+#undef slop
+
+ if ( pbbox->p.x <= x0 && x1 <= pbbox->q.x &&
+ pbbox->p.y <= y0 && y1 <= pbbox->q.y
+ )
+ return (*dev_proc(dev, draw_thin_line))(dev,
+ lix, liy, litox, litoy,
+ pdevc, pis->log_op);
+ /* We didn't set up the endpoint parameters before, */
+ /* because the line was thin. stroke_add will do this. */
+ }
+ /* Check for being able to fill directly. */
+ { const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ gs_line_cap cap = pgs_lp->cap;
+ gs_line_join join = pgs_lp->join;
+
+ if ( !plp->thin && (nplp == 0 || !nplp->thin)
+ && ((first != 0 && nplp != 0) || cap == gs_cap_butt
+ || cap == gs_cap_square)
+ && (join == gs_join_bevel || join == gs_join_miter ||
+ join == gs_join_none)
+ && (pis->fill_adjust.x | pis->fill_adjust.y) == 0
+ && lop_is_idempotent(pis->log_op)
+ )
+ { gs_fixed_point points[6];
+ int npoints, code;
+
+ npoints = cap_points((first == 0 ? cap : gs_cap_butt),
+ &plp->o, points);
+ if ( nplp == 0 )
+ code = cap_points(cap, &plp->e, points + npoints);
+ else
+ code = line_join_points(pgs_lp, plp, nplp, points + npoints,
+ (uniform ? (gs_matrix *)0 :
+ &ctm_only(pis)));
+ if ( code < 0 )
+ return code;
+ if ( nplp != 0 )
+ { if ( join == gs_join_miter )
+ { /* Make sure we have a bevel and not a miter. */
+ if ( !(points[2].x == plp->e.co.x &&
+ points[2].y == plp->e.co.y &&
+ points[5].x == plp->e.ce.x &&
+ points[5].y == plp->e.ce.y)
+ )
+ goto fill;
+ }
+ { const gs_fixed_point *bevel = points + 2;
+
+ /* Identify which 3 points define the bevel triangle. */
+ if ( points[3].x == nplp->o.p.x &&
+ points[3].y == nplp->o.p.y
+ )
+ ++bevel;
+ /* Fill the bevel. */
+ code = (*dev_proc(dev, fill_triangle))(dev,
+ bevel->x, bevel->y,
+ bevel[1].x - bevel->x,
+ bevel[1].y - bevel->y,
+ bevel[2].x - bevel->x,
+ bevel[2].y - bevel->y,
+ pdevc, pis->log_op);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ /* Fill the body of the stroke. */
+ return (*dev_proc(dev, fill_parallelogram))(dev,
+ points[1].x, points[1].y,
+ points[0].x - points[1].x,
+ points[0].y - points[1].y,
+ points[2].x - points[1].x,
+ points[2].y - points[1].y,
+ pdevc, pis->log_op);
+fill: code = add_points(ppath, points, npoints + code, true);
+ if ( code < 0 )
+ return code;
+ return gx_path_close_subpath(ppath);
+ }
+ }
+ /* General case: construct a path for the fill algorithm. */
+ return stroke_add(ppath, first, plp, nplp, pdevc, dev, pis, params,
+ pbbox, uniform);
+}
+
+#undef lix
+#undef liy
+#undef litox
+#undef litoy
+
+/* Add a segment to the path. This handles all the complex cases. */
+private int near
+stroke_add(gx_path *ppath, int first, register pl_ptr plp, pl_ptr nplp,
+ const gx_device_color *pdevc, gx_device *dev, const gs_imager_state *pis,
+ const gx_stroke_params *params, const gs_fixed_rect *ignore_pbbox,
+ int uniform)
+{ const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ gs_fixed_point points[8];
+ int npoints;
+ int code;
+ bool moveto_first = true;
+
+ if ( plp->thin )
+ { /* We didn't set up the endpoint parameters before, */
+ /* because the line was thin. Do it now. */
+ set_thin_widths(plp);
+ adjust_stroke(plp, pis, true);
+ compute_caps(plp);
+ }
+ /* Create an initial cap if desired. */
+ if ( first == 0 && pgs_lp->cap == gs_cap_round )
+ { if ( (code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
+ (code = add_round_cap(ppath, &plp->o)) < 0
+ )
+ return code;
+ npoints = 0;
+ moveto_first = false;
+ }
+ else
+ { if ( (npoints = cap_points((first == 0 ? pgs_lp->cap : gs_cap_butt), &plp->o, points)) < 0 )
+ return npoints;
+ }
+ if ( nplp == 0 )
+ { /* Add a final cap. */
+ if ( pgs_lp->cap == gs_cap_round )
+ { assign_point(&points[npoints], plp->e.co);
+ ++npoints;
+ if ( (code = add_points(ppath, points, npoints, moveto_first)) < 0 )
+ return code;
+ code = add_round_cap(ppath, &plp->e);
+ goto done;
+ }
+ code = cap_points(pgs_lp->cap, &plp->e, points + npoints);
+ }
+ else if ( pgs_lp->join == gs_join_round )
+ { assign_point(&points[npoints], plp->e.co);
+ ++npoints;
+ if ( (code = add_points(ppath, points, npoints, moveto_first)) < 0 )
+ return code;
+ code = add_round_cap(ppath, &plp->e);
+ goto done;
+ }
+ else if ( nplp->thin ) /* no join */
+ code = cap_points(gs_cap_butt, &plp->e, points + npoints);
+ else /* non-round join */
+ code = line_join_points(pgs_lp, plp, nplp, points + npoints,
+ (uniform ? (gs_matrix *)0 : &ctm_only(pis)));
+ if ( code < 0 )
+ return code;
+ code = add_points(ppath, points, npoints + code, moveto_first);
+done: if ( code < 0 )
+ return code;
+ return gx_path_close_subpath(ppath);
+}
+
+/* Add lines with a possible initial moveto. */
+private int near
+add_points(gx_path *ppath, const gs_fixed_point _ss *points, int npoints,
+ bool moveto_first)
+{ if ( moveto_first )
+ { int code = gx_path_add_point(ppath, points[0].x, points[0].y);
+ if ( code < 0 )
+ return code;
+ return gx_path_add_lines(ppath, points + 1, npoints - 1);
+ }
+ else
+ return gx_path_add_lines(ppath, points, npoints);
+}
+
+/* ---------------- Join computation ---------------- */
+
+/* Compute the points for a bevel, miter, or triangle join. */
+/* Treat no join the same as a bevel join. */
+/* If pmat != 0, we must inverse-transform the distances for */
+/* the miter check. */
+private int near
+line_join_points(const gx_line_params *pgs_lp, pl_ptr plp, pl_ptr nplp,
+ gs_fixed_point _ss *join_points, const gs_matrix *pmat)
+{ gs_line_join join = pgs_lp->join;
+#define jp1 join_points[0]
+#define np1 join_points[1]
+#define np2 join_points[2]
+#define jp2 join_points[3]
+#define jpx join_points[4]
+ /*
+ * Set np to whichever of nplp->o.co or .ce is outside
+ * the current line. We observe that the point (x2,y2)
+ * is counter-clockwise from (x1,y1), relative to the origin,
+ * iff
+ * (arctan(y2/x2) - arctan(y1/x1)) mod 2*pi < pi,
+ * taking the signs of xi and yi into account to determine
+ * the quadrants of the results. It turns out that
+ * even though arctan is monotonic only in the 4th/1st
+ * quadrants and the 2nd/3rd quadrants, case analysis on
+ * the signs of xi and yi demonstrates that this test
+ * is equivalent to the much less expensive test
+ * x1 * y2 > x2 * y1
+ * in all cases.
+ *
+ * In the present instance, x1,y1 are plp->width,
+ * x2,y2 are nplp->width, and the origin is
+ * their common point (plp->e.p, nplp->o.p).
+ * ccw will be true iff nplp.o.co (nplp.o.p + width) is
+ * counter-clockwise from plp.e.ce (plp.e.p + width),
+ * in which case we want tan(a-b) rather than tan(b-a).
+ *
+ * We make the test using double arithmetic only because
+ * the !@#&^*% C language doesn't give us access to
+ * the double-width-result multiplication operation
+ * that almost all CPUs provide!
+ */
+ bool ccw =
+ (double)(plp->width.x) * /* x1 */
+ (nplp->width.y) > /* y2 */
+ (double)(nplp->width.x) * /* x2 */
+ (plp->width.y);
+ p_ptr outp, np;
+
+ /* Initialize for a bevel join. */
+ assign_point(&jp1, plp->e.co);
+ assign_point(&jp2, plp->e.ce);
+
+ /* Because of stroke adjustment, it is possible that */
+ /* plp->e.p != nplp->o.p. For that reason, we must use */
+ /* nplp->o.p as np1 or np2. */
+ if ( !ccw )
+ { outp = &jp2;
+ assign_point(&np2, nplp->o.co);
+ assign_point(&np1, nplp->o.p);
+ np = &np2;
+ }
+ else
+ { outp = &jp1;
+ assign_point(&np1, nplp->o.ce);
+ assign_point(&np2, nplp->o.p);
+ np = &np1;
+ }
+ if_debug1('O', "[o]use %s\n", (ccw ? "co (ccw)" : "ce (cw)"));
+
+ /* Handle triangular joins now. */
+ if ( join == gs_join_triangle )
+ { fixed tpx = outp->x - nplp->o.p.x + np->x;
+ fixed tpy = outp->y - nplp->o.p.y + np->y;
+ assign_point(&jpx, jp2);
+ if ( !ccw )
+ { /* Insert tp between np2 and jp2. */
+ jp2.x = tpx, jp2.y = tpy;
+ }
+ else
+ { /* Insert tp between jp1 and np1. */
+ assign_point(&jp2, np2);
+ assign_point(&np2, np1);
+ np1.x = tpx, np1.y = tpy;
+ }
+ return 5;
+ }
+
+ /* Don't bother with the miter check if the two */
+ /* points to be joined are very close together, */
+ /* namely, in the same square half-pixel. */
+ if ( join == gs_join_miter &&
+ !(fixed2long(outp->x << 1) == fixed2long(np->x << 1) &&
+ fixed2long(outp->y << 1) == fixed2long(np->y << 1))
+ )
+ { /*
+ * Check whether a miter join is appropriate.
+ * Let a, b be the angles of the two lines.
+ * We check tan(a-b) against the miter_check
+ * by using the following formula:
+ * If tan(a)=u1/v1 and tan(b)=u2/v2, then
+ * tan(a-b) = (u1*v2 - u2*v1) / (u1*u2 + v1*v2).
+ *
+ * We can do all the computations unscaled,
+ * because we're only concerned with ratios.
+ * However, if we have a non-uniform coordinate
+ * system (indicated by pmat != 0), we must do the
+ * computations in user space.
+ */
+ float check = pgs_lp->miter_check;
+ double u1 = plp->e.cdelta.y, v1 = plp->e.cdelta.x;
+ double u2 = nplp->o.cdelta.y, v2 = nplp->o.cdelta.x;
+ double num, denom;
+
+ if ( pmat )
+ { gs_point pt;
+
+ gs_distance_transform_inverse(v1, u1, pmat, &pt);
+ v1 = pt.x, u1 = pt.y;
+ gs_distance_transform_inverse(v2, u2, pmat, &pt);
+ v2 = pt.x, u2 = pt.y;
+ /*
+ * We need to recompute ccw according to the
+ * relative positions of the lines in user space.
+ * We repeat the computation described above,
+ * using the cdelta values instead of the widths.
+ * Because the definition of ccw above is inverted
+ * from the intuitive one (for historical reasons),
+ * we actually have to do the test backwards.
+ */
+ ccw = v1 * u2 < v2 * u1;
+#ifdef DEBUG
+ { double a1 = atan2(u1, v1), a2 = atan2(u2, v2),
+ dif = a1 - a2;
+
+ if ( dif < 0 )
+ dif += 2 * M_PI;
+ else if ( dif >= 2 * M_PI )
+ dif -= 2 * M_PI;
+ if ( (dif < M_PI) != ccw )
+ lprintf8("ccw wrong: tan(a1=%g)=%g/%g, tan(a2=%g)=%g,%g, dif=%g, ccw=%d\n",
+ a1, u1, v1, a2, u2, v2, dif, ccw);
+ }
+#endif
+ }
+ num = u1 * v2 - u2 * v1;
+ denom = u1 * u2 + v1 * v2;
+ /*
+ * We will want either tan(a-b) or tan(b-a)
+ * depending on the orientations of the lines.
+ * Fortunately we know the relative orientations already.
+ */
+ if ( !ccw ) /* have plp - nplp, want vice versa */
+ num = -num;
+#ifdef DEBUG
+if ( gs_debug_c('O') )
+ { dprintf4("[o]Miter check: u1/v1=%f/%f, u2/v2=%f/%f,\n",
+ u1, v1, u2, v2);
+ dprintf3(" num=%f, denom=%f, check=%f\n",
+ num, denom, check);
+ }
+#endif
+ /*
+ * If we define T = num / denom, then we want to use
+ * a miter join iff arctan(T) >= arctan(check).
+ * We know that both of these angles are in the 1st
+ * or 2nd quadrant, and since arctan is monotonic
+ * within each quadrant, we can do the comparisons
+ * on T and check directly, taking signs into account
+ * as follows:
+ * sign(T) sign(check) atan(T) >= atan(check)
+ * ------- ----------- ----------------------
+ * + + T >= check
+ * - + true
+ * + - false
+ * - - T >= check
+ */
+ if ( denom < 0 )
+ num = -num, denom = -denom;
+ /* Now denom >= 0, so sign(num) = sign(T). */
+ if ( check > 0 ?
+ (num < 0 || num >= denom * check) :
+ (num < 0 && num >= denom * check)
+ )
+ { /* OK to use a miter join. */
+ gs_fixed_point mpt;
+ if_debug0('O', " ... passes.\n");
+ /* Compute the intersection of */
+ /* the extended edge lines. */
+ if ( line_intersect(outp, &plp->e.cdelta, np,
+ &nplp->o.cdelta, &mpt) == 0
+ )
+ assign_point(outp, mpt);
+ }
+ }
+ return 4;
+}
+/* ---------------- Cap computations ---------------- */
+
+/* Compute the endpoints of the two caps of a segment. */
+/* Only o.p, e.p, width, and cdelta have been set. */
+private void near
+compute_caps(register pl_ptr plp)
+{ fixed wx2 = plp->width.x;
+ fixed wy2 = plp->width.y;
+ plp->o.co.x = plp->o.p.x + wx2, plp->o.co.y = plp->o.p.y + wy2;
+ plp->o.cdelta.x = -plp->e.cdelta.x,
+ plp->o.cdelta.y = -plp->e.cdelta.y;
+ plp->o.ce.x = plp->o.p.x - wx2, plp->o.ce.y = plp->o.p.y - wy2;
+ plp->e.co.x = plp->e.p.x - wx2, plp->e.co.y = plp->e.p.y - wy2;
+ plp->e.ce.x = plp->e.p.x + wx2, plp->e.ce.y = plp->e.p.y + wy2;
+#ifdef DEBUG
+if ( gs_debug_c('O') )
+ dprintf4("[o]Stroke o=(%f,%f) e=(%f,%f)\n",
+ fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
+ fixed2float(plp->e.p.x), fixed2float(plp->e.p.y)),
+ dprintf4("\twxy=(%f,%f) lxy=(%f,%f)\n",
+ fixed2float(wx2), fixed2float(wy2),
+ fixed2float(plp->e.cdelta.x), fixed2float(plp->e.cdelta.y));
+#endif
+}
+
+#define px endp->p.x
+#define py endp->p.y
+#define xo endp->co.x
+#define yo endp->co.y
+#define xe endp->ce.x
+#define ye endp->ce.y
+#define cdx endp->cdelta.x
+#define cdy endp->cdelta.y
+
+/* Add a round cap to a path. */
+/* Assume the current point is the cap origin (endp->co). */
+private int near
+add_round_cap(gx_path *ppath, const_ep_ptr endp)
+{ fixed xm = px + cdx;
+ fixed ym = py + cdy;
+ int code;
+
+ if ( (code = gx_path_add_partial_arc(ppath, xm, ym,
+ xo + cdx, yo + cdy, quarter_arc_fraction)) < 0 ||
+ (code = gx_path_add_partial_arc(ppath, xe, ye,
+ xe + cdx, ye + cdy, quarter_arc_fraction)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* Compute the points for a non-round cap. */
+/* Return the number of points. */
+private int near
+cap_points(gs_line_cap type, const_ep_ptr endp,
+ gs_fixed_point _ss *pts /* [3] */)
+{
+#define put_point(i, px, py)\
+ pts[i].x = (px), pts[i].y = (py)
+ switch ( type )
+ {
+ case gs_cap_butt:
+ put_point(0, xo, yo);
+ put_point(1, xe, ye);
+ return 2;
+ case gs_cap_square:
+ put_point(0, xo + cdx, yo + cdy);
+ put_point(1, xe + cdx, ye + cdy);
+ return 2;
+ case gs_cap_triangle: /* (not supported by PostScript) */
+ put_point(0, xo, yo);
+ put_point(1, px + cdx, py + cdy);
+ put_point(2, xe, ye);
+ return 3;
+ default: /* can't happen */
+ return_error(gs_error_unregistered);
+ }
+#undef put_point
+}
diff --git a/gs/src/gxsync.c b/gs/src/gxsync.c
new file mode 100644
index 000000000..a0aef2c1d
--- /dev/null
+++ b/gs/src/gxsync.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxsync.c */
+/* Interface to platform-based synchronization primitives */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "gxsync.h"
+
+/* This module abstracts the platform-specific synchronization primitives. */
+/* Since these routines will see heavy use, performance is important. */
+
+
+/* ----- Semaphore interface ----- */
+/* These have the usual queued, counting semaphore semantics: at init time, */
+/* the event count is set to 0 ('wait' will wait until 1st signal). */
+
+/* Allocate & initialize a semaphore */
+gx_semaphore_t * /* returns a new semaphore, 0 if error */
+gx_semaphore_alloc(
+ gs_memory_t *memory /* memory allocator to use */
+) {
+ gx_semaphore_t *sema;
+
+ /* sizeof decl'd sema struct, minus semaphore placeholder's size, + actual semaphore size */
+ unsigned semaSizeof
+ = sizeof(*sema) - sizeof(sema->native) + gp_semaphore_sizeof;
+
+ if ( gp_semaphore_open(0) == 0 ) /* see if gp_semaphores are movable */
+ /* movable */
+ sema = (gx_semaphore_t *)gs_alloc_bytes(memory, semaSizeof,
+ "gx_semaphore (create)");
+ else
+ /* unmovable */
+ sema = (gx_semaphore_t *)gs_alloc_bytes_immovable(memory, semaSizeof,
+ "gx_semaphore (create)");
+ if (sema == 0)
+ return 0;
+
+ /* Make sema remember which allocator was used to allocate it */
+ sema->memory = memory;
+
+ if ( gp_semaphore_open(&sema->native) < 0 )
+ {
+ gs_free_object(memory, sema, "gx_semaphore (alloc)");
+ return 0;
+ }
+ return sema;
+ }
+
+/* Deinit & free a semaphore */
+void
+gx_semaphore_free(
+ gx_semaphore_t *sema /* semaphore to delete */
+) {
+ if (sema)
+ {
+ gp_semaphore_close(&sema->native);
+ gs_free_object(sema->memory, sema, "gx_semaphore (free)");
+ }
+ }
+
+/* Macros defined in gxsync.h, but redefined here so compiler chex consistency */
+#define gx_semaphore_wait(sema) gp_semaphore_wait(&(sema)->native)
+#define gx_semaphore_signal(sema) gp_semaphore_signal(&(sema)->native)
+
+
+/* ----- Monitor interface ----- */
+/* These have the usual monitor semantics: at init time, */
+/* the event count is set to 1 (1st 'enter' succeeds immediately). */
+
+/* Allocate & Init a monitor */
+gx_monitor_t * /* returns a new monitor, 0 if error */
+gx_monitor_alloc(
+ gs_memory_t *memory /* memory allocator to use */
+) {
+ gx_monitor_t *mon;
+
+ /* sizeof decl'd mon struct, minus monitor placeholder's size, + actual monitor size */
+ unsigned monSizeof
+ = sizeof(*mon) - sizeof(mon->native) + gp_monitor_sizeof;
+
+ if ( gp_monitor_open(0) == 0 ) /* see if gp_monitors are movable */
+ /* movable */
+ mon = (gx_monitor_t *)gs_alloc_bytes(memory, monSizeof,
+ "gx_monitor (create)");
+ else
+ /* unmovable */
+ mon = (gx_monitor_t *)gs_alloc_bytes_immovable(memory, monSizeof,
+ "gx_monitor (create)");
+ if (mon == 0)
+ return 0;
+
+ /* Make monitor remember which allocator was used to allocate it */
+ mon->memory = memory;
+
+ if ( gp_monitor_open(&mon->native) < 0 )
+ {
+ gs_free_object(memory, mon, "gx_monitor (alloc)");
+ return 0;
+ }
+ return mon;
+ }
+
+/* Dnit & free a monitor */
+void
+gx_monitor_free(
+ gx_monitor_t *mon /* monitor to delete */
+) {
+ if (mon)
+ {
+ gp_monitor_close(&mon->native);
+ gs_free_object(mon->memory, mon, "gx_monitor (free)");
+ }
+ }
+
+/* Macros defined in gxsync.h, but redefined here so compiler chex consistency */
+#define gx_monitor_enter(sema) gp_monitor_enter(&(sema)->native)
+#define gx_monitor_leave(sema) gp_monitor_leave(&(sema)->native)
+
diff --git a/gs/src/gxsync.h b/gs/src/gxsync.h
new file mode 100644
index 000000000..eecc35623
--- /dev/null
+++ b/gs/src/gxsync.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxsync.h */
+/* Interface to synchronization primitives */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gxsync_INCLUDED)
+ #define gxsync_INCLUDED
+
+ #include "gpsync.h"
+ #include "gsmemory.h"
+
+/* This module abstracts the platform-specific synchronization primitives. */
+/* Since these routines will see heavy use, performance is important. */
+
+/* ----- Semaphore interface ----- */
+/* These have the usual queued, counting semaphore semantics: at init time, */
+/* the event count is set to 0 ('wait' will wait until 1st signal). */
+typedef struct gx_semaphore_s {
+ gs_memory_t *memory; /* allocator to free memory */
+ gp_semaphore native; /* MUST BE LAST last since length is undef'd */
+ /* platform-dep impl, len is gp_semaphore_sizeof */
+} gx_semaphore_t;
+
+gx_semaphore_t * /* returns a new semaphore, 0 if error */
+gx_semaphore_alloc(P1(
+ gs_memory_t *memory /* memory allocator to use */
+));
+void
+gx_semaphore_free(P1(
+ gx_semaphore_t *sema /* semaphore to delete */
+));
+ #define gx_semaphore_wait(sema) gp_semaphore_wait(&(sema)->native)
+ #define gx_semaphore_signal(sema) gp_semaphore_signal(&(sema)->native)
+
+
+/* ----- Monitor interface ----- */
+/* These have the usual monitor semantics: at init time, */
+/* the event count is set to 1 (1st 'enter' succeeds immediately). */
+typedef struct gx_monitor_s {
+ gs_memory_t *memory; /* allocator to free memory */
+ gp_monitor native; /* platform-dep impl, len is gp_monitor_sizeof */
+} gx_monitor_t;
+
+gx_monitor_t * /* returns a new monitor, 0 if error */
+gx_monitor_alloc(P1(
+ gs_memory_t *memory /* memory allocator to use */
+));
+void
+gx_monitor_free(P1(
+ gx_monitor_t *mon /* monitor to delete */
+));
+ #define gx_monitor_enter(sema) gp_monitor_enter(&(sema)->native)
+ #define gx_monitor_leave(sema) gp_monitor_leave(&(sema)->native)
+
+#endif /* !defined(gxsync_INCLUDED) */
diff --git a/gs/src/gxtmap.h b/gs/src/gxtmap.h
new file mode 100644
index 000000000..b627b90e3
--- /dev/null
+++ b/gs/src/gxtmap.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxtmap.h */
+/* Definition of transfer mapping function */
+/* (also used for black generation and undercolor removal) */
+
+#ifndef gxtmap_INCLUDED
+# define gxtmap_INCLUDED
+
+/* Common definition for mapping procedures. */
+/* These are used for transfer functions, black generation, */
+/* and undercolor removal. */
+/* gx_transfer_map should probably be renamed gx_mapping_cache.... */
+
+/* Define an abstract type for a transfer map. */
+typedef struct gx_transfer_map_s gx_transfer_map;
+
+/* Define the type of a mapping procedure. */
+typedef float (*gs_mapping_proc)(P2(floatp, const gx_transfer_map *));
+
+#endif /* gxtmap_INCLUDED */
diff --git a/gs/src/gxtype1.c b/gs/src/gxtype1.c
new file mode 100644
index 000000000..f6979b322
--- /dev/null
+++ b/gs/src/gxtype1.c
@@ -0,0 +1,419 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxtype1.c */
+/* Adobe Type 1 font interpreter support */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccode.h"
+#include "gsline.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzpath.h"
+
+/*
+ * The routines in this file are used for both Type 1 and Type 2
+ * charstring interpreters.
+ */
+
+/*
+ * Define whether or not to force hints to "big pixel" boundaries
+ * when rasterizing at higher resolution. With the current algorithms,
+ * a value of 1 is better for devices without alpha capability,
+ * but 0 is better if alpha is available.
+ */
+#define FORCE_HINTS_TO_BIG_PIXELS 1
+
+/* Structure descriptor */
+public_st_gs_font_type1();
+
+/* Encrypt a string. */
+int
+gs_type1_encrypt(byte *dest, const byte *src, uint len, crypt_state *pstate)
+{ register crypt_state state = *pstate;
+ register const byte *from = src;
+ register byte *to = dest;
+ register uint count = len;
+ while ( count )
+ { encrypt_next(*from, state, *to);
+ from++, to++, count--;
+ }
+ *pstate = state;
+ return 0;
+}
+/* Decrypt a string. */
+int
+gs_type1_decrypt(byte *dest, const byte *src, uint len, crypt_state *pstate)
+{ register crypt_state state = *pstate;
+ register const byte *from = src;
+ register byte *to = dest;
+ register uint count = len;
+ while ( count )
+ { /* If from == to, we can't use the obvious */
+ /* decrypt_next(*from, state, *to); */
+ register byte ch = *from++;
+ decrypt_next(ch, state, *to);
+ to++, count--;
+ }
+ *pstate = state;
+ return 0;
+}
+
+/* Define the structure type for a Type 1 interpreter state. */
+public_st_gs_type1_state();
+/* GC procedures */
+#define pcis ((gs_type1_state *)vptr)
+private ENUM_PTRS_BEGIN(gs_type1_state_enum_ptrs) {
+ if ( index < pcis->ips_count + 3 )
+ { ENUM_RETURN_CONST_STRING_PTR(gs_type1_state,
+ ipstack[index - 3].char_string);
+ }
+ return 0;
+ }
+ ENUM_PTR(0, gs_type1_state, pfont);
+ ENUM_PTR(1, gs_type1_state, pis);
+ ENUM_PTR(2, gs_type1_state, path);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_type1_state_reloc_ptrs) {
+ int i;
+ RELOC_PTR(gs_type1_state, pfont);
+ RELOC_PTR(gs_type1_state, pis);
+ RELOC_PTR(gs_type1_state, path);
+ for ( i = 0; i < pcis->ips_count; i++ )
+ { ip_state *ipsp = &pcis->ipstack[i];
+ int diff = ipsp->ip - ipsp->char_string.data;
+ gs_reloc_const_string(&ipsp->char_string, gcst);
+ ipsp->ip = ipsp->char_string.data + diff;
+ }
+} RELOC_PTRS_END
+#undef pcis
+
+/* ------ Interpreter entry point ------ */
+
+private int
+gs_no_charstring_interpret(gs_type1_state *pcis, const gs_const_string *str,
+ int *pindex)
+{ return_error(gs_error_rangecheck);
+}
+int (*gs_charstring_interpreter[3])
+ (P3(gs_type1_state *pcis, const gs_const_string *str, int *pindex)) = {
+ gs_no_charstring_interpret,
+ gs_no_charstring_interpret,
+ gs_no_charstring_interpret
+};
+
+/*
+ * Continue interpreting a Type 1 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+int
+gs_type1_interpret(gs_type1_state *pcis, const gs_const_string *str,
+ int *pindex)
+{ return (*gs_charstring_interpreter[pcis->pfont->data.CharstringType])
+ (pcis, str, pindex);
+}
+
+/* ------ Interpreter services ------ */
+
+#define s (*ps)
+
+/* We export this for the Type 2 charstring interpreter. */
+void
+accum_xy_proc(register is_ptr ps, fixed dx, fixed dy)
+{ ptx += c_fixed(dx, xx),
+ pty += c_fixed(dy, yy);
+ if ( sfc.skewed )
+ ptx += c_fixed(dy, yx),
+ pty += c_fixed(dx, xy);
+}
+
+/* Initialize a Type 1 interpreter. */
+/* The caller must supply a string to the first call of gs_type1_interpret. */
+int
+gs_type1_interp_init(register gs_type1_state *pcis, gs_imager_state *pis,
+ gx_path *ppath, const gs_log2_scale_point *pscale, bool charpath_flag,
+ int paint_type, gs_font_type1 *pfont)
+{ static const gs_log2_scale_point no_scale = { 0, 0 };
+ const gs_log2_scale_point *plog2_scale =
+ (FORCE_HINTS_TO_BIG_PIXELS ? pscale : &no_scale);
+
+ pcis->pfont = pfont;
+ pcis->pis = pis;
+ pcis->path = ppath;
+ /*
+ * charpath_flag controls coordinate rounding, hinting, and
+ * flatness enhancement. If we allow it to be set to true,
+ * charpath may produce results quite different from show.
+ */
+ pcis->charpath_flag = false /*charpath_flag*/;
+ pcis->paint_type = paint_type;
+ pcis->os_count = 0;
+ pcis->ips_count = 1;
+ pcis->ipstack[0].ip = 0;
+ pcis->ipstack[0].char_string.data = 0;
+ pcis->ipstack[0].char_string.size = 0;
+ pcis->ignore_pops = 0;
+ pcis->init_done = -1;
+ pcis->sb_set = false;
+ pcis->width_set = false;
+
+ /* Set the sampling scale. */
+ set_pixel_scale(&pcis->scale.x, plog2_scale->x);
+ set_pixel_scale(&pcis->scale.y, plog2_scale->y);
+
+ return 0;
+}
+/* Preset the left side bearing and/or width. */
+void
+gs_type1_set_lsb(gs_type1_state *pcis, const gs_point *psbpt)
+{ pcis->lsb.x = float2fixed(psbpt->x);
+ pcis->lsb.y = float2fixed(psbpt->y);
+ pcis->sb_set = true;
+}
+void
+gs_type1_set_width(gs_type1_state *pcis, const gs_point *pwpt)
+{ pcis->width.x = float2fixed(pwpt->x);
+ pcis->width.y = float2fixed(pwpt->y);
+ pcis->width_set = true;
+}
+/* Finish initializing the interpreter if we are actually rasterizing */
+/* the character, as opposed to just computing the side bearing and width. */
+void
+gs_type1_finish_init(gs_type1_state *pcis, gs_op1_state _ss *ps)
+{ gs_imager_state *pis = pcis->pis;
+
+ /* Set up the fixed version of the transformation. */
+ gx_matrix_to_fixed_coeff(&ctm_only(pis), &pcis->fc, max_coeff_bits);
+ sfc = pcis->fc;
+
+ /* Set the current point of the path to the origin, */
+ /* in anticipation of the initial [h]sbw. */
+ { gx_path *ppath = pcis->path;
+ ptx = pcis->origin.x = ppath->position.x;
+ pty = pcis->origin.y = ppath->position.y;
+ }
+
+ /* Initialize hint-related scalars. */
+ pcis->have_hintmask = false;
+ pcis->seac_base = -1;
+ pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0;
+ pcis->flex_count = flex_max; /* not in Flex */
+ pcis->dotsection_flag = dotsection_out;
+ pcis->vstem3_set = false;
+ pcis->vs_offset.x = pcis->vs_offset.y = 0;
+ pcis->hints_initial = 0; /* probably not needed */
+ pcis->hint_next = 0;
+ pcis->hints_pending = 0;
+
+ /* Assimilate the hints proper. */
+ { gs_log2_scale_point log2_scale;
+ log2_scale.x = pcis->scale.x.log2_unit;
+ log2_scale.y = pcis->scale.y.log2_unit;
+ if ( pcis->charpath_flag )
+ reset_font_hints(&pcis->fh, &log2_scale);
+ else
+ compute_font_hints(&pcis->fh, &pis->ctm, &log2_scale,
+ &pcis->pfont->data);
+ }
+ reset_stem_hints(pcis);
+
+ /*
+ * Set the flatness to a value that is likely to produce reasonably
+ * good-looking curves, regardless of its current value in the
+ * graphics state. If the character is very small, set the flatness
+ * to zero, which will produce very accurate curves.
+ */
+ { float cxx = fabs(pis->ctm.xx), cyy = fabs(pis->ctm.yy);
+ if ( cyy < cxx )
+ cxx = cyy;
+ if ( !is_xxyy(&pis->ctm) )
+ { float cxy = fabs(pis->ctm.xy), cyx = fabs(pis->ctm.yx);
+ if ( cxy < cxx )
+ cxx = cxy;
+ if ( cyx < cxx )
+ cxx = cyx;
+ }
+ /* Don't let the flatness be worse than the default. */
+ if ( cxx > pis->flatness )
+ cxx = pis->flatness;
+ /* If the character is tiny, force accurate curves. */
+ if ( cxx < 0.2 )
+ cxx = 0;
+ pcis->flatness = cxx;
+ }
+
+ /* Move to the side bearing point. */
+ accum_xy(pcis->lsb.x, pcis->lsb.y);
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+
+ pcis->init_done = 1;
+}
+
+/* ------ Operator procedures ------ */
+
+/* We put these before the interpreter to save having to write */
+/* prototypes for all of them. */
+
+int
+gs_op1_closepath(register is_ptr ps)
+{ /* Note that this does NOT reset the current point! */
+ gx_path *ppath = sppath;
+ subpath *psub;
+ segment *pseg;
+ fixed dx, dy;
+ int code;
+
+ /* Check for and suppress a microscopic closing line. */
+ if ( (psub = ppath->current_subpath) != 0 &&
+ (pseg = psub->last) != 0 &&
+ (dx = pseg->pt.x - psub->pt.x,
+ any_abs(dx) < float2fixed(0.1)) &&
+ (dy = pseg->pt.y - psub->pt.y,
+ any_abs(dy) < float2fixed(0.1))
+ )
+ switch ( pseg->type )
+ {
+ case s_line:
+ code = gx_path_pop_close_subpath(sppath);
+ break;
+ case s_curve:
+ /*
+ * Unfortunately, there is no "s_curve_close". (Maybe there
+ * should be?) Just adjust the final point of the curve so it
+ * is identical to the closing point.
+ */
+ pseg->pt = psub->pt;
+#define pcseg ((curve_segment *)pseg)
+ pcseg->p2.x -= dx;
+ pcseg->p2.y -= dy;
+#undef pcseg
+ /* falls through */
+ default:
+ /* What else could it be?? */
+ code = gx_path_close_subpath(sppath);
+ }
+ else
+ code = gx_path_close_subpath(sppath);
+ if ( code < 0 )
+ return code;
+ return gx_path_add_point(ppath, ptx, pty); /* put the point where it was */
+}
+
+int
+gs_op1_rrcurveto(register is_ptr ps, fixed dx1, fixed dy1,
+ fixed dx2, fixed dy2, fixed dx3, fixed dy3)
+{ gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+ accum_xy(dx1, dy1);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(dx2, dy2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_xy(dx3, dy3);
+ return gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+}
+
+#undef s
+
+/* Record the side bearing and character width. */
+int
+gs_type1_sbw(gs_type1_state *pcis, fixed lsbx, fixed lsby, fixed wx, fixed wy)
+{ if ( !pcis->sb_set )
+ pcis->lsb.x = lsbx, pcis->lsb.y = lsby,
+ pcis->sb_set = true; /* needed for accented chars */
+ if ( !pcis->width_set )
+ pcis->width.x = wx, pcis->width.y = wy,
+ pcis->width_set = true;
+ if_debug4('1',"[1]sb=(%g,%g) w=(%g,%g)\n",
+ fixed2float(pcis->lsb.x), fixed2float(pcis->lsb.y),
+ fixed2float(pcis->width.x), fixed2float(pcis->width.y));
+ return 0;
+}
+
+/* Handle the end of a character. */
+int
+gs_type1_endchar(gs_type1_state *pcis)
+{ gs_imager_state *pis = pcis->pis;
+ gx_path *ppath = pcis->path;
+
+ if ( pcis->hint_next != 0 || path_is_drawing(ppath) )
+ apply_path_hints(pcis, true);
+ /* Set the current point to the character origin */
+ /* plus the width. */
+ { gs_fixed_point pt;
+
+ gs_point_transform2fixed(&pis->ctm,
+ fixed2float(pcis->width.x),
+ fixed2float(pcis->width.y),
+ &pt);
+ gx_path_add_point(ppath, pt.x, pt.y);
+ }
+ if ( pcis->scale.x.log2_unit + pcis->scale.y.log2_unit == 0 )
+ { /*
+ * Tweak up the fill adjustment. This is a hack for when
+ * we can't oversample. The values here are based entirely
+ * on experience, not theory, and are designed primarily
+ * for displays and low-resolution fax.
+ */
+ gs_fixed_rect bbox;
+ int dx, dy, dmax;
+
+ gx_path_bbox(ppath, &bbox);
+ dx = fixed2int_ceiling(bbox.q.x - bbox.p.x);
+ dy = fixed2int_ceiling(bbox.q.y - bbox.p.y);
+ dmax = max(dx, dy);
+ if ( pcis->fh.snap_h.count || pcis->fh.snap_v.count ||
+ pcis->fh.a_zone_count
+ )
+ { /* We have hints. Only tweak up a little at */
+ /* very small sizes, to help nearly-vertical */
+ /* or nearly-horizontal diagonals. */
+ pis->fill_adjust.x = pis->fill_adjust.y =
+ (dmax < 15 ? float2fixed(0.15) :
+ dmax < 25 ? float2fixed(0.1) :
+ fixed_0);
+ }
+ else
+ { /* No hints. Tweak a little more to compensate */
+ /* for lack of snapping to pixel grid. */
+ pis->fill_adjust.x = pis->fill_adjust.y =
+ (dmax < 10 ? float2fixed(0.2) :
+ dmax < 25 ? float2fixed(0.1) :
+ float2fixed(0.05));
+ }
+ }
+ else
+ { /* Don't do any adjusting. */
+ pis->fill_adjust.x = pis->fill_adjust.y = fixed_0;
+ }
+ /* Set the flatness for curve rendering. */
+ if ( !pcis->charpath_flag )
+ gs_imager_setflat(pis, pcis->flatness);
+ return 0;
+}
diff --git a/gs/src/gxtype1.h b/gs/src/gxtype1.h
new file mode 100644
index 000000000..c3da67231
--- /dev/null
+++ b/gs/src/gxtype1.h
@@ -0,0 +1,320 @@
+/* Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxtype1.h */
+/* Private Adobe Type 1 / Type 2 charstring interpreter definitions */
+#include "gscrypt1.h"
+#include "gstype1.h"
+#include "gxop1.h"
+
+/* This file defines the structures for the state of a Type 1 / */
+/* Type 2 charstring interpreter. */
+
+/*
+ * Because of oversampling, one pixel in the Type 1 interpreter may
+ * correspond to several device pixels. This is also true of the hint data,
+ * since the CTM reflects the transformation to the oversampled space.
+ * To help keep the font level hints separated from the character level hints,
+ * we store the scaling factor separately with each set of hints.
+ */
+typedef struct pixel_scale_s {
+ fixed unit; /* # of pixels per device pixel */
+ fixed half; /* unit / 2 */
+ int log2_unit; /* log2(unit / fixed_1) */
+} pixel_scale;
+typedef struct point_scale_s {
+ pixel_scale x, y;
+} point_scale;
+#define set_pixel_scale(pps, log2)\
+ (pps)->unit = ((pps)->half = fixed_half << ((pps)->log2_unit = log2)) << 1
+#define scaled_rounded(v, pps)\
+ (((v) + (pps)->half) & -(pps)->unit)
+
+/* ------ Font level hints ------ */
+
+/* Define the standard stem width tables. */
+/* Each table is sorted, since the StemSnap arrays are sorted. */
+#define max_snaps (1 + max_StemSnap)
+typedef struct {
+ int count;
+ fixed data[max_snaps];
+} stem_snap_table;
+
+/* Define the alignment zone structure. */
+/* These are in device coordinates also. */
+#define max_a_zones (max_BlueValues + max_OtherBlues)
+typedef struct {
+ int is_top_zone;
+ fixed v0, v1; /* range for testing */
+ fixed flat; /* flat position */
+} alignment_zone;
+
+/* Define the structure for hints that depend only on the font and CTM, */
+/* not on the individual character. Eventually these should be cached */
+/* with the font/matrix pair. */
+typedef struct font_hints_s {
+ bool axes_swapped; /* true if x & y axes interchanged */
+ /* (only set if using hints) */
+ bool x_inverted, y_inverted; /* true if axis is inverted */
+ bool use_x_hints; /* true if we should use hints */
+ /* for char space x coords (vstem) */
+ bool use_y_hints; /* true if we should use hints */
+ /* for char space y coords (hstem) */
+ point_scale scale; /* oversampling scale */
+ stem_snap_table snap_h; /* StdHW, StemSnapH */
+ stem_snap_table snap_v; /* StdVW, StemSnapV */
+ fixed blue_fuzz, blue_shift; /* alignment zone parameters */
+ /* in device pixels */
+ bool suppress_overshoot; /* (computed from BlueScale) */
+ int a_zone_count; /* # of alignment zones */
+ alignment_zone a_zones[max_a_zones]; /* the alignment zones */
+} font_hints;
+
+/* ------ Character level hints ------ */
+
+/*
+ * Define the stem hint tables. Each stem hint table is kept sorted.
+ * Stem hints are in device coordinates. We have to retain replaced hints
+ * so that we can make consistent rounding choices for stem edges.
+ * This is clunky, but I don't see any other way to do it.
+ *
+ * The Type 2 charstring documentation says that the total number of hints
+ * is limited to 96, but since we store horizontal and vertical hints
+ * separately, we must set max_stems large enough to allow either one to
+ * get this big.
+ */
+#define max_total_stem_hints 96
+#define max_stems 96
+typedef struct {
+ fixed v0, v1; /* coordinates (widened a little) */
+ fixed dv0, dv1; /* adjustment values */
+} stem_hint;
+typedef struct {
+ int count;
+ int current; /* cache cursor for search */
+ /*
+ * We store active hints at the bottom of the table, and
+ * replaced hints at the top. (Eventually we will have to use a
+ * more sophisticated scheme, to implement Type 2 hint masks.)
+ */
+ int replaced_count; /* # of replaced hints at top */
+ stem_hint data[max_stems];
+} stem_hint_table;
+
+/* ------ Interpreter state ------ */
+
+/* Define the control state of the interpreter. */
+/* This is what must be saved and restored */
+/* when calling a CharString subroutine. */
+typedef struct {
+ const byte *ip;
+ crypt_state dstate;
+ gs_const_string char_string; /* original CharString or Subr, */
+ /* for GC */
+} ip_state;
+
+/* Get the next byte from a CharString. It may or may not be encrypted. */
+#define charstring_this(ch, state, encrypted)\
+ (encrypted ? decrypt_this(ch, state) : ch)
+#define charstring_next(ch, state, chvar, encrypted)\
+ (encrypted ? (chvar = decrypt_this(ch, state),\
+ decrypt_skip_next(ch, state)) :\
+ (chvar = ch))
+#define charstring_skip_next(ch, state, encrypted)\
+ (encrypted ? decrypt_skip_next(ch, state) : 0)
+
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+
+#ifndef segment_DEFINED
+# define segment_DEFINED
+typedef struct segment_s segment;
+#endif
+
+/* This is the full state of the Type 1 interpreter. */
+#define ostack_size 48 /* per Type 2 documentation */
+#define ipstack_size 10 /* per documentation */
+struct gs_type1_state_s {
+ /* The following are set at initialization */
+ gs_font_type1 *pfont; /* font-specific data */
+ gs_imager_state *pis; /* imager state */
+ gx_path *path; /* path for appending */
+ bool charpath_flag; /* false if show, true if charpath */
+ int paint_type; /* 0/3 for fill, 1/2 for stroke */
+ fixed_coeff fc; /* cached fixed coefficients */
+ float flatness; /* flatness for character curves */
+ point_scale scale; /* oversampling scale */
+ font_hints fh; /* font-level hints */
+ gs_fixed_point origin; /* character origin */
+ /* The following are updated dynamically */
+ fixed ostack[ostack_size]; /* the Type 1 operand stack */
+ int os_count; /* # of occupied stack entries */
+ ip_state ipstack[ipstack_size+1]; /* control stack */
+ int ips_count; /* # of occupied entries */
+ int init_done; /* -1 if not done & not needed, */
+ /* 0 if not done & needed, 1 if done */
+ bool sb_set; /* true if lsb is preset */
+ bool width_set; /* true if width is set (for */
+ /* seac components) */
+ bool have_hintmask; /* true if using a hint mask */
+ /* (Type 2 charstrings only) */
+ gs_fixed_point lsb; /* left side bearing (char coords) */
+ gs_fixed_point width; /* character width (char coords) */
+ int seac_base; /* base character code for seac, */
+ /* or -1 */
+ gs_fixed_point adxy; /* seac accent displacement, */
+ /* needed to adjust currentpoint */
+ fixed asb_diff; /* seac asb - accented char lsb.x, */
+ /* needed to adjust Flex endpoint */
+ gs_fixed_point position; /* save unadjusted position */
+ /* when returning temporarily */
+ /* to caller */
+ int flex_path_state_flags; /* record whether path was open */
+ /* at start of Flex section */
+#define flex_max 8
+ gs_fixed_point flex_points[flex_max]; /* points for Flex */
+ int flex_count;
+ int ignore_pops; /* # of pops to ignore (after */
+ /* a known othersubr call) */
+ /* The following are set dynamically. */
+#define dotsection_in 0
+#define dotsection_out (-1)
+ int dotsection_flag; /* 0 if inside dotsection, */
+ /* -1 if outside */
+ bool vstem3_set; /* true if vstem3 seen */
+ gs_fixed_point vs_offset; /* device space offset for centering */
+ /* middle stem of vstem3 */
+ int hints_initial; /* hints applied to initial point */
+ /* of subpath */
+ gs_fixed_point unmoved_start; /* original initial point of subpath */
+ segment *hint_next; /* last segment where hints have */
+ /* been applied, 0 means none of */
+ /* current subpath has been hinted */
+ int hints_pending; /* hints applied to end of hint_next */
+ gs_fixed_point unmoved_end; /* original hint_next->pt */
+ stem_hint_table hstem_hints; /* horizontal stem hints */
+ stem_hint_table vstem_hints; /* vertical stem hints */
+ fixed transient_array[32]; /* Type 2 transient array, */
+ /* will be variable-size someday */
+};
+extern_st(st_gs_type1_state);
+#define public_st_gs_type1_state() /* in gstype1.c */\
+ gs_public_st_composite(st_gs_type1_state, gs_type1_state, "gs_type1_state",\
+ gs_type1_state_enum_ptrs, gs_type1_state_reloc_ptrs)
+
+/* ------ Shared Type 1 / Type 2 interpreter fragments ------ */
+
+/* Declare the array of charstring interpreters, indexed by CharstringType. */
+extern int (*gs_charstring_interpreter[3])
+ (P3(gs_type1_state *pcis, const gs_const_string *str, int *pindex));
+
+/* Copy the operand stack out of the saved state. */
+#define init_cstack(cstack, csp, pcis)\
+ do {\
+ if ( pcis->os_count == 0 )\
+ csp = cstack - 1;\
+ else\
+ { memcpy(cstack, pcis->ostack, pcis->os_count * sizeof(fixed));\
+ csp = &cstack[pcis->os_count - 1];\
+ }\
+ } while (0)\
+
+/* Decode and push a 1-byte number. */
+#define decode_push_num1(csp, c)\
+ (*++csp = int2fixed(c_value_num1(c)))
+
+/* Decode and push a 2-byte number. */
+#define decode_push_num2(csp, c, cip, state, encrypted)\
+ do {\
+ uint c2 = *cip++;\
+ int cn;\
+\
+ cn = charstring_this(c2, state, encrypted);\
+ if ( c < c_neg2_0 )\
+ { if_debug2('1', "[1] (%d)+%d\n", c_value_pos2(c, 0), cn);\
+ *++csp = int2fixed(c_value_pos2(c, 0) + (int)cn);\
+ }\
+ else\
+ { if_debug2('1', "[1] (%d)-%d\n", c_value_neg2(c, 0), cn);\
+ *++csp = int2fixed(c_value_neg2(c, 0) - (int)cn);\
+ }\
+ charstring_skip_next(c2, state, encrypted);\
+ } while (0)
+
+/* Decode a 4-byte number, but don't push it, because Type 1 and Type 2 */
+/* charstrings scale it differently. */
+#if arch_sizeof_long > 4
+# define sign_extend_num4(lw)\
+ lw = (lw ^ 0x80000000L) - 0x80000000L
+#else
+# define sign_extend_num4(lw) DO_NOTHING
+#endif
+#define decode_num4(lw, cip, state, encrypted)\
+ do {\
+ int i;\
+ uint c4;\
+\
+ lw = 0;\
+ for ( i = 4; --i >= 0; )\
+ { charstring_next(*cip, state, c4, encrypted);\
+ lw = (lw << 8) + c4;\
+ cip++;\
+ }\
+ sign_extend_num4(lw);\
+ } while (0)
+
+/* ------ Shared Type 1 / Type 2 charstring utilities ------ */
+
+void gs_type1_finish_init(P2(gs_type1_state *pcis, is_ptr ps));
+
+int gs_type1_sbw(P5(gs_type1_state *pcis, fixed sbx, fixed sby,
+ fixed wx, fixed wy));
+
+int gs_type1_endchar(P1(gs_type1_state *pcis));
+
+/* ----- Interface between main Type 1 interpreter and hint routines ----- */
+
+/* Font level hints */
+void reset_font_hints(P2(font_hints *, const gs_log2_scale_point *));
+void compute_font_hints(P4(font_hints *, const gs_matrix_fixed *,
+ const gs_log2_scale_point *,
+ const gs_type1_data *));
+/* Character level hints */
+void reset_stem_hints(P1(gs_type1_state *)),
+ update_stem_hints(P1(gs_type1_state *)),
+ type1_replace_stem_hints(P1(gs_type1_state *)),
+#define replace_stem_hints(pcis)\
+ (apply_path_hints(pcis, false),\
+ type1_replace_stem_hints(pcis))
+ type1_apply_path_hints(P3(gs_type1_state *, bool, gx_path *)),
+#define apply_path_hints(pcis, closing)\
+ type1_apply_path_hints(pcis, closing, pcis->path)
+ type1_do_hstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *)),
+#define type1_hstem(pcis, y, dy)\
+ type1_do_hstem(pcis, y, dy, &(pcis)->pis->ctm)
+ type1_do_vstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *)),
+#define type1_vstem(pcis, x, dx)\
+ type1_do_vstem(pcis, x, dx, &(pcis)->pis->ctm)
+ type1_do_center_vstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *));
+#define center_vstem(pcis, x0, dx)\
+ type1_do_center_vstem(pcis, x0, dx, &(pcis)->pis->ctm)
diff --git a/gs/src/gxxfont.h b/gs/src/gxxfont.h
new file mode 100644
index 000000000..84aebe21d
--- /dev/null
+++ b/gs/src/gxxfont.h
@@ -0,0 +1,167 @@
+/* Copyright (C) 1992, 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gxxfont.h */
+/* External font interface for Ghostscript library */
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gsuid.h"
+#include "gsxfont.h"
+
+/*
+ * Design issues for external fonts
+ *
+ * 1. Where do xfonts come from: a device or a font service?
+ *
+ * 2. Is a given xfont associated with a particular device, or with a
+ * class of devices, which may have different output media?
+ * (Specifically, Windows displays vs. printers.)
+ *
+ * 3. Is an xfont a handle that must be interpreted by its originator,
+ * or an object with its own set of operations?
+ *
+ * 4. Are xfonts always transformation-specific, or is there such a thing
+ * as a scalable xfont?
+ *
+ * 5. What is the meaning of the transformation matrix supplied when
+ * asking for an xfont?
+ *
+ * Answers (for the current design)
+ *
+ * 1. Devices supply xfonts. Internal devices (image, null, clipping,
+ * command list, tracing) forward font requests to a real underlying
+ * device. File format devices should do the same, but right now
+ * they don't.
+ *
+ * 2. An xfont is not associated with anything: it just provides bitmaps.
+ * Since xfonts are only used at small sizes and low resolutions,
+ * tuning differences for different output media aren't likely to be
+ * an issue.
+ *
+ * 3. Xfonts are objects. They are allocated by their originator, and
+ * (currently) only freed by `restore'.
+ *
+ * 4. Xfonts are always transformation-specific. This may lead to some
+ * clutter, but it's very unlikely that a document will have enough
+ * different transformed versions of a single font for this to be a
+ * problem in practice.
+ *
+ * 5. The transformation matrix is the CTM within the BuildChar or BuildGlyph
+ * procedure. This maps a 1000x1000 square to the intended character size
+ * (assuming the base font uses the usual 1000-unit scaling).
+ */
+
+/* The definitions for xfonts are very similar to those for devices. */
+
+/* Structure for generic xfonts. */
+typedef struct gx_xfont_common_s {
+ gx_xfont_procs *procs;
+} gx_xfont_common;
+/* A generic xfont. */
+struct gx_xfont_s {
+ gx_xfont_common common;
+};
+
+/* Definition of xfont procedures. */
+
+struct gx_xfont_procs_s {
+
+ /* Look up a font name, UniqueID, and matrix, and return */
+ /* an xfont. */
+
+ /* NOTE: even though this is defined as an xfont_proc, */
+ /* it is actually a `factory' procedure, the only one that */
+ /* does not take an xfont * as its first argument. */
+
+#define xfont_proc_lookup_font(proc)\
+ gx_xfont *proc(P7(gx_device *dev, const byte *fname, uint len,\
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,\
+ gs_memory_t *mem))
+ xfont_proc_lookup_font((*lookup_font));
+
+ /* Convert a character name to an xglyph code. */
+ /* encoding_index is 0 for StandardEncoding, */
+ /* 1 for ISOLatin1Encoding, 2 for SymbolEncoding, */
+ /* and -1 for any other encoding. Either chr or glyph */
+ /* may be absent (gs_no_char/glyph), but not both. */
+ /* OBSOLETE as of release 3.43, but still supported. */
+
+#define xfont_proc_char_xglyph(proc)\
+ gx_xglyph proc(P5(gx_xfont *xf, gs_char chr, int encoding_index,\
+ gs_glyph glyph, gs_proc_glyph_name((*glyph_name))))
+ xfont_proc_char_xglyph((*char_xglyph));
+
+ /* Get the metrics for a character. */
+ /* Note: pwidth changed in release 2.9.7. */
+
+#define xfont_proc_char_metrics(proc)\
+ int proc(P5(gx_xfont *xf, gx_xglyph xg, int wmode,\
+ gs_point *pwidth, gs_int_rect *pbbox))
+ xfont_proc_char_metrics((*char_metrics));
+
+ /* Render a character. */
+ /* (x,y) corresponds to the character origin. */
+ /* The target may be any Ghostscript device. */
+
+#define xfont_proc_render_char(proc)\
+ int proc(P7(gx_xfont *xf, gx_xglyph xg, gx_device *target,\
+ int x, int y, gx_color_index color, int required))
+ xfont_proc_render_char((*render_char));
+
+ /* Release any external resources associated with an xfont. */
+ /* If mprocs is not NULL, also free any storage */
+ /* allocated by lookup_font (including the xfont itself). */
+
+#define xfont_proc_release(proc)\
+ int proc(P2(gx_xfont *xf, gs_memory_t *mem))
+ xfont_proc_release((*release));
+
+ /* Convert a character name to an xglyph code. */
+ /* This is the same as char_xglyph, except that */
+ /* it takes a vector of callback procedures. */
+ /* (New in release 3.43.) */
+
+#define xfont_proc_char_xglyph2(proc)\
+ gx_xglyph proc(P5(gx_xfont *xf, gs_char chr, int encoding_index,\
+ gs_glyph glyph, const gx_xfont_callbacks *callbacks))
+ xfont_proc_char_xglyph2((*char_xglyph2));
+
+};
+
+/*
+ * Since xfonts are garbage-collectable, they need structure descriptors.
+ * Fortunately, the common part of an xfont contains no pointers to
+ * GC-managed space, so simple xfonts can use gs_private_st_simple.
+ * The following macro will serve for an xfont with only one pointer,
+ * to its device:
+ */
+#define gs__st_dev_ptrs1(scope_st, stname, stype, sname, penum, preloc, de)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ case 0: ENUM_RETURN(gx_device_enum_ptr((gx_device *)(((stype *)vptr)->de)));\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ ((stype *)vptr)->de = (void *)gx_device_reloc_ptr((gx_device *)(((stype *)vptr)->de), gcst);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+/*
+ * We probably don't ever want xfont descriptors to be public....
+#define gs_public_st_dev_ptrs1(stname, stype, sname, penum, preloc, de)\
+ gs__st_dev_ptrs1(public_st, stname, stype, sname, penum, preloc, de)
+ */
+#define gs_private_st_dev_ptrs1(stname, stype, sname, penum, preloc, de)\
+ gs__st_dev_ptrs1(private_st, stname, stype, sname, penum, preloc, de)
diff --git a/gs/src/gzacpath.h b/gs/src/gzacpath.h
new file mode 100644
index 000000000..d6ec04427
--- /dev/null
+++ b/gs/src/gzacpath.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gzacpath.h */
+/* Private representation of clipping path accumulator */
+/* Requires gxdevice.h, gzcpath.h */
+
+/*
+ * Device for accumulating a rectangle list. This device can clip
+ * the list being accumulated with a clipping rectangle on the fly:
+ * we use this to clip clipping paths to band boundaries when
+ * rendering a band list.
+ */
+typedef struct gx_device_cpath_accum_s {
+ gx_device_common;
+ gs_memory_t *list_memory;
+ gs_int_rect clip_box;
+ gs_int_rect bbox;
+ gx_clip_list list;
+} gx_device_cpath_accum;
+
+/* Start accumulating a clipping path. */
+void gx_cpath_accum_begin(P2(gx_device_cpath_accum *padev, gs_memory_t *mem));
+
+/* Set the accumulator's clipping box. */
+void gx_cpath_accum_set_cbox(P2(gx_device_cpath_accum *padev,
+ const gs_fixed_rect *pbox));
+
+/* Finish accumulating a clipping path. */
+/* Note that this releases the old contents of the clipping path. */
+int gx_cpath_accum_end(P2(const gx_device_cpath_accum *padev,
+ gx_clip_path *pcpath));
+
+/* Discard an accumulator in case of error. */
+void gx_cpath_accum_discard(P1(gx_device_cpath_accum *padev));
diff --git a/gs/src/gzcpath.h b/gs/src/gzcpath.h
new file mode 100644
index 000000000..6819d52e7
--- /dev/null
+++ b/gs/src/gzcpath.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gzcpath.h */
+/* Private representation of clipping paths for Ghostscript library */
+/* Requires gzpath.h. */
+#include "gxcpath.h"
+
+/* gx_clip_path is a 'subclass' of gx_path. */
+struct gx_clip_path_s {
+ gx_path path;
+ int rule; /* rule for insideness of path */
+ /* Anything within the inner_box is guaranteed to fall */
+ /* entirely within the clipping path. */
+ gs_fixed_rect inner_box;
+ /* Anything outside the outer_box is guaranteed to fall */
+ /* entirely outside the clipping path. This is the same */
+ /* as the path bounding box, widened to pixel boundaries. */
+ gs_fixed_rect outer_box;
+ gx_clip_list list;
+ char segments_valid; /* segment representation is valid */
+ char shares_list; /* if true, this path shares its */
+ /* clip list storage with the one in */
+ /* the previous saved graphics state */
+ /* The id changes whenever the clipping region changes. */
+ gs_id id;
+};
+extern_st(st_clip_path);
+#define public_st_clip_path() /* in gxcpath.c */\
+ gs_public_st_composite(st_clip_path, gx_clip_path, "clip_path",\
+ clip_path_enum_ptrs, clip_path_reloc_ptrs)
+#define st_clip_path_max_ptrs (st_path_max_ptrs + st_clip_list_max_ptrs)
diff --git a/gs/src/gzline.h b/gs/src/gzline.h
new file mode 100644
index 000000000..db82c7ce1
--- /dev/null
+++ b/gs/src/gzline.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gzline.h */
+/* Line parameter implementation */
+#include "gxline.h"
+
+#define private_st_line_params() /* in gsstate.c */\
+ gs_private_st_ptrs1(st_line_params, gx_line_params, "line_params",\
+ line_params_enum_ptrs, line_params_reloc_ptrs, dash.pattern)
+#define st_line_params_num_ptrs 1
+
+/* Internal accessor for line parameters in graphics state */
+const gx_line_params *gs_currentlineparams(P1(const gs_imager_state *));
diff --git a/gs/src/gzpath.h b/gs/src/gzpath.h
new file mode 100644
index 000000000..897459ac9
--- /dev/null
+++ b/gs/src/gzpath.h
@@ -0,0 +1,293 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gzpath.h */
+/* Private representation of paths for Ghostscript library */
+/* Requires gxfixed.h */
+#include "gxpath.h"
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * Paths are represented as a linked list of line or curve segments,
+ * similar to what pathforall reports.
+ */
+
+/*
+ * Define path segment types: segment start, line, or Bezier curve.
+ * We have a special type for the line added by closepath.
+ */
+typedef enum {
+ s_start,
+ s_line,
+ s_line_close,
+ s_curve
+} segment_type;
+/* Define the common structure for all segments. */
+#define segment_common\
+ segment *prev;\
+ segment *next;\
+ ushort /*segment_type*/ type;\
+ ushort /*segment_notes*/ notes;\
+ gs_fixed_point pt; /* initial point for starts, */\
+ /* final point for others */
+
+/* Forward declarations for structure types */
+#ifndef segment_DEFINED
+# define segment_DEFINED
+typedef struct segment_s segment;
+#endif
+typedef struct subpath_s subpath;
+
+/*
+ * Define a generic segment. This is never instantiated,
+ * but we define a descriptor anyway for the benefit of subclasses.
+ */
+struct segment_s {
+ segment_common
+};
+#define private_st_segment() /* in gxpath.c */\
+ gs_private_st_ptrs2(st_segment, struct segment_s, "segment",\
+ segment_enum_ptrs, segment_reloc_ptrs, prev, next)
+
+/* Line segments have no special data. */
+typedef struct {
+ segment_common
+} line_segment;
+#define private_st_line() /* in gxpath.c */\
+ gs_private_st_suffix_add0(st_line, line_segment, "line",\
+ line_enum_ptrs, line_reloc_ptrs, st_segment)
+
+/* Line_close segments are for the lines appended by closepath. */
+/* They point back to the subpath being closed. */
+typedef struct {
+ segment_common
+ subpath *sub;
+} line_close_segment;
+#define private_st_line_close() /* in gxpath.c */\
+ gs_private_st_suffix_add1(st_line_close, line_close_segment, "close",\
+ close_enum_ptrs, close_reloc_ptrs, st_segment, sub)
+
+/*
+ * We use two different representations for curve segments: one defined by
+ * two endpoints (p0, p3) and two control points (p1, p2), and one defined
+ * by two sets of parametric cubic coefficients (ax ... dy). Here is how
+ * they are related (v = x or y). We spell out some multiplies by 3 for
+ * the benefit of compilers too simple to optimize this.
+ */
+#define curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, t01, t12)\
+ (/*d = (v0),*/\
+ t01 = (v1) - (v0), c = (t01 << 1) + t01,\
+ t12 = (v2) - (v1), b = (t12 << 1) + t12 - c,\
+ a = (v3) - b - c - (v0))
+/*
+ * or conversely
+ */
+#define curve_coefficients_to_points(a, b, c, d, v1, v2, v3)\
+ (/*v0 = (d),*/\
+ v1 = (d) + ((c) / 3),\
+ v2 = v1 + (((b) + (c)) / 3),\
+ v3 = (a) + (b) + (c) + (d))
+
+/* Curve segments store the control points. */
+typedef struct {
+ segment_common
+ gs_fixed_point p1, p2;
+} curve_segment;
+#define private_st_curve() /* in gxpath.c */\
+ gs_private_st_composite_only(st_curve, curve_segment, "curve",\
+ segment_enum_ptrs, segment_reloc_ptrs)
+
+/*
+ * Define a start segment. This serves as the head of a subpath.
+ * The closer is only used temporarily when filling,
+ * to close an open subpath.
+ */
+struct subpath_s {
+ segment_common
+ segment *last; /* last segment of subpath, */
+ /* points back to here if empty */
+ int curve_count; /* # of curves */
+ line_close_segment closer;
+ char/*bool*/ is_closed; /* true if subpath is closed */
+};
+#define private_st_subpath() /* in gxpath.c */\
+ gs_private_st_suffix_add1(st_subpath, subpath, "subpath",\
+ subpath_enum_ptrs, subpath_reloc_ptrs, st_segment, last)
+
+/* Test whether a subpath is a rectangle; if so, also return */
+/* the start of the next subpath. */
+bool gx_subpath_is_rectangle(P3(const subpath *pstart, gs_fixed_rect *pbox,
+ const subpath **ppnext));
+
+/* Curve manipulation */
+
+/* Return the smallest value k such that 2^k segments will approximate */
+/* the curve to within the desired flatness. */
+int gx_curve_log2_samples(P4(fixed, fixed, const curve_segment *, fixed));
+
+/* Return up to 2 values of t which split the curve into monotonic parts. */
+int gx_curve_monotonic_points(P5(fixed, fixed, fixed, fixed, double [2]));
+
+/* Split a curve at an arbitrary value of t. */
+void gx_curve_split(P6(fixed, fixed, const curve_segment *, double,
+ curve_segment *, curve_segment *));
+
+/* Flatten a partial curve by sampling (internal procedure). */
+int gx_flatten_sample(P4(gx_path *, int, curve_segment *, segment_notes));
+
+/* Initialize a cursor for rasterizing a monotonic curve. */
+typedef struct curve_cursor_s {
+ /* Following are set at initialization */
+ int k; /* 2^k segments */
+ gs_fixed_point p0; /* starting point */
+ const curve_segment *pc; /* other points */
+ fixed a, b, c; /* curve coefficients */
+ double da, db, dc; /* scaled double versions of a, b, c */
+ bool double_set; /* true if da/b/c set */
+ int fixed_limit; /* can do in fixed point if t <= limit */
+ /* Following are updated dynamically. */
+ struct ccc_ { /* one-element cache */
+ fixed ky0, ky3; /* key (range) */
+ fixed xl, xd; /* value */
+ } cache;
+} curve_cursor;
+void gx_curve_cursor_init(P5(curve_cursor *prc, fixed x0, fixed y0,
+ const curve_segment *pc, int k));
+
+/* Return the value of X at a given Y value on a monotonic curve. */
+/* y must lie between prc->p0.y and prc->pt.y. */
+fixed gx_curve_x_at_y(P2(curve_cursor *prc, fixed y));
+
+/*
+ * The path state flags reflect the most recent operation on the path
+ * as follows:
+ * Operation position_valid subpath_open is_drawing
+ * newpath no no no
+ * moveto yes yes no
+ * lineto/curveto yes yes yes
+ * closepath yes no no
+ * If position_valid is true, outside_range reflects whether the most
+ * recent operation went outside of the representable coordinate range.
+ * If this is the case, the corresponding member of position (x and/or y)
+ * is min_fixed or max_fixed, and outside_position is the true position.
+ */
+/*
+ */
+typedef enum {
+ /* Individual flags. These may be or'ed together, per above. */
+ psf_position_valid = 1,
+ psf_subpath_open = 2,
+ psf_is_drawing = 4,
+ psf_outside_range = 8,
+ /* Values stored by path building operations. */
+ psf_last_newpath = 0,
+ psf_last_moveto = psf_position_valid | psf_subpath_open,
+ psf_last_draw = psf_position_valid | psf_subpath_open | psf_is_drawing,
+ psf_last_closepath = psf_position_valid
+} gx_path_state_flags;
+/*
+ * Individual tests
+ */
+#define path_position_valid(ppath)\
+ (((ppath)->state_flags & psf_position_valid) != 0)
+#define path_subpath_open(ppath)\
+ (((ppath)->state_flags & psf_subpath_open) != 0)
+#define path_is_drawing(ppath)\
+ (((ppath)->state_flags & psf_is_drawing) != 0)
+#define path_outside_range(ppath)\
+ (((ppath)->state_flags & psf_outside_range) != 0)
+/*
+ * Composite tests
+ */
+#define path_last_is_moveto(ppath)\
+ (((ppath)->state_flags & ~psf_outside_range) == psf_last_moveto)
+#define path_position_in_range(ppath)\
+ (((ppath)->state_flags & (psf_position_valid + psf_outside_range)) ==\
+ psf_position_valid)
+#define path_start_outside_range(ppath)\
+ ((ppath)->state_flags != 0 &&\
+ ((ppath)->start_flags & psf_outside_range) != 0)
+/*
+ * Updating operations
+ */
+#define path_update_newpath(ppath)\
+ ((ppath)->state_flags = psf_last_newpath)
+#define path_update_moveto(ppath)\
+ ((ppath)->state_flags = (ppath)->start_flags = psf_last_moveto)
+#define path_update_draw(ppath)\
+ ((ppath)->state_flags = psf_last_draw)
+#define path_update_closepath(ppath)\
+ ((ppath)->state_flags = psf_last_closepath)
+#define path_set_outside_position(ppath, px, py)\
+ ((ppath)->outside_position.x = (px),\
+ (ppath)->outside_position.y = (py),\
+ (ppath)->state_flags |= psf_outside_range)
+
+/* Here is the actual structure of a path. */
+struct gx_path_s {
+ gs_memory_t *memory;
+ gs_fixed_rect bbox; /* bounding box (in device space) */
+ segment *box_last; /* bbox incorporates segments */
+ /* up to & including this one */
+ subpath *first_subpath;
+ subpath *current_subpath;
+ int subpath_count;
+ int curve_count;
+ gs_fixed_point position; /* current position */
+ gs_point outside_position; /* position if outside_range is set */
+ gs_point outside_start; /* outside_position of last moveto */
+ byte/*gx_path_state_flags*/ start_flags; /* flags of moveto */
+ byte/*gx_path_state_flags*/ state_flags; /* (see above) */
+ byte/*bool*/ bbox_set; /* true if setbbox is in effect */
+ byte/*bool*/ shares_segments; /* if true, this path shares its */
+ /* segment storage with the one in */
+ /* the previous saved graphics state */
+};
+extern_st(st_path);
+#define public_st_path() /* in gxpath.c */\
+ gs_public_st_ptrs3(st_path, gx_path, "path",\
+ path_enum_ptrs, path_reloc_ptrs, box_last, first_subpath, current_subpath)
+#define st_path_max_ptrs 3
+
+/* Path enumeration structure */
+struct gs_path_enum_s {
+ const segment *pseg;
+ const gs_state *pgs;
+ const gx_path *path; /* path being enumerated */
+ gx_path *copied_path; /* if the path was copied, this is the */
+ /* the same as path, to be released */
+ /* when done enumerating */
+ bool moveto_done; /* have we reported a final moveto yet? */
+ segment_notes notes; /* notes from most recent segment */
+};
+#define private_st_path_enum() /* in gxpath2.c */\
+ gs_private_st_ptrs4(st_gs_path_enum, gs_path_enum, "gs_path_enum",\
+ path_enum_enum_ptrs, path_enum_reloc_ptrs, pseg, pgs, path, copied_path)
+
+/* Macros equivalent to a few heavily used procedures. */
+/* Be aware that these macros may evaluate arguments more than once. */
+#define gx_path_current_point_inline(ppath,ppt)\
+ ( !path_position_valid(ppath) ? gs_note_error(gs_error_nocurrentpoint) :\
+ ((ppt)->x = ppath->position.x, (ppt)->y = ppath->position.y, 0) )
+/* ...rel_point rather than ...relative_point is because */
+/* some compilers dislike identifiers of >31 characters. */
+#define gx_path_add_rel_point_inline(ppath,dx,dy)\
+ ( !path_position_in_range(ppath) || ppath->bbox_set ?\
+ gx_path_add_relative_point(ppath, dx, dy) :\
+ (ppath->position.x += dx, ppath->position.y += dy,\
+ path_update_moveto(ppath), 0) )
diff --git a/gs/src/gzstate.h b/gs/src/gzstate.h
new file mode 100644
index 000000000..f7005ec5f
--- /dev/null
+++ b/gs/src/gzstate.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gzstate.h */
+/* Private graphics state definition for Ghostscript library */
+#include "gscpm.h"
+#ifdef DPNEXT
+#include "gsrefct.h"
+#endif
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gsstate.h"
+#include "gxstate.h"
+
+/* Opaque types referenced by the graphics state. */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+#endif
+
+/*
+ * We allocate a subset of the graphics state as a single object.
+ * Its type is opaque here, defined in gsstate.c.
+ * The components marked with @ must be allocated in the contents.
+ * (Consult gsstate.c for more details about gstate storage management.)
+ */
+typedef struct gs_state_contents_s gs_state_contents;
+
+/* Graphics state structure. */
+
+#ifdef DPNEXT
+typedef struct gx_clip_state_s {
+ rc_header rc;
+ struct gx_clip_path_s *path;
+} gx_clip_state;
+#define private_st_gx_clip_state() /* in gsstate.c */\
+ gs_private_st_ptrs1(st_gx_clip_state, gx_clip_state, "gx_clip_state",\
+ clip_state_enum_ptrs, clip_state_reloc_ptrs, path)
+#endif
+
+struct gs_state_s {
+ gs_imager_state_common; /* imager state, must be first */
+ gs_state *saved; /* previous state from gsave */
+ gs_state_contents *contents;
+
+ /* Transformation: */
+
+ gs_matrix ctm_inverse;
+ bool ctm_inverse_valid; /* true if ctm_inverse = ctm^-1 */
+ gs_matrix ctm_default;
+ bool ctm_default_set; /* if true, use ctm_default; */
+ /* if false, ask device */
+
+ /* Paths: */
+
+ struct gx_path_s *path;
+ struct gx_clip_path_s *clip_path; /* @ */
+#ifdef DPNEXT
+ gx_clip_state *view_clip;
+ struct gx_clip_path_s *saved_view_clip; /* for save/restore only */
+#endif
+ bool clamp_coordinates; /* if true, clamp out-of-range */
+ /* coordinates; if false, */
+ /* report a limitcheck */
+
+ /* Color (device-independent): */
+
+ struct gs_color_space_s *color_space;
+ struct gs_client_color_s *ccolor;
+
+ /* Color caches: */
+
+ gx_device_color *dev_color;
+
+ /* Font: */
+
+ gs_font *font;
+ gs_font *root_font;
+ gs_matrix_fixed char_tm; /* font matrix * ctm */
+#define char_tm_only(pgs) *(gs_matrix *)&(pgs)->char_tm
+ bool char_tm_valid; /* true if char_tm is valid */
+ byte in_cachedevice; /* 0 if not in setcachedevice, */
+ /* 1 if in setcachedevice but not */
+ /* actually caching, */
+ /* 2 if in setcachedevice and */
+ /* actually caching */
+ gs_char_path_mode in_charpath; /* (see gscpm.h) */
+ gs_state *show_gstate; /* gstate when show was invoked */
+ /* (so charpath can append to path) */
+
+ /* Other stuff: */
+
+ int level; /* incremented by 1 per gsave */
+ gx_device *device;
+#undef gs_currentdevice_inline
+#define gs_currentdevice_inline(pgs) ((pgs)->device)
+
+ /* Client data: */
+
+ void *client_data;
+#define gs_state_client_data(pgs) ((pgs)->client_data)
+ gs_state_client_procs client_procs;
+};
+#define private_st_gs_state() /* in gsstate.c */\
+ gs_private_st_composite(st_gs_state, gs_state, "gs_state",\
+ gs_state_enum_ptrs, gs_state_reloc_ptrs)
diff --git a/gs/src/ialloc.c b/gs/src/ialloc.c
new file mode 100644
index 000000000..278b0058d
--- /dev/null
+++ b/gs/src/ialloc.c
@@ -0,0 +1,259 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ialloc.c */
+/* Memory allocator for Ghostscript interpreter */
+#include "gx.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsstruct.h"
+#include "gxarith.h" /* for small_exact_log2 */
+#include "iref.h" /* must precede iastate.h */
+#include "iastate.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/*
+ * Define global and local instances.
+ */
+gs_dual_memory_t gs_imemory;
+
+/* Imported from gsalloc.c */
+gs_ref_memory_t *ialloc_alloc_state(P2(gs_memory_t *, uint));
+
+#define imem ((gs_ref_memory_t *)mem)
+
+/* Initialize the allocator */
+void
+ialloc_init(gs_memory_t *mem, uint chunk_size, bool level2)
+{ gs_ref_memory_t *ilmem = ialloc_alloc_state(mem, chunk_size);
+ gs_ref_memory_t *igmem =
+ (level2 ?
+ ialloc_alloc_state(mem, chunk_size) :
+ ilmem);
+ gs_ref_memory_t *ismem = ialloc_alloc_state(mem, chunk_size);
+ int i;
+
+ for ( i = 0; i < countof(gs_imemory.spaces.indexed); i++ )
+ gs_imemory.spaces.indexed[i] = 0;
+ gs_imemory.space_local = ilmem;
+ gs_imemory.space_global = igmem;
+ gs_imemory.space_system = ismem;
+ gs_imemory.reclaim = 0;
+ /* Level 1 systems have only local VM. */
+ igmem->space = avm_global;
+ ilmem->space = avm_local; /* overrides if ilmem == igmem */
+ igmem->global = ilmem->global = igmem;
+ ismem->space = avm_system;
+ ialloc_set_space(&gs_imemory, avm_global);
+}
+
+/* ================ Local/global VM ================ */
+
+/* Get the space attribute of an allocator */
+uint
+imemory_space(gs_ref_memory_t *iimem)
+{ return iimem->space;
+}
+
+/* Select the allocation space. */
+void
+ialloc_set_space(gs_dual_memory_t *dmem, uint space)
+{ gs_ref_memory_t *mem = dmem->spaces.indexed[space >> r_space_shift];
+ dmem->current = mem;
+ dmem->current_space = mem->space;
+}
+
+/* Reset the requests. */
+void
+ialloc_reset_requested(gs_dual_memory_t *dmem)
+{ dmem->space_system->gc_status.requested = 0;
+ dmem->space_global->gc_status.requested = 0;
+ dmem->space_local->gc_status.requested = 0;
+}
+
+/* ================ Refs ================ */
+
+/*
+ * As noted in iastate.h, every run of refs has an extra ref at the end
+ * to hold relocation information for the garbage collector;
+ * since sizeof(ref) % obj_align_mod == 0, we never need to
+ * allocate any additional padding space at the end of the block.
+ */
+
+/* Allocate an array of refs. */
+int
+gs_alloc_ref_array(gs_ref_memory_t *mem, ref *parr, uint attrs,
+ uint num_refs, client_name_t cname)
+{ ref *obj;
+ /* If we're allocating a run of refs already, */
+ /* and we aren't about to overflow the maximum run length, use it. */
+ if ( mem->cc.rtop == mem->cc.cbot &&
+ num_refs < (mem->cc.ctop - mem->cc.cbot) / sizeof(ref) &&
+ mem->cc.rtop - (byte *)mem->cc.rcur + num_refs * sizeof(ref) <
+ max_size_st_refs
+ )
+ { obj = (ref *)mem->cc.rtop - 1; /* back up over last ref */
+ if_debug4('A', "[a%d:+$ ]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), num_refs, (ulong)obj);
+ mem->cc.rcur[-1].o_size += num_refs * sizeof(ref);
+ { ref *end = (ref *)(mem->cc.rtop = mem->cc.cbot +=
+ num_refs * sizeof(ref));
+ make_mark(end - 1);
+ }
+ }
+ else
+ { /*
+ * Allocate a new run. We have to distinguish 3 cases:
+ * - Same chunk: pcc unchanged, end == cc.cbot.
+ * - Large chunk: pcc unchanged, end != cc.cbot.
+ * - New chunk: pcc changed.
+ */
+ chunk_t *pcc = mem->pcc;
+ ref *end;
+ obj = gs_alloc_struct_array((gs_memory_t *)mem, num_refs + 1,
+ ref, &st_refs, cname);
+ if ( obj == 0 )
+ return_error(e_VMerror);
+ /* Set the terminating ref now. */
+ end = (ref *)obj + num_refs;
+ make_mark(end);
+ /* Set has_refs in the chunk. */
+ if ( mem->pcc != pcc || mem->cc.cbot == (byte *)(end + 1) )
+ { /* Ordinary chunk. */
+ mem->cc.rcur = (obj_header_t *)obj;
+ mem->cc.rtop = (byte *)(end + 1);
+ mem->cc.has_refs = true;
+ }
+ else
+ { /* Large chunk. */
+ /* This happens only for very large arrays, */
+ /* so it doesn't need to be cheap. */
+ chunk_locator_t cl;
+ cl.memory = mem;
+ cl.cp = mem->clast;
+ chunk_locate_ptr(obj, &cl);
+ cl.cp->has_refs = true;
+ }
+ }
+ make_array(parr, attrs | mem->space, num_refs, obj);
+ return 0;
+}
+
+/* Resize an array of refs. Currently this is only implemented */
+/* for shrinking, not for growing. */
+int
+gs_resize_ref_array(gs_ref_memory_t *mem, ref *parr,
+ uint new_num_refs, client_name_t cname)
+{ uint old_num_refs = r_size(parr);
+ uint diff;
+ ref *obj = parr->value.refs;
+ if ( new_num_refs > old_num_refs || !r_has_type(parr, t_array) )
+ return_error(e_Fatal);
+ diff = old_num_refs - new_num_refs;
+ /* Check for LIFO. See gs_free_ref_array for more details. */
+ if ( mem->cc.rtop == mem->cc.cbot &&
+ (byte *)(obj + (old_num_refs + 1)) == mem->cc.rtop
+ )
+ { /* Shorten the refs object. */
+ ref *end = (ref *)(mem->cc.cbot = mem->cc.rtop -=
+ diff * sizeof(ref));
+ if_debug4('A', "[a%d:<$ ]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), diff, (ulong)obj);
+ mem->cc.rcur[-1].o_size -= diff * sizeof(ref);
+ make_mark(end - 1);
+ }
+ else
+ { /* Punt. */
+ if_debug4('A', "[a%d:<$#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), diff, (ulong)obj);
+ imem->lost.refs += diff * sizeof(ref);
+ }
+ r_set_size(parr, new_num_refs);
+ return 0;
+}
+
+/* Deallocate an array of refs. Only do this if LIFO, or if */
+/* the array occupies an entire chunk by itself. */
+void
+gs_free_ref_array(gs_ref_memory_t *mem, ref *parr, client_name_t cname)
+{ uint num_refs = r_size(parr);
+ ref *obj = parr->value.refs;
+ /*
+ * Compute the storage size of the array, and check for LIFO
+ * freeing or a separate chunk. Note that the array might be packed;
+ * for the moment, if it's anything but a t_array, punt.
+ * The +1s are for the extra ref for the GC.
+ */
+ if ( !r_has_type(parr, t_array) )
+ ; /* don't look for special cases */
+ else if ( mem->cc.rtop == mem->cc.cbot &&
+ (byte *)(obj + (num_refs + 1)) == mem->cc.rtop
+ )
+ { if ( (obj_header_t *)obj == mem->cc.rcur )
+ { /* Deallocate the entire refs object. */
+ gs_free_object((gs_memory_t *)mem, obj, cname);
+ mem->cc.rcur = 0;
+ mem->cc.rtop = 0;
+ }
+ else
+ { /* Deallocate it at the end of the refs object. */
+ if_debug4('A', "[a%d:-$ ]%s(%u) 0x%lx\n",
+ imem->space, client_name_string(cname),
+ num_refs, (ulong)obj);
+ mem->cc.rcur[-1].o_size -= num_refs * sizeof(ref);
+ mem->cc.rtop = mem->cc.cbot = (byte *)(obj + 1);
+ make_mark(obj);
+ }
+ return;
+ }
+ else if ( num_refs >= (mem->large_size / arch_sizeof_ref - 1) )
+ { /* See if this array has a chunk all to itself. */
+ /* We only make this check when freeing very large objects, */
+ /* so it doesn't need to be cheap. */
+ chunk_locator_t cl;
+ cl.memory = imem;
+ cl.cp = imem->clast;
+ if ( chunk_locate_ptr(obj, &cl) &&
+ obj == (ref *)((obj_header_t *)(cl.cp->cbase) + 1) &&
+ (byte *)(obj + (num_refs + 1)) == cl.cp->cend
+ )
+ { /* Free the chunk. */
+ if_debug4('a', "[a%d:-$L]%s(%u) 0x%lx\n",
+ imem->space, client_name_string(cname),
+ num_refs, (ulong)obj);
+ alloc_free_chunk(cl.cp, imem);
+ return;
+ }
+ }
+ /* Punt. */
+ if_debug4('A', "[a%d:-$#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), num_refs, (ulong)obj);
+ imem->lost.refs += num_refs * sizeof(ref);
+}
+
+/* Allocate a string ref. */
+int
+gs_alloc_string_ref(gs_ref_memory_t *mem, ref *psref,
+ uint attrs, uint nbytes, client_name_t cname)
+{ byte *str = gs_alloc_string((gs_memory_t *)mem, nbytes, cname);
+ if ( str == 0 )
+ return_error(e_VMerror);
+ make_string(psref, attrs | mem->space, nbytes, str);
+ return 0;
+}
diff --git a/gs/src/ialloc.h b/gs/src/ialloc.h
new file mode 100644
index 000000000..6d4ff3631
--- /dev/null
+++ b/gs/src/ialloc.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ialloc.h */
+/* Interface to Ghostscript interpreter memory allocator */
+
+#ifndef ialloc_INCLUDED
+# define ialloc_INCLUDED
+
+#include "imemory.h"
+
+/*
+ * Define the interpreter memory manager instance.
+ */
+extern gs_dual_memory_t gs_imemory;
+#define idmemory (&gs_imemory)
+#define iimemory (gs_imemory.current)
+#define imemory ((gs_memory_t *)iimemory)
+#define iimemory_local (gs_imemory.space_local)
+#define imemory_local ((gs_memory_t *)iimemory_local)
+#define iimemory_global (gs_imemory.space_global)
+#define imemory_global ((gs_memory_t *)iimemory_global)
+#define iimemory_system (gs_imemory.space_system)
+#define imemory_system ((gs_memory_t *)iimemory_system)
+
+/*
+ * Aliases for invoking the standard allocator interface.
+ */
+#define ialloc_bytes(nbytes, cname)\
+ gs_alloc_bytes(imemory, nbytes, cname)
+#define ialloc_struct(typ, pstype, cname)\
+ gs_alloc_struct(imemory, typ, pstype, cname)
+#define ialloc_byte_array(nelts, esize, cname)\
+ gs_alloc_byte_array(imemory, nelts, esize, cname)
+#define ialloc_struct_array(nelts, typ, pstype, cname)\
+ gs_alloc_struct_array(imemory, nelts, typ, pstype, cname)
+#define ifree_object(data, cname)\
+ gs_free_object(imemory, data, cname)
+#define ialloc_string(nbytes, cname)\
+ gs_alloc_string(imemory, nbytes, cname)
+#define ifree_string(data, nbytes, cname)\
+ gs_free_string(imemory, data, nbytes, cname)
+
+/* Initialize the interpreter's allocator. */
+void ialloc_init(P3(gs_memory_t *, uint, bool));
+
+/* Resize a string. */
+#define iresize_string(data, oldn, newn, cname)\
+ gs_resize_string(imemory, data, oldn, newn, cname)
+
+/* ------ Internal routines ------ */
+
+/* Reset the request values that identify the cause of a GC. */
+void ialloc_reset_requested(P1(gs_dual_memory_t *));
+
+/* Validate the contents of memory. */
+void ialloc_validate_spaces(P1(const gs_dual_memory_t *));
+#define ivalidate_spaces() ialloc_validate_spaces(idmemory)
+
+/*
+ * Local/global VM management.
+ */
+
+/* Get the space attribute of the current allocator. */
+#define ialloc_space(dmem) ((dmem)->current_space)
+#define icurrent_space ialloc_space(idmemory)
+extern uint imemory_space(P1(gs_ref_memory_t *));
+
+/* Select the allocation space. */
+void ialloc_set_space(P2(gs_dual_memory_t *, uint));
+
+/*
+ * Ref-related facilities.
+ */
+
+#ifdef r_type /* i.e., we know about refs */
+
+/* Allocate and free ref arrays. */
+#define ialloc_ref_array(paref, attrs, nrefs, cname)\
+ gs_alloc_ref_array(iimemory, paref, attrs, nrefs, cname)
+#define iresize_ref_array(paref, nrefs, cname)\
+ gs_resize_ref_array(iimemory, paref, nrefs, cname)
+#define ifree_ref_array(paref, cname)\
+ gs_free_ref_array(iimemory, paref, cname)
+
+/* Allocate a string ref. */
+#define ialloc_string_ref(psref, attrs, nbytes, cname)\
+ gs_alloc_string_ref(iimemory, psref, attrs, nbytes, cname)
+
+/* Make a ref for a newly allocated structure. */
+#define make_istruct(pref,attrs,ptr)\
+ make_struct(pref, (attrs) | icurrent_space, ptr)
+#define make_istruct_new(pref,attrs,ptr)\
+ make_struct_new(pref, (attrs) | icurrent_space, ptr)
+#define make_iastruct(pref,attrs,ptr)\
+ make_astruct(pref, (attrs) | icurrent_space, ptr)
+#define make_iastruct_new(pref,attrs,ptr)\
+ make_astruct_new(pref, (attrs) | icurrent_space, ptr)
+
+#endif /* ifdef r_type */
+
+#endif /* ialloc_INCLUDED */
diff --git a/gs/src/iastate.h b/gs/src/iastate.h
new file mode 100644
index 000000000..f6e0e85d0
--- /dev/null
+++ b/gs/src/iastate.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iastate.h */
+/* Interpreter memory manager internal definitions */
+/* Requires gsmemory.h, gsstruct.h */
+#include "gxalloc.h"
+#include "istruct.h"
+#include "ialloc.h"
diff --git a/gs/src/iastruct.h b/gs/src/iastruct.h
new file mode 100644
index 000000000..b5a0bc49d
--- /dev/null
+++ b/gs/src/iastruct.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iastruct.h */
+/* Interpreter memory manager implementation structures */
+#include "gxobj.h"
+#include "ialloc.h"
diff --git a/gs/src/ibnum.c b/gs/src/ibnum.c
new file mode 100644
index 000000000..a7d4cb5cc
--- /dev/null
+++ b/gs/src/ibnum.c
@@ -0,0 +1,208 @@
+/* Copyright (C) 1990, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ibnum.c */
+/* Level 2 encoded number reading utilities for Ghostscript */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "imemory.h" /* for iutil.h */
+#include "iutil.h"
+
+/* Define the number of bytes for a given format of encoded number. */
+const byte enc_num_bytes[] = { enc_num_bytes_values };
+
+/* ------ Encoded number reading ------ */
+
+/* Set up to read from an encoded number array/string. */
+/* Return <0 for error, or a number format. */
+int
+num_array_format(const ref *op)
+{ switch ( r_type(op) )
+ {
+ case t_string:
+ { /* Check that this is a legitimate encoded number string. */
+ const byte *bp = op->value.bytes;
+ int format = bp[1];
+
+ if ( r_size(op) < 4 || bp[0] != bt_num_array_value ||
+ !num_is_valid(format)
+ )
+ return_error(e_rangecheck);
+ if ( sdecodeshort(bp + 2, format) !=
+ (r_size(op) - 4) / encoded_number_bytes(format)
+ )
+ return_error(e_rangecheck);
+ return format;
+ }
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ return num_array;
+ default:
+ return_error(e_typecheck);
+ }
+}
+
+/* Get the number of elements in an encoded number array/string. */
+uint
+num_array_size(const ref *op, int format)
+{ return (format == num_array ? r_size(op) :
+ (r_size(op) - 4) / encoded_number_bytes(format));
+}
+
+/* Get an encoded number from an array/string according to the given format. */
+/* Put the value in np->value.{intval,realval}. */
+/* Return t_int if integer, t_real if real, t_null if end of stream, */
+/* or an error if the format is invalid. */
+int
+num_array_get(const ref *op, int format, uint index, ref *np)
+{ if ( format == num_array )
+ { int code = array_get(op, (long)index, np);
+ if ( code < 0 )
+ return t_null;
+ switch ( r_type(np) )
+ {
+ case t_integer:
+ return t_integer;
+ case t_real:
+ return t_real;
+ default:
+ return_error(e_rangecheck);
+ }
+ }
+ else
+ { uint nbytes = encoded_number_bytes(format);
+ if ( index >= (r_size(op) - 4) / nbytes )
+ return t_null;
+ return sdecode_number(op->value.bytes + 4 + index * nbytes,
+ format, np);
+ }
+}
+
+/* Internal routine to decode a number in a given format. */
+/* Same returns as sget_encoded_number. */
+static const double binary_scale[32] = {
+#define expn2(n) (0.5 / (1L << (n-1)))
+ 1.0, expn2(1), expn2(2), expn2(3),
+ expn2(4), expn2(5), expn2(6), expn2(7),
+ expn2(8), expn2(9), expn2(10), expn2(11),
+ expn2(12), expn2(13), expn2(14), expn2(15),
+ expn2(16), expn2(17), expn2(18), expn2(19),
+ expn2(20), expn2(21), expn2(22), expn2(23),
+ expn2(24), expn2(25), expn2(26), expn2(27),
+ expn2(28), expn2(29), expn2(30), expn2(31)
+#undef expn2
+};
+int
+sdecode_number(const byte *str, int format, ref *np)
+{ switch ( format & 0x170 )
+ {
+ case num_int32: case num_int32 + 16:
+ if ( (format & 31) == 0 )
+ { np->value.intval = sdecodelong(str, format);
+ return t_integer;
+ }
+ else
+ { np->value.realval =
+ (double)sdecodelong(str, format) *
+ binary_scale[format & 31];
+ return t_real;
+ }
+ case num_int16:
+ if ( (format & 15) == 0 )
+ { np->value.intval = sdecodeshort(str, format);
+ return t_integer;
+ }
+ else
+ { np->value.realval =
+ sdecodeshort(str, format) *
+ binary_scale[format & 15];
+ return t_real;
+ }
+ case num_float:
+ np->value.realval = sdecodefloat(str, format);
+ return t_real;
+ default:
+ return_error(e_syntaxerror); /* invalid format?? */
+ }
+}
+
+/* ------ Decode number ------ */
+
+/* Decode encoded numbers from a string according to format. */
+
+/* Decode a (16-bit, signed) short. */
+short
+sdecodeshort(register const byte *p, int format)
+{ int a = p[0], b = p[1];
+ short v = (num_is_lsb(format) ? (b << 8) + a : (a << 8) + b);
+#if arch_sizeof_short == 2
+ return v;
+#else
+ /* Sign-extend if sizeof(short) > 2. */
+ return (v & 0x7fff) - (v & 0x8000);
+#endif
+}
+
+/* Decode a (32-bit, signed) long. */
+long
+sdecodelong(register const byte *p, int format)
+{ int a = p[0], b = p[1], c = p[2], d = p[3];
+ long v = (num_is_lsb(format) ?
+ ((long)d << 24) + ((long)c << 16) + (b << 8) + a :
+ ((long)a << 24) + ((long)b << 16) + (c << 8) + d);
+#if arch_sizeof_long == 4
+ return v;
+#else
+ /* Sign-extend if sizeof(long) > 4. */
+ return (v & 0x7fffffffL) - (v & 0x80000000L);
+#endif
+}
+
+/* Decode a float. We don't handle non-IEEE native representations yet. */
+float
+sdecodefloat(register const byte *p, int format)
+{ float fnum;
+ if ( format != num_float_native )
+ { bits32 lnum = (bits32)sdecodelong(p, format);
+ /* We know IEEE floats take 32 bits. */
+#if !arch_floats_are_IEEE
+ /* Convert IEEE float to native float. */
+ int sign_expt = lnum >> 23;
+ int expt = sign_expt & 0xff;
+ long mant = lnum & 0x7fffff;
+ if ( expt == 0 && mant == 0 )
+ fnum = 0;
+ else
+ { mant += 0x800000;
+ fnum = (float)ldexp((float)mant, expt - 127 - 24);
+ }
+ if ( sign_expt & 0x100 )
+ fnum = -fnum;
+#else
+ fnum = *(float *)&lnum;
+#endif
+ }
+ else
+ memcpy(&fnum, p, sizeof(float));
+ return fnum;
+}
diff --git a/gs/src/ibnum.h b/gs/src/ibnum.h
new file mode 100644
index 000000000..ac46e7833
--- /dev/null
+++ b/gs/src/ibnum.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1990, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ibnum.h */
+/* Interface to Level 2 number readers */
+/* Requires stream.h */
+
+/* Define the byte that begins an encoded number string. */
+/* (This is the same as the value of bt_num_array in btoken.h.) */
+#define bt_num_array_value 149
+
+/* Homogenous number array formats. */
+/* The default for numbers is big-endian. */
+#define num_int32 0 /* [0..31] */
+#define num_int16 32 /* [32..47] */
+#define num_float 48
+#define num_float_IEEE num_float
+#define num_float_native (num_float + 1)
+#define num_msb 0
+#define num_lsb 128
+#define num_is_lsb(format) ((format) >= num_lsb)
+#define num_is_valid(format) (((format) & 127) <= 49)
+/* Special "format" for reading from an array. */
+/* num_msb/lsb is not used in this case. */
+#define num_array 256
+/* Define the number of bytes for a given format of encoded number. */
+extern const byte enc_num_bytes[]; /* in ibnum.c */
+#define enc_num_bytes_values\
+ 4, 4, 2, 4, 0, 0, 0, 0,\
+ 4, 4, 2, 4, 0, 0, 0, 0,\
+ sizeof(ref)
+#define encoded_number_bytes(format)\
+ (enc_num_bytes[(format) >> 4])
+
+/* Read from an array or encoded number string. */
+int num_array_format(P1(const ref *)); /* returns format or error */
+uint num_array_size(P2(const ref *, int));
+int num_array_get(P4(const ref *, int, uint, ref *));
+
+/* Decode a number from a string with appropriate byte swapping. */
+int sdecode_number(P3(const byte *, int, ref *));
+short sdecodeshort(P2(const byte *, int));
+long sdecodelong(P2(const byte *, int));
+float sdecodefloat(P2(const byte *, int));
diff --git a/gs/src/iccfont.c b/gs/src/iccfont.c
new file mode 100644
index 000000000..8e7c95f16
--- /dev/null
+++ b/gs/src/iccfont.c
@@ -0,0 +1,313 @@
+/* Copyright (C) 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iccfont.c */
+/* Initialization support for compiled fonts */
+#include "string_.h"
+#include "ghost.h"
+#include "gsstruct.h" /* for iscan.h */
+#include "ccfont.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "ifont.h"
+#include "iname.h"
+#include "isave.h" /* for ialloc_ref_array */
+#include "iutil.h"
+#include "oper.h"
+#include "ostack.h" /* for iscan.h */
+#include "store.h"
+#include "stream.h" /* for iscan.h */
+#include "strimpl.h" /* for sfilter.h for picky compilers */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+
+/* ------ Private code ------ */
+
+/* Forward references */
+private int huge cfont_ref_from_string(P3(ref *, const char *, uint));
+
+typedef struct {
+ const char *str_array;
+ ref next;
+} str_enum;
+#define init_str_enum(sep, ksa)\
+ (sep)->str_array = ksa
+typedef struct {
+ cfont_dict_keys keys;
+ str_enum strings;
+} key_enum;
+#define init_key_enum(kep, kp, ksa)\
+ (kep)->keys = *kp, init_str_enum(&(kep)->strings, ksa)
+
+/* Check for reaching the end of the keys. */
+#define more_keys(kep) ((kep)->keys.num_enc_keys | (kep)->keys.num_str_keys)
+
+/* Get the next string from a string array. */
+/* Return 1 if it was a string, 0 if it was something else, */
+/* or an error code. */
+private int near
+cfont_next_string(str_enum _ss *pse)
+{ const byte *str = pse->str_array;
+ uint len = (str[0] << 8) + str[1];
+
+ if ( len == 0xffff )
+ { make_null(&pse->next);
+ pse->str_array = str + 2;
+ return 0;
+ }
+ else if ( len >= 0xff00 )
+ { int code;
+ len = ((len & 0xff) << 8) + str[2];
+ code = cfont_ref_from_string(&pse->next,
+ (const char *)str + 3, len);
+ if ( code < 0 )
+ return code;
+ pse->str_array = str + 3 + len;
+ return 0;
+ }
+ make_const_string(&pse->next, avm_foreign, len, str + 2);
+ pse->str_array = str + 2 + len;
+ return 1;
+}
+
+/* Put the next entry into a dictionary. */
+/* We know that more_keys(kp) is true. */
+private int near
+cfont_put_next(ref *pdict, key_enum _ss *kep, const ref *pvalue)
+{ ref kname;
+ int code;
+
+#define kp (&kep->keys)
+ if ( pdict->value.pdict == 0 )
+ { /* First time, create the dictionary. */
+ code = dict_create(kp->num_enc_keys + kp->num_str_keys + kp->extra_slots, pdict);
+ if ( code < 0 )
+ return code;
+ }
+ if ( kp->num_enc_keys )
+ { const charindex *skp = kp->enc_keys++;
+ code = array_get(&registered_Encoding(skp->encx), (long)(skp->charx), &kname);
+ kp->num_enc_keys--;
+ }
+ else /* must have kp->num_str_keys != 0 */
+ { code = cfont_next_string(&kep->strings);
+ if ( code != 1 )
+ return (code < 0 ? code : gs_note_error(e_Fatal));
+ code = name_ref(kep->strings.next.value.const_bytes,
+ r_size(&kep->strings.next), &kname, 0);
+ kp->num_str_keys--;
+ }
+ if ( code < 0 )
+ return code;
+ return dict_put(pdict, &kname, pvalue);
+#undef kp
+}
+
+/* ------ Routines called from compiled font initialization ------ */
+
+/* Create a dictionary with general ref values. */
+private int huge
+cfont_ref_dict_create(ref *pdict, const cfont_dict_keys *kp,
+ cfont_string_array ksa, const ref *values)
+{ key_enum kenum;
+ const ref *vp = values;
+ init_key_enum(&kenum, kp, ksa);
+ pdict->value.pdict = 0;
+ while ( more_keys(&kenum) )
+ { const ref *pvalue = vp++;
+ int code = cfont_put_next(pdict, &kenum, pvalue);
+ if ( code < 0 ) return code;
+ }
+ return 0;
+}
+
+/* Create a dictionary with string/null values. */
+private int huge
+cfont_string_dict_create(ref *pdict, const cfont_dict_keys *kp,
+ cfont_string_array ksa, cfont_string_array kva)
+{ key_enum kenum;
+ str_enum senum;
+ uint attrs = kp->value_attrs;
+ init_key_enum(&kenum, kp, ksa);
+ init_str_enum(&senum, kva);
+ pdict->value.pdict = 0;
+ while ( more_keys(&kenum) )
+ { int code = cfont_next_string(&senum);
+ switch ( code )
+ {
+ default: /* error */
+ return code;
+ case 1: /* string */
+ r_set_attrs(&senum.next, attrs);
+ case 0: /* other */
+ ;
+ }
+ code = cfont_put_next(pdict, &kenum, &senum.next);
+ if ( code < 0 ) return code;
+ }
+ return 0;
+}
+
+/* Create a dictionary with number values. */
+private int huge
+cfont_num_dict_create(ref *pdict, const cfont_dict_keys *kp,
+ cfont_string_array ksa, const ref *values, const char *lengths)
+{ key_enum kenum;
+ const ref *vp = values;
+ const char *lp = lengths;
+ ref vnum;
+
+ init_key_enum(&kenum, kp, ksa);
+ pdict->value.pdict = 0;
+ while ( more_keys(&kenum) )
+ { int len = (lp == 0 ? 0 : *lp++);
+ int code;
+
+ if ( len == 0 )
+ vnum = *vp++;
+ else
+ { --len;
+ make_const_array(&vnum, avm_foreign | a_readonly, len, vp);
+ vp += len;
+ }
+ code = cfont_put_next(pdict, &kenum, &vnum);
+ if ( code < 0 ) return code;
+ }
+ return 0;
+}
+
+/* Create an array with name values. */
+private int huge
+cfont_name_array_create(ref *parray, cfont_string_array ksa, int size)
+{ int code = ialloc_ref_array(parray, a_readonly, size,
+ "cfont_name_array_create");
+ ref *aptr = parray->value.refs;
+ int i;
+ str_enum senum;
+
+ if ( code < 0 ) return code;
+ init_str_enum(&senum, ksa);
+ for ( i = 0; i < size; i++, aptr++ )
+ { ref nref;
+ int code = cfont_next_string(&senum);
+ if ( code != 1 )
+ return (code < 0 ? code : gs_note_error(e_Fatal));
+ code = name_ref(senum.next.value.const_bytes,
+ r_size(&senum.next), &nref, 0);
+ if ( code < 0 )
+ return code;
+ ref_assign_new(aptr, &nref);
+ }
+ return 0;
+}
+
+/* Create an array with string/null values. */
+private int huge
+cfont_string_array_create(ref *parray, cfont_string_array ksa,
+ int size, uint attrs)
+{ int code = ialloc_ref_array(parray, a_readonly, size,
+ "cfont_string_array_create");
+ ref *aptr = parray->value.refs;
+ int i;
+ str_enum senum;
+
+ if ( code < 0 ) return code;
+ init_str_enum(&senum, ksa);
+ for ( i = 0; i < size; i++, aptr++ )
+ { int code = cfont_next_string(&senum);
+ switch ( code )
+ {
+ default: /* error */
+ return code;
+ case 1: /* string */
+ r_set_attrs(&senum.next, attrs);
+ case 0: /* other */
+ ;
+ }
+ ref_mark_new(&senum.next);
+ *aptr = senum.next;
+ }
+ return 0;
+}
+
+/* Create a name. */
+private int huge
+cfont_name_create(ref *pnref, const char *str)
+{ return name_ref((const byte *)str, strlen(str), pnref, 0);
+}
+
+/* Create an object by parsing a string. */
+private int huge
+cfont_ref_from_string(ref *pref, const char *str, uint len)
+{ scanner_state sstate;
+ stream s;
+ int code;
+
+ scanner_state_init(&sstate, false);
+ sread_string(&s, (const byte *)str, len);
+ code = scan_token(&s, pref, &sstate);
+ return (code <= 0 ? code : gs_note_error(e_Fatal));
+}
+
+/* ------ Initialization ------ */
+
+/* Procedure vector passed to font initialization procedures. */
+private const cfont_procs ccfont_procs = {
+ cfont_ref_dict_create,
+ cfont_string_dict_create,
+ cfont_num_dict_create,
+ cfont_name_array_create,
+ cfont_string_array_create,
+ cfont_name_create,
+ cfont_ref_from_string
+};
+
+/* null .getccfont <number-of-fonts> */
+/* <int> .getccfont <font-object> */
+private int
+zgetccfont(register os_ptr op)
+{
+ int code;
+ ccfont_fproc **fprocs;
+ int nfonts;
+ int index;
+
+ code = ccfont_fprocs (&nfonts, &fprocs);
+ if ( code != ccfont_version )
+ return_error(e_invalidfont);
+
+ if ( r_has_type(op, t_null) )
+ {
+ make_int(op, nfonts);
+ return 0;
+ }
+
+ check_type(*op, t_integer);
+ index = op->value.intval;
+ if ( index < 0 || index >= nfonts )
+ return_error(e_rangecheck);
+
+ return (*fprocs[index])(&ccfont_procs, op);
+}
+
+/* Operator table initialization */
+
+BEGIN_OP_DEFS(ccfonts_op_defs) {
+ {"0.getccfont", zgetccfont},
+END_OP_DEFS(0) }
diff --git a/gs/src/iccinit0.c b/gs/src/iccinit0.c
new file mode 100644
index 000000000..26425f1d1
--- /dev/null
+++ b/gs/src/iccinit0.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iccinit0.c */
+/* Initialization string for non-compiled initialization */
+#include "stdpre.h"
+
+/* gsmain.c recognizes an empty init string specially. */
+const byte gs_init_string[] = { 0 };
+const uint gs_init_string_sizeof = 0;
diff --git a/gs/src/icfontab.c b/gs/src/icfontab.c
new file mode 100644
index 000000000..952bbe75c
--- /dev/null
+++ b/gs/src/icfontab.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icfontab.c */
+/* Table of compiled fonts */
+#include "ccfont.h"
+
+/* This is compiled separately and linked with the fonts themselves, */
+/* in a shared library when applicable. */
+
+#undef font_
+#define font_(fname, fproc, zfproc) extern ccfont_fproc fproc;
+#ifndef GCONFIGF_H
+# include "gconfigf.h"
+#else
+# include GCONFIGF_H
+#endif
+
+private ccfont_fproc *fprocs[] = {
+#undef font_
+#define font_(fname, fproc, zfproc) &fproc, /* fname, zfproc are not needed */
+#ifndef GCONFIGF_H
+# include "gconfigf.h"
+#else
+# include GCONFIGF_H
+#endif
+ 0
+};
+
+int
+ccfont_fprocs(int *pnum_fprocs, ccfont_fproc ***pfprocs)
+{
+ *pnum_fprocs = countof(fprocs) - 1;
+ *pfprocs = &fprocs[0];
+ return ccfont_version; /* for compatibility checking */
+}
diff --git a/gs/src/ichar.h b/gs/src/ichar.h
new file mode 100644
index 000000000..2ca3f3d21
--- /dev/null
+++ b/gs/src/ichar.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ichar.h */
+/* Shared definitions for text operators */
+/* Requires gxchar.h */
+
+/*
+ * All the character rendering operators use the execution stack
+ * for loop control -- see estack.h for details.
+ * The information pushed by these operators is as follows:
+ * the enumerator (t_struct, a gs_show_enum);
+ * a slot for the procedure for kshow or cshow (probably t_array) or
+ * the string or array for [x][y]show (t_string or t_array);
+ * a slot for the string/array index for [x][y]show (t_integer);
+ * a slot for the saved o-stack depth for cshow or stringwidth,
+ * and for error recovery (t_integer);
+ * a slot for the saved d-stack depth ditto (t_integer);
+ * a slot for the saved gstate level ditto (t_integer);
+ * the procedure to be called at the end of the enumeration
+ * (t_operator, but called directly, not by the interpreter);
+ * the usual e-stack mark (t_null).
+ */
+#define snumpush 8
+#define esenum(ep) r_ptr(ep, gs_show_enum)
+#define senum esenum(esp)
+#define esslot(ep) ((ep)[-1])
+#define sslot esslot(esp)
+#define essindex(ep) ((ep)[-2])
+#define ssindex essindex(esp)
+#define esodepth(ep) ((ep)[-3])
+#define sodepth esodepth(esp)
+#define esddepth(ep) ((ep)[-4])
+#define sddepth esddepth(esp)
+#define esgslevel(ep) ((ep)[-5])
+#define sgslevel esgslevel(esp)
+#define eseproc(ep) ((ep)[-6])
+#define seproc eseproc(esp)
+
+/* Procedures exported by zchar.c for zchar1.c, zchar2.c, and/or zcharcid.c. */
+gs_show_enum *op_show_find(P0());
+int op_show_setup(P2(os_ptr, gs_show_enum **));
+int op_show_enum_setup(P2(os_ptr, gs_show_enum **));
+void op_show_finish_setup(P3(gs_show_enum *, int, op_proc_p));
+int op_show_continue(P1(os_ptr));
+int op_show_continue_dispatch(P2(os_ptr, int));
+int op_show_free(P1(int));
diff --git a/gs/src/icharout.h b/gs/src/icharout.h
new file mode 100644
index 000000000..8469c52bf
--- /dev/null
+++ b/gs/src/icharout.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icharout.h */
+/* Interface to zcharout.c */
+
+/* Execute an outline defined by a PostScript procedure. */
+int zchar_exec_char_proc(P1(os_ptr));
+
+/*
+ * Get the metrics for a character from the Metrics dictionary of a base
+ * font. If present, store the l.s.b. in psbw[0,1] and the width in
+ * psbw[2,3].
+ */
+typedef enum {
+ metricsNone = 0,
+ metricsWidthOnly = 1,
+ metricsSideBearingAndWidth = 2
+} metrics_present;
+int /*metrics_present*/
+ zchar_get_metrics(P3(const gs_font_base *pbfont, const ref *pcnref,
+ double psbw[4]));
+
+/*
+ * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return
+ * o_push_estack if we had to call a CDevProc, or if we are skipping the
+ * rendering process (only getting the metrics).
+ */
+int zchar_set_cache(P8(os_ptr op, const gs_font_base *pbfont,
+ const ref *pcnref, const double psb[2],
+ const double pwidth[2], const gs_rect *pbbox,
+ int (*cont_fill)(P1(os_ptr)),
+ int (*cont_stroke)(P1(os_ptr))));
diff --git a/gs/src/icie.h b/gs/src/icie.h
new file mode 100644
index 000000000..602764a58
--- /dev/null
+++ b/gs/src/icie.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icie.h */
+/* Internal definitions for interpreter CIE color handling */
+
+/*
+ * All of the routines below are exported by zcie.c for zcrd.c,
+ * except for cie_cache_joint which is exported by zcrd.c for zcie.c.
+ */
+
+/* ------ Parameter acquisition ------ */
+
+/* Get a range array parameter from a dictionary. */
+/* We know that count <= 4. */
+int dict_ranges_param(P4(const ref *pdref, const char _ds *kstr, int count,
+ gs_range *prange));
+
+/* Get 3 ranges from a dictionary. */
+#define dict_range3_param(pdref, kstr, prange3)\
+ dict_ranges_param(pdref, kstr, 3, (prange3)->ranges)
+
+/* Get a 3x3 matrix parameter from a dictionary. */
+#define dict_matrix3_param(op, kstr, pmat)\
+ dict_float_array_param(op, kstr, 9, (float *)pmat, (const float *)&Matrix3_default)
+#define matrix3_ok 9
+
+/* Get an array of procedures from a dictionary. */
+/* We know count <= countof(empty_procs). */
+int dict_proc_array_param(P4(const ref *pdict, const char _ds *kstr,
+ uint count, ref *pparray));
+
+/* Get 3 procedures from a dictionary. */
+#define dict_proc3_param(op, kstr, pparray)\
+ dict_proc_array_param(op, kstr, 3, pparray)
+
+/* Get WhitePoint and BlackPoint values. */
+int cie_points_param(P2(const ref *pdref, gs_cie_wb *pwb));
+
+/* Process a 3- or 4-dimensional lookup table from a dictionary. */
+/* The caller has set pclt->n and pclt->m. */
+/* ptref is known to be a readable array of size at least n+1. */
+int cie_table_param(P3(const ref *ptable, gx_color_lookup_table *pclt,
+ gs_memory_t *mem));
+
+/* ------ Internal routines ------ */
+
+int cie_cache_push_finish(P3(int (*)(P1(os_ptr)), gs_state *, void *));
+int cie_prepare_cache(P6(const gs_range *, const ref *,
+ cie_cache_floats *, void *, const gs_state *, client_name_t));
+int cie_prepare_caches_3(P8(const gs_range3 *, const ref *,
+ cie_cache_floats *, cie_cache_floats *, cie_cache_floats *,
+ void *, const gs_state *, client_name_t));
+#define cie_prepare_cache3(d3,p3,c3,pcie,pgs,cname)\
+ cie_prepare_caches_3(d3, p3, &(c3)->floats, &(c3)[1].floats, &(c3)[2].floats, pcie, pgs, cname)
+
+int cie_cache_joint(P2(const ref_cie_render_procs *, gs_state *));
diff --git a/gs/src/icolor.h b/gs/src/icolor.h
new file mode 100644
index 000000000..a9bd79cfe
--- /dev/null
+++ b/gs/src/icolor.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icolor.h */
+/* Declarations for transfer function & similar cache remapping */
+
+/* Define the number of stack slots needed for zcolor_remap_one. */
+/* The client is responsible for doing check_e/ostack or the equivalent */
+/* before calling zcolor_remap_one. */
+extern const int zcolor_remap_one_ostack;
+extern const int zcolor_remap_one_estack;
+
+/* Schedule the sampling and reloading of a cache. */
+int zcolor_remap_one(P5(const ref *, os_ptr, gx_transfer_map *,
+ const gs_state *, int (*)(P1(os_ptr))));
+
+/* Reload a cache with entries in [0..1] after sampling. */
+int zcolor_remap_one_finish(P1(os_ptr));
+
+/* Reload a cache with entries in [-1..1] after sampling. */
+int zcolor_remap_one_signed_finish(P1(os_ptr));
+
+/* Recompute the effective transfer functions and invalidate the current */
+/* color after cache reloading. */
+int zcolor_reset_transfer(P1(os_ptr));
+
+/* Invalidate the current color after cache reloading. */
+int zcolor_remap_color(P1(os_ptr));
diff --git a/gs/src/iconf.c b/gs/src/iconf.c
new file mode 100644
index 000000000..ec6d8ac27
--- /dev/null
+++ b/gs/src/iconf.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iconf.c */
+/* Configuration-dependent tables and initialization for interpreter */
+#include "stdio_.h" /* stdio for stream.h */
+#include "gsmemory.h" /* for gscdefs.h */
+#include "gscdefs.h"
+#include "gconfig.h"
+#include "iref.h"
+#include "ivmspace.h"
+#include "opdef.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "iminst.h"
+
+/* Define the default values for an interpreter instance. */
+const gs_main_instance gs_main_instance_init_values =
+ { gs_main_instance_default_init_values };
+
+/* Set up the .ps file name string array. */
+/* We fill in the lengths at initialization time. */
+#define ref_(t) struct { struct tas_s tas; t value; }
+#define string_(s)\
+ { { (t_string<<r_type_shift) + a_readonly + avm_foreign, 0 }, s },
+#define psfile_(fns) string_(fns)
+ref_(const char *) gs_init_file_array[] = {
+#include "gconfig.h"
+ string_(0)
+};
+#undef psfile_
+
+/* Set up the emulator name string array similarly. */
+#define emulator_(ems) string_(ems)
+ref_(const char *) gs_emulator_name_array[] = {
+#include "gconfig.h"
+ string_(0)
+};
+#undef emulator_
+
+/* Initialize the operators. */
+extern op_def_ptr
+ /* Initialization operators */
+#define oper_(defs) defs(P0()),
+#include "gconfig.h"
+#undef oper_
+ /* Interpreter operators */
+ interp_op_defs(P0());
+op_def_ptr (*(op_defs_all[]))(P0()) = {
+ /* Initialization operators */
+#define oper_(defs) defs,
+#include "gconfig.h"
+#undef oper_
+ /* Interpreter operators */
+ interp_op_defs,
+ /* end marker */
+ 0
+};
diff --git a/gs/src/icontext.c b/gs/src/icontext.c
new file mode 100644
index 000000000..97da9777d
--- /dev/null
+++ b/gs/src/icontext.c
@@ -0,0 +1,117 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icontext.c */
+/* Context state operations */
+#include "ghost.h"
+#include "gsstruct.h" /* for gxalloc.h */
+#include "gxalloc.h"
+#include "errors.h"
+#include "igstate.h"
+#include "icontext.h"
+#include "interp.h"
+#include "dstack.h"
+#include "estack.h"
+#include "ostack.h"
+#include "store.h"
+
+/* Define the initial stack sizes. */
+#define DSTACK_INITIAL 20
+#define ESTACK_INITIAL 250
+#define OSTACK_INITIAL 200
+
+/* Per-context state stored in statics */
+extern ref ref_array_packing;
+extern ref ref_binary_object_format;
+extern ref user_names;
+extern long zrand_state;
+
+/* Initialization procedures */
+void zrand_state_init(P1(long *));
+
+/* Allocate the state of a context. */
+/* The client is responsible for the 'memory' member. */
+int
+context_state_alloc(gs_context_state_t *pcst, gs_ref_memory_t *mem)
+{ int code = gs_interp_create_stacks(mem, &pcst->dstack, &pcst->estack,
+ &pcst->ostack);
+
+ if ( code < 0 )
+ return code;
+ pcst->pgs = int_gstate_alloc(mem);
+ if ( pcst->pgs == 0 )
+ return_error(e_VMerror);
+ make_false(&pcst->array_packing);
+ make_int(&pcst->binary_object_format, 0);
+ zrand_state_init(&pcst->rand_state);
+ pcst->usertime_total = 0;
+ pcst->keep_usertime = false;
+ /****** user parameters ******/
+ /****** %stdin, %stdout ******/
+ return 0;
+}
+
+/* Load the interpreter state from a context. */
+void
+context_state_load(const gs_context_state_t *pcst)
+{ d_stack = *r_ptr(&pcst->dstack, ref_stack);
+ e_stack = *r_ptr(&pcst->estack, ref_stack);
+ o_stack = *r_ptr(&pcst->ostack, ref_stack);
+ igs = pcst->pgs;
+ gs_imemory = pcst->memory;
+ ref_array_packing = pcst->array_packing;
+ ref_binary_object_format = pcst->binary_object_format;
+ zrand_state = pcst->rand_state;
+ /****** user parameters ******/
+ /****** %stdin, %stdout ******/
+}
+
+/* Store the interpreter state in a context. */
+void
+context_state_store(gs_context_state_t *pcst)
+{ *r_ptr(&pcst->dstack, ref_stack) = d_stack;
+ *r_ptr(&pcst->estack, ref_stack) = e_stack;
+ *r_ptr(&pcst->ostack, ref_stack) = o_stack;
+ pcst->pgs = igs;
+ pcst->memory = gs_imemory;
+ pcst->array_packing = ref_array_packing;
+ pcst->binary_object_format = ref_binary_object_format;
+ pcst->rand_state = zrand_state;
+ /****** user parameters ******/
+ /****** %stdin, %stdout ******/
+}
+
+/* Free the state of a context. */
+void
+context_state_free(gs_context_state_t *pcst, gs_ref_memory_t *mem)
+{ /****** SEE alloc ABOVE ******/
+ int i;
+
+ /*
+ * If this context is the last one referencing a particular VM
+ * (local, or local and global), free the entire VM space;
+ * otherwise, just free the context-related structures.
+ */
+ for ( i = countof(pcst->memory.spaces.indexed); --i >= 0; ) {
+ if ( pcst->memory.spaces.indexed[i] != 0 &&
+ !--(pcst->memory.spaces.indexed[i]->num_contexts)
+ ) {
+ /****** FREE THE ENTIRE SPACE ******/
+ }
+ }
+}
diff --git a/gs/src/icontext.h b/gs/src/icontext.h
new file mode 100644
index 000000000..57009761b
--- /dev/null
+++ b/gs/src/icontext.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icontext.h */
+/* Externally visible context state */
+/* Requires iref.h */
+
+#ifndef icontext_INCLUDED
+# define icontext_INCLUDED
+
+#include "imemory.h"
+#include "istack.h"
+
+/*
+ * Define the externally visible state of an interpreter context.
+ * If we aren't supporting Display PostScript features, there is only
+ * a single context.
+ */
+typedef struct gs_context_state_s {
+ /* These refs are t_struct pointing to ref_stack structures. */
+ ref dstack, estack, ostack;
+ gs_state *pgs;
+ gs_dual_memory_t memory;
+ ref array_packing; /* t_boolean */
+ ref binary_object_format; /* t_integer */
+ long rand_state; /* (not in Red Book) */
+ long usertime_total; /* total accumulated usertime, */
+ /* not counting current time if running */
+ bool keep_usertime; /* true if context ever executed usertime */
+ /* View clipping is handled in the graphics state. */
+ /****** User parameters ******/
+ /****** %stdin, %stdout ******/
+} gs_context_state_t;
+/*
+ * Note that in single-context systems, we never allocate a context state
+ * on the heap: we only allocate one in a local variable for long enough
+ * to initialize it and load the interpreter state from it. Therefore,
+ * we declare the GC type for gs_context_state_t here, but we don't
+ * actually create it unless multiple contexts are supported.
+ */
+#define private_st_context_state() /* in zcontext.c, not icontext.c */\
+ gs_private_st_composite(st_context_state, gs_context_state_t,\
+ "gs_context_state_t", context_state_enum_ptrs, context_state_reloc_ptrs)
+
+/* Allocate the state of a context. */
+/* The client is responsible for the 'memory' member. */
+int context_state_alloc(P2(gs_context_state_t *, gs_ref_memory_t *));
+
+/* Load the state of the interpreter from a context. */
+void context_state_load(P1(const gs_context_state_t *));
+
+/* Store the state of the interpreter into a context. */
+void context_state_store(P1(gs_context_state_t *));
+
+/* Free the state of a context. */
+void context_state_free(P2(gs_context_state_t *, gs_ref_memory_t *));
+
+#endif /* icontext_INCLUDED */
diff --git a/gs/src/icsmap.h b/gs/src/icsmap.h
new file mode 100644
index 000000000..d8f33e73e
--- /dev/null
+++ b/gs/src/icsmap.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* icsmap.h */
+/* Interface to shared routines for loading the cached color space maps. */
+
+/*
+ * Set up to load a cached map for an Indexed or substituted Separation
+ * color space. The implementation is in zcsindex.c. When the map1
+ * procedure is called, the following structure is on the e_stack:
+ */
+#define num_csme 5
+# define csme_num_components (-4) /* t_integer */
+# define csme_map (-3) /* t_struct (bytes) */
+# define csme_proc (-2) /* -procedure- */
+# define csme_hival (-1) /* t_integer */
+# define csme_index 0 /* t_integer */
+int zcs_begin_map(P5(gs_indexed_map **pmap, const ref *pproc, int num_entries,
+ const gs_base_color_space *base_space, int (*map1)(P1(os_ptr))));
diff --git a/gs/src/idebug.c b/gs/src/idebug.c
new file mode 100644
index 000000000..6f9199228
--- /dev/null
+++ b/gs/src/idebug.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idebug.c */
+/* Debugging support for Ghostscript interpreter */
+/* This file must always be compiled with DEBUG set. */
+#undef DEBUG
+#define DEBUG
+#include "string_.h"
+#include "ghost.h"
+#include "ialloc.h" /* for imemory for getting struct type */
+#include "idebug.h" /* defines interface */
+#include "idict.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "istack.h"
+#include "iutil.h"
+#include "ivmspace.h"
+#include "ostack.h" /* for opdef.h */
+#include "opdef.h"
+#include "store.h" /* for make_oper for opdef.h */
+
+/* Table of type name strings */
+static const char *type_strings[] = { type_print_strings };
+
+/* First unassigned type index */
+extern const int tx_next_index; /* in interp.c */
+
+/* Print a name. */
+void
+debug_print_name(const ref *pnref)
+{ ref sref;
+ name_string_ref(pnref, &sref);
+ debug_print_string(sref.value.const_bytes, r_size(&sref));
+}
+
+/* Print a ref. */
+private void
+debug_print_full_ref(const ref *pref)
+{ unsigned size = r_size(pref);
+ ref nref;
+ dprintf1("(%x)", r_type_attrs(pref));
+ switch ( r_type(pref) )
+ {
+ case t_array:
+ dprintf2("array(%u)0x%lx", size, (ulong)pref->value.refs); break;
+ case t_astruct:
+ goto strct;
+ case t_boolean:
+ dprintf1("boolean %x", pref->value.boolval); break;
+ case t_device:
+ dprintf1("device 0x%lx", (ulong)pref->value.pdevice); break;
+ case t_dictionary:
+ dprintf3("dict(%u/%u)0x%lx",
+ dict_length(pref), dict_maxlength(pref),
+ (ulong)pref->value.pdict);
+ break;
+ case t_file:
+ dprintf1("file 0x%lx", (ulong)pref->value.pfile); break;
+ case t_fontID:
+ goto strct;
+ case t_integer:
+ dprintf1("int %ld", pref->value.intval); break;
+ case t_mark:
+ dprintf("mark"); break;
+ case t_mixedarray:
+ dprintf2("mixed packedarray(%u)0x%lx", size,
+ (ulong)pref->value.packed); break;
+ case t_name:
+ dprintf2("name(0x%lx#%u)", (ulong)pref->value.pname,
+ name_index(pref));
+ debug_print_name(pref);
+ break;
+ case t_null:
+ dprintf("null"); break;
+ case t_oparray:
+ dprintf2("op_array(%u)0x%lx:", size, (ulong)pref->value.const_refs);
+ { const op_array_table *opt = op_index_op_array_table(size);
+ name_index_ref(opt->nx_table[size - opt->base_index], &nref);
+ }
+ debug_print_name(&nref);
+ break;
+ case t_operator:
+ dprintf1("op(%u", size);
+ if ( size > 0 && size < op_def_count ) /* just in case */
+ dprintf1(":%s", (const char *)(op_def_table[size]->oname + 1));
+ dprintf1(")0x%lx", (ulong)pref->value.opproc);
+ break;
+ case t_real:
+ dprintf1("real %f", pref->value.realval); break;
+ case t_save:
+ dprintf1("save %lu", pref->value.saveid); break;
+ case t_shortarray:
+ dprintf2("short packedarray(%u)0x%lx", size,
+ (ulong)pref->value.packed); break;
+ case t_string:
+ dprintf2("string(%u)0x%lx", size, (ulong)pref->value.bytes); break;
+ case t_struct:
+strct: { obj_header_t *obj = (obj_header_t *)pref->value.pstruct;
+ dprintf2("struct %s 0x%lx",
+ (r_is_foreign(pref) ? "-foreign-" :
+ gs_struct_type_name_string(gs_object_type(imemory, obj))),
+ (ulong)obj);
+ }
+ break;
+ default: dprintf1("type 0x%x", r_type(pref));
+ }
+}
+private void
+debug_print_packed_ref(const ref_packed *pref)
+{ ushort elt = *pref & packed_value_mask;
+ ref nref;
+ switch ( *pref >> r_packed_type_shift )
+ {
+ case pt_executable_operator:
+ dprintf("<op_name>");
+ op_index_ref(elt, &nref);
+ debug_print_ref(&nref);
+ break;
+ case pt_integer:
+ dprintf1("<int> %d", (int)elt + packed_min_intval);
+ break;
+ case pt_literal_name:
+ dprintf("<lit_name>"); goto ptn;
+ case pt_executable_name:
+ dprintf("<exec_name>");
+ptn: name_index_ref(elt, &nref);
+ dprintf2("(0x%lx#%u)", (ulong)nref.value.pname, elt);
+ debug_print_name(&nref);
+ break;
+ default:
+ dprintf2("<packed_%d?>0x%x", *pref >> r_packed_type_shift, elt);
+ }
+}
+void
+debug_print_ref(const ref *pref)
+{ if ( r_is_packed(pref) )
+ debug_print_packed_ref((const ref_packed *)pref);
+ else
+ debug_print_full_ref(pref);
+ fflush(dstderr);
+}
+
+/* Dump one ref. */
+void
+debug_dump_one_ref(const ref *p)
+{ uint attrs = r_type_attrs(p);
+ uint type = r_type(p);
+ static const attr_print_mask apm[] = {attr_print_masks, {0,0,0}};
+ const attr_print_mask *ap = apm;
+#define buf_size 30
+ char buf[buf_size + 1];
+ uint plen;
+
+ if ( type >= tx_next_index )
+ dprintf1("0x%02x?? ", type);
+ else if ( type >= t_next_index )
+ dprintf("opr* ");
+ else
+ dprintf1("%s ", type_strings[type]);
+ for ( ; ap->mask; ++ap )
+ if ( (attrs & ap->mask) == ap->value )
+ dputc(ap->print);
+ dprintf2(" 0x%04x 0x%08lx", r_size(p), *(const ulong *)&p->value);
+ if ( obj_cvs(p, (byte *)buf, countof(buf) - 1, &plen, NULL) >= 0 &&
+ ((buf[plen] = 0), strcmp(buf, "--nostringval--"))
+ )
+ dprintf1(" = %s", buf);
+ fflush(dstderr);
+}
+
+/* Dump a region of memory containing refs. */
+void
+debug_dump_refs(const ref *from, uint size, const char *msg)
+{ const ref *p = from;
+ uint count = size;
+ if ( size && msg )
+ dprintf2("%s at 0x%lx:\n", msg, (ulong)from);
+ while ( count-- )
+ { /* The double cast in the next line is to pacify some */
+ /* unreasonably picky compilers. */
+ dprintf2("..%04x: 0x%04x ", (uint)(ulong)p & 0xffff,
+ r_type_attrs(p));
+ debug_dump_one_ref(p);
+ dputc('\n');
+ p++;
+ }
+}
+
+/* Dump a stack. */
+void
+debug_dump_stack(const ref_stack *pstack, const char *msg)
+{ uint i;
+ const char *m = msg;
+ for ( i = ref_stack_count(pstack); i != 0; )
+ { const ref *p = ref_stack_index(pstack, --i);
+ if ( m )
+ dprintf2("%s at 0x%lx:\n", m, (ulong)pstack),
+ m = NULL;
+ dprintf2("0x%lx: 0x%02x ", (ulong)p, r_type(p));
+ debug_dump_one_ref(p);
+ dputc('\n');
+ }
+}
+
+/* Dump an array. */
+void
+debug_dump_array(const ref *array)
+{ const ref_packed *pp;
+ unsigned int type = r_type(array);
+ uint len;
+
+ switch (type)
+ {
+ default:
+ dprintf2 ("%s at 0x%lx isn't an array.\n",
+ (type < countof(type_strings) ?
+ type_strings[type] : "????"),
+ (ulong)array);
+ return;
+ case t_oparray:
+ /* This isn't really an array, but we'd like to see */
+ /* its contents anyway. */
+ debug_dump_array(array->value.const_refs);
+ return;
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ ;
+ }
+
+ /* This "packed" loop works for all array-types. */
+ for ( len = r_size (array), pp = array->value.packed;
+ len > 0;
+ len--, pp = packed_next(pp))
+ { ref temp;
+ packed_get(pp, &temp);
+ /* The double cast in the next line is to pacify some */
+ /* unreasonably picky compilers. */
+ dprintf3("..%04x%c 0x%02x ",
+ (uint)(ulong)pp & 0xffff,
+ ((r_is_packed(pp)) ? '*' : ':'),
+ r_type(&temp));
+ debug_dump_one_ref(&temp);
+ dputc ('\n');
+ }
+}
diff --git a/gs/src/idebug.h b/gs/src/idebug.h
new file mode 100644
index 000000000..6fbfe3915
--- /dev/null
+++ b/gs/src/idebug.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idebug.h */
+/* Prototypes for debugging procedures in idebug.c */
+
+/* Print individual values. */
+void debug_print_name(P1(const ref *));
+void debug_print_ref(P1(const ref *));
+
+/* Dump regions of memory. */
+void debug_dump_one_ref(P1(const ref *));
+void debug_dump_refs(P3(const ref *from, uint size, const char *msg));
+void debug_dump_array(P1(const ref *array));
+
+/* Dump a stack. Using this requires istack.h. */
+#ifndef ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack; /* also defined in istack.h */
+# define ref_stack_DEFINED
+#endif
+void debug_dump_stack(P2(const ref_stack *pstack, const char *msg));
diff --git a/gs/src/idict.c b/gs/src/idict.c
new file mode 100644
index 000000000..a13235c54
--- /dev/null
+++ b/gs/src/idict.c
@@ -0,0 +1,1003 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idict.c */
+/* Dictionaries for Ghostscript */
+#include "string_.h" /* for strlen */
+#include "ghost.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "idebug.h" /* for debug_print_name */
+#include "inamedef.h"
+#include "ipacked.h"
+#include "isave.h" /* for value cache in names */
+#include "store.h"
+#include "idict.h" /* interface definition */
+#include "dstack.h" /* interface & some implementation */
+#include "iutil.h"
+#include "ivmspace.h" /* for store check */
+
+/*
+ * A dictionary of capacity M is a structure of four elements (refs):
+ *
+ * keys - a t_shortarray or t_array of M+1 elements, containing
+ * the keys.
+ *
+ * values - a t_array of M+1 elements, containing the values.
+ *
+ * count - a t_integer whose value tells how many entries are
+ * occupied (N).
+ *
+ * maxlength - a t_integer whose value gives the client's view of
+ * the capacity (C). C may be less than M (see below).
+ *
+ * C < M is possible because on large-memory systems, we usually round up M
+ * so that M is a power of 2 (see idict.h for details); this allows us to
+ * use masking rather than division for computing the initial hash probe.
+ * However, C is always the maxlength specified by the client, so clients
+ * get a consistent story.
+ *
+ * As noted above, the keys may be either in packed or unpacked form.
+ * The markers for unused and deleted entries are different in the two forms.
+ * In the packed form:
+ * unused entries contain packed_key_empty;
+ * deleted entries contain packed_key_deleted.
+ * In the unpacked form:
+ * unused entries contain a literal null;
+ * deleted entries contain an executable null.
+ *
+ * The first entry is always marked deleted, to reduce the cost of the
+ * wrap-around check.
+ *
+ * Note that if the keys slot in the dictionary is new,
+ * all the key slots are new (more recent than the last save).
+ * We use this fact to avoid saving stores into packed keys
+ * for newly created dictionaries.
+ *
+ * Note that name keys with indices above packed_name_max_index require using
+ * the unpacked form. */
+#define dict_is_packed(dct) r_has_type(&(dct)->keys, t_shortarray)
+#define packed_key_empty (pt_tag(pt_integer) + 0)
+#define packed_key_deleted (pt_tag(pt_integer) + 1)
+#define packed_key_impossible pt_tag(pt_full_ref) /* never matches */
+#define packed_name_key(nidx)\
+ ((nidx) <= packed_name_max_index ? pt_tag(pt_literal_name) + (nidx) :\
+ packed_key_impossible)
+/*
+ * Using a special mark for deleted entries causes lookup time to degrade
+ * as entries are inserted and deleted. This is not a problem, because
+ * entries are almost never deleted.
+ */
+#define d_maxlength(dct) ((uint)((dct)->maxlength.value.intval))
+#define d_set_maxlength(dct,siz) ((dct)->maxlength.value.intval = (siz))
+#define nslots(dct) r_size(&(dct)->values)
+#define npairs(dct) (nslots(dct) - 1)
+#define d_length(dct) ((uint)((dct)->count.value.intval))
+
+/*
+ * Define the size of the largest valid dictionary.
+ * This is limited by the size field of the keys and values refs,
+ * and by the enumeration interface, which requires the size to
+ * fit in an int. As it happens, max_array_size will always be
+ * smaller than max_int.
+ */
+const uint dict_max_size = max_array_size - 1;
+
+/* Define whether dictionaries expand automatically when full. */
+bool dict_auto_expand = false;
+
+/* Define whether dictionaries are packed by default. */
+bool dict_default_pack = true;
+
+/* Cached values from the top element of the dictionary stack. */
+/* See dstack.h for details. */
+int dsspace; /* see dstack.h */
+const ref_packed *dtop_keys;
+uint dtop_npairs;
+ref *dtop_values;
+
+/* Forward references */
+private int dict_create_contents(P3(uint size, const ref *pdref, bool pack));
+
+/* Debugging statistics */
+#ifdef DEBUG
+long dn_lookups; /* total lookups */
+long dn_1probe; /* successful lookups on only 1 probe */
+long dn_2probe; /* successful lookups on 2 probes */
+/* Wrappers for dict_find and dict_find_name_by_index */
+int real_dict_find(P3(const ref *pdref, const ref *key, ref **ppvalue));
+int
+dict_find(const ref *pdref, const ref *pkey, ref **ppvalue)
+{ dict *pdict = pdref->value.pdict;
+ int code = real_dict_find(pdref, pkey, ppvalue);
+
+ dn_lookups++;
+ if ( r_has_type(pkey, t_name) && dict_is_packed(pdict) )
+ { uint nidx = name_index(pkey);
+ uint hash =
+ dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
+ if ( pdict->keys.value.packed[hash] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_1probe++;
+ else if ( pdict->keys.value.packed[hash - 1] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_2probe++;
+ }
+ /* Do the cheap flag test before the expensive remainder test. */
+ if ( gs_debug_c('d') && !(dn_lookups % 1000) )
+ dprintf3("[d]lookups=%ld 1probe=%ld 2probe=%ld\n",
+ dn_lookups, dn_1probe, dn_2probe);
+ return code;
+}
+#define dict_find real_dict_find
+ref *real_dict_find_name_by_index(P1(uint nidx));
+ref *
+dict_find_name_by_index(uint nidx)
+{ ref *pvalue = real_dict_find_name_by_index(nidx);
+ dict *pdict = dsp->value.pdict;
+
+ dn_lookups++;
+ if ( dict_is_packed(pdict) )
+ { uint hash =
+ dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
+ if ( pdict->keys.value.packed[hash] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_1probe++;
+ else if ( pdict->keys.value.packed[hash - 1] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_2probe++;
+ }
+ /* Do the cheap flag test before the expensive remainder test. */
+ if ( gs_debug_c('d') && !(dn_lookups % 1000) )
+ dprintf3("[d]lookups=%ld 1probe=%ld 2probe=%ld\n",
+ dn_lookups, dn_1probe, dn_2probe);
+ return pvalue;
+}
+#define dict_find_name_by_index real_dict_find_name_by_index
+#endif
+
+/* Round up the size of a dictionary. Return 0 if too large. */
+uint
+dict_round_size_small(uint rsize)
+{ return (rsize > dict_max_size ? 0 : rsize);
+}
+uint
+dict_round_size_large(uint rsize)
+{ /* Round up to a power of 2 if not huge. */
+ /* If the addition overflows, the new rsize will be zero, */
+ /* which will (correctly) be interpreted as a limitcheck. */
+ if ( rsize > dict_max_non_huge )
+ return (rsize > dict_max_size ? 0 : rsize);
+ while ( rsize & (rsize - 1) )
+ rsize = (rsize | (rsize - 1)) + 1;
+ return (rsize <= dict_max_size ? rsize : dict_max_non_huge);
+}
+
+/* Create a dictionary in the current VM space. */
+int
+dict_create(uint size, ref *pdref)
+{ ref arr;
+ int code = ialloc_ref_array(&arr, a_all, sizeof(dict) / sizeof(ref),
+ "dict_create");
+ ref dref;
+
+ if ( code < 0 )
+ return code;
+ make_tav_new(&dref, t_dictionary, r_space(&arr) | a_all,
+ pdict, (dict *)arr.value.refs);
+ code = dict_create_contents(size, &dref, dict_default_pack);
+ if ( code < 0 )
+ return code;
+ *pdref = dref;
+ return 0;
+}
+/* Create unpacked keys for a dictionary. */
+/* The keys are allocated in the same VM space as the dictionary. */
+private int
+dict_create_unpacked_keys(uint asize, const ref *pdref)
+{ dict *pdict = pdref->value.pdict;
+ uint space = ialloc_space(idmemory);
+ int code;
+
+ ialloc_set_space(idmemory, r_space(pdref));
+ code = ialloc_ref_array(&pdict->keys, a_all, asize, "dict create unpacked keys");
+ if ( code >= 0 )
+ { ref *kp = pdict->keys.value.refs;
+ ref_mark_new(&pdict->keys);
+ refset_null(kp, asize);
+ r_set_attrs(kp, a_executable); /* wraparound entry */
+ }
+ ialloc_set_space(idmemory, space);
+ return code;
+}
+/* Create the contents (keys and values) of a newly allocated dictionary. */
+/* Allocate in the current VM space, which is assumed to be the same as */
+/* the VM space where the dictionary is allocated. */
+private int
+dict_create_contents(uint size, const ref *pdref, bool pack)
+{ dict *pdict = pdref->value.pdict;
+ uint asize = dict_round_size((size == 0 ? 1 : size));
+ int code;
+ register uint i;
+
+ if ( asize == 0 || asize > max_array_size - 1 ) /* too large */
+ return_error(e_limitcheck);
+ asize++; /* allow room for wraparound entry */
+ code = ialloc_ref_array(&pdict->values, a_all, asize,
+ "dict_create(values)");
+ if ( code < 0 )
+ return code;
+ ref_mark_new(&pdict->values);
+ refset_null(pdict->values.value.refs, asize);
+ if ( pack )
+ { uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
+ ref arr;
+ ref_packed *pkp;
+ ref_packed *pzp;
+ code = ialloc_ref_array(&arr, a_all, ksize,
+ "dict_create(packed keys)");
+ if ( code < 0 )
+ return code;
+ pkp = (ref_packed *)arr.value.refs;
+ make_tasv_new(&pdict->keys, t_shortarray,
+ r_space(&arr) | a_all,
+ asize, packed, pkp);
+ for ( pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++ )
+ *pzp = packed_key_empty;
+ *pkp = packed_key_deleted; /* wraparound entry */
+ }
+ else /* not packed */
+ { int code = dict_create_unpacked_keys(asize, pdref);
+ if ( code < 0 ) return code;
+ }
+ make_int_new(&pdict->count, 0);
+ make_int_new(&pdict->maxlength, size);
+ return 0;
+}
+
+/*
+ * Ensure that a dictionary uses the unpacked representation for keys.
+ * We can't just use dict_resize, because the values slots mustn't move.
+ */
+int
+dict_unpack(ref *pdref)
+{ dict *pdict = pdref->value.pdict;
+ if ( !dict_is_packed(pdict) )
+ return 0; /* nothing to do */
+ { uint count = nslots(pdict);
+ const ref_packed *okp = pdict->keys.value.packed;
+ ref old_keys;
+ int code;
+ ref *nkp;
+ old_keys = pdict->keys;
+ if ( ref_must_save(&old_keys) )
+ ref_do_save(pdref, &pdict->keys, "dict_unpack(keys)");
+ code = dict_create_unpacked_keys(count, pdref);
+ if ( code < 0 )
+ return code;
+ for ( nkp = pdict->keys.value.refs; count--; okp++, nkp++ )
+ if ( r_packed_is_name(okp) )
+ { packed_get(okp, nkp);
+ ref_mark_new(nkp);
+ }
+ else if ( *okp == packed_key_deleted )
+ r_set_attrs(nkp, a_executable);
+ if ( !ref_must_save(&old_keys) )
+ ifree_ref_array(&old_keys, "dict_unpack(old keys)");
+ dict_set_top(); /* just in case */
+ }
+ return 0;
+}
+
+/*
+ * Define a macro for searching a packed dictionary. Free variables:
+ * ref_packed kpack - holds the packed key.
+ * uint hash - holds the hash of the name.
+ * dict *pdict - points to the dictionary.
+ * uint size - holds npairs(pdict).
+ * Note that the macro is *not* enclosed in {}, so that we can access
+ * the values of kbot and kp after leaving the loop.
+ *
+ * We break the macro into two to avoid overflowing some preprocessors.
+ */
+/* packed_search_body also uses kp and kbot as free variables. */
+#define packed_search_value_pointer (pdict->values.value.refs + (kp - kbot))
+#define packed_search_body(found1,found2,del,miss)\
+ { if_debug2('D', "[D]probe 0x%lx: 0x%x\n", (ulong)kp, *kp);\
+ if ( *kp == kpack )\
+ { found1;\
+ found2;\
+ }\
+ else if ( !r_packed_is_name(kp) )\
+ { /* Empty, deleted, or wraparound. Figure out which. */\
+ if ( *kp == packed_key_empty ) miss;\
+ if ( kp == kbot ) break; /* wrap */\
+ else { del; }\
+ }\
+ }
+#define packed_search_1(found1,found2,del,miss)\
+ const ref_packed *kbot = pdict->keys.value.packed;\
+ register const ref_packed *kp;\
+ for ( kp = kbot + dict_hash_mod(hash, size) + 1; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+#define packed_search_2(found1,found2,del,miss)\
+ for ( kp += size; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+
+/*
+ * Look up a key in a dictionary. Store a pointer to the value slot
+ * where found, or to the (value) slot for inserting.
+ * Return 1 if found, 0 if not and there is room for a new entry,
+ * or e_dictfull if the dictionary is full and the key is missing.
+ * The caller is responsible for ensuring key is not a null.
+ */
+int
+dict_find(const ref *pdref, const ref *pkey,
+ ref **ppvalue /* result is stored here */)
+{ dict *pdict = pdref->value.pdict;
+ uint size = npairs(pdict);
+ register int etype;
+ uint nidx;
+ ref_packed kpack;
+ uint hash;
+ int ktype;
+ /* Compute hash. The only types we bother with are strings, */
+ /* names, and (unlikely, but worth checking for) integers. */
+ switch ( r_type(pkey) )
+ {
+ case t_name:
+ nidx = name_index(pkey);
+nh: hash = dict_name_index_hash(nidx);
+ kpack = packed_name_key(nidx);
+ ktype = t_name;
+ break;
+ case t_string: /* convert to a name first */
+ { ref nref;
+ int code;
+ if ( !r_has_attr(pkey, a_read) )
+ return_error(e_invalidaccess);
+ code = name_ref(pkey->value.bytes, r_size(pkey), &nref, 1);
+ if ( code < 0 )
+ return code;
+ nidx = name_index(&nref);
+ } goto nh;
+ case t_integer:
+ hash = (uint)pkey->value.intval * 30503;
+ kpack = packed_key_impossible;
+ ktype = -1;
+ nidx = 0; /* only to pacify gcc */
+ break;
+ case t_null: /* not allowed as a key */
+ return_error(e_typecheck);
+ default:
+ hash = r_btype(pkey) * 99; /* yech */
+ kpack = packed_key_impossible;
+ ktype = -1;
+ nidx = 0; /* only to pacify gcc */
+ }
+ /* Search the dictionary */
+ if ( dict_is_packed(pdict) )
+ { const ref_packed *pslot = 0;
+ packed_search_1(*ppvalue = packed_search_value_pointer,
+ return 1,
+ if ( pslot == 0 ) pslot = kp, goto miss);
+ packed_search_2(*ppvalue = packed_search_value_pointer,
+ return 1,
+ if ( pslot == 0 ) pslot = kp, goto miss);
+ /*
+ * Double wraparound, dict is full.
+ * Note that even if there was an empty slot (pslot != 0),
+ * we must return dictfull if length = maxlength.
+ */
+ if ( pslot == 0 || d_length(pdict) == d_maxlength(pdict) )
+ return(e_dictfull);
+ *ppvalue = pdict->values.value.refs + (pslot - kbot);
+ return 0;
+miss: /* Key is missing, not double wrap. See above re dictfull. */
+ if ( d_length(pdict) == d_maxlength(pdict) )
+ return(e_dictfull);
+ if ( pslot == 0 )
+ pslot = kp;
+ *ppvalue = pdict->values.value.refs + (pslot - kbot);
+ return 0;
+ }
+ else
+ { ref *kbot = pdict->keys.value.refs;
+ register ref *kp;
+ ref *pslot = 0;
+ int wrap = 0;
+ for ( kp = kbot + dict_hash_mod(hash, size) + 2; ; )
+ { --kp;
+ if ( (etype = r_type(kp)) == ktype )
+ { /* Fast comparison if both keys are names */
+ if ( name_index(kp) == nidx )
+ { *ppvalue = pdict->values.value.refs + (kp - kbot);
+ return 1;
+ }
+ }
+ else if ( etype == t_null )
+ { /* Empty, deleted, or wraparound. */
+ /* Figure out which. */
+ if ( kp == kbot ) /* wrap */
+ { if ( wrap++ ) /* wrapped twice */
+ { if ( pslot == 0 )
+ return(e_dictfull);
+ break;
+ }
+ kp += size + 1;
+ }
+ else if ( r_has_attr(kp, a_executable) )
+ { /* Deleted entry, save the slot. */
+ if ( pslot == 0 )
+ pslot = kp;
+ }
+ else /* key not found */
+ break;
+ }
+ else
+ { if ( obj_eq(kp, pkey) )
+ { *ppvalue = pdict->values.value.refs + (kp - kbot);
+ return 1;
+ }
+ }
+ }
+ if ( d_length(pdict) == d_maxlength(pdict) )
+ return(e_dictfull);
+ *ppvalue = pdict->values.value.refs +
+ ((pslot != 0 ? pslot : kp) - kbot);
+ return 0;
+ }
+}
+
+/*
+ * Look up a (constant) C string in a dictionary.
+ * Return 1 if found, <= 0 if not.
+ */
+int
+dict_find_string(const ref *pdref, const char _ds *kstr, ref **ppvalue)
+{ int code;
+ ref kname;
+ if ( (code = name_ref((const byte *)kstr, strlen(kstr), &kname, -1)) < 0 )
+ return code;
+ return dict_find(pdref, &kname, ppvalue);
+}
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool
+dict_is_permanent_on_dstack(const ref *pdref)
+{ dict *pdict = pdref->value.pdict;
+ int i;
+ if ( d_stack.extension_size == 0 )
+ { /* Only one block of d-stack. */
+ for ( i = 0; i < min_dstack_size; ++i )
+ if ( dsbot[i].value.pdict == pdict )
+ return true;
+ }
+ else
+ { /* More than one block of d-stack. */
+ uint count = ref_stack_count(&d_stack);
+ for ( i = count - min_dstack_size; i < count; ++i )
+ if ( ref_stack_index(&d_stack, i)->value.pdict == pdict )
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Look up a name on the dictionary stack.
+ * Return the pointer to the value if found, 0 if not.
+ */
+ref *
+dict_find_name_by_index(uint nidx)
+{ ds_ptr pdref = dsp;
+/* Since we know the hash function is the identity function, */
+/* there's no point in allocating a separate variable for it. */
+#define hash dict_name_index_hash(nidx)
+ ref_packed kpack = packed_name_key(nidx);
+ do
+ { dict *pdict = pdref->value.pdict;
+ uint size = npairs(pdict);
+#ifdef DEBUG
+ if ( gs_debug_c('D') )
+ { ref dnref;
+ name_index_ref(nidx, &dnref);
+ dputs("[D]lookup ");
+ debug_print_name(&dnref);
+ dprintf3(" in 0x%lx(%u/%u)\n",
+ (ulong)pdict, dict_length(pdref),
+ dict_maxlength(pdref));
+ }
+#endif
+ if ( dict_is_packed(pdict) )
+ { packed_search_1(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, goto miss);
+ packed_search_2(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, break);
+ miss: ;
+ }
+ else
+ { ref *kbot = pdict->keys.value.refs;
+ register ref *kp;
+ int wrap = 0;
+ /* Search the dictionary */
+ for ( kp = kbot + dict_hash_mod(hash, size) + 2; ; )
+ { --kp;
+ if ( r_has_type(kp, t_name) )
+ { if ( name_index(kp) == nidx )
+ return pdict->values.value.refs +
+ (kp - kbot);
+ }
+ else if ( r_has_type(kp, t_null) )
+ { /* Empty, deleted, or wraparound. */
+ /* Figure out which. */
+ if ( !r_has_attr(kp, a_executable) )
+ break;
+ if ( kp == kbot ) /* wrap */
+ { if ( wrap++ )
+ break; /* 2 wraps */
+ kp += size + 1;
+ }
+ }
+ }
+ }
+ }
+ while ( pdref-- > dsbot );
+ /* The name isn't in the top dictionary block. */
+ /* If there are other blocks, search them now (more slowly). */
+ if ( !d_stack.extension_size ) /* no more blocks */
+ return (ref *)0;
+ { /* We could use the STACK_LOOP macros, but for now, */
+ /* we'll do things the simplest way. */
+ ref key;
+ uint i = dsp + 1 - dsbot;
+ uint size = ref_stack_count(&d_stack);
+ ref *pvalue;
+ name_index_ref(nidx, &key);
+ for ( ; i < size; i++ )
+ { if ( dict_find(ref_stack_index(&d_stack, i),
+ &key, &pvalue) > 0
+ )
+ return pvalue;
+ }
+ }
+ return (ref *)0;
+#undef hash
+}
+
+/*
+ * Enter a key-value pair in a dictionary.
+ * See idict.h for the possible return values.
+ */
+int
+dict_put(ref *pdref /* t_dictionary */, const ref *pkey, const ref *pvalue)
+{ int rcode = 0;
+ int code;
+ ref *pvslot;
+ /* Check the value. */
+ store_check_dest(pdref, pvalue);
+top: if ( (code = dict_find(pdref, pkey, &pvslot)) <= 0 ) /* not found */
+ { /* Check for overflow */
+ dict *pdict = pdref->value.pdict;
+ ref kname;
+ uint index;
+ switch ( code )
+ {
+ case 0:
+ break;
+ case e_dictfull:
+ if ( !dict_auto_expand )
+ return_error(e_dictfull);
+ code = dict_grow(pdref);
+ if ( code < 0 )
+ return code;
+ goto top; /* keep things simple */
+ default: /* e_typecheck */
+ return code;
+ }
+ index = pvslot - pdict->values.value.refs;
+ /* If the key is a string, convert it to a name. */
+ if ( r_has_type(pkey, t_string) )
+ { int code;
+ if ( !r_has_attr(pkey, a_read) )
+ return_error(e_invalidaccess);
+ code = name_from_string(pkey, &kname);
+ if ( code < 0 )
+ return code;
+ pkey = &kname;
+ }
+ if ( dict_is_packed(pdict) )
+ { ref_packed *kp;
+ if ( !r_has_type(pkey, t_name) ||
+ name_index(pkey) > packed_name_max_index
+ )
+ { /* Change to unpacked representation. */
+ int code = dict_unpack(pdref);
+ if ( code < 0 )
+ return code;
+ goto top;
+ }
+ kp = (ref_packed *)(pdict->keys.value.packed + index);
+ if ( ref_must_save(&pdict->keys) )
+ { /* See initial comment for why it is safe */
+ /* not to save the change if the keys */
+ /* array itself is new. */
+ ref_do_save(&pdict->keys, kp, "dict_put(key)");
+ }
+ *kp = pt_tag(pt_literal_name) + name_index(pkey);
+ }
+ else
+ { ref *kp = pdict->keys.value.refs + index;
+ if_debug2('d', "[d]0x%lx: fill key at 0x%lx\n",
+ (ulong)pdict, (ulong)kp);
+ store_check_dest(pdref, pkey);
+ ref_assign_old(&pdict->keys, kp, pkey,
+ "dict_put(key)"); /* set key of pair */
+ }
+ ref_save(pdref, &pdict->count, "dict_put(count)");
+ pdict->count.value.intval++;
+ /* If the key is a name, update its 1-element cache. */
+ if ( r_has_type(pkey, t_name) )
+ { name *pname = pkey->value.pname;
+ if ( pname->pvalue == pv_no_defn &&
+ (pdict == systemdict->value.pdict ||
+ dict_is_permanent_on_dstack(pdref)) &&
+ /* Only set the cache if we aren't inside */
+ /* a save. This way, we never have to */
+ /* undo setting the cache. */
+ alloc_save_level(idmemory) == 0
+ )
+ { /* Set the cache. */
+ if_debug0('d', "[d]set cache\n");
+ pname->pvalue = pvslot;
+ }
+ else
+ { /* The cache can't be used. */
+ if_debug0('d', "[d]no cache\n");
+ pname->pvalue = pv_other;
+ }
+ }
+ rcode = 1;
+ }
+ if_debug8('d', "[d]0x%lx: put key 0x%lx 0x%lx\n value at 0x%lx: old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
+ (ulong)pdref->value.pdict,
+ ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
+ (ulong)pvslot,
+ ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
+ ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
+ ref_assign_old(&pdref->value.pdict->values, pvslot, pvalue,
+ "dict_put(value)");
+ return rcode;
+}
+
+/*
+ * Enter a key-value pair where the key is a (constant) C string.
+ */
+int
+dict_put_string(ref *pdref, const char *kstr, const ref *pvalue)
+{ int code;
+ ref kname;
+ if ( (code = name_ref((const byte *)kstr, strlen(kstr), &kname, 0)) < 0 )
+ return code;
+ return dict_put(pdref, &kname, pvalue);
+}
+
+/* Remove an element from a dictionary. */
+int
+dict_undef(ref *pdref, const ref *pkey)
+{ ref *pvslot;
+ dict *pdict;
+ uint index;
+ if ( dict_find(pdref, pkey, &pvslot) <= 0 )
+ return(e_undefined);
+ /* Remove the entry from the dictionary. */
+ pdict = pdref->value.pdict;
+ index = pvslot - pdict->values.value.refs;
+ if ( dict_is_packed(pdict) )
+ { ref_packed *pkp =
+ (ref_packed *)(pdict->keys.value.packed + index);
+ /* See the initial comment for why it is safe not to save */
+ /* the change if the keys array itself is new. */
+ if ( ref_must_save(&pdict->keys) )
+ ref_do_save(&pdict->keys, pkp, "dict_undef(key)");
+ /* Accumulating deleted entries slows down lookup. */
+ /* Detect the easy case where we can use an empty entry */
+ /* rather than a deleted one, namely, when the next entry */
+ /* in the probe order is empty. */
+ if ( pkp[-1] == packed_key_empty )
+ *pkp = packed_key_empty;
+ else
+ *pkp = packed_key_deleted;
+ }
+ else /* not packed */
+ { ref *kp = pdict->keys.value.refs + index;
+ make_null_old(&pdict->keys, kp, "dict_undef(key)");
+ /* Accumulating deleted entries slows down lookup. */
+ /* Detect the easy case where we can use an empty entry */
+ /* rather than a deleted one, namely, when the next entry */
+ /* in the probe order is empty. */
+ if ( !r_has_type(kp - 1, t_null) || /* full entry */
+ r_has_attr(kp - 1, a_executable) /* deleted or wraparound */
+ )
+ r_set_attrs(kp, a_executable); /* mark as deleted */
+ }
+ ref_save(pdref, &pdict->count, "dict_undef(count)");
+ pdict->count.value.intval--;
+ /* If the key is a name, update its 1-element cache. */
+ if ( r_has_type(pkey, t_name) )
+ { name *pname = pkey->value.pname;
+ if ( pv_valid(pname->pvalue) )
+ {
+#ifdef DEBUG
+ /* Check the the cache is correct. */
+ if ( !dict_is_permanent_on_dstack(pdref) )
+ lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n",
+ (ulong)pname->pvalue);
+#endif
+ /* Clear the cache */
+ pname->pvalue = pv_no_defn;
+ }
+ }
+ make_null_old(&pdict->values, pvslot, "dict_undef(value)");
+ return 0;
+}
+
+/* Return the number of elements in a dictionary. */
+uint
+dict_length(const ref *pdref /* t_dictionary */)
+{ return d_length(pdref->value.pdict);
+}
+
+/* Return the capacity of a dictionary. */
+uint
+dict_maxlength(const ref *pdref /* t_dictionary */)
+{ return d_maxlength(pdref->value.pdict);
+}
+
+/* Return the maximum index of a slot within a dictionary. */
+uint
+dict_max_index(const ref *pdref /* t_dictionary */)
+{ return npairs(pdref->value.pdict) - 1;
+}
+
+/* Copy one dictionary into another. */
+/* If new_only is true, only copy entries whose keys */
+/* aren't already present in the destination. */
+int
+dict_copy_entries(const ref *pdrfrom /* t_dictionary */,
+ ref *pdrto /* t_dictionary */, bool new_only)
+{ int space = r_space(pdrto);
+ int index;
+ ref elt[2];
+ ref *pvslot;
+ int code;
+ if ( space != avm_max )
+ { /* Do the store check before starting the copy. */
+ index = dict_first(pdrfrom);
+ while ( (index = dict_next(pdrfrom, index, elt)) >= 0 )
+ if ( !new_only || dict_find(pdrto, &elt[0], &pvslot) <= 0 )
+ { store_check_space(space, &elt[0]);
+ store_check_space(space, &elt[1]);
+ }
+ }
+ /* Now copy the contents. */
+ index = dict_first(pdrfrom);
+ while ( (index = dict_next(pdrfrom, index, elt)) >= 0 )
+ { if ( new_only && dict_find(pdrto, &elt[0], &pvslot) > 0 )
+ continue;
+ if ( (code = dict_put(pdrto, &elt[0], &elt[1])) < 0 )
+ return code;
+ }
+ return 0;
+}
+
+/* Set the cached values computed from the top entry on the dstack. */
+/* See dstack.h for details. */
+private const ref_packed no_packed_keys[2] =
+ { packed_key_deleted, packed_key_empty };
+void
+dict_set_top(void)
+{ dict *pdict = dsp->value.pdict;
+ if_debug3('d', "[d]dsp = 0x%lx -> 0x%lx, key array type = %d\n",
+ (ulong)dsp, (ulong)pdict, r_type(&pdict->keys));
+ if ( dict_is_packed(pdict) &&
+ r_has_attr(dict_access_ref(dsp), a_read)
+ )
+ { dtop_keys = pdict->keys.value.packed;
+ dtop_npairs = npairs(pdict);
+ dtop_values = pdict->values.value.refs;
+ }
+ else
+ { dtop_keys = no_packed_keys;
+ dtop_npairs = 1;
+ }
+ if ( !r_has_attr(dict_access_ref(dsp), a_write) )
+ dsspace = -1;
+ else
+ dsspace = r_space(dsp);
+}
+
+/* Resize a dictionary. */
+int
+dict_resize(ref *pdref, uint new_size)
+{ dict *pdict = pdref->value.pdict;
+ dict dnew;
+ ref drto;
+ int code;
+ uint space;
+ if ( new_size < d_length(pdict) )
+ { if ( !dict_auto_expand )
+ return_error(e_dictfull);
+ new_size = d_length(pdict);
+ }
+ space = ialloc_space(idmemory);
+ ialloc_set_space(idmemory, r_space(pdref));
+ make_tav_new(&drto, t_dictionary, r_space(pdref) | a_all,
+ pdict, &dnew);
+ if ( (code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0 )
+ { ialloc_set_space(idmemory, space);
+ return code;
+ }
+ /* We must suppress the store check, in case we are expanding */
+ /* systemdict or another global dictionary that is allowed */
+ /* to reference local objects. */
+ r_set_space(&drto, avm_local);
+ dict_copy(pdref, &drto); /* can't fail */
+ /* Save or free the old dictionary. */
+ if ( ref_must_save(&pdict->values) )
+ ref_do_save(pdref, &pdict->values, "dict_resize(values)");
+ else
+ ifree_ref_array(&pdict->values, "dict_resize(old values)");
+ if ( ref_must_save(&pdict->keys) )
+ ref_do_save(pdref, &pdict->keys, "dict_resize(keys)");
+ else
+ ifree_ref_array(&pdict->keys, "dict_resize(old keys)");
+ ref_assign(&pdict->keys, &dnew.keys);
+ ref_assign(&pdict->values, &dnew.values);
+ ref_save(pdref, &pdict->maxlength, "dict_resize(maxlength)");
+ d_set_maxlength(pdict, new_size);
+ ialloc_set_space(idmemory, space);
+ dict_set_top(); /* just in case this is the top dict */
+ return 0;
+}
+
+/* Grow a dictionary for dict_put. */
+int
+dict_grow(ref *pdref)
+{ dict *pdict = pdref->value.pdict;
+ /* We might have maxlength < npairs, if */
+ /* dict_round_size increased the size. */
+ ulong new_size = (ulong)d_maxlength(pdict) * 3 / 2 + 2;
+
+#if arch_sizeof_int < arch_sizeof_long
+ if ( new_size > max_uint )
+ new_size = max_uint;
+#endif
+ if ( new_size > npairs(pdict) )
+ { int code = dict_resize(pdref, (uint)new_size);
+ if ( code >= 0 )
+ return code;
+ /* new_size was too big. */
+ if ( npairs(pdict) < dict_max_size )
+ { code = dict_resize(pdref, dict_max_size);
+ if ( code >= 0 )
+ return code;
+ }
+ if ( npairs(pdict) == d_maxlength(pdict) )
+ { /* Can't do it. */
+ return code;
+ }
+ /* We can't grow to new_size, but we can grow to npairs. */
+ new_size = npairs(pdict);
+ }
+ /* maxlength < npairs, we can grow in place */
+ ref_save(pdref, &pdict->maxlength, "dict_put(maxlength)");
+ d_set_maxlength(pdict, new_size);
+ return 0;
+}
+
+/* Prepare to enumerate a dictionary. */
+int
+dict_first(const ref *pdref)
+{ return (int)nslots(pdref->value.pdict);
+}
+
+/* Enumerate the next element of a dictionary. */
+int
+dict_next(const ref *pdref, int index, ref *eltp /* ref eltp[2] */)
+{ dict *pdict = pdref->value.pdict;
+ ref *vp = pdict->values.value.refs + index;
+ while ( vp--, --index >= 0 )
+ { array_get(&pdict->keys, (long)index, eltp);
+ /* Make sure this is a valid entry. */
+ if ( r_has_type(eltp, t_name) ||
+ (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
+ )
+ { eltp[1] = *vp;
+ if_debug6('d', "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
+ (ulong)pdict, index,
+ ((ulong *)eltp)[0], ((ulong *)eltp)[1],
+ ((ulong *)vp)[0], ((ulong *)vp)[1]);
+ return index;
+ }
+ }
+ return -1; /* no more elements */
+}
+
+/* Return the index of a value within a dictionary. */
+int
+dict_value_index(const ref *pdref, const ref *pvalue)
+{ return (int)(pvalue - pdref->value.pdict->values.value.refs - 1);
+}
+
+/* Return the entry at a given index within a dictionary. */
+/* If the index designates an unoccupied entry, return e_undefined. */
+int
+dict_index_entry(const ref *pdref, int index, ref *eltp /* ref eltp[2] */)
+{ const dict *pdict = pdref->value.pdict;
+ array_get(&pdict->keys, (long)(index + 1), eltp);
+ if ( r_has_type(eltp, t_name) ||
+ (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
+ )
+ { eltp[1] = pdict->values.value.refs[index + 1];
+ return 0;
+ }
+ return e_undefined;
+}
+
+/* After a garbage collection, scan the permanent dictionaries and */
+/* update the cached value pointers in names. */
+void
+dstack_gc_cleanup(void)
+{ uint count = ref_stack_count(&d_stack);
+ uint dsi;
+ for ( dsi = min_dstack_size; dsi > 0; --dsi )
+ { const dict *pdict =
+ ref_stack_index(&d_stack, count - dsi)->value.pdict;
+ uint size = nslots(pdict);
+ ref *pvalue = pdict->values.value.refs;
+ uint i;
+ for ( i = 0; i < size; ++i, ++pvalue )
+ { ref key;
+ ref *old_pvalue;
+ array_get(&pdict->keys, (long)i, &key);
+ if ( r_has_type(&key, t_name) &&
+ pv_valid(old_pvalue = key.value.pname->pvalue)
+ )
+ { /*
+ * The name only has a single definition,
+ * so it must be this one. Check to see if
+ * no relocation is actually needed; if so,
+ * we can skip the entire dictionary.
+ */
+ if ( old_pvalue == pvalue )
+ { if_debug1('d', "[d]skipping dstack entry %d\n",
+ dsi - 1);
+ break;
+ }
+ /* Update the value pointer. */
+ key.value.pname->pvalue = pvalue;
+ }
+ }
+ }
+}
diff --git a/gs/src/idict.h b/gs/src/idict.h
new file mode 100644
index 000000000..3a5a032e1
--- /dev/null
+++ b/gs/src/idict.h
@@ -0,0 +1,240 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idict.h */
+/* Interfaces for Ghostscript dictionary package */
+
+/*
+ * Contrary to our usual practice, we expose the (first-level)
+ * representation of a dictionary in the interface file,
+ * because it is so important that access checking go fast.
+ * The access attributes for the dictionary are stored in
+ * the values ref.
+ */
+struct dict_s {
+ ref values; /* t_array, values */
+ ref keys; /* t_shortarray or t_array, keys */
+ ref count; /* t_integer, count of occupied entries */
+ /* (length) */
+ ref maxlength; /* t_integer, maxlength as seen by client. */
+};
+
+/*
+ * Define the maximum size of a dictionary.
+ */
+extern const uint dict_max_size;
+
+/*
+ * Define whether dictionaries expand automatically when full. Note that
+ * if dict_auto_expand is true, dict_put, dict_copy, dict_resize, and
+ * dict_grow cannot return e_dictfull; however, they can return e_VMerror.
+ * (dict_find can return e_dictfull even if dict_auto_expand is true.)
+ */
+extern bool dict_auto_expand;
+
+/*
+ * Create a dictionary.
+ */
+int dict_create(P2(uint maxlength, ref *pdref));
+
+/*
+ * Return a pointer to a ref that holds the access attributes
+ * for a dictionary.
+ */
+#define dict_access_ref(pdref) (&(pdref)->value.pdict->values)
+/*
+ * Check a dictionary for read or write permission.
+ * Note: this does NOT check the type of its operand!
+ */
+#define check_dict_read(dref) check_read(*dict_access_ref(&dref))
+#define check_dict_write(dref) check_write(*dict_access_ref(&dref))
+
+/*
+ * Look up a key in a dictionary. Store a pointer to the value slot
+ * where found, or to the (value) slot for inserting.
+ * The caller is responsible for checking that the dictionary is readable.
+ * Return 1 if found, 0 if not and there is room for a new entry,
+ * Failure returns:
+ * e_typecheck if the key is null;
+ * e_invalidaccess if the key is a string lacking read access;
+ * e_VMerror or e_limitcheck if the key is a string and the corresponding
+ * error occurs from attempting to convert it to a name;
+ * e_dictfull if the dictionary is full and the key is missing.
+ */
+int dict_find(P3(const ref *pdref, const ref *key, ref **ppvalue));
+
+/*
+ * Look up a (constant) C string in a dictionary.
+ * Return 1 if found, <= 0 if not.
+ */
+int dict_find_string(P3(const ref *pdref, const char _ds *kstr,
+ ref **ppvalue));
+
+/*
+ * Enter a key-value pair in a dictionary.
+ * The caller is responsible for checking that the dictionary is writable.
+ * Return 1 if this was a new entry, 0 if this replaced an existing entry.
+ * Failure returns are as for dict_find, except that e_dictfull doesn't
+ * occur if the dictionary is full but expandable, plus:
+ * e_invalidaccess for an attempt to store a younger key or value into
+ * an older dictionary;
+ * e_VMerror if a VMerror occurred while trying to expand the
+ * dictionary.
+ */
+int dict_put(P3(ref *pdref, const ref *key, const ref *pvalue));
+
+/*
+ * Enter a key-value pair where the key is a (constant) C string.
+ */
+int dict_put_string(P3(ref *pdref, const char *kstr, const ref *pvalue));
+
+/*
+ * Remove a key-value pair from a dictionary.
+ * Return 0 or e_undefined.
+ */
+int dict_undef(P2(ref *pdref, const ref *key));
+
+/*
+ * Return the number of elements in a dictionary.
+ */
+uint dict_length(P1(const ref *pdref));
+
+/*
+ * Return the capacity of a dictionary.
+ */
+uint dict_maxlength(P1(const ref *pdref));
+
+/*
+ * Return the maximum index of a slot within a dictionary.
+ * Note that this may be greater than maxlength.
+ */
+uint dict_max_index(P1(const ref *pdref));
+
+/*
+ * Copy one dictionary into another.
+ * Return 0 or e_dictfull.
+ * If new_only is true, only copy entries whose keys
+ * aren't already present in the destination.
+ */
+int dict_copy_entries(P3(const ref *dfrom, ref *dto, bool new_only));
+#define dict_copy(dfrom, dto) dict_copy_entries(dfrom, dto, false)
+#define dict_copy_new(dfrom, dto) dict_copy_entries(dfrom, dto, true)
+
+/*
+ * Grow or shrink a dictionary.
+ * Return 0, e_dictfull, or e_VMerror.
+ */
+int dict_resize(P2(ref *pdref, uint newmaxlength));
+
+/*
+ * Grow a dictionary in the same way as dict_put does.
+ * We export this for some special-case code in zop_def.
+ */
+int dict_grow(P1(ref *pdref));
+
+/*
+ * Ensure that a dictionary uses the unpacked representation for keys.
+ * (This is of no interest to ordinary clients.)
+ */
+int dict_unpack(P1(ref *pdref));
+
+/*
+ * Prepare to enumerate a dictionary.
+ * Return an integer suitable for the first call to dict_next.
+ */
+int dict_first(P1(const ref *pdref));
+
+/*
+ * Enumerate the next element of a dictionary.
+ * index is initially the result of a call on dict_first.
+ * Either store a key and value at eltp[0] and eltp[1]
+ * and return an updated index, or return -1
+ * to signal that there are no more elements in the dictionary.
+ */
+int dict_next(P3(const ref *pdref, int index, ref *eltp));
+
+/*
+ * Given a value pointer return by dict_find, return an index that
+ * identifies the entry within the dictionary. (This may, but need not,
+ * be the same as the index returned by dict_next.)
+ * The index is in the range [0..max_index-1].
+ */
+int dict_value_index(P2(const ref *pdref, const ref *pvalue));
+
+/*
+ * Given an index in [0..max_index-1], as returned by dict_value_index,
+ * return the key and value, as returned by dict_next.
+ * If the index designates an unoccupied entry, return e_undefined.
+ */
+int dict_index_entry(P3(const ref *pdref, int index, ref *eltp));
+
+/*
+ * The following are some internal details that are used in both the
+ * implementation and some high-performance clients.
+ */
+
+/* On machines with reasonable amounts of memory, we round up dictionary
+ * sizes to the next power of 2 whenever possible, to allow us to use
+ * masking rather than division for computing the hash index.
+ * Unfortunately, if we required this, it would cut the maximum size of a
+ * dictionary in half. Therefore, on such machines, we distinguish
+ * "huge" dictionaries (dictionaries whose size is larger than the largest
+ * power of 2 less than dict_max_size) as a special case:
+ *
+ * - If the top dictionary on the stack is huge, we set the dtop
+ * parameters so that the fast inline lookup will always fail.
+ *
+ * - For general lookup, we use the slower hash_mod algorithm for
+ * huge dictionaries.
+ */
+#define dict_max_non_huge ((uint)(max_array_size / 2 + 1))
+
+/* Hash an arbitrary non-negative or unsigned integer into a dictionary. */
+#define dict_hash_mod_rem(hash, size) ((hash) % (size))
+#define dict_hash_mod_mask(hash, size) ((hash) & ((size) - 1))
+#define dict_hash_mod_small(hash, size) dict_hash_mod_rem(hash, size)
+#define dict_hash_mod_inline_small(hash, size) dict_hash_mod_rem(hash, size)
+#define dict_hash_mod_large(hash, size)\
+ (size > dict_max_non_huge ? dict_hash_mod_rem(hash, size) :\
+ dict_hash_mod_mask(hash, size))
+#define dict_hash_mod_inline_large(hash, size) dict_hash_mod_mask(hash, size)
+/* Round up the requested size of a dictionary. Return 0 if too big. */
+uint dict_round_size_small(P1(uint rsize));
+uint dict_round_size_large(P1(uint rsize));
+/* Choose the algorithms depending on the size of memory. */
+#if arch_small_memory
+# define dict_hash_mod(h, s) dict_hash_mod_small(h, s)
+# define dict_hash_mod_inline(h, s) dict_hash_mod_inline_small(h, s)
+# define dict_round_size(s) dict_round_size_small(s)
+#else
+# ifdef DEBUG
+# define dict_hash_mod(h, s)\
+ (gs_debug_c('.') ? dict_hash_mod_small(h, s) :\
+ dict_hash_mod_large(h, s))
+# define dict_hash_mod_inline(h, s)\
+ (gs_debug_c('.') ? dict_hash_mod_inline_small(h, s) :\
+ dict_hash_mod_inline_large(h, s))
+# define dict_round_size(s)\
+ (gs_debug_c('.') ? dict_round_size_small(s) :\
+ dict_round_size_large(s))
+# else
+# define dict_hash_mod(h, s) dict_hash_mod_large(h, s)
+# define dict_hash_mod_inline(h, s) dict_hash_mod_inline_large(h, s)
+# define dict_round_size(s) dict_round_size_large(s)
+# endif
+#endif
diff --git a/gs/src/idparam.c b/gs/src/idparam.c
new file mode 100644
index 000000000..a2bc7ec79
--- /dev/null
+++ b/gs/src/idparam.c
@@ -0,0 +1,342 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idparam.c */
+/* Utilities for getting parameters out of dictionaries. */
+#include "memory_.h"
+#include "string_.h" /* for strlen */
+#include "ghost.h"
+#include "errors.h"
+#include "gsmatrix.h" /* for dict_matrix_param */
+#include "gsuid.h"
+#include "idict.h"
+#include "idparam.h" /* interface definition */
+#include "ilevel.h"
+#include "imemory.h" /* for iutil.h */
+#include "iname.h"
+#include "iutil.h"
+#include "oper.h" /* for check_proc */
+#include "store.h" /* for making empty proc */
+
+/* Get a Boolean parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if wrong type. */
+int
+dict_bool_param(const ref *pdict, const char _ds *kstr,
+ bool defaultval, bool *pvalue)
+{ ref *pdval;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { *pvalue = defaultval;
+ return 1;
+ }
+ if ( !r_has_type(pdval, t_boolean) )
+ return_error(e_typecheck);
+ *pvalue = pdval->value.boolval;
+ return 0;
+}
+
+/* Get an integer or null parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if invalid. */
+/* If the parameter is null, return 2 without setting *pvalue. */
+/* Note that the default value may be out of range, in which case */
+/* a missing value will return e_rangecheck rather than 1. */
+int
+dict_int_null_param(const ref *pdict, const char _ds *kstr, int minval,
+ int maxval, int defaultval, int *pvalue)
+{ ref *pdval;
+ int code;
+ long ival;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { ival = defaultval;
+ code = 1;
+ }
+ else
+ { switch ( r_type(pdval) )
+ {
+ case t_integer:
+ ival = pdval->value.intval;
+ break;
+ case t_real:
+ /* Allow an integral real, because Fontographer */
+ /* (which violates the Adobe specs in other ways */
+ /* as well) sometimes generates output that */
+ /* needs this. */
+ if ( pdval->value.realval < minval || pdval->value.realval > maxval )
+ return_error(e_rangecheck);
+ ival = (long)pdval->value.realval;
+ if ( ival != pdval->value.realval )
+ return_error(e_rangecheck);
+ break;
+ case t_null:
+ return 2;
+ default:
+ return_error(e_typecheck);
+ }
+ code = 0;
+ }
+ if ( ival < minval || ival > maxval )
+ return_error(e_rangecheck);
+ *pvalue = (int)ival;
+ return code;
+}
+/* Get an integer parameter from a dictionary. */
+/* Return like dict_int_null_param, but return e_typecheck for null. */
+int
+dict_int_param(const ref *pdict, const char _ds *kstr, int minval, int maxval,
+ int defaultval, int *pvalue)
+{ int code = dict_int_null_param(pdict, kstr, minval, maxval,
+ defaultval, pvalue);
+ return (code == 2 ? gs_note_error(e_typecheck) : code);
+}
+
+/* Get an unsigned integer parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if invalid. */
+/* Note that the default value may be out of range, in which case */
+/* a missing value will return e_rangecheck rather than 1. */
+int
+dict_uint_param(const ref *pdict, const char _ds *kstr,
+ uint minval, uint maxval, uint defaultval, uint *pvalue)
+{ ref *pdval;
+ int code;
+ uint ival;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { ival = defaultval;
+ code = 1;
+ }
+ else
+ { check_type_only(*pdval, t_integer);
+ if ( pdval->value.intval != (uint)pdval->value.intval )
+ return_error(e_rangecheck);
+ ival = (uint)pdval->value.intval;
+ code = 0;
+ }
+ if ( ival < minval || ival > maxval )
+ return_error(e_rangecheck);
+ *pvalue = ival;
+ return code;
+}
+
+/* Get a float parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if wrong type. */
+int
+dict_float_param(const ref *pdict, const char _ds *kstr,
+ floatp defaultval, float *pvalue)
+{ ref *pdval;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { *pvalue = defaultval;
+ return 1;
+ }
+ switch ( r_type(pdval) )
+ {
+ case t_integer: *pvalue = pdval->value.intval; return 0;
+ case t_real: *pvalue = pdval->value.realval; return 0;
+ }
+ return_error(e_typecheck);
+}
+
+/* Get an integer array from a dictionary. */
+/* Return the element count if OK, 0 if missing, <0 if invalid. */
+int
+dict_int_array_param(const ref *pdict, const char _ds *kstr,
+ uint maxlen, int *ivec)
+{ ref *pdval;
+ const ref *pa;
+ int *pi = ivec;
+ uint size;
+ int i;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ return 0;
+ if ( !r_has_type(pdval, t_array) )
+ return_error(e_typecheck);
+ size = r_size(pdval);
+ if ( size > maxlen )
+ return_error(e_limitcheck);
+ pa = pdval->value.const_refs;
+ for ( i = 0; i < size; i++, pa++, pi++ )
+ { /* See dict_int_param above for why we allow reals here. */
+ switch ( r_type(pa) )
+ {
+ case t_integer:
+ if ( pa->value.intval != (int)pa->value.intval )
+ return_error(e_rangecheck);
+ *pi = (int)pa->value.intval;
+ break;
+ case t_real:
+ if ( pa->value.realval < min_int ||
+ pa->value.realval > max_int ||
+ pa->value.realval != (int)pa->value.realval
+ )
+ return_error(e_rangecheck);
+ *pi = (int)pa->value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ return size;
+}
+
+/* Get a float array from a dictionary. */
+/* Return the element count if OK, <0 if invalid. */
+/* If the parameter is missing, then if defaultvec is NULL, return 0; */
+/* if defaultvec is not NULL, copy it into fvec (maxlen elements) */
+/* and return maxlen. */
+int
+dict_float_array_param(const ref *pdict, const char _ds *kstr,
+ uint maxlen, float *fvec, const float *defaultvec)
+{ ref *pdval;
+ uint size;
+ int code;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { if ( defaultvec == NULL ) return 0;
+ memcpy(fvec, defaultvec, maxlen * sizeof(float));
+ return maxlen;
+ }
+ if ( !r_has_type(pdval, t_array) )
+ return_error(e_typecheck);
+ size = r_size(pdval);
+ if ( size > maxlen )
+ return_error(e_limitcheck);
+ code = float_params(pdval->value.refs + size - 1, size, fvec);
+ return (code >= 0 ? size : code);
+}
+
+/*
+ * Get a procedure from a dictionary. If the key is missing,
+ * defaultval = false means substitute t__invalid;
+ * defaultval = true means substitute an empty procedure.
+ * In either case, return 1.
+ */
+int
+dict_proc_param(const ref *pdict, const char _ds *kstr, ref *pproc,
+ bool defaultval)
+{ ref *pdval;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ { if ( defaultval )
+ make_empty_const_array(pproc, a_readonly + a_executable);
+ else
+ make_t(pproc, t__invalid);
+ return 1;
+ }
+ check_proc(*pdval);
+ *pproc = *pdval;
+ return 0;
+}
+
+/* Get a matrix from a dictionary. */
+int
+dict_matrix_param(const ref *pdict, const char _ds *kstr, gs_matrix *pmat)
+{ ref *pdval;
+ if ( pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0 )
+ return_error(e_typecheck);
+ return read_matrix(pdval, pmat);
+}
+
+/* Get a UniqueID or XUID from a dictionary. */
+/* Return 0 if UniqueID, 1 if XUID, <0 if error. */
+/* If there is no uid, return default. */
+int
+dict_uid_param(const ref *pdict, gs_uid *puid, int defaultval,
+ gs_memory_t *mem)
+{ ref *puniqueid;
+ if ( pdict == 0 )
+ { uid_set_invalid(puid);
+ return defaultval;
+ }
+ /* In a Level 2 environment, check for XUID first. */
+ if ( level2_enabled &&
+ dict_find_string(pdict, "XUID", &puniqueid) > 0
+ )
+ { long *xvalues;
+ uint size, i;
+ if ( !r_has_type(puniqueid, t_array) )
+ return_error(e_typecheck);
+ size = r_size(puniqueid);
+ if ( size == 0 )
+ return_error(e_rangecheck);
+ xvalues = (long *)gs_alloc_byte_array(mem, size, sizeof(long),
+ "get XUID");
+ if ( xvalues == 0 )
+ return_error(e_VMerror);
+ /* Get the values from the XUID array. */
+ for ( i = 0; i < size; i++ )
+ { const ref *pvalue = puniqueid->value.const_refs + i;
+ if ( !r_has_type(pvalue, t_integer) )
+ { gs_free_object(mem, xvalues, "get XUID");
+ return_error(e_typecheck);
+ }
+ xvalues[i] = pvalue->value.intval;
+ }
+ uid_set_XUID(puid, xvalues, size);
+ return 1;
+ }
+ /* If no UniqueID entry, set the UID to invalid, */
+ /* because UniqueID need not be present in all fonts, */
+ /* and if it is, the legal range is 0 to 2^24-1. */
+ if ( dict_find_string(pdict, "UniqueID", &puniqueid) <= 0 )
+ { uid_set_invalid(puid);
+ return defaultval;
+ }
+ else
+ { if ( !r_has_type(puniqueid, t_integer) ||
+ puniqueid->value.intval < 0 ||
+ puniqueid->value.intval > 0xffffffL
+ )
+ return_error(e_rangecheck);
+ /* Apparently fonts created by Fontographer often have */
+ /* a UniqueID of 0, contrary to Adobe's specifications. */
+ /* Treat 0 as equivalent to -1 (no UniqueID). */
+ if ( puniqueid->value.intval == 0 )
+ { uid_set_invalid(puid);
+ return defaultval;
+ }
+ else
+ uid_set_UniqueID(puid, puniqueid->value.intval);
+ }
+ return 0;
+}
+
+/* Check that a UID in a dictionary is equal to an existing, valid UID. */
+bool
+dict_check_uid_param(const ref *pdict, const gs_uid *puid)
+{ ref *puniqueid;
+ if ( uid_is_XUID(puid) )
+ { uint size = uid_XUID_size(puid);
+ uint i;
+ if ( dict_find_string(pdict, "XUID", &puniqueid) <= 0 )
+ return false;
+ if ( !r_has_type(puniqueid, t_array) ||
+ r_size(puniqueid) != size
+ )
+ return false;
+ for ( i = 0; i < size; i++ )
+ { const ref *pvalue = puniqueid->value.const_refs + i;
+ if ( !r_has_type(pvalue, t_integer) )
+ return false;
+ if ( pvalue->value.intval != uid_XUID_values(puid)[i] )
+ return false;
+ }
+ return true;
+ }
+ else
+ { if ( dict_find_string(pdict, "UniqueID", &puniqueid) <= 0 )
+ return false;
+ return (r_has_type(puniqueid, t_integer) &&
+ puniqueid->value.intval == puid->id);
+ }
+}
+
diff --git a/gs/src/idparam.h b/gs/src/idparam.h
new file mode 100644
index 000000000..dc9c333ae
--- /dev/null
+++ b/gs/src/idparam.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* idparam.h */
+/* Interface to idparam.c */
+
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+
+#ifndef gs_uid_DEFINED
+# define gs_uid_DEFINED
+typedef struct gs_uid_s gs_uid;
+#endif
+
+/*
+ * Unless otherwise noted, all the following routines return 0 for
+ * a valid parameter, 1 for a defaulted parameter, or <0 on error.
+ *
+ * Note that all the dictionary parameter routines take a C string,
+ * not a t_name ref *. Even though this is slower, it means that
+ * the GC doesn't have to worry about finding statically declared
+ * name refs, and we have that many fewer static variables.
+ *
+ * All these routines allow pdict == NULL, which they treat the same as
+ * pdict referring to an empty dictionary. Routines with "null" in their
+ * name return 2 if the parameter is null, without setting *pvalue.
+ */
+int dict_bool_param(P4(const ref *pdict, const char _ds *kstr,
+ bool defaultval, bool *pvalue));
+int dict_int_param(P6(const ref *pdict, const char _ds *kstr,
+ int minval, int maxval, int defaultval, int *pvalue));
+int dict_int_null_param(P6(const ref *pdict, const char _ds *kstr,
+ int minval, int maxval, int defaultval,
+ int *pvalue));
+int dict_uint_param(P6(const ref *pdict, const char _ds *kstr,
+ uint minval, uint maxval, uint defaultval,
+ uint *pvalue));
+int dict_float_param(P4(const ref *pdict, const char _ds *kstr,
+ floatp defaultval, float *pvalue));
+int dict_int_array_param(P4(const ref *pdict, const char _ds *kstr,
+ uint maxlen, int *ivec));
+int dict_float_array_param(P5(const ref *pdict, const char _ds *kstr,
+ uint maxlen, float *fvec,
+ const float *defaultvec));
+/*
+ * For dict_proc_param,
+ * defaultval = false means substitute t__invalid;
+ * defaultval = true means substitute an empty procedure.
+ * In either case, return 1.
+ */
+int dict_proc_param(P4(const ref *pdict, const char _ds *kstr, ref *pproc,
+ bool defaultval));
+int dict_matrix_param(P3(const ref *pdict, const char _ds *kstr,
+ gs_matrix *pmat));
+int dict_uid_param(P4(const ref *pdict, gs_uid *puid, int defaultval,
+ gs_memory_t *mem));
+/* Check that a UID in a dictionary is equal to an existing, valid UID. */
+bool dict_check_uid_param(P2(const ref *pdict, const gs_uid *puid));
diff --git a/gs/src/ifilter.h b/gs/src/ifilter.h
new file mode 100644
index 000000000..97f5255e6
--- /dev/null
+++ b/gs/src/ifilter.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ifilter.h */
+/* Filter creation utilities for Ghostscript */
+/* Requires oper.h, stream.h, strimpl.h */
+#include "istream.h"
+#include "ivmspace.h"
+
+/*
+ * Define the utility procedures for creating filters.
+ * Note that a filter will be allocated in global VM iff the source/target
+ * and all relevant parameters (if any) are in global VM.
+ */
+int filter_read(P5(
+ /* Operand stack pointer that was passed to zfxxx operator */
+ os_ptr op,
+ /* # of parameters to pop off o-stack, */
+ /* not counting the source/target */
+ int npop,
+ /* Template for stream */
+ const stream_template *template,
+ /* Initialized s_xxx_state, 0 if no separate state */
+ stream_state *st,
+ /* Max of space attributes of all parameters referenced by */
+ /* the state, 0 if no such parameters */
+ uint space
+ ));
+int filter_write(P5(os_ptr op, int npop, const stream_template *template,
+ stream_state *st, uint space));
+/*
+ * Define a simplified interface for streams with no parameters or state.
+ * These procedures also pop the top o-stack element if it is a dictionary.
+ */
+int filter_read_simple(P2(os_ptr op, const stream_template *template));
+int filter_write_simple(P2(os_ptr op, const stream_template *template));
+
+/* Mark a filter stream as temporary. */
+/* See stream.h for the meaning of is_temp. */
+void filter_mark_temp(P2(const ref *fop, int is_temp));
+
+/*
+ * Define the state of a procedure-based stream.
+ * Note that procedure-based streams are defined at the Ghostscript
+ * interpreter level, unlike all other stream types which depend only
+ * on the stream package and the memory manager.
+ */
+typedef struct stream_proc_state_s {
+ stream_state_common;
+ bool eof;
+ uint index; /* current index within data */
+ ref proc;
+ ref data;
+} stream_proc_state;
+#define private_st_stream_proc_state() /* in zfproc.c */\
+ gs_private_st_complex_only(st_sproc_state, stream_proc_state,\
+ "procedure stream state", sproc_clear_marks, sproc_enum_ptrs, sproc_reloc_ptrs, 0)
diff --git a/gs/src/ifont.h b/gs/src/ifont.h
new file mode 100644
index 000000000..d274af0bb
--- /dev/null
+++ b/gs/src/ifont.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 1989, 1991, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ifont.h */
+/* Interpreter internal font representation */
+
+#include "gsccode.h" /* for gs_glyph */
+#include "gsstruct.h" /* for extern_st */
+
+/* The external definition of fonts is given in the PostScript manual, */
+/* pp. 91-93. */
+
+/* The structure given below is 'client data' from the viewpoint */
+/* of the library. font-type objects (t_struct/st_font, "t_fontID") */
+/* point directly to a gs_font. */
+
+typedef struct font_data_s {
+ ref dict; /* font dictionary object */
+ ref BuildChar;
+ ref BuildGlyph;
+ ref Encoding;
+ ref CharStrings;
+ union _fs {
+ struct _f1 {
+ ref OtherSubrs; /* from Private dictionary */
+ ref Subrs; /* from Private dictionary */
+ ref GlobalSubrs; /* from Private dictionary, */
+ /* for Type 2 charstrings */
+ } type1;
+ struct _f42 {
+ ref sfnts;
+ } type42;
+ } u;
+} font_data;
+/*
+ * Even though the interpreter's part of the font data actually
+ * consists of refs, allocating it as refs tends to create sandbars;
+ * since it is always allocated and freed as a unit, we can treat it
+ * as an ordinary structure.
+ */
+/* st_font_data is exported for zdefault_make_font in zfont.c. */
+extern_st(st_font_data);
+#define public_st_font_data() /* in zfont2.c */\
+ gs_public_st_ref_struct(st_font_data, font_data, "font_data")
+#define pfont_data(pfont) ((font_data *)((pfont)->client_data))
+#define pfont_dict(pfont) (&pfont_data(pfont)->dict)
+
+/* Registered encodings, for the benefit of platform fonts, `seac', */
+/* and compiled font initialization. */
+/* This is a t_array ref that points to the encodings. */
+#define registered_Encodings_countof 5
+extern ref registered_Encodings;
+#define registered_Encoding(i) (registered_Encodings.value.refs[i])
+#define StandardEncoding registered_Encoding(0)
+
+/* Internal procedures shared between modules */
+
+/* In zchar.c */
+int font_bbox_param(P2(const ref *pfdict, double bbox[4]));
+
+/* In zfont.c */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+#endif
+int font_param(P2(const ref *pfdict, gs_font **ppfont));
+bool zfont_mark_glyph_name(P2(gs_glyph glyph, void *ignore_data));
diff --git a/gs/src/ifunc.h b/gs/src/ifunc.h
new file mode 100644
index 000000000..65cdd7a2c
--- /dev/null
+++ b/gs/src/ifunc.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ifunc.h */
+/* Internal interpreter interfaces for Functions */
+
+#ifndef ifunc_INCLUDED
+# define ifunc_INCLUDED
+
+/* Define build procedures for the various function types. */
+#define build_function_proc(proc)\
+ int proc(P4(const_os_ptr op, const gs_function_params_t *params, int depth,\
+ gs_function_t **ppfn))
+build_function_proc(build_function_undefined);
+
+/* Define the table of build procedures, indexed by FunctionType. */
+extern build_function_proc((*build_function_procs[5]));
+
+/* Build a function structure from a PostScript dictionary. */
+int fn_build_sub_function(P3(const ref *op, gs_function_t **ppfn, int depth));
+#define fn_build_function(op, ppfn)\
+ fn_build_sub_function(op, ppfn, 0)
+
+/* Allocate an array of function objects. */
+int ialloc_function_array(P2(uint count, gs_function_t ***pFunctions));
+
+/* Collect a heap-allocated array of floats. */
+/* If the key is missing, set *pparray = 0 and return 0; */
+/* otherwise set *pparray and return the number of elements. */
+int fn_build_float_array(P5(const ref *op, const char _ds *kstr, bool required,
+ bool even, const float **pparray));
+
+#endif /* ifunc_INCLUDED */
diff --git a/gs/src/igc.c b/gs/src/igc.c
new file mode 100644
index 000000000..f1a365e36
--- /dev/null
+++ b/gs/src/igc.c
@@ -0,0 +1,1249 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igc.c */
+/* Garbage collector for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "iastate.h"
+#include "isave.h"
+#include "isstate.h"
+#include "idict.h"
+#include "ipacked.h"
+#include "istruct.h"
+#include "igc.h"
+#include "igcstr.h"
+#include "inamedef.h"
+#include "opdef.h" /* for marking oparray names */
+
+/* Define whether to force all garbage collections to be global. */
+private bool force_global_gc = false;
+
+/* Define whether to bypass the collector entirely. */
+private bool bypass_gc = false;
+
+/* Define an entry on the mark stack. */
+typedef struct { void *ptr; uint index; bool is_refs; } ms_entry;
+
+/* Define (a segment of) the mark stack. */
+/* entries[0] has ptr = 0 to indicate the bottom of the stack. */
+/* count additional entries follow this structure. */
+typedef struct gc_mark_stack_s gc_mark_stack;
+struct gc_mark_stack_s {
+ gc_mark_stack *prev;
+ gc_mark_stack *next;
+ uint count;
+ bool on_heap; /* if true, allocated with gs_malloc */
+ ms_entry entries[1];
+};
+/* Define the mark stack sizing parameters. */
+#define ms_size_default 100 /* default, allocated on C stack */
+/* This should probably be defined as a parameter somewhere.... */
+#define ms_size_desired /* for gs_malloc */\
+ ((max_ushort - sizeof(gc_mark_stack)) / sizeof(ms_entry) - 10)
+#define ms_size_min 50 /* min size for segment in free block */
+
+/* Forward references */
+private void gc_init_mark_stack(P2(gc_mark_stack *, uint));
+private void gc_objects_clear_marks(P1(chunk_t *));
+private void gc_unmark_names(P0());
+private int gc_trace(P3(gs_gc_root_t *, gc_state_t *, gc_mark_stack *));
+private int gc_rescan_chunk(P3(chunk_t *, gc_state_t *, gc_mark_stack *));
+private int gc_trace_chunk(P3(chunk_t *, gc_state_t *, gc_mark_stack *));
+private bool gc_trace_finish(P1(gc_state_t *));
+private void gc_clear_reloc(P1(chunk_t *));
+private void gc_objects_set_reloc(P1(chunk_t *));
+private void gc_do_reloc(P3(chunk_t *, gs_ref_memory_t *, gc_state_t *));
+private void gc_objects_compact(P2(chunk_t *, gc_state_t *));
+private void gc_free_empty_chunks(P1(gs_ref_memory_t *));
+
+/* Forward references for pointer types */
+private ptr_proc_unmark(ptr_struct_unmark);
+private ptr_proc_mark(ptr_struct_mark);
+private ptr_proc_unmark(ptr_string_unmark);
+private ptr_proc_mark(ptr_string_mark);
+/*ptr_proc_unmark(ptr_ref_unmark);*/ /* in igc.h */
+/*ptr_proc_mark(ptr_ref_mark);*/ /* in igc.h */
+/*ptr_proc_reloc(gs_reloc_struct_ptr, void);*/ /* in gsstruct.h */
+/*ptr_proc_reloc(gs_reloc_ref_ptr, ref_packed);*/ /* in istruct.h */
+
+/* Pointer type descriptors. */
+/* Note that the trace/mark routine has special knowledge of ptr_ref_type */
+/* and ptr_struct_type -- it assumes that no other types have embedded */
+/* pointers. Note also that the reloc procedures for string and ref */
+/* pointers are never called. */
+typedef ptr_proc_reloc((*ptr_proc_reloc_t), void);
+const gs_ptr_procs_t ptr_struct_procs =
+ { ptr_struct_unmark, ptr_struct_mark, (ptr_proc_reloc_t)gs_reloc_struct_ptr };
+const gs_ptr_procs_t ptr_string_procs =
+ { ptr_string_unmark, ptr_string_mark, NULL };
+const gs_ptr_procs_t ptr_const_string_procs =
+ { ptr_string_unmark, ptr_string_mark, NULL };
+const gs_ptr_procs_t ptr_ref_procs =
+ { ptr_ref_unmark, ptr_ref_mark, NULL };
+
+/* ------ Main program ------ */
+
+/* Top level of garbage collector. */
+#ifdef DEBUG
+private void
+end_phase(const char _ds *str)
+{ if ( gs_debug_c('6') )
+ { dprintf1("[6]---------------- end %s ----------------\n",
+ (const char *)str);
+ fflush(dstderr);
+ }
+}
+static const char *depth_dots_string = "..........";
+private const char *
+depth_dots_proc(const ms_entry *sp, const gc_mark_stack *pms)
+{ int depth = sp - pms->entries - 1;
+ const gc_mark_stack *pss = pms;
+
+ while ( (pss = pss->prev) != 0 )
+ depth += pss->count - 1;
+ return depth_dots_string + (depth >= 10 ? 0 : 10 - depth);
+}
+#else
+# define end_phase(str) DO_NOTHING
+#endif
+void
+gs_reclaim(vm_spaces *pspaces, bool global)
+{ vm_spaces spaces;
+#define nspaces (i_vm_max + 1)
+ gs_gc_root_t space_roots[nspaces];
+ int max_trace; /* max space to trace */
+ int min_collect; /* min space to collect */
+ int ispace;
+ gs_ref_memory_t *mem;
+ chunk_t *cp;
+ gs_gc_root_t *rp;
+ gc_state_t state;
+ struct _msd {
+ gc_mark_stack stack;
+ ms_entry body[ms_size_default];
+ } ms_default;
+ gc_mark_stack *mark_stack = &ms_default.stack;
+
+ /* Optionally force global GC for debugging. */
+ if ( force_global_gc )
+ global = true;
+
+ /* Determine which spaces we are collecting. */
+ spaces = *pspaces;
+ if ( space_global != space_local )
+ max_trace = i_vm_local;
+ else
+ max_trace = i_vm_global;
+ min_collect = (global ? 1 : max_trace);
+
+#define for_spaces(i, n)\
+ for ( i = 1; i <= n; ++i )
+#define for_collected_spaces(i)\
+ for ( i = min_collect; i <= max_trace; ++i )
+#define for_space_mems(i, mem)\
+ for ( mem = spaces.indexed[i]; mem != 0; mem = &mem->saved->state )
+#define for_mem_chunks(mem, cp)\
+ for ( cp = (mem)->cfirst; cp != 0; cp = cp->cnext )
+#define for_space_chunks(i, mem, cp)\
+ for_space_mems(i, mem) for_mem_chunks(mem, cp)
+#define for_chunks(n, mem, cp)\
+ for_spaces(ispace, n) for_space_chunks(ispace, mem, cp)
+#define for_collected_chunks(mem, cp)\
+ for_collected_spaces(ispace) for_space_chunks(ispace, mem, cp)
+#define for_roots(n, mem, rp)\
+ for_spaces(ispace, n)\
+ for ( mem = spaces.indexed[ispace], rp = mem->roots; rp != 0; rp = rp->next )
+
+ /* Initialize the state. */
+ state.loc.memory = spaces.named.global; /* any one will do */
+ state.loc.cp = 0;
+ state.spaces = spaces;
+ state.min_collect = min_collect << r_space_shift;
+ state.relocating_untraced = false;
+
+ /* Register the allocators themselves as roots, */
+ /* so we mark and relocate the change and save lists properly. */
+
+ for_spaces(ispace, max_trace)
+ gs_register_struct_root((gs_memory_t *)spaces.indexed[ispace],
+ &space_roots[ispace],
+ (void **)&spaces.indexed[ispace],
+ "gc_top_level");
+
+ end_phase("register space roots");
+
+#ifdef DEBUG
+
+ /* Pre-validate the state. This shouldn't be necessary.... */
+
+ for_spaces(ispace, max_trace)
+ ialloc_validate_memory(spaces.indexed[ispace], &state);
+
+ end_phase("pre-validate pointers");
+
+#endif
+
+ if ( bypass_gc )
+ { /* Don't collect at all. */
+ goto no_collect;
+ }
+
+ /* Clear marks in spaces to be collected. */
+
+ for_collected_spaces(ispace)
+ for_space_chunks(ispace, mem, cp)
+ { gc_objects_clear_marks(cp);
+ gc_strings_set_marks(cp, false);
+ }
+
+ end_phase("clear chunk marks");
+
+ /* Clear the marks of roots. We must do this explicitly, */
+ /* since some roots are not in any chunk. */
+
+ for_roots(max_trace, mem, rp)
+ { void *vptr = *rp->p;
+ if_debug_root('6', "[6]unmarking root", rp);
+ (*rp->ptype->unmark)(vptr, &state);
+ }
+
+ end_phase("clear root marks");
+
+ if ( global )
+ gc_unmark_names();
+
+ /* Initialize the (default) mark stack. */
+
+ gc_init_mark_stack(&ms_default.stack, ms_size_default);
+ ms_default.stack.prev = 0;
+ ms_default.stack.on_heap = false;
+
+ /* Add all large-enough free blocks to the mark stack. */
+ /* Also initialize the rescan pointers. */
+
+ { gc_mark_stack *end = mark_stack;
+ for_chunks(max_trace, mem, cp)
+ { uint avail = cp->ctop - cp->cbot;
+ if ( avail >= sizeof(gc_mark_stack) + sizeof(ms_entry) *
+ ms_size_min &&
+ !cp->inner_count
+ )
+ { gc_mark_stack *pms = (gc_mark_stack *)cp->cbot;
+ gc_init_mark_stack(pms, (avail - sizeof(gc_mark_stack)) /
+ sizeof(ms_entry));
+ end->next = pms;
+ pms->prev = end;
+ pms->on_heap = false;
+ if_debug2('6', "[6]adding free 0x%lx(%u) to mark stack\n",
+ (ulong)pms, pms->count);
+ }
+ cp->rescan_bot = cp->cend;
+ cp->rescan_top = cp->cbase;
+ }
+ }
+
+ /* Mark reachable objects. */
+
+ { int more = 0;
+
+ /* Mark from roots. */
+
+ for_roots(max_trace, mem, rp)
+ { if_debug_root('6', "[6]marking root", rp);
+ more |= gc_trace(rp, &state, mark_stack);
+ }
+
+ end_phase("mark");
+
+ /* If this is a local GC, mark from non-local chunks. */
+
+ if ( !global )
+ for_chunks(min_collect - 1, mem, cp)
+ more |= gc_trace_chunk(cp, &state, mark_stack);
+
+ /* Handle mark stack overflow. */
+
+ while ( more < 0 ) /* stack overflowed */
+ { more = 0;
+ for_chunks(max_trace, mem, cp)
+ more |= gc_rescan_chunk(cp, &state, mark_stack);
+ }
+
+ end_phase("mark overflow");
+ }
+
+ /* Free the mark stack. */
+
+ { gc_mark_stack *pms = mark_stack;
+
+ while ( pms->next )
+ pms = pms->next;
+ while ( pms )
+ { gc_mark_stack *prev = pms->prev;
+ uint size = sizeof(*pms) + sizeof(ms_entry) * pms->count;
+
+ if ( pms->on_heap )
+ gs_free(pms, 1, size, "gc mark stack");
+ else
+ gs_alloc_fill(pms, gs_alloc_fill_free, size);
+ pms = prev;
+ }
+ }
+
+ end_phase("free mark stack");
+
+ if ( global )
+ {
+ gc_trace_finish(&state);
+ name_trace_finish(&state);
+
+ end_phase("finish trace");
+ }
+
+ /* Clear marks and relocation in spaces that are only being traced. */
+ /* We have to clear the marks first, because we want the */
+ /* relocation to wind up as o_untraced, not o_unmarked. */
+
+ for_chunks(min_collect - 1, mem, cp)
+ gc_objects_clear_marks(cp);
+
+ end_phase("post-clear marks");
+
+ for_chunks(min_collect - 1, mem, cp)
+ gc_clear_reloc(cp);
+
+ end_phase("clear reloc");
+
+ /* Set the relocation of roots outside any chunk to o_untraced, */
+ /* so we won't try to relocate pointers to them. */
+ /* (Currently, there aren't any.) */
+
+ /* Disable freeing in the allocators of the spaces we are */
+ /* collecting, so finalization procedures won't cause problems. */
+ { int i;
+ for_collected_spaces(i)
+ gs_enable_free((gs_memory_t *)spaces.indexed[i], false);
+ }
+
+ /* Compute relocation based on marks, in the spaces */
+ /* we are going to compact. Also finalize freed objects. */
+
+ for_collected_chunks(mem, cp)
+ { gc_objects_set_reloc(cp);
+ gc_strings_set_reloc(cp);
+ }
+
+ /* Re-enable freeing. */
+ { int i;
+ for_collected_spaces(i)
+ gs_enable_free((gs_memory_t *)spaces.indexed[i], true);
+ }
+
+ end_phase("set reloc");
+
+ /* Relocate pointers. */
+
+ state.relocating_untraced = true;
+ for_chunks(min_collect - 1, mem, cp)
+ gc_do_reloc(cp, mem, &state);
+ state.relocating_untraced = false;
+ for_collected_chunks(mem, cp)
+ gc_do_reloc(cp, mem, &state);
+
+ end_phase("relocate chunks");
+
+ for_roots(max_trace, mem, rp)
+ { if_debug3('6', "[6]relocating root 0x%lx: 0x%lx -> 0x%lx\n",
+ (ulong)rp, (ulong)rp->p, (ulong)*rp->p);
+ if ( rp->ptype == ptr_ref_type )
+ { ref *pref = (ref *)*rp->p;
+ gs_reloc_refs((ref_packed *)pref,
+ (ref_packed *)(pref + 1),
+ &state);
+ }
+ else
+ *rp->p = (*rp->ptype->reloc)(*rp->p, &state);
+ if_debug3('6', "[6]relocated root 0x%lx: 0x%lx -> 0x%lx\n",
+ (ulong)rp, (ulong)rp->p, (ulong)*rp->p);
+ }
+
+ end_phase("relocate roots");
+
+ /* Compact data. We only do this for spaces we are collecting. */
+
+ for_collected_spaces(ispace)
+ { for_space_mems(ispace, mem)
+ { for_mem_chunks(mem, cp)
+ { if_debug_chunk('6', "[6]compacting chunk", cp);
+ gc_objects_compact(cp, &state);
+ gc_strings_compact(cp);
+ if_debug_chunk('6', "[6]after compaction:", cp);
+ if ( mem->pcc == cp )
+ mem->cc = *cp;
+ }
+ mem->saved = mem->reloc_saved;
+ ialloc_reset_free(mem);
+ }
+ }
+
+ end_phase("compact");
+
+ /* Free empty chunks. */
+
+ for_collected_spaces(ispace)
+ for_space_mems(ispace, mem)
+ gc_free_empty_chunks(mem);
+
+ end_phase("free empty chunks");
+
+ /*
+ * Update previous_status to reflect any freed chunks,
+ * and set inherited to the negative of allocated,
+ * so it has no effect. We must update previous_status by
+ * working back-to-front along the save chain, using pointer reversal.
+ * (We could update inherited in any order, since it only uses
+ * information local to the individual save level.)
+ */
+
+ for_collected_spaces(ispace)
+ { /* Reverse the pointers. */
+ alloc_save_t *curr;
+ alloc_save_t *prev = 0;
+ alloc_save_t *next;
+ gs_memory_status_t total;
+
+ for ( curr = spaces.indexed[ispace]->saved; curr != 0;
+ prev = curr, curr = next
+ )
+ { next = curr->state.saved;
+ curr->state.saved = prev;
+ }
+ /* Now work the other way, accumulating the values. */
+ total.allocated = 0, total.used = 0;
+ for ( curr = prev, prev = 0; curr != 0;
+ prev = curr, curr = next
+ )
+ { mem = &curr->state;
+ next = mem->saved;
+ mem->saved = prev;
+ mem->previous_status = total;
+ if_debug3('6',
+ "[6]0x%lx previous allocated=%lu, used=%lu\n",
+ (ulong)mem, total.allocated, total.used);
+ gs_memory_status((gs_memory_t *)mem, &total);
+ mem->gc_allocated = mem->allocated + total.allocated;
+ mem->inherited = -mem->allocated;
+ }
+ mem = spaces.indexed[ispace];
+ mem->previous_status = total;
+ mem->gc_allocated = mem->allocated + total.allocated;
+ if_debug3('6', "[6]0x%lx previous allocated=%lu, used=%lu\n",
+ (ulong)mem, total.allocated, total.used);
+ }
+
+ end_phase("update stats");
+
+no_collect:
+
+ /* Unregister the allocator roots. */
+
+ for_spaces(ispace, max_trace)
+ gs_unregister_root((gs_memory_t *)spaces.indexed[ispace],
+ &space_roots[ispace], "gc_top_level");
+
+ end_phase("unregister space roots");
+
+#ifdef DEBUG
+
+ /* Validate the state. This shouldn't be necessary.... */
+
+ for_spaces(ispace, max_trace)
+ ialloc_validate_memory(spaces.indexed[ispace], &state);
+
+ end_phase("validate pointers");
+
+#endif
+}
+
+/* ------ Debugging utilities ------ */
+
+/* Validate a pointer to an object header. */
+#ifdef DEBUG
+# define debug_check_object(pre, cp, gcst)\
+ ialloc_validate_object((pre) + 1, cp, gcst)
+#else
+# define debug_check_object(pre, cp, gcst) DO_NOTHING
+#endif
+
+/* ------ Unmarking phase ------ */
+
+/* Unmark a single struct. */
+private void
+ptr_struct_unmark(void *vptr, gc_state_t *ignored)
+{ if ( vptr != 0 )
+ o_set_unmarked(((obj_header_t *)vptr - 1));
+}
+
+/* Unmark a single string. */
+private void
+ptr_string_unmark(void *vptr, gc_state_t *gcst)
+{ discard(gc_string_mark(((gs_string *)vptr)->data,
+ ((gs_string *)vptr)->size,
+ false, gcst));
+}
+
+/* Unmark the objects in a chunk. */
+private void
+gc_objects_clear_marks(chunk_t *cp)
+{ if_debug_chunk('6', "[6]unmarking chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+#ifdef DEBUG
+ if ( pre->o_type != &st_free )
+ debug_check_object(pre, cp, NULL);
+#endif
+ if_debug3('7', " [7](un)marking %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)size, (ulong)pre);
+ o_set_unmarked(pre);
+ if ( proc != 0 )
+ (*proc)(pre + 1, size);
+ END_OBJECTS_SCAN
+}
+
+/* Mark 0- and 1-character names, and those referenced from the */
+/* op_array_nx_table, and unmark all the rest. */
+private void
+gc_unmark_names(void)
+{ register uint i;
+ name_unmark_all();
+ for ( i = 0; i < op_array_table_global.count; i++ )
+ { uint nidx = op_array_table_global.nx_table[i];
+ name_index_ptr(nidx)->mark = 1;
+ }
+ for ( i = 0; i < op_array_table_local.count; i++ )
+ { uint nidx = op_array_table_local.nx_table[i];
+ name_index_ptr(nidx)->mark = 1;
+ }
+}
+
+/* ------ Marking phase ------ */
+
+/* Initialize (a segment of) the mark stack. */
+private void
+gc_init_mark_stack(gc_mark_stack *pms, uint count)
+{ pms->next = 0;
+ pms->count = count;
+ pms->entries[0].ptr = 0;
+ pms->entries[0].index = 0;
+ pms->entries[0].is_refs = false;
+}
+
+/* Mark starting from all marked objects in the interval of a chunk */
+/* needing rescanning. */
+private int
+gc_rescan_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack)
+{ byte *sbot = cp->rescan_bot;
+ byte *stop = cp->rescan_top;
+ gs_gc_root_t root;
+ void *comp;
+ int more = 0;
+
+ if ( sbot > stop )
+ return 0;
+ root.p = &comp;
+ if_debug_chunk('6', "[6]rescanning chunk", cp);
+ cp->rescan_bot = cp->cend;
+ cp->rescan_top = cp->cbase;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if ( (byte *)(pre + 1) + size < sbot )
+ ;
+ else if ( (byte *)(pre + 1) > stop )
+ return more; /* 'break' won't work here */
+ else
+ { if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
+ (ulong)pre, (ulong)size);
+ if ( pre->o_type == &st_refs )
+ { ref_packed *rp = (ref_packed *)(pre + 1);
+ char *end = (char *)rp + size;
+ root.ptype = ptr_ref_type;
+ while ( (char *)rp < end )
+ { comp = rp;
+ if ( r_is_packed(rp) )
+ { if ( r_has_pmark(rp) )
+ { r_clear_pmark(rp);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp++;
+ }
+ else
+ { if ( r_has_attr((ref *)rp, l_mark) )
+ { r_clear_attrs((ref *)rp, l_mark);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ }
+ else if ( !o_is_unmarked(pre) )
+ { struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+ root.ptype = ptr_struct_type;
+ comp = pre + 1;
+ if ( !o_is_untraced(pre) )
+ o_set_unmarked(pre);
+ if ( proc != 0 )
+ (*proc)(comp, size);
+ more |= gc_trace(&root, pstate, pmstack);
+ }
+ }
+ END_OBJECTS_SCAN
+ return more;
+}
+
+/* Mark starting from all the objects in a chunk. */
+/* We assume that pstate->min_collect > avm_system, */
+/* so we don't have to trace names. */
+private int
+gc_trace_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack)
+{ gs_gc_root_t root;
+ void *comp;
+ int more = 0;
+ int min_trace = pstate->min_collect;
+
+ root.p = &comp;
+ if_debug_chunk('6', "[6]marking from chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ { if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
+ (ulong)pre, (ulong)size);
+ if ( pre->o_type == &st_refs )
+ { ref_packed *rp = (ref_packed *)(pre + 1);
+ char *end = (char *)rp + size;
+
+ root.ptype = ptr_ref_type;
+ while ( (char *)rp < end )
+ { comp = rp;
+ if ( r_is_packed(rp) )
+ { /* No packed refs need tracing. */
+ rp++;
+ }
+ else
+ { if ( r_space((ref *)rp) >= min_trace )
+ { r_clear_attrs((ref *)rp, l_mark);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ }
+ else if ( !o_is_unmarked(pre) )
+ { if ( !o_is_untraced(pre) )
+ o_set_unmarked(pre);
+ if ( pre->o_type != &st_free )
+ { struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+
+ root.ptype = ptr_struct_type;
+ comp = pre + 1;
+ if ( proc != 0 )
+ (*proc)(comp, size);
+ more |= gc_trace(&root, pstate, pmstack);
+ }
+ }
+ }
+ END_OBJECTS_SCAN
+ return more;
+}
+
+/* Recursively mark from a (root) pointer. */
+/* Return -1 if we overflowed the mark stack, */
+/* 0 if we completed successfully without marking any new objects, */
+/* 1 if we completed and marked some new objects. */
+private int gc_extend_stack(P2(gc_mark_stack *, gc_state_t *));
+private int
+gc_trace(gs_gc_root_t *rp, gc_state_t *pstate, gc_mark_stack *pmstack)
+{ int min_trace = pstate->min_collect;
+ gc_mark_stack *pms = pmstack;
+ ms_entry *sp = pms->entries + 1;
+ /* We stop the mark stack 1 entry early, because we store into */
+ /* the entry beyond the top. */
+ ms_entry *stop = sp + pms->count - 2;
+#ifdef DEBUG
+# define depth_dots depth_dots_proc(sp, pms)
+#endif
+ int new = 0;
+ void *nptr = *rp->p;
+#define mark_name(nidx, pname)\
+ { if ( !pname->mark )\
+ { pname->mark = 1;\
+ new |= 1;\
+ if_debug2('8', " [8]marked name 0x%lx(%u)\n", (ulong)pname, nidx);\
+ }\
+ }
+
+ if ( nptr == 0 )
+ return 0;
+
+ /* Initialize the stack */
+ sp->ptr = nptr;
+ if ( rp->ptype == ptr_ref_type )
+ sp->index = 1, sp->is_refs = true;
+ else
+ { sp->index = 0, sp->is_refs = false;
+ if ( (*rp->ptype->mark)(nptr, pstate) )
+ new |= 1;
+ }
+ for ( ; ; )
+ { gs_ptr_type_t ptp;
+ /*
+ * The following should really be an if..else, but that
+ * would force unnecessary is_refs tests.
+ */
+ if ( sp->is_refs )
+ goto do_refs;
+
+ /* ---------------- Structure ---------------- */
+
+do_struct:
+ { obj_header_t *ptr = sp->ptr;
+ struct_proc_enum_ptrs((*mproc));
+
+ if ( ptr == 0 )
+ { /* We've reached the bottom of a stack segment. */
+ pms = pms->prev;
+ if ( pms == 0 )
+ break; /* all done */
+ stop = pms->entries + pms->count - 1;
+ sp = stop;
+ continue;
+ }
+ debug_check_object(ptr - 1, NULL, NULL);
+ts: if_debug4('7', " [7]%smarking %s 0x%lx[%u]",
+ depth_dots,
+ struct_type_name_string(ptr[-1].o_type),
+ (ulong)ptr, sp->index);
+ mproc = ptr[-1].o_type->enum_ptrs;
+ /* The cast in the following statement is the one */
+ /* place we need to break 'const' to make the */
+ /* template for pointer enumeration work. */
+ if ( mproc == 0 ||
+ (ptp = (*mproc)
+ (ptr, pre_obj_contents_size(ptr - 1),
+ sp->index, (const void **)&nptr)) == 0
+ )
+ { if_debug0('7', " - done\n");
+ sp--;
+ continue;
+ }
+ sp->index++;
+ if_debug1('7', " = 0x%lx\n", (ulong)nptr);
+ /* Descend into nptr, whose pointer type is ptp. */
+ if ( ptp == ptr_struct_type )
+ { sp[1].index = 0;
+ sp[1].is_refs = false;
+ if ( sp == stop )
+ goto push;
+ if ( !ptr_struct_mark(nptr, pstate) )
+ goto ts;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_struct;
+ }
+ else if ( ptp == ptr_ref_type )
+ { sp[1].index = 1;
+ sp[1].is_refs = true;
+ if ( sp == stop )
+ goto push;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_refs;
+ }
+ else
+ { /* We assume this is some non-pointer- */
+ /* containing type. */
+ if ( (*ptp->mark)(nptr, pstate) )
+ new |= 1;
+ goto ts;
+ }
+ }
+
+ /* ---------------- Refs ---------------- */
+
+do_refs:
+ { ref_packed *pptr = sp->ptr;
+
+tr: if ( !sp->index )
+ { --sp;
+ continue;
+ }
+ --(sp->index);
+ if_debug3('8', " [8]%smarking refs 0x%lx[%u]\n",
+ depth_dots, (ulong)pptr, sp->index);
+#define rptr ((ref *)pptr)
+ if ( r_is_packed(rptr) )
+ { if ( !r_has_pmark(pptr) )
+ { r_set_pmark(pptr);
+ new |= 1;
+ if ( r_packed_is_name(pptr) )
+ { uint nidx = packed_name_index(pptr);
+ name *pname = name_index_ptr(nidx);
+ mark_name(nidx, pname);
+ }
+ }
+ ++pptr;
+ goto tr;
+ }
+ if ( r_has_attr(rptr, l_mark) )
+ { pptr = (ref_packed *)(rptr + 1);
+ goto tr;
+ }
+ r_set_attrs(rptr, l_mark);
+ new |= 1;
+ if ( r_space(rptr) < min_trace )
+ { /* Note that this always picks up all scalars. */
+ pptr = (ref_packed *)(rptr + 1);
+ goto tr;
+ }
+ sp->ptr = rptr + 1;
+ switch ( r_type(rptr) )
+ {
+ /* Struct cases */
+ case t_file:
+ nptr = rptr->value.pfile;
+rs: sp[1].is_refs = false;
+ sp[1].index = 0;
+ if ( sp == stop )
+ { ptp = ptr_struct_type;
+ break;
+ }
+ if ( !ptr_struct_mark(nptr, pstate) )
+ goto nr;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_struct;
+ case t_device:
+ nptr = rptr->value.pdevice;
+ goto rs;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ nptr = rptr->value.pstruct;
+ goto rs;
+ /* Non-trivial non-struct cases */
+ case t_dictionary:
+ nptr = rptr->value.pdict;
+ sp[1].index = sizeof(dict) / sizeof(ref);
+ goto rrp;
+ case t_array:
+ nptr = rptr->value.refs;
+rr: if ( (sp[1].index = r_size(rptr)) == 0 )
+ { /* Set the base pointer to 0, */
+ /* so we never try to relocate it. */
+ rptr->value.refs = 0;
+ goto nr;
+ }
+rrp:
+rrc: sp[1].is_refs = true;
+ if ( sp == stop )
+ break;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_refs;
+ case t_mixedarray: case t_shortarray:
+ nptr = (void *)rptr->value.packed; /* discard const */
+ goto rr;
+ case t_name:
+ mark_name(name_index(rptr), rptr->value.pname);
+nr: pptr = (ref_packed *)(rptr + 1);
+ goto tr;
+ case t_string:
+ if ( gc_string_mark(rptr->value.bytes, r_size(rptr), true, pstate) )
+ new |= 1;
+ goto nr;
+ case t_oparray:
+ nptr = (void *)rptr->value.const_refs; /* discard const */
+ sp[1].index = 1;
+ goto rrc;
+ default:
+ goto nr;
+ }
+#undef rptr
+ }
+
+ /* ---------------- Recursion ---------------- */
+
+push:
+ if ( sp == stop )
+ { /* The current segment is full. */
+ int new_added = gc_extend_stack(pms, pstate);
+ if ( new_added )
+ { new |= new_added;
+ continue;
+ }
+ pms = pms->next;
+ stop = pms->entries + pms->count - 1;
+ pms->entries[1] = sp[1];
+ sp = pms->entries;
+ }
+ /* index and is_refs are already set */
+ if ( !sp[1].is_refs )
+ { if ( !(*ptp->mark)(nptr, pstate) )
+ continue;
+ new |= 1;
+ }
+ (++sp)->ptr = nptr;
+ }
+ return new;
+}
+/* Link to, attempting to allocate if necessary, */
+/* another chunk of mark stack. */
+private int
+gc_extend_stack(gc_mark_stack *pms, gc_state_t *pstate)
+{ if ( pms->next == 0 )
+ { /* Try to allocate another segment. */
+ uint count;
+
+ for ( count = ms_size_desired; count >= ms_size_min; count >>= 1 )
+ { pms->next =
+ gs_malloc(1, sizeof(gc_mark_stack) +
+ sizeof(ms_entry) * count,
+ "gc mark stack");
+ if ( pms->next != 0 )
+ break;
+ }
+ if ( pms->next == 0 )
+ { /* The mark stack overflowed. */
+ ms_entry *sp = pms->entries + pms->count - 1;
+ byte *cptr = sp->ptr; /* container */
+ chunk_t *cp = gc_locate(cptr, pstate);
+ int new = 1;
+
+ if ( cp == 0 )
+ { /* We were tracing outside collectible */
+ /* storage. This can't happen. */
+ lprintf1("mark stack overflowed while outside collectible space at 0x%lx!\n",
+ (ulong)cptr);
+ gs_abort();
+ }
+ if ( cptr < cp->rescan_bot )
+ cp->rescan_bot = cptr, new = -1;
+ if ( cptr > cp->rescan_top )
+ cp->rescan_top = cptr, new = -1;
+ return new;
+ }
+ gc_init_mark_stack(pms->next, count);
+ pms->next->prev = pms;
+ pms->next->on_heap = true;
+ }
+ return 0;
+}
+
+/* Mark a struct. Return true if new mark. */
+private bool
+ptr_struct_mark(void *vptr, gc_state_t *ignored)
+{ obj_header_t *ptr = vptr;
+ if ( vptr == 0 )
+ return false;
+ ptr--; /* point to header */
+ if ( !o_is_unmarked(ptr) )
+ return false;
+ o_mark(ptr);
+ return true;
+}
+
+/* Mark a string. Return true if new mark. */
+private bool
+ptr_string_mark(void *vptr, gc_state_t *gcst)
+{ return gc_string_mark(((gs_string *)vptr)->data,
+ ((gs_string *)vptr)->size,
+ true, gcst);
+}
+
+/* Finish tracing by marking names. */
+private bool
+gc_trace_finish(gc_state_t *pstate)
+{ uint nidx = 0;
+ bool marked = false;
+ while ( (nidx = name_next_valid_index(nidx)) != 0 )
+ { name *pname = name_index_ptr(nidx);
+ if ( pname->mark )
+ { if ( !pname->foreign_string && gc_string_mark(pname->string_bytes, pname->string_size, true, pstate) )
+ marked = true;
+ marked |= ptr_struct_mark(name_index_ptr_sub_table(nidx, pname), pstate);
+ }
+ }
+ return marked;
+}
+
+/* ------ Relocation planning phase ------ */
+
+/* Initialize the relocation information in the chunk header. */
+private void
+gc_init_reloc(chunk_t *cp)
+{ chunk_head_t *chead = cp->chead;
+ chead->dest = cp->cbase;
+ chead->free.o_back =
+ offset_of(chunk_head_t, free) >> obj_back_shift;
+ chead->free.o_size = sizeof(obj_header_t);
+ chead->free.o_nreloc = 0;
+}
+
+/* Set marks and clear relocation for chunks that won't be compacted. */
+private void
+gc_clear_reloc(chunk_t *cp)
+{ byte *pfree = (byte *)&cp->chead->free;
+
+ gc_init_reloc(cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ const struct_shared_procs_t _ds *procs =
+ pre->o_type->shared;
+
+ if ( procs != 0 )
+ (*procs->clear_reloc)(pre, size);
+ o_set_untraced(pre);
+ if ( !pre->o_large )
+ pre->o_back = ((byte *)pre - pfree) >> obj_back_shift;
+ END_OBJECTS_SCAN
+ gc_strings_set_marks(cp, true);
+ gc_strings_clear_reloc(cp);
+}
+
+/* Set the relocation for the objects in a chunk. */
+/* This will never be called for a chunk with any o_untraced objects. */
+private void
+gc_objects_set_reloc(chunk_t *cp)
+{ uint reloc = 0;
+ chunk_head_t *chead = cp->chead;
+ byte *pfree = (byte *)&chead->free; /* most recent free object */
+ if_debug_chunk('6', "[6]setting reloc for chunk", cp);
+ gc_init_reloc(cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_finalize((*finalize));
+ const struct_shared_procs_t _ds *procs =
+ pre->o_type->shared;
+ if ( (procs == 0 ? o_is_unmarked(pre) :
+ !(*procs->set_reloc)(pre, reloc, size))
+ )
+ { /* Free object */
+ reloc += sizeof(obj_header_t) + obj_align_round(size);
+ if ( (finalize = pre->o_type->finalize) != 0 )
+ { if_debug2('u', "[u]GC finalizing %s 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)(pre + 1));
+ (*finalize)(pre + 1);
+ }
+ if ( pre->o_large )
+ { /* We should chop this up into small */
+ /* free blocks, but there's no value */
+ /* in doing this right now. */
+ o_set_unmarked_large(pre);
+ }
+ else
+ { pfree = (byte *)pre;
+ pre->o_back =
+ (pfree - (byte *)chead) >> obj_back_shift;
+ pre->o_nreloc = reloc;
+ }
+ if_debug3('7', " [7]at 0x%lx, unmarked %lu, new reloc = %u\n",
+ (ulong)pre, (ulong)size, reloc);
+ }
+ else
+ { /* Useful object */
+ debug_check_object(pre, cp, NULL);
+ if ( pre->o_large )
+ { if ( o_is_unmarked_large(pre) )
+ o_mark_large(pre);
+ }
+ else
+ pre->o_back =
+ ((byte *)pre - pfree) >> obj_back_shift;
+ }
+ END_OBJECTS_SCAN
+#ifdef DEBUG
+ if ( reloc != 0 )
+ { if_debug1('6', "[6]freed %u", reloc);
+ if_debug_chunk('6', " in", cp);
+ }
+#endif
+}
+
+/* ------ Relocation phase ------ */
+
+/* Relocate the pointers in all the objects in a chunk. */
+private void
+gc_do_reloc(chunk_t *cp, gs_ref_memory_t *mem, gc_state_t *pstate)
+{ chunk_head_t *chead = cp->chead;
+ if_debug_chunk('6', "[6]relocating in chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ /* We need to relocate the pointers in an object iff */
+ /* it is o_untraced, or it is a useful object. */
+ /* An object is free iff its back pointer points to */
+ /* the chunk_head structure. */
+ if ( o_is_untraced(pre) ||
+ (pre->o_large ? !o_is_unmarked(pre) :
+ pre->o_back << obj_back_shift !=
+ (byte *)pre - (byte *)chead)
+ )
+ { struct_proc_reloc_ptrs((*proc)) =
+ pre->o_type->reloc_ptrs;
+ if_debug3('7',
+ " [7]relocating ptrs in %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)size, (ulong)pre);
+ if ( proc != 0 )
+ (*proc)(pre + 1, size, pstate);
+ }
+ END_OBJECTS_SCAN
+}
+
+/* Print pointer relocation if debugging. */
+/* We have to provide this procedure even if DEBUG is not defined, */
+/* in case one of the other GC modules was compiled with DEBUG. */
+void *
+print_reloc_proc(const void *obj, const char *cname, void *robj)
+{ if_debug3('9', " [9]relocate %s * 0x%lx to 0x%lx\n",
+ cname, (ulong)obj, (ulong)robj);
+ return robj;
+}
+
+/* Relocate a pointer to an (aligned) object. */
+/* See gsmemory.h for why the argument is const and the result is not. */
+void /*obj_header_t*/ *
+gs_reloc_struct_ptr(const void /*obj_header_t*/ *obj, gc_state_t *gcst)
+{ const void *robj;
+
+ if ( obj == 0 )
+ return print_reloc(obj, "NULL", 0);
+#define optr ((const obj_header_t *)obj)
+ debug_check_object(optr - 1, NULL, gcst);
+ /* The following should be a conditional expression, */
+ /* but Sun's cc compiler can't handle it. */
+ if ( optr[-1].o_large )
+ robj = obj;
+ else
+ { uint back = optr[-1].o_back;
+ if ( back == o_untraced )
+ robj = obj;
+ else
+ {
+#ifdef DEBUG
+ /* Do some sanity checking. */
+ if ( back > gcst->space_local->chunk_size >> obj_back_shift )
+ { lprintf2("Invalid back pointer %u at 0x%lx!\n",
+ back, (ulong)obj);
+ gs_abort();
+ }
+#endif
+ { const obj_header_t *pfree = (const obj_header_t *)
+ ((const char *)(optr - 1) -
+ (back << obj_back_shift));
+ const chunk_head_t *chead = (const chunk_head_t *)
+ ((const char *)pfree -
+ (pfree->o_back << obj_back_shift));
+ robj = chead->dest +
+ ((const char *)obj - (const char *)(chead + 1) -
+ pfree->o_nreloc);
+ }
+ }
+ }
+ return print_reloc(obj,
+ struct_type_name_string(optr[-1].o_type),
+ (void *)robj); /* discard const */
+#undef optr
+}
+
+/* ------ Compaction phase ------ */
+
+/* Compact the objects in a chunk. */
+/* This will never be called for a chunk with any o_untraced objects. */
+private void
+gc_objects_compact(chunk_t *cp, gc_state_t *gcst)
+{ chunk_head_t *chead = cp->chead;
+ obj_header_t *dpre = (obj_header_t *)chead->dest;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ /* An object is free iff its back pointer points to */
+ /* the chunk_head structure. */
+ if ( (pre->o_large ? !o_is_unmarked(pre) :
+ pre->o_back << obj_back_shift !=
+ (byte *)pre - (byte *)chead)
+ )
+ { const struct_shared_procs_t _ds *procs =
+ pre->o_type->shared;
+ debug_check_object(pre, cp, gcst);
+ if_debug4('7',
+ " [7]compacting %s 0x%lx(%lu) to 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)pre, (ulong)size, (ulong)dpre);
+ if ( procs == 0 )
+ { if ( dpre != pre )
+ memmove(dpre, pre,
+ sizeof(obj_header_t) + size);
+ }
+ else
+ (*procs->compact)(pre, dpre, size);
+ dpre = (obj_header_t *)
+ ((byte *)dpre + obj_size_round(size));
+ }
+ END_OBJECTS_SCAN
+ if ( cp->outer == 0 && chead->dest != cp->cbase )
+ dpre = (obj_header_t *)cp->cbase; /* compacted this chunk into another */
+ gs_alloc_fill(dpre, gs_alloc_fill_collected, cp->cbot - (byte *)dpre);
+ cp->cbot = (byte *)dpre;
+ cp->rcur = 0;
+ cp->rtop = 0; /* just to be sure */
+}
+
+/* ------ Cleanup ------ */
+
+/* Free empty chunks. */
+private void
+gc_free_empty_chunks(gs_ref_memory_t *mem)
+{ chunk_t *cp;
+ chunk_t *csucc;
+ /* Free the chunks in reverse order, */
+ /* to encourage LIFO behavior. */
+ for ( cp = mem->clast; cp != 0; cp = csucc )
+ { /* Make sure this isn't an inner chunk, */
+ /* or a chunk that has inner chunks. */
+ csucc = cp->cprev; /* save before freeing */
+ if ( cp->cbot == cp->cbase && cp->ctop == cp->climit &&
+ cp->outer == 0 && cp->inner_count == 0
+ )
+ { alloc_free_chunk(cp, mem);
+ if ( mem->pcc == cp )
+ mem->pcc = 0;
+ }
+ }
+}
diff --git a/gs/src/igc.h b/gs/src/igc.h
new file mode 100644
index 000000000..40c223359
--- /dev/null
+++ b/gs/src/igc.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igc.h */
+/* Internal interfaces in Ghostscript GC */
+
+/* Define the procedures shared among a "genus" of structures. */
+/* Currently there are only two genera: refs, and all other structures. */
+struct struct_shared_procs_s {
+
+ /* Clear the relocation information in an object. */
+
+#define gc_proc_clear_reloc(proc)\
+ void proc(P2(obj_header_t *pre, uint size))
+ gc_proc_clear_reloc((*clear_reloc));
+
+ /* Compute any internal relocation for a marked object. */
+ /* Return true if the object should be kept. */
+ /* The reloc argument shouldn't be required, */
+ /* but we need it for ref objects. */
+
+#define gc_proc_set_reloc(proc)\
+ bool proc(P3(obj_header_t *pre, uint reloc, uint size))
+ gc_proc_set_reloc((*set_reloc));
+
+ /* Compact an object. */
+
+#define gc_proc_compact(proc)\
+ void proc(P3(obj_header_t *pre, obj_header_t *dpre, uint size))
+ gc_proc_compact((*compact));
+
+};
+
+/* Define the structure for holding GC state. */
+/*typedef struct gc_state_s gc_state_t;*/ /* in gsstruct.h */
+struct gc_state_s {
+ chunk_locator_t loc;
+ vm_spaces spaces;
+ int min_collect; /* avm_space */
+ bool relocating_untraced; /* if true, we're relocating */
+ /* pointers from untraced spaces */
+};
+
+/* Exported by igcref.c for igc.c */
+void ptr_ref_unmark(P2(void *, gc_state_t *));
+bool ptr_ref_mark(P2(void *, gc_state_t *));
+/*ref_packed *gs_reloc_ref_ptr(P2(const ref_packed *, gc_state_t *));*/
+
+/* Exported by ilocate.c for igc.c */
+void ialloc_validate_memory(P2(const gs_ref_memory_t *, gc_state_t *));
+void ialloc_validate_chunk(P2(const chunk_t *, gc_state_t *));
+void ialloc_validate_object(P3(const obj_header_t *, const chunk_t *,
+ gc_state_t *));
+
+/* Macro for returning a relocated pointer */
+#ifdef DEBUG
+void *print_reloc_proc(P3(const void *obj, const char *cname, void *robj));
+# define print_reloc(obj, cname, nobj)\
+ (gs_debug_c('9') ? print_reloc_proc(obj, cname, nobj) :\
+ (void *)(nobj))
+#else
+# define print_reloc(obj, cname, nobj)\
+ (void *)(nobj)
+#endif
diff --git a/gs/src/igcref.c b/gs/src/igcref.c
new file mode 100644
index 000000000..689f664d5
--- /dev/null
+++ b/gs/src/igcref.c
@@ -0,0 +1,682 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igcref.c */
+/* ref garbage collector for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsexit.h"
+#include "gsstruct.h" /* for gxalloc.h */
+#include "iname.h"
+#include "iastate.h"
+#include "idebug.h"
+#include "igc.h"
+#include "ipacked.h"
+#include "store.h" /* for ref_assign_inline */
+
+/* Define whether to trace every step of relocating ref pointers. */
+#if 0
+# define rputc(c) dputc(c)
+#else
+# define rputc(c) DO_NOTHING
+#endif
+
+/*
+ * Define the 'structure' type descriptor for refs.
+ * This is special because it has different shared procs.
+ */
+private gc_proc_clear_reloc(refs_clear_reloc);
+private gc_proc_set_reloc(refs_set_reloc);
+private gc_proc_compact(refs_compact);
+private const struct_shared_procs_t refs_shared_procs =
+ { refs_clear_reloc, refs_set_reloc, refs_compact };
+private struct_proc_clear_marks(refs_clear_marks);
+private struct_proc_reloc_ptrs(refs_do_reloc);
+const gs_memory_struct_type_t st_refs =
+ { sizeof(ref), "refs", &refs_shared_procs, refs_clear_marks, 0, refs_do_reloc };
+
+/*
+ * Define the GC procedures for structs that actually contain refs.
+ * These are special because the shared refs_* procedures
+ * are never called. Instead, we unmark the individual refs in clear_marks,
+ * disregard refs_*_reloc (because we will never relocate a ptr_ref_type
+ * pointer pointing into the structure), disregard refs_compact (because
+ * compaction is never required), and remove the marks in reloc_ptrs.
+ * See also the comment about ptr_ref_type in imemory.h.
+ */
+CLEAR_MARKS_PROC(ref_struct_clear_marks) {
+ ref *pref = (ref *)vptr;
+ ref *end = (ref *)((char *)vptr + size);
+ for ( ; pref < end; pref++ )
+ r_clear_attrs(pref, l_mark);
+}
+ENUM_PTRS_BEGIN_PROC(ref_struct_enum_ptrs) {
+ if ( index >= size / sizeof(ref) )
+ return 0;
+ *pep = (ref *)vptr + index;
+ return ptr_ref_type;
+ENUM_PTRS_END_PROC }
+RELOC_PTRS_BEGIN(ref_struct_reloc_ptrs) {
+ ref *beg = vptr;
+ ref *end = (ref *)((char *)vptr + size);
+ gs_reloc_refs((ref_packed *)beg, (ref_packed *)end, gcst);
+ ref_struct_clear_marks(vptr, size);
+} RELOC_PTRS_END
+
+/* Define a fast lookup table for ref types that use the size field. */
+private byte types_using_size[1 << r_type_bits];
+
+/* ------ Initialization ------ */
+void
+gs_igcref_init(gs_memory_t *mem)
+{ int i;
+ for ( i = 0; i < t_next_index; ++i )
+ switch ( i )
+ {
+ default:
+ types_using_size[i] = 0;
+ break;
+ case t_null: /* see relocation planning phase below */
+ case_types_with_size:
+ types_using_size[i] = 1;
+ }
+ memset(types_using_size + t_next_index, 1,
+ countof(types_using_size) - t_next_index);
+}
+
+/* ------ Unmarking phase ------ */
+
+/* Unmark a single ref. */
+void
+ptr_ref_unmark(void *vptr, gc_state_t *ignored)
+{ if ( r_is_packed((ref *)vptr) )
+ r_clear_pmark((ref_packed *)vptr);
+ else
+ r_clear_attrs((ref *)vptr, l_mark);
+}
+
+/* Unmarking routine for ref objects. */
+private void
+refs_clear_marks(void /*obj_header_t*/ *vptr, uint size)
+{ ref_packed *rp = (ref_packed *)vptr;
+ ref_packed *end = (ref_packed *)((byte *)vptr + size);
+
+ /* Since the last ref is full-size, we only need to check for */
+ /* the end of the block when we see one of those. */
+ for ( ; ; )
+ { if ( r_is_packed(rp) )
+ {
+#ifdef DEBUG
+if ( gs_debug_c('8') )
+{ dprintf1(" [8]unmark packed 0x%lx ", (ulong)rp);
+ debug_print_ref((const ref *)rp);
+ dprintf("\n");
+}
+#endif
+ r_clear_pmark(rp);
+ rp++;
+ }
+ else /* full-size ref */
+ {
+#ifdef DEBUG
+if ( gs_debug_c('8') )
+{ dprintf1(" [8]unmark ref 0x%lx ", (ulong)rp);
+ debug_print_ref((ref *)rp);
+ dprintf("\n");
+}
+#endif
+ r_clear_attrs((ref *)rp, l_mark);
+ rp += packed_per_ref;
+ if ( rp >= (ref_packed *)end )
+ break;
+ }
+ }
+}
+
+/* ------ Marking phase ------ */
+
+/* Mark a ref. Return true if new mark. */
+bool
+ptr_ref_mark(void *vptr, gc_state_t *ignored)
+{ if ( r_is_packed(vptr) )
+ { if ( r_has_pmark((ref_packed *)vptr) )
+ return false;
+ r_set_pmark((ref_packed *)vptr);
+ }
+ else
+ { if ( r_has_attr((ref *)vptr, l_mark) )
+ return false;
+ r_set_attrs((ref *)vptr, l_mark);
+ }
+ return true;
+}
+
+/* ------ Relocation planning phase ------ */
+
+/*
+ * We store relocation in the size field of refs that don't use it,
+ * so that we don't have to scan all the way to an unmarked object.
+ * We must avoid nulls, which sometimes have useful information
+ * in their size fields, and the types above t_next_index, which are
+ * actually operators in disguise and also use the size field.
+ */
+#define case_types_using_size\
+ case t_null: case_types_with_size
+
+/* Clear the relocation for a ref object. */
+private void
+refs_clear_reloc(obj_header_t *hdr, uint size)
+{ register ref_packed *rp = (ref_packed *)(hdr + 1);
+ ref_packed *end = (ref_packed *)((byte *)rp + size);
+ while ( rp < end )
+ { if ( r_is_packed(rp) )
+ rp++;
+ else /* full-size ref */
+ { /* Store the relocation here if possible. */
+ if ( !types_using_size[r_type((ref *)rp)] )
+ { if_debug1('8',
+ " [8]clearing reloc at 0x%lx\n",
+ (ulong)rp);
+ r_set_size((ref *)rp, 0);
+ }
+ rp += packed_per_ref;
+ }
+ }
+}
+
+/* Set the relocation for a ref object. */
+private bool
+refs_set_reloc(obj_header_t *hdr, uint reloc, uint size)
+{ ref_packed *rp = (ref_packed *)(hdr + 1);
+ ref_packed *end = (ref_packed *)((byte *)rp + size);
+ uint freed = 0;
+
+ /*
+ * We have to be careful to keep refs aligned properly.
+ * For the moment, we do this by either keeping or discarding
+ * an entire (aligned) block of align_packed_per_ref packed elements
+ * as a unit. We know that align_packed_per_ref <= packed_per_ref,
+ * and we also know that packed refs are always allocated in blocks
+ * of align_packed_per_ref, so this makes things relatively easy.
+ */
+ while ( rp < end )
+ { if ( r_is_packed(rp) )
+ {
+#if align_packed_per_ref == 1
+ if ( r_has_pmark(rp) )
+ { if_debug1('8',
+ " [8]packed ref 0x%lx is marked\n",
+ (ulong)rp);
+ rp++;
+ }
+ else
+ {
+#else
+ int i;
+ /*
+ * Note: align_packed_per_ref is typically
+ * 2 or 4 for 32-bit processors.
+ */
+#define all_marked (align_packed_per_ref * lp_mark)
+# if align_packed_per_ref == 2
+# if arch_sizeof_long == arch_sizeof_short * 2
+# undef all_marked
+# define all_marked ( ((long)lp_mark << (sizeof(short) * 8)) + lp_mark )
+# define marked (*(long *)rp & all_marked)
+# else
+# define marked ((*rp & lp_mark) + (rp[1] & lp_mark))
+# endif
+# else
+# if align_packed_per_ref == 4
+# define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\
+ (rp[2] & lp_mark) + (rp[3] & lp_mark))
+# else
+ uint marked = *rp & lp_mark;
+ for ( i = 1; i < align_packed_per_ref; i++ )
+ marked += rp[i] & lp_mark;
+# endif
+# endif
+ /*
+ * Now marked is lp_mark * the number of marked
+ * packed refs in the aligned block, except for
+ * a couple of special cases above.
+ */
+ switch ( marked )
+ {
+ case all_marked:
+ if_debug2('8',
+ " [8]packed refs 0x%lx..0x%lx are marked\n",
+ (ulong)rp,
+ (ulong)(rp + (align_packed_per_ref - 1)));
+ rp += align_packed_per_ref;
+ break;
+ default:
+ /* At least one packed ref in the block */
+ /* is marked: Keep the whole block. */
+ for ( i = align_packed_per_ref; i--; rp++ )
+ { r_set_pmark(rp);
+ if_debug1('8',
+ " [8]packed ref 0x%lx is marked\n",
+ (ulong)rp);
+ }
+ break;
+ case 0:
+#endif
+ if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n",
+ align_packed_per_ref, (ulong)rp);
+ { uint rel = reloc + freed;
+ /* Change this to an integer so we can */
+ /* store the relocation here. */
+ *rp = pt_tag(pt_integer) +
+ min(rel, packed_max_value);
+ }
+ rp += align_packed_per_ref;
+ freed += sizeof(ref_packed) * align_packed_per_ref;
+ }
+ }
+ else /* full-size ref */
+ { uint rel = reloc + freed;
+ /* The following assignment is logically */
+ /* unnecessary; we do it only for convenience */
+ /* in debugging. */
+ ref *pref = (ref *)rp;
+ if ( !r_has_attr(pref, l_mark) )
+ { if_debug1('8', " [8]ref 0x%lx is unmarked\n",
+ (ulong)pref);
+ /* Change this to a mark so we can */
+ /* store the relocation. */
+ r_set_type(pref, t_mark);
+ r_set_size(pref, rel);
+ freed += sizeof(ref);
+ }
+ else
+ { if_debug1('8', " [8]ref 0x%lx is marked\n",
+ (ulong)pref);
+ /* Store the relocation here if possible. */
+ if ( !types_using_size[r_type(pref)] )
+ { if_debug2('8', " [8]storing reloc %u at 0x%lx\n",
+ rel, (ulong)pref);
+ r_set_size(pref, rel);
+ }
+ }
+ rp += packed_per_ref;
+ }
+ }
+ if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n",
+ (ulong)(hdr + 1), size, freed);
+ if ( freed == size )
+ return false;
+#if arch_sizeof_int > arch_sizeof_short
+ /*
+ * If the final relocation can't fit in the r_size field
+ * (which can't happen if the object shares a chunk with
+ * any other objects, so we know reloc = 0 in this case),
+ * we have to keep the entire object unless there are no
+ * references to any ref in it.
+ */
+ if ( freed <= max_ushort )
+ return true;
+ /*
+ * We have to mark all surviving refs, but we also must
+ * overwrite any non-surviving refs with something that
+ * doesn't contain any pointers.
+ */
+ rp = (ref_packed *)(hdr + 1);
+ while ( rp < end )
+ { if ( r_is_packed(rp) )
+ { if ( !r_has_pmark(rp) )
+ *rp = pt_tag(pt_integer) | lp_mark;
+ ++rp;
+ }
+ else
+ { /* The following assignment is logically */
+ /* unnecessary; we do it only for convenience */
+ /* in debugging. */
+ ref *pref = (ref *)rp;
+ if ( !r_has_attr(pref, l_mark) )
+ { r_set_type_attrs(pref, t_mark, l_mark);
+ r_set_size(pref, reloc);
+ }
+ else
+ { if ( !types_using_size[r_type(pref)] )
+ r_set_size(pref, reloc);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ /* The last ref has to remain unmarked. */
+ r_clear_attrs((ref *)rp - 1, l_mark);
+#endif
+ return true;
+}
+
+/* ------ Relocation phase ------ */
+
+/* Relocate all the pointers in a block of refs. */
+private void
+refs_do_reloc(void /*obj_header_t*/ *vptr, uint size, gc_state_t *gcst)
+{ gs_reloc_refs((ref_packed *)vptr,
+ (ref_packed *)((char *)vptr + size),
+ gcst);
+}
+/* Relocate the contents of a block of refs. */
+/* If gcst->relocating_untraced is true, we are relocating pointers from an */
+/* untraced space, so relocate all refs, not just marked ones. */
+void
+gs_reloc_refs(ref_packed *from, ref_packed *to, gc_state_t *gcst)
+{ int min_trace = gcst->min_collect;
+ ref_packed *rp = from;
+ bool do_all = gcst->relocating_untraced;
+
+ while ( rp < to )
+ { ref *pref;
+ if ( r_is_packed(rp) )
+ { rp++;
+ continue;
+ }
+ /* The following assignment is logically unnecessary; */
+ /* we do it only for convenience in debugging. */
+ pref = (ref *)rp;
+ if_debug3('8', " [8]relocating %s %d ref at 0x%lx\n",
+ (r_has_attr(pref, l_mark) ? "marked" : "unmarked"),
+ r_btype(pref), (ulong)pref);
+ if ( (r_has_attr(pref, l_mark) || do_all) &&
+ r_space(pref) >= min_trace
+ )
+ switch ( r_type(pref) )
+ {
+ /* Struct cases */
+#define ref_case(v, t)\
+ pref->value.v =\
+ (t *)gs_reloc_struct_ptr((obj_header_t *)pref->value.v, gcst)
+ case t_file:
+ ref_case(pfile, struct stream_s); break;
+ case t_device:
+ ref_case(pdevice, struct gx_device_s); break;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ ref_case(pstruct, void); break;
+#undef ref_case
+ /* Non-trivial non-struct cases */
+ case t_dictionary:
+ rputc('d');
+ pref->value.pdict =
+ (dict *)gs_reloc_ref_ptr((ref_packed *)pref->value.pdict, gcst);
+ break;
+ case t_array:
+ { uint size = r_size(pref);
+ if ( size != 0 ) /* value.refs might be NULL */
+ { /*
+ * If the array is large, we allocated it in its
+ * own object (at least originally -- this might
+ * be a pointer to a subarray.) In this case,
+ * we know it is the only object in its
+ * containing st_refs object, so we know that
+ * the mark containing the relocation appears
+ * just after it.
+ */
+ if ( size < max_size_st_refs / sizeof(ref) )
+ { rputc('a');
+ pref->value.refs =
+ (ref *)gs_reloc_ref_ptr(
+ (ref_packed *)pref->value.refs, gcst);
+ }
+ else
+ { rputc('A');
+ /*
+ * See the t_shortarray case below for why we
+ * decrement size.
+ */
+ --size;
+ pref->value.refs =
+ (ref *)gs_reloc_ref_ptr(
+ (ref_packed *)(pref->value.refs + size),
+ gcst) - size;
+ }
+ }
+ } break;
+ case t_mixedarray:
+ if ( r_size(pref) != 0 ) /* value.refs might be NULL */
+ { rputc('m');
+ pref->value.packed =
+ gs_reloc_ref_ptr(pref->value.packed, gcst);
+ }
+ break;
+ case t_shortarray:
+ { uint size = r_size(pref);
+ /*
+ * Since we know that gs_reloc_ref_ptr works by
+ * scanning forward, and we know that all the
+ * elements of this array itself are marked, we can
+ * save some scanning time by relocating the pointer
+ * to the end of the array rather than the
+ * beginning.
+ */
+ if ( size != 0 ) /* value.refs might be NULL */
+ { rputc('s');
+ /*
+ * gs_reloc_ref_ptr has to be able to determine
+ * whether the pointer points into a space that
+ * isn't being collected. It does this by
+ * checking whether the referent of the pointer
+ * is marked. For this reason, we have to pass
+ * a pointer to the last real element of the
+ * array, rather than just beyond it.
+ */
+ --size;
+ pref->value.packed =
+ gs_reloc_ref_ptr(pref->value.packed + size,
+ gcst) - size;
+ }
+ } break;
+ case t_name:
+ { void *psub = name_ref_sub_table(pref);
+ void *rsub = gs_reloc_struct_ptr(psub, gcst);
+ pref->value.pname = (name *)
+ ((char *)rsub + ((char *)pref->value.pname - (char *)psub));
+ } break;
+ case t_string:
+ { gs_string str;
+ str.data = pref->value.bytes;
+ str.size = r_size(pref);
+ gs_reloc_string(&str, gcst);
+ pref->value.bytes = str.data;
+ } break;
+ case t_oparray:
+ rputc('o');
+ pref->value.const_refs =
+ (const ref *)gs_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst);
+ break;
+ }
+ rp += packed_per_ref;
+ }
+}
+
+/* Relocate a pointer to a ref. */
+/* See gsmemory.h for why the argument is const and the result is not. */
+ref_packed *
+gs_reloc_ref_ptr(const ref_packed *prp, gc_state_t *ignored)
+{ /*
+ * Search forward for relocation. This algorithm is intrinsically
+ * very inefficient; we hope eventually to replace it with a better
+ * one.
+ */
+ register const ref_packed *rp = prp;
+ uint dec = 0;
+
+ /*
+ * Iff this pointer points into a space that wasn't traced,
+ * the referent won't be marked. In this case, we shouldn't
+ * do any relocation. Check for this first.
+ */
+ if ( r_is_packed(rp) )
+ { if ( !r_has_pmark(rp) )
+ return (ref_packed *)rp;
+ }
+ else
+ { if ( !r_has_attr((const ref *)rp, l_mark) )
+ return (ref_packed *)rp;
+ }
+ for ( ; ; )
+ { if ( r_is_packed(rp) )
+ { /*
+ * Normally, an unmarked packed ref will be an
+ * integer whose value is the amount of relocation.
+ * However, the relocation value might have been
+ * too large to fit. If this is the case, for
+ * each such unmarked packed ref we pass over,
+ * we have to decrement the final relocation.
+ */
+ rputc((*rp & lp_mark ? '1' : '0'));
+ if ( !(*rp & lp_mark) )
+ { if ( *rp != pt_tag(pt_integer) + packed_max_value )
+ { /* This is a stored relocation value. */
+ rputc('\n');
+ return print_reloc(prp, "ref",
+ (ref_packed *)
+ ((const char *)prp -
+ (*rp & packed_value_mask) + dec));
+ }
+ /*
+ * We know this is the first of an aligned block
+ * of packed refs. Skip over the entire block,
+ * decrementing the final relocation.
+ */
+ dec += sizeof(ref_packed) * align_packed_per_ref;
+ rp += align_packed_per_ref;
+ }
+ else
+ rp++;
+ continue;
+ }
+ if ( !types_using_size[r_type((const ref *)rp)] )
+ { /* reloc is in r_size */
+ rputc('\n');
+ return print_reloc(prp, "ref",
+ (ref_packed *)
+ (r_size((const ref *)rp) == 0 ? prp :
+ (const ref_packed *)((const char *)prp - r_size((const ref *)rp) + dec)));
+ }
+ rputc('u');
+ rp += packed_per_ref;
+ }
+}
+
+/* ------ Compaction phase ------ */
+
+/* Compact a ref object. */
+/* Remove the marks at the same time. */
+private void
+refs_compact(obj_header_t *pre, obj_header_t *dpre, uint size)
+{ ref_packed *dest;
+ ref_packed *src;
+ ref_packed *end;
+ uint new_size;
+ src = (ref_packed *)(pre + 1);
+ end = (ref_packed *)((byte *)src + size);
+ /*
+ * We know that a block of refs always ends with an unmarked
+ * full-size ref, so we only need to check for reaching the end
+ * of the block when we see one of those.
+ */
+ if ( dpre == pre ) /* Loop while we don't need to copy. */
+ for ( ; ; )
+ { if ( r_is_packed(src) )
+ { if ( !r_has_pmark(src) )
+ break;
+ if_debug1('8', " [8]packed ref 0x%lx \"copied\"\n",
+ (ulong)src);
+ *src &= ~lp_mark;
+ src++;
+ }
+ else /* full-size ref */
+ { if ( !r_has_attr((ref *)src, l_mark) )
+ break;
+ if_debug1('8', " [8]ref 0x%lx \"copied\"\n",
+ (ulong)src);
+ r_clear_attrs((ref *)src, l_mark);
+ src += packed_per_ref;
+ }
+ }
+ else
+ *dpre = *pre;
+ dest = (ref_packed *)((char *)dpre + ((char *)src - (char *)pre));
+ for ( ; ; )
+ { if ( r_is_packed(src) )
+ { if ( r_has_pmark(src) )
+ { if_debug2('8', " [8]packed ref 0x%lx copied to 0x%lx\n",
+ (ulong)src, (ulong)dest);
+ *dest++ = *src & ~lp_mark;
+ }
+ src++;
+ }
+ else /* full-size ref */
+ { if ( r_has_attr((ref *)src, l_mark) )
+ { ref rtemp;
+ if_debug2('8', " [8]ref 0x%lx copied to 0x%lx\n",
+ (ulong)src, (ulong)dest);
+ /* We can't just use ref_assign_inline, */
+ /* because the source and destination */
+ /* might overlap! */
+ ref_assign_inline(&rtemp, (ref *)src);
+ r_clear_attrs(&rtemp, l_mark);
+ ref_assign_inline((ref *)dest, &rtemp);
+ dest += packed_per_ref;
+ src += packed_per_ref;
+ }
+ else /* check for end of block */
+ { src += packed_per_ref;
+ if ( src >= end )
+ break;
+ }
+ }
+ }
+ new_size = (byte *)dest - (byte *)(dpre + 1) + sizeof(ref);
+#ifdef DEBUG
+ /* Check that the relocation came out OK. */
+ /* NOTE: this check only works within a single chunk. */
+ if ( (byte *)src - (byte *)dest != r_size((ref *)src - 1) + sizeof(ref) )
+ { lprintf3("Reloc error for refs 0x%lx: reloc = %lu, stored = %u\n",
+ (ulong)dpre, (ulong)((byte *)src - (byte *)dest),
+ (uint)r_size((ref *)src - 1));
+ gs_exit(1);
+ }
+#endif
+ /* Pad to a multiple of sizeof(ref). */
+ while ( new_size & (sizeof(ref) - 1) )
+ *dest++ = pt_tag(pt_integer),
+ new_size += sizeof(ref_packed);
+ /* We want to make the newly freed space into a free block, */
+ /* but we can only do this if we have enough room. */
+ if ( size - new_size < sizeof(obj_header_t) )
+ { /* Not enough room. Pad to original size. */
+ while ( new_size < size )
+ *dest++ = pt_tag(pt_integer),
+ new_size += sizeof(ref_packed);
+ }
+ else
+ { obj_header_t *pfree = (obj_header_t *)((ref *)dest + 1);
+ pfree->o_large = 0;
+ pfree->o_size = size - new_size - sizeof(obj_header_t);
+ pfree->o_type = &st_bytes;
+ }
+ /* Re-create the final ref. */
+ r_set_type((ref *)dest, t_integer);
+ dpre->o_size = new_size;
+}
diff --git a/gs/src/igcstr.c b/gs/src/igcstr.c
new file mode 100644
index 000000000..ba2fcf5f2
--- /dev/null
+++ b/gs/src/igcstr.c
@@ -0,0 +1,362 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igcstr.c */
+/* String GC routines for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "igcstr.h"
+
+/* Forward references */
+private bool gc_mark_string(P4(const byte *, uint, bool, const chunk_t *));
+
+/* (Un)mark the strings in a chunk. */
+void
+gc_strings_set_marks(chunk_t *cp, bool mark)
+{ if ( cp->smark != 0 )
+ { if_debug3('6', "[6]clearing string marks 0x%lx[%u] to %d\n",
+ (ulong)cp->smark, cp->smark_size, (int)mark);
+ memset(cp->smark, 0, cp->smark_size);
+ if ( mark )
+ gc_mark_string(cp->sbase, cp->climit - cp->sbase, true, cp);
+ }
+}
+
+/* We mark strings a word at a time. */
+typedef string_mark_unit bword;
+#define bword_log2_bytes log2_sizeof_string_mark_unit
+#define bword_bytes (1 << bword_log2_bytes)
+#define bword_log2_bits (bword_log2_bytes + 3)
+#define bword_bits (1 << bword_log2_bits)
+#define bword_1s (~(bword)0)
+/* Compensate for byte order reversal if necessary. */
+#if arch_is_big_endian
+# if bword_bytes == 2
+# define bword_swap_bytes(m) m = (m << 8) | (m >> 8)
+# else /* bword_bytes == 4 */
+# define bword_swap_bytes(m)\
+ m = (m << 24) | ((m & 0xff00) << 8) | ((m >> 8) & 0xff00) | (m >> 24)
+# endif
+#else
+# define bword_swap_bytes(m) DO_NOTHING
+#endif
+
+/* (Un)mark a string in a known chunk. Return true iff any new marks. */
+private bool
+gc_mark_string(const byte *ptr, uint size, bool set, const chunk_t *cp)
+{ uint offset = ptr - cp->sbase;
+ bword *bp = (bword *)(cp->smark + ((offset & -bword_bits) >> 3));
+ uint bn = offset & (bword_bits - 1);
+ bword m = bword_1s << bn;
+ uint left = size;
+ bword marks = 0;
+
+ bword_swap_bytes(m);
+ if ( set )
+ { if ( left + bn >= bword_bits )
+ { marks |= ~*bp & m;
+ *bp |= m;
+ m = bword_1s, left -= bword_bits - bn, bp++;
+ while ( left >= bword_bits )
+ { marks |= ~*bp;
+ *bp = bword_1s;
+ left -= bword_bits, bp++;
+ }
+ }
+ if ( left )
+ { bword_swap_bytes(m);
+ m -= m << left;
+ bword_swap_bytes(m);
+ marks |= ~*bp & m;
+ *bp |= m;
+ }
+ }
+ else
+ { if ( left + bn >= bword_bits )
+ { *bp &= ~m;
+ m = bword_1s, left -= bword_bits - bn, bp++;
+ if ( left >= bword_bits * 5 )
+ { memset(bp, 0, (left & -bword_bits) >> 3);
+ bp += left >> bword_log2_bits;
+ left &= bword_bits - 1;
+ }
+ else
+ while ( left >= bword_bits )
+ { *bp = 0;
+ left -= bword_bits, bp++;
+ }
+ }
+ if ( left )
+ { bword_swap_bytes(m);
+ m -= m << left;
+ bword_swap_bytes(m);
+ *bp &= ~m;
+ }
+ }
+ return marks != 0;
+}
+
+/* Mark a string. Return true if any new marks. */
+bool
+gc_string_mark(const byte *ptr, uint size, bool set, gc_state_t *gcst)
+{ const chunk_t *cp;
+ bool marks;
+
+ if ( size == 0 )
+ return false;
+#define dprintstr()\
+ dputc('('); fwrite(ptr, 1, min(size, 20), dstderr);\
+ dputs((size <= 20 ? ")" : "...)"))
+ if ( !(cp = gc_locate(ptr, gcst)) ) /* not in a chunk */
+ {
+#ifdef DEBUG
+ if ( gs_debug_c('5') )
+ { dprintf2("[5]0x%lx[%u]", (ulong)ptr, size);
+ dprintstr();
+ dputs(" not in a chunk\n");
+ }
+#endif
+ return false;
+ }
+ if ( cp->smark == 0 ) /* not marking strings */
+ return false;
+#ifdef DEBUG
+ if ( ptr < cp->ctop )
+ { lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n",
+ (ulong)ptr, size, (ulong)cp->ctop, (ulong)cp->climit);
+ return false;
+ }
+ else if ( ptr + size > cp->climit )
+ { /*
+ * If this is the bottommost string in a chunk that has
+ * an inner chunk, the string's starting address is both
+ * cp->ctop of the outer chunk and cp->climit of the inner;
+ * gc_locate may incorrectly attribute the string to the
+ * inner chunk because of this. This doesn't affect
+ * marking or relocation, since the machinery for these
+ * is all associated with the outermost chunk,
+ * but it can cause the validity check to fail.
+ * Check for this case now.
+ */
+ const chunk_t *scp = cp;
+ while ( ptr == scp->climit && scp->outer != 0 )
+ scp = scp->outer;
+ if ( ptr + size > scp->climit )
+ { lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n",
+ (ulong)ptr, size,
+ (ulong)scp->ctop, (ulong)scp->climit);
+ return false;
+ }
+ }
+#endif
+ marks = gc_mark_string(ptr, size, set, cp);
+#ifdef DEBUG
+ if ( gs_debug_c('5') )
+ { dprintf4("[5]%s%smarked 0x%lx[%u]",
+ (marks ? "" : "already "), (set ? "" : "un"),
+ (ulong)ptr, size);
+ dprintstr();
+ dputc('\n');
+ }
+#endif
+ return marks;
+}
+
+/* Clear the relocation for strings. */
+/* This requires setting the marks. */
+void
+gc_strings_clear_reloc(chunk_t *cp)
+{ if ( cp->sreloc != 0 )
+ { gc_strings_set_marks(cp, true);
+ if_debug1('6', "[6]clearing string reloc 0x%lx\n",
+ (ulong)cp->sreloc);
+ gc_strings_set_reloc(cp);
+ }
+}
+
+/* Count the 0-bits in a byte. */
+private const byte count_zero_bits_table[256] = {
+#define o4(n) n,n-1,n-1,n-2
+#define o16(n) o4(n),o4(n-1),o4(n-1),o4(n-2)
+#define o64(n) o16(n),o16(n-1),o16(n-1),o16(n-2)
+ o64(8), o64(7), o64(7), o64(6)
+};
+#define byte_count_zero_bits(byt)\
+ (uint)(count_zero_bits_table[byt])
+#define byte_count_one_bits(byt)\
+ (uint)(8 - count_zero_bits_table[byt])
+
+/* Set the relocation for the strings in a chunk. */
+/* The sreloc table stores the relocated offset from climit for */
+/* the beginning of each block of string_data_quantum characters. */
+void
+gc_strings_set_reloc(chunk_t *cp)
+{ if ( cp->sreloc != 0 && cp->smark != 0 )
+ { byte *bot = cp->ctop;
+ byte *top = cp->climit;
+ uint count =
+ (top - bot + (string_data_quantum - 1)) >>
+ log2_string_data_quantum;
+ string_reloc_offset *relp =
+ cp->sreloc +
+ (cp->smark_size >> (log2_string_data_quantum - 3));
+ register byte *bitp = cp->smark + cp->smark_size;
+ register string_reloc_offset reloc = 0;
+
+ while ( count-- )
+ { bitp -= string_data_quantum / 8;
+ reloc += string_data_quantum -
+ byte_count_zero_bits(bitp[0]);
+ reloc -= byte_count_zero_bits(bitp[1]);
+ reloc -= byte_count_zero_bits(bitp[2]);
+ reloc -= byte_count_zero_bits(bitp[3]);
+#if log2_string_data_quantum > 5
+ reloc -= byte_count_zero_bits(bitp[4]);
+ reloc -= byte_count_zero_bits(bitp[5]);
+ reloc -= byte_count_zero_bits(bitp[6]);
+ reloc -= byte_count_zero_bits(bitp[7]);
+#endif
+ *--relp = reloc;
+ }
+ }
+ cp->sdest = cp->climit;
+}
+
+/* Relocate a string pointer. */
+void
+gs_reloc_string(gs_string *sptr, gc_state_t *gcst)
+{ byte *ptr;
+ const chunk_t *cp;
+ uint offset;
+ uint reloc;
+ const byte *bitp;
+ byte byt;
+
+ if ( sptr->size == 0 )
+ { sptr->data = 0;
+ return;
+ }
+ ptr = sptr->data;
+ if ( !(cp = gc_locate(ptr, gcst)) ) /* not in a chunk */
+ return;
+ if ( cp->sreloc == 0 || cp->smark == 0 ) /* not marking strings */
+ return;
+ offset = ptr - cp->sbase;
+ reloc = cp->sreloc[offset >> log2_string_data_quantum];
+ bitp = &cp->smark[offset >> 3];
+ switch ( offset & (string_data_quantum - 8) )
+ {
+#if log2_string_data_quantum > 5
+ case 56: reloc -= byte_count_one_bits(bitp[-7]);
+ case 48: reloc -= byte_count_one_bits(bitp[-6]);
+ case 40: reloc -= byte_count_one_bits(bitp[-5]);
+ case 32: reloc -= byte_count_one_bits(bitp[-4]);
+#endif
+ case 24: reloc -= byte_count_one_bits(bitp[-3]);
+ case 16: reloc -= byte_count_one_bits(bitp[-2]);
+ case 8: reloc -= byte_count_one_bits(bitp[-1]);
+ }
+ byt = *bitp & (0xff >> (8 - (offset & 7)));
+ reloc -= byte_count_one_bits(byt);
+ if_debug2('5', "[5]relocate string 0x%lx to 0x%lx\n",
+ (ulong)ptr, (ulong)(cp->sdest - reloc));
+ sptr->data = cp->sdest - reloc;
+}
+void
+gs_reloc_const_string(gs_const_string *sptr, gc_state_t *gcst)
+{ /* We assume the representation of byte * and const byte * is */
+ /* the same.... */
+ gs_reloc_string((gs_string *)sptr, gcst);
+}
+
+/* Compact the strings in a chunk. */
+void
+gc_strings_compact(chunk_t *cp)
+{ if ( cp->smark != 0 )
+ { byte *hi = cp->climit;
+ byte *lo = cp->ctop;
+ register const byte *from = hi;
+ register byte *to = hi;
+ register const byte *bp = cp->smark + cp->smark_size;
+
+#ifdef DEBUG
+ if ( gs_debug_c('4') || gs_debug_c('5') )
+ { byte *base = cp->sbase;
+ uint i = (lo - base) & -string_data_quantum;
+ uint n = round_up(hi - base, string_data_quantum);
+#define R 16
+ for ( ; i < n; i += R )
+ { uint j;
+
+ dprintf1("[4]0x%lx: ", (ulong)(base + i));
+ for ( j = i; j < i + R; j++ )
+ { byte ch = base[j];
+
+ if ( ch <= 31 )
+ { dputc('^'); dputc(ch + 0100); }
+ else
+ dputc(ch);
+ }
+ dputc(' ');
+ for ( j = i; j < i + R; j++ )
+ dputc((cp->smark[j >> 3] & (1 << (j & 7)) ?
+ '+' : '.'));
+#undef R
+ if ( !(i & (string_data_quantum - 1)) )
+ dprintf1(" %u", cp->sreloc[i >> log2_string_data_quantum]);
+ dputc('\n');
+ }
+ }
+#endif
+ while ( from > lo )
+ { register byte b = *--bp;
+
+ from -= 8;
+ switch ( b )
+ {
+ case 0xff:
+ to -= 8;
+ if ( to != from )
+ { to[7] = from[7]; to[6] = from[6];
+ to[5] = from[5]; to[4] = from[4];
+ to[3] = from[3]; to[2] = from[2];
+ to[1] = from[1]; to[0] = from[0];
+ }
+ break;
+ default:
+ if ( b & 0x80 ) *--to = from[7];
+ if ( b & 0x40 ) *--to = from[6];
+ if ( b & 0x20 ) *--to = from[5];
+ if ( b & 0x10 ) *--to = from[4];
+ if ( b & 8 ) *--to = from[3];
+ if ( b & 4 ) *--to = from[2];
+ if ( b & 2 ) *--to = from[1];
+ if ( b & 1 ) *--to = from[0];
+ /* falls through */
+ case 0:
+ ;
+ }
+ }
+ gs_alloc_fill(cp->ctop, gs_alloc_fill_collected,
+ to - cp->ctop);
+ cp->ctop = to;
+ }
+}
diff --git a/gs/src/igcstr.h b/gs/src/igcstr.h
new file mode 100644
index 000000000..99377adfd
--- /dev/null
+++ b/gs/src/igcstr.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igcstr.h */
+/* Internal interface to string garbage collector */
+
+/* Exported by ilocate.c for igcstr.c */
+chunk_t *gc_locate(P2(const void *, gc_state_t *));
+
+/* Exported by igcstr.c for igc.c */
+void gc_strings_set_marks(P2(chunk_t *, bool));
+bool gc_string_mark(P4(const byte *, uint, bool, gc_state_t *));
+void gc_strings_clear_reloc(P1(chunk_t *));
+void gc_strings_set_reloc(P1(chunk_t *));
+void gc_strings_compact(P1(chunk_t *));
diff --git a/gs/src/igstate.h b/gs/src/igstate.h
new file mode 100644
index 000000000..c8d734551
--- /dev/null
+++ b/gs/src/igstate.h
@@ -0,0 +1,162 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* igstate.h */
+/* Ghostscript interpreter graphics state definition */
+#include "gsstate.h"
+#include "gxstate.h" /* for 'client data' access */
+#include "istruct.h" /* for gstate obj definition */
+
+/*
+ * From the interpreter's point of view, the graphics state is largely opaque,
+ * i.e., the interpreter is just another client of the library.
+ * The interpreter does require additional items in the graphics state;
+ * these are "client data" from the library's point of view.
+ * Most of the complexity in this added state comes from
+ * the parameters associated with the various Level 2 color spaces.
+ * Note that the added information consists entirely of refs.
+ */
+
+/*
+ * The interpreter represents graphics state objects in a slightly
+ * unnatural way, namely, by a t_astruct ref that points to an object
+ * of type st_igstate_obj, which is essentially a t_struct ref that in turn
+ * points to a real graphics state (object of type st_gs_state).
+ * We do this so that save and restore can manipulate the intermediate
+ * object and not have to worry about copying entire gs_states.
+ *
+ * Because a number of different operators must test whether an object
+ * is a gstate, we make an exception to our convention of declaring
+ * structure descriptors only in the place where the structure itself
+ * is defined (see gsstruct.h for more information on this).
+ */
+typedef struct igstate_obj_s {
+ ref gstate; /* t_struct / st_gs_state */
+} igstate_obj;
+extern_st(st_igstate_obj);
+#define public_st_igstate_obj() /* in zdps1.c */\
+ gs_public_st_ref_struct(st_igstate_obj, igstate_obj, "gstatetype")
+#define igstate_ptr(rp) r_ptr(&r_ptr(rp, igstate_obj)->gstate, gs_state)
+
+/* CIE transformation procedures */
+typedef struct ref_cie_procs_s {
+ union {
+ ref DEFG;
+ ref DEF;
+ } PreDecode;
+ union {
+ ref ABC;
+ ref A;
+ } Decode;
+ ref DecodeLMN;
+} ref_cie_procs;
+/* CIE rendering transformation procedures */
+typedef struct ref_cie_render_procs_s {
+ ref TransformPQR, EncodeLMN, EncodeABC, RenderTableT;
+} ref_cie_render_procs;
+
+/* Separation name and tint transform */
+typedef struct ref_separation_params_s {
+ ref layer_name, tint_transform;
+} ref_separation_params;
+
+/* All color space parameters. */
+/* All of these are optional. */
+/* Note that they may actually be the parameters for an underlying or */
+/* alternate space for a special space. */
+typedef struct ref_color_procs_s {
+ ref_cie_procs cie;
+ union {
+ ref_separation_params separation;
+ ref index_proc;
+ } special;
+} ref_color_procs;
+typedef struct ref_colorspace_s {
+ ref array; /* color space (array), */
+ /* only relevant if the current */
+ /* color space has parameters associated with it. */
+ ref_color_procs procs; /* associated procedures/parameters, */
+ /* only relevant for CIE, Separation, Indexed/CIE, */
+ /* Indexed with procedure, or a Pattern with one of these. */
+} ref_colorspace;
+
+typedef struct int_gstate_s {
+ ref dash_pattern; /* (array) */
+ /* Screen_procs are only relevant if setscreen was */
+ /* executed more recently than sethalftone */
+ /* (for this graphics context). */
+ union {
+ ref indexed[4];
+ struct {
+ /* The components must be in this order: */
+ ref red, green, blue, gray;
+ } colored;
+ } screen_procs, /* halftone screen procedures */
+ transfer_procs; /* transfer procedures */
+ ref black_generation; /* (procedure) */
+ ref undercolor_removal; /* (procedure) */
+ ref_colorspace colorspace;
+ /* Pattern is only relevant if the current color space */
+ /* is a pattern space. */
+ ref pattern; /* pattern (dictionary) */
+ struct {
+ ref dict; /* CIE color rendering dictionary */
+ ref_cie_render_procs procs; /* (see above) */
+ } colorrendering;
+ /* Halftone is only relevant if sethalftone was executed */
+ /* more recently than setscreen for this graphics context. */
+ /* setscreen sets it to null. */
+ ref halftone; /* halftone (dictionary) */
+ /* Pagedevice is only relevant if setpagedevice was */
+ /* executed more recently than nulldevice, setcachedevice, */
+ /* or setdevice with a non-page device (for this */
+ /* graphics context). If the current device is not a */
+ /* page device, pagedevice is an empty dictionary. */
+ ref pagedevice; /* page device (dictionary) */
+} int_gstate;
+extern ref i_null_pagedevice;
+#define clear_pagedevice(pigs) ((pigs)->pagedevice = i_null_pagedevice)
+/*
+ * Even though the interpreter's part of the graphics state actually
+ * consists of refs, allocating it as refs tends to create sandbars;
+ * since it is always allocated and freed as a unit, we can treat it
+ * as an ordinary structure.
+ */
+#define private_st_int_gstate() /* in zgstate.c */\
+ gs_private_st_ref_struct(st_int_gstate, int_gstate, "int_gstate")
+
+/* Enumerate the refs in an int_gstate. */
+/* Since all the elements of an int_gstate are refs, this is simple. */
+#define int_gstate_map_refs(p,m)\
+ { register ref *rp_ = (ref *)(p);\
+ register int i = sizeof(int_gstate) / sizeof(ref);\
+ do { m(rp_); ++rp_; } while ( --i );\
+ }
+
+#ifdef DPNEXT
+/* Create the gstate for a new context. */
+/* We export this so that fork can use it. */
+gs_state *int_gstate_alloc(P1(gs_ref_memory_t *mem));
+#endif
+
+/* Get the int_gstate from a gs_state. */
+#define gs_int_gstate(pgs) ((int_gstate *)gs_state_client_data(pgs))
+
+/* The current instances. */
+extern gs_state *igs;
+#define istate gs_int_gstate(igs)
diff --git a/gs/src/iht.h b/gs/src/iht.h
new file mode 100644
index 000000000..a8192b9d0
--- /dev/null
+++ b/gs/src/iht.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iht.h */
+/* Procedures exported by zht.c for zht1.c and zht2.c */
+
+int zscreen_params(P2(os_ptr op, gs_screen_halftone *phs));
+
+int zscreen_enum_init(P7(os_ptr op, const gx_ht_order *porder,
+ gs_screen_halftone *phs, ref *pproc, int npop,
+ int (*finish_proc)(P1(os_ptr)), gs_memory_t *mem));
diff --git a/gs/src/iimage.h b/gs/src/iimage.h
new file mode 100644
index 000000000..6d2f277e6
--- /dev/null
+++ b/gs/src/iimage.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iimage.h */
+/* Internal interpreter interfaces to image painting */
+/* Requires gscspace.h, gsiparam.h */
+
+/* These procedures are exported by zimage.c for other modules. */
+
+/* Exported for zimage2.c */
+int zimage_setup(P4(const gs_image_t *pim, bool multi, const ref *sources,
+ int npop));
+
+/* Exported for zcolor1.c and zdpnext.c */
+#ifdef DPNEXT
+int zimage_opaque_setup(P5(os_ptr op, bool multi, bool has_alpha,
+ const gs_color_space *pcs, int npop));
+#else
+int zimage_opaque_setup(P4(os_ptr op, bool multi,
+ const gs_color_space *pcs, int npop));
+#endif
diff --git a/gs/src/iinit.c b/gs/src/iinit.c
new file mode 100644
index 000000000..b85270189
--- /dev/null
+++ b/gs/src/iinit.c
@@ -0,0 +1,462 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iinit.c */
+/* Initialize internally known objects for Ghostscript interpreter */
+#include "string_.h"
+#include "ghost.h"
+#include "gscdefs.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#define INCLUDE_ERROR_NAMES /* see errors.h */
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "interp.h"
+#include "ipacked.h"
+#include "iparray.h"
+#include "iutil.h"
+#include "ivmspace.h"
+#include "opdef.h"
+#include "store.h"
+
+/* Implementation parameters. */
+/* The size of systemdict can be set in the makefile. */
+/* We want the sizes to be prime numbers large enough to cover */
+/* all the operators, plus everything in the init files, */
+/* even if all the optional features are selected. */
+#ifndef SYSTEMDICT_SIZE
+# define SYSTEMDICT_SIZE 563
+#endif
+#ifndef SYSTEMDICT_LEVEL2_SIZE
+# define SYSTEMDICT_LEVEL2_SIZE 809
+#endif
+/* The size of level2dict, if applicable, can be set in the makefile. */
+#ifndef LEVEL2DICT_SIZE
+# define LEVEL2DICT_SIZE 191
+#endif
+/* Ditto the size of filterdict. */
+#ifndef FILTERDICT_SIZE
+# define FILTERDICT_SIZE 43
+#endif
+/* Ditto the size of internaldict. */
+#ifndef INTERNALDICT_SIZE
+# define INTERNALDICT_SIZE 3
+#endif
+/* Define an arbitrary size for the operator procedure tables. */
+#ifndef OP_ARRAY_TABLE_SIZE
+# define OP_ARRAY_TABLE_SIZE 150
+#endif
+#ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
+# define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
+#endif
+#ifndef OP_ARRAY_TABLE_LOCAL_SIZE
+# define OP_ARRAY_TABLE_LOCAL_SIZE (OP_ARRAY_TABLE_SIZE / 2)
+#endif
+#define OP_ARRAY_TABLE_TOTAL_SIZE\
+ (OP_ARRAY_TABLE_GLOBAL_SIZE + OP_ARRAY_TABLE_LOCAL_SIZE)
+
+/* The operator tables */
+extern op_def_ptr (*(op_defs_all[]))(P0()); /* in iconfig.c */
+/* Because of a bug in Sun's SC1.0 compiler, */
+/* we have to spell out the typedef for op_def_ptr here: */
+const op_def **op_def_table;
+uint op_def_count;
+op_array_table op_array_table_global, op_array_table_local; /* definitions of `operator' procedures */
+uint op_array_count;
+/* GC roots for the same */
+private gs_gc_root_t
+ op_def_root, op_array_root_global, op_array_root_local,
+ op_array_nx_root_global, op_array_nx_root_local;
+
+/* Enter a name and value into a dictionary. */
+void
+initial_enter_name_in(const char *nstr, const ref *pref, ref *pdict)
+{ int code = dict_put_string(pdict, nstr, pref);
+ if ( code < 0 )
+ { lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
+ code, nstr, dict_length(pdict), dict_maxlength(pdict));
+ gs_exit(1);
+ }
+}
+void
+initial_enter_name(const char *nstr, const ref *pref)
+{ initial_enter_name_in(nstr, pref, systemdict);
+}
+
+/* Remove a name from systemdict. */
+void
+initial_remove_name(const char *nstr)
+{ ref nref;
+ if ( name_ref((const byte *)nstr, strlen(nstr), &nref, -1) >= 0 )
+ dict_undef(systemdict, &nref);
+}
+
+/* Create a name. Fatal error if it fails. */
+private void
+name_enter(const char *str, ref *pref)
+{ if ( name_enter_string(str, pref) != 0 )
+ { lprintf1("name_enter failed - %s\n", str);
+ gs_exit(1);
+ }
+}
+
+/* Define the names and sizes of the initial dictionaries. */
+/* The names are used to create references in systemdict. */
+const struct { const char *name; uint size; bool local; }
+ initial_dictionaries[] = {
+#ifdef INITIAL_DICTIONARIES
+ INITIAL_DICTIONARIES
+#else
+ /* systemdict is created and named automagically */
+ { "level2dict", LEVEL2DICT_SIZE, false },
+ { "globaldict", 0, false },
+ { "userdict", 0, true },
+ { "filterdict", FILTERDICT_SIZE, false },
+ { "internaldict", INTERNALDICT_SIZE, true }
+#endif
+};
+/* systemdict and globaldict are magically inserted at the bottom */
+const char *initial_dstack[] = {
+#ifdef INITIAL_DSTACK
+ INITIAL_DSTACK
+#else
+ "userdict"
+#endif
+};
+#define MIN_DSTACK_SIZE (countof(initial_dstack) + 1) /* +1 for systemdict */
+
+
+/* Detect whether we have any Level 2 operators. */
+/* We export this for gs_init1 in gsmain.c. */
+/* This is very slow, but we only call it a couple of times. */
+bool
+gs_have_level2(void)
+{ op_def_ptr (**tptr)(P0());
+
+ for ( tptr = op_defs_all; *tptr != 0; tptr++ )
+ { const op_def *def;
+ for ( def = (*tptr)(); def->oname != 0; def++ )
+ if ( op_def_is_begin_dict(def) &&
+ !strcmp(def->oname, "level2dict")
+ )
+ return true;
+ }
+ return false;
+}
+
+/* Create an initial dictionary if necessary. */
+private ref *
+make_initial_dict(const char *iname, ref idicts[])
+{ int i;
+
+ /* systemdict was created specially. */
+ if ( !strcmp(iname, "systemdict") )
+ return &ref_systemdict;
+ for ( i = 0; i < countof(initial_dictionaries); i++ )
+ { const char *dname = initial_dictionaries[i].name;
+ const int dsize = initial_dictionaries[i].size;
+
+ if ( !strcmp(iname, dname) )
+ { ref *dref = &idicts[i];
+ if ( r_has_type(dref, t_null) )
+ { int code;
+ /* Perhaps dict_create should take */
+ /* the allocator as an argument.... */
+ uint space = ialloc_space(idmemory);
+ ialloc_set_space(idmemory,
+ (initial_dictionaries[i].local ?
+ avm_local : avm_global));
+ code = dict_create(dsize, dref);
+ ialloc_set_space(idmemory, space);
+ if ( code < 0 )
+ return 0; /* disaster */
+ }
+ return dref;
+ }
+ }
+
+ /*
+ * Name mentioned in some op_def, but not in initial_dictionaries.
+ * Punt.
+ */
+ return 0;
+}
+
+/* Initialize objects other than operators. In particular, */
+/* initialize the dictionaries that hold operator definitions. */
+void
+obj_init(void)
+{ uint space = ialloc_space(idmemory);
+ bool level2 = gs_have_level2();
+
+ /* Initialize the language level. */
+ make_int(&ref_language_level, 1);
+
+ /* Initialize the interpreter. */
+ gs_interp_init();
+
+ {
+#define icount countof(initial_dictionaries)
+ ref idicts[icount];
+ int i;
+ op_def_ptr (**tptr)(P0());
+
+ min_dstack_size = MIN_DSTACK_SIZE;
+
+ refset_null(idicts, icount);
+
+ /* Create systemdict. */
+ ialloc_set_space(idmemory, avm_global);
+ if ( level2 )
+ { dsp += 2;
+ dict_create(SYSTEMDICT_LEVEL2_SIZE, dsp);
+ /* For the moment, let globaldict be an alias */
+ /* for systemdict. */
+ dsp[-1] = *dsp;
+ min_dstack_size++;
+ }
+ else
+ { ++dsp;
+ dict_create(SYSTEMDICT_SIZE, dsp);
+ }
+ ref_systemdict = *dsp;
+ ialloc_set_space(idmemory, space);
+
+ /* Create dictionaries which are to be homes for operators. */
+ for ( tptr = op_defs_all; *tptr != 0; tptr++ )
+ { const op_def *def;
+ for ( def = (*tptr)(); def->oname != 0; def++ )
+ if ( op_def_is_begin_dict(def) )
+ make_initial_dict(def->oname, idicts);
+ }
+
+ /* Set up the initial dstack. */
+ for ( i = 0; i < countof(initial_dstack); i++ )
+ { const char *dname = initial_dstack[i];
+ ++dsp;
+ ref_assign(dsp, make_initial_dict(dname, idicts));
+ }
+
+ /* Enter names of referenced initial dictionaries into systemdict. */
+ initial_enter_name("systemdict", &ref_systemdict);
+ for (i = 0; i < icount; i++)
+ { ref *idict = &idicts[i];
+ if ( !r_has_type(idict, t_null) )
+ { /*
+ * Note that we enter the dictionary in systemdict
+ * even if it is in local VM. There is a special
+ * provision in the garbage collector for this:
+ * see ivmspace.h for more information.
+ * In order to do this, we must temporarily
+ * identify systemdict as local, so that the
+ * store check in dict_put won't fail.
+ */
+ uint save_space = r_space(systemdict);
+ r_set_space(systemdict, avm_local);
+ initial_enter_name(initial_dictionaries[i].name,
+ idict);
+ r_set_space(systemdict, save_space);
+ }
+ }
+#undef icount
+ }
+
+ gs_interp_reset();
+
+ { ref vtemp;
+ make_null(&vtemp);
+ initial_enter_name("null", &vtemp);
+ make_true(&vtemp);
+ initial_enter_name("true", &vtemp);
+ make_false(&vtemp);
+ initial_enter_name("false", &vtemp);
+ }
+
+ /* Create the error name table */
+ { int n = countof(gs_error_names) - 1;
+ int i;
+ ref era;
+ ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
+ for ( i = 0; i < n; i++ )
+ name_enter((const char *)gs_error_names[i],
+ era.value.refs + i);
+ initial_enter_name("ErrorNames", &era);
+ }
+}
+
+/* Run the initialization procedures of the individual operator files. */
+void
+zop_init(void)
+{ op_def_ptr (**tptr)(P0());
+ /* Because of a bug in Sun's SC1.0 compiler, */
+ /* we have to spell out the typedef for op_def_ptr here: */
+ const op_def *def;
+ for ( tptr = op_defs_all; *tptr != 0; tptr++ )
+ { for ( def = (*tptr)(); def->oname != 0; def++ )
+ DO_NOTHING;
+ if ( def->proc != 0 )
+ ((void (*)(P0()))(def->proc))();
+ }
+
+ /* Initialize the predefined names other than operators. */
+ /* Do this here in case op_init changed any of them. */
+ { ref vtemp;
+ make_const_string(&vtemp, a_readonly | avm_foreign,
+ strlen(gs_copyright),
+ (const byte *)gs_copyright);
+ initial_enter_name("copyright", &vtemp);
+ make_const_string(&vtemp, a_readonly | avm_foreign,
+ strlen(gs_product),
+ (const byte *)gs_product);
+ initial_enter_name("product", &vtemp);
+ make_int(&vtemp, gs_revision);
+ initial_enter_name("revision", &vtemp);
+ make_int(&vtemp, gs_revisiondate);
+ initial_enter_name("revisiondate", &vtemp);
+ }
+}
+
+/* Create an op_array table. */
+private int
+alloc_op_array_table(uint size, uint space, op_array_table *opt)
+{ uint save_space = ialloc_space(idmemory);
+ int code;
+ ialloc_set_space(idmemory, space);
+ code = ialloc_ref_array(&opt->table, a_readonly, size,
+ "op_array table");
+ ialloc_set_space(idmemory, save_space);
+ if ( code < 0 )
+ return code;
+ refset_null(opt->table.value.refs, size);
+ opt->nx_table =
+ (ushort *)ialloc_byte_array(size, sizeof(ushort),
+ "op_array nx_table");
+ if ( opt->nx_table == 0 )
+ return_error(e_VMerror);
+ opt->count = 0;
+ opt->root_p = &opt->table;
+ opt->attrs = space | a_executable;
+ return 0;
+}
+
+/* Initialize the operator table. */
+void
+op_init(void)
+{ int count = 1;
+ op_def_ptr (**tptr)(P0());
+ /* Because of a bug in Sun's SC1.0 compiler, */
+ /* we have to spell out the typedef for op_def_ptr here: */
+ const op_def *def;
+ const char _ds *nstr;
+
+ /* Do a first pass just to count the operators. */
+
+ for ( tptr = op_defs_all; *tptr != 0; tptr ++ )
+ { for ( def = (*tptr)(); def->oname != 0; def++ )
+ if ( !op_def_is_begin_dict(def) )
+ count++;
+ }
+
+ /* Do a second pass to construct the operator table, */
+ /* and enter the operators into the appropriate dictionary. */
+
+ /* Because of a bug in Sun's SC1.0 compiler, */
+ /* we have to spell out the typedef for op_def_ptr here: */
+ op_def_table =
+ (const op_def **)ialloc_byte_array(count, sizeof(op_def_ptr),
+ "op_init(op_def_table)");
+ op_def_count = count;
+ for (count = 0; count <= gs_interp_num_special_ops; count++)
+ op_def_table[count] = 0;
+ count = gs_interp_num_special_ops + 1; /* leave space for magic entries */
+ for ( tptr = op_defs_all; *tptr != 0; tptr ++ )
+ { ref *pdict = systemdict;
+ for ( def = (*tptr)(); (nstr = def->oname) != 0; def++ )
+ if ( op_def_is_begin_dict(def) )
+ { ref nref;
+ int code = name_ref((const byte *)nstr, strlen(nstr),
+ &nref, -1);
+
+ if ( code != 0 )
+ gs_abort();
+ if ( !dict_find(systemdict, &nref, &pdict) )
+ gs_abort();
+ if ( !r_has_type(pdict, t_dictionary) )
+ gs_abort();
+ }
+ else
+ { ref oper;
+ uint opidx;
+
+ gs_interp_make_oper(&oper, def->proc, count);
+ opidx = r_size(&oper);
+ /* The first character of the name is a digit */
+ /* giving the minimum acceptable number of operands. */
+ /* Check to make sure it's within bounds. */
+ if ( *nstr - '0' > gs_interp_max_op_num_args )
+ gs_abort();
+ nstr++;
+ /* Don't enter internal operators into */
+ /* the dictionary. */
+ if ( *nstr != '%' )
+ initial_enter_name_in(nstr, &oper, pdict);
+ op_def_table[opidx] = def;
+ if ( opidx == count )
+ count++;
+ }
+ }
+ /* All of the built-ins had better be defined somewhere, */
+ /* or things like op_find_index will choke. */
+ for ( count = 1; count <= gs_interp_num_special_ops; count++ )
+ if ( op_def_table[count] == 0 )
+ gs_abort();
+ gs_register_struct_root(imemory, &op_def_root,
+ (void **)&op_def_table, "op_def_table");
+
+ /* Allocate the tables for `operator' procedures. */
+ /* Make one of them local so we can have local operators. */
+
+ if ( alloc_op_array_table(OP_ARRAY_TABLE_GLOBAL_SIZE,
+ avm_global, &op_array_table_global) < 0 )
+ gs_abort();
+ op_array_table_global.base_index = op_def_count;
+ gs_register_ref_root(imemory, &op_array_root_global,
+ (void **)&op_array_table_global.root_p,
+ "op_array_table(global)");
+ gs_register_struct_root(imemory, &op_array_nx_root_global,
+ (void **)&op_array_table_global.nx_table,
+ "op_array nx_table(global)");
+
+ if ( alloc_op_array_table(OP_ARRAY_TABLE_LOCAL_SIZE,
+ avm_local, &op_array_table_local) < 0 )
+ gs_abort();
+ op_array_table_local.base_index =
+ op_array_table_global.base_index +
+ r_size(&op_array_table_global.table);
+ gs_register_ref_root(imemory, &op_array_root_local,
+ (void **)&op_array_table_local.root_p,
+ "op_array_table(local)");
+ gs_register_struct_root(imemory, &op_array_nx_root_local,
+ (void **)&op_array_table_local.nx_table,
+ "op_array nx_table(local)");
+
+}
diff --git a/gs/src/ilevel.h b/gs/src/ilevel.h
new file mode 100644
index 000000000..cf0fffaca
--- /dev/null
+++ b/gs/src/ilevel.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ilevel.h */
+/* Interpreter language level interface for Ghostscript */
+
+/* The current interpreter language level (1 or 2) */
+extern ref ref_language_level;
+#define level2_enabled ((int)ref_language_level.value.intval == 2)
diff --git a/gs/src/ilocate.c b/gs/src/ilocate.c
new file mode 100644
index 000000000..b02dc40d4
--- /dev/null
+++ b/gs/src/ilocate.c
@@ -0,0 +1,405 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ilocate.c */
+/* Object locating and validating for Ghostscript memory manager */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "idict.h"
+#include "igc.h" /* for gc_state_t */
+#include "igcstr.h" /* for prototype */
+#include "iname.h"
+#include "ipacked.h"
+#include "isstate.h"
+#include "iutil.h" /* for packed_get */
+#include "ivmspace.h"
+#include "store.h"
+
+/* ================ Locating ================ */
+
+/* Locate a pointer in the chunks of a space being collected. */
+/* This is only used for string garbage collection and for debugging. */
+chunk_t *
+gc_locate(const void *ptr, gc_state_t *gcst)
+{ const gs_ref_memory_t *mem;
+ if ( chunk_locate(ptr, &gcst->loc) )
+ return gcst->loc.cp;
+ mem = gcst->loc.memory;
+ /* Try the other space, if there is one. */
+ if ( gcst->space_local != gcst->space_global )
+ { gcst->loc.memory =
+ (mem->space == avm_local ? gcst->space_global : gcst->space_local);
+ gcst->loc.cp = 0;
+ if ( chunk_locate(ptr, &gcst->loc) )
+ return gcst->loc.cp;
+ /* Try other save levels of this space. */
+ while ( gcst->loc.memory->saved != 0 )
+ { gcst->loc.memory = &gcst->loc.memory->saved->state;
+ gcst->loc.cp = 0;
+ if ( chunk_locate(ptr, &gcst->loc) )
+ return gcst->loc.cp;
+ }
+ }
+ /* Try the system space. This is simpler because it isn't */
+ /* subject to save/restore. */
+ if ( mem != gcst->space_system )
+ { gcst->loc.memory = gcst->space_system;
+ gcst->loc.cp = 0;
+ if ( chunk_locate(ptr, &gcst->loc) )
+ return gcst->loc.cp;
+ }
+ /* Try other save levels of the initial space, */
+ /* or of global space if the original space was system space. */
+ /* In the latter case, try all levels. */
+ gcst->loc.memory =
+ (mem == gcst->space_system || mem->space == avm_global ?
+ gcst->space_global : gcst->space_local);
+ for ( ; ; )
+ { if ( gcst->loc.memory != mem ) /* don't do twice */
+ { gcst->loc.cp = 0;
+ if ( chunk_locate(ptr, &gcst->loc) )
+ return gcst->loc.cp;
+ }
+ if ( gcst->loc.memory->saved == 0 )
+ break;
+ gcst->loc.memory = &gcst->loc.memory->saved->state;
+ }
+ /* Restore locator to a legal state. */
+ gcst->loc.memory = mem;
+ gcst->loc.cp = 0;
+ return 0;
+}
+
+/* ================ Debugging ================ */
+
+#ifdef DEBUG
+
+/* Validate the contents of an allocator. */
+void
+ialloc_validate_spaces(const gs_dual_memory_t *dmem)
+{ int i;
+ gc_state_t state;
+#define nspaces countof(dmem->spaces.indexed)
+ chunk_t cc[nspaces];
+ uint rsize[nspaces];
+ ref rlast[nspaces];
+
+ state.spaces = dmem->spaces;
+ state.loc.memory = state.spaces.named.local;
+ state.loc.cp = 0;
+
+ /* Save everything we need to reset temporarily. */
+ for ( i = 0; i < nspaces; i++ )
+ if ( dmem->spaces.indexed[i] != 0 )
+ { gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+ chunk_t *pcc = mem->pcc;
+ obj_header_t *rcur = mem->cc.rcur;
+ if ( pcc != 0 )
+ { cc[i] = *pcc;
+ *pcc = mem->cc;
+ }
+ if ( rcur != 0 )
+ { rsize[i] = rcur[-1].o_size;
+ rcur[-1].o_size = mem->cc.rtop - (byte *)rcur;
+ /* Create the final ref, reserved for the GC. */
+ rlast[i] = ((ref *)mem->cc.rtop)[-1];
+ make_mark((ref *)mem->cc.rtop - 1);
+ }
+ }
+
+ /* Validate memory. */
+ for ( i = 0; i < nspaces; i++ )
+ if ( dmem->spaces.indexed[i] != 0 )
+ ialloc_validate_memory(dmem->spaces.indexed[i], &state);
+
+ /* Undo temporary changes. */
+ for ( i = 0; i < nspaces; i++ )
+ if ( dmem->spaces.indexed[i] != 0 )
+ { gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+ chunk_t *pcc = mem->pcc;
+ obj_header_t *rcur = mem->cc.rcur;
+ if ( rcur != 0 )
+ { rcur[-1].o_size = rsize[i];
+ ((ref *)mem->cc.rtop)[-1] = rlast[i];
+ }
+ if ( pcc != 0 )
+ *pcc = cc[i];
+ }
+}
+void
+ialloc_validate_memory(const gs_ref_memory_t *mem, gc_state_t *gcst)
+{ const gs_ref_memory_t *smem;
+ int level;
+
+ for ( smem = mem, level = 0; smem != 0;
+ smem = &smem->saved->state, --level
+ )
+ { const chunk_t *cp;
+ int i;
+
+ if_debug3('6', "[6]validating memory 0x%lx, space %d, level %d\n",
+ (ulong)mem, mem->space, level);
+ /* Validate chunks. */
+ for ( cp = smem->cfirst; cp != 0; cp = cp->cnext )
+ ialloc_validate_chunk(cp, gcst);
+ /* Validate freelists. */
+ for ( i = 0; i < num_freelists; ++i )
+ { uint free_size = i << log2_obj_align_mod;
+ const obj_header_t *pfree;
+
+ for ( pfree = mem->freelists[i]; pfree != 0;
+ pfree = *(const obj_header_t * const *)pfree
+ )
+ { uint size = pfree[-1].o_size;
+
+ if ( pfree[-1].o_type != &st_free )
+ { lprintf3("Non-free object 0x%lx(%u) on freelist %i!\n",
+ (ulong)pfree, size, i);
+ break;
+ }
+ if ( size < free_size - obj_align_mask ||
+ size > free_size
+ )
+ { lprintf3("Object 0x%lx(%u) size wrong on freelist %i!\n",
+ (ulong)pfree, size, i);
+ break;
+ }
+ }
+ }
+ };
+}
+
+/* Check the validity of an object's size. */
+#define object_size_valid(pre, size, cp)\
+((pre)->o_large ? (const byte *)(pre) == (cp)->cbase :\
+ (size) <= (cp)->ctop - (const byte *)((pre) + 1))
+
+/* Validate all the objects in a chunk. */
+private void ialloc_validate_ref(P2(const ref *, gc_state_t *));
+void
+ialloc_validate_chunk(const chunk_t *cp, gc_state_t *gcst)
+{ if_debug_chunk('6', "[6]validating chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp);
+ DO_ALL
+ if ( pre->o_type == &st_free )
+ { if ( !object_size_valid(pre, size, cp) )
+ lprintf3("Bad free object 0x%lx(%lu), in chunk 0x%lx!\n",
+ (ulong)(pre + 1), (ulong)size, (ulong)cp);
+ }
+ else
+ ialloc_validate_object(pre + 1, cp, gcst);
+ if_debug3('7', " [7]validating %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)size, (ulong)pre);
+ if ( pre->o_type == &st_refs )
+ { const ref_packed *rp = (const ref_packed *)(pre + 1);
+ const char *end = (const char *)rp + size;
+
+ while ( (const char *)rp < end )
+ if ( r_is_packed(rp) )
+ { ref unpacked;
+ packed_get(rp, &unpacked);
+ ialloc_validate_ref(&unpacked, gcst);
+ rp++;
+ }
+ else
+ { ialloc_validate_ref((const ref *)rp, gcst);
+ rp += packed_per_ref;
+ }
+ }
+ else
+ { struct_proc_enum_ptrs((*proc)) =
+ pre->o_type->enum_ptrs;
+ uint index = 0;
+ const void *ptr;
+ gs_ptr_type_t ptype;
+
+ if ( proc != 0 )
+ for ( ; (ptype = (*proc)(pre + 1, size, index, &ptr)) != 0; ++index )
+ if ( ptr == 0 )
+ DO_NOTHING;
+ else if ( ptype == ptr_struct_type )
+ ialloc_validate_object(ptr, NULL, gcst);
+ else if ( ptype == ptr_ref_type )
+ ialloc_validate_ref(ptr, gcst);
+ }
+ END_OBJECTS_SCAN
+}
+/* Validate a ref. */
+private void
+ialloc_validate_ref(const ref *pref, gc_state_t *gcst)
+{ const void *optr;
+ const ref *rptr;
+ const char *tname;
+ uint size;
+
+ if ( !gs_debug_c('?') )
+ return; /* no check */
+ if ( r_space(pref) == avm_foreign )
+ return;
+ switch ( r_type(pref) )
+ {
+ case t_file:
+ optr = pref->value.pfile;
+ goto cks;
+ case t_device:
+ optr = pref->value.pdevice;
+ goto cks;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ optr = pref->value.pstruct;
+cks: if ( optr != 0 )
+ ialloc_validate_object(optr, NULL, gcst);
+ break;
+ case t_name:
+ if ( name_index_ptr(r_size(pref)) != pref->value.pname )
+ { lprintf3("At 0x%lx, bad name %u, pname = 0x%lx\n",
+ (ulong)pref, (uint)r_size(pref),
+ (ulong)pref->value.pname);
+ break;
+ }
+ { ref sref;
+ name_string_ref(pref, &sref);
+ if ( r_space(&sref) != avm_foreign &&
+ !gc_locate(sref.value.const_bytes, gcst)
+ )
+ { lprintf4("At 0x%lx, bad name %u, pname = 0x%lx, string 0x%lx not in any chunk\n",
+ (ulong)pref, (uint)r_size(pref),
+ (ulong)pref->value.pname,
+ (ulong)sref.value.const_bytes);
+ }
+ }
+ break;
+ case t_string:
+ if ( r_size(pref) != 0 && !gc_locate(pref->value.bytes, gcst) )
+ lprintf3("At 0x%lx, string ptr 0x%lx[%u] not in any chunk\n",
+ (ulong)pref, (ulong)pref->value.bytes,
+ (uint)r_size(pref));
+ break;
+ case t_array:
+ if ( r_size(pref) == 0 )
+ break;
+ rptr = pref->value.refs;
+ size = r_size(pref);
+ tname = "array";
+cka: if ( !gc_locate(rptr, gcst) )
+ { lprintf3("At 0x%lx, %s 0x%lx not in any chunk\n",
+ (ulong)pref, tname, (ulong)rptr);
+ break;
+ }
+ { uint i;
+ for ( i = 0; i < size; ++i )
+ { const ref *elt = rptr + i;
+ if ( r_is_packed(elt) )
+ lprintf5("At 0x%lx, %s 0x%lx[%u] element %u is not a ref\n",
+ (ulong)pref, tname, (ulong)rptr, size, i);
+ }
+ }
+ break;
+ case t_shortarray:
+ case t_mixedarray:
+ if ( r_size(pref) == 0 )
+ break;
+ optr = pref->value.packed;
+ if ( !gc_locate(optr, gcst) )
+ lprintf2("At 0x%lx, packed array 0x%lx not in any chunk\n",
+ (ulong)pref, (ulong)optr);
+ break;
+ case t_dictionary:
+ { const dict *pdict = pref->value.pdict;
+ if ( !r_has_type(&pdict->values, t_array) ||
+ !r_is_array(&pdict->keys) ||
+ !r_has_type(&pdict->count, t_integer) ||
+ !r_has_type(&pdict->maxlength, t_integer)
+ )
+ lprintf2("At 0x%lx, invalid dict 0x%lx\n",
+ (ulong)pref, (ulong)pdict);
+ rptr = (const ref *)pdict;
+ }
+ size = sizeof(dict) / sizeof(ref);
+ tname = "dict";
+ goto cka;
+ }
+}
+
+/* Validate an object. */
+void
+ialloc_validate_object(const obj_header_t *ptr, const chunk_t *cp,
+ gc_state_t *gcst)
+{ const obj_header_t *pre = ptr - 1;
+ ulong size = pre_obj_contents_size(pre);
+ gs_memory_type_ptr_t otype = pre->o_type;
+ const char *oname;
+
+ if ( !gs_debug_c('?') )
+ return; /* no check */
+ if ( cp == 0 && gcst != 0 )
+ { gc_state_t st;
+ st = *gcst; /* no side effects! */
+ if ( !(cp = gc_locate(pre, &st)) )
+ { lprintf1("Object 0x%lx not in any chunk!\n",
+ (ulong)ptr);
+ return;/*gs_abort();*/
+ }
+ }
+ if ( otype == &st_free )
+ { lprintf3("Reference to free object 0x%lx(%lu), in chunk 0x%lx!\n",
+ (ulong)ptr, (ulong)size, (ulong)cp);
+ gs_abort();
+ }
+ if ( (cp != 0 && !object_size_valid(pre, size, cp)) ||
+ otype->ssize == 0 ||
+ size % otype->ssize != 0 ||
+ (oname = struct_type_name_string(otype),
+ *oname < 33 || *oname > 126)
+ )
+ { lprintf4("Bad object 0x%lx(%lu), ssize = %u, in chunk 0x%lx!\n",
+ (ulong)ptr, (ulong)size, otype->ssize, (ulong)cp);
+ gs_abort();
+ }
+}
+
+#else /* !DEBUG */
+
+void
+ialloc_validate_spaces(const gs_dual_memory_t *dmem)
+{
+}
+
+void
+ialloc_validate_memory(const gs_ref_memory_t *mem, gc_state_t *gcst)
+{
+}
+
+void
+ialloc_validate_chunk(const chunk_t *cp, gc_state_t *gcst)
+{
+}
+
+void
+ialloc_validate_object(const obj_header_t *ptr, const chunk_t *cp,
+ gc_state_t *gcst)
+{
+}
+
+#endif /* (!)DEBUG */
diff --git a/gs/src/imain.c b/gs/src/imain.c
new file mode 100644
index 000000000..25cec1155
--- /dev/null
+++ b/gs/src/imain.c
@@ -0,0 +1,612 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* imain.c */
+/* Common support for interpreter front ends */
+#include "memory_.h"
+#include "string_.h"
+/* Capture stdin/out/err before gs.h redefines them. */
+#include <stdio.h>
+void
+gs_get_real_stdio(FILE *stdfiles[3])
+{ stdfiles[0] = stdin;
+ stdfiles[1] = stdout;
+ stdfiles[2] = stderr;
+}
+#include "ghost.h"
+#include "gp.h"
+#include "gslib.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gsutil.h" /* for bytes_compare */
+#include "gxdevice.h"
+#include "errors.h"
+#include "oper.h"
+#include "idebug.h"
+#include "idict.h"
+#include "iname.h" /* for name_init */
+#include "dstack.h"
+#include "estack.h"
+#include "ostack.h" /* put here for files.h */
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+#include "main.h"
+#include "store.h"
+#include "isave.h" /* for prototypes */
+#include "interp.h"
+#include "ivmspace.h"
+
+/* ------ Exported data ------ */
+
+/* Define the default instance of the interpreter. */
+/* Currently, this is the *only possible* instance, because most of */
+/* the places that need to take an explicit instance argument don't. */
+private gs_main_instance the_gs_main_instance;
+gs_main_instance *
+gs_main_instance_default(void)
+{ /* Determine whether the instance has been initialized. */
+ if ( the_gs_main_instance.memory_chunk_size == 0 )
+ the_gs_main_instance = gs_main_instance_init_values;
+ return &the_gs_main_instance;
+}
+
+/* The only reason we export gs_exit_status is so that window systems */
+/* with alert boxes can know whether to pause before exiting if */
+/* the program terminates with an error. There must be a better way .... */
+int gs_exit_status;
+
+/* ------ Imported data ------ */
+
+/* Configuration information imported from gconfig.c and iinit.c. */
+extern const char *gs_init_file;
+extern const byte far_data gs_init_string[];
+extern const uint far_data gs_init_string_sizeof;
+extern ref gs_init_file_array[];
+extern ref gs_emulator_name_array[];
+
+/* ------ Forward references ------ */
+
+private int gs_run_init_file(P3(gs_main_instance *, int *, ref *));
+#ifdef DEBUG
+private void print_usage(P3(const gs_main_instance *, gs_dual_memory_t *,
+ const char *));
+#endif
+
+/* ------ Initialization ------ */
+
+/* A handy way to declare and execute an initialization procedure: */
+#define call_init(proc)\
+{ extern void proc(P0()); proc(); }
+
+/* Initialization to be done before anything else. */
+void
+gs_main_init0(gs_main_instance *minst, FILE *in, FILE *out, FILE *err,
+ int max_lib_paths)
+{ /* Set our versions of stdin/out/err. */
+ gs_stdin = in;
+ gs_stdout = out;
+ gs_stderr = err;
+ /* Do platform-dependent initialization. */
+ /* We have to do this as the very first thing, */
+ /* because it detects attempts to run 80N86 executables (N>0) */
+ /* on incompatible processors. */
+ gp_init();
+#ifdef DEBUG
+ gp_get_usertime(minst->base_time);
+#endif
+ /* Initialize the imager. */
+ gs_lib_init0(gs_stdout);
+ /* Initialize the file search paths. */
+ make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
+ (ref *)gs_malloc(max_lib_paths, sizeof(ref),
+ "lib_path array"));
+ make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
+ minst->lib_path.container.value.refs);
+ minst->lib_path.env = 0;
+ minst->lib_path.final = 0;
+ minst->lib_path.count = 0;
+ minst->user_errors = 1;
+ minst->init_done = 0;
+}
+
+/* Initialization to be done before constructing any objects. */
+void
+gs_main_init1(gs_main_instance *minst)
+{ if ( minst->init_done < 1 )
+ { { extern bool gs_have_level2(P0());
+ ialloc_init(&gs_memory_default,
+ minst->memory_chunk_size,
+ gs_have_level2());
+ gs_lib_init1((gs_memory_t *)imemory_system);
+ alloc_save_init(idmemory);
+ }
+ if ( name_init(minst->name_table_size, imemory_system) == 0 )
+ { puts("name_init failed");
+ gs_exit(1);
+ }
+ call_init(obj_init) /* requires name_init */
+ call_init(scan_init) /* ditto */
+ minst->init_done = 1;
+ }
+}
+
+/* Initialization to be done before running any files. */
+private void
+init2_make_string_array(ref *srefs, const char *aname)
+{ ref *ifp = srefs;
+ ref ifa;
+ for ( ; ifp->value.bytes != 0; ifp++ )
+ r_set_size(ifp, strlen((const char *)ifp->value.bytes));
+ make_tasv(&ifa, t_array, a_readonly | avm_foreign,
+ ifp - srefs, refs, srefs);
+ initial_enter_name(aname, &ifa);
+}
+void
+gs_main_init2(gs_main_instance *minst)
+{ gs_main_init1(minst);
+ if ( minst->init_done < 2 )
+ { int code, exit_code;
+ ref error_object;
+ call_init(igs_init)
+ call_init(zop_init)
+ { extern void gs_iodev_init(P1(gs_memory_t *));
+ gs_iodev_init(imemory);
+ }
+ call_init(op_init) /* requires obj_init, scan_init */
+
+ /* Set up the array of additional initialization files. */
+ init2_make_string_array(gs_init_file_array, "INITFILES");
+ /* Set up the array of emulator names. */
+ init2_make_string_array(gs_emulator_name_array, "EMULATORS");
+ /* Pass the search path. */
+ initial_enter_name("LIBPATH", &minst->lib_path.list);
+
+ /* Execute the standard initialization file. */
+ code = gs_run_init_file(minst, &exit_code, &error_object);
+ if ( code < 0 )
+ { if ( code != e_Fatal )
+ gs_debug_dump_stack(code, &error_object);
+ gs_exit_with_code((exit_code ? exit_code : 2), code);
+ }
+ minst->init_done = 2;
+ }
+#ifdef DEBUG
+ if ( gs_debug_c(':') )
+ print_usage(minst, &gs_imemory, "Start");
+#endif
+}
+
+/* ------ Search paths ------ */
+
+/* Internal routine to add a set of directories to a search list. */
+/* Returns 0 or an error code. */
+private int
+file_path_add(gs_file_path *pfp, const char *dirs)
+{ uint len = r_size(&pfp->list);
+ const char *dpath = dirs;
+
+ if ( dirs == 0 )
+ return 0;
+ for ( ; ; )
+ { /* Find the end of the next directory name. */
+ const char *npath = dpath;
+
+ while ( *npath != 0 && *npath != gp_file_name_list_separator )
+ npath++;
+ if ( npath > dpath )
+ { if ( len == r_size(&pfp->container) )
+ return_error(e_limitcheck);
+ make_const_string(&pfp->container.value.refs[len],
+ avm_foreign | a_readonly,
+ npath - dpath, (const byte *)dpath);
+ ++len;
+ }
+ if ( !*npath )
+ break;
+ dpath = npath + 1;
+ }
+ r_set_size(&pfp->list, len);
+ return 0;
+}
+
+/* Add a library search path to the list. */
+void
+gs_main_add_lib_path(gs_main_instance *minst, const char *lpath)
+{ /* Account for the possibility that the first element */
+ /* is gp_current_directory name added by set_lib_paths. */
+ int first_is_here =
+ (r_size(&minst->lib_path.list) != 0 &&
+ minst->lib_path.container.value.refs[0].value.bytes ==
+ (const byte *)gp_current_directory_name ? 1 : 0);
+
+ r_set_size(&minst->lib_path.list, minst->lib_path.count +
+ first_is_here);
+ file_path_add(&minst->lib_path, lpath);
+ minst->lib_path.count = r_size(&minst->lib_path.list) - first_is_here;
+ gs_main_set_lib_paths(minst);
+}
+
+/* ------ Execution ------ */
+
+/* Complete the list of library search paths. */
+/* This may involve adding or removing the current directory */
+/* as the first element. */
+void
+gs_main_set_lib_paths(gs_main_instance *minst)
+{ ref *paths = minst->lib_path.container.value.refs;
+ int first_is_here =
+ (r_size(&minst->lib_path.list) != 0 &&
+ paths[0].value.bytes == (const byte *)gp_current_directory_name ? 1 : 0);
+ int count = minst->lib_path.count;
+
+ if ( minst->search_here_first )
+ { if ( !(first_is_here ||
+ (r_size(&minst->lib_path.list) != 0 &&
+ !bytes_compare((const byte *)gp_current_directory_name,
+ strlen(gp_current_directory_name),
+ paths[0].value.bytes,
+ r_size(&paths[0]))))
+ )
+ { memmove(paths + 1, paths, count * sizeof(*paths));
+ make_const_string(paths, avm_foreign | a_readonly,
+ strlen(gp_current_directory_name),
+ (const byte *)gp_current_directory_name);
+ }
+ }
+ else
+ { if ( first_is_here )
+ memmove(paths, paths + 1, count * sizeof(*paths));
+ }
+ r_set_size(&minst->lib_path.list,
+ count + (minst->search_here_first ? 1 : 0));
+ if ( minst->lib_path.env != 0 )
+ file_path_add(&minst->lib_path, minst->lib_path.env);
+ if ( minst->lib_path.final != 0 )
+ file_path_add(&minst->lib_path, minst->lib_path.final);
+}
+
+/* Open a file, using the search paths. */
+int
+gs_main_lib_open(gs_main_instance *minst, const char *file_name, ref *pfile)
+{ /* This is a separate procedure only to avoid tying up */
+ /* extra stack space while running the file. */
+#define maxfn 200
+ byte fn[maxfn];
+ uint len;
+ return lib_file_open(file_name, strlen(file_name), fn, maxfn,
+ &len, pfile);
+}
+
+/* Open and execute a file. */
+int
+gs_main_run_file(gs_main_instance *minst, const char *file_name, int user_errors, int *pexit_code, ref *perror_object)
+{ ref initial_file;
+ int code = gs_main_run_file_open(minst, file_name, &initial_file);
+ if ( code < 0 ) return code;
+ return gs_interpret(&initial_file, user_errors, pexit_code, perror_object);
+}
+int
+gs_main_run_file_open(gs_main_instance *minst, const char *file_name, ref *pfref)
+{ gs_main_set_lib_paths(minst);
+ if ( gs_main_lib_open(minst, file_name, pfref) < 0 )
+ { eprintf1("Can't find initialization file %s.\n", file_name);
+ return_error(e_Fatal);
+ }
+ r_set_attrs(pfref, a_execute + a_executable);
+ return 0;
+}
+
+/* Open and run the very first initialization file. */
+private int
+gs_run_init_file(gs_main_instance *minst, int *pexit_code, ref *perror_object)
+{ ref ifile;
+ ref first_token;
+ int code;
+ scanner_state state;
+
+ gs_main_set_lib_paths(minst);
+ if ( gs_init_string_sizeof == 0 )
+ { /* Read from gs_init_file. */
+ code = gs_main_run_file_open(minst, gs_init_file, &ifile);
+ }
+ else
+ { /* Read from gs_init_string. */
+ code = file_read_string(gs_init_string, gs_init_string_sizeof,
+ &ifile);
+ }
+ if ( code < 0 )
+ { *pexit_code = 255;
+ return code;
+ }
+ /* Check to make sure the first token is an integer */
+ /* (for the version number check.) */
+ scanner_state_init(&state, false);
+ code = scan_token(ifile.value.pfile, &first_token, &state);
+ if ( code != 0 || !r_has_type(&first_token, t_integer) )
+ { eprintf1("Initialization file %s does not begin with an integer.\n", gs_init_file);
+ *pexit_code = 255;
+ return_error(e_Fatal);
+ }
+ *++osp = first_token;
+ r_set_attrs(&ifile, a_executable);
+ return gs_interpret(&ifile, minst->user_errors,
+ pexit_code, perror_object);
+}
+
+/* Run a string. */
+int
+gs_main_run_string(gs_main_instance *minst, const char *str, int user_errors,
+ int *pexit_code, ref *perror_object)
+{ return gs_main_run_string_with_length(minst, str, (uint)strlen(str),
+ user_errors,
+ pexit_code, perror_object);
+}
+int
+gs_main_run_string_with_length(gs_main_instance *minst, const char *str,
+ uint length, int user_errors, int *pexit_code, ref *perror_object)
+{ int code;
+ code = gs_main_run_string_begin(minst, user_errors,
+ pexit_code, perror_object);
+ if ( code < 0 )
+ return code;
+ code = gs_main_run_string_continue(minst, str, length, user_errors,
+ pexit_code, perror_object);
+ if ( code != e_NeedInput )
+ return code;
+ return gs_main_run_string_end(minst, user_errors,
+ pexit_code, perror_object);
+}
+
+/* Set up for a suspendable run_string. */
+int
+gs_main_run_string_begin(gs_main_instance *minst, int user_errors,
+ int *pexit_code, ref *perror_object)
+{ const char *setup = ".runstringbegin";
+ ref rstr;
+ int code;
+
+ gs_main_set_lib_paths(minst);
+ make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
+ strlen(setup), (const byte *)setup);
+ code = gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+ return (code == e_NeedInput ? 0 : code == 0 ? e_Fatal : code);
+}
+/* Continue running a string with the option of suspending. */
+int
+gs_main_run_string_continue(gs_main_instance *minst, const char *str,
+ uint length, int user_errors, int *pexit_code, ref *perror_object)
+{ ref rstr;
+
+ if ( length == 0 )
+ return 0; /* empty string signals EOF */
+ make_const_string(&rstr, avm_foreign | a_readonly, length,
+ (const byte *)str);
+ return gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+}
+/* Signal EOF when suspended. */
+int
+gs_main_run_string_end(gs_main_instance *minst, int user_errors,
+ int *pexit_code, ref *perror_object)
+{ ref rstr;
+
+ make_empty_const_string(&rstr, avm_foreign | a_readonly);
+ return gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+}
+
+/* ------ Operand stack access ------ */
+
+/* These are built for comfort, not for speed. */
+
+private int
+push_value(ref *pvalue)
+{ int code = ref_stack_push(&o_stack, 1);
+ if ( code < 0 )
+ return code;
+ *ref_stack_index(&o_stack, 0L) = *pvalue;
+ return 0;
+}
+
+int
+gs_push_boolean(gs_main_instance *minst, bool value)
+{ ref vref;
+ make_bool(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_integer(gs_main_instance *minst, long value)
+{ ref vref;
+ make_int(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_real(gs_main_instance *minst, floatp value)
+{ ref vref;
+ make_real(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_string(gs_main_instance *minst, byte *chars, uint length,
+ bool read_only)
+{ ref vref;
+ make_string(&vref, avm_foreign | (read_only ? a_readonly : a_all),
+ length, (byte *)chars);
+ return push_value(&vref);
+}
+
+private int
+pop_value(ref *pvalue)
+{ if ( !ref_stack_count(&o_stack) )
+ return_error(e_stackunderflow);
+ *pvalue = *ref_stack_index(&o_stack, 0L);
+ return 0;
+}
+
+int
+gs_pop_boolean(gs_main_instance *minst, bool *result)
+{ ref vref;
+ int code = pop_value(&vref);
+ if ( code < 0 )
+ return code;
+ check_type_only(vref, t_boolean);
+ *result = vref.value.boolval;
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_integer(gs_main_instance *minst, long *result)
+{ ref vref;
+ int code = pop_value(&vref);
+ if ( code < 0 )
+ return code;
+ check_type_only(vref, t_integer);
+ *result = vref.value.intval;
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_real(gs_main_instance *minst, float *result)
+{ ref vref;
+ int code = pop_value(&vref);
+ if ( code < 0 )
+ return code;
+ switch ( r_type(&vref) )
+ {
+ case t_real:
+ *result = vref.value.realval;
+ break;
+ case t_integer:
+ *result = vref.value.intval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_string(gs_main_instance *minst, gs_string *result)
+{ ref vref;
+ int code = pop_value(&vref);
+ if ( code < 0 )
+ return code;
+ switch ( r_type(&vref) )
+ {
+ case t_name:
+ name_string_ref(&vref, &vref);
+ code = 1;
+ goto rstr;
+ case t_string:
+ code = (r_has_attr(&vref, a_write) ? 0 : 1);
+rstr: result->data = vref.value.bytes;
+ result->size = r_size(&vref);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ ref_stack_pop(&o_stack, 1);
+ return code;
+}
+
+/* ------ Termination ------ */
+
+/* Free all resources and exit. */
+void
+gs_main_finit(gs_main_instance *minst, int exit_status, int code)
+{ /*
+ * Previous versions of this code closed the devices in the
+ * device list here. Since these devices are now prototypes,
+ * they cannot be opened, so they do not need to be closed;
+ * alloc_restore_all will close dynamically allocated devices.
+ */
+ gs_exit_status = exit_status; /* see above */
+
+#ifdef DEBUG
+ if ( gs_debug_c(':') )
+ print_usage(minst, &gs_imemory, "Final");
+#endif
+ /* Do the equivalent of a restore "past the bottom". */
+ /* This will release all memory, close all open files, etc. */
+ if ( minst->init_done >= 1 )
+ alloc_restore_all(idmemory);
+ gs_lib_finit(exit_status, code);
+}
+void
+gs_exit_with_code(int exit_status, int code)
+{ gs_finit(exit_status, code);
+ gp_do_exit(exit_status);
+}
+void
+gs_exit(int exit_status)
+{ gs_exit_with_code(exit_status, 0);
+}
+
+/* ------ Debugging ------ */
+
+#ifdef DEBUG
+/* Print usage statistics. */
+private void
+print_usage(const gs_main_instance *minst, gs_dual_memory_t *dmem,
+ const char *msg)
+{ ulong allocated = 0, used = 0;
+ long utime[2];
+
+ gp_get_usertime(utime);
+ { int i;
+
+ for ( i = 0; i < countof(dmem->spaces.indexed); ++i ) {
+ gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+
+ if ( mem != 0 && (i == 0 || mem != dmem->spaces.indexed[i - 1]) ) {
+ gs_memory_status_t status;
+
+ gs_memory_status((gs_memory_t *)mem, &status);
+ allocated += status.allocated;
+ used += status.used;
+ }
+ }
+ }
+ dprintf4("%% %s time = %g, memory allocated = %lu, used = %lu\n",
+ msg, utime[0] - minst->base_time[0] +
+ (utime[1] - minst->base_time[1]) / 1000000000.0,
+ allocated, used);
+}
+#endif
+
+/* Dump the stacks after interpretation */
+void
+gs_debug_dump_stack(int code, ref *perror_object)
+{ zflush(osp); /* force out buffered output */
+ dprintf1("\nUnexpected interpreter error %d.\n", code);
+ if ( perror_object != 0 )
+ { dputs("Error object: ");
+ debug_print_ref(perror_object);
+ dputc('\n');
+ }
+ debug_dump_stack(&o_stack, "Operand stack");
+ debug_dump_stack(&e_stack, "Execution stack");
+ debug_dump_stack(&d_stack, "Dictionary stack");
+}
diff --git a/gs/src/imain.h b/gs/src/imain.h
new file mode 100644
index 000000000..e5f3b470e
--- /dev/null
+++ b/gs/src/imain.h
@@ -0,0 +1,266 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* imain.h */
+/* Interface to imain.c */
+/* Requires <stdio.h>, stdpre.h, gsmemory.h, gstypes.h, iref.h */
+
+#ifndef imain_INCLUDED
+# define imain_INCLUDED
+
+#include "gsexit.h" /* exported by imain.c */
+
+/*
+ * This file defines the intended API between client front ends
+ * (such as imainarg.c, the command-line-driven front end)
+ * and imain.c, which provides top-level control of the interpreter.
+ */
+
+/* ================ Types ================ */
+
+/*
+ * Currently, the interpreter has a lot of static variables, but
+ * eventually it will have none, so that clients will be able to make
+ * multiple instances of it. In anticipation of this, many of the
+ * top-level API calls take an interpreter instance (gs_main_instance *)
+ * as their first argument.
+ */
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s gs_main_instance;
+#endif
+
+/* ================ Exported procedures from imain.c ================ */
+
+/* ---------------- Instance creation ---------------- */
+
+/*
+ * As noted above, multiple instances are not supported yet:
+ */
+/*gs_main_instance *gs_main_alloc_instance(P1(gs_memory_t *));*/
+/*
+ * Instead, we provide only a default instance:
+ */
+gs_main_instance *gs_main_instance_default(P0());
+
+/* ---------------- Initialization ---------------- */
+
+/*
+ * The interpreter requires three initialization steps, called init0,
+ * init1, and init2. These steps must be done in that order, but
+ * init1 may be omitted.
+ */
+
+/*
+ * Since gsio.h (which is included in many other header files)
+ * redefines stdin/out/err, callers need a way to get the "real"
+ * stdio files to pass to init0 if they wish to do so.
+ */
+void gs_get_real_stdio(P1(FILE *stdfiles[3]));
+
+/*
+ * init0 records the files to be used for stdio, and initializes the
+ * graphics library, the file search paths, and other instance data.
+ */
+void gs_main_init0(P5(gs_main_instance *minst, FILE *in, FILE *out, FILE *err,
+ int max_lib_paths));
+
+/*
+ * init1 initializes the memory manager and other internal data
+ * structures such as the name table, the token scanner tables,
+ * dictionaries such as systemdict, and the interpreter stacks.
+ */
+void gs_main_init1(P1(gs_main_instance *minst));
+
+/*
+ * init2 finishes preparing the interpreter for use by running
+ * initialization files with PostScript procedure definitions.
+ */
+void gs_main_init2(P1(gs_main_instance *minst));
+
+/*
+ * The runlibfile operator uses a search path, as described in
+ * use.doc, for looking up file names. Each interpreter instance has
+ * its own search path. The following call adds a directory or set of
+ * directories to the search path; it is equivalent to the -I command
+ * line switch. It may be called any time after init0.
+ */
+void gs_main_add_lib_path(P2(gs_main_instance *minst, const char *path));
+/*
+ * Under certain internal conditions, the search path may temporarily
+ * be in an inconsistent state; gs_main_set_lib_paths takes care of
+ * this. Clients should never need to call this procedure, and
+ * eventually it may be removed.
+ */
+void gs_main_set_lib_paths(P1(gs_main_instance *minst));
+
+/*
+ * Open a PostScript file using the search path. Clients should
+ * never need to call this procedure, since gs_main_run_file opens the
+ * file itself, and eventually the procedure may be removed.
+ */
+int gs_main_lib_open(P3(gs_main_instance *minst, const char *fname,
+ ref *pfile));
+
+/*
+ * Here we summarize the C API calls that correspond to some of the
+ * most common command line switches documented in use.doc, to help
+ * clients who are familiar with the command line and are starting to
+ * use the API.
+ *
+ * -d/D, -s/S (for setting device parameters like OutputFile)
+ * Use the C API for device parameters documented near the
+ * end of gsparam.h.
+ *
+ * -d/D (for setting Boolean parameters like NOPAUSE)
+ * { ref vtrue;
+ * make_true(&vtrue);
+ * dict_put_string(systemdict, "NOPAUSE", &vtrue);
+ * }
+ * -I
+ * Use gs_main_add_lib_path, documented above.
+ *
+ * -A, -A-
+ * Set gs_debug['@'] = 1 or 0 respectively.
+ * -E, -E-
+ * Set gs_debug['#'] = 1 or 0 respectively.
+ * -Z..., -Z-...
+ * Set gs_debug[c] = 1 or 0 respectively for each character
+ * c in the string.
+ */
+
+/* ---------------- Execution ---------------- */
+
+/*
+ * After initializing the interpreter, clients may pass it files or
+ * strings to be interpreted. There are four ways to do this:
+ * - Pass a file name (gs_main_run_file);
+ * - Pass a C string (gs_main_run_string);
+ * - Pass a string defined by pointer and length
+ * (gs_main_run_string_with_length);
+ * - Pass strings piece-by-piece
+ * (gs_main_run_string_begin/continue/end).
+ *
+ * The value returned by the first three of these calls is
+ * 0 if the interpreter ran to completion, e_Quit for a normal quit,
+ * or e_Fatal for a non-zero quit or a fatal error.
+ * e_Fatal stores the exit code in the third argument.
+ * The str argument of gs_main_run_string[_with_length] must be allocated
+ * in non-garbage-collectable space (e.g., by malloc or gs_malloc,
+ * or statically).
+ */
+int gs_main_run_file(P5(gs_main_instance *minst,
+ const char *fname,
+ int user_errors, int *pexit_code,
+ ref *perror_object));
+int gs_main_run_string(P5(gs_main_instance *minst,
+ const char *str,
+ int user_errors, int *pexit_code,
+ ref *perror_object));
+int gs_main_run_string_with_length(P6(gs_main_instance *minst,
+ const char *str, uint length,
+ int user_errors, int *pexit_code,
+ ref *perror_object));
+
+/*
+ * Open the file for gs_main_run_file. This is an internal routine
+ * that is only exported for some special clients.
+ */
+int gs_main_run_file_open(P3(gs_main_instance *minst,
+ const char *file_name, ref *pfref));
+
+/*
+ * The next 3 procedures provide for feeding input to the interpreter
+ * in arbitrary chunks, unlike run_string, which requires that each string
+ * be a properly formed PostScript program fragment. To use them:
+ * Call run_string_begin.
+ * Call run_string_continue as many times as desired,
+ * stopping if it returns anything other than e_NeedInput.
+ * If run_string_continue didn't indicate an error or a quit
+ * (i.e., a return value other than e_NeedInput), call run_string_end
+ * to provide an EOF indication.
+ * Note that run_string_continue takes a pointer and a length, like
+ * run_string_with_length.
+ */
+int gs_main_run_string_begin(P4(gs_main_instance *minst, int user_errors,
+ int *pexit_code, ref *perror_object));
+int gs_main_run_string_continue(P6(gs_main_instance *minst,
+ const char *str, uint length,
+ int user_errors, int *pexit_code,
+ ref *perror_object));
+int gs_main_run_string_end(P4(gs_main_instance *minst, int user_errors,
+ int *pexit_code, ref *perror_object));
+
+/* ---------------- Operand stack access ---------------- */
+
+/*
+ * The following procedures are not used in normal operation;
+ * they exist only to allow clients driving the interpreter through the
+ * gs_main_run_xxx procedures to push parameters quickly and to get results
+ * back. The push procedures return 0, e_stackoverflow, or e_VMerror;
+ * the pop procedures return 0, e_stackunderflow, or e_typecheck.
+ *
+ * Procedures to push values on the operand stack:
+ */
+int gs_push_boolean(P2(gs_main_instance *minst, bool value));
+int gs_push_integer(P2(gs_main_instance *minst, long value));
+int gs_push_real(P2(gs_main_instance *minst, floatp value));
+int gs_push_string(P4(gs_main_instance *minst, byte *chars, uint length,
+ bool read_only));
+/*
+ * Procedures to pop values from the operand stack:
+ */
+int gs_pop_boolean(P2(gs_main_instance *minst, bool *result));
+int gs_pop_integer(P2(gs_main_instance *minst, long *result));
+int gs_pop_real(P2(gs_main_instance *minst, float *result));
+/* gs_pop_string returns 1 if the string is read-only. */
+int gs_pop_string(P2(gs_main_instance *minst, gs_string *result));
+
+/* ---------------- Debugging ---------------- */
+
+/*
+ * Print an error mesage including the error code, error object (if any),
+ * and operand and execution stacks in hex. Clients will probably
+ * never call this.
+ */
+void gs_debug_dump_stack(P2(int code, ref *perror_object));
+
+/* ---------------- Termination ---------------- */
+
+/*
+ * Terminate the interpreter by closing all devices and releasing all
+ * allocated memory. Currently, because of some technical problems
+ * with statically initialized data, it is not possible to reinitialize
+ * the interpreter after terminating it; we plan to fix this as soon as
+ * possible.
+ *
+ * Note that calling gs_exit (defined in gsexit.h) automatically calls
+ * gs_main_finit for the default instance.
+ */
+void gs_main_finit(P3(gs_main_instance *minst, int exit_status, int code));
+
+/* ================ Other exported procedures ================ */
+
+/*
+ * Define an internal interface to the interpreter. Clients do not
+ * normally use this.
+ */
+int gs_interpret(P4(ref *pref, int user_errors, int *pexit_code,
+ ref *perror_object));
+
+#endif /* imain_INCLUDED */
diff --git a/gs/src/imainarg.c b/gs/src/imainarg.c
new file mode 100644
index 000000000..60d955a83
--- /dev/null
+++ b/gs/src/imainarg.c
@@ -0,0 +1,704 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* imainarg.c */
+/* Command line parsing and dispatching */
+/* Define PROGRAM_NAME before we include std.h */
+#define PROGRAM_NAME gs_product
+#include "ctype_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "gsargs.h"
+#include "gscdefs.h"
+#include "gsmdebug.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gsdevice.h"
+#include "stream.h"
+#include "errors.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "ostack.h" /* must precede iscan.h */
+#include "iscan.h"
+#include "imain.h"
+#include "imainarg.h"
+#include "iminst.h"
+#include "iname.h"
+#include "store.h"
+#include "files.h" /* requires stream.h */
+#include "interp.h"
+#include "iutil.h"
+#include "ivmspace.h"
+
+/* Import operator procedures */
+extern int zflush (P1(os_ptr));
+extern int zflushpage (P1(os_ptr));
+
+#ifndef GS_LIB
+# define GS_LIB "GS_LIB"
+#endif
+
+#ifndef GS_OPTIONS
+# define GS_OPTIONS "GS_OPTIONS"
+#endif
+
+#ifndef GS_MAX_LIB_DIRS
+# define GS_MAX_LIB_DIRS 25
+#endif
+
+#ifndef GS_BUG_MAILBOX
+# define GS_BUG_MAILBOX "ghost@aladdin.com"
+#endif
+
+/* Library routines not declared in a standard header */
+extern char *getenv(P1(const char *));
+/* Note: sscanf incorrectly defines its first argument as char * */
+/* rather than const char *. This accounts for the ugly casts below. */
+
+/* Redefine puts to use fprintf, so it will work even without stdio. */
+#undef puts
+private void near
+fpputs(const char *str)
+{ fprintf(stdout, "%s\n", str);
+}
+#define puts(str) fpputs(str)
+
+/* Other imported data */
+extern const char *gs_doc_directory;
+extern const char *gs_lib_default_path;
+extern ref gs_emulator_name_array[];
+extern long gs_malloc_limit;
+
+/* Forward references */
+private int swproc(P3(gs_main_instance *, const char *, arg_list *));
+private void argproc(P2(gs_main_instance *, const char *));
+private int esc_strlen(P1(const char *));
+private void esc_strcat(P2(char *, const char *));
+private void runarg(P6(gs_main_instance *, const char *, const char *, const char *, bool, bool));
+private void run_string(P3(gs_main_instance *, const char *, bool));
+private void run_finish(P3(int, int, ref *));
+
+/* Forward references for help printout */
+private void print_help(P1(gs_main_instance *));
+private void print_revision(P0());
+private void print_version(P0());
+private void print_usage(P0());
+private void print_devices(P0());
+private void print_emulators(P0());
+private void print_paths(P1(gs_main_instance *));
+private void print_help_trailer(P0());
+
+/* ------ Main program ------ */
+
+/* Process the command line with a given instance. */
+private FILE *
+gs_main_arg_fopen(const char *fname, void *vminst)
+{ gs_main_set_lib_paths((gs_main_instance *)vminst);
+ return lib_fopen(fname);
+}
+#define arg_heap_copy(str) arg_copy(str, &gs_memory_default)
+int
+gs_main_init_with_args(gs_main_instance *minst, int argc, char *argv[])
+{ const char *arg;
+ arg_list args;
+ FILE *stdfiles[3];
+
+ gs_get_real_stdio(stdfiles);
+ arg_init(&args, (const char **)argv, argc,
+ gs_main_arg_fopen, (void *)minst);
+ gs_main_init0(minst, stdfiles[0], stdfiles[1], stdfiles[2],
+ GS_MAX_LIB_DIRS);
+ { char *lib = getenv(GS_LIB);
+ if ( lib != 0 )
+ { int len = strlen(lib);
+ char *path = gs_malloc(len + 1, 1, "GS_LIB");
+ strcpy(path, lib);
+ minst->lib_path.env = path;
+ }
+ }
+ minst->lib_path.final = gs_lib_default_path;
+ gs_main_set_lib_paths(minst);
+ /* Prescan the command line for --help and --version. */
+ { int i;
+ bool helping = false;
+ for ( i = 1; i < argc; ++i )
+ if ( !strcmp(argv[i], "--" ) )
+ { /* A PostScript program will be interpreting all the */
+ /* remaining switches, so stop scanning. */
+ helping = false;
+ break;
+ }
+ else if ( !strcmp(argv[i], "--help") )
+ { print_help(minst);
+ helping = true;
+ }
+ else if ( !strcmp(argv[i], "--version") )
+ { print_version();
+ puts(""); /* \n */
+ helping = true;
+ }
+ if ( helping )
+ gs_exit(gs_exit_INFO);
+ }
+ /* Execute files named in the command line, */
+ /* processing options along the way. */
+ /* Wait until the first file name (or the end */
+ /* of the line) to finish initialization. */
+ minst->run_start = true;
+ { const char *opts = getenv(GS_OPTIONS);
+ if ( opts != 0 )
+ arg_push_string(&args, opts);
+ }
+ while ( (arg = arg_next(&args)) != 0 )
+ { switch ( *arg )
+ {
+ case '-':
+ if ( swproc(minst, arg, &args) < 0 )
+ fprintf(stdout,
+ "Unknown switch %s - ignoring\n", arg);
+ break;
+ default:
+ argproc(minst, arg);
+ }
+ }
+
+ gs_main_init2(minst);
+
+ return 0;
+}
+
+/* Run the 'start' procedure (after processing the command line). */
+/* Note that this procedure exits rather than returning. */
+void
+gs_main_run_start(gs_main_instance *minst)
+{ run_string(minst, "systemdict /start get exec", true);
+}
+
+/* Process switches */
+private int
+swproc(gs_main_instance *minst, const char *arg, arg_list *pal)
+{ char sw = arg[1];
+ ref vtrue;
+
+ make_true(&vtrue);
+ arg += 2; /* skip - and letter */
+ switch ( sw )
+ {
+ default:
+ return -1;
+ case 0: /* read stdin as a file */
+ minst->run_start = false; /* don't run 'start' */
+ /* Set NOPAUSE so showpage won't try to read from stdin. */
+ swproc(minst, "-dNOPAUSE", pal);
+ gs_main_init2(minst); /* Finish initialization */
+ /* We delete this only to make Ghostview work properly. */
+ /**************** This is WRONG. ****************/
+ /*gs_stdin_is_interactive = false;*/
+ run_string(minst, ".runstdin", true);
+ break;
+ case '-': /* run with command line args */
+ case '+':
+ pal->expand_ats = false;
+ case '@': /* ditto with @-expansion */
+ { const char *psarg = arg_next(pal);
+ if ( psarg == 0 )
+ { fprintf(stdout, "Usage: gs ... -%c file.ps arg1 ... argn\n", sw);
+ arg_finit(pal);
+ gs_exit(1);
+ }
+ psarg = arg_heap_copy(psarg);
+ gs_main_init2(minst);
+ run_string(minst, "userdict/ARGUMENTS[", false);
+ while ( (arg = arg_next(pal)) != 0 )
+ runarg(minst, "", arg_heap_copy(arg), "", true, false);
+ runarg(minst, "]put", psarg, ".runfile", true, true);
+ gs_exit(0);
+ }
+ case 'A': /* trace allocator */
+ switch ( *arg )
+ {
+ case 0: gs_alloc_debug = 1; break;
+ case '-': gs_alloc_debug = 0; break;
+ default: puts("-A may only be followed by -"); gs_exit(1);
+ }
+ break;
+ case 'c': /* code follows */
+ { bool ats = pal->expand_ats;
+ gs_main_init2(minst);
+ pal->expand_ats = false;
+ while ( (arg = arg_next(pal)) != 0 )
+ { char *sarg;
+ if ( arg[0] == '@' ||
+ (arg[0] == '-' && !isdigit(arg[1]))
+ )
+ break;
+ sarg = arg_heap_copy(arg);
+ runarg(minst, "", sarg, ".runstring", false, false);
+ }
+ if ( arg != 0 )
+ arg_push_string(pal, arg_heap_copy(arg));
+ pal->expand_ats = ats;
+ break;
+ }
+ case 'E': /* log errors */
+ switch ( *arg )
+ {
+ case 0: gs_log_errors = 1; break;
+ case '-': gs_log_errors = 0; break;
+ default: puts("-E may only be followed by -"); gs_exit(1);
+ }
+ break;
+ case 'f': /* run file of arbitrary name */
+ if ( *arg != 0 )
+ argproc(minst, arg);
+ break;
+ case 'g': /* define device geometry */
+ { long width, height;
+ ref value;
+ gs_main_init1(minst);
+ if ( sscanf((const char *)arg, "%ldx%ld", &width, &height) != 2 )
+ { puts("-g must be followed by <width>x<height>");
+ gs_exit(1);
+ }
+ make_int(&value, width);
+ initial_enter_name("DEVICEWIDTH", &value);
+ make_int(&value, height);
+ initial_enter_name("DEVICEHEIGHT", &value);
+ initial_enter_name("FIXEDMEDIA", &vtrue);
+ break;
+ }
+ case 'h': /* print help */
+ case '?': /* ditto */
+ print_help(minst);
+ gs_exit(gs_exit_INFO);
+ case 'I': /* specify search path */
+ gs_main_add_lib_path(minst, arg_heap_copy(arg));
+ break;
+ case 'K': /* set malloc limit */
+ { long msize = 0;
+ sscanf((const char *)arg, "%ld", &msize);
+ if ( msize <= 0 || msize > max_long >> 10 )
+ { fprintf(stdout, "-K<numK> must have 1 <= numK <= %ld\n",
+ max_long >> 10);
+ gs_exit(1);
+ }
+ gs_malloc_limit = msize << 10;
+ }
+ break;
+ case 'M': /* set memory allocation increment */
+ { unsigned msize = 0;
+ sscanf((const char *)arg, "%u", &msize);
+#if arch_ints_are_short
+ if ( msize <= 0 || msize >= 64 )
+ { puts("-M must be between 1 and 63");
+ gs_exit(1);
+ }
+#endif
+ minst->memory_chunk_size = msize << 10;
+ }
+ break;
+ case 'N': /* set size of name table */
+ { unsigned nsize = 0;
+ sscanf((const char *)arg, "%d", &nsize);
+#if arch_ints_are_short
+ if ( nsize < 2 || nsize > 64 )
+ { puts("-N must be between 2 and 64");
+ gs_exit(1);
+ }
+#endif
+ minst->name_table_size = (ulong)nsize << 10;
+ }
+ break;
+ case 'P': /* choose whether search '.' first */
+ if ( !strcmp(arg, "") )
+ minst->search_here_first = true;
+ else if ( !strcmp(arg, "-") )
+ minst->search_here_first = false;
+ else
+ { puts("Only -P or -P- is allowed.");
+ gs_exit(1);
+ }
+ break;
+ case 'q': /* quiet startup */
+ gs_main_init1(minst);
+ initial_enter_name("QUIET", &vtrue);
+ break;
+ case 'r': /* define device resolution */
+ { float xres, yres;
+ ref value;
+ gs_main_init1(minst);
+ switch ( sscanf((const char *)arg, "%fx%f", &xres, &yres) )
+ {
+ default:
+ puts("-r must be followed by <res> or <xres>x<yres>");
+ gs_exit(1);
+ case 1: /* -r<res> */
+ yres = xres;
+ case 2: /* -r<xres>x<yres> */
+ make_real(&value, xres);
+ initial_enter_name("DEVICEXRESOLUTION", &value);
+ make_real(&value, yres);
+ initial_enter_name("DEVICEYRESOLUTION", &value);
+ initial_enter_name("FIXEDRESOLUTION", &vtrue);
+ }
+ break;
+ }
+ case 'D': /* define name */
+ case 'd':
+ case 'S': /* define name as string */
+ case 's':
+ { char *adef = arg_heap_copy(arg);
+ char *eqp = strchr(adef, '=');
+ bool isd = (sw == 'D' || sw == 'd');
+ ref value;
+
+ if ( eqp == NULL )
+ eqp = strchr(adef, '#');
+ /* Initialize the object memory, scanner, and */
+ /* name table now if needed. */
+ gs_main_init1(minst);
+ if ( eqp == adef )
+ { puts("Usage: -dname, -dname=token, -sname=string");
+ gs_exit(1);
+ }
+ if ( eqp == NULL )
+ { if ( isd )
+ make_true(&value);
+ else
+ make_empty_string(&value, a_readonly);
+ }
+ else
+ { int code;
+ uint space = icurrent_space;
+
+ *eqp++ = 0;
+ ialloc_set_space(idmemory, avm_system);
+ if ( isd )
+ { stream astream;
+ scanner_state state;
+
+ sread_string(&astream,
+ (const byte *)eqp, strlen(eqp));
+ scanner_state_init(&state, false);
+ code = scan_token(&astream, &value, &state);
+ if ( code )
+ { puts("-dname= must be followed by a valid token");
+ gs_exit(1);
+ }
+ if ( r_has_type_attrs(&value, t_name,
+ a_executable) )
+ { ref nsref;
+ name_string_ref(&value, &nsref);
+#define string_is(nsref, str, len)\
+ (r_size(&(nsref)) == (len) &&\
+ !strncmp((const char *)(nsref).value.const_bytes, str, (len)))
+ if ( string_is(nsref, "null", 4) )
+ make_null(&value);
+ else if ( string_is(nsref, "true", 4) )
+ make_true(&value);
+ else if ( string_is(nsref, "false", 5) )
+ make_false(&value);
+ else
+ { puts("-dvar=name requires name=null, true, or false");
+ gs_exit(1);
+ }
+#undef name_is_string
+ }
+ }
+ else
+ { int len = strlen(eqp);
+ char *str = gs_malloc((uint)len, 1, "-s");
+
+ if ( str == 0 )
+ { lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ memcpy(str, eqp, len);
+ make_const_string(&value,
+ a_readonly | avm_foreign,
+ len, (const byte *)str);
+ }
+ ialloc_set_space(idmemory, space);
+ }
+ /* Enter the name in systemdict. */
+ initial_enter_name(adef, &value);
+ break;
+ }
+ case 'u': /* undefine name */
+ if ( !*arg )
+ { puts("-u requires a name to undefine.");
+ gs_exit(1);
+ }
+ gs_main_init1(minst);
+ initial_remove_name(arg);
+ break;
+ case 'v': /* print revision */
+ print_revision();
+ gs_exit(0);
+/*#ifdef DEBUG*/
+ /*
+ * Here we provide a place for inserting debugging code that can be
+ * run in place of the normal interpreter code.
+ */
+ case 'X':
+ gs_main_init2(minst);
+ { int xec; /* exit_code */
+ ref xeo; /* error_object */
+#define start_x()\
+ gs_main_run_string_begin(minst, 1, &xec, &xeo)
+#define run_x(str)\
+ gs_main_run_string_continue(minst, str, strlen(str), 1, &xec, &xeo)
+#define stop_x()\
+ gs_main_run_string_end(minst, 1, &xec, &xeo)
+ start_x();
+ run_x("\216\003abc");
+ run_x("== flush\n");
+ stop_x();
+ }
+ gs_exit(0);
+/*#endif*/
+ case 'Z':
+ { byte value = (*arg == '-' ? (++arg, 0) : 0xff);
+ while ( *arg )
+ gs_debug[*arg++ & 127] = value;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Define versions of strlen and strcat that encode strings in hex. */
+/* This is so we can enter escaped characters regardless of whether */
+/* the Level 1 convention of ignoring \s in strings-within-strings */
+/* is being observed (sigh). */
+private int
+esc_strlen(const char *str)
+{ return strlen(str) * 2 + 2;
+}
+private void
+esc_strcat(char *dest, const char *src)
+{ char *d = dest + strlen(dest);
+ const char *p;
+ static const char *hex = "0123456789abcdef";
+ *d++ = '<';
+ for ( p = src; *p; p++ )
+ { byte c = (byte)*p;
+ *d++ = hex[c >> 4];
+ *d++ = hex[c & 0xf];
+ }
+ *d++ = '>';
+ *d = 0;
+}
+
+/* Process file names */
+private void
+argproc(gs_main_instance *minst, const char *arg)
+{ runarg(minst, "", arg, ".runfile", true, true);
+}
+private void
+runarg(gs_main_instance *minst, const char *pre, const char *arg,
+ const char *post, bool init, bool flush)
+{ int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
+ char *line;
+ if ( init )
+ gs_main_init2(minst); /* Finish initialization */
+ line = gs_malloc(len, 1, "argproc");
+ if ( line == 0 )
+ { lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ strcpy(line, pre);
+ esc_strcat(line, arg);
+ strcat(line, post);
+ run_string(minst, line, flush);
+}
+private void
+run_string(gs_main_instance *minst, const char *str, bool flush)
+{ int exit_code;
+ ref error_object;
+ int code = gs_main_run_string(minst, str, minst->user_errors,
+ &exit_code, &error_object);
+ if ( flush || code != 0 )
+ { zflush(osp); /* flush stdout */
+ zflushpage(osp); /* force display update */
+ }
+ run_finish(code, exit_code, &error_object);
+}
+private void
+run_finish(int code, int exit_code, ref *perror_object)
+{ switch ( code )
+ {
+ case 0:
+ break;
+ case e_Quit:
+ gs_exit(0);
+ case e_Fatal:
+ eprintf1("Unrecoverable error, exit code %d\n", exit_code);
+ gs_exit(exit_code);
+ default:
+ gs_debug_dump_stack(code, perror_object);
+ gs_exit_with_code(255, code);
+ }
+}
+
+/* ---------------- Print information ---------------- */
+
+/*
+ * Help strings. We have to break them up into parts, because
+ * the Watcom compiler has a limit of 510 characters for a single token.
+ * For PC displays, we want to limit the strings to 24 lines.
+ */
+private const char far_data help_usage1[] = "\
+Usage: gs [switches] [file1.ps file2.ps ...]\n\
+Most frequently used switches: (you can use # in place of =)\n\
+ -dNOPAUSE no pause after page | -q `quiet', fewer messages\n\
+ -g<width>x<height> page size in pixels | -r<res> pixels/inch resolution\n";
+private const char far_data help_usage2[] = "\
+ -sDEVICE=<devname> select device | -dBATCH exit after last file\n\
+ -sOutputFile=<file> select output file: - for stdout, |command for pipe,\n\
+ embed %d or %ld for page #\n";
+private const char far_data help_trailer[] = "\
+For more information, see %s%suse.txt.\n\
+Report bugs to %s; use the form in bug-form.txt.\n";
+private const char far_data help_devices[] = "Available devices:";
+private const char far_data help_emulators[] = "Input formats:";
+private const char far_data help_paths[] = "Search path:";
+
+/* Print the standard help message. */
+private void
+print_help(gs_main_instance *minst)
+{ print_revision();
+ print_usage();
+ print_emulators();
+ print_devices();
+ print_paths(minst);
+ print_help_trailer();
+}
+
+/* Print the revision, revision date, and copyright. */
+private void
+print_revision(void)
+{ fprintf(stdout, "%s ", gs_product);
+ print_version();
+ fprintf(stdout, " (%d-%d-%d)\n%s\n",
+ (int)(gs_revisiondate / 10000),
+ (int)(gs_revisiondate / 100 % 100),
+ (int)(gs_revisiondate % 100),
+ gs_copyright);
+}
+
+/* Print the version number. */
+private void
+print_version(void)
+{ fprintf(stdout, "%d.%02d",
+ (int)(gs_revision / 100),
+ (int)(gs_revision % 100));
+}
+
+/* Print usage information. */
+private void
+print_usage(void)
+{ fprintf(stdout, "%s", help_usage1);
+ fprintf(stdout, "%s", help_usage2);
+}
+
+/* Print the list of available devices. */
+private void
+print_devices(void)
+{ fprintf(stdout, "%s", help_devices);
+ { int i;
+ int pos = 100;
+ const gx_device *pdev;
+
+ for ( i = 0; (pdev = gs_getdevice(i)) != 0; i++ )
+ { const char *dname = gs_devicename(pdev);
+ int len = strlen(dname);
+
+ if ( pos + 1 + len > 76 )
+ fprintf(stdout, "\n "), pos = 2;
+ fprintf(stdout, " %s", dname);
+ pos += 1 + len;
+ }
+ }
+ fprintf(stdout, "\n");
+}
+
+/* Print the list of language emulators. */
+private void
+print_emulators(void)
+{ fprintf(stdout, "%s", help_emulators);
+ { const ref *pes;
+ for ( pes = gs_emulator_name_array;
+ pes->value.const_bytes != 0; pes++
+ )
+ fprintf(stdout, " %s", pes->value.const_bytes);
+ }
+ fprintf(stdout, "\n");
+}
+
+/* Print the search paths. */
+private void
+print_paths(gs_main_instance *minst)
+{ fprintf(stdout, "%s", help_paths);
+ gs_main_set_lib_paths(minst);
+ { uint count = r_size(&minst->lib_path.list);
+ uint i;
+ int pos = 100;
+ char fsepr[3];
+
+ fsepr[0] = ' ', fsepr[1] = gp_file_name_list_separator,
+ fsepr[2] = 0;
+ for ( i = 0; i < count; ++i )
+ { const ref *prdir =
+ minst->lib_path.list.value.refs + i;
+ uint len = r_size(prdir);
+ const char *sepr = (i == count - 1 ? "" : fsepr);
+
+ if ( 1 + pos + strlen(sepr) + len > 76 )
+ fprintf(stdout, "\n "), pos = 2;
+ fprintf(stdout, " ");
+ /*
+ * This is really ugly, but it's necessary.
+ * We wish we could just do:
+ fwrite(prdir->value.bytes, 1, len, stdout);
+ */
+ { const char *p = (const char *)prdir->value.bytes;
+ uint j;
+ for ( j = len; j; j-- )
+ fprintf(stdout, "%c", *p++);
+ }
+ fprintf(stdout, sepr);
+ pos += 1 + len + strlen(sepr);
+ }
+ }
+ fprintf(stdout, "\n");
+}
+
+/* Print the help trailer. */
+private void
+print_help_trailer(void)
+{ fprintf(stdout, help_trailer, gs_doc_directory,
+ gp_file_name_concat_string(gs_doc_directory,
+ strlen(gs_doc_directory),
+ "use.txt", 7),
+ GS_BUG_MAILBOX);
+}
diff --git a/gs/src/imainarg.h b/gs/src/imainarg.h
new file mode 100644
index 000000000..5f4870fa6
--- /dev/null
+++ b/gs/src/imainarg.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* imainarg.h */
+/* argv/argc interface to imainarg.c */
+
+#ifndef imainarg_INCLUDED
+# define imainarg_INCLUDED
+
+/* Define an opaque type for an interpreter instance. See imain.h. */
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s gs_main_instance;
+#endif
+
+/*
+ * As a shortcut for very high-level clients, we define a single call
+ * that does the equivalent of command line invocation, passing argc
+ * and argv. This call includes calling init0 through init2.
+ * argv should really be const char *[], but ANSI C requires writable
+ * strings (which, however, it forbids the callee to modify!).
+ */
+int gs_main_init_with_args(P3(gs_main_instance *minst, int argc,
+ char *argv[]));
+
+/*
+ * Run the 'start' procedure (after processing the command line).
+ * Note that this procedure exits rather than returning.
+ */
+void gs_main_run_start(P1(gs_main_instance *minst));
+
+#endif /* imainarg_INCLUDED */
diff --git a/gs/src/imemory.h b/gs/src/imemory.h
new file mode 100644
index 000000000..c3ee19053
--- /dev/null
+++ b/gs/src/imemory.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* imemory.h */
+/* Ghostscript memory allocator extensions for interpreter level */
+
+#ifndef imemory_INCLUDED
+# define imemory_INCLUDED
+
+#include "ivmspace.h"
+
+/*
+ * The interpreter level of Ghostscript defines a "subclass" extension
+ * of the allocator interface in gsmemory.h, by adding the ability to
+ * allocate and free arrays of refs, and by adding the distinction
+ * between local, global, and system allocation.
+ */
+
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+#include "gsalloc.h"
+
+ /* Allocate a ref array. */
+
+int gs_alloc_ref_array(P5(gs_ref_memory_t *mem, ref *paref,
+ uint attrs, uint num_refs, client_name_t cname));
+
+ /* Resize a ref array. */
+ /* Currently this is only implemented for shrinking, */
+ /* not growing. */
+
+int gs_resize_ref_array(P4(gs_ref_memory_t *mem, ref *paref,
+ uint new_num_refs, client_name_t cname));
+
+ /* Free a ref array. */
+
+void gs_free_ref_array(P3(gs_ref_memory_t *mem, ref *paref,
+ client_name_t cname));
+
+ /* Allocate a string ref. */
+
+int gs_alloc_string_ref(P5(gs_ref_memory_t *mem, ref *psref,
+ uint attrs, uint nbytes, client_name_t cname));
+
+/*
+ * Define the pointer type for refs. Note that if a structure contains refs,
+ * both its clear_marks and its reloc_ptrs procedure must unmark them,
+ * since the GC will never see the refs during the unmarking sweep.
+ */
+extern const gs_ptr_procs_t ptr_ref_procs;
+#define ptr_ref_type (&ptr_ref_procs)
+
+/* Register a ref root. */
+/* Note that ref roots are a little peculiar: they assume that */
+/* the ref * that they point to points to a *statically* allocated ref. */
+#define gs_register_ref_root(mem, root, rp, cname)\
+ gs_register_root(mem, root, ptr_ref_type, rp, cname)
+
+/*
+ * The interpreter allocator can allocate in either local or global VM,
+ * and can switch between the two dynamically. In Level 1 configurations,
+ * global VM is the same as local; however, this is *not* currently true in
+ * a Level 2 system running in Level 1 mode. In addition, there is a third
+ * VM space, system VM, that exists in both modes and is used for objects
+ * that must not be affected by even the outermost save/restore (stack
+ * segments and names).
+ */
+typedef struct gs_dual_memory_s gs_dual_memory_t;
+struct gs_dual_memory_s {
+ gs_ref_memory_t *current; /* = ...global or ...local */
+ vm_spaces spaces; /* system, global, local */
+ uint current_space; /* = current->space */
+ /* Save/restore machinery */
+ int save_level;
+ /* Garbage collection hook */
+ int (*reclaim)(P2(gs_dual_memory_t *, int));
+ /* Masks for store checking, see isave.h. */
+ uint test_mask;
+ uint new_mask;
+};
+
+#endif /* imemory_INCLUDED */
diff --git a/gs/src/iminst.h b/gs/src/iminst.h
new file mode 100644
index 000000000..e420c4cd9
--- /dev/null
+++ b/gs/src/iminst.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iminst.h */
+/* Definition of interpreter instance */
+#include "imain.h"
+
+/*
+ * Define the structure of a search path. Currently there is only one,
+ * but there might be more someday.
+ *
+ * container - an array large enough to hold the specified maximum
+ * number of directories. Both the array and all the strings in it are
+ * in the 'foreign' VM space.
+ * list - the initial interval of container that defines the actual
+ * search list.
+ * env - the contents of an environment variable, implicitly added
+ * at the end of the list; may be 0.
+ * final - the final set of directories specified in the makefile;
+ * may be 0.
+ * count - the number of elements in the list, excluding a possible
+ * initial '.', env, and final.
+ */
+typedef struct gs_file_path_s {
+ ref container;
+ ref list;
+ const char *env;
+ const char *final;
+ uint count;
+} gs_file_path;
+
+/*
+ * Here is where we actually define the structure of interpreter instances.
+ * Clients should not reference any of the members.
+ */
+struct gs_main_instance_s {
+ /* The following are set during initialization. */
+ FILE *fstdin;
+ FILE *fstdout;
+ FILE *fstderr;
+ uint memory_chunk_size; /* 'wholesale' allocation unit */
+ ulong name_table_size;
+ int init_done; /* highest init done so far */
+ int user_errors; /* define what to do with errors */
+ bool search_here_first; /* if true, make '.' first lib dir */
+ bool run_start; /* if true, run 'start' after */
+ /* processing command line */
+ gs_file_path lib_path; /* library search list (GS_LIB) */
+ long base_time[2]; /* starting usertime */
+};
+/*
+ * Note that any file that uses the following definition of default values
+ * must include gconfig.h, because of SEARCH_HERE_FIRST.
+ */
+#define gs_main_instance_default_init_values\
+ 0, 0, 0, 20000, 0, -1, 0, SEARCH_HERE_FIRST, 1
+extern const gs_main_instance gs_main_instance_init_values;
diff --git a/gs/src/iname.c b/gs/src/iname.c
new file mode 100644
index 000000000..577ad7990
--- /dev/null
+++ b/gs/src/iname.c
@@ -0,0 +1,602 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iname.c */
+/* Name lookup for Ghostscript interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gsstruct.h"
+#include "gxobj.h" /* for o_set_unmarked */
+#include "errors.h"
+#include "inamedef.h"
+#include "imemory.h" /* for isave.h */
+#include "isave.h"
+#include "store.h"
+
+/* Public values */
+const uint name_max_string = max_name_string;
+
+/* In the code below, we use the hashing method described in */
+/* "Fast Hashing of Variable-Length Text Strings" by Peter K. Pearson, */
+/* pp. 677-680, CACM 33(6), June 1990. */
+
+/* Define a pseudo-random permutation of the integers 0..255. */
+/* Pearson's article claims this permutation gave good results. */
+private const far_data byte hash_permutation[256] = {
+ 1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163,
+ 14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200,
+110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222,
+ 25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235,
+ 97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248,
+174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243,
+132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219,
+119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10,
+138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152,
+170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131,
+125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123,
+118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229,
+ 27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203,
+233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76,
+140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120,
+ 51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209
+};
+
+/*
+ * Definitions and structure for the name table.
+ * Entry 0 is left unused.
+ * The entry with count = 1 is the entry for the 0-length name.
+ * The next nt_1char_size entries (in count order) are 1-character names.
+ */
+#define nt_1char_size 128
+#define nt_1char_first 2
+private const far_data byte nt_1char_names[128] = {
+#define q8(n) n,n+1,n+2,n+3,n+4,n+5,n+6,n+7
+#define q32(n) q8(n),q8(n+8),q8(n+16),q8(n+24)
+ q32(0), q32(32), q32(64), q32(96)
+#undef q8
+};
+
+/* Structure descriptors */
+gs_private_st_composite(st_name_sub_table, name_sub_table, "name_sub_table",
+ name_sub_enum_ptrs, name_sub_reloc_ptrs);
+gs_private_st_composite(st_name_table, name_table, "name_table",
+ name_table_enum_ptrs, name_table_reloc_ptrs);
+
+/* The one and only name table (for now). */
+private name_table *the_nt;
+private gs_gc_root_t the_nt_root;
+
+/* Forward references */
+private int name_alloc_sub(P1(name_table *));
+private void name_scan_sub(P3(name_table *, uint, bool));
+
+/* Debugging printout */
+#ifdef DEBUG
+private void
+name_print(const char *msg, name *pname, uint nidx, const int *pflag)
+{ const byte *ptr = pname->string_bytes;
+ dprintf1("[n]%s", msg);
+ if ( pflag )
+ dprintf1("(%d)", *pflag);
+ dprintf2(" (0x%lx#%u)", (ulong)pname, nidx);
+ debug_print_string(ptr, pname->string_size);
+ dprintf2("(0x%lx,%u)\n", (ulong)ptr, pname->string_size);
+}
+# define if_debug_name(msg, pname, nidx, pflag)\
+ if ( gs_debug_c('n') ) name_print(msg, pname, nidx, pflag)
+#else
+# define if_debug_name(msg, pname, nidx, pflag) DO_NOTHING
+#endif
+
+/* Initialize the name table */
+name_table *
+name_init(ulong count, gs_memory_t *mem)
+{ register int i;
+ name_table *nt;
+
+ if ( count == 0 )
+ count = max_name_count + 1L;
+ else if ( count - 1 > max_name_count )
+ return 0;
+ nt =
+ gs_alloc_struct(mem, name_table, &st_name_table, "name_init(nt)");
+ the_nt = nt;
+ memset(nt, 0, sizeof(name_table));
+ nt->max_sub_count =
+ ((count - 1) | nt_sub_index_mask) >> nt_log2_sub_size;
+ nt->memory = mem;
+ /* Initialize the one-character names. */
+ /* Start by creating the necessary sub-tables. */
+ for ( i = 0; i < nt_1char_first + nt_1char_size; i += nt_sub_size )
+ name_alloc_sub(nt);
+ for ( i = -1; i < nt_1char_size; i++ )
+ { uint ncnt = nt_1char_first + i;
+ uint nidx = name_count_to_index(ncnt);
+ register name *pname = name_index_ptr_inline(nt, nidx);
+ if ( i < 0 )
+ pname->string_bytes = nt_1char_names,
+ pname->string_size = 0;
+ else
+ pname->string_bytes = nt_1char_names + i,
+ pname->string_size = 1;
+ pname->foreign_string = 1;
+ pname->mark = 1;
+ pname->pvalue = pv_no_defn;
+ }
+ /* Reconstruct the free list. */
+ nt->free = 0;
+ name_trace_finish(NULL);
+ /* Register the name table root. */
+ gs_register_struct_root(mem, &the_nt_root, (void **)&the_nt,
+ "name table");
+ return nt;
+}
+
+/* Return the one and only table. */
+const name_table *
+the_name_table(void)
+{ return the_nt;
+}
+
+/* Get the allocator for the name table. */
+gs_memory_t *
+name_memory(void)
+{ return the_nt->memory;
+}
+
+/* Look up or enter a name in the table. */
+/* Return 0 or an error code. */
+/* The return may overlap the characters of the string! */
+/* See iname.h for the meaning of enterflag. */
+int
+name_ref(const byte *ptr, uint size, ref *pref, int enterflag)
+{ name_table *nt = the_nt;
+ register name *pname;
+ uint nidx;
+ uint *phash;
+
+ /* Compute a hash for the string. */
+ { uint hash;
+ const byte *p = ptr;
+ uint n = size;
+ /* Make a special check for 1-character names. */
+ switch ( size )
+ {
+ case 0:
+ nidx = name_count_to_index(1);
+ pname = name_index_ptr_inline(nt, nidx);
+ goto mkn;
+ case 1:
+ if ( *p < nt_1char_size )
+ { hash = *p + nt_1char_first;
+ nidx = name_count_to_index(hash);
+ pname = name_index_ptr_inline(nt, nidx);
+ goto mkn;
+ }
+ /* falls through */
+ default:
+ hash = hash_permutation[*p++];
+ while ( --n > 0 )
+ hash = (hash << 8) |
+ hash_permutation[(byte)hash ^ *p++];
+ }
+ phash = nt->hash + (hash & (nt_hash_size - 1));
+ }
+
+ for ( nidx = *phash; nidx != 0;
+ nidx = name_next_index(nidx, pname)
+ )
+ { pname = name_index_ptr_inline(nt, nidx);
+ if ( pname->string_size == size &&
+ !memcmp_inline(ptr, pname->string_bytes, size)
+ )
+ goto mkn;
+ }
+ /* Name was not in the table. Make a new entry. */
+ if ( enterflag < 0 )
+ return_error(e_undefined);
+ if ( size > max_name_string )
+ return_error(e_limitcheck);
+ nidx = nt->free;
+ if ( nidx == 0 )
+ { int code = name_alloc_sub(nt);
+ if ( code < 0 ) return code;
+ nidx = nt->free;
+ }
+ pname = name_index_ptr_inline(nt, nidx);
+ if ( enterflag == 1 )
+ { byte *cptr = (byte *)gs_alloc_string(nt->memory, size,
+ "name_ref(string)");
+ if ( cptr == 0 )
+ return_error(e_VMerror);
+ memcpy(cptr, ptr, size);
+ pname->string_bytes = cptr;
+ pname->foreign_string = 0;
+ }
+ else
+ { pname->string_bytes = ptr;
+ pname->foreign_string = (enterflag == 0 ? 1 : 0);
+ }
+ pname->string_size = size;
+ pname->pvalue = pv_no_defn;
+ nt->free = name_next_index(nidx, pname);
+ set_name_next_index(nidx, pname, *phash);
+ *phash = nidx;
+ if_debug_name("new name", pname, nidx, &enterflag);
+mkn: make_name(pref, nidx, pname);
+ return 0;
+}
+
+/* Get the string for a name. */
+void
+name_string_ref(const ref *pnref /* t_name */,
+ ref *psref /* result, t_string */)
+{ name *pname = pnref->value.pname;
+ const name_table *nt = the_nt;
+ make_const_string(psref,
+ (pname->foreign_string ? avm_foreign :
+ imemory_space((gs_ref_memory_t *)nt->memory))
+ | a_readonly,
+ pname->string_size,
+ (const byte *)pname->string_bytes);
+}
+
+/* Convert a t_string object to a name. */
+/* Copy the executable attribute. */
+int
+name_from_string(const ref *psref, ref *pnref)
+{ int exec = r_has_attr(psref, a_executable);
+ int code = name_ref(psref->value.bytes, r_size(psref), pnref, 1);
+ if ( code < 0 )
+ return code;
+ if ( exec )
+ r_set_attrs(pnref, a_executable);
+ return code;
+}
+
+/* Enter a (permanently allocated) C string as a name. */
+int
+name_enter_string(const char *str, ref *pref)
+{ return name_ref((const byte *)str, strlen(str), pref, 0);
+}
+
+/* Invalidate the value cache for a name. */
+void
+name_invalidate_value_cache(const ref *pnref)
+{ pnref->value.pname->pvalue = pv_other;
+}
+
+/* Convert between names and indices. */
+#undef name_index
+uint
+name_index(const ref *pnref)
+{ return name_index_inline(pnref);
+}
+void
+name_index_ref(uint index, ref *pnref)
+{ name_index_ref_inline(the_nt, index, pnref);
+}
+name *
+name_index_ptr(uint index)
+{ return name_index_ptr_inline(the_nt, index);
+}
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+uint
+name_next_valid_index(uint nidx)
+{ name_table *nt = the_nt;
+ name_sub_table *sub = nt->sub_tables[nidx >> nt_log2_sub_size];
+ name *pname;
+ do
+ { ++nidx;
+ if ( (nidx & nt_sub_index_mask) == 0 )
+ for ( ; ; nidx += nt_sub_size )
+ { if ( (nidx >> nt_log2_sub_size) >= nt->sub_count )
+ return 0;
+ sub = nt->sub_tables[nidx >> nt_log2_sub_size];
+ if ( sub != 0 )
+ break;
+ }
+ pname = &sub->names[nidx & nt_sub_index_mask];
+ }
+ while ( pname->string_bytes == 0 );
+ return nidx;
+}
+
+/* ------ Garbage collection ------ */
+
+/* Unmark all names, except for 1-character permanent names, */
+/* before a garbage collection. */
+void
+name_unmark_all(void)
+{ name_table *nt = the_nt;
+ uint si;
+ name_sub_table *sub;
+ for ( si = 0; si < nt->sub_count; ++si )
+ if ( (sub = nt->sub_tables[si]) != 0 )
+ { uint i;
+ for ( i = 0; i < nt_sub_size; ++i )
+ sub->names[i].mark = 0;
+ }
+ { uint ncnt;
+ for ( ncnt = 1; ncnt <= nt_1char_size; ++ncnt )
+ name_index_ptr(name_count_to_index(ncnt))->mark = 1;
+ }
+}
+
+/* Mark a name. Return true if new mark. We export this so we can mark */
+/* character names in the character cache. */
+bool
+name_mark_index(uint nidx)
+{ name *pname = name_index_ptr(nidx);
+ if ( pname->mark )
+ return false;
+ pname->mark = 1;
+ return true;
+}
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+void/*obj_header_t*/ *
+name_ref_sub_table(const ref *pnref)
+{ /* When this procedure is called, the pointers from the name table */
+ /* to the sub-tables may or may not have been relocated already, */
+ /* so we can't use them. Instead, we have to work backwards from */
+ /* the name pointer itself. */
+ return pnref->value.pname - (name_index_inline(pnref) & nt_sub_index_mask);
+}
+void/*obj_header_t*/ *
+name_index_ptr_sub_table(uint index, name *pname)
+{ return pname - (index & nt_sub_index_mask);
+}
+
+/*
+ * Clean up the name table after the trace/mark phase of a garbage
+ * collection, by removing names that aren't marked. gcst == NULL indicates
+ * we're doing this for initialization or restore rather than for a GC.
+ */
+void
+name_trace_finish(gc_state_t *gcst)
+{ name_table *nt = the_nt;
+ uint *phash = &nt->hash[0];
+ uint i;
+
+ for ( i = 0; i < nt_hash_size; phash++, i++ )
+ { uint prev = 0;
+ name *pnprev;
+ uint nidx = *phash;
+ while ( nidx != 0 )
+ { name *pname = name_index_ptr_inline(nt, nidx);
+ uint next = name_next_index(nidx, pname);
+ if ( pname->mark )
+ { prev = nidx;
+ pnprev = pname;
+ }
+ else
+ { if_debug_name("GC remove name", pname, nidx,
+ NULL);
+ /* Zero out the string data for the GC. */
+ pname->string_bytes = 0;
+ pname->string_size = 0;
+ if ( prev == 0 )
+ *phash = next;
+ else
+ set_name_next_index(prev, pnprev, next);
+ }
+ nidx = next;
+ }
+ }
+ /* Reconstruct the free list. */
+ nt->free = 0;
+ for ( i = nt->sub_count; i--; )
+ { name_sub_table *sub = nt->sub_tables[i];
+
+ if ( sub != 0 )
+ { name_scan_sub(nt, i, true);
+ if ( nt->sub_tables[i] == 0 && gcst != 0 )
+ { /* Mark the just-freed sub-table as unmarked. */
+ o_set_unmarked((obj_header_t *)sub - 1);
+ }
+ }
+ if ( i == 0 )
+ break;
+ }
+ nt->sub_next = 0;
+}
+
+/* ------ Save/restore ------ */
+
+/* Clean up the name table before a restore. */
+/* Currently, this is never called, because the name table is allocated */
+/* in system VM. However, for a Level 1 system, we might choose to */
+/* allocate the name table in global VM; in this case, this routine */
+/* would be called before doing the global part of a top-level restore. */
+/* Currently we don't make any attempt to optimize this. */
+void
+name_restore(alloc_save_t *save)
+{ name_table *nt = the_nt;
+ /* We simply mark all names older than the save, */
+ /* and let name_trace_finish sort everything out. */
+ uint si;
+ for ( si = 0; si < nt->sub_count; ++si )
+ if ( nt->sub_tables[si] != 0 )
+ { uint i;
+ for ( i = 0; i < nt_sub_size; ++i )
+ { name *pname =
+ name_index_ptr_inline(nt, (si << nt_log2_sub_size) + i);
+ if ( pname->string_bytes == 0 )
+ pname->mark = 0;
+ else if ( pname->foreign_string )
+ pname->mark = 1;
+ else
+ pname->mark =
+ !alloc_is_since_save(pname->string_bytes, save);
+ }
+ }
+ name_trace_finish(NULL);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Allocate the next sub-table. */
+private int
+name_alloc_sub(name_table *nt)
+{ uint sub_index = nt->sub_next;
+ name_sub_table *sub;
+
+ for ( ; ; ++sub_index )
+ { if ( sub_index > nt->max_sub_count )
+ return_error(e_limitcheck);
+ if ( nt->sub_tables[sub_index] == 0 )
+ break;
+ }
+ nt->sub_next = sub_index + 1;
+ if ( nt->sub_next > nt->sub_count )
+ nt->sub_count = nt->sub_next;
+ sub = gs_alloc_struct(nt->memory, name_sub_table, &st_name_sub_table,
+ "name_alloc_sub");
+ if ( sub == 0 )
+ return_error(e_VMerror);
+ memset(sub, 0, sizeof(name_sub_table));
+ /* The following code is only used if EXTEND_NAMES is non-zero. */
+ if ( sub_index >= 0x10000L >> nt_log2_sub_size )
+ { /* Fill in my_extension in all the newly created names. */
+ uint extn = sub_index >> (16 - nt_log2_sub_size);
+ int i;
+ for ( i = 0; i < nt_sub_size; ++i )
+ set_name_extension(&sub->names[i], extn);
+ }
+ nt->sub_tables[sub_index] = sub;
+ /* Add the newly allocated entries to the free list. */
+ /* Note that the free list will only be properly sorted if */
+ /* it was empty initially. */
+ name_scan_sub(nt, sub_index, false);
+#ifdef DEBUG
+ if ( gs_debug_c('n') )
+ { /* Print the lengths of the hash chains. */
+ int i0;
+ for ( i0 = 0; i0 < nt_hash_size; i0 += 16 )
+ { int i;
+ dprintf1("[n]chain %d:", i0);
+ for ( i = i0; i < i0 + 16; i++ )
+ { int n = 0;
+ uint nidx;
+ for ( nidx = nt->hash[i]; nidx != 0;
+ nidx = name_next_index(nidx, name_index_ptr_inline(nt, nidx))
+ )
+ n++;
+ dprintf1(" %d", n);
+ }
+ dputc('\n');
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Scan a sub-table and add unmarked entries to the free list. */
+/* We add the entries in decreasing count order, so the free list */
+/* will stay sorted. If all entries are unmarked and free_empty is true, */
+/* free the sub-table. */
+private void
+name_scan_sub(name_table *nt, uint sub_index, bool free_empty)
+{ name_sub_table *sub = nt->sub_tables[sub_index];
+ uint free = nt->free;
+ uint nbase = sub_index << nt_log2_sub_size;
+ uint ncnt = nbase + (nt_sub_size - 1);
+ bool keep = !free_empty;
+
+ if ( sub == 0 )
+ return;
+ if ( nbase == 0 )
+ nbase = 1, keep = true; /* don't free name 0 */
+ for ( ; ; --ncnt )
+ { uint nidx = name_count_to_index(ncnt);
+ name *pname = &sub->names[nidx & nt_sub_index_mask];
+ if ( pname->mark )
+ keep = true;
+ else
+ { set_name_next_index(nidx, pname, free);
+ free = nidx;
+ }
+ if ( ncnt == nbase )
+ break;
+ }
+ if ( keep )
+ nt->free = free;
+ else
+ { /* No marked entries, free the sub-table. */
+ gs_free_object(nt->memory, sub, "name_scan_sub");
+ nt->sub_tables[sub_index] = 0;
+ if ( sub_index == nt->sub_count - 1 ) {
+ /* Back up over a final run of deleted sub-tables. */
+ do {
+ --sub_index;
+ } while ( nt->sub_tables[sub_index] == 0 );
+ nt->sub_count = sub_index + 1;
+ if ( nt->sub_next > sub_index )
+ nt->sub_next = sub_index;
+ } else if ( nt->sub_next == sub_index )
+ nt->sub_next--;
+ }
+}
+
+/* Garbage collector enumeration and relocation procedures. */
+#define ntptr ((name_table *)vptr)
+private ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs) {
+ if ( index >= ntptr->sub_count )
+ return 0;
+ *pep = ntptr->sub_tables[index];
+ return ptr_struct_type;
+} ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(name_table_reloc_ptrs) {
+ name_sub_table **sub = ntptr->sub_tables;
+ uint sub_count = ntptr->sub_count;
+ uint i;
+ /* Now we can relocate the sub-table pointers. */
+ for ( i = 0; i < sub_count; i++, sub++ )
+ *sub = gs_reloc_struct_ptr(*sub, gcst);
+ /*
+ * We also need to relocate the cached value pointers.
+ * We don't do this here, but in a separate scan over the
+ * permanent dictionaries, at the very end of garbage collection.
+ */
+} RELOC_PTRS_END
+#undef ntptr
+
+private ENUM_PTRS_BEGIN_PROC(name_sub_enum_ptrs) {
+ return 0;
+} ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(name_sub_reloc_ptrs) {
+ name *pname = ((name_sub_table *)vptr)->names;
+ uint i;
+
+ for ( i = 0; i < nt_sub_size; ++pname, ++i ) {
+ if ( pname->string_bytes != 0 && !pname->foreign_string ) {
+ gs_const_string nstr;
+
+ nstr.data = pname->string_bytes;
+ nstr.size = pname->string_size;
+ gs_reloc_const_string(&nstr, gcst);
+ pname->string_bytes = nstr.data;
+ }
+ }
+} RELOC_PTRS_END
diff --git a/gs/src/iname.h b/gs/src/iname.h
new file mode 100644
index 000000000..073a4c313
--- /dev/null
+++ b/gs/src/iname.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iname.h */
+/* Name table interface */
+
+/*
+ * This file defines those parts of the name table API that do not depend
+ * at all on the implementation.
+ */
+
+/* ---------------- Abstract types ---------------- */
+
+typedef struct name_table_s name_table;
+
+/* ---------------- Constant values ---------------- */
+
+extern const uint name_max_string;
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Allocate and initialize a name table. */
+name_table *name_init(P2(ulong, gs_memory_t *));
+
+/*
+ * The name table machinery is designed so that multiple name tables
+ * are possible, but the interpreter relies on there being only one,
+ * and many of the procedures below assume this (by virtue of
+ * not taking a name_table argument). Therefore, we provide a procedure
+ * to get our hands on that unique table (read-only, however).
+ */
+const name_table *the_name_table(P0());
+
+/* Get the allocator for the name table. */
+gs_memory_t *name_memory(P0());
+
+/*
+ * Look up and/or enter a name in the name table.
+ * The values of enterflag are:
+ * -1 -- don't enter (return an error) if missing;
+ * 0 -- enter if missing, don't copy the string, which was allocated
+ * statically;
+ * 1 -- enter if missing, copy the string;
+ * 2 -- enter if missing, don't copy the string, which was already
+ * allocated dynamically (using the name_memory allocator).
+ * Possible errors: VMerror, limitcheck (if string is too long or if
+ * we have assigned all possible name indices).
+ */
+int name_ref(P4(const byte *ptr, uint size, ref *pnref, int enterflag));
+void name_string_ref(P2(const ref *pnref, ref *psref));
+/*
+ * name_enter_string calls name_ref with a (permanent) C string.
+ */
+int name_enter_string(P2(const char *str, ref *pnref));
+/*
+ * name_from_string essentially implements cvn.
+ * It always enters the name, and copies the executable attribute.
+ */
+int name_from_string(P2(const ref *psref, ref *pnref));
+
+/* Compare two names for equality. */
+#define name_eq(pnref1, pnref2)\
+ ((pnref1)->value.pname == (pnref2)->value.pname)
+
+/* Invalidate the value cache for a name. */
+void name_invalidate_value_cache(P1(const ref *));
+
+/* Convert between names and indices. */
+uint name_index(P1(const ref *)); /* ref => index */
+name *name_index_ptr(P1(uint nidx)); /* index => name */
+void name_index_ref(P2(uint nidx, ref *pnref)); /* index => ref */
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+uint name_next_valid_index(P1(uint));
+
+/* Mark a name for the garbage collector. */
+/* Return true if this is a new mark. */
+bool name_mark_index(P1(uint));
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+void/*obj_header_t*/ *name_ref_sub_table(P1(const ref *));
+void/*obj_header_t*/ *name_index_ptr_sub_table(P2(uint, name *));
diff --git a/gs/src/inamedef.h b/gs/src/inamedef.h
new file mode 100644
index 000000000..e893454f5
--- /dev/null
+++ b/gs/src/inamedef.h
@@ -0,0 +1,207 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* inamedef.h */
+/* Name table definition */
+#include "iname.h"
+#include "gconfigv.h" /* defines EXTEND_NAMES */
+
+/*
+ * The name table machinery has two slightly different configurations:
+ * a faster one that limits the total number of names to 64K and allows
+ * names up to 16K in size, and a slightly slower one that limits
+ * the total to 4M and restricts names to 256 characters.
+ */
+#if arch_sizeof_int < 4
+# undef EXTEND_NAMES /* no extended names if ints are short */
+#endif
+#ifndef EXTEND_NAMES /* # of bits beyond 16 */
+# define EXTEND_NAMES 0
+#endif
+#define max_name_extension_bits 6
+#if EXTEND_NAMES > max_name_extension_bits
+# undef EXTEND_NAMES
+# define EXTEND_NAMES max_name_extension_bits
+#endif
+/*
+ * We capture the small algorithmic differences between these two
+ * configurations entirely in this header file;
+ * the implementation doesn't need any conditionals on EXTEND_NAMES.
+ */
+#define max_name_index (uint)((0x10000 << EXTEND_NAMES) - 1)
+/* As explained below, we distinguish name indices from name counts. */
+#define max_name_count max_name_index
+
+/* ---------------- Structure definitions ---------------- */
+
+/*
+ * Define the structure of a name. The next_index "pointer" is used for
+ * the chained hash table in the name_table, and also for the list of
+ * free names. The pvalue member implements an important optimization
+ * to avoid lookup for operator and other global names.
+ */
+struct name_s {
+ ushort next_index; /* (low bits of) next name in chain or 0 */
+ unsigned foreign_string : 1; /* string is allocated statically */
+ unsigned mark : 1; /* GC mark bit */
+#if EXTEND_NAMES
+# define name_extension_bits 6
+ unsigned my_extension : name_extension_bits; /* high-order bits */
+# define set_name_extension(pname, xbits) ((pname)->my_extension = xbits)
+#else
+# define name_extension_bits 0
+# define set_name_extension(name, xbits) DO_NOTHING
+#endif
+ /* of index for this name */
+#define name_string_size_bits (14 - name_extension_bits)
+#define max_name_string ((1 << name_string_size_bits) - 1)
+ unsigned string_size : name_string_size_bits;
+ const byte *string_bytes;
+/* pvalue specifies the definition status of the name: */
+/* pvalue == pv_no_defn: no definitions */
+#define pv_no_defn ((ref *)0)
+/* pvalue == pv_other: other status */
+#define pv_other ((ref *)1)
+/* pvalue != pv_no_defn, pvalue != pv_other: pvalue is valid */
+#define pv_valid(pvalue) ((unsigned long)(pvalue) > 1)
+ ref *pvalue; /* if only defined in systemdict */
+ /* or userdict, this points to */
+ /* the value */
+};
+/*typedef struct name_s name;*/ /* in iref.h */
+
+/*
+ * Define the structure of a name table. Normally we would make this
+ * an opaque type, but we want to be able to in-line some of the
+ * access procedures.
+ *
+ * The name table is a two-level indexed table, consisting of
+ * sub-tables of size nt_sub_size each.
+ *
+ * First we define the name sub-table structure.
+ */
+#define nt_log2_sub_size (7 + (EXTEND_NAMES / 2))
+# define nt_sub_size (1 << nt_log2_sub_size)
+# define nt_sub_index_mask (nt_sub_size - 1)
+typedef struct name_sub_table_s {
+ name names[nt_sub_size]; /* must be first */
+#if EXTEND_NAMES
+ byte next_index_extension[nt_sub_size]; /* high-order bits */
+ /* of next_index */
+# define name_next_index(nidx, pname)\
+ ( (((name_sub_table *)((pname) - ((nidx) & nt_sub_index_mask)))->\
+ next_index_extension[(nidx) & nt_sub_index_mask] << 16) +\
+ ((pname)->next_index)\
+ )
+# define set_name_next_index(nidx, pname, next)\
+ ( ((name_sub_table *)((pname) - ((nidx) & nt_sub_index_mask)))->\
+ next_index_extension[(nidx) & nt_sub_index_mask] =\
+ (byte)((next) >> 16),\
+ (pname)->next_index = (ushort)(next)\
+ )
+#else /* !EXTEND_NAMES */
+# define name_next_index(nidx, pname)\
+ ((pname)->next_index)
+# define set_name_next_index(nidx, pname, next)\
+ ((pname)->next_index = (next))
+#endif /* (!)EXTEND_NAMES */
+} name_sub_table;
+/*
+ * Now define the name table itself.
+ * This must be made visible so that the interpreter can use the
+ * inline macros defined below.
+ */
+#define nt_hash_size (1024 << (EXTEND_NAMES / 2)) /* must be a power of 2 */
+struct name_table_s {
+ uint free; /* head of free list, which is sorted in */
+ /* increasing count (not index) order */
+ uint sub_next; /* index of next sub-table to allocate */
+ /* if not already allocated */
+ uint sub_count; /* index of highest allocated sub-table +1 */
+ uint max_sub_count; /* max allowable value of sub_count */
+ gs_memory_t *memory;
+ uint hash[nt_hash_size];
+ name_sub_table *sub_tables[max_name_index / nt_sub_size + 1];
+};
+/*typedef struct name_table_s name_table;*/ /* in iname.h */
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Convert between names and indices. Note that the inline versions, */
+/* but not the procedure versions, take a name_table argument. */
+ /* ref => index */
+#if EXTEND_NAMES
+# define name_index_inline(pnref)\
+ ( ((uint)((pnref)->value.pname->my_extension) << 16) + r_size(pnref) )
+#else
+# define name_index_inline(pnref) r_size(pnref)
+#endif
+#define name_index(pnref) name_index_inline(pnref)
+ /* index => name */
+#define name_index_ptr_inline(nt, nidx)\
+ ((nt)->sub_tables[(nidx) >> nt_log2_sub_size]->names + ((nidx) & nt_sub_index_mask))
+ /* index => ref */
+#define name_index_ref_inline(nt, nidx, pnref)\
+ make_name(pnref, nidx, name_index_ptr_inline(nt, nidx));
+ /* name => ref */
+/* We have to set the space to system so that the garbage collector */
+/* won't think names are foreign and therefore untraceable. */
+#define make_name(pnref, nidx, pnm)\
+ make_tasv(pnref, t_name, avm_system, (ushort)(nidx), pname, pnm)
+
+/* ------ Garbage collection ------ */
+
+/* Unmark all names, except for 1-character permanent names, */
+/* before a garbage collection. */
+void name_unmark_all(P0());
+
+/* Finish tracing the name table by putting free names on the free list. */
+void name_trace_finish(P1(gc_state_t *));
+
+/* ------ Save/restore ------ */
+
+/* Clean up the name table before a restore, */
+/* by removing names whose count is less than old_count. */
+#ifndef alloc_save_t_DEFINED /* also in isave.h */
+typedef struct alloc_save_s alloc_save_t;
+# define alloc_save_t_DEFINED
+#endif
+void name_restore(P1(alloc_save_t *));
+
+/* ---------------- Name count/index maintenance ---------------- */
+
+/*
+ * We scramble the assignment order within a sub-table, so that
+ * dictionary lookup doesn't have to scramble the index.
+ * The scrambling algorithm must have three properties:
+ * - It must map 0 to 0;
+ * - It must only scramble the sub-table index;
+ * - It must be a permutation on the sub-table index.
+ * Something very simple works just fine.
+ */
+#define name_count_to_index(cnt)\
+ (((cnt) & (-nt_sub_size)) +\
+ (((cnt) * 59) & nt_sub_index_mask))
+/*
+ * The reverse permutation requires finding a number R such that
+ * 59*R = 1 mod nt_sub_size. For nt_sub_size any power of 2 up to 2048,
+ * R = 243 will work. Currently, this is only needed for debugging printout.
+ */
+#define name_index_to_count(nidx)\
+ (((nidx) & (-nt_sub_size)) +\
+ (((nidx) * 243) & nt_sub_index_mask))
diff --git a/gs/src/int.mak b/gs/src/int.mak
new file mode 100644
index 000000000..4b8227ad9
--- /dev/null
+++ b/gs/src/int.mak
@@ -0,0 +1,1223 @@
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for language interpreters.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+INT_MAK=int.mak
+
+# ======================== Interpreter support ======================== #
+
+# This is support code for all interpreters, not just PostScript and PDF.
+# It knows about the PostScript data types, but isn't supposed to
+# depend on anything outside itself.
+
+errors_h=errors.h
+idebug_h=idebug.h
+idict_h=idict.h
+igc_h=igc.h
+igcstr_h=igcstr.h
+iname_h=iname.h
+inamedef_h=inamedef.h $(gconfigv_h) $(iname_h)
+ipacked_h=ipacked.h
+iref_h=iref.h
+isave_h=isave.h
+isstate_h=isstate.h
+istruct_h=istruct.h $(gsstruct_h)
+iutil_h=iutil.h
+ivmspace_h=ivmspace.h $(gsgc_h)
+opdef_h=opdef.h
+# Nested include files
+ghost_h=ghost.h $(gx_h) $(iref_h)
+imemory_h=imemory.h $(gsalloc_h) $(ivmspace_h)
+ialloc_h=ialloc.h $(imemory_h)
+iastruct_h=iastruct.h $(gxobj_h) $(ialloc_h)
+iastate_h=iastate.h $(gxalloc_h) $(ialloc_h) $(istruct_h)
+store_h=store.h $(ialloc_h)
+
+GH=$(AK) $(ghost_h)
+
+isupport1_=ialloc.$(OBJ) igc.$(OBJ) igcref.$(OBJ) igcstr.$(OBJ)
+isupport2_=ilocate.$(OBJ) iname.$(OBJ) isave.$(OBJ)
+isupport_=$(isupport1_) $(isupport2_)
+isupport.dev: $(INT_MAK) $(ECHOGS_XE) $(isupport_)
+ $(SETMOD) isupport $(isupport1_)
+ $(ADDMOD) isupport -obj $(isupport2_)
+ $(ADDMOD) isupport -init igcref
+
+ialloc.$(OBJ): ialloc.c $(AK) $(memory__h) $(gx_h)\
+ $(errors_h) $(gsstruct_h) $(gxarith_h)\
+ $(iastate_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+# igc.c, igcref.c, and igcstr.c should really be in the dpsand2 list,
+# but since all the GC enumeration and relocation routines refer to them,
+# it's too hard to separate them out from the Level 1 base.
+igc.$(OBJ): igc.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsmdebug_h) $(gsstruct_h) $(gsutil_h) \
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(inamedef_h) \
+ $(ipacked_h) $(isave_h) $(isstate_h) $(istruct_h) $(opdef_h)
+
+igcref.$(OBJ): igcref.c $(GH) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idebug_h) $(igc_h) $(iname_h) $(ipacked_h) $(store_h)
+
+igcstr.$(OBJ): igcstr.c $(GH) $(memory__h)\
+ $(gsmdebug_h) $(gsstruct_h) $(iastate_h) $(igcstr_h)
+
+ilocate.$(OBJ): ilocate.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(iname_h)\
+ $(ipacked_h) $(isstate_h) $(iutil_h) $(ivmspace_h)\
+ $(store_h)
+
+iname.$(OBJ): iname.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h) $(gxobj_h)\
+ $(errors_h) $(imemory_h) $(inamedef_h) $(isave_h) $(store_h)
+
+isave.$(OBJ): isave.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h) $(gsutil_h)\
+ $(iastate_h) $(inamedef_h) $(isave_h) $(isstate_h) $(ivmspace_h)\
+ $(ipacked_h) $(store_h)
+
+### Include files
+
+idparam_h=idparam.h
+ilevel_h=ilevel.h
+iparam_h=iparam.h $(gsparam_h)
+istack_h=istack.h
+iutil2_h=iutil2.h
+opcheck_h=opcheck.h
+opextern_h=opextern.h
+# Nested include files
+dstack_h=dstack.h $(istack_h)
+estack_h=estack.h $(istack_h)
+ostack_h=ostack.h $(istack_h)
+oper_h=oper.h $(iutil_h) $(opcheck_h) $(opdef_h) $(opextern_h) $(ostack_h)
+
+idebug.$(OBJ): idebug.c $(GH) $(string__h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(ostack_h) $(opdef_h) $(ipacked_h) $(store_h)
+
+idict.$(OBJ): idict.c $(GH) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idebug_h) $(ivmspace_h) $(inamedef_h) $(ipacked_h)\
+ $(isave_h) $(store_h) $(iutil_h) $(idict_h) $(dstack_h)
+
+idparam.$(OBJ): idparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(gsmatrix_h) $(gsuid_h)\
+ $(idict_h) $(idparam_h) $(ilevel_h) $(imemory_h) $(iname_h) $(iutil_h)\
+ $(oper_h) $(store_h)
+
+iparam.$(OBJ): iparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(iname_h) $(imemory_h) $(iparam_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(opcheck_h) $(store_h)
+
+istack.$(OBJ): istack.c $(GH) $(memory__h) \
+ $(errors_h) $(gsstruct_h) $(gsutil_h) \
+ $(ialloc_h) $(istack_h) $(istruct_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iutil.$(OBJ): iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\
+ $(gsccode_h) $(gsmatrix_h) $(gsutil_h) $(gxfont_h)\
+ $(errors_h) $(idict_h) $(imemory_h) $(iutil_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(oper_h) $(store_h)
+
+# ======================== PostScript Level 1 ======================== #
+
+###### Include files
+
+files_h=files.h
+fname_h=fname.h
+ichar_h=ichar.h
+icharout_h=icharout.h
+icolor_h=icolor.h
+icontext_h=icontext.h $(imemory_h) $(istack_h)
+icsmap_h=icsmap.h
+ifont_h=ifont.h $(gsccode_h) $(gsstruct_h)
+iht_h=iht.h
+iimage_h=iimage.h
+imain_h=imain.h $(gsexit_h)
+imainarg_h=imainarg.h
+iminst_h=iminst.h $(imain_h)
+interp_h=interp.h
+iparray_h=iparray.h
+iscannum_h=iscannum.h
+istream_h=istream.h
+main_h=main.h $(iminst_h)
+overlay_h=overlay.h
+sbwbs_h=sbwbs.h
+sfilter_h=sfilter.h $(gstypes_h)
+shcgen_h=shcgen.h
+smtf_h=smtf.h
+# Nested include files
+bfont_h=bfont.h $(ifont_h)
+ifilter_h=ifilter.h $(istream_h) $(ivmspace_h)
+igstate_h=igstate.h $(gsstate_h) $(gxstate_h) $(istruct_h)
+iscan_h=iscan.h $(sa85x_h) $(sstring_h)
+sbhc_h=sbhc.h $(shc_h)
+# Include files for optional features
+ibnum_h=ibnum.h
+
+### Initialization and scanning
+
+iconfig=iconfig$(CONFIG)
+$(iconfig).$(OBJ): iconf.c $(stdio__h) \
+ $(gconfig_h) $(gscdefs_h) $(gsmemory_h) \
+ $(files_h) $(iminst_h) $(iref_h) $(ivmspace_h) $(opdef_h) $(stream_h)
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) iconf.c $(iconfig).c
+ $(CCC) $(iconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+
+iinit.$(OBJ): iinit.c $(GH) $(string__h)\
+ $(gscdefs_h) $(gsexit_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h)\
+ $(ilevel_h) $(iname_h) $(interp_h) $(opdef_h)\
+ $(ipacked_h) $(iparray_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iscan.$(OBJ): iscan.c $(GH) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h) $(files_h)\
+ $(ilevel_h) $(iutil_h) $(iscan_h) $(iscannum_h) $(istruct_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(iparray_h) $(istream_h) $(ostack_h) $(store_h)\
+ $(stream_h) $(strimpl_h) $(sfilter_h) $(scanchar_h)
+
+iscannum.$(OBJ): iscannum.c $(GH) $(math__h)\
+ $(errors_h) $(iscannum_h) $(scanchar_h) $(scommon_h) $(store_h)
+
+### Streams
+
+sfilter1.$(OBJ): sfilter1.c $(AK) $(stdio__h) $(memory__h) \
+ $(sfilter_h) $(strimpl_h)
+
+###### Operators
+
+OP=$(GH) $(errors_h) $(oper_h)
+
+### Non-graphics operators
+
+zarith.$(OBJ): zarith.c $(OP) $(math__h) $(store_h)
+
+zarray.$(OBJ): zarray.c $(OP) $(memory__h) $(ialloc_h) $(ipacked_h) $(store_h)
+
+zcontrol.$(OBJ): zcontrol.c $(OP) $(string__h)\
+ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)
+
+zdict.$(OBJ): zdict.c $(OP) \
+ $(dstack_h) $(idict_h) $(ilevel_h) $(iname_h) $(ipacked_h) $(ivmspace_h) \
+ $(store_h)
+
+zfile.$(OBJ): zfile.c $(OP) $(memory__h) $(string__h) $(gp_h)\
+ $(gsstruct_h) $(gxiodev_h) \
+ $(ialloc_h) $(estack_h) $(files_h) $(fname_h) $(ilevel_h) $(interp_h) $(iutil_h)\
+ $(isave_h) $(main_h) $(sfilter_h) $(stream_h) $(strimpl_h) $(store_h)
+
+zfileio.$(OBJ): zfileio.c $(OP) $(gp_h) \
+ $(files_h) $(ifilter_h) $(store_h) $(stream_h) $(strimpl_h) \
+ $(gsmatrix_h) $(gxdevice_h) $(gxdevmem_h)
+
+zfilter.$(OBJ): zfilter.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sfilter_h) $(srlx_h) $(sstring_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zfname.$(OBJ): zfname.c $(OP) $(memory__h)\
+ $(fname_h) $(gxiodev_h) $(ialloc_h) $(stream_h)
+
+zfproc.$(OBJ): zfproc.c $(GH) $(memory__h)\
+ $(errors_h) $(oper_h)\
+ $(estack_h) $(files_h) $(gsstruct_h) $(ialloc_h) $(ifilter_h) $(istruct_h)\
+ $(store_h) $(stream_h) $(strimpl_h)
+
+zgeneric.$(OBJ): zgeneric.c $(OP) $(memory__h)\
+ $(idict_h) $(estack_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(store_h)
+
+ziodev.$(OBJ): ziodev.c $(OP) $(memory__h) $(stdio__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsstruct_h) $(gxiodev_h)\
+ $(files_h) $(ialloc_h) $(ivmspace_h) $(store_h) $(stream_h)
+
+zmath.$(OBJ): zmath.c $(OP) $(math__h) $(gxfarith_h) $(store_h)
+
+zmisc.$(OBJ): zmisc.c $(OP) $(gscdefs_h) $(gp_h) \
+ $(errno__h) $(memory__h) $(string__h) \
+ $(ialloc_h) $(idict_h) $(dstack_h) $(iname_h) $(ivmspace_h) $(ipacked_h) $(store_h)
+
+zpacked.$(OBJ): zpacked.c $(OP) \
+ $(ialloc_h) $(idict_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(iparray_h) \
+ $(istack_h) $(store_h)
+
+zrelbit.$(OBJ): zrelbit.c $(OP) $(gsutil_h) $(store_h) $(idict_h)
+
+zstack.$(OBJ): zstack.c $(OP) $(memory__h)\
+ $(ialloc_h) $(istack_h) $(store_h)
+
+zstring.$(OBJ): zstring.c $(OP) $(memory__h)\
+ $(gsutil_h)\
+ $(ialloc_h) $(iname_h) $(ivmspace_h) $(store_h)
+
+zsysvm.$(OBJ): zsysvm.c $(GH)\
+ $(ialloc_h) $(ivmspace_h) $(oper_h) $(store_h)
+
+ztoken.$(OBJ): ztoken.c $(OP) \
+ $(estack_h) $(files_h) $(gsstruct_h) $(iscan_h) \
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+ztype.$(OBJ): ztype.c $(OP) $(math__h) $(memory__h) $(string__h)\
+ $(dstack_h) $(idict_h) $(imemory_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zvmem.$(OBJ): zvmem.c $(OP)\
+ $(dstack_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(isave_h) $(store_h) $(stream_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h)
+
+### Graphics operators
+
+zchar.$(OBJ): zchar.c $(OP)\
+ $(gsstruct_h) $(gxarith_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxchar_h) $(gxdevice_h) $(gxfont_h) $(gzpath_h) $(gzstate_h)\
+ $(dstack_h) $(estack_h) $(ialloc_h) $(ichar_h) $(idict_h) $(ifont_h)\
+ $(ilevel_h) $(iname_h) $(igstate_h) $(ipacked_h) $(store_h)
+
+# zcharout is used for Type 1 and Type 42 fonts only.
+zcharout.$(OBJ): zcharout.c $(OP)\
+ $(gschar_h) $(gxdevice_h) $(gxfont_h)\
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h)\
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zcolor.$(OBJ): zcolor.c $(OP) \
+ $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gxdevice_h) $(gxcmap_h) \
+ $(ialloc_h) $(icolor_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zdevice.$(OBJ): zdevice.c $(OP) $(string__h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gxdevice_h) $(store_h)
+
+zfont.$(OBJ): zfont.c $(OP)\
+ $(gschar_h) $(gsstruct_h) $(gxdevice_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(isave_h) $(ivmspace_h)\
+ $(bfont_h) $(store_h)
+
+zfont2.$(OBJ): zfont2.c $(OP) $(memory__h) $(string__h)\
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(bfont_h) $(idict_h) $(idparam_h) $(ilevel_h) $(iname_h) $(istruct_h)\
+ $(ipacked_h) $(store_h)
+
+zgstate.$(OBJ): zgstate.c $(OP) $(math__h)\
+ $(gsmatrix_h) $(ialloc_h) $(idict_h) $(igstate_h) $(istruct_h) $(store_h)
+
+zht.$(OBJ): zht.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+zimage.$(OBJ): zimage.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ifilter_h) $(igstate_h) $(iimage_h) $(ilevel_h) \
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(store_h) $(stream_h)
+
+zmatrix.$(OBJ): zmatrix.c $(OP)\
+ $(gsmatrix_h) $(igstate_h) $(gscoord_h) $(store_h)
+
+zpaint.$(OBJ): zpaint.c $(OP)\
+ $(gspaint_h) $(igstate_h)
+
+zpath.$(OBJ): zpath.c $(OP) $(math__h) \
+ $(gsmatrix_h) $(gspath_h) $(igstate_h) $(store_h)
+
+# Define the base PostScript language interpreter.
+# This is the subset of PostScript Level 1 required by our PDF reader.
+
+INT1=idebug.$(OBJ) idict.$(OBJ) idparam.$(OBJ)
+INT2=iinit.$(OBJ) interp.$(OBJ) iparam.$(OBJ) ireclaim.$(OBJ)
+INT3=iscan.$(OBJ) iscannum.$(OBJ) istack.$(OBJ) iutil.$(OBJ)
+INT4=scantab.$(OBJ) sfilter1.$(OBJ) sstring.$(OBJ) stream.$(OBJ)
+Z1=zarith.$(OBJ) zarray.$(OBJ) zcontrol.$(OBJ) zdict.$(OBJ)
+Z1OPS=zarith zarray zcontrol zdict
+Z2=zfile.$(OBJ) zfileio.$(OBJ) zfilter.$(OBJ) zfname.$(OBJ) zfproc.$(OBJ)
+Z2OPS=zfile zfileio zfilter zfproc
+Z3=zgeneric.$(OBJ) ziodev.$(OBJ) zmath.$(OBJ) zmisc.$(OBJ) zpacked.$(OBJ)
+Z3OPS=zgeneric ziodev zmath zmisc zpacked
+Z4=zrelbit.$(OBJ) zstack.$(OBJ) zstring.$(OBJ) zsysvm.$(OBJ)
+Z4OPS=zrelbit zstack zstring zsysvm
+Z5=ztoken.$(OBJ) ztype.$(OBJ) zvmem.$(OBJ)
+Z5OPS=ztoken ztype zvmem
+Z6=zchar.$(OBJ) zcolor.$(OBJ) zdevice.$(OBJ) zfont.$(OBJ) zfont2.$(OBJ)
+Z6OPS=zchar zcolor zdevice zfont zfont2
+Z7=zgstate.$(OBJ) zht.$(OBJ) zimage.$(OBJ) zmatrix.$(OBJ) zpaint.$(OBJ) zpath.$(OBJ)
+Z7OPS=zgstate zht zimage zmatrix zpaint zpath
+# We have to be a little underhanded with *config.$(OBJ) so as to avoid
+# circular definitions.
+INT_OBJS=imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ) \
+ $(INT1) $(INT2) $(INT3) $(INT4) \
+ $(Z1) $(Z2) $(Z3) $(Z4) $(Z5) $(Z6) $(Z7)
+INT_CONFIG=$(gconfig).$(OBJ) $(gscdefs).$(OBJ) $(iconfig).$(OBJ) \
+ iccinit$(COMPILE_INITS).$(OBJ)
+INT_ALL=$(INT_OBJS) $(INT_CONFIG)
+# We omit libcore.dev, which should be included here, because problems
+# with the Unix linker require libcore to appear last in the link list
+# when libcore is really a library.
+# We omit $(INT_CONFIG) from the dependency list because they have special
+# dependency requirements and are added to the link list at the very end.
+# zfilter.c shouldn't include the RLE and RLD filters, but we don't want to
+# change this now.
+psbase.dev: $(INT_MAK) $(ECHOGS_XE) $(INT_OBJS)\
+ isupport.dev rld.dev rle.dev sfile.dev
+ $(SETMOD) psbase imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ)
+ $(ADDMOD) psbase -obj $(INT_CONFIG)
+ $(ADDMOD) psbase -obj $(INT1)
+ $(ADDMOD) psbase -obj $(INT2)
+ $(ADDMOD) psbase -obj $(INT3)
+ $(ADDMOD) psbase -obj $(INT4)
+ $(ADDMOD) psbase -obj $(Z1)
+ $(ADDMOD) psbase -oper $(Z1OPS)
+ $(ADDMOD) psbase -obj $(Z2)
+ $(ADDMOD) psbase -oper $(Z2OPS)
+ $(ADDMOD) psbase -obj $(Z3)
+ $(ADDMOD) psbase -oper $(Z3OPS)
+ $(ADDMOD) psbase -obj $(Z4)
+ $(ADDMOD) psbase -oper $(Z4OPS)
+ $(ADDMOD) psbase -obj $(Z5)
+ $(ADDMOD) psbase -oper $(Z5OPS)
+ $(ADDMOD) psbase -obj $(Z6)
+ $(ADDMOD) psbase -oper $(Z6OPS)
+ $(ADDMOD) psbase -obj $(Z7)
+ $(ADDMOD) psbase -oper $(Z7OPS)
+ $(ADDMOD) psbase -iodev stdin stdout stderr lineedit statementedit
+ $(ADDMOD) psbase -include isupport rld rle sfile
+
+# -------------------------- Feature definitions -------------------------- #
+
+# ---------------- Full Level 1 interpreter ---------------- #
+
+level1.dev: $(INT_MAK) $(ECHOGS_XE) psbase.dev bcp.dev hsb.dev path1.dev type1.dev
+ $(SETMOD) level1 -include psbase bcp hsb path1 type1
+ $(ADDMOD) level1 -emulator PostScript PostScriptLevel1
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+color.dev: $(INT_MAK) $(ECHOGS_XE) cmyklib.dev colimlib.dev cmykread.dev
+ $(SETMOD) color -include cmyklib colimlib cmykread
+
+cmykread_=zcolor1.$(OBJ) zht1.$(OBJ)
+cmykread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmykread_)
+ $(SETMOD) cmykread $(cmykread_)
+ $(ADDMOD) cmykread -oper zcolor1 zht1
+
+zcolor1.$(OBJ): zcolor1.c $(OP) \
+ $(gscolor1_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) \
+ $(ialloc_h) $(icolor_h) $(iimage_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zht1.$(OBJ): zht1.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h)\
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+# ---------------- HSB color ---------------- #
+
+hsb_=zhsb.$(OBJ)
+hsb.dev: $(INT_MAK) $(ECHOGS_XE) $(hsb_) hsblib.dev
+ $(SETMOD) hsb $(hsb_)
+ $(ADDMOD) hsb -include hsblib
+ $(ADDMOD) hsb -oper zhsb
+
+zhsb.$(OBJ): zhsb.c $(OP) \
+ $(gshsb_h) $(igstate_h) $(store_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1_=zpath1.$(OBJ)
+path1.dev: $(INT_MAK) $(ECHOGS_XE) $(path1_) path1lib.dev
+ $(SETMOD) path1 $(path1_)
+ $(ADDMOD) path1 -include path1lib
+ $(ADDMOD) path1 -oper zpath1
+
+zpath1.$(OBJ): zpath1.c $(OP) $(memory__h)\
+ $(ialloc_h) $(estack_h) $(gspath_h) $(gsstruct_h) $(igstate_h) $(store_h)
+
+# ================ Level-independent PostScript options ================ #
+
+# ---------------- BCP filters ---------------- #
+
+bcp_=sbcp.$(OBJ) zfbcp.$(OBJ)
+bcp.dev: $(INT_MAK) $(ECHOGS_XE) $(bcp_)
+ $(SETMOD) bcp $(bcp_)
+ $(ADDMOD) bcp -oper zfbcp
+
+sbcp.$(OBJ): sbcp.c $(AK) $(stdio__h) \
+ $(sfilter_h) $(strimpl_h)
+
+zfbcp.$(OBJ): zfbcp.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# ---------------- Incremental font loading ---------------- #
+# (This only works for Type 1 fonts without eexec encryption.)
+
+diskfont.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) diskfont -ps gs_diskf
+
+# ---------------- Double-precision floats ---------------- #
+
+double_=zdouble.$(OBJ)
+double.dev: $(INT_MAK) $(ECHOGS_XE) $(double_)
+ $(SETMOD) double $(double_)
+ $(ADDMOD) double -oper zdouble
+
+zdouble.$(OBJ): zdouble.c $(OP) $(ctype__h) $(math__h) $(memory__h) $(string__h) \
+ $(gxfarith_h) $(store_h)
+
+# ---------------- EPSF files with binary headers ---------------- #
+
+epsf.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) epsf -ps gs_epsf
+
+# ---------------- RasterOp ---------------- #
+# This should be a separable feature in the core also....
+
+rasterop.dev: $(INT_MAK) $(ECHOGS_XE) roplib.dev ropread.dev
+ $(SETMOD) rasterop -include roplib ropread
+
+ropread_=zrop.$(OBJ)
+ropread.dev: $(INT_MAK) $(ECHOGS_XE) $(ropread_)
+ $(SETMOD) ropread $(ropread_)
+ $(ADDMOD) ropread -oper zrop
+
+zrop.$(OBJ): zrop.c $(OP) $(memory__h)\
+ $(gsrop_h) $(gsutil_h) $(gxdevice_h)\
+ $(idict_h) $(idparam_h) $(igstate_h) $(store_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1.dev: $(INT_MAK) $(ECHOGS_XE) psf1lib.dev psf1read.dev
+ $(SETMOD) type1 -include psf1lib psf1read
+
+psf1read_=seexec.$(OBJ) zchar1.$(OBJ) zcharout.$(OBJ) zfont1.$(OBJ) zmisc1.$(OBJ)
+psf1read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf1read_)
+ $(SETMOD) psf1read $(psf1read_)
+ $(ADDMOD) psf1read -oper zchar1 zfont1 zmisc1
+ $(ADDMOD) psf1read -ps gs_type1
+
+seexec.$(OBJ): seexec.c $(AK) $(stdio__h) \
+ $(gscrypt1_h) $(scanchar_h) $(sfilter_h) $(strimpl_h)
+
+zchar1.$(OBJ): zchar1.c $(OP) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h) $(gzstate_h) \
+ $(estack_h) $(ialloc_h) $(ichar_h) $(icharout_h) \
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zfont1.$(OBJ): zfont1.c $(OP) \
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont1_h) \
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(store_h)
+
+zmisc1.$(OBJ): zmisc1.c $(OP) $(memory__h)\
+ $(gscrypt1_h)\
+ $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# -------------- Compact Font Format and Type 2 charstrings ------------- #
+
+cff.dev: $(INT_MAK) $(ECHOGS_XE) gs_cff.ps psl2int.dev
+ $(SETMOD) cff -ps gs_cff
+
+type2.dev: $(INT_MAK) $(ECHOGS_XE) type1.dev psf2lib.dev
+ $(SETMOD) type2 -include psf2lib
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+# Native TrueType support
+ttfont.dev: $(INT_MAK) $(ECHOGS_XE) type42.dev
+ $(SETMOD) ttfont -include type42
+ $(ADDMOD) ttfont -ps gs_mro_e gs_wan_e gs_ttf
+
+# Type 42 (embedded TrueType) support
+type42read_=zchar42.$(OBJ) zcharout.$(OBJ) zfont42.$(OBJ)
+type42.dev: $(INT_MAK) $(ECHOGS_XE) $(type42read_) ttflib.dev
+ $(SETMOD) type42 $(type42read_)
+ $(ADDMOD) type42 -include ttflib
+ $(ADDMOD) type42 -oper zchar42 zfont42
+ $(ADDMOD) type42 -ps gs_typ42
+
+zchar42.$(OBJ): zchar42.c $(OP) \
+ $(gsmatrix_h) $(gspaint_h) $(gspath_h) \
+ $(gxfixed_h) $(gxchar_h) $(gxfont_h) $(gxfont42_h) \
+ $(gxistate_h) $(gxpath_h) $(gzstate_h) \
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h) \
+ $(ifont_h) $(igstate_h) $(store_h)
+
+zfont42.$(OBJ): zfont42.c $(OP) \
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h) $(gxfont42_h) \
+ $(bfont_h) $(idict_h) $(idparam_h) $(store_h)
+
+# ======================== Precompilation options ======================== #
+
+# ---------------- Precompiled fonts ---------------- #
+# See fonts.txt for more information.
+
+ccfont_h=ccfont.h $(std_h) $(gsmemory_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+CCFONT=$(OP) $(ccfont_h)
+
+# List the fonts we are going to compile.
+# Because of intrinsic limitations in `make', we have to list
+# the object file names and the font names separately.
+# Because of limitations in the DOS shell, we have to break the fonts up
+# into lists that will fit on a single line (120 characters).
+# The rules for constructing the .c files from the fonts themselves,
+# and for compiling the .c files, are in cfonts.mak, not here.
+# For example, to compile the Courier fonts, you should invoke
+# make -f cfonts.mak Courier_o
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+ccfonts_ps=gs_ccfnt
+ccfonts1_=0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+ccfonts1=agk agko agd agdo
+ccfonts2_=0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+ccfonts2=bkl bkli bkd bkdi
+ccfonts3_=0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+ccfonts3=crr cri crb crbi
+ccfonts4_=0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ)
+ccfonts4=hvr hvro hvb hvbo
+ccfonts5_=0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+ccfonts5=hvrrn hvrorn hvbrn hvborn
+ccfonts6_=0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+ccfonts6=ncr ncri ncb ncbi
+ccfonts7_=0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+ccfonts7=plr plri plb plbi
+ccfonts8_=0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+ccfonts8=tmr tmri tmb tmbi
+ccfonts9_=0syr.$(OBJ) 0zcmi.$(OBJ) 0zdr.$(OBJ)
+ccfonts9=syr zcmi zdr
+# The free distribution includes Bitstream Charter, Utopia, and
+# freeware Cyrillic and Kana fonts. We only provide for compiling
+# Charter and Utopia.
+ccfonts10free_=bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+ccfonts10free=chr chri chb chbi
+ccfonts11free_=putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+ccfonts11free=utr utri utb utbi
+# Uncomment the alternatives in the next 4 lines if you want
+# Charter and Utopia compiled in.
+#ccfonts10_=$(ccfonts10free_)
+ccfonts10_=
+#ccfonts10=$(ccfonts10free)
+ccfonts10=
+#ccfonts11_=$(ccfonts11free_)
+ccfonts11_=
+#ccfonts11=$(ccfonts11free)
+ccfonts11=
+# Add your own fonts here if desired.
+ccfonts12_=
+ccfonts12=
+ccfonts13_=
+ccfonts13=
+ccfonts14_=
+ccfonts14=
+ccfonts15_=
+ccfonts15=
+
+# It's OK for ccfonts_.dev not to be CONFIG-dependent, because it only
+# exists during the execution of the following rule.
+# font2c has the prefix "gs" built into it, so we need to instruct
+# genconf to use the same one.
+$(gconfigf_h): $(MAKEFILE) $(INT_MAK) $(GENCONF_XE)
+ $(SETMOD) ccfonts_ -font $(ccfonts1)
+ $(ADDMOD) ccfonts_ -font $(ccfonts2)
+ $(ADDMOD) ccfonts_ -font $(ccfonts3)
+ $(ADDMOD) ccfonts_ -font $(ccfonts4)
+ $(ADDMOD) ccfonts_ -font $(ccfonts5)
+ $(ADDMOD) ccfonts_ -font $(ccfonts6)
+ $(ADDMOD) ccfonts_ -font $(ccfonts7)
+ $(ADDMOD) ccfonts_ -font $(ccfonts8)
+ $(ADDMOD) ccfonts_ -font $(ccfonts9)
+ $(ADDMOD) ccfonts_ -font $(ccfonts10)
+ $(ADDMOD) ccfonts_ -font $(ccfonts11)
+ $(ADDMOD) ccfonts_ -font $(ccfonts12)
+ $(ADDMOD) ccfonts_ -font $(ccfonts13)
+ $(ADDMOD) ccfonts_ -font $(ccfonts14)
+ $(ADDMOD) ccfonts_ -font $(ccfonts15)
+ $(EXP)genconf ccfonts_.dev -n gs -f $(gconfigf_h)
+
+# We separate icfontab.dev from ccfonts.dev so that a customer can put
+# compiled fonts into a separate shared library.
+
+icfontab=icfontab$(CONFIG)
+
+# Define ccfont_table separately, so it can be set from the command line
+# to select an alternate compiled font table.
+ccfont_table=$(icfontab)
+
+$(icfontab).dev: $(MAKEFILE) $(INT_MAK) $(ECHOGS_XE) $(icfontab).$(OBJ) \
+ $(ccfonts1_) $(ccfonts2_) $(ccfonts3_) $(ccfonts4_) $(ccfonts5_) \
+ $(ccfonts6_) $(ccfonts7_) $(ccfonts8_) $(ccfonts9_) $(ccfonts10_) \
+ $(ccfonts11_) $(ccfonts12_) $(ccfonts13_) $(ccfonts14_) $(ccfonts15_)
+ $(SETMOD) $(icfontab) -obj $(icfontab).$(OBJ)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts1_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts2_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts3_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts4_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts5_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts6_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts7_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts8_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts9_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts10_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts11_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts12_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts13_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts14_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts15_)
+
+$(icfontab).$(OBJ): icfontab.c $(AK) $(ccfont_h) $(gconfigf_h)
+ $(CP_) $(gconfigf_h) gconfigf.h
+ $(CCCF) icfontab.c
+
+# Strictly speaking, ccfonts shouldn't need to include type1,
+# since one could choose to precompile only Type 0 fonts,
+# but getting this exactly right would be too much work.
+ccfonts=ccfonts$(CONFIG)
+$(ccfonts).dev: $(MAKEFILE) $(INT_MAK) type1.dev iccfont.$(OBJ) \
+ $(ccfont_table).dev
+ $(SETMOD) $(ccfonts) -include type1
+ $(ADDMOD) $(ccfonts) -include $(ccfont_table)
+ $(ADDMOD) $(ccfonts) -obj iccfont.$(OBJ)
+ $(ADDMOD) $(ccfonts) -oper ccfonts
+ $(ADDMOD) $(ccfonts) -ps $(ccfonts_ps)
+
+iccfont.$(OBJ): iccfont.c $(GH) $(string__h)\
+ $(gsstruct_h) $(ccfont_h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(ifont_h) $(iname_h) $(isave_h) $(iutil_h)\
+ $(oper_h) $(ostack_h) $(store_h) $(stream_h) $(strimpl_h) $(sfilter_h) $(iscan_h)
+ $(CCCF) iccfont.c
+
+# ---------------- Compiled initialization code ---------------- #
+
+# We select either iccinit0 or iccinit1 depending on COMPILE_INITS.
+
+iccinit0.$(OBJ): iccinit0.c $(stdpre_h)
+ $(CCCF) iccinit0.c
+
+iccinit1.$(OBJ): gs_init.$(OBJ)
+ $(CP_) gs_init.$(OBJ) iccinit1.$(OBJ)
+
+# All the gs_*.ps files should be prerequisites of gs_init.c,
+# but we don't have any convenient list of them.
+gs_init.c: $(GS_INIT) $(GENINIT_XE) $(gconfig_h)
+ $(EXP)geninit $(GS_INIT) $(gconfig_h) -c gs_init.c
+
+gs_init.$(OBJ): gs_init.c $(stdpre_h)
+ $(CCCF) gs_init.c
+
+# ======================== PostScript Level 2 ======================== #
+
+level2.dev: $(INT_MAK) $(ECHOGS_XE) \
+ cidfont.dev cie.dev cmapread.dev compfont.dev dct.dev devctrl.dev dpsand2.dev\
+ filter.dev level1.dev pattern.dev psl2lib.dev psl2read.dev sepr.dev\
+ type42.dev xfilter.dev
+ $(SETMOD) level2 -include cidfont cie cmapread compfont
+ $(ADDMOD) level2 -include dct devctrl dpsand2 filter
+ $(ADDMOD) level2 -include level1 pattern psl2lib psl2read
+ $(ADDMOD) level2 -include sepr type42 xfilter
+ $(ADDMOD) level2 -emulator PostScript PostScriptLevel2
+
+# Define basic Level 2 language support.
+# This is the minimum required for CMap and CIDFont support.
+
+psl2int_=iutil2.$(OBJ) zmisc2.$(OBJ) zusparam.$(OBJ)
+psl2int.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2int_) dps2int.dev
+ $(SETMOD) psl2int $(psl2int_)
+ $(ADDMOD) psl2int -include dps2int
+ $(ADDMOD) psl2int -oper zmisc2 zusparam
+ $(ADDMOD) psl2int -ps gs_lev2 gs_res
+
+iutil2.$(OBJ): iutil2.c $(GH) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsutil_h)\
+ $(errors_h) $(opcheck_h) $(imemory_h) $(iutil_h) $(iutil2_h)
+
+zmisc2.$(OBJ): zmisc2.c $(OP) $(memory__h) $(string__h)\
+ $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(ilevel_h) $(iname_h) $(iutil2_h) $(ivmspace_h) $(store_h)
+
+# Note that zusparam includes both Level 1 and Level 2 operators.
+zusparam.$(OBJ): zusparam.c $(OP) $(memory__h) $(string__h)\
+ $(gscdefs_h) $(gsfont_h) $(gsstruct_h) $(gsutil_h) $(gxht_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(iname_h) $(iutil2_h) $(store_h)
+
+# Define full Level 2 support.
+
+psl2read_=zcolor2.$(OBJ) zcsindex.$(OBJ) zht2.$(OBJ) zimage2.$(OBJ)
+# Note that zmisc2 includes both Level 1 and Level 2 operators.
+psl2read.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2read_) psl2int.dev dps2read.dev
+ $(SETMOD) psl2read $(psl2read_)
+ $(ADDMOD) psl2read -include psl2int dps2read
+ $(ADDMOD) psl2read -oper zcolor2_l2 zcsindex_l2
+ $(ADDMOD) psl2read -oper zht2_l2 zimage2_l2
+
+zcolor2.$(OBJ): zcolor2.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+zcsindex.$(OBJ): zcsindex.c $(OP) $(memory__h) \
+ $(gscolor_h) $(gsstruct_h) $(gxfixed_h) $(gxcolor2_h) $(gxcspace_h) $(gsmatrix_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zht2.$(OBJ): zht2.c $(OP) \
+ $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(estack_h) $(ialloc_h) $(icolor_h) $(idict_h) $(idparam_h) $(igstate_h) \
+ $(iht_h) $(store_h)
+
+zimage2.$(OBJ): zimage2.c $(OP) $(math__h) $(memory__h)\
+ $(gscolor_h) $(gscolor2_h) $(gscspace_h) $(gsimage_h) $(gsmatrix_h)\
+ $(idict_h) $(idparam_h) $(iimage_h) $(ilevel_h) $(igstate_h)
+
+# ---------------- Device control ---------------- #
+# This is a catch-all for setpagedevice and IODevices.
+
+devctrl_=zdevice2.$(OBJ) ziodev2.$(OBJ) zmedia2.$(OBJ) zdevcal.$(OBJ)
+devctrl.dev: $(INT_MAK) $(ECHOGS_XE) $(devctrl_)
+ $(SETMOD) devctrl $(devctrl_)
+ $(ADDMOD) devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+ $(ADDMOD) devctrl -iodev null ram calendar
+ $(ADDMOD) devctrl -ps gs_setpd
+
+zdevice2.$(OBJ): zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(store_h)\
+ $(gxdevice_h) $(gsstate_h)
+
+ziodev2.$(OBJ): ziodev2.c $(OP) $(string__h) $(gp_h)\
+ $(gxiodev_h) $(stream_h) $(files_h) $(iparam_h) $(iutil2_h) $(store_h)
+
+zmedia2.$(OBJ): zmedia2.c $(OP) $(math__h) $(memory__h) \
+ $(gsmatrix_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+
+zdevcal.$(OBJ): zdevcal.c $(GH) $(time__h) \
+ $(gxiodev_h) $(iparam_h) $(istack_h)
+
+# ---------------- Filters other than the ones in sfilter.c ---------------- #
+
+# Standard Level 2 decoding filters only. The PDF configuration uses this.
+fdecode_=scantab.$(OBJ) sfilter2.$(OBJ) zfdecode.$(OBJ)
+fdecode.dev: $(INT_MAK) $(ECHOGS_XE) $(fdecode_) cfd.dev lzwd.dev pdiff.dev pngp.dev rld.dev
+ $(SETMOD) fdecode $(fdecode_)
+ $(ADDMOD) fdecode -include cfd lzwd pdiff pngp rld
+ $(ADDMOD) fdecode -oper zfdecode
+
+zfdecode.$(OBJ): zfdecode.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sa85x_h) $(scf_h) $(scfx_h) $(sfilter_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) \
+ $(store_h) $(stream_h) $(strimpl_h)
+
+# Complete Level 2 filter capability.
+filter_=zfilter2.$(OBJ)
+filter.dev: $(INT_MAK) $(ECHOGS_XE) fdecode.dev $(filter_) cfe.dev lzwe.dev rle.dev
+ $(SETMOD) filter -include fdecode
+ $(ADDMOD) filter -obj $(filter_)
+ $(ADDMOD) filter -include cfe lzwe rle
+ $(ADDMOD) filter -oper zfilter2
+
+zfilter2.$(OBJ): zfilter2.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(store_h) \
+ $(sfilter_h) $(scfx_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) $(strimpl_h)
+
+# Extensions beyond Level 2 standard.
+xfilter_=sbhc.$(OBJ) sbwbs.$(OBJ) shcgen.$(OBJ) smtf.$(OBJ) \
+ zfilterx.$(OBJ)
+xfilter.dev: $(INT_MAK) $(ECHOGS_XE) $(xfilter_) pcxd.dev pngp.dev
+ $(SETMOD) xfilter $(xfilter_)
+ $(ADDMOD) xfilter -include pcxd
+ $(ADDMOD) xfilter -oper zfilterx
+
+sbhc.$(OBJ): sbhc.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(sbhc_h) $(shcgen_h) $(strimpl_h)
+
+sbwbs.$(OBJ): sbwbs.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(sbwbs_h) $(sfilter_h) $(strimpl_h)
+
+shcgen.$(OBJ): shcgen.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gserror_h) $(gserrors_h) $(gsmemory_h)\
+ $(scommon_h) $(shc_h) $(shcgen_h)
+
+smtf.$(OBJ): smtf.c $(AK) $(stdio__h) \
+ $(smtf_h) $(strimpl_h)
+
+zfilterx.$(OBJ): zfilterx.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(store_h) $(sfilter_h) $(sbhc_h) $(sbtx_h) $(sbwbs_h) $(shcgen_h)\
+ $(smtf_h) $(spcxx_h) $(strimpl_h)
+
+# ---------------- Binary tokens ---------------- #
+
+btoken_=iscanbin.$(OBJ) zbseq.$(OBJ)
+btoken.dev: $(INT_MAK) $(ECHOGS_XE) $(btoken_)
+ $(SETMOD) btoken $(btoken_)
+ $(ADDMOD) btoken -oper zbseq_l2
+ $(ADDMOD) btoken -ps gs_btokn
+
+bseq_h=bseq.h
+btoken_h=btoken.h
+
+iscanbin.$(OBJ): iscanbin.c $(GH) $(math__h) $(memory__h) $(errors_h)\
+ $(gsutil_h) $(ialloc_h) $(ibnum_h) $(idict_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(ivmspace_h)\
+ $(bseq_h) $(btoken_h) $(dstack_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zbseq.$(OBJ): zbseq.c $(OP) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(isave_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)\
+ $(iname_h) $(ibnum_h) $(btoken_h) $(bseq_h)
+
+# ---------------- User paths & insideness testing ---------------- #
+
+upath_=zupath.$(OBJ) ibnum.$(OBJ)
+upath.dev: $(INT_MAK) $(ECHOGS_XE) $(upath_)
+ $(SETMOD) upath $(upath_)
+ $(ADDMOD) upath -oper zupath_l2
+
+zupath.$(OBJ): zupath.c $(OP) \
+ $(idict_h) $(dstack_h) $(iutil_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h) \
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstate_h) \
+ $(gxfixed_h) $(gxdevice_h) $(gzpath_h) $(gzstate_h)
+
+# -------- Additions common to Display PostScript and Level 2 -------- #
+
+dpsand2.dev: $(INT_MAK) $(ECHOGS_XE) btoken.dev color.dev upath.dev dps2lib.dev dps2read.dev
+ $(SETMOD) dpsand2 -include btoken color upath dps2lib dps2read
+
+dps2int_=zvmem2.$(OBJ) zdps1.$(OBJ)
+# Note that zvmem2 includes both Level 1 and Level 2 operators.
+dps2int.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2int_)
+ $(SETMOD) dps2int $(dps2int_)
+ $(ADDMOD) dps2int -oper zvmem2 zdps1_l2
+ $(ADDMOD) dps2int -ps gs_dps1
+
+dps2read_=ibnum.$(OBJ) zchar2.$(OBJ)
+dps2read.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2read_) dps2int.dev
+ $(SETMOD) dps2read $(dps2read_)
+ $(ADDMOD) dps2read -include dps2int
+ $(ADDMOD) dps2read -oper ireclaim_l2 zchar2_l2
+ $(ADDMOD) dps2read -ps gs_dps2
+
+ibnum.$(OBJ): ibnum.c $(GH) $(math__h) $(memory__h)\
+ $(errors_h) $(stream_h) $(ibnum_h) $(imemory_h) $(iutil_h)
+
+zchar2.$(OBJ): zchar2.c $(OP)\
+ $(gschar_h) $(gsmatrix_h) $(gspath_h) $(gsstruct_h)\
+ $(gxchar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(ichar_h) $(estack_h) $(ifont_h) $(iname_h) $(igstate_h)\
+ $(store_h) $(stream_h) $(ibnum_h)
+
+zdps1.$(OBJ): zdps1.c $(OP) \
+ $(gsmatrix_h) $(gspath_h) $(gspath2_h) $(gsstate_h) \
+ $(ialloc_h) $(ivmspace_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h)
+
+zvmem2.$(OBJ): zvmem2.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Display PostScript ---------------- #
+
+dps_=zdps.$(OBJ) icontext.$(OBJ) zcontext.$(OBJ)
+dps.dev: $(INT_MAK) $(ECHOGS_XE) dpslib.dev level2.dev $(dps_)
+ $(SETMOD) dps -include dpslib level2
+ $(ADDMOD) dps -obj $(dps_)
+ $(ADDMOD) dps -oper zcontext zdps
+ $(ADDMOD) dps -ps gs_dps
+
+icontext.$(OBJ): icontext.c $(GH)\
+ $(gsstruct_h) $(gxalloc_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(ostack_h)\
+ $(icontext_h) $(igstate_h) $(interp_h) $(store_h)
+
+zdps.$(OBJ): zdps.c $(OP)\
+ $(gsdps_h) $(gsstate_h) $(igstate_h) $(iname_h) $(store_h)
+
+zcontext.$(OBJ): zcontext.c $(OP) $(gp_h) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h) $(gsutil_h) $(gxalloc_h)\
+ $(icontext_h) $(idict_h) $(igstate_h) $(istruct_h)\
+ $(dstack_h) $(estack_h) $(ostack_h) $(store_h)
+
+# The following #ifdef ... #endif are just a comment to mark a DPNEXT area.
+#ifdef DPNEXT
+
+# ---------------- NeXT Display PostScript ---------------- #
+#**************** NOT READY FOR USE YET ****************#
+
+# There should be a gsdpnext.c, but there isn't yet.
+#dpsnext_=zdpnext.$(OBJ) gsdpnext.$(OBJ)
+dpsnext_=zdpnext.$(OBJ)
+dpsnext.dev: $(INT_MAK) $(ECHOGS_XE) dps.dev $(dpsnext_) gs_dpnxt.ps
+ $(SETMOD) dpsnext -include dps
+ $(ADDMOD) dpsnext -obj $(dpsnext_)
+ $(ADDMOD) dpsnext -oper zdpnext
+ $(ADDMOD) dpsnext -ps gs_dpnxt
+
+zdpnext.$(OBJ): zdpnext.c $(OP)\
+ $(gscspace_h) $(gsiparam_h) $(gsmatrix_h) $(gxcvalue_h) $(gxsample_h)\
+ $(ialloc_h) $(igstate_h) $(iimage_h)
+
+# See above re the following.
+#endif /* DPNEXT */
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+compfont.dev: $(INT_MAK) $(ECHOGS_XE) psf0lib.dev psf0read.dev
+ $(SETMOD) compfont -include psf0lib psf0read
+
+# We always include zfcmap.$(OBJ) because zfont0.c refers to it,
+# and it's not worth the trouble to exclude.
+psf0read_=zchar2.$(OBJ) zfcmap.$(OBJ) zfont0.$(OBJ)
+psf0read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf0read_)
+ $(SETMOD) psf0read $(psf0read_)
+ $(ADDMOD) psf0read -oper zfont0 zchar2 zfcmap
+
+zfcmap.$(OBJ): zfcmap.c $(OP)\
+ $(gsmatrix_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxfcmap_h) $(gxfont_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifont_h) $(iname_h) $(store_h)
+
+zfont0.$(OBJ): zfont0.c $(OP)\
+ $(gschar_h) $(gsstruct_h)\
+ $(gxdevice_h) $(gxfcmap_h) $(gxfixed_h) $(gxfont_h) $(gxfont0_h) $(gxmatrix_h)\
+ $(gzstate_h)\
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h)\
+ $(store_h)
+
+# ---------------- CMap support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cmapread_=zfcmap.$(OBJ)
+cmapread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmapread_) cmaplib.dev psl2int.dev
+ $(SETMOD) cmapread $(cmapread_)
+ $(ADDMOD) cmapread -include cmaplib psl2int
+ $(ADDMOD) cmapread -oper zfcmap
+ $(ADDMOD) cmapread -ps gs_cmap
+
+# ---------------- CIDFont support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cidread_=zcid.$(OBJ)
+cidfont.dev: $(INT_MAK) $(ECHOGS_XE) psf1read.dev psl2int.dev type42.dev\
+ $(cidread_)
+ $(SETMOD) cidfont $(cidread_)
+ $(ADDMOD) cidfont -include psf1read psl2int type42
+ $(ADDMOD) cidfont -ps gs_cidfn
+ $(ADDMOD) cidfont -oper zcid
+
+zcid.$(OBJ): zcid.c $(OP)\
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h)\
+ $(bfont_h) $(iname_h) $(store_h)
+
+# ---------------- CIE color ---------------- #
+
+cieread_=zcie.$(OBJ) zcrd.$(OBJ)
+cie.dev: $(INT_MAK) $(ECHOGS_XE) $(cieread_) cielib.dev
+ $(SETMOD) cie $(cieread_)
+ $(ADDMOD) cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) cie -include cielib
+
+icie_h=icie.h
+
+zcie.$(OBJ): zcie.c $(OP) $(math__h) $(memory__h) \
+ $(gscolor2_h) $(gscie_h) $(gsstruct_h) $(gxcspace_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zcrd.$(OBJ): zcrd.c $(OP) $(math__h) \
+ $(gscspace_h) $(gscolor2_h) $(gscie_h) $(gsstruct_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Pattern color ---------------- #
+
+pattern.dev: $(INT_MAK) $(ECHOGS_XE) patlib.dev patread.dev
+ $(SETMOD) pattern -include patlib patread
+
+patread_=zpcolor.$(OBJ)
+patread.dev: $(INT_MAK) $(ECHOGS_XE) $(patread_)
+ $(SETMOD) patread $(patread_)
+ $(ADDMOD) patread -oper zpcolor_l2
+
+zpcolor.$(OBJ): zpcolor.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+# ---------------- Separation color ---------------- #
+
+seprread_=zcssepr.$(OBJ)
+sepr.dev: $(INT_MAK) $(ECHOGS_XE) $(seprread_) seprlib.dev
+ $(SETMOD) sepr $(seprread_)
+ $(ADDMOD) sepr -oper zcssepr_l2
+ $(ADDMOD) sepr -include seprlib
+
+zcssepr.$(OBJ): zcssepr.c $(OP) \
+ $(gscolor_h) $(gscsepr_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Functions ---------------- #
+
+ifunc_h=ifunc.h
+
+# Generic support, and FunctionType 0.
+funcread_=zfunc.$(OBJ) zfunc0.$(OBJ)
+func.dev: $(INT_MAK) $(ECHOGS_XE) $(funcread_) funclib.dev
+ $(SETMOD) func $(funcread_)
+ $(ADDMOD) func -oper zfunc zfunc0
+ $(ADDMOD) func -include funclib
+
+zfunc.$(OBJ): zfunc.c $(OP) $(memory__h)\
+ $(gsfunc_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h) $(store_h)
+
+zfunc0.$(OBJ): zfunc0.c $(OP) $(memory__h)\
+ $(gsdsrc_h) $(gsfunc_h) $(gsfunc0_h)\
+ $(stream_h)\
+ $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)
+
+# ---------------- DCT filters ---------------- #
+# The definitions for jpeg*.dev are in jpeg.mak.
+
+dct.dev: $(INT_MAK) $(ECHOGS_XE) dcte.dev dctd.dev
+ $(SETMOD) dct -include dcte dctd
+
+# Common code
+
+dctc_=zfdctc.$(OBJ)
+
+zfdctc.$(OBJ): zfdctc.c $(GH) $(memory__h) $(stdio__h)\
+ $(errors_h) $(opcheck_h)\
+ $(idict_h) $(idparam_h) $(imemory_h) $(ipacked_h) $(iutil_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h)\
+ jpeglib.h
+
+# Encoding (compression)
+
+dcte_=$(dctc_) zfdcte.$(OBJ)
+dcte.dev: $(INT_MAK) $(ECHOGS_XE) sdcte.dev $(dcte_)
+ $(SETMOD) dcte -include sdcte
+ $(ADDMOD) dcte -obj $(dcte_)
+ $(ADDMOD) dcte -oper zfdcte
+
+zfdcte.$(OBJ): zfdcte.c $(OP) $(memory__h) $(stdio__h)\
+ $(idict_h) $(idparam_h) $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# Decoding (decompression)
+
+dctd_=$(dctc_) zfdctd.$(OBJ)
+dctd.dev: $(INT_MAK) $(ECHOGS_XE) sdctd.dev $(dctd_)
+ $(SETMOD) dctd -include sdctd
+ $(ADDMOD) dctd -obj $(dctd_)
+ $(ADDMOD) dctd -oper zfdctd
+
+zfdctd.$(OBJ): zfdctd.c $(OP) $(memory__h) $(stdio__h)\
+ $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# ---------------- zlib/Flate filters ---------------- #
+
+fzlib.dev: $(INT_MAK) $(ECHOGS_XE) zfzlib.$(OBJ) szlibe.dev szlibd.dev
+ $(SETMOD) fzlib -include szlibe szlibd
+ $(ADDMOD) fzlib -obj zfzlib.$(OBJ)
+ $(ADDMOD) fzlib -oper zfzlib
+
+zfzlib.$(OBJ): zfzlib.c $(OP) \
+ $(errors_h) $(idict_h) $(ifilter_h) \
+ $(spdiffx_h) $(spngpx_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) zfzlib.c
+
+# ================================ PDF ================================ #
+
+# We need most of the Level 2 interpreter to do PDF, but not all of it.
+# In fact, we don't even need all of a Level 1 interpreter.
+
+# Because of the way the PDF encodings are defined, they must get loaded
+# before we install the Level 2 resource machinery.
+# On the other hand, the PDF .ps files must get loaded after
+# level2dict is defined.
+pdfmin.dev: $(INT_MAK) $(ECHOGS_XE)\
+ psbase.dev color.dev dps2lib.dev dps2read.dev\
+ fdecode.dev type1.dev pdffonts.dev psl2lib.dev psl2read.dev pdfread.dev
+ $(SETMOD) pdfmin -include psbase color dps2lib dps2read
+ $(ADDMOD) pdfmin -include fdecode type1
+ $(ADDMOD) pdfmin -include pdffonts psl2lib psl2read pdfread
+ $(ADDMOD) pdfmin -emulator PDF
+
+pdf.dev: $(INT_MAK) $(ECHOGS_XE)\
+ pdfmin.dev cff.dev cidfont.dev cie.dev compfont.dev cmapread.dev dctd.dev\
+ func.dev ttfont.dev type2.dev
+ $(SETMOD) pdf -include pdfmin cff cidfont cie cmapread compfont dctd
+ $(ADDMOD) pdf -include func ttfont type2
+
+# Reader only
+
+pdffonts.dev: $(INT_MAK) $(ECHOGS_XE) \
+ gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps
+ $(SETMOD) pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+
+# pdf_2ps must be the last .ps file loaded.
+pdfread.dev: $(INT_MAK) $(ECHOGS_XE) fzlib.dev
+ $(SETMOD) pdfread -include fzlib
+ $(ADDMOD) pdfread -ps gs_pdf gs_l2img
+ $(ADDMOD) pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+ $(ADDMOD) pdfread -ps pdf_2ps
+
+# ============================= Main program ============================== #
+
+gs.$(OBJ): gs.c $(GH) \
+ $(imain_h) $(imainarg_h) $(iminst_h)
+
+imainarg.$(OBJ): imainarg.c $(GH) $(ctype__h) $(memory__h) $(string__h) \
+ $(gp_h) \
+ $(gsargs_h) $(gscdefs_h) $(gsdevice_h) $(gsmdebug_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(errors_h) $(estack_h) $(files_h) \
+ $(ialloc_h) $(imain_h) $(imainarg_h) $(iminst_h) \
+ $(iname_h) $(interp_h) $(iscan_h) $(iutil_h) $(ivmspace_h) \
+ $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+imain.$(OBJ): imain.c $(GH) $(memory__h) $(string__h)\
+ $(gp_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h) $(gxdevice_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(interp_h)\
+ $(isave_h) $(iscan_h) $(ivmspace_h)\
+ $(main_h) $(oper_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+interp.$(OBJ): interp.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(iastruct_h) $(inamedef_h) $(idict_h) $(interp_h) $(ipacked_h)\
+ $(iscan_h) $(isave_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(oper_h) $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(CCINT) interp.c
+
+ireclaim.$(OBJ): ireclaim.c $(GH) \
+ $(errors_h) $(gsstruct_h) $(iastate_h) $(opdef_h) $(store_h) \
+ $(dstack_h) $(estack_h) $(ostack_h)
diff --git a/gs/src/interp.c b/gs/src/interp.c
new file mode 100644
index 000000000..7b39433dc
--- /dev/null
+++ b/gs/src/interp.c
@@ -0,0 +1,1565 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* interp.c */
+/* Ghostscript language interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gsstruct.h" /* for iastruct.h */
+#include "stream.h"
+#include "errors.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "iastruct.h"
+#include "inamedef.h"
+#include "interp.h"
+#include "ipacked.h"
+#include "ostack.h" /* must precede iscan.h */
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+#include "idict.h"
+#include "isave.h"
+#include "istack.h"
+#include "iutil.h" /* for array_get */
+#include "ivmspace.h"
+#include "dstack.h"
+#include "files.h" /* for file_check_read */
+#include "oper.h"
+#include "store.h"
+
+/*
+ * We may or may not optimize the handling of the special fast operators
+ * in packed arrays. If we do this, they run much faster when packed, but
+ * slightly slower when not packed.
+ */
+#define PACKED_SPECIAL_OPS 1
+
+/*
+ * Pseudo-operators (procedures of type t_oparray) record
+ * the operand and dictionary stack pointers, and restore them if an error
+ * occurs during the execution of the procedure and if the procedure hasn't
+ * (net) decreased the depth of the stack. While this obviously doesn't
+ * do all the work of restoring the state if a pseudo-operator gets an
+ * error, it's a big help. The only downside is that pseudo-operators run
+ * a little slower.
+ */
+
+/* Imported operator procedures */
+extern int zop_add(P1(os_ptr));
+extern int zop_def(P1(os_ptr));
+extern int zop_sub(P1(os_ptr));
+/* Other imported procedures */
+extern int ztokenexec_continue(P1(os_ptr));
+
+/*
+ * The procedure to call if an operator requests rescheduling.
+ * This causes an error unless the context machinery has been installed.
+ */
+private int
+no_reschedule(void)
+{ return_error(e_invalidcontext);
+}
+int (*gs_interp_reschedule_proc)(P0()) = no_reschedule;
+/*
+ * The procedure to call for time-slicing.
+ * This is a no-op unless the context machinery has been installed.
+ */
+int
+no_time_slice_proc(void)
+{ return 0;
+}
+int (*gs_interp_time_slice_proc)(P0()) = no_time_slice_proc;
+/*
+ * The number of interpreter "ticks" between calls on the time_slice_proc.
+ * Currently, the clock ticks before each operator, and at each
+ * procedure return.
+ */
+int gs_interp_time_slice_ticks = 0x7fff;
+
+/*
+ * Apply an operator. We route all operator calls through a procedure when
+ * debugging.
+ */
+#ifdef DEBUG
+private int
+call_operator(int (*op_proc)(P1(os_ptr)), os_ptr op)
+{ int code = (*op_proc)(op);
+ return code;
+}
+#else
+# define call_operator(proc, op) ((*(proc))(op))
+#endif
+
+/* Forward references */
+private int estack_underflow(P1(os_ptr));
+private int interp(P2(ref *, ref *));
+private int interp_exit(P1(os_ptr));
+private void set_gc_signal(P2(int *, int));
+private int copy_stack(P2(const ref_stack *, ref *));
+private int oparray_pop(P1(os_ptr));
+private int oparray_cleanup(P1(os_ptr));
+
+/* Stack sizes */
+
+/* The maximum stack sizes may all be set in the makefile. */
+
+/*
+ * Define the initial maximum size of the operand stack (MaxOpStack
+ * user parameter). Currently this is also the block size for extending
+ * the operand stack, but this isn't guaranteed in the future.
+ */
+#ifndef MAX_OSTACK
+# define MAX_OSTACK 800
+#endif
+/*
+ * The minimum block size for extending the operand stack is the larger of:
+ * - the maximum number of parameters to an operator
+ * (currently setcolorscreen, with 12 parameters);
+ * - the maximum number of values pushed by an operator
+ * (currently setcolortransfer, which calls zcolor_remap_one 4 times
+ * and therefore pushes 16 values).
+ */
+#define min_block_ostack 16
+const int gs_interp_max_op_num_args = min_block_ostack; /* for iinit.c */
+
+/*
+ * Define the initial maximum size of the execution stack (MaxExecStack
+ * user parameter).
+ */
+#ifndef MAX_ESTACK
+# define MAX_ESTACK 250
+#endif
+/*
+ * The minimum block size for extending the execution stack is the largest
+ * size of a contiguous block surrounding an e-stack mark, currently ???.
+ * At least, that's what the minimum value would be if we supported
+ * multi-block estacks, which we currently don't.
+ */
+#define min_block_estack MAX_ESTACK
+
+/*
+ * Define the initial maximum size of the dictionary stack (MaxDictStack
+ * user parameter). Again, this is also currently the block size for
+ * extending the d-stack.
+ */
+#ifndef MAX_DSTACK
+# define MAX_DSTACK 20
+#endif
+/*
+ * The minimum block size for extending the dictionary stack is the number
+ * of permanent entries on the dictionary stack, currently 3.
+ */
+#define min_block_dstack 3
+uint min_dstack_size; /* set by iinit.c */
+
+/* Interpreter state variables */
+ref ref_systemdict; /* set by iinit.c */
+ref ref_language_level; /* 1 or 2, set by iinit.c */
+
+/* See estack.h for a description of the execution stack. */
+
+/* The logic for managing icount and iref below assumes that */
+/* there are no control operators which pop and then push */
+/* information on the execution stack. */
+
+/* Stacks */
+/*
+ * We must create the stacks as legitimate 'objects' for the memory
+ * manager, so that the garbage collector can work with them.
+ */
+#define os_guard_under 10
+#define os_guard_over 10
+#define os_refs_size(body_size)\
+ (stack_block_refs + os_guard_under + (body_size) + os_guard_over)
+ref_stack o_stack;
+#define es_guard_under 1
+#define es_guard_over 10
+#define es_refs_size(body_size)\
+ (stack_block_refs + es_guard_under + (body_size) + es_guard_over)
+ref_stack e_stack;
+#define ds_refs_size(body_size)\
+ (stack_block_refs + (body_size))
+ref_stack d_stack;
+
+/* Allocate the top blocks statically iff we are dealing with */
+/* a segmented architecture where this is important. */
+#if stacks_are_segmented
+private struct stk_ {
+ chunk_head_t head;
+ obj_header_t prefix;
+ ref bodies[os_refs_size(MAX_OSTACK) +
+ es_refs_size(MAX_ESTACK) +
+ ds_refs_size(MAX_DSTACK)];
+ ref padding; /* for GC */
+} static_stacks;
+#endif
+extern_st(st_ref_stack);
+ref ref_static_stacks; /* exported for GC */
+ref ref_ref_stacks[3]; /* exported for GC */
+
+/* Stack pointers */
+ref *esfile; /* cache pointer to currentfile */
+/* Cached dstack values are in idict.c. */
+
+/* Extended types. The interpreter may replace the type of operators */
+/* in procedures with these, to speed up the interpretation loop. */
+/****** NOTE: If you add or change entries in this list, */
+/****** you must change the three dispatches in the interpreter loop. */
+/* The operator procedures are declared in opextern.h. */
+#define tx_op t_next_index
+private const op_proc_p special_ops[] = {
+ zadd, zdef, zdup, zexch, zif, zifelse, zindex, zpop, zroll, zsub
+};
+typedef enum {
+ tx_op_add = tx_op,
+ tx_op_def,
+ tx_op_dup,
+ tx_op_exch,
+ tx_op_if,
+ tx_op_ifelse,
+ tx_op_index,
+ tx_op_pop,
+ tx_op_roll,
+ tx_op_sub,
+ tx_next_op
+} special_op_types;
+#define num_special_ops ((int)tx_next_op - tx_op)
+const int gs_interp_num_special_ops = num_special_ops; /* for iinit.c */
+const int tx_next_index = tx_next_op;
+
+/* A null procedure. */
+#define make_null_proc(pref)\
+ make_empty_const_array(pref, a_executable + a_readonly)
+static ref null_proc;
+
+/* Initialize the interpreter */
+#ifndef DPNEXT
+void
+gs_interp_init(void)
+{ /* Initialize the stacks. */
+ gs_ref_memory_t *smem = iimemory_system;
+ ref stk;
+ ref euop;
+ ref *next_body;
+ uint refs_size_ostack, refs_size_estack, refs_size_dstack;
+
+ if ( gs_debug_c('+') )
+ refs_size_ostack = os_refs_size(min_block_ostack),
+ refs_size_estack = es_refs_size(min_block_estack),
+ refs_size_dstack = ds_refs_size(min_block_dstack);
+ else
+ refs_size_ostack = os_refs_size(MAX_OSTACK),
+ refs_size_estack = es_refs_size(MAX_ESTACK),
+ refs_size_dstack = ds_refs_size(MAX_DSTACK);
+#if stacks_are_segmented
+ next_body = static_stacks.bodies;
+ make_array(&ref_static_stacks, avm_system,
+ countof(static_stacks.bodies), next_body);
+ refset_null(next_body, countof(static_stacks.bodies));
+#else
+ make_empty_array(&ref_static_stacks, 0);
+ { ref sdata;
+ gs_alloc_ref_array(smem, &sdata, 0,
+ refs_size_ostack + refs_size_estack +
+ refs_size_dstack, "interp_init");
+ next_body = sdata.value.refs;
+ }
+#endif
+#define alloc_init_stack(stk, i, n)\
+ make_array(&stk, avm_system, n, next_body),\
+ next_body += (n),\
+ make_struct(&ref_ref_stacks[i], avm_system,\
+ gs_alloc_struct((gs_memory_t *)smem, ref_stack, &st_ref_stack,\
+ "alloc_init_stack"))
+
+ alloc_init_stack(stk, 0, refs_size_ostack);
+ ref_stack_init(&o_stack, &stk, os_guard_under, os_guard_over, NULL,
+ smem);
+ o_stack.underflow_error = e_stackunderflow;
+ o_stack.overflow_error = e_stackoverflow;
+ ref_stack_set_max_count(&o_stack, MAX_OSTACK);
+
+ alloc_init_stack(stk, 1, refs_size_estack);
+ make_oper(&euop, 0, estack_underflow);
+ ref_stack_init(&e_stack, &stk, es_guard_under, es_guard_over, &euop,
+ smem);
+ e_stack.underflow_error = e_ExecStackUnderflow;
+ e_stack.overflow_error = e_execstackoverflow;
+ /**************** E-STACK EXPANSION IS NYI. ****************/
+ e_stack.allow_expansion = false;
+ esfile_clear_cache();
+ ref_stack_set_max_count(&e_stack, MAX_ESTACK);
+
+ alloc_init_stack(stk, 2, refs_size_dstack);
+ ref_stack_init(&d_stack, &stk, 0, 0, NULL, smem);
+ d_stack.underflow_error = e_dictstackunderflow;
+ d_stack.overflow_error = e_dictstackoverflow;
+ ref_stack_set_max_count(&d_stack, MAX_DSTACK);
+}
+#else /* DPNEXT */
+void
+gs_interp_init(void)
+{ /* Initialize the stacks. */
+ gs_ref_memory_t *smem = iimemory_system;
+ int code =
+ gs_interp_create_stacks(smem, &ref_ref_stacks[0],
+ &ref_ref_stacks[1], &ref_ref_stacks[2]);
+ /****** FATAL ERROR IF code < 0 ******/
+
+ d_stack = *r_ptr(&ref_ref_stacks[0], ref_stack);
+ e_stack = *r_ptr(&ref_ref_stacks[1], ref_stack);
+ o_stack = *r_ptr(&ref_ref_stacks[2], ref_stack);
+ esfile_clear_cache();
+}
+int
+gs_interp_create_stacks(gs_ref_memory_t *smem, ref *prds, ref *pres,
+ ref *pros)
+{ ref sdata, stk;
+
+#define refs_size_ostack os_refs_size(MAX_OSTACK)
+#define refs_size_estack es_refs_size(MAX_ESTACK)
+#define refs_size_dstack ds_refs_size(MAX_DSTACK)
+ gs_alloc_ref_array(smem, &sdata, 0,
+ refs_size_ostack + refs_size_estack +
+ refs_size_dstack, "gs_interp_create_stacks");
+
+
+ make_struct(pros, avm_system,
+ gs_alloc_struct((gs_memory_t *)smem, ref_stack,
+ &st_ref_stack,
+ "gs_interp_create_stacks(ostack)"));
+ make_array(&stk, avm_system, refs_size_ostack, sdata.value.refs);
+ { ref_stack *pos = r_ptr(pros, ref_stack);
+ ref_stack_init(pos, &stk, os_guard_under, os_guard_over, NULL,
+ smem);
+ pos->underflow_error = e_stackunderflow;
+ pos->overflow_error = e_stackoverflow;
+ ref_stack_set_max_count(pos, MAX_OSTACK);
+ }
+
+ make_struct(pres, avm_system,
+ gs_alloc_struct((gs_memory_t *)smem, ref_stack,
+ &st_ref_stack,
+ "gs_interp_create_stacks(estack)"));
+ stk.value.refs += refs_size_ostack;
+ r_set_size(&stk, refs_size_estack);
+ { ref_stack *pes = r_ptr(pres, ref_stack);
+ ref euop;
+
+ make_oper(&euop, 0, estack_underflow);
+ ref_stack_init(pes, &stk, es_guard_under, es_guard_over, &euop,
+ smem);
+ pes->underflow_error = e_ExecStackUnderflow;
+ pes->overflow_error = e_execstackoverflow;
+ /**************** E-STACK EXPANSION IS NYI. ****************/
+ pes->allow_expansion = false;
+ ref_stack_set_max_count(pes, MAX_ESTACK);
+ }
+
+ make_struct(prds, avm_system,
+ gs_alloc_struct((gs_memory_t *)smem, ref_stack,
+ &st_ref_stack,
+ "gs_interp_create_stacks(dstack)"));
+ stk.value.refs += refs_size_estack;
+ r_set_size(&stk, refs_size_dstack);
+ { ref_stack *pds = r_ptr(prds, ref_stack);
+
+ ref_stack_init(pds, &stk, 0, 0, NULL, smem);
+ pds->underflow_error = e_dictstackunderflow;
+ pds->overflow_error = e_dictstackoverflow;
+ ref_stack_set_max_count(pds, MAX_DSTACK);
+ }
+
+#undef refs_size_ostack
+#undef refs_size_estack
+#undef refs_size_dstack
+ return 0;
+}
+#endif
+void
+gs_interp_reset(void)
+{ /* Reset the stacks. */
+ ref_stack_clear(&o_stack);
+ ref_stack_clear(&e_stack);
+ esp++;
+ make_oper(esp, 0, interp_exit);
+ ref_stack_pop_to(&d_stack, min_dstack_size);
+ dict_set_top();
+}
+/* Report an e-stack block underflow. The bottom guard slots of */
+/* e-stack blocks contain a pointer to this procedure. */
+private int
+estack_underflow(os_ptr op)
+{ return e_ExecStackUnderflow;
+}
+
+/*
+ * Create an operator during initialization.
+ * If operator is hard-coded into the interpreter,
+ * assign it a special type and index.
+ */
+void
+gs_interp_make_oper(ref *opref, op_proc_p proc, int idx)
+{ register int i = num_special_ops;
+ while ( --i >= 0 && proc != special_ops[i] )
+ ;
+ if ( i >= 0 )
+ make_tasv(opref, tx_op + i, a_executable, i + 1, opproc, proc);
+ else
+ make_tasv(opref, t_operator, a_executable, idx, opproc, proc);
+}
+
+/*
+ * Invoke the interpreter. If execution completes normally, return 0.
+ * If an error occurs, the action depends on user_errors as follows:
+ * user_errors < 0: always return an error code.
+ * user_errors >= 0: let the PostScript machinery handle all errors.
+ * (This will eventually result in a fatal error if no 'stopped'
+ * is active.)
+ * In case of a quit or a fatal error, also store the exit code.
+ */
+private int gs_call_interp(P4(ref *, int, int *, ref *));
+int
+gs_interpret(ref *pref, int user_errors, int *pexit_code, ref *perror_object)
+{ gs_gc_root_t error_root;
+ int code;
+
+ gs_register_ref_root(imemory_system, &error_root,
+ (void **)&perror_object, "gs_interpret");
+ /* Initialize the error object in case of GC. */
+ make_null(perror_object);
+ code = gs_call_interp(pref, user_errors, pexit_code, perror_object);
+ gs_unregister_root(imemory_system, &error_root, "gs_interpret");
+ /* Avoid a dangling reference to a stack-allocated GC signal. */
+ set_gc_signal(NULL, 0);
+ return code;
+}
+private int
+gs_call_interp(ref *pref, int user_errors, int *pexit_code, ref *perror_object)
+{ ref *epref = pref;
+ ref doref;
+ ref *perrordict;
+ ref error_name;
+ int code, ccode;
+ ref saref;
+ int gc_signal = 0;
+
+ *pexit_code = 0;
+ ialloc_reset_requested(idmemory);
+again: o_stack.requested = e_stack.requested = d_stack.requested = 0;
+ while ( gc_signal )
+ { /* Some routine below triggered a GC. */
+ gs_gc_root_t epref_root;
+
+ gc_signal = 0;
+ /* Make sure that doref will get relocated properly if */
+ /* a garbage collection happens with epref == &doref. */
+ gs_register_ref_root(imemory_system, &epref_root,
+ (void **)&epref,
+ "gs_call_interpret(epref)");
+ code = (*idmemory->reclaim)(idmemory, -1);
+ gs_unregister_root(imemory_system, &epref_root,
+ "gs_call_interpret(epref)");
+ if ( code < 0 )
+ return code;
+ }
+ code = interp(epref, perror_object);
+ /* Prevent a dangling reference to the GC signal in ticks_left */
+ /* in the frame of interp, but be prepared to do a GC if */
+ /* an allocation in this routine asks for it. */
+ set_gc_signal(&gc_signal, 1);
+ if ( esp < esbot ) /* popped guard entry */
+ esp = esbot;
+ switch ( code )
+ {
+ case e_Fatal:
+ *pexit_code = 255;
+ return code;
+ case e_Quit:
+ *perror_object = osp[-1];
+ *pexit_code = code = osp->value.intval;
+ osp -= 2;
+ return
+ (code == 0 ? e_Quit :
+ code < 0 && code > -100 ? code : e_Fatal);
+ case e_InterpreterExit:
+ return 0;
+ case e_ExecStackUnderflow:
+ /****** WRONG -- must keep mark blocks intact ******/
+ ref_stack_pop_block(&e_stack);
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ case e_VMreclaim:
+ /* Do the GC and continue. */
+ code = (*idmemory->reclaim)(idmemory,
+ (osp->value.intval == 2 ?
+ avm_global : avm_local));
+ /****** What if code < 0? ******/
+ make_oper(&doref, 0, zpop);
+ epref = &doref;
+ goto again;
+ case e_NeedInput:
+ return code;
+ }
+ /* Adjust osp in case of operand stack underflow */
+ if ( osp < osbot - 1 )
+ osp = osbot - 1;
+ /* We have to handle stack over/underflow specially, because */
+ /* we might be able to recover by adding or removing a block. */
+ switch ( code )
+ {
+ case e_dictstackoverflow:
+ if ( ref_stack_extend(&d_stack, d_stack.requested) >= 0 )
+ { dict_set_top();
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ if ( osp >= ostop )
+ { if ( (ccode = ref_stack_extend(&o_stack, 1)) < 0 )
+ return ccode;
+ }
+ ccode = copy_stack(&d_stack, &saref);
+ if ( ccode < 0 )
+ return ccode;
+ ref_stack_pop_to(&d_stack, min_dstack_size);
+ dict_set_top();
+ *++osp = saref;
+ break;
+ case e_dictstackunderflow:
+ if ( ref_stack_pop_block(&d_stack) >= 0 )
+ { dict_set_top();
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ break;
+ case e_execstackoverflow:
+ /* We don't have to handle this specially: */
+ /* The only places that could generate it */
+ /* use check_estack, which does a ref_stack_extend, */
+ /* so if we get this error, it's a real one. */
+ if ( osp >= ostop )
+ { if ( (ccode = ref_stack_extend(&o_stack, 1)) < 0 )
+ return ccode;
+ }
+ ccode = copy_stack(&e_stack, &saref);
+ if ( ccode < 0 )
+ return ccode;
+ { uint count = ref_stack_count(&e_stack);
+ long limit = ref_stack_max_count(&e_stack) - 10;
+ if ( count > limit )
+ pop_estack(count - limit);
+ }
+ *++osp = saref;
+ break;
+ case e_stackoverflow:
+ if ( ref_stack_extend(&o_stack, o_stack.requested) >= 0 )
+ { /* We can't just re-execute the object, because */
+ /* it might be a procedure being pushed as a */
+ /* literal. We check for this case specially. */
+ doref = *perror_object;
+ if ( r_is_proc(&doref) )
+ { *++osp = doref;
+ make_null_proc(&doref);
+ }
+ epref = &doref;
+ goto again;
+ }
+ ccode = copy_stack(&o_stack, &saref);
+ if ( ccode < 0 ) return ccode;
+ ref_stack_clear(&o_stack);
+ *++osp = saref;
+ break;
+ case e_stackunderflow:
+ if ( ref_stack_pop_block(&o_stack) >= 0 )
+ { doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ break;
+ }
+ if ( user_errors < 0 )
+ return code;
+ if ( gs_errorname(code, &error_name) < 0 )
+ return code; /* out-of-range error code! */
+ if ( dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
+ dict_find(perrordict, &error_name, &epref) <= 0
+ )
+ return code; /* error name not in errordict??? */
+ doref = *epref;
+ epref = &doref;
+ /* Push the error object on the operand stack if appropriate. */
+ if ( !error_is_interrupt(code) )
+ *++osp = *perror_object;
+ goto again;
+}
+private int
+interp_exit(os_ptr op)
+{ return e_InterpreterExit;
+}
+
+/* Set the GC signal for all VMs. */
+private void
+set_gc_signal(int *psignal, int value)
+{ gs_memory_gc_status_t stat;
+ int i;
+ for ( i = 0; i < countof(idmemory->spaces.indexed); i++ )
+ { gs_ref_memory_t *mem = idmemory->spaces.indexed[i];
+ if ( mem != 0 )
+ { gs_memory_gc_status(mem, &stat);
+ stat.psignal = psignal;
+ stat.signal_value = value;
+ gs_memory_set_gc_status(mem, &stat);
+ }
+ }
+}
+
+
+/* Copy the contents of an overflowed stack into a (local) array. */
+private int
+copy_stack(const ref_stack *pstack, ref *arr)
+{ uint size = ref_stack_count(pstack);
+ uint save_space = ialloc_space(idmemory);
+ int code;
+ ialloc_set_space(idmemory, avm_local);
+ code = ialloc_ref_array(arr, a_all, size, "copy_stack");
+ if ( code >= 0 )
+ code = ref_stack_store(pstack, arr, size, 0, 1, true, "copy_stack");
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+
+/* Get the name corresponding to an error number. */
+int
+gs_errorname(int code, ref *perror_name)
+{ ref *perrordict, *pErrorNames;
+ if ( dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
+ dict_find_string(systemdict, "ErrorNames", &pErrorNames) <= 0
+ )
+ return_error(e_undefined); /* errordict or ErrorNames not found?! */
+ return array_get(pErrorNames, (long)(-code - 1), perror_name);
+}
+
+/* Store an error string in $error.errorinfo. */
+/* This routine is here because of the proximity to the error handler. */
+int
+gs_errorinfo_put_string(const char *str)
+{ ref rstr;
+ ref *pderror;
+ int code = string_to_ref(str, &rstr, iimemory, "gs_errorinfo_put_string");
+ if ( code < 0 )
+ return code;
+ if ( dict_find_string(systemdict, "$error", &pderror) <= 0 ||
+ !r_has_type(pderror, t_dictionary) ||
+ dict_put_string(pderror, "errorinfo", &rstr) < 0
+ )
+ return_error(e_Fatal);
+ return 0;
+}
+
+/* Main interpreter. */
+/* If execution terminates normally, return e_InterpreterExit. */
+/* If an error occurs, leave the current object in *perror_object */
+/* and return a (negative) error code. */
+private int
+interp(ref *pref /* object to interpret */, ref *perror_object)
+{ /*
+ * Note that iref is declared as a ref *, but it may actually be
+ * a ref_packed *.
+ */
+ register const ref *iref = pref;
+ register int icount = 0; /* # of consecutive tokens at iref */
+ register os_ptr iosp = osp; /* private copy of osp */
+ register es_ptr iesp = esp; /* private copy of esp */
+ int code;
+ ref token; /* token read from file or string, */
+ /* must be declared in this scope */
+ register const ref *pvalue;
+ os_ptr whichp;
+ /*
+ * We have to make the error information into a struct;
+ * otherwise, the Watcom compiler will assign it to registers
+ * strictly on the basis of textual frequency.
+ * We also have to use ref_assign_inline everywhere, and
+ * avoid direct assignments of refs, so that esi and edi
+ * will remain available on Intel processors.
+ */
+ struct interp_error_s {
+ int code;
+ int line;
+ const ref *obj;
+ ref full;
+ } ierror;
+ /*
+ * Get a pointer to the name table so that we can use the
+ * inline version of name_index_ref.
+ */
+ const name_table *int_nt = the_name_table();
+#define set_error(ecode)\
+ { ierror.code = ecode; ierror.line = __LINE__; }
+#define return_with_error(ecode, objp)\
+ { set_error(ecode); ierror.obj = objp; goto rwe; }
+#define return_with_error_iref(ecode)\
+ { set_error(ecode); goto rwei; }
+#define return_with_code_iref()\
+ { ierror.line = __LINE__; goto rweci; }
+#define return_with_error_code_op(nargs)\
+ return_with_code_iref()
+#define return_with_stackoverflow(objp)\
+ { o_stack.requested = 1; return_with_error(e_stackoverflow, objp); }
+#define return_with_stackoverflow_iref()\
+ { o_stack.requested = 1; return_with_error_iref(e_stackoverflow); }
+ int ticks_left = gs_interp_time_slice_ticks;
+
+ /*
+ * If we exceed the VMThreshold, set ticks_left to -1
+ * to alert the interpreter that we need to garbage collect.
+ */
+ set_gc_signal(&ticks_left, -100);
+
+ esfile_clear_cache();
+ /*
+ * From here on, if icount > 0, iref and icount correspond
+ * to the top entry on the execution stack: icount is the count
+ * of sequential entries remaining AFTER the current one.
+ */
+#define add1_short(pref) (const ref *)((const ushort *)(pref) + 1)
+#define add1_either(pref) (r_is_packed(pref) ? add1_short(pref) : (pref) + 1)
+#define store_state(ep)\
+ ( icount > 0 ? (ep->value.const_refs = iref + 1, r_set_size(ep, icount)) : 0 )
+#define store_state_short(ep)\
+ ( icount > 0 ? (ep->value.const_refs = add1_short(iref), r_set_size(ep, icount)) : 0 )
+#define store_state_either(ep)\
+ ( icount > 0 ? (ep->value.const_refs = add1_either(iref), r_set_size(ep, icount)) : 0 )
+#define next()\
+ if ( --icount > 0 ) { iref++; goto top; } else goto out
+#define next_short()\
+ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
+ iref = add1_short(iref); goto top
+#define next_either()\
+ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
+ iref = add1_either(iref); goto top
+
+#if !PACKED_SPECIAL_OPS
+# undef next_either
+# define next_either() next()
+# undef store_state_either
+# define store_state_either(ep) store_state(ep)
+#endif
+
+ /* We want to recognize executable arrays here, */
+ /* so we push the argument on the estack and enter */
+ /* the loop at the bottom. */
+ if ( iesp >= estop ) return_with_error(e_execstackoverflow, pref);
+ ++iesp;
+ ref_assign_inline(iesp, pref);
+ goto bot;
+top: /*
+ * This is the top of the interpreter loop.
+ * iref points to the ref being interpreted.
+ * Note that this might be an element of a packed array,
+ * not a real ref: we carefully arranged the first 16 bits of
+ * a ref and of a packed array element so they could be distinguished
+ * from each other. (See ghost.h and packed.h for more detail.)
+ */
+#ifdef DEBUG
+ /* Do a little validation on the top o-stack entry. */
+ if ( iosp >= osbot &&
+ (r_type(iosp) == t__invalid || r_type(iosp) >= tx_next_op)
+ )
+ { lprintf("Invalid value on o-stack!\n");
+ return_with_error_iref(e_Fatal);
+ }
+if ( gs_debug['I'] ||
+ (gs_debug['i'] &&
+ (r_is_packed(iref) ?
+ r_packed_is_name((const ref_packed *)iref) :
+ r_has_type(iref, t_name)))
+ )
+ { void debug_print_ref(P1(const ref *));
+ os_ptr save_osp = osp; /* avoid side-effects */
+ es_ptr save_esp = esp;
+ int edepth;
+ char depth[10];
+ osp = iosp;
+ esp = iesp;
+ edepth = ref_stack_count(&e_stack);
+ sprintf(depth, "%2d", edepth);
+ dputs(depth);
+ for ( edepth -= strlen(depth); edepth >= 5; edepth -= 5 )
+ dputc('*'); /* indent */
+ for ( ; edepth > 0; --edepth )
+ dputc('.');
+ dprintf3("0x%lx(%d)<%d>: ",
+ (ulong)iref, icount, ref_stack_count(&o_stack));
+ debug_print_ref(iref);
+ if ( iosp >= osbot )
+ { dputs(" // ");
+ debug_print_ref(iosp);
+ }
+ dputc('\n');
+ osp = save_osp;
+ esp = save_esp;
+ fflush(dstderr);
+ }
+#endif
+/* Objects that have attributes (arrays, dictionaries, files, and strings) */
+/* use lit and exec; other objects use plain and plain_exec. */
+#define lit(t) type_xe_value(t, a_execute)
+#define exec(t) type_xe_value(t, a_execute + a_executable)
+#define nox(t) type_xe_value(t, 0)
+#define nox_exec(t) type_xe_value(t, a_executable)
+#define plain(t) type_xe_value(t, 0)
+#define plain_exec(t) type_xe_value(t, a_executable)
+ /*
+ * We have to populate enough cases of the switch statement to force
+ * some compilers to use a dispatch rather than a testing loop.
+ * What a nuisance!
+ */
+ switch ( r_type_xe(iref) )
+ {
+ /* Access errors. */
+#define cases_invalid()\
+ case plain(t__invalid): case plain_exec(t__invalid)
+ cases_invalid():
+ return_with_error_iref(e_Fatal);
+#define cases_nox()\
+ case nox_exec(t_array): case nox_exec(t_dictionary):\
+ case nox_exec(t_file): case nox_exec(t_string):\
+ case nox_exec(t_mixedarray): case nox_exec(t_shortarray)
+ cases_nox():
+ return_with_error_iref(e_invalidaccess);
+ /*
+ * Literal objects. We have to enumerate all the types.
+ * In fact, we have to include some extra plain_exec entries
+ * just to populate the switch. We break them up into groups
+ * to avoid overflowing some preprocessors.
+ */
+#define cases_lit_1()\
+ case lit(t_array): case nox(t_array):\
+ case plain(t_boolean): case plain_exec(t_boolean):\
+ case lit(t_dictionary): case nox(t_dictionary)
+#define cases_lit_2()\
+ case lit(t_file): case nox(t_file):\
+ case plain(t_fontID): case plain_exec(t_fontID):\
+ case plain(t_integer): case plain_exec(t_integer):\
+ case plain(t_mark): case plain_exec(t_mark)
+#define cases_lit_3()\
+ case plain(t_name):\
+ case plain(t_null):\
+ case plain(t_oparray):\
+ case plain(t_operator)
+#define cases_lit_4()\
+ case plain(t_real): case plain_exec(t_real):\
+ case plain(t_save): case plain_exec(t_save):\
+ case lit(t_string): case nox(t_string)
+#define cases_lit_5()\
+ case lit(t_mixedarray): case nox(t_mixedarray):\
+ case lit(t_shortarray): case nox(t_shortarray):\
+ case plain(t_device): case plain_exec(t_device):\
+ case plain(t_struct): case plain_exec(t_struct):\
+ case plain(t_astruct): case plain_exec(t_astruct)
+ /* Executable arrays are treated as literals in direct execution. */
+#define cases_lit_array()\
+ case exec(t_array): case exec(t_mixedarray): case exec(t_shortarray)
+ cases_lit_1():
+ cases_lit_2():
+ cases_lit_3():
+ cases_lit_4():
+ cases_lit_5():
+ cases_lit_array():
+ break;
+ /* Special operators. */
+ case plain_exec(tx_op_add):
+x_add: if ( (code = zop_add(iosp)) < 0 )
+ return_with_error_code_op(2);
+ iosp--;
+ next_either();
+ case plain_exec(tx_op_def):
+x_def: if ( (code = zop_def(iosp)) < 0 )
+ return_with_error_code_op(2);
+ iosp -= 2;
+ next_either();
+ case plain_exec(tx_op_dup):
+x_dup: if ( iosp < osbot )
+ return_with_error_iref(e_stackunderflow);
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ iosp++;
+ ref_assign_inline(iosp, iosp - 1);
+ next_either();
+ case plain_exec(tx_op_exch):
+x_exch: if ( iosp <= osbot )
+ return_with_error_iref(e_stackunderflow);
+ ref_assign_inline(&token, iosp);
+ ref_assign_inline(iosp, iosp - 1);
+ ref_assign_inline(iosp - 1, &token);
+ next_either();
+ case plain_exec(tx_op_if):
+x_if: if ( !r_has_type(iosp - 1, t_boolean) )
+ return_with_error_iref((iosp <= osbot ?
+ e_stackunderflow : e_typecheck));
+ if ( !r_is_proc(iosp) )
+ return_with_error_iref(check_proc_failed(iosp));
+ if ( !iosp[-1].value.boolval )
+ { iosp -= 2;
+ next_either();
+ }
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ store_state_either(iesp);
+ whichp = iosp;
+ iosp -= 2;
+ goto ifup;
+ case plain_exec(tx_op_ifelse):
+x_ifelse: if ( !r_has_type(iosp - 2, t_boolean) )
+ return_with_error_iref((iosp < osbot + 2 ?
+ e_stackunderflow : e_typecheck));
+ if ( !r_is_proc(iosp - 1) )
+ return_with_error_iref(check_proc_failed(iosp - 1));
+ if ( !r_is_proc(iosp) )
+ return_with_error_iref(check_proc_failed(iosp));
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ store_state_either(iesp);
+ whichp = (iosp[-2].value.boolval ? iosp - 1 : iosp);
+ iosp -= 3;
+ /* Open code "up" for the array case(s) */
+ifup: if ( (icount = r_size(whichp) - 1) <= 0 )
+ { if ( icount < 0 ) goto up; /* 0-element proc */
+ iref = whichp->value.refs; /* 1-element proc */
+ if ( --ticks_left > 0 )
+ goto top;
+ }
+ ++iesp;
+ /* Do a ref_assign, but also set iref. */
+ iesp->tas = whichp->tas;
+ iref = iesp->value.refs = whichp->value.refs;
+ if ( --ticks_left > 0 )
+ goto top;
+ goto slice;
+ case plain_exec(tx_op_index):
+x_index: osp = iosp; /* zindex references o_stack */
+ if ( (code = zindex(iosp)) < 0 )
+ return_with_error_code_op(1);
+ next_either();
+ case plain_exec(tx_op_pop):
+x_pop: if ( iosp < osbot )
+ return_with_error_iref(e_stackunderflow);
+ iosp--;
+ next_either();
+ case plain_exec(tx_op_roll):
+x_roll: osp = iosp; /* zroll references o_stack */
+ if ( (code = zroll(iosp)) < 0 )
+ return_with_error_code_op(2);
+ iosp -= 2;
+ next_either();
+ case plain_exec(tx_op_sub):
+x_sub: if ( (code = zop_sub(iosp)) < 0 )
+ return_with_error_code_op(2);
+ iosp--;
+ next_either();
+ /* Executable types. */
+ case plain_exec(t_null):
+ goto bot;
+ case plain_exec(t_oparray):
+ /* Replace with the definition and go again. */
+ pvalue = (const ref *)iref->value.const_refs;
+opst: /* Prepare to call a t_oparray procedure in *pvalue. */
+ store_state(iesp);
+oppr: /* Record the stack depths in case of failure. */
+ if ( iesp >= estop - 3 )
+ return_with_error_iref(e_execstackoverflow);
+ iesp += 4;
+ osp = iosp; /* ref_stack_count_inline needs this */
+ make_mark_estack(iesp - 3, es_other, oparray_cleanup);
+ make_int(iesp - 2, ref_stack_count_inline(&o_stack));
+ make_int(iesp - 1, ref_stack_count_inline(&d_stack));
+ make_op_estack(iesp, oparray_pop);
+ goto pr;
+prst: /* Prepare to call the procedure (array) in *pvalue. */
+ store_state(iesp);
+pr: /* Call the array in *pvalue. State has been stored. */
+ if ( (icount = r_size(pvalue) - 1) <= 0 )
+ { if ( icount < 0 ) goto up; /* 0-element proc */
+ iref = pvalue->value.refs; /* 1-element proc */
+ if ( --ticks_left > 0 )
+ goto top;
+ }
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ /* Do a ref_assign, but also set iref. */
+ iesp->tas = pvalue->tas;
+ iref = iesp->value.refs = pvalue->value.refs;
+ if ( --ticks_left > 0 )
+ goto top;
+ goto slice;
+ case plain_exec(t_operator):
+ if ( --ticks_left <= 0 )
+ { /* The following doesn't work, */
+ /* and I can't figure out why. */
+ /****** goto sst; ******/
+ }
+ esp = iesp; /* save for operator */
+ osp = iosp; /* ditto */
+ /* Operator routines take osp as an argument. */
+ /* This is just a convenience, since they adjust */
+ /* osp themselves to reflect the results. */
+ /* Operators that (net) push information on the */
+ /* operand stack must check for overflow: */
+ /* this normally happens automatically through */
+ /* the push macro (in oper.h). */
+ /* Operators that do not typecheck their operands, */
+ /* or take a variable number of arguments, */
+ /* must check explicitly for stack underflow. */
+ /* (See oper.h for more detail.) */
+ /* Note that each case must set iosp = osp: */
+ /* this is so we can switch on code without having to */
+ /* store it and reload it (for dumb compilers). */
+ switch ( code = call_operator(real_opproc(iref), iosp) )
+ {
+ case 0: /* normal case */
+ case 1: /* alternative success case */
+ iosp = osp;
+ next();
+ case o_push_estack: /* store the state and go to up */
+ store_state(iesp);
+opush: iosp = osp;
+ iesp = esp;
+ if ( --ticks_left > 0 )
+ goto up;
+ goto slice;
+ case o_pop_estack: /* just go to up */
+opop: iosp = osp;
+ if ( esp == iesp ) goto bot;
+ iesp = esp;
+ goto up;
+ case o_reschedule:
+ store_state(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state(iesp);
+oeinsert: ref_assign_inline(iesp + 1, iref);
+ /* esp = iesp + 2; *esp = the procedure */
+ iesp = esp;
+ goto up;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_code_iref();
+ case plain_exec(t_name):
+ pvalue = iref->value.pname->pvalue;
+ if ( !pv_valid(pvalue) )
+ { uint nidx = name_index(iref);
+ uint htemp;
+ if ( (pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0 )
+ return_with_error_iref(e_undefined);
+ }
+ /* Dispatch on the type of the value. */
+ /* Again, we have to over-populate the switch. */
+ switch ( r_type_xe(pvalue) )
+ {
+ cases_invalid():
+ return_with_error_iref(e_Fatal);
+ cases_nox(): /* access errors */
+ return_with_error_iref(e_invalidaccess);
+ cases_lit_1():
+ cases_lit_2():
+ cases_lit_3():
+ cases_lit_4():
+ cases_lit_5():
+ /* Just push the value */
+ if ( iosp >= ostop )
+ return_with_stackoverflow(pvalue);
+ ++iosp;
+ ref_assign_inline(iosp, pvalue);
+ next();
+ case exec(t_array):
+ case exec(t_mixedarray):
+ case exec(t_shortarray):
+ /* This is an executable procedure, execute it. */
+ goto prst;
+ case plain_exec(tx_op_add): goto x_add;
+ case plain_exec(tx_op_def): goto x_def;
+ case plain_exec(tx_op_dup): goto x_dup;
+ case plain_exec(tx_op_exch): goto x_exch;
+ case plain_exec(tx_op_if): goto x_if;
+ case plain_exec(tx_op_ifelse): goto x_ifelse;
+ case plain_exec(tx_op_index): goto x_index;
+ case plain_exec(tx_op_pop): goto x_pop;
+ case plain_exec(tx_op_roll): goto x_roll;
+ case plain_exec(tx_op_sub): goto x_sub;
+ case plain_exec(t_null):
+ goto bot;
+ case plain_exec(t_oparray):
+ pvalue = (const ref *)pvalue->value.const_refs;
+ goto opst;
+ case plain_exec(t_operator):
+ { /* Shortcut for operators. */
+ /* See above for the logic. */
+ if ( --ticks_left <= 0 )
+ { /* The following doesn't work, */
+ /* and I can't figure out why. */
+ /****** goto sst; ******/
+ }
+ esp = iesp;
+ osp = iosp;
+ switch ( code = call_operator(real_opproc(pvalue), iosp) )
+ {
+ case 0: /* normal case */
+ case 1: /* alternative success case */
+ iosp = osp;
+ next();
+ case o_push_estack:
+ store_state(iesp);
+ goto opush;
+ case o_pop_estack:
+ goto opop;
+ case o_reschedule:
+ store_state(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state(iesp);
+ goto oeinsert;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_error(code, pvalue);
+ }
+ case plain_exec(t_name):
+ case exec(t_file):
+ case exec(t_string):
+ default:
+ /* Not a procedure, reinterpret it. */
+ store_state(iesp);
+ icount = 0;
+ iref = pvalue;
+ goto top;
+ }
+ case exec(t_file):
+ { /* Executable file. Read the next token and interpret it. */
+ stream *s;
+ scanner_state sstate;
+ check_read_known_file(s, iref, return_with_error_iref);
+rt: if ( iosp >= ostop ) /* check early */
+ return_with_stackoverflow_iref();
+ osp = iosp; /* scan_token uses ostack */
+ scanner_state_init(&sstate, false);
+again: code = scan_token(s, &token, &sstate);
+ iosp = osp; /* ditto */
+ switch ( code )
+ {
+ case 0: /* read a token */
+ /* It's worth checking for literals, which make up */
+ /* the majority of input tokens, before storing the */
+ /* state on the e-stack. Note that because of //, */
+ /* the token may have *any* type and attributes. */
+ /* Note also that executable arrays aren't executed */
+ /* at the top level -- they're treated as literals. */
+ if ( !r_has_attr(&token, a_executable) ||
+ r_is_array(&token)
+ )
+ { /* If scan_token used the o-stack, */
+ /* we know we can do a push now; if not, */
+ /* the pre-check is still valid. */
+ iosp++;
+ ref_assign_inline(iosp, &token);
+ goto rt;
+ }
+ store_state(iesp);
+ /* Push the file on the e-stack */
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ esfile_set_cache(++iesp);
+ ref_assign_inline(iesp, iref);
+ iref = &token;
+ icount = 0;
+ goto top;
+ case scan_EOF: /* end of file */
+ esfile_clear_cache();
+ goto bot;
+ case scan_BOS:
+ /* Binary object sequences */
+ /* ARE executed at the top level. */
+ store_state(iesp);
+ /* Push the file on the e-stack */
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ esfile_set_cache(++iesp);
+ ref_assign_inline(iesp, iref);
+ pvalue = &token;
+ goto pr;
+ case scan_Refill:
+ store_state(iesp);
+ /* iref may point into the exec stack; */
+ /* save its referent now. */
+ ref_assign_inline(&token, iref);
+ /* Push the file on the e-stack */
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ ref_assign_inline(iesp, &token);
+ esp = iesp;
+ osp = iosp;
+ code = scan_handle_refill(&token, &sstate, true, true,
+ ztokenexec_continue);
+ iosp = osp;
+ iesp = esp;
+ switch ( code )
+ {
+ case 0:
+ iesp--; /* don't push the file */
+ goto again; /* stacks are unchanged */
+ case o_push_estack:
+ esfile_clear_cache();
+ if ( --ticks_left > 0 )
+ goto up;
+ goto slice;
+ }
+ /* must be an error */
+ iesp--; /* don't push the file */
+ default: /* error */
+ return_with_code_iref();
+ }
+ }
+ case exec(t_string):
+ { /* Executable string. Read a token and interpret it. */
+ stream ss;
+ scanner_state sstate;
+ scanner_state_init(&sstate, true);
+ sread_string(&ss, iref->value.bytes, r_size(iref));
+ osp = iosp; /* scan_token uses ostack */
+ code = scan_token(&ss, &token, &sstate);
+ iosp = osp; /* ditto */
+ switch ( code )
+ {
+ case 0: /* read a token */
+ case scan_BOS: /* binary object sequence */
+ store_state(iesp);
+ /* If the updated string isn't empty, push it back */
+ /* on the e-stack. */
+ { uint size = sbufavailable(&ss);
+ if ( size )
+ { if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ iesp->tas.type_attrs = iref->tas.type_attrs;
+ iesp->value.const_bytes = sbufptr(&ss);
+ r_set_size(iesp, size);
+ }
+ }
+ if ( code == 0 )
+ { iref = &token;
+ icount = 0;
+ goto top;
+ }
+ /* Handle BOS specially */
+ pvalue = &token;
+ goto pr;
+ case scan_EOF: /* end of string */
+ goto bot;
+ case scan_Refill: /* error */
+ code = gs_note_error(e_syntaxerror);
+ default: /* error */
+ return_with_code_iref();
+ }
+ }
+ /* Handle packed arrays here by re-dispatching. */
+ /* This also picks up some anomalous cases of non-packed arrays. */
+ default:
+ { uint index;
+ switch ( *(const ushort *)iref >> r_packed_type_shift )
+ {
+ case pt_full_ref:
+ case pt_full_ref+1:
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ /* We know this can't be an executable object */
+ /* requiring special handling, so we just push it. */
+ ++iosp;
+ /* We know that refs are properly aligned: */
+ /* see packed.h for details. */
+ ref_assign_inline(iosp, iref);
+ next();
+ case pt_executable_operator:
+ index = *(const ushort *)iref & packed_value_mask;
+ if ( --ticks_left <= 0 )
+ { /* The following doesn't work, */
+ /* and I can't figure out why. */
+ /****** goto sst_short; ******/
+ }
+ if ( !op_index_is_operator(index) )
+ { store_state_short(iesp);
+ /* Call the operator procedure. */
+ index -= op_def_count;
+ pvalue = (const ref *)
+ (index < r_size(&op_array_table_global.table) ?
+ op_array_table_global.table.value.const_refs +
+ index :
+ op_array_table_local.table.value.const_refs +
+ (index - r_size(&op_array_table_global.table)));
+ goto oppr;
+ }
+ /* See the main plain_exec(t_operator) case */
+ /* for details of what happens here. */
+#if PACKED_SPECIAL_OPS
+ /* We arranged in iinit.c that the special ops */
+ /* have operator indices starting at 1. */
+# define case_xop(xop) case xop - tx_op + 1
+ switch ( index )
+ {
+ case_xop(tx_op_add): goto x_add;
+ case_xop(tx_op_def): goto x_def;
+ case_xop(tx_op_dup): goto x_dup;
+ case_xop(tx_op_exch): goto x_exch;
+ case_xop(tx_op_if): goto x_if;
+ case_xop(tx_op_ifelse): goto x_ifelse;
+ case_xop(tx_op_index): goto x_index;
+ case_xop(tx_op_pop): goto x_pop;
+ case_xop(tx_op_roll): goto x_roll;
+ case_xop(tx_op_sub): goto x_sub;
+ case 0: /* for dumb compilers */
+ default:
+ ;
+ }
+# undef case_xop
+#endif
+ esp = iesp;
+ osp = iosp;
+ switch ( code = call_operator(op_index_proc(index), iosp) )
+ {
+ case 0:
+ case 1:
+ iosp = osp;
+ next_short();
+ case o_push_estack:
+ store_state_short(iesp);
+ goto opush;
+ case o_pop_estack:
+ iosp = osp;
+ if ( esp == iesp )
+ { next_short();
+ }
+ iesp = esp;
+ goto up;
+ case o_reschedule:
+ store_state_short(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state_short(iesp);
+ packed_get((const ref_packed *)iref, iesp + 1);
+ /* esp = iesp + 2; *esp = the procedure */
+ iesp = esp;
+ goto up;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_code_iref();
+ case pt_integer:
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ ++iosp;
+ make_int(iosp,
+ (*(const short *)iref & packed_int_mask) +
+ packed_min_intval);
+ next_short();
+ case pt_literal_name:
+ { uint nidx = *(const ushort *)iref & packed_value_mask;
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ ++iosp;
+ name_index_ref_inline(int_nt, nidx, iosp);
+ next_short();
+ }
+ case pt_executable_name:
+ { uint nidx =
+ (uint)*(const ushort *)iref & packed_value_mask;
+ pvalue = name_index_ptr_inline(int_nt, nidx)->pvalue;
+ if ( !pv_valid(pvalue) )
+ { uint htemp;
+ if ( (pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0 )
+ { name_index_ref(nidx, &token);
+ return_with_error(e_undefined, &token);
+ }
+ }
+ if ( r_has_masked_attrs(pvalue, a_execute, a_execute + a_executable) )
+ { /* Literal, push it. */
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ ++iosp;
+ ref_assign_inline(iosp, pvalue);
+ next_short();
+ }
+ if ( r_is_proc(pvalue) )
+ { /* This is an executable procedure, */
+ /* execute it. */
+ store_state_short(iesp);
+ goto pr;
+ }
+ /* Not a literal or procedure, reinterpret it. */
+ store_state_short(iesp);
+ icount = 0;
+ iref = pvalue;
+ goto top;
+ }
+ /* default can't happen here */
+ }
+ }
+ }
+ /* Literal type, just push it. */
+ if ( iosp >= ostop )
+ return_with_stackoverflow_iref();
+ ++iosp;
+ ref_assign_inline(iosp, iref);
+bot: next();
+out: /* At most 1 more token in the current procedure. */
+ /* (We already decremented icount.) */
+ if ( !icount )
+ { /* Pop the execution stack for tail recursion. */
+ iesp--;
+ iref++;
+ goto top;
+ }
+up: if ( --ticks_left < 0 )
+ goto slice;
+ /* See if there is anything left on the execution stack. */
+ if ( !r_is_proc(iesp) )
+ { iref = iesp--;
+ icount = 0;
+ goto top;
+ }
+ iref = iesp->value.refs; /* next element of array */
+ icount = r_size(iesp) - 1;
+ if ( icount <= 0 ) /* <= 1 more elements */
+ { iesp--; /* pop, or tail recursion */
+ if ( icount < 0 ) goto up;
+ }
+ goto top;
+res: /* Some operator has asked for context rescheduling. */
+ /* We've done a store_state. */
+ code = (*gs_interp_reschedule_proc)();
+sched: /* We've just called a scheduling procedure. */
+ /* The interpreter state is in memory; iref is not current. */
+ if ( code < 0 )
+ { set_error(code);
+ make_null_proc(&null_proc);
+ ierror.obj = iref = &null_proc;
+ goto error_exit;
+ }
+ /* Reload state information from memory. */
+ iosp = osp;
+ iesp = esp;
+ goto up;
+#if 0 /****** ****** ******/
+sst: /* Time-slice, but push the current object first. */
+ store_state(iesp);
+ if ( iesp >= estop )
+ return_with_error_iref(e_execstackoverflow);
+ iesp++;
+ ref_assign_inline(iesp, iref);
+#endif /****** ****** ******/
+slice: /* It's time to time-slice or garbage collect. */
+ /* iref is not live, so we don't need to do a store_state. */
+ osp = iosp;
+ esp = iesp;
+ /* If ticks_left <= -100, we need to GC now. */
+ if ( ticks_left <= -100 )
+ { /* We need to garbage collect now. */
+ code = (*idmemory->reclaim)(idmemory, -1);
+ }
+ else
+ code = (*gs_interp_time_slice_proc)();
+ ticks_left = gs_interp_time_slice_ticks;
+ goto sched;
+
+ /* Error exits. */
+
+rweci:
+ ierror.code = code;
+rwei:
+ ierror.obj = iref;
+rwe:
+ if ( !r_is_packed(iref) )
+ store_state(iesp);
+ else
+ { /* We need a real object to return as the error object. */
+ /* (It only has to last long enough to store in *perror_object.) */
+ packed_get((const ref_packed *)ierror.obj, &ierror.full);
+ store_state_short(iesp);
+ if ( iref == ierror.obj )
+ iref = &ierror.full;
+ ierror.obj = &ierror.full;
+ }
+error_exit:
+ if ( error_is_interrupt(ierror.code) )
+ { /* We must push the current object being interpreted */
+ /* back on the e-stack so it will be re-executed. */
+ /* Currently, this is always an executable operator, */
+ /* but it might be something else someday if we check */
+ /* for interrupts in the interpreter loop itself. */
+ if ( iesp >= estop )
+ code = e_execstackoverflow;
+ else
+ { iesp++;
+ ref_assign_inline(iesp, iref);
+ }
+ }
+ esp = iesp;
+ osp = iosp;
+ ref_assign_inline(perror_object, ierror.obj);
+ return gs_log_error(ierror.code, __FILE__, ierror.line);
+
+}
+
+/* Pop the bookkeeping information for a normal exit from a t_oparray. */
+private int
+oparray_pop(os_ptr op)
+{ esp -= 3;
+ return o_pop_estack;
+}
+
+/* Restore the stack pointers after an error inside a t_oparray procedure. */
+/* This procedure is called only from pop_estack. */
+private int
+oparray_cleanup(os_ptr op)
+{ /* esp points just below the cleanup procedure. */
+ es_ptr ep = esp;
+ uint ocount_old = (uint)ep[2].value.intval;
+ uint dcount_old = (uint)ep[3].value.intval;
+ uint ocount = ref_stack_count(&o_stack);
+ uint dcount = ref_stack_count(&d_stack);
+
+ if ( ocount > ocount_old )
+ ref_stack_pop(&o_stack, ocount - ocount_old);
+ if ( dcount > dcount_old )
+ ref_stack_pop(&d_stack, dcount - dcount_old);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(interp_op_defs) {
+ /* Internal operators */
+ {"0%interp_exit", interp_exit},
+ {"0%oparray_pop", oparray_pop},
+END_OP_DEFS(0) }
diff --git a/gs/src/interp.h b/gs/src/interp.h
new file mode 100644
index 000000000..5bc666213
--- /dev/null
+++ b/gs/src/interp.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* interp.h */
+/* Internal interfaces to interp.c and iinit.c */
+
+/* ------ iinit.c ------ */
+
+/* Enter a name and value into systemdict. */
+void initial_enter_name(P2(const char *, const ref *));
+
+/* Remove a name from systemdict. */
+void initial_remove_name(P1(const char *));
+
+/* ------ interp.c ------ */
+
+/*
+ * Maximum number of arguments (and results) for an operator,
+ * determined by operand stack block size.
+ */
+extern const int gs_interp_max_op_num_args;
+
+/*
+ * Number of slots to reserve at the start of op_def_table for
+ * operators which are hard-coded into the interpreter loop.
+ */
+extern const int gs_interp_num_special_ops;
+
+/*
+ * Create an operator during initialization.
+ * If operator is hard-coded into the interpreter,
+ * assign it a special type and index.
+ */
+void gs_interp_make_oper(P3(ref *opref, op_proc_p, int index));
+
+/* Get the name corresponding to an error number. */
+int gs_errorname(P2(int, ref *));
+
+/* Put a string in $error /errorinfo. */
+int gs_errorinfo_put_string(P1(const char *));
+
+/* Initialize the interpreter. */
+void gs_interp_init(P0());
+
+#ifdef DPNEXT
+/*
+ * Create initial stacks for the interpreter.
+ * We export this for creating new contexts.
+ * The last 3 arguments are t_struct refs pointing to ref_stacks.
+ */
+int gs_interp_create_stacks(P4(gs_ref_memory_t *smem, ref *prds, ref *pres,
+ ref *pros));
+#endif
+
+/* Reset the interpreter. */
+void gs_interp_reset(P0());
diff --git a/gs/src/ipacked.h b/gs/src/ipacked.h
new file mode 100644
index 000000000..811e5bb91
--- /dev/null
+++ b/gs/src/ipacked.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 1991, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ipacked.h */
+/* Packed array format for Ghostscript */
+
+/*
+
+In a packed array, an element may either be a 2-byte ref_packed or a
+full-size ref (8 or 16 bytes). We carefully arrange the first two bytes,
+which are either an entire ref_packed or the type_attrs member of a ref,
+so that we can distinguish the 2 forms. The encoding:
+
+ 00tttttt exrwsfnm full-size ref
+ 010mjjjj jjjjjjjj executable operator (so bind can work)
+ 011mvvvv vvvvvvvv integer (biased by packed_min_intval)
+ 100m---- -------- (not used)
+ 101m---- -------- (not used)
+ 110miiii iiiiiiii literal name
+ 111miiii iiiiiiii executable name
+
+The m bit is the mark bit for the garbage collector.
+
+****** Note for the future: We could get packed tokens into the first-level
+****** interpreter dispatch by changing to the following representation:
+
+ 000ttttt exrwsfnm full-size ref
+ m0100jjj jjjjjjjj executable operator (so bind can work)
+ m0101vvv vvvvvvvv integer (biased by packed_min_intval)
+ m011iiii iiiiiiii literal name
+ m100iiii iiiiiiii executable name
+ m101---- -------- (not used)
+ m11----- -------- (not used)
+
+****** We aren't going to do this for a while.
+
+The jjj index of executable operators is either the index of the operator
+in the op_def_table, if the index is less than op_def_count, or the index
+of the definition in the op_array_table (subtracting op_def_count first).
+
+The iii index of names is the one that the name machinery already
+maintains. A name whose index is larger than will fit in the packed
+representation must be represented as a full-size ref.
+
+There are two packed array types, t_mixedarray and t_shortarray. A
+t_mixedarray can have a mix of packed and full-size elements; a
+t_shortarray has all packed elements. The 'size' of a packed array is the
+number of elements, not the number of bytes it occupies.
+
+Packed array elements can be distinguished from full-size elements, so we
+allow the interpreter to simply execute all the different kinds of arrays
+directly. However, if we really allowed free mixing of packed and
+full-size elements, this could lead to unaligned placement of full-size
+refs; some machines can't handle unaligned accesses of this kind. To
+guarantee that full-size elements in mixed arrays are always properly
+aligned, if a full-size ref must be aligned at an address which is 0 mod
+N, we convert up to N/2-1 preceding packed elements into full-size
+elements, when creating the array, so that the alignment is preserved.
+The only code this actually affects is in make_packed_array and in the
+code for compacting refs in the garbage collector.
+
+Note that code in zpacked.c and interp.c knows more about the
+representation of packed elements than the definitions in this file would
+imply. Read the code carefully if you change the representation.
+
+ */
+
+#define r_packed_type_shift 13
+#define r_packed_value_bits 12
+typedef enum {
+ pt_full_ref = 0,
+#define pt_min_packed 2
+ pt_executable_operator = 2,
+ pt_integer = 3,
+ pt_unused1 = 4,
+ pt_unused2 = 5,
+#define pt_min_name 6
+ pt_literal_name = 6,
+#define pt_min_exec_name 7
+ pt_executable_name = 7
+} packed_type;
+#define packed_per_ref (sizeof(ref) / sizeof(ref_packed))
+#define align_packed_per_ref\
+ (arch_align_ref_mod / arch_align_short_mod)
+#define pt_tag(pt) ((ref_packed)(pt) << r_packed_type_shift)
+#define packed_value_mask ((1 << r_packed_value_bits) - 1)
+#define packed_max_value packed_value_mask
+#define r_is_packed(rp) (*(const ref_packed *)(rp) >= pt_tag(pt_min_packed))
+/* Names */
+#define r_packed_is_name(prp) (*(prp) >= pt_tag(pt_min_name))
+#define r_packed_is_exec_name(prp) (*(prp) >= pt_tag(pt_min_exec_name))
+#define packed_name_max_index packed_max_value
+#define packed_name_index(prp) (*(prp) & packed_value_mask)
+/* Integers */
+#define packed_min_intval (-(1 << (r_packed_value_bits - 1)))
+#define packed_max_intval ((1 << (r_packed_value_bits - 1)) - 1)
+#define packed_int_mask packed_value_mask
+
+/* Packed ref marking */
+#define lp_mark_shift 12
+#define lp_mark (1 << lp_mark_shift)
+#define r_has_pmark(rp) (*(rp) & lp_mark)
+#define r_set_pmark(rp) (*(rp) |= lp_mark)
+#define r_clear_pmark(rp) (*(rp) &= ~lp_mark)
+#define r_store_pmark(rp,pm) (*(rp) = (*(rp) & ~lp_mark) | (pm))
+
+/* Advance to the next element in a packed array. */
+#define packed_next(prp)\
+ (r_is_packed(prp) ? prp + 1 : prp + packed_per_ref)
diff --git a/gs/src/iparam.c b/gs/src/iparam.c
new file mode 100644
index 000000000..7c0890647
--- /dev/null
+++ b/gs/src/iparam.c
@@ -0,0 +1,1053 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iparam.c */
+/* Interpreter implementations of parameter dictionaries */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "opcheck.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "imemory.h" /* for iutil.h */
+#include "iname.h"
+#include "istack.h"
+#include "iparam.h"
+#include "iutil.h" /* for num_params */
+#include "ivmspace.h"
+#include "store.h"
+
+/* ================ Utilities ================ */
+
+#define iplist ((iparam_list *)plist)
+#define ciplist ((const iparam_list *)plist)
+
+/* Convert a key to a ref. */
+private int near
+ref_param_key(const iparam_list *plist, gs_param_name pkey, ref *pkref)
+{ if ( plist->int_keys )
+ { long key;
+ if ( sscanf(pkey, "%ld", &key) != 1 )
+ return_error(e_rangecheck);
+ make_int(pkref, key);
+ return 0;
+ }
+ else
+ { return name_ref((const byte *)pkey, strlen(pkey), pkref, 0);
+ }
+}
+
+/* Fill in a gs_param_key_t's key from a name or int ref */
+private int
+ref_to_key(const ref *pref, gs_param_key_t *key)
+{
+ if ( r_has_type(pref, t_name) )
+ { ref nref;
+ name_string_ref(pref, &nref);
+ key->key = (char *)nref.value.const_bytes;
+ key->key_sizeof = r_size(&nref);
+ }
+ else if ( r_has_type(pref, t_integer) )
+ { char *buf = (char *)ialloc_bytes(22, "ref_to_key");
+ /* GC will take care of freeing this */
+ if (!buf)
+ return_error(e_VMerror);
+ sprintf(buf, "%ld", pref->value.intval);
+ key->key = buf;
+ key->key_sizeof = strlen(buf);
+ }
+ else
+ return_error(e_typecheck);
+ return 0;
+}
+
+/* ================ Writing parameters to refs ================ */
+
+/* ---------------- Generic writing procedures ---------------- */
+
+private param_proc_xmit_null(ref_param_write_null);
+private param_proc_xmit_typed(ref_param_write_typed);
+private param_proc_xmit_bool(ref_param_write_bool);
+private param_proc_xmit_int(ref_param_write_int);
+private param_proc_xmit_long(ref_param_write_long);
+private param_proc_xmit_float(ref_param_write_float);
+private param_proc_xmit_string(ref_param_write_string);
+private param_proc_xmit_name(ref_param_write_name);
+private param_proc_xmit_int_array(ref_param_write_int_array);
+private param_proc_xmit_float_array(ref_param_write_float_array);
+private param_proc_xmit_string_array(ref_param_write_string_array);
+private param_proc_xmit_name_array(ref_param_write_name_array);
+private param_proc_begin_xmit_dict(ref_param_begin_write_dict);
+private param_proc_end_xmit_dict(ref_param_end_write_dict);
+private param_proc_next_key(ref_param_get_next_key);
+private param_proc_requested(ref_param_requested);
+private const gs_param_list_procs ref_write_procs = {
+ ref_param_write_null,
+ ref_param_write_typed,
+ ref_param_write_bool,
+ ref_param_write_int,
+ ref_param_write_long,
+ ref_param_write_float,
+ ref_param_write_string,
+ ref_param_write_name,
+ ref_param_write_int_array,
+ ref_param_write_float_array,
+ ref_param_write_string_array,
+ ref_param_write_name_array,
+ ref_param_begin_write_dict,
+ ref_param_end_write_dict,
+ ref_param_get_next_key,
+ ref_param_requested
+};
+private int near ref_array_param_requested(P5(const gs_param_list *, gs_param_name, ref *, uint, client_name_t));
+private int near ref_param_write(P3(iparam_list *, gs_param_name, const ref *));
+private int near ref_param_write_string_value(P2(ref *,
+ const gs_param_string *));
+#define ref_param_write_name_value(pref, pvalue)\
+ name_ref((pvalue)->data, (pvalue)->size, pref,\
+ ((pvalue)->persistent ? 0 : 1))
+
+private int
+ref_param_write_null(gs_param_list *plist, gs_param_name pkey)
+{ ref value;
+ make_null(&value);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_typed(gs_param_list *plist, gs_param_name pkey,
+ gs_param_typed_value *pvalue)
+{
+ switch (pvalue->type)
+ {
+ case cpt_null:
+ return ref_param_write_null(plist, pkey);
+ case cpt_bool:
+ return ref_param_write_bool(plist, pkey, &pvalue->value.b);
+ case cpt_int:
+ case cpt_long:
+ return ref_param_write_long(plist, pkey, &pvalue->value.l);
+ case cpt_float:
+ return ref_param_write_float(plist, pkey, &pvalue->value.f);
+ case cpt_string:
+ return ref_param_write_string(plist, pkey, &pvalue->value.s);
+ case cpt_name:
+ return ref_param_write_name(plist, pkey, &pvalue->value.n);
+ case cpt_int_array:
+ return ref_param_write_int_array(plist, pkey, &pvalue->value.ia);
+ case cpt_float_array:
+ return ref_param_write_float_array(plist, pkey, &pvalue->value.fa);
+ case cpt_string_array:
+ return ref_param_write_string_array(plist, pkey, &pvalue->value.sa);
+ case cpt_name_array:
+ return ref_param_write_name_array(plist, pkey, &pvalue->value.na);
+ case cpt_dict:
+ case cpt_dict_int_keys:
+ return ref_param_begin_write_dict(plist, pkey,
+ &pvalue->value.d, pvalue->type == cpt_dict_int_keys);
+ default:;
+ }
+ return e_typecheck;
+}
+private int
+ref_param_write_bool(gs_param_list *plist, gs_param_name pkey, bool *pvalue)
+{ ref value;
+ make_bool(&value, *pvalue);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_int(gs_param_list *plist, gs_param_name pkey, int *pvalue)
+{ ref value;
+ make_int(&value, *pvalue);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_long(gs_param_list *plist, gs_param_name pkey, long *pvalue)
+{ ref value;
+ make_int(&value, *pvalue);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_float(gs_param_list *plist, gs_param_name pkey, float *pvalue)
+{ ref value;
+ make_real(&value, *pvalue);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_string(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string *pvalue)
+{ ref sref;
+ int code;
+
+ if ( !ref_param_requested(plist, pkey) )
+ return 0;
+ code = ref_param_write_string_value(&sref, pvalue);
+ if ( code < 0 )
+ return code;
+ return ref_param_write(iplist, pkey, &sref);
+}
+private int
+ref_param_write_name(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string *pvalue)
+{ ref nref;
+ int code;
+
+ if ( !ref_param_requested(plist, pkey) )
+ return 0;
+ code = ref_param_write_name_value(&nref, pvalue);
+ if ( code < 0 )
+ return code;
+ return ref_param_write(iplist, pkey, &nref);
+}
+private int
+ref_param_write_int_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_int_array *pvalue)
+{ ref value;
+ const int *pdata = pvalue->data;
+ uint n = pvalue->size;
+ ref *pe;
+ int code;
+
+ if ( (code = ref_array_param_requested(plist, pkey, &value, n,
+ "ref_param_write_int_array")) <= 0 )
+ return code;
+ for ( pe = value.value.refs; n > 0; n--, pe++, pdata++ )
+ make_int_new(pe, *pdata);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_float_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_float_array *pvalue)
+{ ref value;
+ const float *pdata = pvalue->data;
+ uint n = pvalue->size;
+ int code;
+ ref *pe;
+
+ if ( (code = ref_array_param_requested(plist, pkey, &value, n,
+ "ref_param_write_float_array")) <= 0 )
+ return code;
+ for ( pe = value.value.refs; n > 0; n--, pe++, pdata++ )
+ make_real_new(pe, *pdata);
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_string_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string_array *pvalue)
+{ ref value;
+ const gs_param_string *pdata = pvalue->data;
+ uint n = pvalue->size;
+ int code;
+ ref *pe;
+
+ if ( (code = ref_array_param_requested(plist, pkey, &value, n,
+ "ref_param_write_string_array")) <= 0 )
+ return code;
+ for ( pe = value.value.refs; n > 0; n--, pe++, pdata++ )
+ { code = ref_param_write_string_value(pe, pdata);
+ if ( code < 0 )
+ { /* Don't bother trying to release memory. */
+ return code;
+ }
+ }
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_write_name_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string_array *pvalue)
+{ ref value;
+ const gs_param_string *pdata = pvalue->data;
+ uint n = pvalue->size;
+ int code;
+ ref *pe;
+
+ if ( (code = ref_array_param_requested(plist, pkey, &value, n,
+ "ref_param_write_name_array")) <= 0 )
+ return code;
+ for ( pe = value.value.refs; n > 0; n--, pe++, pdata++ )
+ { code = ref_param_write_name_value(pe, pdata);
+ if ( code < 0 )
+ { /* Don't bother trying to release memory. */
+ return code;
+ }
+ }
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_begin_write_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue, bool int_keys)
+{ dict_param_list *dlist =
+ (dict_param_list *)ialloc_bytes(size_of(dict_param_list),
+ "ref_param_begin_write_dict");
+ ref dref;
+ int code;
+
+ if ( dlist == 0 )
+ return_error(e_VMerror);
+ code = dict_create(pvalue->size, &dref);
+ if ( code < 0 )
+ { ifree_object(dlist, "ref_param_begin_write_dict");
+ return code;
+ }
+ pvalue->list = (gs_param_list *)dlist;
+ code = dict_param_list_write(dlist, &dref, NULL);
+ if ( code < 0 )
+ return code;
+ dlist->int_keys = int_keys;
+ return 0;
+}
+private int
+ref_param_end_write_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue)
+{ int code = ref_param_write(iplist, pkey,
+ &((dict_param_list *)pvalue->list)->dict);
+ ifree_object(pvalue->list, "ref_param_end_write_dict");
+ return code;
+}
+
+/* Check whether a given parameter was requested. */
+private bool
+ref_param_requested(const gs_param_list *plist, gs_param_name pkey)
+{ ref kref;
+ ref *ignore_value;
+ if ( !r_has_type(&ciplist->u.w.wanted, t_dictionary) )
+ return true;
+ if ( ref_param_key(ciplist, pkey, &kref) < 0 )
+ return true; /* catch it later */
+ return (dict_find(&ciplist->u.w.wanted, &kref, &ignore_value) > 0);
+}
+/* Check whether an array parameter is wanted, and allocate it if so. */
+/* Return <0 on error, 0 if not wanted, 1 if wanted. */
+private int near
+ref_array_param_requested(const gs_param_list *plist, gs_param_name pkey,
+ ref *pvalue, uint size, client_name_t cname)
+{ int code;
+ if ( !ref_param_requested(plist, pkey) )
+ return 0;
+ code = ialloc_ref_array(pvalue, a_all, size, cname);
+ return (code < 0 ? code : 1);
+}
+
+/* ---------------- Internal routines ---------------- */
+
+/* Prepare to write a string value. */
+private int near
+ref_param_write_string_value(ref *pref, const gs_param_string *pvalue)
+{ const byte *pdata = pvalue->data;
+ uint n = pvalue->size;
+
+ if ( pvalue->persistent )
+ make_const_string(pref, a_readonly | avm_foreign, n, pdata);
+ else
+ { byte *pstr = ialloc_string(n, "ref_param_write_string");
+ if ( pstr == 0 )
+ return_error(e_VMerror);
+ memcpy(pstr, pdata, n);
+ make_string(pref, a_readonly | icurrent_space, n, pstr);
+ }
+ return 0;
+}
+
+/* Generic routine for writing a ref parameter. */
+private int near
+ref_param_write(iparam_list *plist, gs_param_name pkey, const ref *pvalue)
+{ ref kref;
+ int code;
+ if ( !ref_param_requested((gs_param_list *)plist, pkey) )
+ return 0;
+ code = ref_param_key(plist, pkey, &kref);
+ if ( code < 0 )
+ return code;
+ return (*plist->u.w.write)(plist, &kref, pvalue);
+}
+
+/* ---------------- Implementations ---------------- */
+
+/* Initialize for writing parameters. */
+private void near
+ref_param_write_init(iparam_list *plist, const ref *pwanted)
+{ if ( pwanted == 0 )
+ make_null(&plist->u.w.wanted);
+ else
+ plist->u.w.wanted = *pwanted;
+ plist->results = 0;
+ plist->int_keys = false;
+}
+
+/* Implementation for getting parameters to a stack. */
+private int
+stack_param_write(iparam_list *plist, const ref *pkey, const ref *pvalue)
+{
+#define splist ((stack_param_list *)plist)
+ ref_stack *pstack = splist->pstack;
+ s_ptr p = pstack->p;
+ if ( pstack->top - p < 2 )
+ { int code = ref_stack_push(pstack, 2);
+ if ( code < 0 )
+ return code;
+ *ref_stack_index(pstack, 1) = *pkey;
+ p = pstack->p;
+ }
+ else
+ { pstack->p = p += 2;
+ p[-1] = *pkey;
+ }
+ *p = *pvalue;
+ splist->count++;
+#undef splist
+ return 0;
+}
+
+/* Implementation for enumerating parameters on a stack */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+stack_param_enumerate(iparam_list *plist, gs_param_key_t *key, ref_type *type)
+{ int code;
+ stack_param_list * const pslist = (stack_param_list *)plist;
+ int enumerator = key->enumerator.intval;
+ ref *stack_element;
+ do
+ { stack_element = ref_stack_index
+ ( pslist->pstack, enumerator + 1 + pslist->skip );
+ if (!stack_element)
+ return 1;
+ }
+ while ( enumerator += 2, !r_has_type(stack_element, t_name) );
+ *type = r_type(stack_element);
+ code = ref_to_key(stack_element, key);
+ key->enumerator.intval = enumerator;
+ return code;
+}
+
+int
+stack_param_list_write(stack_param_list *plist, ref_stack *pstack,
+ const ref *pwanted)
+{ plist->procs = &ref_write_procs;
+ plist->u.w.write = stack_param_write;
+ ref_param_write_init((iparam_list *)plist, pwanted);
+ plist->enumerate = stack_param_enumerate;
+ plist->pstack = pstack;
+ plist->skip = 0;
+ plist->count = 0;
+ return 0;
+}
+
+/* Implementation for getting parameters to a dictionary. */
+private int
+dict_param_write(iparam_list *plist, const ref *pkey, const ref *pvalue)
+{ int code = dict_put(&((dict_param_list *)plist)->dict, pkey, pvalue);
+ return min(code, 0);
+}
+
+/* Implementation for enumerating parameters in a dictionary */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+dict_param_enumerate(iparam_list *plist, gs_param_key_t *key, ref_type *type)
+{ ref elt[2];
+ int code;
+ dict_param_list * const pdlist = (dict_param_list *)plist;
+ int enumerator = key->enumerator.intval != 0
+ ? key->enumerator.intval : dict_first(&pdlist->dict);
+ enumerator = dict_next(&pdlist->dict, enumerator, elt);
+ if (enumerator < 0)
+ return 1;
+ *type = r_type(&elt[1]);
+ code = ref_to_key(&elt[1], key);
+ key->enumerator.intval = enumerator;
+ return code;
+}
+
+int
+dict_param_list_write(dict_param_list *plist, ref *pdict,
+ const ref *pwanted)
+{ check_dict_write(*pdict);
+ plist->procs = &ref_write_procs;
+ plist->u.w.write = dict_param_write;
+ plist->enumerate = dict_param_enumerate;
+ ref_param_write_init((iparam_list *)plist, pwanted);
+ plist->dict = *pdict;
+ return 0;
+}
+
+/* ================ Reading refs to parameters ================ */
+
+/* ---------------- Generic reading procedures ---------------- */
+
+private param_proc_xmit_null(ref_param_read_null);
+private param_proc_xmit_typed(ref_param_read_typed);
+private param_proc_xmit_bool(ref_param_read_bool);
+private param_proc_xmit_int(ref_param_read_int);
+private param_proc_xmit_long(ref_param_read_long);
+private param_proc_xmit_float(ref_param_read_float);
+private param_proc_xmit_string(ref_param_read_string);
+private param_proc_xmit_int_array(ref_param_read_int_array);
+private param_proc_xmit_float_array(ref_param_read_float_array);
+private param_proc_xmit_string_array(ref_param_read_string_array);
+private param_proc_begin_xmit_dict(ref_param_begin_read_dict);
+private param_proc_end_xmit_dict(ref_param_end_read_dict);
+/*private param_proc_next_key(ref_param_get_next_key); already dec'ld above */
+private param_proc_get_policy(ref_param_read_get_policy);
+private param_proc_signal_error(ref_param_read_signal_error);
+private param_proc_commit(ref_param_read_commit);
+private const gs_param_list_procs ref_read_procs = {
+ ref_param_read_null,
+ ref_param_read_typed,
+ ref_param_read_bool,
+ ref_param_read_int,
+ ref_param_read_long,
+ ref_param_read_float,
+ ref_param_read_string,
+ ref_param_read_string, /* name = string */
+ ref_param_read_int_array,
+ ref_param_read_float_array,
+ ref_param_read_string_array,
+ ref_param_read_string_array, /* name = string */
+ ref_param_begin_read_dict,
+ ref_param_end_read_dict,
+ ref_param_get_next_key,
+ NULL, /* requested */
+ ref_param_read_get_policy,
+ ref_param_read_signal_error,
+ ref_param_read_commit
+};
+private int near ref_param_read(P4(iparam_list *, gs_param_name,
+ iparam_loc *, int));
+private int near ref_param_read_string_value(P2(const iparam_loc *,
+ gs_param_string *));
+private int near ref_param_read_array(P3(iparam_list *, gs_param_name,
+ iparam_loc *));
+#define iparam_return_error(loc, code)\
+ return_error(*(loc).presult = code)
+#define iparam_check_type(loc, typ)\
+ if ( !r_has_type((loc).pvalue, typ) )\
+ iparam_return_error(loc, e_typecheck)
+#define iparam_check_read(loc)\
+ if ( !r_has_attr((loc).pvalue, a_read) )\
+ iparam_return_error(loc, e_invalidaccess)
+
+private int
+ref_param_read_null(gs_param_list *plist, gs_param_name pkey)
+{ iparam_loc loc;
+ return ref_param_read(iplist, pkey, &loc, t_null);
+}
+private int
+ref_param_read_typed(gs_param_list *plist, gs_param_name pkey,
+ gs_param_typed_value *pvalue)
+{ iparam_loc loc;
+ ref elt;
+ int code = ref_param_read(iplist, pkey, &loc, -1);
+ if ( code != 0 )
+ return code;
+ switch ( r_type(loc.pvalue) )
+ {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ iparam_check_read(loc);
+ if ( r_size(loc.pvalue) <= 0 )
+ { /* 0-length array; can't get type info */
+ pvalue->type = cpt_int_array;
+ return ref_param_read_int_array(plist, pkey, &pvalue->value.ia);
+ }
+
+ /* Get array type based on type of 1st element of array */
+ array_get(loc.pvalue, 0, &elt);
+ switch ( r_type(&elt) ) /* redundant key lookup, but cached */
+ {
+ case t_integer:
+ pvalue->type = cpt_int_array;
+ return ref_param_read_int_array(plist, pkey, &pvalue->value.ia);
+ case t_real:
+ pvalue->type = cpt_float_array;
+ return ref_param_read_float_array(plist, pkey, &pvalue->value.fa);
+ case t_string:
+ pvalue->type = cpt_string_array;
+ return ref_param_read_string_array(plist, pkey, &pvalue->value.sa);
+ case t_name:
+ pvalue->type = cpt_name_array;
+ return ref_param_read_string_array(plist, pkey, &pvalue->value.na);
+ default:
+ break;
+ }
+ return gs_note_error(e_typecheck);
+ case t_boolean:
+ pvalue->type = cpt_bool;
+ pvalue->value.b = loc.pvalue->value.boolval;
+ return 0;
+ case t_dictionary:
+ code
+ = ref_param_begin_read_dict(plist, pkey, &pvalue->value.d, 0);
+ if (code < 0)
+ return code;
+ pvalue->type = cpt_dict;
+
+ /* fixup new dict's type & int_keys field if contents have int keys */
+ { gs_param_key_t key;
+ ref_type keytype;
+ param_init_enumerator(&key.enumerator); /* pick a key, any key... */
+ if ( !( *( (iparam_list *)plist )->enumerate )
+ ( (iparam_list *)pvalue->value.d.list, &key, &keytype )
+ && keytype == t_integer )
+ { ( (dict_param_list *)pvalue->value.d.list )->int_keys = 1;
+ pvalue->type = cpt_dict_int_keys;
+ }
+ }
+ return 0;
+ case t_integer:
+ pvalue->type = cpt_long;
+ pvalue->value.l = loc.pvalue->value.intval;
+ return 0;
+ case t_name:
+ pvalue->type = cpt_name;
+ return ref_param_read_string_value(&loc, &pvalue->value.n);
+ case t_null:
+ pvalue->type = cpt_null;
+ return 0;
+ case t_real:
+ pvalue->value.f = loc.pvalue->value.realval;
+ pvalue->type = cpt_float;
+ return 0;
+ case t_string:
+ pvalue->type = cpt_string;
+ return ref_param_read_string_value(&loc, &pvalue->value.s);
+ default:
+ break;
+ }
+ return gs_note_error(e_typecheck);
+}
+private int
+ref_param_read_bool(gs_param_list *plist, gs_param_name pkey, bool *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read(iplist, pkey, &loc, t_boolean);
+ if ( code != 0 )
+ return code;
+ *pvalue = loc.pvalue->value.boolval;
+ return 0;
+}
+private int
+ref_param_read_int(gs_param_list *plist, gs_param_name pkey, int *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read(iplist, pkey, &loc, t_integer);
+ if ( code != 0 )
+ return code;
+#if arch_sizeof_int < arch_sizeof_long
+ if ( loc.pvalue->value.intval != (int)loc.pvalue->value.intval )
+ return_error(e_rangecheck);
+#endif
+ *pvalue = (int)loc.pvalue->value.intval;
+ return 0;
+}
+private int
+ref_param_read_long(gs_param_list *plist, gs_param_name pkey, long *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read(iplist, pkey, &loc, t_integer);
+ if ( code != 0 )
+ return code;
+ *pvalue = loc.pvalue->value.intval;
+ return 0;
+}
+private int
+ref_param_read_float(gs_param_list *plist, gs_param_name pkey, float *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read(iplist, pkey, &loc, -1);
+ if ( code != 0 )
+ return code;
+ switch ( r_type(loc.pvalue) )
+ {
+ case t_integer:
+ *pvalue = loc.pvalue->value.intval;
+ break;
+ case t_real:
+ *pvalue = loc.pvalue->value.realval;
+ break;
+ default:
+ iparam_return_error(loc, e_typecheck);
+ }
+ return 0;
+}
+private int
+ref_param_read_string(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read(iplist, pkey, &loc, -1);
+ if ( code != 0 )
+ return code;
+ return ref_param_read_string_value(&loc, pvalue);
+}
+private int
+ref_param_read_int_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_int_array *pvalue)
+{ iparam_loc loc;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ int *piv;
+ uint size;
+ long i;
+
+ if ( code != 0 )
+ return code;
+ size = r_size(loc.pvalue);
+ piv = (int *)ialloc_byte_array(size, sizeof(int),
+ "ref_param_read_int_array");
+ if ( piv == 0 )
+ return_error(e_VMerror);
+ for ( i = 0; i < size; i++ )
+ { ref elt;
+
+ array_get(loc.pvalue, i, &elt);
+ if ( !r_has_type(&elt, t_integer) )
+ { code = gs_note_error(e_typecheck); break; }
+#if arch_sizeof_int < arch_sizeof_long
+ if ( elt.value.intval != (int)elt.value.intval )
+ { code = gs_note_error(e_rangecheck); break; }
+#endif
+ piv[i] = (int)elt.value.intval;
+ }
+ if ( code < 0 )
+ { ifree_object(piv, "ref_param_read_int_array");
+ return (*loc.presult = code);
+ }
+ pvalue->data = piv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_read_float_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_float_array *pvalue)
+{ iparam_loc loc;
+ ref aref, elt;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ float *pfv;
+ uint size;
+ long i;
+
+ if ( code != 0 )
+ return code;
+ size = r_size(loc.pvalue);
+ pfv = (float *)ialloc_byte_array(size, sizeof(float),
+ "ref_param_read_float_array");
+ if ( pfv == 0 )
+ return_error(e_VMerror);
+ aref = *loc.pvalue;
+ loc.pvalue = &elt;
+ for ( i = 0; code >= 0 && i < size; i++ )
+ { array_get(&aref, i, &elt);
+ code = float_param(&elt, pfv + i);
+ }
+ if ( code < 0 )
+ { ifree_object(pfv, "ref_read_float_array_param");
+ return (*loc.presult = code);
+ }
+ pvalue->data = pfv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_read_string_array(gs_param_list *plist, gs_param_name pkey,
+ gs_param_string_array *pvalue)
+{ iparam_loc loc;
+ ref aref, elt;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ gs_param_string *psv;
+ uint size;
+ long i;
+
+ if ( code != 0 )
+ return code;
+ size = r_size(loc.pvalue);
+ psv =
+ (gs_param_string *)ialloc_byte_array(size, sizeof(gs_param_string),
+ "ref_param_read_string_array");
+ if ( psv == 0 )
+ return_error(e_VMerror);
+ aref = *loc.pvalue;
+ loc.pvalue = &elt;
+ for ( i = 0; code >= 0 && i < size; i++ )
+ { array_get(&aref, i, &elt);
+ code = ref_param_read_string_value(&loc, psv + i);
+ }
+ if ( code < 0 )
+ { ifree_object(psv, "ref_param_read_string_array");
+ return (*loc.presult = code);
+ }
+ pvalue->data = psv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_begin_read_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue, bool int_keys)
+{ iparam_loc loc;
+ dict_param_list *dlist =
+ (dict_param_list *)ialloc_bytes(size_of(dict_param_list),
+ "ref_param_begin_read_dict");
+ int code = ref_param_read(iplist, pkey, &loc, t_dictionary);
+
+ if ( code != 0 )
+ return code;
+ code = dict_param_list_read(dlist, loc.pvalue, NULL, false);
+ if ( code < 0 )
+ iparam_return_error(loc, code);
+ dlist->int_keys = int_keys;
+ pvalue->list = (gs_param_list *)dlist;
+ pvalue->size = dict_length(loc.pvalue);
+ return 0;
+}
+private int
+ref_param_end_read_dict(gs_param_list *plist, gs_param_name pkey,
+ gs_param_dict *pvalue)
+{ iparam_list_release((dict_param_list *)pvalue->list);
+ ifree_object(pvalue->list, "ref_param_end_read_dict");
+ return 0;
+}
+private int
+ref_param_read_get_policy(gs_param_list *plist, gs_param_name pkey)
+{ ref kname;
+ ref *pvalue;
+ /* We can't use dict_find_string directly here, because */
+ /* pkey might not be a _ds string. */
+ if ( !(r_has_type(&iplist->u.r.policies, t_dictionary) &&
+ name_ref((const byte *)pkey, strlen(pkey), &kname, -1) >= 0 &&
+ dict_find(&iplist->u.r.policies, &kname, &pvalue) > 0 &&
+ r_has_type(pvalue, t_integer))
+ )
+ return gs_param_policy_ignore;
+ return (int)pvalue->value.intval;
+}
+private int
+ref_param_read_signal_error(gs_param_list *plist, gs_param_name pkey, int code)
+{ iparam_loc loc;
+ ref_param_read(iplist, pkey, &loc, -1); /* can't fail */
+ *loc.presult = code;
+ switch ( ref_param_read_get_policy(plist, pkey) )
+ {
+ case gs_param_policy_ignore:
+ return 0;
+ case gs_param_policy_consult_user:
+ return_error(e_configurationerror);
+ default:
+ return code;
+ }
+}
+private int
+ref_param_read_commit(gs_param_list *plist)
+{ int i;
+ int ecode = 0;
+ if ( !iplist->u.r.require_all )
+ return 0;
+ /* Check to make sure that all parameters were actually read. */
+ for ( i = 0; i < iplist->count; ++i )
+ if ( iplist->results[i] == 0 )
+ iplist->results[i] = ecode = gs_note_error(e_undefined);
+ return ecode;
+}
+private int
+ref_param_get_next_key(gs_param_list *plist, gs_param_key_t *key)
+{ ref_type keytype; /* result not needed here */
+ iparam_list * const pilist = (iparam_list *)plist;
+ return (*pilist->enumerate)(pilist, key, &keytype);
+}
+
+
+/* ---------------- Internal routines ---------------- */
+
+/* Read a string value. */
+private int near
+ref_param_read_string_value(const iparam_loc *ploc, gs_param_string *pvalue)
+{ const ref *pref = ploc->pvalue;
+ ref nref;
+ switch ( r_type(pref) )
+ {
+ case t_name:
+ name_string_ref(pref, &nref);
+ pref = &nref;
+ pvalue->persistent = true;
+ goto s;
+ case t_string:
+ iparam_check_read(*ploc);
+ pvalue->persistent = false;
+s: pvalue->data = pref->value.const_bytes;
+ pvalue->size = r_size(pref);
+ break;
+ default:
+ iparam_return_error(*ploc, e_typecheck);
+ }
+ return 0;
+}
+
+/* Read an array (or packed array) parameter. */
+private int near
+ref_param_read_array(iparam_list *plist, gs_param_name pkey, iparam_loc *ploc)
+{ int code = ref_param_read(plist, pkey, ploc, -1);
+
+ if ( code != 0 )
+ return code;
+ if ( !r_is_array(ploc->pvalue) )
+ iparam_return_error(*ploc, e_typecheck);
+ iparam_check_read(*ploc);
+ return 0;
+}
+
+/* Generic routine for reading a ref parameter. */
+private int near
+ref_param_read(iparam_list *plist, gs_param_name pkey, iparam_loc *ploc,
+ int type)
+{ ref kref;
+ int code = ref_param_key(plist, pkey, &kref);
+ if ( code < 0 )
+ return code;
+ code = (*plist->u.r.read)(iplist, &kref, ploc);
+ if ( code != 0 )
+ return code;
+ if ( type >= 0 )
+ iparam_check_type(*ploc, type);
+ return 0;
+}
+
+/* ---------------- Implementations ---------------- */
+
+/* Initialize for reading parameters. */
+private int
+ref_param_read_init(iparam_list *plist, uint count, const ref *ppolicies,
+ bool require_all)
+{ if ( ppolicies == 0 )
+ make_null(&plist->u.r.policies);
+ else
+ plist->u.r.policies = *ppolicies;
+ plist->u.r.require_all = require_all;
+ plist->count = count;
+ plist->results =
+ (int *)ialloc_byte_array(count, sizeof(int), "ref_param_read_init");
+ if ( plist->results == 0 )
+ return_error(e_VMerror);
+ memset(plist->results, 0, count * sizeof(int));
+ plist->int_keys = false;
+ return 0;
+}
+
+/* Implementation for putting parameters from an array. */
+private int
+array_param_read(iparam_list *plist, const ref *pkey, iparam_loc *ploc)
+{ ref *bot = ((array_param_list *)plist)->bot;
+ ref *ptr = bot;
+ ref *top = ((array_param_list *)plist)->top;
+ for ( ; ptr < top; ptr += 2 )
+ { if ( r_has_type(ptr, t_name) && name_eq(ptr, pkey) )
+ { ploc->pvalue = ptr + 1;
+ ploc->presult = &plist->results[ptr - bot];
+ *ploc->presult = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Implementation for enumerating parameters in an array */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+array_param_enumerate(iparam_list *plist, gs_param_key_t *key, ref_type *type)
+{ int enumerator = key->enumerator.intval;
+ ref *bot = ((array_param_list *)plist)->bot;
+ ref *ptr = bot + enumerator;
+ ref *top = ((array_param_list *)plist)->top;
+ for ( ; ptr < top; ptr += 2 )
+ { enumerator += 2;
+ if ( r_has_type(ptr, t_name) )
+ { int code = ref_to_key(ptr, key);
+ *type = r_type(ptr);
+ key->enumerator.intval = enumerator;
+ return code;
+ }
+ }
+ return 1;
+}
+
+int
+array_param_list_read(array_param_list *plist, ref *bot, uint count,
+ const ref *ppolicies, bool require_all)
+{ if ( count & 1 )
+ return_error(e_rangecheck);
+ plist->procs = &ref_read_procs;
+ plist->u.r.read = array_param_read;
+ plist->enumerate = array_param_enumerate;
+ plist->bot = bot;
+ plist->top = bot + count;
+ return ref_param_read_init(iplist, count, ppolicies, require_all);
+}
+
+/* Implementation for putting parameters from a stack. */
+private int
+stack_param_read(iparam_list *plist, const ref *pkey, iparam_loc *ploc)
+{
+#define splist ((stack_param_list *)plist)
+ ref_stack *pstack = splist->pstack;
+ /* This implementation is slow, but it probably doesn't matter. */
+ uint index = splist->skip + 1;
+ uint count = splist->count;
+ for ( ; count; count--, index += 2 )
+ { const ref *p = ref_stack_index(pstack, index);
+ if ( r_has_type(p, t_name) && name_eq(p, pkey) )
+ { ploc->pvalue = ref_stack_index(pstack, index - 1);
+ ploc->presult = &plist->results[count - 1];
+ *ploc->presult = 1;
+ return 0;
+ }
+ }
+#undef splist
+ return 1;
+}
+int
+stack_param_list_read(stack_param_list *plist, ref_stack *pstack, uint skip,
+ const ref *ppolicies, bool require_all)
+{ uint count = ref_stack_counttomark(pstack);
+ if ( count == 0 )
+ return_error(e_unmatchedmark);
+ count -= skip + 1;
+ if ( count & 1 )
+ return_error(e_rangecheck);
+ plist->procs = &ref_read_procs;
+ plist->u.r.read = stack_param_read;
+ plist->enumerate = stack_param_enumerate;
+ plist->pstack = pstack;
+ plist->skip = skip;
+ return ref_param_read_init(iplist, count >> 1, ppolicies, require_all);
+}
+
+/* Implementation for putting parameters from a dictionary. */
+private int
+dict_param_read(iparam_list *plist, const ref *pkey, iparam_loc *ploc)
+{
+#define spdict (&((dict_param_list *)plist)->dict)
+ int code = dict_find(spdict, pkey, &ploc->pvalue);
+ if ( code != 1 )
+ return 1;
+ ploc->presult = &plist->results[dict_value_index(spdict, ploc->pvalue)];
+#undef spdict
+ *ploc->presult = 1;
+ return 0;
+}
+int
+dict_param_list_read(dict_param_list *plist, const ref *pdict,
+ const ref *ppolicies, bool require_all)
+{ check_dict_read(*pdict);
+ plist->procs = &ref_read_procs;
+ plist->u.r.read = dict_param_read;
+ plist->enumerate = dict_param_enumerate;
+ plist->dict = *pdict;
+ return ref_param_read_init(iplist, dict_max_index(pdict) + 1,
+ ppolicies, require_all);
+}
diff --git a/gs/src/iparam.h b/gs/src/iparam.h
new file mode 100644
index 000000000..b03e0f203
--- /dev/null
+++ b/gs/src/iparam.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iparam.h */
+/* Interpreter-level implementations of parameter dictionaries */
+/* Requires istack.h */
+#include "gsparam.h"
+
+/*
+ * This file defines the interface to iparam.c, which provides
+ * several implementations of the parameter dictionary interface
+ * defined in gsparam.h:
+ * - an implementation using dictionary objects;
+ * - an implementation using name/value pairs in an array;
+ * - an implementation using name/value pairs on a stack.
+ *
+ * When reading ('putting'), these implementations keep track of
+ * which parameters have been referenced and which have caused errors.
+ * The results array contains 0 for a parameter that has not been accessed,
+ * 1 for a parameter accessed without error, or <0 for an error.
+ */
+
+typedef struct iparam_loc_s {
+ ref *pvalue; /* (actually const) */
+ int *presult;
+} iparam_loc;
+
+#define iparam_list_common\
+ gs_param_list_common;\
+ union {\
+ struct { /* reading */\
+ int (*read)(P3(iparam_list *, const ref *, iparam_loc *));\
+ ref policies; /* policy dictionary or null */\
+ bool require_all; /* if true, require all params to be known */\
+ } r;\
+ struct { /* writing */\
+ int (*write)(P3(iparam_list *, const ref *, const ref *));\
+ ref wanted; /* desired keys or null */\
+ } w;\
+ } u;\
+ int (*enumerate)(P3(iparam_list *, gs_param_key_t *, ref_type *));\
+ int *results; /* (only used when reading, 0 when writing) */\
+ uint count; /* # of key/value pairs */\
+ bool int_keys /* if true, keys are integers */
+typedef struct iparam_list_s iparam_list;
+struct iparam_list_s {
+ iparam_list_common;
+};
+
+typedef struct dict_param_list_s {
+ iparam_list_common;
+ ref dict;
+} dict_param_list;
+typedef struct array_param_list_s {
+ iparam_list_common;
+ ref *bot;
+ ref *top;
+} array_param_list;
+/* For stack lists, the bottom of the list is just above a mark. */
+typedef struct stack_param_list_s {
+ iparam_list_common;
+ ref_stack *pstack;
+ uint skip; /* # of top items to skip (reading only) */
+} stack_param_list;
+
+/* Procedural interface */
+/*
+ * The const ref * parameter is the policies dictionary when reading,
+ * or the key selection dictionary when writing; It may be NULL in either case.
+ * If the bool parameter is true, if there are any unqueried parameters,
+ * the commit procedure will return an e_undefined error.
+ */
+int dict_param_list_read(P4(dict_param_list *, const ref * /*t_dictionary*/,
+ const ref *, bool));
+int dict_param_list_write(P3(dict_param_list *, ref * /*t_dictionary*/,
+ const ref *));
+int array_param_list_read(P5(array_param_list *, ref *, uint,
+ const ref *, bool));
+int stack_param_list_read(P5(stack_param_list *, ref_stack *, uint,
+ const ref *, bool));
+int stack_param_list_write(P3(stack_param_list *, ref_stack *,
+ const ref *));
+#define iparam_list_release(plist)\
+ ifree_object((plist)->results, "iparam_list_release")
diff --git a/gs/src/iparray.h b/gs/src/iparray.h
new file mode 100644
index 000000000..71517a12b
--- /dev/null
+++ b/gs/src/iparray.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iparray.h */
+/* Packed array constructor for Ghostscript */
+
+/*
+ * The only reason to put this in a separate header is that it requires
+ * both ipacked.h and istack.h; putting it in either one would make it
+ * depend on the other one. There must be a better way....
+ */
+
+/* Procedures implemented in zpacked.c */
+
+/* Make a packed array from the top N elements of a stack. */
+int make_packed_array(P4(ref *, ref_stack *, uint, client_name_t));
diff --git a/gs/src/ireclaim.c b/gs/src/ireclaim.c
new file mode 100644
index 000000000..b57f69c28
--- /dev/null
+++ b/gs/src/ireclaim.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ireclaim.c */
+/* Interpreter's interface to garbage collector */
+#include "ghost.h"
+#include "errors.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "dstack.h" /* for dsbot, dsp, dict_set_top */
+#include "estack.h" /* for esbot, esp */
+#include "ostack.h" /* for osbot, osp */
+#include "opdef.h" /* for defining init procedure */
+#include "store.h" /* for make_array */
+
+/* Import the static interpreter refs from interp.c. */
+extern ref ref_static_stacks;
+extern ref ref_ref_stacks[3];
+
+/* Import preparation and cleanup routines. */
+extern void file_gc_prepare(P0());
+extern void dstack_gc_cleanup(P0());
+
+/* Forward references */
+private void gs_vmreclaim(P2(gs_dual_memory_t *, bool));
+
+/* Initialize the GC hook in the allocator. */
+private int ireclaim(P2(gs_dual_memory_t *, int));
+private void
+ireclaim_init(void)
+{ gs_imemory.reclaim = ireclaim;
+}
+
+/* GC hook called when the allocator returns a VMerror (space = -1), */
+/* or for vmreclaim (space = the space to collect). */
+private int
+ireclaim(gs_dual_memory_t *dmem, int space)
+{ bool global;
+ gs_ref_memory_t *mem;
+ if ( space < 0 )
+ { /* Determine which allocator got the VMerror. */
+ gs_memory_status_t stats;
+ int i;
+ mem = dmem->space_global; /* just in case */
+ for ( i = 0; i < countof(dmem->spaces.indexed); ++i )
+ { mem = dmem->spaces.indexed[i];
+ if ( mem == 0 )
+ continue;
+ if ( mem->gc_status.requested > 0 )
+ break;
+ }
+ gs_memory_status((gs_memory_t *)mem, &stats);
+ if ( stats.allocated >= mem->gc_status.max_vm )
+ { /* We can't satisfy this request within max_vm. */
+ return_error(e_VMerror);
+ }
+ }
+ else
+ { mem = dmem->spaces.indexed[space >> r_space_shift];
+ }
+ if_debug3('0', "[0]GC called, space=%d, requestor=%d, requested=%ld\n",
+ space, mem->space, (long)mem->gc_status.requested);
+ global = mem->space != avm_local;
+ gs_vmreclaim(dmem, global);
+ ialloc_set_limit(mem);
+ ialloc_reset_requested(dmem);
+ return 0;
+}
+
+/* Interpreter entry to garbage collector. */
+/* This registers the stacks before calling the main GC. */
+private void near set_ref_chunk(P4(chunk_t *, ref *, ref *, gs_ref_memory_t *));
+private void
+gs_vmreclaim(gs_dual_memory_t *dmem, bool global)
+{ /*
+ * Create pseudo-chunks to hold the interpreter roots:
+ * copies of the ref_stacks, and, if necessary,
+ * the statically allocated stack bodies.
+ */
+ gs_ref_memory_t *lmem = dmem->space_local;
+ gs_ref_memory_t *gmem = dmem->space_global;
+ gs_ref_memory_t *smem = dmem->space_system;
+ struct ir_ {
+ chunk_head_t head;
+ obj_header_t prefix;
+ ref refs[5+1]; /* +1 for extra relocation ref */
+ } iroot_refs;
+ chunk_t cir, css;
+ void *piroot = &iroot_refs.refs[0];
+ gs_gc_root_t iroot;
+
+ alloc_close_chunk(lmem);
+ if ( gmem != lmem )
+ alloc_close_chunk(gmem);
+ alloc_close_chunk(smem);
+
+ /*
+ * Copy the ref_stacks into the heap, so we can trace and
+ * relocate them. Note that they are allocated in system VM.
+ */
+#define stkmem smem
+#define get_stack(i, stk)\
+ ref_stack_cleanup(&stk);\
+ iroot_refs.refs[i+2] = ref_ref_stacks[i],\
+ *r_ptr(&iroot_refs.refs[i+2], ref_stack) = stk
+ get_stack(0, d_stack);
+ get_stack(1, e_stack);
+ get_stack(2, o_stack);
+#undef get_stack
+
+ /* Make the root chunk. */
+ iroot_refs.refs[1] = ref_static_stacks;
+ make_array(&iroot_refs.refs[0], avm_system, 4, &iroot_refs.refs[1]);
+ set_ref_chunk(&cir, &iroot_refs.refs[0], &iroot_refs.refs[5], stkmem);
+ gs_register_ref_root((gs_memory_t *)stkmem, &iroot, &piroot,
+ "gs_gc_main");
+
+ /* If necessary, make the static stack chunk. */
+#define css_array iroot_refs.refs[1]
+#define css_base css_array.value.refs
+ if ( css_base != NULL )
+ set_ref_chunk(&css, css_base, css_base + r_size(&css_array), stkmem);
+
+ /* Prune the file list so it won't retain potentially collectible */
+ /* files. */
+ file_gc_prepare();
+
+ /* Do the actual collection. */
+ gs_reclaim(&dmem->spaces, global);
+
+ /* Remove the temporary chunks. */
+ if ( css_base != NULL )
+ alloc_unlink_chunk(&css, stkmem);
+ gs_unregister_root((gs_memory_t *)stkmem, &iroot, "gs_gc_main");
+ alloc_unlink_chunk(&cir, stkmem);
+#undef css_array
+#undef css_base
+
+ /* Update the static copies of the ref_stacks. */
+#define put_stack(i, stk)\
+ ref_ref_stacks[i].value.pstruct = iroot_refs.refs[i+2].value.pstruct,\
+ stk = *r_ptr(&iroot_refs.refs[i+2], ref_stack)
+ put_stack(0, d_stack);
+ put_stack(1, e_stack);
+ put_stack(2, o_stack);
+#undef put_stack
+#undef stkmem
+
+ /* Update the cached value pointers in names. */
+
+ dstack_gc_cleanup();
+
+ /* Reopen the active chunks. */
+
+ alloc_open_chunk(smem);
+ if ( gmem != lmem )
+ alloc_open_chunk(gmem);
+ alloc_open_chunk(lmem);
+
+ /* Update caches */
+
+ { uint dcount = ref_stack_count(&d_stack);
+ ref_systemdict = *ref_stack_index(&d_stack, dcount - 1);
+ }
+ dict_set_top();
+}
+private void near
+set_ref_chunk(chunk_t *cp, ref *bot, ref *top, gs_ref_memory_t *mem)
+{ obj_header_t *pre = (obj_header_t *)bot - 1;
+ chunk_head_t *head = (chunk_head_t *)pre - 1;
+ pre->o_large = 1; /* not relocatable */
+ pre->o_lsize = 0;
+ pre->o_lmark = o_l_unmarked;
+ pre->o_size = (byte *)(top + 1) - (byte *)bot;
+ pre->o_type = &st_refs;
+ alloc_init_chunk(cp, (byte *)head, (byte *)(top + 1), false, NULL); /* +1 for extra reloc ref */
+ cp->cbot = cp->ctop;
+ alloc_link_chunk(cp, mem);
+ make_int(top, 0); /* relocation ref */
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(ireclaim_l2_op_defs) {
+END_OP_DEFS(ireclaim_init) }
diff --git a/gs/src/iref.h b/gs/src/iref.h
new file mode 100644
index 000000000..f4374d4ab
--- /dev/null
+++ b/gs/src/iref.h
@@ -0,0 +1,376 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iref.h */
+/* Object structure and type definitions for Ghostscript */
+
+#ifndef iref_INCLUDED
+# define iref_INCLUDED
+
+/* The typedef for object references */
+typedef struct ref_s ref;
+
+/* The typedef for packed object references. This is opaque here: */
+/* the details are in packed.h. */
+typedef ushort ref_packed;
+#define log2_sizeof_ref_packed arch_log2_sizeof_short
+#define sizeof_ref_packed (1 << log2_sizeof_ref_packed)
+
+/*
+ * Define the object types.
+ * The types marked with @ are composite and hence use the a_space field;
+ * objects of all other types must have a_space cleared.
+ * The types marked with ! behave differently in the interpreter
+ * depending on whether they are executable or literal.
+ * The types marked with + use the read/write/execute
+ * attributes; the rest only use the executable attribute.
+ * The types marked with # use the size field.
+ */
+typedef enum {
+
+/*
+ * Type 0 must be left unassigned, so that the type (and type_attrs)
+ * of a valid ref will never be zero. This speeds up simultaneous
+ * type/space checking in def (see dstack.h for details) and a similar
+ * check in ref_save (see store.h for details). We may as well use
+ * type 0 for t__invalid, which will never appear in a real ref.
+ *
+ * The "invalid" type is only used in a few special places: the guard
+ * entries at the bottom of the o-stack that detect stack underflow,
+ * and (eventually) the ref that the cached value pointer in names points to
+ * if the binding isn't known. It never appears on a stack or in a
+ * program-visible data structure.
+ */
+
+ t__invalid, /* (no value) */
+ t_boolean, /* value.boolval */
+ t_dictionary, /* @ + value.pdict */
+ t_file, /* @!+# value.pfile, uses size for id */
+
+/*
+ * The 4 array types must be kept together, and must start at
+ * a multiple of 4, for the sake of r_is_array and r_is_proc (see below).
+ */
+
+#define _t_array_span 4
+ t_array, /* @!+# value.refs */
+ /* The following are the two implementations of */
+ /* packed arrays. */
+ t_mixedarray, /* @!+# value.packed */
+ t_shortarray, /* @!+# value.packed */
+ t_unused_array_, /* (an unused array type) */
+
+/*
+ * t_[a]struct is an "umbrella" for other types that are represented by
+ * allocated objects (structures). Objects of these types are composite
+ * and hence use the a_local attribute. The type name is taken from
+ * the allocator template for the structure. t_astruct objects use the
+ * access attributes; t_struct objects do not. Neither t_struct nor
+ * t_astruct objects use the size.
+ *
+ * t_struct is currently used for the following PostScript types:
+ * condition, lock.
+ * We could use it for fontIDs, except that they may have subclasses.
+ * Eventually it will also be used for the new 'device' type.
+ * t_astruct is currently used for the following PostScript types:
+ * gstate.
+ *
+ * The 2 structure types must be kept together, and must start at
+ * a multiple of 2, for the sake of r_has_stype (see below).
+ */
+
+#define _t_struct_span 2
+ t_struct, /* @ value.pstruct */
+ t_astruct, /* @ + value.pstruct */
+
+/*
+ * We now continue with individual types.
+ */
+ t_fontID, /* @ value.pstruct */
+ t_integer, /* value.intval */
+ t_mark, /* (no value) */
+/*
+ * Name objects use the a_space field because they really are composite
+ * objects internally.
+ */
+ t_name, /* @! # value.pname, uses size for index */
+ t_null, /* ! # (value.opproc, uses size for mark */
+ /* type, on e-stack only) */
+/*
+ * Operator objects use the a_space field because they may actually be
+ * disguised procedures. (Real operators always have a_space = 0.)
+ */
+ t_operator, /* @! # value.opproc, uses size for index */
+ t_real, /* value.realval */
+ t_save, /* value.saveid, see isave.h for why */
+ /* this isn't a t_struct */
+ t_string, /* @!+# value.bytes */
+/*
+ * The following are extensions to the PostScript type set.
+ * When adding new types, be sure to edit the table in gs_init.ps
+ * (==only operator), the printing routine in idebug.c, the dispatches
+ * in igc.c, igcref.c, and interp.c, obj_eq in iutil.c, restore_check_stack
+ * in zvmem.c, and also type_name_strings and type_print_strings below.
+ */
+ t_device, /* @ + value.pdevice */
+ t_oparray, /* @! # value.const_refs, uses size */
+ /* for index */
+ t_next_index /*** first available index ***/
+} ref_type;
+/*
+ * The interpreter uses types starting at t_next_index for representing
+ * a few high-frequency operators.
+ * Since there are no operations specifically on operators,
+ * there is no need for any operators to check specifically for these
+ * types. The r_btype macro takes care of the conversion when required.
+ */
+/*extern const int tx_next_index;*/ /* in interp.c */
+/*
+ * Define the types that use the access attributes (w/r/x).
+ */
+#define case_types_with_access\
+ case t_dictionary: case t_file:\
+ case t_array: case t_mixedarray: case t_shortarray:\
+ case t_astruct: case t_string: case t_device
+/*
+ * Define the types that use the size field.
+ * (The extended types used by the interpreter also use the size field.)
+ * We don't include t_null here, because it only uses the size field
+ * on the e-stack.
+ */
+#define case_types_with_size\
+ case t_array: case t_mixedarray: case t_shortarray:\
+ case t_file: case t_name: case t_operator: case t_string:\
+ case t_oparray
+/*
+ * Define the type names for debugging printout.
+ * All names must be the same length, so that columns will line up.
+ */
+#define type_print_strings\
+ "INVL","bool","dict","file",\
+ "arry","mpry","spry","u?ry",\
+ "STRC","ASTR",\
+ "font","int ","mark","name","null",\
+ "oper","real","save","str ",\
+ "devc","opry"
+/*
+ * Define the type names for the type operator.
+ */
+#define type_name_strings\
+ 0,"booleantype","dicttype","filetype",\
+ "arraytype","packedarraytype","packedarraytype","arraytype",\
+ 0,0,\
+ "fonttype","integertype","marktype","nametype","nulltype",\
+ "operatortype","realtype","savetype","stringtype",\
+ "devicetype","operatortype"
+
+/*
+ * The following factors affect the encoding of attributes:
+ *
+ * - The packed array format requires the high-order bits of the
+ * type/attributes field to be 0. (see packed.h)
+ *
+ * - The interpreter wants the type, executable bit, and execute
+ * permission to be adjacent, and in that order from high to low.
+ *
+ * - Type testing is most efficient if the type is in a byte by itself.
+ *
+ * The layout given below results in the most efficient code overall.
+ */
+
+/* Location attributes. */
+/* Note that these are associated with the *location*, not with the */
+/* ref that is *stored* in that location. */
+#define l_mark 1 /* mark for garbage collector */
+#define l_new 2 /* stored into since last save */
+/* Attributes visible at the PostScript language level. */
+/* Reserve bits for VM space information (defined in ivmspace.h). */
+#define r_space_bits 2
+#define r_space_shift 2
+#define a_write 0x10
+#define a_read 0x20
+#define a_execute 0x40
+#define a_executable 0x80
+#define a_readonly (a_read+a_execute)
+#define a_all (a_write+a_read+a_execute)
+#define r_type_shift 8
+#define r_type_bits 6
+
+/* Define the attribute names for debugging printout. */
+/* Each entry has the form <mask, value, character>. */
+typedef struct attr_print_mask_s {
+ ushort mask;
+ ushort value;
+ char print;
+} attr_print_mask;
+#define attr_print_flag(m,c)\
+ {m,m,c},{m,0,'-'}
+#define attr_print_space(v,c)\
+ {((1<<r_space_bits)-1)<<r_space_shift,v,c}
+#define attr_print_masks\
+ attr_print_flag(l_mark,'m'),\
+ attr_print_flag(l_new,'n'),\
+ attr_print_space(avm_foreign,'F'),\
+ attr_print_space(avm_system,'S'),\
+ attr_print_space(avm_global,'G'),\
+ attr_print_space(avm_local,'L'),\
+ attr_print_flag(a_write,'w'),\
+ attr_print_flag(a_read,'r'),\
+ attr_print_flag(a_execute,'x'),\
+ attr_print_flag(a_executable,'e'),\
+ attr_print_flag(0x4000,'?'),\
+ attr_print_flag(0x8000,'?')
+
+/* Abstract types */
+typedef struct dict_s dict;
+typedef struct name_s name;
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+#endif
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+#ifndef obj_header_DEFINED
+# define obj_header_DEFINED
+typedef struct obj_header_s obj_header_t;
+#endif
+/* We duplicate the definition of os_ptr (a.k.a. s_ptr) here */
+/* so that we can have an accurate typedef for op_proc */
+/* without having to drag in istack.h and ostack.h. */
+typedef int (*op_proc_p)(P1(ref _ds *));
+/* real_opproc is a holdover.... */
+#define real_opproc(pref) ((pref)->value.opproc)
+
+/* Object reference */
+/*
+ * Note that because of the way packed arrays are represented,
+ * the type_attrs member must be the first one in the ref structure.
+ */
+struct tas_s {
+ ushort type_attrs;
+ ushort rsize;
+};
+struct ref_s {
+
+ struct tas_s tas;
+
+#define r_size(rp) ((rp)->tas.rsize)
+#define r_inc_size(rp,inc) ((rp)->tas.rsize += (inc))
+#define r_dec_size(rp,dec) ((rp)->tas.rsize -= (dec))
+#define r_set_size(rp,siz) ((rp)->tas.rsize = (siz))
+/* type_attrs is a single element for fast dispatching in the interpreter */
+#if r_type_shift == 8
+# if arch_is_big_endian
+# define r_type(rp) (((const byte *)&((rp)->tas.type_attrs))[sizeof(ushort)-2])
+# else
+# define r_type(rp) (((const byte *)&((rp)->tas.type_attrs))[1])
+# endif
+# define r_has_type(rp,typ) (r_type(rp) == (typ))
+#else
+# define r_type(rp) ((rp)->tas.type_attrs >> r_type_shift)
+# define r_has_type(rp,typ) r_has_type_attrs(rp,typ,0) /* see below */
+#endif
+/* A special macro for testing arrayhood. */
+#define r_is_array(rp) _r_has_masked_type_attrs(rp,t_array,_t_array_span,0)
+#define r_set_type(rp,typ) ((rp)->tas.type_attrs = (typ) << r_type_shift)
+#define r_btype(rp)\
+ ((rp)->tas.type_attrs >= (t_next_index << r_type_shift) ?\
+ t_operator : r_type(rp))
+#define r_type_xe_shift (r_type_shift - 2)
+#define type_xe_(tas) ((tas) >> r_type_xe_shift) /* internal use only */
+/*
+ * The r_type_xe macro is used in (and only in) the main interpreter loop,
+ * where its rp operand may be a ref_packed, not necessarily aligned as
+ * strictly as a full-size ref. The DEC C compiler, and possibly others,
+ * may compile code assuming that rp is ref-aligned. Therefore, we
+ * explicitly cast the pointer to a less-strictly-aligned type.
+ * In order to convince the compiler, we have to do the cast before
+ * indexing into the structure.
+ */
+#define r_type_xe(rp)\
+ type_xe_(((const ushort *)(rp))[offset_of(ref, tas.type_attrs) / sizeof(ushort)])
+#define type_xe_value(t,xe) type_xe_(((t) << r_type_shift) + (xe))
+#define r_type_attrs(rp) ((rp)->tas.type_attrs) /* reading only */
+#define r_has_attrs(rp,mask) !(~r_type_attrs(rp) & (mask))
+#define r_has_masked_attrs(rp,attrs,mask)\
+ ((r_type_attrs(rp) & (mask)) == (attrs))
+#define r_has_attr(rp,mask1) /* optimize 1-bit case */\
+ (r_type_attrs(rp) & (mask1))
+/* The following macro is not for external use. */
+#define _r_has_masked_type_attrs(rp,typ,tspan,mask)\
+ (((rp)->tas.type_attrs &\
+ ((((1 << r_type_bits) - (tspan)) << r_type_shift) + (mask))) ==\
+ (((typ) << r_type_shift) + (mask)))
+#define r_has_type_attrs(rp,typ,mask)\
+ _r_has_masked_type_attrs(rp,typ,1,mask)
+/* A special macro for testing procedurehood. */
+#define r_is_proc(rp)\
+ _r_has_masked_type_attrs(rp,t_array,_t_array_span,a_execute+a_executable)
+#define r_set_attrs(rp,mask) ((rp)->tas.type_attrs |= (mask))
+#define r_clear_attrs(rp,mask) ((rp)->tas.type_attrs &= ~(mask))
+#define r_store_attrs(rp,mask,attrs)\
+ ((rp)->tas.type_attrs = ((rp)->tas.type_attrs & ~(mask)) | (attrs))
+#define r_copy_attrs(rp,mask,sp)\
+ r_store_attrs(rp,mask,(sp)->tas.type_attrs & (mask))
+#define r_set_type_attrs(rp,typ,mask)\
+ ((rp)->tas.type_attrs = ((typ) << r_type_shift) + (mask))
+/* Macros for t_[a]struct objects. */
+#define r_is_struct(rp) _r_has_masked_type_attrs(rp,t_struct,_t_struct_span,0)
+#define r_has_stype(rp,mem,styp)\
+ (r_is_struct(rp) && gs_object_type(mem, (rp)->value.pstruct) == &styp)
+#define r_ptr(rp,typ) ((typ *)((rp)->value.pstruct))
+#define r_set_ptr(rp,ptr) ((rp)->value.pstruct = (obj_header_t *)(ptr))
+
+ union v { /* name the union to keep gdb happy */
+ long intval;
+ ushort boolval;
+ float realval;
+ ulong saveid;
+ byte *bytes;
+ const byte *const_bytes;
+ ref *refs;
+ const ref *const_refs;
+ name *pname;
+ const name *const_pname;
+ dict *pdict;
+ const dict *const_pdict;
+ const ref_packed *packed;
+ op_proc_p opproc;
+ struct stream_s *pfile;
+ struct gx_device_s *pdevice;
+ obj_header_t *pstruct;
+ } value;
+};
+
+/* Define the size of a ref. */
+#define arch_sizeof_ref sizeof(ref)
+/* Define the required alignment for refs. */
+/* We assume all alignment values are powers of 2. */
+#define arch_align_ref_mod\
+ (((arch_align_long_mod - 1) | (arch_align_float_mod - 1) |\
+ (arch_align_ptr_mod - 1)) + 1)
+
+/* Define the maximum size of an array or a string. */
+/* The maximum array size is determined by the fact that */
+/* the allocator cannot allocate a block larger than max_uint. */
+#define max_array_size (max_ushort & (max_uint / (uint)arch_sizeof_ref))
+#define max_string_size max_ushort
+
+#endif /* iref_INCLUDED */
diff --git a/gs/src/isave.c b/gs/src/isave.c
new file mode 100644
index 000000000..29dd8c76b
--- /dev/null
+++ b/gs/src/isave.c
@@ -0,0 +1,987 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* isave.c */
+/* Save/restore manager for Ghostscript interpreter */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "inamedef.h"
+#include "ipacked.h"
+#include "isave.h"
+#include "isstate.h"
+#include "store.h" /* for ref_assign */
+#include "ivmspace.h"
+#include "gsutil.h" /* gs_next_ids prototype */
+
+/* Imported restore routines */
+extern void file_save(P0());
+extern void file_restore(P2(const alloc_save_t *, const gs_memory_t *));
+extern void file_forget_save(P1(const alloc_save_t *));
+extern void font_restore(P1(const alloc_save_t *));
+
+/* Structure descriptor */
+private_st_alloc_save();
+
+/* Define the maximum amount of data we are willing to scan repeatedly -- */
+/* see below for details. */
+private const long max_repeated_scan = 100000;
+
+/* Some compilers try to substitute macro args in string literals! */
+#define print_save(str, spacen, sav)\
+ if_debug5('u', "[u]%s space %u 0x%lx: cdata = 0x%lx, id = %lu\n",\
+ str, spacen, (ulong)(sav), (ulong)(sav)->client_data, (ulong)(sav)->id);
+
+/*
+ * The logic for saving and restoring the state is complex.
+ * Both the changes to individual objects, and the overall state
+ * of the memory manager, must be saved and restored.
+ */
+
+/*
+ * To save the state of the memory manager:
+ * Save the state of the current chunk in which we are allocating.
+ * Shrink the current chunk to its inner unallocated region.
+ * Save and reset the free block chains.
+ * By doing this, we guarantee that no object older than the save
+ * can be freed.
+ *
+ * To restore the state of the memory manager:
+ * Free all chunks newer than the save, and the descriptor for
+ * the inner chunk created by the save.
+ * Make current the chunk that was current at the time of the save.
+ * Restore the state of the current chunk.
+ *
+ * In addition to save ("start transaction") and restore ("abort transaction"),
+ * we support forgetting a save ("commit transation"). To forget a save:
+ * Reassign to the next outer save all chunks newer than the save.
+ * Free the descriptor for the inner chunk, updating its outer chunk
+ * to reflect additional allocations in the inner chunk.
+ * Concatenate the free block chains with those of the outer save.
+ */
+
+/*
+ * For saving changes to individual objects, we add an "attribute" bit
+ * (l_new) that logically belongs to the slot where the ref is stored,
+ * not to the ref itself. The bit means "the contents of this slot
+ * have been changed, or the slot was allocated, since the last save."
+ * To keep track of changes since the save, we associate a chain of
+ * <slot, old_contents> pairs that remembers the old contents of slots.
+ *
+ * When creating an object, if the save level is non-zero:
+ * Set l_new in all slots.
+ *
+ * When storing into a slot, if the save level is non-zero:
+ * If l_new isn't set, save the address and contents of the slot
+ * on the current contents chain.
+ * Set l_new after storing the new value.
+ *
+ * To do a save:
+ * If the save level is non-zero:
+ * Reset l_new in all slots on the contents chain, and in all
+ * objects created since the previous save.
+ * Push the head of the contents chain, and reset the chain to empty.
+ *
+ * To do a restore:
+ * Check all the stacks to make sure they don't contain references
+ * to objects created since the save.
+ * Restore all the slots on the contents chain.
+ * Pop the contents chain head.
+ * If the save level is now non-zero:
+ * Scan the newly restored contents chain, and set l_new in all
+ * the slots it references.
+ * Scan all objects created since the previous save, and set
+ * l_new in all the slots of each object.
+ *
+ * To forget a save:
+ * If the save level is greater than 1:
+ * Set l_new as for a restore, per the next outer save.
+ * Concatenate the next outer contents chain to the end of
+ * the current one.
+ * If the save level is 1:
+ * Reset l_new as for a save.
+ * Free the contents chain.
+ */
+
+/*
+ * A consequence of the foregoing algorithms is that the cost of a save
+ * is proportional to the total amount of data allocated since the previous
+ * save. If a PostScript program reads in a large amount of setup code
+ * and then uses save/restore heavily, each save/restore will be expensive.
+ * To mitigate this, we check to see how much data we are scanning at a save;
+ * if it is large, we do a second, invisible save. This greatly reduces
+ * the cost of inner saves, at the expense of possibly saving some changes
+ * twice that otherwise would only have to be saved once.
+ */
+
+/*
+ * The presence of global and local VM complicates the situation further.
+ * There is a separate save chain and contents chain for each VM space.
+ * When multiple contexts are fully implemented, save and restore will have
+ * the following effects, according to the privacy status of the current
+ * context's global and local VM:
+ * Private global, private local:
+ * The outermost save saves both global and local VM;
+ * otherwise, save only saves local VM.
+ * Shared global, private local:
+ * Save only saves local VM.
+ * Shared global, shared local:
+ * Save only saves local VM, and suspends all other contexts
+ * sharing the same local VM until the matching restore.
+ * Since we do not currently implement multiple contexts, only the first
+ * case is relevant.
+ *
+ * Note that when saving the contents of a slot, the choice of chain
+ * is determined by the VM space in which the slot is allocated,
+ * not by the current allocation mode.
+ */
+
+#define set_in_save(dmem)\
+ ((dmem)->test_mask = (dmem)->new_mask = l_new)
+#define set_not_in_save(dmem)\
+ ((dmem)->test_mask = ~0, (dmem)->new_mask = 0)
+
+/*
+ * Structure for saved change chain for save/restore. Because of the
+ * garbage collector, we need to distinguish the cases where the change
+ * is in a static object, a dynamic ref, or a dynamic struct.
+ */
+typedef struct alloc_change_s alloc_change_t;
+struct alloc_change_s {
+ alloc_change_t *next;
+ ref_packed *where;
+ ref contents;
+#define ac_offset_static (-2) /* static object */
+#define ac_offset_ref (-1) /* dynamic ref */
+ short offset; /* if >= 0, offset within struct */
+};
+#define ptr ((alloc_change_t *)vptr)
+private CLEAR_MARKS_PROC(change_clear_marks) {
+ if ( r_is_packed(&ptr->contents) )
+ r_clear_pmark((ref_packed *)&ptr->contents);
+ else
+ r_clear_attrs(&ptr->contents, l_mark);
+}
+private ENUM_PTRS_BEGIN(change_enum_ptrs) return 0;
+ ENUM_PTR(0, alloc_change_t, next);
+ case 1:
+ if ( ptr->offset >= 0 )
+ { *pep = (byte *)ptr->where - ptr->offset;
+ return ptr_struct_type;
+ }
+ else
+ { *pep = ptr->where;
+ return ptr_ref_type;
+ }
+ case 2:
+ *pep = &ptr->contents;
+ return ptr_ref_type;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(change_reloc_ptrs) {
+ RELOC_PTR(alloc_change_t, next);
+ switch ( ptr->offset )
+ {
+ case ac_offset_static:
+ break;
+ case ac_offset_ref:
+ ptr->where = gs_reloc_ref_ptr(ptr->where, gcst);
+ break;
+ default:
+ { byte *obj = (byte *)ptr->where - ptr->offset;
+ byte *robj = gs_reloc_struct_ptr(obj, gcst);
+ ptr->where = (ref_packed *)(robj + ptr->offset);
+ } break;
+ }
+ if ( r_is_packed(&ptr->contents) )
+ r_clear_pmark((ref_packed *)&ptr->contents);
+ else
+ { gs_reloc_refs((ref_packed *)&ptr->contents,
+ (ref_packed *)(&ptr->contents + 1),
+ gcst);
+ r_clear_attrs(&ptr->contents, l_mark);
+ }
+} RELOC_PTRS_END
+#undef ptr
+gs_private_st_complex_only(st_alloc_change, alloc_change_t, "alloc_change",
+ change_clear_marks, change_enum_ptrs, change_reloc_ptrs, 0);
+
+/* Debugging printout */
+#ifdef DEBUG
+private void
+alloc_save_print(alloc_change_t *cp, bool print_current)
+{ dprintf2(" 0x%lx: 0x%lx: ", (ulong)cp, (ulong)cp->where);
+ if ( r_is_packed(&cp->contents) )
+ { if ( print_current )
+ dprintf2("saved=%x cur=%x\n", *(ref_packed *)&cp->contents,
+ *cp->where);
+ else
+ dprintf1("%x\n", *(ref_packed *)&cp->contents);
+ }
+ else
+ { if ( print_current )
+ dprintf6("saved=%x %x %lx cur=%x %x %lx\n",
+ r_type_attrs(&cp->contents), r_size(&cp->contents),
+ (ulong)cp->contents.value.intval,
+ r_type_attrs((ref *)cp->where),
+ r_size((ref *)cp->where),
+ (ulong)((ref *)cp->where)->value.intval);
+ else
+ dprintf3("%x %x %lx\n",
+ r_type_attrs(&cp->contents), r_size(&cp->contents),
+ (ulong)cp->contents.value.intval);
+ }
+}
+#endif
+
+/* Forward references */
+private void restore_resources(P2(alloc_save_t *, gs_ref_memory_t *));
+private void restore_free(P1(gs_ref_memory_t *));
+private long save_set_new(P2(gs_ref_memory_t *, bool));
+private void save_set_new_changes(P2(gs_ref_memory_t *, bool));
+
+/* Initialize the save/restore machinery. */
+void
+alloc_save_init(gs_dual_memory_t *dmem)
+{ dmem->save_level = 0;
+ set_not_in_save(dmem);
+}
+
+/* Save the state. */
+private alloc_save_t *alloc_save_space(P2(gs_ref_memory_t *,
+ gs_dual_memory_t *));
+ulong
+alloc_save_state(gs_dual_memory_t *dmem, void *cdata)
+{ gs_ref_memory_t *lmem = dmem->space_local;
+ gs_ref_memory_t *gmem = dmem->space_global;
+ ulong sid = gs_next_ids(2);
+#define alloc_free_save(mem, s, scn, icn)\
+ { chunk_t *inner = (mem)->pcc;\
+ gs_free_object((gs_memory_t *)(mem), s, scn);\
+ gs_free_object((mem)->parent, inner, icn);\
+ }
+ bool global =
+ dmem->save_level == 0 && gmem != lmem &&
+ gmem->num_contexts == 1;
+ alloc_save_t *gsave =
+ (global ? alloc_save_space(gmem, dmem) : (alloc_save_t *)0);
+ alloc_save_t *lsave = alloc_save_space(lmem, dmem);
+
+ if ( lsave == 0 || (global && gsave == 0) )
+ { if ( lsave != 0 )
+ alloc_free_save(lmem, lsave, "alloc_save_state(local save)",
+ "alloc_save_state(local inner)");
+ if ( gsave != 0 )
+ alloc_free_save(gmem, gsave, "alloc_save_state(global save)",
+ "alloc_save_state(global inner)");
+ return 0;
+ }
+#undef alloc_free_save
+ if ( gsave != 0 )
+ { gsave->id = sid + 1;
+ gsave->client_data = 0;
+ print_save("save", gmem->space, gsave);
+ /* Restore names when we do the local restore. */
+ lsave->restore_names = gsave->restore_names;
+ gsave->restore_names = false;
+ }
+ lsave->id = sid;
+ lsave->client_data = cdata;
+ print_save("save", lmem->space, lsave);
+ /* Reset the l_new attribute in all slots. The only slots that */
+ /* can have the attribute set are the ones on the changes chain, */
+ /* and ones in objects allocated since the last save. */
+ if ( dmem->save_level != 0 )
+ { long scanned = save_set_new(&lsave->state, false);
+ if ( scanned > max_repeated_scan )
+ { /* Do a second, invisible save. */
+ alloc_save_t *rsave;
+ /* Notify the file machinery of the first save. */
+ file_save();
+ rsave = alloc_save_space(lmem, dmem);
+ if ( rsave != 0 )
+ { rsave->id = sid;
+ rsave->client_data = cdata;
+ print_save("save", lmem->space, rsave);
+ lsave->id = 0; /* mark as invisible */
+ lsave->client_data = 0;
+ /* Inherit the allocated space count -- */
+ /* we need this for triggering a GC. */
+ rsave->state.inherited =
+ lsave->state.allocated +
+ lsave->state.inherited;
+ lmem->inherited = rsave->state.inherited;
+ print_save("save", lmem->space, lsave);
+ }
+ }
+ }
+ dmem->save_level++;
+ set_in_save(dmem);
+ /* Notify the file machinery we just did a save. */
+ file_save();
+ return sid;
+}
+/* Save the state of one space (global or local). */
+private alloc_save_t *
+alloc_save_space(gs_ref_memory_t *mem, gs_dual_memory_t *dmem)
+{ gs_ref_memory_t save_mem;
+ alloc_save_t *save;
+ chunk_t *inner = 0;
+
+ if ( mem->cc.ctop - mem->cc.cbot > sizeof(chunk_head_t) )
+ { inner = gs_alloc_struct(mem->parent, chunk_t, &st_chunk,
+ "alloc_save_space(inner)");
+ if ( inner == 0 )
+ return 0;
+ }
+ save_mem = *mem;
+ alloc_close_chunk(mem);
+ gs_memory_status((gs_memory_t *)mem, &mem->previous_status);
+ ialloc_reset(mem);
+ mem->cc.cnext = mem->cc.cprev = 0;
+ if ( inner != 0 )
+ { /* Create an inner chunk to cover only the unallocated part. */
+ alloc_init_chunk(&mem->cc, mem->cc.cbot, mem->cc.ctop,
+ true, mem->pcc);
+ *inner = mem->cc;
+ mem->pcc = inner;
+ mem->cfirst = mem->clast = inner;
+ }
+ else
+ { /* Not enough room to create an inner chunk. */
+ mem->pcc = 0;
+ mem->cfirst = mem->clast = 0;
+ mem->cc.cbot = mem->cc.ctop = 0;
+ }
+ save = gs_alloc_struct((gs_memory_t *)mem, alloc_save_t,
+ &st_alloc_save, "alloc_save_space(save)");
+#ifdef DEBUG
+ if ( inner != 0 )
+ { if_debug4('u',
+ "[u]save space %u at 0x%lx: cbot=0x%lx ctop=0x%lx\n",
+ mem->space, (ulong)save,
+ (ulong)inner->cbot, (ulong)inner->ctop);
+ }
+ else
+ { if_debug2('u',
+ "[u]save space %u at 0x%lx (no inner)\n",
+ mem->space, (ulong)save);
+ }
+#endif
+ if ( save == 0 )
+ { gs_free_object(mem->parent, inner, "alloc_save_space(inner)");
+ *mem = save_mem;
+ return 0;
+ }
+ save->state = save_mem;
+ save->dmem = dmem;
+ save->restore_names = (name_memory() == (gs_memory_t *)mem);
+ save->is_current = (dmem->current == mem);
+ mem->saved = save;
+ return save;
+}
+
+/* Record a state change that must be undone for restore, */
+/* and mark it as having been saved. */
+int
+alloc_save_change(gs_dual_memory_t *dmem, const ref *pcont,
+ ref_packed *where, client_name_t cname)
+{ gs_ref_memory_t *mem;
+ register alloc_change_t *cp;
+ if ( dmem->save_level == 0 )
+ return 0; /* no saving */
+ mem = (pcont == NULL ? dmem->space_local :
+ dmem->spaces.indexed[r_space(pcont) >> r_space_shift]);
+ cp = gs_alloc_struct((gs_memory_t *)mem, alloc_change_t,
+ &st_alloc_change, "alloc_save_change");
+ if ( cp == 0 )
+ return -1;
+ cp->next = mem->changes;
+ cp->where = where;
+ if ( pcont == NULL )
+ cp->offset = ac_offset_static;
+ else if ( r_is_array(pcont) || r_has_type(pcont, t_dictionary) )
+ cp->offset = ac_offset_ref;
+ else if ( r_is_struct(pcont) )
+ cp->offset = (byte *)where - (byte *)pcont->value.pstruct;
+ else
+ { lprintf3("Bad type %u for save! pcont = 0x%lx, where = 0x%lx\n",
+ r_type(pcont), (ulong)pcont, (ulong)where);
+ gs_abort();
+ }
+ if ( r_is_packed(where) )
+ *(ref_packed *)&cp->contents = *where;
+ else
+ { ref_assign_inline(&cp->contents, (ref *)where);
+ r_set_attrs((ref *)where, l_new);
+ }
+ mem->changes = cp;
+#ifdef DEBUG
+if ( gs_debug_c('U') )
+ { dprintf1("[u]save(%s)", client_name_string(cname));
+ alloc_save_print(cp, false);
+ }
+#endif
+ return 0;
+}
+
+/* Return the current save level */
+int
+alloc_save_level(const gs_dual_memory_t *dmem)
+{ return dmem->save_level;
+}
+
+/* Return the innermost externally visible save object, i.e., */
+/* the innermost save with a non-zero ID. */
+alloc_save_t *
+alloc_save_current(const gs_dual_memory_t *dmem)
+{ alloc_save_t *save = dmem->space_local->saved;
+ while ( save != 0 && save->id == 0 )
+ save = save->state.saved;
+ return save;
+}
+
+/* Test whether a reference would be invalidated by a restore. */
+bool
+alloc_is_since_save(const void *vptr, const alloc_save_t *save)
+{
+#define ptr ((const char *)vptr)
+
+ /* A reference postdates a save iff it is in a chunk allocated */
+ /* since the save (including the carried-over inner chunk). */
+
+ const gs_dual_memory_t *dmem = save->dmem;
+ register const gs_ref_memory_t *mem = dmem->space_local;
+
+ if_debug2('U', "[U]is_since_save 0x%lx, 0x%lx:\n",
+ (ulong)ptr, (ulong)save);
+ if ( mem->saved == 0 )
+ { /* This is a special case, the final 'restore' from */
+ /* alloc_restore_all. */
+ return true;
+ }
+
+ /* Check against chunks allocated since the save. */
+ /* (There may have been intermediate saves as well.) */
+ for ( ; ; mem = &mem->saved->state )
+ { const chunk_t *cp;
+ if_debug1('U', "[U]checking mem=0x%lx\n", (ulong)mem);
+ for ( cp = mem->cfirst; cp != 0; cp = cp->cnext )
+ { if ( ptr_is_within_chunk(ptr, cp) )
+ { if_debug3('U', "[U+]in new chunk 0x%lx: 0x%lx, 0x%lx\n",
+ (ulong)cp,
+ (ulong)cp->cbase, (ulong)cp->cend);
+ return true;
+ }
+ if_debug1('U', "[U-]not in 0x%lx\n", (ulong)cp);
+ }
+ if ( mem->saved == save )
+ { /* We've checked all the more recent saves, */
+ /* must be OK. */
+ break;
+ }
+ }
+
+ /* If we're about to do a global restore (save level = 1), */
+ /* we also have to check the global save. */
+ /* Global saves can't be nested, which makes things easy. */
+ if ( dmem->save_level == 1 &&
+ (mem = dmem->space_global) != dmem->space_local
+ )
+ { const chunk_t *cp;
+ if_debug1('U', "[U]checking global mem=0x%lx\n", (ulong)mem);
+ for ( cp = mem->cfirst; cp != 0; cp = cp->cnext )
+ if ( ptr_is_within_chunk(ptr, cp) )
+ { if_debug3('U', "[U+] new chunk 0x%lx: 0x%lx, 0x%lx\n",
+ (ulong)cp, (ulong)cp->cbase, (ulong)cp->cend);
+ return true;
+ }
+ }
+
+ return false;
+
+#undef ptr
+}
+
+/* Test whether a name would be invalidated by a restore. */
+bool
+alloc_name_is_since_save(const ref *pnref, const alloc_save_t *save)
+{ const name *pname;
+ if ( !save->restore_names )
+ return false;
+ pname = pnref->value.pname;
+ if ( pname->foreign_string )
+ return false;
+ return alloc_is_since_save(pname->string_bytes, save);
+}
+bool
+alloc_name_index_is_since_save(uint nidx, const alloc_save_t *save)
+{ ref nref;
+ nref.value.pname = name_index_ptr(nidx);
+ return alloc_name_is_since_save(&nref, save);
+}
+
+/* Check whether any names have been created since a given save */
+/* that might be released by the restore. */
+bool
+alloc_any_names_since_save(const alloc_save_t *save)
+{ return save->restore_names;
+}
+
+/* Get the saved state with a given ID. */
+alloc_save_t *
+alloc_find_save(const gs_dual_memory_t *dmem, ulong sid)
+{ alloc_save_t *sprev = dmem->space_local->saved;
+ if ( sid == 0 )
+ return 0; /* invalid id */
+ while ( sprev != 0 )
+ { if ( sprev->id == sid )
+ return sprev;
+ sprev = sprev->state.saved;
+ }
+ return 0;
+}
+
+/* Get the client data from a saved state. */
+void *
+alloc_save_client_data(const alloc_save_t *save)
+{ return save->client_data;
+}
+
+/*
+ * Do one step of restoring the state. The client is responsible for
+ * calling alloc_find_save to get the save object, and for ensuring that
+ * there are no surviving pointers for which alloc_is_since_save is true.
+ * Return true if the argument was the innermost save, in which case
+ * this is the last (or only) step.
+ * Note that "one step" may involve multiple internal steps,
+ * if this is the outermost restore (which requires restoring both local
+ * and global VM) or if we created extra save levels to reduce scanning.
+ */
+private void restore_finalize(P1(gs_ref_memory_t *));
+private void restore_space(P1(gs_ref_memory_t *));
+bool
+alloc_restore_state_step(alloc_save_t *save)
+{ gs_dual_memory_t *dmem = save->dmem;
+ gs_ref_memory_t *mem = dmem->space_local;
+ alloc_save_t *sprev;
+
+ /* Do one (externally visible) step of restoring the state. */
+ do
+ { ulong sid;
+ sprev = mem->saved;
+ sid = sprev->id;
+ restore_finalize(mem); /* finalize objects */
+ restore_resources(sprev, mem); /* release other resources */
+ restore_space(mem); /* release memory */
+ if ( sid != 0 )
+ { dmem->save_level--;
+ break;
+ }
+ }
+ while ( sprev != save );
+
+ if ( dmem->save_level == 0 )
+ { /* This is the outermost save, which might also */
+ /* need to restore global VM. */
+ mem = dmem->space_global;
+ if ( mem != dmem->space_local && mem->saved != 0 )
+ { restore_finalize(mem);
+ restore_resources(mem->saved, mem);
+ restore_space(mem);
+ }
+ set_not_in_save(dmem);
+ }
+ else
+ { /* Set the l_new attribute in all slots that are now new. */
+ save_set_new(mem, true);
+ }
+
+ return sprev == save;
+}
+/* Restore the memory of one space, by undoing changes and freeing */
+/* memory allocated since the save. */
+private void
+restore_space(gs_ref_memory_t *mem)
+{ alloc_save_t *save = mem->saved;
+ alloc_save_t saved;
+
+ print_save("restore", mem->space, save);
+
+ /* Undo changes since the save. */
+ { register alloc_change_t *cp = mem->changes;
+ while ( cp )
+ {
+#ifdef DEBUG
+if ( gs_debug_c('U') )
+ { dprintf("[U]restore");
+ alloc_save_print(cp, true);
+ }
+#endif
+ if ( r_is_packed(&cp->contents) )
+ *cp->where = *(ref_packed *)&cp->contents;
+ else
+ ref_assign_inline((ref *)cp->where, &cp->contents);
+ cp = cp->next;
+ }
+ }
+
+ /* Free memory allocated since the save. */
+ /* Note that this frees all chunks except the inner one */
+ /* belonging to this level. */
+ saved = *save;
+ restore_free(mem);
+
+ /* Restore the allocator state. */
+ { int num_contexts = mem->num_contexts; /* don't restore */
+ *mem = saved.state;
+ mem->num_contexts = num_contexts;
+ }
+ alloc_open_chunk(mem);
+
+ /* Make the allocator current if it was current before the save. */
+ if ( saved.is_current )
+ { gs_dual_memory_t *dmem = saved.dmem;
+ dmem->current = mem;
+ dmem->current_space = mem->space;
+ }
+}
+
+/* Restore to the initial state, releasing all resources. */
+/* The allocator is no longer usable after calling this routine! */
+void
+alloc_restore_all(gs_dual_memory_t *dmem)
+{
+ /* Restore to a state outside any saves. */
+ while ( dmem->save_level != 0 )
+ discard(alloc_restore_state_step(dmem->space_local->saved));
+
+ /* Finalize memory. */
+ restore_finalize(dmem->space_local);
+ { gs_ref_memory_t *mem = dmem->space_global;
+ if ( mem != dmem->space_local && mem->num_contexts == 1 )
+ restore_finalize(mem);
+ }
+ restore_finalize(dmem->space_system);
+
+ /* Release resources other than memory, using fake */
+ /* save and memory objects. */
+ { alloc_save_t empty_save;
+ empty_save.dmem = dmem;
+ empty_save.restore_names = false; /* don't bother to release */
+ restore_resources(&empty_save, NULL);
+ }
+
+ /* Finally, release memory. */
+ restore_free(dmem->space_local);
+ { gs_ref_memory_t *mem = dmem->space_global;
+ if ( mem != dmem->space_local )
+ { if ( !--(mem->num_contexts) )
+ restore_free(mem);
+ }
+ }
+ restore_free(dmem->space_system);
+
+}
+
+/*
+ * Finalize objects that will be freed by a restore.
+ * Note that we must temporarily disable the freeing operations
+ * of the allocator while doing this.
+ */
+private void
+restore_finalize(gs_ref_memory_t *mem)
+{ chunk_t *cp;
+
+ alloc_close_chunk(mem);
+ gs_enable_free((gs_memory_t *)mem, false);
+ for ( cp = mem->clast; cp != 0; cp = cp->cprev )
+ { SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_finalize((*finalize)) =
+ pre->o_type->finalize;
+ if ( finalize != 0 )
+ { if_debug2('u', "[u]restore finalizing %s 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong)(pre + 1));
+ (*finalize)(pre + 1);
+ }
+ END_OBJECTS_SCAN
+ }
+ gs_enable_free((gs_memory_t *)mem, true);
+}
+
+/* Release resources for a restore */
+private void
+restore_resources(alloc_save_t *sprev, gs_ref_memory_t *mem)
+{
+ /* Close inaccessible files. */
+ file_restore(sprev, (const gs_memory_t *)mem);
+
+ /* Remove entries from font and character caches. */
+ font_restore(sprev);
+
+ /* Adjust the name table. */
+ if ( sprev->restore_names )
+ name_restore(sprev);
+}
+
+/* Release memory for a restore. */
+private void
+restore_free(gs_ref_memory_t *mem)
+{ /* Free chunks allocated since the save. */
+ chunk_t *cp;
+ chunk_t *csucc;
+
+ /* Free the chunks in reverse order, to encourage LIFO behavior. */
+ /* Don't free the chunk holding the allocator itself! */
+ for ( cp = mem->clast; cp != 0; cp = csucc )
+ { csucc = cp->cprev; /* save before freeing */
+ if ( cp->cbase + sizeof(obj_header_t) != (byte *)mem )
+ alloc_free_chunk(cp, mem);
+ }
+}
+
+/* Forget a save, by merging this level with the next outer one. */
+private void combine_space(P1(gs_ref_memory_t *));
+private void forget_changes(P1(gs_ref_memory_t *));
+void
+alloc_forget_save(alloc_save_t *save)
+{ gs_dual_memory_t *dmem = save->dmem;
+ gs_ref_memory_t *mem = dmem->space_local;
+ alloc_save_t *sprev;
+
+ print_save("forget_save", mem->space, save);
+
+ /* Iteratively combine the current level with the previous one. */
+ do
+ { sprev = mem->saved;
+ if ( sprev->id != 0 )
+ dmem->save_level--;
+ if ( dmem->save_level != 0 )
+ { alloc_change_t *chp = mem->changes;
+ save_set_new(&sprev->state, true);
+ /* Concatenate the changes chains. */
+ if ( chp == 0 )
+ mem->changes = sprev->state.changes;
+ else
+ { while ( chp->next != 0 )
+ chp = chp->next;
+ chp->next = sprev->state.changes;
+ }
+ file_forget_save(sprev);
+ combine_space(mem); /* combine memory */
+ }
+ else
+ { forget_changes(mem);
+ save_set_new(mem, false);
+ file_forget_save(sprev);
+ combine_space(mem); /* combine memory */
+ /* This is the outermost save, which might also */
+ /* need to combine global VM. */
+ mem = dmem->space_global;
+ if ( mem != dmem->space_local && mem->saved != 0 )
+ { forget_changes(mem);
+ save_set_new(mem, false);
+ combine_space(mem);
+ }
+ set_not_in_save(dmem);
+ break; /* must be outermost */
+ }
+ }
+ while ( sprev != save );
+}
+/* Combine the chunks of the next outer level with those of the current one, */
+/* and free the bookkeeping structures. */
+private void
+combine_space(gs_ref_memory_t *mem)
+{ alloc_save_t *saved = mem->saved;
+ gs_ref_memory_t *omem = &saved->state;
+ chunk_t *cp;
+ chunk_t *csucc;
+
+ alloc_close_chunk(mem);
+ for ( cp = mem->cfirst; cp != 0; cp = csucc )
+ { csucc = cp->cnext; /* save before relinking */
+ if ( cp->outer == 0 )
+ alloc_link_chunk(cp, omem);
+ else
+ { chunk_t *outer = cp->outer;
+ outer->inner_count--;
+ if ( mem->pcc == cp )
+ mem->pcc = outer;
+ if ( mem->cfreed.cp == cp )
+ mem->cfreed.cp = outer;
+ /* "Free" the header of the inner chunk, */
+ /* and any immediately preceding gap left by */
+ /* the GC having compacted the outer chunk. */
+ { obj_header_t *hp = (obj_header_t *)outer->cbot;
+ hp->o_large = 0;
+ hp->o_size = (char *)(cp->chead + 1)
+ - (char *)(hp + 1);
+ hp->o_type = &st_bytes;
+ /* The following call is probably not safe. */
+#if 0 /* **************** */
+ gs_free_object((gs_memory_t *)mem,
+ hp + 1, "combine_space(header)");
+#endif /* **************** */
+ }
+ /* Update the outer chunk's allocation pointers. */
+ outer->cbot = cp->cbot;
+ outer->rcur = cp->rcur;
+ outer->rtop = cp->rtop;
+ outer->ctop = cp->ctop;
+ outer->has_refs |= cp->has_refs;
+ gs_free_object(mem->parent, cp,
+ "combine_space(inner)");
+ }
+ }
+ /* Update relevant parts of allocator state. */
+ mem->cfirst = omem->cfirst;
+ mem->clast = omem->clast;
+ mem->allocated += omem->allocated;
+ mem->gc_allocated += omem->allocated;
+ mem->lost.objects += omem->lost.objects;
+ mem->lost.refs += omem->lost.refs;
+ mem->lost.strings += omem->lost.strings;
+ mem->saved = omem->saved;
+ mem->previous_status = omem->previous_status;
+ { /* Concatenate free lists. */
+ int i;
+ for ( i = 0; i < num_freelists; i++ )
+ { obj_header_t *olist = omem->freelists[i];
+ obj_header_t *list = mem->freelists[i];
+ if ( olist == 0 )
+ ;
+ else if ( list == 0 )
+ mem->freelists[i] = olist;
+ else
+ { while ( *(obj_header_t **)list != 0 )
+ list = *(obj_header_t **)list;
+ *(obj_header_t **)list = olist;
+ }
+ }
+ }
+ gs_free_object((gs_memory_t *)mem, saved, "combine_space(saved)");
+ alloc_open_chunk(mem);
+}
+/* Free the changes chain for a level 0 .forgetsave, */
+/* resetting the l_new flag in the changed refs. */
+private void
+forget_changes(gs_ref_memory_t *mem)
+{ register alloc_change_t *chp = mem->changes;
+ alloc_change_t *next;
+ for ( ; chp; chp = next )
+ { ref_packed *prp = chp->where;
+ if_debug1('U', "[U]forgetting change 0x%lx\n", (ulong)chp);
+ if ( !r_is_packed(prp) )
+ r_clear_attrs((ref *)prp, l_new);
+ next = chp->next;
+ gs_free_object((gs_memory_t *)mem, chp, "forget_changes");
+ }
+ mem->changes = 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Set or reset the l_new attribute in every relevant slot. */
+/* This includes every slot on the current change chain, */
+/* and every (ref) slot allocated at this save level. */
+/* Return the number of bytes of data scanned. */
+private long
+save_set_new(gs_ref_memory_t *mem, bool to_new)
+{
+ long scanned = 0;
+
+ /* Handle the change chain. */
+ save_set_new_changes(mem, to_new);
+
+ /* Handle newly allocated ref objects. */
+ SCAN_MEM_CHUNKS(mem, cp)
+ { if ( cp->has_refs )
+ { bool has_refs = false;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if_debug3('U', "[U]set_new scan(0x%lx(%lu), %d)\n",
+ (ulong)pre, size, to_new);
+ if ( pre->o_type == &st_refs )
+ { /* These are refs, scan them. */
+ ref_packed *prp = (ref_packed *)(pre + 1);
+ ref_packed *next = (ref_packed *)((char *)prp + size);
+ if_debug2('U', "[U]refs 0x%lx to 0x%lx\n",
+ (ulong)prp, (ulong)next);
+ has_refs = true;
+ scanned += size;
+ /* We know that every block of refs ends with */
+ /* a full-size ref, so we only need the end check */
+ /* when we encounter one of those. */
+#define rp ((ref *)prp)
+ if ( to_new )
+ while ( 1 )
+ { if ( r_is_packed(prp) )
+ prp++;
+ else
+ { rp->tas.type_attrs |= l_new;
+ prp += packed_per_ref;
+ if ( prp >= next )
+ break;
+ }
+ }
+ else
+ while ( 1 )
+ { if ( r_is_packed(prp) )
+ prp++;
+ else
+ { rp->tas.type_attrs &= ~l_new;
+ prp += packed_per_ref;
+ if ( prp >= next )
+ break;
+ }
+ }
+#undef rp
+ }
+ else
+ scanned += sizeof(obj_header_t);
+ END_OBJECTS_SCAN
+ cp->has_refs = has_refs;
+ }
+ }
+ END_CHUNKS_SCAN
+ if_debug2('u', "[u]set_new (%s) scanned %ld\n",
+ (to_new ? "restore" : "save"), scanned);
+ return scanned;
+}
+
+/* Set or reset the l_new attribute on the changes chain. */
+private void
+save_set_new_changes(gs_ref_memory_t *mem, bool to_new)
+{ register alloc_change_t *chp = mem->changes;
+ register uint new = (to_new ? l_new : 0);
+ for ( ; chp; chp = chp->next )
+ { ref_packed *prp = chp->where;
+ if_debug2('U', "[U]set_new(0x%lx, %d)\n",
+ (ulong)prp, new);
+ if ( !r_is_packed(prp) )
+#define rp ((ref *)prp)
+ rp->tas.type_attrs =
+ (rp->tas.type_attrs & ~l_new) + new;
+#undef rp
+ }
+}
diff --git a/gs/src/isave.h b/gs/src/isave.h
new file mode 100644
index 000000000..91287e66e
--- /dev/null
+++ b/gs/src/isave.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* isave.h */
+/* Interface to Ghostscript save/restore machinery */
+/* Requires imemory.h */
+
+/*
+ * According to the PostScript language definition, save objects are simple,
+ * not composite. Consequently, we cannot use their natural representation,
+ * namely a t_struct pointing to an alloc_save_t, since we aren't willing to
+ * allocate them all in global VM and rely on garbage collection to clean
+ * them up. Instead, we assign each one a unique "save ID", and store this
+ * in the alloc_save_t object. Mapping the number to the object requires
+ * at most searching the local save chain for the current gs_dual_memory_t,
+ * and this approach means we don't have to do anything to invalidate
+ * save objects when we do a restore.
+ */
+#ifndef alloc_save_t_DEFINED /* also in inamedef.h */
+typedef struct alloc_save_s alloc_save_t;
+# define alloc_save_t_DEFINED
+#endif
+
+/* Initialize the save machinery. */
+extern void alloc_save_init(P1(gs_dual_memory_t *));
+
+/* Map a save ID to its save object. Return 0 if the ID is invalid. */
+alloc_save_t *alloc_find_save(P2(const gs_dual_memory_t *, ulong));
+
+/* Save the state. Return 0 if we can't allocate the save object, */
+/* otherwise return the save ID. The second argument is a client data */
+/* pointer, assumed to point to an object. */
+ulong alloc_save_state(P2(gs_dual_memory_t *, void *));
+
+/* Get the client pointer passed to alloc_saved_state. */
+void *alloc_save_client_data(P1(const alloc_save_t *));
+
+/* Return the current level of save nesting. */
+int alloc_save_level(P1(const gs_dual_memory_t *));
+
+/* Return the innermost externally visible save object. */
+alloc_save_t *alloc_save_current(P1(const gs_dual_memory_t *));
+
+/* Check whether a pointer refers to an object allocated since a given save. */
+bool alloc_is_since_save(P2(const void *, const alloc_save_t *));
+
+/* Check whether a name was created since a given save. */
+bool alloc_name_is_since_save(P2(const ref *, const alloc_save_t *));
+bool alloc_name_index_is_since_save(P2(uint, const alloc_save_t *));
+
+/* Check whether any names have been created since a given save */
+/* that might be released by the restore. */
+bool alloc_any_names_since_save(P1(const alloc_save_t *));
+
+/* Do one step of restoring the state. Return true if the argument */
+/* was the innermost save, in which case this is the last (or only) step. */
+/* Assume the caller obtained the argument by calling alloc_find_save; */
+/* if this is the case, the operation cannot fail. */
+bool alloc_restore_state_step(P1(alloc_save_t *));
+
+/* Forget a save -- like committing a transaction (restore is like */
+/* aborting a transaction). Assume the caller obtained the argument */
+/* by calling alloc_find_save. Note that forgetting a save does not */
+/* require checking pointers for recency. */
+void alloc_forget_save(P1(alloc_save_t *));
+
+/* Release all memory -- like doing a restore "past the bottom". */
+void alloc_restore_all(P1(gs_dual_memory_t *));
+
+/*
+ * If we are in a save, we want to save the old contents if l_new is
+ * not set; if we are not in a save, we never want to save old contents.
+ * We can test this quickly with a single mask that is l_new if we are
+ * in a save, and -1 if we are not, since type_attrs of a valid ref
+ * cannot be 0; this is the test_mask in a gs_dual_memory_t. Similarly,
+ * we want to set the l_new bit in newly allocated objects iff we are in
+ * a save; this is the new_mask in a gs_dual_memory_t.
+ *
+ * We have to pass the pointer to the containing object to alloc_save_change
+ * for two reasons:
+ *
+ * - We need to know which VM the containing object is in, so we can
+ * know on which chain of saved changes to put the new change.
+ *
+ * - We need to know whether the object is an array of refs (which
+ * includes dictionaries) or a struct, so we can properly trace and
+ * relocate the pointer to it from the change record during garbage
+ * collection.
+ */
+int alloc_save_change(P4(gs_dual_memory_t *, const ref *pcont,
+ ref_packed *ptr, client_name_t cname));
diff --git a/gs/src/iscan.c b/gs/src/iscan.c
new file mode 100644
index 000000000..c0d549007
--- /dev/null
+++ b/gs/src/iscan.c
@@ -0,0 +1,1035 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iscan.c */
+/* Token scanner for Ghostscript interpreter */
+#include "ghost.h"
+#include "memory_.h"
+#include "stream.h"
+#include "errors.h"
+#include "files.h" /* for fptr */
+#include "ialloc.h"
+#include "idict.h" /* for //name lookup */
+#include "dstack.h" /* ditto */
+#include "ilevel.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "iparray.h"
+#include "strimpl.h" /* for string decoding */
+#include "sfilter.h" /* ditto */
+#include "ostack.h" /* for accumulating proc bodies; */
+ /* must precede iscan.h */
+#include "iscan.h" /* defines interface */
+#include "iscannum.h"
+#include "istream.h"
+#include "istruct.h" /* for gs_reloc_refs */
+#include "iutil.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "scanchar.h"
+
+/* Array packing flag */
+ref ref_array_packing; /* t_boolean */
+/* Binary object format flag. This will never be set non-zero */
+/* unless the binary token feature is enabled. */
+ref ref_binary_object_format; /* t_integer */
+#define recognize_btokens()\
+ (ref_binary_object_format.value.intval != 0 && level2_enabled)
+
+/* Procedure for binary tokens. Set at initialization if Level 2 */
+/* features are included; only called if recognize_btokens() is true. */
+/* Returns 0 or scan_BOS on success, <0 on failure. */
+int (*scan_btoken_proc)(P3(stream *, ref *, scanner_state *)) = NULL;
+
+/* Stream template for scanning ASCII85 literals. */
+/* Set at initialization if Level 2 features are included. */
+const stream_template _ds *scan_ascii85_template = NULL;
+
+#ifdef DEBUG
+/* Dummy comment processing procedure for testing. */
+private int
+no_comment_proc(const byte *str, uint len)
+{ return 0;
+}
+#endif
+
+/* Procedure for handling DSC comments if desired. */
+/* Set at initialization if a DSC handling module is included. */
+int (*scan_dsc_proc)(P2(const byte *, uint)) = NULL;
+
+/* Procedure for handling all comments if desired. */
+/* Set at initialization if a comment handling module is included. */
+/* If both scan_comment_proc and scan_dsc_proc are set, */
+/* scan_comment_proc is called only for non-DSC comments. */
+int (*scan_comment_proc)(P2(const byte *, uint)) = NULL;
+
+/*
+ * Level 2 includes some changes in the scanner:
+ * - \ is always recognized in strings, regardless of the data source;
+ * - << and >> are legal tokens;
+ * - <~ introduces an ASCII85 encoded string (terminated by ~>);
+ * - Character codes above 127 introduce binary objects.
+ * We explicitly enable or disable these changes here.
+ */
+#define scan_enable_level2 level2_enabled /* from ilevel.h */
+
+/* ------ Dynamic strings ------ */
+
+/* Begin collecting a dynamically allocated string. */
+#define dynamic_init(pda, mem)\
+ ((pda)->is_dynamic = false,\
+ (pda)->limit = (pda)->buf + da_buf_size,\
+ (pda)->next = (pda)->base = (pda)->buf,\
+ (pda)->memory = (mem))
+
+/* Free a dynamic string. */
+private void
+dynamic_free(da_ptr pda)
+{ if ( pda->is_dynamic )
+ gs_free_string(pda->memory, pda->base, da_size(pda), "scanner");
+}
+
+/* Resize a dynamic string. */
+/* If the allocation fails, return e_VMerror; otherwise, return 0. */
+private int
+dynamic_resize(register da_ptr pda, uint new_size)
+{ uint old_size = da_size(pda);
+ uint pos = pda->next - pda->base;
+ gs_memory_t *mem = pda->memory;
+ byte *base;
+ if ( pda->is_dynamic )
+ { base = gs_resize_string(mem, pda->base, old_size,
+ new_size, "scanner");
+ if ( base == 0 )
+ return_error(e_VMerror);
+ }
+ else /* switching from static to dynamic */
+ { base = gs_alloc_string(mem, new_size, "scanner");
+ if ( base == 0 )
+ return_error(e_VMerror);
+ memcpy(base, pda->base, min(old_size, new_size));
+ pda->is_dynamic = true;
+ }
+ pda->base = base;
+ pda->next = base + pos;
+ pda->limit = base + new_size;
+ return 0;
+}
+
+/* Grow a dynamic string. */
+/* Return 0 if the allocation failed, the new 'next' ptr if OK. */
+/* Return 0 or an error code, updating pda->next to point to the first */
+/* available byte after growing. */
+private int
+dynamic_grow(register da_ptr pda, byte *next, uint max_size)
+{ uint old_size = da_size(pda);
+ uint new_size = (old_size < 10 ? 20 :
+ old_size >= (max_size >> 1) ? max_size :
+ old_size << 1);
+ int code;
+ pda->next = next;
+ if ( old_size == max_size )
+ return_error(e_limitcheck);
+ while ( (code = dynamic_resize(pda, new_size)) < 0 &&
+ new_size > old_size
+ )
+ { /* Try trimming down the requested new size. */
+ new_size -= (new_size - old_size + 1) >> 1;
+ }
+ return code;
+}
+
+/* Ensure that a dynamic string is either on the heap or in the */
+/* private buffer. */
+private void
+dynamic_save(da_ptr pda)
+{ if ( !pda->is_dynamic && pda->base != pda->buf )
+ { memcpy(pda->buf, pda->base, da_size(pda));
+ pda->next = pda->buf + da_size(pda);
+ pda->base = pda->buf;
+ }
+}
+
+/* Finish collecting a dynamic string. */
+private int
+dynamic_make_string(ref *pref, da_ptr pda, byte *next)
+{ uint size = (pda->next = next) - pda->base;
+ int code = dynamic_resize(pda, size);
+ if ( code < 0 )
+ return code;
+ make_tasv_new(pref, t_string,
+ a_all | imemory_space((gs_ref_memory_t *)pda->memory),
+ size, bytes, pda->base);
+ return 0;
+}
+
+/* ------ Main scanner ------ */
+
+/* GC procedures */
+#define ssptr ((scanner_state *)vptr)
+#define ssarray ssptr->s_ss.binary.bin_array
+private CLEAR_MARKS_PROC(scanner_clear_marks) {
+ r_clear_attrs(&ssarray, l_mark);
+}
+private ENUM_PTRS_BEGIN(scanner_enum_ptrs) return 0;
+ case 0:
+ if ( ssptr->s_scan_type == scanning_none ||
+ !ssptr->s_da.is_dynamic
+ )
+ ENUM_RETURN(0);
+ ssptr->s_da.str.data = ssptr->s_da.base;
+ ssptr->s_da.str.size = da_size(&ssptr->s_da);
+ ENUM_RETURN_STRING_PTR(scanner_state, s_da.str);
+ case 1:
+ if ( ssptr->s_scan_type != scanning_binary )
+ return 0;
+ *pep = &ssarray;
+ return ptr_ref_type;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(scanner_reloc_ptrs) {
+ if ( ssptr->s_scan_type != scanning_none && ssptr->s_da.is_dynamic )
+ { RELOC_STRING_PTR(scanner_state, s_da.str);
+ ssptr->s_da.limit = ssptr->s_da.str.data + ssptr->s_da.str.size;
+ ssptr->s_da.next = ssptr->s_da.str.data + (ssptr->s_da.next - ssptr->s_da.base);
+ ssptr->s_da.base = ssptr->s_da.str.data;
+ }
+ if ( ssptr->s_scan_type == scanning_binary )
+ { gs_reloc_refs((ref_packed *)&ssarray,
+ (ref_packed *)(&ssarray + 1),
+ gcst);
+ r_clear_attrs(&ssarray, l_mark);
+ }
+} RELOC_PTRS_END
+#undef ssptr
+/* Structure type */
+public_st_scanner_state();
+
+/* Initialize the scanner. */
+void
+scan_init(void)
+{ make_false(&ref_array_packing);
+ make_int(&ref_binary_object_format, 0);
+}
+
+/* Handle a scan_Refill return from scan_token. */
+/* This may return o_push_estack, 0 (meaning just call scan_token again), */
+/* or an error code. */
+int
+scan_handle_refill(const ref *fop, scanner_state *sstate, bool save,
+ bool push_file, int (*cont)(P1(os_ptr)))
+{ stream *s = fptr(fop);
+ uint avail = sbufavailable(s);
+ int status;
+
+ if ( s->end_status == EOFC )
+ { /* More data needed, but none available, */
+ /* so this is a syntax error. */
+ return_error(e_syntaxerror);
+ }
+ status = s_process_read_buf(s);
+ if ( sbufavailable(s) > avail )
+ return 0;
+ if ( status == 0 )
+ status = s->end_status;
+ switch ( status )
+ {
+ case EOFC:
+ /* We just discovered that we're at EOF. */
+ /* Let the caller find this out. */
+ return 0;
+ case ERRC:
+ return_error(e_ioerror);
+ case INTC:
+ case CALLC:
+ { ref rstate[2];
+ scanner_state *pstate;
+ int nstate = (push_file ? 2 : 1);
+
+ if ( save )
+ { pstate =
+ ialloc_struct(scanner_state, &st_scanner_state,
+ "scan_handle_refill");
+ if ( pstate == 0 )
+ return_error(e_VMerror);
+ *pstate = *sstate;
+ }
+ else
+ pstate = sstate;
+ /* If push_file is true, we want to push the file on the */
+ /* o-stack before the state, for the continuation proc. */
+ /* Since the refs passed to s_handle_read_exception */
+ /* are pushed on the e-stack, we must ensure they are */
+ /* literal, and also pass them in the opposite order! */
+ make_istruct(&rstate[0], 0, pstate);
+ rstate[1] = *fop;
+ r_clear_attrs(&rstate[1], a_executable);
+ return s_handle_read_exception(status, fop,
+ rstate, nstate, cont);
+ }
+ }
+ /* No more data available, but no exception. How can this be? */
+ lprintf("Can't refill scanner input buffer!");
+ return_error(e_Fatal);
+}
+
+/* Handle a comment. The 'saved' argument is needed only for */
+/* tracing printout. */
+private int
+scan_comment(const byte *base, const byte *end, bool saved)
+{ uint len = (uint)(end - base);
+#ifdef DEBUG
+ const char *sstr = (saved ? ">" : "");
+#endif
+ if ( len > 1 && base[1] == '%' && scan_dsc_proc != NULL )
+ {
+#ifdef DEBUG
+ if ( gs_debug_c('%') )
+ { dprintf2("[%%%%%s%c]", sstr, (len >= 3 ? '+' : '-'));
+ fwrite(base, 1, len, dstderr);
+ dputs("\n");
+ }
+#endif
+ if ( end - base >= 3 )
+ return (*scan_dsc_proc)(base, len);
+ }
+ else if ( scan_comment_proc != NULL )
+ {
+#ifdef DEBUG
+ if ( gs_debug_c('%') )
+ { dprintf2("[%% %s%c]", sstr, (len >= 2 ? '+' : '-'));
+ fwrite(base, 1, len, dstderr);
+ dputs("\n");
+ }
+#endif
+ if ( end - base >= 2 )
+ return (*scan_comment_proc)(base, len);
+ }
+ return 0;
+}
+
+/* Read a token from a string. */
+/* Update the string if succesful. */
+int
+scan_string_token(ref *pstr, ref *pref)
+{ stream st;
+ stream *s = &st;
+ scanner_state state;
+ int code;
+
+ if ( !r_has_attr(pstr, a_read) )
+ return_error(e_invalidaccess);
+ sread_string(s, pstr->value.bytes, r_size(pstr));
+ scanner_state_init(&state, true);
+ switch ( code = scan_token(s, pref, &state) )
+ {
+ case 0: /* read a token */
+ case scan_BOS:
+ { uint pos = stell(s);
+ pstr->value.bytes += pos;
+ r_dec_size(pstr, pos);
+ } break;
+ case scan_Refill: /* error */
+ code = gs_note_error(e_syntaxerror);
+ default: /* error */
+ ;
+ }
+ return code;
+}
+
+/*
+ * Read a token from a stream.
+ * Return 0 if an ordinary token was read,
+ * scan_BOS for a binary object sequence, scan_EOF for end-of-stream,
+ * scan_Refill if more data needed, or a (negative) error code.
+ * If the token required a terminating character (i.e., was a name or
+ * number) and the next character was whitespace, read and discard
+ * that character. Note that the state is relevant for e_VMerror
+ * as well as for scan_Refill.
+ */
+int
+scan_token(register stream *s, ref *pref, scanner_state *pstate)
+{ ref *myref = pref;
+ int retcode = 0;
+ register int c;
+ s_declare_inline(s, sptr, endptr);
+#define scan_begin_inline() s_begin_inline(s, sptr, endptr)
+#define scan_getc() sgetc_inline(s, sptr, endptr)
+#define scan_putback() sputback_inline(s, sptr, endptr)
+#define scan_end_inline() s_end_inline(s, sptr, endptr)
+ const byte *newptr;
+ byte *daptr;
+#define sreturn(code)\
+ { retcode = gs_note_error(code); goto sret; }
+#define sreturn_no_error(code)\
+ { scan_end_inline(); return(code); }
+#define if_not_spush1()\
+ if ( osp < ostop ) osp++;\
+ else if ( (retcode = ref_stack_push(&o_stack, 1)) >= 0 )\
+ ;\
+ else
+#define spop1()\
+ if ( osp >= osbot ) osp--;\
+ else ref_stack_pop(&o_stack, 1)
+ int max_name_ctype =
+ (recognize_btokens() ? ctype_name : ctype_btoken);
+#define scan_sign(sign, ptr)\
+ switch ( *ptr ) {\
+ case '-': sign = -1; ptr++; break;\
+ case '+': sign = 1; ptr++; break;\
+ default: sign = 0;\
+ }
+#define ensure2_back(styp,nback)\
+ if ( sptr >= endptr ) { sptr -= nback; scan_type = styp; goto pause; }
+#define ensure2(styp) ensure2_back(styp, 1)
+ byte s1[2];
+ register const byte _ds *decoder = scan_char_decoder;
+ int status;
+ int sign;
+ scanner_state sstate;
+#define pstack sstate.s_pstack
+#define pdepth sstate.s_pdepth
+#define scan_type sstate.s_scan_type
+#define da sstate.s_da
+#define name_type sstate.s_ss.s_name.s_name_type
+#define try_number sstate.s_ss.s_name.s_try_number
+
+ if ( pstate->s_pstack != 0 )
+ { if_not_spush1()
+ return retcode;
+ myref = osp;
+ }
+ /* Check whether we are resuming after an interruption. */
+ if ( pstate->s_scan_type != scanning_none )
+ { sstate = *pstate;
+ if ( !da.is_dynamic && da.base != da.buf )
+ { /* The da contains some self-referencing pointers. */
+ /* Fix them up now. */
+ uint size = da.next - da.base;
+ da.base = da.buf;
+ da.next = da.buf + size;
+ da.limit = da.buf + da_buf_size;
+ }
+ daptr = da.next;
+ switch ( scan_type )
+ {
+ case scanning_binary:
+ retcode = (*sstate.s_ss.binary.cont)(s, myref, &sstate);
+ scan_begin_inline();
+ if ( retcode == scan_Refill )
+ goto pause;
+ goto sret;
+ case scanning_comment:
+ scan_begin_inline();
+ goto cont_comment;
+ case scanning_name:
+ goto cont_name;
+ case scanning_string:
+ goto cont_string;
+ default:
+ return_error(e_Fatal);
+ }
+ }
+ /* Fetch any state variables that are relevant even if */
+ /* scan_type == scanning_none. */
+ pstack = pstate->s_pstack;
+ pdepth = pstate->s_pdepth;
+ scan_begin_inline();
+ /*
+ * Loop invariants:
+ * If pstack != 0, myref = osp, and *osp is a valid slot.
+ */
+top: c = scan_getc();
+ if_debug1('S', (c >= 32 && c <= 126 ? "`%c'" : c >= 0 ? "`\\%03o'" : "`%d'"), c);
+ switch ( c )
+ {
+ case ' ': case '\f': case '\t':
+ case char_CR: case char_EOL:
+ case char_NULL:
+ goto top;
+ case '[':
+ case ']':
+ s1[0] = (byte)c;
+ retcode = name_ref(s1, 1, myref, 1); /* can't fail */
+ r_set_attrs(myref, a_executable);
+ break;
+ case '<':
+ if ( scan_enable_level2 )
+ { ensure2(scanning_none);
+ c = scan_getc();
+ switch ( c )
+ {
+ case '<':
+ scan_putback();
+ name_type = 0;
+ try_number = false;
+ goto try_funny_name;
+ case '~':
+ s_A85D_init_inline(&sstate.s_ss.a85d);
+ sstate.s_ss.st.template =
+ scan_ascii85_template;
+ goto str;
+ }
+ scan_putback();
+ }
+ s_AXD_init_inline(&sstate.s_ss.axd);
+ sstate.s_ss.st.template = &s_AXD_template;
+str: scan_end_inline();
+ dynamic_init(&da, imemory);
+cont_string: for ( ; ; )
+ { stream_cursor_write w;
+ w.ptr = da.next - 1;
+ w.limit = da.limit - 1;
+ status = (*sstate.s_ss.st.template->process)
+ (&sstate.s_ss.st, &s->cursor.r, &w,
+ s->end_status == EOFC);
+ da.next = w.ptr + 1;
+ switch ( status )
+ {
+ case 0:
+ status = s->end_status;
+ if ( status < 0 )
+ { if ( status == EOFC )
+ sreturn(e_syntaxerror);
+ break;
+ }
+ s_process_read_buf(s);
+ continue;
+ case 1:
+ retcode = dynamic_grow(&da, da.next,
+ max_string_size);
+ if ( retcode == e_VMerror )
+ { scan_type = scanning_string;
+ goto suspend;
+ }
+ else if ( retcode < 0 )
+ sreturn(retcode);
+ continue;
+ }
+ break;
+ }
+ scan_begin_inline();
+ switch ( status )
+ {
+ default:
+ /*case ERRC:*/
+ sreturn(e_syntaxerror);
+ case INTC:
+ case CALLC:
+ scan_type = scanning_string;
+ goto pause;
+ case EOFC:
+ ;
+ }
+ retcode = dynamic_make_string(myref, &da, da.next);
+ if ( retcode < 0 ) /* VMerror */
+ { sputback(s); /* rescan ) */
+ scan_type = scanning_string;
+ goto suspend;
+ }
+ break;
+ case '(':
+ sstate.s_ss.pssd.from_string =
+ pstate->s_from_string && !scan_enable_level2;
+ s_PSSD_init_inline(&sstate.s_ss.pssd);
+ sstate.s_ss.st.template = &s_PSSD_template;
+ goto str;
+ case '{':
+ if ( pstack == 0 ) /* outermost procedure */
+ { if_not_spush1()
+ { scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ pdepth = ref_stack_count_inline(&o_stack);
+ }
+ make_int(osp, pstack);
+ pstack = ref_stack_count_inline(&o_stack);
+ if_debug3('S', "[S{]d=%d, s=%d->%d\n",
+ pdepth, (int)osp->value.intval, pstack);
+ goto snext;
+ case '>':
+ if ( scan_enable_level2 )
+ { ensure2(scanning_none);
+ name_type = 0;
+ try_number = false;
+ goto try_funny_name;
+ }
+ /* falls through */
+ case ')':
+ sreturn(e_syntaxerror);
+ case '}':
+ if ( pstack == 0 )
+ sreturn(e_syntaxerror);
+ osp--;
+ { uint size = ref_stack_count_inline(&o_stack) - pstack;
+ ref arr;
+ if_debug4('S', "[S}]d=%d, s=%d->%ld, c=%d\n",
+ pdepth, pstack,
+ (pstack == pdepth ? 0 :
+ ref_stack_index(&o_stack, size)->value.intval),
+ size + pstack);
+ myref = (pstack == pdepth ? pref : &arr);
+ if ( ref_array_packing.value.boolval )
+ { retcode = make_packed_array(myref, &o_stack,
+ size, "scanner(packed)");
+ if ( retcode < 0 ) /* must be VMerror */
+ { osp++;
+ scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ r_set_attrs(myref, a_executable);
+ }
+ else
+ { retcode = ialloc_ref_array(myref,
+ a_executable + a_all, size,
+ "scanner(proc)");
+ if ( retcode < 0 ) /* must be VMerror */
+ { osp++;
+ scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ retcode = ref_stack_store(&o_stack, myref,
+ size, 0, 1, false, "scanner");
+ if ( retcode < 0 )
+ { ifree_ref_array(myref, "scanner(proc)");
+ sreturn(retcode);
+ }
+ ref_stack_pop(&o_stack, size);
+ }
+ if ( pstack == pdepth )
+ { /* This was the top-level procedure. */
+ spop1();
+ pstack = 0;
+ }
+ else
+ { if ( osp < osbot )
+ ref_stack_pop_block(&o_stack);
+ pstack = osp->value.intval;
+ *osp = arr;
+ goto snext;
+ }
+ }
+ break;
+ case '/':
+ ensure2(scanning_none);
+ c = scan_getc();
+ if ( c == '/' )
+ { name_type = 2;
+ c = scan_getc();
+ }
+ else
+ name_type = 1;
+ try_number = false;
+ switch ( decoder[c] )
+ {
+ case ctype_name:
+ default:
+ goto do_name;
+ case ctype_btoken:
+ if ( !recognize_btokens() ) goto do_name;
+ /* otherwise, an empty name */
+ case ctype_exception:
+ case ctype_space:
+ /*
+ * Amazingly enough, the Adobe implementations don't accept
+ * / or // followed by [, ], <<, or >>, so we do the same.
+ * (Older versions of our code had a ctype_other case here
+ * that handled these specially.)
+ */
+ case ctype_other:
+ da.base = da.limit = daptr = 0;
+ da.is_dynamic = false;
+ goto nx;
+ }
+ case '%':
+ { /* Scan as much as possible within the buffer. */
+ const byte *base = sptr;
+ const byte *end;
+ while ( ++sptr < endptr ) /* stop 1 char early */
+ switch ( *sptr )
+ {
+ case char_CR:
+ end = sptr;
+ if ( sptr[1] == char_EOL )
+ sptr++;
+cend: /* Check for externally processed comments. */
+ retcode = scan_comment(base, end, false);
+ if ( retcode < 0 )
+ goto sret;
+ goto top;
+ case char_EOL:
+ case '\f':
+ end = sptr;
+ goto cend;
+ }
+ /*
+ * We got to the end of the buffer while inside a comment.
+ * If there is a possibility that we must pass the comment
+ * to an external procedure, move what we have collected
+ * so far into a private buffer now.
+ */
+#define comment_line da.buf
+ --sptr;
+ comment_line[1] = 0;
+ if ( scan_comment_proc != NULL ||
+ ((sptr == base || base[1] == '%') &&
+ scan_dsc_proc != NULL)
+ )
+ { /* Could be an externally processable comment. */
+ uint len = sptr + 1 - base;
+ memcpy(comment_line, base, len);
+ daptr = comment_line + len;
+ }
+ else
+ { /* Not a DSC comment. */
+ daptr = comment_line + (max_comment_line + 1);
+ }
+ da.base = comment_line;
+ da.is_dynamic = false;
+ }
+ /* Enter here to continue scanning a comment. */
+ /* daptr must be set. */
+cont_comment: for ( ; ; )
+ { switch ( (c = scan_getc()) )
+ {
+ default:
+ if ( c < 0 )
+ switch ( c )
+ {
+ case INTC:
+ case CALLC:
+ da.next = daptr;
+ scan_type = scanning_comment;
+ goto pause;
+ case EOFC:
+ /*
+ * One would think that an EOF in a comment
+ * should be a syntax error, but there are
+ * quite a number of files that end that way.
+ */
+ goto end_comment;
+ default:
+ sreturn(e_syntaxerror);
+ }
+ if ( daptr < comment_line + max_comment_line )
+ *daptr++ = c;
+ continue;
+ case char_CR:
+ case char_EOL:
+ case '\f':
+end_comment: retcode = scan_comment(comment_line, daptr, true);
+ if ( retcode < 0 )
+ goto sret;
+ goto top;
+ }
+ }
+#undef comment_line
+ /*NOTREACHED*/
+ case EOFC:
+ if ( pstack != 0 )
+ sreturn(e_syntaxerror)
+ retcode = scan_EOF;
+ break;
+ case ERRC:
+ sreturn(e_ioerror);
+
+ /* Check for a Level 2 funny name (<< or >>). */
+ /* c is '<' or '>'. We already did an ensure2. */
+try_funny_name:
+ { int c1 = scan_getc();
+ if ( c1 == c )
+ { s1[0] = s1[1] = c;
+ name_ref(s1, 2, myref, 1); /* can't fail */
+ goto have_name;
+ }
+ scan_putback();
+ } sreturn(e_syntaxerror);
+
+ /* Handle separately the names that might be a number. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '.':
+ sign = 0;
+nr: /*
+ * Skip a leading sign, if any, by conditionally passing
+ * sptr + 1 rather than sptr. Also, if the last character
+ * in the buffer is a CR, we must stop the scan 1 character
+ * early, to be sure that we can test for CR+LF within the
+ * buffer, by passing endptr rather than endptr + 1.
+ */
+ retcode = scan_number(sptr + (sign & 1),
+ endptr /*(*endptr == char_CR ? endptr : endptr + 1)*/,
+ sign, myref, &newptr);
+ if ( retcode == 1 && decoder[newptr[-1]] == ctype_space )
+ { sptr = newptr - 1;
+ if ( *sptr == char_CR && sptr[1] == char_EOL )
+ sptr++;
+ retcode = 0;
+ break;
+ }
+ name_type = 0;
+ try_number = true;
+ goto do_name;
+ case '+':
+ sign = 1;
+ goto nr;
+ case '-':
+ sign = -1;
+ goto nr;
+
+ /* Check for a binary object */
+#define case4(c) case c: case c+1: case c+2: case c+3
+ case4(128): case4(132): case4(136): case4(140):
+ case4(144): case4(148): case4(152): case4(156):
+#undef case4
+ if ( recognize_btokens() )
+ { scan_end_inline();
+ retcode = (*scan_btoken_proc)(s, myref, &sstate);
+ scan_begin_inline();
+ if ( retcode == scan_Refill )
+ goto pause;
+ break;
+ }
+ /* Not a binary object, fall through. */
+
+ /* The default is a name. */
+ default:
+ if ( c < 0 )
+ { dynamic_init(&da, name_memory()); /* da state must be clean */
+ scan_type = scanning_none;
+ goto pause;
+ }
+ /* Populate the switch with enough cases to force */
+ /* simple compilers to use a dispatch rather than tests. */
+ case '!': case '"': case '#': case '$': case '&': case '\'':
+ case '*': case ',': case '=': case ':': case ';': case '?': case '@':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M':
+ case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S':
+ case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case '\\': case '^': case '_': case '`':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
+ case 'n': case 'o': case 'p': case 'q': case 'r': case 's':
+ case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case '|': case '~':
+ /* Common code for scanning a name. */
+ /* try_number and name_type are already set. */
+ /* We know c has ctype_name (or maybe ctype_btoken) */
+ /* or is a digit. */
+ name_type = 0;
+ try_number = false;
+do_name:
+ /* Try to scan entirely within the stream buffer. */
+ /* We stop 1 character early, so we don't switch buffers */
+ /* looking ahead if the name is terminated by \r\n. */
+ da.base = (byte *)sptr;
+ da.is_dynamic = false;
+ { const byte *endp1 = endptr - 1;
+ do
+ { if ( sptr >= endp1 ) /* stop 1 early! */
+ goto dyn_name;
+ }
+ while ( decoder[*++sptr] <= max_name_ctype ); /* digit or name */
+ }
+ /* Name ended within the buffer. */
+ daptr = (byte *)sptr;
+ c = *sptr;
+ goto nx;
+dyn_name: /* Name extended past end of buffer. */
+ scan_end_inline();
+ /* Initialize the dynamic area. */
+ /* We have to do this before the next */
+ /* sgetc, which will overwrite the buffer. */
+ da.limit = (byte *)++sptr;
+ da.memory = name_memory();
+ retcode = dynamic_grow(&da, da.limit, name_max_string);
+ if ( retcode < 0 )
+ { dynamic_save(&da);
+ if ( retcode != e_VMerror )
+ sreturn(retcode);
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ daptr = da.next;
+ /* Enter here to continue scanning a name. */
+ /* daptr must be set. */
+cont_name: scan_begin_inline();
+ while ( decoder[c = scan_getc()] <= max_name_ctype )
+ { if ( daptr == da.limit )
+ { retcode = dynamic_grow(&da, daptr,
+ name_max_string);
+ if ( retcode < 0 )
+ { dynamic_save(&da);
+ if ( retcode != e_VMerror )
+ sreturn(retcode);
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ daptr = da.next;
+ }
+ *daptr++ = c;
+ }
+nx: switch ( decoder[c] )
+ {
+ case ctype_btoken:
+ case ctype_other:
+ scan_putback();
+ break;
+ case ctype_space:
+ /* Check for \r\n */
+ if ( c == char_CR )
+ { if ( sptr >= endptr ) /* ensure2 */
+ { /* We have to check specially for */
+ /* the case where the very last */
+ /* character of a file is a CR. */
+ if ( s->end_status != EOFC )
+ { sptr--;
+ goto pause_name;
+ }
+ }
+ else if ( sptr[1] == char_EOL )
+ sptr++;
+ }
+ break;
+ case ctype_exception:
+ switch ( c )
+ {
+ case INTC:
+ case CALLC:
+ goto pause_name;
+ case ERRC:
+ sreturn(e_ioerror);
+ case EOFC:
+ break;
+ }
+ }
+ /* Check for a number */
+ if ( try_number )
+ { const byte *base = da.base;
+
+ scan_sign(sign, base);
+ retcode = scan_number(base, daptr, sign, myref, &newptr);
+ if ( retcode == 1 )
+ retcode = 0;
+ else if ( retcode != e_syntaxerror )
+ { dynamic_free(&da);
+ if ( name_type == 2 )
+ sreturn(e_syntaxerror);
+ break; /* might be e_limitcheck */
+ }
+ }
+ if ( da.is_dynamic )
+ { /* We've already allocated the string on the heap. */
+ uint size = daptr - da.base;
+ retcode = name_ref(da.base, size, myref, -1);
+ if ( retcode >= 0 )
+ { dynamic_free(&da);
+ }
+ else
+ { retcode = dynamic_resize(&da, size);
+ if ( retcode < 0 ) /* VMerror */
+ { if ( c != EOFC )
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ retcode = name_ref(da.base, size, myref, 2);
+ }
+ }
+ else
+ { retcode = name_ref(da.base, (uint)(daptr - da.base),
+ myref, 1);
+ }
+ /* Done scanning. Check for preceding /'s. */
+ if ( retcode < 0 )
+ { if ( retcode != e_VMerror )
+ sreturn(retcode);
+ if ( !da.is_dynamic )
+ { da.next = daptr;
+ dynamic_save(&da);
+ }
+ if ( c != EOFC )
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+have_name: switch ( name_type )
+ {
+ case 0: /* ordinary executable name */
+ if ( r_has_type(myref, t_name) ) /* i.e., not a number */
+ r_set_attrs(myref, a_executable);
+ case 1: /* quoted name */
+ break;
+ case 2: /* immediate lookup */
+ { ref *pvalue;
+ if ( !r_has_type(myref, t_name) )
+ sreturn(e_undefined);
+ if ( (pvalue = dict_find_name(myref)) == 0 )
+ sreturn(e_undefined);
+ if ( pstack != 0 &&
+ r_space(pvalue) > ialloc_space(idmemory)
+ )
+ sreturn(e_invalidaccess);
+ ref_assign_new(myref, pvalue);
+ }
+ }
+ }
+sret: if ( retcode < 0 )
+ { scan_end_inline();
+ if ( pstack != 0 )
+ ref_stack_pop(&o_stack,
+ ref_stack_count(&o_stack) - (pdepth - 1));
+ return retcode;
+ }
+ /* If we are at the top level, return the object, */
+ /* otherwise keep going. */
+ if ( pstack == 0 )
+ { scan_end_inline();
+ return retcode;
+ }
+snext: if_not_spush1()
+ { scan_end_inline();
+ scan_type = scanning_none;
+ goto save;
+ }
+ myref = osp;
+ goto top;
+
+ /* Pause for an interrupt or callout. */
+pause_name:
+ /* If we're still scanning within the stream buffer, */
+ /* move the characters to the private buffer (da.buf) now. */
+ da.next = daptr;
+ dynamic_save(&da);
+ scan_type = scanning_name;
+pause:
+ retcode = scan_Refill;
+pause_ret:
+ scan_end_inline();
+suspend:
+ if ( pstack != 0 )
+ osp--; /* myref */
+save:
+ sstate.s_from_string = pstate->s_from_string;
+ *pstate = sstate;
+ return retcode;
+}
diff --git a/gs/src/iscan.h b/gs/src/iscan.h
new file mode 100644
index 000000000..b315318b4
--- /dev/null
+++ b/gs/src/iscan.h
@@ -0,0 +1,143 @@
+/* Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iscan.h */
+/* Interface to Ghostscript scanner */
+/* Requires gsstruct.h, ostack.h, stream.h */
+#include "sa85x.h"
+#include "sstring.h"
+
+/*
+ * Define the state of the scanner. Before calling scan_token initially,
+ * the caller must initialize the state by calling scanner_state_init.
+ * Most of the state is only used if scanning is suspended because of
+ * an interrupt or a callout.
+ *
+ * We expose the entire state definition to the caller so that
+ * the state can normally be allocated on the stack.
+ */
+typedef struct scanner_state_s scanner_state;
+
+/*
+ * Define a structure for dynamically growable strings.
+ * If is_dynamic is true, base/next/limit point to a string on the heap;
+ * if is_dynamic is false, base/next/limit point either to the local buffer
+ * or (only while control is inside scan_token) into the source stream buffer.
+ */
+#define max_comment_line 255 /* max size of an externally processable comment */
+#define max_dsc_line max_comment_line /* backward compatibility */
+#define da_buf_size (max_comment_line + 2)
+typedef struct dynamic_area_s {
+ gs_string str; /* for GC */
+ byte *base;
+ byte *next;
+ byte *limit;
+ bool is_dynamic;
+ byte buf[da_buf_size]; /* initial buffer */
+ gs_memory_t *memory;
+} dynamic_area;
+#define da_size(pda) ((uint)((pda)->limit - (pda)->base))
+typedef dynamic_area _ss *da_ptr;
+
+/* Define state specific to binary tokens and binary object sequences. */
+typedef struct scan_binary_state_s {
+ int num_format;
+ int (*cont)(P3(stream *, ref *, scanner_state *));
+ ref bin_array;
+ uint index;
+ uint max_array_index; /* largest legal index in objects */
+ uint min_string_index; /* smallest legal index in strings */
+ uint top_size;
+ uint size;
+} scan_binary_state;
+
+/* Define the scanner state. */
+struct scanner_state_s {
+ uint s_pstack; /* stack depth when starting current */
+ /* procedure, after pushing old pstack */
+ uint s_pdepth; /* pstack for very first { encountered, */
+ /* for error recovery */
+ bool s_from_string; /* true if string is source of data */
+ /* (for Level 1 `\' handling) */
+ enum {
+ scanning_none,
+ scanning_binary,
+ scanning_comment,
+ scanning_name,
+ scanning_string
+ } s_scan_type;
+ dynamic_area s_da;
+ union sss_ { /* scanning sub-state */
+ scan_binary_state binary; /* binary */
+ struct sns_ { /* name */
+ int s_name_type; /* number of /'s preceding a name */
+ bool s_try_number; /* true if should try scanning name */
+ /* as number */
+ } s_name;
+ stream_state st; /* string */
+ stream_A85D_state a85d; /* string */
+ stream_AXD_state axd; /* string */
+ stream_PSSD_state pssd; /* string */
+ } s_ss;
+};
+/* The type descriptor is public only for checking. */
+extern_st(st_scanner_state);
+#define public_st_scanner_state() /* in iscan.c */\
+ gs_public_st_complex_only(st_scanner_state, scanner_state, "scanner state",\
+ scanner_clear_marks, scanner_enum_ptrs, scanner_reloc_ptrs, 0)
+#define scanner_state_init(pstate, from_string)\
+ ((pstate)->s_scan_type = scanning_none,\
+ (pstate)->s_pstack = 0,\
+ (pstate)->s_from_string = from_string)
+
+/*
+ * Read a token from a stream. As usual, 0 is a normal return,
+ * <0 is an error. There are also three special return codes:
+ */
+#define scan_BOS 1 /* binary object sequence */
+#define scan_EOF 2 /* end of stream */
+#define scan_Refill 3 /* get more input data, then call again */
+int scan_token(P3(stream *s, ref *pref, scanner_state *pstate));
+
+/*
+ * Read a token from a string. Return like scan_token, but also
+ * update the string to move past the token (if no error).
+ */
+int scan_string_token(P2(ref *pstr, ref *pref));
+
+/*
+ * Handle a scan_Refill return from scan_token.
+ * This may return o_push_estack, 0 (meaning just call scan_token again),
+ * or an error code.
+ */
+int scan_handle_refill(P5(const ref *fop, scanner_state *pstate, bool save,
+ bool push_file, int (*cont)(P1(os_ptr))));
+
+/*
+ * Define the procedure "hook" for parsing DSC comments. If not NULL,
+ * this procedure is called for every DSC comment seen by the scanner.
+ */
+extern int (*scan_dsc_proc)(P2(const byte *, uint));
+
+/*
+ * Define the procedure "hook" for parsing general comments. If not NULL,
+ * this procedure is called for every comment seen by the scanner.
+ * If both scan_dsc_proc and scan_comment_proc are set,
+ * scan_comment_proc is called only for non-DSC comments.
+ */
+extern int (*scan_comment_proc)(P2(const byte *, uint));
diff --git a/gs/src/iscanbin.c b/gs/src/iscanbin.c
new file mode 100644
index 000000000..3ce3957f0
--- /dev/null
+++ b/gs/src/iscanbin.c
@@ -0,0 +1,576 @@
+/* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iscanbin.c */
+/* Ghostscript binary token scanner */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "gsutil.h"
+#include "stream.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h" /* for immediately evaluated names */
+#include "ostack.h" /* must precede iscan.h */
+#include "iname.h"
+#include "iscan.h" /* for scan_Refill */
+#include "iutil.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "bseq.h"
+#include "btoken.h"
+#include "ibnum.h"
+
+/* Define the number of required initial bytes for binary tokens. */
+const byte bin_token_bytes[] = { bin_token_bytes_values };
+
+/* Import the system and user name tables */
+extern ref system_names, user_names;
+
+/* Forward references */
+private int scan_bin_num_array_continue(P3(stream *, ref *, scanner_state *));
+private int scan_bin_string_continue(P3(stream *, ref *, scanner_state *));
+private int scan_bos_continue(P3(stream *, ref *, scanner_state *));
+private byte *scan_bos_resize(P3(scanner_state *, uint, uint));
+private int scan_bos_string_continue(P3(stream *, ref *, scanner_state *));
+
+/* Scan a binary token. Called from the main scanner */
+/* when it encounters an ASCII code 128-159, */
+/* if binary tokens are being recognized (object format != 0). */
+#define pbs (&pstate->s_ss.binary)
+int
+scan_binary_token(stream *s, ref *pref, scanner_state *pstate)
+{ s_declare_inline(s, p, rlimit);
+#define return_skip(n) { p += n; s_end_inline(s, p, rlimit); return 0; }
+ int num_format, code;
+ uint arg;
+ uint wanted;
+ uint rcnt;
+ s_begin_inline(s, p, rlimit);
+ wanted = binary_token_bytes(*p) - 1;
+ rcnt = rlimit - p;
+#define return_refill()\
+ { sputback_inline(s, p, rlimit); s_end_inline(s, p, rlimit);\
+ pstate->s_scan_type = scanning_none; return scan_Refill;\
+ }
+ if ( rcnt < wanted )
+ return_refill();
+ switch ( *p )
+ {
+ case bt_seq_IEEE_msb:
+ num_format = num_msb + num_float_IEEE; goto bseq;
+ case bt_seq_IEEE_lsb:
+ num_format = num_lsb + num_float_IEEE; goto bseq;
+ case bt_seq_native_msb:
+ num_format = num_msb + num_float_native; goto bseq;
+ case bt_seq_native_lsb:
+ num_format = num_lsb + num_float_native;
+bseq: pbs->num_format = num_format;
+ { uint top_size = p[1];
+ uint hsize, size;
+ if ( top_size == 0 )
+ { /* Extended header (2-byte array size, */
+ /* 4-byte length) */
+ ulong lsize;
+ if ( rcnt < 7 )
+ return_refill();
+ top_size = sdecodeshort(p + 2, num_format);
+ lsize = sdecodelong(p + 4, num_format);
+ if ( (size = lsize) != lsize )
+ return_error(e_limitcheck);
+ hsize = 8;
+ }
+ else
+ { /* Normal header (1-byte array size, 2-byte length). */
+ /* We already checked rcnt >= 3. */
+ size = sdecodeshort(p + 2, num_format);
+ hsize = 4;
+ }
+ if ( size < hsize )
+ return_error(e_syntaxerror);
+ /* Preallocate an array large enough for the worst case, */
+ /* namely, all objects and no strings. */
+ code = ialloc_ref_array(&pbs->bin_array,
+ a_all + a_executable,
+ size / sizeof(ref),
+ "binary object sequence(objects)");
+ if ( code < 0 )
+ return code;
+ p += hsize - 1;
+ size -= hsize;
+ s_end_inline(s, p, rlimit);
+ pbs->max_array_index = pbs->top_size = top_size;
+ pbs->min_string_index = pbs->size = size;
+ pbs->index = 0;
+ }
+ pstate->s_da.is_dynamic = false;
+ pstate->s_da.base = pstate->s_da.next =
+ pstate->s_da.limit = pstate->s_da.buf;
+ code = scan_bos_continue(s, pref, pstate);
+ if ( code == scan_Refill || code < 0 )
+ { /* Clean up array for GC. */
+ uint index = pbs->index;
+ refset_null(pbs->bin_array.value.refs + index,
+ r_size(&pbs->bin_array) - index);
+ pbs->cont = scan_bos_continue;
+ }
+ return code;
+ case bt_int32_msb:
+ num_format = num_msb + num_int32; goto num;
+ case bt_int32_lsb:
+ num_format = num_lsb + num_int32; goto num;
+ case bt_int16_msb:
+ num_format = num_msb + num_int16; goto num;
+ case bt_int16_lsb:
+ num_format = num_lsb + num_int16; goto num;
+ case bt_int8:
+ make_int(pref, (p[1] ^ 128) - 128);
+ return_skip(1);
+ case bt_fixed:
+ num_format = p[1];
+ if ( !num_is_valid(num_format) )
+ return_error(e_syntaxerror);
+ wanted = 1 + encoded_number_bytes(num_format);
+ if ( rcnt < wanted )
+ return_refill();
+ code = sdecode_number(p + 2, num_format, pref);
+ goto rnum;
+ case bt_float_IEEE_msb:
+ num_format = num_msb + num_float_IEEE; goto num;
+ case bt_float_IEEE_lsb:
+ num_format = num_lsb + num_float_IEEE; goto num;
+ case bt_float_native:
+ num_format = num_float_native;
+num: code = sdecode_number(p + 1, num_format, pref);
+rnum: switch ( code )
+ {
+ case t_integer: case t_real:
+ r_set_type(pref, code);
+ break;
+ case t_null:
+ return_error(e_syntaxerror);
+ default:
+ return code;
+ }
+ return_skip(wanted);
+ case bt_boolean:
+ arg = p[1];
+ if ( arg & ~1 )
+ return_error(e_syntaxerror);
+ make_bool(pref, arg);
+ return_skip(1);
+ case bt_string_256:
+ arg = p[1]; p++; goto str;
+ case bt_string_64k_msb:
+ arg = (p[1] << 8) + p[2]; p += 2; goto str;
+ case bt_string_64k_lsb:
+ arg = p[1] + (p[2] << 8); p += 2; goto str;
+str: { byte *str = ialloc_string(arg, "string token");
+ if ( str == 0 )
+ return_error(e_VMerror);
+ s_end_inline(s, p, rlimit);
+ pstate->s_da.base = pstate->s_da.next = str;
+ pstate->s_da.limit = str + arg;
+ code = scan_bin_string_continue(s, pref, pstate);
+ if ( code == scan_Refill || code < 0 )
+ { pstate->s_da.is_dynamic = true;
+ make_null(&pbs->bin_array); /* clean up for GC */
+ pbs->cont = scan_bin_string_continue;
+ }
+ return code;
+ }
+ case bt_litname_system:
+ code = array_get(&system_names, p[1], pref);
+ goto lname;
+ case bt_execname_system:
+ code = array_get(&system_names, p[1], pref);
+ goto xname;
+ case bt_litname_user:
+ code = array_get(&user_names, p[1], pref);
+lname: if ( code < 0 ) return code;
+ if ( !r_has_type(pref, t_name) )
+ return_error(e_undefined);
+ return_skip(1);
+ case bt_execname_user:
+ code = array_get(&user_names, p[1], pref);
+xname: if ( code < 0 ) return code;
+ if ( !r_has_type(pref, t_name) )
+ return_error(e_undefined);
+ r_set_attrs(pref, a_executable);
+ return_skip(1);
+ case bt_num_array:
+ num_format = p[1];
+ if ( !num_is_valid(num_format) )
+ return_error(e_syntaxerror);
+ arg = sdecodeshort(p + 2, num_format);
+ code = ialloc_ref_array(&pbs->bin_array, a_all, arg,
+ "number array token");
+ if ( code < 0 )
+ return code;
+ pbs->num_format = num_format;
+ pbs->index = 0;
+ p += 3;
+ s_end_inline(s, p, rlimit);
+ code = scan_bin_num_array_continue(s, pref, pstate);
+ if ( code == scan_Refill || code < 0 )
+ { /* Make sure the array is clean for the GC. */
+ refset_null(pbs->bin_array.value.refs + pbs->index,
+ arg - pbs->index);
+ pbs->cont = scan_bin_num_array_continue;
+ }
+ return code;
+ }
+ return_error(e_syntaxerror);
+}
+
+/* Continue collecting a binary string. */
+private int
+scan_bin_string_continue(stream *s, ref *pref, scanner_state *pstate)
+{ byte *q = pstate->s_da.next;
+ uint wanted = pstate->s_da.limit - q;
+ uint rcnt;
+ sgets(s, q, wanted, &rcnt);
+ if ( rcnt == wanted )
+ { /* Finished collecting the string. */
+ make_string(pref, a_all | icurrent_space,
+ pstate->s_da.limit - pstate->s_da.base,
+ pstate->s_da.base);
+ return 0;
+ }
+ pstate->s_da.next = q + rcnt;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+}
+
+/* Continue scanning a binary number array. */
+private int
+scan_bin_num_array_continue(stream *s, ref *pref, scanner_state *pstate)
+{ uint index = pbs->index;
+ ref *np = pbs->bin_array.value.refs + index;
+ uint wanted = encoded_number_bytes(pbs->num_format);
+ for ( ; index < r_size(&pbs->bin_array); index++, np++ )
+ { int code;
+ if ( sbufavailable(s) < wanted )
+ { pbs->index = index;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+ }
+ code = sdecode_number(sbufptr(s), pbs->num_format, np);
+ switch ( code )
+ {
+ case t_integer: case t_real:
+ r_set_type(np, code);
+ sbufskip(s, wanted);
+ break;
+ case t_null:
+ return_error(e_syntaxerror);
+ default:
+ return code;
+ }
+ }
+ *pref = pbs->bin_array;
+ return 0;
+}
+
+/*
+ * Continue scanning a binary object sequence. We preallocated space for
+ * the largest possible number of objects, but not for strings, since
+ * the latter would probably be a gross over-estimate. Instead,
+ * we wait until we see the first string or name, and allocate string space
+ * based on the hope that its string index is the smallest one we will see.
+ * If this turns out to be wrong, we may have to reallocate, and adjust
+ * all the pointers.
+ */
+#define sizeof_bin_seq_obj ((uint)sizeof(bin_seq_obj))
+private int
+scan_bos_continue(register stream *s, ref *pref, scanner_state *pstate)
+{ s_declare_inline(s, p, rlimit);
+ uint max_array_index = pbs->max_array_index;
+ uint min_string_index = pbs->min_string_index;
+ int format = pbs->num_format;
+#if arch_is_big_endian
+# define must_swap_bytes num_is_lsb(format)
+#else
+# define must_swap_bytes !num_is_lsb(format)
+#endif
+ uint index = pbs->index;
+ uint size = pbs->size;
+ ref *abase = pbs->bin_array.value.refs;
+ int code;
+ s_begin_inline(s, p, rlimit);
+ for ( ; index < max_array_index; index++ )
+ { bin_seq_obj ob;
+ byte bt;
+ ref *op = abase + index;
+ uint atype, sattrs;
+ s_end_inline(s, p, rlimit); /* in case of error */
+ if ( rlimit - p < sizeof_bin_seq_obj )
+ { pbs->index = index;
+ pbs->max_array_index = max_array_index;
+ pbs->min_string_index = min_string_index;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+ }
+ memcpy(&ob, p + 1, sizeof_bin_seq_obj);
+ p += sizeof_bin_seq_obj;
+#define do_swap_size()\
+ bt = ob.size.b[0], ob.size.b[0] = ob.size.b[1], ob.size.b[1] = bt
+#define swap_size()\
+ if ( must_swap_bytes ) do_swap_size()
+#define do_swap_value()\
+ bt = ob.value.b[0], ob.value.b[0] = ob.value.b[3], ob.value.b[3] = bt,\
+ bt = ob.value.b[1], ob.value.b[1] = ob.value.b[2], ob.value.b[2] = bt
+#define swap_value()\
+ if ( must_swap_bytes ) do_swap_value()
+#define swap_size_also_value()\
+ if ( must_swap_bytes ) do_swap_size(), do_swap_value()
+ switch ( ob.tx & 0x7f )
+ {
+ case bs_null:
+ make_null(op); break;
+ case bs_integer:
+ swap_value();
+ make_int(op, ob.value.w);
+ break;
+ case bs_real:
+ if ( ob.size.w != 0 ) /* fixed-point number */
+ { swap_size_also_value();
+ ob.value.f = (float)ldexp((float)ob.value.w,
+ -ob.size.w);
+ }
+ else if ( (format & ~(num_lsb | num_msb)) !=
+ num_float_native
+ )
+ { ob.value.f = sdecodefloat(ob.value.b, format);
+ }
+ make_real(op, ob.value.f);
+ break;
+ case bs_boolean:
+ swap_value();
+ make_bool(op, (ob.value.w == 0 ? 0 : 1));
+ break;
+ case bs_string:
+ swap_size_also_value();
+ sattrs = (ob.tx < 128 ? a_all : a_all + a_executable);
+str: if ( ob.size.w == 0 )
+ { /* For zero-length strings, the offset */
+ /* doesn't matter, and may be zero. */
+ make_empty_string(op, sattrs);
+ break;
+ }
+ if ( ob.value.w < max_array_index * sizeof_bin_seq_obj ||
+ ob.value.w + ob.size.w > size
+ )
+ return_error(e_syntaxerror);
+ if ( ob.value.w < min_string_index )
+ { /* We have to (re)allocate the strings. */
+ uint str_size = size - ob.value.w;
+ byte *sbase;
+ if ( pstate->s_da.is_dynamic )
+ sbase = scan_bos_resize(pstate, str_size,
+ index);
+ else
+ sbase = ialloc_string(str_size,
+ "bos strings");
+ if ( sbase == 0 )
+ return_error(e_VMerror);
+ pstate->s_da.is_dynamic = true;
+ pstate->s_da.base = pstate->s_da.next = sbase;
+ pstate->s_da.limit = sbase + str_size;
+ min_string_index = ob.value.w;
+ }
+ make_string(op, sattrs | icurrent_space, ob.size.w,
+ pstate->s_da.base +
+ (ob.value.w - min_string_index));
+ break;
+ case bs_name:
+ sattrs = (ob.tx < 128 ? 0 : a_executable);
+ goto nam;
+ case bs_eval_name:
+ sattrs = a_readonly;
+nam: swap_size_also_value();
+ switch ( ob.size.w )
+ {
+ case 0:
+ code = array_get(&user_names, ob.value.w, op);
+ goto usn;
+ case 0xffff:
+ code = array_get(&system_names, ob.value.w, op);
+usn: if ( code < 0 )
+ return code;
+ if ( !r_has_type(op, t_name) )
+ return_error(e_undefined);
+ r_set_attrs(op, sattrs);
+ break;
+ default:
+ goto str;
+ }
+ break;
+ case bs_array:
+ swap_size_also_value();
+ atype = t_array;
+arr: if ( ob.value.w + ob.size.w > min_string_index ||
+ ob.value.w & (sizeof_bin_seq_obj - 1)
+ )
+ return_error(e_syntaxerror);
+ { uint aindex = ob.value.w / sizeof_bin_seq_obj;
+ max_array_index =
+ max(max_array_index, aindex + ob.size.w);
+ make_tasv_new(op, atype,
+ (ob.tx < 128 ? a_all :
+ a_all + a_executable) | icurrent_space,
+ ob.size.w, refs, abase + aindex);
+ }
+ break;
+ case bs_dictionary: /* EXTENSION */
+ swap_size_also_value();
+ if ( (ob.size.w & 1) != 0 && ob.size.w != 1 )
+ return_error(e_syntaxerror);
+ atype = t_mixedarray; /* mark as dictionary */
+ goto arr;
+ case bs_mark:
+ make_mark(op); break;
+ default:
+ return_error(e_syntaxerror);
+ }
+ }
+ s_end_inline(s, p, rlimit);
+ /* Shorten the objects to remove the space that turned out */
+ /* to be used for strings. */
+ iresize_ref_array(&pbs->bin_array, max_array_index,
+ "binary object sequence(objects)");
+ code = scan_bos_string_continue(s, pref, pstate);
+ if ( code == scan_Refill )
+ { pbs->cont = scan_bos_string_continue;
+ }
+ return code;
+}
+
+/* Reallocate the strings for a binary object sequence, */
+/* adjusting all the pointers to them from objects. */
+private byte *
+scan_bos_resize(scanner_state *pstate, uint new_size, uint index)
+{ uint old_size = da_size(&pstate->s_da);
+ byte *old_base = pstate->s_da.base;
+ byte *new_base = iresize_string(old_base, old_size, new_size,
+ "scan_bos_resize");
+ byte *relocated_base = new_base + (new_size - old_size);
+ uint i;
+ ref *aptr = pbs->bin_array.value.refs;
+ if ( new_base == 0 )
+ return 0;
+ /* Since the allocator normally extends strings downward, */
+ /* it's quite possible that new and old addresses are the same. */
+ if ( relocated_base != old_base )
+ for ( i = index; i != 0; i--, aptr++ )
+ if ( r_has_type(aptr, t_string) && r_size(aptr) != 0 )
+ aptr->value.bytes =
+ aptr->value.bytes - old_base + relocated_base;
+ return new_base;
+}
+
+/* Continue reading the strings for a binary object sequence. */
+private int
+scan_bos_string_continue(register stream *s, ref *pref, scanner_state *pstate)
+{ ref rstr;
+ ref *op = pbs->bin_array.value.refs;
+ int code = scan_bin_string_continue(s, &rstr, pstate);
+ uint space = ialloc_space(idmemory);
+ bool rescan = false;
+ uint i;
+
+ if ( code != 0 )
+ return code;
+ /* Finally, fix up names and dictionaries. */
+ for ( i = r_size(&pbs->bin_array); i != 0; i--, op++ )
+ switch ( r_type(op) )
+ {
+ case t_string:
+ if ( r_has_attr(op, a_write) ) /* a real string */
+ break;
+ /* This is actually a name; look it up now. */
+ { uint sattrs =
+ (r_has_attr(op, a_executable) ? a_executable : 0);
+ code = name_ref(op->value.bytes, r_size(op), op, 1);
+ if ( code < 0 )
+ return code;
+ r_set_attrs(op, sattrs);
+ }
+ /* falls through */
+ case t_name:
+ if ( r_has_attr(op, a_read) ) /* bs_eval_name */
+ { ref *defp = dict_find_name(op);
+ if ( defp == 0 )
+ return_error(e_undefined);
+ store_check_space(space, defp);
+ ref_assign(op, defp);
+ }
+ break;
+ case t_mixedarray: /* actually a dictionary */
+ { uint count = r_size(op);
+ ref rdict;
+ if ( count == 1 )
+ { /* Indirect reference. */
+ if ( op->value.refs < op )
+ ref_assign(&rdict, op->value.refs);
+ else
+ { rescan = true;
+ continue;
+ }
+ }
+ else
+ { code = dict_create(count >> 1, &rdict);
+ if ( code < 0 )
+ return code;
+ while ( count )
+ { count -= 2;
+ code = dict_put(&rdict,
+ &op->value.refs[count],
+ &op->value.refs[count + 1]);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ r_set_attrs(&rdict, a_all);
+ r_copy_attrs(&rdict, a_executable, op);
+ ref_assign(op, &rdict);
+ }
+ break;
+ }
+ /* If there were any forward indirect references, */
+ /* fix them up now. */
+ if ( rescan )
+ for ( op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
+ i != 0; i--, op++
+ )
+ if ( r_has_type(op, t_mixedarray) )
+ { const ref *piref = op->value.const_refs;
+ ref rdict;
+ if ( r_has_type(piref, t_mixedarray) ) /* ref to indirect */
+ return_error(e_syntaxerror);
+ ref_assign(&rdict, piref);
+ r_copy_attrs(&rdict, a_executable, op);
+ ref_assign(op, &rdict);
+ }
+ ref_assign(pref, &pbs->bin_array);
+ r_set_size(pref, pbs->top_size);
+ return scan_BOS;
+}
diff --git a/gs/src/iscannum.c b/gs/src/iscannum.c
new file mode 100644
index 000000000..fb63e4752
--- /dev/null
+++ b/gs/src/iscannum.c
@@ -0,0 +1,377 @@
+/* Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iscannum.c */
+/* Number scanner for Ghostscript interpreter */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "scommon.h"
+#include "iscannum.h" /* defines interface */
+#include "scanchar.h"
+#include "store.h"
+
+#define is_digit(d, c)\
+ ((d = decoder[c]) < 10)
+
+#define scan_sign(sign, ptr)\
+ switch ( *ptr ) {\
+ case '-': sign = -1; ptr++; break;\
+ case '+': sign = 1; ptr++; break;\
+ default: sign = 0;\
+ }
+
+/* Note that the number scanning procedures use a byte ** and a byte * */
+/* rather than a stream. (It makes quite a difference in performance.) */
+#define ngetc(cvar, sp, exit)\
+ if ( sp >= end ) { exit; } else cvar = *sp++
+
+/* Scan a number. If the number consumes the entire string, return 0; */
+/* if not, set *psp to the first character beyond the number and return 1. */
+int
+scan_number(register const byte *sp, const byte *end, int sign,
+ ref *pref, const byte **psp)
+{ /* Powers of 10 up to 6 can be represented accurately as */
+ /* a single-precision float. */
+#define num_powers_10 6
+ static const float powers_10[num_powers_10+1] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
+ };
+ static const double neg_powers_10[num_powers_10+1] = {
+ 1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6
+ };
+ int ival;
+ long lval;
+ double dval;
+ int exp10;
+ int code = 0;
+ register int c, d;
+ register const byte _ds *decoder = scan_char_decoder;
+
+ ngetc(c, sp, return_error(e_syntaxerror));
+#define would_overflow(val, d, maxv)\
+ (val >= maxv / 10 && (val > maxv / 10 || d > (int)(maxv % 10)))
+ if ( !is_digit(d, c) )
+ { if ( c != '.' )
+ return_error(e_syntaxerror);
+ /* Might be a number starting with '.'. */
+ ngetc(c, sp, return_error(e_syntaxerror));
+ if ( !is_digit(d, c) )
+ return_error(e_syntaxerror);
+ ival = 0;
+ goto i2r;
+ }
+
+ /* Accumulate an integer in ival. */
+ /* Do up to 4 digits without a loop, */
+ /* since we know this can't overflow and since */
+ /* most numbers have 4 (integer) digits or fewer. */
+ ival = d;
+ if ( end - sp >= 3 ) /* just check once */
+ { if ( !is_digit(d, (c = *sp)) )
+ { sp++;
+ goto ind;
+ }
+ ival = ival * 10 + d;
+ if ( !is_digit(d, (c = sp[1])) )
+ { sp += 2;
+ goto ind;
+ }
+ ival = ival * 10 + d;
+ sp += 3;
+ if ( !is_digit(d, (c = sp[-1])) )
+ goto ind;
+ ival = ival * 10 + d;
+ }
+ for ( ; ; ival = ival * 10 + d )
+ { ngetc(c, sp, goto iret);
+ if ( !is_digit(d, c) )
+ break;
+ if ( would_overflow(ival, d, max_int) )
+ goto i2l;
+ }
+ind: /* We saw a non-digit while accumulating an integer in ival. */
+ switch ( c )
+ {
+ case '.':
+ ngetc(c, sp, c = EOFC);
+ goto i2r;
+ default:
+ *psp = sp;
+ code = 1;
+ break;
+ case 'e': case 'E':
+ if ( sign < 0 )
+ ival = -ival;
+ dval = ival;
+ exp10 = 0;
+ goto fe;
+ case '#':
+ { ulong uval = 0, lmax;
+#define radix (uint)ival
+ if ( sign || radix < min_radix || radix > max_radix )
+ return_error(e_syntaxerror);
+ /* Avoid multiplies for power-of-2 radix. */
+ if ( !(radix & (radix - 1)) )
+ { int shift;
+ switch ( radix )
+ {
+#define set_shift(n)\
+ shift = n; lmax = max_ulong >> n
+ case 2: set_shift(1); break;
+ case 4: set_shift(2); break;
+ case 8: set_shift(3); break;
+ case 16: set_shift(4); break;
+ case 32: set_shift(5); break;
+#undef set_shift
+ default: /* can't happen */
+ return_error(e_rangecheck);
+ }
+ for ( ; ; uval = (uval << shift) + d )
+ { ngetc(c, sp, break);
+ d = decoder[c];
+ if ( d >= radix )
+ { *psp = sp;
+ code = 1;
+ break;
+ }
+ if ( uval > lmax )
+ return_error(e_limitcheck);
+ }
+ }
+ else
+ { int lrem = max_ulong % radix;
+ lmax = max_ulong / radix;
+ for ( ; ; uval = uval * radix + d )
+ { ngetc(c, sp, break);
+ d = decoder[c];
+ if ( d >= radix )
+ { *psp = sp;
+ code = 1;
+ break;
+ }
+ if ( uval >= lmax &&
+ (uval > lmax || d > lrem)
+ )
+ return_error(e_limitcheck);
+ }
+ }
+#undef radix
+ make_int_new(pref, uval);
+ return code;
+ }
+ }
+iret: make_int_new(pref, (sign < 0 ? -ival : ival));
+ return code;
+
+ /* Accumulate a long in lval. */
+i2l: for ( lval = ival; ; )
+ { if ( would_overflow(lval, d, max_long) )
+ { /* Make a special check for entering the smallest */
+ /* (most negative) integer. */
+ if ( lval == max_long / 10 &&
+ d == (int)(max_long % 10) + 1 && sign < 0
+ )
+ { ngetc(c, sp, c = EOFC);
+ dval = -(double)min_long;
+ if ( c == 'e' || c == 'E' || c == '.' )
+ { exp10 = 0;
+ goto fs;
+ }
+ else if ( !is_digit(d, c) )
+ { lval = min_long;
+ break;
+ }
+ }
+ else
+ dval = lval;
+ goto l2d;
+ }
+ lval = lval * 10 + d;
+ ngetc(c, sp, goto lret);
+ if ( !is_digit(d, c) )
+ break;
+ }
+ switch ( c )
+ {
+ case '.':
+ ngetc(c, sp, c = EOFC);
+ exp10 = 0;
+ goto l2r;
+ default:
+ *psp = sp;
+ code = 1;
+ break;
+ case 'e': case 'E':
+ exp10 = 0;
+ goto le;
+ case '#':
+ return_error(e_syntaxerror);
+ }
+lret: make_int_new(pref, (sign < 0 ? -lval : lval));
+ return code;
+
+ /* Accumulate a double in dval. */
+l2d: exp10 = 0;
+ for ( ; ; )
+ { dval = dval * 10 + d;
+ ngetc(c, sp, c = EOFC);
+ if ( !is_digit(d, c) )
+ break;
+ }
+ switch ( c )
+ {
+ case '.':
+ ngetc(c, sp, c = EOFC);
+ exp10 = 0;
+ goto fs;
+ default:
+ *psp = sp;
+ code = 1;
+ /* falls through */
+ case EOFC:
+ if ( sign < 0 )
+ dval = -dval;
+ goto rret;
+ case 'e': case 'E':
+ exp10 = 0;
+ goto fs;
+ case '#':
+ return_error(e_syntaxerror);
+ }
+
+ /* We saw a '.' while accumulating an integer in ival. */
+i2r: exp10 = 0;
+ while ( is_digit(d, c) )
+ { if ( would_overflow(ival, d, max_int) )
+ { lval = ival;
+ goto l2r;
+ }
+ ival = ival * 10 + d;
+ exp10--;
+ ngetc(c, sp, c = EOFC);
+ }
+ if ( sign < 0 )
+ ival = -ival;
+ /* Take a shortcut for the common case */
+ if ( !(c == 'e' || c == 'E' || exp10 < -num_powers_10) )
+ { /* Check for trailing garbage */
+ if ( c != EOFC )
+ *psp = sp, code = 1;
+ make_real_new(pref, ival * neg_powers_10[-exp10]);
+ return code;
+ }
+ dval = ival;
+ goto fe;
+
+ /* We saw a '.' while accumulating a long in lval. */
+l2r: while ( is_digit(d, c) )
+ { if ( would_overflow(lval, d, max_long) )
+ { dval = lval;
+ goto fd;
+ }
+ lval = lval * 10 + d;
+ exp10--;
+ ngetc(c, sp, c = EOFC);
+ }
+le: if ( sign < 0 )
+ lval = -lval;
+ dval = lval;
+ goto fe;
+
+ /* Now we are accumulating a double in dval. */
+fd: while ( is_digit(d, c) )
+ { dval = dval * 10 + d;
+ exp10--;
+ ngetc(c, sp, c = EOFC);
+ }
+fs: if ( sign < 0 )
+ dval = -dval;
+fe: /* Now dval contains the value, negated if necessary. */
+ switch ( c )
+ {
+ case 'e': case 'E':
+ { /* Check for a following exponent. */
+ int esign = 0;
+ int iexp;
+
+ ngetc(c, sp, return_error(e_syntaxerror));
+ switch ( c )
+ {
+ case '-':
+ esign = 1;
+ case '+':
+ ngetc(c, sp, return_error(e_syntaxerror));
+ }
+ /* Scan the exponent. We limit it arbitrarily to 999. */
+ if ( !is_digit(d, c) )
+ return_error(e_syntaxerror);
+ iexp = d;
+ for ( ; ; iexp = iexp * 10 + d )
+ { ngetc(c, sp, break);
+ if ( !is_digit(d, c) )
+ { *psp = sp;
+ code = 1;
+ break;
+ }
+ if ( iexp > 99 )
+ return_error(e_limitcheck);
+ }
+ if ( esign )
+ exp10 -= iexp;
+ else
+ exp10 += iexp;
+ break;
+ }
+ default:
+ *psp = sp;
+ code = 1;
+ case EOFC:
+ ;
+ }
+ /* Compute dval * 10^exp10. */
+ if ( exp10 > 0 )
+ { while ( exp10 > num_powers_10 )
+ dval *= powers_10[num_powers_10],
+ exp10 -= num_powers_10;
+ if ( exp10 > 0 )
+ dval *= powers_10[exp10];
+ }
+ else if ( exp10 < 0 )
+ { while ( exp10 < -num_powers_10 )
+ dval /= powers_10[num_powers_10],
+ exp10 += num_powers_10;
+ if ( exp10 < 0 )
+ dval /= powers_10[-exp10];
+ }
+ /*
+ * Check for an out-of-range result. Currently we don't check for
+ * absurdly large numbers of digits in the accumulation loops,
+ * but we should.
+ */
+ if ( dval >= 0 )
+ { if ( dval > MAX_FLOAT )
+ return_error(e_limitcheck);
+ }
+ else
+ { if ( dval < -MAX_FLOAT )
+ return_error(e_limitcheck);
+ }
+rret: make_real_new(pref, dval);
+ return code;
+}
diff --git a/gs/src/iscannum.h b/gs/src/iscannum.h
new file mode 100644
index 000000000..0850e3510
--- /dev/null
+++ b/gs/src/iscannum.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iscannum.h */
+/* Interface to Ghostscript number scanner */
+
+/* Scan a number. If the number consumes the entire string, return 0; */
+/* if not, set *psp to the first character beyond the number and return 1. */
+int scan_number(P5(const byte *sp, const byte *end, int sign, ref *pref,
+ const byte **psp));
diff --git a/gs/src/isstate.h b/gs/src/isstate.h
new file mode 100644
index 000000000..092d8f3bf
--- /dev/null
+++ b/gs/src/isstate.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* isstate.h */
+/* State structure for Ghostscript save/restore machinery */
+/* Requires isave.h */
+
+/* Saved state of allocator and other things as needed. */
+/*typedef struct alloc_save_s alloc_save_t;*/ /* in isave.h */
+struct alloc_save_s {
+ gs_ref_memory_t state; /* must be first for subclassing */
+ gs_dual_memory_t *dmem;
+ bool restore_names;
+ bool is_current;
+ ulong id;
+ void *client_data;
+};
+#define private_st_alloc_save() /* in isave.c */\
+ gs_private_st_suffix_add1(st_alloc_save, alloc_save_t, "alloc_save",\
+ save_enum_ptrs, save_reloc_ptrs, st_ref_memory, client_data)
diff --git a/gs/src/istack.c b/gs/src/istack.c
new file mode 100644
index 000000000..6ba4c7d03
--- /dev/null
+++ b/gs/src/istack.c
@@ -0,0 +1,500 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* istack.c */
+/* Ghostscript expandable stack manager */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "istack.h"
+#include "istruct.h" /* for gs_reloc_refs */
+#include "iutil.h"
+#include "ivmspace.h" /* for local/global test */
+#include "store.h"
+
+/* Forward references */
+private void init_block(P3(ref_stack *, ref *, uint));
+int ref_stack_push_block(P3(ref_stack *, uint, uint));
+
+/* GC procedures */
+#define sptr ((ref_stack *)vptr)
+private CLEAR_MARKS_PROC(ref_stack_clear_marks) {
+ r_clear_attrs(&sptr->current, l_mark);
+}
+private ENUM_PTRS_BEGIN(ref_stack_enum_ptrs) return 0;
+ case 0:
+ *pep = &sptr->current;
+ return ptr_ref_type;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(ref_stack_reloc_ptrs) {
+#if stacks_are_segmented
+ /* In a segmented environment, the top block can't move, */
+ /* so we don't need to relocate pointers to it. */
+#else
+ /* Note that the relocation must be a multiple of sizeof(ref_packed) */
+ /* * align_packed_per_ref, but it need not be a multiple of */
+ /* sizeof(ref). Therefore, we must do the adjustments using */
+ /* ref_packed pointers rather than ref pointers. */
+ ref_packed *bot = (ref_packed *)sptr->current.value.refs;
+ long reloc;
+ gs_reloc_refs((ref_packed *)&sptr->current,
+ (ref_packed *)(&sptr->current + 1),
+ gcst);
+ r_clear_attrs(&sptr->current, l_mark);
+ reloc = bot - (ref_packed *)sptr->current.value.refs;
+#define reloc_p(p)\
+ sptr->p = (ref *)((ref_packed *)sptr->p - reloc);
+ reloc_p(p);
+ reloc_p(bot);
+ reloc_p(top);
+#undef reloc_p
+#endif
+} RELOC_PTRS_END
+/* Structure type for a ref_stack. */
+public_st_ref_stack();
+
+/* Initialize a stack. */
+void
+ref_stack_init(register ref_stack *pstack, ref *psb,
+ uint bot_guard, uint top_guard, ref *pguard, gs_ref_memory_t *mem)
+{ uint size = r_size(psb);
+ uint avail = size - (stack_block_refs + bot_guard + top_guard);
+ ref_stack_block *pblock = (ref_stack_block *)psb->value.refs;
+ s_ptr body = (s_ptr)(pblock + 1);
+ pstack->bot = body + bot_guard;
+ pstack->p = pstack->bot - 1;
+ pstack->top = pstack->p + avail;
+ pstack->current = *psb;
+ pstack->extension_size = 0;
+ pstack->extension_used = 0;
+
+ make_int(&pstack->max_stack, avail);
+ pstack->requested = 0;
+
+ pstack->bot_guard = bot_guard;
+ pstack->top_guard = top_guard;
+ pstack->block_size = size - segmented_guard(bot_guard + top_guard);
+ pstack->body_size = avail;
+ if ( pguard != 0 )
+ pstack->guard_value = *pguard;
+ else
+ make_tav(&pstack->guard_value, t__invalid, 0, intval, 0);
+ pstack->underflow_error = -1; /* bogus, caller must set */
+ pstack->overflow_error = -1; /* bogus, caller must set */
+ pstack->allow_expansion = true; /* default, caller may reset */
+ pstack->memory = mem;
+ init_block(pstack, psb, 0);
+ refset_null(pstack->bot, avail);
+ make_empty_array(&pblock->next, 0);
+}
+
+/* Set the maximum number of elements allowed on a stack. */
+int
+ref_stack_set_max_count(ref_stack *pstack, long nmax)
+{ uint nmin = pstack->extension_size + (pstack->top - pstack->bot + 1);
+ if ( nmax < nmin )
+ nmax = nmin;
+ if ( nmax > max_uint / sizeof(ref) )
+ nmax = max_uint / sizeof(ref);
+ if ( !pstack->allow_expansion )
+ { uint ncur = pstack->body_size;
+ if ( nmax > ncur )
+ nmax = ncur;
+ }
+ pstack->max_stack.value.intval = nmax;
+ return 0;
+}
+
+/* Return the number of elements on a stack. */
+uint
+ref_stack_count(const ref_stack *pstack)
+{ return pstack->extension_used + (pstack->p - pstack->bot + 1);
+}
+
+/* Retrieve a given element from the stack, counting from */
+/* 0 as the top element. */
+ref *
+ref_stack_index(const ref_stack *pstack, long idx)
+{ ref_stack_block *pblock;
+ uint used = pstack->p + 1 - pstack->bot;
+ if ( idx < 0 )
+ return NULL;
+ if ( idx < used ) /* common case */
+ return pstack->p - (uint)idx;
+ pblock = (ref_stack_block *)pstack->current.value.refs;
+ do
+ { pblock = (ref_stack_block *)pblock->next.value.refs;
+ if ( pblock == 0 )
+ return NULL;
+ idx -= used;
+ used = r_size(&pblock->used);
+ }
+ while ( idx >= used );
+ return pblock->used.value.refs + (used - 1 - (uint)idx);
+}
+
+/* Count the number of elements down to and including the first mark. */
+/* If no mark is found, return 0. */
+uint
+ref_stack_counttomark(const ref_stack *pstack)
+{ uint scanned = 0;
+ STACK_LOOP_BEGIN(pstack, p, used)
+ { uint count = used;
+ p += used - 1;
+ for ( ; count; count--, p-- )
+ if ( r_has_type(p, t_mark) )
+ return scanned + (used - count + 1);
+ scanned += used;
+ }
+ STACK_LOOP_END(p, used)
+ return 0;
+}
+
+/* Do the store check for storing elements of a stack into an array. */
+/* May return e_invalidaccess. */
+int
+ref_stack_store_check(const ref_stack *pstack, ref *parray, uint count,
+ uint skip)
+{ uint space = r_space(parray);
+
+ if ( space != avm_local )
+ { uint left = count, pass = skip;
+
+ STACK_LOOP_BEGIN(pstack, ptr, size)
+ if ( size <= pass )
+ pass -= size;
+ else
+ { int code;
+ if ( pass != 0 )
+ size -= pass, pass = 0;
+ ptr += size;
+ if ( size > left )
+ size = left;
+ left -= size;
+ code = refs_check_space(ptr - size, size, space);
+ if ( code < 0 )
+ return code;
+ if ( left == 0 )
+ break;
+ }
+ STACK_LOOP_END(ptr, size)
+ }
+ return 0;
+}
+
+/* Store the top elements of a stack into an array, */
+/* with or without store/undo checking. */
+/* May return e_rangecheck or e_invalidaccess. */
+int
+ref_stack_store(const ref_stack *pstack, ref *parray, uint count, uint skip,
+ int age, bool check, client_name_t cname)
+{ uint left, pass;
+ ref *to;
+
+ if ( count > ref_stack_count(pstack) || count > r_size(parray) )
+ return_error(e_rangecheck);
+ if ( check )
+ { int code = ref_stack_store_check(pstack, parray, count, skip);
+ if ( code < 0 )
+ return code;
+ }
+ to = parray->value.refs + count;
+ left = count, pass = skip;
+ STACK_LOOP_BEGIN(pstack, from, size)
+ if ( size <= pass )
+ pass -= size;
+ else
+ { if ( pass != 0 )
+ size -= pass, pass = 0;
+ from += size;
+ if ( size > left )
+ size = left;
+ left -= size;
+ switch ( age )
+ {
+ case -1: /* not an array */
+ while ( size-- )
+ { from--, to--;
+ ref_assign(to, from);
+ }
+ break;
+ case 0: /* old array */
+ while ( size-- )
+ { from--, to--;
+ ref_assign_old(parray, to, from, cname);
+ }
+ break;
+ case 1: /* new array */
+ while ( size-- )
+ { from--, to--;
+ ref_assign_new(to, from);
+ }
+ break;
+ }
+ if ( left == 0 )
+ break;
+ }
+ STACK_LOOP_END(from, size)
+ r_set_size(parray, count);
+ return 0;
+}
+
+/* Pop a given number of elements off a stack. */
+/* The number must not exceed the number of elements in use. */
+void
+ref_stack_pop(register ref_stack *pstack, uint count)
+{ uint used;
+ while ( (used = pstack->p + 1 - pstack->bot) < count )
+ { count -= used;
+ pstack->p = pstack->bot - 1;
+ ref_stack_pop_block(pstack);
+ }
+ pstack->p -= count;
+}
+
+/* Pop the top block off a stack. */
+int
+ref_stack_pop_block(register ref_stack *pstack)
+{ s_ptr bot = pstack->bot;
+ uint count = pstack->p + 1 - bot;
+ ref_stack_block *pcur =
+ (ref_stack_block *)pstack->current.value.refs;
+ register ref_stack_block *pnext =
+ (ref_stack_block *)pcur->next.value.refs;
+ uint used;
+ ref *body;
+ ref next;
+ if ( pnext == 0 )
+ return_error(pstack->underflow_error);
+ used = r_size(&pnext->used);
+ body = (ref *)(pnext + 1) + flat_guard(pstack->bot_guard);
+ next = pcur->next;
+ /*
+ * If we're on a segmented system, the top block does not move,
+ * so we move up the used part of the top block, copy the contents
+ * of the next block under it, and free the next block.
+ * We also do this on non-segmented systems if the contents of the
+ * two blocks won't fit in a single block; in this case we copy up
+ * as much as will fit. On non-segmented systems where the contents
+ * of both blocks fit in a single block, we copy the used part
+ * of the top block to the top of the next block, and free
+ * the top block.
+ */
+ if ( used + count > pstack->body_size )
+ { /* Move as much into the top block as will fit. */
+ uint moved = pstack->body_size - count;
+ uint left;
+ if ( moved == 0 )
+ return_error(e_Fatal);
+ memmove(bot + moved, bot, count * sizeof(ref));
+ left = used - moved;
+ memcpy(bot, body + left, moved * sizeof(ref));
+ refset_null(body + left, moved);
+ r_dec_size(&pnext->used, moved);
+ pstack->p = pstack->top;
+ pstack->extension_used -= moved;
+ }
+ else
+ {
+#if stacks_are_segmented
+ /* We know there are no guard elements in the next block. */
+ memmove(bot + used, bot, count * sizeof(ref));
+ memcpy(bot, body, used * sizeof(ref));
+ pcur->next = pnext->next;
+ gs_free_ref_array(pstack->memory, &next, "ref_stack_pop_block");
+#else
+ memcpy(body + used, bot, count * sizeof(ref));
+ pstack->bot = bot = body;
+ pstack->top = bot + pstack->body_size - 1;
+ gs_free_ref_array(pstack->memory, &pstack->current,
+ "ref_stack_pop_block");
+ pstack->current = next;
+#endif
+ pstack->p = bot + (used + count - 1);
+ pstack->extension_size -= pstack->body_size;
+ pstack->extension_used -= used;
+ }
+ return 0;
+}
+
+/* Extend a stack to recover from an overflow condition. */
+/* May return overflow_error or e_VMerror. */
+int
+ref_stack_extend(ref_stack *pstack, uint request)
+{ uint keep = (pstack->top - pstack->bot + 1) / 3;
+ uint count = pstack->p - pstack->bot + 1;
+
+ if ( pstack->p < pstack->bot )
+ { /* Adding another block can't help things. */
+ return_error(pstack->overflow_error);
+ }
+ if ( keep + request > pstack->body_size )
+ keep = pstack->body_size - request;
+ if ( keep > count )
+ keep = count; /* required by ref_stack_push_block */
+ return ref_stack_push_block(pstack, keep, request);
+}
+
+/* Push N empty slots onto a stack. These slots are not initialized; */
+/* the caller must fill them immediately. May return overflow_error */
+/* (if max_stack would be exceeded, or the stack has no allocator) */
+/* or e_VMerror. */
+int
+ref_stack_push(register ref_stack *pstack, uint count)
+{ /* Don't bother to pre-check for overflow: we must be able to */
+ /* back out in the case of a VMerror anyway, and */
+ /* ref_stack_push_block will make the check itself. */
+ uint needed = count;
+ uint added;
+ for ( ; (added = pstack->top - pstack->p) < needed; needed -= added )
+ { int code;
+ pstack->p = pstack->top;
+ code =
+ ref_stack_push_block(pstack,
+ (pstack->top - pstack->bot + 1) / 3,
+ count);
+ if ( code < 0 )
+ { /* Back out. */
+ ref_stack_pop(pstack, count - needed);
+ pstack->requested = count;
+ return code;
+ }
+ }
+ pstack->p += needed;
+ return 0;
+}
+
+/* Push a block onto the stack, specifying how many elements of */
+/* the current top block should remain in the top block and also */
+/* how many elements we are trying to add. */
+/* May return overflow_error or e_VMerror. */
+/* Must have keep <= count. */
+int
+ref_stack_push_block(register ref_stack *pstack, uint keep, uint add)
+{ uint count = pstack->p - pstack->bot + 1;
+ uint move = count - keep;
+ ref_stack_block *pcur = (ref_stack_block *)pstack->current.value.refs;
+ ref next;
+ ref_stack_block *pnext;
+ ref *body;
+ int code;
+ if ( keep > count )
+ return_error(e_Fatal);
+ /* Check for overflowing the maximum size, */
+ /* or expansion not allowed. */
+ if ( pstack->memory == 0 ||
+ pstack->extension_used + (pstack->top - pstack->bot) + add >=
+ pstack->max_stack.value.intval ||
+ !pstack->allow_expansion
+ )
+ return_error(pstack->overflow_error);
+ code = gs_alloc_ref_array(pstack->memory, &next, 0,
+ pstack->block_size, "ref_stack_push_block");
+ if ( code < 0 )
+ return code;
+ pnext = (ref_stack_block *)next.value.refs;
+ body = (ref *)(pnext + 1);
+#if stacks_are_segmented
+ /* Copy all but the top keep elements into the new block, */
+ /* and move the top elements down. */
+ /* We know there are no guard elements in the new block. */
+ memcpy(body, pstack->bot, move * sizeof(ref));
+ /* Clear the elements above the top of the new block. */
+ refset_null(body + move, pstack->body_size - move);
+ if ( keep <= move )
+ { /* No overlap, memcpy is safe. */
+ memcpy(pstack->bot, pstack->bot + move, keep * sizeof(ref));
+ }
+ else
+ { uint i;
+ s_ptr bot = pstack->bot;
+ s_ptr up = bot + move;
+ for ( i = 0; i < keep; i++ )
+ bot[i] = up[i];
+ }
+ pnext->next = pcur->next;
+ pnext->used = next;
+ pcur->next = next;
+ pnext->used.value.refs = body;
+ r_set_size(&pnext->used, move);
+#else
+ /* Copy the top keep elements into the new block, */
+ /* and make the new block the top block. */
+ init_block(pstack, &next, keep);
+ body += pstack->bot_guard;
+ memcpy(body, pstack->bot + move, keep * sizeof(ref));
+ /* Clear the elements above the top of the new block. */
+ refset_null(body + keep, pstack->body_size - keep);
+ /* Clear the elements above the top of the old block. */
+ refset_null(pstack->bot + move, keep);
+ pnext->next = pstack->current;
+ pcur->used.value.refs = pstack->bot;
+ r_set_size(&pcur->used, move);
+ pstack->current = next;
+ pstack->bot = body;
+ pstack->top = pstack->bot + pstack->body_size - 1;
+#endif
+ pstack->p = pstack->bot + keep - 1;
+ pstack->extension_size += pstack->body_size;
+ pstack->extension_used += move;
+ return 0;
+}
+
+/* Clean up a stack for garbage collection. */
+void
+ref_stack_cleanup(ref_stack *pstack)
+{ ref_stack_block *pblock =
+ (ref_stack_block *)pstack->current.value.refs;
+ refset_null(pstack->p + 1, pstack->top - pstack->p);
+ pblock->used = pstack->current; /* set attrs */
+ pblock->used.value.refs = pstack->bot;
+ r_set_size(&pblock->used, pstack->p + 1 - pstack->bot);
+}
+
+/* ------ Internal routines ------ */
+
+/* Initialize the guards and body of a stack block. */
+/* Note that this always initializes the guards, so it should not be used */
+/* for extension blocks in a segmented environments. */
+private void
+init_block(ref_stack *pstack, ref *psb, uint used)
+{ ref *brefs = psb->value.refs;
+#define pblock ((ref_stack_block *)brefs)
+ register uint i;
+ register ref *p;
+ for ( i = pstack->bot_guard, p = brefs + stack_block_refs;
+ i != 0; i--, p++
+ )
+ ref_assign(p, &pstack->guard_value);
+ /* The top guard elements will never be read, */
+ /* but we need to initialize them for the sake of the GC. */
+ /* We can use refset_null for this, because even though it uses */
+ /* make_null_new and stack elements must not be marked new, */
+ /* these slots will never actually be read or written. */
+ if ( pstack->top_guard )
+ { ref *top = brefs + r_size(psb);
+ int top_guard = pstack->top_guard;
+ refset_null(top - top_guard, top_guard);
+ }
+ pblock->used = *psb;
+ pblock->used.value.refs = brefs + stack_block_refs + pstack->bot_guard;
+ r_set_size(&pblock->used, 0);
+}
diff --git a/gs/src/istack.h b/gs/src/istack.h
new file mode 100644
index 000000000..1de13147b
--- /dev/null
+++ b/gs/src/istack.h
@@ -0,0 +1,248 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* istack.h */
+/* Definitions for expandable Ghostscript stacks */
+/* Requires iref.h */
+
+#ifndef istack_INCLUDED
+# define istack_INCLUDED
+
+/* Define an opaque allocator type. */
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+/*
+ * The 3 principal Ghostscript stacks (operand, execution, and dictionary)
+ * are implemented as a linked list of blocks. On segmented MS-DOS and
+ * MS Windows systems, where there is a substantial performance advantage
+ * to keeping the top of the stack in the primary data segment, the top
+ * block is stored there, and copied to and from blocks in the heap;
+ * on systems with flat address spaces, the top block is stored in the heap
+ * like other blocks. Note that in environments with multiple PostScript
+ * contexts, the MS-DOS approach requires some combination of keeping
+ * multiple top blocks in the primary data segment, and copying top blocks
+ * to and from the heap when switching contexts.
+ *
+ * Since all operators exit cleanly in case of stack under- or overflow,
+ * we handle all issues related to stack blocks in the top-level error
+ * recovery code in interp.c. A few situations require special treatment:
+ * see ostack.h, estack.h, and dstack.h for details.
+ */
+
+#ifdef DPNEXT
+/*
+ * Eventually we will remove all support for segmented systems.
+ * For the moment, only remove it if we have to support multiple contexts.
+ */
+# define stacks_are_segmented 0
+#else
+# define stacks_are_segmented arch_ptrs_are_segmented
+#endif
+#if stacks_are_segmented
+# define flat_guard(n) 0
+# define segmented_guard(n) (n)
+#else
+# define flat_guard(n) (n)
+# define segmented_guard(n) 0
+#endif
+
+typedef ref _ds *s_ptr;
+typedef const ref _ds *const_s_ptr;
+
+/*
+ * Define the structure for a stack block.
+ * In order to simplify allocation, stack blocks are implemented as
+ * t_array objects, with the first few elements used for special purposes.
+ * The actual layout is as follows:
+ * ref_stack_block structure
+ * bottom guard if any (see below)
+ * used elements of block
+ * unused elements of block
+ * top guard if any (see below)
+ * The `next' member of the next higher stack block includes all of this.
+ * The `used' member only includes the used elements of this block.
+ * Notes:
+ * - In the top block, the size of the `used' member may not be correct.
+ * - In all blocks but the top, we fill the unused elements with nulls.
+ */
+typedef struct ref_stack_block_s {
+ ref next; /* t_array, next lower block on stack */
+ ref used; /* t_array, subinterval of this block */
+ /* Actual stack starts here */
+} ref_stack_block;
+#define stack_block_refs (sizeof(ref_stack_block) / sizeof(ref))
+
+/*
+ * In order to detect under- and overflow with minimum overhead, we may put
+ * guard elements at the top and bottom of the stacks (see dstack.h,
+ * estack.h, and ostack.h for details of the individual stacks).
+ * On segmented systems, we only put guard elements around the top block;
+ * on other systems, we put guard elements around every block. Note that
+ * in the latter case, the 'current' and 'next' arrays include the
+ * guard elements.
+ */
+
+/*
+ * The garbage collector requires that the entire contents of every block
+ * be 'clean', i.e., contain legitimate refs; we also need to ensure that
+ * at GC time, pointers in unused areas of a block will not be followed
+ * (since they may be dangling). We ensure this as follows:
+ * - When allocating a new block, we set the entire body to nulls.
+ * This is necessary because the block may be freed before the next GC,
+ * and the GC must be able to scan (parse) refs even if they are free.
+ * - When adding a new block to the top of the stack, we set to nulls
+ * the unused area of the new next-to-top blocks.
+ * - At the beginning of garbage collection, we set to nulls the unused
+ * elements of the top block.
+ */
+
+/*
+ * Define the (statically allocated) state of a stack.
+ * Note that the total size of a stack cannot exceed max_uint,
+ * because it has to be possible to copy a stack to a PostScript array.
+ */
+#ifndef ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack; /* also defined in idebug.h */
+# define ref_stack_DEFINED
+#endif
+struct ref_stack_s {
+ /* Following are updated dynamically. */
+ s_ptr p; /* current top element */
+ /* Following are updated when adding or deleting blocks. */
+ s_ptr bot; /* bottommost valid element */
+ s_ptr top; /* topmost valid element */
+ ref current; /* t_array for current top block */
+ uint extension_size; /* total sizes of extn. blocks */
+ uint extension_used; /* total used sizes of extn. blocks */
+ /* Following are updated rarely. */
+ ref max_stack; /* t_integer, Max...Stack user param */
+ uint requested; /* amount of last failing */
+ /* push or pop request */
+ /* Following are set at initialization. */
+ uint bot_guard; /* # of guard elements below bot */
+ uint top_guard; /* # of guard elements above top */
+ uint block_size; /* size of each block */
+ uint body_size; /* # of data slots in each block */
+ ref guard_value; /* t__invalid or t_operator, */
+ /* bottom guard value */
+ int underflow_error; /* error code for underflow */
+ int overflow_error; /* error code for overflow */
+ bool allow_expansion; /* if false, don't expand */
+ gs_ref_memory_t *memory; /* allocator for blocks */
+};
+#define public_st_ref_stack() /* in istack.c */\
+ gs_public_st_complex_only(st_ref_stack, ref_stack, "ref_stack",\
+ ref_stack_clear_marks, ref_stack_enum_ptrs, ref_stack_reloc_ptrs, 0)
+#define st_ref_stack_num_ptrs 1 /* current */
+
+/*
+ * Define the loop control for enumerating the elements of a stack,
+ * as follows:
+
+ STACK_LOOP_BEGIN(pstack, ptr, size)
+ ...
+ STACK_LOOP_END(ptr, size)
+
+ * Each time through the loop, we set ptr to the bottom of a block
+ * and size to the size of the block.
+ */
+#define STACK_LOOP_BEGIN(pstack, ptr, size)\
+{ ref_stack_block *pblock_ = (ref_stack_block *)(pstack)->current.value.refs;\
+ ref *ptr = (pstack)->bot; uint size = (pstack)->p + 1 - (pstack)->bot;\
+ for ( ; ; ) {
+#define STACK_LOOP_END(ptr, size)\
+ pblock_ = (ref_stack_block *)pblock_->next.value.refs;\
+ if ( pblock_ == 0 ) break;\
+ ptr = pblock_->used.value.refs; size = r_size(&pblock_->used);\
+ }\
+}
+
+/* ------ Procedural interface ------ */
+
+/* Initialize a stack. Note that on segmented systems, */
+/* the body of the stack (the elements of the array given by the first ref) */
+/* must be in the _ds segment. */
+void ref_stack_init(P6(ref_stack *, ref *, uint, uint, ref *,
+ gs_ref_memory_t *));
+
+/* Set the maximum number of elements allowed on a stack. */
+/* Note that the value is a long, not a uint or a ulong. */
+int ref_stack_set_max_count(P2(ref_stack *, long));
+
+/* Return the number of elements on a stack. */
+uint ref_stack_count(P1(const ref_stack *));
+#define ref_stack_count_inline(pstk)\
+ ((pstk)->p + 1 - (pstk)->bot + (pstk)->extension_used)
+
+/* Return the maximum number of elements allowed on a stack. */
+#define ref_stack_max_count(pstk) (uint)((pstk)->max_stack.value.intval)
+
+/* Return a pointer to a given element from the stack, counting from */
+/* 0 as the top element. If the index is out of range, return 0. */
+/* Note that the index is a long, not a uint or a ulong. */
+ref *ref_stack_index(P2(const ref_stack *, long));
+
+/* Count the number of elements down to and including the first mark. */
+/* If no mark is found, return 0. */
+uint ref_stack_counttomark(P1(const ref_stack *));
+
+/*
+ * Do the store check for storing 'count' elements of a stack, starting
+ * 'skip' elements below the top, into an array. Return 0 or e_invalidaccess.
+ */
+int ref_stack_store_check(P4(const ref_stack *pstack, ref *parray,
+ uint count, uint skip));
+
+/*
+ * Store 'count elements of a stack, starting 'skip' elements below the top,
+ * into an array, with or without store/undo checking.
+ * age=-1 for no check, 0 for old, 1 for new.
+ * May return e_rangecheck or e_invalidaccess.
+ */
+int ref_stack_store(P7(const ref_stack *pstack, ref *parray, uint count,
+ uint skip, int age, bool check, client_name_t cname));
+
+/* Pop the top N elements off a stack. */
+/* The number must not exceed the number of elements in use. */
+void ref_stack_pop(P2(ref_stack *, uint));
+#define ref_stack_clear(pstk) ref_stack_pop(pstk, ref_stack_count(pstk))
+#define ref_stack_pop_to(pstk, depth)\
+ ref_stack_pop(pstk, ref_stack_count(pstk) - (depth))
+
+/* Pop the top block off a stack. */
+/* May return underflow_error. */
+int ref_stack_pop_block(P1(ref_stack *));
+
+/* Extend a stack to recover from an overflow condition. */
+/* Uses the requested value to decide what to do. */
+/* May return overflow_error or e_VMerror. */
+int ref_stack_extend(P2(ref_stack *, uint));
+
+/* Push N empty slots onto a stack. These slots are not initialized; */
+/* the caller must immediately fill them. May return overflow_error */
+/* (if max_stack would be exceeded, or the stack has no allocator) */
+/* or e_VMerror. */
+int ref_stack_push(P2(ref_stack *, uint));
+
+/* Clean up a stack for garbage collection. */
+void ref_stack_cleanup(P1(ref_stack *));
+
+#endif /* istack_INCLUDED */
diff --git a/gs/src/istream.h b/gs/src/istream.h
new file mode 100644
index 000000000..0417da8a7
--- /dev/null
+++ b/gs/src/istream.h
@@ -0,0 +1,32 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* istream.h */
+/* Interpreter-level stream procedures */
+/* Requires scommon.h, ostack.h */
+
+/* Procedures exported by zfproc.c */
+ /* for zfilter.c - procedure stream initialization */
+int sread_proc(P2(ref *, stream **));
+int swrite_proc(P2(ref *, stream **));
+ /* for interp.c, zfileio.c, zpaint.c - handle a procedure */
+ /* callback or an interrupt */
+int s_handle_read_exception(P5(int, const ref *, const ref *, int,
+ int (*)(P1(os_ptr))));
+int s_handle_write_exception(P5(int, const ref *, const ref *, int,
+ int (*)(P1(os_ptr))));
diff --git a/gs/src/istruct.h b/gs/src/istruct.h
new file mode 100644
index 000000000..1f13a12a0
--- /dev/null
+++ b/gs/src/istruct.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* istruct.h */
+/* Interpreter-level extension of gsstruct.h */
+
+#ifndef istruct_INCLUDED
+# define istruct_INCLUDED
+
+#include "gsstruct.h"
+
+/* ================ Refs ================ */
+
+/* The structure type descriptor for (blocks of) refs. */
+/* This is defined in igc.c and exported for isave.c. */
+extern_st(st_refs);
+
+/* Relocate a pointer to a ref[_packed]. */
+ptr_proc_reloc(gs_reloc_ref_ptr, ref_packed);
+
+/* Relocate a block of ref[_packed]s. */
+void gs_reloc_refs(P3(ref_packed *from, ref_packed *to, gc_state_t *gcst));
+
+#ifdef DPNEXT
+#define ENUM_RETURN_REF(typ, elt)\
+ do { *pep = (const void *)&((typ *)vptr)->elt; return ptr_ref_type; } while (0)
+#define ENUM_REF(i, typ, elt)\
+ case i: ENUM_RETURN_REF(typ, elt)
+#define RELOC_REF(typ, elt)\
+ gs_reloc_refs( (ref_packed *)&((typ *)vptr)->elt,\
+ (ref_packed *)(&((typ *)vptr)->elt + 1), gcst)
+#endif
+
+/*
+ * Define an object allocated as a struct, but actually containing refs.
+ * Such objects are useful as the client_data of library structures
+ * (currently only gstates and fonts).
+ */
+struct_proc_clear_marks(ref_struct_clear_marks);
+struct_proc_enum_ptrs(ref_struct_enum_ptrs);
+struct_proc_reloc_ptrs(ref_struct_reloc_ptrs);
+#define gs__st_ref_struct(scope_st, stname, stype, sname)\
+ gs__st_complex_only(scope_st, stname, stype, sname, ref_struct_clear_marks,\
+ ref_struct_enum_ptrs, ref_struct_reloc_ptrs, 0)
+#define gs_public_st_ref_struct(stname, stype, sname)\
+ gs__st_ref_struct(public_st, stname, stype, sname)
+#define gs_private_st_ref_struct(stname, stype, sname)\
+ gs__st_ref_struct(private_st, stname, stype, sname)
+
+#endif /* istruct_INCLUDED */
diff --git a/gs/src/iutil.c b/gs/src/iutil.c
new file mode 100644
index 000000000..130a1af42
--- /dev/null
+++ b/gs/src/iutil.c
@@ -0,0 +1,599 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iutil.c */
+/* Utilities for Ghostscript interpreter */
+#include "math_.h" /* for fabs */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "idict.h"
+#include "imemory.h"
+#include "iname.h"
+#include "ipacked.h" /* for array_get */
+#include "iutil.h" /* for checking prototypes */
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfont.h"
+
+/* ------ Object utilities ------ */
+
+/* Copy refs from one place to another. */
+int
+refcpy_to_old(ref *aref, uint index, register const ref *from,
+ register uint size, client_name_t cname)
+{ register ref *to = aref->value.refs + index;
+ int code = refs_check_space(from, size, r_space(aref));
+ if ( code < 0 )
+ return code;
+ /* We have to worry about aliasing.... */
+ if ( to <= from || from + size <= to )
+ while ( size-- )
+ ref_assign_old(aref, to, from, cname), to++, from++;
+ else
+ for ( from += size, to += size; size--; )
+ from--, to--, ref_assign_old(aref, to, from, cname);
+ return 0;
+}
+void
+refcpy_to_new(register ref *to, register const ref *from, register uint size)
+{ while ( size-- )
+ ref_assign_new(to, from), to++, from++;
+}
+
+/* Fill a new object with nulls. */
+void
+refset_null(register ref *to, register uint size)
+{ while ( size-- ) make_null_new(to), to++;
+}
+
+/* Compare two objects for equality. */
+bool
+obj_eq(register const ref *pref1, register const ref *pref2)
+{ ref nref;
+ if ( r_type(pref1) != r_type(pref2) )
+ { /* Only a few cases need be considered here: */
+ /* integer/real (and vice versa), name/string */
+ /* (and vice versa), and extended operators. */
+ switch ( r_type(pref1) )
+ {
+ case t_integer:
+ return (r_has_type(pref2, t_real) &&
+ pref2->value.realval == pref1->value.intval);
+ case t_real:
+ return (r_has_type(pref2, t_integer) &&
+ pref2->value.intval == pref1->value.realval);
+ case t_name:
+ if ( !r_has_type(pref2, t_string) )
+ return false;
+ name_string_ref(pref1, &nref);
+ pref1 = &nref;
+ break;
+ case t_string:
+ if ( !r_has_type(pref2, t_name) )
+ return false;
+ name_string_ref(pref2, &nref);
+ pref2 = &nref;
+ break;
+ default:
+ if ( r_btype(pref1) != r_btype(pref2) )
+ return false;
+ }
+ }
+ /* Now do a type-dependent comparison. */
+ /* This would be very simple if we always filled in */
+ /* all 8 bytes of a ref, but we currently don't. */
+ switch ( r_btype(pref1) )
+ {
+ case t_array:
+ return (pref1->value.refs == pref2->value.refs &&
+ r_size(pref1) == r_size(pref2));
+ case t_mixedarray:
+ case t_shortarray:
+ return (pref1->value.packed == pref2->value.packed &&
+ r_size(pref1) == r_size(pref2));
+ case t_boolean:
+ return (pref1->value.boolval == pref2->value.boolval);
+ case t_dictionary:
+ return (pref1->value.pdict == pref2->value.pdict);
+ case t_file:
+ return (pref1->value.pfile == pref2->value.pfile &&
+ r_size(pref1) == r_size(pref2));
+ case t_integer:
+ return (pref1->value.intval == pref2->value.intval);
+ case t_mark:
+ case t_null:
+ return true;
+ case t_name:
+ return (pref1->value.pname == pref2->value.pname);
+ case t_oparray:
+ case t_operator:
+ return (op_index(pref1) == op_index(pref2));
+ case t_real:
+ return (pref1->value.realval == pref2->value.realval);
+ case t_save:
+ return (pref2->value.saveid == pref1->value.saveid);
+ case t_string:
+ return (!bytes_compare(pref1->value.bytes, r_size(pref1),
+ pref2->value.bytes, r_size(pref2)));
+ case t_device:
+ return (pref1->value.pdevice == pref2->value.pdevice);
+ case t_struct:
+ case t_astruct:
+ return (pref1->value.pstruct == pref2->value.pstruct);
+ case t_fontID:
+ { /*
+ * In the Adobe implementations, different scalings of a
+ * font have "equal" FIDs, so we do the same.
+ */
+ const gs_font *pfont1 = r_ptr(pref1, gs_font);
+ const gs_font *pfont2 = r_ptr(pref2, gs_font);
+
+ while ( pfont1->base != pfont1 )
+ pfont1 = pfont1->base;
+ while ( pfont2->base != pfont2 )
+ pfont2 = pfont2->base;
+ return (pfont1 == pfont2);
+ }
+ }
+ return false; /* shouldn't happen! */
+}
+
+/* Compare two objects for identity. */
+bool
+obj_ident_eq(register const ref *pref1, register const ref *pref2)
+{ if ( r_type(pref1) != r_type(pref2) )
+ return false;
+ if ( r_has_type(pref1, t_string) )
+ return (pref1->value.bytes == pref2->value.bytes &&
+ r_size(pref1) == r_size(pref2));
+ return obj_eq(pref1, pref2);
+}
+
+/*
+ * Create a printable representation of an object, a la cvs (full_print =
+ * false) or == (full_print = true). Return 0 if OK, <0 if the destination
+ * wasn't large enough or the object's contents weren't readable.
+ * If the object was a string or name, store a pointer to its characters
+ * even if it was too large.
+ */
+int
+obj_cvp(const ref *op, byte *str, uint len, uint *prlen, const byte **pchars,
+ bool full_print)
+{ char buf[30]; /* big enough for any float */
+ const byte *pstr = (const byte *)buf;
+ uint plen;
+ ref nref;
+
+ if ( full_print )
+ switch ( r_btype(op))
+ {
+ case t_boolean:
+ case t_integer:
+ case t_real:
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ switch ( r_btype(op) )
+ {
+ case t_boolean:
+ pstr = (const byte *)(op->value.boolval ? "true" : "false");
+ break;
+ case t_integer:
+ sprintf(buf, "%ld", op->value.intval);
+ break;
+ case t_name:
+ name_string_ref(op, &nref); /* name string */
+cvname: pstr = nref.value.bytes;
+ plen = r_size(&nref);
+ if ( pchars != 0 )
+ *pchars = pstr;
+ goto nl;
+ case t_oparray:
+ { uint index = op_index(op);
+ const op_array_table *opt = op_index_op_array_table(index);
+ name_index_ref(opt->nx_table[index - opt->base_index], &nref);
+ }
+ name_string_ref(&nref, &nref);
+ goto cvname;
+ case t_operator:
+ { /* Recover the name from the initialization table. */
+ uint index = op_index(op);
+ /* Check the validity of the index. (An out-of-bounds */
+ /* index is only possible when examining an invalid */
+ /* object using the debugger.) */
+ if ( index > 0 && index < op_def_count )
+ { pstr = (const byte *)(op_def_table[index]->oname + 1);
+ break;
+ }
+ }
+ /* Internal operator, no name. */
+ sprintf(buf, "@0x%lx", (ulong)op->value.opproc);
+ break;
+ case t_real:
+ /*
+ * To get fully accurate output results for IEEE single-
+ * precision floats (24 bits of mantissa), the ANSI
+ * %g default of 6 digits is not enough; 9 are needed.
+ * Unfortunately, using %.9g for floats (as opposed to
+ * doubles) produces unfortunate artifacts such as 0.01 5 mul
+ * printing as 0.049999997. Therefore, we print using %g,
+ * and if the result isn't accurate enough, print again
+ * using %.9g. Unfortunately, a few PostScript programs
+ * 'know' that the printed representation of floats fits
+ * into 6 digits (e.g., with cvs). We resolve this by letting
+ * cvs, cvrs, and = do what the Adobe interpreters appear
+ * to do (use %g), and only produce accurate output for ==,
+ * for which there is no analogue of cvs. What a hack!
+ */
+ { float value = op->value.realval;
+ sprintf(buf, "%g", value);
+ if ( full_print )
+ { float scanned;
+ sscanf(buf, "%f", &scanned);
+ if ( scanned != value )
+ sprintf(buf, "%.9g", value);
+ }
+ }
+ /*
+ * Make sure the output has a decimal point.
+ * This is needed for compatibility with
+ * Adobe (and other) interpreters.
+ */
+ if ( strchr(buf, '.') != NULL ) break;
+ { char *ept = strchr(buf, 'e');
+ if ( ept == NULL )
+ strcat(buf, ".0");
+ else
+ { /* Insert the .0 before the exponent. */
+ /* What a nuisance! */
+ char buf1[30];
+ strcpy(buf1, ept);
+ strcpy(ept, ".0");
+ strcat(buf, buf1);
+ }
+ }
+ break;
+ case t_string:
+ check_read(*op);
+ pstr = op->value.bytes;
+ plen = r_size(op);
+ if ( pchars != 0 )
+ *pchars = pstr;
+ goto nl;
+ default:
+ pstr = (const byte *)"--nostringval--";
+ }
+ plen = strlen((const char *)pstr);
+nl: *prlen = plen;
+ if ( plen > len )
+ return_error(e_rangecheck);
+ memcpy(str, pstr, plen);
+ return 0;
+}
+
+/* Find the index of an operator that doesn't have one stored in it. */
+ushort
+op_find_index(const ref *pref /* t_operator */)
+{ op_proc_p proc = real_opproc(pref);
+ register const op_def_ptr *opp = op_def_table;
+ register const op_def_ptr *opend = opp + op_def_count;
+ for ( ; ++opp < opend; )
+ { if ( (*opp)->proc == proc )
+ return opp - op_def_table;
+ }
+ /* Lookup failed! This isn't possible.... */
+ return 0;
+}
+
+/*
+ * Convert an operator index to an operator or oparray ref.
+ * This is only used for debugging and for 'get' from packed arrays,
+ * so it doesn't have to be very fast.
+ */
+void
+op_index_ref(uint index, ref *pref)
+{ const op_array_table *opt;
+ if ( op_index_is_operator(index) )
+ { make_oper(pref, index, op_index_proc(index));
+ return;
+ }
+ opt = op_index_op_array_table(index);
+ make_tasv(pref, t_oparray, opt->attrs, index,
+ const_refs, (opt->table.value.const_refs
+ + index - opt->base_index));
+}
+
+/* Get an element from an array of some kind. */
+/* This is also used to index into Encoding vectors, */
+/* the error name vector, etc. */
+int
+array_get(const ref *aref, long index_long, ref *pref)
+{ if ( (ulong)index_long >= r_size(aref) )
+ return_error(e_rangecheck);
+ switch ( r_type(aref) )
+ {
+ case t_array:
+ { const ref *pvalue =
+ aref->value.refs + (uint)index_long;
+ ref_assign(pref, pvalue);
+ } return 0;
+ case t_mixedarray:
+ { const ref_packed *packed = aref->value.packed;
+ uint index = (uint)index_long;
+ for ( ; index--; ) packed = packed_next(packed);
+ packed_get(packed, pref);
+ } return 0;
+ case t_shortarray:
+ { const ref_packed *packed =
+ aref->value.packed + (uint)index_long;
+ packed_get(packed, pref);
+ } return 0;
+ default:
+ return_error(e_typecheck);
+ }
+}
+
+/* Get an element from a packed array. */
+/* (This works for ordinary arrays too.) */
+/* Source and destination are allowed to overlap if the source is packed, */
+/* or if they are identical. */
+void
+packed_get(const ref_packed *packed, ref *pref)
+{ const ref_packed elt = *packed;
+ uint value = elt & packed_value_mask;
+ switch ( elt >> r_packed_type_shift )
+ {
+ default: /* (shouldn't happen) */
+ make_null(pref);
+ break;
+ case pt_executable_operator:
+ op_index_ref(value, pref);
+ break;
+ case pt_integer:
+ make_int(pref, (int)value + packed_min_intval);
+ break;
+ case pt_literal_name:
+ name_index_ref(value, pref);
+ break;
+ case pt_executable_name:
+ name_index_ref(value, pref);
+ r_set_attrs(pref, a_executable);
+ break;
+ case pt_full_ref:
+ case pt_full_ref+1:
+ ref_assign(pref, (const ref *)packed);
+ }
+}
+
+/* Check to make sure an interval contains no object references */
+/* to a space younger than a given one. */
+/* Return 0 or e_invalidaccess. */
+int
+refs_check_space(register const ref *bot, register uint size, uint space)
+{ for ( ; size--; bot++ )
+ store_check_space(space, bot);
+ return 0;
+}
+
+/* ------ String utilities ------ */
+
+/* Convert a C string to a Ghostscript string */
+int
+string_to_ref(const char *cstr, ref *pref, gs_ref_memory_t *mem,
+ client_name_t cname)
+{ uint size = strlen(cstr);
+ int code = gs_alloc_string_ref(mem, pref, a_all, size, cname);
+ if ( code < 0 )
+ return code;
+ memcpy(pref->value.bytes, cstr, size);
+ return 0;
+}
+
+/* Convert a Ghostscript string to a C string. */
+/* Return 0 iff the buffer can't be allocated. */
+char *
+ref_to_string(const ref *pref, gs_memory_t *mem, client_name_t cname)
+{ uint size = r_size(pref);
+ char *str = (char *)gs_alloc_string(mem, size + 1, cname);
+ if ( str == 0 )
+ return 0;
+ memcpy(str, (const char *)pref->value.bytes, size);
+ str[size] = 0;
+ return str;
+}
+
+/* ------ Operand utilities ------ */
+
+/* Get N numeric operands from the stack or an array. */
+/* Return a bit-mask indicating which ones are integers, */
+/* or a (negative) error indication. */
+/* The 1-bit in the bit-mask refers to the first operand. */
+/* Store float versions of the operands at pval. */
+/* The stack underflow check (check for t__invalid) is harmless */
+/* if the operands come from somewhere other than the stack. */
+int
+num_params(const ref *op, int count, double *pval)
+{ int mask = 0;
+
+ pval += count;
+ while ( --count >= 0 )
+ { mask <<= 1;
+ switch ( r_type(op) )
+ {
+ case t_real:
+ *--pval = op->value.realval;
+ break;
+ case t_integer:
+ *--pval = op->value.intval;
+ mask++;
+ break;
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ return_error(e_typecheck);
+ }
+ op--;
+ }
+ /* If count is very large, mask might overflow. */
+ /* In this case we clearly don't care about the value of mask. */
+ return (mask < 0 ? 0 : mask);
+}
+/* float_params doesn't bother to keep track of the mask. */
+int
+float_params(const ref *op, int count, float *pval)
+{ for ( pval += count; --count >= 0; --op )
+ switch ( r_type(op) )
+ {
+ case t_real:
+ *--pval = op->value.realval;
+ break;
+ case t_integer:
+ *--pval = op->value.intval;
+ break;
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ return_error(e_typecheck);
+ }
+ return 0;
+}
+
+/* Get a single real parameter. */
+/* The only possible error is e_typecheck. */
+/* If an error is returned, the return value is not updated. */
+int
+real_param(const ref *op, double *pparam)
+{ switch ( r_type(op) )
+ {
+ case t_integer:
+ *pparam = op->value.intval;
+ break;
+ case t_real:
+ *pparam = op->value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ return 0;
+}
+int
+float_param(const ref *op, float *pparam)
+{ double dval;
+ int code = real_param(op, &dval);
+
+ if ( code >= 0 )
+ *pparam = (float)dval; /* can't overflow */
+ return code;
+}
+
+/* Get an integer parameter in a given range. */
+int
+int_param(const ref *op, int max_value, int *pparam)
+{ check_int_leu(*op, max_value);
+ *pparam = (int)op->value.intval;
+ return 0;
+}
+
+/* Make real values on the operand stack. */
+int
+make_reals(ref *op, const double *pval, int count)
+{ /* This should return e_limitcheck if any real is too large */
+ /* to fit into a float on the stack. */
+ for ( ; count--; op++, pval++ )
+ make_real(op, *pval);
+ return 0;
+}
+int
+make_floats(ref *op, const float *pval, int count)
+{ /* This should return e_limitcheck for infinities. */
+ for ( ; count--; op++, pval++ )
+ make_real(op, *pval);
+ return 0;
+}
+
+/* Compute the error code when check_proc fails. */
+/* Note that the client, not this procedure, uses return_error. */
+/* The stack underflow check is harmless in the off-stack case. */
+int
+check_proc_failed(const ref *pref)
+{ return (r_is_array(pref) ? e_invalidaccess :
+ r_has_type(pref, t__invalid) ? e_stackunderflow :
+ e_typecheck);
+}
+
+/* Compute the error code when a type check on the stack fails. */
+/* Note that the client, not this procedure, uses return_error. */
+int
+check_type_failed(const ref *op)
+{ return (r_has_type(op, t__invalid) ? e_stackunderflow : e_typecheck);
+}
+
+/* ------ Matrix utilities ------ */
+
+/* Read a matrix operand. */
+/* Return 0 if OK, error code if not. */
+int
+read_matrix(const ref *op, gs_matrix *pmat)
+{ int code;
+ ref values[6];
+ const ref *pvalues;
+
+ if ( r_has_type(op, t_array) )
+ pvalues = op->value.refs;
+ else
+ { int i;
+ for ( i = 0; i < 6; ++i )
+ { code = array_get(op, (long)i, &values[i]);
+ if ( code < 0 )
+ return code;
+ }
+ pvalues = values;
+ }
+ check_read(*op);
+ if ( r_size(op) != 6 )
+ return_error(e_rangecheck);
+ code = float_params(pvalues + 5, 6, (float *)pmat);
+ return (code < 0 ? code : 0);
+}
+
+/* Write a matrix operand. */
+/* Return 0 if OK, error code if not. */
+int
+write_matrix(register ref *op, const gs_matrix *pmat)
+{ ref *aptr;
+ const float *pel;
+ int i;
+
+ check_write_type(*op, t_array);
+ if ( r_size(op) != 6 )
+ return_error(e_rangecheck);
+ aptr = op->value.refs;
+ pel = (const float *)pmat;
+ for ( i = 5; i >= 0; i--, aptr++, pel++ )
+ { ref_save(op, aptr, "write_matrix");
+ make_real_new(aptr, *pel);
+ }
+ return 0;
+}
diff --git a/gs/src/iutil.h b/gs/src/iutil.h
new file mode 100644
index 000000000..222ed4dea
--- /dev/null
+++ b/gs/src/iutil.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 1991, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iutil.h */
+/* Prototypes for procedures in iutil.c */
+/* Requires imemory.h, ostack.h */
+
+/* ------ Object utilities ------ */
+
+/* Copy refs from one place to another. */
+/* (If we are copying to the stack, we can just use memcpy.) */
+void refcpy_to_new(P3(ref *to, const ref *from, uint size));
+int refcpy_to_old(P5(ref *aref, uint index, const ref *from, uint size, client_name_t cname));
+
+/* Fill an array with nulls. */
+void refset_null(P2(ref *to, uint size));
+
+/* Compare two objects for equality. */
+bool obj_eq(P2(const ref *, const ref *));
+
+/* Compare two objects for identity. */
+/* (This is not a standard PostScript concept.) */
+bool obj_ident_eq(P2(const ref *, const ref *));
+
+/*
+ * Create a printable representation of an object, a la cvs (full_print =
+ * false) or == (full_print = true). Return 0 if OK, <0 if the destination
+ * wasn't large enough or the object's contents weren't readable.
+ * If the object was a string or name, store a pointer to its characters
+ * even if it was too large. Note that if full_print is true, the only
+ * allowed types are boolean, integer, and real.
+ */
+int obj_cvp(P6(const ref *op, byte *str, uint len, uint *prlen,
+ const byte **pchars, bool full_print));
+#define obj_cvs(op, str, len, prlen, pchars)\
+ obj_cvp(op, str, len, prlen, pchars, false)
+
+/* Get an element from an array (packed or not). */
+int array_get(P3(const ref *, long, ref *));
+
+/* Get an element from a packed array. */
+/* (This works for ordinary arrays too.) */
+/* Source and destination are allowed to overlap if the source is packed, */
+/* or if they are identical. */
+void packed_get(P2(const ref_packed *, ref *));
+
+/* Check to make sure an interval contains no object references */
+/* to a space younger than a given one. */
+/* Return 0 or e_invalidaccess. */
+int refs_check_space(P3(const ref *refs, uint size, uint space));
+
+/* ------ String utilities ------ */
+
+/* Convert a C string to a string object. */
+int string_to_ref(P4(const char *, ref *, gs_ref_memory_t *, client_name_t));
+
+/* Convert a string object to a C string. */
+/* Return 0 iff the buffer can't be allocated. */
+char *ref_to_string(P3(const ref *, gs_memory_t *, client_name_t));
+
+/* ------ Operand utilities ------ */
+
+/* Get N numeric operands from the stack or an array. */
+int num_params(P3(const ref *, int, double *));
+/* float_params can lose accuracy for large integers. */
+int float_params(P3(const ref *, int, float *));
+
+/* Get a single real parameter. */
+/* The only possible error is e_typecheck. */
+int real_param(P2(const ref *, double *));
+/* float_param can lose accuracy for large integers. */
+int float_param(P2(const ref *, float *));
+
+/* Get an integer parameter in a given range. */
+int int_param(P3(const ref *, int, int *));
+
+/* Make real values on the stack. */
+/* Return e_limitcheck for infinities or double->float overflow. */
+int make_reals(P3(ref *, const double *, int));
+int make_floats(P3(ref *, const float *, int));
+
+/* Define the gs_matrix type if necessary. */
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+
+/* Read a matrix operand. */
+int read_matrix(P2(const ref *, gs_matrix *));
+
+/* Write a matrix operand. */
+int write_matrix(P2(ref *, const gs_matrix *));
diff --git a/gs/src/iutil2.c b/gs/src/iutil2.c
new file mode 100644
index 000000000..3b85b9cdf
--- /dev/null
+++ b/gs/src/iutil2.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iutil2.c */
+/* Level 2 utilities for Ghostscript interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "opcheck.h"
+#include "gsparam.h"
+#include "gsutil.h" /* bytes_compare prototype */
+#include "imemory.h" /* for iutil.h */
+#include "iutil.h"
+#include "iutil2.h"
+
+/* ------ Password utilities ------ */
+
+/* Read a password from a parameter list. */
+/* Return 0 if present, 1 if absent, or an error code. */
+int
+param_read_password(gs_param_list *plist, const char _ds *kstr, password *ppass)
+{ gs_param_string ps;
+ long ipass;
+ int code;
+ ps.data = (const byte *)ppass->data, ps.size = ppass->size,
+ ps.persistent = false;
+ code = param_read_string(plist, kstr, &ps);
+ switch ( code )
+ {
+ case 0: /* OK */
+ if ( ps.size > max_password )
+ return_error(e_limitcheck);
+ /* Copy the data back. */
+ memcpy(ppass->data, ps.data, ps.size);
+ ppass->size = ps.size;
+ return 0;
+ case 1: /* key is missing */
+ return 1;
+ }
+ /* We might have gotten a typecheck because */
+ /* the supplied password was an integer. */
+ if ( code != e_typecheck)
+ return code;
+ code = param_read_long(plist, kstr, &ipass);
+ if ( code != 0 ) /* error or missing */
+ return code;
+ sprintf((char *)ppass->data, "%ld", ipass);
+ ppass->size = strlen((char *)ppass->data);
+ return 0;
+}
+/* Write a password to a parameter list. */
+int
+param_write_password(gs_param_list *plist, const char _ds *kstr, const password *ppass)
+{ gs_param_string ps;
+ ps.data = (const byte *)ppass->data, ps.size = ppass->size,
+ ps.persistent = false;
+ if ( ps.size > max_password )
+ return_error(e_limitcheck);
+ return param_write_string(plist, kstr, &ps);
+}
+
+/* Check a password from a parameter list. */
+/* Return 0 if OK, 1 if not OK, or an error code. */
+int
+param_check_password(gs_param_list *plist, const password *ppass)
+{ if ( ppass->size != 0 )
+ { password pass;
+ int code = param_read_password(plist, "Password", &pass);
+ if ( code )
+ return code;
+ if ( pass.size != ppass->size ||
+ bytes_compare(&pass.data[0], pass.size,
+ &ppass->data[0],
+ ppass->size) != 0
+ )
+ return 1;
+ }
+ return 0;
+}
diff --git a/gs/src/iutil2.h b/gs/src/iutil2.h
new file mode 100644
index 000000000..f8b93560b
--- /dev/null
+++ b/gs/src/iutil2.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* iutil2.h */
+/* Interface to procedures in iutil2.c */
+
+/* ------ Password utilities ------ */
+
+/* Define the password structure. */
+#define max_password 64 /* must be at least 11 */
+typedef struct password_s {
+ uint size;
+ byte data[max_password];
+} password;
+# define NULL_PASSWORD {0, {0}}
+
+/* Define the system password(s). */
+extern password SystemParamsPassword;
+
+/* Transmit a password to or from a parameter list. */
+int param_read_password(P3(gs_param_list *, const char _ds *, password *));
+int param_write_password(P3(gs_param_list *, const char _ds *, const password *));
+
+/* Check a password from a parameter list. */
+/* Return 0 if OK, 1 if not OK, or an error code. */
+int param_check_password(P2(gs_param_list *, const password *));
diff --git a/gs/src/iutilasm.asm b/gs/src/iutilasm.asm
new file mode 100644
index 000000000..6afece9c2
--- /dev/null
+++ b/gs/src/iutilasm.asm
@@ -0,0 +1,696 @@
+; Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
+;
+; This file is part of Aladdin Ghostscript.
+;
+; Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+; or distributor accepts any responsibility for the consequences of using it,
+; or for whether it serves any particular purpose or works at all, unless he
+; or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+; License (the "License") for full details.
+;
+; Every copy of Aladdin Ghostscript must include a copy of the License,
+; normally in a plain ASCII text file named PUBLIC. The License grants you
+; the right to copy, modify and redistribute Aladdin Ghostscript, but only
+; under certain conditions described in the License. Among other things, the
+; License requires that the copyright notice and this notice be preserved on
+; all copies.
+
+; iutilasm.asm
+; Assembly code for Ghostscript interpreter on MS-DOS systems
+
+ ifdef FOR80386
+
+ .286c
+
+ endif
+
+utilasm_TEXT SEGMENT WORD PUBLIC 'CODE'
+ ASSUME CS:utilasm_TEXT
+
+
+ ifdef FOR80386
+
+; Macro for 32-bit operand prefix.
+OP32 macro
+ db 66h
+ endm
+
+ endif ; FOR80386
+
+; Clear a register
+
+clear macro reg
+ xor reg,reg
+ endm
+
+
+ ifdef FOR80386
+
+; Replace the multiply and divide routines in the Turbo C library
+; if we are running on an 80386.
+
+; Macro to swap the halves of a 32-bit register.
+; Unfortunately, masm won't allow a shift instruction with a count of 16,
+; so we have to code it in hex.
+swap macro regno
+ OP32
+ db 0c1h,0c0h+regno,16 ; rol regno,16
+ endm
+regax equ 0
+regcx equ 1
+regdx equ 2
+regbx equ 3
+
+
+; Multiply (dx,ax) by (cx,bx) to (dx,ax).
+ PUBLIC LXMUL@
+ PUBLIC F_LXMUL@
+F_LXMUL@ proc far
+LXMUL@ proc far
+ swap regdx
+ mov dx,ax
+ swap regcx
+ mov cx,bx
+ OP32
+ db 0fh,0afh,0d1h ; imul dx,cx
+ OP32
+ mov ax,dx
+ swap regdx
+ ret
+LXMUL@ endp
+F_LXMUL@ endp
+
+
+; Divide two stack operands, leave the result in (dx,ax).
+
+ ifdef DEBUG
+
+setup32 macro
+ mov bx,sp
+ push bp
+ mov bp,sp
+ OP32
+ mov ax,ss:[bx+4] ; dividend
+ endm
+
+ret32 macro n
+ mov sp,bp
+ pop bp
+ ret n
+ endm
+
+ else ; !DEBUG
+
+setup32 macro
+ mov bx,sp
+ OP32
+ mov ax,ss:[bx+4] ; dividend
+ endm
+
+ret32 macro n
+ ret n
+ endm
+
+ endif ; (!)DEBUG
+
+ PUBLIC LDIV@, LUDIV@, LMOD@, LUMOD@
+ PUBLIC F_LDIV@, F_LUDIV@, F_LMOD@, F_LUMOD@
+F_LDIV@ proc far
+LDIV@ proc far
+ setup32
+ OP32
+ cwd
+ OP32
+ idiv word ptr ss:[bx+8] ; divisor
+ OP32
+ mov dx,ax
+ swap regdx
+ ret32 8
+LDIV@ endp
+F_LDIV@ endp
+F_LUDIV@ proc far
+LUDIV@ proc far
+ setup32
+ OP32
+ xor dx,dx
+ OP32
+ div word ptr ss:[bx+8] ; divisor
+ OP32
+ mov dx,ax
+ swap regdx
+ ret32 8
+LUDIV@ endp
+F_LUDIV@ endp
+F_LMOD@ proc far
+LMOD@ proc far
+ setup32
+ OP32
+ cwd
+ OP32
+ idiv word ptr ss:[bx+8] ; divisor
+ OP32
+ mov ax,dx
+ swap regdx
+ ret32 8
+LMOD@ endp
+F_LMOD@ endp
+F_LUMOD@ proc far
+LUMOD@ proc far
+ setup32
+ OP32
+ xor dx,dx
+ OP32
+ div word ptr ss:[bx+8] ; divisor
+ OP32
+ mov ax,dx
+ swap regdx
+ ret32 8
+LUMOD@ endp
+F_LUMOD@ endp
+
+ else ; !FOR80386
+
+; Replace the divide routines in the Turbo C library,
+; which do the division one bit at a time (!).
+
+ PUBLIC LDIV@, LMOD@, LUDIV@, LUMOD@
+ PUBLIC F_LDIV@, F_LMOD@, F_LUDIV@, F_LUMOD@
+
+; Negate a long on the stack.
+negbp macro offset
+ neg word ptr [bp+offset+2] ; high part
+ neg word ptr [bp+offset] ; low part
+ sbb word ptr [bp+offset+2],0
+ endm
+
+; Negate a long in (dx,ax).
+negr macro
+ neg dx
+ neg ax
+ sbb dx,0
+ endm
+
+; Divide two unsigned longs on the stack.
+; Leave either the quotient or the remainder in (dx,ax).
+; Operand offsets assume that bp (and only bp) has been pushed.
+nlo equ 6
+nhi equ 8
+dlo equ 10
+dhi equ 12
+
+; We use an offset in bx to distinguish div from mod,
+; and to indicate whether the result should be negated.
+odiv equ 0
+omod equ 2
+odivneg equ 4
+omodneg equ 6
+F_LMOD@ proc far
+LMOD@ proc far
+ push bp
+ mov bp,sp
+ mov bx,omod
+ ; Take abs of denominator
+ cmp byte ptr [bp+dhi+1],bh ; bh = 0
+ jge modpd
+ negbp dlo
+modpd: ; Negate mod if numerator < 0
+ cmp byte ptr [bp+nhi+1],bh ; bh = 0
+ jge udiv
+ mov bx,omodneg
+negnum: negbp nlo
+ jmp udiv
+LMOD@ endp
+F_LMOD@ endp
+F_LUMOD@ proc far
+LUMOD@ proc far
+ mov bx,omod
+ jmp udpush
+LUMOD@ endp
+F_LUMOD@ endp
+F_LDIV@ proc far
+LDIV@ proc far
+ push bp
+ mov bp,sp
+ mov bx,odiv
+ ; Negate quo if num^den < 0
+ mov ax,[bp+nhi]
+ xor ax,[bp+dhi]
+ jge divabs
+ mov bx,odivneg
+divabs: ; Take abs of denominator
+ cmp byte ptr [bp+dhi+1],bh ; bh = 0
+ jge divpd
+ negbp dlo
+divpd: ; Take abs of numerator
+ cmp byte ptr [bp+nhi+1],bh ; bh = 0
+ jge udiv
+ jmp negnum
+LDIV@ endp
+F_LDIV@ endp
+F_LUDIV@ proc far
+LUDIV@ proc far
+ mov bx,odiv
+udpush: push bp
+ mov bp,sp
+udiv: push bx ; odiv, omod, odivneg, omodneg
+ mov ax,[bp+nlo]
+ mov dx,[bp+nhi]
+ mov bx,[bp+dlo]
+ mov cx,[bp+dhi]
+; Now we are dividing dx:ax by cx:bx.
+; Check to see whether this is really a 32/16 division.
+ or cx,cx
+ jnz div2
+; 32/16, check for 16- vs. 32-bit quotient
+ cmp dx,bx
+ jae div1
+; 32/16 with 16-bit quotient, just do it.
+ div bx ; ax = quo, dx = rem
+ pop bx
+ pop bp
+ jmp cs:xx1[bx]
+ even
+xx1 dw offset divx1
+ dw offset modx1
+ dw offset divx1neg
+ dw offset modx1neg
+modx1: mov ax,dx
+divx1: xor dx,dx
+ ret 8
+modx1neg: mov ax,dx
+divx1neg: xor dx,dx
+rneg: negr
+ ret 8
+; 32/16 with 32-bit quotient, do in 2 parts.
+div1: mov cx,ax ; save lo num
+ mov ax,dx
+ xor dx,dx
+ div bx ; ax = hi quo
+ xchg cx,ax ; save hi quo, get lo num
+ div bx ; ax = lo quo, dx = rem
+ pop bx
+ pop bp
+ jmp cs:xx1a[bx]
+ even
+xx1a dw offset divx1a
+ dw offset modx1
+ dw offset divx1aneg
+ dw offset modx1neg
+divx1a: mov dx,cx ; hi quo
+ ret 8
+divx1aneg: mov dx,cx
+ jmp rneg
+; This is really a 32/32 bit division.
+; (Note that the quotient cannot exceed 16 bits.)
+; The following algorithm is taken from pp. 235-240 of Knuth, vol. 2
+; (first edition).
+; Start by normalizing the numerator and denominator.
+div2: or ch,ch
+ jz div21 ; ch == 0, but cl != 0
+; Do 8 steps all at once.
+ mov bl,bh
+ mov bh,cl
+ mov cl,ch
+ xor ch,ch
+ mov al,ah
+ mov ah,dl
+ mov dl,dh
+ xor dh,dh
+ rol bx,1 ; faster than jmp
+div2a: rcr bx,1 ; finish previous shift
+div21: shr dx,1
+ rcr ax,1
+ shr cx,1
+ jnz div2a
+ rcr bx,1
+; Now we can do a 32/16 divide.
+div2x: div bx ; ax = quo, dx = rem
+; Multiply by the denominator, and correct the result.
+ mov cx,ax ; save quotient
+ mul word ptr [bp+dhi]
+ mov bx,ax ; save lo part of hi product
+ mov ax,cx
+ mul word ptr [bp+dlo]
+ add dx,bx
+; Now cx = trial quotient, (dx,ax) = cx * denominator.
+ not dx
+ neg ax
+ cmc
+ adc dx,0 ; double-precision neg
+ jc divz ; zero quotient
+ ; requires special handling
+ add ax,[bp+nlo]
+ adc dx,[bp+nhi]
+ jc divx
+; Quotient is too large, adjust it.
+div3: dec cx
+ add ax,[bp+dlo]
+ adc dx,[bp+dhi]
+ jnc div3
+; All done. (dx,ax) = remainder, cx = lo quotient.
+divx: pop bx
+ pop bp
+ jmp cs:xx3[bx]
+ even
+xx3 dw offset divx3
+ dw offset modx3
+ dw offset divx3neg
+ dw offset modx3neg
+divx3: mov ax,cx
+ xor dx,dx
+modx3: ret 8
+divx3neg: mov ax,cx
+ xor dx,dx
+modx3neg: jmp rneg
+; Handle zero quotient specially.
+divz: pop bx
+ jmp cs:xxz[bx]
+ even
+xxz dw offset divxz
+ dw offset modxz
+ dw offset divxz
+ dw offset modxzneg
+divxz: pop bp
+ ret 8
+modxzneg: negbp nlo
+modxz: mov ax,[bp+nlo]
+ mov dx,[bp+nhi]
+ pop bp
+ ret 8
+LUDIV@ endp
+F_LUDIV@ endp
+
+ endif ; FOR80386
+
+
+ ifdef NOFPU
+
+; See gsmisc.c for the C version of this code.
+
+; /*
+; * Floating multiply with fixed result, for avoiding floating point in
+; * common coordinate transformations. Assumes IEEE representation,
+; * 16-bit short, 32-bit long. Optimized for the case where the first
+; * operand has no more than 16 mantissa bits, e.g., where it is a user space
+; * coordinate (which are often integers).
+; *
+; * The assembly language version of this code is actually faster than
+; * the FPU, if the code is compiled with FPU_TYPE=0 (which requires taking
+; * a trap on every FPU operation). If there is no FPU, the assembly
+; * language version of this code is over 10 times as fast as the
+; * emulated FPU.
+; */
+; fixed
+; fmul2fixed_(long /*float*/ a, long /*float*/ b)
+; {
+
+ PUBLIC _fmul2fixed_
+_fmul2fixed_ proc far
+ push bp
+ mov bp,sp
+a equ 6
+alo equ a
+ahi equ a+2
+b equ 10
+blo equ b
+bhi equ b+2
+ push si ; will hold ma
+ push di ; will hold mb
+
+; int e = 260 + _fixed_shift - ((
+; (((uint)(a >> 16)) & 0x7f80) + (((uint)(b >> 16)) & 0x7f80)
+; ) >> 7);
+
+ mov dx,[bp+ahi]
+; dfmul2fixed enters here
+fmf: mov cx,260+12
+ mov ax,[bp+bhi]
+ and ax,7f80h
+ and dx,7f80h
+ add ax,dx
+ xchg ah,al ; ror ax,7 without using cl
+ rol ax,1
+ sub cx,ax
+ push cx ; e
+
+; ulong ma = (ushort)(a >> 8) | 0x8000;
+; ulong mb = (ushort)(b >> 8) | 0x8000;
+
+ mov si,[bp+alo+1] ; unaligned
+ clear ax
+ mov di,[bp+blo+1] ; unaligned
+ or si,8000h
+ or di,8000h
+
+; ulong p1 = ma * (b & 0xff);
+
+ mov al,[bp+blo]
+ mul si
+
+; (Do this later:)
+; ulong p = ma * mb;
+
+; if ( (byte)a ) /* >16 mantissa bits */
+
+ cmp byte ptr [bp+alo],0
+ je mshort
+
+; { ulong p2 = (a & 0xff) * mb;
+; p += ((((uint)(byte)a * (uint)(byte)b) >> 8) + p1 + p2) >> 8;
+
+ mov cx,dx
+ mov bx,ax
+ clear ax
+ mov al,[bp+alo]
+ clear dx
+ mov dl,[bp+blo]
+ mul dx
+ mov dl,ah ; dx is zero
+ add bx,cx
+ adc cx,0
+ clear ax
+ mov al,[bp+alo]
+ mul di
+ add ax,bx
+ adc dx,cx
+
+; }
+
+mshort:
+
+; else
+; p += p1 >> 8;
+
+ mov bl,ah ; set (cx,bx) = (dx,ax) >> 8
+ mov bh,dl
+ clear cx
+ mov cl,dh
+ mov ax,si
+ mul di
+ add ax,bx
+ adc dx,cx
+
+; if ( (uint)e < 32 ) /* e = -1 is possible */
+
+ pop cx ; e
+ cmp cx,16
+ jb shr1
+
+; else if ( e >= 32 ) /* also detects a=0 or b=0 */
+
+ cmp cx,0
+ jl eneg
+ sub cx,16
+ cmp cx,16
+ jge shr0
+ mov ax,dx
+ clear dx
+ shr ax,cl
+ jmp ex
+
+; return fixed_0;
+
+shr0: clear ax
+ clear dx
+ jmp ex
+
+; else
+; p <<= -e;
+
+ even
+eneg: neg cx
+ shl dx,cl
+ mov bx,ax
+ shl ax,cl
+ rol bx,cl
+ xor bx,ax
+ add dx,bx
+ jmp ex
+
+; p >>= e;
+
+ even
+shr1: shr ax,cl
+ mov bx,dx
+ shr dx,cl
+ ror bx,cl
+ xor bx,dx
+ add ax,bx
+
+ex:
+
+; return ((a ^ b) < 0 ? -p : p);
+
+ mov cx,[bp+ahi]
+ xor cx,[bp+bhi]
+ jge pos
+ neg dx
+ neg ax
+ sbb dx,0
+pos:
+
+; }
+
+retu: pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+
+_fmul2fixed_ ENDP
+
+; The same routine with the first argument a double rather than a float.
+; The argument is split into two pieces to reduce data movement.
+
+ PUBLIC _dfmul2fixed_
+_dfmul2fixed_ proc far
+ push bp
+ mov bp,sp
+xalo equ 6
+;b equ 10
+xahi equ 14
+ push si ; overlap this below
+ push di ; ditto
+
+; Shuffle the arguments and then use fmul2fixed.
+
+; Squeeze 3 exponent bits out of the top 35 bits of a.
+
+ mov dx,[bp+xahi+2]
+ mov bx,0c000h
+ mov ax,[bp+xahi]
+ and bx,dx
+ mov cx,[bp+xalo+2]
+ and dx,7ffh ; get rid of discarded bits
+ add cx,cx ; faster than shl!
+ jz cz ; detect common case
+ adc ax,ax ; faster than rcl!
+ adc dx,dx
+ add cx,cx
+ adc ax,ax
+ adc dx,dx
+ add cx,cx
+ adc ax,ax
+ mov [bp+alo],ax
+ adc dx,dx
+ or dx,bx
+ mov [bp+ahi],dx
+ jmp fmf
+ even
+cz: adc ax,ax
+ adc dx,dx
+ add ax,ax
+ adc dx,dx
+ add ax,ax
+ mov [bp+alo],ax
+ adc dx,dx
+ or dx,bx
+ mov [bp+ahi],dx
+ jmp fmf
+
+_dfmul2fixed_ ENDP
+
+ endif ; NOFPU
+
+
+; Transpose an 8x8 bit matrix. See gsmisc.c for the algorithm in C.
+ PUBLIC _memflip8x8
+_memflip8x8 proc far
+ push ds
+ push si
+ push di
+ ; After pushing, the offsets of the parameters are:
+ ; byte *inp=10, int line_size=14, byte *outp=16, int dist=20.
+ mov si,sp
+ mov di,ss:[si+14] ; line_size
+ lds si,ss:[si+10] ; inp
+ ; We assign variables to registers as follows:
+ ; ax = AE, bx = BF, cx (or di) = CG, dx = DH.
+ ; Load the input data. Initially we assign
+ ; ax = AB, bx = EF, cx (or di) = CD, dx = GH.
+ mov ah,[si]
+iload macro reg
+ add si,di
+ mov reg,[si]
+ endm
+ iload al
+ iload ch
+ iload cl
+ iload bh
+ iload bl
+ iload dh
+ iload dl
+ ; Transposition macro, see C code for explanation.
+trans macro reg1,reg2,shift,mask
+ mov si,reg1
+ shr si,shift
+ xor si,reg2
+ and si,mask
+ xor reg2,si
+ shl si,shift
+ xor reg1,si
+ endm
+ ; Do 4x4 transpositions
+ mov di,cx ; we need cl for the shift count
+ mov cl,4
+ trans bx,ax,cl,0f0fh
+ trans dx,di,cl,0f0fh
+ ; Swap B/E, D/G
+ xchg al,bh
+ mov cx,di
+ xchg cl,dh
+ ; Do 2x2 transpositions
+ mov di,cx ; need cl again
+ mov cl,2
+ trans di,ax,cl,3333h
+ trans dx,bx,cl,3333h
+ mov cx,di ; done shifting >1
+ ; Do 1x1 transpositions
+ trans bx,ax,1,5555h
+ trans dx,cx,1,5555h
+ ; Store result
+ mov si,sp
+ mov di,ss:[si+20] ; dist
+ lds si,ss:[si+16] ; outp
+ mov [si],ah
+istore macro reg
+ add si,di
+ mov [si],reg
+ endm
+ istore bh
+ istore ch
+ istore dh
+ istore al
+ istore bl
+ istore cl
+ istore dl
+ ; All done
+ pop di
+ pop si
+ pop ds
+ ret
+_memflip8x8 ENDP
+
+
+utilasm_TEXT ENDS
+ END
diff --git a/gs/src/ivmspace.h b/gs/src/ivmspace.h
new file mode 100644
index 000000000..806257838
--- /dev/null
+++ b/gs/src/ivmspace.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 1992, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ivmspace.h */
+/* Local/global space management */
+/* Requires iref.h */
+
+#ifndef ivmspace_INCLUDED
+# define ivmspace_INCLUDED
+
+#include "gsgc.h"
+
+/*
+ * r_space_bits and r_space_shift, which define the bits in a ref
+ * that carry VM space information, are defined in iref.h.
+ * r_space_bits must be at least 2.
+ */
+#define a_space (((1 << r_space_bits) - 1) << r_space_shift)
+/*
+ * The i_vm_xxx values are defined in gsgc.h.
+ */
+typedef enum {
+ avm_foreign = (i_vm_foreign << r_space_shift),
+ avm_system = (i_vm_system << r_space_shift),
+ avm_global = (i_vm_global << r_space_shift),
+ avm_local = (i_vm_local << r_space_shift),
+ avm_max = avm_local
+} avm_space;
+#define r_space(rp) (avm_space)(r_type_attrs(rp) & a_space)
+#define r_space_index(rp) ((int)r_space(rp) >> r_space_shift)
+#define r_set_space(rp,space) r_store_attrs(rp, a_space, (uint)space)
+
+/*
+ * According to the PostScript language specification, attempting to store
+ * a reference to a local object into a global object must produce an
+ * invalidaccess error. However, systemdict must be able to refer to
+ * a number of local dictionaries such as userdict and errordict.
+ * Therefore, we implement a special hack in 'def' that allows such stores
+ * if the dictionary being stored into is systemdict (which is normally
+ * only writable during initialization) or a dictionary that appears
+ * in systemdict (such as level2dict), and the current save level is zero
+ * (to guarantee that we can't get dangling pointers).
+ * We could allow this for any global dictionary, except that the garbage
+ * collector must treat any such dictionaries as roots when collecting
+ * local VM without collecting global VM.
+ * We make a similar exception for .makeglobaloperator; this requires
+ * treating the operator table as a GC root as well.
+ *
+ * We extend the local-into-global store check because we have four VM
+ * spaces (local, global, system, and foreign), and we allow PostScript
+ * programs to create objects in any of the first three. If we define
+ * the "generation" of an object as foreign = 0, system = 1, global = 2,
+ * and local = 3, then a store is legal iff the generation of the object
+ * into which a pointer is being stored is greater than or equal to
+ * the generation of the object into which the store is occurring.
+ *
+ * We must check for local-into-global stores in three categories of places:
+ *
+ * - The scanner, when it encounters a //name inside {}.
+ *
+ * - All operators that allocate ref-containing objects and also
+ * store into them:
+ * packedarray gstate makepattern?
+ * makefont scalefont definefont filter
+ *
+ * - All operators that store refs into existing objects
+ * ("operators" marked with * are actually PostScript procedures):
+ * put(array) putinterval(array) astore copy(to array)
+ * def store* put(dict) copy(dict)
+ * dictstack execstack .make(global)operator
+ * currentgstate defineusername
+ */
+
+/* Test whether an object is in local space, */
+/* which implies that we need not check when storing into it. */
+#define r_is_local(rp) (r_space(rp) == avm_local)
+/* Test whether an object is foreign, i.e., outside known space. */
+#define r_is_foreign(rp) (r_space(rp) == avm_foreign)
+/* Check whether a store is allowed. */
+#define store_check_space(destspace,rpnew)\
+ if ( r_space(rpnew) > (destspace) )\
+ return_error(e_invalidaccess)
+#define store_check_dest(rpdest,rpnew)\
+ store_check_space(r_space(rpdest), rpnew)
+/* BACKWARD COMPATIBILITY (not used by any Ghostscript code per se) */
+#define check_store_space(rdest,rnewcont)\
+ store_check_dest(&(rdest),&(rnewcont))
+
+#endif /* ivmspace_INCLUDED */
diff --git a/gs/src/jpeg.mak b/gs/src/jpeg.mak
new file mode 100644
index 000000000..86aa8a273
--- /dev/null
+++ b/gs/src/jpeg.mak
@@ -0,0 +1,361 @@
+# Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Independent JPEG Group library code.
+
+# NOTE: This makefile is only known to work with the following versions
+# of the IJG library: 6, 6a.
+# As of May 11, 1996, version 6a is the current version.
+#
+# You can get the IJG library by Internet anonymous FTP from the following
+# places:
+# Standard distribution (tar + gzip format, Unix end-of-line):
+# ftp.uu.net:/graphics/jpeg/jpegsrc.v*.tar.gz
+# ftp.cs.wisc.edu:/ghost/jpegsrc.v*.tar.gz
+# MS-DOS archive (PKZIP a.k.a. zip format, MS-DOS end-of-line):
+# ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr*.zip
+# ftp.cs.wisc.edu:/ghost/jpeg-*.zip
+# The first site named above (ftp.uu.net and ftp.simtel.net) is supposed
+# to be the master distribution site, so it may have a more up-to-date
+# version; the ftp.cs.wisc.edu site is the master distribution site for
+# Ghostscript, so it will always have IJG library versions known to be
+# compatible with Ghostscript.
+#
+# If the version number, and hence the subdirectory name, changes, you
+# will probably want to change the definitions of JSRCDIR and possibly
+# JVERSION (in the platform-specific makefile, not here) to reflect this,
+# since that way you can use the IJG archive without change.
+#
+# NOTE: For some obscure reason (probably a bug in djtarx), if you are
+# compiling on a DesqView/X system, you should use the zip version of the
+# IJG library, not the tar.gz version.
+
+# Define the name of this makefile.
+JPEG_MAK=jpeg.mak
+
+# JSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the IJG library sources are stored.
+#JSRCDIR=jpeg-6a
+# JVERSION is defined in the platform-specific makefile, not here,
+# as the IJG library major version number (currently "5" or "6").
+#JVERSION=6
+
+JSRC=$(JSRCDIR)$(D)
+# CCCJ is defined in gs.mak.
+#CCCJ=$(CCC) -I. -I$(JSRCDIR)
+
+# We keep all of the IJG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+# However, we need our own version of jconfig.h, and our own "wrapper" for
+# jmorecfg.h. We also need a substitute for jerror.c, in order to
+# keep the error strings out of the automatic data segment in
+# 16-bit environments. For v5*, we also need our own version of jpeglib.h
+# in order to change MAX_BLOCKS_IN_MCU for Adobe compatibility.
+# (This need will go away when IJG v6 is released.)
+
+# Because this file is included after lib.mak, we can't use _h macros
+# to express indirect dependencies; instead, we build the dependencies
+# into the rules for copying the files.
+jconfig_h=jconfig.h
+jerror_h=jerror.h
+jmorecfg_h=jmorecfg.h
+jpeglib_h=jpeglib.h
+
+jconfig.h: gsjconf.h $(std_h)
+ $(CP_) gsjconf.h jconfig.h
+
+jmorecfg.h: gsjmorec.h jmcorig.h
+ $(CP_) gsjmorec.h jmorecfg.h
+
+jmcorig.h: $(JSRC)jmorecfg.h
+ $(CP_) $(JSRC)jmorecfg.h jmcorig.h
+
+jpeglib.h: jlib$(JVERSION).h jconfig.h jmorecfg.h
+ $(CP_) jlib$(JVERSION).h jpeglib.h
+
+jlib5.h: gsjpglib.h
+ $(CP_) gsjpglib.h jlib5.h
+
+jlib6.h: $(JSRC)jpeglib.h
+ $(CP_) $(JSRC)jpeglib.h jlib6.h
+
+# To ensure that the compiler finds our versions of jconfig.h and jmorecfg.h,
+# regardless of the compiler's search rule, we must copy up all .c files,
+# and all .h files that include either of these files, directly or
+# indirectly. The only such .h files currently are jinclude.h and jpeglib.h.
+# (Currently, we supply our own version of jpeglib.h -- see above.)
+# Also, to avoid including the JSRCDIR directory name in our source files,
+# we must also copy up any other .h files that our own code references.
+# Currently, the only such .h files are jerror.h and jversion.h.
+
+JHCOPY=jinclude.h jpeglib.h jerror.h jversion.h
+
+jinclude.h: $(JSRC)jinclude.h
+ $(CP_) $(JSRC)jinclude.h jinclude.h
+
+#jpeglib.h: $(JSRC)jpeglib.h
+# $(CP_) $(JSRC)jpeglib.h jpeglib.h
+
+jerror.h: $(JSRC)jerror.h
+ $(CP_) $(JSRC)jerror.h jerror.h
+
+jversion.h: $(JSRC)jversion.h
+ $(CP_) $(JSRC)jversion.h jversion.h
+
+# In order to avoid having to keep the dependency lists for the IJG code
+# accurate, we simply make all of them depend on the only files that
+# we are ever going to change, and on all the .h files that must be copied up.
+# This is too conservative, but only hurts us if we are changing our own
+# j*.h files, which happens only rarely during development.
+
+JDEP=$(AK) $(jconfig_h) $(jerror_h) $(jmorecfg_h) $(JHCOPY)
+
+# Code common to compression and decompression.
+
+jpegc_=jcomapi.$(OBJ) jutils.$(OBJ) sjpegerr.$(OBJ) jmemmgr.$(OBJ)
+jpegc.dev: $(JPEG_MAK) $(ECHOGS_XE) $(jpegc_)
+ $(SETMOD) jpegc $(jpegc_)
+
+jcomapi.$(OBJ): $(JSRC)jcomapi.c $(JDEP)
+ $(CP_) $(JSRC)jcomapi.c .
+ $(CCCJ) jcomapi.c
+ $(RM_) jcomapi.c
+
+jutils.$(OBJ): $(JSRC)jutils.c $(JDEP)
+ $(CP_) $(JSRC)jutils.c .
+ $(CCCJ) jutils.c
+ $(RM_) jutils.c
+
+# Note that sjpegerr replaces jerror.
+sjpegerr.$(OBJ): sjpegerr.c $(JDEP)
+ $(CCCF) sjpegerr.c
+
+jmemmgr.$(OBJ): $(JSRC)jmemmgr.c $(JDEP)
+ $(CP_) $(JSRC)jmemmgr.c .
+ $(CCCJ) jmemmgr.c
+ $(RM_) jmemmgr.c
+
+# Encoding (compression) code.
+
+jpege.dev: jpege$(JVERSION).dev
+ $(CP_) jpege$(JVERSION).dev jpege.dev
+
+jpege5=jcapi.$(OBJ)
+jpege6=jcapimin.$(OBJ) jcapistd.$(OBJ) jcinit.$(OBJ)
+
+jpege_1=jccoefct.$(OBJ) jccolor.$(OBJ) jcdctmgr.$(OBJ)
+jpege_2=jchuff.$(OBJ) jcmainct.$(OBJ) jcmarker.$(OBJ) jcmaster.$(OBJ)
+jpege_3=jcparam.$(OBJ) jcprepct.$(OBJ) jcsample.$(OBJ) jfdctint.$(OBJ)
+
+jpege5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege5) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege5 $(jpege5)
+ $(ADDMOD) jpege5 -include jpegc
+ $(ADDMOD) jpege5 -obj $(jpege_1)
+ $(ADDMOD) jpege5 -obj $(jpege_2)
+ $(ADDMOD) jpege5 -obj $(jpege_3)
+
+jpege6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege6) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege6 $(jpege6)
+ $(ADDMOD) jpege6 -include jpegc
+ $(ADDMOD) jpege6 -obj $(jpege_1)
+ $(ADDMOD) jpege6 -obj $(jpege_2)
+ $(ADDMOD) jpege6 -obj $(jpege_3)
+
+# jcapi.c is v5* only
+jcapi.$(OBJ): $(JSRC)jcapi.c $(JDEP)
+ $(CP_) $(JSRC)jcapi.c .
+ $(CCCJ) jcapi.c
+ $(RM_) jcapi.c
+
+# jcapimin.c is new in v6
+jcapimin.$(OBJ): $(JSRC)jcapimin.c $(JDEP)
+ $(CP_) $(JSRC)jcapimin.c .
+ $(CCCJ) jcapimin.c
+ $(RM_) jcapimin.c
+
+# jcapistd.c is new in v6
+jcapistd.$(OBJ): $(JSRC)jcapistd.c $(JDEP)
+ $(CP_) $(JSRC)jcapistd.c .
+ $(CCCJ) jcapistd.c
+ $(RM_) jcapistd.c
+
+# jcinit.c is new in v6
+jcinit.$(OBJ): $(JSRC)jcinit.c $(JDEP)
+ $(CP_) $(JSRC)jcinit.c .
+ $(CCCJ) jcinit.c
+ $(RM_) jcinit.c
+
+jccoefct.$(OBJ): $(JSRC)jccoefct.c $(JDEP)
+ $(CP_) $(JSRC)jccoefct.c .
+ $(CCCJ) jccoefct.c
+ $(RM_) jccoefct.c
+
+jccolor.$(OBJ): $(JSRC)jccolor.c $(JDEP)
+ $(CP_) $(JSRC)jccolor.c .
+ $(CCCJ) jccolor.c
+ $(RM_) jccolor.c
+
+jcdctmgr.$(OBJ): $(JSRC)jcdctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jcdctmgr.c .
+ $(CCCJ) jcdctmgr.c
+ $(RM_) jcdctmgr.c
+
+jchuff.$(OBJ): $(JSRC)jchuff.c $(JDEP)
+ $(CP_) $(JSRC)jchuff.c .
+ $(CCCJ) jchuff.c
+ $(RM_) jchuff.c
+
+jcmainct.$(OBJ): $(JSRC)jcmainct.c $(JDEP)
+ $(CP_) $(JSRC)jcmainct.c .
+ $(CCCJ) jcmainct.c
+ $(RM_) jcmainct.c
+
+jcmarker.$(OBJ): $(JSRC)jcmarker.c $(JDEP)
+ $(CP_) $(JSRC)jcmarker.c .
+ $(CCCJ) jcmarker.c
+ $(RM_) jcmarker.c
+
+jcmaster.$(OBJ): $(JSRC)jcmaster.c $(JDEP)
+ $(CP_) $(JSRC)jcmaster.c .
+ $(CCCJ) jcmaster.c
+ $(RM_) jcmaster.c
+
+jcparam.$(OBJ): $(JSRC)jcparam.c $(JDEP)
+ $(CP_) $(JSRC)jcparam.c .
+ $(CCCJ) jcparam.c
+ $(RM_) jcparam.c
+
+jcprepct.$(OBJ): $(JSRC)jcprepct.c $(JDEP)
+ $(CP_) $(JSRC)jcprepct.c .
+ $(CCCJ) jcprepct.c
+ $(RM_) jcprepct.c
+
+jcsample.$(OBJ): $(JSRC)jcsample.c $(JDEP)
+ $(CP_) $(JSRC)jcsample.c .
+ $(CCCJ) jcsample.c
+ $(RM_) jcsample.c
+
+jfdctint.$(OBJ): $(JSRC)jfdctint.c $(JDEP)
+ $(CP_) $(JSRC)jfdctint.c .
+ $(CCCJ) jfdctint.c
+ $(RM_) jfdctint.c
+
+# Decompression code
+
+jpegd.dev: jpegd$(JVERSION).dev
+ $(CP_) jpegd$(JVERSION).dev jpegd.dev
+
+jpegd5=jdapi.$(OBJ)
+jpegd6=jdapimin.$(OBJ) jdapistd.$(OBJ) jdinput.$(OBJ) jdphuff.$(OBJ)
+
+jpegd_1=jdcoefct.$(OBJ) jdcolor.$(OBJ)
+jpegd_2=jddctmgr.$(OBJ) jdhuff.$(OBJ) jdmainct.$(OBJ) jdmarker.$(OBJ)
+jpegd_3=jdmaster.$(OBJ) jdpostct.$(OBJ) jdsample.$(OBJ) jidctint.$(OBJ)
+
+jpegd5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd5) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd5 $(jpegd5)
+ $(ADDMOD) jpegd5 -include jpegc
+ $(ADDMOD) jpegd5 -obj $(jpegd_1)
+ $(ADDMOD) jpegd5 -obj $(jpegd_2)
+ $(ADDMOD) jpegd5 -obj $(jpegd_3)
+
+jpegd6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd6) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd6 $(jpegd6)
+ $(ADDMOD) jpegd6 -include jpegc
+ $(ADDMOD) jpegd6 -obj $(jpegd_1)
+ $(ADDMOD) jpegd6 -obj $(jpegd_2)
+ $(ADDMOD) jpegd6 -obj $(jpegd_3)
+
+# jdapi.c is v5* only
+jdapi.$(OBJ): $(JSRC)jdapi.c $(JDEP)
+ $(CP_) $(JSRC)jdapi.c .
+ $(CCCJ) jdapi.c
+ $(RM_) jdapi.c
+
+# jdapimin.c is new in v6
+jdapimin.$(OBJ): $(JSRC)jdapimin.c $(JDEP)
+ $(CP_) $(JSRC)jdapimin.c .
+ $(CCCJ) jdapimin.c
+ $(RM_) jdapimin.c
+
+# jdapistd.c is new in v6
+jdapistd.$(OBJ): $(JSRC)jdapistd.c $(JDEP)
+ $(CP_) $(JSRC)jdapistd.c .
+ $(CCCJ) jdapistd.c
+ $(RM_) jdapistd.c
+
+jdcoefct.$(OBJ): $(JSRC)jdcoefct.c $(JDEP)
+ $(CP_) $(JSRC)jdcoefct.c .
+ $(CCCJ) jdcoefct.c
+ $(RM_) jdcoefct.c
+
+jdcolor.$(OBJ): $(JSRC)jdcolor.c $(JDEP)
+ $(CP_) $(JSRC)jdcolor.c .
+ $(CCCJ) jdcolor.c
+ $(RM_) jdcolor.c
+
+jddctmgr.$(OBJ): $(JSRC)jddctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jddctmgr.c .
+ $(CCCJ) jddctmgr.c
+ $(RM_) jddctmgr.c
+
+jdhuff.$(OBJ): $(JSRC)jdhuff.c $(JDEP)
+ $(CP_) $(JSRC)jdhuff.c .
+ $(CCCJ) jdhuff.c
+ $(RM_) jdhuff.c
+
+# jdinput.c is new in v6
+jdinput.$(OBJ): $(JSRC)jdinput.c $(JDEP)
+ $(CP_) $(JSRC)jdinput.c .
+ $(CCCJ) jdinput.c
+ $(RM_) jdinput.c
+
+jdmainct.$(OBJ): $(JSRC)jdmainct.c $(JDEP)
+ $(CP_) $(JSRC)jdmainct.c .
+ $(CCCJ) jdmainct.c
+ $(RM_) jdmainct.c
+
+jdmarker.$(OBJ): $(JSRC)jdmarker.c $(JDEP)
+ $(CP_) $(JSRC)jdmarker.c .
+ $(CCCJ) jdmarker.c
+ $(RM_) jdmarker.c
+
+jdmaster.$(OBJ): $(JSRC)jdmaster.c $(JDEP)
+ $(CP_) $(JSRC)jdmaster.c .
+ $(CCCJ) jdmaster.c
+ $(RM_) jdmaster.c
+
+# jdphuff.c is new in v6
+jdphuff.$(OBJ): $(JSRC)jdphuff.c $(JDEP)
+ $(CP_) $(JSRC)jdphuff.c .
+ $(CCCJ) jdphuff.c
+ $(RM_) jdphuff.c
+
+jdpostct.$(OBJ): $(JSRC)jdpostct.c $(JDEP)
+ $(CP_) $(JSRC)jdpostct.c .
+ $(CCCJ) jdpostct.c
+ $(RM_) jdpostct.c
+
+jdsample.$(OBJ): $(JSRC)jdsample.c $(JDEP)
+ $(CP_) $(JSRC)jdsample.c .
+ $(CCCJ) jdsample.c
+ $(RM_) jdsample.c
+
+jidctint.$(OBJ): $(JSRC)jidctint.c $(JDEP)
+ $(CP_) $(JSRC)jidctint.c .
+ $(CCCJ) jidctint.c
+ $(RM_) jidctint.c
diff --git a/gs/src/lib.mak b/gs/src/lib.mak
new file mode 100644
index 000000000..f5eb6165a
--- /dev/null
+++ b/gs/src/lib.mak
@@ -0,0 +1,1278 @@
+# Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for graphics library and other support code.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+LIB_MAK=lib.mak
+
+# Define the inter-dependencies of the .h files.
+# Since not all versions of `make' defer expansion of macros,
+# we must list these in bottom-to-top order.
+
+# Generic files
+
+arch_h=arch.h
+stdpre_h=stdpre.h
+std_h=std.h $(arch_h) $(stdpre_h)
+
+# Platform interfaces
+
+gp_h=gp.h
+gpcheck_h=gpcheck.h
+gpsync_h=gpsync.h
+
+# Configuration definitions
+
+# gconfig*.h are generated dynamically.
+gconfig__h=gconfig_.h
+gconfigv_h=gconfigv.h
+gscdefs_h=gscdefs.h
+
+# C library interfaces
+
+# Because of variations in the "standard" header files between systems, and
+# because we must include std.h before any file that includes sys/types.h,
+# we define local include files named *_.h to substitute for <*.h>.
+
+vmsmath_h=vmsmath.h
+
+dos__h=dos_.h
+ctype__h=ctype_.h $(std_h)
+dirent__h=dirent_.h $(std_h) $(gconfig__h)
+errno__h=errno_.h $(std_h)
+malloc__h=malloc_.h $(std_h)
+math__h=math_.h $(std_h) $(vmsmath_h)
+memory__h=memory_.h $(std_h)
+stat__h=stat_.h $(std_h)
+stdio__h=stdio_.h $(std_h)
+string__h=string_.h $(std_h)
+time__h=time_.h $(std_h) $(gconfig__h)
+windows__h=windows_.h
+
+# Miscellaneous
+
+gdebug_h=gdebug.h
+gsalloc_h=gsalloc.h
+gsargs_h=gsargs.h
+gserror_h=gserror.h
+gserrors_h=gserrors.h
+gsexit_h=gsexit.h
+gsgc_h=gsgc.h
+gsio_h=gsio.h
+gsmdebug_h=gsmdebug.h
+gsmemraw_h=gsmemraw.h
+gsmemory_h=gsmemory.h $(gsmemraw_h)
+gsrefct_h=gsrefct.h
+gsstruct_h=gsstruct.h
+gstypes_h=gstypes.h
+gx_h=gx.h $(stdio__h) $(gdebug_h) $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
+
+GX=$(AK) $(gx_h)
+GXERR=$(GX) $(gserrors_h)
+
+###### Support
+
+### Include files
+
+gsbitmap_h=gsbitmap.h $(gsstruct_h)
+gsbitops_h=gsbitops.h
+gsbittab_h=gsbittab.h
+gsflip_h=gsflip.h
+gsuid_h=gsuid.h
+gsutil_h=gsutil.h
+gxarith_h=gxarith.h
+gxbitmap_h=gxbitmap.h $(gsbitmap_h) $(gstypes_h)
+gxfarith_h=gxfarith.h $(gconfigv_h) $(gxarith_h)
+gxfixed_h=gxfixed.h
+gxobj_h=gxobj.h $(gxbitmap_h)
+# Out of order
+gxalloc_h=gxalloc.h $(gsalloc_h) $(gxobj_h)
+
+### Executable code
+
+gsalloc.$(OBJ): gsalloc.c $(GX) $(memory__h) $(string__h) \
+ $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsargs.$(OBJ): gsargs.c $(ctype__h) $(stdio__h) $(string__h)\
+ $(gsargs_h) $(gsexit_h) $(gsmemory_h)
+
+gsbitops.$(OBJ): gsbitops.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gsbitops_h) $(gstypes_h)
+
+gsbittab.$(OBJ): gsbittab.c $(AK) $(stdpre_h) $(gsbittab_h)
+
+# gsfemu is only used in FPU-less configurations, and currently only with gcc.
+# We thought using CCLEAF would produce smaller code, but it actually
+# produces larger code!
+gsfemu.$(OBJ): gsfemu.c $(AK) $(std_h)
+
+# gsflip is not part of the standard configuration: it's rather large,
+# and no standard facility requires it.
+gsflip.$(OBJ): gsflip.c $(GX) $(gsbittab_h) $(gsflip_h)
+ $(CCLEAF) gsflip.c
+
+gsmemory.$(OBJ): gsmemory.c $(GX) $(malloc__h) $(memory__h) \
+ $(gsmdebug_h) $(gsrefct_h) $(gsstruct_h) $(gsmemraw_h)
+
+gsmisc.$(OBJ): gsmisc.c $(GXERR) $(gconfigv_h) \
+ $(malloc__h) $(math__h) $(memory__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h)
+
+# gsnogc currently is only used in library-only configurations.
+gsnogc.$(OBJ): gsnogc.c $(GX)\
+ $(gsgc_h) $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsutil.$(OBJ): gsutil.c $(AK) $(memory__h) $(string__h) $(gconfigv_h)\
+ $(gstypes_h) $(gsuid_h) $(gsutil_h)
+
+###### Low-level facilities and utilities
+
+### Include files
+
+gdevbbox_h=gdevbbox.h
+gdevmem_h=gdevmem.h $(gsbitops_h)
+gdevmrop_h=gdevmrop.h
+
+gsccode_h=gsccode.h
+gsccolor_h=gsccolor.h $(gsstruct_h)
+gscsel_h=gscsel.h
+gscolor1_h=gscolor1.h
+gscoord_h=gscoord.h
+gscpm_h=gscpm.h
+gsdevice_h=gsdevice.h
+gsfcmap_h=gsfcmap.h $(gsccode_h)
+gsfont_h=gsfont.h
+gshsb_h=gshsb.h
+gsht_h=gsht.h
+gsht1_h=gsht1.h $(gsht_h)
+gsiparam_h=gsiparam.h
+gsjconf_h=gsjconf.h $(std_h)
+gslib_h=gslib.h
+gslparam_h=gslparam.h
+gsmatrix_h=gsmatrix.h
+gspaint_h=gspaint.h
+gsparam_h=gsparam.h
+gsparams_h=gsparams.h $(gsparam_h)
+gspath2_h=gspath2.h
+gspenum_h=gspenum.h
+gsropt_h=gsropt.h
+gsxfont_h=gsxfont.h
+# Out of order
+gschar_h=gschar.h $(gsccode_h) $(gscpm_h)
+gscolor2_h=gscolor2.h $(gsccolor_h) $(gsuid_h) $(gxbitmap_h)
+gsimage_h=gsimage.h $(gsiparam_h)
+gsline_h=gsline.h $(gslparam_h)
+gspath_h=gspath.h $(gspenum_h)
+gsrop_h=gsrop.h $(gsropt_h)
+
+gxbcache_h=gxbcache.h $(gxbitmap_h)
+gxchar_h=gxchar.h $(gschar_h)
+gxcindex_h=gxcindex.h
+gxcvalue_h=gxcvalue.h
+gxclio_h=gxclio.h
+gxclip2_h=gxclip2.h
+gxcolor2_h=gxcolor2.h $(gscolor2_h) $(gsrefct_h) $(gxbitmap_h)
+gxcoord_h=gxcoord.h $(gscoord_h)
+gxcpath_h=gxcpath.h
+gxdda_h=gxdda.h
+gxdevrop_h=gxdevrop.h
+gxdevmem_h=gxdevmem.h
+gxdither_h=gxdither.h
+gxfcmap_h=gxfcmap.h $(gsfcmap_h) $(gsuid_h)
+gxfont0_h=gxfont0.h
+gxfrac_h=gxfrac.h
+gxftype_h=gxftype.h
+gxhttile_h=gxhttile.h
+gxhttype_h=gxhttype.h
+gxiodev_h=gxiodev.h $(stat__h)
+gxline_h=gxline.h $(gslparam_h)
+gxlum_h=gxlum.h
+gxmatrix_h=gxmatrix.h $(gsmatrix_h)
+gxpaint_h=gxpaint.h
+gxpath_h=gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h)
+gxpcache_h=gxpcache.h
+gxpcolor_h=gxpcolor.h $(gxpcache_h)
+gxsample_h=gxsample.h
+gxstate_h=gxstate.h
+gxtmap_h=gxtmap.h
+gxxfont_h=gxxfont.h $(gsccode_h) $(gsmatrix_h) $(gsuid_h) $(gsxfont_h)
+# The following are out of order because they include other files.
+gsdcolor_h=gsdcolor.h $(gsccolor_h) $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+gxdcolor_h=gxdcolor.h $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gxdevice_h=gxdevice.h $(stdio__h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h) \
+ $(gsropt_h) $(gsstruct_h) $(gsxfont_h) \
+ $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)
+gxdht_h=gxdht.h $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+gxctable_h=gxctable.h $(gxfixed_h) $(gxfrac_h)
+gxfcache_h=gxfcache.h $(gsuid_h) $(gsxfont_h) $(gxbcache_h) $(gxftype_h)
+gxfont_h=gxfont.h $(gsfont_h) $(gsuid_h) $(gsstruct_h) $(gxftype_h)
+gscie_h=gscie.h $(gsrefct_h) $(gxctable_h)
+gscsepr_h=gscsepr.h
+gscspace_h=gscspace.h
+gxdcconv_h=gxdcconv.h $(gxfrac_h)
+gxfmap_h=gxfmap.h $(gsrefct_h) $(gxfrac_h) $(gxtmap_h)
+gxistate_h=gxistate.h $(gscsel_h) $(gsropt_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+gxband_h=gxband.h $(gxclio_h)
+gxclist_h=gxclist.h $(gscspace_h) $(gxbcache_h) $(gxclio_h) $(gxistate_h) $(gxband_h)
+gxcmap_h=gxcmap.h $(gscsel_h) $(gxcvalue_h) $(gxfmap_h)
+gxcspace_h=gxcspace.h $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gsstruct_h) $(gxfrac_h)
+gxht_h=gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gscolor_h=gscolor.h $(gxtmap_h)
+gsstate_h=gsstate.h $(gscolor_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
+
+gzacpath_h=gzacpath.h
+gzcpath_h=gzcpath.h $(gxcpath_h)
+gzht_h=gzht.h $(gscsel_h) $(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
+gzline_h=gzline.h $(gxline_h)
+gzpath_h=gzpath.h $(gsstruct_h) $(gxpath_h)
+gzstate_h=gzstate.h $(gscpm_h) $(gsrefct_h) $(gsstate_h)\
+ $(gxdcolor_h) $(gxistate_h) $(gxstate_h)
+
+gdevprn_h=gdevprn.h $(memory__h) $(string__h) $(gx_h) \
+ $(gserrors_h) $(gsmatrix_h) $(gsparam_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxdevmem_h) $(gxclist_h)
+
+sa85x_h=sa85x.h
+sbtx_h=sbtx.h
+scanchar_h=scanchar.h
+scommon_h=scommon.h $(gsmemory_h) $(gstypes_h) $(gsstruct_h)
+sdct_h=sdct.h
+shc_h=shc.h $(gsbittab_h)
+siscale_h=siscale.h $(gconfigv_h)
+sjpeg_h=sjpeg.h
+slzwx_h=slzwx.h
+spcxx_h=spcxx.h
+spdiffx_h=spdiffx.h
+spngpx_h=spngpx.h
+srlx_h=srlx.h
+sstring_h=sstring.h
+strimpl_h=strimpl.h $(scommon_h) $(gstypes_h) $(gsstruct_h)
+szlibx_h=szlibx.h
+# Out of order
+scf_h=scf.h $(shc_h)
+scfx_h=scfx.h $(shc_h)
+gximage_h=gximage.h $(gsiparam_h) $(gxcspace_h) $(gxdda_h) $(gxsample_h)\
+ $(siscale_h) $(strimpl_h)
+
+### Executable code
+
+# gconfig and gscdefs are handled specially. Currently they go in psbase
+# rather than in libcore, which is clearly wrong.
+gconfig=gconfig$(CONFIG)
+$(gconfig).$(OBJ): gconf.c $(GX) \
+ $(gscdefs_h) $(gconfig_h) $(gxdevice_h) $(gxiodev_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gconf.c $(gconfig).c
+ $(CCC) $(gconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+
+gscdefs=gscdefs$(CONFIG)
+$(gscdefs).$(OBJ): gscdef.c $(stdpre_h) $(gscdefs_h) $(gconfig_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gscdef.c $(gscdefs).c
+ $(CCC) $(gscdefs).c
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+
+gxacpath.$(OBJ): gxacpath.c $(GXERR) \
+ $(gsdcolor_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxpaint_h) \
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)
+
+gxbcache.$(OBJ): gxbcache.c $(GX) $(memory__h) \
+ $(gsmdebug_h) $(gxbcache_h)
+
+gxccache.$(OBJ): gxccache.c $(GXERR) $(gpcheck_h) \
+ $(gscspace_h) $(gsimage_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxdevmem_h) $(gxfcache_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxhttile_h) $(gxmatrix_h) $(gxxfont_h) \
+ $(gzstate_h) $(gzpath_h) $(gzcpath_h)
+
+gxccman.$(OBJ): gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfont_h) $(gxfcache_h) $(gxchar_h)\
+ $(gxxfont_h) $(gzstate_h) $(gzpath_h)
+
+gxcht.$(OBJ): gxcht.c $(GXERR) $(memory__h)\
+ $(gsutil_h)\
+ $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h)\
+ $(gxmatrix_h) $(gzht_h)
+
+gxcmap.$(OBJ): gxcmap.c $(GXERR) \
+ $(gsccolor_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gxdither_h) \
+ $(gxfarith_h) $(gxfrac_h) $(gxlum_h) $(gzstate_h)
+
+gxcpath.$(OBJ): gxcpath.c $(GXERR)\
+ $(gscoord_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gzpath_h) $(gzcpath_h)
+
+gxdcconv.$(OBJ): gxdcconv.c $(GX) \
+ $(gsdcolor_h) $(gxcmap_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gxfarith_h) $(gxistate_h) $(gxlum_h)
+
+gxdcolor.$(OBJ): gxdcolor.c $(GX) \
+ $(gsbittab_h) $(gxdcolor_h) $(gxdevice_h)
+
+gxdither.$(OBJ): gxdither.c $(GX) \
+ $(gsstruct_h) $(gsdcolor_h) \
+ $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
+
+gxfill.$(OBJ): gxfill.c $(GXERR) $(math__h) \
+ $(gsstruct_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h) \
+ $(gxistate_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+gxht.$(OBJ): gxht.c $(GXERR) $(memory__h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+
+gximage.$(OBJ): gximage.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h) $(gsstruct_h)\
+ $(gxfixed_h) $(gxfrac_h) $(gxarith_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gzpath_h) $(gzstate_h)\
+ $(gzcpath_h) $(gxdevmem_h) $(gximage_h) $(gdevmrop_h)
+
+gximage0.$(OBJ): gximage0.c $(GXERR) $(memory__h)\
+ $(gxcpath_h) $(gxdevice_h) $(gximage_h)
+
+gximage1.$(OBJ): gximage1.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsbittab_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gximage2.$(OBJ): gximage2.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gxpaint.$(OBJ): gxpaint.c $(GX) \
+ $(gxdevice_h) $(gxhttile_h) $(gxpaint_h) $(gxpath_h) $(gzstate_h)
+
+gxpath.$(OBJ): gxpath.c $(GXERR) \
+ $(gsstruct_h) $(gxfixed_h) $(gzpath_h)
+
+gxpath2.$(OBJ): gxpath2.c $(GXERR) $(math__h) \
+ $(gxfixed_h) $(gxarith_h) $(gzpath_h)
+
+gxpcopy.$(OBJ): gxpcopy.c $(GXERR) $(math__h) $(gconfigv_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxpdash.$(OBJ): gxpdash.c $(GX) $(math__h) \
+ $(gscoord_h) $(gsline_h) $(gsmatrix_h) \
+ $(gxfixed_h) $(gzline_h) $(gzpath_h)
+
+gxpflat.$(OBJ): gxpflat.c $(GX)\
+ $(gxarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxsample.$(OBJ): gxsample.c $(GX)\
+ $(gxsample_h)
+
+gxstroke.$(OBJ): gxstroke.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gscoord_h) $(gsdcolor_h) $(gsdevice_h) \
+ $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) \
+ $(gxhttile_h) $(gxistate_h) $(gxmatrix_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzline_h) $(gzpath_h)
+
+###### Higher-level facilities
+
+gschar.$(OBJ): gschar.c $(GXERR) $(memory__h) $(string__h)\
+ $(gspath_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxarith_h) $(gxmatrix_h) $(gxcoord_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxfcache_h) $(gzpath_h) $(gzstate_h)
+
+gscolor.$(OBJ): gscolor.c $(GXERR) \
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
+
+gscoord.$(OBJ): gscoord.c $(GXERR) $(math__h) \
+ $(gsccode_h) $(gxcoord_h) $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) $(gxfont_h) \
+ $(gxmatrix_h) $(gxpath_h) $(gzstate_h)
+
+gsdevice.$(OBJ): gsdevice.c $(GXERR) $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
+ $(gscdefs_h) $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstruct_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gzstate_h)
+
+gsdevmem.$(OBJ): gsdevmem.c $(GXERR) $(math__h) $(memory__h) \
+ $(gxarith_h) $(gxdevice_h) $(gxdevmem_h)
+
+gsdparam.$(OBJ): gsdparam.c $(GXERR) $(memory__h) $(string__h) \
+ $(gsparam_h) $(gxdevice_h) $(gxfixed_h)
+
+gsfont.$(OBJ): gsfont.c $(GXERR) $(memory__h)\
+ $(gschar_h) $(gsstruct_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)
+
+gsht.$(OBJ): gsht.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gshtscr.$(OBJ): gshtscr.c $(GXERR) $(math__h) \
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gsimage.$(OBJ): gsimage.c $(GXERR) $(memory__h)\
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxdevice_h) $(gzstate_h)
+
+gsimpath.$(OBJ): gsimpath.c $(GXERR) \
+ $(gsmatrix_h) $(gsstate_h) $(gspath_h)
+
+gsinit.$(OBJ): gsinit.c $(memory__h) $(stdio__h) \
+ $(gdebug_h) $(gp_h) $(gscdefs_h) $(gslib_h) $(gsmemory_h)
+
+gsiodev.$(OBJ): gsiodev.c $(GXERR) $(errno__h) $(string__h) \
+ $(gp_h) $(gsparam_h) $(gxiodev_h)
+
+gsline.$(OBJ): gsline.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsline_h) $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gzline_h)
+
+gsmatrix.$(OBJ): gsmatrix.c $(GXERR) $(math__h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h)
+
+gspaint.$(OBJ): gspaint.c $(GXERR) $(math__h) $(gpcheck_h)\
+ $(gspaint_h) $(gspath_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdevmem_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxpaint_h)\
+ $(gzpath_h) $(gzstate_h)
+
+gsparam.$(OBJ): gsparam.c $(GXERR) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsstruct_h)
+
+gsparams.$(OBJ): gsparams.c $(gx_h) $(memory__h) $(gserrors_h) $(gsparam_h)
+
+gspath.$(OBJ): gspath.c $(GXERR) \
+ $(gscoord_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+gsstate.$(OBJ): gsstate.c $(GXERR) $(memory__h)\
+ $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h) \
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+
+###### The internal devices
+
+### The built-in device implementations:
+
+# The bounding box device is not normally a free-standing device.
+# To configure it as one for testing, change SETMOD to SETDEV, and also
+# define TEST in gdevbbox.c.
+bbox.dev: $(LIB_MAK) $(ECHOGS_XE) gdevbbox.$(OBJ)
+ $(SETMOD) bbox gdevbbox.$(OBJ)
+
+gdevbbox.$(OBJ): gdevbbox.c $(GXERR) $(math__h) $(memory__h) \
+ $(gdevbbox_h) $(gsdevice_h) $(gsparam_h) \
+ $(gxcpath_h) $(gxdevice_h) $(gxistate_h) $(gxpaint_h) $(gxpath_h)
+
+gdevddrw.$(OBJ): gdevddrw.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h)
+
+gdevdflt.$(OBJ): gdevdflt.c $(GXERR) $(gpcheck_h)\
+ $(gsbittab_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)
+
+gdevnfwd.$(OBJ): gdevnfwd.c $(GX) \
+ $(gxdevice_h)
+
+# The render/RGB device is only here as an example, but we can configure
+# it as a real device for testing.
+rrgb.dev: $(LIB_MAK) $(ECHOGS_XE) gdevrrgb.$(OBJ) page.dev
+ $(SETPDEV) rrgb gdevrrgb.$(OBJ)
+
+gdevrrgb.$(OBJ): gdevrrgb.c $(AK)\
+ $(gdevprn_h)
+
+### The memory devices:
+
+gdevabuf.$(OBJ): gdevabuf.c $(GXERR) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmem.$(OBJ): gdevmem.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm1.$(OBJ): gdevm1.c $(GX) $(memory__h) $(gsrop_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm2.$(OBJ): gdevm2.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm4.$(OBJ): gdevm4.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm8.$(OBJ): gdevm8.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm16.$(OBJ): gdevm16.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm24.$(OBJ): gdevm24.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm32.$(OBJ): gdevm32.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmpla.$(OBJ): gdevmpla.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+# Create a pseudo-"feature" for the entire graphics library.
+
+LIB1s=gsalloc.$(OBJ) gsbitops.$(OBJ) gsbittab.$(OBJ)
+LIB2s=gschar.$(OBJ) gscolor.$(OBJ) gscoord.$(OBJ) gsdevice.$(OBJ) gsdevmem.$(OBJ)
+LIB3s=gsdparam.$(OBJ) gsfont.$(OBJ) gsht.$(OBJ) gshtscr.$(OBJ)
+LIB4s=gsimage.$(OBJ) gsimpath.$(OBJ) gsinit.$(OBJ) gsiodev.$(OBJ)
+LIB5s=gsline.$(OBJ) gsmatrix.$(OBJ) gsmemory.$(OBJ) gsmisc.$(OBJ)
+LIB6s=gspaint.$(OBJ) gsparam.$(OBJ) gsparams.$(OBJ) gspath.$(OBJ) gsstate.$(OBJ) gsutil.$(OBJ)
+LIB1x=gxacpath.$(OBJ) gxbcache.$(OBJ)
+LIB2x=gxccache.$(OBJ) gxccman.$(OBJ) gxcht.$(OBJ) gxcmap.$(OBJ) gxcpath.$(OBJ)
+LIB3x=gxdcconv.$(OBJ) gxdcolor.$(OBJ) gxdither.$(OBJ) gxfill.$(OBJ) gxht.$(OBJ)
+LIB4x=gximage.$(OBJ) gximage0.$(OBJ) gximage1.$(OBJ) gximage2.$(OBJ)
+LIB5x=gxpaint.$(OBJ) gxpath.$(OBJ) gxpath2.$(OBJ) gxpcopy.$(OBJ)
+LIB6x=gxpdash.$(OBJ) gxpflat.$(OBJ) gxsample.$(OBJ) gxstroke.$(OBJ)
+LIB1d=gdevabuf.$(OBJ) gdevddrw.$(OBJ) gdevdflt.$(OBJ) gdevnfwd.$(OBJ)
+LIB2d=gdevmem.$(OBJ) gdevm1.$(OBJ) gdevm2.$(OBJ) gdevm4.$(OBJ) gdevm8.$(OBJ)
+LIB3d=gdevm16.$(OBJ) gdevm24.$(OBJ) gdevm32.$(OBJ) gdevmpla.$(OBJ)
+LIBs=$(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s)
+LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d)
+LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
+libs.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBs)
+ $(EXP)echogs -w libs.dev $(LIB1s)
+ $(EXP)echogs -a libs.dev $(LIB2s)
+ $(EXP)echogs -a libs.dev $(LIB3s)
+ $(EXP)echogs -a libs.dev $(LIB4s)
+ $(EXP)echogs -a libs.dev $(LIB5s)
+ $(EXP)echogs -a libs.dev $(LIB6s)
+ $(ADDMOD) libs -init gscolor
+
+libx.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBx)
+ $(EXP)echogs -w libx.dev $(LIB1x)
+ $(EXP)echogs -a libx.dev $(LIB2x)
+ $(EXP)echogs -a libx.dev $(LIB3x)
+ $(EXP)echogs -a libx.dev $(LIB4x)
+ $(EXP)echogs -a libx.dev $(LIB5x)
+ $(EXP)echogs -a libx.dev $(LIB6x)
+ $(ADDMOD) libx -init gximage1 gximage2
+
+libd.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBd)
+ $(EXP)echogs -w libd.dev $(LIB1d)
+ $(EXP)echogs -a libd.dev $(LIB2d)
+ $(EXP)echogs -a libd.dev $(LIB3d)
+
+# roplib shouldn't be required....
+libcore.dev: $(LIB_MAK) $(ECHOGS_XE)\
+ libs.dev libx.dev libd.dev iscale.dev roplib.dev
+ $(SETMOD) libcore
+ $(ADDMOD) libcore -dev nullpage
+ $(ADDMOD) libcore -include libs libx libd iscale roplib
+
+# ---------------- Stream support ---------------- #
+# Currently the only things in the library that use this are clists
+# and file streams.
+
+stream_h=stream.h $(scommon_h)
+
+stream.$(OBJ): stream.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+# ---------------- File streams ---------------- #
+# Currently only the high-level drivers use these, but more drivers will
+# probably use them eventually.
+
+sfile_=sfx$(FILE_IMPLEMENTATION).$(OBJ) stream.$(OBJ)
+sfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(sfile_)
+ $(SETMOD) sfile $(sfile_)
+
+sfxstdio.$(OBJ): sfxstdio.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxfd.$(OBJ): sfxfd.c $(AK) $(stdio__h) $(errno__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxboth.$(OBJ): sfxboth.c sfxstdio.c sfxfd.c
+
+# ---------------- CCITTFax filters ---------------- #
+# These are used by clists, some drivers, and Level 2 in general.
+
+cfe_=scfe.$(OBJ) scfetab.$(OBJ) shc.$(OBJ)
+cfe.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfe_)
+ $(SETMOD) cfe $(cfe_)
+
+scfe.$(OBJ): scfe.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfetab.$(OBJ): scfetab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+shc.$(OBJ): shc.c $(AK) $(std_h) $(scommon_h) $(shc_h)
+
+cfd_=scfd.$(OBJ) scfdtab.$(OBJ)
+cfd.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfd_)
+ $(SETMOD) cfd $(cfd_)
+
+scfd.$(OBJ): scfd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfdtab.$(OBJ): scfdtab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+# ---------------- DCT (JPEG) filters ---------------- #
+# These are used by Level 2, and by the JPEG-writing driver.
+
+# Common code
+
+sdctc_=sdctc.$(OBJ) sjpegc.$(OBJ)
+
+sdctc.$(OBJ): sdctc.c $(AK) $(stdio__h)\
+ $(sdct_h) $(strimpl_h)\
+ jpeglib.h
+
+sjpegc.$(OBJ): sjpegc.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Encoding (compression)
+
+sdcte_=$(sdctc_) sdcte.$(OBJ) sjpege.$(OBJ)
+sdcte.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdcte_) jpege.dev
+ $(SETMOD) sdcte $(sdcte_)
+ $(ADDMOD) sdcte -include jpege
+
+sdcte.$(OBJ): sdcte.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpege.$(OBJ): sjpege.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Decoding (decompression)
+
+sdctd_=$(sdctc_) sdctd.$(OBJ) sjpegd.$(OBJ)
+sdctd.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdctd_) jpegd.dev
+ $(SETMOD) sdctd $(sdctd_)
+ $(ADDMOD) sdctd -include jpegd
+
+sdctd.$(OBJ): sdctd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpegd.$(OBJ): sjpegd.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h)\
+ jerror.h jpeglib.h
+
+# ---------------- LZW filters ---------------- #
+# These are used by Level 2 in general.
+
+slzwe_=slzwce
+#slzwe_=slzwe
+lzwe_=$(slzwe_).$(OBJ) slzwc.$(OBJ)
+lzwe.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwe_)
+ $(SETMOD) lzwe $(lzwe_)
+
+# We need slzwe.dev as a synonym for lzwe.dev for BAND_LIST_STORAGE = memory.
+slzwe.dev: lzwe.dev
+ $(CP_) lzwe.dev slzwe.dev
+
+slzwce.$(OBJ): slzwce.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwe.$(OBJ): slzwe.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwc.$(OBJ): slzwc.c $(AK) $(std_h)\
+ $(slzwx_h) $(strimpl_h)
+
+lzwd_=slzwd.$(OBJ) slzwc.$(OBJ)
+lzwd.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwd_)
+ $(SETMOD) lzwd $(lzwd_)
+
+# We need slzwd.dev as a synonym for lzwd.dev for BAND_LIST_STORAGE = memory.
+slzwd.dev: lzwd.dev
+ $(CP_) lzwd.dev slzwd.dev
+
+slzwd.$(OBJ): slzwd.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+# ---------------- PCX decoding filter ---------------- #
+# This is an adhoc filter not used by anything in the standard configuration.
+
+pcxd_=spcxd.$(OBJ)
+pcxd.dev: $(LIB_MAK) $(ECHOGS_XE) $(pcxd_)
+ $(SETMOD) pcxd $(pcxd_)
+
+spcxd.$(OBJ): spcxd.c $(AK) $(stdio__h) $(memory__h) \
+ $(spcxx_h) $(strimpl_h)
+
+# ---------------- Pixel-difference filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pdiff_=spdiff.$(OBJ)
+pdiff.dev: $(LIB_MAK) $(ECHOGS_XE) $(pdiff_)
+ $(SETMOD) pdiff $(pdiff_)
+
+spdiff.$(OBJ): spdiff.c $(AK) $(stdio__h)\
+ $(spdiffx_h) $(strimpl_h)
+
+# ---------------- PNG pixel prediction filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pngp_=spngp.$(OBJ)
+pngp.dev: $(LIB_MAK) $(ECHOGS_XE) $(pngp_)
+ $(SETMOD) pngp $(pngp_)
+
+spngp.$(OBJ): spngp.c $(AK) $(memory__h)\
+ $(spngpx_h) $(strimpl_h)
+
+# ---------------- RunLength filters ---------------- #
+# These are used by clists and also by Level 2 in general.
+
+rle_=srle.$(OBJ)
+rle.dev: $(LIB_MAK) $(ECHOGS_XE) $(rle_)
+ $(SETMOD) rle $(rle_)
+
+srle.$(OBJ): srle.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+rld_=srld.$(OBJ)
+rld.dev: $(LIB_MAK) $(ECHOGS_XE) $(rld_)
+ $(SETMOD) rld $(rld_)
+
+srld.$(OBJ): srld.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+# ---------------- String encoding/decoding filters ---------------- #
+# These are used by the PostScript and PDF writers, and also by the
+# PostScript interpreter.
+
+scantab.$(OBJ): scantab.c $(AK) $(stdpre_h)\
+ $(scanchar_h) $(scommon_h)
+
+sfilter2.$(OBJ): sfilter2.c $(AK) $(memory__h) $(stdio__h)\
+ $(sa85x_h) $(scanchar_h) $(sbtx_h) $(strimpl_h)
+
+sstring.$(OBJ): sstring.c $(AK) $(stdio__h) $(memory__h) $(string__h)\
+ $(scanchar_h) $(sstring_h) $(strimpl_h)
+
+# ---------------- zlib filters ---------------- #
+# These are used by clists and are also available as filters.
+
+szlibc_=szlibc.$(OBJ)
+
+szlibc.$(OBJ): szlibc.c $(AK) $(std_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibc.c
+
+szlibe_=$(szlibc_) szlibe.$(OBJ)
+szlibe.dev: $(LIB_MAK) $(ECHOGS_XE) zlibe.dev $(szlibe_)
+ $(SETMOD) szlibe $(szlibe_)
+ $(ADDMOD) szlibe -include zlibe
+
+szlibe.$(OBJ): szlibe.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibe.c
+
+szlibd_=$(szlibc_) szlibd.$(OBJ)
+szlibd.dev: $(LIB_MAK) $(ECHOGS_XE) zlibd.dev $(szlibd_)
+ $(SETMOD) szlibd $(szlibd_)
+ $(ADDMOD) szlibd -include zlibd
+
+szlibd.$(OBJ): szlibd.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibd.c
+
+# ---------------- Command lists ---------------- #
+
+gxcldev_h=gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
+ $(strimpl_h) $(scfx_h) $(srlx_h)
+gxclpage_h=gxclpage.h $(gxclio_h)
+gxclpath_h=gxclpath.h $(gxfixed_h)
+
+# Command list package. Currently the higher-level facilities are required,
+# but eventually they will be optional.
+clist.dev: $(LIB_MAK) $(ECHOGS_XE) clbase.dev clpath.dev
+ $(SETMOD) clist -include clbase clpath
+
+# Base command list facility.
+clbase1_=gxclist.$(OBJ) gxclbits.$(OBJ) gxclpage.$(OBJ)
+clbase2_=gxclread.$(OBJ) gxclrect.$(OBJ) stream.$(OBJ)
+clbase_=$(clbase1_) $(clbase2_)
+clbase.dev: $(LIB_MAK) $(ECHOGS_XE) $(clbase_) cl$(BAND_LIST_STORAGE).dev \
+ cfe.dev cfd.dev rle.dev rld.dev
+ $(SETMOD) clbase $(clbase1_)
+ $(ADDMOD) clbase -obj $(clbase2_)
+ $(ADDMOD) clbase -include cl$(BAND_LIST_STORAGE) cfe cfd rle rld
+
+gdevht_h=gdevht.h $(gzht_h)
+
+gdevht.$(OBJ): gdevht.c $(GXERR) \
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+
+gxclist.$(OBJ): gxclist.c $(GXERR) $(memory__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)
+
+gxclbits.$(OBJ): gxclbits.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h)
+
+gxclpage.$(OBJ): gxclpage.c $(AK)\
+ $(gdevprn_h) $(gxcldev_h) $(gxclpage_h)
+
+# (gxclread shouldn't need gxclpath.h)
+gxclread.$(OBJ): gxclread.c $(GXERR) $(memory__h) $(gp_h) $(gpcheck_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscoord_h) $(gsdevice_h) $(gsstate_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcspace_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)\
+ $(gxhttile_h) $(gxpaint_h) $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h)
+
+gxclrect.$(OBJ): gxclrect.c $(GXERR)\
+ $(gsutil_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h)
+
+# Higher-level command list facilities.
+clpath_=gxclimag.$(OBJ) gxclpath.$(OBJ)
+clpath.dev: $(LIB_MAK) $(ECHOGS_XE) $(clpath_) psl2cs.dev
+ $(SETMOD) clpath $(clpath_)
+ $(ADDMOD) clpath -include psl2cs
+ $(ADDMOD) clpath -init climag clpath
+
+gxclimag.$(OBJ): gxclimag.c $(GXERR) $(math__h) $(memory__h)\
+ $(gscspace_h)\
+ $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpath_h) $(gxfmap_h)\
+ $(siscale_h) $(strimpl_h)
+
+gxclpath.$(OBJ): gxclpath.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcolor2_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+# Implement band lists on files.
+
+clfile_=gxclfile.$(OBJ)
+clfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
+ $(SETMOD) clfile $(clfile_)
+
+gxclfile.$(OBJ): gxclfile.c $(stdio__h) $(string__h) \
+ $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
+
+# Implement band lists in memory (RAM).
+
+clmemory_=gxclmem.$(OBJ) gxcl$(BAND_LIST_COMPRESSOR).$(OBJ)
+clmemory.dev: $(LIB_MAK) $(ECHOGS_XE) $(clmemory_) s$(BAND_LIST_COMPRESSOR)e.dev s$(BAND_LIST_COMPRESSOR)d.dev
+ $(SETMOD) clmemory $(clmemory_)
+ $(ADDMOD) clmemory -include s$(BAND_LIST_COMPRESSOR)e s$(BAND_LIST_COMPRESSOR)d
+ $(ADDMOD) clmemory -init cl_$(BAND_LIST_COMPRESSOR)
+
+gxclmem_h=gxclmem.h $(gxclio_h) $(strimpl_h)
+
+gxclmem.$(OBJ): gxclmem.c $(GXERR) $(LIB_MAK) $(memory__h) \
+ $(gxclmem_h)
+
+# Implement the compression method for RAM-based band lists.
+
+gxcllzw.$(OBJ): gxcllzw.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(slzwx_h)
+
+gxclzlib.$(OBJ): gxclzlib.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(szlibx_h)
+ $(CCCZ) gxclzlib.c
+
+# ---------------- Page devices ---------------- #
+# We include this here, rather than in devs.mak, because it is more like
+# a feature than a simple device.
+
+page_=gdevprn.$(OBJ)
+page.dev: $(LIB_MAK) $(ECHOGS_XE) $(page_) clist.dev
+ $(SETMOD) page $(page_)
+ $(ADDMOD) page -include clist
+
+gdevprn.$(OBJ): gdevprn.c $(ctype__h) \
+ $(gdevprn_h) $(gp_h) $(gsparam_h) $(gxclio_h)
+
+# ---------------- Vector devices ---------------- #
+# We include this here for the same reasons as page.dev.
+
+gdevvec_h=gdevvec.h $(gdevbbox_h) $(gsropt_h) $(gxdevice_h) $(gxistate_h) $(stream_h)
+
+vector_=gdevvec.$(OBJ)
+vector.dev: $(LIB_MAK) $(ECHOGS_XE) $(vector_) bbox.dev sfile.dev
+ $(SETMOD) vector $(vector_)
+ $(ADDMOD) vector -include bbox sfile
+
+gdevvec.$(OBJ): gdevvec.c $(GXERR) $(math__h) $(memory__h) $(string__h)\
+ $(gdevvec_h) $(gp_h) $(gscspace_h) $(gsparam_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxfixed_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+# ---------------- Image scaling filter ---------------- #
+
+iscale_=siscale.$(OBJ)
+iscale.dev: $(LIB_MAK) $(ECHOGS_XE) $(iscale_)
+ $(SETMOD) iscale $(iscale_)
+
+siscale.$(OBJ): siscale.c $(AK) $(math__h) $(memory__h) $(stdio__h) \
+ $(siscale_h) $(strimpl_h)
+
+# ---------------- RasterOp et al ---------------- #
+# Currently this module is required, but it should be optional.
+
+roplib_=gdevmrop.$(OBJ) gsrop.$(OBJ) gsroptab.$(OBJ)
+roplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(roplib_)
+ $(SETMOD) roplib $(roplib_)
+ $(ADDMOD) roplib -init roplib
+
+gdevrun.$(OBJ): gdevrun.c $(GXERR) $(memory__h) \
+ $(gxdevice_h) $(gxdevmem_h)
+
+gdevmrop.$(OBJ): gdevmrop.c $(GXERR) $(memory__h) \
+ $(gsbittab_h) $(gsropt_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) \
+ $(gdevmrop_h)
+
+gsrop.$(OBJ): gsrop.c $(GXERR) \
+ $(gsrop_h) $(gzstate_h)
+
+gsroptab.$(OBJ): gsroptab.c $(stdpre_h) $(gsropt_h)
+ $(CCLEAF) gsroptab.c
+
+# ---------------- Async rendering ---------------- #
+
+gsmemfix_h=gsmemfix.h $(gsmemraw_h)
+gxsync_h=gxsync.h $(gpsync_h) $(gsmemory_h)
+gxpageq_h=gxpageq.h $(gsmemory_h) $(gxband_h) $(gxsync_h)
+gsmemlok_h=gsmemlok.h $(gsmemory_h) $(gxsync_h)
+gdevprna_h=gdevprna.h $(gdevprn_h) $(gxsync_h)
+
+async_=gdevprna.$(OBJ) gxsync.$(OBJ) gxpageq.$(OBJ) gsmemlok.$(OBJ)\
+ gsmemfix.$(OBJ)
+async.dev: $(INT_MAK) $(ECHOGS_XE) $(async_) clist.dev
+ $(SETMOD) async $(async_)
+
+gdevprna.$(OBJ): gdevprna.c $(AK) $(ctype__h) $(gdevprna_h) $(gsparam_h)\
+ $(gsdevice_h) $(gxcldev_h) $(gxclpath_h) $(gxpageq_h) $(gsmemory_h)\
+ $(gsmemlok_h) $(gsmemfix_h)
+
+gsmemfix.$(OBJ): gsmemfix.c $(AK) $(memory__h) $(gsmemraw_h) $(gsmemfix_h)
+
+gxsync.$(OBJ): gxsync.c $(AK) $(gxsync_h) $(memory__h) $(gx_h) $(gserrors_h)\
+ $(gsmemory_h)
+
+gxpageq.$(OBJ): gxpageq.c $(GXERR) $(gxdevice_h) $(gxclist_h)\
+ $(gxpageq_h) $(gserrors_h)
+
+gsmemlok.$(OBJ): gsmemlok.c $(GXERR) $(gsmemlok_h) $(gserrors_h)
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+cmaplib_=gsfcmap.$(OBJ)
+cmaplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmaplib_)
+ $(SETMOD) cmaplib $(cmaplib_)
+
+gsfcmap.$(OBJ): gsfcmap.c $(GXERR)\
+ $(gsstruct_h) $(gxfcmap_h)
+
+psf0lib_=gschar0.$(OBJ) gsfont0.$(OBJ)
+psf0lib.dev: $(LIB_MAK) $(ECHOGS_XE) cmaplib.dev $(psf0lib_)
+ $(SETMOD) psf0lib $(psf0lib_)
+ $(ADDMOD) psf0lib -include cmaplib
+
+gschar0.$(OBJ): gschar0.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxfixed_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gsfcmap_h) $(gxfont_h) $(gxfont0_h) $(gxchar_h)
+
+gsfont0.$(OBJ): gsfont0.c $(GXERR) $(memory__h)\
+ $(gsmatrix_h) $(gsstruct_h) $(gxfixed_h) $(gxdevmem_h) $(gxfcache_h)\
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxdevice_h)
+
+# ---------------- Pattern color ---------------- #
+
+patlib_=gspcolor.$(OBJ) gxclip2.$(OBJ) gxpcmap.$(OBJ)
+patlib.dev: $(LIB_MAK) $(ECHOGS_XE) cmyklib.dev psl2cs.dev $(patlib_)
+ $(SETMOD) patlib -include cmyklib psl2cs
+ $(ADDMOD) patlib -obj $(patlib_)
+
+gspcolor.$(OBJ): gspcolor.c $(GXERR) $(math__h) \
+ $(gsimage_h) $(gspath_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcoord_h) $(gxclip2_h) $(gxcspace_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfixed_h) $(gxmatrix_h) $(gxpath_h) $(gxpcolor_h) $(gzstate_h)
+
+gxclip2.$(OBJ): gxclip2.c $(GXERR) $(memory__h) \
+ $(gsstruct_h) $(gxclip2_h) $(gxdevice_h) $(gxdevmem_h)
+
+gxpcmap.$(OBJ): gxpcmap.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h)\
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1lib_=gxtype1.$(OBJ) gxhint1.$(OBJ) gxhint2.$(OBJ) gxhint3.$(OBJ)
+
+gscrypt1_h=gscrypt1.h
+gstype1_h=gstype1.h
+gxfont1_h=gxfont1.h
+gxop1_h=gxop1.h
+gxtype1_h=gxtype1.h $(gscrypt1_h) $(gstype1_h) $(gxop1_h)
+
+gxtype1.$(OBJ): gxtype1.c $(GXERR) $(math__h)\
+ $(gsccode_h) $(gsline_h) $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+gxhint1.$(OBJ): gxhint1.c $(GXERR)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint2.$(OBJ): gxhint2.c $(GXERR) $(memory__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint3.$(OBJ): gxhint3.c $(GXERR) $(math__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 1 charstrings
+
+psf1lib_=gstype1.$(OBJ)
+psf1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf1lib_) $(type1lib_)
+ $(SETMOD) psf1lib $(psf1lib_)
+ $(ADDMOD) psf1lib $(type1lib_)
+ $(ADDMOD) psf1lib -init gstype1
+
+gstype1.$(OBJ): gstype1.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 2 charstrings
+
+psf2lib_=gstype2.$(OBJ)
+psf2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf2lib_) $(type1lib_)
+ $(SETMOD) psf2lib $(psf2lib_)
+ $(ADDMOD) psf2lib $(type1lib_)
+ $(ADDMOD) psf2lib -init gstype2
+
+gstype2.$(OBJ): gstype2.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+ttflib_=gstype42.$(OBJ)
+ttflib.dev: $(LIB_MAK) $(ECHOGS_XE) $(ttflib_)
+ $(SETMOD) ttflib $(ttflib_)
+
+gxfont42_h=gxfont42.h
+
+gstype42.$(OBJ): gstype42.c $(GXERR) $(memory__h) \
+ $(gsccode_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont42_h) $(gxistate_h) $(gxpath_h)
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+cmyklib_=gscolor1.$(OBJ) gsht1.$(OBJ)
+cmyklib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmyklib_)
+ $(SETMOD) cmyklib $(cmyklib_)
+ $(ADDMOD) cmyklib -init gscolor1
+
+gscolor1.$(OBJ): gscolor1.c $(GXERR) \
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gzstate_h)
+
+gsht1.$(OBJ): gsht1.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+colimlib_=gximage3.$(OBJ)
+colimlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(colimlib_)
+ $(SETMOD) colimlib $(colimlib_)
+ $(ADDMOD) colimlib -init gximage3
+
+gximage3.$(OBJ): gximage3.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcconv_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h)\
+ $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzpath_h) $(gzstate_h)
+
+# ---------------- HSB color ---------------- #
+
+hsblib_=gshsb.$(OBJ)
+hsblib.dev: $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
+ $(SETMOD) hsblib $(hsblib_)
+
+gshsb.$(OBJ): gshsb.c $(GX) \
+ $(gscolor_h) $(gshsb_h) $(gxfrac_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1lib_=gspath1.$(OBJ)
+path1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(path1lib_)
+ $(SETMOD) path1lib $(path1lib_)
+
+gspath1.$(OBJ): gspath1.c $(GXERR) $(math__h) \
+ $(gscoord_h) $(gspath_h) $(gsstruct_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) $(gzpath_h)
+
+# --------------- Level 2 color space and color image support --------------- #
+
+psl2cs_=gscolor2.$(OBJ)
+psl2cs.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2cs_)
+ $(SETMOD) psl2cs $(psl2cs_)
+
+gscolor2.$(OBJ): gscolor2.c $(GXERR) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h)
+
+psl2lib_=gximage4.$(OBJ) gximage5.$(OBJ)
+psl2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2lib_) colimlib.dev psl2cs.dev
+ $(SETMOD) psl2lib $(psl2lib_)
+ $(ADDMOD) psl2lib -init gximage4 gximage5
+ $(ADDMOD) psl2lib -include colimlib psl2cs
+
+gximage4.$(OBJ): gximage4.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+gximage5.$(OBJ): gximage5.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+# ---------------- Display Postscript / Level 2 support ---------------- #
+
+dps2lib_=gsdps1.$(OBJ)
+dps2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dps2lib_)
+ $(SETMOD) dps2lib $(dps2lib_)
+
+gsdps1.$(OBJ): gsdps1.c $(GXERR) $(math__h)\
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gspath2_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- Display Postscript extensions ---------------- #
+
+gsdps_h=gsdps.h
+
+dpslib_=gsdps.$(OBJ)
+dpslib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dpslib_)
+ $(SETMOD) dpslib $(dpslib_)
+
+gsdps.$(OBJ): gsdps.c $(GX) $(gsdps_h)\
+ $(gsdps_h) $(gspath_h) $(gxdevice_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- CIE color ---------------- #
+
+cielib_=gscie.$(OBJ) gxctable.$(OBJ)
+cielib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cielib_)
+ $(SETMOD) cielib $(cielib_)
+
+gscie.$(OBJ): gscie.c $(GXERR) $(math__h) \
+ $(gscie_h) $(gscolor2_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gzstate_h)
+
+gxctable.$(OBJ): gxctable.c $(GX) \
+ $(gxfixed_h) $(gxfrac_h) $(gxctable_h)
+
+# ---------------- Separation colors ---------------- #
+
+seprlib_=gscsepr.$(OBJ)
+seprlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(seprlib_)
+ $(SETMOD) seprlib $(seprlib_)
+
+gscsepr.$(OBJ): gscsepr.c $(GXERR)\
+ $(gscsepr_h) $(gsmatrix_h) $(gsrefct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+
+# ---------------- Functions ---------------- #
+
+gsdsrc_h=gsdsrc.h $(gsstruct_h)
+gsfunc_h=gsfunc.h
+gsfunc0_h=gsfunc0.h $(gsdsrc_h) $(gsfunc_h)
+gxfunc_h=gxfunc.h $(gsfunc_h) $(gsstruct_h)
+
+# Generic support, and FunctionType 0.
+funclib_=gsdsrc.$(OBJ) gsfunc.$(OBJ) gsfunc0.$(OBJ)
+funclib.dev: $(LIB_MAK) $(ECHOGS_XE) $(funclib_)
+ $(SETMOD) funclib $(funclib_)
+
+gsdsrc.$(OBJ): gsdsrc.c $(GX) $(memory__h)\
+ $(gsdsrc_h) $(gserrors_h) $(stream_h)
+
+gsfunc.$(OBJ): gsfunc.c $(GX)\
+ $(gserrors_h) $(gxfunc_h)
+
+gsfunc0.$(OBJ): gsfunc0.c $(GX) $(math__h)\
+ $(gserrors_h) $(gsfunc0_h) $(gxfunc_h)
+
+# ----------------------- Platform-specific modules ----------------------- #
+# Platform-specific code doesn't really belong here: this is code that is
+# shared among multiple platforms.
+
+# Frame buffer implementations.
+
+gp_nofb.$(OBJ): gp_nofb.c $(GX) \
+ $(gp_h) $(gxdevice_h)
+
+gp_dosfb.$(OBJ): gp_dosfb.c $(AK) $(malloc__h) $(memory__h)\
+ $(gx_h) $(gp_h) $(gserrors_h) $(gxdevice_h)
+
+# MS-DOS file system, also used by Desqview/X.
+gp_dosfs.$(OBJ): gp_dosfs.c $(AK) $(dos__h) $(gp_h) $(gx_h)
+
+# MS-DOS file enumeration, *not* used by Desqview/X.
+gp_dosfe.$(OBJ): gp_dosfe.c $(AK) $(stdio__h) $(memory__h) $(string__h) \
+ $(dos__h) $(gstypes_h) $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h)
+
+# Other MS-DOS facilities.
+gp_msdos.$(OBJ): gp_msdos.c $(AK) $(dos__h) $(stdio__h) $(string__h)\
+ $(gsmemory_h) $(gstypes_h) $(gp_h)
+
+# Unix(-like) file system, also used by Desqview/X.
+gp_unifs.$(OBJ): gp_unifs.c $(AK) $(memory__h) $(string__h) $(gx_h) $(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+
+# Unix(-like) file name syntax, *not* used by Desqview/X.
+gp_unifn.$(OBJ): gp_unifn.c $(AK) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+# Main program for library testing
+
+gslib.$(OBJ): gslib.c $(AK) $(math__h) \
+ $(gx_h) $(gp_h) $(gserrors_h) $(gsmatrix_h) $(gsstate_h) $(gscspace_h) \
+ $(gscdefs_h) $(gscolor2_h) $(gscoord_h) $(gslib_h) $(gsparam_h) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxalloc_h) $(gxdevice_h)
diff --git a/gs/src/libpng.mak b/gs/src/libpng.mak
new file mode 100644
index 000000000..2346809d5
--- /dev/null
+++ b/gs/src/libpng.mak
@@ -0,0 +1,108 @@
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for PNG (Portable Network Graphics) code.
+
+# This partial makefile compiles the png library for use in the Ghostscript
+# PNG drivers. You can get the source code for this library from:
+# ftp://swrinde.nde.swri.edu/pub/png/src/
+# The makefile is known to work with the following library versions:
+# 0.89, 0.90, 0.95, and 0.96. NOTE: the archive for libpng 0.95 may
+# be inconsistent: if you have compilation problems, use an older version.
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+#
+# The specification for the PNG file format is available from:
+# http://www.group42.com/png.htm
+# http://www.w3.org/pub/WWW/TR/WD-png
+
+# Define the name of this makefile.
+LIBPNG_MAK=libpng.mak
+
+# PSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the PNG library sources are stored.
+#PSRCDIR=libpng
+# PVERSION is defined in the platform-specific makefile, not here,
+# as the libpng version number ("89", "90", "95", or "96").
+#PVERSION=96
+
+PSRC=$(PSRCDIR)$(D)
+# CCCP is defined in gs.mak.
+#CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR)
+
+# We keep all of the PNG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+PDEP=$(AK)
+
+png_1=png.$(OBJ) pngmem.$(OBJ) pngerror.$(OBJ)
+png_2=pngtrans.$(OBJ) pngwrite.$(OBJ) pngwtran.$(OBJ) pngwutil.$(OBJ)
+
+# libpng modules
+
+png.$(OBJ): $(PSRC)png.c $(PDEP)
+ $(CCCP) $(PSRC)png.c
+
+# version 0.89 uses pngwio.c
+pngwio.$(OBJ): $(PSRC)pngwio.c $(PDEP)
+ $(CCCP) $(PSRC)pngwio.c
+
+pngmem.$(OBJ): $(PSRC)pngmem.c $(PDEP)
+ $(CCCP) $(PSRC)pngmem.c
+
+pngerror.$(OBJ): $(PSRC)pngerror.c $(PDEP)
+ $(CCCP) $(PSRC)pngerror.c
+
+pngtrans.$(OBJ): $(PSRC)pngtrans.c $(PDEP)
+ $(CCCP) $(PSRC)pngtrans.c
+
+pngwrite.$(OBJ): $(PSRC)pngwrite.c $(PDEP)
+ $(CCCP) $(PSRC)pngwrite.c
+
+pngwtran.$(OBJ): $(PSRC)pngwtran.c $(PDEP)
+ $(CCCP) $(PSRC)pngwtran.c
+
+pngwutil.$(OBJ): $(PSRC)pngwutil.c $(PDEP)
+ $(CCCP) $(PSRC)pngwutil.c
+
+# Define the version of libpng.dev that we are actually using.
+libpng.dev: $(MAKEFILE) libpng_$(SHARE_LIBPNG).dev
+ $(CP_) libpng_$(SHARE_LIBPNG).dev libpng.dev
+
+# Define the shared version of libpng.
+# Note that it requires libz, which must be searched *after* libpng.
+libpng_1.dev: $(MAKEFILE) $(LIBPNG_MAK) $(ECHOGS_XE) zlibe.dev
+ $(SETMOD) libpng_1 -lib $(LIBPNG_NAME)
+ $(ADDMOD) libpng_1 -include zlibe
+
+# Define the non-shared version of libpng.
+libpng_0.dev: $(LIBPNG_MAK) $(ECHOGS_XE) $(png_1) $(png_2)\
+ zlibe.dev libpng$(PVERSION).dev
+ $(SETMOD) libpng_0 $(png_1)
+ $(ADDMOD) libpng_0 $(png_2)
+ $(ADDMOD) libpng_0 -include zlibe libpng$(PVERSION)
+
+libpng89.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ)
+ $(SETMOD) libpng89 pngwio.$(OBJ)
+
+libpng90.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng90 pngwio.$(OBJ) -include crc32
+
+libpng95.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng95 pngwio.$(OBJ) -include crc32
+
+libpng96.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng96 pngwio.$(OBJ) -include crc32
diff --git a/gs/src/main.h b/gs/src/main.h
new file mode 100644
index 000000000..0516eec5e
--- /dev/null
+++ b/gs/src/main.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* main.h */
+/* Backward-compatible interface to gsmain.c */
+#include "iminst.h"
+
+/*
+ * This file adds to imain.h some backward-compatible procedures and
+ * data elements that assume there is only a single instance of
+ * the interpreter.
+ */
+
+/* ================ Data elements ================ */
+
+/* Clients should never access these directly. */
+
+#define gs_user_errors (gs_main_instance_default()->user_errors)
+#define gs_lib_path (gs_main_instance_default()->lib_path)
+/* gs_lib_paths removed in release 3.65 */
+/* gs_lib_env_path removed in release 3.65 */
+
+/* ================ Exported procedures from gsmain.c ================ */
+
+/* ---------------- Initialization ---------------- */
+
+#define gs_init0(in, out, err, mlp)\
+ gs_main_init0(gs_main_instance_default(), in, out, err, mlp)
+
+#define gs_init1()\
+ gs_main_init1(gs_main_instance_default())
+
+#define gs_init2()\
+ gs_main_init2(gs_main_instance_default())
+
+#define gs_add_lib_path(path)\
+ gs_main_add_lib_path(gs_main_instance_default(), path)
+
+#define gs_set_lib_paths()\
+ gs_main_set_lib_paths(gs_main_instance_default())
+
+#define gs_lib_open(fname, pfile)\
+ gs_main_lib_open(gs_main_instance_default(), fname, pfile)
+
+/* ---------------- Execution ---------------- */
+
+#define gs_run_file(fn, ue, pec, peo)\
+ gs_main_run_file(gs_main_instance_default(), fn, ue, pec, peo)
+
+#define gs_run_string(str, ue, pec, peo)\
+ gs_main_run_string(gs_main_instance_default(), str, ue, pec, peo)
+
+#define gs_run_string_with_length(str, len, ue, pec, peo)\
+ gs_main_run_string_with_length(gs_main_instance_default(),\
+ str, len, ue, pec, peo)
+
+#define gs_run_file_open(fn, pfref)\
+ gs_main_run_file_open(gs_main_instance_default(), fn, pfref)
+
+#define gs_run_string_begin(ue, pec, peo)\
+ gs_main_run_string_begin(gs_main_instance_default(), ue, pec, peo)
+
+#define gs_run_string_continue(str, len, ue, pec, peo)\
+ gs_main_run_string_continue(gs_main_instance_default(),\
+ str, len, ue, pec, peo)
+
+#define gs_run_string_end(ue, pec, peo)\
+ gs_main_run_string_end(gs_main_instance_default(), ue, pec, peo)
+
+/* ---------------- Termination ---------------- */
+
+#define gs_finit(status, code)\
+ gs_main_finit(gs_main_instance_default(), status, code)
diff --git a/gs/src/malloc_.h b/gs/src/malloc_.h
new file mode 100644
index 000000000..af2b3a2b9
--- /dev/null
+++ b/gs/src/malloc_.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1989, 1992, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* malloc_.h */
+/* Generic substitute for Unix malloc.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#ifdef __TURBOC__
+# include <alloc.h>
+#else
+# if defined(BSD4_2) || defined(apollo) || defined(vax) || defined(sequent) || defined(UTEK)
+ extern char *malloc();
+ extern void free();
+# else
+# if defined(_HPUX_SOURCE) || defined(__CONVEX__) || defined(__convex__) || defined(__OSF__) || defined(__386BSD__) || defined(_POSIX_SOURCE) || defined(__STDC__) || defined(VMS)
+# include <stdlib.h>
+# else
+# include <malloc.h>
+# endif /* !_HPUX_SOURCE, ... */
+# endif /* !BSD4_2, ... */
+#endif /* !__TURBOC__ */
+
+/* (At least some versions of) Linux don't have a working realloc.... */
+#ifdef linux
+# define malloc__need_realloc
+void *gs_realloc(P3(void *, size_t, size_t));
+#else
+# define gs_realloc(ptr, old_size, new_size) realloc(ptr, new_size)
+#endif
diff --git a/gs/src/math_.h b/gs/src/math_.h
new file mode 100644
index 000000000..6fca942c9
--- /dev/null
+++ b/gs/src/math_.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* math_.h */
+/* Generic substitute for math.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#if defined(VMS) && defined(__GNUC__)
+/* DEC VAX/VMS C comes with a math.h file, but GNU VAX/VMS C does not. */
+# include "vmsmath.h"
+#else
+# include <math.h>
+#endif
+
+/* math.h is different for Turbo and Unix.... */
+#ifndef M_PI
+# ifdef PI
+# define M_PI PI
+# else
+# define M_PI 3.14159265358979324
+# endif
+#endif
+
+/* Factors for converting between degrees and radians */
+#define degrees_to_radians (M_PI / 180.0)
+#define radians_to_degrees (180.0 / M_PI)
+
+/* Define the maximum value of a single-precision float. */
+/* This doesn't seem to be defined in any standard place, */
+/* and we need an exact value for it. */
+#undef MAX_FLOAT /* just in case */
+#if defined(vax) || defined(VAX) || defined(__vax) || defined(__VAX)
+/* Maximum exponent is +127, 23 bits of fraction. */
+# define MAX_FLOAT\
+ ((0x800000 - 1.0) * 0x1000000 * 0x1000000 * 0x10000000 * 0x10000000)
+#else
+/* IEEE, maximum exponent is +127, 23 bits of fraction + an implied '1'. */
+# define MAX_FLOAT\
+ ((0x1000000 - 1.0) * 0x1000000 * 0x1000000 * 0x10000000 * 0x10000000)
+#endif
+
+/* Define the hypot procedure on those few systems that don't provide it. */
+#ifdef _IBMR2
+/* The RS/6000 has hypot, but math.h doesn't declare it! */
+extern double hypot(double, double);
+#else
+# if !defined(__TURBOC__) && !defined(BSD4_2) && !defined(VMS)
+# define hypot(x,y) sqrt((x)*(x)+(y)*(y))
+# endif
+#endif
+
+#ifdef OSK
+/* OSK has atan2 and ldexp, but math.h doesn't declare them! */
+extern double atan2(), ldexp();
+#endif
+
+#ifdef DEBUG
+
+/* Intercept calls on sqrt for debugging. */
+extern double gs_sqrt(P3(double, const char *, int));
+#undef sqrt
+#define sqrt(x) gs_sqrt(x, __FILE__, __LINE__)
+
+#endif /* DEBUG */
diff --git a/gs/src/memory_.h b/gs/src/memory_.h
new file mode 100644
index 000000000..1c26113fd
--- /dev/null
+++ b/gs/src/memory_.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* memory_.h */
+/* Generic substitute for Unix memory.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/****** Note: the System V bcmp routine only returns zero or non-zero, ******/
+/****** unlike memcmp which returns -1, 0, or 1. ******/
+
+#ifdef __TURBOC__
+/* Define inline functions */
+# ifdef __WIN32__
+# define memcmp_inline(b1,b2,len) memcmp(b1,b2,len)
+# else
+# define memcmp_inline(b1,b2,len) __memcmp__(b1,b2,len)
+# endif
+/* The Turbo C implementation of memset swaps the arguments and calls */
+/* the non-standard routine setmem. We may as well do it in advance. */
+# undef memset /* just in case */
+# include <mem.h>
+# ifndef memset /* Borland C++ can inline this */
+# define memset(dest,chr,cnt) setmem(dest,cnt,chr)
+# endif
+#else
+ /* Not Turbo C, no inline functions */
+# define memcmp_inline(b1,b2,len) memcmp(b1,b2,len)
+ /* Apparently the newer VMS compilers include prototypes */
+ /* for the mem... routines in <string.h>. Unfortunately, */
+ /* gcc lies on Sun systems: it defines __STDC__ even if */
+ /* the header files in /usr/include are broken. */
+ /* However, Solaris systems, which define __svr4__, do have */
+ /* correct header files. */
+# if defined(VMS) || defined(_POSIX_SOURCE) || (defined(__STDC__) && (!defined(sun) || defined(__svr4__))) || defined(_HPUX_SOURCE) || defined(__WATCOMC__) || defined(THINK_C) || defined(bsdi) || (defined(_MSC_VER) && _MSC_VER >= 1000)
+# include <string.h>
+# else
+# if defined(BSD4_2) || defined(UTEK)
+ extern bcopy(), bcmp(), bzero();
+# define memcpy(dest,src,len) bcopy(src,dest,len)
+# define memcmp(b1,b2,len) bcmp(b1,b2,len)
+ /* Define our own versions of missing routines (in gsmisc.c). */
+# define memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# include <sys/types.h> /* for size_t */
+ void *gs_memmove(P3(void *, const void *, size_t));
+# define memory__need_memset
+# define memset(dest,ch,len) gs_memset(dest,ch,len)
+ void *gs_memset(P3(void *, int, size_t));
+# if defined(UTEK)
+# define memory__need_memchr
+# define memchr(ptr,ch,len) gs_memchr(ptr,ch,len)
+ const char *gs_memchr(P3(const void *, int, size_t));
+# endif /* UTEK */
+# else
+# include <memory.h>
+# if defined(__SVR3) || defined(sun) /* Not sure this is right.... */
+# define memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# include <sys/types.h> /* for size_t */
+ void *gs_memmove(P3(void *, const void *, size_t));
+# endif /* __SVR3 or sun */
+# endif /* BSD4_2 or UTEK */
+# endif /* VMS, POSIX, ... */
+#endif /* !__TURBOC__ */
diff --git a/gs/src/msvc32.mak b/gs/src/msvc32.mak
new file mode 100644
index 000000000..530ce46d2
--- /dev/null
+++ b/gs/src/msvc32.mak
@@ -0,0 +1,367 @@
+# Copyright (C) 1991-1997 Aladdin Enterprises. All rights reserved.
+# This software is licensed to a single customer by Artifex Software Inc.
+# under the terms of a specific OEM agreement.
+
+# msvc32.mak
+# makefile for 32-bit Microsoft Visual C++, Windows NT or Windows 95 platform.
+#
+# All configurable options are surrounded by !ifndef/!endif to allow
+# preconfiguration from within another makefile.
+#
+# Optimization /O2 seems OK with MSVC++ 4.1 & 5.0.
+# Created 1997-01-24 by Russell Lang from MSVC++ 2.0 makefile.
+# Enhanced 97-05-15 by JD
+# Common code factored out 1997-05-22 by L. Peter Deutsch.
+# Made pre-configurable by JD 6/4/98
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+!ifndef GS_DOCDIR
+GS_DOCDIR=c:/gs
+!endif
+
+# Define the default directory/ies for the runtime initialization and
+# font files. Separate multiple directories with ';'.
+# Use / to indicate directories, not \.
+# MSVC will not allow \'s here because it sees '\;' CPP-style as an
+# illegal escape.
+
+!ifndef GS_LIB_DEFAULT
+GS_LIB_DEFAULT=.;c:/gs
+!endif
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+!ifndef SEARCH_HERE_FIRST
+SEARCH_HERE_FIRST=1
+!endif
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+!ifndef GS_INIT
+GS_INIT=gs_init.ps
+!endif
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+!ifndef DEBUG
+DEBUG=1
+!endif
+
+# Setting TDEBUG=1 includes symbol table information for the debugger,
+# and also enables stack checking. Code is substantially slower and larger.
+
+!ifndef TDEBUG
+TDEBUG=1
+!endif
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+!ifndef NOPRIVATE
+NOPRIVATE=0
+!endif
+
+# Define the name of the executable file.
+
+!ifndef GS
+GS=gswin32
+!endif
+!ifndef GSCONSOLE
+GSCONSOLE=gswin32c
+!endif
+!ifndef GSDLL
+GSDLL=gsdll32
+!endif
+
+# To build two small executables and a large DLL use MAKEDLL=1
+# To build two large executables use MAKEDLL=0
+
+!ifndef MAKEDLL
+MAKEDLL=1
+!endif
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+!ifndef JSRCDIR
+JSRCDIR=jpeg-6a
+JVERSION=6
+!endif
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+!ifndef PSRCDIR
+PSRCDIR=libpng
+PVERSION=96
+!endif
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+!ifndef ZSRCDIR
+ZSRCDIR=zlib
+!endif
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+!ifndef CONFIG
+CONFIG=
+!endif
+
+# Define any other compilation flags.
+
+!ifndef CFLAGS
+CFLAGS=
+!endif
+
+# ------ Platform-specific options ------ #
+
+# Define which major version of MSVC is being used (currently, 4 & 5 supported)
+
+!ifndef MSVC_VERSION
+MSVC_VERSION = 5
+!endif
+
+# Define the drive, directory, and compiler name for the Microsoft C files.
+# COMPDIR contains the compiler and linker (normally \msdev\bin).
+# INCDIR contains the include files (normally \msdev\include).
+# LIBDIR contains the library files (normally \msdev\lib).
+# COMP is the full C compiler path name (normally \msdev\bin\cl).
+# COMPCPP is the full C++ compiler path name (normally \msdev\bin\cl).
+# COMPAUX is the compiler name for DOS utilities (normally \msdev\bin\cl).
+# RCOMP is the resource compiler name (normallly \msdev\bin\rc).
+# LINK is the full linker path name (normally \msdev\bin\link).
+# Note that when INCDIR and LIBDIR are used, they always get a '\' appended,
+# so if you want to use the current directory, use an explicit '.'.
+
+!if $(MSVC_VERSION) == 4
+! ifndef DEVSTUDIO
+DEVSTUDIO=c:\msdev
+! endif
+COMPBASE=$(DEVSTUDIO)
+SHAREDBASE=$(DEVSTUDIO)
+!else
+! ifndef DEVSTUDIO
+DEVSTUDIO=c:\devstudio
+! endif
+COMPBASE=$(DEVSTUDIO)\VC
+SHAREDBASE=$(DEVSTUDIO)\SharedIDE
+!endif
+COMPDIR=$(COMPBASE)\bin
+LINKDIR=$(COMPBASE)\bin
+RCDIR=$(SHAREDBASE)\bin
+INCDIR=$(COMPBASE)\include
+LIBDIR=$(COMPBASE)\lib
+COMP=$(COMPDIR)\cl
+COMPCPP=$(COMP)
+COMPAUX=$(COMPDIR)\cl
+RCOMP=$(RCDIR)\rc
+LINK=$(LINKDIR)\link
+
+# Define the processor architecture. (i386, ppc, alpha)
+
+!ifndef CPU_FAMILY
+CPU_FAMILY=i386
+#CPU_FAMILY=ppc
+#CPU_FAMILY=alpha # not supported yet - we need someone to tweak
+!endif
+
+# Define the processor (CPU) type. Allowable values depend on the family:
+# i386: 386, 486, 586
+# ppc: 601, 604, 620
+# alpha: not currently used.
+
+!ifndef CPU_TYPE
+CPU_TYPE=486
+#CPU_TYPE=601
+!endif
+
+!if "$(CPU_FAMILY)"=="i386"
+
+# Intel(-compatible) processors are the only ones for which the CPU type
+# doesn't indicate whether a math coprocessor is present.
+# For Intel processors only, define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If you have a 486 or Pentium CPU, you should normally set FPU_TYPE to 387,
+# since most of these CPUs include the equivalent of an 80387 on-chip;
+# however, the 486SX and the Cyrix 486SLC do not have an on-chip FPU, so if
+# you have one of these CPUs and no external FPU, set FPU_TYPE to -1 or 0.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+! ifndef FPU_TYPE
+FPU_TYPE=0
+! endif
+
+!endif
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+!ifndef FEATURE_DEVS
+FEATURE_DEVS=level2.dev pdf.dev ttfont.dev
+!endif
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+!ifndef COMPILE_INITS
+COMPILE_INITS=0
+!endif
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+!ifndef BAND_LIST_STORAGE
+BAND_LIST_STORAGE=memory
+!endif
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+!ifndef BAND_LIST_COMPRESSOR
+BAND_LIST_COMPRESSOR=zlib
+!endif
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+!ifndef FILE_IMPLEMENTATION
+FILE_IMPLEMENTATION=stdio
+!endif
+
+# Choose the device(s) to include. See devs.mak for details.
+
+!ifndef DEVICE_DEVS
+DEVICE_DEVS=mswindll.dev mswinprn.dev mswinpr2.dev
+DEVICE_DEVS2=asynmono.dev
+DEVICE_DEVS3=bmpmono.dev
+DEVICE_DEVS4=
+DEVICE_DEVS5=
+DEVICE_DEVS6=
+DEVICE_DEVS7=
+DEVICE_DEVS8=
+DEVICE_DEVS9=
+DEVICE_DEVS10=
+DEVICE_DEVS11=
+DEVICE_DEVS12=
+DEVICE_DEVS13=
+DEVICE_DEVS14=
+DEVICE_DEVS15=
+!endif
+
+# ---------------------------- End of options ---------------------------- #
+
+# Derive values for FPU_TYPE for non-Intel processors.
+
+!if "$(CPU_FAMILY)"=="ppc"
+! if $(CPU_TYPE)>601
+FPU_TYPE=2
+! else
+FPU_TYPE=1
+! endif
+!endif
+
+!if "$(CPU_FAMILY)"=="alpha"
+# *** alpha *** This needs fixing
+FPU_TYPE=1
+!endif
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=msvc32.mak msvccmd.mak msvctail.mak winlib.mak winint.mak
+
+# Define the files to be removed by `make clean'.
+# nmake expands macros when encountered, not when used,
+# so this must precede the !include statements.
+
+BEGINFILES2=gsdll32.exp gsdll32.ilk gsdll32.pdb gsdll32.lib\
+ gswin32.exp gswin32.ilk gswin32.pdb gswin32.lib\
+ gswin32c.exp gswin32c.ilk gswin32c.pdb gswin32c.lib
+
+
+!include msvccmd.mak
+!include winlib.mak
+!include msvctail.mak
+!include winint.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+!if $(MAKEDLL)
+# The graphical small EXE loader
+$(GS_XE): $(GSDLL).dll $(DWOBJ) $(GSCONSOLE).exe
+ echo /SUBSYSTEM:WINDOWS > gswin32.rsp
+ echo /DEF:dwmain32.def /OUT:$(GS_XE) >> gswin32.rsp
+ $(LINK) $(LCT) @gswin32.rsp $(DWOBJ) @$(LIBCTR) $(GS).res
+ del gswin32.rsp
+
+# The console mode small EXE loader
+$(GSCONSOLE).exe: $(OBJC) $(GS).res dw32c.def
+ echo /SUBSYSTEM:CONSOLE > gswin32.rsp
+ echo /DEF:dw32c.def /OUT:$(GSCONSOLE).exe >> gswin32.rsp
+ $(LINK_SETUP)
+ $(LINK) $(LCT) @gswin32.rsp $(OBJC) @$(LIBCTR) $(GS).res
+ del gswin32.rsp
+
+# The big DLL
+$(GSDLL).dll: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(GSDLL).res
+ echo /DLL /DEF:gsdll32.def /OUT:$(GSDLL).dll > gswin32.rsp
+ $(LINK_SETUP)
+ $(LINK) $(LCT) @gswin32.rsp gsdll @$(ld_tr) $(INTASM) @lib.tr @$(LIBCTR) $(GSDLL).res
+ del gswin32.rsp
+
+!else
+# The big graphical EXE
+$(GS_XE): $(GSCONSOLE).exe $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(DWOBJNO) $(GS).res dwmain32.def
+ copy $(ld_tr) gswin32.tr
+ echo dwnodll.obj >> gswin32.tr
+ echo dwimg.obj >> gswin32.tr
+ echo dwmain.obj >> gswin32.tr
+ echo dwtext.obj >> gswin32.tr
+ echo /DEF:dwmain32.def /OUT:$(GS_XE) > gswin32.rsp
+ $(LINK_SETUP)
+ $(LINK) $(LCT) @gswin32.rsp gsdll @gswin32.tr @$(LIBCTR) $(INTASM) @lib.tr $(GSDLL).res
+ del gswin32.tr
+ del gswin32.rsp
+
+# The big console mode EXE
+$(GSCONSOLE).exe: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(OBJCNO) $(GS).res dw32c.def
+ copy $(ld_tr) gswin32c.tr
+ echo dwnodllc.obj >> gswin32c.tr
+ echo dwmainc.obj >> gswin32c.tr
+ echo /SUBSYSTEM:CONSOLE > gswin32.rsp
+ echo /DEF:dw32c.def /OUT:$(GSCONSOLE).exe >> gswin32.rsp
+ $(LINK_SETUP)
+ $(LINK) $(LCT) @gswin32.rsp gsdll @gswin32c.tr @$(LIBCTR) $(INTASM) @lib.tr $(GS).res
+ del gswin32.rsp
+ del gswin32c.tr
+!endif
+
+# end of makefile
diff --git a/gs/src/msvccmd.mak b/gs/src/msvccmd.mak
new file mode 100644
index 000000000..8d22352cb
--- /dev/null
+++ b/gs/src/msvccmd.mak
@@ -0,0 +1,185 @@
+# Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+# This software is licensed to a single customer by Artifex Software Inc.
+# under the terms of a specific OEM agreement.
+
+# msvccmd.mak
+# Command definition section for Microsoft Visual C++ 4.x/5.x,
+# Windows NT or Windows 95 platform.
+# Created 1997-05-22 by L. Peter Deutsch from msvc4/5 makefiles.
+# edited 1997-06-xx by JD to factor out interpreter-specific sections
+
+# Set up linker differently for MSVC 4 vs. later versions
+
+!if $(MSVC_VERSION) == 4
+
+# MSVC version 4.x doesn't recognize the /QI0f switch, which works around
+# an unspecified bug in the Pentium decoding of certain 0F instructions.
+QI0f=
+
+# Set up LIB enviromnent variable to include LIBDIR. This is a hack for
+# MSVC4.x, which doesn't have compiler switches to do the deed
+
+!ifdef LIB
+LIB=$(LIBDIR);$(LIB)
+!else
+LINK_SETUP=set LIB=$(LIBDIR)
+CCAUX_SETUP=$(LINK_SETUP)
+!endif
+
+!else
+#else #$(MSVC_VERSION) == 4
+
+# MSVC 5.x does recognize /QI0f.
+QI0f=/QI0f
+
+# Define linker switch that will select where MS libraries are.
+
+LINK_LIB_SWITCH=/LIBPATH:$(LIBDIR)
+
+# Define separate CCAUX command-line switch that must be at END of line.
+
+CCAUX_TAIL= /link $(LINK_LIB_SWITCH)
+
+!endif
+#endif #$(MSVC_VERSION) == 4
+
+
+# Define the current directory prefix and shell invocations.
+
+D=\#
+
+EXPP=
+SH=
+SHP=
+
+# Define the arguments for genconf.
+
+CONFILES=-p %%s -o ld$(CONFIG).tr -l lib.tr
+
+# Define the generic compilation flags.
+
+PLATOPT=
+
+INTASM=
+PCFBASM=
+
+# Make sure we get the right default target for make.
+
+dosdefault: default
+
+# Define the compilation flags.
+
+!if "$(CPU_FAMILY)"=="i386"
+
+!if $(CPU_TYPE)>500
+CPFLAGS=/G5 $(QI0f)
+!else if $(CPU_TYPE)>400
+CPFLAGS=/GB $(QI0f)
+!else
+CPFLAGS=/GB $(QI0f)
+!endif
+
+!if $(FPU_TYPE)>0
+FPFLAGS=/FPi87
+!else
+FPFLAGS=
+!endif
+
+!endif
+
+!if "$(CPU_FAMILY)"=="ppc"
+
+!if $(CPU_TYPE)>=620
+CPFLAGS=/QP620
+!else if $(CPU_TYPE)>=604
+CPFLAGS=/QP604
+!else
+CPFLAGS=/QP601
+!endif
+
+FPFLAGS=
+
+!endif
+
+!if "$(CPU_FAMILY)"=="alpha"
+
+# *** alpha *** This needs fixing
+CPFLAGS=
+FPFLAGS=
+
+!endif
+
+!if $(NOPRIVATE)!=0
+CP=/DNOPRIVATE
+!else
+CP=
+!endif
+
+!if $(DEBUG)!=0
+CD=/DDEBUG
+!else
+CD=
+!endif
+
+!if $(TDEBUG)!=0
+CT=/Zi /Od
+LCT=/DEBUG $(LINK_LIB_SWITCH)
+COMPILE_FULL_OPTIMIZED= # no optimization when debugging
+COMPILE_WITH_FRAMES= # no optimization when debugging
+COMPILE_WITHOUT_FRAMES= # no optimization when debugging
+!else
+CT=
+LCT=$(LINK_LIB_SWITCH)
+COMPILE_FULL_OPTIMIZED=/O2
+COMPILE_WITH_FRAMES=
+COMPILE_WITHOUT_FRAMES=/Oy
+!endif
+
+!if $(DEBUG)!=0 || $(TDEBUG)!=0
+CS=/Ge
+!else
+CS=/Gs
+!endif
+
+# Specify output object name
+CCOBJNAME=-Fo
+
+# Specify function prolog type
+COMPILE_FOR_DLL=
+COMPILE_FOR_EXE=
+COMPILE_FOR_CONSOLE_EXE=
+
+
+GENOPT=$(CP) $(CD) $(CT) $(CS) /W2 /nologo
+
+CCFLAGS=$(PLATOPT) $(FPFLAGS) $(CPFLAGS) $(CFLAGS) $(XCFLAGS)
+CC=$(COMP) /c $(CCFLAGS) @ccf32.tr
+CPP=$(COMPCPP) /c $(CCFLAGS) @ccf32.tr
+!if $(MAKEDLL)
+WX=$(COMPILE_FOR_DLL)
+!else
+WX=$(COMPILE_FOR_EXE)
+!endif
+CCC=$(CC) $(WX) $(COMPILE_FULL_OPTIMIZED) /Za
+CCD=$(CC) $(WX) $(COMPILE_WITH_FRAMES)
+CCINT=$(CCC)
+CCCF=$(CCC)
+CCLEAF=$(CCC) $(COMPILE_WITHOUT_FRAMES)
+
+# Compiler for auxilliary programs
+
+CCAUX=$(COMPAUX) /I$(INCDIR) /O
+
+# Compiler w/Microsoft extensions for compiling Windows files
+
+CCCWIN=$(CC) $(WX) $(COMPILE_FULL_OPTIMIZED) /Ze
+
+# Define the generic compilation rules.
+
+.c.obj:
+ $(CCC) $<
+
+.cpp.obj:
+ $(CPP) $<
+
+#end msvccmd.mak
diff --git a/gs/src/msvccom.mak b/gs/src/msvccom.mak
new file mode 100644
index 000000000..b40a948b9
--- /dev/null
+++ b/gs/src/msvccom.mak
@@ -0,0 +1,225 @@
+# Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# msvccom.mak
+# Common makefile section for Microsoft Visual C++ 4.x/5.x,
+# Windows NT or Windows 95 platform.
+# Created 1997-05-22 by L. Peter Deutsch from msvc4/5 makefiles.
+# edited 1997-06-xx by JD to factor out interpreter-specific sections
+
+# Set up linker differently for MSVC 4 vs. later versions
+
+!if $(MSVC_VERSION) == 4
+
+# MSVC version 4.x doesn't recognize the /QI0f switch, which works around
+# an unspecified bug in the Pentium decoding of certain 0F instructions.
+QI0f=
+
+# Set up LIB enviromnent variable to include LIBDIR. This is a hack for
+# MSVC4.x, which doesn't have compiler switches to do the deed
+
+!ifdef LIB
+LIB=$(LIBDIR);$(LIB)
+!else
+LINK_SETUP=set LIB=$(LIBDIR)
+CCAUX_SETUP=$(LINK_SETUP)
+!endif
+
+!else
+#else #$(MSVC_VERSION) == 4
+
+# MSVC 5.x does recognize /QI0f.
+QI0f=/QI0f
+
+# Define linker switch that will select where MS libraries are.
+
+LINK_LIB_SWITCH=/LIBPATH:$(LIBDIR)
+
+# Define separate CCAUX command-line switch that must be at END of line.
+
+CCAUX_TAIL= /link $(LINK_LIB_SWITCH)
+
+!endif
+#endif #$(MSVC_VERSION) == 4
+
+
+# Define the current directory prefix and shell invocations.
+
+D=\#
+
+EXPP=
+SH=
+SHP=
+
+# Define the arguments for genconf.
+
+CONFILES=-p %%s -o $(ld_tr) -l lib.tr
+
+# Define the generic compilation flags.
+
+PLATOPT=
+
+INTASM=
+PCFBASM=
+
+# Make sure we get the right default target for make.
+
+dosdefault: default
+
+# Define the compilation flags.
+
+!if "$(CPU_FAMILY)"=="i386"
+
+!if $(CPU_TYPE)>500
+CPFLAGS=/G5 $(QI0f)
+!else if $(CPU_TYPE)>400
+CPFLAGS=/GB $(QI0f)
+!else
+CPFLAGS=/GB $(QI0f)
+!endif
+
+!if $(FPU_TYPE)>0
+FPFLAGS=/FPi87
+!else
+FPFLAGS=
+!endif
+
+!endif
+
+!if "$(CPU_FAMILY)"=="ppc"
+
+!if $(CPU_TYPE)>=620
+CPFLAGS=/QP620
+!else if $(CPU_TYPE)>=604
+CPFLAGS=/QP604
+!else
+CPFLAGS=/QP601
+!endif
+
+FPFLAGS=
+
+!endif
+
+!if "$(CPU_FAMILY)"=="alpha"
+
+# *** alpha *** This needs fixing
+CPFLAGS=
+FPFLAGS=
+
+!endif
+
+!if $(NOPRIVATE)!=0
+CP=/DNOPRIVATE
+!else
+CP=
+!endif
+
+!if $(DEBUG)!=0
+CD=/DDEBUG
+!else
+CD=
+!endif
+
+!if $(TDEBUG)!=0
+CT=/Zi /Od
+LCT=/DEBUG $(LINK_LIB_SWITCH)
+COMPILE_FULL_OPTIMIZED= # no optimization when debugging
+COMPILE_WITH_FRAMES= # no optimization when debugging
+COMPILE_WITHOUT_FRAMES= # no optimization when debugging
+!else
+CT=
+LCT=$(LINK_LIB_SWITCH)
+COMPILE_FULL_OPTIMIZED=/O2
+COMPILE_WITH_FRAMES=
+COMPILE_WITHOUT_FRAMES=/Oy
+!endif
+
+!if $(DEBUG)!=0 || $(TDEBUG)!=0
+CS=/Ge
+!else
+CS=/Gs
+!endif
+
+# Specify output object name
+CCOBJNAME=-Fo
+
+# Specify function prolog type
+COMPILE_FOR_DLL=
+COMPILE_FOR_EXE=
+COMPILE_FOR_CONSOLE_EXE=
+
+
+GENOPT=$(CP) $(CD) $(CT) $(CS) /W2 /nologo
+
+CCFLAGS=$(PLATOPT) $(FPFLAGS) $(CPFLAGS) $(CFLAGS) $(XCFLAGS)
+CC=$(COMP) /c $(CCFLAGS) @ccf32.tr
+CPP=$(COMPCPP) /c $(CCFLAGS) @ccf32.tr
+!if $(MAKEDLL)
+WX=$(COMPILE_FOR_DLL)
+!else
+WX=$(COMPILE_FOR_EXE)
+!endif
+CCC=$(CC) $(WX) $(COMPILE_FULL_OPTIMIZED)
+CCD=$(CC) $(WX) $(COMPILE_WITH_FRAMES)
+CCINT=$(CCC)
+CCCF=$(CCC)
+CCLEAF=$(CCC) $(COMPILE_WITHOUT_FRAMES)
+
+# Compiler for auxilliary programs
+
+CCAUX=$(COMPAUX) /I$(INCDIR) /O
+
+
+# Define the generic compilation rules.
+
+.c.obj:
+ $(CCC) $<
+
+.cpp.obj:
+ $(CPP) $<
+
+
+# Include the generic library makefiles.
+
+!include winlib.mak
+
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+ccf32.tr: $(MAKEFILE) makefile
+ echo $(GENOPT) /I$(INCDIR) -DCHECK_INTERRUPTS -D_Windows -D__WIN32__ > ccf32.tr
+
+$(GENARCH_XE): genarch.c $(stdpre_h) $(iref_h) ccf32.tr
+ $(CCAUX_SETUP)
+ $(CCAUX) @ccf32.tr genarch.c $(CCAUX_TAIL)
+
+# -------------------------------- Library -------------------------------- #
+
+# See winlib.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+LIBCTR=libc32.tr
+
+$(LIBCTR): $(MAKEFILE) $(ECHOGS_XE)
+ echogs -w $(LIBCTR) $(LIBDIR)\shell32.lib
+ echogs -a $(LIBCTR) $(LIBDIR)\comdlg32.lib
+ echogs -a $(LIBCTR) $(LIBDIR)\gdi32.lib
+ echogs -a $(LIBCTR) $(LIBDIR)\user32.lib
+ echogs -a $(LIBCTR) $(LIBDIR)\winspool.lib
+
+# end of msvccom.mak
diff --git a/gs/src/msvclib.mak b/gs/src/msvclib.mak
new file mode 100644
index 000000000..a29726e54
--- /dev/null
+++ b/gs/src/msvclib.mak
@@ -0,0 +1,342 @@
+# Copyright (C) 1991-1997 Aladdin Enterprises. All rights reserved.
+# This software is licensed to a single customer by Artifex Software Inc.
+# under the terms of a specific OEM agreement.
+
+# msvclib.mak
+# makefile for Microsoft Visual C++ 4.1 or later, Windows NT or Windows 95 LIBRARY.
+#
+# All configurable options are surrounded by !ifndef/!endif to allow
+# preconfiguration from within another makefile.
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+!ifndef GS_DOCDIR
+GS_DOCDIR=c:/gs
+!endif
+
+# Define the default directory/ies for the runtime initialization and
+# font files. Separate multiple directories with ';'.
+# Use / to indicate directories, not \.
+# MSVC will not allow \'s here because it sees '\;' CPP-style as an
+# illegal escape.
+
+!ifndef GS_LIB_DEFAULT
+GS_LIB_DEFAULT=.;c:/gs/lib;c:/gs/fonts
+!endif
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+!ifndef SEARCH_HERE_FIRST
+SEARCH_HERE_FIRST=1
+!endif
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+!ifndef DEBUG
+DEBUG=0
+!endif
+
+# Setting TDEBUG=1 includes symbol table information for the debugger,
+# and also enables stack checking. Code is substantially slower and larger.
+
+!ifndef TDEBUG
+TDEBUG=1
+!endif
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+!ifndef NOPRIVATE
+NOPRIVATE=0
+!endif
+
+# Define the name of the executable file.
+
+!ifndef GS
+GS=gslib
+!endif
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+!ifndef JSRCDIR
+JSRCDIR=jpeg-6a
+JVERSION=6
+!endif
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+!ifndef PSRCDIR
+PSRCDIR=libpng
+PVERSION=96
+!endif
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+!ifndef ZSRCDIR
+ZSRCDIR=zlib
+!endif
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+!ifndef CONFIG
+CONFIG=
+!endif
+
+# Define any other compilation flags.
+
+!ifndef CFLAGS
+CFLAGS=
+!endif
+
+# ------ Platform-specific options ------ #
+
+# Define which major version of MSVC is being used (currently, 4 & 5 supported)
+
+!ifndef MSVC_VERSION
+MSVC_VERSION = 5
+!endif
+
+# Define the drive, directory, and compiler name for the Microsoft C files.
+# COMPDIR contains the compiler and linker (normally \msdev\bin).
+# INCDIR contains the include files (normally \msdev\include).
+# LIBDIR contains the library files (normally \msdev\lib).
+# COMP is the full C compiler path name (normally \msdev\bin\cl).
+# COMPCPP is the full C++ compiler path name (normally \msdev\bin\cl).
+# COMPAUX is the compiler name for DOS utilities (normally \msdev\bin\cl).
+# RCOMP is the resource compiler name (normallly \msdev\bin\rc).
+# LINK is the full linker path name (normally \msdev\bin\link).
+# Note that when INCDIR and LIBDIR are used, they always get a '\' appended,
+# so if you want to use the current directory, use an explicit '.'.
+
+!if $(MSVC_VERSION) == 4
+! ifndef DEVSTUDIO
+DEVSTUDIO=c:\msdev
+! endif
+COMPBASE=$(DEVSTUDIO)
+SHAREDBASE=$(DEVSTUDIO)
+!else
+! ifndef DEVSTUDIO
+DEVSTUDIO=c:\devstudio
+! endif
+COMPBASE=$(DEVSTUDIO)\VC
+SHAREDBASE=$(DEVSTUDIO)\SharedIDE
+!endif
+COMPDIR=$(COMPBASE)\bin
+LINKDIR=$(COMPBASE)\bin
+RCDIR=$(SHAREDBASE)\bin
+INCDIR=$(COMPBASE)\include
+LIBDIR=$(COMPBASE)\lib
+COMP=$(COMPDIR)\cl
+COMPCPP=$(COMP)
+COMPAUX=$(COMPDIR)\cl
+RCOMP=$(RCDIR)\rc
+LINK=$(LINKDIR)\link
+
+# Define the processor architecture. (i386, ppc, alpha)
+
+!ifndef CPU_FAMILY
+CPU_FAMILY=i386
+#CPU_FAMILY=ppc
+#CPU_FAMILY=alpha # not supported yet - we need someone to tweak
+!endif
+
+# Define the processor (CPU) type. Allowable values depend on the family:
+# i386: 386, 486, 586
+# ppc: 601, 604, 620
+# alpha: not currently used.
+
+!ifndef CPU_TYPE
+CPU_TYPE=486
+#CPU_TYPE=601
+!endif
+
+!if "$(CPU_FAMILY)"=="i386"
+
+# Intel(-compatible) processors are the only ones for which the CPU type
+# doesn't indicate whether a math coprocessor is present.
+# For Intel processors only, define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If you have a 486 or Pentium CPU, you should normally set FPU_TYPE to 387,
+# since most of these CPUs include the equivalent of an 80387 on-chip;
+# however, the 486SX and the Cyrix 486SLC do not have an on-chip FPU, so if
+# you have one of these CPUs and no external FPU, set FPU_TYPE to -1 or 0.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+! ifndef FPU_TYPE
+FPU_TYPE=0
+! endif
+
+!endif
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+# Allow predefinition of selectable options
+# when using this makefile from inside another one.
+!ifndef FEATURE_DEVS
+FEATURE_DEVS=patlib.dev path1lib.dev hsblib.dev
+!endif
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+!ifndef COMPILED_INITS
+COMPILE_INITS=0
+!endif
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+!ifndef BAND_LIST_STORAGE
+BAND_LIST_STORAGE=file
+!endif
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+!ifndef BAND_LIST_COMPRESSOR
+BAND_LIST_COMPRESSOR=zlib
+!endif
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfilefd.c for more details.
+
+!ifndef FILE_IMPLEMENTATION
+FILE_IMPLEMENTATION=stdio
+!endif
+
+# Choose the device(s) to include. See devs.mak for details.
+!ifndef DEVICE_DEVS
+DEVICE_DEVS=ljet2p.dev
+DEVICE_DEVS2=
+DEVICE_DEVS3=
+DEVICE_DEVS4=
+DEVICE_DEVS5=
+DEVICE_DEVS6=
+DEVICE_DEVS7=
+DEVICE_DEVS8=
+DEVICE_DEVS9=
+DEVICE_DEVS10=
+DEVICE_DEVS11=
+DEVICE_DEVS12=
+DEVICE_DEVS13=
+DEVICE_DEVS15=
+!endif
+
+# ---------------------------- End of options ---------------------------- #
+
+# Derive values for FPU_TYPE for non-Intel processors.
+
+!if "$(CPU_FAMILY)"=="ppc"
+! if $(CPU_TYPE)>601
+FPU_TYPE=2
+! else
+FPU_TYPE=1
+! endif
+!endif
+
+!if "$(CPU_FAMILY)"=="alpha"
+# *** alpha *** This needs fixing
+FPU_TYPE=1
+!endif
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=msvclib.mak msvccmd.mak msvctail.mak winlib.mak
+
+# Define the files to be removed by `make clean'.
+# nmake expands macros when encountered, not when used,
+# so this must precede the !include statements.
+
+BEGINFILES2=$(GS).ilk $(GS).pdb
+
+# Define these right away because they modify the behavior of
+# msvccmd.mak, msvctail.mak & winlib.mak.
+
+LIB_ONLY=gslib.obj gsnogc.obj gconfig.obj gscdefs.obj
+MAKEDLL=0
+PLATFORM=mslib32_
+
+
+!include msvccmd.mak
+!include winlib.mak
+!include msvctail.mak
+
+# -------------------------------- Library -------------------------------- #
+
+# The Windows Win32 platform for library
+
+# For some reason, C-file dependencies have to be before mslib32__.dev
+
+gp_mslib.$(OBJ): gp_mslib.c $(AK)
+ $(CCCWIN) gp_mslib.c
+
+gp_mswin.$(OBJ): gp_mswin.c $(AK) gp_mswin.h \
+ $(ctype__h) $(dos__h) $(malloc__h) $(memory__h) $(string__h) $(windows__h) \
+ $(gx_h) $(gp_h) $(gpcheck_h) $(gserrors_h) $(gsexit_h)
+ $(CCCWIN) gp_mswin.c
+
+gp_win32.$(OBJ): gp_win32.c $(AK) $(stdio__h) $(dos__h) $(string__h) \
+ $(gstypes_h) $(gsmemory_h) $(gp_h) $(gp_sync_h) $(gserror_h) $(gserrors_h)
+ $(CCCWIN) gp_win32.c
+
+gp_ntfs.$(OBJ): gp_ntfs.c $(AK) $(stdio__h) $(dos__h) $(string__h) $(gstypes_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h) $(windows__h)
+ $(CCCWIN) gp_ntfs.c
+
+mslib32__=gp_mslib.$(OBJ) gp_mswin.$(OBJ) gp_win32.$(OBJ) gp_nofb.$(OBJ) \
+ gp_ntfs.$(OBJ)
+
+mslib32_.dev: $(mslib32__) $(ECHOGS_XE)
+ $(SETMOD) mslib32_ $(mslib32__)
+
+# ----------------------------- Main program ------------------------------ #
+
+# The library tester EXE
+$(GS_XE): $(GS_ALL) $(DEVS_ALL) $(LIB_ONLY) $(LIBCTR)
+ copy $(ld_tr) gslib32.tr
+ echo gsnogc.obj >> gslib32.tr
+ echo gconfig.obj >> gslib32.tr
+ echo gscdefs.obj >> gslib32.tr
+ echo /SUBSYSTEM:CONSOLE > gslib32.rsp
+ echo /OUT:$(GS_XE) >> gslib32.rsp
+ $(LINK_SETUP)
+ $(LINK) $(LCT) @gslib32.rsp gslib @gslib32.tr @$(LIBCTR) $(INTASM) @lib.tr
+ -del gslib32.rsp
+ -del gslib32.tr
+
+
+# end of msvclib.mak
diff --git a/gs/src/msvctail.mak b/gs/src/msvctail.mak
new file mode 100644
index 000000000..771bbbdf3
--- /dev/null
+++ b/gs/src/msvctail.mak
@@ -0,0 +1,39 @@
+# Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+# This software is licensed to a single customer by Artifex Software Inc.
+# under the terms of a specific OEM agreement.
+
+# msvctail.mak
+# Common tail section for Microsoft Visual C++ 4.x/5.x,
+# Windows NT or Windows 95 platform.
+# Created 1997-05-22 by L. Peter Deutsch from msvc4/5 makefiles.
+# edited 1997-06-xx by JD to factor out interpreter-specific sections
+
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+ccf32.tr: $(MAKEFILE)
+ echo $(GENOPT) /I$(INCDIR) -DCHECK_INTERRUPTS -D_Windows -D__WIN32__ > ccf32.tr
+
+# Don't create genarch if it's not needed
+!ifdef GENARCH_XE
+$(GENARCH_XE): genarch.c $(stdpre_h) $(iref_h) ccf32.tr
+ $(CCAUX_SETUP)
+ $(CCAUX) @ccf32.tr genarch.c $(CCAUX_TAIL)
+!endif
+
+# -------------------------------- Library -------------------------------- #
+
+# See winlib.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+LIBCTR=libc32.tr
+
+$(LIBCTR): $(MAKEFILE) $(ECHOGS_XE)
+ echo $(LIBDIR)\shell32.lib >$(LIBCTR)
+ echo $(LIBDIR)\comdlg32.lib >>$(LIBCTR)
+ echo $(LIBDIR)\gdi32.lib >>$(LIBCTR)
+ echo $(LIBDIR)\user32.lib >>$(LIBCTR)
+ echo $(LIBDIR)\winspool.lib >>$(LIBCTR)
+
+# end of msvctail.mak
diff --git a/gs/src/mv.cmd b/gs/src/mv.cmd
new file mode 100755
index 000000000..daff17f54
--- /dev/null
+++ b/gs/src/mv.cmd
@@ -0,0 +1 @@
+@rename %1 %2
diff --git a/gs/src/opcheck.h b/gs/src/opcheck.h
new file mode 100644
index 000000000..ef7428c5e
--- /dev/null
+++ b/gs/src/opcheck.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* opcheck.h */
+/* Operand checking for Ghostscript operators */
+/* Requires ialloc.h (for imemory), iref.h, errors.h */
+
+/*
+ * Check the type of an object. Operators almost always use check_type,
+ * which is defined in oper.h; check_type_only is for checking
+ * subsidiary objects obtained from places other than the stack.
+ */
+#define check_type_only(rf,typ)\
+ if ( !r_has_type(&rf,typ) ) return_error(e_typecheck)
+#define check_stype_only(rf,styp)\
+ if ( !r_has_stype(&rf,imemory,styp) ) return_error(e_typecheck)
+/* Check for array */
+#define check_array_else(rf,errstat)\
+ if ( !r_has_type(&rf, t_array) ) errstat
+#define check_array_only(rf)\
+ check_array_else(rf, return_error(e_typecheck))
+/* Check for procedure. check_proc_failed includes the stack underflow */
+/* check, but it doesn't do any harm in the off-stack case. */
+int check_proc_failed(P1(const ref *));
+#define check_proc(rf)\
+ if ( !r_is_proc(&rf) ) return_error(check_proc_failed(&rf));
+#define check_proc_only(rf) check_proc(rf)
+
+/* Check for read, write, or execute access. */
+#define check_access(rf,acc1)\
+ if ( !r_has_attr(&rf,acc1) ) return_error(e_invalidaccess)
+#define check_read(rf) check_access(rf,a_read)
+#define check_write(rf) check_access(rf,a_write)
+#define check_execute(rf) check_access(rf,a_execute)
+#define check_type_access_only(rf,typ,acc1)\
+ if ( !r_has_type_attrs(&rf,typ,acc1) )\
+ return_error((!r_has_type(&rf,typ) ? e_typecheck : e_invalidaccess))
+#define check_read_type_only(rf,typ)\
+ check_type_access_only(rf,typ,a_read)
+#define check_write_type_only(rf,typ)\
+ check_type_access_only(rf,typ,a_write)
+
+/* Check for an integer value within an unsigned bound. */
+#define check_int_leu(orf, u)\
+ check_type(orf, t_integer);\
+ if ( (ulong)(orf).value.intval > (u) ) return_error(e_rangecheck)
+#define check_int_leu_only(rf, u)\
+ check_type_only(rf, t_integer);\
+ if ( (ulong)(rf).value.intval > (u) ) return_error(e_rangecheck)
+#define check_int_ltu(orf, u)\
+ check_type(orf, t_integer);\
+ if ( (ulong)(orf).value.intval >= (u) ) return_error(e_rangecheck)
diff --git a/gs/src/opdef.h b/gs/src/opdef.h
new file mode 100644
index 000000000..4a66d47b9
--- /dev/null
+++ b/gs/src/opdef.h
@@ -0,0 +1,138 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* opdef.h */
+/* Operator definition interface for Ghostscript */
+
+/*
+ * Operator procedures take the pointer to the top of the o-stack
+ * as their argument. They return 0 for success, a negative code
+ * for an error, or a positive code for some uncommon situations (see below).
+ */
+
+/* Structure for initializing the operator table. */
+/*
+ * Each operator file declares an array of these, of the following kind:
+
+BEGIN_OP_DEFS(my_defs) {
+ {"1name", zname},
+ ...
+END_OP_DEFS(iproc) }
+
+ * where iproc is an initialization procedure for the file, or 0.
+ * This definition always appears at the END of the file,
+ * to avoid the need for forward declarations for all the
+ * operator procedures.
+ *
+ * Operators may be stored in dictionaries other than systemdict.
+ * We support this with op_def entries of a special form:
+
+ op_def_begin_dict("dictname"),
+
+ */
+typedef struct {
+ const char _ds *oname;
+ op_proc_p proc;
+} op_def;
+typedef const op_def *op_def_ptr;
+#define op_def_begin_dict(dname) {dname, 0}
+#define op_def_begin_filter() op_def_begin_dict("filterdict")
+#define op_def_begin_level2() op_def_begin_dict("level2dict")
+#define op_def_is_begin_dict(def) ((def)->proc == 0)
+#define op_def_end(iproc) {(char _ds *)0, (op_proc_p)iproc}
+
+/*
+ * We need to define each op_defs table as a procedure that returns
+ * the actual table, because of cross-segment linking restrictions
+ * in the Borland C compiler for MS Windows.
+ */
+
+#define BEGIN_OP_DEFS(xx_op_defs)\
+const op_def *xx_op_defs(P0())\
+{ static const far_data op_def op_defs_[] =
+
+#define END_OP_DEFS(iproc)\
+ op_def_end(iproc)\
+ };\
+ return op_defs_;
+
+/*
+ * Internal operators whose names begin with %, such as continuation
+ * operators, do not appear in systemdict. Ghostscript assumes
+ * that these operators cannot appear anywhere (in executable form)
+ * except on the e-stack; to maintain this invariant, the execstack
+ * operator converts them to literal form, and cvx refuses to convert
+ * them back. As a result of this invariant, they do not need to
+ * push themselves back on the e-stack when executed, since the only
+ * place they could have come from was the e-stack.
+ */
+#define op_def_is_internal(def) ((def)->oname[1] == '%')
+
+/*
+ * All operators are catalogued in a table; this is necessary because
+ * they must have a short packed representation for the sake of 'bind'.
+ * The `size' of an operator is normally its index in this table;
+ * however, internal operators have a `size' of 0, and their true index
+ * must be found by searching the table for their procedure address.
+ */
+ushort op_find_index(P1(const ref *));
+#define op_index(opref)\
+ (r_size(opref) == 0 ? op_find_index(opref) : r_size(opref))
+/*
+ * There are actually two kinds of operators: the real ones (t_operator),
+ * and ones defined by procedures (t_oparray). The catalog for t_operators
+ * is op_def_table, and their index is in the range [1..op_def_count-1].
+ */
+#define op_index_is_operator(index) ((index) < op_def_count)
+/*
+ * Because of a bug in Sun's SC1.0 compiler,
+ * we have to spell out the typedef for op_def_ptr here:
+ */
+extern const op_def **op_def_table;
+extern uint op_def_count;
+#define op_num_args(opref) (op_def_table[op_index(opref)]->oname[0] - '0')
+#define op_index_proc(index) (op_def_table[index]->proc)
+/*
+ * There are two catalogs for t_oparrays, one global and one local.
+ * Operator indices for the global table are in the range
+ * [op_def_count..op_def_count+op_array_global.count-1]
+ * Operator indices for the local table are in the range
+ * [op_def_count+r_size(&op_array_global.table)..
+ * op_def_count+r_size(&op_array_global.table)+op_array_local.count-1]
+ */
+typedef struct op_array_table_s {
+ ref table; /* t_array */
+ ushort *nx_table; /* name indices */
+ uint count; /* # of occupied entries */
+ uint base_index; /* operator index of first entry */
+ uint attrs; /* ref attrs of ops in this table */
+ ref *root_p; /* self-pointer for GC root */
+} op_array_table;
+extern op_array_table
+ op_array_table_global,
+ op_array_table_local;
+#define op_index_op_array_table(index)\
+ ((index) < op_array_table_local.base_index ?\
+ &op_array_table_global : &op_array_table_local)
+
+/*
+ * Convert an operator index to an operator or oparray ref.
+ * This is only used for debugging and for 'get' from packed arrays,
+ * so it doesn't have to be very fast.
+ */
+void op_index_ref(P2(uint, ref *));
diff --git a/gs/src/openvms.mak b/gs/src/openvms.mak
new file mode 100644
index 000000000..b6625d344
--- /dev/null
+++ b/gs/src/openvms.mak
@@ -0,0 +1,402 @@
+# Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for OpenVMS VAX and Alpha
+#
+# Please contact Jim Dunham (dunham@omtool.com) if you have questions.
+#
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# on the make command line specify:
+# make -fopenvms.mak "OPENVMS={VAX,ALPHA}" "DECWINDOWS={1.2,<blank>}"
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+GS_DOCDIR=GS_DOC
+#GS_DOCDIR=SYS$COMMON:[GS]
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with ,.
+
+GS_LIB_DEFAULT=GS_LIB
+#GS_LIB_DEFAULT=SYS$COMMON:[GS],SYS$COMMON:[GS.FONT]
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=GS_INIT.PS
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features in the code
+
+DEBUG=
+
+# Setting TDEBUG=1 includes symbol table information for the debugger,
+# and also enables stack tracing on failure.
+
+TDEBUG=
+
+# Setting CDEBUG=1 enables 'C' compiler debugging and turns off optimization
+# Code is substantially slower and larger.
+
+CDEBUG=
+
+# Define the name of the executable file.
+
+GS=GS
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=[.jpeg-6a]
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=[.libpng-0_96]
+PVERSION=96
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=[.zlib-1_0_4]
+
+# Note that built-in libpng and zlib aren't available.
+
+SHARE_LIBPNG=0
+SHARE_ZLIB=0
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# Define the path to X11 include files
+
+X_INCLUDE=DECW$$INCLUDE
+
+# ------ Platform-specific options ------ #
+
+# Define the drive, directory, and compiler name for the 'C' compiler.
+# COMP is the full compiler path name.
+
+COMP=CC
+
+ifdef DEBUG
+COMP:=$(COMP)/DEBUG/NOOPTIMIZE
+else
+COMP:=$(COMP)/NODEBUG/OPTIMIZE
+endif
+
+ifeq "$(OPENVMS)" "VAX"
+COMP:=$(COMP)/VAXC
+else
+COMP:=$(COMP)/DECC/PREFIX=ALL/NESTED_INCLUDE=PRIMARY
+endif
+
+# Define any other compilation flags.
+# Including defines for A4 paper size
+
+ifdef A4_PAPER
+COMP:=$(COMP)/DEFINE=("A4")
+endif
+
+# LINK is the full linker path name
+
+ifdef LDEBUG
+LINKER=LINK/DEBUG/TRACEBACK
+else
+LINKER=LINK/NODEBUG/NOTRACEBACK
+endif
+
+# INCDIR contains the include files
+INCDIR=
+
+# LIBDIR contains the library files
+LIBDIR=
+
+# ------ Devices and features ------ #
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Define the name table capacity size of 2^(16+n).
+
+EXTEND_NAMES=0
+
+# Define the platform name.
+
+PLATFORM=openvms_
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=openvms.mak
+
+# Define the platform options
+
+PLATOPT=
+
+# Patch a couple of PC-specific things that aren't relevant to OpenVMS builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
+
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+
+# Define the suffix for command files (e.g., null or .bat).
+
+CMD=
+
+# Define the directory separator character (\ for MS-DOS, / for Unix,
+# nothing for OpenVMS).
+
+D=
+
+# Define the string for specifying the output file from the C compiler.
+
+O=/OBJECT=
+
+# Define the extension for executable files (e.g., null or .exe).
+
+XE=.exe
+
+# Define the extension for executable files for the auxiliary programs
+# (e.g., null or .exe).
+
+XEAUX=.exe
+
+# Define the list of files that `make begin' and `make clean' remove.
+
+BEGINFILES=OPENVMS.OPT OPENVMS.COM
+
+# Define the C invocation for the ansi2knr program. We don't use this.
+
+CCA2K=
+
+# Define the C invocation for auxiliary programs (echogs, genarch).
+# We don't need to define this separately.
+
+CCAUX=
+
+# Define the compilation command for `make begin'. We don't use this.
+
+CCBEGIN=
+
+# Define the C invocation for normal compilation.
+
+CC=$(COMP)/OBJECT=$@ $<
+
+# Define the Link invocation.
+
+LINK=$(LINKER)/MAP/EXE=$@ $^,OPENVMS.OPT/OPTION
+
+# Define the ANSI-to-K&R dependency. We don't need this.
+
+AK=
+
+# Define the syntax for command, object, and executable files.
+
+OBJ=obj
+
+# Define the current directory prefix for image invocations.
+
+EXPP=
+EXP=MCR []
+
+# Define the current directory prefix for shell invocations.
+
+SH=
+SHP=
+
+# Define generic commands.
+
+CP_=$$ @COPY_ONE
+
+# Define the command for deleting (a) file(s) (including wild cards)
+
+RM_=$$ @RM_ONE
+
+# Define the command for deleting multiple files / patterns.
+
+RMN_=$$ @RM_ALL
+
+# Define the arguments for genconf.
+
+CONFILES=-p %s -o $(ld_tr)
+
+# Define the generic compilation rules.
+
+.suffixes: .c .obj .exe
+
+.c.obj:
+ $(CC)
+
+.obj.exe:
+ $(LINK)
+
+# ---------------------------- End of options ---------------------------- #
+
+
+# ------------------- Include the generic makefiles ---------------------- #
+
+include version.mak
+include gs.mak
+include lib.mak
+include jpeg.mak
+include libpng.mak
+include zlib.mak
+include devs.mak
+include int.mak
+
+# Define various incantations of the 'c' compiler.
+
+CCC=$(COMP)/OBJECT=$@
+CCCF=$(CCC)
+CCCJ=$(CCC)/INCLUDE=($(JSRCDIR))
+CCCZ=$(CCC)/INCLUDE=($(ZSRCDIR))
+CCCP=$(CCC)/INCLUDE=($(ZSRCDIR),$(PSRCDIR))
+CCINT=$(CCC)
+CCLEAF=$(CCC)
+
+# ----------------------------- Main program ------------------------------ #
+
+$(GS_XE): openvms gs.$(OBJ) $(INT_ALL) $(LIB_ALL)
+ $(LINKER)/MAP/EXE=$@ gs.$(OBJ),$(ld_tr)/OPTIONS,OPENVMS.OPT/OPTION
+
+# OpenVMS.dev
+
+openvms__=gp_vms.$(OBJ) gp_nofb.$(OBJ)
+openvms_.dev: $(openvms__)
+ $(SETMOD) openvms_ $(openvms__)
+
+# Interpreter AUX programs
+
+$(ECHOGS_XE): echogs.$(OBJ)
+$(GENARCH_XE): genarch.$(OBJ)
+$(GENCONF_XE): genconf.$(OBJ)
+$(GENINIT_XE): geninit.$(OBJ)
+
+# Preliminary definitions
+
+openvms: openvms.com openvms.opt
+ $$ @OPENVMS
+
+openvms.com: append_l.com
+ $$ @APPEND_L $@ "$$ DEFINE/JOB X11 $(X_INCLUDE)"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB GS_LIB ''F$$ENVIRONMENT(""DEFAULT"")'"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB GS_DOC ''F$$ENVIRONMENT(""DEFAULT"")'"
+ifeq "$(OPENVMS)" "VAX"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB C$$INCLUDE ''F$$ENVIRONMENT(""DEFAULT"")', DECW$$INCLUDE, SYS$$LIBRARY"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB VAXC$$INCLUDE C$$INCLUDE"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB SYS SYS$$LIBRARY"
+else
+ $$ @APPEND_L $@ "$$ DEFINE/JOB DECC$$USER_INCLUDE ''F$$ENVIRONMENT(""DEFAULT"")', DECW$$INCLUDE, DECC$$LIBRARY_INCLUDE, SYS$$LIBRARY"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB DECC$$SYSTEM_INCLUDE ''F$$ENVIRONMENT(""DEFAULT"")', DECW$$INCLUDE, DECC$$LIBRARY_INCLUDE, SYS$$LIBRARY"
+ $$ @APPEND_L $@ "$$ DEFINE/JOB SYS "DECC$$LIBRARY_INCLUDE,SYS$$LIBRARY"
+endif
+
+openvms.opt:
+ifeq "$(OPENVMS)" "VAX"
+ $$ @APPEND_L $@ "SYS$$SHARE:VAXCRTL.EXE/SHARE"
+endif
+ifeq "$(DECWINDOWS)" "1.2"
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XMLIBSHR12.EXE/SHARE"
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XTLIBSHRR5.EXE/SHARE"
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XLIBSHR.EXE/SHARE"
+else
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XMLIBSHR.EXE/SHARE"
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XTSHR.EXE/SHARE"
+ $$ @APPEND_L $@ "SYS$$SHARE:DECW$$XLIBSHR.EXE/SHARE"
+endif
+ $$ @APPEND_L $@ ""Ident="""""GS $(GS_DOT_VERSION)"""""
+
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+gconfig_.h: $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfig_.h -x 23 define "HAVE_SYS_TIME_H"
+
+gconfigv.h: $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define "USE_ASM" 0
+ $(EXP)echogs -a gconfigv.h -x 23 define "USE_FPU" 1
+ $(EXP)echogs -a gconfigv.h -x 23 define "EXTEND_NAMES" 0$(EXTEND_NAME)
diff --git a/gs/src/oper.h b/gs/src/oper.h
new file mode 100644
index 000000000..35ccd65ea
--- /dev/null
+++ b/gs/src/oper.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* oper.h */
+/* Definitions for Ghostscript operators */
+#include "ostack.h"
+#include "opdef.h"
+#include "opextern.h"
+#include "opcheck.h"
+#include "iutil.h"
+
+/*
+ * In order to combine typecheck and stackunderflow error checking
+ * into a single test, we guard the bottom of the o-stack with
+ * additional entries of type t__invalid. However, if a type check fails,
+ * we must make an additional check to determine which error
+ * should be reported. In order not to have to make this check in-line
+ * in every type check in every operator, we define a procedure that takes
+ * an o-stack pointer and returns e_stackunderflow if it points to
+ * a guard entry, e_typecheck otherwise.
+ *
+ * Note that we only need to do this for typecheck, not for any other
+ * kind of error such as invalidaccess, since any operator that can
+ * generate the latter will do a check_type or a check_op first.
+ * (See ostack.h for more information.)
+ *
+ * We define the operand type of check_type_failed as const ref * rather than
+ * const_os_ptr simply because there are a number of routines that might
+ * be used either with a stack operand or with a general operand, and
+ * the check for t__invalid is harmless when applied to off-stack refs.
+ */
+int check_type_failed(P1(const ref *));
+
+/*
+ * Check the type of an object. Operators almost always use check_type,
+ * which includes the stack underflow check described just above;
+ * check_type_only is for checking subsidiary objects obtained from
+ * places other than the stack.
+ */
+#define return_op_typecheck(op)\
+ return_error(check_type_failed(op))
+#define check_type(orf,typ)\
+ if ( !r_has_type(&orf,typ) ) return_op_typecheck(&orf)
+#define check_stype(orf,styp)\
+ if ( !r_has_stype(&orf,imemory,styp) ) return_op_typecheck(&orf)
+#define check_array(orf)\
+ check_array_else(orf, return_op_typecheck(&orf))
+#define check_type_access(orf,typ,acc1)\
+ if ( !r_has_type_attrs(&orf,typ,acc1) )\
+ return_error((!r_has_type(&orf,typ) ? check_type_failed(&orf) :\
+ e_invalidaccess))
+#define check_read_type(orf,typ)\
+ check_type_access(orf,typ,a_read)
+#define check_write_type(orf,typ)\
+ check_type_access(orf,typ,a_write)
+
+/* Macro for as yet unimplemented operators. */
+/* The if ( 1 ) is to prevent the compiler from complaining about */
+/* unreachable code. */
+#define NYI(msg) if ( 1 ) return_error(e_undefined)
+
+/*
+ * If an operator has popped or pushed something on the control stack,
+ * it must return o_pop_estack or o_push_estack respectively,
+ * rather than 0, to indicate success.
+ * It is OK to return o_pop_estack if nothing has been popped,
+ * but it is not OK to return o_push_estack if nothing has been pushed.
+ *
+ * If an operator has suspended the current context and wants the
+ * interpreter to call the scheduler, it must return o_reschedule.
+ * It may also have pushed or popped elements on the control stack.
+ * (This is only used when the Display PostScript option is included.)
+ *
+ * These values must be greater than 1, and far enough apart from zero and
+ * from each other not to tempt a compiler into implementing a 'switch'
+ * on them using indexing rather than testing.
+ */
+#define o_push_estack 5
+#define o_pop_estack 14
+#define o_reschedule 22
diff --git a/gs/src/opextern.h b/gs/src/opextern.h
new file mode 100644
index 000000000..8577745d5
--- /dev/null
+++ b/gs/src/opextern.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* opextern.h */
+/* Externally accessible operator declarations */
+
+/*
+ * Normally, the procedures that implement PostScript operators (named zX
+ * where X is the name of the operator, e.g., zadd) are private to the
+ * file in which they are defined. There are, however, a surprising
+ * number of these procedures that are used from other files.
+ * This file, opextern.h, declares all z* procedures that are
+ * - referenced from outside their defining file, and
+ * - present in *all* configurations of the interpreter.
+ * For z* procedures referenced from outside their file but not present
+ * in all configurations (e.g., Level 2 operators), the file making the
+ * reference must include a local extern. Not pretty, but c'est la vie.
+ */
+
+/* Operators exported for the special operator encoding in interp.c. */
+int zadd(P1(os_ptr));
+int zdef(P1(os_ptr));
+int zdup(P1(os_ptr));
+int zexch(P1(os_ptr));
+int zif(P1(os_ptr));
+int zifelse(P1(os_ptr));
+int zindex(P1(os_ptr));
+int zpop(P1(os_ptr));
+int zroll(P1(os_ptr));
+int zsub(P1(os_ptr));
+
+/* Operators exported for server loop implementations. */
+int zflush(P1(os_ptr));
+int zflushpage(P1(os_ptr));
+int zsave(P1(os_ptr));
+int zrestore(P1(os_ptr));
+
+/* Operators exported for save/restore. */
+int zgsave(P1(os_ptr));
+int zgrestore(P1(os_ptr));
+
+/* Operators exported for Level 2 pagedevice facilities. */
+int zcopy_gstate(P1(os_ptr));
+int zcurrentgstate(P1(os_ptr));
+int zgrestoreall(P1(os_ptr));
+int zgstate(P1(os_ptr));
+int zreadonly(P1(os_ptr));
+int zsetdevice(P1(os_ptr));
+int zsetgstate(P1(os_ptr));
+
+/* Operators exported for Level 2 "wrappers". */
+int zimage(P1(os_ptr));
+int zimagemask(P1(os_ptr));
+int zwhere(P1(os_ptr));
+
+/* Operators exported for specific-VM operators. */
+int zarray(P1(os_ptr));
+int zdict(P1(os_ptr));
+int zpackedarray(P1(os_ptr));
+int zstring(P1(os_ptr));
+
+/* Operators exported for user path decoding. */
+/* Note that only operators defined in all configurations are declared here. */
+int zclosepath(P1(os_ptr));
+int zcurveto(P1(os_ptr));
+int zlineto(P1(os_ptr));
+int zmoveto(P1(os_ptr));
+int zrcurveto(P1(os_ptr));
+int zrlineto(P1(os_ptr));
+int zrmoveto(P1(os_ptr));
+
+/* Operators exported for CIE cache loading. */
+int zcvx(P1(os_ptr));
+int zexec(P1(os_ptr)); /* also for .runexec */
+int zfor(P1(os_ptr));
+
+/* Odds and ends */
+int zbegin(P1(os_ptr));
+int zcleartomark(P1(os_ptr));
+int zend(P1(os_ptr));
+int zclosefile(P1(os_ptr)); /* for runexec_cleanup */
+int zsetfont(P1(os_ptr)); /* for cshow_continue */
+
+/* Operators exported for special customer needs. */
+int zcurrentdevice(P1(os_ptr));
+int ztoken(P1(os_ptr));
+int ztokenexec(P1(os_ptr));
+int zwrite(P1(os_ptr));
diff --git a/gs/src/os2.mak b/gs/src/os2.mak
new file mode 100644
index 000000000..434d97f89
--- /dev/null
+++ b/gs/src/os2.mak
@@ -0,0 +1,553 @@
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for MS-DOS or OS/2 GCC/EMX platform.
+# Uses Borland (MSDOS) MAKER or
+# Uses IBM NMAKE.EXE Version 2.000.000 Mar 27 1992
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+GS_DOCDIR=c:/gs
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with ;.
+# Use / to indicate directories, not a single \.
+
+GS_LIB_DEFAULT=c:/gs;c:/gs/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+DEBUG=0
+
+# Setting GDEBUG=1 includes symbol table information for GDB.
+# Produces larger .OBJ and .EXE files.
+
+GDEBUG=0
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+NOPRIVATE=0
+
+# Setting MAKEDLL=1 makes the target a DLL instead of an EXE
+MAKEDLL=1
+
+# Setting EMX=1 uses GCC/EMX
+# Setting IBMCPP=1 uses IBM C++
+EMX=1
+IBMCPP=0
+
+# Define the name of the executable file.
+
+GS=gsos2
+GSDLL=gsdll2
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# If you don't have an assembler, set USE_ASM=0. Otherwise, set USE_ASM=1,
+# and set ASM to the name of the assembler you are using. This can be
+# a full path name if you want. Normally it will be masm or tasm.
+
+USE_ASM=0
+ASM=
+
+# Define the drive, directory, and compiler name for the EMX files.
+# COMP is the compiler name (gcc)
+# COMPDIR contains the compiler and linker (normally \emx\bin).
+# EMXPATH contains the path to the EMX directory (normally /emx)
+# INCDIR contains the include files (normally /emx/include).
+# LIBDIR contains the library files (normally /emx/lib).
+# Note that these prefixes are always followed by a \,
+# so if you want to use the current directory, use an explicit '.'.
+
+!if $(EMX)
+COMP=gcc
+COMPBASE=\emx
+EMXPATH=/emx
+COMPDIR=$(COMPBASE)\bin
+INCDIR=$(EMXPATH)/include
+LIBDIR=$(EMXPATH)/lib
+!endif
+
+!if $(IBMCPP)
+COMP=icc /Q
+COMPBASE=\ibmcpp
+TOOLPATH=\toolkit
+COMPDIR=$(COMPBASE)\bin
+INCDIR=$(TOOLPATH)\h;$(COMPBASE)\include
+LIBDIR=$(TOOLPATH)\lib;$(COMPBASE)\lib
+!endif
+
+# Choose platform-specific options.
+
+# Define the processor (CPU) type. Options are 86 (8086 or 8088),
+# 186, 286, 386, 485 (486SX or Cyrix 486SLC), 486 (486DX), or 586 (Pentium).
+# Higher numbers produce code that may be significantly smaller and faster,
+# but the executable will bail out with an error message on any processor
+# less capable than the designated one.
+
+# EMX requires 386 or higher
+CPU_TYPE=386
+
+# Define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If CPU_TYPE is 486 or above, FPU_TYPE is implicitly set to 387,
+# since 486DX and later processors include the equivalent of an 80387 on-chip.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+FPU_TYPE=0
+
+# ---------------------------- End of options ---------------------------- #
+
+# Note that built-in libpng and zlib aren't available.
+
+SHARE_LIBPNG=0
+SHARE_ZLIB=0
+
+# Swapping `make' out of memory makes linking much faster.
+# only used by Borland MAKER.EXE
+
+#.swap
+
+# Define the platform name.
+
+PLATFORM=os2_
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=os2.mak
+
+# Define the files to be deleted by 'make begin' and 'make clean'.
+
+BEGINFILES=gspmdrv.exe gs*.res gs*.ico $(GSDLL).dll
+
+# Define the ANSI-to-K&R dependency.
+
+AK=
+
+#Compiler Optimiser option
+!if $(EMX)
+CO=-O
+!endif
+!if $(IBMCPP)
+#CO=/O+
+CO=/O-
+!endif
+
+# Make sure we get the right default target for make.
+
+dosdefault: default gspmdrv.exe
+
+# Define a rule for invoking just the preprocessor.
+
+.c.i:
+ $(COMPDIR)\cpp $(CCFLAGS) $<
+
+# Define the extensions for command, object, and executable files.
+
+CMD=.cmd
+O=-o ./
+!if $(MAKEDLL)
+OBJ=obj
+!else
+OBJ=o
+!endif
+XE=.exe
+XEAUX=.exe
+
+# Define the current directory prefix, shell quote string, and shell name.
+
+D=\#
+
+EXP=
+QQ="
+SH=
+SHP=
+
+# Define generic commands.
+
+# We use cp.cmd rather than copy /B so that we update the write date.
+CP_=cp.cmd
+# We use rm.cmd rather than erase because rm.cmd never generates
+# a non-zero return code.
+RM_=rm.cmd
+# OS/2 erase, unlike MS-DOS erase, accepts multiple files or patterns.
+RMN_=rm.cmd
+
+# Define the arguments for genconf.
+
+!if $(MAKEDLL)
+CONFILES=-p %%s+ -o $(ld_tr) -l lib.tr
+!else
+CONFILES=-o $(ld_tr) -l lib.tr
+!endif
+
+# Define the generic compilation flags.
+
+!if $(CPU_TYPE) >= 486
+ASMCPU=/DFOR80386 /DFOR80486
+PLATOPT=-DFOR80386 -DFOR80486
+!else
+!if $(CPU_TYPE) >= 386
+ASMCPU=/DFOR80386
+PLATOPT=-DFOR80386
+!endif
+!endif
+
+!if $(FPU_TYPE) > 0
+ASMFPU=/DFORFPU
+!else
+ASMFPU=
+!endif
+
+!if $(USE_ASM)
+INTASM=iutilasm.$(OBJ)
+PCFBASM=gdevegaa.$(OBJ)
+!else
+INTASM=
+PCFBASM=
+!endif
+
+# Define the generic compilation rules.
+
+ASMFLAGS=$(ASMCPU) $(ASMFPU) $(ASMDEBUG)
+
+.asm.o:
+ $(ASM) $(ASMFLAGS) $<;
+
+# ---------------------- MS-DOS I/O debugging option ---------------------- #
+
+dosio_=zdosio.$(OBJ)
+dosio.dev: $(dosio_)
+ $(SETMOD) dosio $(dosio_)
+ $(ADDMOD) dosio -oper zdosio
+
+zdosio.$(OBJ): zdosio.c $(OP) $(store_h)
+
+# ----------------------------- Assembly code ----------------------------- #
+
+iutilasm.$(OBJ): iutilasm.asm
+
+################# END
+
+# Define the compilation flags.
+
+!if $(NOPRIVATE)
+CP=-DNOPRIVATE
+!else
+CP=
+!endif
+
+!if $(DEBUG)
+CD=-DDEBUG
+!else
+CD=
+!endif
+
+!if $(GDEBUG)
+!if $(EMX)
+CGDB=-g
+!endif
+!if $(IBMCPP)
+CGDB=/Ti+
+!endif
+!else
+CGDB=
+!endif
+
+!if $(MAKEDLL)
+!if $(EMX)
+CDLL=-Zdll -Zso -Zsys -Zomf -D__DLL__
+!endif
+!if $(IBMCPP)
+CDLL=/Gd- /Ge- /Gm+ /Gs+ /D__DLL__
+!endif
+!else
+CDLL=
+!endif
+
+GENOPT=$(CP) $(CD) $(CGDB) $(CDLL) $(CO)
+
+CCFLAGS0=$(GENOPT) $(PLATOPT)
+CCFLAGS=$(CCFLAGS0)
+CC=$(COMPDIR)\$(COMP) $(CCFLAGS0)
+CCC=$(CC) -c
+CCD=$(CC) $(CO) -c
+CCCF=$(COMPDIR)\$(COMP) $(CO) $(CCFLAGS0) -c
+CCINT=$(CC) -c
+CCLEAF=$(CCC)
+
+.c.o:
+# $(CCC) { $<}
+ $(CCC) $<
+
+.c.obj:
+ $(CCC) $<
+
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+# Since we have a large address space, we include some optional features.
+
+FEATURE_DEVS=level2.dev pdf.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+!if $(MAKEDLL)
+DEVICE_DEVS=os2pm.dev os2dll.dev os2prn.dev
+!else
+DEVICE_DEVS=os2pm.dev
+!endif
+#DEVICE_DEVS1=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS2=epson.dev eps9high.dev eps9mid.dev epsonc.dev ibmpro.dev
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=djet500c.dev declj250.dev lj250.dev jetp3852.dev r4081.dev t4693d2.dev t4693d4.dev t4693d8.dev tek4696.dev lbp8.dev uniprint.dev
+DEVICE_DEVS6=st800.dev stcolor.dev bj10e.dev bj200.dev bjc600.dev bjc800.dev m8510.dev necp6.dev
+DEVICE_DEVS7=dfaxhigh.dev dfaxlow.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=bmpmono.dev bmp16.dev bmp256.dev bmp16m.dev tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev
+
+# Include the generic makefiles.
+!include "version.mak"
+!include "gs.mak"
+!include "lib.mak"
+!include "jpeg.mak"
+!include "libpng.mak"
+!include "zlib.mak"
+!include "devs.mak"
+!include "int.mak"
+
+# -------------------------------- Library -------------------------------- #
+
+# The GCC/EMX platform
+
+os2__=gp_nofb.$(OBJ) gp_os2.$(OBJ)
+os2_.dev: $(os2__)
+ $(SETMOD) os2_ $(os2__)
+!if $(MAKEDLL)
+# Using a file device resource to get the console streams re-initialized
+# is bad architecture (an upward reference to ziodev),
+# but it will have to do for the moment.
+# We need to redirect stdin/out/err to gsdll_callback
+ $(ADDMOD) os2_ -iodev wstdio
+!endif
+
+
+gp_os2.$(OBJ): gp_os2.c $(dos__h) $(string__h) $(time__h) $(gsdll_h) \
+ $(gx_h) $(gsexit_h) $(gsutil_h) $(gp_h)
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+CCAUX=$(COMPDIR)\$(COMP) $(CO)
+
+$(ECHOGS_XE): echogs.c
+!if $(EMX)
+ $(CCAUX) -o echogs echogs.c
+ $(COMPDIR)\emxbind $(EMXPATH)/bin/emxl.exe echogs echogs.exe
+ del echogs
+!endif
+!if $(IBMCPP)
+ $(CCAUX) /Feechogs.exe echogs.c
+!endif
+
+$(GENARCH_XE): genarch.c $(stdpre_h)
+!if $(EMX)
+ $(CCAUX) -o genarch genarch.c
+ $(COMPDIR)\emxbind $(EMXPATH)/bin/emxl.exe genarch genarch.exe
+ del genarch
+!endif
+!if $(IBMCPP)
+ $(CCAUX) /Fegenarch genarch.c
+!endif
+
+$(GENCONF_XE): genconf.c $(stdpre_h)
+!if $(EMX)
+ $(CCAUX) -o genconf genconf.c
+ $(COMPDIR)\emxbind $(EMXPATH)/bin/emxl.exe genconf genconf.exe
+ del genconf
+!endif
+!if $(IBMCPP)
+ $(CCAUX) /Fegenconf genconf.c
+!endif
+
+$(GENINIT_XE): geninit.c $(stdio__h) $(string__h)
+!if $(EMX)
+ $(CCAUX) -o geninit geninit.c
+ $(COMPDIR)\emxbind $(EMXPATH)/bin/emxl.exe geninit geninit.exe
+ del geninit
+!endif
+!if $(IBMCPP)
+ $(CCAUX) /Fegeninit geninit.c
+!endif
+
+# No special gconfig_.h is needed.
+gconfig_.h: os2.mak $(ECHOGS_XE)
+ echogs -w gconfig_.h /* This file deliberately left blank. */
+
+gconfigv.h: os2.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# ----------------------------- Main program ------------------------------ #
+
+CCBEGIN=$(CCC) *.c
+
+# Interpreter main program
+
+ICONS=gsos2.ico gspmdrv.ico
+
+!if $(MAKEDLL)
+#making a DLL
+GS_ALL=gsdll.$(OBJ) $(INT_ALL) $(INTASM)\
+ $(LIB_ALL) $(LIBCTR) $(ld_tr) lib.tr $(GS).res $(ICONS)
+
+$(GS_XE): $(GSDLL).dll dpmainc.c gsdll.h gsos2.rc gscdefs.$(OBJ)
+!if $(EMX)
+ $(COMPDIR)\gcc $(CGDB) $(CO) -Zomf -o$(GS_XE) dpmainc.c gscdefs.$(OBJ) gsos2.def
+!endif
+!if $(IBMCPP)
+ $(CCAUX) /Fe$(GX_XE) dpmainc.c gscdefs.$(OBJ)
+!endif
+ rc gsos2.res $(GS_XE)
+
+gsdll.$(OBJ): gsdll.c gsdll.h $(ghost_h)
+
+$(GSDLL).dll: $(GS_ALL) $(ALL_DEVS) gsdll.$(OBJ)
+!if $(EMX)
+ LINK386 /DEBUG $(COMPBASE)\lib\dll0.obj $(COMPBASE)\lib\end.lib @$(ld_tr) gsdll.obj, $(GSDLL).dll, ,$(COMPBASE)\lib\gcc.lib $(COMPBASE)\lib\st\c.lib $(COMPBASE)\lib\st\c_dllso.lib $(COMPBASE)\lib\st\sys.lib $(COMPBASE)\lib\c_alias.lib $(COMPBASE)\lib\os2.lib, gsdll2.def
+!endif
+!if $(IBMCPP)
+ LINK386 /NOE /DEBUG @$(ld_tr) gsdll.obj, $(GSDLL).dll, , , gsdll2.def
+!endif
+
+!else
+#making an EXE
+GS_ALL=gs.$(OBJ) $(INT_ALL) $(INTASM)\
+ $(LIB_ALL) $(LIBCTR) $(ld_tr) lib.tr $(GS).res $(ICONS)
+
+$(GS_XE): $(GS_ALL) $(ALL_DEVS)
+ $(COMPDIR)\gcc $(CGDB) -o $(GS) gs.$(OBJ) @$(ld_tr) $(INTASM) -lm
+ $(COMPDIR)\emxbind -r$*.res $(COMPDIR)\emxl.exe $(GS) $(GS_XE) -ac
+ del $(GS)
+!endif
+
+# Make the icons from their text form.
+
+gsos2.ico: gsos2.icx $(ECHOGS_XE)
+ echogs -wb gsos2.ico -n -X -r gsos2.icx
+
+gspmdrv.ico: gspmdrv.icx $(ECHOGS_XE)
+ echogs -wb gspmdrv.ico -n -X -r gspmdrv.icx
+
+$(GS).res: $(GS).rc gsos2.ico
+ rc -i $(COMPBASE)\include -r $*.rc
+
+# PM driver program
+
+gspmdrv.o: gspmdrv.c gspmdrv.h
+ $(COMPDIR)\gcc $(CGDB) $(CO) -c $*.c
+
+gspmdrv.res: gspmdrv.rc gspmdrv.h gspmdrv.ico
+ rc -i $(COMPBASE)\include -r $*.rc
+
+gspmdrv.exe: gspmdrv.o gspmdrv.res gspmdrv.def
+ $(COMPDIR)\gcc $(CGDB) $(CO) -o $* $*.o
+ $(COMPDIR)\emxbind -p -r$*.res -d$*.def $(COMPDIR)\emxl.exe $* $*.exe
+ del $*
diff --git a/gs/src/ostack.h b/gs/src/ostack.h
new file mode 100644
index 000000000..54e8e5a34
--- /dev/null
+++ b/gs/src/ostack.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 1991, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ostack.h */
+/* Definitions for Ghostscript operand stack */
+
+#ifndef ostack_INCLUDED
+# define ostack_INCLUDED
+
+#include "istack.h"
+
+/* Define the operand stack pointers. */
+typedef s_ptr os_ptr;
+typedef const_s_ptr const_os_ptr;
+extern ref_stack o_stack;
+#define osbot (o_stack.bot)
+#define osp (o_stack.p)
+#define ostop (o_stack.top)
+
+/* Macro to ensure enough room on the operand stack */
+#define check_ostack(n)\
+ if ( ostop - osp < (n) )\
+ { o_stack.requested = (n); return_error(e_stackoverflow); }
+
+/* Operand stack manipulation. */
+
+/* Note that push sets osp to (the new value of) op. */
+/* The do... avoids problems with a possible enclosing 'if'. */
+#define push(n)\
+ do { if ( (op += (n)) > ostop )\
+ { o_stack.requested = (n); return_error(e_stackoverflow); }\
+ else osp = op;\
+ } while (0)
+
+/*
+ * Note that the pop macro only decrements osp, not op. For this reason,
+ *
+ * >>> pop should only be used just before returning, <<<
+ * >>> or else op must be decremented explicitly. <<<
+ */
+#define pop(n) (osp -= (n))
+
+/*
+ * Note that the interpreter does not check for operand stack underflow
+ * before calling the operator procedure. There are "guard" entries
+ * with invalid types and attributes just below the bottom of the
+ * operand stack: if the operator returns with a typecheck error,
+ * the interpreter checks for underflow at that time.
+ * Operators that don't typecheck their arguments must check for
+ * operand stack underflow explicitly; operators that take a variable
+ * number of arguments must also check for stack underflow in those cases
+ * where they expect more than their minimum number of arguments.
+ * (This is because the interpreter can only recognize that a typecheck
+ * is really a stackunderflow when the stack has fewer than the
+ * operator's declared minimum number of entries.)
+ */
+#define check_op(nargs)\
+ if ( op < osbot + ((nargs) - 1) ) return_error(e_stackunderflow)
+/*
+ * Similarly, in order to simplify some overflow checks, we allocate
+ * a few guard entries just above the top of the o-stack.
+ */
+
+/*
+ * The operand stack is implemented as a linked list of blocks;
+ * operators that can push or pop an unbounded number of values, or that
+ * access the entire o-stack, must take this into account. These are:
+ * (int)copy index roll clear count cleartomark
+ * counttomark aload astore packedarray
+ * getdeviceprops putdeviceprops
+ */
+
+#endif /* ostack_INCLUDED */
diff --git a/gs/src/overlay.h b/gs/src/overlay.h
new file mode 100644
index 000000000..4a63eab7b
--- /dev/null
+++ b/gs/src/overlay.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* overlay.h */
+/* Overlay definitions for MS-DOS / Borland C++ version of Ghostscript */
+
+/* Parameters used for initialization. */
+/* K bytes to use for overlay buffer */
+/* *** NOTE: Performance will be unacceptable with OVLBUFK < 200. */
+#ifndef OVLBUFK /* might be set in makefile */
+# define OVLBUFK 120
+#endif
+
+/* parameters for EMS memory */
+/* #define OVEMS */ /* define this to enable use of EMS memory for overlays */
+#define OVEMS_HANDLE 0 /* handle argument to _OvrInitEms */
+#define OVEMS_FIRST 0 /* first argument to _OvrInitEms */
+#define OVEMS_PAGES 0 /* pages argument to _OvrInitEms */
+
+/* parameters for extended memory; note that start and length must be longs! */
+/* #define OVEXT /* define this to enable use of extended memory for overlays */
+#define OVEXT_START 0L /* start argument to _OvrInitExt */
+#define OVEXT_LENGTH 0L /* length argument to _OvrInitExt */
diff --git a/gs/src/rm.cmd b/gs/src/rm.cmd
new file mode 100755
index 000000000..ec73ac552
--- /dev/null
+++ b/gs/src/rm.cmd
@@ -0,0 +1,9 @@
+@echo off
+:next
+if '%1'=='' goto exit
+if '%1'=='-f' goto sh
+erase %1
+:sh
+shift
+goto next
+:exit
diff --git a/gs/src/rm_all.com b/gs/src/rm_all.com
new file mode 100644
index 000000000..998fef8ea
--- /dev/null
+++ b/gs/src/rm_all.com
@@ -0,0 +1,15 @@
+$ Verif = F$Verify(0)
+$ ! OpenVMS command file to emulate behavior of:
+$ !
+$ ! Define the command for deleting multiple files / patterns
+$ !
+$ DELETE="DELETE$$$/LOG"
+$ IF F$SEARCH("''P1'") .NES. "" THEN DELETE 'P1';*
+$ IF F$SEARCH("''P2'") .NES. "" THEN DELETE 'P2';*
+$ IF F$SEARCH("''P3'") .NES. "" THEN DELETE 'P3';*
+$ IF F$SEARCH("''P4'") .NES. "" THEN DELETE 'P4';*
+$ IF F$SEARCH("''P5'") .NES. "" THEN DELETE 'P5';*
+$ IF F$SEARCH("''P6'") .NES. "" THEN DELETE 'P6';*
+$ IF F$SEARCH("''P7'") .NES. "" THEN DELETE 'P7';*
+$ IF F$SEARCH("''P8'") .NES. "" THEN DELETE 'P8';*
+$ xxx = F$Verify(Verif)
diff --git a/gs/src/rm_one.com b/gs/src/rm_one.com
new file mode 100644
index 000000000..39594ac1d
--- /dev/null
+++ b/gs/src/rm_one.com
@@ -0,0 +1,9 @@
+$ Verif = F$Verify(0)
+$ ! OpenVMS command file to emulate behavior of:
+$ !
+$ ! Define the command for deleting (a) file(s) (including wild cards)
+$ !
+$ DELETE="DELETE$$$/LOG"
+$ FILE = F$SEARCH("''P1'")
+$ IF "''FILE'" .NES. "" THEN DELETE 'FILE'
+$ xxx = F$Verify(Verif)
diff --git a/gs/src/sa85x.h b/gs/src/sa85x.h
new file mode 100644
index 000000000..b14e3b053
--- /dev/null
+++ b/gs/src/sa85x.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sa85x.h */
+/* Definitions for ASCII85 streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* ASCII85Encode */
+/* (no state) */
+extern const stream_template s_A85E_template;
+
+/* ASCII85Decode */
+typedef struct stream_A85D_state_s {
+ stream_state_common;
+ int odd; /* # of odd digits */
+ ulong word; /* word being accumulated */
+} stream_A85D_state;
+#define private_st_A85D_state() /* in sfilter2.c */\
+ gs_private_st_simple(st_A85D_state, stream_A85D_state,\
+ "ASCII85Decode state")
+/* We define the initialization procedure here, so that the scanner */
+/* can avoid a procedure call. */
+#define s_A85D_init_inline(ss)\
+ ((ss)->word = 0, (ss)->odd = 0)
+extern const stream_template s_A85D_template;
diff --git a/gs/src/sbcp.c b/gs/src/sbcp.c
new file mode 100644
index 000000000..7d87679b4
--- /dev/null
+++ b/gs/src/sbcp.c
@@ -0,0 +1,232 @@
+/* Copyright (C) 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbcp.c */
+/* BCP and TBCP filters */
+#include "stdio_.h"
+#include "strimpl.h"
+#include "sfilter.h"
+
+#define CtrlA 0x01
+#define CtrlC 0x03
+#define CtrlD 0x04
+#define CtrlE 0x05
+#define CtrlQ 0x11
+#define CtrlS 0x13
+#define CtrlT 0x14
+#define ESC 0x1b
+#define CtrlBksl 0x1c
+
+/* The following is not used yet. */
+/*private const char *TBCP_end_protocol_string = "\033%-12345X";*/
+
+/* ------ BCPEncode and TBCPEncode ------ */
+
+/* Process a buffer */
+private int
+s_xBCPE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last, const byte _ds *escaped)
+{ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint rcount = rlimit - p;
+ byte *q = pw->ptr;
+ uint wcount = pw->limit - q;
+ const byte *end = p + min(rcount, wcount);
+ while ( p < end )
+ { byte ch = *++p;
+ if ( ch <= 31 && escaped[ch] )
+ { if ( p == rlimit )
+ { p--;
+ break;
+ }
+ *++q = CtrlA;
+ ch ^= 0x40;
+ if ( --wcount < rcount )
+ end--;
+ }
+ *++q = ch;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return (p == rlimit ? 0 : 1);
+}
+
+/* Actual process procedures */
+private int
+s_BCPE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ static const byte escaped[32] = {
+ 0,1,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,
+ 0,1,0,1,1,0,0,0, 0,0,0,0,1,0,0,0
+ };
+ return s_xBCPE_process(st, pr, pw, last, escaped);
+}
+private int
+s_TBCPE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ static const byte escaped[32] = {
+ 0,1,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,
+ 0,1,0,1,1,0,0,0, 0,0,0,1,1,0,0,0
+ };
+ return s_xBCPE_process(st, pr, pw, last, escaped);
+}
+
+/* Stream templates */
+const stream_template s_BCPE_template =
+{ &st_stream_state, NULL, s_BCPE_process, 1, 2
+};
+const stream_template s_TBCPE_template =
+{ &st_stream_state, NULL, s_TBCPE_process, 1, 2
+};
+
+/* ------ BCPDecode and TBCPDecode ------ */
+
+private_st_BCPD_state();
+
+#define ss ((stream_BCPD_state *)st)
+
+/* Initialize the state */
+private int
+s_BCPD_init(stream_state *st)
+{ ss->escaped = 0;
+ ss->matched = ss->copy_count = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_xBCPD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last, bool tagged)
+{ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int copy_count = ss->copy_count;
+ int status;
+ bool escaped = ss->escaped;
+ for ( ; ; )
+ { byte ch;
+ if ( copy_count )
+ { if ( q == wlimit )
+ { status = (p < rlimit ? 1 : 0);
+ break;
+ }
+ *++q = *++(ss->copy_ptr);
+ copy_count--;
+ continue;
+ }
+ if ( p == rlimit )
+ { status = 0;
+ break;
+ }
+ ch = *++p;
+ if ( ch <= 31 )
+ switch ( ch )
+ {
+ case CtrlA:
+ if ( escaped )
+ { status = ERRC;
+ goto out;
+ }
+ escaped = true;
+ continue;
+ case CtrlC:
+ status = (*ss->signal_interrupt)(st);
+ if ( status < 0 )
+ goto out;
+ continue;
+ case CtrlD:
+ if ( escaped )
+ { status = ERRC;
+ goto out;
+ }
+ status = EOFC;
+ goto out;
+ case CtrlE:
+ continue;
+ case CtrlQ:
+ continue;
+ case CtrlS:
+ continue;
+ case CtrlT:
+ status = (*ss->request_status)(st);
+ if ( status < 0 )
+ goto out;
+ continue;
+ case CtrlBksl:
+ continue;
+ }
+ if ( q == wlimit )
+ { p--;
+ status = 1;
+ break;
+ }
+ if ( escaped )
+ { escaped = false;
+ switch ( ch )
+ { case '[':
+ if ( !tagged )
+ { status = ERRC;
+ goto out;
+ }
+ /* falls through */
+ case 'A': case 'C': case 'D': case 'E':
+ case 'Q': case 'S': case 'T': case '\\':
+ ch ^= 0x40;
+ break;
+ case 'M':
+ if ( !tagged )
+ { status = ERRC;
+ goto out;
+ }
+ continue;
+ default:
+ status = ERRC;
+ goto out;
+ }
+ }
+ *++q = ch;
+ }
+out: ss->copy_count = copy_count;
+ ss->escaped = escaped;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Actual process procedures */
+private int
+s_BCPD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ return s_xBCPD_process(st, pr, pw, last, false);
+}
+private int
+s_TBCPD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ return s_xBCPD_process(st, pr, pw, last, true);
+}
+
+/* Stream templates */
+const stream_template s_BCPD_template =
+{ &st_BCPD_state, s_BCPD_init, s_BCPD_process, 1, 1,
+ NULL, NULL, s_BCPD_init
+};
+const stream_template s_TBCPD_template =
+{ &st_BCPD_state, s_BCPD_init, s_TBCPD_process, 1, 1,
+ NULL, NULL, s_BCPD_init
+};
diff --git a/gs/src/sbhc.c b/gs/src/sbhc.c
new file mode 100644
index 000000000..1ef6eb7b2
--- /dev/null
+++ b/gs/src/sbhc.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbhc.c */
+/* Bounded Huffman code filters */
+#include "memory_.h"
+#include "stdio_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sbhc.h"
+#include "shcgen.h"
+
+/* ------ BoundedHuffmanEncode ------ */
+
+private_st_BHCE_state();
+
+#define ss ((stream_BHCE_state *)st)
+
+/* Initialize BoundedHuffmanEncode filter. */
+private int
+s_BHCE_reinit(stream_state *st)
+{ ss->encode.count = ss->definition.num_values;
+ s_bhce_init_inline(ss);
+ return 0;
+}
+private int
+s_BHCE_init(register stream_state *st)
+{ hce_code *encode = ss->encode.codes =
+ (hce_code *)gs_alloc_byte_array(st->memory,
+ ss->definition.num_values,
+ sizeof(hce_code), "BHCE encode");
+ if ( encode == 0 )
+ return ERRC; /****** WRONG ******/
+ hc_make_encoding(encode, &ss->definition);
+ return s_BHCE_reinit(st);
+}
+
+/* Release the filter. */
+private void
+s_BHCE_release(stream_state *st)
+{ gs_free_object(st->memory, ss->encode.codes, "BHCE encode");
+}
+
+/* Process a buffer. */
+private int
+s_BHCE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit - (hc_bits_size >> 3);
+ const hce_code *encode = ss->encode.codes;
+ uint num_values = ss->definition.num_values;
+ uint zero_runs = ss->EncodeZeroRuns;
+ uint zero_max = num_values - zero_runs + (ss->EndOfData ? 0 : 1);
+ uint zero_value = (zero_max > 1 ? 0 : 0x100);
+ int zeros = ss->zeros;
+ int status = 0;
+ hce_declare_state;
+
+ hce_load_state();
+ while ( p < rlimit && q < wlimit )
+ { uint value = *++p;
+ const hce_code *cp;
+ if ( value >= num_values )
+ { status = ERRC;
+ break;
+ }
+ if ( value == zero_value )
+ { /* Accumulate a run of zeros. */
+ ++zeros;
+ if ( zeros != zero_max )
+ continue;
+ /* We've scanned the longest run we can encode. */
+ cp = &encode[zeros - 2 + zero_runs];
+ zeros = 0;
+ hc_put_code((stream_hc_state *)ss, q, cp);
+ continue;
+ }
+ /* Check whether we need to put out a zero run. */
+ if ( zeros > 0 )
+ { --p;
+ cp = (zeros == 1 ? &encode[0] :
+ &encode[zeros - 2 + zero_runs]);
+ zeros = 0;
+ hc_put_code((stream_hc_state *)ss, q, cp);
+ continue;
+ }
+ cp = &encode[value];
+ hc_put_code((stream_hc_state *)ss, q, cp);
+ }
+ if ( q >= wlimit )
+ status = 1;
+ wlimit = pw->limit;
+ if ( last && status == 0 )
+ { if ( zeros > 0 )
+ { /* Put out a final run of zeros. */
+ const hce_code *cp = (zeros == 1 ? &encode[0] :
+ &encode[zeros - 2 + zero_runs]);
+ if ( !hce_bits_available(cp->code_length) )
+ status = 1;
+ else
+ { hc_put_code((stream_hc_state *)ss, q, cp);
+ zeros = 0;
+ }
+ }
+ if ( ss->EndOfData )
+ { /* Put out the EOD code if we have room. */
+ const hce_code *cp = &encode[num_values - 1];
+ if ( !hce_bits_available(cp->code_length) )
+ status = 1;
+ else
+ hc_put_code((stream_hc_state *)ss, q, cp);
+ }
+ else
+ { if ( q >= wlimit )
+ status = 1;
+ }
+ if ( !status )
+ { q = hc_put_last_bits((stream_hc_state *)ss, q);
+ goto ns;
+ }
+ }
+ hce_store_state();
+ns: pr->ptr = p;
+ pw->ptr = q;
+ ss->zeros = zeros;
+ return (p == rlimit ? 0 : 1);
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_BHCE_template =
+{ &st_BHCE_state, s_BHCE_init, s_BHCE_process,
+ 1, hc_bits_size >> 3, s_BHCE_release, NULL, s_BHCE_reinit
+};
+
+/* ------ BoundedHuffmanDecode ------ */
+
+private_st_BHCD_state();
+
+#define ss ((stream_BHCD_state *)st)
+
+#define hcd_initial_bits 7 /* arbitrary, >= 1 and <= 8 */
+
+/* Initialize BoundedHuffmanDecode filter. */
+private int
+s_BHCD_reinit(stream_state *st)
+{ ss->decode.count = ss->definition.num_values;
+ s_bhcd_init_inline(ss);
+ return 0;
+}
+private int
+s_BHCD_init(register stream_state *st)
+{ uint initial_bits = ss->decode.initial_bits =
+ min(hcd_initial_bits, ss->definition.num_counts);
+ uint dsize = hc_sizeof_decoding(&ss->definition, initial_bits);
+ hcd_code *decode = ss->decode.codes =
+ (hcd_code *)gs_alloc_byte_array(st->memory, dsize,
+ sizeof(hcd_code), "BHCD decode");
+ if ( decode == 0 )
+ return ERRC; /****** WRONG ******/
+ hc_make_decoding(decode, &ss->definition, initial_bits);
+ return s_BHCD_reinit(st);
+}
+
+/* Release the filter. */
+private void
+s_BHCD_release(stream_state *st)
+{ gs_free_object(st->memory, ss->decode.codes, "BHCD decode");
+}
+
+/* Process a buffer. */
+private int
+s_BHCD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ bhcd_declare_state;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ const hcd_code *decode = ss->decode.codes;
+ uint initial_bits = ss->decode.initial_bits;
+ uint zero_runs = ss->EncodeZeroRuns;
+ int status = 0;
+ int eod = (ss->EndOfData ? ss->definition.num_values - 1 : -1);
+
+ bhcd_load_state();
+z: for ( ; zeros > 0; --zeros )
+ { if ( q >= wlimit )
+ { status = 1;
+ goto out;
+ }
+ *++q = 0;
+ }
+ for ( ; ; )
+ { const hcd_code *cp;
+ int clen;
+ hcd_ensure_bits(initial_bits, x1);
+ cp = &decode[hcd_peek_var_bits(initial_bits)];
+w1: if ( q >= wlimit )
+ { status = 1;
+ break;
+ }
+ if ( (clen = cp->code_length) > initial_bits )
+ { if ( !hcd_bits_available(clen) )
+ { /* We don't have enough bits for */
+ /* all possible codes that begin this way, */
+ /* but we might have enough for */
+ /* the next code. */
+ /****** NOT IMPLEMENTED YET ******/
+ break;
+ }
+ clen -= initial_bits;
+ hcd_skip_bits(initial_bits);
+ hcd_ensure_bits(clen, out); /* can't exit */
+ cp = &decode[cp->value + hcd_peek_var_bits(clen)];
+ hcd_skip_bits(cp->code_length);
+ }
+ else
+ { hcd_skip_bits(clen);
+ }
+ if ( cp->value >= zero_runs )
+ { if ( cp->value == eod )
+ { status = EOFC;
+ goto out;
+ }
+ /* This code represents a run of zeros, */
+ /* not a single output value. */
+ zeros = cp->value - zero_runs + 2;
+ goto z;
+ }
+ *++q = cp->value;
+ continue;
+ /* We don't have enough bits for all possible */
+ /* codes, but we might have enough for */
+ /* the next code. */
+x1: cp = &decode[(bits & ((1 << bits_left) - 1)) <<
+ (initial_bits - bits_left)];
+ if ( (clen = cp->code_length) <= bits_left )
+ goto w1;
+ break;
+ }
+out: bhcd_store_state();
+ pw->ptr = q;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_BHCD_template =
+{ &st_BHCD_state, s_BHCD_init, s_BHCD_process, 1, 1, s_BHCD_release,
+ NULL, s_BHCD_reinit
+};
diff --git a/gs/src/sbhc.h b/gs/src/sbhc.h
new file mode 100644
index 000000000..b94f17fd7
--- /dev/null
+++ b/gs/src/sbhc.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbhc.h */
+/* BoundedHuffman filter state definition */
+/* Requires strimpl.h */
+#include "shc.h"
+
+/*
+ * The BoundedHuffman filters extend the basic Huffman coding model by
+ * providing the ability to encode runs of zeros as a single data item,
+ * and by providing an end-of-data (EOD) marker.
+ */
+#define max_zero_run 100
+
+/* Common state */
+#define stream_BHC_state_common\
+ stream_hc_state_common;\
+ hc_definition definition;\
+ /* The client sets the following before initialization. */\
+ bool EndOfData;\
+ uint EncodeZeroRuns;\
+ /* The following are updated dynamically. */\
+ int zeros /* # of zeros scanned or left to output */
+typedef struct stream_BHC_state_s {
+ stream_BHC_state_common;
+} stream_BHC_state;
+
+/* BoundedHuffmanEncode */
+typedef struct stream_BHCE_state_s {
+ stream_BHC_state_common;
+ hce_table encode;
+} stream_BHCE_state;
+#define private_st_BHCE_state() /* in sbhc.c */\
+ gs_private_st_ptrs3(st_BHCE_state, stream_BHCE_state,\
+ "BoundedHuffmanEncode state", bhce_enum_ptrs, bhce_reloc_ptrs,\
+ definition.counts, definition.values, encode.codes)
+extern const stream_template s_BHCE_template;
+
+#define s_bhce_init_inline(ss)\
+ (s_hce_init_inline(ss), (ss)->zeros = 0)
+
+/* BoundedHuffmanDecode */
+typedef struct stream_BHCD_state_s {
+ stream_BHC_state_common;
+ hcd_table decode;
+} stream_BHCD_state;
+#define private_st_BHCD_state() /* in sbhc.c */\
+ gs_private_st_ptrs3(st_BHCD_state, stream_BHCD_state,\
+ "BoundedHuffmanDecode state", bhcd_enum_ptrs, bhcd_reloc_ptrs,\
+ definition.counts, definition.values, decode.codes)
+extern const stream_template s_BHCD_template;
+
+#define s_bhcd_init_inline(ss)\
+ (s_hcd_init_inline(ss), (ss)->zeros = 0)
+
+/* Declare variables that hold the decoder state. */
+#define bhcd_declare_state\
+ hcd_declare_state;\
+ int zeros
+
+/* Load the state from the stream. */
+/* Free variables: pr, ss, p, rlimit, bits, bits_left, zeros. */
+#define bhcd_load_state()\
+ hcd_load_state(), zeros = ss->zeros
+
+/* Store the state back in the stream. */
+/* Free variables: pr, ss, p, bits, bits_left, zeros. */
+#define bhcd_store_state()\
+ hcd_store_state(), ss->zeros = zeros
diff --git a/gs/src/sbtx.h b/gs/src/sbtx.h
new file mode 100644
index 000000000..37933d2e1
--- /dev/null
+++ b/gs/src/sbtx.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbtx.h */
+/* Definitions for BTE/BTD streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* ByteTranslateEncode/Decode */
+typedef struct stream_BT_state_s {
+ stream_state_common;
+ byte table[256];
+} stream_BT_state;
+typedef stream_BT_state stream_BTE_state;
+typedef stream_BT_state stream_BTD_state;
+#define private_st_BT_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_BT_state, stream_BT_state, "ByteTranslateEncode/Decode state")
+extern const stream_template s_BT_template;
+#define s_BTD_template s_BT_template
+#define s_BTE_template s_BT_template
diff --git a/gs/src/sbwbs.c b/gs/src/sbwbs.c
new file mode 100644
index 000000000..7c0093f8e
--- /dev/null
+++ b/gs/src/sbwbs.c
@@ -0,0 +1,471 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbwbs.c */
+/* Burrows/Wheeler block sorting compression filters */
+#include "stdio_.h"
+#include "memory_.h"
+#include <stdlib.h> /* for qsort */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sbwbs.h"
+
+/* ------ Common code for streams that buffer a block ------ */
+
+private_st_buffered_state();
+
+#define ss ((stream_buffered_state *)st)
+
+/* Initialize */
+private int
+s_buffered_no_block_init(stream_state *st)
+{ ss->buffer = 0;
+ ss->filling = true;
+ ss->bpos = 0;
+ return 0;
+}
+private int
+s_buffered_block_init(stream_state *st)
+{ s_buffered_no_block_init(st);
+ ss->buffer = gs_alloc_bytes(st->memory, ss->BlockSize, "buffer");
+ if ( ss->buffer == 0 )
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Continue filling the buffer if needed. */
+/* Return 0 if the buffer isn't full yet, 1 if it is full or if */
+/* we reached the end of input data. */
+/* In the latter case, also set filling = false. */
+/* Note that this procedure doesn't take pw as an argument. */
+private int
+s_buffered_process(stream_state *st, stream_cursor_read *pr, bool last)
+{ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint left = ss->bsize - ss->bpos;
+ if ( !ss->filling )
+ return 1;
+ if ( left < count )
+ count = left;
+ if_debug3('w', "[w]buffering %d bytes to position %d, last = %s\n",
+ count, ss->bpos, (last ? "true" : "false"));
+ memcpy(ss->buffer + ss->bpos, p + 1, count);
+ pr->ptr = p += count;
+ ss->bpos += count;
+ if ( ss->bpos == ss->bsize || (p == rlimit && last) )
+ { ss->filling = false;
+ return 1;
+ }
+ return 0;
+}
+
+/* Release */
+private void
+s_buffered_release(stream_state *st)
+{ gs_free_object(st->memory, ss->buffer, "buffer");
+}
+
+#undef ss
+
+/* ------ Common code for Burrows/Wheeler block sorting filters ------ */
+
+private_st_BWBS_state();
+private void s_BWBS_release(P1(stream_state *));
+
+#define ss ((stream_BWBS_state *)st)
+
+/* Initialize */
+private int
+bwbs_init(stream_state *st, uint osize)
+{ int code;
+ ss->bsize = ss->BlockSize;
+ code = s_buffered_block_init(st);
+ if ( code != 0 )
+ return code;
+ ss->offsets = (void *)gs_alloc_bytes(st->memory, osize,
+ "BWBlockSort offsets");
+ if ( ss->offsets == 0 )
+ { s_BWBS_release(st);
+ return ERRC; /****** WRONG ******/
+ }
+ ss->I = -1; /* haven't read I yet */
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_BWBS_release(stream_state *st)
+{ gs_free_object(st->memory, ss->offsets, "BWBlockSort offsets");
+ s_buffered_release(st);
+}
+
+/* ------ BWBlockSortEncode ------ */
+
+/* Initialize */
+private int
+s_BWBSE_init(stream_state *st)
+{ return bwbs_init(st, ss->BlockSize * sizeof(int));
+}
+
+/* Compare two rotated strings for sorting. */
+private stream_BWBS_state *bwbs_compare_ss;
+private int
+bwbs_compare_rotations(const void *p1, const void *p2)
+{ const byte *buffer = bwbs_compare_ss->buffer;
+ const byte *s1 = buffer + *(const int *)p1;
+ const byte *s2 = buffer + *(const int *)p2;
+ const byte *start1;
+ const byte *end;
+ int swap;
+ if ( *s1 != *s2 )
+ return (*s1 < *s2 ? -1 : 1);
+ if ( s1 < s2 )
+ swap = 1;
+ else
+ { const byte *t = s1; s1 = s2; s2 = t;
+ swap = -1;
+ }
+ start1 = s1;
+ end = buffer + bwbs_compare_ss->N;
+ for ( s1++, s2++; s2 < end; s1++, s2++ )
+ if ( *s1 != *s2 )
+ return (*s1 < *s2 ? -swap : swap);
+ s2 = buffer;
+ for ( ; s1 < end; s1++, s2++ )
+ if ( *s1 != *s2 )
+ return (*s1 < *s2 ? -swap : swap);
+ s1 = buffer;
+ for ( ; s1 < start1; s1++, s2++ )
+ if ( *s1 != *s2 )
+ return (*s1 < *s2 ? -swap : swap);
+ return 0;
+}
+/* Sort the strings. */
+private void
+bwbse_sort(const byte *buffer, uint *indices, int N)
+{ offsets_full Cs;
+#define C Cs.v
+ /* Sort the strings. We start with a radix sort. */
+ uint sum = 0, j, ch;
+ memset(C, 0, sizeof(Cs));
+ for ( j = 0; j < N; j++ )
+ C[buffer[j]]++;
+ for ( ch = 0; ch <= 255; ch++ )
+ { sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ for ( j = 0; j < N; j++ )
+ indices[C[buffer[j]]++] = j;
+ /* Now C[ch] = the number of strings that start */
+ /* with a character less than or equal to ch. */
+ sum = 0;
+ /* qsort each bucket produced by the radix sort. */
+ for ( ch = 0; ch <= 255; sum = C[ch], ch++ )
+ qsort(indices + sum, C[ch] - sum,
+ sizeof(*indices),
+ bwbs_compare_rotations);
+#undef C
+}
+
+/* Encode a buffer */
+private int
+s_BWBSE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ uint wcount = wlimit - q;
+ uint *indices = ss->offsets;
+ if ( ss->filling )
+ { int status, j, N;
+ byte *buffer = ss->buffer;
+ if ( wcount < sizeof(int) * 2 )
+ return 1;
+ /* Continue filling the buffer. */
+ status = s_buffered_process(st, pr, last);
+ if ( !status )
+ return 0;
+ ss->N = N = ss->bpos;
+ /* We reverse the string before encoding it, */
+ /* so it will come out of the decoder correctly. */
+ for ( j = N / 2 - 1; j >= 0; j-- )
+ { byte *p0 = &buffer[j];
+ byte *p1 = &buffer[N - 1 - j];
+ byte b = *p0;
+ *p0 = *p1;
+ *p1 = b;
+ }
+ /* Save st in a static, because that's the only way */
+ /* we can pass it to the comparison procedure (ugh). */
+ bwbs_compare_ss = ss;
+ /* Sort the strings. */
+ bwbse_sort(buffer, indices, N);
+ /* Find the unrotated string. */
+ for ( j = 0; j < N; j++ )
+ if ( indices[j] == 0 )
+ { ss->I = j;
+ break;
+ }
+ for ( j = sizeof(int); --j >= 0; )
+ *++q = (byte)(N >> (j * 8));
+ for ( j = sizeof(int); --j >= 0; )
+ *++q = (byte)(ss->I >> (j * 8));
+ ss->bpos = 0;
+ }
+ /* We're reading out of the buffer, writing the permuted string. */
+ while ( q < wlimit && ss->bpos < ss->N )
+ { int i = indices[ss->bpos++];
+ *++q = ss->buffer[(i == 0 ? ss->N - 1 : i - 1)];
+ }
+ if ( ss->bpos == ss->N )
+ { ss->filling = true;
+ ss->bpos = 0;
+ }
+ pw->ptr = q;
+ if ( q == wlimit )
+ return 1;
+ return 0;
+}
+
+/* Stream template */
+const stream_template s_BWBSE_template =
+{ &st_BWBS_state, s_BWBSE_init, s_BWBSE_process, sizeof(int) * 2, 1, s_BWBS_release
+};
+
+/* ------ BWBlockSortDecode ------ */
+
+#define SHORT_OFFSETS
+
+#ifdef SHORT_OFFSETS
+
+/*
+ * Letting S[0..N-1] be the data block before depermutation, we need
+ * a table P[0..N-1] that maps the index i to O(S[i],i), where O(c,i) is
+ * the number of occurrences of c in S before position i.
+ * We observe that for a fixed c, O(c,i) is monotonic with i,
+ * and falls in the range 0 .. i; consequently, if 0 <= i <= j,
+ * 0 <= O(c,j) - O(c,i) <= j - i. Proceeding from this observation,
+ * rather than allocate an entire int to each entry of P,
+ * we construct three tables as follows:
+ * P2[k,c] = O(c,k*65536) for k = 0 .. (N-1)/65536;
+ * each entry requires an int.
+ * P1[k,c] = O(c,k*4096) - P2[k/16,c] for k = 0 .. (N-1)/4096;
+ * each entry falls in the range 0 .. 15*4096 and hence
+ * requires 16 bits.
+ * P0[i] = O(S[i],i) - P1[i/4096,S[i]] for i = 0 .. N-1;
+ * each entry falls in the range 0 .. 4095 and hence
+ * requires 12 bits.
+ * Since the value we need in the decompression loop is actually
+ * P[i] + C[S[i]], where C[c] is the sum of O(0,N) ... O(c-1,N),
+ * we add C[c] into P2[k,c] for all k.
+ */
+/*typedef struct { uint v[256]; } offsets_full;*/ /* in sbwbs.h */
+typedef struct { bits16 v[256]; } offsets_4k;
+#if arch_sizeof_int > 2
+# define ceil_64k(n) (((n) + 0xffff) >> 16)
+#else
+# define ceil_64k(n) 1
+#endif
+#define ceil_4k(n) (((n) + 0xfff) >> 12)
+#define offset_space(bsize)\
+ (ceil_64k(bsize) * sizeof(offsets_full) +\
+ ceil_4k(bsize) * sizeof(offsets_4k) +\
+ ((bsize + 1) >> 1) * 3)
+
+#else /* !SHORT_OFFSETS */
+
+#define offset_space(bsize)\
+ (bsize * sizeof(int))
+
+#endif /* (!)SHORT_OFFSETS */
+
+/* Initialize */
+private int
+s_BWBSD_init(stream_state *st)
+{ uint bsize = ss->BlockSize;
+ return bwbs_init(st, offset_space(bsize));
+}
+
+/* Construct the decoding tables. */
+
+#ifdef SHORT_OFFSETS
+
+private void
+bwbsd_construct_offsets(stream_BWBS_state *sst, offsets_full *po64k,
+ offsets_4k *po4k, byte *po1, int N)
+{ offsets_full Cs;
+#define C Cs.v
+ uint i1;
+ byte *b = sst->buffer;
+ offsets_full *p2 = po64k - 1;
+ offsets_4k *p1 = po4k;
+ byte *p0 = po1;
+ memset(C, 0, sizeof(Cs));
+ for ( i1 = 0; i1 < ceil_4k(N); i1++, p1++ )
+ { int j;
+ if ( !(i1 & 15) )
+ *++p2 = Cs;
+ for ( j = 0; j < 256; j++ )
+ p1->v[j] = C[j] - p2->v[j];
+ j = (N + 1 - (i1 << 12)) >> 1;
+ if ( j > 4096/2 )
+ j = 4096/2;
+ for ( ; j > 0; j--, b += 2, p0 += 3 )
+ { byte b0 = b[0];
+ uint d0 = C[b0]++ - (p1->v[b0] + p2->v[b0]);
+ byte b1 = b[1];
+ uint d1 = C[b1]++ - (p1->v[b1] + p2->v[b1]);
+ p0[0] = d0 >> 4;
+ p0[1] = (byte)((d0 << 4) + (d1 >> 8));
+ p0[2] = (byte)d1;
+ }
+ }
+ /* If the block length is odd, discount the extra byte. */
+ if ( N & 1 )
+ C[sst->buffer[N]]--;
+ /* Compute the cumulative totals in C. */
+ { int sum = 0, ch;
+ for ( ch = 0; ch <= 255; ch++ )
+ { sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ }
+ /* Add the C values back into the 64K table, */
+ /* which saves an addition of C[b] in the decoding loop. */
+ { int i2, ch;
+ for ( p2 = po64k, i2 = ceil_64k(N); i2 > 0; p2++, i2-- )
+ for ( ch = 0; ch < 256; ch++ )
+ p2->v[ch] += C[ch];
+ }
+#undef C
+}
+
+#else /* !SHORT_OFFSETS */
+
+private void
+bwbsd_construct_offsets(stream_BWBS_state *sst, int *po, int N)
+{ offsets_full Cs;
+#define C Cs.v
+ uint i;
+ byte *b = sst->buffer;
+ int *p = po;
+ memset(C, 0, sizeof(Cs));
+ for ( i = 0; i < N; i++, p++, b++ )
+ *p = C[*b]++;
+ /* Compute the cumulative totals in C. */
+ { int sum = 0, ch;
+ for ( ch = 0; ch <= 255; ch++ )
+ { sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ }
+ /* Add the C values back into the offsets. */
+ for ( i = 0, b = sst->buffer, p = po; i < N; i++, b++, p++ )
+ *p += C[*b];
+#undef C
+}
+
+#endif /* (!)SHORT_OFFSETS */
+
+/* Decode a buffer */
+private int
+s_BWBSD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+#ifdef SHORT_OFFSETS
+ uint BlockSize = ss->BlockSize;
+ offsets_full *po64k = ss->offsets;
+ offsets_4k *po4k = (offsets_4k *)(po64k + ceil_64k(BlockSize));
+ byte *po1 = (byte *)(po4k + ceil_4k(BlockSize));
+#else /* !SHORT_OFFSETS */
+ int *po = ss->offsets;
+#endif /* (!)SHORT_OFFSETS */
+ if ( ss->I < 0 )
+ { /* Read block parameters */
+ int I, N, j;
+ if ( count < sizeof(int) * 2 )
+ return 0;
+ for ( N = 0, j = 0; j < sizeof(int); j++ )
+ N = (N << 8) + *++p;
+ for ( I = 0, j = 0; j < sizeof(int); j++ )
+ I = (I << 8) + *++p;
+ ss->N = N;
+ ss->I = I;
+ if_debug2('w', "[w]N=%d I=%d\n", N, I);
+ pr->ptr = p;
+ if ( N < 0 || N > ss->BlockSize || I < 0 || I >= N )
+ return ERRC;
+ if ( N == 0 )
+ return EOFC;
+ count -= sizeof(int) * 2;
+ ss->bpos = 0;
+ ss->bsize = N;
+ }
+ if ( ss->filling )
+ { /* Continue filling the buffer. */
+ if ( !s_buffered_process(st, pr, last) )
+ return 0;
+ /* Construct the inverse sort order. */
+#ifdef SHORT_OFFSETS
+ bwbsd_construct_offsets(ss, po64k, po4k, po1, ss->bsize);
+#else /* !SHORT_OFFSETS */
+ bwbsd_construct_offsets(ss, po, ss->bsize);
+#endif /* (!)SHORT_OFFSETS */
+ ss->bpos = 0;
+ ss->i = ss->I;
+ }
+ /* We're reading out of the buffer. */
+ while ( q < wlimit && ss->bpos < ss->bsize )
+ { int i = ss->i;
+ byte b = ss->buffer[i];
+#ifdef SHORT_OFFSETS
+ uint d;
+ const byte *pd = &po1[(i >> 1) + i];
+ *++q = b;
+ if ( !(i & 1) )
+ d = ((uint)pd[0] << 4) + (pd[1] >> 4);
+ else
+ d = ((pd[0] & 0xf) << 8) + pd[1];
+ ss->i = po64k[i >> 16].v[b] + po4k[i >> 12].v[b] + d;
+#else /* !SHORT_OFFSETS */
+ *++q = b;
+ ss->i = po[i];
+#endif /* (!)SHORT_OFFSETS */
+ ss->bpos++;
+ }
+ if ( ss->bpos == ss->bsize )
+ { ss->I = -1;
+ ss->filling = true;
+ }
+ pw->ptr = q;
+ if ( q == wlimit )
+ return 1;
+ return 0;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_BWBSD_template =
+{ &st_BWBS_state, s_BWBSD_init, s_BWBSD_process, 1, sizeof(int) * 2, s_BWBS_release
+};
diff --git a/gs/src/sbwbs.h b/gs/src/sbwbs.h
new file mode 100644
index 000000000..4b6e73d72
--- /dev/null
+++ b/gs/src/sbwbs.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sbwbs.h */
+/* Definitions for Burroughs/Wheeler block sorting compression streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* Common framework for streams that buffer a block for processing */
+#define stream_buffered_state_common\
+ stream_state_common;\
+ /* The client may set the following before initialization, */\
+ /* or the stream may set it later. */\
+ int BlockSize;\
+ /* The init procedure sets the following, */\
+ /* if BlockSize has been set. */\
+ byte *buffer; /* [BlockSize] */\
+ /* The following are updated dynamically. */\
+ bool filling; /* true if filling buffer, */\
+ /* false if emptying */\
+ int bsize; /* size of current block (<= BlockSize) */\
+ int bpos /* current index within buffer */
+typedef struct stream_buffered_state_s {
+ stream_buffered_state_common;
+} stream_buffered_state;
+#define private_st_buffered_state() /* in sbwbs.c */\
+ gs_private_st_ptrs1(st_buffered_state, stream_buffered_state,\
+ "stream_buffered state", sbuf_enum_ptrs, sbuf_reloc_ptrs, buffer)
+
+/* BWBlockSortEncode/Decode */
+typedef struct of_ {
+ uint v[256];
+} offsets_full;
+typedef struct stream_BWBS_state_s {
+ stream_buffered_state_common;
+ /* The init procedure sets the following. */
+ void *offsets; /* permutation indices when writing, */
+ /* multi-level indices when reading */
+ /* The following are updated dynamically. */
+ int N; /* actual length of block */
+ /* The following are only used when decoding. */
+ int I; /* index of unrotated string */
+ int i; /* next index in encoded string */
+} stream_BWBS_state;
+typedef stream_BWBS_state stream_BWBSE_state;
+typedef stream_BWBS_state stream_BWBSD_state;
+#define private_st_BWBS_state() /* in sbwbs.c */\
+ gs_private_st_suffix_add1(st_BWBS_state, stream_BWBS_state,\
+ "BWBlockSortEncode/Decode state", bwbs_enum_ptrs, bwbs_reloc_ptrs,\
+ st_buffered_state, offsets)
+extern const stream_template s_BWBSE_template;
+extern const stream_template s_BWBSD_template;
diff --git a/gs/src/scanchar.h b/gs/src/scanchar.h
new file mode 100644
index 000000000..2839df1cc
--- /dev/null
+++ b/gs/src/scanchar.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scanchar.h */
+/* Character scanning table for Ghostscript */
+/* Requires scommon.h */
+
+/*
+ * An array for fast scanning of names, numbers, and hex strings.
+ * Indexed by character code (including exceptions), it contains:
+ * 0 - max_radix-1 for valid digits,
+ * ctype_name for other characters valid in names,
+ * ctype_btoken for characters introducing binary tokens
+ * (if the binary token feature is enabled),
+ * ctype_space for whitespace characters,
+ * ctype_exception for exceptions (see scommon.h), and
+ * ctype_other for everything else.
+ * Exceptions are negative values; we bias the table origin accordingly.
+ *
+ * NOTE: This table is defined in iscantab.c and used in a variety of places.
+ * If any of the values below change, you must edit the table.
+ */
+extern const byte scan_char_array[max_stream_exception + 256];
+#define scan_char_decoder (&scan_char_array[max_stream_exception])
+#define min_radix 2
+#define max_radix 36
+#define ctype_name 100
+#define ctype_btoken 101
+#define ctype_space 102
+#define ctype_other 103
+#define ctype_exception 104
+/* Special characters with no \xxx representation */
+#define char_NULL 0
+#define char_EOT 004 /* ^D, job delimiter */
+#define char_VT 013 /* ^K, vertical tab */
+#define char_DOS_EOF 032 /* ^Z */
+/*
+ * Most systems define '\n' as 0x0a and '\r' as 0x0d; however, OS-9
+ * has '\n' = '\r' = 0x0d and '\l' = 0x0a. To deal with this,
+ * we introduce abstract characters char_CR and char_EOL such that
+ * any of [char_CR], [char_CR char_EOL], or [char_EOL] is recognized
+ * as an end-of-line sequence.
+ */
+#define char_CR '\r'
+#if '\r' == '\n'
+# define char_EOL 0x0a /* non-OS-9 compilers complain about '\l' */
+#else
+# define char_EOL '\n'
+#endif
diff --git a/gs/src/scantab.c b/gs/src/scantab.c
new file mode 100644
index 000000000..89363a73a
--- /dev/null
+++ b/gs/src/scantab.c
@@ -0,0 +1,106 @@
+/* Copyright (C) 1994, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scantab.c */
+/* Scanner table for PostScript/PDF tokens */
+#include "stdpre.h"
+#include "scommon.h"
+#include "scanchar.h" /* defines interface */
+
+/* Define the character scanning table (see scanchar.h). */
+const byte scan_char_array[max_stream_exception + 256] =
+{ stream_exception_repeat(ctype_exception),
+ /* Control characters 0-31. */
+ ctype_space, /* NULL - standard only in Level 2 */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name,
+ ctype_space, /* TAB (\t) */
+ ctype_space, /* LF (\n) */
+ ctype_name,
+ ctype_space, /* FF (\f) */
+ ctype_space, /* CR (\r) */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name,
+ /* Printable characters 32-63 */
+ ctype_space, /* space (\s) */
+ ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_other, /* % */
+ ctype_name, ctype_name,
+ ctype_other, /* ( */
+ ctype_other, /* ) */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_other, /* / */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* digits 0-9 */
+ ctype_name, ctype_name,
+ ctype_other, /* < */
+ ctype_name,
+ ctype_other, /* > */
+ ctype_name,
+ /* Printable characters 64-95 */
+ ctype_name,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35,
+ ctype_other, /* [ */
+ ctype_name,
+ ctype_other, /* ] */
+ ctype_name, ctype_name,
+ /* Printable characters 96-126 and DEL */
+ ctype_name,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35,
+ ctype_other, /* { */
+ ctype_name,
+ ctype_other, /* } */
+ ctype_name, ctype_name,
+ /* Characters 128-159, binary tokens */
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken,
+ /* Characters 160-191, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name,
+ /* Characters 192-223, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name,
+ /* Characters 224-255, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name
+};
diff --git a/gs/src/scf.h b/gs/src/scf.h
new file mode 100644
index 000000000..023261d09
--- /dev/null
+++ b/gs/src/scf.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scf.h */
+/* Common definitions for CCITTFax encoding and decoding filters */
+#include "shc.h"
+
+/*
+ * The CCITT Group 3 (T.4) and Group 4 (T.6) fax specifications map
+ * run lengths to Huffman codes. White and black have different mappings.
+ * If the run length is 64 or greater, two or more codes are needed:
+ * - One or more 'make-up' codes for 2560 pixels;
+ * - A 'make-up' code that encodes the multiple of 64;
+ * - A 'termination' code for the remainder.
+ * For runs of 63 or less, only the 'termination' code is needed.
+ */
+
+/* ------ Encoding tables ------ */
+
+/*
+ * The maximum possible length of a scan line is determined by the
+ * requirement that 3 runs have to fit into the stream buffer.
+ * A run of length N requires approximately ceil(N / 2560) makeup codes,
+ * hence 1.5 * ceil(N / 2560) bytes. Taking the largest safe stream
+ * buffer size as 32K, we arrive at the following maximum width:
+ */
+#if arch_sizeof_int > 2
+# define cfe_max_width (2560 * 32000 * 2 / 3)
+#else
+# define cfe_max_width (max_int - 40) /* avoid overflows */
+#endif
+/* The +5 in cfe_max_code_bytes is a little conservative. */
+#define cfe_max_code_bytes(width) ((width) / 2560 * 3 / 2 + 5)
+
+typedef hce_code cfe_run;
+#define cfe_entry(c, len) hce_entry(c, len)
+
+/* Codes common to 1-D and 2-D encoding. */
+/* The decoding algorithms know that EOL is 0....01. */
+#define run_eol_code_length 12
+#define run_eol_code_value 1
+extern const cfe_run cf_run_eol;
+extern const cfe_run far_data cf_white_termination[64];
+extern const cfe_run far_data cf_white_make_up[41];
+extern const cfe_run far_data cf_black_termination[64];
+extern const cfe_run far_data cf_black_make_up[41];
+extern const cfe_run cf_uncompressed[6];
+extern const cfe_run cf_uncompressed_exit[10]; /* indexed by 2 x length of */
+ /* white run + (1 if next run black, 0 if white) */
+/* 1-D encoding. */
+extern const cfe_run cf1_run_uncompressed;
+/* 2-D encoding. */
+extern const cfe_run cf2_run_pass;
+#define cf2_run_pass_length 4
+#define cf2_run_pass_value 0x1
+#define cf2_run_vertical_offset 3
+extern const cfe_run cf2_run_vertical[7]; /* indexed by b1 - a1 + offset */
+extern const cfe_run cf2_run_horizontal;
+#define cf2_run_horizontal_value 1
+#define cf2_run_horizontal_length 3
+extern const cfe_run cf2_run_uncompressed;
+/* 2-D Group 3 encoding. */
+extern const cfe_run cf2_run_eol_1d;
+extern const cfe_run cf2_run_eol_2d;
+
+/* ------ Decoding tables ------ */
+
+typedef hcd_code cfd_node;
+#define run_length value
+
+/*
+ * The value in the decoding tables is either a white or black run length,
+ * or a (negative) exceptional value.
+ */
+#define run_error (-1)
+#define run_zeros (-2) /* EOL follows, possibly with more padding first */
+#define run_uncompressed (-3)
+/* 2-D codes */
+#define run2_pass (-4)
+#define run2_horizontal (-5)
+
+#define cfd_white_initial_bits 8
+extern const cfd_node far_data cf_white_decode[];
+#define cfd_black_initial_bits 7
+extern const cfd_node far_data cf_black_decode[];
+#define cfd_2d_initial_bits 7
+extern const cfd_node far_data cf_2d_decode[];
+#define cfd_uncompressed_initial_bits 6 /* must be 6 */
+extern const cfd_node far_data cf_uncompressed_decode[];
+
+/* ------ Run detection macros ------ */
+
+/*
+ * For the run detection macros:
+ * white_byte is 0 or 0xff for BlackIs1 or !BlackIs1 respectively;
+ * data holds p[-1], inverted if !BlackIs1;
+ * count is the number of valid bits remaining in the scan line.
+ */
+
+/* Aliases for bit processing tables. */
+#define cf_byte_run_length byte_bit_run_length_neg
+#define cf_byte_run_length_0 byte_bit_run_length_0
+
+/* Skip over white pixels to find the next black pixel in the input. */
+/* Store the run length in rlen, and update data, p, and count. */
+/* There are many more white pixels in typical input than black pixels, */
+/* and the runs of white pixels tend to be much longer, so we use */
+/* substantially different loops for the two cases. */
+
+#define skip_white_pixels(data, p, count, white_byte, rlen)\
+{ if ( (rlen = cf_byte_run_length[count & 7][data ^ 0xff]) >= 8 )\
+ { if ( white_byte == 0 )\
+ { if ( p[0] ) { data = p[0]; p += 1; rlen -= 8; }\
+ else if ( p[1] ) { data = p[1]; p += 2; }\
+ else\
+ { while ( !(p[2] | p[3] | p[4] | p[5]) ) p += 4, rlen += 32;\
+ if ( p[2] ) { data = p[2]; p += 3; rlen += 8; }\
+ else if ( p[3] ) { data = p[3]; p += 4; rlen += 16; }\
+ else if ( p[4] ) { data = p[4]; p += 5; rlen += 24; }\
+ else /* p[5] */ { data = p[5]; p += 6; rlen += 32; }\
+ }\
+ }\
+ else\
+ { if ( p[0] != 0xff ) { data = (byte)~p[0]; p += 1; rlen -= 8; }\
+ else if ( p[1] != 0xff ) { data = (byte)~p[1]; p += 2; }\
+ else\
+ { while ( (p[2] & p[3] & p[4] & p[5]) == 0xff ) p += 4, rlen += 32;\
+ if ( p[2] != 0xff ) { data = (byte)~p[2]; p += 3; rlen += 8; }\
+ else if ( p[3] != 0xff ) { data = (byte)~p[3]; p += 4; rlen += 16; }\
+ else if ( p[4] != 0xff ) { data = (byte)~p[4]; p += 5; rlen += 24; }\
+ else /* p[5] != 0xff */ { data = (byte)~p[5]; p += 6; rlen += 32; }\
+ }\
+ }\
+ rlen += cf_byte_run_length_0[data ^ 0xff];\
+ }\
+ count -= rlen;\
+}
+
+/* Skip over black pixels to find the next white pixel in the input. */
+/* Store the run length in rlen, and update data, p, and count. */
+
+#define skip_black_pixels(data, p, count, white_byte, rlen)\
+{ if ( (rlen = cf_byte_run_length[count & 7][data]) >= 8 )\
+ { if ( white_byte == 0 )\
+ for ( ; ; p += 4, rlen += 32 )\
+ { if ( p[0] != 0xff ) { data = p[0]; p += 1; rlen -= 8; break; }\
+ if ( p[1] != 0xff ) { data = p[1]; p += 2; break; }\
+ if ( p[2] != 0xff ) { data = p[2]; p += 3; rlen += 8; break; }\
+ if ( p[3] != 0xff ) { data = p[3]; p += 4; rlen += 16; break; }\
+ }\
+ else\
+ for ( ; ; p += 4, rlen += 32 )\
+ { if ( p[0] ) { data = (byte)~p[0]; p += 1; rlen -= 8; break; }\
+ if ( p[1] ) { data = (byte)~p[1]; p += 2; break; }\
+ if ( p[2] ) { data = (byte)~p[2]; p += 3; rlen += 8; break; }\
+ if ( p[3] ) { data = (byte)~p[3]; p += 4; rlen += 16; break; }\
+ }\
+ rlen += cf_byte_run_length_0[data];\
+ }\
+ count -= rlen;\
+}
diff --git a/gs/src/scfd.c b/gs/src/scfd.c
new file mode 100644
index 000000000..8ba437441
--- /dev/null
+++ b/gs/src/scfd.c
@@ -0,0 +1,781 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scfd.c */
+/* CCITTFax decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "scf.h"
+#include "scfx.h"
+
+/* ------ CCITTFaxDecode ------ */
+
+private_st_CFD_state();
+
+#define ss ((stream_CFD_state *)st)
+
+/* Set default parameter values. */
+private void
+s_CFD_set_defaults(register stream_state *st)
+{ s_CFD_set_defaults_inline(ss);
+}
+
+/* Initialize CCITTFaxDecode filter */
+private int
+s_CFD_init(stream_state *st)
+{ int raster = ss->raster =
+ round_up((ss->Columns + 7) >> 3, ss->DecodedByteAlign);
+ byte white = (ss->BlackIs1 ? 0 : 0xff);
+ s_hcd_init_inline(ss);
+ /* Because skip_white_pixels can look as many as 4 bytes ahead, */
+ /* we need to allow 4 extra bytes at the end of the row buffers. */
+ ss->lbuf = gs_alloc_bytes(st->memory, raster + 4, "CFD lbuf");
+ ss->lprev = 0;
+ if ( ss->lbuf == 0 )
+ return ERRC; /****** WRONG ******/
+ if ( ss->K != 0 )
+ { ss->lprev = gs_alloc_bytes(st->memory, raster + 4, "CFD lprev");
+ if ( ss->lprev == 0 )
+ return ERRC; /****** WRONG ******/
+ /* Clear the initial reference line for 2-D encoding. */
+ memset(ss->lbuf, white, raster);
+ /* Ensure that the scan of the reference line will stop. */
+ ss->lbuf[raster] = 0xa0;
+ }
+ ss->k_left = min(ss->K, 0);
+ ss->run_color = 0;
+ ss->damaged_rows = 0;
+ ss->skipping_damage = false;
+ ss->cbit = 0;
+ ss->uncomp_run = 0;
+ ss->rows_left = (ss->Rows <= 0 || ss->EndOfBlock ? -1 : ss->Rows + 1);
+ ss->rpos = ss->wpos = raster - 1;
+ ss->eol_count = 0;
+ ss->invert = white;
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_CFD_release(stream_state *st)
+{ gs_free_object(st->memory, ss->lprev, "CFD lprev(close)");
+ gs_free_object(st->memory, ss->lbuf, "CFD lbuf(close)");
+}
+
+/* Declare the variables that hold the state. */
+#define cfd_declare_state\
+ hcd_declare_state;\
+ register byte *q;\
+ int qbit
+/* Load the state from the stream. */
+#define cfd_load_state()\
+ hcd_load_state(),\
+ q = ss->lbuf + ss->wpos, qbit = ss->cbit
+/* Store the state back in the stream. */
+#define cfd_store_state()\
+ hcd_store_state(),\
+ ss->wpos = q - ss->lbuf, ss->cbit = qbit
+
+/* Macros to get blocks of bits from the input stream. */
+/* Invariants: 0 <= bits_left <= bits_size; */
+/* bits [bits_left-1..0] contain valid data. */
+
+#define avail_bits(n) hcd_bits_available(n)
+#define ensure_bits(n, outl) hcd_ensure_bits(n, outl)
+#define peek_bits(n) hcd_peek_bits(n)
+#define peek_var_bits(n) hcd_peek_var_bits(n)
+#define skip_bits(n) hcd_skip_bits(n)
+
+/* Get a run from the stream. */
+#define get_run(decode, initial_bits, runlen, str, outl)\
+{ const cfd_node *np;\
+ int clen;\
+ ensure_bits(initial_bits, outl);\
+ np = &decode[peek_bits(initial_bits)];\
+ if ( (clen = np->code_length) > initial_bits )\
+ { do_debug(uint init_bits = peek_bits(initial_bits));\
+ if ( !avail_bits(clen) ) goto outl;\
+ clen -= initial_bits;\
+ skip_bits(initial_bits);\
+ ensure_bits(clen, outl); /* can't goto outl */\
+ np = &decode[np->run_length + peek_var_bits(clen)];\
+ if_debug4('W', "%s xcode=0x%x,%d rlen=%d\n", str,\
+ (init_bits << np->code_length) +\
+ peek_var_bits(np->code_length),\
+ initial_bits + np->code_length,\
+ np->run_length);\
+ skip_bits(np->code_length);\
+ }\
+ else\
+ { if_debug4('W', "%s code=0x%x,%d rlen=%d\n", str,\
+ peek_var_bits(clen), clen, np->run_length);\
+ skip_bits(clen);\
+ }\
+ runlen = np->run_length;\
+}
+
+/* Skip data bits for a white run. */
+/* rlen is either less than 64, or a multiple of 64. */
+#define skip_data(rlen, makeup_label)\
+ if ( (qbit -= rlen) < 0 )\
+ { q -= qbit >> 3, qbit &= 7;\
+ if ( rlen >= 64 ) goto makeup_label;\
+ }
+
+/* Invert data bits for a black run. */
+/* If rlen >= 64, execute makeup_action: this is to handle */
+/* makeup codes efficiently, since these are always a multiple of 64. */
+#define invert_data(rlen, black_byte, makeup_action, d)\
+ if ( rlen > qbit )\
+ { *q++ ^= (1 << qbit) - 1;\
+ rlen -= qbit;\
+ switch ( rlen >> 3 )\
+ {\
+ case 7: /* original rlen possibly >= 64 */\
+ if ( rlen + qbit >= 64 ) goto d;\
+ *q++ = black_byte;\
+ case 6: *q++ = black_byte;\
+ case 5: *q++ = black_byte;\
+ case 4: *q++ = black_byte;\
+ case 3: *q++ = black_byte;\
+ case 2: *q++ = black_byte;\
+ case 1: *q = black_byte;\
+ rlen &= 7;\
+ if ( !rlen ) { qbit = 0; break; }\
+ q++;\
+ case 0: /* know rlen != 0 */\
+ qbit = 8 - rlen;\
+ *q ^= 0xff << qbit;\
+ break;\
+ default: /* original rlen >= 64 */\
+d: memset(q, black_byte, rlen >> 3);\
+ q += rlen >> 3;\
+ rlen &= 7;\
+ if ( !rlen ) qbit = 0, q--;\
+ else qbit = 8 - rlen, *q ^= 0xff << qbit;\
+ makeup_action;\
+ }\
+ }\
+ else\
+ qbit -= rlen,\
+ *q ^= ((1 << rlen) - 1) << qbit
+
+/* Buffer refill for CCITTFaxDecode filter */
+private int cf_decode_eol(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_1d(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_2d(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_uncompressed(P2(stream_CFD_state *, stream_cursor_read *));
+private int
+s_CFD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ int wstop = ss->raster - 1;
+ int eol_count = ss->eol_count;
+ int k_left = ss->k_left;
+ int rows_left = ss->rows_left;
+ int status = 0;
+#ifdef DEBUG
+ const byte *rstart = pr->ptr;
+ const byte *wstart = pw->ptr;
+#endif
+
+top:
+#ifdef DEBUG
+ { hcd_declare_state;
+ hcd_load_state();
+ if_debug8('w', "\
+[w]CFD_process top: eol_count=%d, k_left=%d, rows_left=%d\n\
+ bits=0x%lx, bits_left=%d, read %u, wrote %u%s\n",
+ eol_count, k_left, rows_left,
+ (ulong)bits, bits_left,
+ (uint)(p - rstart), (uint)(pw->ptr - wstart),
+ (ss->skipping_damage ? ", skipping damage" : ""));
+ }
+#endif
+ if ( ss->skipping_damage )
+ { /* Skip until we reach an EOL. */
+ hcd_declare_state;
+ int skip;
+ status = 0;
+ do
+ { switch ( (skip = cf_decode_eol(ss, pr)) )
+ {
+ default: /* not EOL */
+ hcd_load_state();
+ skip_bits(-skip);
+ hcd_store_state();
+ continue;
+ case 0: /* need more input */
+ goto out;
+ case 1: /* EOL */
+ { /* Back up over the EOL. */
+ hcd_load_state();
+ bits_left += run_eol_code_length;
+ hcd_store_state();
+ }
+ ss->skipping_damage = false;
+ }
+ }
+ while ( ss->skipping_damage );
+ ss->damaged_rows++;
+ }
+ /*
+ * Check for a completed input scan line. This isn't quite as
+ * simple as it seems, because we could have run out of input data
+ * between a makeup code and a 0-length termination code, or in a
+ * 2-D line before a final horizontal code with a 0-length second
+ * run. There's probably a way to think about this situation that
+ * doesn't require a special check, but I haven't found it yet.
+ */
+ if ( ss->wpos == wstop && ss->cbit <= (-ss->Columns & 7) &&
+ (k_left == 0 ? !(ss->run_color & ~1) : ss->run_color == 0)
+ )
+ { /* Check for completed data to be copied to the client. */
+ /* (We could avoid the extra copy step for 1-D, but */
+ /* it's simpler not to, and it doesn't cost much.) */
+ if ( ss->rpos < ss->wpos )
+ { stream_cursor_read cr;
+ cr.ptr = ss->lbuf + ss->rpos;
+ cr.limit = ss->lbuf + ss->wpos;
+ status = stream_move(&cr, pw);
+ ss->rpos = cr.ptr - ss->lbuf;
+ if ( status )
+ goto out;
+ }
+ if ( rows_left > 0 && --rows_left == 0 )
+ { status = EOFC;
+ goto out;
+ }
+ if ( ss->K != 0 )
+ { byte *prev_bits = ss->lprev;
+ ss->lprev = ss->lbuf;
+ ss->lbuf = prev_bits;
+ if ( ss->K > 0 )
+ k_left = (k_left == 0 ? ss->K : k_left) - 1;
+ }
+ ss->rpos = ss->wpos = -1;
+ ss->eol_count = eol_count = 0;
+ ss->cbit = 0;
+ ss->invert = (ss->BlackIs1 ? 0 : 0xff);
+ memset(ss->lbuf, ss->invert, wstop + 1);
+ ss->run_color = 0;
+ /*
+ * If EndOfLine is true, we want to include the byte padding
+ * in the string of initial zeros in the EOL. If EndOfLine
+ * is false, we aren't sure what we should do....
+ */
+ if ( ss->EncodedByteAlign & !ss->EndOfLine )
+ ss->bits_left &= ~7;
+ }
+ /* If we're between scan lines, scan for EOLs. */
+ if ( ss->wpos < 0 )
+ { while ( (status = cf_decode_eol(ss, pr)) > 0 )
+ { if_debug0('w', "[w]EOL\n");
+ /* If we are in a Group 3 mixed regime, */
+ /* check the next bit for 1- vs. 2-D. */
+ if ( ss->K > 0 )
+ { hcd_declare_state;
+ hcd_load_state();
+ ensure_bits(1, out); /* can't fail */
+ k_left = (peek_bits(1) ? 0 : 1);
+ skip_bits(1);
+ hcd_store_state();
+ }
+ ++eol_count;
+ if ( ss->EndOfBlock )
+ { /* Check for end-of-data sequence. */
+ if (eol_count == (ss->K < 0 ? 2 : 6))
+ { status = EOFC;
+ goto out;
+ }
+ }
+ else
+ break; /* >1 EOL is an error */
+ }
+ if ( status == 0 ) /* input empty while scanning EOLs */
+ goto out;
+ switch ( eol_count )
+ {
+ case 0:
+ if ( ss->EndOfLine )
+ { /* EOL is required, but none is present. */
+ status = ERRC;
+ goto check;
+ }
+ case 1:
+ break;
+ default:
+ status = ERRC;
+ goto check;
+ }
+ }
+ /* Now decode actual data. */
+ if ( k_left < 0 )
+ { if_debug0('w', "[w2]new row\n");
+ status = cf_decode_2d(ss, pr);
+ }
+ else if ( k_left == 0 )
+ { if_debug0('w', "[w1]new row\n");
+ status = cf_decode_1d(ss, pr);
+ }
+ else
+ { if_debug1('w', "[w1]new 2-D row, %d left\n", k_left);
+ status = cf_decode_2d(ss, pr);
+ }
+ if_debug3('w', "[w]CFD status = %d, wpos = %d, cbit = %d\n",
+ status, ss->wpos, ss->cbit);
+check: switch ( status )
+ {
+ case 1: /* output full */
+ goto top;
+ case ERRC:
+ /* Check for special handling of damaged rows. */
+ if ( ss->damaged_rows >= ss->DamagedRowsBeforeError ||
+ !(ss->EndOfLine && ss->K >= 0)
+ )
+ break;
+ /* Substitute undamaged data if appropriate. */
+ /****** NOT IMPLEMENTED YET ******/
+ { ss->wpos = wstop;
+ ss->cbit = -ss->Columns & 7;
+ ss->run_color = 0;
+ }
+ ss->skipping_damage = true;
+ goto top;
+ default:
+ ss->damaged_rows = 0; /* finished a good row */
+ }
+out: ss->k_left = k_left;
+ ss->rows_left = rows_left;
+ ss->eol_count = eol_count;
+ return status;
+}
+
+#undef ss
+
+/*
+ * Decode a leading EOL, if any.
+ * If an EOL is present, skip over it and return 1;
+ * if no EOL is present, read no input and return -N, where N is the
+ * number of initial bits that can be skipped in the search for an EOL;
+ * if more input is needed, return 0.
+ * Note that if we detected an EOL, we know that we can back up over it;
+ * if we detected an N-bit non-EOL, we know that at least N bits of data
+ * are available in the buffer.
+ */
+private int
+cf_decode_eol(stream_CFD_state *ss, stream_cursor_read *pr)
+{ hcd_declare_state;
+ int zeros;
+ int look_ahead;
+ hcd_load_state();
+ for ( zeros = 0; zeros < run_eol_code_length - 1; zeros++ )
+ { ensure_bits(1, out);
+ if ( peek_bits(1) )
+ return -(zeros + 1);
+ skip_bits(1);
+ }
+ /* We definitely have an EOL. Skip further zero bits. */
+ look_ahead = (ss->K > 0 ? 2 : 1);
+ for ( ; ; )
+ { ensure_bits(look_ahead, back);
+ if ( peek_bits(1) )
+ break;
+ skip_bits(1);
+ }
+ skip_bits(1);
+ hcd_store_state();
+ return 1;
+back: /*
+ * We ran out of data while skipping zeros.
+ * We know we are at a byte boundary, and have just skipped
+ * at least run_eol_code_length - 1 zeros. However,
+ * bits_left may be 1 if look_ahead == 2.
+ */
+ bits &= (1 << bits_left) - 1;
+ bits_left += run_eol_code_length - 1;
+ hcd_store_state();
+out: return 0;
+}
+
+/* Decode a 1-D scan line. */
+private int
+cf_decode_1d(stream_CFD_state *ss, stream_cursor_read *pr)
+{ cfd_declare_state;
+ byte black_byte = (ss->BlackIs1 ? 0xff : 0);
+ int end_bit = -ss->Columns & 7;
+ byte *stop = ss->lbuf - 1 + ss->raster;
+ int run_color = ss->run_color;
+ int status;
+ int bcnt;
+
+ cfd_load_state();
+ if_debug1('w', "[w1]entry run_color = %d\n", ss->run_color);
+ if ( ss->run_color > 0 )
+ goto db;
+ else
+ goto dw;
+#define q_at_stop() (q >= stop && (qbit <= end_bit || q > stop))
+top: run_color = 0;
+ if ( q_at_stop() )
+ goto done;
+dw: /* Decode a white run. */
+ get_run(cf_white_decode, cfd_white_initial_bits, bcnt, "[w1]white", out0);
+ if ( bcnt < 0 ) /* exceptional situation */
+ { switch ( bcnt )
+ {
+ case run_uncompressed: /* Uncompressed data. */
+ cfd_store_state();
+ bcnt = cf_decode_uncompressed(ss, pr);
+ if ( bcnt < 0 )
+ return bcnt;
+ cfd_load_state();
+ if ( bcnt ) goto db;
+ else goto dw;
+ /*case run_error:*/
+ /*case run_zeros:*/ /* Premature end-of-line. */
+ default:
+ status = ERRC;
+ goto out;
+ }
+ }
+ skip_data(bcnt, dwx);
+ if ( q_at_stop() )
+ { run_color = 0; /* not inside a run */
+ goto done;
+ }
+ run_color = 1;
+db: /* Decode a black run. */
+ get_run(cf_black_decode, cfd_black_initial_bits, bcnt, "[w1]black", out1);
+ if ( bcnt < 0 )
+ { /* All exceptional codes are invalid here. */
+ /****** WRONG, uncompressed IS ALLOWED ******/
+ status = ERRC;
+ goto out;
+ }
+ /* Invert bits designated by black run. */
+ invert_data(bcnt, black_byte, goto dbx, idb);
+ goto top;
+dwx: /* If we run out of data after a makeup code, */
+ /* note that we are still processing a white run. */
+ run_color = -1;
+ goto dw;
+dbx: /* If we run out of data after a makeup code, */
+ /* note that we are still processing a black run. */
+ run_color = 2;
+ goto db;
+done: if ( q > stop || qbit < end_bit )
+ status = ERRC;
+ else
+ status = 1;
+out: cfd_store_state();
+ ss->run_color = run_color;
+ if_debug1('w', "[w1]exit run_color = %d\n", run_color);
+ return status;
+out0: /* We already set run_color to 0 or -1. */
+ status = 0;
+ goto out;
+out1: /* We already set run_color to 1 or 2. */
+ status = 0;
+ goto out;
+}
+
+/* Decode a 2-D scan line. */
+private int
+cf_decode_2d(stream_CFD_state *ss, stream_cursor_read *pr)
+{ cfd_declare_state;
+ byte invert_white = (ss->BlackIs1 ? 0 : 0xff);
+ byte black_byte = ~invert_white;
+ byte invert = ss->invert;
+ int end_count = -ss->Columns & 7;
+ uint raster = ss->raster;
+ byte *q0 = ss->lbuf;
+ byte *prev_q01 = ss->lprev + 1;
+ byte *endptr = q0 - 1 + raster;
+ int init_count = raster << 3;
+ register int count;
+ int rlen;
+ int status;
+ cfd_load_state();
+ count = ((endptr - q) << 3) + qbit;
+ endptr[1] = 0xa0; /* a byte with some 0s and some 1s, */
+ /* to ensure run scan will stop */
+ if_debug1('W', "[w2]raster=%d\n", raster);
+ switch ( ss->run_color )
+ {
+ case -2: ss->run_color = 0; goto hww;
+ case -1: ss->run_color = 0; goto hbw;
+ case 1: ss->run_color = 0; goto hwb;
+ case 2: ss->run_color = 0; goto hbb;
+ /*case 0:*/
+ }
+top: if ( count <= end_count )
+ { status = (count < end_count ? ERRC : 1);
+ goto out;
+ }
+ /* If invert == invert_white, white and black have their */
+ /* correct meanings; if invert == ~invert_white, */
+ /* black and white are interchanged. */
+ if_debug1('W', "[w2]%4d:\n", count);
+#ifdef DEBUG
+ /* Check the invariant between q, qbit, and count. */
+ { int pcount = (endptr - q) * 8 + qbit;
+ if ( pcount != count )
+ dprintf2("[w2]Error: count=%d pcount=%d\n",
+ count, pcount);
+ }
+#endif
+ /* We could just use get_run here, but we can do better: */
+ ensure_bits(3, out0);
+#define vertical_0 (countof(cf2_run_vertical) / 2)
+ switch( peek_bits(3) )
+ {
+ default/*4..7*/: /* vertical(0) */
+ skip_bits(1);
+ rlen = vertical_0;
+ break;
+ case 2: /* vertical(+1) */
+ skip_bits(3);
+ rlen = vertical_0 + 1;
+ break;
+ case 3: /* vertical(-1) */
+ skip_bits(3);
+ rlen = vertical_0 - 1;
+ break;
+ case 1: /* horizontal */
+ skip_bits(3);
+ if ( invert == invert_white )
+ goto hww;
+ else
+ goto hbb;
+ case 0: /* everything else */
+ get_run(cf_2d_decode, cfd_2d_initial_bits, rlen,
+ "[w2]", out0);
+ /* rlen may be run2_pass, run_uncompressed, or */
+ /* 0..countof(cf2_run_vertical)-1. */
+ if ( rlen < 0 )
+ switch ( rlen )
+ {
+ case run2_pass:
+ break;
+ case run_uncompressed:
+ { int which;
+ cfd_store_state();
+ which = cf_decode_uncompressed(ss, pr);
+ if ( which < 0 )
+ { status = which;
+ goto out;
+ }
+ cfd_load_state();
+ /****** ADJUST count ******/
+ invert = (which ? ~invert_white : invert_white);
+ } goto top;
+ default: /* run_error, run_zeros */
+ status = ERRC;
+ goto out;
+ }
+ }
+ /* Interpreting the run requires scanning the */
+ /* previous ('reference') line. */
+ { int prev_count = count;
+ byte prev_data;
+ int dlen;
+ static const byte count_bit[8] =
+ { 0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40 };
+ byte *prev_q = prev_q01 + (q - q0);
+ int plen;
+
+ if ( !(count & 7) )
+ prev_q++; /* because of skip macros */
+ prev_data = prev_q[-1] ^ invert;
+ /* Find the b1 transition. */
+ if ( (prev_data & count_bit[prev_count & 7]) &&
+ (prev_count < init_count || invert != invert_white )
+ )
+ { /* Look for changing white first. */
+ if_debug1('W', " data=0x%x", prev_data);
+ skip_black_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if ( prev_count < end_count ) /* overshot */
+ prev_count = end_count;
+ if_debug1('W', " b1 other=%d", prev_count);
+ }
+ if ( prev_count != end_count )
+ { if_debug1('W', " data=0x%x", prev_data);
+ skip_white_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if ( prev_count < end_count ) /* overshot */
+ prev_count = end_count;
+ if_debug1('W', " b1 same=%d", prev_count);
+ }
+ /* b1 = prev_count; */
+ if ( rlen == run2_pass )
+ { /* Pass mode. Find b2. */
+ if ( prev_count != end_count )
+ { if_debug1('W', " data=0x%x", prev_data);
+ skip_black_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if ( prev_count < end_count ) /* overshot */
+ prev_count = end_count;
+ }
+ /* b2 = prev_count; */
+ if_debug2('W', " b2=%d, pass %d\n",
+ prev_count, count - prev_count);
+ }
+ else
+ { /* Vertical coding. */
+ /* Remember that count counts *down*. */
+ prev_count += rlen - vertical_0; /* a1 */
+ if_debug2('W', " vertical %d -> %d\n",
+ rlen - vertical_0, prev_count);
+ }
+ /* Now either invert or skip from count */
+ /* to prev_count, and reset count. */
+ if ( invert == invert_white )
+ { /* Skip data bits. */
+ q = endptr - (prev_count >> 3);
+ qbit = prev_count & 7;
+ }
+ else
+ { /* Invert data bits. */
+ dlen = count - prev_count;
+ invert_data(dlen, black_byte, DO_NOTHING, idd);
+ }
+ count = prev_count;
+ if ( rlen >= 0 ) /* vertical mode */
+ invert = ~invert; /* polarity changes */
+ }
+ goto top;
+out: cfd_store_state();
+ ss->invert = invert;
+ return status;
+out0: status = 0;
+ goto out;
+ /*
+ * We handle horizontal decoding here, so that we can
+ * branch back into it if we run out of input data.
+ */
+ /* White, then black. */
+hww: get_run(cf_white_decode, cfd_white_initial_bits, rlen,
+ " white", outww);
+ if ( (count -= rlen) < end_count )
+ { status = ERRC;
+ goto out;
+ }
+ skip_data(rlen, hww);
+ /* Handle the second half of a white-black horizontal code. */
+hwb: get_run(cf_black_decode, cfd_black_initial_bits, rlen,
+ " black", outwb);
+ if ( (count -= rlen) < end_count )
+ { status = ERRC;
+ goto out;
+ }
+ invert_data(rlen, black_byte, goto hwb, ihwb);
+ goto top;
+outww: ss->run_color = -2;
+ goto out0;
+outwb: ss->run_color = 1;
+ goto out0;
+ /* Black, then white. */
+hbb: get_run(cf_black_decode, cfd_black_initial_bits, rlen,
+ " black", outbb);
+ if ( (count -= rlen) < end_count )
+ { status = ERRC;
+ goto out;
+ }
+ invert_data(rlen, black_byte, goto hbb, ihbb);
+ /* Handle the second half of a black-white horizontal code. */
+hbw: get_run(cf_white_decode, cfd_white_initial_bits, rlen,
+ " white", outbw);
+ if ( (count -= rlen) < end_count )
+ { status = ERRC;
+ goto out;
+ }
+ skip_data(rlen, hbw);
+ goto top;
+outbb: ss->run_color = 2;
+ goto out0;
+outbw: ss->run_color = -1;
+ goto out0;
+}
+
+#if 1 /****************/
+private int
+cf_decode_uncompressed(stream_CFD_state *ss, stream_cursor_read *pr)
+{ return ERRC;
+}
+#else /****************/
+
+/* Decode uncompressed data. */
+/* (Not tested: no sample data available!) */
+/****** DOESN'T CHECK FOR OVERFLOWING SCAN LINE ******/
+private int
+cf_decode_uncompressed(stream *s)
+{ cfd_declare_state;
+ const cfd_node *np;
+ int clen, rlen;
+ cfd_load_state();
+ while ( 1 )
+ { ensure_bits(cfd_uncompressed_initial_bits, NOOUT);
+ np = &cf_uncompressed_decode[peek_bits(cfd_uncompressed_initial_bits)];
+ clen = np->code_length;
+ rlen = np->run_length;
+ if ( clen > cfd_uncompressed_initial_bits )
+ { /* Must be an exit code. */
+ break;
+ }
+ if ( rlen == cfd_uncompressed_initial_bits )
+ { /* Longest representable white run */
+ if_debug1('W', "[wu]%d\n", rlen);
+ if ( (qbit -= cfd_uncompressed_initial_bits) < 0 )
+ qbit += 8, q++;
+ }
+ else
+ { if_debug1('W', "[wu]%d+1\n", rlen);
+ if ( qbit -= rlen < 0 )
+ qbit += 8, q++;
+ *q ^= 1 << qbit;
+ }
+ skip_bits(clen);
+ }
+ clen -= cfd_uncompressed_initial_bits;
+ skip_bits(cfd_uncompressed_initial_bits);
+ ensure_bits(clen, NOOUT);
+ np = &cf_uncompressed_decode[rlen + peek_var_bits(clen)];
+ rlen = np->run_length;
+ skip_bits(np->code_length);
+ if_debug1('w', "[wu]exit %d\n", rlen);
+ if ( rlen >= 0 )
+ { /* Valid exit code, rlen = 2 * run length + next polarity */
+ if ( (qbit -= rlen >> 1) < 0 )
+ qbit += 8, q++;
+ rlen &= 1;
+ }
+out: /******* WRONG ******/
+ cfd_store_state();
+ return rlen;
+}
+
+#endif /****************/
+
+/* Stream template */
+const stream_template s_CFD_template =
+{ &st_CFD_state, s_CFD_init, s_CFD_process, 1, 1, s_CFD_release,
+ s_CFD_set_defaults
+};
diff --git a/gs/src/scfdgen.c b/gs/src/scfdgen.c
new file mode 100644
index 000000000..7db4fc158
--- /dev/null
+++ b/gs/src/scfdgen.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scfdgen.c */
+/* Generate the CCITTFaxDecode tables */
+#include "stdio_.h" /* includes std.h */
+#include "scf.h"
+#include "malloc_.h"
+#include "memory_.h"
+
+typedef void (*cfd_node_proc)(P6(cfd_node *, cfd_node *,
+ uint, int, int, int));
+typedef void (*cfd_enum_proc)(P4(cfd_node_proc,
+ cfd_node *, cfd_node *, int));
+private void cfd_build_tree(P4(cfd_node *, cfd_enum_proc, int, FILE *));
+private void cfd_enumerate_white(P4(cfd_node_proc,
+ cfd_node *, cfd_node *, int));
+private void cfd_enumerate_black(P4(cfd_node_proc,
+ cfd_node *, cfd_node *, int));
+private void cfd_enumerate_2d(P4(cfd_node_proc,
+ cfd_node *, cfd_node *, int));
+private void cfd_enumerate_uncompressed(P4(cfd_node_proc,
+ cfd_node *, cfd_node *, int));
+
+main()
+{ FILE *out = fopen("scfdtab.c", "w");
+ cfd_node area[1 << max(cfd_white_initial_bits, cfd_black_initial_bits)];
+ fputs("/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved. */\n\n", out);
+ fputs("/* This file was generated automatically. It is governed by the same terms */\n", out);
+ fputs("/* as the files scfetab.c and scfdgen.c from which it was derived. */\n", out);
+ fputs("/* Consult those files for the licensing terms and conditions. */\n\n", out);
+ fputs("/* scfdtab.c */\n", out);
+ fputs("/* Tables for CCITTFaxDecode filter. */\n\n", out);
+ fputs("#include \"std.h\"\n", out);
+ fputs("#include \"scommon.h\"\t\t/* for scf.h */\n", out);
+ fputs("#include \"scf.h\"\n\n", out);
+ fputs("/* White decoding table. */\n", out);
+ fputs("const cfd_node far_data cf_white_decode[] = {\n", out);
+ cfd_build_tree(area, cfd_enumerate_white, cfd_white_initial_bits, out);
+ fputs("\n};\n\n", out);
+ fputs("/* Black decoding table. */\n", out);
+ fputs("const cfd_node far_data cf_black_decode[] = {\n", out);
+ cfd_build_tree(area, cfd_enumerate_black, cfd_black_initial_bits, out);
+ fputs("\n};\n\n", out);
+ fputs("/* 2-D decoding table. */\n", out);
+ fputs("const cfd_node far_data cf_2d_decode[] = {\n", out);
+ cfd_build_tree(area, cfd_enumerate_2d, cfd_2d_initial_bits, out);
+ fputs("\n};\n\n", out);
+ fputs("/* Uncompresssed decoding table. */\n", out);
+ fputs("const cfd_node far_data cf_uncompressed_decode[] = {\n", out);
+ cfd_build_tree(area, cfd_enumerate_uncompressed, cfd_uncompressed_initial_bits, out);
+ fputs("\n};\n\n", out);
+ fputs("/* Dummy executable code to pacify compilers. */\n", out);
+ fputs("void\ncfd_dummy()\n{\n}\n", out);
+ fclose(out);
+ return 0;
+}
+
+/* Initialize first-level leaves, count second-level nodes. */
+private void
+cfd_count_nodes(cfd_node *tree, cfd_node *ignore_extn,
+ uint code, int code_length, int run_length, int initial_bits)
+{ if ( code_length <= initial_bits )
+ { /* Initialize one or more first-level leaves. */
+ int sh = initial_bits - code_length;
+ cfd_node *np = &tree[code << sh];
+ int i;
+ for ( i = 1 << sh; i > 0; i--, np++ )
+ np->run_length = run_length,
+ np->code_length = code_length;
+ }
+ else
+ { /* Note the need for a second level. */
+ cfd_node *np = &tree[code >> (code_length - initial_bits)];
+ np->code_length = max(np->code_length, code_length);
+ }
+}
+
+/* Initialize second-level nodes. */
+private void
+cfd_init2_nodes(cfd_node *tree, cfd_node *extn,
+ uint code, int code_length, int run_length, int initial_bits)
+{ int xbits = code_length - initial_bits;
+ int xrep;
+ cfd_node *np1, *np2;
+ int i;
+ if ( xbits <= 0 ) return;
+ np1 = &tree[code >> xbits];
+ np2 = &extn[np1->run_length - (1 << initial_bits)];
+ xrep = np1->code_length - code_length;
+ i = 1 << xrep;
+ np2 += (code & ((1 << xbits) - 1)) * i;
+ for ( ; i > 0; i--, np2++ )
+ np2->run_length = run_length,
+ np2->code_length = xbits;
+}
+
+/* Enumerate all the relevant white or black codes. */
+private void
+cfd_enumerate_codes(cfd_node_proc proc, cfd_node *tree, cfd_node *extn,
+ int initial_bits, const cfe_run *tt, const cfe_run *mut)
+{ int i;
+ const cfe_run *ep;
+ for ( i = 0, ep = tt; i < 64; i++, ep++ )
+ (*proc)(tree, extn, ep->code, ep->code_length, i, initial_bits);
+ for ( i = 1, ep = mut + 1; i < 41; i++, ep++ )
+ (*proc)(tree, extn, ep->code, ep->code_length, i << 6, initial_bits);
+ (*proc)(tree, extn, cf1_run_uncompressed.code, cf1_run_uncompressed.code_length, run_uncompressed, initial_bits);
+ (*proc)(tree, extn, 0, run_eol_code_length - 1, run_zeros, initial_bits);
+}
+private void
+cfd_enumerate_white(cfd_node_proc proc, cfd_node *tree, cfd_node *extn,
+ int initial_bits)
+{ cfd_enumerate_codes(proc, tree, extn, initial_bits,
+ cf_white_termination, cf_white_make_up);
+}
+private void
+cfd_enumerate_black(cfd_node_proc proc, cfd_node *tree, cfd_node *extn,
+ int initial_bits)
+{ cfd_enumerate_codes(proc, tree, extn, initial_bits,
+ cf_black_termination, cf_black_make_up);
+}
+
+/* Enumerate the 2-D codes. */
+private void
+cfd_enumerate_2d(cfd_node_proc proc, cfd_node *tree, cfd_node *extn,
+ int initial_bits)
+{ int i;
+ const cfe_run *ep;
+ (*proc)(tree, extn, cf2_run_pass.code, cf2_run_pass.code_length,
+ run2_pass, initial_bits);
+ (*proc)(tree, extn, cf2_run_horizontal.code, cf2_run_horizontal.code_length,
+ run2_horizontal, initial_bits);
+ for ( i = 0; i < countof(cf2_run_vertical); i++ )
+ { ep = &cf2_run_vertical[i];
+ (*proc)(tree, extn, ep->code, ep->code_length, i, initial_bits);
+ }
+ (*proc)(tree, extn, cf2_run_uncompressed.code, cf2_run_uncompressed.code_length,
+ run_uncompressed, initial_bits);
+ (*proc)(tree, extn, 0, run_eol_code_length - 1, run_zeros, initial_bits);
+}
+
+/* Enumerate the uncompressed codes. */
+private void
+cfd_enumerate_uncompressed(cfd_node_proc proc, cfd_node *tree, cfd_node *extn,
+ int initial_bits)
+{ int i;
+ const cfe_run *ep;
+ for ( i = 0; i < countof(cf_uncompressed); i++ )
+ { ep = &cf_uncompressed[i];
+ (*proc)(tree, extn, ep->code, ep->code_length, i, initial_bits);
+ }
+ for ( i = 0; i < countof(cf_uncompressed_exit); i++ )
+ { ep = &cf_uncompressed_exit[i];
+ (*proc)(tree, extn, ep->code, ep->code_length, i, initial_bits);
+ }
+}
+
+/* Build and write out the table. */
+private void
+cfd_build_tree(cfd_node *tree, cfd_enum_proc enum_proc, int initial_bits,
+ FILE *f)
+{ cfd_node *np;
+ const char *prev = "";
+ int i, next;
+ cfd_node *extn;
+ memset(tree, 0, sizeof(cfd_node) << initial_bits);
+ /* Construct and write the first level of the tree. */
+ (*enum_proc)(cfd_count_nodes, tree, (cfd_node *)0, initial_bits);
+ next = 0;
+ for ( i = 0, np = tree; i < 1 << initial_bits; i++, np++ )
+ { if ( np->code_length > initial_bits ) /* second level needed */
+ { np->run_length = next + (1 << initial_bits);
+ next += 1 << (np->code_length - initial_bits);
+ }
+ fprintf(f, "%s\t{ %d, %d }", prev, np->run_length, np->code_length);
+ prev = ",\n";
+ }
+ /* Construct and write the second level. */
+ extn = (cfd_node *)malloc(sizeof(cfd_node) * next);
+ for ( i = 0, np = extn; i < next; i++, np++ )
+ np->run_length = run_error,
+ np->code_length = 0;
+ (*enum_proc)(cfd_init2_nodes, tree, extn, initial_bits);
+ for ( i = 0, np = extn; i < next; i++, np++ )
+ fprintf(f, ",\n\t{ %d, %d }", np->run_length, np->code_length);
+ free((char *)extn);
+}
diff --git a/gs/src/scfdtab.c b/gs/src/scfdtab.c
new file mode 100644
index 000000000..dc20d7caf
--- /dev/null
+++ b/gs/src/scfdtab.c
@@ -0,0 +1,938 @@
+/* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved. */
+
+/* This file was generated automatically. It is governed by the same terms */
+/* as the files scftab.c and scfdgen.c from which it was derived. */
+/* Consult those files for the licensing terms and conditions. */
+
+/* scfdtab.c */
+/* Tables for CCITTFaxDecode filter. */
+
+#include "std.h"
+#include "scommon.h" /* for scf.h */
+#include "scf.h"
+
+/* White decoding table. */
+const cfd_node far_data cf_white_decode[] = {
+ { 256, 12 },
+ { 272, 12 },
+ { 29, 8 },
+ { 30, 8 },
+ { 45, 8 },
+ { 46, 8 },
+ { 22, 7 },
+ { 22, 7 },
+ { 23, 7 },
+ { 23, 7 },
+ { 47, 8 },
+ { 48, 8 },
+ { 13, 6 },
+ { 13, 6 },
+ { 13, 6 },
+ { 13, 6 },
+ { 20, 7 },
+ { 20, 7 },
+ { 33, 8 },
+ { 34, 8 },
+ { 35, 8 },
+ { 36, 8 },
+ { 37, 8 },
+ { 38, 8 },
+ { 19, 7 },
+ { 19, 7 },
+ { 31, 8 },
+ { 32, 8 },
+ { 1, 6 },
+ { 1, 6 },
+ { 1, 6 },
+ { 1, 6 },
+ { 12, 6 },
+ { 12, 6 },
+ { 12, 6 },
+ { 12, 6 },
+ { 53, 8 },
+ { 54, 8 },
+ { 26, 7 },
+ { 26, 7 },
+ { 39, 8 },
+ { 40, 8 },
+ { 41, 8 },
+ { 42, 8 },
+ { 43, 8 },
+ { 44, 8 },
+ { 21, 7 },
+ { 21, 7 },
+ { 28, 7 },
+ { 28, 7 },
+ { 61, 8 },
+ { 62, 8 },
+ { 63, 8 },
+ { 0, 8 },
+ { 320, 8 },
+ { 384, 8 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 10, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 11, 5 },
+ { 27, 7 },
+ { 27, 7 },
+ { 59, 8 },
+ { 60, 8 },
+ { 288, 9 },
+ { 290, 9 },
+ { 18, 7 },
+ { 18, 7 },
+ { 24, 7 },
+ { 24, 7 },
+ { 49, 8 },
+ { 50, 8 },
+ { 51, 8 },
+ { 52, 8 },
+ { 25, 7 },
+ { 25, 7 },
+ { 55, 8 },
+ { 56, 8 },
+ { 57, 8 },
+ { 58, 8 },
+ { 192, 6 },
+ { 192, 6 },
+ { 192, 6 },
+ { 192, 6 },
+ { 1664, 6 },
+ { 1664, 6 },
+ { 1664, 6 },
+ { 1664, 6 },
+ { 448, 8 },
+ { 512, 8 },
+ { 292, 9 },
+ { 640, 8 },
+ { 576, 8 },
+ { 294, 9 },
+ { 296, 9 },
+ { 298, 9 },
+ { 300, 9 },
+ { 302, 9 },
+ { 256, 7 },
+ { 256, 7 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 2, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 128, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 8, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 9, 5 },
+ { 16, 6 },
+ { 16, 6 },
+ { 16, 6 },
+ { 16, 6 },
+ { 17, 6 },
+ { 17, 6 },
+ { 17, 6 },
+ { 17, 6 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 14, 6 },
+ { 14, 6 },
+ { 14, 6 },
+ { 14, 6 },
+ { 15, 6 },
+ { 15, 6 },
+ { 15, 6 },
+ { 15, 6 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 64, 5 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { 7, 4 },
+ { -2, 3 },
+ { -2, 3 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -3, 4 },
+ { 1792, 3 },
+ { 1792, 3 },
+ { 1984, 4 },
+ { 2048, 4 },
+ { 2112, 4 },
+ { 2176, 4 },
+ { 2240, 4 },
+ { 2304, 4 },
+ { 1856, 3 },
+ { 1856, 3 },
+ { 1920, 3 },
+ { 1920, 3 },
+ { 2368, 4 },
+ { 2432, 4 },
+ { 2496, 4 },
+ { 2560, 4 },
+ { 1472, 1 },
+ { 1536, 1 },
+ { 1600, 1 },
+ { 1728, 1 },
+ { 704, 1 },
+ { 768, 1 },
+ { 832, 1 },
+ { 896, 1 },
+ { 960, 1 },
+ { 1024, 1 },
+ { 1088, 1 },
+ { 1152, 1 },
+ { 1216, 1 },
+ { 1280, 1 },
+ { 1344, 1 },
+ { 1408, 1 }
+};
+
+/* Black decoding table. */
+const cfd_node far_data cf_black_decode[] = {
+ { 128, 12 },
+ { 160, 13 },
+ { 224, 12 },
+ { 256, 12 },
+ { 10, 7 },
+ { 11, 7 },
+ { 288, 12 },
+ { 12, 7 },
+ { 9, 6 },
+ { 9, 6 },
+ { 8, 6 },
+ { 8, 6 },
+ { 7, 5 },
+ { 7, 5 },
+ { 7, 5 },
+ { 7, 5 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 6, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 1, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 3, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { 2, 2 },
+ { -2, 4 },
+ { -2, 4 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -3, 5 },
+ { 1792, 4 },
+ { 1792, 4 },
+ { 1984, 5 },
+ { 2048, 5 },
+ { 2112, 5 },
+ { 2176, 5 },
+ { 2240, 5 },
+ { 2304, 5 },
+ { 1856, 4 },
+ { 1856, 4 },
+ { 1920, 4 },
+ { 1920, 4 },
+ { 2368, 5 },
+ { 2432, 5 },
+ { 2496, 5 },
+ { 2560, 5 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 18, 3 },
+ { 52, 5 },
+ { 52, 5 },
+ { 640, 6 },
+ { 704, 6 },
+ { 768, 6 },
+ { 832, 6 },
+ { 55, 5 },
+ { 55, 5 },
+ { 56, 5 },
+ { 56, 5 },
+ { 1280, 6 },
+ { 1344, 6 },
+ { 1408, 6 },
+ { 1472, 6 },
+ { 59, 5 },
+ { 59, 5 },
+ { 60, 5 },
+ { 60, 5 },
+ { 1536, 6 },
+ { 1600, 6 },
+ { 24, 4 },
+ { 24, 4 },
+ { 24, 4 },
+ { 24, 4 },
+ { 25, 4 },
+ { 25, 4 },
+ { 25, 4 },
+ { 25, 4 },
+ { 1664, 6 },
+ { 1728, 6 },
+ { 320, 5 },
+ { 320, 5 },
+ { 384, 5 },
+ { 384, 5 },
+ { 448, 5 },
+ { 448, 5 },
+ { 512, 6 },
+ { 576, 6 },
+ { 53, 5 },
+ { 53, 5 },
+ { 54, 5 },
+ { 54, 5 },
+ { 896, 6 },
+ { 960, 6 },
+ { 1024, 6 },
+ { 1088, 6 },
+ { 1152, 6 },
+ { 1216, 6 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 64, 3 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 13, 1 },
+ { 23, 4 },
+ { 23, 4 },
+ { 50, 5 },
+ { 51, 5 },
+ { 44, 5 },
+ { 45, 5 },
+ { 46, 5 },
+ { 47, 5 },
+ { 57, 5 },
+ { 58, 5 },
+ { 61, 5 },
+ { 256, 5 },
+ { 16, 3 },
+ { 16, 3 },
+ { 16, 3 },
+ { 16, 3 },
+ { 17, 3 },
+ { 17, 3 },
+ { 17, 3 },
+ { 17, 3 },
+ { 48, 5 },
+ { 49, 5 },
+ { 62, 5 },
+ { 63, 5 },
+ { 30, 5 },
+ { 31, 5 },
+ { 32, 5 },
+ { 33, 5 },
+ { 40, 5 },
+ { 41, 5 },
+ { 22, 4 },
+ { 22, 4 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 14, 1 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 15, 2 },
+ { 128, 5 },
+ { 192, 5 },
+ { 26, 5 },
+ { 27, 5 },
+ { 28, 5 },
+ { 29, 5 },
+ { 19, 4 },
+ { 19, 4 },
+ { 20, 4 },
+ { 20, 4 },
+ { 34, 5 },
+ { 35, 5 },
+ { 36, 5 },
+ { 37, 5 },
+ { 38, 5 },
+ { 39, 5 },
+ { 21, 4 },
+ { 21, 4 },
+ { 42, 5 },
+ { 43, 5 },
+ { 0, 3 },
+ { 0, 3 },
+ { 0, 3 },
+ { 0, 3 }
+};
+
+/* 2-D decoding table. */
+const cfd_node far_data cf_2d_decode[] = {
+ { 128, 11 },
+ { 144, 10 },
+ { 6, 7 },
+ { 0, 7 },
+ { 5, 6 },
+ { 5, 6 },
+ { 1, 6 },
+ { 1, 6 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -4, 4 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { -5, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 4, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { 3, 1 },
+ { -2, 4 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -1, 0 },
+ { -3, 3 }
+};
+
+/* Uncompresssed decoding table. */
+const cfd_node far_data cf_uncompressed_decode[] = {
+ { 64, 12 },
+ { 5, 6 },
+ { 4, 5 },
+ { 4, 5 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 3, 4 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { 0, 1 },
+ { -1, 0 },
+ { -1, 0 },
+ { 8, 6 },
+ { 9, 6 },
+ { 6, 5 },
+ { 6, 5 },
+ { 7, 5 },
+ { 7, 5 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 4, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 5, 4 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 3, 3 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 0, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 },
+ { 1, 2 }
+};
+
+/* Dummy executable code to pacify compilers. */
+void
+cfd_dummy(void)
+{
+}
diff --git a/gs/src/scfe.c b/gs/src/scfe.c
new file mode 100644
index 000000000..c15306f95
--- /dev/null
+++ b/gs/src/scfe.c
@@ -0,0 +1,500 @@
+/* Copyright (C) 1992, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scfe.c */
+/* CCITTFax encoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "scf.h"
+#include "scfx.h"
+
+/* ------ Macros and support routines ------ */
+
+/* Statistics */
+
+#ifdef DEBUG
+private struct _r1d { ulong termination[64], make_up[41]; } runs_1d[2];
+# define count_run(tab, i) ((tab)[i]++)
+#else
+# define count_run(cnt, n) DO_NOTHING
+#endif
+
+/* Put a run onto the output stream. */
+/* Free variables: q, wlimit, status. */
+
+#define cf_ensure_put_runs(max_bytes, color, out)\
+ if ( wlimit - q < ss->max_bytes ) /* worst case */\
+ { ss->run_color = color;\
+ status = 1;\
+ goto out;\
+ }
+#define cf_put_run(ss, lenv, tt, mut, tab)\
+{ cfe_run rr;\
+ if ( lenv >= 64 )\
+ { while ( lenv >= 2560 + 64 )\
+ { rr = mut[40];\
+ count_run(tab.make_up, 40);\
+ hc_put_value(ss, q, rr.code, rr.code_length);\
+ lenv -= 2560;\
+ }\
+ rr = mut[lenv >> 6];\
+ count_run(tab.make_up, lenv >> 6);\
+ hc_put_value(ss, q, rr.code, rr.code_length);\
+ lenv &= 63;\
+ }\
+ rr = tt[lenv];\
+ count_run(tab.termination, lenv);\
+ hc_put_value(ss, q, rr.code, rr.code_length);\
+}
+
+#define cf_put_white_run(ss, lenv)\
+ cf_put_run(ss, lenv, cf_white_termination, cf_white_make_up, runs_1d[0])
+
+#define cf_put_black_run(ss, lenv)\
+ cf_put_run(ss, lenv, cf_black_termination, cf_black_make_up, runs_1d[1])
+
+/* ------ CCITTFaxEncode ------ */
+
+private_st_CFE_state();
+
+#define ss ((stream_CFE_state *)st)
+
+private void s_CFE_release(P1(stream_state *));
+
+/*
+ * For the 2-D encoding modes, we leave the previous complete scan line
+ * at the beginning of the buffer, and start the new data after it.
+ */
+
+/* Set default parameter values. */
+private void
+s_CFE_set_defaults(register stream_state *st)
+{ s_CFE_set_defaults_inline(ss);
+}
+
+/* Initialize CCITTFaxEncode filter */
+private int
+s_CFE_init(register stream_state *st)
+{ int columns = ss->Columns;
+ int raster = ss->raster =
+ round_up((columns + 7) >> 3, ss->DecodedByteAlign);
+
+ s_hce_init_inline(ss);
+ ss->count = raster << 3; /* starting a scan line */
+ ss->lbuf = ss->lprev = 0;
+ if ( columns > cfe_max_width )
+ return ERRC; /****** WRONG ******/
+ /* Because skip_white_pixels can look as many as 4 bytes ahead, */
+ /* we need to allow 4 extra bytes at the end of the row buffers. */
+ ss->lbuf = gs_alloc_bytes(st->memory, raster + 4,
+ "CFE lbuf");
+ if ( ss->lbuf == 0 )
+ { s_CFE_release(st);
+ return ERRC; /****** WRONG ******/
+ }
+ if ( ss->K != 0 )
+ { ss->lprev = gs_alloc_bytes(st->memory, raster + 4,
+ "CFE lprev");
+ if ( ss->lprev == 0 )
+ { s_CFE_release(st);
+ return ERRC; /****** WRONG ******/
+ }
+ /* Clear the initial reference line for 2-D encoding. */
+ /* Make sure it is terminated properly. */
+ memset(ss->lprev, (ss->BlackIs1 ? 0 : 0xff), raster);
+ if ( columns & 7 )
+ ss->lprev[raster - 1] ^= 0x80 >> (columns & 7);
+ else
+ ss->lprev[raster] = ~ss->lprev[0];
+ }
+ ss->copy_count = raster;
+ ss->new_line = true;
+ ss->k_left = (ss->K > 0 ? 1 : ss->K);
+ /* Initialize values for buffer space checking. */
+ { int max_bytes = cfe_max_code_bytes(columns);
+
+ /*
+ * For a single-run line, we need room for byte alignment,
+ * an aligned EOL, run_horizontal, and 2 runs.
+ */
+ ss->max_line_bytes = max_bytes * 2 + 4;
+ ss->max_run2_bytes = max_bytes * 2;
+ ss->max_run3_bytes = max_bytes * 3;
+ }
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_CFE_release(stream_state *st)
+{ gs_free_object(st->memory, ss->lprev, "CFE lprev(close)");
+ gs_free_object(st->memory, ss->lbuf, "CFE lbuf(close)");
+}
+
+/* Flush the buffer */
+private int cf_encode_1d(P4(stream_CFE_state *, const byte *,
+ stream_cursor_write *, uint));
+private int cf_encode_2d(P5(stream_CFE_state *, const byte *,
+ stream_cursor_write *, uint, const byte *));
+private int
+s_CFE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int raster = ss->raster;
+ int initial_count = raster << 3;
+ int end_count = -ss->Columns & 7;
+ byte end_mask = 1 << (-ss->Columns & 7);
+ int status = 0;
+ hce_declare_state;
+
+ hce_load_state();
+ while ( pr->ptr < rlimit || ss->count != initial_count )
+ { byte *end = ss->lbuf + raster - 1;
+ if_debug7('w', "[w]CFE: copy_count = %d, pr = 0x%lx(%d)0x%lx, pw = 0x%lx(%d)0x%lx\n",
+ ss->copy_count, (ulong)pr->ptr,
+ (int)(rlimit - pr->ptr), (ulong)rlimit,
+ (ulong)pw->ptr, (int)(wlimit - pw->ptr),
+ (ulong)wlimit);
+ /* Check whether we are still accumulating a scan line. */
+ if ( ss->copy_count != 0 )
+ { int rcount = rlimit - pr->ptr;
+ int ccount = min(rcount, ss->copy_count);
+ memcpy(ss->lbuf + raster - ss->copy_count,
+ pr->ptr + 1, ccount);
+ pr->ptr += ccount;
+ if ( (ss->copy_count -= ccount) != 0 )
+ goto out;
+ /*
+ * Ensure that the scan line ends with two
+ * polarity changes.
+ */
+ { byte end_bit = *end & end_mask;
+ byte not_bit = end_bit ^ end_mask;
+ *end &= -end_mask;
+ if ( end_mask == 1 )
+ end[1] = (end_bit ? 0x40 : 0x80);
+ else if ( end_mask == 2 )
+ *end |= not_bit >> 1, end[1] = end_bit << 7;
+ else
+ *end |= (not_bit >> 1) | (end_bit >> 2);
+ }
+ }
+ if ( ss->new_line )
+ { /* Start a new scan line. */
+ byte *q = pw->ptr;
+ if ( wlimit - q < ss->max_line_bytes )
+ { status = 1;
+ break;
+ }
+#ifdef DEBUG
+ if ( ss->K > 0 )
+ { if_debug1('w', "[w]new row, k_left=%d\n",
+ ss->k_left);
+ }
+ else
+ { if_debug0('w', "[w]new row\n");
+ }
+#endif
+ if ( ss->EndOfLine )
+ { const cfe_run *rp =
+ (ss->K <= 0 ? &cf_run_eol :
+ ss->k_left > 1 ? &cf2_run_eol_2d :
+ &cf2_run_eol_1d);
+ cfe_run run;
+ if ( ss->EncodedByteAlign )
+ { run = *rp;
+ /* Pad the run on the left */
+ /* so it winds up byte-aligned. */
+ run.code_length +=
+ (bits_left - run_eol_code_length) & 7;
+ if ( run.code_length > 16 ) /* <= 23 */
+ bits_left -= run.code_length & 7,
+ run.code_length = 16;
+ rp = &run;
+ }
+ hc_put_code(ss, q, rp);
+ pw->ptr = q;
+ }
+ else if ( ss->EncodedByteAlign )
+ bits_left &= ~7;
+ ss->run_color = 0;
+ ss->new_line = false;
+ }
+ hce_store_state();
+ if ( ss->K > 0 )
+ { /* Group 3, mixed encoding */
+ if ( --(ss->k_left) ) /* Use 2-D encoding */
+ { status = cf_encode_2d(ss, ss->lbuf, pw, end_count, ss->lprev);
+ if ( status )
+ { /* We didn't finish encoding */
+ /* the line, so back out. */
+ ss->k_left++;
+ }
+ }
+ else /* Use 1-D encoding */
+ { status = cf_encode_1d(ss, ss->lbuf, pw, end_count);
+ if ( status )
+ { /* Didn't finish encoding the line, */
+ /* back out. */
+ ss->k_left++;
+ }
+ else
+ ss->k_left = ss->K;
+ }
+ }
+ else /* Uniform encoding */
+ { status = (ss->K == 0 ?
+ cf_encode_1d(ss, ss->lbuf, pw, end_count) :
+ cf_encode_2d(ss, ss->lbuf, pw, end_count, ss->lprev));
+ }
+ hce_load_state();
+ if ( status )
+ break;
+ if ( ss->count == end_count )
+ { /* Finished a scan line, start a new one. */
+ ss->count = initial_count;
+ ss->new_line = true;
+ if ( ss->K != 0 )
+ { byte *temp = ss->lbuf;
+ ss->lbuf = ss->lprev;
+ ss->lprev = temp;
+ }
+ ss->copy_count = raster;
+ }
+ }
+ /* Check for end of data. */
+ if ( last && status == 0 )
+ { const cfe_run *rp =
+ (ss->K > 0 ? &cf2_run_eol_1d : &cf_run_eol);
+ int i = (!ss->EndOfBlock ? 0 : ss->K < 0 ? 2 : 6);
+ uint bits_to_write =
+ hc_bits_size - bits_left + i * rp->code_length;
+ byte *q = pw->ptr;
+ if ( wlimit - q < (bits_to_write + 7) >> 3 )
+ { status = 1;
+ goto out;
+ }
+ if ( ss->EncodedByteAlign )
+ bits_left &= ~7;
+ while ( --i >= 0 )
+ hc_put_code(ss, q, rp);
+ /* Force out the last byte or bytes. */
+ pw->ptr = q = hc_put_last_bits((stream_hc_state *)ss, q);
+ goto ns;
+ }
+out: hce_store_state();
+ns: if_debug9('w', "[w]CFE exit %d: count = %d, run_color = %d,\n pr = 0x%lx(%d)0x%lx; pw = 0x%lx(%d)0x%lx\n",
+ status, ss->count, ss->run_color,
+ (ulong)pr->ptr, (int)(rlimit - pr->ptr), (ulong)rlimit,
+ (ulong)pw->ptr, (int)(wlimit - pw->ptr), (ulong)wlimit);
+#ifdef DEBUG
+ if ( pr->ptr > rlimit || pw->ptr > wlimit )
+ { lprintf("Pointer overrun!\n");
+ status = ERRC;
+ }
+ if ( gs_debug_c('w') && status == 1 )
+ { int ti;
+ for ( ti = 0; ti < 2; ti++ )
+ { int i;
+ ulong total;
+ dprintf1("[w]runs[%d]", ti);
+ for ( i = 0, total = 0; i < 41; i++ )
+ dprintf1(" %lu", runs_1d[ti].make_up[i]),
+ total += runs_1d[ti].make_up[i];
+ dprintf1(" total=%lu\n\t", total);
+ for ( i = 0, total = 0; i < 64; i++ )
+ dprintf1(" %lu", runs_1d[ti].termination[i]),
+ total += runs_1d[ti].termination[i];
+ dprintf1(" total=%lu\n", total);
+ }
+ }
+#endif
+ return status;
+}
+
+#undef ss
+
+/*
+ * For all encoding methods, we know we have a full scan line of input,
+ * but we must be prepared to suspend if we run out of space to store
+ * the output.
+ */
+
+/* Encode a 1-D scan line. */
+private int
+cf_encode_1d(stream_CFE_state *ss, const byte *lbuf,
+ stream_cursor_write *pw, uint end_count)
+{ uint count = ss->count;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int rlen;
+ int status = 0;
+ hce_declare_state;
+
+ { register const byte *p = lbuf + ss->raster - ((count + 7) >> 3);
+ byte invert = (ss->BlackIs1 ? 0 : 0xff);
+ /* Invariant: data = p[-1] ^ invert. */
+ register uint data = *p++ ^ invert;
+
+ hce_load_state();
+ while ( count != end_count )
+ { /* Parse a white run. */
+ cf_ensure_put_runs(max_run2_bytes, 0, out);
+ skip_white_pixels(data, p, count, invert, rlen);
+ cf_put_white_run(ss, rlen);
+ if ( count == end_count )
+ break;
+ /* Parse a black run. */
+ skip_black_pixels(data, p, count, invert, rlen);
+ cf_put_black_run(ss, rlen);
+ }
+ }
+
+out: hce_store_state();
+ pw->ptr = q;
+ ss->count = count;
+ return status;
+}
+
+/* Encode a 2-D scan line. */
+private int
+cf_encode_2d(stream_CFE_state *ss, const byte *lbuf,
+ stream_cursor_write *pw, uint end_count, const byte *lprev)
+{ byte invert_white = (ss->BlackIs1 ? 0 : 0xff);
+ byte invert = (ss->run_color ? ~invert_white : invert_white);
+ register uint count = ss->count;
+ const byte *p = lbuf + ss->raster - ((count + 7) >> 3);
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ register uint data = *p++ ^ invert;
+ int status = 0;
+ hce_declare_state;
+ /* In order to handle the nominal 'changing white' at the */
+ /* beginning of each scan line, we need to suppress the test for */
+ /* an initial black bit in the reference line when we are at */
+ /* the very beginning of the scan line. To avoid an extra test, */
+ /* we use two different mask tables. */
+ static const byte initial_count_bit[8] =
+ { 0, 1, 2, 4, 8, 0x10, 0x20, 0x40 };
+ static const byte further_count_bit[8] =
+ { 0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40 };
+ const byte _ds *count_bit =
+ (count == ss->raster << 3 ? initial_count_bit : further_count_bit);
+
+ hce_load_state();
+ while ( count != end_count )
+ { /* If invert == invert_white, white and black have their */
+ /* correct meanings; if invert == ~invert_white, */
+ /* black and white are interchanged. */
+ uint a0 = count;
+ uint a1;
+#define b1 (a1 - diff) /* only for printing */
+ int diff;
+ uint prev_count = count;
+ const byte *prev_p = p - lbuf + lprev;
+ byte prev_data = prev_p[-1] ^ invert;
+ int rlen;
+
+ /* Make sure we have room for a run_horizontal plus */
+ /* two data runs. */
+ cf_ensure_put_runs(max_run3_bytes, invert != invert_white, out);
+ /* Find the a1 and b1 transitions. */
+ skip_white_pixels(data, p, count, invert, rlen);
+ a1 = count;
+ if ( (prev_data & count_bit[prev_count & 7]) )
+ { /* Look for changing white first. */
+ skip_black_pixels(prev_data, prev_p, prev_count, invert, rlen);
+ }
+ count_bit = further_count_bit; /* no longer at beginning */
+pass: if ( prev_count != end_count )
+ { skip_white_pixels(prev_data, prev_p, prev_count, invert, rlen);
+ }
+ diff = a1 - prev_count; /* i.e., logical b1 - a1 */
+ /* In all the comparisons below, remember that count */
+ /* runs downward, not upward, so the comparisons are */
+ /* reversed. */
+ if ( diff <= -2 )
+ { /* Could be a pass mode. Find b2. */
+ if ( prev_count != end_count )
+ { skip_black_pixels(prev_data, prev_p,
+ prev_count, invert, rlen);
+ }
+ if ( prev_count > a1 )
+ { /* Use pass mode. */
+ if_debug4('W', "[W]pass: count = %d, a1 = %d, b1 = %d, new count = %d\n",
+ a0, a1, b1, prev_count);
+ hc_put_value(ss, q, cf2_run_pass_value,
+ cf2_run_pass_length);
+ cf_ensure_put_runs(max_run3_bytes,
+ invert != invert_white,
+ pass_out);
+ a0 = prev_count;
+ goto pass;
+pass_out: count = prev_count;
+ break;
+ }
+ }
+ /* Check for vertical coding. */
+ if ( diff <= 3 && diff >= -3 )
+ { /* Use vertical coding. */
+ const cfe_run *cp;
+ if_debug5('W', "[W]vertical %d: count = %d, a1 = %d, b1 = %d, new count = %d\n",
+ diff, a0, a1, b1, count);
+ cp = &cf2_run_vertical[diff + 3];
+ hc_put_code(ss, q, cp);
+ invert = ~invert; /* a1 polarity changes */
+ data ^= 0xff;
+ continue;
+ }
+ /* No luck, use horizontal coding. */
+ if ( count != end_count )
+ { skip_black_pixels(data, p, count, invert, rlen); /* find a2 */
+ }
+ hc_put_value(ss, q, cf2_run_horizontal_value,
+ cf2_run_horizontal_length);
+ a0 -= a1;
+ a1 -= count;
+ if ( invert == invert_white )
+ { if_debug3('W', "[W]horizontal: white = %d, black = %d, new count = %d\n",
+ a0, a1, count);
+ cf_put_white_run(ss, a0);
+ cf_put_black_run(ss, a1);
+ }
+ else
+ { if_debug3('W', "[W]horizontal: black = %d, white = %d, new count = %d\n",
+ a0, a1, count);
+ cf_put_black_run(ss, a0);
+ cf_put_white_run(ss, a1);
+#undef b1
+ }
+ }
+out: hce_store_state();
+ pw->ptr = q;
+ ss->count = count;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_CFE_template =
+{ &st_CFE_state, s_CFE_init, s_CFE_process,
+ 2, 15, /* 31 left-over bits + 7 bits of padding + 6 13-bit EOLs */
+ s_CFE_release, s_CFE_set_defaults
+};
diff --git a/gs/src/scfetab.c b/gs/src/scfetab.c
new file mode 100644
index 000000000..aadff83fb
--- /dev/null
+++ b/gs/src/scfetab.c
@@ -0,0 +1,156 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scftab.c */
+/* Tables for CCITTFaxEncode filter */
+#include "std.h"
+#include "scommon.h" /* for scf.h */
+#include "scf.h"
+
+/* We make this a separate file so that it can be used by */
+/* the program that generates the tables for the CCITTFaxDecode filter. */
+
+/* ------ Run encoding tables ------ */
+
+/* Abbreviate cfe_entry to make the file smaller. */
+#define e_(c,len) cfe_entry(c,len)
+
+/* Define the end-of-line code. */
+/* Code in scfd.c and scfdgen.c knows that the run value is 1. */
+const cfe_run cf_run_eol = e_(run_eol_code_value, run_eol_code_length);
+
+/* Define the 1-D code that signals uncompressed data. */
+const cfe_run cf1_run_uncompressed = e_(0xf, 12);
+
+/* Define the 2-D run codes. */
+const cfe_run cf2_run_pass =
+ e_(cf2_run_pass_value, cf2_run_pass_length);
+const cfe_run cf2_run_vertical[7] = {
+ e_(0x3, 7),
+ e_(0x3, 6),
+ e_(0x3, 3),
+ e_(0x1, 1),
+ e_(0x2, 3),
+ e_(0x2, 6),
+ e_(0x2, 7)
+};
+const cfe_run cf2_run_horizontal =
+ e_(cf2_run_horizontal_value, cf2_run_horizontal_length);
+const cfe_run cf2_run_uncompressed = e_(0xf, 10);
+
+/* EOL codes for Group 3 2-D. */
+/* Code in scfd.c knows that these are 0...01x. */
+const cfe_run cf2_run_eol_1d =
+ e_((run_eol_code_value << 1) + 1, run_eol_code_length + 1);
+const cfe_run cf2_run_eol_2d =
+ e_((run_eol_code_value << 1) + 0, run_eol_code_length + 1);
+
+/* White run termination codes. */
+const cfe_run far_data cf_white_termination[64] = {
+ e_(0x35, 8), e_(0x7, 6), e_(0x7, 4), e_(0x8, 4),
+ e_(0xb, 4), e_(0xc, 4), e_(0xe, 4), e_(0xf, 4),
+ e_(0x13, 5), e_(0x14, 5), e_(0x7, 5), e_(0x8, 5),
+ e_(0x8, 6), e_(0x3, 6), e_(0x34, 6), e_(0x35, 6),
+ e_(0x2a, 6), e_(0x2b, 6), e_(0x27, 7), e_(0xc, 7),
+ e_(0x8, 7), e_(0x17, 7), e_(0x3, 7), e_(0x4, 7),
+ e_(0x28, 7), e_(0x2b, 7), e_(0x13, 7), e_(0x24, 7),
+ e_(0x18, 7), e_(0x2, 8), e_(0x3, 8), e_(0x1a, 8),
+ e_(0x1b, 8), e_(0x12, 8), e_(0x13, 8), e_(0x14, 8),
+ e_(0x15, 8), e_(0x16, 8), e_(0x17, 8), e_(0x28, 8),
+ e_(0x29, 8), e_(0x2a, 8), e_(0x2b, 8), e_(0x2c, 8),
+ e_(0x2d, 8), e_(0x4, 8), e_(0x5, 8), e_(0xa, 8),
+ e_(0xb, 8), e_(0x52, 8), e_(0x53, 8), e_(0x54, 8),
+ e_(0x55, 8), e_(0x24, 8), e_(0x25, 8), e_(0x58, 8),
+ e_(0x59, 8), e_(0x5a, 8), e_(0x5b, 8), e_(0x4a, 8),
+ e_(0x4b, 8), e_(0x32, 8), e_(0x33, 8), e_(0x34, 8)
+};
+
+/* White run make-up codes. */
+const cfe_run far_data cf_white_make_up[41] = {
+ e_(0, 0) /* dummy */, e_(0x1b, 5), e_(0x12, 5), e_(0x17, 6),
+ e_(0x37, 7), e_(0x36, 8), e_(0x37, 8), e_(0x64, 8),
+ e_(0x65, 8), e_(0x68, 8), e_(0x67, 8), e_(0xcc, 9),
+ e_(0xcd, 9), e_(0xd2, 9), e_(0xd3, 9), e_(0xd4, 9),
+ e_(0xd5, 9), e_(0xd6, 9), e_(0xd7, 9), e_(0xd8, 9),
+ e_(0xd9, 9), e_(0xda, 9), e_(0xdb, 9), e_(0x98, 9),
+ e_(0x99, 9), e_(0x9a, 9), e_(0x18, 6), e_(0x9b, 9),
+ e_(0x8, 11), e_(0xc, 11), e_(0xd, 11), e_(0x12, 12),
+ e_(0x13, 12), e_(0x14, 12), e_(0x15, 12), e_(0x16, 12),
+ e_(0x17, 12), e_(0x1c, 12), e_(0x1d, 12), e_(0x1e, 12),
+ e_(0x1f, 12)
+};
+
+/* Black run termination codes. */
+const cfe_run far_data cf_black_termination[64] = {
+ e_(0x37, 10), e_(0x2, 3), e_(0x3, 2), e_(0x2, 2),
+ e_(0x3, 3), e_(0x3, 4), e_(0x2, 4), e_(0x3, 5),
+ e_(0x5, 6), e_(0x4, 6), e_(0x4, 7), e_(0x5, 7),
+ e_(0x7, 7), e_(0x4, 8), e_(0x7, 8), e_(0x18, 9),
+ e_(0x17, 10), e_(0x18, 10), e_(0x8, 10), e_(0x67, 11),
+ e_(0x68, 11), e_(0x6c, 11), e_(0x37, 11), e_(0x28, 11),
+ e_(0x17, 11), e_(0x18, 11), e_(0xca, 12), e_(0xcb, 12),
+ e_(0xcc, 12), e_(0xcd, 12), e_(0x68, 12), e_(0x69, 12),
+ e_(0x6a, 12), e_(0x6b, 12), e_(0xd2, 12), e_(0xd3, 12),
+ e_(0xd4, 12), e_(0xd5, 12), e_(0xd6, 12), e_(0xd7, 12),
+ e_(0x6c, 12), e_(0x6d, 12), e_(0xda, 12), e_(0xdb, 12),
+ e_(0x54, 12), e_(0x55, 12), e_(0x56, 12), e_(0x57, 12),
+ e_(0x64, 12), e_(0x65, 12), e_(0x52, 12), e_(0x53, 12),
+ e_(0x24, 12), e_(0x37, 12), e_(0x38, 12), e_(0x27, 12),
+ e_(0x28, 12), e_(0x58, 12), e_(0x59, 12), e_(0x2b, 12),
+ e_(0x2c, 12), e_(0x5a, 12), e_(0x66, 12), e_(0x67, 12)
+};
+
+/* Black run make-up codes. */
+const cfe_run far_data cf_black_make_up[41] = {
+ e_(0, 0) /* dummy */, e_(0xf, 10), e_(0xc8, 12), e_(0xc9, 12),
+ e_(0x5b, 12), e_(0x33, 12), e_(0x34, 12), e_(0x35, 12),
+ e_(0x6c, 13), e_(0x6d, 13), e_(0x4a, 13), e_(0x4b, 13),
+ e_(0x4c, 13), e_(0x4d, 13), e_(0x72, 13), e_(0x73, 13),
+ e_(0x74, 13), e_(0x75, 13), e_(0x76, 13), e_(0x77, 13),
+ e_(0x52, 13), e_(0x53, 13), e_(0x54, 13), e_(0x55, 13),
+ e_(0x5a, 13), e_(0x5b, 13), e_(0x64, 13), e_(0x65, 13),
+ e_(0x8, 11), e_(0xc, 11), e_(0xd, 11), e_(0x12, 12),
+ e_(0x13, 12), e_(0x14, 12), e_(0x15, 12), e_(0x16, 12),
+ e_(0x17, 12), e_(0x1c, 12), e_(0x1d, 12), e_(0x1e, 12),
+ e_(0x1f, 12)
+};
+
+/* Uncompressed codes. */
+const cfe_run cf_uncompressed[6] = {
+ e_(1, 1),
+ e_(1, 2),
+ e_(1, 3),
+ e_(1, 4),
+ e_(1, 5),
+ e_(1, 6)
+};
+
+/* Uncompressed exit codes. */
+const cfe_run cf_uncompressed_exit[10] = {
+ e_(2, 8), e_(3, 8),
+ e_(2, 9), e_(3, 9),
+ e_(2, 10), e_(3, 10),
+ e_(2, 11), e_(3, 11),
+ e_(2, 12), e_(3, 12)
+};
+
+/* Some C compilers insist on having executable code in every file.... */
+void
+cfe_dummy(void)
+{
+}
diff --git a/gs/src/scfx.h b/gs/src/scfx.h
new file mode 100644
index 000000000..c707a089b
--- /dev/null
+++ b/gs/src/scfx.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scfx.h */
+/* CCITTFax filter state definition */
+/* Requires strimpl.h */
+#include "shc.h"
+
+/* Common state */
+#define stream_CF_state_common\
+ stream_hc_state_common;\
+ /* The client sets the following before initialization. */\
+ bool Uncompressed;\
+ int K;\
+ bool EndOfLine;\
+ bool EncodedByteAlign;\
+ int Columns;\
+ int Rows;\
+ bool EndOfBlock;\
+ bool BlackIs1;\
+ int DamagedRowsBeforeError; /* (Decode only) */\
+ /*bool FirstBitLowOrder;*/ /* in stream_hc_state_common */\
+ int DecodedByteAlign;\
+ /* The init procedure sets the following. */\
+ uint raster;\
+ byte *lbuf; /* current scan line buffer */\
+ /* (only if decoding or 2-D encoding) */\
+ byte *lprev; /* previous scan line buffer (only if 2-D) */\
+ /* The following are updated dynamically. */\
+ int k_left; /* number of next rows to encode in 2-D */\
+ /* (only if K > 0) */\
+ int run_color; /* -1 if processing white run, */\
+ /* 0 if between runs but white is next, */\
+ /* 1 if between runs and black is next, */\
+ /* 2 if processing black run */\
+ int damaged_rows; /* # of consecutive damaged rows preceding */\
+ /* the current row */\
+ bool skipping_damage /* true if skipping a damaged row looking */\
+ /* for EOL */
+typedef struct stream_CF_state_s {
+ stream_CF_state_common;
+} stream_CF_state;
+/* Define common default parameter setting. */
+#define s_CF_set_defaults_inline(ss)\
+ ((ss)->Uncompressed = false,\
+ (ss)->K = 0,\
+ (ss)->EndOfLine = false,\
+ (ss)->EncodedByteAlign = false,\
+ (ss)->Columns = 1728,\
+ (ss)->Rows = 0,\
+ (ss)->EndOfBlock = true,\
+ (ss)->BlackIs1 = false,\
+ /* Added by Adobe since the Red Book */\
+ (ss)->DamagedRowsBeforeError = 0,\
+ (ss)->FirstBitLowOrder = false,\
+ /* Added by us */\
+ (ss)->DecodedByteAlign = 1)
+
+/* CCITTFaxEncode */
+typedef struct stream_CFE_state_s {
+ stream_CF_state_common;
+ /* The init procedure sets the following. */
+ int max_line_bytes; /* max # of bytes for a 1-run line */
+ int max_run2_bytes; /* max # of bytes for 2 runs */
+ int max_run3_bytes; /* max # of bytes for 3 runs */
+ /* The following change dynamically. */
+ int count; /* # of source bits left to scan, */
+ /* padded to a byte boundary */
+ int run_count; /* count at start of run begin scanned */
+ int copy_count; /* # of bytes to copy into lbuf */
+ bool new_line; /* false if processing a line, */
+ /* true if need to start new line */
+} stream_CFE_state;
+#define private_st_CFE_state() /* in scfe.c */\
+ gs_private_st_ptrs2(st_CFE_state, stream_CFE_state, "CCITTFaxEncode state",\
+ cfe_enum_ptrs, cfe_reloc_ptrs, lbuf, lprev)
+#define s_CFE_set_defaults_inline(ss)\
+ s_CF_set_defaults_inline(ss)
+extern const stream_template s_CFE_template;
+
+/* CCITTFaxDecode */
+typedef struct stream_CFD_state_s {
+ stream_CF_state_common;
+ int cbit; /* bits left to fill in current decoded */
+ /* byte at lbuf[wpos] (0..7) */
+ int rows_left; /* number of rows left */
+ int rpos; /* rptr for copying lbuf to client */
+ int wpos; /* rlimit/wptr for filling lbuf or */
+ /* copying to client */
+ int eol_count; /* number of EOLs seen so far */
+ byte invert; /* current value of 'white' */
+ /* for 2-D decoding */
+ /* The following are not used yet. */
+ int uncomp_run; /* non-0 iff we are in an uncompressed */
+ /* run straddling a scan line (-1 if white, */
+ /* 1 if black) */
+ int uncomp_left; /* # of bits left in the run */
+ int uncomp_exit; /* non-0 iff this is an exit run */
+ /* (-1 if next run white, 1 if black) */
+} stream_CFD_state;
+#define private_st_CFD_state() /* in scfd.c */\
+ gs_private_st_ptrs2(st_CFD_state, stream_CFD_state, "CCITTFaxDecode state",\
+ cfd_enum_ptrs, cfd_reloc_ptrs, lbuf, lprev)
+#define s_CFD_set_defaults_inline(ss)\
+ (s_CF_set_defaults_inline(ss),\
+ (ss)->DamagedRowsBeforeError = 0)
+extern const stream_template s_CFD_template;
diff --git a/gs/src/scommon.h b/gs/src/scommon.h
new file mode 100644
index 000000000..4405e0d63
--- /dev/null
+++ b/gs/src/scommon.h
@@ -0,0 +1,152 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* scommon.h */
+/* Definitions common to stream clients and implementors */
+
+#ifndef scommon_DEFINED
+# define scommon_DEFINED
+
+#include "gsmemory.h"
+#include "gstypes.h" /* for gs_string */
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * There are three major structures involved in the stream package.
+ *
+ * A stream is an "object" that owns a buffer, which it uses to implement
+ * byte-oriented sequential access in a standard way, and a set of
+ * procedures that handle things like buffer refilling. See stream.h
+ * for more information about streams.
+ */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+#endif
+/*
+ * A stream_state records the state specific to a given variety of stream.
+ * The buffer processing function of a stream maintains this state.
+ */
+typedef struct stream_state_s stream_state;
+/*
+ * A stream_template provides the information needed to create a stream.
+ * The client must fill in any needed setup parameters in the appropriate
+ * variety of stream_state, and then call the initialization function
+ * provided by the template. See strimpl.h for more information about
+ * stream_templates.
+ */
+typedef struct stream_template_s stream_template;
+
+/*
+ * The stream package works with bytes, not chars.
+ * This is to ensure unsigned representation on all systems.
+ * A stream currently can only be read or written, not both.
+ * Note also that the read procedure returns an int, not a char or a byte;
+ * we use negative values to indicate exceptional conditions.
+ * (We cast these values to int explicitly, because some compilers
+ * don't do this if the other arm of a conditional is a byte.)
+ */
+/* End of data */
+#define EOFC ((int)(-1))
+/* Error */
+#define ERRC ((int)(-2))
+/* Interrupt */
+#define INTC ((int)(-3))
+/****** INTC IS NOT USED YET ******/
+/* Callout */
+#define CALLC ((int)(-4))
+#define max_stream_exception 4
+/* The following hack is needed for initializing scan_char_array in iscan.c. */
+#define stream_exception_repeat(x) x, x, x, x
+
+/*
+ * Define cursors for reading from or writing into a buffer.
+ * We lay them out this way so that we can alias
+ * the write pointer and the read limit.
+ */
+typedef struct stream_cursor_read_s {
+ const byte *ptr;
+ const byte *limit;
+ byte *_skip;
+} stream_cursor_read;
+typedef struct stream_cursor_write_s {
+ const byte *_skip;
+ byte *ptr;
+ byte *limit;
+} stream_cursor_write;
+typedef union stream_cursor_s {
+ stream_cursor_read r;
+ stream_cursor_write w;
+} stream_cursor;
+
+/*
+ * Define the prototype for the procedures known to both the generic
+ * stream code and the stream implementations.
+ */
+
+/* Initialize the stream state (after the client parameters are set). */
+#define stream_proc_init(proc)\
+ int proc(P1(stream_state *))
+
+/* Process a buffer. See strimpl.h for details. */
+#define stream_proc_process(proc)\
+ int proc(P4(stream_state *, stream_cursor_read *,\
+ stream_cursor_write *, bool))
+
+/* Release the stream state when closing. */
+#define stream_proc_release(proc)\
+ void proc(P1(stream_state *))
+
+/* Initialize the client parameters to default values. */
+#define stream_proc_set_defaults(proc)\
+ void proc(P1(stream_state *))
+
+/* Reinitialize any internal stream state. Note that this does not */
+/* affect buffered data. We declare this as returning an int so that */
+/* it can be the same as the init procedure; however, reinit cannot fail. */
+#define stream_proc_reinit(proc)\
+ int proc(P1(stream_state *))
+
+/* Report an error. Note that this procedure is stored in the state, */
+/* not in the main stream structure. */
+#define stream_proc_report_error(proc)\
+ int proc(P2(stream_state *, const char *))
+stream_proc_report_error(s_no_report_error);
+
+/*
+ * Define a generic stream state. If a processing procedure has no
+ * state of its own, it can use stream_state; otherwise, it must
+ * create a "subclass". There is a hack in stream.h to allow the stream
+ * itself to serve as the "state" of a couple of heavily used stream types.
+ *
+ * In order to simplify the structure descriptors for concrete streams,
+ * we require that the generic stream state not contain any pointers
+ * to garbage-collectable storage.
+ */
+#define stream_state_common\
+ const stream_template *template;\
+ gs_memory_t *memory;\
+ stream_proc_report_error((*report_error))
+struct stream_state_s {
+ stream_state_common;
+};
+extern_st(st_stream_state);
+#define public_st_stream_state() /* in stream.c */\
+ gs_public_st_simple(st_stream_state, stream_state, "stream_state")
+
+#endif /* scommon_INCLUDED */
diff --git a/gs/src/sdct.h b/gs/src/sdct.h
new file mode 100644
index 000000000..0e113606c
--- /dev/null
+++ b/gs/src/sdct.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sdct.h */
+/* Definitions for DCT filters for Ghostscript streams */
+/* Requires stream.h, strimpl.h, jpeg/jpeglib.h */
+#include <setjmp.h> /* for jmp_buf */
+
+/* ------ DCT filters ------ */
+
+/*
+ * Define the stream state.
+ * The jpeg_xxx_data structs are allocated in immovable memory
+ * to simplify use of the IJG library.
+ */
+#define jpeg_stream_data_common\
+ /* We put a copy of the stream template here, because */\
+ /* the minimum buffer sizes depend on the image parameters. */\
+ stream_template template;\
+ struct jpeg_error_mgr err;\
+ jmp_buf exit_jmpbuf;\
+ /* The following are documented in Adobe TN 5116. */\
+ int Picky; /* 0 or 1 */\
+ int Relax /* 0 or 1 */
+typedef struct jpeg_stream_data_s {
+ jpeg_stream_data_common;
+} jpeg_stream_data;
+typedef struct jpeg_compress_data_s {
+ jpeg_stream_data_common;
+ /* cinfo must immediately follow the common fields */
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_destination_mgr destination;
+} jpeg_compress_data;
+typedef struct jpeg_decompress_data_s {
+ jpeg_stream_data_common;
+ /* dinfo must immediately follow the common fields, */
+ /* so that it has same offset as cinfo. */
+ struct jpeg_decompress_struct dinfo;
+ struct jpeg_source_mgr source;
+ long skip; /* # of bytes remaining to skip in input */
+ bool input_eod; /* true when no more input data available */
+ bool faked_eoi; /* true when fill_input_buffer inserted EOI */
+ byte * scanline_buffer; /* buffer for oversize scanline, or NULL */
+ uint bytes_in_scanline; /* # of bytes remaining to output from same */
+} jpeg_decompress_data;
+
+/* The stream state itself. This is kept in garbage-collectable memory. */
+typedef struct stream_DCT_state_s {
+ stream_state_common;
+ /* The following are set before initialization. */
+ /* Note that most JPEG parameters go straight into */
+ /* the IJG data structures, not into this struct. */
+ gs_const_string Markers; /* NULL if no Markers parameter */
+ float QFactor;
+ int ColorTransform; /* -1 if not specified */
+ bool NoMarker; /* DCTEncode only */
+ /* This is a pointer to immovable storage. */
+ union _jd {
+ jpeg_stream_data *common;
+ jpeg_compress_data *compress;
+ jpeg_decompress_data *decompress;
+ } data;
+ /* DCTEncode sets this before initialization;
+ * DCTDecode cannot set it until the JPEG headers are read.
+ */
+ uint scan_line_size;
+ /* The following are updated dynamically. */
+ int phase;
+} stream_DCT_state;
+/* The state descriptor is public only to allow us to split up */
+/* the encoding and decoding filters. */
+extern_st(st_DCT_state);
+#define public_st_DCT_state() /* in sdctc.c */\
+ gs_public_st_composite(st_DCT_state, stream_DCT_state,\
+ "DCTEncode/Decode state", dct_enum_ptrs, dct_reloc_ptrs)
+extern const stream_template s_DCTD_template;
+extern const stream_template s_DCTE_template;
diff --git a/gs/src/sdctc.c b/gs/src/sdctc.c
new file mode 100644
index 000000000..d415cb8f0
--- /dev/null
+++ b/gs/src/sdctc.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sdctc.c */
+/* Code common to DCT encoding and decoding streams */
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "strimpl.h"
+#include "sdct.h"
+
+public_st_DCT_state();
+/* GC procedures */
+private ENUM_PTRS_BEGIN(dct_enum_ptrs) return 0;
+ ENUM_CONST_STRING_PTR(0, stream_DCT_state, Markers);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dct_reloc_ptrs) {
+ RELOC_CONST_STRING_PTR(stream_DCT_state, Markers);
+} RELOC_PTRS_END
diff --git a/gs/src/sdctd.c b/gs/src/sdctd.c
new file mode 100644
index 000000000..e1de99389
--- /dev/null
+++ b/gs/src/sdctd.c
@@ -0,0 +1,274 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sdctd.c */
+/* DCT decoding filter stream */
+#include "memory_.h"
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+#define ss ((stream_DCT_state *)st)
+
+/* ------ DCTDecode ------ */
+
+/* JPEG source manager procedures */
+private void
+dctd_init_source(j_decompress_ptr dinfo)
+{
+}
+static const JOCTET fake_eoi[2] = { 0xFF , JPEG_EOI };
+private boolean
+dctd_fill_input_buffer(j_decompress_ptr dinfo)
+{ jpeg_decompress_data *jddp =
+ (jpeg_decompress_data *)((char *)dinfo -
+ offset_of(jpeg_decompress_data, dinfo));
+ if (! jddp->input_eod)
+ return FALSE; /* normal case: suspend processing */
+ /* Reached end of source data without finding EOI */
+ WARNMS(dinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ dinfo->src->next_input_byte = fake_eoi;
+ dinfo->src->bytes_in_buffer = 2;
+ jddp->faked_eoi = true; /* so process routine doesn't use next_input_byte */
+ return TRUE;
+}
+private void
+dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes)
+{ struct jpeg_source_mgr *src = dinfo->src;
+ jpeg_decompress_data *jddp =
+ (jpeg_decompress_data *)((char *)dinfo -
+ offset_of(jpeg_decompress_data, dinfo));
+ if ( num_bytes > 0 )
+ { if ( num_bytes > src->bytes_in_buffer )
+ { jddp->skip += num_bytes - src->bytes_in_buffer;
+ src->next_input_byte += src->bytes_in_buffer;
+ src->bytes_in_buffer = 0;
+ return;
+ }
+ src->next_input_byte += num_bytes;
+ src->bytes_in_buffer -= num_bytes;
+ }
+}
+private void
+dctd_term_source(j_decompress_ptr dinfo)
+{
+}
+
+/* Initialize DCTDecode filter */
+private int
+s_DCTD_init(stream_state *st)
+{ struct jpeg_source_mgr *src = &ss->data.decompress->source;
+ src->init_source = dctd_init_source;
+ src->fill_input_buffer = dctd_fill_input_buffer;
+ src->skip_input_data = dctd_skip_input_data;
+ src->term_source = dctd_term_source;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ ss->data.decompress->dinfo.src = src;
+ ss->data.decompress->skip = 0;
+ ss->data.decompress->input_eod = false;
+ ss->data.decompress->faked_eoi = false;
+ ss->phase = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_DCTD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ jpeg_decompress_data *jddp = ss->data.decompress;
+ struct jpeg_source_mgr *src = jddp->dinfo.src;
+ int code;
+
+ if_debug3('w', "[wdd]process avail=%u, skip=%u, last=%d\n",
+ (uint)(pr->limit - pr->ptr), (uint)jddp->skip, last);
+ if ( jddp->skip != 0 )
+ { long avail = pr->limit - pr->ptr;
+ if ( avail < jddp->skip )
+ { jddp->skip -= avail;
+ pr->ptr = pr->limit;
+ if (!last)
+ return 0; /* need more data */
+ jddp->skip = 0; /* don't skip past input EOD */
+ }
+ pr->ptr += jddp->skip;
+ jddp->skip = 0;
+ }
+ src->next_input_byte = pr->ptr + 1;
+ src->bytes_in_buffer = pr->limit - pr->ptr;
+ jddp->input_eod = last;
+ switch ( ss->phase )
+ {
+ case 0: /* not initialized yet */
+ /*
+ * Adobe implementations seem to ignore leading garbage bytes,
+ * even though neither the standard nor Adobe's own
+ * documentation mention this.
+ */
+ while ( pr->ptr < pr->limit && pr->ptr[1] != 0xff )
+ pr->ptr++;
+ if ( pr->ptr == pr->limit )
+ return 0;
+ src->next_input_byte = pr->ptr + 1;
+ src->bytes_in_buffer = pr->limit - pr->ptr;
+ ss->phase = 1;
+ /* falls through */
+ case 1: /* reading header markers */
+ if ( (code = gs_jpeg_read_header(ss, TRUE)) < 0 )
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ switch ( code )
+ {
+ case JPEG_SUSPENDED:
+ return 0;
+ /*case JPEG_HEADER_OK: */
+ }
+ /* If we have a ColorTransform parameter, and it's not
+ * overridden by an Adobe marker in the data, set colorspace.
+ */
+ if ( ss->ColorTransform >= 0 &&
+ ! jddp->dinfo.saw_Adobe_marker )
+ { switch ( jddp->dinfo.num_components )
+ {
+ case 3:
+ jddp->dinfo.jpeg_color_space =
+ (ss->ColorTransform ? JCS_YCbCr : JCS_RGB);
+ /* out_color_space will default to JCS_RGB */
+ break;
+ case 4:
+ jddp->dinfo.jpeg_color_space =
+ (ss->ColorTransform ? JCS_YCCK : JCS_CMYK);
+ /* out_color_space will default to JCS_CMYK */
+ break;
+ }
+ }
+ ss->phase = 2;
+ /* falls through */
+ case 2: /* start_decompress */
+ if ( (code = gs_jpeg_start_decompress(ss)) < 0 )
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if ( code == 0 )
+ return 0;
+ ss->scan_line_size =
+ jddp->dinfo.output_width * jddp->dinfo.output_components;
+ if_debug4('w', "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n",
+ jddp->dinfo.output_width,
+ jddp->dinfo.output_components,
+ ss->scan_line_size, jddp->template.min_out_size);
+ if ( ss->scan_line_size > (uint) jddp->template.min_out_size )
+ {
+ /* Create a spare buffer for oversize scanline */
+ jddp->scanline_buffer = (byte *)
+ gs_malloc(ss->scan_line_size, sizeof(byte),
+ "s_DCTD_process(scanline_buffer)");
+ if ( jddp->scanline_buffer == NULL )
+ return ERRC;
+ }
+ jddp->bytes_in_scanline = 0;
+ ss->phase = 3;
+ /* falls through */
+ case 3: /* reading data */
+dumpbuffer:
+ if ( jddp->bytes_in_scanline != 0 )
+ { uint avail = pw->limit - pw->ptr;
+ uint tomove = min(jddp->bytes_in_scanline,
+ avail);
+ if_debug2('w', "[wdd]moving %u/%u\n",
+ tomove, avail);
+ memcpy(pw->ptr + 1, jddp->scanline_buffer +
+ (ss->scan_line_size - jddp->bytes_in_scanline),
+ tomove);
+ pw->ptr += tomove;
+ jddp->bytes_in_scanline -= tomove;
+ if ( jddp->bytes_in_scanline != 0 )
+ return 1; /* need more room */
+ }
+ while ( jddp->dinfo.output_height > jddp->dinfo.output_scanline )
+ { int read;
+ byte *samples;
+ if ( jddp->scanline_buffer != NULL )
+ samples = jddp->scanline_buffer;
+ else
+ { if ( (uint)(pw->limit - pw->ptr) < ss->scan_line_size )
+ return 1; /* need more room */
+ samples = pw->ptr + 1;
+ }
+ read = gs_jpeg_read_scanlines(ss, &samples, 1);
+ if ( read < 0 )
+ return ERRC;
+ if_debug3('w', "[wdd]read returns %d, used=%u, faked_eoi=%d\n",
+ read,
+ (uint)(src->next_input_byte - 1 - pr->ptr),
+ (int)jddp->faked_eoi);
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if ( !read )
+ return 0; /* need more data */
+ if ( jddp->scanline_buffer != NULL )
+ { jddp->bytes_in_scanline = ss->scan_line_size;
+ goto dumpbuffer;
+ }
+ pw->ptr += ss->scan_line_size;
+ }
+ ss->phase = 4;
+ /* falls through */
+ case 4: /* end of image; scan for EOI */
+ if ( (code = gs_jpeg_finish_decompress(ss)) < 0 )
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if ( code == 0 )
+ return 0;
+ ss->phase = 5;
+ /* falls through */
+ case 5: /* we are DONE */
+ return EOFC;
+ }
+ /* Default case can't happen.... */
+ return ERRC;
+}
+
+/* Release the stream */
+private void
+s_DCTD_release(stream_state *st)
+{ gs_jpeg_destroy(ss);
+ if ( ss->data.decompress->scanline_buffer != NULL )
+ {
+ gs_free(ss->data.decompress->scanline_buffer,
+ ss->scan_line_size, sizeof(byte),
+ "s_DCTD_release(scanline_buffer)");
+ }
+ gs_free(ss->data.decompress, 1, sizeof(jpeg_decompress_data),
+ "s_DCTD_release");
+ /* Switch the template pointer back in case we still need it. */
+ st->template = &s_DCTD_template;
+}
+
+/* Stream template */
+const stream_template s_DCTD_template =
+{ &st_DCT_state, s_DCTD_init, s_DCTD_process, 2000, 4000, s_DCTD_release
+};
+
+#undef ss
diff --git a/gs/src/sdcte.c b/gs/src/sdcte.c
new file mode 100644
index 000000000..8aae4b5e2
--- /dev/null
+++ b/gs/src/sdcte.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sdcte.c */
+/* DCT encoding filter stream */
+#include "memory_.h"
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+#define ss ((stream_DCT_state *)st)
+
+/* ------ DCTEncode ------ */
+
+/* JPEG destination manager procedures */
+private void
+dcte_init_destination(j_compress_ptr cinfo)
+{
+}
+private boolean
+dcte_empty_output_buffer(j_compress_ptr cinfo)
+{ return FALSE;
+}
+private void
+dcte_term_destination(j_compress_ptr cinfo)
+{
+}
+
+/* Initialize DCTEncode filter */
+private int
+s_DCTE_init(stream_state *st)
+{ struct jpeg_destination_mgr *dest = &ss->data.compress->destination;
+ dest->init_destination = dcte_init_destination;
+ dest->empty_output_buffer = dcte_empty_output_buffer;
+ dest->term_destination = dcte_term_destination;
+ ss->data.compress->cinfo.dest = dest;
+ ss->phase = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_DCTE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ jpeg_compress_data *jcdp = ss->data.compress;
+ struct jpeg_destination_mgr *dest = jcdp->cinfo.dest;
+ dest->next_output_byte = pw->ptr + 1;
+ dest->free_in_buffer = pw->limit - pw->ptr;
+ switch ( ss->phase )
+ {
+ case 0: /* not initialized yet */
+ if ( gs_jpeg_start_compress(ss, TRUE) < 0 )
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ ss->phase = 1;
+ /* falls through */
+ case 1: /* initialized, Markers not written */
+ if ( pw->limit - pw->ptr < ss->Markers.size )
+ return 1;
+ memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size);
+ pw->ptr += ss->Markers.size;
+ ss->phase = 2;
+ /* falls through */
+ case 2: /* still need to write Adobe marker */
+ if ( ! ss->NoMarker )
+ { static const byte Adobe[] = {
+ 0xFF, JPEG_APP0+14, 0, 14, /* parameter length */
+ 'A', 'd', 'o', 'b', 'e',
+ 0, 100, /* Version */
+ 0, 0, /* Flags0 */
+ 0, 0, /* Flags1 */
+ 0 /* ColorTransform */
+ };
+#define ADOBE_MARKER_LEN sizeof(Adobe)
+ if ( pw->limit - pw->ptr < ADOBE_MARKER_LEN )
+ return 1;
+ memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN);
+ pw->ptr += ADOBE_MARKER_LEN;
+ *pw->ptr = ss->ColorTransform;
+#undef ADOBE_MARKER_LEN
+ }
+ dest->next_output_byte = pw->ptr + 1;
+ dest->free_in_buffer = pw->limit - pw->ptr;
+ ss->phase = 3;
+ /* falls through */
+ case 3: /* markers written, processing data */
+ while ( jcdp->cinfo.image_height > jcdp->cinfo.next_scanline )
+ { int written;
+ /*
+ * The data argument for jpeg_write_scanlines is
+ * declared as a JSAMPARRAY. There is no corresponding
+ * const type, so we must remove const from the
+ * argument that we are passing here. (Tom Lane of IJG
+ * judges that providing const analogues of the
+ * interface types wouldn't be worth the trouble.)
+ */
+ /*const*/ byte *samples = (byte *)(pr->ptr + 1);
+ if ( (uint)(pr->limit - pr->ptr) < ss->scan_line_size )
+ { if ( last )
+ return ERRC; /* premature EOD */
+ return 0; /* need more data */
+ }
+ written = gs_jpeg_write_scanlines(ss, &samples, 1);
+ if ( written < 0 )
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ if ( !written )
+ return 1; /* output full */
+ pr->ptr += ss->scan_line_size;
+ }
+ ss->phase = 4;
+ /* falls through */
+ case 4: /* all data processed, finishing */
+ /* jpeg_finish_compress can't suspend, so make sure
+ * it has plenty of room to write the last few bytes.
+ */
+ if ( pw->limit - pw->ptr < 100 )
+ return 1;
+ if ( gs_jpeg_finish_compress(ss) < 0 )
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ ss->phase = 5;
+ /* falls through */
+ case 5: /* we are DONE */
+ return EOFC;
+ }
+ /* Default case can't happen.... */
+ return ERRC;
+}
+
+/* Release the stream */
+private void
+s_DCTE_release(stream_state *st)
+{ gs_jpeg_destroy(ss);
+ gs_free(ss->data.compress, 1, sizeof(jpeg_compress_data),
+ "s_DCTE_release");
+ /* Switch the template pointer back in case we still need it. */
+ st->template = &s_DCTE_template;
+}
+
+/* Stream template */
+const stream_template s_DCTE_template =
+{ &st_DCT_state, s_DCTE_init, s_DCTE_process, 1000, 4000, s_DCTE_release
+};
+
+#undef ss
diff --git a/gs/src/seexec.c b/gs/src/seexec.c
new file mode 100644
index 000000000..176206868
--- /dev/null
+++ b/gs/src/seexec.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* seexec.c */
+/* eexec filters */
+#include "stdio_.h" /* includes std.h */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "gscrypt1.h"
+#include "scanchar.h"
+
+/* ------ eexecEncode ------ */
+
+/* Encoding is much simpler than decoding, because we don't */
+/* worry about initial characters or hex vs. binary (the client */
+/* has to take care of these aspects). */
+
+private_st_exE_state();
+
+#define ss ((stream_exE_state *)st)
+
+/* Process a buffer */
+private int
+s_exE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ uint rcount = pr->limit - p;
+ uint wcount = pw->limit - q;
+ uint count;
+ int status;
+ if ( rcount <= wcount )
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+ gs_type1_encrypt(q + 1, p + 1, count, (crypt_state *)&ss->cstate);
+ pr->ptr += count;
+ pw->ptr += count;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_exE_template =
+{ &st_exE_state, NULL, s_exE_process, 1, 2
+};
+
+/* ------ eexecDecode ------ */
+
+private_st_exD_state();
+
+#define ss ((stream_exD_state *)st)
+
+/* Set defaults. */
+private void
+s_exD_set_defaults(stream_state *st)
+{ ss->lenIV = 4;
+}
+
+/* Initialize the state for reading and decrypting. */
+/* Decrypting streams are not positionable. */
+private int
+s_exD_init(stream_state *st)
+{ ss->odd = -1;
+ ss->binary = -1; /* unknown */
+ ss->record_left = max_long;
+ ss->skip = ss->lenIV;
+ return 0;
+}
+
+/* Process a buffer. */
+private int
+s_exD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int skip = ss->skip;
+ int rcount = pr->limit - p;
+ int wcount = pw->limit - q;
+ int status = 0;
+ int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+
+ if ( ss->binary < 0 )
+ { /* This is the very first time we're filling the buffer. */
+ /* Determine whether this is ASCII or hex encoding. */
+ register const byte _ds *decoder = scan_char_decoder;
+ int i;
+
+ if ( rcount < 8 )
+ return 0;
+ /* Adobe's documentation doesn't actually specify the test */
+ /* that eexec should use, but we believe the following */
+ /* gives correct answers even on certain non-conforming */
+ /* PostScript files encountered in practice: */
+ ss->binary = 0;
+ for ( i = 1; i <= 8; i++ )
+ if ( !(decoder[p[i]] <= 0xf ||
+ decoder[p[i]] == ctype_space)
+ )
+ { ss->binary = 1;
+ if ( ss->pfb_state != 0 )
+ { /* Stop at the end of the .PFB binary data. */
+ ss->record_left = ss->pfb_state->record_left;
+ }
+ break;
+ }
+ }
+ if ( ss->binary )
+ { if ( count > ss->record_left )
+ { count = ss->record_left;
+ status = 0;
+ }
+ /* We pause at the end of the .PFB binary data, */
+ /* in an attempt to keep from reading beyond the end of */
+ /* the encrypted data. */
+ if ( (ss->record_left -= count) == 0 )
+ ss->record_left = max_long;
+ pr->ptr = p + count;
+ }
+ else
+ { /* We only ignore leading whitespace, in an attempt to */
+ /* keep from reading beyond the end of the encrypted data. */
+ status = s_hex_process(pr, pw, &ss->odd,
+ hex_ignore_leading_whitespace);
+ p = q;
+ count = pw->ptr - q;
+ }
+ if ( skip >= count && skip != 0 )
+ { gs_type1_decrypt(q + 1, p + 1, count,
+ (crypt_state *)&ss->cstate);
+ ss->skip -= count;
+ count = 0;
+ status = 0;
+ }
+ else
+ { gs_type1_decrypt(q + 1, p + 1, skip,
+ (crypt_state *)&ss->cstate);
+ count -= skip;
+ gs_type1_decrypt(q + 1, p + 1 + skip, count,
+ (crypt_state *)&ss->cstate);
+ ss->skip = 0;
+ }
+ pw->ptr = q + count;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+/*
+ * The specification of eexec decoding requires that it never read more than
+ * 512 source bytes ahead. The only reliable way to ensure this is to
+ * limit the size of the output buffer to 256. We set it a little smaller
+ * so that it will stay under the limit even after adding min_in_size
+ * for a subsequent filter in a pipeline. Note that we have to specify
+ * a size of at least 128 so that filter_read won't round it up.
+ */
+const stream_template s_exD_template =
+{ &st_exD_state, s_exD_init, s_exD_process, 8, 200,
+ NULL, s_exD_set_defaults
+};
diff --git a/gs/src/sfilter.h b/gs/src/sfilter.h
new file mode 100644
index 000000000..8e69046b4
--- /dev/null
+++ b/gs/src/sfilter.h
@@ -0,0 +1,125 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfilter.h */
+/* Definitions for simple Ghostscript streams */
+/* Requires scommon.h; should require strimpl.h only if any templates */
+/* are referenced, but some compilers always require strimpl.h. */
+
+#include "gstypes.h" /* for gs_[const_]string */
+
+/*
+ * Define the processing states of the simplest Ghostscript streams.
+ * We use abbreviations for the stream names so as not to exceed the
+ * 31-character limit that some compilers put on identifiers.
+ *
+ * The processing state of a stream has three logical sections:
+ * parameters set by the client before the stream is opened,
+ * values computed from the parameters at initialization time,
+ * and values that change dynamically. Unless otherwise indicated,
+ * all structure members change dynamically.
+ */
+
+/* (T)BCPEncode */
+/* (no state) */
+extern const stream_template s_BCPE_template;
+extern const stream_template s_TBCPE_template;
+
+/* (T)BCPDecode */
+typedef struct stream_BCPD_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int (*signal_interrupt)(P1(stream_state *));
+ int (*request_status)(P1(stream_state *));
+ /* The following are updated dynamically. */
+ bool escaped;
+ int matched; /* TBCP only */
+ int copy_count; /* TBCP only */
+ const byte _ds *copy_ptr; /* TBCP only */
+} stream_BCPD_state;
+#define private_st_BCPD_state() /* in sbcp.c */\
+ gs_private_st_simple(st_BCPD_state, stream_BCPD_state, "(T)BCPDecode state")
+extern const stream_template s_BCPD_template;
+extern const stream_template s_TBCPD_template;
+
+/* eexecEncode */
+typedef struct stream_exE_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ ushort cstate; /* encryption state */
+} stream_exE_state;
+#define private_st_exE_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_exE_state, stream_exE_state, "eexecEncode state")
+extern const stream_template s_exE_template;
+
+/* eexecDecode */
+typedef struct stream_PFBD_state_s stream_PFBD_state;
+typedef struct stream_exD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ ushort cstate; /* encryption state */
+ stream_PFBD_state *pfb_state; /* state of underlying */
+ /* PFBDecode stream, if any */
+ int binary; /* 1=binary, 0=hex, -1=don't know yet */
+ int lenIV; /* # of initial decoded bytes to skip */
+ /* The following change dynamically. */
+ int odd; /* odd digit */
+ long record_left; /* data left in binary record in .PFB file, */
+ /* max_long if not reading a .PFB file */
+ int skip; /* # of decoded bytes to skip */
+} stream_exD_state;
+#define private_st_exD_state() /* in seexec.c */\
+ gs_private_st_ptrs1(st_exD_state, stream_exD_state, "eexecDecode state",\
+ exd_enum_ptrs, exd_reloc_ptrs, pfb_state)
+extern const stream_template s_exD_template;
+
+/* NullEncode/Decode */
+/* (no state) */
+extern const stream_template s_Null_template;
+#define s_NullE_template s_Null_template
+#define s_NullD_template s_Null_template
+
+/* PFBDecode */
+/* The typedef for the state appears under eexecDecode above. */
+/*typedef*/ struct stream_PFBD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ int binary_to_hex;
+ /* The following change dynamically. */
+ int record_type;
+ ulong record_left; /* bytes left in current record */
+} /*stream_PFBD_state*/;
+#define private_st_PFBD_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_PFBD_state, stream_PFBD_state, "PFBDecode state")
+extern const stream_template s_PFBD_template;
+
+/* SubFileDecode */
+typedef struct stream_SFD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ long count; /* # of EODs to scan over */
+ gs_const_string eod;
+ /* The following change dynamically. */
+ uint match; /* # of matched chars not copied to output */
+ uint copy_count; /* # of matched characters left to copy */
+ uint copy_ptr; /* index of next character to copy */
+} stream_SFD_state;
+#define private_st_SFD_state() /* in sfilter1.c */\
+ gs_private_st_composite(st_SFD_state, stream_SFD_state,\
+ "SubFileDecode state", sfd_enum_ptrs, sfd_reloc_ptrs)
+extern const stream_template s_SFD_template;
diff --git a/gs/src/sfilter1.c b/gs/src/sfilter1.c
new file mode 100644
index 000000000..47488dfd1
--- /dev/null
+++ b/gs/src/sfilter1.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfilter1.c */
+/* Filters included in Level 1 systems: NullEncode/Decode, PFBDecode, */
+/* SubFileDecode. */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "sfilter.h"
+
+/* ------ NullEncode/Decode ------ */
+
+/* Process a buffer */
+private int
+s_Null_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ return stream_move(pr, pw);
+}
+
+/* Stream template */
+const stream_template s_Null_template =
+{ &st_stream_state, NULL, s_Null_process, 1, 1
+};
+
+/* ------ PFBDecode ------ */
+
+private_st_PFBD_state();
+
+#define ss ((stream_PFBD_state *)st)
+
+/* Initialize the state */
+private int
+s_PFBD_init(stream_state *st)
+{ ss->record_type = -1;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_PFBD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int rcount, wcount;
+ int c;
+ int status = 0;
+top: rcount = pr->limit - p;
+ wcount = pw->limit - q;
+ switch ( ss->record_type )
+ {
+ case -1: /* new record */
+ if ( rcount < 2 )
+ goto out;
+ if ( p[1] != 0x80 )
+ goto err;
+ c = p[2];
+ switch ( c )
+ {
+ case 1: case 2:
+ break;
+ case 3:
+ status = EOFC;
+ p += 2;
+ goto out;
+ default:
+ p += 2;
+ goto err;
+ }
+ if ( rcount < 6 )
+ goto out;
+ ss->record_type = c;
+ ss->record_left = p[3] + ((uint)p[4] << 8) +
+ ((ulong)p[5] << 16) +
+ ((ulong)p[6] << 24);
+ p += 6;
+ goto top;
+ case 1: /* text data */
+ /* Translate \r to \n. */
+ { int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ if ( count > ss->record_left )
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ for ( ; count != 0; count-- )
+ { c = *++p;
+ *++q = (c == '\r' ? '\n' : c);
+ }
+ } break;
+ case 2: /* binary data */
+ if ( ss->binary_to_hex )
+ { /* Translate binary to hex. */
+ int count;
+ register const char _ds *hex_digits =
+ "0123456789abcdef";
+ wcount >>= 1; /* 2 chars per input byte */
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ if ( count > ss->record_left )
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ for ( ; count != 0; count-- )
+ { c = *++p;
+ q[1] = hex_digits[c >> 4];
+ q[2] = hex_digits[c & 0xf];
+ q += 2;
+ }
+ }
+ else
+ { /* Just read binary data. */
+ int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ if ( count > ss->record_left )
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ memcpy(q + 1, p + 1, count);
+ p += count;
+ q += count;
+ }
+ break;
+ }
+ if ( ss->record_left == 0 )
+ { ss->record_type = -1;
+ goto top;
+ }
+out: pr->ptr = p;
+ pw->ptr = q;
+ return status;
+err: pr->ptr = p;
+ pw->ptr = q;
+ return ERRC;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_PFBD_template =
+{ &st_PFBD_state, s_PFBD_init, s_PFBD_process, 6, 2
+};
+
+/* ------ SubFileDecode ------ */
+
+private_st_SFD_state();
+/* GC procedures */
+private ENUM_PTRS_BEGIN(sfd_enum_ptrs) return 0;
+ ENUM_CONST_STRING_PTR(0, stream_SFD_state, eod);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(sfd_reloc_ptrs) ;
+ RELOC_CONST_STRING_PTR(stream_SFD_state, eod);
+RELOC_PTRS_END
+
+#define ss ((stream_SFD_state *)st)
+
+/* Initialize the stream */
+private int
+s_SFD_init(stream_state *st)
+{ ss->match = 0;
+ ss->copy_count = 0;
+ return 0;
+}
+
+/* Refill the buffer */
+private int
+s_SFD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ if ( ss->eod.size == 0 )
+ { /* Just read, with no EOD pattern. */
+ int rcount = rlimit - p;
+ int wcount = wlimit - q;
+ int count = min(rcount, wcount);
+ if ( ss->count == 0 ) /* no EOD limit */
+ return stream_move(pr, pw);
+ else if ( ss->count > count ) /* not EOD yet */
+ { ss->count -= count;
+ return stream_move(pr, pw);
+ }
+ else
+ { /* We're going to reach EOD. */
+ count = ss->count;
+ memcpy(q + 1, p + 1, count);
+ pr->ptr = p + count;
+ pw->ptr = q + count;
+ return EOFC;
+ }
+ }
+ else
+ { /* Read looking for an EOD pattern. */
+ const byte *pattern = ss->eod.data;
+ uint match = ss->match;
+cp: /* Check whether we're still copying a partial match. */
+ if ( ss->copy_count )
+ { int count = min(wlimit - q, ss->copy_count);
+ memcpy(q + 1, ss->eod.data + ss->copy_ptr, count);
+ ss->copy_count -= count;
+ ss->copy_ptr += count;
+ q += count;
+ if ( ss->copy_count != 0 ) /* hit wlimit */
+ { status = 1;
+ goto xit;
+ }
+ else if ( ss->count < 0 )
+ { status = EOFC;
+ goto xit;
+ }
+ }
+ while ( p < rlimit )
+ { int c = *++p;
+ if ( c == pattern[match] )
+ { if ( ++match == ss->eod.size )
+ { switch ( ss->count )
+ {
+ case 0:
+ status = EOFC;
+ goto xit;
+ case 1:
+ ss->count = -1;
+ break;
+ default:
+ ss->count--;
+ }
+ ss->copy_ptr = 0;
+ ss->copy_count = match;
+ match = 0;
+ goto cp;
+ }
+ continue;
+ }
+ /* No match here, back up to find the longest one. */
+ /* This may be quadratic in string_size, but */
+ /* we don't expect this to be a real problem. */
+ if ( match > 0 )
+ { int end = match;
+ while ( match > 0 )
+ { match--;
+ if ( !memcmp(pattern,
+ pattern + end - match,
+ match)
+ )
+ break;
+ }
+ /* Copy the unmatched initial portion of */
+ /* the EOD string to the output. */
+ p--;
+ ss->copy_ptr = 0;
+ ss->copy_count = end - match;
+ goto cp;
+ }
+ if ( q == wlimit )
+ { p--;
+ status = 1;
+ break;
+ }
+ *++q = c;
+ }
+xit: pr->ptr = p;
+ pw->ptr = q;
+ ss->match = match;
+ }
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_SFD_template =
+{ &st_SFD_state, s_SFD_init, s_SFD_process, 1, 1
+};
diff --git a/gs/src/sfilter2.c b/gs/src/sfilter2.c
new file mode 100644
index 000000000..277accef5
--- /dev/null
+++ b/gs/src/sfilter2.c
@@ -0,0 +1,279 @@
+/* Copyright (C) 1991, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfilter2.c */
+/* Simple Level 2 filters */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "sa85x.h"
+#include "sbtx.h"
+#include "scanchar.h"
+
+/* ------ ASCII85Encode ------ */
+
+/* Process a buffer */
+private int
+s_A85E_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ int count;
+ for ( ; (count = rlimit - p) >= 4; p += 4 )
+ { ulong word =
+ ((ulong)(((uint)p[1] << 8) + p[2]) << 16) +
+ (((uint)p[3] << 8) + p[4]);
+ if ( word == 0 )
+ { if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ *++q = 'z';
+ }
+ else
+ { ulong v4 = word / 85; /* max 85^4 */
+ ulong v3 = v4 / 85; /* max 85^3 */
+ uint v2 = v3 / 85; /* max 85^2 */
+ uint v1 = v2 / 85; /* max 85 */
+
+ if ( wlimit - q < 6 )
+ { status = 1;
+ break;
+ }
+ q[1] = (byte)v1 + '!';
+ q[2] = (byte)(v2 - v1 * 85) + '!';
+ q[3] = (byte)((uint)v3 - v2 * 85) + '!';
+ q[4] = (byte)((uint)v4 - (uint)v3 * 85) + '!';
+ q[5] = (byte)((uint)word - (uint)v4 * 85) + '!';
+ q += 5;
+ }
+ if ( !(count & 60) )
+ *++q = '\n';
+ }
+ /* Check for final partial word. */
+ if ( last && status == 0 && count < 4 )
+ { if ( wlimit - q < (count == 0 ? 2 : count + 3) )
+ status = 1;
+ else
+ { ulong word = 0;
+ ulong divisor = 85L*85*85*85;
+ switch ( count )
+ {
+ case 3:
+ word += (uint)p[3] << 8;
+ case 2:
+ word += (ulong)p[2] << 16;
+ case 1:
+ word += (ulong)p[1] << 24;
+ p += count;
+ while ( count-- >= 0 )
+ { ulong v = word / divisor; /* actually only a byte */
+ *++q = (byte)v + '!';
+ word -= v * divisor;
+ divisor /= 85;
+ }
+ /*case 0:*/
+ }
+ *++q = '~';
+ *++q = '>';
+ }
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_A85E_template =
+{ &st_stream_state, NULL, s_A85E_process, 4, 6
+};
+
+/* ------ ASCII85Decode ------ */
+
+private_st_A85D_state();
+
+#define ss ((stream_A85D_state *)st)
+
+/* Initialize the state */
+private int
+s_A85D_init(stream_state *st)
+{ return s_A85D_init_inline(ss);
+}
+
+/* Process a buffer */
+private int a85d_finish(P3(int, ulong, stream_cursor_write *));
+private int
+s_A85D_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int ccount = ss->odd;
+ ulong word = ss->word;
+ int status = 0;
+
+ while ( p < rlimit )
+ { int ch = *++p;
+ uint ccode = ch - '!';
+ if ( ccode < 85 ) /* catches ch < '!' as well */
+ { if ( wlimit - q < 4 )
+ { p--;
+ status = 1;
+ break;
+ }
+ word = word * 85 + ccode;
+ if ( ++ccount == 5 )
+ { q[1] = (byte)(word >> 24);
+ q[2] = (byte)(word >> 16);
+ q[3] = (byte)((uint)word >> 8);
+ q[4] = (byte)word;
+ q += 4;
+ word = 0;
+ ccount = 0;
+ }
+ }
+ else if ( ch == 'z' && ccount == 0 )
+ { if ( wlimit - q < 4 )
+ { p--;
+ status = 1;
+ break;
+ }
+ q[1] = q[2] = q[3] = q[4] = 0,
+ q += 4;
+ }
+ else if ( scan_char_decoder[ch] == ctype_space )
+ ;
+ else if ( ch == '~' )
+ { /* Handle odd bytes. */
+ if ( p == rlimit )
+ { if ( last )
+ status = ERRC;
+ else
+ p--;
+ break;
+ }
+ if ( (int)(wlimit - q) < ccount - 1 )
+ { status = 1;
+ p--;
+ break;
+ }
+ if ( *++p != '>' )
+ { status = ERRC;
+ break;
+ }
+ pw->ptr = q;
+ status = a85d_finish(ccount, word, pw);
+ q = pw->ptr;
+ break;
+ }
+ else /* syntax error or exception */
+ { status = ERRC;
+ break;
+ }
+ }
+ pw->ptr = q;
+ if ( status == 0 && last )
+ { if ( (int)(wlimit - q) < ccount - 1 )
+ status = 1;
+ else
+ status = a85d_finish(ccount, word, pw);
+ }
+ pr->ptr = p;
+ ss->odd = ccount;
+ ss->word = word;
+ return status;
+}
+/* Handle the end of input data. */
+private int
+a85d_finish(int ccount, ulong word, stream_cursor_write *pw)
+{ /* Assume there is enough room in the output buffer! */
+ byte *q = pw->ptr;
+ int status = EOFC;
+ switch ( ccount )
+ {
+ case 0:
+ break;
+ case 1: /* syntax error */
+ status = ERRC;
+ break;
+ case 2: /* 1 odd byte */
+ word = word * (85L*85*85) + 0xffffffL;
+ goto o1;
+ case 3: /* 2 odd bytes */
+ word = word * (85L*85) + 0xffffL;
+ goto o2;
+ case 4: /* 3 odd bytes */
+ word = word * 85 + 0xffL;
+ q[3] = (byte)(word >> 8);
+o2: q[2] = (byte)(word >> 16);
+o1: q[1] = (byte)(word >> 24);
+ q += ccount - 1;
+ pw->ptr = q;
+ }
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_A85D_template =
+{ &st_A85D_state, s_A85D_init, s_A85D_process, 2, 4
+};
+
+/* ------ ByteTranslateEncode/Decode ------ */
+
+private_st_BT_state();
+
+#define ss ((stream_BT_state *)st)
+
+/* Process a buffer. Note that the same code serves for both streams. */
+
+private int
+s_BT_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ uint rcount = pr->limit - p;
+ uint wcount = pw->limit - q;
+ uint count;
+ int status;
+
+ if ( rcount <= wcount )
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+
+ while ( count-- )
+ *++q = ss->table[*++p];
+
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+
+const stream_template s_BT_template =
+{ &st_BT_state, NULL, s_BT_process, 1, 1
+};
diff --git a/gs/src/sfxboth.c b/gs/src/sfxboth.c
new file mode 100644
index 000000000..cf50c9eb8
--- /dev/null
+++ b/gs/src/sfxboth.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfxboth.c */
+/* File stream implementation using both stdio and direct OS calls */
+
+#include "sfxstdio.c"
+
+#define KEEP_FILENO_API /* see sfxfd.c */
+#include "sfxfd.c"
diff --git a/gs/src/sfxfd.c b/gs/src/sfxfd.c
new file mode 100644
index 000000000..5eeeae9d6
--- /dev/null
+++ b/gs/src/sfxfd.c
@@ -0,0 +1,313 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfxfd.c */
+/* File stream implementation using direct OS calls */
+/******
+ ****** NOTE: THIS FILE PROBABLY WILL NOT COMPILE ON NON-UNIX
+ ****** PLATFORMS, AND IT MAY REQUIRE EDITING ON SOME UNIX PLATFORMS.
+ ******/
+#include "stdio_.h" /* includes std.h */
+#include "errno_.h"
+#include "memory_.h"
+/*
+ * It's likely that you will have to edit the next line on some Unix
+ * and most non-Unix platforms, since there is no standard (ANSI or
+ * otherwise) for where to find these definitions.
+ */
+/*
+ * unistd.h may declare unlink in a way that conflicts with stdio_.h if
+ * const has been disabled.
+ */
+#define unlink unlink_
+#include <unistd.h> /* for read, write, fsync, lseek */
+#include "gdebug.h"
+#include "gpcheck.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/*
+ * This is an alternate implementation of file streams. It still uses
+ * FILE * in the interface, but it uses direct OS calls for I/O.
+ * It also includes workarounds for the nasty habit of System V Unix
+ * of breaking out of read and write operations with EINTR, EAGAIN,
+ * and/or EWOULDBLOCK "errors".
+ *
+ * The interface should be identical to that of sfxstdio.c. However, in
+ * order to allow both implementations to exist in the same executable, we
+ * optionally use different names for sread_file, swrite_file, and
+ * sappend_file (the public procedures). See sfxboth.c.
+ */
+#ifndef KEEP_FILENO_API
+# define sread_fileno sread_file
+# define swrite_fileno swrite_file
+# define sappend_fileno sappend_file
+#endif
+
+/* Forward references for file stream procedures */
+private int
+ s_fileno_available(P2(stream *, long *)),
+ s_fileno_read_seek(P2(stream *, long)),
+ s_fileno_read_close(P1(stream *)),
+ s_fileno_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_fileno_write_seek(P2(stream *, long)),
+ s_fileno_write_flush(P1(stream *)),
+ s_fileno_write_close(P1(stream *)),
+ s_fileno_write_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_fileno_switch(P2(stream *, bool));
+
+/* ------ File streams ------ */
+
+/* Get the file descriptor number of a stream. */
+#define sfileno(s) fileno((s)->file)
+
+/* Initialize a stream for reading an OS file. */
+void
+sread_fileno(register stream *s, FILE *file, byte *buf, uint len)
+{ static const stream_procs p =
+ { s_fileno_available, s_fileno_read_seek, s_std_read_reset,
+ s_std_read_flush, s_fileno_read_close, s_fileno_read_process,
+ s_fileno_switch
+ };
+ /*
+ * There is no really portable way to test seekability,
+ * but this should work on most systems.
+ */
+ int fd = fileno(file);
+ long curpos = lseek(fd, 0L, SEEK_CUR);
+ bool seekable = (curpos != -1L && lseek(fd, curpos, SEEK_SET) != -1L);
+
+ s_std_init(s, buf, len, &p,
+ (seekable ? s_mode_read + s_mode_seek : s_mode_read));
+ if_debug2('s', "[s]read file=0x%lx, fd=%d\n", (ulong)file,
+ fileno(file));
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Procedures for reading from a file */
+private int
+s_fileno_available(register stream *s, long *pl)
+{ int fd = sfileno(s);
+ *pl = sbufavailable(s);
+ if ( sseekable(s) )
+ { long pos, end;
+ pos = lseek(fd, 0L, SEEK_CUR);
+ if ( pos < 0 )
+ return ERRC;
+ end = lseek(fd, 0L, SEEK_END);
+ if ( lseek(fd, pos, SEEK_SET) < 0 || end < 0 )
+ return ERRC;
+ *pl += end - pos;
+ if ( *pl == 0 ) *pl = -1; /* EOF */
+ }
+ else
+ { if ( *pl == 0 ) *pl = -1; /* EOF */
+ }
+ return 0;
+}
+private int
+s_fileno_read_seek(register stream *s, long pos)
+{ uint end = s->srlimit - s->cbuf + 1;
+ long offset = pos - s->position;
+ if ( offset >= 0 && offset <= end )
+ { /* Staying within the same buffer */
+ s->srptr = s->cbuf + offset - 1;
+ return 0;
+ }
+ if ( lseek(sfileno(s), pos, SEEK_SET) < 0 )
+ return ERRC;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ s->end_status = 0;
+ s->position = pos;
+ return 0;
+}
+private int
+s_fileno_read_close(stream *s)
+{ FILE *file = s->file;
+ if ( file != 0 )
+ { s->file = 0;
+ return fclose(file);
+ }
+ return 0;
+}
+
+/* Initialize a stream for writing an OS file. */
+void
+swrite_fileno(register stream *s, FILE *file, byte *buf, uint len)
+{ static const stream_procs p =
+ { s_std_noavailable, s_fileno_write_seek, s_std_write_reset,
+ s_fileno_write_flush, s_fileno_write_close, s_fileno_write_process,
+ s_fileno_switch
+ };
+ s_std_init(s, buf, len, &p,
+ (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
+ if_debug2('s', "[s]write file=0x%lx, fd=%d\n", (ulong)file,
+ fileno(file));
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Initialize for appending to an OS file. */
+void
+sappend_fileno(register stream *s, FILE *file, byte *buf, uint len)
+{ swrite_fileno(s, file, buf, len);
+ s->modes = s_mode_write + s_mode_append; /* no seek */
+ s->file_modes = s->modes;
+ s->position = lseek(fileno(file), 0L, SEEK_END);
+}
+/* Procedures for writing on a file */
+private int
+s_fileno_write_seek(stream *s, long pos)
+{ /* We must flush the buffer to reposition. */
+ int code = sflush(s);
+ if ( code < 0 )
+ return code;
+ if ( lseek(sfileno(s), pos, SEEK_SET) < 0 )
+ return ERRC;
+ s->position = pos;
+ return 0;
+}
+private int
+s_fileno_write_flush(register stream *s)
+{ int result = s_process_write_buf(s, false);
+ discard(fsync(sfileno(s)));
+ return result;
+}
+private int
+s_fileno_write_close(register stream *s)
+{ s_process_write_buf(s, true);
+ return s_fileno_read_close(s);
+}
+
+#define ss ((stream *)st)
+
+/* Define the switch cases for System V interrupts. */
+#define case_again(errn) case errn: goto again;
+#ifdef EINTR
+# define handle_EINTR() case_again(EINTR)
+#else
+# define handle_EINTR() /* */
+#endif
+#if defined(EAGAIN) && (!defined(EINTR) || EAGAIN != EINTR)
+# define handle_EAGAIN() case_again(EAGAIN)
+#else
+# define handle_EAGAIN() /* */
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EINTR) || EWOULDBLOCK != EINTR) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
+# define handle_EWOULDBLOCK() case_again(EWOULDBLOCK)
+#else
+# define handle_EWOULDBLOCK() /* */
+#endif
+#define handle_SYSV_errno()\
+ handle_EINTR() handle_EAGAIN() handle_EWOULDBLOCK()
+
+/* Process a buffer for a file reading stream. */
+/* This is the first stream in the pipeline, so pr is irrelevant. */
+private int
+s_fileno_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ int nread, status;
+again: nread = read(sfileno(ss), pw->ptr + 1, (uint)(pw->limit - pw->ptr));
+ if ( nread > 0 )
+ { pw->ptr += nread;
+ status = 0;
+ }
+ else if ( nread == 0 )
+ status = EOFC;
+ else switch ( errno )
+ {
+ handle_SYSV_errno() /* Handle System V interrupts */
+ default:
+ status = ERRC;
+ }
+ process_interrupts();
+ return status;
+}
+
+/* Process a buffer for a file writing stream. */
+/* This is the last stream in the pipeline, so pw is irrelevant. */
+private int
+s_fileno_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ int nwrite, status;
+ uint count;
+again: count = pr->limit - pr->ptr;
+ /* Some versions of the DEC C library on AXP architectures */
+ /* give an error on write if the count is zero! */
+ if ( count == 0 )
+ { process_interrupts();
+ return 0;
+ }
+ nwrite = write(sfileno(ss), pr->ptr + 1, count);
+ if ( nwrite >= 0 )
+ { pr->ptr += nwrite;
+ status = 0;
+ }
+ else switch ( errno )
+ {
+ handle_SYSV_errno() /* Handle System V interrupts */
+ default:
+ status = ERRC;
+ }
+ process_interrupts();
+ return status;
+}
+
+#undef ss
+
+/* Switch a file stream to reading or writing. */
+private int
+s_fileno_switch(stream *s, bool writing)
+{ uint modes = s->file_modes;
+ int fd = sfileno(s);
+ long pos;
+ if ( writing )
+ { if ( !(s->file_modes & s_mode_write) )
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
+ (ulong)s, pos);
+ lseek(fd, pos, SEEK_SET); /* pacify OS */
+ if ( modes & s_mode_append )
+ { sappend_file(s, s->file, s->cbuf, s->cbsize); /* sets position */
+ }
+ else
+ { swrite_file(s, s->file, s->cbuf, s->cbsize);
+ s->position = pos;
+ }
+ s->modes = modes;
+ }
+ else
+ { if ( !(s->file_modes & s_mode_read) )
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
+ (ulong)s, pos);
+ if ( sflush(s) < 0 )
+ return ERRC;
+ lseek(fd, 0L, SEEK_CUR); /* pacify OS */
+ sread_file(s, s->file, s->cbuf, s->cbsize);
+ s->modes |= modes & s_mode_append; /* don't lose append info */
+ s->position = pos;
+ }
+ s->file_modes = modes;
+ return 0;
+}
diff --git a/gs/src/sfxstdio.c b/gs/src/sfxstdio.c
new file mode 100644
index 000000000..562ced91e
--- /dev/null
+++ b/gs/src/sfxstdio.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sfxstdio.c */
+/* File stream implementation using stdio */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "gpcheck.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* Forward references for file stream procedures */
+private int
+ s_file_available(P2(stream *, long *)),
+ s_file_read_seek(P2(stream *, long)),
+ s_file_read_close(P1(stream *)),
+ s_file_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_file_write_seek(P2(stream *, long)),
+ s_file_write_flush(P1(stream *)),
+ s_file_write_close(P1(stream *)),
+ s_file_write_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_file_switch(P2(stream *, bool));
+
+/* ------ File streams ------ */
+
+/* Initialize a stream for reading an OS file. */
+void
+sread_file(register stream *s, FILE *file, byte *buf, uint len)
+{ static const stream_procs p =
+ { s_file_available, s_file_read_seek, s_std_read_reset,
+ s_std_read_flush, s_file_read_close, s_file_read_process,
+ s_file_switch
+ };
+ /*
+ * There is no really portable way to test seekability,
+ * but this should work on most systems.
+ * Note that if our probe sets the ferror bit for the stream,
+ * we have to clear it again to avoid trouble later.
+ */
+ int had_error = ferror(file);
+ long curpos = ftell(file);
+ bool seekable = (curpos != -1L && fseek(file, curpos, SEEK_SET) == 0);
+
+ if ( !had_error )
+ clearerr(file);
+ s_std_init(s, buf, len, &p,
+ (seekable ? s_mode_read + s_mode_seek : s_mode_read));
+ if_debug1('s', "[s]read file=0x%lx\n", (ulong)file);
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Procedures for reading from a file */
+private int
+s_file_available(register stream *s, long *pl)
+{ *pl = sbufavailable(s);
+ if ( sseekable(s) )
+ { long pos, end;
+ pos = ftell(s->file);
+ if ( fseek(s->file, 0L, SEEK_END) ) return ERRC;
+ end = ftell(s->file);
+ if ( fseek(s->file, pos, SEEK_SET) ) return ERRC;
+ *pl += end - pos;
+ if ( *pl == 0 ) *pl = -1; /* EOF */
+ }
+ else
+ { if ( *pl == 0 && feof(s->file) ) *pl = -1; /* EOF */
+ }
+ return 0;
+}
+private int
+s_file_read_seek(register stream *s, long pos)
+{ uint end = s->srlimit - s->cbuf + 1;
+ long offset = pos - s->position;
+ if ( offset >= 0 && offset <= end )
+ { /* Staying within the same buffer */
+ s->srptr = s->cbuf + offset - 1;
+ return 0;
+ }
+ if ( fseek(s->file, pos, SEEK_SET) != 0 )
+ return ERRC;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ s->end_status = 0;
+ s->position = pos;
+ return 0;
+}
+private int
+s_file_read_close(stream *s)
+{ FILE *file = s->file;
+ if ( file != 0 )
+ { s->file = 0;
+ return fclose(file);
+ }
+ return 0;
+}
+
+/* Initialize a stream for writing an OS file. */
+void
+swrite_file(register stream *s, FILE *file, byte *buf, uint len)
+{ static const stream_procs p =
+ { s_std_noavailable, s_file_write_seek, s_std_write_reset,
+ s_file_write_flush, s_file_write_close, s_file_write_process,
+ s_file_switch
+ };
+ s_std_init(s, buf, len, &p,
+ (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
+ if_debug1('s', "[s]write file=0x%lx\n", (ulong)file);
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Initialize for appending to an OS file. */
+void
+sappend_file(register stream *s, FILE *file, byte *buf, uint len)
+{ swrite_file(s, file, buf, len);
+ s->modes = s_mode_write + s_mode_append; /* no seek */
+ s->file_modes = s->modes;
+ fseek(file, 0L, SEEK_END);
+ s->position = ftell(file);
+}
+/* Procedures for writing on a file */
+private int
+s_file_write_seek(stream *s, long pos)
+{ /* We must flush the buffer to reposition. */
+ int code = sflush(s);
+ if ( code < 0 )
+ return code;
+ if ( fseek(s->file, pos, SEEK_SET) != 0 )
+ return ERRC;
+ s->position = pos;
+ return 0;
+}
+private int
+s_file_write_flush(register stream *s)
+{ int result = s_process_write_buf(s, false);
+ fflush(s->file);
+ return result;
+}
+private int
+s_file_write_close(register stream *s)
+{ s_process_write_buf(s, true);
+ return s_file_read_close(s);
+}
+
+#define ss ((stream *)st)
+
+/* Process a buffer for a file reading stream. */
+/* This is the first stream in the pipeline, so pr is irrelevant. */
+private int
+s_file_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ FILE *file = ss->file;
+ int count = fread(pw->ptr + 1, 1, (uint)(pw->limit - pw->ptr), file);
+ if ( count < 0 )
+ count = 0;
+ pw->ptr += count;
+ process_interrupts();
+ return (ferror(file) ? ERRC : feof(file) ? EOFC : 1);
+}
+
+/* Process a buffer for a file writing stream. */
+/* This is the last stream in the pipeline, so pw is irrelevant. */
+private int
+s_file_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ /* The DEC C library on AXP architectures gives an error on */
+ /* fwrite if the count is zero! */
+ uint count = pr->limit - pr->ptr;
+ if ( count != 0 )
+ { FILE *file = ss->file;
+ int written = fwrite(pr->ptr + 1, 1, count, file);
+ if ( written < 0 )
+ written = 0;
+ pr->ptr += written;
+ process_interrupts();
+ return (ferror(file) ? ERRC : 0);
+ }
+ else
+ { process_interrupts();
+ return 0;
+ }
+}
+
+#undef ss
+
+/* Switch a file stream to reading or writing. */
+private int
+s_file_switch(stream *s, bool writing)
+{ uint modes = s->file_modes;
+ FILE *file = s->file;
+ long pos;
+ if ( writing )
+ { if ( !(s->file_modes & s_mode_write) )
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
+ (ulong)s, pos);
+ fseek(file, pos, SEEK_SET);
+ if ( modes & s_mode_append )
+ { sappend_file(s, file, s->cbuf, s->cbsize); /* sets position */
+ }
+ else
+ { swrite_file(s, file, s->cbuf, s->cbsize);
+ s->position = pos;
+ }
+ s->modes = modes;
+ }
+ else
+ { if ( !(s->file_modes & s_mode_read) )
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
+ (ulong)s, pos);
+ if ( sflush(s) < 0 )
+ return ERRC;
+ fseek(file, 0L, SEEK_CUR); /* pacify C library */
+ sread_file(s, file, s->cbuf, s->cbsize);
+ s->modes |= modes & s_mode_append; /* don't lose append info */
+ s->position = pos;
+ }
+ s->file_modes = modes;
+ return 0;
+}
diff --git a/gs/src/shc.c b/gs/src/shc.c
new file mode 100644
index 000000000..09f052b44
--- /dev/null
+++ b/gs/src/shc.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* shc.c */
+/* Support code for shc.h */
+#include "std.h"
+#include "scommon.h"
+#include "shc.h"
+
+/* ------ Encoding ------ */
+
+/* Empty the 1-word buffer onto the output stream. */
+/* q has already been incremented. */
+void
+hc_put_code_proc(bool reverse_bits, byte *q, uint cw)
+{
+#define cb(n) ((byte)(cw >> (n * 8)))
+ if ( reverse_bits )
+ {
+#if hc_bits_size > 16
+ q[-3] = byte_reverse_bits[cb(3)];
+ q[-2] = byte_reverse_bits[cb(2)];
+#endif
+ q[-1] = byte_reverse_bits[cb(1)];
+ q[0] = byte_reverse_bits[cb(0)];
+ }
+ else
+ {
+#if hc_bits_size > 16
+ q[-3] = cb(3);
+ q[-2] = cb(2);
+#endif
+ q[-1] = cb(1);
+ q[0] = cb(0);
+ }
+#undef cb
+}
+
+/* Put out any final bytes. */
+/* Note that this does a store_state, but not a load_state. */
+byte *
+hc_put_last_bits_proc(stream_hc_state *ss, byte *q, uint bits, int bits_left)
+{ while ( bits_left < hc_bits_size )
+ { byte c = (byte)(bits >> (hc_bits_size - 8));
+ if ( ss->FirstBitLowOrder )
+ c = byte_reverse_bits[c];
+ *++q = c;
+ bits <<= 8;
+ bits_left += 8;
+ }
+ ss->bits = bits;
+ ss->bits_left = bits_left;
+ return q;
+}
diff --git a/gs/src/shc.h b/gs/src/shc.h
new file mode 100644
index 000000000..86b5a27fa
--- /dev/null
+++ b/gs/src/shc.h
@@ -0,0 +1,245 @@
+/* Copyright (C) 1992, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* shc.h */
+/* Common definitions for filters using Huffman coding */
+/* Requires scommon.h */
+
+#ifndef shc_INCLUDED
+# define shc_INCLUDED
+
+#include "gsbittab.h"
+
+/*
+ * These definitions are valid for code lengths up to 16 bits
+ * and non-negative decoded values up to 15 bits.
+ *
+ * We define 3 different representations of the code: encoding tables,
+ * decoding tables, and a definition table which can be generated easily
+ * from frequency information and which in turn can easily generate
+ * the encoding and decoding tables.
+ *
+ * The definition table has two parts: a list of the number of i-bit
+ * codes for each i >= 1, and the decoded values corresponding to
+ * the code values in increasing lexicographic order (which will also
+ * normally be decreasing code frequency). Calling these two lists
+ * L[1..M] and V[0..N-1] respectively, we have the following invariants:
+ * - 1 <= M <= max_hc_length, N >= 2.
+ * - L[0] = 0.
+ * - for i=1..M, L[i] >= 0.
+ * - sum(i=1..M: L[i]) = N.
+ * - sum(i=1..M: L[i] * 2^-i) = 1.
+ * - V[0..N-1] are a permutation of the integers 0..N-1.
+ */
+#define max_hc_length 16
+typedef struct hc_definition_s {
+ ushort *counts; /* [0..M] */
+ uint num_counts; /* M */
+ ushort *values; /* [0..N-1] */
+ uint num_values; /* N */
+} hc_definition;
+
+/* ------ Common state ------ */
+
+/*
+ * Define the common stream state for Huffman-coded filters.
+ * Invariants when writing:
+ * 0 <= bits_left <= hc_bits_size;
+ * Only the leftmost (hc_bits_size - bits_left) bits of bits
+ * contain valid data.
+ */
+#define stream_hc_state_common\
+ stream_state_common;\
+ /* The client sets the following before initialization. */\
+ bool FirstBitLowOrder;\
+ /* The following are updated dynamically. */\
+ uint bits; /* most recent bits of input or */\
+ /* current bits of output */\
+ int bits_left /* # of valid low bits (input) or */\
+ /* unused low bits (output) in above, */\
+ /* 0 <= bits_left <= 7 */
+typedef struct stream_hc_state_s {
+ stream_hc_state_common;
+} stream_hc_state;
+
+#define hc_bits_size (arch_sizeof_int * 8)
+#define s_hce_init_inline(ss)\
+ ((ss)->bits = 0, (ss)->bits_left = hc_bits_size)
+#define s_hcd_init_inline(ss)\
+ ((ss)->bits = 0, (ss)->bits_left = 0)
+
+/* ------ Encoding tables ------ */
+
+/* Define the structure for the encoding tables. */
+typedef struct hce_code_s {
+ ushort code;
+ ushort code_length;
+} hce_code;
+#define hce_entry(c, len) { c, len }
+
+typedef struct hce_table_s {
+ uint count;
+ hce_code *codes;
+} hce_table;
+
+#define hce_bits_available(n)\
+ (ss->bits_left >= (n) || wlimit - q > ((n) - ss->bits_left - 1) >> 3)
+
+/* ------ Encoding utilities ------ */
+
+/*
+ * Put a code on the output. The client is responsible for ensuring
+ * that q does not exceed pw->limit.
+ */
+
+#ifdef DEBUG
+# define hc_print_value(code, clen)\
+ (gs_debug_c('W') ?\
+ (dprintf2("[W]0x%x,%d\n", code, clen), 0) : 0)
+# define hc_print_value_then(code, clen) hc_print_value(code, clen),
+#else
+# define hc_print_value(code, clen) 0
+# define hc_print_value_then(code, clen) /* */
+#endif
+#define hc_print_code(rp) hc_print_value((rp)->code, (rp)->code_length)
+
+/* Declare variables that hold the encoder state. */
+#define hce_declare_state\
+ register uint bits;\
+ register int bits_left
+
+/* Load the state from the stream. */
+/* Free variables: ss, bits, bits_left. */
+#define hce_load_state()\
+ bits = ss->bits, bits_left = ss->bits_left
+
+/* Store the state back in the stream. */
+/* Free variables: ss, bits, bits_left. */
+#define hce_store_state()\
+ ss->bits = bits, ss->bits_left = bits_left
+
+/* Put a code on the stream. */
+void hc_put_code_proc(P3(bool, byte *, uint));
+#define hc_put_value(ss, q, code, clen)\
+ (hc_print_value_then(code, clen)\
+ ((bits_left -= (clen)) >= 0 ?\
+ (bits += (code) << bits_left) :\
+ (hc_put_code_proc((ss)->FirstBitLowOrder,\
+ q += hc_bits_size >> 3,\
+ (bits + ((code) >> -bits_left))),\
+ bits = (code) << (bits_left += hc_bits_size))))
+#define hc_put_code(ss, q, cp)\
+ hc_put_value(ss, q, (cp)->code, (cp)->code_length)
+
+/*
+ * Force out the final bits to the output.
+ * Note that this does a store_state, but not a load_state.
+ */
+byte *hc_put_last_bits_proc(P4(stream_hc_state *, byte *, uint, int));
+#define hc_put_last_bits(ss, q)\
+ hc_put_last_bits_proc(ss, q, bits, bits_left)
+
+/* ------ Decoding tables ------ */
+
+/*
+ * Define the structure for the decoding tables.
+ * First-level nodes are either leaves, which have
+ * value = decoded value
+ * code_length <= initial_bits
+ * or non-leaves, which have
+ * value = the index of a sub-table
+ * code_length = initial_bits + the number of additional dispatch bits
+ * Second-level nodes are always leaves, with
+ * code_length = the actual number of bits in the code - initial_bits.
+ */
+
+typedef struct hcd_code_s {
+ short value;
+ ushort code_length;
+} hcd_code;
+
+typedef struct hcd_table_s {
+ uint count;
+ uint initial_bits;
+ hcd_code *codes;
+} hcd_table;
+
+/* Declare variables that hold the decoder state. */
+#define hcd_declare_state\
+ register const byte *p;\
+ const byte *rlimit;\
+ uint bits;\
+ int bits_left
+
+/* Load the state from the stream. */
+/* Free variables: pr, ss, p, rlimit, bits, bits_left. */
+#define hcd_load_state()\
+ p = pr->ptr,\
+ rlimit = pr->limit,\
+ bits = ss->bits,\
+ bits_left = ss->bits_left
+
+/* Store the state back in the stream. */
+/* Put back any complete bytes into the input buffer. */
+/* Free variables: pr, ss, p, bits, bits_left. */
+#define hcd_store_state()\
+ pr->ptr = p -= (bits_left >> 3),\
+ ss->bits = bits >>= (bits_left & ~7),\
+ ss->bits_left = bits_left &= 7
+
+/* Macros to get blocks of bits from the input stream. */
+/* Invariants: 0 <= bits_left <= bits_size; */
+/* bits [bits_left-1..0] contain valid data. */
+
+#define hcd_bits_available(n)\
+ (bits_left >= (n) || rlimit - p > ((n) - bits_left - 1) >> 3)
+/* For hcd_ensure_bits, n must not be greater than 8. */
+#define hcd_ensure_bits(n, outl)\
+ if ( bits_left < n ) hcd_more_bits(outl)
+
+/* Load more bits into the buffer. */
+#define hcd_more_bits_1(outl)\
+ { int c;\
+ if ( p < rlimit ) c = *++p;\
+ else goto outl;\
+ if ( ss->FirstBitLowOrder ) c = byte_reverse_bits[c];\
+ bits = (bits << 8) + c, bits_left += 8;\
+ }
+#if hc_bits_size == 16
+# define hcd_more_bits(outl) hcd_more_bits_1(outl)
+#else /* hc_bits_size >= 32 */
+# define hcd_more_bits(outl)\
+ { if ( rlimit - p < 3 ) hcd_more_bits_1(outl)\
+ else\
+ { if ( ss->FirstBitLowOrder )\
+ bits = (bits << 24) + ((uint)byte_reverse_bits[p[1]] << 16) + ((uint)byte_reverse_bits[p[2]] << 8) + byte_reverse_bits[p[3]];\
+ else\
+ bits = (bits << 24) + ((uint)p[1] << 16) + ((uint)p[2] << 8) + p[3];\
+ bits_left += 24, p += 3;\
+ }\
+ }
+#endif
+
+#define hcd_peek_bits(n) ((bits >> (bits_left - (n))) & ((1 << (n)) - 1))
+
+#define hcd_peek_var_bits(n)\
+ ((bits >> (bits_left - (n))) & byte_right_mask[n])
+
+#define hcd_skip_bits(n) (bits_left -= (n))
+
+#endif /* shc_INCLUDED */
diff --git a/gs/src/shcgen.c b/gs/src/shcgen.c
new file mode 100644
index 000000000..161d9e8b2
--- /dev/null
+++ b/gs/src/shcgen.c
@@ -0,0 +1,462 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* shcgen.c */
+/* Generate (bounded) Huffman code definitions from frequencies, */
+/* and tables from definitions. */
+#include "memory_.h"
+#include "stdio_.h"
+#include <stdlib.h> /* for qsort */
+#include "gdebug.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "scommon.h"
+#include "shc.h"
+#include "shcgen.h"
+
+/* ------ Frequency -> definition procedure ------ */
+
+/* Define a node for the Huffman code tree. */
+typedef struct count_node_s count_node;
+struct count_node_s {
+ long freq; /* frequency of value */
+ uint value; /* data value being encoded */
+ uint code_length; /* length of Huffman code */
+ count_node *next; /* next node in freq-sorted list */
+ count_node *left; /* left child in tree (smaller code_length) */
+ count_node *right; /* right child in tree (greater code_length) */
+};
+
+#ifdef DEBUG
+# define debug_print_nodes(nodes, n, tag, lengths)\
+ if ( gs_debug_c('W') ) print_nodes_proc(nodes, n, tag, lengths);
+private void
+print_nodes_proc(const count_node *nodes, int n, const char *tag, int lengths)
+{ int i;
+
+ dprintf1("[w]---------------- %s ----------------\n", tag);
+ for ( i = 0; i < n; ++i )
+ dprintf7("[w]node %d: f=%ld v=%d len=%d N=%d L=%d R=%d\n",
+ i, nodes[i].freq, nodes[i].value, nodes[i].code_length,
+ (nodes[i].next == 0 ? -1 : (int)(nodes[i].next - nodes)),
+ (nodes[i].left == 0 ? -1 : (int)(nodes[i].left - nodes)),
+ (nodes[i].right == 0 ? -1 : (int)(nodes[i].right - nodes)));
+ for ( i = lengths; i > 0; )
+ { int j = i;
+ int len = nodes[--j].code_length;
+
+ while ( j > 0 && nodes[j-1].code_length == len )
+ --j;
+ dprintf2("[w]%d codes of length %d\n", i - j, len);
+ i = j;
+ }
+}
+#else
+# define debug_print_nodes(nodes, n, tag, lengths) DO_NOTHING
+#endif
+
+/* Node comparison procedures for sorting. */
+#define pn1 ((const count_node *)p1)
+#define pn2 ((const count_node *)p2)
+/* Sort by decreasing frequency. */
+private int
+compare_freqs(const void *p1, const void *p2)
+{ long diff = pn2->freq - pn1->freq;
+ return (diff < 0 ? -1 : diff > 0 ? 1 : 0);
+}
+/* Sort by increasing code length, and secondarily by decreasing frequency. */
+private int
+compare_code_lengths(const void *p1, const void *p2)
+{ int diff = pn1->code_length - pn2->code_length;
+ return (diff < 0 ? -1 : diff > 0 ? 1 : compare_freqs(p1, p2));
+}
+/* Sort by increasing code value. */
+private int
+compare_values(const void *p1, const void *p2)
+{ return (pn1->value < pn2->value ? -1 :
+ pn1->value > pn2->value ? 1 : 0);
+}
+#undef pn1
+#undef pn2
+
+/* Adjust code lengths so that none of them exceeds max_length. */
+/* We break this out just to help organize the code; it's only called */
+/* from one place in hc_compute. */
+private void
+hc_limit_code_lengths(count_node *nodes, uint num_values, int max_length)
+{ int needed; /* # of max_length codes we need to free up */
+ count_node *longest = nodes + num_values;
+
+ { /* Compute the number of additional max_length codes */
+ /* we need to make available. */
+ int length = longest[-1].code_length;
+ int next_length;
+ int avail = 0;
+ while ( (next_length = longest[-1].code_length) > max_length )
+ { avail >>= length - next_length;
+ length = next_length;
+ (--longest)->code_length = max_length;
+ ++avail;
+ }
+ needed = (nodes + num_values - longest) -
+ (avail >>= (length - max_length));
+ if_debug2('W', "[w]avail=%d, needed=%d\n",
+ avail, needed);
+ }
+ /* Skip over all max_length codes. */
+ while ( longest[-1].code_length == max_length )
+ --longest;
+
+ /*
+ * To make available a code of length N, suppose that the next
+ * shortest used code is of length M.
+ * We take the lowest-frequency code of length M and change it
+ * to M+1; we then have to compensate by reducing the length of
+ * some of the highest-frequency codes of length N, as follows:
+ * M new lengths for codes of length N
+ * --- -----------
+ * N-1 (none)
+ * N-2 N-1
+ * <N-2 M+2, M+2, N-1
+ * In the present situation, N = max_length.
+ */
+ for ( ; needed > 0; --needed )
+ { /* longest points to the first code of length max_length. */
+ /* Since codes are sorted by increasing code length, */
+ /* longest-1 is the desired code of length M. */
+ int M1 = ++(longest[-1].code_length);
+ switch ( max_length - M1 )
+ {
+ case 0: /* M == N-1 */
+ --longest;
+ break;
+ case 1: /* M == N-2 */
+ longest++->code_length = M1;
+ break;
+ default:
+ longest->code_length = M1 + 1;
+ longest[1].code_length = M1 + 1;
+ longest[2].code_length--;
+ longest += 3;
+ }
+ }
+}
+
+/* Compute an optimal Huffman code from an input data set. */
+/* The client must have set all the elements of *def. */
+int
+hc_compute(hc_definition *def, const long *freqs, gs_memory_t *mem)
+{ uint num_values = def->num_values;
+ count_node *nodes =
+ (count_node *)gs_alloc_byte_array(mem, num_values * 2 - 1,
+ sizeof(count_node), "hc_compute");
+ int i;
+ count_node *lowest;
+ count_node *comb;
+
+ if ( nodes == 0 )
+ return_error(gs_error_VMerror);
+
+ /* Create leaf nodes for the input data. */
+ for ( i = 0; i < num_values; ++i )
+ nodes[i].freq = freqs[i], nodes[i].value = i;
+
+ /* Create a list sorted by increasing frequency. */
+ /* Also initialize the tree structure. */
+ qsort(nodes, num_values, sizeof(count_node), compare_freqs);
+ for ( i = 0; i < num_values; ++i )
+ nodes[i].next = &nodes[i - 1],
+ nodes[i].code_length = 0,
+ nodes[i].left = nodes[i].right = 0;
+ nodes[0].next = 0;
+ debug_print_nodes(nodes, num_values, "after sort", 0);
+
+ /* Construct the Huffman code tree. */
+ for ( lowest = &nodes[num_values - 1], comb = &nodes[num_values]; ;
+ ++comb
+ )
+ { count_node *pn1 = lowest;
+ count_node *pn2 = pn1->next;
+ long freq = pn1->freq + pn2->freq;
+
+ /* Create a parent for the two lowest-frequency nodes. */
+ lowest = pn2->next;
+ comb->freq = freq;
+ if ( pn1->code_length <= pn2->code_length )
+ comb->left = pn1, comb->right = pn2,
+ comb->code_length = pn2->code_length + 1;
+ else
+ comb->left = pn2, comb->right = pn1,
+ comb->code_length = pn1->code_length + 1;
+ if ( lowest == 0 ) /* no nodes left to combine */
+ break;
+ /* Insert comb in the sorted list. */
+ if ( freq < lowest->freq )
+ comb->next = lowest, lowest = comb;
+ else
+ { count_node *here = lowest;
+ while ( here->next != 0 && freq >= here->next->freq )
+ here = here->next;
+ comb->next = here->next;
+ here->next = comb;
+ }
+ }
+
+ /* comb (i.e., &nodes[num_values * 2 - 2] is the root of the tree. */
+ /* Note that the left and right children of an interior node */
+ /* were constructed before, and therefore have lower indices */
+ /* in the nodes array than, the parent node. Thus we can assign */
+ /* the code lengths (node depths) in a single descending-order */
+ /* sweep. */
+ comb++->code_length = 0;
+ while ( comb > nodes + num_values )
+ { --comb;
+ comb->left->code_length = comb->right->code_length =
+ comb->code_length + 1;
+ }
+ debug_print_nodes(nodes, num_values * 2 - 1, "after combine", 0);
+
+ /* Sort the leaves again by code length. */
+ qsort(nodes, num_values, sizeof(count_node), compare_code_lengths);
+ debug_print_nodes(nodes, num_values, "after re-sort", num_values);
+
+ /* Limit the code length to def->num_counts. */
+ hc_limit_code_lengths(nodes, num_values, def->num_counts);
+ debug_print_nodes(nodes, num_values, "after limit", num_values);
+
+ /* Sort within each code length by increasing code value. */
+ /* This doesn't affect data compression, but it makes */
+ /* the code definition itself compress better using our */
+ /* incremental encoding. */
+ for ( i = num_values; i > 0; )
+ { int j = i;
+ int len = nodes[--j].code_length;
+ while ( j > 0 && nodes[j-1].code_length == len )
+ --j;
+ qsort(&nodes[j], i - j, sizeof(count_node), compare_values);
+ i = j;
+ }
+
+ /* Extract the definition from the nodes. */
+ memset(def->counts, 0, sizeof(*def->counts) * (def->num_counts + 1));
+ for ( i = 0; i < num_values; ++i )
+ { def->values[i] = nodes[i].value;
+ def->counts[nodes[i].code_length]++;
+ }
+
+ /* All done, release working storage. */
+ gs_free_object(mem, nodes, "hc_compute");
+ return 0;
+}
+
+/* ------ Byte string <-> definition procedures ------ */
+
+/*
+ * We define a compressed representation for (well-behaved) definitions
+ * as a byte string. A "well-behaved" definition is one where if
+ * code values A and B have the same code length and A < B,
+ * A precedes B in the values table of the definition, and hence
+ * A's encoding lexicographically precedes B's.
+ *
+ * The successive bytes in the compressed string give the code lengths for
+ * runs of decoded values, in the form nnnnllll where nnnn is the number of
+ * consecutive values -1 and llll is the code length -1.
+ */
+
+/* Convert a definition to a byte string. */
+/* The caller must provide the byte string, of length def->num_values. */
+/* Assume (do not check) that the definition is well-behaved. */
+/* Return the actual length of the string. */
+int
+hc_bytes_from_definition(byte *dbytes, const hc_definition *def)
+{ int i, j;
+ byte *bp = dbytes;
+ const byte *lp = dbytes;
+ const byte *end = dbytes + def->num_values;
+ const ushort *values = def->values;
+
+ /* Temporarily use the output string as a map from */
+ /* values to code lengths. */
+ for ( i = 1; i <= def->num_counts; i++ )
+ for ( j = 0; j < def->counts[i]; j++ )
+ bp[*values++] = i;
+
+ /* Now construct the actual string. */
+ while ( lp < end )
+ { const byte *vp;
+ byte len = *lp;
+ for ( vp = lp + 1; vp < end && vp < lp + 16 && *vp == len; )
+ vp++;
+ *bp++ = ((vp - lp - 1) << 4) + (len - 1);
+ lp = vp;
+ }
+
+ return bp - dbytes;
+}
+
+/* Extract num_counts and num_values from a byte string. */
+void
+hc_sizes_from_bytes(hc_definition *def, const byte *dbytes, int num_bytes)
+{ uint num_counts = 0, num_values = 0;
+ int i;
+
+ for ( i = 0; i < num_bytes; i++ )
+ { int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+ if ( l > num_counts )
+ num_counts = l;
+ num_values += n;
+ }
+ def->num_counts = num_counts;
+ def->num_values = num_values;
+}
+
+/* Convert a byte string back to a definition. */
+/* The caller must initialize *def, including allocating counts and values. */
+void
+hc_definition_from_bytes(hc_definition *def, const byte *dbytes)
+{ int v, i;
+ ushort counts[max_hc_length + 1];
+
+ /* Make a first pass to set the counts for each code length. */
+ memset(counts, 0, sizeof(counts[0]) * (def->num_counts + 1));
+ for ( i = 0, v = 0; v < def->num_values; i++ )
+ { int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+ counts[l] += n;
+ v += n;
+ }
+
+ /* Now fill in the definition. */
+ memcpy(def->counts, counts, sizeof(counts[0]) * (def->num_counts + 1));
+ for ( i = 1, v = 0; i <= def->num_counts; i++ )
+ { uint prev = counts[i];
+ counts[i] = v;
+ v += prev;
+ }
+ for ( i = 0, v = 0; v < def->num_values; i++ )
+ { int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+ int j;
+ for ( j = 0; j < n; n++ )
+ def->values[counts[l]++] = v++;
+ }
+}
+
+/* ------ Definition -> table procedures ------ */
+
+/* Generate the encoding table from the definition. */
+/* The size of the encode array is def->num_values. */
+void
+hc_make_encoding(hce_code *encode, const hc_definition *def)
+{ uint next = 0;
+ const ushort *pvalue = def->values;
+ uint i, k;
+
+ for ( i = 1; i <= def->num_counts; i++ )
+ { for ( k = 0; k < def->counts[i]; k++, pvalue++, next++ )
+ { hce_code *pce = encode + *pvalue;
+ pce->code = next;
+ pce->code_length = i;
+ }
+ next <<= 1;
+ }
+}
+
+/* We decode in two steps, first indexing into a table with */
+/* a fixed number of bits from the source, and then indexing into */
+/* an auxiliary table if necessary. (See shc.h for details.) */
+
+/* Calculate the size of the decoding table. */
+uint
+hc_sizeof_decoding(const hc_definition *def, int initial_bits)
+{ uint size = 1 << initial_bits;
+ uint carry = 0, mask = (uint)~1;
+ uint i;
+
+ for ( i = initial_bits + 1; i <= def->num_counts;
+ i++, carry <<= 1, mask <<= 1
+ )
+ { carry += def->counts[i];
+ size += carry & mask;
+ carry &= ~mask;
+ }
+ return size;
+}
+
+/* Generate the decoding tables. */
+void
+hc_make_decoding(hcd_code *decode, const hc_definition *def,
+ int initial_bits)
+{ /* Make entries for single-dispatch codes. */
+ { hcd_code *pcd = decode;
+ const ushort *pvalue = def->values;
+ uint i, k, d;
+
+ for ( i = 0; i <= initial_bits; i++ )
+ { for ( k = 0; k < def->counts[i]; k++, pvalue++ )
+ { for ( d = 1 << (initial_bits - i); d > 0;
+ d--, pcd++
+ )
+ pcd->value = *pvalue,
+ pcd->code_length = i;
+ }
+ }
+ }
+ /* Make entries for two-dispatch codes. */
+ /* By working backward, we can do this more easily */
+ /* in a single pass. */
+ { uint dsize = hc_sizeof_decoding(def, initial_bits);
+ hcd_code *pcd = decode + (1 << initial_bits);
+ hcd_code *pcd2 = decode + dsize;
+ const ushort *pvalue = def->values + def->num_values;
+ uint entries_left = 0, slots_left = 0, mult_shift = 0;
+ uint i = def->num_counts + 1, j;
+
+ for ( ; ; )
+ { if ( slots_left == 0 )
+ { if ( entries_left != 0 )
+ { slots_left = 1 << (i - initial_bits);
+ mult_shift = 0;
+ continue;
+ }
+ if ( --i <= initial_bits )
+ break;
+ entries_left = def->counts[i];
+ continue;
+ }
+ if ( entries_left == 0 )
+ { entries_left = def->counts[--i];
+ mult_shift++;
+ continue;
+ }
+ --entries_left, --pvalue;
+ for ( j = 1 << mult_shift; j > 0; j-- )
+ { --pcd2;
+ pcd2->value = *pvalue;
+ pcd2->code_length = i - initial_bits;
+ }
+ if ( (slots_left -= 1 << mult_shift) == 0 )
+ { --pcd;
+ pcd->value = pcd2 - decode;
+ pcd->code_length = i + mult_shift;
+ }
+ }
+ }
+}
diff --git a/gs/src/shcgen.h b/gs/src/shcgen.h
new file mode 100644
index 000000000..b41e9da7f
--- /dev/null
+++ b/gs/src/shcgen.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* shcgen.h */
+/* Interface to shcgen.c */
+/* Requires shc.h */
+
+/* Compute an optimal Huffman code from an input data set. */
+/* The client must have set all the elements of *def. */
+/* The definition is guaranteed to be well-behaved. */
+int hc_compute(P3(hc_definition *def, const long *freqs, gs_memory_t *mem));
+
+/* Convert a definition to a byte string. */
+/* The caller must provide the byte string, of length def->num_values. */
+/* Assume (do not check) that the definition is well-behaved. */
+/* Return the actual length of the string. */
+int hc_bytes_from_definition(P2(byte *dbytes, const hc_definition *def));
+
+/* Extract num_counts and num_values from a byte string. */
+void hc_sizes_from_bytes(P3(hc_definition *def, const byte *dbytes, int num_bytes));
+
+/* Convert a byte string back to a definition. */
+/* The caller must initialize *def, including allocating counts and values. */
+void hc_definition_from_bytes(P2(hc_definition *def, const byte *dbytes));
+
+/* Generate the encoding table from the definition. */
+/* The size of the encode array is def->num_values. */
+void hc_make_encoding(P2(hce_code *encode, const hc_definition *def));
+
+/* Calculate the size of the decoding table. */
+uint hc_sizeof_decoding(P2(const hc_definition *def, int initial_bits));
+
+/* Generate the decoding tables. */
+void hc_make_decoding(P3(hcd_code *decode, const hc_definition *def,
+ int initial_bits));
diff --git a/gs/src/siscale.c b/gs/src/siscale.c
new file mode 100644
index 000000000..e258e52c4
--- /dev/null
+++ b/gs/src/siscale.c
@@ -0,0 +1,483 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* siscale.c */
+/* Image scaling filters */
+#include "math_.h"
+#include "memory_.h"
+#include "stdio_.h"
+#include <assert.h>
+#include "strimpl.h"
+#include "siscale.h"
+
+/*
+ * Image scaling code is based on public domain code from
+ * Graphics Gems III (pp. 414-424), Academic Press, 1992.
+ */
+
+/* ---------------- ImageScaleEncode/Decode ---------------- */
+
+public_st_IScale_state(); /* public so clients can allocate */
+
+/* ------ Digital filter definition ------ */
+
+/* Mitchell filter definition */
+#define Mitchell_support 2.0
+#define B (1.0 / 3.0)
+#define C (1.0 / 3.0)
+private double
+Mitchell_filter(double t)
+{ double t2 = t * t;
+
+ if ( t < 0 )
+ t = -t;
+
+ if ( t < 1 )
+ return
+ ((12 - 9 * B - 6 * C) * (t * t2) +
+ (-18 + 12 * B + 6 * C) * t2 +
+ (6 - 2 * B)) / 6;
+ else if ( t < 2 )
+ return
+ ((-1 * B - 6 * C) * (t * t2) +
+ (6 * B + 30 * C) * t2 +
+ (-12 * B - 48 * C) * t +
+ (8 * B + 24 * C)) / 6;
+ else
+ return 0;
+}
+
+#define filter_support Mitchell_support
+#define filter_proc Mitchell_filter
+#define fproc(t) filter_proc(t)
+#define fWidthIn filter_support
+
+/*
+ * The environment provides the following definitions:
+ * typedef PixelTmp, PixelTmp2
+ * double fproc(double t)
+ * double fWidthIn
+ * PixelTmp {min,max,unit}PixelTmp
+ */
+#define CLAMP(v, mn, mx)\
+ (v < mn ? mn : v > mx ? mx : v)
+
+/* ------ Auxiliary procedures ------ */
+
+/* Define the minimum scale. */
+#define min_scale ((fWidthIn * 2) / (max_support - 1.01))
+
+/* Calculate the support for a given scale. */
+/* The value is always in the range 1 .. max_support. */
+private int
+contrib_pixels(double scale)
+{ return (int)(fWidthIn / (scale >= 1.0 ? 1.0 : max(scale, min_scale))
+ * 2 + 1);
+}
+
+/* Pre-calculate filter contributions for a row or a column. */
+/* Return the highest input pixel index used. */
+private int
+calculate_contrib(
+ /* Return weight list parameters in contrib[0 .. size-1]. */
+ CLIST *contrib,
+ /* Store weights in items[0 .. contrib_pixels(scale)*size-1]. */
+ /* (Less space than this may actually be needed.) */
+ CONTRIB *items,
+ /* The output image is scaled by 'scale' relative to the input. */
+ double scale,
+ /* Start generating weights for input pixel 'input_index'. */
+ int input_index,
+ /* Generate 'size' weight lists. */
+ int size,
+ /* Limit pixel indices to 'limit', for clamping at the edges */
+ /* of the image. */
+ int limit,
+ /* Wrap pixel indices modulo 'modulus'. */
+ int modulus,
+ /* Successive pixel values are 'stride' distance apart -- */
+ /* normally, the number of color components. */
+ int stride,
+ /* The unit of output is 'rescale_factor' times the unit of input. */
+ double rescale_factor
+ )
+{
+ double scaled_factor = scale_PixelWeight(rescale_factor);
+ double WidthIn, fscale;
+ bool squeeze;
+ int npixels;
+ int i, j;
+ int last_index = -1;
+
+ if ( scale < 1.0 )
+ { double clamped_scale = max(scale, min_scale);
+ WidthIn = fWidthIn / clamped_scale;
+ fscale = 1.0 / clamped_scale;
+ squeeze = true;
+ }
+ else
+ { WidthIn = fWidthIn;
+ fscale = 1.0;
+ squeeze = false;
+ }
+ npixels = (int)(WidthIn * 2 + 1);
+
+ for ( i = 0; i < size; ++i )
+ { double center = (input_index + i) / scale;
+ int left = (int)ceil(center - WidthIn);
+ int right = (int)floor(center + WidthIn);
+#define clamp_pixel(j)\
+ (j < 0 ? -j : j >= limit ? (limit - j) + limit - 1 : j)
+ int lmin = (left < 0 ? 0 : left);
+ int lmax = (left < 0 ? -left : left);
+ int rmin =
+ (right >= limit ? (limit - right) + limit - 1 : right);
+ int rmax = (right >= limit ? limit - 1 : right);
+ int first_pixel = min(lmin, rmin);
+ int last_pixel = max(lmax, rmax);
+ CONTRIB *p;
+
+ if ( last_pixel > last_index )
+ last_index = last_pixel;
+ contrib[i].first_pixel = (first_pixel % modulus) * stride;
+ contrib[i].n = last_pixel - first_pixel + 1;
+ contrib[i].index = i * npixels;
+ p = items + contrib[i].index;
+ for ( j = 0; j < npixels; ++j )
+ p[j].weight = 0;
+ if ( squeeze )
+ { for ( j = left; j <= right; ++j )
+ { double weight =
+ fproc((center - j) / fscale) / fscale;
+ int n = clamp_pixel(j);
+ int k = n - first_pixel;
+ p[k].weight +=
+ (PixelWeight)(weight * scaled_factor);
+ }
+ }
+ else
+ { for ( j = left; j <= right; ++j )
+ { double weight = fproc(center - j);
+ int n = clamp_pixel(j);
+ int k = n - first_pixel;
+ p[k].weight +=
+ (PixelWeight)(weight * scaled_factor);
+ }
+ }
+ }
+ return last_index;
+}
+
+
+/* Apply filter to zoom horizontally from src to tmp. */
+private void
+zoom_x(PixelTmp *tmp, const void /*PixelIn*/ *src, int sizeofPixelIn,
+ int tmp_width, int WidthIn, int Colors, const CLIST *contrib,
+ const CONTRIB *items)
+{ int c, i;
+ for ( c = 0; c < Colors; ++c )
+ { PixelTmp *tp = tmp + c;
+ const CLIST *clp = contrib;
+#define zoom_x_loop(PixelIn, PixelIn2)\
+ const PixelIn *raster = (const PixelIn *)src + c;\
+ for ( i = 0; i < tmp_width; tp += Colors, ++clp, ++i )\
+ { AccumTmp weight = 0;\
+ { int j = clp->n;\
+ const PixelIn *pp = raster + clp->first_pixel;\
+ const CONTRIB *cp = items + clp->index;\
+ switch ( Colors )\
+ {\
+ case 1:\
+ for ( ; j > 0; pp += 1, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ break;\
+ case 3:\
+ for ( ; j > 0; pp += 3, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ break;\
+ default:\
+ for ( ; j > 0; pp += Colors, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ }\
+ }\
+ { PixelIn2 pixel = unscale_AccumTmp(weight);\
+ *tp =\
+ (PixelTmp)CLAMP(pixel, minPixelTmp, maxPixelTmp);\
+ }\
+ }
+
+ if ( sizeofPixelIn == 1 )
+ { zoom_x_loop(byte, int)
+ }
+ else /* sizeofPixelIn == 2 */
+ {
+#if arch_ints_are_short
+ zoom_x_loop(bits16, long)
+#else
+ zoom_x_loop(bits16, int)
+#endif
+ }
+ }
+}
+
+/* Apply filter to zoom vertically from tmp to dst. */
+/* This is simpler because we can treat all columns identically */
+/* without regard to the number of samples per pixel. */
+private void
+zoom_y(void /*PixelOut*/ *dst, int sizeofPixelOut, uint MaxValueOut,
+ const PixelTmp *tmp, int WidthOut, int tmp_width,
+ int Colors, const CLIST *contrib, const CONTRIB *items)
+{ int kn = WidthOut * Colors;
+ int cn = contrib->n;
+ int first_pixel = contrib->first_pixel;
+ const CONTRIB *cbp = items + contrib->index;
+ int kc;
+ PixelTmp2 max_weight = MaxValueOut;
+
+#define zoom_y_loop(PixelOut)\
+ for ( kc = 0; kc < kn; ++kc )\
+ { AccumTmp weight = 0;\
+ { const PixelTmp *pp = &tmp[kc + first_pixel];\
+ int j = cn;\
+ const CONTRIB *cp = cbp;\
+ for ( ; j > 0; pp += kn, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ }\
+ { PixelTmp2 pixel = unscale_AccumTmp(weight);\
+ ((PixelOut *)dst)[kc] =\
+ (PixelOut)CLAMP(pixel, 0, max_weight);\
+ }\
+ }
+
+ if ( sizeofPixelOut == 1 )
+ { zoom_y_loop(byte)
+ }
+ else /* sizeofPixelOut == 2 */
+ { zoom_y_loop(bits16)
+ }
+}
+
+/* ------ Stream implementation ------ */
+
+#define tmp_width WidthOut
+#define tmp_height HeightIn
+
+/* Forward references */
+private void s_IScale_release(P1(stream_state *st));
+
+/* Calculate the weights for an output row. */
+private void
+calculate_dst_contrib(stream_IScale_state *ss, int y)
+{ uint row_size = ss->WidthOut * ss->Colors;
+ int last_index =
+ calculate_contrib(&ss->dst_next_list, ss->dst_items, ss->yscale,
+ y, 1, ss->HeightIn, max_support, row_size,
+ (double)ss->MaxValueOut / unitPixelTmp);
+ int first_index_mod = ss->dst_next_list.first_pixel / row_size;
+
+ ss->dst_last_index = last_index;
+ last_index %= max_support;
+ if ( last_index < first_index_mod )
+ { /* Shuffle the indices to account for wraparound. */
+ CONTRIB shuffle[max_support];
+ int i;
+
+ for ( i = 0; i < max_support; ++i )
+ shuffle[i].weight =
+ (i <= last_index ?
+ ss->dst_items[i + max_support - first_index_mod].weight :
+ i >= first_index_mod ?
+ ss->dst_items[i - first_index_mod].weight :
+ 0);
+ memcpy(ss->dst_items, shuffle, max_support * sizeof(CONTRIB));
+ ss->dst_next_list.n = max_support;
+ ss->dst_next_list.first_pixel = 0;
+ }
+}
+
+#define ss ((stream_IScale_state *)st)
+
+/* Initialize the filter. */
+private int
+s_IScale_init(stream_state *st)
+{ gs_memory_t *mem = ss->memory;
+
+ ss->sizeofPixelIn = ss->BitsPerComponentIn / 8;
+ ss->sizeofPixelOut = ss->BitsPerComponentOut / 8;
+ ss->xscale = (double)ss->WidthOut / (double)ss->WidthIn;
+ ss->yscale = (double)ss->HeightOut / (double)ss->HeightIn;
+
+ ss->src_y = 0;
+ ss->src_size = ss->WidthIn * ss->sizeofPixelIn * ss->Colors;
+ ss->src_offset = 0;
+ ss->dst_y = 0;
+ ss->dst_size = ss->WidthOut * ss->sizeofPixelOut * ss->Colors;
+ ss->dst_offset = 0;
+
+ /* create intermediate image to hold horizontal zoom */
+ ss->tmp = (PixelTmp *)gs_alloc_byte_array(mem,
+ min(ss->tmp_height, max_support),
+ ss->tmp_width * ss->Colors * sizeof(PixelTmp),
+ "image_scale tmp");
+ ss->contrib = (CLIST *)gs_alloc_byte_array(mem,
+ max(ss->WidthOut, ss->HeightOut),
+ sizeof(CLIST), "image_scale contrib");
+ ss->items = (CONTRIB *)gs_alloc_byte_array(mem,
+ contrib_pixels(ss->xscale) * ss->WidthOut,
+ sizeof(CONTRIB), "image_scale contrib[*]");
+ /* Allocate buffers for 1 row of source and destination. */
+ ss->dst = gs_alloc_byte_array(mem, ss->WidthOut * ss->Colors,
+ ss->sizeofPixelOut, "image_scale dst");
+ ss->src = gs_alloc_byte_array(mem, ss->WidthIn * ss->Colors,
+ ss->sizeofPixelIn, "image_scale src");
+ if ( ss->tmp == 0 || ss->contrib == 0 || ss->items == 0 ||
+ ss->dst == 0 || ss->src == 0
+ )
+ { s_IScale_release(st);
+ return ERRC; /****** WRONG ******/
+ }
+
+ /* Pre-calculate filter contributions for a row. */
+ calculate_contrib(ss->contrib, ss->items, ss->xscale,
+ 0, ss->WidthOut, ss->WidthIn, ss->WidthIn,
+ ss->Colors, (double)unitPixelTmp / ss->MaxValueIn);
+
+ /* Prepare the weights for the first output row. */
+ calculate_dst_contrib(ss, 0);
+
+ return 0;
+
+}
+
+/* Process a buffer. Note that this handles Encode and Decode identically. */
+private int
+s_IScale_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{
+ /* Check whether we need to deliver any output. */
+
+top: while ( ss->src_y > ss->dst_last_index )
+ { /* We have enough horizontally scaled temporary rows */
+ /* to generate a vertically scaled output row. */
+ uint wleft = pw->limit - pw->ptr;
+ if ( ss->dst_y == ss->HeightOut )
+ return EOFC;
+ if ( wleft == 0 )
+ return 1;
+ if ( ss->dst_offset == 0 )
+ { byte *row;
+ if ( wleft >= ss->dst_size )
+ { /* We can scale the row directly into the output. */
+ row = pw->ptr + 1;
+ pw->ptr += ss->dst_size;
+ }
+ else
+ { /* We'll have to buffer the row. */
+ row = ss->dst;
+ }
+ /* Apply filter to zoom vertically from tmp to dst. */
+ zoom_y(row, ss->sizeofPixelOut, ss->MaxValueOut, ss->tmp,
+ ss->WidthOut, ss->tmp_width, ss->Colors,
+ &ss->dst_next_list, ss->dst_items);
+ /* Idiotic C coercion rules allow T* and void* to be */
+ /* inter-assigned freely, but not compared! */
+ if ( (void *)row != ss->dst ) /* no buffering */
+ goto adv;
+ }
+ { /* We're delivering a buffered output row. */
+ uint wcount = ss->dst_size - ss->dst_offset;
+ uint ncopy = min(wleft, wcount);
+ memcpy(pw->ptr + 1, (byte *)ss->dst + ss->dst_offset, ncopy);
+ pw->ptr += ncopy;
+ ss->dst_offset += ncopy;
+ if ( ncopy != wcount )
+ return 1;
+ ss->dst_offset = 0;
+ }
+ /* Advance to the next output row. */
+adv: ++(ss->dst_y);
+ if ( ss->dst_y != ss->HeightOut )
+ calculate_dst_contrib(ss, ss->dst_y);
+ }
+
+ /* Read input data and scale horizontally into tmp. */
+
+#ifdef DEBUG
+ assert(ss->src_y < ss->HeightIn);
+#endif
+ { uint rleft = pr->limit - pr->ptr;
+ uint rcount = ss->src_size - ss->src_offset;
+ if ( rleft == 0 )
+ return 0; /* need more input */
+ if ( rleft >= rcount )
+ { /* We're going to fill up a row. */
+ const byte *row;
+ if ( ss->src_offset == 0 )
+ { /* We have a complete row. Read the data */
+ /* directly from the input. */
+ row = pr->ptr + 1;
+ }
+ else
+ { /* We're buffering a row in src. */
+ row = ss->src;
+ memcpy((byte *)ss->src + ss->src_offset, pr->ptr + 1,
+ rcount);
+ ss->src_offset = 0;
+ }
+ /* Apply filter to zoom horizontally from src to tmp. */
+ zoom_x(ss->tmp + (ss->src_y % max_support) *
+ ss->tmp_width * ss->Colors, row,
+ ss->sizeofPixelIn, ss->tmp_width, ss->WidthIn,
+ ss->Colors, ss->contrib, ss->items);
+ pr->ptr += rcount;
+ ++(ss->src_y);
+ goto top;
+ }
+ else
+ { /* We don't have a complete row. Copy data to src buffer. */
+ memcpy((byte *)ss->src + ss->src_offset, pr->ptr + 1, rleft);
+ ss->src_offset += rleft;
+ pr->ptr += rleft;
+ return 0;
+ }
+ }
+}
+
+/* Release the filter's storage. */
+private void
+s_IScale_release(stream_state *st)
+{ gs_memory_t *mem = ss->memory;
+ gs_free_object(mem, (void *)ss->src, "image_scale src"); /* no longer const */
+ ss->src = 0;
+ gs_free_object(mem, ss->dst, "image_scale dst");
+ ss->dst = 0;
+ gs_free_object(mem, ss->items, "image_scale contrib[*]");
+ ss->items = 0;
+ gs_free_object(mem, ss->contrib, "image_scale contrib");
+ ss->contrib = 0;
+ gs_free_object(mem, ss->tmp, "image_scale tmp");
+ ss->tmp = 0;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_IScale_template =
+{ &st_IScale_state, s_IScale_init, s_IScale_process, 1, 1,
+ s_IScale_release
+};
diff --git a/gs/src/siscale.h b/gs/src/siscale.h
new file mode 100644
index 000000000..616385c15
--- /dev/null
+++ b/gs/src/siscale.h
@@ -0,0 +1,131 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* siscale.h */
+/* Image scaling filter state definition */
+/* Requires strimpl.h */
+#include "gconfigv.h"
+
+/* Define whether to accumulate pixels in fixed or floating point. */
+#if USE_FPU <= 0
+
+ /* Accumulate pixels in fixed point. */
+
+typedef int PixelWeight;
+# if arch_ints_are_short
+typedef long AccumTmp;
+# else
+typedef int AccumTmp;
+# endif
+#define num_weight_bits\
+ ((sizeof(AccumTmp) - maxSizeofPixel) * 8 - (log2_max_support + 1))
+#define scale_PixelWeight(factor) ((int)((factor) * (1 << num_weight_bits)))
+#define unscale_AccumTmp(atemp) arith_rshift(atemp, num_weight_bits)
+
+#else /* USE_FPU > 0 */
+
+ /* Accumulate pixels in floating point. */
+
+typedef float PixelWeight;
+typedef double AccumTmp;
+#define scale_PixelWeight(factor) (factor)
+#define unscale_AccumTmp(atemp) ((int)(atemp))
+
+#endif /* USE_FPU */
+
+/* Input values */
+/*typedef byte PixelIn;*/ /* see sizeofPixelIn below */
+/*#define MaxValueIn 255*/ /* see MaxValueIn below */
+
+/* Temporary intermediate values */
+typedef byte PixelTmp;
+typedef int PixelTmp2; /* extra width for clamping sum */
+#define minPixelTmp 0
+#define maxPixelTmp 255
+#define unitPixelTmp 255
+
+/* Max of all pixel sizes */
+#define maxSizeofPixel 2
+
+/* Output values */
+/*typedef byte PixelOut;*/ /* see sizeofPixelOut below */
+/*#define MaxValueOut 255*/ /* see MaxValueOut below */
+
+/*
+ * The 'support' S of the digital filter is the value such that the filter
+ * is guaranteed to be zero for all arguments outside the range [-S..S].
+ * We artificially limit the support so that we can put an upper bound
+ * on the time required to compute an output value and on the amount of
+ * storage required for the X-filtered input data; this also allows us
+ * to use pre-scaled fixed-point values for the weights if we wish.
+ *
+ * 8x8 pixels should be enough for any reasonable application....
+ */
+#define log2_max_support 3
+#define max_support (1 << log2_max_support)
+
+/* Auxiliary structures. */
+
+typedef struct {
+ PixelWeight weight; /* float or scaled fraction */
+} CONTRIB;
+
+typedef struct {
+ int index; /* index of first element in list of */
+ /* contributors */
+ int n; /* number of contributors */
+ /* (not multiplied by stride) */
+ int first_pixel; /* offset of first value in source data */
+} CLIST;
+
+/* ImageScaleEncode / ImageScaleDecode */
+typedef struct stream_IScale_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* any number >= 1 */
+ int BitsPerComponentIn; /* bits per input value, 8 or 16 */
+ uint MaxValueIn; /* max value of input component */
+ int WidthIn, HeightIn;
+ int BitsPerComponentOut; /* bits per output value, 8 or 16 */
+ uint MaxValueOut; /* max value of output component */
+ int WidthOut, HeightOut;
+ /* The init procedure sets the following. */
+ int sizeofPixelIn; /* bytes per input value, 1 or 2 */
+ int sizeofPixelOut; /* bytes per output value, 1 or 2 */
+ double xscale, yscale;
+ void /*PixelIn*/ *src;
+ void /*PixelOut*/ *dst;
+ PixelTmp *tmp;
+ CLIST *contrib;
+ CONTRIB *items;
+ /* The following are updated dynamically. */
+ int src_y;
+ uint src_offset, src_size;
+ int dst_y;
+ uint dst_offset, dst_size;
+ CLIST dst_next_list; /* for next output value */
+ int dst_last_index; /* highest index used in list */
+ CONTRIB dst_items[max_support]; /* ditto */
+} stream_IScale_state;
+extern_st(st_IScale_state); /* so clients can allocate */
+#define public_st_IScale_state() /* in siscale.c */\
+ gs_public_st_ptrs5(st_IScale_state, stream_IScale_state,\
+ "ImageScaleEncode/Decode state",\
+ iscale_state_enum_ptrs, iscale_state_reloc_ptrs,\
+ dst, src, tmp, contrib, items)
+extern const stream_template s_IScale_template;
diff --git a/gs/src/sjpeg.h b/gs/src/sjpeg.h
new file mode 100644
index 000000000..6f574fc1d
--- /dev/null
+++ b/gs/src/sjpeg.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sjpeg.h */
+/* Definitions for Ghostscript's IJG library interface routines */
+/* Requires sdct.h, jpeg/jpeglib.h */
+
+/*
+ * Each routine gs_jpeg_xxx is equivalent to the IJG entry point jpeg_xxx,
+ * except that
+ * (a) it takes a pointer to stream_DCT_state instead of just the IJG
+ * jpeg_(de)compress_data struct;
+ * (b) it catches any error exit from the IJG code and converts it into
+ * an error return value per Ghostscript custom. A negative return
+ * value is an error code, except for gs_jpeg_alloc_xxx which return
+ * NULL (indicating e_VMerror).
+ */
+
+/* Common to encode/decode */
+
+void gs_jpeg_error_setup (P1(stream_DCT_state *st));
+int gs_jpeg_log_error (P1(stream_DCT_state *st));
+JQUANT_TBL * gs_jpeg_alloc_quant_table (P1(stream_DCT_state *st));
+JHUFF_TBL * gs_jpeg_alloc_huff_table (P1(stream_DCT_state *st));
+int gs_jpeg_destroy (P1(stream_DCT_state *st));
+
+/* Encode */
+
+int gs_jpeg_create_compress (P1(stream_DCT_state *st));
+int gs_jpeg_set_defaults (P1(stream_DCT_state *st));
+int gs_jpeg_set_colorspace (P2(stream_DCT_state *st,
+ J_COLOR_SPACE colorspace));
+int gs_jpeg_set_linear_quality (P3(stream_DCT_state *st,
+ int scale_factor,
+ boolean force_baseline));
+int gs_jpeg_set_quality (P3(stream_DCT_state *st,
+ int quality,
+ boolean force_baseline));
+int gs_jpeg_start_compress (P2(stream_DCT_state *st,
+ boolean write_all_tables));
+int gs_jpeg_write_scanlines (P3(stream_DCT_state *st,
+ JSAMPARRAY scanlines,
+ int num_lines));
+int gs_jpeg_finish_compress (P1(stream_DCT_state *st));
+
+/* Decode */
+
+int gs_jpeg_create_decompress (P1(stream_DCT_state *st));
+int gs_jpeg_read_header (P2(stream_DCT_state *st,
+ boolean require_image));
+int gs_jpeg_start_decompress (P1(stream_DCT_state *st));
+int gs_jpeg_read_scanlines (P3(stream_DCT_state *st,
+ JSAMPARRAY scanlines,
+ int max_lines));
+int gs_jpeg_finish_decompress (P1(stream_DCT_state *st));
diff --git a/gs/src/sjpegc.c b/gs/src/sjpegc.c
new file mode 100644
index 000000000..f46613455
--- /dev/null
+++ b/gs/src/sjpegc.c
@@ -0,0 +1,264 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sjpegc.c */
+/* Interface routines for IJG code, common to encode/decode. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* gs_jpeg_message_table() is kept in a separate file for arcane reasons.
+ * See sjpegerr.c.
+ */
+const char * const * gs_jpeg_message_table (P1(void));
+
+/*
+ * Error handling routines (these replace corresponding IJG routines from
+ * jpeg/jerror.c). These are used for both compression and decompression.
+ * We assume
+ * offset_of(jpeg_compress_data, cinfo)==offset_of(jpeg_decompress_data, dinfo)
+ */
+
+private void
+gs_jpeg_error_exit (j_common_ptr cinfo)
+{ jpeg_stream_data *jcomdp =
+ (jpeg_stream_data *)((char *)cinfo -
+ offset_of(jpeg_compress_data, cinfo));
+ longjmp(jcomdp->exit_jmpbuf, 1);
+}
+
+private void
+gs_jpeg_emit_message (j_common_ptr cinfo, int msg_level)
+{ if ( msg_level < 0 )
+ { /* GS policy is to ignore IJG warnings when Picky=0,
+ * treat them as errors when Picky=1.
+ */
+ jpeg_stream_data *jcomdp =
+ (jpeg_stream_data *)((char *)cinfo -
+ offset_of(jpeg_compress_data, cinfo));
+ if ( jcomdp->Picky )
+ gs_jpeg_error_exit(cinfo);
+ }
+ /* Trace messages are always ignored. */
+}
+
+/*
+ * This is an exact copy of format_message from jpeg/jerror.c.
+ * We do not use jerror.c in Ghostscript, so we have to duplicate this routine.
+ */
+
+private void
+gs_jpeg_format_message (j_common_ptr cinfo, char * buffer)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+ int msg_code = err->msg_code;
+ const char * msgtext = NULL;
+ const char * msgptr;
+ char ch;
+ boolean isstring;
+
+ /* Look up message string in proper table */
+ if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+ msgtext = err->jpeg_message_table[msg_code];
+ } else if (err->addon_message_table != NULL &&
+ msg_code >= err->first_addon_message &&
+ msg_code <= err->last_addon_message) {
+ msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+ }
+
+ /* Defend against bogus message number */
+ if (msgtext == NULL) {
+ err->msg_parm.i[0] = msg_code;
+ msgtext = err->jpeg_message_table[0];
+ }
+
+ /* Check for string parameter, as indicated by %s in the message text */
+ isstring = FALSE;
+ msgptr = msgtext;
+ while ((ch = *msgptr++) != '\0') {
+ if (ch == '%') {
+ if (*msgptr == 's') isstring = TRUE;
+ break;
+ }
+ }
+
+ /* Format the message into the passed buffer */
+ if (isstring)
+ sprintf(buffer, msgtext, err->msg_parm.s);
+ else
+ sprintf(buffer, msgtext,
+ err->msg_parm.i[0], err->msg_parm.i[1],
+ err->msg_parm.i[2], err->msg_parm.i[3],
+ err->msg_parm.i[4], err->msg_parm.i[5],
+ err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+/* And this is an exact copy of another routine from jpeg/jerror.c. */
+
+private void
+gs_jpeg_reset_error_mgr (j_common_ptr cinfo)
+{
+ cinfo->err->num_warnings = 0;
+ /* trace_level is not reset since it is an application-supplied parameter */
+ cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
+}
+
+/*
+ * This routine initializes the error manager fields in the JPEG object.
+ * It is based on jpeg_std_error from jpeg/jerror.c.
+ */
+
+void
+gs_jpeg_error_setup (stream_DCT_state *st)
+{
+ struct jpeg_error_mgr * err = &st->data.common->err;
+
+ err->error_exit = gs_jpeg_error_exit;
+ err->emit_message = gs_jpeg_emit_message;
+ /* We need not set the output_message field since gs_jpeg_emit_message
+ * doesn't call it, and the IJG library never calls output_message directly.
+ * Setting the format_message field isn't strictly necessary either,
+ * since gs_jpeg_log_error calls gs_jpeg_format_message directly.
+ */
+ err->format_message = gs_jpeg_format_message;
+ err->reset_error_mgr = gs_jpeg_reset_error_mgr;
+
+ err->trace_level = 0; /* default = no tracing */
+ err->num_warnings = 0; /* no warnings emitted yet */
+ err->msg_code = 0; /* may be useful as a flag for "no error" */
+
+ /* Initialize message table pointers */
+ err->jpeg_message_table = gs_jpeg_message_table();
+ err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
+
+ err->addon_message_table = NULL;
+ err->first_addon_message = 0; /* for safety */
+ err->last_addon_message = 0;
+
+ st->data.compress->cinfo.err = err; /* works for decompress case too */
+}
+
+/* Stuff the IJG error message into errorinfo after an error exit. */
+
+int
+gs_jpeg_log_error (stream_DCT_state *st)
+{ j_common_ptr cinfo = (j_common_ptr) &st->data.compress->cinfo;
+ char buffer[JMSG_LENGTH_MAX];
+ /* Format the error message */
+ gs_jpeg_format_message(cinfo, buffer);
+ (*st->report_error)((stream_state *)st, buffer);
+ return gs_error_ioerror; /* caller will do return_error() */
+}
+
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+
+JQUANT_TBL *
+gs_jpeg_alloc_quant_table (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ { gs_jpeg_log_error(st);
+ return NULL;
+ }
+ return jpeg_alloc_quant_table((j_common_ptr)
+ &st->data.compress->cinfo);
+}
+
+JHUFF_TBL *
+gs_jpeg_alloc_huff_table (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ { gs_jpeg_log_error(st);
+ return NULL;
+ }
+ return jpeg_alloc_huff_table((j_common_ptr)
+ &st->data.compress->cinfo);
+}
+
+int
+gs_jpeg_destroy (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_destroy((j_common_ptr) &st->data.compress->cinfo);
+ return 0;
+}
+
+
+/*
+ * These routines replace the low-level memory manager of the IJG library.
+ * They pass malloc/free calls to the Ghostscript memory manager.
+ * Note we do not need these to be declared in any GS header file.
+ */
+
+void *
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return gs_malloc(1, sizeofobject, "JPEG small internal data allocation");
+}
+
+void
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ gs_free(object, 1, sizeofobject, "Freeing JPEG small internal data");
+}
+
+void FAR *
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return gs_malloc(1, sizeofobject, "JPEG large internal data allocation");
+}
+
+void
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ gs_free(object, 1, sizeofobject, "Freeing JPEG large internal data");
+}
+
+long
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return max_bytes_needed;
+}
+
+void
+jpeg_open_backing_store (j_common_ptr cinfo, void * info,
+ long total_bytes_needed)
+{
+ ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+long
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return 0; /* just set max_memory_to_use to 0 */
+}
+
+void
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/gs/src/sjpegd.c b/gs/src/sjpegd.c
new file mode 100644
index 000000000..b9e41c162
--- /dev/null
+++ b/gs/src/sjpegd.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sjpegd.c */
+/* Interface routines for IJG decoding code. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+int
+gs_jpeg_create_decompress (stream_DCT_state *st)
+{ /* Initialize error handling */
+ gs_jpeg_error_setup(st);
+ /* Establish the setjmp return context for gs_jpeg_error_exit to use. */
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+
+ jpeg_create_decompress(&st->data.decompress->dinfo);
+ return 0;
+}
+
+int
+gs_jpeg_read_header (stream_DCT_state *st,
+ boolean require_image)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return jpeg_read_header(&st->data.decompress->dinfo, require_image);
+}
+
+int
+gs_jpeg_start_decompress (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+#if JPEG_LIB_VERSION > 55
+ return (int) jpeg_start_decompress(&st->data.decompress->dinfo);
+#else
+ /* in IJG version 5, jpeg_start_decompress had no return value */
+ jpeg_start_decompress(&st->data.decompress->dinfo);
+ return 1;
+#endif
+}
+
+int
+gs_jpeg_read_scanlines (stream_DCT_state *st,
+ JSAMPARRAY scanlines,
+ int max_lines)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int) jpeg_read_scanlines(&st->data.decompress->dinfo,
+ scanlines, (JDIMENSION) max_lines);
+}
+
+int
+gs_jpeg_finish_decompress (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int) jpeg_finish_decompress(&st->data.decompress->dinfo);
+}
diff --git a/gs/src/sjpege.c b/gs/src/sjpege.c
new file mode 100644
index 000000000..6f1cfa714
--- /dev/null
+++ b/gs/src/sjpege.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sjpege.c */
+/* Interface routines for IJG encoding code. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+int
+gs_jpeg_create_compress (stream_DCT_state *st)
+{ /* Initialize error handling */
+ gs_jpeg_error_setup(st);
+ /* Establish the setjmp return context for gs_jpeg_error_exit to use. */
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+
+ jpeg_create_compress(&st->data.compress->cinfo);
+ return 0;
+}
+
+int
+gs_jpeg_set_defaults (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_defaults(&st->data.compress->cinfo);
+ return 0;
+}
+
+int
+gs_jpeg_set_colorspace (stream_DCT_state *st,
+ J_COLOR_SPACE colorspace)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_colorspace(&st->data.compress->cinfo, colorspace);
+ return 0;
+}
+
+int
+gs_jpeg_set_linear_quality (stream_DCT_state *st,
+ int scale_factor, boolean force_baseline)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_linear_quality(&st->data.compress->cinfo,
+ scale_factor, force_baseline);
+ return 0;
+}
+
+int
+gs_jpeg_set_quality (stream_DCT_state *st,
+ int quality, boolean force_baseline)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_quality(&st->data.compress->cinfo,
+ quality, force_baseline);
+ return 0;
+}
+
+int
+gs_jpeg_start_compress (stream_DCT_state *st,
+ boolean write_all_tables)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_start_compress(&st->data.compress->cinfo, write_all_tables);
+ return 0;
+}
+
+int
+gs_jpeg_write_scanlines (stream_DCT_state *st,
+ JSAMPARRAY scanlines,
+ int num_lines)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int) jpeg_write_scanlines(&st->data.compress->cinfo,
+ scanlines, (JDIMENSION) num_lines);
+}
+
+int
+gs_jpeg_finish_compress (stream_DCT_state *st)
+{ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_finish_compress(&st->data.compress->cinfo);
+ return 0;
+}
diff --git a/gs/src/sjpegerr.c b/gs/src/sjpegerr.c
new file mode 100644
index 000000000..023a3e193
--- /dev/null
+++ b/gs/src/sjpegerr.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sjpegerr.c */
+/* IJG error message table for Ghostscript. */
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "jversion.h"
+
+/*
+ * This file exists solely to hold the rather large IJG error message string
+ * table (now about 4K, and likely to grow in future releases). The table
+ * is large enough that we don't want it to be in the default data segment
+ * in a 16-bit executable.
+ *
+ * In IJG version 5 and earlier, under Borland C, this is accomplished simply
+ * by compiling this one file in "huge" memory model rather than "large".
+ * The string constants will then go into a private far data segment.
+ * In less brain-damaged architectures, this file is simply compiled normally,
+ * and we pay only the price of one extra function call.
+ *
+ * In IJG version 5a and later, under Borland C, this is accomplished by making
+ * each string be a separate variable that's explicitly declared "far".
+ * (What a crock...)
+ *
+ * This must be a separate file to avoid duplicate-symbol errors, since we
+ * use the IJG message code names as variables rather than as enum constants.
+ */
+
+#if JPEG_LIB_VERSION <= 50 /**************** ****************/
+
+#include "jerror.h" /* get error codes */
+#define JMAKE_MSG_TABLE
+#include "jerror.h" /* create message string table */
+
+#define jpeg_std_message_table jpeg_message_table
+
+#else /* JPEG_LIB_VERSION >= 51 */ /**************** ****************/
+
+/* Create a static const char[] variable for each message string. */
+
+#define JMESSAGE(code,string) static const char far_data code[] = string;
+
+#include "jerror.h"
+
+/* Now build an array of pointers to same. */
+
+#define JMESSAGE(code,string) code ,
+
+static const char far_data * const far_data jpeg_std_message_table[] = {
+#include "jerror.h"
+ NULL
+};
+
+#endif /* JPEG_LIB_VERSION */ /**************** ****************/
+
+/*
+ * Return a pointer to the message table.
+ * It is unsafe to do much more than this within the "huge" environment.
+ */
+
+const char * const *
+gs_jpeg_message_table (void)
+{ return jpeg_std_message_table;
+}
diff --git a/gs/src/slzwc.c b/gs/src/slzwc.c
new file mode 100644
index 000000000..2eb3ffb13
--- /dev/null
+++ b/gs/src/slzwc.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* slzwc.c */
+/* Code common to LZW encoding and decoding streams */
+#include "std.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* Define the structure for the GC. */
+public_st_LZW_state();
+
+#define ss ((stream_LZW_state *)st)
+
+/* Set defaults */
+void
+s_LZW_set_defaults(stream_state *st)
+{ s_LZW_set_defaults_inline(ss);
+}
+
+/* Release a LZW filter. */
+void
+s_LZW_release(stream_state *st)
+{ gs_free_object(st->memory, ss->table.decode, "LZW(close)");
+}
+
+#undef ss
diff --git a/gs/src/slzwce.c b/gs/src/slzwce.c
new file mode 100644
index 000000000..19ea872f6
--- /dev/null
+++ b/gs/src/slzwce.c
@@ -0,0 +1,155 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* slzwce.c */
+/* Simple encoder compatible with LZW decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* ------ Alternate LZWEncode filter implementation ------ */
+
+/*
+
+The encoded data stream produced by this implementation of the LZWEncode
+filter consists of a sequence of 9-bit data elements. These elements are
+packed into bytes in big-endian order, e.g. the elements
+
+ 100000000 001100001
+
+occurring at the very beginning of the data stream would be packed into
+bytes as
+
+ 10000000 00011000 01......
+
+The first bit of each data element is a control bit. If the control bit is
+0, the remaining 8 bits of the data element are a data byte. If the control
+bit is 1, the remaining 8 bits of the data element define a control
+function:
+
+ 1 00000000 synchronization mark, see below
+ 1 00000001 end of data
+ 1 xxxxxxxx not used (all other values)
+
+The synchronization mark occurs at the beginning of the data stream, and at
+least once every 254 data bytes thereafter.
+
+This format is derived from basic principles of data encoding (the use of a
+separate flag bit to distinguish out-of-band control information from data
+per se, and the use of a periodic synchronization mark to help verify the
+validity of a data stream); it has no relationship to data compression. It
+is, however, compatible with LZW decompressors. It produces output that is
+approximately 9/8 times the size of the input.
+
+*/
+
+/* Define the special codes, relative to 1 << InitialCodeLength. */
+#define code_reset 0
+#define code_eod 1
+#define code_0 2 /* first assignable code */
+
+/* Internal routine to put a code into the output buffer. */
+/* Let S = ss->code_size. */
+/* Relevant invariants: 9 <= S <= 15, 0 <= code < 1 << S; */
+/* 1 <= ss->bits_left <= 8; only the rightmost (8 - ss->bits_left) */
+/* bits of ss->bits contain valid data. */
+private byte *
+lzw_put_code(register stream_LZW_state *ss, byte *q, uint code)
+{ uint size = ss->code_size;
+ byte cb = (ss->bits << ss->bits_left) +
+ (code >> (size - ss->bits_left));
+ if_debug2('W', "[w]writing 0x%x,%d\n", code, ss->code_size);
+ *++q = cb;
+ if ( (ss->bits_left += 8 - size) <= 0 )
+ { *++q = code >> -ss->bits_left;
+ ss->bits_left += 8;
+ }
+ ss->bits = code;
+ return q;
+}
+
+#define ss ((stream_LZW_state *)st)
+
+/* Initialize LZW-compatible encoding filter. */
+int
+s_LZWE_reset(stream_state *st)
+{ ss->code_size = ss->InitialCodeLength + 1;
+ ss->bits_left = 8;
+ ss->next_code = (1 << ss->InitialCodeLength) + code_0;
+ return 0;
+}
+private int
+s_LZWE_init(stream_state *st)
+{ ss->InitialCodeLength = 8;
+ ss->table.encode = 0;
+ return s_LZWE_reset(st);
+}
+
+/* Process a buffer */
+private int
+s_LZWE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ int signal = 1 << (ss->code_size - 1);
+ uint limit_code = (1 << ss->code_size) - 1;
+ uint next_code = ss->next_code;
+
+ while ( p < rlimit )
+ { if ( next_code == limit_code )
+ { /* Emit a reset code. */
+ if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ q = lzw_put_code(ss, q, signal + code_reset);
+ next_code = signal + code_0;
+ }
+ if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ q = lzw_put_code(ss, q, *++p);
+ next_code++;
+ }
+ if ( last && status == 0 )
+ { if ( wlimit - q < 2 )
+ status = 1;
+ else
+ { q = lzw_put_code(ss, q, signal + code_eod);
+ if ( ss->bits_left < 8 )
+ *++q = ss->bits << ss->bits_left; /* final byte */
+ }
+ }
+ ss->next_code = next_code;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_LZWE_template =
+{ &st_LZW_state, s_LZWE_init, s_LZWE_process, 1, 2, NULL,
+ s_LZW_set_defaults, s_LZWE_reset
+};
diff --git a/gs/src/slzwd.c b/gs/src/slzwd.c
new file mode 100644
index 000000000..f5e64584d
--- /dev/null
+++ b/gs/src/slzwd.c
@@ -0,0 +1,368 @@
+/* Copyright (C) 1993, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* slzwd.c */
+/* LZW decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* ------ LZWDecode ------ */
+
+/********************************************************/
+/* LZW routines are based on: */
+/* Dr. Dobbs Journal --- Oct. 1989. */
+/* Article on LZW Data Compression by Mark R. Nelson */
+/********************************************************/
+
+/* Define the special codes in terms of code_escape, which is */
+/* 1 << InitialCodeLength. */
+#define code_reset (code_escape + 0)
+#define code_eod (code_escape + 1)
+#define code_0 (code_escape + 2) /* first assignable code */
+
+struct lzw_decode_s {
+ byte datum;
+ byte len; /* length of code */
+ ushort prefix; /* code to be prefixed */
+};
+gs_private_st_simple(st_lzw_decode, lzw_decode, "lzw_decode");
+/* We can use a simple type as the element type, */
+/* because there are no pointers to enumerate or relocate. */
+#define st_lzw_decode_element st_lzw_decode
+#define lzw_decode_max 4096 /* must be 4096 */
+
+#define ss ((stream_LZW_state *)st)
+
+/* Initialize LZWDecode filter */
+/* We separate out the reset function for some non-stream clients. */
+int
+s_LZWD_reset(stream_state *st)
+{ register lzw_decode *dc = ss->table.decode;
+ register int i;
+ uint code_escape = 1 << ss->InitialCodeLength;
+
+ ss->bits_left = 0;
+ ss->bytes_left = 0;
+ ss->next_code = code_0;
+ ss->code_size = ss->InitialCodeLength + 1;
+ ss->prev_code = -1;
+ ss->copy_code = -1;
+ dc[code_reset].len = 255;
+ dc[code_eod].len = 255;
+ for ( i = 0; i < code_escape; i++, dc++ )
+ dc->datum = i, dc->len = 1, dc->prefix = code_eod;
+ return 0;
+}
+private int
+s_LZWD_init(stream_state *st)
+{ lzw_decode *dc =
+ gs_alloc_struct_array(st->memory, lzw_decode_max + 1,
+ lzw_decode, &st_lzw_decode_element,
+ "LZWDecode(init)");
+
+ if ( dc == 0 )
+ return ERRC; /****** WRONG ******/
+ ss->table.decode = dc;
+ return s_LZWD_reset(st);
+}
+
+/* Process a buffer */
+private int
+s_LZWD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+#ifdef DEBUG
+ byte *q0 = q;
+#endif
+ const byte *rlimit = pr->limit; /* constant pointer */
+ byte *wlimit = pw->limit; /* constant pointer */
+ int status = 0;
+ int code = ss->copy_code;
+ int prev_code = ss->prev_code;
+ uint prev_len = ss->prev_len;
+ byte bits = ss->bits;
+ int bits_left = ss->bits_left;
+ int bytes_left = ss->bytes_left;
+ int code_size = ss->code_size;
+ int code_mask;
+ int switch_code;
+ int next_code = ss->next_code;
+ lzw_decode *table = ss->table.decode; /* constant pointer */
+ lzw_decode *dc_next = table + next_code; /* invariant */
+ lzw_decode *dc;
+ int code_escape = 1 << ss->InitialCodeLength;
+ int eod = code_eod;
+ bool low_order = ss->FirstBitLowOrder;
+ uint len;
+ int c;
+ byte b;
+ byte *q1;
+ if_debug2('w', "[w]process decode: code_size=%d next_code=%d\n",
+ code_size, next_code);
+#define set_code_size()\
+ code_mask = (1 << code_size) - 1,\
+ switch_code = code_mask + 1 - ss->EarlyChange
+ set_code_size();
+ if ( !ss->BlockData )
+ bytes_left = rlimit - p + 2; /* never stop for bytes_left */
+ /* If we are in the middle of copying a string, */
+ /* do some more now. */
+ if ( code >= 0 )
+ { int rlen = ss->copy_left;
+ int wlen = wlimit - q;
+ int n = len = min(rlen, wlen);
+ c = code;
+ ss->copy_left = rlen -= len;
+ if_debug3('W', "[W]copying 0x%x, %d byte(s) out of %d left\n",
+ code, len, rlen + len);
+ while ( rlen )
+ c = table[c].prefix,
+ rlen--;
+ q1 = q += len;
+ n = len;
+ while ( --n >= 0 )
+ { *q1-- = (dc = &table[c])->datum;
+ c = dc->prefix;
+ }
+ if ( ss->copy_left ) /* more to do */
+ { pw->ptr = q;
+ return 1;
+ }
+ ss->copy_code = -1;
+ len = ss->copy_len;
+ /* Retrieve the first byte of the code just copied. */
+ if ( c == eod )
+ { /* We just copied the entire code, */
+ /* so the byte we want is immediately available. */
+ b = q1[1];
+ }
+ else
+ { /* We have to scan to the beginning of the code. */
+ for ( ; c != eod; c = table[c].prefix )
+ b = (byte)c;
+ }
+ goto add;
+ }
+top: if ( code_size > bits_left )
+ { if ( bytes_left == 0 )
+ { if ( p == rlimit )
+ goto out;
+ bytes_left = *++p;
+ if_debug1('W', "[W]block count %d\n", bytes_left);
+ if ( bytes_left == 0 )
+ { status = EOFC;
+ goto out;
+ }
+ goto top;
+ }
+ if ( low_order )
+ code = bits >> (8 - bits_left);
+ else
+ code = (uint)bits << (code_size - bits_left);
+ if ( bits_left + 8 < code_size )
+ { /* Need 2 more data bytes */
+ if ( bytes_left == 1 )
+ { if ( rlimit - p < 3 )
+ goto out;
+ bytes_left = p[2];
+ if_debug1('W', "[W]block count %d\n",
+ bytes_left);
+ if ( bytes_left == 0 )
+ { status = EOFC;
+ goto out;
+ }
+ bytes_left++;
+ bits = p[1];
+ p++;
+ }
+ else
+ { if ( rlimit - p < 2 )
+ goto out;
+ bits = p[1];
+ }
+ if ( low_order )
+ code += (uint)bits << bits_left;
+ else
+ code += (uint)bits << (code_size - 8 - bits_left);
+ bits_left += 8;
+ bits = p[2];
+ p += 2;
+ bytes_left -= 2;
+ }
+ else
+ { if ( p == rlimit )
+ goto out;
+ bits = *++p;
+ bytes_left--;
+ }
+ if ( low_order )
+ code += (uint)bits << bits_left,
+ bits_left += 8 - code_size;
+ else
+ bits_left += 8 - code_size,
+ code += bits >> bits_left;
+ }
+ else
+ { if ( low_order )
+ code = bits >> (8 - bits_left),
+ bits_left -= code_size;
+ else
+ bits_left -= code_size,
+ code = bits >> bits_left;
+ }
+ code &= code_mask;
+ if_debug2('W', "[W]reading 0x%x,%d\n", code, code_size);
+ /*
+ * There is an anomalous case where a code S is followed
+ * immediately by another occurrence of the S string.
+ * In this case, the next available code will be defined as
+ * S followed by the first character of S, and will be
+ * emitted immediately after the code S. We have to
+ * recognize this case specially, by noting that the code is
+ * equal to next_code.
+ */
+ if ( code >= next_code )
+ { if ( code > next_code )
+ {
+#ifdef DEBUG
+ lprintf2("[W]code = %d > next_code = %d\n",
+ code, next_code);
+#endif
+ status = ERRC;
+ goto out;
+ }
+ /* Fabricate the entry for the code. It will be */
+ /* overwritten immediately, of course. */
+ for ( c = prev_code; c != eod; c = table[c].prefix )
+ dc_next->datum = c;
+ len = prev_len + 1;
+ dc_next->len = min(len, 255);
+ dc_next->prefix = prev_code;
+ if_debug3('w', "[w]decoding anomalous 0x%x=0x%x+%c\n",
+ next_code, prev_code, dc_next->datum);
+ }
+ /* See if there is enough room for the code. */
+ len = table[code].len;
+ if ( len == 255 )
+ { /* Check for special code (reset or end). */
+ /* We set their lengths to 255 to avoid doing */
+ /* an extra check in the normal case. */
+ if ( code == code_reset )
+ { if_debug1('w', "[w]reset: next_code was %d\n",
+ next_code);
+ next_code = code_0;
+ dc_next = table + code_0;
+ code_size = ss->InitialCodeLength + 1;
+ set_code_size();
+ prev_code = -1;
+ goto top;
+ }
+ else if ( code == eod )
+ { status = EOFC;
+ goto out;
+ }
+ /* The code length won't fit in a byte, */
+ /* compute it the hard way. */
+ for ( c = code, len = 0; c != eod; len++ )
+ c = table[c].prefix;
+ if_debug2('w', "[w]long code %d, length=%d\n", code, len);
+ }
+ if ( wlimit - q < len )
+ { ss->copy_code = code;
+ ss->copy_left = ss->copy_len = len;
+ status = 1;
+ goto out;
+ }
+ /* Copy the string to the buffer (back to front). */
+ /* Optimize for short codes, which are the most frequent. */
+ dc = &table[code];
+ switch ( len )
+ {
+ default:
+ { byte *q1 = q += len;
+ c = code;
+ do
+ { *q1-- = (dc = &table[c])->datum;
+ }
+ while ( (c = dc->prefix) != eod );
+ b = q1[1];
+ } break;
+ case 3:
+ q[3] = dc->datum;
+ dc = &table[dc->prefix];
+ case 2:
+ q[2] = dc->datum;
+ dc = &table[dc->prefix];
+ case 1:
+ q[1] = b = dc->datum;
+ q += len;
+ }
+add: /* Add a new entry to the table */
+ if ( prev_code >= 0 )
+ { /* Unfortunately, we have to check for next_code == */
+ /* lzw_decode_max every time: just checking at power */
+ /* of 2 boundaries stops us one code too soon. */
+ if ( next_code == lzw_decode_max )
+ { status = ERRC;
+ goto out;
+ }
+ dc_next->datum = b; /* added char of string */
+ dc_next->len = min(prev_len, 254) + 1;
+ dc_next->prefix = prev_code;
+ dc_next++;
+ if_debug4('W', "[W]adding 0x%x=0x%x+%c(%d)\n",
+ next_code, prev_code, b, min(len, 255));
+ if ( ++next_code == switch_code )
+ { /* Crossed a power of 2. */
+ /* We have to make a strange special check for */
+ /* reaching the end of the code space. */
+ if ( next_code < lzw_decode_max - 1 )
+ { code_size++;
+ set_code_size();
+ if_debug2('w', "[w]crossed power of 2: new code_size=%d, next_code=%d\n",
+ code_size, next_code);
+ }
+ }
+ }
+ prev_code = code;
+ prev_len = len;
+ goto top;
+out: pr->ptr = p;
+ pw->ptr = q;
+ ss->code_size = code_size;
+ ss->prev_code = prev_code;
+ ss->prev_len = prev_len;
+ ss->bits = bits;
+ ss->bits_left = bits_left;
+ ss->bytes_left = bytes_left;
+ ss->next_code = next_code;
+ if_debug3('w', "[w]decoded %d bytes, prev_code=%d, next_code=%d\n",
+ (int)(q - q0), prev_code, next_code);
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_LZWD_template =
+{ &st_LZW_state, s_LZWD_init, s_LZWD_process, 3, 1, s_LZW_release,
+ s_LZW_set_defaults, s_LZWD_reset
+};
diff --git a/gs/src/slzwx.h b/gs/src/slzwx.h
new file mode 100644
index 000000000..e90ed2419
--- /dev/null
+++ b/gs/src/slzwx.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* slzwx.h */
+/* LZW filter state definition */
+/* Requires strimpl.h */
+
+typedef struct lzw_decode_s lzw_decode;
+typedef struct lzw_encode_table_s lzw_encode_table;
+typedef struct stream_LZW_state_s {
+ stream_state_common;
+ /* The following are set before initialization. */
+ int InitialCodeLength; /* decoding only */
+ bool FirstBitLowOrder; /* decoding only */
+ bool BlockData; /* decoding only */
+ int EarlyChange; /* decoding only */
+ /* The following are updated dynamically. */
+ uint bits; /* buffer for input bits */
+ int bits_left; /* # of valid low bits left */
+ int bytes_left; /* # of bytes left in current block */
+ /* (arbitrary large # if not GIF) */
+ union _lzt {
+ lzw_decode *decode;
+ lzw_encode_table *encode;
+ } table;
+ uint next_code; /* next code to be assigned */
+ int code_size; /* current # of bits per code */
+ int prev_code; /* previous code recognized */
+ /* or assigned */
+ uint prev_len; /* length of prev_code */
+ int copy_code; /* code whose string is being */
+ /* copied, -1 if none */
+ uint copy_len; /* length of copy_code */
+ int copy_left; /* amount of string left to copy */
+ bool first; /* true if no output yet */
+} stream_LZW_state;
+extern_st(st_LZW_state);
+#define public_st_LZW_state() /* in slzwc.c */\
+ gs_public_st_ptrs1(st_LZW_state, stream_LZW_state,\
+ "LZWDecode state", lzwd_enum_ptrs, lzwd_reloc_ptrs, table.decode)
+#define s_LZW_set_defaults_inline(ss)\
+ ((ss)->InitialCodeLength = 8,\
+ (ss)->FirstBitLowOrder = false,\
+ (ss)->BlockData = false,\
+ (ss)->EarlyChange = 1)
+extern const stream_template s_LZWD_template;
+extern const stream_template s_LZWE_template;
+
+/* Shared procedures */
+void s_LZW_set_defaults(P1(stream_state *));
+void s_LZW_release(P1(stream_state *));
diff --git a/gs/src/smtf.c b/gs/src/smtf.c
new file mode 100644
index 000000000..0124a5d2e
--- /dev/null
+++ b/gs/src/smtf.c
@@ -0,0 +1,166 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* smtf.c */
+/* MoveToFront filters */
+#include "stdio_.h"
+#include "strimpl.h"
+#include "smtf.h"
+
+/* ------ MoveToFrontEncode/Decode ------ */
+
+private_st_MTF_state();
+
+#define ss ((stream_MTF_state *)st)
+
+/* Initialize */
+private int
+s_MTF_init(stream_state *st)
+{ int i;
+ for ( i = 0; i < 256; i++ )
+ ss->prev.b[i] = (byte)i;
+ return 0;
+}
+
+/* Encode a buffer */
+private int
+s_MTFE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint wcount = pw->limit - q;
+ int status =
+ (count < wcount ? 0 :
+ (rlimit = p + wcount, 1));
+ while ( p < rlimit )
+ { byte b = *++p;
+ int i;
+ byte prev = b, repl;
+ for ( i = 0; (repl = ss->prev.b[i]) != b; i++ )
+ ss->prev.b[i] = prev, prev = repl;
+ ss->prev.b[i] = prev;
+ *++q = (byte)i;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_MTFE_template =
+{ &st_MTF_state, s_MTF_init, s_MTFE_process, 1, 1
+};
+
+/* Decode a buffer */
+private int
+s_MTFD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint wcount = pw->limit - q;
+ int status = (count <= wcount ? 0 : (rlimit = p + wcount, 1));
+ /* Cache the first few entries in local variables. */
+ byte
+ v0 = ss->prev.b[0], v1 = ss->prev.b[1],
+ v2 = ss->prev.b[2], v3 = ss->prev.b[3];
+ while ( p < rlimit )
+ { byte first;
+ /* Zeros far outnumber all other bytes in the BWBS */
+ /* code; check for them first. */
+ if ( *++p == 0 )
+ { *++q = v0;
+ continue;
+ }
+ switch ( *p )
+ {
+ default:
+ { uint b = *p;
+ byte *bp = &ss->prev.b[b];
+ *++q = first = *bp;
+#if arch_sizeof_long == 4
+ ss->prev.b[3] = v3;
+#endif
+ /* Move trailing entries individually. */
+ for ( ; ; bp--, b-- )
+ { *bp = bp[-1];
+ if ( !(b & (sizeof(long) - 1)) )
+ break;
+ }
+ /* Move in long-size chunks. */
+ for ( ; (b -= sizeof(long)) != 0; )
+ { bp -= sizeof(long);
+#if arch_is_big_endian
+ *(ulong *)bp =
+ (*(ulong *)bp >> 8) |
+ ((ulong)bp[-1] << ((sizeof(long) - 1) * 8));
+#else
+ *(ulong *)bp = (*(ulong *)bp << 8) | bp[-1];
+#endif
+ }
+ }
+#if arch_sizeof_long > 4 /* better be 8! */
+ goto m7;
+ case 7:
+ *++q = first = ss->prev.b[7];
+m7: ss->prev.b[7] = ss->prev.b[6];
+ goto m6;
+ case 6:
+ *++q = first = ss->prev.b[6];
+m6: ss->prev.b[6] = ss->prev.b[5];
+ goto m5;
+ case 5:
+ *++q = first = ss->prev.b[5];
+m5: ss->prev.b[5] = ss->prev.b[4];
+ goto m4;
+ case 4:
+ *++q = first = ss->prev.b[4];
+m4: ss->prev.b[4] = v3;
+#endif
+ goto m3;
+ case 3:
+ *++q = first = v3;
+m3: v3 = v2, v2 = v1, v1 = v0, v0 = first;
+ break;
+ case 2:
+ *++q = first = v2;
+ v2 = v1, v1 = v0, v0 = first;
+ break;
+ case 1:
+ *++q = first = v1;
+ v1 = v0, v0 = first;
+ break;
+ }
+ }
+ ss->prev.b[0] = v0; ss->prev.b[1] = v1;
+ ss->prev.b[2] = v2; ss->prev.b[3] = v3;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_MTFD_template =
+{ &st_MTF_state, s_MTF_init, s_MTFD_process, 1, 1,
+ NULL, NULL, s_MTF_init
+};
+
+#undef ss
diff --git a/gs/src/smtf.h b/gs/src/smtf.h
new file mode 100644
index 000000000..d827621d0
--- /dev/null
+++ b/gs/src/smtf.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* smtf.h */
+/* Definitions for MoveToFront streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* MoveToFrontEncode/Decode */
+typedef struct stream_MTF_state_s {
+ stream_state_common;
+ /* The following change dynamically. */
+ union _p {
+ ulong l[256 / sizeof(long)];
+ byte b[256];
+ } prev;
+} stream_MTF_state;
+typedef stream_MTF_state stream_MTFE_state;
+typedef stream_MTF_state stream_MTFD_state;
+#define private_st_MTF_state() /* in sbwbs.c */\
+ gs_private_st_simple(st_MTF_state, stream_MTF_state,\
+ "MoveToFrontEncode/Decode state")
+extern const stream_template s_MTFE_template;
+extern const stream_template s_MTFD_template;
diff --git a/gs/src/spcxd.c b/gs/src/spcxd.c
new file mode 100644
index 000000000..7bc5c5694
--- /dev/null
+++ b/gs/src/spcxd.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spcxd.c */
+/* PCXDecode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "spcxx.h"
+
+/* ------ PCXDecode ------ */
+
+/* Refill the buffer */
+private int
+s_PCXD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+
+ while ( p < rlimit )
+ { int b = *++p;
+ if ( b < 0xc0 )
+ { if ( q >= wlimit )
+ { --p;
+ status = 1;
+ break;
+ }
+ *++q = b;
+ }
+ else if ( p >= rlimit )
+ { --p;
+ break;
+ }
+ else if ( (b -= 0xc0) > wlimit - q )
+ { --p;
+ status = 1;
+ break;
+ }
+ else
+ { memset(q + 1, *++p, b);
+ q += b;
+ }
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_PCXD_template =
+{ &st_stream_state, NULL, s_PCXD_process, 2, 63
+};
diff --git a/gs/src/spcxx.h b/gs/src/spcxx.h
new file mode 100644
index 000000000..730211fad
--- /dev/null
+++ b/gs/src/spcxx.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spcxx.h */
+/* Definitions for PCXDecode streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* PCXDecode */
+/* (no state) */
+extern const stream_template s_PCXD_template;
diff --git a/gs/src/spdiff.c b/gs/src/spdiff.c
new file mode 100644
index 000000000..2ef0ea956
--- /dev/null
+++ b/gs/src/spdiff.c
@@ -0,0 +1,297 @@
+/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spdiff.c */
+/* Pixel differencing filters */
+#include "stdio_.h" /* should be std.h, but needs NULL */
+#include "strimpl.h"
+#include "spdiffx.h"
+
+/* ------ PixelDifferenceEncode/Decode ------ */
+
+private_st_PDiff_state();
+
+#define ss ((stream_PDiff_state *)st)
+
+/* Define values for case dispatch. */
+#define cBits1 0
+#define cBits2 4
+#define cBits4 8
+#define cBits8 12
+#define cEncode -1
+#define cDecode 15
+
+/* Set defaults */
+private void
+s_PDiff_set_defaults(stream_state *st)
+{ s_PDiff_set_defaults_inline(ss);
+}
+
+/* Common (re)initialization. */
+private int
+s_PDiff_reinit(stream_state *st)
+{ ss->row_left = 0;
+ return 0;
+}
+
+/* Initialize PixelDifferenceEncode filter. */
+private int
+s_PDiffE_init(stream_state *st)
+{ long bits_per_row =
+ ss->Colors * ss->BitsPerComponent * (long)ss->Columns;
+ static const byte cb_values[] =
+ { 0, cBits1, cBits2, 0, cBits4, 0, 0, 0, cBits8 };
+ ss->row_count = (uint)((bits_per_row + 7) >> 3);
+ ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
+ ss->case_index =
+ cb_values[ss->BitsPerComponent] + ss->Colors + cEncode;
+ return s_PDiff_reinit(st);
+}
+
+/* Initialize PixelDifferenceDecode filter. */
+private int
+s_PDiffD_init(stream_state *st)
+{ s_PDiffE_init(st);
+ ss->case_index += cDecode - cEncode;
+ return 0;
+}
+
+/* Process a buffer. Note that this handles both Encode and Decode. */
+private int
+s_PDiff_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int rcount, wcount;
+ register int count;
+ int status = 0;
+ register byte s0 = ss->s0;
+ register byte t;
+ byte save_last;
+ const byte end_mask = ss->end_mask;
+
+row: if ( ss->row_left == 0 )
+ ss->row_left = ss->row_count,
+ s0 = ss->s1 = ss->s2 = ss->s3 = 0;
+ rcount = pr->limit - p;
+ wcount = pw->limit - q;
+ if ( ss->row_left < rcount )
+ rcount = ss->row_left;
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ ss->row_left -= count;
+ if ( ss->row_left == count )
+ save_last = p[count];
+
+ /*
+ * Encoding and decoding are fundamentally different.
+ * Encoding computes E[i] = D[i] - D[i-1];
+ * decoding computes D[i] = E[i] + D[i-1].
+ * Nevertheless, the loop structures are similar enough that
+ * we put the code for both functions in the same place.
+ */
+
+#define loopn(n, body)\
+ while ( count >= n ) p += n, q += n, body, count -= n
+
+ switch ( ss->case_index )
+ {
+
+ /* 1 bit per component */
+
+#define eloop1(ee)\
+ loopn(1, (t = *p, *q = ee, s0 = t))
+
+ case cEncode+cBits1+1:
+ eloop1(t ^ ((s0 << 7) | (t >> 1)));
+ case cEncode+cBits1+2:
+ eloop1(t ^ ((s0 << 6) | (t >> 2)));
+ case cEncode+cBits1+3:
+ eloop1(t ^ ((s0 << 5) | (t >> 3)));
+ case cEncode+cBits1+4:
+ eloop1(t ^ ((s0 << 4) | (t >> 4)));
+
+#define dloop1(te, de)\
+ loopn(1, (t = te, s0 = *q = de)); break
+
+ case cDecode+cBits1+1:
+ dloop1(*p ^ (s0 << 7),
+ (t ^= t >> 1, t ^= t >> 2, t ^ (t >> 4)));
+ case cDecode+cBits1+2:
+ dloop1(*p ^ (s0 << 6),
+ (t ^= (t >> 2), t ^ (t >> 4)));
+ case cDecode+cBits1+3:
+ dloop1(*p ^ (s0 << 5),
+ t ^ (t >> 3) ^ (t >> 6));
+ case cDecode+cBits1+4:
+ dloop1(*p ^ (s0 << 4),
+ t ^ (t >> 4));
+
+ /* 2 bits per component */
+
+#define add4x2(a, b) ( (((a) & (b) & 0x55) << 1) ^ (a) ^ (b) )
+#define sub4x2(a, b) ( ((~(a) & (b) & 0x55) << 1) ^ (a) ^ (b) )
+
+ case cEncode+cBits2+1:
+ eloop1((s0 = (s0 << 6) | (t >> 2), sub4x2(t, s0)));
+ case cEncode+cBits2+2:
+ eloop1((s0 = (s0 << 4) | (t >> 4), sub4x2(t, s0)));
+ case cEncode+cBits2+3:
+ eloop1((s0 = (s0 << 2) | (t >> 6), sub4x2(t, s0)));
+ case cEncode+cBits2+4:
+ eloop1(sub4x2(t, s0));
+
+ case cDecode+cBits2+1:
+ dloop1(*p + (s0 << 6),
+ (t = add4x2(t >> 2, t),
+ add4x2(t >> 4, t)));
+ case cDecode+cBits2+2:
+ dloop1(*p, (t = add4x2(t, s0 << 4),
+ add4x2(t >> 4, t)));
+ case cDecode+cBits2+3:
+ dloop1(*p, (t = add4x2(t, s0 << 2),
+ add4x2(t >> 6, t)));
+ case cDecode+cBits2+4:
+ dloop1(*p, add4x2(t, s0));
+
+#undef add4x2
+#undef sub4x2
+
+ /* 4 bits per component */
+
+#define add2x4(a, b) ( (((a) + (b)) & 0xf) + ((a) & 0xf0) + ((b) & 0xf0) )
+#define add2x4r4(a) ( (((a) + ((a) >> 4)) & 0xf) + ((a) & 0xf0) )
+#define sub2x4(a, b) ( (((a) - (b)) & 0xf) + ((a) & 0xf0) - ((b) & 0xf0) )
+#define sub2x4r4(a) ( (((a) - ((a) >> 4)) & 0xf) + ((a) & 0xf0) )
+
+ case cEncode+cBits4+1:
+ eloop1( ((t - (s0 << 4)) & 0xf0) | ((t - (t >> 4)) & 0xf) );
+ case cEncode+cBits4+2:
+ eloop1(sub2x4(t, s0));
+ case cEncode+cBits4+3:
+ { register byte s1 = ss->s1;
+ loopn(1, (t = *p,
+ *q =
+ ((t - (s0 << 4)) & 0xf0) | ((t - (s1 >> 4)) & 0xf),
+ s0 = s1, s1 = t));
+ ss->s1 = s1;
+ } break;
+ case cEncode+cBits4+4:
+ { register byte s1 = ss->s1;
+ loopn(2,
+ (t = p[-1], q[-1] = sub2x4(t, s0), s0 = t,
+ t = *p, *q = sub2x4(t, s1), s1 = t));
+ ss->s1 = s1;
+ } break;
+
+ case cDecode+cBits4+1:
+ dloop1(*p + (s0 << 4), add2x4r4(t));
+ case cDecode+cBits4+2:
+ dloop1(*p, add2x4(t, s0));
+ case cDecode+cBits4+3:
+ { register byte s1 = ss->s1;
+ loopn(1, (t = (s0 << 4) + (s1 >> 4),
+ s0 = s1, s1 = *q = add2x4(*p, t)));
+ ss->s1 = s1;
+ } break;
+ case cDecode+cBits4+4:
+ { register byte s1 = ss->s1;
+ loopn(2,
+ (t = p[-1], s0 = q[-1] = add2x4(s0, t),
+ t = *p, s1 = *q = add2x4(s1, t)));
+ ss->s1 = s1;
+ } break;
+
+#undef add2x4
+#undef add2x4r4
+#undef sub2x4
+#undef sub2x4r4
+
+ /* 8 bits per component */
+
+#define encode8(s, d) (q[d] = p[d] - s, s = p[d])
+#define decode8(s, d) s = q[d] = s + p[d]
+
+ case cEncode+cBits8+1:
+ loopn(1, encode8(s0, 0));
+ break;
+ case cDecode+cBits8+1:
+ loopn(1, decode8(s0, 0));
+ break;
+ case cEncode+cBits8+2:
+ { register byte s1 = ss->s1;
+ loopn(2, (encode8(s0, -1), encode8(s1, 0)));
+ ss->s1 = s1;
+ } break;
+ case cDecode+cBits8+2:
+ { register byte s1 = ss->s1;
+ loopn(2, (decode8(s0, -1), decode8(s1, 0)));
+ ss->s1 = s1;
+ } break;
+ case cEncode+cBits8+3:
+ { register byte s1 = ss->s1, s2 = ss->s2;
+ loopn(3, (encode8(s0, -2), encode8(s1, -1),
+ encode8(s2, 0)));
+ ss->s1 = s1, ss->s2 = s2;
+ } break;
+ case cDecode+cBits8+3:
+ { register byte s1 = ss->s1, s2 = ss->s2;
+ loopn(3, (decode8(s0, -2), decode8(s1, -1),
+ decode8(s2, 0)));
+ ss->s1 = s1, ss->s2 = s2;
+ } break;
+ case cEncode+cBits8+4:
+ { register byte s1 = ss->s1, s2 = ss->s2, s3 = ss->s3;
+ loopn(4, (encode8(s0, -3), encode8(s1, -2),
+ encode8(s2, -1), encode8(s3, 0)));
+ ss->s1 = s1, ss->s2 = s2, ss->s3 = s3;
+ } break;
+ case cDecode+cBits8+4:
+ { register byte s1 = ss->s1, s2 = ss->s2, s3 = ss->s3;
+ loopn(4, (decode8(s0, -3), decode8(s1, -2),
+ decode8(s2, -1), decode8(s3, 0)));
+ ss->s1 = s1, ss->s2 = s2, ss->s3 = s3;
+ } break;
+
+#undef encode8
+#undef decode8
+
+ }
+#undef loopn
+#undef dloop1
+ ss->row_left += count; /* leftover bytes are possible */
+ if ( ss->row_left == 0 )
+ { if ( end_mask != 0 )
+ *q = (*q & ~end_mask) | (save_last & end_mask);
+ if ( p < pr->limit && q < pw->limit )
+ goto row;
+ }
+ ss->s0 = s0;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream templates */
+const stream_template s_PDiffE_template =
+{ &st_PDiff_state, s_PDiffE_init, s_PDiff_process, 1, 1, NULL,
+ s_PDiff_set_defaults, s_PDiff_reinit
+};
+const stream_template s_PDiffD_template =
+{ &st_PDiff_state, s_PDiffD_init, s_PDiff_process, 1, 1, NULL,
+ s_PDiff_set_defaults, s_PDiff_reinit
+};
diff --git a/gs/src/spdiffx.h b/gs/src/spdiffx.h
new file mode 100644
index 000000000..3c1162496
--- /dev/null
+++ b/gs/src/spdiffx.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spdiffx.h */
+/* Pixel differencing filter state definition */
+/* Requires strimpl.h */
+
+/* PixelDifferenceDecode / PixelDifferenceEncode */
+typedef struct stream_PDiff_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* # of colors, 1..4 */
+ int BitsPerComponent; /* 1, 2, 4, 8 */
+ int Columns;
+ /* The init procedure computes the following. */
+ uint row_count; /* # of bytes per row */
+ byte end_mask; /* mask for left-over bits in last byte */
+ int case_index; /* switch index for case dispatch */
+ /* The following are updated dynamically. */
+ uint row_left; /* # of bytes left in row */
+ byte s0, s1, s2, s3; /* previous sample */
+} stream_PDiff_state;
+#define private_st_PDiff_state() /* in spdiff.c */\
+ gs_private_st_simple(st_PDiff_state, stream_PDiff_state,\
+ "PixelDifferenceEncode/Decode state")
+#define s_PDiff_set_defaults_inline(ss)\
+ ((ss)->Colors = 1, (ss)->BitsPerComponent = 8, (ss)->Columns = 1)
+extern const stream_template s_PDiffD_template;
+extern const stream_template s_PDiffE_template;
diff --git a/gs/src/spngp.c b/gs/src/spngp.c
new file mode 100644
index 000000000..31116d1ef
--- /dev/null
+++ b/gs/src/spngp.c
@@ -0,0 +1,334 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spngp.c */
+/* PNG pixel prediction filters */
+#include "memory_.h"
+#include "strimpl.h"
+#include "spngpx.h"
+
+/* ------ PNGPredictorEncode/Decode ------ */
+
+private_st_PNGP_state();
+
+#define ss ((stream_PNGP_state *)st)
+#define ss_const ((const stream_PNGP_state *)st_const)
+
+/* Define values for case dispatch. */
+#define cNone 10
+#define cSub 11
+#define cUp 12
+#define cAverage 13
+#define cPaeth 14
+#define cOptimum 15
+#define cEncode -10
+#define cDecode -4
+private const byte pngp_case_needs_prev[] = { 0, 0, 1, 1, 1, 1 };
+
+/* Set defaults */
+private void
+s_PNGP_set_defaults(stream_state *st)
+{ s_PNGP_set_defaults_inline(ss);
+}
+
+/* Common (re)initialization. */
+private int
+s_PNGP_reinit(stream_state *st)
+{ if ( ss->prev_row != 0 )
+ memset(ss->prev_row + ss->bpp, 0, ss->row_count);
+ ss->row_left = 0;
+ return 0;
+}
+
+/* Initialize PNGPredictorEncode filter. */
+private int
+s_pngp_init(stream_state *st, bool need_prev)
+{ int bits_per_pixel = ss->Colors * ss->BitsPerComponent;
+ long bits_per_row = (long)bits_per_pixel * ss->Columns;
+ byte *prev_row = 0;
+
+#if arch_sizeof_long > arch_sizeof_int
+ if ( bits_per_row > max_uint * 7L )
+ return ERRC; /****** WRONG ******/
+#endif
+ ss->row_count = (uint)((bits_per_row + 7) >> 3);
+ ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
+ ss->bpp = (bits_per_pixel + 7) >> 3;
+ if ( need_prev )
+ { prev_row = gs_alloc_bytes(st->memory, ss->bpp + ss->row_count,
+ "PNGPredictor prev row");
+ if ( prev_row == 0 )
+ return ERRC; /****** WRONG ******/
+ memset(prev_row, 0, ss->bpp);
+ }
+ ss->prev_row = prev_row;
+ /* case_index is only preset for encoding */
+ return s_PNGP_reinit(st);
+}
+
+/* Initialize PNGPredictorEncode filter. */
+private int
+s_PNGPE_init(stream_state *st)
+{ return s_pngp_init(st, pngp_case_needs_prev[ss->Predictor - cNone]);
+}
+
+/* Initialize PNGPredictorDecode filter. */
+private int
+s_PNGPD_init(stream_state *st)
+{ return s_pngp_init(st, true);
+}
+
+/*
+ * Process a partial buffer. We pass in current and previous pointers
+ * to both the current and preceding scan line. Note that dprev is
+ * p - bpp for encoding, q - bpp for decoding; similarly, the 'up' row
+ * is the raw data for encoding, the filtered data for decoding.
+ * Note also that the case_index cannot be cOptimum.
+ */
+private int
+paeth_predictor(int a, int b, int c)
+{
+#undef any_abs /* just in case */
+#define any_abs(u) ((u) < 0 ? -(u) : (u))
+ int px = a + b - c;
+ int pa = any_abs(px - a), pb = any_abs(px - b), pc = any_abs(px - c);
+ return (pa <= pb && pa <= pc ? a : pb <= pc ? b : c);
+#undef any_abs
+}
+private void
+s_pngp_process(stream_state *st, stream_cursor_write *pw,
+ const byte *dprev, stream_cursor_read *pr,
+ const byte *upprev, const byte *up, uint count)
+{ byte *q = pw->ptr + 1;
+ const byte *p = pr->ptr + 1;
+
+ pr->ptr += count;
+ pw->ptr += count;
+ ss->row_left -= count;
+ switch ( ss->case_index )
+ {
+ case cEncode + cNone:
+ case cDecode + cNone:
+ memcpy(q, p, count);
+ break;
+ case cEncode + cSub:
+ for ( ; count; ++q, ++dprev, ++p, --count )
+ *q = (byte)(*p - *dprev);
+ break;
+ case cDecode + cSub:
+ for ( ; count; ++q, ++dprev, ++p, --count )
+ *q = (byte)(*p + *dprev);
+ break;
+ case cEncode + cUp:
+ for ( ; count; ++q, ++up, ++p, --count )
+ *q = (byte)(*p - *up);
+ break;
+ case cDecode + cUp:
+ for ( ; count; ++q, ++up, ++p, --count )
+ *q = (byte)(*p + *up);
+ break;
+ case cEncode + cAverage:
+ for ( ; count; ++q, ++dprev, ++up, ++p, --count )
+ *q = (byte)(*p - arith_rshift_1((int)*dprev + (int)*up));
+ break;
+ case cDecode + cAverage:
+ for ( ; count; ++q, ++dprev, ++up, ++p, --count )
+ *q = (byte)(*p + arith_rshift_1((int)*dprev + (int)*up));
+ break;
+ case cEncode + cPaeth:
+ for ( ; count; ++q, ++dprev, ++up, ++upprev, ++p, --count )
+ *q = (byte)(*p - paeth_predictor(*dprev, *up, *upprev));
+ break;
+ case cDecode + cPaeth:
+ for ( ; count; ++q, ++dprev, ++up, ++upprev, ++p, --count )
+ *q = (byte)(*p + paeth_predictor(*dprev, *up, *upprev));
+ break;
+ }
+}
+
+/* Calculate the number of bytes for the next processing step, */
+/* the min of (input data, output data, remaining row length). */
+private uint near
+s_pngp_count(const stream_state *st_const, const stream_cursor_read *pr,
+ const stream_cursor_write *pw)
+{ uint rcount = pr->limit - pr->ptr;
+ uint wcount = pw->limit - pw->ptr;
+ uint row_left = ss_const->row_left;
+
+ if ( rcount < row_left )
+ row_left = rcount;
+ if ( wcount < row_left )
+ row_left = wcount;
+ return row_left;
+}
+
+/*
+ * Encode a buffer. Let N = ss->row_count, P = N - ss->row_left,
+ * and B = ss->bpp. Consider that bytes [-B .. -1] of every row are zero.
+ * Then:
+ * prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
+ * of the current input row.
+ * ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
+ * of the current input row.
+ * prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
+ * of the previous input row.
+ */
+private int
+optimum_predictor(const stream_state *st, const stream_cursor_read *pr)
+{ return cSub;
+}
+private int
+s_PNGPE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ int bpp = ss->bpp;
+ int code = 0;
+ while ( pr->ptr < pr->limit )
+ { uint count;
+ if ( ss->row_left == 0 )
+ { /* Beginning of row, write algorithm byte. */
+ int predictor;
+ if ( pw->ptr >= pw->limit )
+ { code = 1;
+ break;
+ }
+ predictor =
+ (ss->Predictor == cOptimum ?
+ optimum_predictor(st, pr) :
+ ss->Predictor);
+ *++(pw->ptr) = (byte)predictor - cNone;
+ ss->case_index = predictor + cEncode;
+ ss->row_left = ss->row_count;
+ memset(ss->prev, 0, bpp);
+ continue;
+ }
+ count = s_pngp_count(st, pr, pw);
+ if ( count == 0 )
+ { /* We know we have input, so output must be full. */
+ code = 1;
+ break;
+ }
+ { byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
+ uint n = min(count, bpp);
+
+ /* Process bytes whose predecessors are in prev. */
+ s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
+ if ( ss->prev_row )
+ memcpy(up - bpp, ss->prev, n);
+ if ( n < bpp )
+ { /* We didn't have enough data to use up all of prev. */
+ /* Shift more data into prev and exit. */
+ int prev_left = bpp - n;
+ memmove(ss->prev, ss->prev + n, prev_left);
+ memcpy(ss->prev + prev_left, pr->ptr - (n - 1), n);
+ break;
+ }
+ /* Process bytes whose predecessors are in the input. */
+ /* We know we have at least bpp input and output bytes, */
+ /* and that n = bpp. */
+ count -= bpp;
+ s_pngp_process(st, pw, pr->ptr - (bpp - 1), pr,
+ up, up + bpp, count);
+ memcpy(ss->prev, pr->ptr - (bpp - 1), bpp);
+ if ( ss->prev_row )
+ { memcpy(up, pr->ptr - (bpp + count - 1), count);
+ if ( ss->row_left == 0 )
+ memcpy(up + count, ss->prev, bpp);
+ }
+ }
+ }
+ return code;
+}
+
+/*
+ * Decode a buffer. Let N = ss->row_count, P = N - ss->row_left,
+ * and B = ss->bpp. Consider that bytes [-B .. -1] of every row are zero.
+ * Then:
+ * prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
+ * of the current output row.
+ * ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
+ * of the current output row.
+ * prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
+ * of the previous output row.
+ */
+private int
+s_PNGPD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ int bpp = ss->bpp;
+ int code = 0;
+ while ( pr->ptr < pr->limit )
+ { uint count;
+ if ( ss->row_left == 0 )
+ { /* Beginning of row, read algorithm byte. */
+ int predictor = pr->ptr[1];
+ if ( predictor >= cOptimum - cNone )
+ { code = ERRC;
+ break;
+ }
+ pr->ptr++;
+ ss->case_index = predictor + cNone + cDecode;
+ ss->row_left = ss->row_count;
+ memset(ss->prev, 0, bpp);
+ continue;
+ }
+ count = s_pngp_count(st, pr, pw);
+ if ( count == 0 )
+ { /* We know we have input, so output must be full. */
+ code = 1;
+ break;
+ }
+ { byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
+ uint n = min(count, bpp);
+
+ /* Process bytes whose predecessors are in prev. */
+ s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
+ if ( ss->prev_row )
+ memcpy(up - bpp, ss->prev, n);
+ if ( n < bpp )
+ { /* We didn't have enough data to use up all of prev. */
+ /* Shift more data into prev and exit. */
+ int prev_left = bpp - n;
+ memmove(ss->prev, ss->prev + n, prev_left);
+ memcpy(ss->prev + prev_left, pw->ptr - (n - 1), n);
+ break;
+ }
+ /* Process bytes whose predecessors are in the output. */
+ /* We know we have at least bpp input and output bytes, */
+ /* and that n = bpp. */
+ count -= bpp;
+ s_pngp_process(st, pw, pw->ptr - (bpp - 1), pr,
+ up, up + bpp, count);
+ memcpy(ss->prev, pw->ptr - (bpp - 1), bpp);
+ if ( ss->prev_row )
+ { memcpy(up, pw->ptr - (bpp + count - 1), count);
+ if ( ss->row_left == 0 )
+ memcpy(up + count, ss->prev, bpp);
+ }
+ }
+ }
+ return code;
+}
+
+/* Stream templates */
+const stream_template s_PNGPE_template =
+{ &st_PNGP_state, s_PNGPE_init, s_PNGPE_process, 1, 1, 0/*NULL*/,
+ s_PNGP_set_defaults, s_PNGP_reinit
+};
+const stream_template s_PNGPD_template =
+{ &st_PNGP_state, s_PNGPD_init, s_PNGPD_process, 1, 1, 0/*NULL*/,
+ s_PNGP_set_defaults, s_PNGP_reinit
+};
diff --git a/gs/src/spngpx.h b/gs/src/spngpx.h
new file mode 100644
index 000000000..2a224fc60
--- /dev/null
+++ b/gs/src/spngpx.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* spngpx.h */
+/* PNG pixel prediction filter state definition */
+/* Requires strimpl.h */
+
+/* PNGPredictorDecode / PNGPredictorEncode */
+typedef struct stream_PNGP_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* # of colors, 1..16 */
+ int BitsPerComponent; /* 1, 2, 4, 8, 16 */
+ uint Columns; /* >0 */
+ int Predictor; /* 10-15, only relevant for Encode */
+ /* The init procedure computes the following. */
+ uint row_count; /* # of bytes per row */
+ byte end_mask; /* mask for left-over bits in last byte */
+ int bpp; /* bytes per pixel */
+ byte *prev_row; /* previous row */
+ int case_index; /* switch index for case dispatch, */
+ /* set dynamically when decoding */
+ /* The following are updated dynamically. */
+ long row_left; /* # of bytes left in row */
+ byte prev[32]; /* previous samples */
+} stream_PNGP_state;
+#define private_st_PNGP_state() /* in sPNGP.c */\
+ gs_private_st_ptrs1(st_PNGP_state, stream_PNGP_state,\
+ "PNGPredictorEncode/Decode state", pngp_enum_ptrs, pngp_reloc_ptrs,\
+ prev_row)
+#define s_PNGP_set_defaults_inline(ss)\
+ ((ss)->Colors = 1, (ss)->BitsPerComponent = 8, (ss)->Columns = 1,\
+ (ss)->Predictor = 15)
+extern const stream_template s_PNGPD_template;
+extern const stream_template s_PNGPE_template;
diff --git a/gs/src/srld.c b/gs/src/srld.c
new file mode 100644
index 000000000..814d152ee
--- /dev/null
+++ b/gs/src/srld.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* srld.c */
+/* RunLengthDecode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "srlx.h"
+
+/* ------ RunLengthDecode ------ */
+
+private_st_RLD_state();
+
+#define ss ((stream_RLD_state *)st)
+
+/* Set defaults */
+private void
+s_RLD_set_defaults(stream_state *st)
+{ s_RLD_set_defaults_inline(ss);
+}
+
+/* Initialize */
+private int
+s_RLD_init(stream_state *st)
+{ return s_RLD_init_inline(ss);
+}
+
+/* Refill the buffer */
+private int
+s_RLD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int left;
+ int status = 0;
+
+top: if ( (left = ss->copy_left) > 0 )
+ { /* We suspended because the output buffer was full; */
+ /* try again now. */
+ uint avail = wlimit - q;
+ int copy_status = 1;
+
+ if ( left > avail )
+ left = avail;
+ if ( ss->copy_data >= 0 )
+ memset(q + 1, ss->copy_data, left);
+ else
+ { avail = rlimit - p;
+ if ( left >= avail )
+ { copy_status = 0;
+ left = avail;
+ }
+ memcpy(q + 1, p + 1, left);
+ p += left;
+ }
+ q += left;
+ if ( (ss->copy_left -= left) > 0 )
+ { status = copy_status;
+ goto x;
+ }
+ }
+ while ( p < rlimit )
+ { int b = *++p;
+ if ( b < 128 )
+ { if ( ++b > rlimit - p || b > wlimit - q )
+ { ss->copy_left = b;
+ ss->copy_data = -1;
+ goto top;
+ }
+ memcpy(q + 1, p + 1, b);
+ p += b;
+ q += b;
+ }
+ else if ( b == 128 ) /* end of data */
+ { if ( ss->EndOfData )
+ { status = EOFC;
+ break;
+ }
+ }
+ else if ( p == rlimit )
+ { p--;
+ break;
+ }
+ else if ( (b = 257 - b) > wlimit - q )
+ { ss->copy_left = b;
+ ss->copy_data = *++p;
+ goto top;
+ }
+ else
+ { memset(q + 1, *++p, b);
+ q += b;
+ }
+ }
+x: pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_RLD_template =
+{ &st_RLD_state, s_RLD_init, s_RLD_process, 1, 1, NULL,
+ s_RLD_set_defaults
+};
diff --git a/gs/src/srle.c b/gs/src/srle.c
new file mode 100644
index 000000000..b0f69d681
--- /dev/null
+++ b/gs/src/srle.c
@@ -0,0 +1,194 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* srle.c */
+/* RunLengthEncode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "srlx.h"
+
+/* ------ RunLengthEncode ------ */
+
+private_st_RLE_state();
+
+#define ss ((stream_RLE_state *)st)
+
+/* Set defaults */
+private void
+s_RLE_set_defaults(stream_state *st)
+{ s_RLE_set_defaults_inline(ss);
+}
+
+/* Initialize */
+private int
+s_RLE_init(stream_state *st)
+{ return s_RLE_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_RLE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ ulong rleft = ss->record_left;
+
+ /*
+ * We thought that the Genoa CET demands that the output from this
+ * filter be not just legal, but optimal, so we went to the trouble
+ * of ensuring this. It turned out that this wasn't actually
+ * necessary, but we didn't want to change the code back.
+ *
+ * For optimal output, we can't just break runs at buffer
+ * boundaries: unless we hit a record boundary or the end of the
+ * input, we have to look ahead far enough to know that we aren't
+ * breaking a run prematurely.
+ */
+
+ /* Check for leftover output. */
+copy: if ( ss->copy_left )
+ { uint rcount = rlimit - p;
+ uint wcount = wlimit - q;
+ uint count = ss->copy_left;
+
+ if ( rcount < count )
+ count = rcount;
+ if ( wcount < count )
+ count = wcount;
+ if ( rleft < count )
+ count = rleft;
+ memcpy(q + 1, p + 1, count);
+ pr->ptr = p += count;
+ pw->ptr = q += count;
+ if ( (ss->record_left = rleft -= count) == 0 )
+ ss->record_left = rleft = ss->record_size;
+ if ( (ss->copy_left -= count) != 0 )
+ return (rcount == 0 ? 0 : 1);
+ }
+ while ( p < rlimit )
+ { const byte *beg = p;
+ const byte *p1;
+ uint count = rlimit - p;
+ bool end = last;
+ byte next;
+
+ if ( count > rleft )
+ count = rleft, end = true;
+ if ( count > 128 )
+ count = 128, end = true;
+ p1 = p + count - 1;
+ if ( count < 3 )
+ { if ( !end || count == 0 )
+ break; /* can't look ahead far enough */
+ if ( count == 1 )
+ { if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ *++q = 0;
+ }
+ else /* count == 2 */
+ { if ( p[1] == p[2] )
+ { if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ *++q = 255;
+ }
+ else
+ { if ( wlimit - q < 3 )
+ { status = 1;
+ break;
+ }
+ *++q = 1;
+ *++q = p[1];
+ }
+ }
+ *++q = p1[1];
+ p = p1 + 1;
+ }
+ else if ( (next = p[1]) == p[2] && next == p[3] )
+ { if ( wlimit - q < 2 )
+ { status = 1;
+ break;
+ }
+ /* Recognize leading repeated byte */
+ do { p++; }
+ while ( p < p1 && p[2] == next );
+ if ( p == p1 && !end )
+ { p = beg; /* need to look ahead further */
+ break;
+ }
+ p++;
+ *++q = (byte)(257 - (p - beg));
+ *++q = next;
+ }
+ else
+ { p1--;
+ while ( p < p1 && (p[2] != p[1] || p[3] != p[1]) )
+ p++;
+ if ( p == p1 )
+ { if ( !end )
+ { p = beg; /* need to look ahead further */
+ break;
+ }
+ p += 2;
+ }
+ count = p - beg;
+ if ( wlimit - q < count + 1 )
+ { p = beg;
+ if ( q >= wlimit )
+ { status = 1;
+ break;
+ }
+ /* Copy some now and some later. */
+ *++q = count - 1;
+ ss->copy_left = count;
+ goto copy;
+ }
+ *++q = count - 1;
+ memcpy(q + 1, beg + 1, count);
+ q += count;
+ }
+ rleft -= p - beg;
+ if ( rleft == 0 )
+ rleft = ss->record_size;
+ }
+ if ( last && status == 0 && ss->EndOfData )
+ { if ( q < wlimit )
+ *++q = 128;
+ else
+ status = 1;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ ss->record_left = rleft;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_RLE_template =
+{ &st_RLE_state, s_RLE_init, s_RLE_process, 128, 2, NULL,
+ s_RLE_set_defaults, s_RLE_init
+};
diff --git a/gs/src/srlx.h b/gs/src/srlx.h
new file mode 100644
index 000000000..74ea59735
--- /dev/null
+++ b/gs/src/srlx.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* srlx.h */
+/* Definitions for RLE/RLD streams */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+/* Common state */
+#define stream_RL_state_common\
+ stream_state_common;\
+ bool EndOfData /* true if 128 = EOD */
+
+/* RunLengthEncode */
+typedef struct stream_RLE_state_s {
+ stream_RL_state_common;
+ /* The following parameters are set by the client. */
+ ulong record_size;
+ /* The following change dynamically. */
+ ulong record_left; /* bytes left in current record */
+ int copy_left; /* # of bytes waiting to be copied */
+} stream_RLE_state;
+#define private_st_RLE_state() /* in srle.c */\
+ gs_private_st_simple(st_RLE_state, stream_RLE_state, "RunLengthEncode state")
+/* We define the initialization procedure here, so that clients */
+/* can avoid a procedure call. */
+#define s_RLE_set_defaults_inline(ss)\
+ ((ss)->EndOfData = true, (ss)->record_size = 0)
+#define s_RLE_init_inline(ss)\
+ ((ss)->record_left = ((ss)->record_size == 0 ?\
+ ((ss)->record_size = max_uint) :\
+ (ss)->record_size),\
+ (ss)->copy_left = 0)
+extern const stream_template s_RLE_template;
+
+/* RunLengthDecode */
+typedef struct stream_RLD_state_s {
+ stream_RL_state_common;
+ /* The following change dynamically. */
+ int copy_left; /* # of output bytes waiting to be produced */
+ int copy_data; /* -1 if copying, repeated byte if repeating */
+} stream_RLD_state;
+#define private_st_RLD_state() /* in srld.c */\
+ gs_private_st_simple(st_RLD_state, stream_RLD_state, "RunLengthDecode state")
+/* We define the initialization procedure here, so that clients */
+/* can avoid a procedure call. */
+#define s_RLD_set_defaults_inline(ss)\
+ ((ss)->EndOfData = true)
+#define s_RLD_init_inline(ss)\
+ ((ss)->copy_left = 0)
+extern const stream_template s_RLD_template;
diff --git a/gs/src/sstring.c b/gs/src/sstring.c
new file mode 100644
index 000000000..1a7539e7e
--- /dev/null
+++ b/gs/src/sstring.c
@@ -0,0 +1,435 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sstring.c */
+/* String and hexstring streams (filters) */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "string_.h"
+#include "strimpl.h"
+#include "sstring.h"
+#include "scanchar.h"
+
+/* ------ ASCIIHexEncode ------ */
+
+/* Process a buffer */
+private int
+s_AXE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int rcount = pr->limit - p;
+ int wcount = pw->limit - q;
+ register int count;
+ register const char _ds *hex_digits = "0123456789abcdef";
+ int status = 0;
+
+ if ( last )
+ wcount--; /* leave room for '>' */
+ wcount -= (wcount + 64) / 65; /* leave room for \n */
+ wcount >>= 1; /* 2 chars per input byte */
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ while ( --count >= 0 )
+ { *++q = hex_digits[*++p >> 4];
+ *++q = hex_digits[*p & 0xf];
+ if ( !(count & 31) && (count != 0 || !last) )
+ *++q = '\n';
+ }
+ if ( last && status == 0 )
+ *++q = '>';
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_AXE_template =
+{ &st_stream_state, NULL, s_AXE_process, 1, 3
+};
+
+/* ------ ASCIIHexDecode ------ */
+
+private_st_AXD_state();
+
+#define ss ((stream_AXD_state *)st)
+
+/* Initialize the state */
+private int
+s_AXD_init(stream_state *st)
+{ return s_AXD_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_AXD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ int code = s_hex_process(pr, pw, &ss->odd, hex_ignore_whitespace);
+ switch ( code )
+ {
+ case 0:
+ if ( ss->odd >= 0 && last )
+ { if ( pw->ptr == pw->limit )
+ return 1;
+ *++(pw->ptr) = ss->odd << 4;
+ }
+ /* falls through */
+ case 1:
+ /* We still need to read ahead and check for EOD. */
+ for ( ; pr->ptr < pr->limit; pr->ptr++ )
+ if ( scan_char_decoder[pr->ptr[1]] != ctype_space )
+ { if ( pr->ptr[1] == '>' )
+ { pr->ptr++;
+ goto eod;
+ }
+ return 1;
+ }
+ return 0; /* still need to scan ahead */
+ default:
+ return code;
+ case ERRC:
+ ;
+ }
+ /*
+ * Check for EOD. ERRC implies at least one more character
+ * was read; we must unread it, since the caller might have
+ * invoked the filter with exactly the right count to read all
+ * the available data, and we might be reading past the end.
+ */
+ if ( *pr->ptr != '>' ) /* EOD */
+ { --(pr->ptr);
+ return ERRC;
+ }
+eod: if ( ss->odd >= 0 )
+ { if ( pw->ptr == pw->limit )
+ return 1;
+ *++(pw->ptr) = ss->odd << 4;
+ }
+ return EOFC;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_AXD_template =
+{ &st_AXD_state, s_AXD_init, s_AXD_process, 2, 1
+};
+
+/* ------ PSStringEncode ------ */
+
+/* Process a buffer */
+private int
+s_PSSE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ /* This doesn't have to be very efficient. */
+ while ( p < rlimit )
+ { register int c = *++p;
+ if ( c < 32 || c >= 127 )
+ { const char *pesc;
+ const char *esc = "\n\r\t\b\f";
+ if ( c < 32 && c != 0 && (pesc = strchr(esc, c)) != 0 )
+ { if ( wlimit - q < 2 )
+ { --p;
+ status = 1;
+ break;
+ }
+ *++q = '\\';
+ *++q = "nrtbf"[pesc - esc];
+ continue;
+ }
+ if ( wlimit - q < 4 )
+ { --p;
+ status = 1;
+ break;
+ }
+ q[1] = '\\';
+ q[2] = (c >> 6) + '0';
+ q[3] = ((c >> 3) & 7) + '0';
+ q[4] = (c & 7) + '0';
+ q += 4;
+ continue;
+ }
+ else if ( c == '(' || c == ')' || c == '\\' )
+ { if ( wlimit - q < 2 )
+ { --p;
+ status = 1;
+ break;
+ }
+ *++q = '\\';
+ }
+ else
+ { if ( q == wlimit )
+ { --p;
+ status = 1;
+ break;
+ }
+ }
+ *++q = c;
+ }
+ if ( last && status == 0 )
+ { if ( q == wlimit )
+ status = 1;
+ else
+ *++q = ')';
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_PSSE_template =
+{ &st_stream_state, NULL, s_PSSE_process, 1, 4
+};
+
+/* ------ PSStringDecode ------ */
+
+private_st_PSSD_state();
+
+#define ss ((stream_PSSD_state *)st)
+
+/* Initialize the state */
+private int
+s_PSSD_init(stream_state *st)
+{ return s_PSSD_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_PSSD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ register int c;
+#define check_p(n)\
+ if ( p == rlimit ) { p -= n; goto out; }
+#define check_q(n)\
+ if ( q == wlimit ) { p -= n; status = 1; goto out; }
+ while ( p < rlimit )
+ { c = *++p;
+ if ( c == '\\' && !ss->from_string )
+ { check_p(1);
+ switch ( (c = *++p) )
+ {
+ case 'n':
+ c = '\n';
+ goto put;
+ case 'r':
+ c = '\r';
+ goto put;
+ case 't':
+ c = '\t';
+ goto put;
+ case 'b':
+ c = '\b';
+ goto put;
+ case 'f':
+ c = '\f';
+ goto put;
+ default: /* ignore the \ */
+put: check_q(2);
+ *++q = c;
+ continue;
+ case char_CR: /* ignore, check for following \n */
+ check_p(2);
+ if ( p[1] == char_EOL )
+ p++;
+ continue;
+ case char_EOL: /* ignore */
+ continue;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ { int d;
+ check_p(2);
+ d = p[1];
+ c -= '0';
+ if ( d >= '0' && d <= '7' )
+ { if ( p + 1 == rlimit )
+ { p -= 2;
+ goto out;
+ }
+ check_q(2);
+ c = (c << 3) + d - '0';
+ d = p[2];
+ if ( d >= '0' && d <= '7' )
+ { c = (c << 3) + d - '0';
+ p += 2;
+ }
+ else
+ p++;
+ }
+ else
+ check_q(2);
+ *++q = c;
+ continue;
+ }
+ }
+ }
+ else
+ switch ( c )
+ {
+ case '(':
+ check_q(1);
+ ss->depth++;
+ break;
+ case ')':
+ if ( ss->depth == 0 )
+ { status = EOFC;
+ goto out;
+ }
+ check_q(1);
+ ss->depth--;
+ break;
+ case char_CR: /* convert to \n */
+ check_p(1);
+ check_q(1);
+ if ( p[1] == char_EOL )
+ p++;
+ *++q = '\n';
+ continue;
+ case char_EOL:
+ c = '\n';
+ default:
+ check_q(1);
+ break;
+ }
+ *++q = c;
+ }
+#undef check_p
+#undef check_q
+out: pr->ptr = p;
+ pw->ptr = q;
+ if ( last && status == 0 && p != rlimit )
+ status = ERRC;
+ return status;
+}
+
+#undef ss
+
+/* Stream template */
+const stream_template s_PSSD_template =
+{ &st_PSSD_state, s_PSSD_init, s_PSSD_process, 4, 1
+};
+
+/* ------ Utilities ------ */
+
+/*
+ * Convert hex data to binary. Return 1 if we filled the string, 0 if
+ * we ran out of input data before filling the string, or ERRC on error.
+ * The caller must set *odd_digit to -1 before the first call;
+ * after each call, if an odd number of hex digits has been read (total),
+ * *odd_digit is the odd digit value, otherwise *odd_digit = -1.
+ * See strimpl.h for the definition of syntax.
+ */
+int
+s_hex_process(stream_cursor_read *pr, stream_cursor_write *pw,
+ int *odd_digit, hex_syntax syntax)
+{ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ byte *q0 = q;
+ byte val1 = (byte)*odd_digit;
+ byte val2;
+ uint rcount;
+ byte *flimit;
+ register const byte _ds *decoder = scan_char_decoder;
+ int code = 0;
+ if ( q >= wlimit )
+ return 1;
+ if ( val1 <= 0xf )
+ goto d2;
+d1: if ( (rcount = (rlimit - p) >> 1) == 0 )
+ goto x1;
+ /* Set up a fast end-of-loop check, so we don't have to test */
+ /* both p and q against their respective limits. */
+ flimit = (rcount < wlimit - q ? q + rcount : wlimit);
+f1: if ( (val1 = decoder[p[1]]) <= 0xf &&
+ (val2 = decoder[p[2]]) <= 0xf
+ )
+ { p += 2;
+ *++q = (val1 << 4) + val2;
+ if ( q < flimit )
+ goto f1;
+ if ( q >= wlimit )
+ goto px;
+ }
+x1: if ( p >= rlimit )
+ goto end1;
+ if ( (val1 = decoder[*++p]) > 0xf )
+ { if ( val1 == ctype_space )
+ { switch ( syntax )
+ {
+ case hex_ignore_whitespace:
+ goto x1;
+ case hex_ignore_leading_whitespace:
+ if ( q == q0 && *odd_digit < 0 )
+ goto x1;
+ --p;
+ code = 1;
+ goto end1;
+ case hex_ignore_garbage:
+ goto x1;
+ }
+ }
+ else if ( syntax == hex_ignore_garbage )
+ goto x1;
+ code = ERRC;
+ goto end1;
+ }
+d2: if ( p >= rlimit )
+ { *odd_digit = val1;
+ goto ended;
+ }
+ if ( (val2 = decoder[*++p]) > 0xf )
+ { if ( val2 == ctype_space )
+ switch ( syntax )
+ {
+ case hex_ignore_whitespace:
+ goto d2;
+ case hex_ignore_leading_whitespace:
+ if ( q == q0 )
+ goto d2;
+ --p;
+ *odd_digit = val1;
+ code = 1;
+ goto ended;
+ case hex_ignore_garbage: /* pacify compilers */
+ ;
+ }
+ if ( syntax == hex_ignore_garbage )
+ goto d2;
+ *odd_digit = val1;
+ code = ERRC;
+ goto ended;
+ }
+ *++q = (val1 << 4) + val2;
+ if ( q < wlimit ) goto d1;
+px: code = 1;
+end1: *odd_digit = -1;
+ended: pr->ptr = p;
+ pw->ptr = q;
+ return code;
+}
diff --git a/gs/src/sstring.h b/gs/src/sstring.h
new file mode 100644
index 000000000..62646cb62
--- /dev/null
+++ b/gs/src/sstring.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* sstring.h */
+/* Definitions for string encoding/decoding streams */
+/* Requires scommon.h; should require strimpl.h only if any templates */
+/* are referenced, but some compilers always require strimpl.h. */
+
+/* ASCIIHexEncode */
+/* (no state) */
+extern const stream_template s_AXE_template;
+
+/* ASCIIHexDecode */
+typedef struct stream_AXD_state_s {
+ stream_state_common;
+ int odd; /* odd digit */
+} stream_AXD_state;
+#define private_st_AXD_state() /* in sstring.c */\
+ gs_private_st_simple(st_AXD_state, stream_AXD_state,\
+ "ASCIIHexDecode state")
+/* We define the initialization procedure here, so that the scanner */
+/* can avoid a procedure call. */
+#define s_AXD_init_inline(ss)\
+ ((ss)->odd = -1, 0)
+extern const stream_template s_AXD_template;
+
+/* PSStringDecode */
+typedef struct stream_PSSD_state_s {
+ stream_state_common;
+ /* The following are set by the client. */
+ bool from_string; /* true if using Level 1 \ convention */
+ /* The following change dynamically. */
+ int depth;
+} stream_PSSD_state;
+#define private_st_PSSD_state() /* in sstring.c */\
+ gs_private_st_simple(st_PSSD_state, stream_PSSD_state, "PSStringDecode state")
+/* We define the initialization procedure here, so that the scanner */
+/* can avoid a procedure call. */
+#define s_PSSD_init_inline(ss)\
+ ((ss)->depth = 0)
+extern const stream_template s_PSSD_template;
+
+/* PSStringEncode */
+/* (no state) */
+extern const stream_template s_PSSE_template;
+
diff --git a/gs/src/stat_.h b/gs/src/stat_.h
new file mode 100644
index 000000000..e48fede95
--- /dev/null
+++ b/gs/src/stat_.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* stat_.h */
+/* Generic substitute for Unix sys/stat.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+#include <sys/stat.h>
+
+/* Many environments, including the MS-DOS compilers, don't define */
+/* the st_blocks member of a stat structure. */
+#if defined(__SVR3) || defined(__EMX__) || defined(__DVX__) || defined(OSK) || defined(__MSDOS__) || defined(__QNX__) || defined(VMS) || defined(__WIN32__) || defined(__IBMC__) || defined(__BEOS__)
+# define stat_blocks(psbuf) (((psbuf)->st_size + 1023) >> 10)
+#else
+# define stat_blocks(psbuf) ((psbuf)->st_blocks)
+#endif
+
+/* Microsoft C uses _stat instead of stat, */
+/* for both the function name and the structure name. */
+#ifdef _MSC_VER
+# define stat _stat
+#endif
+
+/* Some (System V?) systems test for directories */
+/* in a slightly different way. */
+#if defined(OSK) || !defined(S_ISDIR)
+# define stat_is_dir(stbuf) ((stbuf).st_mode & S_IFDIR)
+#else
+# define stat_is_dir(stbuf) S_ISDIR((stbuf).st_mode)
+#endif
diff --git a/gs/src/std.h b/gs/src/std.h
new file mode 100644
index 000000000..e37906847
--- /dev/null
+++ b/gs/src/std.h
@@ -0,0 +1,220 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* std.h */
+/* Standard definitions for Aladdin Enterprises code */
+
+#ifndef std_INCLUDED
+# define std_INCLUDED
+
+#include "stdpre.h"
+
+/* Include the architecture definitions. */
+#include "arch.h"
+
+/* Define integer data type sizes in terms of log2s. */
+#define arch_sizeof_short (1 << arch_log2_sizeof_short)
+#define arch_sizeof_int (1 << arch_log2_sizeof_int)
+#define arch_sizeof_long (1 << arch_log2_sizeof_long)
+#define arch_ints_are_short (arch_sizeof_int == arch_sizeof_short)
+
+/* Define whether we are on a large- or small-memory machine. */
+/* Currently, we assume small memory and 16-bit ints are synonymous. */
+#define arch_small_memory (arch_sizeof_int <= 2)
+
+/* Define unsigned 16- and 32-bit types. These are needed in */
+/* a surprising number of places that do bit manipulation. */
+#if arch_sizeof_short == 2 /* no plausible alternative! */
+typedef ushort bits16;
+#endif
+#if arch_sizeof_int == 4
+typedef uint bits32;
+#else
+# if arch_sizeof_long == 4
+typedef ulong bits32;
+# endif
+#endif
+
+/* Minimum and maximum values for the signed types. */
+/* Avoid casts, to make them acceptable to strict ANSI compilers. */
+#define min_short (-1 << (arch_sizeof_short * 8 - 1))
+#define max_short (~min_short)
+#define min_int (-1 << (arch_sizeof_int * 8 - 1))
+#define max_int (~min_int)
+#define min_long (-1L << (arch_sizeof_long * 8 - 1))
+#define max_long (~min_long)
+
+/*
+ * The maximum values for the unsigned types are defined in arch.h,
+ * because so many compilers handle unsigned constants wrong.
+ * In particular, most of the DEC VMS compilers incorrectly sign-extend
+ * short unsigned constants (but not short unsigned variables) when
+ * widening them to longs. We program around this on a case-by-case basis.
+ * Some compilers don't truncate constants when they are cast down.
+ * The UTek compiler does special weird things of its own.
+ * All the rest (including gcc on all platforms) do the right thing.
+ */
+#define max_uchar arch_max_uchar
+#define max_ushort arch_max_ushort
+#define max_uint arch_max_uint
+#define max_ulong arch_max_ulong
+
+/* Minimum and maximum values for pointers. */
+#if arch_ptrs_are_signed
+# define min_ptr min_long
+# define max_ptr max_long
+#else
+# define min_ptr ((ulong)0)
+# define max_ptr max_ulong
+#endif
+
+/*
+ * Define whether pointers are segmented. If they are, we assume that
+ * the compiler can't do reasonable register assignment for pointers,
+ * so sometimes we use in-line casts instead of assignment to
+ * a logically redundant pointer of the proper type.
+ */
+#define arch_ptrs_are_segmented (arch_sizeof_ds_ptr < arch_sizeof_ptr)
+
+/* Define a reliable arithmetic right shift. */
+/* Must use arith_rshift_1 for a shift by a literal 1. */
+#define arith_rshift_slow(x,n) ((x) < 0 ? ~(~(x) >> (n)) : (x) >> (n))
+#if arch_arith_rshift == 2
+# define arith_rshift(x,n) ((x) >> (n))
+# define arith_rshift_1(x) ((x) >> 1)
+#else
+#if arch_arith_rshift == 1 /* OK except for n=1 */
+# define arith_rshift(x,n) ((x) >> (n))
+# define arith_rshift_1(x) arith_rshift_slow(x,1)
+#else
+# define arith_rshift(x,n) arith_rshift_slow(x,n)
+# define arith_rshift_1(x) arith_rshift_slow(x,1)
+#endif
+#endif
+
+/*
+ * Standard error printing macros.
+ * Use dprintf for messages that just go to dstderr,
+ * eprintf for error messages to estderr that include the program name,
+ * lprintf for debugging messages that should include line number info.
+ * Since we intercept fprintf to redirect output under MS Windows,
+ * we have to define dputc and dputs in terms of fprintf also.
+ * We also define eprintf and lprintf in a way that allows us to
+ * intercept all calls to them by redefining eprintf_program_name
+ * and lprintf_file_and_line.
+ */
+
+/* dstderr and estderr may be redefined. */
+#define dstderr stderr
+#define estderr stderr
+
+#define dputc(chr) dprintf1("%c", chr)
+#define dputs(str) dprintf1("%s", str)
+#define dprintf(str)\
+ fprintf(dstderr, str)
+#define dprintf1(str,arg1)\
+ fprintf(dstderr, str, arg1)
+#define dprintf2(str,arg1,arg2)\
+ fprintf(dstderr, str, arg1, arg2)
+#define dprintf3(str,arg1,arg2,arg3)\
+ fprintf(dstderr, str, arg1, arg2, arg3)
+#define dprintf4(str,arg1,arg2,arg3,arg4)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4)
+#define dprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5)
+#define dprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6)
+#define dprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+#define dprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+#define dprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+#define dprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
+#define dprintf11(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)
+#define dprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+
+/* eprintf_program_name may be redefined. */
+#define eprintf_program_name(f, program_name)\
+ fprintf(f, "%s: ", program_name)
+#ifdef PROGRAM_NAME
+extern const char *PROGRAM_NAME;
+# define _epn eprintf_program_name(estderr, PROGRAM_NAME),
+#else
+# define _epn /* */
+#endif
+
+#define eprintf(str)\
+ (_epn fprintf(estderr, str))
+#define eprintf1(str,arg1)\
+ (_epn fprintf(estderr, str, arg1))
+#define eprintf2(str,arg1,arg2)\
+ (_epn fprintf(estderr, str, arg1, arg2))
+#define eprintf3(str,arg1,arg2,arg3)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3))
+#define eprintf4(str,arg1,arg2,arg3,arg4)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4))
+#define eprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5))
+#define eprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6))
+#define eprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+#define eprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+#define eprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+#define eprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
+
+/* lprintf_file_and_line may be redefined. */
+#define lprintf_file_and_line(f, file, line)\
+ fprintf(f, "%s(%d): ", file, line)
+#if __LINE__ /* compiler provides it */
+# define _epl _epn lprintf_file_and_line(estderr, __FILE__, __LINE__),
+#else
+# define _epl _epn
+#endif
+
+#define lprintf(str)\
+ (_epl fprintf(estderr, str))
+#define lprintf1(str,arg1)\
+ (_epl fprintf(estderr, str, arg1))
+#define lprintf2(str,arg1,arg2)\
+ (_epl fprintf(estderr, str, arg1, arg2))
+#define lprintf3(str,arg1,arg2,arg3)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3))
+#define lprintf4(str,arg1,arg2,arg3,arg4)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4))
+#define lprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5))
+#define lprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6))
+#define lprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+#define lprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+#define lprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+#define lprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
+
+#endif /* std_INCLUDED */
diff --git a/gs/src/stdio_.h b/gs/src/stdio_.h
new file mode 100644
index 000000000..8c7a9f99d
--- /dev/null
+++ b/gs/src/stdio_.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* stdio_.h */
+/* Generic substitute for stdio.h */
+
+/* This is here primarily because we must include std.h before */
+/* any file that includes sys/types.h. */
+#include "std.h"
+#include <stdio.h>
+
+#ifdef VMS
+/* VMS doesn't have the unlink system call. Use delete instead. */
+# ifdef __DECC
+# include <unixio.h>
+# endif
+# define unlink(fname) delete(fname)
+#else
+/* Other systems may or may not declare unlink in stdio.h; */
+/* if they do, the declaration will be compatible with this one. */
+int unlink(P1(const char *));
+#endif
+
+/* Patch a couple of things possibly missing from stdio.h. */
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
diff --git a/gs/src/stdpre.h b/gs/src/stdpre.h
new file mode 100644
index 000000000..753d04b31
--- /dev/null
+++ b/gs/src/stdpre.h
@@ -0,0 +1,378 @@
+/* Copyright (C) 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* stdpre.h */
+/* Standard definitions for Aladdin Enterprises code not needing arch.h */
+
+#ifndef stdpre_INCLUDED
+# define stdpre_INCLUDED
+
+/*
+ * Here we deal with the vagaries of various C compilers. We assume that:
+ * ANSI-standard Unix compilers define __STDC__.
+ * Borland Turbo C and Turbo C++ define __MSDOS__ and __TURBOC__.
+ * Borland C++ defines __BORLANDC__, __MSDOS__, and __TURBOC__.
+ * Microsoft C/C++ defines _MSC_VER and _MSDOS.
+ * Watcom C defines __WATCOMC__ and MSDOS.
+ *
+ * We arrange to define __MSDOS__ on all the MS-DOS platforms.
+ */
+#if (defined(MSDOS) || defined(_MSDOS)) && !defined(__MSDOS__)
+# define __MSDOS__
+#endif
+/*
+ * Also, not used much here, but used in other header files, we assume:
+ * Unix System V environments define SYSV.
+ * The SCO ODT compiler defines M_SYSV and M_SYS3.
+ * VMS systems define VMS.
+ * OSF/1 compilers define __osf__ or __OSF__.
+ * (The VMS and OSF/1 C compilers handle prototypes and const,
+ * but do not define __STDC__.)
+ * bsd 4.2 or 4.3 systems define BSD4_2.
+ * POSIX-compliant environments define _POSIX_SOURCE.
+ * Motorola 88K BCS/OCS systems defined m88k.
+ *
+ * We make fairly heroic efforts to confine all uses of these flags to
+ * header files, and never to use them in code.
+ */
+#if defined(__osf__) && !defined(__OSF__)
+# define __OSF__ /* */
+#endif
+#if defined(M_SYSV) && !defined(SYSV)
+# define SYSV /* */
+#endif
+#if defined(M_SYS3) && !defined(__SVR3)
+# define __SVR3 /* */
+#endif
+
+#if defined(__STDC__) || defined(__MSDOS__) || defined(__convex__) || defined(VMS) || defined(__OSF__) || defined(__WIN32__) || defined(__IBMC__) || defined(M_UNIX) || defined(__GNUC__) || defined(__BORLANDC__)
+# if !(defined(M_XENIX) && !defined(__GNUC__)) /* SCO Xenix cc is broken */
+# define __PROTOTYPES__ /* */
+# endif
+#endif
+
+/* Define dummy values for __FILE__ and __LINE__ if the compiler */
+/* doesn't provide these. Note that places that use __FILE__ */
+/* must check explicitly for a null pointer. */
+#ifndef __FILE__
+# define __FILE__ NULL
+#endif
+#ifndef __LINE__
+# define __LINE__ 0
+#endif
+
+/* Disable 'const' and 'volatile' if the compiler can't handle them. */
+#ifndef __PROTOTYPES__
+# undef const
+# define const /* */
+# undef volatile
+# define volatile /* */
+#endif
+
+/*
+ * Some compilers give a warning if a function call that returns a value
+ * is used as a statement; a few compilers give an error for the construct
+ * (void)0, which is contrary to the ANSI standard. Since we don't know of
+ * any compilers that do both, we define a macro here for discarding
+ * the value of an expression statement, which can be defined as either
+ * including or not including the cast. (We don't conditionalize this here,
+ * because no commercial compiler gives the error on (void)0, although
+ * some give warnings.)
+ */
+#define discard(expr) ((void)(expr))
+
+/*
+ * The SVR4.2 C compiler incorrectly considers the result of << and >>
+ * to be unsigned if the left operand is signed and the right operand is
+ * unsigned. We believe this only causes trouble in Ghostscript code when
+ * the right operand is a sizeof(...), which is unsigned for this compiler.
+ * Therefore, we replace the relevant uses of sizeof with size_of:
+ */
+#define size_of(x) ((int)(sizeof(x)))
+
+/*
+ * Disable MS-DOS specialized pointer types on non-MS-DOS systems.
+ * Watcom C defines near, far, and huge as macros, so we must undef them.
+ * far_data is used for static data that must get its own segment.
+ * This is supported in Borland C++, but none of the others.
+ */
+#undef far_data
+#if defined(__TURBOC__) && !defined(__WIN32__)
+# ifdef __BORLANDC__
+# define far_data far
+# else
+# define far_data /* */
+# endif
+#else
+# undef near
+# define near /* */
+# undef far
+# define far /* */
+# define far_data /* */
+# undef huge
+# define huge /* */
+# define _cs /* */
+# define _ds /* */
+/* _es is never safe to use */
+# define _ss /* */
+#endif
+
+/* Get the size of a statically declared array. */
+#define countof(a) (sizeof(a) / sizeof((a)[0]))
+#define count_of(a) (size_of(a) / size_of((a)[0]))
+
+/*
+ * Get the offset of a structure member. Amazingly enough, the simpler
+ * definition works on all compilers except for one broken MIPS compiler
+ * and the IBM RS/6000. Unfortunately, because of these two compilers,
+ * we have to use the more complex definition. Even more unfortunately,
+ * the more complex definition doesn't work on the MetroWerks
+ * CodeWarrior compiler (Macintosh and BeOS).
+ */
+#ifdef __MWERKS__
+#define offset_of(type, memb)\
+ ((int) &((type *) 0)->memb)
+#else
+#define offset_of(type, memb)\
+ ((int) ( (char *)&((type *)0)->memb - (char *)((type *)0) ))
+#endif
+
+/*
+ * Get the alignment of a pointer modulo a given power of 2.
+ * There is no portable way to do this, but the following definition
+ * works on all reasonable systems.
+ */
+#define alignment_mod(ptr, modu)\
+ ((uint)( ((const char *)(ptr) - (const char *)0) & ((modu) - 1) ))
+
+/* Define short names for the unsigned types. */
+typedef unsigned char byte;
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+/* Since sys/types.h often defines one or more of these (depending on */
+/* the platform), we have to take steps to prevent name clashes. */
+/*** NOTE: This requires that you include std.h *before* any other ***/
+/*** header file that includes sys/types.h. ***/
+#define bool bool_ /* (maybe not needed) */
+#define uchar uchar_
+#define uint uint_
+#define ushort ushort_
+#define ulong ulong_
+#include <sys/types.h>
+#undef bool
+#undef uchar
+#undef uint
+#undef ushort
+#undef ulong
+
+/*
+ * Define a Boolean type. Even though we would like it to be
+ * unsigned char, it pretty well has to be int, because
+ * that's what all the relational operators and && and || produce.
+ * We can't make it an enumerated type, because ints don't coerce
+ * freely to enums (although the opposite is true).
+ * Unfortunately, at least some C++ compilers have a built-in bool type,
+ * and the MetroWerks C++ compiler insists that bool be equivalent to
+ * unsigned char.
+ */
+#ifndef __cplusplus
+#ifdef __BEOS__
+typedef unsigned char bool;
+#else
+typedef int bool;
+#endif
+#endif
+/*
+ * MetroWerks CodeWarrior predefines true and false, probably as 1 and 0.
+ * We need to cancel those definitions for our own code.
+ */
+#undef false
+#define false ((bool)0)
+#undef true
+#define true ((bool)1)
+
+/*
+ * Compilers disagree as to whether macros used in macro arguments
+ * should be expanded at the time of the call, or at the time of
+ * final expansion. Even authoritative documents disagree: the ANSI
+ * standard says the former, but Harbison and Steele's book says the latter.
+ * In order to work around this discrepancy, we have to do some very
+ * ugly things in a couple of places. We mention it here because
+ * it might well trip up future developers.
+ */
+
+/*
+ * Define the type to be used for ordering pointers (<, >=, etc.).
+ * The Borland and Microsoft large models only compare the offset part
+ * of segmented pointers. Semantically, the right type to use for the
+ * comparison is char huge *, but we have no idea how expensive comparing
+ * such pointers is, and any type that compares all the bits of the pointer,
+ * gives the right result for pointers in the same segment, and keeps
+ * different segments disjoint will do.
+ */
+#if defined(__TURBOC__) || defined(_MSC_VER)
+typedef unsigned long ptr_ord_t;
+#else
+typedef const char *ptr_ord_t;
+#endif
+/* Define all the pointer comparison operations. */
+#define _ptr_cmp(p1, rel, p2) ((ptr_ord_t)(p1) rel (ptr_ord_t)(p2))
+#define ptr_le(p1, p2) _ptr_cmp(p1, <=, p2)
+#define ptr_lt(p1, p2) _ptr_cmp(p1, <, p2)
+#define ptr_ge(p1, p2) _ptr_cmp(p1, >=, p2)
+#define ptr_gt(p1, p2) _ptr_cmp(p1, >, p2)
+#define ptr_between(ptr, lo, hi)\
+ (ptr_ge(ptr, lo) && ptr_lt(ptr, hi))
+
+/* Define min and max, but make sure to use the identical definition */
+/* to the one that all the compilers seem to have.... */
+#ifndef min
+# define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+# define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/* Define a standard way to round values to a (constant) modulus. */
+#define round_down(value, modulus)\
+ ( (modulus) & ((modulus) - 1) ? /* not a power of 2 */\
+ (value) - (value) % (modulus) :\
+ (value) & -(modulus) )
+#define round_up(value, modulus)\
+ ( (modulus) & ((modulus) - 1) ? /* not a power of 2 */\
+ ((value) + ((modulus) - 1)) / (modulus) * (modulus) :\
+ ((value) + ((modulus) - 1)) & -(modulus) )
+
+/*
+ * In pre-ANSI C, float parameters get converted to double.
+ * However, if we pass a float to a function that has been declared
+ * with a prototype, and the parameter has been declared as float,
+ * the ANSI standard specifies that the parameter is left as float.
+ * To avoid problems caused by missing prototypes,
+ * we declare almost all float parameters as double.
+ */
+typedef double floatp;
+
+/*
+ * Define a handy macro for a statement that does nothing.
+ * We can't just use an empty body, since this upsets some compilers.
+ * We can't use the obvious
+ * if (0)
+ * since that could "capture" a following statement if used incorrectly.
+ */
+#ifndef DO_NOTHING
+# define DO_NOTHING do {} while (0)
+#endif
+
+/*
+ * For accountability, debugging, and error messages,
+ * we pass a client identification string to alloc and free,
+ * and possibly other places as well.
+ * Define the type for these strings. Note that because of the _ds,
+ * we must coerce them explicitly when passing them to printf et al.
+ */
+typedef const char _ds *client_name_t;
+#define client_name_string(cname) ((const char *)(cname))
+
+/*
+ * If we are debugging, make all static variables and procedures public
+ * so they get passed through the linker.
+ */
+#define public /* */
+/*
+ * We separate out the definition of private this way so that
+ * we can temporarily #undef it to handle the X Windows headers,
+ * which define a member named private.
+ */
+#ifdef NOPRIVATE
+# define private_ /* */
+#else
+# define private_ static
+#endif
+#define private private_
+
+/*
+ * Macros for argument templates. ANSI C has these, as does Turbo C,
+ * but older pcc-derived (K&R) Unix compilers don't. The syntax is
+ * resulttype func(Pn(arg1, ..., argn));
+ */
+
+#ifdef __PROTOTYPES__
+# define P0() void
+# define P1(t1) t1
+# define P2(t1,t2) t1,t2
+# define P3(t1,t2,t3) t1,t2,t3
+# define P4(t1,t2,t3,t4) t1,t2,t3,t4
+# define P5(t1,t2,t3,t4,t5) t1,t2,t3,t4,t5
+# define P6(t1,t2,t3,t4,t5,t6) t1,t2,t3,t4,t5,t6
+# define P7(t1,t2,t3,t4,t5,t6,t7) t1,t2,t3,t4,t5,t6,t7
+# define P8(t1,t2,t3,t4,t5,t6,t7,t8) t1,t2,t3,t4,t5,t6,t7,t8
+# define P9(t1,t2,t3,t4,t5,t6,t7,t8,t9) t1,t2,t3,t4,t5,t6,t7,t8,t9
+# define P10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10
+# define P11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11
+# define P12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12
+# define P13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13
+# define P14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14
+# define P15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15
+#else
+# define P0() /* */
+# define P1(t1) /* */
+# define P2(t1,t2) /* */
+# define P3(t1,t2,t3) /* */
+# define P4(t1,t2,t3,t4) /* */
+# define P5(t1,t2,t3,t4,t5) /* */
+# define P6(t1,t2,t3,t4,t5,t6) /* */
+# define P7(t1,t2,t3,t4,t5,t6,t7) /* */
+# define P8(t1,t2,t3,t4,t5,t6,t7,t8) /* */
+# define P9(t1,t2,t3,t4,t5,t6,t7,t8,t9) /* */
+# define P10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) /* */
+# define P11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) /* */
+# define P12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) /* */
+# define P13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) /* */
+# define P14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) /* */
+# define P15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) /* */
+#endif
+
+/* Define success and failure codes for 'exit'. */
+#ifdef VMS
+# define exit_OK 1
+# define exit_FAILED 18
+#else
+# define exit_OK 0
+# define exit_FAILED 1
+#endif
+/*
+ * Define the informational exit status.
+ * We need to distinguish information returns because under MS Windows,
+ * they must return like an error so that the text window stays on the
+ * screen, while on other platforms, they must return successfully.
+ * Note that we define both gs_exit_INFO (before platform-specific
+ * mapping of 0 to exit_OK and 1 to exit_FAILED) and exit_INFO.
+ */
+#if defined(_WINDOWS) || defined(_Windows)
+# define exit_INFO exit_FAILED
+# define gs_exit_INFO 1
+#else
+# define exit_INFO exit_OK
+# define gs_exit_INFO 0
+#endif
+
+#endif /* stdpre_INCLUDED */
diff --git a/gs/src/store.h b/gs/src/store.h
new file mode 100644
index 000000000..34e7d1d20
--- /dev/null
+++ b/gs/src/store.h
@@ -0,0 +1,238 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* store.h */
+/* Assignment-related macros */
+#include "ialloc.h" /* for imemory masks & checks */
+
+/*
+ * Macros for storing a ref. We use macros for storing into objects,
+ * since the storage manager needs to be able to track stores for
+ * save/restore and also for global/local checking.
+ * We also use macros for other ref assignments, because (as it happens)
+ * Turbo C generates pretty awful code for doing this.
+ *
+ * There are three cases that we need to distinguish:
+ * - Storing to a stack (no special action);
+ * - Storing into a newly created object (set l_new);
+ * - Storing into a slot of an existing object (check l_new in
+ * old value, set in new value).
+ * The macros are called
+ * <make/store><new_type><case>(place_to_store, new_value)
+ * where <case> is nothing for storing to the stack, _new for storing into
+ * a new object, and _old for storing into an existing object.
+ * (The _old macros also take a client name for tracing and debugging.)
+ * <new_type> and new_value are chosen from the following alternatives:
+ * ref_assign POINTER TO arbitrary ref
+ * make_t type (only for null and mark)
+ * make_tv type, value field name, value
+ * (only for scalars, which don't have attributes)
+ * make_tav type, attributes, value field name, value
+ * make_tasv type, attributes, size, value field name, value
+ * There are also specialized make_ macros for specific types:
+ * make_array, make_int, make_real, make_bool, make_false, make_true,
+ * make_mark, make_null, make_oper, make_[const_]string, make_struct.
+ * Not all of the specialized make_ macros have _new and _old variants.
+ *
+ * For _tav and _tasv, we must store the value first, because sometimes
+ * it depends on the contents of the place being stored into.
+ *
+ * Note that for composite objects (dictionary, file, array, string, device,
+ * struct), we must set a_foreign if the contents are allocated statically
+ * (e.g., for constant C strings) or not by the Ghostscript allocator
+ * (e.g., with malloc).
+ */
+
+/*
+ * Define the most efficient ref assignment macro for the platform.
+ */
+/*
+ * Assigning the components individually is fastest on Turbo C,
+ * and on Watcom C when one or both of the addresses are
+ * already known or in a register.
+ */
+#define ref_assign_inline(pto,pfrom)\
+ ((pto)->value = (pfrom)->value,\
+ (pto)->tas = (pfrom)->tas)
+#ifdef __TURBOC__
+ /*
+ * Move the data in two 32-bit chunks, because
+ * otherwise the compiler calls SCOPY@.
+ * The cast to void is to discourage the compiler from
+ * wanting to deliver the value of the expression.
+ */
+# define ref_assign(pto,pfrom)\
+ discard(ref_assign_inline(pto, pfrom))
+#else
+ /*
+ * Trust the compiler and hope for the best.
+ * The MIPS compiler doesn't like the cast to void.
+ */
+# define ref_assign(pto,pfrom)\
+ (*(pto) = *(pfrom))
+#endif
+
+/****** NOTE: the following declarations are duplicated from isave.h. ******/
+
+int alloc_save_change(P4(gs_dual_memory_t *, const ref *pcont,
+ ref_packed *ptr, client_name_t cname));
+int alloc_save_level(P1(const gs_dual_memory_t *));
+
+/****** END duplicated declarations. ******/
+
+#define ialloc_save_change(pcont, ptr, cname)\
+ alloc_save_change(idmemory, pcont, ptr, cname)
+#define ialloc_is_in_save() (idmemory->save_level > 0)
+#define ialloc_test_mask (idmemory->test_mask)
+#define ialloc_new_mask (idmemory->new_mask)
+#define ref_must_save(pto)\
+ ((r_type_attrs(pto) & ialloc_test_mask) == 0)
+#define ref_do_save(pcont, pto, cname)\
+ ialloc_save_change(pcont, (ref_packed *)(pto), cname)
+#define ref_save(pcont, pto, cname)\
+ discard((ref_must_save(pto) ? ref_do_save(pcont, pto, cname) : 0))
+#define ref_mark_new(pto) ((pto)->tas.type_attrs |= ialloc_new_mask)
+#define ref_assign_new(pto,pfrom)\
+ discard((ref_assign(pto,pfrom), ref_mark_new(pto)))
+#define ref_assign_new_inline(pto,pfrom)\
+ discard((ref_assign_inline(pto,pfrom), ref_mark_new(pto)))
+#define ref_assign_old(pcont,pto,pfrom,cname)\
+ (ref_save(pcont,pto,cname), ref_assign_new(pto,pfrom))
+#define ref_assign_old_inline(pcont,pto,pfrom,cname)\
+ (ref_save(pcont,pto,cname), ref_assign_new_inline(pto,pfrom))
+/* ref_mark_old is only needed in very unusual situations, namely, */
+/* when we want to do a ref_save just before a save instead of */
+/* when the actual assignment occurs. */
+#define ref_mark_old(pto) ((pto)->tas.type_attrs &= ~ialloc_new_mask)
+
+/* Define macros for conditionally clearing the parts of a ref */
+/* that aren't being set to anything useful. */
+
+#ifdef DEBUG
+# define and_fill_s(pref)\
+ , (gs_debug['$'] ? r_set_size(pref, 0xfeed) : 0)
+# define and_fill_sv(pref)\
+ , (gs_debug['$'] ? (r_set_size(pref, 0xfeed),\
+ (pref)->value.intval = 0xdeadbeef) : 0)
+#else /* !DEBUG */
+# define and_fill_s(pref) /* */
+# define and_fill_sv(pref) /* */
+#endif
+
+/* make_t must set the attributes to 0 to clear a_local! */
+#define make_t(pref,newtype)\
+ (r_set_type_attrs(pref, newtype, 0) and_fill_sv(pref))
+#define make_t_new(pref,newtype)\
+ (r_set_type_attrs(pref, newtype, ialloc_new_mask) and_fill_sv(pref))
+#define make_t_old(pcont,pref,newtype,cname)\
+ (ref_save(pcont,pref,cname), make_t_new(pref,newtype))
+
+#define make_tav(pref,newtype,newattrs,valfield,newvalue)\
+ ((pref)->value.valfield = (newvalue),\
+ r_set_type_attrs(pref, newtype, newattrs)\
+ and_fill_s(pref))
+#define make_tav_new(pref,t,a,vf,v)\
+ make_tav(pref,t,(a)|ialloc_new_mask,vf,v)
+#define make_tav_old(pcont,pref,t,a,vf,v,cname)\
+ (ref_save(pcont,pref,cname), make_tav_new(pref,t,a,vf,v))
+
+#define make_tv(pref,newtype,valfield,newvalue)\
+ make_tav(pref,newtype,0,valfield,newvalue)
+#define make_tv_new(pref,t,vf,v)\
+ make_tav_new(pref,t,0,vf,v)
+#define make_tv_old(pcont,pref,t,vf,v,cname)\
+ make_tav_old(pcont,pref,t,0,vf,v,cname)
+
+#define make_tasv(pref,newtype,newattrs,newsize,valfield,newvalue)\
+ ((pref)->value.valfield = (newvalue),\
+ r_set_type_attrs(pref, newtype, newattrs),\
+ r_set_size(pref, newsize))
+#define make_tasv_new(pref,t,a,s,vf,v)\
+ make_tasv(pref,t,(a)|ialloc_new_mask,s,vf,v)
+#define make_tasv_old(pcont,pref,t,a,s,vf,v,cname)\
+ (ref_save(pcont,pref,cname), make_tasv_new(pref,t,a,s,vf,v))
+
+/* Type-specific constructor macros for scalar (non-composite) types */
+
+#define make_bool(pref,bval)\
+ make_tv(pref, t_boolean, boolval, bval)
+#define make_false(pref)\
+ make_bool(pref, 0)
+#define make_true(pref)\
+ make_bool(pref, 1)
+
+#define make_int(pref,ival)\
+ make_tv(pref, t_integer, intval, ival)
+#define make_int_new(pref,ival)\
+ make_tv_new(pref, t_integer, intval, ival)
+
+#define make_mark(pref)\
+ make_t(pref, t_mark)
+
+#define make_null(pref)\
+ make_t(pref, t_null)
+#define make_null_new(pref)\
+ make_t_new(pref, t_null)
+#define make_null_old(pcont,pref,cname)\
+ make_t_old(pcont, pref, t_null, cname)
+
+#define make_oper(pref,opidx,proc)\
+ make_tasv(pref, t_operator, a_executable, opidx, opproc, proc)
+#define make_oper_new(pref,opidx,proc)\
+ make_tasv_new(pref, t_operator, a_executable, opidx, opproc, proc)
+
+#define make_real(pref,rval)\
+ make_tv(pref, t_real, realval, rval)
+#define make_real_new(pref,rval)\
+ make_tv_new(pref, t_real, realval, rval)
+
+/* Type-specific constructor macros for composite types */
+
+/* For composite types, the a_space field is relevant; however, */
+/* as noted in ivmspace.h, a value of 0 designates the most static space, */
+/* so for making empty composites, a space value of 0 is appropriate. */
+
+#define make_array(pref,attrs,size,elts)\
+ make_tasv(pref, t_array, attrs, size, refs, elts)
+#define make_array_new(pref,attrs,size,elts)\
+ make_tasv_new(pref, t_array, attrs, size, refs, elts)
+#define make_const_array(pref,attrs,size,elts)\
+ make_tasv(pref, t_array, attrs, size, const_refs, elts)
+#define make_empty_array(pref,attrs)\
+ make_array(pref, attrs, 0, (ref *)NULL)
+#define make_empty_const_array(pref,attrs)\
+ make_const_array(pref, attrs, 0, (const ref *)NULL)
+
+#define make_string(pref,attrs,size,chars)\
+ make_tasv(pref, t_string, attrs, size, bytes, chars)
+#define make_const_string(pref,attrs,size,chars)\
+ make_tasv(pref, t_string, attrs, size, const_bytes, chars)
+#define make_empty_string(pref,attrs)\
+ make_string(pref, attrs, 0, (byte *)NULL)
+#define make_empty_const_string(pref,attrs)\
+ make_const_string(pref, attrs, 0, (const byte *)NULL)
+
+#define make_struct(pref,attrs,ptr)\
+ make_tav(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
+#define make_struct_new(pref,attrs,ptr)\
+ make_tav_new(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
+
+#define make_astruct(pref,attrs,ptr)\
+ make_tav(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
+#define make_astruct_new(pref,attrs,ptr)\
+ make_tav_new(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
diff --git a/gs/src/stream.c b/gs/src/stream.c
new file mode 100644
index 000000000..7158d6736
--- /dev/null
+++ b/gs/src/stream.c
@@ -0,0 +1,803 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* stream.c */
+/* Stream package for Ghostscript interpreter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "gpcheck.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* Forward declarations */
+private int sreadbuf(P2(stream *, stream_cursor_write *));
+private int swritebuf(P3(stream *, stream_cursor_read *, bool));
+private void stream_compact(P2(stream *, bool));
+
+/* Structure types for allocating streams. */
+private_st_stream();
+public_st_stream_state(); /* default */
+/* GC procedures */
+#define st ((stream *)vptr)
+private ENUM_PTRS_BEGIN(stream_enum_ptrs) return 0;
+ case 0:
+ if ( st->foreign )
+ ENUM_RETURN(NULL);
+ else if ( st->cbuf_string.data != 0 )
+ ENUM_RETURN_STRING_PTR(stream, cbuf_string);
+ else
+ ENUM_RETURN(st->cbuf);
+ ENUM_PTR(1, stream, strm);
+ ENUM_PTR(2, stream, prev);
+ ENUM_PTR(3, stream, next);
+ ENUM_PTR(4, stream, state);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(stream_reloc_ptrs) {
+ byte *cbuf_old = st->cbuf;
+ if ( cbuf_old != 0 && !st->foreign )
+ { long reloc;
+ if ( st->cbuf_string.data != 0 )
+ { RELOC_STRING_PTR(stream, cbuf_string);
+ st->cbuf = st->cbuf_string.data;
+ }
+ else
+ RELOC_PTR(stream, cbuf);
+ reloc = cbuf_old - st->cbuf;
+ /* Relocate the other buffer pointers. */
+ st->srptr -= reloc;
+ st->srlimit -= reloc; /* same as swptr */
+ st->swlimit -= reloc;
+ }
+ RELOC_PTR(stream, strm);
+ RELOC_PTR(stream, prev);
+ RELOC_PTR(stream, next);
+ RELOC_PTR(stream, state);
+} RELOC_PTRS_END
+/* Finalize a stream by closing it. */
+/* We only do this for file streams, because other kinds of streams */
+/* may attempt to free storage when closing. */
+private void
+stream_finalize(void *vptr)
+{ if_debug2('u', "[u]%s 0x%lx\n",
+ (!s_is_valid(st) ? "already closed:" :
+ st->is_temp ? "is_temp set:" :
+ st->file == 0 ? "not file:" :
+ "closing file:"), (ulong)st);
+ if ( s_is_valid(st) && !st->is_temp && st->file != 0 )
+ { /* Prevent any attempt to free the buffer. */
+ st->cbuf = 0;
+ st->cbuf_string.data = 0;
+ sclose(st); /* ignore errors */
+ }
+}
+#undef st
+
+/* Dummy template for streams that don't have a separate state. */
+private const stream_template s_no_template =
+{ &st_stream_state, 0, 0, 1, 1, 0
+};
+
+/* ------ Generic procedures ------ */
+
+/* Allocate a stream and initialize it minimally. */
+stream *
+s_alloc(gs_memory_t *mem, client_name_t cname)
+{ stream *s = gs_alloc_struct(mem, stream, &st_stream, cname);
+ if_debug2('s', "[s]alloc(%s) = 0x%lx\n",
+ client_name_string(cname), (ulong)s);
+ if ( s == 0 )
+ return 0;
+ s->memory = mem;
+ s->report_error = s_no_report_error;
+ s->prev = s->next = 0; /* clean for GC */
+ return s;
+}
+
+/* Allocate a stream state and initialize it minimally. */
+stream_state *
+s_alloc_state(gs_memory_t *mem, gs_memory_type_ptr_t stype,
+ client_name_t cname)
+{ stream_state *st = gs_alloc_struct(mem, stream_state, stype, cname);
+ if_debug3('s', "[s]alloc_state %s(%s) = 0x%lx\n",
+ client_name_string(cname),
+ client_name_string(stype->sname),
+ (ulong)st);
+ if ( st == 0 )
+ return 0;
+ st->memory = mem;
+ st->report_error = s_no_report_error;
+ return st;
+}
+
+/* Vacuous stream initialization */
+int
+s_no_init(stream_state *st)
+{ return 0;
+}
+
+/* Standard stream initialization */
+void
+s_std_init(register stream *s, byte *ptr, uint len, const stream_procs *pp,
+ int modes)
+{ s->template = &s_no_template;
+ s->cbuf = ptr;
+ s->srptr = s->srlimit = s->swptr = ptr - 1;
+ s->swlimit = ptr - 1 + len;
+ s->end_status = 0;
+ s->foreign = 0;
+ s->modes = modes;
+ s->cbuf_string.data = 0;
+ s->position = 0;
+ s->bsize = s->cbsize = len;
+ s->strm = 0; /* not a filter */
+ s->is_temp = 0;
+ s->procs = *pp;
+ s->state = (stream_state *)s; /* hack to avoid separate state */
+ s->file = 0;
+ if_debug4('s', "[s]init 0x%lx, buf=0x%lx, len=%u, modes=%d\n",
+ (ulong)s, (ulong)ptr, len, modes);
+}
+
+/* Implement a stream procedure as a no-op. */
+int
+s_std_null(stream *s)
+{ return 0;
+}
+
+/* Discard the contents of the buffer when reading. */
+void
+s_std_read_reset(stream *s)
+{ s->srptr = s->srlimit = s->cbuf - 1;
+}
+
+/* Discard the contents of the buffer when writing. */
+void
+s_std_write_reset(stream *s)
+{ s->swptr = s->cbuf- 1;
+}
+
+/* Flush data to end-of-file when reading. */
+int
+s_std_read_flush(stream *s)
+{ while ( 1 )
+ { s->srptr = s->srlimit = s->cbuf - 1;
+ if ( s->end_status ) break;
+ s_process_read_buf(s);
+ }
+ return (s->end_status == EOFC ? 0 : s->end_status);
+}
+
+/* Flush buffered data when writing. */
+int
+s_std_write_flush(stream *s)
+{ return s_process_write_buf(s, false);
+}
+
+/* Indicate that the number of available input bytes is unknown. */
+int
+s_std_noavailable(stream *s, long *pl)
+{ *pl = -1;
+ return 0;
+}
+
+/* Indicate an error when asked to seek. */
+int
+s_std_noseek(stream *s, long pos)
+{ return ERRC;
+}
+
+/* Standard stream closing. */
+int
+s_std_close(stream *s)
+{ return 0;
+}
+
+/* Standard stream mode switching. */
+int
+s_std_switch_mode(stream *s, bool writing)
+{ return ERRC;
+}
+
+/* Standard stream finalization. Disable the stream. */
+void
+s_disable(register stream *s)
+{ s->cbuf = 0;
+ s->bsize = 0;
+ s->end_status = EOFC;
+ s->modes = 0;
+ s->cbuf_string.data = 0;
+ /* The pointers in the next two statements should really be */
+ /* initialized to ([const] byte *)0 - 1, but some very picky */
+ /* compilers complain about this. */
+ s->cursor.r.ptr = s->cursor.r.limit = 0;
+ s->cursor.w.limit = 0;
+ s->procs.close = s_std_null;
+ /* Clear pointers for GC */
+ s->strm = 0;
+ s->state = (stream_state *)s;
+ s->template = &s_no_template;
+ /****** SHOULD DO MORE THAN THIS ******/
+ if_debug1('s', "[s]disable 0x%lx\n", (ulong)s);
+}
+
+/* Implement flushing for encoding filters. */
+int
+s_filter_write_flush(register stream *s)
+{ int status = s_process_write_buf(s, false);
+ if ( status != 0 )
+ return status;
+ return sflush(s->strm);
+}
+
+/* Close a filter. If this is an encoding filter, flush it first. */
+int
+s_filter_close(register stream *s)
+{ if ( s_is_writing(s) )
+ { int status = s_process_write_buf(s, true);
+ if ( status != 0 && status != EOFC )
+ return status;
+ }
+ return s_std_close(s);
+}
+
+/* Disregard a stream error message. */
+int
+s_no_report_error(stream_state *st, const char *str)
+{ return 0;
+}
+
+/* ------ Implementation-independent procedures ------ */
+
+/* Store the amount of available data in a(n input) stream. */
+int
+savailable(stream *s, long *pl)
+{ return (*(s)->procs.available)(s, pl);
+}
+
+/* Return the current position of a stream. */
+long
+stell(stream *s)
+{ /* The stream might have been closed, but the position */
+ /* is still meaningful in this case. */
+ const byte *ptr = (s_is_writing(s) ? s->swptr : s->srptr);
+ return (ptr == 0 ? 0 : ptr + 1 - s->cbuf) + s->position;
+}
+
+/* Set the position of a stream. */
+int
+spseek(stream *s, long pos)
+{ if_debug3('s', "[s]seek 0x%lx to %ld, position was %ld\n",
+ (ulong)s, pos, stell(s));
+ return (*(s)->procs.seek)(s, pos);
+}
+
+/* Switch a stream to read or write mode. */
+/* Return 0 or ERRC. */
+int
+sswitch(register stream *s, bool writing)
+{ if ( s->procs.switch_mode == 0 )
+ return ERRC;
+ return (*s->procs.switch_mode)(s, writing);
+}
+
+/* Close a stream, disabling it if successful. */
+/* (The stream may already be closed.) */
+int
+sclose(register stream *s)
+{ stream_state *st;
+ int code = (*s->procs.close)(s);
+ if ( code < 0 )
+ return code;
+ st = s->state;
+ if ( st != 0 )
+ { stream_proc_release((*release)) = st->template->release;
+ if ( release != 0 )
+ (*release)(st);
+ if ( st != (stream_state *)s && st->memory != 0 )
+ gs_free_object(st->memory, st, "s_std_close");
+ s->state = (stream_state *)s;
+ }
+ s_disable(s);
+ return code;
+}
+
+/*
+ * Implement sgetc when the buffer may be empty.
+ * If the buffer really is empty, refill it and then read a byte.
+ * Note that filters must read one byte ahead, so that they can close immediately
+ * after the client reads the last data byte if the next thing is an EOD.
+ */
+int
+spgetcc(register stream *s, bool close_on_eof)
+{ int status, left;
+ int min_left = sbuf_min_left(s);
+
+ while ( status = s->end_status,
+ left = s->srlimit - s->srptr,
+ left <= min_left && status >= 0
+ )
+ s_process_read_buf(s);
+ if ( left <= min_left && (left == 0 || (status != EOFC && status != ERRC)) )
+ { /* Compact the stream so stell will return the right result. */
+ stream_compact(s, true);
+ if ( status == EOFC && close_on_eof )
+ { status = sclose(s);
+ if ( status == 0 )
+ status = EOFC;
+ s->end_status = status;
+ }
+ return status;
+ }
+ return *++(s->srptr);
+}
+
+/* Implementing sputc when the buffer is full, */
+/* by flushing the buffer and then writing the byte. */
+int
+spputc(register stream *s, byte b)
+{ for ( ; ; )
+ { if ( s->end_status )
+ return s->end_status;
+ if ( !sendwp(s) )
+ { *++(s->swptr) = b;
+ return b;
+ }
+ s_process_write_buf(s, false);
+ }
+}
+
+/* Push back a character onto a (read) stream. */
+/* The character must be the same as the last one read. */
+/* Return 0 on success, ERRC on failure. */
+int
+sungetc(register stream *s, byte c)
+{ if ( !s_is_reading(s) || s->srptr < s->cbuf || *(s->srptr) != c )
+ return ERRC;
+ s->srptr--;
+ return 0;
+}
+
+/* Get a string from a stream. */
+/* Return 0 if the string was filled, or an exception status. */
+int
+sgets(stream *s, byte *buf, uint nmax, uint *pn)
+{ stream_cursor_write cw;
+ int status = 0;
+ int min_left = sbuf_min_left(s);
+
+ cw.ptr = buf - 1;
+ cw.limit = cw.ptr + nmax;
+ while ( cw.ptr < cw.limit )
+ { int left;
+ if ( (left = s->srlimit - s->srptr) > min_left )
+ { s->srlimit -= min_left;
+ stream_move(&s->cursor.r, &cw);
+ s->srlimit += min_left;
+ }
+ else
+ { uint wanted = cw.limit - cw.ptr;
+ int c;
+ stream_state *st;
+ if ( wanted >= s->bsize >> 2 &&
+ (st = s->state) != 0 &&
+ wanted >= st->template->min_out_size &&
+ s->end_status == 0 &&
+ left == 0
+ )
+ { byte *wptr = cw.ptr;
+ cw.limit -= min_left;
+ status = sreadbuf(s, &cw);
+ cw.limit += min_left;
+ /* We know the stream buffer is empty, */
+ /* so it's safe to update position. */
+ s->position += cw.ptr - wptr;
+ if ( status != 1 || cw.ptr == cw.limit )
+ break;
+ }
+ c = spgetc(s);
+ if ( c < 0 )
+ { status = c;
+ break;
+ }
+ *++(cw.ptr) = c;
+ }
+ }
+ *pn = cw.ptr + 1 - buf;
+ return (status >= 0 ? 0 : status);
+}
+
+/* Write a string on a stream. */
+/* Return 0 if the entire string was written, or an exception status. */
+int
+sputs(register stream *s, const byte *str, uint wlen, uint *pn)
+{ uint len = wlen;
+ int status = s->end_status;
+ if ( status >= 0 )
+ while ( len > 0 )
+ { uint count = s->swlimit - s->swptr;
+ if ( count > 0 )
+ { if ( count > len ) count = len;
+ memcpy(s->swptr + 1, str, count);
+ s->swptr += count;
+ str += count;
+ len -= count;
+ }
+ else
+ { byte ch = *str++;
+ status = sputc(s, ch);
+ if ( status < 0 )
+ break;
+ len--;
+ }
+ }
+ *pn = wlen - len;
+ return (status >= 0 ? 0 : status);
+}
+
+/* Skip ahead a specified distance in a read stream. */
+/* Return 0 or an exception code. */
+/* Store the number of bytes skipped in *pskipped. */
+int
+spskip(register stream *s, long nskip, long *pskipped)
+{ long n = nskip;
+ int min_left;
+
+ if ( nskip < 0 || !s_is_reading(s) )
+ { *pskipped = 0;
+ return ERRC;
+ }
+ if ( s_can_seek(s) )
+ { long pos = stell(s);
+ int code = sseek(s, pos + n);
+ *pskipped = stell(s) - pos;
+ return code;
+ }
+ min_left = sbuf_min_left(s);
+ while ( sbufavailable(s) < n + min_left )
+ { int code;
+ n -= sbufavailable(s);
+ s->srptr = s->srlimit;
+ if ( s->end_status )
+ { *pskipped = nskip - n;
+ return s->end_status;
+ }
+ code = sgetc(s);
+ if ( code < 0 )
+ { *pskipped = nskip - n;
+ return code;
+ }
+ --n;
+ }
+ /* Note that if min_left > 0, n < 0 is possible; this is harmless. */
+ s->srptr += n;
+ *pskipped = nskip;
+ return 0;
+}
+
+/* ------ Utilities ------ */
+
+/*
+ * Attempt to refill the buffer of a read stream. Only call this if the
+ * end_status is not EOFC, and if the buffer is (nearly) empty.
+ */
+int
+s_process_read_buf(stream *s)
+{ int status;
+ stream_compact(s, false);
+ status = sreadbuf(s, &s->cursor.w);
+ s->end_status = (status >= 0 ? 0 : status);
+ return 0;
+}
+
+/*
+ * Attempt to empty the buffer of a write stream. Only call this if the
+ * end_status is not EOFC.
+ */
+int
+s_process_write_buf(stream *s, bool last)
+{ int status = swritebuf(s, &s->cursor.r, last);
+ stream_compact(s, false);
+ if ( status >= 0 )
+ status = 0;
+ s->end_status = status;
+ return status;
+}
+
+/* Move forward or backward in a pipeline. We temporarily reverse */
+/* the direction of the pointers while doing this. */
+/* (Cf the Deutsch-Schorr-Waite graph marking algorithm.) */
+#define move_back(curr, prev)\
+{ stream *back = prev->strm;\
+ prev->strm = curr; curr = prev; prev = back;\
+}
+#define move_ahead(curr, prev)\
+{ stream *ahead = curr->strm;\
+ curr->strm = prev; prev = curr; curr = ahead;\
+}
+
+/* Read from a pipeline. */
+private int
+sreadbuf(stream *s, stream_cursor_write *pbuf)
+{ stream *prev = 0;
+ stream *curr = s;
+ int status;
+ for ( ; ; )
+ { stream *strm;
+ for ( ; ; )
+ { /* Descend into the recursion. */
+ stream_cursor_read cr;
+ stream_cursor_read *pr;
+ stream_cursor_write *pw;
+ bool eof;
+
+ strm = curr->strm;
+ if ( strm == 0 )
+ { cr.ptr = 0, cr.limit = 0;
+ pr = &cr;
+ eof = false;
+ }
+ else
+ { pr = &strm->cursor.r;
+ eof = strm->end_status == EOFC;
+ }
+ pw = (prev == 0 ? pbuf : &curr->cursor.w);
+ if_debug4('s', "[s]read process 0x%lx, nr=%u, nw=%u, eof=%d\n",
+ (ulong)curr, (uint)(pr->limit - pr->ptr),
+ (uint)(pw->limit - pw->ptr), eof);
+ status = (*curr->procs.process)(curr->state, pr, pw, eof);
+ if_debug4('s', "[s]after read 0x%lx, nr=%u, nw=%u, status=%d\n",
+ (ulong)curr, (uint)(pr->limit - pr->ptr),
+ (uint)(pw->limit - pw->ptr), status);
+ if ( strm == 0 || status != 0 )
+ break;
+ status = strm->end_status;
+ if ( status < 0 )
+ break;
+ move_ahead(curr, prev);
+ stream_compact(curr, false);
+ }
+ /* If curr reached EOD and is a filter stream, close it. */
+ if ( strm != 0 && status == EOFC &&
+ curr->cursor.r.ptr >= curr->cursor.r.limit
+ )
+ { int cstat = sclose(curr);
+ if ( cstat != 0 )
+ status = cstat;
+ }
+#if 0
+ /* If we need to do a callout, unwind all the way now. */
+ if ( status == CALLC )
+ { while ( (curr->end_status = status), prev != 0 )
+ { move_back(curr, prev);
+ }
+ return status;
+ }
+#endif
+ /* Unwind from the recursion. */
+ curr->end_status = (status >= 0 ? 0 : status);
+ if ( prev == 0 )
+ return status;
+ move_back(curr, prev);
+ }
+}
+
+/* Write to a pipeline. */
+private int
+swritebuf(stream *s, stream_cursor_read *pbuf, bool last)
+{ stream *prev = 0;
+ stream *curr = s;
+ int depth = 0; /* depth of nesting in non-temp streams */
+ int status;
+
+ /*
+ * The handling of EOFC is a little tricky. There are two
+ * invariants that keep it straight:
+ * - We only pass last = true to a stream if either it is
+ * the first stream in the pipeline, or it is a temporary stream
+ * below the first stream and the stream immediately above it has
+ * end_status = EOFC.
+ * - We never unwind the recursion past a stream with
+ * end_status < 0.
+ */
+ for ( ; ; )
+ { for ( ; ; )
+ { /* Descend into the recursion. */
+ stream *strm = curr->strm;
+ stream_cursor_write cw;
+ stream_cursor_read *pr;
+ stream_cursor_write *pw;
+ /*
+ * We only want to set the last/end flag for
+ * the top-level stream and any temporary streams
+ * immediately below it.
+ */
+ bool end = last &&
+ (prev == 0 ||
+ (depth <= 1 && prev->end_status == EOFC));
+
+ if ( strm == 0 )
+ cw.ptr = 0, cw.limit = 0, pw = &cw;
+ else
+ pw = &strm->cursor.w;
+ if ( prev == 0 )
+ pr = pbuf;
+ else
+ pr = &curr->cursor.r;
+ if_debug4('s', "[s]write process 0x%lx, nr=%u, nw=%u, end=%d\n",
+ (ulong)curr, (uint)(pr->limit - pr->ptr),
+ (uint)(pw->limit - pw->ptr), end);
+ status = curr->end_status;
+ if ( status < 0 )
+ break;
+ status = (*curr->procs.process)(curr->state,
+ pr, pw, end);
+ if_debug5('s', "[s]after write 0x%lx, nr=%u, nw=%u, end=%d, status=%d\n",
+ (ulong)curr, (uint)(pr->limit - pr->ptr),
+ (uint)(pw->limit - pw->ptr), end, status);
+ if ( status == 0 && end )
+ status = EOFC;
+ if ( status == EOFC || status == ERRC )
+ curr->end_status = status;
+ if ( strm == 0 || (status < 0 && status != EOFC) )
+ break;
+ if ( status == 1 )
+ end = false;
+ else
+ { /* Keep going if we are closing */
+ /* a filter with a sub-stream. */
+ /* We know status == 0 or EOFC. */
+ if ( !end || !strm->is_temp )
+ break;
+ }
+ status = strm->end_status;
+ if ( status < 0 )
+ break;
+ move_ahead(curr, prev);
+ stream_compact(curr, false);
+ if ( !curr->is_temp )
+ ++depth;
+ }
+ /* Unwind from the recursion. */
+ curr->end_status = (status >= 0 ? 0 : status);
+ if ( status < 0 || prev == 0 )
+ { /*
+ * All streams above here were called with last = true
+ * and returned 0 or EOFC: finish unwinding and then
+ * return.
+ */
+ while ( prev )
+ { move_back(curr, prev);
+ curr->end_status = (status >= 0 ? 0 : status);
+ }
+ return status;
+ }
+ move_back(curr, prev);
+ if ( !curr->is_temp )
+ --depth;
+ }
+}
+
+/* Move as much data as possible from one buffer to another. */
+/* Return 0 if the input became empty, 1 if the output became full. */
+int
+stream_move(stream_cursor_read *pr, stream_cursor_write *pw)
+{ uint rcount = pr->limit - pr->ptr;
+ uint wcount = pw->limit - pw->ptr;
+ uint count;
+ int status;
+ if ( rcount <= wcount )
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+ memmove(pw->ptr + 1, pr->ptr + 1, count);
+ pr->ptr += count;
+ pw->ptr += count;
+ return status;
+}
+
+/* If possible, compact the information in a stream buffer to the bottom. */
+private void
+stream_compact(stream *s, bool always)
+{ if ( s->cursor.r.ptr >= s->cbuf && (always || s->end_status >= 0) )
+ { uint dist = s->cursor.r.ptr + 1 - s->cbuf;
+ memmove(s->cbuf, s->cursor.r.ptr + 1,
+ (uint)(s->cursor.r.limit - s->cursor.r.ptr));
+ s->cursor.r.ptr = s->cbuf - 1;
+ s->cursor.r.limit -= dist; /* same as w.ptr */
+ s->position += dist;
+ }
+}
+
+/* ------ String streams ------ */
+
+/* String stream procedures */
+private int
+ s_string_available(P2(stream *, long *)),
+ s_string_read_seek(P2(stream *, long)),
+ s_string_write_seek(P2(stream *, long)),
+ s_string_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool)),
+ s_string_write_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+
+/* Initialize a stream for reading a string. */
+void
+sread_string(register stream *s, const byte *ptr, uint len)
+{ static const stream_procs p =
+ { s_string_available, s_string_read_seek, s_std_read_reset,
+ s_std_read_flush, s_std_null, s_string_read_process
+ };
+ s_std_init(s, (byte *)ptr, len, &p, s_mode_read + s_mode_seek);
+ s->cbuf_string.data = (byte *)ptr;
+ s->cbuf_string.size = len;
+ s->end_status = EOFC;
+ s->srlimit = s->swlimit;
+}
+/* Return the number of available bytes when reading from a string. */
+private int
+s_string_available(stream *s, long *pl)
+{ *pl = sbufavailable(s);
+ if ( *pl == 0 ) /* EOF */
+ *pl = -1;
+ return 0;
+}
+
+/* Seek in a string being read. Return 0 if OK, ERRC if not. */
+private int
+s_string_read_seek(register stream *s, long pos)
+{ if ( pos < 0 || pos > s->bsize ) return ERRC;
+ s->srptr = s->cbuf + pos - 1;
+ return 0;
+}
+
+/* Initialize a stream for writing a string. */
+void
+swrite_string(register stream *s, byte *ptr, uint len)
+{ static const stream_procs p =
+ { s_std_noavailable, s_string_write_seek, s_std_write_reset,
+ s_std_null, s_std_null, s_string_write_process
+ };
+ s_std_init(s, ptr, len, &p, s_mode_write + s_mode_seek);
+ s->cbuf_string.data = ptr;
+ s->cbuf_string.size = len;
+}
+
+/* Seek in a string being written. Return 0 if OK, ERRC if not. */
+private int
+s_string_write_seek(register stream *s, long pos)
+{ if ( pos < 0 || pos > s->bsize ) return ERRC;
+ s->swptr = s->cbuf + pos - 1;
+ return 0;
+}
+
+/* Since we initialize the input buffer of a string read stream */
+/* to contain all of the data in the string, if we are ever asked */
+/* to refill the buffer, we should signal EOF. */
+private int
+s_string_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ return EOFC;
+}
+/* Similarly, if we are ever asked to empty the buffer, it means that */
+/* there has been an overrun (unless we are closing the stream). */
+private int
+s_string_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ return (last ? EOFC : ERRC);
+}
diff --git a/gs/src/stream.h b/gs/src/stream.h
new file mode 100644
index 000000000..3a92d883d
--- /dev/null
+++ b/gs/src/stream.h
@@ -0,0 +1,318 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* stream.h */
+/* Definitions for Ghostscript stream package */
+/* Requires stdio.h */
+
+#ifndef stream_INCLUDED
+# define stream_INCLUDED
+
+#include "scommon.h"
+
+/* See scommon.h for documentation on the design of streams. */
+
+/* ------ Stream structure definition ------ */
+
+/*
+ * We expose the stream structure definition to clients so that
+ * they can get reasonable performance out of the basic operations.
+ */
+
+/* Define the "virtual" stream procedures. */
+
+typedef struct {
+
+ /* Store # available for reading. */
+ /* Return 0 if OK, ERRC if error or not implemented. */
+#define stream_proc_available(proc)\
+ int proc(P2(stream *, long *))
+ stream_proc_available((*available));
+
+ /* Set position. */
+ /* Return 0 if OK, ERRC if error or not implemented. */
+#define stream_proc_seek(proc)\
+ int proc(P2(stream *, long))
+ stream_proc_seek((*seek));
+
+ /* Clear buffer and, if relevant, unblock channel. */
+ /* Cannot cause an error. */
+#define stream_proc_reset(proc)\
+ void proc(P1(stream *))
+ stream_proc_reset((*reset));
+
+ /* Flush buffered data to output, or drain input. */
+ /* Return 0 if OK, ERRC if error. */
+#define stream_proc_flush(proc)\
+ int proc(P1(stream *))
+ stream_proc_flush((*flush));
+
+ /* Flush data (if writing) & close stream. */
+ /* Return 0 if OK, ERRC if error. */
+#define stream_proc_close(proc)\
+ int proc(P1(stream *))
+ stream_proc_close((*close));
+
+ /* Process a buffer, updating the cursor pointers. */
+ /* See strimpl.h for details. */
+ stream_proc_process((*process));
+
+ /* Switch the stream to read or write mode. */
+ /* false = read, true = write. */
+ /* If the procedure is 0, switching is not allowed. */
+#define stream_proc_switch_mode(proc)\
+ int proc(P2(stream *, bool))
+ stream_proc_switch_mode((*switch_mode));
+
+} stream_procs;
+
+/* ------ The actual stream structure ------ */
+
+struct stream_s {
+ /*
+ * To allow the stream itself to serve as the "state"
+ * of a couple of heavily used types, we start its
+ * definition with the common stream state.
+ */
+ stream_state_common;
+ stream_cursor cursor; /* cursor for reading/writing data */
+ byte *cbuf; /* base of buffer */
+ uint bsize; /* size of buffer, 0 if closed */
+ uint cbsize; /* size of buffer */
+ /*
+ * end_status indicates what should happen when the client
+ * reaches the end of the buffer:
+ * 0 in the normal case;
+ * EOFC if a read stream has reached EOD or a write
+ * stream has written the EOD marker;
+ * ERRC if an error terminated the last read or write
+ * operation from or to the underlying data source
+ * or sink;
+ * INTC if the last transfer was interrupted (NOT
+ * USED YET);
+ * CALLC if a callout is required.
+ */
+ short end_status; /* status at end of buffer (when */
+ /* reading) or now (when writing) */
+ byte foreign; /* true if buffer is outside heap */
+ byte modes; /* access modes allowed for this */
+ /* stream */
+#define s_mode_read 1
+#define s_mode_write 2
+#define s_mode_seek 4
+#define s_mode_append 8 /* (s_mode_write also set) */
+#define s_is_valid(s) ((s)->modes != 0)
+#define s_is_reading(s) (((s)->modes & s_mode_read) != 0)
+#define s_is_writing(s) (((s)->modes & s_mode_write) != 0)
+#define s_can_seek(s) (((s)->modes & s_mode_seek) != 0)
+ gs_string cbuf_string; /* cbuf/cbsize if cbuf is a string, */
+ /* 0/? if not */
+ long position; /* file position of beginning of */
+ /* buffer */
+ stream_procs procs;
+ stream *strm; /* the underlying stream, non-zero */
+ /* iff this is a filter stream */
+ int is_temp; /* if >0, this is a temporary */
+ /* stream and should be freed */
+ /* when its source/sink is closed; */
+ /* if >1, the buffer is also */
+ /* temporary */
+ int inline_temp; /* temporary for inline access */
+ /* (see spgetc_inline below) */
+ stream_state *state; /* state of process */
+ /*
+ * The following are for the use of the interpreter.
+ * See files.h for more information on read_id and write_id,
+ * zfile.c for more information on prev, next, and save_count.
+ */
+ ushort read_id; /* "unique" serial # for detecting */
+ /* references to closed streams */
+ /* and for validating read access */
+ ushort write_id; /* ditto to validate write access */
+ stream *prev, *next; /* keep track of all files */
+ int save_count; /* # of saves for which this stream */
+ /* was the head of the file list */
+ /*
+ * In order to avoid allocating a separate stream_state for
+ * file streams, which are the most heavily used stream type,
+ * we put their state here.
+ */
+ FILE *file; /* file handle for C library */
+ uint file_modes; /* access modes for the file, */
+ /* may be a superset of modes */
+ int (*save_close)(P1(stream *)); /* save original close proc */
+};
+#define private_st_stream() /* in stream.c */\
+ gs_private_st_composite_final(st_stream, stream, "stream",\
+ stream_enum_ptrs, stream_reloc_ptrs, stream_finalize)
+
+/* Initialize the checking IDs of a stream. */
+#define s_init_ids(s) ((s)->read_id = (s)->write_id = 1)
+#define s_init_read_id(s) ((s)->read_id = 1, (s)->write_id = 0)
+#define s_init_write_id(s) ((s)->read_id = 0, (s)->write_id = 1)
+#define s_init_no_id(s) ((s)->read_id = (s)->write_id = 0)
+
+/* ------ Stream functions ------ */
+
+#define srptr cursor.r.ptr
+#define srlimit cursor.r.limit
+#define swptr cursor.w.ptr
+#define swlimit cursor.w.limit
+
+/* Some of these are macros -- beware. */
+/* Note that unlike the C stream library, */
+/* ALL stream procedures take the stream as the first argument. */
+#define sendrp(s) ((s)->srptr >= (s)->srlimit) /* NOT FOR CLIENTS */
+#define sendwp(s) ((s)->swptr >= (s)->swlimit) /* NOT FOR CLIENTS */
+
+/*
+ * Following are valid for all streams.
+ */
+/* flush is NOT a no-op for read streams -- it discards data until EOF. */
+/* close is NOT a no-op for non-file streams -- */
+/* it actively disables them. */
+/* The close routine must do a flush if needed. */
+#define sseekable(s) s_can_seek(s)
+int savailable(P2(stream *, long *));
+#define sreset(s) (*(s)->procs.reset)(s)
+#define sflush(s) (*(s)->procs.flush)(s)
+int sclose(P1(stream *));
+int sswitch(P2(stream *, bool));
+
+/*
+ * Following are only valid for read streams.
+ */
+int spgetcc(P2(stream *, bool)); /* bool indicates close-on-EOD */
+#define spgetc(s) spgetcc(s, true) /* a procedure equivalent of sgetc */
+/*
+ * Note that sgetc must call spgetc one byte early, because filter must read ahead
+ * to detect EOD.
+ *
+ * In the definition of sgetc, the first alternative should read
+ * (int)(*++((s)->srptr))
+ * but the Borland compiler generates truly atrocious code for this.
+ * The SCO ODT compiler requires the first, pointless cast to int.
+ */
+#define sgetc(s)\
+ ((int)((s)->srlimit - (s)->srptr > 1 ? (++((s)->srptr), (int)*(s)->srptr) : spgetc(s)))
+int sgets(P4(stream *, byte *, uint, uint *));
+int sungetc(P2(stream *, byte)); /* ERRC on error, 0 if OK */
+#define sputback(s) ((s)->srptr--) /* can only do this once! */
+#define seofp(s) (sendrp(s) && (s)->end_status == EOFC)
+#define serrorp(s) (sendrp(s) && (s)->end_status == ERRC)
+int spskip(P3(stream *, long, long *));
+#define sskip(s,nskip,pskipped) spskip(s, (long)(nskip), pskipped)
+/*
+ * Attempt to refill the buffer of a read stream.
+ * Only call this if the end_status is not EOFC,
+ * and if the buffer is (nearly) empty.
+ */
+int s_process_read_buf(P1(stream *));
+
+/*
+ * Following are only valid for write streams.
+ */
+int spputc(P2(stream *, byte)); /* a procedure equivalent of sputc */
+/*
+ * The first alternative should read
+ * ((int)(*++((s)->swptr)=(c)))
+ * but the Borland compiler generates truly atrocious code for this.
+ */
+#define sputc(s,c)\
+ (!sendwp(s) ? (++((s)->swptr), *(s)->swptr=(c), 0) : spputc((s),(c)))
+int sputs(P4(stream *, const byte *, uint, uint *));
+/*
+ * Attempt to empty the buffer of a write stream.
+ * Only call this if the end_status is not EOFC.
+ */
+int s_process_write_buf(P2(stream *, bool));
+
+/* Following are only valid for positionable streams. */
+long stell(P1(stream *));
+int spseek(P2(stream *, long));
+#define sseek(s,pos) spseek(s, (long)(pos))
+
+/* Following are for high-performance reading clients. */
+/* bufptr points to the next item. */
+#define sbufptr(s) ((s)->srptr + 1)
+#define sbufavailable(s) ((s)->srlimit - (s)->srptr)
+#define sbufskip(s, n) ((s)->srptr += (n), 0)
+/*
+ * Define the minimum amount of data that must be left in an input buffer
+ * after a read operation to handle filter read-ahead. This is 1 byte for
+ * filters (including procedure data sources), 0 for files.
+ */
+#define max_min_left 1
+#define sbuf_min_left(s) (s->strm == 0 && s->end_status != CALLC ? 0 : 1)
+
+/* The following are for very high-performance clients of read streams, */
+/* who unpack the stream state into local variables. */
+/* Note that any non-inline operations must do a s_end_inline before, */
+/* and a s_begin_inline after. */
+#define s_declare_inline(s, cp, ep)\
+ register const byte *cp;\
+ const byte *ep
+#define s_begin_inline(s, cp, ep)\
+ cp = (s)->srptr, ep = (s)->srlimit
+#define s_end_inline(s, cp, ep)\
+ (s)->srptr = cp
+#define sbufavailable_inline(s, cp, ep)\
+ (ep - cp)
+#define sendbufp_inline(s, cp, ep)\
+ (cp >= ep)
+/* The (int) is needed to pacify the SCO ODT compiler. */
+#define sgetc_inline(s, cp, ep)\
+ ((int)(sendbufp_inline(s, cp, ep) ? spgetc_inline(s, cp, ep) : *++cp))
+#define spgetc_inline(s, cp, ep)\
+ (s_end_inline(s, cp, ep), (s)->inline_temp = spgetc(s),\
+ s_begin_inline(s, cp, ep), (s)->inline_temp)
+#define sputback_inline(s, cp, ep)\
+ --cp
+
+/* Allocate a stream or a stream state. */
+stream *s_alloc(P2(gs_memory_t *, client_name_t));
+stream_state *s_alloc_state(P3(gs_memory_t *, gs_memory_type_ptr_t, client_name_t));
+
+/* Stream creation procedures */
+void sread_string(P3(stream *, const byte *, uint)),
+ swrite_string(P3(stream *, byte *, uint));
+void sread_file(P4(stream *, FILE *, byte *, uint)),
+ swrite_file(P4(stream *, FILE *, byte *, uint)),
+ sappend_file(P4(stream *, FILE *, byte *, uint));
+
+/* Standard stream initialization */
+void s_std_init(P5(stream *, byte *, uint, const stream_procs *, int /*mode*/));
+
+/* Standard stream finalization */
+void s_disable(P1(stream *));
+
+/* Generic stream procedures exported for templates */
+int s_std_null(P1(stream *));
+void s_std_read_reset(P1(stream *)),
+ s_std_write_reset(P1(stream *));
+int s_std_read_flush(P1(stream *)),
+ s_std_write_flush(P1(stream *)),
+ s_std_noavailable(P2(stream *, long *)),
+ s_std_noseek(P2(stream *, long)),
+ s_std_close(P1(stream *)),
+ s_std_switch_mode(P2(stream *, bool));
+/* Generic procedures for filters. */
+int s_filter_write_flush(P1(stream *)),
+ s_filter_close(P1(stream *));
+
+#endif /* stream_INCLUDED */
diff --git a/gs/src/strimpl.h b/gs/src/strimpl.h
new file mode 100644
index 000000000..d52492164
--- /dev/null
+++ b/gs/src/strimpl.h
@@ -0,0 +1,147 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* strimpl.h */
+/* Definitions for stream implementors */
+/* Requires stdio.h */
+
+#ifndef strimpl_INCLUDED
+# define strimpl_INCLUDED
+
+#include "scommon.h"
+#include "gstypes.h" /* for gsstruct.h */
+#include "gsstruct.h"
+
+/*
+ * The 'process' procedure does the real work of the stream.
+ * It must process as much input information (from pr->ptr + 1 through
+ * pr->limit) as it can, subject to space available for output
+ * (pw->ptr + 1 through pw->limit), updating pr->ptr and pw->ptr.
+ *
+ * The procedure return value must be one of:
+ * EOFC - an end-of-data pattern was detected in the input,
+ * or no more input can be processed for some other reason (e.g.,
+ * the stream was told only to read a certain amount of data).
+ * ERRC - a syntactic error was detected in the input.
+ * 0 - more input data is needed.
+ * 1 - more output space is needed.
+ * If the procedure returns EOFC, it can assume it will never be called
+ * again for that stream.
+ *
+ * If the procedure is called with last = 1, this is an indication that
+ * no more input will ever be supplied (after the input in the current
+ * buffer defined by *pr); the procedure should produce as much output
+ * as possible, including an end-of-data marker if applicable. In this
+ * case:
+ * - If the procedure returns 1, it may be called again (also with
+ * last = 1).
+ * - If the procedure returns any other value other than 1, the
+ * procedure will never be called again for that stream.
+ * - If the procedure returns 0, this is taken as equivalent to
+ * returning EOFC.
+ * - If the procedure returns EOFC (or 0), the stream's end_status
+ * is set to EOFC, meaning no more writing is allowed.
+ *
+ * Note that these specifications do not distinguish input from output
+ * streams. This is deliberate: The processing procedures should work
+ * regardless of which way they are oriented in a stream pipeline.
+ * (The PostScript language does take a position as whether any given
+ * filter may be used for input or output, but this occurs at a higher level.)
+ *
+ * The value returned by the process procedure of a stream whose data source
+ * or sink is external (i.e., not another stream) is interpreted slightly
+ * differently. For an external data source, a return value of 0 means
+ * "no more input data are available now, but more might become available
+ * later." For an external data sink, a return value of 1 means "there is
+ * no more room for output data now, but there might be room later."
+ *
+ * It appears that the Adobe specifications, read correctly, require that when
+ * the process procedure of a decoding filter has filled up the output
+ * buffer, it must still peek ahead in the input to determine whether or not
+ * the next thing in the input stream is EOD. If the next thing is an EOD (or
+ * end-of-data, indicated by running out of input data with last = true), the
+ * process procedure must return EOFC; if the next thing is definitely not
+ * an EOD, the process procedure must return 1 (output full) (without, of
+ * course, consuming the non-EOD datum); if the procedure cannot determine
+ * whether or not the next thing is an EOD, it must return 0 (need more input).
+ * Decoding filters that don't have EOD (for example, NullDecode) can use
+ * a simpler algorithm: if the output buffer is full, then if there is more
+ * input, return 1, otherwise return 0 (which is taken as EOFC if last
+ * is true). All this may seem a little awkward, but it is needed in order
+ * to have consistent behavior regardless of where buffer boundaries fall --
+ * in particular, if a buffer boundary falls just before an EOD. It is
+ * actually quite easy to implement if the main loop of the process
+ * procedure tests for running out of input rather than for filling the
+ * output: with this structure, exhausting the input always returns 0,
+ * and discovering that the output buffer is full when attempting to store
+ * more output always returns 1.
+ *
+ * Even this algorithm for handling end-of-buffer is not sufficient if an
+ * EOD falls just after a buffer boundary, but the generic stream code
+ * handles this case: the process procedures need only do what was just
+ * described.
+ */
+
+/*
+ * Define a template for creating a stream.
+ *
+ * The meaning of min_in_size and min_out_size is the following:
+ * If the amount of input information is at least min_in_size,
+ * and the available output space is at least min_out_size,
+ * the process procedure guarantees that it will make some progress.
+ * (It may make progress even if this condition is not met, but this is
+ * not guaranteed.)
+ */
+struct stream_template_s {
+
+ /* Define the structure type for the stream state. */
+ gs_memory_type_ptr_t stype;
+
+ /* Define an optional initialization procedure. */
+ stream_proc_init((*init));
+
+ /* Define the processing procedure. */
+ /* (The init procedure can reset other procs if it wants.) */
+ stream_proc_process((*process));
+
+ /* Define the minimum buffer sizes. */
+ uint min_in_size; /* minimum size for process input */
+ uint min_out_size; /* minimum size for process output */
+
+ /* Define an optional releasing procedure. */
+ stream_proc_release((*release));
+
+ /* Define an optional parameter defaulting procedure. */
+ stream_proc_set_defaults((*set_defaults));
+
+ /* Define an optional reinitialization procedure. */
+ stream_proc_reinit((*reinit));
+
+};
+
+/* Utility procedures */
+int stream_move(P2(stream_cursor_read *, stream_cursor_write *)); /* in stream.c */
+/* Hex decoding utility procedure */
+typedef enum {
+ hex_ignore_garbage = 0,
+ hex_ignore_whitespace = 1,
+ hex_ignore_leading_whitespace = 2
+} hex_syntax;
+int s_hex_process(P4(stream_cursor_read *, stream_cursor_write *, int *, hex_syntax)); /* in sstring.c */
+
+#endif /* strimpl_INCLUDED */
diff --git a/gs/src/string_.h b/gs/src/string_.h
new file mode 100644
index 000000000..0ceee34a2
--- /dev/null
+++ b/gs/src/string_.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* string.h */
+/* Generic substitute for Unix string.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#ifdef BSD4_2
+# include <strings.h>
+# define strchr index
+#else
+# ifdef __TURBOC__
+# undef memset /* just in case */
+# include <string.h>
+# ifndef memset /* Borland C++ can inline this */
+# define memset(dest,chr,cnt) setmem(dest,cnt,chr)
+# endif
+# else
+# ifdef memory__need_memmove
+# undef memmove /* This is disgusting, but so is GCC */
+# endif
+# include <string.h>
+# if defined(THINK_C)
+ /* Patch strlen to return a uint rather than a size_t. */
+# define strlen (uint)strlen
+# endif
+# ifdef memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# endif
+# endif
+#endif
diff --git a/gs/src/szlibc.c b/gs/src/szlibc.c
new file mode 100644
index 000000000..f7dd2982c
--- /dev/null
+++ b/gs/src/szlibc.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* szlibc.c */
+/* Code common to zlib encoding and decoding streams */
+#include "std.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "strimpl.h"
+#include "szlibx.h"
+#include "zconf.h"
+
+public_st_zlib_state();
+
+#define ss ((stream_zlib_state *)st)
+
+/* Set defaults for stream parameters. */
+void
+s_zlib_set_defaults(stream_state *st)
+{ ss->windowBits = MAX_WBITS;
+ ss->no_wrapper = false;
+ ss->level = Z_DEFAULT_COMPRESSION;
+ ss->method = Z_DEFLATED;
+ /* DEF_MEM_LEVEL should be in zlib.h or zconf.h, but it isn't. */
+ ss->memLevel = min(MAX_MEM_LEVEL, 8);
+ ss->strategy = Z_DEFAULT_STRATEGY;
+}
+
+#undef ss
+
+/* Provide zlib-compatible allocation and freeing functions. */
+void *
+s_zlib_alloc(void *mem, uint items, uint size)
+{ void *address =
+ gs_alloc_byte_array_immovable((gs_memory_t *)mem, items, size, "zlib");
+ return (address == 0 ? Z_NULL : address);
+}
+void
+s_zlib_free(void *mem, void *address)
+{ gs_free_object((gs_memory_t *)mem, address, "zlib");
+}
diff --git a/gs/src/szlibd.c b/gs/src/szlibd.c
new file mode 100644
index 000000000..6a210d16a
--- /dev/null
+++ b/gs/src/szlibd.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* szlibd.c */
+/* zlib decoding (decompression) filter stream */
+#include "std.h"
+#include "gsmemory.h"
+#include "strimpl.h"
+#include "szlibx.h"
+
+#define ss ((stream_zlib_state *)st)
+#define szs (&ss->zstate)
+
+/* Initialize the filter. */
+private int
+s_zlibD_init(stream_state *st)
+{ szs->zalloc = (alloc_func)s_zlib_alloc;
+ szs->zfree = (free_func)s_zlib_free;
+ szs->opaque = (voidpf)(st->memory ? st->memory : &gs_memory_default);
+ if ( inflateInit2(szs,
+ (ss->no_wrapper ? -ss->windowBits : ss->windowBits))
+ != Z_OK
+ )
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Reinitialize the filter. */
+private int
+s_zlibD_reset(stream_state *st)
+{ if ( inflateReset(szs) != Z_OK )
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_zlibD_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool ignore_last)
+{ const byte *p = pr->ptr;
+ int status;
+
+ /* Detect no input or full output so that we don't get */
+ /* a Z_BUF_ERROR return. */
+ if ( pw->ptr == pw->limit )
+ return 1;
+ if ( pr->ptr == pr->limit )
+ return 0;
+ szs->next_in = (Bytef *)p + 1;
+ szs->avail_in = pr->limit - p;
+ szs->next_out = pw->ptr + 1;
+ szs->avail_out = pw->limit - pw->ptr;
+ status = inflate(szs, Z_PARTIAL_FLUSH);
+ pr->ptr = szs->next_in - 1;
+ pw->ptr = szs->next_out - 1;
+ switch ( status )
+ {
+ case Z_OK:
+ return (pw->ptr == pw->limit ? 1 : pr->ptr > p ? 0 : 1);
+ case Z_STREAM_END:
+ return EOFC;
+ default:
+ return ERRC;
+ }
+}
+
+/* Release the stream */
+private void
+s_zlibD_release(stream_state *st)
+{ inflateEnd(szs);
+}
+
+/* Stream template */
+const stream_template s_zlibD_template =
+{ &st_zlib_state, s_zlibD_init, s_zlibD_process, 1, 1, s_zlibD_release,
+ s_zlib_set_defaults, s_zlibD_reset
+};
+
+#undef ss
diff --git a/gs/src/szlibe.c b/gs/src/szlibe.c
new file mode 100644
index 000000000..2619898b5
--- /dev/null
+++ b/gs/src/szlibe.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* szlibe.c */
+/* zlib encoding (compression) filter stream */
+#include "std.h"
+#include "gsmemory.h"
+#include "strimpl.h"
+#include "szlibx.h"
+
+#define ss ((stream_zlib_state *)st)
+#define szs (&ss->zstate)
+
+/* Initialize the filter. */
+private int
+s_zlibE_init(stream_state *st)
+{ szs->zalloc = (alloc_func)s_zlib_alloc;
+ szs->zfree = (free_func)s_zlib_free;
+ szs->opaque = (voidpf)(st->memory ? st->memory : &gs_memory_default);
+ if ( deflateInit2(szs, ss->level, ss->method,
+ (ss->no_wrapper ? -ss->windowBits : ss->windowBits),
+ ss->memLevel, ss->strategy) != Z_OK )
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Reinitialize the filter. */
+private int
+s_zlibE_reset(stream_state *st)
+{ if ( deflateReset(szs) != Z_OK )
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_zlibE_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ const byte *p = pr->ptr;
+ int status;
+
+ /* Detect no input or full output so that we don't get */
+ /* a Z_BUF_ERROR return. */
+ if ( pw->ptr == pw->limit )
+ return 1;
+ if ( p == pr->limit && !last )
+ return 0;
+ szs->next_in = (Bytef *)p + 1;
+ szs->avail_in = pr->limit - p;
+ szs->next_out = pw->ptr + 1;
+ szs->avail_out = pw->limit - pw->ptr;
+ status = deflate(szs, (last ? Z_FINISH : Z_NO_FLUSH));
+ pr->ptr = szs->next_in - 1;
+ pw->ptr = szs->next_out - 1;
+ switch ( status )
+ {
+ case Z_OK:
+ return (pw->ptr == pw->limit ? 1 : pr->ptr > p && !last ? 0 : 1);
+ case Z_STREAM_END:
+ return (last && pr->ptr == pr->limit ? 0 : ERRC);
+ default:
+ return ERRC;
+ }
+}
+
+/* Release the stream */
+private void
+s_zlibE_release(stream_state *st)
+{ deflateEnd(szs);
+}
+
+/* Stream template */
+const stream_template s_zlibE_template =
+{ &st_zlib_state, s_zlibE_init, s_zlibE_process, 1, 1, s_zlibE_release,
+ s_zlib_set_defaults, s_zlibE_reset
+};
+
+#undef ss
diff --git a/gs/src/szlibx.h b/gs/src/szlibx.h
new file mode 100644
index 000000000..c9e50693d
--- /dev/null
+++ b/gs/src/szlibx.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* szlibx.h */
+/* Definitions for zlib filters */
+/* Requires strimpl.h */
+/* Must be compiled with -I$(ZSRCDIR) */
+#include "zlib.h"
+
+/* Provide zlib-compatible allocation and freeing functions. */
+void *s_zlib_alloc(P3(void *mem, uint items, uint size));
+void s_zlib_free(P2(void *mem, void *address));
+
+typedef struct stream_zlib_state_s {
+ stream_state_common;
+ /* Parameters - compression and decompression */
+ int windowBits;
+ bool no_wrapper; /* omit wrapper and checksum */
+ /* Parameters - compression only */
+ int level; /* effort level */
+ int method;
+ int memLevel;
+ int strategy;
+ /* Dynamic state */
+ z_stream zstate;
+} stream_zlib_state;
+/* The state descriptor is public only to allow us to split up */
+/* the encoding and decoding filters. */
+/* Note that all zlib's allocations are done as immovable bytes */
+/* to avoid garbage collection issues. */
+extern_st(st_zlib_state);
+#define public_st_zlib_state() /* in szlibc.c */\
+ gs_public_st_simple(st_zlib_state, stream_zlib_state,\
+ "zlibEncode/Decode state")
+extern const stream_template s_zlibD_template;
+extern const stream_template s_zlibE_template;
+
+/* Shared procedures */
+stream_proc_set_defaults(s_zlib_set_defaults);
diff --git a/gs/src/time_.h b/gs/src/time_.h
new file mode 100644
index 000000000..0f75c28b9
--- /dev/null
+++ b/gs/src/time_.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 1991, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* time_.h */
+/* Generic substitute for Unix sys/time.h */
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/* The location (or existence) of certain system headers is */
+/* environment-dependent. We detect this in the makefile */
+/* and conditionally define switches in gconfig_.h. */
+#include "gconfig_.h"
+
+/* Some System V environments don't include sys/time.h. */
+/* The HAVE_SYS_TIME_H switch in gconfig_.h reflects this. */
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# if defined(M_UNIX) || defined(_IBMR2) || defined(_SEQUENT_) /* SCO, AIX and Sequent's DYNIX/ptx need both time.h and sys/time.h! */
+# include <time.h>
+# endif
+#else
+# include <time.h>
+# ifndef __DECC
+struct timeval {
+ long tv_sec, tv_usec;
+};
+# endif
+struct timezone {
+ int tz_minuteswest, tz_dsttime;
+};
+#endif
+
+#if defined(ultrix) && defined(mips)
+/* Apparently some versions of Ultrix for the DECstation include */
+/* time_t in sys/time.h, and some don't. If you get errors */
+/* compiling gp_unix.c, uncomment the next line. */
+/* typedef int time_t; */
+#endif
+
+/* In SVR4.0 (but not other System V implementations), */
+/* gettimeofday doesn't take a timezone argument. */
+#ifdef SVR4_0
+# define gettimeofday_no_timezone 1
+#else
+# define gettimeofday_no_timezone 0
+#endif
+
+/* Some System V environments, and Posix environments, need <sys/times.h>. */
+#ifdef HAVE_SYS_TIMES_H
+# include <sys/times.h>
+# define use_times_for_usertime 1
+ /* Posix 1003.1b-1993 section 4.8.1.5 says that
+ CLK_TCK is obsolescent and that sysconf(_SC_CLK_TCK)
+ should be used instead, but this requires including
+ <unistd.h>, which is too painful to configure. */
+# ifndef CLK_TCK
+# define CLK_TCK 100 /* guess for older hosts */
+# endif
+#else
+# define use_times_for_usertime 0
+#endif
diff --git a/gs/src/turboc.cfg b/gs/src/turboc.cfg
new file mode 100755
index 000000000..6f80f44e2
--- /dev/null
+++ b/gs/src/turboc.cfg
@@ -0,0 +1,5 @@
+-wdup -wret -wstr -w-stu -wsus -wvoi -wzst
+-waus -wdef -w-eff -w-par -w-pia -w-rch -wrvl
+-w-amb -w-amp -w-nod -w-stv -wuse
+-wapt -w-cln -wcpt -wdgn -wrpt -w-sig -w-ucp
+-N
diff --git a/gs/src/ugcclib.mak b/gs/src/ugcclib.mak
new file mode 100644
index 000000000..36eee3f7c
--- /dev/null
+++ b/gs/src/ugcclib.mak
@@ -0,0 +1,158 @@
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix / gcc library testing.
+
+include version.mak
+
+gsdir = /usr/local/share/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+GS_DOCDIR=$(gsatadir)/doc
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+SEARCH_HERE_FIRST=1
+GS_INIT=gs_init.ps
+
+GENOPT=-DDEBUG
+GS=gslib
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+PSRCDIR=libpng
+PVERSION=96
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+ZSRCDIR=zlib
+SHARE_ZLIB=0
+ZLIB_NAME=z
+
+CONFIG=
+
+CC=gcc
+CCLD=$(CC)
+
+#GCFLAGS=-Wall -Wpointer-arith -Wstrict-prototypes -Wwrite-strings
+GCFLAGS=-Dconst= -Wall -Wpointer-arith -Wstrict-prototypes
+CFLAGS=-g -O $(GCFLAGS) $(XCFLAGS)
+LDFLAGS=$(XLDFLAGS)
+EXTRALIBS=
+XINCLUDE=-I/usr/local/X/include
+XLIBDIRS=-L/usr/X11/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+FPU_TYPE=1
+
+FEATURE_DEVS=patlib.dev path1lib.dev hsblib.dev
+COMPILE_INITS=0
+BAND_LIST_STORAGE=file
+BAND_LIST_COMPRESSOR=zlib
+FILE_IMPLEMENTATION=stdio
+DEVICE_DEVS=x11.dev x11mono.dev x11alpha.dev x11cmyk.dev\
+ djet500.dev\
+ pbmraw.dev pgmraw.dev ppmraw.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=
+DEVICE_DEVS4=
+DEVICE_DEVS5=
+DEVICE_DEVS6=
+DEVICE_DEVS7=
+DEVICE_DEVS8=
+DEVICE_DEVS9=
+DEVICE_DEVS10=
+DEVICE_DEVS11=
+DEVICE_DEVS12=
+DEVICE_DEVS13=
+DEVICE_DEVS14=
+DEVICE_DEVS15=
+
+MAKEFILE=ugcclib.mak
+
+AK=
+CCAUX=$(CC)
+CCC=$(CC) $(CCFLAGS) -c
+CCLEAF=$(CCC)
+# When using gcc, CCA2K isn't needed....
+CCA2K=$(CC)
+
+include unixhead.mak
+
+include gs.mak
+include lib.mak
+include jpeg.mak
+include libpng.mak
+include zlib.mak
+include devs.mak
+
+# Following is from unixtail.mak, we have a different link step.
+unix__=gp_nofb.o gp_unix.o gp_unifs.o gp_unifn.o
+unix_.dev: $(unix__)
+ $(SETMOD) unix_ $(unix__)
+
+gp_unix.o: gp_unix.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h)
+
+sysv__=gp_nofb.o gp_unix.o gp_unifs.o gp_unifn.o gp_sysv.o
+sysv_.dev: $(sysv__)
+ $(SETMOD) sysv_ $(sysv__)
+
+gp_sysv.o: gp_sysv.c $(time__h) $(AK)
+
+ansi2knr: ansi2knr.c $(stdio__h) $(string__h) $(malloc__h)
+ $(CCA2K) $(O)ansi2knr ansi2knr.c
+
+echogs: echogs.c
+ $(CCAUX) $(O)echogs echogs.c
+
+genarch: genarch.c $(stdpre_h)
+ $(CCAUX) $(O)genarch genarch.c
+
+genconf: genconf.c $(stdpre_h)
+ $(CCAUX) $(O)genconf genconf.c
+
+geninit: geninit.c $(stdio__h) $(string__h)
+ $(CCAUX) $(O)geninit geninit.c
+
+INCLUDE=/usr/include
+gconfig_.h: unixtail.mak echogs
+ ./echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ sh -c 'if ( test -f $(INCLUDE)/dirent.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H; fi'
+ sh -c 'if ( test -f $(INCLUDE)/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_NDIR_H; fi'
+ sh -c 'if ( test -f $(INCLUDE)/sys/dir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_DIR_H; fi'
+ sh -c 'if ( test -f $(INCLUDE)/sys/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_NDIR_H; fi'
+ sh -c 'if ( test -f $(INCLUDE)/sys/time.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H; fi'
+ sh -c 'if ( test -f $(INCLUDE)/sys/times.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIMES_H; fi'
+
+LIB_ONLY=gslib.o gsnogc.o gconfig.o gscdefs.o
+$(GS): $(ld_tr) echogs $(LIB_ALL) $(DEVS_ALL) $(LIB_ONLY)
+ ./echogs -w ldt.tr -n - $(CCLD) $(LDFLAGS) $(XLIBDIRS) -o $(GS)
+ ./echogs -a ldt.tr -n -s $(LIB_ONLY) -s
+ cat $(ld_tr) >>ldt.tr
+ ./echogs -a ldt.tr -s - $(EXTRALIBS) -lm
+ LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; $(SH) <ldt.tr
+
+# Following is from unix-end.mak, we omit the install and tar_cat rules.
+pg:
+ make GENOPT='' CFLAGS='-pg -O $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+gconfigv.h: $(MAKEFILE) echogs
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
diff --git a/gs/src/unix-cc.mak b/gs/src/unix-cc.mak
new file mode 100755
index 000000000..272f28de5
--- /dev/null
+++ b/gs/src/unix-cc.mak
@@ -0,0 +1,5775 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile fragment containing the current revision identification.
+
+# Define the name of this makefile.
+VERSION_MAK=version.mak
+
+# Major and minor version numbers.
+# MINOR0 is different from MINOR only if MINOR is a single digit.
+GS_VERSION_MAJOR=5
+GS_VERSION_MINOR=13
+GS_VERSION_MINOR0=13
+# Revision date: year x 10000 + month x 100 + day.
+GS_REVISIONDATE=19980427
+
+# Derived values
+GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0)
+GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR)
+GS_REVISION=$(GS_VERSION)
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/cc/X11 configuration.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unix-cc.mak #
+# or makefile. Edit cc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+#GENOPT=-DDEBUG
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the other compilation flags. Add at most one of the following:
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# Also add -Xa if your compiler accepts it.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+XCFLAGS=
+
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS and some others want -X; Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+XLIBDIRS=-L/usr/local/X/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+# Sun's cc can't compile gdevcdj.c.
+#DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS4=
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS6=
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=jpeg.dev jpeggray.dev pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=cc-head.mak
+
+# Define the ANSI-to-K&R dependency.
+
+# This should be ansi2knr$(XEAUX), or $(ANSI2KNR_XE), but these macros
+# haven't been defined yet, and some buggy 'make' programs expand macros in
+# definitions at the time of definition rather than at the time of use.
+AK=ansi2knr
+
+# Define the compilation rules and flags.
+
+CCC=$(SHP)ccgs "$(CC) $(CCFLAGS) -c"
+# We compile ansi2knr, and only ansi2knr, unmodified.
+CCA2K=$(CC)
+CCAUX=$(SHP)ccgs "$(CC)"
+CCLEAF=$(CCC)
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
+# Copyright (C) 1990, 1993, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name. For a "stock" System V platform,
+# use sysv_ instead of unix_.
+
+PLATFORM=unix_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=
+O=-o ./
+OBJ=o
+XE=
+XEAUX=
+
+# Define the current directory prefix and command invocations.
+
+CAT=cat
+D=/
+EXPP=
+EXP=./
+SHELL=/bin/sh
+SH=$(SHELL)
+SHP=$(SH) $(EXP)
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+RMN_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p "%s&s&&" -pl "&-l%s&s&&" -pL "&-L%s&s&&" -ol $(ld_tr)
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Patch a couple of PC-specific things that aren't relevant to Unix builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Generic makefile, common to all platforms.
+# The platform-specific makefiles `include' this file.
+# They define the following symbols:
+# GS - the name of the executable (without the extension, if any).
+# GS_LIB_DEFAULT - the default directory/ies for searching for the
+# initialization and font files at run time.
+# SEARCH_HERE_FIRST - the default setting of -P (whether or not to
+# look for files in the current directory first).
+# GS_DOCDIR - the directory where documentation will be available
+# at run time.
+# JSRCDIR - the directory where the IJG JPEG library source code
+# is stored (at compilation time).
+# JVERSION - the major version number of the IJG JPEG library.
+# PSRCDIR, PVERSION - the same for libpng.
+# ZSRCDIR - the same for zlib.
+# SHARE_LIBPNG - normally 0; if set to 1, asks the linker to use
+# an existing compiled libpng (-lpng) instead of compiling and
+# linking libpng explicitly.
+# LIBPNG_NAME, the name of the shared libpng, currently always
+# png (libpng, -lpng).
+# SHARE_ZLIB - normally 0; if set to 1, asks the linker to use
+# an existing compiled zlib (-lgz or -lz) instead of compiling
+# and linking libgz/libz explicitly.
+# ZLIB_NAME - the name of the shared zlib, either gz (for libgz, -lgz)
+# or z (for libz, -lz).
+# CONFIG - a configuration ID, added at the request of a customer,
+# that is supposed to help in maintaining multiple variants in
+# a single directory. Normally this is an empty string;
+# it may be any string that is legal as part of a file name.
+# DEVICE_DEVS - the devices to include in the executable.
+# See devs.mak for details.
+# DEVICE_DEVS1...DEVICE_DEVS15 - additional devices, if the definition
+# of DEVICE_DEVS doesn't fit on one line. See devs.mak for details.
+# FEATURE_DEVS - what features to include in the executable.
+# Normally this is one of:
+# level1 - a standard PostScript Level 1 language
+# interpreter.
+# level2 - a standard PostScript Level 2 language
+# interpreter.
+# pdf - a PDF-capable interpreter.
+# You may include both level1 and pdf, or both level2 and pdf.
+# The following feature may be added to either of the standard
+# configurations:
+# ccfonts - precompile fonts into C, and link them
+# with the executable. See fonts.txt for details.
+# The remaining features are of interest primarily to developers
+# who want to "mix and match" features to create custom
+# configurations:
+# dps - (partial) support for Display PostScript extensions:
+# see language.txt for details.
+# btoken - support for binary token encodings.
+# Included automatically in the dps and level2 features.
+# cidfont - (currently partial) support for CID-keyed fonts.
+# color - support for the Level 1 CMYK color extensions.
+# Included automatically in the dps and level2 features.
+# compfont - support for composite (type 0) fonts.
+# Included automatically in the level2 feature.
+# dct - support for DCTEncode/Decode filters.
+# Included automatically in the level2 feature.
+# epsf - support for recognizing and skipping the binary
+# header of MS-DOS EPSF files.
+# filter - support for Level 2 filters (other than eexec,
+# ASCIIHexEncode/Decode, NullEncode, PFBDecode,
+# RunLengthEncode/Decode, and SubFileDecode, which are
+# always included, and DCTEncode/Decode,
+# which are separate).
+# Included automatically in the level2 feature.
+# fzlib - support for zlibEncode/Decode filters.
+# ttfont - support for TrueType fonts.
+# type1 - support for Type 1 fonts and eexec;
+# normally included automatically in all configurations.
+# type42 - support for Type 42 (embedded TrueType) fonts.
+# Included automatically in the level2 feature.
+# There are quite a number of other sub-features that can be
+# selectively included in or excluded from a configuration,
+# but the above are the ones that are most likely to be of
+# interest.
+# COMPILE_INITS - normally 0; if set to 1, compiles the PostScript
+# language initialization files (gs_init.ps et al) into the
+# executable, eliminating the need for these files to be present
+# at run time.
+# BAND_LIST_STORAGE - normally file; if set to memory, stores band
+# lists in memory (with compression if needed).
+# BAND_LIST_COMPRESSOR - normally zlib: selects the compression method
+# to use for band lists in memory.
+# FILE_IMPLEMENTATION - normally stdio; if set to fd, uses file
+# descriptors instead of buffered stdio for file I/O; if set to
+# both, provides both implementations with different procedure
+# names for the fd-based implementation (see sfxfd.c for
+# more information).
+# EXTEND_NAMES - a value N between 0 and 6, indicating that the name
+# table should have a capacity of 2^(16+N) names. This normally
+# should be set to 0 (or left undefined), since non-zero values
+# result in a larger fixed space overhead and slightly slower code.
+# EXTEND_NAMES is ignored in 16-bit environments.
+#
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+# GS_INIT - the name of the initialization file for the interpreter,
+# normally gs_init.ps.
+# PLATFORM - a "device" name for the platform, so that platforms can
+# add various kinds of resources like devices and features.
+# CMD - the suffix for shell command files (e.g., null or .bat).
+# (This is only needed in a few places.)
+# D - the directory separator character (\ for MS-DOS, / for Unix).
+# O - the string for specifying the output file from the C compiler
+# (-o for MS-DOS, -o ./ for Unix).
+# OBJ - the extension for relocatable object files (e.g., o or obj).
+# XE - the extension for executable files (e.g., null or .exe).
+# XEAUX - the extension for the executable files (e.g., null or .exe)
+# for the utility programs (ansi2knr and those compiled with
+# CCAUX).
+# BEGINFILES - the list of files that `make begin' and `make clean'
+# should delete.
+# CCA2K - the C invocation for the ansi2knr program, which is the only
+# one that doesn't use ANSI C syntax. (It is only needed if
+# the main C compiler also isn't an ANSI compiler.)
+# CCAUX - the C invocation for auxiliary programs (echogs, genarch,
+# genconf, geninit).
+# CCBEGIN - the compilation command for `make begin', normally
+# $(CCC) *.c.
+# CCC - the C invocation for normal compilation.
+# CCD - the C invocation for files that store into frame buffers or
+# device registers. Needed because some optimizing compilers
+# will eliminate necessary stores.
+# CCCF - the C invocation for compiled fonts and other large,
+# self-contained data modules. Needed because MS-DOS
+# requires using the 'huge' memory model for these.
+# CCINT - the C invocation for compiling the main interpreter module,
+# normally the same as CCC: this is needed because the
+# Borland compiler generates *worse* code for this module
+# (but only this module) when optimization (-O) is turned on.
+# CCLEAF - the C invocation for compiling modules that contain only
+# leaf procedures, which don't need to build stack frames.
+# This is needed only because many compilers aren't able to
+# recognize leaf procedures on their own.
+# AK - if source files must be converted from ANSI to K&R syntax,
+# this is $(ANSI2KNR_XE); if not, it is null.
+# If a particular platform requires other utility programs
+# to be built, AK must include them too.
+# SHP - the prefix for invoking a shell script in the current directory
+# (null for MS-DOS, $(SH) ./ for Unix).
+# EXPP, EXP - the prefix for invoking an executable program in the
+# current directory (null for MS-DOS, ./ for Unix).
+# SH - the shell for scripts (null on MS-DOS, sh on Unix).
+# CONFILES - the arguments for genconf to generate the appropriate
+# linker control files (various).
+# CP_ - the command for copying one file to another. Because of
+# limitations in the MS-DOS/MS Windows environment, the
+# second argument must either be '.' (in which case the
+# write date may be either preserved or set to the current
+# date) or a file name (in which case the write date is
+# always updated).
+# RM_ - the command for deleting (a) file(s) (including wild cards,
+# but limited to a single file or pattern).
+# RMN_ = the command for deleting multiple files / patterns.
+#
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+# Define the name of this makefile.
+GS_MAK=gs.mak
+
+# Define the names of the executables.
+GS_XE=$(GS)$(XE)
+ANSI2KNR_XE=ansi2knr$(XEAUX)
+ECHOGS_XE=echogs$(XEAUX)
+GENARCH_XE=genarch$(XEAUX)
+GENCONF_XE=genconf$(XEAUX)
+GENINIT_XE=geninit$(XEAUX)
+
+# Define the names of the CONFIG-dependent header files.
+# gconfig*.h and gconfx*.h are generated dynamically.
+gconfig_h=gconfxx$(CONFIG).h
+gconfigf_h=gconfxc$(CONFIG).h
+
+# Watcom make insists that rules have a non-empty body!
+all default: $(GS_XE)
+ $(RM_) _temp_*
+
+distclean maintainer-clean realclean: clean
+ $(RM_) makefile
+
+clean: mostlyclean
+ $(RM_) arch.h
+ $(RM_) $(GS_XE)
+
+mostlyclean:
+ $(RMN_) *.$(OBJ) *.a core gmon.out
+ $(RMN_) *.dev *.d_* devs*.tr gconfig*.h gconfx*.h j*.h o*.tr l*.tr
+ $(RMN_) deflate.h zutil.h
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) _temp_* _temp_*.* *.map *.sym
+ $(RMN_) $(ANSI2KNR_XE) $(ECHOGS_XE) $(GENARCH_XE) $(GENCONF_XE) $(GENINIT_XE)
+ $(RMN_) gs_init.c $(BEGINFILES)
+
+# Remove only configuration-dependent information.
+config-clean:
+ $(RMN_) *.dev devs*.tr gconfig*.h gconfx*.h o*.tr l*.tr
+
+# A rule to do a quick and dirty compilation attempt when first installing
+# the interpreter. Many of the compilations will fail:
+# follow this with 'make'.
+
+begin:
+ $(RMN_) arch.h gconfig*.h gconfx*.h $(GENARCH_XE) $(GS_XE)
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) gs_init.c $(BEGINFILES)
+ make arch.h gconfigv.h
+ - $(CCBEGIN)
+ $(RMN_) gconfig.$(OBJ) gdev*.$(OBJ) gp_*.$(OBJ) gscdefs.$(OBJ) gsmisc.$(OBJ)
+ $(RMN_) icfontab.$(OBJ) iconfig.$(OBJ) iinit.$(OBJ) interp.$(OBJ)
+
+# Auxiliary programs
+
+arch.h: $(GENARCH_XE)
+ $(EXPP) $(EXP)genarch arch.h
+
+# Macros for constructing the *.dev files that describe features and
+# devices.
+SETDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-obj
+SETPDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-include -lpage -l-obj
+SETMOD=$(EXP)echogs -e .dev -w- -l-obj
+ADDMOD=$(EXP)echogs -e .dev -a-
+
+# Define the compilation commands for the third-party libraries.
+CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR) -DPNG_USE_CONST
+CCCJ=$(CCC) -I. -I$(JSRCDIR)
+CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+
+######################## How to define new 'features' #######################
+#
+# One defines new 'features' exactly like devices (see devs.mak for details).
+# For example, one would define a feature abc by adding the following to
+# gs.mak:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_)
+# $(SETMOD) abc $(abc_)
+# $(ADDMOD) abc -obj ... [if needed]
+# $(ADDMOD) abc -oper ... [if appropriate]
+# $(ADDMOD) abc -ps ... [if appropriate]
+#
+# If the abc feature requires the presence of some other features jkl and
+# pqr, then the rules must look like this:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_) jkl.dev pqr.dev
+# $(SETMOD) abc $(abc_)
+# ...
+# $(ADDMOD) abc -include jkl pqr
+
+# --------------------- Configuration-dependent files --------------------- #
+
+# gconfig.h shouldn't have to depend on DEVS_ALL, but that would
+# involve rewriting gsconfig to only save the device name, not the
+# contents of the <device>.dev files.
+# FEATURE_DEVS must precede DEVICE_DEVS so that devices can override
+# features in obscure cases.
+
+DEVS_ALL=$(PLATFORM).dev $(FEATURE_DEVS) \
+ $(DEVICE_DEVS) $(DEVICE_DEVS1) \
+ $(DEVICE_DEVS2) $(DEVICE_DEVS3) $(DEVICE_DEVS4) $(DEVICE_DEVS5) \
+ $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
+ $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
+ $(DEVICE_DEVS14) $(DEVICE_DEVS15)
+
+devs_tr=devs.tr$(CONFIG)
+$(devs_tr): $(GS_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w $(devs_tr) - -include $(PLATFORM).dev
+ $(EXP)echogs -a $(devs_tr) - $(FEATURE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS1)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS2)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS3)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS4)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS5)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS6)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS7)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS8)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS9)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS10)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS11)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS12)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS13)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS14)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS15)
+
+# GCONFIG_EXTRAS can be set on the command line.
+# Note that it consists of arguments for echogs, i.e.,
+# it isn't just literal text.
+GCONFIG_EXTRAS=
+
+ld_tr=ld$(CONFIG).tr
+$(gconfig_h) $(ld_tr) lib.tr: \
+ $(GS_MAK) $(MAKEFILE) version.mak $(GENCONF_XE) $(ECHOGS_XE) $(devs_tr) $(DEVS_ALL) libcore.dev
+ $(EXP)genconf $(devs_tr) libcore.dev -h $(gconfig_h) $(CONFILES)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_LIB_DEFAULT -x 2022 $(GS_LIB_DEFAULT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u SEARCH_HERE_FIRST -s $(SEARCH_HERE_FIRST)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_DOCDIR -x 2022 $(GS_DOCDIR) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_INIT -x 2022 $(GS_INIT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISION -s $(GS_REVISION)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISIONDATE -s $(GS_REVISIONDATE)
+ $(EXP)echogs -a $(gconfig_h) $(GCONFIG_EXTRAS)
+
+################################################################
+# The other platform-independent makefiles are concatenated
+# (or included) after this one:
+# lib.mak
+# int.mak
+# jpeg.mak
+# libpng.mak
+# zlib.mak
+# devs.mak
+################################################################
+# Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for graphics library and other support code.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+LIB_MAK=lib.mak
+
+# Define the inter-dependencies of the .h files.
+# Since not all versions of `make' defer expansion of macros,
+# we must list these in bottom-to-top order.
+
+# Generic files
+
+arch_h=arch.h
+stdpre_h=stdpre.h
+std_h=std.h $(arch_h) $(stdpre_h)
+
+# Platform interfaces
+
+gp_h=gp.h
+gpcheck_h=gpcheck.h
+gpsync_h=gpsync.h
+
+# Configuration definitions
+
+# gconfig*.h are generated dynamically.
+gconfig__h=gconfig_.h
+gconfigv_h=gconfigv.h
+gscdefs_h=gscdefs.h
+
+# C library interfaces
+
+# Because of variations in the "standard" header files between systems, and
+# because we must include std.h before any file that includes sys/types.h,
+# we define local include files named *_.h to substitute for <*.h>.
+
+vmsmath_h=vmsmath.h
+
+dos__h=dos_.h
+ctype__h=ctype_.h $(std_h)
+dirent__h=dirent_.h $(std_h) $(gconfig__h)
+errno__h=errno_.h $(std_h)
+malloc__h=malloc_.h $(std_h)
+math__h=math_.h $(std_h) $(vmsmath_h)
+memory__h=memory_.h $(std_h)
+stat__h=stat_.h $(std_h)
+stdio__h=stdio_.h $(std_h)
+string__h=string_.h $(std_h)
+time__h=time_.h $(std_h) $(gconfig__h)
+windows__h=windows_.h
+
+# Miscellaneous
+
+gdebug_h=gdebug.h
+gsalloc_h=gsalloc.h
+gsargs_h=gsargs.h
+gserror_h=gserror.h
+gserrors_h=gserrors.h
+gsexit_h=gsexit.h
+gsgc_h=gsgc.h
+gsio_h=gsio.h
+gsmdebug_h=gsmdebug.h
+gsmemraw_h=gsmemraw.h
+gsmemory_h=gsmemory.h $(gsmemraw_h)
+gsrefct_h=gsrefct.h
+gsstruct_h=gsstruct.h
+gstypes_h=gstypes.h
+gx_h=gx.h $(stdio__h) $(gdebug_h) $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
+
+GX=$(AK) $(gx_h)
+GXERR=$(GX) $(gserrors_h)
+
+###### Support
+
+### Include files
+
+gsbitmap_h=gsbitmap.h $(gsstruct_h)
+gsbitops_h=gsbitops.h
+gsbittab_h=gsbittab.h
+gsflip_h=gsflip.h
+gsuid_h=gsuid.h
+gsutil_h=gsutil.h
+gxarith_h=gxarith.h
+gxbitmap_h=gxbitmap.h $(gsbitmap_h) $(gstypes_h)
+gxfarith_h=gxfarith.h $(gconfigv_h) $(gxarith_h)
+gxfixed_h=gxfixed.h
+gxobj_h=gxobj.h $(gxbitmap_h)
+# Out of order
+gxalloc_h=gxalloc.h $(gsalloc_h) $(gxobj_h)
+
+### Executable code
+
+gsalloc.$(OBJ): gsalloc.c $(GX) $(memory__h) $(string__h) \
+ $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsargs.$(OBJ): gsargs.c $(ctype__h) $(stdio__h) $(string__h)\
+ $(gsargs_h) $(gsexit_h) $(gsmemory_h)
+
+gsbitops.$(OBJ): gsbitops.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gsbitops_h) $(gstypes_h)
+
+gsbittab.$(OBJ): gsbittab.c $(AK) $(stdpre_h) $(gsbittab_h)
+
+# gsfemu is only used in FPU-less configurations, and currently only with gcc.
+# We thought using CCLEAF would produce smaller code, but it actually
+# produces larger code!
+gsfemu.$(OBJ): gsfemu.c $(AK) $(std_h)
+
+# gsflip is not part of the standard configuration: it's rather large,
+# and no standard facility requires it.
+gsflip.$(OBJ): gsflip.c $(GX) $(gsbittab_h) $(gsflip_h)
+ $(CCLEAF) gsflip.c
+
+gsmemory.$(OBJ): gsmemory.c $(GX) $(malloc__h) $(memory__h) \
+ $(gsmdebug_h) $(gsrefct_h) $(gsstruct_h) $(gsmemraw_h)
+
+gsmisc.$(OBJ): gsmisc.c $(GXERR) $(gconfigv_h) \
+ $(malloc__h) $(math__h) $(memory__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h)
+
+# gsnogc currently is only used in library-only configurations.
+gsnogc.$(OBJ): gsnogc.c $(GX)\
+ $(gsgc_h) $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsutil.$(OBJ): gsutil.c $(AK) $(memory__h) $(string__h) $(gconfigv_h)\
+ $(gstypes_h) $(gsuid_h) $(gsutil_h)
+
+###### Low-level facilities and utilities
+
+### Include files
+
+gdevbbox_h=gdevbbox.h
+gdevmem_h=gdevmem.h $(gsbitops_h)
+gdevmrop_h=gdevmrop.h
+
+gsccode_h=gsccode.h
+gsccolor_h=gsccolor.h $(gsstruct_h)
+gscsel_h=gscsel.h
+gscolor1_h=gscolor1.h
+gscoord_h=gscoord.h
+gscpm_h=gscpm.h
+gsdevice_h=gsdevice.h
+gsfcmap_h=gsfcmap.h $(gsccode_h)
+gsfont_h=gsfont.h
+gshsb_h=gshsb.h
+gsht_h=gsht.h
+gsht1_h=gsht1.h $(gsht_h)
+gsiparam_h=gsiparam.h
+gsjconf_h=gsjconf.h $(std_h)
+gslib_h=gslib.h
+gslparam_h=gslparam.h
+gsmatrix_h=gsmatrix.h
+gspaint_h=gspaint.h
+gsparam_h=gsparam.h
+gsparams_h=gsparams.h $(gsparam_h)
+gspath2_h=gspath2.h
+gspenum_h=gspenum.h
+gsropt_h=gsropt.h
+gsxfont_h=gsxfont.h
+# Out of order
+gschar_h=gschar.h $(gsccode_h) $(gscpm_h)
+gscolor2_h=gscolor2.h $(gsccolor_h) $(gsuid_h) $(gxbitmap_h)
+gsimage_h=gsimage.h $(gsiparam_h)
+gsline_h=gsline.h $(gslparam_h)
+gspath_h=gspath.h $(gspenum_h)
+gsrop_h=gsrop.h $(gsropt_h)
+
+gxbcache_h=gxbcache.h $(gxbitmap_h)
+gxchar_h=gxchar.h $(gschar_h)
+gxcindex_h=gxcindex.h
+gxcvalue_h=gxcvalue.h
+gxclio_h=gxclio.h
+gxclip2_h=gxclip2.h
+gxcolor2_h=gxcolor2.h $(gscolor2_h) $(gsrefct_h) $(gxbitmap_h)
+gxcoord_h=gxcoord.h $(gscoord_h)
+gxcpath_h=gxcpath.h
+gxdda_h=gxdda.h
+gxdevrop_h=gxdevrop.h
+gxdevmem_h=gxdevmem.h
+gxdither_h=gxdither.h
+gxfcmap_h=gxfcmap.h $(gsfcmap_h) $(gsuid_h)
+gxfont0_h=gxfont0.h
+gxfrac_h=gxfrac.h
+gxftype_h=gxftype.h
+gxhttile_h=gxhttile.h
+gxhttype_h=gxhttype.h
+gxiodev_h=gxiodev.h $(stat__h)
+gxline_h=gxline.h $(gslparam_h)
+gxlum_h=gxlum.h
+gxmatrix_h=gxmatrix.h $(gsmatrix_h)
+gxpaint_h=gxpaint.h
+gxpath_h=gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h)
+gxpcache_h=gxpcache.h
+gxpcolor_h=gxpcolor.h $(gxpcache_h)
+gxsample_h=gxsample.h
+gxstate_h=gxstate.h
+gxtmap_h=gxtmap.h
+gxxfont_h=gxxfont.h $(gsccode_h) $(gsmatrix_h) $(gsuid_h) $(gsxfont_h)
+# The following are out of order because they include other files.
+gsdcolor_h=gsdcolor.h $(gsccolor_h) $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+gxdcolor_h=gxdcolor.h $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gxdevice_h=gxdevice.h $(stdio__h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h) \
+ $(gsropt_h) $(gsstruct_h) $(gsxfont_h) \
+ $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)
+gxdht_h=gxdht.h $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+gxctable_h=gxctable.h $(gxfixed_h) $(gxfrac_h)
+gxfcache_h=gxfcache.h $(gsuid_h) $(gsxfont_h) $(gxbcache_h) $(gxftype_h)
+gxfont_h=gxfont.h $(gsfont_h) $(gsuid_h) $(gsstruct_h) $(gxftype_h)
+gscie_h=gscie.h $(gsrefct_h) $(gxctable_h)
+gscsepr_h=gscsepr.h
+gscspace_h=gscspace.h
+gxdcconv_h=gxdcconv.h $(gxfrac_h)
+gxfmap_h=gxfmap.h $(gsrefct_h) $(gxfrac_h) $(gxtmap_h)
+gxistate_h=gxistate.h $(gscsel_h) $(gsropt_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+gxband_h=gxband.h $(gxclio_h)
+gxclist_h=gxclist.h $(gscspace_h) $(gxbcache_h) $(gxclio_h) $(gxistate_h) $(gxband_h)
+gxcmap_h=gxcmap.h $(gscsel_h) $(gxcvalue_h) $(gxfmap_h)
+gxcspace_h=gxcspace.h $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gsstruct_h) $(gxfrac_h)
+gxht_h=gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gscolor_h=gscolor.h $(gxtmap_h)
+gsstate_h=gsstate.h $(gscolor_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
+
+gzacpath_h=gzacpath.h
+gzcpath_h=gzcpath.h $(gxcpath_h)
+gzht_h=gzht.h $(gscsel_h) $(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
+gzline_h=gzline.h $(gxline_h)
+gzpath_h=gzpath.h $(gsstruct_h) $(gxpath_h)
+gzstate_h=gzstate.h $(gscpm_h) $(gsrefct_h) $(gsstate_h)\
+ $(gxdcolor_h) $(gxistate_h) $(gxstate_h)
+
+gdevprn_h=gdevprn.h $(memory__h) $(string__h) $(gx_h) \
+ $(gserrors_h) $(gsmatrix_h) $(gsparam_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxdevmem_h) $(gxclist_h)
+
+sa85x_h=sa85x.h
+sbtx_h=sbtx.h
+scanchar_h=scanchar.h
+scommon_h=scommon.h $(gsmemory_h) $(gstypes_h) $(gsstruct_h)
+sdct_h=sdct.h
+shc_h=shc.h $(gsbittab_h)
+siscale_h=siscale.h $(gconfigv_h)
+sjpeg_h=sjpeg.h
+slzwx_h=slzwx.h
+spcxx_h=spcxx.h
+spdiffx_h=spdiffx.h
+spngpx_h=spngpx.h
+srlx_h=srlx.h
+sstring_h=sstring.h
+strimpl_h=strimpl.h $(scommon_h) $(gstypes_h) $(gsstruct_h)
+szlibx_h=szlibx.h
+# Out of order
+scf_h=scf.h $(shc_h)
+scfx_h=scfx.h $(shc_h)
+gximage_h=gximage.h $(gsiparam_h) $(gxcspace_h) $(gxdda_h) $(gxsample_h)\
+ $(siscale_h) $(strimpl_h)
+
+### Executable code
+
+# gconfig and gscdefs are handled specially. Currently they go in psbase
+# rather than in libcore, which is clearly wrong.
+gconfig=gconfig$(CONFIG)
+$(gconfig).$(OBJ): gconf.c $(GX) \
+ $(gscdefs_h) $(gconfig_h) $(gxdevice_h) $(gxiodev_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gconf.c $(gconfig).c
+ $(CCC) $(gconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+
+gscdefs=gscdefs$(CONFIG)
+$(gscdefs).$(OBJ): gscdef.c $(stdpre_h) $(gscdefs_h) $(gconfig_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gscdef.c $(gscdefs).c
+ $(CCC) $(gscdefs).c
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+
+gxacpath.$(OBJ): gxacpath.c $(GXERR) \
+ $(gsdcolor_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxpaint_h) \
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)
+
+gxbcache.$(OBJ): gxbcache.c $(GX) $(memory__h) \
+ $(gsmdebug_h) $(gxbcache_h)
+
+gxccache.$(OBJ): gxccache.c $(GXERR) $(gpcheck_h) \
+ $(gscspace_h) $(gsimage_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxdevmem_h) $(gxfcache_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxhttile_h) $(gxmatrix_h) $(gxxfont_h) \
+ $(gzstate_h) $(gzpath_h) $(gzcpath_h)
+
+gxccman.$(OBJ): gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfont_h) $(gxfcache_h) $(gxchar_h)\
+ $(gxxfont_h) $(gzstate_h) $(gzpath_h)
+
+gxcht.$(OBJ): gxcht.c $(GXERR) $(memory__h)\
+ $(gsutil_h)\
+ $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h)\
+ $(gxmatrix_h) $(gzht_h)
+
+gxcmap.$(OBJ): gxcmap.c $(GXERR) \
+ $(gsccolor_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gxdither_h) \
+ $(gxfarith_h) $(gxfrac_h) $(gxlum_h) $(gzstate_h)
+
+gxcpath.$(OBJ): gxcpath.c $(GXERR)\
+ $(gscoord_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gzpath_h) $(gzcpath_h)
+
+gxdcconv.$(OBJ): gxdcconv.c $(GX) \
+ $(gsdcolor_h) $(gxcmap_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gxfarith_h) $(gxistate_h) $(gxlum_h)
+
+gxdcolor.$(OBJ): gxdcolor.c $(GX) \
+ $(gsbittab_h) $(gxdcolor_h) $(gxdevice_h)
+
+gxdither.$(OBJ): gxdither.c $(GX) \
+ $(gsstruct_h) $(gsdcolor_h) \
+ $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
+
+gxfill.$(OBJ): gxfill.c $(GXERR) $(math__h) \
+ $(gsstruct_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h) \
+ $(gxistate_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+gxht.$(OBJ): gxht.c $(GXERR) $(memory__h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+
+gximage.$(OBJ): gximage.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h) $(gsstruct_h)\
+ $(gxfixed_h) $(gxfrac_h) $(gxarith_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gzpath_h) $(gzstate_h)\
+ $(gzcpath_h) $(gxdevmem_h) $(gximage_h) $(gdevmrop_h)
+
+gximage0.$(OBJ): gximage0.c $(GXERR) $(memory__h)\
+ $(gxcpath_h) $(gxdevice_h) $(gximage_h)
+
+gximage1.$(OBJ): gximage1.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsbittab_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gximage2.$(OBJ): gximage2.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gxpaint.$(OBJ): gxpaint.c $(GX) \
+ $(gxdevice_h) $(gxhttile_h) $(gxpaint_h) $(gxpath_h) $(gzstate_h)
+
+gxpath.$(OBJ): gxpath.c $(GXERR) \
+ $(gsstruct_h) $(gxfixed_h) $(gzpath_h)
+
+gxpath2.$(OBJ): gxpath2.c $(GXERR) $(math__h) \
+ $(gxfixed_h) $(gxarith_h) $(gzpath_h)
+
+gxpcopy.$(OBJ): gxpcopy.c $(GXERR) $(math__h) $(gconfigv_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxpdash.$(OBJ): gxpdash.c $(GX) $(math__h) \
+ $(gscoord_h) $(gsline_h) $(gsmatrix_h) \
+ $(gxfixed_h) $(gzline_h) $(gzpath_h)
+
+gxpflat.$(OBJ): gxpflat.c $(GX)\
+ $(gxarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxsample.$(OBJ): gxsample.c $(GX)\
+ $(gxsample_h)
+
+gxstroke.$(OBJ): gxstroke.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gscoord_h) $(gsdcolor_h) $(gsdevice_h) \
+ $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) \
+ $(gxhttile_h) $(gxistate_h) $(gxmatrix_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzline_h) $(gzpath_h)
+
+###### Higher-level facilities
+
+gschar.$(OBJ): gschar.c $(GXERR) $(memory__h) $(string__h)\
+ $(gspath_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxarith_h) $(gxmatrix_h) $(gxcoord_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxfcache_h) $(gzpath_h) $(gzstate_h)
+
+gscolor.$(OBJ): gscolor.c $(GXERR) \
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
+
+gscoord.$(OBJ): gscoord.c $(GXERR) $(math__h) \
+ $(gsccode_h) $(gxcoord_h) $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) $(gxfont_h) \
+ $(gxmatrix_h) $(gxpath_h) $(gzstate_h)
+
+gsdevice.$(OBJ): gsdevice.c $(GXERR) $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
+ $(gscdefs_h) $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstruct_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gzstate_h)
+
+gsdevmem.$(OBJ): gsdevmem.c $(GXERR) $(math__h) $(memory__h) \
+ $(gxarith_h) $(gxdevice_h) $(gxdevmem_h)
+
+gsdparam.$(OBJ): gsdparam.c $(GXERR) $(memory__h) $(string__h) \
+ $(gsparam_h) $(gxdevice_h) $(gxfixed_h)
+
+gsfont.$(OBJ): gsfont.c $(GXERR) $(memory__h)\
+ $(gschar_h) $(gsstruct_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)
+
+gsht.$(OBJ): gsht.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gshtscr.$(OBJ): gshtscr.c $(GXERR) $(math__h) \
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gsimage.$(OBJ): gsimage.c $(GXERR) $(memory__h)\
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxdevice_h) $(gzstate_h)
+
+gsimpath.$(OBJ): gsimpath.c $(GXERR) \
+ $(gsmatrix_h) $(gsstate_h) $(gspath_h)
+
+gsinit.$(OBJ): gsinit.c $(memory__h) $(stdio__h) \
+ $(gdebug_h) $(gp_h) $(gscdefs_h) $(gslib_h) $(gsmemory_h)
+
+gsiodev.$(OBJ): gsiodev.c $(GXERR) $(errno__h) $(string__h) \
+ $(gp_h) $(gsparam_h) $(gxiodev_h)
+
+gsline.$(OBJ): gsline.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsline_h) $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gzline_h)
+
+gsmatrix.$(OBJ): gsmatrix.c $(GXERR) $(math__h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h)
+
+gspaint.$(OBJ): gspaint.c $(GXERR) $(math__h) $(gpcheck_h)\
+ $(gspaint_h) $(gspath_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdevmem_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxpaint_h)\
+ $(gzpath_h) $(gzstate_h)
+
+gsparam.$(OBJ): gsparam.c $(GXERR) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsstruct_h)
+
+gsparams.$(OBJ): gsparams.c $(gx_h) $(memory__h) $(gserrors_h) $(gsparam_h)
+
+gspath.$(OBJ): gspath.c $(GXERR) \
+ $(gscoord_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+gsstate.$(OBJ): gsstate.c $(GXERR) $(memory__h)\
+ $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h) \
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+
+###### The internal devices
+
+### The built-in device implementations:
+
+# The bounding box device is not normally a free-standing device.
+# To configure it as one for testing, change SETMOD to SETDEV, and also
+# define TEST in gdevbbox.c.
+bbox.dev: $(LIB_MAK) $(ECHOGS_XE) gdevbbox.$(OBJ)
+ $(SETMOD) bbox gdevbbox.$(OBJ)
+
+gdevbbox.$(OBJ): gdevbbox.c $(GXERR) $(math__h) $(memory__h) \
+ $(gdevbbox_h) $(gsdevice_h) $(gsparam_h) \
+ $(gxcpath_h) $(gxdevice_h) $(gxistate_h) $(gxpaint_h) $(gxpath_h)
+
+gdevddrw.$(OBJ): gdevddrw.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h)
+
+gdevdflt.$(OBJ): gdevdflt.c $(GXERR) $(gpcheck_h)\
+ $(gsbittab_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)
+
+gdevnfwd.$(OBJ): gdevnfwd.c $(GX) \
+ $(gxdevice_h)
+
+# The render/RGB device is only here as an example, but we can configure
+# it as a real device for testing.
+rrgb.dev: $(LIB_MAK) $(ECHOGS_XE) gdevrrgb.$(OBJ) page.dev
+ $(SETPDEV) rrgb gdevrrgb.$(OBJ)
+
+gdevrrgb.$(OBJ): gdevrrgb.c $(AK)\
+ $(gdevprn_h)
+
+### The memory devices:
+
+gdevabuf.$(OBJ): gdevabuf.c $(GXERR) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmem.$(OBJ): gdevmem.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm1.$(OBJ): gdevm1.c $(GX) $(memory__h) $(gsrop_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm2.$(OBJ): gdevm2.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm4.$(OBJ): gdevm4.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm8.$(OBJ): gdevm8.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm16.$(OBJ): gdevm16.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm24.$(OBJ): gdevm24.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm32.$(OBJ): gdevm32.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmpla.$(OBJ): gdevmpla.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+# Create a pseudo-"feature" for the entire graphics library.
+
+LIB1s=gsalloc.$(OBJ) gsbitops.$(OBJ) gsbittab.$(OBJ)
+LIB2s=gschar.$(OBJ) gscolor.$(OBJ) gscoord.$(OBJ) gsdevice.$(OBJ) gsdevmem.$(OBJ)
+LIB3s=gsdparam.$(OBJ) gsfont.$(OBJ) gsht.$(OBJ) gshtscr.$(OBJ)
+LIB4s=gsimage.$(OBJ) gsimpath.$(OBJ) gsinit.$(OBJ) gsiodev.$(OBJ)
+LIB5s=gsline.$(OBJ) gsmatrix.$(OBJ) gsmemory.$(OBJ) gsmisc.$(OBJ)
+LIB6s=gspaint.$(OBJ) gsparam.$(OBJ) gsparams.$(OBJ) gspath.$(OBJ) gsstate.$(OBJ) gsutil.$(OBJ)
+LIB1x=gxacpath.$(OBJ) gxbcache.$(OBJ)
+LIB2x=gxccache.$(OBJ) gxccman.$(OBJ) gxcht.$(OBJ) gxcmap.$(OBJ) gxcpath.$(OBJ)
+LIB3x=gxdcconv.$(OBJ) gxdcolor.$(OBJ) gxdither.$(OBJ) gxfill.$(OBJ) gxht.$(OBJ)
+LIB4x=gximage.$(OBJ) gximage0.$(OBJ) gximage1.$(OBJ) gximage2.$(OBJ)
+LIB5x=gxpaint.$(OBJ) gxpath.$(OBJ) gxpath2.$(OBJ) gxpcopy.$(OBJ)
+LIB6x=gxpdash.$(OBJ) gxpflat.$(OBJ) gxsample.$(OBJ) gxstroke.$(OBJ)
+LIB1d=gdevabuf.$(OBJ) gdevddrw.$(OBJ) gdevdflt.$(OBJ) gdevnfwd.$(OBJ)
+LIB2d=gdevmem.$(OBJ) gdevm1.$(OBJ) gdevm2.$(OBJ) gdevm4.$(OBJ) gdevm8.$(OBJ)
+LIB3d=gdevm16.$(OBJ) gdevm24.$(OBJ) gdevm32.$(OBJ) gdevmpla.$(OBJ)
+LIBs=$(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s)
+LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d)
+LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
+libs.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBs)
+ $(EXP)echogs -w libs.dev $(LIB1s)
+ $(EXP)echogs -a libs.dev $(LIB2s)
+ $(EXP)echogs -a libs.dev $(LIB3s)
+ $(EXP)echogs -a libs.dev $(LIB4s)
+ $(EXP)echogs -a libs.dev $(LIB5s)
+ $(EXP)echogs -a libs.dev $(LIB6s)
+ $(ADDMOD) libs -init gscolor
+
+libx.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBx)
+ $(EXP)echogs -w libx.dev $(LIB1x)
+ $(EXP)echogs -a libx.dev $(LIB2x)
+ $(EXP)echogs -a libx.dev $(LIB3x)
+ $(EXP)echogs -a libx.dev $(LIB4x)
+ $(EXP)echogs -a libx.dev $(LIB5x)
+ $(EXP)echogs -a libx.dev $(LIB6x)
+ $(ADDMOD) libx -init gximage1 gximage2
+
+libd.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBd)
+ $(EXP)echogs -w libd.dev $(LIB1d)
+ $(EXP)echogs -a libd.dev $(LIB2d)
+ $(EXP)echogs -a libd.dev $(LIB3d)
+
+# roplib shouldn't be required....
+libcore.dev: $(LIB_MAK) $(ECHOGS_XE)\
+ libs.dev libx.dev libd.dev iscale.dev roplib.dev
+ $(SETMOD) libcore
+ $(ADDMOD) libcore -dev nullpage
+ $(ADDMOD) libcore -include libs libx libd iscale roplib
+
+# ---------------- Stream support ---------------- #
+# Currently the only things in the library that use this are clists
+# and file streams.
+
+stream_h=stream.h $(scommon_h)
+
+stream.$(OBJ): stream.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+# ---------------- File streams ---------------- #
+# Currently only the high-level drivers use these, but more drivers will
+# probably use them eventually.
+
+sfile_=sfx$(FILE_IMPLEMENTATION).$(OBJ) stream.$(OBJ)
+sfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(sfile_)
+ $(SETMOD) sfile $(sfile_)
+
+sfxstdio.$(OBJ): sfxstdio.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxfd.$(OBJ): sfxfd.c $(AK) $(stdio__h) $(errno__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxboth.$(OBJ): sfxboth.c sfxstdio.c sfxfd.c
+
+# ---------------- CCITTFax filters ---------------- #
+# These are used by clists, some drivers, and Level 2 in general.
+
+cfe_=scfe.$(OBJ) scfetab.$(OBJ) shc.$(OBJ)
+cfe.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfe_)
+ $(SETMOD) cfe $(cfe_)
+
+scfe.$(OBJ): scfe.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfetab.$(OBJ): scfetab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+shc.$(OBJ): shc.c $(AK) $(std_h) $(scommon_h) $(shc_h)
+
+cfd_=scfd.$(OBJ) scfdtab.$(OBJ)
+cfd.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfd_)
+ $(SETMOD) cfd $(cfd_)
+
+scfd.$(OBJ): scfd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfdtab.$(OBJ): scfdtab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+# ---------------- DCT (JPEG) filters ---------------- #
+# These are used by Level 2, and by the JPEG-writing driver.
+
+# Common code
+
+sdctc_=sdctc.$(OBJ) sjpegc.$(OBJ)
+
+sdctc.$(OBJ): sdctc.c $(AK) $(stdio__h)\
+ $(sdct_h) $(strimpl_h)\
+ jpeglib.h
+
+sjpegc.$(OBJ): sjpegc.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Encoding (compression)
+
+sdcte_=$(sdctc_) sdcte.$(OBJ) sjpege.$(OBJ)
+sdcte.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdcte_) jpege.dev
+ $(SETMOD) sdcte $(sdcte_)
+ $(ADDMOD) sdcte -include jpege
+
+sdcte.$(OBJ): sdcte.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpege.$(OBJ): sjpege.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Decoding (decompression)
+
+sdctd_=$(sdctc_) sdctd.$(OBJ) sjpegd.$(OBJ)
+sdctd.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdctd_) jpegd.dev
+ $(SETMOD) sdctd $(sdctd_)
+ $(ADDMOD) sdctd -include jpegd
+
+sdctd.$(OBJ): sdctd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpegd.$(OBJ): sjpegd.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h)\
+ jerror.h jpeglib.h
+
+# ---------------- LZW filters ---------------- #
+# These are used by Level 2 in general.
+
+slzwe_=slzwce
+#slzwe_=slzwe
+lzwe_=$(slzwe_).$(OBJ) slzwc.$(OBJ)
+lzwe.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwe_)
+ $(SETMOD) lzwe $(lzwe_)
+
+# We need slzwe.dev as a synonym for lzwe.dev for BAND_LIST_STORAGE = memory.
+slzwe.dev: lzwe.dev
+ $(CP_) lzwe.dev slzwe.dev
+
+slzwce.$(OBJ): slzwce.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwe.$(OBJ): slzwe.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwc.$(OBJ): slzwc.c $(AK) $(std_h)\
+ $(slzwx_h) $(strimpl_h)
+
+lzwd_=slzwd.$(OBJ) slzwc.$(OBJ)
+lzwd.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwd_)
+ $(SETMOD) lzwd $(lzwd_)
+
+# We need slzwd.dev as a synonym for lzwd.dev for BAND_LIST_STORAGE = memory.
+slzwd.dev: lzwd.dev
+ $(CP_) lzwd.dev slzwd.dev
+
+slzwd.$(OBJ): slzwd.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+# ---------------- PCX decoding filter ---------------- #
+# This is an adhoc filter not used by anything in the standard configuration.
+
+pcxd_=spcxd.$(OBJ)
+pcxd.dev: $(LIB_MAK) $(ECHOGS_XE) $(pcxd_)
+ $(SETMOD) pcxd $(pcxd_)
+
+spcxd.$(OBJ): spcxd.c $(AK) $(stdio__h) $(memory__h) \
+ $(spcxx_h) $(strimpl_h)
+
+# ---------------- Pixel-difference filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pdiff_=spdiff.$(OBJ)
+pdiff.dev: $(LIB_MAK) $(ECHOGS_XE) $(pdiff_)
+ $(SETMOD) pdiff $(pdiff_)
+
+spdiff.$(OBJ): spdiff.c $(AK) $(stdio__h)\
+ $(spdiffx_h) $(strimpl_h)
+
+# ---------------- PNG pixel prediction filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pngp_=spngp.$(OBJ)
+pngp.dev: $(LIB_MAK) $(ECHOGS_XE) $(pngp_)
+ $(SETMOD) pngp $(pngp_)
+
+spngp.$(OBJ): spngp.c $(AK) $(memory__h)\
+ $(spngpx_h) $(strimpl_h)
+
+# ---------------- RunLength filters ---------------- #
+# These are used by clists and also by Level 2 in general.
+
+rle_=srle.$(OBJ)
+rle.dev: $(LIB_MAK) $(ECHOGS_XE) $(rle_)
+ $(SETMOD) rle $(rle_)
+
+srle.$(OBJ): srle.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+rld_=srld.$(OBJ)
+rld.dev: $(LIB_MAK) $(ECHOGS_XE) $(rld_)
+ $(SETMOD) rld $(rld_)
+
+srld.$(OBJ): srld.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+# ---------------- String encoding/decoding filters ---------------- #
+# These are used by the PostScript and PDF writers, and also by the
+# PostScript interpreter.
+
+scantab.$(OBJ): scantab.c $(AK) $(stdpre_h)\
+ $(scanchar_h) $(scommon_h)
+
+sfilter2.$(OBJ): sfilter2.c $(AK) $(memory__h) $(stdio__h)\
+ $(sa85x_h) $(scanchar_h) $(sbtx_h) $(strimpl_h)
+
+sstring.$(OBJ): sstring.c $(AK) $(stdio__h) $(memory__h) $(string__h)\
+ $(scanchar_h) $(sstring_h) $(strimpl_h)
+
+# ---------------- zlib filters ---------------- #
+# These are used by clists and are also available as filters.
+
+szlibc_=szlibc.$(OBJ)
+
+szlibc.$(OBJ): szlibc.c $(AK) $(std_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibc.c
+
+szlibe_=$(szlibc_) szlibe.$(OBJ)
+szlibe.dev: $(LIB_MAK) $(ECHOGS_XE) zlibe.dev $(szlibe_)
+ $(SETMOD) szlibe $(szlibe_)
+ $(ADDMOD) szlibe -include zlibe
+
+szlibe.$(OBJ): szlibe.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibe.c
+
+szlibd_=$(szlibc_) szlibd.$(OBJ)
+szlibd.dev: $(LIB_MAK) $(ECHOGS_XE) zlibd.dev $(szlibd_)
+ $(SETMOD) szlibd $(szlibd_)
+ $(ADDMOD) szlibd -include zlibd
+
+szlibd.$(OBJ): szlibd.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibd.c
+
+# ---------------- Command lists ---------------- #
+
+gxcldev_h=gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
+ $(strimpl_h) $(scfx_h) $(srlx_h)
+gxclpage_h=gxclpage.h $(gxclio_h)
+gxclpath_h=gxclpath.h $(gxfixed_h)
+
+# Command list package. Currently the higher-level facilities are required,
+# but eventually they will be optional.
+clist.dev: $(LIB_MAK) $(ECHOGS_XE) clbase.dev clpath.dev
+ $(SETMOD) clist -include clbase clpath
+
+# Base command list facility.
+clbase1_=gxclist.$(OBJ) gxclbits.$(OBJ) gxclpage.$(OBJ)
+clbase2_=gxclread.$(OBJ) gxclrect.$(OBJ) stream.$(OBJ)
+clbase_=$(clbase1_) $(clbase2_)
+clbase.dev: $(LIB_MAK) $(ECHOGS_XE) $(clbase_) cl$(BAND_LIST_STORAGE).dev \
+ cfe.dev cfd.dev rle.dev rld.dev
+ $(SETMOD) clbase $(clbase1_)
+ $(ADDMOD) clbase -obj $(clbase2_)
+ $(ADDMOD) clbase -include cl$(BAND_LIST_STORAGE) cfe cfd rle rld
+
+gdevht_h=gdevht.h $(gzht_h)
+
+gdevht.$(OBJ): gdevht.c $(GXERR) \
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+
+gxclist.$(OBJ): gxclist.c $(GXERR) $(memory__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)
+
+gxclbits.$(OBJ): gxclbits.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h)
+
+gxclpage.$(OBJ): gxclpage.c $(AK)\
+ $(gdevprn_h) $(gxcldev_h) $(gxclpage_h)
+
+# (gxclread shouldn't need gxclpath.h)
+gxclread.$(OBJ): gxclread.c $(GXERR) $(memory__h) $(gp_h) $(gpcheck_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscoord_h) $(gsdevice_h) $(gsstate_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcspace_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)\
+ $(gxhttile_h) $(gxpaint_h) $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h)
+
+gxclrect.$(OBJ): gxclrect.c $(GXERR)\
+ $(gsutil_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h)
+
+# Higher-level command list facilities.
+clpath_=gxclimag.$(OBJ) gxclpath.$(OBJ)
+clpath.dev: $(LIB_MAK) $(ECHOGS_XE) $(clpath_) psl2cs.dev
+ $(SETMOD) clpath $(clpath_)
+ $(ADDMOD) clpath -include psl2cs
+ $(ADDMOD) clpath -init climag clpath
+
+gxclimag.$(OBJ): gxclimag.c $(GXERR) $(math__h) $(memory__h)\
+ $(gscspace_h)\
+ $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpath_h) $(gxfmap_h)\
+ $(siscale_h) $(strimpl_h)
+
+gxclpath.$(OBJ): gxclpath.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcolor2_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+# Implement band lists on files.
+
+clfile_=gxclfile.$(OBJ)
+clfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
+ $(SETMOD) clfile $(clfile_)
+
+gxclfile.$(OBJ): gxclfile.c $(stdio__h) $(string__h) \
+ $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
+
+# Implement band lists in memory (RAM).
+
+clmemory_=gxclmem.$(OBJ) gxcl$(BAND_LIST_COMPRESSOR).$(OBJ)
+clmemory.dev: $(LIB_MAK) $(ECHOGS_XE) $(clmemory_) s$(BAND_LIST_COMPRESSOR)e.dev s$(BAND_LIST_COMPRESSOR)d.dev
+ $(SETMOD) clmemory $(clmemory_)
+ $(ADDMOD) clmemory -include s$(BAND_LIST_COMPRESSOR)e s$(BAND_LIST_COMPRESSOR)d
+ $(ADDMOD) clmemory -init cl_$(BAND_LIST_COMPRESSOR)
+
+gxclmem_h=gxclmem.h $(gxclio_h) $(strimpl_h)
+
+gxclmem.$(OBJ): gxclmem.c $(GXERR) $(LIB_MAK) $(memory__h) \
+ $(gxclmem_h)
+
+# Implement the compression method for RAM-based band lists.
+
+gxcllzw.$(OBJ): gxcllzw.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(slzwx_h)
+
+gxclzlib.$(OBJ): gxclzlib.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(szlibx_h)
+ $(CCCZ) gxclzlib.c
+
+# ---------------- Page devices ---------------- #
+# We include this here, rather than in devs.mak, because it is more like
+# a feature than a simple device.
+
+page_=gdevprn.$(OBJ)
+page.dev: $(LIB_MAK) $(ECHOGS_XE) $(page_) clist.dev
+ $(SETMOD) page $(page_)
+ $(ADDMOD) page -include clist
+
+gdevprn.$(OBJ): gdevprn.c $(ctype__h) \
+ $(gdevprn_h) $(gp_h) $(gsparam_h) $(gxclio_h)
+
+# ---------------- Vector devices ---------------- #
+# We include this here for the same reasons as page.dev.
+
+gdevvec_h=gdevvec.h $(gdevbbox_h) $(gsropt_h) $(gxdevice_h) $(gxistate_h) $(stream_h)
+
+vector_=gdevvec.$(OBJ)
+vector.dev: $(LIB_MAK) $(ECHOGS_XE) $(vector_) bbox.dev sfile.dev
+ $(SETMOD) vector $(vector_)
+ $(ADDMOD) vector -include bbox sfile
+
+gdevvec.$(OBJ): gdevvec.c $(GXERR) $(math__h) $(memory__h) $(string__h)\
+ $(gdevvec_h) $(gp_h) $(gscspace_h) $(gsparam_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxfixed_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+# ---------------- Image scaling filter ---------------- #
+
+iscale_=siscale.$(OBJ)
+iscale.dev: $(LIB_MAK) $(ECHOGS_XE) $(iscale_)
+ $(SETMOD) iscale $(iscale_)
+
+siscale.$(OBJ): siscale.c $(AK) $(math__h) $(memory__h) $(stdio__h) \
+ $(siscale_h) $(strimpl_h)
+
+# ---------------- RasterOp et al ---------------- #
+# Currently this module is required, but it should be optional.
+
+roplib_=gdevmrop.$(OBJ) gsrop.$(OBJ) gsroptab.$(OBJ)
+roplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(roplib_)
+ $(SETMOD) roplib $(roplib_)
+ $(ADDMOD) roplib -init roplib
+
+gdevrun.$(OBJ): gdevrun.c $(GXERR) $(memory__h) \
+ $(gxdevice_h) $(gxdevmem_h)
+
+gdevmrop.$(OBJ): gdevmrop.c $(GXERR) $(memory__h) \
+ $(gsbittab_h) $(gsropt_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) \
+ $(gdevmrop_h)
+
+gsrop.$(OBJ): gsrop.c $(GXERR) \
+ $(gsrop_h) $(gzstate_h)
+
+gsroptab.$(OBJ): gsroptab.c $(stdpre_h) $(gsropt_h)
+ $(CCLEAF) gsroptab.c
+
+# ---------------- Async rendering ---------------- #
+
+gsmemfix_h=gsmemfix.h $(gsmemraw_h)
+gxsync_h=gxsync.h $(gpsync_h) $(gsmemory_h)
+gxpageq_h=gxpageq.h $(gsmemory_h) $(gxband_h) $(gxsync_h)
+gsmemlok_h=gsmemlok.h $(gsmemory_h) $(gxsync_h)
+gdevprna_h=gdevprna.h $(gdevprn_h) $(gxsync_h)
+
+async_=gdevprna.$(OBJ) gxsync.$(OBJ) gxpageq.$(OBJ) gsmemlok.$(OBJ)\
+ gsmemfix.$(OBJ)
+async.dev: $(INT_MAK) $(ECHOGS_XE) $(async_) clist.dev
+ $(SETMOD) async $(async_)
+
+gdevprna.$(OBJ): gdevprna.c $(AK) $(ctype__h) $(gdevprna_h) $(gsparam_h)\
+ $(gsdevice_h) $(gxcldev_h) $(gxclpath_h) $(gxpageq_h) $(gsmemory_h)\
+ $(gsmemlok_h) $(gsmemfix_h)
+
+gsmemfix.$(OBJ): gsmemfix.c $(AK) $(memory__h) $(gsmemraw_h) $(gsmemfix_h)
+
+gxsync.$(OBJ): gxsync.c $(AK) $(gxsync_h) $(memory__h) $(gx_h) $(gserrors_h)\
+ $(gsmemory_h)
+
+gxpageq.$(OBJ): gxpageq.c $(GXERR) $(gxdevice_h) $(gxclist_h)\
+ $(gxpageq_h) $(gserrors_h)
+
+gsmemlok.$(OBJ): gsmemlok.c $(GXERR) $(gsmemlok_h) $(gserrors_h)
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+cmaplib_=gsfcmap.$(OBJ)
+cmaplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmaplib_)
+ $(SETMOD) cmaplib $(cmaplib_)
+
+gsfcmap.$(OBJ): gsfcmap.c $(GXERR)\
+ $(gsstruct_h) $(gxfcmap_h)
+
+psf0lib_=gschar0.$(OBJ) gsfont0.$(OBJ)
+psf0lib.dev: $(LIB_MAK) $(ECHOGS_XE) cmaplib.dev $(psf0lib_)
+ $(SETMOD) psf0lib $(psf0lib_)
+ $(ADDMOD) psf0lib -include cmaplib
+
+gschar0.$(OBJ): gschar0.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxfixed_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gsfcmap_h) $(gxfont_h) $(gxfont0_h) $(gxchar_h)
+
+gsfont0.$(OBJ): gsfont0.c $(GXERR) $(memory__h)\
+ $(gsmatrix_h) $(gsstruct_h) $(gxfixed_h) $(gxdevmem_h) $(gxfcache_h)\
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxdevice_h)
+
+# ---------------- Pattern color ---------------- #
+
+patlib_=gspcolor.$(OBJ) gxclip2.$(OBJ) gxpcmap.$(OBJ)
+patlib.dev: $(LIB_MAK) $(ECHOGS_XE) cmyklib.dev psl2cs.dev $(patlib_)
+ $(SETMOD) patlib -include cmyklib psl2cs
+ $(ADDMOD) patlib -obj $(patlib_)
+
+gspcolor.$(OBJ): gspcolor.c $(GXERR) $(math__h) \
+ $(gsimage_h) $(gspath_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcoord_h) $(gxclip2_h) $(gxcspace_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfixed_h) $(gxmatrix_h) $(gxpath_h) $(gxpcolor_h) $(gzstate_h)
+
+gxclip2.$(OBJ): gxclip2.c $(GXERR) $(memory__h) \
+ $(gsstruct_h) $(gxclip2_h) $(gxdevice_h) $(gxdevmem_h)
+
+gxpcmap.$(OBJ): gxpcmap.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h)\
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1lib_=gxtype1.$(OBJ) gxhint1.$(OBJ) gxhint2.$(OBJ) gxhint3.$(OBJ)
+
+gscrypt1_h=gscrypt1.h
+gstype1_h=gstype1.h
+gxfont1_h=gxfont1.h
+gxop1_h=gxop1.h
+gxtype1_h=gxtype1.h $(gscrypt1_h) $(gstype1_h) $(gxop1_h)
+
+gxtype1.$(OBJ): gxtype1.c $(GXERR) $(math__h)\
+ $(gsccode_h) $(gsline_h) $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+gxhint1.$(OBJ): gxhint1.c $(GXERR)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint2.$(OBJ): gxhint2.c $(GXERR) $(memory__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint3.$(OBJ): gxhint3.c $(GXERR) $(math__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 1 charstrings
+
+psf1lib_=gstype1.$(OBJ)
+psf1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf1lib_) $(type1lib_)
+ $(SETMOD) psf1lib $(psf1lib_)
+ $(ADDMOD) psf1lib $(type1lib_)
+ $(ADDMOD) psf1lib -init gstype1
+
+gstype1.$(OBJ): gstype1.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 2 charstrings
+
+psf2lib_=gstype2.$(OBJ)
+psf2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf2lib_) $(type1lib_)
+ $(SETMOD) psf2lib $(psf2lib_)
+ $(ADDMOD) psf2lib $(type1lib_)
+ $(ADDMOD) psf2lib -init gstype2
+
+gstype2.$(OBJ): gstype2.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+ttflib_=gstype42.$(OBJ)
+ttflib.dev: $(LIB_MAK) $(ECHOGS_XE) $(ttflib_)
+ $(SETMOD) ttflib $(ttflib_)
+
+gxfont42_h=gxfont42.h
+
+gstype42.$(OBJ): gstype42.c $(GXERR) $(memory__h) \
+ $(gsccode_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont42_h) $(gxistate_h) $(gxpath_h)
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+cmyklib_=gscolor1.$(OBJ) gsht1.$(OBJ)
+cmyklib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmyklib_)
+ $(SETMOD) cmyklib $(cmyklib_)
+ $(ADDMOD) cmyklib -init gscolor1
+
+gscolor1.$(OBJ): gscolor1.c $(GXERR) \
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gzstate_h)
+
+gsht1.$(OBJ): gsht1.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+colimlib_=gximage3.$(OBJ)
+colimlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(colimlib_)
+ $(SETMOD) colimlib $(colimlib_)
+ $(ADDMOD) colimlib -init gximage3
+
+gximage3.$(OBJ): gximage3.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcconv_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h)\
+ $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzpath_h) $(gzstate_h)
+
+# ---------------- HSB color ---------------- #
+
+hsblib_=gshsb.$(OBJ)
+hsblib.dev: $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
+ $(SETMOD) hsblib $(hsblib_)
+
+gshsb.$(OBJ): gshsb.c $(GX) \
+ $(gscolor_h) $(gshsb_h) $(gxfrac_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1lib_=gspath1.$(OBJ)
+path1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(path1lib_)
+ $(SETMOD) path1lib $(path1lib_)
+
+gspath1.$(OBJ): gspath1.c $(GXERR) $(math__h) \
+ $(gscoord_h) $(gspath_h) $(gsstruct_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) $(gzpath_h)
+
+# --------------- Level 2 color space and color image support --------------- #
+
+psl2cs_=gscolor2.$(OBJ)
+psl2cs.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2cs_)
+ $(SETMOD) psl2cs $(psl2cs_)
+
+gscolor2.$(OBJ): gscolor2.c $(GXERR) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h)
+
+psl2lib_=gximage4.$(OBJ) gximage5.$(OBJ)
+psl2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2lib_) colimlib.dev psl2cs.dev
+ $(SETMOD) psl2lib $(psl2lib_)
+ $(ADDMOD) psl2lib -init gximage4 gximage5
+ $(ADDMOD) psl2lib -include colimlib psl2cs
+
+gximage4.$(OBJ): gximage4.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+gximage5.$(OBJ): gximage5.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+# ---------------- Display Postscript / Level 2 support ---------------- #
+
+dps2lib_=gsdps1.$(OBJ)
+dps2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dps2lib_)
+ $(SETMOD) dps2lib $(dps2lib_)
+
+gsdps1.$(OBJ): gsdps1.c $(GXERR) $(math__h)\
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gspath2_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- Display Postscript extensions ---------------- #
+
+gsdps_h=gsdps.h
+
+dpslib_=gsdps.$(OBJ)
+dpslib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dpslib_)
+ $(SETMOD) dpslib $(dpslib_)
+
+gsdps.$(OBJ): gsdps.c $(GX) $(gsdps_h)\
+ $(gsdps_h) $(gspath_h) $(gxdevice_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- CIE color ---------------- #
+
+cielib_=gscie.$(OBJ) gxctable.$(OBJ)
+cielib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cielib_)
+ $(SETMOD) cielib $(cielib_)
+
+gscie.$(OBJ): gscie.c $(GXERR) $(math__h) \
+ $(gscie_h) $(gscolor2_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gzstate_h)
+
+gxctable.$(OBJ): gxctable.c $(GX) \
+ $(gxfixed_h) $(gxfrac_h) $(gxctable_h)
+
+# ---------------- Separation colors ---------------- #
+
+seprlib_=gscsepr.$(OBJ)
+seprlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(seprlib_)
+ $(SETMOD) seprlib $(seprlib_)
+
+gscsepr.$(OBJ): gscsepr.c $(GXERR)\
+ $(gscsepr_h) $(gsmatrix_h) $(gsrefct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+
+# ---------------- Functions ---------------- #
+
+gsdsrc_h=gsdsrc.h $(gsstruct_h)
+gsfunc_h=gsfunc.h
+gsfunc0_h=gsfunc0.h $(gsdsrc_h) $(gsfunc_h)
+gxfunc_h=gxfunc.h $(gsfunc_h) $(gsstruct_h)
+
+# Generic support, and FunctionType 0.
+funclib_=gsdsrc.$(OBJ) gsfunc.$(OBJ) gsfunc0.$(OBJ)
+funclib.dev: $(LIB_MAK) $(ECHOGS_XE) $(funclib_)
+ $(SETMOD) funclib $(funclib_)
+
+gsdsrc.$(OBJ): gsdsrc.c $(GX) $(memory__h)\
+ $(gsdsrc_h) $(gserrors_h) $(stream_h)
+
+gsfunc.$(OBJ): gsfunc.c $(GX)\
+ $(gserrors_h) $(gxfunc_h)
+
+gsfunc0.$(OBJ): gsfunc0.c $(GX) $(math__h)\
+ $(gserrors_h) $(gsfunc0_h) $(gxfunc_h)
+
+# ----------------------- Platform-specific modules ----------------------- #
+# Platform-specific code doesn't really belong here: this is code that is
+# shared among multiple platforms.
+
+# Frame buffer implementations.
+
+gp_nofb.$(OBJ): gp_nofb.c $(GX) \
+ $(gp_h) $(gxdevice_h)
+
+gp_dosfb.$(OBJ): gp_dosfb.c $(AK) $(malloc__h) $(memory__h)\
+ $(gx_h) $(gp_h) $(gserrors_h) $(gxdevice_h)
+
+# MS-DOS file system, also used by Desqview/X.
+gp_dosfs.$(OBJ): gp_dosfs.c $(AK) $(dos__h) $(gp_h) $(gx_h)
+
+# MS-DOS file enumeration, *not* used by Desqview/X.
+gp_dosfe.$(OBJ): gp_dosfe.c $(AK) $(stdio__h) $(memory__h) $(string__h) \
+ $(dos__h) $(gstypes_h) $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h)
+
+# Other MS-DOS facilities.
+gp_msdos.$(OBJ): gp_msdos.c $(AK) $(dos__h) $(stdio__h) $(string__h)\
+ $(gsmemory_h) $(gstypes_h) $(gp_h)
+
+# Unix(-like) file system, also used by Desqview/X.
+gp_unifs.$(OBJ): gp_unifs.c $(AK) $(memory__h) $(string__h) $(gx_h) $(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+
+# Unix(-like) file name syntax, *not* used by Desqview/X.
+gp_unifn.$(OBJ): gp_unifn.c $(AK) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+# Main program for library testing
+
+gslib.$(OBJ): gslib.c $(AK) $(math__h) \
+ $(gx_h) $(gp_h) $(gserrors_h) $(gsmatrix_h) $(gsstate_h) $(gscspace_h) \
+ $(gscdefs_h) $(gscolor2_h) $(gscoord_h) $(gslib_h) $(gsparam_h) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxalloc_h) $(gxdevice_h)
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for language interpreters.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+INT_MAK=int.mak
+
+# ======================== Interpreter support ======================== #
+
+# This is support code for all interpreters, not just PostScript and PDF.
+# It knows about the PostScript data types, but isn't supposed to
+# depend on anything outside itself.
+
+errors_h=errors.h
+idebug_h=idebug.h
+idict_h=idict.h
+igc_h=igc.h
+igcstr_h=igcstr.h
+iname_h=iname.h
+inamedef_h=inamedef.h $(gconfigv_h) $(iname_h)
+ipacked_h=ipacked.h
+iref_h=iref.h
+isave_h=isave.h
+isstate_h=isstate.h
+istruct_h=istruct.h $(gsstruct_h)
+iutil_h=iutil.h
+ivmspace_h=ivmspace.h $(gsgc_h)
+opdef_h=opdef.h
+# Nested include files
+ghost_h=ghost.h $(gx_h) $(iref_h)
+imemory_h=imemory.h $(gsalloc_h) $(ivmspace_h)
+ialloc_h=ialloc.h $(imemory_h)
+iastruct_h=iastruct.h $(gxobj_h) $(ialloc_h)
+iastate_h=iastate.h $(gxalloc_h) $(ialloc_h) $(istruct_h)
+store_h=store.h $(ialloc_h)
+
+GH=$(AK) $(ghost_h)
+
+isupport1_=ialloc.$(OBJ) igc.$(OBJ) igcref.$(OBJ) igcstr.$(OBJ)
+isupport2_=ilocate.$(OBJ) iname.$(OBJ) isave.$(OBJ)
+isupport_=$(isupport1_) $(isupport2_)
+isupport.dev: $(INT_MAK) $(ECHOGS_XE) $(isupport_)
+ $(SETMOD) isupport $(isupport1_)
+ $(ADDMOD) isupport -obj $(isupport2_)
+ $(ADDMOD) isupport -init igcref
+
+ialloc.$(OBJ): ialloc.c $(AK) $(memory__h) $(gx_h)\
+ $(errors_h) $(gsstruct_h) $(gxarith_h)\
+ $(iastate_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+# igc.c, igcref.c, and igcstr.c should really be in the dpsand2 list,
+# but since all the GC enumeration and relocation routines refer to them,
+# it's too hard to separate them out from the Level 1 base.
+igc.$(OBJ): igc.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsmdebug_h) $(gsstruct_h) $(gsutil_h) \
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(inamedef_h) \
+ $(ipacked_h) $(isave_h) $(isstate_h) $(istruct_h) $(opdef_h)
+
+igcref.$(OBJ): igcref.c $(GH) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idebug_h) $(igc_h) $(iname_h) $(ipacked_h) $(store_h)
+
+igcstr.$(OBJ): igcstr.c $(GH) $(memory__h)\
+ $(gsmdebug_h) $(gsstruct_h) $(iastate_h) $(igcstr_h)
+
+ilocate.$(OBJ): ilocate.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(iname_h)\
+ $(ipacked_h) $(isstate_h) $(iutil_h) $(ivmspace_h)\
+ $(store_h)
+
+iname.$(OBJ): iname.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h) $(gxobj_h)\
+ $(errors_h) $(imemory_h) $(inamedef_h) $(isave_h) $(store_h)
+
+isave.$(OBJ): isave.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h) $(gsutil_h)\
+ $(iastate_h) $(inamedef_h) $(isave_h) $(isstate_h) $(ivmspace_h)\
+ $(ipacked_h) $(store_h)
+
+### Include files
+
+idparam_h=idparam.h
+ilevel_h=ilevel.h
+iparam_h=iparam.h $(gsparam_h)
+istack_h=istack.h
+iutil2_h=iutil2.h
+opcheck_h=opcheck.h
+opextern_h=opextern.h
+# Nested include files
+dstack_h=dstack.h $(istack_h)
+estack_h=estack.h $(istack_h)
+ostack_h=ostack.h $(istack_h)
+oper_h=oper.h $(iutil_h) $(opcheck_h) $(opdef_h) $(opextern_h) $(ostack_h)
+
+idebug.$(OBJ): idebug.c $(GH) $(string__h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(ostack_h) $(opdef_h) $(ipacked_h) $(store_h)
+
+idict.$(OBJ): idict.c $(GH) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idebug_h) $(ivmspace_h) $(inamedef_h) $(ipacked_h)\
+ $(isave_h) $(store_h) $(iutil_h) $(idict_h) $(dstack_h)
+
+idparam.$(OBJ): idparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(gsmatrix_h) $(gsuid_h)\
+ $(idict_h) $(idparam_h) $(ilevel_h) $(imemory_h) $(iname_h) $(iutil_h)\
+ $(oper_h) $(store_h)
+
+iparam.$(OBJ): iparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(iname_h) $(imemory_h) $(iparam_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(opcheck_h) $(store_h)
+
+istack.$(OBJ): istack.c $(GH) $(memory__h) \
+ $(errors_h) $(gsstruct_h) $(gsutil_h) \
+ $(ialloc_h) $(istack_h) $(istruct_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iutil.$(OBJ): iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\
+ $(gsccode_h) $(gsmatrix_h) $(gsutil_h) $(gxfont_h)\
+ $(errors_h) $(idict_h) $(imemory_h) $(iutil_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(oper_h) $(store_h)
+
+# ======================== PostScript Level 1 ======================== #
+
+###### Include files
+
+files_h=files.h
+fname_h=fname.h
+ichar_h=ichar.h
+icharout_h=icharout.h
+icolor_h=icolor.h
+icontext_h=icontext.h $(imemory_h) $(istack_h)
+icsmap_h=icsmap.h
+ifont_h=ifont.h $(gsccode_h) $(gsstruct_h)
+iht_h=iht.h
+iimage_h=iimage.h
+imain_h=imain.h $(gsexit_h)
+imainarg_h=imainarg.h
+iminst_h=iminst.h $(imain_h)
+interp_h=interp.h
+iparray_h=iparray.h
+iscannum_h=iscannum.h
+istream_h=istream.h
+main_h=main.h $(iminst_h)
+overlay_h=overlay.h
+sbwbs_h=sbwbs.h
+sfilter_h=sfilter.h $(gstypes_h)
+shcgen_h=shcgen.h
+smtf_h=smtf.h
+# Nested include files
+bfont_h=bfont.h $(ifont_h)
+ifilter_h=ifilter.h $(istream_h) $(ivmspace_h)
+igstate_h=igstate.h $(gsstate_h) $(gxstate_h) $(istruct_h)
+iscan_h=iscan.h $(sa85x_h) $(sstring_h)
+sbhc_h=sbhc.h $(shc_h)
+# Include files for optional features
+ibnum_h=ibnum.h
+
+### Initialization and scanning
+
+iconfig=iconfig$(CONFIG)
+$(iconfig).$(OBJ): iconf.c $(stdio__h) \
+ $(gconfig_h) $(gscdefs_h) $(gsmemory_h) \
+ $(files_h) $(iminst_h) $(iref_h) $(ivmspace_h) $(opdef_h) $(stream_h)
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) iconf.c $(iconfig).c
+ $(CCC) $(iconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+
+iinit.$(OBJ): iinit.c $(GH) $(string__h)\
+ $(gscdefs_h) $(gsexit_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h)\
+ $(ilevel_h) $(iname_h) $(interp_h) $(opdef_h)\
+ $(ipacked_h) $(iparray_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iscan.$(OBJ): iscan.c $(GH) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h) $(files_h)\
+ $(ilevel_h) $(iutil_h) $(iscan_h) $(iscannum_h) $(istruct_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(iparray_h) $(istream_h) $(ostack_h) $(store_h)\
+ $(stream_h) $(strimpl_h) $(sfilter_h) $(scanchar_h)
+
+iscannum.$(OBJ): iscannum.c $(GH) $(math__h)\
+ $(errors_h) $(iscannum_h) $(scanchar_h) $(scommon_h) $(store_h)
+
+### Streams
+
+sfilter1.$(OBJ): sfilter1.c $(AK) $(stdio__h) $(memory__h) \
+ $(sfilter_h) $(strimpl_h)
+
+###### Operators
+
+OP=$(GH) $(errors_h) $(oper_h)
+
+### Non-graphics operators
+
+zarith.$(OBJ): zarith.c $(OP) $(math__h) $(store_h)
+
+zarray.$(OBJ): zarray.c $(OP) $(memory__h) $(ialloc_h) $(ipacked_h) $(store_h)
+
+zcontrol.$(OBJ): zcontrol.c $(OP) $(string__h)\
+ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)
+
+zdict.$(OBJ): zdict.c $(OP) \
+ $(dstack_h) $(idict_h) $(ilevel_h) $(iname_h) $(ipacked_h) $(ivmspace_h) \
+ $(store_h)
+
+zfile.$(OBJ): zfile.c $(OP) $(memory__h) $(string__h) $(gp_h)\
+ $(gsstruct_h) $(gxiodev_h) \
+ $(ialloc_h) $(estack_h) $(files_h) $(fname_h) $(ilevel_h) $(interp_h) $(iutil_h)\
+ $(isave_h) $(main_h) $(sfilter_h) $(stream_h) $(strimpl_h) $(store_h)
+
+zfileio.$(OBJ): zfileio.c $(OP) $(gp_h) \
+ $(files_h) $(ifilter_h) $(store_h) $(stream_h) $(strimpl_h) \
+ $(gsmatrix_h) $(gxdevice_h) $(gxdevmem_h)
+
+zfilter.$(OBJ): zfilter.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sfilter_h) $(srlx_h) $(sstring_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zfname.$(OBJ): zfname.c $(OP) $(memory__h)\
+ $(fname_h) $(gxiodev_h) $(ialloc_h) $(stream_h)
+
+zfproc.$(OBJ): zfproc.c $(GH) $(memory__h)\
+ $(errors_h) $(oper_h)\
+ $(estack_h) $(files_h) $(gsstruct_h) $(ialloc_h) $(ifilter_h) $(istruct_h)\
+ $(store_h) $(stream_h) $(strimpl_h)
+
+zgeneric.$(OBJ): zgeneric.c $(OP) $(memory__h)\
+ $(idict_h) $(estack_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(store_h)
+
+ziodev.$(OBJ): ziodev.c $(OP) $(memory__h) $(stdio__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsstruct_h) $(gxiodev_h)\
+ $(files_h) $(ialloc_h) $(ivmspace_h) $(store_h) $(stream_h)
+
+zmath.$(OBJ): zmath.c $(OP) $(math__h) $(gxfarith_h) $(store_h)
+
+zmisc.$(OBJ): zmisc.c $(OP) $(gscdefs_h) $(gp_h) \
+ $(errno__h) $(memory__h) $(string__h) \
+ $(ialloc_h) $(idict_h) $(dstack_h) $(iname_h) $(ivmspace_h) $(ipacked_h) $(store_h)
+
+zpacked.$(OBJ): zpacked.c $(OP) \
+ $(ialloc_h) $(idict_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(iparray_h) \
+ $(istack_h) $(store_h)
+
+zrelbit.$(OBJ): zrelbit.c $(OP) $(gsutil_h) $(store_h) $(idict_h)
+
+zstack.$(OBJ): zstack.c $(OP) $(memory__h)\
+ $(ialloc_h) $(istack_h) $(store_h)
+
+zstring.$(OBJ): zstring.c $(OP) $(memory__h)\
+ $(gsutil_h)\
+ $(ialloc_h) $(iname_h) $(ivmspace_h) $(store_h)
+
+zsysvm.$(OBJ): zsysvm.c $(GH)\
+ $(ialloc_h) $(ivmspace_h) $(oper_h) $(store_h)
+
+ztoken.$(OBJ): ztoken.c $(OP) \
+ $(estack_h) $(files_h) $(gsstruct_h) $(iscan_h) \
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+ztype.$(OBJ): ztype.c $(OP) $(math__h) $(memory__h) $(string__h)\
+ $(dstack_h) $(idict_h) $(imemory_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zvmem.$(OBJ): zvmem.c $(OP)\
+ $(dstack_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(isave_h) $(store_h) $(stream_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h)
+
+### Graphics operators
+
+zchar.$(OBJ): zchar.c $(OP)\
+ $(gsstruct_h) $(gxarith_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxchar_h) $(gxdevice_h) $(gxfont_h) $(gzpath_h) $(gzstate_h)\
+ $(dstack_h) $(estack_h) $(ialloc_h) $(ichar_h) $(idict_h) $(ifont_h)\
+ $(ilevel_h) $(iname_h) $(igstate_h) $(ipacked_h) $(store_h)
+
+# zcharout is used for Type 1 and Type 42 fonts only.
+zcharout.$(OBJ): zcharout.c $(OP)\
+ $(gschar_h) $(gxdevice_h) $(gxfont_h)\
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h)\
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zcolor.$(OBJ): zcolor.c $(OP) \
+ $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gxdevice_h) $(gxcmap_h) \
+ $(ialloc_h) $(icolor_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zdevice.$(OBJ): zdevice.c $(OP) $(string__h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gxdevice_h) $(store_h)
+
+zfont.$(OBJ): zfont.c $(OP)\
+ $(gschar_h) $(gsstruct_h) $(gxdevice_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(isave_h) $(ivmspace_h)\
+ $(bfont_h) $(store_h)
+
+zfont2.$(OBJ): zfont2.c $(OP) $(memory__h) $(string__h)\
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(bfont_h) $(idict_h) $(idparam_h) $(ilevel_h) $(iname_h) $(istruct_h)\
+ $(ipacked_h) $(store_h)
+
+zgstate.$(OBJ): zgstate.c $(OP) $(math__h)\
+ $(gsmatrix_h) $(ialloc_h) $(idict_h) $(igstate_h) $(istruct_h) $(store_h)
+
+zht.$(OBJ): zht.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+zimage.$(OBJ): zimage.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ifilter_h) $(igstate_h) $(iimage_h) $(ilevel_h) \
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(store_h) $(stream_h)
+
+zmatrix.$(OBJ): zmatrix.c $(OP)\
+ $(gsmatrix_h) $(igstate_h) $(gscoord_h) $(store_h)
+
+zpaint.$(OBJ): zpaint.c $(OP)\
+ $(gspaint_h) $(igstate_h)
+
+zpath.$(OBJ): zpath.c $(OP) $(math__h) \
+ $(gsmatrix_h) $(gspath_h) $(igstate_h) $(store_h)
+
+# Define the base PostScript language interpreter.
+# This is the subset of PostScript Level 1 required by our PDF reader.
+
+INT1=idebug.$(OBJ) idict.$(OBJ) idparam.$(OBJ)
+INT2=iinit.$(OBJ) interp.$(OBJ) iparam.$(OBJ) ireclaim.$(OBJ)
+INT3=iscan.$(OBJ) iscannum.$(OBJ) istack.$(OBJ) iutil.$(OBJ)
+INT4=scantab.$(OBJ) sfilter1.$(OBJ) sstring.$(OBJ) stream.$(OBJ)
+Z1=zarith.$(OBJ) zarray.$(OBJ) zcontrol.$(OBJ) zdict.$(OBJ)
+Z1OPS=zarith zarray zcontrol zdict
+Z2=zfile.$(OBJ) zfileio.$(OBJ) zfilter.$(OBJ) zfname.$(OBJ) zfproc.$(OBJ)
+Z2OPS=zfile zfileio zfilter zfproc
+Z3=zgeneric.$(OBJ) ziodev.$(OBJ) zmath.$(OBJ) zmisc.$(OBJ) zpacked.$(OBJ)
+Z3OPS=zgeneric ziodev zmath zmisc zpacked
+Z4=zrelbit.$(OBJ) zstack.$(OBJ) zstring.$(OBJ) zsysvm.$(OBJ)
+Z4OPS=zrelbit zstack zstring zsysvm
+Z5=ztoken.$(OBJ) ztype.$(OBJ) zvmem.$(OBJ)
+Z5OPS=ztoken ztype zvmem
+Z6=zchar.$(OBJ) zcolor.$(OBJ) zdevice.$(OBJ) zfont.$(OBJ) zfont2.$(OBJ)
+Z6OPS=zchar zcolor zdevice zfont zfont2
+Z7=zgstate.$(OBJ) zht.$(OBJ) zimage.$(OBJ) zmatrix.$(OBJ) zpaint.$(OBJ) zpath.$(OBJ)
+Z7OPS=zgstate zht zimage zmatrix zpaint zpath
+# We have to be a little underhanded with *config.$(OBJ) so as to avoid
+# circular definitions.
+INT_OBJS=imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ) \
+ $(INT1) $(INT2) $(INT3) $(INT4) \
+ $(Z1) $(Z2) $(Z3) $(Z4) $(Z5) $(Z6) $(Z7)
+INT_CONFIG=$(gconfig).$(OBJ) $(gscdefs).$(OBJ) $(iconfig).$(OBJ) \
+ iccinit$(COMPILE_INITS).$(OBJ)
+INT_ALL=$(INT_OBJS) $(INT_CONFIG)
+# We omit libcore.dev, which should be included here, because problems
+# with the Unix linker require libcore to appear last in the link list
+# when libcore is really a library.
+# We omit $(INT_CONFIG) from the dependency list because they have special
+# dependency requirements and are added to the link list at the very end.
+# zfilter.c shouldn't include the RLE and RLD filters, but we don't want to
+# change this now.
+psbase.dev: $(INT_MAK) $(ECHOGS_XE) $(INT_OBJS)\
+ isupport.dev rld.dev rle.dev sfile.dev
+ $(SETMOD) psbase imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ)
+ $(ADDMOD) psbase -obj $(INT_CONFIG)
+ $(ADDMOD) psbase -obj $(INT1)
+ $(ADDMOD) psbase -obj $(INT2)
+ $(ADDMOD) psbase -obj $(INT3)
+ $(ADDMOD) psbase -obj $(INT4)
+ $(ADDMOD) psbase -obj $(Z1)
+ $(ADDMOD) psbase -oper $(Z1OPS)
+ $(ADDMOD) psbase -obj $(Z2)
+ $(ADDMOD) psbase -oper $(Z2OPS)
+ $(ADDMOD) psbase -obj $(Z3)
+ $(ADDMOD) psbase -oper $(Z3OPS)
+ $(ADDMOD) psbase -obj $(Z4)
+ $(ADDMOD) psbase -oper $(Z4OPS)
+ $(ADDMOD) psbase -obj $(Z5)
+ $(ADDMOD) psbase -oper $(Z5OPS)
+ $(ADDMOD) psbase -obj $(Z6)
+ $(ADDMOD) psbase -oper $(Z6OPS)
+ $(ADDMOD) psbase -obj $(Z7)
+ $(ADDMOD) psbase -oper $(Z7OPS)
+ $(ADDMOD) psbase -iodev stdin stdout stderr lineedit statementedit
+ $(ADDMOD) psbase -include isupport rld rle sfile
+
+# -------------------------- Feature definitions -------------------------- #
+
+# ---------------- Full Level 1 interpreter ---------------- #
+
+level1.dev: $(INT_MAK) $(ECHOGS_XE) psbase.dev bcp.dev hsb.dev path1.dev type1.dev
+ $(SETMOD) level1 -include psbase bcp hsb path1 type1
+ $(ADDMOD) level1 -emulator PostScript PostScriptLevel1
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+color.dev: $(INT_MAK) $(ECHOGS_XE) cmyklib.dev colimlib.dev cmykread.dev
+ $(SETMOD) color -include cmyklib colimlib cmykread
+
+cmykread_=zcolor1.$(OBJ) zht1.$(OBJ)
+cmykread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmykread_)
+ $(SETMOD) cmykread $(cmykread_)
+ $(ADDMOD) cmykread -oper zcolor1 zht1
+
+zcolor1.$(OBJ): zcolor1.c $(OP) \
+ $(gscolor1_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) \
+ $(ialloc_h) $(icolor_h) $(iimage_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zht1.$(OBJ): zht1.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h)\
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+# ---------------- HSB color ---------------- #
+
+hsb_=zhsb.$(OBJ)
+hsb.dev: $(INT_MAK) $(ECHOGS_XE) $(hsb_) hsblib.dev
+ $(SETMOD) hsb $(hsb_)
+ $(ADDMOD) hsb -include hsblib
+ $(ADDMOD) hsb -oper zhsb
+
+zhsb.$(OBJ): zhsb.c $(OP) \
+ $(gshsb_h) $(igstate_h) $(store_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1_=zpath1.$(OBJ)
+path1.dev: $(INT_MAK) $(ECHOGS_XE) $(path1_) path1lib.dev
+ $(SETMOD) path1 $(path1_)
+ $(ADDMOD) path1 -include path1lib
+ $(ADDMOD) path1 -oper zpath1
+
+zpath1.$(OBJ): zpath1.c $(OP) $(memory__h)\
+ $(ialloc_h) $(estack_h) $(gspath_h) $(gsstruct_h) $(igstate_h) $(store_h)
+
+# ================ Level-independent PostScript options ================ #
+
+# ---------------- BCP filters ---------------- #
+
+bcp_=sbcp.$(OBJ) zfbcp.$(OBJ)
+bcp.dev: $(INT_MAK) $(ECHOGS_XE) $(bcp_)
+ $(SETMOD) bcp $(bcp_)
+ $(ADDMOD) bcp -oper zfbcp
+
+sbcp.$(OBJ): sbcp.c $(AK) $(stdio__h) \
+ $(sfilter_h) $(strimpl_h)
+
+zfbcp.$(OBJ): zfbcp.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# ---------------- Incremental font loading ---------------- #
+# (This only works for Type 1 fonts without eexec encryption.)
+
+diskfont.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) diskfont -ps gs_diskf
+
+# ---------------- Double-precision floats ---------------- #
+
+double_=zdouble.$(OBJ)
+double.dev: $(INT_MAK) $(ECHOGS_XE) $(double_)
+ $(SETMOD) double $(double_)
+ $(ADDMOD) double -oper zdouble
+
+zdouble.$(OBJ): zdouble.c $(OP) $(ctype__h) $(math__h) $(memory__h) $(string__h) \
+ $(gxfarith_h) $(store_h)
+
+# ---------------- EPSF files with binary headers ---------------- #
+
+epsf.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) epsf -ps gs_epsf
+
+# ---------------- RasterOp ---------------- #
+# This should be a separable feature in the core also....
+
+rasterop.dev: $(INT_MAK) $(ECHOGS_XE) roplib.dev ropread.dev
+ $(SETMOD) rasterop -include roplib ropread
+
+ropread_=zrop.$(OBJ)
+ropread.dev: $(INT_MAK) $(ECHOGS_XE) $(ropread_)
+ $(SETMOD) ropread $(ropread_)
+ $(ADDMOD) ropread -oper zrop
+
+zrop.$(OBJ): zrop.c $(OP) $(memory__h)\
+ $(gsrop_h) $(gsutil_h) $(gxdevice_h)\
+ $(idict_h) $(idparam_h) $(igstate_h) $(store_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1.dev: $(INT_MAK) $(ECHOGS_XE) psf1lib.dev psf1read.dev
+ $(SETMOD) type1 -include psf1lib psf1read
+
+psf1read_=seexec.$(OBJ) zchar1.$(OBJ) zcharout.$(OBJ) zfont1.$(OBJ) zmisc1.$(OBJ)
+psf1read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf1read_)
+ $(SETMOD) psf1read $(psf1read_)
+ $(ADDMOD) psf1read -oper zchar1 zfont1 zmisc1
+ $(ADDMOD) psf1read -ps gs_type1
+
+seexec.$(OBJ): seexec.c $(AK) $(stdio__h) \
+ $(gscrypt1_h) $(scanchar_h) $(sfilter_h) $(strimpl_h)
+
+zchar1.$(OBJ): zchar1.c $(OP) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h) $(gzstate_h) \
+ $(estack_h) $(ialloc_h) $(ichar_h) $(icharout_h) \
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zfont1.$(OBJ): zfont1.c $(OP) \
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont1_h) \
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(store_h)
+
+zmisc1.$(OBJ): zmisc1.c $(OP) $(memory__h)\
+ $(gscrypt1_h)\
+ $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# -------------- Compact Font Format and Type 2 charstrings ------------- #
+
+cff.dev: $(INT_MAK) $(ECHOGS_XE) gs_cff.ps psl2int.dev
+ $(SETMOD) cff -ps gs_cff
+
+type2.dev: $(INT_MAK) $(ECHOGS_XE) type1.dev psf2lib.dev
+ $(SETMOD) type2 -include psf2lib
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+# Native TrueType support
+ttfont.dev: $(INT_MAK) $(ECHOGS_XE) type42.dev
+ $(SETMOD) ttfont -include type42
+ $(ADDMOD) ttfont -ps gs_mro_e gs_wan_e gs_ttf
+
+# Type 42 (embedded TrueType) support
+type42read_=zchar42.$(OBJ) zcharout.$(OBJ) zfont42.$(OBJ)
+type42.dev: $(INT_MAK) $(ECHOGS_XE) $(type42read_) ttflib.dev
+ $(SETMOD) type42 $(type42read_)
+ $(ADDMOD) type42 -include ttflib
+ $(ADDMOD) type42 -oper zchar42 zfont42
+ $(ADDMOD) type42 -ps gs_typ42
+
+zchar42.$(OBJ): zchar42.c $(OP) \
+ $(gsmatrix_h) $(gspaint_h) $(gspath_h) \
+ $(gxfixed_h) $(gxchar_h) $(gxfont_h) $(gxfont42_h) \
+ $(gxistate_h) $(gxpath_h) $(gzstate_h) \
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h) \
+ $(ifont_h) $(igstate_h) $(store_h)
+
+zfont42.$(OBJ): zfont42.c $(OP) \
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h) $(gxfont42_h) \
+ $(bfont_h) $(idict_h) $(idparam_h) $(store_h)
+
+# ======================== Precompilation options ======================== #
+
+# ---------------- Precompiled fonts ---------------- #
+# See fonts.txt for more information.
+
+ccfont_h=ccfont.h $(std_h) $(gsmemory_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+CCFONT=$(OP) $(ccfont_h)
+
+# List the fonts we are going to compile.
+# Because of intrinsic limitations in `make', we have to list
+# the object file names and the font names separately.
+# Because of limitations in the DOS shell, we have to break the fonts up
+# into lists that will fit on a single line (120 characters).
+# The rules for constructing the .c files from the fonts themselves,
+# and for compiling the .c files, are in cfonts.mak, not here.
+# For example, to compile the Courier fonts, you should invoke
+# make -f cfonts.mak Courier_o
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+ccfonts_ps=gs_ccfnt
+ccfonts1_=0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+ccfonts1=agk agko agd agdo
+ccfonts2_=0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+ccfonts2=bkl bkli bkd bkdi
+ccfonts3_=0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+ccfonts3=crr cri crb crbi
+ccfonts4_=0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ)
+ccfonts4=hvr hvro hvb hvbo
+ccfonts5_=0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+ccfonts5=hvrrn hvrorn hvbrn hvborn
+ccfonts6_=0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+ccfonts6=ncr ncri ncb ncbi
+ccfonts7_=0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+ccfonts7=plr plri plb plbi
+ccfonts8_=0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+ccfonts8=tmr tmri tmb tmbi
+ccfonts9_=0syr.$(OBJ) 0zcmi.$(OBJ) 0zdr.$(OBJ)
+ccfonts9=syr zcmi zdr
+# The free distribution includes Bitstream Charter, Utopia, and
+# freeware Cyrillic and Kana fonts. We only provide for compiling
+# Charter and Utopia.
+ccfonts10free_=bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+ccfonts10free=chr chri chb chbi
+ccfonts11free_=putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+ccfonts11free=utr utri utb utbi
+# Uncomment the alternatives in the next 4 lines if you want
+# Charter and Utopia compiled in.
+#ccfonts10_=$(ccfonts10free_)
+ccfonts10_=
+#ccfonts10=$(ccfonts10free)
+ccfonts10=
+#ccfonts11_=$(ccfonts11free_)
+ccfonts11_=
+#ccfonts11=$(ccfonts11free)
+ccfonts11=
+# Add your own fonts here if desired.
+ccfonts12_=
+ccfonts12=
+ccfonts13_=
+ccfonts13=
+ccfonts14_=
+ccfonts14=
+ccfonts15_=
+ccfonts15=
+
+# It's OK for ccfonts_.dev not to be CONFIG-dependent, because it only
+# exists during the execution of the following rule.
+# font2c has the prefix "gs" built into it, so we need to instruct
+# genconf to use the same one.
+$(gconfigf_h): $(MAKEFILE) $(INT_MAK) $(GENCONF_XE)
+ $(SETMOD) ccfonts_ -font $(ccfonts1)
+ $(ADDMOD) ccfonts_ -font $(ccfonts2)
+ $(ADDMOD) ccfonts_ -font $(ccfonts3)
+ $(ADDMOD) ccfonts_ -font $(ccfonts4)
+ $(ADDMOD) ccfonts_ -font $(ccfonts5)
+ $(ADDMOD) ccfonts_ -font $(ccfonts6)
+ $(ADDMOD) ccfonts_ -font $(ccfonts7)
+ $(ADDMOD) ccfonts_ -font $(ccfonts8)
+ $(ADDMOD) ccfonts_ -font $(ccfonts9)
+ $(ADDMOD) ccfonts_ -font $(ccfonts10)
+ $(ADDMOD) ccfonts_ -font $(ccfonts11)
+ $(ADDMOD) ccfonts_ -font $(ccfonts12)
+ $(ADDMOD) ccfonts_ -font $(ccfonts13)
+ $(ADDMOD) ccfonts_ -font $(ccfonts14)
+ $(ADDMOD) ccfonts_ -font $(ccfonts15)
+ $(EXP)genconf ccfonts_.dev -n gs -f $(gconfigf_h)
+
+# We separate icfontab.dev from ccfonts.dev so that a customer can put
+# compiled fonts into a separate shared library.
+
+icfontab=icfontab$(CONFIG)
+
+# Define ccfont_table separately, so it can be set from the command line
+# to select an alternate compiled font table.
+ccfont_table=$(icfontab)
+
+$(icfontab).dev: $(MAKEFILE) $(INT_MAK) $(ECHOGS_XE) $(icfontab).$(OBJ) \
+ $(ccfonts1_) $(ccfonts2_) $(ccfonts3_) $(ccfonts4_) $(ccfonts5_) \
+ $(ccfonts6_) $(ccfonts7_) $(ccfonts8_) $(ccfonts9_) $(ccfonts10_) \
+ $(ccfonts11_) $(ccfonts12_) $(ccfonts13_) $(ccfonts14_) $(ccfonts15_)
+ $(SETMOD) $(icfontab) -obj $(icfontab).$(OBJ)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts1_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts2_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts3_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts4_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts5_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts6_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts7_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts8_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts9_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts10_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts11_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts12_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts13_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts14_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts15_)
+
+$(icfontab).$(OBJ): icfontab.c $(AK) $(ccfont_h) $(gconfigf_h)
+ $(CP_) $(gconfigf_h) gconfigf.h
+ $(CCCF) icfontab.c
+
+# Strictly speaking, ccfonts shouldn't need to include type1,
+# since one could choose to precompile only Type 0 fonts,
+# but getting this exactly right would be too much work.
+ccfonts=ccfonts$(CONFIG)
+$(ccfonts).dev: $(MAKEFILE) $(INT_MAK) type1.dev iccfont.$(OBJ) \
+ $(ccfont_table).dev
+ $(SETMOD) $(ccfonts) -include type1
+ $(ADDMOD) $(ccfonts) -include $(ccfont_table)
+ $(ADDMOD) $(ccfonts) -obj iccfont.$(OBJ)
+ $(ADDMOD) $(ccfonts) -oper ccfonts
+ $(ADDMOD) $(ccfonts) -ps $(ccfonts_ps)
+
+iccfont.$(OBJ): iccfont.c $(GH) $(string__h)\
+ $(gsstruct_h) $(ccfont_h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(ifont_h) $(iname_h) $(isave_h) $(iutil_h)\
+ $(oper_h) $(ostack_h) $(store_h) $(stream_h) $(strimpl_h) $(sfilter_h) $(iscan_h)
+ $(CCCF) iccfont.c
+
+# ---------------- Compiled initialization code ---------------- #
+
+# We select either iccinit0 or iccinit1 depending on COMPILE_INITS.
+
+iccinit0.$(OBJ): iccinit0.c $(stdpre_h)
+ $(CCCF) iccinit0.c
+
+iccinit1.$(OBJ): gs_init.$(OBJ)
+ $(CP_) gs_init.$(OBJ) iccinit1.$(OBJ)
+
+# All the gs_*.ps files should be prerequisites of gs_init.c,
+# but we don't have any convenient list of them.
+gs_init.c: $(GS_INIT) $(GENINIT_XE) $(gconfig_h)
+ $(EXP)geninit $(GS_INIT) $(gconfig_h) -c gs_init.c
+
+gs_init.$(OBJ): gs_init.c $(stdpre_h)
+ $(CCCF) gs_init.c
+
+# ======================== PostScript Level 2 ======================== #
+
+level2.dev: $(INT_MAK) $(ECHOGS_XE) \
+ cidfont.dev cie.dev cmapread.dev compfont.dev dct.dev devctrl.dev dpsand2.dev\
+ filter.dev level1.dev pattern.dev psl2lib.dev psl2read.dev sepr.dev\
+ type42.dev xfilter.dev
+ $(SETMOD) level2 -include cidfont cie cmapread compfont
+ $(ADDMOD) level2 -include dct devctrl dpsand2 filter
+ $(ADDMOD) level2 -include level1 pattern psl2lib psl2read
+ $(ADDMOD) level2 -include sepr type42 xfilter
+ $(ADDMOD) level2 -emulator PostScript PostScriptLevel2
+
+# Define basic Level 2 language support.
+# This is the minimum required for CMap and CIDFont support.
+
+psl2int_=iutil2.$(OBJ) zmisc2.$(OBJ) zusparam.$(OBJ)
+psl2int.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2int_) dps2int.dev
+ $(SETMOD) psl2int $(psl2int_)
+ $(ADDMOD) psl2int -include dps2int
+ $(ADDMOD) psl2int -oper zmisc2 zusparam
+ $(ADDMOD) psl2int -ps gs_lev2 gs_res
+
+iutil2.$(OBJ): iutil2.c $(GH) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsutil_h)\
+ $(errors_h) $(opcheck_h) $(imemory_h) $(iutil_h) $(iutil2_h)
+
+zmisc2.$(OBJ): zmisc2.c $(OP) $(memory__h) $(string__h)\
+ $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(ilevel_h) $(iname_h) $(iutil2_h) $(ivmspace_h) $(store_h)
+
+# Note that zusparam includes both Level 1 and Level 2 operators.
+zusparam.$(OBJ): zusparam.c $(OP) $(memory__h) $(string__h)\
+ $(gscdefs_h) $(gsfont_h) $(gsstruct_h) $(gsutil_h) $(gxht_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(iname_h) $(iutil2_h) $(store_h)
+
+# Define full Level 2 support.
+
+psl2read_=zcolor2.$(OBJ) zcsindex.$(OBJ) zht2.$(OBJ) zimage2.$(OBJ)
+# Note that zmisc2 includes both Level 1 and Level 2 operators.
+psl2read.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2read_) psl2int.dev dps2read.dev
+ $(SETMOD) psl2read $(psl2read_)
+ $(ADDMOD) psl2read -include psl2int dps2read
+ $(ADDMOD) psl2read -oper zcolor2_l2 zcsindex_l2
+ $(ADDMOD) psl2read -oper zht2_l2 zimage2_l2
+
+zcolor2.$(OBJ): zcolor2.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+zcsindex.$(OBJ): zcsindex.c $(OP) $(memory__h) \
+ $(gscolor_h) $(gsstruct_h) $(gxfixed_h) $(gxcolor2_h) $(gxcspace_h) $(gsmatrix_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zht2.$(OBJ): zht2.c $(OP) \
+ $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(estack_h) $(ialloc_h) $(icolor_h) $(idict_h) $(idparam_h) $(igstate_h) \
+ $(iht_h) $(store_h)
+
+zimage2.$(OBJ): zimage2.c $(OP) $(math__h) $(memory__h)\
+ $(gscolor_h) $(gscolor2_h) $(gscspace_h) $(gsimage_h) $(gsmatrix_h)\
+ $(idict_h) $(idparam_h) $(iimage_h) $(ilevel_h) $(igstate_h)
+
+# ---------------- Device control ---------------- #
+# This is a catch-all for setpagedevice and IODevices.
+
+devctrl_=zdevice2.$(OBJ) ziodev2.$(OBJ) zmedia2.$(OBJ) zdevcal.$(OBJ)
+devctrl.dev: $(INT_MAK) $(ECHOGS_XE) $(devctrl_)
+ $(SETMOD) devctrl $(devctrl_)
+ $(ADDMOD) devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+ $(ADDMOD) devctrl -iodev null ram calendar
+ $(ADDMOD) devctrl -ps gs_setpd
+
+zdevice2.$(OBJ): zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(store_h)\
+ $(gxdevice_h) $(gsstate_h)
+
+ziodev2.$(OBJ): ziodev2.c $(OP) $(string__h) $(gp_h)\
+ $(gxiodev_h) $(stream_h) $(files_h) $(iparam_h) $(iutil2_h) $(store_h)
+
+zmedia2.$(OBJ): zmedia2.c $(OP) $(math__h) $(memory__h) \
+ $(gsmatrix_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+
+zdevcal.$(OBJ): zdevcal.c $(GH) $(time__h) \
+ $(gxiodev_h) $(iparam_h) $(istack_h)
+
+# ---------------- Filters other than the ones in sfilter.c ---------------- #
+
+# Standard Level 2 decoding filters only. The PDF configuration uses this.
+fdecode_=scantab.$(OBJ) sfilter2.$(OBJ) zfdecode.$(OBJ)
+fdecode.dev: $(INT_MAK) $(ECHOGS_XE) $(fdecode_) cfd.dev lzwd.dev pdiff.dev pngp.dev rld.dev
+ $(SETMOD) fdecode $(fdecode_)
+ $(ADDMOD) fdecode -include cfd lzwd pdiff pngp rld
+ $(ADDMOD) fdecode -oper zfdecode
+
+zfdecode.$(OBJ): zfdecode.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sa85x_h) $(scf_h) $(scfx_h) $(sfilter_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) \
+ $(store_h) $(stream_h) $(strimpl_h)
+
+# Complete Level 2 filter capability.
+filter_=zfilter2.$(OBJ)
+filter.dev: $(INT_MAK) $(ECHOGS_XE) fdecode.dev $(filter_) cfe.dev lzwe.dev rle.dev
+ $(SETMOD) filter -include fdecode
+ $(ADDMOD) filter -obj $(filter_)
+ $(ADDMOD) filter -include cfe lzwe rle
+ $(ADDMOD) filter -oper zfilter2
+
+zfilter2.$(OBJ): zfilter2.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(store_h) \
+ $(sfilter_h) $(scfx_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) $(strimpl_h)
+
+# Extensions beyond Level 2 standard.
+xfilter_=sbhc.$(OBJ) sbwbs.$(OBJ) shcgen.$(OBJ) smtf.$(OBJ) \
+ zfilterx.$(OBJ)
+xfilter.dev: $(INT_MAK) $(ECHOGS_XE) $(xfilter_) pcxd.dev pngp.dev
+ $(SETMOD) xfilter $(xfilter_)
+ $(ADDMOD) xfilter -include pcxd
+ $(ADDMOD) xfilter -oper zfilterx
+
+sbhc.$(OBJ): sbhc.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(sbhc_h) $(shcgen_h) $(strimpl_h)
+
+sbwbs.$(OBJ): sbwbs.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(sbwbs_h) $(sfilter_h) $(strimpl_h)
+
+shcgen.$(OBJ): shcgen.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gserror_h) $(gserrors_h) $(gsmemory_h)\
+ $(scommon_h) $(shc_h) $(shcgen_h)
+
+smtf.$(OBJ): smtf.c $(AK) $(stdio__h) \
+ $(smtf_h) $(strimpl_h)
+
+zfilterx.$(OBJ): zfilterx.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(store_h) $(sfilter_h) $(sbhc_h) $(sbtx_h) $(sbwbs_h) $(shcgen_h)\
+ $(smtf_h) $(spcxx_h) $(strimpl_h)
+
+# ---------------- Binary tokens ---------------- #
+
+btoken_=iscanbin.$(OBJ) zbseq.$(OBJ)
+btoken.dev: $(INT_MAK) $(ECHOGS_XE) $(btoken_)
+ $(SETMOD) btoken $(btoken_)
+ $(ADDMOD) btoken -oper zbseq_l2
+ $(ADDMOD) btoken -ps gs_btokn
+
+bseq_h=bseq.h
+btoken_h=btoken.h
+
+iscanbin.$(OBJ): iscanbin.c $(GH) $(math__h) $(memory__h) $(errors_h)\
+ $(gsutil_h) $(ialloc_h) $(ibnum_h) $(idict_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(ivmspace_h)\
+ $(bseq_h) $(btoken_h) $(dstack_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zbseq.$(OBJ): zbseq.c $(OP) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(isave_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)\
+ $(iname_h) $(ibnum_h) $(btoken_h) $(bseq_h)
+
+# ---------------- User paths & insideness testing ---------------- #
+
+upath_=zupath.$(OBJ) ibnum.$(OBJ)
+upath.dev: $(INT_MAK) $(ECHOGS_XE) $(upath_)
+ $(SETMOD) upath $(upath_)
+ $(ADDMOD) upath -oper zupath_l2
+
+zupath.$(OBJ): zupath.c $(OP) \
+ $(idict_h) $(dstack_h) $(iutil_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h) \
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstate_h) \
+ $(gxfixed_h) $(gxdevice_h) $(gzpath_h) $(gzstate_h)
+
+# -------- Additions common to Display PostScript and Level 2 -------- #
+
+dpsand2.dev: $(INT_MAK) $(ECHOGS_XE) btoken.dev color.dev upath.dev dps2lib.dev dps2read.dev
+ $(SETMOD) dpsand2 -include btoken color upath dps2lib dps2read
+
+dps2int_=zvmem2.$(OBJ) zdps1.$(OBJ)
+# Note that zvmem2 includes both Level 1 and Level 2 operators.
+dps2int.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2int_)
+ $(SETMOD) dps2int $(dps2int_)
+ $(ADDMOD) dps2int -oper zvmem2 zdps1_l2
+ $(ADDMOD) dps2int -ps gs_dps1
+
+dps2read_=ibnum.$(OBJ) zchar2.$(OBJ)
+dps2read.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2read_) dps2int.dev
+ $(SETMOD) dps2read $(dps2read_)
+ $(ADDMOD) dps2read -include dps2int
+ $(ADDMOD) dps2read -oper ireclaim_l2 zchar2_l2
+ $(ADDMOD) dps2read -ps gs_dps2
+
+ibnum.$(OBJ): ibnum.c $(GH) $(math__h) $(memory__h)\
+ $(errors_h) $(stream_h) $(ibnum_h) $(imemory_h) $(iutil_h)
+
+zchar2.$(OBJ): zchar2.c $(OP)\
+ $(gschar_h) $(gsmatrix_h) $(gspath_h) $(gsstruct_h)\
+ $(gxchar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(ichar_h) $(estack_h) $(ifont_h) $(iname_h) $(igstate_h)\
+ $(store_h) $(stream_h) $(ibnum_h)
+
+zdps1.$(OBJ): zdps1.c $(OP) \
+ $(gsmatrix_h) $(gspath_h) $(gspath2_h) $(gsstate_h) \
+ $(ialloc_h) $(ivmspace_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h)
+
+zvmem2.$(OBJ): zvmem2.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Display PostScript ---------------- #
+
+dps_=zdps.$(OBJ) icontext.$(OBJ) zcontext.$(OBJ)
+dps.dev: $(INT_MAK) $(ECHOGS_XE) dpslib.dev level2.dev $(dps_)
+ $(SETMOD) dps -include dpslib level2
+ $(ADDMOD) dps -obj $(dps_)
+ $(ADDMOD) dps -oper zcontext zdps
+ $(ADDMOD) dps -ps gs_dps
+
+icontext.$(OBJ): icontext.c $(GH)\
+ $(gsstruct_h) $(gxalloc_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(ostack_h)\
+ $(icontext_h) $(igstate_h) $(interp_h) $(store_h)
+
+zdps.$(OBJ): zdps.c $(OP)\
+ $(gsdps_h) $(gsstate_h) $(igstate_h) $(iname_h) $(store_h)
+
+zcontext.$(OBJ): zcontext.c $(OP) $(gp_h) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h) $(gsutil_h) $(gxalloc_h)\
+ $(icontext_h) $(idict_h) $(igstate_h) $(istruct_h)\
+ $(dstack_h) $(estack_h) $(ostack_h) $(store_h)
+
+# The following #ifdef ... #endif are just a comment to mark a DPNEXT area.
+#ifdef DPNEXT
+
+# ---------------- NeXT Display PostScript ---------------- #
+#**************** NOT READY FOR USE YET ****************#
+
+# There should be a gsdpnext.c, but there isn't yet.
+#dpsnext_=zdpnext.$(OBJ) gsdpnext.$(OBJ)
+dpsnext_=zdpnext.$(OBJ)
+dpsnext.dev: $(INT_MAK) $(ECHOGS_XE) dps.dev $(dpsnext_) gs_dpnxt.ps
+ $(SETMOD) dpsnext -include dps
+ $(ADDMOD) dpsnext -obj $(dpsnext_)
+ $(ADDMOD) dpsnext -oper zdpnext
+ $(ADDMOD) dpsnext -ps gs_dpnxt
+
+zdpnext.$(OBJ): zdpnext.c $(OP)\
+ $(gscspace_h) $(gsiparam_h) $(gsmatrix_h) $(gxcvalue_h) $(gxsample_h)\
+ $(ialloc_h) $(igstate_h) $(iimage_h)
+
+# See above re the following.
+#endif /* DPNEXT */
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+compfont.dev: $(INT_MAK) $(ECHOGS_XE) psf0lib.dev psf0read.dev
+ $(SETMOD) compfont -include psf0lib psf0read
+
+# We always include zfcmap.$(OBJ) because zfont0.c refers to it,
+# and it's not worth the trouble to exclude.
+psf0read_=zchar2.$(OBJ) zfcmap.$(OBJ) zfont0.$(OBJ)
+psf0read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf0read_)
+ $(SETMOD) psf0read $(psf0read_)
+ $(ADDMOD) psf0read -oper zfont0 zchar2 zfcmap
+
+zfcmap.$(OBJ): zfcmap.c $(OP)\
+ $(gsmatrix_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxfcmap_h) $(gxfont_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifont_h) $(iname_h) $(store_h)
+
+zfont0.$(OBJ): zfont0.c $(OP)\
+ $(gschar_h) $(gsstruct_h)\
+ $(gxdevice_h) $(gxfcmap_h) $(gxfixed_h) $(gxfont_h) $(gxfont0_h) $(gxmatrix_h)\
+ $(gzstate_h)\
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h)\
+ $(store_h)
+
+# ---------------- CMap support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cmapread_=zfcmap.$(OBJ)
+cmapread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmapread_) cmaplib.dev psl2int.dev
+ $(SETMOD) cmapread $(cmapread_)
+ $(ADDMOD) cmapread -include cmaplib psl2int
+ $(ADDMOD) cmapread -oper zfcmap
+ $(ADDMOD) cmapread -ps gs_cmap
+
+# ---------------- CIDFont support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cidread_=zcid.$(OBJ)
+cidfont.dev: $(INT_MAK) $(ECHOGS_XE) psf1read.dev psl2int.dev type42.dev\
+ $(cidread_)
+ $(SETMOD) cidfont $(cidread_)
+ $(ADDMOD) cidfont -include psf1read psl2int type42
+ $(ADDMOD) cidfont -ps gs_cidfn
+ $(ADDMOD) cidfont -oper zcid
+
+zcid.$(OBJ): zcid.c $(OP)\
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h)\
+ $(bfont_h) $(iname_h) $(store_h)
+
+# ---------------- CIE color ---------------- #
+
+cieread_=zcie.$(OBJ) zcrd.$(OBJ)
+cie.dev: $(INT_MAK) $(ECHOGS_XE) $(cieread_) cielib.dev
+ $(SETMOD) cie $(cieread_)
+ $(ADDMOD) cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) cie -include cielib
+
+icie_h=icie.h
+
+zcie.$(OBJ): zcie.c $(OP) $(math__h) $(memory__h) \
+ $(gscolor2_h) $(gscie_h) $(gsstruct_h) $(gxcspace_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zcrd.$(OBJ): zcrd.c $(OP) $(math__h) \
+ $(gscspace_h) $(gscolor2_h) $(gscie_h) $(gsstruct_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Pattern color ---------------- #
+
+pattern.dev: $(INT_MAK) $(ECHOGS_XE) patlib.dev patread.dev
+ $(SETMOD) pattern -include patlib patread
+
+patread_=zpcolor.$(OBJ)
+patread.dev: $(INT_MAK) $(ECHOGS_XE) $(patread_)
+ $(SETMOD) patread $(patread_)
+ $(ADDMOD) patread -oper zpcolor_l2
+
+zpcolor.$(OBJ): zpcolor.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+# ---------------- Separation color ---------------- #
+
+seprread_=zcssepr.$(OBJ)
+sepr.dev: $(INT_MAK) $(ECHOGS_XE) $(seprread_) seprlib.dev
+ $(SETMOD) sepr $(seprread_)
+ $(ADDMOD) sepr -oper zcssepr_l2
+ $(ADDMOD) sepr -include seprlib
+
+zcssepr.$(OBJ): zcssepr.c $(OP) \
+ $(gscolor_h) $(gscsepr_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Functions ---------------- #
+
+ifunc_h=ifunc.h
+
+# Generic support, and FunctionType 0.
+funcread_=zfunc.$(OBJ) zfunc0.$(OBJ)
+func.dev: $(INT_MAK) $(ECHOGS_XE) $(funcread_) funclib.dev
+ $(SETMOD) func $(funcread_)
+ $(ADDMOD) func -oper zfunc zfunc0
+ $(ADDMOD) func -include funclib
+
+zfunc.$(OBJ): zfunc.c $(OP) $(memory__h)\
+ $(gsfunc_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h) $(store_h)
+
+zfunc0.$(OBJ): zfunc0.c $(OP) $(memory__h)\
+ $(gsdsrc_h) $(gsfunc_h) $(gsfunc0_h)\
+ $(stream_h)\
+ $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)
+
+# ---------------- DCT filters ---------------- #
+# The definitions for jpeg*.dev are in jpeg.mak.
+
+dct.dev: $(INT_MAK) $(ECHOGS_XE) dcte.dev dctd.dev
+ $(SETMOD) dct -include dcte dctd
+
+# Common code
+
+dctc_=zfdctc.$(OBJ)
+
+zfdctc.$(OBJ): zfdctc.c $(GH) $(memory__h) $(stdio__h)\
+ $(errors_h) $(opcheck_h)\
+ $(idict_h) $(idparam_h) $(imemory_h) $(ipacked_h) $(iutil_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h)\
+ jpeglib.h
+
+# Encoding (compression)
+
+dcte_=$(dctc_) zfdcte.$(OBJ)
+dcte.dev: $(INT_MAK) $(ECHOGS_XE) sdcte.dev $(dcte_)
+ $(SETMOD) dcte -include sdcte
+ $(ADDMOD) dcte -obj $(dcte_)
+ $(ADDMOD) dcte -oper zfdcte
+
+zfdcte.$(OBJ): zfdcte.c $(OP) $(memory__h) $(stdio__h)\
+ $(idict_h) $(idparam_h) $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# Decoding (decompression)
+
+dctd_=$(dctc_) zfdctd.$(OBJ)
+dctd.dev: $(INT_MAK) $(ECHOGS_XE) sdctd.dev $(dctd_)
+ $(SETMOD) dctd -include sdctd
+ $(ADDMOD) dctd -obj $(dctd_)
+ $(ADDMOD) dctd -oper zfdctd
+
+zfdctd.$(OBJ): zfdctd.c $(OP) $(memory__h) $(stdio__h)\
+ $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# ---------------- zlib/Flate filters ---------------- #
+
+fzlib.dev: $(INT_MAK) $(ECHOGS_XE) zfzlib.$(OBJ) szlibe.dev szlibd.dev
+ $(SETMOD) fzlib -include szlibe szlibd
+ $(ADDMOD) fzlib -obj zfzlib.$(OBJ)
+ $(ADDMOD) fzlib -oper zfzlib
+
+zfzlib.$(OBJ): zfzlib.c $(OP) \
+ $(errors_h) $(idict_h) $(ifilter_h) \
+ $(spdiffx_h) $(spngpx_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) zfzlib.c
+
+# ================================ PDF ================================ #
+
+# We need most of the Level 2 interpreter to do PDF, but not all of it.
+# In fact, we don't even need all of a Level 1 interpreter.
+
+# Because of the way the PDF encodings are defined, they must get loaded
+# before we install the Level 2 resource machinery.
+# On the other hand, the PDF .ps files must get loaded after
+# level2dict is defined.
+pdfmin.dev: $(INT_MAK) $(ECHOGS_XE)\
+ psbase.dev color.dev dps2lib.dev dps2read.dev\
+ fdecode.dev type1.dev pdffonts.dev psl2lib.dev psl2read.dev pdfread.dev
+ $(SETMOD) pdfmin -include psbase color dps2lib dps2read
+ $(ADDMOD) pdfmin -include fdecode type1
+ $(ADDMOD) pdfmin -include pdffonts psl2lib psl2read pdfread
+ $(ADDMOD) pdfmin -emulator PDF
+
+pdf.dev: $(INT_MAK) $(ECHOGS_XE)\
+ pdfmin.dev cff.dev cidfont.dev cie.dev compfont.dev cmapread.dev dctd.dev\
+ func.dev ttfont.dev type2.dev
+ $(SETMOD) pdf -include pdfmin cff cidfont cie cmapread compfont dctd
+ $(ADDMOD) pdf -include func ttfont type2
+
+# Reader only
+
+pdffonts.dev: $(INT_MAK) $(ECHOGS_XE) \
+ gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps
+ $(SETMOD) pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+
+# pdf_2ps must be the last .ps file loaded.
+pdfread.dev: $(INT_MAK) $(ECHOGS_XE) fzlib.dev
+ $(SETMOD) pdfread -include fzlib
+ $(ADDMOD) pdfread -ps gs_pdf gs_l2img
+ $(ADDMOD) pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+ $(ADDMOD) pdfread -ps pdf_2ps
+
+# ============================= Main program ============================== #
+
+gs.$(OBJ): gs.c $(GH) \
+ $(imain_h) $(imainarg_h) $(iminst_h)
+
+imainarg.$(OBJ): imainarg.c $(GH) $(ctype__h) $(memory__h) $(string__h) \
+ $(gp_h) \
+ $(gsargs_h) $(gscdefs_h) $(gsdevice_h) $(gsmdebug_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(errors_h) $(estack_h) $(files_h) \
+ $(ialloc_h) $(imain_h) $(imainarg_h) $(iminst_h) \
+ $(iname_h) $(interp_h) $(iscan_h) $(iutil_h) $(ivmspace_h) \
+ $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+imain.$(OBJ): imain.c $(GH) $(memory__h) $(string__h)\
+ $(gp_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h) $(gxdevice_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(interp_h)\
+ $(isave_h) $(iscan_h) $(ivmspace_h)\
+ $(main_h) $(oper_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+interp.$(OBJ): interp.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(iastruct_h) $(inamedef_h) $(idict_h) $(interp_h) $(ipacked_h)\
+ $(iscan_h) $(isave_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(oper_h) $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(CCINT) interp.c
+
+ireclaim.$(OBJ): ireclaim.c $(GH) \
+ $(errors_h) $(gsstruct_h) $(iastate_h) $(opdef_h) $(store_h) \
+ $(dstack_h) $(estack_h) $(ostack_h)
+# Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Independent JPEG Group library code.
+
+# NOTE: This makefile is only known to work with the following versions
+# of the IJG library: 6, 6a.
+# As of May 11, 1996, version 6a is the current version.
+#
+# You can get the IJG library by Internet anonymous FTP from the following
+# places:
+# Standard distribution (tar + gzip format, Unix end-of-line):
+# ftp.uu.net:/graphics/jpeg/jpegsrc.v*.tar.gz
+# ftp.cs.wisc.edu:/ghost/jpegsrc.v*.tar.gz
+# MS-DOS archive (PKZIP a.k.a. zip format, MS-DOS end-of-line):
+# ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr*.zip
+# ftp.cs.wisc.edu:/ghost/jpeg-*.zip
+# The first site named above (ftp.uu.net and ftp.simtel.net) is supposed
+# to be the master distribution site, so it may have a more up-to-date
+# version; the ftp.cs.wisc.edu site is the master distribution site for
+# Ghostscript, so it will always have IJG library versions known to be
+# compatible with Ghostscript.
+#
+# If the version number, and hence the subdirectory name, changes, you
+# will probably want to change the definitions of JSRCDIR and possibly
+# JVERSION (in the platform-specific makefile, not here) to reflect this,
+# since that way you can use the IJG archive without change.
+#
+# NOTE: For some obscure reason (probably a bug in djtarx), if you are
+# compiling on a DesqView/X system, you should use the zip version of the
+# IJG library, not the tar.gz version.
+
+# Define the name of this makefile.
+JPEG_MAK=jpeg.mak
+
+# JSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the IJG library sources are stored.
+#JSRCDIR=jpeg-6a
+# JVERSION is defined in the platform-specific makefile, not here,
+# as the IJG library major version number (currently "5" or "6").
+#JVERSION=6
+
+JSRC=$(JSRCDIR)$(D)
+# CCCJ is defined in gs.mak.
+#CCCJ=$(CCC) -I. -I$(JSRCDIR)
+
+# We keep all of the IJG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+# However, we need our own version of jconfig.h, and our own "wrapper" for
+# jmorecfg.h. We also need a substitute for jerror.c, in order to
+# keep the error strings out of the automatic data segment in
+# 16-bit environments. For v5*, we also need our own version of jpeglib.h
+# in order to change MAX_BLOCKS_IN_MCU for Adobe compatibility.
+# (This need will go away when IJG v6 is released.)
+
+# Because this file is included after lib.mak, we can't use _h macros
+# to express indirect dependencies; instead, we build the dependencies
+# into the rules for copying the files.
+jconfig_h=jconfig.h
+jerror_h=jerror.h
+jmorecfg_h=jmorecfg.h
+jpeglib_h=jpeglib.h
+
+jconfig.h: gsjconf.h $(std_h)
+ $(CP_) gsjconf.h jconfig.h
+
+jmorecfg.h: gsjmorec.h jmcorig.h
+ $(CP_) gsjmorec.h jmorecfg.h
+
+jmcorig.h: $(JSRC)jmorecfg.h
+ $(CP_) $(JSRC)jmorecfg.h jmcorig.h
+
+jpeglib.h: jlib$(JVERSION).h jconfig.h jmorecfg.h
+ $(CP_) jlib$(JVERSION).h jpeglib.h
+
+jlib5.h: gsjpglib.h
+ $(CP_) gsjpglib.h jlib5.h
+
+jlib6.h: $(JSRC)jpeglib.h
+ $(CP_) $(JSRC)jpeglib.h jlib6.h
+
+# To ensure that the compiler finds our versions of jconfig.h and jmorecfg.h,
+# regardless of the compiler's search rule, we must copy up all .c files,
+# and all .h files that include either of these files, directly or
+# indirectly. The only such .h files currently are jinclude.h and jpeglib.h.
+# (Currently, we supply our own version of jpeglib.h -- see above.)
+# Also, to avoid including the JSRCDIR directory name in our source files,
+# we must also copy up any other .h files that our own code references.
+# Currently, the only such .h files are jerror.h and jversion.h.
+
+JHCOPY=jinclude.h jpeglib.h jerror.h jversion.h
+
+jinclude.h: $(JSRC)jinclude.h
+ $(CP_) $(JSRC)jinclude.h jinclude.h
+
+#jpeglib.h: $(JSRC)jpeglib.h
+# $(CP_) $(JSRC)jpeglib.h jpeglib.h
+
+jerror.h: $(JSRC)jerror.h
+ $(CP_) $(JSRC)jerror.h jerror.h
+
+jversion.h: $(JSRC)jversion.h
+ $(CP_) $(JSRC)jversion.h jversion.h
+
+# In order to avoid having to keep the dependency lists for the IJG code
+# accurate, we simply make all of them depend on the only files that
+# we are ever going to change, and on all the .h files that must be copied up.
+# This is too conservative, but only hurts us if we are changing our own
+# j*.h files, which happens only rarely during development.
+
+JDEP=$(AK) $(jconfig_h) $(jerror_h) $(jmorecfg_h) $(JHCOPY)
+
+# Code common to compression and decompression.
+
+jpegc_=jcomapi.$(OBJ) jutils.$(OBJ) sjpegerr.$(OBJ) jmemmgr.$(OBJ)
+jpegc.dev: $(JPEG_MAK) $(ECHOGS_XE) $(jpegc_)
+ $(SETMOD) jpegc $(jpegc_)
+
+jcomapi.$(OBJ): $(JSRC)jcomapi.c $(JDEP)
+ $(CP_) $(JSRC)jcomapi.c .
+ $(CCCJ) jcomapi.c
+ $(RM_) jcomapi.c
+
+jutils.$(OBJ): $(JSRC)jutils.c $(JDEP)
+ $(CP_) $(JSRC)jutils.c .
+ $(CCCJ) jutils.c
+ $(RM_) jutils.c
+
+# Note that sjpegerr replaces jerror.
+sjpegerr.$(OBJ): sjpegerr.c $(JDEP)
+ $(CCCF) sjpegerr.c
+
+jmemmgr.$(OBJ): $(JSRC)jmemmgr.c $(JDEP)
+ $(CP_) $(JSRC)jmemmgr.c .
+ $(CCCJ) jmemmgr.c
+ $(RM_) jmemmgr.c
+
+# Encoding (compression) code.
+
+jpege.dev: jpege$(JVERSION).dev
+ $(CP_) jpege$(JVERSION).dev jpege.dev
+
+jpege5=jcapi.$(OBJ)
+jpege6=jcapimin.$(OBJ) jcapistd.$(OBJ) jcinit.$(OBJ)
+
+jpege_1=jccoefct.$(OBJ) jccolor.$(OBJ) jcdctmgr.$(OBJ)
+jpege_2=jchuff.$(OBJ) jcmainct.$(OBJ) jcmarker.$(OBJ) jcmaster.$(OBJ)
+jpege_3=jcparam.$(OBJ) jcprepct.$(OBJ) jcsample.$(OBJ) jfdctint.$(OBJ)
+
+jpege5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege5) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege5 $(jpege5)
+ $(ADDMOD) jpege5 -include jpegc
+ $(ADDMOD) jpege5 -obj $(jpege_1)
+ $(ADDMOD) jpege5 -obj $(jpege_2)
+ $(ADDMOD) jpege5 -obj $(jpege_3)
+
+jpege6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege6) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege6 $(jpege6)
+ $(ADDMOD) jpege6 -include jpegc
+ $(ADDMOD) jpege6 -obj $(jpege_1)
+ $(ADDMOD) jpege6 -obj $(jpege_2)
+ $(ADDMOD) jpege6 -obj $(jpege_3)
+
+# jcapi.c is v5* only
+jcapi.$(OBJ): $(JSRC)jcapi.c $(JDEP)
+ $(CP_) $(JSRC)jcapi.c .
+ $(CCCJ) jcapi.c
+ $(RM_) jcapi.c
+
+# jcapimin.c is new in v6
+jcapimin.$(OBJ): $(JSRC)jcapimin.c $(JDEP)
+ $(CP_) $(JSRC)jcapimin.c .
+ $(CCCJ) jcapimin.c
+ $(RM_) jcapimin.c
+
+# jcapistd.c is new in v6
+jcapistd.$(OBJ): $(JSRC)jcapistd.c $(JDEP)
+ $(CP_) $(JSRC)jcapistd.c .
+ $(CCCJ) jcapistd.c
+ $(RM_) jcapistd.c
+
+# jcinit.c is new in v6
+jcinit.$(OBJ): $(JSRC)jcinit.c $(JDEP)
+ $(CP_) $(JSRC)jcinit.c .
+ $(CCCJ) jcinit.c
+ $(RM_) jcinit.c
+
+jccoefct.$(OBJ): $(JSRC)jccoefct.c $(JDEP)
+ $(CP_) $(JSRC)jccoefct.c .
+ $(CCCJ) jccoefct.c
+ $(RM_) jccoefct.c
+
+jccolor.$(OBJ): $(JSRC)jccolor.c $(JDEP)
+ $(CP_) $(JSRC)jccolor.c .
+ $(CCCJ) jccolor.c
+ $(RM_) jccolor.c
+
+jcdctmgr.$(OBJ): $(JSRC)jcdctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jcdctmgr.c .
+ $(CCCJ) jcdctmgr.c
+ $(RM_) jcdctmgr.c
+
+jchuff.$(OBJ): $(JSRC)jchuff.c $(JDEP)
+ $(CP_) $(JSRC)jchuff.c .
+ $(CCCJ) jchuff.c
+ $(RM_) jchuff.c
+
+jcmainct.$(OBJ): $(JSRC)jcmainct.c $(JDEP)
+ $(CP_) $(JSRC)jcmainct.c .
+ $(CCCJ) jcmainct.c
+ $(RM_) jcmainct.c
+
+jcmarker.$(OBJ): $(JSRC)jcmarker.c $(JDEP)
+ $(CP_) $(JSRC)jcmarker.c .
+ $(CCCJ) jcmarker.c
+ $(RM_) jcmarker.c
+
+jcmaster.$(OBJ): $(JSRC)jcmaster.c $(JDEP)
+ $(CP_) $(JSRC)jcmaster.c .
+ $(CCCJ) jcmaster.c
+ $(RM_) jcmaster.c
+
+jcparam.$(OBJ): $(JSRC)jcparam.c $(JDEP)
+ $(CP_) $(JSRC)jcparam.c .
+ $(CCCJ) jcparam.c
+ $(RM_) jcparam.c
+
+jcprepct.$(OBJ): $(JSRC)jcprepct.c $(JDEP)
+ $(CP_) $(JSRC)jcprepct.c .
+ $(CCCJ) jcprepct.c
+ $(RM_) jcprepct.c
+
+jcsample.$(OBJ): $(JSRC)jcsample.c $(JDEP)
+ $(CP_) $(JSRC)jcsample.c .
+ $(CCCJ) jcsample.c
+ $(RM_) jcsample.c
+
+jfdctint.$(OBJ): $(JSRC)jfdctint.c $(JDEP)
+ $(CP_) $(JSRC)jfdctint.c .
+ $(CCCJ) jfdctint.c
+ $(RM_) jfdctint.c
+
+# Decompression code
+
+jpegd.dev: jpegd$(JVERSION).dev
+ $(CP_) jpegd$(JVERSION).dev jpegd.dev
+
+jpegd5=jdapi.$(OBJ)
+jpegd6=jdapimin.$(OBJ) jdapistd.$(OBJ) jdinput.$(OBJ) jdphuff.$(OBJ)
+
+jpegd_1=jdcoefct.$(OBJ) jdcolor.$(OBJ)
+jpegd_2=jddctmgr.$(OBJ) jdhuff.$(OBJ) jdmainct.$(OBJ) jdmarker.$(OBJ)
+jpegd_3=jdmaster.$(OBJ) jdpostct.$(OBJ) jdsample.$(OBJ) jidctint.$(OBJ)
+
+jpegd5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd5) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd5 $(jpegd5)
+ $(ADDMOD) jpegd5 -include jpegc
+ $(ADDMOD) jpegd5 -obj $(jpegd_1)
+ $(ADDMOD) jpegd5 -obj $(jpegd_2)
+ $(ADDMOD) jpegd5 -obj $(jpegd_3)
+
+jpegd6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd6) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd6 $(jpegd6)
+ $(ADDMOD) jpegd6 -include jpegc
+ $(ADDMOD) jpegd6 -obj $(jpegd_1)
+ $(ADDMOD) jpegd6 -obj $(jpegd_2)
+ $(ADDMOD) jpegd6 -obj $(jpegd_3)
+
+# jdapi.c is v5* only
+jdapi.$(OBJ): $(JSRC)jdapi.c $(JDEP)
+ $(CP_) $(JSRC)jdapi.c .
+ $(CCCJ) jdapi.c
+ $(RM_) jdapi.c
+
+# jdapimin.c is new in v6
+jdapimin.$(OBJ): $(JSRC)jdapimin.c $(JDEP)
+ $(CP_) $(JSRC)jdapimin.c .
+ $(CCCJ) jdapimin.c
+ $(RM_) jdapimin.c
+
+# jdapistd.c is new in v6
+jdapistd.$(OBJ): $(JSRC)jdapistd.c $(JDEP)
+ $(CP_) $(JSRC)jdapistd.c .
+ $(CCCJ) jdapistd.c
+ $(RM_) jdapistd.c
+
+jdcoefct.$(OBJ): $(JSRC)jdcoefct.c $(JDEP)
+ $(CP_) $(JSRC)jdcoefct.c .
+ $(CCCJ) jdcoefct.c
+ $(RM_) jdcoefct.c
+
+jdcolor.$(OBJ): $(JSRC)jdcolor.c $(JDEP)
+ $(CP_) $(JSRC)jdcolor.c .
+ $(CCCJ) jdcolor.c
+ $(RM_) jdcolor.c
+
+jddctmgr.$(OBJ): $(JSRC)jddctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jddctmgr.c .
+ $(CCCJ) jddctmgr.c
+ $(RM_) jddctmgr.c
+
+jdhuff.$(OBJ): $(JSRC)jdhuff.c $(JDEP)
+ $(CP_) $(JSRC)jdhuff.c .
+ $(CCCJ) jdhuff.c
+ $(RM_) jdhuff.c
+
+# jdinput.c is new in v6
+jdinput.$(OBJ): $(JSRC)jdinput.c $(JDEP)
+ $(CP_) $(JSRC)jdinput.c .
+ $(CCCJ) jdinput.c
+ $(RM_) jdinput.c
+
+jdmainct.$(OBJ): $(JSRC)jdmainct.c $(JDEP)
+ $(CP_) $(JSRC)jdmainct.c .
+ $(CCCJ) jdmainct.c
+ $(RM_) jdmainct.c
+
+jdmarker.$(OBJ): $(JSRC)jdmarker.c $(JDEP)
+ $(CP_) $(JSRC)jdmarker.c .
+ $(CCCJ) jdmarker.c
+ $(RM_) jdmarker.c
+
+jdmaster.$(OBJ): $(JSRC)jdmaster.c $(JDEP)
+ $(CP_) $(JSRC)jdmaster.c .
+ $(CCCJ) jdmaster.c
+ $(RM_) jdmaster.c
+
+# jdphuff.c is new in v6
+jdphuff.$(OBJ): $(JSRC)jdphuff.c $(JDEP)
+ $(CP_) $(JSRC)jdphuff.c .
+ $(CCCJ) jdphuff.c
+ $(RM_) jdphuff.c
+
+jdpostct.$(OBJ): $(JSRC)jdpostct.c $(JDEP)
+ $(CP_) $(JSRC)jdpostct.c .
+ $(CCCJ) jdpostct.c
+ $(RM_) jdpostct.c
+
+jdsample.$(OBJ): $(JSRC)jdsample.c $(JDEP)
+ $(CP_) $(JSRC)jdsample.c .
+ $(CCCJ) jdsample.c
+ $(RM_) jdsample.c
+
+jidctint.$(OBJ): $(JSRC)jidctint.c $(JDEP)
+ $(CP_) $(JSRC)jidctint.c .
+ $(CCCJ) jidctint.c
+ $(RM_) jidctint.c
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for PNG (Portable Network Graphics) code.
+
+# This partial makefile compiles the png library for use in the Ghostscript
+# PNG drivers. You can get the source code for this library from:
+# ftp://swrinde.nde.swri.edu/pub/png/src/
+# The makefile is known to work with the following library versions:
+# 0.89, 0.90, 0.95, and 0.96. NOTE: the archive for libpng 0.95 may
+# be inconsistent: if you have compilation problems, use an older version.
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+#
+# The specification for the PNG file format is available from:
+# http://www.group42.com/png.htm
+# http://www.w3.org/pub/WWW/TR/WD-png
+
+# Define the name of this makefile.
+LIBPNG_MAK=libpng.mak
+
+# PSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the PNG library sources are stored.
+#PSRCDIR=libpng
+# PVERSION is defined in the platform-specific makefile, not here,
+# as the libpng version number ("89", "90", "95", or "96").
+#PVERSION=96
+
+PSRC=$(PSRCDIR)$(D)
+# CCCP is defined in gs.mak.
+#CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR)
+
+# We keep all of the PNG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+PDEP=$(AK)
+
+png_1=png.$(OBJ) pngmem.$(OBJ) pngerror.$(OBJ)
+png_2=pngtrans.$(OBJ) pngwrite.$(OBJ) pngwtran.$(OBJ) pngwutil.$(OBJ)
+
+# libpng modules
+
+png.$(OBJ): $(PSRC)png.c $(PDEP)
+ $(CCCP) $(PSRC)png.c
+
+# version 0.89 uses pngwio.c
+pngwio.$(OBJ): $(PSRC)pngwio.c $(PDEP)
+ $(CCCP) $(PSRC)pngwio.c
+
+pngmem.$(OBJ): $(PSRC)pngmem.c $(PDEP)
+ $(CCCP) $(PSRC)pngmem.c
+
+pngerror.$(OBJ): $(PSRC)pngerror.c $(PDEP)
+ $(CCCP) $(PSRC)pngerror.c
+
+pngtrans.$(OBJ): $(PSRC)pngtrans.c $(PDEP)
+ $(CCCP) $(PSRC)pngtrans.c
+
+pngwrite.$(OBJ): $(PSRC)pngwrite.c $(PDEP)
+ $(CCCP) $(PSRC)pngwrite.c
+
+pngwtran.$(OBJ): $(PSRC)pngwtran.c $(PDEP)
+ $(CCCP) $(PSRC)pngwtran.c
+
+pngwutil.$(OBJ): $(PSRC)pngwutil.c $(PDEP)
+ $(CCCP) $(PSRC)pngwutil.c
+
+# Define the version of libpng.dev that we are actually using.
+libpng.dev: $(MAKEFILE) libpng_$(SHARE_LIBPNG).dev
+ $(CP_) libpng_$(SHARE_LIBPNG).dev libpng.dev
+
+# Define the shared version of libpng.
+# Note that it requires libz, which must be searched *after* libpng.
+libpng_1.dev: $(MAKEFILE) $(LIBPNG_MAK) $(ECHOGS_XE) zlibe.dev
+ $(SETMOD) libpng_1 -lib $(LIBPNG_NAME)
+ $(ADDMOD) libpng_1 -include zlibe
+
+# Define the non-shared version of libpng.
+libpng_0.dev: $(LIBPNG_MAK) $(ECHOGS_XE) $(png_1) $(png_2)\
+ zlibe.dev libpng$(PVERSION).dev
+ $(SETMOD) libpng_0 $(png_1)
+ $(ADDMOD) libpng_0 $(png_2)
+ $(ADDMOD) libpng_0 -include zlibe libpng$(PVERSION)
+
+libpng89.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ)
+ $(SETMOD) libpng89 pngwio.$(OBJ)
+
+libpng90.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng90 pngwio.$(OBJ) -include crc32
+
+libpng95.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng95 pngwio.$(OBJ) -include crc32
+
+libpng96.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng96 pngwio.$(OBJ) -include crc32
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for zlib library code.
+
+# This partial makefile compiles the zlib library for use in Ghostscript.
+# You can get the source code for this library from:
+# ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib104.zip (zlib 1.0.4)
+# or zlib-1.0.4.tar.gz
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+
+# Define the name of this makefile.
+ZLIB_MAK=zlib.mak
+
+# ZSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the zlib sources are stored.
+#ZSRCDIR=zlib
+ZSRC=$(ZSRCDIR)$(D)
+# We would like to define
+#CCCZ=$(CCC) -I$(ZSRCDIR) -Dverbose=-1
+# but the Watcom C compiler has strange undocumented restrictions on what can
+# follow a -D=, and it doesn't allow negative numbers. Instead, we define
+# (in gs.mak):
+#CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+# and handle the definition of verbose in a different, more awkward way.
+
+# We keep all of the zlib code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+ZDEP=$(AK)
+
+# Contrary to what some portability bigots assert as fact, C compilers are
+# not consistent about where they start searching for #included files:
+# some always start by looking in the same directory as the .c file being
+# compiled, before using the search path specified with -I on the command
+# line, while others do not do this. For this reason, we must explicitly
+# copy and then delete all the .c files, because they need to obtain our
+# modified version of zutil.h. We must also copy all header files that
+# reference zutil.h directly or indirectly.
+
+# Code common to compression and decompression.
+
+zlibc_=zutil.$(OBJ)
+zlibc.dev: $(ZLIB_MAK) $(ECHOGS_XE) $(zlibc_)
+ $(SETMOD) zlibc $(zlibc_)
+
+zutil.h: $(ZSRC)zutil.h $(ECHOGS_XE)
+ $(EXP)echogs -w zutil.h -x 23 define verbose -s - -1
+ $(EXP)echogs -a zutil.h -+R $(ZSRC)zutil.h
+
+zutil.$(OBJ): $(ZSRC)zutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)zutil.c .
+ $(CCCZ) zutil.c
+ $(RM_) zutil.c
+
+# Encoding (compression) code.
+
+deflate.h: $(ZSRC)deflate.h zutil.h
+ $(CP_) $(ZSRC)deflate.h .
+
+zlibe.dev: $(MAKEFILE) zlibe_$(SHARE_ZLIB).dev
+ $(CP_) zlibe_$(SHARE_ZLIB).dev zlibe.dev
+
+zlibe_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibe_1 -lib $(ZLIB_NAME)
+
+zlibe_=adler32.$(OBJ) deflate.$(OBJ) trees.$(OBJ)
+zlibe_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibe_)
+ $(SETMOD) zlibe_0 $(zlibe_)
+ $(ADDMOD) zlibe_0 -include zlibc
+
+adler32.$(OBJ): $(ZSRC)adler32.c $(ZDEP)
+ $(CP_) $(ZSRC)adler32.c .
+ $(CCCZ) adler32.c
+ $(RM_) adler32.c
+
+deflate.$(OBJ): $(ZSRC)deflate.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)deflate.c .
+ $(CCCZ) deflate.c
+ $(RM_) deflate.c
+
+trees.$(OBJ): $(ZSRC)trees.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)trees.c .
+ $(CCCZ) trees.c
+ $(RM_) trees.c
+
+# The zlib filters per se don't need crc32, but libpng versions starting
+# with 0.90 do.
+
+crc32.dev: $(MAKEFILE) crc32_$(SHARE_ZLIB).dev
+ $(CP_) crc32_$(SHARE_ZLIB).dev crc32.dev
+
+crc32_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) crc32_1 -lib $(ZLIB_NAME)
+
+crc32_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) crc32.$(OBJ)
+ $(SETMOD) crc32_0 crc32.$(OBJ)
+
+crc32.$(OBJ): $(ZSRC)crc32.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)crc32.c .
+ $(CCCZ) crc32.c
+ $(RM_) crc32.c
+
+# Decoding (decompression) code.
+
+zlibd.dev: $(MAKEFILE) zlibd_$(SHARE_ZLIB).dev
+ $(CP_) zlibd_$(SHARE_ZLIB).dev zlibd.dev
+
+zlibd_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibd_1 -lib $(ZLIB_NAME)
+
+zlibd1_=infblock.$(OBJ) infcodes.$(OBJ) inffast.$(OBJ)
+zlibd2_=inflate.$(OBJ) inftrees.$(OBJ) infutil.$(OBJ)
+zlibd_ = $(zlibd1_) $(zlibd2_)
+zlibd_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibd_)
+ $(SETMOD) zlibd_0 $(zlibd1_)
+ $(ADDMOD) zlibd_0 -obj $(zlibd2_)
+ $(ADDMOD) zlibd_0 -include zlibc
+
+infblock.$(OBJ): $(ZSRC)infblock.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infblock.c .
+ $(CCCZ) infblock.c
+ $(RM_) infblock.c
+
+infcodes.$(OBJ): $(ZSRC)infcodes.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infcodes.c .
+ $(CCCZ) infcodes.c
+ $(RM_) infcodes.c
+
+inffast.$(OBJ): $(ZSRC)inffast.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inffast.c .
+ $(CCCZ) inffast.c
+ $(RM_) inffast.c
+
+inflate.$(OBJ): $(ZSRC)inflate.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inflate.c .
+ $(CCCZ) inflate.c
+ $(RM_) inflate.c
+
+inftrees.$(OBJ): $(ZSRC)inftrees.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inftrees.c .
+ $(CCCZ) inftrees.c
+ $(RM_) inftrees.c
+
+infutil.$(OBJ): $(ZSRC)infutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infutil.c .
+ $(CCCZ) infutil.c
+ $(RM_) infutil.c
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for device drivers.
+
+# Define the name of this makefile.
+DEVS_MAK=devs.mak
+
+###### --------------------------- Catalog -------------------------- ######
+
+# It is possible to build configurations with an arbitrary collection of
+# device drivers, although some drivers are supported only on a subset
+# of the target platforms. The currently available drivers are:
+
+# MS-DOS displays (note: not usable with Desqview/X):
+# MS-DOS EGA and VGA:
+# ega EGA (640x350, 16-color)
+# vga VGA (640x480, 16-color)
+# MS-DOS SuperVGA:
+# * ali SuperVGA using Avance Logic Inc. chipset, 256-color modes
+# * atiw ATI Wonder SuperVGA, 256-color modes
+# * s3vga SuperVGA using S3 86C911 chip (e.g., Diamond Stealth board)
+# svga16 Generic SuperVGA in 800x600, 16-color mode
+# * tseng SuperVGA using Tseng Labs ET3000/4000 chips, 256-color modes
+# * tvga SuperVGA using Trident chipset, 256-color modes
+# ****** NOTE: The vesa device does not work with the Watcom (32-bit MS-DOS)
+# ****** compiler or executable.
+# vesa SuperVGA with VESA standard API driver
+# MS-DOS other:
+# bgi Borland Graphics Interface (CGA) [MS-DOS only]
+# * herc Hercules Graphics display [MS-DOS only]
+# * pe Private Eye display
+# Other displays:
+# MS Windows:
+# mswindll Microsoft Windows 3.1 DLL [MS Windows only]
+# mswinprn Microsoft Windows 3.0, 3.1 DDB printer [MS Windows only]
+# mswinpr2 Microsoft Windows 3.0, 3.1 DIB printer [MS Windows only]
+# OS/2:
+# * os2pm OS/2 Presentation Manager [OS/2 only]
+# * os2dll OS/2 DLL bitmap [OS/2 only]
+# * os2prn OS/2 printer [OS/2 only]
+# Unix and VMS:
+# ****** NOTE: For direct frame buffer addressing under SCO Unix or Xenix,
+# ****** edit the definition of EGAVGA below.
+# * att3b1 AT&T 3b1/Unixpc monochrome display [3b1 only]
+# * lvga256 Linux vgalib, 256-color VGA modes [Linux only]
+# * sonyfb Sony Microsystems monochrome display [Sony only]
+# * sunview SunView window system [SunOS only]
+# + vgalib Linux PC with VGALIB [Linux only]
+# x11 X Windows version 11, release >=4 [Unix and VMS only]
+# x11alpha X Windows masquerading as a device with alpha capability
+# x11cmyk X Windows masquerading as a 1-bit-per-plane CMYK device
+# x11gray2 X Windows as a 2-bit gray-scale device
+# x11mono X Windows masquerading as a black-and-white device
+# Platform-independent:
+# * sxlcrt CRT sixels, e.g. for VT240-like terminals
+# Printers:
+# * ap3250 Epson AP3250 printer
+# * appledmp Apple Dot Matrix Printer (should also work with Imagewriter)
+# bj10e Canon BubbleJet BJ10e
+# * bj200 Canon BubbleJet BJ200
+# * bjc600 Canon Color BubbleJet BJC-600, BJC-4000 and BJC-70
+# also good for Apple printers like the StyleWriter 2x00
+# * bjc800 Canon Color BubbleJet BJC-800
+# * ccr CalComp Raster format
+# * cdeskjet H-P DeskJet 500C with 1 bit/pixel color
+# * cdjcolor H-P DeskJet 500C with 24 bit/pixel color and
+# high-quality color (Floyd-Steinberg) dithering;
+# also good for DeskJet 540C and Citizen Projet IIc (-r200x300)
+# * cdjmono H-P DeskJet 500C printing black only;
+# also good for DeskJet 510, 520, and 540C (black only)
+# * cdj500 H-P DeskJet 500C (same as cdjcolor)
+# * cdj550 H-P DeskJet 550C/560C/660C/660Cse
+# * cp50 Mitsubishi CP50 color printer
+# * declj250 alternate DEC LJ250 driver
+# + deskjet H-P DeskJet and DeskJet Plus
+# djet500 H-P DeskJet 500; use -r600 for DJ 600 series
+# * djet500c H-P DeskJet 500C alternate driver
+# (does not work on 550C or 560C)
+# * dnj650c H-P DesignJet 650C
+# epson Epson-compatible dot matrix printers (9- or 24-pin)
+# * eps9mid Epson-compatible 9-pin, interleaved lines
+# (intermediate resolution)
+# * eps9high Epson-compatible 9-pin, interleaved lines
+# (triple resolution)
+# * epsonc Epson LQ-2550 and Fujitsu 3400/2400/1200 color printers
+# * ibmpro IBM 9-pin Proprinter
+# * imagen Imagen ImPress printers
+# * iwhi Apple Imagewriter in high-resolution mode
+# * iwlo Apple Imagewriter in low-resolution mode
+# * iwlq Apple Imagewriter LQ in 320 x 216 dpi mode
+# * jetp3852 IBM Jetprinter ink-jet color printer (Model #3852)
+# + laserjet H-P LaserJet
+# * la50 DEC LA50 printer
+# * la70 DEC LA70 printer
+# * la70t DEC LA70 printer with low-resolution text enhancement
+# * la75 DEC LA75 printer
+# * la75plus DEC LA75plus printer
+# * lbp8 Canon LBP-8II laser printer
+# * lips3 Canon LIPS III laser printer in English (CaPSL) mode
+# * ln03 DEC LN03 printer
+# * lj250 DEC LJ250 Companion color printer
+# + ljet2p H-P LaserJet IId/IIp/III* with TIFF compression
+# + ljet3 H-P LaserJet III* with Delta Row compression
+# + ljet3d H-P LaserJet IIID with duplex capability
+# + ljet4 H-P LaserJet 4 (defaults to 600 dpi)
+# + lj4dith H-P LaserJet 4 with Floyd-Steinberg dithering
+# + ljetplus H-P LaserJet Plus
+# lj5mono H-P LaserJet 5 & 6 family (PCL XL), bitmap:
+# see below for restrictions & advice
+# lj5gray H-P LaserJet 5 & 6 family, gray-scale bitmap;
+# see below for restrictions & advice
+# * lp2563 H-P 2563B line printer
+# * lp8000 Epson LP-8000 laser printer
+# * lq850 Epson LQ850 printer at 360 x 360 DPI resolution;
+# also good for Canon BJ300 with LQ850 emulation
+# * m8510 C.Itoh M8510 printer
+# * necp6 NEC P6/P6+/P60 printers at 360 x 360 DPI resolution
+# * nwp533 Sony Microsystems NWP533 laser printer [Sony only]
+# * oce9050 OCE 9050 printer
+# * oki182 Okidata MicroLine 182
+# * okiibm Okidata MicroLine IBM-compatible printers
+# * paintjet alternate H-P PaintJet color printer
+# * pj H-P PaintJet XL driver
+# * pjetxl alternate H-P PaintJet XL driver
+# * pjxl H-P PaintJet XL color printer
+# * pjxl300 H-P PaintJet XL300 color printer;
+# also good for PaintJet 1200C
+# (pxlmono) H-P black-and-white PCL XL printers (LaserJet 5 and 6 family)
+# (pxlcolor) H-P color PCL XL printers (none available yet)
+# * r4081 Ricoh 4081 laser printer
+# * sj48 StarJet 48 inkjet printer
+# * sparc SPARCprinter
+# * st800 Epson Stylus 800 printer
+# * stcolor Epson Stylus Color
+# * t4693d2 Tektronix 4693d color printer, 2 bits per R/G/B component
+# * t4693d4 Tektronix 4693d color printer, 4 bits per R/G/B component
+# * t4693d8 Tektronix 4693d color printer, 8 bits per R/G/B component
+# * tek4696 Tektronix 4695/4696 inkjet plotter
+# * uniprint Unified printer driver -- Configurable Color ESC/P-,
+# ESC/P2-, HP-RTL/PCL mono/color driver
+# * xes Xerox XES printers (2700, 3700, 4045, etc.)
+# Fax systems:
+# * dfaxhigh DigiBoard, Inc.'s DigiFAX software format (high resolution)
+# * dfaxlow DigiFAX low (normal) resolution
+# Fax file format:
+# ****** NOTE: all of these drivers adjust the page size to match
+# ****** one of the three CCITT standard sizes (U.S. letter with A4 width,
+# ****** A4, or B4).
+# faxg3 Group 3 fax, with EOLs but no header or EOD
+# faxg32d Group 3 2-D fax, with EOLs but no header or EOD
+# faxg4 Group 4 fax, with EOLs but no header or EOD
+# tiffcrle TIFF "CCITT RLE 1-dim" (= Group 3 fax with no EOLs)
+# tiffg3 TIFF Group 3 fax (with EOLs)
+# tiffg32d TIFF Group 3 2-D fax
+# tiffg4 TIFF Group 4 fax
+# High-level file formats:
+# epswrite EPS output (like PostScript Distillery)
+# pdfwrite PDF output (like Adobe Acrobat Distiller)
+# pswrite PostScript output (like PostScript Distillery)
+# pxlmono Black-and-white PCL XL
+# pxlcolor Color PCL XL
+# Other raster file formats and devices:
+# bit Plain bits, monochrome
+# bitrgb Plain bits, RGB
+# bitcmyk Plain bits, CMYK
+# bmpmono Monochrome MS Windows .BMP file format
+# bmp16 4-bit (EGA/VGA) .BMP file format
+# bmp256 8-bit (256-color) .BMP file format
+# bmp16m 24-bit .BMP file format
+# cgmmono Monochrome (black-and-white) CGM -- LOW LEVEL OUTPUT ONLY
+# cgm8 8-bit (256-color) CGM -- DITTO
+# cgm24 24-bit color CGM -- DITTO
+# * cif CIF file format for VLSI
+# jpeg JPEG format, RGB output
+# jpeggray JPEG format, gray output
+# miff24 ImageMagick MIFF format, 24-bit direct color, RLE compressed
+# * mgrmono 1-bit monochrome MGR devices
+# * mgrgray2 2-bit gray scale MGR devices
+# * mgrgray4 4-bit gray scale MGR devices
+# * mgrgray8 8-bit gray scale MGR devices
+# * mgr4 4-bit (VGA) color MGR devices
+# * mgr8 8-bit color MGR devices
+# pcxmono PCX file format, monochrome (1-bit black and white)
+# pcxgray PCX file format, 8-bit gray scale
+# pcx16 PCX file format, 4-bit planar (EGA/VGA) color
+# pcx256 PCX file format, 8-bit chunky color
+# pcx24b PCX file format, 24-bit color (3 8-bit planes)
+# pcxcmyk PCX file format, 4-bit chunky CMYK color
+# pbm Portable Bitmap (plain format)
+# pbmraw Portable Bitmap (raw format)
+# pgm Portable Graymap (plain format)
+# pgmraw Portable Graymap (raw format)
+# pgnm Portable Graymap (plain format), optimizing to PBM if possible
+# pgnmraw Portable Graymap (raw format), optimizing to PBM if possible
+# pnm Portable Pixmap (plain format) (RGB), optimizing to PGM or PBM
+# if possible
+# pnmraw Portable Pixmap (raw format) (RGB), optimizing to PGM or PBM
+# if possible
+# ppm Portable Pixmap (plain format) (RGB)
+# ppmraw Portable Pixmap (raw format) (RGB)
+# pkm Portable inKmap (plain format) (4-bit CMYK => RGB)
+# pkmraw Portable inKmap (raw format) (4-bit CMYK => RGB)
+# pngmono Monochrome Portable Network Graphics (PNG)
+# pnggray 8-bit gray Portable Network Graphics (PNG)
+# png16 4-bit color Portable Network Graphics (PNG)
+# png256 8-bit color Portable Network Graphics (PNG)
+# png16m 24-bit color Portable Network Graphics (PNG)
+# psmono PostScript (Level 1) monochrome image
+# psgray PostScript (Level 1) 8-bit gray image
+# sgirgb SGI RGB pixmap format
+# tiff12nc TIFF 12-bit RGB, no compression
+# tiff24nc TIFF 24-bit RGB, no compression (NeXT standard format)
+# tifflzw TIFF LZW (tag = 5) (monochrome)
+# tiffpack TIFF PackBits (tag = 32773) (monochrome)
+
+# User-contributed drivers marked with * require hardware or software
+# that is not available to Aladdin Enterprises. Please contact the
+# original contributors, not Aladdin Enterprises, if you have questions.
+# Contact information appears in the driver entry below.
+#
+# Drivers marked with a + are maintained by Aladdin Enterprises with
+# the assistance of users, since Aladdin Enterprises doesn't have access to
+# the hardware for these either.
+
+# If you add drivers, it would be nice if you kept each list
+# in alphabetical order.
+
+###### ----------------------- End of catalog ----------------------- ######
+
+# As noted in gs.mak, DEVICE_DEVS and DEVICE_DEVS1..15 select the devices
+# that should be included in a given configuration. By convention, these
+# are used as follows. Each of these must be limited to about 10 devices
+# so as not to overflow the 120 character limit on MS-DOS command lines.
+# DEVICE_DEVS - the default device, and any display devices.
+# DEVICE_DEVS1 - additional display devices if needed.
+# DEVICE_DEVS2 - dot matrix printers.
+# DEVICE_DEVS3 - H-P monochrome printers.
+# DEVICE_DEVS4 - H-P color printers.
+# DEVICE_DEVS5 - additional H-P printers if needed.
+# DEVICE_DEVS6 - other ink-jet and laser printers.
+# DEVICE_DEVS7 - fax file formats.
+# DEVICE_DEVS8 - PCX file formats.
+# DEVICE_DEVS9 - PBM/PGM/PPM file formats.
+# DEVICE_DEVS10 - black-and-white TIFF file formats.
+# DEVICE_DEVS11 - BMP and color TIFF file formats.
+# DEVICE_DEVS12 - PostScript image and 'bit' file formats.
+# DEVICE_DEVS13 - PNG file formats.
+# DEVICE_DEVS14 - CGM, JPEG, and MIFF file formats.
+# DEVICE_DEVS15 - high-level (PostScript and PDF) file formats.
+# Feel free to disregard this convention if it gets in your way.
+
+# If you want to add a new device driver, the examples below should be
+# enough of a guide to the correct form for the makefile rules.
+# Note that all drivers other than displays must include page.dev in their
+# dependencies and use $(SETPDEV) rather than $(SETDEV) in their rule bodies.
+
+# All device drivers depend on the following:
+GDEV=$(AK) $(ECHOGS_XE) $(gserrors_h) $(gx_h) $(gxdevice_h)
+
+# "Printer" drivers depend on the following:
+PDEVH=$(AK) $(gdevprn_h)
+
+# Define the header files for device drivers. Every header file used by
+# more than one device driver family must be listed here.
+gdev8bcm_h=gdev8bcm.h
+gdevpccm_h=gdevpccm.h
+gdevpcfb_h=gdevpcfb.h $(dos__h)
+gdevpcl_h=gdevpcl.h
+gdevsvga_h=gdevsvga.h
+gdevx_h=gdevx.h
+
+###### ----------------------- Device support ----------------------- ######
+
+# Provide a mapping between StandardEncoding and ISOLatin1Encoding.
+gdevemap.$(OBJ): gdevemap.c $(AK) $(std_h)
+
+# Implement dynamic color management for 8-bit mapped color displays.
+gdev8bcm.$(OBJ): gdev8bcm.c $(AK) \
+ $(gx_h) $(gxdevice_h) $(gdev8bcm_h)
+
+###### ------------------- MS-DOS display devices ------------------- ######
+
+# There are really only three drivers: an EGA/VGA driver (4 bit-planes,
+# plane-addressed), a SuperVGA driver (8 bit-planes, byte addressed),
+# and a special driver for the S3 chip.
+
+# PC display color mapping
+gdevpccm.$(OBJ): gdevpccm.c $(AK) \
+ $(gx_h) $(gsmatrix_h) $(gxdevice_h) $(gdevpccm_h)
+
+### ----------------------- EGA and VGA displays ----------------------- ###
+
+# The shared MS-DOS makefile defines PCFBASM as either gdevegaa.$(OBJ)
+# or an empty string.
+
+gdevegaa.$(OBJ): gdevegaa.asm
+
+# NOTE: for direct frame buffer addressing under SCO Unix or Xenix,
+# change gdevevga to gdevsco in the following line. Also, since
+# SCO's /bin/as does not support the "out" instructions, you must build
+# the gnu assembler and have it on your path as "as".
+EGAVGA=gdevevga.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+#EGAVGA=gdevsco.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevevga.$(OBJ): gdevevga.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+ $(CCD) gdevevga.c
+
+gdevsco.$(OBJ): gdevsco.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+
+# Common code for MS-DOS and SCO.
+gdevpcfb.$(OBJ): gdevpcfb.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gdevpccm_h) $(gdevpcfb_h) $(gsparam_h)
+ $(CCD) gdevpcfb.c
+
+# The EGA/VGA family includes EGA and VGA. Many SuperVGAs in 800x600,
+# 16-color mode can share the same code; see the next section below.
+
+ega.dev: $(EGAVGA)
+ $(SETDEV) ega $(EGAVGA)
+
+vga.dev: $(EGAVGA)
+ $(SETDEV) vga $(EGAVGA)
+
+### ------------------------- SuperVGA displays ------------------------ ###
+
+# SuperVGA displays in 16-color, 800x600 mode are really just slightly
+# glorified VGA's, so we can handle them all with a single driver.
+# The way to select them on the command line is with
+# -sDEVICE=svga16 -dDisplayMode=NNN
+# where NNN is the display mode in decimal. See use.txt for the modes
+# for some popular display chipsets.
+
+svga16.dev: $(EGAVGA)
+ $(SETDEV) svga16 $(EGAVGA)
+
+# More capable SuperVGAs have a wide variety of slightly differing
+# interfaces, so we need a separate driver for each one.
+
+SVGA=gdevsvga.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevsvga.$(OBJ): gdevsvga.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gsparam_h) $(gxarith_h) $(gdevpccm_h) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevsvga.c
+
+# The SuperVGA family includes: Avance Logic Inc., ATI Wonder, S3,
+# Trident, Tseng ET3000/4000, and VESA.
+
+ali.dev: $(SVGA)
+ $(SETDEV) ali $(SVGA)
+
+atiw.dev: $(SVGA)
+ $(SETDEV) atiw $(SVGA)
+
+tseng.dev: $(SVGA)
+ $(SETDEV) tseng $(SVGA)
+
+tvga.dev: $(SVGA)
+ $(SETDEV) tvga $(SVGA)
+
+vesa.dev: $(SVGA)
+ $(SETDEV) vesa $(SVGA)
+
+# The S3 driver doesn't share much code with the others.
+
+s3vga_=gdevs3ga.$(OBJ) gdevsvga.$(OBJ) gdevpccm.$(OBJ)
+s3vga.dev: $(SVGA) $(s3vga_)
+ $(SETDEV) s3vga $(SVGA)
+ $(ADDMOD) s3vga -obj $(s3vga_)
+
+gdevs3ga.$(OBJ): gdevs3ga.c $(GDEV) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevs3ga.c
+
+### ------------ The BGI (Borland Graphics Interface) device ----------- ###
+
+cgaf.$(OBJ): $(BGIDIR)\cga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\cga
+
+egavgaf.$(OBJ): $(BGIDIR)\egavga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\egavga
+
+# Include egavgaf.$(OBJ) for debugging only.
+bgi_=gdevbgi.$(OBJ) cgaf.$(OBJ)
+bgi.dev: $(bgi_)
+ $(SETDEV) bgi $(bgi_)
+ $(ADDMOD) bgi -lib $(LIBDIR)\graphics
+
+gdevbgi.$(OBJ): gdevbgi.c $(GDEV) $(MAKEFILE) $(gxxfont_h)
+ $(CCC) -DBGI_LIB="$(BGIDIRSTR)" gdevbgi.c
+
+### ------------------- The Hercules Graphics display ------------------- ###
+
+herc_=gdevherc.$(OBJ)
+herc.dev: $(herc_)
+ $(SETDEV) herc $(herc_)
+
+gdevherc.$(OBJ): gdevherc.c $(GDEV) $(dos__h) $(gsmatrix_h) $(gxbitmap_h)
+ $(CCC) gdevherc.c
+
+### ---------------------- The Private Eye display ---------------------- ###
+### Note: this driver was contributed by a user: ###
+### please contact narf@media-lab.media.mit.edu if you have questions. ###
+
+pe_=gdevpe.$(OBJ)
+pe.dev: $(pe_)
+ $(SETDEV) pe $(pe_)
+
+gdevpe.$(OBJ): gdevpe.c $(GDEV) $(memory__h)
+
+###### ----------------------- Other displays ------------------------ ######
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gsdll_h=gsdll.h
+
+gdevmswn_h=gdevmswn.h $(GDEV)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ gp_mswin.h
+
+gdevmswn.$(OBJ): gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h) \
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(CCCWIN) gdevmswn.c
+
+gdevmsxf.$(OBJ): gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCCWIN) gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+gdevwdib.$(OBJ): gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(CCCWIN) gdevwdib.c
+
+mswindll_=gdevmswn.$(OBJ) gdevmsxf.$(OBJ) gdevwdib.$(OBJ) \
+ gdevemap.$(OBJ) gdevpccm.$(OBJ)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=gdevwprn.$(OBJ) gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+gdevwprn.$(OBJ): gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(CCCWIN) gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+gdevwpr2.$(OBJ): gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) gp_mswin.h
+ $(CCCWIN) gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+gdevpm.$(OBJ): gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) gdevpm.h
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+os2prn.$(OBJ): os2prn.c $(gp_h)
+
+### -------------- The AT&T 3b1 Unixpc monochrome display --------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Andy Fyfe (andy@cs.caltech.edu) if you have questions. ###
+
+att3b1_=gdev3b1.$(OBJ)
+att3b1.dev: $(att3b1_)
+ $(SETDEV) att3b1 $(att3b1_)
+
+gdev3b1.$(OBJ): gdev3b1.c $(GDEV)
+
+### ---------------------- Linux PC with vgalib ------------------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the lvga256 driver, please contact ###
+### Ludger Kunz (ludger.kunz@fernuni-hagen.de). ###
+### For questions about the vgalib driver, please contact ###
+### Erik Talvola (talvola@gnu.ai.mit.edu). ###
+
+lvga256_=gdevl256.$(OBJ)
+lvga256.dev: $(lvga256_)
+ $(SETDEV) lvga256 $(lvga256_)
+ $(ADDMOD) lvga256 -lib vga vgagl
+
+gdevl256.$(OBJ): gdevl256.c $(GDEV)
+
+vgalib_=gdevvglb.$(OBJ) gdevpccm.$(OBJ)
+vgalib.dev: $(vgalib_)
+ $(SETDEV) vgalib $(vgalib_)
+ $(ADDMOD) vgalib -lib vga
+
+gdevvglb.$(OBJ): gdevvglb.c $(GDEV) $(gdevpccm_h) $(gsparam_h)
+
+### ------------------- Sony NeWS frame buffer device ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Mike Smolenski (mike@intertech.com) if you have questions. ###
+
+# This is implemented as a 'printer' device.
+sonyfb_=gdevsnfb.$(OBJ)
+sonyfb.dev: $(sonyfb_) page.dev
+ $(SETPDEV) sonyfb $(sonyfb_)
+
+gdevsnfb.$(OBJ): gdevsnfb.c $(PDEVH)
+
+### ------------------------ The SunView device ------------------------ ###
+### Note: this driver is maintained by a user: if you have questions, ###
+### please contact Andreas Stolcke (stolcke@icsi.berkeley.edu). ###
+
+sunview_=gdevsun.$(OBJ)
+sunview.dev: $(sunview_)
+ $(SETDEV) sunview $(sunview_)
+ $(ADDMOD) sunview -lib suntool sunwindow pixrect
+
+gdevsun.$(OBJ): gdevsun.c $(GDEV) $(malloc__h)\
+ $(gscdefs_h) $(gserrors_h) $(gsmatrix_h)
+
+### -------------------------- The X11 device -------------------------- ###
+
+# Aladdin Enterprises does not support Ghostview. For more information
+# about Ghostview, please contact Tim Theisen (ghostview@cs.wisc.edu).
+
+# See the main makefile for the definition of XLIBS.
+x11_=gdevx.$(OBJ) gdevxini.$(OBJ) gdevxxf.$(OBJ) gdevemap.$(OBJ)
+x11.dev: $(x11_)
+ $(SETDEV) x11 $(x11_)
+ $(ADDMOD) x11 -lib $(XLIBS)
+
+# See the main makefile for the definition of XINCLUDE.
+GDEVX=$(GDEV) x_.h gdevx.h $(MAKEFILE)
+gdevx.$(OBJ): gdevx.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevx.c
+
+gdevxini.$(OBJ): gdevxini.c $(GDEVX) $(math__h) $(memory__h) $(gserrors_h)
+ $(CCC) $(XINCLUDE) gdevxini.c
+
+gdevxxf.$(OBJ): gdevxxf.c $(GDEVX) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCC) $(XINCLUDE) gdevxxf.c
+
+# Alternate X11-based devices to help debug other drivers.
+# x11alpha pretends to have 4 bits of alpha channel.
+# x11cmyk pretends to be a CMYK device with 1 bit each of C,M,Y,K.
+# x11gray2 pretends to be a 2-bit gray-scale device.
+# x11mono pretends to be a black-and-white device.
+x11alt_=$(x11_) gdevxalt.$(OBJ)
+x11alpha.dev: $(x11alt_)
+ $(SETDEV) x11alpha $(x11alt_)
+ $(ADDMOD) x11alpha -lib $(XLIBS)
+
+x11cmyk.dev: $(x11alt_)
+ $(SETDEV) x11cmyk $(x11alt_)
+ $(ADDMOD) x11cmyk -lib $(XLIBS)
+
+x11gray2.dev: $(x11alt_)
+ $(SETDEV) x11gray2 $(x11alt_)
+ $(ADDMOD) x11gray2 -lib $(XLIBS)
+
+x11mono.dev: $(x11alt_)
+ $(SETDEV) x11mono $(x11alt_)
+ $(ADDMOD) x11mono -lib $(XLIBS)
+
+gdevxalt.$(OBJ): gdevxalt.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevxalt.c
+
+### ------------------------- DEC sixel displays ------------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Phil Keegstra (keegstra@tonga.gsfc.nasa.gov) if you have questions. ###
+
+# This is a "printer" device, but it probably shouldn't be.
+# I don't know why the implementor chose to do it this way.
+sxlcrt_=gdevln03.$(OBJ)
+sxlcrt.dev: $(sxlcrt_) page.dev
+ $(SETPDEV) sxlcrt $(sxlcrt_)
+
+###### --------------- Memory-buffered printer devices --------------- ######
+
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users. ###
+### If you have questions about the DMP driver, please contact ###
+### Mark Wedel (master@cats.ucsc.edu). ###
+### If you have questions about the Imagewriter drivers, please contact ###
+### Jonathan Luckey (luckey@rtfm.mlb.fl.us). ###
+### If you have questions about the Imagewriter LQ driver, please ###
+### contact Scott Barker (barkers@cuug.ab.ca). ###
+
+appledmp_=gdevadmp.$(OBJ)
+
+gdevadmp.$(OBJ): gdevadmp.c $(PDEVH)
+
+appledmp.dev: $(appledmp_) page.dev
+ $(SETPDEV) appledmp $(appledmp_)
+
+iwhi.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwhi $(appledmp_)
+
+iwlo.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlo $(appledmp_)
+
+iwlq.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlq $(appledmp_)
+
+### ------------ The Canon BubbleJet BJ10e and BJ200 devices ------------ ###
+
+bj10e_=gdevbj10.$(OBJ)
+
+bj10e.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj10e $(bj10e_)
+
+bj200.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj200 $(bj10e_)
+
+gdevbj10.$(OBJ): gdevbj10.c $(PDEVH)
+
+### ------------- The CalComp Raster Format ----------------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Ernst Muellner (ernst.muellner@oenzl.siemens.de) if you have ###
+### questions. ###
+
+ccr_=gdevccr.$(OBJ)
+ccr.dev: $(ccr_) page.dev
+ $(SETPDEV) ccr $(ccr_)
+
+gdevccr.$(OBJ): gdevccr.c $(PDEVH)
+
+### ----------- The H-P DeskJet and LaserJet printer devices ----------- ###
+
+### These are essentially the same device.
+### NOTE: printing at full resolution (300 DPI) requires a printer
+### with at least 1.5 Mb of memory. 150 DPI only requires .5 Mb.
+### Note that the lj4dith driver is included with the H-P color printer
+### drivers below.
+
+HPPCL=gdevpcl.$(OBJ)
+HPMONO=gdevdjet.$(OBJ) $(HPPCL)
+
+gdevpcl.$(OBJ): gdevpcl.c $(PDEVH) $(gdevpcl_h)
+
+gdevdjet.$(OBJ): gdevdjet.c $(PDEVH) $(gdevpcl_h)
+
+deskjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) deskjet $(HPMONO)
+
+djet500.dev: $(HPMONO) page.dev
+ $(SETPDEV) djet500 $(HPMONO)
+
+laserjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) laserjet $(HPMONO)
+
+ljetplus.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljetplus $(HPMONO)
+
+### Selecting ljet2p provides TIFF (mode 2) compression on LaserJet III,
+### IIIp, IIId, IIIsi, IId, and IIp.
+
+ljet2p.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet2p $(HPMONO)
+
+### Selecting ljet3 provides Delta Row (mode 3) compression on LaserJet III,
+### IIIp, IIId, IIIsi.
+
+ljet3.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3 $(HPMONO)
+
+### Selecting ljet3d also provides duplex printing capability.
+
+ljet3d.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3d $(HPMONO)
+
+### Selecting ljet4 also provides Delta Row compression on LaserJet IV series.
+
+ljet4.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet4 $(HPMONO)
+
+lp2563.dev: $(HPMONO) page.dev
+ $(SETPDEV) lp2563 $(HPMONO)
+
+oce9050.dev: $(HPMONO) page.dev
+ $(SETPDEV) oce9050 $(HPMONO)
+
+### ------------------ The H-P LaserJet 5 and 6 devices ----------------- ###
+
+### These drivers use H-P's new PCL XL printer language, like H-P's
+### LaserJet 5 Enhanced driver for MS Windows. We don't recommend using
+### them:
+### - If you have a LJ 5L or 5P, which isn't a "real" LaserJet 5,
+### use the ljet4 driver instead. (The lj5 drivers won't work.)
+### - If you have any other model of LJ 5 or 6, use the pxlmono
+### driver, which often produces much more compact output.
+
+gdevpxat_h=gdevpxat.h
+gdevpxen_h=gdevpxen.h
+gdevpxop_h=gdevpxop.h
+
+ljet5_=gdevlj56.$(OBJ) $(HPPCL)
+lj5mono.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5mono $(ljet5_)
+
+lj5gray.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5gray $(ljet5_)
+
+gdevlj56.$(OBJ): gdevlj56.c $(PDEVH) $(gdevpcl_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h)
+
+### The H-P DeskJet, PaintJet, and DesignJet family color printer devices.###
+### Note: there are two different 500C drivers, both contributed by users.###
+### If you have questions about the djet500c driver, ###
+### please contact AKayser@et.tudelft.nl. ###
+### If you have questions about the cdj* drivers, ###
+### please contact g.cameron@biomed.abdn.ac.uk. ###
+### If you have questions about the dnj560c driver, ###
+### please contact koert@zen.cais.com. ###
+### If you have questions about the lj4dith driver, ###
+### please contact Eckhard.Rueggeberg@ts.go.dlr.de. ###
+### If you have questions about the BJC600/BJC4000, BJC800, or ESCP ###
+### drivers, please contact Yves.Arrouye@imag.fr. ###
+
+cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+cdeskjet.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdeskjet $(cdeskjet_)
+
+cdjcolor.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjcolor $(cdeskjet_)
+
+cdjmono.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjmono $(cdeskjet_)
+
+cdj500.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj500 $(cdeskjet_)
+
+cdj550.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj550 $(cdeskjet_)
+
+declj250.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) declj250 $(cdeskjet_)
+
+dnj650c.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) dnj650c $(cdeskjet_)
+
+lj4dith.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) lj4dith $(cdeskjet_)
+
+pj.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pj $(cdeskjet_)
+
+pjxl.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl $(cdeskjet_)
+
+pjxl300.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl300 $(cdeskjet_)
+
+# Note: the BJC600 driver also works for the BJC4000.
+bjc600.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc600 $(cdeskjet_)
+
+bjc800.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc800 $(cdeskjet_)
+
+escp.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) escp $(cdeskjet_)
+
+# NB: you can also customise the build if required, using
+# -DBitsPerPixel=<number> if you wish the default to be other than 24
+# for the generic drivers (cdj500, cdj550, pjxl300, pjtest, pjxltest).
+gdevcdj.$(OBJ): gdevcdj.c $(std_h) $(PDEVH) gdevbjc.h\
+ $(gsparam_h) $(gsstate_h) $(gxlum_h)\
+ $(gdevpcl_h)
+
+djet500c_=gdevdjtc.$(OBJ) $(HPPCL)
+djet500c.dev: $(djet500c_) page.dev
+ $(SETPDEV) djet500c $(djet500c_)
+
+gdevdjtc.$(OBJ): gdevdjtc.c $(PDEVH) $(malloc__h) $(gdevpcl_h)
+
+### -------------------- The Mitsubishi CP50 printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Michael Hu (michael@ximage.com) if you have questions. ###
+
+cp50_=gdevcp50.$(OBJ)
+cp50.dev: $(cp50_) page.dev
+ $(SETPDEV) cp50 $(cp50_)
+
+gdevcp50.$(OBJ): gdevcp50.c $(PDEVH)
+
+### ----------------- The generic Epson printer device ----------------- ###
+### Note: most of this code was contributed by users. Please contact ###
+### the following people if you have questions: ###
+### eps9mid - Guenther Thomsen (thomsen@cs.tu-berlin.de) ###
+### eps9high - David Wexelblat (dwex@mtgzfs3.att.com) ###
+### ibmpro - James W. Birdsall (jwbirdsa@picarefy.picarefy.com) ###
+
+epson_=gdevepsn.$(OBJ)
+
+epson.dev: $(epson_) page.dev
+ $(SETPDEV) epson $(epson_)
+
+eps9mid.dev: $(epson_) page.dev
+ $(SETPDEV) eps9mid $(epson_)
+
+eps9high.dev: $(epson_) page.dev
+ $(SETPDEV) eps9high $(epson_)
+
+gdevepsn.$(OBJ): gdevepsn.c $(PDEVH)
+
+### ----------------- The IBM Proprinter printer device ---------------- ###
+
+ibmpro.dev: $(epson_) page.dev
+ $(SETPDEV) ibmpro $(epson_)
+
+### -------------- The Epson LQ-2550 color printer device -------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Dave St. Clair (dave@exlog.com) if you have questions. ###
+
+epsonc_=gdevepsc.$(OBJ)
+epsonc.dev: $(epsonc_) page.dev
+ $(SETPDEV) epsonc $(epsonc_)
+
+gdevepsc.$(OBJ): gdevepsc.c $(PDEVH)
+
+### ------------- The Epson ESC/P 2 language printer devices ------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the Stylus 800 and AP3250 drivers, please contact ###
+### Richard Brown (rab@tauon.ph.unimelb.edu.au). ###
+### For questions about the Stylus Color drivers, please contact ###
+### Gunther Hess (gunther@elmos.de). ###
+
+ESCP2=gdevescp.$(OBJ)
+
+gdevescp.$(OBJ): gdevescp.c $(PDEVH)
+
+ap3250.dev: $(ESCP2) page.dev
+ $(SETPDEV) ap3250 $(ESCP2)
+
+st800.dev: $(ESCP2) page.dev
+ $(SETPDEV) st800 $(ESCP2)
+
+stcolor1_=gdevstc.$(OBJ) gdevstc1.$(OBJ) gdevstc2.$(OBJ)
+stcolor2_=gdevstc3.$(OBJ) gdevstc4.$(OBJ)
+stcolor.dev: $(stcolor1_) $(stcolor2_) page.dev
+ $(SETPDEV) stcolor $(stcolor1_)
+ $(ADDMOD) stcolor -obj $(stcolor2_)
+
+gdevstc.$(OBJ): gdevstc.c gdevstc.h $(PDEVH)
+
+gdevstc1.$(OBJ): gdevstc1.c gdevstc.h $(PDEVH)
+
+gdevstc2.$(OBJ): gdevstc2.c gdevstc.h $(PDEVH)
+
+gdevstc3.$(OBJ): gdevstc3.c gdevstc.h $(PDEVH)
+
+gdevstc4.$(OBJ): gdevstc4.c gdevstc.h $(PDEVH)
+
+### --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+### For questions about this driver, please contact: ###
+### Gunther Hess (gunther@elmos.de) ###
+
+uniprint_=gdevupd.$(OBJ)
+uniprint.dev: $(uniprint_) page.dev
+ $(SETPDEV) uniprint $(uniprint_)
+
+gdevupd.$(OBJ): gdevupd.c $(PDEVH) $(gsparam_h)
+
+### -------------- cdj850 - HP 850c Driver under development ------------- ###
+### Since this driver is in the development-phase it is not distributed ###
+### with ghostscript, but it is available via anonymous ftp from: ###
+### ftp://bonk.ethz.ch ###
+### For questions about this driver, please contact: ###
+### Uli Wortmann (E-Mail address inside the driver-package) ###
+
+cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+cdj850.dev: $(cdeskjet8_) page.dev
+ $(SETPDEV) cdj850 $(cdeskjet8_)
+
+### ------------ The H-P PaintJet color printer device ----------------- ###
+### Note: this driver also supports the DEC LJ250 color printer, which ###
+### has a PaintJet-compatible mode, and the PaintJet XL. ###
+### If you have questions about the XL, please contact Rob Reiss ###
+### (rob@moray.berkeley.edu). ###
+
+PJET=gdevpjet.$(OBJ) $(HPPCL)
+
+gdevpjet.$(OBJ): gdevpjet.c $(PDEVH) $(gdevpcl_h)
+
+lj250.dev: $(PJET) page.dev
+ $(SETPDEV) lj250 $(PJET)
+
+paintjet.dev: $(PJET) page.dev
+ $(SETPDEV) paintjet $(PJET)
+
+pjetxl.dev: $(PJET) page.dev
+ $(SETPDEV) pjetxl $(PJET)
+
+### -------------- Imagen ImPress Laser Printer device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Alan Millar (AMillar@bolis.sf-bay.org) if you have questions. ###
+### Set USE_BYTE_STREAM if using parallel interface; ###
+### Don't set it if using 'ipr' spooler (default). ###
+### You may also add -DA4 if needed for A4 paper. ###
+
+imagen_=gdevimgn.$(OBJ)
+imagen.dev: $(imagen_) page.dev
+ $(SETPDEV) imagen $(imagen_)
+
+gdevimgn.$(OBJ): gdevimgn.c $(PDEVH)
+ $(CCC) gdevimgn.c # for ipr spooler
+# $(CCC) -DUSE_BYTE_STREAM gdevimgn.c # for parallel
+
+### ------- The IBM 3852 JetPrinter color inkjet printer device -------- ###
+### Note: this driver was contributed by users: please contact ###
+### Kevin Gift (kgift@draper.com) if you have questions. ###
+### Note that the paper size that can be addressed by the graphics mode ###
+### used in this driver is fixed at 7-1/2 inches wide (the printable ###
+### width of the jetprinter itself.) ###
+
+jetp3852_=gdev3852.$(OBJ)
+jetp3852.dev: $(jetp3852_) page.dev
+ $(SETPDEV) jetp3852 $(jetp3852_)
+
+gdev3852.$(OBJ): gdev3852.c $(PDEVH) $(gdevpcl_h)
+
+### ---------- The Canon LBP-8II and LIPS III printer devices ---------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about these drivers, please contact ###
+### Lauri Paatero, lauri.paatero@paatero.pp.fi ###
+
+lbp8_=gdevlbp8.$(OBJ)
+lbp8.dev: $(lbp8_) page.dev
+ $(SETPDEV) lbp8 $(lbp8_)
+
+lips3.dev: $(lbp8_) page.dev
+ $(SETPDEV) lips3 $(lbp8_)
+
+gdevlbp8.$(OBJ): gdevlbp8.c $(PDEVH)
+
+### ----------- The DEC LN03/LA50/LA70/LA75 printer devices ------------ ###
+### Note: this driver was contributed by users: please contact ###
+### Ulrich Mueller (ulm@vsnhd1.cern.ch) if you have questions. ###
+### For questions about LA50 and LA75, please contact ###
+### Ian MacPhedran (macphed@dvinci.USask.CA). ###
+### For questions about the LA70, please contact ###
+### Bruce Lowekamp (lowekamp@csugrad.cs.vt.edu). ###
+### For questions about the LA75plus, please contact ###
+### Andre' Beck (Andre_Beck@IRS.Inf.TU-Dresden.de). ###
+
+ln03_=gdevln03.$(OBJ)
+ln03.dev: $(ln03_) page.dev
+ $(SETPDEV) ln03 $(ln03_)
+
+la50.dev: $(ln03_) page.dev
+ $(SETPDEV) la50 $(ln03_)
+
+la70.dev: $(ln03_) page.dev
+ $(SETPDEV) la70 $(ln03_)
+
+la75.dev: $(ln03_) page.dev
+ $(SETPDEV) la75 $(ln03_)
+
+la75plus.dev: $(ln03_) page.dev
+ $(SETPDEV) la75plus $(ln03_)
+
+gdevln03.$(OBJ): gdevln03.c $(PDEVH)
+
+# LA70 driver with low-resolution text enhancement.
+
+la70t_=gdevla7t.$(OBJ)
+la70t.dev: $(la70t_) page.dev
+ $(SETPDEV) la70t $(la70t_)
+
+gdevla7t.$(OBJ): gdevla7t.c $(PDEVH)
+
+### -------------- The Epson LP-8000 laser printer device -------------- ###
+### Note: this driver was contributed by a user: please contact Oleg ###
+### Oleg Fat'yanov <faty1@rlem.titech.ac.jp> if you have questions.###
+
+lp8000_=gdevlp8k.$(OBJ)
+lp8000.dev: $(lp8000_) page.dev
+ $(SETPDEV) lp8000 $(lp8000_)
+
+gdevlp8k.$(OBJ): gdevlp8k.c $(PDEVH)
+
+### -------------- The C.Itoh M8510 printer device --------------------- ###
+### Note: this driver was contributed by a user: please contact Bob ###
+### Smith <bob@snuffy.penfield.ny.us> if you have questions. ###
+
+m8510_=gdev8510.$(OBJ)
+m8510.dev: $(m8510_) page.dev
+ $(SETPDEV) m8510 $(m8510_)
+
+gdev8510.$(OBJ): gdev8510.c $(PDEVH)
+
+### -------------- 24pin Dot-matrix printer with 360DPI ---------------- ###
+### Note: this driver was contributed by users. Please contact: ###
+### Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) for ###
+### questions about the NEC P6; ###
+### Christian Felsch (felsch@tu-harburg.d400.de) for ###
+### questions about the Epson LQ850. ###
+
+dm24_=gdevdm24.$(OBJ)
+gdevdm24.$(OBJ): gdevdm24.c $(PDEVH)
+
+necp6.dev: $(dm24_) page.dev
+ $(SETPDEV) necp6 $(dm24_)
+
+lq850.dev: $(dm24_) page.dev
+ $(SETPDEV) lq850 $(dm24_)
+
+### ----------------- The Okidata MicroLine 182 device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Maarten Koning (smeg@bnr.ca) if you have questions. ###
+
+oki182_=gdevo182.$(OBJ)
+oki182.dev: $(oki182_) page.dev
+ $(SETPDEV) oki182 $(oki182_)
+
+gdevo182.$(OBJ): gdevo182.c $(PDEVH)
+
+### ------------- The Okidata IBM compatible printer device ------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Charles Mack (chasm@netcom.com) if you have questions. ###
+
+okiibm_=gdevokii.$(OBJ)
+okiibm.dev: $(okiibm_) page.dev
+ $(SETPDEV) okiibm $(okiibm_)
+
+gdevokii.$(OBJ): gdevokii.c $(PDEVH)
+
+### ------------- The Ricoh 4081 laser printer device ------------------ ###
+### Note: this driver was contributed by users: ###
+### please contact kdw@oasis.icl.co.uk if you have questions. ###
+
+r4081_=gdev4081.$(OBJ)
+r4081.dev: $(r4081_) page.dev
+ $(SETPDEV) r4081 $(r4081_)
+
+
+gdev4081.$(OBJ): gdev4081.c $(PDEVH)
+
+### -------------------- Sony NWP533 printer device -------------------- ###
+### Note: this driver was contributed by a user: please contact Tero ###
+### Kivinen (kivinen@joker.cs.hut.fi) if you have questions. ###
+
+nwp533_=gdevn533.$(OBJ)
+nwp533.dev: $(nwp533_) page.dev
+ $(SETPDEV) nwp533 $(nwp533_)
+
+gdevn533.$(OBJ): gdevn533.c $(PDEVH)
+
+### ------------------------- The SPARCprinter ------------------------- ###
+### Note: this driver was contributed by users: please contact Martin ###
+### Schulte (schulte@thp.uni-koeln.de) if you have questions. ###
+### He would also like to hear from anyone using the driver. ###
+### Please consult the source code for additional documentation. ###
+
+sparc_=gdevsppr.$(OBJ)
+sparc.dev: $(sparc_) page.dev
+ $(SETPDEV) sparc $(sparc_)
+
+gdevsppr.$(OBJ): gdevsppr.c $(PDEVH)
+
+### ----------------- The StarJet SJ48 device -------------------------- ###
+### Note: this driver was contributed by a user: if you have questions, ###
+### . ###
+### please contact Mats Akerblom (f86ma@dd.chalmers.se). ###
+
+sj48_=gdevsj48.$(OBJ)
+sj48.dev: $(sj48_) page.dev
+ $(SETPDEV) sj48 $(sj48_)
+
+gdevsj48.$(OBJ): gdevsj48.c $(PDEVH)
+
+### ----------------- Tektronix 4396d color printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karl Hakimian (hakimian@haney.eecs.wsu.edu) ###
+### if you have questions. ###
+
+t4693d_=gdev4693.$(OBJ)
+t4693d2.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d2 $(t4693d_)
+
+t4693d4.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d4 $(t4693d_)
+
+t4693d8.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d8 $(t4693d_)
+
+gdev4693.$(OBJ): gdev4693.c $(PDEVH)
+
+### -------------------- Tektronix ink-jet printers -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karsten Spang (spang@nbivax.nbi.dk) if you have questions. ###
+
+tek4696_=gdevtknk.$(OBJ)
+tek4696.dev: $(tek4696_) page.dev
+ $(SETPDEV) tek4696 $(tek4696_)
+
+gdevtknk.$(OBJ): gdevtknk.c $(PDEVH) $(malloc__h)
+
+### ----------------- The Xerox XES printer device --------------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Peter Flass (flass@lbdrscs.bitnet) if you have questions. ###
+
+xes_=gdevxes.$(OBJ)
+xes.dev: $(xes_) page.dev
+ $(SETPDEV) xes $(xes_)
+
+gdevxes.$(OBJ): gdevxes.c $(PDEVH)
+
+###### ------------------------- Fax devices ------------------------- ######
+
+### --------------- Generic PostScript system compatible fax ------------ ###
+
+# This code doesn't work yet. Don't even think about using it.
+
+PSFAX=gdevpfax.$(OBJ)
+
+psfax_=$(PSFAX)
+psfax.dev: $(psfax_) page.dev
+ $(SETPDEV) psfax $(psfax_)
+ $(ADDMOD) psfax -iodev Fax
+
+gdevpfax.$(OBJ): gdevpfax.c $(PDEVH) $(gsparam_h) $(gxiodev_h)
+
+### ------------------------- The DigiFAX device ------------------------ ###
+### This driver outputs images in a format suitable for use with ###
+### DigiBoard, Inc.'s DigiFAX software. Use -sDEVICE=dfaxhigh for ###
+### high resolution output, -sDEVICE=dfaxlow for normal output. ###
+### Note: this driver was contributed by a user: please contact ###
+### Rick Richardson (rick@digibd.com) if you have questions. ###
+
+dfax_=gdevdfax.$(OBJ) gdevtfax.$(OBJ)
+
+dfaxlow.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxlow $(dfax_)
+ $(ADDMOD) dfaxlow -include cfe
+
+dfaxhigh.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxhigh $(dfax_)
+ $(ADDMOD) dfaxhigh -include cfe
+
+gdevdfax.$(OBJ): gdevdfax.c $(PDEVH) $(scfx_h) $(strimpl_h)
+
+### --------------See under TIFF below for fax-format TIFF -------------- ###
+
+###### ------------------- High-level file formats ------------------- ######
+
+# Support for PostScript and PDF
+
+gdevpsdf_h=gdevpsdf.h $(gdevvec_h) $(strimpl_h)
+gdevpstr_h=gdevpstr.h
+
+gdevpsdf.$(OBJ): gdevpsdf.c $(stdio__h) $(string__h)\
+ $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsparam_h) $(gstypes_h)\
+ $(gxdevice_h)\
+ $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpstr.$(OBJ): gdevpstr.c $(math__h) $(stdio__h) $(string__h)\
+ $(gdevpstr_h) $(stream_h)
+
+# PostScript and EPS writers
+
+pswrite1_=gdevps.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pswrite2_=scantab.$(OBJ) sfilter2.$(OBJ)
+pswrite_=$(pswrite1_) $(pswrite2_)
+epswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) epswrite $(pswrite1_)
+ $(ADDMOD) epswrite $(pswrite2_)
+ $(ADDMOD) epswrite -include vector
+
+pswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) pswrite $(pswrite1_)
+ $(ADDMOD) pswrite $(pswrite2_)
+ $(ADDMOD) pswrite -include vector
+
+gdevps.$(OBJ): gdevps.c $(GDEV) $(math__h) $(time__h)\
+ $(gscdefs_h) $(gscspace_h) $(gsparam_h) $(gsiparam_h) $(gsmatrix_h)\
+ $(gxdcolor_h)\
+ $(sa85x_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+# PDF writer
+# Note that gs_pdfwr.ps will only actually be loaded if the configuration
+# includes a PostScript interpreter.
+
+pdfwrite1_=gdevpdf.$(OBJ) gdevpdfd.$(OBJ) gdevpdfi.$(OBJ) gdevpdfm.$(OBJ)
+pdfwrite2_=gdevpdfp.$(OBJ) gdevpdft.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pdfwrite3_=gsflip.$(OBJ) scantab.$(OBJ) sfilter2.$(OBJ) sstring.$(OBJ)
+pdfwrite_=$(pdfwrite1_) $(pdfwrite2_) $(pdfwrite3_)
+pdfwrite.dev: $(ECHOGS_XE) $(pdfwrite_) \
+ cmyklib.dev cfe.dev dcte.dev lzwe.dev rle.dev vector.dev
+ $(SETDEV) pdfwrite $(pdfwrite1_)
+ $(ADDMOD) pdfwrite $(pdfwrite2_)
+ $(ADDMOD) pdfwrite $(pdfwrite3_)
+ $(ADDMOD) pdfwrite -ps gs_pdfwr
+ $(ADDMOD) pdfwrite -include cmyklib cfe dcte lzwe rle vector
+
+gdevpdfx_h=gdevpdfx.h $(gsparam_h) $(gxdevice_h) $(gxline_h) $(stream_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpdf.$(OBJ): gdevpdf.c $(math__h) $(memory__h) $(string__h) $(time__h)\
+ $(gp_h)\
+ $(gdevpdfx_h) $(gscdefs_h) $(gserrors_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)\
+ $(scanchar_h) $(scfx_h) $(slzwx_h) $(sstring_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) gdevpdf.c
+
+gdevpdfd.$(OBJ): gdevpdfd.c $(math__h)\
+ $(gdevpdfx_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+gdevpdfi.$(OBJ): gdevpdfi.c $(math__h) $(memory__h) $(gx_h) \
+ $(gdevpdfx_h) $(gscie_h) $(gscolor2_h) $(gserrors_h) $(gsflip_h)\
+ $(gxcspace_h) $(gxistate_h) \
+ $(sa85x_h) $(scfx_h) $(srlx_h) $(strimpl_h)
+
+gdevpdfm.$(OBJ): gdevpdfm.c $(memory__h) $(string__h) $(gx_h) \
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h) $(scanchar_h)
+
+gdevpdfp.$(OBJ): gdevpdfp.c $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h)
+
+gdevpdft.$(OBJ): gdevpdft.c $(math__h) $(memory__h) $(string__h) $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h)\
+ $(scommon_h)
+
+# High-level PCL XL writer
+
+pxl_=gdevpx.$(OBJ)
+pxlmono.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlmono $(pxl_)
+ $(ADDMOD) pxlmono -include vector
+
+pxlcolor.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlcolor $(pxl_)
+ $(ADDMOD) pxlcolor -include vector
+
+gdevpx.$(OBJ): gdevpx.c $(math__h) $(memory__h) $(string__h)\
+ $(gx_h) $(gsccolor_h) $(gsdcolor_h) $(gserrors_h)\
+ $(gxcspace_h) $(gxdevice_h) $(gxpath_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h) $(gdevvec_h)\
+ $(srlx_h) $(strimpl_h)
+
+###### --------------------- Raster file formats --------------------- ######
+
+### --------------------- The "plain bits" devices ---------------------- ###
+
+bit_=gdevbit.$(OBJ)
+
+bit.dev: $(bit_) page.dev
+ $(SETPDEV) bit $(bit_)
+
+bitrgb.dev: $(bit_) page.dev
+ $(SETPDEV) bitrgb $(bit_)
+
+bitcmyk.dev: $(bit_) page.dev
+ $(SETPDEV) bitcmyk $(bit_)
+
+gdevbit.$(OBJ): gdevbit.c $(PDEVH) $(gsparam_h) $(gxlum_h)
+
+### ------------------------- .BMP file formats ------------------------- ###
+
+bmp_=gdevbmp.$(OBJ) gdevpccm.$(OBJ)
+
+gdevbmp.$(OBJ): gdevbmp.c $(PDEVH) $(gdevpccm_h)
+
+bmpmono.dev: $(bmp_) page.dev
+ $(SETPDEV) bmpmono $(bmp_)
+
+bmp16.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16 $(bmp_)
+
+bmp256.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp256 $(bmp_)
+
+bmp16m.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16m $(bmp_)
+
+### ------------- BMP driver that serves as demo of async rendering ---- ###
+devasync_=gdevasyn.$(OBJ) gdevpccm.$(OBJ) gxsync.$(OBJ)
+
+gdevasyn.$(OBJ): gdevasyn.c $(AK) $(stdio__h) $(gdevprna_h) $(gdevpccm_h)\
+ $(gserrors_h) $(gpsync_h)
+
+asynmono.dev: $(devasync_) page.dev async.dev
+ $(SETPDEV) asynmono $(devasync_)
+ $(ADDMOD) asynmono -include async
+
+
+### -------------------------- CGM file format ------------------------- ###
+### This driver is under development. Use at your own risk. ###
+### The output is very low-level, consisting only of rectangles and ###
+### cell arrays. ###
+
+cgm_=gdevcgm.$(OBJ) gdevcgml.$(OBJ)
+
+gdevcgml_h=gdevcgml.h
+gdevcgmx_h=gdevcgmx.h $(gdevcgml_h)
+
+gdevcgm.$(OBJ): gdevcgm.c $(GDEV) $(memory__h)\
+ $(gsparam_h) $(gdevpccm_h) $(gdevcgml_h)
+
+gdevcgml.$(OBJ): gdevcgml.c $(memory__h) $(stdio__h)\
+ $(gdevcgmx_h)
+
+cgmmono.dev: $(cgm_)
+ $(SETDEV) cgmmono $(cgm_)
+
+cgm8.dev: $(cgm_)
+ $(SETDEV) cgm8 $(cgm_)
+
+cgm24.dev: $(cgm_)
+ $(SETDEV) cgm24 $(cgm_)
+
+### -------------------- The CIF file format for VLSI ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Frederic Petrot (petrot@masi.ibp.fr) if you have questions. ###
+
+cif_=gdevcif.$(OBJ)
+cif.dev: $(cif_) page.dev
+ $(SETPDEV) cif $(cif_)
+
+gdevcif.$(OBJ): gdevcif.c $(PDEVH)
+
+### ------------------------- JPEG file format ------------------------- ###
+
+jpeg_=gdevjpeg.$(OBJ)
+
+# RGB output
+jpeg.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeg $(jpeg_)
+ $(ADDMOD) jpeg -include sdcte
+
+# Gray output
+jpeggray.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeggray $(jpeg_)
+ $(ADDMOD) jpeggray -include sdcte
+
+gdevjpeg.$(OBJ): gdevjpeg.c $(stdio__h) $(PDEVH)\
+ $(sdct_h) $(sjpeg_h) $(stream_h) $(strimpl_h) jpeglib.h
+
+### ------------------------- MIFF file format ------------------------- ###
+### Right now we support only 24-bit direct color, but we might add more ###
+### formats in the future. ###
+
+miff_=gdevmiff.$(OBJ)
+
+miff24.dev: $(miff_) page.dev
+ $(SETPDEV) miff24 $(miff_)
+
+gdevmiff.$(OBJ): gdevmiff.c $(PDEVH)
+
+### --------------------------- MGR devices ---------------------------- ###
+### Note: these drivers were contributed by a user: please contact ###
+### Carsten Emde (carsten@ce.pr.net.ch) if you have questions. ###
+
+MGR=gdevmgr.$(OBJ) gdevpccm.$(OBJ)
+
+gdevmgr.$(OBJ): gdevmgr.c $(PDEVH) $(gdevpccm_h) gdevmgr.h
+
+mgrmono.dev: $(MGR) page.dev
+ $(SETPDEV) mgrmono $(MGR)
+
+mgrgray2.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray2 $(MGR)
+
+mgrgray4.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray4 $(MGR)
+
+mgrgray8.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray8 $(MGR)
+
+mgr4.dev: $(MGR) page.dev
+ $(SETPDEV) mgr4 $(MGR)
+
+mgr8.dev: $(MGR) page.dev
+ $(SETPDEV) mgr8 $(MGR)
+
+### ------------------------- PCX file formats ------------------------- ###
+
+pcx_=gdevpcx.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpcx.$(OBJ): gdevpcx.c $(PDEVH) $(gdevpccm_h) $(gxlum_h)
+
+pcxmono.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxmono $(pcx_)
+
+pcxgray.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxgray $(pcx_)
+
+pcx16.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx16 $(pcx_)
+
+pcx256.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx256 $(pcx_)
+
+pcx24b.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx24b $(pcx_)
+
+pcxcmyk.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxcmyk $(pcx_)
+
+# The 2-up PCX device is here only as an example, and for testing.
+pcx2up.dev: $(LIB_MAK) $(ECHOGS_XE) gdevp2up.$(OBJ) page.dev pcx256.dev
+ $(SETPDEV) pcx2up gdevp2up.$(OBJ)
+ $(ADDMOD) pcx2up -include pcx256
+
+gdevp2up.$(OBJ): gdevp2up.c $(AK)\
+ $(gdevpccm_h) $(gdevprn_h) $(gxclpage_h)
+
+### ------------------- Portable Bitmap file formats ------------------- ###
+### For more information, see the pbm(5), pgm(5), and ppm(5) man pages. ###
+
+pxm_=gdevpbm.$(OBJ)
+
+gdevpbm.$(OBJ): gdevpbm.c $(PDEVH) $(gscdefs_h) $(gxlum_h)
+
+### Portable Bitmap (PBM, plain or raw format, magic numbers "P1" or "P4")
+
+pbm.dev: $(pxm_) page.dev
+ $(SETPDEV) pbm $(pxm_)
+
+pbmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pbmraw $(pxm_)
+
+### Portable Graymap (PGM, plain or raw format, magic numbers "P2" or "P5")
+
+pgm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgm $(pxm_)
+
+pgmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgmraw $(pxm_)
+
+# PGM with automatic optimization to PBM if this is possible.
+
+pgnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnm $(pxm_)
+
+pgnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnmraw $(pxm_)
+
+### Portable Pixmap (PPM, plain or raw format, magic numbers "P3" or "P6")
+
+ppm.dev: $(pxm_) page.dev
+ $(SETPDEV) ppm $(pxm_)
+
+ppmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) ppmraw $(pxm_)
+
+# PPM with automatic optimization to PGM or PBM if possible.
+
+pnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pnm $(pxm_)
+
+pnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pnmraw $(pxm_)
+
+### Portable inKmap (CMYK internally, converted to PPM=RGB at output time)
+
+pkm.dev: $(pxm_) page.dev
+ $(SETPDEV) pkm $(pxm_)
+
+pkmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pkmraw $(pxm_)
+
+### --------------- Portable Network Graphics file format --------------- ###
+### Requires libpng 0.81 and zlib 0.95 (or more recent versions). ###
+### See libpng.mak and zlib.mak for more details. ###
+
+png_=gdevpng.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpng.$(OBJ): gdevpng.c $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(PSRC)png.h
+ $(CCCP) gdevpng.c
+
+pngmono.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pngmono $(png_)
+ $(ADDMOD) pngmono -include libpng
+
+pnggray.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pnggray $(png_)
+ $(ADDMOD) pnggray -include libpng
+
+png16.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16 $(png_)
+ $(ADDMOD) png16 -include libpng
+
+png256.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png256 $(png_)
+ $(ADDMOD) png256 -include libpng
+
+png16m.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16m $(png_)
+ $(ADDMOD) png16m -include libpng
+
+### ---------------------- PostScript image format ---------------------- ###
+### These devices make it possible to print Level 2 files on a Level 1 ###
+### printer, by converting them to a bitmap in PostScript format. ###
+
+ps_=gdevpsim.$(OBJ)
+
+gdevpsim.$(OBJ): gdevpsim.c $(PDEVH)
+
+psmono.dev: $(ps_) page.dev
+ $(SETPDEV) psmono $(ps_)
+
+psgray.dev: $(ps_) page.dev
+ $(SETPDEV) psgray $(ps_)
+
+# Someday there will be RGB and CMYK variants....
+
+### -------------------------- SGI RGB pixmaps -------------------------- ###
+
+sgirgb_=gdevsgi.$(OBJ)
+
+gdevsgi.$(OBJ): gdevsgi.c $(PDEVH) gdevsgi.h
+
+sgirgb.dev: $(sgirgb_) page.dev
+ $(SETPDEV) sgirgb $(sgirgb_)
+
+### -------------------- Plain or TIFF fax encoding --------------------- ###
+### Use -sDEVICE=tiffg3 or tiffg4 and ###
+### -r204x98 for low resolution output, or ###
+### -r204x196 for high resolution output ###
+### These drivers recognize 3 page sizes: letter, A4, and B4. ###
+
+gdevtifs_h=gdevtifs.h
+
+tfax_=gdevtfax.$(OBJ)
+tfax.dev: $(tfax_) cfe.dev lzwe.dev rle.dev tiffs.dev
+ $(SETMOD) tfax $(tfax_)
+ $(ADDMOD) tfax -include cfe lzwe rle tiffs
+
+gdevtfax.$(OBJ): gdevtfax.c $(PDEVH)\
+ $(gdevtifs_h) $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)
+
+### Plain G3/G4 fax with no header
+
+faxg3.dev: tfax.dev
+ $(SETDEV) faxg3 -include tfax
+
+faxg32d.dev: tfax.dev
+ $(SETDEV) faxg32d -include tfax
+
+faxg4.dev: tfax.dev
+ $(SETDEV) faxg4 -include tfax
+
+### ---------------------------- TIFF formats --------------------------- ###
+
+tiffs_=gdevtifs.$(OBJ)
+tiffs.dev: $(tiffs_) page.dev
+ $(SETMOD) tiffs $(tiffs_)
+ $(ADDMOD) tiffs -include page
+
+gdevtifs.$(OBJ): gdevtifs.c $(PDEVH) $(stdio__h) $(time__h) \
+ $(gdevtifs_h) $(gscdefs_h) $(gstypes_h)
+
+# Black & white, G3/G4 fax
+
+tiffcrle.dev: tfax.dev
+ $(SETDEV) tiffcrle -include tfax
+
+tiffg3.dev: tfax.dev
+ $(SETDEV) tiffg3 -include tfax
+
+tiffg32d.dev: tfax.dev
+ $(SETDEV) tiffg32d -include tfax
+
+tiffg4.dev: tfax.dev
+ $(SETDEV) tiffg4 -include tfax
+
+# Black & white, LZW compression
+
+tifflzw.dev: tfax.dev
+ $(SETDEV) tifflzw -include tfax
+
+# Black & white, PackBits compression
+
+tiffpack.dev: tfax.dev
+ $(SETDEV) tiffpack -include tfax
+
+# RGB, no compression
+
+tiffrgb_=gdevtfnx.$(OBJ)
+
+tiff12nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff12nc $(tiffrgb_)
+ $(ADDMOD) tiff12nc -include tiffs
+
+tiff24nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff24nc $(tiffrgb_)
+ $(ADDMOD) tiff24nc -include tiffs
+
+gdevtfnx.$(OBJ): gdevtfnx.c $(PDEVH) $(gdevtifs_h)
+# Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This is the last part of the makefile for Unix configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define the name of this makefile.
+UNIXTAIL_MAK=unixtail.mak
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Unix platforms
+
+# We have to include a test for the existence of sys/time.h,
+# because some System V platforms don't have it.
+
+# Define pipes as a separable feature.
+
+pipe_=gdevpipe.$(OBJ)
+pipe.dev: $(UNIXTAIL_MAK) $(ECHOGS_XE) $(pipe_)
+ $(SETMOD) pipe $(pipe_)
+ $(ADDMOD) pipe -iodev pipe
+
+gdevpipe.$(OBJ): gdevpipe.c $(AK) $(errno__h) $(stdio__h) $(string__h) \
+ $(gserror_h) $(gsmemory_h) $(gstypes_h) $(gxiodev_h) $(stream_h)
+
+# Unix platforms other than System V, and also System V Release 4
+# (SVR4) platforms.
+unix__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ)
+unix_.dev: $(unix__)
+ $(SETMOD) unix_ $(unix__)
+
+gp_unix.$(OBJ): gp_unix.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h)
+
+# System V platforms other than SVR4, which lack some system calls,
+# but have pipes.
+sysv__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ) gp_sysv.$(OBJ)
+sysv_.dev: $(sysv__)
+ $(SETMOD) sysv_ $(sysv__)
+
+gp_sysv.$(OBJ): gp_sysv.c $(stdio__h) $(time__h) $(AK)
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c
+ $(CCA2K) $(O)$(ANSI2KNR_XE) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c $(AK)
+ $(CCAUX) $(O)$(ECHOGS_XE) echogs.c
+
+# On the RS/6000 (at least), compiling genarch.c with gcc with -O
+# produces a buggy executable.
+$(GENARCH_XE): genarch.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENARCH_XE) genarch.c
+
+$(GENCONF_XE): genconf.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENCONF_XE) genconf.c
+
+$(GENINIT_XE): geninit.c $(AK) $(stdio__h) $(string__h)
+ $(CCAUX) $(O)$(GENINIT_XE) geninit.c
+
+# Query the environment to construct gconfig_.h.
+# The "else true; is required because Ultrix's implementation of sh -e
+# terminates execution of a command if any error occurs, even if the command
+# traps the error with ||.
+INCLUDE=/usr/include
+gconfig_.h: $(UNIXTAIL_MAK) $(ECHOGS_XE)
+ ./echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ if ( test -f $(INCLUDE)/dirent.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H; else true; fi
+ if ( test -f $(INCLUDE)/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/dir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_DIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/time.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/times.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIMES_H; else true; fi
+
+# ----------------------------- Main program ------------------------------ #
+
+### Library files and archive
+
+LIB_ARCHIVE_ALL=$(LIB_ALL) $(DEVS_ALL)\
+ gsnogc.$(OBJ) gconfig.$(OBJ) gscdefs.$(OBJ)
+
+# Build an archive for the library only.
+# This is not used in a standard build.
+GSLIB_A=$(GS)lib.a
+$(GSLIB_A): $(LIB_ARCHIVE_ALL)
+ rm -f $(GSLIB_A)
+ $(AR) $(ARFLAGS) $(GSLIB_A) $(LIB_ARCHIVE_ALL)
+ $(RANLIB) $(GSLIB_A)
+
+### Interpreter main program
+
+INT_ARCHIVE_ALL=imainarg.$(OBJ) imain.$(OBJ) $(INT_ALL) $(DEVS_ALL)\
+ gconfig.$(OBJ) gscdefs.$(OBJ)
+XE_ALL=gs.$(OBJ) $(INT_ARCHIVE_ALL)
+
+# Build a library archive for the entire interpreter.
+# This is not used in a standard build.
+GS_A=$(GS).a
+$(GS_A): $(INT_ARCHIVE_ALL)
+ rm -f $(GS_A)
+ $(AR) $(ARFLAGS) $(GS_A) $(INT_ARCHIVE_ALL)
+ $(RANLIB) $(GS_A)
+
+# Here is the final link step. The stuff with LD_RUN_PATH is for SVR4
+# systems with dynamic library loading; I believe it's harmless elsewhere.
+# The resetting of the environment variables to empty strings is for SCO Unix,
+# which has limited environment space.
+$(GS_XE): ld.tr echogs $(XE_ALL)
+ ./echogs -w ldt.tr -n - $(CCLD) $(LDFLAGS) $(XLIBDIRS) -o $(GS_XE)
+ ./echogs -a ldt.tr -n -s gs.$(OBJ) -s
+ cat ld.tr >>ldt.tr
+ ./echogs -a ldt.tr -s - $(EXTRALIBS) -lm
+ LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; \
+ XCFLAGS= XINCLUDE= XLDFLAGS= XLIBDIRS= XLIBS= \
+ FEATURE_DEVS= DEVICE_DEVS= DEVICE_DEVS1= DEVICE_DEVS2= DEVICE_DEVS3= \
+ DEVICE_DEVS4= DEVICE_DEVS5= DEVICE_DEVS6= DEVICE_DEVS7= DEVICE_DEVS8= \
+ DEVICE_DEVS9= DEVICE_DEVS10= DEVICE_DEVS11= DEVICE_DEVS12= \
+ DEVICE_DEVS13= DEVICE_DEVS14= DEVICE_DEVS15= \
+ $(SH) <ldt.tr
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix and Desqview/X configurations.
+
+# This is the very last part of the makefile for these configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define a rule for building profiling configurations.
+pg:
+ make GENOPT='' CFLAGS='-pg -O $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+# Define a rule for building debugging configurations.
+debug:
+ make GENOPT='-DDEBUG' CFLAGS='-g -O $(GCFLAGS) $(XCFLAGS)'
+
+# The rule for gconfigv.h is here because it is shared between Unix and
+# DV/X environments.
+gconfigv.h: unix-end.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# The following rules are equivalent to what tar_cat does.
+# The rm -f is so that we don't overwrite a file that `make'
+# may currently be reading from.
+GENERIC_MAK_LIST=$(GS_MAK) $(LIB_MAK) $(INT_MAK) $(JPEG_MAK) $(LIBPNG_MAK) $(ZLIB_MAK) $(DEVS_MAK)
+UNIX_MAK_LIST=dvx-gcc.mak unixansi.mak unix-cc.mak unix-gcc.mak
+
+unix.mak: $(UNIX_MAK_LIST)
+
+DVX_GCC_MAK=$(VERSION_MAK) dgc-head.mak dvx-head.mak $(GENERIC_MAK_LIST) dvx-tail.mak unix-end.mak
+dvx-gcc.mak: $(DVX_GCC_MAK)
+ rm -f dvx-gcc.mak
+ $(CAT) $(DVX_GCC_MAK) >dvx-gcc.mak
+
+UNIXANSI_MAK=$(VERSION_MAK) ansihead.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unixansi.mak: $(UNIXANSI_MAK)
+ rm -f unixansi.mak
+ $(CAT) $(UNIXANSI_MAK) >unixansi.mak
+
+UNIX_CC_MAK=$(VERSION_MAK) cc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-cc.mak: $(UNIX_CC_MAK)
+ rm -f unix-cc.mak
+ $(CAT) $(UNIX_CC_MAK) >unix-cc.mak
+
+UNIX_GCC_MAK=$(VERSION_MAK) gcc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-gcc.mak: $(UNIX_GCC_MAK)
+ rm -f unix-gcc.mak
+ $(CAT) $(UNIX_GCC_MAK) >unix-gcc.mak
+
+# Installation
+
+TAGS:
+ etags -t *.c *.h
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+install-exec: $(GS)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(scriptdir)
+ sh -c 'for f in gsbj gsdj gsdj500 gslj gslp gsnd bdftops font2c \
+pdf2dsc pdf2ps printafm ps2ascii ps2epsi ps2pdf wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pfbtogs.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps gs_pdf.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps pdf_2ps.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/unix-end.mak b/gs/src/unix-end.mak
new file mode 100644
index 000000000..d0a2d3737
--- /dev/null
+++ b/gs/src/unix-end.mak
@@ -0,0 +1,137 @@
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix and Desqview/X configurations.
+
+# This is the very last part of the makefile for these configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define a rule for building profiling configurations.
+pg:
+ make GENOPT='' CFLAGS='-pg -O $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+# Define a rule for building debugging configurations.
+debug:
+ make GENOPT='-DDEBUG' CFLAGS='-g -O $(GCFLAGS) $(XCFLAGS)'
+
+# The rule for gconfigv.h is here because it is shared between Unix and
+# DV/X environments.
+gconfigv.h: unix-end.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# The following rules are equivalent to what tar_cat does.
+# The rm -f is so that we don't overwrite a file that `make'
+# may currently be reading from.
+GENERIC_MAK_LIST=$(GS_MAK) $(LIB_MAK) $(INT_MAK) $(JPEG_MAK) $(LIBPNG_MAK) $(ZLIB_MAK) $(DEVS_MAK)
+UNIX_MAK_LIST=dvx-gcc.mak unixansi.mak unix-cc.mak unix-gcc.mak
+
+unix.mak: $(UNIX_MAK_LIST)
+
+DVX_GCC_MAK=$(VERSION_MAK) dgc-head.mak dvx-head.mak $(GENERIC_MAK_LIST) dvx-tail.mak unix-end.mak
+dvx-gcc.mak: $(DVX_GCC_MAK)
+ rm -f dvx-gcc.mak
+ $(CAT) $(DVX_GCC_MAK) >dvx-gcc.mak
+
+UNIXANSI_MAK=$(VERSION_MAK) ansihead.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unixansi.mak: $(UNIXANSI_MAK)
+ rm -f unixansi.mak
+ $(CAT) $(UNIXANSI_MAK) >unixansi.mak
+
+UNIX_CC_MAK=$(VERSION_MAK) cc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-cc.mak: $(UNIX_CC_MAK)
+ rm -f unix-cc.mak
+ $(CAT) $(UNIX_CC_MAK) >unix-cc.mak
+
+UNIX_GCC_MAK=$(VERSION_MAK) gcc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-gcc.mak: $(UNIX_GCC_MAK)
+ rm -f unix-gcc.mak
+ $(CAT) $(UNIX_GCC_MAK) >unix-gcc.mak
+
+# Installation
+
+TAGS:
+ etags -t *.c *.h
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+install-exec: $(GS)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(scriptdir)
+ sh -c 'for f in gsbj gsdj gsdj500 gslj gslp gsnd bdftops font2c \
+pdf2dsc pdf2ps printafm ps2ascii ps2epsi ps2pdf wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pfbtogs.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps gs_pdf.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps pdf_2ps.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/unix-gcc.mak b/gs/src/unix-gcc.mak
new file mode 100755
index 000000000..eb74e05cc
--- /dev/null
+++ b/gs/src/unix-gcc.mak
@@ -0,0 +1,5783 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile fragment containing the current revision identification.
+
+# Define the name of this makefile.
+VERSION_MAK=version.mak
+
+# Major and minor version numbers.
+# MINOR0 is different from MINOR only if MINOR is a single digit.
+GS_VERSION_MAJOR=5
+GS_VERSION_MINOR=13
+GS_VERSION_MINOR0=13
+# Revision date: year x 10000 + month x 100 + day.
+GS_REVISIONDATE=19980427
+
+# Derived values
+GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0)
+GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR)
+GS_REVISION=$(GS_VERSION)
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/gcc/X11 configuration.
+# Note: this makefile assumes you are using gcc in ANSI mode.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unix-gcc.mak #
+# or makefile. Edit gcc-head.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+#GENOPT=-DDEBUG
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler.
+
+CC=gcc
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the default gcc flags.
+# To work around the gcc 2.7.x optimizer bug,
+# add -Dconst= and remove -Wcast-qual and -Wwrite-strings.
+
+#GCFLAGS=-Wall -Wcast-qual -Wpointer-arith -Wstrict-prototypes -Wwrite-strings
+GCFLAGS=-Dconst= -Wall -Wpointer-arith -Wstrict-prototypes
+
+# Define the other compilation flags. Add at most one of the following:
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSYSV -D__SVR3 for SCO ODT, ISC Unix 2.2 or before,
+# or any System III Unix, or System V release 3-or-older Unix.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+# We don't include -ansi, because this gets in the way of the platform-
+# specific stuff that <math.h> typically needs; nevertheless, we expect
+# gcc to accept ANSI-style function prototypes and function definitions.
+XCFLAGS=
+
+CFLAGS=-O $(GCFLAGS) $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS 4.n may need -Bstatic.
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+#XLIBDIRS=-L/usr/local/X/lib
+XLIBDIRS=-L/usr/X11/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11gray2.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=gcc-head.mak
+
+# Define the ANSI-to-K&R dependency. (gcc accepts ANSI syntax.)
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCAUX=$(CC)
+#We can't use -fomit-frame-pointer with -pg....
+#CCLEAF=$(CCC)
+CCLEAF=$(CCC) -fomit-frame-pointer
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile (unixhead.mak, gs.mak, devs.mak, unixtail.mak)
+# is generic. tar_cat concatenates all these together.
+# Copyright (C) 1990, 1993, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name. For a "stock" System V platform,
+# use sysv_ instead of unix_.
+
+PLATFORM=unix_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=
+O=-o ./
+OBJ=o
+XE=
+XEAUX=
+
+# Define the current directory prefix and command invocations.
+
+CAT=cat
+D=/
+EXPP=
+EXP=./
+SHELL=/bin/sh
+SH=$(SHELL)
+SHP=$(SH) $(EXP)
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+RMN_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p "%s&s&&" -pl "&-l%s&s&&" -pL "&-L%s&s&&" -ol $(ld_tr)
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Patch a couple of PC-specific things that aren't relevant to Unix builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Generic makefile, common to all platforms.
+# The platform-specific makefiles `include' this file.
+# They define the following symbols:
+# GS - the name of the executable (without the extension, if any).
+# GS_LIB_DEFAULT - the default directory/ies for searching for the
+# initialization and font files at run time.
+# SEARCH_HERE_FIRST - the default setting of -P (whether or not to
+# look for files in the current directory first).
+# GS_DOCDIR - the directory where documentation will be available
+# at run time.
+# JSRCDIR - the directory where the IJG JPEG library source code
+# is stored (at compilation time).
+# JVERSION - the major version number of the IJG JPEG library.
+# PSRCDIR, PVERSION - the same for libpng.
+# ZSRCDIR - the same for zlib.
+# SHARE_LIBPNG - normally 0; if set to 1, asks the linker to use
+# an existing compiled libpng (-lpng) instead of compiling and
+# linking libpng explicitly.
+# LIBPNG_NAME, the name of the shared libpng, currently always
+# png (libpng, -lpng).
+# SHARE_ZLIB - normally 0; if set to 1, asks the linker to use
+# an existing compiled zlib (-lgz or -lz) instead of compiling
+# and linking libgz/libz explicitly.
+# ZLIB_NAME - the name of the shared zlib, either gz (for libgz, -lgz)
+# or z (for libz, -lz).
+# CONFIG - a configuration ID, added at the request of a customer,
+# that is supposed to help in maintaining multiple variants in
+# a single directory. Normally this is an empty string;
+# it may be any string that is legal as part of a file name.
+# DEVICE_DEVS - the devices to include in the executable.
+# See devs.mak for details.
+# DEVICE_DEVS1...DEVICE_DEVS15 - additional devices, if the definition
+# of DEVICE_DEVS doesn't fit on one line. See devs.mak for details.
+# FEATURE_DEVS - what features to include in the executable.
+# Normally this is one of:
+# level1 - a standard PostScript Level 1 language
+# interpreter.
+# level2 - a standard PostScript Level 2 language
+# interpreter.
+# pdf - a PDF-capable interpreter.
+# You may include both level1 and pdf, or both level2 and pdf.
+# The following feature may be added to either of the standard
+# configurations:
+# ccfonts - precompile fonts into C, and link them
+# with the executable. See fonts.txt for details.
+# The remaining features are of interest primarily to developers
+# who want to "mix and match" features to create custom
+# configurations:
+# dps - (partial) support for Display PostScript extensions:
+# see language.txt for details.
+# btoken - support for binary token encodings.
+# Included automatically in the dps and level2 features.
+# cidfont - (currently partial) support for CID-keyed fonts.
+# color - support for the Level 1 CMYK color extensions.
+# Included automatically in the dps and level2 features.
+# compfont - support for composite (type 0) fonts.
+# Included automatically in the level2 feature.
+# dct - support for DCTEncode/Decode filters.
+# Included automatically in the level2 feature.
+# epsf - support for recognizing and skipping the binary
+# header of MS-DOS EPSF files.
+# filter - support for Level 2 filters (other than eexec,
+# ASCIIHexEncode/Decode, NullEncode, PFBDecode,
+# RunLengthEncode/Decode, and SubFileDecode, which are
+# always included, and DCTEncode/Decode,
+# which are separate).
+# Included automatically in the level2 feature.
+# fzlib - support for zlibEncode/Decode filters.
+# ttfont - support for TrueType fonts.
+# type1 - support for Type 1 fonts and eexec;
+# normally included automatically in all configurations.
+# type42 - support for Type 42 (embedded TrueType) fonts.
+# Included automatically in the level2 feature.
+# There are quite a number of other sub-features that can be
+# selectively included in or excluded from a configuration,
+# but the above are the ones that are most likely to be of
+# interest.
+# COMPILE_INITS - normally 0; if set to 1, compiles the PostScript
+# language initialization files (gs_init.ps et al) into the
+# executable, eliminating the need for these files to be present
+# at run time.
+# BAND_LIST_STORAGE - normally file; if set to memory, stores band
+# lists in memory (with compression if needed).
+# BAND_LIST_COMPRESSOR - normally zlib: selects the compression method
+# to use for band lists in memory.
+# FILE_IMPLEMENTATION - normally stdio; if set to fd, uses file
+# descriptors instead of buffered stdio for file I/O; if set to
+# both, provides both implementations with different procedure
+# names for the fd-based implementation (see sfxfd.c for
+# more information).
+# EXTEND_NAMES - a value N between 0 and 6, indicating that the name
+# table should have a capacity of 2^(16+N) names. This normally
+# should be set to 0 (or left undefined), since non-zero values
+# result in a larger fixed space overhead and slightly slower code.
+# EXTEND_NAMES is ignored in 16-bit environments.
+#
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+# GS_INIT - the name of the initialization file for the interpreter,
+# normally gs_init.ps.
+# PLATFORM - a "device" name for the platform, so that platforms can
+# add various kinds of resources like devices and features.
+# CMD - the suffix for shell command files (e.g., null or .bat).
+# (This is only needed in a few places.)
+# D - the directory separator character (\ for MS-DOS, / for Unix).
+# O - the string for specifying the output file from the C compiler
+# (-o for MS-DOS, -o ./ for Unix).
+# OBJ - the extension for relocatable object files (e.g., o or obj).
+# XE - the extension for executable files (e.g., null or .exe).
+# XEAUX - the extension for the executable files (e.g., null or .exe)
+# for the utility programs (ansi2knr and those compiled with
+# CCAUX).
+# BEGINFILES - the list of files that `make begin' and `make clean'
+# should delete.
+# CCA2K - the C invocation for the ansi2knr program, which is the only
+# one that doesn't use ANSI C syntax. (It is only needed if
+# the main C compiler also isn't an ANSI compiler.)
+# CCAUX - the C invocation for auxiliary programs (echogs, genarch,
+# genconf, geninit).
+# CCBEGIN - the compilation command for `make begin', normally
+# $(CCC) *.c.
+# CCC - the C invocation for normal compilation.
+# CCD - the C invocation for files that store into frame buffers or
+# device registers. Needed because some optimizing compilers
+# will eliminate necessary stores.
+# CCCF - the C invocation for compiled fonts and other large,
+# self-contained data modules. Needed because MS-DOS
+# requires using the 'huge' memory model for these.
+# CCINT - the C invocation for compiling the main interpreter module,
+# normally the same as CCC: this is needed because the
+# Borland compiler generates *worse* code for this module
+# (but only this module) when optimization (-O) is turned on.
+# CCLEAF - the C invocation for compiling modules that contain only
+# leaf procedures, which don't need to build stack frames.
+# This is needed only because many compilers aren't able to
+# recognize leaf procedures on their own.
+# AK - if source files must be converted from ANSI to K&R syntax,
+# this is $(ANSI2KNR_XE); if not, it is null.
+# If a particular platform requires other utility programs
+# to be built, AK must include them too.
+# SHP - the prefix for invoking a shell script in the current directory
+# (null for MS-DOS, $(SH) ./ for Unix).
+# EXPP, EXP - the prefix for invoking an executable program in the
+# current directory (null for MS-DOS, ./ for Unix).
+# SH - the shell for scripts (null on MS-DOS, sh on Unix).
+# CONFILES - the arguments for genconf to generate the appropriate
+# linker control files (various).
+# CP_ - the command for copying one file to another. Because of
+# limitations in the MS-DOS/MS Windows environment, the
+# second argument must either be '.' (in which case the
+# write date may be either preserved or set to the current
+# date) or a file name (in which case the write date is
+# always updated).
+# RM_ - the command for deleting (a) file(s) (including wild cards,
+# but limited to a single file or pattern).
+# RMN_ = the command for deleting multiple files / patterns.
+#
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+# Define the name of this makefile.
+GS_MAK=gs.mak
+
+# Define the names of the executables.
+GS_XE=$(GS)$(XE)
+ANSI2KNR_XE=ansi2knr$(XEAUX)
+ECHOGS_XE=echogs$(XEAUX)
+GENARCH_XE=genarch$(XEAUX)
+GENCONF_XE=genconf$(XEAUX)
+GENINIT_XE=geninit$(XEAUX)
+
+# Define the names of the CONFIG-dependent header files.
+# gconfig*.h and gconfx*.h are generated dynamically.
+gconfig_h=gconfxx$(CONFIG).h
+gconfigf_h=gconfxc$(CONFIG).h
+
+# Watcom make insists that rules have a non-empty body!
+all default: $(GS_XE)
+ $(RM_) _temp_*
+
+distclean maintainer-clean realclean: clean
+ $(RM_) makefile
+
+clean: mostlyclean
+ $(RM_) arch.h
+ $(RM_) $(GS_XE)
+
+mostlyclean:
+ $(RMN_) *.$(OBJ) *.a core gmon.out
+ $(RMN_) *.dev *.d_* devs*.tr gconfig*.h gconfx*.h j*.h o*.tr l*.tr
+ $(RMN_) deflate.h zutil.h
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) _temp_* _temp_*.* *.map *.sym
+ $(RMN_) $(ANSI2KNR_XE) $(ECHOGS_XE) $(GENARCH_XE) $(GENCONF_XE) $(GENINIT_XE)
+ $(RMN_) gs_init.c $(BEGINFILES)
+
+# Remove only configuration-dependent information.
+config-clean:
+ $(RMN_) *.dev devs*.tr gconfig*.h gconfx*.h o*.tr l*.tr
+
+# A rule to do a quick and dirty compilation attempt when first installing
+# the interpreter. Many of the compilations will fail:
+# follow this with 'make'.
+
+begin:
+ $(RMN_) arch.h gconfig*.h gconfx*.h $(GENARCH_XE) $(GS_XE)
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) gs_init.c $(BEGINFILES)
+ make arch.h gconfigv.h
+ - $(CCBEGIN)
+ $(RMN_) gconfig.$(OBJ) gdev*.$(OBJ) gp_*.$(OBJ) gscdefs.$(OBJ) gsmisc.$(OBJ)
+ $(RMN_) icfontab.$(OBJ) iconfig.$(OBJ) iinit.$(OBJ) interp.$(OBJ)
+
+# Auxiliary programs
+
+arch.h: $(GENARCH_XE)
+ $(EXPP) $(EXP)genarch arch.h
+
+# Macros for constructing the *.dev files that describe features and
+# devices.
+SETDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-obj
+SETPDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-include -lpage -l-obj
+SETMOD=$(EXP)echogs -e .dev -w- -l-obj
+ADDMOD=$(EXP)echogs -e .dev -a-
+
+# Define the compilation commands for the third-party libraries.
+CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR) -DPNG_USE_CONST
+CCCJ=$(CCC) -I. -I$(JSRCDIR)
+CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+
+######################## How to define new 'features' #######################
+#
+# One defines new 'features' exactly like devices (see devs.mak for details).
+# For example, one would define a feature abc by adding the following to
+# gs.mak:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_)
+# $(SETMOD) abc $(abc_)
+# $(ADDMOD) abc -obj ... [if needed]
+# $(ADDMOD) abc -oper ... [if appropriate]
+# $(ADDMOD) abc -ps ... [if appropriate]
+#
+# If the abc feature requires the presence of some other features jkl and
+# pqr, then the rules must look like this:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_) jkl.dev pqr.dev
+# $(SETMOD) abc $(abc_)
+# ...
+# $(ADDMOD) abc -include jkl pqr
+
+# --------------------- Configuration-dependent files --------------------- #
+
+# gconfig.h shouldn't have to depend on DEVS_ALL, but that would
+# involve rewriting gsconfig to only save the device name, not the
+# contents of the <device>.dev files.
+# FEATURE_DEVS must precede DEVICE_DEVS so that devices can override
+# features in obscure cases.
+
+DEVS_ALL=$(PLATFORM).dev $(FEATURE_DEVS) \
+ $(DEVICE_DEVS) $(DEVICE_DEVS1) \
+ $(DEVICE_DEVS2) $(DEVICE_DEVS3) $(DEVICE_DEVS4) $(DEVICE_DEVS5) \
+ $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
+ $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
+ $(DEVICE_DEVS14) $(DEVICE_DEVS15)
+
+devs_tr=devs.tr$(CONFIG)
+$(devs_tr): $(GS_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w $(devs_tr) - -include $(PLATFORM).dev
+ $(EXP)echogs -a $(devs_tr) - $(FEATURE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS1)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS2)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS3)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS4)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS5)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS6)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS7)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS8)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS9)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS10)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS11)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS12)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS13)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS14)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS15)
+
+# GCONFIG_EXTRAS can be set on the command line.
+# Note that it consists of arguments for echogs, i.e.,
+# it isn't just literal text.
+GCONFIG_EXTRAS=
+
+ld_tr=ld$(CONFIG).tr
+$(gconfig_h) $(ld_tr) lib.tr: \
+ $(GS_MAK) $(MAKEFILE) version.mak $(GENCONF_XE) $(ECHOGS_XE) $(devs_tr) $(DEVS_ALL) libcore.dev
+ $(EXP)genconf $(devs_tr) libcore.dev -h $(gconfig_h) $(CONFILES)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_LIB_DEFAULT -x 2022 $(GS_LIB_DEFAULT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u SEARCH_HERE_FIRST -s $(SEARCH_HERE_FIRST)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_DOCDIR -x 2022 $(GS_DOCDIR) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_INIT -x 2022 $(GS_INIT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISION -s $(GS_REVISION)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISIONDATE -s $(GS_REVISIONDATE)
+ $(EXP)echogs -a $(gconfig_h) $(GCONFIG_EXTRAS)
+
+################################################################
+# The other platform-independent makefiles are concatenated
+# (or included) after this one:
+# lib.mak
+# int.mak
+# jpeg.mak
+# libpng.mak
+# zlib.mak
+# devs.mak
+################################################################
+# Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for graphics library and other support code.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+LIB_MAK=lib.mak
+
+# Define the inter-dependencies of the .h files.
+# Since not all versions of `make' defer expansion of macros,
+# we must list these in bottom-to-top order.
+
+# Generic files
+
+arch_h=arch.h
+stdpre_h=stdpre.h
+std_h=std.h $(arch_h) $(stdpre_h)
+
+# Platform interfaces
+
+gp_h=gp.h
+gpcheck_h=gpcheck.h
+gpsync_h=gpsync.h
+
+# Configuration definitions
+
+# gconfig*.h are generated dynamically.
+gconfig__h=gconfig_.h
+gconfigv_h=gconfigv.h
+gscdefs_h=gscdefs.h
+
+# C library interfaces
+
+# Because of variations in the "standard" header files between systems, and
+# because we must include std.h before any file that includes sys/types.h,
+# we define local include files named *_.h to substitute for <*.h>.
+
+vmsmath_h=vmsmath.h
+
+dos__h=dos_.h
+ctype__h=ctype_.h $(std_h)
+dirent__h=dirent_.h $(std_h) $(gconfig__h)
+errno__h=errno_.h $(std_h)
+malloc__h=malloc_.h $(std_h)
+math__h=math_.h $(std_h) $(vmsmath_h)
+memory__h=memory_.h $(std_h)
+stat__h=stat_.h $(std_h)
+stdio__h=stdio_.h $(std_h)
+string__h=string_.h $(std_h)
+time__h=time_.h $(std_h) $(gconfig__h)
+windows__h=windows_.h
+
+# Miscellaneous
+
+gdebug_h=gdebug.h
+gsalloc_h=gsalloc.h
+gsargs_h=gsargs.h
+gserror_h=gserror.h
+gserrors_h=gserrors.h
+gsexit_h=gsexit.h
+gsgc_h=gsgc.h
+gsio_h=gsio.h
+gsmdebug_h=gsmdebug.h
+gsmemraw_h=gsmemraw.h
+gsmemory_h=gsmemory.h $(gsmemraw_h)
+gsrefct_h=gsrefct.h
+gsstruct_h=gsstruct.h
+gstypes_h=gstypes.h
+gx_h=gx.h $(stdio__h) $(gdebug_h) $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
+
+GX=$(AK) $(gx_h)
+GXERR=$(GX) $(gserrors_h)
+
+###### Support
+
+### Include files
+
+gsbitmap_h=gsbitmap.h $(gsstruct_h)
+gsbitops_h=gsbitops.h
+gsbittab_h=gsbittab.h
+gsflip_h=gsflip.h
+gsuid_h=gsuid.h
+gsutil_h=gsutil.h
+gxarith_h=gxarith.h
+gxbitmap_h=gxbitmap.h $(gsbitmap_h) $(gstypes_h)
+gxfarith_h=gxfarith.h $(gconfigv_h) $(gxarith_h)
+gxfixed_h=gxfixed.h
+gxobj_h=gxobj.h $(gxbitmap_h)
+# Out of order
+gxalloc_h=gxalloc.h $(gsalloc_h) $(gxobj_h)
+
+### Executable code
+
+gsalloc.$(OBJ): gsalloc.c $(GX) $(memory__h) $(string__h) \
+ $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsargs.$(OBJ): gsargs.c $(ctype__h) $(stdio__h) $(string__h)\
+ $(gsargs_h) $(gsexit_h) $(gsmemory_h)
+
+gsbitops.$(OBJ): gsbitops.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gsbitops_h) $(gstypes_h)
+
+gsbittab.$(OBJ): gsbittab.c $(AK) $(stdpre_h) $(gsbittab_h)
+
+# gsfemu is only used in FPU-less configurations, and currently only with gcc.
+# We thought using CCLEAF would produce smaller code, but it actually
+# produces larger code!
+gsfemu.$(OBJ): gsfemu.c $(AK) $(std_h)
+
+# gsflip is not part of the standard configuration: it's rather large,
+# and no standard facility requires it.
+gsflip.$(OBJ): gsflip.c $(GX) $(gsbittab_h) $(gsflip_h)
+ $(CCLEAF) gsflip.c
+
+gsmemory.$(OBJ): gsmemory.c $(GX) $(malloc__h) $(memory__h) \
+ $(gsmdebug_h) $(gsrefct_h) $(gsstruct_h) $(gsmemraw_h)
+
+gsmisc.$(OBJ): gsmisc.c $(GXERR) $(gconfigv_h) \
+ $(malloc__h) $(math__h) $(memory__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h)
+
+# gsnogc currently is only used in library-only configurations.
+gsnogc.$(OBJ): gsnogc.c $(GX)\
+ $(gsgc_h) $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsutil.$(OBJ): gsutil.c $(AK) $(memory__h) $(string__h) $(gconfigv_h)\
+ $(gstypes_h) $(gsuid_h) $(gsutil_h)
+
+###### Low-level facilities and utilities
+
+### Include files
+
+gdevbbox_h=gdevbbox.h
+gdevmem_h=gdevmem.h $(gsbitops_h)
+gdevmrop_h=gdevmrop.h
+
+gsccode_h=gsccode.h
+gsccolor_h=gsccolor.h $(gsstruct_h)
+gscsel_h=gscsel.h
+gscolor1_h=gscolor1.h
+gscoord_h=gscoord.h
+gscpm_h=gscpm.h
+gsdevice_h=gsdevice.h
+gsfcmap_h=gsfcmap.h $(gsccode_h)
+gsfont_h=gsfont.h
+gshsb_h=gshsb.h
+gsht_h=gsht.h
+gsht1_h=gsht1.h $(gsht_h)
+gsiparam_h=gsiparam.h
+gsjconf_h=gsjconf.h $(std_h)
+gslib_h=gslib.h
+gslparam_h=gslparam.h
+gsmatrix_h=gsmatrix.h
+gspaint_h=gspaint.h
+gsparam_h=gsparam.h
+gsparams_h=gsparams.h $(gsparam_h)
+gspath2_h=gspath2.h
+gspenum_h=gspenum.h
+gsropt_h=gsropt.h
+gsxfont_h=gsxfont.h
+# Out of order
+gschar_h=gschar.h $(gsccode_h) $(gscpm_h)
+gscolor2_h=gscolor2.h $(gsccolor_h) $(gsuid_h) $(gxbitmap_h)
+gsimage_h=gsimage.h $(gsiparam_h)
+gsline_h=gsline.h $(gslparam_h)
+gspath_h=gspath.h $(gspenum_h)
+gsrop_h=gsrop.h $(gsropt_h)
+
+gxbcache_h=gxbcache.h $(gxbitmap_h)
+gxchar_h=gxchar.h $(gschar_h)
+gxcindex_h=gxcindex.h
+gxcvalue_h=gxcvalue.h
+gxclio_h=gxclio.h
+gxclip2_h=gxclip2.h
+gxcolor2_h=gxcolor2.h $(gscolor2_h) $(gsrefct_h) $(gxbitmap_h)
+gxcoord_h=gxcoord.h $(gscoord_h)
+gxcpath_h=gxcpath.h
+gxdda_h=gxdda.h
+gxdevrop_h=gxdevrop.h
+gxdevmem_h=gxdevmem.h
+gxdither_h=gxdither.h
+gxfcmap_h=gxfcmap.h $(gsfcmap_h) $(gsuid_h)
+gxfont0_h=gxfont0.h
+gxfrac_h=gxfrac.h
+gxftype_h=gxftype.h
+gxhttile_h=gxhttile.h
+gxhttype_h=gxhttype.h
+gxiodev_h=gxiodev.h $(stat__h)
+gxline_h=gxline.h $(gslparam_h)
+gxlum_h=gxlum.h
+gxmatrix_h=gxmatrix.h $(gsmatrix_h)
+gxpaint_h=gxpaint.h
+gxpath_h=gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h)
+gxpcache_h=gxpcache.h
+gxpcolor_h=gxpcolor.h $(gxpcache_h)
+gxsample_h=gxsample.h
+gxstate_h=gxstate.h
+gxtmap_h=gxtmap.h
+gxxfont_h=gxxfont.h $(gsccode_h) $(gsmatrix_h) $(gsuid_h) $(gsxfont_h)
+# The following are out of order because they include other files.
+gsdcolor_h=gsdcolor.h $(gsccolor_h) $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+gxdcolor_h=gxdcolor.h $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gxdevice_h=gxdevice.h $(stdio__h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h) \
+ $(gsropt_h) $(gsstruct_h) $(gsxfont_h) \
+ $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)
+gxdht_h=gxdht.h $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+gxctable_h=gxctable.h $(gxfixed_h) $(gxfrac_h)
+gxfcache_h=gxfcache.h $(gsuid_h) $(gsxfont_h) $(gxbcache_h) $(gxftype_h)
+gxfont_h=gxfont.h $(gsfont_h) $(gsuid_h) $(gsstruct_h) $(gxftype_h)
+gscie_h=gscie.h $(gsrefct_h) $(gxctable_h)
+gscsepr_h=gscsepr.h
+gscspace_h=gscspace.h
+gxdcconv_h=gxdcconv.h $(gxfrac_h)
+gxfmap_h=gxfmap.h $(gsrefct_h) $(gxfrac_h) $(gxtmap_h)
+gxistate_h=gxistate.h $(gscsel_h) $(gsropt_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+gxband_h=gxband.h $(gxclio_h)
+gxclist_h=gxclist.h $(gscspace_h) $(gxbcache_h) $(gxclio_h) $(gxistate_h) $(gxband_h)
+gxcmap_h=gxcmap.h $(gscsel_h) $(gxcvalue_h) $(gxfmap_h)
+gxcspace_h=gxcspace.h $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gsstruct_h) $(gxfrac_h)
+gxht_h=gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gscolor_h=gscolor.h $(gxtmap_h)
+gsstate_h=gsstate.h $(gscolor_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
+
+gzacpath_h=gzacpath.h
+gzcpath_h=gzcpath.h $(gxcpath_h)
+gzht_h=gzht.h $(gscsel_h) $(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
+gzline_h=gzline.h $(gxline_h)
+gzpath_h=gzpath.h $(gsstruct_h) $(gxpath_h)
+gzstate_h=gzstate.h $(gscpm_h) $(gsrefct_h) $(gsstate_h)\
+ $(gxdcolor_h) $(gxistate_h) $(gxstate_h)
+
+gdevprn_h=gdevprn.h $(memory__h) $(string__h) $(gx_h) \
+ $(gserrors_h) $(gsmatrix_h) $(gsparam_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxdevmem_h) $(gxclist_h)
+
+sa85x_h=sa85x.h
+sbtx_h=sbtx.h
+scanchar_h=scanchar.h
+scommon_h=scommon.h $(gsmemory_h) $(gstypes_h) $(gsstruct_h)
+sdct_h=sdct.h
+shc_h=shc.h $(gsbittab_h)
+siscale_h=siscale.h $(gconfigv_h)
+sjpeg_h=sjpeg.h
+slzwx_h=slzwx.h
+spcxx_h=spcxx.h
+spdiffx_h=spdiffx.h
+spngpx_h=spngpx.h
+srlx_h=srlx.h
+sstring_h=sstring.h
+strimpl_h=strimpl.h $(scommon_h) $(gstypes_h) $(gsstruct_h)
+szlibx_h=szlibx.h
+# Out of order
+scf_h=scf.h $(shc_h)
+scfx_h=scfx.h $(shc_h)
+gximage_h=gximage.h $(gsiparam_h) $(gxcspace_h) $(gxdda_h) $(gxsample_h)\
+ $(siscale_h) $(strimpl_h)
+
+### Executable code
+
+# gconfig and gscdefs are handled specially. Currently they go in psbase
+# rather than in libcore, which is clearly wrong.
+gconfig=gconfig$(CONFIG)
+$(gconfig).$(OBJ): gconf.c $(GX) \
+ $(gscdefs_h) $(gconfig_h) $(gxdevice_h) $(gxiodev_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gconf.c $(gconfig).c
+ $(CCC) $(gconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+
+gscdefs=gscdefs$(CONFIG)
+$(gscdefs).$(OBJ): gscdef.c $(stdpre_h) $(gscdefs_h) $(gconfig_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gscdef.c $(gscdefs).c
+ $(CCC) $(gscdefs).c
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+
+gxacpath.$(OBJ): gxacpath.c $(GXERR) \
+ $(gsdcolor_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxpaint_h) \
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)
+
+gxbcache.$(OBJ): gxbcache.c $(GX) $(memory__h) \
+ $(gsmdebug_h) $(gxbcache_h)
+
+gxccache.$(OBJ): gxccache.c $(GXERR) $(gpcheck_h) \
+ $(gscspace_h) $(gsimage_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxdevmem_h) $(gxfcache_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxhttile_h) $(gxmatrix_h) $(gxxfont_h) \
+ $(gzstate_h) $(gzpath_h) $(gzcpath_h)
+
+gxccman.$(OBJ): gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfont_h) $(gxfcache_h) $(gxchar_h)\
+ $(gxxfont_h) $(gzstate_h) $(gzpath_h)
+
+gxcht.$(OBJ): gxcht.c $(GXERR) $(memory__h)\
+ $(gsutil_h)\
+ $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h)\
+ $(gxmatrix_h) $(gzht_h)
+
+gxcmap.$(OBJ): gxcmap.c $(GXERR) \
+ $(gsccolor_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gxdither_h) \
+ $(gxfarith_h) $(gxfrac_h) $(gxlum_h) $(gzstate_h)
+
+gxcpath.$(OBJ): gxcpath.c $(GXERR)\
+ $(gscoord_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gzpath_h) $(gzcpath_h)
+
+gxdcconv.$(OBJ): gxdcconv.c $(GX) \
+ $(gsdcolor_h) $(gxcmap_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gxfarith_h) $(gxistate_h) $(gxlum_h)
+
+gxdcolor.$(OBJ): gxdcolor.c $(GX) \
+ $(gsbittab_h) $(gxdcolor_h) $(gxdevice_h)
+
+gxdither.$(OBJ): gxdither.c $(GX) \
+ $(gsstruct_h) $(gsdcolor_h) \
+ $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
+
+gxfill.$(OBJ): gxfill.c $(GXERR) $(math__h) \
+ $(gsstruct_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h) \
+ $(gxistate_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+gxht.$(OBJ): gxht.c $(GXERR) $(memory__h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+
+gximage.$(OBJ): gximage.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h) $(gsstruct_h)\
+ $(gxfixed_h) $(gxfrac_h) $(gxarith_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gzpath_h) $(gzstate_h)\
+ $(gzcpath_h) $(gxdevmem_h) $(gximage_h) $(gdevmrop_h)
+
+gximage0.$(OBJ): gximage0.c $(GXERR) $(memory__h)\
+ $(gxcpath_h) $(gxdevice_h) $(gximage_h)
+
+gximage1.$(OBJ): gximage1.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsbittab_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gximage2.$(OBJ): gximage2.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gxpaint.$(OBJ): gxpaint.c $(GX) \
+ $(gxdevice_h) $(gxhttile_h) $(gxpaint_h) $(gxpath_h) $(gzstate_h)
+
+gxpath.$(OBJ): gxpath.c $(GXERR) \
+ $(gsstruct_h) $(gxfixed_h) $(gzpath_h)
+
+gxpath2.$(OBJ): gxpath2.c $(GXERR) $(math__h) \
+ $(gxfixed_h) $(gxarith_h) $(gzpath_h)
+
+gxpcopy.$(OBJ): gxpcopy.c $(GXERR) $(math__h) $(gconfigv_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxpdash.$(OBJ): gxpdash.c $(GX) $(math__h) \
+ $(gscoord_h) $(gsline_h) $(gsmatrix_h) \
+ $(gxfixed_h) $(gzline_h) $(gzpath_h)
+
+gxpflat.$(OBJ): gxpflat.c $(GX)\
+ $(gxarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxsample.$(OBJ): gxsample.c $(GX)\
+ $(gxsample_h)
+
+gxstroke.$(OBJ): gxstroke.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gscoord_h) $(gsdcolor_h) $(gsdevice_h) \
+ $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) \
+ $(gxhttile_h) $(gxistate_h) $(gxmatrix_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzline_h) $(gzpath_h)
+
+###### Higher-level facilities
+
+gschar.$(OBJ): gschar.c $(GXERR) $(memory__h) $(string__h)\
+ $(gspath_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxarith_h) $(gxmatrix_h) $(gxcoord_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxfcache_h) $(gzpath_h) $(gzstate_h)
+
+gscolor.$(OBJ): gscolor.c $(GXERR) \
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
+
+gscoord.$(OBJ): gscoord.c $(GXERR) $(math__h) \
+ $(gsccode_h) $(gxcoord_h) $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) $(gxfont_h) \
+ $(gxmatrix_h) $(gxpath_h) $(gzstate_h)
+
+gsdevice.$(OBJ): gsdevice.c $(GXERR) $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
+ $(gscdefs_h) $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstruct_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gzstate_h)
+
+gsdevmem.$(OBJ): gsdevmem.c $(GXERR) $(math__h) $(memory__h) \
+ $(gxarith_h) $(gxdevice_h) $(gxdevmem_h)
+
+gsdparam.$(OBJ): gsdparam.c $(GXERR) $(memory__h) $(string__h) \
+ $(gsparam_h) $(gxdevice_h) $(gxfixed_h)
+
+gsfont.$(OBJ): gsfont.c $(GXERR) $(memory__h)\
+ $(gschar_h) $(gsstruct_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)
+
+gsht.$(OBJ): gsht.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gshtscr.$(OBJ): gshtscr.c $(GXERR) $(math__h) \
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gsimage.$(OBJ): gsimage.c $(GXERR) $(memory__h)\
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxdevice_h) $(gzstate_h)
+
+gsimpath.$(OBJ): gsimpath.c $(GXERR) \
+ $(gsmatrix_h) $(gsstate_h) $(gspath_h)
+
+gsinit.$(OBJ): gsinit.c $(memory__h) $(stdio__h) \
+ $(gdebug_h) $(gp_h) $(gscdefs_h) $(gslib_h) $(gsmemory_h)
+
+gsiodev.$(OBJ): gsiodev.c $(GXERR) $(errno__h) $(string__h) \
+ $(gp_h) $(gsparam_h) $(gxiodev_h)
+
+gsline.$(OBJ): gsline.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsline_h) $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gzline_h)
+
+gsmatrix.$(OBJ): gsmatrix.c $(GXERR) $(math__h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h)
+
+gspaint.$(OBJ): gspaint.c $(GXERR) $(math__h) $(gpcheck_h)\
+ $(gspaint_h) $(gspath_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdevmem_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxpaint_h)\
+ $(gzpath_h) $(gzstate_h)
+
+gsparam.$(OBJ): gsparam.c $(GXERR) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsstruct_h)
+
+gsparams.$(OBJ): gsparams.c $(gx_h) $(memory__h) $(gserrors_h) $(gsparam_h)
+
+gspath.$(OBJ): gspath.c $(GXERR) \
+ $(gscoord_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+gsstate.$(OBJ): gsstate.c $(GXERR) $(memory__h)\
+ $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h) \
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+
+###### The internal devices
+
+### The built-in device implementations:
+
+# The bounding box device is not normally a free-standing device.
+# To configure it as one for testing, change SETMOD to SETDEV, and also
+# define TEST in gdevbbox.c.
+bbox.dev: $(LIB_MAK) $(ECHOGS_XE) gdevbbox.$(OBJ)
+ $(SETMOD) bbox gdevbbox.$(OBJ)
+
+gdevbbox.$(OBJ): gdevbbox.c $(GXERR) $(math__h) $(memory__h) \
+ $(gdevbbox_h) $(gsdevice_h) $(gsparam_h) \
+ $(gxcpath_h) $(gxdevice_h) $(gxistate_h) $(gxpaint_h) $(gxpath_h)
+
+gdevddrw.$(OBJ): gdevddrw.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h)
+
+gdevdflt.$(OBJ): gdevdflt.c $(GXERR) $(gpcheck_h)\
+ $(gsbittab_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)
+
+gdevnfwd.$(OBJ): gdevnfwd.c $(GX) \
+ $(gxdevice_h)
+
+# The render/RGB device is only here as an example, but we can configure
+# it as a real device for testing.
+rrgb.dev: $(LIB_MAK) $(ECHOGS_XE) gdevrrgb.$(OBJ) page.dev
+ $(SETPDEV) rrgb gdevrrgb.$(OBJ)
+
+gdevrrgb.$(OBJ): gdevrrgb.c $(AK)\
+ $(gdevprn_h)
+
+### The memory devices:
+
+gdevabuf.$(OBJ): gdevabuf.c $(GXERR) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmem.$(OBJ): gdevmem.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm1.$(OBJ): gdevm1.c $(GX) $(memory__h) $(gsrop_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm2.$(OBJ): gdevm2.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm4.$(OBJ): gdevm4.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm8.$(OBJ): gdevm8.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm16.$(OBJ): gdevm16.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm24.$(OBJ): gdevm24.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm32.$(OBJ): gdevm32.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmpla.$(OBJ): gdevmpla.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+# Create a pseudo-"feature" for the entire graphics library.
+
+LIB1s=gsalloc.$(OBJ) gsbitops.$(OBJ) gsbittab.$(OBJ)
+LIB2s=gschar.$(OBJ) gscolor.$(OBJ) gscoord.$(OBJ) gsdevice.$(OBJ) gsdevmem.$(OBJ)
+LIB3s=gsdparam.$(OBJ) gsfont.$(OBJ) gsht.$(OBJ) gshtscr.$(OBJ)
+LIB4s=gsimage.$(OBJ) gsimpath.$(OBJ) gsinit.$(OBJ) gsiodev.$(OBJ)
+LIB5s=gsline.$(OBJ) gsmatrix.$(OBJ) gsmemory.$(OBJ) gsmisc.$(OBJ)
+LIB6s=gspaint.$(OBJ) gsparam.$(OBJ) gsparams.$(OBJ) gspath.$(OBJ) gsstate.$(OBJ) gsutil.$(OBJ)
+LIB1x=gxacpath.$(OBJ) gxbcache.$(OBJ)
+LIB2x=gxccache.$(OBJ) gxccman.$(OBJ) gxcht.$(OBJ) gxcmap.$(OBJ) gxcpath.$(OBJ)
+LIB3x=gxdcconv.$(OBJ) gxdcolor.$(OBJ) gxdither.$(OBJ) gxfill.$(OBJ) gxht.$(OBJ)
+LIB4x=gximage.$(OBJ) gximage0.$(OBJ) gximage1.$(OBJ) gximage2.$(OBJ)
+LIB5x=gxpaint.$(OBJ) gxpath.$(OBJ) gxpath2.$(OBJ) gxpcopy.$(OBJ)
+LIB6x=gxpdash.$(OBJ) gxpflat.$(OBJ) gxsample.$(OBJ) gxstroke.$(OBJ)
+LIB1d=gdevabuf.$(OBJ) gdevddrw.$(OBJ) gdevdflt.$(OBJ) gdevnfwd.$(OBJ)
+LIB2d=gdevmem.$(OBJ) gdevm1.$(OBJ) gdevm2.$(OBJ) gdevm4.$(OBJ) gdevm8.$(OBJ)
+LIB3d=gdevm16.$(OBJ) gdevm24.$(OBJ) gdevm32.$(OBJ) gdevmpla.$(OBJ)
+LIBs=$(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s)
+LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d)
+LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
+libs.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBs)
+ $(EXP)echogs -w libs.dev $(LIB1s)
+ $(EXP)echogs -a libs.dev $(LIB2s)
+ $(EXP)echogs -a libs.dev $(LIB3s)
+ $(EXP)echogs -a libs.dev $(LIB4s)
+ $(EXP)echogs -a libs.dev $(LIB5s)
+ $(EXP)echogs -a libs.dev $(LIB6s)
+ $(ADDMOD) libs -init gscolor
+
+libx.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBx)
+ $(EXP)echogs -w libx.dev $(LIB1x)
+ $(EXP)echogs -a libx.dev $(LIB2x)
+ $(EXP)echogs -a libx.dev $(LIB3x)
+ $(EXP)echogs -a libx.dev $(LIB4x)
+ $(EXP)echogs -a libx.dev $(LIB5x)
+ $(EXP)echogs -a libx.dev $(LIB6x)
+ $(ADDMOD) libx -init gximage1 gximage2
+
+libd.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBd)
+ $(EXP)echogs -w libd.dev $(LIB1d)
+ $(EXP)echogs -a libd.dev $(LIB2d)
+ $(EXP)echogs -a libd.dev $(LIB3d)
+
+# roplib shouldn't be required....
+libcore.dev: $(LIB_MAK) $(ECHOGS_XE)\
+ libs.dev libx.dev libd.dev iscale.dev roplib.dev
+ $(SETMOD) libcore
+ $(ADDMOD) libcore -dev nullpage
+ $(ADDMOD) libcore -include libs libx libd iscale roplib
+
+# ---------------- Stream support ---------------- #
+# Currently the only things in the library that use this are clists
+# and file streams.
+
+stream_h=stream.h $(scommon_h)
+
+stream.$(OBJ): stream.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+# ---------------- File streams ---------------- #
+# Currently only the high-level drivers use these, but more drivers will
+# probably use them eventually.
+
+sfile_=sfx$(FILE_IMPLEMENTATION).$(OBJ) stream.$(OBJ)
+sfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(sfile_)
+ $(SETMOD) sfile $(sfile_)
+
+sfxstdio.$(OBJ): sfxstdio.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxfd.$(OBJ): sfxfd.c $(AK) $(stdio__h) $(errno__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxboth.$(OBJ): sfxboth.c sfxstdio.c sfxfd.c
+
+# ---------------- CCITTFax filters ---------------- #
+# These are used by clists, some drivers, and Level 2 in general.
+
+cfe_=scfe.$(OBJ) scfetab.$(OBJ) shc.$(OBJ)
+cfe.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfe_)
+ $(SETMOD) cfe $(cfe_)
+
+scfe.$(OBJ): scfe.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfetab.$(OBJ): scfetab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+shc.$(OBJ): shc.c $(AK) $(std_h) $(scommon_h) $(shc_h)
+
+cfd_=scfd.$(OBJ) scfdtab.$(OBJ)
+cfd.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfd_)
+ $(SETMOD) cfd $(cfd_)
+
+scfd.$(OBJ): scfd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfdtab.$(OBJ): scfdtab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+# ---------------- DCT (JPEG) filters ---------------- #
+# These are used by Level 2, and by the JPEG-writing driver.
+
+# Common code
+
+sdctc_=sdctc.$(OBJ) sjpegc.$(OBJ)
+
+sdctc.$(OBJ): sdctc.c $(AK) $(stdio__h)\
+ $(sdct_h) $(strimpl_h)\
+ jpeglib.h
+
+sjpegc.$(OBJ): sjpegc.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Encoding (compression)
+
+sdcte_=$(sdctc_) sdcte.$(OBJ) sjpege.$(OBJ)
+sdcte.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdcte_) jpege.dev
+ $(SETMOD) sdcte $(sdcte_)
+ $(ADDMOD) sdcte -include jpege
+
+sdcte.$(OBJ): sdcte.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpege.$(OBJ): sjpege.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Decoding (decompression)
+
+sdctd_=$(sdctc_) sdctd.$(OBJ) sjpegd.$(OBJ)
+sdctd.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdctd_) jpegd.dev
+ $(SETMOD) sdctd $(sdctd_)
+ $(ADDMOD) sdctd -include jpegd
+
+sdctd.$(OBJ): sdctd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpegd.$(OBJ): sjpegd.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h)\
+ jerror.h jpeglib.h
+
+# ---------------- LZW filters ---------------- #
+# These are used by Level 2 in general.
+
+slzwe_=slzwce
+#slzwe_=slzwe
+lzwe_=$(slzwe_).$(OBJ) slzwc.$(OBJ)
+lzwe.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwe_)
+ $(SETMOD) lzwe $(lzwe_)
+
+# We need slzwe.dev as a synonym for lzwe.dev for BAND_LIST_STORAGE = memory.
+slzwe.dev: lzwe.dev
+ $(CP_) lzwe.dev slzwe.dev
+
+slzwce.$(OBJ): slzwce.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwe.$(OBJ): slzwe.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwc.$(OBJ): slzwc.c $(AK) $(std_h)\
+ $(slzwx_h) $(strimpl_h)
+
+lzwd_=slzwd.$(OBJ) slzwc.$(OBJ)
+lzwd.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwd_)
+ $(SETMOD) lzwd $(lzwd_)
+
+# We need slzwd.dev as a synonym for lzwd.dev for BAND_LIST_STORAGE = memory.
+slzwd.dev: lzwd.dev
+ $(CP_) lzwd.dev slzwd.dev
+
+slzwd.$(OBJ): slzwd.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+# ---------------- PCX decoding filter ---------------- #
+# This is an adhoc filter not used by anything in the standard configuration.
+
+pcxd_=spcxd.$(OBJ)
+pcxd.dev: $(LIB_MAK) $(ECHOGS_XE) $(pcxd_)
+ $(SETMOD) pcxd $(pcxd_)
+
+spcxd.$(OBJ): spcxd.c $(AK) $(stdio__h) $(memory__h) \
+ $(spcxx_h) $(strimpl_h)
+
+# ---------------- Pixel-difference filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pdiff_=spdiff.$(OBJ)
+pdiff.dev: $(LIB_MAK) $(ECHOGS_XE) $(pdiff_)
+ $(SETMOD) pdiff $(pdiff_)
+
+spdiff.$(OBJ): spdiff.c $(AK) $(stdio__h)\
+ $(spdiffx_h) $(strimpl_h)
+
+# ---------------- PNG pixel prediction filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pngp_=spngp.$(OBJ)
+pngp.dev: $(LIB_MAK) $(ECHOGS_XE) $(pngp_)
+ $(SETMOD) pngp $(pngp_)
+
+spngp.$(OBJ): spngp.c $(AK) $(memory__h)\
+ $(spngpx_h) $(strimpl_h)
+
+# ---------------- RunLength filters ---------------- #
+# These are used by clists and also by Level 2 in general.
+
+rle_=srle.$(OBJ)
+rle.dev: $(LIB_MAK) $(ECHOGS_XE) $(rle_)
+ $(SETMOD) rle $(rle_)
+
+srle.$(OBJ): srle.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+rld_=srld.$(OBJ)
+rld.dev: $(LIB_MAK) $(ECHOGS_XE) $(rld_)
+ $(SETMOD) rld $(rld_)
+
+srld.$(OBJ): srld.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+# ---------------- String encoding/decoding filters ---------------- #
+# These are used by the PostScript and PDF writers, and also by the
+# PostScript interpreter.
+
+scantab.$(OBJ): scantab.c $(AK) $(stdpre_h)\
+ $(scanchar_h) $(scommon_h)
+
+sfilter2.$(OBJ): sfilter2.c $(AK) $(memory__h) $(stdio__h)\
+ $(sa85x_h) $(scanchar_h) $(sbtx_h) $(strimpl_h)
+
+sstring.$(OBJ): sstring.c $(AK) $(stdio__h) $(memory__h) $(string__h)\
+ $(scanchar_h) $(sstring_h) $(strimpl_h)
+
+# ---------------- zlib filters ---------------- #
+# These are used by clists and are also available as filters.
+
+szlibc_=szlibc.$(OBJ)
+
+szlibc.$(OBJ): szlibc.c $(AK) $(std_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibc.c
+
+szlibe_=$(szlibc_) szlibe.$(OBJ)
+szlibe.dev: $(LIB_MAK) $(ECHOGS_XE) zlibe.dev $(szlibe_)
+ $(SETMOD) szlibe $(szlibe_)
+ $(ADDMOD) szlibe -include zlibe
+
+szlibe.$(OBJ): szlibe.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibe.c
+
+szlibd_=$(szlibc_) szlibd.$(OBJ)
+szlibd.dev: $(LIB_MAK) $(ECHOGS_XE) zlibd.dev $(szlibd_)
+ $(SETMOD) szlibd $(szlibd_)
+ $(ADDMOD) szlibd -include zlibd
+
+szlibd.$(OBJ): szlibd.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibd.c
+
+# ---------------- Command lists ---------------- #
+
+gxcldev_h=gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
+ $(strimpl_h) $(scfx_h) $(srlx_h)
+gxclpage_h=gxclpage.h $(gxclio_h)
+gxclpath_h=gxclpath.h $(gxfixed_h)
+
+# Command list package. Currently the higher-level facilities are required,
+# but eventually they will be optional.
+clist.dev: $(LIB_MAK) $(ECHOGS_XE) clbase.dev clpath.dev
+ $(SETMOD) clist -include clbase clpath
+
+# Base command list facility.
+clbase1_=gxclist.$(OBJ) gxclbits.$(OBJ) gxclpage.$(OBJ)
+clbase2_=gxclread.$(OBJ) gxclrect.$(OBJ) stream.$(OBJ)
+clbase_=$(clbase1_) $(clbase2_)
+clbase.dev: $(LIB_MAK) $(ECHOGS_XE) $(clbase_) cl$(BAND_LIST_STORAGE).dev \
+ cfe.dev cfd.dev rle.dev rld.dev
+ $(SETMOD) clbase $(clbase1_)
+ $(ADDMOD) clbase -obj $(clbase2_)
+ $(ADDMOD) clbase -include cl$(BAND_LIST_STORAGE) cfe cfd rle rld
+
+gdevht_h=gdevht.h $(gzht_h)
+
+gdevht.$(OBJ): gdevht.c $(GXERR) \
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+
+gxclist.$(OBJ): gxclist.c $(GXERR) $(memory__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)
+
+gxclbits.$(OBJ): gxclbits.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h)
+
+gxclpage.$(OBJ): gxclpage.c $(AK)\
+ $(gdevprn_h) $(gxcldev_h) $(gxclpage_h)
+
+# (gxclread shouldn't need gxclpath.h)
+gxclread.$(OBJ): gxclread.c $(GXERR) $(memory__h) $(gp_h) $(gpcheck_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscoord_h) $(gsdevice_h) $(gsstate_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcspace_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)\
+ $(gxhttile_h) $(gxpaint_h) $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h)
+
+gxclrect.$(OBJ): gxclrect.c $(GXERR)\
+ $(gsutil_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h)
+
+# Higher-level command list facilities.
+clpath_=gxclimag.$(OBJ) gxclpath.$(OBJ)
+clpath.dev: $(LIB_MAK) $(ECHOGS_XE) $(clpath_) psl2cs.dev
+ $(SETMOD) clpath $(clpath_)
+ $(ADDMOD) clpath -include psl2cs
+ $(ADDMOD) clpath -init climag clpath
+
+gxclimag.$(OBJ): gxclimag.c $(GXERR) $(math__h) $(memory__h)\
+ $(gscspace_h)\
+ $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpath_h) $(gxfmap_h)\
+ $(siscale_h) $(strimpl_h)
+
+gxclpath.$(OBJ): gxclpath.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcolor2_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+# Implement band lists on files.
+
+clfile_=gxclfile.$(OBJ)
+clfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
+ $(SETMOD) clfile $(clfile_)
+
+gxclfile.$(OBJ): gxclfile.c $(stdio__h) $(string__h) \
+ $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
+
+# Implement band lists in memory (RAM).
+
+clmemory_=gxclmem.$(OBJ) gxcl$(BAND_LIST_COMPRESSOR).$(OBJ)
+clmemory.dev: $(LIB_MAK) $(ECHOGS_XE) $(clmemory_) s$(BAND_LIST_COMPRESSOR)e.dev s$(BAND_LIST_COMPRESSOR)d.dev
+ $(SETMOD) clmemory $(clmemory_)
+ $(ADDMOD) clmemory -include s$(BAND_LIST_COMPRESSOR)e s$(BAND_LIST_COMPRESSOR)d
+ $(ADDMOD) clmemory -init cl_$(BAND_LIST_COMPRESSOR)
+
+gxclmem_h=gxclmem.h $(gxclio_h) $(strimpl_h)
+
+gxclmem.$(OBJ): gxclmem.c $(GXERR) $(LIB_MAK) $(memory__h) \
+ $(gxclmem_h)
+
+# Implement the compression method for RAM-based band lists.
+
+gxcllzw.$(OBJ): gxcllzw.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(slzwx_h)
+
+gxclzlib.$(OBJ): gxclzlib.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(szlibx_h)
+ $(CCCZ) gxclzlib.c
+
+# ---------------- Page devices ---------------- #
+# We include this here, rather than in devs.mak, because it is more like
+# a feature than a simple device.
+
+page_=gdevprn.$(OBJ)
+page.dev: $(LIB_MAK) $(ECHOGS_XE) $(page_) clist.dev
+ $(SETMOD) page $(page_)
+ $(ADDMOD) page -include clist
+
+gdevprn.$(OBJ): gdevprn.c $(ctype__h) \
+ $(gdevprn_h) $(gp_h) $(gsparam_h) $(gxclio_h)
+
+# ---------------- Vector devices ---------------- #
+# We include this here for the same reasons as page.dev.
+
+gdevvec_h=gdevvec.h $(gdevbbox_h) $(gsropt_h) $(gxdevice_h) $(gxistate_h) $(stream_h)
+
+vector_=gdevvec.$(OBJ)
+vector.dev: $(LIB_MAK) $(ECHOGS_XE) $(vector_) bbox.dev sfile.dev
+ $(SETMOD) vector $(vector_)
+ $(ADDMOD) vector -include bbox sfile
+
+gdevvec.$(OBJ): gdevvec.c $(GXERR) $(math__h) $(memory__h) $(string__h)\
+ $(gdevvec_h) $(gp_h) $(gscspace_h) $(gsparam_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxfixed_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+# ---------------- Image scaling filter ---------------- #
+
+iscale_=siscale.$(OBJ)
+iscale.dev: $(LIB_MAK) $(ECHOGS_XE) $(iscale_)
+ $(SETMOD) iscale $(iscale_)
+
+siscale.$(OBJ): siscale.c $(AK) $(math__h) $(memory__h) $(stdio__h) \
+ $(siscale_h) $(strimpl_h)
+
+# ---------------- RasterOp et al ---------------- #
+# Currently this module is required, but it should be optional.
+
+roplib_=gdevmrop.$(OBJ) gsrop.$(OBJ) gsroptab.$(OBJ)
+roplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(roplib_)
+ $(SETMOD) roplib $(roplib_)
+ $(ADDMOD) roplib -init roplib
+
+gdevrun.$(OBJ): gdevrun.c $(GXERR) $(memory__h) \
+ $(gxdevice_h) $(gxdevmem_h)
+
+gdevmrop.$(OBJ): gdevmrop.c $(GXERR) $(memory__h) \
+ $(gsbittab_h) $(gsropt_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) \
+ $(gdevmrop_h)
+
+gsrop.$(OBJ): gsrop.c $(GXERR) \
+ $(gsrop_h) $(gzstate_h)
+
+gsroptab.$(OBJ): gsroptab.c $(stdpre_h) $(gsropt_h)
+ $(CCLEAF) gsroptab.c
+
+# ---------------- Async rendering ---------------- #
+
+gsmemfix_h=gsmemfix.h $(gsmemraw_h)
+gxsync_h=gxsync.h $(gpsync_h) $(gsmemory_h)
+gxpageq_h=gxpageq.h $(gsmemory_h) $(gxband_h) $(gxsync_h)
+gsmemlok_h=gsmemlok.h $(gsmemory_h) $(gxsync_h)
+gdevprna_h=gdevprna.h $(gdevprn_h) $(gxsync_h)
+
+async_=gdevprna.$(OBJ) gxsync.$(OBJ) gxpageq.$(OBJ) gsmemlok.$(OBJ)\
+ gsmemfix.$(OBJ)
+async.dev: $(INT_MAK) $(ECHOGS_XE) $(async_) clist.dev
+ $(SETMOD) async $(async_)
+
+gdevprna.$(OBJ): gdevprna.c $(AK) $(ctype__h) $(gdevprna_h) $(gsparam_h)\
+ $(gsdevice_h) $(gxcldev_h) $(gxclpath_h) $(gxpageq_h) $(gsmemory_h)\
+ $(gsmemlok_h) $(gsmemfix_h)
+
+gsmemfix.$(OBJ): gsmemfix.c $(AK) $(memory__h) $(gsmemraw_h) $(gsmemfix_h)
+
+gxsync.$(OBJ): gxsync.c $(AK) $(gxsync_h) $(memory__h) $(gx_h) $(gserrors_h)\
+ $(gsmemory_h)
+
+gxpageq.$(OBJ): gxpageq.c $(GXERR) $(gxdevice_h) $(gxclist_h)\
+ $(gxpageq_h) $(gserrors_h)
+
+gsmemlok.$(OBJ): gsmemlok.c $(GXERR) $(gsmemlok_h) $(gserrors_h)
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+cmaplib_=gsfcmap.$(OBJ)
+cmaplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmaplib_)
+ $(SETMOD) cmaplib $(cmaplib_)
+
+gsfcmap.$(OBJ): gsfcmap.c $(GXERR)\
+ $(gsstruct_h) $(gxfcmap_h)
+
+psf0lib_=gschar0.$(OBJ) gsfont0.$(OBJ)
+psf0lib.dev: $(LIB_MAK) $(ECHOGS_XE) cmaplib.dev $(psf0lib_)
+ $(SETMOD) psf0lib $(psf0lib_)
+ $(ADDMOD) psf0lib -include cmaplib
+
+gschar0.$(OBJ): gschar0.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxfixed_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gsfcmap_h) $(gxfont_h) $(gxfont0_h) $(gxchar_h)
+
+gsfont0.$(OBJ): gsfont0.c $(GXERR) $(memory__h)\
+ $(gsmatrix_h) $(gsstruct_h) $(gxfixed_h) $(gxdevmem_h) $(gxfcache_h)\
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxdevice_h)
+
+# ---------------- Pattern color ---------------- #
+
+patlib_=gspcolor.$(OBJ) gxclip2.$(OBJ) gxpcmap.$(OBJ)
+patlib.dev: $(LIB_MAK) $(ECHOGS_XE) cmyklib.dev psl2cs.dev $(patlib_)
+ $(SETMOD) patlib -include cmyklib psl2cs
+ $(ADDMOD) patlib -obj $(patlib_)
+
+gspcolor.$(OBJ): gspcolor.c $(GXERR) $(math__h) \
+ $(gsimage_h) $(gspath_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcoord_h) $(gxclip2_h) $(gxcspace_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfixed_h) $(gxmatrix_h) $(gxpath_h) $(gxpcolor_h) $(gzstate_h)
+
+gxclip2.$(OBJ): gxclip2.c $(GXERR) $(memory__h) \
+ $(gsstruct_h) $(gxclip2_h) $(gxdevice_h) $(gxdevmem_h)
+
+gxpcmap.$(OBJ): gxpcmap.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h)\
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1lib_=gxtype1.$(OBJ) gxhint1.$(OBJ) gxhint2.$(OBJ) gxhint3.$(OBJ)
+
+gscrypt1_h=gscrypt1.h
+gstype1_h=gstype1.h
+gxfont1_h=gxfont1.h
+gxop1_h=gxop1.h
+gxtype1_h=gxtype1.h $(gscrypt1_h) $(gstype1_h) $(gxop1_h)
+
+gxtype1.$(OBJ): gxtype1.c $(GXERR) $(math__h)\
+ $(gsccode_h) $(gsline_h) $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+gxhint1.$(OBJ): gxhint1.c $(GXERR)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint2.$(OBJ): gxhint2.c $(GXERR) $(memory__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint3.$(OBJ): gxhint3.c $(GXERR) $(math__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 1 charstrings
+
+psf1lib_=gstype1.$(OBJ)
+psf1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf1lib_) $(type1lib_)
+ $(SETMOD) psf1lib $(psf1lib_)
+ $(ADDMOD) psf1lib $(type1lib_)
+ $(ADDMOD) psf1lib -init gstype1
+
+gstype1.$(OBJ): gstype1.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 2 charstrings
+
+psf2lib_=gstype2.$(OBJ)
+psf2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf2lib_) $(type1lib_)
+ $(SETMOD) psf2lib $(psf2lib_)
+ $(ADDMOD) psf2lib $(type1lib_)
+ $(ADDMOD) psf2lib -init gstype2
+
+gstype2.$(OBJ): gstype2.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+ttflib_=gstype42.$(OBJ)
+ttflib.dev: $(LIB_MAK) $(ECHOGS_XE) $(ttflib_)
+ $(SETMOD) ttflib $(ttflib_)
+
+gxfont42_h=gxfont42.h
+
+gstype42.$(OBJ): gstype42.c $(GXERR) $(memory__h) \
+ $(gsccode_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont42_h) $(gxistate_h) $(gxpath_h)
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+cmyklib_=gscolor1.$(OBJ) gsht1.$(OBJ)
+cmyklib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmyklib_)
+ $(SETMOD) cmyklib $(cmyklib_)
+ $(ADDMOD) cmyklib -init gscolor1
+
+gscolor1.$(OBJ): gscolor1.c $(GXERR) \
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gzstate_h)
+
+gsht1.$(OBJ): gsht1.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+colimlib_=gximage3.$(OBJ)
+colimlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(colimlib_)
+ $(SETMOD) colimlib $(colimlib_)
+ $(ADDMOD) colimlib -init gximage3
+
+gximage3.$(OBJ): gximage3.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcconv_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h)\
+ $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzpath_h) $(gzstate_h)
+
+# ---------------- HSB color ---------------- #
+
+hsblib_=gshsb.$(OBJ)
+hsblib.dev: $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
+ $(SETMOD) hsblib $(hsblib_)
+
+gshsb.$(OBJ): gshsb.c $(GX) \
+ $(gscolor_h) $(gshsb_h) $(gxfrac_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1lib_=gspath1.$(OBJ)
+path1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(path1lib_)
+ $(SETMOD) path1lib $(path1lib_)
+
+gspath1.$(OBJ): gspath1.c $(GXERR) $(math__h) \
+ $(gscoord_h) $(gspath_h) $(gsstruct_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) $(gzpath_h)
+
+# --------------- Level 2 color space and color image support --------------- #
+
+psl2cs_=gscolor2.$(OBJ)
+psl2cs.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2cs_)
+ $(SETMOD) psl2cs $(psl2cs_)
+
+gscolor2.$(OBJ): gscolor2.c $(GXERR) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h)
+
+psl2lib_=gximage4.$(OBJ) gximage5.$(OBJ)
+psl2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2lib_) colimlib.dev psl2cs.dev
+ $(SETMOD) psl2lib $(psl2lib_)
+ $(ADDMOD) psl2lib -init gximage4 gximage5
+ $(ADDMOD) psl2lib -include colimlib psl2cs
+
+gximage4.$(OBJ): gximage4.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+gximage5.$(OBJ): gximage5.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+# ---------------- Display Postscript / Level 2 support ---------------- #
+
+dps2lib_=gsdps1.$(OBJ)
+dps2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dps2lib_)
+ $(SETMOD) dps2lib $(dps2lib_)
+
+gsdps1.$(OBJ): gsdps1.c $(GXERR) $(math__h)\
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gspath2_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- Display Postscript extensions ---------------- #
+
+gsdps_h=gsdps.h
+
+dpslib_=gsdps.$(OBJ)
+dpslib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dpslib_)
+ $(SETMOD) dpslib $(dpslib_)
+
+gsdps.$(OBJ): gsdps.c $(GX) $(gsdps_h)\
+ $(gsdps_h) $(gspath_h) $(gxdevice_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- CIE color ---------------- #
+
+cielib_=gscie.$(OBJ) gxctable.$(OBJ)
+cielib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cielib_)
+ $(SETMOD) cielib $(cielib_)
+
+gscie.$(OBJ): gscie.c $(GXERR) $(math__h) \
+ $(gscie_h) $(gscolor2_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gzstate_h)
+
+gxctable.$(OBJ): gxctable.c $(GX) \
+ $(gxfixed_h) $(gxfrac_h) $(gxctable_h)
+
+# ---------------- Separation colors ---------------- #
+
+seprlib_=gscsepr.$(OBJ)
+seprlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(seprlib_)
+ $(SETMOD) seprlib $(seprlib_)
+
+gscsepr.$(OBJ): gscsepr.c $(GXERR)\
+ $(gscsepr_h) $(gsmatrix_h) $(gsrefct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+
+# ---------------- Functions ---------------- #
+
+gsdsrc_h=gsdsrc.h $(gsstruct_h)
+gsfunc_h=gsfunc.h
+gsfunc0_h=gsfunc0.h $(gsdsrc_h) $(gsfunc_h)
+gxfunc_h=gxfunc.h $(gsfunc_h) $(gsstruct_h)
+
+# Generic support, and FunctionType 0.
+funclib_=gsdsrc.$(OBJ) gsfunc.$(OBJ) gsfunc0.$(OBJ)
+funclib.dev: $(LIB_MAK) $(ECHOGS_XE) $(funclib_)
+ $(SETMOD) funclib $(funclib_)
+
+gsdsrc.$(OBJ): gsdsrc.c $(GX) $(memory__h)\
+ $(gsdsrc_h) $(gserrors_h) $(stream_h)
+
+gsfunc.$(OBJ): gsfunc.c $(GX)\
+ $(gserrors_h) $(gxfunc_h)
+
+gsfunc0.$(OBJ): gsfunc0.c $(GX) $(math__h)\
+ $(gserrors_h) $(gsfunc0_h) $(gxfunc_h)
+
+# ----------------------- Platform-specific modules ----------------------- #
+# Platform-specific code doesn't really belong here: this is code that is
+# shared among multiple platforms.
+
+# Frame buffer implementations.
+
+gp_nofb.$(OBJ): gp_nofb.c $(GX) \
+ $(gp_h) $(gxdevice_h)
+
+gp_dosfb.$(OBJ): gp_dosfb.c $(AK) $(malloc__h) $(memory__h)\
+ $(gx_h) $(gp_h) $(gserrors_h) $(gxdevice_h)
+
+# MS-DOS file system, also used by Desqview/X.
+gp_dosfs.$(OBJ): gp_dosfs.c $(AK) $(dos__h) $(gp_h) $(gx_h)
+
+# MS-DOS file enumeration, *not* used by Desqview/X.
+gp_dosfe.$(OBJ): gp_dosfe.c $(AK) $(stdio__h) $(memory__h) $(string__h) \
+ $(dos__h) $(gstypes_h) $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h)
+
+# Other MS-DOS facilities.
+gp_msdos.$(OBJ): gp_msdos.c $(AK) $(dos__h) $(stdio__h) $(string__h)\
+ $(gsmemory_h) $(gstypes_h) $(gp_h)
+
+# Unix(-like) file system, also used by Desqview/X.
+gp_unifs.$(OBJ): gp_unifs.c $(AK) $(memory__h) $(string__h) $(gx_h) $(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+
+# Unix(-like) file name syntax, *not* used by Desqview/X.
+gp_unifn.$(OBJ): gp_unifn.c $(AK) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+# Main program for library testing
+
+gslib.$(OBJ): gslib.c $(AK) $(math__h) \
+ $(gx_h) $(gp_h) $(gserrors_h) $(gsmatrix_h) $(gsstate_h) $(gscspace_h) \
+ $(gscdefs_h) $(gscolor2_h) $(gscoord_h) $(gslib_h) $(gsparam_h) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxalloc_h) $(gxdevice_h)
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for language interpreters.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+INT_MAK=int.mak
+
+# ======================== Interpreter support ======================== #
+
+# This is support code for all interpreters, not just PostScript and PDF.
+# It knows about the PostScript data types, but isn't supposed to
+# depend on anything outside itself.
+
+errors_h=errors.h
+idebug_h=idebug.h
+idict_h=idict.h
+igc_h=igc.h
+igcstr_h=igcstr.h
+iname_h=iname.h
+inamedef_h=inamedef.h $(gconfigv_h) $(iname_h)
+ipacked_h=ipacked.h
+iref_h=iref.h
+isave_h=isave.h
+isstate_h=isstate.h
+istruct_h=istruct.h $(gsstruct_h)
+iutil_h=iutil.h
+ivmspace_h=ivmspace.h $(gsgc_h)
+opdef_h=opdef.h
+# Nested include files
+ghost_h=ghost.h $(gx_h) $(iref_h)
+imemory_h=imemory.h $(gsalloc_h) $(ivmspace_h)
+ialloc_h=ialloc.h $(imemory_h)
+iastruct_h=iastruct.h $(gxobj_h) $(ialloc_h)
+iastate_h=iastate.h $(gxalloc_h) $(ialloc_h) $(istruct_h)
+store_h=store.h $(ialloc_h)
+
+GH=$(AK) $(ghost_h)
+
+isupport1_=ialloc.$(OBJ) igc.$(OBJ) igcref.$(OBJ) igcstr.$(OBJ)
+isupport2_=ilocate.$(OBJ) iname.$(OBJ) isave.$(OBJ)
+isupport_=$(isupport1_) $(isupport2_)
+isupport.dev: $(INT_MAK) $(ECHOGS_XE) $(isupport_)
+ $(SETMOD) isupport $(isupport1_)
+ $(ADDMOD) isupport -obj $(isupport2_)
+ $(ADDMOD) isupport -init igcref
+
+ialloc.$(OBJ): ialloc.c $(AK) $(memory__h) $(gx_h)\
+ $(errors_h) $(gsstruct_h) $(gxarith_h)\
+ $(iastate_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+# igc.c, igcref.c, and igcstr.c should really be in the dpsand2 list,
+# but since all the GC enumeration and relocation routines refer to them,
+# it's too hard to separate them out from the Level 1 base.
+igc.$(OBJ): igc.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsmdebug_h) $(gsstruct_h) $(gsutil_h) \
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(inamedef_h) \
+ $(ipacked_h) $(isave_h) $(isstate_h) $(istruct_h) $(opdef_h)
+
+igcref.$(OBJ): igcref.c $(GH) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idebug_h) $(igc_h) $(iname_h) $(ipacked_h) $(store_h)
+
+igcstr.$(OBJ): igcstr.c $(GH) $(memory__h)\
+ $(gsmdebug_h) $(gsstruct_h) $(iastate_h) $(igcstr_h)
+
+ilocate.$(OBJ): ilocate.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(iname_h)\
+ $(ipacked_h) $(isstate_h) $(iutil_h) $(ivmspace_h)\
+ $(store_h)
+
+iname.$(OBJ): iname.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h) $(gxobj_h)\
+ $(errors_h) $(imemory_h) $(inamedef_h) $(isave_h) $(store_h)
+
+isave.$(OBJ): isave.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h) $(gsutil_h)\
+ $(iastate_h) $(inamedef_h) $(isave_h) $(isstate_h) $(ivmspace_h)\
+ $(ipacked_h) $(store_h)
+
+### Include files
+
+idparam_h=idparam.h
+ilevel_h=ilevel.h
+iparam_h=iparam.h $(gsparam_h)
+istack_h=istack.h
+iutil2_h=iutil2.h
+opcheck_h=opcheck.h
+opextern_h=opextern.h
+# Nested include files
+dstack_h=dstack.h $(istack_h)
+estack_h=estack.h $(istack_h)
+ostack_h=ostack.h $(istack_h)
+oper_h=oper.h $(iutil_h) $(opcheck_h) $(opdef_h) $(opextern_h) $(ostack_h)
+
+idebug.$(OBJ): idebug.c $(GH) $(string__h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(ostack_h) $(opdef_h) $(ipacked_h) $(store_h)
+
+idict.$(OBJ): idict.c $(GH) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idebug_h) $(ivmspace_h) $(inamedef_h) $(ipacked_h)\
+ $(isave_h) $(store_h) $(iutil_h) $(idict_h) $(dstack_h)
+
+idparam.$(OBJ): idparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(gsmatrix_h) $(gsuid_h)\
+ $(idict_h) $(idparam_h) $(ilevel_h) $(imemory_h) $(iname_h) $(iutil_h)\
+ $(oper_h) $(store_h)
+
+iparam.$(OBJ): iparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(iname_h) $(imemory_h) $(iparam_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(opcheck_h) $(store_h)
+
+istack.$(OBJ): istack.c $(GH) $(memory__h) \
+ $(errors_h) $(gsstruct_h) $(gsutil_h) \
+ $(ialloc_h) $(istack_h) $(istruct_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iutil.$(OBJ): iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\
+ $(gsccode_h) $(gsmatrix_h) $(gsutil_h) $(gxfont_h)\
+ $(errors_h) $(idict_h) $(imemory_h) $(iutil_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(oper_h) $(store_h)
+
+# ======================== PostScript Level 1 ======================== #
+
+###### Include files
+
+files_h=files.h
+fname_h=fname.h
+ichar_h=ichar.h
+icharout_h=icharout.h
+icolor_h=icolor.h
+icontext_h=icontext.h $(imemory_h) $(istack_h)
+icsmap_h=icsmap.h
+ifont_h=ifont.h $(gsccode_h) $(gsstruct_h)
+iht_h=iht.h
+iimage_h=iimage.h
+imain_h=imain.h $(gsexit_h)
+imainarg_h=imainarg.h
+iminst_h=iminst.h $(imain_h)
+interp_h=interp.h
+iparray_h=iparray.h
+iscannum_h=iscannum.h
+istream_h=istream.h
+main_h=main.h $(iminst_h)
+overlay_h=overlay.h
+sbwbs_h=sbwbs.h
+sfilter_h=sfilter.h $(gstypes_h)
+shcgen_h=shcgen.h
+smtf_h=smtf.h
+# Nested include files
+bfont_h=bfont.h $(ifont_h)
+ifilter_h=ifilter.h $(istream_h) $(ivmspace_h)
+igstate_h=igstate.h $(gsstate_h) $(gxstate_h) $(istruct_h)
+iscan_h=iscan.h $(sa85x_h) $(sstring_h)
+sbhc_h=sbhc.h $(shc_h)
+# Include files for optional features
+ibnum_h=ibnum.h
+
+### Initialization and scanning
+
+iconfig=iconfig$(CONFIG)
+$(iconfig).$(OBJ): iconf.c $(stdio__h) \
+ $(gconfig_h) $(gscdefs_h) $(gsmemory_h) \
+ $(files_h) $(iminst_h) $(iref_h) $(ivmspace_h) $(opdef_h) $(stream_h)
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) iconf.c $(iconfig).c
+ $(CCC) $(iconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+
+iinit.$(OBJ): iinit.c $(GH) $(string__h)\
+ $(gscdefs_h) $(gsexit_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h)\
+ $(ilevel_h) $(iname_h) $(interp_h) $(opdef_h)\
+ $(ipacked_h) $(iparray_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iscan.$(OBJ): iscan.c $(GH) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h) $(files_h)\
+ $(ilevel_h) $(iutil_h) $(iscan_h) $(iscannum_h) $(istruct_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(iparray_h) $(istream_h) $(ostack_h) $(store_h)\
+ $(stream_h) $(strimpl_h) $(sfilter_h) $(scanchar_h)
+
+iscannum.$(OBJ): iscannum.c $(GH) $(math__h)\
+ $(errors_h) $(iscannum_h) $(scanchar_h) $(scommon_h) $(store_h)
+
+### Streams
+
+sfilter1.$(OBJ): sfilter1.c $(AK) $(stdio__h) $(memory__h) \
+ $(sfilter_h) $(strimpl_h)
+
+###### Operators
+
+OP=$(GH) $(errors_h) $(oper_h)
+
+### Non-graphics operators
+
+zarith.$(OBJ): zarith.c $(OP) $(math__h) $(store_h)
+
+zarray.$(OBJ): zarray.c $(OP) $(memory__h) $(ialloc_h) $(ipacked_h) $(store_h)
+
+zcontrol.$(OBJ): zcontrol.c $(OP) $(string__h)\
+ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)
+
+zdict.$(OBJ): zdict.c $(OP) \
+ $(dstack_h) $(idict_h) $(ilevel_h) $(iname_h) $(ipacked_h) $(ivmspace_h) \
+ $(store_h)
+
+zfile.$(OBJ): zfile.c $(OP) $(memory__h) $(string__h) $(gp_h)\
+ $(gsstruct_h) $(gxiodev_h) \
+ $(ialloc_h) $(estack_h) $(files_h) $(fname_h) $(ilevel_h) $(interp_h) $(iutil_h)\
+ $(isave_h) $(main_h) $(sfilter_h) $(stream_h) $(strimpl_h) $(store_h)
+
+zfileio.$(OBJ): zfileio.c $(OP) $(gp_h) \
+ $(files_h) $(ifilter_h) $(store_h) $(stream_h) $(strimpl_h) \
+ $(gsmatrix_h) $(gxdevice_h) $(gxdevmem_h)
+
+zfilter.$(OBJ): zfilter.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sfilter_h) $(srlx_h) $(sstring_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zfname.$(OBJ): zfname.c $(OP) $(memory__h)\
+ $(fname_h) $(gxiodev_h) $(ialloc_h) $(stream_h)
+
+zfproc.$(OBJ): zfproc.c $(GH) $(memory__h)\
+ $(errors_h) $(oper_h)\
+ $(estack_h) $(files_h) $(gsstruct_h) $(ialloc_h) $(ifilter_h) $(istruct_h)\
+ $(store_h) $(stream_h) $(strimpl_h)
+
+zgeneric.$(OBJ): zgeneric.c $(OP) $(memory__h)\
+ $(idict_h) $(estack_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(store_h)
+
+ziodev.$(OBJ): ziodev.c $(OP) $(memory__h) $(stdio__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsstruct_h) $(gxiodev_h)\
+ $(files_h) $(ialloc_h) $(ivmspace_h) $(store_h) $(stream_h)
+
+zmath.$(OBJ): zmath.c $(OP) $(math__h) $(gxfarith_h) $(store_h)
+
+zmisc.$(OBJ): zmisc.c $(OP) $(gscdefs_h) $(gp_h) \
+ $(errno__h) $(memory__h) $(string__h) \
+ $(ialloc_h) $(idict_h) $(dstack_h) $(iname_h) $(ivmspace_h) $(ipacked_h) $(store_h)
+
+zpacked.$(OBJ): zpacked.c $(OP) \
+ $(ialloc_h) $(idict_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(iparray_h) \
+ $(istack_h) $(store_h)
+
+zrelbit.$(OBJ): zrelbit.c $(OP) $(gsutil_h) $(store_h) $(idict_h)
+
+zstack.$(OBJ): zstack.c $(OP) $(memory__h)\
+ $(ialloc_h) $(istack_h) $(store_h)
+
+zstring.$(OBJ): zstring.c $(OP) $(memory__h)\
+ $(gsutil_h)\
+ $(ialloc_h) $(iname_h) $(ivmspace_h) $(store_h)
+
+zsysvm.$(OBJ): zsysvm.c $(GH)\
+ $(ialloc_h) $(ivmspace_h) $(oper_h) $(store_h)
+
+ztoken.$(OBJ): ztoken.c $(OP) \
+ $(estack_h) $(files_h) $(gsstruct_h) $(iscan_h) \
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+ztype.$(OBJ): ztype.c $(OP) $(math__h) $(memory__h) $(string__h)\
+ $(dstack_h) $(idict_h) $(imemory_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zvmem.$(OBJ): zvmem.c $(OP)\
+ $(dstack_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(isave_h) $(store_h) $(stream_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h)
+
+### Graphics operators
+
+zchar.$(OBJ): zchar.c $(OP)\
+ $(gsstruct_h) $(gxarith_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxchar_h) $(gxdevice_h) $(gxfont_h) $(gzpath_h) $(gzstate_h)\
+ $(dstack_h) $(estack_h) $(ialloc_h) $(ichar_h) $(idict_h) $(ifont_h)\
+ $(ilevel_h) $(iname_h) $(igstate_h) $(ipacked_h) $(store_h)
+
+# zcharout is used for Type 1 and Type 42 fonts only.
+zcharout.$(OBJ): zcharout.c $(OP)\
+ $(gschar_h) $(gxdevice_h) $(gxfont_h)\
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h)\
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zcolor.$(OBJ): zcolor.c $(OP) \
+ $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gxdevice_h) $(gxcmap_h) \
+ $(ialloc_h) $(icolor_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zdevice.$(OBJ): zdevice.c $(OP) $(string__h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gxdevice_h) $(store_h)
+
+zfont.$(OBJ): zfont.c $(OP)\
+ $(gschar_h) $(gsstruct_h) $(gxdevice_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(isave_h) $(ivmspace_h)\
+ $(bfont_h) $(store_h)
+
+zfont2.$(OBJ): zfont2.c $(OP) $(memory__h) $(string__h)\
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(bfont_h) $(idict_h) $(idparam_h) $(ilevel_h) $(iname_h) $(istruct_h)\
+ $(ipacked_h) $(store_h)
+
+zgstate.$(OBJ): zgstate.c $(OP) $(math__h)\
+ $(gsmatrix_h) $(ialloc_h) $(idict_h) $(igstate_h) $(istruct_h) $(store_h)
+
+zht.$(OBJ): zht.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+zimage.$(OBJ): zimage.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ifilter_h) $(igstate_h) $(iimage_h) $(ilevel_h) \
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(store_h) $(stream_h)
+
+zmatrix.$(OBJ): zmatrix.c $(OP)\
+ $(gsmatrix_h) $(igstate_h) $(gscoord_h) $(store_h)
+
+zpaint.$(OBJ): zpaint.c $(OP)\
+ $(gspaint_h) $(igstate_h)
+
+zpath.$(OBJ): zpath.c $(OP) $(math__h) \
+ $(gsmatrix_h) $(gspath_h) $(igstate_h) $(store_h)
+
+# Define the base PostScript language interpreter.
+# This is the subset of PostScript Level 1 required by our PDF reader.
+
+INT1=idebug.$(OBJ) idict.$(OBJ) idparam.$(OBJ)
+INT2=iinit.$(OBJ) interp.$(OBJ) iparam.$(OBJ) ireclaim.$(OBJ)
+INT3=iscan.$(OBJ) iscannum.$(OBJ) istack.$(OBJ) iutil.$(OBJ)
+INT4=scantab.$(OBJ) sfilter1.$(OBJ) sstring.$(OBJ) stream.$(OBJ)
+Z1=zarith.$(OBJ) zarray.$(OBJ) zcontrol.$(OBJ) zdict.$(OBJ)
+Z1OPS=zarith zarray zcontrol zdict
+Z2=zfile.$(OBJ) zfileio.$(OBJ) zfilter.$(OBJ) zfname.$(OBJ) zfproc.$(OBJ)
+Z2OPS=zfile zfileio zfilter zfproc
+Z3=zgeneric.$(OBJ) ziodev.$(OBJ) zmath.$(OBJ) zmisc.$(OBJ) zpacked.$(OBJ)
+Z3OPS=zgeneric ziodev zmath zmisc zpacked
+Z4=zrelbit.$(OBJ) zstack.$(OBJ) zstring.$(OBJ) zsysvm.$(OBJ)
+Z4OPS=zrelbit zstack zstring zsysvm
+Z5=ztoken.$(OBJ) ztype.$(OBJ) zvmem.$(OBJ)
+Z5OPS=ztoken ztype zvmem
+Z6=zchar.$(OBJ) zcolor.$(OBJ) zdevice.$(OBJ) zfont.$(OBJ) zfont2.$(OBJ)
+Z6OPS=zchar zcolor zdevice zfont zfont2
+Z7=zgstate.$(OBJ) zht.$(OBJ) zimage.$(OBJ) zmatrix.$(OBJ) zpaint.$(OBJ) zpath.$(OBJ)
+Z7OPS=zgstate zht zimage zmatrix zpaint zpath
+# We have to be a little underhanded with *config.$(OBJ) so as to avoid
+# circular definitions.
+INT_OBJS=imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ) \
+ $(INT1) $(INT2) $(INT3) $(INT4) \
+ $(Z1) $(Z2) $(Z3) $(Z4) $(Z5) $(Z6) $(Z7)
+INT_CONFIG=$(gconfig).$(OBJ) $(gscdefs).$(OBJ) $(iconfig).$(OBJ) \
+ iccinit$(COMPILE_INITS).$(OBJ)
+INT_ALL=$(INT_OBJS) $(INT_CONFIG)
+# We omit libcore.dev, which should be included here, because problems
+# with the Unix linker require libcore to appear last in the link list
+# when libcore is really a library.
+# We omit $(INT_CONFIG) from the dependency list because they have special
+# dependency requirements and are added to the link list at the very end.
+# zfilter.c shouldn't include the RLE and RLD filters, but we don't want to
+# change this now.
+psbase.dev: $(INT_MAK) $(ECHOGS_XE) $(INT_OBJS)\
+ isupport.dev rld.dev rle.dev sfile.dev
+ $(SETMOD) psbase imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ)
+ $(ADDMOD) psbase -obj $(INT_CONFIG)
+ $(ADDMOD) psbase -obj $(INT1)
+ $(ADDMOD) psbase -obj $(INT2)
+ $(ADDMOD) psbase -obj $(INT3)
+ $(ADDMOD) psbase -obj $(INT4)
+ $(ADDMOD) psbase -obj $(Z1)
+ $(ADDMOD) psbase -oper $(Z1OPS)
+ $(ADDMOD) psbase -obj $(Z2)
+ $(ADDMOD) psbase -oper $(Z2OPS)
+ $(ADDMOD) psbase -obj $(Z3)
+ $(ADDMOD) psbase -oper $(Z3OPS)
+ $(ADDMOD) psbase -obj $(Z4)
+ $(ADDMOD) psbase -oper $(Z4OPS)
+ $(ADDMOD) psbase -obj $(Z5)
+ $(ADDMOD) psbase -oper $(Z5OPS)
+ $(ADDMOD) psbase -obj $(Z6)
+ $(ADDMOD) psbase -oper $(Z6OPS)
+ $(ADDMOD) psbase -obj $(Z7)
+ $(ADDMOD) psbase -oper $(Z7OPS)
+ $(ADDMOD) psbase -iodev stdin stdout stderr lineedit statementedit
+ $(ADDMOD) psbase -include isupport rld rle sfile
+
+# -------------------------- Feature definitions -------------------------- #
+
+# ---------------- Full Level 1 interpreter ---------------- #
+
+level1.dev: $(INT_MAK) $(ECHOGS_XE) psbase.dev bcp.dev hsb.dev path1.dev type1.dev
+ $(SETMOD) level1 -include psbase bcp hsb path1 type1
+ $(ADDMOD) level1 -emulator PostScript PostScriptLevel1
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+color.dev: $(INT_MAK) $(ECHOGS_XE) cmyklib.dev colimlib.dev cmykread.dev
+ $(SETMOD) color -include cmyklib colimlib cmykread
+
+cmykread_=zcolor1.$(OBJ) zht1.$(OBJ)
+cmykread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmykread_)
+ $(SETMOD) cmykread $(cmykread_)
+ $(ADDMOD) cmykread -oper zcolor1 zht1
+
+zcolor1.$(OBJ): zcolor1.c $(OP) \
+ $(gscolor1_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) \
+ $(ialloc_h) $(icolor_h) $(iimage_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zht1.$(OBJ): zht1.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h)\
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+# ---------------- HSB color ---------------- #
+
+hsb_=zhsb.$(OBJ)
+hsb.dev: $(INT_MAK) $(ECHOGS_XE) $(hsb_) hsblib.dev
+ $(SETMOD) hsb $(hsb_)
+ $(ADDMOD) hsb -include hsblib
+ $(ADDMOD) hsb -oper zhsb
+
+zhsb.$(OBJ): zhsb.c $(OP) \
+ $(gshsb_h) $(igstate_h) $(store_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1_=zpath1.$(OBJ)
+path1.dev: $(INT_MAK) $(ECHOGS_XE) $(path1_) path1lib.dev
+ $(SETMOD) path1 $(path1_)
+ $(ADDMOD) path1 -include path1lib
+ $(ADDMOD) path1 -oper zpath1
+
+zpath1.$(OBJ): zpath1.c $(OP) $(memory__h)\
+ $(ialloc_h) $(estack_h) $(gspath_h) $(gsstruct_h) $(igstate_h) $(store_h)
+
+# ================ Level-independent PostScript options ================ #
+
+# ---------------- BCP filters ---------------- #
+
+bcp_=sbcp.$(OBJ) zfbcp.$(OBJ)
+bcp.dev: $(INT_MAK) $(ECHOGS_XE) $(bcp_)
+ $(SETMOD) bcp $(bcp_)
+ $(ADDMOD) bcp -oper zfbcp
+
+sbcp.$(OBJ): sbcp.c $(AK) $(stdio__h) \
+ $(sfilter_h) $(strimpl_h)
+
+zfbcp.$(OBJ): zfbcp.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# ---------------- Incremental font loading ---------------- #
+# (This only works for Type 1 fonts without eexec encryption.)
+
+diskfont.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) diskfont -ps gs_diskf
+
+# ---------------- Double-precision floats ---------------- #
+
+double_=zdouble.$(OBJ)
+double.dev: $(INT_MAK) $(ECHOGS_XE) $(double_)
+ $(SETMOD) double $(double_)
+ $(ADDMOD) double -oper zdouble
+
+zdouble.$(OBJ): zdouble.c $(OP) $(ctype__h) $(math__h) $(memory__h) $(string__h) \
+ $(gxfarith_h) $(store_h)
+
+# ---------------- EPSF files with binary headers ---------------- #
+
+epsf.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) epsf -ps gs_epsf
+
+# ---------------- RasterOp ---------------- #
+# This should be a separable feature in the core also....
+
+rasterop.dev: $(INT_MAK) $(ECHOGS_XE) roplib.dev ropread.dev
+ $(SETMOD) rasterop -include roplib ropread
+
+ropread_=zrop.$(OBJ)
+ropread.dev: $(INT_MAK) $(ECHOGS_XE) $(ropread_)
+ $(SETMOD) ropread $(ropread_)
+ $(ADDMOD) ropread -oper zrop
+
+zrop.$(OBJ): zrop.c $(OP) $(memory__h)\
+ $(gsrop_h) $(gsutil_h) $(gxdevice_h)\
+ $(idict_h) $(idparam_h) $(igstate_h) $(store_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1.dev: $(INT_MAK) $(ECHOGS_XE) psf1lib.dev psf1read.dev
+ $(SETMOD) type1 -include psf1lib psf1read
+
+psf1read_=seexec.$(OBJ) zchar1.$(OBJ) zcharout.$(OBJ) zfont1.$(OBJ) zmisc1.$(OBJ)
+psf1read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf1read_)
+ $(SETMOD) psf1read $(psf1read_)
+ $(ADDMOD) psf1read -oper zchar1 zfont1 zmisc1
+ $(ADDMOD) psf1read -ps gs_type1
+
+seexec.$(OBJ): seexec.c $(AK) $(stdio__h) \
+ $(gscrypt1_h) $(scanchar_h) $(sfilter_h) $(strimpl_h)
+
+zchar1.$(OBJ): zchar1.c $(OP) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h) $(gzstate_h) \
+ $(estack_h) $(ialloc_h) $(ichar_h) $(icharout_h) \
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zfont1.$(OBJ): zfont1.c $(OP) \
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont1_h) \
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(store_h)
+
+zmisc1.$(OBJ): zmisc1.c $(OP) $(memory__h)\
+ $(gscrypt1_h)\
+ $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# -------------- Compact Font Format and Type 2 charstrings ------------- #
+
+cff.dev: $(INT_MAK) $(ECHOGS_XE) gs_cff.ps psl2int.dev
+ $(SETMOD) cff -ps gs_cff
+
+type2.dev: $(INT_MAK) $(ECHOGS_XE) type1.dev psf2lib.dev
+ $(SETMOD) type2 -include psf2lib
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+# Native TrueType support
+ttfont.dev: $(INT_MAK) $(ECHOGS_XE) type42.dev
+ $(SETMOD) ttfont -include type42
+ $(ADDMOD) ttfont -ps gs_mro_e gs_wan_e gs_ttf
+
+# Type 42 (embedded TrueType) support
+type42read_=zchar42.$(OBJ) zcharout.$(OBJ) zfont42.$(OBJ)
+type42.dev: $(INT_MAK) $(ECHOGS_XE) $(type42read_) ttflib.dev
+ $(SETMOD) type42 $(type42read_)
+ $(ADDMOD) type42 -include ttflib
+ $(ADDMOD) type42 -oper zchar42 zfont42
+ $(ADDMOD) type42 -ps gs_typ42
+
+zchar42.$(OBJ): zchar42.c $(OP) \
+ $(gsmatrix_h) $(gspaint_h) $(gspath_h) \
+ $(gxfixed_h) $(gxchar_h) $(gxfont_h) $(gxfont42_h) \
+ $(gxistate_h) $(gxpath_h) $(gzstate_h) \
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h) \
+ $(ifont_h) $(igstate_h) $(store_h)
+
+zfont42.$(OBJ): zfont42.c $(OP) \
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h) $(gxfont42_h) \
+ $(bfont_h) $(idict_h) $(idparam_h) $(store_h)
+
+# ======================== Precompilation options ======================== #
+
+# ---------------- Precompiled fonts ---------------- #
+# See fonts.txt for more information.
+
+ccfont_h=ccfont.h $(std_h) $(gsmemory_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+CCFONT=$(OP) $(ccfont_h)
+
+# List the fonts we are going to compile.
+# Because of intrinsic limitations in `make', we have to list
+# the object file names and the font names separately.
+# Because of limitations in the DOS shell, we have to break the fonts up
+# into lists that will fit on a single line (120 characters).
+# The rules for constructing the .c files from the fonts themselves,
+# and for compiling the .c files, are in cfonts.mak, not here.
+# For example, to compile the Courier fonts, you should invoke
+# make -f cfonts.mak Courier_o
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+ccfonts_ps=gs_ccfnt
+ccfonts1_=0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+ccfonts1=agk agko agd agdo
+ccfonts2_=0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+ccfonts2=bkl bkli bkd bkdi
+ccfonts3_=0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+ccfonts3=crr cri crb crbi
+ccfonts4_=0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ)
+ccfonts4=hvr hvro hvb hvbo
+ccfonts5_=0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+ccfonts5=hvrrn hvrorn hvbrn hvborn
+ccfonts6_=0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+ccfonts6=ncr ncri ncb ncbi
+ccfonts7_=0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+ccfonts7=plr plri plb plbi
+ccfonts8_=0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+ccfonts8=tmr tmri tmb tmbi
+ccfonts9_=0syr.$(OBJ) 0zcmi.$(OBJ) 0zdr.$(OBJ)
+ccfonts9=syr zcmi zdr
+# The free distribution includes Bitstream Charter, Utopia, and
+# freeware Cyrillic and Kana fonts. We only provide for compiling
+# Charter and Utopia.
+ccfonts10free_=bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+ccfonts10free=chr chri chb chbi
+ccfonts11free_=putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+ccfonts11free=utr utri utb utbi
+# Uncomment the alternatives in the next 4 lines if you want
+# Charter and Utopia compiled in.
+#ccfonts10_=$(ccfonts10free_)
+ccfonts10_=
+#ccfonts10=$(ccfonts10free)
+ccfonts10=
+#ccfonts11_=$(ccfonts11free_)
+ccfonts11_=
+#ccfonts11=$(ccfonts11free)
+ccfonts11=
+# Add your own fonts here if desired.
+ccfonts12_=
+ccfonts12=
+ccfonts13_=
+ccfonts13=
+ccfonts14_=
+ccfonts14=
+ccfonts15_=
+ccfonts15=
+
+# It's OK for ccfonts_.dev not to be CONFIG-dependent, because it only
+# exists during the execution of the following rule.
+# font2c has the prefix "gs" built into it, so we need to instruct
+# genconf to use the same one.
+$(gconfigf_h): $(MAKEFILE) $(INT_MAK) $(GENCONF_XE)
+ $(SETMOD) ccfonts_ -font $(ccfonts1)
+ $(ADDMOD) ccfonts_ -font $(ccfonts2)
+ $(ADDMOD) ccfonts_ -font $(ccfonts3)
+ $(ADDMOD) ccfonts_ -font $(ccfonts4)
+ $(ADDMOD) ccfonts_ -font $(ccfonts5)
+ $(ADDMOD) ccfonts_ -font $(ccfonts6)
+ $(ADDMOD) ccfonts_ -font $(ccfonts7)
+ $(ADDMOD) ccfonts_ -font $(ccfonts8)
+ $(ADDMOD) ccfonts_ -font $(ccfonts9)
+ $(ADDMOD) ccfonts_ -font $(ccfonts10)
+ $(ADDMOD) ccfonts_ -font $(ccfonts11)
+ $(ADDMOD) ccfonts_ -font $(ccfonts12)
+ $(ADDMOD) ccfonts_ -font $(ccfonts13)
+ $(ADDMOD) ccfonts_ -font $(ccfonts14)
+ $(ADDMOD) ccfonts_ -font $(ccfonts15)
+ $(EXP)genconf ccfonts_.dev -n gs -f $(gconfigf_h)
+
+# We separate icfontab.dev from ccfonts.dev so that a customer can put
+# compiled fonts into a separate shared library.
+
+icfontab=icfontab$(CONFIG)
+
+# Define ccfont_table separately, so it can be set from the command line
+# to select an alternate compiled font table.
+ccfont_table=$(icfontab)
+
+$(icfontab).dev: $(MAKEFILE) $(INT_MAK) $(ECHOGS_XE) $(icfontab).$(OBJ) \
+ $(ccfonts1_) $(ccfonts2_) $(ccfonts3_) $(ccfonts4_) $(ccfonts5_) \
+ $(ccfonts6_) $(ccfonts7_) $(ccfonts8_) $(ccfonts9_) $(ccfonts10_) \
+ $(ccfonts11_) $(ccfonts12_) $(ccfonts13_) $(ccfonts14_) $(ccfonts15_)
+ $(SETMOD) $(icfontab) -obj $(icfontab).$(OBJ)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts1_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts2_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts3_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts4_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts5_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts6_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts7_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts8_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts9_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts10_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts11_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts12_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts13_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts14_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts15_)
+
+$(icfontab).$(OBJ): icfontab.c $(AK) $(ccfont_h) $(gconfigf_h)
+ $(CP_) $(gconfigf_h) gconfigf.h
+ $(CCCF) icfontab.c
+
+# Strictly speaking, ccfonts shouldn't need to include type1,
+# since one could choose to precompile only Type 0 fonts,
+# but getting this exactly right would be too much work.
+ccfonts=ccfonts$(CONFIG)
+$(ccfonts).dev: $(MAKEFILE) $(INT_MAK) type1.dev iccfont.$(OBJ) \
+ $(ccfont_table).dev
+ $(SETMOD) $(ccfonts) -include type1
+ $(ADDMOD) $(ccfonts) -include $(ccfont_table)
+ $(ADDMOD) $(ccfonts) -obj iccfont.$(OBJ)
+ $(ADDMOD) $(ccfonts) -oper ccfonts
+ $(ADDMOD) $(ccfonts) -ps $(ccfonts_ps)
+
+iccfont.$(OBJ): iccfont.c $(GH) $(string__h)\
+ $(gsstruct_h) $(ccfont_h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(ifont_h) $(iname_h) $(isave_h) $(iutil_h)\
+ $(oper_h) $(ostack_h) $(store_h) $(stream_h) $(strimpl_h) $(sfilter_h) $(iscan_h)
+ $(CCCF) iccfont.c
+
+# ---------------- Compiled initialization code ---------------- #
+
+# We select either iccinit0 or iccinit1 depending on COMPILE_INITS.
+
+iccinit0.$(OBJ): iccinit0.c $(stdpre_h)
+ $(CCCF) iccinit0.c
+
+iccinit1.$(OBJ): gs_init.$(OBJ)
+ $(CP_) gs_init.$(OBJ) iccinit1.$(OBJ)
+
+# All the gs_*.ps files should be prerequisites of gs_init.c,
+# but we don't have any convenient list of them.
+gs_init.c: $(GS_INIT) $(GENINIT_XE) $(gconfig_h)
+ $(EXP)geninit $(GS_INIT) $(gconfig_h) -c gs_init.c
+
+gs_init.$(OBJ): gs_init.c $(stdpre_h)
+ $(CCCF) gs_init.c
+
+# ======================== PostScript Level 2 ======================== #
+
+level2.dev: $(INT_MAK) $(ECHOGS_XE) \
+ cidfont.dev cie.dev cmapread.dev compfont.dev dct.dev devctrl.dev dpsand2.dev\
+ filter.dev level1.dev pattern.dev psl2lib.dev psl2read.dev sepr.dev\
+ type42.dev xfilter.dev
+ $(SETMOD) level2 -include cidfont cie cmapread compfont
+ $(ADDMOD) level2 -include dct devctrl dpsand2 filter
+ $(ADDMOD) level2 -include level1 pattern psl2lib psl2read
+ $(ADDMOD) level2 -include sepr type42 xfilter
+ $(ADDMOD) level2 -emulator PostScript PostScriptLevel2
+
+# Define basic Level 2 language support.
+# This is the minimum required for CMap and CIDFont support.
+
+psl2int_=iutil2.$(OBJ) zmisc2.$(OBJ) zusparam.$(OBJ)
+psl2int.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2int_) dps2int.dev
+ $(SETMOD) psl2int $(psl2int_)
+ $(ADDMOD) psl2int -include dps2int
+ $(ADDMOD) psl2int -oper zmisc2 zusparam
+ $(ADDMOD) psl2int -ps gs_lev2 gs_res
+
+iutil2.$(OBJ): iutil2.c $(GH) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsutil_h)\
+ $(errors_h) $(opcheck_h) $(imemory_h) $(iutil_h) $(iutil2_h)
+
+zmisc2.$(OBJ): zmisc2.c $(OP) $(memory__h) $(string__h)\
+ $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(ilevel_h) $(iname_h) $(iutil2_h) $(ivmspace_h) $(store_h)
+
+# Note that zusparam includes both Level 1 and Level 2 operators.
+zusparam.$(OBJ): zusparam.c $(OP) $(memory__h) $(string__h)\
+ $(gscdefs_h) $(gsfont_h) $(gsstruct_h) $(gsutil_h) $(gxht_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(iname_h) $(iutil2_h) $(store_h)
+
+# Define full Level 2 support.
+
+psl2read_=zcolor2.$(OBJ) zcsindex.$(OBJ) zht2.$(OBJ) zimage2.$(OBJ)
+# Note that zmisc2 includes both Level 1 and Level 2 operators.
+psl2read.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2read_) psl2int.dev dps2read.dev
+ $(SETMOD) psl2read $(psl2read_)
+ $(ADDMOD) psl2read -include psl2int dps2read
+ $(ADDMOD) psl2read -oper zcolor2_l2 zcsindex_l2
+ $(ADDMOD) psl2read -oper zht2_l2 zimage2_l2
+
+zcolor2.$(OBJ): zcolor2.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+zcsindex.$(OBJ): zcsindex.c $(OP) $(memory__h) \
+ $(gscolor_h) $(gsstruct_h) $(gxfixed_h) $(gxcolor2_h) $(gxcspace_h) $(gsmatrix_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zht2.$(OBJ): zht2.c $(OP) \
+ $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(estack_h) $(ialloc_h) $(icolor_h) $(idict_h) $(idparam_h) $(igstate_h) \
+ $(iht_h) $(store_h)
+
+zimage2.$(OBJ): zimage2.c $(OP) $(math__h) $(memory__h)\
+ $(gscolor_h) $(gscolor2_h) $(gscspace_h) $(gsimage_h) $(gsmatrix_h)\
+ $(idict_h) $(idparam_h) $(iimage_h) $(ilevel_h) $(igstate_h)
+
+# ---------------- Device control ---------------- #
+# This is a catch-all for setpagedevice and IODevices.
+
+devctrl_=zdevice2.$(OBJ) ziodev2.$(OBJ) zmedia2.$(OBJ) zdevcal.$(OBJ)
+devctrl.dev: $(INT_MAK) $(ECHOGS_XE) $(devctrl_)
+ $(SETMOD) devctrl $(devctrl_)
+ $(ADDMOD) devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+ $(ADDMOD) devctrl -iodev null ram calendar
+ $(ADDMOD) devctrl -ps gs_setpd
+
+zdevice2.$(OBJ): zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(store_h)\
+ $(gxdevice_h) $(gsstate_h)
+
+ziodev2.$(OBJ): ziodev2.c $(OP) $(string__h) $(gp_h)\
+ $(gxiodev_h) $(stream_h) $(files_h) $(iparam_h) $(iutil2_h) $(store_h)
+
+zmedia2.$(OBJ): zmedia2.c $(OP) $(math__h) $(memory__h) \
+ $(gsmatrix_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+
+zdevcal.$(OBJ): zdevcal.c $(GH) $(time__h) \
+ $(gxiodev_h) $(iparam_h) $(istack_h)
+
+# ---------------- Filters other than the ones in sfilter.c ---------------- #
+
+# Standard Level 2 decoding filters only. The PDF configuration uses this.
+fdecode_=scantab.$(OBJ) sfilter2.$(OBJ) zfdecode.$(OBJ)
+fdecode.dev: $(INT_MAK) $(ECHOGS_XE) $(fdecode_) cfd.dev lzwd.dev pdiff.dev pngp.dev rld.dev
+ $(SETMOD) fdecode $(fdecode_)
+ $(ADDMOD) fdecode -include cfd lzwd pdiff pngp rld
+ $(ADDMOD) fdecode -oper zfdecode
+
+zfdecode.$(OBJ): zfdecode.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sa85x_h) $(scf_h) $(scfx_h) $(sfilter_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) \
+ $(store_h) $(stream_h) $(strimpl_h)
+
+# Complete Level 2 filter capability.
+filter_=zfilter2.$(OBJ)
+filter.dev: $(INT_MAK) $(ECHOGS_XE) fdecode.dev $(filter_) cfe.dev lzwe.dev rle.dev
+ $(SETMOD) filter -include fdecode
+ $(ADDMOD) filter -obj $(filter_)
+ $(ADDMOD) filter -include cfe lzwe rle
+ $(ADDMOD) filter -oper zfilter2
+
+zfilter2.$(OBJ): zfilter2.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(store_h) \
+ $(sfilter_h) $(scfx_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) $(strimpl_h)
+
+# Extensions beyond Level 2 standard.
+xfilter_=sbhc.$(OBJ) sbwbs.$(OBJ) shcgen.$(OBJ) smtf.$(OBJ) \
+ zfilterx.$(OBJ)
+xfilter.dev: $(INT_MAK) $(ECHOGS_XE) $(xfilter_) pcxd.dev pngp.dev
+ $(SETMOD) xfilter $(xfilter_)
+ $(ADDMOD) xfilter -include pcxd
+ $(ADDMOD) xfilter -oper zfilterx
+
+sbhc.$(OBJ): sbhc.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(sbhc_h) $(shcgen_h) $(strimpl_h)
+
+sbwbs.$(OBJ): sbwbs.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(sbwbs_h) $(sfilter_h) $(strimpl_h)
+
+shcgen.$(OBJ): shcgen.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gserror_h) $(gserrors_h) $(gsmemory_h)\
+ $(scommon_h) $(shc_h) $(shcgen_h)
+
+smtf.$(OBJ): smtf.c $(AK) $(stdio__h) \
+ $(smtf_h) $(strimpl_h)
+
+zfilterx.$(OBJ): zfilterx.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(store_h) $(sfilter_h) $(sbhc_h) $(sbtx_h) $(sbwbs_h) $(shcgen_h)\
+ $(smtf_h) $(spcxx_h) $(strimpl_h)
+
+# ---------------- Binary tokens ---------------- #
+
+btoken_=iscanbin.$(OBJ) zbseq.$(OBJ)
+btoken.dev: $(INT_MAK) $(ECHOGS_XE) $(btoken_)
+ $(SETMOD) btoken $(btoken_)
+ $(ADDMOD) btoken -oper zbseq_l2
+ $(ADDMOD) btoken -ps gs_btokn
+
+bseq_h=bseq.h
+btoken_h=btoken.h
+
+iscanbin.$(OBJ): iscanbin.c $(GH) $(math__h) $(memory__h) $(errors_h)\
+ $(gsutil_h) $(ialloc_h) $(ibnum_h) $(idict_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(ivmspace_h)\
+ $(bseq_h) $(btoken_h) $(dstack_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zbseq.$(OBJ): zbseq.c $(OP) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(isave_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)\
+ $(iname_h) $(ibnum_h) $(btoken_h) $(bseq_h)
+
+# ---------------- User paths & insideness testing ---------------- #
+
+upath_=zupath.$(OBJ) ibnum.$(OBJ)
+upath.dev: $(INT_MAK) $(ECHOGS_XE) $(upath_)
+ $(SETMOD) upath $(upath_)
+ $(ADDMOD) upath -oper zupath_l2
+
+zupath.$(OBJ): zupath.c $(OP) \
+ $(idict_h) $(dstack_h) $(iutil_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h) \
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstate_h) \
+ $(gxfixed_h) $(gxdevice_h) $(gzpath_h) $(gzstate_h)
+
+# -------- Additions common to Display PostScript and Level 2 -------- #
+
+dpsand2.dev: $(INT_MAK) $(ECHOGS_XE) btoken.dev color.dev upath.dev dps2lib.dev dps2read.dev
+ $(SETMOD) dpsand2 -include btoken color upath dps2lib dps2read
+
+dps2int_=zvmem2.$(OBJ) zdps1.$(OBJ)
+# Note that zvmem2 includes both Level 1 and Level 2 operators.
+dps2int.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2int_)
+ $(SETMOD) dps2int $(dps2int_)
+ $(ADDMOD) dps2int -oper zvmem2 zdps1_l2
+ $(ADDMOD) dps2int -ps gs_dps1
+
+dps2read_=ibnum.$(OBJ) zchar2.$(OBJ)
+dps2read.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2read_) dps2int.dev
+ $(SETMOD) dps2read $(dps2read_)
+ $(ADDMOD) dps2read -include dps2int
+ $(ADDMOD) dps2read -oper ireclaim_l2 zchar2_l2
+ $(ADDMOD) dps2read -ps gs_dps2
+
+ibnum.$(OBJ): ibnum.c $(GH) $(math__h) $(memory__h)\
+ $(errors_h) $(stream_h) $(ibnum_h) $(imemory_h) $(iutil_h)
+
+zchar2.$(OBJ): zchar2.c $(OP)\
+ $(gschar_h) $(gsmatrix_h) $(gspath_h) $(gsstruct_h)\
+ $(gxchar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(ichar_h) $(estack_h) $(ifont_h) $(iname_h) $(igstate_h)\
+ $(store_h) $(stream_h) $(ibnum_h)
+
+zdps1.$(OBJ): zdps1.c $(OP) \
+ $(gsmatrix_h) $(gspath_h) $(gspath2_h) $(gsstate_h) \
+ $(ialloc_h) $(ivmspace_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h)
+
+zvmem2.$(OBJ): zvmem2.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Display PostScript ---------------- #
+
+dps_=zdps.$(OBJ) icontext.$(OBJ) zcontext.$(OBJ)
+dps.dev: $(INT_MAK) $(ECHOGS_XE) dpslib.dev level2.dev $(dps_)
+ $(SETMOD) dps -include dpslib level2
+ $(ADDMOD) dps -obj $(dps_)
+ $(ADDMOD) dps -oper zcontext zdps
+ $(ADDMOD) dps -ps gs_dps
+
+icontext.$(OBJ): icontext.c $(GH)\
+ $(gsstruct_h) $(gxalloc_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(ostack_h)\
+ $(icontext_h) $(igstate_h) $(interp_h) $(store_h)
+
+zdps.$(OBJ): zdps.c $(OP)\
+ $(gsdps_h) $(gsstate_h) $(igstate_h) $(iname_h) $(store_h)
+
+zcontext.$(OBJ): zcontext.c $(OP) $(gp_h) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h) $(gsutil_h) $(gxalloc_h)\
+ $(icontext_h) $(idict_h) $(igstate_h) $(istruct_h)\
+ $(dstack_h) $(estack_h) $(ostack_h) $(store_h)
+
+# The following #ifdef ... #endif are just a comment to mark a DPNEXT area.
+#ifdef DPNEXT
+
+# ---------------- NeXT Display PostScript ---------------- #
+#**************** NOT READY FOR USE YET ****************#
+
+# There should be a gsdpnext.c, but there isn't yet.
+#dpsnext_=zdpnext.$(OBJ) gsdpnext.$(OBJ)
+dpsnext_=zdpnext.$(OBJ)
+dpsnext.dev: $(INT_MAK) $(ECHOGS_XE) dps.dev $(dpsnext_) gs_dpnxt.ps
+ $(SETMOD) dpsnext -include dps
+ $(ADDMOD) dpsnext -obj $(dpsnext_)
+ $(ADDMOD) dpsnext -oper zdpnext
+ $(ADDMOD) dpsnext -ps gs_dpnxt
+
+zdpnext.$(OBJ): zdpnext.c $(OP)\
+ $(gscspace_h) $(gsiparam_h) $(gsmatrix_h) $(gxcvalue_h) $(gxsample_h)\
+ $(ialloc_h) $(igstate_h) $(iimage_h)
+
+# See above re the following.
+#endif /* DPNEXT */
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+compfont.dev: $(INT_MAK) $(ECHOGS_XE) psf0lib.dev psf0read.dev
+ $(SETMOD) compfont -include psf0lib psf0read
+
+# We always include zfcmap.$(OBJ) because zfont0.c refers to it,
+# and it's not worth the trouble to exclude.
+psf0read_=zchar2.$(OBJ) zfcmap.$(OBJ) zfont0.$(OBJ)
+psf0read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf0read_)
+ $(SETMOD) psf0read $(psf0read_)
+ $(ADDMOD) psf0read -oper zfont0 zchar2 zfcmap
+
+zfcmap.$(OBJ): zfcmap.c $(OP)\
+ $(gsmatrix_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxfcmap_h) $(gxfont_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifont_h) $(iname_h) $(store_h)
+
+zfont0.$(OBJ): zfont0.c $(OP)\
+ $(gschar_h) $(gsstruct_h)\
+ $(gxdevice_h) $(gxfcmap_h) $(gxfixed_h) $(gxfont_h) $(gxfont0_h) $(gxmatrix_h)\
+ $(gzstate_h)\
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h)\
+ $(store_h)
+
+# ---------------- CMap support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cmapread_=zfcmap.$(OBJ)
+cmapread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmapread_) cmaplib.dev psl2int.dev
+ $(SETMOD) cmapread $(cmapread_)
+ $(ADDMOD) cmapread -include cmaplib psl2int
+ $(ADDMOD) cmapread -oper zfcmap
+ $(ADDMOD) cmapread -ps gs_cmap
+
+# ---------------- CIDFont support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cidread_=zcid.$(OBJ)
+cidfont.dev: $(INT_MAK) $(ECHOGS_XE) psf1read.dev psl2int.dev type42.dev\
+ $(cidread_)
+ $(SETMOD) cidfont $(cidread_)
+ $(ADDMOD) cidfont -include psf1read psl2int type42
+ $(ADDMOD) cidfont -ps gs_cidfn
+ $(ADDMOD) cidfont -oper zcid
+
+zcid.$(OBJ): zcid.c $(OP)\
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h)\
+ $(bfont_h) $(iname_h) $(store_h)
+
+# ---------------- CIE color ---------------- #
+
+cieread_=zcie.$(OBJ) zcrd.$(OBJ)
+cie.dev: $(INT_MAK) $(ECHOGS_XE) $(cieread_) cielib.dev
+ $(SETMOD) cie $(cieread_)
+ $(ADDMOD) cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) cie -include cielib
+
+icie_h=icie.h
+
+zcie.$(OBJ): zcie.c $(OP) $(math__h) $(memory__h) \
+ $(gscolor2_h) $(gscie_h) $(gsstruct_h) $(gxcspace_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zcrd.$(OBJ): zcrd.c $(OP) $(math__h) \
+ $(gscspace_h) $(gscolor2_h) $(gscie_h) $(gsstruct_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Pattern color ---------------- #
+
+pattern.dev: $(INT_MAK) $(ECHOGS_XE) patlib.dev patread.dev
+ $(SETMOD) pattern -include patlib patread
+
+patread_=zpcolor.$(OBJ)
+patread.dev: $(INT_MAK) $(ECHOGS_XE) $(patread_)
+ $(SETMOD) patread $(patread_)
+ $(ADDMOD) patread -oper zpcolor_l2
+
+zpcolor.$(OBJ): zpcolor.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+# ---------------- Separation color ---------------- #
+
+seprread_=zcssepr.$(OBJ)
+sepr.dev: $(INT_MAK) $(ECHOGS_XE) $(seprread_) seprlib.dev
+ $(SETMOD) sepr $(seprread_)
+ $(ADDMOD) sepr -oper zcssepr_l2
+ $(ADDMOD) sepr -include seprlib
+
+zcssepr.$(OBJ): zcssepr.c $(OP) \
+ $(gscolor_h) $(gscsepr_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Functions ---------------- #
+
+ifunc_h=ifunc.h
+
+# Generic support, and FunctionType 0.
+funcread_=zfunc.$(OBJ) zfunc0.$(OBJ)
+func.dev: $(INT_MAK) $(ECHOGS_XE) $(funcread_) funclib.dev
+ $(SETMOD) func $(funcread_)
+ $(ADDMOD) func -oper zfunc zfunc0
+ $(ADDMOD) func -include funclib
+
+zfunc.$(OBJ): zfunc.c $(OP) $(memory__h)\
+ $(gsfunc_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h) $(store_h)
+
+zfunc0.$(OBJ): zfunc0.c $(OP) $(memory__h)\
+ $(gsdsrc_h) $(gsfunc_h) $(gsfunc0_h)\
+ $(stream_h)\
+ $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)
+
+# ---------------- DCT filters ---------------- #
+# The definitions for jpeg*.dev are in jpeg.mak.
+
+dct.dev: $(INT_MAK) $(ECHOGS_XE) dcte.dev dctd.dev
+ $(SETMOD) dct -include dcte dctd
+
+# Common code
+
+dctc_=zfdctc.$(OBJ)
+
+zfdctc.$(OBJ): zfdctc.c $(GH) $(memory__h) $(stdio__h)\
+ $(errors_h) $(opcheck_h)\
+ $(idict_h) $(idparam_h) $(imemory_h) $(ipacked_h) $(iutil_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h)\
+ jpeglib.h
+
+# Encoding (compression)
+
+dcte_=$(dctc_) zfdcte.$(OBJ)
+dcte.dev: $(INT_MAK) $(ECHOGS_XE) sdcte.dev $(dcte_)
+ $(SETMOD) dcte -include sdcte
+ $(ADDMOD) dcte -obj $(dcte_)
+ $(ADDMOD) dcte -oper zfdcte
+
+zfdcte.$(OBJ): zfdcte.c $(OP) $(memory__h) $(stdio__h)\
+ $(idict_h) $(idparam_h) $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# Decoding (decompression)
+
+dctd_=$(dctc_) zfdctd.$(OBJ)
+dctd.dev: $(INT_MAK) $(ECHOGS_XE) sdctd.dev $(dctd_)
+ $(SETMOD) dctd -include sdctd
+ $(ADDMOD) dctd -obj $(dctd_)
+ $(ADDMOD) dctd -oper zfdctd
+
+zfdctd.$(OBJ): zfdctd.c $(OP) $(memory__h) $(stdio__h)\
+ $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# ---------------- zlib/Flate filters ---------------- #
+
+fzlib.dev: $(INT_MAK) $(ECHOGS_XE) zfzlib.$(OBJ) szlibe.dev szlibd.dev
+ $(SETMOD) fzlib -include szlibe szlibd
+ $(ADDMOD) fzlib -obj zfzlib.$(OBJ)
+ $(ADDMOD) fzlib -oper zfzlib
+
+zfzlib.$(OBJ): zfzlib.c $(OP) \
+ $(errors_h) $(idict_h) $(ifilter_h) \
+ $(spdiffx_h) $(spngpx_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) zfzlib.c
+
+# ================================ PDF ================================ #
+
+# We need most of the Level 2 interpreter to do PDF, but not all of it.
+# In fact, we don't even need all of a Level 1 interpreter.
+
+# Because of the way the PDF encodings are defined, they must get loaded
+# before we install the Level 2 resource machinery.
+# On the other hand, the PDF .ps files must get loaded after
+# level2dict is defined.
+pdfmin.dev: $(INT_MAK) $(ECHOGS_XE)\
+ psbase.dev color.dev dps2lib.dev dps2read.dev\
+ fdecode.dev type1.dev pdffonts.dev psl2lib.dev psl2read.dev pdfread.dev
+ $(SETMOD) pdfmin -include psbase color dps2lib dps2read
+ $(ADDMOD) pdfmin -include fdecode type1
+ $(ADDMOD) pdfmin -include pdffonts psl2lib psl2read pdfread
+ $(ADDMOD) pdfmin -emulator PDF
+
+pdf.dev: $(INT_MAK) $(ECHOGS_XE)\
+ pdfmin.dev cff.dev cidfont.dev cie.dev compfont.dev cmapread.dev dctd.dev\
+ func.dev ttfont.dev type2.dev
+ $(SETMOD) pdf -include pdfmin cff cidfont cie cmapread compfont dctd
+ $(ADDMOD) pdf -include func ttfont type2
+
+# Reader only
+
+pdffonts.dev: $(INT_MAK) $(ECHOGS_XE) \
+ gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps
+ $(SETMOD) pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+
+# pdf_2ps must be the last .ps file loaded.
+pdfread.dev: $(INT_MAK) $(ECHOGS_XE) fzlib.dev
+ $(SETMOD) pdfread -include fzlib
+ $(ADDMOD) pdfread -ps gs_pdf gs_l2img
+ $(ADDMOD) pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+ $(ADDMOD) pdfread -ps pdf_2ps
+
+# ============================= Main program ============================== #
+
+gs.$(OBJ): gs.c $(GH) \
+ $(imain_h) $(imainarg_h) $(iminst_h)
+
+imainarg.$(OBJ): imainarg.c $(GH) $(ctype__h) $(memory__h) $(string__h) \
+ $(gp_h) \
+ $(gsargs_h) $(gscdefs_h) $(gsdevice_h) $(gsmdebug_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(errors_h) $(estack_h) $(files_h) \
+ $(ialloc_h) $(imain_h) $(imainarg_h) $(iminst_h) \
+ $(iname_h) $(interp_h) $(iscan_h) $(iutil_h) $(ivmspace_h) \
+ $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+imain.$(OBJ): imain.c $(GH) $(memory__h) $(string__h)\
+ $(gp_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h) $(gxdevice_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(interp_h)\
+ $(isave_h) $(iscan_h) $(ivmspace_h)\
+ $(main_h) $(oper_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+interp.$(OBJ): interp.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(iastruct_h) $(inamedef_h) $(idict_h) $(interp_h) $(ipacked_h)\
+ $(iscan_h) $(isave_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(oper_h) $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(CCINT) interp.c
+
+ireclaim.$(OBJ): ireclaim.c $(GH) \
+ $(errors_h) $(gsstruct_h) $(iastate_h) $(opdef_h) $(store_h) \
+ $(dstack_h) $(estack_h) $(ostack_h)
+# Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Independent JPEG Group library code.
+
+# NOTE: This makefile is only known to work with the following versions
+# of the IJG library: 6, 6a.
+# As of May 11, 1996, version 6a is the current version.
+#
+# You can get the IJG library by Internet anonymous FTP from the following
+# places:
+# Standard distribution (tar + gzip format, Unix end-of-line):
+# ftp.uu.net:/graphics/jpeg/jpegsrc.v*.tar.gz
+# ftp.cs.wisc.edu:/ghost/jpegsrc.v*.tar.gz
+# MS-DOS archive (PKZIP a.k.a. zip format, MS-DOS end-of-line):
+# ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr*.zip
+# ftp.cs.wisc.edu:/ghost/jpeg-*.zip
+# The first site named above (ftp.uu.net and ftp.simtel.net) is supposed
+# to be the master distribution site, so it may have a more up-to-date
+# version; the ftp.cs.wisc.edu site is the master distribution site for
+# Ghostscript, so it will always have IJG library versions known to be
+# compatible with Ghostscript.
+#
+# If the version number, and hence the subdirectory name, changes, you
+# will probably want to change the definitions of JSRCDIR and possibly
+# JVERSION (in the platform-specific makefile, not here) to reflect this,
+# since that way you can use the IJG archive without change.
+#
+# NOTE: For some obscure reason (probably a bug in djtarx), if you are
+# compiling on a DesqView/X system, you should use the zip version of the
+# IJG library, not the tar.gz version.
+
+# Define the name of this makefile.
+JPEG_MAK=jpeg.mak
+
+# JSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the IJG library sources are stored.
+#JSRCDIR=jpeg-6a
+# JVERSION is defined in the platform-specific makefile, not here,
+# as the IJG library major version number (currently "5" or "6").
+#JVERSION=6
+
+JSRC=$(JSRCDIR)$(D)
+# CCCJ is defined in gs.mak.
+#CCCJ=$(CCC) -I. -I$(JSRCDIR)
+
+# We keep all of the IJG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+# However, we need our own version of jconfig.h, and our own "wrapper" for
+# jmorecfg.h. We also need a substitute for jerror.c, in order to
+# keep the error strings out of the automatic data segment in
+# 16-bit environments. For v5*, we also need our own version of jpeglib.h
+# in order to change MAX_BLOCKS_IN_MCU for Adobe compatibility.
+# (This need will go away when IJG v6 is released.)
+
+# Because this file is included after lib.mak, we can't use _h macros
+# to express indirect dependencies; instead, we build the dependencies
+# into the rules for copying the files.
+jconfig_h=jconfig.h
+jerror_h=jerror.h
+jmorecfg_h=jmorecfg.h
+jpeglib_h=jpeglib.h
+
+jconfig.h: gsjconf.h $(std_h)
+ $(CP_) gsjconf.h jconfig.h
+
+jmorecfg.h: gsjmorec.h jmcorig.h
+ $(CP_) gsjmorec.h jmorecfg.h
+
+jmcorig.h: $(JSRC)jmorecfg.h
+ $(CP_) $(JSRC)jmorecfg.h jmcorig.h
+
+jpeglib.h: jlib$(JVERSION).h jconfig.h jmorecfg.h
+ $(CP_) jlib$(JVERSION).h jpeglib.h
+
+jlib5.h: gsjpglib.h
+ $(CP_) gsjpglib.h jlib5.h
+
+jlib6.h: $(JSRC)jpeglib.h
+ $(CP_) $(JSRC)jpeglib.h jlib6.h
+
+# To ensure that the compiler finds our versions of jconfig.h and jmorecfg.h,
+# regardless of the compiler's search rule, we must copy up all .c files,
+# and all .h files that include either of these files, directly or
+# indirectly. The only such .h files currently are jinclude.h and jpeglib.h.
+# (Currently, we supply our own version of jpeglib.h -- see above.)
+# Also, to avoid including the JSRCDIR directory name in our source files,
+# we must also copy up any other .h files that our own code references.
+# Currently, the only such .h files are jerror.h and jversion.h.
+
+JHCOPY=jinclude.h jpeglib.h jerror.h jversion.h
+
+jinclude.h: $(JSRC)jinclude.h
+ $(CP_) $(JSRC)jinclude.h jinclude.h
+
+#jpeglib.h: $(JSRC)jpeglib.h
+# $(CP_) $(JSRC)jpeglib.h jpeglib.h
+
+jerror.h: $(JSRC)jerror.h
+ $(CP_) $(JSRC)jerror.h jerror.h
+
+jversion.h: $(JSRC)jversion.h
+ $(CP_) $(JSRC)jversion.h jversion.h
+
+# In order to avoid having to keep the dependency lists for the IJG code
+# accurate, we simply make all of them depend on the only files that
+# we are ever going to change, and on all the .h files that must be copied up.
+# This is too conservative, but only hurts us if we are changing our own
+# j*.h files, which happens only rarely during development.
+
+JDEP=$(AK) $(jconfig_h) $(jerror_h) $(jmorecfg_h) $(JHCOPY)
+
+# Code common to compression and decompression.
+
+jpegc_=jcomapi.$(OBJ) jutils.$(OBJ) sjpegerr.$(OBJ) jmemmgr.$(OBJ)
+jpegc.dev: $(JPEG_MAK) $(ECHOGS_XE) $(jpegc_)
+ $(SETMOD) jpegc $(jpegc_)
+
+jcomapi.$(OBJ): $(JSRC)jcomapi.c $(JDEP)
+ $(CP_) $(JSRC)jcomapi.c .
+ $(CCCJ) jcomapi.c
+ $(RM_) jcomapi.c
+
+jutils.$(OBJ): $(JSRC)jutils.c $(JDEP)
+ $(CP_) $(JSRC)jutils.c .
+ $(CCCJ) jutils.c
+ $(RM_) jutils.c
+
+# Note that sjpegerr replaces jerror.
+sjpegerr.$(OBJ): sjpegerr.c $(JDEP)
+ $(CCCF) sjpegerr.c
+
+jmemmgr.$(OBJ): $(JSRC)jmemmgr.c $(JDEP)
+ $(CP_) $(JSRC)jmemmgr.c .
+ $(CCCJ) jmemmgr.c
+ $(RM_) jmemmgr.c
+
+# Encoding (compression) code.
+
+jpege.dev: jpege$(JVERSION).dev
+ $(CP_) jpege$(JVERSION).dev jpege.dev
+
+jpege5=jcapi.$(OBJ)
+jpege6=jcapimin.$(OBJ) jcapistd.$(OBJ) jcinit.$(OBJ)
+
+jpege_1=jccoefct.$(OBJ) jccolor.$(OBJ) jcdctmgr.$(OBJ)
+jpege_2=jchuff.$(OBJ) jcmainct.$(OBJ) jcmarker.$(OBJ) jcmaster.$(OBJ)
+jpege_3=jcparam.$(OBJ) jcprepct.$(OBJ) jcsample.$(OBJ) jfdctint.$(OBJ)
+
+jpege5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege5) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege5 $(jpege5)
+ $(ADDMOD) jpege5 -include jpegc
+ $(ADDMOD) jpege5 -obj $(jpege_1)
+ $(ADDMOD) jpege5 -obj $(jpege_2)
+ $(ADDMOD) jpege5 -obj $(jpege_3)
+
+jpege6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege6) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege6 $(jpege6)
+ $(ADDMOD) jpege6 -include jpegc
+ $(ADDMOD) jpege6 -obj $(jpege_1)
+ $(ADDMOD) jpege6 -obj $(jpege_2)
+ $(ADDMOD) jpege6 -obj $(jpege_3)
+
+# jcapi.c is v5* only
+jcapi.$(OBJ): $(JSRC)jcapi.c $(JDEP)
+ $(CP_) $(JSRC)jcapi.c .
+ $(CCCJ) jcapi.c
+ $(RM_) jcapi.c
+
+# jcapimin.c is new in v6
+jcapimin.$(OBJ): $(JSRC)jcapimin.c $(JDEP)
+ $(CP_) $(JSRC)jcapimin.c .
+ $(CCCJ) jcapimin.c
+ $(RM_) jcapimin.c
+
+# jcapistd.c is new in v6
+jcapistd.$(OBJ): $(JSRC)jcapistd.c $(JDEP)
+ $(CP_) $(JSRC)jcapistd.c .
+ $(CCCJ) jcapistd.c
+ $(RM_) jcapistd.c
+
+# jcinit.c is new in v6
+jcinit.$(OBJ): $(JSRC)jcinit.c $(JDEP)
+ $(CP_) $(JSRC)jcinit.c .
+ $(CCCJ) jcinit.c
+ $(RM_) jcinit.c
+
+jccoefct.$(OBJ): $(JSRC)jccoefct.c $(JDEP)
+ $(CP_) $(JSRC)jccoefct.c .
+ $(CCCJ) jccoefct.c
+ $(RM_) jccoefct.c
+
+jccolor.$(OBJ): $(JSRC)jccolor.c $(JDEP)
+ $(CP_) $(JSRC)jccolor.c .
+ $(CCCJ) jccolor.c
+ $(RM_) jccolor.c
+
+jcdctmgr.$(OBJ): $(JSRC)jcdctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jcdctmgr.c .
+ $(CCCJ) jcdctmgr.c
+ $(RM_) jcdctmgr.c
+
+jchuff.$(OBJ): $(JSRC)jchuff.c $(JDEP)
+ $(CP_) $(JSRC)jchuff.c .
+ $(CCCJ) jchuff.c
+ $(RM_) jchuff.c
+
+jcmainct.$(OBJ): $(JSRC)jcmainct.c $(JDEP)
+ $(CP_) $(JSRC)jcmainct.c .
+ $(CCCJ) jcmainct.c
+ $(RM_) jcmainct.c
+
+jcmarker.$(OBJ): $(JSRC)jcmarker.c $(JDEP)
+ $(CP_) $(JSRC)jcmarker.c .
+ $(CCCJ) jcmarker.c
+ $(RM_) jcmarker.c
+
+jcmaster.$(OBJ): $(JSRC)jcmaster.c $(JDEP)
+ $(CP_) $(JSRC)jcmaster.c .
+ $(CCCJ) jcmaster.c
+ $(RM_) jcmaster.c
+
+jcparam.$(OBJ): $(JSRC)jcparam.c $(JDEP)
+ $(CP_) $(JSRC)jcparam.c .
+ $(CCCJ) jcparam.c
+ $(RM_) jcparam.c
+
+jcprepct.$(OBJ): $(JSRC)jcprepct.c $(JDEP)
+ $(CP_) $(JSRC)jcprepct.c .
+ $(CCCJ) jcprepct.c
+ $(RM_) jcprepct.c
+
+jcsample.$(OBJ): $(JSRC)jcsample.c $(JDEP)
+ $(CP_) $(JSRC)jcsample.c .
+ $(CCCJ) jcsample.c
+ $(RM_) jcsample.c
+
+jfdctint.$(OBJ): $(JSRC)jfdctint.c $(JDEP)
+ $(CP_) $(JSRC)jfdctint.c .
+ $(CCCJ) jfdctint.c
+ $(RM_) jfdctint.c
+
+# Decompression code
+
+jpegd.dev: jpegd$(JVERSION).dev
+ $(CP_) jpegd$(JVERSION).dev jpegd.dev
+
+jpegd5=jdapi.$(OBJ)
+jpegd6=jdapimin.$(OBJ) jdapistd.$(OBJ) jdinput.$(OBJ) jdphuff.$(OBJ)
+
+jpegd_1=jdcoefct.$(OBJ) jdcolor.$(OBJ)
+jpegd_2=jddctmgr.$(OBJ) jdhuff.$(OBJ) jdmainct.$(OBJ) jdmarker.$(OBJ)
+jpegd_3=jdmaster.$(OBJ) jdpostct.$(OBJ) jdsample.$(OBJ) jidctint.$(OBJ)
+
+jpegd5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd5) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd5 $(jpegd5)
+ $(ADDMOD) jpegd5 -include jpegc
+ $(ADDMOD) jpegd5 -obj $(jpegd_1)
+ $(ADDMOD) jpegd5 -obj $(jpegd_2)
+ $(ADDMOD) jpegd5 -obj $(jpegd_3)
+
+jpegd6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd6) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd6 $(jpegd6)
+ $(ADDMOD) jpegd6 -include jpegc
+ $(ADDMOD) jpegd6 -obj $(jpegd_1)
+ $(ADDMOD) jpegd6 -obj $(jpegd_2)
+ $(ADDMOD) jpegd6 -obj $(jpegd_3)
+
+# jdapi.c is v5* only
+jdapi.$(OBJ): $(JSRC)jdapi.c $(JDEP)
+ $(CP_) $(JSRC)jdapi.c .
+ $(CCCJ) jdapi.c
+ $(RM_) jdapi.c
+
+# jdapimin.c is new in v6
+jdapimin.$(OBJ): $(JSRC)jdapimin.c $(JDEP)
+ $(CP_) $(JSRC)jdapimin.c .
+ $(CCCJ) jdapimin.c
+ $(RM_) jdapimin.c
+
+# jdapistd.c is new in v6
+jdapistd.$(OBJ): $(JSRC)jdapistd.c $(JDEP)
+ $(CP_) $(JSRC)jdapistd.c .
+ $(CCCJ) jdapistd.c
+ $(RM_) jdapistd.c
+
+jdcoefct.$(OBJ): $(JSRC)jdcoefct.c $(JDEP)
+ $(CP_) $(JSRC)jdcoefct.c .
+ $(CCCJ) jdcoefct.c
+ $(RM_) jdcoefct.c
+
+jdcolor.$(OBJ): $(JSRC)jdcolor.c $(JDEP)
+ $(CP_) $(JSRC)jdcolor.c .
+ $(CCCJ) jdcolor.c
+ $(RM_) jdcolor.c
+
+jddctmgr.$(OBJ): $(JSRC)jddctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jddctmgr.c .
+ $(CCCJ) jddctmgr.c
+ $(RM_) jddctmgr.c
+
+jdhuff.$(OBJ): $(JSRC)jdhuff.c $(JDEP)
+ $(CP_) $(JSRC)jdhuff.c .
+ $(CCCJ) jdhuff.c
+ $(RM_) jdhuff.c
+
+# jdinput.c is new in v6
+jdinput.$(OBJ): $(JSRC)jdinput.c $(JDEP)
+ $(CP_) $(JSRC)jdinput.c .
+ $(CCCJ) jdinput.c
+ $(RM_) jdinput.c
+
+jdmainct.$(OBJ): $(JSRC)jdmainct.c $(JDEP)
+ $(CP_) $(JSRC)jdmainct.c .
+ $(CCCJ) jdmainct.c
+ $(RM_) jdmainct.c
+
+jdmarker.$(OBJ): $(JSRC)jdmarker.c $(JDEP)
+ $(CP_) $(JSRC)jdmarker.c .
+ $(CCCJ) jdmarker.c
+ $(RM_) jdmarker.c
+
+jdmaster.$(OBJ): $(JSRC)jdmaster.c $(JDEP)
+ $(CP_) $(JSRC)jdmaster.c .
+ $(CCCJ) jdmaster.c
+ $(RM_) jdmaster.c
+
+# jdphuff.c is new in v6
+jdphuff.$(OBJ): $(JSRC)jdphuff.c $(JDEP)
+ $(CP_) $(JSRC)jdphuff.c .
+ $(CCCJ) jdphuff.c
+ $(RM_) jdphuff.c
+
+jdpostct.$(OBJ): $(JSRC)jdpostct.c $(JDEP)
+ $(CP_) $(JSRC)jdpostct.c .
+ $(CCCJ) jdpostct.c
+ $(RM_) jdpostct.c
+
+jdsample.$(OBJ): $(JSRC)jdsample.c $(JDEP)
+ $(CP_) $(JSRC)jdsample.c .
+ $(CCCJ) jdsample.c
+ $(RM_) jdsample.c
+
+jidctint.$(OBJ): $(JSRC)jidctint.c $(JDEP)
+ $(CP_) $(JSRC)jidctint.c .
+ $(CCCJ) jidctint.c
+ $(RM_) jidctint.c
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for PNG (Portable Network Graphics) code.
+
+# This partial makefile compiles the png library for use in the Ghostscript
+# PNG drivers. You can get the source code for this library from:
+# ftp://swrinde.nde.swri.edu/pub/png/src/
+# The makefile is known to work with the following library versions:
+# 0.89, 0.90, 0.95, and 0.96. NOTE: the archive for libpng 0.95 may
+# be inconsistent: if you have compilation problems, use an older version.
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+#
+# The specification for the PNG file format is available from:
+# http://www.group42.com/png.htm
+# http://www.w3.org/pub/WWW/TR/WD-png
+
+# Define the name of this makefile.
+LIBPNG_MAK=libpng.mak
+
+# PSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the PNG library sources are stored.
+#PSRCDIR=libpng
+# PVERSION is defined in the platform-specific makefile, not here,
+# as the libpng version number ("89", "90", "95", or "96").
+#PVERSION=96
+
+PSRC=$(PSRCDIR)$(D)
+# CCCP is defined in gs.mak.
+#CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR)
+
+# We keep all of the PNG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+PDEP=$(AK)
+
+png_1=png.$(OBJ) pngmem.$(OBJ) pngerror.$(OBJ)
+png_2=pngtrans.$(OBJ) pngwrite.$(OBJ) pngwtran.$(OBJ) pngwutil.$(OBJ)
+
+# libpng modules
+
+png.$(OBJ): $(PSRC)png.c $(PDEP)
+ $(CCCP) $(PSRC)png.c
+
+# version 0.89 uses pngwio.c
+pngwio.$(OBJ): $(PSRC)pngwio.c $(PDEP)
+ $(CCCP) $(PSRC)pngwio.c
+
+pngmem.$(OBJ): $(PSRC)pngmem.c $(PDEP)
+ $(CCCP) $(PSRC)pngmem.c
+
+pngerror.$(OBJ): $(PSRC)pngerror.c $(PDEP)
+ $(CCCP) $(PSRC)pngerror.c
+
+pngtrans.$(OBJ): $(PSRC)pngtrans.c $(PDEP)
+ $(CCCP) $(PSRC)pngtrans.c
+
+pngwrite.$(OBJ): $(PSRC)pngwrite.c $(PDEP)
+ $(CCCP) $(PSRC)pngwrite.c
+
+pngwtran.$(OBJ): $(PSRC)pngwtran.c $(PDEP)
+ $(CCCP) $(PSRC)pngwtran.c
+
+pngwutil.$(OBJ): $(PSRC)pngwutil.c $(PDEP)
+ $(CCCP) $(PSRC)pngwutil.c
+
+# Define the version of libpng.dev that we are actually using.
+libpng.dev: $(MAKEFILE) libpng_$(SHARE_LIBPNG).dev
+ $(CP_) libpng_$(SHARE_LIBPNG).dev libpng.dev
+
+# Define the shared version of libpng.
+# Note that it requires libz, which must be searched *after* libpng.
+libpng_1.dev: $(MAKEFILE) $(LIBPNG_MAK) $(ECHOGS_XE) zlibe.dev
+ $(SETMOD) libpng_1 -lib $(LIBPNG_NAME)
+ $(ADDMOD) libpng_1 -include zlibe
+
+# Define the non-shared version of libpng.
+libpng_0.dev: $(LIBPNG_MAK) $(ECHOGS_XE) $(png_1) $(png_2)\
+ zlibe.dev libpng$(PVERSION).dev
+ $(SETMOD) libpng_0 $(png_1)
+ $(ADDMOD) libpng_0 $(png_2)
+ $(ADDMOD) libpng_0 -include zlibe libpng$(PVERSION)
+
+libpng89.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ)
+ $(SETMOD) libpng89 pngwio.$(OBJ)
+
+libpng90.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng90 pngwio.$(OBJ) -include crc32
+
+libpng95.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng95 pngwio.$(OBJ) -include crc32
+
+libpng96.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng96 pngwio.$(OBJ) -include crc32
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for zlib library code.
+
+# This partial makefile compiles the zlib library for use in Ghostscript.
+# You can get the source code for this library from:
+# ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib104.zip (zlib 1.0.4)
+# or zlib-1.0.4.tar.gz
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+
+# Define the name of this makefile.
+ZLIB_MAK=zlib.mak
+
+# ZSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the zlib sources are stored.
+#ZSRCDIR=zlib
+ZSRC=$(ZSRCDIR)$(D)
+# We would like to define
+#CCCZ=$(CCC) -I$(ZSRCDIR) -Dverbose=-1
+# but the Watcom C compiler has strange undocumented restrictions on what can
+# follow a -D=, and it doesn't allow negative numbers. Instead, we define
+# (in gs.mak):
+#CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+# and handle the definition of verbose in a different, more awkward way.
+
+# We keep all of the zlib code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+ZDEP=$(AK)
+
+# Contrary to what some portability bigots assert as fact, C compilers are
+# not consistent about where they start searching for #included files:
+# some always start by looking in the same directory as the .c file being
+# compiled, before using the search path specified with -I on the command
+# line, while others do not do this. For this reason, we must explicitly
+# copy and then delete all the .c files, because they need to obtain our
+# modified version of zutil.h. We must also copy all header files that
+# reference zutil.h directly or indirectly.
+
+# Code common to compression and decompression.
+
+zlibc_=zutil.$(OBJ)
+zlibc.dev: $(ZLIB_MAK) $(ECHOGS_XE) $(zlibc_)
+ $(SETMOD) zlibc $(zlibc_)
+
+zutil.h: $(ZSRC)zutil.h $(ECHOGS_XE)
+ $(EXP)echogs -w zutil.h -x 23 define verbose -s - -1
+ $(EXP)echogs -a zutil.h -+R $(ZSRC)zutil.h
+
+zutil.$(OBJ): $(ZSRC)zutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)zutil.c .
+ $(CCCZ) zutil.c
+ $(RM_) zutil.c
+
+# Encoding (compression) code.
+
+deflate.h: $(ZSRC)deflate.h zutil.h
+ $(CP_) $(ZSRC)deflate.h .
+
+zlibe.dev: $(MAKEFILE) zlibe_$(SHARE_ZLIB).dev
+ $(CP_) zlibe_$(SHARE_ZLIB).dev zlibe.dev
+
+zlibe_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibe_1 -lib $(ZLIB_NAME)
+
+zlibe_=adler32.$(OBJ) deflate.$(OBJ) trees.$(OBJ)
+zlibe_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibe_)
+ $(SETMOD) zlibe_0 $(zlibe_)
+ $(ADDMOD) zlibe_0 -include zlibc
+
+adler32.$(OBJ): $(ZSRC)adler32.c $(ZDEP)
+ $(CP_) $(ZSRC)adler32.c .
+ $(CCCZ) adler32.c
+ $(RM_) adler32.c
+
+deflate.$(OBJ): $(ZSRC)deflate.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)deflate.c .
+ $(CCCZ) deflate.c
+ $(RM_) deflate.c
+
+trees.$(OBJ): $(ZSRC)trees.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)trees.c .
+ $(CCCZ) trees.c
+ $(RM_) trees.c
+
+# The zlib filters per se don't need crc32, but libpng versions starting
+# with 0.90 do.
+
+crc32.dev: $(MAKEFILE) crc32_$(SHARE_ZLIB).dev
+ $(CP_) crc32_$(SHARE_ZLIB).dev crc32.dev
+
+crc32_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) crc32_1 -lib $(ZLIB_NAME)
+
+crc32_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) crc32.$(OBJ)
+ $(SETMOD) crc32_0 crc32.$(OBJ)
+
+crc32.$(OBJ): $(ZSRC)crc32.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)crc32.c .
+ $(CCCZ) crc32.c
+ $(RM_) crc32.c
+
+# Decoding (decompression) code.
+
+zlibd.dev: $(MAKEFILE) zlibd_$(SHARE_ZLIB).dev
+ $(CP_) zlibd_$(SHARE_ZLIB).dev zlibd.dev
+
+zlibd_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibd_1 -lib $(ZLIB_NAME)
+
+zlibd1_=infblock.$(OBJ) infcodes.$(OBJ) inffast.$(OBJ)
+zlibd2_=inflate.$(OBJ) inftrees.$(OBJ) infutil.$(OBJ)
+zlibd_ = $(zlibd1_) $(zlibd2_)
+zlibd_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibd_)
+ $(SETMOD) zlibd_0 $(zlibd1_)
+ $(ADDMOD) zlibd_0 -obj $(zlibd2_)
+ $(ADDMOD) zlibd_0 -include zlibc
+
+infblock.$(OBJ): $(ZSRC)infblock.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infblock.c .
+ $(CCCZ) infblock.c
+ $(RM_) infblock.c
+
+infcodes.$(OBJ): $(ZSRC)infcodes.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infcodes.c .
+ $(CCCZ) infcodes.c
+ $(RM_) infcodes.c
+
+inffast.$(OBJ): $(ZSRC)inffast.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inffast.c .
+ $(CCCZ) inffast.c
+ $(RM_) inffast.c
+
+inflate.$(OBJ): $(ZSRC)inflate.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inflate.c .
+ $(CCCZ) inflate.c
+ $(RM_) inflate.c
+
+inftrees.$(OBJ): $(ZSRC)inftrees.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inftrees.c .
+ $(CCCZ) inftrees.c
+ $(RM_) inftrees.c
+
+infutil.$(OBJ): $(ZSRC)infutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infutil.c .
+ $(CCCZ) infutil.c
+ $(RM_) infutil.c
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for device drivers.
+
+# Define the name of this makefile.
+DEVS_MAK=devs.mak
+
+###### --------------------------- Catalog -------------------------- ######
+
+# It is possible to build configurations with an arbitrary collection of
+# device drivers, although some drivers are supported only on a subset
+# of the target platforms. The currently available drivers are:
+
+# MS-DOS displays (note: not usable with Desqview/X):
+# MS-DOS EGA and VGA:
+# ega EGA (640x350, 16-color)
+# vga VGA (640x480, 16-color)
+# MS-DOS SuperVGA:
+# * ali SuperVGA using Avance Logic Inc. chipset, 256-color modes
+# * atiw ATI Wonder SuperVGA, 256-color modes
+# * s3vga SuperVGA using S3 86C911 chip (e.g., Diamond Stealth board)
+# svga16 Generic SuperVGA in 800x600, 16-color mode
+# * tseng SuperVGA using Tseng Labs ET3000/4000 chips, 256-color modes
+# * tvga SuperVGA using Trident chipset, 256-color modes
+# ****** NOTE: The vesa device does not work with the Watcom (32-bit MS-DOS)
+# ****** compiler or executable.
+# vesa SuperVGA with VESA standard API driver
+# MS-DOS other:
+# bgi Borland Graphics Interface (CGA) [MS-DOS only]
+# * herc Hercules Graphics display [MS-DOS only]
+# * pe Private Eye display
+# Other displays:
+# MS Windows:
+# mswindll Microsoft Windows 3.1 DLL [MS Windows only]
+# mswinprn Microsoft Windows 3.0, 3.1 DDB printer [MS Windows only]
+# mswinpr2 Microsoft Windows 3.0, 3.1 DIB printer [MS Windows only]
+# OS/2:
+# * os2pm OS/2 Presentation Manager [OS/2 only]
+# * os2dll OS/2 DLL bitmap [OS/2 only]
+# * os2prn OS/2 printer [OS/2 only]
+# Unix and VMS:
+# ****** NOTE: For direct frame buffer addressing under SCO Unix or Xenix,
+# ****** edit the definition of EGAVGA below.
+# * att3b1 AT&T 3b1/Unixpc monochrome display [3b1 only]
+# * lvga256 Linux vgalib, 256-color VGA modes [Linux only]
+# * sonyfb Sony Microsystems monochrome display [Sony only]
+# * sunview SunView window system [SunOS only]
+# + vgalib Linux PC with VGALIB [Linux only]
+# x11 X Windows version 11, release >=4 [Unix and VMS only]
+# x11alpha X Windows masquerading as a device with alpha capability
+# x11cmyk X Windows masquerading as a 1-bit-per-plane CMYK device
+# x11gray2 X Windows as a 2-bit gray-scale device
+# x11mono X Windows masquerading as a black-and-white device
+# Platform-independent:
+# * sxlcrt CRT sixels, e.g. for VT240-like terminals
+# Printers:
+# * ap3250 Epson AP3250 printer
+# * appledmp Apple Dot Matrix Printer (should also work with Imagewriter)
+# bj10e Canon BubbleJet BJ10e
+# * bj200 Canon BubbleJet BJ200
+# * bjc600 Canon Color BubbleJet BJC-600, BJC-4000 and BJC-70
+# also good for Apple printers like the StyleWriter 2x00
+# * bjc800 Canon Color BubbleJet BJC-800
+# * ccr CalComp Raster format
+# * cdeskjet H-P DeskJet 500C with 1 bit/pixel color
+# * cdjcolor H-P DeskJet 500C with 24 bit/pixel color and
+# high-quality color (Floyd-Steinberg) dithering;
+# also good for DeskJet 540C and Citizen Projet IIc (-r200x300)
+# * cdjmono H-P DeskJet 500C printing black only;
+# also good for DeskJet 510, 520, and 540C (black only)
+# * cdj500 H-P DeskJet 500C (same as cdjcolor)
+# * cdj550 H-P DeskJet 550C/560C/660C/660Cse
+# * cp50 Mitsubishi CP50 color printer
+# * declj250 alternate DEC LJ250 driver
+# + deskjet H-P DeskJet and DeskJet Plus
+# djet500 H-P DeskJet 500; use -r600 for DJ 600 series
+# * djet500c H-P DeskJet 500C alternate driver
+# (does not work on 550C or 560C)
+# * dnj650c H-P DesignJet 650C
+# epson Epson-compatible dot matrix printers (9- or 24-pin)
+# * eps9mid Epson-compatible 9-pin, interleaved lines
+# (intermediate resolution)
+# * eps9high Epson-compatible 9-pin, interleaved lines
+# (triple resolution)
+# * epsonc Epson LQ-2550 and Fujitsu 3400/2400/1200 color printers
+# * ibmpro IBM 9-pin Proprinter
+# * imagen Imagen ImPress printers
+# * iwhi Apple Imagewriter in high-resolution mode
+# * iwlo Apple Imagewriter in low-resolution mode
+# * iwlq Apple Imagewriter LQ in 320 x 216 dpi mode
+# * jetp3852 IBM Jetprinter ink-jet color printer (Model #3852)
+# + laserjet H-P LaserJet
+# * la50 DEC LA50 printer
+# * la70 DEC LA70 printer
+# * la70t DEC LA70 printer with low-resolution text enhancement
+# * la75 DEC LA75 printer
+# * la75plus DEC LA75plus printer
+# * lbp8 Canon LBP-8II laser printer
+# * lips3 Canon LIPS III laser printer in English (CaPSL) mode
+# * ln03 DEC LN03 printer
+# * lj250 DEC LJ250 Companion color printer
+# + ljet2p H-P LaserJet IId/IIp/III* with TIFF compression
+# + ljet3 H-P LaserJet III* with Delta Row compression
+# + ljet3d H-P LaserJet IIID with duplex capability
+# + ljet4 H-P LaserJet 4 (defaults to 600 dpi)
+# + lj4dith H-P LaserJet 4 with Floyd-Steinberg dithering
+# + ljetplus H-P LaserJet Plus
+# lj5mono H-P LaserJet 5 & 6 family (PCL XL), bitmap:
+# see below for restrictions & advice
+# lj5gray H-P LaserJet 5 & 6 family, gray-scale bitmap;
+# see below for restrictions & advice
+# * lp2563 H-P 2563B line printer
+# * lp8000 Epson LP-8000 laser printer
+# * lq850 Epson LQ850 printer at 360 x 360 DPI resolution;
+# also good for Canon BJ300 with LQ850 emulation
+# * m8510 C.Itoh M8510 printer
+# * necp6 NEC P6/P6+/P60 printers at 360 x 360 DPI resolution
+# * nwp533 Sony Microsystems NWP533 laser printer [Sony only]
+# * oce9050 OCE 9050 printer
+# * oki182 Okidata MicroLine 182
+# * okiibm Okidata MicroLine IBM-compatible printers
+# * paintjet alternate H-P PaintJet color printer
+# * pj H-P PaintJet XL driver
+# * pjetxl alternate H-P PaintJet XL driver
+# * pjxl H-P PaintJet XL color printer
+# * pjxl300 H-P PaintJet XL300 color printer;
+# also good for PaintJet 1200C
+# (pxlmono) H-P black-and-white PCL XL printers (LaserJet 5 and 6 family)
+# (pxlcolor) H-P color PCL XL printers (none available yet)
+# * r4081 Ricoh 4081 laser printer
+# * sj48 StarJet 48 inkjet printer
+# * sparc SPARCprinter
+# * st800 Epson Stylus 800 printer
+# * stcolor Epson Stylus Color
+# * t4693d2 Tektronix 4693d color printer, 2 bits per R/G/B component
+# * t4693d4 Tektronix 4693d color printer, 4 bits per R/G/B component
+# * t4693d8 Tektronix 4693d color printer, 8 bits per R/G/B component
+# * tek4696 Tektronix 4695/4696 inkjet plotter
+# * uniprint Unified printer driver -- Configurable Color ESC/P-,
+# ESC/P2-, HP-RTL/PCL mono/color driver
+# * xes Xerox XES printers (2700, 3700, 4045, etc.)
+# Fax systems:
+# * dfaxhigh DigiBoard, Inc.'s DigiFAX software format (high resolution)
+# * dfaxlow DigiFAX low (normal) resolution
+# Fax file format:
+# ****** NOTE: all of these drivers adjust the page size to match
+# ****** one of the three CCITT standard sizes (U.S. letter with A4 width,
+# ****** A4, or B4).
+# faxg3 Group 3 fax, with EOLs but no header or EOD
+# faxg32d Group 3 2-D fax, with EOLs but no header or EOD
+# faxg4 Group 4 fax, with EOLs but no header or EOD
+# tiffcrle TIFF "CCITT RLE 1-dim" (= Group 3 fax with no EOLs)
+# tiffg3 TIFF Group 3 fax (with EOLs)
+# tiffg32d TIFF Group 3 2-D fax
+# tiffg4 TIFF Group 4 fax
+# High-level file formats:
+# epswrite EPS output (like PostScript Distillery)
+# pdfwrite PDF output (like Adobe Acrobat Distiller)
+# pswrite PostScript output (like PostScript Distillery)
+# pxlmono Black-and-white PCL XL
+# pxlcolor Color PCL XL
+# Other raster file formats and devices:
+# bit Plain bits, monochrome
+# bitrgb Plain bits, RGB
+# bitcmyk Plain bits, CMYK
+# bmpmono Monochrome MS Windows .BMP file format
+# bmp16 4-bit (EGA/VGA) .BMP file format
+# bmp256 8-bit (256-color) .BMP file format
+# bmp16m 24-bit .BMP file format
+# cgmmono Monochrome (black-and-white) CGM -- LOW LEVEL OUTPUT ONLY
+# cgm8 8-bit (256-color) CGM -- DITTO
+# cgm24 24-bit color CGM -- DITTO
+# * cif CIF file format for VLSI
+# jpeg JPEG format, RGB output
+# jpeggray JPEG format, gray output
+# miff24 ImageMagick MIFF format, 24-bit direct color, RLE compressed
+# * mgrmono 1-bit monochrome MGR devices
+# * mgrgray2 2-bit gray scale MGR devices
+# * mgrgray4 4-bit gray scale MGR devices
+# * mgrgray8 8-bit gray scale MGR devices
+# * mgr4 4-bit (VGA) color MGR devices
+# * mgr8 8-bit color MGR devices
+# pcxmono PCX file format, monochrome (1-bit black and white)
+# pcxgray PCX file format, 8-bit gray scale
+# pcx16 PCX file format, 4-bit planar (EGA/VGA) color
+# pcx256 PCX file format, 8-bit chunky color
+# pcx24b PCX file format, 24-bit color (3 8-bit planes)
+# pcxcmyk PCX file format, 4-bit chunky CMYK color
+# pbm Portable Bitmap (plain format)
+# pbmraw Portable Bitmap (raw format)
+# pgm Portable Graymap (plain format)
+# pgmraw Portable Graymap (raw format)
+# pgnm Portable Graymap (plain format), optimizing to PBM if possible
+# pgnmraw Portable Graymap (raw format), optimizing to PBM if possible
+# pnm Portable Pixmap (plain format) (RGB), optimizing to PGM or PBM
+# if possible
+# pnmraw Portable Pixmap (raw format) (RGB), optimizing to PGM or PBM
+# if possible
+# ppm Portable Pixmap (plain format) (RGB)
+# ppmraw Portable Pixmap (raw format) (RGB)
+# pkm Portable inKmap (plain format) (4-bit CMYK => RGB)
+# pkmraw Portable inKmap (raw format) (4-bit CMYK => RGB)
+# pngmono Monochrome Portable Network Graphics (PNG)
+# pnggray 8-bit gray Portable Network Graphics (PNG)
+# png16 4-bit color Portable Network Graphics (PNG)
+# png256 8-bit color Portable Network Graphics (PNG)
+# png16m 24-bit color Portable Network Graphics (PNG)
+# psmono PostScript (Level 1) monochrome image
+# psgray PostScript (Level 1) 8-bit gray image
+# sgirgb SGI RGB pixmap format
+# tiff12nc TIFF 12-bit RGB, no compression
+# tiff24nc TIFF 24-bit RGB, no compression (NeXT standard format)
+# tifflzw TIFF LZW (tag = 5) (monochrome)
+# tiffpack TIFF PackBits (tag = 32773) (monochrome)
+
+# User-contributed drivers marked with * require hardware or software
+# that is not available to Aladdin Enterprises. Please contact the
+# original contributors, not Aladdin Enterprises, if you have questions.
+# Contact information appears in the driver entry below.
+#
+# Drivers marked with a + are maintained by Aladdin Enterprises with
+# the assistance of users, since Aladdin Enterprises doesn't have access to
+# the hardware for these either.
+
+# If you add drivers, it would be nice if you kept each list
+# in alphabetical order.
+
+###### ----------------------- End of catalog ----------------------- ######
+
+# As noted in gs.mak, DEVICE_DEVS and DEVICE_DEVS1..15 select the devices
+# that should be included in a given configuration. By convention, these
+# are used as follows. Each of these must be limited to about 10 devices
+# so as not to overflow the 120 character limit on MS-DOS command lines.
+# DEVICE_DEVS - the default device, and any display devices.
+# DEVICE_DEVS1 - additional display devices if needed.
+# DEVICE_DEVS2 - dot matrix printers.
+# DEVICE_DEVS3 - H-P monochrome printers.
+# DEVICE_DEVS4 - H-P color printers.
+# DEVICE_DEVS5 - additional H-P printers if needed.
+# DEVICE_DEVS6 - other ink-jet and laser printers.
+# DEVICE_DEVS7 - fax file formats.
+# DEVICE_DEVS8 - PCX file formats.
+# DEVICE_DEVS9 - PBM/PGM/PPM file formats.
+# DEVICE_DEVS10 - black-and-white TIFF file formats.
+# DEVICE_DEVS11 - BMP and color TIFF file formats.
+# DEVICE_DEVS12 - PostScript image and 'bit' file formats.
+# DEVICE_DEVS13 - PNG file formats.
+# DEVICE_DEVS14 - CGM, JPEG, and MIFF file formats.
+# DEVICE_DEVS15 - high-level (PostScript and PDF) file formats.
+# Feel free to disregard this convention if it gets in your way.
+
+# If you want to add a new device driver, the examples below should be
+# enough of a guide to the correct form for the makefile rules.
+# Note that all drivers other than displays must include page.dev in their
+# dependencies and use $(SETPDEV) rather than $(SETDEV) in their rule bodies.
+
+# All device drivers depend on the following:
+GDEV=$(AK) $(ECHOGS_XE) $(gserrors_h) $(gx_h) $(gxdevice_h)
+
+# "Printer" drivers depend on the following:
+PDEVH=$(AK) $(gdevprn_h)
+
+# Define the header files for device drivers. Every header file used by
+# more than one device driver family must be listed here.
+gdev8bcm_h=gdev8bcm.h
+gdevpccm_h=gdevpccm.h
+gdevpcfb_h=gdevpcfb.h $(dos__h)
+gdevpcl_h=gdevpcl.h
+gdevsvga_h=gdevsvga.h
+gdevx_h=gdevx.h
+
+###### ----------------------- Device support ----------------------- ######
+
+# Provide a mapping between StandardEncoding and ISOLatin1Encoding.
+gdevemap.$(OBJ): gdevemap.c $(AK) $(std_h)
+
+# Implement dynamic color management for 8-bit mapped color displays.
+gdev8bcm.$(OBJ): gdev8bcm.c $(AK) \
+ $(gx_h) $(gxdevice_h) $(gdev8bcm_h)
+
+###### ------------------- MS-DOS display devices ------------------- ######
+
+# There are really only three drivers: an EGA/VGA driver (4 bit-planes,
+# plane-addressed), a SuperVGA driver (8 bit-planes, byte addressed),
+# and a special driver for the S3 chip.
+
+# PC display color mapping
+gdevpccm.$(OBJ): gdevpccm.c $(AK) \
+ $(gx_h) $(gsmatrix_h) $(gxdevice_h) $(gdevpccm_h)
+
+### ----------------------- EGA and VGA displays ----------------------- ###
+
+# The shared MS-DOS makefile defines PCFBASM as either gdevegaa.$(OBJ)
+# or an empty string.
+
+gdevegaa.$(OBJ): gdevegaa.asm
+
+# NOTE: for direct frame buffer addressing under SCO Unix or Xenix,
+# change gdevevga to gdevsco in the following line. Also, since
+# SCO's /bin/as does not support the "out" instructions, you must build
+# the gnu assembler and have it on your path as "as".
+EGAVGA=gdevevga.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+#EGAVGA=gdevsco.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevevga.$(OBJ): gdevevga.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+ $(CCD) gdevevga.c
+
+gdevsco.$(OBJ): gdevsco.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+
+# Common code for MS-DOS and SCO.
+gdevpcfb.$(OBJ): gdevpcfb.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gdevpccm_h) $(gdevpcfb_h) $(gsparam_h)
+ $(CCD) gdevpcfb.c
+
+# The EGA/VGA family includes EGA and VGA. Many SuperVGAs in 800x600,
+# 16-color mode can share the same code; see the next section below.
+
+ega.dev: $(EGAVGA)
+ $(SETDEV) ega $(EGAVGA)
+
+vga.dev: $(EGAVGA)
+ $(SETDEV) vga $(EGAVGA)
+
+### ------------------------- SuperVGA displays ------------------------ ###
+
+# SuperVGA displays in 16-color, 800x600 mode are really just slightly
+# glorified VGA's, so we can handle them all with a single driver.
+# The way to select them on the command line is with
+# -sDEVICE=svga16 -dDisplayMode=NNN
+# where NNN is the display mode in decimal. See use.txt for the modes
+# for some popular display chipsets.
+
+svga16.dev: $(EGAVGA)
+ $(SETDEV) svga16 $(EGAVGA)
+
+# More capable SuperVGAs have a wide variety of slightly differing
+# interfaces, so we need a separate driver for each one.
+
+SVGA=gdevsvga.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevsvga.$(OBJ): gdevsvga.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gsparam_h) $(gxarith_h) $(gdevpccm_h) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevsvga.c
+
+# The SuperVGA family includes: Avance Logic Inc., ATI Wonder, S3,
+# Trident, Tseng ET3000/4000, and VESA.
+
+ali.dev: $(SVGA)
+ $(SETDEV) ali $(SVGA)
+
+atiw.dev: $(SVGA)
+ $(SETDEV) atiw $(SVGA)
+
+tseng.dev: $(SVGA)
+ $(SETDEV) tseng $(SVGA)
+
+tvga.dev: $(SVGA)
+ $(SETDEV) tvga $(SVGA)
+
+vesa.dev: $(SVGA)
+ $(SETDEV) vesa $(SVGA)
+
+# The S3 driver doesn't share much code with the others.
+
+s3vga_=gdevs3ga.$(OBJ) gdevsvga.$(OBJ) gdevpccm.$(OBJ)
+s3vga.dev: $(SVGA) $(s3vga_)
+ $(SETDEV) s3vga $(SVGA)
+ $(ADDMOD) s3vga -obj $(s3vga_)
+
+gdevs3ga.$(OBJ): gdevs3ga.c $(GDEV) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevs3ga.c
+
+### ------------ The BGI (Borland Graphics Interface) device ----------- ###
+
+cgaf.$(OBJ): $(BGIDIR)\cga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\cga
+
+egavgaf.$(OBJ): $(BGIDIR)\egavga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\egavga
+
+# Include egavgaf.$(OBJ) for debugging only.
+bgi_=gdevbgi.$(OBJ) cgaf.$(OBJ)
+bgi.dev: $(bgi_)
+ $(SETDEV) bgi $(bgi_)
+ $(ADDMOD) bgi -lib $(LIBDIR)\graphics
+
+gdevbgi.$(OBJ): gdevbgi.c $(GDEV) $(MAKEFILE) $(gxxfont_h)
+ $(CCC) -DBGI_LIB="$(BGIDIRSTR)" gdevbgi.c
+
+### ------------------- The Hercules Graphics display ------------------- ###
+
+herc_=gdevherc.$(OBJ)
+herc.dev: $(herc_)
+ $(SETDEV) herc $(herc_)
+
+gdevherc.$(OBJ): gdevherc.c $(GDEV) $(dos__h) $(gsmatrix_h) $(gxbitmap_h)
+ $(CCC) gdevherc.c
+
+### ---------------------- The Private Eye display ---------------------- ###
+### Note: this driver was contributed by a user: ###
+### please contact narf@media-lab.media.mit.edu if you have questions. ###
+
+pe_=gdevpe.$(OBJ)
+pe.dev: $(pe_)
+ $(SETDEV) pe $(pe_)
+
+gdevpe.$(OBJ): gdevpe.c $(GDEV) $(memory__h)
+
+###### ----------------------- Other displays ------------------------ ######
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gsdll_h=gsdll.h
+
+gdevmswn_h=gdevmswn.h $(GDEV)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ gp_mswin.h
+
+gdevmswn.$(OBJ): gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h) \
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(CCCWIN) gdevmswn.c
+
+gdevmsxf.$(OBJ): gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCCWIN) gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+gdevwdib.$(OBJ): gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(CCCWIN) gdevwdib.c
+
+mswindll_=gdevmswn.$(OBJ) gdevmsxf.$(OBJ) gdevwdib.$(OBJ) \
+ gdevemap.$(OBJ) gdevpccm.$(OBJ)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=gdevwprn.$(OBJ) gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+gdevwprn.$(OBJ): gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(CCCWIN) gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+gdevwpr2.$(OBJ): gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) gp_mswin.h
+ $(CCCWIN) gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+gdevpm.$(OBJ): gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) gdevpm.h
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+os2prn.$(OBJ): os2prn.c $(gp_h)
+
+### -------------- The AT&T 3b1 Unixpc monochrome display --------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Andy Fyfe (andy@cs.caltech.edu) if you have questions. ###
+
+att3b1_=gdev3b1.$(OBJ)
+att3b1.dev: $(att3b1_)
+ $(SETDEV) att3b1 $(att3b1_)
+
+gdev3b1.$(OBJ): gdev3b1.c $(GDEV)
+
+### ---------------------- Linux PC with vgalib ------------------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the lvga256 driver, please contact ###
+### Ludger Kunz (ludger.kunz@fernuni-hagen.de). ###
+### For questions about the vgalib driver, please contact ###
+### Erik Talvola (talvola@gnu.ai.mit.edu). ###
+
+lvga256_=gdevl256.$(OBJ)
+lvga256.dev: $(lvga256_)
+ $(SETDEV) lvga256 $(lvga256_)
+ $(ADDMOD) lvga256 -lib vga vgagl
+
+gdevl256.$(OBJ): gdevl256.c $(GDEV)
+
+vgalib_=gdevvglb.$(OBJ) gdevpccm.$(OBJ)
+vgalib.dev: $(vgalib_)
+ $(SETDEV) vgalib $(vgalib_)
+ $(ADDMOD) vgalib -lib vga
+
+gdevvglb.$(OBJ): gdevvglb.c $(GDEV) $(gdevpccm_h) $(gsparam_h)
+
+### ------------------- Sony NeWS frame buffer device ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Mike Smolenski (mike@intertech.com) if you have questions. ###
+
+# This is implemented as a 'printer' device.
+sonyfb_=gdevsnfb.$(OBJ)
+sonyfb.dev: $(sonyfb_) page.dev
+ $(SETPDEV) sonyfb $(sonyfb_)
+
+gdevsnfb.$(OBJ): gdevsnfb.c $(PDEVH)
+
+### ------------------------ The SunView device ------------------------ ###
+### Note: this driver is maintained by a user: if you have questions, ###
+### please contact Andreas Stolcke (stolcke@icsi.berkeley.edu). ###
+
+sunview_=gdevsun.$(OBJ)
+sunview.dev: $(sunview_)
+ $(SETDEV) sunview $(sunview_)
+ $(ADDMOD) sunview -lib suntool sunwindow pixrect
+
+gdevsun.$(OBJ): gdevsun.c $(GDEV) $(malloc__h)\
+ $(gscdefs_h) $(gserrors_h) $(gsmatrix_h)
+
+### -------------------------- The X11 device -------------------------- ###
+
+# Aladdin Enterprises does not support Ghostview. For more information
+# about Ghostview, please contact Tim Theisen (ghostview@cs.wisc.edu).
+
+# See the main makefile for the definition of XLIBS.
+x11_=gdevx.$(OBJ) gdevxini.$(OBJ) gdevxxf.$(OBJ) gdevemap.$(OBJ)
+x11.dev: $(x11_)
+ $(SETDEV) x11 $(x11_)
+ $(ADDMOD) x11 -lib $(XLIBS)
+
+# See the main makefile for the definition of XINCLUDE.
+GDEVX=$(GDEV) x_.h gdevx.h $(MAKEFILE)
+gdevx.$(OBJ): gdevx.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevx.c
+
+gdevxini.$(OBJ): gdevxini.c $(GDEVX) $(math__h) $(memory__h) $(gserrors_h)
+ $(CCC) $(XINCLUDE) gdevxini.c
+
+gdevxxf.$(OBJ): gdevxxf.c $(GDEVX) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCC) $(XINCLUDE) gdevxxf.c
+
+# Alternate X11-based devices to help debug other drivers.
+# x11alpha pretends to have 4 bits of alpha channel.
+# x11cmyk pretends to be a CMYK device with 1 bit each of C,M,Y,K.
+# x11gray2 pretends to be a 2-bit gray-scale device.
+# x11mono pretends to be a black-and-white device.
+x11alt_=$(x11_) gdevxalt.$(OBJ)
+x11alpha.dev: $(x11alt_)
+ $(SETDEV) x11alpha $(x11alt_)
+ $(ADDMOD) x11alpha -lib $(XLIBS)
+
+x11cmyk.dev: $(x11alt_)
+ $(SETDEV) x11cmyk $(x11alt_)
+ $(ADDMOD) x11cmyk -lib $(XLIBS)
+
+x11gray2.dev: $(x11alt_)
+ $(SETDEV) x11gray2 $(x11alt_)
+ $(ADDMOD) x11gray2 -lib $(XLIBS)
+
+x11mono.dev: $(x11alt_)
+ $(SETDEV) x11mono $(x11alt_)
+ $(ADDMOD) x11mono -lib $(XLIBS)
+
+gdevxalt.$(OBJ): gdevxalt.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevxalt.c
+
+### ------------------------- DEC sixel displays ------------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Phil Keegstra (keegstra@tonga.gsfc.nasa.gov) if you have questions. ###
+
+# This is a "printer" device, but it probably shouldn't be.
+# I don't know why the implementor chose to do it this way.
+sxlcrt_=gdevln03.$(OBJ)
+sxlcrt.dev: $(sxlcrt_) page.dev
+ $(SETPDEV) sxlcrt $(sxlcrt_)
+
+###### --------------- Memory-buffered printer devices --------------- ######
+
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users. ###
+### If you have questions about the DMP driver, please contact ###
+### Mark Wedel (master@cats.ucsc.edu). ###
+### If you have questions about the Imagewriter drivers, please contact ###
+### Jonathan Luckey (luckey@rtfm.mlb.fl.us). ###
+### If you have questions about the Imagewriter LQ driver, please ###
+### contact Scott Barker (barkers@cuug.ab.ca). ###
+
+appledmp_=gdevadmp.$(OBJ)
+
+gdevadmp.$(OBJ): gdevadmp.c $(PDEVH)
+
+appledmp.dev: $(appledmp_) page.dev
+ $(SETPDEV) appledmp $(appledmp_)
+
+iwhi.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwhi $(appledmp_)
+
+iwlo.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlo $(appledmp_)
+
+iwlq.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlq $(appledmp_)
+
+### ------------ The Canon BubbleJet BJ10e and BJ200 devices ------------ ###
+
+bj10e_=gdevbj10.$(OBJ)
+
+bj10e.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj10e $(bj10e_)
+
+bj200.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj200 $(bj10e_)
+
+gdevbj10.$(OBJ): gdevbj10.c $(PDEVH)
+
+### ------------- The CalComp Raster Format ----------------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Ernst Muellner (ernst.muellner@oenzl.siemens.de) if you have ###
+### questions. ###
+
+ccr_=gdevccr.$(OBJ)
+ccr.dev: $(ccr_) page.dev
+ $(SETPDEV) ccr $(ccr_)
+
+gdevccr.$(OBJ): gdevccr.c $(PDEVH)
+
+### ----------- The H-P DeskJet and LaserJet printer devices ----------- ###
+
+### These are essentially the same device.
+### NOTE: printing at full resolution (300 DPI) requires a printer
+### with at least 1.5 Mb of memory. 150 DPI only requires .5 Mb.
+### Note that the lj4dith driver is included with the H-P color printer
+### drivers below.
+
+HPPCL=gdevpcl.$(OBJ)
+HPMONO=gdevdjet.$(OBJ) $(HPPCL)
+
+gdevpcl.$(OBJ): gdevpcl.c $(PDEVH) $(gdevpcl_h)
+
+gdevdjet.$(OBJ): gdevdjet.c $(PDEVH) $(gdevpcl_h)
+
+deskjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) deskjet $(HPMONO)
+
+djet500.dev: $(HPMONO) page.dev
+ $(SETPDEV) djet500 $(HPMONO)
+
+laserjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) laserjet $(HPMONO)
+
+ljetplus.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljetplus $(HPMONO)
+
+### Selecting ljet2p provides TIFF (mode 2) compression on LaserJet III,
+### IIIp, IIId, IIIsi, IId, and IIp.
+
+ljet2p.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet2p $(HPMONO)
+
+### Selecting ljet3 provides Delta Row (mode 3) compression on LaserJet III,
+### IIIp, IIId, IIIsi.
+
+ljet3.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3 $(HPMONO)
+
+### Selecting ljet3d also provides duplex printing capability.
+
+ljet3d.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3d $(HPMONO)
+
+### Selecting ljet4 also provides Delta Row compression on LaserJet IV series.
+
+ljet4.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet4 $(HPMONO)
+
+lp2563.dev: $(HPMONO) page.dev
+ $(SETPDEV) lp2563 $(HPMONO)
+
+oce9050.dev: $(HPMONO) page.dev
+ $(SETPDEV) oce9050 $(HPMONO)
+
+### ------------------ The H-P LaserJet 5 and 6 devices ----------------- ###
+
+### These drivers use H-P's new PCL XL printer language, like H-P's
+### LaserJet 5 Enhanced driver for MS Windows. We don't recommend using
+### them:
+### - If you have a LJ 5L or 5P, which isn't a "real" LaserJet 5,
+### use the ljet4 driver instead. (The lj5 drivers won't work.)
+### - If you have any other model of LJ 5 or 6, use the pxlmono
+### driver, which often produces much more compact output.
+
+gdevpxat_h=gdevpxat.h
+gdevpxen_h=gdevpxen.h
+gdevpxop_h=gdevpxop.h
+
+ljet5_=gdevlj56.$(OBJ) $(HPPCL)
+lj5mono.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5mono $(ljet5_)
+
+lj5gray.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5gray $(ljet5_)
+
+gdevlj56.$(OBJ): gdevlj56.c $(PDEVH) $(gdevpcl_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h)
+
+### The H-P DeskJet, PaintJet, and DesignJet family color printer devices.###
+### Note: there are two different 500C drivers, both contributed by users.###
+### If you have questions about the djet500c driver, ###
+### please contact AKayser@et.tudelft.nl. ###
+### If you have questions about the cdj* drivers, ###
+### please contact g.cameron@biomed.abdn.ac.uk. ###
+### If you have questions about the dnj560c driver, ###
+### please contact koert@zen.cais.com. ###
+### If you have questions about the lj4dith driver, ###
+### please contact Eckhard.Rueggeberg@ts.go.dlr.de. ###
+### If you have questions about the BJC600/BJC4000, BJC800, or ESCP ###
+### drivers, please contact Yves.Arrouye@imag.fr. ###
+
+cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+cdeskjet.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdeskjet $(cdeskjet_)
+
+cdjcolor.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjcolor $(cdeskjet_)
+
+cdjmono.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjmono $(cdeskjet_)
+
+cdj500.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj500 $(cdeskjet_)
+
+cdj550.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj550 $(cdeskjet_)
+
+declj250.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) declj250 $(cdeskjet_)
+
+dnj650c.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) dnj650c $(cdeskjet_)
+
+lj4dith.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) lj4dith $(cdeskjet_)
+
+pj.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pj $(cdeskjet_)
+
+pjxl.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl $(cdeskjet_)
+
+pjxl300.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl300 $(cdeskjet_)
+
+# Note: the BJC600 driver also works for the BJC4000.
+bjc600.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc600 $(cdeskjet_)
+
+bjc800.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc800 $(cdeskjet_)
+
+escp.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) escp $(cdeskjet_)
+
+# NB: you can also customise the build if required, using
+# -DBitsPerPixel=<number> if you wish the default to be other than 24
+# for the generic drivers (cdj500, cdj550, pjxl300, pjtest, pjxltest).
+gdevcdj.$(OBJ): gdevcdj.c $(std_h) $(PDEVH) gdevbjc.h\
+ $(gsparam_h) $(gsstate_h) $(gxlum_h)\
+ $(gdevpcl_h)
+
+djet500c_=gdevdjtc.$(OBJ) $(HPPCL)
+djet500c.dev: $(djet500c_) page.dev
+ $(SETPDEV) djet500c $(djet500c_)
+
+gdevdjtc.$(OBJ): gdevdjtc.c $(PDEVH) $(malloc__h) $(gdevpcl_h)
+
+### -------------------- The Mitsubishi CP50 printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Michael Hu (michael@ximage.com) if you have questions. ###
+
+cp50_=gdevcp50.$(OBJ)
+cp50.dev: $(cp50_) page.dev
+ $(SETPDEV) cp50 $(cp50_)
+
+gdevcp50.$(OBJ): gdevcp50.c $(PDEVH)
+
+### ----------------- The generic Epson printer device ----------------- ###
+### Note: most of this code was contributed by users. Please contact ###
+### the following people if you have questions: ###
+### eps9mid - Guenther Thomsen (thomsen@cs.tu-berlin.de) ###
+### eps9high - David Wexelblat (dwex@mtgzfs3.att.com) ###
+### ibmpro - James W. Birdsall (jwbirdsa@picarefy.picarefy.com) ###
+
+epson_=gdevepsn.$(OBJ)
+
+epson.dev: $(epson_) page.dev
+ $(SETPDEV) epson $(epson_)
+
+eps9mid.dev: $(epson_) page.dev
+ $(SETPDEV) eps9mid $(epson_)
+
+eps9high.dev: $(epson_) page.dev
+ $(SETPDEV) eps9high $(epson_)
+
+gdevepsn.$(OBJ): gdevepsn.c $(PDEVH)
+
+### ----------------- The IBM Proprinter printer device ---------------- ###
+
+ibmpro.dev: $(epson_) page.dev
+ $(SETPDEV) ibmpro $(epson_)
+
+### -------------- The Epson LQ-2550 color printer device -------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Dave St. Clair (dave@exlog.com) if you have questions. ###
+
+epsonc_=gdevepsc.$(OBJ)
+epsonc.dev: $(epsonc_) page.dev
+ $(SETPDEV) epsonc $(epsonc_)
+
+gdevepsc.$(OBJ): gdevepsc.c $(PDEVH)
+
+### ------------- The Epson ESC/P 2 language printer devices ------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the Stylus 800 and AP3250 drivers, please contact ###
+### Richard Brown (rab@tauon.ph.unimelb.edu.au). ###
+### For questions about the Stylus Color drivers, please contact ###
+### Gunther Hess (gunther@elmos.de). ###
+
+ESCP2=gdevescp.$(OBJ)
+
+gdevescp.$(OBJ): gdevescp.c $(PDEVH)
+
+ap3250.dev: $(ESCP2) page.dev
+ $(SETPDEV) ap3250 $(ESCP2)
+
+st800.dev: $(ESCP2) page.dev
+ $(SETPDEV) st800 $(ESCP2)
+
+stcolor1_=gdevstc.$(OBJ) gdevstc1.$(OBJ) gdevstc2.$(OBJ)
+stcolor2_=gdevstc3.$(OBJ) gdevstc4.$(OBJ)
+stcolor.dev: $(stcolor1_) $(stcolor2_) page.dev
+ $(SETPDEV) stcolor $(stcolor1_)
+ $(ADDMOD) stcolor -obj $(stcolor2_)
+
+gdevstc.$(OBJ): gdevstc.c gdevstc.h $(PDEVH)
+
+gdevstc1.$(OBJ): gdevstc1.c gdevstc.h $(PDEVH)
+
+gdevstc2.$(OBJ): gdevstc2.c gdevstc.h $(PDEVH)
+
+gdevstc3.$(OBJ): gdevstc3.c gdevstc.h $(PDEVH)
+
+gdevstc4.$(OBJ): gdevstc4.c gdevstc.h $(PDEVH)
+
+### --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+### For questions about this driver, please contact: ###
+### Gunther Hess (gunther@elmos.de) ###
+
+uniprint_=gdevupd.$(OBJ)
+uniprint.dev: $(uniprint_) page.dev
+ $(SETPDEV) uniprint $(uniprint_)
+
+gdevupd.$(OBJ): gdevupd.c $(PDEVH) $(gsparam_h)
+
+### -------------- cdj850 - HP 850c Driver under development ------------- ###
+### Since this driver is in the development-phase it is not distributed ###
+### with ghostscript, but it is available via anonymous ftp from: ###
+### ftp://bonk.ethz.ch ###
+### For questions about this driver, please contact: ###
+### Uli Wortmann (E-Mail address inside the driver-package) ###
+
+cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+cdj850.dev: $(cdeskjet8_) page.dev
+ $(SETPDEV) cdj850 $(cdeskjet8_)
+
+### ------------ The H-P PaintJet color printer device ----------------- ###
+### Note: this driver also supports the DEC LJ250 color printer, which ###
+### has a PaintJet-compatible mode, and the PaintJet XL. ###
+### If you have questions about the XL, please contact Rob Reiss ###
+### (rob@moray.berkeley.edu). ###
+
+PJET=gdevpjet.$(OBJ) $(HPPCL)
+
+gdevpjet.$(OBJ): gdevpjet.c $(PDEVH) $(gdevpcl_h)
+
+lj250.dev: $(PJET) page.dev
+ $(SETPDEV) lj250 $(PJET)
+
+paintjet.dev: $(PJET) page.dev
+ $(SETPDEV) paintjet $(PJET)
+
+pjetxl.dev: $(PJET) page.dev
+ $(SETPDEV) pjetxl $(PJET)
+
+### -------------- Imagen ImPress Laser Printer device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Alan Millar (AMillar@bolis.sf-bay.org) if you have questions. ###
+### Set USE_BYTE_STREAM if using parallel interface; ###
+### Don't set it if using 'ipr' spooler (default). ###
+### You may also add -DA4 if needed for A4 paper. ###
+
+imagen_=gdevimgn.$(OBJ)
+imagen.dev: $(imagen_) page.dev
+ $(SETPDEV) imagen $(imagen_)
+
+gdevimgn.$(OBJ): gdevimgn.c $(PDEVH)
+ $(CCC) gdevimgn.c # for ipr spooler
+# $(CCC) -DUSE_BYTE_STREAM gdevimgn.c # for parallel
+
+### ------- The IBM 3852 JetPrinter color inkjet printer device -------- ###
+### Note: this driver was contributed by users: please contact ###
+### Kevin Gift (kgift@draper.com) if you have questions. ###
+### Note that the paper size that can be addressed by the graphics mode ###
+### used in this driver is fixed at 7-1/2 inches wide (the printable ###
+### width of the jetprinter itself.) ###
+
+jetp3852_=gdev3852.$(OBJ)
+jetp3852.dev: $(jetp3852_) page.dev
+ $(SETPDEV) jetp3852 $(jetp3852_)
+
+gdev3852.$(OBJ): gdev3852.c $(PDEVH) $(gdevpcl_h)
+
+### ---------- The Canon LBP-8II and LIPS III printer devices ---------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about these drivers, please contact ###
+### Lauri Paatero, lauri.paatero@paatero.pp.fi ###
+
+lbp8_=gdevlbp8.$(OBJ)
+lbp8.dev: $(lbp8_) page.dev
+ $(SETPDEV) lbp8 $(lbp8_)
+
+lips3.dev: $(lbp8_) page.dev
+ $(SETPDEV) lips3 $(lbp8_)
+
+gdevlbp8.$(OBJ): gdevlbp8.c $(PDEVH)
+
+### ----------- The DEC LN03/LA50/LA70/LA75 printer devices ------------ ###
+### Note: this driver was contributed by users: please contact ###
+### Ulrich Mueller (ulm@vsnhd1.cern.ch) if you have questions. ###
+### For questions about LA50 and LA75, please contact ###
+### Ian MacPhedran (macphed@dvinci.USask.CA). ###
+### For questions about the LA70, please contact ###
+### Bruce Lowekamp (lowekamp@csugrad.cs.vt.edu). ###
+### For questions about the LA75plus, please contact ###
+### Andre' Beck (Andre_Beck@IRS.Inf.TU-Dresden.de). ###
+
+ln03_=gdevln03.$(OBJ)
+ln03.dev: $(ln03_) page.dev
+ $(SETPDEV) ln03 $(ln03_)
+
+la50.dev: $(ln03_) page.dev
+ $(SETPDEV) la50 $(ln03_)
+
+la70.dev: $(ln03_) page.dev
+ $(SETPDEV) la70 $(ln03_)
+
+la75.dev: $(ln03_) page.dev
+ $(SETPDEV) la75 $(ln03_)
+
+la75plus.dev: $(ln03_) page.dev
+ $(SETPDEV) la75plus $(ln03_)
+
+gdevln03.$(OBJ): gdevln03.c $(PDEVH)
+
+# LA70 driver with low-resolution text enhancement.
+
+la70t_=gdevla7t.$(OBJ)
+la70t.dev: $(la70t_) page.dev
+ $(SETPDEV) la70t $(la70t_)
+
+gdevla7t.$(OBJ): gdevla7t.c $(PDEVH)
+
+### -------------- The Epson LP-8000 laser printer device -------------- ###
+### Note: this driver was contributed by a user: please contact Oleg ###
+### Oleg Fat'yanov <faty1@rlem.titech.ac.jp> if you have questions.###
+
+lp8000_=gdevlp8k.$(OBJ)
+lp8000.dev: $(lp8000_) page.dev
+ $(SETPDEV) lp8000 $(lp8000_)
+
+gdevlp8k.$(OBJ): gdevlp8k.c $(PDEVH)
+
+### -------------- The C.Itoh M8510 printer device --------------------- ###
+### Note: this driver was contributed by a user: please contact Bob ###
+### Smith <bob@snuffy.penfield.ny.us> if you have questions. ###
+
+m8510_=gdev8510.$(OBJ)
+m8510.dev: $(m8510_) page.dev
+ $(SETPDEV) m8510 $(m8510_)
+
+gdev8510.$(OBJ): gdev8510.c $(PDEVH)
+
+### -------------- 24pin Dot-matrix printer with 360DPI ---------------- ###
+### Note: this driver was contributed by users. Please contact: ###
+### Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) for ###
+### questions about the NEC P6; ###
+### Christian Felsch (felsch@tu-harburg.d400.de) for ###
+### questions about the Epson LQ850. ###
+
+dm24_=gdevdm24.$(OBJ)
+gdevdm24.$(OBJ): gdevdm24.c $(PDEVH)
+
+necp6.dev: $(dm24_) page.dev
+ $(SETPDEV) necp6 $(dm24_)
+
+lq850.dev: $(dm24_) page.dev
+ $(SETPDEV) lq850 $(dm24_)
+
+### ----------------- The Okidata MicroLine 182 device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Maarten Koning (smeg@bnr.ca) if you have questions. ###
+
+oki182_=gdevo182.$(OBJ)
+oki182.dev: $(oki182_) page.dev
+ $(SETPDEV) oki182 $(oki182_)
+
+gdevo182.$(OBJ): gdevo182.c $(PDEVH)
+
+### ------------- The Okidata IBM compatible printer device ------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Charles Mack (chasm@netcom.com) if you have questions. ###
+
+okiibm_=gdevokii.$(OBJ)
+okiibm.dev: $(okiibm_) page.dev
+ $(SETPDEV) okiibm $(okiibm_)
+
+gdevokii.$(OBJ): gdevokii.c $(PDEVH)
+
+### ------------- The Ricoh 4081 laser printer device ------------------ ###
+### Note: this driver was contributed by users: ###
+### please contact kdw@oasis.icl.co.uk if you have questions. ###
+
+r4081_=gdev4081.$(OBJ)
+r4081.dev: $(r4081_) page.dev
+ $(SETPDEV) r4081 $(r4081_)
+
+
+gdev4081.$(OBJ): gdev4081.c $(PDEVH)
+
+### -------------------- Sony NWP533 printer device -------------------- ###
+### Note: this driver was contributed by a user: please contact Tero ###
+### Kivinen (kivinen@joker.cs.hut.fi) if you have questions. ###
+
+nwp533_=gdevn533.$(OBJ)
+nwp533.dev: $(nwp533_) page.dev
+ $(SETPDEV) nwp533 $(nwp533_)
+
+gdevn533.$(OBJ): gdevn533.c $(PDEVH)
+
+### ------------------------- The SPARCprinter ------------------------- ###
+### Note: this driver was contributed by users: please contact Martin ###
+### Schulte (schulte@thp.uni-koeln.de) if you have questions. ###
+### He would also like to hear from anyone using the driver. ###
+### Please consult the source code for additional documentation. ###
+
+sparc_=gdevsppr.$(OBJ)
+sparc.dev: $(sparc_) page.dev
+ $(SETPDEV) sparc $(sparc_)
+
+gdevsppr.$(OBJ): gdevsppr.c $(PDEVH)
+
+### ----------------- The StarJet SJ48 device -------------------------- ###
+### Note: this driver was contributed by a user: if you have questions, ###
+### . ###
+### please contact Mats Akerblom (f86ma@dd.chalmers.se). ###
+
+sj48_=gdevsj48.$(OBJ)
+sj48.dev: $(sj48_) page.dev
+ $(SETPDEV) sj48 $(sj48_)
+
+gdevsj48.$(OBJ): gdevsj48.c $(PDEVH)
+
+### ----------------- Tektronix 4396d color printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karl Hakimian (hakimian@haney.eecs.wsu.edu) ###
+### if you have questions. ###
+
+t4693d_=gdev4693.$(OBJ)
+t4693d2.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d2 $(t4693d_)
+
+t4693d4.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d4 $(t4693d_)
+
+t4693d8.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d8 $(t4693d_)
+
+gdev4693.$(OBJ): gdev4693.c $(PDEVH)
+
+### -------------------- Tektronix ink-jet printers -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karsten Spang (spang@nbivax.nbi.dk) if you have questions. ###
+
+tek4696_=gdevtknk.$(OBJ)
+tek4696.dev: $(tek4696_) page.dev
+ $(SETPDEV) tek4696 $(tek4696_)
+
+gdevtknk.$(OBJ): gdevtknk.c $(PDEVH) $(malloc__h)
+
+### ----------------- The Xerox XES printer device --------------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Peter Flass (flass@lbdrscs.bitnet) if you have questions. ###
+
+xes_=gdevxes.$(OBJ)
+xes.dev: $(xes_) page.dev
+ $(SETPDEV) xes $(xes_)
+
+gdevxes.$(OBJ): gdevxes.c $(PDEVH)
+
+###### ------------------------- Fax devices ------------------------- ######
+
+### --------------- Generic PostScript system compatible fax ------------ ###
+
+# This code doesn't work yet. Don't even think about using it.
+
+PSFAX=gdevpfax.$(OBJ)
+
+psfax_=$(PSFAX)
+psfax.dev: $(psfax_) page.dev
+ $(SETPDEV) psfax $(psfax_)
+ $(ADDMOD) psfax -iodev Fax
+
+gdevpfax.$(OBJ): gdevpfax.c $(PDEVH) $(gsparam_h) $(gxiodev_h)
+
+### ------------------------- The DigiFAX device ------------------------ ###
+### This driver outputs images in a format suitable for use with ###
+### DigiBoard, Inc.'s DigiFAX software. Use -sDEVICE=dfaxhigh for ###
+### high resolution output, -sDEVICE=dfaxlow for normal output. ###
+### Note: this driver was contributed by a user: please contact ###
+### Rick Richardson (rick@digibd.com) if you have questions. ###
+
+dfax_=gdevdfax.$(OBJ) gdevtfax.$(OBJ)
+
+dfaxlow.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxlow $(dfax_)
+ $(ADDMOD) dfaxlow -include cfe
+
+dfaxhigh.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxhigh $(dfax_)
+ $(ADDMOD) dfaxhigh -include cfe
+
+gdevdfax.$(OBJ): gdevdfax.c $(PDEVH) $(scfx_h) $(strimpl_h)
+
+### --------------See under TIFF below for fax-format TIFF -------------- ###
+
+###### ------------------- High-level file formats ------------------- ######
+
+# Support for PostScript and PDF
+
+gdevpsdf_h=gdevpsdf.h $(gdevvec_h) $(strimpl_h)
+gdevpstr_h=gdevpstr.h
+
+gdevpsdf.$(OBJ): gdevpsdf.c $(stdio__h) $(string__h)\
+ $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsparam_h) $(gstypes_h)\
+ $(gxdevice_h)\
+ $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpstr.$(OBJ): gdevpstr.c $(math__h) $(stdio__h) $(string__h)\
+ $(gdevpstr_h) $(stream_h)
+
+# PostScript and EPS writers
+
+pswrite1_=gdevps.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pswrite2_=scantab.$(OBJ) sfilter2.$(OBJ)
+pswrite_=$(pswrite1_) $(pswrite2_)
+epswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) epswrite $(pswrite1_)
+ $(ADDMOD) epswrite $(pswrite2_)
+ $(ADDMOD) epswrite -include vector
+
+pswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) pswrite $(pswrite1_)
+ $(ADDMOD) pswrite $(pswrite2_)
+ $(ADDMOD) pswrite -include vector
+
+gdevps.$(OBJ): gdevps.c $(GDEV) $(math__h) $(time__h)\
+ $(gscdefs_h) $(gscspace_h) $(gsparam_h) $(gsiparam_h) $(gsmatrix_h)\
+ $(gxdcolor_h)\
+ $(sa85x_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+# PDF writer
+# Note that gs_pdfwr.ps will only actually be loaded if the configuration
+# includes a PostScript interpreter.
+
+pdfwrite1_=gdevpdf.$(OBJ) gdevpdfd.$(OBJ) gdevpdfi.$(OBJ) gdevpdfm.$(OBJ)
+pdfwrite2_=gdevpdfp.$(OBJ) gdevpdft.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pdfwrite3_=gsflip.$(OBJ) scantab.$(OBJ) sfilter2.$(OBJ) sstring.$(OBJ)
+pdfwrite_=$(pdfwrite1_) $(pdfwrite2_) $(pdfwrite3_)
+pdfwrite.dev: $(ECHOGS_XE) $(pdfwrite_) \
+ cmyklib.dev cfe.dev dcte.dev lzwe.dev rle.dev vector.dev
+ $(SETDEV) pdfwrite $(pdfwrite1_)
+ $(ADDMOD) pdfwrite $(pdfwrite2_)
+ $(ADDMOD) pdfwrite $(pdfwrite3_)
+ $(ADDMOD) pdfwrite -ps gs_pdfwr
+ $(ADDMOD) pdfwrite -include cmyklib cfe dcte lzwe rle vector
+
+gdevpdfx_h=gdevpdfx.h $(gsparam_h) $(gxdevice_h) $(gxline_h) $(stream_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpdf.$(OBJ): gdevpdf.c $(math__h) $(memory__h) $(string__h) $(time__h)\
+ $(gp_h)\
+ $(gdevpdfx_h) $(gscdefs_h) $(gserrors_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)\
+ $(scanchar_h) $(scfx_h) $(slzwx_h) $(sstring_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) gdevpdf.c
+
+gdevpdfd.$(OBJ): gdevpdfd.c $(math__h)\
+ $(gdevpdfx_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+gdevpdfi.$(OBJ): gdevpdfi.c $(math__h) $(memory__h) $(gx_h) \
+ $(gdevpdfx_h) $(gscie_h) $(gscolor2_h) $(gserrors_h) $(gsflip_h)\
+ $(gxcspace_h) $(gxistate_h) \
+ $(sa85x_h) $(scfx_h) $(srlx_h) $(strimpl_h)
+
+gdevpdfm.$(OBJ): gdevpdfm.c $(memory__h) $(string__h) $(gx_h) \
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h) $(scanchar_h)
+
+gdevpdfp.$(OBJ): gdevpdfp.c $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h)
+
+gdevpdft.$(OBJ): gdevpdft.c $(math__h) $(memory__h) $(string__h) $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h)\
+ $(scommon_h)
+
+# High-level PCL XL writer
+
+pxl_=gdevpx.$(OBJ)
+pxlmono.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlmono $(pxl_)
+ $(ADDMOD) pxlmono -include vector
+
+pxlcolor.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlcolor $(pxl_)
+ $(ADDMOD) pxlcolor -include vector
+
+gdevpx.$(OBJ): gdevpx.c $(math__h) $(memory__h) $(string__h)\
+ $(gx_h) $(gsccolor_h) $(gsdcolor_h) $(gserrors_h)\
+ $(gxcspace_h) $(gxdevice_h) $(gxpath_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h) $(gdevvec_h)\
+ $(srlx_h) $(strimpl_h)
+
+###### --------------------- Raster file formats --------------------- ######
+
+### --------------------- The "plain bits" devices ---------------------- ###
+
+bit_=gdevbit.$(OBJ)
+
+bit.dev: $(bit_) page.dev
+ $(SETPDEV) bit $(bit_)
+
+bitrgb.dev: $(bit_) page.dev
+ $(SETPDEV) bitrgb $(bit_)
+
+bitcmyk.dev: $(bit_) page.dev
+ $(SETPDEV) bitcmyk $(bit_)
+
+gdevbit.$(OBJ): gdevbit.c $(PDEVH) $(gsparam_h) $(gxlum_h)
+
+### ------------------------- .BMP file formats ------------------------- ###
+
+bmp_=gdevbmp.$(OBJ) gdevpccm.$(OBJ)
+
+gdevbmp.$(OBJ): gdevbmp.c $(PDEVH) $(gdevpccm_h)
+
+bmpmono.dev: $(bmp_) page.dev
+ $(SETPDEV) bmpmono $(bmp_)
+
+bmp16.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16 $(bmp_)
+
+bmp256.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp256 $(bmp_)
+
+bmp16m.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16m $(bmp_)
+
+### ------------- BMP driver that serves as demo of async rendering ---- ###
+devasync_=gdevasyn.$(OBJ) gdevpccm.$(OBJ) gxsync.$(OBJ)
+
+gdevasyn.$(OBJ): gdevasyn.c $(AK) $(stdio__h) $(gdevprna_h) $(gdevpccm_h)\
+ $(gserrors_h) $(gpsync_h)
+
+asynmono.dev: $(devasync_) page.dev async.dev
+ $(SETPDEV) asynmono $(devasync_)
+ $(ADDMOD) asynmono -include async
+
+
+### -------------------------- CGM file format ------------------------- ###
+### This driver is under development. Use at your own risk. ###
+### The output is very low-level, consisting only of rectangles and ###
+### cell arrays. ###
+
+cgm_=gdevcgm.$(OBJ) gdevcgml.$(OBJ)
+
+gdevcgml_h=gdevcgml.h
+gdevcgmx_h=gdevcgmx.h $(gdevcgml_h)
+
+gdevcgm.$(OBJ): gdevcgm.c $(GDEV) $(memory__h)\
+ $(gsparam_h) $(gdevpccm_h) $(gdevcgml_h)
+
+gdevcgml.$(OBJ): gdevcgml.c $(memory__h) $(stdio__h)\
+ $(gdevcgmx_h)
+
+cgmmono.dev: $(cgm_)
+ $(SETDEV) cgmmono $(cgm_)
+
+cgm8.dev: $(cgm_)
+ $(SETDEV) cgm8 $(cgm_)
+
+cgm24.dev: $(cgm_)
+ $(SETDEV) cgm24 $(cgm_)
+
+### -------------------- The CIF file format for VLSI ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Frederic Petrot (petrot@masi.ibp.fr) if you have questions. ###
+
+cif_=gdevcif.$(OBJ)
+cif.dev: $(cif_) page.dev
+ $(SETPDEV) cif $(cif_)
+
+gdevcif.$(OBJ): gdevcif.c $(PDEVH)
+
+### ------------------------- JPEG file format ------------------------- ###
+
+jpeg_=gdevjpeg.$(OBJ)
+
+# RGB output
+jpeg.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeg $(jpeg_)
+ $(ADDMOD) jpeg -include sdcte
+
+# Gray output
+jpeggray.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeggray $(jpeg_)
+ $(ADDMOD) jpeggray -include sdcte
+
+gdevjpeg.$(OBJ): gdevjpeg.c $(stdio__h) $(PDEVH)\
+ $(sdct_h) $(sjpeg_h) $(stream_h) $(strimpl_h) jpeglib.h
+
+### ------------------------- MIFF file format ------------------------- ###
+### Right now we support only 24-bit direct color, but we might add more ###
+### formats in the future. ###
+
+miff_=gdevmiff.$(OBJ)
+
+miff24.dev: $(miff_) page.dev
+ $(SETPDEV) miff24 $(miff_)
+
+gdevmiff.$(OBJ): gdevmiff.c $(PDEVH)
+
+### --------------------------- MGR devices ---------------------------- ###
+### Note: these drivers were contributed by a user: please contact ###
+### Carsten Emde (carsten@ce.pr.net.ch) if you have questions. ###
+
+MGR=gdevmgr.$(OBJ) gdevpccm.$(OBJ)
+
+gdevmgr.$(OBJ): gdevmgr.c $(PDEVH) $(gdevpccm_h) gdevmgr.h
+
+mgrmono.dev: $(MGR) page.dev
+ $(SETPDEV) mgrmono $(MGR)
+
+mgrgray2.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray2 $(MGR)
+
+mgrgray4.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray4 $(MGR)
+
+mgrgray8.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray8 $(MGR)
+
+mgr4.dev: $(MGR) page.dev
+ $(SETPDEV) mgr4 $(MGR)
+
+mgr8.dev: $(MGR) page.dev
+ $(SETPDEV) mgr8 $(MGR)
+
+### ------------------------- PCX file formats ------------------------- ###
+
+pcx_=gdevpcx.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpcx.$(OBJ): gdevpcx.c $(PDEVH) $(gdevpccm_h) $(gxlum_h)
+
+pcxmono.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxmono $(pcx_)
+
+pcxgray.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxgray $(pcx_)
+
+pcx16.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx16 $(pcx_)
+
+pcx256.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx256 $(pcx_)
+
+pcx24b.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx24b $(pcx_)
+
+pcxcmyk.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxcmyk $(pcx_)
+
+# The 2-up PCX device is here only as an example, and for testing.
+pcx2up.dev: $(LIB_MAK) $(ECHOGS_XE) gdevp2up.$(OBJ) page.dev pcx256.dev
+ $(SETPDEV) pcx2up gdevp2up.$(OBJ)
+ $(ADDMOD) pcx2up -include pcx256
+
+gdevp2up.$(OBJ): gdevp2up.c $(AK)\
+ $(gdevpccm_h) $(gdevprn_h) $(gxclpage_h)
+
+### ------------------- Portable Bitmap file formats ------------------- ###
+### For more information, see the pbm(5), pgm(5), and ppm(5) man pages. ###
+
+pxm_=gdevpbm.$(OBJ)
+
+gdevpbm.$(OBJ): gdevpbm.c $(PDEVH) $(gscdefs_h) $(gxlum_h)
+
+### Portable Bitmap (PBM, plain or raw format, magic numbers "P1" or "P4")
+
+pbm.dev: $(pxm_) page.dev
+ $(SETPDEV) pbm $(pxm_)
+
+pbmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pbmraw $(pxm_)
+
+### Portable Graymap (PGM, plain or raw format, magic numbers "P2" or "P5")
+
+pgm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgm $(pxm_)
+
+pgmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgmraw $(pxm_)
+
+# PGM with automatic optimization to PBM if this is possible.
+
+pgnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnm $(pxm_)
+
+pgnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnmraw $(pxm_)
+
+### Portable Pixmap (PPM, plain or raw format, magic numbers "P3" or "P6")
+
+ppm.dev: $(pxm_) page.dev
+ $(SETPDEV) ppm $(pxm_)
+
+ppmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) ppmraw $(pxm_)
+
+# PPM with automatic optimization to PGM or PBM if possible.
+
+pnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pnm $(pxm_)
+
+pnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pnmraw $(pxm_)
+
+### Portable inKmap (CMYK internally, converted to PPM=RGB at output time)
+
+pkm.dev: $(pxm_) page.dev
+ $(SETPDEV) pkm $(pxm_)
+
+pkmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pkmraw $(pxm_)
+
+### --------------- Portable Network Graphics file format --------------- ###
+### Requires libpng 0.81 and zlib 0.95 (or more recent versions). ###
+### See libpng.mak and zlib.mak for more details. ###
+
+png_=gdevpng.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpng.$(OBJ): gdevpng.c $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(PSRC)png.h
+ $(CCCP) gdevpng.c
+
+pngmono.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pngmono $(png_)
+ $(ADDMOD) pngmono -include libpng
+
+pnggray.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pnggray $(png_)
+ $(ADDMOD) pnggray -include libpng
+
+png16.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16 $(png_)
+ $(ADDMOD) png16 -include libpng
+
+png256.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png256 $(png_)
+ $(ADDMOD) png256 -include libpng
+
+png16m.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16m $(png_)
+ $(ADDMOD) png16m -include libpng
+
+### ---------------------- PostScript image format ---------------------- ###
+### These devices make it possible to print Level 2 files on a Level 1 ###
+### printer, by converting them to a bitmap in PostScript format. ###
+
+ps_=gdevpsim.$(OBJ)
+
+gdevpsim.$(OBJ): gdevpsim.c $(PDEVH)
+
+psmono.dev: $(ps_) page.dev
+ $(SETPDEV) psmono $(ps_)
+
+psgray.dev: $(ps_) page.dev
+ $(SETPDEV) psgray $(ps_)
+
+# Someday there will be RGB and CMYK variants....
+
+### -------------------------- SGI RGB pixmaps -------------------------- ###
+
+sgirgb_=gdevsgi.$(OBJ)
+
+gdevsgi.$(OBJ): gdevsgi.c $(PDEVH) gdevsgi.h
+
+sgirgb.dev: $(sgirgb_) page.dev
+ $(SETPDEV) sgirgb $(sgirgb_)
+
+### -------------------- Plain or TIFF fax encoding --------------------- ###
+### Use -sDEVICE=tiffg3 or tiffg4 and ###
+### -r204x98 for low resolution output, or ###
+### -r204x196 for high resolution output ###
+### These drivers recognize 3 page sizes: letter, A4, and B4. ###
+
+gdevtifs_h=gdevtifs.h
+
+tfax_=gdevtfax.$(OBJ)
+tfax.dev: $(tfax_) cfe.dev lzwe.dev rle.dev tiffs.dev
+ $(SETMOD) tfax $(tfax_)
+ $(ADDMOD) tfax -include cfe lzwe rle tiffs
+
+gdevtfax.$(OBJ): gdevtfax.c $(PDEVH)\
+ $(gdevtifs_h) $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)
+
+### Plain G3/G4 fax with no header
+
+faxg3.dev: tfax.dev
+ $(SETDEV) faxg3 -include tfax
+
+faxg32d.dev: tfax.dev
+ $(SETDEV) faxg32d -include tfax
+
+faxg4.dev: tfax.dev
+ $(SETDEV) faxg4 -include tfax
+
+### ---------------------------- TIFF formats --------------------------- ###
+
+tiffs_=gdevtifs.$(OBJ)
+tiffs.dev: $(tiffs_) page.dev
+ $(SETMOD) tiffs $(tiffs_)
+ $(ADDMOD) tiffs -include page
+
+gdevtifs.$(OBJ): gdevtifs.c $(PDEVH) $(stdio__h) $(time__h) \
+ $(gdevtifs_h) $(gscdefs_h) $(gstypes_h)
+
+# Black & white, G3/G4 fax
+
+tiffcrle.dev: tfax.dev
+ $(SETDEV) tiffcrle -include tfax
+
+tiffg3.dev: tfax.dev
+ $(SETDEV) tiffg3 -include tfax
+
+tiffg32d.dev: tfax.dev
+ $(SETDEV) tiffg32d -include tfax
+
+tiffg4.dev: tfax.dev
+ $(SETDEV) tiffg4 -include tfax
+
+# Black & white, LZW compression
+
+tifflzw.dev: tfax.dev
+ $(SETDEV) tifflzw -include tfax
+
+# Black & white, PackBits compression
+
+tiffpack.dev: tfax.dev
+ $(SETDEV) tiffpack -include tfax
+
+# RGB, no compression
+
+tiffrgb_=gdevtfnx.$(OBJ)
+
+tiff12nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff12nc $(tiffrgb_)
+ $(ADDMOD) tiff12nc -include tiffs
+
+tiff24nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff24nc $(tiffrgb_)
+ $(ADDMOD) tiff24nc -include tiffs
+
+gdevtfnx.$(OBJ): gdevtfnx.c $(PDEVH) $(gdevtifs_h)
+# Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This is the last part of the makefile for Unix configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define the name of this makefile.
+UNIXTAIL_MAK=unixtail.mak
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Unix platforms
+
+# We have to include a test for the existence of sys/time.h,
+# because some System V platforms don't have it.
+
+# Define pipes as a separable feature.
+
+pipe_=gdevpipe.$(OBJ)
+pipe.dev: $(UNIXTAIL_MAK) $(ECHOGS_XE) $(pipe_)
+ $(SETMOD) pipe $(pipe_)
+ $(ADDMOD) pipe -iodev pipe
+
+gdevpipe.$(OBJ): gdevpipe.c $(AK) $(errno__h) $(stdio__h) $(string__h) \
+ $(gserror_h) $(gsmemory_h) $(gstypes_h) $(gxiodev_h) $(stream_h)
+
+# Unix platforms other than System V, and also System V Release 4
+# (SVR4) platforms.
+unix__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ)
+unix_.dev: $(unix__)
+ $(SETMOD) unix_ $(unix__)
+
+gp_unix.$(OBJ): gp_unix.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h)
+
+# System V platforms other than SVR4, which lack some system calls,
+# but have pipes.
+sysv__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ) gp_sysv.$(OBJ)
+sysv_.dev: $(sysv__)
+ $(SETMOD) sysv_ $(sysv__)
+
+gp_sysv.$(OBJ): gp_sysv.c $(stdio__h) $(time__h) $(AK)
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c
+ $(CCA2K) $(O)$(ANSI2KNR_XE) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c $(AK)
+ $(CCAUX) $(O)$(ECHOGS_XE) echogs.c
+
+# On the RS/6000 (at least), compiling genarch.c with gcc with -O
+# produces a buggy executable.
+$(GENARCH_XE): genarch.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENARCH_XE) genarch.c
+
+$(GENCONF_XE): genconf.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENCONF_XE) genconf.c
+
+$(GENINIT_XE): geninit.c $(AK) $(stdio__h) $(string__h)
+ $(CCAUX) $(O)$(GENINIT_XE) geninit.c
+
+# Query the environment to construct gconfig_.h.
+# The "else true; is required because Ultrix's implementation of sh -e
+# terminates execution of a command if any error occurs, even if the command
+# traps the error with ||.
+INCLUDE=/usr/include
+gconfig_.h: $(UNIXTAIL_MAK) $(ECHOGS_XE)
+ ./echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ if ( test -f $(INCLUDE)/dirent.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H; else true; fi
+ if ( test -f $(INCLUDE)/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/dir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_DIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/time.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/times.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIMES_H; else true; fi
+
+# ----------------------------- Main program ------------------------------ #
+
+### Library files and archive
+
+LIB_ARCHIVE_ALL=$(LIB_ALL) $(DEVS_ALL)\
+ gsnogc.$(OBJ) gconfig.$(OBJ) gscdefs.$(OBJ)
+
+# Build an archive for the library only.
+# This is not used in a standard build.
+GSLIB_A=$(GS)lib.a
+$(GSLIB_A): $(LIB_ARCHIVE_ALL)
+ rm -f $(GSLIB_A)
+ $(AR) $(ARFLAGS) $(GSLIB_A) $(LIB_ARCHIVE_ALL)
+ $(RANLIB) $(GSLIB_A)
+
+### Interpreter main program
+
+INT_ARCHIVE_ALL=imainarg.$(OBJ) imain.$(OBJ) $(INT_ALL) $(DEVS_ALL)\
+ gconfig.$(OBJ) gscdefs.$(OBJ)
+XE_ALL=gs.$(OBJ) $(INT_ARCHIVE_ALL)
+
+# Build a library archive for the entire interpreter.
+# This is not used in a standard build.
+GS_A=$(GS).a
+$(GS_A): $(INT_ARCHIVE_ALL)
+ rm -f $(GS_A)
+ $(AR) $(ARFLAGS) $(GS_A) $(INT_ARCHIVE_ALL)
+ $(RANLIB) $(GS_A)
+
+# Here is the final link step. The stuff with LD_RUN_PATH is for SVR4
+# systems with dynamic library loading; I believe it's harmless elsewhere.
+# The resetting of the environment variables to empty strings is for SCO Unix,
+# which has limited environment space.
+$(GS_XE): ld.tr echogs $(XE_ALL)
+ ./echogs -w ldt.tr -n - $(CCLD) $(LDFLAGS) $(XLIBDIRS) -o $(GS_XE)
+ ./echogs -a ldt.tr -n -s gs.$(OBJ) -s
+ cat ld.tr >>ldt.tr
+ ./echogs -a ldt.tr -s - $(EXTRALIBS) -lm
+ LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; \
+ XCFLAGS= XINCLUDE= XLDFLAGS= XLIBDIRS= XLIBS= \
+ FEATURE_DEVS= DEVICE_DEVS= DEVICE_DEVS1= DEVICE_DEVS2= DEVICE_DEVS3= \
+ DEVICE_DEVS4= DEVICE_DEVS5= DEVICE_DEVS6= DEVICE_DEVS7= DEVICE_DEVS8= \
+ DEVICE_DEVS9= DEVICE_DEVS10= DEVICE_DEVS11= DEVICE_DEVS12= \
+ DEVICE_DEVS13= DEVICE_DEVS14= DEVICE_DEVS15= \
+ $(SH) <ldt.tr
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix and Desqview/X configurations.
+
+# This is the very last part of the makefile for these configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define a rule for building profiling configurations.
+pg:
+ make GENOPT='' CFLAGS='-pg -O2 $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+# Define a rule for building debugging configurations.
+debug:
+ make GENOPT='-DDEBUG' CFLAGS='-g -O $(GCFLAGS) $(XCFLAGS)'
+
+# The rule for gconfigv.h is here because it is shared between Unix and
+# DV/X environments.
+gconfigv.h: unix-end.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# The following rules are equivalent to what tar_cat does.
+# The rm -f is so that we don't overwrite a file that `make'
+# may currently be reading from.
+GENERIC_MAK_LIST=$(GS_MAK) $(LIB_MAK) $(INT_MAK) $(JPEG_MAK) $(LIBPNG_MAK) $(ZLIB_MAK) $(DEVS_MAK)
+UNIX_MAK_LIST=dvx-gcc.mak unixansi.mak unix-cc.mak unix-gcc.mak
+
+unix.mak: $(UNIX_MAK_LIST)
+
+DVX_GCC_MAK=$(VERSION_MAK) dgc-head.mak dvx-head.mak $(GENERIC_MAK_LIST) dvx-tail.mak unix-end.mak
+dvx-gcc.mak: $(DVX_GCC_MAK)
+ rm -f dvx-gcc.mak
+ $(CAT) $(DVX_GCC_MAK) >dvx-gcc.mak
+
+UNIXANSI_MAK=$(VERSION_MAK) ansihead.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unixansi.mak: $(UNIXANSI_MAK)
+ rm -f unixansi.mak
+ $(CAT) $(UNIXANSI_MAK) >unixansi.mak
+
+UNIX_CC_MAK=$(VERSION_MAK) cc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-cc.mak: $(UNIX_CC_MAK)
+ rm -f unix-cc.mak
+ $(CAT) $(UNIX_CC_MAK) >unix-cc.mak
+
+UNIX_GCC_MAK=$(VERSION_MAK) gcc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-gcc.mak: $(UNIX_GCC_MAK)
+ rm -f unix-gcc.mak
+ $(CAT) $(UNIX_GCC_MAK) >unix-gcc.mak
+
+# Installation
+
+TAGS:
+ etags -t *.c *.h
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+install-exec: $(GS)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(scriptdir)
+ sh -c 'for f in gsbj gsdj gsdj500 gslj gslp gsnd bdftops font2c \
+pdf2dsc pdf2ps printafm ps2ascii ps2epsi ps2pdf wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pfbtogs.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps gs_pdf.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps pdf_2ps.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/unixansi.mak b/gs/src/unixansi.mak
new file mode 100755
index 000000000..8387d6e73
--- /dev/null
+++ b/gs/src/unixansi.mak
@@ -0,0 +1,5771 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile fragment containing the current revision identification.
+
+# Define the name of this makefile.
+VERSION_MAK=version.mak
+
+# Major and minor version numbers.
+# MINOR0 is different from MINOR only if MINOR is a single digit.
+GS_VERSION_MAJOR=5
+GS_VERSION_MINOR=13
+GS_VERSION_MINOR0=13
+# Revision date: year x 10000 + month x 100 + day.
+GS_REVISIONDATE=19980427
+
+# Derived values
+GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0)
+GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR)
+GS_REVISION=$(GS_VERSION)
+# Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Unix/ANSI C/X11 configuration.
+
+#****************************************************************#
+# If you want to change options, DO NOT edit unixansi.mak #
+# or makefile. Edit ansihead.mak and run the tar_cat script. #
+#****************************************************************#
+
+# ------------------------------- Options ------------------------------- #
+
+####### The following are the only parts of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the installation commands and target directories for
+# executables and files. The commands are only relevant to `make install';
+# the directories also define the default search path for the
+# initialization files (gs_*.ps) and the fonts.
+
+# If your system has installbsd, change install to installbsd in the next line.
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL) -m 755
+INSTALL_DATA = $(INSTALL) -m 644
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+scriptdir = $(bindir)
+mandir = $(prefix)/man
+man1ext = 1
+man1dir = $(mandir)/man$(man1ext)
+datadir = $(prefix)/share
+gsdir = $(datadir)/ghostscript
+gsdatadir = $(gsdir)/$(GS_DOT_VERSION)
+
+docdir=$(gsdatadir)/doc
+exdir=$(gsdatadir)/examples
+GS_DOCDIR=$(docdir)
+
+# Define the default directory/ies for the runtime initialization and
+# font files. Separate multiple directories with a :.
+
+GS_LIB_DEFAULT=$(gsdatadir):$(gsdir)/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# -DDEBUG
+# includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches
+# are set.
+# -DNOPRIVATE
+# makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty.
+
+GENOPT=
+
+# Define the name of the executable file.
+
+GS=gs
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Choose whether to use a shared version of the PNG library, and if so,
+# what its name is.
+# See gs.mak and make.txt for more information.
+
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Choose whether to use a shared version of the zlib library, and if so,
+# what its name is (usually libz, but sometimes libgz).
+# See gs.mak and make.txt for more information.
+
+SHARE_ZLIB=0
+#ZLIB_NAME=gz
+ZLIB_NAME=z
+
+# Define how to build the library archives. (These are not used in any
+# standard configuration.)
+
+AR=ar
+ARFLAGS=qc
+RANLIB=ranlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# ------ Platform-specific options ------ #
+
+# Define the name of the C compiler. If the standard compiler for your
+# platform is ANSI-compatible, leave this line commented out; if not,
+# uncomment the line and insert the proper definition.
+
+#CC=some_C_compiler
+
+# Define the name of the linker for the final link step.
+# Normally this is the same as the C compiler.
+
+CCLD=$(CC)
+
+# Define the other compilation flags. Add at most one of the following:
+# -Aa -w -D_HPUX_SOURCE for the HP 400.
+# -DBSD4_2 for 4.2bsd systems.
+# -DSYSV for System V or DG/UX.
+# -DSVR4 -DSVR4_0 (not -DSYSV) for System V release 4.0.
+# -DSVR4 (not -DSYSV) for System V release 4.2 (or later) and Solaris 2.
+# XCFLAGS can be set from the command line.
+XCFLAGS=
+
+CFLAGS=-O $(XCFLAGS)
+
+# Define platform flags for ld.
+# SunOS and some others want -X; Ultrix wants -x.
+# SunOS 4.n may need -Bstatic.
+# Apollos running DomainOS don't support -X (and -x has no effect).
+# XLDFLAGS can be set from the command line.
+XLDFLAGS=
+
+LDFLAGS=$(XLDFLAGS)
+
+# Define any extra libraries to link into the executable.
+# ISC Unix 2.2 wants -linet.
+# SCO Unix needs -lsocket if you aren't including the X11 driver.
+# SVR4 may need -lnsl.
+# (Libraries required by individual drivers are handled automatically.)
+
+EXTRALIBS=
+
+# Define the include switch(es) for the X11 header files.
+# This can be null if handled in some other way (e.g., the files are
+# in /usr/include, or the directory is supplied by an environment variable);
+# in particular, SCO Xenix, Unix, and ODT just want
+#XINCLUDE=
+# Note that x_.h expects to find the header files in $(XINCLUDE)/X11,
+# not in $(XINCLUDE).
+
+XINCLUDE=-I/usr/local/X/include
+
+# Define the directory/ies and library names for the X11 library files.
+# XLIBDIRS is for ld and should include -L; XLIBDIR is for LD_RUN_PATH
+# (dynamic libraries on SVR4) and should not include -L.
+# Both can be null if these files are in the default linker search path;
+# in particular, SCO Xenix, Unix, and ODT just want
+#XLIBDIRS=
+# Solaris and other SVR4 systems with dynamic linking probably want
+#XLIBDIRS=-L/usr/openwin/lib
+#XLIBDIR=/usr/openwin/lib
+# X11R6 (on any platform) may need
+#XLIBS=Xt SM ICE Xext X11
+
+XLIBDIRS=-L/usr/local/X/lib
+XLIBDIR=
+XLIBS=Xt Xext X11
+
+# Define whether this platform has floating point hardware:
+# FPU_TYPE=2 means floating point is faster than fixed point.
+# (This is the case on some RISCs with multiple instruction dispatch.)
+# FPU_TYPE=1 means floating point is at worst only slightly slower
+# than fixed point.
+# FPU_TYPE=0 means that floating point may be considerably slower.
+# FPU_TYPE=-1 means that floating point is always much slower than
+# fixed point.
+
+FPU_TYPE=1
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev pipe.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=x11.dev x11alpha.dev x11cmyk.dev x11mono.dev
+DEVICE_DEVS1=
+DEVICE_DEVS2=
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=faxg3.dev faxg32d.dev faxg4.dev
+DEVICE_DEVS8=jpeg.dev jpeggray.dev pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options --------------------------- #
+
+# Define the name of the partial makefile that specifies options --
+# used in dependencies.
+
+MAKEFILE=ansihead.mak
+
+# Define the ANSI-to-K&R dependency (none for ANSI compilers).
+
+AK=
+
+# Define the compilation rules and flags.
+
+CCC=$(CC) $(CCFLAGS) -c
+CCAUX=$(CC)
+CCLEAF=$(CCC)
+
+# --------------------------- Generic makefile ---------------------------- #
+
+# The remainder of the makefile is generic.
+# tar_cat concatenates this makefile with the generic makefiles.
+# Copyright (C) 1990, 1993, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name. For a "stock" System V platform,
+# use sysv_ instead of unix_.
+
+PLATFORM=unix_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=
+O=-o ./
+OBJ=o
+XE=
+XEAUX=
+
+# Define the current directory prefix and command invocations.
+
+CAT=cat
+D=/
+EXPP=
+EXP=./
+SHELL=/bin/sh
+SH=$(SHELL)
+SHP=$(SH) $(EXP)
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+RMN_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p "%s&s&&" -pl "&-l%s&s&&" -pL "&-L%s&s&&" -ol $(ld_tr)
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Patch a couple of PC-specific things that aren't relevant to Unix builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Generic makefile, common to all platforms.
+# The platform-specific makefiles `include' this file.
+# They define the following symbols:
+# GS - the name of the executable (without the extension, if any).
+# GS_LIB_DEFAULT - the default directory/ies for searching for the
+# initialization and font files at run time.
+# SEARCH_HERE_FIRST - the default setting of -P (whether or not to
+# look for files in the current directory first).
+# GS_DOCDIR - the directory where documentation will be available
+# at run time.
+# JSRCDIR - the directory where the IJG JPEG library source code
+# is stored (at compilation time).
+# JVERSION - the major version number of the IJG JPEG library.
+# PSRCDIR, PVERSION - the same for libpng.
+# ZSRCDIR - the same for zlib.
+# SHARE_LIBPNG - normally 0; if set to 1, asks the linker to use
+# an existing compiled libpng (-lpng) instead of compiling and
+# linking libpng explicitly.
+# LIBPNG_NAME, the name of the shared libpng, currently always
+# png (libpng, -lpng).
+# SHARE_ZLIB - normally 0; if set to 1, asks the linker to use
+# an existing compiled zlib (-lgz or -lz) instead of compiling
+# and linking libgz/libz explicitly.
+# ZLIB_NAME - the name of the shared zlib, either gz (for libgz, -lgz)
+# or z (for libz, -lz).
+# CONFIG - a configuration ID, added at the request of a customer,
+# that is supposed to help in maintaining multiple variants in
+# a single directory. Normally this is an empty string;
+# it may be any string that is legal as part of a file name.
+# DEVICE_DEVS - the devices to include in the executable.
+# See devs.mak for details.
+# DEVICE_DEVS1...DEVICE_DEVS15 - additional devices, if the definition
+# of DEVICE_DEVS doesn't fit on one line. See devs.mak for details.
+# FEATURE_DEVS - what features to include in the executable.
+# Normally this is one of:
+# level1 - a standard PostScript Level 1 language
+# interpreter.
+# level2 - a standard PostScript Level 2 language
+# interpreter.
+# pdf - a PDF-capable interpreter.
+# You may include both level1 and pdf, or both level2 and pdf.
+# The following feature may be added to either of the standard
+# configurations:
+# ccfonts - precompile fonts into C, and link them
+# with the executable. See fonts.txt for details.
+# The remaining features are of interest primarily to developers
+# who want to "mix and match" features to create custom
+# configurations:
+# dps - (partial) support for Display PostScript extensions:
+# see language.txt for details.
+# btoken - support for binary token encodings.
+# Included automatically in the dps and level2 features.
+# cidfont - (currently partial) support for CID-keyed fonts.
+# color - support for the Level 1 CMYK color extensions.
+# Included automatically in the dps and level2 features.
+# compfont - support for composite (type 0) fonts.
+# Included automatically in the level2 feature.
+# dct - support for DCTEncode/Decode filters.
+# Included automatically in the level2 feature.
+# epsf - support for recognizing and skipping the binary
+# header of MS-DOS EPSF files.
+# filter - support for Level 2 filters (other than eexec,
+# ASCIIHexEncode/Decode, NullEncode, PFBDecode,
+# RunLengthEncode/Decode, and SubFileDecode, which are
+# always included, and DCTEncode/Decode,
+# which are separate).
+# Included automatically in the level2 feature.
+# fzlib - support for zlibEncode/Decode filters.
+# ttfont - support for TrueType fonts.
+# type1 - support for Type 1 fonts and eexec;
+# normally included automatically in all configurations.
+# type42 - support for Type 42 (embedded TrueType) fonts.
+# Included automatically in the level2 feature.
+# There are quite a number of other sub-features that can be
+# selectively included in or excluded from a configuration,
+# but the above are the ones that are most likely to be of
+# interest.
+# COMPILE_INITS - normally 0; if set to 1, compiles the PostScript
+# language initialization files (gs_init.ps et al) into the
+# executable, eliminating the need for these files to be present
+# at run time.
+# BAND_LIST_STORAGE - normally file; if set to memory, stores band
+# lists in memory (with compression if needed).
+# BAND_LIST_COMPRESSOR - normally zlib: selects the compression method
+# to use for band lists in memory.
+# FILE_IMPLEMENTATION - normally stdio; if set to fd, uses file
+# descriptors instead of buffered stdio for file I/O; if set to
+# both, provides both implementations with different procedure
+# names for the fd-based implementation (see sfxfd.c for
+# more information).
+# EXTEND_NAMES - a value N between 0 and 6, indicating that the name
+# table should have a capacity of 2^(16+N) names. This normally
+# should be set to 0 (or left undefined), since non-zero values
+# result in a larger fixed space overhead and slightly slower code.
+# EXTEND_NAMES is ignored in 16-bit environments.
+#
+# It is very unlikely that anyone would want to edit the remaining
+# symbols, but we describe them here for completeness:
+# GS_INIT - the name of the initialization file for the interpreter,
+# normally gs_init.ps.
+# PLATFORM - a "device" name for the platform, so that platforms can
+# add various kinds of resources like devices and features.
+# CMD - the suffix for shell command files (e.g., null or .bat).
+# (This is only needed in a few places.)
+# D - the directory separator character (\ for MS-DOS, / for Unix).
+# O - the string for specifying the output file from the C compiler
+# (-o for MS-DOS, -o ./ for Unix).
+# OBJ - the extension for relocatable object files (e.g., o or obj).
+# XE - the extension for executable files (e.g., null or .exe).
+# XEAUX - the extension for the executable files (e.g., null or .exe)
+# for the utility programs (ansi2knr and those compiled with
+# CCAUX).
+# BEGINFILES - the list of files that `make begin' and `make clean'
+# should delete.
+# CCA2K - the C invocation for the ansi2knr program, which is the only
+# one that doesn't use ANSI C syntax. (It is only needed if
+# the main C compiler also isn't an ANSI compiler.)
+# CCAUX - the C invocation for auxiliary programs (echogs, genarch,
+# genconf, geninit).
+# CCBEGIN - the compilation command for `make begin', normally
+# $(CCC) *.c.
+# CCC - the C invocation for normal compilation.
+# CCD - the C invocation for files that store into frame buffers or
+# device registers. Needed because some optimizing compilers
+# will eliminate necessary stores.
+# CCCF - the C invocation for compiled fonts and other large,
+# self-contained data modules. Needed because MS-DOS
+# requires using the 'huge' memory model for these.
+# CCINT - the C invocation for compiling the main interpreter module,
+# normally the same as CCC: this is needed because the
+# Borland compiler generates *worse* code for this module
+# (but only this module) when optimization (-O) is turned on.
+# CCLEAF - the C invocation for compiling modules that contain only
+# leaf procedures, which don't need to build stack frames.
+# This is needed only because many compilers aren't able to
+# recognize leaf procedures on their own.
+# AK - if source files must be converted from ANSI to K&R syntax,
+# this is $(ANSI2KNR_XE); if not, it is null.
+# If a particular platform requires other utility programs
+# to be built, AK must include them too.
+# SHP - the prefix for invoking a shell script in the current directory
+# (null for MS-DOS, $(SH) ./ for Unix).
+# EXPP, EXP - the prefix for invoking an executable program in the
+# current directory (null for MS-DOS, ./ for Unix).
+# SH - the shell for scripts (null on MS-DOS, sh on Unix).
+# CONFILES - the arguments for genconf to generate the appropriate
+# linker control files (various).
+# CP_ - the command for copying one file to another. Because of
+# limitations in the MS-DOS/MS Windows environment, the
+# second argument must either be '.' (in which case the
+# write date may be either preserved or set to the current
+# date) or a file name (in which case the write date is
+# always updated).
+# RM_ - the command for deleting (a) file(s) (including wild cards,
+# but limited to a single file or pattern).
+# RMN_ = the command for deleting multiple files / patterns.
+#
+# The platform-specific makefiles must also include rules for creating
+# certain dynamically generated files:
+# gconfig_.h - this indicates the presence or absence of
+# certain system header files that are located in different
+# places on different systems. (It could be generated by
+# the GNU `configure' program.)
+# gconfigv.h - this indicates the status of certain machine-
+# and configuration-specific features derived from definitions
+# in the platform-specific makefile.
+
+# Define the name of this makefile.
+GS_MAK=gs.mak
+
+# Define the names of the executables.
+GS_XE=$(GS)$(XE)
+ANSI2KNR_XE=ansi2knr$(XEAUX)
+ECHOGS_XE=echogs$(XEAUX)
+GENARCH_XE=genarch$(XEAUX)
+GENCONF_XE=genconf$(XEAUX)
+GENINIT_XE=geninit$(XEAUX)
+
+# Define the names of the CONFIG-dependent header files.
+# gconfig*.h and gconfx*.h are generated dynamically.
+gconfig_h=gconfxx$(CONFIG).h
+gconfigf_h=gconfxc$(CONFIG).h
+
+# Watcom make insists that rules have a non-empty body!
+all default: $(GS_XE)
+ $(RM_) _temp_*
+
+distclean maintainer-clean realclean: clean
+ $(RM_) makefile
+
+clean: mostlyclean
+ $(RM_) arch.h
+ $(RM_) $(GS_XE)
+
+mostlyclean:
+ $(RMN_) *.$(OBJ) *.a core gmon.out
+ $(RMN_) *.dev *.d_* devs*.tr gconfig*.h gconfx*.h j*.h o*.tr l*.tr
+ $(RMN_) deflate.h zutil.h
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) _temp_* _temp_*.* *.map *.sym
+ $(RMN_) $(ANSI2KNR_XE) $(ECHOGS_XE) $(GENARCH_XE) $(GENCONF_XE) $(GENINIT_XE)
+ $(RMN_) gs_init.c $(BEGINFILES)
+
+# Remove only configuration-dependent information.
+config-clean:
+ $(RMN_) *.dev devs*.tr gconfig*.h gconfx*.h o*.tr l*.tr
+
+# A rule to do a quick and dirty compilation attempt when first installing
+# the interpreter. Many of the compilations will fail:
+# follow this with 'make'.
+
+begin:
+ $(RMN_) arch.h gconfig*.h gconfx*.h $(GENARCH_XE) $(GS_XE)
+ $(RMN_) gconfig*.c gscdefs*.c iconfig*.c
+ $(RMN_) gs_init.c $(BEGINFILES)
+ make arch.h gconfigv.h
+ - $(CCBEGIN)
+ $(RMN_) gconfig.$(OBJ) gdev*.$(OBJ) gp_*.$(OBJ) gscdefs.$(OBJ) gsmisc.$(OBJ)
+ $(RMN_) icfontab.$(OBJ) iconfig.$(OBJ) iinit.$(OBJ) interp.$(OBJ)
+
+# Auxiliary programs
+
+arch.h: $(GENARCH_XE)
+ $(EXPP) $(EXP)genarch arch.h
+
+# Macros for constructing the *.dev files that describe features and
+# devices.
+SETDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-obj
+SETPDEV=$(EXP)echogs -e .dev -w- -l-dev -F -s -l-include -lpage -l-obj
+SETMOD=$(EXP)echogs -e .dev -w- -l-obj
+ADDMOD=$(EXP)echogs -e .dev -a-
+
+# Define the compilation commands for the third-party libraries.
+CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR) -DPNG_USE_CONST
+CCCJ=$(CCC) -I. -I$(JSRCDIR)
+CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+
+######################## How to define new 'features' #######################
+#
+# One defines new 'features' exactly like devices (see devs.mak for details).
+# For example, one would define a feature abc by adding the following to
+# gs.mak:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_)
+# $(SETMOD) abc $(abc_)
+# $(ADDMOD) abc -obj ... [if needed]
+# $(ADDMOD) abc -oper ... [if appropriate]
+# $(ADDMOD) abc -ps ... [if appropriate]
+#
+# If the abc feature requires the presence of some other features jkl and
+# pqr, then the rules must look like this:
+#
+# abc_=abc1.$(OBJ) ...
+# abc.dev: $(GS_MAK) $(ECHOGS_XE) $(abc_) jkl.dev pqr.dev
+# $(SETMOD) abc $(abc_)
+# ...
+# $(ADDMOD) abc -include jkl pqr
+
+# --------------------- Configuration-dependent files --------------------- #
+
+# gconfig.h shouldn't have to depend on DEVS_ALL, but that would
+# involve rewriting gsconfig to only save the device name, not the
+# contents of the <device>.dev files.
+# FEATURE_DEVS must precede DEVICE_DEVS so that devices can override
+# features in obscure cases.
+
+DEVS_ALL=$(PLATFORM).dev $(FEATURE_DEVS) \
+ $(DEVICE_DEVS) $(DEVICE_DEVS1) \
+ $(DEVICE_DEVS2) $(DEVICE_DEVS3) $(DEVICE_DEVS4) $(DEVICE_DEVS5) \
+ $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
+ $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
+ $(DEVICE_DEVS14) $(DEVICE_DEVS15)
+
+devs_tr=devs.tr$(CONFIG)
+$(devs_tr): $(GS_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w $(devs_tr) - -include $(PLATFORM).dev
+ $(EXP)echogs -a $(devs_tr) - $(FEATURE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS1)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS2)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS3)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS4)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS5)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS6)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS7)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS8)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS9)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS10)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS11)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS12)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS13)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS14)
+ $(EXP)echogs -a $(devs_tr) - $(DEVICE_DEVS15)
+
+# GCONFIG_EXTRAS can be set on the command line.
+# Note that it consists of arguments for echogs, i.e.,
+# it isn't just literal text.
+GCONFIG_EXTRAS=
+
+ld_tr=ld$(CONFIG).tr
+$(gconfig_h) $(ld_tr) lib.tr: \
+ $(GS_MAK) $(MAKEFILE) version.mak $(GENCONF_XE) $(ECHOGS_XE) $(devs_tr) $(DEVS_ALL) libcore.dev
+ $(EXP)genconf $(devs_tr) libcore.dev -h $(gconfig_h) $(CONFILES)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_LIB_DEFAULT -x 2022 $(GS_LIB_DEFAULT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u SEARCH_HERE_FIRST -s $(SEARCH_HERE_FIRST)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_DOCDIR -x 2022 $(GS_DOCDIR) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_INIT -x 2022 $(GS_INIT) -x 22
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISION -s $(GS_REVISION)
+ $(EXP)echogs -a $(gconfig_h) -x 23 define -s -u GS_REVISIONDATE -s $(GS_REVISIONDATE)
+ $(EXP)echogs -a $(gconfig_h) $(GCONFIG_EXTRAS)
+
+################################################################
+# The other platform-independent makefiles are concatenated
+# (or included) after this one:
+# lib.mak
+# int.mak
+# jpeg.mak
+# libpng.mak
+# zlib.mak
+# devs.mak
+################################################################
+# Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for graphics library and other support code.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+LIB_MAK=lib.mak
+
+# Define the inter-dependencies of the .h files.
+# Since not all versions of `make' defer expansion of macros,
+# we must list these in bottom-to-top order.
+
+# Generic files
+
+arch_h=arch.h
+stdpre_h=stdpre.h
+std_h=std.h $(arch_h) $(stdpre_h)
+
+# Platform interfaces
+
+gp_h=gp.h
+gpcheck_h=gpcheck.h
+gpsync_h=gpsync.h
+
+# Configuration definitions
+
+# gconfig*.h are generated dynamically.
+gconfig__h=gconfig_.h
+gconfigv_h=gconfigv.h
+gscdefs_h=gscdefs.h
+
+# C library interfaces
+
+# Because of variations in the "standard" header files between systems, and
+# because we must include std.h before any file that includes sys/types.h,
+# we define local include files named *_.h to substitute for <*.h>.
+
+vmsmath_h=vmsmath.h
+
+dos__h=dos_.h
+ctype__h=ctype_.h $(std_h)
+dirent__h=dirent_.h $(std_h) $(gconfig__h)
+errno__h=errno_.h $(std_h)
+malloc__h=malloc_.h $(std_h)
+math__h=math_.h $(std_h) $(vmsmath_h)
+memory__h=memory_.h $(std_h)
+stat__h=stat_.h $(std_h)
+stdio__h=stdio_.h $(std_h)
+string__h=string_.h $(std_h)
+time__h=time_.h $(std_h) $(gconfig__h)
+windows__h=windows_.h
+
+# Miscellaneous
+
+gdebug_h=gdebug.h
+gsalloc_h=gsalloc.h
+gsargs_h=gsargs.h
+gserror_h=gserror.h
+gserrors_h=gserrors.h
+gsexit_h=gsexit.h
+gsgc_h=gsgc.h
+gsio_h=gsio.h
+gsmdebug_h=gsmdebug.h
+gsmemraw_h=gsmemraw.h
+gsmemory_h=gsmemory.h $(gsmemraw_h)
+gsrefct_h=gsrefct.h
+gsstruct_h=gsstruct.h
+gstypes_h=gstypes.h
+gx_h=gx.h $(stdio__h) $(gdebug_h) $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
+
+GX=$(AK) $(gx_h)
+GXERR=$(GX) $(gserrors_h)
+
+###### Support
+
+### Include files
+
+gsbitmap_h=gsbitmap.h $(gsstruct_h)
+gsbitops_h=gsbitops.h
+gsbittab_h=gsbittab.h
+gsflip_h=gsflip.h
+gsuid_h=gsuid.h
+gsutil_h=gsutil.h
+gxarith_h=gxarith.h
+gxbitmap_h=gxbitmap.h $(gsbitmap_h) $(gstypes_h)
+gxfarith_h=gxfarith.h $(gconfigv_h) $(gxarith_h)
+gxfixed_h=gxfixed.h
+gxobj_h=gxobj.h $(gxbitmap_h)
+# Out of order
+gxalloc_h=gxalloc.h $(gsalloc_h) $(gxobj_h)
+
+### Executable code
+
+gsalloc.$(OBJ): gsalloc.c $(GX) $(memory__h) $(string__h) \
+ $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsargs.$(OBJ): gsargs.c $(ctype__h) $(stdio__h) $(string__h)\
+ $(gsargs_h) $(gsexit_h) $(gsmemory_h)
+
+gsbitops.$(OBJ): gsbitops.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gsbitops_h) $(gstypes_h)
+
+gsbittab.$(OBJ): gsbittab.c $(AK) $(stdpre_h) $(gsbittab_h)
+
+# gsfemu is only used in FPU-less configurations, and currently only with gcc.
+# We thought using CCLEAF would produce smaller code, but it actually
+# produces larger code!
+gsfemu.$(OBJ): gsfemu.c $(AK) $(std_h)
+
+# gsflip is not part of the standard configuration: it's rather large,
+# and no standard facility requires it.
+gsflip.$(OBJ): gsflip.c $(GX) $(gsbittab_h) $(gsflip_h)
+ $(CCLEAF) gsflip.c
+
+gsmemory.$(OBJ): gsmemory.c $(GX) $(malloc__h) $(memory__h) \
+ $(gsmdebug_h) $(gsrefct_h) $(gsstruct_h) $(gsmemraw_h)
+
+gsmisc.$(OBJ): gsmisc.c $(GXERR) $(gconfigv_h) \
+ $(malloc__h) $(math__h) $(memory__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h)
+
+# gsnogc currently is only used in library-only configurations.
+gsnogc.$(OBJ): gsnogc.c $(GX)\
+ $(gsgc_h) $(gsmdebug_h) $(gsstruct_h) $(gxalloc_h)
+
+gsutil.$(OBJ): gsutil.c $(AK) $(memory__h) $(string__h) $(gconfigv_h)\
+ $(gstypes_h) $(gsuid_h) $(gsutil_h)
+
+###### Low-level facilities and utilities
+
+### Include files
+
+gdevbbox_h=gdevbbox.h
+gdevmem_h=gdevmem.h $(gsbitops_h)
+gdevmrop_h=gdevmrop.h
+
+gsccode_h=gsccode.h
+gsccolor_h=gsccolor.h $(gsstruct_h)
+gscsel_h=gscsel.h
+gscolor1_h=gscolor1.h
+gscoord_h=gscoord.h
+gscpm_h=gscpm.h
+gsdevice_h=gsdevice.h
+gsfcmap_h=gsfcmap.h $(gsccode_h)
+gsfont_h=gsfont.h
+gshsb_h=gshsb.h
+gsht_h=gsht.h
+gsht1_h=gsht1.h $(gsht_h)
+gsiparam_h=gsiparam.h
+gsjconf_h=gsjconf.h $(std_h)
+gslib_h=gslib.h
+gslparam_h=gslparam.h
+gsmatrix_h=gsmatrix.h
+gspaint_h=gspaint.h
+gsparam_h=gsparam.h
+gsparams_h=gsparams.h $(gsparam_h)
+gspath2_h=gspath2.h
+gspenum_h=gspenum.h
+gsropt_h=gsropt.h
+gsxfont_h=gsxfont.h
+# Out of order
+gschar_h=gschar.h $(gsccode_h) $(gscpm_h)
+gscolor2_h=gscolor2.h $(gsccolor_h) $(gsuid_h) $(gxbitmap_h)
+gsimage_h=gsimage.h $(gsiparam_h)
+gsline_h=gsline.h $(gslparam_h)
+gspath_h=gspath.h $(gspenum_h)
+gsrop_h=gsrop.h $(gsropt_h)
+
+gxbcache_h=gxbcache.h $(gxbitmap_h)
+gxchar_h=gxchar.h $(gschar_h)
+gxcindex_h=gxcindex.h
+gxcvalue_h=gxcvalue.h
+gxclio_h=gxclio.h
+gxclip2_h=gxclip2.h
+gxcolor2_h=gxcolor2.h $(gscolor2_h) $(gsrefct_h) $(gxbitmap_h)
+gxcoord_h=gxcoord.h $(gscoord_h)
+gxcpath_h=gxcpath.h
+gxdda_h=gxdda.h
+gxdevrop_h=gxdevrop.h
+gxdevmem_h=gxdevmem.h
+gxdither_h=gxdither.h
+gxfcmap_h=gxfcmap.h $(gsfcmap_h) $(gsuid_h)
+gxfont0_h=gxfont0.h
+gxfrac_h=gxfrac.h
+gxftype_h=gxftype.h
+gxhttile_h=gxhttile.h
+gxhttype_h=gxhttype.h
+gxiodev_h=gxiodev.h $(stat__h)
+gxline_h=gxline.h $(gslparam_h)
+gxlum_h=gxlum.h
+gxmatrix_h=gxmatrix.h $(gsmatrix_h)
+gxpaint_h=gxpaint.h
+gxpath_h=gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h)
+gxpcache_h=gxpcache.h
+gxpcolor_h=gxpcolor.h $(gxpcache_h)
+gxsample_h=gxsample.h
+gxstate_h=gxstate.h
+gxtmap_h=gxtmap.h
+gxxfont_h=gxxfont.h $(gsccode_h) $(gsmatrix_h) $(gsuid_h) $(gsxfont_h)
+# The following are out of order because they include other files.
+gsdcolor_h=gsdcolor.h $(gsccolor_h) $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+gxdcolor_h=gxdcolor.h $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gxdevice_h=gxdevice.h $(stdio__h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h) \
+ $(gsropt_h) $(gsstruct_h) $(gsxfont_h) \
+ $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)
+gxdht_h=gxdht.h $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+gxctable_h=gxctable.h $(gxfixed_h) $(gxfrac_h)
+gxfcache_h=gxfcache.h $(gsuid_h) $(gsxfont_h) $(gxbcache_h) $(gxftype_h)
+gxfont_h=gxfont.h $(gsfont_h) $(gsuid_h) $(gsstruct_h) $(gxftype_h)
+gscie_h=gscie.h $(gsrefct_h) $(gxctable_h)
+gscsepr_h=gscsepr.h
+gscspace_h=gscspace.h
+gxdcconv_h=gxdcconv.h $(gxfrac_h)
+gxfmap_h=gxfmap.h $(gsrefct_h) $(gxfrac_h) $(gxtmap_h)
+gxistate_h=gxistate.h $(gscsel_h) $(gsropt_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+gxband_h=gxband.h $(gxclio_h)
+gxclist_h=gxclist.h $(gscspace_h) $(gxbcache_h) $(gxclio_h) $(gxistate_h) $(gxband_h)
+gxcmap_h=gxcmap.h $(gscsel_h) $(gxcvalue_h) $(gxfmap_h)
+gxcspace_h=gxcspace.h $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gsstruct_h) $(gxfrac_h)
+gxht_h=gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gscolor_h=gscolor.h $(gxtmap_h)
+gsstate_h=gsstate.h $(gscolor_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
+
+gzacpath_h=gzacpath.h
+gzcpath_h=gzcpath.h $(gxcpath_h)
+gzht_h=gzht.h $(gscsel_h) $(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
+gzline_h=gzline.h $(gxline_h)
+gzpath_h=gzpath.h $(gsstruct_h) $(gxpath_h)
+gzstate_h=gzstate.h $(gscpm_h) $(gsrefct_h) $(gsstate_h)\
+ $(gxdcolor_h) $(gxistate_h) $(gxstate_h)
+
+gdevprn_h=gdevprn.h $(memory__h) $(string__h) $(gx_h) \
+ $(gserrors_h) $(gsmatrix_h) $(gsparam_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxdevmem_h) $(gxclist_h)
+
+sa85x_h=sa85x.h
+sbtx_h=sbtx.h
+scanchar_h=scanchar.h
+scommon_h=scommon.h $(gsmemory_h) $(gstypes_h) $(gsstruct_h)
+sdct_h=sdct.h
+shc_h=shc.h $(gsbittab_h)
+siscale_h=siscale.h $(gconfigv_h)
+sjpeg_h=sjpeg.h
+slzwx_h=slzwx.h
+spcxx_h=spcxx.h
+spdiffx_h=spdiffx.h
+spngpx_h=spngpx.h
+srlx_h=srlx.h
+sstring_h=sstring.h
+strimpl_h=strimpl.h $(scommon_h) $(gstypes_h) $(gsstruct_h)
+szlibx_h=szlibx.h
+# Out of order
+scf_h=scf.h $(shc_h)
+scfx_h=scfx.h $(shc_h)
+gximage_h=gximage.h $(gsiparam_h) $(gxcspace_h) $(gxdda_h) $(gxsample_h)\
+ $(siscale_h) $(strimpl_h)
+
+### Executable code
+
+# gconfig and gscdefs are handled specially. Currently they go in psbase
+# rather than in libcore, which is clearly wrong.
+gconfig=gconfig$(CONFIG)
+$(gconfig).$(OBJ): gconf.c $(GX) \
+ $(gscdefs_h) $(gconfig_h) $(gxdevice_h) $(gxiodev_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gconf.c $(gconfig).c
+ $(CCC) $(gconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(gconfig).c
+
+gscdefs=gscdefs$(CONFIG)
+$(gscdefs).$(OBJ): gscdef.c $(stdpre_h) $(gscdefs_h) $(gconfig_h) $(MAKEFILE)
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) gscdef.c $(gscdefs).c
+ $(CCC) $(gscdefs).c
+ $(RM_) gconfig.h
+ $(RM_) $(gscdefs).c
+
+gxacpath.$(OBJ): gxacpath.c $(GXERR) \
+ $(gsdcolor_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxpaint_h) \
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)
+
+gxbcache.$(OBJ): gxbcache.c $(GX) $(memory__h) \
+ $(gsmdebug_h) $(gxbcache_h)
+
+gxccache.$(OBJ): gxccache.c $(GXERR) $(gpcheck_h) \
+ $(gscspace_h) $(gsimage_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxdevmem_h) $(gxfcache_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxhttile_h) $(gxmatrix_h) $(gxxfont_h) \
+ $(gzstate_h) $(gzpath_h) $(gzcpath_h)
+
+gxccman.$(OBJ): gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfont_h) $(gxfcache_h) $(gxchar_h)\
+ $(gxxfont_h) $(gzstate_h) $(gzpath_h)
+
+gxcht.$(OBJ): gxcht.c $(GXERR) $(memory__h)\
+ $(gsutil_h)\
+ $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h)\
+ $(gxmatrix_h) $(gzht_h)
+
+gxcmap.$(OBJ): gxcmap.c $(GXERR) \
+ $(gsccolor_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gxdither_h) \
+ $(gxfarith_h) $(gxfrac_h) $(gxlum_h) $(gzstate_h)
+
+gxcpath.$(OBJ): gxcpath.c $(GXERR)\
+ $(gscoord_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gzpath_h) $(gzcpath_h)
+
+gxdcconv.$(OBJ): gxdcconv.c $(GX) \
+ $(gsdcolor_h) $(gxcmap_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gxfarith_h) $(gxistate_h) $(gxlum_h)
+
+gxdcolor.$(OBJ): gxdcolor.c $(GX) \
+ $(gsbittab_h) $(gxdcolor_h) $(gxdevice_h)
+
+gxdither.$(OBJ): gxdither.c $(GX) \
+ $(gsstruct_h) $(gsdcolor_h) \
+ $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
+
+gxfill.$(OBJ): gxfill.c $(GXERR) $(math__h) \
+ $(gsstruct_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h) \
+ $(gxistate_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+gxht.$(OBJ): gxht.c $(GXERR) $(memory__h)\
+ $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+
+gximage.$(OBJ): gximage.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h) $(gsstruct_h)\
+ $(gxfixed_h) $(gxfrac_h) $(gxarith_h) $(gxmatrix_h)\
+ $(gxdevice_h) $(gzpath_h) $(gzstate_h)\
+ $(gzcpath_h) $(gxdevmem_h) $(gximage_h) $(gdevmrop_h)
+
+gximage0.$(OBJ): gximage0.c $(GXERR) $(memory__h)\
+ $(gxcpath_h) $(gxdevice_h) $(gximage_h)
+
+gximage1.$(OBJ): gximage1.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsbittab_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gximage2.$(OBJ): gximage2.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gzpath_h)
+
+gxpaint.$(OBJ): gxpaint.c $(GX) \
+ $(gxdevice_h) $(gxhttile_h) $(gxpaint_h) $(gxpath_h) $(gzstate_h)
+
+gxpath.$(OBJ): gxpath.c $(GXERR) \
+ $(gsstruct_h) $(gxfixed_h) $(gzpath_h)
+
+gxpath2.$(OBJ): gxpath2.c $(GXERR) $(math__h) \
+ $(gxfixed_h) $(gxarith_h) $(gzpath_h)
+
+gxpcopy.$(OBJ): gxpcopy.c $(GXERR) $(math__h) $(gconfigv_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxpdash.$(OBJ): gxpdash.c $(GX) $(math__h) \
+ $(gscoord_h) $(gsline_h) $(gsmatrix_h) \
+ $(gxfixed_h) $(gzline_h) $(gzpath_h)
+
+gxpflat.$(OBJ): gxpflat.c $(GX)\
+ $(gxarith_h) $(gxfixed_h) $(gzpath_h)
+
+gxsample.$(OBJ): gxsample.c $(GX)\
+ $(gxsample_h)
+
+gxstroke.$(OBJ): gxstroke.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gscoord_h) $(gsdcolor_h) $(gsdevice_h) \
+ $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) \
+ $(gxhttile_h) $(gxistate_h) $(gxmatrix_h) $(gxpaint_h) \
+ $(gzcpath_h) $(gzline_h) $(gzpath_h)
+
+###### Higher-level facilities
+
+gschar.$(OBJ): gschar.c $(GXERR) $(memory__h) $(string__h)\
+ $(gspath_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxarith_h) $(gxmatrix_h) $(gxcoord_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxfcache_h) $(gzpath_h) $(gzstate_h)
+
+gscolor.$(OBJ): gscolor.c $(GXERR) \
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
+
+gscoord.$(OBJ): gscoord.c $(GXERR) $(math__h) \
+ $(gsccode_h) $(gxcoord_h) $(gxdevice_h) $(gxfarith_h) $(gxfixed_h) $(gxfont_h) \
+ $(gxmatrix_h) $(gxpath_h) $(gzstate_h)
+
+gsdevice.$(OBJ): gsdevice.c $(GXERR) $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
+ $(gscdefs_h) $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstruct_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gzstate_h)
+
+gsdevmem.$(OBJ): gsdevmem.c $(GXERR) $(math__h) $(memory__h) \
+ $(gxarith_h) $(gxdevice_h) $(gxdevmem_h)
+
+gsdparam.$(OBJ): gsdparam.c $(GXERR) $(memory__h) $(string__h) \
+ $(gsparam_h) $(gxdevice_h) $(gxfixed_h)
+
+gsfont.$(OBJ): gsfont.c $(GXERR) $(memory__h)\
+ $(gschar_h) $(gsstruct_h) \
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)
+
+gsht.$(OBJ): gsht.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gshtscr.$(OBJ): gshtscr.c $(GXERR) $(math__h) \
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+gsimage.$(OBJ): gsimage.c $(GXERR) $(memory__h)\
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxdevice_h) $(gzstate_h)
+
+gsimpath.$(OBJ): gsimpath.c $(GXERR) \
+ $(gsmatrix_h) $(gsstate_h) $(gspath_h)
+
+gsinit.$(OBJ): gsinit.c $(memory__h) $(stdio__h) \
+ $(gdebug_h) $(gp_h) $(gscdefs_h) $(gslib_h) $(gsmemory_h)
+
+gsiodev.$(OBJ): gsiodev.c $(GXERR) $(errno__h) $(string__h) \
+ $(gp_h) $(gsparam_h) $(gxiodev_h)
+
+gsline.$(OBJ): gsline.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsline_h) $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gzline_h)
+
+gsmatrix.$(OBJ): gsmatrix.c $(GXERR) $(math__h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h)
+
+gspaint.$(OBJ): gspaint.c $(GXERR) $(math__h) $(gpcheck_h)\
+ $(gspaint_h) $(gspath_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdevmem_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gxpaint_h)\
+ $(gzpath_h) $(gzstate_h)
+
+gsparam.$(OBJ): gsparam.c $(GXERR) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsstruct_h)
+
+gsparams.$(OBJ): gsparams.c $(gx_h) $(memory__h) $(gserrors_h) $(gsparam_h)
+
+gspath.$(OBJ): gspath.c $(GXERR) \
+ $(gscoord_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+gsstate.$(OBJ): gsstate.c $(GXERR) $(memory__h)\
+ $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h) \
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+
+###### The internal devices
+
+### The built-in device implementations:
+
+# The bounding box device is not normally a free-standing device.
+# To configure it as one for testing, change SETMOD to SETDEV, and also
+# define TEST in gdevbbox.c.
+bbox.dev: $(LIB_MAK) $(ECHOGS_XE) gdevbbox.$(OBJ)
+ $(SETMOD) bbox gdevbbox.$(OBJ)
+
+gdevbbox.$(OBJ): gdevbbox.c $(GXERR) $(math__h) $(memory__h) \
+ $(gdevbbox_h) $(gsdevice_h) $(gsparam_h) \
+ $(gxcpath_h) $(gxdevice_h) $(gxistate_h) $(gxpaint_h) $(gxpath_h)
+
+gdevddrw.$(OBJ): gdevddrw.c $(GXERR) $(math__h) $(gpcheck_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h)
+
+gdevdflt.$(OBJ): gdevdflt.c $(GXERR) $(gpcheck_h)\
+ $(gsbittab_h) $(gsropt_h)\
+ $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)
+
+gdevnfwd.$(OBJ): gdevnfwd.c $(GX) \
+ $(gxdevice_h)
+
+# The render/RGB device is only here as an example, but we can configure
+# it as a real device for testing.
+rrgb.dev: $(LIB_MAK) $(ECHOGS_XE) gdevrrgb.$(OBJ) page.dev
+ $(SETPDEV) rrgb gdevrrgb.$(OBJ)
+
+gdevrrgb.$(OBJ): gdevrrgb.c $(AK)\
+ $(gdevprn_h)
+
+### The memory devices:
+
+gdevabuf.$(OBJ): gdevabuf.c $(GXERR) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmem.$(OBJ): gdevmem.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm1.$(OBJ): gdevm1.c $(GX) $(memory__h) $(gsrop_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm2.$(OBJ): gdevm2.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm4.$(OBJ): gdevm4.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm8.$(OBJ): gdevm8.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm16.$(OBJ): gdevm16.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm24.$(OBJ): gdevm24.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevm32.$(OBJ): gdevm32.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+gdevmpla.$(OBJ): gdevmpla.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+
+# Create a pseudo-"feature" for the entire graphics library.
+
+LIB1s=gsalloc.$(OBJ) gsbitops.$(OBJ) gsbittab.$(OBJ)
+LIB2s=gschar.$(OBJ) gscolor.$(OBJ) gscoord.$(OBJ) gsdevice.$(OBJ) gsdevmem.$(OBJ)
+LIB3s=gsdparam.$(OBJ) gsfont.$(OBJ) gsht.$(OBJ) gshtscr.$(OBJ)
+LIB4s=gsimage.$(OBJ) gsimpath.$(OBJ) gsinit.$(OBJ) gsiodev.$(OBJ)
+LIB5s=gsline.$(OBJ) gsmatrix.$(OBJ) gsmemory.$(OBJ) gsmisc.$(OBJ)
+LIB6s=gspaint.$(OBJ) gsparam.$(OBJ) gsparams.$(OBJ) gspath.$(OBJ) gsstate.$(OBJ) gsutil.$(OBJ)
+LIB1x=gxacpath.$(OBJ) gxbcache.$(OBJ)
+LIB2x=gxccache.$(OBJ) gxccman.$(OBJ) gxcht.$(OBJ) gxcmap.$(OBJ) gxcpath.$(OBJ)
+LIB3x=gxdcconv.$(OBJ) gxdcolor.$(OBJ) gxdither.$(OBJ) gxfill.$(OBJ) gxht.$(OBJ)
+LIB4x=gximage.$(OBJ) gximage0.$(OBJ) gximage1.$(OBJ) gximage2.$(OBJ)
+LIB5x=gxpaint.$(OBJ) gxpath.$(OBJ) gxpath2.$(OBJ) gxpcopy.$(OBJ)
+LIB6x=gxpdash.$(OBJ) gxpflat.$(OBJ) gxsample.$(OBJ) gxstroke.$(OBJ)
+LIB1d=gdevabuf.$(OBJ) gdevddrw.$(OBJ) gdevdflt.$(OBJ) gdevnfwd.$(OBJ)
+LIB2d=gdevmem.$(OBJ) gdevm1.$(OBJ) gdevm2.$(OBJ) gdevm4.$(OBJ) gdevm8.$(OBJ)
+LIB3d=gdevm16.$(OBJ) gdevm24.$(OBJ) gdevm32.$(OBJ) gdevmpla.$(OBJ)
+LIBs=$(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s)
+LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d)
+LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
+libs.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBs)
+ $(EXP)echogs -w libs.dev $(LIB1s)
+ $(EXP)echogs -a libs.dev $(LIB2s)
+ $(EXP)echogs -a libs.dev $(LIB3s)
+ $(EXP)echogs -a libs.dev $(LIB4s)
+ $(EXP)echogs -a libs.dev $(LIB5s)
+ $(EXP)echogs -a libs.dev $(LIB6s)
+ $(ADDMOD) libs -init gscolor
+
+libx.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBx)
+ $(EXP)echogs -w libx.dev $(LIB1x)
+ $(EXP)echogs -a libx.dev $(LIB2x)
+ $(EXP)echogs -a libx.dev $(LIB3x)
+ $(EXP)echogs -a libx.dev $(LIB4x)
+ $(EXP)echogs -a libx.dev $(LIB5x)
+ $(EXP)echogs -a libx.dev $(LIB6x)
+ $(ADDMOD) libx -init gximage1 gximage2
+
+libd.dev: $(LIB_MAK) $(ECHOGS_XE) $(LIBd)
+ $(EXP)echogs -w libd.dev $(LIB1d)
+ $(EXP)echogs -a libd.dev $(LIB2d)
+ $(EXP)echogs -a libd.dev $(LIB3d)
+
+# roplib shouldn't be required....
+libcore.dev: $(LIB_MAK) $(ECHOGS_XE)\
+ libs.dev libx.dev libd.dev iscale.dev roplib.dev
+ $(SETMOD) libcore
+ $(ADDMOD) libcore -dev nullpage
+ $(ADDMOD) libcore -include libs libx libd iscale roplib
+
+# ---------------- Stream support ---------------- #
+# Currently the only things in the library that use this are clists
+# and file streams.
+
+stream_h=stream.h $(scommon_h)
+
+stream.$(OBJ): stream.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+# ---------------- File streams ---------------- #
+# Currently only the high-level drivers use these, but more drivers will
+# probably use them eventually.
+
+sfile_=sfx$(FILE_IMPLEMENTATION).$(OBJ) stream.$(OBJ)
+sfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(sfile_)
+ $(SETMOD) sfile $(sfile_)
+
+sfxstdio.$(OBJ): sfxstdio.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxfd.$(OBJ): sfxfd.c $(AK) $(stdio__h) $(errno__h) $(memory__h) \
+ $(gdebug_h) $(gpcheck_h) $(stream_h) $(strimpl_h)
+
+sfxboth.$(OBJ): sfxboth.c sfxstdio.c sfxfd.c
+
+# ---------------- CCITTFax filters ---------------- #
+# These are used by clists, some drivers, and Level 2 in general.
+
+cfe_=scfe.$(OBJ) scfetab.$(OBJ) shc.$(OBJ)
+cfe.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfe_)
+ $(SETMOD) cfe $(cfe_)
+
+scfe.$(OBJ): scfe.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfetab.$(OBJ): scfetab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+shc.$(OBJ): shc.c $(AK) $(std_h) $(scommon_h) $(shc_h)
+
+cfd_=scfd.$(OBJ) scfdtab.$(OBJ)
+cfd.dev: $(LIB_MAK) $(ECHOGS_XE) $(cfd_)
+ $(SETMOD) cfd $(cfd_)
+
+scfd.$(OBJ): scfd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(scf_h) $(strimpl_h) $(scfx_h)
+
+scfdtab.$(OBJ): scfdtab.c $(AK) $(std_h) $(scommon_h) $(scf_h)
+
+# ---------------- DCT (JPEG) filters ---------------- #
+# These are used by Level 2, and by the JPEG-writing driver.
+
+# Common code
+
+sdctc_=sdctc.$(OBJ) sjpegc.$(OBJ)
+
+sdctc.$(OBJ): sdctc.c $(AK) $(stdio__h)\
+ $(sdct_h) $(strimpl_h)\
+ jpeglib.h
+
+sjpegc.$(OBJ): sjpegc.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Encoding (compression)
+
+sdcte_=$(sdctc_) sdcte.$(OBJ) sjpege.$(OBJ)
+sdcte.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdcte_) jpege.dev
+ $(SETMOD) sdcte $(sdcte_)
+ $(ADDMOD) sdcte -include jpege
+
+sdcte.$(OBJ): sdcte.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpege.$(OBJ): sjpege.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+# Decoding (decompression)
+
+sdctd_=$(sdctc_) sdctd.$(OBJ) sjpegd.$(OBJ)
+sdctd.dev: $(LIB_MAK) $(ECHOGS_XE) $(sdctd_) jpegd.dev
+ $(SETMOD) sdctd $(sdctd_)
+ $(ADDMOD) sdctd -include jpegd
+
+sdctd.$(OBJ): sdctd.c $(AK) $(memory__h) $(stdio__h) $(gdebug_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jerror.h jpeglib.h
+
+sjpegd.$(OBJ): sjpegd.c $(AK) $(stdio__h) $(string__h) $(gx_h)\
+ $(gserrors_h) $(sjpeg_h) $(sdct_h) $(strimpl_h)\
+ jerror.h jpeglib.h
+
+# ---------------- LZW filters ---------------- #
+# These are used by Level 2 in general.
+
+slzwe_=slzwce
+#slzwe_=slzwe
+lzwe_=$(slzwe_).$(OBJ) slzwc.$(OBJ)
+lzwe.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwe_)
+ $(SETMOD) lzwe $(lzwe_)
+
+# We need slzwe.dev as a synonym for lzwe.dev for BAND_LIST_STORAGE = memory.
+slzwe.dev: lzwe.dev
+ $(CP_) lzwe.dev slzwe.dev
+
+slzwce.$(OBJ): slzwce.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwe.$(OBJ): slzwe.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+slzwc.$(OBJ): slzwc.c $(AK) $(std_h)\
+ $(slzwx_h) $(strimpl_h)
+
+lzwd_=slzwd.$(OBJ) slzwc.$(OBJ)
+lzwd.dev: $(LIB_MAK) $(ECHOGS_XE) $(lzwd_)
+ $(SETMOD) lzwd $(lzwd_)
+
+# We need slzwd.dev as a synonym for lzwd.dev for BAND_LIST_STORAGE = memory.
+slzwd.dev: lzwd.dev
+ $(CP_) lzwd.dev slzwd.dev
+
+slzwd.$(OBJ): slzwd.c $(AK) $(stdio__h) $(gdebug_h)\
+ $(slzwx_h) $(strimpl_h)
+
+# ---------------- PCX decoding filter ---------------- #
+# This is an adhoc filter not used by anything in the standard configuration.
+
+pcxd_=spcxd.$(OBJ)
+pcxd.dev: $(LIB_MAK) $(ECHOGS_XE) $(pcxd_)
+ $(SETMOD) pcxd $(pcxd_)
+
+spcxd.$(OBJ): spcxd.c $(AK) $(stdio__h) $(memory__h) \
+ $(spcxx_h) $(strimpl_h)
+
+# ---------------- Pixel-difference filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pdiff_=spdiff.$(OBJ)
+pdiff.dev: $(LIB_MAK) $(ECHOGS_XE) $(pdiff_)
+ $(SETMOD) pdiff $(pdiff_)
+
+spdiff.$(OBJ): spdiff.c $(AK) $(stdio__h)\
+ $(spdiffx_h) $(strimpl_h)
+
+# ---------------- PNG pixel prediction filters ---------------- #
+# The Predictor facility of the LZW and Flate filters uses these.
+
+pngp_=spngp.$(OBJ)
+pngp.dev: $(LIB_MAK) $(ECHOGS_XE) $(pngp_)
+ $(SETMOD) pngp $(pngp_)
+
+spngp.$(OBJ): spngp.c $(AK) $(memory__h)\
+ $(spngpx_h) $(strimpl_h)
+
+# ---------------- RunLength filters ---------------- #
+# These are used by clists and also by Level 2 in general.
+
+rle_=srle.$(OBJ)
+rle.dev: $(LIB_MAK) $(ECHOGS_XE) $(rle_)
+ $(SETMOD) rle $(rle_)
+
+srle.$(OBJ): srle.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+rld_=srld.$(OBJ)
+rld.dev: $(LIB_MAK) $(ECHOGS_XE) $(rld_)
+ $(SETMOD) rld $(rld_)
+
+srld.$(OBJ): srld.c $(AK) $(stdio__h) $(memory__h) \
+ $(srlx_h) $(strimpl_h)
+
+# ---------------- String encoding/decoding filters ---------------- #
+# These are used by the PostScript and PDF writers, and also by the
+# PostScript interpreter.
+
+scantab.$(OBJ): scantab.c $(AK) $(stdpre_h)\
+ $(scanchar_h) $(scommon_h)
+
+sfilter2.$(OBJ): sfilter2.c $(AK) $(memory__h) $(stdio__h)\
+ $(sa85x_h) $(scanchar_h) $(sbtx_h) $(strimpl_h)
+
+sstring.$(OBJ): sstring.c $(AK) $(stdio__h) $(memory__h) $(string__h)\
+ $(scanchar_h) $(sstring_h) $(strimpl_h)
+
+# ---------------- zlib filters ---------------- #
+# These are used by clists and are also available as filters.
+
+szlibc_=szlibc.$(OBJ)
+
+szlibc.$(OBJ): szlibc.c $(AK) $(std_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibc.c
+
+szlibe_=$(szlibc_) szlibe.$(OBJ)
+szlibe.dev: $(LIB_MAK) $(ECHOGS_XE) zlibe.dev $(szlibe_)
+ $(SETMOD) szlibe $(szlibe_)
+ $(ADDMOD) szlibe -include zlibe
+
+szlibe.$(OBJ): szlibe.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibe.c
+
+szlibd_=$(szlibc_) szlibd.$(OBJ)
+szlibd.dev: $(LIB_MAK) $(ECHOGS_XE) zlibd.dev $(szlibd_)
+ $(SETMOD) szlibd $(szlibd_)
+ $(ADDMOD) szlibd -include zlibd
+
+szlibd.$(OBJ): szlibd.c $(AK) $(std_h) \
+ $(gsmemory_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) szlibd.c
+
+# ---------------- Command lists ---------------- #
+
+gxcldev_h=gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
+ $(strimpl_h) $(scfx_h) $(srlx_h)
+gxclpage_h=gxclpage.h $(gxclio_h)
+gxclpath_h=gxclpath.h $(gxfixed_h)
+
+# Command list package. Currently the higher-level facilities are required,
+# but eventually they will be optional.
+clist.dev: $(LIB_MAK) $(ECHOGS_XE) clbase.dev clpath.dev
+ $(SETMOD) clist -include clbase clpath
+
+# Base command list facility.
+clbase1_=gxclist.$(OBJ) gxclbits.$(OBJ) gxclpage.$(OBJ)
+clbase2_=gxclread.$(OBJ) gxclrect.$(OBJ) stream.$(OBJ)
+clbase_=$(clbase1_) $(clbase2_)
+clbase.dev: $(LIB_MAK) $(ECHOGS_XE) $(clbase_) cl$(BAND_LIST_STORAGE).dev \
+ cfe.dev cfd.dev rle.dev rld.dev
+ $(SETMOD) clbase $(clbase1_)
+ $(ADDMOD) clbase -obj $(clbase2_)
+ $(ADDMOD) clbase -include cl$(BAND_LIST_STORAGE) cfe cfd rle rld
+
+gdevht_h=gdevht.h $(gzht_h)
+
+gdevht.$(OBJ): gdevht.c $(GXERR) \
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+
+gxclist.$(OBJ): gxclist.c $(GXERR) $(memory__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)
+
+gxclbits.$(OBJ): gxclbits.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsbitops_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h)
+
+gxclpage.$(OBJ): gxclpage.c $(AK)\
+ $(gdevprn_h) $(gxcldev_h) $(gxclpage_h)
+
+# (gxclread shouldn't need gxclpath.h)
+gxclread.$(OBJ): gxclread.c $(GXERR) $(memory__h) $(gp_h) $(gpcheck_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscoord_h) $(gsdevice_h) $(gsstate_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcspace_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gsparams_h)\
+ $(gxhttile_h) $(gxpaint_h) $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h)
+
+gxclrect.$(OBJ): gxclrect.c $(GXERR)\
+ $(gsutil_h) $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h)
+
+# Higher-level command list facilities.
+clpath_=gxclimag.$(OBJ) gxclpath.$(OBJ)
+clpath.dev: $(LIB_MAK) $(ECHOGS_XE) $(clpath_) psl2cs.dev
+ $(SETMOD) clpath $(clpath_)
+ $(ADDMOD) clpath -include psl2cs
+ $(ADDMOD) clpath -init climag clpath
+
+gxclimag.$(OBJ): gxclimag.c $(GXERR) $(math__h) $(memory__h)\
+ $(gscspace_h)\
+ $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpath_h) $(gxfmap_h)\
+ $(siscale_h) $(strimpl_h)
+
+gxclpath.$(OBJ): gxclpath.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gxcldev_h) $(gxclpath_h) $(gxcolor2_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxpaint_h) \
+ $(gzcpath_h) $(gzpath_h)
+
+# Implement band lists on files.
+
+clfile_=gxclfile.$(OBJ)
+clfile.dev: $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
+ $(SETMOD) clfile $(clfile_)
+
+gxclfile.$(OBJ): gxclfile.c $(stdio__h) $(string__h) \
+ $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
+
+# Implement band lists in memory (RAM).
+
+clmemory_=gxclmem.$(OBJ) gxcl$(BAND_LIST_COMPRESSOR).$(OBJ)
+clmemory.dev: $(LIB_MAK) $(ECHOGS_XE) $(clmemory_) s$(BAND_LIST_COMPRESSOR)e.dev s$(BAND_LIST_COMPRESSOR)d.dev
+ $(SETMOD) clmemory $(clmemory_)
+ $(ADDMOD) clmemory -include s$(BAND_LIST_COMPRESSOR)e s$(BAND_LIST_COMPRESSOR)d
+ $(ADDMOD) clmemory -init cl_$(BAND_LIST_COMPRESSOR)
+
+gxclmem_h=gxclmem.h $(gxclio_h) $(strimpl_h)
+
+gxclmem.$(OBJ): gxclmem.c $(GXERR) $(LIB_MAK) $(memory__h) \
+ $(gxclmem_h)
+
+# Implement the compression method for RAM-based band lists.
+
+gxcllzw.$(OBJ): gxcllzw.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(slzwx_h)
+
+gxclzlib.$(OBJ): gxclzlib.c $(std_h)\
+ $(gsmemory_h) $(gstypes_h) $(gxclmem_h) $(szlibx_h)
+ $(CCCZ) gxclzlib.c
+
+# ---------------- Page devices ---------------- #
+# We include this here, rather than in devs.mak, because it is more like
+# a feature than a simple device.
+
+page_=gdevprn.$(OBJ)
+page.dev: $(LIB_MAK) $(ECHOGS_XE) $(page_) clist.dev
+ $(SETMOD) page $(page_)
+ $(ADDMOD) page -include clist
+
+gdevprn.$(OBJ): gdevprn.c $(ctype__h) \
+ $(gdevprn_h) $(gp_h) $(gsparam_h) $(gxclio_h)
+
+# ---------------- Vector devices ---------------- #
+# We include this here for the same reasons as page.dev.
+
+gdevvec_h=gdevvec.h $(gdevbbox_h) $(gsropt_h) $(gxdevice_h) $(gxistate_h) $(stream_h)
+
+vector_=gdevvec.$(OBJ)
+vector.dev: $(LIB_MAK) $(ECHOGS_XE) $(vector_) bbox.dev sfile.dev
+ $(SETMOD) vector $(vector_)
+ $(ADDMOD) vector -include bbox sfile
+
+gdevvec.$(OBJ): gdevvec.c $(GXERR) $(math__h) $(memory__h) $(string__h)\
+ $(gdevvec_h) $(gp_h) $(gscspace_h) $(gsparam_h) $(gsutil_h)\
+ $(gxdcolor_h) $(gxfixed_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+# ---------------- Image scaling filter ---------------- #
+
+iscale_=siscale.$(OBJ)
+iscale.dev: $(LIB_MAK) $(ECHOGS_XE) $(iscale_)
+ $(SETMOD) iscale $(iscale_)
+
+siscale.$(OBJ): siscale.c $(AK) $(math__h) $(memory__h) $(stdio__h) \
+ $(siscale_h) $(strimpl_h)
+
+# ---------------- RasterOp et al ---------------- #
+# Currently this module is required, but it should be optional.
+
+roplib_=gdevmrop.$(OBJ) gsrop.$(OBJ) gsroptab.$(OBJ)
+roplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(roplib_)
+ $(SETMOD) roplib $(roplib_)
+ $(ADDMOD) roplib -init roplib
+
+gdevrun.$(OBJ): gdevrun.c $(GXERR) $(memory__h) \
+ $(gxdevice_h) $(gxdevmem_h)
+
+gdevmrop.$(OBJ): gdevmrop.c $(GXERR) $(memory__h) \
+ $(gsbittab_h) $(gsropt_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) \
+ $(gdevmrop_h)
+
+gsrop.$(OBJ): gsrop.c $(GXERR) \
+ $(gsrop_h) $(gzstate_h)
+
+gsroptab.$(OBJ): gsroptab.c $(stdpre_h) $(gsropt_h)
+ $(CCLEAF) gsroptab.c
+
+# ---------------- Async rendering ---------------- #
+
+gsmemfix_h=gsmemfix.h $(gsmemraw_h)
+gxsync_h=gxsync.h $(gpsync_h) $(gsmemory_h)
+gxpageq_h=gxpageq.h $(gsmemory_h) $(gxband_h) $(gxsync_h)
+gsmemlok_h=gsmemlok.h $(gsmemory_h) $(gxsync_h)
+gdevprna_h=gdevprna.h $(gdevprn_h) $(gxsync_h)
+
+async_=gdevprna.$(OBJ) gxsync.$(OBJ) gxpageq.$(OBJ) gsmemlok.$(OBJ)\
+ gsmemfix.$(OBJ)
+async.dev: $(INT_MAK) $(ECHOGS_XE) $(async_) clist.dev
+ $(SETMOD) async $(async_)
+
+gdevprna.$(OBJ): gdevprna.c $(AK) $(ctype__h) $(gdevprna_h) $(gsparam_h)\
+ $(gsdevice_h) $(gxcldev_h) $(gxclpath_h) $(gxpageq_h) $(gsmemory_h)\
+ $(gsmemlok_h) $(gsmemfix_h)
+
+gsmemfix.$(OBJ): gsmemfix.c $(AK) $(memory__h) $(gsmemraw_h) $(gsmemfix_h)
+
+gxsync.$(OBJ): gxsync.c $(AK) $(gxsync_h) $(memory__h) $(gx_h) $(gserrors_h)\
+ $(gsmemory_h)
+
+gxpageq.$(OBJ): gxpageq.c $(GXERR) $(gxdevice_h) $(gxclist_h)\
+ $(gxpageq_h) $(gserrors_h)
+
+gsmemlok.$(OBJ): gsmemlok.c $(GXERR) $(gsmemlok_h) $(gserrors_h)
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+cmaplib_=gsfcmap.$(OBJ)
+cmaplib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmaplib_)
+ $(SETMOD) cmaplib $(cmaplib_)
+
+gsfcmap.$(OBJ): gsfcmap.c $(GXERR)\
+ $(gsstruct_h) $(gxfcmap_h)
+
+psf0lib_=gschar0.$(OBJ) gsfont0.$(OBJ)
+psf0lib.dev: $(LIB_MAK) $(ECHOGS_XE) cmaplib.dev $(psf0lib_)
+ $(SETMOD) psf0lib $(psf0lib_)
+ $(ADDMOD) psf0lib -include cmaplib
+
+gschar0.$(OBJ): gschar0.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gxfixed_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gsfcmap_h) $(gxfont_h) $(gxfont0_h) $(gxchar_h)
+
+gsfont0.$(OBJ): gsfont0.c $(GXERR) $(memory__h)\
+ $(gsmatrix_h) $(gsstruct_h) $(gxfixed_h) $(gxdevmem_h) $(gxfcache_h)\
+ $(gxfont_h) $(gxfont0_h) $(gxchar_h) $(gxdevice_h)
+
+# ---------------- Pattern color ---------------- #
+
+patlib_=gspcolor.$(OBJ) gxclip2.$(OBJ) gxpcmap.$(OBJ)
+patlib.dev: $(LIB_MAK) $(ECHOGS_XE) cmyklib.dev psl2cs.dev $(patlib_)
+ $(SETMOD) patlib -include cmyklib psl2cs
+ $(ADDMOD) patlib -obj $(patlib_)
+
+gspcolor.$(OBJ): gspcolor.c $(GXERR) $(math__h) \
+ $(gsimage_h) $(gspath_h) $(gsrop_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcoord_h) $(gxclip2_h) $(gxcspace_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(gxfixed_h) $(gxmatrix_h) $(gxpath_h) $(gxpcolor_h) $(gzstate_h)
+
+gxclip2.$(OBJ): gxclip2.c $(GXERR) $(memory__h) \
+ $(gsstruct_h) $(gxclip2_h) $(gxdevice_h) $(gxdevmem_h)
+
+gxpcmap.$(OBJ): gxpcmap.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h)\
+ $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1lib_=gxtype1.$(OBJ) gxhint1.$(OBJ) gxhint2.$(OBJ) gxhint3.$(OBJ)
+
+gscrypt1_h=gscrypt1.h
+gstype1_h=gstype1.h
+gxfont1_h=gxfont1.h
+gxop1_h=gxop1.h
+gxtype1_h=gxtype1.h $(gscrypt1_h) $(gstype1_h) $(gxop1_h)
+
+gxtype1.$(OBJ): gxtype1.c $(GXERR) $(math__h)\
+ $(gsccode_h) $(gsline_h) $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+gxhint1.$(OBJ): gxhint1.c $(GXERR)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint2.$(OBJ): gxhint2.c $(GXERR) $(memory__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)
+
+gxhint3.$(OBJ): gxhint3.c $(GXERR) $(math__h)\
+ $(gxarith_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 1 charstrings
+
+psf1lib_=gstype1.$(OBJ)
+psf1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf1lib_) $(type1lib_)
+ $(SETMOD) psf1lib $(psf1lib_)
+ $(ADDMOD) psf1lib $(type1lib_)
+ $(ADDMOD) psf1lib -init gstype1
+
+gstype1.$(OBJ): gstype1.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# Type 2 charstrings
+
+psf2lib_=gstype2.$(OBJ)
+psf2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psf2lib_) $(type1lib_)
+ $(SETMOD) psf2lib $(psf2lib_)
+ $(ADDMOD) psf2lib $(type1lib_)
+ $(ADDMOD) psf2lib -init gstype2
+
+gstype2.$(OBJ): gstype2.c $(GXERR) $(math__h) $(memory__h)\
+ $(gsstruct_h)\
+ $(gxarith_h) $(gxcoord_h) $(gxfixed_h) $(gxmatrix_h) $(gxchar_h)\
+ $(gxfont_h) $(gxfont1_h) $(gxistate_h) $(gxtype1_h)\
+ $(gzpath_h)
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+ttflib_=gstype42.$(OBJ)
+ttflib.dev: $(LIB_MAK) $(ECHOGS_XE) $(ttflib_)
+ $(SETMOD) ttflib $(ttflib_)
+
+gxfont42_h=gxfont42.h
+
+gstype42.$(OBJ): gstype42.c $(GXERR) $(memory__h) \
+ $(gsccode_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont42_h) $(gxistate_h) $(gxpath_h)
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+cmyklib_=gscolor1.$(OBJ) gsht1.$(OBJ)
+cmyklib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cmyklib_)
+ $(SETMOD) cmyklib $(cmyklib_)
+ $(ADDMOD) cmyklib -init gscolor1
+
+gscolor1.$(OBJ): gscolor1.c $(GXERR) \
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) \
+ $(gzstate_h)
+
+gsht1.$(OBJ): gsht1.c $(GXERR) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+
+colimlib_=gximage3.$(OBJ)
+colimlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(colimlib_)
+ $(SETMOD) colimlib $(colimlib_)
+ $(ADDMOD) colimlib -init gximage3
+
+gximage3.$(OBJ): gximage3.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcconv_h) $(gxdcolor_h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h)\
+ $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
+ $(gzpath_h) $(gzstate_h)
+
+# ---------------- HSB color ---------------- #
+
+hsblib_=gshsb.$(OBJ)
+hsblib.dev: $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
+ $(SETMOD) hsblib $(hsblib_)
+
+gshsb.$(OBJ): gshsb.c $(GX) \
+ $(gscolor_h) $(gshsb_h) $(gxfrac_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1lib_=gspath1.$(OBJ)
+path1lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(path1lib_)
+ $(SETMOD) path1lib $(path1lib_)
+
+gspath1.$(OBJ): gspath1.c $(GXERR) $(math__h) \
+ $(gscoord_h) $(gspath_h) $(gsstruct_h) \
+ $(gxfarith_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) $(gzpath_h)
+
+# --------------- Level 2 color space and color image support --------------- #
+
+psl2cs_=gscolor2.$(OBJ)
+psl2cs.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2cs_)
+ $(SETMOD) psl2cs $(psl2cs_)
+
+gscolor2.$(OBJ): gscolor2.c $(GXERR) \
+ $(gxarith_h) $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h)
+
+psl2lib_=gximage4.$(OBJ) gximage5.$(OBJ)
+psl2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(psl2lib_) colimlib.dev psl2cs.dev
+ $(SETMOD) psl2lib $(psl2lib_)
+ $(ADDMOD) psl2lib -init gximage4 gximage5
+ $(ADDMOD) psl2lib -include colimlib psl2cs
+
+gximage4.$(OBJ): gximage4.c $(GXERR) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+gximage5.$(OBJ): gximage5.c $(GXERR) $(math__h) $(memory__h) $(gpcheck_h)\
+ $(gsccolor_h) $(gspaint_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
+ $(gxmatrix_h)\
+ $(gzpath_h)
+
+# ---------------- Display Postscript / Level 2 support ---------------- #
+
+dps2lib_=gsdps1.$(OBJ)
+dps2lib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dps2lib_)
+ $(SETMOD) dps2lib $(dps2lib_)
+
+gsdps1.$(OBJ): gsdps1.c $(GXERR) $(math__h)\
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gspath2_h)\
+ $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- Display Postscript extensions ---------------- #
+
+gsdps_h=gsdps.h
+
+dpslib_=gsdps.$(OBJ)
+dpslib.dev: $(LIB_MAK) $(ECHOGS_XE) $(dpslib_)
+ $(SETMOD) dpslib $(dpslib_)
+
+gsdps.$(OBJ): gsdps.c $(GX) $(gsdps_h)\
+ $(gsdps_h) $(gspath_h) $(gxdevice_h) $(gzcpath_h) $(gzpath_h) $(gzstate_h)
+
+# ---------------- CIE color ---------------- #
+
+cielib_=gscie.$(OBJ) gxctable.$(OBJ)
+cielib.dev: $(LIB_MAK) $(ECHOGS_XE) $(cielib_)
+ $(SETMOD) cielib $(cielib_)
+
+gscie.$(OBJ): gscie.c $(GXERR) $(math__h) \
+ $(gscie_h) $(gscolor2_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxarith_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gzstate_h)
+
+gxctable.$(OBJ): gxctable.c $(GX) \
+ $(gxfixed_h) $(gxfrac_h) $(gxctable_h)
+
+# ---------------- Separation colors ---------------- #
+
+seprlib_=gscsepr.$(OBJ)
+seprlib.dev: $(LIB_MAK) $(ECHOGS_XE) $(seprlib_)
+ $(SETMOD) seprlib $(seprlib_)
+
+gscsepr.$(OBJ): gscsepr.c $(GXERR)\
+ $(gscsepr_h) $(gsmatrix_h) $(gsrefct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+
+# ---------------- Functions ---------------- #
+
+gsdsrc_h=gsdsrc.h $(gsstruct_h)
+gsfunc_h=gsfunc.h
+gsfunc0_h=gsfunc0.h $(gsdsrc_h) $(gsfunc_h)
+gxfunc_h=gxfunc.h $(gsfunc_h) $(gsstruct_h)
+
+# Generic support, and FunctionType 0.
+funclib_=gsdsrc.$(OBJ) gsfunc.$(OBJ) gsfunc0.$(OBJ)
+funclib.dev: $(LIB_MAK) $(ECHOGS_XE) $(funclib_)
+ $(SETMOD) funclib $(funclib_)
+
+gsdsrc.$(OBJ): gsdsrc.c $(GX) $(memory__h)\
+ $(gsdsrc_h) $(gserrors_h) $(stream_h)
+
+gsfunc.$(OBJ): gsfunc.c $(GX)\
+ $(gserrors_h) $(gxfunc_h)
+
+gsfunc0.$(OBJ): gsfunc0.c $(GX) $(math__h)\
+ $(gserrors_h) $(gsfunc0_h) $(gxfunc_h)
+
+# ----------------------- Platform-specific modules ----------------------- #
+# Platform-specific code doesn't really belong here: this is code that is
+# shared among multiple platforms.
+
+# Frame buffer implementations.
+
+gp_nofb.$(OBJ): gp_nofb.c $(GX) \
+ $(gp_h) $(gxdevice_h)
+
+gp_dosfb.$(OBJ): gp_dosfb.c $(AK) $(malloc__h) $(memory__h)\
+ $(gx_h) $(gp_h) $(gserrors_h) $(gxdevice_h)
+
+# MS-DOS file system, also used by Desqview/X.
+gp_dosfs.$(OBJ): gp_dosfs.c $(AK) $(dos__h) $(gp_h) $(gx_h)
+
+# MS-DOS file enumeration, *not* used by Desqview/X.
+gp_dosfe.$(OBJ): gp_dosfe.c $(AK) $(stdio__h) $(memory__h) $(string__h) \
+ $(dos__h) $(gstypes_h) $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h)
+
+# Other MS-DOS facilities.
+gp_msdos.$(OBJ): gp_msdos.c $(AK) $(dos__h) $(stdio__h) $(string__h)\
+ $(gsmemory_h) $(gstypes_h) $(gp_h)
+
+# Unix(-like) file system, also used by Desqview/X.
+gp_unifs.$(OBJ): gp_unifs.c $(AK) $(memory__h) $(string__h) $(gx_h) $(gp_h) \
+ $(gsstruct_h) $(gsutil_h) $(stat__h) $(dirent__h)
+
+# Unix(-like) file name syntax, *not* used by Desqview/X.
+gp_unifn.$(OBJ): gp_unifn.c $(AK) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+# Main program for library testing
+
+gslib.$(OBJ): gslib.c $(AK) $(math__h) \
+ $(gx_h) $(gp_h) $(gserrors_h) $(gsmatrix_h) $(gsstate_h) $(gscspace_h) \
+ $(gscdefs_h) $(gscolor2_h) $(gscoord_h) $(gslib_h) $(gsparam_h) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) $(gsutil_h) \
+ $(gxalloc_h) $(gxdevice_h)
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# (Platform-independent) makefile for language interpreters.
+# See the end of gs.mak for where this fits into the build process.
+
+# Define the name of this makefile.
+INT_MAK=int.mak
+
+# ======================== Interpreter support ======================== #
+
+# This is support code for all interpreters, not just PostScript and PDF.
+# It knows about the PostScript data types, but isn't supposed to
+# depend on anything outside itself.
+
+errors_h=errors.h
+idebug_h=idebug.h
+idict_h=idict.h
+igc_h=igc.h
+igcstr_h=igcstr.h
+iname_h=iname.h
+inamedef_h=inamedef.h $(gconfigv_h) $(iname_h)
+ipacked_h=ipacked.h
+iref_h=iref.h
+isave_h=isave.h
+isstate_h=isstate.h
+istruct_h=istruct.h $(gsstruct_h)
+iutil_h=iutil.h
+ivmspace_h=ivmspace.h $(gsgc_h)
+opdef_h=opdef.h
+# Nested include files
+ghost_h=ghost.h $(gx_h) $(iref_h)
+imemory_h=imemory.h $(gsalloc_h) $(ivmspace_h)
+ialloc_h=ialloc.h $(imemory_h)
+iastruct_h=iastruct.h $(gxobj_h) $(ialloc_h)
+iastate_h=iastate.h $(gxalloc_h) $(ialloc_h) $(istruct_h)
+store_h=store.h $(ialloc_h)
+
+GH=$(AK) $(ghost_h)
+
+isupport1_=ialloc.$(OBJ) igc.$(OBJ) igcref.$(OBJ) igcstr.$(OBJ)
+isupport2_=ilocate.$(OBJ) iname.$(OBJ) isave.$(OBJ)
+isupport_=$(isupport1_) $(isupport2_)
+isupport.dev: $(INT_MAK) $(ECHOGS_XE) $(isupport_)
+ $(SETMOD) isupport $(isupport1_)
+ $(ADDMOD) isupport -obj $(isupport2_)
+ $(ADDMOD) isupport -init igcref
+
+ialloc.$(OBJ): ialloc.c $(AK) $(memory__h) $(gx_h)\
+ $(errors_h) $(gsstruct_h) $(gxarith_h)\
+ $(iastate_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+# igc.c, igcref.c, and igcstr.c should really be in the dpsand2 list,
+# but since all the GC enumeration and relocation routines refer to them,
+# it's too hard to separate them out from the Level 1 base.
+igc.$(OBJ): igc.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsmdebug_h) $(gsstruct_h) $(gsutil_h) \
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(inamedef_h) \
+ $(ipacked_h) $(isave_h) $(isstate_h) $(istruct_h) $(opdef_h)
+
+igcref.$(OBJ): igcref.c $(GH) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idebug_h) $(igc_h) $(iname_h) $(ipacked_h) $(store_h)
+
+igcstr.$(OBJ): igcstr.c $(GH) $(memory__h)\
+ $(gsmdebug_h) $(gsstruct_h) $(iastate_h) $(igcstr_h)
+
+ilocate.$(OBJ): ilocate.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h)\
+ $(iastate_h) $(idict_h) $(igc_h) $(igcstr_h) $(iname_h)\
+ $(ipacked_h) $(isstate_h) $(iutil_h) $(ivmspace_h)\
+ $(store_h)
+
+iname.$(OBJ): iname.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h) $(gxobj_h)\
+ $(errors_h) $(imemory_h) $(inamedef_h) $(isave_h) $(store_h)
+
+isave.$(OBJ): isave.c $(GH) $(memory__h)\
+ $(errors_h) $(gsexit_h) $(gsstruct_h) $(gsutil_h)\
+ $(iastate_h) $(inamedef_h) $(isave_h) $(isstate_h) $(ivmspace_h)\
+ $(ipacked_h) $(store_h)
+
+### Include files
+
+idparam_h=idparam.h
+ilevel_h=ilevel.h
+iparam_h=iparam.h $(gsparam_h)
+istack_h=istack.h
+iutil2_h=iutil2.h
+opcheck_h=opcheck.h
+opextern_h=opextern.h
+# Nested include files
+dstack_h=dstack.h $(istack_h)
+estack_h=estack.h $(istack_h)
+ostack_h=ostack.h $(istack_h)
+oper_h=oper.h $(iutil_h) $(opcheck_h) $(opdef_h) $(opextern_h) $(ostack_h)
+
+idebug.$(OBJ): idebug.c $(GH) $(string__h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(ostack_h) $(opdef_h) $(ipacked_h) $(store_h)
+
+idict.$(OBJ): idict.c $(GH) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idebug_h) $(ivmspace_h) $(inamedef_h) $(ipacked_h)\
+ $(isave_h) $(store_h) $(iutil_h) $(idict_h) $(dstack_h)
+
+idparam.$(OBJ): idparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(gsmatrix_h) $(gsuid_h)\
+ $(idict_h) $(idparam_h) $(ilevel_h) $(imemory_h) $(iname_h) $(iutil_h)\
+ $(oper_h) $(store_h)
+
+iparam.$(OBJ): iparam.c $(GH) $(memory__h) $(string__h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(iname_h) $(imemory_h) $(iparam_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(opcheck_h) $(store_h)
+
+istack.$(OBJ): istack.c $(GH) $(memory__h) \
+ $(errors_h) $(gsstruct_h) $(gsutil_h) \
+ $(ialloc_h) $(istack_h) $(istruct_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iutil.$(OBJ): iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\
+ $(gsccode_h) $(gsmatrix_h) $(gsutil_h) $(gxfont_h)\
+ $(errors_h) $(idict_h) $(imemory_h) $(iutil_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(oper_h) $(store_h)
+
+# ======================== PostScript Level 1 ======================== #
+
+###### Include files
+
+files_h=files.h
+fname_h=fname.h
+ichar_h=ichar.h
+icharout_h=icharout.h
+icolor_h=icolor.h
+icontext_h=icontext.h $(imemory_h) $(istack_h)
+icsmap_h=icsmap.h
+ifont_h=ifont.h $(gsccode_h) $(gsstruct_h)
+iht_h=iht.h
+iimage_h=iimage.h
+imain_h=imain.h $(gsexit_h)
+imainarg_h=imainarg.h
+iminst_h=iminst.h $(imain_h)
+interp_h=interp.h
+iparray_h=iparray.h
+iscannum_h=iscannum.h
+istream_h=istream.h
+main_h=main.h $(iminst_h)
+overlay_h=overlay.h
+sbwbs_h=sbwbs.h
+sfilter_h=sfilter.h $(gstypes_h)
+shcgen_h=shcgen.h
+smtf_h=smtf.h
+# Nested include files
+bfont_h=bfont.h $(ifont_h)
+ifilter_h=ifilter.h $(istream_h) $(ivmspace_h)
+igstate_h=igstate.h $(gsstate_h) $(gxstate_h) $(istruct_h)
+iscan_h=iscan.h $(sa85x_h) $(sstring_h)
+sbhc_h=sbhc.h $(shc_h)
+# Include files for optional features
+ibnum_h=ibnum.h
+
+### Initialization and scanning
+
+iconfig=iconfig$(CONFIG)
+$(iconfig).$(OBJ): iconf.c $(stdio__h) \
+ $(gconfig_h) $(gscdefs_h) $(gsmemory_h) \
+ $(files_h) $(iminst_h) $(iref_h) $(ivmspace_h) $(opdef_h) $(stream_h)
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+ $(CP_) $(gconfig_h) gconfig.h
+ $(CP_) iconf.c $(iconfig).c
+ $(CCC) $(iconfig).c
+ $(RM_) gconfig.h
+ $(RM_) $(iconfig).c
+
+iinit.$(OBJ): iinit.c $(GH) $(string__h)\
+ $(gscdefs_h) $(gsexit_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h)\
+ $(ilevel_h) $(iname_h) $(interp_h) $(opdef_h)\
+ $(ipacked_h) $(iparray_h) $(iutil_h) $(ivmspace_h) $(store_h)
+
+iscan.$(OBJ): iscan.c $(GH) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(dstack_h) $(errors_h) $(files_h)\
+ $(ilevel_h) $(iutil_h) $(iscan_h) $(iscannum_h) $(istruct_h) $(ivmspace_h)\
+ $(iname_h) $(ipacked_h) $(iparray_h) $(istream_h) $(ostack_h) $(store_h)\
+ $(stream_h) $(strimpl_h) $(sfilter_h) $(scanchar_h)
+
+iscannum.$(OBJ): iscannum.c $(GH) $(math__h)\
+ $(errors_h) $(iscannum_h) $(scanchar_h) $(scommon_h) $(store_h)
+
+### Streams
+
+sfilter1.$(OBJ): sfilter1.c $(AK) $(stdio__h) $(memory__h) \
+ $(sfilter_h) $(strimpl_h)
+
+###### Operators
+
+OP=$(GH) $(errors_h) $(oper_h)
+
+### Non-graphics operators
+
+zarith.$(OBJ): zarith.c $(OP) $(math__h) $(store_h)
+
+zarray.$(OBJ): zarray.c $(OP) $(memory__h) $(ialloc_h) $(ipacked_h) $(store_h)
+
+zcontrol.$(OBJ): zcontrol.c $(OP) $(string__h)\
+ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)
+
+zdict.$(OBJ): zdict.c $(OP) \
+ $(dstack_h) $(idict_h) $(ilevel_h) $(iname_h) $(ipacked_h) $(ivmspace_h) \
+ $(store_h)
+
+zfile.$(OBJ): zfile.c $(OP) $(memory__h) $(string__h) $(gp_h)\
+ $(gsstruct_h) $(gxiodev_h) \
+ $(ialloc_h) $(estack_h) $(files_h) $(fname_h) $(ilevel_h) $(interp_h) $(iutil_h)\
+ $(isave_h) $(main_h) $(sfilter_h) $(stream_h) $(strimpl_h) $(store_h)
+
+zfileio.$(OBJ): zfileio.c $(OP) $(gp_h) \
+ $(files_h) $(ifilter_h) $(store_h) $(stream_h) $(strimpl_h) \
+ $(gsmatrix_h) $(gxdevice_h) $(gxdevmem_h)
+
+zfilter.$(OBJ): zfilter.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sfilter_h) $(srlx_h) $(sstring_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zfname.$(OBJ): zfname.c $(OP) $(memory__h)\
+ $(fname_h) $(gxiodev_h) $(ialloc_h) $(stream_h)
+
+zfproc.$(OBJ): zfproc.c $(GH) $(memory__h)\
+ $(errors_h) $(oper_h)\
+ $(estack_h) $(files_h) $(gsstruct_h) $(ialloc_h) $(ifilter_h) $(istruct_h)\
+ $(store_h) $(stream_h) $(strimpl_h)
+
+zgeneric.$(OBJ): zgeneric.c $(OP) $(memory__h)\
+ $(idict_h) $(estack_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(store_h)
+
+ziodev.$(OBJ): ziodev.c $(OP) $(memory__h) $(stdio__h) $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsstruct_h) $(gxiodev_h)\
+ $(files_h) $(ialloc_h) $(ivmspace_h) $(store_h) $(stream_h)
+
+zmath.$(OBJ): zmath.c $(OP) $(math__h) $(gxfarith_h) $(store_h)
+
+zmisc.$(OBJ): zmisc.c $(OP) $(gscdefs_h) $(gp_h) \
+ $(errno__h) $(memory__h) $(string__h) \
+ $(ialloc_h) $(idict_h) $(dstack_h) $(iname_h) $(ivmspace_h) $(ipacked_h) $(store_h)
+
+zpacked.$(OBJ): zpacked.c $(OP) \
+ $(ialloc_h) $(idict_h) $(ivmspace_h) $(iname_h) $(ipacked_h) $(iparray_h) \
+ $(istack_h) $(store_h)
+
+zrelbit.$(OBJ): zrelbit.c $(OP) $(gsutil_h) $(store_h) $(idict_h)
+
+zstack.$(OBJ): zstack.c $(OP) $(memory__h)\
+ $(ialloc_h) $(istack_h) $(store_h)
+
+zstring.$(OBJ): zstring.c $(OP) $(memory__h)\
+ $(gsutil_h)\
+ $(ialloc_h) $(iname_h) $(ivmspace_h) $(store_h)
+
+zsysvm.$(OBJ): zsysvm.c $(GH)\
+ $(ialloc_h) $(ivmspace_h) $(oper_h) $(store_h)
+
+ztoken.$(OBJ): ztoken.c $(OP) \
+ $(estack_h) $(files_h) $(gsstruct_h) $(iscan_h) \
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+ztype.$(OBJ): ztype.c $(OP) $(math__h) $(memory__h) $(string__h)\
+ $(dstack_h) $(idict_h) $(imemory_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zvmem.$(OBJ): zvmem.c $(OP)\
+ $(dstack_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(isave_h) $(store_h) $(stream_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h)
+
+### Graphics operators
+
+zchar.$(OBJ): zchar.c $(OP)\
+ $(gsstruct_h) $(gxarith_h) $(gxfixed_h) $(gxmatrix_h)\
+ $(gxchar_h) $(gxdevice_h) $(gxfont_h) $(gzpath_h) $(gzstate_h)\
+ $(dstack_h) $(estack_h) $(ialloc_h) $(ichar_h) $(idict_h) $(ifont_h)\
+ $(ilevel_h) $(iname_h) $(igstate_h) $(ipacked_h) $(store_h)
+
+# zcharout is used for Type 1 and Type 42 fonts only.
+zcharout.$(OBJ): zcharout.c $(OP)\
+ $(gschar_h) $(gxdevice_h) $(gxfont_h)\
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h)\
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zcolor.$(OBJ): zcolor.c $(OP) \
+ $(gxfixed_h) $(gxmatrix_h) $(gzstate_h) $(gxdevice_h) $(gxcmap_h) \
+ $(ialloc_h) $(icolor_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zdevice.$(OBJ): zdevice.c $(OP) $(string__h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
+ $(gsmatrix_h) $(gsstate_h) $(gxdevice_h) $(store_h)
+
+zfont.$(OBJ): zfont.c $(OP)\
+ $(gschar_h) $(gsstruct_h) $(gxdevice_h) $(gxfont_h) $(gxfcache_h)\
+ $(gzstate_h)\
+ $(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(isave_h) $(ivmspace_h)\
+ $(bfont_h) $(store_h)
+
+zfont2.$(OBJ): zfont2.c $(OP) $(memory__h) $(string__h)\
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(bfont_h) $(idict_h) $(idparam_h) $(ilevel_h) $(iname_h) $(istruct_h)\
+ $(ipacked_h) $(store_h)
+
+zgstate.$(OBJ): zgstate.c $(OP) $(math__h)\
+ $(gsmatrix_h) $(ialloc_h) $(idict_h) $(igstate_h) $(istruct_h) $(store_h)
+
+zht.$(OBJ): zht.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+zimage.$(OBJ): zimage.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ifilter_h) $(igstate_h) $(iimage_h) $(ilevel_h) \
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(store_h) $(stream_h)
+
+zmatrix.$(OBJ): zmatrix.c $(OP)\
+ $(gsmatrix_h) $(igstate_h) $(gscoord_h) $(store_h)
+
+zpaint.$(OBJ): zpaint.c $(OP)\
+ $(gspaint_h) $(igstate_h)
+
+zpath.$(OBJ): zpath.c $(OP) $(math__h) \
+ $(gsmatrix_h) $(gspath_h) $(igstate_h) $(store_h)
+
+# Define the base PostScript language interpreter.
+# This is the subset of PostScript Level 1 required by our PDF reader.
+
+INT1=idebug.$(OBJ) idict.$(OBJ) idparam.$(OBJ)
+INT2=iinit.$(OBJ) interp.$(OBJ) iparam.$(OBJ) ireclaim.$(OBJ)
+INT3=iscan.$(OBJ) iscannum.$(OBJ) istack.$(OBJ) iutil.$(OBJ)
+INT4=scantab.$(OBJ) sfilter1.$(OBJ) sstring.$(OBJ) stream.$(OBJ)
+Z1=zarith.$(OBJ) zarray.$(OBJ) zcontrol.$(OBJ) zdict.$(OBJ)
+Z1OPS=zarith zarray zcontrol zdict
+Z2=zfile.$(OBJ) zfileio.$(OBJ) zfilter.$(OBJ) zfname.$(OBJ) zfproc.$(OBJ)
+Z2OPS=zfile zfileio zfilter zfproc
+Z3=zgeneric.$(OBJ) ziodev.$(OBJ) zmath.$(OBJ) zmisc.$(OBJ) zpacked.$(OBJ)
+Z3OPS=zgeneric ziodev zmath zmisc zpacked
+Z4=zrelbit.$(OBJ) zstack.$(OBJ) zstring.$(OBJ) zsysvm.$(OBJ)
+Z4OPS=zrelbit zstack zstring zsysvm
+Z5=ztoken.$(OBJ) ztype.$(OBJ) zvmem.$(OBJ)
+Z5OPS=ztoken ztype zvmem
+Z6=zchar.$(OBJ) zcolor.$(OBJ) zdevice.$(OBJ) zfont.$(OBJ) zfont2.$(OBJ)
+Z6OPS=zchar zcolor zdevice zfont zfont2
+Z7=zgstate.$(OBJ) zht.$(OBJ) zimage.$(OBJ) zmatrix.$(OBJ) zpaint.$(OBJ) zpath.$(OBJ)
+Z7OPS=zgstate zht zimage zmatrix zpaint zpath
+# We have to be a little underhanded with *config.$(OBJ) so as to avoid
+# circular definitions.
+INT_OBJS=imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ) \
+ $(INT1) $(INT2) $(INT3) $(INT4) \
+ $(Z1) $(Z2) $(Z3) $(Z4) $(Z5) $(Z6) $(Z7)
+INT_CONFIG=$(gconfig).$(OBJ) $(gscdefs).$(OBJ) $(iconfig).$(OBJ) \
+ iccinit$(COMPILE_INITS).$(OBJ)
+INT_ALL=$(INT_OBJS) $(INT_CONFIG)
+# We omit libcore.dev, which should be included here, because problems
+# with the Unix linker require libcore to appear last in the link list
+# when libcore is really a library.
+# We omit $(INT_CONFIG) from the dependency list because they have special
+# dependency requirements and are added to the link list at the very end.
+# zfilter.c shouldn't include the RLE and RLD filters, but we don't want to
+# change this now.
+psbase.dev: $(INT_MAK) $(ECHOGS_XE) $(INT_OBJS)\
+ isupport.dev rld.dev rle.dev sfile.dev
+ $(SETMOD) psbase imainarg.$(OBJ) gsargs.$(OBJ) imain.$(OBJ)
+ $(ADDMOD) psbase -obj $(INT_CONFIG)
+ $(ADDMOD) psbase -obj $(INT1)
+ $(ADDMOD) psbase -obj $(INT2)
+ $(ADDMOD) psbase -obj $(INT3)
+ $(ADDMOD) psbase -obj $(INT4)
+ $(ADDMOD) psbase -obj $(Z1)
+ $(ADDMOD) psbase -oper $(Z1OPS)
+ $(ADDMOD) psbase -obj $(Z2)
+ $(ADDMOD) psbase -oper $(Z2OPS)
+ $(ADDMOD) psbase -obj $(Z3)
+ $(ADDMOD) psbase -oper $(Z3OPS)
+ $(ADDMOD) psbase -obj $(Z4)
+ $(ADDMOD) psbase -oper $(Z4OPS)
+ $(ADDMOD) psbase -obj $(Z5)
+ $(ADDMOD) psbase -oper $(Z5OPS)
+ $(ADDMOD) psbase -obj $(Z6)
+ $(ADDMOD) psbase -oper $(Z6OPS)
+ $(ADDMOD) psbase -obj $(Z7)
+ $(ADDMOD) psbase -oper $(Z7OPS)
+ $(ADDMOD) psbase -iodev stdin stdout stderr lineedit statementedit
+ $(ADDMOD) psbase -include isupport rld rle sfile
+
+# -------------------------- Feature definitions -------------------------- #
+
+# ---------------- Full Level 1 interpreter ---------------- #
+
+level1.dev: $(INT_MAK) $(ECHOGS_XE) psbase.dev bcp.dev hsb.dev path1.dev type1.dev
+ $(SETMOD) level1 -include psbase bcp hsb path1 type1
+ $(ADDMOD) level1 -emulator PostScript PostScriptLevel1
+
+# -------- Level 1 color extensions (CMYK color and colorimage) -------- #
+
+color.dev: $(INT_MAK) $(ECHOGS_XE) cmyklib.dev colimlib.dev cmykread.dev
+ $(SETMOD) color -include cmyklib colimlib cmykread
+
+cmykread_=zcolor1.$(OBJ) zht1.$(OBJ)
+cmykread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmykread_)
+ $(SETMOD) cmykread $(cmykread_)
+ $(ADDMOD) cmykread -oper zcolor1 zht1
+
+zcolor1.$(OBJ): zcolor1.c $(OP) \
+ $(gscolor1_h) \
+ $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gzstate_h) \
+ $(ialloc_h) $(icolor_h) $(iimage_h) $(estack_h) $(iutil_h) $(igstate_h) $(store_h)
+
+zht1.$(OBJ): zht1.c $(OP) $(memory__h)\
+ $(gsmatrix_h) $(gsstate_h) $(gsstruct_h) $(gxdevice_h) $(gzht_h)\
+ $(ialloc_h) $(estack_h) $(igstate_h) $(iht_h) $(store_h)
+
+# ---------------- HSB color ---------------- #
+
+hsb_=zhsb.$(OBJ)
+hsb.dev: $(INT_MAK) $(ECHOGS_XE) $(hsb_) hsblib.dev
+ $(SETMOD) hsb $(hsb_)
+ $(ADDMOD) hsb -include hsblib
+ $(ADDMOD) hsb -oper zhsb
+
+zhsb.$(OBJ): zhsb.c $(OP) \
+ $(gshsb_h) $(igstate_h) $(store_h)
+
+# ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
+
+path1_=zpath1.$(OBJ)
+path1.dev: $(INT_MAK) $(ECHOGS_XE) $(path1_) path1lib.dev
+ $(SETMOD) path1 $(path1_)
+ $(ADDMOD) path1 -include path1lib
+ $(ADDMOD) path1 -oper zpath1
+
+zpath1.$(OBJ): zpath1.c $(OP) $(memory__h)\
+ $(ialloc_h) $(estack_h) $(gspath_h) $(gsstruct_h) $(igstate_h) $(store_h)
+
+# ================ Level-independent PostScript options ================ #
+
+# ---------------- BCP filters ---------------- #
+
+bcp_=sbcp.$(OBJ) zfbcp.$(OBJ)
+bcp.dev: $(INT_MAK) $(ECHOGS_XE) $(bcp_)
+ $(SETMOD) bcp $(bcp_)
+ $(ADDMOD) bcp -oper zfbcp
+
+sbcp.$(OBJ): sbcp.c $(AK) $(stdio__h) \
+ $(sfilter_h) $(strimpl_h)
+
+zfbcp.$(OBJ): zfbcp.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# ---------------- Incremental font loading ---------------- #
+# (This only works for Type 1 fonts without eexec encryption.)
+
+diskfont.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) diskfont -ps gs_diskf
+
+# ---------------- Double-precision floats ---------------- #
+
+double_=zdouble.$(OBJ)
+double.dev: $(INT_MAK) $(ECHOGS_XE) $(double_)
+ $(SETMOD) double $(double_)
+ $(ADDMOD) double -oper zdouble
+
+zdouble.$(OBJ): zdouble.c $(OP) $(ctype__h) $(math__h) $(memory__h) $(string__h) \
+ $(gxfarith_h) $(store_h)
+
+# ---------------- EPSF files with binary headers ---------------- #
+
+epsf.dev: $(INT_MAK) $(ECHOGS_XE)
+ $(SETMOD) epsf -ps gs_epsf
+
+# ---------------- RasterOp ---------------- #
+# This should be a separable feature in the core also....
+
+rasterop.dev: $(INT_MAK) $(ECHOGS_XE) roplib.dev ropread.dev
+ $(SETMOD) rasterop -include roplib ropread
+
+ropread_=zrop.$(OBJ)
+ropread.dev: $(INT_MAK) $(ECHOGS_XE) $(ropread_)
+ $(SETMOD) ropread $(ropread_)
+ $(ADDMOD) ropread -oper zrop
+
+zrop.$(OBJ): zrop.c $(OP) $(memory__h)\
+ $(gsrop_h) $(gsutil_h) $(gxdevice_h)\
+ $(idict_h) $(idparam_h) $(igstate_h) $(store_h)
+
+# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+
+type1.dev: $(INT_MAK) $(ECHOGS_XE) psf1lib.dev psf1read.dev
+ $(SETMOD) type1 -include psf1lib psf1read
+
+psf1read_=seexec.$(OBJ) zchar1.$(OBJ) zcharout.$(OBJ) zfont1.$(OBJ) zmisc1.$(OBJ)
+psf1read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf1read_)
+ $(SETMOD) psf1read $(psf1read_)
+ $(ADDMOD) psf1read -oper zchar1 zfont1 zmisc1
+ $(ADDMOD) psf1read -ps gs_type1
+
+seexec.$(OBJ): seexec.c $(AK) $(stdio__h) \
+ $(gscrypt1_h) $(scanchar_h) $(sfilter_h) $(strimpl_h)
+
+zchar1.$(OBJ): zchar1.c $(OP) \
+ $(gspaint_h) $(gspath_h) $(gsstruct_h) \
+ $(gxchar_h) $(gxdevice_h) $(gxfixed_h) $(gxmatrix_h) \
+ $(gxfont_h) $(gxfont1_h) $(gxtype1_h) $(gzstate_h) \
+ $(estack_h) $(ialloc_h) $(ichar_h) $(icharout_h) \
+ $(idict_h) $(ifont_h) $(igstate_h) $(store_h)
+
+zfont1.$(OBJ): zfont1.c $(OP) \
+ $(gsmatrix_h) $(gxdevice_h) $(gschar_h) \
+ $(gxfixed_h) $(gxfont_h) $(gxfont1_h) \
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(store_h)
+
+zmisc1.$(OBJ): zmisc1.c $(OP) $(memory__h)\
+ $(gscrypt1_h)\
+ $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(sfilter_h) $(stream_h) $(strimpl_h)
+
+# -------------- Compact Font Format and Type 2 charstrings ------------- #
+
+cff.dev: $(INT_MAK) $(ECHOGS_XE) gs_cff.ps psl2int.dev
+ $(SETMOD) cff -ps gs_cff
+
+type2.dev: $(INT_MAK) $(ECHOGS_XE) type1.dev psf2lib.dev
+ $(SETMOD) type2 -include psf2lib
+
+# ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+
+# Native TrueType support
+ttfont.dev: $(INT_MAK) $(ECHOGS_XE) type42.dev
+ $(SETMOD) ttfont -include type42
+ $(ADDMOD) ttfont -ps gs_mro_e gs_wan_e gs_ttf
+
+# Type 42 (embedded TrueType) support
+type42read_=zchar42.$(OBJ) zcharout.$(OBJ) zfont42.$(OBJ)
+type42.dev: $(INT_MAK) $(ECHOGS_XE) $(type42read_) ttflib.dev
+ $(SETMOD) type42 $(type42read_)
+ $(ADDMOD) type42 -include ttflib
+ $(ADDMOD) type42 -oper zchar42 zfont42
+ $(ADDMOD) type42 -ps gs_typ42
+
+zchar42.$(OBJ): zchar42.c $(OP) \
+ $(gsmatrix_h) $(gspaint_h) $(gspath_h) \
+ $(gxfixed_h) $(gxchar_h) $(gxfont_h) $(gxfont42_h) \
+ $(gxistate_h) $(gxpath_h) $(gzstate_h) \
+ $(dstack_h) $(estack_h) $(ichar_h) $(icharout_h) \
+ $(ifont_h) $(igstate_h) $(store_h)
+
+zfont42.$(OBJ): zfont42.c $(OP) \
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h) $(gxfont42_h) \
+ $(bfont_h) $(idict_h) $(idparam_h) $(store_h)
+
+# ======================== Precompilation options ======================== #
+
+# ---------------- Precompiled fonts ---------------- #
+# See fonts.txt for more information.
+
+ccfont_h=ccfont.h $(std_h) $(gsmemory_h) $(iref_h) $(ivmspace_h) $(store_h)
+
+CCFONT=$(OP) $(ccfont_h)
+
+# List the fonts we are going to compile.
+# Because of intrinsic limitations in `make', we have to list
+# the object file names and the font names separately.
+# Because of limitations in the DOS shell, we have to break the fonts up
+# into lists that will fit on a single line (120 characters).
+# The rules for constructing the .c files from the fonts themselves,
+# and for compiling the .c files, are in cfonts.mak, not here.
+# For example, to compile the Courier fonts, you should invoke
+# make -f cfonts.mak Courier_o
+# By convention, the names of the 35 standard compiled fonts use '0' for
+# the foundry name. This allows users to substitute different foundries
+# without having to change this makefile.
+ccfonts_ps=gs_ccfnt
+ccfonts1_=0agk.$(OBJ) 0agko.$(OBJ) 0agd.$(OBJ) 0agdo.$(OBJ)
+ccfonts1=agk agko agd agdo
+ccfonts2_=0bkl.$(OBJ) 0bkli.$(OBJ) 0bkd.$(OBJ) 0bkdi.$(OBJ)
+ccfonts2=bkl bkli bkd bkdi
+ccfonts3_=0crr.$(OBJ) 0cri.$(OBJ) 0crb.$(OBJ) 0crbi.$(OBJ)
+ccfonts3=crr cri crb crbi
+ccfonts4_=0hvr.$(OBJ) 0hvro.$(OBJ) 0hvb.$(OBJ) 0hvbo.$(OBJ)
+ccfonts4=hvr hvro hvb hvbo
+ccfonts5_=0hvrrn.$(OBJ) 0hvrorn.$(OBJ) 0hvbrn.$(OBJ) 0hvborn.$(OBJ)
+ccfonts5=hvrrn hvrorn hvbrn hvborn
+ccfonts6_=0ncr.$(OBJ) 0ncri.$(OBJ) 0ncb.$(OBJ) 0ncbi.$(OBJ)
+ccfonts6=ncr ncri ncb ncbi
+ccfonts7_=0plr.$(OBJ) 0plri.$(OBJ) 0plb.$(OBJ) 0plbi.$(OBJ)
+ccfonts7=plr plri plb plbi
+ccfonts8_=0tmr.$(OBJ) 0tmri.$(OBJ) 0tmb.$(OBJ) 0tmbi.$(OBJ)
+ccfonts8=tmr tmri tmb tmbi
+ccfonts9_=0syr.$(OBJ) 0zcmi.$(OBJ) 0zdr.$(OBJ)
+ccfonts9=syr zcmi zdr
+# The free distribution includes Bitstream Charter, Utopia, and
+# freeware Cyrillic and Kana fonts. We only provide for compiling
+# Charter and Utopia.
+ccfonts10free_=bchr.$(OBJ) bchri.$(OBJ) bchb.$(OBJ) bchbi.$(OBJ)
+ccfonts10free=chr chri chb chbi
+ccfonts11free_=putr.$(OBJ) putri.$(OBJ) putb.$(OBJ) putbi.$(OBJ)
+ccfonts11free=utr utri utb utbi
+# Uncomment the alternatives in the next 4 lines if you want
+# Charter and Utopia compiled in.
+#ccfonts10_=$(ccfonts10free_)
+ccfonts10_=
+#ccfonts10=$(ccfonts10free)
+ccfonts10=
+#ccfonts11_=$(ccfonts11free_)
+ccfonts11_=
+#ccfonts11=$(ccfonts11free)
+ccfonts11=
+# Add your own fonts here if desired.
+ccfonts12_=
+ccfonts12=
+ccfonts13_=
+ccfonts13=
+ccfonts14_=
+ccfonts14=
+ccfonts15_=
+ccfonts15=
+
+# It's OK for ccfonts_.dev not to be CONFIG-dependent, because it only
+# exists during the execution of the following rule.
+# font2c has the prefix "gs" built into it, so we need to instruct
+# genconf to use the same one.
+$(gconfigf_h): $(MAKEFILE) $(INT_MAK) $(GENCONF_XE)
+ $(SETMOD) ccfonts_ -font $(ccfonts1)
+ $(ADDMOD) ccfonts_ -font $(ccfonts2)
+ $(ADDMOD) ccfonts_ -font $(ccfonts3)
+ $(ADDMOD) ccfonts_ -font $(ccfonts4)
+ $(ADDMOD) ccfonts_ -font $(ccfonts5)
+ $(ADDMOD) ccfonts_ -font $(ccfonts6)
+ $(ADDMOD) ccfonts_ -font $(ccfonts7)
+ $(ADDMOD) ccfonts_ -font $(ccfonts8)
+ $(ADDMOD) ccfonts_ -font $(ccfonts9)
+ $(ADDMOD) ccfonts_ -font $(ccfonts10)
+ $(ADDMOD) ccfonts_ -font $(ccfonts11)
+ $(ADDMOD) ccfonts_ -font $(ccfonts12)
+ $(ADDMOD) ccfonts_ -font $(ccfonts13)
+ $(ADDMOD) ccfonts_ -font $(ccfonts14)
+ $(ADDMOD) ccfonts_ -font $(ccfonts15)
+ $(EXP)genconf ccfonts_.dev -n gs -f $(gconfigf_h)
+
+# We separate icfontab.dev from ccfonts.dev so that a customer can put
+# compiled fonts into a separate shared library.
+
+icfontab=icfontab$(CONFIG)
+
+# Define ccfont_table separately, so it can be set from the command line
+# to select an alternate compiled font table.
+ccfont_table=$(icfontab)
+
+$(icfontab).dev: $(MAKEFILE) $(INT_MAK) $(ECHOGS_XE) $(icfontab).$(OBJ) \
+ $(ccfonts1_) $(ccfonts2_) $(ccfonts3_) $(ccfonts4_) $(ccfonts5_) \
+ $(ccfonts6_) $(ccfonts7_) $(ccfonts8_) $(ccfonts9_) $(ccfonts10_) \
+ $(ccfonts11_) $(ccfonts12_) $(ccfonts13_) $(ccfonts14_) $(ccfonts15_)
+ $(SETMOD) $(icfontab) -obj $(icfontab).$(OBJ)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts1_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts2_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts3_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts4_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts5_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts6_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts7_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts8_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts9_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts10_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts11_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts12_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts13_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts14_)
+ $(ADDMOD) $(icfontab) -obj $(ccfonts15_)
+
+$(icfontab).$(OBJ): icfontab.c $(AK) $(ccfont_h) $(gconfigf_h)
+ $(CP_) $(gconfigf_h) gconfigf.h
+ $(CCCF) icfontab.c
+
+# Strictly speaking, ccfonts shouldn't need to include type1,
+# since one could choose to precompile only Type 0 fonts,
+# but getting this exactly right would be too much work.
+ccfonts=ccfonts$(CONFIG)
+$(ccfonts).dev: $(MAKEFILE) $(INT_MAK) type1.dev iccfont.$(OBJ) \
+ $(ccfont_table).dev
+ $(SETMOD) $(ccfonts) -include type1
+ $(ADDMOD) $(ccfonts) -include $(ccfont_table)
+ $(ADDMOD) $(ccfonts) -obj iccfont.$(OBJ)
+ $(ADDMOD) $(ccfonts) -oper ccfonts
+ $(ADDMOD) $(ccfonts) -ps $(ccfonts_ps)
+
+iccfont.$(OBJ): iccfont.c $(GH) $(string__h)\
+ $(gsstruct_h) $(ccfont_h) $(errors_h)\
+ $(ialloc_h) $(idict_h) $(ifont_h) $(iname_h) $(isave_h) $(iutil_h)\
+ $(oper_h) $(ostack_h) $(store_h) $(stream_h) $(strimpl_h) $(sfilter_h) $(iscan_h)
+ $(CCCF) iccfont.c
+
+# ---------------- Compiled initialization code ---------------- #
+
+# We select either iccinit0 or iccinit1 depending on COMPILE_INITS.
+
+iccinit0.$(OBJ): iccinit0.c $(stdpre_h)
+ $(CCCF) iccinit0.c
+
+iccinit1.$(OBJ): gs_init.$(OBJ)
+ $(CP_) gs_init.$(OBJ) iccinit1.$(OBJ)
+
+# All the gs_*.ps files should be prerequisites of gs_init.c,
+# but we don't have any convenient list of them.
+gs_init.c: $(GS_INIT) $(GENINIT_XE) $(gconfig_h)
+ $(EXP)geninit $(GS_INIT) $(gconfig_h) -c gs_init.c
+
+gs_init.$(OBJ): gs_init.c $(stdpre_h)
+ $(CCCF) gs_init.c
+
+# ======================== PostScript Level 2 ======================== #
+
+level2.dev: $(INT_MAK) $(ECHOGS_XE) \
+ cidfont.dev cie.dev cmapread.dev compfont.dev dct.dev devctrl.dev dpsand2.dev\
+ filter.dev level1.dev pattern.dev psl2lib.dev psl2read.dev sepr.dev\
+ type42.dev xfilter.dev
+ $(SETMOD) level2 -include cidfont cie cmapread compfont
+ $(ADDMOD) level2 -include dct devctrl dpsand2 filter
+ $(ADDMOD) level2 -include level1 pattern psl2lib psl2read
+ $(ADDMOD) level2 -include sepr type42 xfilter
+ $(ADDMOD) level2 -emulator PostScript PostScriptLevel2
+
+# Define basic Level 2 language support.
+# This is the minimum required for CMap and CIDFont support.
+
+psl2int_=iutil2.$(OBJ) zmisc2.$(OBJ) zusparam.$(OBJ)
+psl2int.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2int_) dps2int.dev
+ $(SETMOD) psl2int $(psl2int_)
+ $(ADDMOD) psl2int -include dps2int
+ $(ADDMOD) psl2int -oper zmisc2 zusparam
+ $(ADDMOD) psl2int -ps gs_lev2 gs_res
+
+iutil2.$(OBJ): iutil2.c $(GH) $(memory__h) $(string__h)\
+ $(gsparam_h) $(gsutil_h)\
+ $(errors_h) $(opcheck_h) $(imemory_h) $(iutil_h) $(iutil2_h)
+
+zmisc2.$(OBJ): zmisc2.c $(OP) $(memory__h) $(string__h)\
+ $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(ilevel_h) $(iname_h) $(iutil2_h) $(ivmspace_h) $(store_h)
+
+# Note that zusparam includes both Level 1 and Level 2 operators.
+zusparam.$(OBJ): zusparam.c $(OP) $(memory__h) $(string__h)\
+ $(gscdefs_h) $(gsfont_h) $(gsstruct_h) $(gsutil_h) $(gxht_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(iparam_h) $(dstack_h) $(estack_h)\
+ $(iname_h) $(iutil2_h) $(store_h)
+
+# Define full Level 2 support.
+
+psl2read_=zcolor2.$(OBJ) zcsindex.$(OBJ) zht2.$(OBJ) zimage2.$(OBJ)
+# Note that zmisc2 includes both Level 1 and Level 2 operators.
+psl2read.dev: $(INT_MAK) $(ECHOGS_XE) $(psl2read_) psl2int.dev dps2read.dev
+ $(SETMOD) psl2read $(psl2read_)
+ $(ADDMOD) psl2read -include psl2int dps2read
+ $(ADDMOD) psl2read -oper zcolor2_l2 zcsindex_l2
+ $(ADDMOD) psl2read -oper zht2_l2 zimage2_l2
+
+zcolor2.$(OBJ): zcolor2.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+zcsindex.$(OBJ): zcsindex.c $(OP) $(memory__h) \
+ $(gscolor_h) $(gsstruct_h) $(gxfixed_h) $(gxcolor2_h) $(gxcspace_h) $(gsmatrix_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zht2.$(OBJ): zht2.c $(OP) \
+ $(gsstruct_h) $(gxdevice_h) $(gzht_h) \
+ $(estack_h) $(ialloc_h) $(icolor_h) $(idict_h) $(idparam_h) $(igstate_h) \
+ $(iht_h) $(store_h)
+
+zimage2.$(OBJ): zimage2.c $(OP) $(math__h) $(memory__h)\
+ $(gscolor_h) $(gscolor2_h) $(gscspace_h) $(gsimage_h) $(gsmatrix_h)\
+ $(idict_h) $(idparam_h) $(iimage_h) $(ilevel_h) $(igstate_h)
+
+# ---------------- Device control ---------------- #
+# This is a catch-all for setpagedevice and IODevices.
+
+devctrl_=zdevice2.$(OBJ) ziodev2.$(OBJ) zmedia2.$(OBJ) zdevcal.$(OBJ)
+devctrl.dev: $(INT_MAK) $(ECHOGS_XE) $(devctrl_)
+ $(SETMOD) devctrl $(devctrl_)
+ $(ADDMOD) devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+ $(ADDMOD) devctrl -iodev null ram calendar
+ $(ADDMOD) devctrl -ps gs_setpd
+
+zdevice2.$(OBJ): zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(store_h)\
+ $(gxdevice_h) $(gsstate_h)
+
+ziodev2.$(OBJ): ziodev2.c $(OP) $(string__h) $(gp_h)\
+ $(gxiodev_h) $(stream_h) $(files_h) $(iparam_h) $(iutil2_h) $(store_h)
+
+zmedia2.$(OBJ): zmedia2.c $(OP) $(math__h) $(memory__h) \
+ $(gsmatrix_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+
+zdevcal.$(OBJ): zdevcal.c $(GH) $(time__h) \
+ $(gxiodev_h) $(iparam_h) $(istack_h)
+
+# ---------------- Filters other than the ones in sfilter.c ---------------- #
+
+# Standard Level 2 decoding filters only. The PDF configuration uses this.
+fdecode_=scantab.$(OBJ) sfilter2.$(OBJ) zfdecode.$(OBJ)
+fdecode.dev: $(INT_MAK) $(ECHOGS_XE) $(fdecode_) cfd.dev lzwd.dev pdiff.dev pngp.dev rld.dev
+ $(SETMOD) fdecode $(fdecode_)
+ $(ADDMOD) fdecode -include cfd lzwd pdiff pngp rld
+ $(ADDMOD) fdecode -oper zfdecode
+
+zfdecode.$(OBJ): zfdecode.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) \
+ $(sa85x_h) $(scf_h) $(scfx_h) $(sfilter_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) \
+ $(store_h) $(stream_h) $(strimpl_h)
+
+# Complete Level 2 filter capability.
+filter_=zfilter2.$(OBJ)
+filter.dev: $(INT_MAK) $(ECHOGS_XE) fdecode.dev $(filter_) cfe.dev lzwe.dev rle.dev
+ $(SETMOD) filter -include fdecode
+ $(ADDMOD) filter -obj $(filter_)
+ $(ADDMOD) filter -include cfe lzwe rle
+ $(ADDMOD) filter -oper zfilter2
+
+zfilter2.$(OBJ): zfilter2.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(store_h) \
+ $(sfilter_h) $(scfx_h) $(slzwx_h) $(spdiffx_h) $(spngpx_h) $(strimpl_h)
+
+# Extensions beyond Level 2 standard.
+xfilter_=sbhc.$(OBJ) sbwbs.$(OBJ) shcgen.$(OBJ) smtf.$(OBJ) \
+ zfilterx.$(OBJ)
+xfilter.dev: $(INT_MAK) $(ECHOGS_XE) $(xfilter_) pcxd.dev pngp.dev
+ $(SETMOD) xfilter $(xfilter_)
+ $(ADDMOD) xfilter -include pcxd
+ $(ADDMOD) xfilter -oper zfilterx
+
+sbhc.$(OBJ): sbhc.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(sbhc_h) $(shcgen_h) $(strimpl_h)
+
+sbwbs.$(OBJ): sbwbs.c $(AK) $(stdio__h) $(memory__h) \
+ $(gdebug_h) $(sbwbs_h) $(sfilter_h) $(strimpl_h)
+
+shcgen.$(OBJ): shcgen.c $(AK) $(memory__h) $(stdio__h)\
+ $(gdebug_h) $(gserror_h) $(gserrors_h) $(gsmemory_h)\
+ $(scommon_h) $(shc_h) $(shcgen_h)
+
+smtf.$(OBJ): smtf.c $(AK) $(stdio__h) \
+ $(smtf_h) $(strimpl_h)
+
+zfilterx.$(OBJ): zfilterx.c $(OP) $(memory__h)\
+ $(gsstruct_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h)\
+ $(store_h) $(sfilter_h) $(sbhc_h) $(sbtx_h) $(sbwbs_h) $(shcgen_h)\
+ $(smtf_h) $(spcxx_h) $(strimpl_h)
+
+# ---------------- Binary tokens ---------------- #
+
+btoken_=iscanbin.$(OBJ) zbseq.$(OBJ)
+btoken.dev: $(INT_MAK) $(ECHOGS_XE) $(btoken_)
+ $(SETMOD) btoken $(btoken_)
+ $(ADDMOD) btoken -oper zbseq_l2
+ $(ADDMOD) btoken -ps gs_btokn
+
+bseq_h=bseq.h
+btoken_h=btoken.h
+
+iscanbin.$(OBJ): iscanbin.c $(GH) $(math__h) $(memory__h) $(errors_h)\
+ $(gsutil_h) $(ialloc_h) $(ibnum_h) $(idict_h) $(iname_h)\
+ $(iscan_h) $(iutil_h) $(ivmspace_h)\
+ $(bseq_h) $(btoken_h) $(dstack_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+zbseq.$(OBJ): zbseq.c $(OP) $(memory__h)\
+ $(ialloc_h) $(idict_h) $(isave_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)\
+ $(iname_h) $(ibnum_h) $(btoken_h) $(bseq_h)
+
+# ---------------- User paths & insideness testing ---------------- #
+
+upath_=zupath.$(OBJ) ibnum.$(OBJ)
+upath.dev: $(INT_MAK) $(ECHOGS_XE) $(upath_)
+ $(SETMOD) upath $(upath_)
+ $(ADDMOD) upath -oper zupath_l2
+
+zupath.$(OBJ): zupath.c $(OP) \
+ $(idict_h) $(dstack_h) $(iutil_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h) \
+ $(gscoord_h) $(gsmatrix_h) $(gspaint_h) $(gspath_h) $(gsstate_h) \
+ $(gxfixed_h) $(gxdevice_h) $(gzpath_h) $(gzstate_h)
+
+# -------- Additions common to Display PostScript and Level 2 -------- #
+
+dpsand2.dev: $(INT_MAK) $(ECHOGS_XE) btoken.dev color.dev upath.dev dps2lib.dev dps2read.dev
+ $(SETMOD) dpsand2 -include btoken color upath dps2lib dps2read
+
+dps2int_=zvmem2.$(OBJ) zdps1.$(OBJ)
+# Note that zvmem2 includes both Level 1 and Level 2 operators.
+dps2int.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2int_)
+ $(SETMOD) dps2int $(dps2int_)
+ $(ADDMOD) dps2int -oper zvmem2 zdps1_l2
+ $(ADDMOD) dps2int -ps gs_dps1
+
+dps2read_=ibnum.$(OBJ) zchar2.$(OBJ)
+dps2read.dev: $(INT_MAK) $(ECHOGS_XE) $(dps2read_) dps2int.dev
+ $(SETMOD) dps2read $(dps2read_)
+ $(ADDMOD) dps2read -include dps2int
+ $(ADDMOD) dps2read -oper ireclaim_l2 zchar2_l2
+ $(ADDMOD) dps2read -ps gs_dps2
+
+ibnum.$(OBJ): ibnum.c $(GH) $(math__h) $(memory__h)\
+ $(errors_h) $(stream_h) $(ibnum_h) $(imemory_h) $(iutil_h)
+
+zchar2.$(OBJ): zchar2.c $(OP)\
+ $(gschar_h) $(gsmatrix_h) $(gspath_h) $(gsstruct_h)\
+ $(gxchar_h) $(gxfixed_h) $(gxfont_h)\
+ $(ialloc_h) $(ichar_h) $(estack_h) $(ifont_h) $(iname_h) $(igstate_h)\
+ $(store_h) $(stream_h) $(ibnum_h)
+
+zdps1.$(OBJ): zdps1.c $(OP) \
+ $(gsmatrix_h) $(gspath_h) $(gspath2_h) $(gsstate_h) \
+ $(ialloc_h) $(ivmspace_h) $(igstate_h) $(store_h) $(stream_h) $(ibnum_h)
+
+zvmem2.$(OBJ): zvmem2.c $(OP) \
+ $(estack_h) $(ialloc_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Display PostScript ---------------- #
+
+dps_=zdps.$(OBJ) icontext.$(OBJ) zcontext.$(OBJ)
+dps.dev: $(INT_MAK) $(ECHOGS_XE) dpslib.dev level2.dev $(dps_)
+ $(SETMOD) dps -include dpslib level2
+ $(ADDMOD) dps -obj $(dps_)
+ $(ADDMOD) dps -oper zcontext zdps
+ $(ADDMOD) dps -ps gs_dps
+
+icontext.$(OBJ): icontext.c $(GH)\
+ $(gsstruct_h) $(gxalloc_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(ostack_h)\
+ $(icontext_h) $(igstate_h) $(interp_h) $(store_h)
+
+zdps.$(OBJ): zdps.c $(OP)\
+ $(gsdps_h) $(gsstate_h) $(igstate_h) $(iname_h) $(store_h)
+
+zcontext.$(OBJ): zcontext.c $(OP) $(gp_h) $(memory__h)\
+ $(gsexit_h) $(gsstruct_h) $(gsutil_h) $(gxalloc_h)\
+ $(icontext_h) $(idict_h) $(igstate_h) $(istruct_h)\
+ $(dstack_h) $(estack_h) $(ostack_h) $(store_h)
+
+# The following #ifdef ... #endif are just a comment to mark a DPNEXT area.
+#ifdef DPNEXT
+
+# ---------------- NeXT Display PostScript ---------------- #
+#**************** NOT READY FOR USE YET ****************#
+
+# There should be a gsdpnext.c, but there isn't yet.
+#dpsnext_=zdpnext.$(OBJ) gsdpnext.$(OBJ)
+dpsnext_=zdpnext.$(OBJ)
+dpsnext.dev: $(INT_MAK) $(ECHOGS_XE) dps.dev $(dpsnext_) gs_dpnxt.ps
+ $(SETMOD) dpsnext -include dps
+ $(ADDMOD) dpsnext -obj $(dpsnext_)
+ $(ADDMOD) dpsnext -oper zdpnext
+ $(ADDMOD) dpsnext -ps gs_dpnxt
+
+zdpnext.$(OBJ): zdpnext.c $(OP)\
+ $(gscspace_h) $(gsiparam_h) $(gsmatrix_h) $(gxcvalue_h) $(gxsample_h)\
+ $(ialloc_h) $(igstate_h) $(iimage_h)
+
+# See above re the following.
+#endif /* DPNEXT */
+
+# -------- Composite (PostScript Type 0) font support -------- #
+
+compfont.dev: $(INT_MAK) $(ECHOGS_XE) psf0lib.dev psf0read.dev
+ $(SETMOD) compfont -include psf0lib psf0read
+
+# We always include zfcmap.$(OBJ) because zfont0.c refers to it,
+# and it's not worth the trouble to exclude.
+psf0read_=zchar2.$(OBJ) zfcmap.$(OBJ) zfont0.$(OBJ)
+psf0read.dev: $(INT_MAK) $(ECHOGS_XE) $(psf0read_)
+ $(SETMOD) psf0read $(psf0read_)
+ $(ADDMOD) psf0read -oper zfont0 zchar2 zfcmap
+
+zfcmap.$(OBJ): zfcmap.c $(OP)\
+ $(gsmatrix_h) $(gsstruct_h) $(gsutil_h)\
+ $(gxfcmap_h) $(gxfont_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifont_h) $(iname_h) $(store_h)
+
+zfont0.$(OBJ): zfont0.c $(OP)\
+ $(gschar_h) $(gsstruct_h)\
+ $(gxdevice_h) $(gxfcmap_h) $(gxfixed_h) $(gxfont_h) $(gxfont0_h) $(gxmatrix_h)\
+ $(gzstate_h)\
+ $(bfont_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(iname_h)\
+ $(store_h)
+
+# ---------------- CMap support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cmapread_=zfcmap.$(OBJ)
+cmapread.dev: $(INT_MAK) $(ECHOGS_XE) $(cmapread_) cmaplib.dev psl2int.dev
+ $(SETMOD) cmapread $(cmapread_)
+ $(ADDMOD) cmapread -include cmaplib psl2int
+ $(ADDMOD) cmapread -oper zfcmap
+ $(ADDMOD) cmapread -ps gs_cmap
+
+# ---------------- CIDFont support ---------------- #
+# Note that this requires at least minimal Level 2 support,
+# because it requires findresource.
+
+cidread_=zcid.$(OBJ)
+cidfont.dev: $(INT_MAK) $(ECHOGS_XE) psf1read.dev psl2int.dev type42.dev\
+ $(cidread_)
+ $(SETMOD) cidfont $(cidread_)
+ $(ADDMOD) cidfont -include psf1read psl2int type42
+ $(ADDMOD) cidfont -ps gs_cidfn
+ $(ADDMOD) cidfont -oper zcid
+
+zcid.$(OBJ): zcid.c $(OP)\
+ $(gsccode_h) $(gsmatrix_h) $(gxfont_h)\
+ $(bfont_h) $(iname_h) $(store_h)
+
+# ---------------- CIE color ---------------- #
+
+cieread_=zcie.$(OBJ) zcrd.$(OBJ)
+cie.dev: $(INT_MAK) $(ECHOGS_XE) $(cieread_) cielib.dev
+ $(SETMOD) cie $(cieread_)
+ $(ADDMOD) cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) cie -include cielib
+
+icie_h=icie.h
+
+zcie.$(OBJ): zcie.c $(OP) $(math__h) $(memory__h) \
+ $(gscolor2_h) $(gscie_h) $(gsstruct_h) $(gxcspace_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+zcrd.$(OBJ): zcrd.c $(OP) $(math__h) \
+ $(gscspace_h) $(gscolor2_h) $(gscie_h) $(gsstruct_h) \
+ $(ialloc_h) $(icie_h) $(idict_h) $(idparam_h) $(estack_h) \
+ $(isave_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Pattern color ---------------- #
+
+pattern.dev: $(INT_MAK) $(ECHOGS_XE) patlib.dev patread.dev
+ $(SETMOD) pattern -include patlib patread
+
+patread_=zpcolor.$(OBJ)
+patread.dev: $(INT_MAK) $(ECHOGS_XE) $(patread_)
+ $(SETMOD) patread $(patread_)
+ $(ADDMOD) patread -oper zpcolor_l2
+
+zpcolor.$(OBJ): zpcolor.c $(OP)\
+ $(gscolor_h) $(gsmatrix_h) $(gsstruct_h)\
+ $(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gxfixed_h) $(gxpcolor_h)\
+ $(estack_h) $(ialloc_h) $(idict_h) $(idparam_h) $(igstate_h) $(istruct_h)\
+ $(store_h)
+
+# ---------------- Separation color ---------------- #
+
+seprread_=zcssepr.$(OBJ)
+sepr.dev: $(INT_MAK) $(ECHOGS_XE) $(seprread_) seprlib.dev
+ $(SETMOD) sepr $(seprread_)
+ $(ADDMOD) sepr -oper zcssepr_l2
+ $(ADDMOD) sepr -include seprlib
+
+zcssepr.$(OBJ): zcssepr.c $(OP) \
+ $(gscolor_h) $(gscsepr_h) $(gsmatrix_h) $(gsstruct_h) \
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) \
+ $(ialloc_h) $(icsmap_h) $(estack_h) $(igstate_h) $(ivmspace_h) $(store_h)
+
+# ---------------- Functions ---------------- #
+
+ifunc_h=ifunc.h
+
+# Generic support, and FunctionType 0.
+funcread_=zfunc.$(OBJ) zfunc0.$(OBJ)
+func.dev: $(INT_MAK) $(ECHOGS_XE) $(funcread_) funclib.dev
+ $(SETMOD) func $(funcread_)
+ $(ADDMOD) func -oper zfunc zfunc0
+ $(ADDMOD) func -include funclib
+
+zfunc.$(OBJ): zfunc.c $(OP) $(memory__h)\
+ $(gsfunc_h) $(gsstruct_h)\
+ $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h) $(store_h)
+
+zfunc0.$(OBJ): zfunc0.c $(OP) $(memory__h)\
+ $(gsdsrc_h) $(gsfunc_h) $(gsfunc0_h)\
+ $(stream_h)\
+ $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)
+
+# ---------------- DCT filters ---------------- #
+# The definitions for jpeg*.dev are in jpeg.mak.
+
+dct.dev: $(INT_MAK) $(ECHOGS_XE) dcte.dev dctd.dev
+ $(SETMOD) dct -include dcte dctd
+
+# Common code
+
+dctc_=zfdctc.$(OBJ)
+
+zfdctc.$(OBJ): zfdctc.c $(GH) $(memory__h) $(stdio__h)\
+ $(errors_h) $(opcheck_h)\
+ $(idict_h) $(idparam_h) $(imemory_h) $(ipacked_h) $(iutil_h)\
+ $(sdct_h) $(sjpeg_h) $(strimpl_h)\
+ jpeglib.h
+
+# Encoding (compression)
+
+dcte_=$(dctc_) zfdcte.$(OBJ)
+dcte.dev: $(INT_MAK) $(ECHOGS_XE) sdcte.dev $(dcte_)
+ $(SETMOD) dcte -include sdcte
+ $(ADDMOD) dcte -obj $(dcte_)
+ $(ADDMOD) dcte -oper zfdcte
+
+zfdcte.$(OBJ): zfdcte.c $(OP) $(memory__h) $(stdio__h)\
+ $(idict_h) $(idparam_h) $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# Decoding (decompression)
+
+dctd_=$(dctc_) zfdctd.$(OBJ)
+dctd.dev: $(INT_MAK) $(ECHOGS_XE) sdctd.dev $(dctd_)
+ $(SETMOD) dctd -include sdctd
+ $(ADDMOD) dctd -obj $(dctd_)
+ $(ADDMOD) dctd -oper zfdctd
+
+zfdctd.$(OBJ): zfdctd.c $(OP) $(memory__h) $(stdio__h)\
+ $(ifilter_h) $(sdct_h) $(sjpeg_h) $(strimpl_h) \
+ jpeglib.h
+
+# ---------------- zlib/Flate filters ---------------- #
+
+fzlib.dev: $(INT_MAK) $(ECHOGS_XE) zfzlib.$(OBJ) szlibe.dev szlibd.dev
+ $(SETMOD) fzlib -include szlibe szlibd
+ $(ADDMOD) fzlib -obj zfzlib.$(OBJ)
+ $(ADDMOD) fzlib -oper zfzlib
+
+zfzlib.$(OBJ): zfzlib.c $(OP) \
+ $(errors_h) $(idict_h) $(ifilter_h) \
+ $(spdiffx_h) $(spngpx_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) zfzlib.c
+
+# ================================ PDF ================================ #
+
+# We need most of the Level 2 interpreter to do PDF, but not all of it.
+# In fact, we don't even need all of a Level 1 interpreter.
+
+# Because of the way the PDF encodings are defined, they must get loaded
+# before we install the Level 2 resource machinery.
+# On the other hand, the PDF .ps files must get loaded after
+# level2dict is defined.
+pdfmin.dev: $(INT_MAK) $(ECHOGS_XE)\
+ psbase.dev color.dev dps2lib.dev dps2read.dev\
+ fdecode.dev type1.dev pdffonts.dev psl2lib.dev psl2read.dev pdfread.dev
+ $(SETMOD) pdfmin -include psbase color dps2lib dps2read
+ $(ADDMOD) pdfmin -include fdecode type1
+ $(ADDMOD) pdfmin -include pdffonts psl2lib psl2read pdfread
+ $(ADDMOD) pdfmin -emulator PDF
+
+pdf.dev: $(INT_MAK) $(ECHOGS_XE)\
+ pdfmin.dev cff.dev cidfont.dev cie.dev compfont.dev cmapread.dev dctd.dev\
+ func.dev ttfont.dev type2.dev
+ $(SETMOD) pdf -include pdfmin cff cidfont cie cmapread compfont dctd
+ $(ADDMOD) pdf -include func ttfont type2
+
+# Reader only
+
+pdffonts.dev: $(INT_MAK) $(ECHOGS_XE) \
+ gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps
+ $(SETMOD) pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+
+# pdf_2ps must be the last .ps file loaded.
+pdfread.dev: $(INT_MAK) $(ECHOGS_XE) fzlib.dev
+ $(SETMOD) pdfread -include fzlib
+ $(ADDMOD) pdfread -ps gs_pdf gs_l2img
+ $(ADDMOD) pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+ $(ADDMOD) pdfread -ps pdf_2ps
+
+# ============================= Main program ============================== #
+
+gs.$(OBJ): gs.c $(GH) \
+ $(imain_h) $(imainarg_h) $(iminst_h)
+
+imainarg.$(OBJ): imainarg.c $(GH) $(ctype__h) $(memory__h) $(string__h) \
+ $(gp_h) \
+ $(gsargs_h) $(gscdefs_h) $(gsdevice_h) $(gsmdebug_h) $(gxdevice_h) $(gxdevmem_h) \
+ $(errors_h) $(estack_h) $(files_h) \
+ $(ialloc_h) $(imain_h) $(imainarg_h) $(iminst_h) \
+ $(iname_h) $(interp_h) $(iscan_h) $(iutil_h) $(ivmspace_h) \
+ $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+imain.$(OBJ): imain.c $(GH) $(memory__h) $(string__h)\
+ $(gp_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h) $(gxdevice_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(idebug_h) $(idict_h) $(iname_h) $(interp_h)\
+ $(isave_h) $(iscan_h) $(ivmspace_h)\
+ $(main_h) $(oper_h) $(ostack_h)\
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+
+interp.$(OBJ): interp.c $(GH) $(memory__h) $(string__h)\
+ $(gsstruct_h)\
+ $(dstack_h) $(errors_h) $(estack_h) $(files_h)\
+ $(ialloc_h) $(iastruct_h) $(inamedef_h) $(idict_h) $(interp_h) $(ipacked_h)\
+ $(iscan_h) $(isave_h) $(istack_h) $(iutil_h) $(ivmspace_h)\
+ $(oper_h) $(ostack_h) $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(CCINT) interp.c
+
+ireclaim.$(OBJ): ireclaim.c $(GH) \
+ $(errors_h) $(gsstruct_h) $(iastate_h) $(opdef_h) $(store_h) \
+ $(dstack_h) $(estack_h) $(ostack_h)
+# Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for Independent JPEG Group library code.
+
+# NOTE: This makefile is only known to work with the following versions
+# of the IJG library: 6, 6a.
+# As of May 11, 1996, version 6a is the current version.
+#
+# You can get the IJG library by Internet anonymous FTP from the following
+# places:
+# Standard distribution (tar + gzip format, Unix end-of-line):
+# ftp.uu.net:/graphics/jpeg/jpegsrc.v*.tar.gz
+# ftp.cs.wisc.edu:/ghost/jpegsrc.v*.tar.gz
+# MS-DOS archive (PKZIP a.k.a. zip format, MS-DOS end-of-line):
+# ftp.simtel.net:/pub/simtelnet/msdos/graphics/jpegsr*.zip
+# ftp.cs.wisc.edu:/ghost/jpeg-*.zip
+# The first site named above (ftp.uu.net and ftp.simtel.net) is supposed
+# to be the master distribution site, so it may have a more up-to-date
+# version; the ftp.cs.wisc.edu site is the master distribution site for
+# Ghostscript, so it will always have IJG library versions known to be
+# compatible with Ghostscript.
+#
+# If the version number, and hence the subdirectory name, changes, you
+# will probably want to change the definitions of JSRCDIR and possibly
+# JVERSION (in the platform-specific makefile, not here) to reflect this,
+# since that way you can use the IJG archive without change.
+#
+# NOTE: For some obscure reason (probably a bug in djtarx), if you are
+# compiling on a DesqView/X system, you should use the zip version of the
+# IJG library, not the tar.gz version.
+
+# Define the name of this makefile.
+JPEG_MAK=jpeg.mak
+
+# JSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the IJG library sources are stored.
+#JSRCDIR=jpeg-6a
+# JVERSION is defined in the platform-specific makefile, not here,
+# as the IJG library major version number (currently "5" or "6").
+#JVERSION=6
+
+JSRC=$(JSRCDIR)$(D)
+# CCCJ is defined in gs.mak.
+#CCCJ=$(CCC) -I. -I$(JSRCDIR)
+
+# We keep all of the IJG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+# However, we need our own version of jconfig.h, and our own "wrapper" for
+# jmorecfg.h. We also need a substitute for jerror.c, in order to
+# keep the error strings out of the automatic data segment in
+# 16-bit environments. For v5*, we also need our own version of jpeglib.h
+# in order to change MAX_BLOCKS_IN_MCU for Adobe compatibility.
+# (This need will go away when IJG v6 is released.)
+
+# Because this file is included after lib.mak, we can't use _h macros
+# to express indirect dependencies; instead, we build the dependencies
+# into the rules for copying the files.
+jconfig_h=jconfig.h
+jerror_h=jerror.h
+jmorecfg_h=jmorecfg.h
+jpeglib_h=jpeglib.h
+
+jconfig.h: gsjconf.h $(std_h)
+ $(CP_) gsjconf.h jconfig.h
+
+jmorecfg.h: gsjmorec.h jmcorig.h
+ $(CP_) gsjmorec.h jmorecfg.h
+
+jmcorig.h: $(JSRC)jmorecfg.h
+ $(CP_) $(JSRC)jmorecfg.h jmcorig.h
+
+jpeglib.h: jlib$(JVERSION).h jconfig.h jmorecfg.h
+ $(CP_) jlib$(JVERSION).h jpeglib.h
+
+jlib5.h: gsjpglib.h
+ $(CP_) gsjpglib.h jlib5.h
+
+jlib6.h: $(JSRC)jpeglib.h
+ $(CP_) $(JSRC)jpeglib.h jlib6.h
+
+# To ensure that the compiler finds our versions of jconfig.h and jmorecfg.h,
+# regardless of the compiler's search rule, we must copy up all .c files,
+# and all .h files that include either of these files, directly or
+# indirectly. The only such .h files currently are jinclude.h and jpeglib.h.
+# (Currently, we supply our own version of jpeglib.h -- see above.)
+# Also, to avoid including the JSRCDIR directory name in our source files,
+# we must also copy up any other .h files that our own code references.
+# Currently, the only such .h files are jerror.h and jversion.h.
+
+JHCOPY=jinclude.h jpeglib.h jerror.h jversion.h
+
+jinclude.h: $(JSRC)jinclude.h
+ $(CP_) $(JSRC)jinclude.h jinclude.h
+
+#jpeglib.h: $(JSRC)jpeglib.h
+# $(CP_) $(JSRC)jpeglib.h jpeglib.h
+
+jerror.h: $(JSRC)jerror.h
+ $(CP_) $(JSRC)jerror.h jerror.h
+
+jversion.h: $(JSRC)jversion.h
+ $(CP_) $(JSRC)jversion.h jversion.h
+
+# In order to avoid having to keep the dependency lists for the IJG code
+# accurate, we simply make all of them depend on the only files that
+# we are ever going to change, and on all the .h files that must be copied up.
+# This is too conservative, but only hurts us if we are changing our own
+# j*.h files, which happens only rarely during development.
+
+JDEP=$(AK) $(jconfig_h) $(jerror_h) $(jmorecfg_h) $(JHCOPY)
+
+# Code common to compression and decompression.
+
+jpegc_=jcomapi.$(OBJ) jutils.$(OBJ) sjpegerr.$(OBJ) jmemmgr.$(OBJ)
+jpegc.dev: $(JPEG_MAK) $(ECHOGS_XE) $(jpegc_)
+ $(SETMOD) jpegc $(jpegc_)
+
+jcomapi.$(OBJ): $(JSRC)jcomapi.c $(JDEP)
+ $(CP_) $(JSRC)jcomapi.c .
+ $(CCCJ) jcomapi.c
+ $(RM_) jcomapi.c
+
+jutils.$(OBJ): $(JSRC)jutils.c $(JDEP)
+ $(CP_) $(JSRC)jutils.c .
+ $(CCCJ) jutils.c
+ $(RM_) jutils.c
+
+# Note that sjpegerr replaces jerror.
+sjpegerr.$(OBJ): sjpegerr.c $(JDEP)
+ $(CCCF) sjpegerr.c
+
+jmemmgr.$(OBJ): $(JSRC)jmemmgr.c $(JDEP)
+ $(CP_) $(JSRC)jmemmgr.c .
+ $(CCCJ) jmemmgr.c
+ $(RM_) jmemmgr.c
+
+# Encoding (compression) code.
+
+jpege.dev: jpege$(JVERSION).dev
+ $(CP_) jpege$(JVERSION).dev jpege.dev
+
+jpege5=jcapi.$(OBJ)
+jpege6=jcapimin.$(OBJ) jcapistd.$(OBJ) jcinit.$(OBJ)
+
+jpege_1=jccoefct.$(OBJ) jccolor.$(OBJ) jcdctmgr.$(OBJ)
+jpege_2=jchuff.$(OBJ) jcmainct.$(OBJ) jcmarker.$(OBJ) jcmaster.$(OBJ)
+jpege_3=jcparam.$(OBJ) jcprepct.$(OBJ) jcsample.$(OBJ) jfdctint.$(OBJ)
+
+jpege5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege5) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege5 $(jpege5)
+ $(ADDMOD) jpege5 -include jpegc
+ $(ADDMOD) jpege5 -obj $(jpege_1)
+ $(ADDMOD) jpege5 -obj $(jpege_2)
+ $(ADDMOD) jpege5 -obj $(jpege_3)
+
+jpege6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpege6) $(jpege_1) $(jpege_2) $(jpege_3)
+ $(SETMOD) jpege6 $(jpege6)
+ $(ADDMOD) jpege6 -include jpegc
+ $(ADDMOD) jpege6 -obj $(jpege_1)
+ $(ADDMOD) jpege6 -obj $(jpege_2)
+ $(ADDMOD) jpege6 -obj $(jpege_3)
+
+# jcapi.c is v5* only
+jcapi.$(OBJ): $(JSRC)jcapi.c $(JDEP)
+ $(CP_) $(JSRC)jcapi.c .
+ $(CCCJ) jcapi.c
+ $(RM_) jcapi.c
+
+# jcapimin.c is new in v6
+jcapimin.$(OBJ): $(JSRC)jcapimin.c $(JDEP)
+ $(CP_) $(JSRC)jcapimin.c .
+ $(CCCJ) jcapimin.c
+ $(RM_) jcapimin.c
+
+# jcapistd.c is new in v6
+jcapistd.$(OBJ): $(JSRC)jcapistd.c $(JDEP)
+ $(CP_) $(JSRC)jcapistd.c .
+ $(CCCJ) jcapistd.c
+ $(RM_) jcapistd.c
+
+# jcinit.c is new in v6
+jcinit.$(OBJ): $(JSRC)jcinit.c $(JDEP)
+ $(CP_) $(JSRC)jcinit.c .
+ $(CCCJ) jcinit.c
+ $(RM_) jcinit.c
+
+jccoefct.$(OBJ): $(JSRC)jccoefct.c $(JDEP)
+ $(CP_) $(JSRC)jccoefct.c .
+ $(CCCJ) jccoefct.c
+ $(RM_) jccoefct.c
+
+jccolor.$(OBJ): $(JSRC)jccolor.c $(JDEP)
+ $(CP_) $(JSRC)jccolor.c .
+ $(CCCJ) jccolor.c
+ $(RM_) jccolor.c
+
+jcdctmgr.$(OBJ): $(JSRC)jcdctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jcdctmgr.c .
+ $(CCCJ) jcdctmgr.c
+ $(RM_) jcdctmgr.c
+
+jchuff.$(OBJ): $(JSRC)jchuff.c $(JDEP)
+ $(CP_) $(JSRC)jchuff.c .
+ $(CCCJ) jchuff.c
+ $(RM_) jchuff.c
+
+jcmainct.$(OBJ): $(JSRC)jcmainct.c $(JDEP)
+ $(CP_) $(JSRC)jcmainct.c .
+ $(CCCJ) jcmainct.c
+ $(RM_) jcmainct.c
+
+jcmarker.$(OBJ): $(JSRC)jcmarker.c $(JDEP)
+ $(CP_) $(JSRC)jcmarker.c .
+ $(CCCJ) jcmarker.c
+ $(RM_) jcmarker.c
+
+jcmaster.$(OBJ): $(JSRC)jcmaster.c $(JDEP)
+ $(CP_) $(JSRC)jcmaster.c .
+ $(CCCJ) jcmaster.c
+ $(RM_) jcmaster.c
+
+jcparam.$(OBJ): $(JSRC)jcparam.c $(JDEP)
+ $(CP_) $(JSRC)jcparam.c .
+ $(CCCJ) jcparam.c
+ $(RM_) jcparam.c
+
+jcprepct.$(OBJ): $(JSRC)jcprepct.c $(JDEP)
+ $(CP_) $(JSRC)jcprepct.c .
+ $(CCCJ) jcprepct.c
+ $(RM_) jcprepct.c
+
+jcsample.$(OBJ): $(JSRC)jcsample.c $(JDEP)
+ $(CP_) $(JSRC)jcsample.c .
+ $(CCCJ) jcsample.c
+ $(RM_) jcsample.c
+
+jfdctint.$(OBJ): $(JSRC)jfdctint.c $(JDEP)
+ $(CP_) $(JSRC)jfdctint.c .
+ $(CCCJ) jfdctint.c
+ $(RM_) jfdctint.c
+
+# Decompression code
+
+jpegd.dev: jpegd$(JVERSION).dev
+ $(CP_) jpegd$(JVERSION).dev jpegd.dev
+
+jpegd5=jdapi.$(OBJ)
+jpegd6=jdapimin.$(OBJ) jdapistd.$(OBJ) jdinput.$(OBJ) jdphuff.$(OBJ)
+
+jpegd_1=jdcoefct.$(OBJ) jdcolor.$(OBJ)
+jpegd_2=jddctmgr.$(OBJ) jdhuff.$(OBJ) jdmainct.$(OBJ) jdmarker.$(OBJ)
+jpegd_3=jdmaster.$(OBJ) jdpostct.$(OBJ) jdsample.$(OBJ) jidctint.$(OBJ)
+
+jpegd5.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd5) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd5 $(jpegd5)
+ $(ADDMOD) jpegd5 -include jpegc
+ $(ADDMOD) jpegd5 -obj $(jpegd_1)
+ $(ADDMOD) jpegd5 -obj $(jpegd_2)
+ $(ADDMOD) jpegd5 -obj $(jpegd_3)
+
+jpegd6.dev: $(JPEG_MAK) $(ECHOGS_XE) jpegc.dev $(jpegd6) $(jpegd_1) $(jpegd_2) $(jpegd_3)
+ $(SETMOD) jpegd6 $(jpegd6)
+ $(ADDMOD) jpegd6 -include jpegc
+ $(ADDMOD) jpegd6 -obj $(jpegd_1)
+ $(ADDMOD) jpegd6 -obj $(jpegd_2)
+ $(ADDMOD) jpegd6 -obj $(jpegd_3)
+
+# jdapi.c is v5* only
+jdapi.$(OBJ): $(JSRC)jdapi.c $(JDEP)
+ $(CP_) $(JSRC)jdapi.c .
+ $(CCCJ) jdapi.c
+ $(RM_) jdapi.c
+
+# jdapimin.c is new in v6
+jdapimin.$(OBJ): $(JSRC)jdapimin.c $(JDEP)
+ $(CP_) $(JSRC)jdapimin.c .
+ $(CCCJ) jdapimin.c
+ $(RM_) jdapimin.c
+
+# jdapistd.c is new in v6
+jdapistd.$(OBJ): $(JSRC)jdapistd.c $(JDEP)
+ $(CP_) $(JSRC)jdapistd.c .
+ $(CCCJ) jdapistd.c
+ $(RM_) jdapistd.c
+
+jdcoefct.$(OBJ): $(JSRC)jdcoefct.c $(JDEP)
+ $(CP_) $(JSRC)jdcoefct.c .
+ $(CCCJ) jdcoefct.c
+ $(RM_) jdcoefct.c
+
+jdcolor.$(OBJ): $(JSRC)jdcolor.c $(JDEP)
+ $(CP_) $(JSRC)jdcolor.c .
+ $(CCCJ) jdcolor.c
+ $(RM_) jdcolor.c
+
+jddctmgr.$(OBJ): $(JSRC)jddctmgr.c $(JDEP)
+ $(CP_) $(JSRC)jddctmgr.c .
+ $(CCCJ) jddctmgr.c
+ $(RM_) jddctmgr.c
+
+jdhuff.$(OBJ): $(JSRC)jdhuff.c $(JDEP)
+ $(CP_) $(JSRC)jdhuff.c .
+ $(CCCJ) jdhuff.c
+ $(RM_) jdhuff.c
+
+# jdinput.c is new in v6
+jdinput.$(OBJ): $(JSRC)jdinput.c $(JDEP)
+ $(CP_) $(JSRC)jdinput.c .
+ $(CCCJ) jdinput.c
+ $(RM_) jdinput.c
+
+jdmainct.$(OBJ): $(JSRC)jdmainct.c $(JDEP)
+ $(CP_) $(JSRC)jdmainct.c .
+ $(CCCJ) jdmainct.c
+ $(RM_) jdmainct.c
+
+jdmarker.$(OBJ): $(JSRC)jdmarker.c $(JDEP)
+ $(CP_) $(JSRC)jdmarker.c .
+ $(CCCJ) jdmarker.c
+ $(RM_) jdmarker.c
+
+jdmaster.$(OBJ): $(JSRC)jdmaster.c $(JDEP)
+ $(CP_) $(JSRC)jdmaster.c .
+ $(CCCJ) jdmaster.c
+ $(RM_) jdmaster.c
+
+# jdphuff.c is new in v6
+jdphuff.$(OBJ): $(JSRC)jdphuff.c $(JDEP)
+ $(CP_) $(JSRC)jdphuff.c .
+ $(CCCJ) jdphuff.c
+ $(RM_) jdphuff.c
+
+jdpostct.$(OBJ): $(JSRC)jdpostct.c $(JDEP)
+ $(CP_) $(JSRC)jdpostct.c .
+ $(CCCJ) jdpostct.c
+ $(RM_) jdpostct.c
+
+jdsample.$(OBJ): $(JSRC)jdsample.c $(JDEP)
+ $(CP_) $(JSRC)jdsample.c .
+ $(CCCJ) jdsample.c
+ $(RM_) jdsample.c
+
+jidctint.$(OBJ): $(JSRC)jidctint.c $(JDEP)
+ $(CP_) $(JSRC)jidctint.c .
+ $(CCCJ) jidctint.c
+ $(RM_) jidctint.c
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for PNG (Portable Network Graphics) code.
+
+# This partial makefile compiles the png library for use in the Ghostscript
+# PNG drivers. You can get the source code for this library from:
+# ftp://swrinde.nde.swri.edu/pub/png/src/
+# The makefile is known to work with the following library versions:
+# 0.89, 0.90, 0.95, and 0.96. NOTE: the archive for libpng 0.95 may
+# be inconsistent: if you have compilation problems, use an older version.
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+#
+# The specification for the PNG file format is available from:
+# http://www.group42.com/png.htm
+# http://www.w3.org/pub/WWW/TR/WD-png
+
+# Define the name of this makefile.
+LIBPNG_MAK=libpng.mak
+
+# PSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the PNG library sources are stored.
+#PSRCDIR=libpng
+# PVERSION is defined in the platform-specific makefile, not here,
+# as the libpng version number ("89", "90", "95", or "96").
+#PVERSION=96
+
+PSRC=$(PSRCDIR)$(D)
+# CCCP is defined in gs.mak.
+#CCCP=$(CCC) -I$(PSRCDIR) -I$(ZSRCDIR)
+
+# We keep all of the PNG code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+PDEP=$(AK)
+
+png_1=png.$(OBJ) pngmem.$(OBJ) pngerror.$(OBJ)
+png_2=pngtrans.$(OBJ) pngwrite.$(OBJ) pngwtran.$(OBJ) pngwutil.$(OBJ)
+
+# libpng modules
+
+png.$(OBJ): $(PSRC)png.c $(PDEP)
+ $(CCCP) $(PSRC)png.c
+
+# version 0.89 uses pngwio.c
+pngwio.$(OBJ): $(PSRC)pngwio.c $(PDEP)
+ $(CCCP) $(PSRC)pngwio.c
+
+pngmem.$(OBJ): $(PSRC)pngmem.c $(PDEP)
+ $(CCCP) $(PSRC)pngmem.c
+
+pngerror.$(OBJ): $(PSRC)pngerror.c $(PDEP)
+ $(CCCP) $(PSRC)pngerror.c
+
+pngtrans.$(OBJ): $(PSRC)pngtrans.c $(PDEP)
+ $(CCCP) $(PSRC)pngtrans.c
+
+pngwrite.$(OBJ): $(PSRC)pngwrite.c $(PDEP)
+ $(CCCP) $(PSRC)pngwrite.c
+
+pngwtran.$(OBJ): $(PSRC)pngwtran.c $(PDEP)
+ $(CCCP) $(PSRC)pngwtran.c
+
+pngwutil.$(OBJ): $(PSRC)pngwutil.c $(PDEP)
+ $(CCCP) $(PSRC)pngwutil.c
+
+# Define the version of libpng.dev that we are actually using.
+libpng.dev: $(MAKEFILE) libpng_$(SHARE_LIBPNG).dev
+ $(CP_) libpng_$(SHARE_LIBPNG).dev libpng.dev
+
+# Define the shared version of libpng.
+# Note that it requires libz, which must be searched *after* libpng.
+libpng_1.dev: $(MAKEFILE) $(LIBPNG_MAK) $(ECHOGS_XE) zlibe.dev
+ $(SETMOD) libpng_1 -lib $(LIBPNG_NAME)
+ $(ADDMOD) libpng_1 -include zlibe
+
+# Define the non-shared version of libpng.
+libpng_0.dev: $(LIBPNG_MAK) $(ECHOGS_XE) $(png_1) $(png_2)\
+ zlibe.dev libpng$(PVERSION).dev
+ $(SETMOD) libpng_0 $(png_1)
+ $(ADDMOD) libpng_0 $(png_2)
+ $(ADDMOD) libpng_0 -include zlibe libpng$(PVERSION)
+
+libpng89.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ)
+ $(SETMOD) libpng89 pngwio.$(OBJ)
+
+libpng90.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng90 pngwio.$(OBJ) -include crc32
+
+libpng95.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng95 pngwio.$(OBJ) -include crc32
+
+libpng96.dev: $(LIBPNG_MAK) $(ECHOGS_XE) pngwio.$(OBJ) crc32.dev
+ $(SETMOD) libpng96 pngwio.$(OBJ) -include crc32
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for zlib library code.
+
+# This partial makefile compiles the zlib library for use in Ghostscript.
+# You can get the source code for this library from:
+# ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib104.zip (zlib 1.0.4)
+# or zlib-1.0.4.tar.gz
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+
+# Define the name of this makefile.
+ZLIB_MAK=zlib.mak
+
+# ZSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the zlib sources are stored.
+#ZSRCDIR=zlib
+ZSRC=$(ZSRCDIR)$(D)
+# We would like to define
+#CCCZ=$(CCC) -I$(ZSRCDIR) -Dverbose=-1
+# but the Watcom C compiler has strange undocumented restrictions on what can
+# follow a -D=, and it doesn't allow negative numbers. Instead, we define
+# (in gs.mak):
+#CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+# and handle the definition of verbose in a different, more awkward way.
+
+# We keep all of the zlib code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+ZDEP=$(AK)
+
+# Contrary to what some portability bigots assert as fact, C compilers are
+# not consistent about where they start searching for #included files:
+# some always start by looking in the same directory as the .c file being
+# compiled, before using the search path specified with -I on the command
+# line, while others do not do this. For this reason, we must explicitly
+# copy and then delete all the .c files, because they need to obtain our
+# modified version of zutil.h. We must also copy all header files that
+# reference zutil.h directly or indirectly.
+
+# Code common to compression and decompression.
+
+zlibc_=zutil.$(OBJ)
+zlibc.dev: $(ZLIB_MAK) $(ECHOGS_XE) $(zlibc_)
+ $(SETMOD) zlibc $(zlibc_)
+
+zutil.h: $(ZSRC)zutil.h $(ECHOGS_XE)
+ $(EXP)echogs -w zutil.h -x 23 define verbose -s - -1
+ $(EXP)echogs -a zutil.h -+R $(ZSRC)zutil.h
+
+zutil.$(OBJ): $(ZSRC)zutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)zutil.c .
+ $(CCCZ) zutil.c
+ $(RM_) zutil.c
+
+# Encoding (compression) code.
+
+deflate.h: $(ZSRC)deflate.h zutil.h
+ $(CP_) $(ZSRC)deflate.h .
+
+zlibe.dev: $(MAKEFILE) zlibe_$(SHARE_ZLIB).dev
+ $(CP_) zlibe_$(SHARE_ZLIB).dev zlibe.dev
+
+zlibe_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibe_1 -lib $(ZLIB_NAME)
+
+zlibe_=adler32.$(OBJ) deflate.$(OBJ) trees.$(OBJ)
+zlibe_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibe_)
+ $(SETMOD) zlibe_0 $(zlibe_)
+ $(ADDMOD) zlibe_0 -include zlibc
+
+adler32.$(OBJ): $(ZSRC)adler32.c $(ZDEP)
+ $(CP_) $(ZSRC)adler32.c .
+ $(CCCZ) adler32.c
+ $(RM_) adler32.c
+
+deflate.$(OBJ): $(ZSRC)deflate.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)deflate.c .
+ $(CCCZ) deflate.c
+ $(RM_) deflate.c
+
+trees.$(OBJ): $(ZSRC)trees.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)trees.c .
+ $(CCCZ) trees.c
+ $(RM_) trees.c
+
+# The zlib filters per se don't need crc32, but libpng versions starting
+# with 0.90 do.
+
+crc32.dev: $(MAKEFILE) crc32_$(SHARE_ZLIB).dev
+ $(CP_) crc32_$(SHARE_ZLIB).dev crc32.dev
+
+crc32_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) crc32_1 -lib $(ZLIB_NAME)
+
+crc32_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) crc32.$(OBJ)
+ $(SETMOD) crc32_0 crc32.$(OBJ)
+
+crc32.$(OBJ): $(ZSRC)crc32.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)crc32.c .
+ $(CCCZ) crc32.c
+ $(RM_) crc32.c
+
+# Decoding (decompression) code.
+
+zlibd.dev: $(MAKEFILE) zlibd_$(SHARE_ZLIB).dev
+ $(CP_) zlibd_$(SHARE_ZLIB).dev zlibd.dev
+
+zlibd_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibd_1 -lib $(ZLIB_NAME)
+
+zlibd1_=infblock.$(OBJ) infcodes.$(OBJ) inffast.$(OBJ)
+zlibd2_=inflate.$(OBJ) inftrees.$(OBJ) infutil.$(OBJ)
+zlibd_ = $(zlibd1_) $(zlibd2_)
+zlibd_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibd_)
+ $(SETMOD) zlibd_0 $(zlibd1_)
+ $(ADDMOD) zlibd_0 -obj $(zlibd2_)
+ $(ADDMOD) zlibd_0 -include zlibc
+
+infblock.$(OBJ): $(ZSRC)infblock.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infblock.c .
+ $(CCCZ) infblock.c
+ $(RM_) infblock.c
+
+infcodes.$(OBJ): $(ZSRC)infcodes.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infcodes.c .
+ $(CCCZ) infcodes.c
+ $(RM_) infcodes.c
+
+inffast.$(OBJ): $(ZSRC)inffast.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inffast.c .
+ $(CCCZ) inffast.c
+ $(RM_) inffast.c
+
+inflate.$(OBJ): $(ZSRC)inflate.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inflate.c .
+ $(CCCZ) inflate.c
+ $(RM_) inflate.c
+
+inftrees.$(OBJ): $(ZSRC)inftrees.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inftrees.c .
+ $(CCCZ) inftrees.c
+ $(RM_) inftrees.c
+
+infutil.$(OBJ): $(ZSRC)infutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infutil.c .
+ $(CCCZ) infutil.c
+ $(RM_) infutil.c
+# Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for device drivers.
+
+# Define the name of this makefile.
+DEVS_MAK=devs.mak
+
+###### --------------------------- Catalog -------------------------- ######
+
+# It is possible to build configurations with an arbitrary collection of
+# device drivers, although some drivers are supported only on a subset
+# of the target platforms. The currently available drivers are:
+
+# MS-DOS displays (note: not usable with Desqview/X):
+# MS-DOS EGA and VGA:
+# ega EGA (640x350, 16-color)
+# vga VGA (640x480, 16-color)
+# MS-DOS SuperVGA:
+# * ali SuperVGA using Avance Logic Inc. chipset, 256-color modes
+# * atiw ATI Wonder SuperVGA, 256-color modes
+# * s3vga SuperVGA using S3 86C911 chip (e.g., Diamond Stealth board)
+# svga16 Generic SuperVGA in 800x600, 16-color mode
+# * tseng SuperVGA using Tseng Labs ET3000/4000 chips, 256-color modes
+# * tvga SuperVGA using Trident chipset, 256-color modes
+# ****** NOTE: The vesa device does not work with the Watcom (32-bit MS-DOS)
+# ****** compiler or executable.
+# vesa SuperVGA with VESA standard API driver
+# MS-DOS other:
+# bgi Borland Graphics Interface (CGA) [MS-DMS only]
+# * herc Hercules Graphics display [MS-DOS only]
+# * pe Private Eye display
+# Other displays:
+# MS Windows:
+# mswindll Microsoft Windows 3.1 DLL [MS Windows only]
+# mswinprn Microsoft Windows 3.0, 3.1 DDB printer [MS Windows only]
+# mswinpr2 Microsoft Windows 3.0, 3.1 DIB printer [MS Windows only]
+# OS/2:
+# * os2pm OS/2 Presentation Manager [OS/2 only]
+# * os2dll OS/2 DLL bitmap [OS/2 only]
+# * os2prn OS/2 printer [OS/2 only]
+# Unix and VMS:
+# ****** NOTE: For direct frame buffer addressing under SCO Unix or Xenix,
+# ****** edit the definition of EGAVGA below.
+# * att3b1 AT&T 3b1/Unixpc monochrome display [3b1 only]
+# * lvga256 Linux vgalib, 256-color VGA modes [Linux only]
+# * sonyfb Sony Microsystems monochrome display [Sony only]
+# * sunview SunView window system [SunOS only]
+# + vgalib Linux PC with VGALIB [Linux only]
+# x11 X Windows version 11, release >=4 [Unix and VMS only]
+# x11alpha X Windows masquerading as a device with alpha capability
+# x11cmyk X Windows masquerading as a 1-bit-per-plane CMYK device
+# x11gray2 X Windows as a 2-bit gray-scale device
+# x11mono X Windows masquerading as a black-and-white device
+# Platform-independent:
+# * sxlcrt CRT sixels, e.g. for VT240-like terminals
+# Printers:
+# * ap3250 Epson AP3250 printer
+# * appledmp Apple Dot Matrix Printer (should also work with Imagewriter)
+# bj10e Canon BubbleJet BJ10e
+# * bj200 Canon BubbleJet BJ200
+# * bjc600 Canon Color BubbleJet BJC-600, BJC-4000 and BJC-70
+# also good for Apple printers like the StyleWriter 2x00
+# * bjc800 Canon Color BubbleJet BJC-800
+# * ccr CalComp Raster format
+# * cdeskjet H-P DeskJet 500C with 1 bit/pixel color
+# * cdjcolor H-P DeskJet 500C with 24 bit/pixel color and
+# high-quality color (Floyd-Steinberg) dithering;
+# also good for DeskJet 540C and Citizen Projet IIc (-r200x300)
+# * cdjmono H-P DeskJet 500C printing black only;
+# also good for DeskJet 510, 520, and 540C (black only)
+# * cdj500 H-P DeskJet 500C (same as cdjcolor)
+# * cdj550 H-P DeskJet 550C/560C/660C/660Cse
+# * cp50 Mitsubishi CP50 color printer
+# * declj250 alternate DEC LJ250 driver
+# + deskjet H-P DeskJet and DeskJet Plus
+# djet500 H-P DeskJet 500; use -r600 for DJ 600 series
+# * djet500c H-P DeskJet 500C alternate driver
+# (does not work on 550C or 560C)
+# * dnj650c H-P DesignJet 650C
+# epson Epson-compatible dot matrix printers (9- or 24-pin)
+# * eps9mid Epson-compatible 9-pin, interleaved lines
+# (intermediate resolution)
+# * eps9high Epson-compatible 9-pin, interleaved lines
+# (triple resolution)
+# * epsonc Epson LQ-2550 and Fujitsu 3400/2400/1200 color printers
+# * ibmpro IBM 9-pin Proprinter
+# * imagen Imagen ImPress printers
+# * iwhi Apple Imagewriter in high-resolution mode
+# * iwlo Apple Imagewriter in low-resolution mode
+# * iwlq Apple Imagewriter LQ in 320 x 216 dpi mode
+# * jetp3852 IBM Jetprinter ink-jet color printer (Model #3852)
+# + laserjet H-P LaserJet
+# * la50 DEC LA50 printer
+# * la70 DEC LA70 printer
+# * la70t DEC LA70 printer with low-resolution text enhancement
+# * la75 DEC LA75 printer
+# * la75plus DEC LA75plus printer
+# * lbp8 Canon LBP-8II laser printer
+# * lips3 Canon LIPS III laser printer in English (CaPSL) mode
+# * ln03 DEC LN03 printer
+# * lj250 DEC LJ250 Companion color printer
+# + ljet2p H-P LaserJet IId/IIp/III* with TIFF compression
+# + ljet3 H-P LaserJet III* with Delta Row compression
+# + ljet3d H-P LaserJet IIID with duplex capability
+# + ljet4 H-P LaserJet 4 (defaults to 600 dpi)
+# + lj4dith H-P LaserJet 4 with Floyd-Steinberg dithering
+# + ljetplus H-P LaserJet Plus
+# lj5mono H-P LaserJet 5 & 6 family (PCL XL), bitmap:
+# see below for restrictions & advice
+# lj5gray H-P LaserJet 5 & 6 family, gray-scale bitmap;
+# see below for restrictions & advice
+# * lp2563 H-P 2563B line printer
+# * lp8000 Epson LP-8000 laser printer
+# * lq850 Epson LQ850 printer at 360 x 360 DPI resolution;
+# also good for Canon BJ300 with LQ850 emulation
+# * m8510 C.Itoh M8510 printer
+# * necp6 NEC P6/P6+/P60 printers at 360 x 360 DPI resolution
+# * nwp533 Sony Microsystems NWP533 laser printer [Sony only]
+# * oce9050 OCE 9050 printer
+# * oki182 Okidata MicroLine 182
+# * okiibm Okidata MicroLine IBM-compatible printers
+# * paintjet alternate H-P PaintJet color printer
+# * pj H-P PaintJet XL driver
+# * pjetxl alternate H-P PaintJet XL driver
+# * pjxl H-P PaintJet XL color printer
+# * pjxl300 H-P PaintJet XL300 color printer;
+# also good for PaintJet 1200C
+# (pxlmono) H-P black-and-white PCL XL printers (LaserJet 5 and 6 family)
+# (pxlcolor) H-P color PCL XL printers (none available yet)
+# * r4081 Ricoh 4081 laser printer
+# * sj48 StarJet 48 inkjet printer
+# * sparc SPARCprinter
+# * st800 Epson Stylus 800 printer
+# * stcolor Epson Stylus Color
+# * t4693d2 Tektronix 4693d color printer, 2 bits per R/G/B component
+# * t4693d4 Tektronix 4693d color printer, 4 bits per R/G/B component
+# * t4693d8 Tektronix 4693d color printer, 8 bits per R/G/B component
+# * tek4696 Tektronix 4695/4696 inkjet plotter
+# * uniprint Unified printer driver -- Configurable Color ESC/P-,
+# ESC/P2-, HP-RTL/PCL mono/color driver
+# * xes Xerox XES printers (2700, 3700, 4045, etc.)
+# Fax systems:
+# * dfaxhigh DigiBoard, Inc.'s DigiFAX software format (high resolution)
+# * dfaxlow DigiFAX low (normal) resolution
+# Fax file format:
+# ****** NOTE: all of these drivers adjust the page size to match
+# ****** one of the three CCITT standard sizes (U.S. letter with A4 width,
+# ****** A4, or B4).
+# faxg3 Group 3 fax, with EOLs but no header or EOD
+# faxg32d Group 3 2-D fax, with EOLs but no header or EOD
+# faxg4 Group 4 fax, with EOLs but no header or EOD
+# tiffcrle TIFF "CCITT RLE 1-dim" (= Group 3 fax with no EOLs)
+# tiffg3 TIFF Group 3 fax (with EOLs)
+# tiffg32d TIFF Group 3 2-D fax
+# tiffg4 TIFF Group 4 fax
+# High-level file formats:
+# epswrite EPS output (like PostScript Distillery)
+# pdfwrite PDF output (like Adobe Acrobat Distiller)
+# pswrite PostScript output (like PostScript Distillery)
+# pxlmono Black-and-white PCL XL
+# pxlcolor Color PCL XL
+# Other raster file formats and devices:
+# bit Plain bits, monochrome
+# bitrgb Plain bits, RGB
+# bitcmyk Plain bits, CMYK
+# bmpmono Monochrome MS Windows .BMP file format
+# bmp16 4-bit (EGA/VGA) .BMP file format
+# bmp256 8-bit (256-color) .BMP file format
+# bmp16m 24-bit .BMP file format
+# cgmmono Monochrome (black-and-white) CGM -- LOW LEVEL OUTPUT ONLY
+# cgm8 8-bit (256-color) CGM -- DITTO
+# cgm24 24-bit color CGM -- DITTO
+# * cif CIF file format for VLSI
+# jpeg JPEG format, RGB output
+# jpeggray JPEG format, gray output
+# miff24 ImageMagick MIFF format, 24-bit direct color, RLE compressed
+# * mgrmono 1-bit monochrome MGR devices
+# * mgrgray2 2-bit gray scale MGR devices
+# * mgrgray4 4-bit gray scale MGR devices
+# * mgrgray8 8-bit gray scale MGR devices
+# * mgr4 4-bit (VGA) color MGR devices
+# * mgr8 8-bit color MGR devices
+# pcxmono PCX file format, monochrome (1-bit black and white)
+# pcxgray PCX file format, 8-bit gray scale
+# pcx16 PCX file format, 4-bit planar (EGA/VGA) color
+# pcx256 PCX file format, 8-bit chunky color
+# pcx24b PCX file format, 24-bit color (3 8-bit planes)
+# pcxcmyk PCX file format, 4-bit chunky CMYK color
+# pbm Portable Bitmap (plain format)
+# pbmraw Portable Bitmap (raw format)
+# pgm Portable Graymap (plain format)
+# pgmraw Portable Graymap (raw format)
+# pgnm Portable Graymap (plain format), optimizing to PBM if possible
+# pgnmraw Portable Graymap (raw format), optimizing to PBM if possible
+# pnm Portable Pixmap (plain format) (RGB), optimizing to PGM or PBM
+# if possible
+# pnmraw Portable Pixmap (raw format) (RGB), optimizing to PGM or PBM
+# if possible
+# ppm Portable Pixmap (plain format) (RGB)
+# ppmraw Portable Pixmap (raw format) (RGB)
+# pkm Portable inKmap (plain format) (4-bit CMYK => RGB)
+# pkmraw Portable inKmap (raw format) (4-bit CMYK => RGB)
+# pngmono Monochrome Portable Network Graphics (PNG)
+# pnggray 8-bit gray Portable Network Graphics (PNG)
+# png16 4-bit color Portable Network Graphics (PNG)
+# png256 8-bit color Portable Network Graphics (PNG)
+# png16m 24-bit color Portable Network Graphics (PNG)
+# psmono PostScript (Level 1) monochrome image
+# psgray PostScript (Level 1) 8-bit gray image
+# sgirgb SGI RGB pixmap format
+# tiff12nc TIFF 12-bit RGB, no compression
+# tiff24nc TIFF 24-bit RGB, no compression (NeXT standard format)
+# tifflzw TIFF LZW (tag = 5) (monochrome)
+# tiffpack TIFF PackBits (tag = 32773) (monochrome)
+
+# User-contributed drivers marked with * require hardware or software
+# that is not available to Aladdin Enterprises. Please contact the
+# original contributors, not Aladdin Enterprises, if you have questions.
+# Contact information appears in the driver entry below.
+#
+# Drivers marked with a + are maintained by Aladdin Enterprises with
+# the assistance of users, since Aladdin Enterprises doesn't have access to
+# the hardware for these either.
+
+# If you add drivers, it would be nice if you kept each list
+# in alphabetical order.
+
+###### ----------------------- End of catalog ----------------------- ######
+
+# As noted in gs.mak, DEVICE_DEVS and DEVICE_DEVS1..15 select the devices
+# that should be included in a given configuration. By convention, these
+# are used as follows. Each of these must be limited to about 10 devices
+# so as not to overflow the 120 character limit on MS-DOS command lines.
+# DEVICE_DEVS - the default device, and any display devices.
+# DEVICE_DEVS1 - additional display devices if needed.
+# DEVICE_DEVS2 - dot matrix printers.
+# DEVICE_DEVS3 - H-P monochrome printers.
+# DEVICE_DEVS4 - H-P color printers.
+# DEVICE_DEVS5 - additional H-P printers if needed.
+# DEVICE_DEVS6 - other ink-jet and laser printers.
+# DEVICE_DEVS7 - fax file formats.
+# DEVICE_DEVS8 - PCX file formats.
+# DEVICE_DEVS9 - PBM/PGM/PPM file formats.
+# DEVICE_DEVS10 - black-and-white TIFF file formats.
+# DEVICE_DEVS11 - BMP and color TIFF file formats.
+# DEVICE_DEVS12 - PostScript image and 'bit' file formats.
+# DEVICE_DEVS13 - PNG file formats.
+# DEVICE_DEVS14 - CGM, JPEG, and MIFF file formats.
+# DEVICE_DEVS15 - high-level (PostScript and PDF) file formats.
+# Feel free to disregard this convention if it gets in your way.
+
+# If you want to add a new device driver, the examples below should be
+# enough of a guide to the correct form for the makefile rules.
+# Note that all drivers other than displays must include page.dev in their
+# dependencies and use $(SETPDEV) rather than $(SETDEV) in their rule bodies.
+
+# All device drivers depend on the following:
+GDEV=$(AK) $(ECHOGS_XE) $(gserrors_h) $(gx_h) $(gxdevice_h)
+
+# "Printer" drivers depend on the following:
+PDEVH=$(AK) $(gdevprn_h)
+
+# Define the header files for device drivers. Every header file used by
+# more than one device driver family must be listed here.
+gdev8bcm_h=gdev8bcm.h
+gdevpccm_h=gdevpccm.h
+gdevpcfb_h=gdevpcfb.h $(dos__h)
+gdevpcl_h=gdevpcl.h
+gdevsvga_h=gdevsvga.h
+gdevx_h=gdevx.h
+
+###### ----------------------- Device support ----------------------- ######
+
+# Provide a mapping between StandardEncoding and ISOLatin1Encoding.
+gdevemap.$(OBJ): gdevemap.c $(AK) $(std_h)
+
+# Implement dynamic color management for 8-bit mapped color displays.
+gdev8bcm.$(OBJ): gdev8bcm.c $(AK) \
+ $(gx_h) $(gxdevice_h) $(gdev8bcm_h)
+
+###### ------------------- MS-DOS display devices ------------------- ######
+
+# There are really only three drivers: an EGA/VGA driver (4 bit-planes,
+# plane-addressed), a SuperVGA driver (8 bit-planes, byte addressed),
+# and a special driver for the S3 chip.
+
+# PC display color mapping
+gdevpccm.$(OBJ): gdevpccm.c $(AK) \
+ $(gx_h) $(gsmatrix_h) $(gxdevice_h) $(gdevpccm_h)
+
+### ----------------------- EGA and VGA displays ----------------------- ###
+
+# The shared MS-DOS makefile defines PCFBASM as either gdevegaa.$(OBJ)
+# or an empty string.
+
+gdevegaa.$(OBJ): gdevegaa.asm
+
+# NOTE: for direct frame buffer addressing under SCO Unix or Xenix,
+# change gdevevga to gdevsco in the following line. Also, since
+# SCO's /bin/as does not support the "out" instructions, you must build
+# the gnu assembler and have it on your path as "as".
+EGAVGA=gdevevga.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+#EGAVGA=gdevsco.$(OBJ) gdevpcfb.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevevga.$(OBJ): gdevevga.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+ $(CCD) gdevevga.c
+
+gdevsco.$(OBJ): gdevsco.c $(GDEV) $(memory__h) $(gdevpcfb_h)
+
+# Common code for MS-DOS and SCO.
+gdevpcfb.$(OBJ): gdevpcfb.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gdevpccm_h) $(gdevpcfb_h) $(gsparam_h)
+ $(CCD) gdevpcfb.c
+
+# The EGA/VGA family includes EGA and VGA. Many SuperVGAs in 800x600,
+# 16-color mode can share the same code; see the next section below.
+
+ega.dev: $(EGAVGA)
+ $(SETDEV) ega $(EGAVGA)
+
+vga.dev: $(EGAVGA)
+ $(SETDEV) vga $(EGAVGA)
+
+### ------------------------- SuperVGA displays ------------------------ ###
+
+# SuperVGA displays in 16-color, 800x600 mode are really just slightly
+# glorified VGA's, so we can handle them all with a single driver.
+# The way to select them on the command line is with
+# -sDEVICE=svga16 -dDisplayMode=NNN
+# where NNN is the display mode in decimal. See use.txt for the modes
+# for some popular display chipsets.
+
+svga16.dev: $(EGAVGA)
+ $(SETDEV) svga16 $(EGAVGA)
+
+# More capable SuperVGAs have a wide variety of slightly differing
+# interfaces, so we need a separate driver for each one.
+
+SVGA=gdevsvga.$(OBJ) gdevpccm.$(OBJ) $(PCFBASM)
+
+gdevsvga.$(OBJ): gdevsvga.c $(GDEV) $(memory__h) $(gconfigv_h)\
+ $(gsparam_h) $(gxarith_h) $(gdevpccm_h) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevsvga.c
+
+# The SuperVGA family includes: Avance Logic Inc., ATI Wonder, S3,
+# Trident, Tseng ET3000/4000, and VESA.
+
+ali.dev: $(SVGA)
+ $(SETDEV) ali $(SVGA)
+
+atiw.dev: $(SVGA)
+ $(SETDEV) atiw $(SVGA)
+
+tseng.dev: $(SVGA)
+ $(SETDEV) tseng $(SVGA)
+
+tvga.dev: $(SVGA)
+ $(SETDEV) tvga $(SVGA)
+
+vesa.dev: $(SVGA)
+ $(SETDEV) vesa $(SVGA)
+
+# The S3 driver doesn't share much code with the others.
+
+s3vga_=gdevs3ga.$(OBJ) gdevsvga.$(OBJ) gdevpccm.$(OBJ)
+s3vga.dev: $(SVGA) $(s3vga_)
+ $(SETDEV) s3vga $(SVGA)
+ $(ADDMOD) s3vga -obj $(s3vga_)
+
+gdevs3ga.$(OBJ): gdevs3ga.c $(GDEV) $(gdevpcfb_h) $(gdevsvga_h)
+ $(CCD) gdevs3ga.c
+
+### ------------ The BGI (Borland Graphics Interface) device ----------- ###
+
+cgaf.$(OBJ): $(BGIDIR)\cga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\cga
+
+egavgaf.$(OBJ): $(BGIDIR)\egavga.bgi
+ $(BGIDIR)\bgiobj /F $(BGIDIR)\egavga
+
+# Include egavgaf.$(OBJ) for debugging only.
+bgi_=gdevbgi.$(OBJ) cgaf.$(OBJ)
+bgi.dev: $(bgi_)
+ $(SETDEV) bgi $(bgi_)
+ $(ADDMOD) bgi -lib $(LIBDIR)\graphics
+
+gdevbgi.$(OBJ): gdevbgi.c $(GDEV) $(MAKEFILE) $(gxxfont_h)
+ $(CCC) -DBGI_LIB="$(BGIDIRSTR)" gdevbgi.c
+
+### ------------------- The Hercules Graphics display ------------------- ###
+
+herc_=gdevherc.$(OBJ)
+herc.dev: $(herc_)
+ $(SETDEV) herc $(herc_)
+
+gdevherc.$(OBJ): gdevherc.c $(GDEV) $(dos__h) $(gsmatrix_h) $(gxbitmap_h)
+ $(CCC) gdevherc.c
+
+### ---------------------- The Private Eye display ---------------------- ###
+### Note: this driver was contributed by a user: ###
+### please contact narf@media-lab.media.mit.edu if you have questions. ###
+
+pe_=gdevpe.$(OBJ)
+pe.dev: $(pe_)
+ $(SETDEV) pe $(pe_)
+
+gdevpe.$(OBJ): gdevpe.c $(GDEV) $(memory__h)
+
+###### ----------------------- Other displays ------------------------ ######
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gsdll_h=gsdll.h
+
+gdevmswn_h=gdevmswn.h $(GDEV)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ gp_mswin.h
+
+gdevmswn.$(OBJ): gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h) \
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(CCCWIN) gdevmswn.c
+
+gdevmsxf.$(OBJ): gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCCWIN) gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+gdevwdib.$(OBJ): gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(CCCWIN) gdevwdib.c
+
+mswindll_=gdevmswn.$(OBJ) gdevmsxf.$(OBJ) gdevwdib.$(OBJ) \
+ gdevemap.$(OBJ) gdevpccm.$(OBJ)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=gdevwprn.$(OBJ) gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+gdevwprn.$(OBJ): gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(CCCWIN) gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+gdevwpr2.$(OBJ): gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) gp_mswin.h
+ $(CCCWIN) gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=gdevpm.$(OBJ) gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+gdevpm.$(OBJ): gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) gdevpm.h
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+os2prn.$(OBJ): os2prn.c $(gp_h)
+
+### -------------- The AT&T 3b1 Unixpc monochrome display --------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Andy Fyfe (andy@cs.caltech.edu) if you have questions. ###
+
+att3b1_=gdev3b1.$(OBJ)
+att3b1.dev: $(att3b1_)
+ $(SETDEV) att3b1 $(att3b1_)
+
+gdev3b1.$(OBJ): gdev3b1.c $(GDEV)
+
+### ---------------------- Linux PC with vgalib ------------------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the lvga256 driver, please contact ###
+### Ludger Kunz (ludger.kunz@fernuni-hagen.de). ###
+### For questions about the vgalib driver, please contact ###
+### Erik Talvola (talvola@gnu.ai.mit.edu). ###
+
+lvga256_=gdevl256.$(OBJ)
+lvga256.dev: $(lvga256_)
+ $(SETDEV) lvga256 $(lvga256_)
+ $(ADDMOD) lvga256 -lib vga vgagl
+
+gdevl256.$(OBJ): gdevl256.c $(GDEV)
+
+vgalib_=gdevvglb.$(OBJ) gdevpccm.$(OBJ)
+vgalib.dev: $(vgalib_)
+ $(SETDEV) vgalib $(vgalib_)
+ $(ADDMOD) vgalib -lib vga
+
+gdevvglb.$(OBJ): gdevvglb.c $(GDEV) $(gdevpccm_h) $(gsparam_h)
+
+### ------------------- Sony NeWS frame buffer device ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Mike Smolenski (mike@intertech.com) if you have questions. ###
+
+# This is implemented as a 'printer' device.
+sonyfb_=gdevsnfb.$(OBJ)
+sonyfb.dev: $(sonyfb_) page.dev
+ $(SETPDEV) sonyfb $(sonyfb_)
+
+gdevsnfb.$(OBJ): gdevsnfb.c $(PDEVH)
+
+### ------------------------ The SunView device ------------------------ ###
+### Note: this driver is maintained by a user: if you have questions, ###
+### please contact Andreas Stolcke (stolcke@icsi.berkeley.edu). ###
+
+sunview_=gdevsun.$(OBJ)
+sunview.dev: $(sunview_)
+ $(SETDEV) sunview $(sunview_)
+ $(ADDMOD) sunview -lib suntool sunwindow pixrect
+
+gdevsun.$(OBJ): gdevsun.c $(GDEV) $(malloc__h)\
+ $(gscdefs_h) $(gserrors_h) $(gsmatrix_h)
+
+### -------------------------- The X11 device -------------------------- ###
+
+# Aladdin Enterprises does not support Ghostview. For more information
+# about Ghostview, please contact Tim Theisen (ghostview@cs.wisc.edu).
+
+# See the main makefile for the definition of XLIBS.
+x11_=gdevx.$(OBJ) gdevxini.$(OBJ) gdevxxf.$(OBJ) gdevemap.$(OBJ)
+x11.dev: $(x11_)
+ $(SETDEV) x11 $(x11_)
+ $(ADDMOD) x11 -lib $(XLIBS)
+
+# See the main makefile for the definition of XINCLUDE.
+GDEVX=$(GDEV) x_.h gdevx.h $(MAKEFILE)
+gdevx.$(OBJ): gdevx.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevx.c
+
+gdevxini.$(OBJ): gdevxini.c $(GDEVX) $(math__h) $(memory__h) $(gserrors_h)
+ $(CCC) $(XINCLUDE) gdevxini.c
+
+gdevxxf.$(OBJ): gdevxxf.c $(GDEVX) $(math__h) $(memory__h)\
+ $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(CCC) $(XINCLUDE) gdevxxf.c
+
+# Alternate X11-based devices to help debug other drivers.
+# x11alpha pretends to have 4 bits of alpha channel.
+# x11cmyk pretends to be a CMYK device with 1 bit each of C,M,Y,K.
+# x11gray2 pretends to be a 2-bit gray-scale device.
+# x11mono pretends to be a black-and-white device.
+x11alt_=$(x11_) gdevxalt.$(OBJ)
+x11alpha.dev: $(x11alt_)
+ $(SETDEV) x11alpha $(x11alt_)
+ $(ADDMOD) x11alpha -lib $(XLIBS)
+
+x11cmyk.dev: $(x11alt_)
+ $(SETDEV) x11cmyk $(x11alt_)
+ $(ADDMOD) x11cmyk -lib $(XLIBS)
+
+x11gray2.dev: $(x11alt_)
+ $(SETDEV) x11gray2 $(x11alt_)
+ $(ADDMOD) x11gray2 -lib $(XLIBS)
+
+x11mono.dev: $(x11alt_)
+ $(SETDEV) x11mono $(x11alt_)
+ $(ADDMOD) x11mono -lib $(XLIBS)
+
+gdevxalt.$(OBJ): gdevxalt.c $(GDEVX) $(math__h) $(memory__h) $(gsparam_h)
+ $(CCC) $(XINCLUDE) gdevxalt.c
+
+### ------------------------- DEC sixel displays ------------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Phil Keegstra (keegstra@tonga.gsfc.nasa.gov) if you have questions. ###
+
+# This is a "printer" device, but it probably shouldn't be.
+# I don't know why the implementor chose to do it this way.
+sxlcrt_=gdevln03.$(OBJ)
+sxlcrt.dev: $(sxlcrt_) page.dev
+ $(SETPDEV) sxlcrt $(sxlcrt_)
+
+###### --------------- Memory-buffered printer devices --------------- ######
+
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users. ###
+### If you have questions about the DMP driver, please contact ###
+### Mark Wedel (master@cats.ucsc.edu). ###
+### If you have questions about the Imagewriter drivers, please contact ###
+### Jonathan Luckey (luckey@rtfm.mlb.fl.us). ###
+### If you have questions about the Imagewriter LQ driver, please ###
+### contact Scott Barker (barkers@cuug.ab.ca). ###
+
+appledmp_=gdevadmp.$(OBJ)
+
+gdevadmp.$(OBJ): gdevadmp.c $(PDEVH)
+
+appledmp.dev: $(appledmp_) page.dev
+ $(SETPDEV) appledmp $(appledmp_)
+
+iwhi.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwhi $(appledmp_)
+
+iwlo.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlo $(appledmp_)
+
+iwlq.dev: $(appledmp_) page.dev
+ $(SETPDEV) iwlq $(appledmp_)
+
+### ------------ The Canon BubbleJet BJ10e and BJ200 devices ------------ ###
+
+bj10e_=gdevbj10.$(OBJ)
+
+bj10e.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj10e $(bj10e_)
+
+bj200.dev: $(bj10e_) page.dev
+ $(SETPDEV) bj200 $(bj10e_)
+
+gdevbj10.$(OBJ): gdevbj10.c $(PDEVH)
+
+### ------------- The CalComp Raster Format ----------------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Ernst Muellner (ernst.muellner@oenzl.siemens.de) if you have ###
+### questions. ###
+
+ccr_=gdevccr.$(OBJ)
+ccr.dev: $(ccr_) page.dev
+ $(SETPDEV) ccr $(ccr_)
+
+gdevccr.$(OBJ): gdevccr.c $(PDEVH)
+
+### ----------- The H-P DeskJet and LaserJet printer devices ----------- ###
+
+### These are essentially the same device.
+### NOTE: printing at full resolution (300 DPI) requires a printer
+### with at least 1.5 Mb of memory. 150 DPI only requires .5 Mb.
+### Note that the lj4dith driver is included with the H-P color printer
+### drivers below.
+
+HPPCL=gdevpcl.$(OBJ)
+HPMONO=gdevdjet.$(OBJ) $(HPPCL)
+
+gdevpcl.$(OBJ): gdevpcl.c $(PDEVH) $(gdevpcl_h)
+
+gdevdjet.$(OBJ): gdevdjet.c $(PDEVH) $(gdevpcl_h)
+
+deskjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) deskjet $(HPMONO)
+
+djet500.dev: $(HPMONO) page.dev
+ $(SETPDEV) djet500 $(HPMONO)
+
+laserjet.dev: $(HPMONO) page.dev
+ $(SETPDEV) laserjet $(HPMONO)
+
+ljetplus.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljetplus $(HPMONO)
+
+### Selecting ljet2p provides TIFF (mode 2) compression on LaserJet III,
+### IIIp, IIId, IIIsi, IId, and IIp.
+
+ljet2p.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet2p $(HPMONO)
+
+### Selecting ljet3 provides Delta Row (mode 3) compression on LaserJet III,
+### IIIp, IIId, IIIsi.
+
+ljet3.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3 $(HPMONO)
+
+### Selecting ljet3d also provides duplex printing capability.
+
+ljet3d.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet3d $(HPMONO)
+
+### Selecting ljet4 also provides Delta Row compression on LaserJet IV series.
+
+ljet4.dev: $(HPMONO) page.dev
+ $(SETPDEV) ljet4 $(HPMONO)
+
+lp2563.dev: $(HPMONO) page.dev
+ $(SETPDEV) lp2563 $(HPMONO)
+
+oce9050.dev: $(HPMONO) page.dev
+ $(SETPDEV) oce9050 $(HPMONO)
+
+### ------------------ The H-P LaserJet 5 and 6 devices ----------------- ###
+
+### These drivers use H-P's new PCL XL printer language, like H-P's
+### LaserJet 5 Enhanced driver for MS Windows. We don't recommend using
+### them:
+### - If you have a LJ 5L or 5P, which isn't a "real" LaserJet 5,
+### use the ljet4 driver instead. (The lj5 drivers won't work.)
+### - If you have any other model of LJ 5 or 6, use the pxlmono
+### driver, which often produces much more compact output.
+
+gdevpxat_h=gdevpxat.h
+gdevpxen_h=gdevpxen.h
+gdevpxop_h=gdevpxop.h
+
+ljet5_=gdevlj56.$(OBJ) $(HPPCL)
+lj5mono.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5mono $(ljet5_)
+
+lj5gray.dev: $(ljet5_) page.dev
+ $(SETPDEV) lj5gray $(ljet5_)
+
+gdevlj56.$(OBJ): gdevlj56.c $(PDEVH) $(gdevpcl_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h)
+
+### The H-P DeskJet, PaintJet, and DesignJet family color printer devices.###
+### Note: there are two different 500C drivers, both contributed by users.###
+### If you have questions about the djet500c driver, ###
+### please contact AKayser@et.tudelft.nl. ###
+### If you have questions about the cdj* drivers, ###
+### please contact g.cameron@biomed.abdn.ac.uk. ###
+### If you have questions about the dnj560c driver, ###
+### please contact koert@zen.cais.com. ###
+### If you have questions about the lj4dith driver, ###
+### please contact Eckhard.Rueggeberg@ts.go.dlr.de. ###
+### If you have questions about the BJC600/BJC4000, BJC800, or ESCP ###
+### drivers, please contact Yves.Arrouye@imag.fr. ###
+
+cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+cdeskjet.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdeskjet $(cdeskjet_)
+
+cdjcolor.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjcolor $(cdeskjet_)
+
+cdjmono.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdjmono $(cdeskjet_)
+
+cdj500.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj500 $(cdeskjet_)
+
+cdj550.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) cdj550 $(cdeskjet_)
+
+declj250.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) declj250 $(cdeskjet_)
+
+dnj650c.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) dnj650c $(cdeskjet_)
+
+lj4dith.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) lj4dith $(cdeskjet_)
+
+pj.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pj $(cdeskjet_)
+
+pjxl.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl $(cdeskjet_)
+
+pjxl300.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) pjxl300 $(cdeskjet_)
+
+# Note: the BJC600 driver also works for the BJC4000.
+bjc600.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc600 $(cdeskjet_)
+
+bjc800.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) bjc800 $(cdeskjet_)
+
+escp.dev: $(cdeskjet_) page.dev
+ $(SETPDEV) escp $(cdeskjet_)
+
+# NB: you can also customise the build if required, using
+# -DBitsPerPixel=<number> if you wish the default to be other than 24
+# for the generic drivers (cdj500, cdj550, pjxl300, pjtest, pjxltest).
+gdevcdj.$(OBJ): gdevcdj.c $(std_h) $(PDEVH) gdevbjc.h\
+ $(gsparam_h) $(gsstate_h) $(gxlum_h)\
+ $(gdevpcl_h)
+
+djet500c_=gdevdjtc.$(OBJ) $(HPPCL)
+djet500c.dev: $(djet500c_) page.dev
+ $(SETPDEV) djet500c $(djet500c_)
+
+gdevdjtc.$(OBJ): gdevdjtc.c $(PDEVH) $(malloc__h) $(gdevpcl_h)
+
+### -------------------- The Mitsubishi CP50 printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Michael Hu (michael@ximage.com) if you have questions. ###
+
+cp50_=gdevcp50.$(OBJ)
+cp50.dev: $(cp50_) page.dev
+ $(SETPDEV) cp50 $(cp50_)
+
+gdevcp50.$(OBJ): gdevcp50.c $(PDEVH)
+
+### ----------------- The generic Epson printer device ----------------- ###
+### Note: most of this code was contributed by users. Please contact ###
+### the following people if you have questions: ###
+### eps9mid - Guenther Thomsen (thomsen@cs.tu-berlin.de) ###
+### eps9high - David Wexelblat (dwex@mtgzfs3.att.com) ###
+### ibmpro - James W. Birdsall (jwbirdsa@picarefy.picarefy.com) ###
+
+epson_=gdevepsn.$(OBJ)
+
+epson.dev: $(epson_) page.dev
+ $(SETPDEV) epson $(epson_)
+
+eps9mid.dev: $(epson_) page.dev
+ $(SETPDEV) eps9mid $(epson_)
+
+eps9high.dev: $(epson_) page.dev
+ $(SETPDEV) eps9high $(epson_)
+
+gdevepsn.$(OBJ): gdevepsn.c $(PDEVH)
+
+### ----------------- The IBM Proprinter printer device ---------------- ###
+
+ibmpro.dev: $(epson_) page.dev
+ $(SETPDEV) ibmpro $(epson_)
+
+### -------------- The Epson LQ-2550 color printer device -------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Dave St. Clair (dave@exlog.com) if you have questions. ###
+
+epsonc_=gdevepsc.$(OBJ)
+epsonc.dev: $(epsonc_) page.dev
+ $(SETPDEV) epsonc $(epsonc_)
+
+gdevepsc.$(OBJ): gdevepsc.c $(PDEVH)
+
+### ------------- The Epson ESC/P 2 language printer devices ------------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about the Stylus 800 and AP3250 drivers, please contact ###
+### Richard Brown (rab@tauon.ph.unimelb.edu.au). ###
+### For questions about the Stylus Color drivers, please contact ###
+### Gunther Hess (gunther@elmos.de). ###
+
+ESCP2=gdevescp.$(OBJ)
+
+gdevescp.$(OBJ): gdevescp.c $(PDEVH)
+
+ap3250.dev: $(ESCP2) page.dev
+ $(SETPDEV) ap3250 $(ESCP2)
+
+st800.dev: $(ESCP2) page.dev
+ $(SETPDEV) st800 $(ESCP2)
+
+stcolor1_=gdevstc.$(OBJ) gdevstc1.$(OBJ) gdevstc2.$(OBJ)
+stcolor2_=gdevstc3.$(OBJ) gdevstc4.$(OBJ)
+stcolor.dev: $(stcolor1_) $(stcolor2_) page.dev
+ $(SETPDEV) stcolor $(stcolor1_)
+ $(ADDMOD) stcolor -obj $(stcolor2_)
+
+gdevstc.$(OBJ): gdevstc.c gdevstc.h $(PDEVH)
+
+gdevstc1.$(OBJ): gdevstc1.c gdevstc.h $(PDEVH)
+
+gdevstc2.$(OBJ): gdevstc2.c gdevstc.h $(PDEVH)
+
+gdevstc3.$(OBJ): gdevstc3.c gdevstc.h $(PDEVH)
+
+gdevstc4.$(OBJ): gdevstc4.c gdevstc.h $(PDEVH)
+
+### --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+### For questions about this driver, please contact: ###
+### Gunther Hess (gunther@elmos.de) ###
+
+uniprint_=gdevupd.$(OBJ)
+uniprint.dev: $(uniprint_) page.dev
+ $(SETPDEV) uniprint $(uniprint_)
+
+gdevupd.$(OBJ): gdevupd.c $(PDEVH) $(gsparam_h)
+
+### -------------- cdj850 - HP 850c Driver under development ------------- ###
+### Since this driver is in the development-phase it is not distributed ###
+### with ghostscript, but it is available via anonymous ftp from: ###
+### ftp://bonk.ethz.ch ###
+### For questions about this driver, please contact: ###
+### Uli Wortmann (E-Mail address inside the driver-package) ###
+
+cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+cdj850.dev: $(cdeskjet8_) page.dev
+ $(SETPDEV) cdj850 $(cdeskjet8_)
+
+### ------------ The H-P PaintJet color printer device ----------------- ###
+### Note: this driver also supports the DEC LJ250 color printer, which ###
+### has a PaintJet-compatible mode, and the PaintJet XL. ###
+### If you have questions about the XL, please contact Rob Reiss ###
+### (rob@moray.berkeley.edu). ###
+
+PJET=gdevpjet.$(OBJ) $(HPPCL)
+
+gdevpjet.$(OBJ): gdevpjet.c $(PDEVH) $(gdevpcl_h)
+
+lj250.dev: $(PJET) page.dev
+ $(SETPDEV) lj250 $(PJET)
+
+paintjet.dev: $(PJET) page.dev
+ $(SETPDEV) paintjet $(PJET)
+
+pjetxl.dev: $(PJET) page.dev
+ $(SETPDEV) pjetxl $(PJET)
+
+### -------------- Imagen ImPress Laser Printer device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Alan Millar (AMillar@bolis.sf-bay.org) if you have questions. ###
+### Set USE_BYTE_STREAM if using parallel interface; ###
+### Don't set it if using 'ipr' spooler (default). ###
+### You may also add -DA4 if needed for A4 paper. ###
+
+imagen_=gdevimgn.$(OBJ)
+imagen.dev: $(imagen_) page.dev
+ $(SETPDEV) imagen $(imagen_)
+
+gdevimgn.$(OBJ): gdevimgn.c $(PDEVH)
+ $(CCC) gdevimgn.c # for ipr spooler
+# $(CCC) -DUSE_BYTE_STREAM gdevimgn.c # for parallel
+
+### ------- The IBM 3852 JetPrinter color inkjet printer device -------- ###
+### Note: this driver was contributed by users: please contact ###
+### Kevin Gift (kgift@draper.com) if you have questions. ###
+### Note that the paper size that can be addressed by the graphics mode ###
+### used in this driver is fixed at 7-1/2 inches wide (the printable ###
+### width of the jetprinter itself.) ###
+
+jetp3852_=gdev3852.$(OBJ)
+jetp3852.dev: $(jetp3852_) page.dev
+ $(SETPDEV) jetp3852 $(jetp3852_)
+
+gdev3852.$(OBJ): gdev3852.c $(PDEVH) $(gdevpcl_h)
+
+### ---------- The Canon LBP-8II and LIPS III printer devices ---------- ###
+### Note: these drivers were contributed by users. ###
+### For questions about these drivers, please contact ###
+### Lauri Paatero, lauri.paatero@paatero.pp.fi ###
+
+lbp8_=gdevlbp8.$(OBJ)
+lbp8.dev: $(lbp8_) page.dev
+ $(SETPDEV) lbp8 $(lbp8_)
+
+lips3.dev: $(lbp8_) page.dev
+ $(SETPDEV) lips3 $(lbp8_)
+
+gdevlbp8.$(OBJ): gdevlbp8.c $(PDEVH)
+
+### ----------- The DEC LN03/LA50/LA70/LA75 printer devices ------------ ###
+### Note: this driver was contributed by users: please contact ###
+### Ulrich Mueller (ulm@vsnhd1.cern.ch) if you have questions. ###
+### For questions about LA50 and LA75, please contact ###
+### Ian MacPhedran (macphed@dvinci.USask.CA). ###
+### For questions about the LA70, please contact ###
+### Bruce Lowekamp (lowekamp@csugrad.cs.vt.edu). ###
+### For questions about the LA75plus, please contact ###
+### Andre' Beck (Andre_Beck@IRS.Inf.TU-Dresden.de). ###
+
+ln03_=gdevln03.$(OBJ)
+ln03.dev: $(ln03_) page.dev
+ $(SETPDEV) ln03 $(ln03_)
+
+la50.dev: $(ln03_) page.dev
+ $(SETPDEV) la50 $(ln03_)
+
+la70.dev: $(ln03_) page.dev
+ $(SETPDEV) la70 $(ln03_)
+
+la75.dev: $(ln03_) page.dev
+ $(SETPDEV) la75 $(ln03_)
+
+la75plus.dev: $(ln03_) page.dev
+ $(SETPDEV) la75plus $(ln03_)
+
+gdevln03.$(OBJ): gdevln03.c $(PDEVH)
+
+# LA70 driver with low-resolution text enhancement.
+
+la70t_=gdevla7t.$(OBJ)
+la70t.dev: $(la70t_) page.dev
+ $(SETPDEV) la70t $(la70t_)
+
+gdevla7t.$(OBJ): gdevla7t.c $(PDEVH)
+
+### -------------- The Epson LP-8000 laser printer device -------------- ###
+### Note: this driver was contributed by a user: please contact Oleg ###
+### Oleg Fat'yanov <faty1@rlem.titech.ac.jp> if you have questions.###
+
+lp8000_=gdevlp8k.$(OBJ)
+lp8000.dev: $(lp8000_) page.dev
+ $(SETPDEV) lp8000 $(lp8000_)
+
+gdevlp8k.$(OBJ): gdevlp8k.c $(PDEVH)
+
+### -------------- The C.Itoh M8510 printer device --------------------- ###
+### Note: this driver was contributed by a user: please contact Bob ###
+### Smith <bob@snuffy.penfield.ny.us> if you have questions. ###
+
+m8510_=gdev8510.$(OBJ)
+m8510.dev: $(m8510_) page.dev
+ $(SETPDEV) m8510 $(m8510_)
+
+gdev8510.$(OBJ): gdev8510.c $(PDEVH)
+
+### -------------- 24pin Dot-matrix printer with 360DPI ---------------- ###
+### Note: this driver was contributed by users. Please contact: ###
+### Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) for ###
+### questions about the NEC P6; ###
+### Christian Felsch (felsch@tu-harburg.d400.de) for ###
+### questions about the Epson LQ850. ###
+
+dm24_=gdevdm24.$(OBJ)
+gdevdm24.$(OBJ): gdevdm24.c $(PDEVH)
+
+necp6.dev: $(dm24_) page.dev
+ $(SETPDEV) necp6 $(dm24_)
+
+lq850.dev: $(dm24_) page.dev
+ $(SETPDEV) lq850 $(dm24_)
+
+### ----------------- The Okidata MicroLine 182 device ----------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Maarten Koning (smeg@bnr.ca) if you have questions. ###
+
+oki182_=gdevo182.$(OBJ)
+oki182.dev: $(oki182_) page.dev
+ $(SETPDEV) oki182 $(oki182_)
+
+gdevo182.$(OBJ): gdevo182.c $(PDEVH)
+
+### ------------- The Okidata IBM compatible printer device ------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Charles Mack (chasm@netcom.com) if you have questions. ###
+
+okiibm_=gdevokii.$(OBJ)
+okiibm.dev: $(okiibm_) page.dev
+ $(SETPDEV) okiibm $(okiibm_)
+
+gdevokii.$(OBJ): gdevokii.c $(PDEVH)
+
+### ------------- The Ricoh 4081 laser printer device ------------------ ###
+### Note: this driver was contributed by users: ###
+### please contact kdw@oasis.icl.co.uk if you have questions. ###
+
+r4081_=gdev4081.$(OBJ)
+r4081.dev: $(r4081_) page.dev
+ $(SETPDEV) r4081 $(r4081_)
+
+
+gdev4081.$(OBJ): gdev4081.c $(PDEVH)
+
+### -------------------- Sony NWP533 printer device -------------------- ###
+### Note: this driver was contributed by a user: please contact Tero ###
+### Kivinen (kivinen@joker.cs.hut.fi) if you have questions. ###
+
+nwp533_=gdevn533.$(OBJ)
+nwp533.dev: $(nwp533_) page.dev
+ $(SETPDEV) nwp533 $(nwp533_)
+
+gdevn533.$(OBJ): gdevn533.c $(PDEVH)
+
+### ------------------------- The SPARCprinter ------------------------- ###
+### Note: this driver was contributed by users: please contact Martin ###
+### Schulte (schulte@thp.uni-koeln.de) if you have questions. ###
+### He would also like to hear from anyone using the driver. ###
+### Please consult the source code for additional documentation. ###
+
+sparc_=gdevsppr.$(OBJ)
+sparc.dev: $(sparc_) page.dev
+ $(SETPDEV) sparc $(sparc_)
+
+gdevsppr.$(OBJ): gdevsppr.c $(PDEVH)
+
+### ----------------- The StarJet SJ48 device -------------------------- ###
+### Note: this driver was contributed by a user: if you have questions, ###
+### . ###
+### please contact Mats Akerblom (f86ma@dd.chalmers.se). ###
+
+sj48_=gdevsj48.$(OBJ)
+sj48.dev: $(sj48_) page.dev
+ $(SETPDEV) sj48 $(sj48_)
+
+gdevsj48.$(OBJ): gdevsj48.c $(PDEVH)
+
+### ----------------- Tektronix 4396d color printer -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karl Hakimian (hakimian@haney.eecs.wsu.edu) ###
+### if you have questions. ###
+
+t4693d_=gdev4693.$(OBJ)
+t4693d2.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d2 $(t4693d_)
+
+t4693d4.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d4 $(t4693d_)
+
+t4693d8.dev: $(t4693d_) page.dev
+ $(SETPDEV) t4693d8 $(t4693d_)
+
+gdev4693.$(OBJ): gdev4693.c $(PDEVH)
+
+### -------------------- Tektronix ink-jet printers -------------------- ###
+### Note: this driver was contributed by a user: please contact ###
+### Karsten Spang (spang@nbivax.nbi.dk) if you have questions. ###
+
+tek4696_=gdevtknk.$(OBJ)
+tek4696.dev: $(tek4696_) page.dev
+ $(SETPDEV) tek4696 $(tek4696_)
+
+gdevtknk.$(OBJ): gdevtknk.c $(PDEVH) $(malloc__h)
+
+### ----------------- The Xerox XES printer device --------------------- ###
+### Note: this driver was contributed by users: please contact ###
+### Peter Flass (flass@lbdrscs.bitnet) if you have questions. ###
+
+xes_=gdevxes.$(OBJ)
+xes.dev: $(xes_) page.dev
+ $(SETPDEV) xes $(xes_)
+
+gdevxes.$(OBJ): gdevxes.c $(PDEVH)
+
+###### ------------------------- Fax devices ------------------------- ######
+
+### --------------- Generic PostScript system compatible fax ------------ ###
+
+# This code doesn't work yet. Don't even think about using it.
+
+PSFAX=gdevpfax.$(OBJ)
+
+psfax_=$(PSFAX)
+psfax.dev: $(psfax_) page.dev
+ $(SETPDEV) psfax $(psfax_)
+ $(ADDMOD) psfax -iodev Fax
+
+gdevpfax.$(OBJ): gdevpfax.c $(PDEVH) $(gsparam_h) $(gxiodev_h)
+
+### ------------------------- The DigiFAX device ------------------------ ###
+### This driver outputs images in a format suitable for use with ###
+### DigiBoard, Inc.'s DigiFAX software. Use -sDEVICE=dfaxhigh for ###
+### high resolution output, -sDEVICE=dfaxlow for normal output. ###
+### Note: this driver was contributed by a user: please contact ###
+### Rick Richardson (rick@digibd.com) if you have questions. ###
+
+dfax_=gdevdfax.$(OBJ) gdevtfax.$(OBJ)
+
+dfaxlow.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxlow $(dfax_)
+ $(ADDMOD) dfaxlow -include cfe
+
+dfaxhigh.dev: $(dfax_) page.dev
+ $(SETPDEV) dfaxhigh $(dfax_)
+ $(ADDMOD) dfaxhigh -include cfe
+
+gdevdfax.$(OBJ): gdevdfax.c $(PDEVH) $(scfx_h) $(strimpl_h)
+
+### --------------See under TIFF below for fax-format TIFF -------------- ###
+
+###### ------------------- High-level file formats ------------------- ######
+
+# Support for PostScript and PDF
+
+gdevpsdf_h=gdevpsdf.h $(gdevvec_h) $(strimpl_h)
+gdevpstr_h=gdevpstr.h
+
+gdevpsdf.$(OBJ): gdevpsdf.c $(stdio__h) $(string__h)\
+ $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsparam_h) $(gstypes_h)\
+ $(gxdevice_h)\
+ $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpstr.$(OBJ): gdevpstr.c $(math__h) $(stdio__h) $(string__h)\
+ $(gdevpstr_h) $(stream_h)
+
+# PostScript and EPS writers
+
+pswrite1_=gdevps.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pswrite2_=scantab.$(OBJ) sfilter2.$(OBJ)
+pswrite_=$(pswrite1_) $(pswrite2_)
+epswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) epswrite $(pswrite1_)
+ $(ADDMOD) epswrite $(pswrite2_)
+ $(ADDMOD) epswrite -include vector
+
+pswrite.dev: $(ECHOGS_XE) $(pswrite_) vector.dev
+ $(SETDEV) pswrite $(pswrite1_)
+ $(ADDMOD) pswrite $(pswrite2_)
+ $(ADDMOD) pswrite -include vector
+
+gdevps.$(OBJ): gdevps.c $(GDEV) $(math__h) $(time__h)\
+ $(gscdefs_h) $(gscspace_h) $(gsparam_h) $(gsiparam_h) $(gsmatrix_h)\
+ $(gxdcolor_h)\
+ $(sa85x_h) $(strimpl_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+# PDF writer
+# Note that gs_pdfwr.ps will only actually be loaded if the configuration
+# includes a PostScript interpreter.
+
+pdfwrite1_=gdevpdf.$(OBJ) gdevpdfd.$(OBJ) gdevpdfi.$(OBJ) gdevpdfm.$(OBJ)
+pdfwrite2_=gdevpdfp.$(OBJ) gdevpdft.$(OBJ) gdevpsdf.$(OBJ) gdevpstr.$(OBJ)
+pdfwrite3_=gsflip.$(OBJ) scantab.$(OBJ) sfilter2.$(OBJ) sstring.$(OBJ)
+pdfwrite_=$(pdfwrite1_) $(pdfwrite2_) $(pdfwrite3_)
+pdfwrite.dev: $(ECHOGS_XE) $(pdfwrite_) \
+ cmyklib.dev cfe.dev dcte.dev lzwe.dev rle.dev vector.dev
+ $(SETDEV) pdfwrite $(pdfwrite1_)
+ $(ADDMOD) pdfwrite $(pdfwrite2_)
+ $(ADDMOD) pdfwrite $(pdfwrite3_)
+ $(ADDMOD) pdfwrite -ps gs_pdfwr
+ $(ADDMOD) pdfwrite -include cmyklib cfe dcte lzwe rle vector
+
+gdevpdfx_h=gdevpdfx.h $(gsparam_h) $(gxdevice_h) $(gxline_h) $(stream_h)\
+ $(gdevpsdf_h) $(gdevpstr_h)
+
+gdevpdf.$(OBJ): gdevpdf.c $(math__h) $(memory__h) $(string__h) $(time__h)\
+ $(gp_h)\
+ $(gdevpdfx_h) $(gscdefs_h) $(gserrors_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)\
+ $(scanchar_h) $(scfx_h) $(slzwx_h) $(sstring_h) $(strimpl_h) $(szlibx_h)
+ $(CCCZ) gdevpdf.c
+
+gdevpdfd.$(OBJ): gdevpdfd.c $(math__h)\
+ $(gdevpdfx_h)\
+ $(gx_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gxpaint_h)\
+ $(gzcpath_h) $(gzpath_h)
+
+gdevpdfi.$(OBJ): gdevpdfi.c $(math__h) $(memory__h) $(gx_h) \
+ $(gdevpdfx_h) $(gscie_h) $(gscolor2_h) $(gserrors_h) $(gsflip_h)\
+ $(gxcspace_h) $(gxistate_h) \
+ $(sa85x_h) $(scfx_h) $(srlx_h) $(strimpl_h)
+
+gdevpdfm.$(OBJ): gdevpdfm.c $(memory__h) $(string__h) $(gx_h) \
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h) $(scanchar_h)
+
+gdevpdfp.$(OBJ): gdevpdfp.c $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h)
+
+gdevpdft.$(OBJ): gdevpdft.c $(math__h) $(memory__h) $(string__h) $(gx_h)\
+ $(gdevpdfx_h) $(gserrors_h) $(gsutil_h)\
+ $(scommon_h)
+
+# High-level PCL XL writer
+
+pxl_=gdevpx.$(OBJ)
+pxlmono.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlmono $(pxl_)
+ $(ADDMOD) pxlmono -include vector
+
+pxlcolor.dev: $(pxl_) $(GDEV) vector.dev
+ $(SETDEV) pxlcolor $(pxl_)
+ $(ADDMOD) pxlcolor -include vector
+
+gdevpx.$(OBJ): gdevpx.c $(math__h) $(memory__h) $(string__h)\
+ $(gx_h) $(gsccolor_h) $(gsdcolor_h) $(gserrors_h)\
+ $(gxcspace_h) $(gxdevice_h) $(gxpath_h)\
+ $(gdevpxat_h) $(gdevpxen_h) $(gdevpxop_h) $(gdevvec_h)\
+ $(srlx_h) $(strimpl_h)
+
+###### --------------------- Raster file formats --------------------- ######
+
+### --------------------- The "plain bits" devices ---------------------- ###
+
+bit_=gdevbit.$(OBJ)
+
+bit.dev: $(bit_) page.dev
+ $(SETPDEV) bit $(bit_)
+
+bitrgb.dev: $(bit_) page.dev
+ $(SETPDEV) bitrgb $(bit_)
+
+bitcmyk.dev: $(bit_) page.dev
+ $(SETPDEV) bitcmyk $(bit_)
+
+gdevbit.$(OBJ): gdevbit.c $(PDEVH) $(gsparam_h) $(gxlum_h)
+
+### ------------------------- .BMP file formats ------------------------- ###
+
+bmp_=gdevbmp.$(OBJ) gdevpccm.$(OBJ)
+
+gdevbmp.$(OBJ): gdevbmp.c $(PDEVH) $(gdevpccm_h)
+
+bmpmono.dev: $(bmp_) page.dev
+ $(SETPDEV) bmpmono $(bmp_)
+
+bmp16.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16 $(bmp_)
+
+bmp256.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp256 $(bmp_)
+
+bmp16m.dev: $(bmp_) page.dev
+ $(SETPDEV) bmp16m $(bmp_)
+
+### ------------- BMP driver that serves as demo of async rendering ---- ###
+devasync_=gdevasyn.$(OBJ) gdevpccm.$(OBJ) gxsync.$(OBJ)
+
+gdevasyn.$(OBJ): gdevasyn.c $(AK) $(stdio__h) $(gdevprna_h) $(gdevpccm_h)\
+ $(gserrors_h) $(gpsync_h)
+
+asynmono.dev: $(devasync_) page.dev async.dev
+ $(SETPDEV) asynmono $(devasync_)
+ $(ADDMOD) asynmono -include async
+
+
+### -------------------------- CGM file format ------------------------- ###
+### This driver is under development. Use at your own risk. ###
+### The output is very low-level, consisting only of rectangles and ###
+### cell arrays. ###
+
+cgm_=gdevcgm.$(OBJ) gdevcgml.$(OBJ)
+
+gdevcgml_h=gdevcgml.h
+gdevcgmx_h=gdevcgmx.h $(gdevcgml_h)
+
+gdevcgm.$(OBJ): gdevcgm.c $(GDEV) $(memory__h)\
+ $(gsparam_h) $(gdevpccm_h) $(gdevcgml_h)
+
+gdevcgml.$(OBJ): gdevcgml.c $(memory__h) $(stdio__h)\
+ $(gdevcgmx_h)
+
+cgmmono.dev: $(cgm_)
+ $(SETDEV) cgmmono $(cgm_)
+
+cgm8.dev: $(cgm_)
+ $(SETDEV) cgm8 $(cgm_)
+
+cgm24.dev: $(cgm_)
+ $(SETDEV) cgm24 $(cgm_)
+
+### -------------------- The CIF file format for VLSI ------------------ ###
+### Note: this driver was contributed by a user: please contact ###
+### Frederic Petrot (petrot@masi.ibp.fr) if you have questions. ###
+
+cif_=gdevcif.$(OBJ)
+cif.dev: $(cif_) page.dev
+ $(SETPDEV) cif $(cif_)
+
+gdevcif.$(OBJ): gdevcif.c $(PDEVH)
+
+### ------------------------- JPEG file format ------------------------- ###
+
+jpeg_=gdevjpeg.$(OBJ)
+
+# RGB output
+jpeg.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeg $(jpeg_)
+ $(ADDMOD) jpeg -include sdcte
+
+# Gray output
+jpeggray.dev: $(jpeg_) sdcte.dev page.dev
+ $(SETPDEV) jpeggray $(jpeg_)
+ $(ADDMOD) jpeggray -include sdcte
+
+gdevjpeg.$(OBJ): gdevjpeg.c $(stdio__h) $(PDEVH)\
+ $(sdct_h) $(sjpeg_h) $(stream_h) $(strimpl_h) jpeglib.h
+
+### ------------------------- MIFF file format ------------------------- ###
+### Right now we support only 24-bit direct color, but we might add more ###
+### formats in the future. ###
+
+miff_=gdevmiff.$(OBJ)
+
+miff24.dev: $(miff_) page.dev
+ $(SETPDEV) miff24 $(miff_)
+
+gdevmiff.$(OBJ): gdevmiff.c $(PDEVH)
+
+### --------------------------- MGR devices ---------------------------- ###
+### Note: these drivers were contributed by a user: please contact ###
+### Carsten Emde (carsten@ce.pr.net.ch) if you have questions. ###
+
+MGR=gdevmgr.$(OBJ) gdevpccm.$(OBJ)
+
+gdevmgr.$(OBJ): gdevmgr.c $(PDEVH) $(gdevpccm_h) gdevmgr.h
+
+mgrmono.dev: $(MGR) page.dev
+ $(SETPDEV) mgrmono $(MGR)
+
+mgrgray2.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray2 $(MGR)
+
+mgrgray4.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray4 $(MGR)
+
+mgrgray8.dev: $(MGR) page.dev
+ $(SETPDEV) mgrgray8 $(MGR)
+
+mgr4.dev: $(MGR) page.dev
+ $(SETPDEV) mgr4 $(MGR)
+
+mgr8.dev: $(MGR) page.dev
+ $(SETPDEV) mgr8 $(MGR)
+
+### ------------------------- PCX file formats ------------------------- ###
+
+pcx_=gdevpcx.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpcx.$(OBJ): gdevpcx.c $(PDEVH) $(gdevpccm_h) $(gxlum_h)
+
+pcxmono.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxmono $(pcx_)
+
+pcxgray.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxgray $(pcx_)
+
+pcx16.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx16 $(pcx_)
+
+pcx256.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx256 $(pcx_)
+
+pcx24b.dev: $(pcx_) page.dev
+ $(SETPDEV) pcx24b $(pcx_)
+
+pcxcmyk.dev: $(pcx_) page.dev
+ $(SETPDEV) pcxcmyk $(pcx_)
+
+# The 2-up PCX device is here only as an example, and for testing.
+pcx2up.dev: $(LIB_MAK) $(ECHOGS_XE) gdevp2up.$(OBJ) page.dev pcx256.dev
+ $(SETPDEV) pcx2up gdevp2up.$(OBJ)
+ $(ADDMOD) pcx2up -include pcx256
+
+gdevp2up.$(OBJ): gdevp2up.c $(AK)\
+ $(gdevpccm_h) $(gdevprn_h) $(gxclpage_h)
+
+### ------------------- Portable Bitmap file formats ------------------- ###
+### For more information, see the pbm(5), pgm(5), and ppm(5) man pages. ###
+
+pxm_=gdevpbm.$(OBJ)
+
+gdevpbm.$(OBJ): gdevpbm.c $(PDEVH) $(gscdefs_h) $(gxlum_h)
+
+### Portable Bitmap (PBM, plain or raw format, magic numbers "P1" or "P4")
+
+pbm.dev: $(pxm_) page.dev
+ $(SETPDEV) pbm $(pxm_)
+
+pbmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pbmraw $(pxm_)
+
+### Portable Graymap (PGM, plain or raw format, magic numbers "P2" or "P5")
+
+pgm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgm $(pxm_)
+
+pgmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgmraw $(pxm_)
+
+# PGM with automatic optimization to PBM if this is possible.
+
+pgnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnm $(pxm_)
+
+pgnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pgnmraw $(pxm_)
+
+### Portable Pixmap (PPM, plain or raw format, magic numbers "P3" or "P6")
+
+ppm.dev: $(pxm_) page.dev
+ $(SETPDEV) ppm $(pxm_)
+
+ppmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) ppmraw $(pxm_)
+
+# PPM with automatic optimization to PGM or PBM if possible.
+
+pnm.dev: $(pxm_) page.dev
+ $(SETPDEV) pnm $(pxm_)
+
+pnmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pnmraw $(pxm_)
+
+### Portable inKmap (CMYK internally, converted to PPM=RGB at output time)
+
+pkm.dev: $(pxm_) page.dev
+ $(SETPDEV) pkm $(pxm_)
+
+pkmraw.dev: $(pxm_) page.dev
+ $(SETPDEV) pkmraw $(pxm_)
+
+### --------------- Portable Network Graphics file format --------------- ###
+### Requires libpng 0.81 and zlib 0.95 (or more recent versions). ###
+### See libpng.mak and zlib.mak for more details. ###
+
+png_=gdevpng.$(OBJ) gdevpccm.$(OBJ)
+
+gdevpng.$(OBJ): gdevpng.c $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(PSRC)png.h
+ $(CCCP) gdevpng.c
+
+pngmono.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pngmono $(png_)
+ $(ADDMOD) pngmono -include libpng
+
+pnggray.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) pnggray $(png_)
+ $(ADDMOD) pnggray -include libpng
+
+png16.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16 $(png_)
+ $(ADDMOD) png16 -include libpng
+
+png256.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png256 $(png_)
+ $(ADDMOD) png256 -include libpng
+
+png16m.dev: libpng.dev $(png_) page.dev
+ $(SETPDEV) png16m $(png_)
+ $(ADDMOD) png16m -include libpng
+
+### ---------------------- PostScript image format ---------------------- ###
+### These devices make it possible to print Level 2 files on a Level 1 ###
+### printer, by converting them to a bitmap in PostScript format. ###
+
+ps_=gdevpsim.$(OBJ)
+
+gdevpsim.$(OBJ): gdevpsim.c $(PDEVH)
+
+psmono.dev: $(ps_) page.dev
+ $(SETPDEV) psmono $(ps_)
+
+psgray.dev: $(ps_) page.dev
+ $(SETPDEV) psgray $(ps_)
+
+# Someday there will be RGB and CMYK variants....
+
+### -------------------------- SGI RGB pixmaps -------------------------- ###
+
+sgirgb_=gdevsgi.$(OBJ)
+
+gdevsgi.$(OBJ): gdevsgi.c $(PDEVH) gdevsgi.h
+
+sgirgb.dev: $(sgirgb_) page.dev
+ $(SETPDEV) sgirgb $(sgirgb_)
+
+### -------------------- Plain or TIFF fax encoding --------------------- ###
+### Use -sDEVICE=tiffg3 or tiffg4 and ###
+### -r204x98 for low resolution output, or ###
+### -r204x196 for high resolution output ###
+### These drivers recognize 3 page sizes: letter, A4, and B4. ###
+
+gdevtifs_h=gdevtifs.h
+
+tfax_=gdevtfax.$(OBJ)
+tfax.dev: $(tfax_) cfe.dev lzwe.dev rle.dev tiffs.dev
+ $(SETMOD) tfax $(tfax_)
+ $(ADDMOD) tfax -include cfe lzwe rle tiffs
+
+gdevtfax.$(OBJ): gdevtfax.c $(PDEVH)\
+ $(gdevtifs_h) $(scfx_h) $(slzwx_h) $(srlx_h) $(strimpl_h)
+
+### Plain G3/G4 fax with no header
+
+faxg3.dev: tfax.dev
+ $(SETDEV) faxg3 -include tfax
+
+faxg32d.dev: tfax.dev
+ $(SETDEV) faxg32d -include tfax
+
+faxg4.dev: tfax.dev
+ $(SETDEV) faxg4 -include tfax
+
+### ---------------------------- TIFF formats --------------------------- ###
+
+tiffs_=gdevtifs.$(OBJ)
+tiffs.dev: $(tiffs_) page.dev
+ $(SETMOD) tiffs $(tiffs_)
+ $(ADDMOD) tiffs -include page
+
+gdevtifs.$(OBJ): gdevtifs.c $(PDEVH) $(stdio__h) $(time__h) \
+ $(gdevtifs_h) $(gscdefs_h) $(gstypes_h)
+
+# Black & white, G3/G4 fax
+
+tiffcrle.dev: tfax.dev
+ $(SETDEV) tiffcrle -include tfax
+
+tiffg3.dev: tfax.dev
+ $(SETDEV) tiffg3 -include tfax
+
+tiffg32d.dev: tfax.dev
+ $(SETDEV) tiffg32d -include tfax
+
+tiffg4.dev: tfax.dev
+ $(SETDEV) tiffg4 -include tfax
+
+# Black & white, LZW compression
+
+tifflzw.dev: tfax.dev
+ $(SETDEV) tifflzw -include tfax
+
+# Black & white, PackBits compression
+
+tiffpack.dev: tfax.dev
+ $(SETDEV) tiffpack -include tfax
+
+# RGB, no compression
+
+tiffrgb_=gdevtfnx.$(OBJ)
+
+tiff12nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff12nc $(tiffrgb_)
+ $(ADDMOD) tiff12nc -include tiffs
+
+tiff24nc.dev: $(tiffrgb_) tiffs.dev
+ $(SETPDEV) tiff24nc $(tiffrgb_)
+ $(ADDMOD) tiff24nc -include tiffs
+
+gdevtfnx.$(OBJ): gdevtfnx.c $(PDEVH) $(gdevtifs_h)
+# Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This is the last part of the makefile for Unix configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define the name of this makefile.
+UNIXTAIL_MAK=unixtail.mak
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Unix platforms
+
+# We have to include a test for the existence of sys/time.h,
+# because some System V platforms don't have it.
+
+# Define pipes as a separable feature.
+
+pipe_=gdevpipe.$(OBJ)
+pipe.dev: $(UNIXTAIL_MAK) $(ECHOGS_XE) $(pipe_)
+ $(SETMOD) pipe $(pipe_)
+ $(ADDMOD) pipe -iodev pipe
+
+gdevpipe.$(OBJ): gdevpipe.c $(AK) $(errno__h) $(stdio__h) $(string__h) \
+ $(gserror_h) $(gsmemory_h) $(gstypes_h) $(gxiodev_h) $(stream_h)
+
+# Unix platforms other than System V, and also System V Release 4
+# (SVR4) platforms.
+unix__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ)
+unix_.dev: $(unix__)
+ $(SETMOD) unix_ $(unix__)
+
+gp_unix.$(OBJ): gp_unix.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h)
+
+# System V platforms other than SVR4, which lack some system calls,
+# but have pipes.
+sysv__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ) gp_sysv.$(OBJ)
+sysv_.dev: $(sysv__)
+ $(SETMOD) sysv_ $(sysv__)
+
+gp_sysv.$(OBJ): gp_sysv.c $(stdio__h) $(time__h) $(AK)
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c
+ $(CCA2K) $(O)$(ANSI2KNR_XE) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c $(AK)
+ $(CCAUX) $(O)$(ECHOGS_XE) echogs.c
+
+# On the RS/6000 (at least), compiling genarch.c with gcc with -O
+# produces a buggy executable.
+$(GENARCH_XE): genarch.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENARCH_XE) genarch.c
+
+$(GENCONF_XE): genconf.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENCONF_XE) genconf.c
+
+$(GENINIT_XE): geninit.c $(AK) $(stdio__h) $(string__h)
+ $(CCAUX) $(O)$(GENINIT_XE) geninit.c
+
+# Query the environment to construct gconfig_.h.
+# The "else true; is required because Ultrix's implementation of sh -e
+# terminates execution of a command if any error occurs, even if the command
+# traps the error with ||.
+INCLUDE=/usr/include
+gconfig_.h: $(UNIXTAIL_MAK) $(ECHOGS_XE)
+ ./echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ if ( test -f $(INCLUDE)/dirent.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H; else true; fi
+ if ( test -f $(INCLUDE)/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/dir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_DIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/time.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/times.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIMES_H; else true; fi
+
+# ----------------------------- Main program ------------------------------ #
+
+### Library files and archive
+
+LIB_ARCHIVE_ALL=$(LIB_ALL) $(DEVS_ALL)\
+ gsnogc.$(OBJ) gconfig.$(OBJ) gscdefs.$(OBJ)
+
+# Build an archive for the library only.
+# This is not used in a standard build.
+GSLIB_A=$(GS)lib.a
+$(GSLIB_A): $(LIB_ARCHIVE_ALL)
+ rm -f $(GSLIB_A)
+ $(AR) $(ARFLAGS) $(GSLIB_A) $(LIB_ARCHIVE_ALL)
+ $(RANLIB) $(GSLIB_A)
+
+### Interpreter main program
+
+INT_ARCHIVE_ALL=imainarg.$(OBJ) imain.$(OBJ) $(INT_ALL) $(DEVS_ALL)\
+ gconfig.$(OBJ) gscdefs.$(OBJ)
+XE_ALL=gs.$(OBJ) $(INT_ARCHIVE_ALL)
+
+# Build a library archive for the entire interpreter.
+# This is not used in a standard build.
+GS_A=$(GS).a
+$(GS_A): $(INT_ARCHIVE_ALL)
+ rm -f $(GS_A)
+ $(AR) $(ARFLAGS) $(GS_A) $(INT_ARCHIVE_ALL)
+ $(RANLIB) $(GS_A)
+
+# Here is the final link step. The stuff with LD_RUN_PATH is for SVR4
+# systems with dynamic library loading; I believe it's harmless elsewhere.
+# The resetting of the environment variables to empty strings is for SCO Unix,
+# which has limited environment space.
+$(GS_XE): ld.tr echogs $(XE_ALL)
+ ./echogs -w ldt.tr -n - $(CCLD) $(LDFLAGS) $(XLIBDIRS) -o $(GS_XE)
+ ./echogs -a ldt.tr -n -s gs.$(OBJ) -s
+ cat ld.tr >>ldt.tr
+ ./echogs -a ldt.tr -s - $(EXTRALIBS) -lm
+ LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; \
+ XCFLAGS= XINCLUDE= XLDFLAGS= XLIBDIRS= XLIBS= \
+ FEATURE_DEVS= DEVICE_DEVS= DEVICE_DEVS1= DEVICE_DEVS2= DEVICE_DEVS3= \
+ DEVICE_DEVS4= DEVICE_DEVS5= DEVICE_DEVS6= DEVICE_DEVS7= DEVICE_DEVS8= \
+ DEVICE_DEVS9= DEVICE_DEVS10= DEVICE_DEVS11= DEVICE_DEVS12= \
+ DEVICE_DEVS13= DEVICE_DEVS14= DEVICE_DEVS15= \
+ $(SH) <ldt.tr
+# Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix and Desqview/X configurations.
+
+# This is the very last part of the makefile for these configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define a rule for building profiling configurations.
+pg:
+ make GENOPT='' CFLAGS='-pg -O $(GCFLAGS) $(XCFLAGS)' LDFLAGS='$(XLDFLAGS) -pg' XLIBS='Xt SM ICE Xext X11' CCLEAF='$(CCC)'
+
+# Define a rule for building debugging configurations.
+debug:
+ make GENOPT='-DDEBUG' CFLAGS='-g -O $(GCFLAGS) $(XCFLAGS)'
+
+# The rule for gconfigv.h is here because it is shared between Unix and
+# DV/X environments.
+gconfigv.h: unix-end.mak $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+# The following rules are equivalent to what tar_cat does.
+# The rm -f is so that we don't overwrite a file that `make'
+# may currently be reading from.
+GENERIC_MAK_LIST=$(GS_MAK) $(LIB_MAK) $(INT_MAK) $(JPEG_MAK) $(LIBPNG_MAK) $(ZLIB_MAK) $(DEVS_MAK)
+UNIX_MAK_LIST=dvx-gcc.mak unixansi.mak unix-cc.mak unix-gcc.mak
+
+unix.mak: $(UNIX_MAK_LIST)
+
+DVX_GCC_MAK=$(VERSION_MAK) dgc-head.mak dvx-head.mak $(GENERIC_MAK_LIST) dvx-tail.mak unix-end.mak
+dvx-gcc.mak: $(DVX_GCC_MAK)
+ rm -f dvx-gcc.mak
+ $(CAT) $(DVX_GCC_MAK) >dvx-gcc.mak
+
+UNIXANSI_MAK=$(VERSION_MAK) ansihead.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unixansi.mak: $(UNIXANSI_MAK)
+ rm -f unixansi.mak
+ $(CAT) $(UNIXANSI_MAK) >unixansi.mak
+
+UNIX_CC_MAK=$(VERSION_MAK) cc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-cc.mak: $(UNIX_CC_MAK)
+ rm -f unix-cc.mak
+ $(CAT) $(UNIX_CC_MAK) >unix-cc.mak
+
+UNIX_GCC_MAK=$(VERSION_MAK) gcc-head.mak unixhead.mak $(GENERIC_MAK_LIST) unixtail.mak unix-end.mak
+unix-gcc.mak: $(UNIX_GCC_MAK)
+ rm -f unix-gcc.mak
+ $(CAT) $(UNIX_GCC_MAK) >unix-gcc.mak
+
+# Installation
+
+TAGS:
+ etags -t *.c *.h
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+install-exec: $(GS)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(scriptdir)
+ sh -c 'for f in gsbj gsdj gsdj500 gslj gslp gsnd bdftops font2c \
+pdf2dsc pdf2ps printafm ps2ascii ps2epsi ps2pdf wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pfbtogs.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps gs_pdf.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps pdf_2ps.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/unixhead.mak b/gs/src/unixhead.mak
new file mode 100644
index 000000000..762185673
--- /dev/null
+++ b/gs/src/unixhead.mak
@@ -0,0 +1,76 @@
+# Copyright (C) 1990, 1993, 1996 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This part of the makefile gets inserted after the compiler-specific part
+# (xxx-head.mak) and before gs.mak and devs.mak.
+
+# ----------------------------- Generic stuff ----------------------------- #
+
+# Define the platform name. For a "stock" System V platform,
+# use sysv_ instead of unix_.
+
+PLATFORM=unix_
+
+# Define the syntax for command, object, and executable files.
+
+CMD=
+O=-o ./
+OBJ=o
+XE=
+XEAUX=
+
+# Define the current directory prefix and command invocations.
+
+CAT=cat
+D=/
+EXPP=
+EXP=./
+SHELL=/bin/sh
+SH=$(SHELL)
+SHP=$(SH) $(EXP)
+
+# Define generic commands.
+
+CP_=cp
+RM_=rm -f
+RMN_=rm -f
+
+# Define the arguments for genconf.
+
+CONFILES=-p "%s&s&&" -pl "&-l%s&s&&" -pL "&-L%s&s&&" -ol $(ld_tr)
+
+# Define the compilation rules and flags.
+
+CCFLAGS=$(GENOPT) $(CFLAGS)
+
+.c.o: $(AK)
+ $(CCC) $*.c
+
+CCCF=$(CCC)
+CCD=$(CCC)
+CCINT=$(CCC)
+
+BEGINFILES=
+CCBEGIN=$(CCC) *.c
+
+# Patch a couple of PC-specific things that aren't relevant to Unix builds,
+# but that cause `make' to produce warnings.
+
+BGIDIR=***UNUSED***
+PCFBASM=
diff --git a/gs/src/unixtail.mak b/gs/src/unixtail.mak
new file mode 100644
index 000000000..bb5b78008
--- /dev/null
+++ b/gs/src/unixtail.mak
@@ -0,0 +1,144 @@
+# Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Partial makefile common to all Unix configurations.
+
+# This is the last part of the makefile for Unix configurations.
+# Since Unix make doesn't have an 'include' facility, we concatenate
+# the various parts of the makefile together by brute force (in tar_cat).
+
+# Define the name of this makefile.
+UNIXTAIL_MAK=unixtail.mak
+
+# The following prevents GNU make from constructing argument lists that
+# include all environment variables, which can easily be longer than
+# brain-damaged system V allows.
+
+.NOEXPORT:
+
+# -------------------------------- Library -------------------------------- #
+
+## The Unix platforms
+
+# We have to include a test for the existence of sys/time.h,
+# because some System V platforms don't have it.
+
+# Define pipes as a separable feature.
+
+pipe_=gdevpipe.$(OBJ)
+pipe.dev: $(UNIXTAIL_MAK) $(ECHOGS_XE) $(pipe_)
+ $(SETMOD) pipe $(pipe_)
+ $(ADDMOD) pipe -iodev pipe
+
+gdevpipe.$(OBJ): gdevpipe.c $(AK) $(errno__h) $(stdio__h) $(string__h) \
+ $(gserror_h) $(gsmemory_h) $(gstypes_h) $(gxiodev_h) $(stream_h)
+
+# Unix platforms other than System V, and also System V Release 4
+# (SVR4) platforms.
+unix__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ)
+unix_.dev: $(unix__)
+ $(SETMOD) unix_ $(unix__)
+
+gp_unix.$(OBJ): gp_unix.c $(AK) $(string__h) $(gx_h) $(gsexit_h) $(gp_h) \
+ $(time__h)
+
+# System V platforms other than SVR4, which lack some system calls,
+# but have pipes.
+sysv__=gp_nofb.$(OBJ) gp_unix.$(OBJ) gp_unifs.$(OBJ) gp_unifn.$(OBJ) gp_sysv.$(OBJ)
+sysv_.dev: $(sysv__)
+ $(SETMOD) sysv_ $(sysv__)
+
+gp_sysv.$(OBJ): gp_sysv.c $(stdio__h) $(time__h) $(AK)
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ANSI2KNR_XE): ansi2knr.c
+ $(CCA2K) $(O)$(ANSI2KNR_XE) ansi2knr.c
+
+$(ECHOGS_XE): echogs.c $(AK)
+ $(CCAUX) $(O)$(ECHOGS_XE) echogs.c
+
+# On the RS/6000 (at least), compiling genarch.c with gcc with -O
+# produces a buggy executable.
+$(GENARCH_XE): genarch.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENARCH_XE) genarch.c
+
+$(GENCONF_XE): genconf.c $(AK) $(stdpre_h)
+ $(CCAUX) $(O)$(GENCONF_XE) genconf.c
+
+$(GENINIT_XE): geninit.c $(AK) $(stdio__h) $(string__h)
+ $(CCAUX) $(O)$(GENINIT_XE) geninit.c
+
+# Query the environment to construct gconfig_.h.
+# The "else true; is required because Ultrix's implementation of sh -e
+# terminates execution of a command if any error occurs, even if the command
+# traps the error with ||.
+INCLUDE=/usr/include
+gconfig_.h: $(UNIXTAIL_MAK) $(ECHOGS_XE)
+ ./echogs -w gconfig_.h -x 2f2a -s This file was generated automatically. -s -x 2a2f
+ if ( test -f $(INCLUDE)/dirent.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_DIRENT_H; else true; fi
+ if ( test -f $(INCLUDE)/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/dir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_DIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/ndir.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_NDIR_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/time.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIME_H; else true; fi
+ if ( test -f $(INCLUDE)/sys/times.h ); then ./echogs -a gconfig_.h -x 23 define HAVE_SYS_TIMES_H; else true; fi
+
+# ----------------------------- Main program ------------------------------ #
+
+### Library files and archive
+
+LIB_ARCHIVE_ALL=$(LIB_ALL) $(DEVS_ALL)\
+ gsnogc.$(OBJ) gconfig.$(OBJ) gscdefs.$(OBJ)
+
+# Build an archive for the library only.
+# This is not used in a standard build.
+GSLIB_A=$(GS)lib.a
+$(GSLIB_A): $(LIB_ARCHIVE_ALL)
+ rm -f $(GSLIB_A)
+ $(AR) $(ARFLAGS) $(GSLIB_A) $(LIB_ARCHIVE_ALL)
+ $(RANLIB) $(GSLIB_A)
+
+### Interpreter main program
+
+INT_ARCHIVE_ALL=imainarg.$(OBJ) imain.$(OBJ) $(INT_ALL) $(DEVS_ALL)\
+ gconfig.$(OBJ) gscdefs.$(OBJ)
+XE_ALL=gs.$(OBJ) $(INT_ARCHIVE_ALL)
+
+# Build a library archive for the entire interpreter.
+# This is not used in a standard build.
+GS_A=$(GS).a
+$(GS_A): $(INT_ARCHIVE_ALL)
+ rm -f $(GS_A)
+ $(AR) $(ARFLAGS) $(GS_A) $(INT_ARCHIVE_ALL)
+ $(RANLIB) $(GS_A)
+
+# Here is the final link step. The stuff with LD_RUN_PATH is for SVR4
+# systems with dynamic library loading; I believe it's harmless elsewhere.
+# The resetting of the environment variables to empty strings is for SCO Unix,
+# which has limited environment space.
+$(GS_XE): ld.tr echogs $(XE_ALL)
+ ./echogs -w ldt.tr -n - $(CCLD) $(LDFLAGS) $(XLIBDIRS) -o $(GS_XE)
+ ./echogs -a ldt.tr -n -s gs.$(OBJ) -s
+ cat ld.tr >>ldt.tr
+ ./echogs -a ldt.tr -s - $(EXTRALIBS) -lm
+ LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; \
+ XCFLAGS= XINCLUDE= XLDFLAGS= XLIBDIRS= XLIBS= \
+ FEATURE_DEVS= DEVICE_DEVS= DEVICE_DEVS1= DEVICE_DEVS2= DEVICE_DEVS3= \
+ DEVICE_DEVS4= DEVICE_DEVS5= DEVICE_DEVS6= DEVICE_DEVS7= DEVICE_DEVS8= \
+ DEVICE_DEVS9= DEVICE_DEVS10= DEVICE_DEVS11= DEVICE_DEVS12= \
+ DEVICE_DEVS13= DEVICE_DEVS14= DEVICE_DEVS15= \
+ $(SH) <ldt.tr
diff --git a/gs/src/version.mak b/gs/src/version.mak
new file mode 100644
index 000000000..f9127dffb
--- /dev/null
+++ b/gs/src/version.mak
@@ -0,0 +1,34 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile fragment containing the current revision identification.
+
+# Define the name of this makefile.
+VERSION_MAK=version.mak
+
+# Major and minor version numbers.
+# MINOR0 is different from MINOR only if MINOR is a single digit.
+GS_VERSION_MAJOR=5
+GS_VERSION_MINOR=13
+GS_VERSION_MINOR0=13
+# Revision date: year x 10000 + month x 100 + day.
+GS_REVISIONDATE=19980427
+
+# Derived values
+GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0)
+GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR)
+GS_REVISION=$(GS_VERSION)
diff --git a/gs/src/vms-cc.mak b/gs/src/vms-cc.mak
new file mode 100644
index 000000000..a18d13c13
--- /dev/null
+++ b/gs/src/vms-cc.mak
@@ -0,0 +1,102 @@
+$ ! Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+$ !
+$ ! This file is part of Aladdin Ghostscript.
+$ !
+$ ! Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+$ ! or distributor accepts any responsibility for the consequences of using it,
+$ ! or for whether it serves any particular purpose or works at all, unless he
+$ ! or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+$ ! License (the "License") for full details.
+$ !
+$ ! Every copy of Aladdin Ghostscript must include a copy of the License,
+$ ! normally in a plain ASCII text file named PUBLIC. The License grants you
+$ ! the right to copy, modify and redistribute Aladdin Ghostscript, but only
+$ ! under certain conditions described in the License. Among other things, the
+$ ! License requires that the copyright notice and this notice be preserved on
+$ ! all copies.
+$ !
+$ VERIFY = 'F$VERIFY(F$INTEGER(F$LOGICAL("GS_VERIFY")))'
+$ !
+$ ! "makefile" for Ghostscript, VMS / VMS C / DECwindows (X11) configuration.
+$ !
+$ !
+$ ! Execute this command file while in the Ghostscript directory!
+$ !
+$ !
+$ ! To build a debugging configuration, issue the command:
+$ !
+$ ! $ @VMS-CC.MAK DEBUG
+$ !
+$ ! Do not abbreviate "DEBUG". To specify an alternate directory for
+$ ! GS_LIB_DEFAULT, issue the command:
+$ !
+$ ! $ @VMS-CC.MAK directory
+$ !
+$ ! with "directory" a fully qualified directory name. "directory" cannot
+$ ! be DEBUG (otherwise it will be confused with the DEBUG switch). Both
+$ ! the DEBUG switch and a directory name may be specified on the same
+$ ! command line and in either order.
+$ !
+$ !
+$ ! Declare local DCL symbols used by VMS.MAK
+$ !
+$ CC_DEF = "" ! Compiler /DEFINEs, US
+$!!! CC_DEF = "A4" ! Compiler /DEFINEs, Europe
+$ L_QUAL = "" ! Qualifiers for the link command
+$ CC_COMMAND = "CC" ! Compile command
+$ X_INCLUDE = "" ! Used with Gnu C to find path to X11 include files
+$ !
+$ GS_DOCDIR = F$ENVIRONMENT("DEFAULT")
+$ GS_INIT = "GS_INIT.PS"
+$ GS_LIB_DEFAULT = F$ENVIRONMENT("DEFAULT")
+$ SEARCH_HERE_FIRST = 1
+$ CONFIG = ""
+$ FEATURE_DEVS = "level2.dev pdf.dev"
+$ COMPILE_INITS = "0"
+$ BAND_LIST_STORAGE = "file"
+$ BAND_LIST_COMPRESSOR = "zlib"
+$ FILE_IMPLEMENTATION = "stdio"
+$ DEVICE_DEVS = "x11.dev x11alpha.dev x11cmyk.dev x11mono.dev"
+$ DEVICE_DEVS3 = "deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev"
+$ DEVICE_DEVS4 = "cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev"
+$ DEVICE_DEVS6 = "bj10e.dev bj200.dev bjc600.dev bjc800.dev"
+$ DEVICE_DEVS7 = "faxg3.dev faxg32d.dev faxg4.dev"
+$ DEVICE_DEVS8 = "pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev"
+$ DEVICE_DEVS9 = "pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev"
+$ DEVICE_DEVS10 = "tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev"
+$ DEVICE_DEVS11 = "tiff12nc.dev tiff24nc.dev"
+$ DEVICE_DEVS12 = "psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev"
+$ DEVICE_DEVS13 = "pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev"
+$ DEVICE_DEVS14 = "jpeg.dev jpeggray.dev"
+$ DEVICE_DEVS15 = "pdfwrite.dev"
+$ !
+$ !
+$ ! Give ourself a healthy search list for C include files
+$ !
+$ DEFINE C$INCLUDE 'F$ENVIRONMENT("DEFAULT"),DECW$INCLUDE,SYS$LIBRARY
+$ DEFINE VAXC$INCLUDE C$INCLUDE
+$ DEFINE SYS SYS$LIBRARY
+$ !
+$ !
+$ ! Option file to use when linking genarch.c
+$ !
+$ CREATE RTL.OPT
+SYS$SHARE:VAXCRTL.EXE/SHARE
+$ !
+$ !
+$ ! Now build everything
+$ !
+$ @VMS.MAK 'P1 'P2 'P3 'P4 'P5 'P6 'P7 'P8
+$ !
+$ !
+$ DONE:
+$ ! Cleanup
+$ !
+$ IF F$LOGICAL("C$INCLUDE") .NES. "" THEN DEASSIGN C$INCLUDE"
+$ IF F$LOGICAL("VAXC$INCLUDE") .NES. "" THEN DEASSIGN VAXC$INCLUDE
+$ IF F$LOGICAL("SYS") .NES. "" THEN DEASSIGN SYS
+$ IF F$SEARCH("RTL.OPT") .NES. "" THEN DELETE RTL.OPT;*
+$ !
+$ ! ALL DONE
+$ !
+$ VERIFY = 'F$VERIFY(VERIFY)
diff --git a/gs/src/vms-decc.mak b/gs/src/vms-decc.mak
new file mode 100644
index 000000000..fd5ed3587
--- /dev/null
+++ b/gs/src/vms-decc.mak
@@ -0,0 +1,112 @@
+$ ! Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+$ !
+$ ! This file is part of Aladdin Ghostscript.
+$ !
+$ ! Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+$ ! or distributor accepts any responsibility for the consequences of using it,
+$ ! or for whether it serves any particular purpose or works at all, unless he
+$ ! or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+$ ! License (the "License") for full details.
+$ !
+$ ! Every copy of Aladdin Ghostscript must include a copy of the License,
+$ ! normally in a plain ASCII text file named PUBLIC. The License grants you
+$ ! the right to copy, modify and redistribute Aladdin Ghostscript, but only
+$ ! under certain conditions described in the License. Among other things, the
+$ ! License requires that the copyright notice and this notice be preserved on
+$ ! all copies.
+$ !
+$ SET SYMBOL/GENERAL/SCOPE=(NOLOCAL,NOGLOBAL)
+$ VERIFY = 'F$VERIFY(F$INTEGER(F$LOGICAL("GS_VERIFY")))'
+$ !
+$ ! "makefile" for Ghostscript, VMS / DEC C / DECwindows (X11) configuration,
+$ ! on AXP or VAX
+$ !
+$ !
+$ ! Execute this command file while in the Ghostscript directory!
+$ !
+$ !
+$ ! To build a debugging configuration, issue the command:
+$ !
+$ ! $ @VMS-DECC.MAK DEBUG
+$ !
+$ ! Do not abbreviate "DEBUG". To specify an alternate file for
+$ ! GS_LIB_DEFAULT, issue the command:
+$ !
+$ ! $ @VMS-DECC.MAK file
+$ !
+$ ! with "file" a fully qualified filename. "file" cannot
+$ ! be DEBUG (otherwise it will be confused with the DEBUG switch). Both
+$ ! the DEBUG switch and a directory name may be specified on the same
+$ ! command line and in either order.
+$ !
+$ !
+$ ! Declare local DCL symbols used by VMS.MAK
+$ !
+$ CC_QUAL = "/DECC/PREFIX=ALL/NESTED_INCLUDE=PRIMARY" ! Quals. for compile
+$ CC_DEF = "" ! Compiler /DEFINEs, US
+$!!! CC_DEF = "A4" ! Compiler /DEFINEs, Europe
+$ L_QUAL = "" ! Qualifiers for the link command
+$ CC_COMMAND = "CC" ! Compile command
+$ X_INCLUDE = "" ! Used with Gnu C to find path to X11 include files
+$ !
+$ GS_DOCDIR = F$ENVIRONMENT("DEFAULT")
+$ GS_INIT = "GS_Init.PS"
+$ GS_LIB_DEFAULT = F$ENVIRONMENT("DEFAULT")
+$ SEARCH_HERE_FIRST = 1
+$ CONFIG = ""
+$ FEATURE_DEVS = "level2.dev pdf.dev"
+$ COMPILE_INITS = "0"
+$ BAND_LIST_STORAGE = "file"
+$ BAND_LIST_COMPRESSOR = "zlib"
+$ FILE_IMPLEMENTATION = "stdio"
+$ DEVICE_DEVS = "x11.dev x11alpha.dev x11cmyk.dev x11mono.dev"
+$ DEVICE_DEVS1 = ""
+$ DEVICE_DEVS2 = ""
+$ DEVICE_DEVS3 = "deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev"
+$ DEVICE_DEVS4 = "cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev"
+$ DEVICE_DEVS5 = "uniprint.dev"
+$ DEVICE_DEVS6 = "bj10e.dev bj200.dev bjc600.dev bjc800.dev"
+$ DEVICE_DEVS7 = "faxg3.dev faxg32d.dev faxg4.dev"
+$ DEVICE_DEVS8 = "jpeg.dev jpeggray.dev pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev"
+$ DEVICE_DEVS9 = "pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev"
+$ DEVICE_DEVS10 = "tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev"
+$ DEVICE_DEVS11 = "tiff12nc.dev tiff24nc.dev"
+$ DEVICE_DEVS12 = "psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev"
+$ DEVICE_DEVS13 = "pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev"
+$ DEVICE_DEVS14 = ""
+$ DEVICE_DEVS15 = "pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev"
+$ !
+$ ! Give ourself a healthy search list for C include files
+$ !
+$ if f$trnlnm("DECC$LIBRARY_INCLUDE").nes.""
+$ then
+$ DEFINE DECC$USER_INCLUDE 'F$ENVIRONMENT("DEFAULT"),DECW$INCLUDE,DECC$LIBRARY_INCLUDE,SYS$LIBRARY
+$ DEFINE DECC$SYSTEM_INCLUDE 'F$ENVIRONMENT("DEFAULT"),DECW$INCLUDE,DECC$LIBRARY_INCLUDE,SYS$LIBRARY
+$ DEFINE SYS DECC$LIBRARY_INCLUDE,SYS$LIBRARY
+$ else
+$ DEFINE DECC$USER_INCLUDE 'F$ENVIRONMENT("DEFAULT"),DECW$INCLUDE,SYS$LIBRARY
+$ DEFINE DECC$SYSTEM_INCLUDE 'F$ENVIRONMENT("DEFAULT"),DECW$INCLUDE,SYS$LIBRARY
+$ DEFINE SYS SYS$LIBRARY
+$ endif
+$ !
+$ !
+$ ! Empty option file to use when linking genarch.c
+$ !
+$ CREATE RTL.OPT
+$ !
+$ !
+$ ! Now build everything
+$ !
+$ @VMS.MAK 'P1 'P2 'P3 'P4 'P5 'P6 'P7 'P8
+$ !
+$ !
+$ ! Cleanup
+$ !
+$ IF F$LOGICAL("DECC$USER_INCLUDE") .NES. "" THEN DEASSIGN DECC$USER_INCLUDE
+$ IF F$LOGICAL("DECC$SYSTEM_INCLUDE") .NES. "" THEN DEASSIGN DECC$SYSTEM_INCLUDE
+$ IF F$LOGICAL("SYS") .NES. "" THEN DEASSIGN SYS
+$ IF F$SEARCH("RTL.OPT") .NES. "" THEN DELETE RTL.OPT;*
+$ !
+$ ! ALL DONE
+$ !
+$ VERIFY = F$VERIFY(VERIFY)
diff --git a/gs/src/vms-gcc.mak b/gs/src/vms-gcc.mak
new file mode 100644
index 000000000..bf114325c
--- /dev/null
+++ b/gs/src/vms-gcc.mak
@@ -0,0 +1,99 @@
+$ ! Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+$ !
+$ ! This file is part of Aladdin Ghostscript.
+$ !
+$ ! Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+$ ! or distributor accepts any responsibility for the consequences of using it,
+$ ! or for whether it serves any particular purpose or works at all, unless he
+$ ! or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+$ ! License (the "License") for full details.
+$ !
+$ ! Every copy of Aladdin Ghostscript must include a copy of the License,
+$ ! normally in a plain ASCII text file named PUBLIC. The License grants you
+$ ! the right to copy, modify and redistribute Aladdin Ghostscript, but only
+$ ! under certain conditions described in the License. Among other things, the
+$ ! License requires that the copyright notice and this notice be preserved on
+$ ! all copies.
+$ !
+$ !
+$ ! "makefile" for Ghostscript, VMS / GNU C / DECwindows (X11) configuration.
+$ !
+$ !
+$ ! Execute this command file while in the Ghostscript directory!
+$ !
+$ !
+$ ! To build a debugging configuration, issue the command:
+$ !
+$ ! $ @VMS-GCC.MAK DEBUG
+$ !
+$ ! Do not abbreviate "DEBUG". To specify an alternate directory for
+$ ! GS_LIB_DEFAULT, issue the command:
+$ !
+$ ! $ @VMS-GCC.MAK directory
+$ !
+$ ! with "directory" a fully qualified directory name. "directory" cannot
+$ ! be DEBUG (otherwise it will be confused with the DEBUG switch). Both
+$ ! the DEBUG switch and a directory name may be specified on the same
+$ ! command line and in either order.
+$ !
+$ !
+$ ! Declare local DCL symbols used by VMS.MAK
+$ !
+$ CC_QUAL = "" ! Qualifiers for the compile comand
+$ L_QUAL = "" ! Qualifiers for the link command
+$ CC_COMMAND = "GCC" ! Compile command
+$ X_INCLUDE = F$TRNLNM("SYS$COMMON") ! Used to find path to X11 include files
+$ !
+$ GS_DOCDIR = F$ENVIRONMENT("DEFAULT")
+$ GS_INIT = "GS_INIT.PS"
+$ GS_LIB_DEFAULT = F$ENVIRONMENT("DEFAULT")
+$ SEARCH_HERE_FIRST = 1
+$ CONFIG = ""
+$ FEATURE_DEVS = "level2.dev pdf.dev"
+$ COMPILE_INITS = "0"
+$ BAND_LIST_STORAGE = "file"
+$ BAND_LIST_COMPRESSOR = "zlib"
+$ FILE_IMPLEMENTATION = "stdio"
+$ DEVICE_DEVS = "x11.dev x11alpha.dev x11cmyk.dev x11mono.dev"
+$ DEVICE_DEVS3 = "deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev"
+$ DEVICE_DEVS4 = "cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev"
+$ DEVICE_DEVS6 = "bj10e.dev bj200.dev bjc600.dev bjc800.dev"
+$ DEVICE_DEVS7 = "faxg3.dev faxg32d.dev faxg4.dev"
+$ DEVICE_DEVS8 = "pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev"
+$ DEVICE_DEVS9 = "pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev"
+$ DEVICE_DEVS10 = "tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev"
+$ DEVICE_DEVS11 = "tiff12nc.dev tiff24nc.dev"
+$ DEVICE_DEVS12 = "psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev"
+$ DEVICE_DEVS13 = "pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev"
+$ DEVICE_DEVS14 = "jpeg.dev jpeggray.dev"
+$ DEVICE_DEVS15 = "pdfwrite.dev"
+$ !
+$ !
+$ ! Is GNU C about and defined?
+$ !
+$ IF F$TRNLNM("GNU_CC") .NES. "" THEN GOTO GNU_CC_OKAY
+$ WRITE SYS$OUTPUT "GNU_CC logical is undefined. You must execute the command"
+$ WRITE SYS$OUTPUT "file GCC_INSTALL.COM in the GNU CC directory before using"
+$ WRITE SYS$OUTPUT "this command file."
+$ EXIT
+$ !
+$ GNU_CC_OKAY:
+$ !
+$ ! Option file to use when linking genarch.c
+$ !
+$ SET COMMAND GNU_CC:[000000]GCC.CLD
+$ CREATE RTL.OPT
+GNU_CC:[000000]GCCLIB.OLB/LIBRARY
+SYS$SHARE:VAXCRTL.EXE/SHARE
+$ !
+$ !
+$ ! Now build everything
+$ !
+$ @VMS.MAK 'P1 'P2 'P3
+$ !
+$ !
+$ ! Cleanup
+$ !
+$ IF F$SEARCH("RTL.OPT") .NES. "" THEN DELETE RTL.OPT;*
+$ !
+$ ! ALL DONE
diff --git a/gs/src/vms.mak b/gs/src/vms.mak
new file mode 100644
index 000000000..965da58b4
--- /dev/null
+++ b/gs/src/vms.mak
@@ -0,0 +1,2245 @@
+$ ! Copyright (C) 1997, 1998 Aladdin Enterprises.
+$ ! All rights reserved.
+$ !
+$ ! This file is part of Aladdin Ghostscript.
+$ !
+$ ! Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+$ ! or distributor accepts any responsibility for the consequences of using it,
+$ ! or for whether it serves any particular purpose or works at all, unless he
+$ ! or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+$ ! License (the "License") for full details.
+$ !
+$ ! Every copy of Aladdin Ghostscript must include a copy of the License,
+$ ! normally in a plain ASCII text file named PUBLIC. The License grants you
+$ ! the right to copy, modify and redistribute Aladdin Ghostscript, but only
+$ ! under certain conditions described in the License. Among other things, the
+$ ! License requires that the copyright notice and this notice be preserved on
+$ ! all copies.
+$ !
+$ !
+$ ! VMS "makefile" for Ghostscript.
+$ !
+$ WSO = "WRITE SYS$OUTPUT"
+$ ON ERROR THEN GOTO DONE
+$ ON CONTROL_Y THEN GOTO DONE
+$ !
+$ ! Version numbers.
+$ ! MINOR0 is different from MINOR only if MINOR is a single digit.
+$ !
+$ GS_VERSION_MAJOR = "5"
+$ GS_VERSION_MINOR = "12"
+$ GS_VERSION_MINOR0 = "12"
+$ ! Revision date: year x 10000 + month x 100 + day.
+$ GS_REVISIONDATE = "19980414"
+$ ! Derived values
+$ GS_VERSION = GS_VERSION_MAJOR + GS_VERSION_MINOR0
+$ GS_DOT_VERSION = GS_VERSION_MAJOR + "." + GS_VERSION_MINOR
+$ GS_REVISION = GS_VERSION
+$ JSRCDIR = "[.jpeg-6a]"
+$ JVERSION = 6
+$!!! PSRCDIR = "[.libpng-0_89c]"
+$!!! PVERSION = 89
+$ PSRCDIR = "[.libpng-0_96]"
+$ PVERSION = 96
+$ ZSRCDIR = "[.zlib-1_0_4]"
+$
+$ !
+$ ! Check input parameters
+$ !
+$ IF P1 .NES. "" .AND. P1 .NES. "DEBUG" .AND. P1 .NES. "LINK" .AND. -
+ P1 .NES. "BUILD" .AND. F$EXTRACT(0,5,P1) .NES. "FROM=" THEN -
+ GS_LIB_DEFAULT = P1
+$ IF P2 .NES. "" .AND. P2 .NES. "DEBUG" .AND. P2 .NES. "LINK" .AND. -
+ P2 .NES. "BUILD" .AND. F$EXTRACT(0,5,P2) .NES. "FROM=" THEN -
+ GS_LIB_DEFAULT = P2
+$ !
+$ IF P1 .NES. "DEBUG" .AND. P2 .NES. "DEBUG" THEN GOTO NODEBUG
+$ CC_QUAL = CC_QUAL + "/NOOPT/DEBUG"
+$ IF CC_DEF .NES. "" THEN CC_DEF= CC_DEF + ","
+$ CC_DEF= CC_DEF + "DEBUG"
+$ L_QUAL = (L_QUAL-"/NOTRACEBACK") + "/DEBUG"
+$ !
+$ NODEBUG:
+$ IF CC_DEF .NES. "" THEN CC_QUAL= CC_QUAL + "/DEFINE=(" + CC_DEF + ")"
+$ If P1 .EQS. "LINK" .OR. P2 .EQS. "LINK" THEN GOTO LINK_ONLY
+$ If P1 .EQS. "BUILD" .OR. P2 .EQS. "BUILD" THEN GOTO BUILD_EXES
+$ FROM = ""
+$ IF F$EXTRACT(0,5,P1) .EQS. "FROM=" THEN FROM = F$EXTRACT(5,F$LENGTH(P1)-5,P1)
+$ IF F$EXTRACT(0,5,P2) .EQS. "FROM=" THEN FROM = F$EXTRACT(5,F$LENGTH(P2)-5,P2)
+$ INSREP = "INSERT"
+$ IF FROM .NES. "" THEN INSREP = "REPLACE"
+$ !
+$ !
+$ ! Compile and link genarch.c and then run it to create the arch.h header file
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=GENARCH.OBJ GENARCH.C"
+$ 'CC_COMMAND''CC_QUAL'/NOLIST/OBJECT=GENARCH.OBJ GENARCH.C
+$ LINK/NOMAP/EXE=GENARCH.EXE GENARCH.OBJ,RTL.OPT/OPT
+$ GENARCH = "$" + F$ENVIRONMENT("DEFAULT") + "GENARCH.EXE"
+$ GENARCH ARCH.H
+$ DELETE GENARCH.EXE.*,GENARCH.OBJ.*
+$ PURGE ARCH.H
+$ !
+$ !
+$ ! Compile and link echogs.c; define ECHOGS as a command
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=ECHOGS.OBJ ECHOGS.C"
+$ 'CC_COMMAND''CC_QUAL'/NOLIST/OBJECT=ECHOGS.OBJ ECHOGS.C
+$ LINK/NOMAP/EXE=ECHOGS.EXE ECHOGS.OBJ,RTL.OPT/OPT
+$ ECHOGS = "$" + F$ENVIRONMENT("DEFAULT") + "ECHOGS.EXE"
+$ DELETE ECHOGS.OBJ;*
+$ PURGE ECHOGS.EXE
+$ !
+$ !
+$ ! Compile and link genconf.c; define GENCONF as a command
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL/NOLIST/OBJECT=GENCONF.OBJ GENCONF.C"
+$ 'CC_COMMAND''CC_QUAL'/NOLIST/OBJECT=GENCONF.OBJ GENCONF.C
+$ LINK/NOMAP/EXE=GENCONF.EXE GENCONF.OBJ,RTL.OPT/OPT
+$ GENCONF = "$" + F$ENVIRONMENT("DEFAULT") + "GENCONF.EXE"
+$ DELETE GENCONF.OBJ;*
+$ PURGE GENCONF.EXE
+$ !
+$ !
+$ ! Create GSSETDEV.COM, GSSETMOD.COM, and GSADDMOD.COM.
+$ ! (These aren't distributed with the fileset because the .COM suffix
+$ ! causes certain development tools to treat them incorrectly.)
+$ !
+$ !
+$ OPEN/WRITE SETDEV GSSETDEV.COM
+$ WRITE SETDEV "$ echogs -w 'p1'.dev - -dev 'p1' -obj 'p2 'p3 'p4 'p5 'p6 'p7 'p8"
+$ CLOSE SETDEV
+$ !
+$ OPEN/WRITE SETMOD GSSETMOD.COM
+$ WRITE SETMOD "$ if p2 .nes. """""
+$ WRITE SETMOD "$ then"
+$ WRITE SETMOD "$ echogs -w 'p1'.dev - 'p2 'p3 'p4 'p5 'p6 'p7 'p8"
+$ WRITE SETMOD "$ else"
+$ WRITE SETMOD "$ echogs -w 'p1'.dev"
+$ WRITE SETMOD "$ endif"
+$ CLOSE SETMOD
+$ !
+$ OPEN/WRITE ADDMOD GSADDMOD.COM
+$ WRITE ADDMOD "$ if (p2 .nes. """") then echogs -a 'p1'.dev - 'p2 'p3 'p4 'p5 'p6 'p7 'p8"
+$ CLOSE ADDMOD
+$ !
+$ !
+$ ! Define SETDEV, SETMOD, ADDMOD as commands to execute GSSETDEV.COM,
+$ ! GSSETMOD.COM and GSADDMOD.COM respectively. Those three command
+$ ! procedures make use of ECHOGS.EXE and the ECHOGS verb.
+$ !
+$ SETDEV = "@GSSETDEV.COM"
+$ SETMOD = "@GSSETMOD.COM"
+$ ADDMOD = "@GSADDMOD.COM"
+$ !
+$ !
+$ ! Build GCONFIG_.H
+$ !
+$ ECHOGS -w gconfig_.h #define HAVE_SYS_TIME_H
+$ !
+$ ! Build GCONFIGV.H
+$ !
+$ ECHOGS -w gconfigv.h #define USE_ASM 0
+$ ECHOGS -a gconfigv.h #define USE_FPU 1
+$ ECHOGS -a gconfigv.h #define EXTEND_NAMES 0
+$ !
+$ ! Now generate *.dev files
+$ !
+$ DEV_LIST_NAMES = "FEATURE_DEVS DEVICE_DEVS DEVICE_DEVS1 DEVICE_DEVS2 DEVICE_DEVS3 DEVICE_DEVS4 DEVICE_DEVS5 DEVICE_DEVS6 DEVICE_DEVS7 DEVICE_DEVS8 DEVICE_DEVS9 DEVICE_DEVS10 DEVICE_DEVS11 DEVICE_DEVS12 DEVICE_DEVS13 DEVICE_DEVS14 DEVICE_DEVS15"
+$ NDEV_MOD = 0
+$ DEV_MODULES = " "
+$ I = 0
+$ ON WARNING THEN GOTO NO_ACTION
+$ DEVS_OUTER:
+$ DEV_LIST = F$ELEMENT(I," ",DEV_LIST_NAMES)
+$ IF DEV_LIST .EQS. " " THEN GOTO DEVS_DONE
+$ I = I+1
+$ IF F$TYPE('DEV_LIST') .EQS. "" THEN GOTO DEVS_OUTER
+$ IF F$EDIT('DEV_LIST',"COLLAPSE") .EQS. "" THEN GOTO DEVS_OUTER
+$ J = 0
+$ DEVS_INNER:
+$ ACTION = F$ELEMENT(J," ",'DEV_LIST')
+$ IF ACTION .EQS. " " THEN GOTO DEVS_OUTER
+$ J = J+1
+$ ! Replace "." with "_"
+$ IF F$LOCATE(".",ACTION) .NE. F$LENGTH(ACTION) THEN -
+$ ACTION = F$ELEMENT(0,".",ACTION) + "_" + F$ELEMENT(1,".",ACTION)
+$ GOSUB 'ACTION'
+$ GOTO DEVS_INNER
+$ !
+$ DEVS_DONE:
+$ ON WARNING THEN CONTINUE
+$ !
+$ !
+$ ! And now build gconfig.h and gconfigf.h
+$ !
+$ GOSUB GCONFIG_H
+$ GOSUB GCONFIGF_H
+$ !
+$ DEV_MODULES = F$EDIT(DEV_MODULES,"TRIM")
+$ DEV_MODULES'NDEV_MOD' = F$EDIT(DEV_MODULES,"COMPRESS")
+$ IF F$LENGTH(DEV_MODULES'NDEV_MOD') .EQ. 0 THEN NDEV_MOD = NDEV_MOD - 1
+$ !
+$ ! Create an empty object library if compilation is started from the beginning.
+$ !
+$ IF FROM .EQS. "" THEN LIBRARY/CREATE GS.OLB
+$ !
+$ ! Now compile device modules found in the DEV_MODULES symbols
+$ !
+$ DEFDIR = F$PARSE(F$ENVIRONMENT("DEFAULT"),,,"DIRECTORY","SYNTAX_ONLY")
+$ OPEN/WRITE OPT_FILE GS.OPT
+$ OPT_LINE = "GS.OLB/LIBRARY/INCLUDE=("
+$ COMMA = ""
+$ !
+$ I = 0
+$ IDEV = 0
+$ OUTER_DEV_LOOP:
+$ DEV_MODULES = F$EDIT(DEV_MODULES'IDEV',"TRIM")
+$ COMPILE_LOOP:
+$ MODULE = F$ELEMENT(I," ",DEV_MODULES)
+$ IF MODULE .EQS. " " THEN GOTO END_COMPILE
+$ I = I + 1
+$ NAME = F$PARSE(MODULE,,,"NAME","SYNTAX_ONLY")
+$ IF NAME .EQS. FROM THEN FROM= ""
+$ IF FROM .NES. "" THEN GOTO MOD_COMPILED
+$ DIR = F$PARSE(MODULE,,,"DIRECTORY","SYNTAX_ONLY") - DEFDIR
+$ IF DIR .NES. ""
+$ THEN
+$ COPY 'MODULE'.C []
+$ INC = "/INCLUDE=(''DEFDIR',''DIR')"
+$ ELSE
+$ INC = ""
+$ ENDIF
+$ WSO "''CC_COMMAND'''CC_QUAL'''INC'/NOLIST/OBJECT=''NAME'.OBJ ''MODULE'.C"
+$ 'CC_COMMAND''CC_QUAL''INC'/NOLIST/OBJECT='NAME'.OBJ 'NAME'.C
+$ LIBRARY/'INSREP' GS.OLB 'NAME'.OBJ
+$ DELETE 'NAME'.OBJ.*
+$ IF DIR .NES. "" THEN DELETE 'NAME'.C;
+$ MOD_COMPILED:
+$ IF F$LENGTH(OPT_LINE) .GE. 70
+$ THEN
+$ OPT_LINE = OPT_LINE + COMMA + "-"
+$ WRITE OPT_FILE OPT_LINE
+$ OPT_LINE = NAME
+$ ELSE
+$ OPT_LINE = OPT_LINE + COMMA + NAME
+$ ENDIF
+$ COMMA = ","
+$ GOTO COMPILE_LOOP
+$ !
+$ END_COMPILE:
+$ I = 0
+$ IDEV = IDEV + 1
+$ IF IDEV .LE. NDEV_MOD THEN GOTO OUTER_DEV_LOOP
+$ !
+$ OPT_LINE = OPT_LINE + ")"
+$ WRITE OPT_FILE OPT_LINE
+$ IF F$SEARCH("SYS$SHARE:DECW$XMLIBSHR12.EXE") .NES. ""
+$ THEN
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XMLIBSHR12.EXE/SHARE"
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XTLIBSHRR5.EXE/SHARE"
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XLIBSHR.EXE/SHARE"
+$ ELSE
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XMLIBSHR.EXE/SHARE"
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XTSHR.EXE/SHARE"
+$ WRITE OPT_FILE "SYS$SHARE:DECW$XLIBSHR.EXE/SHARE"
+$ ENDIF
+$ WRITE OPT_FILE "Ident=""gs ''GS_DOT_VERSION'"""
+$ CLOSE OPT_FILE
+$ !
+$ !
+$ ! Is the DECwindows environment about? Must be installed in order to
+$ ! build the executable program gs.exe.
+$ !
+$ IF F$SEARCH("SYS$SHARE:DECW$XLIBSHR.EXE") .NES. "" THEN GOTO CHECK2
+$ WSO "DECwindows user environment not installed;"
+$ WSO "unable to build executable programs."
+$ GOTO DONE
+$ !
+$ CHECK2:
+$ IF F$TRNLNM("DECW$INCLUDE") .NES. "" THEN GOTO BUILD_EXES
+$ WSO "You must invoke @DECW$STARTUP before using this"
+$ WSO "command procedure to build the executable programs."
+$ GOTO DONE
+$ !
+$ ! Build the executables
+$ !
+$ BUILD_EXES:
+$ !
+$ DEFINE X11 DECW$INCLUDE
+$ !
+$ LINK_ONLY:
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=GCONFIG.OBJ GCONF.C"
+$ 'CC_COMMAND''CC_QUAL/NOLIST/OBJECT=GCONFIG.OBJ GCONF.C
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=ICONFIG.OBJ ICONF.C"
+$ 'CC_COMMAND''CC_QUAL/NOLIST/OBJECT=ICONFIG.OBJ ICONF.C
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=ICCINIT0.OBJ ICCINIT0.C"
+$ 'CC_COMMAND''CC_QUAL/NOLIST/OBJECT=ICCINIT0.OBJ ICCINIT0.C
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=GSCDEFS.OBJ GSCDEF.C"
+$ 'CC_COMMAND''CC_QUAL/NOLIST/OBJECT=GSCDEFS.OBJ GSCDEF.C
+$ !
+$ WSO "''CC_COMMAND'''CC_QUAL'/NOLIST/OBJECT=GS.OBJ GS.C"
+$ 'CC_COMMAND''CC_QUAL/NOLIST/OBJECT=GS.OBJ GS.C
+$ !
+$ WSO "Linking ... "
+$ WSO "LINK''L_QUAL'/NOMAP/EXE=GS.EXE GS,GCONFIG,ICONFIG,ICCINIT0,GSCDEFS,GS.OPT/OPT"
+$ LINK'L_QUAL/NOMAP/EXE=GS.EXE GS,GCONFIG,ICONFIG,ICCINIT0,GSCDEFS,GS.OPT/OPT
+$ !
+$ IF P1 .EQS. "LINK" THEN GOTO AFTER_DEL
+$ DELETE GS.OBJ.*,GCONFIG.OBJ.*,ICONFIG.OBJ.*,ICCINIT0.OBJ.*,GSCDEFS.OBJ.*
+$ !
+$ GOTO DONE
+$ !
+$ !
+$ DEVS_TR:
+$ ! quote the dashes so that they are not interpreted as continuation
+$ ! marks when the following DCL symbol is not defined!
+$ ECHOGS -w devs.tr "-" -include vms_.dev
+$ ECHOGS -a devs.tr "-" 'FEATURE_DEVS'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS1'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS2'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS3'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS4'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS5'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS6'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS7'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS8'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS9'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS10'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS11'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS12'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS13'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS14'
+$ ECHOGS -a devs.tr "-" 'DEVICE_DEVS15'
+$ RETURN
+$ !
+$ GCONFIG_H:
+$ GOSUB DEVS_TR
+$ GOSUB VMS_DEV
+$ GOSUB LIBCORE_DEV
+$ GENCONF "devs.tr" libcore.dev -h gconfig.h
+$ ECHOGS -a gconfig.h "#define GS_LIB_DEFAULT ""''GS_LIB_DEFAULT'"""
+$ ECHOGS -a gconfig.h "#define SEARCH_HERE_FIRST ''SEARCH_HERE_FIRST'"
+$ ECHOGS -a gconfig.h "#define GS_DOCDIR ""''GS_DOCDIR'"""
+$ ECHOGS -a gconfig.h "#define GS_INIT ""''GS_INIT'"""
+$ ECHOGS -a gconfig.h "#define GS_REVISION ''GS_REVISION'"
+$ ECHOGS -a gconfig.h "#define GS_REVISIONDATE ''GS_REVISIONDATE'"
+$ RETURN
+$ !
+$ BBOX_DEV:
+$ SETMOD bbox "gdevbbox.obj"
+$ ADD_DEV_MODULES = "gdevbbox.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! The render/RGB device is only here as an example, but we can configure
+$! it as a real device for testing.
+$ RRGB_DEV:
+$ SETDEV rrgb "gdevrrgb.obj"
+$ ADD_DEV_MODULES = "gdevrrgb.obj gdevprn.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LIBS_DEV:
+$ LIB1s = "gsalloc.obj gsbitops.obj gsbittab.obj"
+$ LIB2s = "gschar.obj gscolor.obj gscoord.obj gsdevice.obj gsdevmem.obj"
+$ LIB3s = "gsdparam.obj gsfont.obj gsht.obj gshtscr.obj"
+$ LIB4s = "gsimage.obj gsimpath.obj gsinit.obj gsiodev.obj"
+$ LIB5s = "gsline.obj gsmatrix.obj gsmemory.obj gsmisc.obj"
+$ LIB6s = "gspaint.obj gsparam.obj gspath.obj gsstate.obj gsutil.obj"
+$ LIBs = "''LIB1s' ''LIB2s' ''LIB3s' ''LIB4s' ''LIB5s' ''LIB6s'"
+$ echogs -w libs.dev 'LIB1s'
+$ echogs -a libs.dev 'LIB2s'
+$ echogs -a libs.dev 'LIB3s'
+$ echogs -a libs.dev 'LIB4s'
+$ echogs -a libs.dev 'LIB5s'
+$ echogs -a libs.dev 'LIB6s'
+$ ADDMOD libs -init gscolor
+$ ADD_DEV_MODULES = "''LIBs'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LIBX_DEV:
+$ LIB1x = "gxacpath.obj gxbcache.obj"
+$ LIB2x = "gxccache.obj gxccman.obj gxcht.obj gxcmap.obj gxcpath.obj"
+$ LIB3x = "gxdcconv.obj gxdcolor.obj gxdither.obj gxfill.obj gxht.obj"
+$ LIB4x = "gximage.obj gximage0.obj gximage1.obj gximage2.obj"
+$ LIB5x = "gxpaint.obj gxpath.obj gxpath2.obj gxpcopy.obj"
+$ LIB6x = "gxpdash.obj gxpflat.obj gxsample.obj gxstroke.obj"
+$ LIBx = "''LIB1x' ''LIB2x' ''LIB3x' ''LIB4x' ''LIB5x' ''LIB6x'"
+$ echogs -w libx.dev 'LIB1x'
+$ echogs -a libx.dev 'LIB2x'
+$ echogs -a libx.dev 'LIB3x'
+$ echogs -a libx.dev 'LIB4x'
+$ echogs -a libx.dev 'LIB5x'
+$ echogs -a libx.dev 'LIB6x'
+$ addmod libx -init gximage1 gximage2
+$ ADD_DEV_MODULES = "''LIBx'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LIBD_DEV:
+$ LIB1d = "gdevabuf.obj gdevddrw.obj gdevdflt.obj gdevnfwd.obj"
+$ LIB2d = "gdevmem.obj gdevm1.obj gdevm2.obj gdevm4.obj gdevm8.obj"
+$ LIB3d = "gdevm16.obj gdevm24.obj gdevm32.obj gdevmpla.obj"
+$ LIBd = "''LIB1d' ''LIB2d' ''LIB3d'"
+$ echogs -w libd.dev 'LIB1d'
+$ echogs -a libd.dev 'LIB2d'
+$ echogs -a libd.dev 'LIB3d'
+$ ADD_DEV_MODULES = "''LIBd'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LIBCORE_DEV:
+$ GOSUB LIBS_DEV
+$ GOSUB LIBX_DEV
+$ GOSUB LIBD_DEV
+$ GOSUB ISCALE_DEV
+$ GOSUB ROPLIB_DEV
+$ SETMOD libcore
+$ ADDMOD libcore -dev nullpage
+$ ADDMOD libcore -include libs libx libd iscale roplib
+$ RETURN
+$ !
+$! ---------------- File streams ---------------- #
+$ SFILE_DEV:
+$ sfile_="sfx''FILE_IMPLEMENTATION'.obj stream.obj"
+$ SETMOD sfile "''sfile_'"
+$ ADD_DEV_MODULES = "''sfile_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CFE_DEV:
+$ IF F$TYPE(cfe_) .NES. "" THEN RETURN
+$ cfe_ = "scfe.obj scfetab.obj shc.obj"
+$ SETMOD cfe 'cfe_'
+$ ADD_DEV_MODULES = "''cfe_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CFD_DEV:
+$ IF F$TYPE(cfd_) .NES. "" THEN RETURN
+$ cfd_ = "scfd.obj scfdtab.obj"
+$ SETMOD cfd 'cfd_'
+$ ADD_DEV_MODULES = "''cfd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- DCT (JPEG) filters ---------------- #
+$! These are used by Level 2, and by the JPEG-writing driver.
+$! Encoding (compression)
+$ SDCTE_DEV:
+$ IF F$TYPE(sdcte_) .NES. "" THEN RETURN
+$ sdcte_ = "sdctc.obj sjpegc.obj sdcte.obj sjpege.obj"
+$ GOSUB JPEGE_DEV
+$ SETMOD sdcte 'sdcte_'
+$ ADDMOD sdcte -include jpege
+$ ADD_DEV_MODULES = "''sdcte_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Decoding (decompression)
+$ SDCTD_DEV:
+$ IF F$TYPE(sdctd_) .NES. "" THEN RETURN
+$ sdctd_="sdctc.obj sjpegc.obj sdctd.obj sjpegd.obj"
+$ GOSUB JPEGD_DEV
+$ SETMOD sdctd 'sdctd_'
+$ ADDMOD sdctd -include jpegd
+$ ADD_DEV_MODULES = "''sdctd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- LZW filters ---------------- #
+$! These are used by Level 2 in general.
+$ LZWE_DEV:
+$ IF F$TYPE(lzwe_) .NES. "" THEN RETURN
+$ lzwe_ = "slzwce.obj slzwc.obj"
+$ SETMOD lzwe 'lzwe_'
+$ ADD_DEV_MODULES = "''lzwe_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SLZWE_DEV:
+$ COPY LZWE.DEV SLZWE.DEV
+$ RETURN
+$ !
+$ LZWD_DEV:
+$ IF F$TYPE(lzwd_) .NES. "" THEN RETURN
+$ lzwd_ = "slzwd.obj slzwc.obj"
+$ SETMOD lzwd 'lzwd_'
+$ ADD_DEV_MODULES = "''lzwd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SLZWD_DEV:
+$ COPY LZWD.DEV SLZWD.DEV
+$ RETURN
+$ !
+$ PCXD_DEV:
+$ pcxd_ = "spcxd.obj"
+$ SETMOD pcxd 'pcxd_'
+$ ADD_DEV_MODULES = "''pcxd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PDIFF_DEV:
+$ pdiff_ = "spdiff.obj"
+$ SETMOD pdiff 'pdiff_'
+$ ADD_DEV_MODULES = "''pdiff_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PNGP_DEV:
+$ pngp_ = "spngp.obj"
+$ SETMOD pngp 'pngp_'
+$ ADD_DEV_MODULES = "''pngp_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ RLE_DEV:
+$ IF F$TYPE(rle_) .NES. "" THEN RETURN
+$ rle_ = "srle.obj"
+$ SETMOD rle 'rle_'
+$ ADD_DEV_MODULES = "''rle_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ RLD_DEV:
+$ IF F$TYPE(rld_) .NES. "" THEN RETURN
+$ rld_ = "srld.obj"
+$ SETMOD rld 'rld_'
+$ ADD_DEV_MODULES = "''rld_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SZLIBE_DEV:
+$ IF F$TYPE(szlibe_) .NES. "" THEN RETURN
+$ szlibe_ = "szlibc.obj szlibe.obj"
+$ GOSUB ZLIBE_DEV
+$ SETMOD szlibe 'szlibe_'
+$ ADDMOD szlibe -include zlibe
+$ ADD_DEV_MODULES = "''szlibe_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SZLIBD_DEV:
+$ IF F$TYPE(szlibd_) .NES. "" THEN RETURN
+$ szlibd_ = "szlibc.obj szlibd.obj"
+$ GOSUB ZLIBD_DEV
+$ SETMOD szlibd 'szlibd_'
+$ ADDMOD szlibd -include zlibd
+$ ADD_DEV_MODULES = "''szlibd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Command list package. Currently the higher-level facilities are required,
+$! but eventually they will be optional.
+$ CLIST_DEV:
+$ IF F$TYPE(CLIST_DONE) .NES. "" THEN RETURN
+$ GOSUB CLBASE_DEV
+$ GOSUB CLPATH_DEV
+$ SETMOD clist -include clbase clpath
+$ CLIST_DONE = 1
+$ RETURN
+$ !
+$! Base command list facility
+$ CLBASE_DEV:
+$ IF F$TYPE(clbase_) .NES. "" THEN RETURN
+$ clbase1_ = "gxclist.obj gxclbits.obj gxclpage.obj"
+$ clbase2_ = "gxclread.obj gxclrect.obj stream.obj"
+$ clbase_ = "''clbase1_' ''clbase2_'"
+$ GOSUB CL'BAND_LIST_STORAGE'_DEV
+$ GOSUB CFE_DEV
+$ GOSUB CFD_DEV
+$ GOSUB RLE_DEV
+$ GOSUB RLD_DEV
+$ SETMOD clbase 'clbase1_'
+$ ADDMOD clbase -obj 'clbase2_'
+$ ADDMOD clbase -include cl'BAND_LIST_STORAGE' cfe cfd rle rld
+$ ADD_DEV_MODULES = "''clbase_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Higher-level command list facilities.
+$ CLPATH_DEV:
+$ IF F$TYPE(clpath_) .NES. "" THEN RETURN
+$ clpath_ = "gxclimag.obj gxclpath.obj"
+$ GOSUB PSL2CS_DEV
+$ SETMOD clpath 'clpath_'
+$ ADDMOD clpath -include psl2cs
+$ ADDMOD clpath -init climag clpath
+$ ADD_DEV_MODULES = "''clpath_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CLFILE_DEV:
+$ IF F$TYPE(clfile_) .NES. "" THEN RETURN
+$ clfile_ = "gxclfile.obj"
+$ SETMOD clfile 'clfile_'
+$ ADD_DEV_MODULES = "''clfile_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CLMEMORY_DEV:
+$ IF F$TYPE(clmemory_) .NES. "" THEN RETURN
+$ clmemory_ = "gxclmem.obj gxcl'BAND_LIST_COMPRESSOR'.obj"
+$ GOSUB S'BAND_LIST_COMPRESSOR'E_DEV
+$ GOSUB S'BAND_LIST_COMPRESSOR'D_DEV
+$ SETMOD clmemory 'clmemory_'
+$ ADDMOD clmemory -include S'BAND_LIST_COMPRESSOR'E S'BAND_LIST_COMPRESSOR'D
+$ ADDMOD clmemory init cl_'BAND_LIST_COMPRESSOR'
+$ ADD_DEV_MODULES = "''clmemory_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ VECTOR_DEV:
+$ IF F$TYPE(vector_) .NES. "" THEN RETURN
+$ vector_ = "gdevvec.obj"
+$ GOSUB BBOX_DEV
+$ GOSUB SFILE_DEV
+$ SETMOD vector "''vector_'"
+$ ADDMOD vector -include bbox sfile
+$ ADD_DEV_MODULES = "''vector_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ ISCALE_DEV:
+$ iscale_ = "siscale.obj"
+$ SETMOD iscale 'iscale_'
+$ ADD_DEV_MODULES = "''iscale_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ ROPLIB_DEV:
+$ roplib_ = "gdevmrop.obj gsrop.obj gsroptab.obj"
+$ SETMOD roplib 'roplib_'
+$ ADDMOD roplib -init roplib
+$ ADD_DEV_MODULES = "''roplib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! -------- Composite (PostScript Type 0) font support -------- #
+$ CMAPLIB_DEV:
+$ cmaplib_="gsfcmap.obj"
+$ SETMOD cmaplib "''cmaplib_'"
+$ ADD_DEV_MODULES = "''cmaplib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PSF0LIB_DEV:
+$ psf0lib_ = "gschar0.obj gsfont0.obj"
+$ GOSUB CMAPLIB_DEV
+$ SETMOD psf0lib 'psf0lib_'
+$ ADDMOD psf0lib -include cmaplib
+$ ADD_DEV_MODULES = "''psf0lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Pattern color ---------------- #
+$ PATLIB_DEV:
+$ patlib_ = "gspcolor.obj gxclip2.obj gxpcmap.obj"
+$ GOSUB CMYKLIB_DEV
+$ GOSUB PSL2CS_DEV
+$ SETMOD patlib -include cmyklib psl2cs
+$ ADDMOD patlib -obj 'patlib_'
+$ ADD_DEV_MODULES = "''patlib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+$ TYPE1LIB_INI:
+$ IF F$TYPE(type1lib_) .NES. "" THEN RETURN
+$ type1lib_= "gxtype1.obj gxhint1.obj gxhint2.obj gxhint3.obj"
+$ ADD_DEV_MODULES = "''type1lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Type 1 charstrings
+$ PSF1LIB_DEV:
+$ IF F$TYPE(psf1lib_) .NES. "" THEN RETURN
+$ GOSUB TYPE1LIB_INI
+$ psf1lib_ = "gstype1.obj"
+$ SETMOD psf1lib 'psf1lib_'
+$ ADDMOD psf1lib 'type1lib_'
+$ ADDMOD psf1lib -init gstype1
+$ ADD_DEV_MODULES = "''psf1lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Type 2 charstrings
+$ PSF2LIB_DEV:
+$ IF F$TYPE(psf2lib_) .NES. "" THEN RETURN
+$ GOSUB TYPE1LIB_INI
+$ psf2lib_ = "gstype2.obj"
+$ SETMOD psf2lib 'psf2lib_'
+$ ADDMOD psf2lib 'type1lib_'
+$ ADDMOD psf2lib -init gstype2
+$ ADD_DEV_MODULES = "''psf2lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+$ TTFLIB_DEV:
+$ IF F$TYPE(ttflib_) .NES. "" THEN RETURN
+$ ttflib_ = "gstype42.obj"
+$ SETMOD ttflib 'ttflib_'
+$ ADD_DEV_MODULES = "''ttflib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CMYKLIB_DEV:
+$ IF F$TYPE(cmyklib_) .NES. "" THEN RETURN
+$ cmyklib_ = "gscolor1.obj gsht1.obj"
+$ SETMOD cmyklib 'cmyklib_'
+$ ADDMOD cmyklib -init gscolor1
+$ ADD_DEV_MODULES = "''cmyklib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ COLIMLIB_DEV:
+$ IF F$TYPE(colimlib_) .NES. "" THEN RETURN
+$ colimlib_ = "gximage3.obj"
+$ SETMOD colimlib 'colimlib_'
+$ ADDMOD colimlib -init gximage3
+$ ADD_DEV_MODULES = "''colimlib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ HSBLIB_DEV:
+$ hsblib_ = "gshsb.obj"
+$ SETMOD hsblib 'hsblib_'
+$ ADD_DEV_MODULES = "''hsblib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PATH1LIB_DEV:
+$ path1lib_ = "gspath1.obj"
+$ SETMOD path1lib 'path1lib_'
+$ ADD_DEV_MODULES = "''path1lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PSL2CS_DEV:
+$ IF F$TYPE(psl2cs_) .NES. "" THEN RETURN
+$ psl2cs_ = "gscolor2.obj"
+$ SETMOD psl2cs 'psl2cs_'
+$ ADD_DEV_MODULES = "''psl2cs_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PSL2LIB_DEV:
+$ IF F$TYPE(psl2lib_) .NES. "" THEN RETURN
+$ psl2lib_ = "gximage4.obj gximage5.obj"
+$ GOSUB COLIMLIB_DEV
+$ GOSUB PSL2CS_DEV
+$ SETMOD psl2lib 'psl2lib_'
+$ ADDMOD psl2lib -init gximage4 gximage5
+$ ADDMOD psl2lib -include colimlib psl2cs
+$ ADD_DEV_MODULES = "''psl2lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Display Postscript / Level 2 support ---------------- #
+$ DPS2LIB_DEV:
+$ IF F$TYPE(dps2lib_) .NES. "" THEN RETURN
+$ dps2lib_ = "gsdps1.obj"
+$ SETMOD dps2lib 'dps2lib_'
+$ ADD_DEV_MODULES = "''dps2lib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Display Postscript extensions ---------------- #
+$ DPSLIB_DEV:
+$ IF F$TYPE(dpslib_) .NES. "" THEN RETURN
+$ dpslib_ = "gsdps.obj"
+$ SETMOD dpslib 'dpslib_'
+$ ADD_DEV_MODULES = "''dpslib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- CIE color ---------------- #
+$ CIELIB_DEV:
+$ IF F$TYPE(cielib_) .NES. "" THEN RETURN
+$ cielib_ = "gscie.obj gxctable.obj"
+$ SETMOD cielib 'cielib_'
+$ ADD_DEV_MODULES = "''cielib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Separation colors ---------------- #
+$ SEPRLIB_DEV:
+$ seprlib_ = "gscsepr.obj"
+$ SETMOD seprlib 'seprlib_'
+$ ADD_DEV_MODULES = "''seprlib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Functions ---------------- #
+$! Generic support, and FunctionType 0.
+$ FUNCLIB_DEV:
+$ IF F$TYPE(funclib_) .NES. "" THEN RETURN
+$ funclib_ = "gsdsrc.obj gsfunc.obj gsfunc0.obj"
+$ SETMOD funclib "''funclib_'"
+$ ADD_DEV_MODULES = "''funclib_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ ISUPPORT_DEV:
+$ IF F$TYPE(isupport1_) .NES. "" THEN RETURN
+$ isupport1_ = "ialloc.obj igc.obj igcref.obj igcstr.obj"
+$ isupport2_ = "ilocate.obj iname.obj isave.obj"
+$ isupport_ = "''isupport1_' ''isupport2_'"
+$ SETMOD isupport 'isupport1_'
+$ ADDMOD isupport -obj 'isupport2_'
+$ ADDMOD isupport -init igcref
+$ ADD_DEV_MODULES = "''isupport_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PSBASE_DEV:
+$ IF F$TYPE(INT_CONFIG) .NES. "" THEN RETURN
+$ INT1 = "idebug.obj idict.obj idparam.obj"
+$ INT2 = "iinit.obj interp.obj iparam.obj ireclaim.obj"
+$ INT3 = "iscan.obj iscannum.obj istack.obj iutil.obj"
+$ INT4 = "scantab.obj sfilter1.obj sstring.obj stream.obj"
+$ Z1 = "zarith.obj zarray.obj zcontrol.obj zdict.obj"
+$ Z1OPS = "zarith zarray zcontrol zdict"
+$ Z2 = "zfile.obj zfileio.obj zfilter.obj zfname.obj zfproc.obj"
+$ Z2OPS = "zfile zfileio zfilter zfproc"
+$ Z3 = "zgeneric.obj ziodev.obj zmath.obj zmisc.obj zpacked.obj"
+$ Z3OPS = "zgeneric ziodev zmath zmisc zpacked"
+$ Z4 = "zrelbit.obj zstack.obj zstring.obj zsysvm.obj"
+$ Z4OPS = "zrelbit zstack zstring zsysvm"
+$ Z5 = "ztoken.obj ztype.obj zvmem.obj"
+$ Z5OPS = "ztoken ztype zvmem"
+$ Z6 = "zchar.obj zcolor.obj zdevice.obj zfont.obj zfont2.obj"
+$ Z6OPS = "zchar zcolor zdevice zfont zfont2"
+$ Z7 = "zgstate.obj zht.obj zimage.obj zmatrix.obj zpaint.obj zpath.obj"
+$ Z7OPS = "zgstate zht zimage zmatrix zpaint zpath"
+$ INT_OBJS = "imainarg.obj gsargs.obj imain.obj ''INT1' ''INT2' ''INT3' ''INT4'"
+$ Z_OBJS = "''Z1' ''Z2' ''Z3' ''Z4' ''Z5' ''Z6' ''Z7'"
+$ INT_CONFIG = "gconfig.obj gscdefs.obj iconfig.obj iccinit0.obj"
+$ GOSUB ISUPPORT_DEV
+$ GOSUB RLD_DEV
+$ GOSUB RLE_DEV
+$ GOSUB SFILE_DEV
+$ SETMOD psbase imainarg.obj gsargs.obj imain.obj
+$ ADDMOD psbase -obj 'INT_CONFIG'
+$ ADDMOD psbase -obj 'INT1'
+$ ADDMOD psbase -obj 'INT2'
+$ ADDMOD psbase -obj 'INT3'
+$ ADDMOD psbase -obj 'INT4'
+$ ADDMOD psbase -obj 'Z1'
+$ ADDMOD psbase -oper 'Z1OPS'
+$ ADDMOD psbase -obj 'Z2'
+$ ADDMOD psbase -oper 'Z2OPS'
+$ ADDMOD psbase -obj 'Z3'
+$ ADDMOD psbase -oper 'Z3OPS'
+$ ADDMOD psbase -obj 'Z4'
+$ ADDMOD psbase -oper 'Z4OPS'
+$ ADDMOD psbase -obj 'Z5'
+$ ADDMOD psbase -oper 'Z5OPS'
+$ ADDMOD psbase -obj 'Z6'
+$ ADDMOD psbase -oper 'Z6OPS'
+$ ADDMOD psbase -obj 'Z7'
+$ ADDMOD psbase -oper 'Z7OPS'
+$ ADDMOD psbase -iodev stdin stdout stderr lineedit statementedit
+$ ADDMOD psbase -include isupport rld rle sfile
+$ ADD_DEV_MODULES = "''INT_OBJS'"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''Z_OBJS'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LEVEL1_DEV:
+$ GOSUB PSBASE_DEV
+$ GOSUB BCP_DEV
+$ GOSUB HSB_DEV
+$ GOSUB PATH1_DEV
+$ GOSUB TYPE1_DEV
+$ SETMOD level1 -include psbase bcp hsb path1 type1
+$ ADDMOD level1 -emulator """PostScript""" """PostScriptLevel1"""
+$ RETURN
+$ !
+$ COLOR_DEV:
+$ IF F$TYPE(COLOR_DONE) .NES. "" THEN RETURN
+$ GOSUB CMYKLIB_DEV
+$ GOSUB COLIMLIB_DEV
+$ GOSUB CMYKREAD_DEV
+$ SETMOD color -include cmyklib colimlib cmykread
+$ COLOR_DONE = 1
+$ RETURN
+$ !
+$ CMYKREAD_DEV:
+$ IF F$TYPE(cmykread_) .NES. "" THEN RETURN
+$ cmykread_ = "zcolor1.obj zht1.obj"
+$ SETMOD cmykread 'cmykread_'
+$ ADDMOD cmykread -oper zcolor1 zht1
+$ ADD_DEV_MODULES = "''cmykread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ HSB_DEV:
+$ hsb_ = "zhsb.obj"
+$ GOSUB HSBLIB_DEV
+$ SETMOD hsb 'hsb_'
+$ ADDMOD hsb -include hsblib
+$ ADDMOD hsb -oper zhsb
+$ ADD_DEV_MODULES = "''hsb_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PATH1_DEV:
+$ path1_ = "zpath1.obj"
+$ GOSUB PATH1LIB_DEV
+$ SETMOD path1 'path1_'
+$ ADDMOD path1 -include path1lib
+$ ADDMOD path1 -oper zpath1
+$ ADD_DEV_MODULES = "''path1_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ BCP_DEV:
+$ bcp_ = "sbcp.obj zfbcp.obj"
+$ SETMOD bcp 'bcp_'
+$ ADDMOD bcp -oper zfbcp
+$ ADD_DEV_MODULES = "''bcp_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ DISKFONT_DEV:
+$ SETMOD diskfont -ps gs_diskf
+$ RETURN
+$ !
+$ DOUBLE_DEV:
+$ IF F$TYPE(double_) .NES. "" THEN RETURN
+$ double_ = "zdouble.obj"
+$ SETMOD double 'double_'
+$ ADDMOD double -oper zdouble
+$ ADD_DEV_MODULES = "''double_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ EPSF_DEV:
+$ SETMOD epsf -ps gs_epsf
+$ RETURN
+$ !
+$! ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
+$ TYPE1_DEV:
+$ IF F$TYPE(TYPE1_DONE) .NES. "" THEN RETURN
+$ GOSUB PSF1LIB_DEV
+$ GOSUB PSF1READ_DEV
+$ SETMOD type1 -include psf1lib psf1read
+$ TYPE1_DONE = 1
+$ RETURN
+$ !
+$ PSF1READ_DEV:
+$ IF F$TYPE(psf1read_) .NES. "" THEN RETURN
+$ psf1read_ = "seexec.obj zchar1.obj zcharout.obj zfont1.obj zmisc1.obj"
+$ SETMOD psf1read 'psf1read_'
+$ ADDMOD psf1read -oper zchar1 zfont1 zmisc1
+$ ADDMOD psf1read -ps gs_type1
+$ ADD_DEV_MODULES = "''psf1read_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ------------- Compact Font Format and Type 2 charstrings ------------- #
+$ CFF_DEV:
+$ GOSUB PSL2INT_DEV
+$ SETMOD cff -ps gs_cff
+$ RETURN
+$!
+$ TYPE2_DEV:
+$ GOSUB TYPE1_DEV
+$ GOSUB PSF2LIB_DEV
+$ SETMOD type2 -include psf2lib
+$ RETURN
+$!
+$! ---------------- TrueType and PostScript Type 42 fonts ---------------- #
+$! Native TrueType support
+$ TTFONT_DEV:
+$ GOSUB TYPE42_DEV
+$ SETMOD ttfont -include type42
+$ ADDMOD ttfont -ps gs_mro_e gs_wan_e gs_ttf
+$ RETURN
+$ !
+$! Type 42 (embedded TrueType) support
+$ TYPE42_DEV:
+$ IF F$TYPE(type42read_) .NES. "" THEN RETURN
+$ type42read_ = "zchar42.obj zcharout.obj zfont42.obj"
+$ GOSUB TTFLIB_DEV
+$ SETMOD type42 'type42read_'
+$ ADDMOD type42 -include ttflib
+$ ADDMOD type42 -oper zchar42 zfont42
+$ ADDMOD type42 -ps gs_typ42
+$ ADD_DEV_MODULES = "''type42read_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ GCONFIGF_H:
+$ SETMOD ccfonts_ -font "''ccfonts1'"
+$ ADDMOD ccfonts_ -font "''ccfonts2'"
+$ ADDMOD ccfonts_ -font "''ccfonts3'"
+$ ADDMOD ccfonts_ -font "''ccfonts4'"
+$ ADDMOD ccfonts_ -font "''ccfonts5'"
+$ ADDMOD ccfonts_ -font "''ccfonts6'"
+$ ADDMOD ccfonts_ -font "''ccfonts7'"
+$ ADDMOD ccfonts_ -font "''ccfonts8'"
+$ ADDMOD ccfonts_ -font "''ccfonts9'"
+$ ADDMOD ccfonts_ -font "''ccfonts10'"
+$ ADDMOD ccfonts_ -font "''ccfonts11'"
+$ ADDMOD ccfonts_ -font "''ccfonts12'"
+$ ADDMOD ccfonts_ -font "''ccfonts13'"
+$ ADDMOD ccfonts_ -font "''ccfonts14'"
+$ ADDMOD ccfonts_ -font "''ccfonts15'"
+$ GENCONF ccfonts_.dev -n gs -f gconfigf.h
+$ RETURN
+$ !
+
+$! ======================== PostScript Level 2 ======================== #
+$ LEVEL2_DEV:
+$ GOSUB CIDFONT_DEV
+$ GOSUB CIE_DEV
+$ GOSUB CMAPREAD_DEV
+$ GOSUB COMPFONT_DEV
+$ GOSUB DCT_DEV
+$ GOSUB DEVCTRL_DEV
+$ GOSUB DPSAND2_DEV
+$ GOSUB FILTER_DEV
+$ GOSUB LEVEL1_DEV
+$ GOSUB PATTERN_DEV
+$ GOSUB PSL2LIB_DEV
+$ GOSUB PSL2READ_DEV
+$ GOSUB SEPR_DEV
+$ GOSUB TYPE42_DEV
+$ GOSUB XFILTER_DEV
+$ SETMOD level2 -include cidfont cie cmapread compfont
+$ SETMOD level2 -include dct devctrl dpsand2 filter
+$ ADDMOD level2 -include level1 pattern psl2lib psl2read
+$ ADDMOD level2 -include sepr type42 xfilter
+$ ADDMOD level2 -emulator """PostScript""" """PostScriptLevel2"""
+$ RETURN
+$ !
+$! Define basic Level 2 language support.
+$! This is the minimum required for CMap and CIDFont support.
+$ PSL2INT_DEV:
+$ IF F$TYPE(psl2int_) .NES. "" THEN RETURN
+$ psl2int_="iutil2.obj zmisc2.obj zusparam.obj"
+$ GOSUB DPS2INT_DEV
+$ SETMOD psl2int "''psl2int_'"
+$ ADDMOD psl2int -include dps2int
+$ ADDMOD psl2int -oper zmisc2 zusparam
+$ ADDMOD psl2int -ps gs_lev2 gs_res
+$ ADD_DEV_MODULES = "''psl2int_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$!
+$! Define full Level 2 support.
+$ PSL2READ_DEV:
+$ IF F$TYPE(psl2read_) .NES. "" THEN RETURN
+$ psl2read_ = "zcolor2.obj zcsindex.obj zht2.obj zimage2.obj"
+$ GOSUB PSL2INT_DEV
+$ GOSUB DPS2READ_DEV
+$ SETMOD psl2read 'psl2read_'
+$ ADDMOD psl2read -include psl2int dps2read
+$ ADDMOD psl2read -oper zcolor2_l2 zcsindex_l2
+$ ADDMOD psl2read -oper zht2_l2 zimage2_l2
+$ ADD_DEV_MODULES = "''psl2read_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ DEVCTRL_DEV:
+$ devctrl_ = "zdevice2.obj ziodev2.obj zmedia2.obj zdevcal.obj"
+$ SETMOD devctrl 'devctrl_'
+$ ADDMOD devctrl -oper zdevice2_l2 ziodev2_l2 zmedia2_l2
+$ ADDMOD devctrl -iodev null ram calendar
+$ ADDMOD devctrl -ps gs_setpd
+$ ADD_DEV_MODULES = "''devctrl_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ FDECODE_DEV:
+$ IF F$TYPE(fdecode_) .NES. "" THEN RETURN
+$ fdecode_ = "scantab.obj sfilter2.obj zfdecode.obj"
+$ GOSUB CFD_DEV
+$ GOSUB LZWD_DEV
+$ GOSUB PDIFF_DEV
+$ GOSUB PNGP_DEV
+$ GOSUB RLD_DEV
+$ SETMOD fdecode 'fdecode_'
+$ ADDMOD fdecode -include cfd lzwd pdiff pngp rld
+$ ADDMOD fdecode -oper zfdecode
+$ ADD_DEV_MODULES = "''fdecode_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ FILTER_DEV:
+$ filter_ = "zfilter2.obj"
+$ GOSUB FDECODE_DEV
+$ GOSUB CFE_DEV
+$ GOSUB LZWE_DEV
+$ GOSUB RLE_DEV
+$ SETMOD filter -include fdecode
+$ ADDMOD filter -obj 'filter_'
+$ ADDMOD filter -include cfe lzwe rle
+$ ADDMOD filter -oper zfilter2
+$ ADD_DEV_MODULES = "''filter_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ XFILTER_DEV:
+$ xfilter_ = "sbhc.obj sbwbs.obj shcgen.obj smtf.obj zfilterx.obj"
+$ GOSUB PCXD_DEV
+$ GOSUB PNGP_DEV
+$ SETMOD xfilter 'xfilter_'
+$ ADDMOD xfilter -include pcxd
+$ ADDMOD xfilter -oper zfilterx
+$ ADD_DEV_MODULES = "''xfilter_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ BTOKEN_DEV:
+$ btoken_ = "iscanbin.obj zbseq.obj"
+$ SETMOD btoken 'btoken_'
+$ ADDMOD btoken -oper zbseq_l2
+$ ADDMOD btoken -ps gs_btokn
+$ ADD_DEV_MODULES = "''btoken_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ UPATH_DEV:
+$ upath_ = "zupath.obj ibnum.obj"
+$ SETMOD upath 'upath_'
+$ ADDMOD upath -oper zupath_l2
+$ ADD_DEV_MODULES = "''upath_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! -------- Additions common to Display PostScript and Level 2 -------- #
+$ DPSAND2_DEV:
+$ GOSUB BTOKEN_DEV
+$ GOSUB COLOR_DEV
+$ GOSUB UPATH_DEV
+$ GOSUB DPS2LIB_DEV
+$ GOSUB DPS2READ_DEV
+$ SETMOD dpsand2 -include btoken color upath dps2lib dps2read
+$ RETURN
+$ !
+$! Note that zvmem2 includes both Level 1 and Level 2 operators.
+$ DPS2INT_DEV:
+$ IF F$TYPE(dps2int_) .NES. "" THEN RETURN
+$ dps2int_="zvmem2.obj zdps1.obj"
+$ SETMOD dps2int "''dps2int_'"
+$ ADDMOD dps2int -oper zvmem2 zdps1_l2
+$ ADDMOD dps2int -ps gs_dps1
+$ ADD_DEV_MODULES = "''dps2int_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$!
+$ DPS2READ_DEV:
+$ IF F$TYPE(dps2read_) .NES. "" THEN RETURN
+$ dps2read_ = "ibnum.obj zchar2.obj"
+$ GOSUB DPS2INT_DEV
+$ SETMOD dps2read 'dps2read_'
+$ ADDMOD dps2read -include dps2int
+$ ADDMOD dps2read -oper ireclaim_l2 zchar2_l2
+$ ADDMOD dps2read -ps gs_dps2
+$ ADD_DEV_MODULES = "''dps2read_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Display PostScript ---------------- #
+$ DPS_DEV:
+$ dps_ = "zdps.obj icontext.obj zcontext.obj"
+$ GOSUB DPSLIB_DEV
+$ GOSUB LEVEL2_DEV
+$ SETMOD dps -include dpslib level2
+$ ADDMOD dps -obj 'dps_'
+$ ADDMOD dps -oper zcontext zdps
+$ ADDMOD dps -ps gs_dps
+$ ADD_DEV_MODULES = "''dps_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- NeXT Display PostScript ---------------- #
+$!**************** NOT READY FOR USE YET ****************#
+$!
+$! DPSNEXT_DEV:
+$! dpsnext_ = "zdpnext.obj"
+$! GOSUB DPS_DEV
+$! SETMOD dpsnext -include dps
+$! ADDMOD dpsnext -obj "''dpsnext_'"
+$! ADDMOD dpsnext -oper zdpnext
+$! ADDMOD dpsnext -ps gs_dpnxt
+$! ADD_DEV_MODULES = "''dpsnext_'"
+$! GOSUB ADD_DEV_MOD
+$! RETURN
+$ !
+$ COMPFONT_DEV:
+$ GOSUB PSF0LIB_DEV
+$ GOSUB PSF0READ_DEV
+$ SETMOD compfont -include psf0lib psf0read
+$ RETURN
+$ !
+$ PSF0READ_DEV:
+$ psf0read_ = "zchar2.obj zfcmap.obj zfont0.obj"
+$ SETMOD psf0read 'psf0read_'
+$ ADDMOD psf0read -oper zfont0 zchar2 zfcmap
+$ ADD_DEV_MODULES = "''psf0read_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- CMap support ---------------- #
+$ CMAPREAD_DEV:
+$ IF F$TYPE(cmapread_) .NES. "" THEN RETURN
+$ cmapread_="zfcmap.obj"
+$ GOSUB CMAPLIB_DEV
+$ GOSUB PSL2INT_DEV
+$ SETMOD cmapread "''cmapread_'"
+$ ADDMOD cmapread -include cmaplib psl2int
+$ ADDMOD cmapread -oper zfcmap
+$ ADDMOD cmapread -ps gs_cmap
+$ ADD_DEV_MODULES = "''cmapread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$!
+$ CIDFONT_DEV:
+$ IF F$TYPE(cidread_) .NES. "" THEN RETURN
+$ cidread_ = "zcid.obj"
+$ GOSUB PSF1READ_DEV
+$ GOSUB PSL2INT_DEV
+$ GOSUB TYPE42_DEV
+$ SETMOD cidfont 'cidread_'
+$ ADDMOD cidfont -include psf1read psl2int type42
+$ ADDMOD cidfont -ps -gs_cidfn
+$ ADDMOD cidfont -oper zcid
+$ ADD_DEV_MODULES = "''cidread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CIE_DEV:
+$ IF F$TYPE(cieread_) .NES. "" THEN RETURN
+$ cieread_ = "zcie.obj zcrd.obj"
+$ GOSUB CIELIB_DEV
+$ SETMOD cie 'cieread_'
+$ ADDMOD cie -oper zcie_l2 zcrd_l2
+$ ADDMOD cie -include cielib
+$ ADD_DEV_MODULES = "''cieread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PATTERN_DEV:
+$ GOSUB PATLIB_DEV
+$ GOSUB PATREAD_DEV
+$ SETMOD pattern -include patlib patread
+$ RETURN
+$ !
+$ PATREAD_DEV:
+$ patread_ = "zpcolor.obj"
+$ SETMOD patread 'patread_'
+$ ADDMOD patread -oper zpcolor_l2
+$ ADD_DEV_MODULES = "''patread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SEPR_DEV:
+$ seprread_ = "zcssepr.obj"
+$ GOSUB SEPRLIB_DEV
+$ SETMOD sepr 'seprread_'
+$ ADDMOD sepr -oper zcssepr_l2
+$ ADDMOD sepr -include seprlib
+$ ADD_DEV_MODULES = "''seprread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- Functions ---------------- #
+$! Generic support, and FunctionType 0.
+$ FUNC_DEV:
+$ IF F$TYPE(funcread_) .NES. "" THEN RETURN
+$ funcread_ = "zfunc.obj zfunc0.obj"
+$ GOSUB FUNCLIB_DEV
+$ SETMOD func 'funcread_'
+$ ADDMOD func -oper zfunc zfunc0
+$ ADDMOD func -include funclib
+$ ADD_DEV_MODULES = "''funcread_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- DCT filters ---------------- #
+$ DCT_DEV:
+$ IF F$TYPE(dctc__) .NES. "" THEN RETURN
+$ dctc_="zfdctc.obj"
+$ GOSUB DCTE_DEV
+$ GOSUB DCTD_DEV
+$ SETMOD dct -include dcte dctd
+$ ADD_DEV_MODULES = "''dctc_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Encoding (compression)
+$ DCTE_DEV:
+$ IF F$TYPE(dcte_) .NES. "" THEN RETURN
+$ dcte_ = "''dctc_' zfdcte.obj"
+$ GOSUB SDCTE_DEV
+$ SETMOD dcte -include sdcte
+$ ADDMOD dcte -obj 'dcte_'
+$ ADDMOD dcte -oper zfdcte
+$ ADD_DEV_MODULES = "''dcte_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Decoding (decompression)
+$ DCTD_DEV:
+$ IF F$TYPE(dctd_) .NES. "" THEN RETURN
+$ dctd_ = "''dctc_' zfdctd.obj"
+$ GOSUB SDCTD_DEV
+$ SETMOD dctd -include sdctd
+$ ADDMOD dctd -obj 'dctd_'
+$ ADDMOD dctd -oper zfdctd
+$ ADD_DEV_MODULES = "''dctd_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ---------------- zlib/Flate filters ---------------- #
+$ FZLIB_DEV:
+$ GOSUB SZLIBE_DEV
+$ GOSUB SZLIBD_DEV
+$ SETMOD fzlib -include szlibe szlibd
+$ ADDMOD fzlib -obj zfzlib.obj
+$ ADDMOD fzlib -oper zfzlib
+$ ADD_DEV_MODULES = "zfzlib.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ================================ PDF ================================ #
+$ PDFMIN_DEV:
+$ GOSUB PSBASE_DEV
+$ GOSUB COLOR_DEV
+$ GOSUB DPS2LIB_DEV
+$ GOSUB DPS2READ_DEV
+$ GOSUB FDECODE_DEV
+$ GOSUB TYPE1_DEV
+$ GOSUB PDFFONTS_DEV
+$ GOSUB PSL2LIB_DEV
+$ GOSUB PSL2READ_DEV
+$ GOSUB PDFREAD_DEV
+$ SETMOD pdfmin -include psbase color dps2lib dps2read
+$ ADDMOD pdfmin -include fdecode type1
+$ ADDMOD pdfmin -include pdffonts psl2lib psl2read pdfread
+$ ADDMOD pdfmin -emulator """PDF"""
+$ RETURN
+$ !
+$ PDF_DEV:
+$ GOSUB PDFMIN_DEV
+$ GOSUB CFF_DEV
+$ GOSUB CIDFONT_DEV
+$ GOSUB CIE_DEV
+$ GOSUB COMPFONT_DEV
+$ GOSUB CMAPREAD_DEV
+$ GOSUB DCTD_DEV
+$ GOSUB FUNC_DEV
+$ GOSUB TTFONT_DEV
+$ GOSUB TYPE2_DEV
+$ SETMOD pdf -include pdfmin cff cidfont cie cmapread
+$ ADDMOD pdf -include compfont dctd func ttfont type2
+$ RETURN
+$ !
+$! Reader only
+$ PDFFONTS_DEV:
+$ SETMOD pdffonts -ps gs_mex_e gs_mro_e gs_pdf_e gs_wan_e
+$ RETURN
+$ !
+$ PDFREAD_DEV:
+$ GOSUB FZLIB_DEV
+$ SETMOD pdfread -include fzlib
+$ ADDMOD pdfread -ps gs_pdf gs_l2img
+$ ADDMOD pdfread -ps pdf_base pdf_draw pdf_font pdf_main pdf_sec
+$ ADDMOD pdfread -ps pdf_2ps
+$ RETURN
+$ !
+$ JPEGC_DEV:
+$ IF F$TYPE(jpegc_) .NES. "" THEN RETURN
+$ jpegc_ = "jcomapi.obj jutils.obj sjpegerr.obj jmemmgr.obj"
+$ COPY GSJCONF.H JCONFIG.H
+$ COPY GSJMOREC.H JMORECFG.H
+$ COPY 'JSRCDIR'JMORECFG.H []JMCORIG.H
+$ COPY 'JSRCDIR'JERROR.H []JERROR.H
+$ COPY 'JSRCDIR'JINCLUDE.H []JINCLUDE.H
+$ COPY 'JSRCDIR'JPEGLIB.H []JPEGLIB.H
+$ COPY 'JSRCDIR'JVERSION.H []JVERSION.H
+$ SETMOD JPEGC 'jpegc_'
+$ ADD_DEV_MODULES = "''JSRCDIR'jcomapi.obj ''JSRCDIR'jutils.obj " +-
+ "sjpegerr.obj ''JSRCDIR'jmemmgr.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ JPEGE_DEV:
+$ IF F$TYPE(jpege6) .NES. "" THEN RETURN
+$ jpege5 = "jcapi.obj"
+$ jpege6 = "jcapimin.obj jcapistd.obj jcinit.obj"
+$ jpege_1 = "jccoefct.obj jccolor.obj jcdctmgr.obj"
+$ jpege_2 = "jchuff.obj jcmainct.obj jcmarker.obj jcmaster.obj"
+$ jpege_3 = "jcparam.obj jcprepct.obj jcsample.obj jfdctint.obj"
+$ GOSUB JPEGC_DEV
+$ IF JVERSION .EQ. 5 THEN SETMOD jpege 'jpege5'
+$ IF JVERSION .EQ. 6 THEN SETMOD jpege 'jpege6'
+$ ADDMOD jpege -include jpegc
+$ ADDMOD jpege -obj 'jpege_1'
+$ ADDMOD jpege -obj 'jpege_2'
+$ ADDMOD jpege -obj 'jpege_3'
+$ IF JVERSION .EQ. 5 THEN ADD_DEV_MODULES = "''JSRCDIR'jcapi.obj"
+$ IF JVERSION .EQ. 6 THEN ADD_DEV_MODULES = "''JSRCDIR'jcapimin.obj " +-
+ "''JSRCDIR'jcapistd.obj ''JSRCDIR'jcinit.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jccoefct.obj ''JSRCDIR'jccolor.obj " +-
+ "''JSRCDIR'jcdctmgr.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jchuff.obj ''JSRCDIR'jcmainct.obj " +-
+ "''JSRCDIR'jcmarker.obj ''JSRCDIR'jcmaster.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jcparam.obj ''JSRCDIR'jcprepct.obj " +-
+ "''JSRCDIR'jcsample.obj ''JSRCDIR'jfdctint.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ JPEGD_DEV:
+$ IF F$TYPE(jpegd6) .NES. "" THEN RETURN
+$ jpegd5 = "jdapi.obj"
+$ jpegd6 = "jdapimin.obj jdapistd.obj jdinput.obj jdphuff.obj"
+$ jpegd_1 = "jdcoefct.obj jdcolor.obj"
+$ jpegd_2 = "jddctmgr.obj jdhuff.obj jdmainct.obj jdmarker.obj"
+$ jpegd_3 = "jdmaster.obj jdpostct.obj jdsample.obj jidctint.obj"
+$ GOSUB JPEGC_DEV
+$ IF JVERSION .EQ. 5 THEN SETMOD jpegd 'jpegd5'
+$ IF JVERSION .EQ. 6 THEN SETMOD jpegd 'jpegd6'
+$ ADDMOD jpegd -include jpegc
+$ ADDMOD jpegd -obj 'jpegd_1'
+$ ADDMOD jpegd -obj 'jpegd_2'
+$ ADDMOD jpegd -obj 'jpegd_3'
+$ IF JVERSION .EQ. 5 THEN ADD_DEV_MODULES = "''JSRCDIR'jdapi.obj"
+$ IF JVERSION .EQ. 6 THEN ADD_DEV_MODULES = "''JSRCDIR'jdapimin.obj " +-
+ "''JSRCDIR'jdapistd.obj ''JSRCDIR'jdinput.obj ''JSRCDIR'jdphuff.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jdcoefct.obj ''JSRCDIR'jdcolor.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jddctmgr.obj ''JSRCDIR'jdhuff.obj " +-
+ "''JSRCDIR'jdmainct.obj ''JSRCDIR'jdmarker.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''JSRCDIR'jdmaster.obj ''JSRCDIR'jdpostct.obj " +-
+ "''JSRCDIR'jdsample.obj ''JSRCDIR'jidctint.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LIBPNG_DEV:
+$ IF F$TYPE(png_) .NES. "" THEN RETURN
+$ png_1 = "png.obj pngmem.obj pngerror.obj"
+$ png_2 = "pngtrans.obj pngwrite.obj pngwtran.obj pngwutil.obj"
+$ png_ = "gdevpng.obj gdevpccm.obj gdevprn.obj"
+$ COPY 'PSRCDIR'PNG.H []PNG.H
+$ COPY 'PSRCDIR'PNGCONF.H []PNGCONF.H
+$ GOSUB ZLIBE_DEV
+$ IF PVERSION .EQ. 88 THEN SETMOD libpng "pngio.obj"
+$ IF PVERSION .EQ. 89 THEN SETMOD libpng "pngwio.obj"
+$ IF PVERSION .GE. 90
+$ THEN
+$ GOSUB CRC32_DEV
+$ SETMOD libpng "pngwio.obj" -include crc32
+$ ENDIF
+$ ADDMOD libpng -obj 'png_1'
+$ ADDMOD libpng -obj 'png_2'
+$ ADDMOD libpng -include zlibe
+$ ADD_DEV_MODULES = "''PSRCDIR'png.obj ''PSRCDIR'pngmem.obj "
+$ IF PVERSION .EQ. 88 THEN ADD_DEV_MODULES = ADD_DEV_MODULES +-
+ "''PSRCDIR'pngio.obj ''PSRCDIR'pngerror.obj"
+$ IF PVERSION .GT. 89 THEN ADD_DEV_MODULES = ADD_DEV_MODULES +-
+ "''PSRCDIR'pngwio.obj ''PSRCDIR'pngerror.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''PSRCDIR'pngtrans.obj ''PSRCDIR'pngwrite.obj " +-
+ "''PSRCDIR'pngwtran.obj ''PSRCDIR'pngwutil.obj"
+$ GOSUB ADD_DEV_MOD
+$ ADD_DEV_MODULES = "''png_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Code common to compression and decompression.
+$ ZLIBC_DEV:
+$ COPY 'ZSRCDIR'ZCONF.H []ZCONF.H
+$ COPY 'ZSRCDIR'ZLIB.H []ZLIB.H
+$ COPY 'ZSRCDIR'ZUTIL.H []ZUTIL.H
+$ COPY 'ZSRCDIR'DEFLATE.H []DEFLATE.H
+$ zlibc_ = "zutil.obj"
+$ SETMOD zlibc 'zlibc_'
+$ ADD_DEV_MODULES = "''ZSRCDIR'zutil.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Encoding (compression) code.
+$ ZLIBE_DEV:
+$ IF F$TYPE(zlibe_) .NES. "" THEN RETURN
+$ zlibe_ = "adler32.obj deflate.obj trees.obj"
+$ GOSUB ZLIBC_DEV
+$ SETMOD zlibe 'zlibe_'
+$ ADDMOD zlibe -include zlibc
+$ ADD_DEV_MODULES = "''ZSRCDIR'adler32.obj ''ZSRCDIR'deflate.obj " +-
+ "''ZSRCDIR'trees.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! The zlib filters per se don't need crc32, but libpng versions starting
+$! with 0.90 do.
+$ CRC32_DEV:
+$ SETMOD crc32 "crc32.obj"
+$ ADD_DEV_MODULES = "''ZSRCDIR'crc32.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! Decoding (decompression) code.
+$ ZLIBD_DEV:
+$ IF F$TYPE(zlibd_) .NES. "" THEN RETURN
+$ zlibd1_ = "infblock.obj infcodes.obj inffast.obj"
+$ zlibd2_ = "inflate.obj inftrees.obj infutil.obj"
+$ zlibd_ = "''zlibd1_' ''zlibd2_'"
+$ GOSUB ZLIBC_DEV
+$ SETMOD zlibd 'zlibd1_'
+$ ADDMOD zlibd -obj 'zlibd2_'
+$ ADDMOD zlibe -include zlibc
+$ ADD_DEV_MODULES =-
+ "''ZSRCDIR'infblock.obj ''ZSRCDIR'infcodes.obj ''ZSRCDIR'inffast.obj " +-
+ "''ZSRCDIR'inflate.obj ''ZSRCDIR'inftrees.obj ''ZSRCDIR'infutil.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ X11DEV_INIT:
+$ x11_ = "gdevx.obj gdevxini.obj gdevxxf.obj gdevemap.obj"
+$ x11alt_ = "''x11_' gdevxalt.obj"
+$ XLIBS = "Xt Xext X11"
+$ ADD_DEV_MODULES = "''x11alt_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ X11_DEV:
+$ IF F$TYPE(x11_) .EQS. "" THEN GOSUB X11DEV_INIT
+$ SETDEV x11 'x11_'
+$ ADDMOD x11 -lib 'XLIBS'
+$ RETURN
+$ !
+$ X11ALPHA_DEV:
+$ IF F$TYPE(x11_) .EQS. "" THEN GOSUB X11DEV_INIT
+$ SETDEV x11alpha 'x11alt_'
+$ ADDMOD x11alpha -lib 'XLIBS'
+$ RETURN
+$ !
+$ X11CMYK_DEV:
+$ IF F$TYPE(x11_) .EQS. "" THEN GOSUB X11DEV_INIT
+$ SETDEV x11cmyk 'x11alt_'
+$ ADDMOD x11cmyk -lib 'XLIBS'
+$ RETURN
+$ !
+$ X11GRAY2_DEV:
+$ IF F$TYPE(x11_) .EQS. "" THEN GOSUB X11DEV_INIT
+$ SETDEV x11gray2 'x11alt_'
+$ ADDMOD x11gray2 -lib 'XLIBS'
+$ RETURN
+$ !
+$ X11MONO_DEV:
+$ IF F$TYPE(x11_) .EQS. "" THEN GOSUB X11DEV_INIT
+$ SETDEV x11mono 'x11alt_'
+$ ADDMOD x11mono -lib 'XLIBS'
+$ RETURN
+$ !
+$ LN03_INIT:
+$ ln03_ = "gdevln03.obj gdevprn.obj"
+$ ADD_DEV_MODULES = "''ln03_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ SXLCRT_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV sxlcrt 'ln03_'
+$ RETURN
+$ !
+$ BJDEV_INIT:
+$ bj10e_ = "gdevbj10.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''bj10e_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ BJ10E_DEV:
+$ IF F$TYPE(bj10e_) .EQS. "" THEN GOSUB BJDEV_INIT
+$ SETDEV bj10e 'bj10e_'
+$ RETURN
+$ !
+$ BJ200_DEV:
+$ IF F$TYPE(bj10e_) .EQS. "" THEN GOSUB BJDEV_INIT
+$ SETDEV bj200 'bj10e_'
+$ RETURN
+$ !
+$ HPMONO_INIT:
+$ HPPCL = "gdevprn.obj gdevpcl.obj"
+$ HPMONO = "gdevdjet.obj ''HPPCL'"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''HPMONO'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ DESKJET_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV deskjet 'HPMONO'
+$ RETURN
+$ !
+$ DJET500_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV djet500 'HPMONO'
+$ RETURN
+$ !
+$ LASERJET_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV laserjet 'HPMONO'
+$ RETURN
+$ !
+$ LJETPLUS_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV ljetplus 'HPMONO'
+$ RETURN
+$ !
+$ LJET2P_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV ljet2p 'HPMONO'
+$ RETURN
+$ !
+$ LJET3_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV ljet3 'HPMONO'
+$ RETURN
+$ !
+$ LJET4_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV ljet4 'HPMONO'
+$ RETURN
+$ !
+$ LP2563_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV lp2563 'HPMONO'
+$ RETURN
+$ !
+$ OCE9050_DEV:
+$ IF F$TYPE(HPMONO) .EQS. "" THEN GOSUB HPMONO_INIT
+$ SETDEV oce9050 'HPMONO'
+$ RETURN
+$ !
+$ LJ5INIT_INIT:
+$ HPPCL = "gdevprn.obj gdevpcl.obj"
+$ ljet5_ = "gdevlj56.obj ''HPPCL'"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''ljet5_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LJ5MONO_DEV:
+$ IF F$TYPE(ljet5_) .EQS. "" THEN GOSUB LJ5INIT_INIT
+$ SETDEV lj5mono 'ljet5_'
+$ RETURN
+$ !
+$ LJ5GRAY_DEV:
+$ IF F$TYPE(ljet5_) .EQS. "" THEN GOSUB LJ5INIT_INIT
+$ SETDEV lj5gray 'ljet5_'
+$ RETURN
+$ !
+$ HPDEV_INIT:
+$ HPPCL = "gdevprn.obj gdevpcl.obj"
+$ cdeskjet_ = "gdevcdj.obj ''HPPCL'"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''cdeskjet_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CDESKJET_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV cdeskjet 'cdeskjet_'
+$ RETURN
+$ !
+$ CDJCOLOR_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV cdjcolor 'cdeskjet_'
+$ RETURN
+$ !
+$ CDJMONO_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV cdjmono 'cdeskjet_'
+$ RETURN
+$ !
+$ CDJ550_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV cdj550 'cdeskjet_'
+$ RETURN
+$ !
+$ DECLJ250_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV declj250 'cdeskjet_'
+$ RETURN
+$ !
+$ DNJ650C_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV dnj650c 'cdeskjet_'
+$ RETURN
+$ !
+$ LJ4DITH_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV lj4dith 'cdeskjet_'
+$ RETURN
+$ !
+$ PJ_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV pj 'cdeskjet_'
+$ RETURN
+$ !
+$ PJXL_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV pjxl 'cdeskjet_'
+$ RETURN
+$ !
+$ PJXL300_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV pjxl300 'cdeskjet_'
+$ RETURN
+$ !
+$ BJC600_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV bjc600 'cdeskjet_'
+$ RETURN
+$ !
+$ BJC800_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV bjc800 'cdeskjet_'
+$ RETURN
+$ !
+$ ESCP_DEV:
+$ IF F$TYPE(cdeskjet_) .EQS. "" THEN GOSUB HPDEV_INIT
+$ SETDEV escp 'cdeskjet_'
+$ RETURN
+$ !
+$! --------------- Ugly/Update -> Unified Printer Driver ---------------- ###
+$ UNIPRINT_DEV:
+$ IF F$TYPE(uniprint_) .NES. "" THEN RETURN
+$ uniprint_ = "gdevupd.obj"
+$ SETDEV uniprint 'uniprint_'
+$ ADD_DEV_MODULES = "''uniprint_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ LN03_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV ln03 'ln03'
+$ RETURN
+$ !
+$ LA50_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV la50 'ln03'
+$ RETURN
+$ !
+$ LA70_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV la70 'ln03'
+$ RETURN
+$ !
+$ LA75_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV la75 'ln03'
+$ RETURN
+$ !
+$ LA75PLUS_DEV:
+$ IF F$TYPE(ln03_) .EQS. "" THEN GOSUB LN03_INIT
+$ SETDEV la75plus 'ln03'
+$ RETURN
+$ !
+$ LA70T_DEV:
+$ la70t_ = "gdevla7t.obj"
+$ SETDEV la70t 'la70t_'
+$ ADD_DEV_MODULES = "''la70t_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ TEK4696_DEV:
+$ tek4696_ = "gdevtknk.obj gdevprn.obj"
+$ SETDEV tek4696 'tek4696_'
+$ ADD_DEV_MODULES = "''tek4696_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ DFAX_INIT:
+$ dfax_ = "gdevdfax.obj gdevtfax.obj"
+$ ADD_DEV_MODULES = "''dfax_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ DFAXLOW_DEV:
+$ IF F$TYPE(dfax_) .EQS. "" THEN GOSUB DFAX_INIT
+$ SETDEV dfaxlow "''dfax_'"
+$ ADDMOD dfaxlow -include cfe
+$ RETURN
+$ !
+$ DFAXHIGH_DEV:
+$ IF F$TYPE(dfax_) .EQS. "" THEN GOSUB DFAX_INIT
+$ SETDEV dfaxhigh "''dfax_'"
+$ ADDMOD dfaxhigh -include cfe
+$ RETURN
+$ !
+$! PostScript and EPS writers
+$ PSWRITE_INI:
+$ IF F$TYPE(pswrite_) .NES. "" THEN RETURN
+$ pswrite1_ = "gdevps.obj gdevpsdf.obj gdevpstr.obj"
+$ pswrite2_ = "scantab.obj sfilter2.obj"
+$ pswrite_ = "''pswrite1_' ''pswrite2_'"
+$ ADD_DEV_MODULES = "''pswrite_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ EPSWRITE_DEV:
+$ GOSUB PSWRITE_INI
+$ GOSUB VECTOR_DEV
+$ SETDEV epswrite "''pswrite1_'"
+$ ADDMOD epswrite "''pswrite2_'"
+$ ADDMOD epswrite -include vector
+$ RETURN
+$ !
+$ PSWRITE_DEV:
+$ GOSUB PSWRITE_INI
+$ GOSUB VECTOR_DEV
+$ SETDEV pswrite "''pswrite1_'"
+$ ADDMOD pswrite "''pswrite2_'"
+$ ADDMOD pswrite -include vector
+$ RETURN
+$ !
+$! PDF writer
+$ PDFWRITE_DEV:
+$ pdfwrite1_ = "gdevpdf.obj gdevpdfd.obj gdevpdfi.obj gdevpdfm.obj"
+$ pdfwrite2_ = "gdevpdfp.obj gdevpdft.obj gdevpsdf.obj gdevpstr.obj"
+$ pdfwrite3_ = "gsflip.obj scantab.obj sfilter2.obj sstring.obj"
+$ pdfwrite_ = "''pdfwrite1_' ''pdfwrite2_' ''pdfwrite3_'"
+$ GOSUB CMYKLIB_DEV
+$ GOSUB CFE_DEV
+$ GOSUB DCTE_DEV
+$ GOSUB LZWE_DEV
+$ GOSUB RLE_DEV
+$ GOSUB VECTOR_DEV
+$ SETDEV pdfwrite 'pdfwrite1_'
+$ ADDMOD pdfwrite 'pdfwrite2_'
+$ ADDMOD pdfwrite 'pdfwrite3_'
+$ ADDMOD pdfwrite -ps gs_pdfwr
+$ ADDMOD pdfwrite -include cmyklib cfe dcte lzwe rle vector
+$ ADD_DEV_MODULES = "''pdfwrite_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PXLDEV_INIT:
+$ pxl_ = "gdevpx.obj"
+$ GOSUB VECTOR_DEV
+$ ADD_DEV_MODULES = "''pxl_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PXLMONO_DEV:
+$ IF F$TYPE(pxl_) .EQS. "" THEN GOSUB PXLDEV_INIT
+$ SETDEV pxlmono "''pxl_'"
+$ ADDMOD pxlmono -include vector
+$ RETURN
+$ !
+$ PXLCOLOR_DEV:
+$ IF F$TYPE(pxl_) .EQS. "" THEN GOSUB PXLDEV_INIT
+$ SETDEV pxlcolor "''pxl_'"
+$ ADDMOD pxlcolor -include vector
+$ RETURN
+$ !
+$ BITDEV_INIT:
+$ bit_ = "gdevbit.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''bit_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ BIT_DEV:
+$ IF F$TYPE(bit_) .EQS. "" THEN GOSUB BITDEV_INIT
+$ SETDEV bit 'bit_'
+$ RETURN
+$ !
+$ BITRGB_DEV:
+$ IF F$TYPE(bit_) .EQS. "" THEN GOSUB BITDEV_INIT
+$ SETDEV bitrgb 'bit_'
+$ RETURN
+$ !
+$ BITCMYK_DEV:
+$ IF F$TYPE(bit_) .EQS. "" THEN GOSUB BITDEV_INIT
+$ SETDEV bitcmyk 'bit_'
+$ RETURN
+$ !
+$ BMPDEV_INIT:
+$ bmp_ = "gdevbmp.obj gdevpccm.obj gdevprn.obj"
+$ ADD_DEV_MODULES = "''bmp_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ BMPMONO_DEV:
+$ IF F$TYPE(bmp_) .EQS. "" THEN GOSUB BMPDEV_INIT
+$ SETDEV bmpmono 'bmp_'
+$ RETURN
+$ !
+$ BMP16_DEV:
+$ IF F$TYPE(bmp_) .EQS. "" THEN GOSUB BMPDEV_INIT
+$ SETDEV bmp16 'bmp_'
+$ RETURN
+$ !
+$ BMP256_DEV:
+$ IF F$TYPE(bmp_) .EQS. "" THEN GOSUB BMPDEV_INIT
+$ SETDEV bmp256 'bmp_'
+$ RETURN
+$ !
+$ BMP16M_DEV:
+$ IF F$TYPE(bmp_) .EQS. "" THEN GOSUB BMPDEV_INIT
+$ SETDEV bmp16m 'bmp_'
+$ RETURN
+$ !
+$ CGMDEV_INIT:
+$ cgm_ = "gdevcgm.obj gdevcgml.obj"
+$ ADD_DEV_MODULES = "''cgm_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ CGMMONO_DEV:
+$ IF F$TYPE(cgm_) .EQS. "" THEN GOSUB CGMDEV_INIT
+$ SETDEV cgmmono 'cgm_'
+$ RETURN
+$ !
+$ CGM8_DEV:
+$ IF F$TYPE(cgm_) .EQS. "" THEN GOSUB CGMDEV_INIT
+$ SETDEV cgm8 'cgm_'
+$ RETURN
+$ !
+$ CGM24_DEV:
+$ IF F$TYPE(cgm_) .EQS. "" THEN GOSUB CGMDEV_INIT
+$ SETDEV cgm24 'cgm_'
+$ RETURN
+$ !
+$!### ------------------------- JPEG file format ------------------------- ###
+$ JPEG_INI:
+$ IF F$TYPE(jpeg_) .NES. "" THEN RETURN
+$ jpeg_="gdevjpeg.obj"
+$ ADD_DEV_MODULES = "''jpeg_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! RGB output
+$ JPEG_DEV:
+$ GOSUB JPEG_INI
+$ GOSUB SDCTE_DEV
+$ SETDEV jpeg "''jpeg_'"
+$ ADDMOD jpeg -include sdcte
+$ RETURN
+$ !
+$! Gray output
+$ JPEGGRAY_DEV:
+$ GOSUB JPEG_INI
+$ GOSUB SDCTE_DEV
+$ SETDEV jpeggray "''jpeg_'"
+$ ADDMOD jpeggray -include sdcte
+$ RETURN
+$ !
+$ PCXDEV_INIT:
+$ pcx_ = "gdevpcx.obj gdevpccm.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''pcx_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PCXMONO_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcxmono 'pcx_'
+$ RETURN
+$ !
+$ PCXGRAY_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcxgray 'pcx_'
+$ RETURN
+$ !
+$ PCX16_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcx16 'pcx_'
+$ RETURN
+$ !
+$ PCX256_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcx256 'pcx_'
+$ RETURN
+$ !
+$ PCX24B_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcx24b 'pcx_'
+$ RETURN
+$ !
+$ PCXCMYK_DEV:
+$ IF F$TYPE(pcx_) .EQS. "" THEN GOSUB PCXDEV_INIT
+$ SETDEV pcxcmyk 'pcx_'
+$ RETURN
+$ !
+$! The 2-up PCX device is also here only as an example, and for testing.
+$ PCX2UP_DEV:
+$ GOSUB PCX256_DEV
+$ SETDEV pcx2up "gdevp2up.obj"
+$ ADDMOD pcx2up -include pcx256
+$ ADD_DEV_MODULES = "gdev2up.obj gdevprn.obj"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$! ### ------------------- Portable Bitmap file formats ------------------- ###
+$ PBMDEV_INIT:
+$ pxm_ = "gdevpbm.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ ADD_DEV_MODULES = "''pxm_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PBM_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pbm 'pxm_'
+$ RETURN
+$ !
+$ PBMRAW_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pbmraw 'pxm_'
+$ RETURN
+$ !
+$ PGM_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pgm 'pxm_'
+$ RETURN
+$ !
+$ PGMRAW_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pgmraw 'pxm_'
+$ RETURN
+$ !
+$ PGNM_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pgnm 'pxm_'
+$ RETURN
+$ !
+$ PGNMRAW_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pgnmraw 'pxm_'
+$ RETURN
+$ !
+$ PPM_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV ppm 'pxm_'
+$ RETURN
+$ !
+$ PPMRAW_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV ppmraw 'pxm_'
+$ RETURN
+$ !
+$ PNM_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pnm 'pxm_'
+$ RETURN
+$ !
+$ PNMRAW_DEV:
+$ IF F$TYPE(pxm_) .EQS. "" THEN GOSUB PBMDEV_INIT
+$ SETDEV pnmraw 'pxm_'
+$ RETURN
+$ !
+$ PNGMONO_DEV:
+$ IF F$TYPE(png_) .EQS. "" THEN GOSUB LIBPNG_DEV
+$ SETDEV pngmono 'png_'
+$ ADDMOD pngmono -include libpng
+$ RETURN
+$ !
+$ PNGGRAY_DEV:
+$ IF F$TYPE(png_) .EQS. "" THEN GOSUB LIBPNG_DEV
+$ SETDEV pnggray 'png_'
+$ ADDMOD pnggray -include libpng
+$ RETURN
+$ !
+$ PNG16_DEV:
+$ IF F$TYPE(png_) .EQS. "" THEN GOSUB LIBPNG_DEV
+$ SETDEV png16 'png_'
+$ ADDMOD png16 -include libpng
+$ RETURN
+$ !
+$ PNG256_DEV:
+$ IF F$TYPE(png_) .EQS. "" THEN GOSUB LIBPNG_DEV
+$ SETDEV png256 'png_'
+$ ADDMOD png256 -include libpng
+$ RETURN
+$ !
+$ PNG16M_DEV:
+$ IF F$TYPE(png_) .EQS. "" THEN GOSUB LIBPNG_DEV
+$ SETDEV png16m 'png_'
+$ ADDMOD png16m -include libpng
+$ RETURN
+$ !
+$ PSMONO_DEV:
+$ ps_ = "gdevpsim.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ SETDEV psmono 'ps_'
+$ ADD_DEV_MODULES = "''ps_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ PSGRAY_DEV:
+$ ps_ = "gdevpsim.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ SETDEV psgray 'ps_'
+$ ADD_DEV_MODULES = "''ps_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ TFAX_DEV:
+$ tfax_ = "gdevtfax.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ GOSUB CFE_DEV
+$ GOSUB LZWE_DEV
+$ GOSUB RLE_DEV
+$ GOSUB TIFFS_DEV
+$ SETMOD tfax 'tfax_'
+$ ADDMOD tfax -include cfe lzwe rle tiffs
+$ ADD_DEV_MODULES = "''tfax_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ FAXG3_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV faxg3 -include tfax
+$ RETURN
+$ !
+$ FAXG32D_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV faxg32d -include tfax
+$ RETURN
+$ !
+$ FAXG4_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV faxg4 -include tfax
+$ RETURN
+$ !
+$ TIFFS_DEV:
+$ IF F$TYPE(tiffs_) .NES. "" THEN RETURN
+$ tiffs_ = "gdevtifs.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ SETMOD tiffs 'tiffs_'
+$ ADD_DEV_MODULES = "''tiffs_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ TIFFCRLE_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tiffcrle -include tfax
+$ RETURN
+$ !
+$ TIFFG3_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tiffg3 -include tfax
+$ RETURN
+$ !
+$ TIFFG32D_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tiffg32d -include tfax
+$ RETURN
+$ !
+$ TIFFG4_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tiffg4 -include tfax
+$ RETURN
+$ !
+$ TIFFLZW_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tifflzw -include tfax
+$ RETURN
+$ !
+$ TIFFPACK_DEV:
+$ IF F$TYPE(tfax_) .EQS. "" THEN GOSUB TFAX_DEV
+$ SETDEV tiffpack -include tfax
+$ RETURN
+$ !
+$ TIFF12NC_DEV:
+$ tiff12nc_ = "gdevtfnx.obj gdevtifs.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ SETDEV tiff12nc 'tiff12nc_'
+$ ADD_DEV_MODULES = "''tiff12nc_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ TIFF24NC_DEV:
+$ tiff24nc_ = "gdevtfnx.obj gdevtifs.obj gdevprn.obj"
+$ GOSUB CLIST_DEV
+$ SETDEV tiff24nc 'tiff24nc_'
+$ ADD_DEV_MODULES = "''tiff24nc_'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ VMS_DEV:
+$ vms__ = "gp_nofb.obj gp_vms.obj"
+$ SETMOD vms_ 'vms__'
+$ ADD_DEV_MODULES = "''vms__'"
+$ GOSUB ADD_DEV_MOD
+$ RETURN
+$ !
+$ ADD_DEV_MOD:
+$ II = 0
+$ ADD_MORE:
+$ DEV_NOW = F$EDIT(F$ELEMENT(II," ",ADD_DEV_MODULES),"UPCASE") - ".OBJ"
+$ IF DEV_NOW .EQS. " " THEN RETURN
+$ II = II + 1
+$ ! add delimiters to avoid mistaken identities
+$ ! (e.g., a search for "x11" finding "x11alpha")
+$ IF F$LOCATE(" "+DEV_NOW+" ",DEV_MODULES) .NE. F$LENGTH(DEV_MODULES) THEN -
+ GOTO ADD_MORE
+$ NDEVL = 0
+$ CHECK_LOOP:
+$ IF F$Type(DEV_MODULES'NDEVL') .EQS. "" THEN GOTO ADD_THIS
+$ IF F$LOCATE(" "+DEV_NOW+" ",DEV_MODULES'NDEVL') .NE. -
+ F$LENGTH(DEV_MODULES'NDEVL') THEN GOTO ADD_MORE
+$ NDEVL = NDEVL + 1
+$ IF NDEVL .LE. NDEV_MOD THEN GOTO CHECK_LOOP
+$ ADD_THIS:
+$ DEV_MODULES = DEV_MODULES + DEV_NOW + " "
+$ IF F$Length(DEV_MODULES) .GT. 512
+$ THEN
+$ DEV_MODULES = F$EDIT(DEV_MODULES,"TRIM")
+$ DEV_MODULES = F$EDIT(DEV_MODULES,"COMPRESS")
+$ DEV_MODULES'NDEV_MOD' = DEV_MODULES + " "
+$ NDEV_MOD = NDEV_MOD + 1
+$ DEV_MODULES = " "
+$ ENDIF
+$ GOTO ADD_MORE
+$ !
+$ DONE:
+$ !
+$ IF P1 .EQS. "DEBUG" .OR. P2 .EQS. "DEBUG" THEN GOTO AFTER_DEL
+$ DELETE *.DEV;*
+$ IF F$SEARCH("DEVS.TR") .NES. "" THEN DELETE DEVS.TR;*
+$ IF F$SEARCH("ECHOGS.EXE") .NES. "" THEN DELETE ECHOGS.EXE;*
+$ IF F$SEARCH("GENCONF.EXE") .NES. "" THEN DELETE GENCONF.EXE;*
+$ IF F$SEARCH("GSSETDEV.COM") .NES. "" THEN DELETE GSSETDEV.COM;*,-
+ GSSETMOD.COM;*,GSADDMOD.COM;*
+$ IF F$SEARCH("JCONFIG.H") .NES. "" THEN DELETE JCONFIG.H;*,JMORECFG.H;*,-
+ JMCORIG.H;*,JERROR.H;*,JINCLUDE.H;*,JPEGLIB.H;*,JVERSION.H;*
+$ IF F$SEARCH("PNG.H") .NES. "" THEN DELETE PNG.H;*,PNGCONF.H;*
+$ IF F$SEARCH("ZCONF.H") .NES. "" THEN DELETE ZCONF.H;*,ZLIB.H;*,-
+ ZUTIL.H;*,DEFLATE.H;*
+$AFTER_DEL:
+$ IF F$LOGICAL("OPT_FILE") .NES. "" THEN CLOSE OPT_FILE
+$ IF F$LOGICAL("X11") .NES. "" THEN DEASSIGN X11
+$ !
+$ ! ALL DONE
+$ EXIT
+$ !
+$ NO_ACTION:
+$ !
+$ WSO "No such device routine: ''ACTION'"
+$ GOTO DONE
diff --git a/gs/src/vmsmath.h b/gs/src/vmsmath.h
new file mode 100644
index 000000000..f37cf2832
--- /dev/null
+++ b/gs/src/vmsmath.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* vmsmath.h */
+/* Substitute for math.h on VAX/VMS systems */
+
+/* DEC VAX/VMS C comes with a math.h file but GNU VAX/VMS C does not. */
+/* This file substitutes for math.h when using GNU C. */
+# ifndef __MATH
+# define __MATH
+# if CC$gfloat
+# define HUGE_VAL 8.988465674311578540726371186585e+307
+# else
+# define HUGE_VAL 1.70141183460469229e+38
+# endif
+ extern double acos(), asin(), atan(), atan2();
+ extern double sin(), tan(), cos();
+ extern double cosh(), sinh(), tanh();
+ extern double exp(), frexp(), ldexp(), log(), log10(), pow();
+ extern double modf(), fmod(), sqrt(), ceil(), floor();
+ extern double fabs(), cabs(), hypot();
+# endif
diff --git a/gs/src/watc.mak b/gs/src/watc.mak
new file mode 100644
index 000000000..3db884693
--- /dev/null
+++ b/gs/src/watc.mak
@@ -0,0 +1,230 @@
+# Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for MS-DOS/Watcom C386 platform.
+# We strongly recommend that you read the Watcom section of make.txt
+# before attempting to build Ghostscript with the Watcom compiler.
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+GS_DOCDIR=c:/gs
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with \;.
+# Use / to indicate directories, not a single \.
+
+GS_LIB_DEFAULT=.;c:/gs\;c:/gs/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+DEBUG=0
+
+# Setting TDEBUG=1 includes symbol table information for the Watcom debugger.
+# (This option is NOT needed for using the Watcom profiler.)
+# Code runs substantially slower, because some optimizations are disabled.
+
+TDEBUG=0
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+NOPRIVATE=0
+
+# Define the name of the executable file.
+
+GS=gs386
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# Define any other compilation flags. Including -DA4 makes A4 paper size
+# the default for most, but not, printer drivers.
+
+CFLAGS=
+
+# ------ Platform-specific options ------ #
+
+# Define which version of Watcom C we are using.
+# Possible values are 8.5, 9.0, 9.5, 10.0, or 10.5.
+# Unfortunately, wmake can only test identity, not compare magnitudes,
+# so the version must be exactly one of those strings.
+WCVERSION=10.0
+
+# Define the locations of the libraries.
+LIBPATHS=LIBPATH $(%WATCOM)\lib386 LIBPATH $(%WATCOM)\lib386\dos
+
+# Choose platform-specific options.
+
+# Define the processor (CPU) type. Options are 386,
+# 485 (486SX or Cyrix 486SLC), 486 (486DX), or 586 (Pentium).
+# Currently the only difference is that 486 and above assume
+# the presence of a FPU, and the other processor types do not.
+
+CPU_TYPE=386
+
+# Define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If CPU_TYPE is 486 or above, FPU_TYPE is implicitly set to 387,
+# since 486DX and later processors include the equivalent of an 80387 on-chip.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+FPU_TYPE=0
+
+# ---------------------------- End of options ---------------------------- #
+
+# Define the platform name.
+
+PLATFORM=watc_
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=watc.mak
+
+# Define additional platform compilation flags.
+
+PLATOPT=
+
+!include wccommon.mak
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+# Since we have a large address space, we include some optional features.
+
+FEATURE_DEVS=level2.dev pdf.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=vga.dev ega.dev svga16.dev
+DEVICE_DEVS1=atiw.dev tseng.dev tvga.dev
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=uniprint.dev
+DEVICE_DEVS6=epson.dev eps9high.dev ibmpro.dev bj10e.dev bj200.dev bjc600.dev bjc800.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=bmpmono.dev bmp16.dev bmp256.dev bmp16m.dev tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev psgray.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev
+
+!include wctail.mak
+!include devs.mak
+!include int.mak
+
+# -------------------------------- Library -------------------------------- #
+
+# The Watcom C platform
+
+watc__=gp_iwatc.$(OBJ) gp_msdos.$(OBJ) gp_dosfb.$(OBJ) gp_dosfs.$(OBJ) gp_dosfe.$(OBJ)
+watc_.dev: $(watc__)
+ $(SETMOD) watc_ $(watc__)
+
+gp_iwatc.$(OBJ): gp_iwatc.c $(stat__h) $(string__h) $(gx_h) $(gp_h)
+
+# ----------------------------- Main program ------------------------------ #
+
+BEGINFILES=*.err
+# The Watcom compiler doesn't recognize wildcards;
+# we don't want any compilation to fail.
+CCBEGIN=for %%f in (gs*.c gx*.c z*.c) do $(CCC) %%f
+
+LIBDOS=$(LIB_ALL) gp_iwatc.$(OBJ) gp_msdos.$(OBJ) gp_dosfb.$(OBJ) gp_dosfs.$(OBJ) $(ld_tr)
+
+# Interpreter main program
+
+GS_ALL=gs.$(OBJ) $(INT_ALL) $(INTASM) $(LIBDOS)
+
+ll_tr=ll$(CONFIG).tr
+$(ll_tr): $(MAKEFILE)
+ echo SYSTEM DOS4G >$(ll_tr)
+ echo OPTION STUB=$(STUB) >>$(ll_tr)
+ echo OPTION STACK=16k >>$(ll_tr)
+
+$(GS_XE): $(GS_ALL) $(DEVS_ALL) $(ll_tr)
+ $(LINK) $(LCT) NAME $(GS) OPTION MAP=$(GS) FILE gs @$(ld_tr) @$(ll_tr)
diff --git a/gs/src/watclib.mak b/gs/src/watclib.mak
new file mode 100644
index 000000000..f915db79e
--- /dev/null
+++ b/gs/src/watclib.mak
@@ -0,0 +1,109 @@
+# Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for MS-DOS / Watcom C/C++ library testing.
+
+libdefault: gslib.exe
+ %null
+
+GS_DOCDIR=c:/gs
+GS_LIB_DEFAULT=.;c:/gs\;c:/gs/fonts
+SEARCH_HERE_FIRST=1
+GS_INIT=gs_init.ps
+
+DEBUG=1
+TDEBUG=0
+NOPRIVATE=1
+
+GS=gslib
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+PSRCDIR=libpng
+PVERSION=96
+SHARE_LIBPNG=0
+LIBPNG_NAME=png
+
+ZSRCDIR=zlib
+SHARE_ZLIB=0
+ZLIB_NAME=z
+
+CONFIG=
+CFLAGS=
+
+# Allow predefinition of WCVERSION
+# when using this makefile from inside another one.
+!ifndef WCVERSION
+WCVERSION=10.0
+!endif
+LIBPATHS=LIBPATH $(%WATCOM)\lib386 LIBPATH $(%WATCOM)\lib386\dos
+STUB=$(%WATCOM)\binb\wstub.exe
+
+CPU_TYPE=386
+FPU_TYPE=0
+
+PLATFORM=watclib_
+MAKEFILE=watclib.mak
+PLATOPT=
+
+!include wccommon.mak
+
+# Allow predefinition of selectable options
+# when using this makefile from inside another one.
+!ifndef FEATURE_DEVS
+FEATURE_DEVS=patlib.dev path1lib.dev hsblib.dev
+!endif
+!ifndef DEVICE_DEVS
+DEVICE_DEVS=vga.dev
+!endif
+!ifndef COMPILE_INITS
+COMPILE_INITS=0
+!endif
+!ifndef BAND_LIST_STORAGE
+BAND_LIST_STORAGE=file
+!endif
+!ifndef BAND_LIST_COMPRESSOR
+BAND_LIST_COMPRESSOR=zlib
+!endif
+!ifndef FILE_IMPLEMENTATION
+FILE_IMPLEMENTATION=stdio
+!endif
+
+!include wctail.mak
+!include devs.mak
+
+watclib__=gp_iwatc.$(OBJ) gp_msdos.$(OBJ) gp_nofb.$(OBJ) gp_dosfs.$(OBJ) gp_dosfe.$(OBJ)
+watclib_.dev: $(watclib__)
+ $(SETMOD) watclib_ $(watclib__)
+
+gp_iwatc.$(OBJ): gp_iwatc.c $(stat__h) $(string__h) $(gx_h) $(gp_h)
+
+BEGINFILES=*.err
+CCBEGIN=for %%f in (gs*.c gx*.c z*.c) do $(CCC) %%f
+
+LIB_ONLY=gslib.obj gsnogc.obj gconfig.obj gscdefs.obj
+ll_tr=ll$(CONFIG).tr
+$(ll_tr): $(MAKEFILE)
+ echo SYSTEM DOS4G >$(ll_tr)
+ echo OPTION STUB=$(STUB) >>$(ll_tr)
+ echo OPTION STACK=12k >>$(ll_tr)
+ echo FILE gsnogc.obj >>$(ll_tr)
+ echo FILE gconfig.obj >>$(ll_tr)
+ echo FILE gscdefs.obj >>$(ll_tr)
+
+gslib.exe: $(LIB_ALL) $(LIB_ONLY) $(ld_tr) $(ll_tr)
+ $(LINK) $(LCT) NAME gslib OPTION MAP=gslib FILE gslib @$(ld_tr) @$(ll_tr)
diff --git a/gs/src/watcw32.mak b/gs/src/watcw32.mak
new file mode 100644
index 000000000..5406d70ef
--- /dev/null
+++ b/gs/src/watcw32.mak
@@ -0,0 +1,414 @@
+# Copyright (C) 1991-1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# watcw32.mak
+# makefile for Watcom C++ v??, Windows NT or Windows 95 platform.
+# Does NOT build gs16spl.exe, which is 16-bit and is used under Win32s.
+# Someone with access to the Watcom 16-bit documentation will need to
+# do this.
+# Created 1997-02-23 by Russell Lang from MSVC++ 4.0 makefile.
+#**************** THIS MAKEFILE DOES NOT WORK. ****************
+#**************** DO NOT ATTEMPT TO USE IT. ****************
+
+# ------------------------------- Options ------------------------------- #
+
+###### This section is the only part of the file you should need to edit.
+
+# ------ Generic options ------ #
+
+# Define the directory that will hold documentation at runtime.
+
+GS_DOCDIR=c:/gs
+
+# Define the default directory/ies for the runtime
+# initialization and font files. Separate multiple directories with \;.
+# Use / to indicate directories, not a single \.
+
+GS_LIB_DEFAULT=.;c:/gs\;c:/gs/fonts
+
+# Define whether or not searching for initialization files should always
+# look in the current directory first. This leads to well-known security
+# and confusion problems, but users insist on it.
+# NOTE: this also affects searching for files named on the command line:
+# see the "File searching" section of use.txt for full details.
+# Because of this, setting SEARCH_HERE_FIRST to 0 is not recommended.
+
+SEARCH_HERE_FIRST=1
+
+# Define the name of the interpreter initialization file.
+# (There is no reason to change this.)
+
+GS_INIT=gs_init.ps
+
+# Choose generic configuration options.
+
+# Setting DEBUG=1 includes debugging features (-Z switch) in the code.
+# Code runs substantially slower even if no debugging switches are set,
+# and also takes about another 25K of memory.
+
+DEBUG=0
+
+# Setting TDEBUG=1 includes symbol table information for the debugger,
+# and also enables stack checking. Code is substantially slower and larger.
+
+TDEBUG=0
+
+# Setting NOPRIVATE=1 makes private (static) procedures and variables public,
+# so they are visible to the debugger and profiler.
+# No execution time or space penalty, just larger .OBJ and .EXE files.
+
+NOPRIVATE=0
+
+# Define the name of the executable file.
+
+GS=gswin32
+GSCONSOLE=gswin32c
+GSDLL=gsdll32
+
+# To build two small executables and a large DLL use MAKEDLL=1
+# To build two large executables use MAKEDLL=0
+
+MAKEDLL=1
+
+# Define the directory where the IJG JPEG library sources are stored,
+# and the major version of the library that is stored there.
+# You may need to change this if the IJG library version changes.
+# See jpeg.mak for more information.
+
+JSRCDIR=jpeg-6a
+JVERSION=6
+
+# Define the directory where the PNG library sources are stored,
+# and the version of the library that is stored there.
+# You may need to change this if the libpng version changes.
+# See libpng.mak for more information.
+
+PSRCDIR=libpng
+PVERSION=96
+
+# Define the directory where the zlib sources are stored.
+# See zlib.mak for more information.
+
+ZSRCDIR=zlib
+
+# Define the configuration ID. Read gs.mak carefully before changing this.
+
+CONFIG=
+
+# Define any other compilation flags.
+
+CFLAGS=
+
+# ------ Platform-specific options ------ #
+
+# Define the drive, directory, and compiler name for the Watcom C files.
+# COMPDIR contains the compiler and linker.
+# INCDIR contains the include files.
+# LIBDIR contains the library files.
+# COMP is the full C compiler path name.
+# COMPCPP is the full C++ compiler path name.
+# COMPAUX is the compiler name for DOS utilities.
+# RCOMP is the resource compiler name.
+# LINK is the full linker path name.
+# WBIND is used for binding resources to an EXE or DLL
+# Note that INCDIR and LIBDIR are always followed by a \,
+# so if you want to use the current directory, use an explicit '.'.
+
+COMPBASE=d:\watcom
+COMPDIR=$(COMPBASE)\binb
+INCDIR=$(COMPBASE)\h;$(COMPBASE)\h\nt
+LIBDIR=$(COMPBASE)\lib386;$(COMPBASE)\lib386\nt
+COMP=$(COMPDIR)\wcc386
+COMPCPP=$(COMPDIR)\wpp386
+COMPAUX=$(COMPDIR)\wcc386
+RCOMP=$(COMPDIR)\wrc
+LINK=$(COMPDIR)\wlink
+WBIND=$(COMPDIR)\wbind
+
+# Define the processor architecture. (always i386)
+CPU_FAMILY=i386
+
+# Define the processor (CPU) type. (386, 486 or 586)
+CPU_TYPE=486
+
+# Define the math coprocessor (FPU) type.
+# Options are -1 (optimize for no FPU), 0 (optimize for FPU present,
+# but do not require a FPU), 87, 287, or 387.
+# If you have a 486 or Pentium CPU, you should normally set FPU_TYPE to 387,
+# since most of these CPUs include the equivalent of an 80387 on-chip;
+# however, the 486SX and the Cyrix 486SLC do not have an on-chip FPU, so if
+# you have one of these CPUs and no external FPU, set FPU_TYPE to -1 or 0.
+# An xx87 option means that the executable will run only if a FPU
+# of that type (or higher) is available: this is NOT currently checked
+# at runtime.
+
+FPU_TYPE=0
+
+# ------ Devices and features ------ #
+
+# Choose the language feature(s) to include. See gs.mak for details.
+
+FEATURE_DEVS=level2.dev pdf.dev ttfont.dev
+
+# Choose whether to compile the .ps initialization files into the executable.
+# See gs.mak for details.
+
+COMPILE_INITS=0
+
+# Choose whether to store band lists on files or in memory.
+# The choices are 'file' or 'memory'.
+
+BAND_LIST_STORAGE=file
+
+# Choose which compression method to use when storing band lists in memory.
+# The choices are 'lzw' or 'zlib'. lzw is not recommended, because the
+# LZW-compatible code in Ghostscript doesn't actually compress its input.
+
+BAND_LIST_COMPRESSOR=zlib
+
+# Choose the implementation of file I/O: 'stdio', 'fd', or 'both'.
+# See gs.mak and sfxfd.c for more details.
+
+FILE_IMPLEMENTATION=stdio
+
+# Choose the device(s) to include. See devs.mak for details.
+
+DEVICE_DEVS=mswindll.dev mswinprn.dev mswinpr2.dev
+DEVICE_DEVS2=epson.dev eps9high.dev eps9mid.dev epsonc.dev ibmpro.dev
+DEVICE_DEVS3=deskjet.dev djet500.dev laserjet.dev ljetplus.dev ljet2p.dev ljet3.dev ljet4.dev
+DEVICE_DEVS4=cdeskjet.dev cdjcolor.dev cdjmono.dev cdj550.dev pj.dev pjxl.dev pjxl300.dev
+DEVICE_DEVS5=djet500c.dev declj250.dev lj250.dev jetp3852.dev r4081.dev lbp8.dev uniprint.dev
+DEVICE_DEVS6=st800.dev stcolor.dev bj10e.dev bj200.dev m8510.dev necp6.dev bjc600.dev bjc800.dev
+DEVICE_DEVS7=t4693d2.dev t4693d4.dev t4693d8.dev tek4696.dev
+DEVICE_DEVS8=pcxmono.dev pcxgray.dev pcx16.dev pcx256.dev pcx24b.dev pcxcmyk.dev
+DEVICE_DEVS9=pbm.dev pbmraw.dev pgm.dev pgmraw.dev pgnm.dev pgnmraw.dev pnm.dev pnmraw.dev ppm.dev ppmraw.dev
+DEVICE_DEVS10=tiffcrle.dev tiffg3.dev tiffg32d.dev tiffg4.dev tifflzw.dev tiffpack.dev
+DEVICE_DEVS11=bmpmono.dev bmp16.dev bmp256.dev bmp16m.dev tiff12nc.dev tiff24nc.dev
+DEVICE_DEVS12=psmono.dev bit.dev bitrgb.dev bitcmyk.dev
+DEVICE_DEVS13=pngmono.dev pnggray.dev png16.dev png256.dev png16m.dev
+DEVICE_DEVS14=jpeg.dev jpeggray.dev
+DEVICE_DEVS15=pdfwrite.dev pswrite.dev epswrite.dev pxlmono.dev pxlcolor.dev
+
+# ---------------------------- End of options ---------------------------- #
+
+# Define the name of the makefile -- used in dependencies.
+
+MAKEFILE=watcw32.mak winlib.mak winint.mak
+
+# Define the current directory prefix and shell invocations.
+
+D=\\
+
+EXPP=
+SH=
+# The following is needed to work around a problem in wmake
+SHP=command /c
+
+# Define the arguments for genconf.
+
+CONFILES=-p %%s, -o $(ld_tr) -l lib.tr
+
+# Define the generic compilation flags.
+
+PLATOPT=
+
+INTASM=
+PCFBASM=
+
+# Make sure we get the right default target for make.
+
+dosdefault: default
+
+# Define the compilation flags.
+
+!ifeq CPU_TYPE 586
+CPFLAGS=-5s
+!else
+!ifeq CPU_TYPE 486
+CPFLAGS=-4s
+!else
+!ifeq CPU_TYPE 386
+CPFLAGS=-3s
+!else
+CPFLAGS=
+!endif
+!endif
+!endif
+
+!ifeq FPU_TYPE 586
+FPFLAGS=-fp5
+!else
+!ifeq FPU_TYPE 486
+FPFLAGS=-fp4
+!else
+!ifeq FPU_TYPE 386
+FPFLAGS=-fp3
+!else
+FPFLAGS=
+!endif
+!endif
+!endif
+
+
+!ifneq NOPRIVATE 0
+CP=/DNOPRIVATE
+!else
+CP=
+!endif
+
+!ifneq DEBUG 0
+CD=/DDEBUG
+!else
+CD=
+!endif
+
+!ifneq TDEBUG 0
+# What options should WATCOM use for $(CT) when debugging?
+CT=-d2
+LCT=DEBUG ALL
+COMPILE_FULL_OPTIMIZED= # no optimization when debugging
+COMPILE_WITH_FRAMES= # no optimization when debugging
+COMPILE_WITHOUT_FRAMES= # no optimization when debugging
+!else
+CT=-d1
+LCT=DEBUG LINES
+COMPILE_FULL_OPTIMIZED=-Oilmre -s
+COMPILE_WITH_FRAMES=-Of+
+COMPILE_WITHOUT_FRAMES=-s
+!endif
+
+!ifneq DEBUG 0
+CS=
+!else
+CS=-s
+!endif
+
+
+# Specify output object name
+CCOBJNAME=-Fo
+
+# Specify function prolog type
+COMPILE_FOR_DLL=/LD
+COMPILE_FOR_EXE=
+COMPILE_FOR_CONSOLE_EXE=
+
+GENOPT=$(CP) $(CD) $(CT) $(CS) -zq
+
+CCFLAGS=$(PLATOPT) $(FPFLAGS) $(CPFLAGS) $(CFLAGS) $(XCFLAGS)
+CC=$(COMP) -c $(CCFLAGS) @ccf32.tr
+CPP=$(COMPCPP) -c $(CCFLAGS) @ccf32.tr
+!ifneq MAKEDLL 0
+WX=$(COMPILE_FOR_DLL)
+!else
+WX=$(COMPILE_FOR_EXE)
+!endif
+CCC=$(CC) $(WX) $(COMPILE_FULL_OPTIMIZED)
+CCD=$(CC) $(WX) $(COMPILE_WITH_FRAMES)
+CCINT=$(CC)
+CCCF=$(CCC)
+CCLEAF=$(CCC) $(COMPILE_WITHOUT_FRAMES)
+
+# Compiler for auxiliary programs
+
+CCAUX=$(COMPAUX) -I$(INCDIR) -O
+
+# Rule for compiling Windows programs
+
+CCCWIN=$(CCC)
+
+# Define the generic compilation rules.
+
+.c.obj:
+ $(CCC) $<
+
+.cpp.obj:
+ $(CPP) $<
+
+# Define the files to be removed by `make clean'.
+# nmake expands macros when encountered, not when used,
+# so this must precede the !include statements.
+
+BEGINFILES2=gsdll32.rex gswin32.rex gswin32c.rex
+
+# Include the generic makefiles.
+
+!include winlib.mak
+!include winint.mak
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+ccf32.tr: $(MAKEFILE) makefile
+ echo $(GENOPT) -I$(INCDIR) -DCHECK_INTERRUPTS -D_Windows -D__WIN32__ -D_WATCOM_ > ccf32.tr
+
+$(GENARCH_XE): genarch.c $(stdpre_h) $(iref_h) ccf32.tr
+ $(CCAUX_SETUP)
+ $(CCAUX) @ccf32.tr genarch.c $(CCAUX_TAIL)
+
+# -------------------------------- Library -------------------------------- #
+
+# See winlib.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+#LIBCTR=libc32.tr
+LIBCTR=
+
+#rjl
+#$(LIBCTR): $(MAKEFILE) $(ECHOGS_XE)
+# echogs -w $(LIBCTR) $(LIBDIR)\shell32.lib
+# echogs -a $(LIBCTR) $(LIBDIR)\comdlg32.lib
+
+DWOBJLINK=dwdll.obj, dwimg.obj, dwmain.obj, dwtext.obj, gscdefs.obj
+DWOBJNOLINK= dwnodll.obj, dwimg.obj, dwmain.obj, dwtext.obj
+OBJCLINK=dwmainc.obj, dwdllc.obj, gscdefs.obj
+OBJCNOLINK=dwmainc.obj, dwnodllc.obj
+
+!ifneq MAKEDLL 0
+# The graphical small EXE loader
+$(GS_XE): $(GSDLL).dll $(GSDLL).lib $(DWOBJ) $(GSCONSOLE).exe $(GS).res
+ $(LINK) system nt_win $(LCT) Name $(GS_XE) File $(DWOBJLINK) Library $(GSDLL).lib
+ $(WBIND) $(GS_XE) -R $(GS).res
+
+# The console mode small EXE loader
+$(GSCONSOLE).exe: $(OBJC) $(GS).res dw32c.def
+ $(LINK) system nt option map $(LCT) Name $(GSCONSOLE).exe File $(OBJCLINK) Library $(GSDLL).lib
+ $(WBIND) $(GSCONSOLE).exe -R $(GS).res
+
+# The big DLL
+$(GSDLL).dll: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(GSDLL).res
+ $(LINK) system nt_dll initinstance terminstance @gsdll32.wex $(LCT) Name $(GSDLL).dll File gsdll.obj, @$(ld_tr)
+ $(WBIND) $(GSDLL).dll -R $(GSDLL).res
+
+$(GSDLL).lib: $(GSDLL).dll
+ erase $(GSDLL).lib
+ wlib $(GSDLL) +$(GSDLL).dll
+
+!else
+# The big graphical EXE
+$(GS_XE): $(GSCONSOLE).exe $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(DWOBJNO) $(GS).res dwmain32.def
+ $(LINK) option map $(LCT) Name $(GS) File gsdll, $(DWOBJNOLINK), @$(ld_tr)
+ $(WBIND) $(GS_XE) -R $(GSDLL).res
+
+# The big console mode EXE
+$(GSCONSOLE).exe: $(GS_ALL) $(DEVS_ALL) gsdll.$(OBJ) $(OBJCNO) $(GS).res dw32c.def
+ $(COMPDIR)\$(LINK) option map $(LCT) Name $(GSCONSOLE).exe File gsdll, $(OBJCNOLINK), @$(ld_tr)
+ $(WBIND) $(GSCONSOLE).exe -R $(GSDLL).res
+!endif
+
+# end of makefile
+
+
diff --git a/gs/src/wccommon.mak b/gs/src/wccommon.mak
new file mode 100644
index 000000000..71bd2751a
--- /dev/null
+++ b/gs/src/wccommon.mak
@@ -0,0 +1,191 @@
+# Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# wccommon.mak
+# Section of Watcom C/C++ makefile common to MS-DOS and MS Windows.
+# We strongly recommend that you read the Watcom section of make.txt
+# before attempting to build Ghostscript with the Watcom compiler.
+
+# This file is used by watc.mak, watcwin.mak, and watclib.mak.
+# Those files supply the following parameters:
+# Configuration, public:
+# GS_LIB_DEFAULT, SEARCH_HERE_FIRST, GS_INIT, FEATURE_DEVS,
+# DEVICE_DEVS*, COMPILE_INITS, BAND_LIST_*
+# Configuration, internal, generic:
+# PLATFORM, MAKEFILE, AK, CC*, DEBUG, NOPRIVATE, CP_, RM_, RMN_
+# Configuration, internal, specific to DOS/Windows:
+# TDEBUG, USE_ASM, ASM,
+# COMPDIR, INCDIR, LIBPATHS,
+# CPU_TYPE, FPU_TYPE
+
+# We want Unix-compatible behavior. This is part of it.
+
+.NOCHECK
+
+# Define additional extensions to keep `make' happy
+
+.EXTENSIONS: .be .z
+
+# Define the ANSI-to-K&R dependency. Watcom C accepts ANSI syntax.
+
+AK=
+
+# Note that built-in libpng and zlib aren't available.
+
+SHARE_LIBPNG=0
+SHARE_ZLIB=0
+
+# Define the extensions for command, object, and executable files.
+
+CMD=.bat
+O=-fo=
+OBJ=obj
+XE=.exe
+XEAUX=.exe
+
+# Define the current directory prefix and shell invocations.
+
+D=\\
+
+EXPP=dos4gw
+SH=
+# The following is needed to work around a problem in wmake.
+SHP=command /c
+
+# Define generic commands.
+
+CP_=call cp.bat
+RM_=erase
+RMN_=call rm.bat
+
+# Define the arguments for genconf.
+
+CONFILES=-p FILE&s&ps -ol $(ld_tr)
+
+# Define the names of the Watcom C files.
+# See the comments in watc.mak and watcwin.mak regarding WCVERSION.
+
+!ifeq WCVERSION 10.5
+COMP=$(%WATCOM)\binw\wcc386
+LINK=$(%WATCOM)\binw\wlink
+STUB=$(%WATCOM)\binw\wstub.exe
+WRC=$(%WATCOM)\binw\wrc.exe
+!else
+!ifeq WCVERSION 10.0
+COMP=$(%WATCOM)\binb\wcc386
+LINK=$(%WATCOM)\bin\wlink
+STUB=$(%WATCOM)\binb\wstub.exe
+WRC=$(%WATCOM)\binb\wrc.exe
+!else
+!ifeq WCVERSION 9.5
+COMP=$(%WATCOM)\bin\wcc386
+LINK=$(%WATCOM)\bin\wlinkp
+STUB=$(%WATCOM)\binb\wstub.exe
+WRC=$(%WATCOM)\binb\wrc.exe
+!else
+COMP=$(%WATCOM)\bin\wcc386p
+LINK=$(%WATCOM)\bin\wlinkp
+STUB=$(%WATCOM)\binb\wstub.exe
+WRC=$(%WATCOM)\binb\rc.exe
+!endif
+!endif
+!endif
+INCDIR=$(%WATCOM)\h
+WBIND=$(%WATCOM)\binb\wbind.exe
+
+# Define the generic compilation flags.
+
+!ifeq CPU_TYPE 586
+!ifeq FPU_TYPE 0
+FPU_TYPE=387
+!endif
+!else
+!ifeq CPU_TYPE 486
+!ifeq FPU_TYPE 0
+FPU_TYPE=387
+!endif
+!endif
+!endif
+
+!ifeq FPU_TYPE 387
+FPFLAGS=-fpi87
+!else
+!ifeq FPU_TYPE 287
+FPFLAGS=-fpi287
+!else
+!ifeq FPU_TYPE -1
+FPFLAGS=-fpc
+!else
+FPFLAGS=-fpi
+!endif
+!endif
+!endif
+
+INTASM=
+PCFBASM=
+
+# Define the generic compilation rules.
+
+.asm.obj:
+ $(ASM) $(ASMFLAGS) $<;
+
+# Make sure we get the right default target for make.
+
+dosdefault: default
+ %null
+
+# Define the compilation flags.
+
+!ifneq NOPRIVATE 0
+CP=-dNOPRIVATE
+!else
+CP=
+!endif
+
+!ifneq DEBUG 0
+CD=-dDEBUG
+!else
+CD=
+!endif
+
+!ifneq TDEBUG 0
+CT=-d2
+LCT=DEBUG ALL
+!else
+CT=-d1
+LCT=DEBUG LINES
+!endif
+
+!ifneq DEBUG 0
+CS=
+!else
+CS=-s
+!endif
+
+GENOPT=$(CP) $(CD) $(CT) $(CS)
+
+CCFLAGS=$(GENOPT) $(PLATOPT) $(FPFLAGS) $(CFLAGS) $(XCFLAGS)
+CC=$(COMP) -oi -i=$(INCDIR) $(CCFLAGS) -zq
+CCAUX=$(COMP) -oi -i=$(INCDIR) $(FPFLAGS) -zq
+CCC=$(CC)
+CCD=$(CC)
+CCCF=$(CC)
+CCINT=$(COMP) -oit -i=$(INCDIR) $(CCFLAGS)
+CCLEAF=$(CCC) -s
+
+.c.obj:
+ $(CCC) $<
diff --git a/gs/src/wctail.mak b/gs/src/wctail.mak
new file mode 100644
index 000000000..4e697ad95
--- /dev/null
+++ b/gs/src/wctail.mak
@@ -0,0 +1,75 @@
+# Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# wctail.mak
+# Last part of Watcom C/C++ makefile common to MS-DOS and MS Windows.
+
+# Define the name of this makefile.
+WCTAIL_MAK=wctail.mak
+
+# Include the generic makefiles, except for devs.mak and int.mak.
+!include version.mak
+!include gs.mak
+!include lib.mak
+!include jpeg.mak
+!include libpng.mak
+!include zlib.mak
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ECHOGS_XE): echogs.$(OBJ)
+ echo OPTION STUB=$(STUB) >_temp_.tr
+ echo $LIBPATHS >>_temp_.tr
+ $(LINK) @_temp_.tr FILE echogs
+
+echogs.$(OBJ): echogs.c
+ $(CCAUX) echogs.c
+
+$(GENARCH_XE): genarch.$(OBJ)
+ echo $LIBPATHS >_temp_.tr
+ $(LINK) @_temp_.tr FILE genarch
+
+genarch.$(OBJ): genarch.c $(stdpre_h)
+ $(CCAUX) genarch.c
+
+$(GENCONF_XE): genconf.$(OBJ)
+ echo OPTION STUB=$(STUB) >_temp_.tr
+ echo OPTION STACK=8k >>_temp_.tr
+ echo $LIBPATHS >>_temp_.tr
+ $(LINK) @_temp_.tr FILE genconf
+
+genconf.$(OBJ): genconf.c $(stdpre_h)
+ $(CCAUX) genconf.c
+
+$(GENINIT_XE): geninit.$(OBJ)
+ echo OPTION STUB=$(STUB) >_temp_.tr
+ echo OPTION STACK=8k >>_temp_.tr
+ echo $LIBPATHS >>_temp_.tr
+ $(LINK) @_temp_.tr FILE geninit
+
+geninit.$(OBJ): geninit.c $(stdio__h) $(string__h)
+ $(CCAUX) geninit.c
+
+# No special gconfig_.h is needed.
+# Watcom `make' supports output redirection.
+gconfig_.h: $(WCTAIL_MAK)
+ echo /* This file deliberately left blank. */ >gconfig_.h
+
+gconfigv.h: $(WCTAIL_MAK) $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
diff --git a/gs/src/windows_.h b/gs/src/windows_.h
new file mode 100644
index 000000000..93155379b
--- /dev/null
+++ b/gs/src/windows_.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* windows_.h */
+/* Wrapper for windows.h */
+
+#define STRICT
+#include <windows.h>
+
+#ifndef __WATCOMC__
+ /* Define null equivalents of the Watcom 32-to-16-bit glue. */
+# define AllocAlias16(ptr) ((DWORD)(ptr))
+# define FreeAlias16(dword) /* */
+# define MK_FP16(fp32) ((DWORD)(fp32))
+# define MK_FP32(fp16) (fp16)
+# define GetProc16(proc, ptype) (proc)
+# define ReleaseProc16(cbp) /* */
+#endif
+
+/* Substitute for special "far" library procedures under Win32. */
+#ifdef __WIN32__
+# undef _fstrtok
+# define _fstrtok(str, set) strtok(str, set)
+#endif
diff --git a/gs/src/winint.mak b/gs/src/winint.mak
new file mode 100644
index 000000000..3cd47b52a
--- /dev/null
+++ b/gs/src/winint.mak
@@ -0,0 +1,96 @@
+# Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Common interpreter makefile section for 32-bit MS Windows.
+
+# This makefile must be acceptable to Microsoft Visual C++, Watcom C++,
+# and Borland C++. For this reason, the only conditional directives
+# allowed are !if[n]def, !else, and !endif.
+
+
+# Include the generic makefile.
+!include int.mak
+
+# ----------------------------- Main program ------------------------------ #
+
+CCBEGIN=$(CCC) *.c
+
+ICONS=gsgraph.ico gstext.ico
+
+GS_ALL=$(INT_ALL) $(INTASM)\
+ $(LIB_ALL) $(LIBCTR) lib.tr $(ld_tr) $(GSDLL).res $(GSDLL).def $(ICONS)
+
+# Make the icons from their text form.
+
+gsgraph.ico: gsgraph.icx echogs$(XE)
+ echogs -wb gsgraph.ico -n -X -r gsgraph.icx
+
+gstext.ico: gstext.icx echogs$(XE)
+ echogs -wb gstext.ico -n -X -r gstext.icx
+
+# resources for short EXE loader (no dialogs)
+$(GS).res: dwmain.rc dwmain.h $(ICONS)
+ $(RCOMP) -i$(INCDIR) -r -fo$(GS).res dwmain.rc
+
+# resources for main program (includes dialogs)
+$(GSDLL).res: gsdll32.rc gp_mswin.h $(ICONS)
+ $(RCOMP) -i$(INCDIR) -r -fo$(GSDLL).res gsdll32.rc
+
+
+# Modules for small EXE loader.
+
+DWOBJ=dwdll.obj dwimg.obj dwmain.obj dwtext.obj gscdefs.obj
+
+dwdll.obj: dwdll.cpp $(AK) dwdll.h gsdll.h
+ $(CPP) $(COMPILE_FOR_EXE) -c dwdll.cpp
+
+dwimg.obj: dwimg.cpp $(AK) dwmain.h dwdll.h dwtext.h dwimg.h gscdefs.h gsdll.h
+ $(CPP) $(COMPILE_FOR_EXE) -c dwimg.cpp
+
+dwmain.obj: dwmain.cpp $(AK) dwdll.h gscdefs.h gsdll.h
+ $(CPP) $(COMPILE_FOR_EXE) -c dwmain.cpp
+
+dwtext.obj: dwtext.cpp $(AK) dwtext.h
+ $(CPP) $(COMPILE_FOR_EXE) -c dwtext.cpp
+
+# Modules for big EXE
+
+DWOBJNO = dwnodll.obj dwimg.obj dwmain.obj dwtext.obj
+
+dwnodll.obj: dwnodll.cpp $(AK) dwdll.h gsdll.h
+ $(CPP) $(COMPILE_FOR_EXE) -c dwnodll.cpp
+
+# Compile gsdll.c, the main program of the DLL.
+
+gsdll.obj: gsdll.c $(AK) gsdll.h $(ghost_h)
+ $(CCCWIN) gsdll.c
+
+# Modules for console mode EXEs
+
+OBJC=dwmainc.obj dwdllc.obj gscdefs.obj
+OBJCNO=dwmainc.obj dwnodllc.obj
+
+dwmainc.obj: dwmainc.cpp $(AK) dwmain.h dwdll.h gscdefs.h gsdll.h
+ $(CPP) $(COMPILE_FOR_CONSOLE_EXE) -c dwmainc.cpp
+
+dwdllc.obj: dwdll.cpp $(AK) dwdll.h gsdll.h
+ $(CPP) $(COMPILE_FOR_CONSOLE_EXE) -c $(CCOBJNAME)dwdllc.obj dwdll.cpp
+
+dwnodllc.obj: dwnodll.cpp $(AK) dwdll.h gsdll.h
+ $(CPP) $(COMPILE_FOR_CONSOLE_EXE) -c $(CCOBJNAME)dwnodllc.obj dwnodll.cpp
+
+# end of winint.mak
diff --git a/gs/src/winlib.mak b/gs/src/winlib.mak
new file mode 100644
index 000000000..a288c9d16
--- /dev/null
+++ b/gs/src/winlib.mak
@@ -0,0 +1,135 @@
+# Copyright (C) 1991-1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Common makefile section for 32-bit MS Windows.
+
+# This makefile must be acceptable to Microsoft Visual C++, Watcom C++,
+# and Borland C++. For this reason, the only conditional directives
+# allowed are !if[n]def, !else, and !endif.
+
+
+# Note that built-in libpng and zlib aren't available.
+
+SHARE_LIBPNG=0
+SHARE_ZLIB=0
+
+# Define the platform name.
+
+!ifndef PLATFORM
+PLATFORM=mswin32_
+!endif
+
+# Define the ANSI-to-K&R dependency. Borland C, Microsoft C and
+# Watcom C all accept ANSI syntax, but we need to preconstruct ccf32.tr
+# to get around the limit on the maximum length of a command line.
+
+AK=ccf32.tr
+
+# Define the syntax for command, object, and executable files.
+
+CMD=.bat
+O=-o
+OBJ=obj
+XE=.exe
+XEAUX=.exe
+
+# Define generic commands.
+
+# We have to use a batch file for the equivalent of cp,
+# because the DOS COPY command copies the file write time, like cp -p.
+CP_=copy /B
+RM_=erase
+RMN_=call rm.bat
+
+# Define the generic compilation flags.
+
+PLATOPT=
+
+INTASM=
+PCFBASM=
+
+# Define the files to be removed by `make clean'.
+# nmake expands macros when encountered, not when used,
+# so this must precede the !include statements.
+
+BEGINFILES=gs*.res gs*.ico ccf32.tr\
+ $(GSDLL).dll $(GSCONSOLE).exe\
+ $(BEGINFILES2)
+
+# Include the generic makefiles.
+!include version.mak
+!include gs.mak
+!include lib.mak
+!include jpeg.mak
+!include libpng.mak
+!include zlib.mak
+!include devs.mak
+
+# -------------------------- Auxiliary programs --------------------------- #
+
+$(ECHOGS_XE): echogs.c
+ $(CCAUX_SETUP)
+ $(CCAUX) echogs.c $(CCAUX_TAIL)
+
+# $(GENARCH_XE) is in individual (compiler-specific) makefiles.
+
+$(GENCONF_XE): genconf.c $(stdpre_h)
+ $(CCAUX_SETUP)
+ $(CCAUX) genconf.c $(CCAUX_TAIL)
+
+$(GENINIT_XE): geninit.c $(stdio__h) $(string__h)
+ $(CCAUX_SETUP)
+ $(CCAUX) geninit.c $(CCAUX_TAIL)
+
+# No special gconfig_.h is needed.
+# Assume `make' supports output redirection.
+gconfig_.h: $(MAKEFILE)
+ echo /* This file deliberately left blank. */ >gconfig_.h
+
+gconfigv.h: $(MAKEFILE) $(ECHOGS_XE)
+ $(EXP)echogs -w gconfigv.h -x 23 define USE_ASM -x 2028 -q $(USE_ASM)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define USE_FPU -x 2028 -q $(FPU_TYPE)-0 -x 29
+ $(EXP)echogs -a gconfigv.h -x 23 define EXTEND_NAMES 0$(EXTEND_NAMES)
+
+
+# -------------------------------- Library -------------------------------- #
+
+# The Windows Win32 platform
+
+mswin32__=gp_mswin.$(OBJ) gp_msio.$(OBJ) gp_win32.$(OBJ) gp_nofb.$(OBJ) gp_ntfs.$(OBJ)
+mswin32_.dev: $(mswin32__)
+ $(SETMOD) mswin32_ $(mswin32__)
+ $(ADDMOD) mswin32_ -iodev wstdio
+
+gp_mswin.$(OBJ): gp_mswin.c $(AK) gp_mswin.h \
+ $(ctype__h) $(dos__h) $(malloc__h) $(memory__h) $(string__h) $(windows__h) \
+ $(gx_h) $(gp_h) $(gpcheck_h) $(gserrors_h) $(gsexit_h)
+ $(CCCWIN) gp_mswin.c
+
+gp_msio.$(OBJ): gp_msio.c $(AK) gp_mswin.h \
+ $(gsdll_h) $(stdio__h) $(gxiodev_h) $(stream_h) $(gx_h) $(gp_h) $(windows__h)
+ $(CCCWIN) gp_msio.c
+
+gp_win32.$(OBJ): gp_win32.c $(AK) $(stdio__h) $(dos__h) $(string__h) \
+ $(gstypes_h) $(gsmemory_h) $(gp_h) $(gp_sync_h) $(gserror_h) $(gserrors_h)
+ $(CCCWIN) gp_win32.c
+
+gp_ntfs.$(OBJ): gp_ntfs.c $(AK) $(stdio__h) $(dos__h) $(string__h) $(gstypes_h) \
+ $(gsmemory_h) $(gsstruct_h) $(gp_h) $(gsutil_h) $(windows__h)
+ $(CCCWIN) gp_ntfs.c
+
+# end of winlib.mak
diff --git a/gs/src/wmin.mak b/gs/src/wmin.mak
new file mode 100644
index 000000000..c0a1418ba
--- /dev/null
+++ b/gs/src/wmin.mak
@@ -0,0 +1,60 @@
+# Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Makefile for compiling the Wadalab free Kanji font into the executable.
+# This does not yet include rules for creating the wmin*.c files.
+
+ccfonts_ps=gs_kanji gs_ccfnt
+
+ccfonts1_=wmin.$(OBJ) wminr21.$(OBJ) wminr22.$(OBJ) wminr23.$(OBJ) \
+ wminr28.$(OBJ)
+ccfonts1=wmin wminr21 wminr22 wminr23 wminr28
+
+ccfonts2_=wminr24.$(OBJ) wminr25.$(OBJ)
+ccfonts2=wminr24 wminr25
+
+ccfonts3_=wminr30.$(OBJ) wminr31.$(OBJ) wminr32.$(OBJ) wminr33.$(OBJ) \
+ wminr34.$(OBJ) wminr35.$(OBJ) wminr36.$(OBJ) wminr37.$(OBJ) \
+ wminr38.$(OBJ) wminr39.$(OBJ) wminr3A.$(OBJ) wminr3B.$(OBJ) \
+ wminr3C.$(OBJ) wminr3D.$(OBJ) wminr3E.$(OBJ) wminr3F.$(OBJ)
+ccfonts3=wminr30 wminr31 wminr32 wminr33 wminr34 wminr35 wminr36 wminr37 \
+ wminr38 wminr39 wminr3A wminr3B wminr3C wminr3D wminr3E wminr3F
+
+ccfonts4_=wminr40.$(OBJ) wminr41.$(OBJ) wminr42.$(OBJ) wminr43.$(OBJ) \
+ wminr44.$(OBJ) wminr45.$(OBJ) wminr46.$(OBJ) wminr47.$(OBJ) \
+ wminr48.$(OBJ) wminr49.$(OBJ) wminr4A.$(OBJ) wminr4B.$(OBJ) \
+ wminr4C.$(OBJ) wminr4D.$(OBJ) wminr4E.$(OBJ) wminr4F.$(OBJ)
+ccfonts4=wminr40 wminr41 wminr42 wminr43 wminr44 wminr45 wminr46 wminr47 \
+ wminr48 wminr49 wminr4A wminr4B wminr4C wminr4D wminr4E wminr4F
+
+ccfonts5_=wminr50.$(OBJ) wminr51.$(OBJ) wminr52.$(OBJ) wminr53.$(OBJ) \
+ wminr54.$(OBJ) wminr55.$(OBJ) wminr56.$(OBJ) wminr57.$(OBJ) \
+ wminr58.$(OBJ) wminr59.$(OBJ) wminr5A.$(OBJ) wminr5B.$(OBJ) \
+ wminr5C.$(OBJ) wminr5D.$(OBJ) wminr5E.$(OBJ) wminr5F.$(OBJ)
+ccfonts5=wminr50 wminr51 wminr52 wminr53 wminr54 wminr55 wminr56 wminr57 \
+ wminr58 wminr59 wminr5A wminr5B wminr5C wminr5D wminr5E wminr5F
+
+ccfonts6_=wminr60.$(OBJ) wminr61.$(OBJ) wminr62.$(OBJ) wminr63.$(OBJ) \
+ wminr64.$(OBJ) wminr65.$(OBJ) wminr66.$(OBJ) wminr67.$(OBJ) \
+ wminr68.$(OBJ) wminr69.$(OBJ) wminr6A.$(OBJ) wminr6B.$(OBJ) \
+ wminr6C.$(OBJ) wminr6D.$(OBJ) wminr6E.$(OBJ) wminr6F.$(OBJ)
+ccfonts6=wminr60 wminr61 wminr62 wminr63 wminr64 wminr65 wminr66 wminr67 \
+ wminr68 wminr69 wminr6A wminr6B wminr6C wminr6D wminr6E wminr6F
+
+ccfonts7_=wminr70.$(OBJ) wminr71.$(OBJ) wminr72.$(OBJ) wminr73.$(OBJ) \
+ wminr74.$(OBJ)
+ccfonts7=wminr70 wminr71 wminr72 wminr73 wminr74
diff --git a/gs/src/x_.h b/gs/src/x_.h
new file mode 100644
index 000000000..9c301a437
--- /dev/null
+++ b/gs/src/x_.h
@@ -0,0 +1,166 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* x_.h */
+/* Header for including X library calls in Ghostscript X11 driver */
+
+/* Some versions of the X library use `private' as a member name, so: */
+#undef private
+
+/* Under DEC C, make sure abs() and exit() are defined. */
+#ifdef __DECC
+# include <stdlib.h>
+#endif
+
+/* Most X implementations have _Xdebug, but VMS DECWindows doesn't. */
+#ifndef VMS
+# define have_Xdebug
+#endif
+
+#ifdef VMS
+
+# ifdef __GNUC__
+
+/* Names of external functions which contain upper case letters are
+ * modified by the VMS GNU C compiler to prevent confusion between
+ * names such as XOpen and xopen. GNU C does this by translating a
+ * name like XOpen into xopen_aaaaaaaax with "aaaaaaaa" a hexadecimal
+ * string. However, this causes problems when we link against the
+ * X library which doesn't contain a routine named xopen_aaaaaaaax.
+ * So, we use #define's to map all X routine names to lower case.
+ * (Note that routines like BlackPixelOfScreen, which are [for VMS]
+ * preprocessor macros, do not appear here.)
+ */
+
+/*
+ * The names redefined here are those which the current Ghostscript X11
+ * driver happens to use: this list may grow in the future.
+ */
+
+# define XAllocColor xalloccolor
+# define XAllocNamedColor xallocnamedcolor
+# define XCloseDisplay xclosedisplay
+# define XCopyArea xcopyarea
+# define XCreateGC xcreategc
+# define XCreatePixmap xcreatepixmap
+# define XCreateWindow xcreatewindow
+# define XDestroyImage xdestroyimage
+# define XDisplayString xdisplaystring
+# define XDrawLine xdrawline
+# define XDrawPoint xdrawpoint
+# define XDrawString xdrawstring
+# define XFillPolygon xfillpolygon
+# define XFillRectangle xfillrectangle
+# define XFillRectangles xfillrectangles
+# define XFlush xflush
+# define XFree xfree
+# define XFreeColors xfreecolors
+# define XFreeFont xfreefont
+# define XFreeFontNames xfreefontnames
+# define XFreeGC xfreegc
+# define XFreePixmap xfreepixmap
+# define XGetDefault xgetdefault
+# define XGetGCValues xgetgcvalues
+# define XGetGeometry xgetgeometry
+# define XGetImage xgetimage
+# define XGetRGBColormaps xgetrgbcolormaps
+# define XGetVisualInfo xgetvisualinfo
+# define XGetWindowAttributes xgetwindowattributes
+# define XGetWindowProperty xgetwindowproperty
+# define XInternAtom xinternatom
+# define XListFonts xlistfonts
+# define XLoadQueryFont xloadqueryfont
+# define XMapWindow xmapwindow
+# define XNextEvent xnextevent
+# define XOpenDisplay xopendisplay
+# define XPutImage xputimage
+# define XQueryColor xquerycolor
+# define XResizeWindow xresizewindow
+# define XSendEvent xsendevent
+# define XSetBackground xsetbackground
+# define XSetClipMask xsetclipmask
+# define XSetClipOrigin xsetcliporigin
+# define XSetErrorHandler xseterrorhandler
+# define XSetFillStyle xsetfillstyle
+# define XSetFont xsetfont
+# define XSetForeground xsetforeground
+# define XSetFunction xsetfunction
+# define XSetLineAttributes xsetlineattributes
+# define XSetTile xsettile
+# define XSetWindowBackgroundPixmap xsetwindowbackgroundpixmap
+# define XSetWMHints xsetwmhints
+# define XSetWMNormalHints xsetwmnormalhints
+# define XStoreName xstorename
+# define XSync xsync
+# define XVisualIDFromVisual xvisualidfromvisual
+# define XWMGeometry xwmgeometry
+# define XtAppCreateShell xtappcreateshell
+# define XtCloseDisplay xtclosedisplay
+# define XtCreateApplicationContext xtcreateapplicationcontext
+# define XtDestroyApplicationContext xtdestroyapplicationcontext
+# define XtDestroyWidget xtdestroywidget
+# define XtAppSetFallbackResources xtappsetfallbackresources
+# define XtGetApplicationResources xtgetapplicationresources
+# define XtOpenDisplay xtopendisplay
+# define XtToolkitInitialize xttoolkitinitialize
+
+# define CADDR_T /* Without this DEFINE, VAX GNUC */
+ /* gets trashed reading Intrinsic.h */
+# endif /* ifdef __GNUC__ */
+
+# include <decw$include/Xlib.h>
+# include <decw$include/Xproto.h>
+# include <decw$include/Xatom.h>
+# include <decw$include/Xutil.h>
+# include <decw$include/Intrinsic.h>
+# include <decw$include/StringDefs.h>
+# include <decw$include/Shell.h>
+
+#else /* !ifdef VMS */
+
+# include <X11/Xlib.h>
+# include <X11/Xproto.h>
+# include <X11/Xatom.h>
+# include <X11/Xutil.h>
+# include <X11/Intrinsic.h>
+# include <X11/StringDefs.h>
+# include <X11/Shell.h>
+
+#endif /* VMS */
+
+/* X11R3 doesn't have XtOffsetOf, but it has XtOffset. */
+#ifndef XtOffsetOf
+# ifdef offsetof
+# define XtOffsetOf(s_type,field) offsetof(s_type,field)
+# else
+# define XtOffsetOf(s_type,field) XtOffset(s_type*,field)
+# endif
+#endif
+
+/* Include standard colormap stuff only for X11R4 and later. */
+# if defined(XtSpecificationRelease) && (XtSpecificationRelease >= 4)
+# define HaveStdCMap 1
+# else
+# define HaveStdCMap 0
+/* This function is not defined in R3. */
+# undef XVisualIDFromVisual
+# define XVisualIDFromVisual(vis) ((vis)->visualid)
+# endif
+
+/* Restore the definition of `private'. */
+#define private private_
diff --git a/gs/src/zarith.c b/gs/src/zarith.c
new file mode 100644
index 000000000..39e96624e
--- /dev/null
+++ b/gs/src/zarith.c
@@ -0,0 +1,291 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zarith.c */
+/* Arithmetic operators */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "store.h"
+
+/****** NOTE: none of the arithmetic operators ******/
+/****** currently check for floating exceptions ******/
+
+/* Define max and min values for what will fit in value.intval. */
+#define min_intval min_long
+#define max_intval max_long
+#define max_half_intval ((1 << (size_of(long) / 2 - 1)) - 1)
+
+/* Macros for generating non-integer cases for arithmetic operations. */
+/* 'frob' is one of the arithmetic operators, +, -, or *. */
+#define non_int_cases(frob,frob_equals)\
+ switch ( r_type(op) ) {\
+ default: return_op_typecheck(op);\
+ case t_real: switch ( r_type(op - 1) ) {\
+ default: return_op_typecheck(op - 1);\
+ case t_real: op[-1].value.realval frob_equals op->value.realval; break;\
+ case t_integer: make_real(op - 1, (double)op[-1].value.intval frob op->value.realval);\
+ } break;\
+ case t_integer: switch ( r_type(op - 1) ) {\
+ default: return_op_typecheck(op - 1);\
+ case t_real: op[-1].value.realval frob_equals (double)op->value.intval; break;\
+ case t_integer:
+#define end_cases()\
+ } }
+
+/* <num1> <num2> add <sum> */
+/* We make this into a separate procedure because */
+/* the interpreter will almost always call it directly. */
+int
+zop_add(register os_ptr op)
+{ non_int_cases(+, +=)
+ { long int2 = op->value.intval;
+ if ( ((op[-1].value.intval += int2) ^ int2) < 0 &&
+ ((op[-1].value.intval - int2) ^ int2) >= 0
+ )
+ { /* Overflow, convert to real */
+ make_real(op - 1, (float)(op[-1].value.intval - int2) + int2);
+ }
+ }
+ end_cases()
+ return 0;
+}
+int
+zadd(os_ptr op)
+{ int code = zop_add(op);
+ if ( code == 0 ) { pop(1); }
+ return code;
+}
+
+/* <num1> <num2> div <real_quotient> */
+private int
+zdiv(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ /* We can't use the non_int_cases macro, */
+ /* because we have to check explicitly for op == 0. */
+ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ if ( op->value.realval == 0 )
+ return_error(e_undefinedresult);
+ switch ( r_type(op1) )
+ {
+ default:
+ return_op_typecheck(op1);
+ case t_real:
+ op1->value.realval /= op->value.realval;
+ break;
+ case t_integer:
+ make_real(op1, (double)op1->value.intval / op->value.realval);
+ }
+ break;
+ case t_integer:
+ if ( op->value.intval == 0 )
+ return_error(e_undefinedresult);
+ switch ( r_type(op1) )
+ {
+ default:
+ return_op_typecheck(op1);
+ case t_real:
+ op1->value.realval /= (double)op->value.intval; break;
+ case t_integer:
+ make_real(op1, (double)op1->value.intval / (double)op->value.intval);
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> mul <product> */
+private int
+zmul(register os_ptr op)
+{ non_int_cases(*, *=)
+ { long int1 = op[-1].value.intval;
+ long int2 = op->value.intval;
+ long abs1 = (int1 >= 0 ? int1 : - int1);
+ long abs2 = (int2 >= 0 ? int2 : - int2);
+ float fprod;
+ if ( (abs1 > max_half_intval || abs2 > max_half_intval) &&
+ /* At least one of the operands is very large. */
+ /* Check for integer overflow. */
+ abs1 != 0 &&
+ abs2 > max_intval / abs1 &&
+ /* Check for the boundary case */
+ (fprod = (float)int1 * int2,
+ (int1 * int2 != min_intval ||
+ fprod != (float)min_intval))
+ )
+ make_real(op - 1, fprod);
+ else
+ op[-1].value.intval = int1 * int2;
+ }
+ end_cases()
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> sub <difference> */
+/* We make this into a separate procedure because */
+/* the interpreter will almost always call it directly. */
+int
+zop_sub(register os_ptr op)
+{ non_int_cases(-, -=)
+ { long int1 = op[-1].value.intval;
+ if ( (int1 ^ (op[-1].value.intval = int1 - op->value.intval)) < 0 &&
+ (int1 ^ op->value.intval) < 0
+ )
+ { /* Overflow, convert to real */
+ make_real(op - 1, (float)int1 - op->value.intval);
+ }
+ }
+ end_cases()
+ return 0;
+}
+int
+zsub(os_ptr op)
+{ int code = zop_sub(op);
+ if ( code == 0 ) { pop(1); }
+ return code;
+}
+
+/* <num1> <num2> idiv <int_quotient> */
+private int
+zidiv(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ check_type(*op, t_integer);
+ check_type(*op1, t_integer);
+ if ( op->value.intval == 0 )
+ return_error(e_undefinedresult);
+ if ( (op1->value.intval /= op->value.intval) ==
+ min_intval && op->value.intval == -1
+ )
+ { /* Anomalous boundary case, fail. */
+ return_error(e_rangecheck);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <int1> <int2> mod <remainder> */
+private int
+zmod(register os_ptr op)
+{ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+ if ( op->value.intval == 0 )
+ return_error(e_undefinedresult);
+ op[-1],value.intval %= op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* <num1> neg <num2> */
+private int
+zneg(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = -op->value.realval;
+ break;
+ case t_integer:
+ if ( op->value.intval == min_intval )
+ make_real(op, -(float)min_intval);
+ else
+ op->value.intval = -op->value.intval;
+ }
+ return 0;
+}
+
+/* <num1> ceiling <num2> */
+private int
+zceiling(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = ceil(op->value.realval);
+ case t_integer: ;
+ }
+ return 0;
+}
+
+/* <num1> floor <num2> */
+private int
+zfloor(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = floor(op->value.realval);
+ case t_integer: ;
+ }
+ return 0;
+}
+
+/* <num1> round <num2> */
+private int
+zround(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = floor(op->value.realval + 0.5);
+ case t_integer: ;
+ }
+ return 0;
+}
+
+/* <num1> truncate <num2> */
+private int
+ztruncate(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval =
+ (op->value.realval < 0.0 ?
+ ceil(op->value.realval) :
+ floor(op->value.realval));
+ case t_integer: ;
+ }
+ return 0;
+}
+
+/* ------ Initialization table ------ */
+
+BEGIN_OP_DEFS(zarith_op_defs) {
+ {"2add", zadd},
+ {"1ceiling", zceiling},
+ {"2div", zdiv},
+ {"2idiv", zidiv},
+ {"1floor", zfloor},
+ {"2mod", zmod},
+ {"2mul", zmul},
+ {"1neg", zneg},
+ {"1round", zround},
+ {"2sub", zsub},
+ {"1truncate", ztruncate},
+END_OP_DEFS(0) }
diff --git a/gs/src/zarray.c b/gs/src/zarray.c
new file mode 100644
index 000000000..7437f9141
--- /dev/null
+++ b/gs/src/zarray.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zarray.c */
+/* Array operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "ipacked.h"
+#include "oper.h"
+#include "store.h"
+
+/* The generic operators (copy, get, put, getinterval, putinterval, */
+/* length, and forall) are implemented in zgeneric.c. */
+
+/* <int> array <array> */
+int
+zarray(register os_ptr op)
+{ uint size;
+ int code;
+ check_int_leu(*op, max_array_size);
+ size = op->value.intval;
+ code = ialloc_ref_array((ref *)op, a_all, size, "array");
+ if ( code < 0 )
+ return code;
+ refset_null(op->value.refs, size);
+ return 0;
+}
+
+/* <array> aload <obj_0> ... <obj_n-1> <array> */
+private int
+zaload(register os_ptr op)
+{ ref aref;
+ ref_assign(&aref, op);
+ if ( !r_is_array(&aref) )
+ return_op_typecheck(op);
+ check_read(aref);
+#define asize r_size(&aref)
+ if ( asize > ostop - op )
+ { /* Use the slow, general algorithm. */
+ int code = ref_stack_push(&o_stack, asize);
+ uint i;
+ const ref_packed *packed = aref.value.packed;
+ if ( code < 0 )
+ return code;
+ for ( i = asize; i > 0; i--, packed = packed_next(packed) )
+ packed_get(packed, ref_stack_index(&o_stack, i));
+ *osp = aref;
+ return 0;
+ }
+ if ( r_has_type(&aref, t_array) )
+ memcpy((char *)op, (const char *)aref.value.refs,
+ asize * sizeof(ref));
+ else
+ { register ushort i;
+ const ref_packed *packed = aref.value.packed;
+ os_ptr pdest = op;
+ for ( i = 0; i < asize; i++, pdest++ )
+ packed_get(packed, pdest),
+ packed = packed_next(packed);
+ }
+ push(asize);
+#undef asize
+ ref_assign(op, &aref);
+ return 0;
+}
+
+/* <obj_0> ... <obj_n-1> <array> astore <array> */
+private int
+zastore(register os_ptr op)
+{ uint size;
+ int code;
+ check_write_type(*op, t_array);
+ size = r_size(op);
+ if ( size > op - osbot )
+ { /* The store operation might involve other stack segments. */
+ ref arr;
+ if ( size >= ref_stack_count(&o_stack) )
+ return_error(e_stackunderflow);
+ arr = *op;
+ code = ref_stack_store(&o_stack, &arr, size, 1, 0, true,
+ "astore");
+ if ( code < 0 )
+ return code;
+ ref_stack_pop(&o_stack, size);
+ *ref_stack_index(&o_stack, 0) = arr;
+ }
+ else
+ { code = refcpy_to_old(op, 0, op - size, size, "astore");
+ if ( code < 0 )
+ return code;
+ op[-(int)size] = *op;
+ pop(size);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zarray_op_defs) {
+ {"1aload", zaload},
+ {"1array", zarray},
+ {"1astore", zastore},
+END_OP_DEFS(0) }
diff --git a/gs/src/zbseq.c b/gs/src/zbseq.c
new file mode 100644
index 000000000..b756f1a29
--- /dev/null
+++ b/gs/src/zbseq.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 1990, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zbseq.c */
+/* Level 2 binary object sequence operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "ialloc.h" /* for isave.h */
+#include "idict.h"
+#include "iname.h"
+#include "isave.h"
+#include "ibnum.h"
+#include "btoken.h"
+#include "bseq.h"
+#include "store.h"
+
+/* Current binary format (in iscan.c) */
+extern ref ref_binary_object_format;
+
+/* System and user name arrays. */
+ref system_names, user_names;
+private ref *system_names_p = &system_names;
+private ref *user_names_p = &user_names;
+private gs_gc_root_t system_names_root, user_names_root;
+
+/* Import the Level 2 scanner extensions. */
+typedef struct scanner_state_s scanner_state;
+extern int scan_binary_token(P3(stream *, ref *, scanner_state *));
+extern int (*scan_btoken_proc)(P3(stream *, ref *, scanner_state *));
+
+/* Forward references */
+private void store_ushort(P3(byte *, ushort, int));
+private void store_long(P3(byte *, long, int));
+
+/* Initialize the binary token machinery. */
+private void
+zbseq_init(void)
+{ /* Initialize fake system and user name tables. */
+ /* PostScript code will install the real system name table. */
+ make_empty_array(&system_names, a_readonly);
+ gs_register_ref_root(imemory, &system_names_root,
+ (void **)&system_names_p, "system_names");
+ make_empty_array(&user_names, a_all);
+ gs_register_ref_root(imemory, &user_names_root,
+ (void **)&user_names_p, "user_names");
+ /* Set up Level 2 scanning constants. */
+ scan_btoken_proc = scan_binary_token;
+}
+
+/* <names> .installsystemnames - */
+private int
+zinstallsystemnames(register os_ptr op)
+{ if ( r_space(op) != avm_global )
+ return_error(e_invalidaccess);
+ check_read_type(*op, t_shortarray);
+ ref_assign_old(NULL, &system_names, op, ".installsystemnames");
+ pop(1);
+ return 0;
+}
+
+/* - currentobjectformat <int> */
+private int
+zcurrentobjectformat(register os_ptr op)
+{ push(1);
+ *op = ref_binary_object_format;
+ return 0;
+}
+
+/* <int> setobjectformat - */
+private int
+zsetobjectformat(register os_ptr op)
+{ check_type(*op, t_integer);
+ if ( op->value.intval < 0 || op->value.intval > 4 )
+ return_error(e_rangecheck);
+ ref_assign_old(NULL, &ref_binary_object_format, op, "setobjectformat");
+ pop(1);
+ return 0;
+}
+
+/*
+ * The remaining operators in this file are conversion operators
+ * that do the dirty work of printobject and writeobject.
+ * The main control is in PostScript code, so that we don't have to worry
+ * about interrupts or callouts in the middle of writing the various data
+ * items.
+ */
+
+/* <top_length> <total_length> <string8> .bosheader <string4|8> */
+private int
+zbosheader(register os_ptr op)
+{ int order = (int)ref_binary_object_format.value.intval - 1;
+ long top, total;
+ byte *p;
+
+ if ( order < 0 )
+ return_error(e_undefined);
+ check_type(op[-2], t_integer);
+ check_type(op[-1], t_integer);
+ check_write_type(*op, t_string);
+ if ( r_size(op) < 8 )
+ return_error(e_rangecheck);
+ top = op[-2].value.intval;
+ total = op[-1].value.intval;
+ p = op->value.bytes;
+ if ( top <= 255 && total <= 0xffff - 4 ) /* use short format */
+ { p[1] = (byte)top;
+ store_ushort(p + 2, (ushort)(total + 4), order);
+ r_set_size(op, 4);
+ }
+ else if ( top <= 0xffff ) /* use long format */
+ { p[1] = 0;
+ store_ushort(p + 2, (ushort)top, order);
+ store_long(p + 4, total + 8, order);
+ r_set_size(op, 8);
+ }
+ else
+ return_error(e_rangecheck);
+ p[0] = bt_seq + order;
+ op[-2] = *op;
+ pop(2);
+ return 0;
+}
+
+/* <ref_offset> <char_offset> <obj> <string8> .bosobject */
+/* <ref_offset'> <char_offset'> <string8> */
+/* This converts a single object to its binary object sequence */
+/* representation. Note that this may or may not modify the 'unused' field. */
+private int
+zbosobject(os_ptr op)
+{ register os_ptr op1 = op - 1;
+ int order = (int)ref_binary_object_format.value.intval - 1;
+ bin_seq_obj ob;
+ ref nstr;
+ check_type(op[-3], t_integer);
+ check_type(op[-2], t_integer);
+ check_write_type(*op, t_string);
+ if ( r_size(op) < 8 )
+ return_error(e_rangecheck);
+#define swap_t(a, b) t = a, a = b, b = t
+#if arch_is_big_endian
+# define must_swap() (order & 1)
+#else
+# define must_swap() (!(order & 1))
+#endif
+ switch ( r_type(op1) )
+ {
+ case t_null:
+ ob.tx = (byte)bs_null;
+ break;
+ case t_mark:
+ ob.tx = (byte)bs_mark;
+ break;
+ case t_integer:
+ ob.tx = (byte)bs_integer;
+ ob.value.w = op1->value.intval;
+num: ob.size.w = 0; /* (matters for reals) */
+swb: /* swap bytes of value if needed */
+ if ( must_swap() )
+ { byte t;
+ swap_t(ob.value.b[0], ob.value.b[3]);
+ swap_t(ob.value.b[1], ob.value.b[2]);
+ }
+ break;
+ case t_real:
+ ob.tx = (byte)bs_real;
+ ob.value.f = op1->value.realval;
+ /***** handle non-IEEE native *****/
+ goto num;
+ case t_boolean:
+ ob.tx = (byte)bs_boolean;
+ ob.value.w = op1->value.boolval;
+ goto num;
+ case t_array:
+ ob.tx = (byte)bs_array;
+ if ( r_has_attr(op1, a_executable) )
+ ob.tx += (byte)bs_executable;
+ ob.size.w = r_size(op1);
+ ob.value.w = op[-3].value.intval;
+ op[-3].value.intval += ob.size.w * (ulong)sizeof(bin_seq_obj);
+ goto nsa;
+ case t_dictionary: /* EXTENSION */
+ ob.tx = (byte)bs_dictionary;
+ if ( r_has_attr(op1, a_executable) )
+ ob.tx += (byte)bs_executable;
+ ob.size.w = dict_length(op1) << 1;
+ ob.value.w = op[-3].value.intval;
+ op[-3].value.intval += ob.size.w * (ulong)sizeof(bin_seq_obj);
+ goto nsa;
+ case t_string:
+ ob.tx = (byte)bs_string;
+ if ( r_has_attr(op1, a_executable) )
+ ob.tx += (byte)bs_executable;
+ ob.size.w = r_size(op1);
+nos: ob.value.w = op[-2].value.intval;
+ op[-2].value.intval += ob.size.w;
+nsa: if ( must_swap() )
+ { byte t;
+ swap_t(ob.size.b[0], ob.size.b[1]);
+ }
+ goto swb;
+ case t_name:
+ ob.tx = (byte)bs_name;
+ name_string_ref(op1, &nstr);
+ ob.size.w = r_size(&nstr);
+ goto nos;
+ }
+ memcpy(op->value.bytes, (byte *)&ob, sizeof(bin_seq_obj));
+ op[-1] = *op;
+ r_set_size(op - 1, 8);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zbseq_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1.installsystemnames", zinstallsystemnames},
+ {"0currentobjectformat", zcurrentobjectformat},
+ {"1setobjectformat", zsetobjectformat},
+ {"3.bosheader", zbosheader},
+ {"4.bosobject", zbosobject},
+END_OP_DEFS(zbseq_init) }
+
+/* ------ Internal routines ------ */
+
+/* Put a short (16 bits). */
+private void
+store_ushort(register byte *p, ushort num, int order)
+{ byte a = (byte)num;
+ byte b = (byte)(num >> 8);
+ if ( order & 1 )
+ p[0] = a, p[1] = b;
+ else
+ p[0] = b, p[1] = a;
+}
+
+/* Put a long (32 bits). */
+private void
+store_long(register byte *p, long num, int order)
+{ byte a = num & 0xff;
+ byte b = (byte)(num >> 8);
+ byte c = (byte)(num >> 16);
+ byte d = (byte)(num >> 24);
+ if ( order & 1 )
+ p[0] = a, p[1] = b, p[2] = c, p[3] = d;
+ else
+ p[0] = d, p[1] = c, p[2] = b, p[3] = a;
+}
diff --git a/gs/src/zchar.c b/gs/src/zchar.c
new file mode 100644
index 000000000..6e8d931d5
--- /dev/null
+++ b/gs/src/zchar.c
@@ -0,0 +1,661 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zchar.c */
+/* Character operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h" /* for ifont.h */
+#include "gxchar.h" /* for stringwidth_flag */
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gzpath.h"
+#include "gzstate.h"
+#include "dstack.h" /* for stack depth */
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "store.h"
+
+/* Forward references */
+private bool map_glyph_to_char(P3(const ref *, const ref *, ref *));
+private int finish_show(P1(os_ptr));
+private int finish_stringwidth(P1(os_ptr));
+private int op_show_cleanup(P1(os_ptr));
+private int op_show_return_width(P3(os_ptr, uint, double *));
+
+/* <string> show - */
+private int
+zshow(register os_ptr op)
+{ gs_show_enum *penum;
+ int code = op_show_setup(op, &penum);
+ if ( code != 0 )
+ return code;
+ if ( (code = gs_show_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, finish_show);
+ return op_show_continue(op - 1);
+}
+
+/* <ax> <ay> <string> ashow - */
+private int
+zashow(register os_ptr op)
+{ gs_show_enum *penum;
+ int code;
+ double axy[2];
+
+ if ( (code = num_params(op - 1, 2, axy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ( (code = gs_ashow_n_init(penum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 3, finish_show);
+ return op_show_continue(op - 3);
+}
+
+/* <cx> <cy> <char> <string> widthshow - */
+private int
+zwidthshow(register os_ptr op)
+{ gs_show_enum *penum;
+ int code;
+ double cxy[2];
+
+ check_type(op[-1], t_integer);
+ if ( (gs_char)(op[-1].value.intval) != op[-1].value.intval )
+ return_error(e_rangecheck);
+ if ( (code = num_params(op - 2, 2, cxy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ( (code = gs_widthshow_n_init(penum, igs, cxy[0], cxy[1],
+ (gs_char)op[-1].value.intval,
+ (char *)op->value.bytes,
+ r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 4, finish_show);
+ return op_show_continue(op - 4);
+}
+
+/* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
+private int
+zawidthshow(register os_ptr op)
+{ gs_show_enum *penum;
+ int code;
+ double cxy[2], axy[2];
+
+ check_type(op[-3], t_integer);
+ if ( (gs_char)(op[-3].value.intval) != op[-3].value.intval )
+ return_error(e_rangecheck);
+ if ( (code = num_params(op - 4, 2, cxy)) < 0 ||
+ (code = num_params(op - 1, 2, axy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ( (code = gs_awidthshow_n_init(penum, igs, cxy[0], cxy[1],
+ (gs_char)op[-3].value.intval,
+ axy[0], axy[1],
+ (char *)op->value.bytes,
+ r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 6, finish_show);
+ return op_show_continue(op - 6);
+}
+
+/* <proc> <string> kshow - */
+private int
+zkshow(register os_ptr op)
+{ gs_show_enum *penum;
+ int code;
+ check_proc(op[-1]);
+ if ( (code = op_show_setup(op, &penum)) != 0 )
+ return code;
+ if ( (code = gs_kshow_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, finish_show);
+ sslot = op[-1]; /* save kerning proc */
+ return op_show_continue(op - 2);
+}
+
+/* Common finish procedure for all show operations. */
+/* Doesn't have to do anything. */
+private int
+finish_show(os_ptr op)
+{ return 0;
+}
+
+/* <string> stringwidth <wx> <wy> */
+private int
+zstringwidth(register os_ptr op)
+{ gs_show_enum *penum;
+ int code = op_show_setup(op, &penum);
+ if ( code != 0 )
+ return code;
+ if ( (code = gs_stringwidth_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, finish_stringwidth);
+ return op_show_continue(op - 1);
+}
+/* Finishing procedure for stringwidth. */
+/* Pushes the accumulated width. */
+private int
+finish_stringwidth(register os_ptr op)
+{ gs_point width;
+ gs_show_width(senum, &width);
+ push(2);
+ make_real(op - 1, width.x);
+ make_real(op, width.y);
+ return 0;
+}
+
+/* Common code for charpath and .charboxpath. */
+private int
+zchar_path(register os_ptr op,
+ int (*init)(P5(gs_show_enum *, gs_state *, const char *, uint, bool)))
+{ gs_show_enum *penum;
+ int code;
+ check_type(*op, t_boolean);
+ code = op_show_setup(op - 1, &penum);
+ if ( code != 0 )
+ return code;
+ if ( (code = (*init)(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.boolval)) < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, finish_show);
+ return op_show_continue(op - 2);
+}
+/* <string> <outline_bool> charpath - */
+private int
+zcharpath(register os_ptr op)
+{ return zchar_path(op, gs_charpath_n_init);
+}
+/* <string> <box_bool> .charboxpath - */
+private int
+zcharboxpath(register os_ptr op)
+{ return zchar_path(op, gs_charboxpath_n_init);
+}
+
+/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
+int
+zsetcachedevice(register os_ptr op)
+{ double wbox[6];
+
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 6, wbox);
+ if ( penum == 0 )
+ return_error(e_undefined);
+ if ( code < 0 )
+ return code;
+ if ( gs_show_width_only(penum) )
+ return op_show_return_width(op, 6, &wbox[0]);
+ code = gs_setcachedevice_double(penum, igs, wbox);
+ if ( code < 0 )
+ return code;
+ pop(6);
+ if ( code == 1 )
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
+int
+zsetcachedevice2(os_ptr op)
+{ double wbox[10];
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 10, wbox);
+
+ if ( penum == 0 )
+ return_error(e_undefined);
+ if ( code < 0 )
+ return code;
+ if ( gs_show_width_only(penum) )
+ return op_show_return_width(op, 10,
+ (gs_rootfont(igs)->WMode ?
+ &wbox[6] : &wbox[0]));
+ code = gs_setcachedevice2_double(penum, igs, wbox);
+ if ( code < 0 )
+ return code;
+ pop(10);
+ if ( code == 1 )
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <wx> <wy> setcharwidth - */
+private int
+zsetcharwidth(register os_ptr op)
+{ double width[2];
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 2, width);
+
+ if ( penum == 0 )
+ return_error(e_undefined);
+ if ( code < 0 )
+ return code;
+ if ( gs_show_width_only(penum) )
+ return op_show_return_width(op, 2, &width[0]);
+ code = gs_setcharwidth(penum, igs, width[0], width[1]);
+ if ( code < 0 )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
+/* <dict> .fontbbox -false- */
+private int
+zfontbbox(register os_ptr op)
+{ double bbox[4];
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = font_bbox_param(op, bbox);
+ if ( code < 0 )
+ return code;
+ if ( bbox[0] < bbox[2] && bbox[1] < bbox[3] )
+ { push(4);
+ make_reals(op - 4, bbox, 4);
+ make_true(op);
+ }
+ else
+ { /* No bbox, or an empty one. */
+ make_false(op);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zchar_op_defs) {
+ {"3ashow", zashow},
+ {"6awidthshow", zawidthshow},
+ {"2charpath", zcharpath},
+ {"2.charboxpath", zcharboxpath},
+ {"2kshow", zkshow},
+ {"6setcachedevice", zsetcachedevice},
+ {":setcachedevice2", zsetcachedevice2},
+ {"2setcharwidth", zsetcharwidth},
+ {"1show", zshow},
+ {"1stringwidth", zstringwidth},
+ {"4widthshow", zwidthshow},
+ /* Extensions */
+ {"1.fontbbox", zfontbbox},
+ /* Internal operators */
+ {"0%finish_show", finish_show},
+ {"0%finish_stringwidth", finish_stringwidth},
+ {"0%op_show_continue", op_show_continue},
+END_OP_DEFS(0) }
+
+/* ------ Subroutines ------ */
+
+/* Most of these are exported for zchar2.c. */
+
+/* Convert a glyph to a ref. */
+private void
+glyph_ref(gs_glyph glyph, ref *gref)
+{ if ( glyph < gs_min_cid_glyph )
+ name_index_ref(glyph, gref);
+ else
+ make_int(gref, glyph - gs_min_cid_glyph);
+}
+
+/* Prepare to set up for a show operator. */
+/* Don't change any state yet. */
+int
+op_show_setup(os_ptr op, gs_show_enum **ppenum)
+{ check_read_type(*op, t_string);
+ return op_show_enum_setup(op, ppenum);
+}
+int
+op_show_enum_setup(os_ptr op, gs_show_enum **ppenum)
+{ /* Provide a special "hook" for an unusual application */
+ /* that needs to be able to intervene before any operator */
+ /* that renders or measures characters. */
+#ifdef OP_SHOW_ENUM_SETUP_HOOK
+ OP_SHOW_ENUM_SETUP_HOOK
+#endif
+ check_estack(snumpush + 2);
+ if ( (*ppenum = gs_show_enum_alloc((gs_memory_t *)imemory, igs, "op_show_enum_setup")) == 0 )
+ return_error(e_VMerror);
+ return 0;
+}
+
+/* Finish setting up a show operator. This can't fail, since */
+/* op_show_enum_setup did the check_estack. */
+void
+op_show_finish_setup(gs_show_enum *penum, int npop, op_proc_p endproc /* end procedure */)
+{ register es_ptr ep = esp + snumpush;
+ esp = ep;
+ make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
+ if ( endproc == NULL )
+ endproc = finish_show;
+ make_null(&esslot(ep));
+ make_int(&essindex(ep), 0);
+ make_int(&esodepth(ep), 0); /* see gs_show_render case in */
+ /* op_show_continue_dispatch */
+ make_int(&esddepth(ep), 0); /* ditto */
+ make_int(&esgslevel(ep), igs->level);
+ make_op_estack(&eseproc(ep), endproc);
+ make_istruct(ep, 0, penum);
+}
+
+/* Continuation operator for character rendering. */
+int
+op_show_continue(os_ptr op)
+{ return op_show_continue_dispatch(op, gs_show_next(senum));
+}
+/* Note that this sets osp = op explicitly iff the dispatch succeeds. */
+/* This is so that the show operators don't pop anything from the o-stack */
+/* if they don't succeed. */
+/* Note also that if it returns an error, it has freed the enumerator. */
+int
+op_show_continue_dispatch(register os_ptr op, int code)
+{ gs_show_enum *penum = senum;
+ switch ( code )
+ {
+ case 0: /* all done */
+ { os_ptr save_osp = osp;
+ osp = op;
+ code = (*real_opproc(&seproc))(op);
+ op_show_free(code);
+ if ( code < 0 )
+ { osp = save_osp;
+ return code;
+ }
+ return o_pop_estack;
+ case gs_show_kern: {
+ case gs_show_kern:
+ { ref *pslot = &sslot;
+ push(2);
+ make_int(op - 1, gs_kshow_previous_char(penum));
+ make_int(op, gs_kshow_next_char(penum));
+ push_op_estack(op_show_continue); /* continue after kerning */
+ *++esp = *pslot; /* kerning procedure */
+ case gs_show_render: {
+ return o_push_estack;
+ case gs_show_render:
+ { gs_font *pfont = gs_currentfont(igs);
+ font_data *pfdata = pfont_data(pfont);
+ gs_char chr = gs_show_current_char(penum);
+ gs_glyph glyph = gs_show_current_glyph(penum);
+ push(2);
+ op[-1] = pfdata->dict; /* push the font */
+ * For a Type 1 or Type 4 font, prefer BuildChar: we know
+ * For Type 1 and Type 4 fonts, prefer BuildChar to
+ * BuildGlyph, so that PostScript procedures appearing in the
+ * CharStrings dictionary will receive the character code
+ * rather than the character name; for Type 3 fonts,
+ * prefer BuildGlyph to BuildChar.
+ if (chr != gs_no_char && !r_has_type(&pfdata->BuildChar, t_null)) {
+ if ( pfont->FontType == ft_user_defined )
+ { /* Type 3 font, prefer BuildGlyph. */
+ if ( level2_enabled &&
+ !r_has_type(&pfdata->BuildGlyph, t_null) &&
+ glyph != gs_no_glyph
+ )
+ { glyph_ref(glyph, op);
+ esp[2] = pfdata->BuildGlyph;
+ }
+ else if ( r_has_type(&pfdata->BuildChar, t_null) )
+ goto err;
+ else if ( chr == gs_no_char )
+ { /* glyphshow, reverse map the character */
+ /* through the Encoding */
+ ref gref;
+ const ref *pencoding = &pfdata->Encoding;
+
+ glyph_ref(glyph, &gref);
+ if ( !map_glyph_to_char(&gref, pencoding,
+ (ref *)op)
+ )
+ { /* Not found, try .notdef */
+ name_enter_string(".notdef", &gref);
+ if ( !map_glyph_to_char(&gref,
+ pencoding,
+ (ref *)op)
+ )
+ goto err;
+ }
+ esp[2] = pfdata->BuildChar;
+ }
+ else
+ { make_int(op, chr);
+ esp[2] = pfdata->BuildChar;
+ }
+ }
+ else
+ { /* Type 1 or Type 4 font, prefer BuildChar. */
+ /* We know that both BuildChar and BuildGlyph */
+ /* are present. */
+ if ( chr != gs_no_char )
+ { make_int(op, chr);
+ esp[2] = pfdata->BuildChar;
+ }
+ else
+ { glyph_ref(glyph, op);
+ esp[2] = pfdata->BuildGlyph;
+ }
+ }
+ /* Save the stack depths in case we bail out. */
+ sodepth.value.intval = ref_stack_count(&o_stack) - 2;
+ sddepth.value.intval = ref_stack_count(&d_stack);
+ push_op_estack(op_show_continue);
+ ++esp; /* skip BuildChar or BuildGlyph proc */
+ }
+ return o_push_estack;
+ default: /* error */
+err: if ( code >= 0 )
+ code = gs_note_error(e_invalidfont);
+ return op_show_free(code);
+ default: /* error */
+/* Reverse-map a glyph name to a character code for glyphshow. */
+private bool
+map_glyph_to_char(const ref * pgref, const ref * pencoding, ref * pch)
+map_glyph_to_char(const ref *pgref, const ref *pencoding, ref *pch)
+{ uint esize = r_size(pencoding);
+ uint ch;
+ ref eref;
+ for ( ch = 0; ch < esize; ch++ )
+ { array_get(pencoding, (long)ch, &eref);
+ if ( obj_eq(pgref, &eref) )
+ { make_int(pch, ch);
+ return true;
+ }
+ }
+ return false;
+
+/* Find the index of the e-stack mark for the current show enumerator. */
+/* Return 0 if we can't find the mark. */
+uint
+op_show_find_index(void)
+{
+{ uint count = 0;
+ STACK_LOOP_BEGIN(&e_stack, ep, size)
+ for ( ep += size - 1; size != 0; size--, ep--, count++ )
+ if ( r_is_estack_mark(ep) && estack_mark_index(ep) == es_show )
+ return count;
+ STACK_LOOP_END(ep, size)
+ return 0; /* no mark */
+
+/* Find the current show enumerator on the e-stack. */
+gs_show_enum *
+op_show_find(void)
+{
+{ uint index = op_show_find_index();
+ if ( index == 0 )
+ return 0; /* no mark */
+ return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
+ gs_show_enum);
+
+/* Shortcut the BuildChar or BuildGlyph procedure at the point */
+/* of the setcharwidth or the setcachedevice[2] if we are in */
+/* a stringwidth or cshow, or if we are only collecting the scalable */
+/* width for an xfont character. */
+private int
+op_show_return_width(os_ptr op, uint npop, double *pwidth)
+{
+{ uint index = op_show_find_index();
+ es_ptr ep = (es_ptr)ref_stack_index(&e_stack, index - (snumpush - 1));
+ int code = gs_setcharwidth(esenum(ep), igs, pwidth[0], pwidth[1]);
+ uint ocount, dsaved, dcount;
+
+ if ( code < 0 )
+ return code;
+ /* Restore the operand and dictionary stacks. */
+ ocount = ref_stack_count(&o_stack) - (uint)esodepth(ep).value.intval;
+ if ( ocount < npop )
+ return_error(e_stackunderflow);
+ dsaved = (uint)esddepth(ep).value.intval;
+ dcount = ref_stack_count(&d_stack);
+ if ( dcount < dsaved )
+ return_error(e_dictstackunderflow);
+ while ( dcount > dsaved )
+ { code = zend(op);
+ if ( code < 0 )
+ return code;
+ dcount--;
+ }
+ ref_stack_pop(&o_stack, ocount);
+ /* We don't want to pop the mark or the continuation */
+ /* procedure (op_show_continue or cshow_continue). */
+ pop_estack(index - snumpush);
+ return o_pop_estack;
+
+/*
+ * Restore state after finishing, or unwinding from an error within, a show
+ * operation. Note that we assume op == osp, and may reset osp.
+ */
+private int
+op_show_restore(bool for_error)
+{
+{ register es_ptr ep = esp + snumpush;
+ gs_show_enum *penum = esenum(ep);
+ int saved_level = esgslevel(ep).value.intval;
+ int code = 0;
+
+ if ( for_error )
+ { uint saved_count = esodepth(ep).value.intval;
+ uint count = ref_stack_count(&o_stack);
+
+ if ( count > saved_count ) /* if <, we're in trouble */
+ ref_stack_pop(&o_stack, count - saved_count);
+ }
+ if ( penum->stringwidth_flag == 1 )
+ { /* stringwidth does an extra gsave */
+ --saved_level;
+ }
+ /*
+ * We might have been inside a cshow, in which case currentfont
+ * was reset temporarily, as though we were inside a BuildChar/
+ * BuildGlyph procedure. If this is the case, set currentfont
+ * back to its normal state, the root font.
+ */
+ if ( penum->fstack.depth >= 0 )
+ gs_set_currentfont(igs, penum->fstack.items[0].font);
+ while ( igs->level > saved_level && code >= 0 )
+ { if ( igs->saved == 0 || igs->saved->saved == 0 )
+ { /*
+ * Bad news: we got an error inside a save inside a
+ * BuildChar or BuildGlyph. Don't attempt to recover.
+ */
+ code = gs_note_error(e_Fatal);
+ }
+ else
+ code = gs_grestore(igs);
+ }
+ gs_show_enum_release(penum, (gs_memory_t *)imemory);
+ return code;
+/* Clean up after an error. */
+private int
+op_show_cleanup(os_ptr op)
+{
+{ return op_show_restore(true);
+/* Clean up after termination of a show operation. */
+int
+op_show_free(int code)
+{
+{ int rcode;
+ esp -= snumpush;
+ rcode = op_show_restore(code < 0);
+ return (rcode < 0 ? rcode : code);
+
+/* Get a FontBBox parameter from a font dictionary. */
+int
+font_bbox_param(const ref * pfdict, double bbox[4])
+font_bbox_param(const ref *pfdict, double bbox[4])
+{ ref *pbbox;
+ /*
+ * Pre-clear the bbox in case it's invalid. The Red Books say that
+ * FontBBox is required, but the Adobe interpreters don't require
+ * it, and a few user-written fonts don't supply it, or supply one
+ * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
+ * sometimes emits an absurd bbox for Type 1 fonts converted from
+ * TrueType.
+ */
+ bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
+ if ( dict_find_string(pfdict, "FontBBox", &pbbox) > 0 )
+ { if ( !r_is_array(pbbox) )
+ return_error(e_typecheck);
+ if ( r_size(pbbox) == 4 )
+ { const ref_packed *pbe = pbbox->value.packed;
+ ref rbe[4];
+ int i;
+ int code;
+ float dx, dy, ratio;
+
+ for ( i = 0; i < 4; i++ )
+ { packed_get(pbe, rbe + i);
+ pbe = packed_next(pbe);
+ }
+ if ( (code = num_params(rbe + 3, 4, bbox)) < 0 )
+ return code;
+ /* Require "reasonable" values. Thanks to Ray */
+ /* Johnston for suggesting the following test. */
+ dx = bbox[2] - bbox[0];
+ dy = bbox[3] - bbox[1];
+ if ( dx <= 0 || dy <= 0 ||
+ (ratio = dy / dx) < 0.125 || ratio > 8.0
+ )
+ bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
+ }
+ }
+ return 0;
diff --git a/gs/src/zchar1.c b/gs/src/zchar1.c
new file mode 100644
index 000000000..55b2519a2
--- /dev/null
+++ b/gs/src/zchar1.c
@@ -0,0 +1,646 @@
+/* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zchar1.c */
+/* Type 1 character display operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxchar.h" /* for gs_type1_init in gstype1.h */
+ /* (should only be gschar.h) */
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzstate.h" /* for path for gs_type1_init */
+ /* (should only be gsstate.h) */
+#include "gspaint.h" /* for gs_fill, gs_stroke */
+#include "gspath.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Test whether a font is Type 1 compatible. */
+#define font_is_type1_compatible(pfont)\
+ ((pfont)->FontType == ft_encrypted || (pfont)->FontType == ft_disk_based)
+
+/* ---------------- .type1execchar ---------------- */
+
+/*
+ * This is the workhorse for %Type1BuildChar, %Type1BuildGlyph,
+ * CCRun, and CID fonts. Eventually this will appear in the C API;
+ * even now, its normal control path doesn't use any continuations.
+ */
+
+/*
+ * Define the state record for this operator, which must save the metrics
+ * separately as well as the Type 1 interpreter state.
+ */
+typedef struct gs_type1exec_state_s {
+ gs_type1_state cis; /* must be first */
+ double sbw[4];
+ int /*metrics_present*/ present;
+ gs_rect char_bbox;
+} gs_type1exec_state;
+gs_private_st_suffix_add0(st_gs_type1exec_state, gs_type1exec_state,
+ "gs_type1exec_state", gs_type1exec_state_enum_ptrs,
+ gs_type1exec_state_reloc_ptrs, st_gs_type1_state);
+
+/* Forward references */
+private int bbox_continue(P1(os_ptr));
+private int nobbox_continue(P1(os_ptr));
+private int type1_call_OtherSubr(P3(const gs_type1exec_state *,
+ int (*)(P1(os_ptr)), const ref *));
+private int type1_continue_dispatch(P3(gs_type1_state *, const ref *, ref *));
+private int type1_callout_dispatch(P2(os_ptr, int (*)(P1(os_ptr))));
+private int op_type1_cleanup(P1(os_ptr));
+private void op_type1_free(P1(os_ptr));
+private void
+ type1_cis_get_metrics(P2(const gs_type1_state *pcis, double psbw[4]));
+private int bbox_getsbw_continue(P1(os_ptr));
+private int type1exec_bbox(P3(os_ptr, gs_type1exec_state *, gs_font *));
+private int bbox_fill(P1(os_ptr));
+private int bbox_stroke(P1(os_ptr));
+private int nobbox_finish(P2(os_ptr, gs_type1exec_state *));
+private int nobbox_fill(P1(os_ptr));
+private int nobbox_stroke(P1(os_ptr));
+private int
+
+/* <font> <code|name> <name> <charstring> .type1execchar - */
+ztype1execchar(register os_ptr op)
+{ gs_font *pfont;
+#define pbfont ((gs_font_base *)pfont)
+#define pfont1 ((gs_font_type1 *)pfont)
+ const gs_type1_data *pdata;
+ int code = font_param(op - 3, &pfont);
+ gs_show_enum *penum = op_show_find();
+ gs_type1exec_state cxs;
+#define pcis (&cxs.cis)
+
+ if ( code < 0 )
+ return code;
+ if ( penum == 0 || !font_is_type1_compatible(pfont) )
+ return_error(e_undefined);
+ pdata = &pfont1->data;
+ /*
+ * Any reasonable implementation would execute something like
+ * 1 setmiterlimit 0 setlinejoin 0 setlinecap
+ * here, but apparently the Adobe implementations aren't reasonable.
+ *
+ * If this is a stroked font, set the stroke width.
+ */
+ if ( pfont->PaintType )
+ gs_setlinewidth(igs, pfont->StrokeWidth);
+ check_estack(3); /* for continuations */
+ /*
+ * Execute the definition of the character.
+ */
+ if ( r_is_proc(op) )
+ return zchar_exec_char_proc(op);
+ /*
+ * The definition must be a Type 1 CharString.
+ * Note that we do not require read access: this is deliberate.
+ */
+ check_type(*op, t_string);
+ if ( r_size(op) <= max(pdata->lenIV, 0) )
+ return_error(e_invalidfont);
+ /*
+ * In order to make character oversampling work, we must
+ * set up the cache before calling .type1addpath.
+ * To do this, we must get the bounding box from the FontBBox,
+ * and the width from the CharString or the Metrics.
+ * If the FontBBox isn't valid, we can't do any of this.
+ */
+ code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
+ if ( code < 0 )
+ return code;
+ cxs.present = code;
+ /* Establish a current point. */
+ code = gs_moveto(igs, 0.0, 0.0);
+ if ( code < 0 )
+ return code;
+ code = gs_type1_init(pcis, penum, NULL,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if ( code < 0 )
+ return code;
+ if ( pfont1->FontBBox.q.x > pfont1->FontBBox.p.x &&
+ pfont1->FontBBox.q.y > pfont1->FontBBox.p.y
+ )
+ { /* The FontBBox is valid. */
+ cxs.char_bbox = pfont1->FontBBox;
+ return type1exec_bbox(op, &cxs, pfont);
+ }
+ else
+ { /*
+ * The FontBBox is not valid. In this case,
+ * we create the path first, then do the setcachedevice.
+ * If we are oversampling (in this case, only for anti-
+ * aliasing, not just to improve quality), we have to
+ * create the path twice, since we can't know the
+ * oversampling factor until after setcachedevice.
+ */
+ const ref *opstr = op;
+ ref other_subr;
+
+ if ( cxs.present == metricsSideBearingAndWidth )
+ { gs_point sbpt;
+ sbpt.x = cxs.sbw[0], sbpt.y = cxs.sbw[1];
+ gs_type1_set_lsb(pcis, &sbpt);
+ }
+ /* Continue interpreting. */
+icont: code = type1_continue_dispatch(pcis, opstr, &other_subr);
+ switch ( code )
+ {
+ case 0: /* all done */
+ return nobbox_finish(op, &cxs);
+ default: /* code < 0, error */
+ return code;
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_call_OtherSubr(&cxs, nobbox_continue,
+ &other_subr);
+ case type1_result_sbw: /* [h]sbw, just continue */
+ if ( cxs.present != metricsSideBearingAndWidth )
+ type1_cis_get_metrics(pcis, cxs.sbw);
+ opstr = 0;
+ goto icont;
+ }
+ }
+#undef pcis
+#undef pfont1
+#undef pbfont
+}
+/* Do all the work for the case where we have a bounding box. */
+private int
+type1exec_bbox(os_ptr op, gs_type1exec_state *pcxs, gs_font *pfont)
+{
+#define pcis (&pcxs->cis)
+#define pbfont ((gs_font_base *)pfont)
+ /*
+ * We have a valid bounding box. If we don't have Metrics
+ * for this character, start interpreting the CharString;
+ * do the setcachedevice as soon as we know the
+ * (side bearing and) width.
+ */
+ if ( pcxs->present == metricsNone )
+ { /* Get the width from the CharString, */
+ /* then set the cache device. */
+ ref cnref;
+ ref other_subr;
+ int code;
+
+ /* Since an OtherSubr callout might change osp, */
+ /* save the character name now. */
+ ref_assign(&cnref, op - 1);
+ code = type1_continue_dispatch(pcis, op, &other_subr);
+ switch ( code )
+ {
+ default: /* code < 0 or done, error */
+ return((code < 0 ? code :
+ gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_call_OtherSubr(pcxs,
+ bbox_getsbw_continue,
+ &other_subr);
+ case type1_result_sbw: /* [h]sbw, done */
+ break;
+ }
+ type1_cis_get_metrics(pcis, pcxs->sbw);
+ return zchar_set_cache(osp, pbfont, &cnref,
+ NULL, pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ bbox_fill, bbox_stroke);
+ }
+ else
+ { /* We have the width and bounding box: */
+ /* set up the cache device now. */
+ return zchar_set_cache(op, pbfont, op - 1,
+ (pcxs->present ==
+ metricsSideBearingAndWidth ?
+ pcxs->sbw : NULL),
+ pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ bbox_fill, bbox_stroke);
+ }
+#undef pcis
+#undef pbfont
+}
+
+
+/* Handle the results of gs_type1_interpret. */
+/* pcref points to a t_string ref. */
+private int
+type1_continue_dispatch(gs_type1_state *pcis, const ref *pcref, ref *pos)
+{ int value;
+ int code;
+ gs_const_string charstring;
+ gs_const_string *pchars;
+
+ if ( pcref == 0 )
+ { pchars = 0;
+ }
+ else
+ { charstring.data = pcref->value.const_bytes;
+ charstring.size = r_size(pcref);
+ pchars = &charstring;
+ }
+ code = gs_type1_interpret(pcis, pchars, &value);
+ switch ( code )
+ {
+ case type1_result_callothersubr:
+ { /* The Type 1 interpreter handles all known OtherSubrs, */
+ /* so this must be an unknown one. */
+ const font_data *pfdata = pfont_data(gs_currentfont(igs));
+
+ code = array_get(&pfdata->u.type1.OtherSubrs,
+ (long)value, pos);
+ return (code < 0 ? code : type1_result_callothersubr);
+ }
+ }
+ return code;
+}
+
+/* Do a callout to an OtherSubr implemented in PostScript. */
+/* The caller must have done a check_estack(4). */
+private int
+type1_call_OtherSubr(const gs_type1exec_state *pcxs, int (*cont)(P1(os_ptr)),
+ const ref *pos)
+{ /* Move the Type 1 interpreter state to the heap. */
+ gs_type1exec_state *hpcxs = ialloc_struct(gs_type1exec_state,
+ &st_gs_type1exec_state,
+ "type1_call_OtherSubr");
+
+ if ( hpcxs == 0 )
+ return_error(e_VMerror);
+ *hpcxs = *pcxs;
+ push_mark_estack(es_show, op_type1_cleanup);
+ ++esp;
+ make_istruct(esp, 0, hpcxs);
+ push_op_estack(cont);
+ ++esp;
+ *esp = *pos;
+ return o_push_estack;
+}
+
+/* Continue from an OtherSubr callout while getting metrics. */
+private int
+bbox_getsbw_continue(os_ptr op)
+{ ref other_subr;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+#define pcis (&pcxs->cis)
+ int code;
+
+ code = type1_continue_dispatch(pcis, NULL, &other_subr);
+ op = osp; /* in case z1_push/pop_proc was called */
+ switch ( code )
+ {
+ default: /* code < 0 or done, error */
+ op_type1_free(op);
+ return((code < 0 ? code : gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ push_op_estack(bbox_getsbw_continue);
+ ++esp;
+ *esp = other_subr;
+ return o_push_estack;
+ case type1_result_sbw: /* [h]sbw, done */
+ { double sbw[4];
+ const gs_font_base *pbfont =
+ (const gs_font_base *)pcis->pfont;
+ gs_rect bbox;
+
+ /* Get the metrics before freeing the state. */
+ type1_cis_get_metrics(pcis, sbw);
+ bbox = pcxs->char_bbox;
+ op_type1_free(op);
+ return zchar_set_cache(op, pbfont, op, sbw, sbw + 2, &bbox,
+ bbox_fill, bbox_stroke);
+ }
+ }
+#undef pcis
+}
+
+/* <font> <code|name> <name> <charstring> <sbx> <sby> %bbox_{fill|stroke} - */
+/* <font> <code|name> <name> <charstring> %bbox_{fill|stroke} - */
+private int bbox_finish(P2(os_ptr, int (*)(P1(os_ptr))));
+private int
+bbox_fill(os_ptr op)
+{ return bbox_finish(op, nobbox_fill);
+}
+private int
+bbox_stroke(os_ptr op)
+{ return bbox_finish(op, nobbox_stroke);
+}
+private int
+bbox_finish(os_ptr op, int (*cont)(P1(os_ptr)))
+{ gs_font *pfont;
+#define pfont1 ((gs_font_type1 *)pfont)
+ int code;
+ gs_show_enum *penum = op_show_find();
+ gs_type1exec_state cxs; /* stack allocate to avoid sandbars */
+#define pcis (&cxs.cis)
+ double sbxy[2];
+ gs_point sbpt;
+ gs_point *psbpt = 0;
+ os_ptr opc = op;
+ const ref *opstr;
+ ref other_subr;
+
+ if ( !r_has_type(opc, t_string) )
+ { check_op(3);
+ code = num_params(op, 2, sbxy);
+ if ( code < 0 )
+ return code;
+ sbpt.x = sbxy[0];
+ sbpt.y = sbxy[1];
+ psbpt = &sbpt;
+ opc -= 2;
+ check_type(*opc, t_string);
+ }
+ code = font_param(opc - 3, &pfont);
+ if ( code < 0 )
+ return code;
+ if ( penum == 0 || !font_is_type1_compatible(pfont) )
+ return_error(e_undefined);
+ { int lenIV = pfont1->data.lenIV;
+
+ if ( lenIV > 0 && r_size(opc) <= lenIV )
+ return_error(e_invalidfont);
+ }
+ check_estack(5); /* in case we need to do a callout */
+ code = gs_type1_init(pcis, penum, psbpt,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if ( code < 0 )
+ return code;
+ opstr = opc;
+icont: code = type1_continue_dispatch(pcis, opstr, &other_subr);
+ switch ( code )
+ {
+ case 0: /* all done */
+ /* Call the continuation now. */
+ if ( psbpt )
+ pop(2);
+ return (*cont)(osp);
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ push_op_estack(cont); /* call later */
+ return type1_call_OtherSubr(&cxs, bbox_continue,
+ &other_subr);
+ case type1_result_sbw: /* [h]sbw, just continue */
+ opstr = 0;
+ goto icont;
+ default: /* code < 0, error */
+ return code;
+ }
+#undef pfont1
+#undef pcis
+}
+
+/* Continue from an OtherSubr callout while building the path. */
+private int
+type1_callout_dispatch(os_ptr op, int (*cont)(P1(os_ptr)))
+{ ref other_subr;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+#define pcis (&pcxs->cis)
+ int code;
+
+icont: code = type1_continue_dispatch(pcis, NULL, &other_subr);
+ op = osp; /* in case z1_push/pop_proc was called */
+ switch ( code )
+ {
+ case 0: /* callout done, cont is on e-stack */
+ return 0;
+ default: /* code < 0 or done, error */
+ op_type1_free(op);
+ return((code < 0 ? code : gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ push_op_estack(cont);
+ ++esp;
+ *esp = other_subr;
+ return o_push_estack;
+ case type1_result_sbw: /* [h]sbw, just continue */
+ goto icont;
+ }
+#undef pcis
+}
+private int
+bbox_continue(os_ptr op)
+{ int code = type1_callout_dispatch(op, bbox_continue);
+
+ if ( code == 0 )
+ { /* Assume the OtherSubr(s) didn't mess with the o-stack.... */
+ int npop = (r_has_type(op, t_string) ? 4 : 6);
+
+ pop(npop); op -= npop;
+ op_type1_free(op);
+ }
+ return code;
+}
+private int
+nobbox_continue(os_ptr op)
+{ int code = type1_callout_dispatch(op, nobbox_continue);
+
+ if ( code )
+ return code;
+ { gs_type1exec_state cxs;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+
+ cxs = *pcxs;
+ op_type1_free(op);
+ return nobbox_finish(op, &cxs);
+ }
+}
+
+/* Clean up after a Type 1 callout. */
+private int
+op_type1_cleanup(os_ptr op)
+{ ifree_object(r_ptr(esp + 2, void), "op_type1_cleanup");
+ return 0;
+}
+private void
+op_type1_free(os_ptr op)
+{ ifree_object(r_ptr(esp, void), "op_type1_free");
+ /*
+ * In order to avoid popping from the e-stack and then pushing onto
+ * it, which would violate an interpreter invariant, we simply
+ * overwrite the two e-stack items being discarded (hpcxs and the
+ * cleanup operator) with empty procedures.
+ */
+ make_empty_const_array(esp - 1, a_readonly + a_executable);
+ make_empty_const_array(esp, a_readonly + a_executable);
+}
+
+/* Finish the no-FontBBox case after constructing the path. */
+/* If we are oversampling for anti-aliasing, we have to go around again. */
+/* <font> <code|name> <name> <charstring> %nobbox_continue - */
+private int
+nobbox_finish(os_ptr op, gs_type1exec_state *pcxs)
+{ int code;
+ gs_show_enum *penum = op_show_find();
+ gs_font *pfont;
+#define pbfont ((gs_font_base *)pfont)
+#define pfont1 ((gs_font_type1 *)pfont)
+
+ if ( (code = gs_pathbbox(igs, &pcxs->char_bbox)) < 0 ||
+ (code = font_param(op - 3, &pfont)) < 0
+ )
+ return code;
+ if ( penum == 0 || !font_is_type1_compatible(pfont) )
+ return_error(e_undefined);
+ if ( pcxs->present == metricsNone )
+ { gs_point endpt;
+ if ( (code = gs_currentpoint(igs, &endpt)) < 0 )
+ return code;
+ pcxs->sbw[2] = endpt.x, pcxs->sbw[3] = endpt.y;
+ pcxs->present = metricsSideBearingAndWidth;
+ }
+ /*
+ * We only need to rebuild the path from scratch if we might
+ * oversample for anti-aliasing.
+ */
+ if ( (*dev_proc(igs->device, get_alpha_bits))
+ (igs->device, go_text) > 1
+ )
+ { gs_newpath(igs);
+ gs_moveto(igs, 0.0, 0.0);
+ code = gs_type1_init(&pcxs->cis, penum, NULL,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if ( code < 0 )
+ return code;
+ return type1exec_bbox(op, pcxs, pfont);
+ }
+ return zchar_set_cache(op, pbfont, op, NULL, pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ nobbox_fill, nobbox_stroke);
+#undef pbfont
+}
+/* Finish by popping the operands and filling or stroking. */
+private int
+nobbox_fill(os_ptr op)
+{ pop(4);
+ /*
+ * Properly designed fonts, which have no self-intersecting outlines
+ * and in which outer and inner outlines are drawn in opposite
+ * directions, aren't affected by choice of filling rule; but some
+ * badly designed fonts in the Genoa test suite seem to require
+ * using the even-odd rule to match Adobe interpreters.
+ */
+ return gs_eofill(igs);
+}
+private int
+nobbox_stroke(os_ptr op)
+{ pop(4);
+ return gs_stroke(igs);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Get the metrics (l.s.b. and width) from the Type 1 interpreter. */
+private void
+type1_cis_get_metrics(const gs_type1_state *pcis, double psbw[4])
+{ psbw[0] = fixed2float(pcis->lsb.x);
+ psbw[1] = fixed2float(pcis->lsb.y);
+ psbw[2] = fixed2float(pcis->width.x);
+ psbw[3] = fixed2float(pcis->width.y);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zchar1_op_defs) {
+ {"4.type1execchar", ztype1execchar},
+ /* Internal operators */
+ {"4%nobbox_continue", nobbox_continue},
+ {"4%nobbox_fill", nobbox_fill},
+ {"4%nobbox_stroke", nobbox_stroke},
+ {"4%bbox_getsbw_continue", bbox_getsbw_continue},
+ {"4%bbox_continue", bbox_continue},
+ {"4%bbox_fill", bbox_fill},
+ {"4%bbox_stroke", bbox_stroke},
+END_OP_DEFS(0) }
+
+/* ------ Auxiliary procedures for type 1 fonts ------ */
+
+/* These are exported for zfont1.c. */
+
+int
+z1_subr_proc(gs_font_type1 *pfont, int index, bool global,
+ gs_const_string *pstr)
+{ const font_data *pfdata = pfont_data(pfont);
+ ref subr;
+ int code;
+
+ code = array_get((global ? &pfdata->u.type1.GlobalSubrs :
+ &pfdata->u.type1.Subrs),
+ index, &subr);
+ if ( code < 0 )
+ return code;
+ check_type_only(subr, t_string);
+ pstr->data = subr.value.const_bytes;
+ pstr->size = r_size(&subr);
+ return 0;
+}
+
+int
+z1_seac_proc(gs_font_type1 *pfont, int index, gs_const_string *pstr)
+{ const font_data *pfdata = pfont_data(pfont);
+ ref *pcstr;
+ ref enc_entry;
+ int code = array_get(&StandardEncoding, (long)index, &enc_entry);
+
+ if ( code < 0 )
+ return code;
+ if ( dict_find(&pfdata->CharStrings, &enc_entry, &pcstr) <= 0 )
+ return_error(e_undefined);
+ check_type_only(*pcstr, t_string);
+ pstr->data = pcstr->value.const_bytes;
+ pstr->size = r_size(pcstr);
+ return 0;
+}
+
+int
+z1_push_proc(gs_font_type1 *ignore, const fixed *pf, int count)
+{ const fixed *p = pf + count - 1;
+ int i;
+
+ check_ostack(count);
+ for ( i = 0; i < count; i++, p-- )
+ { osp++;
+ make_real(osp, fixed2float(*p));
+ }
+ return 0;
+}
+
+int
+z1_pop_proc(gs_font_type1 *ignore, fixed *pf)
+{ double val;
+ int code = real_param(osp, &val);
+
+ if ( code < 0 )
+ return code;
+ *pf = float2fixed(val);
+ osp--;
+ return 0;
+}
diff --git a/gs/src/zchar2.c b/gs/src/zchar2.c
new file mode 100644
index 000000000..47a7eec50
--- /dev/null
+++ b/gs/src/zchar2.c
@@ -0,0 +1,317 @@
+/* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zchar2.c */
+/* Level 2 character operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gsstruct.h" /* for st_stream */
+#include "gxfixed.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxchar.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "gspath.h" /* gs_rmoveto prototype */
+
+/* Table of continuation procedures. */
+private int xshow_continue(P1(os_ptr));
+private int yshow_continue(P1(os_ptr));
+private int xyshow_continue(P1(os_ptr));
+static const op_proc_p xyshow_continues[4] = {
+ 0, xshow_continue, yshow_continue, xyshow_continue
+};
+
+/* Forward references */
+private int cshow_continue(P1(os_ptr));
+private int cshow_restore_font(P1(os_ptr));
+private int moveshow(P2(os_ptr, int));
+private int moveshow_continue(P2(os_ptr, int));
+
+/* <proc> <string> cshow - */
+private int
+zcshow(os_ptr op)
+{ os_ptr proc_op = op - 1;
+ os_ptr str_op = op;
+ gs_show_enum *penum;
+ int code;
+
+ /* Even though this is not documented anywhere by Adobe, */
+ /* the Adobe interpreters apparently allow the string and */
+ /* the procedure to be provided in either order! */
+ if ( r_is_proc(proc_op) )
+ ;
+ else if ( r_is_proc(op) ) /* operands reversed */
+ { proc_op = op;
+ str_op = op - 1;
+ }
+ else
+ { check_op(2);
+ return_error(e_typecheck);
+ }
+ if ( (code = op_show_setup(str_op, &penum)) != 0 )
+ return code;
+ if ( (code = gs_cshow_n_init(penum, igs, (char *)str_op->value.bytes,
+ r_size(str_op))) < 0
+ )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, NULL);
+ sslot = *proc_op; /* save kerning proc */
+ return cshow_continue(op - 2);
+}
+private int
+cshow_continue(os_ptr op)
+{ gs_show_enum *penum = senum;
+ int code;
+
+ check_estack(4); /* in case we call the procedure */
+ code = gs_show_next(penum);
+ if ( code != gs_show_move )
+ { code = op_show_continue_dispatch(op, code);
+ if ( code == o_push_estack ) /* must be gs_show_render */
+ make_op_estack(esp - 1, cshow_continue);
+ return code;
+ }
+ /* Push the character code and width, and call the procedure. */
+ { ref *pslot = &sslot;
+ gs_point wpt;
+ gs_font *font = gs_show_current_font(penum);
+ gs_font *scaled_font;
+
+ gs_show_current_width(penum, &wpt);
+#if 0
+ /****************
+ * The following code is logically correct (or at least,
+ * probably more correct than the code it replaces),
+ * but because of the issues about creating the scaled
+ * font in the correct VM space that make_font (in zfont.c)
+ * has to deal with, it creates references pointing to
+ * the wrong spaces. Therefore, we've removed it.
+ *****************/
+ { int fdepth = penum->fstack.depth;
+
+ if ( fdepth <= 0 )
+ scaled_font = font; /* not composite */
+ else
+ { code = gs_makefont(font->dir, font,
+ &penum->fstack.items[fdepth - 1].font->
+ FontMatrix, &scaled_font);
+ if ( code < 0 )
+ return code;
+ }
+ }
+#else
+ scaled_font = font;
+#endif
+ push(3);
+ make_int(op - 2, gs_show_current_char(penum));
+ make_real(op - 1, wpt.x);
+ make_real(op, wpt.y);
+ push_op_estack(cshow_continue);
+ if ( scaled_font != gs_rootfont(igs) )
+ push_op_estack(cshow_restore_font);
+ /* cshow does not change rootfont for user procedure */
+ gs_set_currentfont(igs, scaled_font);
+ *++esp = *pslot; /* user procedure */
+ }
+ return o_push_estack;
+}
+private int
+cshow_restore_font(os_ptr op)
+{ /* We have 1 more entry on the e-stack (cshow_continue). */
+ return gs_show_restore_font(esenum(esp - 1));
+}
+
+/* <charname> glyphshow - */
+private int
+zglyphshow(os_ptr op)
+{ gs_glyph glyph;
+ gs_show_enum *penum;
+ int code;
+
+ switch ( gs_currentfont(igs)->FontType )
+ {
+ case ft_CID_encrypted:
+ case ft_CID_user_defined:
+ case ft_CID_TrueType:
+ check_int_leu(*op, gs_max_glyph - gs_min_cid_glyph);
+ glyph = (gs_glyph)op->value.intval + gs_min_cid_glyph;
+ break;
+ default:
+ check_type(*op, t_name);
+ glyph = name_index(op);
+ }
+ if ( (code = op_show_enum_setup(op, &penum)) != 0 )
+ return code;
+ if ( (code = gs_glyphshow_init(penum, igs, glyph)) < 0 )
+ { ifree_object(penum, "op_show_glyph");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, NULL);
+ return op_show_continue(op - 1);
+}
+
+/* - rootfont <font> */
+private int
+zrootfont(os_ptr op)
+{ push(1);
+ *op = *pfont_dict(gs_rootfont(igs));
+ return 0;
+}
+
+/* <string> <numarray|numstring> xshow - */
+private int
+zxshow(os_ptr op)
+{ return moveshow(op, 1);
+}
+
+/* <string> <numarray|numstring> yshow - */
+private int
+zyshow(os_ptr op)
+{ return moveshow(op, 2);
+}
+
+/* <string> <numarray|numstring> xyshow - */
+private int
+zxyshow(os_ptr op)
+{ return moveshow(op, 3);
+}
+
+/* Common code for {x,y,xy}show */
+private int
+moveshow(os_ptr op, int xymask)
+{ gs_show_enum *penum;
+ int code = op_show_setup(op - 1, &penum);
+
+ if ( code != 0 )
+ return code;
+ if ( (code = gs_xyshow_n_init(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1)) < 0) )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ code = num_array_format(op);
+ if ( code < 0 )
+ { ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, NULL);
+ ref_assign(&sslot, op);
+ return moveshow_continue(op - 2, xymask);
+}
+
+/* Continuation procedures */
+
+private int
+xshow_continue(os_ptr op)
+{ return moveshow_continue(op, 1);
+}
+
+private int
+yshow_continue(os_ptr op)
+{ return moveshow_continue(op, 2);
+}
+
+private int
+xyshow_continue(os_ptr op)
+{ return moveshow_continue(op, 3);
+}
+
+/* Get one value from the encoded number string or array. */
+/* Sets pvalue->value.realval. */
+private int
+sget_real(const ref *nsp, int format, uint index, ref *pvalue)
+{ int code;
+ switch ( code = num_array_get(nsp, format, index, pvalue) )
+ {
+ case t_integer: pvalue->value.realval = pvalue->value.intval;
+ case t_real: return t_real;
+ case t_null: code = gs_note_error(e_rangecheck);
+ default: return code;
+ }
+}
+
+private int
+moveshow_continue(os_ptr op, int xymask)
+{ const ref *nsp = &sslot;
+ int format = num_array_format(nsp);
+ int code;
+ gs_show_enum *penum = senum;
+ uint index = ssindex.value.intval;
+
+ for ( ; ; )
+ { ref rwx, rwy;
+ code = gs_show_next(penum);
+ if ( code != gs_show_move )
+ { ssindex.value.intval = index;
+ code = op_show_continue_dispatch(op, code);
+ if ( code == o_push_estack ) /* must be gs_show_render */
+ { make_op_estack(esp - 1, xyshow_continues[xymask]);
+ }
+ return code;
+ }
+ /* Move according to the next value(s) from the stream. */
+ if ( xymask & 1 )
+ { code = sget_real(nsp, format, index++, &rwx);
+ if ( code < 0 ) break;
+ }
+ else
+ rwx.value.realval = 0;
+ if ( xymask & 2 )
+ { code = sget_real(nsp, format, index++, &rwy);
+ if ( code < 0 ) break;
+ }
+ else
+ rwy.value.realval = 0;
+ code = gs_rmoveto(igs, rwx.value.realval, rwy.value.realval);
+ if ( code < 0 ) break;
+ }
+ /* An error occurred. Clean up before returning. */
+ return op_show_free(code);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zchar2_op_defs) {
+ {"2cshow", zcshow},
+ {"0rootfont", zrootfont},
+ /* Internal operators */
+ {"0%cshow_continue", cshow_continue},
+ {"0%cshow_restore_font", cshow_restore_font},
+END_OP_DEFS(0) }
+BEGIN_OP_DEFS(zchar2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1glyphshow", zglyphshow},
+ {"2xshow", zxshow},
+ {"2xyshow", zxyshow},
+ {"2yshow", zyshow},
+ /* Internal operators */
+ {"0%xshow_continue", xshow_continue},
+ {"0%yshow_continue", yshow_continue},
+ {"0%xyshow_continue", xyshow_continue},
+END_OP_DEFS(0) }
diff --git a/gs/src/zchar42.c b/gs/src/zchar42.c
new file mode 100644
index 000000000..ff771d232
--- /dev/null
+++ b/gs/src/zchar42.c
@@ -0,0 +1,174 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zchar42.c */
+/* Type 42 character display operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gspaint.h" /* for gs_fill, gs_stroke */
+#include "gspath.h"
+#include "gxfixed.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gzstate.h" /* only for ->path */
+#include "dstack.h" /* only for systemdict */
+#include "estack.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "ifont.h" /* for font_param */
+#include "igstate.h"
+#include "store.h"
+
+/* Imported procedures */
+int gs_type42_append(P7(uint glyph_index, gs_imager_state *pis,
+ gx_path *ppath, const gs_log2_scale_point *pscale, bool charpath_flag,
+ int paint_type, gs_font_type42 *pfont));
+int gs_type42_get_metrics(P3(gs_font_type42 *pfont, uint glyph_index,
+ float psbw[4]));
+
+/* <font> <code|name> <name> <glyph_index> .type42execchar - */
+private int type42_fill(P1(os_ptr));
+private int type42_stroke(P1(os_ptr));
+private int
+ztype42execchar(register os_ptr op)
+{ gs_font *pfont;
+#define pbfont ((gs_font_base *)pfont)
+#define pfont42 ((gs_font_type42 *)pfont)
+ int code = font_param(op - 3, &pfont);
+ gs_show_enum *penum = op_show_find();
+ int present;
+ double sbw[4];
+
+ if ( code < 0 )
+ return code;
+ if ( penum == 0 || (pfont->FontType != ft_TrueType &&
+ pfont->FontType != ft_CID_TrueType)
+ )
+ return_error(e_undefined);
+ /*
+ * Any reasonable implementation would execute something like
+ * 1 setmiterlimit 0 setlinejoin 0 setlinecap
+ * here, but apparently the Adobe implementations aren't reasonable.
+ *
+ * If this is a stroked font, set the stroke width.
+ */
+ if ( pfont->PaintType )
+ gs_setlinewidth(igs, pfont->StrokeWidth);
+ check_estack(3); /* for continuations */
+ /*
+ * Execute the definition of the character.
+ */
+ if ( r_is_proc(op) )
+ return zchar_exec_char_proc(op);
+ /*
+ * The definition must be a Type 42 glyph index.
+ * Note that we do not require read access: this is deliberate.
+ */
+ check_type(*op, t_integer);
+ check_ostack(3); /* for lsb values */
+ present = zchar_get_metrics(pbfont, op - 1, sbw);
+ if ( present < 0 )
+ return present;
+ /* Establish a current point. */
+ code = gs_moveto(igs, 0.0, 0.0);
+ if ( code < 0 )
+ return code;
+ /* Get the metrics and set the cache device. */
+ if ( present == metricsNone )
+ { float sbw42[4];
+ int i;
+
+ code = gs_type42_get_metrics(pfont42, (uint)op->value.intval, sbw42);
+ if ( code < 0 )
+ return code;
+ for ( i = 0; i < 4; ++i )
+ sbw[i] = sbw42[i];
+ }
+ return zchar_set_cache(op, pbfont, op - 1,
+ (present == metricsSideBearingAndWidth ?
+ sbw : NULL),
+ sbw + 2, &pbfont->FontBBox,
+ type42_fill, type42_stroke);
+#undef pfont42
+#undef pbfont
+}
+
+/* Continue after a CDevProc callout. */
+private int type42_finish(P2(os_ptr op, int (*cont)(P1(gs_state *))));
+private int
+type42_fill(os_ptr op)
+{ return type42_finish(op, gs_fill);
+}
+private int
+type42_stroke(os_ptr op)
+{ return type42_finish(op, gs_stroke);
+}
+/* <font> <code|name> <name> <glyph_index> <sbx> <sby> %type42_{fill|stroke} - */
+/* <font> <code|name> <name> <glyph_index> %type42_{fill|stroke} - */
+private int
+type42_finish(os_ptr op, int (*cont)(P1(gs_state *)))
+{ gs_font *pfont;
+#define pfont42 ((gs_font_type42 *)pfont)
+ int code;
+ gs_show_enum *penum = op_show_find();
+ double sbxy[2];
+ gs_point sbpt;
+ gs_point *psbpt = 0;
+ os_ptr opc = op;
+
+ if ( !r_has_type(op - 3, t_dictionary) )
+ { check_op(6);
+ code = num_params(op, 2, sbxy);
+ if ( code < 0 )
+ return code;
+ sbpt.x = sbxy[0];
+ sbpt.y = sbxy[1];
+ psbpt = &sbpt;
+ opc -= 2;
+ }
+ check_type(*opc, t_integer);
+ code = font_param(opc - 3, &pfont);
+ if ( code < 0 )
+ return code;
+ if ( penum == 0 || (pfont->FontType != ft_TrueType &&
+ pfont->FontType != ft_CID_TrueType)
+ )
+ return_error(e_undefined);
+ code = gs_type42_append((uint)opc->value.intval,
+ (gs_imager_state *)penum->pgs,
+ penum->pgs->path,
+ &penum->log2_current_scale,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont->PaintType, pfont42);
+ if ( code < 0 )
+ return code;
+ pop((psbpt == 0 ? 4 : 6));
+ return (*cont)(penum->pgs);
+#undef pfont42
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zchar42_op_defs) {
+ {"4.type42execchar", ztype42execchar},
+END_OP_DEFS(0) }
diff --git a/gs/src/zcharout.c b/gs/src/zcharout.c
new file mode 100644
index 000000000..5a88bfdd6
--- /dev/null
+++ b/gs/src/zcharout.c
@@ -0,0 +1,234 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcharout.c */
+/* Common code for outline (Type 1 / 4 / 42) fonts */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "dstack.h" /* only for systemdict */
+#include "estack.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Imported operators */
+int zsetcachedevice(P1(os_ptr)); /* zchar.c */
+int zsetcachedevice2(P1(os_ptr)); /* zchar.c */
+
+/*
+ * Execute an outline defined by a PostScript procedure.
+ * The top elements of the stack are:
+ * <font> <code|name> <name> <outline_id>
+ */
+int
+zchar_exec_char_proc(os_ptr op)
+{ /*
+ * The definition is a PostScript procedure. Execute
+ * <code|name> proc
+ * within a systemdict begin/end and a font begin/end.
+ */
+ es_ptr ep;
+
+ check_estack(5);
+ ep = esp += 5;
+ make_op_estack(ep - 4, zend);
+ make_op_estack(ep - 3, zend);
+ ref_assign(ep - 2, op);
+ make_op_estack(ep - 1, zbegin);
+ make_op_estack(ep, zbegin);
+ ref_assign(op - 1, systemdict);
+ { ref rfont;
+ ref_assign(&rfont, op - 3);
+ ref_assign(op - 3, op - 2);
+ ref_assign(op - 2, &rfont);
+ }
+ pop(1);
+ return o_push_estack;
+}
+
+/*
+ * Get the metrics for a character from the Metrics dictionary of a base
+ * font. If present, store the l.s.b. in psbw[0,1] and the width in
+ * psbw[2,3].
+ */
+int /*metrics_present*/
+zchar_get_metrics(const gs_font_base *pbfont, const ref *pcnref,
+ double psbw[4])
+{ const ref *pfdict = &pfont_data(pbfont)->dict;
+ ref *pmdict;
+
+ if ( dict_find_string(pfdict, "Metrics", &pmdict) > 0 )
+ { ref *pmvalue;
+
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if ( dict_find(pmdict, pcnref, &pmvalue) > 0 )
+ { if ( num_params(pmvalue, 1, psbw + 2) >= 0 )
+ { /* <wx> only */
+ psbw[3] = 0;
+ return metricsWidthOnly;
+ }
+ else
+ { int code;
+ check_read_type_only(*pmvalue, t_array);
+ switch ( r_size(pmvalue) )
+ {
+ case 2: /* [<sbx> <wx>] */
+ code = num_params(pmvalue->value.refs + 1,
+ 2, psbw);
+ psbw[2] = psbw[1];
+ psbw[1] = psbw[3] = 0;
+ break;
+ case 4: /* [<sbx> <sby> <wx> <wy>] */
+ code = num_params(pmvalue->value.refs + 3,
+ 4, psbw);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if ( code < 0 )
+ return code;
+ return metricsSideBearingAndWidth;
+ }
+ }
+ }
+ return metricsNone;
+}
+
+/*
+ * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return
+ * o_push_estack if we had to call a CDevProc, or if we are skipping the
+ * rendering process (only getting the metrics).
+ */
+int
+zchar_set_cache(os_ptr op, const gs_font_base *pbfont, const ref *pcnref,
+ const double psb[2], const double pwidth[2], const gs_rect *pbbox,
+ int (*cont_fill)(P1(os_ptr)), int (*cont_stroke)(P1(os_ptr)))
+{ const ref *pfdict = &pfont_data(pbfont)->dict;
+ ref *pmdict;
+ ref *pcdevproc;
+ int have_cdevproc;
+ ref rpop;
+ bool metrics2 = false;
+ int (*cont)(P1(os_ptr));
+ double w2[10];
+ gs_show_enum *penum = op_show_find();
+
+ w2[0] = pwidth[0], w2[1] = pwidth[1];
+
+ /* Adjust the bounding box for stroking if needed. */
+
+ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
+ w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
+ if ( pbfont->PaintType == 0 )
+ cont = cont_fill;
+ else
+ { double expand = max(1.415, gs_currentmiterlimit(igs)) *
+ gs_currentlinewidth(igs) / 2;
+
+ w2[2] -= expand, w2[3] -= expand;
+ w2[4] += expand, w2[5] += expand;
+ cont = cont_stroke;
+ }
+
+ /* Check for Metrics2. */
+
+ if ( dict_find_string(pfdict, "Metrics2", &pmdict) > 0 )
+ { ref *pmvalue;
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if ( dict_find(pmdict, pcnref, &pmvalue) > 0 )
+ { check_read_type_only(*pmvalue, t_array);
+ if ( r_size(pmvalue) == 4 )
+ { int code = num_params(pmvalue->value.refs + 3,
+ 4, w2 + 6);
+ if ( code < 0 )
+ return code;
+ metrics2 = true;
+ }
+ }
+ }
+
+ /* Check for CDevProc or "short-circuiting". */
+
+ have_cdevproc = dict_find_string(pfdict, "CDevProc", &pcdevproc) > 0;
+ if ( have_cdevproc || gs_show_width_only(penum) )
+ { int i;
+ int (*zsetc)(P1(os_ptr));
+ int nparams;
+
+ if ( have_cdevproc )
+ { check_proc_only(*pcdevproc);
+ zsetc = zsetcachedevice2;
+ if ( !metrics2 )
+ { w2[6] = w2[0], w2[7] = w2[1];
+ w2[8] = w2[9] = 0;
+ }
+ nparams = 10;
+ }
+ else
+ { make_oper(&rpop, 0, zpop);
+ pcdevproc = &rpop;
+ if ( metrics2 )
+ zsetc = zsetcachedevice2, nparams = 10;
+ else
+ zsetc = zsetcachedevice, nparams = 6;
+ }
+ check_estack(3);
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if ( psb != 0 )
+ { push(nparams + 3);
+ make_real(op - (nparams + 2), psb[0]);
+ make_real(op - (nparams + 1), psb[1]);
+ }
+ else
+ { push(nparams + 1);
+ }
+ for ( i = 0; i < nparams; ++i )
+ make_real(op - nparams + i, w2[i]);
+ ref_assign(op, pcnref);
+ push_op_estack(cont);
+ push_op_estack(zsetc);
+ ++esp;
+ ref_assign(esp, pcdevproc);
+ return o_push_estack;
+ }
+ { int code =
+ (metrics2 ? gs_setcachedevice2_double(penum, igs, w2) :
+ gs_setcachedevice_double(penum, igs, w2));
+ if ( code < 0 )
+ return code;
+ }
+
+ /* No metrics modification, do the stroke or fill now. */
+
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if ( psb != 0 )
+ { push(2);
+ make_real(op - 1, psb[0]);
+ make_real(op, psb[1]);
+ }
+ return cont(op);
+}
diff --git a/gs/src/zcid.c b/gs/src/zcid.c
new file mode 100644
index 000000000..e17e9f0ee
--- /dev/null
+++ b/gs/src/zcid.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcid.c */
+/* CID-keyed font operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gsccode.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "iname.h"
+#include "store.h"
+
+/* Imported from zfont42.c */
+int build_gs_TrueType_font(P5(os_ptr op, font_type ftype,
+ const char _ds *bcstr, const char _ds *bgstr,
+ build_font_options_t options));
+
+/* <string|name> <font_dict> .buildfont9/10 <string|name> <font> */
+/* Build a type 9 or 10 (CID-keyed) font. */
+/* Right now, we treat these like type 3 (with a BuildGlyph procedure). */
+private int
+build_gs_cid_font(os_ptr op, font_type ftype, const build_proc_refs *pbuild)
+{ int code;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ code = build_gs_simple_font(op, &pfont, ftype, &st_gs_font_base,
+ pbuild,
+ bf_Encoding_optional |
+ bf_FontBBox_required |
+ bf_UniqueID_ignored);
+ if ( code < 0 )
+ return code;
+ return define_gs_font((gs_font *)pfont);
+}
+private int
+zbuildfont9(os_ptr op)
+{ build_proc_refs build;
+ int code = build_proc_name_refs(&build, NULL, "%Type9BuildGlyph");
+
+ if ( code < 0 )
+ return code;
+ return build_gs_cid_font(op, ft_CID_encrypted, &build);
+}
+private int
+zbuildfont10(os_ptr op)
+{ build_proc_refs build;
+ int code = build_gs_font_procs(op, &build);
+
+ if ( code < 0 )
+ return code;
+ make_null(&build.BuildChar); /* only BuildGlyph */
+ return build_gs_cid_font(op, ft_CID_user_defined, &build);
+}
+
+/* <string|name> <font_dict> .buildfont11 <string|name> <font> */
+private int
+zbuildfont11(os_ptr op)
+{ return build_gs_TrueType_font(op, ft_CID_TrueType, (const char _ds *)0,
+ "%Type11BuildGlyph",
+ bf_Encoding_optional |
+ bf_FontBBox_required |
+ bf_UniqueID_ignored |
+ bf_CharStrings_optional);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcid_op_defs) {
+ {"2.buildfont9", zbuildfont9},
+ {"2.buildfont10", zbuildfont10},
+ {"2.buildfont11", zbuildfont11},
+END_OP_DEFS(0) }
diff --git a/gs/src/zcie.c b/gs/src/zcie.c
new file mode 100644
index 000000000..0bf7b7494
--- /dev/null
+++ b/gs/src/zcie.c
@@ -0,0 +1,627 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcie.c */
+/* CIE color operators */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxcspace.h" /* gscolor2.h requires gscspace.h */
+#include "gscolor2.h"
+#include "gscie.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icie.h"
+#include "isave.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_null */
+
+/* CIE color dictionaries are so complex that */
+/* we handle the CIE case of setcolorspace separately here. */
+
+/* Forward references */
+private int cache_common(P4(gs_cie_common *, const ref_cie_procs *,
+ void *, const gs_state *));
+
+/* Allocator structure types for CIE structures */
+private_st_cie_defg();
+private_st_cie_def();
+private_st_cie_abc();
+private_st_cie_a();
+
+/* Empty procedures */
+static ref empty_procs[4];
+
+/* Original CIE color space types. */
+/* We use CIExxx rather than CIEBasedxxx in some places because */
+/* gcc under VMS only retains 23 characters of procedure names, */
+/* and DEC C truncates all identifiers at 31 characters. */
+extern const gs_color_space_type
+ gs_color_space_type_CIEDEFG,
+ gs_color_space_type_CIEDEF,
+ gs_color_space_type_CIEABC,
+ gs_color_space_type_CIEA;
+/* Redefined CIE color space types (that load the cache when installed) */
+gs_color_space_type
+ cs_type_zCIEDEFG,
+ cs_type_zCIEDEF,
+ cs_type_zCIEABC,
+ cs_type_zCIEA;
+private cs_proc_install_cspace(cs_install_zCIEDEFG);
+private cs_proc_install_cspace(cs_install_zCIEDEF);
+private cs_proc_install_cspace(cs_install_zCIEABC);
+private cs_proc_install_cspace(cs_install_zCIEA);
+
+/* Initialization */
+private void
+zcie_init(void)
+{
+ /* Make the null (default) transformation procedures. */
+ make_empty_const_array(&empty_procs[0], a_readonly + a_executable);
+ make_empty_const_array(&empty_procs[1], a_readonly + a_executable);
+ make_empty_const_array(&empty_procs[2], a_readonly + a_executable);
+ make_empty_const_array(&empty_procs[3], a_readonly + a_executable);
+
+ /* Create the modified color space types. */
+ cs_type_zCIEDEFG = gs_color_space_type_CIEDEFG;
+ cs_type_zCIEDEFG.install_cspace = cs_install_zCIEDEFG;
+ cs_type_zCIEDEF = gs_color_space_type_CIEDEF;
+ cs_type_zCIEDEF.install_cspace = cs_install_zCIEDEF;
+ cs_type_zCIEABC = gs_color_space_type_CIEABC;
+ cs_type_zCIEABC.install_cspace = cs_install_zCIEABC;
+ cs_type_zCIEA = gs_color_space_type_CIEA;
+ cs_type_zCIEA.install_cspace = cs_install_zCIEA;
+
+}
+
+/* ------ Parameter extraction utilities ------ */
+
+/* Get a range array parameter from a dictionary. */
+/* We know that count <= 4. */
+int
+dict_ranges_param(const ref *pdref, const char _ds *kstr, int count,
+ gs_range *prange)
+{ int code = dict_float_array_param(pdref, kstr, count * 2,
+ (float *)prange, NULL);
+ if ( code < 0 )
+ return code;
+ else if ( code == 0 )
+ memcpy(prange, Range4_default.ranges, count * sizeof(gs_range));
+ else if ( code != count * 2 )
+ return_error(e_rangecheck);
+ return 0;
+}
+
+/* Get an array of procedures from a dictionary. */
+/* We know count <= countof(empty_procs). */
+int
+dict_proc_array_param(const ref *pdict, const char _ds *kstr,
+ uint count, ref *pparray)
+{ ref *pvalue;
+ if ( dict_find_string(pdict, kstr, &pvalue) > 0 )
+ { uint i;
+ check_array_only(*pvalue);
+ if ( r_size(pvalue) != count )
+ return_error(e_rangecheck);
+ for ( i = 0; i < count; i++ )
+ { ref proc;
+ array_get(pvalue, (long)i, &proc);
+ check_proc_only(proc);
+ }
+ *pparray = *pvalue;
+ }
+ else
+ make_const_array(pparray, a_readonly | avm_foreign,
+ count, &empty_procs[0]);
+ return 0;
+}
+
+/* Get WhitePoint and BlackPoint values. */
+int
+cie_points_param(const ref *pdref, gs_cie_wb *pwb)
+{ int code;
+ if ( (code = dict_float_array_param(pdref, "WhitePoint", 3, (float *)&pwb->WhitePoint, NULL)) != 3 ||
+ (code = dict_float_array_param(pdref, "BlackPoint", 3, (float *)&pwb->BlackPoint, (const float *)&BlackPoint_default)) != 3
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if ( pwb->WhitePoint.u <= 0 ||
+ pwb->WhitePoint.v != 1 ||
+ pwb->WhitePoint.w <= 0 ||
+ pwb->BlackPoint.u < 0 ||
+ pwb->BlackPoint.v < 0 ||
+ pwb->BlackPoint.w < 0
+ )
+ return_error(e_rangecheck);
+ return 0;
+}
+
+/* Process a 3- or 4-dimensional lookup table from a dictionary. */
+/* The caller has set pclt->n and pclt->m. */
+/* ptref is known to be a readable array of size at least n+1. */
+private int cie_3d_table_param(P4(const ref *ptable, uint count, uint nbytes,
+ gs_const_string *strings));
+int
+cie_table_param(const ref *ptref, gx_color_lookup_table *pclt,
+ gs_memory_t *mem)
+{ int n = pclt->n, m = pclt->m;
+ const ref *pta = ptref->value.const_refs;
+ int i;
+ uint nbytes;
+ int code;
+ gs_const_string *table;
+
+ for ( i = 0; i < n; ++i )
+ { check_type_only(pta[i], t_integer);
+ if ( pta[i].value.intval <= 1 || pta[i].value.intval > max_ushort )
+ return_error(e_rangecheck);
+ pclt->dims[i] = (int)pta[i].value.intval;
+ }
+ nbytes = m * pclt->dims[n-2] * pclt->dims[n-1];
+ if ( n == 3 )
+ { /* gs_alloc_byte_array is ****** WRONG ****** */
+ table =
+ (gs_const_string *)gs_alloc_byte_array(mem, pclt->dims[0],
+ sizeof(gs_const_string),
+ "cie_table_param");
+ if ( table == 0 )
+ return_error(e_VMerror);
+ code = cie_3d_table_param(pta + 3, pclt->dims[0], nbytes,
+ table);
+ }
+ else /* n == 4 */
+ { int d0 = pclt->dims[0], d1 = pclt->dims[1];
+ uint ntables = d0 * d1;
+ const ref *psuba;
+ check_read_type(pta[4], t_array);
+ if ( r_size(pta + 4) != d0 )
+ return_error(e_rangecheck);
+ /* gs_alloc_byte_array is ****** WRONG ****** */
+ table =
+ (gs_const_string *)gs_alloc_byte_array(mem, ntables,
+ sizeof(gs_const_string),
+ "cie_table_param");
+ if ( table == 0 )
+ return_error(e_VMerror);
+ psuba = pta[4].value.const_refs;
+ for ( i = 0; i < d0; ++i )
+ { code = cie_3d_table_param(psuba + i, d1, nbytes,
+ table + d1 * i);
+ if ( code < 0 )
+ break;
+ }
+ }
+ if ( code < 0 )
+ { gs_free_object(mem, table, "cie_table_param");
+ return code;
+ }
+ pclt->table = table;
+ return 0;
+}
+private int
+cie_3d_table_param(const ref *ptable, uint count, uint nbytes,
+ gs_const_string *strings)
+{ const ref *rstrings;
+ uint i;
+
+ check_read_type(*ptable, t_array);
+ if ( r_size(ptable) != count )
+ return_error(e_rangecheck);
+ rstrings = ptable->value.const_refs;
+ for ( i = 0; i < count; ++i )
+ { const ref *prt2 = rstrings + i;
+ check_read_type(*prt2, t_string);
+ if ( r_size(prt2) != nbytes )
+ return_error(e_rangecheck);
+ strings[i].data = rstrings[i].value.const_bytes;
+ strings[i].size = nbytes;
+ }
+ return 0;
+}
+
+/* ------ CIE setcolorspace ------ */
+
+/* Common code for the CIEBased* cases of setcolorspace. */
+private int
+cie_lmnp_param(const ref *pdref, gs_cie_common *pcie, ref_cie_procs *pcprocs)
+{ int code;
+ if ( (code = dict_range3_param(pdref, "RangeLMN", &pcie->RangeLMN)) < 0 ||
+ (code = dict_proc3_param(pdref, "DecodeLMN", &pcprocs->DecodeLMN)) < 0 ||
+ (code = dict_matrix3_param(pdref, "MatrixLMN", &pcie->MatrixLMN)) != matrix3_ok ||
+ (code = cie_points_param(pdref, &pcie->points)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ pcie->DecodeLMN = DecodeLMN_default;
+ return 0;
+}
+
+/* Common code for the CIEBasedABC/DEF[G] cases of setcolorspace. */
+private int
+cie_abc_param(const ref *pdref, gs_cie_abc_common *pcie,
+ ref_cie_procs *pcprocs)
+{ int code;
+ if ( (code = dict_range3_param(pdref, "RangeABC", &pcie->RangeABC)) < 0 ||
+ (code = dict_proc3_param(pdref, "DecodeABC", &pcprocs->Decode.ABC)) < 0 ||
+ (code = dict_matrix3_param(pdref, "MatrixABC", &pcie->MatrixABC)) != matrix3_ok ||
+ (code = cie_lmnp_param(pdref, &pcie->common, pcprocs)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ pcie->DecodeABC = DecodeABC_default;
+ return 0;
+}
+
+/* Finish setting a CIE space. */
+private int
+set_cie_finish(os_ptr op, gs_color_space *pcs, const ref_cie_procs *pcprocs)
+{ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ int code;
+
+ /* The color space installation procedure may refer to */
+ /* istate->colorspace.procs. */
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.cie = *pcprocs;
+ code = gs_setcolorspace(igs, pcs);
+ if ( code < 0 )
+ { istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+#ifdef NEW_CIE /**************** ****************/
+
+/* <dict> .setciedefgspace - */
+private int
+zsetciedefgspace(register os_ptr op)
+{ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space cs;
+ ref_color_procs procs;
+ gs_cie_defg *pcie;
+ int code;
+ ref *ptref;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ rc_alloc_struct_0(pcie, gs_cie_defg, &st_cie_defg, mem,
+ return_error(e_VMerror),
+ "setcolorspace(CIEBasedDEFG)");
+ if ( (code = dict_find_string(op, "Table", &ptref)) <= 0 )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_read_type(*ptref, t_array);
+ if ( r_size(ptref) != 5 )
+ return_error(e_rangecheck);
+ pcie->Table.n = 4;
+ pcie->Table.m = 3;
+ if ( (code = dict_ranges_param(op, "RangeDEFG", 4, pcie->RangeDEFG.ranges)) < 0 ||
+ (code = dict_proc_array_param(op, "DecodeDEFG", 4, &procs.cie.PreDecode.DEFG)) < 0 ||
+ (code = dict_ranges_param(op, "RangeHIJK", 4, pcie->RangeHIJK.ranges)) < 0 ||
+ (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
+ (code = cie_abc_param(op, &pcie->abc, &procs.cie)) < 0
+ )
+ { rc_free_struct(pcie, mem, "setcolorspace(CIEBasedDEFG)");
+ return code;
+ }
+ cs.params.defg = pcie;
+ cs.type = &cs_type_zCIEDEFG;
+ return set_cie_finish(op, &cs, &procs.cie);
+}
+
+/* <dict> .setciedefspace - */
+private int
+zsetciedefspace(register os_ptr op)
+{ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space cs;
+ ref_color_procs procs;
+ gs_cie_def *pcie;
+ int code;
+ ref *ptref;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ rc_alloc_struct_0(pcie, gs_cie_def, &st_cie_def, mem,
+ return_error(e_VMerror),
+ "setcolorspace(CIEBasedDEF)");
+ if ( (code = dict_find_string(op, "Table", &ptref)) <= 0 )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_read_type(*ptref, t_array);
+ if ( r_size(ptref) != 4 )
+ return_error(e_rangecheck);
+ pcie->Table.n = 4;
+ pcie->Table.m = 3;
+ if ( (code = dict_range3_param(op, "RangeDEF", &pcie->RangeDEF)) < 0 ||
+ (code = dict_proc3_param(op, "DecodeDEF", &procs.cie.PreDecode.DEF)) < 0 ||
+ (code = dict_range3_param(op, "RangeHIJ", &pcie->RangeHIJ)) < 0 ||
+ (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
+ (code = cie_abc_param(op, &pcie->abc, &procs.cie)) < 0
+ )
+ { rc_free_struct(pcie, mem, "setcolorspace(CIEBasedDEF)");
+ return code;
+ }
+ cs.params.def = pcie;
+ cs.type = &cs_type_zCIEDEF;
+ return set_cie_finish(op, &cs, &procs.cie);
+}
+
+#endif /*NEW_CIE*/ /**************** ****************/
+
+/* <dict> .setcieabcspace - */
+private int
+zsetcieabcspace(register os_ptr op)
+{ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space cs;
+ ref_color_procs procs;
+ gs_cie_abc *pcie;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ rc_alloc_struct_0(pcie, gs_cie_abc, &st_cie_abc, mem,
+ return_error(e_VMerror),
+ "setcolorspace(CIEBasedABC)");
+ code = cie_abc_param(op, pcie, &procs.cie);
+ if ( code < 0 )
+ { rc_free_struct(pcie, "setcolorspace(CIEBasedABC)");
+ return code;
+ }
+ cs.params.abc = pcie;
+ cs.type = &cs_type_zCIEABC;
+ return set_cie_finish(op, &cs, &procs.cie);
+}
+
+/* <dict> .setcieaspace - */
+private int
+zsetcieaspace(register os_ptr op)
+{ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space cs;
+ ref_color_procs procs;
+ gs_cie_a *pcie;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ if ( (code = dict_proc_param(op, "DecodeA", &procs.cie.Decode.A, true)) < 0 )
+ return code;
+ rc_alloc_struct_0(pcie, gs_cie_a, &st_cie_a, mem,
+ return_error(e_VMerror),
+ "setcolorspace(CIEBasedA)");
+ if ( (code = dict_float_array_param(op, "RangeA", 2, (float *)&pcie->RangeA, (const float *)&RangeA_default)) != 2 ||
+ (code = dict_float_array_param(op, "MatrixA", 3, (float *)&pcie->MatrixA, (const float *)&MatrixA_default)) != 3 ||
+ (code = cie_lmnp_param(op, &pcie->common, &procs.cie)) < 0
+ )
+ { rc_free_struct(pcie, "setcolorspace(CIEBasedA)");
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ pcie->DecodeA = DecodeA_default;
+ cs.params.a = pcie;
+ cs.type = &cs_type_zCIEA;
+ return set_cie_finish(op, &cs, &procs.cie);
+}
+
+/* ------ Install a CIE-based color space. ------ */
+
+/* The new CIEBasedDEF[G] spaces aren't really implemented yet.... */
+private int
+cs_install_zCIEDEFG(gs_color_space *pcs, gs_state *pgs)
+{ return_error(e_undefined);
+}
+private int
+cs_install_zCIEDEF(gs_color_space *pcs, gs_state *pgs)
+{ return_error(e_undefined);
+}
+
+private int cie_abc_finish(P1(os_ptr));
+private int
+cs_install_zCIEABC(gs_color_space *pcs, gs_state *pgs)
+{ es_ptr ep = esp;
+ gs_cie_abc *pcie = pcs->params.abc;
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code =
+ (*gs_color_space_type_CIEABC.install_cspace)(pcs, pgs); /* former routine */
+ if ( code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_abc_finish, pgs, pcie)) < 0 ||
+#ifdef NEW_CIE
+ (code = cie_prepare_cache3(&pcie->abc.RangeABC, pcprocs->Decode.ABC.value.const_refs, &pcie->abc.caches.DecodeABC[0], pcie, pgs, "Decode.ABC")) < 0 ||
+ (code = cache_common(&pcie->abc.common, pcprocs, pcie, pgs)) < 0
+#else
+ (code = cie_prepare_cache3(&pcie->RangeABC, pcprocs->Decode.ABC.value.const_refs, &pcie->caches.DecodeABC[0], pcie, pgs, "Decode.ABC")) < 0 ||
+ (code = cache_common(&pcie->common, pcprocs, pcie, pgs)) < 0
+#endif
+ )
+ { esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_abc_finish(os_ptr op)
+{ gs_cie_abc_complete(r_ptr(op, gs_cie_abc));
+ pop(1);
+ return 0;
+}
+
+private int cie_a_finish(P1(os_ptr));
+private int
+cs_install_zCIEA(gs_color_space *pcs, gs_state *pgs)
+{ es_ptr ep = esp;
+ gs_cie_a *pcie = pcs->params.a;
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code =
+ (*gs_color_space_type_CIEA.install_cspace)(pcs, pgs); /* former routine */
+ if ( code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_a_finish, pgs, pcie)) < 0 ||
+ (code = cie_prepare_cache(&pcie->RangeA, &pcprocs->Decode.A, &pcie->caches.DecodeA.floats, pcie, pgs, "Decode.A")) < 0 ||
+ (code = cache_common(&pcie->common, pcprocs, pcie, pgs)) < 0
+ )
+ { esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_a_finish(os_ptr op)
+{ gs_cie_a_complete(r_ptr(op, gs_cie_a));
+ pop(1);
+ return 0;
+}
+
+/* Common cache code */
+private int
+cache_common(gs_cie_common *pcie, const ref_cie_procs *pcprocs,
+ void *container, const gs_state *pgs)
+{ return cie_prepare_cache3(&pcie->RangeLMN,
+ pcprocs->DecodeLMN.value.const_refs,
+ &pcie->caches.DecodeLMN[0], container, pgs,
+ "Decode.LMN");
+}
+
+/* ------ Internal routines ------ */
+
+/* Prepare to cache the values for one or more procedures. */
+private int cie_cache_finish(P1(os_ptr));
+int
+cie_prepare_cache(const gs_range *domain, const ref *proc,
+ cie_cache_floats *pcache, void *container, const gs_state *pgs,
+ client_name_t cname)
+{ int space = imemory_space((gs_ref_memory_t *)gs_state_memory(pgs));
+ gs_for_loop_params flp;
+ register es_ptr ep;
+
+ check_estack(9);
+ ep = esp;
+ gs_cie_cache_init(&pcache->params, &flp, domain, cname);
+ pcache->params.is_identity = r_size(proc) == 0;
+ make_real(ep + 9, flp.init);
+ make_real(ep + 8, flp.step);
+ make_real(ep + 7, flp.limit);
+ ep[6] = *proc;
+ r_clear_attrs(ep + 6, a_executable);
+ make_op_estack(ep + 5, zcvx);
+ make_op_estack(ep + 4, zfor);
+ make_op_estack(ep + 3, cie_cache_finish);
+ /*
+ * The caches are embedded in the middle of other
+ * structures, so we represent the pointer to the cache
+ * as a pointer to the container plus an offset.
+ */
+ make_int(ep + 2, (char *)pcache - (char *)container);
+ make_struct(ep + 1, space, container);
+ esp += 9;
+ return o_push_estack;
+}
+private int
+cie_prepare_caches(const gs_range *domains, const ref *procs,
+ cie_cache_floats **ppc, int count, void *container, const gs_state *pgs,
+ client_name_t cname)
+{ int i, code = 0;
+ for ( i = 0; i < count; ++i )
+ if ( (code = cie_prepare_cache(domains + i, procs + i, ppc[i],
+ container, pgs, cname)) < 0
+ )
+ return code;
+ return code;
+}
+int
+cie_prepare_caches_3(const gs_range3 *domains, const ref *procs,
+ cie_cache_floats *pc0, cie_cache_floats *pc1, cie_cache_floats *pc2,
+ void *container, const gs_state *pgs, client_name_t cname)
+{ cie_cache_floats *pc3[3];
+ pc3[0] = pc0, pc3[1] = pc1, pc3[2] = pc2;
+ return cie_prepare_caches((const gs_range *)domains, procs, pc3, 3,
+ container, pgs, cname);
+}
+
+/* Store the result of caching one procedure. */
+private int
+cie_cache_finish(os_ptr op)
+{ cie_cache_floats *pcache;
+ int code;
+ check_esp(2);
+ /* See above for the container + offset representation of */
+ /* the pointer to the cache. */
+ pcache = (cie_cache_floats *)(r_ptr(esp - 1, char) + esp->value.intval);
+ code = float_params(op, gx_cie_cache_size, &pcache->values[0]);
+ if_debug3('c', "[c]cache 0x%lx base=%g, factor=%g:\n",
+ (ulong)pcache, pcache->params.base, pcache->params.factor);
+ if ( code < 0 )
+ { /* We might have underflowed the current stack block. */
+ /* Handle the parameters one-by-one. */
+ uint i;
+ for ( i = 0; i < gx_cie_cache_size; i++ )
+ { code = float_param(ref_stack_index(&o_stack,
+ gx_cie_cache_size - 1 - i),
+ &pcache->values[i]);
+ if ( code < 0 )
+ return code;
+ }
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('c') )
+ { int i;
+ for ( i = 0; i < gx_cie_cache_size; i += 4 )
+ dprintf5("[c] cache[%3d]=%g, %g, %g, %g\n", i,
+ pcache->values[i], pcache->values[i + 1],
+ pcache->values[i + 2], pcache->values[i + 3]);
+ }
+#endif
+ ref_stack_pop(&o_stack, gx_cie_cache_size);
+ esp -= 2; /* pop pointer to cache */
+ return o_pop_estack;
+}
+
+/* Push a finishing procedure on the e-stack. */
+/* ptr will be the top element of the o-stack. */
+int
+cie_cache_push_finish(int (*proc)(P1(os_ptr)), gs_state *pgs, void *ptr)
+{ check_estack(2);
+ push_op_estack(proc);
+ ++esp;
+ make_struct(esp, imemory_space((gs_ref_memory_t *)gs_state_memory(pgs)), ptr);
+ return o_push_estack;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcie_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1.setcieaspace", zsetcieaspace},
+ {"1.setcieabcspace", zsetcieabcspace},
+#ifdef NEW_CIE
+ {"1.setciedefspace", zsetciedefspace},
+ {"1.setciedefgspace", zsetciedefgspace},
+#endif
+ /* Internal operators */
+ {"1%cie_abc_finish", cie_abc_finish},
+ {"1%cie_a_finish", cie_a_finish},
+ {"0%cie_cache_finish", cie_cache_finish},
+END_OP_DEFS(zcie_init) }
diff --git a/gs/src/zcolor.c b/gs/src/zcolor.c
new file mode 100644
index 000000000..1add51042
--- /dev/null
+++ b/gs/src/zcolor.c
@@ -0,0 +1,242 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcolor.c */
+/* Color operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "iutil.h"
+#include "store.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "icolor.h"
+
+/* Import the 'for' operator */
+extern int
+ zfor_fraction(P1(os_ptr));
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Define the number of stack slots needed for zcolor_remap_one. */
+const int zcolor_remap_one_ostack = 4;
+const int zcolor_remap_one_estack = 3;
+
+/* - currentalpha <alpha> */
+private int
+zcurrentalpha(register os_ptr op)
+{ push(1);
+ make_real(op, gs_currentalpha(igs));
+ return 0;
+}
+
+/* - currentgray <gray> */
+private int
+zcurrentgray(register os_ptr op)
+{ push(1);
+ make_real(op, gs_currentgray(igs));
+ return 0;
+}
+
+/* - currentrgbcolor <red> <green> <blue> */
+private int
+zcurrentrgbcolor(register os_ptr op)
+{ float par[3];
+
+ gs_currentrgbcolor(igs, par);
+ push(3);
+ make_floats(op - 2, par, 3);
+ return 0;
+}
+
+/* - currenttransfer <proc> */
+private int
+zcurrenttransfer(register os_ptr op)
+{ push(1);
+ *op = istate->transfer_procs.colored.gray;
+ return 0;
+}
+
+/* - processcolors <int> - */
+/* Note: this is an undocumented operator that is not supported */
+/* in Level 2. */
+private int
+zprocesscolors(register os_ptr op)
+{ push(1);
+ make_int(op, gs_currentdevice(igs)->color_info.num_components);
+ return 0;
+}
+
+/* <alpha> setalpha - */
+private int
+zsetalpha(register os_ptr op)
+{ double alpha;
+ int code;
+
+ if ( real_param(op, &alpha) < 0 )
+ return_op_typecheck(op);
+ if ( (code = gs_setalpha(igs, alpha)) < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <gray> setgray - */
+private int
+zsetgray(register os_ptr op)
+{ double gray;
+ int code;
+
+ if ( real_param(op, &gray) < 0 )
+ return_op_typecheck(op);
+ if ( (code = gs_setgray(igs, gray)) < 0 )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(1);
+ return 0;
+}
+
+/* <red> <green> <blue> setrgbcolor - */
+private int
+zsetrgbcolor(register os_ptr op)
+{ double par[3];
+ int code;
+
+ if ( (code = num_params(op, 3, par)) < 0 ||
+ (code = gs_setrgbcolor(igs, par[0], par[1], par[2])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(3);
+ return 0;
+}
+
+/* <proc> settransfer - */
+private int
+zsettransfer(register os_ptr op)
+{ int code;
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ istate->transfer_procs.colored.red =
+ istate->transfer_procs.colored.green =
+ istate->transfer_procs.colored.blue =
+ istate->transfer_procs.colored.gray = *op;
+ code = gs_settransfer_remap(igs, gs_mapped_transfer, false);
+ if ( code < 0 ) return code;
+ push_op_estack(zcolor_reset_transfer);
+ pop(1); op--;
+ return zcolor_remap_one(&istate->transfer_procs.colored.gray, op,
+ igs->set_transfer.colored.gray, igs,
+ zcolor_remap_one_finish);
+}
+
+/* ------ Internal routines ------ */
+
+/* Prepare to remap one color component */
+/* (also used for black generation and undercolor removal). */
+/* Use the 'for' operator to gather the values. */
+/* The caller must have done the necessary check_ostack and check_estack. */
+int
+zcolor_remap_one(const ref *pproc, register os_ptr op, gx_transfer_map *pmap,
+ const gs_state *pgs, int (*finish_proc)(P1(os_ptr)))
+{ osp = op += 4;
+ make_int(op - 3, 0);
+ make_int(op - 2, 1);
+ make_int(op - 1, transfer_map_size - 1);
+ *op = *pproc;
+ ++esp;
+ make_struct(esp, imemory_space((gs_ref_memory_t *)pgs->memory),
+ pmap);
+ push_op_estack(finish_proc);
+ push_op_estack(zfor_fraction);
+ return o_push_estack;
+}
+
+/* Store the result of remapping a component. */
+private int
+zcolor_remap_one_store(os_ptr op, floatp min_value)
+{ int i;
+ gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
+ if ( ref_stack_count(&o_stack) < transfer_map_size )
+ return_error(e_stackunderflow);
+ for ( i = 0; i < transfer_map_size; i++ )
+ { double v;
+ int code =
+ real_param(ref_stack_index(&o_stack,
+ transfer_map_size - 1 - i),
+ &v);
+
+ if ( code < 0 )
+ return code;
+ pmap->values[i] =
+ (v < min_value ? float2frac(min_value) :
+ v >= 1.0 ? frac_1 :
+ float2frac(v));
+ }
+ ref_stack_pop(&o_stack, transfer_map_size);
+ esp--; /* pop pointer to transfer map */
+ return o_pop_estack;
+}
+int
+zcolor_remap_one_finish(os_ptr op)
+{ return zcolor_remap_one_store(op, 0.0);
+}
+int
+zcolor_remap_one_signed_finish(os_ptr op)
+{ return zcolor_remap_one_store(op, -1.0);
+}
+
+/* Finally, reset the effective transfer functions and */
+/* invalidate the current color. */
+int
+zcolor_reset_transfer(os_ptr op)
+{ gx_set_effective_transfer(igs);
+ return zcolor_remap_color(op);
+}
+int
+zcolor_remap_color(os_ptr op)
+{ gx_unset_dev_color(igs);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcolor_op_defs) {
+ {"0currentalpha", zcurrentalpha},
+ {"0currentgray", zcurrentgray},
+ {"0currentrgbcolor", zcurrentrgbcolor},
+ {"0currenttransfer", zcurrenttransfer},
+ {"0processcolors", zprocesscolors},
+ {"1setalpha", zsetalpha},
+ {"1setgray", zsetgray},
+ {"3setrgbcolor", zsetrgbcolor},
+ {"1settransfer", zsettransfer},
+ /* Internal operators */
+ {"1%zcolor_remap_one_finish", zcolor_remap_one_finish},
+ {"1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish},
+ {"0%zcolor_reset_transfer", zcolor_reset_transfer},
+ {"0%zcolor_remap_color", zcolor_remap_color},
+END_OP_DEFS(0) }
diff --git a/gs/src/zcolor1.c b/gs/src/zcolor1.c
new file mode 100644
index 000000000..d1662cf2f
--- /dev/null
+++ b/gs/src/zcolor1.c
@@ -0,0 +1,235 @@
+/* Copyright (C) 1993, 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcolor1.c */
+/* Level 1 extended color operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "iutil.h"
+#include "store.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gscolor1.h"
+#include "gxcspace.h"
+#include "icolor.h"
+#include "iimage.h"
+
+/* - currentblackgeneration <proc> */
+private int
+zcurrentblackgeneration(register os_ptr op)
+{ push(1);
+ *op = istate->black_generation;
+ return 0;
+}
+
+/* - currentcmykcolor <cyan> <magenta> <yellow> <black> */
+private int
+zcurrentcmykcolor(register os_ptr op)
+{ float par[4];
+
+ gs_currentcmykcolor(igs, par);
+ push(4);
+ make_floats(op - 3, par, 4);
+ return 0;
+}
+
+/* - currentcolortransfer <redproc> <greenproc> <blueproc> <grayproc> */
+private int
+zcurrentcolortransfer(register os_ptr op)
+{ push(4);
+ op[-3] = istate->transfer_procs.colored.red;
+ op[-2] = istate->transfer_procs.colored.green;
+ op[-1] = istate->transfer_procs.colored.blue;
+ *op = istate->transfer_procs.colored.gray;
+ return 0;
+}
+
+/* - currentundercolorremoval <proc> */
+private int
+zcurrentundercolorremoval(register os_ptr op)
+{ push(1);
+ *op = istate->undercolor_removal;
+ return 0;
+}
+
+/* <proc> setblackgeneration - */
+private int
+zsetblackgeneration(register os_ptr op)
+{ int code;
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ code = gs_setblackgeneration_remap(igs, gs_mapped_transfer, false);
+ if ( code < 0 )
+ return code;
+ istate->black_generation = *op;
+ pop(1); op--;
+ push_op_estack(zcolor_remap_color);
+ return zcolor_remap_one(&istate->black_generation, op,
+ igs->black_generation, igs,
+ zcolor_remap_one_finish);
+}
+
+/* <cyan> <magenta> <yellow> <black> setcmykcolor - */
+private int
+zsetcmykcolor(register os_ptr op)
+{ double par[4];
+ int code;
+
+ if ( (code = num_params(op, 4, par)) < 0 ||
+ (code = gs_setcmykcolor(igs, par[0], par[1], par[2], par[3])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(4);
+ return 0;
+}
+
+/* <redproc> <greenproc> <blueproc> <grayproc> setcolortransfer - */
+private int
+zsetcolortransfer(register os_ptr op)
+{ int code;
+ check_proc(op[-3]);
+ check_proc(op[-2]);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack * 4 - 4);
+ check_estack(1 + zcolor_remap_one_estack * 4);
+ istate->transfer_procs.colored.red = op[-3];
+ istate->transfer_procs.colored.green = op[-2];
+ istate->transfer_procs.colored.blue = op[-1];
+ istate->transfer_procs.colored.gray = *op;
+ if ( (code = gs_setcolortransfer_remap(igs,
+ gs_mapped_transfer, gs_mapped_transfer,
+ gs_mapped_transfer, gs_mapped_transfer,
+ false)) < 0
+ )
+ return code;
+ /* Use osp rather than op here, because zcolor_remap_one pushes. */
+ pop(4); op -= 4;
+ push_op_estack(zcolor_reset_transfer);
+ if ( (code = zcolor_remap_one(&istate->transfer_procs.colored.red,
+ osp, igs->set_transfer.colored.red, igs,
+ zcolor_remap_one_finish)) < 0 ||
+ (code = zcolor_remap_one(&istate->transfer_procs.colored.green,
+ osp, igs->set_transfer.colored.green, igs,
+ zcolor_remap_one_finish)) < 0 ||
+ (code = zcolor_remap_one(&istate->transfer_procs.colored.blue,
+ osp, igs->set_transfer.colored.blue, igs,
+ zcolor_remap_one_finish)) < 0
+ )
+ return code;
+ return zcolor_remap_one(&istate->transfer_procs.colored.gray,
+ osp, igs->set_transfer.colored.gray, igs,
+ zcolor_remap_one_finish);
+}
+
+/* <proc> setundercolorremoval - */
+private int
+zsetundercolorremoval(register os_ptr op)
+{ int code;
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ code = gs_setundercolorremoval_remap(igs, gs_mapped_transfer, false);
+ if ( code < 0 )
+ return code;
+ istate->undercolor_removal = *op;
+ pop(1); op--;
+ push_op_estack(zcolor_remap_color);
+ return zcolor_remap_one(&istate->undercolor_removal, op,
+ igs->undercolor_removal, igs,
+ zcolor_remap_one_signed_finish);
+}
+
+/* <width> <height> <bits/comp> <matrix> */
+/* <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> colorimage - */
+/* <datasrc> false <ncomp> colorimage - */
+#ifdef DPNEXT
+int zimage_multiple(P2(os_ptr op, bool has_alpha));
+#endif
+private int
+zcolorimage(register os_ptr op)
+{
+#ifdef DPNEXT
+ return zimage_multiple(op, false);
+}
+/* We export zimage_multiple for alphaimage. */
+int
+zimage_multiple(os_ptr op, bool has_alpha)
+{
+#endif
+ int spp; /* samples per pixel */
+ int npop = 7;
+ os_ptr procp = op - 2;
+ const gs_color_space *pcs;
+ bool multi = false;
+
+ check_int_leu(*op, 4); /* ncolors */
+ check_type(op[-1], t_boolean); /* multiproc */
+ switch ( (spp = (int)(op->value.intval)) )
+ {
+ case 1:
+ pcs = gs_color_space_DeviceGray();
+ break;
+ case 3:
+ pcs = gs_color_space_DeviceRGB();
+ goto color;
+ case 4:
+ pcs = gs_color_space_DeviceCMYK();
+color: if ( op[-1].value.boolval ) /* planar format */
+ {
+#ifdef DPNEXT
+ if ( has_alpha )
+ ++spp;
+#endif
+ npop += spp - 1;
+ procp -= spp - 1,
+ multi = true;
+ }
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ return zimage_opaque_setup(procp, multi,
+#ifdef DPNEXT
+ has_alpha,
+#endif
+ pcs, npop);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcolor1_op_defs) {
+ {"0currentblackgeneration", zcurrentblackgeneration},
+ {"0currentcmykcolor", zcurrentcmykcolor},
+ {"0currentcolortransfer", zcurrentcolortransfer},
+ {"0currentundercolorremoval", zcurrentundercolorremoval},
+ {"1setblackgeneration", zsetblackgeneration},
+ {"4setcmykcolor", zsetcmykcolor},
+ {"4setcolortransfer", zsetcolortransfer},
+ {"1setundercolorremoval", zsetundercolorremoval},
+ {"7colorimage", zcolorimage},
+END_OP_DEFS(0) }
diff --git a/gs/src/zcolor2.c b/gs/src/zcolor2.c
new file mode 100644
index 000000000..889b90f2e
--- /dev/null
+++ b/gs/src/zcolor2.c
@@ -0,0 +1,175 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcolor2.c */
+/* Level 2 color operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gsmatrix.h"
+#include "gsstruct.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h" /* for gxpcolor.h */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxpcolor.h */
+#include "gxpcolor.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "istruct.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Declare a local alias for st_pattern_instance. */
+/* We do this so we can have configurations with */
+/* the base Level 2 color machinery but without patterns. */
+gs_memory_type_ptr_t zcolor2_st_pattern_instance_p = 0;
+
+/* Forward references */
+private int store_color_params(P3(os_ptr, const gs_paint_color *, const gs_color_space *));
+private int load_color_params(P3(os_ptr, gs_paint_color *, const gs_color_space *));
+
+/* - currentcolor <param1> ... <paramN> */
+private int
+zcurrentcolor(register os_ptr op)
+{ const gs_client_color *pc = gs_currentcolor(igs);
+ const gs_color_space *pcs = gs_currentcolorspace(igs);
+ int n;
+ check_ostack(5); /* Worst case: CMYK + pattern */
+ if ( pcs->type->index == gs_color_space_index_Pattern )
+ { n = 1;
+ if ( pc->pattern != 0 && pc->pattern->template.PaintType == 2 ) /* uncolored */
+ n += store_color_params(op, &pc->paint,
+ (const gs_color_space *)&pcs->params.pattern.base_space);
+ op[n] = istate->pattern;
+ }
+ else
+ n = store_color_params(op, &pc->paint, pcs);
+ push(n);
+ return 0;
+}
+
+/* - .currentcolorspace <array|int> */
+private int
+zcurrentcolorspace(register os_ptr op)
+{ push(1);
+ if ( r_has_type(&istate->colorspace.array, t_null) )
+ { /* Return the color space index. */
+ /* This is only possible if the color was set by */
+ /* setgray, sethsb/rgbcolor, or setcmykcolor. */
+ make_int(op, (int)(gs_currentcolorspace(igs)->type->index));
+ }
+ else
+ *op = istate->colorspace.array;
+ return 0;
+}
+
+/* <param1> ... <paramN> setcolor - */
+private int
+zsetcolor(register os_ptr op)
+{ gs_client_color c;
+ const gs_color_space *pcs = gs_currentcolorspace(igs);
+ int n, code;
+ gs_pattern_instance *pinst = 0;
+ if ( pcs->type->index == gs_color_space_index_Pattern )
+ { /* Make sure *op is a real Pattern. */
+ ref *pImpl;
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ( dict_find_string(op, "Implementation", &pImpl) <= 0 ||
+ !r_has_stype(pImpl, imemory, *zcolor2_st_pattern_instance_p)
+ )
+ return_error(e_rangecheck);
+ pinst = r_ptr(pImpl, gs_pattern_instance);
+ c.pattern = pinst;
+ if ( pinst->template.PaintType == 2 ) /* uncolored */
+ { if ( !pcs->params.pattern.has_base_space )
+ return_error(e_rangecheck);
+ n = load_color_params(op - 1, &c.paint,
+ (const gs_color_space *)&pcs->params.pattern.base_space);
+ if ( n < 0 ) return n;
+ n++;
+ }
+ else
+ n = 1;
+ }
+ else
+ { n = load_color_params(op, &c.paint, pcs);
+ c.pattern = 0; /* for GC */
+ }
+ if ( n < 0 )
+ return n;
+ code = gs_setcolor(igs, &c);
+ if ( code < 0 )
+ return code;
+ if ( pinst != 0 )
+ istate->pattern = *op;
+ pop(n);
+ return code;
+}
+
+/* <array> .setcolorspace - */
+private int
+zsetcolorspace(register os_ptr op)
+{ check_type(*op, t_array);
+ istate->colorspace.array = *op;
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcolor2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"0currentcolor", zcurrentcolor},
+ {"0.currentcolorspace", zcurrentcolorspace},
+ {"1setcolor", zsetcolor},
+ {"1.setcolorspace", zsetcolorspace},
+END_OP_DEFS(0) }
+
+/* ------ Internal procedures ------ */
+
+/* Store non-pattern color values on the operand stack. */
+/* Return the number of values stored. */
+private int
+store_color_params(os_ptr op, const gs_paint_color *pc,
+ const gs_color_space *pcs)
+{ int n = pcs->type->num_components;
+ if ( pcs->type->index == gs_color_space_index_Indexed )
+ make_int(op + 1, (int)pc->values[0]);
+ else
+ make_floats(op + 1, pc->values, n);
+ return n;
+}
+
+/* Load non-pattern color values from the operand stack. */
+/* Return the number of values stored. */
+private int
+load_color_params(os_ptr op, gs_paint_color *pc,
+ const gs_color_space *pcs)
+{ int n = pcs->type->num_components;
+ int code = float_params(op, n, pc->values);
+
+ if ( code < 0 )
+ return code;
+ return n;
+}
diff --git a/gs/src/zcontext.c b/gs/src/zcontext.c
new file mode 100644
index 000000000..c570f54ce
--- /dev/null
+++ b/gs/src/zcontext.c
@@ -0,0 +1,709 @@
+/* Copyright (C) 1991, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcontext.c */
+/* Display PostScript context operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "gp.h" /* for usertime */
+#include "errors.h"
+#include "oper.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxalloc.h"
+#include "idict.h"
+#include "igstate.h"
+#include "icontext.h"
+#include "istruct.h"
+#include "dstack.h"
+#include "estack.h"
+#include "ostack.h"
+#include "store.h"
+
+/* Still needs:
+ fork: copy gstate stack
+ fork_done: do all necessary restores
+ */
+
+/* Scheduling hooks in interp.c */
+extern int (*gs_interp_reschedule_proc)(P0());
+extern int (*gs_interp_time_slice_proc)(P0());
+extern int gs_interp_time_slice_ticks;
+
+/* Per-context state stored in statics */
+extern ref ref_binary_object_format;
+
+/* Context state structure */
+/* (defined in icontext.h) */
+extern_st(st_ref_stack);
+private_st_context_state();
+#define pcst ((gs_context_state_t *)vptr)
+private ENUM_PTRS_BEGIN(context_state_enum_ptrs) return 0;
+ ENUM_REF(0, gs_context_state_t, dstack);
+ ENUM_REF(1, gs_context_state_t, estack);
+ ENUM_REF(2, gs_context_state_t, ostack);
+ ENUM_PTR(3, gs_context_state_t, pgs);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(context_state_reloc_ptrs) {
+ RELOC_REF(gs_context_state_t, dstack);
+ RELOC_REF(gs_context_state_t, estack);
+ RELOC_REF(gs_context_state_t, ostack);
+ RELOC_PTR(gs_context_state_t, pgs);
+} RELOC_PTRS_END
+#undef pcst
+
+/* Context structure */
+typedef enum {
+ cs_active,
+ cs_done
+} ctx_status;
+typedef struct gs_context_s gs_context;
+struct gs_context_s {
+ gs_context_state_t state; /* (must be first for subclassing) */
+ /* Private state */
+ ctx_status status;
+ ulong index;
+ bool detach; /* true if a detach has been */
+ /* executed for this context */
+ gs_context *next; /* next context with same status */
+ /* (active, waiting on same lock, */
+ /* waiting on same condition, */
+ /* waiting to be destroyed) */
+ gs_context *joiner; /* context waiting on a join */
+ /* for this one */
+ gs_context *table_next; /* hash table chain */
+};
+gs_private_st_suffix_add3(st_context, gs_context, "context",
+ context_enum_ptrs, context_reloc_ptrs, st_context_state,
+ next, joiner, table_next);
+
+/* Context list structure */
+typedef struct ctx_list_s {
+ gs_context *head;
+ gs_context *tail;
+} ctx_list;
+
+/* Condition structure */
+typedef struct gs_condition_s {
+ ctx_list waiting; /* contexts waiting on this condition */
+} gs_condition;
+gs_private_st_ptrs2(st_condition, gs_condition, "conditiontype",
+ condition_enum_ptrs, condition_reloc_ptrs, waiting.head, waiting.tail);
+
+/* Lock structure */
+typedef struct gs_lock_s {
+ ctx_list waiting; /* contexts waiting for this lock, */
+ /* must be first for subclassing */
+ gs_context *holder; /* context holding the lock, if any */
+} gs_lock;
+gs_private_st_suffix_add1(st_lock, gs_lock, "locktype",
+ lock_enum_ptrs, lock_reloc_ptrs, st_condition, holder);
+
+/* Global state */
+typedef struct gs_scheduler_s {
+ gs_context *current;
+ long usertime_initial; /* usertime when current started running */
+ ctx_list active;
+ gs_context *dead;
+#define ctx_table_size 19
+ gs_context *table[ctx_table_size];
+} gs_scheduler_t;
+private gs_scheduler_t *gs_scheduler;
+#define ctx_current gs_scheduler->current
+#define ctx_active gs_scheduler->active
+#define ctx_dead gs_scheduler->dead
+#define ctx_table gs_scheduler->table
+private gs_gc_root_t gs_scheduler_root;
+/* Structure definition */
+gs_private_st_composite(st_scheduler, gs_scheduler_t, "gs_scheduler",
+ scheduler_enum_ptrs, scheduler_reloc_ptrs);
+private ENUM_PTRS_BEGIN(scheduler_enum_ptrs) {
+ index -= 4;
+ if ( index < ctx_table_size )
+ ENUM_RETURN_PTR(gs_scheduler_t, table[index]);
+ return 0;
+}
+ ENUM_PTR(0, gs_scheduler_t, current);
+ ENUM_PTR(1, gs_scheduler_t, active.head);
+ ENUM_PTR(2, gs_scheduler_t, active.tail);
+ ENUM_PTR(3, gs_scheduler_t, dead);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(scheduler_reloc_ptrs) {
+ RELOC_PTR(gs_scheduler_t, current);
+ RELOC_PTR(gs_scheduler_t, active.head);
+ RELOC_PTR(gs_scheduler_t, active.tail);
+ RELOC_PTR(gs_scheduler_t, dead);
+ { int i;
+ for ( i = 0; i < ctx_table_size; ++i )
+ RELOC_PTR(gs_scheduler_t, table[i]);
+ }
+} RELOC_PTRS_END
+
+/* Forward references */
+private int context_create(P2(gs_context **, gs_ref_memory_t *));
+private long context_usertime(P0());
+#define context_load(psched, pctx)\
+ do {\
+ if ( (pctx)->state.keep_usertime )\
+ (psched)->usertime_initial = context_usertime();\
+ context_state_load(&(pctx)->state);\
+ } while (0)
+#define context_store(psched, pctx)\
+ do {\
+ context_state_store(&(pctx)->state);\
+ if ( (pctx)->state.keep_usertime )\
+ (pctx)->state.usertime_total +=\
+ context_usertime() - (psched)->usertime_initial;\
+ } while (0)
+private int context_param(P2(os_ptr, gs_context **));
+#define check_context(op, vpc)\
+ if ( (code = context_param(op, &vpc)) < 0 ) return code
+private void context_destroy(P1(gs_context *));
+private void stack_copy(P4(ref_stack *, const ref_stack *, uint, uint));
+private int lock_acquire(P1(os_ptr));
+private int lock_release(P1(ref *));
+
+/* List manipulation macros */
+#define add_last(pl,pc)\
+ (((pl)->head == 0 ? ((pl)->head = pc) : ((pl)->tail->next = pc)),\
+ (pl)->tail = pc, (pc)->next = 0)
+#define add_last_all(pl,pcl) /* pcl->head != 0 */\
+ (((pl)->head == 0 ? ((pl)->head = (pcl)->head) :\
+ ((pl)->tail->next = (pcl)->head)),\
+ (pl)->tail = (pcl)->tail, (pcl)->head = (pcl)->tail = 0)
+
+/* ------ Initialization ------ */
+
+private int ctx_reschedule(P0());
+private int ctx_time_slice(P0());
+private void
+zcontext_init(void)
+{ gs_ref_memory_t *imem = iimemory_global;
+
+ gs_scheduler = gs_alloc_struct((gs_memory_t *)imem, gs_scheduler_t,
+ &st_scheduler, "gs_scheduler");
+ gs_register_struct_root((gs_memory_t *)imem, &gs_scheduler_root,
+ (void **)&gs_scheduler, "gs_scheduler");
+ ctx_current = 0;
+ ctx_active.head = ctx_active.tail = 0;
+ ctx_dead = 0;
+ memset(ctx_table, 0, sizeof(ctx_table));
+ /* Create an initial context. */
+ if ( context_create(&ctx_current, imem) < 0 )
+ { lprintf("Can't create initial context!");
+ gs_abort();
+ }
+ ctx_current->state.memory = gs_imemory;
+ /* Hook into the interpreter. */
+ gs_interp_reschedule_proc = ctx_reschedule;
+ gs_interp_time_slice_proc = ctx_time_slice;
+ gs_interp_time_slice_ticks = 100;
+}
+
+/* ------ Interpreter interface to scheduler ------ */
+
+/* When an operator decides it is time to run a new context, */
+/* it returns o_reschedule. The interpreter saves all its state in */
+/* memory, calls ctx_reschedule, and then loads the state from memory. */
+private int
+ctx_reschedule(void)
+{ /* Save the state of the current context in ctx_current, */
+ /* if any context is current at all. */
+ if ( ctx_current != 0 )
+ context_store(gs_scheduler, ctx_current);
+ /* If there are any dead contexts waiting to be released, */
+ /* take care of that now. */
+ while ( ctx_dead != 0 )
+ { gs_context *next = ctx_dead->next;
+
+ context_destroy(ctx_dead);
+ ctx_dead = next;
+ }
+ /* Run the first ready context. */
+ if ( ctx_active.head == 0 )
+ { lprintf("No context to run!");
+ return_error(e_Fatal);
+ }
+ ctx_current = ctx_active.head;
+ if ( !(ctx_active.head = ctx_active.head->next) )
+ ctx_active.tail = 0;
+ /* Load the state of the new current context. */
+ context_load(gs_scheduler, ctx_current);
+ esfile_clear_cache();
+ dict_set_top(); /* reload dict stack cache */
+ return 0;
+}
+
+/* If the interpreter wants to time-slice, it saves its state, */
+/* calls ctx_time_slice, and reloads its state. */
+private int
+ctx_time_slice(void)
+{ if ( ctx_active.head == 0 )
+ return 0;
+ add_last(&ctx_active, ctx_current);
+ return ctx_reschedule();
+}
+
+/* ------ Context operators ------ */
+
+private int fork_done(P1(os_ptr));
+
+/* - currentcontext <context> */
+private int
+zcurrentcontext(register os_ptr op)
+{ push(1);
+ make_int(op, ctx_current->index);
+ return 0;
+}
+
+/* <context> detach - */
+private int
+zdetach(register os_ptr op)
+{ gs_context *pctx;
+ int code;
+
+ check_context(op, pctx);
+ if ( pctx->joiner != 0 || pctx->detach )
+ return_error(e_invalidcontext);
+ switch ( pctx->status )
+ {
+ case cs_active:
+ pctx->detach = true;
+ break;
+ case cs_done:
+ context_destroy(pctx);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <mark> <obj1> ... <objN> <proc> fork <context> */
+private int
+zfork(register os_ptr op)
+{ uint mcount = ref_stack_counttomark(&o_stack);
+ gs_context *pctx;
+ int code;
+
+ check_proc(*op);
+ if ( mcount == 0 )
+ return_error(e_unmatchedmark);
+ if ( gs_imemory.save_level )
+ return_error(e_invalidcontext);
+ code = context_create(&pctx, iimemory_global);
+ if ( code < 0 )
+ return code;
+ /* Share local and global VM. */
+ pctx->state.memory = gs_imemory;
+ { int i;
+ for ( i = 0; i < countof(gs_imemory.spaces.indexed); ++i )
+ if ( gs_imemory.spaces.indexed[i] != 0 )
+ gs_imemory.spaces.indexed[i]->num_contexts++;
+ }
+ /* Initialize the stacks. */
+ { ref_stack *dstack = r_ptr(&pctx->state.dstack, ref_stack);
+ uint count = ref_stack_count(&d_stack);
+
+ ref_stack_push(dstack, count - ref_stack_count(dstack));
+ stack_copy(dstack, &d_stack, count, 0);
+ }
+ { ref_stack *estack = r_ptr(&pctx->state.estack, ref_stack);
+
+ ref_stack_push(estack, 3);
+ /* fork_done must be executed in both normal and error cases. */
+ make_mark_estack(estack->p - 2, es_other, fork_done);
+ make_oper(estack->p - 1, 0, fork_done);
+ *estack->p = *op;
+ }
+ { ref_stack *ostack = r_ptr(&pctx->state.ostack, ref_stack);
+ uint count = mcount - 2;
+
+ ref_stack_push(ostack, count);
+ stack_copy(ostack, &o_stack, count, 1);
+ }
+ /****** COPY GSTATE STACK ******/
+ pctx->state.binary_object_format = ref_binary_object_format;
+ add_last(&ctx_active, pctx);
+ pop(mcount - 1);
+ op = osp;
+ make_int(op, pctx->index);
+ return 0;
+}
+/* This gets executed when a context terminates normally */
+/* or when the stack is being unwound for an error termination. */
+/****** MUST DO ALL RESTORES ******/
+/****** WHAT IF invalidrestore? ******/
+private int
+fork_done(os_ptr op)
+{ if ( ctx_current->detach )
+ { /*
+ * We can't free the context's memory yet, because the
+ * interpreter still has references to it. Instead, queue the
+ * context to be freed the next time we reschedule.
+ */
+ context_store(gs_scheduler, ctx_current);
+ ctx_current->next = ctx_dead;
+ ctx_dead = ctx_current;
+ ctx_current = 0;
+ }
+ else
+ { gs_context *pctx = ctx_current->joiner;
+
+ ctx_current->status = cs_done;
+ /* Schedule the context waiting to join this one, if any. */
+ if ( pctx != 0 )
+ add_last(&ctx_active, pctx);
+ }
+ return o_reschedule;
+}
+
+/* <context> join <mark> <obj1> ... <objN> */
+private int
+zjoin(register os_ptr op)
+{ gs_context *pctx;
+ int code;
+
+ check_context(op, pctx);
+ if ( pctx->joiner != 0 || pctx->detach || pctx == ctx_current ||
+ pctx->state.memory.space_global !=
+ ctx_current->state.memory.space_global ||
+ pctx->state.memory.space_local !=
+ ctx_current->state.memory.space_local ||
+ gs_imemory.save_level != 0
+ )
+ return_error(e_invalidcontext);
+ switch ( pctx->status )
+ {
+ case cs_active:
+ pctx->joiner = ctx_current;
+ return o_reschedule;
+ case cs_done:
+ { const ref_stack *ostack =
+ r_ptr(&pctx->state.ostack, ref_stack);
+ uint count = ref_stack_count(ostack);
+
+ push(count);
+ { ref *rp = ref_stack_index(&o_stack, count);
+ make_mark(rp);
+ }
+ stack_copy(&o_stack, ostack, count, 0);
+ context_destroy(pctx);
+ }
+ }
+ return 0;
+}
+
+/* - yield - */
+private int
+zyield(register os_ptr op)
+{ if ( ctx_active.head == 0 )
+ return 0;
+ add_last(&ctx_active, ctx_current);
+ return o_reschedule;
+}
+
+/* ------ Condition and lock operators ------ */
+
+private int
+ monitor_cleanup(P1(os_ptr)),
+ monitor_release(P1(os_ptr)),
+ await_lock(P1(os_ptr));
+
+/* - condition <condition> */
+private int
+zcondition(register os_ptr op)
+{ gs_condition *pcond =
+ ialloc_struct(gs_condition, &st_condition, "zcondition");
+
+ if ( pcond == 0 )
+ return_error(e_VMerror);
+ pcond->waiting.head = pcond->waiting.tail = 0;
+ push(1);
+ make_istruct(op, a_all, pcond);
+ return 0;
+}
+
+/* - lock <lock> */
+private int
+zlock(register os_ptr op)
+{ gs_lock *plock = ialloc_struct(gs_lock, &st_lock, "zlock");
+
+ if ( plock == 0 )
+ return_error(e_VMerror);
+ plock->holder = 0;
+ plock->waiting.head = plock->waiting.tail = 0;
+ push(1);
+ make_istruct(op, a_all, plock);
+ return 0;
+}
+
+/* <lock> <proc> monitor - */
+private int
+zmonitor(register os_ptr op)
+{ gs_lock *plock;
+ int code;
+
+ check_stype(op[-1], st_lock);
+ check_proc(*op);
+ plock = r_ptr(op - 1, gs_lock);
+ if ( plock->holder == ctx_current ||
+ (gs_imemory.save_level != 0 &&
+ plock->holder != 0 &&
+ plock->holder->state.memory.space_local ==
+ ctx_current->state.memory.space_local)
+ )
+ return_error(e_invalidcontext);
+ /*
+ * We push on the e-stack:
+ * The lock object
+ * An e-stack mark with monitor_cleanup, to release the lock
+ * in case of an error
+ * monitor_release, to release the lock in the normal case
+ * The procedure to execute
+ */
+ check_estack(4);
+ code = lock_acquire(op - 1);
+ if ( code != 0 )
+ { /* We didn't acquire the lock. Re-execute this later. */
+ push_op_estack(zmonitor);
+ return code; /* o_reschedule */
+ }
+ *++esp = op[-1];
+ push_mark_estack(es_other, monitor_cleanup);
+ push_op_estack(monitor_release);
+ *++esp = *op;
+ pop(2);
+ return code;
+}
+/* Release the monitor lock when unwinding for an error or exit. */
+private int
+monitor_cleanup(os_ptr op)
+{ int code = lock_release(esp);
+ --esp;
+ return code;
+}
+/* Release the monitor lock when the procedure completes. */
+private int
+monitor_release(os_ptr op)
+{ --esp;
+ return monitor_cleanup(op);
+}
+
+/* <condition> notify - */
+private int
+znotify(register os_ptr op)
+{ gs_condition *pcond;
+
+ check_stype(*op, st_condition);
+ pcond = r_ptr(op, gs_condition);
+ pop(1); op--;
+ if ( pcond->waiting.head == 0 ) /* nothing to do */
+ return 0;
+ add_last_all(&ctx_active, &pcond->waiting);
+ return zyield(op);
+}
+
+/* <lock> <condition> wait - */
+private int
+zwait(register os_ptr op)
+{ gs_lock *plock;
+ gs_condition *pcond;
+
+ check_stype(op[-1], st_lock);
+ plock = r_ptr(op - 1, gs_lock);
+ check_stype(*op, st_condition);
+ pcond = r_ptr(op, gs_condition);
+ if ( plock->holder != ctx_current ||
+ (gs_imemory.save_level != 0 &&
+ (r_space(op - 1) == avm_local || r_space(op) == avm_local))
+ )
+ return_error(e_invalidcontext);
+ check_estack(1);
+ lock_release(op - 1);
+ add_last(&pcond->waiting, ctx_current);
+ push_op_estack(await_lock);
+ return o_reschedule;
+}
+/* When the condition is signaled, wait for acquiring the lock. */
+private int
+await_lock(os_ptr op)
+{ int code = lock_acquire(op - 1);
+
+ if ( code == 0 )
+ { pop(2);
+ return code;
+ }
+ /* We didn't acquire the lock. Re-execute the wait. */
+ push_op_estack(await_lock);
+ return code; /* o_reschedule */
+}
+
+/* ------ Miscellaneous operators ------ */
+
+/* - usertime <int> */
+private int
+zusertime_context(register os_ptr op)
+{ long utime = context_usertime();
+
+ push(1);
+ if ( !ctx_current->state.keep_usertime ) {
+ /*
+ * This is the first time this context has executed usertime:
+ * we must track its execution time from now on.
+ */
+ gs_scheduler->usertime_initial = utime;
+ ctx_current->state.keep_usertime = true;
+ }
+ make_int(op, ctx_current->state.usertime_total + utime -
+ gs_scheduler->usertime_initial);
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Create a context. */
+private int
+context_create(gs_context **ppctx, gs_ref_memory_t *mem)
+{ gs_context *pctx;
+ int code;
+ long ctx_index;
+ gs_context **pte;
+
+ pctx = gs_alloc_struct((gs_memory_t *)mem, gs_context, &st_context,
+ "context_create");
+ if ( pctx == 0 )
+ return_error(e_VMerror);
+ code = context_state_alloc(&pctx->state, mem);
+ if ( code < 0 )
+ { gs_free_object((gs_memory_t *)mem, pctx, "context_create");
+ return code;
+ }
+ ctx_index = gs_next_ids(1);
+ pctx->status = cs_active;
+ pctx->index = ctx_index;
+ pctx->detach = false;
+ pctx->next = 0;
+ pctx->joiner = 0;
+ pte = &ctx_table[ctx_index % ctx_table_size];
+ pctx->table_next = *pte;
+ *pte = pctx;
+ *ppctx = pctx;
+ return 0;
+}
+
+/* Check a context ID. Note that we do not check for context validity. */
+private int
+context_param(os_ptr op, gs_context **ppctx)
+{ gs_context *pctx;
+ long index;
+
+ check_type(*op, t_integer);
+ index = op->value.intval;
+ if ( index < 0 )
+ return_error(e_invalidcontext);
+ pctx = ctx_table[index % ctx_table_size];
+ for ( ; ; pctx = pctx->table_next )
+ { if ( pctx == 0 )
+ return_error(e_invalidcontext);
+ if ( pctx->index == index )
+ break;
+ }
+ *ppctx = pctx;
+ return 0;
+}
+
+/* Read the usertime as a single value. */
+private long
+context_usertime(void)
+{ long secs_ns[2];
+
+ gp_get_usertime(secs_ns);
+ return secs_ns[0] * 1000 + secs_ns[1] / 1000000;
+}
+
+/* Destroy a context. */
+private void
+context_destroy(gs_context *pctx)
+{ gs_context **ppctx = &ctx_table[pctx->index % ctx_table_size];
+
+ while ( *ppctx != pctx )
+ ppctx = &(*ppctx)->table_next;
+ *ppctx = (*ppctx)->table_next;
+ context_state_free(&pctx->state, iimemory);
+ ifree_object(pctx, "context_destroy");
+}
+
+/* Copy the top elements of one stack to another. */
+/* Note that this does not push the elements: */
+/* the destination stack must have enough space preallocated. */
+private void
+stack_copy(ref_stack *to, const ref_stack *from, uint count, uint from_index)
+{ long i;
+
+ for ( i = (long)count - 1; i >= 0; --i )
+ *ref_stack_index(to, i) = *ref_stack_index(from, i + from_index);
+}
+
+/* Acquire a lock. Return 0 if acquired, o_reschedule if not. */
+private int
+lock_acquire(os_ptr op)
+{ gs_lock *plock = r_ptr(op, gs_lock);
+
+ if ( plock->holder == 0 )
+ { plock->holder = ctx_current;
+ return 0;
+ }
+ add_last(&plock->waiting, ctx_current);
+ return o_reschedule;
+}
+
+/* Release a lock. Return 0 if OK, e_invalidcontext if not. */
+private int
+lock_release(ref *op)
+{ gs_lock *plock = r_ptr(op, gs_lock);
+
+ if ( plock->holder == ctx_current )
+ { plock->holder = 0;
+ add_last_all(&ctx_active, &plock->waiting);
+ return 0;
+ }
+ return_error(e_invalidcontext);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcontext_op_defs) {
+ {"0condition", zcondition},
+ {"0currentcontext", zcurrentcontext},
+ {"1detach", zdetach},
+ {"2fork", zfork},
+ {"1join", zjoin},
+ {"0lock", zlock},
+ {"2monitor", zmonitor},
+ {"1notify", znotify},
+ {"2wait", zwait},
+ {"0yield", zyield},
+ /* Note that the following replace prior definitions */
+ /* in the indicated files: */
+ {"0usertime", zusertime_context}, /* zmisc.c */
+ /* Internal operators */
+ {"0%fork_done", fork_done},
+ {"0%monitor_cleanup", monitor_cleanup},
+ {"0%monitor_release", monitor_release},
+ {"2%await_lock", await_lock},
+END_OP_DEFS(zcontext_init) }
diff --git a/gs/src/zcontrol.c b/gs/src/zcontrol.c
new file mode 100644
index 000000000..bbf36e28e
--- /dev/null
+++ b/gs/src/zcontrol.c
@@ -0,0 +1,804 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcontrol.c */
+/* Control operators */
+#include "string_.h"
+#include "ghost.h"
+#include "stream.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "files.h"
+#include "ipacked.h"
+#include "iutil.h"
+#include "store.h"
+
+/* Make an invalid file object. */
+extern void make_invalid_file(P1(ref *)); /* in zfile.c */
+
+/* Forward references */
+private int no_cleanup(P1(os_ptr));
+private uint count_exec_stack(P1(os_ptr));
+private uint count_to_stopped(P1(long));
+
+/* See the comment in opdef.h for an invariant which allows */
+/* more efficient implementation of for, loop, and repeat. */
+
+/* <[test0 body0 ...]> .cond - */
+private int cond_continue(P1(os_ptr));
+private int
+zcond(register os_ptr op)
+{ es_ptr ep = esp;
+ /* Push the array on the e-stack and call the continuation. */
+ if ( !r_is_array(op) )
+ return_op_typecheck(op);
+ check_execute(*op);
+ if ( (r_size(op) & 1) != 0)
+ return_error(e_rangecheck);
+ if ( r_size(op) == 0 )
+ return zpop(op);
+ check_estack(3);
+ esp = ep += 3;
+ ref_assign(ep - 2, op); /* the cond body */
+ make_op_estack(ep - 1, cond_continue);
+ array_get(op, 0L, ep);
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+private int
+cond_continue(register os_ptr op)
+{ es_ptr ep = esp;
+ int code;
+ /* The top element of the e-stack is the remaining tail of */
+ /* the cond body. The top element of the o-stack should be */
+ /* the (boolean) result of the test that is the first element */
+ /* of the tail. */
+ check_type(*op, t_boolean);
+ if ( op->value.boolval )
+ { /* true */
+ array_get(ep, 1L, ep);
+ esfile_check_cache();
+ code = o_pop_estack;
+ }
+ else if ( r_size(ep) > 2 )
+ { /* false */
+ const ref_packed *elts = ep->value.packed;
+ check_estack(2);
+ r_dec_size(ep, 2);
+ elts = packed_next(elts);
+ elts = packed_next(elts);
+ ep->value.packed = elts;
+ array_get(ep, 0L, ep + 2);
+ make_op_estack(ep + 1, cond_continue);
+ esp = ep + 2;
+ esfile_check_cache();
+ code = o_push_estack;
+ }
+ else
+ { /* fall off end of cond */
+ esp = ep - 1;
+ code = o_pop_estack;
+ }
+ pop(1); /* get rid of the boolean */
+ return code;
+}
+
+/* <obj> exec - */
+int
+zexec(register os_ptr op)
+{ check_op(1);
+ if ( !r_has_attr(op, a_executable) )
+ return 0; /* literal object just gets pushed back */
+ check_estack(1);
+ ++esp;
+ ref_assign(esp, op);
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+
+/* <obj1> ... <objn> <n> .execn - */
+int
+zexecn(register os_ptr op)
+{ uint n, i;
+ es_ptr esp_orig;
+
+ check_int_leu(*op, max_uint - 1);
+ n = (uint)op->value.intval;
+ check_op(n + 1);
+ check_estack(n);
+ esp_orig = esp;
+ for ( i = 0; i < n; ++i )
+ { const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
+
+ /* Make sure this object is legal to execute. */
+ switch ( r_type(rp) )
+ {
+ case_types_with_access:
+ if ( !r_has_attr(rp, a_execute) &&
+ r_has_attr(rp, a_executable)
+ )
+ { esp = esp_orig;
+ return_error(e_invalidaccess);
+ }
+ default:
+ DO_NOTHING;
+ }
+ /* Executable nulls have a special meaning on the e-stack, */
+ /* so since they are no-ops, don't push them. */
+ if ( !r_has_type_attrs(rp, t_null, a_executable) )
+ { ++esp;
+ ref_assign(esp, rp);
+ }
+ }
+ esfile_check_cache();
+ pop(n + 1);
+ return o_push_estack;
+}
+
+/* <obj> superexec - */
+/* THIS IS NOT REALLY IMPLEMENTED YET. */
+private int
+zsuperexec(os_ptr op)
+{ return zexec(op);
+}
+
+/* <bool> <proc> if - */
+int
+zif(register os_ptr op)
+{ check_type(op[-1], t_boolean);
+ check_proc(*op);
+ if ( op[-1].value.boolval )
+ { check_estack(1);
+ ++esp;
+ ref_assign(esp, op);
+ esfile_check_cache();
+ }
+ pop(2);
+ return o_push_estack;
+}
+
+/* <bool> <proc_true> <proc_false> ifelse - */
+int
+zifelse(register os_ptr op)
+{ check_type(op[-2], t_boolean);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_estack(1);
+ ++esp;
+ if ( op[-2].value.boolval )
+ { ref_assign(esp, op - 1);
+ }
+ else
+ { ref_assign(esp, op);
+ }
+ esfile_check_cache();
+ pop(3);
+ return o_push_estack;
+}
+
+/* <init> <step> <limit> <proc> for - */
+private int
+ for_pos_int_continue(P1(os_ptr)),
+ for_neg_int_continue(P1(os_ptr)),
+ for_real_continue(P1(os_ptr));
+int
+zfor(register os_ptr op)
+{ register es_ptr ep;
+ check_estack(7);
+ ep = esp + 6;
+ check_proc(*op);
+ /* Push a mark, the control variable, the initial value, */
+ /* the increment, the limit, and the procedure, */
+ /* and invoke the continuation operator. */
+ if ( r_has_type(op - 3, t_integer) &&
+ r_has_type(op - 2, t_integer)
+ )
+ { make_int(ep - 4, op[-3].value.intval);
+ make_int(ep - 3, op[-2].value.intval);
+ switch ( r_type(op - 1) )
+ {
+ case t_integer:
+ make_int(ep - 2, op[-1].value.intval);
+ break;
+ case t_real:
+ make_int(ep - 2, (long)op[-1].value.realval);
+ break;
+ default:
+ return_op_typecheck(op - 1);
+ }
+ if ( ep[-3].value.intval >= 0 )
+ make_op_estack(ep, for_pos_int_continue);
+ else
+ make_op_estack(ep, for_neg_int_continue);
+ }
+ else
+ { float params[3];
+ int code;
+
+ if ( (code = float_params(op - 1, 3, params)) < 0 )
+ return code;
+ make_real(ep - 4, params[0]);
+ make_real(ep - 3, params[1]);
+ make_real(ep - 2, params[2]);
+ make_op_estack(ep, for_real_continue);
+ }
+ make_mark_estack(ep - 5, es_for, no_cleanup);
+ ref_assign(ep - 1, op);
+ esp = ep;
+ pop(4);
+ return o_push_estack;
+}
+/* Continuation operators for for, separate for positive integer, */
+/* negative integer, and real. */
+/* Execution stack contains mark, control variable, increment, */
+/* limit, and procedure (procedure is topmost.) */
+/* Continuation operator for positive integers. */
+private int
+for_pos_int_continue(register os_ptr op)
+{ register es_ptr ep = esp;
+ long var = ep[-3].value.intval;
+ if ( var > ep[-1].value.intval )
+ { esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ make_int(op, var);
+ ep[-3].value.intval = var + ep[-2].value.intval;
+ ref_assign_inline(ep + 2, ep); /* saved proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+/* Continuation operator for negative integers. */
+private int
+for_neg_int_continue(register os_ptr op)
+{ register es_ptr ep = esp;
+ long var = ep[-3].value.intval;
+ if ( var < ep[-1].value.intval )
+ { esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ make_int(op, var);
+ ep[-3].value.intval = var + ep[-2].value.intval;
+ ref_assign(ep + 2, ep); /* saved proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+/* Continuation operator for reals. */
+private int
+for_real_continue(register os_ptr op)
+{ es_ptr ep = esp;
+ float var = ep[-3].value.realval;
+ float incr = ep[-2].value.realval;
+ if ( incr >= 0 ? (var > ep[-1].value.realval) :
+ (var < ep[-1].value.realval)
+ )
+ { esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ ref_assign(op, ep - 3);
+ ep[-3].value.realval = var + incr;
+ esp = ep + 2;
+ ref_assign(ep + 2, ep); /* saved proc */
+ return o_push_estack;
+}
+
+/* Here we provide an internal variant of 'for' that enumerates the */
+/* values 0, 1/N, 2/N, ..., 1 precisely. The arguments must be */
+/* the integers 0, 1, and N. We need this for */
+/* loading caches such as the transfer function cache. */
+private int for_fraction_continue(P1(os_ptr));
+int
+zfor_fraction(register os_ptr op)
+{ int code = zfor(op);
+ if ( code < 0 ) return code; /* shouldn't ever happen! */
+ make_op_estack(esp, for_fraction_continue);
+ return code;
+}
+/* Continuation procedure */
+private int
+for_fraction_continue(register os_ptr op)
+{ register es_ptr ep = esp;
+ int code = for_pos_int_continue(op);
+ if ( code != o_push_estack )
+ return code;
+ /* We must use osp instead of op here, because */
+ /* for_pos_int_continue pushes a value on the o-stack. */
+ make_real(osp, (float)osp->value.intval / ep[-1].value.intval);
+ return code;
+}
+
+/* <int> <proc> repeat - */
+private int repeat_continue(P1(os_ptr));
+private int
+zrepeat(register os_ptr op)
+{ check_type(op[-1], t_integer);
+ check_proc(*op);
+ if ( op[-1].value.intval < 0 )
+ return_error(e_rangecheck);
+ check_estack(5);
+ /* Push a mark, the count, and the procedure, and invoke */
+ /* the continuation operator. */
+ push_mark_estack(es_for, no_cleanup);
+ *++esp = op[-1];
+ *++esp = *op;
+ make_op_estack(esp + 1, repeat_continue);
+ pop(2);
+ return repeat_continue(op - 2);
+}
+/* Continuation operator for repeat */
+private int
+repeat_continue(register os_ptr op)
+{ es_ptr ep = esp; /* saved proc */
+ if ( --(ep[-1].value.intval) >= 0 ) /* continue */
+ { esp += 2;
+ ref_assign(esp, ep);
+ return o_push_estack;
+ }
+ else /* done */
+ { esp -= 3; /* pop mark, count, proc */
+ return o_pop_estack;
+ }
+}
+
+/* <proc> loop */
+private int loop_continue(P1(os_ptr));
+private int
+zloop(register os_ptr op)
+{ check_proc(*op);
+ check_estack(4);
+ /* Push a mark and the procedure, and invoke */
+ /* the continuation operator. */
+ push_mark_estack(es_for, no_cleanup);
+ *++esp = *op;
+ make_op_estack(esp + 1, loop_continue);
+ pop(1);
+ return loop_continue(op - 1);
+}
+/* Continuation operator for loop */
+private int
+loop_continue(register os_ptr op)
+{ register es_ptr ep = esp; /* saved proc */
+ ref_assign(ep + 2, ep);
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* - exit - */
+private int
+zexit(register os_ptr op)
+{ uint scanned = 0;
+ STACK_LOOP_BEGIN(&e_stack, ep, used)
+ { uint count = used;
+ ep += used - 1;
+ for ( ; count; count--, ep-- )
+ if ( r_is_estack_mark(ep) )
+ switch ( estack_mark_index(ep) )
+ {
+ case es_for:
+ pop_estack(scanned + (used - count + 1));
+ return o_pop_estack;
+ case es_stopped:
+ return_error(e_invalidexit); /* not a loop */
+ }
+ scanned += used;
+ }
+ STACK_LOOP_END(ep, used)
+ /* Return e_invalidexit if there is no mark at all. */
+ /* This is different from PostScript, which aborts. */
+ /* It shouldn't matter in practice. */
+ return_error(e_invalidexit);
+}
+
+/*
+ * .stopped pushes the following on the e-stack:
+ * - A mark with type = es_stopped and procedure = no_cleanup.
+ * - The result to be pushed on a normal return.
+ * - The signal mask for .stop.
+ * - The procedure %stopped_push, to handle the normal return case.
+ */
+
+/* In the normal (no-error) case, pop the mask from the e-stack, */
+/* and move the result to the o-stack. */
+private int
+stopped_push(register os_ptr op)
+{ push(1);
+ *op = esp[-1];
+ esp -= 3;
+ return o_pop_estack;
+}
+
+/* - stop - */
+/* Equivalent to true 1 .stop. */
+/* This is implemented in C because if were a pseudo-operator, */
+/* the stacks would get restored in case of an error. */
+private int
+zstop(register os_ptr op)
+{ uint count = count_to_stopped(1L);
+
+ if ( count )
+ { /*
+ * If there are any t_oparrays on the e-stack, they will pop
+ * any new items from the o-stack. Wait to push the 'true'
+ * until we have run all the unwind procedures.
+ */
+ check_ostack(2);
+ pop_estack(count);
+ op = osp;
+ push(1);
+ make_true(op);
+ return o_pop_estack;
+ }
+ /* Return e_invalidexit if there is no mark at all. */
+ /* This is different from PostScript, which aborts. */
+ /* It shouldn't matter in practice. */
+ return_error(e_invalidexit);
+}
+
+/* <result> <mask> .stop - */
+private int
+zzstop(register os_ptr op)
+{ uint count;
+
+ check_type(*op, t_integer);
+ count = count_to_stopped(op->value.intval);
+ if ( count )
+ { /*
+ * If there are any t_oparrays on the e-stack, they will pop
+ * any new items from the o-stack. Wait to push the result
+ * until we have run all the unwind procedures.
+ */
+ ref save_result;
+
+ check_op(2);
+ save_result = op[-1];
+ pop(2);
+ pop_estack(count);
+ op = osp;
+ push(1);
+ *op = save_result;
+ return o_pop_estack;
+ }
+ /* Return e_invalidexit if there is no mark at all. */
+ /* This is different from PostScript, which aborts. */
+ /* It shouldn't matter in practice. */
+ return_error(e_invalidexit);
+}
+
+/* <obj> stopped <stopped> */
+/* Equivalent to false 1 .stopped. */
+/* This is implemented in C because if were a pseudo-operator, */
+/* the stacks would get restored in case of an error. */
+private int
+zstopped(register os_ptr op)
+{ check_op(1);
+ /* Mark the execution stack, and push the default result */
+ /* in case control returns normally. */
+ check_estack(5);
+ push_mark_estack(es_stopped, no_cleanup);
+ ++esp;
+ make_false(esp); /* save the result */
+ ++esp;
+ make_int(esp, 1); /* save the signal mask */
+ push_op_estack(stopped_push);
+ *++esp = *op; /* execute the operand */
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+
+/* <obj> <result> <mask> .stopped <result> */
+private int
+zzstopped(register os_ptr op)
+{ check_type(*op, t_integer);
+ check_op(3);
+ /* Mark the execution stack, and push the default result */
+ /* in case control returns normally. */
+ check_estack(5);
+ push_mark_estack(es_stopped, no_cleanup);
+ *++esp = op[-1]; /* save the result */
+ *++esp = *op; /* save the signal mask */
+ push_op_estack(stopped_push);
+ *++esp = op[-2]; /* execute the operand */
+ esfile_check_cache();
+ pop(3);
+ return o_push_estack;
+}
+
+/* <mask> .instopped false */
+/* <mask> .instopped <result> true */
+private int
+zinstopped(register os_ptr op)
+{ uint count;
+
+ check_type(*op, t_integer);
+ count = count_to_stopped(op->value.intval);
+ if ( count )
+ { push(1);
+ op[-1] = *ref_stack_index(&e_stack, count - 2); /* default result */
+ make_true(op);
+ }
+ else
+ make_false(op);
+ return 0;
+}
+
+/* <include_marks> .countexecstack <int> */
+private int
+zcountexecstack(register os_ptr op)
+{ check_type(*op, t_boolean);
+ make_int(op, count_exec_stack(op));
+ return 0;
+}
+
+/* <array> <include_marks> .execstack <subarray> */
+private int execstack_continue(P1(os_ptr));
+private int
+zexecstack(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ uint size;
+ /*
+ * We can't do this directly, because the interpreter
+ * might have cached some state. To force the interpreter
+ * to update the stored state, we push a continuation on
+ * the exec stack; the continuation is executed immediately,
+ * and does the actual transfer.
+ */
+ uint depth;
+
+ check_type(*op, t_boolean);
+ check_write_type(*op1, t_array);
+ size = r_size(op1);
+ depth = count_exec_stack(op);
+ if ( depth > size )
+ return_error(e_rangecheck);
+ { int code = ref_stack_store_check(&e_stack, op1, size, 0);
+ if ( code < 0 )
+ return code;
+ }
+ check_estack(1);
+ r_set_size(op1, depth);
+ push_op_estack(execstack_continue);
+ return o_push_estack;
+}
+/* Continuation operator to do the actual transfer. */
+/* r_size(op - 1) was set just above. */
+private int
+execstack_continue(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ ref *arefs = op1->value.refs;
+ uint asize = r_size(op1);
+ uint i;
+ ref *rq;
+
+ /*
+ * Copy elements from the stack to the array,
+ * optionally skipping executable nulls.
+ * Clear the executable bit in any internal operators, and
+ * convert t_structs and t_astructs (which can only appear
+ * in connection with stack marks, which means that they will
+ * probably be freed when unwinding) to something harmless.
+ */
+ for ( i = 0, rq = arefs + asize; rq != arefs; ++i )
+ { const ref *rp = ref_stack_index(&e_stack, (long)i);
+
+ if ( r_has_type_attrs(rp, t_null, a_executable) &&
+ !op->value.boolval
+ )
+ continue;
+ --rq;
+ ref_assign_old(op1, rq, rp, "execstack");
+ switch ( r_type(rq) )
+ {
+ case t_operator:
+ { uint opidx = op_index(rq);
+ if ( opidx == 0 || op_def_is_internal(op_def_table[opidx]) )
+ r_clear_attrs(rq, a_executable);
+ }
+ break;
+ case t_struct:
+ case t_astruct:
+ { const char *tname =
+ gs_struct_type_name_string(
+ gs_object_type(imemory, rq->value.pstruct));
+ make_const_string(rq, a_readonly | avm_foreign,
+ strlen(tname), (const byte *)tname);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* - .needinput - */
+private int
+zneedinput(register os_ptr op)
+{ return e_NeedInput; /* interpreter will exit to caller */
+}
+
+/* <obj> <int> .quit - */
+private int
+zquit(register os_ptr op)
+{ check_op(2);
+ check_type(*op, t_integer);
+ return e_Quit; /* Interpreter will do the exit */
+}
+
+/* - currentfile <file> */
+private ref *zget_current_file(P0());
+private int
+zcurrentfile(register os_ptr op)
+{ ref *fp;
+ push(1);
+ /* Check the cache first */
+ if ( esfile != 0 )
+ {
+#ifdef DEBUG
+ /* Check that esfile is valid. */
+ ref *efp = zget_current_file();
+ if ( esfile != efp )
+ { lprintf2("currentfile: esfile=0x%lx, efp=0x%lx\n",
+ (ulong)esfile, (ulong)efp);
+ ref_assign(op, efp);
+ }
+ else
+#endif
+ ref_assign(op, esfile);
+ }
+ else if ( (fp = zget_current_file()) == 0 )
+ { /* Return an invalid file object. */
+ /* This doesn't make a lot of sense to me, */
+ /* but it's what the PostScript manual specifies. */
+ make_invalid_file(op);
+ }
+ else
+ { ref_assign(op, fp);
+ esfile_set_cache(fp);
+ }
+ /* Make the returned value literal. */
+ r_clear_attrs(op, a_executable);
+ return 0;
+}
+/* Get the current file from which the interpreter is reading. */
+private ref *
+zget_current_file(void)
+{ STACK_LOOP_BEGIN(&e_stack, ep, used)
+ { uint count = used;
+ ep += used - 1;
+ for ( ; count; count--, ep-- )
+ if ( r_has_type_attrs(ep, t_file, a_executable) )
+ return ep;
+ }
+ STACK_LOOP_END(ep, used)
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcontrol_op_defs) {
+ {"1.cond", zcond},
+ {"1.countexecstack", zcountexecstack},
+ {"0currentfile", zcurrentfile},
+ {"1exec", zexec},
+ {"1.execn", zexecn},
+ {"2.execstack", zexecstack},
+ {"0exit", zexit},
+ {"2if", zif},
+ {"3ifelse", zifelse},
+ {"0.instopped", zinstopped},
+ {"0.needinput", zneedinput},
+ {"4for", zfor},
+ {"1loop", zloop},
+ {"2.quit", zquit},
+ {"2repeat", zrepeat},
+ {"0stop", zstop},
+ {"1.stop", zzstop},
+ {"1stopped", zstopped},
+ {"2.stopped", zzstopped},
+ /* Internal operators */
+ {"1%cond_continue", cond_continue},
+ {"2%execstack_continue", execstack_continue},
+ {"0%for_pos_int_continue", for_pos_int_continue},
+ {"0%for_neg_int_continue", for_neg_int_continue},
+ {"0%for_real_continue", for_real_continue},
+ {"4%for_fraction", zfor_fraction},
+ {"0%for_fraction_continue", for_fraction_continue},
+ {"0%loop_continue", loop_continue},
+ {"0%repeat_continue", repeat_continue},
+ {"0%stopped_push", stopped_push},
+ /* Operators defined in internaldict */
+ op_def_begin_dict("internaldict"),
+ {"1superexec", zsuperexec},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Vacuous cleanup routine */
+private int
+no_cleanup(os_ptr op)
+{ return 0;
+}
+
+/*
+ * Count the number of elements on the exec stack, with or without
+ * the normally invisible elements (*op is a Boolean that indicates this).
+ */
+private uint
+count_exec_stack(os_ptr op)
+{ uint count = ref_stack_count(&e_stack);
+
+ if ( !op->value.boolval )
+ { uint i;
+ for ( i = count; i--; )
+ if ( r_has_type_attrs(ref_stack_index(&e_stack, (long)i),
+ t_null, a_executable) )
+ --count;
+ }
+ return count;
+}
+
+/*
+ * Count the number of elements down to and including the first 'stopped'
+ * mark on the e-stack with a given mask. Return 0 if there is no 'stopped'
+ * mark.
+ */
+private uint
+count_to_stopped(long mask)
+{ uint scanned = 0;
+ STACK_LOOP_BEGIN(&e_stack, ep, used)
+ { uint count = used;
+ ep += used - 1;
+ for ( ; count; count--, ep-- )
+ if ( r_is_estack_mark(ep) &&
+ estack_mark_index(ep) == es_stopped &&
+ (ep[2].value.intval & mask) != 0
+ )
+ return scanned + (used - count + 1);
+ scanned += used;
+ }
+ STACK_LOOP_END(ep, used)
+ return 0;
+}
+
+/* Pop the e-stack, executing cleanup procedures as needed. */
+/* We could make this more efficient using the STACK_LOOP macros, */
+/* but it isn't used enough to make this worthwhile. */
+void
+pop_estack(uint count)
+{ uint idx = 0;
+ uint popped = 0;
+
+ esfile_clear_cache();
+ for ( ; idx < count; idx++ )
+ { ref *ep = ref_stack_index(&e_stack, idx - popped);
+
+ if ( r_is_estack_mark(ep) )
+ { ref_stack_pop(&e_stack, idx + 1 - popped);
+ popped = idx + 1;
+ (*real_opproc(ep))(osp);
+ }
+ }
+ ref_stack_pop(&e_stack, count - popped);
+}
diff --git a/gs/src/zcrd.c b/gs/src/zcrd.c
new file mode 100644
index 000000000..3fce6307f
--- /dev/null
+++ b/gs/src/zcrd.c
@@ -0,0 +1,311 @@
+/* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcrd.c */
+/* CIE color rendering operators */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gscie.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icie.h"
+#include "isave.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_null */
+
+/* Forward references */
+private int zcrd_params(P4(os_ptr, gs_cie_render *, ref_cie_render_procs *, gs_memory_t *));
+private int cache_colorrendering(P3(gs_cie_render *,
+ const ref_cie_render_procs *, gs_state *));
+
+/* Allocator structure type for CIE rendering structure */
+private_st_cie_render();
+
+/* - currentcolorrendering <dict> */
+private int
+zcurrentcolorrendering(register os_ptr op)
+{ push(1);
+ *op = istate->colorrendering.dict;
+ return 0;
+}
+
+/* <dict> setcolorrendering - */
+private int
+zsetcolorrendering(register os_ptr op)
+{ gs_memory_t *mem = gs_state_memory(igs);
+ int code;
+ es_ptr ep = esp;
+ gs_cie_render *pcie;
+ ref_cie_render_procs procs_old;
+
+ check_read_type(*op, t_dictionary);
+ check_dict_read(*op);
+ rc_alloc_struct_0(pcie, gs_cie_render, &st_cie_render, mem,
+ return_error(e_VMerror),
+ "setcolorrendering");
+ /* gs_setcolorrendering may refer to istate->colorrendering.procs. */
+ procs_old = istate->colorrendering.procs;
+ code = zcrd_params(op, pcie, &istate->colorrendering.procs, mem);
+ if ( code < 0 ||
+ (code = gs_setcolorrendering(igs, pcie)) < 0 ||
+ (code = cache_colorrendering(pcie, &istate->colorrendering.procs, igs)) < 0
+ )
+ { rc_free_struct(pcie, "setcolorrendering");
+ istate->colorrendering.procs = procs_old;
+ esp = ep;
+ return code;
+ }
+ istate->colorrendering.dict = *op;
+ pop(1);
+ return (esp == ep ? 0 : o_push_estack);
+}
+/* Get the CRD parameters from the PostScript dictionary. */
+private int
+zcrd_params(os_ptr op, gs_cie_render *pcie,
+ ref_cie_render_procs *pcprocs, gs_memory_t *mem)
+{ int code;
+ int ignore;
+ ref *pRT;
+
+ if ( (code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixLMN", &pcie->MatrixLMN)) != matrix3_ok ||
+ (code = dict_proc3_param(op, "EncodeLMN", &pcprocs->EncodeLMN)) < 0 ||
+ (code = dict_range3_param(op, "RangeLMN", &pcie->RangeLMN)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixABC", &pcie->MatrixABC)) != matrix3_ok ||
+ (code = dict_proc3_param(op, "EncodeABC", &pcprocs->EncodeABC)) < 0 ||
+ (code = dict_range3_param(op, "RangeABC", &pcie->RangeABC)) < 0 ||
+ (code = cie_points_param(op, &pcie->points)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixPQR", &pcie->MatrixPQR)) != matrix3_ok ||
+ (code = dict_range3_param(op, "RangePQR", &pcie->RangePQR)) < 0 ||
+ (code = dict_proc3_param(op, "TransformPQR", &pcprocs->TransformPQR)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+#define rRT pcie->RenderTable.lookup
+ if ( dict_find_string(op, "RenderTable", &pRT) > 0 )
+ { const ref *prte;
+ int i;
+
+ check_read_type(*pRT, t_array);
+ if ( r_size(pRT) < 5 )
+ return_error(e_rangecheck);
+ prte = pRT->value.const_refs;
+ check_type_only(prte[4], t_integer);
+ if ( !(prte[4].value.intval == 3 || prte[4].value.intval == 4) )
+ return_error(e_rangecheck);
+ rRT.n = 3;
+ rRT.m = prte[4].value.intval;
+ if ( r_size(pRT) != rRT.m + 5 )
+ return_error(e_rangecheck);
+ prte += 5;
+ for ( i = 0; i < rRT.m; i++ )
+ check_proc_only(prte[i]);
+ code = cie_table_param(pRT, &rRT, mem);
+ if ( code < 0 )
+ return code;
+ make_const_array(&pcprocs->RenderTableT,
+ a_readonly | r_space(pRT),
+ rRT.m, prte);
+ }
+ else
+ { rRT.table = 0;
+ make_null(&pcprocs->RenderTableT);
+ }
+#undef rRT
+ pcie->EncodeLMN = Encode_default;
+ pcie->EncodeABC = Encode_default;
+ pcie->TransformPQR = TransformPQR_default;
+ pcie->RenderTable.T = RenderTableT_default;
+ return 0;
+}
+
+/* Cache the results of the color rendering procedures. */
+private int cie_cache_render_finish(P1(os_ptr));
+private int
+cache_colorrendering(gs_cie_render *pcie,
+ const ref_cie_render_procs *pcrprocs, gs_state *pgs)
+{ es_ptr ep = esp;
+ int code = gs_cie_render_init(pcie); /* sets Domain values */
+ int i;
+
+ /* We must run gs_cie_render_complete when we're done. */
+ if ( code < 0 ||
+ (gs_cie_cs_common(pgs) != 0 &&
+ (code = cie_cache_joint(pcrprocs, pgs)) < 0) || /* do this last */
+ (code = cie_cache_push_finish(cie_cache_render_finish, pgs, pcie)) < 0 ||
+ (code = cie_prepare_cache3(&pcie->DomainLMN, pcrprocs->EncodeLMN.value.const_refs, &pcie->caches.EncodeLMN[0], pcie, pgs, "Encode.LMN")) < 0 ||
+ (code = cie_prepare_cache3(&pcie->DomainABC, pcrprocs->EncodeABC.value.const_refs, &pcie->caches.EncodeABC[0], pcie, pgs, "Encode.ABC")) < 0
+ )
+ { esp = ep;
+ return code;
+ }
+ if ( pcie->RenderTable.lookup.table != 0 )
+ { bool is_identity = true;
+ for ( i = 0; i < pcie->RenderTable.lookup.m; i++ )
+ if ( r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0 )
+ { is_identity = false;
+ break;
+ }
+ pcie->caches.RenderTableT_is_identity = is_identity;
+ if ( !is_identity )
+ for ( i = 0; i < pcie->RenderTable.lookup.m; i++ )
+ if ( (code =
+ cie_prepare_cache(Range4_default.ranges,
+ pcrprocs->RenderTableT.value.const_refs + i,
+ &pcie->caches.RenderTableT[i].floats,
+ pcie, pgs, "RenderTable.T")) < 0
+ )
+ { esp = ep;
+ return code;
+ }
+ }
+ return o_push_estack;
+}
+
+/* Finish up after loading the rendering caches. */
+private int
+cie_cache_render_finish(os_ptr op)
+{ gs_cie_render *pcie = r_ptr(op, gs_cie_render);
+ int code;
+ if ( pcie->RenderTable.lookup.table != 0 && !pcie->caches.RenderTableT_is_identity )
+ { /* Convert the RenderTableT cache from floats to fracs. */
+ int j;
+ for ( j = 0; j < pcie->RenderTable.lookup.m; j++ )
+ gs_cie_cache_to_fracs(&pcie->caches.RenderTableT[j]);
+ }
+ code = gs_cie_render_complete(pcie);
+ if ( code < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Load the joint caches. */
+private int
+ cie_exec_tpqr(P1(os_ptr)),
+ cie_post_exec_tpqr(P1(os_ptr)),
+ cie_tpqr_finish(P1(os_ptr));
+int
+cie_cache_joint(const ref_cie_render_procs *pcrprocs, gs_state *pgs)
+{ const gs_cie_render *pcier = gs_currentcolorrendering(pgs);
+ /* The former installation procedures have allocated */
+ /* the joint caches and filled in points_sd. */
+ gx_cie_joint_caches *pjc = gx_currentciecaches(pgs);
+ ref pqr_procs;
+#define pqr_refs pqr_procs.value.refs
+ uint space;
+ int code;
+ int i;
+
+ if ( pcier == 0 ) /* cache is not set up yet */
+ return 0;
+ if ( pjc == 0 )
+ return_error(e_VMerror);
+ code = ialloc_ref_array(&pqr_procs, a_readonly, 3*(1+4+4*6),
+ "cie_cache_common");
+ if ( code < 0 ) return code;
+ /* When we're done, deallocate the procs and complete the caches. */
+ check_estack(3);
+ cie_cache_push_finish(cie_tpqr_finish, pgs, pgs);
+ *++esp = pqr_procs;
+ space = r_space(&pqr_procs);
+ for ( i = 0; i < 3; i++ )
+ { ref *p = pqr_refs + 3 + (4+4*6) * i;
+ const float *ppt = (float *)&pjc->points_sd;
+ int j;
+
+ make_array(pqr_refs + i, a_readonly | a_executable | space,
+ 4, p);
+ make_array(p, a_readonly | space, 4*6, p + 4);
+ p[1] = pcrprocs->TransformPQR.value.refs[i];
+ make_oper(p + 2, 0, cie_exec_tpqr);
+ make_oper(p + 3, 0, cie_post_exec_tpqr);
+ for ( j = 0, p += 4; j < 4*6; j++, p++, ppt++ )
+ make_real(p, *ppt);
+ }
+ return cie_prepare_cache3(&pcier->RangePQR,
+ pqr_procs.value.const_refs,
+ &pjc->TransformPQR[0],
+ pjc, pgs, "Transform.PQR");
+}
+
+/* Private operator to shuffle arguments for the TransformPQR procedure: */
+/* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
+private int
+cie_exec_tpqr(register os_ptr op)
+{ const ref *ppt = op[-1].value.const_refs;
+ uint space = r_space(op - 1);
+ int i;
+
+ check_op(3);
+ push(4);
+ *op = op[-4]; /* proc */
+ op[-1] = op[-6]; /* v */
+ for ( i = 0; i < 4; i++ )
+ make_const_array(op - 5 + i, a_readonly | space,
+ 6, ppt + i * 6);
+ make_mark(op - 6);
+ return zexec(op);
+}
+
+/* Remove extraneous values from the stack after executing */
+/* the TransformPQR procedure. -mark- ... v -> v */
+private int
+cie_post_exec_tpqr(register os_ptr op)
+{ uint count = ref_stack_counttomark(&o_stack);
+ ref vref;
+
+ if ( count < 2 )
+ return_error(e_unmatchedmark);
+ vref = *op;
+ ref_stack_pop(&o_stack, count - 1);
+ *osp = vref;
+ return 0;
+}
+
+/* Free the procs array and complete the joint caches. */
+private int
+cie_tpqr_finish(register os_ptr op)
+{ gs_state *pgs = r_ptr(op, gs_state);
+ ifree_ref_array(op - 1, "cie_tpqr_finish");
+ gs_cie_cs_complete(pgs, false);
+ pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcrd_l2_op_defs) {
+ op_def_begin_level2(),
+ {"0currentcolorrendering", zcurrentcolorrendering},
+ {"1setcolorrendering", zsetcolorrendering},
+ /* Internal operators */
+ {"1%cie_render_finish", cie_cache_render_finish},
+ {"3%cie_exec_tpqr", cie_exec_tpqr},
+ {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
+ {"1%cie_tpqr_finish", cie_tpqr_finish},
+END_OP_DEFS(0) }
diff --git a/gs/src/zcsindex.c b/gs/src/zcsindex.c
new file mode 100644
index 000000000..971775b5e
--- /dev/null
+++ b/gs/src/zcsindex.c
@@ -0,0 +1,218 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcsindex.c */
+/* Indexed color space support */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscolor.h"
+#include "gsmatrix.h" /* for gxcolor2.h */
+#include "gxcspace.h"
+#include "gxfixed.h" /* ditto */
+#include "gxcolor2.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "icsmap.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Imported from gscolor2.c */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+/* Forward references. */
+private int indexed_map1(P1(os_ptr));
+
+/* Free the map when freeing the gs_indexed_map structure. */
+private void
+rc_free_indexed_map(gs_memory_t *mem, void *data, client_name_t cname)
+{ /*
+ * A bug in the SGI Irix 4.05 compiler requires the following:
+ */
+ char *cdata = (char *)data;
+ gs_free_object(mem, ((gs_indexed_map *)cdata)->values, cname);
+ gs_free_object(mem, cdata, cname);
+}
+
+/* Indexed lookup procedure that just consults the cache. */
+private int
+lookup_indexed(const gs_indexed_params *params, int index, float *values)
+{ int m = params->base_space.type->num_components;
+ const float *pv = &params->lookup.map->values[index * m];
+ switch ( m )
+ {
+ default: return_error(e_rangecheck);
+ case 4: values[3] = pv[3];
+ case 3: values[2] = pv[2];
+ values[1] = pv[1];
+ case 1: values[0] = pv[0];
+ }
+ return 0;
+}
+
+/* <array> .setindexedspace - */
+/* The current color space is the base space for the indexed space. */
+private int
+zsetindexedspace(register os_ptr op)
+{ ref *pproc = &istate->colorspace.procs.special.index_proc;
+ const ref *pcsa;
+ gs_color_space cs;
+ gs_base_color_space cs_base;
+ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ int num_entries;
+ int code;
+
+ check_read_type(*op, t_array);
+ if ( r_size(op) != 4 )
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ check_type_only(pcsa[1], t_integer);
+ if ( pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095 )
+ return_error(e_rangecheck);
+ num_entries = (int)pcsa[1].value.intval + 1;
+ cs = *gs_currentcolorspace(igs);
+ if ( !cs.type->can_be_base_space )
+ return_error(e_rangecheck);
+ cspace_old = istate->colorspace;
+ /*
+ * We can't count on C compilers to recognize the aliasing
+ * that would be involved in a direct assignment.
+ * Formerly, we used the following code:
+ cs_base = *(gs_base_color_space *)&cs;
+ cs.params.indexed.base_space = cs_base;
+ * But the Watcom C 10.0 compiler is too smart: it turns this into
+ * a direct assignment (and compiles incorrect code for it),
+ * defeating our purpose. Instead, we have to do it by brute force:
+ */
+ memcpy(&cs_base, &cs, sizeof(gs_base_color_space));
+ cs.params.indexed.base_space = cs_base;
+ if ( r_has_type(&pcsa[2], t_string) )
+ { int num_values = num_entries * cs.type->num_components;
+ check_read(pcsa[2]);
+ if ( r_size(&pcsa[2]) != num_values )
+ return_error(e_rangecheck);
+ cs.params.indexed.lookup.table.data =
+ pcsa[2].value.const_bytes;
+ cs.params.indexed.use_proc = 0;
+ make_null(pproc);
+ code = 0;
+ }
+ else
+ { gs_indexed_map *map;
+ check_proc(pcsa[2]);
+ code = zcs_begin_map(&map, &pcsa[2], num_entries,
+ (const gs_base_color_space *)&cs,
+ indexed_map1);
+ if ( code < 0 )
+ return code;
+ cs.params.indexed.use_proc = 1;
+ *pproc = pcsa[2];
+ map->proc.lookup_index = lookup_indexed;
+ cs.params.indexed.lookup.map = map;
+ }
+ cs.params.indexed.hival = num_entries - 1;
+ cs.type = &gs_color_space_type_Indexed;
+ code = gs_setcolorspace(igs, &cs);
+ if ( code < 0 )
+ { istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* Continuation procedure for saving mapped Indexed color values. */
+private int
+indexed_map1(os_ptr op)
+{ es_ptr ep = esp;
+ int i = (int)ep[csme_index].value.intval;
+ if ( i >= 0 ) /* i.e., not first time */
+ { int m = (int)ep[csme_num_components].value.intval;
+ int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
+
+ if ( code < 0 )
+ return code;
+ pop(m); op -= m;
+ if ( i == (int)ep[csme_hival].value.intval )
+ { /* All done. */
+ esp -= num_csme;
+ return o_pop_estack;
+ }
+ }
+ push(1);
+ ep[csme_index].value.intval = ++i;
+ make_int(op, i);
+ make_op_estack(ep + 1, indexed_map1);
+ ep[2] = ep[csme_proc]; /* lookup proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcsindex_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1.setindexedspace", zsetindexedspace},
+ /* Internal operators */
+ {"1%indexed_map1", indexed_map1},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Allocate, and prepare to load, the index or tint map. */
+int
+zcs_begin_map(gs_indexed_map **pmap, const ref *pproc, int num_entries,
+ const gs_base_color_space *base_space, int (*map1)(P1(os_ptr)))
+{ gs_memory_t *mem = gs_state_memory(igs);
+ int num_components = base_space->type->num_components;
+ int num_values = num_entries * num_components;
+ gs_indexed_map *map;
+ es_ptr ep;
+ float *values;
+ rc_alloc_struct_0(map, gs_indexed_map, &st_indexed_map,
+ mem, return_error(e_VMerror),
+ "setcolorspace(mapped)");
+ values =
+ (float *)gs_alloc_byte_array(mem, num_values, sizeof(float),
+ "setcolorspace(mapped)");
+ if ( values == 0 )
+ { gs_free_object(mem, map, "setcolorspace(mapped)");
+ return_error(e_VMerror);
+ }
+ map->rc.free = rc_free_indexed_map;
+ map->num_values = num_values;
+ map->values = values;
+ *pmap = map;
+ /* Map the entire set of color indices. Since the */
+ /* o-stack may not be able to hold 4*4096 values, we have */
+ /* to load them into the cache as they are generated. */
+ check_estack(num_csme + 1); /* 1 extra for map1 proc */
+ ep = esp += num_csme;
+ make_int(ep + csme_num_components, num_components);
+ make_struct(ep + csme_map, imemory_space((gs_ref_memory_t *)mem), map);
+ ep[csme_proc] = *pproc;
+ make_int(ep + csme_hival, num_entries - 1);
+ make_int(ep + csme_index, -1);
+ push_op_estack(map1);
+ return o_push_estack;
+}
diff --git a/gs/src/zcssepr.c b/gs/src/zcssepr.c
new file mode 100644
index 000000000..29d3cfbce
--- /dev/null
+++ b/gs/src/zcssepr.c
@@ -0,0 +1,171 @@
+/* Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zcssepr.c */
+/* Separation color space support */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscolor.h"
+#include "gsmatrix.h" /* for gxcolor2.h */
+#include "gscsepr.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* ditto */
+#include "gxcolor2.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "icsmap.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Imported from gscsepr.c */
+extern const gs_color_space_type gs_color_space_type_Separation;
+
+/* Forward references */
+private int separation_map1(P1(os_ptr));
+
+/* Define the separation cache size. This makes many useful tint values */
+/* map to integer cache indices. */
+#define separation_cache_size 360
+
+/* Tint transform procedure that just consults the cache. */
+private int
+lookup_tint(const gs_separation_params *params, floatp tint, float *values)
+{ int m = params->alt_space.type->num_components;
+ const gs_indexed_map *map = params->map;
+ int value_index =
+ (tint < 0 ? 0 : tint > 1 ? map->num_values - m :
+ (int)(tint * separation_cache_size + 0.5) * m);
+ const float *pv = &map->values[value_index];
+ switch ( m )
+ {
+ default: return_error(e_rangecheck);
+ case 4: values[3] = pv[3];
+ case 3: values[2] = pv[2];
+ values[1] = pv[1];
+ case 1: values[0] = pv[0];
+ }
+ return 0;
+}
+
+/* <array> .setseparationspace - */
+/* The current color space is the alternate space for the separation space. */
+private int
+zsetseparationspace(register os_ptr op)
+{ const ref *pcsa;
+ gs_color_space cs;
+ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ gs_indexed_map *map;
+ int code;
+
+ check_read_type(*op, t_array);
+ if ( r_size(op) != 4 )
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ switch ( r_type(pcsa) )
+ {
+ default:
+ return_error(e_typecheck);
+ case t_string:
+ case t_name:
+ ;
+ }
+ check_proc(pcsa[2]);
+ cs = *gs_currentcolorspace(igs);
+ if ( !cs.type->can_be_base_space )
+ return_error(e_rangecheck);
+ code = zcs_begin_map(&map, &pcsa[2], separation_cache_size + 1,
+ (const gs_base_color_space *)&cs,
+ separation_map1);
+ if ( code < 0 )
+ return code;
+ map->proc.tint_transform = lookup_tint;
+ cs.params.separation.alt_space = *(gs_base_color_space *)&cs;
+ cs.params.separation.map = map;
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.special.separation.layer_name = pcsa[0];
+ istate->colorspace.procs.special.separation.tint_transform = pcsa[2];
+ cs.type = &gs_color_space_type_Separation;
+ code = gs_setcolorspace(igs, &cs);
+ if ( code < 0 )
+ { istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* Continuation procedure for saving transformed tint values. */
+private int
+separation_map1(os_ptr op)
+{ es_ptr ep = esp;
+ int i = (int)ep[csme_index].value.intval;
+
+ if ( i >= 0 ) /* i.e., not first time */
+ { int m = (int)ep[csme_num_components].value.intval;
+ int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
+
+ if ( code < 0 )
+ return code;
+ pop(m); op -= m;
+ if ( i == (int)ep[csme_hival].value.intval )
+ { /* All done. */
+ esp -= num_csme;
+ return o_pop_estack;
+ }
+ }
+ push(1);
+ ep[csme_index].value.intval = ++i;
+ make_real(op, i / (float)separation_cache_size);
+ make_op_estack(ep + 1, separation_map1);
+ ep[2] = ep[csme_proc]; /* tint_transform */
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* - currentoverprint <bool> */
+private int
+zcurrentoverprint(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentoverprint(igs));
+ return 0;
+}
+
+/* <bool> setoverprint - */
+private int
+zsetoverprint(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_setoverprint(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zcssepr_l2_op_defs) {
+ op_def_begin_level2(),
+ {"0currentoverprint", zcurrentoverprint},
+ {"1setoverprint", zsetoverprint},
+ {"1.setseparationspace", zsetseparationspace},
+ /* Internal operators */
+ {"1%separation_map1", separation_map1},
+END_OP_DEFS(0) }
diff --git a/gs/src/zdevcal.c b/gs/src/zdevcal.c
new file mode 100644
index 000000000..a2a2c2728
--- /dev/null
+++ b/gs/src/zdevcal.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdevcal.c */
+/* %Calendar% IODevice */
+#include "time_.h"
+#include "ghost.h"
+#include "gxiodev.h"
+#include "istack.h"
+#include "iparam.h"
+
+/* ------ %Calendar% ------ */
+
+private iodev_proc_get_params(calendar_get_params);
+gx_io_device gs_iodev_calendar =
+ { "%Calendar%", "Special",
+ { iodev_no_init, iodev_no_open_device, iodev_no_open_file,
+ iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ calendar_get_params, iodev_no_put_params
+ }
+ };
+
+/* Get the date and time. */
+private int
+calendar_get_params(gx_io_device *iodev, gs_param_list *plist)
+{ int code;
+ time_t t;
+ struct tm *pltime;
+ struct tm ltime;
+ bool running;
+
+ if ( time(&t) == -1 || (pltime = localtime(&t)) == 0 )
+ { ltime.tm_sec = ltime.tm_min = ltime.tm_hour =
+ ltime.tm_mday = ltime.tm_mon = ltime.tm_year = 0;
+ running = false;
+ }
+ else
+ { ltime = *pltime;
+ ltime.tm_year += 1900;
+ ltime.tm_mon++; /* 1-origin */
+ running = true;
+ }
+ if ( (code = param_write_int(plist, "Year", &ltime.tm_year)) < 0 ||
+ (code = param_write_int(plist, "Month", &ltime.tm_mon)) < 0 ||
+ (code = param_write_int(plist, "Day", &ltime.tm_mday)) < 0 ||
+ (code = param_write_int(plist, "Weekday", &ltime.tm_wday)) < 0 ||
+ (code = param_write_int(plist, "Hour", &ltime.tm_hour)) < 0 ||
+ (code = param_write_int(plist, "Minute", &ltime.tm_min)) < 0 ||
+ (code = param_write_int(plist, "Second", &ltime.tm_sec)) < 0
+ )
+ return code;
+ return param_write_bool(plist, "Running", &running);
+}
diff --git a/gs/src/zdevice.c b/gs/src/zdevice.c
new file mode 100644
index 000000000..8c0f6160b
--- /dev/null
+++ b/gs/src/zdevice.c
@@ -0,0 +1,362 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdevice.c */
+/* Device-related operators */
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "igstate.h"
+#include "iname.h"
+#include "interp.h"
+#include "iparam.h"
+#include "ivmspace.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gxdevice.h"
+#include "store.h"
+
+/* <device> copydevice <newdevice> */
+private int
+zcopydevice(register os_ptr op)
+{ gx_device *new_dev;
+ int code;
+
+ check_read_type(*op, t_device);
+ code = gs_copydevice(&new_dev, op->value.pdevice, imemory);
+ if ( code < 0 )
+ return code;
+ new_dev->memory = imemory;
+ make_tav(op, t_device, icurrent_space | a_all, pdevice, new_dev);
+ return 0;
+}
+
+/* <device> <y> <string> copyscanlines <substring> */
+private int
+zcopyscanlines(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ os_ptr op2 = op - 2;
+ gx_device *dev;
+ int code;
+ uint bytes_copied;
+
+ check_read_type(*op2, t_device);
+ dev = op2->value.pdevice;
+ check_type(*op1, t_integer);
+ if ( op1->value.intval < 0 || op1->value.intval > dev->height )
+ return_error(e_rangecheck);
+ check_write_type(*op, t_string);
+ code = gs_copyscanlines(dev, (int)op1->value.intval,
+ op->value.bytes, r_size(op), NULL,
+ &bytes_copied);
+ if ( code < 0 )
+ return_error(e_rangecheck); /* not a memory device */
+ *op2 = *op;
+ r_set_size(op2, bytes_copied);
+ pop(2);
+ return 0;
+}
+
+/* - currentdevice <device> */
+int
+zcurrentdevice(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+ gs_ref_memory_t *mem = (gs_ref_memory_t *)dev->memory;
+
+ push(1);
+ make_tav(op, t_device,
+ (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all,
+ pdevice, dev);
+ return 0;
+}
+
+/* <device> .devicename <string> */
+int
+zdevicename(register os_ptr op)
+{ const char *dname;
+
+ check_read_type(*op, t_device);
+ dname = op->value.pdevice->dname;
+ make_const_string(op, avm_foreign | a_readonly, strlen(dname),
+ (const byte *)dname);
+ return 0;
+}
+
+/* - .doneshowpage - */
+private int
+zdoneshowpage(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+ gx_device *tdev = (*dev_proc(dev, get_page_device))(dev);
+
+ if ( tdev != 0 )
+ tdev->ShowpageCount++;
+ return 0;
+}
+
+/* - flushpage - */
+int
+zflushpage(register os_ptr op)
+{ return gs_flushpage(igs);
+}
+
+/* <int> .getdevice <device> */
+private int
+zgetdevice(register os_ptr op)
+{ const gx_device *dev;
+
+ check_type(*op, t_integer);
+ if ( op->value.intval != (int)(op->value.intval) )
+ return_error(e_rangecheck); /* won't fit in an int */
+ dev = gs_getdevice((int)(op->value.intval));
+ if ( dev == 0 ) /* index out of range */
+ return_error(e_rangecheck);
+ /* Device prototypes are read-only; */
+ /* the cast is logically unnecessary. */
+ make_tav(op, t_device, avm_foreign | a_readonly, pdevice,
+ (gx_device *)dev);
+ return 0;
+}
+
+/* Common functionality of zgethardwareparms & zgetdeviceparams */
+private int
+get_device_params(os_ptr op, bool is_hardware)
+{ ref rkeys;
+ gx_device *dev;
+ stack_param_list list;
+ int code;
+ ref *pmark;
+
+ check_read_type(op[-1], t_device);
+ rkeys = *op;
+ dev = op[-1].value.pdevice;
+ pop(1);
+ stack_param_list_write(&list, &o_stack, &rkeys);
+ code = gs_get_device_or_hardware_params
+ (dev, (gs_param_list *)&list, is_hardware);
+ if ( code < 0 )
+ { /* We have to put back the top argument. */
+ if ( list.count > 0 )
+ ref_stack_pop(&o_stack, list.count * 2 - 1);
+ else
+ ref_stack_push(&o_stack, 1);
+ *osp = rkeys;
+ return code;
+ }
+ pmark = ref_stack_index(&o_stack, list.count * 2);
+ make_mark(pmark);
+ return 0;
+}
+
+/* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */
+private int
+zgetdeviceparams(os_ptr op)
+{ return get_device_params(op, false);
+}
+
+/* <device> <key_dict|null> .gethardwareparams <mark> <name> <value> ... */
+private int
+zgethardwareparams(os_ptr op)
+{ return get_device_params(op, true);
+}
+
+/* <matrix> <width> <height> <palette> <word?> makewordimagedevice <device> */
+private int
+zmakewordimagedevice(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ gs_matrix imat;
+ gx_device *new_dev;
+ const byte *colors;
+ int colors_size;
+ int code;
+
+ check_int_leu(op[-3], max_uint >> 1); /* width */
+ check_int_leu(op[-2], max_uint >> 1); /* height */
+ check_type(*op, t_boolean);
+ if ( r_has_type(op1, t_null) ) /* true color */
+ { colors = 0;
+ colors_size = -24; /* 24-bit true color */
+ }
+ else if ( r_has_type(op1, t_integer) )
+ { switch ( op1->value.intval )
+ {
+ case 16: case 24: case 32: break;
+ default: return_error(e_rangecheck);
+ }
+ colors = 0;
+ colors_size = -op1->value.intval;
+ }
+ else
+ { check_type(*op1, t_string); /* palette */
+ if ( r_size(op1) > 3*256 )
+ return_error(e_rangecheck);
+ colors = op1->value.bytes;
+ colors_size = r_size(op1);
+ }
+ if ( (code = read_matrix(op - 4, &imat)) < 0 )
+ return code;
+ /* Everything OK, create device */
+ code = gs_makewordimagedevice(&new_dev, &imat,
+ (int)op[-3].value.intval,
+ (int)op[-2].value.intval,
+ colors, colors_size,
+ op->value.boolval, true, imemory);
+ if ( code == 0 )
+ { new_dev->memory = imemory;
+ make_tav(op - 4, t_device, imemory_space(iimemory) | a_all,
+ pdevice, new_dev);
+ pop(4);
+ }
+ return code;
+}
+
+/* - nulldevice - */
+/* Note that nulldevice clears the current pagedevice. */
+private int
+znulldevice(register os_ptr op)
+{ gs_nulldevice(igs);
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <num_copies> <flush_bool> .outputpage - */
+private int
+zoutputpage(register os_ptr op)
+{ int code;
+
+ check_type(op[-1], t_integer);
+ check_type(*op, t_boolean);
+ code = gs_output_page(igs, (int)op[-1].value.intval,
+ op->value.boolval);
+ if ( code < 0 )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <device> <policy_dict|null> <require_all> <mark> <name> <value> ... */
+/* .putdeviceparams */
+/* (on success) <device> <eraseflag> */
+/* (on failure) <device> <policy_dict|null> <require_all> <mark> */
+/* <name1> <error1> ... */
+/* For a key that simply was not recognized, if require_all is true, */
+/* the result will be an /undefined error; if require_all is false, */
+/* the key will be ignored. */
+/* Note that .putdeviceparams clears the current pagedevice. */
+private int
+zputdeviceparams(os_ptr op)
+{ uint count = ref_stack_counttomark(&o_stack);
+ ref *prequire_all;
+ ref *ppolicy;
+ ref *pdev;
+ gx_device *dev;
+ stack_param_list list;
+ int code;
+ int old_width, old_height;
+ int i, dest;
+
+ if ( count == 0 )
+ return_error(e_unmatchedmark);
+ prequire_all = ref_stack_index(&o_stack, count);
+ ppolicy = ref_stack_index(&o_stack, count + 1);
+ pdev = ref_stack_index(&o_stack, count + 2);
+ if ( pdev == 0 )
+ return_error(e_stackunderflow);
+ check_type_only(*prequire_all, t_boolean);
+ check_write_type_only(*pdev, t_device);
+ dev = pdev->value.pdevice;
+ code = stack_param_list_read(&list, &o_stack, 0, ppolicy,
+ prequire_all->value.boolval);
+ if ( code < 0 )
+ return code;
+ old_width = dev->width;
+ old_height = dev->height;
+ code = gs_putdeviceparams(dev, (gs_param_list *)&list);
+ /* Check for names that were undefined or caused errors. */
+ for ( dest = count - 2, i = 0; i < count >> 1; i++ )
+ if ( list.results[i] < 0 )
+ { *ref_stack_index(&o_stack, dest) =
+ *ref_stack_index(&o_stack, count - (i << 1) - 2);
+ gs_errorname(list.results[i],
+ ref_stack_index(&o_stack, dest - 1));
+ dest -= 2;
+ }
+ iparam_list_release(&list);
+ if ( code < 0 )
+ { /* There were errors reported. */
+ ref_stack_pop(&o_stack, dest + 1);
+ return 0;
+ }
+ if ( code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height)) )
+ { /* The device was open and is now closed, */
+ /* or its dimensions have changed. */
+ /* If it was the current device, */
+ /* call setdevice to reinstall it and erase the page. */
+ /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/
+ if ( gs_currentdevice(igs) == dev )
+ { bool was_open = dev->is_open;
+ code = gs_setdevice_no_erase(igs, dev);
+ /* If the device wasn't closed, */
+ /* setdevice won't erase the page. */
+ if ( was_open && code >= 0 )
+ code = 1;
+ }
+ }
+ if ( code < 0 )
+ return code;
+ ref_stack_pop(&o_stack, count + 1);
+ make_bool(osp, code);
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <device> .setdevice <eraseflag> */
+/* Note that .setdevice clears the current pagedevice. */
+int
+zsetdevice(register os_ptr op)
+{ int code;
+
+ check_write_type(*op, t_device);
+ code = gs_setdevice_no_erase(igs, op->value.pdevice);
+ if ( code < 0 )
+ return code;
+ make_bool(op, code != 0); /* erase page if 1 */
+ clear_pagedevice(istate);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdevice_op_defs) {
+ {"1copydevice", zcopydevice},
+ {"3copyscanlines", zcopyscanlines},
+ {"0currentdevice", zcurrentdevice},
+ {"1.devicename", zdevicename},
+ {"0.doneshowpage", zdoneshowpage},
+ {"0flushpage", zflushpage},
+ {"1.getdevice", zgetdevice},
+ {"2.getdeviceparams", zgetdeviceparams},
+ {"2.gethardwareparams", zgethardwareparams},
+ {"5makewordimagedevice", zmakewordimagedevice},
+ {"0nulldevice", znulldevice},
+ {"2.outputpage", zoutputpage},
+ {"3.putdeviceparams", zputdeviceparams},
+ {"1.setdevice", zsetdevice},
+END_OP_DEFS(0) }
diff --git a/gs/src/zdevice2.c b/gs/src/zdevice2.c
new file mode 100644
index 000000000..55118288f
--- /dev/null
+++ b/gs/src/zdevice2.c
@@ -0,0 +1,330 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdevice2.c */
+/* Level 2 device operators */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "dstack.h" /* for dict_find_name */
+#include "estack.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+#include "gxdevice.h"
+#include "gsstate.h"
+
+/* Imported data */
+extern op_proc_p zcopy_procs[t_next_index];
+
+/* Forward references */
+private int z2copy_gstate(P1(os_ptr));
+private int near push_callout(P1(const char _ds *));
+
+/* Initialize by adding changing the `copy' operator for gstates. */
+/* This is a hack -- we know that gstates are the only */
+/* t_astruct subtype that implements copy. */
+private void
+zdevice2_init(void)
+{ zcopy_procs[t_astruct] = z2copy_gstate;
+}
+
+/* - .currentshowpagecount <count> true */
+/* - .currentshowpagecount false */
+private int
+zcurrentshowpagecount(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ if ( (*dev_proc(dev, get_page_device))(dev) == 0 )
+ { push(1);
+ make_false(op);
+ }
+ else
+ { push(2);
+ make_int(op - 1, dev->ShowpageCount);
+ make_true(op);
+ }
+ return 0;
+}
+
+/* - .currentpagedevice <dict> <bool> */
+private int
+zcurrentpagedevice(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ push(2);
+ if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
+ { op[-1] = istate->pagedevice;
+ make_true(op);
+ }
+ else
+ { op[-1] = i_null_pagedevice;
+ make_false(op);
+ }
+ return 0;
+}
+
+/* <dict> .setpagedevice - */
+private int
+zsetpagedevice(register os_ptr op)
+{ int code;
+
+/******
+ if ( igs->in_cachedevice )
+ return_error(e_undefined);
+ ******/
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ /* Make the dictionary read-only. */
+ code = zreadonly(op);
+ if ( code < 0 )
+ return code;
+ istate->pagedevice = *op;
+ pop(1);
+ return 0;
+}
+
+/* Default Install/BeginPage/EndPage procedures */
+/* that just call the procedure in the device. */
+
+/* - .callinstall - */
+private int
+zcallinstall(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { int code = (*dev->page_procs.install)(dev, igs);
+ if ( code < 0 )
+ return code;
+ }
+ return 0;
+}
+
+/* <showpage_count> .callbeginpage - */
+private int
+zcallbeginpage(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ check_type(*op, t_integer);
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { int code = (*dev->page_procs.begin_page)(dev, igs);
+ if ( code < 0 )
+ return code;
+ }
+ pop(1);
+ return 0;
+}
+
+/* <showpage_count> <reason_int> .callendpage <flush_bool> */
+private int
+zcallendpage(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+ int code;
+
+ check_type(op[-1], t_integer);
+ check_type(*op, t_integer);
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
+ if ( code < 0 )
+ return code;
+ if ( code > 1 )
+ return_error(e_rangecheck);
+ }
+ else
+ { code = (op->value.intval == 2 ? 0 : 1);
+ }
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* ------ Wrappers for operators that save the graphics state. ------ */
+
+/* When saving the state with the current device a page device, */
+/* we need to make sure that the page device dictionary exists */
+/* so that grestore can use it to reset the device parameters. */
+/* This may have significant performance consequences, but we don't see */
+/* any way around it. */
+
+/* Check whether we need to call out to create the page device dictionary. */
+#define save_page_device(pgs)\
+ (gs_int_gstate(pgs)->pagedevice.value.pdict ==\
+ i_null_pagedevice.value.pdict &&\
+ (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs))\
+ != 0)
+
+/* - gsave - */
+private int
+z2gsave(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return gs_gsave(igs);
+ return push_callout("%gsavepagedevice");
+}
+
+/* - save - */
+private int
+z2save(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zsave(op);
+ return push_callout("%savepagedevice");
+}
+
+/* - gstate <gstate> */
+private int
+z2gstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zgstate(op);
+ return push_callout("%gstatepagedevice");
+}
+
+/* <gstate1> <gstate2> copy <gstate2> */
+private int
+z2copy_gstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zcopy_gstate(op);
+ return push_callout("%copygstatepagedevice");
+}
+
+/* <gstate1> <gstate2> currentgstate <gstate2> */
+private int
+z2currentgstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zcurrentgstate(op);
+ return push_callout("%currentgstatepagedevice");
+}
+
+/* ------ Wrappers for operators that reset the graphics state. ------ */
+
+/* Check whether we need to call out to restore the page device. */
+private bool near
+restore_page_device(const gs_state *pgs_old, const gs_state *pgs_new)
+{ gx_device *dev_old = gs_currentdevice(pgs_old);
+ gx_device *dev_new;
+ gx_device *dev_t1;
+ gx_device *dev_t2;
+
+ if ( (dev_t1 = (*dev_proc(dev_old, get_page_device))(dev_old)) == 0 )
+ return false;
+ dev_new = gs_currentdevice(pgs_new);
+ if ( dev_old != dev_new )
+ { if ( (dev_t2 = (*dev_proc(dev_new, get_page_device))(dev_new)) == 0 )
+ return false;
+ if ( dev_t1 != dev_t2 )
+ return true;
+ }
+ /* The current implementation of setpagedevice just sets new */
+ /* parameters in the same device object, so we have to check */
+ /* whether the page device dictionaries are the same. */
+ { const ref *pdict1 = &gs_int_gstate(pgs_old)->pagedevice;
+ const ref *pdict2 = &gs_int_gstate(pgs_new)->pagedevice;
+ return pdict1->value.pdict != pdict2->value.pdict;
+ }
+}
+
+/* - grestore - */
+private int
+z2grestore(os_ptr op)
+{ if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ return gs_grestore(igs);
+ return push_callout("%grestorepagedevice");
+}
+
+/* - grestoreall - */
+private int
+z2grestoreall(os_ptr op)
+{ for ( ; ; )
+ { if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ { bool done = !gs_state_saved(gs_state_saved(igs));
+
+ gs_grestore(igs);
+ if ( done )
+ break;
+ }
+ else
+ return push_callout("%grestoreallpagedevice");
+ }
+ return 0;
+}
+
+/* <save> restore - */
+private int
+z2restore(os_ptr op)
+{ for ( ; ; )
+ { if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ { zgrestore(op);
+ if ( !gs_state_saved(gs_state_saved(igs)) )
+ break;
+ }
+ else
+ return push_callout("%restorepagedevice");
+ }
+ return zrestore(op);
+}
+
+/* <gstate> setgstate - */
+private int
+z2setgstate(os_ptr op)
+{ check_stype(*op, st_igstate_obj);
+ if ( !restore_page_device(igs, igstate_ptr(op)) )
+ return zsetgstate(op);
+ return push_callout("%setgstatepagedevice");
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdevice2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"0.currentshowpagecount", zcurrentshowpagecount},
+ {"0.currentpagedevice", zcurrentpagedevice},
+ {"1.setpagedevice", zsetpagedevice},
+ /* Note that the following replace prior definitions */
+ /* in the indicated files: */
+ {"0gsave", z2gsave}, /* zgstate.c */
+ {"0save", z2save}, /* zvmem.c */
+ {"0gstate", z2gstate}, /* zdps1.c */
+ {"1currentgstate", z2currentgstate}, /* zdps1.c */
+ {"0grestore", z2grestore}, /* zgstate.c */
+ {"0grestoreall", z2grestoreall}, /* zgstate.c */
+ {"1restore", z2restore}, /* zvmem.c */
+ {"1setgstate", z2setgstate}, /* zdps1.c */
+ /* Default Install/BeginPage/EndPage procedures */
+ /* that just call the procedure in the device. */
+ {"0.callinstall", zcallinstall},
+ {"1.callbeginpage", zcallbeginpage},
+ {"2.callendpage", zcallendpage},
+END_OP_DEFS(zdevice2_init) }
+
+/* ------ Internal routines ------ */
+
+/* Call out to a PostScript procedure. */
+private int near
+push_callout(const char _ds *callout_name)
+{ int code;
+
+ check_estack(1);
+ code = name_enter_string(callout_name, esp + 1);
+ if ( code < 0 )
+ return code;
+ ++esp;
+ r_set_attrs(esp, a_executable);
+ return o_push_estack;
+}
diff --git a/gs/src/zdict.c b/gs/src/zdict.c
new file mode 100644
index 000000000..5d070c580
--- /dev/null
+++ b/gs/src/zdict.c
@@ -0,0 +1,494 @@
+/* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdict.c */
+/* Dictionary operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "idict.h"
+#include "dstack.h"
+#include "ilevel.h" /* for [count]dictstack */
+#include "iname.h" /* for dict_find_name */
+#include "ipacked.h" /* for inline dict lookup */
+#include "ivmspace.h"
+#include "store.h"
+
+/* <int> dict <dict> */
+int
+zdict(register os_ptr op)
+{ check_type(*op, t_integer);
+#if arch_sizeof_int < arch_sizeof_long
+ check_int_leu(*op, max_uint);
+#else
+ if ( op->value.intval < 0 )
+ return_error(e_rangecheck);
+#endif
+ return dict_create((uint)op->value.intval, op);
+}
+
+/* <dict> maxlength <int> */
+private int
+zmaxlength(register os_ptr op)
+{ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ make_int(op, dict_maxlength(op));
+ return 0;
+}
+
+/* <dict> begin - */
+int
+zbegin(register os_ptr op)
+{ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ( dsp == dstop )
+ return_error(e_dictstackoverflow);
+ ++dsp;
+ ref_assign(dsp, op);
+ dict_set_top();
+ pop(1);
+ return 0;
+}
+
+/* - end - */
+int
+zend(register os_ptr op)
+{ if ( ref_stack_count_inline(&d_stack) == min_dstack_size )
+ { /* We would underflow the d-stack. */
+ return_error(e_dictstackunderflow);
+ }
+ while ( dsp == dsbot )
+ { /* We would underflow the current block. */
+ ref_stack_pop_block(&d_stack);
+ }
+ dsp--;
+ dict_set_top();
+ return 0;
+}
+
+/* <key> <value> def - */
+/* We make this into a separate procedure because */
+/* the interpreter will almost always call it directly. */
+int
+zop_def(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ ref *pvslot;
+ /* The following combines a check_op(2) with a type check. */
+ switch ( r_type(op1) )
+ {
+ case t_name:
+ { /* We can use the fast single-probe lookup here. */
+ uint nidx = name_index(op1);
+ uint htemp;
+ if_dict_find_name_by_index_top(nidx, htemp, pvslot)
+ { if ( dtop_can_store(op) )
+ goto ra;
+ }
+ break; /* handle all slower cases */
+ }
+ case t_null:
+ return_error(e_typecheck);
+ case t__invalid:
+ return_error(e_stackunderflow);
+ }
+ /* Combine the check for a writable top dictionary with */
+ /* the global/local store check. See dstack.h for details. */
+ if ( !dtop_can_store(op) )
+ { int code;
+ check_dict_write(*dsp);
+ /*
+ * If the dictionary is writable, the problem must be
+ * an invalid store. We need a special check to allow
+ * storing references to local objects in systemdict,
+ * or in dictionaries known in systemdict,
+ * during initialization (see ivmspace.h).
+ */
+ if ( ialloc_is_in_save() )
+ return_error(e_invalidaccess);
+ if ( dsp->value.pdict != systemdict->value.pdict )
+ { /* See if systemdict is still writable, */
+ /* i.e., we are still doing initialization. */
+ int index;
+ ref elt[2]; /* key, value */
+ check_dict_write(*systemdict);
+ /* See if this dictionary is known in systemdict. */
+ for ( index = dict_first(systemdict);
+ (index = dict_next(systemdict, index, &elt[0])) >= 0;
+ )
+ if ( r_has_type(&elt[1], t_dictionary) &&
+ elt[1].value.pdict == dsp->value.pdict
+ )
+ break;
+ if ( index < 0 )
+ return_error(e_invalidaccess);
+ }
+ switch ( code = dict_find(dsp, op1, &pvslot) )
+ {
+ case 1: /* found */
+ goto ra;
+ default: /* some other error */
+ return code;
+ /*
+ * If we have to grow the dictionary, do it now, so that
+ * the allocator will allocate the copy in the correct space.
+ */
+ case e_dictfull:
+ if ( !dict_auto_expand )
+ return_error(e_dictfull);
+ code = dict_grow(dsp);
+ if ( code < 0 )
+ return code;
+ case 0:
+ ;
+ }
+ /* Temporarily identify the dictionary as local, */
+ /* so the store check in dict_put won't fail. */
+ { uint space = r_space(dsp);
+ r_set_space(dsp, avm_local);
+ code = dict_put(dsp, op1, op);
+ r_set_space(dsp, space);
+ return code;
+ }
+ }
+ /* Save a level of procedure call in the common (redefinition) */
+ /* case. With the current interfaces, we pay a double lookup */
+ /* in the uncommon case. */
+ if ( dict_find(dsp, op1, &pvslot) <= 0 )
+ return dict_put(dsp, op1, op);
+ra: ref_assign_old_inline(&dsp->value.pdict->values, pvslot, op,
+ "dict_put(value)");
+ return 0;
+}
+int
+zdef(os_ptr op)
+{ int code = zop_def(op);
+ if ( code >= 0 ) { pop(2); }
+ return code;
+}
+
+/* <key> load <value> */
+private int
+zload(register os_ptr op)
+{ ref *pvalue;
+ switch ( r_type(op) )
+ {
+ case t_name:
+ /* Use the fast lookup. */
+ if ( (pvalue = dict_find_name(op)) == 0 )
+ return_error(e_undefined);
+ ref_assign(op, pvalue);
+ return 0;
+ case t_null:
+ return_error(e_typecheck);
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ { /* Use an explicit loop. */
+ uint size = ref_stack_count(&d_stack);
+ uint i;
+ for ( i = 0; i < size; i++ )
+ { ref *dp = ref_stack_index(&d_stack, i);
+ check_dict_read(*dp);
+ if ( dict_find(dp, op, &pvalue) > 0 )
+ { ref_assign(op, pvalue);
+ return 0;
+ }
+ }
+ return_error(e_undefined);
+ }
+ }
+}
+
+/* get - implemented in zgeneric.c */
+
+/* put - implemented in zgeneric.c */
+
+/* <dict> <key> .undef - */
+/* <dict> <key> undef - */
+private int
+zundef(register os_ptr op)
+{ check_type(op[-1], t_dictionary);
+ check_dict_write(op[-1]);
+ dict_undef(op - 1, op); /* ignore undefined error */
+ pop(2);
+ return 0;
+}
+
+/* <dict> <key> known <bool> */
+private int
+zknown(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ ref *pvalue;
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ make_bool(op1, (dict_find(op1, op, &pvalue) > 0 ? 1 : 0));
+ pop(1);
+ return 0;
+}
+
+/* <key> where <dict> true */
+/* <key> where false */
+int
+zwhere(register os_ptr op)
+{ check_op(1);
+ STACK_LOOP_BEGIN(&d_stack, bot, size)
+ { const ref *pdref = bot + size;
+ ref *pvalue;
+ while ( pdref-- > bot )
+ { check_dict_read(*pdref);
+ if ( dict_find(pdref, op, &pvalue) > 0 )
+ { push(1);
+ ref_assign(op - 1, pdref);
+ make_true(op);
+ return 0;
+ }
+ }
+ }
+ STACK_LOOP_END(bot, size)
+ make_false(op);
+ return 0;
+}
+
+/* copy for dictionaries -- called from zcopy in zgeneric.c. */
+/* Only the type of *op has been checked. */
+int
+zcopy_dict(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int code;
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ check_dict_write(*op);
+ if ( !dict_auto_expand &&
+ (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1))
+ )
+ return_error(e_rangecheck);
+ code = dict_copy(op1, op);
+ if ( code < 0 )
+ return code;
+ /*
+ * In Level 1 systems, we must copy the access attributes too.
+ * The only possible effect this can have is to make the
+ * copy read-only if the original dictionary is read-only.
+ */
+ if ( !level2_enabled )
+ r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1));
+ ref_assign(op1, op);
+ pop(1);
+ return 0;
+}
+
+/* - currentdict <dict> */
+private int
+zcurrentdict(register os_ptr op)
+{ push(1);
+ ref_assign(op, dsp);
+ return 0;
+}
+
+/* - countdictstack <int> */
+private int
+zcountdictstack(register os_ptr op)
+{ uint count = ref_stack_count(&d_stack);
+ push(1);
+ if ( !level2_enabled )
+ count--; /* see dstack.h */
+ make_int(op, count);
+ return 0;
+}
+
+/* <array> dictstack <subarray> */
+private int
+zdictstack(register os_ptr op)
+{ uint count = ref_stack_count(&d_stack);
+ check_write_type(*op, t_array);
+ if ( !level2_enabled )
+ count--; /* see dstack.h */
+ return ref_stack_store(&d_stack, op, count, 0, 0, true, "dictstack");
+}
+
+/* - cleardictstack - */
+private int
+zcleardictstack(os_ptr op)
+{ while ( zend(op) >= 0 ) ;
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <dict1> <dict2> .dictcopynew <dict2> */
+private int
+zdictcopynew(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int code;
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ check_type(*op, t_dictionary);
+ check_dict_write(*op);
+ /* This is only recognized in Level 2 mode. */
+ if ( !dict_auto_expand )
+ return_error(e_undefined);
+ code = dict_copy_new(op1, op);
+ if ( code < 0 )
+ return code;
+ ref_assign(op1, op);
+ pop(1);
+ return 0;
+}
+
+/* -mark- <key0> <value0> <key1> <value1> ... .dicttomark <dict> */
+/* This is the Level 2 >> operator. */
+private int
+zdicttomark(register os_ptr op)
+{ uint count2 = ref_stack_counttomark(&o_stack);
+ ref rdict;
+ int code;
+ uint idx;
+
+ if ( count2 == 0 )
+ return_error(e_unmatchedmark);
+ count2--;
+ if ( (count2 & 1) != 0 )
+ return_error(e_rangecheck);
+ code = dict_create(count2 >> 1, &rdict);
+ if ( code < 0 )
+ return code;
+ /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */
+ /* we must enter the keys in top-to-bottom order. */
+ for ( idx = 0; idx < count2; idx += 2 )
+ { code = dict_put(&rdict,
+ ref_stack_index (&o_stack, idx + 1),
+ ref_stack_index (&o_stack, idx));
+ if ( code < 0 )
+ { /* There's no way to free the dictionary -- too bad. */
+ return code;
+ }
+ }
+ ref_stack_pop(&o_stack, count2);
+ ref_assign(osp, &rdict);
+ return code;
+}
+
+/* <dict> <key> <value> .forceput - */
+/*
+ * This forces a "put" even if the dictionary is not writable, and (if
+ * the dictionary is systemdict) even if the value is in local VM.
+ * It is meant to be used only for replacing the value of FontDirectory
+ * in systemdict when switching between local and global VM,
+ * and a few similar applications. After initialization, this operator
+ * should no longer be accessible by name.
+ */
+private int
+zforceput(register os_ptr op)
+{ os_ptr odp = op - 2;
+ int code;
+ check_type(*odp, t_dictionary);
+ if ( odp->value.pdict == systemdict->value.pdict )
+ { uint space = r_space(odp);
+ r_set_space(odp, avm_local);
+ code = dict_put(odp, op - 1, op);
+ r_set_space(odp, space);
+ }
+ else
+ code = dict_put(odp, op - 1, op);
+ if ( code < 0 )
+ return code;
+ pop(3);
+ return 0;
+}
+
+/* <dict> <key> .knownget <value> true */
+/* <dict> <key> .knownget false */
+private int
+zknownget(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ ref *pvalue;
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ if ( dict_find(op1, op, &pvalue) <= 0 )
+ { make_false(op1);
+ pop(1);
+ }
+ else
+ { ref_assign(op1, pvalue);
+ make_true(op);
+ }
+ return 0;
+}
+
+/* <dict> <key> .knownundef <bool> */
+private int
+zknownundef(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int code;
+ check_type(*op1, t_dictionary);
+ check_dict_write(*op1);
+ code = dict_undef(op1, op);
+ make_bool(op1, code == 0);
+ pop(1);
+ return 0;
+}
+
+/* <dict> <int> .setmaxlength - */
+private int
+zsetmaxlength(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ uint new_size;
+ int code;
+
+ check_type(*op1, t_dictionary);
+ check_dict_write(*op1);
+ check_type(*op, t_integer);
+#if arch_sizeof_int < arch_sizeof_long
+ check_int_leu(*op, max_uint);
+#else
+ if ( op->value.intval < 0 )
+ return_error(e_rangecheck);
+#endif
+ new_size = (uint)op->value.intval;
+ if ( dict_length(op - 1) > new_size )
+ return_error(e_dictfull);
+ code = dict_resize(op - 1, new_size);
+ if ( code >= 0 )
+ pop(2);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdict_op_defs) {
+ {"0cleardictstack", zcleardictstack},
+ {"1begin", zbegin},
+ {"0countdictstack", zcountdictstack},
+ {"0currentdict", zcurrentdict},
+ {"2def", zdef},
+ {"1dict", zdict},
+ {"0dictstack", zdictstack},
+ {"0end", zend},
+ {"2known", zknown},
+ {"1load", zload},
+ {"1maxlength", zmaxlength},
+ {"2.undef", zundef}, /* we need this even in Level 1 */
+ {"1where", zwhere},
+ /* Extensions */
+ {"2.dictcopynew", zdictcopynew},
+ {"1.dicttomark", zdicttomark},
+ {"3.forceput", zforceput},
+ {"2.knownget", zknownget},
+ {"1.knownundef", zknownundef},
+ {"2.setmaxlength", zsetmaxlength},
+END_OP_DEFS(0) }
diff --git a/gs/src/zdosio.c b/gs/src/zdosio.c
new file mode 100644
index 000000000..318c28e0b
--- /dev/null
+++ b/gs/src/zdosio.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdosio.c */
+/* MS-DOS direct I/O operators. */
+/* These should NEVER be included in a released configuration! */
+#include "dos_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "store.h"
+
+/* <port> .inport <word> */
+private int
+zinport(register os_ptr op)
+{ check_type(*op, t_integer);
+ make_int(op, inport((int)op->value.intval));
+ return 0;
+}
+
+/* <port> .inportb <byte> */
+private int
+zinportb(register os_ptr op)
+{ check_type(*op, t_integer);
+ make_int(op, inportb((int)op->value.intval));
+ return 0;
+}
+
+/* <port> <word> .outport - */
+private int
+zoutport(register os_ptr op)
+{ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+ outport((int)op[-1].value.intval, (int)op->value.intval);
+ pop(1);
+ return 0;
+}
+
+/* <port> <byte> .outportb - */
+private int
+zoutportb(register os_ptr op)
+{ check_type(*op, t_integer);
+ check_int_leu(op[-1], 0xff);
+ outportb((int)op[-1].value.intval, (byte)op->value.intval);
+ pop(1);
+ return 0;
+}
+
+/* <loc> .peek <byte> */
+private int
+zpeek(register os_ptr op)
+{ check_type(*op, t_integer);
+ make_int(op, *(byte *)(op->value.intval));
+ return 0;
+}
+
+/* <loc> <byte> .poke - */
+private int
+zpoke(register os_ptr op)
+{ check_type(*op, t_integer);
+ check_int_leu(op[-1], 0xff);
+ *(byte *)(op[-1].value.intval) = (byte)op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* ------ Operator initialization ------ */
+
+BEGIN_OP_DEFS(zdosio_op_defs) {
+ {"1.inport", zinport},
+ {"1.inportb", zinportb},
+ {"2.outport", zoutport},
+ {"2.outportb", zoutportb},
+ {"1.peek", zpeek},
+ {"2.poke", zpoke},
+END_OP_DEFS(0) }
diff --git a/gs/src/zdouble.c b/gs/src/zdouble.c
new file mode 100644
index 000000000..7ed995ecf
--- /dev/null
+++ b/gs/src/zdouble.c
@@ -0,0 +1,488 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdouble.c */
+/* Double-precision floating point arithmetic operators */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ctype_.h"
+#include "ghost.h"
+#include "gxfarith.h"
+#include "errors.h"
+#include "oper.h"
+#include "store.h"
+
+/*
+ * Thanks to Jean-Pierre Demailly of the Institut Fourier of the
+ * Universit\'e de Grenoble I <demailly@fourier.grenet.fr> for proposing
+ * this package and for arranging the funding for its creation.
+ *
+ * These operators work with doubles represented as 8-byte strings. When
+ * applicable, they write their result into a string supplied as an argument.
+ * They also accept ints and reals as arguments.
+ */
+
+/******
+ ****** Time expended: 2.75 hours.
+ ******/
+
+/* Forward references */
+private int near double_params_result(P3(os_ptr, int, double *));
+private int near double_params(P3(os_ptr, int, double *));
+private int near double_result(P3(os_ptr, int, double));
+private int near double_unary(P2(os_ptr, double (*)(P1(double))));
+
+#define dbegin_unary()\
+ double num;\
+ int code = double_params_result(op, 1, &num);\
+ if ( code < 0 )\
+ return code
+
+#define dbegin_binary()\
+ double num[2];\
+ int code = double_params_result(op, 2, num);\
+ if ( code < 0 )\
+ return code
+
+/* ------ Arithmetic ------ */
+
+/* <dnum1> <dnum2> <dresult> .dadd <dresult> */
+private int
+zdadd(os_ptr op)
+{ dbegin_binary();
+ return double_result(op, 2, num[0] + num[1]);
+}
+
+/* <dnum1> <dnum2> <dresult> .ddiv <dresult> */
+private int
+zddiv(os_ptr op)
+{ dbegin_binary();
+ if ( num[1] == 0.0 )
+ return_error(e_undefinedresult);
+ return double_result(op, 2, num[0] / num[1]);
+}
+
+/* <dnum1> <dnum2> <dresult> .dmul <dresult> */
+private int
+zdmul(os_ptr op)
+{ dbegin_binary();
+ return double_result(op, 2, num[0] * num[1]);
+}
+
+/* <dnum1> <dnum2> <dresult> .dsub <dresult> */
+private int
+zdsub(os_ptr op)
+{ dbegin_binary();
+ return double_result(op, 2, num[0] - num[1]);
+}
+
+/* ------ Simple functions ------ */
+
+/* <dnum> <dresult> .dabs <dresult> */
+private int
+zdabs(os_ptr op)
+{ return double_unary(op, fabs);
+}
+
+/* <dnum> <dresult> .dceiling <dresult> */
+private int
+zdceiling(os_ptr op)
+{ return double_unary(op, ceil);
+}
+
+/* <dnum> <dresult> .dfloor <dresult> */
+private int
+zdfloor(os_ptr op)
+{ return double_unary(op, floor);
+}
+
+/* <dnum> <dresult> .dneg <dresult> */
+private int
+zdneg(os_ptr op)
+{ dbegin_unary();
+ return double_result(op, 1, -num);
+}
+
+/* <dnum> <dresult> .dround <dresult> */
+private int
+zdround(os_ptr op)
+{ dbegin_unary();
+ return double_result(op, 1, floor(num + 0.5));
+}
+
+/* <dnum> <dresult> .dsqrt <dresult> */
+private int
+zdsqrt(os_ptr op)
+{ dbegin_unary();
+ if ( num < 0.0 )
+ return_error(e_rangecheck);
+ return double_result(op, 1, sqrt(num));
+}
+
+/* <dnum> <dresult> .dtruncate <dresult> */
+private int
+zdtruncate(os_ptr op)
+{ dbegin_unary();
+ return double_result(op, 1, (num < 0 ? ceil(num) : floor(num)));
+}
+
+/* ------ Transcendental functions ------ */
+
+private int near
+darc(os_ptr op, double (*afunc)(P1(double)))
+{ dbegin_unary();
+ return double_result(op, 1, (*afunc)(num) * radians_to_degrees);
+}
+/* <dnum> <dresult> .darccos <dresult> */
+private int
+zdarccos(os_ptr op)
+{ return darc(op, acos);
+}
+/* <dnum> <dresult> .darcsin <dresult> */
+private int
+zdarcsin(os_ptr op)
+{ return darc(op, asin);
+}
+
+/* <dnum> <ddenom> <dresult> .datan <dresult> */
+private int
+zdatan(register os_ptr op)
+{ double result;
+ dbegin_binary();
+ if ( num[0] == 0 ) /* on X-axis, special case */
+ { if ( num[1] == 0 )
+ return_error(e_undefinedresult);
+ result = (num[1] < 0 ? 180 : 0);
+ }
+ else
+ { result = atan2(num[0], num[1]) * radians_to_degrees;
+ if ( result < 0 )
+ result += 360;
+ }
+ return double_result(op, 2, result);
+}
+
+/* <dnum> <dresult> .dcos <dresult> */
+private int
+zdcos(os_ptr op)
+{ return double_unary(op, gs_cos_degrees);
+}
+
+/* <dbase> <dexponent> <dresult> .dexp <dresult> */
+private int
+zdexp(os_ptr op)
+{ double ipart;
+ dbegin_binary();
+ if ( num[0] == 0.0 && num[1] == 0.0 )
+ return_error(e_undefinedresult);
+ if ( num[0] < 0.0 && modf(num[1], &ipart) != 0.0 )
+ return_error(e_undefinedresult);
+ return double_result(op, 2, pow(num[0], num[1]));
+}
+
+private int near
+dlog(os_ptr op, double (*lfunc)(P1(double)))
+{ dbegin_unary();
+ if ( num <= 0.0 )
+ return_error(e_rangecheck);
+ return double_result(op, 1, (*lfunc)(num));
+}
+/* <dposnum> <dresult> .dln <dresult> */
+private int
+zdln(os_ptr op)
+{ return dlog(op, log);
+}
+/* <dposnum> <dresult> .dlog <dresult> */
+private int
+zdlog(os_ptr op)
+{ return dlog(op, log10);
+}
+
+/* <dnum> <dresult> .dsin <dresult> */
+private int
+zdsin(os_ptr op)
+{ return double_unary(op, gs_sin_degrees);
+}
+
+/* ------ Comparison ------ */
+
+private int near
+dcompare(os_ptr op, int mask)
+{ double num[2];
+ int code = double_params(op, 2, num);
+ if ( code < 0 )
+ return code;
+ make_bool(op - 1,
+ (mask & (num[0] < num[1] ? 1 : num[0] > num[1] ? 4 : 2))
+ != 0);
+ pop(1);
+ return 0;
+}
+/* <dnum1> <dnum2> .deq <bool> */
+private int
+zdeq(os_ptr op)
+{ return dcompare(op, 2);
+}
+/* <dnum1> <dnum2> .dge <bool> */
+private int
+zdge(os_ptr op)
+{ return dcompare(op, 6);
+}
+/* <dnum1> <dnum2> .dgt <bool> */
+private int
+zdgt(os_ptr op)
+{ return dcompare(op, 4);
+}
+/* <dnum1> <dnum2> .dle <bool> */
+private int
+zdle(os_ptr op)
+{ return dcompare(op, 3);
+}
+/* <dnum1> <dnum2> .dlt <bool> */
+private int
+zdlt(os_ptr op)
+{ return dcompare(op, 1);
+}
+/* <dnum1> <dnum2> .dne <bool> */
+private int
+zdne(os_ptr op)
+{ return dcompare(op, 5);
+}
+
+/* ------ Conversion ------ */
+
+/* Take the easy way out.... */
+#define max_chars 50
+
+/* <dnum> <dresult> .cvd <dresult> */
+private int
+zcvd(os_ptr op)
+{ dbegin_unary();
+ return double_result(op, 1, num);
+}
+
+/* <string> <dresult> .cvsd <dresult> */
+private int
+zcvsd(os_ptr op)
+{ int code = double_params_result(op, 0, NULL);
+ double num;
+ char buf[max_chars + 2];
+ char *str = buf;
+ uint len;
+ char end;
+
+ if ( code < 0 )
+ return code;
+ check_read_type(op[-1], t_string);
+ len = r_size(op - 1);
+ if ( len > max_chars )
+ return_error(e_limitcheck);
+ memcpy(str, op[-1].value.bytes, len);
+ /*
+ * We check syntax in the following way: we remove whitespace,
+ * verify that the string contains only [0123456789+-.dDeE],
+ * then append a $ and then check that the next character after
+ * the scanned number is a $.
+ */
+ while ( len > 0 && isspace(*str) )
+ ++str, --len;
+ while ( len > 0 && isspace(str[len - 1]) )
+ --len;
+ str[len] = 0;
+ if ( strspn(str, "0123456789+-.dDeE") != len )
+ return_error(e_syntaxerror);
+ strcat(str, "$");
+ if ( sscanf(str, "%lf%c", &num, &end) != 2 || end != '$' )
+ return_error(e_syntaxerror);
+ return double_result(op, 1, num);
+}
+
+/* <dnum> .dcvi <int> */
+private int
+zdcvi(os_ptr op)
+{
+#define alt_min_long (-1L << (arch_sizeof_long * 8 - 1))
+#define alt_max_long (~(alt_min_long))
+ static const double min_int_real = (alt_min_long * 1.0 - 1);
+ static const double max_int_real = (alt_max_long * 1.0 + 1);
+ double num;
+ int code = double_params(op, 1, &num);
+ if ( code < 0 )
+ return code;
+
+ if ( num < min_int_real || num > max_int_real )
+ return_error(e_rangecheck);
+ make_int(op, (long)num); /* truncates toward 0 */
+ return 0;
+}
+
+/* <dnum> .dcvr <real> */
+private int
+zdcvr(os_ptr op)
+{
+#define b30 (0x40000000L * 1.0)
+#define max_mag (0xffffff * b30 * b30 * b30 * 0x4000)
+ static const float min_real = -max_mag;
+ static const float max_real = max_mag;
+#undef b30
+#undef max_mag
+ double num;
+ int code = double_params(op, 1, &num);
+ if ( code < 0 )
+ return code;
+ if ( num < min_real || num > max_real )
+ return_error(e_rangecheck);
+ make_real(op, (float)num);
+ return 0;
+}
+
+/* <dnum> <string> .dcvs <substring> */
+private int
+zdcvs(os_ptr op)
+{ double num;
+ int code = double_params(op - 1, 1, &num);
+ char str[max_chars + 1];
+ int len;
+
+ if ( code < 0 )
+ return code;
+ check_write_type(*op, t_string);
+ /*
+ * To get fully accurate output results for IEEE double-
+ * precision floats (53 bits of mantissa), the ANSI
+ * %g default of 6 digits is not enough; 16 are needed.
+ * Unfortunately, using %.16g produces unfortunate artifacts such as
+ * 1.2 printing as 1.200000000000005. Therefore, we print using %g,
+ * and if the result isn't accurate enough, print again
+ * using %.16g.
+ */
+ { double scanned;
+ sprintf(str, "%g", num);
+ sscanf(str, "%lf", &scanned);
+ if ( scanned != num )
+ sprintf(str, "%.16g", num);
+ }
+ len = strlen(str);
+ if ( len > r_size(op) )
+ return_error(e_rangecheck);
+ memcpy(op->value.bytes, str, len);
+ op[-1] = *op;
+ r_set_size(op - 1, len);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization table ------ */
+
+BEGIN_OP_DEFS(zdouble_op_defs) {
+ /* Arithmetic */
+ {"3.dadd", zdadd},
+ {"3.ddiv", zddiv},
+ {"3.dmul", zdmul},
+ {"3.dsub", zdsub},
+ /* Simple functions */
+ {"2.dabs", zdabs},
+ {"2.dceiling", zdceiling},
+ {"2.dfloor", zdfloor},
+ {"2.dneg", zdneg},
+ {"2.dround", zdround},
+ {"2.dsqrt", zdsqrt},
+ {"2.dtruncate", zdtruncate},
+ /* Transcendental functions */
+ {"2.darccos", zdarccos},
+ {"2.darcsin", zdarcsin},
+ {"3.datan", zdatan},
+ {"2.dcos", zdcos},
+ {"3.dexp", zdexp},
+ {"2.dln", zdln},
+ {"2.dlog", zdlog},
+ {"2.dsin", zdsin},
+ /* Comparison */
+ {"2.deq", zdeq},
+ {"2.dge", zdge},
+ {"2.dgt", zdgt},
+ {"2.dle", zdle},
+ {"2.dlt", zdlt},
+ {"2.dne", zdne},
+ /* Conversion */
+ {"2.cvd", zcvd},
+ {"2.cvsd", zcvsd},
+ {"1.dcvi", zdcvi},
+ {"1.dcvr", zdcvr},
+ {"2.dcvs", zdcvs},
+END_OP_DEFS(0) }
+
+/* ------ Internal procedures ------ */
+
+/* Get some double arguments. */
+private int near
+double_params(os_ptr op, int count, double *pval)
+{ pval += count;
+ while ( --count >= 0 )
+ { switch ( r_type(op) )
+ {
+ case t_real:
+ *--pval = op->value.realval;
+ break;
+ case t_integer:
+ *--pval = op->value.intval;
+ break;
+ case t_string:
+ if ( !r_has_attr(op, a_read) ||
+ r_size(op) != sizeof(double)
+ )
+ return_error(e_typecheck);
+ --pval;
+ memcpy(pval, op->value.bytes, sizeof(double));
+ break;
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ return_error(e_typecheck);
+ }
+ op--;
+ }
+ return 0;
+}
+
+/* Get some double arguments, and check for a double result. */
+private int near
+double_params_result(os_ptr op, int count, double *pval)
+{ check_write_type(*op, t_string);
+ if ( r_size(op) != sizeof(double) )
+ return_error(e_typecheck);
+ return double_params(op - 1, count, pval);
+}
+
+/* Return a double result. */
+private int near
+double_result(os_ptr op, int count, double result)
+{ os_ptr op1 = op - count;
+ ref_assign_inline(op1, op);
+ memcpy(op1->value.bytes, &result, sizeof(double));
+ pop(count);
+ return 0;
+}
+
+/* Apply a unary function to a double operand. */
+private int near
+double_unary(os_ptr op, double (*func)(P1(double)))
+{ dbegin_unary();
+ return double_result(op, 1, (*func)(num));
+}
diff --git a/gs/src/zdpnext.c b/gs/src/zdpnext.c
new file mode 100644
index 000000000..e81aeb253
--- /dev/null
+++ b/gs/src/zdpnext.c
@@ -0,0 +1,438 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdpnext.c */
+/* NeXT Display PostScript extensions */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscspace.h" /* for iimage.h */
+#include "gsmatrix.h"
+#include "gsiparam.h" /* for iimage.h */
+#include "gxcvalue.h"
+#include "gxsample.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "iimage.h"
+
+/*
+ * Miscellaneous notes:
+ *
+ * composite / dissolve respect destination clipping (both clip & viewclip),
+ * but ignore source clipping.
+ * composite / dissolve must handle overlapping source/destination correctly.
+ * compositing converts the source to the destination's color model
+ * (including halftoning if needed).
+ */
+
+/*
+ * Define the compositing operations. Eventually this will be moved to
+ * a header file in the library. These values must match the ones in
+ * dpsNeXT.h.
+ */
+typedef enum {
+ NX_CLEAR = 0,
+ NX_COPY,
+ NX_SOVER,
+ NX_SIN,
+ NX_SOUT,
+ NX_SATOP,
+ NX_DOVER,
+ NX_DIN,
+ NX_DOUT,
+ NX_DATOP,
+ NX_XOR,
+ NX_PLUSD,
+ NX_HIGHLIGHT, /* only for compositerect */
+ NX_PLUSL,
+#define NX_composite_last NX_PLUSL
+#define NX_compositerect_last NX_PLUSL
+ NX_DISSOLVE /* fake value used internally for dissolve */
+} gs_composite_op_t;
+
+/*
+ * Define the parameters for a compositing operation at the library level.
+ * Of course this too belongs in the library.
+ */
+typedef struct gs_composite_params_s {
+ gs_composite_op_t cop;
+ gx_color_value delta; /* only for dissolve */
+ byte src_value[5*2]; /* only if src == 0 or !src_has_alpha */
+} gs_composite_params_t;
+
+/* Define a local structure for holding compositing operands. */
+typedef struct gs_composite_operands_s {
+ double src_rect[4]; /* x, y, width, height */
+ gs_state *src_gs;
+ double dest_pt[2]; /* x, y */
+} gs_composite_operands_t;
+
+/* Imported procedures */
+int zimage_multiple(P2(os_ptr op, bool has_alpha)); /* in zcolor1.c */
+
+/* Forward references */
+private int composite_operands(P2(gs_composite_operands_t *, os_ptr));
+private int rect_param(P2(os_ptr, double [4]));
+
+/* <width> <height> <bits/comp> <matrix> */
+/* <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> alphaimage - */
+/* <datasrc> false <ncomp> alphaimage - */
+private int
+zalphaimage(register os_ptr op)
+{ /* Essentially the whole implementation is shared with colorimage. */
+ return zimage_multiple(op, true);
+}
+
+/* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <op> */
+/* composite - */
+private int
+zcomposite(register os_ptr op)
+{ gs_composite_operands_t operands;
+ int code = composite_operands(&operands, op);
+ gs_composite_params_t params;
+
+ if ( code < 0 )
+ return code;
+ check_int_leu(*op, NX_composite_last);
+ params.cop = (gs_composite_op_t)op->value.intval;
+ if ( params.cop == NX_HIGHLIGHT )
+ return_error(e_rangecheck);
+ /****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* <destx> <desty> <width> <height> <op> compositerect - */
+private int
+zcompositerect(register os_ptr op)
+{ double dest_rect[4];
+ gs_composite_params_t params;
+ int code = rect_param(op - 1, dest_rect);
+
+ if ( code < 0 )
+ return code;
+ check_int_leu(*op, NX_compositerect_last);
+ params.cop = (gs_composite_op_t)op->value.intval;
+ /****** SET src_value ******/
+ /****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <delta> */
+/* dissolve - */
+private int
+zdissolve(register os_ptr op)
+{ gs_composite_operands_t operands;
+ int code = composite_operands(&operands, op);
+ gs_composite_params_t params;
+ double delta;
+
+ if ( code < 0 )
+ return code;
+ code = real_param(op, &delta);
+ if ( code < 0 )
+ return code;
+ if ( delta < 0 || delta > 1 )
+ return_error(e_rangecheck);
+ params.cop = NX_DISSOLVE;
+ params.delta = (gx_color_value)(delta * gx_max_color_value);
+ /****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdpnext_op_defs) {
+ {"7alphaimage", zalphaimage},
+ {"8composite", zcomposite},
+ {"5compositerect", zcompositerect},
+ {"8dissolve", zdissolve},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Collect a rect operand. */
+private int
+rect_param(os_ptr op, double rect[4])
+{ int code = num_params(op, 4, rect);
+
+ if ( code < 0 )
+ return code;
+ if ( rect[2] < 0 )
+ rect[0] += rect[2], rect[2] = -rect[2];
+ if ( rect[3] < 0 )
+ rect[1] += rect[3], rect[3] = -rect[3];
+ return code;
+}
+
+/* Collect parameters for a compositing operation. */
+private int
+composite_operands(gs_composite_operands_t *pco, os_ptr op)
+{ int code = rect_param(op - 4, pco->src_rect);
+
+ if ( code < 0 ||
+ (code = num_params(op - 1, 2, pco->dest_pt)) < 0
+ )
+ return code;
+ if ( r_has_type(op - 3, t_null) )
+ pco->src_gs = igs;
+ else {
+ check_stype(op[-3], st_igstate_obj);
+ check_read(op[-3]);
+ pco->src_gs = igstate_ptr(op - 3);
+ }
+ return 0;
+}
+
+/* ------ Library procedures ------ */
+
+/*
+ * Composite two arrays of (premultiplied) pixel values.
+ * Legal values of bits_per_value are 1, 2, 4, 8, and 16.
+ * src_has_alpha indicates whether or not the source has alpha values;
+ * if not, the alpha value is constant (in the parameter structure).
+ * Legal values of values_per_pixel are 1-5, including alpha.
+ * (The source has one fewer value per pixel if it doesn't have alpha.)
+ * src_data = 0 is legal and indicates that the source value is constant,
+ * specified in the parameter structure.
+ *
+ * The current implementation is simple but inefficient. We'll speed it up
+ * later if necessary.
+ */
+private int
+composite_values(byte *dest_data, int dest_x, const byte *src_data, int src_x,
+ int bits_per_value, int values_per_pixel, bool src_has_alpha,
+ uint num_pixels, const gs_composite_params_t *pcp, gs_memory_t *mem)
+{ int src_vpp = values_per_pixel - (src_has_alpha ? 0 : 1);
+ int bytes_per_value = bits_per_value >> 3;
+ int dest_bpp, src_bpp;
+ uint highlight_value = (1 << bits_per_value) - 1;
+ byte *dbuf = 0;
+ byte *sbuf = 0;
+ int dx;
+ byte *dptr;
+ const byte *sptr;
+
+ if ( bytes_per_value == 0 ) {
+ /*
+ * Unpack the operands now, and repack the results after the
+ * operation.
+ */
+ sample_unpack_proc((*unpack_proc));
+ static const bits16 lookup2x2[16] = {
+#if arch_is_big_endian
+# define map2(a,b) (a * 0x5500 + b * 0x0055)
+#else
+# define map2(a,b) (a * 0x0055 + b * 0x5500)
+#endif
+#define map4x2(a) map2(a,0), map2(a,1), map2(a,2), map2(a,3)
+ map4x2(0), map4x2(1), map4x2(2), map4x2(3)
+#undef map2
+#undef map4x2
+ };
+ static const byte lookup4[16] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ const sample_lookup_t *lookup;
+ int sx;
+
+ switch ( bits_per_value ) {
+ case 1:
+ unpack_proc = sample_unpack_1;
+ lookup = sample_lookup_1_identity;
+ break;
+ case 2:
+ unpack_proc = sample_unpack_2;
+ lookup = (const sample_lookup_t *)lookup2x2;
+ break;
+ case 4:
+ unpack_proc = sample_unpack_4;
+ lookup = (const sample_lookup_t *)lookup4;
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ /*
+ * Because of partial input bytes due to dest_/src_x,
+ * we may need as many as 3 extra pixels in the buffers.
+ */
+ dbuf = gs_alloc_bytes(mem, (num_pixels + 3) * values_per_pixel,
+ "composite_values(dbuf)");
+ if ( src_data )
+ sbuf = gs_alloc_bytes(mem, (num_pixels + 3) * src_vpp,
+ "composite_values(sbuf)");
+ if ( (sbuf == 0 && src_data) || dbuf == 0 ) {
+ gs_free_object(mem, sbuf, "composite_values(sbuf)");
+ gs_free_object(mem, dbuf, "composite_values(dbuf)");
+ return_error(e_VMerror);
+ }
+ dptr = (*unpack_proc)(dbuf, &dx, dest_data, dest_x,
+ ((dest_x + num_pixels) * bits_per_value *
+ values_per_pixel + 7) >> 3,
+ lookup, 1);
+ if ( src_data )
+ sptr = (*unpack_proc)(sbuf, &sx, src_data, src_x,
+ ((src_x + num_pixels) * bits_per_value *
+ src_vpp + 7) >> 3,
+ lookup, 1);
+ src_vpp = bytes_per_value = 1;
+ dest_bpp = values_per_pixel;
+ src_bpp = src_vpp;
+ dptr += dx * dest_bpp;
+ sptr += sx * src_bpp;
+ } else {
+ dest_bpp = bytes_per_value * values_per_pixel;
+ src_bpp = bytes_per_value * src_vpp;
+ dptr = dest_data + dest_x * dest_bpp;
+ sptr = src_data + src_x * src_bpp;
+ }
+ {
+#define bits16_get(p) ( ((p)[0] << 8) + (p)[1] )
+#define bits16_put(p,v) ( (p)[0] = (byte)((v) >> 8), (p)[1] = (byte)(v) )
+ uint max_value = (1 << bits_per_value) - 1;
+ uint delta_v = pcp->delta * max_value / gx_max_color_value;
+ int src_no_alpha_j;
+ uint src_alpha;
+ uint x;
+
+ if ( src_has_alpha )
+ src_no_alpha_j = -1;
+ else {
+ src_alpha =
+ (bytes_per_value == 1 ?
+ pcp->src_value[values_per_pixel - 1] :
+ bits16_get(&pcp->src_value[src_bpp - 2]));
+ src_no_alpha_j = 0;
+ }
+ for ( x = 0; x < num_pixels; ++x ) {
+ uint dest_alpha;
+ int j;
+
+ if ( !src_data )
+ sptr = pcp->src_value;
+ if ( bytes_per_value == 1 ) {
+ dest_alpha = dptr[values_per_pixel - 1];
+ if ( src_has_alpha )
+ src_alpha = sptr[values_per_pixel - 1];
+ } else {
+ dest_alpha =
+ bits16_get(&dptr[dest_bpp - 2]);
+ if ( src_has_alpha )
+ src_alpha =
+ bits16_get(&sptr[src_bpp - 2]);
+ }
+#define fr(v, a) ((v) * (a) / max_value)
+#define nfr(v, a) ((v) * (max_value - (a)) / max_value)
+ for ( j = values_per_pixel; --j != 0; ) {
+ uint dest_v, src_v, result;
+#define set_clamped(r, v) if ( (r = (v)) > max_value ) r = max_value
+
+ if ( bytes_per_value == 1 ) {
+ dest_v = *dptr;
+ src_v = (j == src_no_alpha_j ? src_alpha : *sptr++);
+ } else {
+ dest_v = bits16_get(dptr);
+ if ( j == src_no_alpha_j )
+ src_v = src_alpha;
+ else
+ src_v = bits16_get(sptr), sptr += 2;
+ }
+ switch ( pcp->cop ) {
+ case NX_CLEAR:
+ result = 0;
+ break;
+ case NX_COPY:
+ result = src_v;
+ break;
+ case NX_PLUSD:
+ /*
+ * This is the only case where we have to worry about
+ * clamping a possibly negative result.
+ */
+ result = src_v + dest_v;
+ result = (result < max_value ? 0 : result - max_value);
+ break;
+ case NX_PLUSL:
+ set_clamped(result, src_v + dest_v);
+ break;
+ case NX_SOVER:
+ set_clamped(result, src_v + nfr(dest_v, src_alpha));
+ break;
+ case NX_DOVER:
+ set_clamped(result, nfr(src_v, dest_alpha) + dest_v);
+ break;
+ case NX_SIN:
+ result = fr(src_v, dest_alpha);
+ break;
+ case NX_DIN:
+ result = fr(dest_v, src_alpha);
+ break;
+ case NX_SOUT:
+ result = nfr(src_v, dest_alpha);
+ break;
+ case NX_DOUT:
+ result = nfr(dest_v, src_alpha);
+ break;
+ case NX_SATOP:
+ set_clamped(result, fr(src_v, dest_alpha) +
+ nfr(dest_v, src_alpha));
+ break;
+ case NX_DATOP:
+ set_clamped(result, nfr(src_v, dest_alpha) +
+ fr(dest_v, src_alpha));
+ break;
+ case NX_XOR:
+ set_clamped(result, nfr(src_v, dest_alpha) +
+ nfr(dest_v, src_alpha));
+ break;
+ case NX_HIGHLIGHT:
+ /*
+ * Bizarre but true: this operation converts white and
+ * light gray into each other, and leaves all other values
+ * unchanged. We only implement it properly for gray-scale
+ * devices.
+ */
+ if ( j != 0 && !((src_v ^ highlight_value) & ~1) )
+ result = src_v ^ 1;
+ else
+ result = src_v;
+ break;
+ case NX_DISSOLVE:
+ result = fr(src_v, delta_v) + nfr(dest_v, delta_v);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if ( bytes_per_value == 1 )
+ *dptr++ = (byte)result;
+ else
+ bits16_put(dptr, result), dptr += 2;
+ }
+ }
+ }
+ if ( dbuf ) {
+ /*
+ * Pack pixels back into the destination. This is modeled on
+ * the line_accum macros in gxcindex.h.
+ */
+ /****** TBC ******/
+ gs_free_object(mem, sbuf, "composite_values(sbuf)");
+ gs_free_object(mem, dbuf, "composite_values(dbuf)");
+ }
+ return 0;
+}
diff --git a/gs/src/zdps.c b/gs/src/zdps.c
new file mode 100644
index 000000000..6460d24da
--- /dev/null
+++ b/gs/src/zdps.c
@@ -0,0 +1,182 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdps.c */
+/* Display PostScript extensions */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstate.h"
+#include "gsdps.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+
+/* Import the user name table. */
+extern ref user_names;
+
+/* ------ Graphics state ------ */
+
+/* <screen_index> <x> <y> .setscreenphase - */
+private int
+zsetscreenphase(register os_ptr op)
+{ int code;
+ long x, y;
+
+ check_type(op[-2], t_integer);
+ check_type(op[-1], t_integer);
+ check_type(*op, t_integer);
+ x = op[-1].value.intval;
+ y = op->value.intval;
+ if ( x != (int)x || y != (int)y ||
+ op[-2].value.intval < -1 ||
+ op[-2].value.intval >= gs_color_select_count
+ )
+ return_error(e_rangecheck);
+ code = gs_setscreenphase(igs, (int)x, (int)y,
+ (gs_color_select_t)op[-2].value.intval);
+ if ( code >= 0 )
+ pop(3);
+ return code;
+}
+
+/* <screen_index> .currentscreenphase <x> <y> */
+private int near
+zcurrentscreenphase(register os_ptr op)
+{ gs_int_point phase;
+ int code;
+
+ check_type(*op, t_integer);
+ if ( op->value.intval < -1 ||
+ op->value.intval >= gs_color_select_count
+ )
+ return_error(e_rangecheck);
+ code = gs_currentscreenphase(igs, &phase,
+ (gs_color_select_t)op->value.intval);
+ if ( code < 0 )
+ return code;
+ push(1);
+ make_int(op - 1, phase.x);
+ make_int(op, phase.y);
+ return 0;
+}
+
+/* ------ View clipping ------ */
+
+/* - viewclip - */
+private int
+zviewclip(register os_ptr op)
+{ return gs_viewclip(igs);
+}
+
+/* - eoviewclip - */
+private int
+zeoviewclip(register os_ptr op)
+{ return gs_eoviewclip(igs);
+}
+
+/* - initviewclip - */
+private int
+zinitviewclip(register os_ptr op)
+{ return gs_initviewclip(igs);
+}
+
+/* - viewclippath - */
+private int
+zviewclippath(register os_ptr op)
+{ return gs_viewclippath(igs);
+}
+
+/* ------ User names ------ */
+
+/* <index> <name> defineusername - */
+private int
+zdefineusername(register os_ptr op)
+{ ref uname;
+
+ check_int_ltu(op[-1], max_array_size);
+ check_type(*op, t_name);
+ if ( array_get(&user_names, op[-1].value.intval, &uname) >= 0 )
+ { switch ( r_type(&uname) )
+ {
+ case t_null:
+ break;
+ case t_name:
+ if ( name_eq(&uname, op) )
+ goto ret;
+ /* falls through */
+ default:
+ return_error(e_invalidaccess);
+ }
+ }
+ else
+ { /* Expand the array. */
+ ref new_array;
+ uint old_size = r_size(&user_names);
+ uint new_size = (uint)op[-1].value.intval + 1;
+
+ if ( new_size < 100 )
+ new_size = 100;
+ else if ( new_size > max_array_size / 2 )
+ new_size = max_array_size;
+ else if ( new_size >> 1 < old_size )
+ new_size = (old_size > max_array_size / 2 ? max_array_size :
+ old_size << 1);
+ else
+ new_size <<= 1;
+ /* The user name array is always allocated in system VM, */
+ /* because it must be immune to save/restore. */
+ { uint save_space = icurrent_space;
+ int code;
+
+ ialloc_set_space(idmemory, avm_system);
+ code = ialloc_ref_array(&new_array, a_all, new_size,
+ "defineusername(new)");
+ if ( code < 0 ) {
+ ialloc_set_space(idmemory, save_space);
+ return code;
+ }
+ refcpy_to_new(new_array.value.refs, user_names.value.refs,
+ old_size);
+ refset_null(new_array.value.refs + old_size,
+ new_size - old_size);
+ ifree_ref_array(&user_names, "defineusername(old)");
+ ialloc_set_space(idmemory, save_space);
+ }
+ user_names = new_array;
+ }
+ ref_assign(user_names.value.refs + op[-1].value.intval, op);
+ret: pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdps_op_defs) {
+ /* Graphics state */
+ {"1.currentscreenphase", zcurrentscreenphase},
+ {"3.setscreenphase", zsetscreenphase},
+ /* View clipping */
+ {"0eoviewclip", zeoviewclip},
+ {"0initviewclip", zinitviewclip},
+ {"0viewclip", zviewclip},
+ {"0viewclippath", zviewclippath},
+ /* User names */
+ {"2defineusername", zdefineusername},
+END_OP_DEFS(0) }
+
diff --git a/gs/src/zdps1.c b/gs/src/zdps1.c
new file mode 100644
index 000000000..c7e18b820
--- /dev/null
+++ b/gs/src/zdps1.c
@@ -0,0 +1,417 @@
+/* Copyright (C) 1990, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdps1.c */
+/* Level 2 / Display PostScript graphics extensions */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gspath.h"
+#include "gspath2.h"
+#include "gsstate.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+
+/* Imported data */
+extern op_proc_p zcopy_procs[t_next_index];
+
+/* Forward references */
+private int gstate_unshare(P1(os_ptr));
+
+/* Structure descriptors */
+public_st_igstate_obj();
+
+/* Initialize by adding an entry for gstates to the `copy' operator. */
+/* This is done with a hack -- we know that gstates are the only */
+/* t_astruct subtype that implements copy. */
+private void
+zdps1_init(void)
+{ /* zdevice2_init might have already initialized this. */
+ /* A hack on top of a hack! */
+ if ( zcopy_procs[t_astruct] == zcopy_procs[t_struct] )
+ zcopy_procs[t_astruct] = zcopy_gstate;
+}
+
+/* ------ Graphics state ------ */
+
+/* <bool> setstrokeadjust - */
+private int
+zsetstrokeadjust(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_setstrokeadjust(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - currentstrokeadjust <bool> */
+private int
+zcurrentstrokeadjust(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentstrokeadjust(igs));
+ return 0;
+}
+
+/* ------ Graphics state objects ------ */
+
+/* Check to make sure that all the elements of a graphics state */
+/* can be stored in the given allocation space. */
+/****** DOESN'T CHECK THE NON-REFS. ****** */
+private int
+gstate_check_space(int_gstate *isp, uint space)
+{
+#define gsref_check(p) store_check_space(space, p)
+ int_gstate_map_refs(isp, gsref_check);
+#undef gsref_check
+ return 0;
+}
+
+/* - gstate <gstate> */
+int
+zgstate(register os_ptr op)
+{ int code = gstate_check_space(istate, icurrent_space);
+ igstate_obj *pigo;
+ gs_state *pnew;
+ int_gstate *isp;
+
+ if ( code < 0 )
+ return code;
+ pigo = ialloc_struct(igstate_obj, &st_igstate_obj, "gstate");
+ if ( pigo == 0 )
+ return_error(e_VMerror);
+ pnew = gs_state_copy(igs, imemory);
+ if ( pnew == 0 )
+ { ifree_object(pigo, "gstate");
+ return_error(e_VMerror);
+ }
+ isp = gs_int_gstate(pnew);
+ int_gstate_map_refs(isp, ref_mark_new);
+ push(1);
+ /*
+ * Since igstate_obj isn't a ref, but only contains a ref,
+ * save won't clear its l_new bit automatically, and
+ * restore won't set it automatically; we have to make sure
+ * this ref is on the changes chain.
+ */
+ make_iastruct(op, a_all, pigo);
+ make_null(&pigo->gstate);
+ ref_save(op, &pigo->gstate, "gstate");
+ make_istruct_new(&pigo->gstate, 0, pnew);
+ return 0;
+}
+
+/* copy for gstates */
+int
+zcopy_gstate(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ gs_state *pgs;
+ gs_state *pgs1;
+ int_gstate *pistate;
+ gs_memory_t *mem;
+ int code;
+ check_stype(*op, st_igstate_obj);
+ check_stype(*op1, st_igstate_obj);
+ check_write(*op);
+ code = gstate_unshare(op);
+ if ( code < 0 )
+ return code;
+ pgs = igstate_ptr(op);
+ pgs1 = igstate_ptr(op1);
+ pistate = gs_int_gstate(pgs);
+ code = gstate_check_space(gs_int_gstate(pgs1), r_space(op));
+ if ( code < 0 ) return code;
+#define gsref_save(p) ref_save(op, p, "copygstate")
+ int_gstate_map_refs(pistate, gsref_save);
+#undef gsref_save
+ mem = gs_state_swap_memory(pgs, imemory);
+ code = gs_copygstate(pgs, pgs1);
+ gs_state_swap_memory(pgs, mem);
+ if ( code < 0 )
+ return code;
+ int_gstate_map_refs(pistate, ref_mark_new);
+ *op1 = *op;
+ pop(1);
+ return 0;
+}
+
+/* <gstate> currentgstate <gstate> */
+int
+zcurrentgstate(register os_ptr op)
+{ gs_state *pgs;
+ int_gstate *pistate;
+ int code;
+ gs_memory_t *mem;
+ check_stype(*op, st_igstate_obj);
+ check_write(*op);
+ code = gstate_unshare(op);
+ if ( code < 0 )
+ return code;
+ pgs = igstate_ptr(op);
+ pistate = gs_int_gstate(pgs);
+ code = gstate_check_space(istate, r_space(op));
+ if ( code < 0 ) return code;
+#define gsref_save(p) ref_save(op, p, "currentgstate")
+ int_gstate_map_refs(pistate, gsref_save);
+#undef gsref_save
+ mem = gs_state_swap_memory(pgs, imemory);
+ code = gs_currentgstate(pgs, igs);
+ gs_state_swap_memory(pgs, mem);
+ if ( code < 0 )
+ return code;
+ int_gstate_map_refs(pistate, ref_mark_new);
+ return 0;
+}
+
+/* <gstate> setgstate - */
+int
+zsetgstate(register os_ptr op)
+{ int code;
+ check_stype(*op, st_igstate_obj);
+ check_read(*op);
+ code = gs_setgstate(igs, igstate_ptr(op));
+ if ( code < 0 ) return code;
+ pop(1);
+ return 0;
+}
+
+/* ------ Rectangles ------- */
+
+/* We preallocate a short list for rectangles, because */
+/* the rectangle operators usually will involve very few rectangles. */
+#define max_local_rect 5
+typedef struct local_rects_s {
+ gs_rect *pr;
+ uint count;
+ gs_rect rl[max_local_rect];
+} local_rects;
+
+/* Forward references */
+private int rect_get(P2(local_rects *, os_ptr));
+private void rect_release(P1(local_rects *));
+
+/* <x> <y> <width> <height> .rectappend - */
+/* <numarray|numstring> .rectappend - */
+private int
+zrectappend(os_ptr op)
+{ local_rects lr;
+ int npop = rect_get(&lr, op);
+ int code;
+ if ( npop < 0 ) return npop;
+ code = gs_rectappend(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if ( code < 0 ) return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectclip - */
+/* <numarray|numstring> rectclip - */
+private int
+zrectclip(os_ptr op)
+{ local_rects lr;
+ int npop = rect_get(&lr, op);
+ int code;
+ if ( npop < 0 ) return npop;
+ code = gs_rectclip(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if ( code < 0 ) return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectfill - */
+/* <numarray|numstring> rectfill - */
+private int
+zrectfill(os_ptr op)
+{ local_rects lr;
+ int npop = rect_get(&lr, op);
+ int code;
+ if ( npop < 0 ) return npop;
+ code = gs_rectfill(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if ( code < 0 ) return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectstroke - */
+/* <numarray|numstring> rectstroke - */
+private int
+zrectstroke(os_ptr op)
+{ gs_matrix mat;
+ local_rects lr;
+ int npop, code;
+ if ( read_matrix(op, &mat) >= 0 )
+ { /* Concatenate the matrix to the CTM just before */
+ /* stroking the path. */
+ npop = rect_get(&lr, op - 1);
+ if ( npop < 0 ) return npop;
+ code = gs_rectstroke(igs, lr.pr, lr.count, &mat);
+ npop++;
+ }
+ else
+ { /* No matrix. */
+ npop = rect_get(&lr, op);
+ if ( npop < 0 ) return npop;
+ code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *)0);
+ }
+ rect_release(&lr);
+ if ( code < 0 ) return code;
+ pop(npop);
+ return 0;
+}
+
+/* --- Internal routines --- */
+
+/* Get rectangles from the stack. */
+/* Return the number of elements to pop (>0) if OK, <0 if error. */
+private int
+rect_get(local_rects *plr, os_ptr op)
+{ int format, code;
+ uint n, count;
+ gs_rect *pr;
+ double rv[4];
+
+ switch ( r_type(op) )
+ {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ case t_string:
+ code = num_array_format(op);
+ if ( code < 0 )
+ return code;
+ format = code;
+ count = num_array_size(op, format);
+ if ( count % 4 )
+ return_error(e_rangecheck);
+ count /= 4;
+ break;
+ default: /* better be 4 numbers */
+ code = num_params(op, 4, rv);
+ if ( code < 0 )
+ return code;
+ plr->pr = plr->rl;
+ plr->count = 1;
+ plr->rl[0].q.x = (plr->rl[0].p.x = rv[0]) + rv[2];
+ plr->rl[0].q.y = (plr->rl[0].p.y = rv[1]) + rv[3];
+ return 4;
+ }
+ plr->count = count;
+ if ( count <= max_local_rect )
+ pr = plr->rl;
+ else
+ { pr = (gs_rect *)ialloc_byte_array(count, sizeof(gs_rect),
+ "rect_get");
+ if ( pr == 0 )
+ return_error(e_VMerror);
+ }
+ plr->pr = pr;
+ for ( n = 0; n < count; n++, pr++ )
+ { ref rnum;
+ int i;
+
+ for ( i = 0; i < 4; i++ )
+ { code = num_array_get((const ref *)op, format,
+ (n << 2) + i, &rnum);
+ switch ( code )
+ {
+ case t_integer:
+ rv[i] = rnum.value.intval;
+ break;
+ case t_real:
+ rv[i] = rnum.value.realval;
+ break;
+ default: /* code < 0 */
+ return code;
+ }
+ }
+ pr->q.x = (pr->p.x = rv[0]) + rv[2];
+ pr->q.y = (pr->p.y = rv[1]) + rv[3];
+ }
+ return 1;
+}
+
+/* Release the rectangle list if needed. */
+private void
+rect_release(local_rects *plr)
+{ if ( plr->pr != plr->rl )
+ ifree_object(plr->pr, "rect_release");
+}
+
+/* ------ Graphics state ------ */
+
+/* <llx> <lly> <urx> <ury> setbbox - */
+int
+zsetbbox(register os_ptr op)
+{ double box[4];
+
+ int code = num_params(op, 4, box);
+ if ( code < 0 ) return code;
+ if ( (code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0 )
+ return code;
+ pop(4);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdps1_l2_op_defs) {
+ op_def_begin_level2(),
+ /* Graphics state */
+ {"0currentstrokeadjust", zcurrentstrokeadjust},
+ {"1setstrokeadjust", zsetstrokeadjust},
+ /* Graphics state objects */
+ {"1currentgstate", zcurrentgstate},
+ {"0gstate", zgstate},
+ {"1setgstate", zsetgstate},
+ /* Rectangles */
+ {"1.rectappend", zrectappend},
+ {"1rectclip", zrectclip},
+ {"1rectfill", zrectfill},
+ {"1rectstroke", zrectstroke},
+ /* Graphics state components */
+ {"4setbbox", zsetbbox},
+END_OP_DEFS(zdps1_init) }
+
+/* ------ Internal routines ------ */
+
+/* Ensure that a gstate is not shared with an outer save level. */
+/* *op is of type t_astruct(igstate_obj). */
+private int
+gstate_unshare(os_ptr op)
+{ ref *pgsref = &r_ptr(op, igstate_obj)->gstate;
+ gs_state *pgs = r_ptr(pgsref, gs_state);
+ gs_state *pnew;
+ int_gstate *isp;
+ if ( !ref_must_save(pgsref) )
+ return 0;
+ /* Copy the gstate. */
+ pnew = gs_gstate(pgs);
+ if ( pnew == 0 )
+ return_error(e_VMerror);
+ isp = gs_int_gstate(pnew);
+ int_gstate_map_refs(isp, ref_mark_new);
+ ref_do_save(op, pgsref, "gstate_unshare");
+ make_istruct_new(pgsref, 0, pnew);
+ return 0;
+}
diff --git a/gs/src/zfbcp.c b/gs/src/zfbcp.c
new file mode 100644
index 000000000..2bba9c2cd
--- /dev/null
+++ b/gs/src/zfbcp.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfbcp.c */
+/* (T)BCP filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "ifilter.h"
+
+/* Define null handlers for the BCP out-of-band signals. */
+private int
+no_bcp_signal_interrupt(stream_state *st)
+{ return 0;
+}
+private int
+no_bcp_request_status(stream_state *st)
+{ return 0;
+}
+
+/* <source> BCPEncode/filter <file> */
+/* <source> <dict_ignored> BCPEncode/filter <file> */
+private int
+zBCPE(os_ptr op)
+{ return filter_write_simple(op, &s_BCPE_template);
+}
+
+/* <target> BCPDecode/filter <file> */
+/* <target> <dict_ignored> BCPDecode/filter <file> */
+private int
+zBCPD(os_ptr op)
+{ stream_BCPD_state state;
+ state.signal_interrupt = no_bcp_signal_interrupt;
+ state.request_status = no_bcp_request_status;
+ return filter_read(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ &s_BCPD_template, (stream_state *)&state, 0);
+}
+
+/* <source> TBCPEncode/filter <file> */
+/* <source> <dict_ignored> TBCPEncode/filter <file> */
+private int
+zTBCPE(os_ptr op)
+{ return filter_write_simple(op, &s_TBCPE_template);
+}
+
+/* <target> TBCPDecode/filter <file> */
+/* <target> <dict_ignored> TBCPDecode/filter <file> */
+private int
+zTBCPD(os_ptr op)
+{ stream_BCPD_state state;
+ state.signal_interrupt = no_bcp_signal_interrupt;
+ state.request_status = no_bcp_request_status;
+ return filter_read(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ &s_TBCPD_template, (stream_state *)&state, 0);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfbcp_op_defs) {
+ op_def_begin_filter(),
+ {"1BCPEncode", zBCPE},
+ {"1BCPDecode", zBCPD},
+ {"1TBCPEncode", zTBCPE},
+ {"1TBCPDecode", zTBCPD},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfcmap.c b/gs/src/zfcmap.c
new file mode 100644
index 000000000..056892a9f
--- /dev/null
+++ b/gs/src/zfcmap.c
@@ -0,0 +1,336 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfcmap.c */
+/* CMap creation operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gsstruct.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gxfcmap.h"
+#include "gxfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifont.h" /* for zfont_mark_glyph_name */
+#include "iname.h"
+#include "store.h"
+
+/* ---------------- Internal procedures ---------------- */
+
+/* Free a code map tree in case of memory overflow. */
+private void
+free_code_map(gx_code_map *pcmap, gs_memory_t *mem)
+{ if ( pcmap->type == cmap_subtree )
+ { int i;
+ for ( i = pcmap->byte_data.count1; i >= 0; --i )
+ free_code_map(&pcmap->data.subtree[i], mem);
+ gs_free_object(mem, pcmap->data.subtree, "free_code_map");
+ }
+}
+
+/* Convert a single code map to internal form. */
+/* This needs to be completely rewritten for space efficiency! */
+private int
+acquire_code_map(gx_code_map *pcmap, const ref *pref, int depth,
+ gs_cmap *root, gs_memory_t *mem)
+{ if ( depth >= 4 )
+ return_error(e_limitcheck);
+ pcmap->add_offset = 0;
+ pcmap->cmap = root;
+ switch ( r_type(pref) )
+ {
+ case t_null:
+ pcmap->type = cmap_glyph;
+ pcmap->byte_data.font_index = 0;
+ pcmap->data.glyph = gs_no_glyph;
+ return 0;
+ case t_name:
+ pcmap->type = cmap_glyph;
+ pcmap->byte_data.font_index = 0;
+ pcmap->data.glyph = name_index(pref);
+ return 0;
+ case t_integer:
+ if ( pref->value.intval < 0 ||
+ pref->value.intval > gs_max_glyph - gs_min_cid_glyph
+ )
+ break;
+ pcmap->type = cmap_glyph;
+ pcmap->data.glyph = pref->value.intval + gs_min_cid_glyph;
+ return 0;
+ case t_string:
+ if ( r_size(pref) < 1 || r_size(pref) > 4 )
+ break;
+ pcmap->type = cmap_char_code;
+ pcmap->num_bytes1 = r_size(pref) - 1;
+ pcmap->byte_data.font_index = 0;
+ { int i;
+ gs_char chr = 0;
+
+ for ( i = 0; i < r_size(pref); ++i )
+ chr = (chr << 8) + pref->value.const_bytes[i];
+ pcmap->data.ccode = chr;
+ }
+ return 0;
+ default:
+ if ( !r_is_array(pref) || r_size(pref) < 1 || r_size(pref) > 256 )
+ break;
+ { uint size = r_size(pref);
+ uint count = 0;
+ ref_type rtype = t_null;
+ long prev_value;
+ long diff;
+ uint run_length;
+ ref rsub;
+ gx_code_map *subtree;
+ uint i, j;
+
+ /* Do a first pass to count non-null entries and find runs. */
+
+ for ( rtype = t_null, i = 0; i < size; ++i )
+ { ref_type prev_type = rtype;
+
+ array_get(pref, (long)i, &rsub);
+ rtype = r_type(&rsub);
+ switch ( rtype )
+ {
+ case t_null:
+ continue;
+ case t_integer:
+ if ( prev_type == t_integer )
+ { if ( run_length == 1 )
+ { diff = rsub.value.intval - prev_value;
+ if ( diff & ~1L )
+ goto noseq;
+ run_length = 2;
+ continue;
+ }
+ else if ( rsub.value.intval - prev_value == diff )
+ { prev_value = rsub.value.intval;
+ ++run_length;
+ continue;
+ }
+ }
+noseq: prev_value = rsub.value.intval;
+ run_length = 1;
+ /* falls through */
+ default:
+ ++count;
+ }
+ }
+
+ if ( count == 0 )
+ count = 1;
+ subtree =
+ gs_alloc_struct_array(mem, count, gx_code_map,
+ &st_code_map_element,
+ "acquire_code_map");
+ if ( subtree == 0 )
+ return_error(e_VMerror);
+ pcmap->type = cmap_subtree;
+ pcmap->data.subtree = subtree;
+ /* Initialize a single undefined entry, in case count = 0 */
+ /* or we have to bail out with j = 0. */
+ subtree->first = subtree->last = 255;
+ subtree->type = cmap_glyph;
+ subtree->byte_data.font_index = 0;
+ subtree->data.glyph = gs_no_glyph;
+
+ /* Do the second pass to construct the tree. */
+
+ for ( rtype = t_null, i = j = 0; i < size; ++i )
+ { ref_type prev_type = rtype;
+ gx_code_map *submap = &subtree[j];
+ int code;
+
+ array_get(pref, (long)i, &rsub);
+ rtype = r_type(&rsub);
+ switch ( rtype )
+ {
+ case t_null:
+ continue;
+ case t_integer:
+ if ( prev_type == t_integer )
+ { if ( submap[-1].first == submap[-1].last )
+ { diff = rsub.value.intval - prev_value;
+ if ( diff & ~1L )
+ goto nseq;
+ submap[-1].add_offset = (uint)diff;
+ submap[-1].last++;
+ continue;
+ }
+ else if ( rsub.value.intval - prev_value == diff )
+ { prev_value = rsub.value.intval;
+ submap[-1].last++;
+ continue;
+ }
+ }
+nseq: prev_value = rsub.value.intval;
+ /* falls through */
+ default:
+ code = acquire_code_map(submap, &rsub, depth + 1,
+ root, mem);
+ if ( code < 0 )
+ { /* Release allocated elements. */
+ pcmap->byte_data.count1 = (j ? j - 1 : 0);
+ free_code_map(pcmap, mem);
+ return code;
+ }
+ submap->first = submap->last = (byte)i;
+ ++j;
+ }
+ }
+ pcmap->byte_data.count1 = count - 1;
+ }
+ return 0;
+ }
+ return_error(e_rangecheck);
+}
+
+/* Acquire CIDSystemInfo. */
+/* Note that this currently does not handle the array format. */
+private int
+acquire_cid_system_info(gs_cid_system_info *pcidsi, const ref *op)
+{ ref *prcidsi;
+ ref *pregistry;
+ ref *pordering;
+
+ if ( dict_find_string(op, "CIDSystemInfo", &prcidsi) <= 0 )
+ return_error(e_rangecheck);
+ if ( !r_has_type(prcidsi, t_dictionary) )
+ return_error(e_typecheck);
+ if ( dict_find_string(prcidsi, "Registry", &pregistry) <= 0 ||
+ dict_find_string(prcidsi, "Ordering", &pordering) <= 0
+ )
+ return_error(e_rangecheck);
+ check_read_type_only(*pregistry, t_string);
+ check_read_type_only(*pordering, t_string);
+ pcidsi->Registry.data = pregistry->value.const_bytes;
+ pcidsi->Registry.size = r_size(pregistry);
+ pcidsi->Ordering.data = pordering->value.const_bytes;
+ pcidsi->Ordering.size = r_size(pordering);
+ return dict_int_param(prcidsi, "Supplement", 0, max_int, -1,
+ &pcidsi->Supplement);
+}
+
+/* Check compatibility of CIDSystemInfo. */
+private bool
+cid_system_info_compatible(const gs_cid_system_info *psi1,
+ const gs_cid_system_info *psi2)
+{
+#define si_eq(part)\
+ !bytes_compare(psi1->part.data, psi1->part.size,\
+ psi2->part.data, psi2->part.size)
+ return si_eq(Registry) && si_eq(Ordering);
+#undef si_eq
+}
+
+/* ---------------- (Semi-)public procedures ---------------- */
+
+/* Get the CodeMap from a Type 0 font, and check the CIDSystemInfo of */
+/* its subsidiary fonts. */
+int
+ztype0_get_cmap(const gs_cmap **ppcmap, const ref *pfdepvector, const ref *op)
+{ ref *prcmap;
+ ref *pcodemap;
+ const gs_cmap *pcmap;
+ int code;
+ ref rfdep;
+ gs_cid_system_info cidsi;
+
+ if ( dict_find_string(op, "CMap", &prcmap) <= 0 ||
+ !r_has_type(prcmap, t_dictionary) ||
+ dict_find_string(prcmap, "CodeMap", &pcodemap) <= 0 ||
+ !r_has_stype(pcodemap, imemory, st_cmap)
+ )
+ return_error(e_invalidfont);
+ pcmap = r_ptr(pcodemap, gs_cmap);
+ /* Currently we only handle 1-element fonts. */
+ if ( r_size(pfdepvector) != 1)
+ return_error(e_rangecheck);
+ array_get(pfdepvector, 0L, &rfdep);
+ code = acquire_cid_system_info(&cidsi, &rfdep);
+ if ( code < 0 )
+ return code;
+ if ( !cid_system_info_compatible(&cidsi, &pcmap->CIDSystemInfo) )
+ return_error(e_rangecheck);
+ *ppcmap = pcmap;
+ return 0;
+}
+
+/* ---------------- Operators ---------------- */
+
+/* <CMap> .buildcmap <CMap> */
+/*
+ * Create the internal form of a CMap. The initial CMap must be read-write
+ * and have an entry with key = CodeMap and value = null; the result is
+ * read-only and has a real CodeMap.
+ */
+private int
+zbuildcmap(os_ptr op)
+{ int code;
+ ref *pcodemaps;
+ ref *pcodemap;
+ gs_cmap *pcmap;
+ ref rdef, rnotdef, rcmap;
+
+ check_type(*op, t_dictionary);
+ check_dict_write(*op);
+ pcmap = ialloc_struct(gs_cmap, &st_cmap, "zbuildcmap(cmap)");
+ if ( pcmap == 0 )
+ { code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ if ( (code = dict_uid_param(op, &pcmap->uid, 0, imemory)) < 0 ||
+ (code = dict_int_param(op, "WMode", 0, 1, 0, &pcmap->WMode)) < 0
+ )
+ goto fail;
+ if ( dict_find_string(op, ".CodeMaps", &pcodemaps) <= 0 ||
+ !r_has_type(pcodemaps, t_array) ||
+ r_size(pcodemaps) != 2 ||
+ dict_find_string(op, "CodeMap", &pcodemap) <= 0 ||
+ !r_has_type(pcodemap, t_null)
+ )
+ { code = gs_note_error(e_rangecheck);
+ goto fail;
+ }
+ if ( (code = acquire_cid_system_info(&pcmap->CIDSystemInfo, op)) < 0 ||
+ (array_get(pcodemaps, 0L, &rdef),
+ (code = acquire_code_map(&pcmap->def, &rdef, 0, pcmap, imemory)) < 0) ||
+ (array_get(pcodemaps, 1L, &rnotdef),
+ (code = acquire_code_map(&pcmap->notdef, &rnotdef, 0, pcmap, imemory)) < 0)
+ )
+ goto fail;
+ pcmap->mark_glyph = zfont_mark_glyph_name;
+ pcmap->mark_glyph_data = 0;
+ make_istruct_new(&rcmap, a_readonly, pcmap);
+ code = dict_put_string(op, "CodeMap", &rcmap);
+ if ( code < 0 )
+ goto fail;
+ return zreadonly(op);
+fail: ifree_object(pcmap, "zbuildcmap(cmap)");
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfcmap_op_defs) {
+ {"1.buildcmap", zbuildcmap},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfdctc.c b/gs/src/zfdctc.c
new file mode 100644
index 000000000..b6503f2bf
--- /dev/null
+++ b/gs/src/zfdctc.c
@@ -0,0 +1,364 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfdctc.c */
+/* Common code for DCT filter creation */
+#include "memory_.h"
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "ghost.h"
+#include "errors.h"
+#include "opcheck.h"
+#include "idict.h"
+#include "idparam.h"
+#include "imemory.h" /* for iutil.h */
+#include "ipacked.h"
+#include "iutil.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* Forward references */
+private int quant_params(P4(const ref *, int, UINT16 *, floatp));
+int zfdct_byte_params(P4(const ref *, int, int, UINT8 *));
+
+/* Common setup for encoding and decoding filters. */
+int
+zfdct_setup_quantization_tables(const ref *op, stream_DCT_state *pdct,
+ bool is_encode)
+{ int code;
+ int i, j;
+ ref *pdval;
+ const ref *pa;
+ const ref *QuantArrays[NUM_QUANT_TBLS]; /* for detecting duplicates */
+ int num_in_tables;
+ int num_out_tables;
+ jpeg_component_info * comp_info;
+ JQUANT_TBL ** table_ptrs;
+ JQUANT_TBL * this_table;
+
+ if ( op == 0 || dict_find_string(op, "QuantTables", &pdval) <= 0 )
+ return 0;
+ if ( !r_has_type(pdval, t_array) )
+ return_error(e_typecheck);
+ if ( is_encode )
+ { num_in_tables = pdct->data.compress->cinfo.num_components;
+ if ( r_size(pdval) < num_in_tables )
+ return_error(e_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
+ }
+ else
+ { num_in_tables = r_size(pdval);
+ comp_info = NULL; /* do not set for decompress case */
+ table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
+ }
+ num_out_tables = 0;
+ for ( i = 0, pa = pdval->value.const_refs;
+ i < num_in_tables; i++, pa++
+ )
+ { for ( j = 0; j < num_out_tables; j++ )
+ { if ( obj_eq(pa, QuantArrays[j]) )
+ break;
+ }
+ if ( comp_info != NULL )
+ comp_info[i].quant_tbl_no = j;
+ if ( j < num_out_tables )
+ continue;
+ if ( ++num_out_tables > NUM_QUANT_TBLS )
+ return_error(e_rangecheck);
+ QuantArrays[j] = pa;
+ this_table = table_ptrs[j];
+ if ( this_table == NULL )
+ { this_table = gs_jpeg_alloc_quant_table(pdct);
+ if ( this_table == NULL )
+ return_error(e_VMerror);
+ table_ptrs[j] = this_table;
+ }
+ if ( r_size(pa) != DCTSIZE2 )
+ return_error(e_rangecheck);
+ code = quant_params(pa, DCTSIZE2,
+ this_table->quantval, pdct->QFactor);
+ if ( code < 0 )
+ return code;
+ }
+ return 0;
+}
+
+int
+zfdct_setup_huffman_tables(const ref *op, stream_DCT_state *pdct,
+ bool is_encode)
+{ int code;
+ int i, j;
+ ref *pdval;
+ const ref *pa;
+ const ref *DCArrays[NUM_HUFF_TBLS]; /* for detecting duplicates */
+ const ref *ACArrays[NUM_HUFF_TBLS];
+ int num_in_tables;
+ int ndc, nac;
+ int codes_size;
+ jpeg_component_info * comp_info;
+ JHUFF_TBL ** dc_table_ptrs;
+ JHUFF_TBL ** ac_table_ptrs;
+ JHUFF_TBL ** this_table_ptr;
+ JHUFF_TBL * this_table;
+ int max_tables = 2; /* baseline limit */
+
+ if ( op == 0 ) /* no dictionary */
+ return 0;
+ if ( (code = dict_find_string(op, "HuffTables", &pdval)) <= 0)
+ return 0;
+ if ( !r_has_type(pdval, t_array) )
+ return_error(e_typecheck);
+ if ( is_encode )
+ { num_in_tables = pdct->data.compress->cinfo.input_components * 2;
+ if ( r_size(pdval) < num_in_tables )
+ return_error(e_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
+ if ( pdct->data.common->Relax )
+ max_tables = max(pdct->data.compress->cinfo.input_components, 2);
+ }
+ else
+ { num_in_tables = r_size(pdval);
+ comp_info = NULL; /* do not set for decompress case */
+ dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
+ if ( pdct->data.common->Relax )
+ max_tables = NUM_HUFF_TBLS;
+ }
+ ndc = nac = 0;
+ for ( i = 0, pa = pdval->value.const_refs;
+ i < num_in_tables; i++, pa++
+ )
+ { if ( i & 1 )
+ { for ( j = 0; j < nac; j++ )
+ { if ( obj_eq(pa, ACArrays[j]) )
+ break;
+ }
+ if ( comp_info != NULL )
+ comp_info[i>>1].ac_tbl_no = j;
+ if ( j < nac )
+ continue;
+ if ( ++nac > NUM_HUFF_TBLS )
+ return_error(e_rangecheck);
+ ACArrays[j] = pa;
+ this_table_ptr = ac_table_ptrs + j;
+ }
+ else
+ { for ( j = 0; j < ndc; j++ )
+ { if ( obj_eq(pa, DCArrays[j]) )
+ break;
+ }
+ if ( comp_info != NULL )
+ comp_info[i>>1].dc_tbl_no = j;
+ if ( j < ndc )
+ continue;
+ if ( ++ndc > NUM_HUFF_TBLS )
+ return_error(e_rangecheck);
+ DCArrays[j] = pa;
+ this_table_ptr = dc_table_ptrs + j;
+ }
+ this_table = *this_table_ptr;
+ if ( this_table == NULL )
+ { this_table = gs_jpeg_alloc_huff_table(pdct);
+ if ( this_table == NULL )
+ return_error(e_VMerror);
+ *this_table_ptr = this_table;
+ }
+ if ( r_size(pa) < 16 )
+ return_error(e_rangecheck);
+ code = zfdct_byte_params(pa, 0, 16, this_table->bits + 1);
+ if ( code < 0 )
+ return code;
+ for ( codes_size = 0, j = 1; j <= 16; j++ )
+ codes_size += this_table->bits[j];
+ if ( codes_size > 256 || r_size(pa) != codes_size+16 )
+ return_error(e_rangecheck);
+ code = zfdct_byte_params(pa, 16, codes_size, this_table->huffval);
+ if ( code < 0 )
+ return code;
+ }
+ if ( nac > max_tables || ndc > max_tables )
+ return_error(e_rangecheck);
+ return 0;
+}
+
+/* The main procedure */
+int
+zfdct_setup(const ref *op, stream_DCT_state *pdct)
+{ const ref *dop;
+ int npop;
+ int code;
+
+ /* Initialize the state in case we bail out. */
+ pdct->Markers.data = 0;
+ pdct->Markers.size = 0;
+ if ( !r_has_type(op, t_dictionary) )
+ { npop = 0;
+ dop = 0;
+ }
+ else
+ { check_dict_read(*op);
+ npop = 1;
+ dop = op;
+ }
+ /* These parameters are common to both, and are all defaultable. */
+ if ( (code = dict_int_param(dop, "Picky", 0, 1, 0,
+ &pdct->data.common->Picky)) < 0 ||
+ (code = dict_int_param(dop, "Relax", 0, 1, 0,
+ &pdct->data.common->Relax)) < 0 ||
+ (code = dict_int_param(dop, "ColorTransform", -1, 2, -1,
+ &pdct->ColorTransform)) < 0 ||
+ (code = dict_float_param(dop, "QFactor", 1.0,
+ &pdct->QFactor)) < 0
+ )
+ return code;
+ if ( pdct->QFactor < 0.0 || pdct->QFactor > 1000000.0 )
+ return_error(e_rangecheck);
+ return npop;
+}
+
+/* ------ Internal routines ------ */
+
+/* Get N quantization values from an array or a string. */
+
+private int
+quant_params(const ref *op, int count, UINT16 *pvals, floatp QFactor)
+{ int i;
+ const ref_packed *pref;
+ double val;
+ /* Adobe specifies the values to be supplied in zigzag order.
+ * For IJG versions newer than v6, we need to convert this order
+ * to natural array order. Older IJG versions want zigzag order.
+ */
+#if JPEG_LIB_VERSION >= 61
+ /* natural array position of n'th element of JPEG zigzag order */
+ static const int natural_order[DCTSIZE2] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+ };
+#define jpeg_order(x) natural_order[x]
+#else
+#define jpeg_order(x) (x)
+#endif
+ switch ( r_type(op) )
+ {
+ case t_string:
+ check_read(*op);
+ for ( i = 0; i < count; i++ )
+ {
+ val = op->value.const_bytes[i] * QFactor;
+ if ( val < 1 ) val = 1;
+ if ( val > 255 ) val = 255;
+ pvals[jpeg_order(i)] = (UINT16) (val + 0.5);
+ }
+ return 0;
+ case t_array:
+ check_read(*op);
+ pref = (const ref_packed *)op->value.const_refs;
+ break;
+ case t_shortarray:
+ case t_mixedarray:
+ check_read(*op);
+ pref = op->value.packed;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ for ( i = 0; i < count; pref = packed_next(pref), i++ )
+ { ref nref;
+ packed_get(pref, &nref);
+ switch ( r_type(&nref) )
+ {
+ case t_integer:
+ val = nref.value.intval * QFactor;
+ break;
+ case t_real:
+ val = nref.value.realval * QFactor;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ if ( val < 1 ) val = 1;
+ if ( val > 255 ) val = 255;
+ pvals[jpeg_order(i)] = (UINT16) (val + 0.5);
+ }
+ return 0;
+#undef jpeg_order
+}
+
+/* Get N byte-size values from an array or a string.
+ * Used for HuffTables, HSamples, VSamples.
+ */
+int
+zfdct_byte_params(const ref *op, int start, int count, UINT8 *pvals)
+{ int i;
+ const ref_packed *pref;
+ UINT8 *pval;
+ switch ( r_type(op) )
+ {
+ case t_string:
+ check_read(*op);
+ for ( i = 0, pval = pvals; i < count; i++, pval++ )
+ *pval = (UINT8)op->value.const_bytes[start+i];
+ return 0;
+ case t_array:
+ check_read(*op);
+ pref = (const ref_packed *)(op->value.const_refs + start);
+ break;
+ case t_shortarray:
+ case t_mixedarray:
+ check_read(*op);
+ pref = op->value.packed;
+ for ( i = 0; i < start; i++ )
+ pref = packed_next(pref);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ for ( i = 0, pval = pvals; i < count;
+ pref = packed_next(pref), i++, pval++
+ )
+ { ref nref;
+ packed_get(pref, &nref);
+ switch ( r_type(&nref) )
+ {
+ case t_integer:
+ if ( nref.value.intval < 0 || nref.value.intval > 255 )
+ return_error(e_rangecheck);
+ *pval = (UINT8)nref.value.intval;
+ break;
+ case t_real:
+ if ( nref.value.realval < 0 || nref.value.realval > 255 )
+ return_error(e_rangecheck);
+ *pval = (UINT8)(nref.value.realval + 0.5);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ return 0;
+}
diff --git a/gs/src/zfdctd.c b/gs/src/zfdctd.c
new file mode 100644
index 000000000..001bba5c0
--- /dev/null
+++ b/gs/src/zfdctd.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfdctd.c */
+/* DCTDecode filter creation */
+#include "memory_.h"
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+#include "ifilter.h"
+
+/* Import the common setup routines from zfdctc.c */
+int zfdct_setup(P2(const ref *op, stream_DCT_state *pdct));
+int zfdct_setup_quantization_tables(P3(const ref *op, stream_DCT_state *pdct,
+ bool is_encode));
+int zfdct_setup_huffman_tables(P3(const ref *op, stream_DCT_state *pdct,
+ bool is_encode));
+
+/* <source> <dict> DCTDecode/filter <file> */
+/* <source> DCTDecode/filter <file> */
+private int
+zDCTD(os_ptr op)
+{ stream_DCT_state state;
+ jpeg_decompress_data *jddp;
+ int code;
+ int npop;
+ const ref *dop;
+ uint dspace;
+
+ /* First allocate space for IJG parameters. */
+ jddp = gs_malloc(1, sizeof(*jddp), "zDCTD");
+ if ( jddp == 0 )
+ return_error(e_VMerror);
+ state.data.decompress = jddp;
+ jddp->scanline_buffer = NULL; /* set this early for safe error exit */
+ if ( (code = gs_jpeg_create_decompress(&state)) < 0 )
+ goto fail; /* correct to do jpeg_destroy here */
+ /* Read parameters from dictionary */
+ if ( (code = zfdct_setup(op, &state)) < 0 )
+ goto fail;
+ npop = code;
+ if ( npop == 0 )
+ dop = 0, dspace = 0;
+ else
+ dop = op, dspace = r_space(op);
+ /* DCTDecode accepts quantization and huffman tables
+ * in case these tables have been omitted from the datastream.
+ */
+ if ( (code = zfdct_setup_huffman_tables(dop, &state, false)) < 0 ||
+ (code = zfdct_setup_quantization_tables(dop, &state, false)) < 0
+ )
+ goto fail;
+ /* Create the filter. */
+ jddp->template = s_DCTD_template;
+ code = filter_read(op, npop, &jddp->template,
+ (stream_state *)&state, dspace);
+ if ( code >= 0 ) /* Success! */
+ return code;
+ /* We assume that if filter_read fails, the stream has not been
+ * registered for closing, so s_DCTD_release will never be called.
+ * Therefore we free the allocated memory before failing.
+ */
+
+fail:
+ gs_jpeg_destroy(&state);
+ gs_free(jddp, 1, sizeof(*jddp), "zDCTD fail");
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfdctd_op_defs) {
+ op_def_begin_filter(),
+ {"2DCTDecode", zDCTD},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfdcte.c b/gs/src/zfdcte.c
new file mode 100644
index 000000000..2d7e926f1
--- /dev/null
+++ b/gs/src/zfdcte.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfdcte.c */
+/* DCTEncode filter creation */
+#include "memory_.h"
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "idict.h"
+#include "idparam.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+#include "ifilter.h"
+
+/* Import the common setup routines from zfdctc.c */
+int zfdct_setup(P2(const ref *op, stream_DCT_state *pdct));
+int zfdct_setup_quantization_tables(P3(const ref *op, stream_DCT_state *pdct,
+ bool is_encode));
+int zfdct_setup_huffman_tables(P3(const ref *op, stream_DCT_state *pdct,
+ bool is_encode));
+int zfdct_byte_params(P4(const ref *op, int start, int count, UINT8 *pvals));
+
+/* Collect encode-only parameters. */
+private int
+dct_setup_samples(const ref *op, const char _ds *kstr, int num_colors,
+ jpeg_compress_data *jcdp, bool is_vert)
+{ int code;
+ int i;
+ ref *pdval;
+ jpeg_component_info * comp_info = jcdp->cinfo.comp_info;
+ UINT8 samples[4];
+ /* Adobe default is all sampling factors = 1,
+ * which is NOT the IJG default, so we must always assign values.
+ */
+ if ( op != 0 && dict_find_string(op, kstr, &pdval) > 0 )
+ { if ( r_size(pdval) < num_colors )
+ return_error(e_rangecheck);
+ if ( (code = zfdct_byte_params(pdval, 0, num_colors, samples)) < 0 )
+ return code;
+ }
+ else
+ { samples[0] = samples[1] = samples[2] = samples[3] = 1;
+ }
+ for ( i = 0; i < num_colors; i++ )
+ { if ( samples[i] < 1 || samples[i] > 4 )
+ return_error(e_rangecheck);
+ if ( is_vert )
+ comp_info[i].v_samp_factor = samples[i];
+ else
+ comp_info[i].h_samp_factor = samples[i];
+ }
+ return 0;
+}
+
+private int
+zfdcte_setup(const ref *op, stream_DCT_state *pdct)
+{ jpeg_compress_data *jcdp = pdct->data.compress;
+ uint Columns, Rows, Resync;
+ int num_colors;
+ int Blend;
+ ref *mstr;
+ int i;
+ int code;
+
+ /* Required parameters for DCTEncode.
+ * (DCTDecode gets the equivalent info from the SOF marker.)
+ */
+ if ( (code = dict_uint_param(op, "Columns", 1, 0xffff, 0,
+ &Columns)) < 0 ||
+ (code = dict_uint_param(op, "Rows", 1, 0xffff, 0,
+ &Rows)) < 0 ||
+ (code = dict_int_param(op, "Colors", 1, 4, -1,
+ &num_colors)) < 0
+ )
+ return code;
+ /* Set up minimal image description & call set_defaults */
+ jcdp->cinfo.image_width = Columns;
+ jcdp->cinfo.image_height = Rows;
+ jcdp->cinfo.input_components = num_colors;
+ switch ( num_colors )
+ {
+ case 1:
+ jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ case 3:
+ jcdp->cinfo.in_color_space = JCS_RGB;
+ break;
+ case 4:
+ jcdp->cinfo.in_color_space = JCS_CMYK;
+ break;
+ default:
+ jcdp->cinfo.in_color_space = JCS_UNKNOWN;
+ }
+ if ( (code = gs_jpeg_set_defaults(pdct)) < 0 )
+ return code;
+ /* Change IJG colorspace defaults as needed;
+ * set ColorTransform to what will go in the Adobe marker.
+ */
+ switch ( num_colors )
+ {
+ case 3:
+ if ( pdct->ColorTransform < 0 )
+ pdct->ColorTransform = 1; /* default */
+ if ( pdct->ColorTransform == 0 )
+ {
+ if ( (code = gs_jpeg_set_colorspace(pdct, JCS_RGB)) < 0 )
+ return code;
+ }
+ else
+ pdct->ColorTransform = 1; /* flag YCC xform */
+ break;
+ case 4:
+ if ( pdct->ColorTransform < 0 )
+ pdct->ColorTransform = 0; /* default */
+ if ( pdct->ColorTransform != 0 )
+ { if ( (code = gs_jpeg_set_colorspace(pdct, JCS_YCCK)) < 0 )
+ return code;
+ pdct->ColorTransform = 2; /* flag YCCK xform */
+ }
+ else
+ { if ( (code = gs_jpeg_set_colorspace(pdct, JCS_CMYK)) < 0 )
+ return code;
+ }
+ break;
+ default:
+ pdct->ColorTransform = 0; /* no transform otherwise */
+ break;
+ }
+ /* Optional encoding-only parameters */
+ if ( dict_find_string(op, "Markers", &mstr) > 0 )
+ { check_read_type(*mstr, t_string);
+ pdct->Markers.data = mstr->value.const_bytes;
+ pdct->Markers.size = r_size(mstr);
+ }
+ if ( (code = dict_bool_param(op, "NoMarker", false,
+ &pdct->NoMarker)) < 0 ||
+ (code = dict_uint_param(op, "Resync", 0, 0xffff, 0,
+ &Resync)) < 0 ||
+ (code = dict_int_param(op, "Blend", 0, 1, 0,
+ &Blend)) < 0 ||
+ (code = dct_setup_samples(op, "HSamples", num_colors,
+ jcdp, false)) < 0 ||
+ (code = dct_setup_samples(op, "VSamples", num_colors,
+ jcdp, true)) < 0
+ )
+ return code;
+ jcdp->cinfo.write_JFIF_header = FALSE;
+ jcdp->cinfo.write_Adobe_marker = FALSE; /* must do it myself */
+ jcdp->cinfo.restart_interval = Resync;
+ /* What to do with Blend ??? */
+ if ( pdct->data.common->Relax == 0 )
+ { jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ int num_samples;
+ for ( i = 0, num_samples = 0; i < num_colors; i++ )
+ num_samples += comp_info[i].h_samp_factor *
+ comp_info[i].v_samp_factor;
+ if ( num_samples > 10 )
+ return_error(e_rangecheck);
+ /* Note: by default the IJG software does not allow
+ * num_samples to exceed 10, Relax or no. For full
+ * compatibility with Adobe's non-JPEG-compliant
+ * software, set MAX_BLOCKS_IN_MCU to 64 in jpeglib.h.
+ */
+ }
+ return 0;
+}
+
+/* <target> <dict> DCTEncode/filter <file> */
+private int
+zDCTE(os_ptr op)
+{ stream_DCT_state state;
+ jpeg_compress_data *jcdp;
+ int code;
+ int npop;
+ const ref *dop;
+ uint dspace;
+ ref *pdval;
+
+ /* First allocate space for IJG parameters. */
+ jcdp = gs_malloc(1, sizeof(*jcdp), "zDCTE");
+ if ( jcdp == 0 )
+ return_error(e_VMerror);
+ state.data.compress = jcdp;
+ if ( (code = gs_jpeg_create_compress(&state)) < 0 )
+ goto fail; /* correct to do jpeg_destroy here */
+ /* Read parameters from dictionary */
+ if ( (code = zfdct_setup(op, &state)) < 0 )
+ goto fail;
+ npop = code;
+ if ( npop == 0 )
+ dop = 0, dspace = 0;
+ else
+ dop = op, dspace = r_space(op);
+ if ( (code = zfdcte_setup(dop, &state)) < 0 )
+ goto fail;
+ /* Check for QFactor without QuantTables. */
+ if ( dop == 0 || dict_find_string(dop, "QuantTables", &pdval) <= 0 )
+ { /* No QuantTables, but maybe a QFactor to apply to default. */
+ if ( state.QFactor != 1.0 )
+ { code = gs_jpeg_set_linear_quality(&state,
+ (int) (min(state.QFactor, 100.0)
+ * 100.0 + 0.5),
+ TRUE);
+ if ( code < 0 )
+ return code;
+ }
+
+ }
+ if ( (code = zfdct_setup_huffman_tables(dop, &state, true)) < 0 ||
+ (code = zfdct_setup_quantization_tables(dop, &state, true)) < 0
+ )
+ goto fail;
+ /* Create the filter. */
+ jcdp->template = s_DCTE_template;
+ /* Make sure we get at least a full scan line of input. */
+ state.scan_line_size = jcdp->cinfo.input_components *
+ jcdp->cinfo.image_width;
+ jcdp->template.min_in_size =
+ max(s_DCTE_template.min_in_size, state.scan_line_size);
+ /* Make sure we can write the user markers in a single go. */
+ jcdp->template.min_out_size =
+ max(s_DCTE_template.min_out_size, state.Markers.size);
+ code = filter_write(op, npop, &jcdp->template,
+ (stream_state *)&state, dspace);
+ if ( code >= 0 ) /* Success! */
+ return code;
+ /* We assume that if filter_write fails, the stream has not been
+ * registered for closing, so s_DCTE_release will never be called.
+ * Therefore we free the allocated memory before failing.
+ */
+
+fail:
+ gs_jpeg_destroy(&state);
+ gs_free(jcdp, 1, sizeof(*jcdp), "zDCTE fail");
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfdcte_op_defs) {
+ op_def_begin_filter(),
+ {"2DCTEncode", zDCTE},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfdecode.c b/gs/src/zfdecode.c
new file mode 100644
index 000000000..3679123f3
--- /dev/null
+++ b/gs/src/zfdecode.c
@@ -0,0 +1,345 @@
+/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfdecode.c */
+/* Additional decoding filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+#include "stream.h" /* for setting is_temp */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sa85x.h"
+#include "scfx.h"
+#include "scf.h"
+#include "slzwx.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "ifilter.h"
+
+/* Import the Level 2 scanner extensions. */
+extern const stream_template _ds *scan_ascii85_template;
+
+/* Initialize the Level 2 scanner for ASCII85 strings. */
+private void
+zfdecode_init(void)
+{ scan_ascii85_template = &s_A85D_template;
+}
+
+/* ------ ASCII85 filters ------ */
+
+/* We include both encoding and decoding filters here, */
+/* because it would be a nuisance to separate them. */
+
+/* <target> ASCII85Encode/filter <file> */
+/* <target> <dict_ignored> ASCII85Encode/filter <file> */
+private int
+zA85E(os_ptr op)
+{ return filter_write_simple(op, &s_A85E_template);
+}
+
+/* <source> ASCII85Decode/filter <file> */
+/* <source> <dict_ignored> ASCII85Decode/filter <file> */
+private int
+zA85D(os_ptr op)
+{ return filter_read_simple(op, &s_A85D_template);
+}
+
+/* ------ CCITTFaxDecode filter ------ */
+
+/* Define a limit on the Rows parameter, close to max_int. */
+#define cf_max_height 32000
+
+/* Common setup for encoding and decoding filters. */
+int
+zcf_setup(os_ptr op, stream_CF_state *pcfs)
+{ int code;
+ if ( (code = dict_bool_param(op, "Uncompressed", false,
+ &pcfs->Uncompressed)) < 0 ||
+ (code = dict_int_param(op, "K", -cf_max_height, cf_max_height, 0,
+ &pcfs->K)) < 0 ||
+ (code = dict_bool_param(op, "EndOfLine", false,
+ &pcfs->EndOfLine)) < 0 ||
+ (code = dict_bool_param(op, "EncodedByteAlign", false,
+ &pcfs->EncodedByteAlign)) < 0 ||
+ (code = dict_int_param(op, "Columns", 0, cfe_max_width, 1728,
+ &pcfs->Columns)) < 0 ||
+ (code = dict_int_param(op, "Rows", 0, cf_max_height, 0,
+ &pcfs->Rows)) < 0 ||
+ (code = dict_bool_param(op, "EndOfBlock", true,
+ &pcfs->EndOfBlock)) < 0 ||
+ (code = dict_bool_param(op, "BlackIs1", false,
+ &pcfs->BlackIs1)) < 0 ||
+ (code = dict_int_param(op, "DamagedRowsBeforeError", 0,
+ cf_max_height, 0,
+ &pcfs->DamagedRowsBeforeError)) < 0 ||
+ (code = dict_bool_param(op, "FirstBitLowOrder", false,
+ &pcfs->FirstBitLowOrder)) < 0 ||
+ (code = dict_int_param(op, "DecodedByteAlign", 1, 16, 1,
+ &pcfs->DecodedByteAlign)) < 0
+ )
+ return code;
+ if ( pcfs->DecodedByteAlign & (pcfs->DecodedByteAlign - 1) )
+ return_error(e_rangecheck); /* not a power of 2 */
+ return 0;
+}
+
+/* <source> <dict> CCITTFaxDecode/filter <file> */
+/* <source> CCITTFaxDecode/filter <file> */
+private int
+zCFD(os_ptr op)
+{ os_ptr dop;
+ int npop;
+ stream_CFD_state cfs;
+ int code;
+
+ if ( r_has_type(op, t_dictionary) )
+ { check_dict_read(*op);
+ dop = op, npop = 1;
+ }
+ else
+ dop = 0, npop = 0;
+ code = zcf_setup(dop, (stream_CF_state *)&cfs);
+ if ( code < 0 )
+ return code;
+ return filter_read(op, npop, &s_CFD_template, (stream_state *)&cfs, 0);
+}
+
+/* ------ Common setup for possibly pixel-oriented decoding filters ------ */
+
+/* Forward declarations */
+int zpd_setup(P2(os_ptr op, stream_PDiff_state *ppds));
+int zpp_setup(P2(os_ptr op, stream_PNGP_state *ppps));
+
+int
+filter_read_predictor(os_ptr op, int npop, const stream_template *template,
+ stream_state *st)
+{ int predictor, code;
+ stream_PDiff_state pds;
+ stream_PNGP_state pps;
+
+ if ( r_has_type(op, t_dictionary) )
+ { if ( (code = dict_int_param(op, "Predictor", 0, 15, 1, &predictor)) < 0 )
+ return code;
+ switch ( predictor )
+ {
+ case 0: /* identity */
+ predictor = 1;
+ case 1: /* identity */
+ break;
+ case 2: /* componentwise horizontal differencing */
+ code = zpd_setup(op, &pds);
+ break;
+ case 10: case 11: case 12: case 13: case 14: case 15:
+ /* PNG prediction */
+ code = zpp_setup(op, &pps);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if ( code < 0 )
+ return code;
+ }
+ else
+ predictor = 1;
+ if ( predictor == 1 )
+ return filter_read(op, npop, template, st, 0);
+ { /* We need to cascade filters. */
+ ref rsource, rdict, rfd;
+ int code;
+
+ /* Save the operands, just in case. */
+ ref_assign(&rsource, op - 1);
+ ref_assign(&rdict, op);
+ code = filter_read(op, 1, template, st, 0);
+ if ( code < 0 )
+ return code;
+ /* filter_read changed osp.... */
+ op = osp;
+ ref_assign(&rfd, op);
+ code =
+ (predictor == 2 ?
+ filter_read(op, 0, &s_PDiffD_template, (stream_state *)&pds, 0) :
+ filter_read(op, 0, &s_PNGPD_template, (stream_state *)&pps, 0));
+ if ( code < 0 )
+ { /* Restore the operands. Don't bother trying to clean up */
+ /* the first stream. */
+ osp = ++op;
+ ref_assign(op - 1, &rsource);
+ ref_assign(op, &rdict);
+ return code;
+ }
+ filter_mark_temp(&rfd, 2); /* Mark the decompression stream as temporary. */
+ return code;
+ }
+}
+
+/* ------ Generalized LZW/GIF decoding filter ------ */
+
+/* Common setup for encoding and decoding filters. */
+int
+zlz_setup(os_ptr op, stream_LZW_state *plzs)
+{ int code;
+ const ref *dop;
+ int npop;
+
+ if ( r_has_type(op, t_dictionary) )
+ { check_dict_read(*op);
+ dop = op, npop = 1;
+ }
+ else
+ dop = 0, npop = 0;
+ if ( /* Following are not PostScript standard */
+ (code = dict_int_param(dop, "EarlyChange", 0, 1, 1,
+ &plzs->EarlyChange)) < 0 ||
+ (code = dict_int_param(dop, "InitialCodeLength", 2, 11, 8,
+ &plzs->InitialCodeLength)) < 0 ||
+ (code = dict_bool_param(dop, "FirstBitLowOrder", false,
+ &plzs->FirstBitLowOrder)) < 0 ||
+ (code = dict_bool_param(dop, "BlockData", false,
+ &plzs->BlockData)) < 0
+ )
+ return code;
+ return npop;
+}
+
+/* <source> LZWDecode/filter <file> */
+/* <source> <dict> LZWDecode/filter <file> */
+private int
+zLZWD(os_ptr op)
+{ stream_LZW_state lzs;
+ int code = zlz_setup(op, &lzs);
+
+ if ( code < 0 )
+ return code;
+ return filter_read_predictor(op, code, &s_LZWD_template,
+ (stream_state *)&lzs);
+}
+
+/* ------ Color differencing filters ------ */
+
+/* We include both encoding and decoding filters here, */
+/* because it would be a nuisance to separate them. */
+
+/* Common setup for encoding and decoding filters. */
+int
+zpd_setup(os_ptr op, stream_PDiff_state *ppds)
+{ int code, bpc;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ( (code = dict_int_param(op, "Colors", 1, 4, 1,
+ &ppds->Colors)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 8, 8,
+ &bpc)) < 0 ||
+ (bpc & (bpc - 1)) != 0 ||
+ (code = dict_int_param(op, "Columns", 1, max_int, 1,
+ &ppds->Columns)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ ppds->BitsPerComponent = bpc;
+ return 0;
+}
+
+/* <target> <dict> PixelDifferenceEncode/filter <file> */
+private int
+zPDiffE(os_ptr op)
+{ stream_PDiff_state pds;
+ int code = zpd_setup(op, &pds);
+
+ if ( code < 0 )
+ return code;
+ return filter_write(op, 1, &s_PDiffE_template, (stream_state *)&pds, 0);
+}
+
+/* <source> <dict> PixelDifferenceDecode/filter <file> */
+private int
+zPDiffD(os_ptr op)
+{ stream_PDiff_state pds;
+ int code = zpd_setup(op, &pds);
+
+ if ( code < 0 )
+ return code;
+ return filter_read(op, 1, &s_PDiffD_template, (stream_state *)&pds, 0);
+}
+
+/* ------ PNG pixel predictor filters ------ */
+
+/* Common setup for encoding and decoding filters. */
+int
+zpp_setup(os_ptr op, stream_PNGP_state *ppps)
+{ int code, bpc;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ( (code = dict_int_param(op, "Colors", 1, 16, 1,
+ &ppps->Colors)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 16, 8,
+ &bpc)) < 0 ||
+ (bpc & (bpc - 1)) != 0 ||
+ (code = dict_uint_param(op, "Columns", 1, max_uint, 1,
+ &ppps->Columns)) < 0 ||
+ (code = dict_int_param(op, "Predictor", 10, 15, 15,
+ &ppps->Predictor)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ ppps->BitsPerComponent = bpc;
+ return 0;
+}
+
+/* <target> <dict> PNGPredictorEncode/filter <file> */
+private int
+zPNGPE(os_ptr op)
+{ stream_PNGP_state pps;
+ int code = zpp_setup(op, &pps);
+
+ if ( code < 0 )
+ return code;
+ return filter_write(op, 1, &s_PNGPE_template, (stream_state *)&pps, 0);
+}
+
+/* <source> <dict> PNGPredictorDecode/filter <file> */
+private int
+zPNGPD(os_ptr op)
+{ stream_PNGP_state pps;
+ int code = zpp_setup(op, &pps);
+
+ if ( code < 0 )
+ return code;
+ return filter_read(op, 1, &s_PNGPD_template, (stream_state *)&pps, 0);
+}
+
+/* ---------------- Initialization procedure ---------------- */
+
+BEGIN_OP_DEFS(zfdecode_op_defs) {
+ op_def_begin_filter(),
+ {"1ASCII85Encode", zA85E},
+ {"1ASCII85Decode", zA85D},
+ {"2CCITTFaxDecode", zCFD},
+ {"1LZWDecode", zLZWD},
+ {"2PixelDifferenceDecode", zPDiffD},
+ {"2PixelDifferenceEncode", zPDiffE},
+ {"2PNGPredictorDecode", zPNGPD},
+ {"2PNGPredictorEncode", zPNGPE},
+END_OP_DEFS(zfdecode_init) }
diff --git a/gs/src/zfile.c b/gs/src/zfile.c
new file mode 100644
index 000000000..40b7414f5
--- /dev/null
+++ b/gs/src/zfile.c
@@ -0,0 +1,882 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfile.c */
+/* Non-I/O file operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "gsstruct.h" /* for registering root */
+#include "errors.h"
+#include "oper.h"
+#include "estack.h" /* for filenameforall, .execfile */
+#include "ialloc.h"
+#include "ilevel.h" /* %names only work in Level 2 */
+#include "interp.h" /* gs_errorinfo_put_string prototype */
+#include "isave.h" /* for restore */
+#include "iutil.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "gxiodev.h" /* must come after stream.h */
+ /* and before files.h */
+#include "files.h" /* ditto */
+#include "fname.h" /* ditto */
+#include "main.h" /* for gs_lib_paths */
+#include "store.h"
+
+/* Import the file_open routine for %os%, which is the default. */
+extern iodev_proc_open_file(iodev_os_open_file);
+
+/* Forward references: file opening. */
+int file_open(P6(const byte *, uint, const char *, uint, ref *, stream **));
+
+/* Forward references: other. */
+private int execfile_finish(P1(os_ptr));
+private int execfile_cleanup(P1(os_ptr));
+private stream_proc_report_error(filter_report_error);
+
+/*
+ * Since there can be many file objects referring to the same file/stream,
+ * we can't simply free a stream when we close it. On the other hand,
+ * we don't want freed streams to clutter up memory needlessly.
+ * Our solution is to retain the freed streams, and reuse them.
+ * To prevent an old file object from being able to access a reused stream,
+ * we keep a serial number in each stream, and check it against a serial
+ * number stored in the file object (as the "size"); when we close a file,
+ * we increment its serial number. If the serial number ever overflows,
+ * we leave it at zero, and do not reuse the stream.
+ * (This will never happen.)
+ *
+ * Storage management for this scheme is a little tricky.
+ * We maintain an invariant that says that a stream opened at a given
+ * save level always uses a stream structure allocated at that level.
+ * By doing this, we don't need to keep track separately of streams open
+ * at a level vs. streams allocated at a level. To make this interact
+ * properly with save and restore, we maintain a list of all streams
+ * currently allocated, both open and closed. The save_count member
+ * of a stream indicates the number of unmatched saves at which
+ * the given stream was the head of the list. Thus the streams
+ * allocated at the current level are precisely those from the head of the
+ * list up to and not including the first stream with non-zero save_count.
+ *
+ * We want to close streams freed by restore and by garbage collection.
+ * We use the finalization procedure for this. For restore, we don't
+ * have to do anything special to make this happen; we only need to ensure
+ * that we remove from the list of allocated streams any streams being freed,
+ * as just described. For garbage collection, we do something more drastic:
+ * we simply clear the list of known streams (at all save levels).
+ * Any streams open at the time of garbage collection will no longer
+ * participate in the list of known streams, but this does no harm;
+ * it simply means that they won't get reused, and can only be reclaimed
+ * by a future garbage collection or restore.
+ */
+private stream *file_list;
+private gs_gc_root_t file_list_root;
+
+/*
+ * Define the default stream buffer sizes. For file streams,
+ * this is arbitrary, since the C library or operating system
+ * does its own buffering in addition.
+ * However, the buffer size for eexec decoding is NOT arbitrary:
+ * it must be at most 512.
+ */
+#define default_buffer_size 512
+const uint file_default_buffer_size = default_buffer_size;
+
+/* An invalid file object */
+stream *invalid_file_entry; /* exported for zfileio.c */
+private gs_gc_root_t invalid_file_root;
+
+/* Initialize the file table */
+private void
+zfile_init(void)
+{
+ /* Create and initialize an invalid (closed) stream. */
+ /* Initialize the stream for the sake of the GC, */
+ /* and so it can act as an empty input stream. */
+
+ stream *s = s_alloc(imemory_system, "zfile_init");
+ sread_string(s, NULL, 0);
+ s->next = s->prev = 0;
+ s->save_count = 0;
+ s_init_no_id(s);
+ invalid_file_entry = s;
+ gs_register_struct_root(imemory, &invalid_file_root,
+ (void **)&invalid_file_entry,
+ "invalid_file_entry");
+
+ /* Initialize the bookkeeping list. */
+
+ file_list = 0;
+ gs_register_struct_root(imemory, &file_list_root,
+ (void **)&file_list, "file_list");
+}
+
+/* Make an invalid file object. */
+void
+make_invalid_file(ref *fp)
+{ make_file(fp, avm_system, ~0, invalid_file_entry);
+}
+
+/* <name_string> <access_string> file <file> */
+int
+zfile(register os_ptr op)
+{ char file_access[3];
+ parsed_file_name pname;
+ const byte *astr;
+ int code;
+ stream *s;
+ check_read_type(*op, t_string);
+ astr = op->value.const_bytes;
+ switch ( r_size(op) )
+ {
+ case 2:
+ if ( astr[1] != '+' )
+ return_error(e_invalidfileaccess);
+ file_access[1] = '+';
+ file_access[2] = 0;
+ break;
+ case 1:
+ file_access[1] = 0;
+ break;
+ default:
+ return_error(e_invalidfileaccess);
+ }
+ switch ( astr[0] )
+ {
+ case 'r': case 'w': case 'a':
+ break;
+ default:
+ return_error(e_invalidfileaccess);
+ }
+ file_access[0] = astr[0];
+ code = parse_file_name(op - 1, &pname);
+ if ( code < 0 )
+ return code;
+ if ( pname.iodev == NULL )
+ pname.iodev = iodev_default;
+ if ( pname.fname == NULL ) /* just a device */
+ code = (*pname.iodev->procs.open_device)(pname.iodev,
+ file_access, &s, imemory);
+ else /* file */
+ { iodev_proc_open_file((*open_file)) =
+ pname.iodev->procs.open_file;
+ if ( open_file == 0 )
+ open_file = iodev_os_open_file;
+ code = (*open_file)(pname.iodev, pname.fname, pname.len,
+ file_access, &s, imemory);
+ }
+ if ( code < 0 )
+ return code;
+ make_stream_file(op - 1, s, file_access);
+ pop(1);
+ return code;
+}
+
+/* ------ Level 2 extensions ------ */
+
+/* <string> deletefile - */
+private int
+zdeletefile(register os_ptr op)
+{ parsed_file_name pname;
+ int code = parse_real_file_name(op, &pname, "deletefile");
+ if ( code < 0 )
+ return code;
+ code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
+ free_file_name(&pname, "deletefile");
+ if ( code < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <template> <proc> <scratch> filenameforall - */
+/****** NOT CONVERTED FOR IODEVICES YET ******/
+private int file_continue(P1(os_ptr));
+private int file_cleanup(P1(os_ptr));
+private int
+zfilenameforall(register os_ptr op)
+{ file_enum *pfen;
+ int code;
+ check_write_type(*op, t_string);
+ check_proc(op[-1]);
+ check_read_type(op[-2], t_string);
+ /* Push a mark, the pattern, the scratch string, the enumerator, */
+ /* and the procedure, and invoke the continuation. */
+ check_estack(7);
+ pfen = gp_enumerate_files_init((char *)op[-2].value.bytes, r_size(op - 2), imemory);
+ if ( pfen == 0 )
+ return_error(e_VMerror);
+ push_mark_estack(es_for, file_cleanup);
+ *++esp = op[-2];
+ *++esp = *op;
+ ++esp;
+ make_istruct(esp, 0, pfen);
+ *++esp = op[-1];
+ pop(3); op -= 3;
+ code = file_continue(op);
+ return (code == o_pop_estack ? o_push_estack : code);
+}
+/* Continuation operator for enumerating files */
+private int
+file_continue(register os_ptr op)
+{ es_ptr pscratch = esp - 2;
+ file_enum *pfen = r_ptr(esp - 1, file_enum);
+ uint len = r_size(pscratch);
+ uint code =
+ gp_enumerate_files_next(pfen, (char *)pscratch->value.bytes, len);
+ if ( code == ~(uint)0 ) /* all done */
+ { esp -= 4; /* pop proc, pfen, scratch, mark */
+ return o_pop_estack;
+ }
+ else if ( code > len ) /* overran string */
+ return_error(e_rangecheck);
+ else
+ { push(1);
+ ref_assign(op, pscratch);
+ r_set_size(op, code);
+ push_op_estack(file_continue); /* come again */
+ *++esp = pscratch[2]; /* proc */
+ return o_push_estack;
+ }
+}
+/* Cleanup procedure for enumerating files */
+private int
+file_cleanup(os_ptr op)
+{ gp_enumerate_files_close(r_ptr(esp + 4, file_enum));
+ return 0;
+}
+
+/* <string1> <string2> renamefile - */
+private int
+zrenamefile(register os_ptr op)
+{ parsed_file_name pname1, pname2;
+ int code = parse_real_file_name(op - 1, &pname1, "renamefile(from)");
+ if ( code < 0 )
+ return code;
+ pname2.fname = 0;
+ code = parse_real_file_name(op, &pname2, "renamefile(to)");
+ if ( code < 0 || pname1.iodev != pname2.iodev ||
+ (code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
+ pname1.fname, pname2.fname)) < 0
+ )
+ { if ( code >= 0 )
+ code = gs_note_error(e_invalidfileaccess);
+ }
+ free_file_name(&pname2, "renamefile(to)");
+ free_file_name(&pname1, "renamefile(from)");
+ if ( code < 0 )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <file> status <open_bool> */
+/* <string> status <pages> <bytes> <ref_time> <creation_time> true */
+/* <string> status false */
+private int
+zstatus(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_file:
+ { stream *s;
+ make_bool(op, (file_is_valid(s, op) ? 1 : 0));
+ } return 0;
+ case t_string:
+ { parsed_file_name pname;
+ struct stat fstat;
+ int code = parse_file_name(op, &pname);
+ if ( code < 0 )
+ return code;
+ code = terminate_file_name(&pname, "status");
+ if ( code < 0 )
+ return code;
+ code = (*pname.iodev->procs.file_status)(pname.iodev,
+ pname.fname, &fstat);
+ switch ( code )
+ {
+ case 0:
+ push(4);
+ make_int(op - 4, stat_blocks(&fstat));
+ make_int(op - 3, fstat.st_size);
+ make_int(op - 2, fstat.st_mtime);
+ make_int(op - 1, fstat.st_ctime);
+ make_bool(op, 1);
+ break;
+ case e_undefinedfilename:
+ make_bool(op, 0);
+ code = 0;
+ }
+ free_file_name(&pname, "status");
+ return code;
+ }
+ default:
+ return_op_typecheck(op);
+ }
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <executable_file> .execfile - */
+private int
+zexecfile(register os_ptr op)
+{ check_type_access(*op, t_file, a_executable | a_read | a_execute);
+ check_estack(4); /* cleanup, file, finish, file */
+ push_mark_estack(es_other, execfile_cleanup);
+ *++esp = *op;
+ push_op_estack(execfile_finish);
+ return zexec(op);
+}
+/* Finish normally. */
+private int
+execfile_finish(os_ptr op)
+{ check_ostack(1);
+ esp -= 2;
+ execfile_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up by closing the file. */
+private int
+execfile_cleanup(os_ptr op)
+{ check_ostack(1);
+ *++osp = esp[2];
+ return zclosefile(osp);
+}
+
+/* <dir> <name> .filenamedirseparator <string> */
+int
+zfilenamedirseparator(os_ptr op)
+{ const char *sepr;
+
+ check_read_type(*op, t_string);
+ check_read_type(op[-1], t_string);
+ sepr =
+ gp_file_name_concat_string((const char *)op[-1].value.const_bytes,
+ r_size(op - 1),
+ (const char *)op->value.const_bytes,
+ r_size(op));
+ make_const_string(op - 1, avm_foreign | a_readonly,
+ strlen(sepr), (const byte *)sepr);
+ pop(1);
+ return 0;
+}
+
+/* - .filenamelistseparator <string> */
+int
+zfilenamelistseparator(os_ptr op)
+{ push(1);
+ make_const_string(op, avm_foreign | a_readonly, 1,
+ (const byte *)&gp_file_name_list_separator);
+ return 0;
+}
+
+/* <name> .filenamesplit <dir> <base> <extension> */
+int
+zfilenamesplit(os_ptr op)
+{ check_read_type(*op, t_string);
+ /****** NOT IMPLEMENTED YET ******/
+ return_error(e_undefined);
+}
+
+/* <string> findlibfile <found_string> <file> true */
+/* <string> findlibfile <string> false */
+int
+zfindlibfile(register os_ptr op)
+{ int code;
+#define maxclen 200
+ byte cname[maxclen];
+ uint clen;
+ parsed_file_name pname;
+ stream *s;
+ check_ostack(2);
+ code = parse_file_name(op, &pname);
+ if ( code < 0 )
+ return code;
+ if ( pname.iodev == NULL )
+ pname.iodev = iodev_default;
+ if ( pname.iodev != iodev_default )
+ { /* Non-OS devices don't have search paths (yet). */
+ code =
+ (pname.fname == NULL ?
+ (*pname.iodev->procs.open_device)(pname.iodev, "r",
+ &s, imemory) :
+ (*pname.iodev->procs.open_file)(pname.iodev,
+ pname.fname, pname.len, "r",
+ &s, imemory));
+ if ( code < 0 )
+ { push(1);
+ make_false(op);
+ return 0;
+ }
+ make_stream_file(op + 1, s, "r");
+ }
+ else
+ { byte *cstr;
+ code = lib_file_open(pname.fname, pname.len, cname, maxclen,
+ &clen, op + 1);
+ if ( code == e_VMerror )
+ return code;
+ if ( code < 0 )
+ { push(1);
+ make_false(op);
+ return 0;
+ }
+ cstr = ialloc_string(clen, "findlibfile");
+ if ( cstr == 0 )
+ return_error(e_VMerror);
+ memcpy(cstr, cname, clen);
+ make_string(op, a_all | icurrent_space, clen, cstr);
+ }
+ push(2);
+ make_true(op);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfile_op_defs) {
+ {"1deletefile", zdeletefile},
+ {"1.execfile", zexecfile},
+ {"2file", zfile},
+ {"3filenameforall", zfilenameforall},
+ {"2.filenamedirseparator", zfilenamedirseparator},
+ {"0.filenamelistseparator", zfilenamelistseparator},
+ {"1.filenamesplit", zfilenamesplit},
+ {"1findlibfile", zfindlibfile},
+ {"2renamefile", zrenamefile},
+ {"1status", zstatus},
+ /* Internal operators */
+ {"0%file_continue", file_continue},
+ {"0%execfile_finish", execfile_finish},
+END_OP_DEFS(zfile_init) }
+
+/* ------ Stream opening ------ */
+
+/* Make a t_file reference to a stream. */
+void
+make_stream_file(ref *pfile, stream *s, const char *access)
+{ uint attrs =
+ (access[1] == '+' ? a_write + a_read + a_execute : 0) |
+ imemory_space((gs_ref_memory_t *)s->memory);
+ if ( access[0] == 'r' )
+ { make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
+ s->write_id = 0;
+ }
+ else
+ { make_file(pfile, attrs | a_write, s->write_id, s);
+ s->read_id = 0;
+ }
+}
+
+/* Open an OS-level file (like fopen), using the search paths if necessary. */
+/* Note that it does not automatically look in the current */
+/* directory first (or at all): this is like Unix, and unlike MS-DOS. */
+private int
+lib_file_fopen(gx_io_device *iodev, const char *bname,
+ const char *ignore_access, FILE **pfile, char *rfname, uint rnamelen)
+{ char fmode[3]; /* r, [b], null */
+ int len = strlen(bname);
+ const gs_file_path *pfpath = &gs_lib_path;
+ uint pi;
+
+ strcpy(fmode, "r");
+ strcat(fmode, gp_fmode_binary_suffix);
+ if ( gp_file_name_is_absolute(bname, len) )
+ return (*iodev->procs.fopen)(iodev, bname, fmode, pfile,
+ rfname, rnamelen);
+ /* Go through the list of search paths */
+ for ( pi = 0; pi < r_size(&pfpath->list); ++pi )
+ { const ref *prdir = pfpath->list.value.refs + pi;
+ const char *pstr = (const char *)prdir->value.const_bytes;
+ uint plen = r_size(prdir);
+ const char *cstr =
+ gp_file_name_concat_string(pstr, plen, bname, len);
+ int up, i;
+ int code;
+
+ /* Concatenate the prefix, combiner, and file name. */
+ /* Do this carefully in case rfname is the same */
+ /* as fname. (We don't worry about the case */
+ /* where rfname only overlaps fname.) */
+ up = plen + strlen(cstr);
+ if ( up + len + 1 > rnamelen )
+ return_error(e_limitcheck);
+ for ( i = len + 1; --i >= 0; )
+ rfname[i + up] = bname[i];
+ memcpy(rfname, pstr, plen);
+ memcpy(rfname + plen, cstr, strlen(cstr));
+ code = (*iodev->procs.fopen)(iodev, rfname, fmode,
+ pfile, rfname, rnamelen);
+ if ( code >= 0 )
+ return code;
+ /* strcpy isn't guaranteed to work for overlapping */
+ /* source and destination, so: */
+ if ( rfname == bname )
+ for ( i = 0; (rfname[i] = rfname[i + up]) != 0; i++ )
+ ;
+ }
+ return_error(e_undefinedfilename);
+}
+/* The startup code calls this to open @-files. */
+FILE *
+lib_fopen(const char *bname)
+{ FILE *file = NULL;
+ /* We need a buffer to hold the expanded file name. */
+#define max_filename 129
+ char buffer[max_filename];
+ int code = lib_file_fopen(iodev_default, bname, "r", &file,
+ buffer, max_filename);
+#undef max_filename
+ return (code < 0 ? NULL : file);
+}
+
+/* Open a file stream on an OS file and create a file object, */
+/* using the search paths. */
+/* The startup code calls this to open the initialization file gs_init.ps. */
+int
+lib_file_open(const char *fname, uint len, byte *cname, uint max_clen,
+ uint *pclen, ref *pfile)
+{ stream *s;
+ int code = file_open_stream(fname, len, "r",
+ default_buffer_size, &s, lib_file_fopen);
+ char *bname;
+ uint blen;
+
+ if ( code < 0 )
+ return code;
+ /* Get the name from the stream buffer. */
+ bname = (char *)s->cbuf;
+ blen = strlen(bname);
+ if ( blen > max_clen )
+ { sclose(s);
+ return_error(e_limitcheck);
+ }
+ memcpy(cname, bname, blen);
+ *pclen = blen;
+ make_stream_file(pfile, s, "r");
+ return 0;
+}
+
+/* Open a file stream that reads a string. */
+/* (This is currently used only by the ccinit feature.) */
+/* The string must be allocated in non-garbage-collectable (foreign) space. */
+int
+file_read_string(const byte *str, uint len, ref *pfile)
+{ stream *s = file_alloc_stream(imemory, "file_read_string");
+ int space;
+
+ if ( s == 0 )
+ return_error(e_VMerror);
+ space = icurrent_space;
+ sread_string(s, str, len);
+ s->foreign = 1;
+ s->write_id = 0;
+ make_file(pfile, a_readonly | space, s->read_id, s);
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_disable;
+ return 0;
+}
+
+/* Open a file stream, optionally on an OS file. */
+/* Return 0 if successful, error code if not. */
+/* On a successful return, the C file name is in the stream buffer. */
+/* If fname==0, set up the file entry, stream, and buffer, */
+/* but don't open an OS file or initialize the stream. */
+int
+file_open_stream(const char *fname, uint len, const char *file_access,
+ uint buffer_size, stream **ps, iodev_proc_fopen_t fopen_proc)
+{ byte *buffer;
+ register stream *s;
+ if ( buffer_size == 0 )
+ buffer_size = default_buffer_size;
+ if ( len >= buffer_size )
+ return_error(e_limitcheck); /* we copy the file name into the buffer */
+ /* Allocate the stream first, since it persists */
+ /* even after the file has been closed. */
+ s = file_alloc_stream(imemory, "file_open_stream");
+ if ( s == 0 )
+ return_error(e_VMerror);
+ /* Allocate the buffer. */
+ buffer = ialloc_bytes(buffer_size, "file_open(buffer)");
+ if ( buffer == 0 )
+ return_error(e_VMerror);
+ if ( fname != 0 )
+ { /* Copy the name (so we can terminate it with a zero byte.) */
+ char *file_name = (char *)buffer;
+ char fmode[4]; /* r/w/a, [+], [b], null */
+ FILE *file;
+ int code;
+ memcpy(file_name, fname, len);
+ file_name[len] = 0; /* terminate string */
+ /* Open the file, always in binary mode. */
+ strcpy(fmode, file_access);
+ strcat(fmode, gp_fmode_binary_suffix);
+ /****** iodev_default IS QUESTIONABLE ******/
+ code = (*fopen_proc)(iodev_default, file_name, fmode, &file,
+ (char *)buffer, buffer_size);
+ if (code < 0 )
+ { ifree_object(buffer, "file_open(buffer)");
+ return code;
+ }
+ /* Set up the stream. */
+ switch ( fmode[0] )
+ {
+ case 'a':
+ sappend_file(s, file, buffer, buffer_size);
+ break;
+ case 'r':
+ sread_file(s, file, buffer, buffer_size);
+ break;
+ case 'w':
+ swrite_file(s, file, buffer, buffer_size);
+ }
+ if ( fmode[1] == '+' )
+ s->file_modes |= s_mode_read | s_mode_write;
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_file;
+ }
+ else /* save the buffer and size */
+ { s->cbuf = buffer;
+ s->bsize = s->cbsize = buffer_size;
+ }
+ *ps = s;
+ return 0;
+}
+
+/* Open a file stream for a filter. */
+int
+filter_open(const char *file_access, uint buffer_size, ref *pfile,
+ const stream_procs _ds *procs, const stream_template *template,
+ const stream_state *st)
+{ stream *s;
+ uint ssize = gs_struct_type_size(template->stype);
+ stream_state *sst = 0;
+ int code;
+
+ if ( template->stype != &st_stream_state )
+ { sst = s_alloc_state(imemory, template->stype,
+ "filter_open(stream_state)");
+ if ( sst == 0 )
+ return_error(e_VMerror);
+ }
+ code = file_open_stream((char *)0, 0, file_access,
+ buffer_size, &s, (iodev_proc_fopen_t)0);
+ if ( code < 0 )
+ { ifree_object(sst, "filter_open(stream_state)");
+ return code;
+ }
+ s_std_init(s, s->cbuf, s->bsize, procs,
+ (*file_access == 'r' ? s_mode_read : s_mode_write));
+ s->procs.process = template->process;
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_file;
+ if ( sst == 0 )
+ { /* This stream doesn't have any state of its own. */
+ /* Hack: use the stream itself as the state. */
+ sst = (stream_state *)s;
+ }
+ else if ( st != 0 ) /* might not have client parameters */
+ memcpy(sst, st, ssize);
+ s->state = sst;
+ sst->template = template;
+ sst->memory = imemory;
+ sst->report_error = filter_report_error;
+ if ( template->init != 0 )
+ { code = (*template->init)(sst);
+ if ( code < 0 )
+ { ifree_object(sst, "filter_open(stream_state)");
+ ifree_object(s->cbuf, "filter_open(buffer)");
+ return code;
+ }
+ }
+ make_stream_file(pfile, s, file_access);
+ return 0;
+}
+
+/* Report an error by storing it in $error.errorinfo. */
+private int
+filter_report_error(stream_state *st, const char *str)
+{ if_debug1('s', "[s]stream error: %s\n", str);
+ return gs_errorinfo_put_string(str);
+}
+
+/* Allocate and return a file stream. */
+/* Return 0 if the allocation failed. */
+/* The stream is initialized to an invalid state, so the caller need not */
+/* worry about cleaning up if a later step in opening the stream fails. */
+stream *
+file_alloc_stream(gs_memory_t *mem, client_name_t cname)
+{ stream *s;
+ /* Look first for a free stream allocated at this level. */
+ s = file_list;
+ while ( s != 0 && s->save_count == 0 )
+ { if ( !s_is_valid(s) && s->read_id != 0 /* i.e. !overflowed */
+ && s->memory == mem
+ )
+ { s->is_temp = 0; /* not a temp stream */
+ return s;
+ }
+ s = s->next;
+ }
+ s = s_alloc(mem, cname);
+ if ( s == 0 )
+ return 0;
+ s_init_ids(s);
+ s->is_temp = 0; /* not a temp stream */
+ /* Disable the stream now (in case we can't open the file, */
+ /* or a filter init procedure fails) so that `restore' won't */
+ /* crash when it tries to close open files. */
+ s_disable(s);
+ /* Add s to the list of files. */
+ if ( file_list != 0 )
+ file_list->prev = s;
+ s->next = file_list;
+ s->prev = 0;
+ s->save_count = 0;
+ file_list = s;
+ return s;
+}
+
+/* ------ Stream closing ------ */
+
+/* Finish closing a file stream. This used to check whether it was */
+/* currentfile, but we don't have to do this any longer. */
+/* This replaces the close procedure for the std* streams, */
+/* which cannot actually be closed. */
+/* This is exported for ziodev.c. */
+int
+file_close_finish(stream *s)
+{ return 0;
+}
+
+/* Close a file stream, but don't deallocate the buffer. */
+/* This replaces the close procedure for %lineedit and %statementedit. */
+/* (This is WRONG: these streams should allocate a new buffer each time */
+/* they are opened, but that would overstress the allocator right now.) */
+/* This is exported for ziodev.c. */
+/* This also replaces the close procedure for the string-reading */
+/* stream created for gs_run_string. */
+int
+file_close_disable(stream *s)
+{ int code = (*s->save_close)(s);
+ if ( code )
+ return code;
+ /* Increment the IDs to prevent further access. */
+ s->read_id = s->write_id = (s->read_id | s->write_id) + 1;
+ return file_close_finish(s);
+}
+
+/* Close a file stream. This replaces the close procedure in the stream */
+/* for normal (OS) files and for filters. */
+int
+file_close_file(stream *s)
+{ stream *stemp = s->strm;
+ gs_memory_t *mem;
+ int code = file_close_disable(s);
+ if ( code )
+ return code;
+ /*
+ * Check for temporary streams created for filters.
+ * There may be more than one in the case of a procedure-based filter,
+ * or if we created an intermediate stream to ensure
+ * a large enough buffer. Note that these streams may have been
+ * allocated by file_alloc_stream, so we mustn't free them.
+ */
+ while ( stemp != 0 && stemp->is_temp != 0 )
+ { stream *snext = stemp->strm;
+ mem = stemp->memory;
+ if ( stemp->is_temp > 1 )
+ gs_free_object(mem, stemp->cbuf,
+ "file_close(temp stream buffer)");
+ s_disable(stemp);
+ stemp = snext;
+ }
+ mem = s->memory;
+ gs_free_object(mem, s->cbuf, "file_close(buffer)");
+ return 0;
+}
+
+/* Close a file object. */
+/* This is exported only for gsmain.c. */
+int
+file_close(ref *pfile)
+{ stream *s;
+ if ( file_is_valid(s, pfile) ) /* closing a closed file is a no-op */
+ { if ( sclose(s) )
+ return_error(e_ioerror);
+ }
+ return 0;
+}
+
+/* ------ Memory management ------ */
+
+/* Mark the current file list at a save. */
+void
+file_save(void)
+{ if_debug1('u', "[u]file_save 0x%lx\n",
+ (ulong)file_list);
+ if ( file_list != 0 )
+ file_list->save_count++;
+}
+
+/* Update the file list before a restore. */
+void
+file_restore(const alloc_save_t *save, const gs_memory_t *mem)
+{ stream *prev = 0;
+ stream *s;
+ stream **ps;
+ /* We must be careful to unlink only those streams which */
+ /* were allocated in the VM space being restored. */
+ for ( ps = &file_list; (s = *ps) != 0 && s->save_count == 0; )
+ if ( s->memory == mem )
+ { if ( (*ps = s->next) != 0 )
+ (*ps)->prev = prev;
+ }
+ else
+ prev = s, ps = &s->next;
+ if ( s != 0 ) /* i.e., s->save_count != 0 */
+ s->save_count--;
+ if_debug2('u', "[u]file_restore 0x%lx for 0x%lx\n",
+ (ulong)file_list, (ulong)save);
+}
+
+/* Note that a save has been forgotten. */
+void
+file_forget_save(const alloc_save_t *save)
+{ stream *s;
+ for ( s = file_list; s != 0 && s->save_count == 0; )
+ s = s->next;
+ if ( s != 0 )
+ s->save_count--;
+ if_debug2('u', "[u]file_forget_save 0x%lx for 0x%lx\n",
+ (ulong)file_list, (ulong)save);
+}
+
+/* Clear the file list for a GC. */
+void
+file_gc_prepare(void)
+{ /* We have to unlink every stream from its neighbors, */
+ /* so that referenced streams don't keep all streams around. */
+ while ( file_list != 0 )
+ { stream *s = file_list;
+ file_list = s->next;
+ s->prev = s->next = 0;
+ }
+}
diff --git a/gs/src/zfileio.c b/gs/src/zfileio.c
new file mode 100644
index 000000000..c648b9fd3
--- /dev/null
+++ b/gs/src/zfileio.c
@@ -0,0 +1,782 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfileio.c */
+/* File I/O operators */
+#include "ghost.h"
+#include "gp.h"
+#include "errors.h"
+#include "oper.h"
+#include "stream.h"
+#include "files.h"
+#include "store.h"
+#include "strimpl.h" /* for ifilter.h */
+#include "ifilter.h" /* for procedure streams */
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Forward references */
+private int write_string(P2(ref *, stream *));
+private int handle_read_status(P4(int, const ref *, const uint *,
+ int (*)(P1(os_ptr))));
+private int handle_write_status(P4(int, const ref *, const uint *,
+ int (*)(P1(os_ptr))));
+
+/* ------ Operators ------ */
+
+/* <file> closefile - */
+int
+zclosefile(register os_ptr op)
+{ stream *s;
+ check_type(*op, t_file);
+ if ( file_is_valid(s, op) ) /* closing a closed file is a no-op */
+ { int status = sclose(s);
+ if ( status != 0 )
+ { if ( s_is_writing(s) )
+ return handle_write_status(status, op, NULL,
+ zclosefile);
+ else
+ return handle_read_status(status, op, NULL,
+ zclosefile);
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <file> read <int> -true- */
+/* <file> read -false- */
+private int
+zread(register os_ptr op)
+{ stream *s;
+ int ch;
+ check_read_file(s, op);
+ ch = sgetc(s);
+ if ( ch >= 0 )
+ { push(1);
+ make_int(op - 1, ch);
+ make_bool(op, 1);
+ }
+ else if ( ch == EOFC )
+ make_bool(op, 0);
+ else
+ return handle_read_status(ch, op, NULL, zread);
+ return 0;
+}
+
+/* <file> <int> write - */
+int
+zwrite(register os_ptr op)
+{ stream *s;
+ byte ch;
+ int status;
+ check_write_file(s, op - 1);
+ check_type(*op, t_integer);
+ ch = (byte)op->value.intval;
+ status = sputc(s, (byte)ch);
+ if ( status >= 0 )
+ { pop(2);
+ return 0;
+ }
+ return handle_write_status(status, op - 1, NULL, zwrite);
+}
+
+/* <file> <string> readhexstring <substring> <filled_bool> */
+private int zreadhexstring_continue(P1(os_ptr));
+/* We keep track of the odd digit in the next byte of the string */
+/* beyond the bytes already used. (This is just for convenience; */
+/* we could do the same thing by passing 2 state parameters to the */
+/* continuation procedure instead of 1.) */
+private int
+zreadhexstring_at(register os_ptr op, uint start)
+{ stream *s;
+ uint len, nread;
+ byte *str;
+ int odd;
+ stream_cursor_write cw;
+ int status;
+ check_read_file(s, op - 1);
+ /*check_write_type(*op, t_string);*/ /* done by caller */
+ str = op->value.bytes;
+ len = r_size(op);
+ if ( start < len )
+ { odd = str[start];
+ if ( odd > 0xf ) odd = -1;
+ }
+ else
+ odd = -1;
+ cw.ptr = str + start - 1;
+ cw.limit = str + len - 1;
+ for ( ; ; )
+ { status = s_hex_process(&s->cursor.r, &cw, &odd,
+ hex_ignore_garbage);
+ if ( status == 1 ) /* filled the string */
+ { ref_assign_inline(op - 1, op);
+ make_true(op);
+ return 0;
+ }
+ else if ( status != 0 ) /* error or EOF */
+ break;
+ /* Didn't fill, keep going. */
+ status = spgetc(s);
+ if ( status < 0 )
+ break;
+ sputback(s);
+ }
+ nread = cw.ptr + 1 - str;
+ if ( status != EOFC )
+ { /* Error */
+ if ( nread < len )
+ str[nread] = (odd < 0 ? 0x10 : odd);
+ return handle_read_status(status, op - 1, &nread,
+ zreadhexstring_continue);
+ }
+ /* Reached end-of-file before filling the string. */
+ /* Return an appropriate substring. */
+ ref_assign_inline(op - 1, op);
+ r_set_size(op - 1, nread);
+ make_false(op);
+ return 0;
+}
+private int
+zreadhexstring(os_ptr op)
+{ check_write_type(*op, t_string);
+ if ( r_size(op) > 0 )
+ *op->value.bytes = 0x10;
+ return zreadhexstring_at(op, 0);
+}
+/* Continue a readhexstring operation after a callout. */
+/* *op is the index within the string. */
+private int
+zreadhexstring_continue(register os_ptr op)
+{ int code;
+ check_type(*op, t_integer);
+ if ( op->value.intval < 0 || op->value.intval > r_size(op - 1) )
+ return_error(e_rangecheck);
+ check_write_type(op[-1], t_string);
+ code = zreadhexstring_at(op - 1, (uint)op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* <file> <string> writehexstring - */
+private int zwritehexstring_continue(P1(os_ptr));
+private int
+zwritehexstring_at(register os_ptr op, uint odd)
+{ register stream *s;
+ register byte ch;
+ register const byte *p;
+ register const char _ds *hex_digits = "0123456789abcdef";
+ register uint len;
+ int status;
+#define max_hex 128
+ byte buf[max_hex];
+ check_write_file(s, op - 1);
+ check_read_type(*op, t_string);
+ p = op->value.bytes;
+ len = r_size(op);
+ while ( len )
+ { uint len1 = min(len, max_hex / 2);
+ register byte *q = buf;
+ uint count = len1;
+ ref rbuf;
+ do
+ { ch = *p++;
+ *q++ = hex_digits[ch >> 4];
+ *q++ = hex_digits[ch & 0xf];
+ }
+ while ( --count );
+ r_set_size(&rbuf, (len1 << 1) - odd);
+ rbuf.value.bytes = buf + odd;
+ status = write_string(&rbuf, s);
+ switch ( status )
+ {
+ default:
+ return_error(e_ioerror);
+ case 0:
+ len -= len1;
+ odd = 0;
+ continue;
+ case INTC:
+ case CALLC:
+ count = rbuf.value.bytes - buf;
+ op->value.bytes += count >> 1;
+ r_set_size(op, len - (count >> 1));
+ count &= 1;
+ return handle_write_status(status, op - 1, &count,
+ zwritehexstring_continue);
+ }
+ }
+ pop(2);
+ return 0;
+#undef max_hex
+}
+private int
+zwritehexstring(os_ptr op)
+{ return zwritehexstring_at(op, 0);
+}
+/* Continue a writehexstring operation after a callout. */
+/* *op is the odd/even hex digit flag for the first byte. */
+private int
+zwritehexstring_continue(register os_ptr op)
+{ int code;
+ check_type(*op, t_integer);
+ if ( (op->value.intval & ~1) != 0 )
+ return_error(e_rangecheck);
+ code = zwritehexstring_at(op - 1, (uint)op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* <file> <string> readstring <substring> <filled_bool> */
+private int zreadstring_continue(P1(os_ptr));
+private int
+zreadstring_at(register os_ptr op, uint start)
+{ stream *s;
+ uint len, rlen;
+ int status;
+ check_read_file(s, op - 1);
+ check_write_type(*op, t_string);
+ len = r_size(op);
+ status = sgets(s, op->value.bytes + start, len - start, &rlen);
+ rlen += start;
+ switch ( status )
+ {
+ case EOFC:
+ case 0:
+ break;
+ default:
+ return handle_read_status(status, op - 1, &rlen,
+ zreadstring_continue);
+ }
+ /*
+ * The most recent Adobe specification says that readstring
+ * must signal a rangecheck if the string length is zero.
+ * I can't imagine the motivation for this, but we emulate it.
+ * It's safe to check it here, rather than earlier, because if
+ * len is zero, sgets will return 0 immediately with rlen = 0.
+ */
+ if ( len == 0 )
+ return_error(e_rangecheck);
+ r_set_size(op, rlen);
+ op[-1] = *op;
+ make_bool(op, (rlen == len ? 1 : 0));
+ return 0;
+}
+private int
+zreadstring(os_ptr op)
+{ return zreadstring_at(op, 0);
+}
+/* Continue a readstring operation after a callout. */
+/* *op is the index within the string. */
+private int
+zreadstring_continue(register os_ptr op)
+{ int code;
+ check_type(*op, t_integer);
+ if ( op->value.intval < 0 || op->value.intval > r_size(op - 1) )
+ return_error(e_rangecheck);
+ code = zreadstring_at(op - 1, (uint)op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* <file> <string> writestring - */
+private int
+zwritestring(register os_ptr op)
+{ stream *s;
+ int status;
+ check_write_file(s, op - 1);
+ check_read_type(*op, t_string);
+ status = write_string(op, s);
+ if ( status >= 0 )
+ { pop(2);
+ return 0;
+ }
+ return handle_write_status(status, op - 1, NULL, zwritestring);
+}
+
+/* <file> <string> readline <substring> <bool> */
+private int zreadline(P1(os_ptr));
+private int zreadline_continue(P1(os_ptr));
+/*
+ * We could handle readline the same way as readstring,
+ * except for the anomalous situation where we get interrupted
+ * between the CR and the LF of an end-of-line marker.
+ * We hack around this in the following way: if we get interrupted
+ * before we've read any characters, we just restart the readline;
+ * if we get interrupted at any other time, we use readline_continue;
+ * we use start=0 (which we have just ruled out as a possible start value
+ * for readline_continue) to indicate interruption after the CR.
+ */
+private int
+zreadline_at(register os_ptr op, uint count, bool in_eol)
+{ stream *s;
+ byte *ptr;
+ uint len;
+ int status;
+ check_read_file(s, op - 1);
+ check_write_type(*op, t_string);
+ ptr = op->value.bytes;
+ len = r_size(op);
+ status = zreadline_from(s, ptr, len, &count, &in_eol);
+ switch ( status )
+ {
+ case 0:
+ case EOFC:
+ break;
+ case 1:
+ return_error(e_rangecheck);
+ default:
+ if ( count == 0 && !in_eol )
+ return handle_read_status(status, op - 1, NULL,
+ zreadline);
+ else
+ { if ( in_eol )
+ { r_set_size(op, count);
+ count = 0;
+ }
+ return handle_read_status(status, op - 1, &count,
+ zreadline_continue);
+ }
+ }
+ r_set_size(op, count);
+ op[-1] = *op;
+ make_bool(op, status == 0);
+ return 0;
+}
+private int
+zreadline(register os_ptr op)
+{ return zreadline_at(op, 0, false);
+}
+/* Continue a readline operation after a callout. */
+/* *op is the index within the string, or 0 for an interrupt after a CR. */
+private int
+zreadline_continue(register os_ptr op)
+{ uint size = r_size(op - 1);
+ uint start;
+ int code;
+
+ check_type(*op, t_integer);
+ if ( op->value.intval < 0 || op->value.intval > size )
+ return_error(e_rangecheck);
+ start = (uint)op->value.intval;
+ code = (start == 0 ? zreadline_at(op - 1, size, true) :
+ zreadline_at(op - 1, start, false));
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* Internal readline routine. */
+/* Returns a stream status value, or 1 if we overflowed the string. */
+/* This is exported for %lineedit. */
+int
+zreadline_from(stream *s, byte *ptr, uint size, uint *pcount, bool *pin_eol)
+{ uint count = *pcount;
+
+ /* Most systems define \n as 0xa and \r as 0xd; however, */
+ /* OS-9 has \n == \r == 0xd and \l == 0xa. The following */
+ /* code works properly regardless of environment. */
+#if '\n' == '\r'
+# define LF 0xa
+#else
+# define LF '\n'
+#endif
+
+top: if ( *pin_eol )
+ { /*
+ * We're in the middle of checking for a two-character
+ * end-of-line sequence. If we get an EOF here, stop, but
+ * don't signal EOF now; wait till the next read.
+ */
+ int ch = spgetcc(s, false);
+ if ( ch == EOFC )
+ { *pin_eol = false;
+ return 0;
+ }
+ else if ( ch < 0 )
+ return ch;
+ else if ( ch != LF )
+ sputback(s);
+ *pin_eol = false;
+ return 0;
+ }
+ for ( ; ; )
+ { int ch = sgetc(s);
+ if ( ch < 0 ) /* EOF or exception */
+ { *pcount = count;
+ return ch;
+ }
+
+ switch ( ch )
+ {
+ case '\r':
+ {
+#if '\n' == '\r' /* OS-9 or similar */
+ stream *ins;
+ int code = zget_stdin(&ins);
+ if ( code < 0 || s != ins )
+#endif
+ { *pcount = count;
+ *pin_eol = true;
+ goto top;
+ }
+ }
+ /* falls through */
+ case LF:
+#undef LF
+ *pcount = count;
+ return 0;
+ }
+ if ( count >= size ) /* filled the string */
+ { sputback(s);
+ *pcount = count;
+ return 1;
+ }
+ ptr[count++] = ch;
+ }
+ /*return 0;*/ /* not reached */
+}
+
+/* <file> bytesavailable <int> */
+private int
+zbytesavailable(register os_ptr op)
+{ stream *s;
+ long avail;
+ check_read_file(s, op);
+ switch ( savailable(s, &avail) )
+ {
+ default:
+ return_error(e_ioerror);
+ case EOFC:
+ avail = -1;
+ case 0:
+ ;
+ }
+ make_int(op, avail);
+ return 0;
+}
+
+/* - flush - */
+int
+zflush(register os_ptr op)
+{ stream *s;
+ int code = zget_stdout(&s);
+ if ( code < 0 )
+ return code;
+ sflush(s);
+ return 0;
+}
+
+/* <file> flushfile - */
+private int
+zflushfile(register os_ptr op)
+{ stream *s;
+ int status;
+ check_file(s, op);
+ status = sflush(s);
+ if ( status == 0 )
+ { pop(1);
+ return 0;
+ }
+ return
+ (s_is_writing(s) ?
+ handle_write_status(status, op, NULL, zflushfile) :
+ handle_read_status(status, op, NULL, zflushfile));
+}
+
+/* <file> resetfile - */
+private int
+zresetfile(register os_ptr op)
+{ stream *s;
+ /* According to Adobe, resetfile is a no-op on closed files. */
+ check_type(*op, t_file);
+ if ( file_is_valid(s, op) )
+ sreset(s);
+ pop(1);
+ return 0;
+}
+
+/* <string> print - */
+private int
+zprint(register os_ptr op)
+{ stream *s;
+ int status;
+ ref rstdout;
+ int code;
+ check_read_type(*op, t_string);
+ code = zget_stdout(&s);
+ if ( code < 0 )
+ return code;
+ status = write_string(op, s);
+ if ( status >= 0 )
+ { pop(1);
+ return 0;
+ }
+ /* Convert print to writestring on the fly. */
+ make_stream_file(&rstdout, s, "w");
+ code = handle_write_status(status, &rstdout, NULL, zwritestring);
+ if ( code != o_push_estack )
+ return code;
+ push(1);
+ *op = op[-1];
+ op[-1] = rstdout;
+ return code;
+}
+
+/* <bool> echo - */
+private int
+zecho(register os_ptr op)
+{ check_type(*op, t_boolean);
+ /****** NOT IMPLEMENTED YET ******/
+ pop(1);
+ return 0;
+}
+
+/* ------ Level 2 extensions ------ */
+
+/* <file> fileposition <int> */
+private int
+zfileposition(register os_ptr op)
+{ stream *s;
+ check_file(s, op);
+ make_int(op, stell(s));
+ return 0;
+}
+
+/* <file> <int> setfileposition - */
+private int
+zsetfileposition(register os_ptr op)
+{ stream *s;
+ check_file(s, op - 1);
+ check_type(*op, t_integer);
+ if ( sseek(s, op->value.intval) < 0 )
+ return_error(e_ioerror);
+ pop(2);
+ return 0;
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <file> <int> unread - */
+private int
+zunread(register os_ptr op)
+{ stream *s;
+ ulong ch;
+ check_read_file(s, op - 1);
+ check_type(*op, t_integer);
+ ch = op->value.intval;
+ if ( ch > 0xff )
+ return_error(e_rangecheck);
+ if ( sungetc(s, (byte)ch) < 0 )
+ return_error(e_ioerror);
+ pop(2);
+ return 0;
+}
+
+/* <file> <object> <==flag> .writecvp - */
+private int zwritecvp_continue(P1(os_ptr));
+private int
+zwritecvp_at(register os_ptr op, uint start)
+{ stream *s;
+#define max_cvs 128
+ byte str[max_cvs];
+ ref rstr;
+ const byte *pchars = str;
+ uint len;
+ int code, status;
+
+ check_write_file(s, op - 2);
+ check_type(*op, t_boolean);
+ code = obj_cvp(op - 1, str, max_cvs, &len, &pchars, op->value.boolval);
+ if ( code < 0 )
+ { if ( pchars == str )
+ return code;
+ }
+ if ( start > len )
+ return_error(e_rangecheck);
+ r_set_size(&rstr, len - start);
+ rstr.value.const_bytes = pchars + start;
+ status = write_string(&rstr, s);
+ switch ( status )
+ {
+ default:
+ return_error(e_ioerror);
+ case 0:
+ break;
+ case INTC:
+ case CALLC:
+ len -= r_size(&rstr);
+ return handle_write_status(status, op - 2, &len,
+ zwritecvp_continue);
+ }
+ pop(3);
+ return 0;
+#undef max_cvs
+}
+private int
+zwritecvp(os_ptr op)
+{ return zwritecvp_at(op, 0);
+}
+/* Continue a .writecvp after a callout. */
+/* *op is the index within the string. */
+private int
+zwritecvp_continue(os_ptr op)
+{ int code;
+ check_type(*op, t_integer);
+ if ( op->value.intval != (uint)op->value.intval )
+ return_error(e_rangecheck);
+ code = zwritecvp_at(op - 1, (uint)op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfileio_op_defs) {
+ {"1bytesavailable", zbytesavailable},
+ {"1closefile", zclosefile},
+ /* currentfile is in zcontrol.c */
+ {"1echo", zecho},
+ {"1fileposition", zfileposition},
+ {"0flush", zflush},
+ {"1flushfile", zflushfile},
+ {"1print", zprint},
+ {"1read", zread},
+ {"2readhexstring", zreadhexstring},
+ {"2readline", zreadline},
+ {"2readstring", zreadstring},
+ {"1resetfile", zresetfile},
+ {"2setfileposition", zsetfileposition},
+ {"2unread", zunread},
+ {"2write", zwrite},
+ {"3.writecvp", zwritecvp},
+ {"2writehexstring", zwritehexstring},
+ {"2writestring", zwritestring},
+ /* Internal operators */
+ {"3%zreadhexstring_continue", zreadhexstring_continue},
+ {"3%zwritehexstring_continue", zwritehexstring_continue},
+ {"3%zreadstring_continue", zreadstring_continue},
+ {"3%zreadline_continue", zreadline_continue},
+ {"4%zwritecvp_continue", zwritecvp_continue},
+END_OP_DEFS(0) }
+
+/* ------ Non-operator routines ------ */
+
+/* Switch a file open for read/write access but currently in write mode */
+/* to read mode. */
+int
+file_switch_to_read(const ref *op)
+{ stream *s = fptr(op);
+ if ( s->write_id != r_size(op) || s->file == 0 ) /* not valid */
+ return_error(e_invalidaccess);
+ if ( sswitch(s, false) < 0 )
+ return_error(e_ioerror);
+ s->read_id = s->write_id; /* enable reading */
+ s->write_id = 0; /* disable writing */
+ return 0;
+}
+
+/* Switch a file open for read/write access but currently in read mode */
+/* to write mode. */
+int
+file_switch_to_write(const ref *op)
+{ stream *s = fptr(op);
+ if ( s->read_id != r_size(op) || s->file == 0 ) /* not valid */
+ return_error(e_invalidaccess);
+ if ( sswitch(s, true) < 0 )
+ return_error(e_ioerror);
+ s->write_id = s->read_id; /* enable writing */
+ s->read_id = 0; /* disable reading */
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Write a string on a file. The file and string have been validated. */
+/* If the status is INTC or CALLC, updates the string on the o-stack. */
+private int
+write_string(ref *op, stream *s)
+{ const byte *data = op->value.const_bytes;
+ uint len = r_size(op);
+ uint wlen;
+ int status = sputs(s, data, len, &wlen);
+ switch ( status )
+ {
+ case INTC:
+ case CALLC:
+ op->value.const_bytes = data + wlen;
+ r_set_size(op, len - wlen);
+ /* falls through */
+ default: /* 0, EOFC, ERRC */
+ return status;
+ }
+}
+
+/* Handle an exceptional status return from a read stream. */
+/* fop points to the ref for the stream. */
+/* ch may be any stream exceptional value. */
+/* Return 0, 1 (EOF), o_push_estack, or an error. */
+private int
+handle_read_status(int ch, const ref *fop, const uint *pindex,
+ int (*cont)(P1(os_ptr)))
+{ switch ( ch )
+ {
+ default: /* error */
+ return_error(e_ioerror);
+ case EOFC:
+ return 1;
+ case INTC:
+ case CALLC:
+ if ( pindex )
+ { ref index;
+ make_int(&index, *pindex);
+ return s_handle_read_exception(ch, fop, &index, 1, cont);
+ }
+ else
+ return s_handle_read_exception(ch, fop, NULL, 0, cont);
+ }
+}
+
+/* Handle an exceptional status return from a write stream. */
+/* fop points to the ref for the stream. */
+/* ch may be any stream exceptional value. */
+/* Return 0, o_push_estack, or an error. */
+private int
+handle_write_status(int ch, const ref *fop, const uint *pindex,
+ int (*cont)(P1(os_ptr)))
+{ switch ( ch )
+ {
+ default: /* error */
+ return_error(e_ioerror);
+ case INTC:
+ case CALLC:
+ if ( pindex )
+ { ref index;
+ make_int(&index, *pindex);
+ return s_handle_write_exception(ch, fop, &index, 1, cont);
+ }
+ else
+ return s_handle_write_exception(ch, fop, NULL, 0, cont);
+ }
+}
diff --git a/gs/src/zfilter.c b/gs/src/zfilter.c
new file mode 100644
index 000000000..8501eaeed
--- /dev/null
+++ b/gs/src/zfilter.c
@@ -0,0 +1,417 @@
+/* Copyright (C) 1993, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfilter.c */
+/* Filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "srlx.h"
+#include "sstring.h"
+#include "ifilter.h"
+#include "files.h" /* for filter_open, file_d'_buffer_size */
+
+/* Define whether we are including some non-standard filters for testing. */
+#define TEST
+
+/* <source> ASCIIHexEncode/filter <file> */
+/* <source> <dict_ignored> ASCIIHexEncode/filter <file> */
+private int
+zAXE(os_ptr op)
+{ return filter_write_simple(op, &s_AXE_template);
+}
+
+/* <target> ASCIIHexDecode/filter <file> */
+/* <target> <dict_ignored> ASCIIHexDecode/filter <file> */
+private int
+zAXD(os_ptr op)
+{ return filter_read_simple(op, &s_AXD_template);
+}
+
+/* <target> NullEncode/filter <file> */
+/* <target> <dict_ignored> NullEncode/filter <file> */
+private int
+zNullE(os_ptr op)
+{ return filter_write_simple(op, &s_NullE_template);
+}
+
+/* <source> <bool> PFBDecode/filter <file> */
+/* <source> <bool> <dict_ignored> PFBDecode/filter <file> */
+private int
+zPFBD(os_ptr op)
+{ stream_PFBD_state state;
+ os_ptr sop = op;
+ int npop = 1;
+
+ if ( r_has_type(op, t_dictionary) )
+ ++npop, --sop;
+ check_type(*sop, t_boolean);
+ state.binary_to_hex = sop->value.boolval;
+ return filter_read(op, npop, &s_PFBD_template, (stream_state *)&state,
+ 0);
+}
+
+/* <target> PSStringEncode/filter <file> */
+/* <target> <dict_ignored> PSStringEncode/filter <file> */
+private int
+zPSSE(os_ptr op)
+{ return filter_write_simple(op, &s_PSSE_template);
+}
+
+/* ------ RunLength filters ------ */
+
+/* Common setup for RLE and RLD filters. */
+private int
+rl_setup(os_ptr op, bool *eod)
+{ if ( r_has_type(op, t_dictionary) )
+ { int code;
+ check_dict_read(*op);
+ if ( (code = dict_bool_param(op, "EndOfData", true, eod)) < 0 )
+ return code;
+ return 1;
+ }
+ else
+ { *eod = true;
+ return 0;
+ }
+}
+
+/* <target> <record_size> RunLengthEncode/filter <file> */
+/* <target> <record_size> <dict> RunLengthEncode/filter <file> */
+private int
+zRLE(register os_ptr op)
+{ stream_RLE_state state;
+ int code = rl_setup(op, &state.EndOfData);
+ if ( code < 0 )
+ return code;
+ check_int_leu(op[-code], max_uint);
+ state.record_size = op->value.intval;
+ return filter_write(op, 1 + code, &s_RLE_template, (stream_state *)&state, 0);
+}
+
+/* <source> RunLengthDecode/filter <file> */
+/* <source> <dict> RunLengthDecode/filter <file> */
+private int
+zRLD(os_ptr op)
+{ stream_RLD_state state;
+ int code = rl_setup(op, &state.EndOfData);
+ if ( code < 0 )
+ return code;
+ return filter_read(op, code, &s_RLD_template, (stream_state *)&state, 0);
+}
+
+/* <source> <EODcount> <EODstring> SubFileDecode/filter <file> */
+/* <source> <EODcount> <EODstring> <dict_ignored> SubFileDecode/filter <file> */
+private int
+zSFD(os_ptr op)
+{ stream_SFD_state state;
+ os_ptr sop = op;
+ int npop = 2;
+
+ if ( r_has_type(op, t_dictionary) )
+ ++npop, --sop;
+ check_type(sop[-1], t_integer);
+ check_read_type(*sop, t_string);
+ if ( sop[-1].value.intval < 0 )
+ return_error(e_rangecheck);
+ state.count = sop[-1].value.intval;
+ state.eod.data = sop->value.const_bytes;
+ state.eod.size = r_size(sop);
+ return filter_read(op, npop, &s_SFD_template, (stream_state *)&state,
+ r_space(sop));
+}
+
+#ifdef TEST
+
+#include "store.h"
+
+/* <size> BigStringEncode/filter <file> */
+private int BSE_close(P1(stream *));
+private int
+zBSE(os_ptr op)
+{ stream *s;
+ byte *data;
+ long len;
+
+ check_type(op[-0], t_integer);
+ len = op[-0].value.intval;
+ if ( len < 0 )
+ return_error(e_rangecheck);
+
+ data = ialloc_string(len, "BigStringEncode(string)");
+ if ( !data )
+ return_error(e_VMerror);
+ s = file_alloc_stream(imemory, "BigStringEncode(stream)");
+ if ( !s )
+ { ifree_string(data, len, "BigStringEncode(string)");
+ return_error(e_VMerror);
+ }
+ swrite_string(s, data, len);
+ s->is_temp = 0;
+ s->read_id = 0;
+ s->procs.close = BSE_close;
+ s->save_close = BSE_close;
+ make_file(op,
+ ((a_write | a_execute) | icurrent_space),
+ s->write_id,
+ s);
+ return 0;
+}
+private int
+BSE_close(stream *s)
+{ return 0;
+}
+
+#endif /* TEST */
+
+/* ------ Utilities ------ */
+
+/* Forward references */
+private int filter_ensure_buf(P3(stream **, uint, bool));
+
+/* Set up an input filter. */
+const stream_procs s_new_read_procs =
+{ s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_filter_close
+};
+int
+filter_read(os_ptr op, int npop, const stream_template *template,
+ stream_state *st, uint space)
+{ uint min_size = template->min_out_size + max_min_left;
+ uint save_space = ialloc_space(idmemory);
+ register os_ptr sop = op - npop;
+ stream *s;
+ stream *sstrm;
+ int code;
+
+ /* Check to make sure that the underlying data */
+ /* can function as a source for reading. */
+ switch ( r_type(sop) )
+ {
+ case t_string:
+ check_read(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ sstrm = file_alloc_stream(imemory,
+ "filter_read(string stream)");
+ if ( sstrm == 0 )
+ { code = gs_note_error(e_VMerror);
+ goto out;
+ }
+ sread_string(sstrm, sop->value.bytes, r_size(sop));
+ sstrm->is_temp = 1;
+ break;
+ case t_file:
+ check_read_known_file(sstrm, sop, return);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ goto ens;
+ default:
+ check_proc(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ code = sread_proc(sop, &sstrm);
+ if ( code < 0 )
+ goto out;
+ sstrm->is_temp = 2;
+ens: code = filter_ensure_buf(&sstrm,
+ template->min_in_size +
+ sstrm->state->template->min_out_size,
+ false);
+ if ( code < 0 )
+ goto out;
+ break;
+ }
+ if ( min_size < 128 )
+ min_size = file_default_buffer_size;
+ code = filter_open("r", min_size, (ref *)sop,
+ &s_new_read_procs, template, st);
+ if ( code < 0 )
+ goto out;
+ s = fptr(sop);
+ s->strm = sstrm;
+ pop(npop);
+out: ialloc_set_space(idmemory, save_space);
+ return code;
+}
+int
+filter_read_simple(os_ptr op, const stream_template *template)
+{ return filter_read(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ template, NULL, 0);
+}
+
+/* Set up an output filter. */
+const stream_procs s_new_write_procs =
+{ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+};
+int
+filter_write(os_ptr op, int npop, const stream_template *template,
+ stream_state *st, uint space)
+{ uint min_size = template->min_in_size + max_min_left;
+ uint save_space = ialloc_space(idmemory);
+ register os_ptr sop = op - npop;
+ stream *s;
+ stream *sstrm;
+ int code;
+
+ /* Check to make sure that the underlying data */
+ /* can function as a sink for writing. */
+ switch ( r_type(sop) )
+ {
+ case t_string:
+ check_write(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ sstrm = file_alloc_stream(imemory,
+ "filter_write(string)");
+ if ( sstrm == 0 )
+ { code = gs_note_error(e_VMerror);
+ goto out;
+ }
+ swrite_string(sstrm, sop->value.bytes, r_size(sop));
+ sstrm->is_temp = 1;
+ break;
+ case t_file:
+ check_write_known_file(sstrm, sop, return);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ goto ens;
+ default:
+ check_proc(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ code = swrite_proc(sop, &sstrm);
+ if ( code < 0 )
+ goto out;
+ sstrm->is_temp = 2;
+ens: code = filter_ensure_buf(&sstrm,
+ template->min_out_size +
+ sstrm->state->template->min_in_size,
+ true);
+ if ( code < 0 )
+ goto out;
+ break;
+ }
+ if ( min_size < 128 )
+ min_size = file_default_buffer_size;
+ code = filter_open("w", min_size, (ref *)sop,
+ &s_new_write_procs, template, st);
+ if ( code < 0 )
+ goto out;
+ s = fptr(sop);
+ s->strm = sstrm;
+ pop(npop);
+out: ialloc_set_space(idmemory, save_space);
+ return code;
+}
+int
+filter_write_simple(os_ptr op, const stream_template *template)
+{ return filter_write(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ template, NULL, 0);
+}
+
+/* Define a byte-at-a-time NullDecode filter for intermediate buffers. */
+/* (The standard NullDecode filter can read ahead too far.) */
+private int
+s_Null1D_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *pw, bool last)
+{ if ( pr->ptr >= pr->limit )
+ return 0;
+ if ( pw->ptr >= pw->limit )
+ return 1;
+ *++(pw->ptr) = *++(pr->ptr);
+ return 1;
+}
+private const stream_template s_Null1D_template =
+{ &st_stream_state, NULL, s_Null1D_process, 1, 1
+};
+
+/* Ensure a minimum buffer size for a filter. */
+/* This may require creating an intermediate stream. */
+private int
+filter_ensure_buf(stream **ps, uint min_buf_size, bool writing)
+{ stream *s = *ps;
+ uint min_size = min_buf_size + max_min_left;
+ stream *bs;
+ ref bsop;
+ int code;
+
+ if ( s->modes == 0 /* stream is closed */ || s->bsize >= min_size )
+ return 0;
+ /* Otherwise, allocate an intermediate stream. */
+ if ( s->cbuf == 0 )
+ { /* This is a newly created procedure stream. */
+ /* Just allocate a buffer for it. */
+ uint len = max(min_size, 128);
+ byte *buf = ialloc_bytes(len, "filter_ensure_buf");
+ if ( buf == 0 )
+ return_error(e_VMerror);
+ s->cbuf = buf;
+ s->srptr = s->srlimit = s->swptr = buf - 1;
+ s->swlimit = buf - 1 + len;
+ s->bsize = s->cbsize = len;
+ return 0;
+ }
+ else
+ { /* Allocate an intermediate stream. */
+ if ( writing )
+ code = filter_open("w", min_size, &bsop, &s_new_write_procs,
+ &s_NullE_template, NULL);
+ else
+ code = filter_open("r", min_size, &bsop, &s_new_read_procs,
+ &s_Null1D_template, NULL);
+ if ( code < 0 )
+ return code;
+ bs = fptr(&bsop);
+ bs->strm = s;
+ bs->is_temp = 2;
+ *ps = bs;
+ return code;
+ }
+}
+
+/* Mark a (filter) stream as temporary. */
+/* We define this here to avoid importing stream.h into zf*.c. */
+void
+filter_mark_temp(const ref *fop, int is_temp)
+{ fptr(fop)->is_temp = is_temp;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfilter_op_defs) {
+ /* We enter PSStringEncode and SubFileDecode (only) */
+ /* as separate operators. */
+ {"1.psstringencode", zPSSE},
+ {"3.subfiledecode", zSFD},
+ op_def_begin_filter(),
+ {"1ASCIIHexEncode", zAXE},
+ {"1ASCIIHexDecode", zAXD},
+ {"1NullEncode", zNullE},
+ {"2PFBDecode", zPFBD},
+ {"1PSStringEncode", zPSSE},
+ {"2RunLengthEncode", zRLE},
+ {"1RunLengthDecode", zRLD},
+ {"3SubFileDecode", zSFD},
+#ifdef TEST
+ {"1BigStringEncode", zBSE},
+#endif
+END_OP_DEFS(0) }
diff --git a/gs/src/zfilter2.c b/gs/src/zfilter2.c
new file mode 100644
index 000000000..1afcf7601
--- /dev/null
+++ b/gs/src/zfilter2.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfilter2.c */
+/* Additional filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "scfx.h"
+#include "slzwx.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "ifilter.h"
+
+/* Import setup code from zfdecode.c */
+int zcf_setup(P2(os_ptr op, stream_CF_state *pcfs));
+int zlz_setup(P2(os_ptr op, stream_LZW_state *plzs));
+int zpd_setup(P2(os_ptr op, stream_PDiff_state *ppds));
+int zpp_setup(P2(os_ptr op, stream_PNGP_state *ppps));
+
+/* ------ CCITTFaxEncode filter ------ */
+
+/* <target> <dict> CCITTFaxEncode/filter <file> */
+private int
+zCFE(os_ptr op)
+{ stream_CFE_state cfs;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = zcf_setup(op, (stream_CF_state *)&cfs);
+ if ( code < 0 )
+ return code;
+ return filter_write(op, 1, &s_CFE_template, (stream_state *)&cfs, 0);
+}
+
+/* ------ Common setup for possibly pixel-oriented encoding filters ------ */
+
+int
+filter_write_predictor(os_ptr op, int npop, const stream_template *template,
+ stream_state *st)
+{ int predictor, code;
+ stream_PDiff_state pds;
+ stream_PNGP_state pps;
+
+ if ( r_has_type(op, t_dictionary) )
+ { if ( (code = dict_int_param(op, "Predictor", 0, 15, 1, &predictor)) < 0 )
+ return code;
+ switch ( predictor )
+ {
+ case 0: /* identity */
+ predictor = 1;
+ case 1: /* identity */
+ break;
+ case 2: /* componentwise horizontal differencing */
+ code = zpd_setup(op, &pds);
+ break;
+ case 10: case 11: case 12: case 13: case 14: case 15:
+ /* PNG prediction */
+ code = zpp_setup(op, &pps);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if ( code < 0 )
+ return code;
+ }
+ else
+ predictor = 1;
+ if ( predictor == 1 )
+ return filter_write(op, npop, template, st, 0);
+ { /* We need to cascade filters. */
+ ref rtarget, rdict, rfd;
+ int code;
+
+ /* Save the operands, just in case. */
+ ref_assign(&rtarget, op - 1);
+ ref_assign(&rdict, op);
+ code = filter_write(op, 1, template, st, 0);
+ if ( code < 0 )
+ return code;
+ /* filter_write changed osp.... */
+ op = osp;
+ ref_assign(&rfd, op);
+ code =
+ (predictor == 2 ?
+ filter_read(op, 0, &s_PDiffE_template, (stream_state *)&pds, 0) :
+ filter_read(op, 0, &s_PNGPE_template, (stream_state *)&pps, 0));
+ if ( code < 0 )
+ { /* Restore the operands. Don't bother trying to clean up */
+ /* the first stream. */
+ osp = ++op;
+ ref_assign(op - 1, &rtarget);
+ ref_assign(op, &rdict);
+ return code;
+ }
+ filter_mark_temp(&rfd, 2); /* Mark the compression stream as temporary. */
+ return code;
+ }
+}
+
+/* ------ LZW encoding filter ------ */
+
+/* <target> LZWEncode/filter <file> */
+/* <target> <dict> LZWEncode/filter <file> */
+/* Note: the default implementation of this filter, in slzwce.c, */
+/* does not use any algorithms that could reasonably be claimed */
+/* to be subject to Unisys' Welch Patent. */
+private int
+zLZWE(os_ptr op)
+{ stream_LZW_state lzs;
+ int code = zlz_setup(op, &lzs);
+
+ if ( code < 0 )
+ return code;
+ return filter_write_predictor(op, code, &s_LZWE_template,
+ (stream_state *)&lzs);
+}
+
+/* ================ Initialization procedure ================ */
+
+BEGIN_OP_DEFS(zfilter2_op_defs) {
+ op_def_begin_filter(),
+ {"2CCITTFaxEncode", zCFE},
+ {"1LZWEncode", zLZWE},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfilterx.c b/gs/src/zfilterx.c
new file mode 100644
index 000000000..a54b49fa2
--- /dev/null
+++ b/gs/src/zfilterx.c
@@ -0,0 +1,314 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfilterx.c */
+/* Extended (non-standard) filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sbwbs.h"
+#include "sbhc.h"
+#include "sbtx.h"
+#include "shcgen.h"
+#include "smtf.h"
+#include "spcxx.h"
+#include "ifilter.h"
+
+/* ------ Bounded Huffman code filters ------ */
+
+/* Common setup for encoding and decoding filters */
+private int
+bhc_setup(os_ptr op, stream_BHC_state *pbhcs)
+{ int code;
+ int num_counts;
+ int data[max_hc_length + 1 + 256 + max_zero_run + 1];
+ uint dsize;
+ int i;
+ uint num_values, accum;
+ ushort *counts;
+ ushort *values;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ( (code = dict_bool_param(op, "FirstBitLowOrder", false,
+ &pbhcs->FirstBitLowOrder)) < 0 ||
+ (code = dict_int_param(op, "MaxCodeLength", 1, max_hc_length,
+ max_hc_length, &num_counts)) < 0 ||
+ (code = dict_bool_param(op, "EndOfData", true,
+ &pbhcs->EndOfData)) < 0 ||
+ (code = dict_uint_param(op, "EncodeZeroRuns", 2, 256,
+ 256, &pbhcs->EncodeZeroRuns)) < 0 ||
+ /* Note: the code returned from the following call */
+ /* is actually the number of elements in the array. */
+ (code = dict_int_array_param(op, "Tables", countof(data),
+ data)) <= 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ dsize = code;
+ if ( dsize <= num_counts + 2 )
+ return_error(e_rangecheck);
+ for ( i = 0, num_values = 0, accum = 0; i <= num_counts;
+ i++, accum <<= 1
+ )
+ { int count = data[i];
+ if ( count < 0 )
+ return_error(e_rangecheck);
+ num_values += count;
+ accum += count;
+ }
+ if ( dsize != num_counts + 1 + num_values ||
+ accum != 1 << (num_counts + 1) ||
+ pbhcs->EncodeZeroRuns >
+ (pbhcs->EndOfData ? num_values - 1 : num_values)
+ )
+ return_error(e_rangecheck);
+ for ( ; i < num_counts + 1 + num_values; i++ )
+ { int value = data[i];
+ if ( value < 0 || value >= num_values )
+ return_error(e_rangecheck);
+ }
+ pbhcs->definition.counts = counts =
+ (ushort *)ialloc_byte_array(num_counts + 1, sizeof(ushort),
+ "bhc_setup(counts)");
+ pbhcs->definition.values = values =
+ (ushort *)ialloc_byte_array(num_values, sizeof(ushort),
+ "bhc_setup(values)");
+ if ( counts == 0 || values == 0 )
+ { ifree_object(values, "bhc_setup(values)");
+ ifree_object(counts, "bhc_setup(counts)");
+ return_error(e_VMerror);
+ }
+ for ( i = 0; i <= num_counts; i++ )
+ counts[i] = data[i];
+ pbhcs->definition.counts = counts;
+ pbhcs->definition.num_counts = num_counts;
+ for ( i = 0; i < num_values; i++ )
+ values[i] = data[i + num_counts + 1];
+ pbhcs->definition.values = values;
+ pbhcs->definition.num_values = num_values;
+ return 0;
+}
+
+/* <target> <dict> BoundedHuffmanEncode/filter <file> */
+private int
+zBHCE(os_ptr op)
+{ stream_BHCE_state bhcs;
+ int code;
+ code = bhc_setup(op, (stream_BHC_state *)&bhcs);
+ if ( code < 0 )
+ return code;
+ return filter_write(op, 1, &s_BHCE_template, (stream_state *)&bhcs, 0);
+}
+
+/* <source> <dict> BoundedHuffmanDecode/filter <file> */
+private int
+zBHCD(os_ptr op)
+{ stream_BHCD_state bhcs;
+ int code;
+ code = bhc_setup(op, (stream_BHC_state *)&bhcs);
+ if ( code < 0 )
+ return code;
+ return filter_read(op, 1, &s_BHCD_template, (stream_state *)&bhcs, 0);
+}
+
+/* <array> <max_length> .computecodes <array> */
+/* The first max_length+1 elements of the array will be filled in with */
+/* the code counts; the remaining elements will be replaced with */
+/* the code values. This is the form needed for the Tables element of */
+/* the dictionary parameter for the BoundedHuffman filters. */
+private int
+zcomputecodes(os_ptr op)
+{ os_ptr op1 = op - 1;
+ uint asize;
+ hc_definition def;
+ ushort *data;
+ long *freqs;
+ int code = 0;
+ check_type(*op, t_integer);
+ check_write_type(*op1, t_array);
+ asize = r_size(op1);
+ if ( op->value.intval < 1 || op->value.intval > max_hc_length )
+ return_error(e_rangecheck);
+ def.num_counts = op->value.intval;
+ if ( asize < def.num_counts + 2 )
+ return_error(e_rangecheck);
+ def.num_values = asize - (def.num_counts + 1);
+ data = (ushort *)gs_alloc_byte_array(imemory, asize, sizeof(ushort),
+ "zcomputecodes");
+ freqs = (long *)gs_alloc_byte_array(imemory, def.num_values,
+ sizeof(long),
+ "zcomputecodes(freqs)");
+ if ( data == 0 || freqs == 0 )
+ code = gs_note_error(e_VMerror);
+ else
+ { uint i;
+ def.counts = data;
+ def.values = data + (def.num_counts + 1);
+ for ( i = 0; i < def.num_values; i++ )
+ { const ref *pf =
+ op1->value.const_refs + i + def.num_counts + 1;
+ if ( !r_has_type(pf, t_integer) )
+ { code = gs_note_error(e_typecheck);
+ break;
+ }
+ freqs[i] = pf->value.intval;
+ }
+ if ( !code )
+ { code = hc_compute(&def, freqs, imemory);
+ if ( code >= 0 )
+ { /* Copy back results. */
+ for ( i = 0; i < asize; i++ )
+ make_int(op1->value.refs + i, data[i]);
+ }
+ }
+ }
+ gs_free_object(imemory, freqs, "zcomputecodes(freqs)");
+ gs_free_object(imemory, data, "zcomputecodes");
+ if ( code < 0 )
+ return code;
+ pop(1);
+ return code;
+}
+
+/* ------ Burrows/Wheeler block sorting filters ------ */
+
+/* Common setup for encoding and decoding filters */
+private int
+bwbs_setup(os_ptr op, stream_BWBS_state *pbwbss)
+{ int code;
+ if ( (code = dict_int_param(op, "BlockSize",
+ 1, max_int / sizeof(int) - 10, 16384,
+ &pbwbss->BlockSize)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* <target> <dict> BWBlockSortEncode/filter <file> */
+private int
+zBWBSE(os_ptr op)
+{ stream_BWBSE_state bwbss;
+ int code;
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
+ if ( code < 0 )
+ return code;
+ return filter_write(op, 1, &s_BWBSE_template, (stream_state *)&bwbss, 0);
+}
+
+/* <source> <dict> BWBlockSortDecode/filter <file> */
+private int
+zBWBSD(os_ptr op)
+{ stream_BWBSD_state bwbss;
+ int code;
+ code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
+ if ( code < 0 )
+ return code;
+ return filter_read(op, 1, &s_BWBSD_template, (stream_state *)&bwbss, 0);
+}
+
+/* ------ Byte translation filters ------ */
+
+/* Common setup */
+private int
+bt_setup(os_ptr op, stream_BT_state *pbts)
+{ int npop = 1;
+ if ( r_has_type(op, t_dictionary) )
+ ++npop, --op;
+ check_read_type(*op, t_string);
+ if ( r_size(op) != 256 )
+ return_error(e_rangecheck);
+ memcpy(pbts->table, op->value.const_bytes, 256);
+ return npop;
+}
+
+/* <target> <table> ByteTranslateEncode/filter <file> */
+/* <target> <table> <dict_ignored> ByteTranslateEncode/filter <file> */
+private int
+zBTE(os_ptr op)
+{ stream_BT_state bts;
+ int code = bt_setup(op, &bts);
+
+ if ( code < 0 )
+ return code;
+ return filter_write(op, code, &s_BTE_template, (stream_state *)&bts,
+ 0);
+}
+
+/* <target> <table> ByteTranslateDecode/filter <file> */
+/* <target> <table> <dict_ignored> ByteTranslateDecode/filter <file> */
+private int
+zBTD(os_ptr op)
+{ stream_BT_state bts;
+ int code = bt_setup(op, &bts);
+
+ if ( code < 0 )
+ return code;
+ return filter_read(op, code, &s_BTD_template, (stream_state *)&bts, 0);
+}
+
+/* ------ Move-to-front filters ------ */
+
+/* <target> MoveToFrontEncode/filter <file> */
+/* <target> <dict_ignored> MoveToFrontEncode/filter <file> */
+private int
+zMTFE(os_ptr op)
+{ return filter_write_simple(op, &s_MTFE_template);
+}
+
+/* <source> MoveToFrontDecode/filter <file> */
+/* <source> <dict_ignored> MoveToFrontDecode/filter <file> */
+private int
+zMTFD(os_ptr op)
+{ return filter_read_simple(op, &s_MTFD_template);
+}
+
+/* ------ PCX decoding filter ------ */
+
+/* <source> PCXDecode/filter <file> */
+/* <source> <dict_ignored> PCXDecode/filter <file> */
+private int
+zPCXD(os_ptr op)
+{ return filter_read_simple(op, &s_PCXD_template);
+}
+
+/* ================ Initialization procedure ================ */
+
+BEGIN_OP_DEFS(zfilterx_op_defs) {
+ {"2.computecodes", zcomputecodes}, /* not a filter */
+ op_def_begin_filter(),
+ /* Non-standard filters */
+ {"2BoundedHuffmanEncode", zBHCE},
+ {"2BoundedHuffmanDecode", zBHCD},
+ {"2BWBlockSortEncode", zBWBSE},
+ {"2BWBlockSortDecode", zBWBSD},
+ {"2ByteTranslateEncode", zBTE},
+ {"2ByteTranslateDecode", zBTD},
+ {"1MoveToFrontEncode", zMTFE},
+ {"1MoveToFrontDecode", zMTFD},
+ {"1PCXDecode", zPCXD},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfname.c b/gs/src/zfname.c
new file mode 100644
index 000000000..9ce4d6ff9
--- /dev/null
+++ b/gs/src/zfname.c
@@ -0,0 +1,106 @@
+/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfname.c */
+/* File name utilities */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "stream.h"
+#include "gxiodev.h" /* must come after stream.h */
+#include "fname.h"
+
+/* Parse a file name into device and individual name. */
+/* The device may be NULL, or the name may be NULL, but not both. */
+/* According to the Adobe documentation, %device and %device% */
+/* are equivalent; both return name==NULL. */
+int
+parse_file_name(const ref *op, parsed_file_name *pfn)
+{ const byte *pname;
+ uint len, dlen;
+ const byte *pdelim;
+ gx_io_device *iodev;
+
+ check_read_type(*op, t_string);
+ len = r_size(op);
+ pname = op->value.const_bytes;
+ if ( len == 0 )
+ return_error(e_undefinedfilename);
+ if ( pname[0] != '%' ) /* no device */
+ { pfn->iodev = NULL;
+ pfn->fname = (const char *)pname;
+ pfn->len = len;
+ return 0;
+ }
+ pdelim = (const byte *)memchr(pname + 1, '%', len - 1);
+ if ( pdelim == NULL ) /* %device */
+ dlen = len;
+ else if ( pdelim[1] == 0 ) /* %device% */
+ { pdelim = NULL;
+ dlen = len;
+ }
+ else
+ { dlen = pdelim - pname;
+ pdelim++, len--;
+ }
+ iodev = gs_findiodevice(pname, dlen);
+ if ( iodev == 0 )
+ return_error(e_undefinedfilename);
+ pfn->iodev = iodev;
+ pfn->fname = (const char *)pdelim;
+ pfn->len = len - dlen;
+ return 0;
+}
+
+/* Parse a real (non-device) file name and convert to a C string. */
+int
+parse_real_file_name(const ref *op, parsed_file_name *pfn, client_name_t cname)
+{ int code = parse_file_name(op, pfn);
+ if ( code < 0 )
+ return code;
+ if ( pfn->len == 0 )
+ return_error(e_invalidfileaccess); /* device only */
+ return terminate_file_name(pfn, cname);
+}
+
+/* Convert a file name to a C string by adding a null terminator. */
+int
+terminate_file_name(parsed_file_name *pfn, client_name_t cname)
+{ uint len = pfn->len;
+ ref fnref;
+ const char *fname;
+ if ( pfn->iodev == NULL ) /* no device */
+ pfn->iodev = iodev_default;
+ fnref.value.const_bytes = (const byte *)pfn->fname;
+ r_set_size(&fnref, len);
+ fname = ref_to_string(&fnref, imemory, cname);
+ if ( fname == 0 )
+ return_error(e_VMerror);
+ pfn->fname = fname;
+ pfn->len = len + 1; /* null terminator */
+ return 0;
+}
+
+/* Free a file name that was copied to a C string. */
+void
+free_file_name(parsed_file_name *pfn, client_name_t cname)
+{ if ( pfn->fname != 0 )
+ ifree_string((byte *)pfn->fname, pfn->len, cname);
+}
diff --git a/gs/src/zfont.c b/gs/src/zfont.c
new file mode 100644
index 000000000..28b2d5074
--- /dev/null
+++ b/gs/src/zfont.c
@@ -0,0 +1,423 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfont.c */
+/* Generic font operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h" /* for registering root */
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "igstate.h"
+#include "iname.h" /* for name_mark_index */
+#include "isave.h"
+#include "store.h"
+#include "ivmspace.h"
+
+/* Forward references */
+private int make_font(P2(os_ptr, const gs_matrix *));
+private void make_uint_array(P3(os_ptr, const uint *, int));
+
+/* The (global) font directory */
+gs_font_dir *ifont_dir = 0; /* needed for buildfont */
+private gs_gc_root_t font_dir_root;
+
+/* Mark a glyph as a PostScript name (if it isn't a CID). */
+bool
+zfont_mark_glyph_name(gs_glyph glyph, void *ignore_data)
+{ return (glyph >= gs_min_cid_glyph || glyph == gs_no_glyph ? false :
+ name_mark_index((uint)glyph));
+}
+
+/* Initialize the font operators */
+private void
+zfont_init(void)
+{ ifont_dir = gs_font_dir_alloc(imemory);
+ ifont_dir->ccache.mark_glyph = zfont_mark_glyph_name;
+ gs_register_struct_root(imemory, &font_dir_root,
+ (void **)&ifont_dir, "ifont_dir");
+}
+
+/* <font> <scale> scalefont <new_font> */
+private int
+zscalefont(register os_ptr op)
+{ int code;
+ double scale;
+ gs_matrix mat;
+
+ if ( (code = real_param(op, &scale)) < 0 )
+ return code;
+ if ( (code = gs_make_scaling(scale, scale, &mat)) < 0 )
+ return code;
+ return make_font(op, &mat);
+}
+
+/* <font> <matrix> makefont <new_font> */
+private int
+zmakefont(register os_ptr op)
+{ int code;
+ gs_matrix mat;
+ if ( (code = read_matrix(op, &mat)) < 0 )
+ return code;
+ return make_font(op, &mat);
+}
+
+/* <font> setfont - */
+int
+zsetfont(register os_ptr op)
+{ gs_font *pfont;
+ int code = font_param(op, &pfont);
+ if ( code < 0 || (code = gs_setfont(igs, pfont)) < 0 )
+ return code;
+ pop(1);
+ return code;
+}
+
+/* - currentfont <font> */
+private int
+zcurrentfont(register os_ptr op)
+{ push(1);
+ *op = *pfont_dict(gs_currentfont(igs));
+ return 0;
+}
+
+/* - cachestatus <mark> <bsize> <bmax> <msize> <mmax> <csize> <cmax> <blimit> */
+private int
+zcachestatus(register os_ptr op)
+{ uint status[7];
+ gs_cachestatus(ifont_dir, status);
+ push(7);
+ make_uint_array(op - 6, status, 7);
+ return 0;
+}
+
+/* <blimit> setcachelimit - */
+private int
+zsetcachelimit(register os_ptr op)
+{ check_int_leu(*op, max_uint);
+ gs_setcachelimit(ifont_dir, (uint)op->value.intval);
+ pop(1);
+ return 0;
+}
+
+/* <mark> <size> <lower> <upper> setcacheparams - */
+private int
+zsetcacheparams(register os_ptr op)
+{ uint params[3];
+ int i, code;
+ os_ptr opp = op;
+
+ for ( i = 0; i < 3 && !r_has_type(opp, t_mark) ; i++, opp-- )
+ { check_int_leu(*opp, max_uint);
+ params[i] = opp->value.intval;
+ }
+ switch ( i )
+ {
+ case 3:
+ if ( (code = gs_setcachesize(ifont_dir, params[2])) < 0 )
+ return code;
+ case 2:
+ if ( (code = gs_setcachelower(ifont_dir, params[1])) < 0 )
+ return code;
+ case 1:
+ if ( (code = gs_setcacheupper(ifont_dir, params[0])) < 0 )
+ return code;
+ case 0: ;
+ }
+ return zcleartomark(op);
+}
+
+/* - currentcacheparams <mark> <size> <lower> <upper> */
+private int
+zcurrentcacheparams(register os_ptr op)
+{ uint params[3];
+
+ params[0] = gs_currentcachesize(ifont_dir);
+ params[1] = gs_currentcachelower(ifont_dir);
+ params[2] = gs_currentcacheupper(ifont_dir);
+ push(4);
+ make_mark(op - 3);
+ make_uint_array(op - 2, params, 3);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfont_op_defs) {
+ {"0currentfont", zcurrentfont},
+ {"2makefont", zmakefont},
+ {"2scalefont", zscalefont},
+ {"1setfont", zsetfont},
+ {"0cachestatus", zcachestatus},
+ {"1setcachelimit", zsetcachelimit},
+ {"1setcacheparams", zsetcacheparams},
+ {"0currentcacheparams", zcurrentcacheparams},
+END_OP_DEFS(zfont_init) }
+
+/* ------ Subroutines ------ */
+
+/* Validate a font parameter. */
+int
+font_param(const ref *pfdict, gs_font **ppfont)
+{ /*
+ * Check that pfdict is a read-only dictionary, that it has a FID
+ * entry whose value is a fontID, and that the fontID points to a
+ * gs_font structure whose associated PostScript dictionary is
+ * pfdict.
+ */
+ ref *pid;
+ gs_font *pfont;
+ const font_data *pdata;
+
+ check_type(*pfdict, t_dictionary);
+ if ( dict_find_string(pfdict, "FID", &pid) <= 0 ||
+ !r_has_type(pid, t_fontID)
+ )
+ return_error(e_invalidfont);
+ pfont = r_ptr(pid, gs_font);
+ pdata = pfont->client_data;
+ if ( !obj_eq(&pdata->dict, pfdict) )
+ return_error(e_invalidfont);
+ *ppfont = pfont;
+ if ( pfont == 0 )
+ return_error(e_invalidfont); /* unregistered font */
+ return 0;
+}
+
+/* Add the FID entry to a font dictionary. */
+int
+add_FID(ref *fp /* t_dictionary */, gs_font *pfont)
+{ ref fid;
+ make_tav_new(&fid, t_fontID, a_readonly | icurrent_space,
+ pstruct, (void *)pfont);
+ return dict_put_string(fp, "FID", &fid);
+}
+
+/* Make a transformed font (common code for makefont/scalefont). */
+private int
+make_font(os_ptr op, const gs_matrix *pmat)
+{ os_ptr fp = op - 1;
+ gs_font *oldfont, *newfont;
+ int code;
+ ref *pencoding = 0;
+
+ code = font_param(fp, &oldfont);
+ if ( code < 0 )
+ return code;
+ { uint space = ialloc_space(idmemory);
+ ialloc_set_space(idmemory, r_space(fp));
+ if ( dict_find_string(fp, "Encoding", &pencoding) > 0 &&
+ !r_is_array(pencoding)
+ )
+ code = gs_note_error(e_invalidfont);
+ else
+ { /*
+ * Temporarily substitute the new dictionary
+ * for the old one, in case the Encoding changed.
+ */
+ ref olddict;
+ olddict = *pfont_dict(oldfont);
+ *pfont_dict(oldfont) = *fp;
+ code = gs_makefont(ifont_dir, oldfont, pmat, &newfont);
+ *pfont_dict(oldfont) = olddict;
+ }
+ ialloc_set_space(idmemory, space);
+ }
+ if ( code < 0 )
+ return code;
+ /*
+ * We have to allow for the possibility that the font's Encoding
+ * is different from that of the base font. Note that the
+ * font_data of the new font was simply copied from the old one.
+ */
+ if ( pencoding != 0 &&
+ !obj_eq(pencoding, &pfont_data(newfont)->Encoding)
+ )
+ { if ( newfont->FontType == ft_composite )
+ return_error(e_rangecheck);
+ /* We should really do validity checking here.... */
+ ref_assign(&pfont_data(newfont)->Encoding, pencoding);
+ lookup_gs_simple_font_encoding((gs_font_base *)newfont);
+ }
+ *fp = *pfont_dict(newfont);
+ pop(1);
+ return 0;
+}
+/* Create the transformed font dictionary. */
+/* This is the make_font completion procedure for all non-composite fonts */
+/* created at the interpreter level (see build_gs_simple_font in zfont2.c.) */
+int
+zbase_make_font(gs_font_dir *pdir, const gs_font *oldfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{ /* We must call gs_base_make_font so that the XUID gets copied */
+ /* if necessary. */
+ int code = gs_base_make_font(pdir, oldfont, pmat, ppfont);
+ if ( code < 0 )
+ return code;
+ return zdefault_make_font(pdir, oldfont, pmat, ppfont);
+}
+int
+zdefault_make_font(gs_font_dir *pdir, const gs_font *oldfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{ gs_font *newfont = *ppfont;
+ ref *fp = pfont_dict(oldfont);
+ font_data *pdata;
+ ref newdict, newmat, scalemat;
+ uint dlen = dict_maxlength(fp);
+ uint mlen = dict_length(fp) + 3; /* FontID, OrigFont, ScaleMatrix */
+ int code;
+
+ if ( dlen < mlen )
+ dlen = mlen;
+ if ( (pdata = ialloc_struct(font_data, &st_font_data,
+ "make_font(font_data)")) == 0
+ )
+ return_error(e_VMerror);
+ if ( (code = dict_create(dlen, &newdict)) < 0 ||
+ (code = dict_copy(fp, &newdict)) < 0 ||
+ (code = ialloc_ref_array(&newmat, a_all, 12, "make_font(matrices)")) < 0
+ )
+ return code;
+ refset_null(newmat.value.refs, 12);
+ ref_assign(&scalemat, &newmat);
+ r_set_size(&scalemat, 6);
+ scalemat.value.refs += 6;
+ /*
+ * Create the scaling matrix. We could do this several different
+ * ways: by "dividing" the new FontMatrix by the base FontMatrix, by
+ * multiplying the current scaling matrix by a ScaleMatrix kept in
+ * the gs_font, or by multiplying the current scaling matrix by the
+ * ScaleMatrix from the font dictionary. We opt for the last of
+ * these.
+ */
+ { gs_matrix scale, prev_scale;
+ ref *ppsm;
+ if ( !(dict_find_string(fp, "ScaleMatrix", &ppsm) > 0 &&
+ read_matrix(ppsm, &prev_scale) >= 0 &&
+ gs_matrix_multiply(pmat, &prev_scale, &scale) >= 0)
+ )
+ scale = *pmat;
+ write_matrix(&scalemat, &scale);
+ }
+ r_clear_attrs(&scalemat, a_write);
+ r_set_size(&newmat, 6);
+ write_matrix(&newmat, &newfont->FontMatrix);
+ r_clear_attrs(&newmat, a_write);
+ if ( (code = dict_put_string(&newdict, "FontMatrix", &newmat)) < 0 ||
+ (code = dict_put_string(&newdict, "OrigFont", pfont_dict(oldfont->base))) < 0 ||
+ (code = dict_put_string(&newdict, "ScaleMatrix", &scalemat)) < 0 ||
+ (code = add_FID(&newdict, newfont)) < 0
+ )
+ return code;
+ newfont->client_data = pdata;
+ *pdata = *pfont_data(oldfont);
+ pdata->dict = newdict;
+ r_clear_attrs(dict_access_ref(&newdict), a_write);
+ return 0;
+}
+
+/* Convert an array of (unsigned) integers to stack form. */
+private void
+make_uint_array(register os_ptr op, const uint *intp, int count)
+{ int i;
+ for ( i = 0; i < count; i++, op++, intp++ )
+ make_int(op, *intp);
+}
+
+/* Remove scaled font and character cache entries that would be */
+/* invalidated by a restore. */
+private bool
+purge_if_name_removed(cached_char *cc, void *vsave)
+{ return alloc_name_index_is_since_save(cc->code, vsave);
+}
+void
+font_restore(const alloc_save_t *save)
+{ gs_font_dir *pdir = ifont_dir;
+ if ( pdir == 0 ) /* not initialized yet */
+ return;
+
+ /* Purge original (unscaled) fonts. */
+
+ { gs_font *pfont;
+otop: for ( pfont = pdir->orig_fonts; pfont != 0;
+ pfont = pfont->next
+ )
+ { if ( alloc_is_since_save((char *)pfont, save) )
+ { gs_purge_font(pfont); goto otop; }
+ }
+ }
+
+ /* Purge cached scaled fonts. */
+
+ { gs_font *pfont;
+top: for ( pfont = pdir->scaled_fonts; pfont != 0;
+ pfont = pfont->next
+ )
+ { if ( alloc_is_since_save((char *)pfont, save) )
+ { gs_purge_font(pfont); goto top; }
+ }
+ }
+
+ /* Purge xfonts and uncached scaled fonts. */
+
+ { cached_fm_pair *pair;
+ uint n;
+ for ( pair = pdir->fmcache.mdata, n = pdir->fmcache.mmax;
+ n > 0; pair++, n--
+ )
+ if ( !fm_pair_is_free(pair) )
+ { if ( (uid_is_XUID(&pair->UID) &&
+ alloc_is_since_save((char *)pair->UID.xvalues,
+ save))
+ )
+ { gs_purge_fm_pair(pdir, pair, 0);
+ continue;
+ }
+ if ( pair->font != 0 &&
+ alloc_is_since_save((char *)pair->font, save)
+ )
+ { if ( !uid_is_valid(&pair->UID) )
+ { gs_purge_fm_pair(pdir, pair, 0);
+ continue;
+ }
+ /* Don't discard pairs with a surviving UID. */
+ pair->font = 0;
+ }
+ if ( pair->xfont != 0 &&
+ alloc_is_since_save((char *)pair->xfont, save)
+ )
+ gs_purge_fm_pair(pdir, pair, 1);
+ }
+ }
+
+ /* Purge characters with names about to be removed. */
+ /* We only need to do this if any new names have been created */
+ /* since the save. */
+
+ if ( alloc_any_names_since_save(save) )
+ gx_purge_selected_cached_chars(pdir, purge_if_name_removed,
+ (void *)save);
+
+}
diff --git a/gs/src/zfont0.c b/gs/src/zfont0.c
new file mode 100644
index 000000000..e0201a945
--- /dev/null
+++ b/gs/src/zfont0.c
@@ -0,0 +1,319 @@
+/* Copyright (C) 1991, 1992, 1993, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfont0.c */
+/* Composite font creation operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+/*
+ * The following lines used to say:
+ * #include "gsmatrix.h"
+ * #include "gxdevice.h" /. for gxfont.h ./
+ * Tony Li says the longer list is necessary to keep the GNU compiler
+ * happy, but this is pretty hard to understand....
+ */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfcmap.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+
+/* Composite font procedures */
+extern font_proc_init_fstack(gs_type0_init_fstack);
+extern font_proc_define_font(gs_type0_define_font);
+extern font_proc_make_font(gs_type0_make_font);
+extern font_proc_next_glyph(gs_type0_next_glyph);
+
+/* Imported from zfcmap.c */
+int ztype0_get_cmap(P3(const gs_cmap **ppcmap, const ref *pfdepvector,
+ const ref *op));
+
+/* Forward references */
+private font_proc_define_font(ztype0_define_font);
+private font_proc_make_font(ztype0_make_font);
+private int ensure_char_entry(P4(os_ptr, const char _ds *, byte *, int));
+
+/* <string|name> <font_dict> .buildfont0 <string|name> <font> */
+/* Build a type 0 (composite) font. */
+private int
+zbuildfont0(os_ptr op)
+{ ref *pfmaptype;
+ gs_type0_data data;
+ ref *pfdepvector;
+ ref *pprefenc;
+ gs_font_type0 *pfont;
+ font_data *pdata;
+ ref save_FID;
+ int i;
+ int code = 0;
+
+ check_type(*op, t_dictionary);
+ if ( dict_find_string(op, "FMapType", &pfmaptype) <= 0 ||
+ !r_has_type(pfmaptype, t_integer) ||
+ pfmaptype->value.intval < (int)fmap_type_min ||
+ pfmaptype->value.intval > (int)fmap_type_max ||
+ dict_find_string(op, "FDepVector", &pfdepvector) <= 0 ||
+ !r_is_array(pfdepvector)
+ )
+ return_error(e_invalidfont);
+ data.FMapType = (fmap_type)pfmaptype->value.intval;
+ /* Check that every element of the FDepVector is a font. */
+ data.fdep_size = r_size(pfdepvector);
+ for ( i = 0; i < data.fdep_size; i++ )
+ { ref fdep;
+ gs_font *psub;
+
+ array_get(pfdepvector, i, &fdep);
+ if ( (code = font_param(&fdep, &psub)) < 0 )
+ return code;
+ /*
+ * Check the inheritance rules. Allowed configurations
+ * (paths from root font) are defined by the regular
+ * expression:
+ * (shift | double_escape escape* | escape*)
+ * non_modal* non_composite
+ */
+ if ( psub->FontType == ft_composite )
+ {
+#define psub0 ((gs_font_type0 *)psub)
+ fmap_type fmt = psub0->data.FMapType;
+ if ( fmt == fmap_double_escape ||
+ fmt == fmap_shift ||
+ (fmt == fmap_escape &&
+ !(data.FMapType == fmap_escape ||
+ data.FMapType == fmap_double_escape))
+ )
+ return_error(e_invalidfont);
+#undef psub0
+ }
+ }
+ switch ( data.FMapType )
+ {
+ case fmap_escape: case fmap_double_escape: /* need EscChar */
+ code = ensure_char_entry(op, "EscChar", &data.EscChar, 255);
+ break;
+ case fmap_shift: /* need ShiftIn & ShiftOut */
+ code = ensure_char_entry(op, "ShiftIn", &data.ShiftIn, 15);
+ if ( code >= 0 )
+ code = ensure_char_entry(op, "ShiftOut", &data.ShiftOut, 14);
+ break;
+ case fmap_SubsVector: /* need SubsVector */
+ { ref *psubsvector;
+ uint svsize;
+
+ if ( dict_find_string(op, "SubsVector", &psubsvector) <= 0 ||
+ !r_has_type(psubsvector, t_string) ||
+ (svsize = r_size(psubsvector)) == 0 ||
+ (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 ||
+ (svsize - 1) % data.subs_width != 0
+ )
+ return_error(e_invalidfont);
+ data.subs_size = (svsize - 1) / data.subs_width;
+ data.SubsVector.data = psubsvector->value.bytes + 1;
+ data.SubsVector.size = svsize - 1;
+ } break;
+ case fmap_CMap: /* need CMap */
+ code = ztype0_get_cmap(&data.CMap, (const ref *)pfdepvector,
+ (const ref *)op);
+ break;
+ default:
+ ;
+ }
+ if ( code < 0 )
+ return code;
+ /*
+ * Save the old FID in case we have to back out.
+ * build_gs_font will return an error if there is a FID entry
+ * but it doesn't reference a valid font.
+ */
+ { ref *pfid;
+ if ( dict_find_string(op, "FID", &pfid) <= 0 )
+ make_null(&save_FID);
+ else
+ save_FID = *pfid;
+ }
+ { build_proc_refs build;
+
+ code = build_proc_name_refs(&build,
+ "%Type0BuildChar", "%Type0BuildGlyph");
+ if ( code < 0 )
+ return code;
+ code = build_gs_font(op, (gs_font **)&pfont,
+ ft_composite, &st_gs_font_type0, &build,
+ bf_options_none);
+ }
+ if ( code != 0 )
+ return code;
+ /* Fill in the rest of the basic font data. */
+ pfont->procs.init_fstack = gs_type0_init_fstack;
+ pfont->procs.next_char = 0; /* superseded by next_glyph */
+ pfont->procs.define_font = ztype0_define_font;
+ pfont->procs.make_font = ztype0_make_font;
+ pfont->procs.next_glyph = gs_type0_next_glyph;
+ if ( dict_find_string(op, "PrefEnc", &pprefenc) <= 0 )
+ { ref nul;
+
+ make_null_new(&nul);
+ if ( (code = dict_put_string(op, "PrefEnc", &nul)) < 0 )
+ goto fail;
+ }
+ /* Fill in the font data */
+ pdata = pfont_data(pfont);
+ data.encoding_size = r_size(&pdata->Encoding);
+ data.Encoding =
+ (uint *)ialloc_byte_array(data.encoding_size, sizeof(uint),
+ "buildfont0(Encoding)");
+ if ( data.Encoding == 0 )
+ { code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ /* Fill in the encoding vector, checking to make sure that */
+ /* each element is an integer between 0 and fdep_size-1. */
+ for ( i = 0; i < data.encoding_size; i++ )
+ { ref enc;
+ array_get(&pdata->Encoding, i, &enc);
+ if ( !r_has_type(&enc, t_integer) )
+ { code = gs_note_error(e_typecheck);
+ goto fail;
+ }
+ if ( (ulong)enc.value.intval >= data.fdep_size )
+ { code = gs_note_error(e_rangecheck);
+ goto fail;
+ }
+ data.Encoding[i] = (uint)enc.value.intval;
+ }
+ data.FDepVector =
+ ialloc_struct_array(data.fdep_size, gs_font *,
+ &st_gs_font_ptr_element,
+ "buildfont0(FDepVector)");
+ if ( data.FDepVector == 0 )
+ { code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ for ( i = 0; i < data.fdep_size; i++ )
+ { ref fdep;
+ ref *pfid;
+ array_get(pfdepvector, i, &fdep);
+ /* The lookup can't fail, because of the pre-check above. */
+ dict_find_string(&fdep, "FID", &pfid);
+ data.FDepVector[i] = r_ptr(pfid, gs_font);
+ }
+ pfont->data = data;
+ code = define_gs_font((gs_font *)pfont);
+ if ( code >= 0 )
+ return code;
+fail: /* Undo the insertion of the FID entry in the dictionary. */
+ if ( r_has_type(&save_FID, t_null) )
+ { ref rnfid;
+
+ name_enter_string("FID", &rnfid);
+ dict_undef(op, &rnfid);
+ }
+ else
+ dict_put_string(op, "FID", &save_FID);
+ gs_free_object(pfont->memory, pfont, "buildfont0(font)");
+ return code;
+}
+/* If a newly defined or scaled composite font had to scale */
+/* any composite sub-fonts, adjust the parent font's FDepVector. */
+/* This is called only if gs_type0_define/make_font */
+/* actually changed the FDepVector. */
+private int
+ztype0_adjust_FDepVector(gs_font_type0 *pfont)
+{ gs_font **pdep = pfont->data.FDepVector;
+ ref newdep;
+ uint fdep_size = pfont->data.fdep_size;
+ ref *prdep;
+ uint i;
+ int code = ialloc_ref_array(&newdep, a_readonly, fdep_size,
+ "ztype0_adjust_matrix");
+ if ( code < 0 )
+ return code;
+ for ( prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++ )
+ { const ref *pdict = pfont_dict(pdep[i]);
+ ref_assign_new(prdep, pdict);
+ }
+ return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep);
+}
+private int
+ztype0_define_font(gs_font_dir *pdir, gs_font *pfont)
+{
+#define pfont0 ((gs_font_type0 *)pfont)
+ gs_font **pdep = pfont0->data.FDepVector;
+ int code = gs_type0_define_font(pdir, pfont);
+ if ( code < 0 || pfont0->data.FDepVector == pdep )
+ return code;
+ return ztype0_adjust_FDepVector(pfont0);
+#undef pfont0
+}
+private int
+ztype0_make_font(gs_font_dir *pdir, const gs_font *pfont,
+ const gs_matrix *pmat, gs_font **ppfont)
+{
+#define ppfont0 ((gs_font_type0 **)ppfont)
+ gs_font **pdep = (*ppfont0)->data.FDepVector;
+ int code;
+ code = zdefault_make_font(pdir, pfont, pmat, ppfont);
+ if ( code < 0 )
+ return code;
+ code = gs_type0_make_font(pdir, pfont, pmat, ppfont);
+ if ( code < 0 )
+ return code;
+ if ( (*ppfont0)->data.FDepVector == pdep )
+ return 0;
+ return ztype0_adjust_FDepVector(*ppfont0);
+#undef ppfont0
+}
+
+/* ------ Internal routines ------ */
+
+/* Find or add a character entry in a font dictionary. */
+private int
+ensure_char_entry(os_ptr op, const char _ds *kstr,
+ byte *pvalue, int default_value)
+{ ref *pentry;
+ if ( dict_find_string(op, kstr, &pentry) <= 0 )
+ { ref ent;
+ make_int(&ent, default_value);
+ *pvalue = (byte)default_value;
+ return dict_put_string(op, kstr, &ent);
+ }
+ else
+ { check_int_leu_only(*pentry, 255);
+ *pvalue = (byte)pentry->value.intval;
+ return 0;
+ }
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfont0_op_defs) {
+ {"2.buildfont0", zbuildfont0},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfont1.c b/gs/src/zfont1.c
new file mode 100644
index 000000000..560336d55
--- /dev/null
+++ b/gs/src/zfont1.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfont1.c */
+/* Type 1 and Type 4 font creation operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+
+/* Type 1 auxiliary procedures (defined in zchar1.c) */
+extern int z1_subr_proc(P4(gs_font_type1 *, int, bool, gs_const_string *));
+extern int z1_seac_proc(P3(gs_font_type1 *, int, gs_const_string *));
+extern int z1_push_proc(P3(gs_font_type1 *, const fixed *, int));
+extern int z1_pop_proc(P2(gs_font_type1 *, fixed *));
+
+/* Default value of lenIV */
+#define default_lenIV_1 4
+#define default_lenIV_2 (-1)
+
+/* Private utilities */
+private uint
+subr_bias(const ref *psubrs)
+{ uint size = r_size(psubrs);
+
+ return (size < 1240 ? 107 : size < 33900 ? 1131 : 32768);
+}
+
+/* Build a Type 1 or Type 4 font. */
+private int
+buildfont1or4(os_ptr op, build_proc_refs *pbuild, font_type ftype,
+ build_font_options_t options)
+{ gs_type1_data data1;
+ static ref no_subrs;
+ ref *pothersubrs = &no_subrs;
+ ref *psubrs = &no_subrs;
+ ref *pglobalsubrs = &no_subrs;
+ ref *pprivate;
+ gs_font_type1 *pfont;
+ font_data *pdata;
+ int code;
+
+ check_type(*op, t_dictionary);
+ if ( dict_find_string(op, "Private", &pprivate) <= 0 ||
+ !r_has_type(pprivate, t_dictionary)
+ )
+ return_error(e_invalidfont);
+ make_empty_array(&no_subrs, 0);
+ if ( dict_find_string(pprivate, "OtherSubrs", &pothersubrs) > 0 )
+ { if ( !r_is_array(pothersubrs) )
+ return_error(e_typecheck);
+ }
+ if ( dict_find_string(pprivate, "Subrs", &psubrs) > 0 )
+ { if ( !r_is_array(psubrs) )
+ return_error(e_typecheck);
+ }
+ if ( (code = dict_int_param(op, "CharstringType", 1, 2, 1,
+ &data1.CharstringType)) < 0
+ )
+ return code;
+ /* Get information specific to Type 2 charstrings. */
+ if ( data1.CharstringType == 2 )
+ { float dwx, nwx;
+
+ data1.subroutineNumberBias = subr_bias(psubrs);
+ if ( dict_find_string(pprivate, "GlobalSubrs", &pglobalsubrs) > 0 )
+ { if ( !r_is_array(pglobalsubrs) )
+ return_error(e_typecheck);
+ }
+ data1.gsubrNumberBias = subr_bias(pglobalsubrs);
+ if ( (code = dict_uint_param(pprivate, "gsubrNumberBias",
+ 0, max_uint, data1.gsubrNumberBias,
+ &data1.gsubrNumberBias)) < 0 ||
+ (code = dict_float_param(pprivate, "defaultWidthX", 0.0,
+ &dwx)) < 0 ||
+ (code = dict_float_param(pprivate, "nominalWidthX", 0.0,
+ &nwx)) < 0
+ )
+ return code;
+ data1.defaultWidthX = float2fixed(dwx);
+ data1.nominalWidthX = float2fixed(nwx);
+ { ref *pirs;
+ if ( dict_find_string(pprivate, "initialRandomSeed", &pirs) <= 0 )
+ data1.initialRandomSeed = 0;
+ else if ( !r_has_type(pirs, t_integer) )
+ return_error(e_typecheck);
+ else
+ data1.initialRandomSeed = pirs->value.intval;
+ }
+ data1.lenIV = default_lenIV_2;
+ }
+ else
+ { data1.subroutineNumberBias = 0;
+ data1.gsubrNumberBias = 0;
+ data1.lenIV = default_lenIV_1;
+ }
+ /* Get the rest of the information from the Private dictionary. */
+ if ( (code = dict_int_param(pprivate, "lenIV", -1, 255, data1.lenIV,
+ &data1.lenIV)) < 0 ||
+ (code = dict_uint_param(pprivate, "subroutineNumberBias",
+ 0, max_uint, data1.subroutineNumberBias,
+ &data1.subroutineNumberBias)) < 0 ||
+ (code = dict_int_param(pprivate, "BlueFuzz", 0, 1999, 1,
+ &data1.BlueFuzz)) < 0 ||
+ (code = dict_float_param(pprivate, "BlueScale", 0.039625,
+ &data1.BlueScale)) < 0 ||
+ (code = dict_float_param(pprivate, "BlueShift", 7.0,
+ &data1.BlueShift)) < 0 ||
+ (code = data1.BlueValues.count = dict_float_array_param(pprivate,
+ "BlueValues", max_BlueValues * 2,
+ &data1.BlueValues.values[0], NULL)) < 0 ||
+ (code = dict_float_param(pprivate, "ExpansionFactor", 0.06,
+ &data1.ExpansionFactor)) < 0 ||
+ (code = data1.FamilyBlues.count = dict_float_array_param(pprivate,
+ "FamilyBlues", max_FamilyBlues * 2,
+ &data1.FamilyBlues.values[0], NULL)) < 0 ||
+ (code = data1.FamilyOtherBlues.count = dict_float_array_param(pprivate,
+ "FamilyOtherBlues", max_FamilyOtherBlues * 2,
+ &data1.FamilyOtherBlues.values[0], NULL)) < 0 ||
+ (code = dict_bool_param(pprivate, "ForceBold", false,
+ &data1.ForceBold)) < 0 ||
+ (code = dict_int_param(pprivate, "LanguageGroup", 0, 1, 0,
+ &data1.LanguageGroup)) < 0 ||
+ (code = data1.OtherBlues.count = dict_float_array_param(pprivate,
+ "OtherBlues", max_OtherBlues * 2,
+ &data1.OtherBlues.values[0], NULL)) < 0 ||
+ (code = dict_bool_param(pprivate, "RndStemUp", true,
+ &data1.RndStemUp)) < 0 ||
+ (code = data1.StdHW.count = dict_float_array_param(pprivate,
+ "StdHW", 1, &data1.StdHW.values[0], NULL)) < 0 ||
+ (code = data1.StdVW.count = dict_float_array_param(pprivate,
+ "StdVW", 1, &data1.StdVW.values[0], NULL)) < 0 ||
+ (code = data1.StemSnapH.count = dict_float_array_param(pprivate,
+ "StemSnapH", max_StemSnap,
+ &data1.StemSnapH.values[0], NULL)) < 0 ||
+ (code = data1.StemSnapV.count = dict_float_array_param(pprivate,
+ "StemSnapV", max_StemSnap,
+ &data1.StemSnapV.values[0], NULL)) < 0 ||
+ /* The WeightVector is in the font dictionary, not Private. */
+ (code = data1.WeightVector.count = dict_float_array_param(op,
+ "WeightVector", max_WeightVector,
+ data1.WeightVector.values, NULL)) < 0
+ )
+ return code;
+ /*
+ * According to section 5.6 of the "Adobe Type 1 Font Format",
+ * there is a requirement that BlueScale times the maximum
+ * alignment zone height must be less than 1. Some fonts
+ * produced by Fontographer have ridiculously large BlueScale
+ * values, so we force BlueScale back into range here.
+ */
+ { float max_zone_height = 1.0;
+ float zone_height;
+ int i;
+#define scan_zone(z)\
+ for ( i = 0; i < data1.z.count; i += 2 )\
+ if ( (zone_height = data1.z.values[i+1] - data1.z.values[i]) > max_zone_height )\
+ max_zone_height = zone_height
+ scan_zone(BlueValues);
+ scan_zone(OtherBlues);
+ scan_zone(FamilyBlues);
+ scan_zone(FamilyOtherBlues);
+ if ( data1.BlueScale * max_zone_height > 1.0 )
+ data1.BlueScale = 1.0 / max_zone_height;
+ }
+ /* Do the work common to primitive font types. */
+ code = build_gs_primitive_font(op, (gs_font_base **)&pfont, ftype,
+ &st_gs_font_type1, pbuild, options);
+ if ( code != 0 )
+ return code;
+ /* This is a new font, fill it in. */
+ pdata = pfont_data(pfont);
+ pfont->data = data1;
+ ref_assign(&pdata->u.type1.OtherSubrs, pothersubrs);
+ ref_assign(&pdata->u.type1.Subrs, psubrs);
+ ref_assign(&pdata->u.type1.GlobalSubrs, pglobalsubrs);
+ pfont->data.subr_proc = z1_subr_proc;
+ pfont->data.seac_proc = z1_seac_proc;
+ pfont->data.push_proc = z1_push_proc;
+ pfont->data.pop_proc = z1_pop_proc;
+ pfont->data.proc_data = (char *)pdata;
+ return define_gs_font((gs_font *)pfont);
+}
+
+/* <string|name> <font_dict> .buildfont1 <string|name> <font> */
+/* Build a type 1 (Adobe encrypted) font. */
+private int
+zbuildfont1(os_ptr op)
+{ build_proc_refs build;
+ int code =
+ build_proc_name_refs(&build,
+ "%Type1BuildChar", "%Type1BuildGlyph");
+
+ if ( code < 0 )
+ return code;
+ return buildfont1or4(op, &build, ft_encrypted, bf_notdef_required);
+}
+
+/* <string|name> <font_dict> .buildfont4 <string|name> <font> */
+/* Build a type 4 (disk-based Adobe encrypted) font. */
+private int
+zbuildfont4(os_ptr op)
+{ build_proc_refs build;
+ int code = build_gs_font_procs(op, &build);
+
+ if ( code < 0 )
+ return code;
+ return buildfont1or4(op, &build, ft_disk_based, bf_options_none);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfont1_op_defs) {
+ {"2.buildfont1", zbuildfont1},
+ {"2.buildfont4", zbuildfont4},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfont2.c b/gs/src/zfont2.c
new file mode 100644
index 000000000..79ec6449d
--- /dev/null
+++ b/gs/src/zfont2.c
@@ -0,0 +1,547 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfont2.c */
+/* Font creation utilities */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gschar.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "istruct.h"
+#include "store.h"
+
+/* Registered encodings. See ifont.h for documentation. */
+ref registered_Encodings;
+private ref *registered_Encodings_p = &registered_Encodings;
+private gs_gc_root_t registered_Encodings_root;
+
+/* Structure descriptor */
+public_st_font_data();
+
+/* Initialize the font building operators */
+private void
+zfont2_init(void)
+{ /* Initialize the registered Encodings. */
+ { int i;
+ ialloc_ref_array(&registered_Encodings, a_readonly,
+ registered_Encodings_countof,
+ "registered_Encodings");
+ for ( i = 0; i < registered_Encodings_countof; i++ )
+ make_empty_array(&registered_Encoding(i), 0);
+ }
+ gs_register_ref_root(imemory, &registered_Encodings_root,
+ (void **)&registered_Encodings_p,
+ "registered_Encodings");
+}
+
+/* <string|name> <font_dict> .buildfont3 <string|name> <font> */
+/* Build a type 3 (user-defined) font. */
+private int
+zbuildfont3(os_ptr op)
+{ int code;
+ build_proc_refs build;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ code = build_gs_font_procs(op, &build);
+ if ( code < 0 )
+ return code;
+ code = build_gs_simple_font(op, &pfont, ft_user_defined,
+ &st_gs_font_base, &build, bf_options_none);
+ if ( code < 0 )
+ return code;
+ return define_gs_font((gs_font *)pfont);
+}
+
+/* <int> <array|shortarray> .registerencoding - */
+private int
+zregisterencoding(register os_ptr op)
+{ long i;
+ if ( !r_is_array(op) )
+ return_op_typecheck(op);
+ check_read(*op);
+ check_type(op[-1], t_integer);
+ for ( i = r_size(op); i > 0; )
+ { ref cname;
+ array_get(op, --i, &cname);
+ check_type_only(cname, t_name);
+ }
+ i = op[-1].value.intval;
+ if ( i >= 0 && i < registered_Encodings_countof )
+ { ref *penc = &registered_Encoding(i);
+ ref_assign_old(&registered_Encodings, penc, op,
+ ".registerencoding");
+ }
+ pop(2);
+ return 0;
+}
+
+/* Encode a character. */
+private gs_glyph
+zfont_encode_char(gs_show_enum *penum, gs_font *pfont, gs_char *pchr)
+{ const ref *pencoding = &pfont_data(pfont)->Encoding;
+ ulong index = *pchr; /* work around VAX widening bug */
+ ref cname;
+ int code = array_get(pencoding, (long)index, &cname);
+ if ( code < 0 || !r_has_type(&cname, t_name) )
+ return gs_no_glyph;
+ return (gs_glyph)name_index(&cname);
+}
+
+/* Encode a character in a known encoding. */
+private gs_glyph
+zfont_known_encode(gs_char chr, int encoding_index)
+{ ulong index = chr; /* work around VAX widening bug */
+ ref cname;
+ int code;
+ if ( encoding_index < 0 )
+ return gs_no_glyph;
+ code = array_get(&registered_Encoding(encoding_index),
+ (long)index, &cname);
+ if ( code < 0 || !r_has_type(&cname, t_name) )
+ return gs_no_glyph;
+ return (gs_glyph)name_index(&cname);
+}
+
+/* Get the name of a glyph. */
+/* The following typedef is needed to work around a bug in */
+/* some AIX C compilers. */
+typedef const char *const_chars;
+private const_chars
+zfont_glyph_name(gs_glyph index, uint *plen)
+{ ref nref, sref;
+
+ if ( index >= gs_min_cid_glyph )
+ { /* Fabricate a numeric name. */
+ char cid_name[sizeof(gs_glyph) * 3 + 1];
+ int code;
+
+ sprintf(cid_name, "%lu", (ulong)index);
+ code = name_ref((const byte *)cid_name, strlen(cid_name),
+ &nref, 1);
+ if ( code < 0 )
+ return 0; /* What can we possibly do here? */
+ }
+ else
+ name_index_ref(index, &nref);
+ name_string_ref(&nref, &sref);
+ *plen = r_size(&sref);
+ return (const char *)sref.value.const_bytes;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfont2_op_defs) {
+ {"2.buildfont3", zbuildfont3},
+ {"2.registerencoding", zregisterencoding},
+END_OP_DEFS(zfont2_init) }
+
+/* ------ Subroutines ------ */
+
+/* Convert strings to executable names for build_proc_refs. */
+int
+build_proc_name_refs(build_proc_refs *pbuild,
+ const char _ds *bcstr, const char _ds *bgstr)
+{ int code;
+
+ if ( !bcstr )
+ make_null(&pbuild->BuildChar);
+ else
+ { if ( (code = name_ref((const byte *)bcstr, strlen(bcstr), &pbuild->BuildChar, 0)) < 0 )
+ return code;
+ r_set_attrs(&pbuild->BuildChar, a_executable);
+ }
+ if ( !bgstr )
+ make_null(&pbuild->BuildGlyph);
+ else
+ { if ( (code = name_ref((const byte *)bgstr, strlen(bgstr), &pbuild->BuildGlyph, 0)) < 0 )
+ return code;
+ r_set_attrs(&pbuild->BuildGlyph, a_executable);
+ }
+ return 0;
+}
+
+/* Get the BuildChar and/or BuildGlyph routines from a (base) font. */
+int
+build_gs_font_procs(os_ptr op, build_proc_refs *pbuild)
+{ int ccode, gcode;
+ ref *pBuildChar;
+ ref *pBuildGlyph;
+
+ check_type(*op, t_dictionary);
+ ccode = dict_find_string(op, "BuildChar", &pBuildChar);
+ gcode = dict_find_string(op, "BuildGlyph", &pBuildGlyph);
+ if ( ccode <= 0 )
+ { if ( gcode <= 0 )
+ return_error(e_invalidfont);
+ make_null(&pbuild->BuildChar);
+ }
+ else
+ { check_proc(*pBuildChar);
+ pbuild->BuildChar = *pBuildChar;
+ }
+ if ( gcode <= 0 )
+ make_null(&pbuild->BuildGlyph);
+ else
+ { check_proc(*pBuildGlyph);
+ pbuild->BuildGlyph = *pBuildGlyph;
+ }
+ return 0;
+}
+
+/* Do the common work for building a primitive font -- one whose execution */
+/* algorithm is implemented in C (Type 1, Type 4, or Type 42). */
+/* The caller guarantees that *op is a dictionary. */
+int
+build_gs_primitive_font(os_ptr op, gs_font_base **ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype, const build_proc_refs *pbuild,
+ build_font_options_t options)
+{ int painttype;
+ float strokewidth;
+ ref *pcharstrings = 0;
+ gs_font_base *pfont;
+ font_data *pdata;
+ int code;
+
+ code = dict_int_param(op, "PaintType", 0, 3, 0, &painttype);
+ if ( code < 0 )
+ return code;
+ code = dict_float_param(op, "StrokeWidth", 0.0, &strokewidth);
+ if ( code < 0 )
+ return code;
+ if ( dict_find_string(op, "CharStrings", &pcharstrings) <= 0 )
+ { if ( !(options & bf_CharStrings_optional) )
+ return_error(e_invalidfont);
+ }
+ else
+ { ref *ignore;
+
+ if ( !r_has_type(pcharstrings, t_dictionary) )
+ return_error(e_invalidfont);
+ if ( (options & bf_notdef_required) != 0 &&
+ dict_find_string(pcharstrings, ".notdef", &ignore) <= 0
+ )
+ return_error(e_invalidfont);
+ }
+ code = build_gs_simple_font(op, &pfont, ftype, pstype, pbuild, options);
+ if ( code != 0 )
+ return code;
+ pfont->PaintType = painttype;
+ pfont->StrokeWidth = strokewidth;
+ pdata = pfont_data(pfont);
+ if ( pcharstrings )
+ ref_assign(&pdata->CharStrings, pcharstrings);
+ else
+ make_null(&pdata->CharStrings);
+ /* Check that the UniqueIDs match. This is part of the */
+ /* Adobe protection scheme, but we may as well emulate it. */
+ if ( uid_is_valid(&pfont->UID) &&
+ !dict_check_uid_param(op, &pfont->UID)
+ )
+ uid_set_invalid(&pfont->UID);
+ *ppfont = pfont;
+ return 0;
+}
+
+/* Do the common work for building a font of any non-composite FontType. */
+/* The caller guarantees that *op is a dictionary. */
+int
+build_gs_simple_font(os_ptr op, gs_font_base **ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype, const build_proc_refs *pbuild,
+ build_font_options_t options)
+{ double bbox[4];
+ gs_uid uid;
+ int code;
+ gs_font_base *pfont;
+
+ code = font_bbox_param(op, bbox);
+ if ( code < 0 )
+ return code;
+ if ( (options & bf_FontBBox_required) &&
+ bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0
+ )
+ return_error(e_invalidfont);
+ code = dict_uid_param(op, &uid, 0, imemory);
+ if ( code < 0 )
+ return code;
+ if ( (options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid) )
+ uid_set_invalid(&uid);
+ code = build_gs_font(op, (gs_font **)ppfont, ftype, pstype, pbuild,
+ options);
+ if ( code != 0 ) /* invalid or scaled font */
+ return code;
+ pfont = *ppfont;
+ pfont->procs.init_fstack = gs_default_init_fstack;
+ pfont->procs.next_char = gs_default_next_char;
+ pfont->procs.define_font = gs_no_define_font;
+ pfont->procs.make_font = zbase_make_font;
+ pfont->FontBBox.p.x = bbox[0];
+ pfont->FontBBox.p.y = bbox[1];
+ pfont->FontBBox.q.x = bbox[2];
+ pfont->FontBBox.q.y = bbox[3];
+ pfont->UID = uid;
+ lookup_gs_simple_font_encoding(pfont);
+ return 0;
+}
+
+/* Compare the encoding of a simple font with the registered encodings. */
+void
+lookup_gs_simple_font_encoding(gs_font_base *pfont)
+{ const ref *pfe = &pfont_data(pfont)->Encoding;
+ int index;
+ for ( index = registered_Encodings_countof; --index >= 0; )
+ if ( obj_eq(pfe, &registered_Encoding(index)) )
+ break;
+ pfont->encoding_index = index;
+ if ( index < 0 )
+ { /* Look for an encoding that's "close". */
+ int near_index = -1;
+ uint esize = r_size(pfe);
+ uint best = esize / 3; /* must match at least this many */
+ for ( index = registered_Encodings_countof; --index >= 0; )
+ { const ref *pre = &registered_Encoding(index);
+ bool r_packed = r_has_type(pre, t_shortarray);
+ bool f_packed = !r_has_type(pfe, t_array);
+ uint match = esize;
+ int i;
+ ref fchar, rchar;
+ const ref *pfchar = &fchar;
+ if ( r_size(pre) != esize )
+ continue;
+ for ( i = esize; --i >= 0; )
+ { uint rnidx;
+ if ( r_packed )
+ rnidx = packed_name_index(pre->value.packed + i);
+ else
+ { array_get(pre, (long)i, &rchar);
+ rnidx = name_index(&rchar);
+ }
+ if ( f_packed )
+ array_get(pfe, (long)i, &fchar);
+ else
+ pfchar = pfe->value.const_refs + i;
+ if ( !r_has_type(pfchar, t_name) ||
+ name_index(pfchar) != rnidx
+ )
+ if ( --match <= best )
+ break;
+ }
+ if ( match > best )
+ best = match,
+ near_index = index;
+ }
+ index = near_index;
+ }
+ pfont->nearest_encoding_index = index;
+}
+
+/* Do the common work for building a font of any FontType. */
+/* The caller guarantees that *op is a dictionary. */
+/* op[-1] must be the key under which the font is being registered */
+/* in FontDirectory, normally a name or string. */
+/* Return 0 for a new font, 1 for a font made by makefont or scalefont, */
+/* or a negative error code. */
+private void get_font_name(P2(ref *, const ref *));
+private void copy_font_name(P2(gs_font_name *, const ref *));
+int
+build_gs_font(os_ptr op, gs_font **ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype, const build_proc_refs *pbuild,
+ build_font_options_t options)
+{ ref kname, fname; /* t_string */
+ ref *pftype;
+ ref *pfontname;
+ ref *pmatrix;
+ gs_matrix mat;
+ ref *pencoding = 0;
+ bool bitmapwidths;
+ int exactsize, inbetweensize, transformedchar;
+ int wmode;
+ int code;
+ gs_font *pfont;
+ ref *pfid;
+ ref *aop = dict_access_ref(op);
+
+ get_font_name(&kname, op - 1);
+ if ( dict_find_string(op, "FontType", &pftype) <= 0 ||
+ !r_has_type(pftype, t_integer) ||
+ pftype->value.intval != (int)ftype ||
+ dict_find_string(op, "FontMatrix", &pmatrix) <= 0 ||
+ read_matrix(pmatrix, &mat) < 0
+ )
+ return_error(e_invalidfont);
+ if ( dict_find_string(op, "Encoding", &pencoding) <= 0 )
+ { if ( !(options & bf_Encoding_optional) )
+ return_error(e_invalidfont);
+ }
+ else
+ { if ( !r_is_array(pencoding) )
+ return_error(e_invalidfont);
+ }
+ if ( dict_find_string(op, "FontName", &pfontname) > 0 )
+ get_font_name(&fname, pfontname);
+ else
+ make_empty_string(&fname, a_readonly);
+ if ( (code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 ||
+ (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 ||
+ (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 ||
+ (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 ||
+ (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0
+ )
+ return code;
+ code = dict_find_string(op, "FID", &pfid);
+ if ( code > 0 )
+ { if ( !r_has_type(pfid, t_fontID) )
+ return_error(e_invalidfont);
+ /*
+ * If this font has a FID entry already, it might be
+ * a scaled font made by makefont or scalefont;
+ * in a Level 2 environment, it might be an existing font
+ * being registered under a second name, or a re-encoded
+ * font (which is questionable PostScript, but dvips
+ * is known to do this).
+ */
+ pfont = r_ptr(pfid, gs_font);
+ if ( pfont->base == pfont ) /* original font */
+ { if ( !level2_enabled )
+ return_error(e_invalidfont);
+ if ( obj_eq(pfont_dict(pfont), op) )
+ { *ppfont = pfont;
+ return 1;
+ }
+ /*
+ * This is a re-encoded font, or some other
+ * questionable situation in which the FID
+ * was preserved. Pretend the FID wasn't there.
+ */
+ }
+ else
+ { /* This was made by makefont or scalefont. */
+ /* Just insert the new name. */
+ code = 1;
+ goto set_name;
+ }
+ }
+ /* This is a new font. */
+ if ( !r_has_attr(aop, a_write) )
+ return_error(e_invalidaccess);
+ { font_data *pdata;
+ /* Make sure that we allocate the font data */
+ /* in the same VM as the font dictionary. */
+ uint space = ialloc_space(idmemory);
+
+ ialloc_set_space(idmemory, r_space(op));
+ pfont = ialloc_struct(gs_font, pstype,
+ "buildfont(font)");
+ pdata = ialloc_struct(font_data, &st_font_data,
+ "buildfont(data)");
+ if ( pfont == 0 || pdata == 0 )
+ code = gs_note_error(e_VMerror);
+ else
+ code = add_FID(op, pfont);
+ if ( code < 0 )
+ { ifree_object(pdata, "buildfont(data)");
+ ifree_object(pfont, "buildfont(font)");
+ ialloc_set_space(idmemory, space);
+ return code;
+ }
+ refset_null((ref *)pdata, sizeof(font_data) / sizeof(ref));
+ ref_assign_new(&pdata->dict, op);
+ ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar);
+ ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph);
+ if ( pencoding )
+ ref_assign_new(&pdata->Encoding, pencoding);
+ /* Clear the chain pointers so as not to confuse the memory */
+ /* manager if we bail out after returning from here. */
+ pfont->next = pfont->prev = 0;
+ pfont->memory = imemory;
+ pfont->dir = 0;
+ pfont->base = pfont;
+ pfont->client_data = pdata;
+ pfont->FontType = ftype;
+ pfont->FontMatrix = mat;
+ pfont->BitmapWidths = bitmapwidths;
+ pfont->ExactSize = (fbit_type)exactsize;
+ pfont->InBetweenSize = (fbit_type)inbetweensize;
+ pfont->TransformedChar = (fbit_type)transformedchar;
+ pfont->WMode = wmode;
+ pfont->PaintType = 0;
+ pfont->StrokeWidth = 0.0;
+ pfont->procs.build_char = gs_no_build_char;
+ pfont->procs.encode_char = zfont_encode_char;
+ pfont->procs.callbacks.glyph_name = zfont_glyph_name;
+ pfont->procs.callbacks.known_encode = zfont_known_encode;
+ ialloc_set_space(idmemory, space);
+ }
+ code = 0;
+set_name:
+ copy_font_name(&pfont->key_name, &kname);
+ copy_font_name(&pfont->font_name, &fname);
+ *ppfont = pfont;
+ return code;
+}
+
+/* Get the string corresponding to a font name. */
+/* If the font name isn't a name or a string, return an empty string. */
+private void
+get_font_name(ref *pfname, const ref *op)
+{ switch ( r_type(op) )
+ {
+ case t_string:
+ *pfname = *op;
+ break;
+ case t_name:
+ name_string_ref(op, pfname);
+ break;
+ default:
+ /* This is weird, but legal.... */
+ make_empty_string(pfname, a_readonly);
+ }
+}
+
+/* Copy a font name into the gs_font structure. */
+private void
+copy_font_name(gs_font_name *pfstr, const ref *pfname)
+{ uint size = r_size(pfname);
+ if ( size > gs_font_name_max )
+ size = gs_font_name_max;
+ memcpy(&pfstr->chars[0], pfname->value.const_bytes, size);
+ /* Following is only for debugging printout. */
+ pfstr->chars[size] = 0;
+ pfstr->size = size;
+}
+
+/* Finish building a font, by calling gs_definefont if needed. */
+int
+define_gs_font(gs_font *pfont)
+{ return (pfont->base == pfont && pfont->dir == 0 ? /* i.e., unregistered original font */
+ gs_definefont(ifont_dir, pfont) :
+ 0);
+}
diff --git a/gs/src/zfont42.c b/gs/src/zfont42.c
new file mode 100644
index 000000000..7daf66f0a
--- /dev/null
+++ b/gs/src/zfont42.c
@@ -0,0 +1,115 @@
+/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfont42.c */
+/* Type 42 font creation operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "bfont.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+
+/* Forward references */
+private int z42_string_proc(P4(gs_font_type42 *, ulong, uint, const byte **));
+
+/* <string|name> <font_dict> .buildfont11/42 <string|name> <font> */
+/* Build a type 11 (TrueType CID-keyed) or 42 (TrueType) font. */
+int
+build_gs_TrueType_font(os_ptr op, font_type ftype, const char _ds *bcstr,
+ const char _ds *bgstr, build_font_options_t options)
+{ build_proc_refs build;
+ ref *psfnts;
+ ref sfnts0;
+#define sfd (sfnts0.value.const_bytes)
+ gs_font_type42 *pfont;
+ font_data *pdata;
+ int code;
+
+ code = build_proc_name_refs(&build, bcstr, bgstr);
+ if ( code < 0 )
+ return code;
+ check_type(*op, t_dictionary);
+ if ( dict_find_string(op, "sfnts", &psfnts) <= 0 )
+ return_error(e_invalidfont);
+ if ( (code = array_get(psfnts, 0L, &sfnts0)) < 0 )
+ return code;
+ if ( !r_has_type(&sfnts0, t_string) )
+ return_error(e_typecheck);
+ code = build_gs_primitive_font(op, (gs_font_base **)&pfont, ftype,
+ &st_gs_font_type42, &build, options);
+ if ( code != 0 )
+ return code;
+ pdata = pfont_data(pfont);
+ ref_assign(&pdata->u.type42.sfnts, psfnts);
+ pfont->data.string_proc = z42_string_proc;
+ pfont->data.proc_data = (char *)pdata;
+ code = gs_type42_font_init(pfont);
+ if ( code < 0 )
+ return code;
+ return define_gs_font((gs_font *)pfont);
+}
+private int
+zbuildfont42(os_ptr op)
+{ return build_gs_TrueType_font(op, ft_TrueType, "%Type42BuildChar",
+ "%Type42BuildGlyph", bf_options_none);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfont42_op_defs) {
+ {"2.buildfont42", zbuildfont42},
+END_OP_DEFS(0) }
+
+/* Procedure for accessing the sfnts array. */
+private int
+z42_string_proc(gs_font_type42 *pfont, ulong offset, uint length,
+ const byte **pdata)
+{ const font_data *pfdata = pfont_data(pfont);
+ ulong left = offset;
+ uint index = 0;
+
+ for ( ; ; ++index )
+ { ref rstr;
+ int code = array_get(&pfdata->u.type42.sfnts, index, &rstr);
+ uint size;
+
+ if ( code < 0 )
+ return code;
+ if ( !r_has_type(&rstr, t_string) )
+ return_error(e_typecheck);
+ /*
+ * NOTE: According to the Adobe documentation, each sfnts
+ * string should have even length. If the length is odd,
+ * the additional byte is padding and should be ignored.
+ */
+ size = r_size(&rstr) & ~1;
+ if ( left < size )
+ { if ( left + length > size )
+ return_error(e_rangecheck);
+ *pdata = rstr.value.const_bytes + left;
+ return 0;
+ }
+ left -= size;
+ }
+}
diff --git a/gs/src/zfproc.c b/gs/src/zfproc.c
new file mode 100644
index 000000000..82590d1da
--- /dev/null
+++ b/gs/src/zfproc.c
@@ -0,0 +1,332 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfproc.c */
+/* Procedure-based filter stream support */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h" /* for ifilter.h */
+#include "estack.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "istruct.h" /* for gs_reloc_refs */
+#include "stream.h"
+#include "strimpl.h"
+#include "ifilter.h"
+#include "files.h"
+#include "store.h"
+
+/* ---------------- Generic ---------------- */
+
+/* GC procedures */
+#define pptr ((stream_proc_state *)vptr)
+private CLEAR_MARKS_PROC(sproc_clear_marks) {
+ r_clear_attrs(&pptr->proc, l_mark);
+ r_clear_attrs(&pptr->data, l_mark);
+}
+private ENUM_PTRS_BEGIN(sproc_enum_ptrs) return 0;
+ case 0:
+ *pep = &pptr->proc;
+ return ptr_ref_type;
+ case 1:
+ *pep = &pptr->data;
+ return ptr_ref_type;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(sproc_reloc_ptrs) ;
+ gs_reloc_refs((ref_packed *)&pptr->proc,
+ (ref_packed *)(&pptr->proc + 1), gcst);
+ r_clear_attrs(&pptr->proc, l_mark);
+ gs_reloc_refs((ref_packed *)&pptr->data,
+ (ref_packed *)(&pptr->data + 1), gcst);
+ r_clear_attrs(&pptr->data, l_mark);
+RELOC_PTRS_END
+#undef pptr
+/* Structure type for procedure-based streams. */
+private_st_stream_proc_state();
+
+/* Allocate and open a procedure-based filter. */
+/* The caller must have checked that *sop is a procedure. */
+private int
+s_proc_init(ref *sop, stream **psstrm, uint mode, const stream_template *temp)
+{ stream *sstrm;
+ stream_proc_state *state;
+ static const stream_procs procs =
+ { s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_std_null, NULL
+ };
+ sstrm = file_alloc_stream(imemory, "s_proc_init(stream)");
+ state = (stream_proc_state *)s_alloc_state(imemory, &st_sproc_state,
+ "s_proc_init(state)");
+ if ( sstrm == 0 || state == 0 )
+ { ifree_object(state, "s_proc_init(state)");
+ /*ifree_object(sstrm, "s_proc_init(stream)");*/ /* just leave it on the file list */
+ return_error(e_VMerror);
+ }
+ s_std_init(sstrm, NULL, 0, &procs, mode);
+ sstrm->procs.process = temp->process;
+ state->template = temp;
+ state->memory = imemory;
+ state->eof = 0;
+ state->proc = *sop;
+ make_empty_string(&state->data, a_all);
+ state->index = 0;
+ sstrm->state = (stream_state *)state;
+ *psstrm = sstrm;
+ return 0;
+}
+
+/* Handle an interrupt during a stream operation. */
+/* This is logically unrelated to procedure streams, */
+/* but it is also associated with the interpreter stream machinery. */
+private int
+s_handle_intc(const ref *pstate, int nstate, int (*cont)(P1(os_ptr)))
+{ int npush = nstate + 2;
+
+ check_estack(npush);
+ if ( nstate )
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+#if 0 /* **************** */
+ { int code = gs_interpret_error(e_interrupt, (ref *)(esp + npush));
+ if ( code < 0 )
+ return code;
+ }
+#else /* **************** */
+ npush--;
+#endif /* **************** */
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ return o_push_estack;
+}
+
+
+/* ---------------- Read streams ---------------- */
+
+/* Forward references */
+private stream_proc_process(s_proc_read_process);
+private int s_proc_read_continue(P1(os_ptr));
+
+/* Stream templates */
+private const stream_template s_proc_read_template =
+{ &st_sproc_state, NULL, s_proc_read_process, 1, 1, NULL
+};
+
+/* Allocate and open a procedure-based read stream. */
+/* The caller must have checked that *sop is a procedure. */
+int
+sread_proc(ref *sop, stream **psstrm)
+{ int code =
+ s_proc_init(sop, psstrm, s_mode_read, &s_proc_read_template);
+ if ( code < 0 )
+ return code;
+ (*psstrm)->end_status = CALLC;
+ return code;
+}
+
+/* Handle an input request. */
+#define ss ((stream_proc_state *)st)
+private int
+s_proc_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ /* Move data from the string returned by the procedure */
+ /* into the stream buffer, or ask for a callback. */
+ uint count = r_size(&ss->data) - ss->index;
+ if ( count > 0 )
+ { uint wcount = pw->limit - pw->ptr;
+ if ( wcount < count )
+ count = wcount;
+ memcpy(pw->ptr + 1, ss->data.value.bytes + ss->index, count);
+ pw->ptr += count;
+ ss->index += count;
+ return 1;
+ }
+ return (ss->eof ? EOFC : CALLC);
+}
+#undef ss
+
+/* Handle an exception (INTC or CALLC) from a read stream */
+/* whose buffer is empty. */
+int
+s_handle_read_exception(int status, const ref *fop, const ref *pstate,
+ int nstate, int (*cont)(P1(os_ptr)))
+{ int npush = nstate + 4;
+ stream *ps;
+
+ switch ( status )
+ {
+ case INTC: return s_handle_intc(pstate, nstate, cont);
+ case CALLC: break;
+ default: return_error(e_ioerror);
+ }
+ /* Find the stream whose buffer needs refilling. */
+ for ( ps = fptr(fop); ps->strm != 0; )
+ ps = ps->strm;
+#define psst ((stream_proc_state *)ps->state)
+ check_estack(npush);
+ if ( nstate )
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ make_op_estack(esp - 2, s_proc_read_continue);
+ esp[-1] = *fop;
+ r_clear_attrs(esp - 1, a_executable);
+ *esp = psst->proc;
+#undef psst
+ return o_push_estack;
+}
+/* Continue a read operation after returning from a procedure callout. */
+/* osp[0] contains the file (pushed on the e-stack by handle_read_status); */
+/* osp[-1] contains the new data string (pushed by the procedure). */
+/* The top of the e-stack contains the real continuation. */
+private int
+s_proc_read_continue(os_ptr op)
+{ os_ptr opbuf = op - 1;
+ stream *ps;
+ stream_proc_state *ss;
+
+ check_file(ps, op);
+ check_read_type(*opbuf, t_string);
+ while ( (ps->end_status = 0, ps->strm) != 0 )
+ ps = ps->strm;
+ ss = (stream_proc_state *)ps->state;
+ ss->data = *opbuf;
+ ss->index = 0;
+ if ( r_size(opbuf) == 0 )
+ ss->eof = true;
+ pop(2);
+ return 0;
+}
+
+/* ---------------- Write streams ---------------- */
+
+/* Forward references */
+private stream_proc_process(s_proc_write_process);
+private int s_proc_write_continue(P1(os_ptr));
+
+/* Stream templates */
+private const stream_template s_proc_write_template =
+{ &st_sproc_state, NULL, s_proc_write_process, 1, 1, NULL
+};
+
+/* Allocate and open a procedure-based write stream. */
+/* The caller must have checked that *sop is a procedure. */
+int
+swrite_proc(ref *sop, stream **psstrm)
+{ return s_proc_init(sop, psstrm, s_mode_write, &s_proc_write_template);
+}
+
+/* Handle an output request. */
+#define ss ((stream_proc_state *)st)
+private int
+s_proc_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ /* Move data from the stream buffer to the string */
+ /* returned by the procedure, or ask for a callback. */
+ uint rcount = pr->limit - pr->ptr;
+ if ( rcount > 0 )
+ { uint wcount = r_size(&ss->data) - ss->index;
+ uint count = min(rcount, wcount);
+ memcpy(ss->data.value.bytes + ss->index, pr->ptr + 1, count);
+ pr->ptr += count;
+ ss->index += count;
+ if ( rcount > wcount )
+ return CALLC;
+ else if ( last )
+ { ss->eof = true;
+ return CALLC;
+ }
+ else
+ return 0;
+ }
+ return ((ss->eof = last) ? EOFC : 0);
+}
+#undef ss
+
+/* Handle an exception (INTC or CALLC) from a write stream */
+/* whose buffer is full. */
+int
+s_handle_write_exception(int status, const ref *fop, const ref *pstate,
+ int nstate, int (*cont)(P1(os_ptr)))
+{ stream *ps;
+
+ switch ( status )
+ {
+ case INTC: return s_handle_intc(pstate, nstate, cont);
+ case CALLC: break;
+ default: return_error(e_ioerror);
+ }
+ /* Find the stream whose buffer needs emptying. */
+ for ( ps = fptr(fop); ps->strm != 0; )
+ ps = ps->strm;
+#define psst ((stream_proc_state *)ps->state)
+ if ( psst->eof )
+ { /* This is the final call from closing the stream. */
+ /* Don't run the continuation. */
+ check_estack(5);
+ esp += 5;
+ make_op_estack(esp - 4, zpop); /* pop the file */
+ make_op_estack(esp - 3, zpop); /* pop the string returned */
+ /* by the procedure */
+ make_false(esp - 1);
+ }
+ else
+ { int npush = nstate + 6;
+ check_estack(npush);
+ if ( nstate )
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ make_op_estack(esp - 4, s_proc_write_continue);
+ esp[-3] = *fop;
+ r_clear_attrs(esp - 3, a_executable);
+ make_true(esp - 1);
+ }
+ esp[-2] = psst->proc;
+ *esp = psst->data;
+ r_set_size(esp, psst->index);
+#undef psst
+ return o_push_estack;
+}
+/* Continue a write operation after returning from a procedure callout. */
+/* osp[0] contains the file (pushed on the e-stack by handle_write_status); */
+/* osp[-1] contains the new buffer string (pushed by the procedure). */
+/* The top of the e-stack contains the real continuation. */
+private int
+s_proc_write_continue(os_ptr op)
+{ os_ptr opbuf = op - 1;
+ stream *ps;
+ stream_proc_state *ss;
+
+ check_file(ps, op);
+ check_write_type(*opbuf, t_string);
+ while ( (ps->end_status = 0, ps->strm) != 0 )
+ ps = ps->strm;
+ ss = (stream_proc_state *)ps->state;
+ ss->data = *opbuf;
+ ss->index = 0;
+ pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfproc_op_defs) {
+ /* Internal operators */
+ {"2%s_proc_read_continue", s_proc_read_continue},
+ {"2%s_proc_write_continue", s_proc_write_continue},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfunc.c b/gs/src/zfunc.c
new file mode 100644
index 000000000..692526edf
--- /dev/null
+++ b/gs/src/zfunc.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfunc.c */
+/* Generic PostScript language interface to Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsfunc.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "store.h"
+
+/* Define the maximum depth of nesting of subsidiary functions. */
+#define max_depth 3
+
+/* Define the table of build procedures. */
+build_function_proc((*build_function_procs[5])) = {
+ build_function_undefined, build_function_undefined, build_function_undefined,
+ build_function_undefined, build_function_undefined
+};
+
+int
+build_function_undefined(const_os_ptr op, const gs_function_params_t *mnDR,
+ int depth, gs_function_t **ppfn)
+{ return_error(e_rangecheck);
+}
+
+/* GC descriptors */
+gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *",
+ function_ptr_enum_ptrs, function_ptr_reloc_ptrs);
+gs_private_st_element(st_function_ptr_element, gs_function_t *,
+ "gs_function_t *[]", function_ptr_element_enum_ptrs,
+ function_ptr_element_reloc_ptrs, st_function_ptr);
+
+/* ------ Operators ------ */
+
+private int zexecfunction(P1(os_ptr op));
+
+/* <dict> .buildfunction <function_struct> */
+private int
+zbuildfunction(os_ptr op)
+{ gs_function_t *pfn;
+ ref cref; /* closure */
+ int code;
+
+ code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
+ ".buildfunction");
+ if ( code < 0 )
+ return code;
+ code = fn_build_function(op, &pfn);
+ if ( code < 0 ) {
+ ifree_ref_array(&cref, ".buildfunction");
+ return code;
+ }
+ make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
+ make_oper_new(cref.value.refs + 1, 0, zexecfunction);
+ ref_assign(op, &cref);
+ return 0;
+}
+
+/* <in1> ... <function_struct> %execfunction <out1> ... */
+private int
+zexecfunction(os_ptr op)
+{ /*
+ * Since this operator's name begins with %, the name is not defined
+ * in systemdict. The only place this operator can ever appear is
+ * in the execute-only closure created by .buildfunction.
+ * Therefore, in principle it is unnecessary to check the argument.
+ * However, we do a little checking anyway just on general
+ * principles. Note that since the argument may be an instance of
+ * any subclass of gs_function_t, we currently have no way to check
+ * its type.
+ */
+ if ( !r_is_struct(op) ||
+ r_has_masked_attrs(op, a_executable | a_execute, a_all)
+ )
+ return_error(e_typecheck);
+ { gs_function_t *pfn = (gs_function_t *)op->value.pstruct;
+ int m = pfn->params.m, n = pfn->params.n;
+ int diff = n - (m + 1);
+
+ if ( diff > 0 )
+ check_ostack(diff);
+ { float *in = (float *)ialloc_byte_array(m, sizeof(float),
+ "%execfunction(in)");
+ float *out = (float *)ialloc_byte_array(n, sizeof(float),
+ "%execfunction(out)");
+ int code;
+
+ if ( in == 0 || out == 0 )
+ code = gs_note_error(e_VMerror);
+ else if ( (code = float_params(op - 1, m, in)) < 0 ||
+ (code = gs_function_evaluate(pfn, in, out)) < 0
+ )
+ DO_NOTHING;
+ else {
+ if ( diff > 0 )
+ push(diff); /* can't fail */
+ else if ( diff < 0 ) {
+ pop(-diff); op = osp;
+ }
+ code = make_floats(op + 1 - n, out, n);
+ }
+ ifree_object(out, "%execfunction(out)");
+ ifree_object(in, "%execfunction(in)");
+ return code;
+ }
+ }
+}
+
+/* ------ Procedures ------ */
+
+/* Build a function structure from a PostScript dictionary. */
+int
+fn_build_sub_function(const ref *op, gs_function_t **ppfn, int depth)
+{ int code, type;
+ gs_function_params_t params;
+
+ if ( depth > max_depth )
+ return_error(e_limitcheck);
+ check_type(*op, t_dictionary);
+ code = dict_int_param(op, "FunctionType", 0,
+ countof(build_function_procs) - 1, -1, &type);
+ if ( code < 0 )
+ return code;
+ /* Collect parameters common to all function types. */
+ params.Domain = 0;
+ params.Range = 0;
+ code = fn_build_float_array(op, "Domain", true, true, &params.Domain);
+ if ( code < 0 )
+ goto fail;
+ params.m = code >> 1;
+ code = fn_build_float_array(op, "Range", false, true, &params.Range);
+ if ( code < 0 )
+ goto fail;
+ params.n = code >> 1;
+ /* Finish building the function. */
+ /* If this fails, it will free all the parameters. */
+ return (*build_function_procs[type])(op, &params, depth + 1, ppfn);
+fail: ifree_object((void *)params.Range, "Range"); /* break const */
+ ifree_object((void *)params.Domain, "Domain"); /* break const */
+ return code;
+}
+
+/* Allocate an array of function objects. */
+int
+ialloc_function_array(uint count, gs_function_t ***pFunctions)
+{ gs_function_t **ptr;
+
+ if ( count == 0 )
+ return_error(e_rangecheck);
+ ptr = ialloc_struct_array(count, gs_function_t *,
+ &st_function_ptr_element, "Functions");
+ if ( ptr == 0 )
+ return_error(e_VMerror);
+ memset(ptr, 0, sizeof(*ptr) * count);
+ *pFunctions = ptr;
+ return 0;
+}
+
+/* Collect a heap-allocated array of floats. */
+/* If the key is missing, set *pparray = 0 and return 0; */
+/* otherwise set *pparray and return the number of elements. */
+int
+fn_build_float_array(const ref *op, const char _ds *kstr, bool required,
+ bool even, const float **pparray)
+{ ref *par;
+ int code;
+
+ *pparray = 0;
+ if ( dict_find_string(op, kstr, &par) <= 0 )
+ return(required ? gs_note_error(e_rangecheck) : 0);
+ if ( !r_is_array(par) )
+ return_error(e_typecheck);
+ { uint size = r_size(par);
+ float *ptr = (float *)ialloc_byte_array(size, sizeof(float), kstr);
+
+ if ( ptr == 0 )
+ return_error(e_VMerror);
+ code = dict_float_array_param(op, kstr, size, ptr, NULL);
+ if ( code <= 0 || (even && (code & 1) != 0) ) {
+ ifree_object(ptr, kstr);
+ return_error(code < 0 ? code : e_rangecheck);
+ }
+ *pparray = ptr;
+ }
+#undef max_values
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfunc_op_defs) {
+ {"1.buildfunction", zbuildfunction},
+ {"1%execfunction", zexecfunction},
+END_OP_DEFS(0) }
diff --git a/gs/src/zfunc0.c b/gs/src/zfunc0.c
new file mode 100644
index 000000000..7c6acedab
--- /dev/null
+++ b/gs/src/zfunc0.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfunc0.c */
+/* PostScript language interface to FunctionType 0 (Sampled) Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsdsrc.h"
+#include "gsfunc.h"
+#include "gsfunc0.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+
+/* Initialization */
+private build_function_proc(build_function_0);
+int
+zfunc0_init(gs_memory_t *mem)
+{ build_function_procs[0] = build_function_0;
+ return 0;
+}
+
+BEGIN_OP_DEFS(zfunc0_op_defs) {
+END_OP_DEFS(zfunc0_init) }
+
+/* Finish building a FunctionType 0 (Sampled) function. */
+private int
+build_function_0(const_os_ptr op, const gs_function_params_t *mnDR, int depth,
+ gs_function_t **ppfn)
+{ gs_function_Sd_params_t params;
+ ref *pDataSource;
+ int code;
+
+ *(gs_function_params_t *)&params = *mnDR;
+ params.Encode = 0;
+ params.Decode = 0;
+ params.Size = 0;
+ if ( (code = dict_find_string(op, "DataSource", &pDataSource)) <= 0 )
+ return(code < 0 ? code : gs_note_error(e_rangecheck));
+ switch ( r_type(pDataSource) ) {
+ case t_string:
+ data_source_init_string2(&params.DataSource,
+ pDataSource->value.const_bytes,
+ r_size(pDataSource));
+ break;
+ case t_file:
+ { stream *s;
+
+ check_read_known_file_else(s, pDataSource, return_error,
+ return_error(e_invalidfileaccess));
+ if ( !(s->modes & s_mode_seek) )
+ return_error(e_ioerror);
+ data_source_init_stream(&params.DataSource, s);
+ }
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if ( (code = dict_int_param(op, "Order", 1, 3, 1, &params.Order)) < 0 ||
+ (code = dict_int_param(op, "BitsPerSample", 1, 32, 0,
+ &params.BitsPerSample)) < 0 ||
+ ((code = fn_build_float_array(op, "Encode", false, true, &params.Encode)) != 2 * params.m && (code != 0 || params.Encode != 0)) ||
+ ((code = fn_build_float_array(op, "Decode", false, true, &params.Decode)) != 2 * params.n && (code != 0 || params.Decode != 0))
+ ) {
+ goto fail;
+ }
+ { int *ptr = (int *)ialloc_byte_array(params.m, sizeof(int), "Size");
+
+ if ( ptr == 0 ) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ params.Size = ptr;
+ code = dict_int_array_param(op, "Size", params.m, ptr);
+ if ( code != params.m )
+ goto fail;
+ }
+ code = gs_function_Sd_init(ppfn, &params, imemory);
+ if ( code >= 0 )
+ return 0;
+fail: gs_function_Sd_free_params(&params, imemory);
+ return(code < 0 ? code : gs_note_error(e_rangecheck));
+}
diff --git a/gs/src/zfzlib.c b/gs/src/zfzlib.c
new file mode 100644
index 000000000..4ac08f98d
--- /dev/null
+++ b/gs/src/zfzlib.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zfzlib.c */
+/* zlib and Flate filter creation */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "idict.h"
+#include "strimpl.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "szlibx.h"
+#include "ifilter.h"
+
+/* Import the Predictor machinery from zfdecode.c and zfilter2.c. */
+int filter_read_predictor(P4(os_ptr op, int npop,
+ const stream_template *template, stream_state *st));
+int filter_write_predictor(P4(os_ptr op, int npop,
+ const stream_template *template, stream_state *st));
+
+/* <source> zlibEncode/filter <file> */
+/* <source> <dict_ignored> zlibEncode/filter <file> */
+private int
+zzlibE(os_ptr op)
+{ stream_zlib_state zls;
+
+ (*s_zlibE_template.set_defaults)((stream_state *)&zls);
+ return filter_write(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ &s_zlibE_template, (stream_state *)&zls, 0);
+}
+
+/* <target> zlibDecode/filter <file> */
+/* <target> <dict_ignored> zlibDecode/filter <file> */
+private int
+zzlibD(os_ptr op)
+{ stream_zlib_state zls;
+
+ (*s_zlibD_template.set_defaults)((stream_state *)&zls);
+ return filter_read(op, (r_has_type(op, t_dictionary) ? 1 : 0),
+ &s_zlibD_template, (stream_state *)&zls, 0);
+}
+
+/* <source> FlateEncode/filter <file> */
+/* <source> <dict> FlateEncode/filter <file> */
+private int
+zFlateE(os_ptr op)
+{ stream_zlib_state zls;
+ int npop;
+
+ if ( r_has_type(op, t_dictionary) )
+ { check_dict_read(*op);
+ npop = 1;
+ }
+ else
+ npop = 0;
+ (*s_zlibE_template.set_defaults)((stream_state *)&zls);
+ return filter_write_predictor(op, npop, &s_zlibE_template,
+ (stream_state *)&zls);
+}
+
+/* <target> FlateDecode/filter <file> */
+/* <target> <dict> FlateDecode/filter <file> */
+private int
+zFlateD(os_ptr op)
+{ stream_zlib_state zls;
+ int npop;
+
+ if ( r_has_type(op, t_dictionary) )
+ { check_dict_read(*op);
+ npop = 1;
+ }
+ else
+ npop = 0;
+ (*s_zlibD_template.set_defaults)((stream_state *)&zls);
+ return filter_read_predictor(op, npop, &s_zlibD_template,
+ (stream_state *)&zls);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zfzlib_op_defs) {
+ op_def_begin_filter(),
+ {"1zlibEncode", zzlibE},
+ {"1zlibDecode", zzlibD},
+ {"1FlateEncode", zFlateE},
+ {"1FlateDecode", zFlateD},
+END_OP_DEFS(0) }
diff --git a/gs/src/zgeneric.c b/gs/src/zgeneric.c
new file mode 100644
index 000000000..89af47130
--- /dev/null
+++ b/gs/src/zgeneric.c
@@ -0,0 +1,496 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zgeneric.c */
+/* Array/string/dictionary generic operators for PostScript */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h" /* for forall */
+#include "idict.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* This file implements copy, get, put, getinterval, putinterval, */
+/* length, and forall, which apply generically to */
+/* arrays, strings, and dictionaries. (Copy also has a special */
+/* meaning for copying the top N elements of the stack.) */
+
+/* See the comment in opdef.h for an invariant which allows */
+/* more efficient implementation of forall. */
+
+/* Imported operators */
+extern int zcopy_dict(P1(os_ptr));
+
+/* Forward references */
+private int zcopy_invalid(P1(os_ptr));
+private int zcopy_integer(P1(os_ptr));
+private int zcopy_interval(P1(os_ptr));
+private int copy_interval(P4(os_ptr, uint, os_ptr, client_name_t));
+
+/* The type dispatch table for `copy'. */
+/* We export it so that Level 2 can extend it to handle gstates. */
+op_proc_p zcopy_procs[t_next_index];
+
+/* Initialize the generic dispatch table. */
+private void
+zgeneric_init(void)
+{ int i;
+
+ /*
+ * Because other files may have initialized some entries,
+ * we only initialize entries that are zero.
+ */
+ for ( i = 0; i < t_next_index; i++ )
+ if ( zcopy_procs[i] == 0 )
+ zcopy_procs[i] = zcopy_invalid;
+ /*zcopy_procs[t_integer] = zcopy_integer;*/ /* handled specially */
+ zcopy_procs[t_array] = zcopy_procs[t_string] = zcopy_interval;
+ zcopy_procs[t_dictionary] = zcopy_dict;
+}
+
+/* <various1> <various2> copy <various> */
+/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
+/* Note that this implements copy for arrays and strings, */
+/* but not for dictionaries (see zcopy_dict in zdict.c). */
+private int
+zcopy(register os_ptr op)
+{ int type = r_type(op);
+ if ( type == t_integer )
+ return zcopy_integer(op);
+ if ( type >= t_next_index )
+ return_error(e_typecheck);
+ check_op(2);
+ return (*zcopy_procs[type])(op);
+}
+/* <other> copy */
+private int
+zcopy_invalid(os_ptr op)
+{ return_op_typecheck(op);
+}
+/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
+private int
+zcopy_integer(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int count, i;
+ int code;
+ if ( (ulong)op->value.intval > op - osbot )
+ { /* There might be enough elements in other blocks. */
+ check_int_ltu(*op, ref_stack_count(&o_stack));
+ count = op->value.intval;
+ }
+ else if ( op1 + (count = op->value.intval) <= ostop )
+ { /* Fast case. */
+ memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
+ push(count - 1);
+ return 0;
+ }
+ /* Do it the slow, general way. */
+ code = ref_stack_push(&o_stack, count - 1);
+ if ( code < 0 )
+ return code;
+ for ( i = 0; i < count; i++ )
+ *ref_stack_index(&o_stack, i) =
+ *ref_stack_index(&o_stack, i + count);
+ return 0;
+}
+/* <array1> <array2> copy <subarray2> */
+/* <string1> <string2> copy <substring2> */
+private int
+zcopy_interval(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int code = copy_interval(op, 0, op1, "copy");
+ if ( code < 0 ) return code;
+ r_set_size(op, r_size(op1));
+ *op1 = *op;
+ pop(1);
+ return 0;
+}
+
+/* <array|dict|name|packedarray|string> length <int> */
+private int
+zlength(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_array:
+ case t_string:
+ case t_mixedarray:
+ case t_shortarray:
+ check_read(*op);
+ make_int(op, r_size(op));
+ return 0;
+ case t_dictionary:
+ check_dict_read(*op);
+ make_int(op, dict_length(op));
+ return 0;
+ case t_name:
+ { ref str;
+ name_string_ref(op, &str);
+ make_int(op, r_size(&str));
+ }
+ return 0;
+ default:
+ return_op_typecheck(op);
+ }
+}
+
+/* <array|packedarray|string> <index> get <obj> */
+/* <dict> <key> get <obj> */
+private int
+zget(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ ref *pvalue;
+ switch ( r_type(op1) )
+ {
+ case t_dictionary:
+ check_dict_read(*op1);
+ if ( dict_find(op1, op, &pvalue) <= 0 )
+ return_error(e_undefined);
+ op[-1] = *pvalue;
+ break;
+ case t_string:
+ check_read(*op1);
+ check_int_ltu(*op, r_size(op1));
+ make_int(op1, op1->value.bytes[(uint)op->value.intval]);
+ break;
+ default:
+ { int code;
+ check_type(*op, t_integer);
+ check_read(*op1);
+ code = array_get(op1, op->value.intval, op1);
+ if ( code < 0 )
+ { /* Might be a stackunderflow reported as typecheck. */
+ if ( code == e_typecheck )
+ return_op_typecheck(op1);
+ else
+ return code;
+ }
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <array> <index> <obj> put - */
+/* <dict> <key> <value> put - */
+/* <string> <index> <int> put - */
+private int
+zput(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ os_ptr op2 = op1 - 1;
+ switch ( r_type(op2) )
+ {
+ case t_dictionary:
+ check_dict_write(*op2);
+ { int code = dict_put(op2, op1, op);
+ if ( code < 0 ) return code; /* error */
+ }
+ break;
+ case t_array:
+ check_write(*op2);
+ check_int_ltu(*op1, r_size(op2));
+ store_check_dest(op2, op);
+ { ref *eltp = op2->value.refs + (uint)op1->value.intval;
+ ref_assign_old(op2, eltp, op, "put");
+ } break;
+ case t_mixedarray: /* packed arrays are read-only */
+ case t_shortarray:
+ return_error(e_invalidaccess);
+ case t_string:
+ check_write(*op2);
+ check_int_ltu(*op1, r_size(op2));
+ check_int_leu(*op, 0xff);
+ op2->value.bytes[(uint)op1->value.intval] = (byte)op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op2);
+ }
+ pop(3);
+ return 0;
+}
+
+/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
+private int
+zgetinterval(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ os_ptr op2 = op1 - 1;
+ uint index;
+ uint count;
+ switch ( r_type(op2) )
+ {
+ default:
+ return_op_typecheck(op2);
+ case t_array: case t_string:
+ case t_mixedarray:
+ case t_shortarray: ;
+ }
+ check_read(*op2);
+ check_int_leu(*op1, r_size(op2));
+ index = op1->value.intval;
+ check_int_leu(*op, r_size(op2) - index);
+ count = op->value.intval;
+ switch ( r_type(op2) )
+ {
+ case t_array: op2->value.refs += index; break;
+ case t_string: op2->value.bytes += index; break;
+ case t_mixedarray:
+ { const ref_packed *packed = op2->value.packed;
+ for ( ; index--; ) packed = packed_next(packed);
+ op2->value.packed = packed;
+ } break;
+ case t_shortarray: op2->value.packed += index; break;
+ }
+ r_set_size(op2, count);
+ pop(2);
+ return 0;
+}
+
+/* <array1> <index> <array2|packedarray2> putinterval - */
+/* <string1> <index> <string2> putinterval - */
+private int
+zputinterval(register os_ptr op)
+{ os_ptr opindex = op - 1;
+ os_ptr opto = opindex - 1;
+ int code;
+ switch ( r_type(opto) )
+ {
+ default:
+ return_op_typecheck(opto);
+ case t_mixedarray:
+ case t_shortarray:
+ return_error(e_invalidaccess);
+ case t_array:
+ case t_string:
+ ;
+ }
+ check_write(*opto);
+ check_int_leu(*opindex, r_size(opto));
+ code = copy_interval(opto, (uint)(opindex->value.intval), op, "putinterval");
+ if ( code >= 0 ) pop(3);
+ return code;
+}
+
+/* <array|packedarray|string> <<element> proc> forall - */
+/* <dict> <<key> <value> proc> forall - */
+private int
+ array_continue(P1(os_ptr)),
+ dict_continue(P1(os_ptr)),
+ string_continue(P1(os_ptr)),
+ packedarray_continue(P1(os_ptr));
+private int forall_cleanup(P1(os_ptr));
+private int
+zforall(register os_ptr op)
+{ os_ptr obj = op - 1;
+ register es_ptr ep = esp;
+ uint index = 0; /* only used for dictionaries */
+ check_estack(6);
+#define cproc (ep + 5)
+ switch ( r_type(obj) )
+ {
+ default:
+ return_op_typecheck(obj);
+ case t_array:
+ check_read(*obj);
+ make_op_estack(cproc, array_continue);
+ break;
+ case t_dictionary:
+ check_dict_read(*obj);
+ make_op_estack(cproc, dict_continue);
+ index = dict_first(obj);
+ break;
+ case t_string:
+ check_read(*obj);
+ make_op_estack(cproc, string_continue);
+ break;
+ case t_mixedarray:
+ case t_shortarray:
+ check_read(*obj);
+ make_op_estack(cproc, packedarray_continue);
+ break;
+ }
+ check_proc(*op);
+ /* Push a mark, the composite object, the iteration index, */
+ /* and the procedure, and invoke the continuation operator. */
+ make_mark_estack(ep + 1, es_for, forall_cleanup);
+ ep[2] = *obj;
+ make_int(ep + 3, index);
+ ep[4] = *op;
+ esp += 4;
+ pop(2); op -= 2;
+ return (*real_opproc(cproc))(op);
+#undef cproc
+}
+/* Continuation operator for arrays */
+private int
+array_continue(register os_ptr op)
+{ es_ptr obj = esp - 2;
+ if ( r_size(obj) ) /* continue */
+ { push(1);
+ r_dec_size(obj, 1);
+ *op = *obj->value.refs;
+ obj->value.refs++;
+ esp += 2;
+ *esp = obj[2];
+ return o_push_estack;
+ }
+ else /* done */
+ { esp -= 4; /* pop mark, object, index, proc */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for dictionaries */
+private int
+dict_continue(register os_ptr op)
+{ es_ptr obj = esp - 2;
+ int index = (int)esp[-1].value.intval;
+ push(2); /* make room for key and value */
+ if ( (index = dict_next(obj, index, op - 1)) >= 0 ) /* continue */
+ { esp[-1].value.intval = index;
+ esp += 2;
+ *esp = obj[2];
+ return o_push_estack;
+ }
+ else /* done */
+ { pop(2); /* undo push */
+ esp -= 4; /* pop mark, object, index, proc */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for strings */
+private int
+string_continue(register os_ptr op)
+{ es_ptr obj = esp - 2;
+ if ( r_size(obj) ) /* continue */
+ { r_dec_size(obj, 1);
+ push(1);
+ make_int(op, *obj->value.bytes);
+ obj->value.bytes++;
+ esp += 2;
+ *esp = obj[2];
+ return o_push_estack;
+ }
+ else /* done */
+ { esp -= 4; /* pop mark, object, index, proc */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for packed arrays */
+private int
+packedarray_continue(register os_ptr op)
+{ es_ptr obj = esp - 2;
+ if ( r_size(obj) ) /* continue */
+ { const ref_packed *packed = obj->value.packed;
+ r_dec_size(obj, 1);
+ push(1);
+ packed_get(packed, op);
+ obj->value.packed = packed_next(packed);
+ esp += 2;
+ *esp = obj[2];
+ return o_push_estack;
+ }
+ else /* done */
+ { esp -= 4; /* pop mark, object, index, proc */
+ return o_pop_estack;
+ }
+}
+/* Vacuous cleanup procedure */
+private int
+forall_cleanup(os_ptr op)
+{ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zgeneric_op_defs) {
+ {"1copy", zcopy},
+ {"2forall", zforall},
+ {"2get", zget},
+ {"3getinterval", zgetinterval},
+ {"1length", zlength},
+ {"3put", zput},
+ {"3putinterval", zputinterval},
+ /* Internal operators */
+ {"0%array_continue", array_continue},
+ {"0%dict_continue", dict_continue},
+ {"0%packedarray_continue", packedarray_continue},
+ {"0%string_continue", string_continue},
+END_OP_DEFS(zgeneric_init) }
+
+/* ------ Shared routines ------ */
+
+/* Copy an interval from one operand to another. */
+/* This is used by both putinterval and string/array copy. */
+/* The destination is known to be an array or string, */
+/* and the starting index is known to be less than or equal to */
+/* its length; nothing else has been checked. */
+private int
+copy_interval(os_ptr prto, uint index, os_ptr prfrom, client_name_t cname)
+{ int fromtype = r_type(prfrom);
+ uint fromsize = r_size(prfrom);
+ if ( !(fromtype == r_type(prto) ||
+ ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
+ r_type(prto) == t_array))
+ )
+ return_op_typecheck(prfrom);
+ check_read(*prfrom);
+ check_write(*prto);
+ if ( fromsize > r_size(prto) - index )
+ return_error(e_rangecheck);
+ switch ( fromtype )
+ {
+ case t_array:
+ { /* We have to worry about aliasing, */
+ /* but refcpy_to_old takes care of it for us. */
+ return refcpy_to_old(prto, index, prfrom->value.refs,
+ fromsize, cname);
+ }
+ case t_string:
+ { /* We have to worry about aliasing. */
+ const byte *from = prfrom->value.bytes;
+ byte *to = prto->value.bytes + index;
+ uint i;
+ if ( from + fromsize <= to || to + fromsize <= from )
+ memcpy(to, from, fromsize);
+ else if ( to < from )
+ for ( i = fromsize; i != 0; i--, from++, to++ )
+ *to = *from;
+ else
+ for ( i = fromsize, from += i, to += i; i != 0; i-- )
+ *--to = *--from;
+ } break;
+ case t_mixedarray:
+ case t_shortarray:
+ { /* We don't have to worry about aliasing, because */
+ /* packed arrays are read-only and hence the destination */
+ /* can't be a packed array. */
+ int i;
+ const ref_packed *packed = prfrom->value.packed;
+ ref *pdest = prto->value.refs + index;
+ ref elt;
+ for ( i = 0; i < fromsize; i++, pdest++ )
+ { packed_get(packed, &elt);
+ ref_assign_old(prto, pdest, &elt, cname);
+ packed = packed_next(packed);
+ }
+ } break;
+ }
+ return 0;
+}
diff --git a/gs/src/zgstate.c b/gs/src/zgstate.c
new file mode 100644
index 000000000..12822c7fd
--- /dev/null
+++ b/gs/src/zgstate.c
@@ -0,0 +1,453 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zgstate.c */
+/* Graphics state operators */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "istruct.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "store.h"
+
+/* Forward references */
+private int near num_param(P2(const_os_ptr, int (*)(P2(gs_state *, floatp))));
+
+/* Structure descriptors */
+private_st_int_gstate();
+
+/* ------ Operations on the entire graphics state ------ */
+
+/* The current graphics state */
+gs_state *igs;
+private gs_gc_root_t igs_root;
+
+/* An empty dictionary for the pagedevice member of the int_gstate. */
+ref i_null_pagedevice;
+private ref *npd_p;
+private gs_gc_root_t npd_root;
+
+/* "Client" procedures */
+private void *gs_istate_alloc(P1(gs_memory_t *mem));
+private int gs_istate_copy(P2(void *to, const void *from));
+private void gs_istate_free(P2(void *old, gs_memory_t *mem));
+private const gs_state_client_procs istate_procs = {
+ gs_istate_alloc,
+ gs_istate_copy,
+ gs_istate_free
+};
+
+/* Initialize the graphics stack. */
+#ifdef DPNEXT
+void
+igs_init(void)
+{ dict_create(0, &i_null_pagedevice);
+ r_clear_attrs(&i_null_pagedevice, a_write);
+ npd_p = &i_null_pagedevice;
+ gs_register_ref_root(imemory, &npd_root, (void **)&npd_p, "igs(npd)");
+ gs_register_struct_root(imemory, &igs_root, (void **)&igs, "igs");
+ igs = int_gstate_alloc(iimemory);
+}
+gs_state *
+int_gstate_alloc(gs_ref_memory_t *mem)
+{
+#else
+void
+igs_init(void)
+{
+#endif
+ int_gstate *iigs;
+ ref proc0;
+
+#ifdef DPNEXT
+ gs_state *pgs = gs_state_alloc((gs_memory_t *)mem);
+
+ iigs = gs_alloc_struct((gs_memory_t *)mem, int_gstate, &st_int_gstate,
+ "int_gstate_alloc(int_gstate)");
+#else
+ igs = gs_state_alloc(imemory);
+ iigs = gs_alloc_struct(imemory, int_gstate, &st_int_gstate,
+ "igs_init");
+#endif
+ int_gstate_map_refs(iigs, make_null);
+ make_empty_array(&iigs->dash_pattern, a_all);
+#ifdef DPNEXT
+ gs_alloc_ref_array(mem, &proc0, a_readonly + a_executable, 2,
+ "int_gstate_alloc(proc0)");
+#else
+ ialloc_ref_array(&proc0, a_readonly + a_executable, 2,
+ "igs_init");
+#endif
+ make_oper(proc0.value.refs, 0, zpop);
+ make_real(proc0.value.refs + 1, 0.0);
+ iigs->black_generation = proc0;
+ iigs->undercolor_removal = proc0;
+#ifndef DPNEXT
+ dict_create(0, &i_null_pagedevice);
+ r_clear_attrs(&i_null_pagedevice, a_write);
+#endif
+ iigs->pagedevice = i_null_pagedevice;
+#ifdef DPNEXT
+ gs_state_set_client(pgs, iigs, &istate_procs);
+ /* PostScript code wants limit clamping enabled. */
+ gs_setlimitclamp(pgs, true);
+#else
+ npd_p = &i_null_pagedevice;
+ gs_register_ref_root(imemory, &npd_root, (void **)&npd_p, "igs(npd)");
+ gs_state_set_client(igs, iigs, &istate_procs);
+ gs_register_struct_root(imemory, &igs_root, (void **)&igs, "igs");
+ /* PostScript code wants limit clamping enabled. */
+ gs_setlimitclamp(igs, true);
+#endif
+ /*
+ * gsave and grestore only work properly
+ * if there are always at least 2 entries on the stack.
+ * We count on the PostScript initialization code to do a gsave.
+ */
+#ifdef DPNEXT
+ return pgs;
+#endif
+}
+
+/* - gsave - */
+int
+zgsave(register os_ptr op)
+{ return gs_gsave(igs);
+}
+
+/* - grestore - */
+int
+zgrestore(register os_ptr op)
+{ return gs_grestore(igs);
+}
+
+/* - grestoreall - */
+int
+zgrestoreall(register os_ptr op)
+{ return gs_grestoreall(igs);
+}
+
+/* - initgraphics - */
+private int
+zinitgraphics(register os_ptr op)
+{ /* gs_initgraphics does a setgray; we must clear the interpreter's */
+ /* cached copy of the color space object. */
+ int code = gs_initgraphics(igs);
+ if ( code >= 0 )
+ make_null(&istate->colorspace.array);
+ return code;
+}
+
+/* ------ Operations on graphics state elements ------ */
+
+/* <num> setlinewidth - */
+private int
+zsetlinewidth(register os_ptr op)
+{ /*
+ * The Red Book doesn't say anything about this, but Adobe
+ * interpreters return (or perhaps store) the absolute value
+ * of the width.
+ */
+ double width;
+ int code = real_param(op, &width);
+
+ if ( code < 0 )
+ return_op_typecheck(op);
+ code = gs_setlinewidth(igs, fabs(width));
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* - currentlinewidth <num> */
+private int
+zcurrentlinewidth(register os_ptr op)
+{ push(1);
+ make_real(op, gs_currentlinewidth(igs));
+ return 0;
+}
+
+/* <cap_int> .setlinecap - */
+private int
+zsetlinecap(register os_ptr op)
+{ int param;
+ int code = int_param(op, max_int, &param);
+
+ if ( code < 0 || (code = gs_setlinecap(igs, (gs_line_cap)param)) < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - currentlinecap <cap_int> */
+private int
+zcurrentlinecap(register os_ptr op)
+{ push(1);
+ make_int(op, (int)gs_currentlinecap(igs));
+ return 0;
+}
+
+/* <join_int> .setlinejoin - */
+private int
+zsetlinejoin(register os_ptr op)
+{ int param;
+ int code = int_param(op, max_int, &param);
+
+ if ( code < 0 || (code = gs_setlinejoin(igs, (gs_line_join)param)) < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - currentlinejoin <join_int> */
+private int
+zcurrentlinejoin(register os_ptr op)
+{ push(1);
+ make_int(op, (int)gs_currentlinejoin(igs));
+ return 0;
+}
+
+/* <num> setmiterlimit - */
+private int
+zsetmiterlimit(register os_ptr op)
+{ return num_param(op, gs_setmiterlimit);
+}
+
+/* - currentmiterlimit <num> */
+private int
+zcurrentmiterlimit(register os_ptr op)
+{ push(1);
+ make_real(op, gs_currentmiterlimit(igs));
+ return 0;
+}
+
+/* <array> <offset> setdash - */
+private int
+zsetdash(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ double offset;
+ int code = real_param(op, &offset);
+ uint i, n;
+ gs_memory_t *mem = imemory;
+ float *pattern;
+
+ if ( code < 0 )
+ return_op_typecheck(op);
+ if ( !r_is_array(op1) )
+ return_op_typecheck(op1);
+ /* Adobe interpreters apparently don't check the array for */
+ /* read access, so we won't either. */
+ /*check_read(*op1);*/
+ /* Unpack the dash pattern and check it */
+ n = r_size(op1);
+ pattern =
+ (float *)gs_alloc_byte_array(mem, n, sizeof(float), "setdash");
+ if ( pattern == 0 )
+ return_error(e_VMerror);
+ for ( i = 0, code = 0; i < n && code >= 0; ++i )
+ { ref element;
+ array_get(op1, (long)i, &element);
+ code = float_param(&element, &pattern[i]);
+ }
+ if ( code >= 0 )
+ code = gs_setdash(igs, pattern, n, offset);
+ gs_free_object(mem, pattern, "setdash"); /* gs_setdash copies this */
+ if ( code < 0 )
+ return code;
+ ref_assign(&istate->dash_pattern, op1);
+ pop(2);
+ return code;
+}
+
+/* - currentdash <array> <offset> */
+private int
+zcurrentdash(register os_ptr op)
+{ push(2);
+ ref_assign(op - 1, &istate->dash_pattern);
+ make_real(op, gs_currentdash_offset(igs));
+ return 0;
+}
+
+/* <num> setflat - */
+private int
+zsetflat(register os_ptr op)
+{ return num_param(op, gs_setflat);
+}
+
+/* - currentflat <num> */
+private int
+zcurrentflat(register os_ptr op)
+{ push(1);
+ make_real(op, gs_currentflat(igs));
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <bool> .setaccuratecurves - */
+private int
+zsetaccuratecurves(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_setaccuratecurves(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currentaccuratecurves <bool> */
+private int
+zcurrentaccuratecurves(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentaccuratecurves(igs));
+ return 0;
+}
+
+/* <adjust.x> <adjust.y> .setfilladjust2 - */
+private int
+zsetfilladjust2(register os_ptr op)
+{ double adjust[2];
+ int code = num_params(op, 2, adjust);
+
+ if ( code < 0 )
+ return code;
+ code = gs_setfilladjust(igs, adjust[0], adjust[1]);
+ if ( code < 0 )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* - .currentfilladjust2 <adjust.x> <adjust.y> */
+private int
+zcurrentfilladjust2(register os_ptr op)
+{ gs_point adjust;
+
+ push(2);
+ gs_currentfilladjust(igs, &adjust);
+ make_real(op - 1, adjust.x);
+ make_real(op, adjust.y);
+ return 0;
+}
+
+/* <bool> .setdashadapt - */
+private int
+zsetdashadapt(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_setdashadapt(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currentdashadapt <bool> */
+private int
+zcurrentdashadapt(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentdashadapt(igs));
+ return 0;
+}
+
+/* <num> <bool> .setdotlength - */
+private int
+zsetdotlength(register os_ptr op)
+{ double length;
+ int code = real_param(op - 1, &length);
+
+ if ( code < 0 )
+ return code;
+ check_type(*op, t_boolean);
+ code = gs_setdotlength(igs, length, op->value.boolval);
+ if ( code < 0 )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* - .currentdotlength <num> <bool> */
+private int
+zcurrentdotlength(register os_ptr op)
+{ push(2);
+ make_real(op - 1, gs_currentdotlength(igs));
+ make_bool(op, gs_currentdotlength_absolute(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zgstate_op_defs) {
+ {"0.currentaccuratecurves", zcurrentaccuratecurves},
+ {"0currentdash", zcurrentdash},
+ {"0.currentdashadapt", zcurrentdashadapt},
+ {"0.currentdotlength", zcurrentdotlength},
+ {"0.currentfilladjust2", zcurrentfilladjust2},
+ {"0currentflat", zcurrentflat},
+ {"0currentlinecap", zcurrentlinecap},
+ {"0currentlinejoin", zcurrentlinejoin},
+ {"0currentlinewidth", zcurrentlinewidth},
+ {"0currentmiterlimit", zcurrentmiterlimit},
+ {"0grestore", zgrestore},
+ {"0grestoreall", zgrestoreall},
+ {"0gsave", zgsave},
+ {"0initgraphics", zinitgraphics},
+ {"1.setaccuratecurves", zsetaccuratecurves},
+ {"2setdash", zsetdash},
+ {"1.setdashadapt", zsetdashadapt},
+ {"2.setdotlength", zsetdotlength},
+ {"2.setfilladjust2", zsetfilladjust2},
+ {"1setflat", zsetflat},
+ {"1.setlinecap", zsetlinecap},
+ {"1.setlinejoin", zsetlinejoin},
+ {"1setlinewidth", zsetlinewidth},
+ {"1setmiterlimit", zsetmiterlimit},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Allocate the interpreter's part of a graphics state. */
+private void *
+gs_istate_alloc(gs_memory_t *mem)
+{ return gs_alloc_struct(mem, int_gstate, &st_int_gstate, "int_gsave");
+}
+
+/* Copy the interpreter's part of a graphics state. */
+private int
+gs_istate_copy(void *to, const void *from)
+{ *(int_gstate *)to = *(const int_gstate *)from;
+ return 0;
+}
+
+/* Free the interpreter's part of a graphics state. */
+private void
+gs_istate_free(void *old, gs_memory_t *mem)
+{ gs_free_object(mem, old, "int_grestore");
+}
+
+/* Get a numeric parameter */
+private int near
+num_param(const_os_ptr op, int (*pproc)(P2(gs_state *, floatp)))
+{ double param;
+ int code = real_param(op, &param);
+
+ if ( code < 0 )
+ return_op_typecheck(op);
+ code = (*pproc)(igs, param);
+ if ( !code ) pop(1);
+ return code;
+}
diff --git a/gs/src/zhsb.c b/gs/src/zhsb.c
new file mode 100644
index 000000000..fdbf489f7
--- /dev/null
+++ b/gs/src/zhsb.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zhsb.c */
+/* HSB color operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "igstate.h"
+#include "store.h"
+#include "gshsb.h"
+
+/* - currenthsbcolor <hue> <saturation> <brightness> */
+private int
+zcurrenthsbcolor(register os_ptr op)
+{ float par[3];
+
+ gs_currenthsbcolor(igs, par);
+ push(3);
+ make_floats(op - 2, par, 3);
+ return 0;
+}
+
+/* <hue> <saturation> <brightness> sethsbcolor - */
+private int
+zsethsbcolor(register os_ptr op)
+{ double par[3];
+ int code;
+
+ if ( (code = num_params(op, 3, par)) < 0 ||
+ (code = gs_sethsbcolor(igs, par[0], par[1], par[2])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(3);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zhsb_op_defs) {
+ {"0currenthsbcolor", zcurrenthsbcolor},
+ {"3sethsbcolor", zsethsbcolor},
+END_OP_DEFS(0) }
diff --git a/gs/src/zht.c b/gs/src/zht.c
new file mode 100644
index 000000000..08db39ad3
--- /dev/null
+++ b/gs/src/zht.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 1989, 1991, 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zht.c */
+/* Halftone definition operators */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* must precede igstate.h, */
+ /* because of #ifdef in gsht.h */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "gsstate.h"
+#include "iht.h" /* prototypes */
+#include "store.h"
+
+/* Forward references */
+private int screen_sample(P1(os_ptr));
+private int set_screen_continue(P1(os_ptr));
+private int screen_cleanup(P1(os_ptr));
+
+/* - .currenthalftone <dict> 0 */
+/* - .currenthalftone <frequency> <angle> <proc> 1 */
+/* - .currenthalftone <red_freq> ... <gray_proc> 2 */
+private int
+zcurrenthalftone(register os_ptr op)
+{ gs_halftone ht;
+ gs_currenthalftone(igs, &ht);
+ switch ( ht.type )
+ {
+ case ht_type_screen:
+ push(4);
+ make_real(op - 3, ht.params.screen.frequency);
+ make_real(op - 2, ht.params.screen.angle);
+ op[-1] = istate->screen_procs.colored.gray;
+ make_int(op, 1);
+ break;
+ case ht_type_colorscreen:
+ push(13);
+ { int i;
+ for ( i = 0; i < 4; i++ )
+ { os_ptr opc = op - 12 + i * 3;
+ gs_screen_halftone *pht =
+ &ht.params.colorscreen.screens.indexed[i];
+ make_real(opc, pht->frequency);
+ make_real(opc + 1, pht->angle);
+ opc[2] = istate->screen_procs.indexed[i];
+ }
+ }
+ make_int(op, 2);
+ break;
+ default: /* Screen was set by sethalftone. */
+ push(2);
+ op[-1] = istate->halftone;
+ make_int(op, 0);
+ break;
+ }
+ return 0;
+}
+
+/* - .currentscreenlevels <int> */
+private int
+zcurrentscreenlevels(register os_ptr op)
+{ push(1);
+ make_int(op, gs_currentscreenlevels(igs));
+ return 0;
+}
+
+/* The setscreen operator is complex because it has to sample */
+/* each pixel in the pattern cell, calling a procedure, and then */
+/* sort the result into a whitening order. */
+
+/* Layout of stuff pushed on estack: */
+/* Control mark, */
+/* [other stuff for other screen-setting operators], */
+/* finishing procedure (or 0), */
+/* spot procedure, */
+/* enumeration structure (as bytes). */
+#define snumpush 4
+#define sproc esp[-1]
+#define senum r_ptr(esp, gs_screen_enum)
+
+/* Forward references */
+int zscreen_enum_init(P7(os_ptr, const gx_ht_order *, gs_screen_halftone *,
+ ref *, int, int (*)(P1(os_ptr)), gs_memory_t *));
+private int setscreen_finish(P1(os_ptr));
+
+/* <frequency> <angle> <proc> setscreen - */
+private int
+zsetscreen(register os_ptr op)
+{ gs_screen_halftone screen;
+ gx_ht_order order;
+ int code = zscreen_params(op, &screen);
+ gs_memory_t *mem;
+
+ if ( code < 0 )
+ return code;
+ mem = (gs_memory_t *)idmemory->spaces.indexed[r_space_index(op)];
+ /*
+ * Allocate the halftone in the same VM space as the procedure.
+ * This keeps the space relationships consistent.
+ */
+ code = gs_screen_order_init_memory(&order, igs, &screen,
+ gs_currentaccuratescreens(), mem);
+ if ( code < 0 )
+ return code;
+ return zscreen_enum_init(op, &order, &screen, op, 3,
+ setscreen_finish, mem);
+}
+/* We break out the body of this operator so it can be shared with */
+/* the code for Type 1 halftones in sethalftone. */
+int
+zscreen_enum_init(os_ptr op, const gx_ht_order *porder,
+ gs_screen_halftone *psp, ref *pproc, int npop,
+ int (*finish_proc)(P1(os_ptr)), gs_memory_t *mem)
+{ gs_screen_enum *penum;
+ int code;
+
+ check_estack(snumpush + 1);
+ penum = gs_screen_enum_alloc(imemory, "setscreen");
+ if ( penum == 0 )
+ return_error(e_VMerror);
+ make_istruct(esp + snumpush, 0, penum); /* do early for screen_cleanup in case of error */
+ code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
+ if ( code < 0 )
+ { screen_cleanup(op);
+ return code;
+ }
+ /* Push everything on the estack */
+ make_mark_estack(esp + 1, es_other, screen_cleanup);
+ esp += snumpush;
+ make_op_estack(esp - 2, finish_proc);
+ sproc = *pproc;
+ push_op_estack(screen_sample);
+ pop(npop);
+ return o_push_estack;
+}
+/* Set up the next sample */
+private int
+screen_sample(register os_ptr op)
+{ gs_screen_enum *penum = senum;
+ gs_point pt;
+ int code = gs_screen_currentpoint(penum, &pt);
+ ref proc;
+ switch ( code )
+ {
+ default:
+ return code;
+ case 1:
+ /* All done */
+ if ( real_opproc(esp - 2) != 0 )
+ code = (*real_opproc(esp - 2))(op);
+ esp -= snumpush;
+ screen_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ case 0:
+ ;
+ }
+ push(2);
+ make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ proc = sproc;
+ push_op_estack(set_screen_continue);
+ *++esp = proc;
+ return o_push_estack;
+}
+/* Continuation procedure for processing sampled pixels. */
+private int
+set_screen_continue(register os_ptr op)
+{ double value;
+ int code = real_param(op, &value);
+
+ if ( code < 0 ) return code;
+ code = gs_screen_next(senum, value);
+ if ( code < 0 ) return code;
+ pop(1); op--;
+ return screen_sample(op);
+}
+/* Finish setscreen. */
+private int
+setscreen_finish(os_ptr op)
+{ gs_screen_install(senum);
+ istate->screen_procs.colored.red = sproc;
+ istate->screen_procs.colored.green = sproc;
+ istate->screen_procs.colored.blue = sproc;
+ istate->screen_procs.colored.gray = sproc;
+ make_null(&istate->halftone);
+ return 0;
+}
+/* Clean up after screen enumeration */
+private int
+screen_cleanup(os_ptr op)
+{ ifree_object(esp[snumpush].value.pstruct, "screen_cleanup");
+ return 0;
+}
+
+/* ------ Utility procedures ------ */
+
+/* Get parameters for a single screen. */
+int
+zscreen_params(os_ptr op, gs_screen_halftone *phs)
+{ double fa[2];
+ int code = num_params(op - 1, 2, fa);
+
+ if ( code < 0 )
+ return code;
+ check_proc(*op);
+ phs->frequency = fa[0];
+ phs->angle = fa[1];
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zht_op_defs) {
+ {"0.currenthalftone", zcurrenthalftone},
+ {"0.currentscreenlevels", zcurrentscreenlevels},
+ {"3setscreen", zsetscreen},
+ /* Internal operators */
+ {"0%screen_sample", screen_sample},
+ {"1%set_screen_continue", set_screen_continue},
+ {"0%setscreen_finish", setscreen_finish},
+END_OP_DEFS(0) }
diff --git a/gs/src/zht1.c b/gs/src/zht1.c
new file mode 100644
index 000000000..91d9d81fd
--- /dev/null
+++ b/gs/src/zht1.c
@@ -0,0 +1,143 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zht1.c */
+/* setcolorscreen operator */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* must precede igstate.h, */
+ /* because of #ifdef in gsht.h */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "gsstate.h"
+#include "iht.h"
+#include "store.h"
+
+/* Dummy spot function */
+float
+spot_dummy(floatp x, floatp y)
+{ return (x + y) / 2;
+}
+
+/* <red_freq> ... <gray_proc> setcolorscreen - */
+private int setcolorscreen_finish(P1(os_ptr));
+private int setcolorscreen_cleanup(P1(os_ptr));
+private int
+zsetcolorscreen(register os_ptr op)
+{ gs_colorscreen_halftone cscreen;
+ ref sprocs[4];
+ gs_halftone *pht;
+ gx_device_halftone *pdht;
+ int i;
+ int code = 0;
+ int space = 0;
+ gs_memory_t *mem;
+
+ for ( i = 0; i < 4; i++ )
+ { os_ptr op1 = op - 9 + i * 3;
+ int code = zscreen_params(op1, &cscreen.screens.indexed[i]);
+ if ( code < 0 )
+ return code;
+ cscreen.screens.indexed[i].spot_function = spot_dummy;
+ sprocs[i] = *op1;
+ space = max(space, r_space_index(op1));
+ }
+ mem = (gs_memory_t *)idmemory->spaces.indexed[space];
+ check_estack(8); /* for sampling screens */
+ rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
+ mem, pht = 0, "setcolorscreen(halftone)");
+ rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
+ mem, pdht = 0, "setcolorscreen(device halftone)");
+ if ( pht == 0 || pdht == 0 )
+ code = gs_note_error(e_VMerror);
+ else
+ { pht->type = ht_type_colorscreen;
+ pht->params.colorscreen = cscreen;
+ code = gs_sethalftone_prepare(igs, pht, pdht);
+ }
+ if ( code >= 0 )
+ { /* Schedule the sampling of the screens. */
+ es_ptr esp0 = esp; /* for backing out */
+ esp += 8;
+ make_mark_estack(esp - 7, es_other, setcolorscreen_cleanup);
+ memcpy(esp - 6, sprocs, sizeof(ref) * 4); /* procs */
+ make_istruct(esp - 2, 0, pht);
+ make_istruct(esp - 1, 0, pdht);
+ make_op_estack(esp, setcolorscreen_finish);
+ for ( i = 0; i < 4; i++ )
+ { /* Shuffle the indices to correspond to */
+ /* the component order. */
+ code = zscreen_enum_init(op,
+ &pdht->components[(i + 1) & 3].corder,
+ &pht->params.colorscreen.screens.indexed[i],
+ &sprocs[i], 0, 0, mem);
+ if ( code < 0 )
+ { esp = esp0;
+ break;
+ }
+ }
+ }
+ if ( code < 0 )
+ { gs_free_object(mem, pdht, "setcolorscreen(device halftone)");
+ gs_free_object(mem, pht, "setcolorscreen(halftone)");
+ return code;
+ }
+ pop(12);
+ return o_push_estack;
+}
+/* Install the color screen after sampling. */
+private int
+setcolorscreen_finish(os_ptr op)
+{ gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
+ int code;
+ pdht->order = pdht->components[0].corder;
+ code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
+ if ( code < 0 )
+ return code;
+ memcpy(istate->screen_procs.indexed, esp - 5, sizeof(ref) * 4);
+ make_null(&istate->halftone);
+ esp -= 7;
+ setcolorscreen_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after installing the color screen. */
+private int
+setcolorscreen_cleanup(os_ptr op)
+{ gs_halftone *pht = r_ptr(esp + 6, gs_halftone);
+ gx_device_halftone *pdht = r_ptr(esp + 7, gx_device_halftone);
+
+ gs_free_object(pdht->rc.memory, pdht,
+ "setcolorscreen_cleanup(device halftone)");
+ gs_free_object(pht->rc.memory, pht,
+ "setcolorscreen_cleanup(halftone)");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zht1_op_defs) {
+ {"<setcolorscreen", zsetcolorscreen},
+ /* Internal operators */
+ {"0%setcolorscreen_finish", setcolorscreen_finish},
+END_OP_DEFS(0) }
diff --git a/gs/src/zht2.c b/gs/src/zht2.c
new file mode 100644
index 000000000..ad6945c8e
--- /dev/null
+++ b/gs/src/zht2.c
@@ -0,0 +1,326 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zht2.c */
+/* Level 2 sethalftone operator */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icolor.h"
+#include "iht.h"
+#include "store.h"
+
+/* Forward references */
+private int dict_spot_params(P4(const ref *, gs_spot_halftone *,
+ ref *, ref *));
+private int dict_spot_results(P2(ref *, const gs_spot_halftone *));
+private int dict_threshold_params(P3(const ref *,
+ gs_threshold_halftone *, ref *));
+
+/* <dict> <dict5> .sethalftone5 - */
+float spot_dummy(P2(floatp, floatp)); /* in zht1.c */
+int spot_sample_finish(P1(os_ptr)); /* in zht.c */
+private int sethalftone_finish(P1(os_ptr));
+private int sethalftone_cleanup(P1(os_ptr));
+private int
+zsethalftone5(register os_ptr op)
+{ uint count;
+ gs_halftone_component *phtc;
+ gs_halftone_component *pc;
+ int code = 0;
+ int i, j;
+ gs_halftone *pht;
+ gx_device_halftone *pdht;
+ static const char _ds *color_names[] =
+ { gs_ht_separation_name_strings };
+ ref sprocs[countof(color_names)];
+ ref tprocs[countof(color_names)];
+ gs_memory_t *mem;
+ int npop = 2;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ check_type(op[-1], t_dictionary);
+ check_dict_read(op[-1]);
+ count = 0;
+ for ( i = 0; i < countof(color_names); i++ )
+ { ref *pvalue;
+ if ( dict_find_string(op, color_names[i], &pvalue) > 0 )
+ count++;
+ else if ( i == gs_ht_separation_Default )
+ return_error(e_typecheck);
+ }
+ mem = (gs_memory_t *)idmemory->spaces.indexed[r_space_index(op - 1)];
+ check_estack(5); /* for sampling Type 1 screens */
+ refset_null(sprocs, countof(sprocs));
+ refset_null(tprocs, countof(tprocs));
+ rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
+ imemory, pht = 0, ".sethalftone5");
+ phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
+ &st_ht_component_element,
+ ".sethalftone5");
+ rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
+ imemory, pdht = 0, ".sethalftone5");
+ if ( pht == 0 || phtc == 0 || pdht == 0 )
+ code = gs_note_error(e_VMerror);
+ else
+ for ( i = 0, j = 0, pc = phtc; i < countof(color_names); i++ )
+ { int type;
+ ref *pvalue;
+ if ( dict_find_string(op, color_names[i], &pvalue) > 0 )
+ { check_type_only(*pvalue, t_dictionary);
+ check_dict_read(*pvalue);
+ if ( dict_int_param(pvalue, "HalftoneType", 1, 5, 0,
+ &type) < 0
+ )
+ { code = gs_note_error(e_typecheck);
+ break;
+ }
+ switch ( type )
+ {
+ default:
+ code = gs_note_error(e_rangecheck);
+ break;
+ case 1:
+ code = dict_spot_params(pvalue,
+ &pc->params.spot, sprocs + j,
+ tprocs + j);
+ pc->params.spot.screen.spot_function =
+ spot_dummy;
+ pc->type = ht_type_spot;
+ break;
+ case 3:
+ code = dict_threshold_params(pvalue,
+ &pc->params.threshold, tprocs + j);
+ pc->type = ht_type_threshold;
+ break;
+ }
+ if ( code < 0 )
+ break;
+ pc->cname = (gs_ht_separation_name)i;
+ pc++, j++;
+ }
+ }
+ if ( code >= 0 )
+ { /* We think that Type 2 and Type 4 halftones, like */
+ /* screens set by setcolorscreen, adapt automatically to */
+ /* the device color space, so we need to mark them */
+ /* with a different internal halftone type. */
+ int type = 0;
+
+ dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
+ pht->type =
+ (type == 2 || type == 4 ? ht_type_multiple_colorscreen :
+ ht_type_multiple);
+ pht->params.multiple.components = phtc;
+ pht->params.multiple.num_comp = count;
+ code = gs_sethalftone_prepare(igs, pht, pdht);
+ }
+ if ( code >= 0 )
+ for ( j = 0, pc = phtc; j < count; j++, pc++ )
+ { if ( pc->type == ht_type_spot )
+ { ref *pvalue;
+ dict_find_string(op, color_names[pc->cname], &pvalue);
+ code = dict_spot_results(pvalue, &pc->params.spot);
+ if ( code < 0 )
+ break;
+ }
+ }
+ if ( code >= 0 )
+ { /* Schedule the sampling of any Type 1 screens, */
+ /* and any (Type 1 or Type 3) TransferFunctions. */
+ /* Save the stack depths in case we have to back out. */
+ uint edepth = ref_stack_count(&e_stack);
+ uint odepth = ref_stack_count(&o_stack);
+ ref odict, odict5;
+
+ odict = op[-1];
+ odict5 = *op;
+ pop(2); op = osp;
+ esp += 5;
+ make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
+ esp[-3] = odict;
+ make_istruct(esp - 2, 0, pht);
+ make_istruct(esp - 1, 0, pdht);
+ make_op_estack(esp, sethalftone_finish);
+ for ( j = 0; j < count; j++ )
+ { gx_ht_order *porder =
+ (pdht->components == 0 ? &pdht->order :
+ &pdht->components[j].corder);
+ switch ( phtc[j].type )
+ {
+ case ht_type_spot:
+ code = zscreen_enum_init(op, porder,
+ &phtc[j].params.spot.screen,
+ &sprocs[j], 0, 0, mem);
+ if ( code < 0 )
+ break;
+ /* falls through */
+ case ht_type_threshold:
+ if ( !r_has_type(tprocs + j, t__invalid) )
+ { /* Schedule TransferFunction sampling. */
+ /****** check_xstack IS WRONG ******/
+ check_ostack(zcolor_remap_one_ostack);
+ check_estack(zcolor_remap_one_estack);
+ code = zcolor_remap_one(tprocs + j,
+ op, porder->transfer, igs,
+ zcolor_remap_one_finish);
+ op = osp;
+ }
+ break;
+ default: /* not possible here, but to keep */
+ /* the compilers happy.... */
+ ;
+ }
+ if ( code < 0 )
+ { /* Restore the stack. */
+ ref_stack_pop_to(&o_stack, odepth);
+ ref_stack_pop_to(&e_stack, edepth);
+ op = osp;
+ op[-1] = odict;
+ *op = odict5;
+ break;
+ }
+ npop = 0;
+ }
+ }
+ if ( code < 0 )
+ { gs_free_object(mem, pdht, ".sethalftone5");
+ gs_free_object(mem, phtc, ".sethalftone5");
+ gs_free_object(mem, pht, ".sethalftone5");
+ return code;
+ }
+ pop(npop);
+ return o_push_estack;
+}
+/* Install the halftone after sampling. */
+private int
+sethalftone_finish(os_ptr op)
+{ gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
+ int code;
+ if ( pdht->components )
+ pdht->order = pdht->components[0].corder;
+ code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
+ if ( code < 0 )
+ return code;
+ istate->halftone = esp[-2];
+ esp -= 4;
+ sethalftone_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after installing the halftone. */
+private int
+sethalftone_cleanup(os_ptr op)
+{ gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
+ gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
+
+ gs_free_object(pdht->rc.memory, pdht,
+ "sethalftone_cleanup(device halftone)");
+ gs_free_object(pht->rc.memory, pht,
+ "sethalftone_cleanup(halftone)");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zht2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"2.sethalftone5", zsethalftone5},
+ /* Internal operators */
+ {"0%sethalftone_finish", sethalftone_finish},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Extract frequency, angle, spot function, and accurate screens flag */
+/* from a dictionary. */
+private int
+dict_spot_params(const ref *pdict, gs_spot_halftone *psp,
+ ref *psproc, ref *ptproc)
+{ int code;
+ check_dict_read(*pdict);
+ if ( (code = dict_float_param(pdict, "Frequency", 0.0,
+ &psp->screen.frequency)) != 0 ||
+ (code = dict_float_param(pdict, "Angle", 0.0,
+ &psp->screen.angle)) != 0 ||
+ (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
+ (code = dict_bool_param(pdict, "AccurateScreens",
+ gs_currentaccuratescreens(),
+ &psp->accurate_screens)) < 0 ||
+ (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
+ )
+ return (code < 0 ? code : e_undefined);
+ psp->transfer = (code > 0 ? (gs_mapping_proc)0 : gs_mapped_transfer);
+ return 0;
+}
+
+/* Set actual frequency and angle in a dictionary. */
+private int
+dict_real_result(ref *pdict, const char _ds *kstr, floatp val)
+{ int code = 0;
+ ref *ignore;
+ if ( dict_find_string(pdict, kstr, &ignore) > 0 )
+ { ref rval;
+ check_dict_write(*pdict);
+ make_real(&rval, val);
+ code = dict_put_string(pdict, kstr, &rval);
+ }
+ return code;
+}
+private int
+dict_spot_results(ref *pdict, const gs_spot_halftone *psp)
+{ int code;
+ code = dict_real_result(pdict, "ActualFrequency",
+ psp->screen.actual_frequency);
+ if ( code < 0 )
+ return code;
+ return dict_real_result(pdict, "ActualAngle",
+ psp->screen.actual_angle);
+}
+
+/* Extract width, height, and thresholds from a dictionary. */
+private int
+dict_threshold_params(const ref *pdict, gs_threshold_halftone *ptp,
+ ref *ptproc)
+{ int code;
+ ref *tstring;
+ check_dict_read(*pdict);
+ if ( (code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
+ &ptp->width)) < 0 ||
+ (code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
+ &ptp->height)) < 0 ||
+ (code = dict_find_string(pdict, "Thresholds", &tstring)) <= 0 ||
+ (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
+ )
+ return (code < 0 ? code : e_undefined);
+ check_read_type_only(*tstring, t_string);
+ if ( r_size(tstring) != (long)ptp->width * ptp->height )
+ return_error(e_rangecheck);
+ ptp->thresholds.data = tstring->value.const_bytes;
+ ptp->thresholds.size = r_size(tstring);
+ ptp->transfer = (code > 0 ? (gs_mapping_proc)0 : gs_mapped_transfer);
+ return 0;
+}
diff --git a/gs/src/zimage.c b/gs/src/zimage.c
new file mode 100644
index 000000000..ff0f2a9cf
--- /dev/null
+++ b/gs/src/zimage.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zimage.c */
+/* Image operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h" /* for image[mask] */
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "ilevel.h"
+#include "store.h"
+#include "gscspace.h"
+#include "gsmatrix.h"
+#include "gsimage.h"
+#include "stream.h"
+#include "ifilter.h" /* for stream exception handling */
+#include "iimage.h"
+
+/* Define the maximum number of image components. */
+/* (We refer to this as M in a number of places below.) */
+#ifdef DPNEXT
+# define max_components 5
+#else
+# define max_components 4
+#endif
+
+/* Forward references */
+private int image_setup(P5(gs_image_t *pim, bool multi, os_ptr op, const gs_color_space *pcs, int npop));
+private int image_proc_continue(P1(os_ptr));
+private int image_file_continue(P1(os_ptr));
+private int image_file_buffered_continue(P1(os_ptr));
+private int image_string_process(P3(os_ptr, gs_image_enum *, int));
+private int image_cleanup(P1(os_ptr));
+
+/* <width> <height> <bits/sample> <matrix> <datasrc> image - */
+int
+zimage(register os_ptr op)
+{ return zimage_opaque_setup(op, false,
+#ifdef DPNEXT
+ false,
+#endif
+ NULL, 5);
+}
+
+/* <width> <height> <paint_1s> <matrix> <datasrc> imagemask - */
+int
+zimagemask(register os_ptr op)
+{ gs_image_t image;
+
+ check_type(op[-2], t_boolean);
+ gs_image_t_init_mask(&image, op[-2].value.boolval);
+ return image_setup(&image, false, op, NULL, 5);
+}
+
+/* Common setup for image, colorimage, and alphaimage. */
+/* Fills in MultipleDataSources, BitsPerComponent, HasAlpha. */
+#ifdef DPNEXT
+int
+zimage_opaque_setup(os_ptr op, bool multi, bool has_alpha,
+ const gs_color_space *pcs, int npop)
+{ gs_image_t image;
+
+ check_int_leu(op[-2], (level2_enabled ? 12 : 8)); /* bits/sample */
+ gs_image_t_init_color(&image);
+ image.BitsPerComponent = (int)op[-2].value.intval;
+ image.HasAlpha = has_alpha;
+ return image_setup(&image, multi, op, pcs, npop);
+}
+#else
+int
+zimage_opaque_setup(os_ptr op, bool multi,
+ const gs_color_space *pcs, int npop)
+{ gs_image_t image;
+
+ check_int_leu(op[-2], (level2_enabled ? 12 : 8)); /* bits/sample */
+ gs_image_t_init_color(&image);
+ image.BitsPerComponent = (int)op[-2].value.intval;
+ return image_setup(&image, multi, op, pcs, npop);
+}
+#endif
+
+/* Common setup for [color]image and imagemask. */
+/* Fills in Width, Height, ImageMatrix, ColorSpace. */
+private int
+image_setup(gs_image_t *pim, bool multi, os_ptr op,
+ const gs_color_space *pcs, int npop)
+{ int code;
+
+ check_type(op[-4], t_integer); /* width */
+ check_type(op[-3], t_integer); /* height */
+ if ( op[-4].value.intval < 0 || op[-3].value.intval < 0 )
+ return_error(e_rangecheck);
+ if ( (code = read_matrix(op - 1, &pim->ImageMatrix)) < 0 )
+ return code;
+ pim->ColorSpace = pcs;
+ pim->Width = (int)op[-4].value.intval;
+ pim->Height = (int)op[-3].value.intval;
+ return zimage_setup(pim, multi, op, npop);
+}
+
+/* Common setup for Level 1 image/imagemask/colorimage, alphaimage, and */
+/* the Level 2 dictionary form of image/imagemask. */
+int
+zimage_setup(const gs_image_t *pim, bool multi, const ref *sources, int npop)
+{ int code;
+ gs_image_enum *penum;
+ int px;
+ const ref *pp;
+ int num_sources =
+ (multi ? gs_color_space_num_components(pim->ColorSpace) : 1);
+ bool must_buffer = false;
+
+ /*
+ * We push the following on the estack. "Optional" values are
+ * set to null if not used, so the offsets will be constant.
+ * Control mark,
+ * M data sources (1-M actually used),
+ * M row buffers (only if must_buffer),
+ * current plane index,
+ * current byte in row (only if must_buffer, otherwise 0),
+ * enumeration structure.
+ */
+#define inumpush (max_components * 2 + 4)
+ check_estack(inumpush + 2); /* stuff above, + continuation + proc */
+#ifdef DPNEXT
+ if ( pim->HasAlpha && multi )
+ ++num_sources;
+#endif
+ /*
+ * Note that the data sources may be procedures, strings, or (Level
+ * 2 only) files. (The Level 1 reference manual says that Level 1
+ * requires procedures, but Adobe Level 1 interpreters also accept
+ * strings.) The sources must all be of the same type.
+ *
+ * If the sources are files, and two or more are the same file,
+ * we must buffer data for each row; otherwise, we can deliver the
+ * data directly out of the stream buffers.
+ */
+ for ( px = 0, pp = sources; px < num_sources; px++, pp++ )
+ { switch ( r_type(pp) )
+ {
+ case t_file:
+ if ( !level2_enabled )
+ return_error(e_typecheck);
+ /* Check for aliasing. */
+ { int pi;
+ for ( pi = 0; pi < px; ++pi )
+ if ( sources[pi].value.pfile == pp->value.pfile )
+ must_buffer = true;
+ }
+ /* falls through */
+ case t_string:
+ if ( r_type(pp) != r_type(sources) )
+ return_error(e_typecheck);
+ check_read(*pp);
+ break;
+ default:
+ if ( !r_is_proc(sources) )
+ return_error(e_typecheck);
+ check_proc(*pp);
+ }
+ }
+ if ( (penum = gs_image_enum_alloc(imemory, "image_setup")) == 0 )
+ return_error(e_VMerror);
+ code = gs_image_init(penum, pim, multi, igs);
+ if ( code != 0 ) /* error, or empty image */
+ { ifree_object(penum, "image_setup");
+ if ( code >= 0 ) /* empty image */
+ pop(npop);
+ return code;
+ }
+ push_mark_estack(es_other, image_cleanup);
+ ++esp;
+ for ( px = 0, pp = sources; px < max_components; esp++, px++, pp++ )
+ { if ( px < num_sources )
+ *esp = *pp;
+ else
+ make_null(esp);
+ make_null(esp + max_components); /* buffer */
+ }
+ esp += max_components + 2;
+ make_int(esp - 2, 0); /* current plane */
+ make_int(esp - 1, 0); /* current byte in row */
+ make_istruct(esp, 0, penum);
+ switch ( r_type(sources) )
+ {
+ case t_file:
+ if ( must_buffer )
+ { /* Allocate a buffer for each row. */
+ uint size = gs_image_bytes_per_row(penum);
+ for ( px = 0; px < num_sources; ++px )
+ { byte *sbody = ialloc_string(size, "image_setup");
+ if ( sbody == 0 )
+ { esp -= inumpush;
+ image_cleanup(osp);
+ return_error(e_VMerror);
+ }
+ make_string(esp - (max_components + 2) + px,
+ icurrent_space, size, sbody);
+ }
+ push_op_estack(image_file_buffered_continue);
+ }
+ else
+ { push_op_estack(image_file_continue);
+ }
+ break;
+ case t_string:
+ pop(npop);
+ return image_string_process(osp, penum, num_sources);
+ default: /* procedure */
+ push_op_estack(image_proc_continue);
+ *++esp = sources[0];
+ break;
+ }
+ pop(npop);
+ return o_push_estack;
+}
+/* Continuation for procedure data source. */
+private int
+image_proc_continue(register os_ptr op)
+{ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ uint size, used;
+ int code;
+ int px;
+ const ref *pproc;
+
+ if ( !r_has_type_attrs(op, t_string, a_read) )
+ { check_op(1);
+ /* Procedure didn't return a (readable) string. Quit. */
+ esp -= inumpush;
+ image_cleanup(op);
+ return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
+ }
+ size = r_size(op);
+ if ( size == 0 )
+ code = 1;
+ else
+ code = gs_image_next(penum, op->value.bytes, size, &used);
+ if ( code )
+ { /* Stop now. */
+ esp -= inumpush;
+ pop(1); op = osp;
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ pop(1);
+ px = (int)++(esp[-2].value.intval);
+ pproc = esp - (inumpush - 2);
+ if ( px == max_components || r_has_type(pproc + px, t_null) )
+ esp[-2].value.intval = px = 0;
+ push_op_estack(image_proc_continue);
+ *++esp = pproc[px];
+ return o_push_estack;
+}
+/* Continue processing data from an image with file data sources */
+/* and no file buffering. */
+private int
+image_file_continue(os_ptr op)
+{ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ const ref *pproc = esp - (inumpush - 2);
+
+ for ( ; ; )
+ { uint size = max_uint;
+ int code;
+ int pn, px;
+ const ref *pp;
+
+ /*
+ * Do a first pass through the files to ensure that they all
+ * have data available in their buffers, and compute the min
+ * of the available amounts.
+ */
+
+ for ( pn = 0, pp = pproc;
+ pn < max_components && !r_has_type(pp, t_null);
+ ++pn, ++pp
+ )
+ { stream *s = pp->value.pfile;
+ int min_left = sbuf_min_left(s);
+ uint avail;
+
+ while ( (avail = sbufavailable(s)) <= min_left )
+ { int next = sgetc(s);
+
+ if ( next >= 0 )
+ { sputback(s);
+ if ( s->end_status == EOFC || s->end_status == ERRC )
+ min_left = 0;
+ continue;
+ }
+ switch ( next )
+ {
+ case EOFC:
+ break; /* with avail = 0 */
+ case INTC:
+ case CALLC:
+ return
+ s_handle_read_exception(next, pp,
+ NULL, 0, image_file_continue);
+ default:
+ /* case ERRC: */
+ return_error(e_ioerror);
+ }
+ break; /* for EOFC */
+ }
+ /* Note that in the EOF case, we can get here with */
+ /* avail < min_left. */
+ if ( avail >= min_left )
+ { avail -= min_left;
+ if ( avail < size )
+ size = avail;
+ }
+ else
+ size = 0;
+ }
+
+ /* Now pass the min of the available buffered data to */
+ /* the image processor. */
+
+ if ( size == 0 )
+ code = 1;
+ else
+ { int pi;
+ uint used; /* only set for the last plane */
+
+ for ( px = 0, pp = pproc, code = 0; px < pn && !code;
+ ++px, ++pp
+ )
+ code = gs_image_next(penum, sbufptr(pp->value.pfile),
+ size, &used);
+ /* Now that used has been set, update the streams. */
+ for ( pi = 0, pp = pproc; pi < px; ++pi, ++pp )
+ sbufskip(pp->value.pfile, used);
+ }
+ if ( code )
+ { esp -= inumpush;
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ }
+}
+/* Continue processing data from an image with file data sources */
+/* and file buffering. This is similar to the procedure case. */
+private int
+image_file_buffered_continue(os_ptr op)
+{ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ const ref *pproc = esp - (inumpush - 2);
+ int px = esp[-2].value.intval;
+ int dpos = esp[-1].value.intval;
+ uint size = gs_image_bytes_per_row(penum);
+ int code = 0;
+
+ while ( !code )
+ { const ref *pp;
+ uint avail = size;
+ uint used;
+ int pi;
+
+ /* Accumulate data until we have a full set of planes. */
+ while ( px < max_components &&
+ !r_has_type((pp = pproc + px), t_null)
+ )
+ { const ref *pb = pp + max_components;
+ uint used;
+ int status = sgets(pp->value.pfile, pb->value.bytes,
+ size - dpos, &used);
+
+ if ( (dpos += used) == size )
+ dpos = 0, ++px;
+ else switch ( status )
+ {
+ case EOFC:
+ if ( dpos < avail )
+ avail = dpos;
+ dpos = 0, ++px;
+ break;
+ case INTC:
+ case CALLC:
+ /* Call out to read from a procedure-based stream. */
+ esp[-2].value.intval = px;
+ esp[-1].value.intval = dpos;
+ return s_handle_read_exception(status, pp,
+ NULL, 0, image_file_buffered_continue);
+ default:
+ /*case ERRC:*/
+ return_error(e_ioerror);
+ }
+ }
+ /* Pass the data to the image processor. */
+ if ( avail == 0 )
+ { code = 1;
+ break;
+ }
+ for ( pi = 0, pp = pproc + max_components;
+ pi < px && !code;
+ ++pi, ++pp
+ )
+ code = gs_image_next(penum, pp->value.bytes, avail, &used);
+ /* Reinitialize for the next row. */
+ px = dpos = 0;
+ }
+ esp -= inumpush;
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+}
+/* Process data from an image with string data sources. */
+/* This never requires callbacks, so it's simpler. */
+private int
+image_string_process(os_ptr op, gs_image_enum *penum, int num_sources)
+{ int px = 0;
+
+ for ( ; ; )
+ { const ref *psrc = esp - (inumpush - 2) + px;
+ uint size = r_size(psrc);
+ uint used;
+ int code;
+
+ if ( size == 0 )
+ code = 1;
+ else
+ code = gs_image_next(penum, psrc->value.bytes, size, &used);
+ if ( code )
+ { /* Stop now. */
+ esp -= inumpush;
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ if ( ++px == num_sources )
+ px = 0;
+ }
+}
+/* Clean up after enumerating an image */
+private int
+image_cleanup(os_ptr op)
+{ gs_image_enum *penum = r_ptr(esp + inumpush, gs_image_enum);
+ const ref *pb;
+
+ /* Free any row buffers, in LIFO order as usual. */
+ for ( pb = esp + (max_components * 2 + 1);
+ pb >= esp + (max_components + 2);
+ --pb
+ )
+ if ( r_has_type(pb, t_string) )
+ gs_free_string(imemory, pb->value.bytes, r_size(pb),
+ "image_cleanup");
+ gs_image_cleanup(penum);
+ ifree_object(penum, "image_cleanup");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zimage_op_defs) {
+ {"5image", zimage},
+ {"5imagemask", zimagemask},
+ /* Internal operators */
+ {"1%image_proc_continue", image_proc_continue},
+ {"0%image_file_continue", image_file_continue},
+END_OP_DEFS(0) }
diff --git a/gs/src/zimage2.c b/gs/src/zimage2.c
new file mode 100644
index 000000000..4c65a5965
--- /dev/null
+++ b/gs/src/zimage2.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zimage2.c */
+/* image operator extensions for Level 2 PostScript */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gsmatrix.h"
+#include "gsimage.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iimage.h"
+#include "ilevel.h"
+#include "igstate.h" /* for igs */
+
+/* Define a structure for acquiring image parameters. */
+typedef struct image_params_s {
+ gs_image_t image;
+ bool MultipleDataSources;
+ ref DataSource[4];
+ const float *pDecode;
+} image_params;
+
+/* Common code for unpacking an image dictionary. */
+/* Assume *op is a dictionary. */
+private int
+image_dict_unpack(os_ptr op, image_params *pip, int max_bits_per_component)
+{ int code;
+ int num_components;
+ int decode_size;
+ ref *pds;
+
+ check_dict_read(*op);
+ num_components =
+ gs_color_space_num_components(gs_currentcolorspace(igs));
+ if ( num_components < 1 )
+ return_error(e_rangecheck); /* Pattern space not allowed */
+ if ( max_bits_per_component == 1 ) /* imagemask */
+ num_components = 1; /* for Decode */
+#define pim (&pip->image)
+ if ( (code = dict_int_param(op, "ImageType", 1, 1, 1,
+ &code)) < 0 ||
+ (code = dict_int_param(op, "Width", 0, 0x7fff, -1,
+ &pim->Width)) < 0 ||
+ (code = dict_int_param(op, "Height", 0, 0x7fff, -1,
+ &pim->Height)) < 0 ||
+ (code = dict_matrix_param(op, "ImageMatrix",
+ &pim->ImageMatrix)) < 0 ||
+ (code = dict_bool_param(op, "MultipleDataSources", false,
+ &pip->MultipleDataSources)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 0,
+ max_bits_per_component, -1,
+ &pim->BitsPerComponent)) < 0 ||
+ (code = decode_size = dict_float_array_param(op, "Decode",
+ num_components * 2,
+ &pim->Decode[0], NULL)) < 0 ||
+ (code = dict_bool_param(op, "Interpolate", false,
+ &pim->Interpolate)) < 0 ||
+ (code = dict_bool_param(op, "CombineWithColor", false,
+ &pim->CombineWithColor)) < 0
+ )
+ return code;
+ if ( decode_size != num_components * 2 )
+ return_error(e_rangecheck);
+ pip->pDecode = &pim->Decode[0];
+ /* Extract and check the data sources. */
+ if ( (code = dict_find_string(op, "DataSource", &pds)) < 0 )
+ return code;
+ if ( pip->MultipleDataSources )
+ { check_type_only(*pds, t_array);
+ if ( r_size(pds) != num_components )
+ return_error(e_rangecheck);
+ memcpy(&pip->DataSource[0], pds->value.refs, sizeof(ref) * num_components);
+ }
+ else
+ pip->DataSource[0] = *pds;
+#undef pim
+ return 0;
+}
+
+/* (<width> <height> <bits/sample> <matrix> <datasrc> image -) */
+/* <dict> image - */
+private int
+z2image(register os_ptr op)
+{ if ( level2_enabled )
+ { check_op(1);
+ if ( r_has_type(op, t_dictionary) )
+ { image_params ip;
+ int code;
+
+ gs_image_t_init_color(&ip.image);
+ code = image_dict_unpack(op, &ip, 12);
+ if ( code < 0 )
+ return code;
+ ip.image.ColorSpace = gs_currentcolorspace(igs);
+ return zimage_setup(&ip.image, ip.MultipleDataSources,
+ &ip.DataSource[0], 1);
+ }
+ }
+ /* Level 1 image operator */
+ check_op(5);
+ return zimage(op);
+}
+
+/* (<width> <height> <paint_1s> <matrix> <datasrc> imagemask -) */
+/* <dict> imagemask - */
+private int
+z2imagemask(register os_ptr op)
+{ if ( level2_enabled )
+ { check_op(1);
+ if ( r_has_type(op, t_dictionary) )
+ { image_params ip;
+ int code;
+
+ gs_image_t_init_mask(&ip.image, false);
+ code = image_dict_unpack(op, &ip, 1);
+ if ( code < 0 )
+ return code;
+ if ( ip.MultipleDataSources )
+ return_error(e_rangecheck);
+ return zimage_setup(&ip.image, false,
+ &ip.DataSource[0], 1);
+ }
+ }
+ /* Level 1 imagemask operator */
+ check_op(5);
+ return zimagemask(op);
+}
+
+/* ------ Initialization procedure ------ */
+
+/* Note that these override the definitions in zpaint.c. */
+BEGIN_OP_DEFS(zimage2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1image", z2image},
+ {"1imagemask", z2imagemask},
+END_OP_DEFS(0) }
diff --git a/gs/src/ziodev.c b/gs/src/ziodev.c
new file mode 100644
index 000000000..8b804de87
--- /dev/null
+++ b/gs/src/ziodev.c
@@ -0,0 +1,396 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ziodev.c */
+/* Standard IODevice implementation */
+#include "memory_.h"
+#include "stdio_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gsstruct.h" /* for registering root */
+#include "errors.h"
+#include "oper.h"
+#include "stream.h"
+#include "ialloc.h"
+#include "ivmspace.h"
+#include "gxiodev.h" /* must come after stream.h */
+ /* and before files.h */
+#include "files.h"
+#include "store.h"
+
+/* Complete the definition of the %os% device. */
+/* The open_file routine is exported for pipes and for %null. */
+int
+iodev_os_open_file(gx_io_device *iodev, const char *fname, uint len,
+ const char *file_access, stream **ps, gs_memory_t *mem)
+{ return file_open_stream(fname, len, file_access,
+ file_default_buffer_size, ps,
+ iodev->procs.fopen);
+}
+
+/* Define the special devices. */
+#define iodev_special(dname, init, open)\
+ { dname, "Special",\
+ { init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
+ iodev_no_enumerate_files, NULL, NULL,\
+ iodev_no_get_params, iodev_no_put_params\
+ }\
+ }
+
+#define stdin_buf_size 128
+private ref ref_stdin;
+bool gs_stdin_is_interactive; /* exported for command line only */
+private iodev_proc_init(stdin_init);
+private iodev_proc_open_device(stdin_open);
+gx_io_device gs_iodev_stdin =
+ iodev_special("%stdin%", stdin_init, stdin_open);
+
+#define stdout_buf_size 128
+private ref ref_stdout;
+private iodev_proc_init(stdout_init);
+private iodev_proc_open_device(stdout_open);
+gx_io_device gs_iodev_stdout =
+ iodev_special("%stdout%", stdout_init, stdout_open);
+
+#define stderr_buf_size 128
+private ref ref_stderr;
+private iodev_proc_init(stderr_init);
+private iodev_proc_open_device(stderr_open);
+gx_io_device gs_iodev_stderr =
+ iodev_special("%stderr%", stderr_init, stderr_open);
+
+#define lineedit_buf_size 20 /* initial size, not fixed size */
+private iodev_proc_open_device(lineedit_open);
+gx_io_device gs_iodev_lineedit =
+ iodev_special("%lineedit%", iodev_no_init, lineedit_open);
+
+private iodev_proc_open_device(statementedit_open);
+gx_io_device gs_iodev_statementedit =
+ iodev_special("%statementedit%", iodev_no_init, statementedit_open);
+
+/* ------ Operators ------ */
+
+/* <int> .getiodevice <string> */
+private int
+zgetiodevice(register os_ptr op)
+{ gx_io_device *iodev;
+ const byte *dname;
+ check_type(*op, t_integer);
+ if ( op->value.intval != (int)op->value.intval )
+ return_error(e_rangecheck);
+ iodev = gs_getiodevice((int)(op->value.intval));
+ if ( iodev == 0 ) /* index out of range */
+ return_error(e_rangecheck);
+ dname = (const byte *)iodev->dname;
+ make_const_string(op, a_readonly | avm_foreign,
+ strlen((const char *)dname), dname);
+ return 0;
+}
+
+/* ------- %stdin, %stdout, and %stderr ------ */
+
+/*
+ * According to Adobe, it is legal to close the %std... files and then
+ * re-open them later. However, the re-opened file object is not 'eq' to
+ * the original file object (in our implementation, it has a different
+ * read_id or write_id).
+ */
+
+private gs_gc_root_t stdin_root, stdout_root, stderr_root;
+
+private int
+ s_stdin_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+
+private int
+stdin_init(gx_io_device *iodev, gs_memory_t *mem)
+{ static ref *pstdin = &ref_stdin;
+ make_file(&ref_stdin, a_readonly | avm_system, 1, invalid_file_entry);
+ gs_stdin_is_interactive = true;
+ gs_register_ref_root(mem, &stdin_root,
+ (void **)&pstdin, "ref_stdin");
+ return 0;
+}
+
+/* Read from stdin into the buffer. */
+/* If interactive, only read one character. */
+private int
+s_stdin_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{ FILE *file = ((stream *)st)->file; /* hack for file streams */
+ int wcount = (int)(pw->limit - pw->ptr);
+ int count;
+
+ if ( wcount > 0 )
+ { if ( gs_stdin_is_interactive )
+ wcount = 1;
+ count = fread(pw->ptr + 1, 1, wcount, file);
+ if ( count < 0 )
+ count = 0;
+ pw->ptr += count;
+ }
+ else
+ count = 0; /* return 1 if no error/EOF */
+ process_interrupts();
+ return (ferror(file) ? ERRC : feof(file) ? EOFC : count == wcount ? 1 : 0);
+}
+
+int
+iodev_stdin_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ stream *s;
+ if ( !streq1(access, 'r') )
+ return_error(e_invalidfileaccess);
+ if ( !file_is_valid(s, &ref_stdin) )
+ {
+ /****** stdin SHOULD NOT LINE-BUFFER ******/
+
+ gs_memory_t *mem = imemory_system;
+ byte *buf;
+ s = file_alloc_stream(mem, "stdin_open(stream)");
+ /* We want stdin to read only one character at a time, */
+ /* but it must have a substantial buffer, in case it is used */
+ /* by a stream that requires more than one input byte */
+ /* to make progress. */
+ buf = gs_alloc_bytes(mem, stdin_buf_size,
+ "stdin_open(buffer)");
+ if ( s == 0 || buf == 0 )
+ return_error(e_VMerror);
+ sread_file(s, gs_stdin, buf, stdin_buf_size);
+ s->procs.process = s_stdin_read_process;
+ s->save_close = s_std_null;
+ s->procs.close = file_close_file;
+ make_file(&ref_stdin, a_readonly | avm_system,
+ s->read_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stdin_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdin_open(iodev, access, ps, mem);
+ return min(code, 0);
+}
+/* This is the public routine for getting the stdin stream. */
+int
+zget_stdin(stream **ps)
+{ stream *s;
+ if ( file_is_valid(s, &ref_stdin) )
+ { *ps = s;
+ return 0;
+ }
+ return (*gs_iodev_stdin.procs.open_device)(&gs_iodev_stdin,
+ "r", ps, imemory_system);
+}
+
+private int
+stdout_init(gx_io_device *iodev, gs_memory_t *mem)
+{ static ref *pstdout = &ref_stdout;
+ make_file(&ref_stdout, a_all | avm_system, 1, invalid_file_entry);
+ gs_register_ref_root(mem, &stdout_root,
+ (void **)&pstdout, "ref_stdout");
+ return 0;
+}
+
+int
+iodev_stdout_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ stream *s;
+ if ( !streq1(access, 'w') )
+ return_error(e_invalidfileaccess);
+ if ( !file_is_valid(s, &ref_stdout) )
+ { gs_memory_t *mem = imemory_system;
+ byte *buf;
+ s = file_alloc_stream(mem, "stdout_open(stream)");
+ buf = gs_alloc_bytes(mem, stdout_buf_size,
+ "stdout_open(buffer)");
+ if ( s == 0 || buf == 0 )
+ return_error(e_VMerror);
+ swrite_file(s, gs_stdout, buf, stdout_buf_size);
+ s->save_close = s->procs.flush;
+ s->procs.close = file_close_file;
+ make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stdout_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stdout_open(iodev, access, ps, mem);
+ return min(code, 0);
+}
+/* This is the public routine for getting the stdout stream. */
+int
+zget_stdout(stream **ps)
+{ stream *s;
+ if ( file_is_valid(s, &ref_stdout) )
+ { *ps = s;
+ return 0;
+ }
+ return (*gs_iodev_stdout.procs.open_device)(&gs_iodev_stdout,
+ "w", ps, imemory_system);
+}
+
+private int
+stderr_init(gx_io_device *iodev, gs_memory_t *mem)
+{ static ref *pstderr = &ref_stderr;
+ make_file(&ref_stderr, a_all | avm_system, 1, invalid_file_entry);
+ gs_register_ref_root(mem, &stderr_root,
+ (void **)&pstderr, "ref_stderr");
+ return 0;
+}
+
+int
+iodev_stderr_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ stream *s;
+ if ( !streq1(access, 'w') )
+ return_error(e_invalidfileaccess);
+ if ( !file_is_valid(s, &ref_stderr) )
+ { gs_memory_t *mem = imemory_system;
+ byte *buf;
+ s = file_alloc_stream(mem, "stderr_open(stream)");
+ buf = gs_alloc_bytes(mem, stderr_buf_size,
+ "stderr_open(buffer)");
+ if ( s == 0 || buf == 0 )
+ return_error(e_VMerror);
+ swrite_file(s, gs_stderr, buf, stderr_buf_size);
+ s->save_close = s->procs.flush;
+ s->procs.close = file_close_file;
+ make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stderr_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ int code = iodev_stderr_open(iodev, access, ps, mem);
+ return min(code, 0);
+}
+/* This is the public routine for getting the stderr stream. */
+int
+zget_stderr(stream **ps)
+{ stream *s;
+ if ( file_is_valid(s, &ref_stderr) )
+ { *ps = s;
+ return 0;
+ }
+ return (*gs_iodev_stderr.procs.open_device)(&gs_iodev_stderr,
+ "w", ps, imemory_system);
+}
+
+/* ------ %lineedit and %statementedit ------ */
+
+private int
+lineedit_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ uint count = 0;
+ bool in_eol = false;
+ int code;
+ stream *s;
+ stream *ins;
+ byte *buf;
+ uint buf_size = lineedit_buf_size;
+
+ if ( strcmp(access, "r") )
+ return_error(e_invalidfileaccess);
+ s = file_alloc_stream(mem, "lineedit_open(stream)");
+ if ( s == 0 )
+ return_error(e_VMerror);
+ code = (gs_iodev_stdin.procs.open_device)(&gs_iodev_stdin, access,
+ &ins, mem);
+ if ( code < 0 )
+ return code;
+ buf = gs_alloc_string(mem, buf_size, "lineedit_open(buffer)");
+ if ( buf == 0 )
+ return_error(e_VMerror);
+rd: code = zreadline_from(ins, buf, buf_size, &count, &in_eol);
+ switch ( code )
+ {
+ case EOFC:
+ code = gs_note_error(e_undefinedfilename);
+ /* falls through */
+ case 0:
+ break;
+ default:
+ code = gs_note_error(e_ioerror);
+ break;
+ case 1: /* filled buffer */
+ { uint nsize;
+ byte *nbuf;
+
+#if arch_ints_are_short
+ if ( nsize == max_uint )
+ { code = gs_note_error(e_limitcheck);
+ break;
+ }
+ else if ( nsize >= max_uint / 2 )
+ nsize = max_uint;
+ else
+#endif
+ nsize = buf_size * 2;
+ nbuf = gs_resize_string(mem, buf, buf_size, nsize,
+ "lineedit_open(grow buffer)");
+ if ( nbuf == 0 )
+ { code = gs_note_error(e_VMerror);
+ break;
+ }
+ buf = nbuf;
+ buf_size = nsize;
+ goto rd;
+ }
+ }
+ if ( code != 0 )
+ { gs_free_string(mem, buf, buf_size, "lineedit_open(buffer)");
+ return code;
+ }
+ buf = gs_resize_string(mem, buf, buf_size, count,
+ "lineedit_open(resize buffer)");
+ if ( buf == 0 )
+ return_error(e_VMerror);
+ sread_string(s, buf, count);
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_disable;
+ *ps = s;
+ return 0;
+}
+
+private int
+statementedit_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ /* NOT IMPLEMENTED PROPERLY YET */
+ return lineedit_open(iodev, access, ps, mem);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(ziodev_op_defs) {
+ {"1.getiodevice", zgetiodevice},
+END_OP_DEFS(0) }
diff --git a/gs/src/ziodev2.c b/gs/src/ziodev2.c
new file mode 100644
index 000000000..7819fe87b
--- /dev/null
+++ b/gs/src/ziodev2.c
@@ -0,0 +1,134 @@
+/* Copyright (C) 1993, 1994, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ziodev2.c */
+/* (Level 2) IODevice operators */
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "errors.h"
+#include "oper.h"
+#include "stream.h"
+#include "gxiodev.h"
+#include "files.h" /* for file_open_stream */
+#include "iparam.h"
+#include "iutil2.h"
+#include "store.h"
+
+/* ------ %null% ------ */
+
+/* This represents the null output file. */
+private iodev_proc_open_device(null_open);
+gx_io_device gs_iodev_null =
+ { "%null%", "FileSystem",
+ { iodev_no_init, null_open, iodev_no_open_file,
+ iodev_os_fopen, iodev_os_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ iodev_no_get_params, iodev_no_put_params
+ }
+ };
+
+private int
+null_open(gx_io_device *iodev, const char *access, stream **ps,
+ gs_memory_t *mem)
+{ if ( !streq1(access, 'w') )
+ return_error(e_invalidfileaccess);
+ return file_open_stream(gp_null_file_name,
+ strlen(gp_null_file_name),
+ access, 256 /* arbitrary */, ps,
+ iodev->procs.fopen);
+}
+
+/* ------ %ram% ------ */
+
+/* This is an IODevice with no interesting parameters for the moment. */
+gx_io_device gs_iodev_ram =
+ { "%ram%", "Special",
+ { iodev_no_init, iodev_no_open_device, iodev_no_open_file,
+ iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ iodev_no_get_params, iodev_no_put_params
+ }
+ };
+
+/* ------ Operators ------ */
+
+/* <iodevice> .getdevparams <mark> <name> <value> ... */
+private int
+zgetdevparams(os_ptr op)
+{
+ gx_io_device *iodev;
+ stack_param_list list;
+ int code;
+ ref *pmark;
+
+ check_read_type(*op, t_string);
+ iodev = gs_findiodevice(op->value.bytes, r_size(op));
+ if ( iodev == 0 )
+ return_error(e_undefinedfilename);
+ stack_param_list_write(&list, &o_stack, NULL);
+#define plist ((gs_param_list *)&list)
+
+ code = gs_getdevparams(iodev, plist);
+ if (code < 0)
+ { ref_stack_pop(&o_stack, list.count * 2);
+ return code;
+ }
+#undef plist
+ pmark = ref_stack_index(&o_stack, list.count * 2);
+ make_mark(pmark);
+ return 0;
+}
+
+/* <mark> <name> <value> ... <iodevice> .putdevparams */
+private int
+zputdevparams(os_ptr op)
+{ gx_io_device *iodev;
+ stack_param_list list;
+ int code;
+ check_read_type(*op, t_string);
+ iodev = gs_findiodevice(op->value.bytes, r_size(op));
+ if ( iodev == 0 )
+ return_error(e_undefinedfilename);
+ code = stack_param_list_read(&list, &o_stack, 1, NULL, false);
+ if ( code < 0 )
+ return code;
+#define plist ((gs_param_list *)&list)
+ code = param_check_password(plist, &SystemParamsPassword);
+ if ( code != 0 )
+ { iparam_list_release(&list);
+ return_error(code < 0 ? code : e_invalidaccess);
+ }
+ code = gs_putdevparams(iodev, plist);
+ iparam_list_release(&list);
+ if ( code < 0 )
+ return code;
+#undef plist
+ ref_stack_pop(&o_stack, list.count * 2 + 2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(ziodev2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"1.getdevparams", zgetdevparams},
+ {"2.putdevparams", zputdevparams},
+END_OP_DEFS(0) }
diff --git a/gs/src/zlib.mak b/gs/src/zlib.mak
new file mode 100644
index 000000000..6f830e317
--- /dev/null
+++ b/gs/src/zlib.mak
@@ -0,0 +1,162 @@
+# Copyright (C) 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# makefile for zlib library code.
+
+# This partial makefile compiles the zlib library for use in Ghostscript.
+# You can get the source code for this library from:
+# ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib104.zip (zlib 1.0.4)
+# or zlib-1.0.4.tar.gz
+# Please see Ghostscript's `make.txt' file for instructions about how to
+# unpack these archives.
+
+# Define the name of this makefile.
+ZLIB_MAK=zlib.mak
+
+# ZSRCDIR is defined in the platform-specific makefile, not here,
+# as the directory where the zlib sources are stored.
+#ZSRCDIR=zlib
+ZSRC=$(ZSRCDIR)$(D)
+# We would like to define
+#CCCZ=$(CCC) -I$(ZSRCDIR) -Dverbose=-1
+# but the Watcom C compiler has strange undocumented restrictions on what can
+# follow a -D=, and it doesn't allow negative numbers. Instead, we define
+# (in gs.mak):
+#CCCZ=$(CCC) -I. -I$(ZSRCDIR)
+# and handle the definition of verbose in a different, more awkward way.
+
+# We keep all of the zlib code in a separate directory so as not to
+# inadvertently mix it up with Aladdin Enterprises' own code.
+ZDEP=$(AK)
+
+# Contrary to what some portability bigots assert as fact, C compilers are
+# not consistent about where they start searching for #included files:
+# some always start by looking in the same directory as the .c file being
+# compiled, before using the search path specified with -I on the command
+# line, while others do not do this. For this reason, we must explicitly
+# copy and then delete all the .c files, because they need to obtain our
+# modified version of zutil.h. We must also copy all header files that
+# reference zutil.h directly or indirectly.
+
+# Code common to compression and decompression.
+
+zlibc_=zutil.$(OBJ)
+zlibc.dev: $(ZLIB_MAK) $(ECHOGS_XE) $(zlibc_)
+ $(SETMOD) zlibc $(zlibc_)
+
+zutil.h: $(ZSRC)zutil.h $(ECHOGS_XE)
+ $(EXP)echogs -w zutil.h -x 23 define verbose -s - -1
+ $(EXP)echogs -a zutil.h -+R $(ZSRC)zutil.h
+
+zutil.$(OBJ): $(ZSRC)zutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)zutil.c .
+ $(CCCZ) zutil.c
+ $(RM_) zutil.c
+
+# Encoding (compression) code.
+
+deflate.h: $(ZSRC)deflate.h zutil.h
+ $(CP_) $(ZSRC)deflate.h .
+
+zlibe.dev: $(MAKEFILE) zlibe_$(SHARE_ZLIB).dev
+ $(CP_) zlibe_$(SHARE_ZLIB).dev zlibe.dev
+
+zlibe_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibe_1 -lib $(ZLIB_NAME)
+
+zlibe_=adler32.$(OBJ) deflate.$(OBJ) trees.$(OBJ)
+zlibe_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibe_)
+ $(SETMOD) zlibe_0 $(zlibe_)
+ $(ADDMOD) zlibe_0 -include zlibc
+
+adler32.$(OBJ): $(ZSRC)adler32.c $(ZDEP)
+ $(CP_) $(ZSRC)adler32.c .
+ $(CCCZ) adler32.c
+ $(RM_) adler32.c
+
+deflate.$(OBJ): $(ZSRC)deflate.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)deflate.c .
+ $(CCCZ) deflate.c
+ $(RM_) deflate.c
+
+trees.$(OBJ): $(ZSRC)trees.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)trees.c .
+ $(CCCZ) trees.c
+ $(RM_) trees.c
+
+# The zlib filters per se don't need crc32, but libpng versions starting
+# with 0.90 do.
+
+crc32.dev: $(MAKEFILE) crc32_$(SHARE_ZLIB).dev
+ $(CP_) crc32_$(SHARE_ZLIB).dev crc32.dev
+
+crc32_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) crc32_1 -lib $(ZLIB_NAME)
+
+crc32_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) crc32.$(OBJ)
+ $(SETMOD) crc32_0 crc32.$(OBJ)
+
+crc32.$(OBJ): $(ZSRC)crc32.c $(ZDEP) deflate.h
+ $(CP_) $(ZSRC)crc32.c .
+ $(CCCZ) crc32.c
+ $(RM_) crc32.c
+
+# Decoding (decompression) code.
+
+zlibd.dev: $(MAKEFILE) zlibd_$(SHARE_ZLIB).dev
+ $(CP_) zlibd_$(SHARE_ZLIB).dev zlibd.dev
+
+zlibd_1.dev: $(MAKEFILE) $(ZLIB_MAK) $(ECHOGS_XE)
+ $(SETMOD) zlibd_1 -lib $(ZLIB_NAME)
+
+zlibd1_=infblock.$(OBJ) infcodes.$(OBJ) inffast.$(OBJ)
+zlibd2_=inflate.$(OBJ) inftrees.$(OBJ) infutil.$(OBJ)
+zlibd_ = $(zlibd1_) $(zlibd2_)
+zlibd_0.dev: $(ZLIB_MAK) $(ECHOGS_XE) zlibc.dev $(zlibd_)
+ $(SETMOD) zlibd_0 $(zlibd1_)
+ $(ADDMOD) zlibd_0 -obj $(zlibd2_)
+ $(ADDMOD) zlibd_0 -include zlibc
+
+infblock.$(OBJ): $(ZSRC)infblock.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infblock.c .
+ $(CCCZ) infblock.c
+ $(RM_) infblock.c
+
+infcodes.$(OBJ): $(ZSRC)infcodes.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infcodes.c .
+ $(CCCZ) infcodes.c
+ $(RM_) infcodes.c
+
+inffast.$(OBJ): $(ZSRC)inffast.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inffast.c .
+ $(CCCZ) inffast.c
+ $(RM_) inffast.c
+
+inflate.$(OBJ): $(ZSRC)inflate.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inflate.c .
+ $(CCCZ) inflate.c
+ $(RM_) inflate.c
+
+inftrees.$(OBJ): $(ZSRC)inftrees.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)inftrees.c .
+ $(CCCZ) inftrees.c
+ $(RM_) inftrees.c
+
+infutil.$(OBJ): $(ZSRC)infutil.c $(ZDEP) zutil.h
+ $(CP_) $(ZSRC)infutil.c .
+ $(CCCZ) infutil.c
+ $(RM_) infutil.c
diff --git a/gs/src/zmath.c b/gs/src/zmath.c
new file mode 100644
index 000000000..de33ea909
--- /dev/null
+++ b/gs/src/zmath.c
@@ -0,0 +1,260 @@
+/* Copyright (C) 1989, 1992, 1993, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmath.c */
+/* Mathematical operators */
+#include "math_.h"
+#include "ghost.h"
+#include "gxfarith.h"
+#include "errors.h"
+#include "oper.h"
+#include "store.h"
+
+/*
+ * Define the current state of random number generator. We have to
+ * implement this ourselves because the Unix rand doesn't provide anything
+ * equivalent to rrand. Note that the value always lies in the range
+ * [0..0x7ffffffe], even if longs are longer than 32 bits.
+ *
+ * The state must be public so that context switching can save and
+ * restore it. (Even though the Red Book doesn't mention this,
+ * we verified with Adobe that this is the case.)
+ */
+long zrand_state;
+
+/* Initialize the random number generator. */
+void
+zrand_state_init(long *pstate)
+{ *pstate = 1;
+}
+private void
+zmath_init(void)
+{ zrand_state_init(&zrand_state);
+}
+
+/****** NOTE: none of these operators currently ******/
+/****** check for floating over- or underflow. ******/
+
+/* <num> sqrt <real> */
+private int
+zsqrt(register os_ptr op)
+{ double num;
+ int code = real_param(op, &num);
+
+ if ( code < 0 )
+ return code;
+ if ( num < 0.0 )
+ return_error(e_rangecheck);
+ make_real(op, sqrt(num));
+ return 0;
+}
+
+/* <num> arccos <real> */
+private int
+zarccos(register os_ptr op)
+{ double num, result;
+ int code = real_param(op, &num);
+
+ if ( code < 0 )
+ return code;
+ result = acos(num) * radians_to_degrees;
+ make_real(op, result);
+ return 0;
+}
+
+/* <num> arcsin <real> */
+private int
+zarcsin(register os_ptr op)
+{ double num, result;
+ int code = real_param(op, &num);
+
+ if ( code < 0 )
+ return code;
+ result = asin(num) * radians_to_degrees;
+ make_real(op, result);
+ return 0;
+}
+
+/* <num> <denom> atan <real> */
+private int
+zatan(register os_ptr op)
+{ double args[2];
+ double result;
+ int code = num_params(op, 2, args);
+
+ if ( code < 0 ) return code;
+ if ( args[0] == 0 ) /* on X-axis, special case */
+ { if ( args[1] == 0 )
+ return_error(e_undefinedresult);
+ result = (args[1] < 0 ? 180 : 0);
+ }
+ else
+ { result = atan2(args[0], args[1]) * radians_to_degrees;
+ if ( result < 0 )
+ result += 360;
+ }
+ make_real(op - 1, result);
+ pop(1);
+ return 0;
+}
+
+/* <num> cos <real> */
+private int
+zcos(register os_ptr op)
+{ double angle;
+ int code = real_param(op, &angle);
+
+ if ( code < 0 )
+ return code;
+ make_real(op, gs_cos_degrees(angle));
+ return 0;
+}
+
+/* <num> sin <real> */
+private int
+zsin(register os_ptr op)
+{ double angle;
+ int code = real_param(op, &angle);
+
+ if ( code < 0 )
+ return code;
+ make_real(op, gs_sin_degrees(angle));
+ return 0;
+}
+
+/* <base> <exponent> exp <real> */
+private int
+zexp(register os_ptr op)
+{ double args[2];
+ double result;
+ double ipart;
+ int code = num_params(op, 2, args);
+
+ if ( code < 0 ) return code;
+ if ( args[0] == 0.0 && args[1] == 0.0 )
+ return_error(e_undefinedresult);
+ if ( args[0] < 0.0 && modf(args[1], &ipart) != 0.0 )
+ return_error(e_undefinedresult);
+ result = pow(args[0], args[1]);
+ make_real(op - 1, result);
+ pop(1);
+ return 0;
+}
+
+/* <posnum> ln <real> */
+private int
+zln(register os_ptr op)
+{ double num;
+ int code = real_param(op, &num);
+
+ if ( code < 0 )
+ return code;
+ if ( num <= 0.0 )
+ return_error(e_rangecheck);
+ make_real(op, log(num));
+ return 0;
+}
+
+/* <posnum> log <real> */
+private int
+zlog(register os_ptr op)
+{ double num;
+ int code = real_param(op, &num);
+
+ if ( code < 0 )
+ return code;
+ if ( num <= 0.0 )
+ return_error(e_rangecheck);
+ make_real(op, log10(num));
+ return 0;
+}
+
+/* - rand <int> */
+private int
+zrand(register os_ptr op)
+{ /*
+ * We use an algorithm from CACM 31 no. 10, pp. 1192-1201,
+ * October 1988. According to a posting by Ed Taft on
+ * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters
+ * use this algorithm too:
+ * x[n+1] = (16807 * x[n]) mod (2^31 - 1)
+ */
+#define A 16807
+#define M 0x7fffffff
+#define Q 127773 /* M / A */
+#define R 2836 /* M % A */
+ zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q);
+ /* Note that zrand_state cannot be 0 here. */
+ if ( zrand_state <= 0 )
+ zrand_state += M;
+#undef A
+#undef M
+#undef Q
+#undef R
+ push(1);
+ make_int(op, zrand_state);
+ return 0;
+}
+
+/* <int> srand - */
+private int
+zsrand(register os_ptr op)
+{ long state;
+ check_type(*op, t_integer);
+ state = op->value.intval;
+#if arch_sizeof_long > 4
+ /* Trim the state back to 32 bits. */
+ state = (int)state;
+#endif
+ /*
+ * The following somewhat bizarre adjustments are according to
+ * public information from Adobe describing their implementation.
+ */
+ if ( state < 1 )
+ state = -(state % 0x7ffffffe) + 1;
+ else if ( state > 0x7ffffffe )
+ state = 0x7ffffffe;
+ zrand_state = state;
+ pop(1);
+ return 0;
+}
+
+/* - rrand <int> */
+private int
+zrrand(register os_ptr op)
+{ push(1);
+ make_int(op, zrand_state);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zmath_op_defs) {
+ {"1arccos", zarccos}, /* extension */
+ {"1arcsin", zarcsin}, /* extension */
+ {"2atan", zatan},
+ {"1cos", zcos},
+ {"2exp", zexp},
+ {"1ln", zln},
+ {"1log", zlog},
+ {"0rand", zrand},
+ {"0rrand", zrrand},
+ {"1sin", zsin},
+ {"1sqrt", zsqrt},
+ {"1srand", zsrand},
+END_OP_DEFS(zmath_init) }
diff --git a/gs/src/zmatrix.c b/gs/src/zmatrix.c
new file mode 100644
index 000000000..eafdabbb3
--- /dev/null
+++ b/gs/src/zmatrix.c
@@ -0,0 +1,326 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmatrix.c */
+/* Matrix operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gscoord.h"
+#include "store.h"
+
+/* Forward references */
+private int near common_transform(P3(os_ptr,
+ int (*)(P4(gs_state *, floatp, floatp, gs_point *)),
+ int (*)(P4(floatp, floatp, const gs_matrix *, gs_point *))));
+
+/* - initmatrix - */
+private int
+zinitmatrix(os_ptr op)
+{ return gs_initmatrix(igs);
+}
+
+/* <matrix> defaultmatrix <matrix> */
+private int
+zdefaultmatrix(register os_ptr op)
+{ gs_matrix mat;
+ gs_defaultmatrix(igs, &mat);
+ return write_matrix(op, &mat);
+}
+
+/* <matrix> currentmatrix <matrix> */
+private int
+zcurrentmatrix(register os_ptr op)
+{ gs_matrix mat;
+ gs_currentmatrix(igs, &mat);
+ return write_matrix(op, &mat);
+}
+
+/* <matrix> setmatrix - */
+private int
+zsetmatrix(register os_ptr op)
+{ gs_matrix mat;
+ int code = read_matrix(op, &mat);
+ if ( code < 0 )
+ return code;
+ if ( (code = gs_setmatrix(igs, &mat)) < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <matrix|null> .setdefaultmatrix - */
+private int
+zsetdefaultmatrix(register os_ptr op)
+{ int code;
+ if ( r_has_type(op, t_null) )
+ code = gs_setdefaultmatrix(igs, NULL);
+ else
+ { gs_matrix mat;
+ code = read_matrix(op, &mat);
+ if ( code < 0 )
+ return code;
+ code = gs_setdefaultmatrix(igs, &mat);
+ }
+ if ( code < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <tx> <ty> translate - */
+/* <tx> <ty> <matrix> translate <matrix> */
+private int
+ztranslate(register os_ptr op)
+{ int code;
+ double trans[2];
+
+ if ( (code = num_params(op, 2, trans)) >= 0 )
+ { code = gs_translate(igs, trans[0], trans[1]);
+ if ( code < 0 )
+ return code;
+ }
+ else /* matrix operand */
+ { gs_matrix mat;
+ /* The num_params failure might be a stack underflow. */
+ check_op(2);
+ if ( (code = num_params(op - 1, 2, trans)) < 0 ||
+ (code = gs_make_translation(trans[0], trans[1], &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ )
+ { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op[-2] = *op;
+ }
+ pop(2);
+ return code;
+}
+
+/* <sx> <sy> scale - */
+/* <sx> <sy> <matrix> scale <matrix> */
+private int
+zscale(register os_ptr op)
+{ int code;
+ double scale[2];
+
+ if ( (code = num_params(op, 2, scale)) >= 0 )
+ { code = gs_scale(igs, scale[0], scale[1]);
+ if ( code < 0 )
+ return code;
+ }
+ else /* matrix operand */
+ { gs_matrix mat;
+ /* The num_params failure might be a stack underflow. */
+ check_op(2);
+ if ( (code = num_params(op - 1, 2, scale)) < 0 ||
+ (code = gs_make_scaling(scale[0], scale[1], &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ )
+ { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op[-2] = *op;
+ }
+ pop(2);
+ return code;
+}
+
+/* <angle> rotate - */
+/* <angle> <matrix> rotate <matrix> */
+private int
+zrotate(register os_ptr op)
+{ int code;
+ double ang;
+
+ if ( (code = real_param(op, &ang)) >= 0 )
+ { code = gs_rotate(igs, ang);
+ if ( code < 0 )
+ return code;
+ }
+ else /* matrix operand */
+ { gs_matrix mat;
+ /* The num_params failure might be a stack underflow. */
+ check_op(1);
+ if ( (code = num_params(op - 1, 1, &ang)) < 0 ||
+ (code = gs_make_rotation(ang, &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ )
+ { /* Might be a stack underflow. */
+ check_op(2);
+ return code;
+ }
+ op[-1] = *op;
+ }
+ pop(1);
+ return code;
+}
+
+/* <matrix> concat - */
+private int
+zconcat(register os_ptr op)
+{ gs_matrix mat;
+ int code = read_matrix(op, &mat);
+ if ( code < 0 ) return code;
+ code = gs_concat(igs, &mat);
+ if ( code < 0 ) return code;
+ pop(1);
+ return 0;
+}
+
+/* <matrix1> <matrix2> <matrix> concatmatrix <matrix> */
+private int
+zconcatmatrix(register os_ptr op)
+{ gs_matrix m1, m2, mp;
+ int code;
+ if ( (code = read_matrix(op - 2, &m1)) < 0 ||
+ (code = read_matrix(op - 1, &m2)) < 0 ||
+ (code = gs_matrix_multiply(&m1, &m2, &mp)) < 0 ||
+ (code = write_matrix(op, &mp)) < 0
+ )
+ return code;
+ op[-2] = *op;
+ pop(2);
+ return code;
+}
+
+/* <x> <y> transform <xt> <yt> */
+/* <x> <y> <matrix> transform <xt> <yt> */
+private int
+ztransform(register os_ptr op)
+{ return common_transform(op, gs_transform, gs_point_transform);
+}
+
+/* <dx> <dy> dtransform <dxt> <dyt> */
+/* <dx> <dy> <matrix> dtransform <dxt> <dyt> */
+private int
+zdtransform(register os_ptr op)
+{ return common_transform(op, gs_dtransform, gs_distance_transform);
+}
+
+/* <xt> <yt> itransform <x> <y> */
+/* <xt> <yt> <matrix> itransform <x> <y> */
+private int
+zitransform(register os_ptr op)
+{ return common_transform(op, gs_itransform, gs_point_transform_inverse);
+}
+
+/* <dxt> <dyt> idtransform <dx> <dy> */
+/* <dxt> <dyt> <matrix> idtransform <dx> <dy> */
+private int
+zidtransform(register os_ptr op)
+{ return common_transform(op, gs_idtransform, gs_distance_transform_inverse);
+}
+
+/* Common logic for [i][d]transform */
+private int near
+common_transform(register os_ptr op,
+ int (*ptproc)(P4(gs_state *, floatp, floatp, gs_point *)),
+ int (*matproc)(P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{ double opxy[2];
+ gs_point pt;
+ int code;
+
+ /* Optimize for the non-matrix case */
+ switch ( r_type(op) )
+ {
+ case t_real:
+ opxy[1] = op->value.realval;
+ break;
+ case t_integer:
+ opxy[1] = op->value.intval;
+ break;
+ case t_array: /* might be a matrix */
+ case t_shortarray:
+ case t_mixedarray:
+ { gs_matrix mat;
+ gs_matrix *pmat = &mat;
+
+ if ( (code = read_matrix(op, pmat)) < 0 ||
+ (code = num_params(op - 1, 2, opxy)) < 0 ||
+ (code = (*matproc)(opxy[0], opxy[1], pmat, &pt)) < 0
+ )
+ { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op--;
+ pop(1);
+ goto out;
+ }
+ default:
+ return_op_typecheck(op);
+ }
+ switch ( r_type(op - 1) )
+ {
+ case t_real:
+ opxy[0] = (op - 1)->value.realval;
+ break;
+ case t_integer:
+ opxy[0] = (op - 1)->value.intval;
+ break;
+ default:
+ return_op_typecheck(op - 1);
+ }
+ if ( (code = (*ptproc)(igs, opxy[0], opxy[1], &pt)) < 0 )
+ return code;
+out: make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ return 0;
+}
+
+/* <matrix> <inv_matrix> invertmatrix <inv_matrix> */
+private int
+zinvertmatrix(register os_ptr op)
+{ gs_matrix m;
+ int code;
+
+ if ( (code = read_matrix(op - 1, &m)) < 0 ||
+ (code = gs_matrix_invert(&m, &m)) < 0 ||
+ (code = write_matrix(op, &m)) < 0
+ )
+ return code;
+ op[-1] = *op;
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zmatrix_op_defs) {
+ {"1concat", zconcat},
+ {"2dtransform", zdtransform},
+ {"3concatmatrix", zconcatmatrix},
+ {"1currentmatrix", zcurrentmatrix},
+ {"1defaultmatrix", zdefaultmatrix},
+ {"2idtransform", zidtransform},
+ {"0initmatrix", zinitmatrix},
+ {"2invertmatrix", zinvertmatrix},
+ {"2itransform", zitransform},
+ {"1rotate", zrotate},
+ {"2scale", zscale},
+ {"1setmatrix", zsetmatrix},
+ {"1.setdefaultmatrix", zsetdefaultmatrix},
+ {"2transform", ztransform},
+ {"2translate", ztranslate},
+END_OP_DEFS(0) }
+
diff --git a/gs/src/zmedia2.c b/gs/src/zmedia2.c
new file mode 100644
index 000000000..708066427
--- /dev/null
+++ b/gs/src/zmedia2.c
@@ -0,0 +1,444 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmedia.c */
+/* Media matching for setpagedevice */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "gsmatrix.h"
+#include "errors.h"
+#include "oper.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iname.h"
+#include "store.h"
+
+/* <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true */
+/* <pagedict> <attrdict> <policydict> <keys> .matchmedia false */
+/* <pagedict> null <policydict> <keys> .matchmedia null true */
+private int zmatch_page_size(P8(const ref *pvreq, const ref *pvmed,
+ int policy, int orient, bool roll, float *best_mismatch, gs_matrix *pmat,
+ gs_point *pmsize));
+private int
+zmatchmedia(register os_ptr op)
+{ os_ptr preq = op - 3;
+ os_ptr pattr = op - 2;
+ os_ptr ppol = op - 1;
+#define pkeys op
+ int policy_default;
+ float best_mismatch = (float)max_long; /* adhoc */
+ ref mmkey, nmkey;
+ float mbest = best_mismatch;
+ uint matched_priority;
+ ref no_priority;
+ ref *ppriority;
+ int mepos, orient;
+ bool roll;
+ int code;
+ int ai;
+ ref aelt[2];
+#define mkey aelt[0]
+#define mdict aelt[1]
+
+ if ( r_has_type(pattr, t_null) )
+ { check_op(4);
+ make_null(op - 3);
+ make_true(op - 2);
+ pop(2);
+ return 0;
+ }
+ check_type(*preq, t_dictionary);
+ check_dict_read(*preq);
+ check_type(*pattr, t_dictionary);
+ check_dict_read(*pattr);
+ check_type(*ppol, t_dictionary);
+ check_dict_read(*ppol);
+ check_array(*pkeys);
+ check_read(*pkeys);
+ switch ( code = dict_int_null_param(preq, "MediaPosition", 0, 0x7fff,
+ 0, &mepos) )
+ {
+ default: return code;
+ case 2:
+ case 1: mepos = -1;
+ case 0: ;
+ }
+ switch ( code = dict_int_null_param(preq, "Orientation", 0, 3,
+ 0, &orient) )
+ {
+ default: return code;
+ case 2:
+ case 1: orient = -1;
+ case 0: ;
+ }
+ code = dict_bool_param(preq, "RollFedMedia", false, &roll);
+ if ( code < 0 )
+ return code;
+ code = dict_int_param(ppol, "PolicyNotFound", 0, 7, 0,
+ &policy_default);
+ if ( code < 0 )
+ return code;
+ if ( dict_find_string(pattr, "Priority", &ppriority) > 0 )
+ { check_array_only(*ppriority);
+ check_read(*ppriority);
+ }
+ else
+ { make_empty_array(&no_priority, a_readonly);
+ ppriority = &no_priority;
+ }
+#define reset_match()\
+ matched_priority = r_size(ppriority),\
+ make_null(&mmkey),\
+ make_null(&nmkey)
+ reset_match();
+ for ( ai = dict_first(pattr); (ai = dict_next(pattr, ai, aelt)) >= 0; )
+ { if ( r_has_type(&mdict, t_dictionary) &&
+ r_has_attr(dict_access_ref(&mdict), a_read) &&
+ r_has_type(&mkey, t_integer) &&
+ (mepos < 0 || mkey.value.intval == mepos)
+ )
+ { bool match_all;
+ uint ki, pi;
+
+ code = dict_bool_param(&mdict, "MatchAll", false,
+ &match_all);
+ if ( code < 0 )
+ return code;
+ for ( ki = 0; ki < r_size(pkeys); ki++ )
+ { ref key;
+ ref kstr;
+ ref *prvalue;
+ ref *pmvalue;
+ ref *ppvalue;
+ int policy;
+
+ array_get(pkeys, ki, &key);
+ if ( dict_find(&mdict, &key, &pmvalue) <= 0 )
+ continue;
+ if ( dict_find(preq, &key, &prvalue) <= 0 ||
+ r_has_type(prvalue, t_null)
+ )
+ { if ( match_all )
+ goto no;
+ else
+ continue;
+ }
+ /* Look for the Policies entry for this key. */
+ if ( dict_find(ppol, &key, &ppvalue) > 0 )
+ { check_type_only(*ppvalue, t_integer);
+ policy = ppvalue->value.intval;
+ }
+ else
+ policy = policy_default;
+ /*
+ * Match a requested attribute value with the attribute value in the
+ * description of a medium. For all attributes except PageSize,
+ * matching means equality. PageSize is special; see match_page_size
+ * below.
+ */
+ if ( r_has_type(&key, t_name) &&
+ (name_string_ref(&key, &kstr),
+ r_size(&kstr) == 8 &&
+ !memcmp(kstr.value.bytes, "PageSize", 8))
+ )
+ { gs_matrix ignore_mat;
+ gs_point ignore_msize;
+ if ( zmatch_page_size(prvalue, pmvalue,
+ policy, orient, roll,
+ &best_mismatch,
+ &ignore_mat,
+ &ignore_msize)
+ <= 0 )
+ goto no;
+ }
+ else
+ if ( !obj_eq(prvalue, pmvalue) )
+ goto no;
+ }
+ /* We have a match. If it is a better match */
+ /* than the current best one, it supersedes it */
+ /* regardless of priority. */
+ if ( best_mismatch < mbest )
+ { mbest = best_mismatch;
+ reset_match();
+ }
+ /* In case of a tie, see if the new match has */
+ /* priority. */
+ for ( pi = matched_priority; pi > 0; )
+ { ref pri;
+ pi--;
+ array_get(ppriority, pi, &pri);
+ if ( obj_eq(&mkey, &pri) )
+ { /* Yes, higher priority. */
+ mmkey = mkey;
+ matched_priority = pi;
+ break;
+ }
+ }
+ /* Save the match in case no match has priority. */
+ nmkey = mkey;
+no: ;
+ }
+ }
+#undef mkey
+#undef mdict
+#undef pkeys
+ if ( r_has_type(&nmkey, t_null) )
+ { make_false(op - 3);
+ pop(3);
+ }
+ else
+ { if ( r_has_type(&mmkey, t_null) )
+ op[-3] = nmkey;
+ else
+ op[-3] = mmkey;
+ make_true(op - 2);
+ pop(2);
+ }
+ return 0;
+}
+
+/* [<req_x> <req_y>] [<med_x0> <med_y0> (<med_x1> <med_y1> | )]
+ * <policy> <orient|null> <roll> <matrix|null> .matchpagesize
+ * <matrix|null> <med_x> <med_y> true -or- false
+ */
+private int
+zmatchpagesize(register os_ptr op)
+{ gs_matrix mat;
+ float ignore_mismatch = (float)max_long;
+ gs_point media_size;
+ int orient;
+ bool roll;
+ int code;
+
+ check_type(op[-3], t_integer);
+ if ( r_has_type(op - 2, t_null) )
+ orient = -1;
+ else
+ { check_int_leu(op[-2], 3);
+ orient = (int)op[-2].value.intval;
+ }
+ check_type(op[-1], t_boolean);
+ roll = op[-1].value.boolval;
+ code = zmatch_page_size(op - 5, op - 4, (int)op[-3].value.intval,
+ orient, roll,
+ &ignore_mismatch, &mat, &media_size);
+ switch ( code )
+ {
+ default:
+ return code;
+ case 0:
+ make_false(op - 5);
+ pop(5);
+ break;
+ case 1:
+ code = write_matrix(op, &mat);
+ if ( code < 0 && !r_has_type(op, t_null) )
+ return code;
+ op[-5] = *op;
+ make_real(op - 4, media_size.x);
+ make_real(op - 3, media_size.y);
+ make_true(op - 2);
+ pop(2);
+ break;
+ }
+ return 0;
+}
+/* Match the PageSize. See below for details. */
+private bool match_page_size(P8(const gs_point *request,
+ const gs_rect *medium, int policy, int orient, bool roll,
+ float *best_mismatch, gs_matrix *pmat, gs_point *pmsize));
+private int
+zmatch_page_size(const ref *pvreq, const ref *pvmed, int policy, int orient,
+ bool roll, float *best_mismatch, gs_matrix *pmat, gs_point *pmsize)
+{ uint nm;
+ check_array(*pvreq);
+ check_array(*pvmed);
+ if ( !(r_size(pvreq) == 2 && ((nm = r_size(pvmed)) == 2 || nm == 4)) )
+ return_error(e_rangecheck);
+ { ref rv[6];
+ uint i;
+ double v[6];
+ int code;
+
+ array_get(pvreq, 0, &rv[0]);
+ array_get(pvreq, 1, &rv[1]);
+ for ( i = 0; i < 4; ++i )
+ array_get(pvmed, i % nm, &rv[i + 2]);
+ if ( (code = num_params(rv + 5, 6, v)) < 0 )
+ return code;
+ { gs_point request;
+ gs_rect medium;
+
+ request.x = v[0], request.y = v[1];
+ medium.p.x = v[2], medium.p.y = v[3],
+ medium.q.x = v[4], medium.q.y = v[5];
+ return match_page_size(&request, &medium, policy, orient,
+ roll, best_mismatch, pmat, pmsize);
+ }
+ }
+}
+/*
+ * Match a requested PageSize with the PageSize of a medium. The medium
+ * may specify either a single value [mx my] or a range
+ * [mxmin mymin mxmax mymax]; matching means equality or inclusion
+ * to within a tolerance of 5, possibly swapping the requested X and Y.
+ * Take the Policies value into account, keeping track of the discrepancy
+ * if needed. When a match is found, also return the matrix to be
+ * concatenated after setting up the default matrix, and the actual
+ * media size.
+ *
+ * NOTE: The algorithm here doesn't work properly for variable-size media
+ * when the match isn't exact. We'll fix it if we ever need to.
+ */
+private void make_adjustment_matrix(P5(const gs_point *request,
+ const gs_rect *medium, gs_matrix *pmat, bool scale, int rotate));
+private bool
+match_page_size(const gs_point *request, const gs_rect *medium, int policy,
+ int orient, bool roll, float *best_mismatch, gs_matrix *pmat,
+ gs_point *pmsize)
+{ double rx = request->x, ry = request->y;
+
+ if ( policy == 7 )
+ { /* (Adobe) hack: just impose requested values */
+ *best_mismatch = 0;
+ gs_make_identity(pmat);
+ *pmsize = *request;
+ return true;
+ }
+ if ( rx - medium->p.x >= -5 && rx - medium->q.x <= 5 &&
+ ry - medium->p.y >= -5 && ry - medium->q.y <= 5 &&
+ (orient < 0 || !(orient & 1))
+ )
+ { *best_mismatch = 0;
+ make_adjustment_matrix(request, medium, pmat, false,
+ (orient >= 0 ? orient : 0));
+ }
+ else if ( rx - medium->p.y >= -5 && rx - medium->q.y <= 5 &&
+ ry - medium->p.x >= -5 && ry - medium->q.x <= 5 &&
+ (orient < 0 || (orient & 1))
+ )
+ { *best_mismatch = 0;
+ make_adjustment_matrix(request, medium, pmat, false,
+ (orient >= 0 ? orient :
+ rx < ry ? -1 : 1));
+ }
+ else
+ { int rotate =
+ (orient >= 0 ? orient :
+ rx < ry ?
+ (medium->q.x > medium->q.y ? -1 : 0) :
+ (medium->q.x < medium->q.y ? 1 : 0));
+ bool larger =
+ (rotate ? medium->q.y >= rx && medium->q.x >= ry :
+ medium->q.x >= rx && medium->q.y >= ry);
+ bool adjust = false;
+ float mismatch = medium->q.x * medium->q.y - rx * ry;
+
+ switch ( policy )
+ {
+ default: /* exact match only */
+ return false;
+ case 3: /* nearest match, adjust */
+ adjust = true;
+ case 5: /* nearest match, don't adjust */
+ if ( fabs(mismatch) >= fabs(*best_mismatch) )
+ return false;
+ break;
+ case 4: /* next larger match, adjust */
+ adjust = true;
+ case 6: /* next larger match, don't adjust */
+ if ( !larger || mismatch >= *best_mismatch )
+ return false;
+ break;
+ }
+ if ( adjust )
+ make_adjustment_matrix(request, medium, pmat, !larger, rotate);
+ else
+ { gs_rect req_rect;
+ req_rect.p = *request;
+ req_rect.q = *request;
+ make_adjustment_matrix(request, &req_rect, pmat, false, rotate);
+ }
+ *best_mismatch = mismatch;
+ }
+ if ( pmat->xx == 0 )
+ { /* Swap request X and Y. */
+ double temp = rx;
+ rx = ry, ry = temp;
+ }
+#define adjust_into(req, mmin, mmax)\
+ (req < mmin ? mmin : req > mmax ? mmax : req)
+ pmsize->x = adjust_into(rx, medium->p.x, medium->q.x);
+ pmsize->y = adjust_into(ry, medium->p.y, medium->q.y);
+ return true;
+}
+/*
+ * Compute the adjustment matrix for scaling and/or rotating the page
+ * to match the medium. If the medium is completely flexible in a given
+ * dimension (e.g., roll media in one dimension, or displays in both),
+ * we must adjust its size in that dimension to match the request.
+ * We recognize this by medium->p.{x,y} = 0.
+ */
+private void
+make_adjustment_matrix(const gs_point *request, const gs_rect *medium,
+ gs_matrix *pmat, bool scale, int rotate)
+{ double rx = request->x, ry = request->y;
+ double mx = medium->q.x, my = medium->q.y;
+
+ /* Rotate the request if necessary. */
+ if ( rotate & 1 )
+ { double temp = rx;
+ rx = ry, ry = temp;
+ }
+
+ /* Adjust the medium size if flexible. */
+ if ( medium->p.x == 0 && mx > rx )
+ mx = rx;
+ if ( medium->p.y == 0 && my > ry )
+ my = ry;
+
+ /* Translate to align the centers. */
+ gs_make_translation(mx / 2, my / 2, pmat);
+
+ /* Rotate if needed. */
+ if ( rotate )
+ gs_matrix_rotate(pmat, 90.0 * rotate, pmat);
+
+ /* Scale if needed. */
+ if ( scale )
+ { double xfactor = mx / rx;
+ double yfactor = my / ry;
+ double factor = min(xfactor, yfactor);
+ if ( factor < 1 )
+ gs_matrix_scale(pmat, factor, factor, pmat);
+ }
+
+ /* Now translate the origin back, */
+ /* using the original, unswapped request. */
+ gs_matrix_translate(pmat, -request->x / 2, -request->y / 2, pmat);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zmedia2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"4.matchmedia", zmatchmedia},
+ {"6.matchpagesize", zmatchpagesize},
+END_OP_DEFS(0) }
diff --git a/gs/src/zmisc.c b/gs/src/zmisc.c
new file mode 100644
index 000000000..1015cf170
--- /dev/null
+++ b/gs/src/zmisc.c
@@ -0,0 +1,308 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmisc.c */
+/* Miscellaneous operators */
+#include "errno_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gscdefs.h" /* for gs_serialnumber */
+#include "gp.h"
+#include "errors.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h" /* for name lookup in bind */
+#include "iname.h"
+#include "ipacked.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Import the C getenv function. */
+extern char *getenv(P1(const char *));
+
+/* <proc> bind <proc> */
+private int
+zbind(os_ptr op)
+{ uint depth = 1;
+ ref defn;
+ register os_ptr bsp;
+ switch ( r_type(op) )
+ {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ defn = *op;
+ break;
+ case t_oparray:
+ defn = *op->value.const_refs;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ push(1);
+ *op = defn;
+ bsp = op;
+ /*
+ * We must not make the top-level procedure read-only,
+ * but we must bind it even if it is read-only already.
+ *
+ * Here are the invariants for the following loop:
+ * `depth' elements have been pushed on the ostack;
+ * For i < depth, p = ref_stack_index(&o_stack, i):
+ * *p is an array (or packedarray) ref. */
+#define r_is_ex_oper(rp)\
+ ((r_btype(rp) == t_operator || r_type(rp) == t_oparray) &&\
+ r_has_attr(rp, a_executable))
+ while ( depth )
+ { while ( r_size(bsp) )
+ { ref *tp = bsp->value.refs;
+ r_dec_size(bsp, 1);
+ if ( r_is_packed(tp) )
+ { /* Check for a packed executable name */
+ ushort elt = *(ushort *)tp;
+ if ( r_packed_is_exec_name(&elt) )
+ { ref nref;
+ ref *pvalue;
+ name_index_ref(packed_name_index(&elt),
+ &nref);
+ if ( (pvalue = dict_find_name(&nref)) != 0 &&
+ r_is_ex_oper(pvalue)
+ )
+ /* Note: can't undo this by restore! */
+ *(ushort *)tp =
+ pt_tag(pt_executable_operator) +
+ op_index(pvalue);
+ }
+ bsp->value.refs = (ref *)((ref_packed *)tp + 1);
+ }
+ else
+ switch ( bsp->value.refs++, r_type(tp) )
+ {
+ case t_name: /* bind the name if an operator */
+ if ( r_has_attr(tp, a_executable) )
+ { ref *pvalue;
+ if ( (pvalue = dict_find_name(tp)) != 0 &&
+ r_is_ex_oper(pvalue)
+ )
+ ref_assign_old(bsp, tp, pvalue, "bind");
+ }
+ break;
+ case t_array: /* push into array if writable */
+ if ( !r_has_attr(tp, a_write) ) break;
+ case t_mixedarray:
+ case t_shortarray:
+ if ( r_has_attr(tp, a_executable) )
+ { /* Make reference read-only */
+ r_clear_attrs(tp, a_write);
+ if ( bsp >= ostop )
+ { /* Push a new stack block. */
+ ref temp;
+ int code;
+ temp = *tp;
+ osp = bsp;
+ code = ref_stack_push(&o_stack, 1);
+ if ( code < 0 )
+ { ref_stack_pop(&o_stack, depth);
+ return_error(code);
+ }
+ bsp = osp;
+ *bsp = temp;
+ }
+ else
+ *++bsp = *tp;
+ depth++;
+ }
+ }
+ }
+ bsp--; depth--;
+ if ( bsp < osbot )
+ { /* Pop back to the previous stack block. */
+ osp = bsp;
+ ref_stack_pop_block(&o_stack);
+ bsp = osp;
+ }
+ }
+ osp = bsp;
+ return 0;
+}
+
+/* - serialnumber <int> */
+private int
+zserialnumber(register os_ptr op)
+{ push(1);
+ make_int(op, gs_serialnumber);
+ return 0;
+}
+
+/* - realtime <int> */
+private int
+zrealtime(register os_ptr op)
+{ long secs_ns[2];
+ gp_get_realtime(secs_ns);
+ push(1);
+ make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
+ return 0;
+}
+
+/* - usertime <int> */
+private int
+zusertime(register os_ptr op)
+{ long secs_ns[2];
+ gp_get_usertime(secs_ns);
+ push(1);
+ make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
+ return 0;
+}
+
+/* ---------------- Non-standard operators ---------------- */
+
+/* <string> getenv <value_string> true */
+/* <string> getenv false */
+private int
+zgetenv(register os_ptr op)
+{ char *str, *value;
+ int code;
+ check_read_type(*op, t_string);
+ str = ref_to_string(op, imemory, "getenv name");
+ if ( str == 0 )
+ return_error(e_VMerror);
+ value = getenv(str);
+ ifree_string((byte *)str, r_size(op) + 1, "getenv name");
+ if ( value == 0 ) /* not found */
+ { make_bool(op, 0);
+ return 0;
+ }
+ code = string_to_ref(value, op, iimemory, "getenv value");
+ if ( code < 0 ) return code;
+ push(1);
+ make_bool(op, 1);
+ return 0;
+}
+
+/* <name> <proc> .makeoperator <oper> */
+private int
+zmakeoperator(register os_ptr op)
+{ op_array_table *opt;
+ uint count;
+ ref *tab;
+
+ check_type(op[-1], t_name);
+ check_proc(*op);
+ switch ( r_space(op) )
+ {
+ case avm_global: opt = &op_array_table_global; break;
+ case avm_local: opt = &op_array_table_local; break;
+ default: return_error(e_invalidaccess);
+ }
+ count = opt->count;
+ tab = opt->table.value.refs;
+ /*
+ * restore doesn't reset op_array_table.count, but it does
+ * remove entries from op_array_table.table. Since we fill
+ * the table in order, we can detect that a restore has occurred
+ * by checking whether what should be the most recent entry
+ * is occupied. If not, we scan backwards over the vacated entries
+ * to find the true end of the table.
+ */
+ while ( count > 0 && r_has_type(&tab[count - 1], t_null) )
+ --count;
+ if ( count == r_size(&opt->table) )
+ return_error(e_limitcheck);
+ ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
+ opt->nx_table[count] = name_index(op - 1);
+ op_index_ref(opt->base_index + count, op - 1);
+ opt->count = count + 1;
+ pop(1);
+ return 0;
+}
+
+/* - .oserrno <int> */
+private int
+zoserrno(register os_ptr op)
+{ push(1);
+ make_int(op, errno);
+ return 0;
+}
+
+/* <int> .setoserrno - */
+private int
+zsetoserrno(register os_ptr op)
+{ check_type(*op, t_integer);
+ errno = op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* <int> .oserrorstring <string> true */
+/* <int> .oserrorstring false */
+private int
+zoserrorstring(register os_ptr op)
+{ const char *str;
+ int code;
+ uint len;
+ byte ch;
+ check_type(*op, t_integer);
+ str = gp_strerror((int)op->value.intval);
+ if ( str == 0 || (len = strlen(str)) == 0 )
+ { make_false(op);
+ return 0;
+ }
+ check_ostack(1);
+ code = string_to_ref(str, op, iimemory, ".oserrorstring");
+ if ( code < 0 )
+ return code;
+ /* Strip trailing end-of-line characters. */
+ while ( (len = r_size(op)) != 0 &&
+ ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
+ )
+ r_dec_size(op, 1);
+ push(1);
+ make_true(op);
+ return 0;
+}
+
+/* <string> <bool> .setdebug - */
+private int
+zsetdebug(register os_ptr op)
+{ check_read_type(op[-1], t_string);
+ check_type(*op, t_boolean);
+ { int i;
+ for ( i = 0; i < r_size(op - 1); i++ )
+ gs_debug[op[-1].value.bytes[i] & 127] =
+ op->value.boolval;
+ }
+ pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zmisc_op_defs) {
+ {"1bind", zbind},
+ {"1getenv", zgetenv},
+ {"2.makeoperator", zmakeoperator},
+ {"0.oserrno", zoserrno},
+ {"1.oserrorstring", zoserrorstring},
+ {"0realtime", zrealtime},
+ {"1serialnumber", zserialnumber},
+ {"2.setdebug", zsetdebug},
+ {"1.setoserrno", zsetoserrno},
+ {"0usertime", zusertime},
+END_OP_DEFS(0) }
diff --git a/gs/src/zmisc1.c b/gs/src/zmisc1.c
new file mode 100644
index 000000000..4602fac36
--- /dev/null
+++ b/gs/src/zmisc1.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmisc1.c */
+/* Miscellaneous Type 1 font operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscrypt1.h"
+#include "stream.h" /* for getting state of PFBD stream */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifilter.h"
+
+/* <state> <from_string> <to_string> .type1encrypt <new_state> <substring> */
+/* <state> <from_string> <to_string> .type1decrypt <new_state> <substring> */
+private int type1crypt(P2(os_ptr,
+ int (*)(P4(byte *, const byte *, uint, ushort *))));
+private int
+ztype1encrypt(os_ptr op)
+{ return type1crypt(op, gs_type1_encrypt);
+}
+private int
+ztype1decrypt(os_ptr op)
+{ return type1crypt(op, gs_type1_decrypt);
+}
+private int
+type1crypt(register os_ptr op, int (*proc)(P4(byte *, const byte *, uint, ushort *)))
+{ crypt_state state;
+ uint ssize;
+ check_type(op[-2], t_integer);
+ state = op[-2].value.intval;
+ if ( op[-2].value.intval != state )
+ return_error(e_rangecheck); /* state value was truncated */
+ check_read_type(op[-1], t_string);
+ check_write_type(*op, t_string);
+ ssize = r_size(op - 1);
+ if ( r_size(op) < ssize )
+ return_error(e_rangecheck);
+ discard((*proc)(op->value.bytes, op[-1].value.const_bytes, ssize,
+ &state)); /* can't fail */
+ op[-2].value.intval = state;
+ op[-1] = *op;
+ r_set_size(op - 1, ssize);
+ pop(1);
+ return 0;
+}
+
+/* Get the seed parameter for eexecEncode/Decode. */
+/* Return npop if OK. */
+private int
+eexec_param(os_ptr op, ushort *pcstate)
+{ int npop = 1;
+ if ( r_has_type(op, t_dictionary) )
+ ++npop, --op;
+ check_type(*op, t_integer);
+ *pcstate = op->value.intval;
+ if ( op->value.intval != *pcstate )
+ return_error(e_rangecheck); /* state value was truncated */
+ return npop;
+}
+
+/* <target> <seed> eexecEncode/filter <file> */
+/* <target> <seed> <dict_ignored> eexecEncode/filter <file> */
+private int
+zexE(register os_ptr op)
+{ stream_exE_state state;
+ int code = eexec_param(op, &state.cstate);
+
+ if ( code < 0 )
+ return code;
+ return filter_write(op, code, &s_exE_template, (stream_state *)&state,
+ 0);
+}
+
+/* <source> <seed> eexecDecode/filter <file> */
+/* <source> <dict> eexecDecode/filter <file> */
+private int
+zexD(register os_ptr op)
+{ stream_exD_state state;
+ int code;
+
+ (*s_exD_template.set_defaults)((stream_state *)&state);
+ if ( r_has_type(op, t_dictionary) ) {
+ uint cstate;
+
+ check_dict_read(*op);
+ if ( (code = dict_uint_param(op, "seed", 0, 0xffff, 0x10000,
+ &cstate)) < 0 ||
+ (code = dict_int_param(op, "lenIV", 0, max_int, 4,
+ &state.lenIV)) < 0
+ )
+ return code;
+ state.cstate = cstate;
+ code = 1;
+ } else {
+ code = eexec_param(op, &state.cstate);
+ }
+ if ( code < 0 )
+ return code;
+ /* If we're reading a .PFB file, let the filter know about it, */
+ /* so it can read recklessly to the end of the binary section. */
+ state.pfb_state = 0;
+ if ( r_has_type(op - 1, t_file) )
+ { stream *s = (op - 1)->value.pfile;
+ if ( s->state != 0 && s->state->template == &s_PFBD_template )
+ state.pfb_state = (stream_PFBD_state *)s->state;
+ }
+ state.binary = -1;
+ return filter_read(op, code, &s_exD_template, (stream_state *)&state,
+ 0);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zmisc1_op_defs) {
+ {"3.type1encrypt", ztype1encrypt},
+ {"3.type1decrypt", ztype1decrypt},
+ op_def_begin_filter(),
+ {"2eexecEncode", zexE},
+ {"2eexecDecode", zexD},
+END_OP_DEFS(0) }
diff --git a/gs/src/zmisc2.c b/gs/src/zmisc2.c
new file mode 100644
index 000000000..5b0034d07
--- /dev/null
+++ b/gs/src/zmisc2.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zmisc2.c */
+/* Miscellaneous Level 2 operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iparam.h"
+#include "dstack.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "iutil2.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Forward references */
+private int set_language_level(P1(int));
+
+/* ------ Language level operators ------ */
+
+/* - .languagelevel <1 or 2> */
+private int
+zlanguagelevel(register os_ptr op)
+{ push(1);
+ ref_assign(op, &ref_language_level);
+ return 0;
+}
+
+/* <1 or 2> .setlanguagelevel - */
+private int
+zsetlanguagelevel(register os_ptr op)
+{ int code = 0;
+ check_type(*op, t_integer);
+ if ( op->value.intval < 1 || op->value.intval > 2 )
+ return_error(e_rangecheck);
+ if ( op->value.intval != ref_language_level.value.intval )
+ { code = set_language_level((int)op->value.intval);
+ if ( code < 0 ) return code;
+ }
+ pop(1);
+ ref_assign_old(NULL, &ref_language_level, op, "setlanguagelevel");
+ return code;
+}
+
+/* ------ The 'where' hack ------ */
+
+private int
+z2where(register os_ptr op)
+{ /*
+ * Aldus Freehand versions 2.x check for the presence of the
+ * setcolor operator, and if it is missing, substitute a procedure.
+ * Unfortunately, the procedure takes different parameters from
+ * the operator. As a result, files produced by this application
+ * cause an error if the setcolor operator is actually defined
+ * and 'bind' is ever used. Aldus fixed this bug in Freehand 3.0,
+ * but there are a lot of files created by the older versions
+ * still floating around. Therefore, at Adobe's suggestion,
+ * we implement the following dreadful hack in the 'where' operator:
+ * If the key is /setcolor, and
+ * there is a dictionary named FreeHandDict, and
+ * currentdict is that dictionary,
+ * then "where" consults only that dictionary and not any other
+ * dictionaries on the dictionary stack.
+ */
+ ref rkns, rfh;
+ const ref *pdref = dsp;
+ ref *pvalue;
+ if ( !r_has_type(op, t_name) ||
+ (name_string_ref(op, &rkns), r_size(&rkns)) != 8 ||
+ memcmp(rkns.value.bytes, "setcolor", 8) != 0 ||
+ name_ref((const byte *)"FreeHandDict", 12, &rfh, -1) < 0 ||
+ (pvalue = dict_find_name(&rfh)) == 0 ||
+ !obj_eq(pvalue, pdref)
+ )
+ return zwhere(op);
+ check_dict_read(*pdref);
+ if ( dict_find(pdref, op, &pvalue) > 0 )
+ { ref_assign(op, pdref);
+ push(1);
+ make_true(op);
+ }
+ else
+ make_false(op);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+/* The level setting ops are recognized even in Level 1 mode. */
+BEGIN_OP_DEFS(zmisc2_op_defs) {
+ {"0.languagelevel", zlanguagelevel},
+ {"1.setlanguagelevel", zsetlanguagelevel},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+/* Note that this overrides the definition in zdict.c. */
+ {"1where", z2where},
+END_OP_DEFS(0) }
+
+/* ------ Internal procedures ------ */
+
+/* Adjust the interpreter for a change in language level. */
+/* This is used for the .setlanguagelevel operator, */
+/* and after a restore. */
+private int swap_entry(P3(ref elt[2], ref *pdict, ref *pdict2));
+private int
+set_language_level(int level)
+{ ref *pgdict = /* globaldict, if present */
+ ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
+ ref *level2dict;
+ if (dict_find_string(systemdict, "level2dict", &level2dict) <= 0)
+ return_error(e_undefined);
+ /* As noted in dstack.h, we allocate the extra d-stack entry */
+ /* for globaldict even in Level 1 mode; in Level 1 mode, */
+ /* this entry holds an extra copy of systemdict, and */
+ /* [count]dictstack omit the very bottommost entry. */
+ if ( level == 2 ) /* from Level 1 to Level 2 */
+ { /* Put globaldict in the dictionary stack. */
+ ref *pdict;
+ int code = dict_find_string(level2dict, "globaldict", &pdict);
+
+ /* This might be called so early in initialization that */
+ /* globaldict hasn't been defined yet. If so, just skip */
+ /* this step. */
+ if ( code > 0 )
+ { if ( !r_has_type(pdict, t_dictionary) )
+ return_error(e_typecheck);
+ *pgdict = *pdict;
+ }
+ /* Set other flags for Level 2 operation. */
+ dict_auto_expand = true;
+ }
+ else /* from Level 2 to Level 1 */
+ { /* Clear the cached definition pointers of all names */
+ /* defined in globaldict. This will slow down */
+ /* future lookups, but we don't care. */
+ int index = dict_first(pgdict);
+ ref elt[2];
+ while ( (index = dict_next(pgdict, index, &elt[0])) >= 0 )
+ if ( r_has_type(&elt[0], t_name) )
+ name_invalidate_value_cache(&elt[0]);
+ /* Overwrite globaldict in the dictionary stack. */
+ *pgdict = *systemdict;
+ /* Set other flags for Level 1 operation. */
+ dict_auto_expand = false;
+ }
+ /* Swap the contents of level2dict and systemdict. */
+ /* If a value in level2dict is a dictionary, and it contains */
+ /* a key/value pair referring to itself, swap its contents */
+ /* with the contents of the same dictionary in systemdict. */
+ /* (This is a hack to swap the contents of statusdict.) */
+ { int index = dict_first(level2dict);
+ ref elt[2]; /* key, value */
+ ref *subdict;
+ while ( (index = dict_next(level2dict, index, &elt[0])) >= 0 )
+ if ( r_has_type(&elt[1], t_dictionary) &&
+ dict_find(&elt[1], &elt[0], &subdict) > 0 &&
+ obj_eq(&elt[1], subdict)
+ )
+ {
+#define sub2dict &elt[1]
+ int isub = dict_first(sub2dict);
+ ref subelt[2];
+ int found = dict_find(systemdict, &elt[0], &subdict);
+ if ( found <= 0 )
+ continue;
+ while ( (isub = dict_next(sub2dict, isub, &subelt[0])) >= 0 )
+ if ( !obj_eq(&subelt[0], &elt[0]) ) /* don't swap dict itself */
+ { int code = swap_entry(subelt, subdict, sub2dict);
+ if ( code < 0 )
+ return code;
+ }
+#undef sub2dict
+ }
+ else
+ { int code = swap_entry(elt, systemdict, level2dict);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ dict_set_top(); /* reload dict stack cache */
+ return 0;
+}
+
+/* Swap an entry from a Level 2 dictionary into a base dictionary. */
+/* elt[0] is the key, elt[1] is the value in the Level 2 dictionary. */
+private int
+swap_entry(ref elt[2], ref *pdict, ref *pdict2)
+{ ref *pvalue;
+ ref old_value;
+ int found = dict_find(pdict, &elt[0], &pvalue);
+ switch ( found )
+ {
+ default: /* <0, error */
+ return found;
+ case 0: /* missing */
+ make_null(&old_value);
+ break;
+ case 1: /* present */
+ old_value = *pvalue;
+ }
+ /*
+ * Temporarily flag the dictionaries as local, so that we don't
+ * get invalidaccess errors. (We know that they are both
+ * referenced from systemdict, so they are allowed to reference
+ * local objects even if they are global.)
+ */
+ { uint space2 = r_space(pdict2);
+ int code;
+ r_set_space(pdict2, avm_local);
+ dict_put(pdict2, &elt[0], &old_value);
+ if ( r_has_type(&elt[1], t_null) )
+ code = dict_undef(pdict, &elt[0]);
+ else
+ { uint space = r_space(pdict);
+ r_set_space(pdict, avm_local);
+ code = dict_put(pdict, &elt[0], &elt[1]);
+ r_set_space(pdict, space);
+ }
+ r_set_space(pdict2, space2);
+ return code;
+ }
+}
diff --git a/gs/src/zpacked.c b/gs/src/zpacked.c
new file mode 100644
index 000000000..04078e262
--- /dev/null
+++ b/gs/src/zpacked.c
@@ -0,0 +1,232 @@
+/* Copyright (C) 1990, 1992, 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zpacked.c */
+/* Packed array operators */
+#include "ghost.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "iname.h"
+#include "istack.h" /* for iparray.h */
+#include "ipacked.h"
+#include "iparray.h"
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+
+/* Import the array packing flag */
+extern ref ref_array_packing;
+
+/* - currentpacking <bool> */
+private int
+zcurrentpacking(register os_ptr op)
+{ push(1);
+ ref_assign(op, &ref_array_packing);
+ return 0;
+}
+
+/* <obj_0> ... <obj_n-1> <n> packedarray <packedarray> */
+int
+zpackedarray(register os_ptr op)
+{ int code;
+ ref parr;
+ check_type(*op, t_integer);
+ if ( op->value.intval < 0 ||
+ (op->value.intval > op - osbot &&
+ op->value.intval >= ref_stack_count(&o_stack))
+ )
+ return_error(e_rangecheck);
+ osp--;
+ code = make_packed_array(&parr, &o_stack, (uint)op->value.intval,
+ "packedarray");
+ osp++;
+ if ( code >= 0 )
+ *osp = parr;
+ return code;
+}
+
+/* <bool> setpacking - */
+private int
+zsetpacking(register os_ptr op)
+{ check_type(*op, t_boolean);
+ ref_assign_old(NULL, &ref_array_packing, op, "setpacking");
+ pop(1);
+ return 0;
+}
+
+/* ------ Non-operator routines ------ */
+
+/* Make a packed array. See the comment in packed.h about */
+/* ensuring that refs in mixed arrays are properly aligned. */
+int
+make_packed_array(ref *parr, ref_stack *pstack, uint size, client_name_t cname)
+{ uint i;
+ const ref *pref;
+ uint idest = 0, ishort = 0;
+ ref_packed *pbody, *pdest;
+ ref_packed *pshort; /* points to start of */
+ /* last run of short elements */
+ uint space = ialloc_space(idmemory);
+ int skip = 0, pad;
+ ref rtemp;
+ int code;
+
+ /* Do a first pass to calculate the size of the array, */
+ /* and to detect local-into-global stores. */
+
+ for ( i = size; i != 0; i-- )
+ { pref = ref_stack_index(pstack, i - 1);
+ switch ( r_btype(pref) ) /* not r_type, opers are special */
+ {
+ case t_name:
+ if ( name_index(pref) >= packed_name_max_index )
+ break; /* can't pack */
+ idest++;
+ continue;
+ case t_integer:
+ if ( pref->value.intval < packed_min_intval ||
+ pref->value.intval > packed_max_intval
+ )
+ break;
+ idest++;
+ continue;
+ case t_oparray:
+ /* Check for local-into-global store. */
+ store_check_space(space, pref);
+ /* falls through */
+ case t_operator:
+ { uint oidx;
+ if ( !r_has_attr(pref, a_executable) )
+ break;
+ oidx = op_index(pref);
+ if ( oidx == 0 || oidx > packed_int_mask )
+ break;
+ } idest++;
+ continue;
+ default:
+ /* Check for local-into-global store. */
+ store_check_space(space, pref);
+ }
+ /* Can't pack this element, use a full ref. */
+ /* We may have to unpack up to align_packed_per_ref - 1 */
+ /* preceding short elements. */
+ /* If we are at the beginning of the array, however, */
+ /* we can just move the elements up. */
+ { int i = (idest - ishort) & (align_packed_per_ref - 1);
+ if ( ishort == 0 ) /* first time */
+ idest += skip = -i & (align_packed_per_ref - 1);
+ else
+ idest += (packed_per_ref - 1) * i;
+ }
+ ishort = idest += packed_per_ref;
+ }
+ pad = -idest & (packed_per_ref - 1); /* padding at end */
+
+ /* Now we can allocate the array. */
+
+ code = ialloc_ref_array(&rtemp, 0, (idest + pad) / packed_per_ref,
+ cname);
+ if ( code < 0 )
+ return code;
+ pbody = (ref_packed *)rtemp.value.refs;
+
+ /* Make sure any initial skipped elements contain legal packed */
+ /* refs, so that the garbage collector can scan storage. */
+
+ pshort = pbody;
+ for ( ; skip; skip-- )
+ *pbody++ = pt_tag(pt_integer);
+ pdest = pbody;
+
+ for ( i = size; i != 0; i-- )
+ { pref = ref_stack_index(pstack, i - 1);
+ switch ( r_btype(pref) ) /* not r_type, opers are special */
+ {
+ case t_name:
+ { uint nidx = name_index(pref);
+ if ( nidx >= packed_name_max_index )
+ break; /* can't pack */
+ *pdest++ = nidx +
+ (r_has_attr(pref, a_executable) ?
+ pt_tag(pt_executable_name) :
+ pt_tag(pt_literal_name));
+ } continue;
+ case t_integer:
+ if ( pref->value.intval < packed_min_intval ||
+ pref->value.intval > packed_max_intval
+ )
+ break;
+ *pdest++ = pt_tag(pt_integer) +
+ ((short)pref->value.intval - packed_min_intval);
+ continue;
+ case t_oparray:
+ case t_operator:
+ { uint oidx;
+ if ( !r_has_attr(pref, a_executable) )
+ break;
+ oidx = op_index(pref);
+ if ( oidx == 0 || oidx > packed_int_mask )
+ break;
+ *pdest++ = pt_tag(pt_executable_operator) + oidx;
+ } continue;
+ }
+ /* Can't pack this element, use a full ref. */
+ /* We may have to unpack up to align_packed_per_ref - 1 */
+ /* preceding short elements. */
+ /* Note that if we are at the beginning of the array, */
+ /* 'skip' already ensures that we don't need to do this. */
+ { int i = (pdest - pshort) & (align_packed_per_ref - 1);
+ const ref_packed *psrc = pdest;
+ ref *pmove =
+ (ref *)(pdest += (packed_per_ref - 1) * i);
+ ref_assign_new(pmove, pref);
+ while ( --i >= 0 )
+ { --psrc;
+ --pmove;
+ packed_get(psrc, pmove);
+ }
+ }
+ pshort = pdest += packed_per_ref;
+ }
+
+ { int atype =
+ (pdest == pbody + size ? t_shortarray : t_mixedarray);
+
+ /* Pad with legal packed refs so that the garbage collector */
+ /* can scan storage. */
+
+ for ( ; pad; pad-- )
+ *pdest++ = pt_tag(pt_integer);
+
+ /* Finally, make the array. */
+
+ ref_stack_pop(pstack, size);
+ make_tasv_new(parr, atype, a_readonly | space, size,
+ packed, pbody + skip);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zpacked_op_defs) {
+ {"0currentpacking", zcurrentpacking},
+ {"1packedarray", zpackedarray},
+ {"1setpacking", zsetpacking},
+END_OP_DEFS(0) }
diff --git a/gs/src/zpaint.c b/gs/src/zpaint.c
new file mode 100644
index 000000000..1e455eb06
--- /dev/null
+++ b/gs/src/zpaint.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zpaint.c */
+/* Painting operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gspaint.h"
+#include "igstate.h"
+
+/* - fill - */
+private int
+zfill(register os_ptr op)
+{ return gs_fill(igs);
+}
+
+/* - eofill - */
+private int
+zeofill(register os_ptr op)
+{ return gs_eofill(igs);
+}
+
+/* - stroke - */
+private int
+zstroke(register os_ptr op)
+{ return gs_stroke(igs);
+}
+
+/* ------ Non-standard operators ------ */
+
+/* - .fillpage - */
+private int
+zfillpage(register os_ptr op)
+{ return gs_fillpage(igs);
+}
+
+/* <width> <height> <data> .imagepath - */
+private int
+zimagepath(register os_ptr op)
+{ int code;
+
+ check_type(op[-2], t_integer);
+ check_type(op[-1], t_integer);
+ check_read_type(*op, t_string);
+ if ( r_size(op) < ((op[-2].value.intval + 7) >> 3) * op[-1].value.intval )
+ return_error(e_rangecheck);
+ code = gs_imagepath(igs,
+ (int)op[-2].value.intval, (int)op[-1].value.intval,
+ op->value.const_bytes);
+ if ( code >= 0 )
+ pop(3);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zpaint_op_defs) {
+ {"0eofill", zeofill},
+ {"0fill", zfill},
+ {"0stroke", zstroke},
+ /* Non-standard operators */
+ {"0.fillpage", zfillpage},
+ {"3.imagepath", zimagepath},
+END_OP_DEFS(0) }
diff --git a/gs/src/zpath.c b/gs/src/zpath.c
new file mode 100644
index 000000000..a485e71a4
--- /dev/null
+++ b/gs/src/zpath.c
@@ -0,0 +1,178 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zpath.c */
+/* Basic path operators */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gspath.h"
+#include "store.h"
+
+/* Forward references */
+private int near common_to(P2(os_ptr,
+ int (*)(P3(gs_state *, floatp, floatp))));
+private int near common_curve(P2(os_ptr,
+ int (*)(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp))));
+
+/* - newpath - */
+private int
+znewpath(register os_ptr op)
+{ return gs_newpath(igs);
+}
+
+/* - currentpoint <x> <y> */
+private int
+zcurrentpoint(register os_ptr op)
+{ gs_point pt;
+ int code = gs_currentpoint(igs, &pt);
+ if ( code < 0 ) return code;
+ push(2);
+ make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ return 0;
+}
+
+/* <x> <y> moveto - */
+int
+zmoveto(os_ptr op)
+{ return common_to(op, gs_moveto);
+}
+
+/* <dx> <dy> rmoveto - */
+int
+zrmoveto(os_ptr op)
+{ return common_to(op, gs_rmoveto);
+}
+
+/* <x> <y> lineto - */
+int
+zlineto(os_ptr op)
+{ return common_to(op, gs_lineto);
+}
+
+/* <dx> <dy> rlineto - */
+int
+zrlineto(os_ptr op)
+{ return common_to(op, gs_rlineto);
+}
+
+/* Common code for [r](move/line)to */
+private int near
+common_to(os_ptr op, int (*add_proc)(P3(gs_state *, floatp, floatp)))
+{ double opxy[2];
+ int code;
+
+ if ( (code = num_params(op, 2, opxy)) < 0 ||
+ (code = (*add_proc)(igs, opxy[0], opxy[1])) < 0
+ )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <x1> <y1> <x2> <y2> <x3> <y3> curveto - */
+int
+zcurveto(register os_ptr op)
+{ return common_curve(op, gs_curveto);
+}
+
+/* <dx1> <dy1> <dx2> <dy2> <dx3> <dy3> rcurveto - */
+int
+zrcurveto(register os_ptr op)
+{ return common_curve(op, gs_rcurveto);
+}
+
+/* Common code for [r]curveto */
+private int near
+common_curve(os_ptr op,
+ int (*add_proc)(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)))
+{ double opxy[6];
+ int code;
+
+ if ( (code = num_params(op, 6, opxy)) < 0 )
+ return code;
+ code = (*add_proc)(igs, opxy[0], opxy[1], opxy[2], opxy[3], opxy[4], opxy[5]);
+ if ( code >= 0 ) pop(6);
+ return code;
+}
+
+/* - closepath - */
+int
+zclosepath(register os_ptr op)
+{ return gs_closepath(igs);
+}
+
+/* - initclip - */
+private int
+zinitclip(register os_ptr op)
+{ return gs_initclip(igs);
+}
+
+/* - clip - */
+private int
+zclip(register os_ptr op)
+{ return gs_clip(igs);
+}
+
+/* - eoclip - */
+private int
+zeoclip(register os_ptr op)
+{ return gs_eoclip(igs);
+}
+
+/* <bool> .setclipoutside - */
+private int
+zsetclipoutside(register os_ptr op)
+{ int code;
+ check_type(*op, t_boolean);
+ code = gs_setclipoutside(igs, op->value.boolval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* - .currentclipoutside <bool> */
+private int
+zcurrentclipoutside(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentclipoutside(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zpath_op_defs) {
+ {"0clip", zclip},
+ {"0closepath", zclosepath},
+ {"0.currentclipoutside", zcurrentclipoutside},
+ {"0currentpoint", zcurrentpoint},
+ {"6curveto", zcurveto},
+ {"0eoclip", zeoclip},
+ {"0initclip", zinitclip},
+ {"2lineto", zlineto},
+ {"2moveto", zmoveto},
+ {"0newpath", znewpath},
+ {"6rcurveto", zrcurveto},
+ {"2rlineto", zrlineto},
+ {"2rmoveto", zrmoveto},
+ {"1.setclipoutside", zsetclipoutside},
+END_OP_DEFS(0) }
diff --git a/gs/src/zpath1.c b/gs/src/zpath1.c
new file mode 100644
index 000000000..84008828f
--- /dev/null
+++ b/gs/src/zpath1.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zpath1.c */
+/* PostScript Level 1 additional path operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "errors.h"
+#include "estack.h" /* for pathforall */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsstruct.h"
+#include "gspath.h"
+#include "store.h"
+
+/* Forward references */
+private int near common_arc(P2(os_ptr,
+ int (*)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp))));
+private int near common_arct(P2(os_ptr, float *));
+
+/* <x> <y> <r> <ang1> <ang2> arc - */
+int
+zarc(os_ptr op)
+{ return common_arc(op, gs_arc);
+}
+
+/* <x> <y> <r> <ang1> <ang2> arcn - */
+int
+zarcn(os_ptr op)
+{ return common_arc(op, gs_arcn);
+}
+
+/* Common code for arc[n] */
+private int near
+common_arc(os_ptr op,
+ int (*aproc)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)))
+{ double xyra[5]; /* x, y, r, ang1, ang2 */
+ int code;
+
+ if ( (code = num_params(op, 5, xyra)) < 0 )
+ return code;
+ code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]);
+ if ( code >= 0 )
+ pop(5);
+ return code;
+}
+
+/* <x1> <y1> <x2> <y2> <r> arct - */
+int
+zarct(register os_ptr op)
+{ int code = common_arct(op, (float *)0);
+ if ( code < 0 ) return code;
+ pop(5);
+ return 0;
+}
+
+/* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */
+private int
+zarcto(register os_ptr op)
+{ float tanxy[4]; /* xt1, yt1, xt2, yt2 */
+ int code = common_arct(op, tanxy);
+ if ( code < 0 ) return code;
+ make_real(op - 4, tanxy[0]);
+ make_real(op - 3, tanxy[1]);
+ make_real(op - 2, tanxy[2]);
+ make_real(op - 1, tanxy[3]);
+ pop(1);
+ return 0;
+}
+
+/* Common code for arct[o] */
+private int near
+common_arct(os_ptr op, float *tanxy)
+{ double args[5]; /* x1, y1, x2, y2, r */
+ int code;
+
+ if ( (code = num_params(op, 5, args)) < 0 )
+ return code;
+ return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy);
+}
+
+/* - .dashpath - */
+private int
+zdashpath(register os_ptr op)
+{ return gs_dashpath(igs);
+}
+
+/* - flattenpath - */
+private int
+zflattenpath(register os_ptr op)
+{ return gs_flattenpath(igs);
+}
+
+/* - reversepath - */
+private int
+zreversepath(register os_ptr op)
+{ return gs_reversepath(igs);
+}
+
+/* - strokepath - */
+private int
+zstrokepath(register os_ptr op)
+{ return gs_strokepath(igs);
+}
+
+/* - clippath - */
+private int
+zclippath(register os_ptr op)
+{ return gs_clippath(igs);
+}
+
+/* <bool> .pathbbox <llx> <lly> <urx> <ury> */
+private int
+zpathbbox(register os_ptr op)
+{ gs_rect box;
+ int code;
+
+ check_type(*op, t_boolean);
+ code = gs_upathbbox(igs, &box, op->value.boolval);
+ if ( code < 0 )
+ return code;
+ push(3);
+ make_real(op - 3, box.p.x);
+ make_real(op - 2, box.p.y);
+ make_real(op - 1, box.q.x);
+ make_real(op, box.q.y);
+ return 0;
+}
+
+/* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */
+private int path_continue(P1(os_ptr));
+private int path_cleanup(P1(os_ptr));
+private int
+zpathforall(register os_ptr op)
+{ gs_path_enum *penum;
+ int code;
+
+ check_proc(op[-3]);
+ check_proc(op[-2]);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_estack(8);
+ if ( (penum = gs_path_enum_alloc(imemory, "pathforall")) == 0 )
+ return_error(e_VMerror);
+ code = gs_path_enum_init(penum, igs);
+ if ( code < 0 )
+ { ifree_object(penum, "path_cleanup");
+ return code;
+ }
+ /* Push a mark, the four procedures, and the path enumerator. */
+ push_mark_estack(es_for, path_cleanup); /* iterator */
+ memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */
+ esp += 5;
+ make_istruct(esp, 0, penum);
+ push_op_estack(path_continue);
+ pop(4); op -= 4;
+ return o_push_estack;
+}
+/* Continuation procedure for pathforall */
+private void pf_push(P3(gs_point *, int, os_ptr));
+private int
+path_continue(register os_ptr op)
+{ gs_path_enum *penum = r_ptr(esp, gs_path_enum);
+ gs_point ppts[3];
+ int code;
+ /* Make sure we have room on the o-stack for the worst case */
+ /* before we enumerate the next path element. */
+ check_ostack(6); /* 3 points for curveto */
+ code = gs_path_enum_next(penum, ppts);
+ switch ( code )
+ {
+ case 0: /* all done */
+ { esp -= 6;
+ path_cleanup(op);
+ return o_pop_estack;
+ }
+ default: /* error */
+ return code;
+ case gs_pe_moveto:
+ esp[2] = esp[-4]; /* moveto proc */
+ pf_push(ppts, 1, op);
+ break;
+ case gs_pe_lineto:
+ esp[2] = esp[-3]; /* lineto proc */
+ pf_push(ppts, 1, op);
+ break;
+ case gs_pe_curveto:
+ esp[2] = esp[-2]; /* curveto proc */
+ pf_push(ppts, 3, op);
+ break;
+ case gs_pe_closepath:
+ esp[2] = esp[-1]; /* closepath proc */
+ break;
+ }
+ push_op_estack(path_continue);
+ ++esp; /* include pushed procedure */
+ return o_push_estack;
+}
+/* Internal procedure to push one or more points */
+private void
+pf_push(gs_point *ppts, int n, os_ptr op)
+{ while ( n-- )
+ { op += 2;
+ make_real(op - 1, ppts->x);
+ make_real(op, ppts->y);
+ ppts++;
+ }
+ osp = op;
+}
+/* Clean up after a pathforall */
+private int
+path_cleanup(os_ptr op)
+{ gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum);
+ gs_path_enum_cleanup(penum);
+ ifree_object(penum, "path_cleanup");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zpath1_op_defs) {
+ {"5arc", zarc},
+ {"5arcn", zarcn},
+ {"5arct", zarct},
+ {"5arcto", zarcto},
+ {"0clippath", zclippath},
+ {"0.dashpath", zdashpath},
+ {"0flattenpath", zflattenpath},
+ {"4pathforall", zpathforall},
+ {"0reversepath", zreversepath},
+ {"0strokepath", zstrokepath},
+ {"0.pathbbox", zpathbbox},
+ /* Internal operators */
+ {"0%path_continue", path_continue},
+END_OP_DEFS(0) }
diff --git a/gs/src/zpcolor.c b/gs/src/zpcolor.c
new file mode 100644
index 000000000..a4fc9725c
--- /dev/null
+++ b/gs/src/zpcolor.c
@@ -0,0 +1,245 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zpcolor.c */
+/* Pattern color */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gsmatrix.h"
+#include "gsstruct.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h" /* for gxpcolor.h */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxpcolor.h */
+#include "gxpcolor.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "istruct.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Imported from gspcolor.c */
+extern const gs_color_space_type gs_color_space_type_Pattern;
+
+/* Imported from zcolor2.c */
+extern gs_memory_type_ptr_t zcolor2_st_pattern_instance_p;
+
+/* Forward references */
+private int zPaintProc(P2(const gs_client_color *, gs_state *));
+private int pattern_paint_prepare(P1(os_ptr));
+private int pattern_paint_finish(P1(os_ptr));
+
+/*
+ * Define the structure for remembering the pattern dictionary.
+ * This is the "client data" in the template.
+ * See zgstate.c (int_gstate) or zfont2.c (font_data) for information
+ * as to why we define this as a structure rather than a ref array.
+ */
+typedef struct int_pattern_s {
+ ref dict;
+} int_pattern;
+gs_private_st_ref_struct(st_int_pattern, int_pattern, "int_pattern");
+
+/* Initialize the Pattern cache and the Pattern instance type. */
+private void
+zpcolor_init(void)
+{ gstate_set_pattern_cache(igs,
+ gx_pattern_alloc_cache(imemory_system,
+ gx_pat_cache_default_tiles(),
+ gx_pat_cache_default_bits()));
+ zcolor2_st_pattern_instance_p = &st_pattern_instance;
+}
+
+/* <pattern> <matrix> .buildpattern <pattern> <instance> */
+private int
+zbuildpattern(os_ptr op)
+{ os_ptr op1 = op - 1;
+ int code;
+ gs_matrix mat;
+ int PatternType;
+ float BBox[4];
+ gs_client_pattern template;
+ int_pattern *pdata;
+ gs_client_color cc_instance;
+ ref *pPaintProc;
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ if ( (code = read_matrix(op, &mat)) < 0 ||
+ (code = dict_uid_param(op1, &template.uid, 1, imemory)) != 1 ||
+ (code = dict_int_param(op1, "PatternType", 1, 1, 0, &PatternType)) < 0 ||
+ (code = dict_int_param(op1, "PaintType", 1, 2, 0, &template.PaintType)) < 0 ||
+ (code = dict_int_param(op1, "TilingType", 1, 3, 0, &template.TilingType)) < 0 ||
+ (code = dict_float_array_param(op1, "BBox", 4, BBox, NULL)) != 4 ||
+ (code = dict_float_param(op1, "XStep", 0.0, &template.XStep)) != 0 ||
+ (code = dict_float_param(op1, "YStep", 0.0, &template.YStep)) != 0 ||
+ (code = dict_find_string(op1, "PaintProc", &pPaintProc)) <= 0
+ )
+ return_error((code < 0 ? code : e_rangecheck));
+ check_proc(*pPaintProc);
+ template.BBox.p.x = BBox[0];
+ template.BBox.p.y = BBox[1];
+ template.BBox.q.x = BBox[2];
+ template.BBox.q.y = BBox[3];
+ template.PaintProc = zPaintProc;
+ pdata = ialloc_struct(int_pattern, &st_int_pattern, "int_pattern");
+ if ( pdata == 0 )
+ return_error(e_VMerror);
+ template.client_data = pdata;
+ pdata->dict = *op1;
+ code = gs_makepattern(&cc_instance, &template, &mat, igs, imemory);
+ if ( code < 0 )
+ { ifree_object(pdata, "int_pattern");
+ return code;
+ }
+ make_istruct(op, a_readonly, cc_instance.pattern);
+ return code;
+}
+
+/* <array> .setpatternspace - */
+/* In the case of uncolored patterns, the current color space is */
+/* the base space for the pattern space. */
+private int
+zsetpatternspace(register os_ptr op)
+{ gs_color_space cs;
+ uint edepth = ref_stack_count(&e_stack);
+ int code;
+
+ check_read_type(*op, t_array);
+ switch ( r_size(op) )
+ {
+ case 1: /* no base space */
+ cs.params.pattern.has_base_space = false;
+ break;
+ default:
+ return_error(e_rangecheck);
+ case 2:
+ cs = *gs_currentcolorspace(igs);
+ if ( cs.type->num_components < 0 ) /* i.e., Pattern space */
+ return_error(e_rangecheck);
+ /* We can't count on C compilers to recognize the aliasing */
+ /* that would be involved in a direct assignment, so.... */
+ { gs_paint_color_space cs_paint;
+ cs_paint = *(gs_paint_color_space *)&cs;
+ cs.params.pattern.base_space = cs_paint;
+ }
+ cs.params.pattern.has_base_space = true;
+ }
+ cs.type = &gs_color_space_type_Pattern;
+ code = gs_setcolorspace(igs, &cs);
+ if ( code < 0 )
+ { ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zpcolor_l2_op_defs) {
+ op_def_begin_level2(),
+ {"2.buildpattern", zbuildpattern},
+ {"1.setpatternspace", zsetpatternspace},
+ /* Internal operators */
+ {"0%pattern_paint_prepare", pattern_paint_prepare},
+ {"0%pattern_paint_finish", pattern_paint_finish},
+END_OP_DEFS(zpcolor_init) }
+
+/* ------ Internal procedures ------ */
+
+/* Set up the pattern pointer in a client color for setcolor */
+/* with a Pattern space. */
+
+
+/* Render the pattern by calling the PaintProc. */
+private int pattern_paint_cleanup(P1(os_ptr));
+private int
+zPaintProc(const gs_client_color *pcc, gs_state *pgs)
+{ /* Just schedule a call on the real PaintProc. */
+ check_estack(2);
+ esp++;
+ push_op_estack(pattern_paint_prepare);
+ return e_InsertProc;
+}
+/* Prepare to run the PaintProc. */
+private int
+pattern_paint_prepare(os_ptr op)
+{ gs_state *pgs = igs;
+ gs_pattern_instance *pinst = gs_currentcolor(pgs)->pattern;
+ ref *pdict = &((int_pattern *)pinst->template.client_data)->dict;
+ gx_device_pattern_accum *pdev;
+ int code;
+ ref *ppp;
+ check_estack(5);
+ pdev = gx_pattern_accum_alloc(imemory, "pattern_paint_prepare");
+ if ( pdev == 0 )
+ return_error(e_VMerror);
+ pdev->instance = pinst;
+ pdev->bitmap_memory = gstate_pattern_cache(pgs)->memory;
+ code = (*dev_proc(pdev, open_device))((gx_device *)pdev);
+ if ( code < 0 )
+ { ifree_object(pdev, "pattern_paint_prepare");
+ return code;
+ }
+ code = gs_gsave(pgs);
+ if ( code < 0 )
+ return code;
+ code = gs_setgstate(pgs, pinst->saved);
+ if ( code < 0 )
+ { gs_grestore(pgs);
+ return code;
+ }
+ gx_set_device_only(pgs, (gx_device *)pdev);
+ push_mark_estack(es_other, pattern_paint_cleanup);
+ ++esp;
+ make_istruct(esp, 0, pdev);
+ push_op_estack(pattern_paint_finish);
+ dict_find_string(pdict, "PaintProc", &ppp); /* can't fail */
+ *++esp = *ppp;
+ *++esp = *pdict; /* (push on ostack) */
+ return o_push_estack;
+}
+/* Save the rendered pattern. */
+private int
+pattern_paint_finish(os_ptr op)
+{ gx_device_pattern_accum *pdev = r_ptr(esp, gx_device_pattern_accum);
+ gx_color_tile *ctile;
+ int code = gx_pattern_cache_add_entry((gs_imager_state *)igs,
+ pdev, &ctile);
+ if ( code < 0 )
+ return code;
+ esp -= 2;
+ pattern_paint_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after rendering a pattern. Note that iff the rendering */
+/* succeeded, closing the accumulator won't free the bits. */
+private int
+pattern_paint_cleanup(os_ptr op)
+{ gx_device_pattern_accum *pdev = r_ptr(esp + 2, gx_device_pattern_accum);
+ gs_grestore(igs);
+ (*dev_proc(pdev, close_device))((gx_device *)pdev);
+ ifree_object(pdev, "pattern_paint_cleanup");
+ return 0;
+}
diff --git a/gs/src/zrelbit.c b/gs/src/zrelbit.c
new file mode 100644
index 000000000..145426cfc
--- /dev/null
+++ b/gs/src/zrelbit.c
@@ -0,0 +1,310 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zrelbit.c */
+/* Relational, boolean, and bit operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsutil.h"
+#include "idict.h"
+#include "store.h"
+
+/* ------ Standard operators ------ */
+
+/* Forward references */
+private int near obj_le(P2(os_ptr, os_ptr));
+
+/* <obj1> <obj2> eq <bool> */
+private int
+zeq(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+#define eq_check_read(opp, dflt)\
+ switch ( r_type(opp) )\
+ { case t_string: check_read(*opp); break;\
+ default: dflt; break;\
+ }
+ eq_check_read(op1, check_op(2));
+ eq_check_read(op, DO_NOTHING);
+ make_bool(op1, (obj_eq(op1, op) ? 1 : 0));
+ pop(1);
+ return 0;
+}
+
+/* <obj1> <obj2> ne <bool> */
+private int
+zne(register os_ptr op)
+{ /* We'll just be lazy and use eq. */
+ int code = zeq(op);
+ if ( !code ) op[-1].value.boolval ^= 1;
+ return code;
+}
+
+/* <num1> <num2> ge <bool> */
+/* <str1> <str2> ge <bool> */
+private int
+zge(register os_ptr op)
+{ int code = obj_le(op, op - 1);
+ if ( code < 0 ) return code;
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> gt <bool> */
+/* <str1> <str2> gt <bool> */
+private int
+zgt(register os_ptr op)
+{ int code = obj_le(op - 1, op);
+ if ( code < 0 ) return code;
+ make_bool(op - 1, code ^ 1);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> le <bool> */
+/* <str1> <str2> le <bool> */
+private int
+zle(register os_ptr op)
+{ int code = obj_le(op - 1, op);
+ if ( code < 0 ) return code;
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> lt <bool> */
+/* <str1> <str2> lt <bool> */
+private int
+zlt(register os_ptr op)
+{ int code = obj_le(op, op - 1);
+ if ( code < 0 ) return code;
+ make_bool(op - 1, code ^ 1);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> .max <num> */
+/* <str1> <str2> .max <str> */
+private int
+zmax(register os_ptr op)
+{ int code = obj_le(op - 1, op);
+ if ( code < 0 ) return code;
+ if ( code )
+ { ref_assign(op - 1, op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> .min <num> */
+/* <str1> <str2> .min <str> */
+private int
+zmin(register os_ptr op)
+{ int code = obj_le(op - 1, op);
+ if ( code < 0 ) return code;
+ if ( !code )
+ { ref_assign(op - 1, op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool1> <bool2> and <bool> */
+/* <int1> <int2> and <int> */
+private int
+zand(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval &= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval &= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool> not <bool> */
+/* <int> not <int> */
+private int
+znot(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_boolean:
+ op->value.boolval = !op->value.boolval;
+ break;
+ case t_integer:
+ op->value.intval = ~op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ return 0;
+}
+
+/* <bool1> <bool2> or <bool> */
+/* <int1> <int2> or <int> */
+private int
+zor(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval |= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval |= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool1> <bool2> xor <bool> */
+/* <int1> <int2> xor <int> */
+private int
+zxor(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval ^= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval ^= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <int> <shift> bitshift <int> */
+private int
+zbitshift(register os_ptr op)
+{ int shift;
+ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+#define max_shift (arch_sizeof_long * 8 - 1)
+ if ( op->value.intval < -max_shift || op->value.intval > max_shift )
+ op[-1].value.intval = 0;
+#undef max_shift
+ else if ( (shift = op->value.intval) < 0 )
+ op[-1].value.intval = ((ulong)(op[-1].value.intval)) >> -shift;
+ else
+ op[-1].value.intval <<= shift;
+ pop(1);
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <obj1> <obj2> .identeq <bool> */
+private int
+zidenteq(register os_ptr op)
+{ register os_ptr op1 = op - 1;
+ eq_check_read(op1, check_op(2));
+ eq_check_read(op, DO_NOTHING);
+ make_bool(op1, (obj_ident_eq(op1, op) ? 1 : 0));
+ pop(1);
+ return 0;
+
+}
+
+/* <obj1> <obj2> .identne <bool> */
+private int
+zidentne(register os_ptr op)
+{ /* We'll just be lazy and use .identeq. */
+ int code = zidenteq(op);
+ if ( !code ) op[-1].value.boolval ^= 1;
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zrelbit_op_defs) {
+ {"2and", zand},
+ {"2bitshift", zbitshift},
+ {"2eq", zeq},
+ {"2ge", zge},
+ {"2gt", zgt},
+ {"2le", zle},
+ {"2lt", zlt},
+ {"2.max", zmax},
+ {"2.min", zmin},
+ {"2ne", zne},
+ {"1not", znot},
+ {"2or", zor},
+ {"2xor", zxor},
+ /* Extensions */
+ {"2.identeq", zidenteq},
+ {"2.identne", zidentne},
+END_OP_DEFS(0) }
+
+/* ------ Internal routines ------ */
+
+/* Compare two operands (both numeric, or both strings). */
+/* Return 1 if op[-1] <= op[0], 0 if op[-1] > op[0], */
+/* or a (negative) error code. */
+#define bval(v) ((v) ? 1 : 0)
+private int near
+obj_le(register os_ptr op1, register os_ptr op)
+{ switch ( r_type(op1) )
+ {
+ case t_integer:
+ switch ( r_type(op) )
+ {
+ case t_integer:
+ return bval(op1->value.intval <= op->value.intval);
+ case t_real:
+ return bval((double)op1->value.intval <= op->value.realval);
+ default:
+ return_op_typecheck(op);
+ }
+ case t_real:
+ switch ( r_type(op) )
+ {
+ case t_real:
+ return bval(op1->value.realval <= op->value.realval);
+ case t_integer:
+ return bval(op1->value.realval <= (double)op->value.intval);
+ default:
+ return_op_typecheck(op);
+ }
+ case t_string:
+ check_read(*op1);
+ check_read_type(*op, t_string);
+ return bval(bytes_compare(op1->value.bytes, r_size(op1),
+ op->value.bytes, r_size(op)) <= 0);
+ default:
+ return_op_typecheck(op1);
+ }
+}
+#undef bval
diff --git a/gs/src/zrop.c b/gs/src/zrop.c
new file mode 100644
index 000000000..1a49f50a6
--- /dev/null
+++ b/gs/src/zrop.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zrop.c */
+/* RasterOp control operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gsrop.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "store.h"
+
+/* <int8> .setrasterop - */
+private int
+zsetrasterop(register os_ptr op)
+{ int param;
+ int code = int_param(op, 0xff, &param);
+ if ( code < 0 )
+ return code;
+ gs_setrasterop(igs, (gs_rop3_t)param);
+ pop(1);
+ return 0;
+}
+
+/* - .currentrasterop <int8> */
+private int
+zcurrentrasterop(register os_ptr op)
+{ push(1);
+ make_int(op, (int)gs_currentrasterop(igs));
+ return 0;
+}
+
+/* <int> .setrenderalgorithm - */
+private int
+zsetrenderalgorithm(register os_ptr op)
+{ int param;
+ int code = int_param(op, render_algorithm_max, &param);
+ if ( code < 0 )
+ return code;
+ gs_setrenderalgorithm(igs, param);
+ pop(1);
+ return 0;
+}
+
+/* - .currentrenderalgorithm <int> */
+private int
+zcurrentrenderalgorithm(register os_ptr op)
+{ push(1);
+ make_int(op, gs_currentrenderalgorithm(igs));
+ return 0;
+}
+
+/* <bool> .setsourcetransparent - */
+private int
+zsetsourcetransparent(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_setsourcetransparent(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currentsourcetransparent <bool> */
+private int
+zcurrentsourcetransparent(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currentsourcetransparent(igs));
+ return 0;
+}
+
+/* <bool> .settexturetransparent - */
+private int
+zsettexturetransparent(register os_ptr op)
+{ check_type(*op, t_boolean);
+ gs_settexturetransparent(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currenttexturetransparent <bool> */
+private int
+zcurrenttexturetransparent(register os_ptr op)
+{ push(1);
+ make_bool(op, gs_currenttexturetransparent(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zrop_op_defs) {
+ {"0.currentrasterop", zcurrentrasterop},
+ {"0.currentrenderalgorithm", zcurrentrenderalgorithm},
+ {"0.currentsourcetransparent", zcurrentsourcetransparent},
+ {"0.currenttexturetransparent", zcurrenttexturetransparent},
+ {"1.setrasterop", zsetrasterop},
+ {"1.setrenderalgorithm", zsetrenderalgorithm},
+ {"1.setsourcetransparent", zsetsourcetransparent},
+ {"1.settexturetransparent", zsettexturetransparent},
+END_OP_DEFS(0) }
diff --git a/gs/src/zstack.c b/gs/src/zstack.c
new file mode 100644
index 000000000..041bcdc5a
--- /dev/null
+++ b/gs/src/zstack.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 1989, 1991, 1992, 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zstack.c */
+/* Operand stack operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "istack.h"
+#include "oper.h"
+#include "store.h"
+
+/* <obj> pop - */
+int
+zpop(register os_ptr op)
+{ check_op(1);
+ pop(1);
+ return 0;
+}
+
+/* <obj1> <obj2> exch <obj2> <obj1> */
+int
+zexch(register os_ptr op)
+{ ref next;
+ check_op(2);
+ ref_assign_inline(&next, op - 1);
+ ref_assign_inline(op - 1, op);
+ ref_assign_inline(op, &next);
+ return 0;
+}
+
+/* <obj> dup <obj> <obj> */
+int
+zdup(register os_ptr op)
+{ check_op(1);
+ push(1);
+ ref_assign_inline(op, op - 1);
+ return 0;
+}
+
+/* <obj_n> ... <obj_0> <n> index <obj_n> ... <obj_0> <obj_n> */
+int
+zindex(register os_ptr op)
+{ register os_ptr opn;
+ check_type(*op, t_integer);
+ if ( (ulong)op->value.intval >= op - osbot )
+ { /* Might be in an older stack block. */
+ ref *elt;
+ if ( op->value.intval < 0 )
+ return_error(e_rangecheck);
+ elt = ref_stack_index(&o_stack, op->value.intval + 1);
+ if ( elt == 0 )
+ return_error(e_rangecheck);
+ ref_assign(op, elt);
+ return 0;
+ }
+ opn = op + ~(int)op->value.intval;
+ ref_assign_inline(op, opn);
+ return 0;
+}
+
+/* <obj_n-1> ... <obj_0> <n> <i> roll */
+/* <obj_(i-1)_mod_ n> ... <obj_0> <obj_n-1> ... <obj_i_mod_n> */
+int
+zroll(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ int count, mod;
+ register os_ptr from, to;
+ register int n;
+ check_type(*op1, t_integer);
+ check_type(*op, t_integer);
+ if ( (ulong)op1->value.intval > op1 - osbot )
+ { /*
+ * The data might span multiple stack blocks.
+ * There are efficient ways to handle this situation,
+ * but they're more complicated than seems worth implementing;
+ * for now, do something very simple and inefficient.
+ */
+ int left, i;
+ if ( op1->value.intval < 0 ||
+ op1->value.intval + 2 > ref_stack_count(&o_stack)
+ )
+ return_error(e_rangecheck);
+ count = op1->value.intval;
+ if ( count <= 1 )
+ { pop(2);
+ return 0;
+ }
+ mod = op->value.intval;
+ if ( mod >= count )
+ mod %= count;
+ else if ( mod < 0 )
+ { mod %= count;
+ if ( mod < 0 ) mod += count; /* can't assume % means mod! */
+ }
+ /* Use the chain rotation algorithm mentioned below. */
+ for ( i = 0, left = count; left; i++ )
+ { ref *elt = ref_stack_index(&o_stack, i + 2);
+ ref save;
+ int j, k;
+ ref *next;
+ save = *elt;
+ for ( j = i, left--; ; j = k, elt = next, left-- )
+ { k = (j + mod) % count;
+ if ( k == i )
+ break;
+ next = ref_stack_index(&o_stack, k + 2);
+ ref_assign(elt, next);
+ }
+ *elt = save;
+ }
+ pop(2);
+ return 0;
+ }
+ count = op1->value.intval;
+ if ( count <= 1 )
+ { pop(2);
+ return 0;
+ }
+ mod = op->value.intval;
+ /*
+ * The elegant approach, requiring no extra space, would be to
+ * rotate the elements in chains separated by mod elements.
+ * Instead, we simply check to make sure there is enough space
+ * above op to do the roll in two block moves.
+ * Unfortunately, we can't count on memcpy doing the right thing
+ * in *either* direction.
+ */
+ switch ( mod )
+ {
+ case 1: /* common special case */
+ pop(2); op -= 2;
+ { ref top;
+ ref_assign_inline(&top, op);
+ for ( from = op, n = count; --n; from-- )
+ ref_assign_inline(from, from - 1);
+ ref_assign_inline(from, &top);
+ } return 0;
+ case -1: /* common special case */
+ pop(2); op -= 2;
+ { ref bot;
+ to = op - count + 1;
+ ref_assign_inline(&bot, to);
+ for ( n = count; --n; to++ )
+ ref_assign(to, to + 1);
+ ref_assign_inline(to, &bot);
+ } return 0;
+ }
+ if ( mod < 0 )
+ { mod += count;
+ if ( mod < 0 )
+ { mod %= count;
+ if ( mod < 0 )
+ mod += count; /* can't assume % means mod! */
+ }
+ }
+ else if ( mod >= count )
+ mod %= count;
+ if ( mod <= count >> 1)
+ { /* Move everything up, then top elements down. */
+ if ( mod >= ostop - op )
+ { o_stack.requested = mod;
+ return_error(e_stackoverflow);
+ }
+ pop(2); op -= 2;
+ for ( to = op + mod, from = op, n = count; n--; to--, from-- )
+ ref_assign(to, from);
+ memcpy((char *)(from + 1), (char *)(op + 1), mod * sizeof(ref));
+ }
+ else
+ { /* Move bottom elements up, then everything down. */
+ mod = count - mod;
+ if ( mod >= ostop - op )
+ { o_stack.requested = mod;
+ return_error(e_stackoverflow);
+ }
+ pop(2); op -= 2;
+ to = op - count + 1;
+ memcpy((char *)(op + 1), (char *)to, mod * sizeof(ref));
+ for ( from = to + mod, n = count; n--; to++, from++ )
+ ref_assign(to, from);
+ }
+ return 0;
+}
+
+/* |- ... clear |- */
+/* The function name is changed, because the IRIS library has */
+/* a function called zclear. */
+private int
+zclear_stack(os_ptr op)
+{ ref_stack_clear(&o_stack);
+ return 0;
+}
+
+/* |- <obj_n-1> ... <obj_0> count <obj_n-1> ... <obj_0> <n> */
+private int
+zcount(register os_ptr op)
+{ push(1);
+ make_int(op, ref_stack_count(&o_stack) - 1);
+ return 0;
+}
+
+/* - mark <mark> */
+private int
+zmark(register os_ptr op)
+{ push(1);
+ make_mark(op);
+ return 0;
+}
+
+/* <mark> ... cleartomark */
+int
+zcleartomark(register os_ptr op)
+{ uint count = ref_stack_counttomark(&o_stack);
+ if ( count == 0 )
+ return_error(e_unmatchedmark);
+ ref_stack_pop(&o_stack, count);
+ return 0;
+}
+
+/* <mark> <obj_n-1> ... <obj_0> counttomark */
+/* <mark> <obj_n-1> ... <obj_0> <n> */
+private int
+zcounttomark(os_ptr op)
+{ uint count = ref_stack_counttomark(&o_stack);
+ if ( count == 0 )
+ return_error(e_unmatchedmark);
+ push(1);
+ make_int(op, count - 1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zstack_op_defs) {
+ {"0clear", zclear_stack},
+ {"0cleartomark", zcleartomark},
+ {"0count", zcount},
+ {"0counttomark", zcounttomark},
+ {"1dup", zdup},
+ {"2exch", zexch},
+ {"2index", zindex},
+ {"0mark", zmark},
+ {"1pop", zpop},
+ {"2roll", zroll},
+END_OP_DEFS(0) }
diff --git a/gs/src/zstring.c b/gs/src/zstring.c
new file mode 100644
index 000000000..8d4ac9103
--- /dev/null
+++ b/gs/src/zstring.c
@@ -0,0 +1,156 @@
+/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zstring.c */
+/* String operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "gsutil.h"
+#include "ialloc.h"
+#include "iname.h"
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+
+/* The generic operators (copy, get, put, getinterval, putinterval, */
+/* length, and forall) are implemented in zgeneric.c. */
+
+/* <int> string <string> */
+int
+zstring(register os_ptr op)
+{ byte *sbody;
+ uint size;
+ check_int_leu(*op, max_string_size);
+ size = op->value.intval;
+ sbody = ialloc_string(size, "string");
+ if ( sbody == 0 )
+ return_error(e_VMerror);
+ make_string(op, a_all | icurrent_space, size, sbody);
+ memset(sbody, 0, size);
+ return 0;
+}
+
+/* <name> .namestring <string> */
+private int
+znamestring(register os_ptr op)
+{ check_type(*op, t_name);
+ name_string_ref(op, op);
+ return 0;
+}
+
+/* <string> <pattern> anchorsearch <post> <match> -true- */
+/* <string> <pattern> anchorsearch <string> -false- */
+private int
+zanchorsearch(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ uint size = r_size(op);
+ check_read_type(*op1, t_string);
+ check_read_type(*op, t_string);
+ if ( size <= r_size(op1) && !memcmp(op1->value.bytes, op->value.bytes, size) )
+ { os_ptr op0 = op;
+ push(1);
+ *op0 = *op1;
+ r_set_size(op0, size);
+ op1->value.bytes += size;
+ r_dec_size(op1, size);
+ make_true(op);
+ }
+ else
+ make_false(op);
+ return 0;
+}
+
+/* <string> <pattern> search <post> <match> <pre> -true- */
+/* <string> <pattern> search <string> -false- */
+private int
+zsearch(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ uint size = r_size(op);
+ uint count;
+ byte *pat;
+ byte *ptr;
+ byte ch;
+
+ check_read_type(*op1, t_string);
+ check_read_type(*op, t_string);
+ if ( size > r_size(op1) ) /* can't match */
+ { make_false(op);
+ return 0;
+ }
+ count = r_size(op1) - size;
+ ptr = op1->value.bytes;
+ if ( size == 0 )
+ goto found;
+ pat = op->value.bytes;
+ ch = pat[0];
+ do
+ { if ( *ptr == ch && (size == 1 || !memcmp(ptr, pat, size)) )
+ goto found;
+ ptr++;
+ }
+ while ( count-- );
+ /* No match */
+ make_false(op);
+ return 0;
+found: op->tas.type_attrs = op1->tas.type_attrs;
+ op->value.bytes = ptr;
+ r_set_size(op, size);
+ push(2);
+ op[-1] = *op1;
+ r_set_size(op - 1, ptr - op[-1].value.bytes);
+ op1->value.bytes = ptr + size;
+ r_set_size(op1, count);
+ make_true(op);
+ return 0;
+}
+
+/* <obj> <pattern> .stringmatch <bool> */
+private int
+zstringmatch(register os_ptr op)
+{ os_ptr op1 = op - 1;
+ bool result;
+ check_read_type(*op, t_string);
+ switch ( r_type(op1) )
+ {
+ case t_string:
+ check_read(*op1);
+ goto cmp;
+ case t_name:
+ name_string_ref(op1, op1); /* can't fail */
+cmp: result = string_match(op1->value.const_bytes, r_size(op1),
+ op->value.const_bytes, r_size(op),
+ NULL);
+ break;
+ default:
+ result = (r_size(op) == 1 && *op->value.bytes == '*');
+ }
+ make_bool(op1, result);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zstring_op_defs) {
+ {"2anchorsearch", zanchorsearch},
+ {"1.namestring", znamestring},
+ {"2search", zsearch},
+ {"1string", zstring},
+ {"2.stringmatch", zstringmatch},
+END_OP_DEFS(0) }
diff --git a/gs/src/zsysvm.c b/gs/src/zsysvm.c
new file mode 100644
index 000000000..5fc49714c
--- /dev/null
+++ b/gs/src/zsysvm.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zsysvm.c */
+/* System VM and VM-specific operators */
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_bool */
+
+/*
+ * These operators allow creation of objects in a specific VM --
+ * local, global, or system. System VM, which is not a standard PostScript
+ * facility, is not subject to save and restore; objects in system VM
+ * may only refer to simple objects or to other (composite) objects
+ * in system VM.
+ */
+
+/* Execute an operator with a specific VM selected as current VM. */
+private int
+specific_vm_op(os_ptr op, int (*opproc)(P1(os_ptr)), uint space)
+{ uint save_space = icurrent_space;
+ int code;
+ ialloc_set_space(idmemory, space);
+ code = (*opproc)(op);
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+
+/* <int> .globalvmarray <array> */
+private int
+zglobalvmarray(os_ptr op)
+{ return specific_vm_op(op, zarray, avm_global);
+}
+
+/* <int> .globalvmdict <dict> */
+private int
+zglobalvmdict(os_ptr op)
+{ return specific_vm_op(op, zdict, avm_global);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .globalvmpackedarray <packedarray> */
+private int
+zglobalvmpackedarray(os_ptr op)
+{ return specific_vm_op(op, zpackedarray, avm_global);
+}
+
+/* <int> .globalvmstring <string> */
+private int
+zglobalvmstring(os_ptr op)
+{ return specific_vm_op(op, zstring, avm_global);
+}
+
+/* <int> .localvmarray <array> */
+private int
+zlocalvmarray(os_ptr op)
+{ return specific_vm_op(op, zarray, avm_local);
+}
+
+/* <int> .localvmdict <dict> */
+private int
+zlocalvmdict(os_ptr op)
+{ return specific_vm_op(op, zdict, avm_local);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .localvmpackedarray <packedarray> */
+private int
+zlocalvmpackedarray(os_ptr op)
+{ return specific_vm_op(op, zpackedarray, avm_local);
+}
+
+/* <int> .localvmstring <string> */
+private int
+zlocalvmstring(os_ptr op)
+{ return specific_vm_op(op, zstring, avm_local);
+}
+
+/* <int> .systemvmarray <array> */
+private int
+zsystemvmarray(os_ptr op)
+{ return specific_vm_op(op, zarray, avm_system);
+}
+
+/* <int> .systemvmdict <dict> */
+private int
+zsystemvmdict(os_ptr op)
+{ return specific_vm_op(op, zdict, avm_system);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .systemvmpackedarray <packedarray> */
+private int
+zsystemvmpackedarray(os_ptr op)
+{ return specific_vm_op(op, zpackedarray, avm_system);
+}
+
+/* <int> .systemvmstring <string> */
+private int
+zsystemvmstring(os_ptr op)
+{ return specific_vm_op(op, zstring, avm_system);
+}
+
+/* <any> .systemvmcheck <bool> */
+private int
+zsystemvmcheck(register os_ptr op)
+{ make_bool(op, (r_space(op) == avm_system ? true : false));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zsysvm_op_defs) {
+ {"1.globalvmarray", zglobalvmarray},
+ {"1.globalvmdict", zglobalvmdict},
+ {"1.globalvmpackedarray", zglobalvmpackedarray},
+ {"1.globalvmstring", zglobalvmstring},
+ {"1.localvmarray", zlocalvmarray},
+ {"1.localvmdict", zlocalvmdict},
+ {"1.localvmpackedarray", zlocalvmpackedarray},
+ {"1.localvmstring", zlocalvmstring},
+ {"1.systemvmarray", zsystemvmarray},
+ {"1.systemvmcheck", zsystemvmcheck},
+ {"1.systemvmdict", zsystemvmdict},
+ {"1.systemvmpackedarray", zsystemvmpackedarray},
+ {"1.systemvmstring", zsystemvmstring},
+END_OP_DEFS(0) }
diff --git a/gs/src/ztoken.c b/gs/src/ztoken.c
new file mode 100644
index 000000000..59a8f817e
--- /dev/null
+++ b/gs/src/ztoken.c
@@ -0,0 +1,227 @@
+/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ztoken.c */
+/* Token reading operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* for iscan.h */
+#include "stream.h"
+#include "files.h"
+#include "store.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+
+/* <file> token <obj> -true- */
+/* <string> token <post> <obj> -true- */
+/* <string|file> token -false- */
+private int ztoken_continue(P1(os_ptr));
+private int token_continue(P4(os_ptr, stream *, scanner_state *, bool));
+int
+ztoken(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ default:
+ return_op_typecheck(op);
+ case t_file:
+ { stream *s;
+ scanner_state state;
+ check_read_file(s, op);
+ check_ostack(1);
+ scanner_state_init(&state, false);
+ return token_continue(op, s, &state, true);
+ }
+ case t_string:
+ { ref token;
+ int code = scan_string_token(op, &token);
+ switch ( code )
+ {
+ case scan_EOF: /* no tokens */
+ make_false(op);
+ return 0;
+ default:
+ if ( code < 0 )
+ return code;
+ }
+ push(2);
+ op[-1] = token;
+ make_true(op);
+ return 0;
+ }
+ }
+}
+/* Continue reading a token after an interrupt or callout. */
+/* *op is the scanner state; op[-1] is the file. */
+private int
+ztoken_continue(os_ptr op)
+{ stream *s;
+ scanner_state *pstate;
+ check_read_file(s, op - 1);
+ check_stype(*op, st_scanner_state);
+ pstate = r_ptr(op, scanner_state);
+ pop(1);
+ return token_continue(osp, s, pstate, false);
+}
+/* Common code for token reading. */
+private int
+token_continue(os_ptr op, stream *s, scanner_state *pstate, bool save)
+{ int code;
+ ref token;
+ /* Note that scan_token may change osp! */
+ /* Also, we must temporarily remove the file from the o-stack */
+ /* when calling scan_token, in case we are scanning a procedure. */
+ ref fref;
+ ref_assign(&fref, op);
+again: pop(1);
+ code = scan_token(s, &token, pstate);
+ op = osp;
+ switch ( code )
+ {
+ default: /* error */
+ push(1);
+ ref_assign(op, &fref);
+ break;
+ case scan_BOS:
+ code = 0;
+ case 0: /* read a token */
+ push(2);
+ ref_assign(op - 1, &token);
+ make_true(op);
+ break;
+ case scan_EOF: /* no tokens */
+ push(1);
+ make_false(op);
+ code = 0;
+ break;
+ case scan_Refill: /* need more data */
+ push(1);
+ ref_assign(op, &fref);
+ code = scan_handle_refill(op, pstate, save, false,
+ ztoken_continue);
+ switch ( code )
+ {
+ case 0: /* state is not copied to the heap */
+ goto again;
+ case o_push_estack:
+ return code;
+ }
+ break; /* error */
+ }
+ if ( code <= 0 && !save )
+ { /* Deallocate the scanner state record. */
+ ifree_object(pstate, "token_continue");
+ }
+ return code;
+}
+
+/* <file> .tokenexec - */
+/* Read a token and do what the interpreter would do with it. */
+/* This is different from token + exec because literal procedures */
+/* are not executed (although binary object sequences ARE executed). */
+int ztokenexec_continue(P1(os_ptr)); /* export for interpreter */
+private int tokenexec_continue(P4(os_ptr, stream *, scanner_state *, bool));
+int
+ztokenexec(register os_ptr op)
+{ stream *s;
+ scanner_state state;
+ check_read_file(s, op);
+ check_estack(1);
+ scanner_state_init(&state, false);
+ return tokenexec_continue(op, s, &state, true);
+}
+/* Continue reading a token for execution after an interrupt or callout. */
+/* *op is the scanner state; op[-1] is the file. */
+/* We export this because this is how the interpreter handles a */
+/* scan_Refill for an executable file. */
+int
+ztokenexec_continue(os_ptr op)
+{ stream *s;
+ scanner_state *pstate;
+ check_read_file(s, op - 1);
+ check_stype(*op, st_scanner_state);
+ pstate = r_ptr(op, scanner_state);
+ pop(1);
+ return tokenexec_continue(osp, s, pstate, false);
+}
+/* Common code for token reading + execution. */
+private int
+tokenexec_continue(os_ptr op, stream *s, scanner_state *pstate, bool save)
+{ int code;
+ /* Note that scan_token may change osp! */
+ /* Also, we must temporarily remove the file from the o-stack */
+ /* when calling scan_token, in case we are scanning a procedure. */
+ ref fref;
+ ref_assign(&fref, op);
+ pop(1);
+again: code = scan_token(s, (ref *)(esp + 1), pstate);
+ op = osp;
+ switch ( code )
+ {
+ case 0:
+ if ( r_is_proc(esp + 1) )
+ { /* Treat procedure as a literal. */
+ push(1);
+ ref_assign(op, esp + 1);
+ code = 0;
+ break;
+ }
+ /* falls through */
+ case scan_BOS:
+ ++esp;
+ code = o_push_estack;
+ break;
+ case scan_EOF: /* no tokens */
+ code = 0;
+ break;
+ case scan_Refill: /* need more data */
+ code = scan_handle_refill(&fref, pstate, save, true,
+ ztokenexec_continue);
+ switch ( code )
+ {
+ case 0: /* state is not copied to the heap */
+ goto again;
+ case o_push_estack:
+ return code;
+ }
+ /* falls through */
+ default: /* error */
+ break;
+ }
+ if ( code < 0 )
+ { /* Push the operand back on the stack. */
+ push(1);
+ ref_assign(op, &fref);
+ }
+ if ( !save )
+ { /* Deallocate the scanner state record. */
+ ifree_object(pstate, "token_continue");
+ }
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(ztoken_op_defs) {
+ {"1token", ztoken},
+ {"1.tokenexec", ztokenexec},
+ /* Internal operators */
+ {"2%ztokenexec_continue", ztokenexec_continue},
+END_OP_DEFS(0) }
diff --git a/gs/src/ztype.c b/gs/src/ztype.c
new file mode 100644
index 000000000..27c6f4aa2
--- /dev/null
+++ b/gs/src/ztype.c
@@ -0,0 +1,463 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* ztype.c */
+/* Type, attribute, and conversion operators */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "imemory.h" /* for register_ref_root */
+#include "idict.h"
+#include "iname.h"
+#include "stream.h" /* for iscan.h */
+#include "strimpl.h" /* for sfilter.h for picky compilers */
+#include "sfilter.h" /* ditto */
+#include "iscan.h"
+#include "iutil.h"
+#include "dstack.h" /* for dict_set_top */
+#include "store.h"
+
+/* Forward references */
+private int near access_check(P3(os_ptr, int, bool));
+private int convert_to_string(P2(os_ptr, os_ptr));
+
+/*
+ * Max and min integer values expressed as reals.
+ * Note that these are biased by 1 to allow for truncation.
+ * They should be #defines rather than static consts, but
+ * several of the SCO Unix compilers apparently can't handle this.
+ * On the other hand, the DEC compiler can't handle casts in
+ * constant expressions, so we can't use min_long and max_long.
+ * What a nuisance!
+ */
+#define alt_min_long (-1L << (arch_sizeof_long * 8 - 1))
+#define alt_max_long (~(alt_min_long))
+private const double min_int_real = (alt_min_long * 1.0 - 1);
+private const double max_int_real = (alt_max_long * 1.0 + 1);
+#define real_can_be_int(v)\
+ ((v) > min_int_real && (v) < max_int_real)
+#define zcvi_possible(v) real_can_be_int(v)
+
+/* Get the pointer to the access flags for a ref. */
+#define access_ref(opp)\
+ (r_has_type(opp, t_dictionary) ? dict_access_ref(opp) : opp)
+
+/* Initialize the table of type names. */
+/* We export the type names just in case they might be useful. */
+ref type_names; /* t_array */
+private ref *type_names_p = &type_names;
+private gs_gc_root_t type_names_root;
+private void
+ztype_init(void)
+{ static const char _ds *tnames[] = { type_name_strings };
+ int i;
+ ialloc_ref_array(&type_names, a_readonly, t_next_index,
+ "type names");
+ for ( i = 0; i < t_next_index; i++ )
+ { if ( tnames[i] == 0 )
+ make_null(&type_names.value.refs[i]);
+ else
+ { name_enter_string(tnames[i],
+ &type_names.value.refs[i]);
+ r_set_attrs(&type_names.value.refs[i], a_executable);
+ }
+ }
+ gs_register_ref_root(imemory, &type_names_root,
+ (void **)&type_names_p, "type_names");
+}
+
+/* <obj> type <name> */
+private int
+ztype(register os_ptr op)
+{ ref *ptref = &type_names.value.refs[r_btype(op)];
+ if ( !r_has_type(ptref, t_name) )
+ { /* Must be either a stack underflow or a t_[a]struct. */
+ check_op(1);
+ { /* Get the type name from the structure. */
+ const char *sname =
+ gs_struct_type_name_string(gs_object_type(imemory,
+ op->value.pstruct));
+ int code = name_ref((const byte *)sname, strlen(sname),
+ (ref *)op, 0);
+ if ( code < 0 )
+ return code;
+ }
+ r_set_attrs(op, a_executable);
+ }
+ else
+ { ref_assign(op, ptref);
+ }
+ return 0;
+}
+
+/* <obj> cvlit <obj> */
+private int
+zcvlit(register os_ptr op)
+{ ref *aop;
+ check_op(1);
+ aop = access_ref(op);
+ r_clear_attrs(aop, a_executable);
+ return 0;
+}
+
+/* <obj> cvx <obj> */
+int
+zcvx(register os_ptr op)
+{ ref *aop;
+ uint opidx;
+ check_op(1);
+ /*
+ * If the object is an internal operator, we can't allow it to
+ * exist in executable form anywhere outside the e-stack.
+ */
+ if ( r_has_type(op, t_operator) &&
+ ((opidx = op_index(op)) == 0 ||
+ op_def_is_internal(op_def_table[opidx]))
+ )
+ return_error(e_rangecheck);
+ aop = access_ref(op);
+ r_set_attrs(aop, a_executable);
+ return 0;
+}
+
+/* <obj> xcheck <bool> */
+private int
+zxcheck(register os_ptr op)
+{ check_op(1);
+ make_bool(op, (r_has_attr(access_ref(op), a_executable) ? 1 : 0));
+ return 0;
+}
+
+/* <obj:array|packedarray|file|string> executeonly <obj> */
+private int
+zexecuteonly(register os_ptr op)
+{ check_op(1);
+ if ( r_has_type(op, t_dictionary) )
+ return_error(e_typecheck);
+ return access_check(op, a_execute, true);
+}
+
+/* <obj:array|packedarray|dict|file|string> noaccess <obj> */
+private int
+znoaccess(register os_ptr op)
+{ check_op(1);
+ if ( r_has_type(op, t_dictionary) )
+ { /*
+ * Setting noaccess on a read-only dictionary is an attempt to
+ * change its value, which is forbidden (this is a subtle
+ * point confirmed with Adobe). Also, don't allow removing
+ * read access to permanent dictionaries.
+ */
+ if ( dict_is_permanent_on_dstack(op) ||
+ !r_has_attr(dict_access_ref(op), a_write)
+ )
+ return_error(e_invalidaccess);
+ }
+ return access_check(op, 0, true);
+}
+
+/* <obj:array|packedarray|dict|file|string> readonly <obj> */
+int
+zreadonly(register os_ptr op)
+{ return access_check(op, a_readonly, true);
+}
+
+/* <array|packedarray|dict|file|string> rcheck <bool> */
+private int
+zrcheck(register os_ptr op)
+{ int code = access_check(op, a_read, false);
+ if ( code >= 0 ) make_bool(op, code), code = 0;
+ return code;
+}
+
+/* <array|packedarray|dict|file|string> wcheck <bool> */
+private int
+zwcheck(register os_ptr op)
+{ int code = access_check(op, a_write, false);
+ if ( code >= 0 ) make_bool(op, code), code = 0;
+ return code;
+}
+
+/* <num> cvi <int> */
+/* <string> cvi <int> */
+private int
+zcvi(register os_ptr op)
+{ float fval;
+ switch ( r_type(op) )
+ {
+ case t_integer:
+ return 0;
+ case t_real:
+ fval = op->value.realval;
+ break;
+ default:
+ return_op_typecheck(op);
+ case t_string:
+ { ref str, token;
+ int code;
+ ref_assign(&str, op);
+ code = scan_string_token(&str, &token);
+ switch ( code )
+ {
+ case scan_EOF: /* no tokens */
+ case scan_BOS: /* not allowed */
+ code = gs_note_error(e_syntaxerror);
+ default:
+ if ( code < 0 )
+ return code;
+ }
+ switch ( r_type(&token) )
+ {
+ case t_integer:
+ *op = token;
+ return 0;
+ case t_real:
+ fval = token.value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ }
+ /* Check if a real will fit into an integer value */
+ if ( !zcvi_possible(fval) )
+ return_error(e_rangecheck);
+ make_int(op, (long)fval); /* truncates towards 0 */
+ return 0;
+}
+
+/* <string> cvn <name> */
+private int
+zcvn(register os_ptr op)
+{ check_read_type(*op, t_string);
+ return name_from_string(op, op);
+}
+
+/* <num> cvr <real> */
+/* <string> cvr <real> */
+private int
+zcvr(register os_ptr op)
+{ switch ( r_type(op) )
+ {
+ case t_integer:
+ make_real(op, op->value.intval);
+ case t_real:
+ return 0;
+ default:
+ return_op_typecheck(op);
+ case t_string:
+ { ref str, token;
+ int code;
+ ref_assign(&str, op);
+ code = scan_string_token(&str, &token);
+ switch ( code )
+ {
+ case scan_EOF: /* no tokens */
+ case scan_BOS: /* not allowed */
+ code = gs_note_error(e_syntaxerror);
+ default:
+ if ( code < 0 )
+ return code;
+ }
+ switch ( r_type(&token) )
+ {
+ case t_integer:
+ make_real(op, token.value.intval);
+ return 0;
+ case t_real:
+ *op = token;
+ return 0;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ }
+}
+
+/* <num> <radix_int> <string> cvrs <substring> */
+private int
+zcvrs(register os_ptr op)
+{ int radix;
+ check_type(op[-1], t_integer);
+ if ( op[-1].value.intval < 2 || op[-1].value.intval > 36 )
+ return_error(e_rangecheck);
+ radix = op[-1].value.intval;
+ check_write_type(*op, t_string);
+ if ( radix == 10 )
+ { switch ( r_type(op - 2) )
+ {
+ case t_integer: case t_real:
+ { int code = convert_to_string(op - 2, op);
+ if ( code < 0 ) return code;
+ pop(2);
+ return 0;
+ }
+ default:
+ return_op_typecheck(op - 2);
+ }
+ }
+ else
+ { ulong ival;
+ byte digits[sizeof(ulong) * 8];
+ byte *endp = &digits[countof(digits)];
+ byte *dp = endp;
+ switch ( r_type(op - 2) )
+ {
+ case t_integer:
+ ival = (ulong)op[-2].value.intval;
+ break;
+ case t_real:
+ { float fval = op[-2].value.realval;
+ if ( !real_can_be_int(fval) )
+ return_error(e_rangecheck);
+ ival = (ulong)(long)fval;
+ } break;
+ default:
+ return_op_typecheck(op - 2);
+ }
+ do
+ { int dit = ival % radix;
+ *--dp = dit + (dit < 10 ? '0' : ('A' - 10));
+ ival /= radix;
+ }
+ while ( ival );
+ if ( endp - dp > r_size(op) ) return_error(e_rangecheck);
+ memcpy(op->value.bytes, dp, (uint)(endp - dp));
+ r_set_size(op, endp - dp);
+ }
+ op[-2] = *op;
+ pop(2);
+ return 0;
+}
+
+/* <any> <string> cvs <substring> */
+private int
+zcvs(register os_ptr op)
+{ int code;
+ check_op(2);
+ check_write_type(*op, t_string);
+ code = convert_to_string(op - 1, op);
+ if ( code >= 0 ) pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(ztype_op_defs) {
+ {"1cvi", zcvi},
+ {"1cvlit", zcvlit},
+ {"1cvn", zcvn},
+ {"1cvr", zcvr},
+ {"3cvrs", zcvrs},
+ {"2cvs", zcvs},
+ {"1cvx", zcvx},
+ {"1executeonly", zexecuteonly},
+ {"1noaccess", znoaccess},
+ {"1rcheck", zrcheck},
+ {"1readonly", zreadonly},
+ {"1type", ztype},
+ {"1wcheck", zwcheck},
+ {"1xcheck", zxcheck},
+END_OP_DEFS(ztype_init) }
+
+/* ------ Internal routines ------ */
+
+/* Test or modify the access of an object. */
+/* If modify = true, restrict to the selected access and return 0; */
+/* if modify = false, do not change the access, and return 1 */
+/* if the object had the access. */
+/* Return an error code if the object is not of appropriate type, */
+/* or if the object did not have the access already when modify=1. */
+private int near
+access_check(os_ptr op,
+ int access, /* mask for attrs */
+ bool modify) /* if true, reduce access */
+{ ref *aop;
+ switch ( r_type(op) )
+ {
+ case t_dictionary:
+ aop = dict_access_ref(op);
+ if ( modify )
+ { if ( !r_has_attrs(aop, access) )
+ return_error(e_invalidaccess);
+ ref_save(op, aop, "access_check(modify)");
+ r_clear_attrs(aop, a_all);
+ r_set_attrs(aop, access);
+ dict_set_top();
+ return 0;
+ }
+ break;
+ case t_array: case t_file: case t_string:
+ case t_mixedarray: case t_shortarray:
+ case t_astruct: case t_device: ;
+ if ( modify )
+ { if ( !r_has_attrs(op, access) )
+ return_error(e_invalidaccess);
+ r_clear_attrs(op, a_all);
+ r_set_attrs(op, access);
+ return 0;
+ }
+ aop = op;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ return (r_has_attrs(aop, access)? 1 : 0);
+}
+
+/* Do all the work of cvs. The destination has been checked, but not */
+/* the source. This is a separate procedure so that */
+/* cvrs can use it when the radix is 10. */
+private int
+convert_to_string(os_ptr op1, os_ptr op)
+{ uint len;
+ const byte *pstr = 0;
+ int code = obj_cvs(op1, op->value.bytes, r_size(op), &len, &pstr);
+
+ if ( code < 0 )
+ { /* Some common downloaded error handlers assume that */
+ /* operator names don't exceed a certain fixed size. */
+ /* To work around this bit of bad design, we implement */
+ /* a special hack here: if we got a rangecheck, and */
+ /* the object is an operator whose name begins with */
+ /* %, ., or @, we just truncate the name. */
+ if ( code == e_rangecheck )
+ switch ( r_btype(op1) )
+ {
+ case t_oparray:
+ case t_operator:
+ if ( pstr != 0 )
+ switch ( *pstr )
+ {
+ case '%':
+ case '.':
+ case '@':
+ len = r_size(op);
+ memcpy(op->value.bytes, pstr, len);
+ goto ok;
+ }
+ }
+ return code;
+ }
+ok: *op1 = *op;
+ r_set_size(op1, len);
+ return 0;
+}
diff --git a/gs/src/zupath.c b/gs/src/zupath.c
new file mode 100644
index 000000000..b364d6138
--- /dev/null
+++ b/gs/src/zupath.c
@@ -0,0 +1,561 @@
+/* Copyright (C) 1990, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zupath.c */
+/* Operators related to user paths */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "idict.h"
+#include "dstack.h"
+#include "igstate.h"
+#include "iutil.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gscoord.h"
+#include "gspaint.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gspath.h"
+#include "gzpath.h" /* for saving path */
+#include "gzstate.h" /* for accessing path */
+
+/* Forward references */
+private int upath_append(P2(os_ptr, os_ptr));
+private int upath_stroke(P1(os_ptr));
+
+/* ------ Insideness testing ------ */
+
+/* Forward references */
+private int in_test(P2(os_ptr, int (*)(P1(gs_state *))));
+private int in_path(P3(os_ptr, os_ptr, gx_device *));
+private int in_path_result(P3(os_ptr, int, int));
+private int in_utest(P2(os_ptr, int (*)(P1(gs_state *))));
+private int in_upath(P2(os_ptr, gx_device *));
+private int in_upath_result(P3(os_ptr, int, int));
+
+/* We use invalidexit, which the painting procedures cannot generate, */
+/* as an "error" to indicate that the hit detection device found a hit. */
+#define e_hit e_invalidexit
+
+/* <x> <y> ineofill <bool> */
+/* <userpath> ineofill <bool> */
+private int
+zineofill(os_ptr op)
+{ return in_test(op, gs_eofill);
+}
+
+/* <x> <y> infill <bool> */
+/* <userpath> infill <bool> */
+private int
+zinfill(os_ptr op)
+{ return in_test(op, gs_fill);
+}
+
+/* <x> <y> instroke <bool> */
+/* <userpath> instroke <bool> */
+private int
+zinstroke(os_ptr op)
+{ return in_test(op, gs_stroke);
+}
+
+/* <x> <y> <userpath> inueofill <bool> */
+/* <userpath1> <userpath2> inueofill <bool> */
+private int
+zinueofill(os_ptr op)
+{ return in_utest(op, gs_eofill);
+}
+
+/* <x> <y> <userpath> inufill <bool> */
+/* <userpath1> <userpath2> inufill <bool> */
+private int
+zinufill(os_ptr op)
+{ return in_utest(op, gs_fill);
+}
+
+/* <x> <y> <userpath> inustroke <bool> */
+/* <userpath1> <userpath2> inustroke <bool> */
+private int
+zinustroke(os_ptr op)
+{ /* This is different because of the optional matrix operand. */
+ int code = gs_gsave(igs);
+ int spop, npop;
+ gx_device hdev;
+
+ if ( code < 0 )
+ return code;
+ if ( (spop = upath_stroke(op)) < 0 )
+ { gs_grestore(igs);
+ return spop;
+ }
+ if ( (npop = in_path(op - spop, op, &hdev)) < 0 )
+ { gs_grestore(igs);
+ return npop;
+ }
+ code = gs_stroke(igs);
+ return in_upath_result(op, npop + spop, code);
+}
+
+/* ------ Internal routines ------ */
+
+/* Define a minimal device for insideness testing. */
+/* It returns e_hit whenever it is asked to actually paint any pixels. */
+private dev_proc_fill_rectangle(hit_fill_rectangle);
+private gx_device hit_device =
+{ std_device_std_body(gx_device, 0, "hit detector",
+ 0, 0, 1, 1),
+ { NULL, /* open_device */
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ NULL, /* close_device */
+ gx_default_map_rgb_color,
+ gx_default_map_color_rgb,
+ hit_fill_rectangle,
+ NULL, /* tile_rectangle */
+ NULL, /* copy_mono */
+ NULL, /* copy_color */
+ gx_default_draw_line,
+ NULL, /* get_bits */
+ NULL, /* get_params */
+ NULL, /* put_params */
+ gx_default_map_cmyk_color,
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ gx_default_map_rgb_alpha_color,
+ gx_default_get_page_device,
+ gx_default_get_alpha_bits,
+ NULL, /* copy_alpha */
+ gx_default_get_band,
+ NULL, /* copy_rop */
+ gx_default_fill_path,
+ NULL, /* stroke_path */
+ NULL, /* fill_mask */
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ gx_default_strip_tile_rectangle,
+ gx_default_strip_copy_rop,
+ gx_get_largest_clipping_box,
+ NULL /* get_hardware_params */
+ }
+};
+/* Test for a hit when filling a rectangle. */
+private int
+hit_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ fit_fill(dev, x, y, w, h); /* returns 0 if empty rectangle */
+ return e_hit;
+}
+
+/* Do the work of the non-user-path insideness operators. */
+private int
+in_test(os_ptr op, int (*paintproc)(P1(gs_state *)))
+{ gx_device hdev;
+ int npop = in_path(op, op, &hdev);
+ int code;
+
+ if ( npop < 0 ) return npop;
+ code = (*paintproc)(igs);
+ return in_path_result(op, npop, code);
+}
+
+/* Set up a clipping path and device for insideness testing. */
+private int
+in_path(os_ptr oppath, os_ptr op, gx_device *phdev)
+{ int code = gs_gsave(igs);
+ int npop;
+ double uxy[2];
+
+ if ( code < 0 )
+ return code;
+ code = num_params(oppath, 2, uxy);
+ if ( code >= 0 )
+ { /* Aperture is a single pixel. */
+ gs_point dxy;
+ gs_fixed_rect fr;
+
+ gs_transform(igs, uxy[0], uxy[1], &dxy);
+ fr.p.x = fixed_floor(float2fixed(dxy.x));
+ fr.p.y = fixed_floor(float2fixed(dxy.y));
+ fr.q.x = fr.p.x + fixed_1;
+ fr.q.y = fr.p.y + fixed_1;
+ code = gx_clip_to_rectangle(igs, &fr);
+ npop = 2;
+ }
+ else
+ { /* Aperture is a user path. */
+ /* We have to set the clipping path without disturbing */
+ /* the current path. */
+ gx_path save;
+ save = *igs->path;
+ gx_path_reset(igs->path); /* prevent newpath from */
+ /* releasing path */
+ code = upath_append(oppath, op);
+ if ( code >= 0 )
+ code = gx_clip_to_path(igs);
+ gs_newpath(igs); /* release upath */
+ *igs->path = save;
+ npop = 1;
+ }
+ if ( code < 0 )
+ { gs_grestore(igs);
+ return code;
+ }
+ /* Install the hit detection device. */
+ gx_set_device_color_1(igs);
+ *phdev = hit_device;
+ phdev->width = phdev->height = max_int;
+ gx_device_fill_in_procs(phdev);
+ gx_set_device_only(igs, phdev);
+ return npop;
+}
+
+/* Finish an insideness test. */
+private int
+in_path_result(os_ptr op, int npop, int code)
+{ int result;
+ gs_grestore(igs); /* matches gsave in in_path */
+ switch ( code )
+ {
+ case e_hit: /* found a hit */
+ result = 1;
+ break;
+ case 0: /* completed painting without a hit */
+ result = 0;
+ break;
+ default: /* error */
+ return code;
+ }
+ npop--;
+ pop(npop); op -= npop;
+ make_bool(op, result);
+ return 0;
+
+}
+
+/* Do the work of the user-path insideness operators. */
+private int
+in_utest(os_ptr op, int (*paintproc)(P1(gs_state *)))
+{ gx_device hdev;
+ int npop = in_upath(op, &hdev);
+ int code;
+
+ if ( npop < 0 ) return npop;
+ code = (*paintproc)(igs);
+ return in_upath_result(op, npop, code);
+}
+
+/* Set up a clipping path and device for insideness testing */
+/* with a user path. */
+private int
+in_upath(os_ptr op, gx_device *phdev)
+{ int code = gs_gsave(igs);
+ int npop;
+
+ if ( code < 0 ) return code;
+ if ( (code = upath_append(op, op)) < 0 ||
+ (npop = in_path(op - 1, op, phdev)) < 0
+ )
+ { gs_grestore(igs);
+ return code;
+ }
+ return npop + 1;
+}
+
+/* Finish an insideness test with a user path. */
+private int
+in_upath_result(os_ptr op, int npop, int code)
+{ gs_grestore(igs); /* matches gsave in in_upath */
+ return in_path_result(op, npop, code);
+}
+
+/* ------ User paths ------ */
+
+/* User path operator codes */
+typedef enum {
+ upath_setbbox = 0,
+ upath_moveto = 1,
+ upath_rmoveto = 2,
+ upath_lineto = 3,
+ upath_rlineto = 4,
+ upath_curveto = 5,
+ upath_rcurveto = 6,
+ upath_arc = 7,
+ upath_arcn = 8,
+ upath_arct = 9,
+ upath_closepath = 10,
+ upath_ucache = 11
+} upath_op;
+#define upath_op_max 11
+#define upath_repeat 32
+static byte up_nargs[upath_op_max + 1] =
+ { 4, 2, 2, 2, 2, 6, 6, 5, 5, 5, 0, 0 };
+/* Declare operator procedures not declared in opextern.h. */
+int zsetbbox(P1(os_ptr));
+int zarc(P1(os_ptr));
+int zarcn(P1(os_ptr));
+int zarct(P1(os_ptr));
+private int zucache(P1(os_ptr));
+#undef zp
+static op_proc_p up_ops[upath_op_max + 1] =
+ { zsetbbox, zmoveto, zrmoveto, zlineto, zrlineto,
+ zcurveto, zrcurveto, zarc, zarcn, zarct,
+ zclosepath, zucache
+ };
+
+/* - ucache - */
+private int
+zucache(os_ptr op)
+{ /* A no-op for now. */
+ return 0;
+}
+
+/* <userpath> uappend - */
+private int
+zuappend(register os_ptr op)
+{ int code = gs_gsave(igs);
+ if ( code < 0 ) return code;
+ if ( (code = upath_append(op, op)) >= 0 )
+ code = gs_upmergepath(igs);
+ gs_grestore(igs);
+ if ( code < 0 ) return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ueofill - */
+private int
+zueofill(register os_ptr op)
+{ int code = gs_gsave(igs);
+ if ( code < 0 ) return code;
+ if ( (code = upath_append(op, op)) >= 0 )
+ code = gs_eofill(igs);
+ gs_grestore(igs);
+ if ( code < 0 ) return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ufill - */
+private int
+zufill(register os_ptr op)
+{ int code = gs_gsave(igs);
+ if ( code < 0 ) return code;
+ if ( (code = upath_append(op, op)) >= 0 )
+ code = gs_fill(igs);
+ gs_grestore(igs);
+ if ( code < 0 ) return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ustroke - */
+/* <userpath> <matrix> ustroke - */
+private int
+zustroke(register os_ptr op)
+{ int code = gs_gsave(igs);
+ int npop;
+ if ( code < 0 ) return code;
+ if ( (code = npop = upath_stroke(op)) >= 0 )
+ code = gs_stroke(igs);
+ gs_grestore(igs);
+ if ( code < 0 ) return code;
+ pop(npop);
+ return 0;
+}
+
+/* <userpath> ustrokepath - */
+/* <userpath> <matrix> ustrokepath - */
+private int
+zustrokepath(register os_ptr op)
+{ gx_path save;
+ int code, npop;
+
+ /* Save and reset the path. */
+ save = *igs->path;
+ gx_path_reset(igs->path);
+ if ( (code = npop = upath_stroke(op)) < 0 ||
+ (code = gs_strokepath(igs)) < 0
+ )
+ { gs_newpath(igs); /* release partial path */
+ *igs->path = save;
+ return code;
+ }
+ gx_path_release(&save);
+ pop(npop);
+ return 0;
+}
+
+/* --- Internal routines --- */
+
+/* Append a user path to the current path. */
+private int
+upath_append(os_ptr oppath, os_ptr op)
+{ check_read(*oppath);
+ gs_newpath(igs);
+ /****** ROUND tx AND ty ******/
+ if ( r_has_type(oppath, t_array) && r_size(oppath) == 2 &&
+ r_has_type(oppath->value.refs + 1, t_string)
+ )
+ { /* 1st element is operators, 2nd is operands */
+ const ref *operands = oppath->value.refs;
+ int code, format;
+ int repcount = 1;
+ const byte *opp;
+ uint ocount, i = 0;
+
+ code = num_array_format(operands);
+ if ( code < 0 )
+ return code;
+ format = code;
+ opp = oppath->value.refs[1].value.bytes;
+ ocount = r_size(&oppath->value.refs[1]);
+ while ( ocount-- )
+ { byte opx = *opp++;
+ if ( opx > 32 )
+ repcount = opx - 32;
+ else if ( opx > upath_op_max )
+ return_error(e_rangecheck);
+ else /* operator */
+ { do
+ { byte opargs = up_nargs[opx];
+ while ( opargs-- )
+ { push(1);
+ code = num_array_get(operands, format, i++, op);
+ switch ( code )
+ {
+ case t_integer:
+ r_set_type_attrs(op, t_integer, 0);
+ break;
+ case t_real:
+ r_set_type_attrs(op, t_real, 0);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ code = (*up_ops[opx])(op);
+ if ( code < 0 ) return code;
+ op = osp; /* resync */
+ }
+ while ( --repcount );
+ repcount = 1;
+ }
+ }
+ }
+ else if ( r_is_array(oppath) )
+ { /* Ordinary executable array. */
+ const ref *arp = oppath;
+ uint ocount = r_size(oppath);
+ long index = 0;
+ int argcount = 0;
+ int (*oproc)(P1(os_ptr));
+ int opx, code;
+
+ for ( ; index < ocount; index++ )
+ { ref rup;
+ ref *defp;
+
+ array_get(arp, index, &rup);
+ switch ( r_type(&rup) )
+ {
+ case t_integer:
+ case t_real:
+ argcount++;
+ push(1);
+ *op = rup;
+ break;
+ case t_name:
+ if ( !r_has_attr(&rup, a_executable) )
+ return_error(e_typecheck);
+ if ( dict_find(systemdict, &rup, &defp) <= 0 )
+ return_error(e_undefined);
+ if ( r_btype(defp) != t_operator )
+ return_error(e_typecheck);
+ goto xop;
+ case t_operator:
+ defp = &rup;
+xop: if ( !r_has_attr(defp, a_executable) )
+ return_error(e_typecheck);
+ oproc = real_opproc(defp);
+ for ( opx = 0; opx <= upath_op_max; opx++ )
+ if ( oproc == up_ops[opx] ) break;
+ if ( opx > upath_op_max || argcount != up_nargs[opx] )
+ return_error(e_typecheck);
+ code = (*oproc)(op);
+ if ( code < 0 ) return code;
+ op = osp; /* resync ostack pointer */
+ argcount = 0;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ if ( argcount )
+ return_error(e_typecheck); /* leftover args */
+ }
+ else
+ return_error(e_typecheck);
+ return 0;
+}
+
+/* Append a user path to the current path, and then apply */
+/* a transformation if one is supplied. */
+private int
+upath_stroke(register os_ptr op)
+{ int code, npop;
+ gs_matrix mat;
+ if ( (code = read_matrix(op, &mat)) >= 0 )
+ { if ( (code = upath_append(op - 1, op)) >= 0 )
+ code = gs_concat(igs, &mat);
+ npop = 2;
+ }
+ else
+ { code = upath_append(op, op);
+ npop = 1;
+ }
+ return (code < 0 ? code : npop);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zupath_l2_op_defs) {
+ op_def_begin_level2(),
+ /* Insideness testing */
+ {"1ineofill", zineofill},
+ {"1infill", zinfill},
+ {"1instroke", zinstroke},
+ {"2inueofill", zinueofill},
+ {"2inufill", zinufill},
+ {"2inustroke", zinustroke},
+ /* User paths */
+ {"1uappend", zuappend},
+ {"1ueofill", zueofill},
+ {"1ufill", zufill},
+ {"1ustroke", zustroke},
+ {"1ustrokepath", zustrokepath},
+ {"0ucache", zucache},
+END_OP_DEFS(0) }
diff --git a/gs/src/zusparam.c b/gs/src/zusparam.c
new file mode 100644
index 000000000..a8ed7ed30
--- /dev/null
+++ b/gs/src/zusparam.c
@@ -0,0 +1,572 @@
+/* Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zusparam.c */
+/* User and system parameter operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "gscdefs.h"
+#include "gsstruct.h" /* for gxht.h */
+#include "gsfont.h" /* for user params */
+#include "gxht.h" /* for user params */
+#include "gsutil.h"
+#include "estack.h"
+#include "ialloc.h" /* for imemory for status */
+#include "idict.h"
+#include "idparam.h"
+#include "iparam.h"
+#include "dstack.h"
+#include "iname.h"
+#include "iutil2.h"
+#include "store.h"
+
+/* The (global) font directory */
+extern gs_font_dir *ifont_dir; /* in zfont.c */
+
+/* Import the GC parameters from zvmem2.c. */
+extern int set_vm_reclaim(P1(long));
+extern int set_vm_threshold(P1(long));
+
+/* The system passwords. */
+private password StartJobPassword = NULL_PASSWORD;
+password SystemParamsPassword = NULL_PASSWORD; /* exported for ziodev2.c. */
+
+/* Define an individual user or system parameter. */
+/* Eventually this will be made public. */
+#define param_def_common\
+ const char _ds *pname
+typedef struct param_def_s {
+ param_def_common;
+} param_def;
+typedef struct long_param_def_s {
+ param_def_common;
+ long min_value, max_value;
+ long (*current)(P0());
+ int (*set)(P1(long));
+} long_param_def;
+#if arch_sizeof_long > arch_sizeof_int
+# define max_uint_param max_uint
+#else
+# define max_uint_param max_long
+#endif
+typedef struct bool_param_def_s {
+ param_def_common;
+ bool (*current)(P0());
+ int (*set)(P1(bool));
+} bool_param_def;
+typedef struct string_param_def_s {
+ param_def_common;
+ void (*current)(P1(gs_param_string *));
+ int (*set)(P1(gs_param_string *));
+} string_param_def;
+/* Define a parameter set (user or system). */
+typedef struct param_set_s {
+ const long_param_def *long_defs;
+ uint long_count;
+ const bool_param_def *bool_defs;
+ uint bool_count;
+ const string_param_def *string_defs;
+ uint string_count;
+} param_set;
+
+/* Forward references */
+private int setparams(P2(gs_param_list *, const param_set _ds *));
+private int currentparams(P2(os_ptr, const param_set _ds *));
+private int currentparam1(P2(os_ptr, const param_set _ds *));
+
+/* ------ Passwords ------ */
+
+#define plist ((gs_param_list *)&list)
+
+/* <string|int> .checkpassword <0|1|2> */
+private int
+zcheckpassword(register os_ptr op)
+{ ref params[2];
+ array_param_list list;
+ int result = 0;
+ int code = name_ref((const byte *)"Password", 8, &params[0], 0);
+
+ if ( code < 0 )
+ return code;
+ params[1] = *op;
+ array_param_list_read(&list, params, 2, NULL, false);
+ if ( param_check_password(plist, &StartJobPassword) == 0 )
+ result = 1;
+ if ( param_check_password(plist, &SystemParamsPassword) == 0 )
+ result = 2;
+ iparam_list_release(&list);
+ make_int(op, result);
+ return 0;
+}
+
+#undef plist
+
+/* ------ System parameters ------ */
+
+/* Integer values */
+private long
+current_BuildTime(void)
+{ return gs_buildtime;
+}
+private long
+current_MaxFontCache(void)
+{ return gs_currentcachesize(ifont_dir);
+}
+private int
+set_MaxFontCache(long val)
+{ return gs_setcachesize(ifont_dir,
+ (uint)(val < 0 ? 0 : val > max_uint ? max_uint :
+ val));
+}
+private long
+current_CurFontCache(void)
+{ uint cstat[7];
+ gs_cachestatus(ifont_dir, cstat);
+ return cstat[0];
+}
+private long
+current_MaxGlobalVM(void)
+{ gs_memory_gc_status_t stat;
+ gs_memory_gc_status(iimemory_global, &stat);
+ return stat.max_vm;
+}
+private int
+set_MaxGlobalVM(long val)
+{ gs_memory_gc_status_t stat;
+ gs_memory_gc_status(iimemory_global, &stat);
+ stat.max_vm = max(val, 0);
+ gs_memory_set_gc_status(iimemory_global, &stat);
+ return 0;
+}
+private long
+current_Revision(void)
+{ return gs_revision;
+}
+private const long_param_def system_long_params[] = {
+ {"BuildTime", 0, max_uint_param, current_BuildTime, NULL},
+ {"MaxFontCache", 0, max_uint_param, current_MaxFontCache, set_MaxFontCache},
+ {"CurFontCache", 0, max_uint_param, current_CurFontCache, NULL},
+ {"Revision", 0, max_uint_param, current_Revision, NULL},
+ /* Extensions */
+ {"MaxGlobalVM", 0, max_uint_param, current_MaxGlobalVM, set_MaxGlobalVM}
+};
+/* Boolean values */
+private bool
+current_ByteOrder(void)
+{ return !arch_is_big_endian;
+}
+private const bool_param_def system_bool_params[] = {
+ {"ByteOrder", current_ByteOrder, NULL}
+};
+/* String values */
+private void
+current_RealFormat(gs_param_string *pval)
+{
+#if arch_floats_are_IEEE
+ static const char *rfs = "IEEE";
+#else
+ static const char *rfs = "not IEEE";
+#endif
+ pval->data = (const byte *)rfs;
+ pval->size = strlen(rfs);
+ pval->persistent = true;
+}
+private const string_param_def system_string_params[] = {
+ {"RealFormat", current_RealFormat, NULL}
+};
+
+/* The system parameter set */
+private const param_set system_param_set = {
+ system_long_params, countof(system_long_params),
+ system_bool_params, countof(system_bool_params),
+ system_string_params, countof(system_string_params)
+};
+
+/* <dict> setsystemparams - */
+private int
+zsetsystemparams(register os_ptr op)
+{ int code;
+ dict_param_list list;
+ password pass;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if ( code < 0 )
+ return code;
+#define plist ((gs_param_list *)&list)
+ code = param_check_password(plist, &SystemParamsPassword);
+ if ( code != 0 )
+ { if ( code > 0 )
+ code = gs_note_error(e_invalidaccess);
+ goto out;
+ }
+ code = param_read_password(plist, "StartJobPassword", &pass);
+ switch ( code )
+ {
+ default: /* invalid */
+ goto out;
+ case 1: /* missing */
+ break;
+ case 0:
+ StartJobPassword = pass;
+ }
+ code = param_read_password(plist, "SystemParamsPassword", &pass);
+ switch ( code )
+ {
+ default: /* invalid */
+ goto out;
+ case 1: /* missing */
+ break;
+ case 0:
+ SystemParamsPassword = pass;
+ }
+ code = setparams(plist, &system_param_set);
+out: iparam_list_release(&list);
+ if ( code < 0 )
+ return code;
+#undef plist
+ pop(1);
+ return 0;
+}
+
+/* - .currentsystemparams <name1> <value1> ... */
+private int
+zcurrentsystemparams(os_ptr op)
+{ return currentparams(op, &system_param_set);
+}
+
+/* <name> .getsystemparam <value> */
+private int
+zgetsystemparam(os_ptr op)
+{ return currentparam1(op, &system_param_set);
+}
+
+/* ------ User parameters ------ */
+
+/* Integer values */
+private long
+current_JobTimeout(void)
+{ return 0;
+}
+private int
+set_JobTimeout(long val)
+{ return 0;
+}
+private long
+current_MaxFontItem(void)
+{ return gs_currentcacheupper(ifont_dir);
+}
+private int
+set_MaxFontItem(long val)
+{ return gs_setcacheupper(ifont_dir, val);
+}
+private long
+current_MinFontCompress(void)
+{ return gs_currentcachelower(ifont_dir);
+}
+private int
+set_MinFontCompress(long val)
+{ return gs_setcachelower(ifont_dir, val);
+}
+private long
+current_MaxOpStack(void)
+{ return ref_stack_max_count(&o_stack);
+}
+private int
+set_MaxOpStack(long val)
+{ return ref_stack_set_max_count(&o_stack, val);
+}
+private long
+current_MaxDictStack(void)
+{ return ref_stack_max_count(&d_stack);
+}
+private int
+set_MaxDictStack(long val)
+{ return ref_stack_set_max_count(&d_stack, val);
+}
+private long
+current_MaxExecStack(void)
+{ return ref_stack_max_count(&e_stack);
+}
+private int
+set_MaxExecStack(long val)
+{ return ref_stack_set_max_count(&e_stack, val);
+}
+private long
+current_MaxLocalVM(void)
+{ gs_memory_gc_status_t stat;
+ gs_memory_gc_status(iimemory_local, &stat);
+ return stat.max_vm;
+}
+private int
+set_MaxLocalVM(long val)
+{ gs_memory_gc_status_t stat;
+ gs_memory_gc_status(iimemory_local, &stat);
+ stat.max_vm = max(val, 0);
+ gs_memory_set_gc_status(iimemory_local, &stat);
+ return 0;
+}
+private long
+current_VMReclaim(void)
+{ gs_memory_gc_status_t gstat, lstat;
+ gs_memory_gc_status(iimemory_global, &gstat);
+ gs_memory_gc_status(iimemory_local, &lstat);
+ return (!gstat.enabled ? -2 : !lstat.enabled ? -1 : 0);
+}
+private long
+current_VMThreshold(void)
+{ gs_memory_gc_status_t stat;
+ gs_memory_gc_status(iimemory_local, &stat);
+ return stat.vm_threshold;
+}
+#define current_WaitTimeout current_JobTimeout
+#define set_WaitTimeout set_JobTimeout
+private long
+current_MinScreenLevels(void)
+{ return gs_currentminscreenlevels();
+}
+private int
+set_MinScreenLevels(long val)
+{ gs_setminscreenlevels((uint)val);
+ return 0;
+}
+private const long_param_def user_long_params[] = {
+ {"JobTimeout", 0, max_uint_param,
+ current_JobTimeout, set_JobTimeout},
+ {"MaxFontItem", 0, max_uint_param,
+ current_MaxFontItem, set_MaxFontItem},
+ {"MinFontCompress", 0, max_uint_param,
+ current_MinFontCompress, set_MinFontCompress},
+ {"MaxOpStack", 0, max_uint_param,
+ current_MaxOpStack, set_MaxOpStack},
+ {"MaxDictStack", 0, max_uint_param,
+ current_MaxDictStack, set_MaxDictStack},
+ {"MaxExecStack", 0, max_uint_param,
+ current_MaxExecStack, set_MaxExecStack},
+ {"MaxLocalVM", 0, max_uint_param,
+ current_MaxLocalVM, set_MaxLocalVM},
+ {"VMReclaim", -2, 0,
+ current_VMReclaim, set_vm_reclaim},
+ {"VMThreshold", 0, max_uint_param,
+ current_VMThreshold, set_vm_threshold},
+ {"WaitTimeout", 0, max_uint_param,
+ current_WaitTimeout, set_WaitTimeout},
+ /* Extensions */
+ {"MinScreenLevels", 0, max_uint_param,
+ current_MinScreenLevels, set_MinScreenLevels}
+};
+/* Boolean values */
+private bool
+current_AccurateScreens(void)
+{ return gs_currentaccuratescreens();
+}
+private int
+set_AccurateScreens(bool val)
+{ gs_setaccuratescreens(val);
+ return 0;
+}
+private const bool_param_def user_bool_params[] = {
+ {"AccurateScreens", current_AccurateScreens, set_AccurateScreens}
+};
+/* String values */
+private void
+current_JobName(gs_param_string *pval)
+{ pval->data = 0;
+ pval->size = 0;
+ pval->persistent = true;
+}
+private int
+set_JobName(gs_param_string *val)
+{ return 0;
+}
+private const string_param_def user_string_params[] = {
+ {"JobName", current_JobName, set_JobName}
+};
+
+/* The user parameter set */
+private const param_set user_param_set = {
+ user_long_params, countof(user_long_params),
+ user_bool_params, countof(user_bool_params),
+ user_string_params, countof(user_string_params)
+};
+
+/* <dict> setuserparams - */
+private int
+zsetuserparams(register os_ptr op)
+{ dict_param_list list;
+ int code;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if ( code < 0 )
+ return code;
+ code = setparams((gs_param_list *)&list, &user_param_set);
+ iparam_list_release(&list);
+ if ( code < 0 )
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - .currentuserparams <name1> <value1> ... */
+private int
+zcurrentuserparams(os_ptr op)
+{ return currentparams(op, &user_param_set);
+}
+
+/* <name> .getuserparam <value> */
+private int
+zgetuserparam(os_ptr op)
+{ return currentparam1(op, &user_param_set);
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zusparam_op_defs) {
+ /* User and system parameters are readable even in Level 1 */
+ /* (if this is a Level 2 system). */
+ {"0.currentsystemparams", zcurrentsystemparams},
+ {"0.currentuserparams", zcurrentuserparams},
+ {"1.getsystemparam", zgetsystemparam},
+ {"1.getuserparam", zgetuserparam},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+ {"1.checkpassword", zcheckpassword},
+ {"1setsystemparams", zsetsystemparams},
+ {"1setuserparams", zsetuserparams},
+END_OP_DEFS(0) }
+
+/* ------ Internal procedures ------ */
+
+/* Set the values of a parameter set from a parameter list. */
+/* We don't attempt to back out if anything fails. */
+private int
+setparams(gs_param_list *plist, const param_set _ds *pset)
+{ int i, code;
+ for ( i = 0; i < pset->long_count; i++ )
+ { const long_param_def *pdef = &pset->long_defs[i];
+ long val;
+ if ( pdef->set == NULL )
+ continue;
+ code = param_read_long(plist, pdef->pname, &val);
+ switch ( code )
+ {
+ default: /* invalid */
+ return code;
+ case 1: /* missing */
+ break;
+ case 0:
+ if ( val < pdef->min_value || val > pdef->max_value )
+ return_error(e_rangecheck);
+ code = (*pdef->set)(val);
+ if ( code < 0 )
+ return code;
+ }
+ }
+ for ( i = 0; i < pset->bool_count; i++ )
+ { const bool_param_def *pdef = &pset->bool_defs[i];
+ bool val;
+ if ( pdef->set == NULL )
+ continue;
+ code = param_read_bool(plist, pdef->pname, &val);
+ if ( code == 0 )
+ code = (*pdef->set)(val);
+ if ( code < 0 )
+ return code;
+ }
+ /****** WE SHOULD DO STRINGS AND STRING ARRAYS, BUT WE DON'T YET ******/
+ return 0;
+}
+
+/* Get the current values of a parameter set to the stack. */
+private int
+current_param_list(os_ptr op, const param_set _ds *pset,
+ const ref *psref /*t_string*/)
+{ stack_param_list list;
+#define plist ((gs_param_list *)&list)
+ int i;
+
+#define pname_ok()\
+ (psref == 0 || !bytes_compare((const byte *)pname, strlen(pname),\
+ psref->value.const_bytes, r_size(psref)))
+ stack_param_list_write(&list, &o_stack, NULL);
+ for ( i = 0; i < pset->long_count; i++ )
+ { const char _ds *pname = pset->long_defs[i].pname;
+ if ( pname_ok() )
+ { long val = (*pset->long_defs[i].current)();
+ int code = param_write_long(plist, pname, &val);
+
+ if ( code < 0 )
+ return code;
+ }
+ }
+ for ( i = 0; i < pset->bool_count; i++ )
+ { const char _ds *pname = pset->bool_defs[i].pname;
+ if ( pname_ok() )
+ { bool val = (*pset->bool_defs[i].current)();
+ int code = param_write_bool(plist, pname, &val);
+
+ if ( code < 0 )
+ return code;
+ }
+ }
+ for ( i = 0; i < pset->string_count; i++ )
+ { const char _ds *pname = pset->string_defs[i].pname;
+ if ( pname_ok() )
+ { gs_param_string val;
+ int code;
+
+ (*pset->string_defs[i].current)(&val);
+ code = param_write_string(plist, pname, &val);
+ if ( code < 0 )
+ return code;
+ }
+ }
+#undef pname_ok
+#undef plist
+ return 0;
+}
+
+/* Get the current values of a parameter set to the stack. */
+private int
+currentparams(os_ptr op, const param_set _ds *pset)
+{ return current_param_list(op, pset, NULL);
+}
+
+/* Get the value of a single parameter to the stack, or signal an error. */
+private int
+currentparam1(os_ptr op, const param_set _ds *pset)
+{ ref sref;
+ int code;
+
+ check_type(*op, t_name);
+ check_ostack(2);
+ name_string_ref((const ref *)op, &sref);
+ code = current_param_list(op, pset, &sref);
+ if ( code < 0 )
+ return code;
+ if ( osp == op )
+ return_error(e_undefined);
+ /* We know osp == op + 2. */
+ ref_assign(op, op + 2);
+ pop(2);
+ return code;
+}
diff --git a/gs/src/zvmem.c b/gs/src/zvmem.c
new file mode 100644
index 000000000..b4393be4b
--- /dev/null
+++ b/gs/src/zvmem.c
@@ -0,0 +1,365 @@
+/* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zvmem.c */
+/* "Virtual memory" operators */
+#include "ghost.h"
+#include "gsstruct.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h" /* for checking in restore */
+#include "ialloc.h"
+#include "idict.h" /* ditto */
+#include "igstate.h"
+#include "isave.h"
+#include "dstack.h"
+#include "stream.h" /* for files.h */
+#include "files.h" /* for e-stack processing */
+#include "store.h"
+#include "gsmatrix.h" /* for gsstate.h */
+#include "gsstate.h"
+
+#ifdef DEBUG
+/* Define whether we validate memory before/after save/restore. */
+/* Note that we only do this if DEBUG is set and -Z? is selected. */
+#define VALIDATE_BEFORE_SAVE
+#define VALIDATE_AFTER_SAVE
+#define VALIDATE_BEFORE_RESTORE
+#define VALIDATE_AFTER_RESTORE
+#endif
+
+/* Make an invalid file object. */
+extern void make_invalid_file(P1(ref *)); /* in zfile.c */
+
+/* 'Save' structure */
+typedef struct vm_save_s vm_save_t;
+struct vm_save_s {
+ gs_state *gsave; /* old graphics state */
+};
+gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
+ vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
+
+/* Clean up the stacks and validate storage. */
+#if defined(VALIDATE_BEFORE_SAVE) || defined(VALIDATE_AFTER_SAVE) || defined(VALIDATE_BEFORE_RESTORE) || defined(VALIDATE_AFTER_RESTORE)
+private void
+ivalidate_clean_spaces(void)
+{ if ( gs_debug_c('?') )
+ { ref_stack_cleanup(&d_stack);
+ ref_stack_cleanup(&e_stack);
+ ref_stack_cleanup(&o_stack);
+ ivalidate_spaces();
+ }
+}
+#endif
+
+/* - save <save> */
+int
+zsave(register os_ptr op)
+{ uint space = icurrent_space;
+ vm_save_t *vmsave;
+ ulong sid;
+ int code;
+ gs_state *prev;
+
+#ifdef VALIDATE_BEFORE_SAVE
+ ivalidate_clean_spaces();
+#endif
+ ialloc_set_space(idmemory, avm_local);
+ vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
+ ialloc_set_space(idmemory, space);
+ if ( vmsave == 0 )
+ return_error(e_VMerror);
+ sid = alloc_save_state(idmemory, vmsave);
+ if ( sid == 0 )
+ { ifree_object(vmsave, "zsave");
+ return_error(e_VMerror);
+ }
+ if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
+ (ulong)vmsave, (ulong)sid);
+ code = gs_gsave_for_save(igs, &prev);
+ if ( code < 0 )
+ return code;
+ code = gs_gsave(igs);
+ if ( code < 0 )
+ return code;
+ vmsave->gsave = prev;
+ push(1);
+ make_tav(op, t_save, 0, saveid, sid);
+#ifdef VALIDATE_AFTER_SAVE
+ ivalidate_clean_spaces();
+#endif
+ return 0;
+}
+
+/* <save> restore - */
+private int restore_check_operand(P2(os_ptr, alloc_save_t **));
+private int restore_check_stack(P3(const ref_stack *, const alloc_save_t *, bool));
+private void restore_fix_stack(P3(ref_stack *, const alloc_save_t *, bool));
+int
+zrestore(register os_ptr op)
+{ alloc_save_t *asave;
+ bool last;
+ vm_save_t *vmsave;
+ int code = restore_check_operand(op, &asave);
+
+ if ( code < 0 )
+ return code;
+ if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
+ (ulong)alloc_save_client_data(asave),
+ (ulong)op->value.saveid);
+#ifdef VALIDATE_BEFORE_RESTORE
+ ivalidate_clean_spaces();
+#endif
+ /* Check the contents of the stacks. */
+ osp--;
+ { int code;
+ if ( (code = restore_check_stack(&o_stack, asave, false)) < 0 ||
+ (code = restore_check_stack(&e_stack, asave, true)) < 0 ||
+ (code = restore_check_stack(&d_stack, asave, false)) < 0
+ )
+ { osp++;
+ return code;
+ }
+ }
+ /* Reset l_new in all stack entries if the new save level is zero. */
+ /* Also do some special fixing on the e-stack. */
+ restore_fix_stack(&o_stack, asave, false);
+ restore_fix_stack(&e_stack, asave, true);
+ restore_fix_stack(&d_stack, asave, false);
+ /* Iteratively restore the state of memory, */
+ /* also doing a grestoreall at each step. */
+ do
+ { vmsave = alloc_save_client_data(alloc_save_current(idmemory));
+ /* Restore the graphics state. */
+ gs_grestoreall(igs);
+ gs_grestore2_for_restore(igs, vmsave->gsave);
+ /*
+ * If alloc_save_space decided to do a second save, the vmsave
+ * object was allocated one save level less deep than the
+ * current level, so ifree_object won't actually free it;
+ * however, it points to a gsave object that definitely
+ * *has* been freed. In order not to trip up the garbage
+ * collector, we clear the gsave pointer now.
+ */
+ vmsave->gsave = 0;
+ /* Now it's safe to restore the state of memory. */
+ last = alloc_restore_state_step(asave);
+ }
+ while ( !last );
+ { uint space = icurrent_space;
+ ialloc_set_space(idmemory, avm_local);
+ ifree_object(vmsave, "zrestore");
+ ialloc_set_space(idmemory, space);
+ }
+ dict_set_top(); /* reload dict stack cache */
+#ifdef VALIDATE_AFTER_RESTORE
+ ivalidate_clean_spaces();
+#endif
+ return 0;
+}
+/* Check the operand of a restore. */
+private int
+restore_check_operand(os_ptr op, alloc_save_t **pasave)
+{ vm_save_t *vmsave;
+ ulong sid;
+ alloc_save_t *asave;
+ check_type(*op, t_save);
+ vmsave = r_ptr(op, vm_save_t);
+ if ( vmsave == 0 ) /* invalidated save */
+ return_error(e_invalidrestore);
+ sid = op->value.saveid;
+ asave = alloc_find_save(idmemory, sid);
+ if ( asave == 0 )
+ return_error(e_invalidrestore);
+ *pasave = asave;
+ return 0;
+}
+/* Check a stack to make sure all its elements are older than a save. */
+private int
+restore_check_stack(const ref_stack *pstack, const alloc_save_t *asave,
+ bool is_estack)
+{ STACK_LOOP_BEGIN(pstack, bot, size)
+ { const ref *stkp;
+ for ( stkp = bot; size; stkp++, size-- )
+ { const void *ptr;
+ switch ( r_type(stkp) )
+ {
+ case t_array:
+ ptr = stkp->value.refs; break;
+ case t_dictionary:
+ ptr = stkp->value.pdict; break;
+ case t_file:
+ /* Don't check executable or closed literal */
+ /* files on the e-stack. */
+ { stream *s;
+ if ( is_estack &&
+ (r_has_attr(stkp, a_executable) ||
+ !file_is_valid(s, stkp))
+ )
+ continue;
+ }
+ ptr = stkp->value.pfile; break;
+ case t_name:
+ /* Names are special because of how they are allocated. */
+ if ( alloc_name_is_since_save(stkp, asave) )
+ return_error(e_invalidrestore);
+ continue;
+ case t_string:
+ /* Don't check empty executable strings */
+ /* on the e-stack. */
+ if ( r_size(stkp) == 0 &&
+ r_has_attr(stkp, a_executable) && is_estack
+ )
+ continue;
+ ptr = stkp->value.bytes; break;
+ case t_mixedarray:
+ case t_shortarray:
+ ptr = stkp->value.packed; break;
+ case t_device:
+ ptr = stkp->value.pdevice; break;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ ptr = stkp->value.pstruct; break;
+ default:
+ continue;
+ }
+ if ( alloc_is_since_save(ptr, asave) )
+ return_error(e_invalidrestore);
+ }
+ }
+ STACK_LOOP_END(bot, size)
+ return 0; /* OK */
+}
+/*
+ * If the new save level is zero, fix up the contents of a stack
+ * by clearing the l_new bit in all the entries (since we can't tolerate
+ * values with l_new set if the save level is zero).
+ * Also, in any case, fix up the e-stack by replacing empty executable
+ * strings and closed executable files that are newer than the save
+ * with canonical ones that aren't.
+ *
+ * Note that this procedure is only called if restore_check_stack succeeded.
+ */
+private void
+restore_fix_stack(ref_stack *pstack, const alloc_save_t *asave,
+ bool is_estack)
+{ STACK_LOOP_BEGIN(pstack, bot, size)
+ { ref *stkp;
+ for ( stkp = bot; size; stkp++, size-- )
+ { r_clear_attrs(stkp, l_new); /* always do it, no harm */
+ if ( is_estack )
+ { ref ofile;
+ ref_assign(&ofile, stkp);
+ switch ( r_type(stkp) )
+ {
+ case t_string:
+ if ( r_size(stkp) == 0 &&
+ alloc_is_since_save(stkp->value.bytes,
+ asave)
+ )
+ { make_empty_const_string(stkp,
+ avm_foreign);
+ break;
+ }
+ continue;
+ case t_file:
+ if ( alloc_is_since_save(stkp->value.pfile,
+ asave)
+ )
+ { make_invalid_file(stkp);
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ r_copy_attrs(stkp, a_all | a_executable,
+ &ofile);
+ }
+ }
+ }
+ STACK_LOOP_END(bot, size)
+}
+
+/* - vmstatus <save_level> <vm_used> <vm_maximum> */
+private int
+zvmstatus(register os_ptr op)
+{ gs_memory_status_t mstat, dstat;
+ gs_memory_status(imemory, &mstat);
+ if ( imemory == imemory_global )
+ { gs_memory_status_t sstat;
+ gs_memory_status(imemory_system, &sstat);
+ mstat.allocated += sstat.allocated;
+ mstat.used += sstat.used;
+ }
+ gs_memory_status(&gs_memory_default, &dstat);
+ push(3);
+ make_int(op - 2, alloc_save_level(idmemory));
+ make_int(op - 1, mstat.used);
+ make_int(op, mstat.allocated + dstat.allocated - dstat.used);
+ return 0;
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <save> .forgetsave - */
+private int
+zforgetsave(register os_ptr op)
+{ alloc_save_t *asave;
+ vm_save_t *vmsave;
+ int code = restore_check_operand(op, &asave);
+ if ( code < 0 )
+ return 0;
+ vmsave = alloc_save_client_data(asave);
+ /* Reset l_new in all stack entries if the new save level is zero. */
+ restore_fix_stack(&o_stack, asave, false);
+ restore_fix_stack(&e_stack, asave, false);
+ restore_fix_stack(&d_stack, asave, false);
+ /* Forget the gsaves, by deleting the bottom gstate on */
+ /* the current stack and the top one on the saved stack and then */
+ /* concatenating the stacks together. */
+ { gs_state *pgs = igs;
+ gs_state *last;
+ while ( gs_state_saved(last = gs_state_saved(pgs)) != 0 )
+ pgs = last;
+ gs_state_swap_saved(last, vmsave->gsave);
+ gs_grestore(last);
+ gs_grestore(last);
+ }
+ /* Forget the save in the memory manager. */
+ alloc_forget_save(asave);
+ { uint space = icurrent_space;
+ ialloc_set_space(idmemory, avm_local);
+ /* See above for why we clear the gsave pointer here. */
+ vmsave->gsave = 0;
+ ifree_object(vmsave, "zrestore");
+ ialloc_set_space(idmemory, space);
+ }
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zvmem_op_defs) {
+ {"1.forgetsave", zforgetsave},
+ {"1restore", zrestore},
+ {"0save", zsave},
+ {"0vmstatus", zvmstatus},
+END_OP_DEFS(0) }
diff --git a/gs/src/zvmem2.c b/gs/src/zvmem2.c
new file mode 100644
index 000000000..53415669c
--- /dev/null
+++ b/gs/src/zvmem2.c
@@ -0,0 +1,151 @@
+/* Copyright (C) 1992, 1993, 1994, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zvmem2.c */
+/* Level 2 "Virtual memory" operators */
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h" /* for ivmspace.h */
+#include "ivmspace.h"
+#include "store.h"
+
+/* Garbage collector control parameters. */
+#define default_vm_threshold_SMALL 20000
+#define default_vm_threshold_LARGE 250000
+#if arch_small_memory
+# define default_vm_threshold default_vm_threshold_SMALL
+#else
+# define default_vm_threshold\
+ (gs_if_debug_c('.') ? default_vm_threshold_SMALL :\
+ default_vm_threshold_LARGE)
+#endif
+#define min_vm_threshold 1
+#define max_vm_threshold max_long
+
+/* ------ Local/global VM control ------ */
+
+/* <bool> .setglobal - */
+private int
+zsetglobal(register os_ptr op)
+{ check_type(*op, t_boolean);
+ ialloc_set_space(idmemory,
+ (op->value.boolval ? avm_global : avm_local));
+ pop(1);
+ return 0;
+}
+
+/* <bool> .currentglobal - */
+private int
+zcurrentglobal(register os_ptr op)
+{ push(1);
+ make_bool(op, ialloc_space(idmemory) != avm_local);
+ return 0;
+}
+
+/* <any> gcheck/scheck <bool> */
+private int
+zgcheck(register os_ptr op)
+{ check_op(1);
+ make_bool(op, (r_is_local(op) ? false : true));
+ return 0;
+}
+
+/* ------ Garbage collector control ------ */
+
+/* These routines are exported for setuserparams. */
+
+/* <int> setvmthreshold - */
+int
+set_vm_threshold(long val)
+{ gs_memory_gc_status_t stat;
+ if ( val < -1 )
+ return_error(e_rangecheck);
+ else if ( val == -1 )
+ val = default_vm_threshold;
+ else if ( val < min_vm_threshold )
+ val = min_vm_threshold;
+ else if ( val > max_vm_threshold )
+ val = max_vm_threshold;
+ gs_memory_gc_status(idmemory->space_global, &stat);
+ stat.vm_threshold = val;
+ gs_memory_set_gc_status(idmemory->space_global, &stat);
+ gs_memory_gc_status(idmemory->space_local, &stat);
+ stat.vm_threshold = val;
+ gs_memory_set_gc_status(idmemory->space_local, &stat);
+ return 0;
+}
+private int
+zsetvmthreshold(register os_ptr op)
+{ int code;
+ check_type(*op, t_integer);
+ code = set_vm_threshold(op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+}
+
+/* <int> vmreclaim - */
+int
+set_vm_reclaim(long val)
+{ if ( val >= -2 && val <= 0 )
+ { gs_memory_gc_status_t stat;
+ gs_memory_gc_status(idmemory->space_system, &stat);
+ stat.enabled = val >= -1;
+ gs_memory_set_gc_status(idmemory->space_system, &stat);
+ gs_memory_gc_status(idmemory->space_global, &stat);
+ stat.enabled = val >= -1;
+ gs_memory_set_gc_status(idmemory->space_global, &stat);
+ gs_memory_gc_status(idmemory->space_local, &stat);
+ stat.enabled = val == 0;
+ gs_memory_set_gc_status(idmemory->space_local, &stat);
+ return 0;
+ }
+ else
+ return_error(e_rangecheck);
+}
+private int
+zvmreclaim(register os_ptr op)
+{ check_type(*op, t_integer);
+ if ( op->value.intval == 1 || op->value.intval == 2 )
+ { /* Force the interpreter to store its state and exit. */
+ /* The interpreter's caller will do the actual GC. */
+ return_error(e_VMreclaim);
+ }
+ else
+ { int code = set_vm_reclaim(op->value.intval);
+ if ( code >= 0 )
+ pop(1);
+ return code;
+ }
+}
+
+/* ------ Initialization procedure ------ */
+
+/* The VM operators are defined even if the initial language level is 1, */
+/* because we need them during initialization. */
+BEGIN_OP_DEFS(zvmem2_op_defs) {
+ {"0.currentglobal", zcurrentglobal},
+ {"1.gcheck", zgcheck},
+ {"1.setglobal", zsetglobal},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+ {"1setvmthreshold", zsetvmthreshold},
+ {"1vmreclaim", zvmreclaim},
+END_OP_DEFS(0) }
diff --git a/gs/src/zwppm.c b/gs/src/zwppm.c
new file mode 100644
index 000000000..9b8892119
--- /dev/null
+++ b/gs/src/zwppm.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zwppm.c */
+/* Obsolete PPM-file-writing operator */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "stream.h"
+#include "files.h"
+#include "gscdefs.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Forward references */
+private int gs_writeppmfile(P2(gx_device_memory *, FILE *));
+
+/* <file> <device> writeppmfile - */
+private int
+zwriteppmfile(register os_ptr op)
+{ stream *s;
+ int code;
+ check_read_type(*op, t_device);
+ check_write_file(s, op - 1);
+ if ( !gs_device_is_memory(op->value.pdevice) )
+ return_error(e_rangecheck);
+ sflush(s);
+ code = gs_writeppmfile((gx_device_memory *)(op->value.pdevice), s->file);
+ if ( code >= 0 )
+ pop(2);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zwppm_op_defs) {
+ {"2writeppmfile", zwriteppmfile},
+END_OP_DEFS(0) }
+
+/* ------ Non-operator routines ------ */
+
+/* Dump the contents of a memory device in PPM format. */
+private int
+gs_writeppmfile(gx_device_memory *md, FILE *file)
+{ int raster = gx_device_raster((gx_device *)md, 0);
+ int height = md->height;
+ int depth = md->color_info.depth;
+ uint rsize = raster * 3; /* * 3 just for mapped color */
+ byte *row = (byte *)gs_malloc(rsize, 1, "ppm file buffer");
+ const char *header;
+ int y;
+ int code = 0; /* return code */
+ if ( row == 0 ) /* can't allocate row buffer */
+ return_error(e_VMerror);
+
+ /* A PPM file consists of: magic number, comment, */
+ /* width, height, maxvalue, (r,g,b).... */
+
+ /* Dispatch on the type of the device -- 1-bit mono, */
+ /* 8-bit (gray scale or color), 24- or 32-bit true color. */
+
+ switch ( depth )
+ {
+ case 1:
+ header = "P4\n# %s 1 bit mono image dump\n%d %d\n";
+ break;
+
+ case 8:
+ header = (gx_device_has_color(md) ?
+ "P6\n# %s 8 bit mapped color image dump\n%d %d\n255\n" :
+ "P5\n# %s 8 bit gray scale image dump\n%d %d\n255\n");
+ break;
+
+ case 24:
+ header = "P6\n# %s 24 bit color image dump\n%d %d\n255\n";
+ break;
+
+ case 32:
+ header = "P6\n# %s 32 bit color image dump\n%d %d\n255\n";
+ break;
+
+ default: /* shouldn't happen! */
+ code = e_undefinedresult;
+ goto done;
+ }
+
+ /* Write the header. */
+ fprintf(file, header, gs_product, md->width, height);
+
+ /* Dump the contents of the image. */
+ for ( y = 0; y < height; y++ )
+ { int count;
+ register byte *from, *to, *end;
+ (*dev_proc(md, get_bits))((gx_device *)md, y, row, NULL);
+ switch ( depth )
+ {
+ case 8:
+ { /* Mapped color, consult the map. */
+ if ( gx_device_has_color(md) )
+ { /* Map color */
+ const byte *palette = md->palette.data;
+ from = row + raster + raster;
+ memcpy(from, row, raster);
+ to = row;
+ end = from + raster;
+ while ( from < end )
+ { register const byte *cp =
+ palette + (int)*from++ * 3;
+ to[0] = cp[0]; /* red */
+ to[1] = cp[1]; /* green */
+ to[2] = cp[2]; /* blue */
+ to += 3;
+ }
+ count = raster * 3;
+ }
+ else
+ { /* Map gray scale */
+ register const byte *palette =
+ md->palette.data;
+ from = to = row, end = row + raster;
+ while ( from < end )
+ *to++ = palette[(int)*from++ * 3];
+ count = raster;
+ }
+ }
+ break;
+ case 32:
+ { /* This case is different, because we must skip */
+ /* every fourth byte. */
+ from = to = row, end = row + raster;
+ while ( from < end )
+ { /* from[0] is unused */
+ to[0] = from[1]; /* red */
+ to[1] = from[2]; /* green */
+ to[2] = from[3]; /* blue */
+ from += 4;
+ to += 3;
+ }
+ count = to - row;
+ }
+ break;
+ default:
+ count = raster;
+ }
+ if ( fwrite(row, 1, count, file) < count )
+ { code = e_ioerror;
+ goto done;
+ }
+ }
+
+done: gs_free((char *)row, rsize, 1, "ppm file buffer");
+ return code;
+}
diff --git a/gs/unix-lpr.txt b/gs/unix-lpr.txt
new file mode 100644
index 000000000..ddf0aadd6
--- /dev/null
+++ b/gs/unix-lpr.txt
@@ -0,0 +1,141 @@
+ NOTE: this file was contributed by a user: please contact
+ George Cameron <george@bio-medical-physics.aberdeen.ac.uk>
+ if you have questions.
+ Please contact Yves Arrouye <Yves.Arrouye@imag.fr> if you
+ have problem with the number-of-colors part of the script.
+
+Help on setting up an lpr filter for Ghostscript
+================================================
+
+OVERVIEW:
+
+ "How do I set up Ghostscript to provide postscript queues in a standard lpr
+ environment on Unix systems" appears as a Frequently Asked Question amongst
+ Ghostscript users, and the following utilities are designed to make this
+ task a little easier. The files supplied are:
+
+ unix-lpr.txt: this file
+ unix-lpr.sh: a flexible, multi-option print filter shell script
+ lprsetup.sh: a shell script which sets up soft links and creates a
+ template insert for the printcap file
+
+
+WHAT IT CAN DO:
+
+ The print filter resides in the standard Ghostscript installation directory
+ (eg. /usr/local/share/ghostscript), together with a dummy filter directory
+ containing various soft links which point to the filter. It offers the
+ following features:
+
+ o Multiple devices supported by a single filter
+ o Multiple bit-depths for the same device
+ o Multiple number of colors for the same device
+ o Direct (single-queue) and indirect (two-queue) setup
+ o Support for the standard preprocessing filters if you have the
+ corresponding (whatever)-to-postscript translators
+ o Redirection of diagnostic and programmed output to a logfile in
+ the spooling directory
+ o Maintaining of printer accounting records of the numbers of pages
+ printed by each user (compatible with the 'pac' command)
+ o Straightforward editing for further customisation
+
+
+SETTING IT UP:
+
+ The lprsetup.sh script needs to have two lines edited before running, to set
+ the printer devices to use and the list of filters available. With this
+ information, it will:
+
+ o Create a 'filt' subdirectory of the standard Ghostscript
+ installation directory
+ o Create the links in this directory which enable the filter to
+ determine the parameters for running Ghostscript
+ o Automatically generate printcap entries which should need only
+ a little editing before adding to your system printcap file
+
+
+EDITING THE DEVICE LIST:
+
+ At the top of lprsetup.sh, you will find a line of the form DEVICES=" ... ".
+ This should be edited to replace the example list with your own list of
+ devices, with each entry comprising the name of the device, follwed by three
+ optional additional fields, separated by dots.
+
+ The first field is only required if the printer device understands the
+ qualifier -dBitsPerPixel=.., which only applies to colour devices. For
+ a particular number <N> of bits per pixel, add the suffix .<N> to the
+ device name, eg. cdj500.3 cdj500.24 etc.
+ The second field is only required if the printer device understand the
+ setting of the Colors device parameter (as in -dColors=...) which only
+ applies to colour devices (and at present is only supported by the bjc*
+ family of drivers). For a particluar number <C> of colors, add the suffix
+ <.C> to te device name, e.g. bjc600.24.3 bjc600.8.1 etc.
+ The third field is required if you wish to use two separate queues for the
+ device, a 'raw' queue as well as the postscript queue (see discussion below).
+ If this is required, you should add the suffix .dq ('dual-queue') to the name,
+ whether or not a bits-per-pixel suffix has already been added.
+
+ Thus, the following list supports a cdj550 device at 3 different bit-depths
+ (24 bpp, 3 bpp and 1 bpp), with a dual-queue (ie. separate queue for the raw
+ data); a monochrome deskjet device with a single queue; and a djet500 device
+ using a separate queue:
+
+ DEVICES="cdj550.24.dq cdj550.3.dq cdj550.1.dq deskjet djet500.dq"
+
+
+EDITING THE FILTER LIST:
+
+ The standard list contains only the generic 'if' filter, although there
+ is a commented-out list showing the other filters which you may have
+ available. If you wish to use the support for these filters, you may
+ need to edit the bsd-if file to add the directories where the translators
+ are stored to the PATH, or to change the names of the filters if yours
+ are different. The bsd-if script is supplied with an example setup
+ using Transcript (a commercial package from Adobe), and PBMPLUS, a PD
+ package by Jeff Poskanzer and others.
+
+
+EDITING THE PRINTER PORT AND TYPE
+
+ You can set the port your printer is on and its type (parallel or printer).
+ If you want to use remote printers, you'll have to modifiy the printcap
+ insert file yourself.
+
+
+MODIFIYING THE PRINTCAP.INSERT:
+
+ Running the lprsetup.sh script generates a file called printcap.insert, which
+ has a template setup for your printer queues. It cannot guarantee to do the
+ whole job, and you will probably need to consult your system documentation
+ and edit this file before you add it to your printcap file. The file has
+ good defaults for serial printers, as these most often cause problems in
+ getting binary data to the printer. The setup is not guaranteed to be
+ correct, but it works on my system! You may well need to change the baud
+ rate, or the hardware/software handshaking used. Only a small change is
+ required to edit the printcap to use a networked remote printer instead of
+ a direct printer, and an example is given in the printcap.insert file.
+
+
+SINGLE OR DUAL QUEUES:
+
+ If you wish to provide a postscript-only queue (eg. so that all pages
+ printed go through the accounting!), and the printer port is local to the
+ host machine, a single queue is appropriate - Ghostscript simply converts
+ the postscript into the printer's native data format and sends it to the
+ port. If the printer is on a remote networked machine (another workstation,
+ or a PC), or if you need to send raw printer data to the printer, you will
+ need to use two queues. Simply specify the '.dq' option above.
+
+
+BUGS:
+
+ You will need write access to the ghostscript installation directory (eg.
+ /usr/local/share/ghostscript) in order for lprsetup.sh to create the filt
+ directory and soft links.
+
+ You must list all instances of a device (if you have multiple bits-per-
+ pixel for the same device) as adjacent items in the device list - if you
+ do not, the printcap.insert will contain multiple entries for the same
+ device.
+
+ Multiple instances of the same device are not supported at present.
diff --git a/gs/use.txt b/gs/use.txt
new file mode 100644
index 000000000..83de493a3
--- /dev/null
+++ b/gs/use.txt
@@ -0,0 +1,1247 @@
+ Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, use.txt, describes how to use the Ghostscript language
+interpreter.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** Installing Ghostscript
+********
+
+Please read the documentation file install.txt for information on installing
+Ghostscript.
+
+********
+******** Unix shell scripts for Ghostscript
+********
+
+The Ghostscript distribution includes several Unix shell scripts for
+driving Ghostscript in different environments. These are all
+user-contributed code: please contact the user identified in the file, not
+Aladdin Enterprises, if you have questions.
+
+> pv.sh - preview a specified page of a dvi file in an X window.
+
+> sysvlp.sh - System V 3.2 lp interface for parallel printer.
+
+> pj-gs.sh - printing on an H-P PaintJet under HP-UX.
+
+> unix-lpr.sh - queue filter for lpr under Unix.
+> lprsetup.sh - setup for unix-lpr.sh.
+
+If one of these serves your needs, you may be able to skip most of
+the rest of this document.
+
+********
+******** How to use Ghostscript ********
+********
+
+The command (that is, a shell command in environments other than MS Windows,
+or a 'Run' line in MS Windows) to invoke Ghostscript is:
+ gs <filename1> ... <filenameN>
+Normally the files are PostScript or EPS files, but depending on how
+Ghostscript was built, they may also be PDF files or MS-DOS EPSF files. The
+interpreter will read in the files in sequence (using the method described
+under "File searching" below to find the files) and execute them. After
+doing this, it reads further input from the primary input stream (normally
+the keyboard), consisting of PostScript language commands. Each line
+(i.e. characters up to a <return>) is interpreted separately. To exit from
+the interpreter, type quit<return>. The interpreter also exits gracefully
+if it encounters end-of-file. Typing the interrupt character, e.g.,
+control-C, is also safe.
+
+The interpreter recognizes many switches described below, which may appear
+anywhere in the command line and apply to all files thereafter.
+
+Many of the switches include an '=' followed by a parameter. Because of a
+strange design decision in the Watcom C/C++ run-time library, you must use
+'#' rather than '=' with Ghostscript if Ghostscript was compiled with Watcom
+C/C++. In particular, the MS-DOS executable included in the standard
+Ghostscript distribution (gs386.exe) was compiled this way.
+
+You can get a brief help message by invoking Ghostscript with
+ gs -h
+or
+ gs -?
+This message also lists the available devices. For a little more
+information about available devices, a one-line description of each device
+appears near the beginning of the file devs.mak.
+
+Choosing the output device
+--------------------------
+
+Ghostscript may be built with multiple output devices. Ghostscript
+normally opens the first one and directs output to it. To use device xyz
+as the initial output device, include the switch
+ -sDEVICE=xyz
+in the command line. Note that this switch must precede the first .ps
+file, and only its first invocation has any effect. For example, for
+printer output in a normal configuration that includes an Epson printer
+driver, you might use the shell command
+ gs -sDEVICE=epson myfile.ps
+instead of just
+ gs myfile.ps
+Alternatively, once you are inside Ghostscript, you can type
+ (epson) selectdevice
+ (myfile.ps) run
+All output then goes to the printer instead of the display until further
+notice. You can switch devices at any time by using the selectdevice
+procedure, e.g.,
+ (vga) selectdevice
+or
+ (epson) selectdevice
+As yet a third alternative, you can define an environment variable
+GS_DEVICE as the desired default device name. The order of precedence for
+these alternatives, highest to lowest, is:
+ selectdevice
+ (command line)
+ GS_DEVICE
+ (first device in build list)
+
+To select the resolution on a printer, use the shell command
+ gs -sDEVICE=<device> -r<xres>x<yres>
+For example, on a 9-pin Epson-compatible printer, you can get the
+lowest-resolution (fastest) mode with
+ gs -sDEVICE=epson -r60x72
+and the highest-resolution mode with
+ gs -sDEVICE=epson -r240x72.
+On a 24-pin printer, the lowest resolution is
+ gs -sDEVICE=epson -r60x60
+and the highest-resolution 24-pin mode is
+ gs -sDEVICE=epson -r360x180
+
+If you select a printer as the output device, Ghostscript also allows you
+to control where the device sends its output. Normally, output goes
+directly to the printer (PRN) on MS-DOS systems, and to a scratch file on
+Unix or VMS systems. To send the output to a series of files foo1.xyz,
+foo2.xyz, ..., use the switch
+ -sOutputFile=foo%d.xyz
+(For compatibility with older versions of Ghostscript, -sOUTPUTFILE=
+also works.) The %d is a printf format specification; you can use
+other formats like %02d. Each file will receive one page of output.
+Alternatively, to send the output to a single file foo.xyz, with all
+the pages concatenated, use the switch
+ -sOutputFile=foo.xyz
+
+On Unix systems, you can send the output directly to a pipe. For
+example, to pipe the output to the command `lpr' (which, on many Unix
+systems, is the command that spools output for a printer), use the
+switch
+ -sOutputFile=\|lpr
+You can also send output to stdout for piping with the switch
+ -sOutputFile=-
+In this case you must also use the -q switch, to prevent Ghostscript from
+writing messages to stdout.
+
+File formats like PCX and PBM are also 'devices'. When you select a file
+format as the 'device', you must also specify an output file, e.g.,
+ gs -sDEVICE=pcxmono -sOutputFile=xyz.pcx
+
+To find out what devices are available, type
+ devicenames ==
+after starting up Ghostscript. Alternatively you can use the -h or
+-? switch in the command line, as described above.
+
+Choosing paper size
+-------------------
+
+Ghostscript is normally configured to use U.S. letter paper as the default.
+To select a different default paper size, find the line in gs_init.ps that
+says
+
+ % Optionally choose a default paper size other than U.S. letter.
+
+The next line begins
+
+ % (a4)
+
+To select A4 as the default paper size, remove the % but do not change
+anything else. To select a different default paper size, remove the % and
+replace the word a4 with the name of the desired paper size. You can use
+any paper size listed in the table at the beginning of gs_statd.ps.
+
+Alternatively, to select a different default paper size for a single
+invocation of Ghostscript, you can use the command line switch
+ -sPAPERSIZE=a_known_paper_size
+e.g.,
+ -sPAPERSIZE=a4
+or
+ -sPAPERSIZE=legal
+
+Individual documents also can (and often do) specify a paper size, which
+will take precedence over the default one. If you want to force a specific
+paper size, ignoring the paper size specified in the document, make that
+paper size the default (as just described), and also include
+ -dFIXEDMEDIA
+on the command line.
+
+Finally, most (but not all) of Ghostscript's printer drivers can be
+configured at compile time to use A4 paper as the default by including
+-DA4 in the CFLAGS switches in the makefile. See make.txt for more
+details.
+
+File searching
+--------------
+
+When looking for initialization files (gs_*.ps, pdf_*.ps), font files, the
+Fontmap file, and files named on the command line, Ghostscript first tests
+whether the file name specifies an explicit directory. The test is as
+follows:
+
+ - On Unix systems, Ghostscript tests whether the name begins with
+ '/', or with one or more '.'s followed by a '/'.
+
+ - On MS-DOS or MS Windows systems, Ghostscript tests whether the
+ name has a ':' as its second character, or begins with '/' or
+ '\', or with one or more '.'s followed by a '/' or '\'.
+
+ - On VMS systems, Ghostscript tests whether the name contains a
+ node, device, root, or directory specification.
+
+If the file name does specify an explicit directory (the test succeeds),
+Ghostscript simply tries to open the file using the given name. Otherwise,
+Ghostscript will try directories in the following order:
+
+ - The current directory (unless disabled by the -P- switch);
+
+ - The directory/ies specified by the -I switch(es) in the command
+ line (see below), if any;
+
+ - The directory/ies specified by the GS_LIB environment variable,
+ if any;
+
+ - The directory/ies specified by the GS_LIB_DEFAULT macro in the
+ Ghostscript makefile, if any.
+
+Each of these (GS_LIB_DEFAULT, GS_LIB, and -I parameter) may be either a
+single directory, or a list of directories separated by a character
+appropriate for the operating system (':' on Unix systems, ';' on VMS
+systems, ';' on MS-DOS systems). We think that trying the current directory
+first is a very bad idea -- it opens serious security loopholes and can lead
+to very confusing errors if one has more than one version of Ghostscript in
+one's environment -- but when we attempted to change it, users insisted that
+we change it back. You can disable looking in the current directory first
+using the -P- switch described below.
+
+Note that Ghostscript does not use this file searching algorithm for the
+'run' or 'file' operators: for these operators, it simply opens the file
+with the given name. To run a file using the searching algorithm, use
+'runlibfile' instead of 'run'.
+
+Resources
+---------
+
+Ghostscript uses a completely different rule for looking for files
+containing PostScript Level 2 "resources": per the Adobe documentation, it
+concatenates together:
+
+ - The value of the system parameter GenericResourceDir
+ (initially "/Resource/");
+
+ - The name of the resource category (e.g., ProcSet);
+
+ - The value of the system parameter GenericResourcePathSep
+ (initially "/");
+
+ - The name of the resource instance (e.g., CIDInit).
+
+For looking up fonts, after exhausting the search method described in the
+next section, it concatenates together:
+
+ - The value of the system parameter FontResourceDir
+ (initially "/Resource/Font/");
+
+ - The name of the resource font (e.g., Times-Roman).
+
+Note that even though the system parameters are named somethingDir, they are
+not just plain directory names: they have a "/" on the end, so that they can
+be concatenated with the category name or font name.
+
+Font lookup
+-----------
+
+Ghostscript has a slightly different rule for determining how to find the
+file containing a font with a given name. This rule uses not only the
+search path defined by -I, GS_LIB, and GS_LIB_DEFAULT as described above,
+but an additional list of directories which is the value of the GS_FONTPATH
+environment variable (or the value provided with the -sFONTPATH= switch, if
+present).
+
+When Ghostscript needs to find a font that isn't already loaded into memory,
+it starts by looking for Fontmap files in every directory on the search
+path: these files provide mappings between font names and file names. (See
+the Fontmap file in the Ghostscript distribution for details.) If it can't
+find a font in any Fontmap file in the search path (or in the list provided
+with the -sFONTMAP= switch, if present), it looks at the GS_FONTPATH
+environment variable (or the value provided with the -sFONTPATH= switch, if
+present), which is also a list of directories. It goes to those
+directories, one by one, and looks for all files that appear to contain
+PostScript fonts; it then effectively adds all those files and fonts to its
+internal copy of the Fontmap (the catalog of fonts and the files that
+contain them).
+
+To summarize, the differences between the search path (-I, GS_LIB,
+GS_LIB_DEFAULT) and the font path (-sFONTPATH=, GS_FONTPATH) are:
+
+ Search path:
+
+ - Consulted first.
+
+ - Font name -> file name mapping given in Fontmap files;
+ aliases are possible, and there need not be any relation
+ between the font name in the Fontmap and the FontName in
+ the file.
+
+ - Only fonts and files named in Fontmap are used.
+
+ Font path:
+
+ - Consulted only if search path doesn't provide the file.
+
+ - Font name -> file name mapping is implicit -- the
+ FontName in the file is used. Aliases are not possible.
+
+ - Every Type 1 font file in each directory is available.
+
+If you are using one of the following types of computer, you
+may wish to set GS_FONTPATH to the indicated value so that Ghostscript will
+automatically acquire all the installed Type 1 fonts:
+
+ System type GS_FONTPATH
+ ----------- -----------
+ DEC OSF/1 /usr/lib/X11/fonts/Type1Adobe
+ DEC Ultrix /usr/lib/DPS/outline/decwin
+ HP-UX 9 /usr/lib/X11/fonts/type1.st/typefaces
+ IBM AIX /usr/lpp/DPS/fonts/outlines
+ " /usr/lpp/X11/lib/X11/fonts/Type1
+ " /usr/lpp/X11/lib/X11/fonts/Type1/DPS
+ NeXT /NextLibrary/Fonts/outline
+ SGI IRIX /usr/lib/DPS/outline/base
+ " /usr/lib/X11/fonts/Type1
+ Sun SunOS 4.x /usr/openwin/lib/X11/fonts/Type1/outline
+ " (NeWSprint only)
+ newsprint_2.5/SUNWsteNP/reloc/$BASEDIR/NeWSprint/small_openwin/lib/fonts
+ Sun Solaris 2 /usr/openwin/lib/X11/fonts/Type1/outline
+ VMS SYS$COMMON:[SYSFONT.XDPS.OUTLINE]
+
+These paths may not be exactly right for your installation; if the
+indicated directory doesn't contain files whose names are familiar font
+names like Courier and Helvetica, you may wish to ask your system
+administrator where to find these fonts.
+
+Adobe Acrobat comes with a set of 14 Type 1 fonts, typically in a directory
+called some_path_name_or_other/Acrobat3/Fonts. There is no particular
+reason to use these instead of the corresponding fonts in the Ghostscript
+distribution, aside from saving about 1 Mb of disk space, but if you want to
+do this, see install.txt.
+
+NOTE: On Solaris systems simply setting GS_FONTPATH may not work, because
+for some reason some versions of Ghostscript can't seem to find any of the
+Type1 fonts in /usr/openwin/lib/X11/fonts/Type1/outline. It says: "15
+files, 15 scanned, 0 new fonts". See Fontmap.Sol instead.
+
+Temporary files
+---------------
+
+By default, Ghostscript creates temporary files named _temp_XX.XXX in the
+current directory on MS-DOS and VMS systems, gsXXXXXX in the current
+directory on OS/2 systems, and gs_XXXXX in the /tmp directory on Unix
+systems. You can change the directory in which Ghostscript will create
+these files by setting the TEMP environment variable to the name of the
+directory.
+
+Ghostscript currently doesn't do a very good job of deleting temporary
+files when it exits; you may have to delete them manually from time to
+time.
+
+Environment variable summary
+----------------------------
+
+GS_DEVICE
+ Defines the default output device. Described above.
+
+GS_FONTPATH
+ Specifies a list of directories that should be scanned for fonts if
+a requested font can't be found anywhere on the search path. Described
+above.
+
+GS_LIB
+ Provides a search path for initialization files and fonts.
+Described above.
+
+GS_OPTIONS
+ Defines a list of command line arguments to be processed before
+the ones actually specified on the command line. For example, setting
+GS_DEVICE to xxx is equivalent to setting GS_OPTIONS to -sDEVICE=xxx. The
+contents of GS_OPTIONS are not limited to switches; they may include
+actual file names or even @file arguments.
+
+TEMP
+ Defines a directory name for temporary files. Described above.
+
+********
+******** Using Ghostscript and Ghostview with PDF files
+********
+
+Ghostscript is normally configured (except on 16-bit MS-DOS platforms) so
+that it can interpret both PostScript and PDF files (the latter are
+sometimes incorrectly called "Acrobat files"). It examines each file to
+determine automatically whether it is a PDF file or a PostScript file. All
+the normal switches and procedures for interpreting PostScript files also
+apply to PDF files, with a few exceptions noted below. In addition, there
+is a shell script / batch file
+
+ pdf2ps input.pdf output.ps
+
+that converts PDF to (Level 2) PostScript.
+
+Switches not applicable to PDF files
+------------------------------------
+
+You cannot use the `-' switch to provide PDF input from stdin or a pipe.
+The PDF language, unlike the PostScript language, inherently requires random
+access to the file.
+
+Added switches for PDF files
+----------------------------
+
+ -dFirstPage=pagenumber
+ Starts interpreting on the given page of the document.
+
+ -dLastPage=pagenumber
+ Stops interpreting after the given page of the document.
+
+ -sPSFile=filename
+ Writes the PostScript equivalent of the PDF input on the
+ given file.
+
+Ghostview and PDF files
+-----------------------
+
+Since Ghostview pipes PostScript files to Ghostscript, you cannot view PDF
+files with Ghostview just by saying
+ ghostview file.pdf
+Instead there are two options:
+
+ 1. Tanmoy Bhattacharya has written some patches for Ghostview 1.5
+ that allow it to read and display PDF files. These are available
+ from:
+ ftp://gita.lanl.gov/people/tanmoy/hypertex/gv1.5gs3.33hack.tar.gz
+
+ 2. Start Ghostview as follows:
+ ghostview -arguments file.pdf quit.ps
+ This will allow you to display a PDF file, but you won't be able
+ to jump to particular pages. Use Tanmoy's code if you want that
+ facility.
+
+********
+******** Notes on specific platforms ********
+********
+
+VMS
+---
+
+On VMS systems, the last character of each "directory" name indicates what
+sort of entity the "directory" references. If the "directory" name ends
+with a colon, it is taken as referring to a logical device, e.g.:
+ $ DEFINE GHOSTSCRIPT_DEVICE DUA1:[GHOSTSCRIPT_14]
+ $ DEFINE GS_LIB GHOSTSCRIPT_DEVICE:
+If the "directory" name ends with a closing square bracket, it is taken as
+referring to a real directory, e.g.:
+ $ DEFINE GS_LIB DUA1:[GHOSTSCRIPT]
+
+In order to specify switches and file names when invoking the interpreter,
+define GS as a foreign command:
+ $ GS == "$disk:[directory]GS.EXE"
+where "disk" and "directory" specify the disk and directory where Ghostscript
+is located. For instance,
+ $ GS == "$DUA1:[GHOSTSCRIPT]GS.EXE"
+To allow the interpreter to be run from any directory, define the logical
+GS_LIB which points to the Ghostscript directory
+ $ DEFINE GS_LIB disk:[directory]
+This allows Ghostscript to locate its initialization files stored in the
+Ghostscript directory -- see use.txt for further details. Finally, to
+invoke the interpreter, merely type GS. Although DCL normally converts
+unquoted parameters to upper case, C programs receive their parameters in
+lower case. That is, the command
+ $ GS -Isys$login:
+passes the switch "-isys$login" to the interpreter. To preserve the
+case of switches, enclose them in double quotes; e.g.,
+ $ GS "-Isys$login:"
+
+If you are on an X Windows display (for which gs is built), you can do
+
+ $ set display/create/node="domain-name"/transport=tcpip
+
+For example,
+
+ $ set display/create/node="doof.city.com"/transport=tcpip
+
+and then run Ghostscript
+
+ $ gs
+
+If you write printer output to a file and then want to print the file
+later, use the "/PASSALL" qualifier to the PRINT command.
+
+In order to get PDF files (or PostScript files that use the setfileposition
+operator) to work properly on VMS systems, you must ensure that they are
+"stream LF" type files. (**NOTE**: This only applies if you are using DEC C
+to compile Ghostscript; there is no known way to get these files to work
+properly with the old VAX C compiler.) If you transfer files by FTP, you
+probably need to do one of the following two things after the transfer:
+
+1. If FTP'd in text/ASCII mode then do:
+
+ $ CONVERT/FDL=STREAMLF.FDL input-file output-file
+
+ where the contents of the file STREAMLF.FDL are given below.
+
+2. Otherwise, if FTP'd in binary mode do
+
+ $ SET FILE/ATTRIBUTE=(RFM:STMLF)
+
+The contents of the STREAMLF.FDL file are shown between, and exclusive of, the
+dashed lines:
+
+-------------------------------------------------
+FILE
+ ORGANIZATION sequential
+
+RECORD
+ BLOCK_SPAN yes
+ CARRIAGE_CONTROL carriage_return
+ FORMAT stream_lf
+-------------------------------------------------
+
+MS-DOS
+------
+
+Ghostscript supports many SuperVGA displays directly, most of them with
+more than 16 colors. The complete list is in the file devs.mak, which is
+part of the Ghostscript source code. (If you got Ghostscript under the
+Aladdin Ghostscript Free Public License, the person or place from which you
+got it is also required to make the source code available to you; if you
+got it under the GNU License, see the GNU License for more information.)
+
+Some applications, such as Microsoft Word, require a prologue in front of
+the PostScript files they output. In the case of Word, this is one of the
+*.ini files included with the Word distribution. Other applications may
+require other prologues. These may be specified on the Ghostscript
+command line, e.g.,
+ gs prologue.ini myfile.ps
+
+If you have a SuperVGA display that supports a 16-color mode with 800x600
+pixels, and you know the display mode number for this mode, you can select
+it by using the command line switches
+ -sDEVICE=svga16 -dDisplayMode=NNN
+where NNN is the display mode number in decimal. The modes for some
+popular display chipsets are as follows:
+
+ Acumos AVGA2, AVGA3 88 (0x58)
+ Advance Logic AL2101 43 (0x2B)
+ Ahead V5000 113 (0x71)
+ ATI VGAWONDER, Graphics Ultra etc. 84 (0x54)
+ Chips and Technologies 106 (0x6A)
+ Cirrus Logic CL-GD 500/600 100 (0x64)
+ Cirrus Logic GD 5422 88 (0x58)
+ Compaq VGA 89 (0x59)
+ CTI 106 (0x6A)
+ * Genoa 5xxx, Sigma VGA 41 (0x29)
+ Genoa 6xxx 106 (0x6A)
+ MXIC MX 68010 85 (0x55)
+ NCR 77C22 88 (0x58)
+ OAK Technologies OTI-067, OTI-077, OTI037C 82 (0x52)
+ OAK Technologies OTI037C w/ NEL BIOS 91 (0x5B)
+ * Orchid Prodesigner 41 (0x29)
+ Paradise 88 (0x58)
+ Poach 106 (0x6A)
+ Primus 42 (0x2A)
+ Realtek RT 3106 31 (0x1F)
+ Tecmar 22 (0x16)
+ Trident 8900 91 (0x5B)
+ * Tseng ET-3000, ET-4000 41 (0x29)
+ * VEGA 41 (0x29)
+ Video 7 SVGA 98 (0x62)
+ WD90C11 92 (0x5C)
+ Western Digital 88 (0x58)
+
+The ones marked * are the default (they all use the same value.) If your
+card's chipset doesn't appear on this list, or if you try the value here
+and it doesn't work, please e-mail the chipset and correct display mode to
+ghost@aladdin.com for inclusion in future releases.
+
+NOTE: The remainder of the MS-DOS section is currently not relevant, because
+the Borland compilers do not support 32-bit MS-DOS executables, and
+Ghostscript no longer supports the 16-bit MS-DOS environment. We have
+retained this section on the off-chance that Borland will support 32-bit
+MS-DOS compilation at some future time.
+
+If you are running Ghostscript on a MS-DOS machine with a display that is
+not EGA/VGA compatible, you must use the Borland compiler. You must build
+Ghostscript with the BGI driver as the default, and you will need the
+appropriate .BGI file from the Borland Turbo C library. (Ghostscript
+includes the EGA/VGA driver in the executable.)
+
+If you are using the BGI driver, two additional environment variables
+become relevant:
+
+ BGIPATH - defines the directory where Ghostscript will look for
+the appropriate BGI driver. If BGIPATH is not defined, Ghostscript will
+look in the directory defined as BGIDIR in the makefile. In either case,
+if no driver is found in the designated directory, Ghostscript will look
+in the current directory.
+
+ BGIUSER - a string of the form nn.dname, where nn is a hexadecimal
+number giving a display mode and dname is the name of a file containing a
+user-supplied BGI driver. If BGIUSER is defined and the BGI device is
+selected, Ghostscript will supply nn as the display mode and will obtain
+the driver from the file named dname.
+
+X Windows
+---------
+
+Ghostscript looks for the following resources under the program name
+"ghostscript" and class name "Ghostscript":
+
+ Name Class Default
+ ---- ----- -------
+ background Background white
+ foreground Foreground black
+ borderColor BorderColor black
+ borderWidth BorderWidth 1
+ geometry Geometry NULL
+ xResolution Resolution **
+ yResolution Resolution **
+ useExternalFonts UseExternalFonts true
+ useScalableFonts UseScalableFonts true
+ logExternalFonts LogExternalFonts false
+ externalFontTolerance ExternalFontTolerance 10.0
+ palette Palette Color
+ maxGrayRamp MaxGrayRamp 128
+ maxRGBRamp MaxRGBRamp 5
+ maxDynamicColors MaxDynamicColors 256
+ useBackingPixmap UseBackingPixmap true
+ useXPutImage UseXPutImage true
+ useXSetTile UseXSetTile true
+ regularFonts RegularFonts see below
+ symbolFonts SymbolFonts see below
+ dingbatFonts DingbatFonts see below
+
+** Calculated from display metrics.
+
+ Notes on Resources:
+
+ Ghostscript doesn't look at the default system background and
+ foreground colors; if you want to change the background or
+ foreground color, you must set them explicitly for Ghostscript.
+ (This is a deliberate choice, so that PostScript documents will
+ display correctly -- with white = white and black = black --
+ by default, even if text windows use other colors.)
+
+ The geometry resource only affects window placement.
+
+ Resolution is given in pixels per inch.
+
+ The font tolerance gives largest acceptable difference in
+ height of the screen font. The tolerance is expressed as
+ a percentage of the height of the desired font.
+
+ The palette resource can be used to restrict ghostscript to
+ using a grayscale or monochrome palette.
+
+ The maxRGBRamp and maxGrayRamp control the maximum number of
+ colors that ghostscript allocates ahead of time for the dither
+ cube/ramp. Ghostscript will never preallocate more than half
+ of the cells in a colormap. maxDynamicColors controls the
+ maximum number of colors that Ghostscript will allocate
+ dynamically in the colormap.
+
+The use... resources exist primarily to work around bugs in X servers. In
+particular, many versions of DEC's X server (DECwindows) have bugs that
+require setting useXPutImage or useXSetTile to false.
+
+ Some servers do not implement backing pixmaps properly, or do not
+ have enough memory for them. If you get strange behavior or "out
+ of memory" messages, try setting useBackingPixmap to false.
+
+ Some servers do not implement tiling properly. This will show up
+ as broad bands of color where dither patterns should appear. If
+ this happens, try setting useXSetTile to false.
+
+ Some servers do not implement bitmap/pixmap displaying properly.
+ This may show up as white or black rectangles where characters
+ should appear, or characters may appear in "inverse video" (e.g.,
+ white on a black rectangle). If this happens, try setting
+ useXPutImage to false.
+
+To use native X11 fonts, Ghostscript must map PostScript font names to
+the XLFD font names. The regularFonts, symbolFonts, and dingbatFonts
+resources give the name mapping for different encodings. The XLFD font
+name in the mapping must contain seven dashes. The X driver adds the
+additional size and encoding fields to bring the total number of dashes
+in the font name to 14. Here are the default font mappings:
+
+ Regular Fonts: (Fonts available in standard or ISO-Latin-1 encoding)
+
+ AvantGarde-Book:-Adobe-ITC Avant Garde Gothic-Book-R-Normal--\n\
+ AvantGarde-BookOblique:-Adobe-ITC Avant Garde Gothic-Book-O-Normal--\n\
+ AvantGarde-Demi:-Adobe-ITC Avant Garde Gothic-Demi-R-Normal--\n\
+ AvantGarde-DemiOblique:-Adobe-ITC Avant Garde Gothic-Demi-O-Normal--\n\
+ Bookman-Demi:-Adobe-ITC Bookman-Demi-R-Normal--\n\
+ Bookman-DemiItalic:-Adobe-ITC Bookman-Demi-I-Normal--\n\
+ Bookman-Light:-Adobe-ITC Bookman-Light-R-Normal--\n\
+ Bookman-LightItalic:-Adobe-ITC Bookman-Light-I-Normal--\n\
+ Courier:-Adobe-Courier-Medium-R-Normal--\n\
+ Courier-Bold:-Adobe-Courier-Bold-R-Normal--\n\
+ Courier-BoldOblique:-Adobe-Courier-Bold-O-Normal--\n\
+ Courier-Oblique:-Adobe-Courier-Medium-O-Normal--\n\
+ Helvetica:-Adobe-Helvetica-Medium-R-Normal--\n\
+ Helvetica-Bold:-Adobe-Helvetica-Bold-R-Normal--\n\
+ Helvetica-BoldOblique:-Adobe-Helvetica-Bold-O-Normal--\n\
+ Helvetica-Narrow:-Adobe-Helvetica-Medium-R-Narrow--\n\
+ Helvetica-Narrow-Bold:-Adobe-Helvetica-Bold-R-Narrow--\n\
+ Helvetica-Narrow-BoldOblique:-Adobe-Helvetica-Bold-O-Narrow--\n\
+ Helvetica-Narrow-Oblique:-Adobe-Helvetica-Medium-O-Narrow--\n\
+ Helvetica-Oblique:-Adobe-Helvetica-Medium-O-Normal--\n\
+ NewCenturySchlbk-Bold:-Adobe-New Century Schoolbook-Bold-R-Normal--\n\
+ NewCenturySchlbk-BoldItalic:-Adobe-New Century Schoolbook-Bold-I-Normal--\n\
+ NewCenturySchlbk-Italic:-Adobe-New Century Schoolbook-Medium-I-Normal--\n\
+ NewCenturySchlbk-Roman:-Adobe-New Century Schoolbook-Medium-R-Normal--\n\
+ Palatino-Bold:-Adobe-Palatino-Bold-R-Normal--\n\
+ Palatino-BoldItalic:-Adobe-Palatino-Bold-I-Normal--\n\
+ Palatino-Italic:-Adobe-Palatino-Medium-I-Normal--\n\
+ Palatino-Roman:-Adobe-Palatino-Medium-R-Normal--\n\
+ Times-Bold:-Adobe-Times-Bold-R-Normal--\n\
+ Times-BoldItalic:-Adobe-Times-Bold-I-Normal--\n\
+ Times-Italic:-Adobe-Times-Medium-I-Normal--\n\
+ Times-Roman:-Adobe-Times-Medium-R-Normal--\n\
+ ZapfChancery-MediumItalic:-Adobe-ITC Zapf Chancery-Medium-I-Normal--
+
+ Symbol Fonts: (using Symbol encoding)
+
+ Symbol: -Adobe-Symbol-Medium-R-Normal--
+
+ Dingbat Fonts: (using Dingbat encoding)
+
+ ZapfDingbats: -Adobe-ITC Zapf Dingbats-Medium-R-Normal--
+
+For X11/NeWS, one can use the OpenWindows scalable fonts instead, which
+will give good quality output for any point size. In this environment,
+the relevant section of the resource file should look like this:
+
+Ghostscript.regularFonts: \
+ AvantGarde-Book: -itc-avantgarde-book-r-normal-- \n\
+ AvantGarde-BookOblique: -itc-avantgarde-book-o-normal-- \n\
+ AvantGarde-Demi: -itc-avantgarde-demi-r-normal-- \n\
+ AvantGarde-DemiOblique: -itc-avantgarde-demi-o-normal-- \n\
+ Bembo: -monotype-bembo-medium-r-normal-- \n\
+ Bembo-Bold: -monotype-bembo-bold-r-normal-- \n\
+ Bembo-BoldItalic: -monotype-bembo-bold-i-normal-- \n\
+ Bembo-Italic: -monotype-bembo-medium-i-normal-- \n\
+ Bookman-Demi: -itc-bookman-demi-r-normal-- \n\
+ Bookman-DemiItalic: -itc-bookman-demi-i-normal-- \n\
+ Bookman-Light: -itc-bookman-light-r-normal-- \n\
+ Bookman-LightItalic: -itc-bookman-light-i-normal-- \n\
+ Courier: -itc-courier-medium-r-normal-- \n\
+ Courier-Bold: -itc-courier-bold-r-normal-- \n\
+ Courier-BoldOblique: -itc-courier-bold-o-normal-- \n\
+ Courier-Oblique: -itc-courier-medium-o-normal-- \n\
+ GillSans: -monotype-gill-medium-r-normal-sans- \n\
+ GillSans-Bold: -monotype-gill-bold-r-normal-sans- \n\
+ GillSans-BoldItalic: -monotype-gill-bold-i-normal-sans- \n\
+ GillSans-Italic: -monotype-gill-normal-i-normal-sans- \n\
+ Helvetica: -linotype-helvetica-medium-r-normal-- \n\
+ Helvetica-Bold: -linotype-helvetica-bold-r-normal-- \n\
+ Helvetica-BoldOblique: -linotype-helvetica-bold-o-normal-- \n\
+ Helvetica-Narrow: -linotype-helvetica-medium-r-narrow-- \n\
+ Helvetica-Narrow-Bold: -linotype-helvetica-bold-r-narrow-- \n\
+ Helvetica-Narrow-BoldOblique: -linotype-helvetica-bold-o-narrow-- \n\
+ Helvetica-Narrow-Oblique: -linotype-helvetica-medium-o-narrow-- \n\
+ Helvetica-Oblique: -linotype-helvetica-medium-o-normal-- \n\
+ LucidaBright: -b&h-lucidabright-medium-r-normal-- \n\
+ LucidaBright-Demi: -b&h-lucidabright-demibold-r-normal-- \n\
+ LucidaBright-DemiItalic: -b&h-lucidabright-demibold-i-normal-- \n\
+ LucidaBright-Italic: -b&h-lucidabright-medium-i-normal-- \n\
+ LucidaSans: -b&h-lucida-medium-r-normal-sans- \n\
+ LucidaSans-Bold: -b&h-lucida-bold-r-normal-sans- \n\
+ LucidaSans-BoldItalic: -b&h-lucida-bold-i-normal-sans- \n\
+ LucidaSans-Italic: -b&h-lucida-medium-i-normal-sans- \n\
+ LucidaSans-Typewriter: -b&h-lucidatypewriter-medium-r-normal-sans- \n\
+ LucidaSans-TypewriterBold: -b&h-lucidatypewriter-bold-r-normal-sans- \n\
+ NewCenturySchlbk-BoldItalic: -linotype-new century schoolbook-bold-i-normal-- \n\
+ NewCenturySchlbk-Bold: -linotype-new century schoolbook-bold-r-normal-- \n\
+ NewCenturySchlbk-Italic: -linotype-new century schoolbook-medium-i-normal-- \n\
+ NewCenturySchlbk-Roman: -linotype-new century schoolbook-medium-r-normal-- \n\
+ Palatino-Bold: -linotype-palatino-bold-r-normal-- \n\
+ Palatino-BoldItalic: -linotype-palatino-bold-i-normal-- \n\
+ Palatino-Italic: -linotype-palatino-medium-i-normal-- \n\
+ Palatino-Roman: -linotype-palatino-medium-r-normal-- \n\
+ Rockwell: -monotype-rockwell-medium-r-normal-- \n\
+ Rockwell-Bold: -monotype-rockwell-bold-r-normal-- \n\
+ Rockwell-BoldItalic: -monotype-rockwell-bold-i-normal-- \n\
+ Rockwell-Italic: -monotype-rockwell-medium-i-normal-- \n\
+ Times-Bold: -linotype-times-bold-r-normal-- \n\
+ Times-BoldItalic: -linotype-times-bold-i-normal-- \n\
+ Times-Italic: -linotype-times-medium-i-normal-- \n\
+ Times-Roman: -linotype-times-medium-r-normal-- \n\
+ Utopia-Bold: -adobe-utopia-bold-r-normal-- \n\
+ Utopia-BoldItalic: -adobe-utopia-bold-i-normal-- \n\
+ Utopia-Italic: -adobe-utopia-regular-i-normal-- \n\
+ Utopia-Regular: -adobe-utopia-regular-r-normal-- \n\
+ ZapfChancery-MediumItalic: -itc-zapfchancery-medium-i-normal-- \n
+Ghostscript.dingbatFonts: \
+ ZapfDingbats: -itc-zapfdingbats-medium-r-normal--
+Ghostscript.symbolFonts: \
+ Symbol: --symbol-medium-r-normal--
+
+Users who switch regularly between different X servers may wish to use the
+'*' wild card in place of the foundry name (itc, monotype, linotype, b&h,
+or adobe); users who do not switch X servers should leave the explicit
+foundry in the name, since it speeds up font accessing.
+
+To set these resources, put them in a file (such as ~/.Xdefaults) in the
+following form:
+
+Ghostscript*geometry: -0+0
+Ghostscript*xResolution: 72
+Ghostscript*yResolution: 72
+
+Then load the defaults into the X server:
+
+% xrdb -merge ~/.Xdefaults
+
+Ghostscript will take advantage of the "HP XLFD Enhancements," if
+available, to use native X11 fonts for fonts that are anamorphically
+scaled, rotated, or mirrored. If the user has installed these changes to
+their X or font server, they will automatically be used when appropriate.
+
+SCO Unix
+--------
+
+Because of bugs in the SCO Unix kernel, Ghostscript will not work if you
+select direct screen output (gdevsco.c) and also allow it to write messages
+on the console. If you are using direct screen output, redirect
+Ghostscript's terminal output to a file.
+
+********
+******** Switches
+********
+
+Unless otherwise noted, these apply to all platforms.
+
+Normal switches
+---------------
+
+ Input control
+ -------------
+
+ @filename
+ Causes Ghostscript to read filename and treat its
+ contents the same as the command line. (This is
+ intended primarily for getting around MS-DOS's
+ 128-character limit on the length of a command line.)
+ Switches or file names in the file may be separated by
+ any amount of white space (space, tab, line break);
+ there is no limit on the size of the file.
+
+ -- filename arg1 ...
+ -+ filename arg1 ...
+ Takes the next argument as a file name as usual, but takes
+ all remaining arguments (even if they have the syntactic
+ form of switches) and defines the name ARGUMENTS in
+ userdict (not systemdict) as an array of those strings,
+ *before* running the file. When Ghostscript finishes
+ executing the file, it exits back to the shell.
+
+ -@ filename arg1 ...
+ Does the same thing as -- and -+, but expands @filename
+ arguments.
+
+ -
+ This is not really a switch. It indicates to Ghostscript
+ that the standard input is coming from a file or a pipe.
+ Ghostscript reads from stdin until reaching end-of-file,
+ executing it like any other file, and then continues
+ processing the command line. At the end of the command
+ line, Ghostscript exits rather than going into its
+ interactive mode. NOTE: this switch works only for
+ PostScript, not for PDF.
+
+ -c tokens ...
+ Interprets arguments, up to the next argument that begins
+ with - followed by a non-digit or with @, as PostScript
+ code. For example, if the file quit.ps contains just
+ the word `quit', the following are equivalent:
+ quit.ps
+ and
+ -c quit
+ Each argument must be exactly one token, as defined by
+ the `token' operator.
+
+ -ffilename
+ Execute the given file, even if its name begins with a -
+ or an @. -f alone does nothing, but it provides a
+ convenient way to terminate the list of tokens for the -c
+ switch.
+
+ File searching
+ --------------
+
+ Note that by "library files" we mean all the files identified as
+ using the search rule under "File searching" above: Ghostscript's
+ own initialization files, fonts, and files named on the command
+ line.
+
+ -Idirectories
+ Adds the designated list of directories at the head of the
+ search path for library files.
+
+ -P
+ Makes Ghostscript look first in the current directory for
+ library files. This is currently the default.
+ -P-
+ Makes Ghostscript *not* look first in the current directory
+ for library files (unless, of course, the first explicitly
+ supplied directory is `.').
+
+ Parameter setting
+ -----------------
+
+ -Dname=token
+ -dname=token
+ Define a name in systemdict with the given definition.
+ The token must be exactly one token (as defined by the
+ 'token' operator) and must not contain any whitespace.
+ If the token is a non-literal name, it must be true,
+ false, or null.
+
+ -Dname
+ -dname
+ Define a name in systemdict with value=true.
+
+ -Sname=string
+ -sname=string
+ Define a name in systemdict with a given string as value.
+ This is different from -d. For example,
+ -dname=35
+ is equivalent to the program fragment
+ /name 35 def
+ whereas
+ -sname=35
+ is equivalent to
+ /name (35) def
+
+ -uname
+ Un-define a name, cancelling -d or -s.
+
+ -gnumber1xnumber2
+ Equivalent to -dDEVICEWIDTH=number1 and
+ -dDEVICEHEIGHT=number2, specifying the device width and
+ height in pixels. This is for the benefit of devices (such
+ as X11 windows and VESA displays) that require (or allow)
+ width and height to be specified. Note that this causes
+ documents of other sizes to be clipped, not scaled:
+ see -dFIXEDMEDIA below.
+
+ -rnumber
+ -rnumber1xnumber2
+ Equivalent to -dDEVICEXRESOLUTION=number1 and
+ -dDEVICEYRESOLUTION=number2, specifying the device
+ horizontal and vertical resolution in pixels per inch. This
+ is for the benefit of devices (such as printers) that
+ support multiple X and Y resolutions.
+
+ Miscellaneous
+ -------------
+
+ -q
+ Quiet startup -- suppress normal startup messages,
+ and also do the equivalent of -dQUIET.
+
+Note that gs_init.ps makes systemdict read-only, so the values of names
+defined with -D/d/S/s cannot be changed (although, of course, they can be
+superseded by definitions in userdict or other dictionaries.)
+
+Special names
+-------------
+
+-dBATCH
+ causes Ghostscript to exit after processing all files named on the
+command line, rather than going into an interactive loop reading PostScript
+commands. Equivalent to putting -c quit at the end of the command line.
+
+-dCOLORSCREEN
+-dCOLORSCREEN=0
+-dCOLORSCREEN=false
+ On high-resolution devices (at least 150 dpi resolution, or
+-dDITHERPPI specified), -dCOLORSCREEN forces the use of separate halftone
+screens with different angles for C/M/Y/K or R/G/B if halftones are needed
+(this produces the best-quality output); -dCOLORSCREEN=0 uses separate
+screens with the same frequency and angle; -dCOLORSCREEN=false forces the
+use of a single binary screen. If COLORSCREEN is not specified, the default
+is to use separate screens with different angles if the device has fewer
+than 5 bits per color, and a single binary screen (which will never actually
+be used under normal circumstances) on all other devices.
+
+-dDELAYBIND
+ causes 'bind' to remember all its invocations, but not actually
+execute them until the .bindnow procedure is called. Useful only for
+certain specialized packages like pstotext that redefine operators.
+
+-dDISKFONTS
+ causes individual character outlines to be loaded from the disk the
+first time they are encountered. (Normally Ghostscript loads all the
+character outlines when it loads a font.) This may allow loading more
+fonts into RAM, at the expense of slower rendering. DISKFONTS is only
+effective if the diskfont feature was selected in the executable; otherwise
+it is ignored.
+
+-dDITHERPPI=lpi
+ forces all devices to be considered high-resolution, and forces use
+of a halftone screen or screens with lpi lines per inch, disregarding the
+actual device resolution. Reasonable values for lpi are N/5 to N/20, where
+N is the resolution in dots per inch.
+
+-dFIXEDMEDIA
+ causes the media size to be fixed after initialization, and causes
+pages of other sizes or orientations to be clipped. This may be useful when
+printing documents on a printer that can handle their requested paper size
+but whose default is some other size. Note that -g automatically sets
+-dFIXEDMEDIA, but -sPAPERSIZE= does not.
+
+-dFIXEDRESOLUTION
+ causes the media resolution to be fixed similarly. -r automatically
+sets -dFIXEDRESOLUTION.
+
+-dLOCALFONTS
+ causes Type 1 fonts to be loaded into the current VM, which is
+normally local VM, instead of always being loaded into global VM. Only
+useful for compatibility with Adobe printers for loading some obsolete
+fonts.
+
+-dNOBIND
+ disables the 'bind' operator. Only useful for debugging.
+
+-dNOCACHE
+ disables character caching. Only useful for debugging.
+
+-dNOCIE
+ substitutes DeviceGray and DeviceRGB for CIEBasedA and CIEBasedABC
+color spaces respectively. Only useful on very slow systems where color
+accuracy is less important.
+
+-dNODISPLAY
+ initializes Ghostscript with a null device (a device that discards
+the output image) rather than the default device or the device selected with
+-sDEVICE=. This is usually only useful when running PostScript code whose
+purpose is to compute something rather than produce an output image.
+
+-dNOFONTMAP
+ suppresses the normal loading of the Fontmap file. This may be
+useful in environments without a file system.
+
+-dNOFONTPATH
+ suppresses consultation of GS_FONTPATH. This may be useful for
+debugging.
+
+-dNOGC
+ suppresses the initial automatic enabling of the garbage collector
+in Level 2 systems. (The vmreclaim operator is not disabled.) Only useful
+for debugging.
+
+-dNOPAUSE
+ disables the prompt and pause at the end of each page. Normally one
+should use this (along with -dBATCH) when producing output on a printer or
+to a file; it also may be desirable for applications where another program
+is 'driving' Ghostscript.
+
+-dNOPLATFONTS
+ disables the use of fonts supplied by the underlying platform
+(X Windows or Microsoft Windows). This may be needed if the platform
+fonts look undesirably different from the scalable fonts.
+
+-dNOPROMPT
+ disables only the prompt, but not the pause, at the end of each
+page. This may be useful on PC displays that get confused if a program
+attempts to write text to the console while the display is in a graphics
+mode.
+
+-dORIENT1=true
+-dORIENT1=false
+ defines the meaning of the 0 and 1 orientation values for the
+setpage[params] compatibility operators. The default value of ORIENT1 is
+true (set in gs_init.ps), which is the correct value for most files that use
+setpage[params] at all, namely, files produced by badly designed
+applications that 'know' that the output will be printed on certain
+roll-media printers: these applications use 0 to mean landscape and 1 to
+mean portrait. -dORIENT1=false declares that 0 means portrait and 1 means
+landscape, which is the convention used by a smaller number of files
+produced by properly written applications.
+
+-dQUIET
+ suppresses routine information comments on stdout. This is
+currently necessary when redirecting device output to stdout.
+
+-dSAFER
+ disables the deletefile and renamefile operators, and the
+ability to open files in any mode other than read-only. This may be
+desirable for spoolers or other sensitive environments.
+
+-dSHORTERRORS
+ makes certain error and information messages more Adobe-compatible.
+
+-dWRITESYSTEMDICT
+ leaves systemdict writable. This is necessary when running
+special utility programs such as font2c and pcharstr, which must bypass
+normal PostScript access protection.
+
+-sDEVICE=device
+ selects an alternate initial output device, as described above.
+
+-sFONTMAP=filename1;filename2;...
+ specifies (an) alternate name(s) for the Fontmap file. Note that
+the names are separated by : on Unix systems, by ; on MS-DOS or MS Windows
+systems, and by , on VMS systems, just as for search paths.
+
+-sFONTPATH=dir1;dir2;...
+ specifies a list of directories that will be scanned when looking
+for fonts not found on the search path, overriding the GS_FONTPATH
+environment variable.
+
+-sOutputFile=filename
+ selects an alternate output file (or pipe) for the initial output
+device, as described above.
+
+-sSUBSTFONT=fontname
+ causes the given font to be substituted for all unknown fonts,
+instead of using the normal intelligent substitution algorithm. Also, in
+this case, the font returned by findfont will be the actual font named
+fontname, not a copy of the font with the FontName changed to the requested
+one.
+
+Debugging switches
+------------------
+
+The -Z switch only applies if the interpreter was built for a
+debugging configuration (DEBUG=1 or -DDEBUG selected at compile
+time).
+
+ -A Fill empty storage with a distinctive bit pattern
+ for debugging. Equivalent to -Z@.
+ -A- Turn off -A, equivalent to -Z-@.
+
+ -E Turn on tracing of error returns from operators.
+ Equivalent to -Z#.
+ -E- Turn off -E, equivalent to -Z-#.
+
+ -Mn Force the interpreter's allocator to acquire additional
+ memory in units of nK, rather than the default (currently
+ 20K on MS-DOS systems, 50K on Unix). n is a positive
+ decimal integer (not exceeding 63 on MS-DOS systems).
+
+ -Nn Allocate space for nK names, rather than the default
+ (normally 64K). n > 64 is only allowed if the interpreter
+ was compiled with EXTEND_NAMES defined.
+
+ -Zxxx Turn on debugging printout.
+ -Z-xxx Turn off debugging printout.
+ Each of the xxx characters selects an option.
+ Case is significant.
+ 0 = garbage collector, minimal detail
+ 1 = type 1 & type 42 font interpreter
+ 2 = curve subdivider/rasterizer
+ 3 = curve subdivider/rasterizer, detail
+ 4 = garbage collector (strings)
+ 5 = garbage collector (strings, detail)
+ 6 = garbage collector (chunks, roots)
+ 7 = garbage collector (objects)
+ 8 = garbage collector (refs)
+ 9 = garbage collector (pointers)
+ a = allocator (large blocks only)
+ A = allocator (all calls)
+ b = bitmap image processor
+ B = bitmap images, detail
+ c = color/halftone mapper
+ d = dictionary put/undef
+ D = dictionary lookups
+ e = external (OS-related) calls
+ f = fill algorithm (summary)
+ F = fill algorithm (detail)
+ g = gsave/grestore[all]
+ h = halftone renderer
+ H = halftones, every pixel
+ i = interpreter, just names
+ I = interpreter, everything
+ j = (Japanese) composite fonts
+ k = character cache & xfonts
+ K = character cache, every access
+ l = command lists, bands
+ L = command lists, everything
+ m = makefont and font cache
+ n = name lookup (new names only)
+ o = outliner (stroke)
+ O = stroke detail
+ p = band list paths
+ P = all paths
+ q = clipping
+ r = arc renderer
+ s = streams
+ S = scanner
+ t = tiling algorithm
+ u = undo saver (for save/restore), finalization
+ U = undo saver, more detail
+ v = rectangle fill
+ V = device-level output
+ w = compression encoder/decoder
+ x = transformations
+ y = Type 1 hints
+ Y = Type 1 hints, every access
+ z = trapezoid fill
+ # = operator error returns
+ % = externally processed comments
+ * = image parameters
+ : = command list & allocator/time summary
+ ~ = math functions
+ The following switches select debugging options other than
+ printout.
+ $ = set unused parts of object references to
+ identifiable garbage values
+ + = use minimum-size stack blocks
+ , = don't use path-based banding
+ . = use small-memory table sizes even on
+ large-memory machines
+ ? = validate pointers before, during and after GC,
+ also before and after save and restore;
+ also make other allocator validity checks
+ @ = fill newly allocated, garbage-collected, and
+ freed storage with a marker (a1, c1, and
+ f1 respectively)
+
+********
+******** Frequently Asked Questions
+********
+
+Please consult our FAQ on the World-Wide Web at
+ http://www.cs.wisc.edu/~ghost/gsfaq.html
+or the text version at
+ http://www.cs.wisc.edu/~ghost/gsfaq.txt
diff --git a/gs/xfonts.txt b/gs/xfonts.txt
new file mode 100644
index 000000000..0960b1e12
--- /dev/null
+++ b/gs/xfonts.txt
@@ -0,0 +1,164 @@
+ Copyright (C) 1993 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This file, xfonts.txt, describes the interface between Ghostscript and the
+routines that access externally supplied font and text facilities.
+
+For an overview of Ghostscript and a list of the documentation files, see
+README.
+
+********
+******** Introduction ********
+********
+
+Starting with release 2.6, Ghostscript has the ability to use the
+character rasterizer provided by the underlying operating system and
+window system; specifically, Adobe Type Manager or a TrueType rasterizer
+under MS Windows, and the facilities provided by X Windows. This ability
+augments, but does not replace, Ghostscript's own Type 1 rasterizer:
+Ghostscript may still use its own rasterizer for very large characters,
+characters that are clipped or transformed in unusual ways, and output to
+devices other than the screen.
+
+Ghostscript interfaces to these platform facilities through a driver-like
+interface called the xfont (external font) interface. Currently, xfont
+implementations are associated directly with device drivers; in a future
+release, Ghostscript may separate them, so that (for example) it will be
+possible to use the platform rasterizer when writing to a file.
+
+Please note that beyond this point, this file is likely to be useful only
+to a small number of Ghostscript porters and implementors.
+
+********
+******** Types ********
+********
+
+gs_char (defined in gsccode.h)
+
+ This type represents a character code that appears in a string.
+Currently it is always a single byte, but composite fonts or Unicode may
+require it to be wider in the future.
+
+gs_glyph (defined in gsccode.h)
+
+ This type represents a character name like 'period' or 'epsilon'.
+From the xfont implementation's point of view, it is just a handle; when
+necessary, Ghostscript provides a gs_proc_glyph_name_t procedure (see next
+type) to convert it to a string name.
+
+gs_proc_glyph_name_t (defined in gsccode.h)
+
+ This type represents a procedure that maps a gs_glyph to its
+string name; see the description of char_glyph below.
+
+gx_xglyph (defined in gsxfont.h)
+
+ This type represents a character or glyph code that can be used
+with a specific platform font. Normally it will be a character code that
+the implementation of render_char will turn into a 1-character string and
+give to the platform's "display string" operation.
+
+gx_xfont_procs (declared in gsxfont.h, defined in gxxfont.h)
+
+ This type is the xfont analogue of gx_device_procs, the type of
+the procedure record that defines an xfont implementation.
+
+gx_xfont (declared in gsxfont.h, defined in gxxfont.h)
+
+ This type is the gxfont analogue of gx_device, the type of the
+basic structure for an xfont.
+
+(encoding_index)
+
+ This is not really a type, although it probably should be: it is
+an int used to indicate the Encoding used by a font. Defined values are
+ 0 = StandardEncoding
+ 1 = ISOLatin1Encoding
+ 2 = SymbolEncoding
+ 3 = DingbatsEncoding
+ -1 = other encoding
+
+********
+******** Implementation procedures ********
+********
+
+All the procedures that return int results return 0 on success, or an
+appropriate negative error code in the case of error conditions. The
+error codes are defined in gserrors.h. The relevant ones are the same as
+for drivers (see drivers.txt for details).
+
+As for drivers, if an implementation procedure returns an error, it
+should use the return_error macro rather than a simple return statement,
+e.g.,
+
+ return_error(gs_error_VMerror);
+
+This macro is defined in gx.h, which is automatically included by
+gdevprn.h but not by gserrors.h.
+
+Font-level
+----------
+
+gx_xfont *(*lookup_font)(P7(gx_device *dev, const byte *fname, uint len,
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,
+ const gs_memory_procs *mprocs))
+
+ Look up a font name, UniqueID, and matrix, and return an xfont, or
+NULL if no suitable xfont exists. Use mprocs to allocate the xfont and
+any subsidiary data structures. The matrix is the FontMatrix concatenated
+with the CTM, so (roughly speaking) the font size in pixels is pmat->yy *
+1000 for a normal Type 1 font.
+
+ Note that this is the only implementation procedure that does not
+take an xfont * as its first argument. In fact, callers of lookup_font
+must use the get_xfont_device driver procedure to get the correct device
+to pass as the first argument to lookup_font.
+
+gx_xglyph (*char_xglyph)(P5(gx_xfont *xf, gs_char chr, int encoding_index,
+ gs_glyph glyph, gs_proc_glyph_name_t glyph_name))
+
+ Convert a character name to an xglyph code. In the case of
+glyphshow, chr may be gs_no_char; for an ordinary show operation, if
+the character code is invalid, glyph may be gs_no_glyph.
+
+int (*char_metrics)(P5(gx_xfont *xf, gx_xglyph xg, int wmode,
+ gs_int_point *pwidth, gs_int_rect *pbbox))
+
+ Get the metrics for a character. If the metrics are unavailable,
+return 1.
+
+int (*render_char)(P7(gx_xfont *xf, gx_xglyph xg, gx_device *target,
+ int x, int y, gx_color_index color, int required))
+
+ Render a character. (x,y) corresponds to the character origin.
+The target may be any Ghostscript device. A good implementation will
+check whether the target can handle this type of xfont directly (e.g., by
+checking the target name), and if so, will render the character directly;
+otherwise, it will do what has to be done in the general case, namely, get
+a bitmap for the character and use the target's copy_mono operation. If
+required is false, the procedure should return an error if the rendering
+operation would be expensive, since in this case Ghostscript has already
+cached the bitmap and metrics from a previous call with required=true.
+If the operation cannot be done, return 1.
+
+int (*release)(P2(gx_xfont *xf, const gs_memory_procs *mprocs))
+
+ Release any external resources associated with an xfont. If
+mprocs is not NULL, also free any storage allocated by lookup_font
+(including the xfont itself).
diff --git a/gs/zlib/ChangeLog b/gs/zlib/ChangeLog
new file mode 100644
index 000000000..218cfb0c5
--- /dev/null
+++ b/gs/zlib/ChangeLog
@@ -0,0 +1,239 @@
+
+ ChangeLog file for zlib
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/gs/zlib/INDEX b/gs/zlib/INDEX
new file mode 100644
index 000000000..bb1e3f0b1
--- /dev/null
+++ b/gs/zlib/INDEX
@@ -0,0 +1,51 @@
+ChangeLog history of changes
+INDEX this file
+Make_vms.com script for Vax/VMS
+Makefile makefile for Unix (generated by configure)
+Makefile.b32 makefile for Borland C++ 32-bit
+Makefile.bor makefile for Borland C/C++ 16-bit
+Makefile.dj2 makefile for DJGPP 2.x
+Makefile.in makefile for Unix (template for configure)
+Makefile.msc makefile for Microsoft C 16-bit
+Makefile.riscos makefile for RISCOS
+Makefile.sas makefile for Amiga SAS/C
+Makefile.tc makefile for Turbo C
+Makefile.wat makefile for Watcom C
+README guess what
+algorithm.doc description of the compression & decompression algorithms
+configure configure script for Unix
+descrip.mms makefile for Vax/VMS
+zlib.def definition file for Windows DLL
+zlib.rc definition file for Windows DLL
+
+
+ zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+deflate.c
+deflate.h
+gzio.c
+infblock.c
+infblock.h
+infcodes.c
+infcodes.h
+inffast.c
+inffast.h
+inflate.c
+inftrees.c
+inftrees.h
+infutil.c
+infutil.h
+trees.c
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs:
+example.c
+minigzip.c
diff --git a/gs/zlib/Make_vms.com b/gs/zlib/Make_vms.com
new file mode 100644
index 000000000..0008d00bb
--- /dev/null
+++ b/gs/zlib/Make_vms.com
@@ -0,0 +1,115 @@
+$! make libz under VMS
+$! written by Martin P.J. Zinser <m.zinser@gsi.de>
+$!
+$! Look for the compiler used
+$!
+$ ccopt = ""
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$ ccopt = "/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$ then
+$ comp = "__vaxc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$ ccopt = "/decc/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ endif
+$ endif
+$!
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Zlib sources ..."
+$ if f$search("SYS$SYSTEM:MMS.EXE").eqs.""
+$ then
+$ dele example.obj;*,minigzip.obj;*
+$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" -
+ adler32.c zutil.h zlib.h zconf.h
+$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" -
+ compress.c zlib.h zconf.h
+$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" -
+ crc32.c zutil.h zlib.h zconf.h
+$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" -
+ deflatec.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" -
+ gsio.c zutil.h zlib.h zconf.h
+$ CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" -
+ infblock.c zutil.h zlib.h zconf.h infblock.h
+$ CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" -
+ infcodes.c zutil.h zlib.h zconf.h inftrees.h
+$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" -
+ inffast.c zutil.h zlib.h zconf.h inffast.h
+$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" -
+ inflate.c zutil.h zlib.h zconf.h infblock.h
+$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" -
+ inftrees.c zutil.h zlib.h zconf.h inftrees.h
+$ CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" -
+ infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" -
+ trees.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" -
+ uncompr.c zlib.h zconf.h
+$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" -
+ zutil.c zutil.h zlib.h zconf.h
+$ write sys$output "Building Zlib ..."
+$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ
+$ write sys$output "Building example..."
+$ CALL MAKE example.OBJ "CC ''CCOPT' example" -
+ example.c zlib.h zconf.h
+$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb
+$ write sys$output "Building minigzip..."
+$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" -
+ minigzip.c zlib.h zconf.h
+$ call make minigzip.exe -
+ "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" -
+ minigzip.obj libz.olb
+$ else
+$ mms/macro=('comp')
+$ endif
+$ write sys$output "Zlib build completed"
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
diff --git a/gs/zlib/Makefile b/gs/zlib/Makefile
new file mode 100644
index 000000000..71b269b61
--- /dev/null
+++ b/gs/zlib/Makefile
@@ -0,0 +1,130 @@
+# Makefile for zlib
+# Copyright (C) 1995-1996 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=$(CC)
+
+VER=1.0.4
+LIBS=libz.a
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] descrip.mms \
+ zlib.def zlib.rc algorithm.doc *.[ch]
+
+all: example minigzip
+
+test: all
+ ./example
+ echo hello world | ./minigzip | ./minigzip -d
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) 2>/dev/null
+
+libz.so.$(VER): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f libz.so; ln -s $@ libz.so
+
+example: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! $(prefix)/include ]; then mkdir $(prefix)/include; fi
+ -@if [ ! $(exec_prefix)/lib ]; then mkdir $(exec_prefix)/lib; fi
+ cp zlib.h zconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/zlib.h $(prefix)/include/zconf.h
+ cp $(LIBS) $(exec_prefix)/lib
+ cd $(exec_prefix)/lib; chmod 644 $(LIBS)
+ -@(cd $(exec_prefix)/lib; $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(exec_prefix)/lib; if test -f libz.so.$(VER); then \
+ ln -s libz.so.$(VER) libz.so; \
+ fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+
+uninstall:
+ cd $(exec_prefix)/lib; rm -f $(LIBS); \
+ if test -f libz.so; then \
+ v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p'<$(prefix)/include/zlib.h`;\
+ rm -f libz.so.$$v libz.so; \
+ fi
+ cd $(prefix)/include; rm -f zlib.h zconf.h
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/gs/zlib/Makefile.in b/gs/zlib/Makefile.in
new file mode 100644
index 000000000..71b269b61
--- /dev/null
+++ b/gs/zlib/Makefile.in
@@ -0,0 +1,130 @@
+# Makefile for zlib
+# Copyright (C) 1995-1996 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=$(CC)
+
+VER=1.0.4
+LIBS=libz.a
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] descrip.mms \
+ zlib.def zlib.rc algorithm.doc *.[ch]
+
+all: example minigzip
+
+test: all
+ ./example
+ echo hello world | ./minigzip | ./minigzip -d
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) 2>/dev/null
+
+libz.so.$(VER): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f libz.so; ln -s $@ libz.so
+
+example: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! $(prefix)/include ]; then mkdir $(prefix)/include; fi
+ -@if [ ! $(exec_prefix)/lib ]; then mkdir $(exec_prefix)/lib; fi
+ cp zlib.h zconf.h $(prefix)/include
+ chmod 644 $(prefix)/include/zlib.h $(prefix)/include/zconf.h
+ cp $(LIBS) $(exec_prefix)/lib
+ cd $(exec_prefix)/lib; chmod 644 $(LIBS)
+ -@(cd $(exec_prefix)/lib; $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(exec_prefix)/lib; if test -f libz.so.$(VER); then \
+ ln -s libz.so.$(VER) libz.so; \
+ fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+
+uninstall:
+ cd $(exec_prefix)/lib; rm -f $(LIBS); \
+ if test -f libz.so; then \
+ v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p'<$(prefix)/include/zlib.h`;\
+ rm -f libz.so.$$v libz.so; \
+ fi
+ cd $(prefix)/include; rm -f zlib.h zconf.h
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/gs/zlib/Makefile.riscos b/gs/zlib/Makefile.riscos
new file mode 100644
index 000000000..0f10aa891
--- /dev/null
+++ b/gs/zlib/Makefile.riscos
@@ -0,0 +1,46 @@
+# Project: zlib_1_03
+
+
+# Toolflags:
+CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fnah
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags =
+LibFileflags = -c -l -o $@
+Squeezeflags = -o $@
+
+
+# Final targets:
+@.zlib_lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \
+ @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \
+ @.o.uncompress @.o.zutil
+ LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \
+ @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \
+ @.o.trees @.o.uncompress @.o.zutil
+@.test: @.tests.minigzip @.tests.example
+ echo Please run "Test" in directory tests
+@.tests.minigzip: @.o.minigzip @.zlib_lib C:o.Stubs
+ Link $(Linkflags) @.o.minigzip @.zlib_lib C:o.Stubs
+@.tests.example: @.o.example @.zlib_lib C:o.Stubs
+ Link $(Linkflags) @.o.example @.zlib_lib C:o.Stubs
+
+
+# User-editable dependencies:
+.c.o:
+ cc $(ccflags) -o $@ $<
+
+# Static dependencies:
+@.o.example: @.tests.c.example
+ cc $(ccflags) -o @.o.example @.tests.c.example
+@.o.minigzip: @.tests.c.minigzip
+ cc $(ccflags) -o @.o.minigzip @.tests.c.minigzip
+
+
+# Dynamic dependencies:
+o.minigzip: tests.c.minigzip
+o.minigzip: h.zlib
+o.minigzip: h.zconf
+o.example: tests.c.example
+o.example: h.zlib
+o.example: h.zconf
diff --git a/gs/zlib/README b/gs/zlib/README
new file mode 100644
index 000000000..28adc90b2
--- /dev/null
+++ b/gs/zlib/README
@@ -0,0 +1,99 @@
+zlib 1.0.4 is a general purpose data compression library. All the code
+is reentrant (thread safe). The data format used by the zlib library
+is described by RFCs (Request for Comments) 1950 to 1952 in the files
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format). These documents are also available in
+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file
+zlib.h. A usage example of the library is given in the file example.c
+which also tests that the library is working correctly. Another
+example is given in the file minigzip.c. The compression library itself
+is composed of all source files except example.c and minigzip.c.
+
+To compile all files and run the test program, follow the instructions
+given at the top of Makefile. In short "make test; make install"
+should work for most machines. For MSDOS, use one of the special
+makefiles such as Makefile.msc; for VMS, use Make_vms.com or descrip.mms.
+
+Questions about zlib should be sent to <zlib@quest.jpl.nasa.gov> or,
+if this fails, to the addresses given below in the Copyright section.
+The zlib home page is http://quest.jpl.nasa.gov/zlib/
+
+The changes made in version 1.0.4 are documented in the file ChangeLog.
+The main changes since 1.0.3 are:
+
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+
+
+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
+is in the CPAN (Comprehensive Perl Archive Network) sites, such as:
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+
+
+Notes for some targets:
+
+- For Turbo C the small model is supported only with reduced performance to
+ avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+
+- For 64-bit Iris, deflate.c must be compiled without any optimization.
+ With -O, one libpng test fails. The test works in 32 bit mode (with
+ the -32 compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1
+ it works when compiled with cc.
+
+- zlib doesn't work on HP-UX 9.05 with one cc compiler (the one not
+ accepting the -O option). It works with the other cc compiler.
+
+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
+ and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
+ For help on building a zlib DLL, contact Alessandro Iacopetti
+ <iaco@email.alessandria.alpcom.it> http://lisa.unial.it/iaco ,
+ or contact Brad Clarke <bclarke@cyberus.ca>.
+
+- gzdopen is not supported on RISCOS
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+ 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.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes.
diff --git a/gs/zlib/adler32.c b/gs/zlib/adler32.c
new file mode 100644
index 000000000..0466094b4
--- /dev/null
+++ b/gs/zlib/adler32.c
@@ -0,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/gs/zlib/algorithm.doc b/gs/zlib/algorithm.doc
new file mode 100644
index 000000000..01902aff6
--- /dev/null
+++ b/gs/zlib/algorithm.doc
@@ -0,0 +1,105 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by zlib (also zip and gzip) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for a
+longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the longer match is emitted afterwards. Otherwise,
+the original match is kept, and the next match search is attempted only
+N steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+The real question is, given a Huffman tree, how to decode fast. The most
+important realization is that shorter codes are much more common than
+longer codes, so pay attention to decoding the short codes fast, and let
+the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code. It gets that many bits from the
+stream, and looks it up in the table. The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table. If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code. However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table. What inflate() does is
+simply to make the number of bits in the first table a variable, and set it
+for the maximum speed.
+
+inflate() sends new trees relatively often, so it is possibly set for a
+smaller first level table than an application that has only one tree for
+all the data. For inflate, which has 286 possible codes for the
+literal/length tree, the size of the first table is nine bits. Also the
+distance trees have 30 possible values, and the size of the first table is
+six bits. Note that for each of those cases, the table ended up one bit
+longer than the ``average'' code length, i.e. the code length of an
+approximately flat code which would be a little more than eight bits for
+286 symbols and a little less than five bits for 30 symbols. It would be
+interesting to see if optimizing the first level table for other
+applications gave values within a bit or two of the flat code size.
+
+
+Jean-loup Gailly Mark Adler
+gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+ftp://ds.internic.net/rfc/rfc1951.txt
diff --git a/gs/zlib/compress.c b/gs/zlib/compress.c
new file mode 100644
index 000000000..9c6b92342
--- /dev/null
+++ b/gs/zlib/compress.c
@@ -0,0 +1,57 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: compress.c,v 1.10 1996/05/23 16:51:12 me Exp */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 8 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+int compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
diff --git a/gs/zlib/configure b/gs/zlib/configure
new file mode 100755
index 000000000..a354e4cf4
--- /dev/null
+++ b/gs/zlib/configure
@@ -0,0 +1,86 @@
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+LIBS=libz.a
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-$prefix}
+
+test -z "$CC" && echo Checking for gcc...
+test=ztest$$
+cat > $test.c <<EOF
+int hello() { printf("hello\n"); }
+EOF
+if test -z "$CC" && (gcc -c -O3 $test.c) 2>/dev/null; then
+ CC=gcc
+ SFLAGS=${CFLAGS-"-fPIC -O3"}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"gcc -shared"}
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ case `(uname -sr || echo unknown) 2>/dev/null` in
+ SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+ CFLAGS=${CFLAGS-"-fast -xcg89"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"};;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc -A";;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ SHAREDLIBS='libz.sl';;
+ # send working options for other systems to gzip@prep.ai.mit.edu
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ esac
+fi
+
+echo Checking for shared library support...
+# we must test in two steps (cc then ld), required at least on SunOS 4.x
+if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+ test "`($LDSHARED -o $test.so $test.o) 2>&1`" = ""; then
+ CFLAGS="$SFLAGS"
+ LIBS='libz.so.$(VER)'
+ echo Building shared library libz.so.$VER with $CC.
+else
+ LDSHARED="$CC"
+ echo Building static library $LIBS version $VER with $CC.
+fi
+rm -f $test.[co] $test.so
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s/=.*/=$CC/
+/^CFLAGS *=/s/=.*/=$CFLAGS/
+/^LDSHARED *=/s/=.*/=$LDSHARED/
+/^LIBS *=/s,=.*,=$LIBS,
+/^AR *=/s/=.*/=$AR/
+/^RANLIB *=/s,=.*,=$RANLIB,
+/^VER *=/s/=.*/=$VER/
+/^prefix *=/s,=.*,=$prefix,
+/^exec_prefix *=/s,=.*,=$exec_prefix,
+" > Makefile
diff --git a/gs/zlib/crc32.c b/gs/zlib/crc32.c
new file mode 100644
index 000000000..6609a8522
--- /dev/null
+++ b/gs/zlib/crc32.c
@@ -0,0 +1,162 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: crc32.c,v 1.8 1996/01/30 21:59:10 me Exp */
+
+#include "zlib.h"
+
+#define local static
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+ Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The table is simply the CRC of all possible eight bit values. This is all
+ the information needed to generate CRC's on data a byte at a time for all
+ combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+ uLong c;
+ int n, k;
+ uLong poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320L) */
+ poly = 0L;
+ for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+ poly |= 1L << (31 - p[n]);
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (uLong)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local uLongf crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+#endif
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+uLongf *get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty) make_crc_table();
+#endif
+ return (uLongf *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong crc32(crc, buf, len)
+ uLong crc;
+ const Bytef *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return crc ^ 0xffffffffL;
+}
diff --git a/gs/zlib/deflate.c b/gs/zlib/deflate.c
new file mode 100644
index 000000000..175139455
--- /dev/null
+++ b/gs/zlib/deflate.c
@@ -0,0 +1,1207 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* Id: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp */
+
+#include "deflate.h"
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, charf *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int noheader = 0;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == Z_NULL) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->noheader = noheader;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
+
+ s = strm->state;
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length;
+ }
+ zmemcpy((charf *)s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ strm->adler = 1;
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ level = 6;
+ }
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the zlib header */
+ if (s->status == INIT_STATE) {
+
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags = (s->level-1) >> 1;
+
+ if (level_flags > 3) level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = 1L;
+ }
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ s->noheader = -1; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ status = strm->state->status;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* ========================================================================= */
+int deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+ *dest = *source;
+ return Z_STREAM_ERROR; /* to be implemented */
+#if 0
+ dest->state = (struct internal_state FAR *)
+ (*dest->zalloc)(1, sizeof(deflate_state));
+ if (dest->state == Z_NULL) return Z_MEM_ERROR;
+
+ *(dest->state) = *(source->state);
+ return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ charf *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (!strm->state->noheader) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp((charf *)s->window + match,
+ (charf *)s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+ (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage):
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+ more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Stored blocks are limited to 0xffff bytes: */
+ if (s->strstart == 0 || s->strstart > 0xfffe) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = s->strstart - 0xffff;
+ s->strstart = 0xffff;
+ }
+
+ /* Emit a stored block if it is large enough: */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ bflush = _tr_tally(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ bflush = _tr_tally (s, 0, s->window[s->strstart]);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ if (_tr_tally (s, 0, s->window[s->strstart-1])) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally (s, 0, s->window[s->strstart-1]);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/gs/zlib/deflate.h b/gs/zlib/deflate.h
new file mode 100644
index 000000000..bd2bd909d
--- /dev/null
+++ b/gs/zlib/deflate.h
@@ -0,0 +1,275 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Id: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zutil.h"
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ ulg compressed_len; /* total bit length of compressed file */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+#endif
diff --git a/gs/zlib/descrip.mms b/gs/zlib/descrip.mms
new file mode 100644
index 000000000..9d364598a
--- /dev/null
+++ b/gs/zlib/descrip.mms
@@ -0,0 +1,48 @@
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser <m.zinser@gsi.de>
+
+cc_defs =
+c_deb =
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\
+ deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\
+ inftrees.obj, infcodes.obj, infutil.obj, inffast.obj
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : example.exe minigzip.exe
+ @ write sys$output " Example applications available"
+libz.olb : libz.olb($(OBJS))
+ @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+ link example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+ link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean :
+ delete *.obj;*,libz.olb;*
+
+
+# Other dependencies.
+adler32.obj : zutil.h zlib.h zconf.h
+compress.obj : zlib.h zconf.h
+crc32.obj : zutil.h zlib.h zconf.h
+deflate.obj : deflate.h zutil.h zlib.h zconf.h
+example.obj : zlib.h zconf.h
+gzio.obj : zutil.h zlib.h zconf.h
+infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.obj : zutil.h zlib.h zconf.h infblock.h
+inftrees.obj : zutil.h zlib.h zconf.h inftrees.h
+infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.obj : zlib.h zconf.h
+trees.obj : deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : zlib.h zconf.h
+zutil.obj : zutil.h zlib.h zconf.h
diff --git a/gs/zlib/example b/gs/zlib/example
new file mode 100755
index 000000000..5794f670a
--- /dev/null
+++ b/gs/zlib/example
Binary files differ
diff --git a/gs/zlib/example.c b/gs/zlib/example.c
new file mode 100644
index 000000000..e8870c23f
--- /dev/null
+++ b/gs/zlib/example.c
@@ -0,0 +1,503 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: example.c,v 1.16 1996/05/23 17:11:28 me Exp */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *out, const char *in,
+ Byte *uncompr, int uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ } else {
+ printf("uncompress(): %s\n", uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(out, in, uncompr, uncomprLen)
+ const char *out; /* output file */
+ const char *in; /* input file */
+ Byte *uncompr;
+ int uncomprLen;
+{
+ int err;
+ int len = strlen(hello)+1;
+ gzFile file;
+
+ file = gzopen(out, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+
+ if (gzwrite(file, (const voidp)hello, (unsigned)len) != len) {
+ fprintf(stderr, "gzwrite err: %s\n", gzerror(file, &err));
+ }
+ gzclose(file);
+
+ file = gzopen(in, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen);
+ if (uncomprLen != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ }
+ gzclose(file);
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread\n");
+ } else {
+ printf("gzread(): %s\n", uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ int len = strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_in = compr;
+ d_stream.next_out = uncompr;
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ } else {
+ printf("inflate(): %s\n", uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ int len = strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_in = compr;
+ d_stream.next_out = uncompr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ } else {
+ printf("inflate with dictionary: %s\n", uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+
+ if (zlibVersion()[0] != ZLIB_VERSION[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : "foo.gz"),
+ (argc > 2 ? argv[2] : "foo.gz"),
+ uncompr, (int)uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ exit(0);
+ return 0; /* to avoid warning */
+}
diff --git a/gs/zlib/gzio.c b/gs/zlib/gzio.c
new file mode 100644
index 000000000..5bb8116bf
--- /dev/null
+++ b/gs/zlib/gzio.c
@@ -0,0 +1,523 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: gzio.c,v 1.14 1996/07/24 13:41:01 me Exp */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#define Z_BUFSIZE 4096
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open return NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ } else {
+ check_header(s); /* skip the .gz header */
+ }
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[20];
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte(s);
+ if (c != gz_magic[len]) {
+ s->transparent = 1;
+ if (c != EOF) s->stream.avail_in++, s->stream.next_in--;
+ s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+ return;
+ }
+ }
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+ err = deflateEnd(&(s->stream));
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ s->stream.next_out = next_out = buf;
+ s->stream.avail_out = len;
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
+ s->file);
+ }
+ return (int)(len - s->stream.avail_out);
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ /* Check for concatenated .gz files: */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ return (int)(len - s->stream.avail_out);
+}
+
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int gzwrite (file, buf, len)
+ gzFile file;
+ const voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+int gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->z_err = deflate(&(s->stream), flush);
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int gzclose (file)
+ gzFile file;
+{
+ int err;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+ err = gzflush (file, Z_FINISH);
+ if (err != Z_OK) return destroy(file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, s->stream.total_in);
+
+ }
+ return destroy(file);
+}
+
+/* ===========================================================================
+ Returns the error message for the last error which occured on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occured in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char* gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
diff --git a/gs/zlib/infblock.c b/gs/zlib/infblock.c
new file mode 100644
index 000000000..cc2e6745a
--- /dev/null
+++ b/gs/zlib/infblock.c
@@ -0,0 +1,402 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (s->checkfn != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ {
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ }
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
+ Trace((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Trace((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, &s->check);
+ return s;
+}
+
+
+#ifdef DEBUG
+ extern uInt inflate_hufts;
+#endif
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Trace((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Trace((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
+ s->sub.decode.td = Z_NULL;
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Trace((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if (t < 19)
+ t = 19;
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BAD;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->word.what.Bits;
+ c = h->more.Base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ inflate_trees_free(s->sub.trees.tb, z);
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+#ifdef DEBUG
+ inflate_hufts = 0;
+#endif
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BAD;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n",
+ inflate_hufts, sizeof(inflate_huft)));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ inflate_trees_free(td, z);
+ inflate_trees_free(tl, z);
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ ZFREE(z, s->sub.trees.blens);
+ s->sub.decode.codes = c;
+ s->sub.decode.tl = tl;
+ s->sub.decode.td = td;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ inflate_blocks_reset(s, z, c);
+ ZFREE(z, s->window);
+ ZFREE(z, s);
+ Trace((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy((charf *)s->window, d, n);
+ s->read = s->write = s->window + n;
+}
diff --git a/gs/zlib/infblock.h b/gs/zlib/infblock.h
new file mode 100644
index 000000000..3ecd50cd3
--- /dev/null
+++ b/gs/zlib/infblock.h
@@ -0,0 +1,37 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+extern int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+extern void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern void inflate_set_dictionary OF((
+ inflate_blocks_statef *s,
+ const Bytef *d, /* dictionary */
+ uInt n)); /* dictionary length */
diff --git a/gs/zlib/infcodes.c b/gs/zlib/infcodes.c
new file mode 100644
index 000000000..3ae3818a1
--- /dev/null
+++ b/gs/zlib/infcodes.c
@@ -0,0 +1,247 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+ mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
diff --git a/gs/zlib/infcodes.h b/gs/zlib/infcodes.h
new file mode 100644
index 000000000..c2c38df2c
--- /dev/null
+++ b/gs/zlib/infcodes.h
@@ -0,0 +1,27 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+extern int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+extern void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
diff --git a/gs/zlib/inffast.c b/gs/zlib/inffast.c
new file mode 100644
index 000000000..86eee4a29
--- /dev/null
+++ b/gs/zlib/inffast.c
@@ -0,0 +1,168 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (uInt)(q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
diff --git a/gs/zlib/inffast.h b/gs/zlib/inffast.h
new file mode 100644
index 000000000..8cc644efb
--- /dev/null
+++ b/gs/zlib/inffast.h
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_streamp ));
diff --git a/gs/zlib/inflate.c b/gs/zlib/inflate.c
new file mode 100644
index 000000000..74cc69c86
--- /dev/null
+++ b/gs/zlib/inflate.c
@@ -0,0 +1,345 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+ mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_streamp z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, &c);
+ Trace((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_streamp z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z, &c);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Trace((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Trace((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
+ return Z_STREAM_ERROR;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r != Z_STREAM_END)
+ return r;
+ r = Z_OK;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+}
+
+
+int inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+int inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
diff --git a/gs/zlib/inftrees.c b/gs/zlib/inftrees.c
new file mode 100644
index 000000000..90205bd1e
--- /dev/null
+++ b/gs/zlib/inftrees.c
@@ -0,0 +1,470 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ uIntf *, /* list of base values for non-simple codes */
+ uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ z_streamp )); /* for zalloc function */
+
+local voidpf falloc OF((
+ voidpf, /* opaque pointer (not used) */
+ uInt, /* number of items */
+ uInt)); /* size of item */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+#ifdef DEBUG
+ uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= N_MAX) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+uIntf *d; /* list of base values for non-simple codes */
+uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+z_streamp zs; /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ uInt v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (inflate_huft *)ZALLOC
+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+ {
+ if (h)
+ inflate_trees_free(u[0], zs);
+ return Z_MEM_ERROR; /* not enough memory */
+ }
+#ifdef DEBUG
+ inflate_hufts += z + 1;
+#endif
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->next)) = Z_NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ r.next = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_streamp z; /* for zfree function */
+{
+ int r;
+
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tb, z);
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for zfree function */
+{
+ int r;
+
+ /* build literal/length tree */
+ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tl, z);
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+ }
+
+ /* build distance tree */
+ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ inflate_trees_free(*td, z);
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ inflate_trees_free(*tl, z);
+ return r;
+#endif
+ }
+
+ /* done */
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_built = 0;
+#define FIXEDH 530 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q; /* opaque pointer */
+uInt n; /* number of items */
+uInt s; /* size of item */
+{
+ Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
+ "inflate_trees falloc overflow");
+ *(intf *)q -= n+s-s; /* s-s to avoid warning */
+ return (voidpf)(fixed_mem + *(intf *)q);
+}
+
+
+int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+{
+ /* build fixed tables if not already (multiple overlapped executions ok) */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ unsigned c[288]; /* length list for huft_build */
+ z_stream z; /* for falloc function */
+ int f = FIXEDH; /* number of hufts left in fixed_mem */
+
+ /* set up fake z_stream for memory routines */
+ z.zalloc = falloc;
+ z.zfree = Z_NULL;
+ z.opaque = (voidpf)&f;
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 7;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+ /* done */
+ Assert(f == 0, "invalid build of fixed tables");
+ fixed_built = 1;
+ }
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
+
+
+int inflate_trees_free(t, z)
+inflate_huft *t; /* table to free */
+z_streamp z; /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register inflate_huft *p, *q, *r;
+
+ /* Reverse linked list */
+ p = Z_NULL;
+ q = t;
+ while (q != Z_NULL)
+ {
+ r = (q - 1)->next;
+ (q - 1)->next = p;
+ p = q;
+ q = r;
+ }
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ while (p != Z_NULL)
+ {
+ q = (--p)->next;
+ ZFREE(z,p);
+ p = q;
+ }
+ return Z_OK;
+}
diff --git a/gs/zlib/inftrees.h b/gs/zlib/inftrees.h
new file mode 100644
index 000000000..b06613ddd
--- /dev/null
+++ b/gs/zlib/inftrees.h
@@ -0,0 +1,59 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
+ union {
+ uInt Base; /* literal, length base, or distance base */
+ inflate_huft *Next; /* pointer to next level of table */
+ } more;
+};
+
+#ifdef DEBUG
+ extern uInt inflate_hufts;
+#endif
+
+extern int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ z_streamp )); /* for zalloc, zfree functions */
+
+extern int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp )); /* for zalloc, zfree functions */
+
+extern int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *)); /* distance tree result */
+
+extern int inflate_trees_free OF((
+ inflate_huft *, /* tables to free */
+ z_streamp )); /* for zfree function */
+
diff --git a/gs/zlib/infutil.c b/gs/zlib/infutil.c
new file mode 100644
index 000000000..eb21199c3
--- /dev/null
+++ b/gs/zlib/infutil.c
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
diff --git a/gs/zlib/infutil.h b/gs/zlib/infutil.h
new file mode 100644
index 000000000..702cd290c
--- /dev/null
+++ b/gs/zlib/infutil.h
@@ -0,0 +1,99 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ BAD} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_huft *tl;
+ inflate_huft *td; /* trees to free */
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#endif
diff --git a/gs/zlib/libz.a b/gs/zlib/libz.a
new file mode 100644
index 000000000..e86870cf4
--- /dev/null
+++ b/gs/zlib/libz.a
Binary files differ
diff --git a/gs/zlib/makefile.b32 b/gs/zlib/makefile.b32
new file mode 100644
index 000000000..fc3ac6898
--- /dev/null
+++ b/gs/zlib/makefile.b32
@@ -0,0 +1,104 @@
+# Makefile for zlib
+# Borland C++
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Borland C 4.5x with the Dos Power Pack for a 32-bit protected mode
+# flat memory model. It was created for use with POV-Ray ray tracer and
+# you may choose to edit the CFLAGS to suit your needs but the
+# switches -WX and -DMSDOS are required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "make -fmakefile.b32"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Borland C++ -------------
+MODEL=-WX
+CFLAGS= $(MODEL) -P-C -K -N- -k- -d -3 -r- -v- -f -DMSDOS
+CC=bcc32
+LD=bcc32
+LIB=tlib
+LDFLAGS= $(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/gs/zlib/makefile.bor b/gs/zlib/makefile.bor
new file mode 100644
index 000000000..2116563d6
--- /dev/null
+++ b/gs/zlib/makefile.bor
@@ -0,0 +1,105 @@
+# Makefile for zlib
+# Borland C++ ************ UNTESTED ***********
+
+# To use, do "make -fmakefile.bor"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C++, Borland C++ -------------
+MODEL=-ml
+CFLAGS=-O2 -Z $(MODEL)
+CC=bcc
+LD=bcc
+LIB=tlib
+# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version
+LDFLAGS=$(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/gs/zlib/makefile.dj2 b/gs/zlib/makefile.dj2
new file mode 100644
index 000000000..398f28bbe
--- /dev/null
+++ b/gs/zlib/makefile.dj2
@@ -0,0 +1,93 @@
+# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96.
+# Copyright (C) 1995-1996 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.dj2; make test -fmakefile.dj2
+#
+# To install libz.a, zconf.h and zlib.h in the djgpp directories, type:
+#
+# make install -fmakefile.dj2
+#
+# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as
+# in the sample below if the pattern of the DJGPP distribution is to
+# be followed. Remember that, while <sp>'es around <=> are ignored in
+# makefiles, they are *not* in batch files or in djgpp.env.
+# - - - - -
+# [make]
+# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include
+# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib
+# BUTT=-m486
+# - - - - -
+# Alternately, these variables may be defined below, overriding the values
+# in djgpp.env, as
+INCLUDE_PATH=c:\usr\include
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is not found, replace with copy /Y .
+CP=cp -f
+# If install.exe is not found, replace with $(CP).
+INSTALL=install
+# The default value of RM is "rm -f." If "rm.exe" is not found, uncomment:
+# RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+ -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+ for %%f in ($(INCL)) do $(INSTALL) %%f $(INCLUDE_PATH)
+ for %%p in ($(LIBS)) do $(INSTALL) %%p $(LIBRARY_PATH)
+
+uninstall:
+ for %%f in ($(INCL)) do $(RM) $(INCLUDE_PATH)\%%f
+ for %%p in ($(LIBS)) do $(RM) $(LIBRARY_PATH)\%%p
+
+clean:
+ for %%p in (*.d *.o *.exe libz.a libz.so* foo.gz) do $(RM) %%p
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/gs/zlib/makefile.msc b/gs/zlib/makefile.msc
new file mode 100644
index 000000000..112684af0
--- /dev/null
+++ b/gs/zlib/makefile.msc
@@ -0,0 +1,101 @@
+# Makefile for zlib
+# Microsoft C 5.1 or later
+
+# To use, do "make makefile.msc"
+# To compile in small model, set below: MODEL=-AS
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft C 5.1 and later -------------
+MODEL=-AL
+CFLAGS=-Oait -Gs -nologo -W3 $(MODEL)
+#-Ox generates bad code with MSC 5.1
+CC=cl
+LD=link
+LDFLAGS=/e/st:0x1000/noe
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: zlib.lib example.exe minigzip.exe
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ if exist zlib.lib del zlib.lib
+ lib zlib $(OBJ1);
+ lib zlib $(OBJ2);
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj,,,zlib.lib;
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj,,,zlib.lib;
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/gs/zlib/makefile.sas b/gs/zlib/makefile.sas
new file mode 100644
index 000000000..5323e8217
--- /dev/null
+++ b/gs/zlib/makefile.sas
@@ -0,0 +1,64 @@
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+ NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+test: all
+ `cd`/example
+ echo hello world | minigzip | minigzip -d
+
+install: z.lib
+ copy zlib.h zconf.h INCLUDE: clone
+ copy z.lib LIB: clone
+
+z.lib: $(OBJS)
+ oml z.lib r $(OBJS)
+
+example: example.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+clean:
+ -delete force quiet *.o example minigzip z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Smakefile
+ copy to $@ <from <
+$(SCOPTIONS)
+<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/gs/zlib/makefile.tc b/gs/zlib/makefile.tc
new file mode 100644
index 000000000..a46ce7367
--- /dev/null
+++ b/gs/zlib/makefile.tc
@@ -0,0 +1,105 @@
+# Makefile for zlib
+# TurboC 2.0
+
+# To use, do "make -fmakefile.tc"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C 2.0 -------------
+MODEL=-ml
+# CFLAGS=-O2 -G -Z $(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+CFLAGS=-O2 -G -Z $(MODEL)
+CC=tcc -I\tc\include
+LD=tcc -L\tc\lib
+LIB=tlib
+LDFLAGS=$(MODEL) -f-
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) -eexample.exe example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) -eminigzip.exe minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/gs/zlib/makefile.wat b/gs/zlib/makefile.wat
new file mode 100644
index 000000000..2a3b629d3
--- /dev/null
+++ b/gs/zlib/makefile.wat
@@ -0,0 +1,103 @@
+# Makefile for zlib
+# Watcom 10a
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Watcom 10a 32-bit protected mode flat memory model. It was created
+# for use with POV-Ray ray tracer and you may choose to edit the CFLAGS to
+# suit your needs but the -DMSDOS is required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "wmake -f makefile.wat"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Watcom 10a -------------
+MODEL=-mf
+CFLAGS= $(MODEL) -fpi87 -fp5 -zp4 -5r -w5 -oneatx -DMSDOS
+CC=wcc386
+LD=wcl386
+LIB=wlib -b -c
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1=adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O)
+OBJ2=trees$(O) zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O)
+OBJ3=infutil$(O) inffast$(O)
+OBJP1=adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)
+OBJP2=trees$(O)+zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)
+OBJP3=infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h &
+ infcodes.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h &
+ infcodes.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2) $(OBJ3)
+ del zlib.lib
+ $(LIB) zlib.lib +$(OBJP1)
+ $(LIB) zlib.lib +$(OBJP2)
+ $(LIB) zlib.lib +$(OBJP3)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: minigzip.exe example.exe
+ example
+ echo hello world | minigzip | minigzip -d >test
+ type test
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/gs/zlib/minigzip b/gs/zlib/minigzip
new file mode 100755
index 000000000..14aeef64d
--- /dev/null
+++ b/gs/zlib/minigzip
Binary files differ
diff --git a/gs/zlib/minigzip.c b/gs/zlib/minigzip.c
new file mode 100644
index 000000000..d4048a278
--- /dev/null
+++ b/gs/zlib/minigzip.c
@@ -0,0 +1,246 @@
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* Id: minigzip.c,v 1.10 1996/07/24 13:41:04 me Exp */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN sizeof(GZ_SUFFIX)
+
+extern int unlink OF((const char *));
+
+#define BUFLEN 4096
+#define MAX_NAME_LEN 1024
+
+#define local static
+/* For MSDOS and other systems with limitation on stack size. For Unix,
+ #define local
+ works also.
+ */
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file)
+ char *file;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, "wb"); /* use "wb9" for maximal compression */
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ int len = strlen(file);
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-d] [files...]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int uncompr = 0;
+ gzFile file;
+
+ prog = argv[0];
+ argc--, argv++;
+
+ if (argc > 0) {
+ uncompr = (strcmp(*argv, "-d") == 0);
+ if (uncompr) {
+ argc--, argv++;
+ }
+ }
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), "wb"); /* "wb9" for max compr. */
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ do {
+ if (uncompr) {
+ file_uncompress(*argv);
+ } else {
+ file_compress(*argv);
+ }
+ } while (argv++, --argc);
+ }
+ exit(0);
+ return 0; /* to avoid warning */
+}
diff --git a/gs/zlib/trees.c b/gs/zlib/trees.c
new file mode 100644
index 000000000..798c5574a
--- /dev/null
+++ b/gs/zlib/trees.c
@@ -0,0 +1,1141 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* Id: trees.c,v 1.11 1996/07/24 13:41:06 me Exp */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+ ct_data *static_tree; /* static tree or NULL */
+ intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->compressed_len = 0L;
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ ct_data *stree = desc->stat_desc->static_tree;
+ intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L;
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes*/
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+ /* If compression failed and this is the first and last block,
+ * and if the .zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+#ifdef STORED_FILE_OK
+# ifdef FORCE_STORED_FILE
+ if (eof && s->compressed_len == 0L) { /* force stored file */
+# else
+ if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+# endif
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == (charf*)0) error ("block vanished");
+
+ copy_block(buf, (unsigned)stored_len, 0); /* without header */
+ s->compressed_len = stored_len << 3;
+ s->method = STORED;
+ } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+ s->compressed_len += 3 + s->static_len;
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+ s->compressed_len += 3 + s->opt_len;
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+ s->compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+
+ return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+ /* Try to guess if it is profitable to stop the current block here */
+ if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/gs/zlib/uncompr.c b/gs/zlib/uncompr.c
new file mode 100644
index 000000000..c156c2d08
--- /dev/null
+++ b/gs/zlib/uncompr.c
@@ -0,0 +1,58 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: uncompr.c,v 1.8 1996/01/30 21:59:26 me Exp */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/gs/zlib/zconf.h b/gs/zlib/zconf.h
new file mode 100644
index 000000000..17ed9c54b
--- /dev/null
+++ b/gs/zlib/zconf.h
@@ -0,0 +1,184 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR __far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR __far
+# endif
+#endif
+#ifndef FAR
+# define FAR
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
+ /* Borland C/C++ ignores FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
+# include <windows.h>
+# define EXPORT WINAPI
+#else
+# define EXPORT
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/gs/zlib/zlib.def b/gs/zlib/zlib.def
new file mode 100644
index 000000000..08c6d5501
--- /dev/null
+++ b/gs/zlib/zlib.def
@@ -0,0 +1,46 @@
+LIBRARY "zlib"
+
+DESCRIPTION '"""zlib data compression library"""'
+
+EXETYPE NT
+
+SUBSYSTEM WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+VERSION 1.04
+
+CODE EXECUTE READ
+
+DATA READ WRITE
+
+HEAPSIZE 1048576,4096
+
+EXPORTS
+ zlibVersion
+ deflate
+ deflateEnd
+ inflate
+ inflateEnd
+ deflateSetDictionary
+ deflateCopy
+ deflateReset
+ deflateParams
+ inflateSetDictionary
+ inflateSync
+ inflateReset
+ compress
+ uncompress
+ gzopen
+ gzdopen
+ gzread
+ gzwrite
+ gzflush
+ gzclose
+ gzerror
+ adler32
+ crc32
+ deflateInit_
+ inflateInit_
+ deflateInit2_
+ inflateInit2_
diff --git a/gs/zlib/zlib.h b/gs/zlib/zlib.h
new file mode 100644
index 000000000..337fe9fe8
--- /dev/null
+++ b/gs/zlib/zlib.h
@@ -0,0 +1,780 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.0.4, Jul 24th, 1996.
+
+ Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+ 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.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "zconf.h"
+
+#define ZLIB_VERSION "1.0.4"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+extern const char * EXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+extern int EXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+extern int EXPORT deflate OF((z_streamp strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+ block is terminated and flushed to the output buffer so that the
+ decompressor can get all input data available so far. For method 9, a future
+ variant on method 8, the current block will be flushed but not terminated.
+ Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+ output is byte aligned (the compressor can clear its internal bit buffer)
+ and the current block is always terminated; this can be useful if the
+ compressor has to be restarted from scratch after an interruption (in which
+ case the internal state of the compressor may be lost).
+ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+ special marker is output and the compression dictionary is discarded; this
+ is useful to allow the decompressor to synchronize if one compressed block
+ has been damaged (see inflateSync below). Flushing degrades compression and
+ so should be used only when necessary. Using Z_FULL_FLUSH too often can
+ seriously degrade the compression. If deflate returns with avail_out == 0,
+ this function must be called again with the same value of the flush
+ parameter and more output space (updated avail_out), until the flush is
+ complete (deflate returns with non-zero avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+
+extern int EXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+extern int EXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+ allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+ with the version assumed by the caller. msg is set to null if there is no
+ error message. inflateInit does not perform any decompression: this will be
+ done by inflate().
+*/
+
+
+extern int EXPORT inflate OF((z_streamp strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_PARTIAL_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
+ inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
+ Z_STREAM_ERROR if the stream structure was inconsistent (for example if
+ next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in
+ the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
+ application may then call inflateSync to look for a good compression block.
+ In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
+ dictionary chosen by the compressor.
+*/
+
+
+extern int EXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+extern int EXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library. (Method 9 will allow a 64K history buffer and
+ partial block flushes.)
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library (the value 16 will be allowed for method 9). Larger
+ values of this parameter result in better compression at the expense of
+ memory usage. The default value is 15 if deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ If next_in is not null, the library will use this buffer to hold also
+ some history information; the buffer must either hold the entire input
+ data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+ is null, the library will allocate its own history buffer (and leave next_in
+ null). next_out need not be provided here but must be provided by the
+ application for the next call of deflate().
+
+ If the history buffer is provided by the application, next_in must
+ must never be changed by the application since the compressor maintains
+ information inside this buffer from call to call; the application
+ must provide more input only by increasing avail_in. next_in is always
+ reset by the library in this case.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ an invalid method). msg is set to null if there is no error message.
+ deflateInit2 does not perform any compression: this will be done by
+ deflate().
+*/
+
+extern int EXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary (history buffer) from the given
+ byte sequence without producing any compressed output. This function must
+ be called immediately after deflateInit or deflateInit2, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and
+ can be predicted with good accuracy; the data can then be compressed better
+ than with the default empty dictionary. In this version of the library,
+ only the last 32K bytes of the dictionary are used.
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state
+ is inconsistent (for example if deflate has already been called for this
+ stream). deflateSetDictionary does not perform any compression: this will
+ be done by deflate().
+*/
+
+extern int EXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream. If
+ the source stream is using an application-supplied history buffer, a new
+ buffer is allocated for the destination stream. The compressed output
+ buffer is always application-supplied. It's the responsibility of the
+ application to provide the correct values of next_out and avail_out for the
+ next call of deflate.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+extern int EXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
+/*
+ Dynamically update the compression level and compression strategy.
+ This can be used to switch between compression and straight copy of
+ the input data, or to switch to a different kind of input data requiring
+ a different strategy. If the compression level is changed, the input
+ available so far is compressed with the old level (and may be flushed);
+ the new level will take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+extern int EXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+extern int EXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary (history buffer) from the given
+ uncompressed byte sequence. This function must be called immediately after
+ a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
+ by the compressor can be determined from the Adler32 value returned by this
+ call of inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+extern int EXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+extern int EXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level, window size,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+extern int EXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+extern int EXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+extern gzFile EXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9"). gzopen can be used to read a file which is not in gzip format;
+ in this case gzread will directly read from the file without decompression.
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+
+extern gzFile EXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+extern int EXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+extern int EXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+extern uLong EXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+extern int EXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+extern int EXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel, int strategy,
+ const char *version, int stream_size));
+extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/gs/zlib/zlib.rc b/gs/zlib/zlib.rc
new file mode 100644
index 000000000..2c0a3e4de
--- /dev/null
+++ b/gs/zlib/zlib.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+#define IDR_VERSION1 1
+IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+ FILEVERSION 1,0,4,0
+ PRODUCTVERSION 1,0,4,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS_DOS_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0 // not used
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ //language ID = U.S. English, char set = Windows, Multilingual
+
+ BEGIN
+ VALUE "FileDescription", "zlib data compression library\0"
+ VALUE "FileVersion", "1.0.4\0"
+ VALUE "InternalName", "zlib\0"
+ VALUE "OriginalFilename", "zlib.lib\0"
+ VALUE "ProductName", "ZLib.DLL\0"
+ VALUE "Comments", "DLL support by Alessandro Iacopetti\0"
+ VALUE "LegalCopyright", "(C) 1995-1996 Jean-loup Gailly & Mark Adler\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
diff --git a/gs/zlib/zutil.c b/gs/zlib/zutil.c
new file mode 100644
index 000000000..66d54a312
--- /dev/null
+++ b/gs/zlib/zutil.c
@@ -0,0 +1,211 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Id: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char *zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+#ifdef DEBUG
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ Bytef* s1;
+ Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER < 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/gs/zlib/zutil.h b/gs/zlib/zutil.h
new file mode 100644
index 000000000..7148920b6
--- /dev/null
+++ b/gs/zlib/zutil.h
@@ -0,0 +1,203 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Id: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+# include <stddef.h>
+# include <errno.h>
+#else
+ extern int errno;
+#endif
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# ifdef __TURBOC__
+# include <alloc.h>
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define FOPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef MACOS
+# define OS_CODE 0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef FOPEN
+# define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len));
+ extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */